     1→from pydantic import BaseModel
     2→
     3→from mirage.types import MountMode, SyncPolicy
     4→from mirage.workspace.consistency import ConsistencyPolicy
     5→
     6→
     7→class MountConfig(BaseModel):
     8→    uri: str | None = None
     9→    backend: str | None = None
    10→    args: dict[str, str] | None = None
    11→    mode: MountMode | None = None
    12→    consistency: ConsistencyPolicy = ConsistencyPolicy.CACHED
    13→
    14→
    15→class CreateWorkspaceRequest(BaseModel):
    16→    mounts: dict[str, str | MountConfig]
    17→    sync_policy: SyncPolicy = SyncPolicy.STAGED
    18→    mode: MountMode = MountMode.WRITE
    19→    consistency: ConsistencyPolicy = ConsistencyPolicy.CACHED
    20→    ttl_seconds: int = 300
    21→    runtime: str | None = None
    22→    fuse_ops: dict[str, str] | None = None
    23→
    24→
    25→class RegisterFuseRequest(BaseModel):
    26→    mountpoint: str
    27→    pid: int
    28→    mount_specs: list[str] = []
    29→    runtime: str | None = None
    30→
    31→
    32→class FilePayloadRequest(BaseModel):
    33→    checksum: str
    34→    data: str | None = None
    35→
    36→
    37→class ExecRequest(BaseModel):
    38→    command: str
    39→    cwd: str | None = None
    40→    stdin: str | None = None
    41→    input_files: dict[str, FilePayloadRequest] | None = None
    42→
    43→
    44→class FuseReportRequest(BaseModel):
    45→    mountpoint: str
    46→    status: dict
    47→    transfers: dict = {}
    48→    ops: list[dict] = []
    49→
    50→
    51→class RegisterCommandRequest(BaseModel):
    52→    name: str
    53→    exec: str
    54→    description: str = ""
    55→
    56→
    57→class RegisterFuseOpRequest(BaseModel):
    58→    pattern: str
    59→    handler: str
    60→
    61→
    62→class ReadRequest(BaseModel):
    63→    path: str
    64→    offset: int
    65→    size: int
    66→
    67→
    68→class WriteRequest(BaseModel):
    69→    path: str
    70→    offset: int
    71→    data: str
    72→
    73→
    74→class PathRequest(BaseModel):
    75→    path: str
    76→
    77→
    78→class ReaddirRequest(BaseModel):
    79→    path: str
    80→    cursor: str | None = None
    81→
    82→
    83→class RenameRequest(BaseModel):
    84→    src: str
    85→    dst: str
    86→
    87→
    88→class TruncateRequest(BaseModel):
    89→    path: str
    90→    size: int
    91→

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

from pydantic import BaseModel

from mirage.types import MountMode, SyncPolicy
from mirage.workspace.consistency import ConsistencyPolicy

class MountConfig(BaseModel):
    uri: str | None = None
    backend: str | None = None
    args: dict[str, str] | None = None
    mode: MountMode | None = None
    consistency: ConsistencyPolicy = ConsistencyPolicy.CACHED

class CreateWorkspaceRequest(BaseModel):
    mounts: dict[str, str | MountConfig]
    sync_policy: SyncPolicy = SyncPolicy.STAGED
    mode: MountMode = MountMode.WRITE
    consistency: ConsistencyPolicy = ConsistencyPolicy.CACHED
    ttl_seconds: int = 300
    runtime: str | None = None
    fuse_ops: dict[str, str] | None = None

class RegisterFuseRequest(BaseModel):
    mountpoint: str
    pid: int
    mount_specs: list[str] = []
    runtime: str | None = None

class FilePayloadRequest(BaseModel):
    checksum: str
    data: str | None = None

class ExecRequest(BaseModel):
    command: str
    cwd: str | None = None
    stdin: str | None = None
    input_files: dict[str, FilePayloadRequest] | None = None

class FuseReportRequest(BaseModel):
    mountpoint: str
    status: dict
    transfers: dict = {}
    ops: list[dict] = []

class RegisterCommandRequest(BaseModel):
    name: str
    exec: str
    description: str = ""

class RegisterFuseOpRequest(BaseModel):
    pattern: str
    handler: str

class ReadRequest(BaseModel):
    path: str
    offset: int
    size: int

class WriteRequest(BaseModel):
    path: str
    offset: int
    data: str

class PathRequest(BaseModel):
    path: str

class ReaddirRequest(BaseModel):
    path: str
    cursor: str | None = None

class RenameRequest(BaseModel):
    src: str
    dst: str

class TruncateRequest(BaseModel):
    path: str
    size: int


     1→import time
     2→import uuid
     3→from datetime import datetime, timezone
     4→
     5→from mirage.backend.loader import load_backend_class
     6→from mirage.cli.config import parse_mount_uri, split_mount_spec
     7→from mirage.commands import COMMANDS, _resolve
     8→from mirage.commands.builtin import nav
     9→from mirage.commands.custom.registry import CommandRegistry, ExternalCommand
    10→from mirage.fuse import FUSE_OPS
    11→from mirage.fuse.loader import build_registry_from_config, load_fuse_op_class
    12→from mirage.observe.entries import (CommandEntry, CommandResult, DispatchInfo,
    13→                                    ParsedCommand, SessionEntry, WorkspaceInfo)
    14→from mirage.observe.session_log import get_or_create_log
    15→from mirage.runtime.base import _BLOCKED, CommandNotAllowedError
    16→from mirage.server.service.base import MirageService
    17→from mirage.server.service.cache import FileCache
    18→from mirage.server.service.session import WorkspaceSession, _unmount_fuse
    19→from mirage.types import (FileStat, MountMode, RuntimeType, SyncPolicy)
    20→from mirage.workspace import Workspace
    21→from mirage.workspace.consistency import ConsistencyPolicy
    22→
    23→
    24→class LocalService(MirageService):
    25→

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

import time
import uuid
from datetime import datetime, timezone

from mirage.backend.loader import load_backend_class
from mirage.cli.config import parse_mount_uri, split_mount_spec
from mirage.commands import COMMANDS, _resolve
from mirage.commands.builtin import nav
from mirage.commands.custom.registry import CommandRegistry, ExternalCommand
from mirage.fuse import FUSE_OPS
from mirage.fuse.loader import build_registry_from_config, load_fuse_op_class
from mirage.observe.entries import (CommandEntry, CommandResult, DispatchInfo,
                                    ParsedCommand, SessionEntry, WorkspaceInfo)
from mirage.observe.session_log import get_or_create_log
from mirage.runtime.base import _BLOCKED, CommandNotAllowedError
from mirage.server.service.base import MirageService
from mirage.server.service.cache import FileCache
from mirage.server.service.session import WorkspaceSession, _unmount_fuse
from mirage.types import (FileStat, MountMode, RuntimeType, SyncPolicy)
from mirage.workspace import Workspace
from mirage.workspace.consistency import ConsistencyPolicy

class LocalService(MirageService):


Edit

from mirage.types import (FileStat, Inode, MountMode, SyncPolicy, SyncResult,
                          TransferStats)
from mirage.workspace.cache import LRUCache
from mirage.workspace.consistency import ConsistencyPolicy, is_fresh
from mirage.workspace.mount import MountRegistry
from mirage.workspace.sync import DirtyTracker

from mirage.types import (FileStat, Inode, MountMode, SyncResult, TransferStats)
from mirage.workspace.cache import LRUCache
from mirage.workspace.consistency import ConsistencyPolicy, is_fresh
from mirage.workspace.mount import MountRegistry
from mirage.workspace.sync import DirtyTracker, SyncPolicy


The file /Users/agent/strukto/mirage/mirage/workspace/workspace.py has been updated successfully.

from mirage.types import (FileStat, Inode, MountMode, SyncResult, TransferStats)
from mirage.workspace.cache import LRUCache
from mirage.workspace.consistency import ConsistencyPolicy, is_fresh
from mirage.workspace.mount import MountRegistry
from mirage.workspace.sync import DirtyTracker, SyncPolicy

from __future__ import annotations

import time

from mirage.backend.base import BaseBackend
from mirage.backend.filetype import guess_type
from mirage.types import (FileStat, Inode, MountMode, SyncPolicy, SyncResult,
                          TransferStats)
from mirage.workspace.cache import LRUCache
from mirage.workspace.consistency import ConsistencyPolicy, is_fresh
from mirage.workspace.mount import MountRegistry
from mirage.workspace.sync import DirtyTracker

class _PathLock:

    def __init__(self, ws: Workspace, paths: list[str]) -> None:
        self._ws = ws
        self._paths = paths

    def __enter__(self) -> _PathLock:
        return self

    def __exit__(self, *_: object) -> None:
        self._ws.unlock_paths(self._paths)

