@yadsh/dsh-session-scope 0.5.0

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.
Files changed (53) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +110 -0
  3. package/compatibility.json +20 -0
  4. package/cordis.patch.yml +7 -0
  5. package/lib/client.d.ts +1 -0
  6. package/lib/client.d.ts.map +1 -0
  7. package/lib/client.js +716 -0
  8. package/lib/client.js.map +1 -0
  9. package/lib/core.d.ts +204 -0
  10. package/lib/core.d.ts.map +1 -0
  11. package/lib/core.js +375 -0
  12. package/lib/core.js.map +1 -0
  13. package/lib/host-api.d.ts +23 -0
  14. package/lib/host-api.d.ts.map +1 -0
  15. package/lib/host-api.js +40 -0
  16. package/lib/host-api.js.map +1 -0
  17. package/lib/index.d.ts +32 -0
  18. package/lib/index.d.ts.map +1 -0
  19. package/lib/index.js +594 -0
  20. package/lib/index.js.map +1 -0
  21. package/lib/scope-context.d.ts +3 -0
  22. package/lib/scope-context.d.ts.map +1 -0
  23. package/lib/scope-context.js +29 -0
  24. package/lib/scope-context.js.map +1 -0
  25. package/lib/scope-delegation.d.ts +23 -0
  26. package/lib/scope-delegation.d.ts.map +1 -0
  27. package/lib/scope-delegation.js +49 -0
  28. package/lib/scope-delegation.js.map +1 -0
  29. package/lib/scope-fs.d.ts +47 -0
  30. package/lib/scope-fs.d.ts.map +1 -0
  31. package/lib/scope-fs.js +150 -0
  32. package/lib/scope-fs.js.map +1 -0
  33. package/lib/scope-processes.d.ts +31 -0
  34. package/lib/scope-processes.d.ts.map +1 -0
  35. package/lib/scope-processes.js +71 -0
  36. package/lib/scope-processes.js.map +1 -0
  37. package/lib/scope-sandbox-linux.d.ts +35 -0
  38. package/lib/scope-sandbox-linux.d.ts.map +1 -0
  39. package/lib/scope-sandbox-linux.js +177 -0
  40. package/lib/scope-sandbox-linux.js.map +1 -0
  41. package/lib/scope-visibility.d.ts +14 -0
  42. package/lib/scope-visibility.d.ts.map +1 -0
  43. package/lib/scope-visibility.js +62 -0
  44. package/lib/scope-visibility.js.map +1 -0
  45. package/lib/session-scope.d.ts +54 -0
  46. package/lib/session-scope.d.ts.map +1 -0
  47. package/lib/session-scope.js +200 -0
  48. package/lib/session-scope.js.map +1 -0
  49. package/lib/tool-guard.d.ts +52 -0
  50. package/lib/tool-guard.d.ts.map +1 -0
  51. package/lib/tool-guard.js +233 -0
  52. package/lib/tool-guard.js.map +1 -0
  53. package/package.json +150 -0
