zidane 7.0.32 → 7.1.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.
- package/README.md +19 -0
- package/dist/{acp-bBDF-dhy.js → acp-B5UfEhMd.js} +4 -4
- package/dist/{acp-bBDF-dhy.js.map → acp-B5UfEhMd.js.map} +1 -1
- package/dist/acp-cli.js +6 -6
- package/dist/acp.d.ts +2 -2
- package/dist/acp.js +1 -1
- package/dist/{agent-BCG9JcZl.js → agent-_xxElOgH.js} +162 -18
- package/dist/agent-_xxElOgH.js.map +1 -0
- package/dist/agent.d.ts +1 -1
- package/dist/agent.js +1 -1
- package/dist/{anthropic-B4UmPm4H.js → anthropic-DPPs3wjJ.js} +111 -7
- package/dist/anthropic-DPPs3wjJ.js.map +1 -0
- package/dist/{approvals-DkwGBMZ9.js → approvals-u2T19Dc-.js} +275 -88
- package/dist/approvals-u2T19Dc-.js.map +1 -0
- package/dist/{auth-D0BHBb02.js → auth-HRKkOErn.js} +3 -3
- package/dist/{auth-D0BHBb02.js.map → auth-HRKkOErn.js.map} +1 -1
- package/dist/chat/pure.d.ts +3 -3
- package/dist/chat/pure.js +1 -1
- package/dist/chat.d.ts +6 -6
- package/dist/chat.js +8 -8
- package/dist/contexts/daytona.d.ts +3 -3
- package/dist/contexts/docker.d.ts +1 -1
- package/dist/contexts/e2b.d.ts +2 -2
- package/dist/contexts/sandbox.d.ts +1 -1
- package/dist/{contexts-BSFQVclW.js → contexts-CRE9pw07.js} +544 -17
- package/dist/contexts-CRE9pw07.js.map +1 -0
- package/dist/contexts.d.ts +4 -4
- package/dist/contexts.js +2 -2
- package/dist/daemon-cli.js +1 -1
- package/dist/eval.d.ts +1 -1
- package/dist/eval.js +3 -3
- package/dist/extensions.d.ts +1 -1
- package/dist/extensions.js +1 -1
- package/dist/headless.d.ts +1 -1
- package/dist/headless.js +3 -3
- package/dist/{index-B6FkK6ZN.d.ts → index-C37_ppWv.d.ts} +2 -2
- package/dist/index-C37_ppWv.d.ts.map +1 -0
- package/dist/{index-Ogi2CeHf.d.ts → index-D3TTaaQ5.d.ts} +20 -7
- package/dist/index-D3TTaaQ5.d.ts.map +1 -0
- package/dist/{index-CCB05-JZ.d.ts → index-DZhrTn-v.d.ts} +259 -12
- package/dist/index-DZhrTn-v.d.ts.map +1 -0
- package/dist/index.d.ts +5 -5
- package/dist/index.js +8 -8
- package/dist/{ipc-C10lnS-a.js → ipc-DwauKEE-.js} +3 -3
- package/dist/{ipc-C10lnS-a.js.map → ipc-DwauKEE-.js.map} +1 -1
- package/dist/ipc.d.ts +5 -5
- package/dist/ipc.js +3 -3
- package/dist/{types-U-rIVUDw.d.ts → isolation-Kfoof0MM.d.ts} +93 -2
- package/dist/isolation-Kfoof0MM.d.ts.map +1 -0
- package/dist/mcp.d.ts +1 -1
- package/dist/output/stream-json.d.ts +1 -1
- package/dist/output/terminal.d.ts +1 -1
- package/dist/{plugins-B531Tz5b.js → plugins-gbI7SBA6.js} +3 -3
- package/dist/{plugins-B531Tz5b.js.map → plugins-gbI7SBA6.js.map} +1 -1
- package/dist/plugins.d.ts +1 -1
- package/dist/plugins.js +1 -1
- package/dist/presets.d.ts +1 -1
- package/dist/presets.js +1 -1
- package/dist/providers/anthropic.d.ts +2 -2
- package/dist/providers/anthropic.js +2 -2
- package/dist/providers/arcee.d.ts +1 -1
- package/dist/providers/baseten.d.ts +1 -1
- package/dist/providers/cerebras.d.ts +1 -1
- package/dist/providers/local.d.ts +1 -1
- package/dist/providers/openai-compat.d.ts +1 -1
- package/dist/providers/openai.d.ts +1 -1
- package/dist/providers/openrouter.d.ts +1 -1
- package/dist/providers/xai.d.ts +1 -1
- package/dist/providers.d.ts +2 -2
- package/dist/providers.js +1 -1
- package/dist/restate.d.ts +2 -2
- package/dist/restate.js +1 -1
- package/dist/{sandbox-CDl9tfTo.d.ts → sandbox-BH0WQkXn.d.ts} +2 -2
- package/dist/{sandbox-CDl9tfTo.d.ts.map → sandbox-BH0WQkXn.d.ts.map} +1 -1
- package/dist/{server--mwNA7oC.js → server-DvPnPSZb.js} +8 -8
- package/dist/{server--mwNA7oC.js.map → server-DvPnPSZb.js.map} +1 -1
- package/dist/session/sqlite.d.ts +1 -1
- package/dist/session/sqlite.d.ts.map +1 -1
- package/dist/session/sqlite.js +7 -0
- package/dist/session/sqlite.js.map +1 -1
- package/dist/{session-CVy-2mAy.js → session-BqRP1hS7.js} +33 -3
- package/dist/session-BqRP1hS7.js.map +1 -0
- package/dist/session.d.ts +1 -1
- package/dist/session.js +1 -1
- package/dist/{skills-PJyiSRCp.js → skills-BC3dodWp.js} +2 -2
- package/dist/{skills-PJyiSRCp.js.map → skills-BC3dodWp.js.map} +1 -1
- package/dist/skills.d.ts +1 -1
- package/dist/skills.js +1 -1
- package/dist/{src-CjkY6fBj.js → src-CkNQKFKr.js} +3 -3
- package/dist/{src-CjkY6fBj.js.map → src-CkNQKFKr.js.map} +1 -1
- package/dist/{tool-formatters-Bu4repDJ.d.ts → tool-formatters-C5s88MUd.d.ts} +2 -2
- package/dist/{tool-formatters-Bu4repDJ.d.ts.map → tool-formatters-C5s88MUd.d.ts.map} +1 -1
- package/dist/tools/fetch-url.d.ts +1 -1
- package/dist/tools/web-search.d.ts +1 -1
- package/dist/tools.d.ts +1 -1
- package/dist/tools.js +1 -1
- package/dist/{transcript-anchors-CJCxyVE-.d.ts → transcript-anchors-DxofXw_y.d.ts} +3 -3
- package/dist/transcript-anchors-DxofXw_y.d.ts.map +1 -0
- package/dist/tui.d.ts +21 -28
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +163 -69
- package/dist/tui.js.map +1 -1
- package/dist/{turn-operations-HX3g3XIc.js → turn-operations-6JDu2ewy.js} +14 -2
- package/dist/{turn-operations-HX3g3XIc.js.map → turn-operations-6JDu2ewy.js.map} +1 -1
- package/dist/{turn-operations-qcv9UFcL.d.ts → turn-operations-BaQnxzhr.d.ts} +14 -4
- package/dist/{turn-operations-qcv9UFcL.d.ts.map → turn-operations-BaQnxzhr.d.ts.map} +1 -1
- package/dist/types-CWgENVLY.js.map +1 -1
- package/dist/types.d.ts +3 -3
- package/docs/ARCHITECTURE.md +2 -1
- package/docs/CHAT.md +9 -1
- package/docs/EXECUTION_CONTEXT.md +64 -3
- package/docs/SKILL.md +28 -0
- package/docs/TUI.md +6 -5
- package/package.json +1 -1
- package/dist/agent-BCG9JcZl.js.map +0 -1
- package/dist/anthropic-B4UmPm4H.js.map +0 -1
- package/dist/approvals-DkwGBMZ9.js.map +0 -1
- package/dist/contexts-BSFQVclW.js.map +0 -1
- package/dist/index-B6FkK6ZN.d.ts.map +0 -1
- package/dist/index-CCB05-JZ.d.ts.map +0 -1
- package/dist/index-Ogi2CeHf.d.ts.map +0 -1
- package/dist/session-CVy-2mAy.js.map +0 -1
- package/dist/transcript-anchors-CJCxyVE-.d.ts.map +0 -1
- package/dist/types-U-rIVUDw.d.ts.map +0 -1
|
@@ -1,9 +1,493 @@
|
|
|
1
1
|
import { t as lazyAsync } from "./lazy-DLOurOC_.js";
|
|
2
2
|
import { n as globLiteralPrefix, t as globFilesLocal } from "./glob-DluQFSw1.js";
|
|
3
3
|
import { a as outputExceededMessage, n as appendCapped, t as DEFAULT_MAX_OUTPUT_BUFFER } from "./output-cap-C9zukcCj.js";
|
|
4
|
-
import { dirname, isAbsolute, relative, resolve } from "node:path";
|
|
5
|
-
import { createWriteStream } from "node:fs";
|
|
4
|
+
import { delimiter, dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
5
|
+
import { accessSync, constants, createWriteStream, realpathSync, statSync } from "node:fs";
|
|
6
|
+
import { homedir } from "node:os";
|
|
6
7
|
import { mkdir, readFile, readdir, realpath, stat, writeFile } from "node:fs/promises";
|
|
8
|
+
//#region src/contexts/isolation.ts
|
|
9
|
+
/**
|
|
10
|
+
* Only `/usr/bin/sandbox-exec` is trusted — never a `PATH` lookup — so a
|
|
11
|
+
* tampered binary earlier in `PATH` cannot silently replace the sandbox.
|
|
12
|
+
*/
|
|
13
|
+
const SEATBELT_EXECUTABLE = "/usr/bin/sandbox-exec";
|
|
14
|
+
/**
|
|
15
|
+
* Credential material hidden from sandboxed commands by default. Relative
|
|
16
|
+
* to `$HOME`; resolved at policy-build time. Covers the usual suspects plus
|
|
17
|
+
* zidane's own OAuth / API-key store.
|
|
18
|
+
*/
|
|
19
|
+
const DEFAULT_UNREADABLE_DIRS = [
|
|
20
|
+
".ssh",
|
|
21
|
+
".aws",
|
|
22
|
+
".gnupg",
|
|
23
|
+
".azure",
|
|
24
|
+
".config/gcloud",
|
|
25
|
+
".kube",
|
|
26
|
+
".docker/config.json",
|
|
27
|
+
".netrc",
|
|
28
|
+
".zidane/credentials.json",
|
|
29
|
+
".zidane/mcp-credentials.json",
|
|
30
|
+
".credentials.json"
|
|
31
|
+
];
|
|
32
|
+
/** Backend for `platform` (defaults to the current process). `null` = unsupported OS. */
|
|
33
|
+
function detectIsolationBackend(platform = process.platform) {
|
|
34
|
+
if (platform === "darwin") return "seatbelt";
|
|
35
|
+
if (platform === "linux") return "bwrap";
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
function isExecutable(path) {
|
|
39
|
+
try {
|
|
40
|
+
accessSync(path, constants.X_OK);
|
|
41
|
+
return true;
|
|
42
|
+
} catch {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function whichSync(name, env = process.env) {
|
|
47
|
+
for (const dir of (env.PATH ?? "").split(delimiter)) {
|
|
48
|
+
if (!dir) continue;
|
|
49
|
+
const candidate = join(dir, name);
|
|
50
|
+
if (isExecutable(candidate)) return candidate;
|
|
51
|
+
}
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Whether the sandbox can actually be enforced on this host. Callers that
|
|
56
|
+
* requested isolation and get `ok: false` MUST fail closed (refuse to run
|
|
57
|
+
* the command) — silently running unsandboxed would turn a security
|
|
58
|
+
* setting into a placebo.
|
|
59
|
+
*/
|
|
60
|
+
function isolationAvailability(platform = process.platform, env = process.env) {
|
|
61
|
+
const backend = detectIsolationBackend(platform);
|
|
62
|
+
if (backend === null) return {
|
|
63
|
+
ok: false,
|
|
64
|
+
reason: `OS sandboxing is not supported on ${platform} (macOS Seatbelt and Linux bwrap only)`
|
|
65
|
+
};
|
|
66
|
+
if (backend === "seatbelt") return isExecutable("/usr/bin/sandbox-exec") ? {
|
|
67
|
+
ok: true,
|
|
68
|
+
backend,
|
|
69
|
+
executable: SEATBELT_EXECUTABLE
|
|
70
|
+
} : {
|
|
71
|
+
ok: false,
|
|
72
|
+
reason: `${SEATBELT_EXECUTABLE} is missing or not executable`
|
|
73
|
+
};
|
|
74
|
+
const bwrap = whichSync("bwrap", env);
|
|
75
|
+
return bwrap ? {
|
|
76
|
+
ok: true,
|
|
77
|
+
backend,
|
|
78
|
+
executable: bwrap
|
|
79
|
+
} : {
|
|
80
|
+
ok: false,
|
|
81
|
+
reason: "bwrap (bubblewrap) is not installed — install it with your package manager (e.g. `apt install bubblewrap`)"
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
/** Expand a leading `~` / `~/` to `home`. Other paths returned unchanged. */
|
|
85
|
+
function expandHome(path, home = homedir()) {
|
|
86
|
+
if (path === "~") return home;
|
|
87
|
+
if (path.startsWith("~/")) return join(home, path.slice(2));
|
|
88
|
+
return path;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Parse the user-facing "extra writable paths" setting: comma- or
|
|
92
|
+
* newline-separated, `~` expanded, relative entries resolved against `cwd`,
|
|
93
|
+
* blanks dropped.
|
|
94
|
+
*/
|
|
95
|
+
function parseAllowWriteSetting(raw, cwd, home = homedir()) {
|
|
96
|
+
return raw.split(/[,\n]/).map((s) => s.trim()).filter(Boolean).map((p) => resolve(cwd, expandHome(p, home)));
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* `realpath` that also works for paths that don't exist yet (an `extra`
|
|
100
|
+
* root the user hasn't created): the deepest existing ancestor is
|
|
101
|
+
* canonicalized and the missing tail re-appended. Without this, `/tmp/x`
|
|
102
|
+
* and `/private/tmp/x` would look like different roots on macOS.
|
|
103
|
+
*/
|
|
104
|
+
function canonical(path) {
|
|
105
|
+
let existing = resolve(path);
|
|
106
|
+
const tail = [];
|
|
107
|
+
while (true) try {
|
|
108
|
+
existing = realpathSync(existing);
|
|
109
|
+
break;
|
|
110
|
+
} catch {
|
|
111
|
+
const parent = dirname(existing);
|
|
112
|
+
if (parent === existing) break;
|
|
113
|
+
tail.unshift(relative(parent, existing));
|
|
114
|
+
existing = parent;
|
|
115
|
+
}
|
|
116
|
+
return tail.length ? resolve(existing, ...tail) : existing;
|
|
117
|
+
}
|
|
118
|
+
/** True when `target` is `root` or lives under it. */
|
|
119
|
+
function isWithinRoot(root, target) {
|
|
120
|
+
const rel = relative(root, target);
|
|
121
|
+
return rel === "" || !rel.startsWith("..") && !isAbsolute(rel);
|
|
122
|
+
}
|
|
123
|
+
/** Drop roots already covered by another root in the list; keeps first-seen order. */
|
|
124
|
+
function dedupeRoots(roots) {
|
|
125
|
+
const out = [];
|
|
126
|
+
for (const root of roots) {
|
|
127
|
+
if (out.some((existing) => isWithinRoot(existing, root))) continue;
|
|
128
|
+
for (let i = out.length - 1; i >= 0; i--) if (isWithinRoot(root, out[i])) out.splice(i, 1);
|
|
129
|
+
out.push(root);
|
|
130
|
+
}
|
|
131
|
+
return out;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Why git's common dir matters: `git rev-parse --git-common-dir` prints a
|
|
135
|
+
* path relative to cwd for the primary checkout (`.git`) and an absolute
|
|
136
|
+
* path for linked worktrees. Without the worktree's common dir writable,
|
|
137
|
+
* `git commit` / `git add` inside a worktree fail under the sandbox —
|
|
138
|
+
* the index and objects live in the main repo's `.git`.
|
|
139
|
+
*
|
|
140
|
+
* Two probes, one contract (`null` on any failure, including no `git`
|
|
141
|
+
* binary, a non-repo, or a slow git — a wedged git must not wedge the
|
|
142
|
+
* host, so slow reads as "not a worktree"):
|
|
143
|
+
* - {@link defaultGitCommonDir}: synchronous, for the in-process TUI whose
|
|
144
|
+
* `buildAgent` is sync. Blocks that window only; 1 s cap.
|
|
145
|
+
* - {@link defaultGitCommonDirAsync}: for the daemon, where a sync probe
|
|
146
|
+
* would stall every window and session on the shared event loop.
|
|
147
|
+
*
|
|
148
|
+
* `node:child_process` is resolved through `process.getBuiltinModule` (not a
|
|
149
|
+
* static import) for the same reason `process.ts` lazy-loads `spawn`: this
|
|
150
|
+
* module sits in the default execution context's import graph, and merely
|
|
151
|
+
* importing zidane must stay possible on shell-less runtimes (edge isolates)
|
|
152
|
+
* where that builtin is gated. Node 20.16+ / Bun; `undefined` → `null`.
|
|
153
|
+
*/
|
|
154
|
+
const GIT_PROBE_ARGS = ["rev-parse", "--git-common-dir"];
|
|
155
|
+
const GIT_PROBE_SYNC_TIMEOUT_MS = 1e3;
|
|
156
|
+
const GIT_PROBE_ASYNC_TIMEOUT_MS = 3e3;
|
|
157
|
+
function childProcess() {
|
|
158
|
+
return process.getBuiltinModule?.("node:child_process");
|
|
159
|
+
}
|
|
160
|
+
function defaultGitCommonDir(cwd) {
|
|
161
|
+
try {
|
|
162
|
+
const cp = childProcess();
|
|
163
|
+
if (!cp) return null;
|
|
164
|
+
const out = cp.execFileSync("git", GIT_PROBE_ARGS, {
|
|
165
|
+
cwd,
|
|
166
|
+
timeout: GIT_PROBE_SYNC_TIMEOUT_MS,
|
|
167
|
+
encoding: "utf8",
|
|
168
|
+
stdio: [
|
|
169
|
+
"ignore",
|
|
170
|
+
"pipe",
|
|
171
|
+
"ignore"
|
|
172
|
+
]
|
|
173
|
+
}).trim();
|
|
174
|
+
return out ? resolve(cwd, out) : null;
|
|
175
|
+
} catch {
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
function defaultGitCommonDirAsync(cwd) {
|
|
180
|
+
const cp = childProcess();
|
|
181
|
+
if (!cp) return Promise.resolve(null);
|
|
182
|
+
return new Promise((resolveP) => {
|
|
183
|
+
try {
|
|
184
|
+
cp.execFile("git", GIT_PROBE_ARGS, {
|
|
185
|
+
cwd,
|
|
186
|
+
timeout: GIT_PROBE_ASYNC_TIMEOUT_MS,
|
|
187
|
+
encoding: "utf8"
|
|
188
|
+
}, (err, stdout) => {
|
|
189
|
+
if (err) return resolveP(null);
|
|
190
|
+
const out = stdout.trim();
|
|
191
|
+
resolveP(out ? resolve(cwd, out) : null);
|
|
192
|
+
});
|
|
193
|
+
} catch {
|
|
194
|
+
resolveP(null);
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* The set of directories a sandboxed command may write to: the workspace
|
|
200
|
+
* (`cwd`), the system temp dirs, git's common dir when `cwd` is a linked
|
|
201
|
+
* worktree, plus any user-configured extras. All canonicalized.
|
|
202
|
+
*/
|
|
203
|
+
function resolveWritableRoots(cwd, options = {}) {
|
|
204
|
+
return assembleWritableRoots(cwd, (options.gitCommonDir ?? defaultGitCommonDir)(cwd), options);
|
|
205
|
+
}
|
|
206
|
+
/** Async twin of {@link resolveWritableRoots} for hosts that must not block (the daemon). */
|
|
207
|
+
async function resolveWritableRootsAsync(cwd, options = {}) {
|
|
208
|
+
return assembleWritableRoots(cwd, await (options.gitCommonDir ?? defaultGitCommonDirAsync)(cwd), options);
|
|
209
|
+
}
|
|
210
|
+
function assembleWritableRoots(cwd, gitCommonDir, options) {
|
|
211
|
+
const env = options.env ?? process.env;
|
|
212
|
+
const platform = options.platform ?? process.platform;
|
|
213
|
+
const raw = [cwd];
|
|
214
|
+
if (env.TMPDIR) raw.push(env.TMPDIR);
|
|
215
|
+
raw.push("/tmp", "/var/tmp");
|
|
216
|
+
if (platform === "darwin") raw.push("/private/tmp", "/private/var/tmp");
|
|
217
|
+
if (gitCommonDir) raw.push(gitCommonDir);
|
|
218
|
+
raw.push(...options.extra ?? []);
|
|
219
|
+
return dedupeRoots(raw.map(canonical));
|
|
220
|
+
}
|
|
221
|
+
/** Resolve {@link DEFAULT_UNREADABLE_DIRS} (or a custom list) against `home`. */
|
|
222
|
+
function resolveUnreadableDirs(dirs = DEFAULT_UNREADABLE_DIRS, home = homedir()) {
|
|
223
|
+
return dirs.map((d) => isAbsolute(d) ? d : join(home, d));
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Deny-default base. Derived from Codex's `seatbelt_base_policy.sbpl`
|
|
227
|
+
* (Apache-2.0), itself from Chromium's renderer/common sandbox policies.
|
|
228
|
+
* Filesystem READ is allowed broadly (below); WRITE and NETWORK are added
|
|
229
|
+
* per policy in {@link buildSeatbeltProfile}.
|
|
230
|
+
*/
|
|
231
|
+
const SEATBELT_BASE_POLICY = `(version 1)
|
|
232
|
+
|
|
233
|
+
; deny-default; everything below is an explicit allow
|
|
234
|
+
(deny default)
|
|
235
|
+
|
|
236
|
+
; child processes inherit the policy of their parent
|
|
237
|
+
(allow process-exec)
|
|
238
|
+
(allow process-fork)
|
|
239
|
+
(allow signal (target same-sandbox))
|
|
240
|
+
(allow process-info* (target same-sandbox))
|
|
241
|
+
|
|
242
|
+
; reads are allowed everywhere except the unreadable roots. SBPL is
|
|
243
|
+
; LAST-MATCH-WINS: the deny block for those roots is emitted at the very
|
|
244
|
+
; end of the profile by buildSeatbeltProfile and must stay there.
|
|
245
|
+
(allow file-read*)
|
|
246
|
+
(allow file-write* (literal "/dev/null"))
|
|
247
|
+
(allow file-read* file-write* (literal "/dev/stdin"))
|
|
248
|
+
(allow file-read* file-write* (literal "/dev/stdout"))
|
|
249
|
+
(allow file-read* file-write* (literal "/dev/stderr"))
|
|
250
|
+
(allow file-read* file-write* (literal "/dev/tty"))
|
|
251
|
+
(allow file-read* file-write* (literal "/dev/random"))
|
|
252
|
+
(allow file-read* file-write* (literal "/dev/urandom"))
|
|
253
|
+
(allow file-read* file-write* (literal "/dev/zero"))
|
|
254
|
+
(allow file-ioctl (literal "/dev/dtracehelper"))
|
|
255
|
+
(allow file-read* file-write* (literal "/dev/dtracehelper"))
|
|
256
|
+
|
|
257
|
+
; sysctls
|
|
258
|
+
(allow sysctl-read
|
|
259
|
+
(sysctl-name "hw.activecpu")
|
|
260
|
+
(sysctl-name "hw.busfrequency_compat")
|
|
261
|
+
(sysctl-name "hw.byteorder")
|
|
262
|
+
(sysctl-name "hw.cacheconfig")
|
|
263
|
+
(sysctl-name "hw.cachelinesize_compat")
|
|
264
|
+
(sysctl-name "hw.cpufamily")
|
|
265
|
+
(sysctl-name "hw.cpufrequency_compat")
|
|
266
|
+
(sysctl-name "hw.cputype")
|
|
267
|
+
(sysctl-name "hw.l1dcachesize_compat")
|
|
268
|
+
(sysctl-name "hw.l1icachesize_compat")
|
|
269
|
+
(sysctl-name "hw.l2cachesize_compat")
|
|
270
|
+
(sysctl-name "hw.l3cachesize_compat")
|
|
271
|
+
(sysctl-name "hw.logicalcpu_max")
|
|
272
|
+
(sysctl-name "hw.machine")
|
|
273
|
+
(sysctl-name "hw.model")
|
|
274
|
+
(sysctl-name "hw.memsize")
|
|
275
|
+
(sysctl-name "hw.ncpu")
|
|
276
|
+
(sysctl-name "hw.nperflevels")
|
|
277
|
+
(sysctl-name-prefix "hw.optional.arm.")
|
|
278
|
+
(sysctl-name-prefix "hw.optional.armv8_")
|
|
279
|
+
(sysctl-name "hw.packages")
|
|
280
|
+
(sysctl-name "hw.pagesize_compat")
|
|
281
|
+
(sysctl-name "hw.pagesize")
|
|
282
|
+
(sysctl-name "hw.physicalcpu")
|
|
283
|
+
(sysctl-name "hw.physicalcpu_max")
|
|
284
|
+
(sysctl-name "hw.logicalcpu")
|
|
285
|
+
(sysctl-name "hw.cpufrequency")
|
|
286
|
+
(sysctl-name "hw.tbfrequency_compat")
|
|
287
|
+
(sysctl-name "hw.vectorunit")
|
|
288
|
+
(sysctl-name "machdep.cpu.brand_string")
|
|
289
|
+
(sysctl-name "kern.argmax")
|
|
290
|
+
(sysctl-name "kern.hostname")
|
|
291
|
+
(sysctl-name "kern.maxfilesperproc")
|
|
292
|
+
(sysctl-name "kern.maxproc")
|
|
293
|
+
(sysctl-name "kern.osproductversion")
|
|
294
|
+
(sysctl-name "kern.osrelease")
|
|
295
|
+
(sysctl-name "kern.ostype")
|
|
296
|
+
(sysctl-name "kern.osvariant_status")
|
|
297
|
+
(sysctl-name "kern.osversion")
|
|
298
|
+
(sysctl-name "kern.secure_kernel")
|
|
299
|
+
(sysctl-name "kern.sysv.semmns")
|
|
300
|
+
(sysctl-name "kern.usrstack64")
|
|
301
|
+
(sysctl-name "kern.version")
|
|
302
|
+
(sysctl-name "sysctl.proc_cputype")
|
|
303
|
+
(sysctl-name "vm.loadavg")
|
|
304
|
+
(sysctl-name-prefix "hw.perflevel")
|
|
305
|
+
(sysctl-name-prefix "kern.proc.pgrp.")
|
|
306
|
+
(sysctl-name-prefix "kern.proc.pid.")
|
|
307
|
+
(sysctl-name-prefix "net.routetable.")
|
|
308
|
+
)
|
|
309
|
+
; Java CPU probe (a read that the kernel classifies as a write)
|
|
310
|
+
(allow sysctl-write (sysctl-name "kern.grade_cputype"))
|
|
311
|
+
|
|
312
|
+
(allow iokit-open (iokit-registry-entry-class "RootDomainUserClient"))
|
|
313
|
+
|
|
314
|
+
; user lookup (getpwuid & co)
|
|
315
|
+
(allow mach-lookup (global-name "com.apple.system.opendirectoryd.libinfo"))
|
|
316
|
+
(allow mach-lookup (global-name "com.apple.PowerManagement.control"))
|
|
317
|
+
|
|
318
|
+
; python multiprocessing / OpenMP
|
|
319
|
+
(allow ipc-posix-sem)
|
|
320
|
+
(allow ipc-posix-shm-read-data
|
|
321
|
+
ipc-posix-shm-write-create
|
|
322
|
+
ipc-posix-shm-write-unlink
|
|
323
|
+
(ipc-posix-name-regex #"^/__KMP_REGISTERED_LIB_[0-9]+$"))
|
|
324
|
+
|
|
325
|
+
; openpty()
|
|
326
|
+
(allow pseudo-tty)
|
|
327
|
+
(allow file-read* file-write* file-ioctl (literal "/dev/ptmx"))
|
|
328
|
+
(allow file-read* file-write*
|
|
329
|
+
(require-all
|
|
330
|
+
(regex #"^/dev/ttys[0-9]+")
|
|
331
|
+
(extension "com.apple.sandbox.pty")))
|
|
332
|
+
(allow file-ioctl (regex #"^/dev/ttys[0-9]+"))
|
|
333
|
+
`;
|
|
334
|
+
/**
|
|
335
|
+
* Network allow block. Mirrors Codex's `seatbelt_network_policy.sbpl`: full
|
|
336
|
+
* outbound/inbound plus the mach services TLS + DNS resolution need.
|
|
337
|
+
*/
|
|
338
|
+
const SEATBELT_NETWORK_POLICY = `
|
|
339
|
+
; ---- network: allow ----
|
|
340
|
+
(allow network-outbound)
|
|
341
|
+
(allow network-inbound)
|
|
342
|
+
(allow network-bind)
|
|
343
|
+
(allow system-socket
|
|
344
|
+
(require-all
|
|
345
|
+
(socket-domain AF_SYSTEM)
|
|
346
|
+
(socket-protocol 2)))
|
|
347
|
+
(allow mach-lookup
|
|
348
|
+
(global-name "com.apple.bsd.dirhelper")
|
|
349
|
+
(global-name "com.apple.system.opendirectoryd.membership")
|
|
350
|
+
(global-name "com.apple.SecurityServer")
|
|
351
|
+
(global-name "com.apple.networkd")
|
|
352
|
+
(global-name "com.apple.ocspd")
|
|
353
|
+
(global-name "com.apple.trustd.agent")
|
|
354
|
+
(global-name "com.apple.SystemConfiguration.DNSConfiguration")
|
|
355
|
+
(global-name "com.apple.SystemConfiguration.configd"))
|
|
356
|
+
(allow sysctl-read (sysctl-name-regex #"^net.routetable"))
|
|
357
|
+
`;
|
|
358
|
+
const WRITABLE_ROOT_PARAM = "WRITABLE_ROOT_";
|
|
359
|
+
const UNREADABLE_ROOT_PARAM = "UNREADABLE_ROOT_";
|
|
360
|
+
/**
|
|
361
|
+
* Build the SBPL profile + params for a policy. Paths are NEVER inlined in
|
|
362
|
+
* the profile text: each is bound to a `-D` param and referenced via
|
|
363
|
+
* `(param "…")`, so spaces, quotes and parentheses in paths need no
|
|
364
|
+
* escaping and the profile text is identical across machines (only the
|
|
365
|
+
* params differ) — which makes it unit-testable as a string.
|
|
366
|
+
*
|
|
367
|
+
* ORDERING IS A SECURITY INVARIANT. Seatbelt resolves overlapping rules by
|
|
368
|
+
* position — the LAST matching rule wins; there is no deny-over-allow
|
|
369
|
+
* precedence. The credential mask (`deny file-read*` on the unreadable
|
|
370
|
+
* roots) only holds because it is the final block, after `(allow
|
|
371
|
+
* file-read*)` in the base policy, the writable-root allows and the
|
|
372
|
+
* network block. Never hoist or reorder it; the profile test asserts every
|
|
373
|
+
* `(deny` line follows every `(allow` line.
|
|
374
|
+
*/
|
|
375
|
+
function buildSeatbeltProfile(policy, home = homedir()) {
|
|
376
|
+
const params = [];
|
|
377
|
+
const lines = [SEATBELT_BASE_POLICY];
|
|
378
|
+
lines.push("; ---- writable roots ----");
|
|
379
|
+
policy.writableRoots.forEach((root, i) => {
|
|
380
|
+
const key = `${WRITABLE_ROOT_PARAM}${i}`;
|
|
381
|
+
params.push([key, root]);
|
|
382
|
+
lines.push(`(allow file-write* (subpath (param "${key}")))`);
|
|
383
|
+
});
|
|
384
|
+
if (policy.network === "allow") lines.push(SEATBELT_NETWORK_POLICY);
|
|
385
|
+
else lines.push("; ---- network: deny (default deny covers all socket ops) ----");
|
|
386
|
+
const unreadable = resolveUnreadableDirs(policy.unreadableDirs, home);
|
|
387
|
+
if (unreadable.length > 0) {
|
|
388
|
+
lines.push("; ---- unreadable roots (must be the final block: last match wins) ----");
|
|
389
|
+
unreadable.forEach((dir, i) => {
|
|
390
|
+
const key = `${UNREADABLE_ROOT_PARAM}${i}`;
|
|
391
|
+
params.push([key, dir]);
|
|
392
|
+
lines.push(`(deny file-read* file-write* (subpath (param "${key}")))`);
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
return {
|
|
396
|
+
profile: `${lines.join("\n")}\n`,
|
|
397
|
+
params
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* bwrap argv for a policy (without the trailing command). The whole host FS
|
|
402
|
+
* is bound read-only, writable roots are re-bound read-write on top, and
|
|
403
|
+
* unreadable dirs are masked with an empty tmpfs. `--die-with-parent` ties
|
|
404
|
+
* the sandbox to the zidane process; no `--new-session`/`--unshare-pid` so
|
|
405
|
+
* the child stays in the caller's process group (the process context kills
|
|
406
|
+
* by `-pgid`) and `ps`/`kill` inside the sandbox behave as usual.
|
|
407
|
+
*/
|
|
408
|
+
function buildBwrapArgs(policy, home = homedir(), kind = statKind) {
|
|
409
|
+
const args = [
|
|
410
|
+
"--ro-bind",
|
|
411
|
+
"/",
|
|
412
|
+
"/",
|
|
413
|
+
"--dev",
|
|
414
|
+
"/dev",
|
|
415
|
+
"--proc",
|
|
416
|
+
"/proc",
|
|
417
|
+
"--die-with-parent"
|
|
418
|
+
];
|
|
419
|
+
for (const root of policy.writableRoots) args.push("--bind-try", root, root);
|
|
420
|
+
for (const path of resolveUnreadableDirs(policy.unreadableDirs, home)) {
|
|
421
|
+
const k = kind(path);
|
|
422
|
+
if (k === "dir") args.push("--tmpfs", path);
|
|
423
|
+
else if (k === "file") args.push("--ro-bind", "/dev/null", path);
|
|
424
|
+
}
|
|
425
|
+
if (policy.network === "deny") args.push("--unshare-net");
|
|
426
|
+
return args;
|
|
427
|
+
}
|
|
428
|
+
function statKind(path) {
|
|
429
|
+
try {
|
|
430
|
+
return statSync(path).isDirectory() ? "dir" : "file";
|
|
431
|
+
} catch {
|
|
432
|
+
return null;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* Produce the `{ file, args }` that runs `/bin/sh -c command` under the
|
|
437
|
+
* sandbox. `home` is injectable for tests.
|
|
438
|
+
*/
|
|
439
|
+
function wrapCommand(backend, executable, policy, command, home = homedir()) {
|
|
440
|
+
if (backend === "seatbelt") {
|
|
441
|
+
const { profile, params } = buildSeatbeltProfile(policy, home);
|
|
442
|
+
const args = ["-p", profile];
|
|
443
|
+
for (const [key, value] of params) args.push(`-D${key}=${value}`);
|
|
444
|
+
args.push("--", "/bin/sh", "-c", command);
|
|
445
|
+
return {
|
|
446
|
+
file: executable,
|
|
447
|
+
args
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
return {
|
|
451
|
+
file: executable,
|
|
452
|
+
args: [
|
|
453
|
+
...buildBwrapArgs(policy, home),
|
|
454
|
+
"--",
|
|
455
|
+
"/bin/sh",
|
|
456
|
+
"-c",
|
|
457
|
+
command
|
|
458
|
+
]
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
/**
|
|
462
|
+
* Patterns a sandboxed command emits when the kernel refuses an operation.
|
|
463
|
+
* Seatbelt surfaces `Operation not permitted` (EPERM); bwrap's read-only
|
|
464
|
+
* root yields `Read-only file system` (EROFS); an unshared netns gives
|
|
465
|
+
* DNS / connect failures that vary by tool, so only the two FS ones are
|
|
466
|
+
* matched — network denial is reported through `network: deny` text.
|
|
467
|
+
*/
|
|
468
|
+
const DENIAL_RE = /Operation not permitted|Read-only file system|sandbox-exec: |deny\(1\)|bwrap: /i;
|
|
469
|
+
/**
|
|
470
|
+
* Append a one-line explanation to a failed result when the failure looks
|
|
471
|
+
* like a sandbox denial. The model otherwise sees a bare EPERM and guesses;
|
|
472
|
+
* this names the mechanism and the exact setting that widens it.
|
|
473
|
+
*/
|
|
474
|
+
function annotateDenial(result, policy) {
|
|
475
|
+
if (result.exitCode === 0 || !DENIAL_RE.test(result.stderr)) return result;
|
|
476
|
+
const hint = `[sandbox] this command ran under zidane's OS sandbox: writes are limited to ${policy.writableRoots.join(", ")}${policy.network === "deny" ? "; network is blocked" : ""}. If the failure is a sandbox denial, ask the user to add the path under Settings → "Sandbox writable paths" or turn off "Sandbox shell commands".`;
|
|
477
|
+
return {
|
|
478
|
+
...result,
|
|
479
|
+
stderr: result.stderr ? `${result.stderr}\n${hint}` : hint
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
/** Result returned for every command when isolation was requested but cannot be enforced. */
|
|
483
|
+
function unavailableResult(reason) {
|
|
484
|
+
return {
|
|
485
|
+
stdout: "",
|
|
486
|
+
stderr: `[sandbox] "Sandbox shell commands" is on but cannot be enforced: ${reason}. Refusing to run unsandboxed — ask the user to fix the sandbox or turn the setting off.`,
|
|
487
|
+
exitCode: 127
|
|
488
|
+
};
|
|
489
|
+
}
|
|
490
|
+
//#endregion
|
|
7
491
|
//#region src/contexts/process.ts
|
|
8
492
|
/**
|
|
9
493
|
* Lazily load `node:child_process`'s `spawn` (memoized after first use).
|
|
@@ -113,10 +597,23 @@ function createProcessContext(config) {
|
|
|
113
597
|
"TMPDIR"
|
|
114
598
|
]) : process.env;
|
|
115
599
|
const workspaceRoot = config?.workspaceRoot !== void 0 ? resolve(defaultCwd, config.workspaceRoot) : void 0;
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
600
|
+
const isolation = config?.isolation;
|
|
601
|
+
const isolationState = isolation ? isolationAvailability() : void 0;
|
|
602
|
+
/**
|
|
603
|
+
* `{ file, args }` for `/bin/sh -c command`, wrapped in the sandbox when
|
|
604
|
+
* isolation is on. Callers check `isolationState.ok` first (the three
|
|
605
|
+
* shell entry points return `unavailableResult` / throw before spawning).
|
|
606
|
+
*/
|
|
607
|
+
function shellCommand(command) {
|
|
608
|
+
if (isolation && isolationState?.ok) return wrapCommand(isolationState.backend, isolationState.executable, isolation, command);
|
|
609
|
+
return {
|
|
610
|
+
file: "/bin/sh",
|
|
611
|
+
args: ["-c", command]
|
|
612
|
+
};
|
|
613
|
+
}
|
|
614
|
+
/** Failure result when isolation was requested but cannot be enforced; `undefined` = proceed. */
|
|
615
|
+
function isolationBlocker() {
|
|
616
|
+
return isolationState && !isolationState.ok ? unavailableResult(isolationState.reason) : void 0;
|
|
120
617
|
}
|
|
121
618
|
/**
|
|
122
619
|
* Resolve `path` against the handle cwd and, when a `workspaceRoot` is
|
|
@@ -127,6 +624,16 @@ function createProcessContext(config) {
|
|
|
127
624
|
async function resolveContained(handle, path) {
|
|
128
625
|
const full = resolve(handle.cwd, path);
|
|
129
626
|
if (workspaceRoot === void 0) return full;
|
|
627
|
+
const canonical = await canonicalizeForCheck(full);
|
|
628
|
+
const canonicalRoot = await realpath(workspaceRoot).catch(() => workspaceRoot);
|
|
629
|
+
if (!isWithinRoot(canonicalRoot, canonical)) throw new Error(`Path escapes the workspace root: ${path} (resolved outside ${canonicalRoot})`);
|
|
630
|
+
return full;
|
|
631
|
+
}
|
|
632
|
+
/**
|
|
633
|
+
* Canonicalize the deepest existing ancestor of `full` to defeat symlink
|
|
634
|
+
* escapes; the non-existent tail (for writes) is appended back verbatim.
|
|
635
|
+
*/
|
|
636
|
+
async function canonicalizeForCheck(full) {
|
|
130
637
|
let existing = full;
|
|
131
638
|
const tail = [];
|
|
132
639
|
while (true) try {
|
|
@@ -141,10 +648,18 @@ function createProcessContext(config) {
|
|
|
141
648
|
tail.unshift(relative(parent, existing));
|
|
142
649
|
existing = parent;
|
|
143
650
|
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
651
|
+
return tail.length ? resolve(existing, ...tail) : existing;
|
|
652
|
+
}
|
|
653
|
+
/**
|
|
654
|
+
* In-process counterpart of the sandbox's write policy: `writeFile` (and
|
|
655
|
+
* so the `write_file` / `edit` tools) may only target `isolation.writableRoots`.
|
|
656
|
+
* Reads are deliberately unrestricted — same boundary the kernel enforces
|
|
657
|
+
* for shell commands, so the two never disagree about where writes land.
|
|
658
|
+
*/
|
|
659
|
+
async function assertWritable(full, path) {
|
|
660
|
+
if (!isolation) return;
|
|
661
|
+
const canonical = await canonicalizeForCheck(full);
|
|
662
|
+
if (!isolation.writableRoots.some((root) => isWithinRoot(root, canonical))) throw new Error(`[sandbox] write denied: ${path} is outside the writable roots (${isolation.writableRoots.join(", ")}). Ask the user to add it under Settings → "Sandbox writable paths" or turn off "Sandbox shell commands".`);
|
|
148
663
|
}
|
|
149
664
|
/**
|
|
150
665
|
* Per-context background-task registry. Entries live for the context's
|
|
@@ -224,6 +739,7 @@ function createProcessContext(config) {
|
|
|
224
739
|
network: true,
|
|
225
740
|
gpu: false,
|
|
226
741
|
stream: true,
|
|
742
|
+
isolated: isolation !== void 0 && isolationState?.ok === true,
|
|
227
743
|
detachedTasks: "process-lifetime"
|
|
228
744
|
},
|
|
229
745
|
async spawn(overrides) {
|
|
@@ -251,11 +767,14 @@ function createProcessContext(config) {
|
|
|
251
767
|
stderr: "aborted by signal before spawn",
|
|
252
768
|
exitCode: 143
|
|
253
769
|
};
|
|
770
|
+
const blocked = isolationBlocker();
|
|
771
|
+
if (blocked) return blocked;
|
|
254
772
|
const timeoutMs = (options?.timeout ?? config?.limits?.timeout ?? 30) * 1e3;
|
|
255
773
|
const maxBuffer = DEFAULT_MAX_OUTPUT_BUFFER;
|
|
256
774
|
const spawnChild = await loadSpawn();
|
|
257
775
|
return new Promise((resolveP) => {
|
|
258
|
-
const
|
|
776
|
+
const shell = shellCommand(command);
|
|
777
|
+
const child = spawnChild(shell.file, shell.args, {
|
|
259
778
|
cwd,
|
|
260
779
|
env: {
|
|
261
780
|
...baseEnv,
|
|
@@ -313,11 +832,12 @@ function createProcessContext(config) {
|
|
|
313
832
|
if (exitGraceTimer) clearTimeout(exitGraceTimer);
|
|
314
833
|
if (userSignal) userSignal.removeEventListener("abort", onAbort);
|
|
315
834
|
const finalStderr = extraStderr ? stderrSlot.text ? `${stderrSlot.text}\n${extraStderr}` : extraStderr : stderrSlot.text;
|
|
316
|
-
|
|
835
|
+
const result = {
|
|
317
836
|
stdout: stdoutSlot.text,
|
|
318
837
|
stderr: finalStderr,
|
|
319
838
|
exitCode
|
|
320
|
-
}
|
|
839
|
+
};
|
|
840
|
+
resolveP(isolation ? annotateDenial(result, isolation) : result);
|
|
321
841
|
};
|
|
322
842
|
const settleFromStatus = (code, signal) => {
|
|
323
843
|
if (killedByAbort) {
|
|
@@ -370,6 +890,7 @@ function createProcessContext(config) {
|
|
|
370
890
|
},
|
|
371
891
|
async writeFile(handle, path, content, encoding = "utf-8") {
|
|
372
892
|
const fullPath = await resolveContained(handle, path);
|
|
893
|
+
await assertWritable(fullPath, path);
|
|
373
894
|
await mkdir(dirname(fullPath), { recursive: true });
|
|
374
895
|
if (typeof content === "string") await writeFile(fullPath, content, encoding);
|
|
375
896
|
else await writeFile(fullPath, content);
|
|
@@ -414,7 +935,10 @@ function createProcessContext(config) {
|
|
|
414
935
|
const cwd = options?.cwd ? resolve(handle.cwd, options.cwd) : handle.cwd;
|
|
415
936
|
const spawnChild = await loadSpawn();
|
|
416
937
|
options?.signal?.throwIfAborted();
|
|
417
|
-
const
|
|
938
|
+
const blocked = isolationBlocker();
|
|
939
|
+
if (blocked) throw new Error(blocked.stderr);
|
|
940
|
+
const shell = shellCommand(command);
|
|
941
|
+
const child = spawnChild(shell.file, shell.args, {
|
|
418
942
|
cwd,
|
|
419
943
|
env: {
|
|
420
944
|
...baseEnv,
|
|
@@ -477,6 +1001,8 @@ function createProcessContext(config) {
|
|
|
477
1001
|
async execBackground(handle, command, options) {
|
|
478
1002
|
const cwd = options.cwd ? resolve(handle.cwd, options.cwd) : handle.cwd;
|
|
479
1003
|
const spawnChild = await loadSpawn();
|
|
1004
|
+
const blocked = isolationBlocker();
|
|
1005
|
+
if (blocked) throw new Error(blocked.stderr);
|
|
480
1006
|
await mkdir(options.outputDir, { recursive: true });
|
|
481
1007
|
const taskId = `bash_${++taskCounter}`;
|
|
482
1008
|
assertSafeTaskId(taskId);
|
|
@@ -486,7 +1012,8 @@ function createProcessContext(config) {
|
|
|
486
1012
|
outputStream.on("error", (err) => {
|
|
487
1013
|
if (process.env.ZIDANE_DEBUG) process.stderr.write(`[zidane/contexts] task ${taskId} log stream error: ${err.message}\n`);
|
|
488
1014
|
});
|
|
489
|
-
const
|
|
1015
|
+
const shell = shellCommand(command);
|
|
1016
|
+
const child = spawnChild(shell.file, shell.args, {
|
|
490
1017
|
cwd,
|
|
491
1018
|
env: {
|
|
492
1019
|
...baseEnv,
|
|
@@ -785,6 +1312,6 @@ function resolveDetachedTasksCapability(context) {
|
|
|
785
1312
|
return context.capabilities.detachedTasks ?? (context.execBackground ? "process-lifetime" : "none");
|
|
786
1313
|
}
|
|
787
1314
|
//#endregion
|
|
788
|
-
export { killProcessGroup as i, SUPPORTS_PROCESS_GROUPS as n, createProcessContext as r, resolveDetachedTasksCapability as t };
|
|
1315
|
+
export { DEFAULT_UNREADABLE_DIRS as a, resolveUnreadableDirs as c, killProcessGroup as i, resolveWritableRoots as l, SUPPORTS_PROCESS_GROUPS as n, isolationAvailability as o, createProcessContext as r, parseAllowWriteSetting as s, resolveDetachedTasksCapability as t, resolveWritableRootsAsync as u };
|
|
789
1316
|
|
|
790
|
-
//# sourceMappingURL=contexts-
|
|
1317
|
+
//# sourceMappingURL=contexts-CRE9pw07.js.map
|