@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.
Files changed (77) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/dist/bundled-resources/skills/n-plus-2-architecture/SKILL.md +13 -0
  3. package/dist/core/agent-session.d.ts.map +1 -1
  4. package/dist/core/agent-session.js +5 -20
  5. package/dist/core/agent-session.js.map +1 -1
  6. package/dist/core/autonomy/envelope-enforcement.d.ts +3 -1
  7. package/dist/core/autonomy/envelope-enforcement.d.ts.map +1 -1
  8. package/dist/core/autonomy/envelope-enforcement.js +23 -12
  9. package/dist/core/autonomy/envelope-enforcement.js.map +1 -1
  10. package/dist/core/autonomy/gates.d.ts.map +1 -1
  11. package/dist/core/autonomy/gates.js +24 -26
  12. package/dist/core/autonomy/gates.js.map +1 -1
  13. package/dist/core/context-gc.d.ts.map +1 -1
  14. package/dist/core/context-gc.js +128 -3
  15. package/dist/core/context-gc.js.map +1 -1
  16. package/dist/core/session-shutdown.d.ts +9 -0
  17. package/dist/core/session-shutdown.d.ts.map +1 -0
  18. package/dist/core/session-shutdown.js +44 -0
  19. package/dist/core/session-shutdown.js.map +1 -0
  20. package/dist/core/settings-manager.js.map +1 -1
  21. package/dist/core/skill-vault.d.ts +6 -2
  22. package/dist/core/skill-vault.d.ts.map +1 -1
  23. package/dist/core/skill-vault.js +30 -12
  24. package/dist/core/skill-vault.js.map +1 -1
  25. package/dist/core/system-prompt.d.ts.map +1 -1
  26. package/dist/core/system-prompt.js +7 -18
  27. package/dist/core/system-prompt.js.map +1 -1
  28. package/dist/core/tools/bash.d.ts.map +1 -1
  29. package/dist/core/tools/bash.js +2 -3
  30. package/dist/core/tools/bash.js.map +1 -1
  31. package/dist/core/tools/edit.d.ts.map +1 -1
  32. package/dist/core/tools/edit.js +86 -33
  33. package/dist/core/tools/edit.js.map +1 -1
  34. package/dist/core/tools/file-mutation-intent.d.ts +16 -0
  35. package/dist/core/tools/file-mutation-intent.d.ts.map +1 -1
  36. package/dist/core/tools/file-mutation-intent.js +51 -2
  37. package/dist/core/tools/file-mutation-intent.js.map +1 -1
  38. package/dist/core/tools/persistent-process-coordinator.d.ts +8 -2
  39. package/dist/core/tools/persistent-process-coordinator.d.ts.map +1 -1
  40. package/dist/core/tools/persistent-process-coordinator.js +52 -4
  41. package/dist/core/tools/persistent-process-coordinator.js.map +1 -1
  42. package/dist/core/tools/shell-execution-session.d.ts +8 -1
  43. package/dist/core/tools/shell-execution-session.d.ts.map +1 -1
  44. package/dist/core/tools/shell-execution-session.js +54 -3
  45. package/dist/core/tools/shell-execution-session.js.map +1 -1
  46. package/dist/core/tools/shell-session.d.ts +2 -1
  47. package/dist/core/tools/shell-session.d.ts.map +1 -1
  48. package/dist/core/tools/shell-session.js +22 -2
  49. package/dist/core/tools/shell-session.js.map +1 -1
  50. package/dist/core/tools/skill.d.ts +1 -0
  51. package/dist/core/tools/skill.d.ts.map +1 -1
  52. package/dist/core/tools/skill.js +11 -6
  53. package/dist/core/tools/skill.js.map +1 -1
  54. package/dist/core/tools/windows-shell-engine.d.ts +1 -1
  55. package/dist/core/tools/windows-shell-engine.d.ts.map +1 -1
  56. package/dist/core/tools/windows-shell-engine.js +6 -2
  57. package/dist/core/tools/windows-shell-engine.js.map +1 -1
  58. package/dist/index.d.ts +1 -1
  59. package/dist/index.d.ts.map +1 -1
  60. package/dist/index.js +1 -1
  61. package/dist/index.js.map +1 -1
  62. package/dist/modes/interactive/components/settings-selector.js +2 -2
  63. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  64. package/dist/utils/shell.d.ts +3 -5
  65. package/dist/utils/shell.d.ts.map +1 -1
  66. package/dist/utils/shell.js +4 -7
  67. package/dist/utils/shell.js.map +1 -1
  68. package/docs/settings.md +7 -7
  69. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  70. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  71. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  72. package/examples/extensions/sandbox/package-lock.json +2 -2
  73. package/examples/extensions/sandbox/package.json +1 -1
  74. package/examples/extensions/with-deps/package-lock.json +2 -2
  75. package/examples/extensions/with-deps/package.json +1 -1
  76. package/npm-shrinkwrap.json +12 -12
  77. 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 tracked child, stale
