@struktoai/mirage-dsh 0.0.1-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,54 @@
1
+ import { Context } from '@deepseek-ai/cordis';
2
+ import { FileSystem, FsTarget, FsInfo, FsPathInfo, FsDirEntry, FsWriteIntent, FsWriteOutcome, FsEditRequest, FsVersion, FsEditOutcome } from '@deepseek-ai/dsh-fs';
3
+
4
+ /** Configuration for the mirage filesystem backend. */
5
+ interface MirageFsConfig {
6
+ /** Virtual base directory for relative paths. Defaults to `/`. */
7
+ cwd?: string;
8
+ /** Exclusive byte limit on each overwrite-diff side. Defaults to 10 MiB. */
9
+ diffBasisMaxBytes?: number;
10
+ }
11
+ /**
12
+ * Mirage-backed implementation of `ctx.fs`. Targets are canonical virtual
13
+ * paths (namespace symlinks followed), every operation walks the workspace
14
+ * op door — session grants, admission policies, cache read-through and
15
+ * post-write invalidation all fire exactly as they do for a shell command —
16
+ * and `processPath` answers in the same virtual path space the mirage shell
17
+ * executes in, so the two providers share one execution world.
18
+ */
19
+ declare class MirageFileSystem extends FileSystem {
20
+ static readonly inject: string[];
21
+ private fsOps;
22
+ private readonly cwd;
23
+ private readonly diffBasisMaxBytes;
24
+ private readonly locks;
25
+ constructor(ctx: Context, config?: MirageFsConfig);
26
+ private ops;
27
+ private get links();
28
+ private normalize;
29
+ private follow;
30
+ private withLock;
31
+ resolve(path: string, opts?: {
32
+ cwd?: string;
33
+ signal?: AbortSignal;
34
+ }): Promise<FsTarget>;
35
+ processPath(target: FsTarget): string;
36
+ fileUrl(target: FsTarget): string;
37
+ contains(parent: FsTarget, child: FsTarget): boolean;
38
+ stat(target: FsTarget, signal?: AbortSignal): Promise<FsInfo | undefined>;
39
+ lstat(path: string, opts?: {
40
+ cwd?: string;
41
+ }, signal?: AbortSignal): Promise<FsPathInfo | undefined>;
42
+ readText(target: FsTarget, signal?: AbortSignal): Promise<string>;
43
+ streamText(target: FsTarget, signal?: AbortSignal): Promise<AsyncIterable<string>>;
44
+ listDir(target: FsTarget, signal?: AbortSignal): Promise<FsDirEntry[]>;
45
+ private dirEntry;
46
+ writeText(target: FsTarget, content: string, expected?: FsWriteIntent, signal?: AbortSignal): Promise<FsWriteOutcome>;
47
+ private diffBasis;
48
+ private versionAfterWrite;
49
+ editText(target: FsTarget, edit: FsEditRequest, expected?: {
50
+ version: FsVersion;
51
+ }, signal?: AbortSignal): Promise<FsEditOutcome>;
52
+ }
53
+
54
+ export { MirageFileSystem as M, type MirageFsConfig as a };
@@ -0,0 +1,8 @@
1
+ export { M as MirageConfig, a as MirageMount, b as MirageMountBlock, c as MirageRuntimeBlock, d as MirageService } from './service-CxFYAvoV.js';
2
+ export { M as MirageFileSystem, a as MirageFsConfig } from './fs-CuiUEA7A.js';
3
+ export { M as MirageShellConfig, a as MirageShellExecutor } from './shell-B0N_jppN.js';
4
+ import '@deepseek-ai/cordis';
5
+ import '@struktoai/mirage-core';
6
+ import '@struktoai/mirage-node';
7
+ import '@deepseek-ai/dsh-fs';
8
+ import '@deepseek-ai/dsh-shell';
package/dist/index.js ADDED
@@ -0,0 +1,16 @@
1
+ import {
2
+ MirageFileSystem
3
+ } from "./chunk-C67TSSYB.js";
4
+ import {
5
+ MirageService
6
+ } from "./chunk-J6F4OX6Z.js";
7
+ import {
8
+ MirageShellExecutor
9
+ } from "./chunk-ZSZVHBSL.js";
10
+ import "./chunk-CATVBGGR.js";
11
+ export {
12
+ MirageFileSystem,
13
+ MirageService,
14
+ MirageShellExecutor
15
+ };
16
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,3 @@
1
+ export { M as default } from '../fs-CuiUEA7A.js';
2
+ import '@deepseek-ai/cordis';
3
+ import '@deepseek-ai/dsh-fs';
@@ -0,0 +1,8 @@
1
+ import {
2
+ MirageFileSystem
3
+ } from "../chunk-C67TSSYB.js";
4
+ import "../chunk-CATVBGGR.js";
5
+ export {
6
+ MirageFileSystem as default
7
+ };
8
+ //# sourceMappingURL=fs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,4 @@
1
+ export { d as default } from '../service-CxFYAvoV.js';
2
+ import '@deepseek-ai/cordis';
3
+ import '@struktoai/mirage-core';
4
+ import '@struktoai/mirage-node';
@@ -0,0 +1,7 @@
1
+ import {
2
+ MirageService
3
+ } from "../chunk-J6F4OX6Z.js";
4
+ export {
5
+ MirageService as default
6
+ };
7
+ //# sourceMappingURL=service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,3 @@
1
+ export { a as default } from '../shell-B0N_jppN.js';
2
+ import '@deepseek-ai/cordis';
3
+ import '@deepseek-ai/dsh-shell';
@@ -0,0 +1,8 @@
1
+ import {
2
+ MirageShellExecutor
3
+ } from "../chunk-ZSZVHBSL.js";
4
+ import "../chunk-CATVBGGR.js";
5
+ export {
6
+ MirageShellExecutor as default
7
+ };
8
+ //# sourceMappingURL=shell.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,91 @@
1
+ import { Service, Context } from '@deepseek-ai/cordis';
2
+ import { MountSpec } from '@struktoai/mirage-core';
3
+ import { Workspace, Mount, NodeWorkspaceOptions } from '@struktoai/mirage-node';
4
+
5
+ declare module '@deepseek-ai/cordis' {
6
+ interface Context {
7
+ mirage: MirageService;
8
+ }
9
+ }
10
+ /**
11
+ * A declarative mount, YAML-friendly: the resource is named by its
12
+ * registry type and built through `buildResource`, so a dsh bundle
13
+ * patch can mount anything without holding a live instance. Told apart
14
+ * from a live `Mount` by the type of `resource`: a string names a
15
+ * registry entry, an object is the instance itself.
16
+ */
17
+ interface MirageMountBlock {
18
+ /** Resource registry name (`ram`, `s3`, `slack`, `redis`, ...). */
19
+ resource: string;
20
+ /** Mount mode: `read`, `write`, or `exec`. Omitted = the workspace default. */
21
+ mode?: string;
22
+ /** Resource constructor config, passed to the registry factory. */
23
+ config?: Record<string, unknown>;
24
+ }
25
+ /** One mount entry: a live spec or instance, or a declarative block. */
26
+ type MirageMount = MountSpec | Mount | MirageMountBlock;
27
+ /** A runtime entry, YAML-friendly: a name, or a name with captures. */
28
+ interface MirageRuntimeBlock {
29
+ /** Runtime registry name (`monty`, `pyodide`, `quickjs`, ...). */
30
+ name: string;
31
+ /** Command words this runtime captures (e.g. `['python', 'python3']`). */
32
+ captures?: string[];
33
+ }
34
+ /**
35
+ * Configuration for the shared mirage execution world. Exactly one of
36
+ * `workspace` (adopt a live workspace the embedder owns and closes) or
37
+ * `mounts` (construct a workspace here; the service closes it when its
38
+ * plugin unloads) must be given.
39
+ */
40
+ interface MirageConfig {
41
+ /** A live workspace to adopt; its lifecycle stays with the embedder. */
42
+ workspace?: Workspace;
43
+ /** Mounts for a service-owned workspace, keyed by mount prefix. */
44
+ mounts?: Record<string, MirageMount>;
45
+ /**
46
+ * Runtimes for a service-owned workspace, built via `buildRuntime`.
47
+ * The YAML-friendly twin of `workspaceOptions.runtimes`; pass one or
48
+ * the other, not both.
49
+ */
50
+ runtimes?: (string | MirageRuntimeBlock)[];
51
+ /** Options forwarded to the service-owned workspace's constructor. */
52
+ workspaceOptions?: NodeWorkspaceOptions;
53
+ }
54
+ /**
55
+ * The one mirage `Workspace` behind every mirage-backed dsh provider
56
+ * (`ctx.mirage`, mirroring how `ctx.e2b` owns one sandbox for the E2B
57
+ * adapters). `MirageFileSystem` and `MirageShellExecutor` both inject it,
58
+ * which is what keeps `ctx.fs` targets and `ctx.shell` commands in one
59
+ * execution world: a `processPath` handed to the shell resolves there.
60
+ *
61
+ * Construction with live resources is synchronous; a declarative mount
62
+ * block defers to `buildResource`, so consumers await `ready` (the
63
+ * adapters do) and `workspace` throws until it resolves, mirroring how
64
+ * the E2B service owner exposes its sandbox.
65
+ */
66
+ declare class MirageService extends Service {
67
+ static readonly provide = "mirage";
68
+ /** Resolves to the shared workspace once every mount is built. */
69
+ readonly ready: Promise<Workspace>;
70
+ private built;
71
+ private readonly plannedRuntimes;
72
+ constructor(ctx: Context, config?: MirageConfig);
73
+ /** The live workspace; throws until `ready` resolves. */
74
+ get workspace(): Workspace;
75
+ /**
76
+ * True while every runtime in the world reaches only the vfs
77
+ * (`Runtime.reach`), meaning the workspace dispatch is the single
78
+ * gate for anything the agent can execute: every effect passes
79
+ * mount modes, session grants, and policy before touching the real
80
+ * backend behind a mount. The default world qualifies, and so do
81
+ * the bridged engines, while the host `local` python or a remote
82
+ * sandbox can act around the gate. Answers before `ready` from the
83
+ * constructor-resolved entries (mounts resolve asynchronously,
84
+ * runtimes never do) and from the live workspace afterwards, so a
85
+ * later `addRuntime` is seen.
86
+ */
87
+ get vfsOnly(): boolean;
88
+ private open;
89
+ }
90
+
91
+ export { type MirageConfig as M, type MirageMount as a, type MirageMountBlock as b, type MirageRuntimeBlock as c, MirageService as d };
@@ -0,0 +1,108 @@
1
+ import { Context } from '@deepseek-ai/cordis';
2
+ import { ShellExecutor, ShellExecRequest, ShellExecSpec, ShellRunResult, ShellProcess } from '@deepseek-ai/dsh-shell';
3
+
4
+ /** Configuration for the mirage shell executor. */
5
+ interface MirageShellConfig {
6
+ /**
7
+ * Default working directory for commands. Defaults to `/`. With
8
+ * `sessionId` it instead seeds the bound session's initial cwd, and the
9
+ * session's own cwd is the default from then on.
10
+ */
11
+ workdir?: string;
12
+ /** Default foreground timeout in milliseconds. Defaults to 120000. */
13
+ defaultTimeoutMs?: number;
14
+ /** Upper cap on any requested timeout. Defaults to 600000. */
15
+ maxTimeoutMs?: number;
16
+ /** Default stdout capture budget in bytes. Defaults to 200000. */
17
+ stdoutMaxBytes?: number;
18
+ /** stderr capture budget in bytes. Defaults to 64000. */
19
+ stderrMaxBytes?: number;
20
+ /**
21
+ * Bind every command to this named workspace session. By default each
22
+ * command runs in an ephemeral fork of the workspace's default session,
23
+ * so nothing persists between calls, which is the one-shot contract of
24
+ * dsh's bash tool. With a session bound, `cd`, `export`, and function
25
+ * definitions persist across calls, the persistent-shell contract. The
26
+ * session is created on first use if the workspace does not have it; an
27
+ * existing session is adopted as is. A spec carrying an explicit
28
+ * `workdir` or `env` still runs as a one-call subshell of the bound
29
+ * session, per mirage's `ExecuteOptions` semantics.
30
+ */
31
+ sessionId?: string;
32
+ /**
33
+ * When set, a background command whose streamed output overruns its
34
+ * delta budget spills its full stdout and stderr to files under this
35
+ * workspace directory, and `readOutput()` points at them so a reader
36
+ * can recover what the delta dropped. The directory is a workspace
37
+ * path (e.g. `/tmp` on a ram mount), so the agent reads the spill
38
+ * through the same VFS as everything else; the writes go through the
39
+ * workspace, so they appear in history like any other write. Unset
40
+ * (the default) means no spill: output that overruns is simply
41
+ * flagged `lossy`, the honest "no safe path available" answer.
42
+ */
43
+ spillDir?: string;
44
+ }
45
+ /**
46
+ * Mirage-backed implementation of `ctx.shell`: `run` executes the command
47
+ * line with mirage's own shell (coreutils-faithful commands, installed
48
+ * CLIs, the policy layer) against the shared `ctx.mirage` workspace, so a
49
+ * path from `ctx.fs` means the same file here. There is no OS process
50
+ * behind a command: `signal` in results is a compatibility value for kills,
51
+ * and abort/timeout act cooperatively at the executor's own boundaries.
52
+ *
53
+ * Every command runs in an ephemeral fork of the workspace's default
54
+ * session, so no shell state survives from one call to the next, matching
55
+ * the one-shot contract of dsh's bash tool. Configuring a `sessionId`
56
+ * binds all commands to one named session instead, whose cwd, exports,
57
+ * and functions persist across calls.
58
+ */
59
+ declare class MirageShellExecutor extends ShellExecutor {
60
+ static readonly inject: string[];
61
+ private readonly workdir;
62
+ private readonly defaultTimeoutMs;
63
+ private readonly maxTimeoutMs;
64
+ private readonly stdoutMaxBytes;
65
+ private readonly stderrMaxBytes;
66
+ private readonly sessionId;
67
+ private readonly spillDir;
68
+ private sessionReady;
69
+ constructor(ctx: Context, config?: MirageShellConfig);
70
+ private workspace;
71
+ private newSpill;
72
+ /**
73
+ * With every runtime in the world reaching only the vfs
74
+ * (`ctx.mirage.vfsOnly`), the workspace dispatch is the single gate
75
+ * for anything a command can do, so this executor behaves like a
76
+ * workspace-write sandbox: reads and writes land only where mounts
77
+ * (and their modes) allow. Declaring it lets sandbox-aware plugins
78
+ * (dsh's permission presets) compose over this executor. A world
79
+ * holding a runtime with doors around the gate (the host `local`
80
+ * python, a remote sandbox) voids that claim, so this answers
81
+ * undefined then (the base contract's "does not sandbox") and those
82
+ * plugins refuse to compose instead of trusting a lie.
83
+ */
84
+ get sandboxMode(): ShellExecutor['sandboxMode'];
85
+ /**
86
+ * The sandbox facts to stamp on this run's result and process handle,
87
+ * or undefined when the world is not fully workspace-bound (no claim).
88
+ *
89
+ * `enforcement` is 'full': when every runtime reaches only the vfs, the
90
+ * workspace gate cannot be bypassed, so unlike an OS sandbox on an older
91
+ * kernel there is no promised effect it fails to govern. `denied` is
92
+ * false because mirage has no out-of-band denial channel: a refused write
93
+ * (a read-only mount) fails in-band as an ordinary command error with a
94
+ * nonzero exit, the way EROFS would, not as a separate sandbox verdict,
95
+ * so there is nothing here to distinguish from the command's own failure.
96
+ * `runnerFailed` is false because the workspace executor is the runner
97
+ * and a failure to run surfaces as a rejected/aborted execution, not a
98
+ * runner that never started.
99
+ */
100
+ private sandboxInfo;
101
+ resolve(request: ShellExecRequest): ShellExecSpec;
102
+ private ensureSession;
103
+ private provisionSession;
104
+ run(spec: ShellExecSpec): Promise<ShellRunResult>;
105
+ start(spec: ShellExecSpec): ShellProcess;
106
+ }
107
+
108
+ export { type MirageShellConfig as M, MirageShellExecutor as a };
package/package.json ADDED
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "@struktoai/mirage-dsh",
3
+ "version": "0.0.1-alpha.1",
4
+ "description": "DeepSeek Harness (dsh) providers backed by a mirage workspace: ctx.fs and ctx.shell over mounted resources",
5
+ "homepage": "https://github.com/strukto-ai/mirage#readme",
6
+ "bugs": {
7
+ "url": "https://github.com/strukto-ai/mirage/issues"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/strukto-ai/mirage.git",
12
+ "directory": "typescript/packages/dsh"
13
+ },
14
+ "license": "Apache-2.0",
15
+ "author": "Zecheng Zhang <zecheng@strukto.ai>",
16
+ "publishConfig": {
17
+ "access": "public"
18
+ },
19
+ "type": "module",
20
+ "main": "./dist/index.js",
21
+ "types": "./dist/index.d.ts",
22
+ "exports": {
23
+ ".": {
24
+ "types": "./dist/index.d.ts",
25
+ "import": "./dist/index.js"
26
+ },
27
+ "./service": {
28
+ "types": "./dist/plugin/service.d.ts",
29
+ "import": "./dist/plugin/service.js"
30
+ },
31
+ "./fs": {
32
+ "types": "./dist/plugin/fs.d.ts",
33
+ "import": "./dist/plugin/fs.js"
34
+ },
35
+ "./shell": {
36
+ "types": "./dist/plugin/shell.d.ts",
37
+ "import": "./dist/plugin/shell.js"
38
+ }
39
+ },
40
+ "dsh": {
41
+ "bundle": {
42
+ "patch": "./cordis.patch.yml"
43
+ }
44
+ },
45
+ "files": [
46
+ "dist",
47
+ "cordis.patch.yml"
48
+ ],
49
+ "dependencies": {
50
+ "@struktoai/mirage-node": "0.0.5-alpha.1",
51
+ "@struktoai/mirage-core": "0.0.5-alpha.1"
52
+ },
53
+ "peerDependencies": {
54
+ "@deepseek-ai/cordis": "^4.0.1",
55
+ "@deepseek-ai/dsh-fs": "0.0.1-rc.1",
56
+ "@deepseek-ai/dsh-shell": "0.0.1-rc.5"
57
+ },
58
+ "devDependencies": {
59
+ "@deepseek-ai/cordis": "^4.0.1",
60
+ "@deepseek-ai/dsh-fs": "0.0.1-rc.1",
61
+ "@deepseek-ai/dsh-shell": "0.0.1-rc.5",
62
+ "tsup": "^8.5.0",
63
+ "typescript": "^6.0.0",
64
+ "vitest": "^3.2.6"
65
+ },
66
+ "scripts": {
67
+ "build": "tsup",
68
+ "test": "vitest run",
69
+ "typecheck": "tsc --noEmit"
70
+ }
71
+ }