@caupulican/pi-adaptative 0.93.5 → 0.93.7
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 +25 -0
- package/dist/bundled-resources/skills/n-plus-2-architecture/SKILL.md +13 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +5 -20
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/autonomy/envelope-enforcement.d.ts +3 -1
- package/dist/core/autonomy/envelope-enforcement.d.ts.map +1 -1
- package/dist/core/autonomy/envelope-enforcement.js +23 -12
- package/dist/core/autonomy/envelope-enforcement.js.map +1 -1
- package/dist/core/autonomy/gates.d.ts.map +1 -1
- package/dist/core/autonomy/gates.js +24 -26
- package/dist/core/autonomy/gates.js.map +1 -1
- package/dist/core/context-gc.d.ts.map +1 -1
- package/dist/core/context-gc.js +128 -3
- package/dist/core/context-gc.js.map +1 -1
- package/dist/core/session-shutdown.d.ts +9 -0
- package/dist/core/session-shutdown.d.ts.map +1 -0
- package/dist/core/session-shutdown.js +44 -0
- package/dist/core/session-shutdown.js.map +1 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/skill-vault.d.ts +6 -2
- package/dist/core/skill-vault.d.ts.map +1 -1
- package/dist/core/skill-vault.js +30 -12
- package/dist/core/skill-vault.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +7 -18
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +2 -3
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +86 -33
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/file-mutation-intent.d.ts +16 -0
- package/dist/core/tools/file-mutation-intent.d.ts.map +1 -1
- package/dist/core/tools/file-mutation-intent.js +51 -2
- package/dist/core/tools/file-mutation-intent.js.map +1 -1
- package/dist/core/tools/persistent-process-coordinator.d.ts +8 -2
- package/dist/core/tools/persistent-process-coordinator.d.ts.map +1 -1
- package/dist/core/tools/persistent-process-coordinator.js +52 -4
- package/dist/core/tools/persistent-process-coordinator.js.map +1 -1
- package/dist/core/tools/shell-execution-session.d.ts +8 -1
- package/dist/core/tools/shell-execution-session.d.ts.map +1 -1
- package/dist/core/tools/shell-execution-session.js +54 -3
- package/dist/core/tools/shell-execution-session.js.map +1 -1
- package/dist/core/tools/shell-session.d.ts +2 -1
- package/dist/core/tools/shell-session.d.ts.map +1 -1
- package/dist/core/tools/shell-session.js +22 -2
- package/dist/core/tools/shell-session.js.map +1 -1
- package/dist/core/tools/skill.d.ts +1 -0
- package/dist/core/tools/skill.d.ts.map +1 -1
- package/dist/core/tools/skill.js +11 -6
- package/dist/core/tools/skill.js.map +1 -1
- package/dist/core/tools/windows-shell-engine.d.ts +1 -1
- package/dist/core/tools/windows-shell-engine.d.ts.map +1 -1
- package/dist/core/tools/windows-shell-engine.js +6 -2
- package/dist/core/tools/windows-shell-engine.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +2 -2
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/utils/shell.d.ts +3 -5
- package/dist/utils/shell.d.ts.map +1 -1
- package/dist/utils/shell.js +4 -7
- package/dist/utils/shell.js.map +1 -1
- package/docs/settings.md +7 -7
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +12 -12
- package/package.json +4 -4
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
* Shared lifecycle owner for one serialized, persistent child process.
|
|
3
3
|
*
|
|
4
4
|
* Wire protocols, state projection, and respawn policy stay with their concrete shell adapters.
|
|
5
|
-
* This boundary owns only the invariant OS mechanics: one active task, one
|
|
6
|
-
* event rejection, exit/close arbitration, whole-tree kill,
|
|
5
|
+
* This boundary owns only the invariant OS mechanics: one active task, one current child, every
|
|
6
|
+
* outstanding child terminal, stale event rejection, exit/close arbitration, whole-tree kill,
|
|
7
|
+
* loop references, and parent exit.
|
|
7
8
|
*/
|
|
8
9
|
import type { ChildProcess } from "node:child_process";
|
|
9
10
|
export interface PersistentChildHandlers {
|
|
@@ -14,18 +15,23 @@ export interface PersistentChildHandlers {
|
|
|
14
15
|
}
|
|
15
16
|
export declare class PersistentProcessCoordinator {
|
|
16
17
|
private currentChild;
|
|
18
|
+
private readonly pendingChildTerminals;
|
|
17
19
|
private queue;
|
|
18
20
|
private disposed;
|
|
19
21
|
constructor();
|
|
20
22
|
get child(): ChildProcess | null;
|
|
23
|
+
get terminalPromise(): Promise<void>;
|
|
21
24
|
runSerialized<T>(task: () => Promise<T>): Promise<T>;
|
|
22
25
|
attach(child: ChildProcess, handlers: PersistentChildHandlers): void;
|
|
23
26
|
kill(): void;
|
|
27
|
+
private terminateChild;
|
|
24
28
|
dispose(): void;
|
|
25
29
|
/** Synchronous best-effort tree kill for the process exit hook. */
|
|
26
30
|
killForProcessExit(): void;
|
|
27
31
|
/** Idle coordinators must not keep one-shot Node modes alive; active commands must. */
|
|
28
32
|
setLoopRef(active: boolean): void;
|
|
33
|
+
private waitForTerminalRelease;
|
|
34
|
+
private trackTerminal;
|
|
29
35
|
private clear;
|
|
30
36
|
}
|
|
31
37
|
//# sourceMappingURL=persistent-process-coordinator.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"persistent-process-coordinator.d.ts","sourceRoot":"","sources":["../../../src/core/tools/persistent-process-coordinator.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"persistent-process-coordinator.d.ts","sourceRoot":"","sources":["../../../src/core/tools/persistent-process-coordinator.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAIvD,MAAM,WAAW,uBAAuB;IACvC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,OAAO,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IAC5B,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC;CACnC;AAaD,qBAAa,4BAA4B;IACxC,OAAO,CAAC,YAAY,CAA6B;IACjD,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAA4B;IAClE,OAAO,CAAC,KAAK,CAAoC;IACjD,OAAO,CAAC,QAAQ,CAAS;IAEzB,cAGC;IAED,IAAI,KAAK,IAAI,YAAY,GAAG,IAAI,CAE/B;IAED,IAAI,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAEnC;IAED,aAAa,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAOnD;IAED,MAAM,CAAC,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,uBAAuB,GAAG,IAAI,CAyCnE;IAED,IAAI,IAAI,IAAI,CAKX;IAED,OAAO,CAAC,cAAc;IAatB,OAAO,IAAI,IAAI,CAKd;IAED,mEAAmE;IACnE,kBAAkB,IAAI,IAAI,CAEzB;IAED,uFAAuF;IACvF,UAAU,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAIhC;YAEa,sBAAsB;IAOpC,OAAO,CAAC,aAAa;IAuBrB,OAAO,CAAC,KAAK;CAMb"}
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
* Shared lifecycle owner for one serialized, persistent child process.
|
|
3
3
|
*
|
|
4
4
|
* Wire protocols, state projection, and respawn policy stay with their concrete shell adapters.
|
|
5
|
-
* This boundary owns only the invariant OS mechanics: one active task, one
|
|
6
|
-
* event rejection, exit/close arbitration, whole-tree kill,
|
|
5
|
+
* This boundary owns only the invariant OS mechanics: one active task, one current child, every
|
|
6
|
+
* outstanding child terminal, stale event rejection, exit/close arbitration, whole-tree kill,
|
|
7
|
+
* loop references, and parent exit.
|
|
7
8
|
*/
|
|
8
9
|
import { setChildProcessLoopRef } from "../../utils/child-process-ref.js";
|
|
9
10
|
import { killProcessTree, trackDetachedChildPid, untrackDetachedChildPid } from "../../utils/shell.js";
|
|
@@ -21,6 +22,7 @@ function installExitHook() {
|
|
|
21
22
|
export class PersistentProcessCoordinator {
|
|
22
23
|
constructor() {
|
|
23
24
|
this.currentChild = null;
|
|
25
|
+
this.pendingChildTerminals = new Set();
|
|
24
26
|
this.queue = Promise.resolve();
|
|
25
27
|
this.disposed = false;
|
|
26
28
|
installExitHook();
|
|
@@ -29,6 +31,9 @@ export class PersistentProcessCoordinator {
|
|
|
29
31
|
get child() {
|
|
30
32
|
return this.currentChild;
|
|
31
33
|
}
|
|
34
|
+
get terminalPromise() {
|
|
35
|
+
return this.waitForTerminalRelease();
|
|
36
|
+
}
|
|
32
37
|
runSerialized(task) {
|
|
33
38
|
const run = this.queue.then(task);
|
|
34
39
|
this.queue = run.then(() => undefined, () => undefined);
|
|
@@ -36,8 +41,8 @@ export class PersistentProcessCoordinator {
|
|
|
36
41
|
}
|
|
37
42
|
attach(child, handlers) {
|
|
38
43
|
if (this.disposed) {
|
|
39
|
-
|
|
40
|
-
|
|
44
|
+
this.trackTerminal(child);
|
|
45
|
+
this.terminateChild(child);
|
|
41
46
|
throw new Error("Persistent process coordinator is disposed");
|
|
42
47
|
}
|
|
43
48
|
if (this.currentChild)
|
|
@@ -45,6 +50,7 @@ export class PersistentProcessCoordinator {
|
|
|
45
50
|
this.currentChild = child;
|
|
46
51
|
if (child.pid)
|
|
47
52
|
trackDetachedChildPid(child.pid);
|
|
53
|
+
this.trackTerminal(child);
|
|
48
54
|
child.stdout?.on("data", (data) => {
|
|
49
55
|
if (this.currentChild === child)
|
|
50
56
|
handlers.onStdout(data);
|
|
@@ -86,8 +92,21 @@ export class PersistentProcessCoordinator {
|
|
|
86
92
|
if (!child)
|
|
87
93
|
return;
|
|
88
94
|
this.clear(child);
|
|
95
|
+
this.terminateChild(child);
|
|
96
|
+
}
|
|
97
|
+
terminateChild(child) {
|
|
98
|
+
// Bun's Windows child-process bridge can stop publishing terminal events after every
|
|
99
|
+
// handle has been unref'd. Re-arm the already-installed close observer before killing so
|
|
100
|
+
// strict teardown can distinguish physical handle release from process exit.
|
|
101
|
+
setChildProcessLoopRef(child, true);
|
|
89
102
|
if (child.pid)
|
|
90
103
|
killProcessTree(child.pid);
|
|
104
|
+
try {
|
|
105
|
+
child.kill();
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
// Process already dead
|
|
109
|
+
}
|
|
91
110
|
}
|
|
92
111
|
dispose() {
|
|
93
112
|
if (this.disposed)
|
|
@@ -107,6 +126,35 @@ export class PersistentProcessCoordinator {
|
|
|
107
126
|
return;
|
|
108
127
|
setChildProcessLoopRef(child, active);
|
|
109
128
|
}
|
|
129
|
+
async waitForTerminalRelease() {
|
|
130
|
+
await this.queue;
|
|
131
|
+
while (this.pendingChildTerminals.size > 0) {
|
|
132
|
+
await Promise.all(Array.from(this.pendingChildTerminals));
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
trackTerminal(child) {
|
|
136
|
+
let settled = false;
|
|
137
|
+
let resolveTerminal;
|
|
138
|
+
const terminalPromise = new Promise((resolve) => {
|
|
139
|
+
resolveTerminal = resolve;
|
|
140
|
+
});
|
|
141
|
+
const settleTerminal = () => {
|
|
142
|
+
if (settled)
|
|
143
|
+
return;
|
|
144
|
+
settled = true;
|
|
145
|
+
child.off("error", handleTerminalError);
|
|
146
|
+
child.off("close", settleTerminal);
|
|
147
|
+
this.pendingChildTerminals.delete(terminalPromise);
|
|
148
|
+
resolveTerminal();
|
|
149
|
+
};
|
|
150
|
+
const handleTerminalError = () => {
|
|
151
|
+
if (!child.pid)
|
|
152
|
+
settleTerminal();
|
|
153
|
+
};
|
|
154
|
+
this.pendingChildTerminals.add(terminalPromise);
|
|
155
|
+
child.on("error", handleTerminalError);
|
|
156
|
+
child.once("close", settleTerminal);
|
|
157
|
+
}
|
|
110
158
|
clear(child) {
|
|
111
159
|
if (this.currentChild !== child)
|
|
112
160
|
return false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"persistent-process-coordinator.js","sourceRoot":"","sources":["../../../src/core/tools/persistent-process-coordinator.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shared lifecycle owner for one serialized, persistent child process.\n *\n * Wire protocols, state projection, and respawn policy stay with their concrete shell adapters.\n * This boundary owns only the invariant OS mechanics: one active task, one tracked child, stale\n * event rejection, exit/close arbitration, whole-tree kill, loop references, and parent exit.\n */\n\nimport type { ChildProcess } from \"node:child_process\";\nimport { setChildProcessLoopRef } from \"../../utils/child-process-ref.ts\";\nimport { killProcessTree, trackDetachedChildPid, untrackDetachedChildPid } from \"../../utils/shell.ts\";\n\nexport interface PersistentChildHandlers {\n\tonStdout(data: Buffer): void;\n\tonStderr(data: Buffer): void;\n\tonError(error: Error): void;\n\tonClose(code: number | null): void;\n}\n\nconst liveCoordinators = new Set<PersistentProcessCoordinator>();\nlet exitHookInstalled = false;\n\nfunction installExitHook(): void {\n\tif (exitHookInstalled) return;\n\texitHookInstalled = true;\n\tprocess.on(\"exit\", () => {\n\t\tfor (const coordinator of liveCoordinators) coordinator.killForProcessExit();\n\t});\n}\n\nexport class PersistentProcessCoordinator {\n\tprivate currentChild: ChildProcess | null = null;\n\tprivate queue: Promise<void> = Promise.resolve();\n\tprivate disposed = false;\n\n\tconstructor() {\n\t\tinstallExitHook();\n\t\tliveCoordinators.add(this);\n\t}\n\n\tget child(): ChildProcess | null {\n\t\treturn this.currentChild;\n\t}\n\n\trunSerialized<T>(task: () => Promise<T>): Promise<T> {\n\t\tconst run = this.queue.then(task);\n\t\tthis.queue = run.then(\n\t\t\t() => undefined,\n\t\t\t() => undefined,\n\t\t);\n\t\treturn run;\n\t}\n\n\tattach(child: ChildProcess, handlers: PersistentChildHandlers): void {\n\t\tif (this.disposed) {\n\t\t\tif (child.pid) killProcessTree(child.pid);\n\t\t\tthrow new Error(\"Persistent process coordinator is disposed\");\n\t\t}\n\t\tif (this.currentChild) throw new Error(\"Persistent process coordinator already owns a child\");\n\t\tthis.currentChild = child;\n\t\tif (child.pid) trackDetachedChildPid(child.pid);\n\n\t\tchild.stdout?.on(\"data\", (data: Buffer) => {\n\t\t\tif (this.currentChild === child) handlers.onStdout(data);\n\t\t});\n\t\tchild.stderr?.on(\"data\", (data: Buffer) => {\n\t\t\tif (this.currentChild === child) handlers.onStderr(data);\n\t\t});\n\t\tchild.on(\"error\", (error) => {\n\t\t\tif (!this.clear(child)) return;\n\t\t\thandlers.onError(error instanceof Error ? error : new Error(String(error)));\n\t\t});\n\t\tlet exitCode: number | null = null;\n\t\tlet fallbackTimer: ReturnType<typeof setTimeout> | undefined;\n\n\t\tchild.on(\"exit\", (code) => {\n\t\t\tif (this.currentChild !== child) return;\n\t\t\texitCode = code;\n\t\t\tfallbackTimer = setTimeout(() => {\n\t\t\t\tif (!this.clear(child)) return;\n\t\t\t\thandlers.onClose(exitCode);\n\t\t\t}, 2_000);\n\t\t\tif (typeof fallbackTimer === \"object\" && fallbackTimer && \"unref\" in fallbackTimer) {\n\t\t\t\tfallbackTimer.unref();\n\t\t\t}\n\t\t});\n\n\t\tchild.on(\"close\", (code) => {\n\t\t\tif (fallbackTimer) clearTimeout(fallbackTimer);\n\t\t\tif (!this.clear(child)) return;\n\t\t\thandlers.onClose(code ?? exitCode);\n\t\t});\n\t}\n\n\tkill(): void {\n\t\tconst child = this.currentChild;\n\t\tif (!child) return;\n\t\tthis.clear(child);\n\t\tif (child.pid) killProcessTree(child.pid);\n\t}\n\n\tdispose(): void {\n\t\tif (this.disposed) return;\n\t\tthis.disposed = true;\n\t\tliveCoordinators.delete(this);\n\t\tthis.kill();\n\t}\n\n\t/** Synchronous best-effort tree kill for the process exit hook. */\n\tkillForProcessExit(): void {\n\t\tthis.kill();\n\t}\n\n\t/** Idle coordinators must not keep one-shot Node modes alive; active commands must. */\n\tsetLoopRef(active: boolean): void {\n\t\tconst child = this.currentChild;\n\t\tif (!child) return;\n\t\tsetChildProcessLoopRef(child, active);\n\t}\n\n\tprivate clear(child: ChildProcess): boolean {\n\t\tif (this.currentChild !== child) return false;\n\t\tif (child.pid) untrackDetachedChildPid(child.pid);\n\t\tthis.currentChild = null;\n\t\treturn true;\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"persistent-process-coordinator.js","sourceRoot":"","sources":["../../../src/core/tools/persistent-process-coordinator.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shared lifecycle owner for one serialized, persistent child process.\n *\n * Wire protocols, state projection, and respawn policy stay with their concrete shell adapters.\n * This boundary owns only the invariant OS mechanics: one active task, one current child, every\n * outstanding child terminal, stale event rejection, exit/close arbitration, whole-tree kill,\n * loop references, and parent exit.\n */\n\nimport type { ChildProcess } from \"node:child_process\";\nimport { setChildProcessLoopRef } from \"../../utils/child-process-ref.ts\";\nimport { killProcessTree, trackDetachedChildPid, untrackDetachedChildPid } from \"../../utils/shell.ts\";\n\nexport interface PersistentChildHandlers {\n\tonStdout(data: Buffer): void;\n\tonStderr(data: Buffer): void;\n\tonError(error: Error): void;\n\tonClose(code: number | null): void;\n}\n\nconst liveCoordinators = new Set<PersistentProcessCoordinator>();\nlet exitHookInstalled = false;\n\nfunction installExitHook(): void {\n\tif (exitHookInstalled) return;\n\texitHookInstalled = true;\n\tprocess.on(\"exit\", () => {\n\t\tfor (const coordinator of liveCoordinators) coordinator.killForProcessExit();\n\t});\n}\n\nexport class PersistentProcessCoordinator {\n\tprivate currentChild: ChildProcess | null = null;\n\tprivate readonly pendingChildTerminals = new Set<Promise<void>>();\n\tprivate queue: Promise<void> = Promise.resolve();\n\tprivate disposed = false;\n\n\tconstructor() {\n\t\tinstallExitHook();\n\t\tliveCoordinators.add(this);\n\t}\n\n\tget child(): ChildProcess | null {\n\t\treturn this.currentChild;\n\t}\n\n\tget terminalPromise(): Promise<void> {\n\t\treturn this.waitForTerminalRelease();\n\t}\n\n\trunSerialized<T>(task: () => Promise<T>): Promise<T> {\n\t\tconst run = this.queue.then(task);\n\t\tthis.queue = run.then(\n\t\t\t() => undefined,\n\t\t\t() => undefined,\n\t\t);\n\t\treturn run;\n\t}\n\n\tattach(child: ChildProcess, handlers: PersistentChildHandlers): void {\n\t\tif (this.disposed) {\n\t\t\tthis.trackTerminal(child);\n\t\t\tthis.terminateChild(child);\n\t\t\tthrow new Error(\"Persistent process coordinator is disposed\");\n\t\t}\n\t\tif (this.currentChild) throw new Error(\"Persistent process coordinator already owns a child\");\n\t\tthis.currentChild = child;\n\t\tif (child.pid) trackDetachedChildPid(child.pid);\n\t\tthis.trackTerminal(child);\n\n\t\tchild.stdout?.on(\"data\", (data: Buffer) => {\n\t\t\tif (this.currentChild === child) handlers.onStdout(data);\n\t\t});\n\t\tchild.stderr?.on(\"data\", (data: Buffer) => {\n\t\t\tif (this.currentChild === child) handlers.onStderr(data);\n\t\t});\n\t\tchild.on(\"error\", (error) => {\n\t\t\tif (!this.clear(child)) return;\n\t\t\thandlers.onError(error instanceof Error ? error : new Error(String(error)));\n\t\t});\n\t\tlet exitCode: number | null = null;\n\t\tlet fallbackTimer: ReturnType<typeof setTimeout> | undefined;\n\n\t\tchild.on(\"exit\", (code) => {\n\t\t\tif (this.currentChild !== child) return;\n\t\t\texitCode = code;\n\t\t\tfallbackTimer = setTimeout(() => {\n\t\t\t\tif (!this.clear(child)) return;\n\t\t\t\thandlers.onClose(exitCode);\n\t\t\t}, 2_000);\n\t\t\tif (typeof fallbackTimer === \"object\" && fallbackTimer && \"unref\" in fallbackTimer) {\n\t\t\t\tfallbackTimer.unref();\n\t\t\t}\n\t\t});\n\n\t\tchild.on(\"close\", (code) => {\n\t\t\tif (fallbackTimer) clearTimeout(fallbackTimer);\n\t\t\tif (!this.clear(child)) return;\n\t\t\thandlers.onClose(code ?? exitCode);\n\t\t});\n\t}\n\n\tkill(): void {\n\t\tconst child = this.currentChild;\n\t\tif (!child) return;\n\t\tthis.clear(child);\n\t\tthis.terminateChild(child);\n\t}\n\n\tprivate terminateChild(child: ChildProcess): void {\n\t\t// Bun's Windows child-process bridge can stop publishing terminal events after every\n\t\t// handle has been unref'd. Re-arm the already-installed close observer before killing so\n\t\t// strict teardown can distinguish physical handle release from process exit.\n\t\tsetChildProcessLoopRef(child, true);\n\t\tif (child.pid) killProcessTree(child.pid);\n\t\ttry {\n\t\t\tchild.kill();\n\t\t} catch {\n\t\t\t// Process already dead\n\t\t}\n\t}\n\n\tdispose(): void {\n\t\tif (this.disposed) return;\n\t\tthis.disposed = true;\n\t\tliveCoordinators.delete(this);\n\t\tthis.kill();\n\t}\n\n\t/** Synchronous best-effort tree kill for the process exit hook. */\n\tkillForProcessExit(): void {\n\t\tthis.kill();\n\t}\n\n\t/** Idle coordinators must not keep one-shot Node modes alive; active commands must. */\n\tsetLoopRef(active: boolean): void {\n\t\tconst child = this.currentChild;\n\t\tif (!child) return;\n\t\tsetChildProcessLoopRef(child, active);\n\t}\n\n\tprivate async waitForTerminalRelease(): Promise<void> {\n\t\tawait this.queue;\n\t\twhile (this.pendingChildTerminals.size > 0) {\n\t\t\tawait Promise.all(Array.from(this.pendingChildTerminals));\n\t\t}\n\t}\n\n\tprivate trackTerminal(child: ChildProcess): void {\n\t\tlet settled = false;\n\t\tlet resolveTerminal: () => void;\n\t\tconst terminalPromise = new Promise<void>((resolve) => {\n\t\t\tresolveTerminal = resolve;\n\t\t});\n\t\tconst settleTerminal = () => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tchild.off(\"error\", handleTerminalError);\n\t\t\tchild.off(\"close\", settleTerminal);\n\t\t\tthis.pendingChildTerminals.delete(terminalPromise);\n\t\t\tresolveTerminal();\n\t\t};\n\t\tconst handleTerminalError = () => {\n\t\t\tif (!child.pid) settleTerminal();\n\t\t};\n\n\t\tthis.pendingChildTerminals.add(terminalPromise);\n\t\tchild.on(\"error\", handleTerminalError);\n\t\tchild.once(\"close\", settleTerminal);\n\t}\n\n\tprivate clear(child: ChildProcess): boolean {\n\t\tif (this.currentChild !== child) return false;\n\t\tif (child.pid) untrackDetachedChildPid(child.pid);\n\t\tthis.currentChild = null;\n\t\treturn true;\n\t}\n}\n"]}
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
/** One production lifecycle boundary for every process/state resource owned by a shell session. */
|
|
2
|
-
|
|
2
|
+
export declare const SHELL_EXECUTION_DISPOSAL_WATCHDOG_MS = 5000;
|
|
3
|
+
/** Synchronously dispose both execution tiers and their shared authoritative Windows state. */
|
|
3
4
|
export declare function disposeShellExecutionSession(sessionKey: string): void;
|
|
5
|
+
/**
|
|
6
|
+
* Awaitable disposal that guarantees child processes in both execution tiers have reached
|
|
7
|
+
* physical terminal close before resolving. Concurrent callers for the same sessionKey share
|
|
8
|
+
* the identical pending wait promise.
|
|
9
|
+
*/
|
|
10
|
+
export declare function disposeShellExecutionSessionAndWait(sessionKey: string, timeoutMs?: number): Promise<void>;
|
|
4
11
|
//# sourceMappingURL=shell-execution-session.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shell-execution-session.d.ts","sourceRoot":"","sources":["../../../src/core/tools/shell-execution-session.ts"],"names":[],"mappings":"AAAA,mGAAmG;
|
|
1
|
+
{"version":3,"file":"shell-execution-session.d.ts","sourceRoot":"","sources":["../../../src/core/tools/shell-execution-session.ts"],"names":[],"mappings":"AAAA,mGAAmG;AASnG,eAAO,MAAM,oCAAoC,OAAQ,CAAC;AAE1D,+FAA+F;AAC/F,wBAAgB,4BAA4B,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAerE;AAUD;;;;GAIG;AACH,wBAAgB,mCAAmC,CAClD,UAAU,EAAE,MAAM,EAClB,SAAS,GAAE,MAA6C,GACtD,OAAO,CAAC,IAAI,CAAC,CA8Bf"}
|
|
@@ -2,10 +2,61 @@
|
|
|
2
2
|
import { disposePersistentShellSession } from "./shell-session.js";
|
|
3
3
|
import { disposeWindowsShellEngineSession } from "./windows-shell-engine.js";
|
|
4
4
|
import { disposeWindowsShellState } from "./windows-shell-state.js";
|
|
5
|
-
|
|
5
|
+
const inFlightTerminalPromises = new Map();
|
|
6
|
+
const inFlightDisposalWaits = new Map();
|
|
7
|
+
export const SHELL_EXECUTION_DISPOSAL_WATCHDOG_MS = 5_000;
|
|
8
|
+
/** Synchronously dispose both execution tiers and their shared authoritative Windows state. */
|
|
6
9
|
export function disposeShellExecutionSession(sessionKey) {
|
|
7
|
-
disposeWindowsShellEngineSession(sessionKey);
|
|
8
|
-
disposePersistentShellSession(sessionKey);
|
|
9
10
|
disposeWindowsShellState(sessionKey);
|
|
11
|
+
const p1 = disposeWindowsShellEngineSession(sessionKey);
|
|
12
|
+
const p2 = disposePersistentShellSession(sessionKey);
|
|
13
|
+
const previous = inFlightTerminalPromises.get(sessionKey);
|
|
14
|
+
const combined = Promise.all([previous ?? Promise.resolve(), p1, p2])
|
|
15
|
+
.then(() => undefined)
|
|
16
|
+
.finally(() => {
|
|
17
|
+
if (inFlightTerminalPromises.get(sessionKey) === combined) {
|
|
18
|
+
inFlightTerminalPromises.delete(sessionKey);
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
inFlightTerminalPromises.set(sessionKey, combined);
|
|
22
|
+
}
|
|
23
|
+
async function drainTerminalPromises(sessionKey) {
|
|
24
|
+
while (true) {
|
|
25
|
+
const terminalPromise = inFlightTerminalPromises.get(sessionKey);
|
|
26
|
+
if (!terminalPromise)
|
|
27
|
+
return;
|
|
28
|
+
await terminalPromise;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Awaitable disposal that guarantees child processes in both execution tiers have reached
|
|
33
|
+
* physical terminal close before resolving. Concurrent callers for the same sessionKey share
|
|
34
|
+
* the identical pending wait promise.
|
|
35
|
+
*/
|
|
36
|
+
export function disposeShellExecutionSessionAndWait(sessionKey, timeoutMs = SHELL_EXECUTION_DISPOSAL_WATCHDOG_MS) {
|
|
37
|
+
disposeShellExecutionSession(sessionKey);
|
|
38
|
+
const existing = inFlightDisposalWaits.get(sessionKey);
|
|
39
|
+
if (existing)
|
|
40
|
+
return existing;
|
|
41
|
+
let watchdogTimer;
|
|
42
|
+
const watchdogPromise = new Promise((_, reject) => {
|
|
43
|
+
watchdogTimer = setTimeout(() => {
|
|
44
|
+
reject(new Error(`Shell execution session terminal release timed out after ${timeoutMs}ms before child close event`));
|
|
45
|
+
}, timeoutMs);
|
|
46
|
+
if (typeof watchdogTimer === "object" && watchdogTimer && "unref" in watchdogTimer) {
|
|
47
|
+
watchdogTimer.unref();
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
const waitPromise = Promise.race([drainTerminalPromises(sessionKey), watchdogPromise])
|
|
51
|
+
.then(() => undefined)
|
|
52
|
+
.finally(() => {
|
|
53
|
+
if (watchdogTimer)
|
|
54
|
+
clearTimeout(watchdogTimer);
|
|
55
|
+
if (inFlightDisposalWaits.get(sessionKey) === waitPromise) {
|
|
56
|
+
inFlightDisposalWaits.delete(sessionKey);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
inFlightDisposalWaits.set(sessionKey, waitPromise);
|
|
60
|
+
return waitPromise;
|
|
10
61
|
}
|
|
11
62
|
//# sourceMappingURL=shell-execution-session.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shell-execution-session.js","sourceRoot":"","sources":["../../../src/core/tools/shell-execution-session.ts"],"names":[],"mappings":"AAAA,mGAAmG;AAEnG,OAAO,EAAE,6BAA6B,EAAE,MAAM,oBAAoB,CAAC;AACnE,OAAO,EAAE,gCAAgC,EAAE,MAAM,2BAA2B,CAAC;AAC7E,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AAEpE,
|
|
1
|
+
{"version":3,"file":"shell-execution-session.js","sourceRoot":"","sources":["../../../src/core/tools/shell-execution-session.ts"],"names":[],"mappings":"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","sourcesContent":["/** One production lifecycle boundary for every process/state resource owned by a shell session. */\n\nimport { disposePersistentShellSession } from \"./shell-session.ts\";\nimport { disposeWindowsShellEngineSession } from \"./windows-shell-engine.ts\";\nimport { disposeWindowsShellState } from \"./windows-shell-state.ts\";\n\nconst inFlightTerminalPromises = new Map<string, Promise<void>>();\nconst inFlightDisposalWaits = new Map<string, Promise<void>>();\n\nexport const SHELL_EXECUTION_DISPOSAL_WATCHDOG_MS = 5_000;\n\n/** Synchronously dispose both execution tiers and their shared authoritative Windows state. */\nexport function disposeShellExecutionSession(sessionKey: string): void {\n\tdisposeWindowsShellState(sessionKey);\n\tconst p1 = disposeWindowsShellEngineSession(sessionKey);\n\tconst p2 = disposePersistentShellSession(sessionKey);\n\n\tconst previous = inFlightTerminalPromises.get(sessionKey);\n\tconst combined = Promise.all([previous ?? Promise.resolve(), p1, p2])\n\t\t.then(() => undefined)\n\t\t.finally(() => {\n\t\t\tif (inFlightTerminalPromises.get(sessionKey) === combined) {\n\t\t\t\tinFlightTerminalPromises.delete(sessionKey);\n\t\t\t}\n\t\t});\n\n\tinFlightTerminalPromises.set(sessionKey, combined);\n}\n\nasync function drainTerminalPromises(sessionKey: string): Promise<void> {\n\twhile (true) {\n\t\tconst terminalPromise = inFlightTerminalPromises.get(sessionKey);\n\t\tif (!terminalPromise) return;\n\t\tawait terminalPromise;\n\t}\n}\n\n/**\n * Awaitable disposal that guarantees child processes in both execution tiers have reached\n * physical terminal close before resolving. Concurrent callers for the same sessionKey share\n * the identical pending wait promise.\n */\nexport function disposeShellExecutionSessionAndWait(\n\tsessionKey: string,\n\ttimeoutMs: number = SHELL_EXECUTION_DISPOSAL_WATCHDOG_MS,\n): Promise<void> {\n\tdisposeShellExecutionSession(sessionKey);\n\tconst existing = inFlightDisposalWaits.get(sessionKey);\n\tif (existing) return existing;\n\n\tlet watchdogTimer: ReturnType<typeof setTimeout> | undefined;\n\tconst watchdogPromise = new Promise<void>((_, reject) => {\n\t\twatchdogTimer = setTimeout(() => {\n\t\t\treject(\n\t\t\t\tnew Error(\n\t\t\t\t\t`Shell execution session terminal release timed out after ${timeoutMs}ms before child close event`,\n\t\t\t\t),\n\t\t\t);\n\t\t}, timeoutMs);\n\t\tif (typeof watchdogTimer === \"object\" && watchdogTimer && \"unref\" in watchdogTimer) {\n\t\t\twatchdogTimer.unref();\n\t\t}\n\t});\n\n\tconst waitPromise = Promise.race([drainTerminalPromises(sessionKey), watchdogPromise])\n\t\t.then(() => undefined)\n\t\t.finally(() => {\n\t\t\tif (watchdogTimer) clearTimeout(watchdogTimer);\n\t\t\tif (inFlightDisposalWaits.get(sessionKey) === waitPromise) {\n\t\t\t\tinFlightDisposalWaits.delete(sessionKey);\n\t\t\t}\n\t\t});\n\n\tinFlightDisposalWaits.set(sessionKey, waitPromise);\n\treturn waitPromise;\n}\n"]}
|
|
@@ -81,6 +81,7 @@ export declare class PersistentShellSession {
|
|
|
81
81
|
}>;
|
|
82
82
|
/** Start and validate the long-lived shell before the first user command. Idempotent per session. */
|
|
83
83
|
prewarm(cwd: string, env?: NodeJS.ProcessEnv): Promise<void>;
|
|
84
|
+
get terminalPromise(): Promise<void>;
|
|
84
85
|
dispose(): void;
|
|
85
86
|
private execNow;
|
|
86
87
|
private spawnChild;
|
|
@@ -93,5 +94,5 @@ export declare class PersistentShellSession {
|
|
|
93
94
|
/** Get or lazily create the persistent session for a key. A kind change replaces the session. */
|
|
94
95
|
export declare function acquirePersistentShellSession(key: string, kind: PlatformShellToolName): PersistentShellSession;
|
|
95
96
|
/** Kill and forget a session (agent teardown). Safe to call for keys that never spawned. */
|
|
96
|
-
export declare function disposePersistentShellSession(key: string): void
|
|
97
|
+
export declare function disposePersistentShellSession(key: string): Promise<void>;
|
|
97
98
|
//# sourceMappingURL=shell-session.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shell-session.d.ts","sourceRoot":"","sources":["../../../src/core/tools/shell-session.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAKH,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,YAAY,EAAS,MAAM,eAAe,CAAC;AAS5E,OAAO,EAIN,KAAK,qBAAqB,EAE1B,KAAK,WAAW,EAChB,MAAM,sBAAsB,CAAC;AAI9B,OAAO,EACN,+BAA+B,EAC/B,sCAAsC,GACtC,MAAM,4CAA4C,CAAC;AAQpD,MAAM,WAAW,uBAAuB;IACvC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,kGAAkG;IAClG,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gGAAgG;IAChG,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACxB;AAED,MAAM,WAAW,6BAA6B;IAC7C,2BAA2B,CAAC,EAAE,MAAM,WAAW,EAAE,CAAC;IAClD,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,YAAY,KAAK,YAAY,CAAC;IACjF,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC1B;AAUD;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAazF;AA6ED,iHAAiH;AACjH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAK/F;AA8CD,qBAAa,sBAAsB;IAClC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAwB;IAC7C,OAAO,CAAC,QAAQ,CAAC,2BAA2B,CAAsB;IAClE,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA2E;IACxG,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAsC;IAClE,OAAO,CAAC,QAAQ,CAAkC;IAClD,OAAO,CAAC,gBAAgB,CAAuB;IAC/C,OAAO,CAAC,UAAU,CAA2B;IAC7C,OAAO,CAAC,aAAa,CAAyC;IAC9D,OAAO,CAAC,QAAQ,CAAS;IAEzB,YAAY,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,qBAAqB,EAAE,OAAO,GAAE,6BAAkC,EAMhG;IAED,IAAI,WAAW,IAAI,qBAAqB,CAEvC;IAED,4FAA4F;IAC5F,IAAI,CACH,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,uBAAuB,GAC9B,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAEpD;IAED,qGAAqG;IACrG,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,GAAE,MAAM,CAAC,UAA0B,GAAG,OAAO,CAAC,IAAI,CAAC,CA0B1E;IAED,OAAO,IAAI,IAAI,CAOd;YAEa,OAAO;YAqMP,UAAU;YAqBV,oBAAoB;IA2BlC,OAAO,CAAC,wBAAwB;IA2FhC,OAAO,CAAC,gBAAgB;IAexB,OAAO,CAAC,eAAe;IAKvB,OAAO,CAAC,SAAS;CAIjB;
|
|
1
|
+
{"version":3,"file":"shell-session.d.ts","sourceRoot":"","sources":["../../../src/core/tools/shell-session.ts"],"names":[],"mappings":"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"}
|
|
@@ -215,6 +215,9 @@ export class PersistentShellSession {
|
|
|
215
215
|
this.coordinator.setLoopRef(false);
|
|
216
216
|
});
|
|
217
217
|
}
|
|
218
|
+
get terminalPromise() {
|
|
219
|
+
return this.coordinator.terminalPromise;
|
|
220
|
+
}
|
|
218
221
|
dispose() {
|
|
219
222
|
if (this.disposed)
|
|
220
223
|
return;
|
|
@@ -580,12 +583,28 @@ export class PersistentShellSession {
|
|
|
580
583
|
}
|
|
581
584
|
}
|
|
582
585
|
const shellSessions = new Map();
|
|
586
|
+
const retiredShellSessionTerminals = new Map();
|
|
587
|
+
function retainShellSessionTerminal(key, terminalPromise) {
|
|
588
|
+
const previous = retiredShellSessionTerminals.get(key);
|
|
589
|
+
const combined = Promise.all([previous ?? Promise.resolve(), terminalPromise])
|
|
590
|
+
.then(() => undefined)
|
|
591
|
+
.finally(() => {
|
|
592
|
+
if (retiredShellSessionTerminals.get(key) === combined) {
|
|
593
|
+
retiredShellSessionTerminals.delete(key);
|
|
594
|
+
}
|
|
595
|
+
});
|
|
596
|
+
retiredShellSessionTerminals.set(key, combined);
|
|
597
|
+
return combined;
|
|
598
|
+
}
|
|
583
599
|
/** Get or lazily create the persistent session for a key. A kind change replaces the session. */
|
|
584
600
|
export function acquirePersistentShellSession(key, kind) {
|
|
585
601
|
const existing = shellSessions.get(key);
|
|
586
602
|
if (existing && existing.sessionKind === kind)
|
|
587
603
|
return existing;
|
|
588
|
-
existing
|
|
604
|
+
if (existing) {
|
|
605
|
+
existing.dispose();
|
|
606
|
+
retainShellSessionTerminal(key, existing.terminalPromise);
|
|
607
|
+
}
|
|
589
608
|
const session = new PersistentShellSession(key, kind);
|
|
590
609
|
shellSessions.set(key, session);
|
|
591
610
|
return session;
|
|
@@ -594,8 +613,9 @@ export function acquirePersistentShellSession(key, kind) {
|
|
|
594
613
|
export function disposePersistentShellSession(key) {
|
|
595
614
|
const session = shellSessions.get(key);
|
|
596
615
|
if (!session)
|
|
597
|
-
return;
|
|
616
|
+
return retiredShellSessionTerminals.get(key) ?? Promise.resolve();
|
|
598
617
|
shellSessions.delete(key);
|
|
599
618
|
session.dispose();
|
|
619
|
+
return retainShellSessionTerminal(key, session.terminalPromise);
|
|
600
620
|
}
|
|
601
621
|
//# sourceMappingURL=shell-session.js.map
|