class Workspace:
    """
    Unified virtual filesystem over heterogeneous backends.

    Mounts backends at virtual path prefixes and provides a command-level API
    (cat, ls, write, cp, mv, rm, ...) with transparent caching
    and write staging.

    Example::

        ws = Workspace(
            {"/data/": S3Backend(S3Config(bucket="my-bucket")),
             "/tmp/":  MemoryBackend()},
            cache_limit="256MB",
            sync_policy=SyncPolicy.STAGED,
        )
        content = ws.cat("/data/reports/q1.json")
        ws.write("/tmp/summary.txt", b"hello")
        ws.sync()
    """

    def __init__(
        self,
        backends: dict[str, BaseBackend | tuple],
        cache_limit: str | int = "512MB",
        sync_policy: SyncPolicy = SyncPolicy.STAGED,
        mode: MountMode = MountMode.READ,
        consistency: ConsistencyPolicy = ConsistencyPolicy.CACHED,
        ttl_seconds: int = 300,
    ) -> None:
        self._registry = MountRegistry()
        self._cache = LRUCache(cache_limit)
        self._tracker = DirtyTracker()
        self._sync_policy = sync_policy
        self._ttl_seconds = ttl_seconds
        self._locked_paths: set[str] = set()
        self._transfer_stats: dict[str, TransferStats] = {}
        self._created_at: float = time.time()

        for prefix, value in backends.items():
            if isinstance(value, tuple) and len(value) == 3:
                backend, mount_mode, mount_consistency = value
            elif isinstance(value, tuple):
                backend, mount_mode = value
                mount_consistency = consistency
            else:
                backend = value
                mount_mode = mode
                mount_consistency = consistency
            self._registry.mount(prefix, backend, mount_mode,
                                 mount_consistency)

    # ── mount management ────────────────────────────────────────────────────

    def mount(
            self,
            prefix: str,
            backend: BaseBackend,
            mode: MountMode = MountMode.READ,
            consistency: ConsistencyPolicy = ConsistencyPolicy.CACHED) -> None:
        self._registry.mount(prefix, backend, mode, consistency)

    def backend(self, path: str) -> BaseBackend:
        backend, _, _ = self._registry.resolve(path)
        return backend

    # ── read ops ────────────────────────────────────────────────────────────

    def cat(self, path: str) -> bytes:
        inode = self._tracker.get(path)
        if inode and inode.dirty:
            entry = self._cache.get(path)
            if entry is not None:
                self._record_transfer(path,
                                      "read",
                                      len(entry.data),
                                      0,
                                      cache_hit=True)
                return entry.data

        entry = self._cache.get(path)
        remote_stat = None
        if entry is not None:
            consistency = self._registry.mount_for(path).consistency
            backend, bp, _ = self._registry.resolve(path)
            fresh, remote_stat = is_fresh(entry, consistency,
                                          self._ttl_seconds, backend, bp)
            if fresh:
                self._record_transfer(path,
                                      "read",
                                      len(entry.data),
                                      0,
                                      cache_hit=True)
                return entry.data
        else:
            backend, bp, _ = self._registry.resolve(path)

        t0 = time.monotonic()
        data = backend.cat(bp)
        duration_ms = int((time.monotonic() - t0) * 1000)
        self._record_transfer(path,
                              "read",
                              len(data),
                              duration_ms,
                              cache_hit=False)
        if remote_stat is None:
            remote_stat = backend.stat(bp)
        self._cache.put(path,
                        data,
                        etag=remote_stat.extra.get("etag"),
                        modified=remote_stat.modified,
                        size=remote_stat.size)
        self._tracker.on_read(path, data, self._mount_prefix(path))
        return data

    def ls(self, path: str) -> list[str]:
        backend, bp, _ = self._registry.resolve(path)
        prefix = self._mount_prefix(path).rstrip("/")
        backend_ok = False
        try:
            backend_entries = backend.ls(bp)
            backend_ok = True
        except FileNotFoundError:
            backend_entries = []
        result: set[str] = {
            prefix + "/" + e.lstrip("/")
            for e in backend_entries
        }
        norm_path = "/" + path.strip("/")
        dir_prefix = norm_path.rstrip("/") + "/"
        has_staged_children = False
        for inode in self._tracker.dirty():
            vp = inode.virtual_path
            if not vp.startswith(dir_prefix):
                continue
            if inode.checksum is None:
                result.discard(vp)
                continue
            has_staged_children = True
            remainder = vp[len(dir_prefix):]
            first = remainder.split("/")[0]
            if not first:
                continue
            if "/" in remainder:
                result.add(dir_prefix + first + "/")
            else:
                result.add(dir_prefix + first)
        if not backend_ok and not has_staged_children:
            raise FileNotFoundError(path)
        return sorted(result)

    def ls_l(self, path: str) -> list[FileStat]:
        backend, bp, _ = self._registry.resolve(path)
        return backend.ls_l(bp)

    def stat(self, path: str) -> FileStat:
        inode = self._tracker.get(path)
        if inode and inode.dirty and inode.checksum is not None:
            entry = self._cache.get(path)
            size = len(entry.data) if entry is not None else inode.size
            return FileStat(
                name=path.rstrip("/").rsplit("/", 1)[-1],
                size=size,
                type=guess_type(path),
            )
        backend, bp, _ = self._registry.resolve(path)
        return backend.stat(bp)

    def exists(self, path: str) -> bool:
        try:
            self.stat(path)
            return True
        except (FileNotFoundError, ValueError):
            return False

    def head(self, path: str, lines: int = 10) -> bytes:
        backend, bp, _ = self._registry.resolve(path)
        return backend.head(bp, lines)

    def tail(self, path: str, lines: int = 10) -> bytes:
        backend, bp, _ = self._registry.resolve(path)
        return backend.tail(bp, lines)

    def read(self, path: str, offset: int, size: int) -> bytes:
        inode = self._tracker.get(path)
        if inode and inode.dirty:
            entry = self._cache.get(path)
            if entry is not None:
                return entry.data[offset:offset + size]

        entry = self._cache.get(path)
        remote_stat = None
        if entry is not None:
            consistency = self._registry.mount_for(path).consistency
            backend, bp, _ = self._registry.resolve(path)
            fresh, remote_stat = is_fresh(entry, consistency,
                                          self._ttl_seconds, backend, bp)
            if fresh:
                return entry.data[offset:offset + size]
        else:
            backend, bp, _ = self._registry.resolve(path)

        data = backend.cat(bp)
        if remote_stat is None:
            remote_stat = backend.stat(bp)
        self._cache.put(path,
                        data,
                        etag=remote_stat.extra.get("etag"),
                        modified=remote_stat.modified,
                        size=remote_stat.size)
        self._tracker.on_read(path, data, self._mount_prefix(path))
        return data[offset:offset + size]

    def grep(self, pattern: str, path: str) -> list[str]:
        backend, bp, _ = self._registry.resolve(path)
        return backend.grep(pattern, bp)

    # ── write ops ───────────────────────────────────────────────────────────

    def write(self, path: str, data: bytes) -> None:
        self._assert_not_locked(path)
        self._assert_writable(path)
        backend, bp, _ = self._registry.resolve(path)
        self._cache.put(path, data)
        self._tracker.on_write(path, data, self._mount_prefix(path))
        self._record_transfer(path, "write", len(data), 0)
        if self._sync_policy == SyncPolicy.IMMEDIATE:
            backend.put(bp, data)
            self._tracker.on_read(path, data, self._mount_prefix(path))

    def mkdir(self, path: str) -> None:
        self._assert_writable(path)
        backend, bp, _ = self._registry.resolve(path)
        backend.mkdir(bp)

    def rm(self, path: str) -> None:
        self._assert_writable(path)
        backend, bp, _ = self._registry.resolve(path)
        inode = self._tracker.get(path)
        staged_only = inode and inode.dirty and inode.remote_checksum is None
        if not staged_only:
            backend.unlink(bp)
        self._cache.invalidate(path)
        self._tracker.on_delete(path)

    def mv(self, src: str, dst: str) -> None:
        self._assert_writable(src)
        sb, sbp, _ = self._registry.resolve(src)
        db, dbp, _ = self._registry.resolve(dst)
        src_inode = self._tracker.get(src)
        staged_only = (src_inode and src_inode.dirty
                       and src_inode.remote_checksum is None)
        if staged_only:
            entry = self._cache.get(src)
            data = entry.data if entry else b""
            self._cache.put(dst, data)
            self._tracker.on_write(dst, data, self._mount_prefix(dst))
            self._cache.invalidate(src)
            self._tracker.on_delete(src)
        elif sb is db:
            sb.rename(sbp, dbp)
            self._cache.invalidate(src)
        else:
            data = sb.cat(sbp)
            db.put(dbp, data)
            sb.unlink(sbp)
            self._cache.invalidate(src)

    def cp(self, src: str, dst: str) -> None:
        self._assert_writable(dst)
        data = self.cat(src)
        db, dbp, _ = self._registry.resolve(dst)
        db.put(dbp, data)

    # ── sync lifecycle ──────────────────────────────────────────────────────

    def sync(self, path: str | None = None) -> list[SyncResult]:
        results: list[SyncResult] = []
        targets = [
            i for i in self._tracker.dirty()
            if path is None or i.virtual_path == path
        ]
        for inode in targets:
            backend, bp, _ = self._registry.resolve(inode.virtual_path)
            entry = self._cache.get(inode.virtual_path)
            data = entry.data if entry else None
            result = self._tracker.on_sync(inode.virtual_path, bp, data,
                                           backend)
            results.append(result)
        return results

    def status(self) -> list[Inode]:
        return self._tracker.status()

    def reset(self) -> None:
        self._tracker.reset()
        self._cache.clear()

    # ── path locking ─────────────────────────────────────────────────────────

    def _lock_path(self, path: str) -> None:
        self._locked_paths.add(path)

    def unlock_paths(self, paths: list[str]) -> None:
        for p in paths:
            self._locked_paths.discard(p)

    def lock_paths(self, paths: list[str]) -> _PathLock:
        for p in paths:
            self._lock_path(p)
        return _PathLock(self, paths)

    def _assert_not_locked(self, path: str) -> None:
        if path in self._locked_paths:
            raise PermissionError(
                f"path {path!r} is locked by remote execution")

    # ── helpers ─────────────────────────────────────────────────────────────

    def _mount_prefix(self, path: str) -> str:
        norm = "/" + path.strip("/")
        for m in self._registry.mounts():
            if norm == m.prefix.rstrip("/") or norm.startswith(m.prefix):
                return m.prefix
        return "/"

    def _assert_writable(self, path: str) -> None:
        _, _, mode = self._registry.resolve(path)
        if mode == MountMode.READ:
            raise PermissionError(f"mount at {path!r} is read-only")

    def _record_transfer(self,
                         path: str,
                         op: str,
                         nbytes: int,
                         duration_ms: int,
                         cache_hit: bool | None = None) -> None:
        prefix = self._mount_prefix(path)
        if prefix not in self._transfer_stats:
            self._transfer_stats[prefix] = TransferStats()
        stats = self._transfer_stats[prefix]
        if op == "read":
            stats.bytes_read += nbytes
            stats.read_ops += 1
            stats.total_read_ms += duration_ms
            if cache_hit is True:
                stats.cache_hits += 1
            elif cache_hit is False:
                stats.cache_misses += 1
        elif op == "write":
            stats.bytes_written += nbytes
            stats.write_ops += 1
            stats.total_write_ms += duration_ms

-from mirage.types import (FileStat, Inode, MountMode, SyncPolicy, SyncResult,

-                          TransferStats)

+from mirage.types import (FileStat, Inode, MountMode, SyncResult, TransferStats)

-from mirage.workspace.sync import DirtyTracker

+from mirage.workspace.sync import DirtyTracker, SyncPolicy


from mirage.types import MountMode, SyncPolicy

from mirage.types import MountMode
from mirage.workspace.sync import SyncPolicy


The file /Users/agent/strukto/mirage/mirage/server/fastapi/config.py has been updated successfully.

from mirage.types import MountMode
from mirage.workspace.sync import SyncPolicy

from pydantic import BaseModel

from mirage.types import MountMode, SyncPolicy
from mirage.workspace.consistency import ConsistencyPolicy

class MountConfig(BaseModel):
    uri: str | None = None
    backend: str | None = None
    args: dict[str, str] | None = None
    mode: MountMode | None = None
    consistency: ConsistencyPolicy = ConsistencyPolicy.CACHED

class CreateWorkspaceRequest(BaseModel):
    mounts: dict[str, str | MountConfig]
    sync_policy: SyncPolicy = SyncPolicy.STAGED
    mode: MountMode = MountMode.WRITE
    consistency: ConsistencyPolicy = ConsistencyPolicy.CACHED
    ttl_seconds: int = 300
    runtime: str | None = None
    fuse_ops: dict[str, str] | None = None

class RegisterFuseRequest(BaseModel):
    mountpoint: str
    pid: int
    mount_specs: list[str] = []
    runtime: str | None = None

class FilePayloadRequest(BaseModel):
    checksum: str
    data: str | None = None

class ExecRequest(BaseModel):
    command: str
    cwd: str | None = None
    stdin: str | None = None
    input_files: dict[str, FilePayloadRequest] | None = None

class FuseReportRequest(BaseModel):
    mountpoint: str
    status: dict
    transfers: dict = {}
    ops: list[dict] = []

class RegisterCommandRequest(BaseModel):
    name: str
    exec: str
    description: str = ""

class RegisterFuseOpRequest(BaseModel):
    pattern: str
    handler: str

class ReadRequest(BaseModel):
    path: str
    offset: int
    size: int

class WriteRequest(BaseModel):
    path: str
    offset: int
    data: str

class PathRequest(BaseModel):
    path: str

class ReaddirRequest(BaseModel):
    path: str
    cursor: str | None = None

class RenameRequest(BaseModel):
    src: str
    dst: str

class TruncateRequest(BaseModel):
    path: str
    size: int

-from mirage.types import MountMode, SyncPolicy

+from mirage.workspace.sync import SyncPolicy


from mirage.types import (FileStat, MountMode, RuntimeType, SyncPolicy)
from mirage.workspace import Workspace

from mirage.types import (FileStat, MountMode, RuntimeType)
from mirage.workspace import Workspace
from mirage.workspace.sync import SyncPolicy


The file /Users/agent/strukto/mirage/mirage/server/service/local.py has been updated successfully.

from mirage.types import (FileStat, MountMode, RuntimeType)
from mirage.workspace import Workspace
from mirage.workspace.sync import SyncPolicy

import time
import uuid
from datetime import datetime, timezone

