@vibe-agent-toolkit/utils 0.1.39-rc.7 → 0.1.39-rc.9
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/path-utils.d.ts +35 -3
- package/dist/path-utils.d.ts.map +1 -1
- package/dist/path-utils.js +63 -3
- package/dist/path-utils.js.map +1 -1
- package/dist/skill-test/spawn-claude.d.ts +17 -9
- package/dist/skill-test/spawn-claude.d.ts.map +1 -1
- package/dist/skill-test/spawn-claude.js +27 -12
- package/dist/skill-test/spawn-claude.js.map +1 -1
- package/package.json +1 -1
package/dist/path-utils.d.ts
CHANGED
|
@@ -175,9 +175,11 @@ export declare function toForwardSlash(p: string): string;
|
|
|
175
175
|
* import { safePath } from '@vibe-agent-toolkit/utils';
|
|
176
176
|
*
|
|
177
177
|
* // Always forward slashes, even on Windows
|
|
178
|
-
* safePath.join('C:\\Users', 'docs', 'file.md')
|
|
179
|
-
* safePath.resolve('/project', './docs')
|
|
180
|
-
* safePath.relative('/project/docs', '/project')
|
|
178
|
+
* safePath.join('C:\\Users', 'docs', 'file.md') // → 'C:/Users/docs/file.md'
|
|
179
|
+
* safePath.resolve('/project', './docs') // → '/project/docs'
|
|
180
|
+
* safePath.relative('/project/docs', '/project') // → '..'
|
|
181
|
+
* safePath.joinUnderRoot('/harness', 'skill-abc') // → '/harness/skill-abc'
|
|
182
|
+
* safePath.joinUnderRoot('/harness', '../escape') // throws Error
|
|
181
183
|
* ```
|
|
182
184
|
*/
|
|
183
185
|
export declare const safePath: {
|
|
@@ -187,6 +189,36 @@ export declare const safePath: {
|
|
|
187
189
|
readonly resolve: (...paths: string[]) => string;
|
|
188
190
|
/** Like `path.relative()` but always returns forward slashes. */
|
|
189
191
|
readonly relative: (from: string, to: string) => string;
|
|
192
|
+
/**
|
|
193
|
+
* Join path segments under a security root, throwing if the result would escape.
|
|
194
|
+
*
|
|
195
|
+
* Resolves `root + segments` and verifies the result is strictly inside `root`
|
|
196
|
+
* (or equal to it). Throws when any segment would cause the result to escape:
|
|
197
|
+
*
|
|
198
|
+
* - A `..` traversal that climbs above root
|
|
199
|
+
* - An absolute POSIX path segment (e.g. `/etc/passwd`)
|
|
200
|
+
* - A Windows drive-letter segment (e.g. `C:\Users\evil`)
|
|
201
|
+
*
|
|
202
|
+
* On success returns a forward-slash-normalized absolute path (consistent with
|
|
203
|
+
* the other `safePath` helpers).
|
|
204
|
+
*
|
|
205
|
+
* **Use this instead of `safePath.join(root, segment)` whenever `segment` may
|
|
206
|
+
* contain caller-controlled input** — this is the bug class that the original
|
|
207
|
+
* skill-test staging code was vulnerable to on Windows.
|
|
208
|
+
*
|
|
209
|
+
* @returns Forward-slash absolute path guaranteed to be inside `root`.
|
|
210
|
+
* @throws {Error} If the resolved path would escape `root`.
|
|
211
|
+
*
|
|
212
|
+
* @example
|
|
213
|
+
* ```typescript
|
|
214
|
+
* // ✅ Safe — throws if caller passes '../../../etc'
|
|
215
|
+
* const dest = safePath.joinUnderRoot(harnessRoot, stagedDirName(item.name));
|
|
216
|
+
*
|
|
217
|
+
* // ❌ Unsafe — silently escapes on Windows with absolute segment
|
|
218
|
+
* const dest = safePath.join(harnessRoot, item.name);
|
|
219
|
+
* ```
|
|
220
|
+
*/
|
|
221
|
+
readonly joinUnderRoot: (root: string, ...segments: string[]) => string;
|
|
190
222
|
};
|
|
191
223
|
/**
|
|
192
224
|
* Resolve an OS-native absolute path from an ESM module's `import.meta.url` and
|
package/dist/path-utils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"path-utils.d.ts","sourceRoot":"","sources":["../src/path-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAgB,MAAM,SAAS,CAAC;AAKlD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,aAAa,CAAC,GAAG,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CA+BxD;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAezC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,GACxC,MAAM,CAiBR;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAKjE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAMhE;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED
|
|
1
|
+
{"version":3,"file":"path-utils.d.ts","sourceRoot":"","sources":["../src/path-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAgB,MAAM,SAAS,CAAC;AAKlD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,aAAa,CAAC,GAAG,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CA+BxD;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAezC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,GACxC,MAAM,CAiBR;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAKjE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAMhE;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,QAAQ;IACnB,6DAA6D;8BAC9C,MAAM,EAAE,KAAG,MAAM;IAIhC,gEAAgE;iCAC9C,MAAM,EAAE,KAAG,MAAM;IAInC,iEAAiE;8BAClD,MAAM,MAAM,MAAM,KAAG,MAAM;IAI1C;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4BG;mCACiB,MAAM,eAAe,MAAM,EAAE,KAAG,MAAM;CAuClD,CAAC;AAEX;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,qBAAqB,CAAC,aAAa,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAQ1F;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,iBAAiB,CAAC,CAAC,GAAG,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAGhF"}
|
package/dist/path-utils.js
CHANGED
|
@@ -260,9 +260,11 @@ export function toForwardSlash(p) {
|
|
|
260
260
|
* import { safePath } from '@vibe-agent-toolkit/utils';
|
|
261
261
|
*
|
|
262
262
|
* // Always forward slashes, even on Windows
|
|
263
|
-
* safePath.join('C:\\Users', 'docs', 'file.md')
|
|
264
|
-
* safePath.resolve('/project', './docs')
|
|
265
|
-
* safePath.relative('/project/docs', '/project')
|
|
263
|
+
* safePath.join('C:\\Users', 'docs', 'file.md') // → 'C:/Users/docs/file.md'
|
|
264
|
+
* safePath.resolve('/project', './docs') // → '/project/docs'
|
|
265
|
+
* safePath.relative('/project/docs', '/project') // → '..'
|
|
266
|
+
* safePath.joinUnderRoot('/harness', 'skill-abc') // → '/harness/skill-abc'
|
|
267
|
+
* safePath.joinUnderRoot('/harness', '../escape') // throws Error
|
|
266
268
|
* ```
|
|
267
269
|
*/
|
|
268
270
|
export const safePath = {
|
|
@@ -278,6 +280,64 @@ export const safePath = {
|
|
|
278
280
|
relative(from, to) {
|
|
279
281
|
return toForwardSlash(path.relative(from, to));
|
|
280
282
|
},
|
|
283
|
+
/**
|
|
284
|
+
* Join path segments under a security root, throwing if the result would escape.
|
|
285
|
+
*
|
|
286
|
+
* Resolves `root + segments` and verifies the result is strictly inside `root`
|
|
287
|
+
* (or equal to it). Throws when any segment would cause the result to escape:
|
|
288
|
+
*
|
|
289
|
+
* - A `..` traversal that climbs above root
|
|
290
|
+
* - An absolute POSIX path segment (e.g. `/etc/passwd`)
|
|
291
|
+
* - A Windows drive-letter segment (e.g. `C:\Users\evil`)
|
|
292
|
+
*
|
|
293
|
+
* On success returns a forward-slash-normalized absolute path (consistent with
|
|
294
|
+
* the other `safePath` helpers).
|
|
295
|
+
*
|
|
296
|
+
* **Use this instead of `safePath.join(root, segment)` whenever `segment` may
|
|
297
|
+
* contain caller-controlled input** — this is the bug class that the original
|
|
298
|
+
* skill-test staging code was vulnerable to on Windows.
|
|
299
|
+
*
|
|
300
|
+
* @returns Forward-slash absolute path guaranteed to be inside `root`.
|
|
301
|
+
* @throws {Error} If the resolved path would escape `root`.
|
|
302
|
+
*
|
|
303
|
+
* @example
|
|
304
|
+
* ```typescript
|
|
305
|
+
* // ✅ Safe — throws if caller passes '../../../etc'
|
|
306
|
+
* const dest = safePath.joinUnderRoot(harnessRoot, stagedDirName(item.name));
|
|
307
|
+
*
|
|
308
|
+
* // ❌ Unsafe — silently escapes on Windows with absolute segment
|
|
309
|
+
* const dest = safePath.join(harnessRoot, item.name);
|
|
310
|
+
* ```
|
|
311
|
+
*/
|
|
312
|
+
joinUnderRoot(root, ...segments) {
|
|
313
|
+
// Eagerly reject any segment that is absolute (POSIX or Windows drive-letter)
|
|
314
|
+
// BEFORE resolving, so the error message can name the offending segment.
|
|
315
|
+
for (const seg of segments) {
|
|
316
|
+
if (path.isAbsolute(seg)) {
|
|
317
|
+
throw new Error(`safePath.joinUnderRoot: segment "${seg}" is absolute and escapes root "${root}".`);
|
|
318
|
+
}
|
|
319
|
+
// Windows drive-letter check for POSIX hosts (path.isAbsolute won't catch
|
|
320
|
+
// 'C:\...' on POSIX, but node's path.win32.isAbsolute does).
|
|
321
|
+
if (path.win32.isAbsolute(seg)) {
|
|
322
|
+
throw new Error(`safePath.joinUnderRoot: segment "${seg}" contains a Windows drive letter and escapes root "${root}".`);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
const resolvedRoot = path.resolve(root);
|
|
326
|
+
const resolvedResult = segments.length > 0
|
|
327
|
+
? path.resolve(resolvedRoot, ...segments)
|
|
328
|
+
: resolvedRoot;
|
|
329
|
+
// Containment check: normalize both to forward slashes so the comparison
|
|
330
|
+
// is platform-independent and no path.sep is needed in string operations.
|
|
331
|
+
const fwdRoot = toForwardSlash(resolvedRoot);
|
|
332
|
+
const fwdResult = toForwardSlash(resolvedResult);
|
|
333
|
+
// Result must equal root or start with root + '/' (not just startsWith(root)
|
|
334
|
+
// which would match '/rootEvil' when root is '/root').
|
|
335
|
+
const rootPrefix = fwdRoot.endsWith('/') ? fwdRoot : `${fwdRoot}/`;
|
|
336
|
+
if (fwdResult !== fwdRoot && !fwdResult.startsWith(rootPrefix)) {
|
|
337
|
+
throw new Error(`safePath.joinUnderRoot: result "${fwdResult}" escapes root "${fwdRoot}".`);
|
|
338
|
+
}
|
|
339
|
+
return fwdResult;
|
|
340
|
+
},
|
|
281
341
|
};
|
|
282
342
|
/**
|
|
283
343
|
* Resolve an OS-native absolute path from an ESM module's `import.meta.url` and
|
package/dist/path-utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"path-utils.js","sourceRoot":"","sources":["../src/path-utils.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"path-utils.js","sourceRoot":"","sources":["../src/path-utils.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
export interface ClaudeSpawnArgs {
|
|
2
|
-
promptFile: string;
|
|
3
2
|
pluginDirs: string[];
|
|
4
3
|
sandboxDir: string;
|
|
5
4
|
model?: string;
|
|
@@ -7,10 +6,11 @@ export interface ClaudeSpawnArgs {
|
|
|
7
6
|
maxBudgetUsd?: number;
|
|
8
7
|
}
|
|
9
8
|
/**
|
|
10
|
-
* Pure assembly of the headless `claude -p` argv (spec §9). The prompt is
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
9
|
+
* Pure assembly of the headless `claude -p` argv (spec §9). The prompt is never
|
|
10
|
+
* inlined as an argv string (Windows cmd-quoting safety) and claude 2.x has no
|
|
11
|
+
* `--prompt-file` flag — the prompt is fed to the child's stdin by
|
|
12
|
+
* {@link spawnHeadlessClaude} instead. `--setting-sources ""` suppresses
|
|
13
|
+
* user/project settings; built-in skills remain (§5).
|
|
14
14
|
*/
|
|
15
15
|
export declare function assembleClaudeArgs(opts: ClaudeSpawnArgs): string[];
|
|
16
16
|
export interface SpawnResult {
|
|
@@ -19,6 +19,13 @@ export interface SpawnResult {
|
|
|
19
19
|
stalled: boolean;
|
|
20
20
|
}
|
|
21
21
|
export interface SpawnHeadlessOptions extends ClaudeSpawnArgs {
|
|
22
|
+
/**
|
|
23
|
+
* Path to the experimenter-prompt file. Its contents are streamed to the
|
|
24
|
+
* child's stdin (claude 2.x reads the `-p` prompt from stdin; there is no
|
|
25
|
+
* `--prompt-file` flag). Kept off argv so the prompt is never inlined
|
|
26
|
+
* (Windows cmd-quoting safety).
|
|
27
|
+
*/
|
|
28
|
+
promptFile: string;
|
|
22
29
|
cwd: string;
|
|
23
30
|
env: NodeJS.ProcessEnv;
|
|
24
31
|
timeoutMs: number;
|
|
@@ -28,10 +35,11 @@ export interface SpawnHeadlessOptions extends ClaudeSpawnArgs {
|
|
|
28
35
|
onStderr?: (chunk: string) => void;
|
|
29
36
|
}
|
|
30
37
|
/**
|
|
31
|
-
* Spawn the headless `claude`.
|
|
32
|
-
* the session
|
|
33
|
-
* If `stallMs` is set, a resettable stall
|
|
34
|
-
* output is received for that duration
|
|
38
|
+
* Spawn the headless `claude`. The prompt file is streamed to the child's stdin
|
|
39
|
+
* so the session reads its prompt and then sees EOF (it cannot block on input,
|
|
40
|
+
* §16). Wall-clock kill on timeout. If `stallMs` is set, a resettable stall
|
|
41
|
+
* watchdog kills the child when no output is received for that duration
|
|
42
|
+
* (stalled: true in result).
|
|
35
43
|
*/
|
|
36
44
|
export declare function spawnHeadlessClaude(opts: SpawnHeadlessOptions): Promise<SpawnResult>;
|
|
37
45
|
//# sourceMappingURL=spawn-claude.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spawn-claude.d.ts","sourceRoot":"","sources":["../../src/skill-test/spawn-claude.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"spawn-claude.d.ts","sourceRoot":"","sources":["../../src/skill-test/spawn-claude.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,eAAe,GAAG,MAAM,EAAE,CAmBlE;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,oBAAqB,SAAQ,eAAe;IAC3D;;;;;OAKG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,yFAAyF;IACzF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACpC;AAED;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAAC,WAAW,CAAC,CAsD1F"}
|
|
@@ -2,19 +2,23 @@ import { spawn } from 'node:child_process';
|
|
|
2
2
|
import { createReadStream } from 'node:fs';
|
|
3
3
|
import which from 'which';
|
|
4
4
|
/**
|
|
5
|
-
* Pure assembly of the headless `claude -p` argv (spec §9). The prompt is
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
5
|
+
* Pure assembly of the headless `claude -p` argv (spec §9). The prompt is never
|
|
6
|
+
* inlined as an argv string (Windows cmd-quoting safety) and claude 2.x has no
|
|
7
|
+
* `--prompt-file` flag — the prompt is fed to the child's stdin by
|
|
8
|
+
* {@link spawnHeadlessClaude} instead. `--setting-sources ""` suppresses
|
|
9
|
+
* user/project settings; built-in skills remain (§5).
|
|
9
10
|
*/
|
|
10
11
|
export function assembleClaudeArgs(opts) {
|
|
11
12
|
const args = [
|
|
12
13
|
'-p',
|
|
14
|
+
// claude 2.x rejects `-p --output-format stream-json` unless --verbose is
|
|
15
|
+
// also passed ("--output-format=stream-json requires --verbose"). The
|
|
16
|
+
// streamed JSON is piped to stderr for progress visibility.
|
|
13
17
|
'--output-format', 'stream-json',
|
|
18
|
+
'--verbose',
|
|
14
19
|
'--setting-sources', '',
|
|
15
20
|
'--permission-mode', 'bypassPermissions',
|
|
16
21
|
'--add-dir', opts.sandboxDir,
|
|
17
|
-
'--prompt-file', opts.promptFile,
|
|
18
22
|
];
|
|
19
23
|
for (const dir of opts.pluginDirs) {
|
|
20
24
|
args.push('--plugin-dir', dir);
|
|
@@ -28,15 +32,15 @@ export function assembleClaudeArgs(opts) {
|
|
|
28
32
|
return args;
|
|
29
33
|
}
|
|
30
34
|
/**
|
|
31
|
-
* Spawn the headless `claude`.
|
|
32
|
-
* the session
|
|
33
|
-
* If `stallMs` is set, a resettable stall
|
|
34
|
-
* output is received for that duration
|
|
35
|
+
* Spawn the headless `claude`. The prompt file is streamed to the child's stdin
|
|
36
|
+
* so the session reads its prompt and then sees EOF (it cannot block on input,
|
|
37
|
+
* §16). Wall-clock kill on timeout. If `stallMs` is set, a resettable stall
|
|
38
|
+
* watchdog kills the child when no output is received for that duration
|
|
39
|
+
* (stalled: true in result).
|
|
35
40
|
*/
|
|
36
41
|
export async function spawnHeadlessClaude(opts) {
|
|
37
42
|
const bin = which.sync('claude');
|
|
38
43
|
const args = assembleClaudeArgs(opts);
|
|
39
|
-
const nullDevice = process.platform === 'win32' ? 'NUL' : '/dev/null';
|
|
40
44
|
return await new Promise((resolve, reject) => {
|
|
41
45
|
const child = spawn(bin, args, { cwd: opts.cwd, env: opts.env, stdio: ['pipe', 'pipe', 'pipe'] });
|
|
42
46
|
let timedOut = false;
|
|
@@ -66,8 +70,19 @@ export async function spawnHeadlessClaude(opts) {
|
|
|
66
70
|
if (stallTimer !== undefined)
|
|
67
71
|
clearTimeout(stallTimer);
|
|
68
72
|
};
|
|
69
|
-
//
|
|
70
|
-
|
|
73
|
+
// Feed the prompt to the child via stdin (claude 2.x has no --prompt-file).
|
|
74
|
+
// eslint-disable-next-line security/detect-non-literal-fs-filename -- our own derived prompt path
|
|
75
|
+
const promptStream = createReadStream(opts.promptFile);
|
|
76
|
+
promptStream.on('error', err => {
|
|
77
|
+
clearAllTimers();
|
|
78
|
+
child.kill('SIGKILL');
|
|
79
|
+
reject(err);
|
|
80
|
+
});
|
|
81
|
+
// Swallow EPIPE: if the child exits before consuming all stdin, the write
|
|
82
|
+
// end errors — that is not a harness failure (the close handler reports the
|
|
83
|
+
// child's real exit status).
|
|
84
|
+
child.stdin.on('error', () => { });
|
|
85
|
+
promptStream.pipe(child.stdin);
|
|
71
86
|
child.stdout.on('data', (d) => { opts.onStdout?.(d.toString()); });
|
|
72
87
|
child.stderr.on('data', (d) => { opts.onStderr?.(d.toString()); });
|
|
73
88
|
child.on('error', err => { clearAllTimers(); reject(err); });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spawn-claude.js","sourceRoot":"","sources":["../../src/skill-test/spawn-claude.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAE3C,OAAO,KAAK,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"spawn-claude.js","sourceRoot":"","sources":["../../src/skill-test/spawn-claude.ts"],"names":[],"mappings":"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"}
|