@leanandmean/coding-agent 0.74.1-scramjet.32 → 0.74.1-scramjet.33
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/CHANGELOG.md +1 -0
- package/dist/core/exec.d.ts +10 -0
- package/dist/core/exec.d.ts.map +1 -1
- package/dist/core/exec.js +68 -19
- package/dist/core/exec.js.map +1 -1
- package/dist/core/extensions/types.d.ts +6 -1
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +8 -1
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +54 -17
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +46 -1
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/docs/extensions.md +27 -4
- package/docs/tui.md +25 -4
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
### Added
|
|
14
14
|
|
|
15
|
+
- Support exact stdin transport and tool-attached approval context with durable transcript ordering for guarded forge publication. ([#486](https://github.com/LeanAndMean/scramjet/pull/486))
|
|
15
16
|
- Expose detached startup version checks and package-manager installation ownership for product update notifications. ([#434](https://github.com/LeanAndMean/scramjet/pull/434))
|
|
16
17
|
- Append-only finalized transcript history with a bounded live canvas prevents routine response completion, tool finalization, height resize, and overlay updates from replaying or jumping terminal scrollback. ([#396](https://github.com/LeanAndMean/scramjet/pull/396))
|
|
17
18
|
|
package/dist/core/exec.d.ts
CHANGED
|
@@ -11,6 +11,12 @@ export interface ExecOptions {
|
|
|
11
11
|
timeout?: number;
|
|
12
12
|
/** Working directory */
|
|
13
13
|
cwd?: string;
|
|
14
|
+
/** Exact UTF-8 input to write before closing stdin */
|
|
15
|
+
stdin?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface ExecError {
|
|
18
|
+
message: string;
|
|
19
|
+
code?: string;
|
|
14
20
|
}
|
|
15
21
|
/**
|
|
16
22
|
* Result of executing a shell command.
|
|
@@ -20,6 +26,10 @@ export interface ExecResult {
|
|
|
20
26
|
stderr: string;
|
|
21
27
|
code: number;
|
|
22
28
|
killed: boolean;
|
|
29
|
+
spawnError?: ExecError;
|
|
30
|
+
stdinError?: ExecError;
|
|
31
|
+
stdoutError?: ExecError;
|
|
32
|
+
stderrError?: ExecError;
|
|
23
33
|
}
|
|
24
34
|
/**
|
|
25
35
|
* Execute a shell command and return stdout/stderr/code.
|
package/dist/core/exec.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../../src/core/exec.ts"],"names":[],"mappings":"AAAA;;GAEG;
|
|
1
|
+
{"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../../src/core/exec.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH;;GAEG;AACH,MAAM,WAAW,WAAW;IAC3B,wCAAwC;IACxC,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,8BAA8B;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wBAAwB;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,sDAAsD;IACtD,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,SAAS;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,WAAW,CAAC,EAAE,SAAS,CAAC;CACxB;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAChC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,UAAU,CAAC,CAkHrB","sourcesContent":["/**\n * Shared command execution utilities for extensions and custom tools.\n */\n\nimport { spawn } from \"node:child_process\";\nimport { StringDecoder } from \"node:string_decoder\";\nimport { waitForChildProcess } from \"../utils/child-process.js\";\n\n/**\n * Options for executing shell commands.\n */\nexport interface ExecOptions {\n\t/** AbortSignal to cancel the command */\n\tsignal?: AbortSignal;\n\t/** Timeout in milliseconds */\n\ttimeout?: number;\n\t/** Working directory */\n\tcwd?: string;\n\t/** Exact UTF-8 input to write before closing stdin */\n\tstdin?: string;\n}\n\nexport interface ExecError {\n\tmessage: string;\n\tcode?: string;\n}\n\n/**\n * Result of executing a shell command.\n */\nexport interface ExecResult {\n\tstdout: string;\n\tstderr: string;\n\tcode: number;\n\tkilled: boolean;\n\tspawnError?: ExecError;\n\tstdinError?: ExecError;\n\tstdoutError?: ExecError;\n\tstderrError?: ExecError;\n}\n\n/**\n * Execute a shell command and return stdout/stderr/code.\n * Supports timeout and abort signal.\n */\nexport async function execCommand(\n\tcommand: string,\n\targs: string[],\n\tcwd: string,\n\toptions?: ExecOptions,\n): Promise<ExecResult> {\n\treturn new Promise((resolve) => {\n\t\tconst proc = spawn(command, args, {\n\t\t\tcwd,\n\t\t\tshell: false,\n\t\t\tstdio: [options?.stdin === undefined ? \"ignore\" : \"pipe\", \"pipe\", \"pipe\"],\n\t\t});\n\n\t\tlet stdout = \"\";\n\t\tlet stderr = \"\";\n\t\t// SCRAMJET-DIVERGENCE: decode process output across chunk boundaries for exact publication verification (#479).\n\t\tconst stdoutDecoder = new StringDecoder(\"utf8\");\n\t\tconst stderrDecoder = new StringDecoder(\"utf8\");\n\t\tlet killed = false;\n\t\tlet settled = false;\n\t\tlet spawned = false;\n\t\tlet terminationRequested = false;\n\t\tlet spawnError: ExecError | undefined;\n\t\tlet stdinError: ExecError | undefined;\n\t\tlet stdoutError: ExecError | undefined;\n\t\tlet stderrError: ExecError | undefined;\n\t\tlet timeoutId: NodeJS.Timeout | undefined;\n\t\tlet killTimeoutId: NodeJS.Timeout | undefined;\n\n\t\t// SCRAMJET-DIVERGENCE: timeout escalation tracks settlement rather than signal delivery (#432).\n\t\tconst terminateSpawnedProcess = () => {\n\t\t\tif (killed || !spawned || !proc.kill(\"SIGTERM\")) return;\n\t\t\tkilled = true;\n\t\t\tkillTimeoutId = setTimeout(() => {\n\t\t\t\tif (!settled) proc.kill(\"SIGKILL\");\n\t\t\t}, 5000);\n\t\t};\n\t\tconst killProcess = () => {\n\t\t\tterminationRequested = true;\n\t\t\tterminateSpawnedProcess();\n\t\t};\n\n\t\t// Handle abort signal\n\t\tif (options?.signal) {\n\t\t\tif (options.signal.aborted) {\n\t\t\t\tkillProcess();\n\t\t\t} else {\n\t\t\t\toptions.signal.addEventListener(\"abort\", killProcess, { once: true });\n\t\t\t}\n\t\t}\n\n\t\t// Handle timeout\n\t\tif (options?.timeout && options.timeout > 0) {\n\t\t\ttimeoutId = setTimeout(() => {\n\t\t\t\tkillProcess();\n\t\t\t}, options.timeout);\n\t\t}\n\n\t\tproc.once(\"spawn\", () => {\n\t\t\tspawned = true;\n\t\t\tif (terminationRequested) terminateSpawnedProcess();\n\t\t});\n\n\t\tproc.stdout?.on(\"data\", (data) => {\n\t\t\tstdout += stdoutDecoder.write(data);\n\t\t});\n\n\t\tproc.stderr?.on(\"data\", (data) => {\n\t\t\tstderr += stderrDecoder.write(data);\n\t\t});\n\n\t\tconst errorDetails = (error: Error): ExecError => {\n\t\t\tconst code = (error as NodeJS.ErrnoException).code;\n\t\t\treturn code === undefined ? { message: error.message } : { message: error.message, code };\n\t\t};\n\n\t\tproc.stdout?.once(\"error\", (error: Error) => {\n\t\t\tstdoutError ??= errorDetails(error);\n\t\t\tkillProcess();\n\t\t});\n\t\tproc.stderr?.once(\"error\", (error: Error) => {\n\t\t\tstderrError ??= errorDetails(error);\n\t\t\tkillProcess();\n\t\t});\n\n\t\tconst stdinSettled = new Promise<void>((resolveStdin) => {\n\t\t\tif (options?.stdin === undefined || proc.stdin === null) {\n\t\t\t\tresolveStdin();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst onStdinError = (error: Error) => {\n\t\t\t\tstdinError ??= errorDetails(error);\n\t\t\t};\n\t\t\tproc.stdin.on(\"error\", onStdinError);\n\t\t\tproc.stdin.once(\"close\", () => {\n\t\t\t\tproc.stdin?.removeListener(\"error\", onStdinError);\n\t\t\t\tresolveStdin();\n\t\t\t});\n\t\t\tproc.stdin.end(options.stdin, \"utf8\");\n\t\t});\n\n\t\tconst processSettled = waitForChildProcess(proc)\n\t\t\t.then((code) => code ?? 0)\n\t\t\t.catch((error: Error) => {\n\t\t\t\tif (!spawned) spawnError = errorDetails(error);\n\t\t\t\treturn 1;\n\t\t\t});\n\n\t\tPromise.all([processSettled, stdinSettled]).then(([code]) => {\n\t\t\tstdout += stdoutDecoder.end();\n\t\t\tstderr += stderrDecoder.end();\n\t\t\tsettled = true;\n\t\t\tif (timeoutId) clearTimeout(timeoutId);\n\t\t\tif (killTimeoutId) clearTimeout(killTimeoutId);\n\t\t\tif (options?.signal) options.signal.removeEventListener(\"abort\", killProcess);\n\t\t\tresolve({ stdout, stderr, code, killed, spawnError, stdinError, stdoutError, stderrError });\n\t\t});\n\t});\n}\n"]}
|
package/dist/core/exec.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Shared command execution utilities for extensions and custom tools.
|
|
3
3
|
*/
|
|
4
4
|
import { spawn } from "node:child_process";
|
|
5
|
+
import { StringDecoder } from "node:string_decoder";
|
|
5
6
|
import { waitForChildProcess } from "../utils/child-process.js";
|
|
6
7
|
/**
|
|
7
8
|
* Execute a shell command and return stdout/stderr/code.
|
|
@@ -12,24 +13,36 @@ export async function execCommand(command, args, cwd, options) {
|
|
|
12
13
|
const proc = spawn(command, args, {
|
|
13
14
|
cwd,
|
|
14
15
|
shell: false,
|
|
15
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
16
|
+
stdio: [options?.stdin === undefined ? "ignore" : "pipe", "pipe", "pipe"],
|
|
16
17
|
});
|
|
17
18
|
let stdout = "";
|
|
18
19
|
let stderr = "";
|
|
20
|
+
// SCRAMJET-DIVERGENCE: decode process output across chunk boundaries for exact publication verification (#479).
|
|
21
|
+
const stdoutDecoder = new StringDecoder("utf8");
|
|
22
|
+
const stderrDecoder = new StringDecoder("utf8");
|
|
19
23
|
let killed = false;
|
|
20
24
|
let settled = false;
|
|
25
|
+
let spawned = false;
|
|
26
|
+
let terminationRequested = false;
|
|
27
|
+
let spawnError;
|
|
28
|
+
let stdinError;
|
|
29
|
+
let stdoutError;
|
|
30
|
+
let stderrError;
|
|
21
31
|
let timeoutId;
|
|
22
32
|
let killTimeoutId;
|
|
23
33
|
// SCRAMJET-DIVERGENCE: timeout escalation tracks settlement rather than signal delivery (#432).
|
|
34
|
+
const terminateSpawnedProcess = () => {
|
|
35
|
+
if (killed || !spawned || !proc.kill("SIGTERM"))
|
|
36
|
+
return;
|
|
37
|
+
killed = true;
|
|
38
|
+
killTimeoutId = setTimeout(() => {
|
|
39
|
+
if (!settled)
|
|
40
|
+
proc.kill("SIGKILL");
|
|
41
|
+
}, 5000);
|
|
42
|
+
};
|
|
24
43
|
const killProcess = () => {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
proc.kill("SIGTERM");
|
|
28
|
-
killTimeoutId = setTimeout(() => {
|
|
29
|
-
if (!settled)
|
|
30
|
-
proc.kill("SIGKILL");
|
|
31
|
-
}, 5000);
|
|
32
|
-
}
|
|
44
|
+
terminationRequested = true;
|
|
45
|
+
terminateSpawnedProcess();
|
|
33
46
|
};
|
|
34
47
|
// Handle abort signal
|
|
35
48
|
if (options?.signal) {
|
|
@@ -46,15 +59,54 @@ export async function execCommand(command, args, cwd, options) {
|
|
|
46
59
|
killProcess();
|
|
47
60
|
}, options.timeout);
|
|
48
61
|
}
|
|
62
|
+
proc.once("spawn", () => {
|
|
63
|
+
spawned = true;
|
|
64
|
+
if (terminationRequested)
|
|
65
|
+
terminateSpawnedProcess();
|
|
66
|
+
});
|
|
49
67
|
proc.stdout?.on("data", (data) => {
|
|
50
|
-
stdout +=
|
|
68
|
+
stdout += stdoutDecoder.write(data);
|
|
51
69
|
});
|
|
52
70
|
proc.stderr?.on("data", (data) => {
|
|
53
|
-
stderr +=
|
|
71
|
+
stderr += stderrDecoder.write(data);
|
|
72
|
+
});
|
|
73
|
+
const errorDetails = (error) => {
|
|
74
|
+
const code = error.code;
|
|
75
|
+
return code === undefined ? { message: error.message } : { message: error.message, code };
|
|
76
|
+
};
|
|
77
|
+
proc.stdout?.once("error", (error) => {
|
|
78
|
+
stdoutError ??= errorDetails(error);
|
|
79
|
+
killProcess();
|
|
80
|
+
});
|
|
81
|
+
proc.stderr?.once("error", (error) => {
|
|
82
|
+
stderrError ??= errorDetails(error);
|
|
83
|
+
killProcess();
|
|
54
84
|
});
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
85
|
+
const stdinSettled = new Promise((resolveStdin) => {
|
|
86
|
+
if (options?.stdin === undefined || proc.stdin === null) {
|
|
87
|
+
resolveStdin();
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
const onStdinError = (error) => {
|
|
91
|
+
stdinError ??= errorDetails(error);
|
|
92
|
+
};
|
|
93
|
+
proc.stdin.on("error", onStdinError);
|
|
94
|
+
proc.stdin.once("close", () => {
|
|
95
|
+
proc.stdin?.removeListener("error", onStdinError);
|
|
96
|
+
resolveStdin();
|
|
97
|
+
});
|
|
98
|
+
proc.stdin.end(options.stdin, "utf8");
|
|
99
|
+
});
|
|
100
|
+
const processSettled = waitForChildProcess(proc)
|
|
101
|
+
.then((code) => code ?? 0)
|
|
102
|
+
.catch((error) => {
|
|
103
|
+
if (!spawned)
|
|
104
|
+
spawnError = errorDetails(error);
|
|
105
|
+
return 1;
|
|
106
|
+
});
|
|
107
|
+
Promise.all([processSettled, stdinSettled]).then(([code]) => {
|
|
108
|
+
stdout += stdoutDecoder.end();
|
|
109
|
+
stderr += stderrDecoder.end();
|
|
58
110
|
settled = true;
|
|
59
111
|
if (timeoutId)
|
|
60
112
|
clearTimeout(timeoutId);
|
|
@@ -62,11 +114,8 @@ export async function execCommand(command, args, cwd, options) {
|
|
|
62
114
|
clearTimeout(killTimeoutId);
|
|
63
115
|
if (options?.signal)
|
|
64
116
|
options.signal.removeEventListener("abort", killProcess);
|
|
65
|
-
resolve({ stdout, stderr, code, killed });
|
|
66
|
-
};
|
|
67
|
-
waitForChildProcess(proc)
|
|
68
|
-
.then((code) => finish(code ?? 0))
|
|
69
|
-
.catch(() => finish(1));
|
|
117
|
+
resolve({ stdout, stderr, code, killed, spawnError, stdinError, stdoutError, stderrError });
|
|
118
|
+
});
|
|
70
119
|
});
|
|
71
120
|
}
|
|
72
121
|
//# sourceMappingURL=exec.js.map
|
package/dist/core/exec.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exec.js","sourceRoot":"","sources":["../../src/core/exec.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"exec.js","sourceRoot":"","sources":["../../src/core/exec.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shared command execution utilities for extensions and custom tools.\n */\n\nimport { spawn } from \"node:child_process\";\nimport { StringDecoder } from \"node:string_decoder\";\nimport { waitForChildProcess } from \"../utils/child-process.js\";\n\n/**\n * Options for executing shell commands.\n */\nexport interface ExecOptions {\n\t/** AbortSignal to cancel the command */\n\tsignal?: AbortSignal;\n\t/** Timeout in milliseconds */\n\ttimeout?: number;\n\t/** Working directory */\n\tcwd?: string;\n\t/** Exact UTF-8 input to write before closing stdin */\n\tstdin?: string;\n}\n\nexport interface ExecError {\n\tmessage: string;\n\tcode?: string;\n}\n\n/**\n * Result of executing a shell command.\n */\nexport interface ExecResult {\n\tstdout: string;\n\tstderr: string;\n\tcode: number;\n\tkilled: boolean;\n\tspawnError?: ExecError;\n\tstdinError?: ExecError;\n\tstdoutError?: ExecError;\n\tstderrError?: ExecError;\n}\n\n/**\n * Execute a shell command and return stdout/stderr/code.\n * Supports timeout and abort signal.\n */\nexport async function execCommand(\n\tcommand: string,\n\targs: string[],\n\tcwd: string,\n\toptions?: ExecOptions,\n): Promise<ExecResult> {\n\treturn new Promise((resolve) => {\n\t\tconst proc = spawn(command, args, {\n\t\t\tcwd,\n\t\t\tshell: false,\n\t\t\tstdio: [options?.stdin === undefined ? \"ignore\" : \"pipe\", \"pipe\", \"pipe\"],\n\t\t});\n\n\t\tlet stdout = \"\";\n\t\tlet stderr = \"\";\n\t\t// SCRAMJET-DIVERGENCE: decode process output across chunk boundaries for exact publication verification (#479).\n\t\tconst stdoutDecoder = new StringDecoder(\"utf8\");\n\t\tconst stderrDecoder = new StringDecoder(\"utf8\");\n\t\tlet killed = false;\n\t\tlet settled = false;\n\t\tlet spawned = false;\n\t\tlet terminationRequested = false;\n\t\tlet spawnError: ExecError | undefined;\n\t\tlet stdinError: ExecError | undefined;\n\t\tlet stdoutError: ExecError | undefined;\n\t\tlet stderrError: ExecError | undefined;\n\t\tlet timeoutId: NodeJS.Timeout | undefined;\n\t\tlet killTimeoutId: NodeJS.Timeout | undefined;\n\n\t\t// SCRAMJET-DIVERGENCE: timeout escalation tracks settlement rather than signal delivery (#432).\n\t\tconst terminateSpawnedProcess = () => {\n\t\t\tif (killed || !spawned || !proc.kill(\"SIGTERM\")) return;\n\t\t\tkilled = true;\n\t\t\tkillTimeoutId = setTimeout(() => {\n\t\t\t\tif (!settled) proc.kill(\"SIGKILL\");\n\t\t\t}, 5000);\n\t\t};\n\t\tconst killProcess = () => {\n\t\t\tterminationRequested = true;\n\t\t\tterminateSpawnedProcess();\n\t\t};\n\n\t\t// Handle abort signal\n\t\tif (options?.signal) {\n\t\t\tif (options.signal.aborted) {\n\t\t\t\tkillProcess();\n\t\t\t} else {\n\t\t\t\toptions.signal.addEventListener(\"abort\", killProcess, { once: true });\n\t\t\t}\n\t\t}\n\n\t\t// Handle timeout\n\t\tif (options?.timeout && options.timeout > 0) {\n\t\t\ttimeoutId = setTimeout(() => {\n\t\t\t\tkillProcess();\n\t\t\t}, options.timeout);\n\t\t}\n\n\t\tproc.once(\"spawn\", () => {\n\t\t\tspawned = true;\n\t\t\tif (terminationRequested) terminateSpawnedProcess();\n\t\t});\n\n\t\tproc.stdout?.on(\"data\", (data) => {\n\t\t\tstdout += stdoutDecoder.write(data);\n\t\t});\n\n\t\tproc.stderr?.on(\"data\", (data) => {\n\t\t\tstderr += stderrDecoder.write(data);\n\t\t});\n\n\t\tconst errorDetails = (error: Error): ExecError => {\n\t\t\tconst code = (error as NodeJS.ErrnoException).code;\n\t\t\treturn code === undefined ? { message: error.message } : { message: error.message, code };\n\t\t};\n\n\t\tproc.stdout?.once(\"error\", (error: Error) => {\n\t\t\tstdoutError ??= errorDetails(error);\n\t\t\tkillProcess();\n\t\t});\n\t\tproc.stderr?.once(\"error\", (error: Error) => {\n\t\t\tstderrError ??= errorDetails(error);\n\t\t\tkillProcess();\n\t\t});\n\n\t\tconst stdinSettled = new Promise<void>((resolveStdin) => {\n\t\t\tif (options?.stdin === undefined || proc.stdin === null) {\n\t\t\t\tresolveStdin();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst onStdinError = (error: Error) => {\n\t\t\t\tstdinError ??= errorDetails(error);\n\t\t\t};\n\t\t\tproc.stdin.on(\"error\", onStdinError);\n\t\t\tproc.stdin.once(\"close\", () => {\n\t\t\t\tproc.stdin?.removeListener(\"error\", onStdinError);\n\t\t\t\tresolveStdin();\n\t\t\t});\n\t\t\tproc.stdin.end(options.stdin, \"utf8\");\n\t\t});\n\n\t\tconst processSettled = waitForChildProcess(proc)\n\t\t\t.then((code) => code ?? 0)\n\t\t\t.catch((error: Error) => {\n\t\t\t\tif (!spawned) spawnError = errorDetails(error);\n\t\t\t\treturn 1;\n\t\t\t});\n\n\t\tPromise.all([processSettled, stdinSettled]).then(([code]) => {\n\t\t\tstdout += stdoutDecoder.end();\n\t\t\tstderr += stderrDecoder.end();\n\t\t\tsettled = true;\n\t\t\tif (timeoutId) clearTimeout(timeoutId);\n\t\t\tif (killTimeoutId) clearTimeout(killTimeoutId);\n\t\t\tif (options?.signal) options.signal.removeEventListener(\"abort\", killProcess);\n\t\t\tresolve({ stdout, stderr, code, killed, spawnError, stdinError, stdoutError, stderrError });\n\t\t});\n\t});\n}\n"]}
|
|
@@ -121,6 +121,11 @@ export interface ExtensionUIContext {
|
|
|
121
121
|
dispose?(): void;
|
|
122
122
|
}>, options?: {
|
|
123
123
|
overlay?: boolean;
|
|
124
|
+
/** Commit immutable visual context at a pending tool's transcript position before focusing controls. Not persisted. */
|
|
125
|
+
toolAttachedContext?: {
|
|
126
|
+
toolCallId: string;
|
|
127
|
+
render: (tui: TUI, theme: Theme) => Component;
|
|
128
|
+
};
|
|
124
129
|
/** Overlay positioning/sizing options. Can be static or a function for dynamic updates. */
|
|
125
130
|
overlayOptions?: OverlayOptions | (() => OverlayOptions);
|
|
126
131
|
/** Called with the overlay handle after the overlay is shown. Use to control visibility. */
|
|
@@ -226,7 +231,7 @@ export interface DispatchUserInputOptions {
|
|
|
226
231
|
export interface ExtensionContext {
|
|
227
232
|
/** UI methods for user interaction */
|
|
228
233
|
ui: ExtensionUIContext;
|
|
229
|
-
/** Whether UI is available (
|
|
234
|
+
/** Whether some UI transport is available; individual methods may still be unsupported (for example custom() in RPC). */
|
|
230
235
|
hasUI: boolean;
|
|
231
236
|
/** Current working directory */
|
|
232
237
|
cwd: string;
|