from mirage.backend.loader import load_backend_class
from mirage.cli.config import parse_mount_uri, split_mount_spec
from mirage.commands import COMMANDS, _resolve
from mirage.commands.builtin import nav
from mirage.commands.custom.registry import CommandRegistry, ExternalCommand
from mirage.fuse import FUSE_OPS
from mirage.fuse.loader import build_registry_from_config, load_fuse_op_class
from mirage.observe.entries import (CommandEntry, CommandResult, DispatchInfo,
                                    ParsedCommand, SessionEntry, WorkspaceInfo)
from mirage.observe.session_log import get_or_create_log
from mirage.runtime.base import _BLOCKED, CommandNotAllowedError
from mirage.server.service.base import MirageService
from mirage.server.service.cache import FileCache
from mirage.server.service.session import WorkspaceSession, _unmount_fuse
from mirage.types import (FileStat, MountMode, RuntimeType, SyncPolicy)
from mirage.workspace import Workspace
from mirage.workspace.consistency import ConsistencyPolicy

class LocalService(MirageService):

    def __init__(self) -> None:
        self._sessions: dict[str, WorkspaceSession] = {}
        self._file_cache = FileCache()

    def _get_session(self, ws_id: str) -> WorkspaceSession:
        session = self._sessions.get(ws_id)
        if session is None:
            raise KeyError(f"workspace {ws_id!r} not found")
        if session.fuse_mounted:
            raise ValueError("not supported for fuse workspaces")
        return session

    def create_workspace(self, config: dict) -> str:
        mode = config.get("mode", "write")
        consistency = config.get("consistency", "cached")
        default_mode = MountMode(mode)
        default_consistency = ConsistencyPolicy(consistency)
        mounts = config.get("mounts", {})

        backends: dict = {}
        for prefix, value in mounts.items():
            if isinstance(value, str):
                backends[prefix] = parse_mount_uri(value)
            else:
                backend_spec = value.get("backend")
                if backend_spec:
                    cls = load_backend_class(backend_spec)
                    backend = cls(**(value.get("args") or {}))
                else:
                    backend = parse_mount_uri(value.get("uri") or "")
                mount_mode = (MountMode(value["mode"])
                              if value.get("mode") else default_mode)
                mount_consistency = (ConsistencyPolicy(value["consistency"])
                                     if value.get("consistency") else
                                     default_consistency)
                if (mount_mode != default_mode
                        or mount_consistency != default_consistency):
                    backends[prefix] = (backend, mount_mode, mount_consistency)
                else:
                    backends[prefix] = backend

        ws = Workspace(
            backends,
            sync_policy=SyncPolicy(config.get("sync_policy", "staged")),
            mode=default_mode,
            consistency=default_consistency,
            ttl_seconds=config.get("ttl_seconds", 300),
        )

        mounts_info: list[dict] = []
        for prefix, value in mounts.items():
            if isinstance(value, str):
                uri = value
            else:
                uri = value.get("uri") or ""
                if not uri and value.get("backend"):
                    uri = f"{value['backend']}://"
            mounts_info.append({"prefix": prefix, "uri": uri})

        ws_id = str(uuid.uuid4())[:8]
        registry = CommandRegistry()
        fuse_ops_config = config.get("fuse_ops") or {}
        fuse_registry = build_registry_from_config(fuse_ops_config)
        runtime = config.get("runtime")
        rt_type = RuntimeType(runtime) if runtime else None

        self._sessions[ws_id] = WorkspaceSession(
            id=ws_id,
            ws=ws,
            registry=registry,
            mode=mode,
            mounts=mounts_info,
            runtime_type=rt_type,
            fuse_registry=fuse_registry,
        )

        log = get_or_create_log(ws_id)
        mount_info = {}
        for m in ws._registry.mounts():
            mount_info[m.prefix] = {
                "type": type(m.backend).__name__,
                "mode": m.mode.value,
            }
        session_entry = SessionEntry(
            timestamp=datetime.now(timezone.utc).isoformat(),
            workspace=WorkspaceInfo(
                mounts=mount_info,
                cache_limit=str(ws._cache.limit),
                runtime_type=rt_type.value if rt_type else None,
            ),
            commands=registry.list_commands(),
        )
        log.write_session(session_entry)
        return ws_id

    def delete_workspace(self, ws_id: str) -> None:
        session = self._sessions.get(ws_id)
        if session is None:
            raise KeyError(f"workspace {ws_id!r} not found")
        if session.fuse_mounted and session.mountpoint:
            _unmount_fuse(session.mountpoint, session.pid)
        self._file_cache.clear(ws_id)
        del self._sessions[ws_id]

    def list_workspaces(self) -> list[dict]:
        return [{
            "id": s.id,
            "fuse_mounted": s.fuse_mounted,
            "mode": s.mode,
            "mountpoint": s.mountpoint,
            "mounts": s.mounts,
            "runtime": s.runtime_type.value if s.runtime_type else None,
        } for s in self._sessions.values()]

    def exec(
        self,
        ws_id: str,
        command: str,
        cwd: str | None = None,
        stdin: bytes | None = None,
        input_files: dict[str, tuple[str, bytes | None]] | None = None,
    ) -> tuple[bool, str, dict[str, bytes] | None, dict[str, str] | None]:
        session = self._get_session(ws_id)
        if cwd is not None:
            session.cwd = cwd

        cache_status: dict[str, str] = {}
        if input_files:
            for path, (checksum, data) in input_files.items():
                hit, _ = self._file_cache.get(ws_id, path, checksum)
                if hit:
                    cache_status[path] = "hit"
                elif data is not None:
                    self._file_cache.put(ws_id, path, checksum, data)
                    session.ws.write(path, data)
                    cache_status[path] = "miss"
                else:
                    return (False, f"cache miss: {path}", None, None)

        cmd_name = command.strip().split()[0] if command.strip() else ""
        session.command_stats.total_commands += 1
        session.command_stats.command_counts[cmd_name] = (
            session.command_stats.command_counts.get(cmd_name, 0) + 1)
        session.command_stats.last_command = command
        session.command_stats.last_timestamp = datetime.now(
            timezone.utc).isoformat()
        t0 = time.monotonic()
        try:
            if session.runtime_type is not None and cmd_name in _BLOCKED:
                raise CommandNotAllowedError(
                    f"{cmd_name!r} is not allowed in this runtime")
            output = session.registry.run(session.ws,
                                          command,
                                          cwd=session.cwd,
                                          stdin=stdin)
            duration_ms = int((time.monotonic() - t0) * 1000)
            if command.strip().startswith("cd "):
                parts = command.strip().split(None, 1)
                if len(parts) > 1:
                    session.cwd = nav.cd(session.ws, session.cwd,
                                         _resolve(session.cwd, parts[1]))
            args = command.strip().split()[1:] if command.strip() else []
            source = "builtin" if cmd_name in COMMANDS else "external"
            log = get_or_create_log(ws_id)
            entry = CommandEntry(
                timestamp=datetime.now(timezone.utc).isoformat(),
                raw=command,
                parsed=ParsedCommand(
                    pipeline=[command],
                    args={cmd_name: args},
                ),
                dispatch=[
                    DispatchInfo(
                        command=cmd_name,
                        handler=f"_{cmd_name}"
                        if source == "builtin" else cmd_name,
                        source=source,
                    )
                ],
                result=CommandResult(
                    exit_code=0,
                    stdout_bytes=len(output.encode()) if output else 0,
                    duration_ms=duration_ms,
                ),
            )
            log.write_command(entry)

            return (True, output, None, cache_status or None)
        except Exception as e:
            duration_ms = int((time.monotonic() - t0) * 1000)
            session.command_stats.total_errors += 1
            log = get_or_create_log(ws_id)
            entry = CommandEntry(
                timestamp=datetime.now(timezone.utc).isoformat(),
                raw=command,
                result=CommandResult(exit_code=1,
                                     stdout_bytes=0,
                                     duration_ms=duration_ms),
            )
            log.write_command(entry)
            return (False, str(e), None, None)

    def list_commands(self, ws_id: str) -> list[str]:
        session = self._get_session(ws_id)
        return session.registry.list_commands()

    def register_command(self,
                         ws_id: str,
                         name: str,
                         exec_str: str,
                         description: str = "") -> None:
        session = self._get_session(ws_id)
        session.registry.register(
            ExternalCommand(name=name, exec=exec_str, description=description))

    def sync(self, ws_id: str) -> list[dict]:
        session = self._get_session(ws_id)
        results = session.ws.sync()
        return [{"path": r.path, "status": r.status} for r in results]

    def status(self, ws_id: str) -> list[dict]:
        session = self._get_session(ws_id)
        inodes = session.ws.status()
        return [{
            "path": i.virtual_path,
            "dirty": i.dirty,
            "size": i.size
        } for i in inodes]

    # ── File I/O (backend-level) ─────────────────────────────────────────

    def io_read(self, ws_id: str, path: str, offset: int, size: int) -> bytes:
        session = self._get_session(ws_id)
        return session.ws.read(path, offset, size)

    def io_write(self, ws_id: str, path: str, offset: int, data: bytes) -> int:
        session = self._get_session(ws_id)
        backend, backend_path, _ = session.ws._registry.resolve(path)
        return backend.write(backend_path, offset, data)

    def io_stat(self, ws_id: str, path: str) -> FileStat:
        session = self._get_session(ws_id)
        return session.ws.stat(path)

    def io_readdir(self,
                   ws_id: str,
                   path: str,
                   cursor: str | None = None) -> tuple[list[str], str | None]:
        session = self._get_session(ws_id)
        backend, backend_path, _ = session.ws._registry.resolve(path)
        return backend.readdir(backend_path, cursor)

    def io_create(self, ws_id: str, path: str) -> None:
        session = self._get_session(ws_id)
        backend, backend_path, _ = session.ws._registry.resolve(path)
        backend.create(backend_path)

    def io_unlink(self, ws_id: str, path: str) -> None:
        session = self._get_session(ws_id)
        backend, backend_path, _ = session.ws._registry.resolve(path)
        backend.unlink(backend_path)

    def io_mkdir(self, ws_id: str, path: str) -> None:
        session = self._get_session(ws_id)
        backend, backend_path, _ = session.ws._registry.resolve(path)
        backend.mkdir(backend_path)

    def io_rmdir(self, ws_id: str, path: str) -> None:
        session = self._get_session(ws_id)
        backend, backend_path, _ = session.ws._registry.resolve(path)
        backend.rmdir(backend_path)

    def io_rename(self, ws_id: str, src: str, dst: str) -> None:
        session = self._get_session(ws_id)
        backend, src_path, _ = session.ws._registry.resolve(src)
        _, dst_path, _ = session.ws._registry.resolve(dst)
        backend.rename(src_path, dst_path)

    def io_truncate(self, ws_id: str, path: str, size: int) -> None:
        session = self._get_session(ws_id)
        backend, backend_path, _ = session.ws._registry.resolve(path)
        backend.truncate(backend_path, size)

    def io_fuse_cat(self, ws_id: str, path: str) -> bytes:
        session = self._get_session(ws_id)
        st = session.ws.stat(path)
        op = session.fuse_registry.resolve(path, st.size or 0, session.ws)
        ctx = op.on_open(session.ws, path, st.size or 0)
        return op.read(session.ws, path, 0, st.size or 0, ctx)

    # ── FuseOp management ────────────────────────────────────────────────

    def list_fuse_ops(self, ws_id: str) -> list[dict]:
        session = self._get_session(ws_id)
        return session.fuse_registry.list_ops()

    def register_fuse_op(self, ws_id: str, pattern: str, handler: str) -> None:
        session = self._get_session(ws_id)
        op = FUSE_OPS.get(handler)
        if op is None:
            try:
                cls = load_fuse_op_class(handler)
                op = cls()
            except (ValueError, Exception) as e:
                raise ValueError(f"unknown handler: {handler} ({e})")
        session.fuse_registry.register(pattern, op)

    # ── FUSE-specific (not part of MirageService ABC) ────────────────────

    def register_fuse(self,
                      mountpoint: str,
                      pid: int,
                      mount_specs: list[str] | None = None,
                      runtime: str | None = None) -> str:
        fuse_mounts: list[dict] = []
        for spec in (mount_specs or []):
            try:
                uri, prefix = split_mount_spec(spec)
                fuse_mounts.append({"prefix": prefix, "uri": uri})
            except ValueError:
                pass
        ws_id = str(uuid.uuid4())[:8]
        rt_type = RuntimeType(runtime) if runtime else None
        self._sessions[ws_id] = WorkspaceSession(
            id=ws_id,
            ws=None,
            registry=None,
            fuse_mounted=True,
            mountpoint=mountpoint,
            pid=pid,
            mounts=fuse_mounts,
            runtime_type=rt_type,
        )
        mount_info = {m["prefix"]: {"type": m["uri"]} for m in fuse_mounts}
        log = get_or_create_log(ws_id)
        session_entry = SessionEntry(
            timestamp=datetime.now(timezone.utc).isoformat(),
            workspace=WorkspaceInfo(
                mounts=mount_info,
                runtime_type=rt_type.value if rt_type else None,
            ),
        )
        log.write_session(session_entry)
        return ws_id

    def report_fuse_stats(self,
                          mountpoint: str,
                          status: dict,
                          transfers: dict | None = None,
                          ops: list[dict] | None = None) -> bool:
        for s in self._sessions.values():
            if s.fuse_mounted and s.mountpoint == mountpoint:
                s.reported_status = status
                s.reported_transfers = transfers or {}
                if ops:
                    log = get_or_create_log(s.id)
                    for op in ops:
                        log._append(op)
                return True
        return False

