chore: import upstream snapshot with attribution
Integ / changes (push) Has been skipped
Pre-commit / pre-commit (push) Failing after 1s
CLI exit codes / changes (push) Has been skipped
Test (Install) / changes (push) Has been skipped
Test (Python) / changes (push) Has been skipped
Test (TypeScript) / changes (push) Has been skipped
CLI exit codes / cli-gate (push) Has been cancelled
Test (Install) / test-install-gate (push) Has been cancelled
Integ / integ-gate (push) Has been cancelled
Test (Python) / test-python-gate (push) Has been cancelled
Test (TypeScript) / test-typescript-gate (push) Has been cancelled
Test (Install) / python-minimal (3.12) (push) Has been cancelled
Test (Install) / python-minimal (3.11) (push) Has been cancelled
Test (Install) / python-extra (agno, mirage.agents.agno) (push) Has been cancelled
Test (Install) / python-extra (chroma, mirage.resource.chroma) (push) Has been cancelled
Test (Install) / python-extra (pdf, mirage.core.filetype.pdf) (push) Has been cancelled
Integ / integ (push) Has been cancelled
Integ / integ-database (push) Has been cancelled
Integ / integ-database-ts (push) Has been cancelled
Integ / integ-data (push) Has been cancelled
Integ / integ-ssh (push) Has been cancelled
Integ / integ-ssh-ts (push) Has been cancelled
Test (Python) / audit (push) Has been cancelled
Test (TypeScript) / test (push) Has been cancelled
Test (TypeScript) / python-fs-shim (push) Has been cancelled
CLI exit codes / Python CLI (push) Has been cancelled
CLI exit codes / TypeScript CLI (push) Has been cancelled
CLI exit codes / Cross-language snapshot interop (push) Has been cancelled
Test (Python) / test (push) Has been cancelled
Test (Python) / import-isolation (deepagents, openai, mirage.agents.openai_agents) (push) Has been cancelled
Test (Python) / import-isolation (deepagents, pydantic-ai, mirage.agents.pydantic_ai) (push) Has been cancelled
Integ / integ-ts (push) Has been cancelled
Integ / integ-fuse (push) Has been cancelled
Test (Install) / python-extra (databricks, mirage.resource.databricks_volume) (push) Has been cancelled
Test (Install) / python-extra (deepagents, mirage.agents.langchain) (push) Has been cancelled
Test (Install) / python-extra (email, mirage.resource.email) (push) Has been cancelled
Test (Install) / python-extra (fuse, mirage.fuse.mount) (push) Has been cancelled
Test (Install) / python-extra (hdf5, mirage.core.filetype.hdf5) (push) Has been cancelled
Test (Install) / python-extra (hf, mirage.resource.hf_buckets) (push) Has been cancelled
Test (Install) / python-extra (lancedb, mirage.resource.lancedb) (push) Has been cancelled
Test (Install) / python-extra (langfuse, mirage.resource.langfuse) (push) Has been cancelled
Test (Install) / python-extra (mongodb, mirage.resource.mongodb) (push) Has been cancelled
Test (Install) / python-extra (nextcloud, mirage.resource.nextcloud) (push) Has been cancelled
Test (Install) / python-extra (openai, mirage.agents.openai_agents) (push) Has been cancelled
Test (Install) / python-extra (openhands, mirage.agents.openhands, 3.12) (push) Has been cancelled
Test (Install) / python-extra (parquet, mirage.core.filetype.parquet) (push) Has been cancelled
Test (Install) / python-extra (postgres, mirage.resource.postgres) (push) Has been cancelled
Test (Install) / python-extra (pydantic-ai, mirage.agents.pydantic_ai) (push) Has been cancelled
Test (Install) / python-extra (qdrant, mirage.resource.qdrant) (push) Has been cancelled
Test (Install) / python-extra (redis, mirage.resource.redis) (push) Has been cancelled
Test (Install) / python-extra (s3, mirage.resource.s3) (push) Has been cancelled
Test (Install) / python-extra (ssh, mirage.resource.ssh) (push) Has been cancelled
Test (Install) / ts-minimal (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 12:30:44 +08:00
commit bcbd1bdb22
5748 changed files with 562488 additions and 0 deletions
+13
View File
@@ -0,0 +1,13 @@
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
+21
View File
@@ -0,0 +1,21 @@
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
from datetime import datetime, timezone
def utc_date_folder(ts: float | None = None) -> str:
t = (datetime.now(timezone.utc) if ts is None else datetime.fromtimestamp(
ts, timezone.utc))
return t.strftime("%Y-%m-%d")
+101
View File
@@ -0,0 +1,101 @@
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
from mirage.types import PathSpec
_FS_STRERROR: list[tuple[type[OSError], str]] = [
(FileNotFoundError, "No such file or directory"),
(NotADirectoryError, "Not a directory"),
(IsADirectoryError, "Is a directory"),
(FileExistsError, "File exists"),
(PermissionError, "Permission denied"),
]
# The recoverable per-operand filesystem errors: every catch site that
# formats a GNU stderr line and keeps going uses this tuple, so the catch
# set and the strerror table can never drift apart (mirrors TS isFsError).
FS_ERRORS: tuple[type[OSError], ...] = tuple(t for t, _ in _FS_STRERROR)
def _virtual_of(path: object) -> str:
original = getattr(path, "virtual", None)
return original if original is not None else str(path)
def enoent(path: object) -> FileNotFoundError:
return FileNotFoundError(_virtual_of(path))
def enotdir(path: object) -> NotADirectoryError:
return NotADirectoryError(_virtual_of(path))
def eisdir(path: object) -> IsADirectoryError:
return IsADirectoryError(_virtual_of(path))
def fs_strerror(exc: BaseException) -> str | None:
for exc_type, strerror in _FS_STRERROR:
if isinstance(exc, exc_type):
return strerror
return None
def fs_error_line(cmd_name: str, path: object, exc: BaseException) -> str:
"""GNU coreutils stderr line for one failed path operand.
Produces ``<cmd>: <path>: <strerror>``, byte-identical with the
TypeScript formatter. ``path`` is the operand itself when the caller
knows it (read-family commands that keep processing remaining operands
after one fails, reported as typed via ``raw_path``), or an
already-resolved label string.
Args:
cmd_name (str): Command name for the ``<cmd>:`` prefix.
path (object): The failed operand; ``raw_path`` (or ``virtual``) is
the reported spelling, a plain string is used verbatim.
exc (BaseException): The filesystem error.
"""
label = getattr(path, "raw_path", None) or _virtual_of(path)
strerror = fs_strerror(exc)
if strerror is not None:
return f"{cmd_name}: {label}: {strerror}\n"
return f"{cmd_name}: {label}\n"
def format_fs_error(cmd_name: str,
exc: OSError,
paths: list[PathSpec] | None = None) -> bytes:
"""Format a filesystem OSError as a GNU coreutils stderr line.
The chokepoint variant of ``fs_error_line`` for callers that only hold
the exception: the path is recovered from it (``exc.filename`` when set,
else ``str(exc)``); backends raise with the resolved absolute path
(``PathSpec.virtual``). When ``paths`` is supplied, the absolute path is
rewritten to the as-typed form (``PathSpec.raw_path``) so a relative
argument is reported as typed, like GNU.
Args:
cmd_name (str): Command name for the ``<cmd>:`` prefix.
exc (OSError): The filesystem error.
paths (list[PathSpec] | None): Command operands, used to map the
resolved path back to the as-typed form.
"""
path = exc.filename or str(exc)
if paths:
for p in paths:
if p.virtual == path:
path = p.raw_path
break
return fs_error_line(cmd_name, path, exc).encode()
+88
View File
@@ -0,0 +1,88 @@
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
from mirage.types import FileType
EXTENSION_MAP: dict[str, FileType] = {
"json": FileType.JSON,
"jsonl": FileType.JSON,
"csv": FileType.CSV,
"tsv": FileType.CSV,
"txt": FileType.TEXT,
"md": FileType.TEXT,
"py": FileType.TEXT,
"js": FileType.TEXT,
"ts": FileType.TEXT,
"yaml": FileType.TEXT,
"yml": FileType.TEXT,
"toml": FileType.TEXT,
"png": FileType.IMAGE_PNG,
"jpg": FileType.IMAGE_JPEG,
"jpeg": FileType.IMAGE_JPEG,
"gif": FileType.IMAGE_GIF,
"zip": FileType.ZIP,
"gz": FileType.GZIP,
"pdf": FileType.PDF,
"parquet": FileType.PARQUET,
"orc": FileType.ORC,
"feather": FileType.FEATHER,
"arrow": FileType.FEATHER,
"ipc": FileType.FEATHER,
"h5": FileType.HDF5,
"hdf5": FileType.HDF5,
}
DEFAULT_TYPE = FileType.BINARY
_MIMETYPE_MAP: dict[str, FileType] = {
"application/pdf": FileType.PDF,
"application/zip": FileType.ZIP,
"application/gzip": FileType.GZIP,
"application/json": FileType.JSON,
"image/png": FileType.IMAGE_PNG,
"image/jpeg": FileType.IMAGE_JPEG,
"image/gif": FileType.IMAGE_GIF,
"text/csv": FileType.CSV,
}
def guess_type(path: str) -> FileType:
"""Return the file type for *path* based on its extension.
Args:
path (str): file path or name.
Returns:
FileType: matched type from EXTENSION_MAP, or DEFAULT_TYPE.
"""
ext = path.rsplit(".", 1)[-1].lower() if "." in path else ""
return EXTENSION_MAP.get(ext, DEFAULT_TYPE)
def filetype_from_mimetype(mime: str) -> FileType:
"""Map a standard mimetype string to a FileType.
Args:
mime (str): mimetype string (e.g., "image/png", "application/pdf").
Returns:
FileType: matched type, TEXT for any text/*, or BINARY default.
"""
if not mime:
return FileType.BINARY
if mime in _MIMETYPE_MAP:
return _MIMETYPE_MAP[mime]
if mime.startswith("text/"):
return FileType.TEXT
return FileType.BINARY
+192
View File
@@ -0,0 +1,192 @@
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
import dataclasses
import fnmatch
import logging
import posixpath
from collections.abc import Callable
from mirage.accessor.base import Accessor
from mirage.cache.index import IndexCacheStore
from mirage.types import PathSpec
from mirage.utils.key_prefix import rekey
logger = logging.getLogger(__name__)
GLOB_CHARS = ("*", "?", "[")
def has_glob(segment: str) -> bool:
"""Whether a path segment contains shell glob characters.
Args:
segment (str): one path component.
"""
return any(ch in segment for ch in GLOB_CHARS)
def is_word_shaped(p: PathSpec) -> bool:
"""Whether a pattern spec is a typed word (not a directory listing).
A classify-shaped word puts the pattern inside ``virtual``
(``/data/s*/x.txt`` with directory ``/data/s*/``); a dir-shaped spec
(``PathSpec.dir``) sets ``virtual`` to the directory itself.
Args:
p (PathSpec): unresolved pattern spec.
"""
return p.virtual.rstrip("/") != p.directory.rstrip("/")
def spell_match(raw: str, virtual: str, walked: int) -> str:
"""Spell a match the way bash expansion would.
Bash rewrites only the glob segments of the typed word; everything
before the first glob segment keeps its typed spelling, so
``../s*/x.txt`` expands to ``../sub/x.txt``. The walked tail has the
same segment count in the typed word and in the match's virtual
path, so the spelling is the typed head plus the match's last
``walked`` segments.
Args:
raw (str): the pattern word as typed (``PathSpec.raw_path``).
virtual (str): one match's absolute virtual path.
walked (int): segment count from the first glob segment on.
"""
head = raw.rstrip("/").split("/")[:-walked]
tail = virtual.rstrip("/").split("/")[-walked:]
return "/".join([*head, *tail])
async def expand_pattern(
readdir: Callable,
accessor: Accessor,
path: PathSpec,
index: IndexCacheStore | None,
) -> list[PathSpec]:
"""Expand a glob PathSpec segment-by-segment via readdir.
Mirrors bash globbing: every path component containing a glob
character is matched against the entries of its (already expanded)
parent directory, so a mid-path pattern (``pages/Demo_*/page.md``)
never reaches the backend as a literal ``*`` path segment. An
intermediate match that cannot be listed (a file, or a vanished
entry) is skipped, matching bash's directories-only descent for
non-final components.
Args:
readdir (Callable): backend readdir ``(accessor, path, index)``
returning absolute virtual paths.
accessor (Accessor): backend handle passed through to readdir.
path (PathSpec): unresolved spec whose ``resource_path`` still
contains the pattern.
index (IndexCacheStore | None): the per-call cache index.
"""
prefix = path.virtual[:len(path.virtual.rstrip("/")) -
len(path.resource_path)]
segments = path.resource_path.split("/") if path.resource_path else []
# Two spec shapes reach resolvers: a full pattern path (classify), where
# the pattern is already the last segment, and a directory-shaped spec
# (PathSpec.dir), where the pattern applies to the directory's entries.
if path.pattern and (not segments or segments[-1] != path.pattern):
segments = [*segments, path.pattern]
first = next((i for i, seg in enumerate(segments) if has_glob(seg)),
len(segments) - 1)
base = (prefix + "/".join(segments[:first])).rstrip("/") or "/"
level = [base]
for seg in segments[first:]:
next_level: list[str] = []
for parent in level:
spec = PathSpec.from_str_path(
parent, rekey(path.virtual, path.resource_path, parent))
try:
entries = await readdir(accessor, spec, index)
except (FileNotFoundError, NotADirectoryError):
continue
next_level.extend(
e for e in entries
if fnmatch.fnmatch(e.rstrip("/").rsplit("/", 1)[-1], seg))
level = next_level
if not level:
return []
matches = [
PathSpec.from_str_path(e, rekey(path.virtual, path.resource_path, e))
for e in level
]
# A typed word (raw differs from virtual) spells its matches; the
# dir-shaped specs internal expansions build (PathSpec.dir) have no
# typed form and keep the resolved virtual.
if path.raw_path == path.virtual:
return matches
walked = len(segments) - first
return [
dataclasses.replace(m,
raw_path=spell_match(path.raw_path, m.virtual,
walked)) for m in matches
]
async def resolve_glob_with(
readdir: Callable,
accessor: Accessor,
paths: list[PathSpec],
index: IndexCacheStore | None,
cap: int | None = None,
) -> list[PathSpec]:
"""Shared resolve_glob loop over a backend's readdir.
Resolved specs pass through, pattern specs expand segment-by-segment
via :func:`expand_pattern` (mid-path aware, spelled as typed), an
unmatched glob word stays the literal (bash with nullglob off: the
command then errors on it like GNU), and matches cap at ``cap`` when
given. Per-backend glob modules bind their own readdir.
Args:
readdir (Callable): backend readdir ``(accessor, path, index)``
returning absolute virtual paths.
accessor (Accessor): backend handle passed through to readdir.
paths (list[PathSpec]): specs to resolve.
index (IndexCacheStore | None): the per-call cache index.
cap (int | None): cap on matches per pattern before truncation.
"""
result: list[PathSpec] = []
for p in paths:
if isinstance(p, str):
result.append(
PathSpec(virtual=p,
directory=posixpath.dirname(p),
resource_path=p.strip("/")))
continue
if p.resolved:
result.append(p)
elif p.pattern:
matched = await expand_pattern(readdir, accessor, p, index)
if not matched and is_word_shaped(p):
# bash with nullglob off: an unmatched glob word stays
# the literal; the command then errors on it like GNU
# (cat '*.nope' -> No such file or directory, exit 1).
# Dir-shaped specs (PathSpec.dir) are internal
# expansions and keep the empty result.
result.append(
dataclasses.replace(p, pattern=None, resolved=True))
continue
if cap is not None and len(matched) > cap:
logger.warning("%s: %d matches exceeds limit (%d), truncating",
p.directory, len(matched), cap)
matched = matched[:cap]
result.extend(matched)
else:
result.append(p)
return result
+168
View File
@@ -0,0 +1,168 @@
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
def normalize(raw: str | None) -> str:
"""Normalize a key prefix.
Args:
raw: The raw prefix string, or None.
Returns:
Empty string if input was None/empty; otherwise the prefix with
leading slashes stripped and a trailing slash ensured.
"""
if not raw:
return ""
v = raw.lstrip("/")
return v if v.endswith("/") else v + "/"
def apply(prefix: str, path: str) -> str:
"""Prepend a normalized prefix to a virtual path.
Args:
prefix: A normalized prefix (use ``normalize()`` first if unsure).
path: The virtual path to scope.
Returns:
The backend key: ``prefix + path`` with the leading slash of
``path`` stripped.
"""
return prefix + path.lstrip("/")
def apply_dir(prefix: str, path: str) -> str:
"""Same as ``apply()`` but guarantees a trailing slash for LIST-style ops.
Args:
prefix: A normalized prefix.
path: The virtual path to scope.
Returns:
The backend key with a trailing slash, suitable for use as a LIST
``Prefix`` argument.
"""
key = apply(prefix, path)
return key if not key or key.endswith("/") else key + "/"
def strip(prefix: str, key: str) -> str:
"""Strip a normalized prefix from a backend-returned key.
Args:
prefix: A normalized prefix.
key: The backend-returned key.
Returns:
The key with the prefix removed if present; otherwise unchanged.
"""
return key[len(prefix):] if prefix and key.startswith(prefix) else key
def strip_mount(virtual: str, prefix: str) -> str:
"""Remove a mount prefix from a virtual path at a path boundary.
A sibling that only shares the prefix as a string (``/database`` vs a
``/data`` prefix) is left untouched.
Args:
virtual (str): An absolute virtual path.
prefix (str): The mount prefix (e.g. ``/data``), without a trailing
slash.
Returns:
The mount-relative path with its leading slash kept.
Example::
strip_mount("/data/sub/x.txt", "/data") -> "/sub/x.txt"
strip_mount("/database/x.txt", "/data") -> "/database/x.txt"
strip_mount("/data", "/data") -> "/"
strip_mount("/x.txt", "") -> "/x.txt"
"""
if prefix and virtual.startswith(prefix):
rest = virtual[len(prefix):]
if prefix.endswith("/") or rest == "" or rest.startswith("/"):
return rest or "/"
return virtual
def mount_key(virtual: str, prefix: str) -> str:
"""Backend key for a virtual path under a mount prefix.
Args:
virtual (str): An absolute virtual path.
prefix (str): The mount prefix.
Returns:
The mount-relative path with surrounding slashes stripped.
Example::
mount_key("/data/sub/x.txt", "/data") -> "sub/x.txt"
mount_key("/data", "/data") -> ""
mount_key("/x.txt", "") -> "x.txt"
"""
return strip_mount(virtual, prefix).strip("/")
def rekey(parent_original: str, parent_key: str, child: str) -> str:
"""Backend key for a child virtual path, derived from its parent.
A child shares the parent's mount prefix, so its key is the child
virtual path with the same prefix removed. The prefix length is
recovered from the parent's ``original``/``key`` pair, so no mount
context is needed.
Args:
parent_original (str): The parent's absolute virtual path.
parent_key (str): The parent's backend key.
child (str): The child's absolute virtual path.
Returns:
The child's backend key (surrounding slashes stripped).
Example::
rekey("/data/sub", "sub", "/data/sub/x.txt") -> "sub/x.txt"
rekey("/data", "", "/data/x.txt") -> "x.txt"
"""
prefix_len = len(parent_original.rstrip("/")) - len(parent_key)
return child[prefix_len:].strip("/")
def mount_prefix_of(virtual: str, resource_path: str) -> str:
"""Recover a mount prefix from a virtual path and its backend key.
The inverse of stamping: given a path's virtual form and the key the
mount stamped, return the mount prefix that was stripped off. Used by
commands (e.g. ``find``) that must map backend keys back to virtual
paths for display.
Args:
virtual (str): An absolute virtual path.
resource_path (str): Its backend key (mount-relative, slashless).
Returns:
The mount prefix without a trailing slash.
Example::
mount_prefix_of("/data/sub", "sub") -> "/data"
mount_prefix_of("/data", "") -> "/data"
mount_prefix_of("/x.txt", "x.txt") -> ""
"""
prefix_len = len(virtual.rstrip("/")) - len(resource_path)
return virtual[:prefix_len].rstrip("/")
+82
View File
@@ -0,0 +1,82 @@
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
from mirage.utils.sanitize import path_safe_name, sanitize_name
def make_id_name(
display_name: str,
resource_id: str,
*,
path_safe: bool = False,
) -> str:
"""Build a name with embedded ID for VFS paths.
Used by resources that encode resource IDs in filenames
for reverse lookups (Discord, Slack, Linear, Trello).
By default applies the full ``sanitize_name`` transform: replaces
unsafe shell chars and spaces with underscores. Set
``path_safe=True`` to preserve the original spelling (apostrophes,
spaces, emoji) and only replace ``/`` with ````. Discord and
Slack use ``path_safe=True`` so display names stay readable.
Example::
make_id_name("general", "C123456")
"general__C123456"
make_id_name("My Project!", "uuid-abc")
"My_Project__uuid-abc"
make_id_name("Zecheng's Server", "G1", path_safe=True)
"Zecheng's Server__G1"
Args:
display_name (str): human-readable name from the API.
resource_id (str): resource-specific unique ID.
path_safe (bool): if True, preserve spelling and only escape
the path separator. Otherwise apply full sanitization.
"""
transform = path_safe_name if path_safe else sanitize_name
return f"{transform(display_name)}__{resource_id}"
def parse_id_name(
name: str,
*,
suffix: str = "",
) -> tuple[str, str]:
"""Extract (display_name, resource_id) from make_id_name output.
Example::
parse_id_name("general__C123456")
→ ("general", "C123456")
parse_id_name("team__uuid.json", suffix=".json")
→ ("team", "uuid")
Args:
name (str): filename with embedded ID.
suffix (str): file extension to strip before parsing.
Raises:
FileNotFoundError: if name doesn't contain "__" or doesn't end
with ``suffix``.
"""
if suffix and not name.endswith(suffix):
raise FileNotFoundError(name)
raw = name[:-len(suffix)] if suffix else name
label, sep, resource_id = raw.rpartition("__")
if not sep or not resource_id:
raise FileNotFoundError(name)
return label, resource_id
+239
View File
@@ -0,0 +1,239 @@
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
import posixpath
def norm(path: str) -> str:
"""Normalize a virtual path to a leading-slash, no-trailing-slash key.
Args:
path: A virtual path string.
Returns:
The path with surrounding slashes collapsed to a single leading
slash (``"foo/bar/"`` -> ``"/foo/bar"``, ``""`` -> ``"/"``).
"""
return "/" + path.strip("/")
def parent(path: str) -> str:
"""Return the parent directory of a normalized virtual key.
Args:
path: A normalized virtual path (leading slash, no trailing slash).
Returns:
The path with its last segment removed (``"/a/b"`` -> ``"/a"``),
or ``"/"`` when there is no parent segment.
"""
i = path.rfind("/")
return path[:i] if i > 0 else "/"
def resolve_path(path: str, cwd: str) -> str:
"""Resolve a relative path against cwd.
Example::
resolve_path("../file.txt", "/data/sub/")
"/data/file.txt"
resolve_path("/abs/path", "/ignored")
"/abs/path"
"""
if not path.startswith("/"):
path = cwd.rstrip("/") + "/" + path
resolved = posixpath.normpath(path)
if resolved.startswith("//"):
resolved = "/" + resolved.lstrip("/")
return resolved
MAX_SYMLINK_HOPS = 40
class CycleError(Exception):
"""Raised when symlink resolution exceeds the maximum hop count.
Mirrors POSIX ELOOP (a loop such as ``a -> b -> a`` or an unbounded
expansion such as ``a -> a/x``). Command boundaries render this as the
GNU ``strerror`` text "Too many levels of symbolic links".
"""
def _is_link_prefix(key: str, path: str) -> bool:
return path == key or path.startswith(key + "/")
def resolve_symlinks(path: str, links: dict[str, str]) -> str:
"""Resolve symlink prefixes in ``path`` until stable.
Repeatedly replaces the longest dict key that is a path-boundary prefix
of ``path`` with its target, mirroring filesystem symlink following
(``/a/b`` is a prefix of ``/a/b/c`` but not ``/a/bc``). Relative targets
are resolved against the link's own parent directory.
Args:
path (str): An absolute virtual path.
links (dict[str, str]): Map of link virtual-path to target.
Returns:
str: The path with all symlink prefixes resolved.
Raises:
CycleError: If resolution exceeds ``MAX_SYMLINK_HOPS`` (a loop or
unbounded expansion), matching POSIX ELOOP.
"""
if not links:
return path
for _ in range(MAX_SYMLINK_HOPS):
best: str | None = None
for key in links:
if _is_link_prefix(key, path) and (best is None
or len(key) > len(best)):
best = key
if best is None:
return path
target = links[best]
if not target.startswith("/"):
target = norm(parent(best) + "/" + target)
path = target + path[len(best):]
raise CycleError(path)
def expand_tilde(word: str, home: str | None) -> str:
"""Expand a leading ``~`` against the home directory.
``~`` alone or ``~/rest`` expands to ``home`` (or ``home/rest``).
``~user`` and any non-leading ``~`` are left unchanged, matching
bash behavior when no matching user exists. When ``home`` is ``None``
(``$HOME`` unset/empty), a leading ``~`` is left literal, mirroring
GNU bash with no home directory.
Args:
word: The unexpanded word.
home: The home directory to substitute for ``~``, or ``None``.
Returns:
The word with a leading ``~`` resolved, or the word unchanged.
"""
if home is None:
return word
if word == "~":
return home
if word.startswith("~/"):
return home.rstrip("/") + word[1:]
return word
def rebase_raw(paths: list[str], original: str, raw: str) -> list[str]:
"""Rewrite the base of walked output paths to the as-typed form.
Used by walkers like ``find``/``grep -r``: results are absolute (start
path plus subpath), but when the start path was typed relatively the
output should show it that way. Maps :func:`rebase_one` over ``paths``.
Because :func:`rebase_one` only rewrites the leading base prefix, this
also works on formatted lines whose path is the prefix, e.g. grep's
``path:line``.
Example::
rebase_raw(["/data/sub/x", "/data/y"], "/data", ".")
-> ["./sub/x", "./y"]
rebase_raw(["/data/sub/x:hit"], "/data/sub", "sub")
-> ["sub/x:hit"]
rebase_raw(["/data/x"], "/data", "/data") # absolute arg
-> ["/data/x"] # unchanged
Args:
paths (list[str]): Absolute result paths (or ``path:...`` lines)
produced by walking ``original``.
original (str): The resolved absolute start path.
raw (str): The as-typed start path (``PathSpec.raw_path``); equal
to ``original`` leaves ``paths`` unchanged (the
absolute-argument case).
Returns:
list[str]: ``paths`` with each ``original`` base replaced by
``raw``.
"""
if raw == original:
return paths
return [rebase_one(p, original, raw) for p in paths]
def rebase_one(path: str, original: str, raw: str) -> str:
"""Rewrite a single path's ``original`` base to the as-typed ``raw``.
Only the leading ``original`` prefix is rewritten, so any suffix after
the path (e.g. grep's ``:line``) is preserved untouched.
Example::
rebase_one("/data/sub/x", "/data", ".") -> "./sub/x"
rebase_one("/data/sub", "/data/sub", "sub") -> "sub"
rebase_one("/data/x:hit", "/data", ".") -> "./x:hit"
rebase_one("/other/x", "/data", ".") -> "/other/x" # no match
rebase_one("/data/x", "/data", "/data") -> "/data/x" # absolute
Args:
path (str): An absolute path at or under ``original`` (optionally with
a trailing ``:...`` suffix).
original (str): The resolved absolute base (traversal root).
raw (str): The as-typed base (``PathSpec.raw_path``); equal to
``original`` leaves ``path`` unchanged.
Returns:
str: ``path`` with its ``original`` base replaced by ``raw``.
"""
if raw == original:
return path
base = original.rstrip("/")
if path == base:
return raw
if path.startswith(base + "/"):
return raw.rstrip("/") + path[len(base):]
return path
def gnu_basename(path: str, suffix: str | None = None) -> str:
i = len(path)
while i > 0 and path[i - 1] == "/":
i -= 1
if i == 0:
return "/" if path else ""
j = path.rfind("/", 0, i)
base = path[j + 1:i]
if suffix and base != suffix and base.endswith(suffix):
base = base[:len(base) - len(suffix)]
return base
def gnu_dirname(path: str) -> str:
if path == "":
return "."
i = len(path)
while i > 0 and path[i - 1] == "/":
i -= 1
if i == 0:
return "/"
j = path.rfind("/", 0, i)
if j == -1:
return "."
while j > 0 and path[j - 1] == "/":
j -= 1
if j == 0:
return "/"
return path[:j]
+63
View File
@@ -0,0 +1,63 @@
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
import re
UNSAFE_CHARS = re.compile(r"[^\w\s\-.]")
MULTI_UNDERSCORE = re.compile(r"_+")
MAX_LEN = 100
def sanitize_name(name: str) -> str:
"""Sanitize a name for use in virtual paths.
Replaces shell-unsafe characters (apostrophes, quotes, etc.)
and spaces with underscores. Safe for use in shell commands
without quoting.
Args:
name (str): raw name from API.
Returns:
str: sanitized name.
"""
if not name.strip():
return "unknown"
cleaned = UNSAFE_CHARS.sub("_", name)
cleaned = cleaned.replace(" ", "_")
cleaned = MULTI_UNDERSCORE.sub("_", cleaned)
cleaned = cleaned.strip("_")
if len(cleaned) > MAX_LEN:
cleaned = cleaned[:MAX_LEN]
return cleaned
def path_safe_name(name: str) -> str:
"""Make a name safe to embed in a VFS path segment.
Preserves the original spelling (spaces, apostrophes, emoji, etc.)
and only replaces the path separator ``/`` with ```` (U+2215)
so the value cannot collide with a directory boundary. Use this
for resource directory and file names where keeping the original
display name matters more than shell ergonomics.
Args:
name (str): raw name from API.
Returns:
str: path-safe name, or "unknown" if empty.
"""
if not name.strip():
return "unknown"
return name.replace("/", "")
+37
View File
@@ -0,0 +1,37 @@
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
def score_from_distance(value: object) -> str:
"""Convert a vector distance into a clamped 0..1 similarity string.
Args:
value (object): Distance reported by the vector store; anything
non-numeric (including bool) collapses to "0.00".
"""
if isinstance(value, bool) or not isinstance(value, (int, float)):
return "0.00"
return f"{max(0.0, 1.0 - float(value)):.2f}"
def format_score(value: object) -> str | None:
"""Format a provider-supplied similarity score to two decimals.
Args:
value (object): Score reported by the provider; anything
non-numeric (including bool) yields None.
"""
if isinstance(value, bool) or not isinstance(value, (int, float)):
return None
return f"{value:.2f}"
+19
View File
@@ -0,0 +1,19 @@
from collections.abc import AsyncIterator
async def ensure_stream(
src: bytes | AsyncIterator[bytes]) -> AsyncIterator[bytes]:
if isinstance(src, bytes):
yield src
return
async for chunk in src:
yield chunk
async def collect_bytes(src: bytes | AsyncIterator[bytes]) -> bytes:
if isinstance(src, bytes):
return src
chunks: list[bytes] = []
async for chunk in src:
chunks.append(chunk)
return b"".join(chunks)