@zelari/core 2.15.0 → 2.16.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.
- package/dist/core/AgentHarness.d.ts +17 -3
- package/dist/core/AgentHarness.d.ts.map +1 -1
- package/dist/core/AgentHarness.js +9 -2
- package/dist/core/AgentHarness.js.map +1 -1
- package/dist/core/hooks/lifecycleHookRunner.d.ts +55 -9
- package/dist/core/hooks/lifecycleHookRunner.d.ts.map +1 -1
- package/dist/core/hooks/lifecycleHookRunner.js +114 -18
- package/dist/core/hooks/lifecycleHookRunner.js.map +1 -1
- package/dist/core/tools/builtin/shell.d.ts +45 -0
- package/dist/core/tools/builtin/shell.d.ts.map +1 -1
- package/dist/core/tools/builtin/shell.js +118 -92
- package/dist/core/tools/builtin/shell.js.map +1 -1
- package/dist/core/tools/registry.d.ts +5 -1
- package/dist/core/tools/registry.d.ts.map +1 -1
- package/dist/core/tools/registry.js +15 -3
- package/dist/core/tools/registry.js.map +1 -1
- package/dist/harness/appServer.d.ts +51 -0
- package/dist/harness/appServer.d.ts.map +1 -0
- package/dist/harness/appServer.js +128 -0
- package/dist/harness/appServer.js.map +1 -0
- package/dist/harness/appServerTypes.d.ts +61 -0
- package/dist/harness/appServerTypes.d.ts.map +1 -0
- package/dist/harness/appServerTypes.js +10 -0
- package/dist/harness/appServerTypes.js.map +1 -0
- package/dist/harness/extensionApi.d.ts +65 -0
- package/dist/harness/extensionApi.d.ts.map +1 -0
- package/dist/harness/extensionApi.js +125 -0
- package/dist/harness/extensionApi.js.map +1 -0
- package/dist/harness/extensionApiTypes.d.ts +115 -0
- package/dist/harness/extensionApiTypes.d.ts.map +1 -0
- package/dist/harness/extensionApiTypes.js +24 -0
- package/dist/harness/extensionApiTypes.js.map +1 -0
- package/dist/harness/index.d.ts +4 -0
- package/dist/harness/index.d.ts.map +1 -1
- package/dist/harness/index.js +8 -0
- package/dist/harness/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,10 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* LifecycleHookRunner — executes PreToolUse / PostToolUse / SessionStart /
|
|
3
|
-
* SessionEnd hooks as external commands (or HTTP POSTs)
|
|
3
|
+
* SessionEnd hooks as external commands (or HTTP POSTs).
|
|
4
4
|
*
|
|
5
5
|
* Safety model (v1.32.0):
|
|
6
6
|
* - A hook that crashes, times out, exits non-zero, or returns invalid JSON
|
|
7
|
-
* is logged and treated as ALLOW
|
|
7
|
+
* is logged and treated as ALLOW (default `failureMode: 'fail-open'`).
|
|
8
|
+
* v2.16 (HARNESS-10 t22): `failureMode: 'fail-closed'` — used by the CLI
|
|
9
|
+
* for strict headless/mission/CI surfaces — treats every such unreliable
|
|
10
|
+
* outcome as an explicit DENY with reason `hook-failed` instead (same
|
|
11
|
+
* deny shape as a hook's own decision). The mode applies to PreToolUse
|
|
12
|
+
* AND Session hooks; the CLI layer decides it (see
|
|
13
|
+
* src/cli/safety/lifecycleHooks.ts `resolveHookFailureMode`).
|
|
14
|
+
* - v2.17 (t27): hook commands spawn as an EXPLICIT argv with `shell: false`
|
|
15
|
+
* on every OS (see splitHookCommandLine) — shell metacharacters in a hook
|
|
16
|
+
* `command` are literal arguments, never re-interpreted by a shell.
|
|
8
17
|
* - The ONLY way to block a tool is an explicit JSON decision
|
|
9
18
|
* `{ "decision": "deny", "reason": "..." }` on stdout / response body.
|
|
10
19
|
* - Tool matching is Claude-code style: `Bash` and `bash` both match the
|
|
@@ -32,16 +41,82 @@ function parseJson(text) {
|
|
|
32
41
|
}
|
|
33
42
|
}
|
|
34
43
|
/**
|
|
35
|
-
*
|
|
36
|
-
*
|
|
44
|
+
* v2.17 (t27): conservative command line → argv split for hook commands.
|
|
45
|
+
*
|
|
46
|
+
* Splits on whitespace; honors single/double quotes and `\"` `\'` `\\`
|
|
47
|
+
* escapes. A backslash escapes ONLY quote/backslash characters (never an
|
|
48
|
+
* arbitrary next char) so Windows paths like `C:\tools\hook.mjs` survive
|
|
49
|
+
* unquoted. There are NO shell semantics: metacharacters (`;`, `&&`, `|`,
|
|
50
|
+
* `$VAR`, `>`) are never special — they become literal argv tokens. Paired
|
|
51
|
+
* with `shell: false` in {@link LifecycleHookRunner.execCommand} the OS
|
|
52
|
+
* executes exactly `[program, ...args]`: `echo a; rm -rf /` is the program
|
|
53
|
+
* `echo` with the literal argument `a;` — the `rm` NEVER runs. Unclosed
|
|
54
|
+
* quotes are tolerated (the partial token is kept, the hook then fails and
|
|
55
|
+
* the failure mode decides the outcome). Env-prefix syntax (`FOO=1 node x`)
|
|
56
|
+
* is NOT shell-magic here: `FOO=1` would be the program name and fail —
|
|
57
|
+
* move environment into the hook script. Windows `.cmd`/`.bat` shims
|
|
58
|
+
* (`npm`, `npx`) need the full path, same limitation as exec_process.
|
|
59
|
+
*/
|
|
60
|
+
export function splitHookCommandLine(line) {
|
|
61
|
+
const out = [];
|
|
62
|
+
let cur = '';
|
|
63
|
+
let hasToken = false;
|
|
64
|
+
let quote = null;
|
|
65
|
+
for (let i = 0; i < line.length; i += 1) {
|
|
66
|
+
const ch = line[i];
|
|
67
|
+
if (quote) {
|
|
68
|
+
if (ch === quote) {
|
|
69
|
+
quote = null;
|
|
70
|
+
}
|
|
71
|
+
else if (quote === '"' && ch === '\\' && (line[i + 1] === '"' || line[i + 1] === '\\')) {
|
|
72
|
+
cur += line[i + 1];
|
|
73
|
+
i += 1;
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
cur += ch;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
else if (ch === '"' || ch === "'") {
|
|
80
|
+
quote = ch;
|
|
81
|
+
hasToken = true;
|
|
82
|
+
}
|
|
83
|
+
else if (ch === '\\' && (line[i + 1] === '"' || line[i + 1] === "'" || line[i + 1] === '\\')) {
|
|
84
|
+
cur += line[i + 1];
|
|
85
|
+
hasToken = true;
|
|
86
|
+
i += 1;
|
|
87
|
+
}
|
|
88
|
+
else if (/\s/.test(ch)) {
|
|
89
|
+
if (hasToken) {
|
|
90
|
+
out.push(cur);
|
|
91
|
+
cur = '';
|
|
92
|
+
hasToken = false;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
cur += ch;
|
|
97
|
+
hasToken = true;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (hasToken || cur.length > 0)
|
|
101
|
+
out.push(cur);
|
|
102
|
+
return out;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Execute hooks for lifecycle events. NEVER throws: an unreliable hook
|
|
106
|
+
* (crash / timeout / invalid JSON / deny without reason) becomes an explicit
|
|
107
|
+
* allow (fail-open, default) or an explicit deny 'hook-failed' (fail-closed,
|
|
108
|
+
* t22), with a logged warning either way.
|
|
37
109
|
*/
|
|
38
110
|
export class LifecycleHookRunner {
|
|
39
111
|
hooks = [];
|
|
40
112
|
logger;
|
|
41
113
|
defaultTimeoutMs;
|
|
114
|
+
/** v2.16 (t22): resolved failure mode. Default 'fail-open'. */
|
|
115
|
+
failureMode;
|
|
42
116
|
constructor(options = {}) {
|
|
43
117
|
this.logger = options.logger ?? ((msg) => console.error(`[hooks] ${msg}`));
|
|
44
118
|
this.defaultTimeoutMs = options.defaultTimeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
119
|
+
this.failureMode = options.failureMode ?? 'fail-open';
|
|
45
120
|
for (const dir of options.dirs ?? []) {
|
|
46
121
|
this.loadDir(dir);
|
|
47
122
|
}
|
|
@@ -84,8 +159,9 @@ export class LifecycleHookRunner {
|
|
|
84
159
|
}
|
|
85
160
|
/**
|
|
86
161
|
* Run matching PreToolUse hooks. Returns `{ ok: false }` ONLY when a hook
|
|
87
|
-
* explicitly denies
|
|
88
|
-
*
|
|
162
|
+
* explicitly denies — or, in fail-closed mode (t22), when the hook runner
|
|
163
|
+
* could not produce a verdict at all. Fail-open: no match, crash, timeout,
|
|
164
|
+
* invalid JSON and allow decisions all return `{ ok: true }`.
|
|
89
165
|
*/
|
|
90
166
|
async runPreToolUse(toolName, toolInput, ctx) {
|
|
91
167
|
for (const hook of this.hooks) {
|
|
@@ -127,11 +203,11 @@ export class LifecycleHookRunner {
|
|
|
127
203
|
await this.runHookSafely(hook, payload);
|
|
128
204
|
}
|
|
129
205
|
}
|
|
130
|
-
/** Run matching SessionStart hooks.
|
|
206
|
+
/** Run matching SessionStart hooks. Failure semantics per failureMode (t22). */
|
|
131
207
|
async runSessionStart(ctx) {
|
|
132
208
|
return this.runSessionHooks('SessionStart', ctx);
|
|
133
209
|
}
|
|
134
|
-
/** Run matching SessionEnd hooks.
|
|
210
|
+
/** Run matching SessionEnd hooks. Failure semantics per failureMode (t22). */
|
|
135
211
|
async runSessionEnd(ctx) {
|
|
136
212
|
return this.runSessionHooks('SessionEnd', ctx);
|
|
137
213
|
}
|
|
@@ -155,7 +231,7 @@ export class LifecycleHookRunner {
|
|
|
155
231
|
}
|
|
156
232
|
return { ok: true };
|
|
157
233
|
}
|
|
158
|
-
/** Execute a single hook
|
|
234
|
+
/** Execute a single hook; the failure mode decides allow vs deny 'hook-failed'. */
|
|
159
235
|
async runHookSafely(hook, payload) {
|
|
160
236
|
try {
|
|
161
237
|
const timeoutMs = hook.timeoutMs ?? this.defaultTimeoutMs;
|
|
@@ -164,26 +240,46 @@ export class LifecycleHookRunner {
|
|
|
164
240
|
: await this.execCommand(hook.command ?? '', payload, timeoutMs, hook.cwd);
|
|
165
241
|
const decision = parseJson(raw);
|
|
166
242
|
if (!decision) {
|
|
167
|
-
this.logger(`hook "${hook.name}" returned invalid JSON (
|
|
168
|
-
return
|
|
243
|
+
this.logger(`hook "${hook.name}" returned invalid JSON (${this.failureMode}): ${raw.slice(0, 200)}`);
|
|
244
|
+
return this.failureDecision();
|
|
169
245
|
}
|
|
170
246
|
if (decision.decision === 'deny' && typeof decision.reason !== 'string') {
|
|
171
|
-
this.logger(`hook "${hook.name}" denied without reason (
|
|
172
|
-
return
|
|
247
|
+
this.logger(`hook "${hook.name}" denied without reason (${this.failureMode})`);
|
|
248
|
+
return this.failureDecision();
|
|
173
249
|
}
|
|
174
250
|
return decision;
|
|
175
251
|
}
|
|
176
252
|
catch (err) {
|
|
177
|
-
this.logger(`hook "${hook.name}" failed (
|
|
178
|
-
return
|
|
253
|
+
this.logger(`hook "${hook.name}" failed (${this.failureMode}): ${err instanceof Error ? err.message : String(err)}`);
|
|
254
|
+
return this.failureDecision();
|
|
179
255
|
}
|
|
180
256
|
}
|
|
257
|
+
/**
|
|
258
|
+
* v2.16 (t22): resolve a hook that produced no usable verdict. Fail-open
|
|
259
|
+
* (default) allows; fail-closed maps the failure to the same shape as an
|
|
260
|
+
* explicit deny so PreToolUse/Session hook consumers block the call.
|
|
261
|
+
*/
|
|
262
|
+
failureDecision() {
|
|
263
|
+
return this.failureMode === 'fail-closed'
|
|
264
|
+
? { decision: 'deny', reason: 'hook-failed' }
|
|
265
|
+
: { decision: 'allow' };
|
|
266
|
+
}
|
|
181
267
|
/** Spawn `command`, write JSON payload to stdin, read stdout until close. */
|
|
182
268
|
execCommand(command, payload, timeoutMs, cwd) {
|
|
183
269
|
return new Promise((resolve, reject) => {
|
|
184
|
-
//
|
|
185
|
-
|
|
186
|
-
|
|
270
|
+
// v2.17 (t27): explicit argv + `shell: false` on EVERY OS (previously
|
|
271
|
+
// `spawn(command, { shell: true })`). The command line is parsed by
|
|
272
|
+
// splitHookCommandLine (quotes yes, shell metacharacters no) so a hook
|
|
273
|
+
// command can never be re-interpreted / chained by a shell: the OS
|
|
274
|
+
// runs exactly [program, ...args]. Plain .exe binaries resolve on PATH
|
|
275
|
+
// (`node script.mjs` / `deno run` keep working cross-platform).
|
|
276
|
+
const argv = splitHookCommandLine(command);
|
|
277
|
+
if (argv.length === 0) {
|
|
278
|
+
reject(new Error('empty hook command'));
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
const child = spawn(argv[0], argv.slice(1), {
|
|
282
|
+
shell: false,
|
|
187
283
|
cwd,
|
|
188
284
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
189
285
|
windowsHide: true,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lifecycleHookRunner.js","sourceRoot":"","sources":["../../../src/core/hooks/lifecycleHookRunner.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"lifecycleHookRunner.js","sourceRoot":"","sources":["../../../src/core/hooks/lifecycleHookRunner.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
import { type ChildProcess } from 'node:child_process';
|
|
2
3
|
import { type ToolDefinition } from '../toolTypes.js';
|
|
3
4
|
declare const BashArgsSchema: z.ZodObject<{
|
|
4
5
|
command: z.ZodString;
|
|
@@ -21,7 +22,51 @@ interface BashResult {
|
|
|
21
22
|
* (live test 2026-07-02: 6× `npm create vite` in a non-empty dir).
|
|
22
23
|
*/
|
|
23
24
|
hint?: string;
|
|
25
|
+
/**
|
|
26
|
+
* v2.17 (t28): present ONLY when the CLI OS-jail seam ran this command
|
|
27
|
+
* in visible fail-open advisory mode (backend missing). Model-visible so
|
|
28
|
+
* the advisory fail-open is never silent.
|
|
29
|
+
*/
|
|
30
|
+
jailNotice?: string;
|
|
24
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* v2.17 (t28) — OS-jail seam (Pilastro A).
|
|
34
|
+
*
|
|
35
|
+
* The builtin runs in TWO hosts with a strict dependency direction:
|
|
36
|
+
* - the CLI (src/cli) must route every spawn through the osJail choke-point
|
|
37
|
+
* (`spawnJailed` in src/cli/safety/osJail.ts) — core cannot import CLI
|
|
38
|
+
* modules, so the CLI INJECTS this seam via createBashTool(seam);
|
|
39
|
+
* - the core harness (harnessToolBridge → bashTool) keeps the default
|
|
40
|
+
* direct spawn (documented, out of the CLI jail surface).
|
|
41
|
+
*
|
|
42
|
+
* The seam receives the FINAL program+argv+env (the same shape t27 made
|
|
43
|
+
* explicit, shell:false everywhere) and returns either a spawned child —
|
|
44
|
+
* optionally with an advisory `notice` — or a typed deny/failed reason that
|
|
45
|
+
* becomes a `[jail]`-prefixed tool error. Never throws.
|
|
46
|
+
*/
|
|
47
|
+
export type BashSpawnSeam = (req: {
|
|
48
|
+
program: string;
|
|
49
|
+
argv: string[];
|
|
50
|
+
cwd: string;
|
|
51
|
+
env: NodeJS.ProcessEnv;
|
|
52
|
+
signal?: AbortSignal;
|
|
53
|
+
}) => {
|
|
54
|
+
outcome: 'spawned';
|
|
55
|
+
child: ChildProcess;
|
|
56
|
+
notice?: string;
|
|
57
|
+
} | {
|
|
58
|
+
outcome: 'denied';
|
|
59
|
+
reason: string;
|
|
60
|
+
} | {
|
|
61
|
+
outcome: 'failed';
|
|
62
|
+
reason: string;
|
|
63
|
+
};
|
|
64
|
+
export declare function createBashTool(spawnSeam?: BashSpawnSeam): ToolDefinition<BashArgs, BashResult>;
|
|
65
|
+
/**
|
|
66
|
+
* Default builtin (core harness host): direct spawn, NO jail seam. The CLI
|
|
67
|
+
* registry builds its own instance via createBashTool(spawnJailedSeam) —
|
|
68
|
+
* see src/cli/toolRegistry.ts (v2.17 t28).
|
|
69
|
+
*/
|
|
25
70
|
export declare const bashTool: ToolDefinition<BashArgs, BashResult>;
|
|
26
71
|
export {};
|
|
27
72
|
//# sourceMappingURL=shell.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shell.d.ts","sourceRoot":"","sources":["../../../../src/core/tools/builtin/shell.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"shell.d.ts","sourceRoot":"","sources":["../../../../src/core/tools/builtin/shell.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAS,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAE9D,OAAO,EAAqB,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAyBzE,QAAA,MAAM,cAAc;;;;iBAIlB,CAAC;AAEH,KAAK,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAE/C,UAAU,UAAU;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,oGAAoG;IACpG,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAYD;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,GAAG,EAAE;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,KACG;IAAE,OAAO,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,YAAY,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAC5D;IAAE,OAAO,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACrC;IAAE,OAAO,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1C,wBAAgB,cAAc,CAAC,SAAS,CAAC,EAAE,aAAa,GAAG,cAAc,CAAC,QAAQ,EAAE,UAAU,CAAC,CAsH9F;AAED;;;;GAIG;AACH,eAAO,MAAM,QAAQ,EAAE,cAAc,CAAC,QAAQ,EAAE,UAAU,CAAoB,CAAC"}
|
|
@@ -38,100 +38,126 @@ const INTERACTIVE_HINT = 'This command tried to PROMPT for input, but stdin is c
|
|
|
38
38
|
'scaffold into a fresh EMPTY subdirectory (e.g. `npm create vite@latest scaffold-tmp -- --template react-ts`, ' +
|
|
39
39
|
'then move its contents here with `mv`/`cp`), or write package.json, configs and sources directly ' +
|
|
40
40
|
'with write_file and then run `npm install`.';
|
|
41
|
-
export
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
'
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
if (resolved.isBash) {
|
|
72
|
-
child = spawn(resolved.shell, ['-c', args.command], {
|
|
73
|
-
cwd,
|
|
74
|
-
signal: ctx.signal,
|
|
75
|
-
shell: false,
|
|
76
|
-
env,
|
|
77
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
41
|
+
export function createBashTool(spawnSeam) {
|
|
42
|
+
return {
|
|
43
|
+
name: 'bash',
|
|
44
|
+
description: 'Run a shell command. On Windows uses Git Bash when available (POSIX semantics: ls, $VAR, && work); falls back to cmd.exe otherwise. Streams stdout/stderr. Respects timeout and cancellation. Returns exit code. ' +
|
|
45
|
+
'stdin is CLOSED (non-interactive): any command that prompts for input will fail or be cancelled — always pass non-interactive flags (--yes, -y, --template), and if a scaffolder insists on prompting (e.g. create-vite in a non-empty directory), create the files manually with write_file instead.',
|
|
46
|
+
permissions: ['execute'],
|
|
47
|
+
sideEffect: 'local',
|
|
48
|
+
timeoutMs: 60000,
|
|
49
|
+
inputSchema: BashArgsSchema,
|
|
50
|
+
execute: async (args, ctx) => {
|
|
51
|
+
return new Promise((resolve) => {
|
|
52
|
+
const start = Date.now();
|
|
53
|
+
const cwd = args.cwd ?? ctx.cwd;
|
|
54
|
+
const resolved = resolveShell();
|
|
55
|
+
// win32 + real bash: spawn the binary directly with `-c` and shell:false
|
|
56
|
+
// so there is no cmd.exe indirection (npm, &&, $VAR, ls all work because
|
|
57
|
+
// Git Bash's PATH resolves shims and `-c` runs a true POSIX string).
|
|
58
|
+
// v2.17 (t27): the fallback branch ALSO spawns the shell binary as an
|
|
59
|
+
// explicit program+argv (`/bin/sh -c` on POSIX, `cmd.exe /d /s /c` on
|
|
60
|
+
// the win32 fallback) — the exact spawn shape of the NodeShellProvider
|
|
61
|
+
// seam (ADR-0022). `shell: true` is gone from every branch: the OS
|
|
62
|
+
// process tree is always [shell, flag, command], never a hidden
|
|
63
|
+
// shell-parsing indirection (DEP0190, Pilastro A prerequisite).
|
|
64
|
+
// v0.7.3: CI=1 pushes well-behaved CLIs (npm, scaffolders, test runners)
|
|
65
|
+
// into non-interactive mode; stdin 'ignore' makes the rest fail FAST
|
|
66
|
+
// with EOF instead of hanging on a prompt until the timeout (live test:
|
|
67
|
+
// `npm create vite` in a non-empty dir prompted → "Operation cancelled").
|
|
68
|
+
const baseEnv = withNodeDirOnPath({
|
|
69
|
+
...process.env,
|
|
70
|
+
CI: process.env.CI ?? '1',
|
|
78
71
|
});
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
72
|
+
const env = resolved.isBash
|
|
73
|
+
? { ...baseEnv, MSYSTEM: process.env.MSYSTEM ?? 'MINGW64' }
|
|
74
|
+
: baseEnv;
|
|
75
|
+
let program;
|
|
76
|
+
let argv;
|
|
77
|
+
if (resolved.isBash) {
|
|
78
|
+
program = resolved.shell;
|
|
79
|
+
argv = ['-c', args.command];
|
|
80
|
+
}
|
|
81
|
+
else if (resolved.isPowerShell) {
|
|
82
|
+
// PowerShell: use `-Command` (works on PS5.1 and PS7+).
|
|
83
|
+
// Do NOT set MSYSTEM — it's not a bash/MSYS2 environment.
|
|
84
|
+
program = resolved.shell;
|
|
85
|
+
argv = ['-Command', args.command];
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
// Fallback (POSIX / win32 without bash or PowerShell): spawn the shell
|
|
89
|
+
// Node's `shell: true` would have picked — /bin/sh on POSIX, cmd.exe
|
|
90
|
+
// (ComSpec semantics: /d skips AutoRun, /s fixes /c quoting) on win32 —
|
|
91
|
+
// but as an explicit argv with shell:false (v2.17 t27).
|
|
92
|
+
const isWin = process.platform === 'win32';
|
|
93
|
+
program = isWin ? 'cmd.exe' : '/bin/sh';
|
|
94
|
+
argv = isWin ? ['/d', '/s', '/c', args.command] : ['-c', args.command];
|
|
95
|
+
}
|
|
96
|
+
// v2.17 (t28): the CLI-injected seam (osJail.spawnJailed) is the ONLY
|
|
97
|
+
// route for CLI spawns; the default stays the direct t27 spawn.
|
|
98
|
+
let child;
|
|
99
|
+
let jailNotice;
|
|
100
|
+
if (spawnSeam) {
|
|
101
|
+
const seamResult = spawnSeam({ program, argv, cwd, env, signal: ctx.signal });
|
|
102
|
+
if (seamResult.outcome !== 'spawned') {
|
|
103
|
+
resolve(typedErr(seamResult.reason));
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
child = seamResult.child;
|
|
107
|
+
jailNotice = seamResult.notice;
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
child = spawn(program, argv, {
|
|
111
|
+
cwd,
|
|
112
|
+
signal: ctx.signal,
|
|
113
|
+
shell: false,
|
|
114
|
+
env,
|
|
115
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
let stdout = '';
|
|
119
|
+
let stderr = '';
|
|
120
|
+
const maxBuffer = 1024 * 1024; // 1MB cap on each stream
|
|
121
|
+
child.stdout?.on('data', (data) => {
|
|
122
|
+
if (stdout.length < maxBuffer)
|
|
123
|
+
stdout += data.toString('utf-8');
|
|
89
124
|
});
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
125
|
+
child.stderr?.on('data', (data) => {
|
|
126
|
+
if (stderr.length < maxBuffer)
|
|
127
|
+
stderr += data.toString('utf-8');
|
|
128
|
+
});
|
|
129
|
+
const timer = setTimeout(() => {
|
|
130
|
+
child.kill('SIGTERM');
|
|
131
|
+
resolve(typedErr(`Bash command timed out after ${args.timeoutMs}ms. ` +
|
|
132
|
+
'If it was waiting for interactive input: stdin is closed — pass non-interactive flags or create the files directly instead of retrying.'));
|
|
133
|
+
}, args.timeoutMs);
|
|
134
|
+
child.on('close', (code) => {
|
|
135
|
+
clearTimeout(timer);
|
|
136
|
+
const cappedStdout = stdout.slice(0, maxBuffer);
|
|
137
|
+
const cappedStderr = stderr.slice(0, maxBuffer);
|
|
138
|
+
const interactive = INTERACTIVE_CANCEL_RE.test(cappedStdout) || INTERACTIVE_CANCEL_RE.test(cappedStderr);
|
|
139
|
+
resolve(typedOk({
|
|
140
|
+
stdout: cappedStdout,
|
|
141
|
+
stderr: cappedStderr,
|
|
142
|
+
exitCode: code ?? -1,
|
|
143
|
+
durationMs: Date.now() - start,
|
|
144
|
+
shellVia: resolved.via,
|
|
145
|
+
...(jailNotice ? { jailNotice } : {}),
|
|
146
|
+
...(interactive ? { hint: INTERACTIVE_HINT } : {}),
|
|
147
|
+
}));
|
|
148
|
+
});
|
|
149
|
+
child.on('error', (err) => {
|
|
150
|
+
clearTimeout(timer);
|
|
151
|
+
resolve(typedErr(err.message));
|
|
98
152
|
});
|
|
99
|
-
}
|
|
100
|
-
let stdout = '';
|
|
101
|
-
let stderr = '';
|
|
102
|
-
const maxBuffer = 1024 * 1024; // 1MB cap on each stream
|
|
103
|
-
child.stdout?.on('data', (data) => {
|
|
104
|
-
if (stdout.length < maxBuffer)
|
|
105
|
-
stdout += data.toString('utf-8');
|
|
106
|
-
});
|
|
107
|
-
child.stderr?.on('data', (data) => {
|
|
108
|
-
if (stderr.length < maxBuffer)
|
|
109
|
-
stderr += data.toString('utf-8');
|
|
110
|
-
});
|
|
111
|
-
const timer = setTimeout(() => {
|
|
112
|
-
child.kill('SIGTERM');
|
|
113
|
-
resolve(typedErr(`Bash command timed out after ${args.timeoutMs}ms. ` +
|
|
114
|
-
'If it was waiting for interactive input: stdin is closed — pass non-interactive flags or create the files directly instead of retrying.'));
|
|
115
|
-
}, args.timeoutMs);
|
|
116
|
-
child.on('close', (code) => {
|
|
117
|
-
clearTimeout(timer);
|
|
118
|
-
const cappedStdout = stdout.slice(0, maxBuffer);
|
|
119
|
-
const cappedStderr = stderr.slice(0, maxBuffer);
|
|
120
|
-
const interactive = INTERACTIVE_CANCEL_RE.test(cappedStdout) || INTERACTIVE_CANCEL_RE.test(cappedStderr);
|
|
121
|
-
resolve(typedOk({
|
|
122
|
-
stdout: cappedStdout,
|
|
123
|
-
stderr: cappedStderr,
|
|
124
|
-
exitCode: code ?? -1,
|
|
125
|
-
durationMs: Date.now() - start,
|
|
126
|
-
shellVia: resolved.via,
|
|
127
|
-
...(interactive ? { hint: INTERACTIVE_HINT } : {}),
|
|
128
|
-
}));
|
|
129
|
-
});
|
|
130
|
-
child.on('error', (err) => {
|
|
131
|
-
clearTimeout(timer);
|
|
132
|
-
resolve(typedErr(err.message));
|
|
133
153
|
});
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Default builtin (core harness host): direct spawn, NO jail seam. The CLI
|
|
159
|
+
* registry builds its own instance via createBashTool(spawnJailedSeam) —
|
|
160
|
+
* see src/cli/toolRegistry.ts (v2.17 t28).
|
|
161
|
+
*/
|
|
162
|
+
export const bashTool = createBashTool();
|
|
137
163
|
//# sourceMappingURL=shell.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shell.js","sourceRoot":"","sources":["../../../../src/core/tools/builtin/shell.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,KAAK,
|
|
1
|
+
{"version":3,"file":"shell.js","sourceRoot":"","sources":["../../../../src/core/tools/builtin/shell.ts"],"names":[],"mappings":"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"}
|
|
@@ -46,7 +46,11 @@ export declare class ToolRegistry {
|
|
|
46
46
|
private openAIToolsCache;
|
|
47
47
|
register<I, O>(def: ToolDefinition<I, O>): void;
|
|
48
48
|
get(name: string): ToolDefinition | undefined;
|
|
49
|
-
/**
|
|
49
|
+
/**
|
|
50
|
+
* v0.10.0: attach the lifecycle hook runner (null to disable).
|
|
51
|
+
* v2.16 (t22): the runner's failureMode decides what a THROWING runner
|
|
52
|
+
* means — fail-closed denies the call, fail-open (default) allows it.
|
|
53
|
+
*/
|
|
50
54
|
setLifecycleHooks(runner: LifecycleHookRunner | null): void;
|
|
51
55
|
getLifecycleHooks(): LifecycleHookRunner | null;
|
|
52
56
|
list(): string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/core/tools/registry.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAE7D,OAAO,EAAY,KAAK,cAAc,EAAoB,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAC;AACnG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAErE,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAEjG,MAAM,WAAW,aAAa;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,yBAAyB;IACxC,yDAAyD;IACzD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,wEAAwE;IACxE,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,uCAAuC;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AA0DD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,SAAS,GAAE,MAAM,GAAG,yBAAgD,GACnE,MAAM,CA0DR;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,KAAK,CAAqC;IAClD,0EAA0E;IAC1E,OAAO,CAAC,cAAc,CAAoC;IAC1D;;;;;OAKG;IACH,OAAO,CAAC,gBAAgB,CAAkI;IAE1J,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI;IAK/C,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAI7C
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/core/tools/registry.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAE7D,OAAO,EAAY,KAAK,cAAc,EAAoB,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAC;AACnG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAErE,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAEjG,MAAM,WAAW,aAAa;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,yBAAyB;IACxC,yDAAyD;IACzD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,wEAAwE;IACxE,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,uCAAuC;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AA0DD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,SAAS,GAAE,MAAM,GAAG,yBAAgD,GACnE,MAAM,CA0DR;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,KAAK,CAAqC;IAClD,0EAA0E;IAC1E,OAAO,CAAC,cAAc,CAAoC;IAC1D;;;;;OAKG;IACH,OAAO,CAAC,gBAAgB,CAAkI;IAE1J,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI;IAK/C,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAI7C;;;;OAIG;IACH,iBAAiB,CAAC,MAAM,EAAE,mBAAmB,GAAG,IAAI,GAAG,IAAI;IAI3D,iBAAiB,IAAI,mBAAmB,GAAG,IAAI;IAI/C,IAAI,IAAI,MAAM,EAAE;IAIhB;;;OAGG;IACH,OAAO,CAAC,UAAU;IAMlB,gFAAgF;IAC1E,MAAM,CAAC,CAAC,EACZ,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,OAAO,EACjB,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IA8H1B,gFAAgF;IAChF,aAAa,IAAI,KAAK,CAAC;QAAE,IAAI,EAAE,UAAU,CAAC;QAAC,QAAQ,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,WAAW,EAAE,MAAM,CAAC;YAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;SAAE,CAAA;KAAE,CAAC;IAalI,oGAAoG;IACpG,YAAY,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,eAAe,EAAE;CAa3D;AAID,wBAAgB,eAAe,IAAI,YAAY,CAG9C"}
|
|
@@ -141,7 +141,11 @@ export class ToolRegistry {
|
|
|
141
141
|
get(name) {
|
|
142
142
|
return this.tools.get(name);
|
|
143
143
|
}
|
|
144
|
-
/**
|
|
144
|
+
/**
|
|
145
|
+
* v0.10.0: attach the lifecycle hook runner (null to disable).
|
|
146
|
+
* v2.16 (t22): the runner's failureMode decides what a THROWING runner
|
|
147
|
+
* means — fail-closed denies the call, fail-open (default) allows it.
|
|
148
|
+
*/
|
|
145
149
|
setLifecycleHooks(runner) {
|
|
146
150
|
this.lifecycleHooks = runner;
|
|
147
151
|
}
|
|
@@ -200,7 +204,10 @@ export class ToolRegistry {
|
|
|
200
204
|
audit: () => { },
|
|
201
205
|
sessionId: options.sessionId ?? 'default',
|
|
202
206
|
};
|
|
203
|
-
// v0.10.0: PreToolUse lifecycle hooks —
|
|
207
|
+
// v0.10.0: PreToolUse lifecycle hooks — deny blocks the tool.
|
|
208
|
+
// v2.16 (t22): a THROWING runner follows the runner's failureMode:
|
|
209
|
+
// fail-closed ⇒ typedErr deny before execute; fail-open (default) ⇒ log
|
|
210
|
+
// + allow, exactly as before.
|
|
204
211
|
if (this.lifecycleHooks) {
|
|
205
212
|
try {
|
|
206
213
|
const pre = await this.lifecycleHooks.runPreToolUse(name, parsed.data, {
|
|
@@ -213,7 +220,12 @@ export class ToolRegistry {
|
|
|
213
220
|
}
|
|
214
221
|
}
|
|
215
222
|
catch (hookErr) {
|
|
216
|
-
|
|
223
|
+
if (this.lifecycleHooks.failureMode === 'fail-closed') {
|
|
224
|
+
parentSignal?.removeEventListener('abort', onParentAbort);
|
|
225
|
+
return typedErr('[hook:unknown] hook-failed');
|
|
226
|
+
}
|
|
227
|
+
// Belt-and-suspenders (fail-open): a throwing runner never blocks the tool.
|
|
228
|
+
console.error(`[hooks] PreToolUse runner threw (fail-open): ${hookErr instanceof Error ? hookErr.message : String(hookErr)}`);
|
|
217
229
|
}
|
|
218
230
|
}
|
|
219
231
|
try {
|