-from mirage.types import (FileStat, MountMode, RuntimeType, SyncPolicy)

+from mirage.types import (FileStat, MountMode, RuntimeType)


Now the runtime files:


     1→from mirage.backend.local.local import LocalBackend
     2→from mirage.commands.custom.registry import CommandRegistry
     3→from mirage.runtime.base import CommandNotAllowedError, Runtime
     4→from mirage.types import MountMode, SyncPolicy
     5→from mirage.workspace import Workspace
     6→
     7→
     8→class LocalRuntime(Runtime):
     9→
    10→    def __init__(self,

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

from mirage.backend.local.local import LocalBackend
from mirage.commands.custom.registry import CommandRegistry
from mirage.runtime.base import CommandNotAllowedError, Runtime
from mirage.types import MountMode, SyncPolicy
from mirage.workspace import Workspace

class LocalRuntime(Runtime):

    def __init__(self,


     1→import shlex
     2→
     3→import httpx
     4→
     5→from mirage.backend.network.proxy import ProxyBackend
     6→from mirage.runtime.accessors.remote import (RemoteCommandsAccessor,
     7→                                             RemoteFuseOpsAccessor,
     8→                                             RemoteWorkspaceOpsAccessor)
     9→from mirage.runtime.base import _BLOCKED, CommandNotAllowedError, Runtime
    10→from mirage.server import routes
    11→from mirage.types import MountMode, SyncPolicy
    12→from mirage.workspace import Workspace
    13→
    14→
    15→class RemoteRuntime(Runtime):

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

import shlex

import httpx

from mirage.backend.network.proxy import ProxyBackend
from mirage.runtime.accessors.remote import (RemoteCommandsAccessor,
                                             RemoteFuseOpsAccessor,
                                             RemoteWorkspaceOpsAccessor)
from mirage.runtime.base import _BLOCKED, CommandNotAllowedError, Runtime
from mirage.server import routes
from mirage.types import MountMode, SyncPolicy
from mirage.workspace import Workspace

class RemoteRuntime(Runtime):


from mirage.types import MountMode, SyncPolicy
from mirage.workspace import Workspace

from mirage.types import MountMode
from mirage.workspace import SyncPolicy, Workspace


The file /Users/agent/strukto/mirage/mirage/runtime/local.py has been updated successfully.

from mirage.types import MountMode
from mirage.workspace import SyncPolicy, Workspace

from mirage.backend.local.local import LocalBackend
from mirage.commands.custom.registry import CommandRegistry
from mirage.runtime.base import CommandNotAllowedError, Runtime
from mirage.types import MountMode, SyncPolicy
from mirage.workspace import Workspace

class LocalRuntime(Runtime):

    def __init__(self,
                 root: str,
                 registry: CommandRegistry | None = None,
                 mode: MountMode = MountMode.WRITE) -> None:
        backend = LocalBackend(root)
        ws = Workspace({"/": backend},
                       mode=mode,
                       sync_policy=SyncPolicy.IMMEDIATE)
        super().__init__(ws, registry)

__all__ = ["CommandNotAllowedError", "LocalRuntime"]

+from mirage.workspace import SyncPolicy, Workspace


from mirage.types import MountMode, SyncPolicy
from mirage.workspace import Workspace

from mirage.types import MountMode
from mirage.workspace import SyncPolicy, Workspace


The file /Users/agent/strukto/mirage/mirage/runtime/remote.py has been updated successfully.

import shlex

import httpx

from mirage.backend.network.proxy import ProxyBackend
from mirage.runtime.accessors.remote import (RemoteCommandsAccessor,
                                             RemoteFuseOpsAccessor,
                                             RemoteWorkspaceOpsAccessor)
from mirage.runtime.base import _BLOCKED, CommandNotAllowedError, Runtime
from mirage.server import routes
from mirage.types import MountMode, SyncPolicy
from mirage.workspace import Workspace

class RemoteRuntime(Runtime):

    def __init__(self,
                 url: str,
                 ws_id: str,
                 agent_id: str | None = None,
                 timeout: int = 30,
                 http_client: httpx.Client | None = None) -> None:
        self._url = url.rstrip("/")
        self._ws_id = ws_id
        backend = ProxyBackend(url, ws_id, timeout, http_client=http_client)
        ws = Workspace({"/": backend},
                       mode=MountMode.WRITE,
                       sync_policy=SyncPolicy.IMMEDIATE)
        self._http = http_client or httpx.Client(base_url=self._url,
                                                 timeout=timeout)
        super().__init__(ws, registry=None, agent_id=agent_id)
        self.commands = RemoteCommandsAccessor(self._http, ws_id)
        self.fuse_ops = RemoteFuseOpsAccessor(self._http, ws_id)
        self.workspace = RemoteWorkspaceOpsAccessor(self._http, ws_id)

    def run(self, command: str) -> str:
        parts = shlex.split(command)
        if not parts:
            return ""
        cmd = parts[0]
        if cmd in _BLOCKED:
            raise CommandNotAllowedError(f"{cmd!r} is not allowed in Runtime.")
        if cmd == "cd":
            return self._handle_cd(parts[1:])
        if cmd == "whoami":
            return self._whoami()
        if cmd == "identify":
            if parts[1:]:
                self.agent_id = " ".join(parts[1:])
            return self.agent_id or ""
        resp = self._http.post(routes.WORKSPACE_EXEC.format(ws_id=self._ws_id),
                               json={
                                   "command": command,
                                   "cwd": self._cwd
                               })
        data = resp.json()
        if not data.get("ok"):
            raise RuntimeError(data.get("error", "unknown error"))
        return data.get("output", "")

    def _handle_cd(self, argv: list[str]) -> str:
        from mirage.commands import _resolve
        from mirage.commands.builtin import nav
        if not argv:
            self._cwd = "/"
            return ""
        self._cwd = nav.cd(self.ws, self._cwd, _resolve(self._cwd, argv[0]))
        return ""


Now the examples and tests. I'll do them in parallel:


     1→"""
     2→Example: R2Backend + MemoryRuntime
     3→
     4→Demonstrates read commands against a real Cloudflare R2 bucket.
     5→Requires: uv sync --extra r2

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

"""
Example: R2Backend + MemoryRuntime

Demonstrates read commands against a real Cloudflare R2 bucket.
Requires: uv sync --extra r2


     1→"""
     2→Example: LocalBackend + MemoryRuntime
     3→
     4→Demonstrates commands over a real local directory.
     5→Uses a temp directory that is cleaned up after the script exits.

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

"""
Example: LocalBackend + MemoryRuntime

Demonstrates commands over a real local directory.
Uses a temp directory that is cleaned up after the script exits.


     1→"""
     2→Example: MemoryBackend + MemoryRuntime
     3→
     4→Demonstrates all command categories using an in-memory filesystem.
     5→No files are created on disk. No external dependencies required.

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

"""
Example: MemoryBackend + MemoryRuntime

Demonstrates all command categories using an in-memory filesystem.
No files are created on disk. No external dependencies required.


     1→import pytest
     2→
     3→from mirage.backend.local.memory import MemoryBackend
     4→from mirage.types import MountMode, SyncPolicy
     5→from mirage.workspace import Workspace
     6→
     7→
     8→@pytest.fixture
     9→def memory_backend():
    10→    return MemoryBackend()

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

import pytest

from mirage.backend.local.memory import MemoryBackend
from mirage.types import MountMode, SyncPolicy
from mirage.workspace import Workspace

@pytest.fixture
def memory_backend():
    return MemoryBackend()


No matches found


examples/r2.py:14:from mirage import MountMode, SyncPolicy, Workspace
examples/r2.py:33:    sync_policy=SyncPolicy.IMMEDIATE,
examples/local.py:11:from mirage import LocalBackend, MountMode, SyncPolicy, Workspace
examples/local.py:19:        sync_policy=SyncPolicy.IMMEDIATE,  # writes go to disk immediately
examples/memory.py:8:from mirage import MemoryBackend, MountMode, SyncPolicy, Workspace
examples/memory.py:13:    sync_policy=SyncPolicy.IMMEDIATE,


The examples import `SyncPolicy` from `mirage` (top-level), not from `mirage.types`. Since `mirage/__init__.py` now re-exports `SyncPolicy` from `mirage.workspace`, these examples will continue to work without any change.

Let me verify that `mirage/__init__.py` still exports `SyncPolicy`:

```python
from mirage.types import FileStat, Inode, MountMode, SyncResult
from mirage.workspace import SyncPolicy
```

Yes, `SyncPolicy` is still in `mirage.__init__`, re-exported from `mirage.workspace`.

The examples are fine as-is, but I need to go through the test files and update their imports since they're pulling `SyncPolicy` directly from `mirage.types` instead of `mirage.workspace`.


Examples import from top-level `mirage` which still re-exports `SyncPolicy` — no changes needed there. Now update test files:


from mirage.types import MountMode, SyncPolicy

from mirage.types import MountMode
from mirage.workspace import SyncPolicy


The file /Users/agent/strukto/mirage/tests/conftest.py has been updated successfully.

from mirage.types import MountMode
from mirage.workspace import SyncPolicy

import pytest

from mirage.backend.local.memory import MemoryBackend
from mirage.types import MountMode, SyncPolicy
from mirage.workspace import Workspace

@pytest.fixture
def memory_backend():
    return MemoryBackend()

@pytest.fixture
def write_ws():
    return Workspace(
        {"/tmp/": MemoryBackend()},
        mode=MountMode.WRITE,
        sync_policy=SyncPolicy.IMMEDIATE,
    )

@pytest.fixture
def staged_ws():
    return Workspace(
        {"/tmp/": MemoryBackend()},
        mode=MountMode.WRITE,
        sync_policy=SyncPolicy.STAGED,
    )

+from mirage.workspace import SyncPolicy


tests/workspace/test_workspace.py:6:from mirage.types import MountMode, SyncPolicy
tests/runtime/test_base.py:5:from mirage.types import MountMode, SyncPolicy
tests/observe/test_inspector.py:7:from mirage.types import CommandStats, MountMode, SyncPolicy
tests/runtime/test_memory.py:5:from mirage.types import MountMode, SyncPolicy
tests/commands/builtin/test_read.py:7:from mirage.types import FileType, MountMode, SyncPolicy
tests/commands/custom/test_arg_resolver.py:3:from mirage.types import MountMode, SyncPolicy
tests/integration/test_remote_transfer.py:6:from mirage.types import CommandResult, MountMode, SyncPolicy
tests/fuse/remote/test_remote.py:5:from mirage.types import MountMode, SyncPolicy


I need to update 8 test files. Let me also check `test_registry.py` which was in the original list.


11:                          SyncPolicy)
29:                   sync_policy=SyncPolicy.IMMEDIATE)
88:                   sync_policy=SyncPolicy.IMMEDIATE)
180:                   sync_policy=SyncPolicy.IMMEDIATE)
208:                   sync_policy=SyncPolicy.IMMEDIATE)
268:                   sync_policy=SyncPolicy.IMMEDIATE)
288:                   sync_policy=SyncPolicy.IMMEDIATE)
305:                   sync_policy=SyncPolicy.IMMEDIATE)
324:                   sync_policy=SyncPolicy.IMMEDIATE)
356:                   sync_policy=SyncPolicy.IMMEDIATE)
382:                   sync_policy=SyncPolicy.IMMEDIATE)
413:                   sync_policy=SyncPolicy.IMMEDIATE)
426:                   sync_policy=SyncPolicy.IMMEDIATE)


     1→import sys
     2→from unittest.mock import MagicMock
     3→
     4→import pytest
     5→from pydantic import ValidationError
     6→
     7→from mirage.backend.local.memory import MemoryBackend
     8→from mirage.commands.custom.registry import CommandRegistry, ExternalCommand
     9→from mirage.commands.remote.client import CommandClient
    10→from mirage.types import (CommandResult, MountMode, RemoteCommandOptions,
    11→                          SyncPolicy)
    12→from mirage.workspace import Workspace
    13→
    14→
    15→def test_external_command_fields():

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