@@ -0,0 +1,29 @@
1
+ export function renderSessionScopeContext(scope) {
2
+ if (scope.mode === "full") {
3
+ return [
4
+ "### Session workspace scope",
5
+ "",
6
+ "The entire session workspace is accessible. Filesystem effects are still controlled by the active permission policy.",
7
+ ].join("\n");
8
+ }
9
+ const roots = scope.roots.length === 0
10
+ ? ["- none (filesystem access is fail-closed until the scope is changed)"]
11
+ : scope.roots.map((root) => `- ${root}`);
12
+ const shell = scope.mode === "isolated"
13
+ ? "Supported shell processes are also confined to this view."
14
+ : "DSH filesystem tools are restricted; shell isolation is not guaranteed in focused mode.";
15
+ return [
16
+ "### Session workspace scope",
17
+ "",
18
+ `The current session uses ${scope.mode} workspace scope.`,
19
+ "",
20
+ "Accessible roots:",
21
+ ...roots,
22
+ "",
23
+ "Treat all other paths under the session workspace as unavailable.",
24
+ "Do not search, inspect, read, modify, or execute against paths outside these roots.",
25
+ "If another workspace area is required, ask the user to change the session scope.",
26
+ shell,
27
+ ].join("\n");
28
+ }
29
+ //# sourceMappingURL=scope-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope-context.js","sourceRoot":"","sources":["../src/scope-context.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,yBAAyB,CAAC,KAA4B;IACpE,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QAC1B,OAAO;YACL,6BAA6B;YAC7B,EAAE;YACF,sHAAsH;SACvH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACf,CAAC;IACD,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC;QACpC,CAAC,CAAC,CAAC,sEAAsE,CAAC;QAC1E,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;IAC3C,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,KAAK,UAAU;QACrC,CAAC,CAAC,2DAA2D;QAC7D,CAAC,CAAC,yFAAyF,CAAC;IAC9F,OAAO;QACL,6BAA6B;QAC7B,EAAE;QACF,4BAA4B,KAAK,CAAC,IAAI,mBAAmB;QACzD,EAAE;QACF,mBAAmB;QACnB,GAAG,KAAK;QACR,EAAE;QACF,mEAAmE;QACnE,qFAAqF;QACrF,kFAAkF;QAClF,KAAK;KACN,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC"}
@@ -0,0 +1,23 @@
1
+ import { type SessionEvent } from "./core.js";
2
+ import { SESSION_SCOPE_EVENT, type SessionHeader, type SessionScopeEventData } from "./session-scope.js";
3
+ export interface DelegatedSessionHeader extends SessionHeader {
4
+ id?: string;
5
+ parentSession?: string;
6
+ seedLength?: number;
7
+ origin?: "subagent";
8
+ }
9
+ export interface DelegatedScopeSession {
10
+ header: DelegatedSessionHeader;
11
+ events: readonly SessionEvent[];
12
+ append(type: typeof SESSION_SCOPE_EVENT, data: SessionScopeEventData): unknown;
13
+ }
14
+ export type ParentSessionResolver = (id: string) => DelegatedScopeSession | undefined;
15
+ /**
16
+ * Persist a subagent's parent scope before the child can execute.
17
+ *
18
+ * A forked child prefers the immutable seed prefix, which captures the scope
19
+ * at the fork boundary. A fresh child resolves its live parent. Resumed
20
+ * children already carry their own delegation snapshot and are left alone.
21
+ */
22
+ export declare function initializeDelegatedSessionScope(child: DelegatedScopeSession, resolveParent: ParentSessionResolver): SessionScopeEventData | undefined;
23
+ //# sourceMappingURL=scope-delegation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope-delegation.d.ts","sourceRoot":"","sources":["../src/scope-delegation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkC,KAAK,YAAY,EAAE,MAAM,WAAW,CAAC;AAC9E,OAAO,EAEL,mBAAmB,EAKnB,KAAK,aAAa,EAClB,KAAK,qBAAqB,EAC3B,MAAM,oBAAoB,CAAC;AAE5B,MAAM,WAAW,sBAAuB,SAAQ,aAAa;IAC3D,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,UAAU,CAAC;CACrB;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,sBAAsB,CAAC;IAC/B,MAAM,EAAE,SAAS,YAAY,EAAE,CAAC;IAChC,MAAM,CAAC,IAAI,EAAE,OAAO,mBAAmB,EAAE,IAAI,EAAE,qBAAqB,GAAG,OAAO,CAAC;CAChF;AAED,MAAM,MAAM,qBAAqB,GAAG,CAAC,EAAE,EAAE,MAAM,KAAK,qBAAqB,GAAG,SAAS,CAAC;AAwBtF;;;;;;GAMG;AACH,wBAAgB,+BAA+B,CAC7C,KAAK,EAAE,qBAAqB,EAC5B,aAAa,EAAE,qBAAqB,GACnC,qBAAqB,GAAG,SAAS,CAgCnC"}
@@ -0,0 +1,49 @@
1
+ import { SELECTION_EVENT, canonicalPath } from "./core.js";
2
+ import { SESSION_SCOPE_ERROR, SESSION_SCOPE_EVENT, SessionScopeError, createSessionScopeEvent, effectiveSessionScope, } from "./session-scope.js";
3
+ function hasScopeSnapshot(events) {
4
+ return events.some((event) => event.type === SESSION_SCOPE_EVENT);
5
+ }
6
+ function hasInheritedScopeState(events) {
7
+ return events.some((event) => event.type === SESSION_SCOPE_EVENT || event.type === SELECTION_EVENT);
8
+ }
9
+ function inheritedSeedScope(session) {
10
+ const seedLength = session.header.seedLength ?? 0;
11
+ if (seedLength <= 0)
12
+ return undefined;
13
+ const inherited = session.events.slice(0, seedLength);
14
+ return hasInheritedScopeState(inherited)
15
+ ? effectiveSessionScope(inherited, session.header)
16
+ : undefined;
17
+ }
18
+ function hasOwnScopeSnapshot(session) {
19
+ const ownStart = session.header.seedLength ?? 0;
20
+ return hasScopeSnapshot(session.events.slice(ownStart));
21
+ }
22
+ /**
23
+ * Persist a subagent's parent scope before the child can execute.
24
+ *
25
+ * A forked child prefers the immutable seed prefix, which captures the scope
26
+ * at the fork boundary. A fresh child resolves its live parent. Resumed
27
+ * children already carry their own delegation snapshot and are left alone.
28
+ */
29
+ export function initializeDelegatedSessionScope(child, resolveParent) {
30
+ if (child.header.origin !== "subagent" || hasOwnScopeSnapshot(child))
31
+ return undefined;
32
+ let scope = inheritedSeedScope(child);
33
+ if (scope === undefined) {
34
+ const parentId = child.header.parentSession;
35
+ const parent = parentId === undefined ? undefined : resolveParent(parentId);
36
+ if (parent === undefined) {
37
+ throw new SessionScopeError(SESSION_SCOPE_ERROR.PARENT_UNAVAILABLE, "The parent session scope is unavailable.");
38
+ }
39
+ scope = effectiveSessionScope(parent.events, parent.header);
40
+ }
41
+ const childWorkspace = child.header.cwd ?? "";
42
+ if (!childWorkspace || canonicalPath(scope.workspaceRoot) !== canonicalPath(childWorkspace)) {
43
+ throw new SessionScopeError(SESSION_SCOPE_ERROR.PARENT_UNAVAILABLE, "The parent session scope does not match the child workspace.");
44
+ }
45
+ const event = createSessionScopeEvent(scope.mode, scope.mode === "full" ? [] : scope.roots, childWorkspace, "delegation");
46
+ child.append(SESSION_SCOPE_EVENT, event);
47
+ return event;
48
+ }
49
+ //# sourceMappingURL=scope-delegation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope-delegation.js","sourceRoot":"","sources":["../src/scope-delegation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
+ import type { ScopeSession } from "./host-api.js";
3
+ import type { ScopeToolExecution } from "./tool-guard.js";
4
+ export interface ScopeFsTarget {
5
+ targetKey: unknown;
6
+ displayPath: string;
7
+ }
8
+ export interface ScopeFsDirEntry {
9
+ name: string;
10
+ type: "file" | "directory" | "other";
11
+ target: ScopeFsTarget;
12
+ [key: string]: unknown;
13
+ }
14
+ export interface ScopeAwareFileSystem {
15
+ resolve(path: string, options?: {
16
+ cwd?: string;
17
+ signal?: AbortSignal;
18
+ }): Promise<ScopeFsTarget>;
19
+ contains(parent: ScopeFsTarget, child: ScopeFsTarget): boolean;
20
+ stat(target: ScopeFsTarget, signal?: AbortSignal): Promise<unknown>;
21
+ lstat(path: string, options?: {
22
+ cwd?: string;
23
+ }, signal?: AbortSignal): Promise<unknown>;
24
+ readText(target: ScopeFsTarget, signal?: AbortSignal): Promise<string>;
25
+ streamText(target: ScopeFsTarget, signal?: AbortSignal): Promise<AsyncIterable<string>>;
26
+ readBytes(target: ScopeFsTarget, signal: AbortSignal | undefined, maxBytes: number): Promise<Uint8Array>;
27
+ listDir(target: ScopeFsTarget, signal?: AbortSignal): Promise<ScopeFsDirEntry[]>;
28
+ writeText(target: ScopeFsTarget, ...args: unknown[]): Promise<unknown>;
29
+ editText(target: ScopeFsTarget, ...args: unknown[]): Promise<unknown>;
30
+ }
31
+ interface SessionScopeRuntimeContext {
32
+ session: ScopeSession;
33
+ execution?: ScopeToolExecution;
34
+ }
35
+ export declare class SessionScopeRuntime {
36
+ readonly storage: AsyncLocalStorage<SessionScopeRuntimeContext>;
37
+ private readonly cache;
38
+ run<T>(session: ScopeSession | undefined, operation: () => T, execution?: ScopeToolExecution): T;
39
+ currentSession(): ScopeSession | undefined;
40
+ currentExecution(): ScopeToolExecution | undefined;
41
+ private resolvedScope;
42
+ private classify;
43
+ private deny;
44
+ patchFileSystem(fs: ScopeAwareFileSystem, fallbackWorkspaceRoot?: string): () => void;
45
+ }
46
+ export {};
47
+ //# sourceMappingURL=scope-fs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope-fs.d.ts","sourceRoot":"","sources":["../src/scope-fs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAErD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAGlD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAO1D,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,OAAO,CAAC;IACrC,MAAM,EAAE,aAAa,CAAC;IACtB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IAChG,QAAQ,CAAC,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC;IAC/D,IAAI,CAAC,MAAM,EAAE,aAAa,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACpE,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACxF,QAAQ,CAAC,MAAM,EAAE,aAAa,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACvE,UAAU,CAAC,MAAM,EAAE,aAAa,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC;IACxF,SAAS,CAAC,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,WAAW,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IACzG,OAAO,CAAC,MAAM,EAAE,aAAa,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAAC;IACjF,SAAS,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACvE,QAAQ,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACvE;AAiBD,UAAU,0BAA0B;IAClC,OAAO,EAAE,YAAY,CAAC;IACtB,SAAS,CAAC,EAAE,kBAAkB,CAAC;CAChC;AAID,qBAAa,mBAAmB;IAC9B,QAAQ,CAAC,OAAO,gDAAuD;IAEvE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA4C;IAElE,GAAG,CAAC,CAAC,EAAE,OAAO,EAAE,YAAY,GAAG,SAAS,EAAE,SAAS,EAAE,MAAM,CAAC,EAAE,SAAS,CAAC,EAAE,kBAAkB,GAAG,CAAC,CAG/F;IAED,cAAc,IAAI,YAAY,GAAG,SAAS,CAEzC;IAED,gBAAgB,IAAI,kBAAkB,GAAG,SAAS,CAEjD;YAEa,aAAa;IAmC3B,OAAO,CAAC,QAAQ;IAehB,OAAO,CAAC,IAAI;IAIZ,eAAe,CAAC,EAAE,EAAE,oBAAoB,EAAE,qBAAqB,SAAK,GAAG,MAAM,IAAI,CA4EhF;CACF"}
@@ -0,0 +1,150 @@
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
+ import { getScope } from "./host-api.js";
3
+ import { isLexicallyUnder } from "./core.js";
4
+ import { SESSION_SCOPE_ERROR, SessionScopeError, } from "./session-scope.js";
5
+ const DENIAL_MESSAGE = "Path is outside the active session scope. Change the session scope if access is required.";
6
+ export class SessionScopeRuntime {
7
+ storage = new AsyncLocalStorage();
8
+ cache = new WeakMap();
9
+ run(session, operation, execution) {
10
+ if (session === undefined)
11
+ return operation();
12
+ return this.storage.run({ session, execution }, operation);
13
+ }
14
+ currentSession() {
15
+ return this.storage.getStore()?.session;
16
+ }
17
+ currentExecution() {
18
+ return this.storage.getStore()?.execution;
19
+ }
20
+ async resolvedScope(fs, session, fallbackWorkspaceRoot) {
21
+ const scope = getScope(session, fallbackWorkspaceRoot);
22
+ if (scope.mode === "full") {
23
+ const workspace = await fs.resolve(scope.workspaceRoot);
24
+ return {
25
+ scope,
26
+ workspace,
27
+ workspaceSpellings: [scope.workspaceRoot, session.header?.cwd ?? fallbackWorkspaceRoot],
28
+ content: [],
29
+ navigation: [],
30
+ };
31
+ }
32
+ const key = JSON.stringify([scope.mode, scope.workspaceRoot, scope.roots, scope.navigationRoots]);
33
+ const cached = this.cache.get(session);
34
+ if (cached?.eventCount === session.events.length && cached.key === key)
35
+ return cached;
36
+ const resolveOne = (path) => fs.resolve(path, { cwd: scope.workspaceRoot });
37
+ const value = {
38
+ scope,
39
+ workspace: await resolveOne(scope.workspaceRoot),
40
+ workspaceSpellings: [scope.workspaceRoot, session.header?.cwd ?? fallbackWorkspaceRoot],
41
+ content: await Promise.all(scope.roots.map(resolveOne)),
42
+ navigation: await Promise.all([...new Set([scope.workspaceRoot, ...scope.navigationRoots])].map(resolveOne)),
43
+ eventCount: session.events.length,
44
+ key,
45
+ };
46
+ this.cache.set(session, value);
47
+ return value;
48
+ }
49
+ classify(fs, resolved, target) {
50
+ if (resolved.scope.mode === "full")
51
+ return "content";
52
+ if (!fs.contains(resolved.workspace, target)) {
53
+ const originatedInsideWorkspace = resolved.workspaceSpellings.some((root) => root.length > 0 && isLexicallyUnder(target.displayPath, root));
54
+ return originatedInsideWorkspace ? "denied" : "content";
55
+ }
56
+ if (resolved.content.some((root) => fs.contains(root, target)))
57
+ return "content";
58
+ if (resolved.navigation.some((root) => fs.contains(root, target) && fs.contains(target, root))) {
59
+ return "navigation";
60
+ }
61
+ return "denied";
62
+ }
63
+ deny() {
64
+ throw new SessionScopeError(SESSION_SCOPE_ERROR.DENIED, DENIAL_MESSAGE);
65
+ }
66
+ patchFileSystem(fs, fallbackWorkspaceRoot = "") {
67
+ const original = {
68
+ stat: fs.stat.bind(fs),
69
+ lstat: fs.lstat.bind(fs),
70
+ readText: fs.readText.bind(fs),
71
+ streamText: fs.streamText.bind(fs),
72
+ readBytes: fs.readBytes.bind(fs),
73
+ listDir: fs.listDir.bind(fs),
74
+ writeText: fs.writeText.bind(fs),
75
+ editText: fs.editText.bind(fs),
76
+ };
77
+ const resolveCurrent = async () => {
78
+ const session = this.currentSession();
79
+ return session === undefined ? undefined : this.resolvedScope(fs, session, fallbackWorkspaceRoot);
80
+ };
81
+ fs.stat = async (target, signal) => {
82
+ const scope = await resolveCurrent();
83
+ if (scope !== undefined && this.classify(fs, scope, target) === "denied")
84
+ this.deny();
85
+ return original.stat(target, signal);
86
+ };
87
+ fs.lstat = async (path, options, signal) => {
88
+ const scope = await resolveCurrent();
89
+ if (scope !== undefined) {
90
+ const target = await fs.resolve(path, { cwd: options?.cwd ?? scope.scope.workspaceRoot, signal });
91
+ if (this.classify(fs, scope, target) === "denied")
92
+ this.deny();
93
+ }
94
+ return original.lstat(path, options, signal);
95
+ };
96
+ fs.readText = async (target, signal) => {
97
+ const scope = await resolveCurrent();
98
+ if (scope !== undefined && this.classify(fs, scope, target) !== "content")
99
+ this.deny();
100
+ return original.readText(target, signal);
101
+ };
102
+ fs.streamText = async (target, signal) => {
103
+ const scope = await resolveCurrent();
104
+ if (scope !== undefined && this.classify(fs, scope, target) !== "content")
105
+ this.deny();
106
+ return original.streamText(target, signal);
107
+ };
108
+ fs.readBytes = async (target, signal, maxBytes) => {
109
+ const scope = await resolveCurrent();
110
+ if (scope !== undefined && this.classify(fs, scope, target) !== "content")
111
+ this.deny();
112
+ return original.readBytes(target, signal, maxBytes);
113
+ };
114
+ fs.listDir = async (target, signal) => {
115
+ const scope = await resolveCurrent();
116
+ if (scope === undefined || scope.scope.mode === "full")
117
+ return original.listDir(target, signal);
118
+ const access = this.classify(fs, scope, target);
119
+ if (access === "denied")
120
+ this.deny();
121
+ const entries = await original.listDir(target, signal);
122
+ if (access === "content")
123
+ return entries;
124
+ return entries.filter((entry) => scope.content.some((root) => fs.contains(entry.target, root) || fs.contains(root, entry.target)));
125
+ };
126
+ fs.writeText = async (target, ...args) => {
127
+ const scope = await resolveCurrent();
128
+ if (scope !== undefined && this.classify(fs, scope, target) !== "content")
129
+ this.deny();
130
+ return original.writeText(target, ...args);
131
+ };
132
+ fs.editText = async (target, ...args) => {
133
+ const scope = await resolveCurrent();
134
+ if (scope !== undefined && this.classify(fs, scope, target) !== "content")
135
+ this.deny();
136
+ return original.editText(target, ...args);
137
+ };
138
+ return () => {
139
+ fs.stat = original.stat;
140
+ fs.lstat = original.lstat;
141
+ fs.readText = original.readText;
142
+ fs.streamText = original.streamText;
143
+ fs.readBytes = original.readBytes;
144
+ fs.listDir = original.listDir;
145
+ fs.writeText = original.writeText;
146
+ fs.editText = original.editText;
147
+ };
148
+ }
149
+ }
150
+ //# sourceMappingURL=scope-fs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope-fs.js","sourceRoot":"","sources":["../src/scope-fs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ export declare const SESSION_SCOPE_PROCESS_ACTIVE_MESSAGE: string;
2
+ export interface ScopeProcessOwner {
3
+ session: unknown;
4
+ ctx: {
5
+ on(event: string, listener: (...args: any[]) => unknown, options?: Record<string, unknown>): unknown;
6
+ };
7
+ }
8
+ export interface ScopeProcessJob {
9
+ kind?: string;
10
+ status?: string;
11
+ }
12
+ export interface ScopeProcessServices {
13
+ terminals?: {
14
+ hasOwnerActivity(owner: ScopeProcessOwner): boolean;
15
+ };
16
+ jobs?: {
17
+ list(owner: ScopeProcessOwner): readonly ScopeProcessJob[];
18
+ };
19
+ }
20
+ /**
21
+ * Tracks process launches which can retain an old isolated mount view and
22
+ * rejects scope changes until every such view has gone away.
23
+ */
24
+ export declare class SessionScopeProcessActivity {
25
+ #private;
26
+ isProcessTool(name: string): boolean;
27
+ ensureFence(owner: ScopeProcessOwner, services: ScopeProcessServices): void;
28
+ hasActive(owner: ScopeProcessOwner, services?: ScopeProcessServices): boolean;
29
+ run<T>(owner: ScopeProcessOwner | undefined, toolName: string, operation: () => T | Promise<T>): Promise<T>;
30
+ }
31
+ //# sourceMappingURL=scope-processes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope-processes.d.ts","sourceRoot":"","sources":["../src/scope-processes.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,oCAAoC,QACyE,CAAC;AAE3H,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE;QACH,EAAE,CACA,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,OAAO,EACrC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,OAAO,CAAC;KACZ,CAAC;CACH;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,oBAAoB;IACnC,SAAS,CAAC,EAAE;QACV,gBAAgB,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC;KACrD,CAAC;IACF,IAAI,CAAC,EAAE;QACL,IAAI,CAAC,KAAK,EAAE,iBAAiB,GAAG,SAAS,eAAe,EAAE,CAAC;KAC5D,CAAC;CACH;AAQD;;;GAGG;AACH,qBAAa,2BAA2B;;IAItC,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEnC;IAED,WAAW,CAAC,KAAK,EAAE,iBAAiB,EAAE,QAAQ,EAAE,oBAAoB,GAAG,IAAI,CAiB1E;IAED,SAAS,CAAC,KAAK,EAAE,iBAAiB,EAAE,QAAQ,GAAE,oBAAyB,GAAG,OAAO,CAiBhF;IAEK,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,iBAAiB,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAWhH;CACF"}
@@ -0,0 +1,71 @@
1
+ import { SESSION_SCOPE_ERROR, SESSION_SCOPE_EVENT, } from "./session-scope.js";
2
+ export const SESSION_SCOPE_PROCESS_ACTIVE_MESSAGE = `${SESSION_SCOPE_ERROR.PROCESS_ACTIVE}: close persistent terminals and stop background shell jobs before changing scope`;
3
+ const PROCESS_TOOL_NAMES = new Set(["bash", "terminal_open"]);
4
+ const LIVE_JOB_KINDS = new Set(["bash", "pty-send"]);
5
+ const LIVE_JOB_STATUSES = new Set(["running", "stopping"]);
6
+ /**
7
+ * Tracks process launches which can retain an old isolated mount view and
8
+ * rejects scope changes until every such view has gone away.
9
+ */
10
+ export class SessionScopeProcessActivity {
11
+ #activeExecutions = new WeakMap();
12
+ #fences = new WeakMap();
13
+ isProcessTool(name) {
14
+ return PROCESS_TOOL_NAMES.has(name);
15
+ }
16
+ ensureFence(owner, services) {
17
+ const existing = this.#fences.get(owner);
18
+ if (existing !== undefined) {
19
+ existing.terminals = services.terminals ?? existing.terminals;
20
+ existing.jobs = services.jobs ?? existing.jobs;
21
+ return;
22
+ }
23
+ const state = { ...services };
24
+ this.#fences.set(owner, state);
25
+ owner.ctx.on("internal/dispatch", (_mode, eventName, args) => {
26
+ if (eventName !== "session/event")
27
+ return;
28
+ const [session, event] = args;
29
+ if (session !== owner.session || event?.type !== SESSION_SCOPE_EVENT)
30
+ return;
31
+ if (!this.hasActive(owner, state))
32
+ return;
33
+ throw new Error(SESSION_SCOPE_PROCESS_ACTIVE_MESSAGE);
34
+ }, { global: true });
35
+ }
36
+ hasActive(owner, services = {}) {
37
+ if ((this.#activeExecutions.get(owner) ?? 0) > 0)
38
+ return true;
39
+ try {
40
+ if (services.terminals?.hasOwnerActivity(owner))
41
+ return true;
42
+ }
43
+ catch {
44
+ return true;
45
+ }
46
+ try {
47
+ const jobs = services.jobs?.list(owner) ?? [];
48
+ return jobs.some((job) => LIVE_JOB_KINDS.has(job.kind ?? "")
49
+ && LIVE_JOB_STATUSES.has(job.status ?? ""));
50
+ }
51
+ catch {
52
+ return true;
53
+ }
54
+ }
55
+ async run(owner, toolName, operation) {
56
+ if (owner === undefined || !this.isProcessTool(toolName))
57
+ return operation();
58
+ this.#activeExecutions.set(owner, (this.#activeExecutions.get(owner) ?? 0) + 1);
59
+ try {
60
+ return await operation();
61
+ }
62
+ finally {
63
+ const remaining = (this.#activeExecutions.get(owner) ?? 1) - 1;
64
+ if (remaining === 0)
65
+ this.#activeExecutions.delete(owner);
66
+ else
67
+ this.#activeExecutions.set(owner, remaining);
68
+ }
69
+ }
70
+ }
71
+ //# sourceMappingURL=scope-processes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope-processes.js","sourceRoot":"","sources":["../src/scope-processes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import { type EffectiveSessionScope } from "./session-scope.js";
2
+ export interface ScopeSandboxPolicy {
3
+ mode: "read-only" | "workspace-write" | "danger-full-access" | string;
4
+ workspaceRoot: string;
5
+ [key: PropertyKey]: unknown;
6
+ }
7
+ export interface ScopeConfinedArgv {
8
+ argv: string[];
9
+ enforcement: "full" | "partial" | string;
10
+ denialSignatures: readonly string[];
11
+ runnerFailureRules: readonly unknown[];
12
+ [key: string]: unknown;
13
+ }
14
+ export interface ScopeSandboxProvider {
15
+ confine(argv: readonly string[], policy: ScopeSandboxPolicy): ScopeConfinedArgv;
16
+ }
17
+ export type BwrapProbeExecutor = (argv: readonly string[]) => boolean;
18
+ /** Same-world, non-serialized carrier added to DSH's per-call sandbox policy. */
19
+ export declare const SESSION_SCOPE_POLICY: unique symbol;
20
+ /** Require the exact, versioned DSH bwrap profile this plugin knows how to narrow. */
21
+ export declare function isSupportedBwrapInvocation(confined: ScopeConfinedArgv, policy: ScopeSandboxPolicy): boolean;
22
+ /**
23
+ * Probe the official provider seam. The local provider performs its own
24
+ * functional bwrap probe before returning this direct profile.
25
+ */
26
+ export declare function detectBwrapIsolation(provider: ScopeSandboxProvider | undefined, workspaceRoot: string, platform?: NodeJS.Platform, execute?: BwrapProbeExecutor): boolean;
27
+ /**
28
+ * Replace DSH's whole-workspace bwrap view with an empty workspace plus only
29
+ * the selected roots. Unknown argv dialects and partial enforcement fail closed.
30
+ */
31
+ export declare function confineIsolatedBwrap(confined: ScopeConfinedArgv, policy: ScopeSandboxPolicy, scope: EffectiveSessionScope, requestedWorkingDirectory?: string): ScopeConfinedArgv;
32
+ /** Attach the effective scope without changing DSH's public policy shape. */
33
+ export declare function attachSessionScopePolicy<T extends object>(policy: T, scope: EffectiveSessionScope): T;
34
+ export declare function sessionScopeFromPolicy(policy: object): EffectiveSessionScope | undefined;
35
+ //# sourceMappingURL=scope-sandbox-linux.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope-sandbox-linux.d.ts","sourceRoot":"","sources":["../src/scope-sandbox-linux.ts"],"names":[],"mappings":"AAGA,OAAO,EAGL,KAAK,qBAAqB,EAC3B,MAAM,oBAAoB,CAAC;AAE5B,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,WAAW,GAAG,iBAAiB,GAAG,oBAAoB,GAAG,MAAM,CAAC;IACtE,aAAa,EAAE,MAAM,CAAC;IACtB,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC;CAC7B;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC;IACzC,gBAAgB,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,kBAAkB,EAAE,SAAS,OAAO,EAAE,CAAC;IACvC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,MAAM,EAAE,kBAAkB,GAAG,iBAAiB,CAAC;CACjF;AAED,MAAM,MAAM,kBAAkB,GAAG,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,KAAK,OAAO,CAAC;AAEtE,iFAAiF;AACjF,eAAO,MAAM,oBAAoB,eAAyC,CAAC;AA6C3E,sFAAsF;AACtF,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,iBAAiB,EAC3B,MAAM,EAAE,kBAAkB,GACzB,OAAO,CAQT;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,oBAAoB,GAAG,SAAS,EAC1C,aAAa,EAAE,MAAM,EACrB,QAAQ,kBAAmB,EAC3B,OAAO,GAAE,kBAGR,GACA,OAAO,CAgBT;AAwCD;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,iBAAiB,EAC3B,MAAM,EAAE,kBAAkB,EAC1B,KAAK,EAAE,qBAAqB,EAC5B,yBAAyB,CAAC,EAAE,MAAM,GACjC,iBAAiB,CAkDnB;AAED,6EAA6E;AAC7E,wBAAgB,wBAAwB,CAAC,CAAC,SAAS,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,qBAAqB,GAAG,CAAC,CAErG;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,qBAAqB,GAAG,SAAS,CAExF"}