6
- * event rejection, exit/close arbitration, whole-tree kill, loop references, and parent exit.
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;;;;;;GAMG;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,KAAK,CAAoC;IACjD,OAAO,CAAC,QAAQ,CAAS;IAEzB,cAGC;IAED,IAAI,KAAK,IAAI,YAAY,GAAG,IAAI,CAE/B;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,CAuCnE;IAED,IAAI,IAAI,IAAI,CAKX;IAED,OAAO,IAAI,IAAI,CAKd;IAED,mEAAmE;IACnE,kBAAkB,IAAI,IAAI,CAEzB;IAED,uFAAuF;IACvF,UAAU,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAIhC;IAED,OAAO,CAAC,KAAK;CAMb"}
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 tracked child, stale
6
- * event rejection, exit/close arbitration, whole-tree kill, loop references, and parent exit.
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
- if (child.pid)
40
- killProcessTree(child.pid);
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":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAC1E,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AASvG,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAAgC,CAAC;AACjE,IAAI,iBAAiB,GAAG,KAAK,CAAC;AAE9B,SAAS,eAAe;IACvB,IAAI,iBAAiB;QAAE,OAAO;IAC9B,iBAAiB,GAAG,IAAI,CAAC;IACzB,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE;QACvB,KAAK,MAAM,WAAW,IAAI,gBAAgB;YAAE,WAAW,CAAC,kBAAkB,EAAE,CAAC;IAC9E,CAAC,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,OAAO,4BAA4B;IAMxC;QALQ,iBAAY,GAAwB,IAAI,CAAC;QAChC,0BAAqB,GAAG,IAAI,GAAG,EAAiB,CAAC;QAC1D,UAAK,GAAkB,OAAO,CAAC,OAAO,EAAE,CAAC;QACzC,aAAQ,GAAG,KAAK,CAAC;QAGxB,eAAe,EAAE,CAAC;QAClB,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAED,IAAI,KAAK;QACR,OAAO,IAAI,CAAC,YAAY,CAAC;IAC1B,CAAC;IAED,IAAI,eAAe;QAClB,OAAO,IAAI,CAAC,sBAAsB,EAAE,CAAC;IACtC,CAAC;IAED,aAAa,CAAI,IAAsB;QACtC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClC,IAAI,CAAC,KAAK,GAAG,GAAG,CAAC,IAAI,CACpB,GAAG,EAAE,CAAC,SAAS,EACf,GAAG,EAAE,CAAC,SAAS,CACf,CAAC;QACF,OAAO,GAAG,CAAC;IACZ,CAAC;IAED,MAAM,CAAC,KAAmB,EAAE,QAAiC;QAC5D,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACnB,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;YAC1B,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;YAC3B,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;QAC/D,CAAC;QACD,IAAI,IAAI,CAAC,YAAY;YAAE,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;QAC9F,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC;QAC1B,IAAI,KAAK,CAAC,GAAG;YAAE,qBAAqB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAChD,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QAE1B,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE;YACzC,IAAI,IAAI,CAAC,YAAY,KAAK,KAAK;gBAAE,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC1D,CAAC,CAAC,CAAC;QACH,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE;YACzC,IAAI,IAAI,CAAC,YAAY,KAAK,KAAK;gBAAE,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC1D,CAAC,CAAC,CAAC;QACH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;YAC3B,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;gBAAE,OAAO;YAC/B,QAAQ,CAAC,OAAO,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC7E,CAAC,CAAC,CAAC;QACH,IAAI,QAAQ,GAAkB,IAAI,CAAC;QACnC,IAAI,aAAwD,CAAC;QAE7D,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;YACzB,IAAI,IAAI,CAAC,YAAY,KAAK,KAAK;gBAAE,OAAO;YACxC,QAAQ,GAAG,IAAI,CAAC;YAChB,aAAa,GAAG,UAAU,CAAC,GAAG,EAAE;gBAC/B,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;oBAAE,OAAO;gBAC/B,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;YAC5B,CAAC,EAAE,KAAK,CAAC,CAAC;YACV,IAAI,OAAO,aAAa,KAAK,QAAQ,IAAI,aAAa,IAAI,OAAO,IAAI,aAAa,EAAE,CAAC;gBACpF,aAAa,CAAC,KAAK,EAAE,CAAC;YACvB,CAAC;QACF,CAAC,CAAC,CAAC;QAEH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;YAC1B,IAAI,aAAa;gBAAE,YAAY,CAAC,aAAa,CAAC,CAAC;YAC/C,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;gBAAE,OAAO;YAC/B,QAAQ,CAAC,OAAO,CAAC,IAAI,IAAI,QAAQ,CAAC,CAAC;QACpC,CAAC,CAAC,CAAC;IACJ,CAAC;IAED,IAAI;QACH,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC;QAChC,IAAI,CAAC,KAAK;YAAE,OAAO;QACnB,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAClB,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;IAC5B,CAAC;IAEO,cAAc,CAAC,KAAmB;QACzC,qFAAqF;QACrF,yFAAyF;QACzF,6EAA6E;QAC7E,sBAAsB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QACpC,IAAI,KAAK,CAAC,GAAG;YAAE,eAAe,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC1C,IAAI,CAAC;YACJ,KAAK,CAAC,IAAI,EAAE,CAAC;QACd,CAAC;QAAC,MAAM,CAAC;YACR,uBAAuB;QACxB,CAAC;IACF,CAAC;IAED,OAAO;QACN,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO;QAC1B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,gBAAgB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC9B,IAAI,CAAC,IAAI,EAAE,CAAC;IACb,CAAC;IAED,mEAAmE;IACnE,kBAAkB;QACjB,IAAI,CAAC,IAAI,EAAE,CAAC;IACb,CAAC;IAED,uFAAuF;IACvF,UAAU,CAAC,MAAe;QACzB,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC;QAChC,IAAI,CAAC,KAAK;YAAE,OAAO;QACnB,sBAAsB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IACvC,CAAC;IAEO,KAAK,CAAC,sBAAsB;QACnC,MAAM,IAAI,CAAC,KAAK,CAAC;QACjB,OAAO,IAAI,CAAC,qBAAqB,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;YAC5C,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC,CAAC;QAC3D,CAAC;IACF,CAAC;IAEO,aAAa,CAAC,KAAmB;QACxC,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,IAAI,eAA2B,CAAC;QAChC,MAAM,eAAe,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;YACrD,eAAe,GAAG,OAAO,CAAC;QAC3B,CAAC,CAAC,CAAC;QACH,MAAM,cAAc,GAAG,GAAG,EAAE;YAC3B,IAAI,OAAO;gBAAE,OAAO;YACpB,OAAO,GAAG,IAAI,CAAC;YACf,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,mBAAmB,CAAC,CAAC;YACxC,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;YACnC,IAAI,CAAC,qBAAqB,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;YACnD,eAAe,EAAE,CAAC;QACnB,CAAC,CAAC;QACF,MAAM,mBAAmB,GAAG,GAAG,EAAE;YAChC,IAAI,CAAC,KAAK,CAAC,GAAG;gBAAE,cAAc,EAAE,CAAC;QAClC,CAAC,CAAC;QAEF,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;QAChD,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,mBAAmB,CAAC,CAAC;QACvC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;IACrC,CAAC;IAEO,KAAK,CAAC,KAAmB;QAChC,IAAI,IAAI,CAAC,YAAY,KAAK,KAAK;YAAE,OAAO,KAAK,CAAC;QAC9C,IAAI,KAAK,CAAC,GAAG;YAAE,uBAAuB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAClD,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QACzB,OAAO,IAAI,CAAC;IACb,CAAC;CACD","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
- /** Idempotently dispose both execution tiers and their shared authoritative Windows state. */
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;AAMnG,8FAA8F;AAC9F,wBAAgB,4BAA4B,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAIrE"}
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
- /** Idempotently dispose both execution tiers and their shared authoritative Windows state. */
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,8FAA8F;AAC9F,MAAM,UAAU,4BAA4B,CAAC,UAAkB;IAC9D,gCAAgC,CAAC,UAAU,CAAC,CAAC;IAC7C,6BAA6B,CAAC,UAAU,CAAC,CAAC;IAC1C,wBAAwB,CAAC,UAAU,CAAC,CAAC;AACtC,CAAC","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\n/** Idempotently dispose both execution tiers and their shared authoritative Windows state. */\nexport function disposeShellExecutionSession(sessionKey: string): void {\n\tdisposeWindowsShellEngineSession(sessionKey);\n\tdisposePersistentShellSession(sessionKey);\n\tdisposeWindowsShellState(sessionKey);\n}\n"]}
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":"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"}
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?.dispose();
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