import sys
from unittest.mock import MagicMock

import pytest
from pydantic import ValidationError

from mirage.backend.local.memory import MemoryBackend
from mirage.commands.custom.registry import CommandRegistry, ExternalCommand
from mirage.commands.remote.client import CommandClient
from mirage.types import (CommandResult, MountMode, RemoteCommandOptions,
                          SyncPolicy)
from mirage.workspace import Workspace

def test_external_command_fields():


Now I'll update all 9 test files at once:


from mirage.types import MountMode, SyncPolicy

from mirage.types import MountMode
from mirage.workspace import SyncPolicy


<tool_use_error>File has not been read yet. Read it first before writing to it.</tool_use_error>

Error: File has not been read yet. Read it first before writing to it.


Bash

head -10 tests/workspace/test_workspace.py tests/runtime/test_base.py tests/observe/test_inspector.py tests/runtime/test_memory.py tests/commands/builtin/test_read.py tests/commands/custom/test_arg_resolver.py tests/integration/test_remote_transfer.py tests/fuse/remote/test_remote.py

Read import lines of all test files


==> tests/workspace/test_workspace.py <==
from datetime import datetime, timezone

import pytest

from mirage.backend.local.memory import MemoryBackend
from mirage.types import MountMode, SyncPolicy
from mirage.workspace import Workspace
from mirage.workspace.consistency import ConsistencyPolicy

==> tests/runtime/test_base.py <==
import pytest

from mirage.backend.local.memory import MemoryBackend
from mirage.runtime.base import CommandNotAllowedError, Runtime
from mirage.types import MountMode, SyncPolicy
from mirage.workspace import Workspace

@pytest.fixture
def runtime():

==> tests/observe/test_inspector.py <==
from dataclasses import dataclass, field

from mirage.backend.local.memory import MemoryBackend
from mirage.commands import COMMANDS
from mirage.commands.custom.registry import CommandRegistry
from mirage.observe import inspector
from mirage.types import CommandStats, MountMode, SyncPolicy
from mirage.workspace import Workspace

==> tests/runtime/test_memory.py <==
import pytest

from mirage.backend.local.memory import MemoryBackend
from mirage.runtime.memory import MemoryRuntime
from mirage.types import MountMode, SyncPolicy
from mirage.workspace import Workspace

@pytest.fixture
def runtime():

==> tests/commands/builtin/test_read.py <==
import hashlib

import pytest

from mirage.backend.local.local import LocalBackend
from mirage.commands.builtin.read import cat, diff, file, head, md5, tail, wc
from mirage.types import FileType, MountMode, SyncPolicy
from mirage.workspace import Workspace

==> tests/commands/custom/test_arg_resolver.py <==
from mirage.backend.local.memory import MemoryBackend
from mirage.commands.custom.arg_resolver import classify_args
from mirage.types import MountMode, SyncPolicy
from mirage.workspace import Workspace

def test_classify_input_file():
    ws = Workspace({"/data/": MemoryBackend()},
                   mode=MountMode.WRITE,
                   sync_policy=SyncPolicy.IMMEDIATE)

==> tests/integration/test_remote_transfer.py <==
from unittest.mock import MagicMock

from mirage.backend.local.memory import MemoryBackend
from mirage.commands.custom.registry import CommandRegistry, ExternalCommand
from mirage.commands.remote.client import CommandClient
from mirage.types import CommandResult, MountMode, SyncPolicy
from mirage.workspace import Workspace

def _fake_run_transform(command, cwd="/", stdin=None, files=None):

==> tests/fuse/remote/test_remote.py <==
from unittest.mock import MagicMock

from mirage.backend.local.memory import MemoryBackend
from mirage.fuse.remote.remote import RemoteFuseOp
from mirage.types import MountMode, SyncPolicy
from mirage.workspace import Workspace

def test_remote_on_open_sends_file():
    mock_client = MagicMock()


Now I can do all the edits. Since `from mirage.workspace import Workspace` is already in each file, I'll just append `SyncPolicy` to that import:


python -c "
import re, sys

files = [
    'tests/workspace/test_workspace.py',
    'tests/runtime/test_base.py',
    'tests/runtime/test_memory.py',
    'tests/commands/builtin/test_read.py',
    'tests/commands/custom/test_arg_resolver.py',
    'tests/integration/test_remote_transfer.py',
    'tests/fuse/remote/test_remote.py',
]

for path in files:
    with open(path) as f:
        content = f.read()
    # Remove SyncPolicy from mirage.types import line
    content = re.sub(r'from mirage\.types import (.*?), SyncPolicy(.*?\n)', lambda m: 'from mirage.types import ' + m.group(1) + m.group(2), content)
    content = re.sub(r'from mirage\.types import SyncPolicy, (.*?\n)', lambda m: 'from mirage.types import ' + m.group(1), content)
    # Add SyncPolicy to workspace import
    content = content.replace('from mirage.workspace import Workspace\n', 'from mirage.workspace import SyncPolicy, Workspace\n')
    with open(path, 'w') as f:
        f.write(content)
    print(f'Updated {path}')
"

Update SyncPolicy imports in 7 test files


Updated tests/workspace/test_workspace.py
Updated tests/runtime/test_base.py
Updated tests/runtime/test_memory.py
Updated tests/commands/builtin/test_read.py
Updated tests/commands/custom/test_arg_resolver.py
Updated tests/integration/test_remote_transfer.py
Updated tests/fuse/remote/test_remote.py


Now handle `test_inspector.py` (has both `CommandStats` and `SyncPolicy`) and `test_registry.py` (SyncPolicy in multi-line import):


     1→from dataclasses import dataclass, field
     2→
     3→from mirage.backend.local.memory import MemoryBackend
     4→from mirage.commands import COMMANDS
     5→from mirage.commands.custom.registry import CommandRegistry
     6→from mirage.observe import inspector
     7→from mirage.types import CommandStats, MountMode, SyncPolicy
     8→from mirage.workspace import Workspace
     9→
    10→
    11→@dataclass
    12→class _FakeSession:

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

from dataclasses import dataclass, field

from mirage.backend.local.memory import MemoryBackend
from mirage.commands import COMMANDS
from mirage.commands.custom.registry import CommandRegistry
from mirage.observe import inspector
from mirage.types import CommandStats, MountMode, SyncPolicy
from mirage.workspace import Workspace

@dataclass
class _FakeSession:


`test_inspector.py` has both `CommandStats` and `SyncPolicy` in the same import. I'll handle this when I do Task 2 (move CommandStats). For now, I just need to handle the `SyncPolicy` part. But since `CommandStats` is still in `mirage.types` at this point, I'll just update the `SyncPolicy` part first:

Change:
```python
from mirage.types import CommandStats, MountMode, SyncPolicy
from mirage.workspace import Workspace
```
To:
```python
from mirage.types import CommandStats, MountMode

from mirage.workspace import SyncPolicy, Workspace
```

Actually, I'll do both tasks for this file at the same time to avoid multiple edits. Let me just continue with Task 1 for now and handle CommandStats later.


Edit

from mirage.types import CommandStats, MountMode, SyncPolicy
from mirage.workspace import Workspace

from mirage.types import CommandStats, MountMode
from mirage.workspace import SyncPolicy, Workspace


The file /Users/agent/strukto/mirage/tests/observe/test_inspector.py has been updated successfully.

from mirage.types import CommandStats, MountMode
from mirage.workspace import SyncPolicy, Workspace

from dataclasses import dataclass, field

from mirage.backend.local.memory import MemoryBackend
from mirage.commands import COMMANDS
from mirage.commands.custom.registry import CommandRegistry
from mirage.observe import inspector
from mirage.types import CommandStats, MountMode, SyncPolicy
from mirage.workspace import Workspace

@dataclass
class _FakeSession:
    id: str = "test-ws"
    ws: Workspace | None = None
    registry: CommandRegistry | None = None
    cwd: str = "/"
    fuse_mounted: bool = False
    mode: str = "write"
    mountpoint: str | None = None
    pid: int | None = None
    mounts: list[dict] = field(default_factory=list)
    command_stats: CommandStats = field(default_factory=CommandStats)

def _make_session() -> _FakeSession:
    ws = Workspace(
        {"/tmp/": MemoryBackend()},
        mode=MountMode.WRITE,
        sync_policy=SyncPolicy.STAGED,
    )
    return _FakeSession(ws=ws, registry=CommandRegistry())

def test_global_status():
    session = _make_session()
    sessions = {"ws1": session}
    result = inspector.global_status(sessions)
    assert "rss_bytes" in result
    assert result["total_sessions"] == 1
    assert result["total_cache_bytes"] == 0
    assert "uptime_seconds" in result

def test_list_sessions():
    session = _make_session()
    sessions = {"ws1": session}
    result = inspector.list_sessions(sessions)
    assert len(result) == 1
    assert result[0]["id"] == "test-ws"
    assert result[0]["cache_used"] == 0
    assert result[0]["total_commands"] == 0

def test_workspace_status():
    session = _make_session()
    session.command_stats.total_commands = 5
    session.command_stats.total_errors = 1
    session.command_stats.last_command = "cat /tmp/test"
    result = inspector.workspace_status(session)
    assert result["cache_used"] == 0
    assert result["dirty_inodes"] == 0
    assert result["total_commands"] == 5
    assert result["total_errors"] == 1
    assert result["last_command"] == "cat /tmp/test"
    assert len(result["backends"]) == 1
    assert result["backends"][0]["backend"] == "MemoryBackend"

def test_workspace_commands():
    session = _make_session()
    result = inspector.workspace_commands(session)
    names = {c["name"] for c in result}
    assert "cat" in names
    assert "ls" in names
    assert "grep" in names
    assert len(result) >= len(COMMANDS)
    for cmd in result:
        assert "source" in cmd
        assert "cost_level" in cmd

def test_workspace_memory():
    session = _make_session()
    session.ws.write("/tmp/hello.txt", b"hello world")
    result = inspector.workspace_memory(session)
    assert result["cache"]["used"] > 0
    assert result["cache"]["entry_count"] == 1
    assert "/tmp/hello.txt" in result["cache"]["entries"]
    assert result["dirty_tracker"]["total_inodes"] == 1
    assert "/tmp/hello.txt" in result["dirty_tracker"]["dirty_paths"]
    assert "/tmp/" in result["backend_memory"]
    assert result["backend_memory"]["/tmp/"]["file_count"] == 0

def test_workspace_memory_with_synced_file():
    ws = Workspace(
        {"/tmp/": MemoryBackend()},
        mode=MountMode.WRITE,
        sync_policy=SyncPolicy.IMMEDIATE,
    )
    session = _FakeSession(ws=ws, registry=CommandRegistry())
    ws.write("/tmp/hello.txt", b"hello")
    result = inspector.workspace_memory(session)
    assert result["backend_memory"]["/tmp/"]["file_count"] == 1

def test_workspace_transfers():
    session = _make_session()
    session.ws.write("/tmp/a.txt", b"data")
    session.ws.cat("/tmp/a.txt")
    session.ws.cat("/tmp/a.txt")
    result = inspector.workspace_transfers(session)
    assert "/tmp/" in result
    stats = result["/tmp/"]
    assert stats["write_ops"] >= 1
    assert stats["read_ops"] >= 2
    assert stats["bytes_read"] > 0
    assert stats["cache_hit_rate"] > 0

-from mirage.types import CommandStats, MountMode, SyncPolicy

+from mirage.types import CommandStats, MountMode


Now `test_registry.py` with its multi-line import:


from mirage.types import (CommandResult, MountMode, RemoteCommandOptions,
                          SyncPolicy)
from mirage.workspace import Workspace

from mirage.types import (CommandResult, MountMode, RemoteCommandOptions)
from mirage.workspace import SyncPolicy, Workspace


The file /Users/agent/strukto/mirage/tests/commands/custom/test_registry.py has been updated successfully.

from mirage.types import (CommandResult, MountMode, RemoteCommandOptions)
from mirage.workspace import SyncPolicy, Workspace

import sys
from unittest.mock import MagicMock

import pytest
from pydantic import ValidationError

from mirage.backend.local.memory import MemoryBackend
from mirage.commands.custom.registry import CommandRegistry, ExternalCommand
from mirage.commands.remote.client import CommandClient
from mirage.types import (CommandResult, MountMode, RemoteCommandOptions,
                          SyncPolicy)
from mirage.workspace import Workspace

def test_external_command_fields():
    cmd = ExternalCommand(name="linecount", exec="python lc.py {file}")
    assert cmd.description == ""

def test_external_command_immutable():
    cmd = ExternalCommand(name="x", exec="echo {file}")
    with pytest.raises(ValidationError):
        cmd.name = "y"

def test_builtin_ls():
    ws = Workspace({"/tmp/": MemoryBackend()},
                   mode=MountMode.WRITE,
                   sync_policy=SyncPolicy.IMMEDIATE)
    ws.write("/tmp/a.txt", b"hi")
    reg = CommandRegistry()
    result = reg.run(ws, "ls /tmp/", cwd="/")
    assert "a.txt" in result

def test_register_external():
    reg = CommandRegistry()
    reg.register(ExternalCommand(name="echo-test", exec="echo hello"))
    assert "echo-test" in reg.list_commands()

def test_run_external_no_placeholder(tmp_path):
    reg = CommandRegistry()
    reg.register(ExternalCommand(name="greet", exec="echo hello"))
    ws = Workspace({"/tmp/": MemoryBackend()})
    result = reg.run(ws, "greet", cwd="/")
    assert "hello" in result

def test_run_external_file_placeholder(tmp_path):
    ws = Workspace({"/tmp/": MemoryBackend()}, mode=MountMode.WRITE)
    ws.write("/tmp/data.txt", b"line1\nline2")
    script = tmp_path / "count.py"
    script.write_text(
        "import sys; lines = open(sys.argv[1]).readlines(); print(len(lines))")
    reg = CommandRegistry()
    reg.register(
        ExternalCommand(name="linecount", exec=f"{sys.executable} {script}"))
    result = reg.run(ws, "linecount /tmp/data.txt", cwd="/")
    assert result.strip() == "2"

def test_unknown_command():
    reg = CommandRegistry()
    ws = Workspace({"/tmp/": MemoryBackend()})
    with pytest.raises(ValueError, match="unknown command"):
        reg.run(ws, "nonexistent", cwd="/")

def test_run_external_file_placeholder_multi_arg(tmp_path):
    ws = Workspace({"/tmp/": MemoryBackend()}, mode=MountMode.WRITE)
    ws.write("/tmp/a.txt", b"aaa")
    ws.write("/tmp/b.txt", b"bbb")
    script = tmp_path / "concat.py"
    script.write_text(
        "import sys; [print(open(f).read(), end='') for f in sys.argv[1:]]")
    reg = CommandRegistry()
    reg.register(
        ExternalCommand(name="concat", exec=f"{sys.executable} {script}"))
    result = reg.run(ws, "concat /tmp/a.txt /tmp/b.txt", cwd="/")
    assert "aaa" in result
    assert "bbb" in result

def test_external_overrides_builtin():
    ws = Workspace({"/tmp/": MemoryBackend()},
                   mode=MountMode.WRITE,
                   sync_policy=SyncPolicy.IMMEDIATE)
    ws.write("/tmp/file.txt", b"data")
    reg = CommandRegistry()
    reg.register(ExternalCommand(name="ls", exec="echo overridden"))
    result = reg.run(ws, "ls /tmp/", cwd="/")
    assert "overridden" in result
    assert "file.txt" not in result

class _CustomMethodBackend(MemoryBackend):

    def lllll(self, path: str) -> str:
        return f"custom-result-for:{path}"

    def bytes_method(self, path: str) -> bytes:
        return b"raw-bytes"

    def list_method(self, path: str) -> list:
        return ["item1", "item2", "item3"]

def test_backend_method_fallback():
    backend = _CustomMethodBackend()
    ws = Workspace({"/data/": backend}, mode=MountMode.WRITE)
    reg = CommandRegistry()
    result = reg.run(ws, "lllll /data/", cwd="/")
    assert "custom-result-for:" in result

def test_backend_method_fallback_bytes_coercion():
    backend = _CustomMethodBackend()
    ws = Workspace({"/data/": backend}, mode=MountMode.WRITE)
    reg = CommandRegistry()
    result = reg.run(ws, "bytes_method /data/", cwd="/")
    assert result == "raw-bytes"

def test_backend_method_fallback_list_coercion():
    backend = _CustomMethodBackend()
    ws = Workspace({"/data/": backend}, mode=MountMode.WRITE)
    reg = CommandRegistry()
    result = reg.run(ws, "list_method /data/", cwd="/")
    assert "item1\nitem2\nitem3" == result

def test_backend_private_method_rejected():
    backend = _CustomMethodBackend()
    ws = Workspace({"/data/": backend}, mode=MountMode.WRITE)
    reg = CommandRegistry()
    with pytest.raises(ValueError, match="unknown command"):
        reg.run(ws, "_files /data/", cwd="/")

def test_list_commands_includes_builtins():
    registry = CommandRegistry()
    cmds = registry.list_commands()
    assert "ls" in cmds
    assert "cat" in cmds

def test_run_builtin_cat():
    backend = MemoryBackend()
    backend.put("/hello.txt", b"hello world")
    ws = Workspace({"/data/": backend}, mode=MountMode.READ)
    result = CommandRegistry().run(ws, "cat /data/hello.txt", cwd="/")
    assert "hello world" in result

def test_external_command_with_options():
    cmd = ExternalCommand(
        name="transform",
        exec="transform",
        options=RemoteCommandOptions(max_file_size="500MB", cache="disabled"),
    )
    assert cmd.options.max_file_size == "500MB"
    assert cmd.options.cache == "disabled"

def test_external_command_default_options():
    cmd = ExternalCommand(name="echo-test", exec="echo hello")
    assert cmd.options.max_file_size == "100MB"

def test_external_command_default_options_not_none():
    cmd = ExternalCommand(name="echo-test", exec="echo hello")
    assert cmd.options is not None
    assert cmd.options.max_file_size == "100MB"

def test_run_external_out_placeholder(tmp_path):
    ws = Workspace({"/tmp/": MemoryBackend()},
                   mode=MountMode.WRITE,
                   sync_policy=SyncPolicy.IMMEDIATE)
    ws.write("/tmp/input.txt", b"hello world")
    script = tmp_path / "upper.py"
    script.write_text("import sys\n"
                      "data = open(sys.argv[1]).read()\n"
                      "open(sys.argv[2], 'w').write(data.upper())\n"
                      "print('done')\n")
    reg = CommandRegistry()
    reg.register(
        ExternalCommand(
            name="upper",
            exec=f"{sys.executable} {script}",
        ))
    result = reg.run(ws, "upper /tmp/input.txt /tmp/output.txt", cwd="/")
    assert "done" in result
    output = ws.cat("/tmp/output.txt")
    assert output == b"HELLO WORLD"

def test_registry_dispatches_to_client_with_files():
    mock_client = MagicMock(spec=CommandClient)
    mock_client.run.return_value = CommandResult(
        stdout="done",
        output_files={"/tmp/out.csv": b"result"},
    )

    ws = Workspace({"/tmp/": MemoryBackend()},
                   mode=MountMode.WRITE,
                   sync_policy=SyncPolicy.IMMEDIATE)
    ws.write("/tmp/input.json", b'{"data": true}')

    reg = CommandRegistry(client=mock_client)
    reg.register(ExternalCommand(
        name="transform",
        exec="transform",
    ))
    result = reg.run(ws, "transform /tmp/input.json /tmp/out.csv", cwd="/")
    assert "done" in result

    call_kwargs = mock_client.run.call_args
    assert call_kwargs.kwargs.get("files") is not None
    files = call_kwargs.kwargs["files"]
    assert "/tmp/input.json" in files
    assert files["/tmp/input.json"].data == b'{"data": true}'
    assert files["/tmp/input.json"].checksum is not None

    output = ws.cat("/tmp/out.csv")
    assert output == b"result"

def test_registry_dispatches_to_client_with_stdin():
    mock_client = MagicMock(spec=CommandClient)
    mock_client.run.return_value = CommandResult(stdout="processed")

    ws = Workspace({"/tmp/": MemoryBackend()})
    reg = CommandRegistry(client=mock_client)
    reg.register(ExternalCommand(name="process", exec="process"))
    result = reg.run(ws, "process", cwd="/", stdin=b"pipe input")
    assert "processed" in result
    call_kwargs = mock_client.run.call_args
    assert call_kwargs.kwargs.get("stdin") == b"pipe input"

def test_registry_client_no_placeholders_still_uses_client():
    mock_client = MagicMock(spec=CommandClient)
    mock_client.run.return_value = CommandResult(stdout="remote echo")

    ws = Workspace({"/tmp/": MemoryBackend()})
    reg = CommandRegistry(client=mock_client)
    reg.register(ExternalCommand(name="remote-echo", exec="echo hello"))
    result = reg.run(ws, "remote-echo", cwd="/")
    assert "remote echo" in result
    mock_client.run.assert_called_once()

def test_registry_out_to_readonly_mount_fails():
    mock_client = MagicMock(spec=CommandClient)
    ws = Workspace({"/data/": MemoryBackend()}, mode=MountMode.READ)
    reg = CommandRegistry(client=mock_client)
    reg.register(ExternalCommand(name="transform", exec="transform"))
    with pytest.raises(PermissionError, match="read-only"):
        reg.run(ws, "transform /data/in.json /data/out.csv", cwd="/")

def test_registry_rejects_oversized_file():
    mock_client = MagicMock(spec=CommandClient)
    ws = Workspace({"/tmp/": MemoryBackend()},
                   mode=MountMode.WRITE,
                   sync_policy=SyncPolicy.IMMEDIATE)
    ws.write("/tmp/big.bin", b"x" * 200)

    reg = CommandRegistry(client=mock_client)
    reg.register(
        ExternalCommand(
            name="process",
            exec="process",
            options=RemoteCommandOptions(max_file_size="100B"),
        ))
    with pytest.raises(ValueError, match="exceeds max"):
        reg.run(ws, "process /tmp/big.bin", cwd="/")

def test_registry_allows_file_within_size_limit():
    mock_client = MagicMock(spec=CommandClient)
    mock_client.run.return_value = CommandResult(stdout="ok")

    ws = Workspace({"/tmp/": MemoryBackend()},
                   mode=MountMode.WRITE,
                   sync_policy=SyncPolicy.IMMEDIATE)
    ws.write("/tmp/small.txt", b"small")

    reg = CommandRegistry(client=mock_client)
    reg.register(
        ExternalCommand(
            name="process",
            exec="process",
            options=RemoteCommandOptions(max_file_size="100B"),
        ))
    result = reg.run(ws, "process /tmp/small.txt", cwd="/")
    assert "ok" in result

def test_run_external_no_template_input_output(tmp_path):
    ws = Workspace({"/tmp/": MemoryBackend()},
                   mode=MountMode.WRITE,
                   sync_policy=SyncPolicy.IMMEDIATE)
    ws.write("/tmp/input.txt", b"hello world")
    script = tmp_path / "upper.py"
    script.write_text("import sys\n"
                      "data = open(sys.argv[1]).read()\n"
                      "open(sys.argv[2], 'w').write(data.upper())\n"
                      "print('done')\n")
    reg = CommandRegistry()
    reg.register(
        ExternalCommand(name="upper", exec=f"{sys.executable} {script}"))
    result = reg.run(ws, "upper /tmp/input.txt /tmp/output.txt", cwd="/")
    assert "done" in result
    output = ws.cat("/tmp/output.txt")
    assert output == b"HELLO WORLD"

def test_run_external_no_template_inplace(tmp_path):
    ws = Workspace({"/tmp/": MemoryBackend()},
                   mode=MountMode.WRITE,
                   sync_policy=SyncPolicy.IMMEDIATE)
    ws.write("/tmp/data.txt", b"hello")
    script = tmp_path / "inplace.py"
    script.write_text("import sys\n"
                      "path = sys.argv[1]\n"
                      "data = open(path).read()\n"
                      "open(path, 'w').write(data.upper())\n"
                      "print('done')\n")
    reg = CommandRegistry()
    reg.register(
        ExternalCommand(name="format", exec=f"{sys.executable} {script}"))
    result = reg.run(ws, "format /tmp/data.txt", cwd="/")
    assert "done" in result
    assert ws.cat("/tmp/data.txt") == b"HELLO"

def test_run_external_no_template_no_files():
    ws = Workspace({"/tmp/": MemoryBackend()})
    reg = CommandRegistry()
    reg.register(ExternalCommand(name="greet", exec="echo"))
    result = reg.run(ws, "greet hello world", cwd="/")
    assert "hello world" in result

def test_dispatch_auto_detect_input_and_output():
    mock_client = MagicMock(spec=CommandClient)
    mock_client.run.return_value = CommandResult(
        stdout="done",
        output_files={"/tmp/out.csv": b"result"},
    )
    ws = Workspace({"/tmp/": MemoryBackend()},
                   mode=MountMode.WRITE,
                   sync_policy=SyncPolicy.IMMEDIATE)
    ws.write("/tmp/input.json", b'{"data": true}')

    reg = CommandRegistry(client=mock_client)
    reg.register(ExternalCommand(name="transform", exec="transform"))
    result = reg.run(ws, "transform /tmp/input.json /tmp/out.csv", cwd="/")
    assert "done" in result

    call_kwargs = mock_client.run.call_args
    files = call_kwargs.kwargs.get("files")
    assert files is not None
    assert "/tmp/input.json" in files
    assert files["/tmp/input.json"].data == b'{"data": true}'

    output = ws.cat("/tmp/out.csv")
    assert output == b"result"

def test_dispatch_auto_detect_inplace():
    mock_client = MagicMock(spec=CommandClient)
    mock_client.run.return_value = CommandResult(
        stdout="formatted",
        output_files={"/tmp/data.json": b'{"formatted": true}'},
    )
    ws = Workspace({"/tmp/": MemoryBackend()},
                   mode=MountMode.WRITE,
                   sync_policy=SyncPolicy.IMMEDIATE)
    ws.write("/tmp/data.json", b'{"data": true}')

    reg = CommandRegistry(client=mock_client)
    reg.register(ExternalCommand(name="format", exec="format"))
    result = reg.run(ws, "format /tmp/data.json", cwd="/")
    assert "formatted" in result
    assert ws.cat("/tmp/data.json") == b'{"formatted": true}'

def test_dispatch_auto_detect_no_files():
    mock_client = MagicMock(spec=CommandClient)
    mock_client.run.return_value = CommandResult(stdout="hello")
    ws = Workspace({"/tmp/": MemoryBackend()})
    reg = CommandRegistry(client=mock_client)
    reg.register(ExternalCommand(name="echo", exec="echo"))
    result = reg.run(ws, "echo hello", cwd="/")
    assert "hello" in result

def test_dispatch_locks_paths_during_execution():
    mock_client = MagicMock(spec=CommandClient)
    locked_during_run = []

    def capture_locks(*args, **kwargs):
        locked_during_run.extend(list(ws._locked_paths))
        return CommandResult(stdout="ok")

    mock_client.run.side_effect = capture_locks
    ws = Workspace({"/tmp/": MemoryBackend()},
                   mode=MountMode.WRITE,
                   sync_policy=SyncPolicy.IMMEDIATE)
    ws.write("/tmp/file.txt", b"data")
    reg = CommandRegistry(client=mock_client)
    reg.register(ExternalCommand(name="process", exec="process"))
    reg.run(ws, "process /tmp/file.txt", cwd="/")
    assert "/tmp/file.txt" in locked_during_run
    assert len(ws._locked_paths) == 0

def test_dispatch_size_limit_enforced():
    mock_client = MagicMock(spec=CommandClient)
    ws = Workspace({"/tmp/": MemoryBackend()},
                   mode=MountMode.WRITE,
                   sync_policy=SyncPolicy.IMMEDIATE)
    ws.write("/tmp/big.bin", b"x" * 200)
    reg = CommandRegistry(client=mock_client)
    reg.register(
        ExternalCommand(
            name="process",
            exec="process",
            options=RemoteCommandOptions(max_file_size="100B"),
        ))
    with pytest.raises(ValueError, match="exceeds max"):
        reg.run(ws, "process /tmp/big.bin", cwd="/")

def test_dispatch_output_to_readonly_fails():
    mock_client = MagicMock(spec=CommandClient)
    ws = Workspace({"/data/": MemoryBackend()}, mode=MountMode.READ)
    reg = CommandRegistry(client=mock_client)
    reg.register(ExternalCommand(name="transform", exec="transform"))
    with pytest.raises(PermissionError, match="read-only"):
        reg.run(ws, "transform /data/in.json /data/out.csv", cwd="/")

-from mirage.types import (CommandResult, MountMode, RemoteCommandOptions,

+from mirage.types import (CommandResult, MountMode, RemoteCommandOptions)


Quick smoke test before continuing:


Bash

uv run python -c "from mirage.workspace.sync import SyncPolicy; from mirage.workspace import SyncPolicy as SP2; from mirage import SyncPolicy as SP3; print('OK', SyncPolicy.STAGED)"

Verify SyncPolicy importable from all paths


OK SyncPolicy.STAGED


TodoWrite

Move SyncPolicy to workspace/sync.py and update all import sites

Move CommandStats to server/service/session.py and update import sites

Remove dead Workspace._created_at field

Verify all tests pass


Todos have been modified successfully. Ensure that you continue to use the todo list to track your progress. Please proceed with the current tasks if applicable

Move SyncPolicy to workspace/sync.py and update all import sites

Move CommandStats to server/service/session.py and update import sites

Remove dead Workspace._created_at field

Verify all tests pass

Remove dead Workspace._created_at field

Verify all tests pass


**Task 2: Move `CommandStats` to `session.py`:**


     1→import os
     2→import signal
     3→import subprocess
     4→import sys
     5→import time
     6→
     7→from pydantic import BaseModel, ConfigDict, Field
     8→
     9→from mirage.commands.custom.registry import CommandRegistry
    10→from mirage.fuse.registry import FuseOpRegistry
    11→from mirage.types import CommandStats, MountMode, RuntimeType
    12→from mirage.workspace import Workspace
    13→
    14→
    15→class WorkspaceSession(BaseModel):
    16→    model_config = ConfigDict(arbitrary_types_allowed=True)
    17→
    18→    id: str
    19→    ws: Workspace | None
    20→    registry: CommandRegistry | None
    21→    cwd: str = "/"
    22→    fuse_mounted: bool = False
    23→    mode: MountMode = MountMode.WRITE
    24→    mountpoint: str | None = None
    25→    pid: int | None = None
    26→    mounts: list[dict] = Field(default_factory=list)
    27→    runtime_type: RuntimeType | None = None
    28→    fuse_registry: FuseOpRegistry = Field(default_factory=FuseOpRegistry)
    29→    command_stats: CommandStats = Field(default_factory=CommandStats)
    30→    created_at: float = Field(default_factory=time.time)
    31→    reported_status: dict | None = None
    32→    reported_transfers: dict | None = None
    33→
    34→
    35→def _unmount_fuse(mountpoint: str, pid: int | None) -> None:
    36→    if sys.platform == "darwin":
    37→        subprocess.run(["diskutil", "unmount", "force", mountpoint],
    38→                       capture_output=True)
    39→    else:
    40→        subprocess.run(["fusermount", "-u", mountpoint], capture_output=True)
    41→    if pid:
    42→        try:
    43→            os.kill(pid, signal.SIGTERM)
    44→        except ProcessLookupError:
    45→            pass
    46→

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

import os
import signal
import subprocess
import sys
import time

from pydantic import BaseModel, ConfigDict, Field

from mirage.commands.custom.registry import CommandRegistry
from mirage.fuse.registry import FuseOpRegistry
from mirage.types import CommandStats, MountMode, RuntimeType
from mirage.workspace import Workspace

class WorkspaceSession(BaseModel):
    model_config = ConfigDict(arbitrary_types_allowed=True)

    id: str
    ws: Workspace | None
    registry: CommandRegistry | None
    cwd: str = "/"
    fuse_mounted: bool = False
    mode: MountMode = MountMode.WRITE
    mountpoint: str | None = None
    pid: int | None = None
    mounts: list[dict] = Field(default_factory=list)
    runtime_type: RuntimeType | None = None
    fuse_registry: FuseOpRegistry = Field(default_factory=FuseOpRegistry)
    command_stats: CommandStats = Field(default_factory=CommandStats)
    created_at: float = Field(default_factory=time.time)
    reported_status: dict | None = None
    reported_transfers: dict | None = None

def _unmount_fuse(mountpoint: str, pid: int | None) -> None:
    if sys.platform == "darwin":
        subprocess.run(["diskutil", "unmount", "force", mountpoint],
                       capture_output=True)
    else:
        subprocess.run(["fusermount", "-u", mountpoint], capture_output=True)
    if pid:
        try:
            os.kill(pid, signal.SIGTERM)
        except ProcessLookupError:
            pass


Edit

from mirage.commands.custom.registry import CommandRegistry
from mirage.fuse.registry import FuseOpRegistry
from mirage.types import CommandStats, MountMode, RuntimeType
from mirage.workspace import Workspace

class WorkspaceSession(BaseModel):

from mirage.commands.custom.registry import CommandRegistry
from mirage.fuse.registry import FuseOpRegistry
from mirage.types import MountMode, RuntimeType
from mirage.workspace import Workspace

class CommandStats(BaseModel):
    total_commands: int = 0
    total_errors: int = 0
    last_command: str = ""
    last_timestamp: str = ""
    command_counts: dict[str, int] = Field(default_factory=dict)

class WorkspaceSession(BaseModel):


The file /Users/agent/strukto/mirage/mirage/server/service/session.py has been updated successfully.

from mirage.commands.custom.registry import CommandRegistry
from mirage.fuse.registry import FuseOpRegistry
from mirage.types import MountMode, RuntimeType
from mirage.workspace import Workspace

class CommandStats(BaseModel):
    total_commands: int = 0
    total_errors: int = 0
    last_command: str = ""
    last_timestamp: str = ""
    command_counts: dict[str, int] = Field(default_factory=dict)

class WorkspaceSession(BaseModel):

import os
import signal
import subprocess
import sys
import time

from pydantic import BaseModel, ConfigDict, Field

from mirage.commands.custom.registry import CommandRegistry
from mirage.fuse.registry import FuseOpRegistry
from mirage.types import CommandStats, MountMode, RuntimeType
from mirage.workspace import Workspace

class WorkspaceSession(BaseModel):
    model_config = ConfigDict(arbitrary_types_allowed=True)

    id: str
    ws: Workspace | None
    registry: CommandRegistry | None
    cwd: str = "/"
    fuse_mounted: bool = False
    mode: MountMode = MountMode.WRITE
    mountpoint: str | None = None
    pid: int | None = None
    mounts: list[dict] = Field(default_factory=list)
    runtime_type: RuntimeType | None = None
    fuse_registry: FuseOpRegistry = Field(default_factory=FuseOpRegistry)
    command_stats: CommandStats = Field(default_factory=CommandStats)
    created_at: float = Field(default_factory=time.time)
    reported_status: dict | None = None
    reported_transfers: dict | None = None

def _unmount_fuse(mountpoint: str, pid: int | None) -> None:
    if sys.platform == "darwin":
        subprocess.run(["diskutil", "unmount", "force", mountpoint],
                       capture_output=True)
    else:
        subprocess.run(["fusermount", "-u", mountpoint], capture_output=True)
    if pid:
        try:
            os.kill(pid, signal.SIGTERM)
        except ProcessLookupError:
            pass

-from mirage.types import CommandStats, MountMode, RuntimeType

+from mirage.types import MountMode, RuntimeType

+    command_counts: dict[str, int] = Field(default_factory=dict)


Remove `CommandStats` from `types.py`:


class CommandStats(BaseModel):
    total_commands: int = 0
    total_errors: int = 0
    last_command: str = ""
    last_timestamp: str = ""
    command_counts: dict[str, int] = Field(default_factory=dict)

class FilePayload(BaseModel):


     1→from enum import Enum
     2→
     3→from pydantic import BaseModel, ConfigDict, Field
     4→
     5→
     6→class FileType(str, Enum):
     7→    DIRECTORY = "directory"
     8→    TEXT = "text"
     9→    BINARY = "binary"
    10→    JSON = "json"
    11→    CSV = "csv"
    12→    IMAGE_PNG = "image/png"
    13→    IMAGE_JPEG = "image/jpeg"
    14→    IMAGE_GIF = "image/gif"
    15→    ZIP = "application/zip"
    16→    GZIP = "application/gzip"
    17→    PDF = "application/pdf"
    18→
    19→
    20→class CostLevel(str, Enum):
    21→    CHEAP = "cheap"
    22→    PARTIAL = "partial"
    23→    EXPENSIVE = "expensive"
    24→    NETWORK = "network"
    25→
    26→
    27→class FileStat(BaseModel):
    28→    model_config = ConfigDict(frozen=True)
    29→
    30→    name: str
    31→    size: int | None = None
    32→    modified: str | None = None
    33→    type: FileType | None = None
    34→    extra: dict = Field(default_factory=dict)
    35→
    36→
    37→class MountMode(str, Enum):
    38→    READ = "read"
    39→    WRITE = "write"
    40→    EXEC = "exec"
    41→
    42→
    43→class RuntimeType(str, Enum):
    44→    MEMORY = "memory"
    45→    LOCAL = "local"
    46→    REMOTE = "remote"
    47→
    48→
    49→class BackendType(str, Enum):
    50→    MEMORY = "memory"
    51→    LOCAL = "local"
    52→    S3 = "s3"
    53→    R2 = "r2"
    54→    HTTP = "http"
    55→    HTTPS = "https"
    56→
    57→
    58→class Inode(BaseModel):
    59→    virtual_path: str
    60→    backend_mount: str
    61→    checksum: str | None = None
    62→    size: int | None = None
    63→    remote_checksum: str | None = None
    64→    dirty: bool = False
    65→
    66→
    67→class SyncResult(BaseModel):
    68→    model_config = ConfigDict(frozen=True)
    69→
    70→    path: str
    71→    op: str
    72→    status: str
    73→    remote: str | None = None
    74→    bytes: int | None = None
    75→    duration_ms: int = 0
    76→    error: str | None = None
    77→
    78→
    79→class TransferStats(BaseModel):
    80→    bytes_read: int = 0
    81→    bytes_written: int = 0
    82→    read_ops: int = 0
    83→    write_ops: int = 0
    84→    cache_hits: int = 0
    85→    cache_misses: int = 0
    86→    total_read_ms: int = 0
    87→    total_write_ms: int = 0
    88→
    89→
    90→class CommandStats(BaseModel):
    91→    total_commands: int = 0
    92→    total_errors: int = 0
    93→    last_command: str = ""
    94→    last_timestamp: str = ""
    95→    command_counts: dict[str, int] = Field(default_factory=dict)
    96→
    97→
    98→class FilePayload(BaseModel):
    99→    checksum: str
   100→    data: bytes | None = None
   101→
   102→
   103→class RemoteCommandOptions(BaseModel):
   104→    max_file_size: str = "100MB"
   105→    cache: str = "enabled"
   106→
   107→
   108→class CommandResult(BaseModel):
   109→    model_config = ConfigDict(arbitrary_types_allowed=True)
   110→
   111→    stdout: str = ""
   112→    output_files: dict[str, bytes] = {}
   113→

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

from enum import Enum

from pydantic import BaseModel, ConfigDict, Field

class FileType(str, Enum):
    DIRECTORY = "directory"
    TEXT = "text"
    BINARY = "binary"
    JSON = "json"
    CSV = "csv"
    IMAGE_PNG = "image/png"
    IMAGE_JPEG = "image/jpeg"
    IMAGE_GIF = "image/gif"
    ZIP = "application/zip"
    GZIP = "application/gzip"
    PDF = "application/pdf"

class CostLevel(str, Enum):
    CHEAP = "cheap"
    PARTIAL = "partial"
    EXPENSIVE = "expensive"
    NETWORK = "network"

class FileStat(BaseModel):
    model_config = ConfigDict(frozen=True)

    name: str
    size: int | None = None
    modified: str | None = None
    type: FileType | None = None
    extra: dict = Field(default_factory=dict)

class MountMode(str, Enum):
    READ = "read"
    WRITE = "write"
    EXEC = "exec"

class RuntimeType(str, Enum):
    MEMORY = "memory"
    LOCAL = "local"
    REMOTE = "remote"

class BackendType(str, Enum):
    MEMORY = "memory"
    LOCAL = "local"
    S3 = "s3"
    R2 = "r2"
    HTTP = "http"
    HTTPS = "https"

class Inode(BaseModel):
    virtual_path: str
    backend_mount: str
    checksum: str | None = None
    size: int | None = None
    remote_checksum: str | None = None
    dirty: bool = False

class SyncResult(BaseModel):
    model_config = ConfigDict(frozen=True)

    path: str
    op: str
    status: str
    remote: str | None = None
    bytes: int | None = None
    duration_ms: int = 0
    error: str | None = None

class TransferStats(BaseModel):
    bytes_read: int = 0
    bytes_written: int = 0
    read_ops: int = 0
    write_ops: int = 0
    cache_hits: int = 0
    cache_misses: int = 0
    total_read_ms: int = 0
    total_write_ms: int = 0

class CommandStats(BaseModel):
    total_commands: int = 0
    total_errors: int = 0
    last_command: str = ""
    last_timestamp: str = ""
    command_counts: dict[str, int] = Field(default_factory=dict)

class FilePayload(BaseModel):
    checksum: str
    data: bytes | None = None

class RemoteCommandOptions(BaseModel):
    max_file_size: str = "100MB"
    cache: str = "enabled"

class CommandResult(BaseModel):
    model_config = ConfigDict(arbitrary_types_allowed=True)

    stdout: str = ""
    output_files: dict[str, bytes] = {}


class CommandStats(BaseModel):
    total_commands: int = 0
    total_errors: int = 0
    last_command: str = ""
    last_timestamp: str = ""
    command_counts: dict[str, int] = Field(default_factory=dict)

class FilePayload(BaseModel):


The file /Users/agent/strukto/mirage/mirage/types.py has been updated successfully.

from enum import Enum

from pydantic import BaseModel, ConfigDict, Field

class FileType(str, Enum):
    DIRECTORY = "directory"
    TEXT = "text"
    BINARY = "binary"
    JSON = "json"
    CSV = "csv"
    IMAGE_PNG = "image/png"
    IMAGE_JPEG = "image/jpeg"
    IMAGE_GIF = "image/gif"
    ZIP = "application/zip"
    GZIP = "application/gzip"
    PDF = "application/pdf"

class CostLevel(str, Enum):
    CHEAP = "cheap"
    PARTIAL = "partial"
    EXPENSIVE = "expensive"
    NETWORK = "network"

class FileStat(BaseModel):
    model_config = ConfigDict(frozen=True)

    name: str
    size: int | None = None
    modified: str | None = None
    type: FileType | None = None
    extra: dict = Field(default_factory=dict)

class MountMode(str, Enum):
    READ = "read"
    WRITE = "write"
    EXEC = "exec"

class RuntimeType(str, Enum):
    MEMORY = "memory"
    LOCAL = "local"
    REMOTE = "remote"

class BackendType(str, Enum):
    MEMORY = "memory"
    LOCAL = "local"
    S3 = "s3"
    R2 = "r2"
    HTTP = "http"
    HTTPS = "https"

class Inode(BaseModel):
    virtual_path: str
    backend_mount: str
    checksum: str | None = None
    size: int | None = None
    remote_checksum: str | None = None
    dirty: bool = False

class SyncResult(BaseModel):
    model_config = ConfigDict(frozen=True)

    path: str
    op: str
    status: str
    remote: str | None = None
    bytes: int | None = None
    duration_ms: int = 0
    error: str | None = None

class TransferStats(BaseModel):
    bytes_read: int = 0
    bytes_written: int = 0
    read_ops: int = 0
    write_ops: int = 0
    cache_hits: int = 0
    cache_misses: int = 0
    total_read_ms: int = 0
    total_write_ms: int = 0

class CommandStats(BaseModel):
    total_commands: int = 0
    total_errors: int = 0
    last_command: str = ""
    last_timestamp: str = ""
    command_counts: dict[str, int] = Field(default_factory=dict)

class FilePayload(BaseModel):
    checksum: str
    data: bytes | None = None

class RemoteCommandOptions(BaseModel):
    max_file_size: str = "100MB"
    cache: str = "enabled"

class CommandResult(BaseModel):
    model_config = ConfigDict(arbitrary_types_allowed=True)

    stdout: str = ""
    output_files: dict[str, bytes] = {}

-    command_counts: dict[str, int] = Field(default_factory=dict)


Update `tests/test_types.py` and `tests/observe/test_inspector.py` (`CommandStats` import):