@bastani/atomic 0.9.12 → 0.9.13-alpha.1

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 (264) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/builtin/intercom/CHANGELOG.md +6 -0
  3. package/dist/builtin/intercom/README.md +5 -12
  4. package/dist/builtin/intercom/broker/client.ts +11 -2
  5. package/dist/builtin/intercom/contact-supervisor-tool.ts +13 -3
  6. package/dist/builtin/intercom/index-heavy.ts +13 -3
  7. package/dist/builtin/intercom/index.ts +43 -19
  8. package/dist/builtin/intercom/intercom-utils.ts +15 -29
  9. package/dist/builtin/intercom/package.json +1 -1
  10. package/dist/builtin/intercom/source-ownership.ts +9 -12
  11. package/dist/builtin/mcp/CHANGELOG.md +6 -0
  12. package/dist/builtin/mcp/README.md +3 -1
  13. package/dist/builtin/mcp/index.ts +10 -16
  14. package/dist/builtin/mcp/package.json +1 -1
  15. package/dist/builtin/mcp/startup-warmup.ts +20 -8
  16. package/dist/builtin/subagents/CHANGELOG.md +30 -0
  17. package/dist/builtin/subagents/README.md +22 -30
  18. package/dist/builtin/subagents/package.json +1 -1
  19. package/dist/builtin/subagents/src/extension/doctor.ts +1 -1
  20. package/dist/builtin/subagents/src/extension/fanout-child.ts +76 -56
  21. package/dist/builtin/subagents/src/extension/index.ts +23 -32
  22. package/dist/builtin/subagents/src/extension/startup-maintenance.ts +25 -44
  23. package/dist/builtin/subagents/src/intercom/result-intercom.ts +7 -7
  24. package/dist/builtin/subagents/src/runs/background/async-job-tracker.ts +166 -434
  25. package/dist/builtin/subagents/src/runs/background/notify.ts +29 -8
  26. package/dist/builtin/subagents/src/runs/foreground/chain-execution-dynamic-step.ts +2 -2
  27. package/dist/builtin/subagents/src/runs/foreground/chain-execution-parallel-runner.ts +4 -4
  28. package/dist/builtin/subagents/src/runs/foreground/chain-execution-parallel-step.ts +2 -2
  29. package/dist/builtin/subagents/src/runs/foreground/chain-execution-sequential-step.ts +2 -2
  30. package/dist/builtin/subagents/src/runs/foreground/execution-run-sync.ts +1 -281
  31. package/dist/builtin/subagents/src/runs/foreground/execution-structured-retries.ts +11 -75
  32. package/dist/builtin/subagents/src/runs/foreground/inprocess-run-sync.ts +457 -0
  33. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-async.ts +119 -246
  34. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-chain.ts +1 -1
  35. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-context.ts +18 -9
  36. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-parallel-task.ts +1 -1
  37. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-parallel.ts +4 -4
  38. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-resume.ts +1 -646
  39. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-runtime.ts +2 -7
  40. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-single.ts +5 -5
  41. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-status.ts +7 -8
  42. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-types.ts +14 -5
  43. package/dist/builtin/subagents/src/runs/foreground/subagent-executor.ts +158 -93
  44. package/dist/builtin/subagents/src/runs/inprocess/background-single.ts +179 -0
  45. package/dist/builtin/subagents/src/runs/inprocess/background.ts +89 -0
  46. package/dist/builtin/subagents/src/runs/inprocess/child-policy.ts +27 -0
  47. package/dist/builtin/subagents/src/runs/inprocess/control-registry.ts +55 -0
  48. package/dist/builtin/subagents/src/runs/inprocess/control-status.ts +106 -0
  49. package/dist/builtin/subagents/src/runs/inprocess/index.ts +50 -0
  50. package/dist/builtin/subagents/src/runs/inprocess/nested-routing.ts +218 -0
  51. package/dist/builtin/subagents/src/runs/{shared/subagent-prompt-runtime.ts → inprocess/prompt-behavior.ts} +37 -75
  52. package/dist/builtin/subagents/src/runs/inprocess/runner.ts +1138 -0
  53. package/dist/builtin/subagents/src/runs/{shared/nested-events.ts → inprocess/runtime-support/nested-api.ts} +13 -7
  54. package/dist/builtin/subagents/src/runs/{shared/nested-events-control.ts → inprocess/runtime-support/nested-control.ts} +18 -17
  55. package/dist/builtin/subagents/src/runs/{shared/nested-events-core.ts → inprocess/runtime-support/nested-core.ts} +14 -61
  56. package/dist/builtin/subagents/src/runs/{shared/nested-events-projection.ts → inprocess/runtime-support/nested-projection.ts} +4 -10
  57. package/dist/builtin/subagents/src/runs/{shared/nested-events-registry.ts → inprocess/runtime-support/nested-registry.ts} +19 -4
  58. package/dist/builtin/subagents/src/runs/{shared/nested-render.ts → inprocess/runtime-support/nested-rendering.ts} +3 -3
  59. package/dist/builtin/subagents/src/runs/{shared/nested-events-sanitize.ts → inprocess/runtime-support/nested-sanitize.ts} +3 -3
  60. package/dist/builtin/subagents/src/runs/inprocess.ts +1 -0
  61. package/dist/builtin/subagents/src/runs/shared/dynamic-fanout.ts +10 -4
  62. package/dist/builtin/subagents/src/runs/shared/model-candidate-filter.ts +0 -1
  63. package/dist/builtin/subagents/src/runs/shared/model-fallback.ts +15 -492
  64. package/dist/builtin/subagents/src/runs/shared/parallel-utils.ts +13 -11
  65. package/dist/builtin/subagents/src/runs/shared/run-history.ts +3 -5
  66. package/dist/builtin/subagents/src/runs/shared/single-output.ts +4 -4
  67. package/dist/builtin/subagents/src/runs/shared/workflow-graph.ts +5 -5
  68. package/dist/builtin/subagents/src/shared/types-async.ts +0 -1
  69. package/dist/builtin/subagents/src/shared/types-config.ts +18 -0
  70. package/dist/builtin/subagents/src/shared/types-results.ts +9 -2
  71. package/dist/builtin/subagents/src/slash/prompt-template-bridge.ts +2 -3
  72. package/dist/builtin/subagents/src/slash/slash-live-state.ts +2 -2
  73. package/dist/builtin/subagents/src/tui/render-chain-graph.ts +10 -4
  74. package/dist/builtin/subagents/src/tui/render-event-formatting.ts +12 -11
  75. package/dist/builtin/subagents/src/tui/render-result-compact.ts +49 -12
  76. package/dist/builtin/subagents/src/tui/render-result.ts +46 -17
  77. package/dist/builtin/subagents/src/tui/render-stable-output.ts +1 -1
  78. package/dist/builtin/subagents/src/tui/render-status-progress.ts +8 -5
  79. package/dist/builtin/subagents/src/tui/render-widget-graph.ts +0 -8
  80. package/dist/builtin/subagents/src/tui/render-widget.ts +0 -24
  81. package/dist/builtin/web-access/package.json +1 -1
  82. package/dist/builtin/workflows/CHANGELOG.md +25 -0
  83. package/dist/builtin/workflows/README.md +13 -3
  84. package/dist/builtin/workflows/package.json +1 -1
  85. package/dist/builtin/workflows/src/durable/backend.ts +7 -0
  86. package/dist/builtin/workflows/src/durable/dbos-metadata.ts +11 -1
  87. package/dist/builtin/workflows/src/durable/resume-runtime.ts +1 -0
  88. package/dist/builtin/workflows/src/durable/tool-primitive.ts +4 -28
  89. package/dist/builtin/workflows/src/durable/types.ts +5 -0
  90. package/dist/builtin/workflows/src/engine/run.ts +17 -1
  91. package/dist/builtin/workflows/src/extension/atomic-stage-session.ts +12 -39
  92. package/dist/builtin/workflows/src/extension/config-file-loader.ts +10 -1
  93. package/dist/builtin/workflows/src/extension/config-loader.ts +1 -1
  94. package/dist/builtin/workflows/src/extension/dispatcher.ts +4 -0
  95. package/dist/builtin/workflows/src/extension/index.bundle.mjs +1151 -737
  96. package/dist/builtin/workflows/src/extension/lifecycle-notifications.ts +303 -38
  97. package/dist/builtin/workflows/src/extension/render-result.ts +4 -0
  98. package/dist/builtin/workflows/src/extension/runtime-durable-resume.ts +6 -3
  99. package/dist/builtin/workflows/src/extension/runtime.ts +7 -1
  100. package/dist/builtin/workflows/src/extension/wiring.ts +53 -11
  101. package/dist/builtin/workflows/src/extension/workflow-command-registration.ts +12 -3
  102. package/dist/builtin/workflows/src/extension/workflow-durable-resume-command.ts +5 -2
  103. package/dist/builtin/workflows/src/extension/workflow-run-control-command.ts +9 -7
  104. package/dist/builtin/workflows/src/extension/workflow-status-summary.ts +11 -0
  105. package/dist/builtin/workflows/src/extension/workflow-tool-content.ts +18 -1
  106. package/dist/builtin/workflows/src/extension/workflow-tool-control.ts +10 -8
  107. package/dist/builtin/workflows/src/extension/workflow-tool.ts +9 -4
  108. package/dist/builtin/workflows/src/runs/background/quit.ts +28 -4
  109. package/dist/builtin/workflows/src/runs/background/resume-acknowledgements.ts +2 -1
  110. package/dist/builtin/workflows/src/runs/background/status.ts +55 -8
  111. package/dist/builtin/workflows/src/runs/foreground/executor-direct-helpers.ts +4 -0
  112. package/dist/builtin/workflows/src/runs/foreground/executor-prompt-nodes.ts +3 -1
  113. package/dist/builtin/workflows/src/runs/foreground/executor-stage-control.ts +1 -1
  114. package/dist/builtin/workflows/src/runs/foreground/stage-runner-context.ts +1 -1
  115. package/dist/builtin/workflows/src/runs/foreground/stage-runner-controller.ts +688 -38
  116. package/dist/builtin/workflows/src/runs/foreground/stage-runner-types.ts +3 -1
  117. package/dist/builtin/workflows/src/runs/shared/model-fallback-failures.ts +19 -514
  118. package/dist/builtin/workflows/src/runs/shared/retry.ts +44 -0
  119. package/dist/builtin/workflows/src/shared/authoring-contract-stage.d.ts +5 -0
  120. package/dist/builtin/workflows/src/shared/authoring-contract-stage.ts +6 -0
  121. package/dist/builtin/workflows/src/shared/authoring-contract-ui.d.ts +5 -1
  122. package/dist/builtin/workflows/src/shared/authoring-contract-ui.ts +5 -0
  123. package/dist/builtin/workflows/src/shared/persistence-restore-helpers.ts +5 -0
  124. package/dist/builtin/workflows/src/shared/persistence-restore.ts +3 -0
  125. package/dist/builtin/workflows/src/shared/persistence-session-entries.ts +4 -0
  126. package/dist/builtin/workflows/src/shared/run-indicator-status.ts +75 -0
  127. package/dist/builtin/workflows/src/shared/store-public-types.ts +43 -7
  128. package/dist/builtin/workflows/src/shared/store-run-methods.ts +42 -8
  129. package/dist/builtin/workflows/src/shared/store-stage-methods.ts +31 -8
  130. package/dist/builtin/workflows/src/shared/store-types.ts +34 -0
  131. package/dist/builtin/workflows/src/shared/timing.ts +10 -0
  132. package/dist/builtin/workflows/src/tui/chat-surface-message.ts +22 -2
  133. package/dist/builtin/workflows/src/tui/session-list.ts +1 -1
  134. package/dist/builtin/workflows/src/tui/session-overlays.ts +14 -10
  135. package/dist/builtin/workflows/src/tui/session-picker.ts +20 -4
  136. package/dist/builtin/workflows/src/tui/status-list.ts +31 -47
  137. package/dist/builtin/workflows/src/tui/store-widget-installer.ts +9 -1
  138. package/dist/builtin/workflows/src/tui/widget.ts +16 -46
  139. package/dist/core/agent-session-auto-compaction.d.ts.map +1 -1
  140. package/dist/core/agent-session-auto-compaction.js +54 -11
  141. package/dist/core/agent-session-auto-compaction.js.map +1 -1
  142. package/dist/core/agent-session-events.d.ts.map +1 -1
  143. package/dist/core/agent-session-events.js +49 -14
  144. package/dist/core/agent-session-events.js.map +1 -1
  145. package/dist/core/agent-session-methods.d.ts +13 -0
  146. package/dist/core/agent-session-methods.d.ts.map +1 -1
  147. package/dist/core/agent-session-methods.js.map +1 -1
  148. package/dist/core/agent-session-models.d.ts.map +1 -1
  149. package/dist/core/agent-session-models.js +12 -1
  150. package/dist/core/agent-session-models.js.map +1 -1
  151. package/dist/core/agent-session-prompt.d.ts.map +1 -1
  152. package/dist/core/agent-session-prompt.js +4 -0
  153. package/dist/core/agent-session-prompt.js.map +1 -1
  154. package/dist/core/agent-session-retry.d.ts +21 -4
  155. package/dist/core/agent-session-retry.d.ts.map +1 -1
  156. package/dist/core/agent-session-retry.js +232 -106
  157. package/dist/core/agent-session-retry.js.map +1 -1
  158. package/dist/core/agent-session-state.d.ts.map +1 -1
  159. package/dist/core/agent-session-state.js +2 -1
  160. package/dist/core/agent-session-state.js.map +1 -1
  161. package/dist/core/agent-session-tool-hooks.d.ts.map +1 -1
  162. package/dist/core/agent-session-tool-hooks.js +12 -0
  163. package/dist/core/agent-session-tool-hooks.js.map +1 -1
  164. package/dist/core/agent-session-tool-registry.d.ts.map +1 -1
  165. package/dist/core/agent-session-tool-registry.js +1 -1
  166. package/dist/core/agent-session-tool-registry.js.map +1 -1
  167. package/dist/core/agent-session-types.d.ts +3 -1
  168. package/dist/core/agent-session-types.d.ts.map +1 -1
  169. package/dist/core/agent-session-types.js.map +1 -1
  170. package/dist/core/agent-session.d.ts +12 -1
  171. package/dist/core/agent-session.d.ts.map +1 -1
  172. package/dist/core/agent-session.js +7 -0
  173. package/dist/core/agent-session.js.map +1 -1
  174. package/dist/core/extensions/context-types.d.ts +25 -0
  175. package/dist/core/extensions/context-types.d.ts.map +1 -1
  176. package/dist/core/extensions/context-types.js.map +1 -1
  177. package/dist/core/extensions/index.d.ts +1 -1
  178. package/dist/core/extensions/index.d.ts.map +1 -1
  179. package/dist/core/extensions/index.js.map +1 -1
  180. package/dist/core/extensions/runner-context.d.ts +2 -1
  181. package/dist/core/extensions/runner-context.d.ts.map +1 -1
  182. package/dist/core/extensions/runner-context.js +4 -0
  183. package/dist/core/extensions/runner-context.js.map +1 -1
  184. package/dist/core/extensions/runner.d.ts +3 -2
  185. package/dist/core/extensions/runner.d.ts.map +1 -1
  186. package/dist/core/extensions/runner.js +3 -1
  187. package/dist/core/extensions/runner.js.map +1 -1
  188. package/dist/core/model-fallback-failures.d.ts +30 -0
  189. package/dist/core/model-fallback-failures.d.ts.map +1 -0
  190. package/dist/core/model-fallback-failures.js +610 -0
  191. package/dist/core/model-fallback-failures.js.map +1 -0
  192. package/dist/core/retry-policy.d.ts +30 -0
  193. package/dist/core/retry-policy.d.ts.map +1 -0
  194. package/dist/core/retry-policy.js +25 -0
  195. package/dist/core/retry-policy.js.map +1 -0
  196. package/dist/core/sdk-types.d.ts +8 -2
  197. package/dist/core/sdk-types.d.ts.map +1 -1
  198. package/dist/core/sdk-types.js.map +1 -1
  199. package/dist/core/sdk.d.ts.map +1 -1
  200. package/dist/core/sdk.js +6 -1
  201. package/dist/core/sdk.js.map +1 -1
  202. package/dist/core/session-manager-core.d.ts +2 -0
  203. package/dist/core/session-manager-core.d.ts.map +1 -1
  204. package/dist/core/session-manager-core.js +7 -0
  205. package/dist/core/session-manager-core.js.map +1 -1
  206. package/dist/index-extensions.d.ts +1 -1
  207. package/dist/index-extensions.d.ts.map +1 -1
  208. package/dist/index-extensions.js.map +1 -1
  209. package/dist/index.d.ts +3 -0
  210. package/dist/index.d.ts.map +1 -1
  211. package/dist/index.js +2 -0
  212. package/dist/index.js.map +1 -1
  213. package/docs/intercom.md +5 -10
  214. package/docs/settings.md +7 -1
  215. package/docs/subagents.md +19 -19
  216. package/docs/workflows.md +21 -5
  217. package/examples/extensions/gondolin/package-lock.json +3 -3
  218. package/npm-shrinkwrap.json +29 -29
  219. package/package.json +2 -2
  220. package/dist/builtin/subagents/src/runs/background/async-event-journal.ts +0 -112
  221. package/dist/builtin/subagents/src/runs/background/async-execution-chain.ts +0 -543
  222. package/dist/builtin/subagents/src/runs/background/async-execution-common.ts +0 -140
  223. package/dist/builtin/subagents/src/runs/background/async-execution-single.ts +0 -279
  224. package/dist/builtin/subagents/src/runs/background/async-execution-types.ts +0 -99
  225. package/dist/builtin/subagents/src/runs/background/async-execution.ts +0 -17
  226. package/dist/builtin/subagents/src/runs/background/async-resume.ts +0 -402
  227. package/dist/builtin/subagents/src/runs/background/async-status.ts +0 -411
  228. package/dist/builtin/subagents/src/runs/background/completion-claims.ts +0 -196
  229. package/dist/builtin/subagents/src/runs/background/completion-dedupe.ts +0 -102
  230. package/dist/builtin/subagents/src/runs/background/parallel-groups.ts +0 -59
  231. package/dist/builtin/subagents/src/runs/background/result-delivery-processor.ts +0 -300
  232. package/dist/builtin/subagents/src/runs/background/result-file-claims.ts +0 -166
  233. package/dist/builtin/subagents/src/runs/background/result-quarantine.ts +0 -77
  234. package/dist/builtin/subagents/src/runs/background/result-retry-scheduler.ts +0 -48
  235. package/dist/builtin/subagents/src/runs/background/result-status.ts +0 -87
  236. package/dist/builtin/subagents/src/runs/background/result-watcher-data.ts +0 -72
  237. package/dist/builtin/subagents/src/runs/background/result-watcher.ts +0 -320
  238. package/dist/builtin/subagents/src/runs/background/run-id-resolver.ts +0 -105
  239. package/dist/builtin/subagents/src/runs/background/run-status.ts +0 -358
  240. package/dist/builtin/subagents/src/runs/background/stale-run-reconciler.ts +0 -457
  241. package/dist/builtin/subagents/src/runs/background/subagent-runner-dynamic.ts +0 -376
  242. package/dist/builtin/subagents/src/runs/background/subagent-runner-finalize.ts +0 -150
  243. package/dist/builtin/subagents/src/runs/background/subagent-runner-output.ts +0 -109
  244. package/dist/builtin/subagents/src/runs/background/subagent-runner-parallel-helpers.ts +0 -128
  245. package/dist/builtin/subagents/src/runs/background/subagent-runner-parallel.ts +0 -309
  246. package/dist/builtin/subagents/src/runs/background/subagent-runner-sequential.ts +0 -173
  247. package/dist/builtin/subagents/src/runs/background/subagent-runner-state.ts +0 -578
  248. package/dist/builtin/subagents/src/runs/background/subagent-runner-step.ts +0 -330
  249. package/dist/builtin/subagents/src/runs/background/subagent-runner-streaming.ts +0 -330
  250. package/dist/builtin/subagents/src/runs/background/subagent-runner-types.ts +0 -210
  251. package/dist/builtin/subagents/src/runs/background/subagent-runner-utils.ts +0 -69
  252. package/dist/builtin/subagents/src/runs/background/subagent-runner.ts +0 -90
  253. package/dist/builtin/subagents/src/runs/background/top-level-async.ts +0 -12
  254. package/dist/builtin/subagents/src/runs/foreground/execution-attempt-control.ts +0 -140
  255. package/dist/builtin/subagents/src/runs/foreground/execution-attempt-finalize.ts +0 -108
  256. package/dist/builtin/subagents/src/runs/foreground/execution-attempt-types.ts +0 -17
  257. package/dist/builtin/subagents/src/runs/foreground/execution-attempt.ts +0 -558
  258. package/dist/builtin/subagents/src/runs/shared/attempt-watchdog.ts +0 -126
  259. package/dist/builtin/subagents/src/runs/shared/final-drain.ts +0 -39
  260. package/dist/builtin/subagents/src/runs/shared/pi-args.ts +0 -339
  261. package/dist/builtin/subagents/src/runs/shared/pi-spawn.ts +0 -165
  262. package/dist/builtin/subagents/src/runs/shared/spawn-env.ts +0 -21
  263. package/dist/builtin/subagents/src/shared/post-exit-stdio-guard.ts +0 -86
  264. /package/dist/builtin/subagents/src/runs/{shared/nested-path.ts → inprocess/runtime-support/nested-paths.ts} +0 -0
@@ -1,39 +0,0 @@
1
- export interface SubagentAssistantDrainMessage {
2
- readonly role?: unknown;
3
- readonly content?: unknown;
4
- readonly stopReason?: unknown;
5
- readonly errorMessage?: unknown;
6
- }
7
-
8
- export function assistantStopReason(message: SubagentAssistantDrainMessage): string | undefined {
9
- return typeof message.stopReason === "string" ? message.stopReason : undefined;
10
- }
11
-
12
- export function isAssistantFailureStopReason(stopReason: string | undefined): boolean {
13
- return stopReason === "error" || stopReason === "aborted";
14
- }
15
-
16
- export function assistantMessageHasToolCall(message: SubagentAssistantDrainMessage): boolean {
17
- return (
18
- Array.isArray(message.content) &&
19
- message.content.some(
20
- (part) =>
21
- part !== null && typeof part === "object" && (part as { readonly type?: unknown }).type === "toolCall",
22
- )
23
- );
24
- }
25
-
26
- function assistantMessageHasError(message: SubagentAssistantDrainMessage): boolean {
27
- const errorMessage = message.errorMessage;
28
- if (typeof errorMessage === "string") return errorMessage.trim().length > 0;
29
- return errorMessage !== undefined && errorMessage !== null;
30
- }
31
-
32
- export function shouldStartSubagentFinalDrain(message: SubagentAssistantDrainMessage): boolean {
33
- if (message.role !== undefined && message.role !== "assistant") return false;
34
- return (
35
- assistantStopReason(message) === "stop" &&
36
- !assistantMessageHasError(message) &&
37
- !assistantMessageHasToolCall(message)
38
- );
39
- }
@@ -1,339 +0,0 @@
1
- import * as fs from "node:fs";
2
- import * as os from "node:os";
3
- import * as path from "node:path";
4
- import { fileURLToPath } from "node:url";
5
- import {
6
- APP_NAME,
7
- type CodexFastModeResolvedSettings,
8
- type CodexFastModeScope,
9
- ENV_CODEX_FAST_MODE,
10
- getEnvValue,
11
- type SessionWorkflowMetadata,
12
- WORKFLOW_SESSION_METADATA_ENV,
13
- } from "@bastani/atomic";
14
- import { THINKING_LEVELS } from "../../shared/model-info.ts";
15
- import type { JsonSchemaObject } from "../../shared/types.ts";
16
- import { MAX_SUBAGENT_NESTING_DEPTH } from "../../shared/types-runtime.ts";
17
- import { resolveMcpDirectToolNames } from "./mcp-direct-tool-allowlist.ts";
18
- import { encodeNestedPathEnv, type NestedPathEntry, parseNestedPathEnv } from "./nested-path.ts";
19
- import { STRUCTURED_OUTPUT_CAPTURE_ENV, STRUCTURED_OUTPUT_SCHEMA_ENV } from "./structured-output.ts";
20
-
21
- const TASK_ARG_LIMIT = 8000;
22
- export const SUBAGENT_PARENT_MAX_DEPTH = MAX_SUBAGENT_NESTING_DEPTH;
23
- export const PROMPT_RUNTIME_EXTENSION_PATH = path.join(
24
- path.dirname(fileURLToPath(import.meta.url)),
25
- "subagent-prompt-runtime.ts",
26
- );
27
- const ENV_PREFIX = APP_NAME.toUpperCase();
28
- export const FANOUT_CHILD_EXTENSION_PATH = path.join(
29
- path.dirname(fileURLToPath(import.meta.url)),
30
- "..",
31
- "..",
32
- "extension",
33
- "fanout-child.ts",
34
- );
35
- export const SUBAGENT_CHILD_ENV = `${ENV_PREFIX}_SUBAGENT_CHILD`;
36
- export const SUBAGENT_ORCHESTRATOR_TARGET_ENV = `${ENV_PREFIX}_SUBAGENT_ORCHESTRATOR_TARGET`;
37
- export const SUBAGENT_RUN_ID_ENV = `${ENV_PREFIX}_SUBAGENT_RUN_ID`;
38
- export const SUBAGENT_CHILD_AGENT_ENV = `${ENV_PREFIX}_SUBAGENT_CHILD_AGENT`;
39
- export const SUBAGENT_CHILD_INDEX_ENV = `${ENV_PREFIX}_SUBAGENT_CHILD_INDEX`;
40
- export const SUBAGENT_FANOUT_CHILD_ENV = `${ENV_PREFIX}_SUBAGENT_FANOUT_CHILD`;
41
- export const SUBAGENT_PARENT_EVENT_SINK_ENV = `${ENV_PREFIX}_SUBAGENT_PARENT_EVENT_SINK`;
42
- export const SUBAGENT_PARENT_CONTROL_INBOX_ENV = `${ENV_PREFIX}_SUBAGENT_PARENT_CONTROL_INBOX`;
43
- export const SUBAGENT_PARENT_ROOT_RUN_ID_ENV = `${ENV_PREFIX}_SUBAGENT_PARENT_ROOT_RUN_ID`;
44
- export const SUBAGENT_PARENT_RUN_ID_ENV = `${ENV_PREFIX}_SUBAGENT_PARENT_RUN_ID`;
45
- export const SUBAGENT_PARENT_CHILD_INDEX_ENV = `${ENV_PREFIX}_SUBAGENT_PARENT_CHILD_INDEX`;
46
- export const SUBAGENT_PARENT_DEPTH_ENV = `${ENV_PREFIX}_SUBAGENT_PARENT_DEPTH`;
47
- export const SUBAGENT_PARENT_PATH_ENV = `${ENV_PREFIX}_SUBAGENT_PARENT_PATH`;
48
- export const SUBAGENT_PARENT_CAPABILITY_TOKEN_ENV = `${ENV_PREFIX}_SUBAGENT_PARENT_CAPABILITY_TOKEN`;
49
- export const SUBAGENT_INHERIT_PROJECT_CONTEXT_ENV = `${ENV_PREFIX}_SUBAGENT_INHERIT_PROJECT_CONTEXT`;
50
- export const SUBAGENT_INHERIT_SKILLS_ENV = `${ENV_PREFIX}_SUBAGENT_INHERIT_SKILLS`;
51
- export const SUBAGENT_INTERCOM_SESSION_NAME_ENV = `${ENV_PREFIX}_SUBAGENT_INTERCOM_SESSION_NAME`;
52
- export const SUBAGENT_SUPERVISOR_CAPABILITY_ENV = `${ENV_PREFIX}_SUBAGENT_SUPERVISOR_CAPABILITY`;
53
- export const SUBAGENT_SUPERVISOR_SESSION_ID_ENV = `${ENV_PREFIX}_SUBAGENT_SUPERVISOR_SESSION_ID`;
54
- /** Intercom home-group env key (not a _SUBAGENT_ key); resolves ATOMIC_/PI_ variants. */
55
- export const INTERCOM_GROUP_ENV = `${ENV_PREFIX}_INTERCOM_GROUP`;
56
- const STRUCTURED_OUTPUT_TOOL_NAME = "structured_output";
57
-
58
- interface BuildPiArgsInput {
59
- baseArgs: string[];
60
- task: string;
61
- sessionEnabled: boolean;
62
- sessionDir?: string;
63
- sessionFile?: string;
64
- model?: string;
65
- thinking?: string;
66
- systemPromptMode?: "append" | "replace";
67
- inheritProjectContext: boolean;
68
- inheritSkills: boolean;
69
- tools?: string[];
70
- extensions?: string[];
71
- systemPrompt?: string | null;
72
- mcpDirectTools?: string[];
73
- cwd?: string;
74
- promptFileStem?: string;
75
- intercomSessionName?: string;
76
- orchestratorIntercomTarget?: string;
77
- intercomGroup?: string;
78
- supervisorAuthorization?: { capability: string; supervisorSessionId: string };
79
- runId?: string;
80
- childAgentName?: string;
81
- childIndex?: number;
82
- parentEventSink?: string;
83
- parentControlInbox?: string;
84
- parentRootRunId?: string;
85
- parentRunId?: string;
86
- parentChildIndex?: number;
87
- parentDepth?: number;
88
- parentPath?: NestedPathEntry[];
89
- parentCapabilityToken?: string;
90
- codexFastModeSettings?: CodexFastModeResolvedSettings;
91
- codexFastModeScope?: CodexFastModeScope;
92
- workflowSessionMetadata?: SessionWorkflowMetadata;
93
- structuredOutput?: {
94
- schema: JsonSchemaObject;
95
- schemaPath: string;
96
- outputPath: string;
97
- };
98
- }
99
-
100
- interface BuildPiArgsResult {
101
- args: string[];
102
- env: Record<string, string | undefined>;
103
- tempDir?: string;
104
- }
105
-
106
- export function applyThinkingSuffix(model: string | undefined, thinking: string | undefined): string | undefined {
107
- if (!model || !thinking || thinking === "off") return model;
108
- const colonIdx = model.lastIndexOf(":");
109
- if (colonIdx !== -1 && THINKING_LEVELS.some((level) => level === model.substring(colonIdx + 1))) return model;
110
- return `${model}:${thinking}`;
111
- }
112
-
113
- function serializeChildCodexFastModeSettings(settings: CodexFastModeResolvedSettings): string {
114
- return `chat=${settings.chat ? "1" : "0"};workflow=${settings.workflow ? "1" : "0"}`;
115
- }
116
-
117
- function mapChildCodexFastModeSettings(
118
- settings: CodexFastModeResolvedSettings,
119
- scope: CodexFastModeScope,
120
- ): CodexFastModeResolvedSettings {
121
- return {
122
- chat: settings[scope],
123
- workflow: settings.workflow,
124
- };
125
- }
126
-
127
- export function buildPiArgs(input: BuildPiArgsInput): BuildPiArgsResult {
128
- const args = [...input.baseArgs];
129
-
130
- if (input.sessionFile) {
131
- fs.mkdirSync(path.dirname(input.sessionFile), { recursive: true });
132
- args.push("--session", input.sessionFile);
133
- } else {
134
- if (!input.sessionEnabled) {
135
- args.push("--no-session");
136
- }
137
- if (input.sessionDir) {
138
- fs.mkdirSync(input.sessionDir, { recursive: true });
139
- args.push("--session-dir", input.sessionDir);
140
- }
141
- }
142
-
143
- const modelArg = applyThinkingSuffix(input.model, input.thinking);
144
- if (modelArg) {
145
- args.push("--model", modelArg);
146
- }
147
-
148
- const declaredBuiltinTools =
149
- input.tools?.filter((tool) => !(tool.includes("/") || tool.endsWith(".ts") || tool.endsWith(".js"))) ?? [];
150
- const fanoutAuthorized = declaredBuiltinTools.includes("subagent");
151
- const toolExtensionPaths: string[] = [];
152
- if (input.tools !== undefined) {
153
- const builtinTools = [...declaredBuiltinTools];
154
- // Path-only extension entries are passed via --extension, not --tools. An
155
- // extension-only list intentionally emits no --tools flag, so default built-ins
156
- // remain available; do not synthesize a built-in allowlist just to add
157
- // structured_output and accidentally make that case restrictive.
158
- const shouldAutoAllowStructuredOutput =
159
- input.structuredOutput && (declaredBuiltinTools.length > 0 || input.tools.length === 0);
160
- if (shouldAutoAllowStructuredOutput && !builtinTools.includes(STRUCTURED_OUTPUT_TOOL_NAME)) {
161
- builtinTools.push(STRUCTURED_OUTPUT_TOOL_NAME);
162
- }
163
- for (const tool of input.tools) {
164
- if (
165
- !declaredBuiltinTools.includes(tool) &&
166
- (tool.includes("/") || tool.endsWith(".ts") || tool.endsWith(".js"))
167
- ) {
168
- toolExtensionPaths.push(tool);
169
- }
170
- }
171
- if (builtinTools.length > 0) {
172
- if (input.mcpDirectTools?.length) {
173
- for (const resolvedTool of resolveMcpDirectToolNames(input.mcpDirectTools, input.cwd)) {
174
- if (!builtinTools.includes(resolvedTool)) {
175
- builtinTools.push(resolvedTool);
176
- }
177
- }
178
- }
179
- args.push("--tools", builtinTools.join(","));
180
- }
181
- }
182
-
183
- // Keep the prompt runtime first: schema-backed children get structured_output
184
- // from this extension before the child session refreshes explicit --tools allowlists.
185
- const runtimeExtensions = fanoutAuthorized
186
- ? [PROMPT_RUNTIME_EXTENSION_PATH, FANOUT_CHILD_EXTENSION_PATH]
187
- : [PROMPT_RUNTIME_EXTENSION_PATH];
188
- if (input.extensions !== undefined) {
189
- args.push("--no-extensions");
190
- for (const extPath of [...new Set([...runtimeExtensions, ...toolExtensionPaths, ...input.extensions])]) {
191
- args.push("--extension", extPath);
192
- }
193
- } else {
194
- for (const extPath of [...new Set([...runtimeExtensions, ...toolExtensionPaths])]) {
195
- args.push("--extension", extPath);
196
- }
197
- }
198
-
199
- if (!input.inheritSkills) {
200
- args.push("--no-skills");
201
- }
202
-
203
- let tempDir: string | undefined;
204
- if (input.systemPrompt !== undefined && input.systemPrompt !== null) {
205
- tempDir = fs.mkdtempSync(path.join(os.tmpdir(), `${APP_NAME}-subagent-`));
206
- const stem = (input.promptFileStem ?? "prompt").replace(/[^\w.-]/g, "_");
207
- const promptPath = path.join(tempDir, `${stem}.md`);
208
- fs.writeFileSync(promptPath, input.systemPrompt, { mode: 0o600 });
209
- args.push(input.systemPromptMode === "replace" ? "--system-prompt" : "--append-system-prompt", promptPath);
210
- }
211
-
212
- if (input.task.length > TASK_ARG_LIMIT) {
213
- if (!tempDir) {
214
- tempDir = fs.mkdtempSync(path.join(os.tmpdir(), `${APP_NAME}-subagent-`));
215
- }
216
- const taskFilePath = path.join(tempDir, "task.md");
217
- fs.writeFileSync(taskFilePath, `Task: ${input.task}`, { mode: 0o600 });
218
- args.push(`@${taskFilePath}`);
219
- } else {
220
- args.push(`Task: ${input.task}`);
221
- }
222
-
223
- const env: Record<string, string | undefined> = {};
224
- env[SUBAGENT_CHILD_ENV] = "1";
225
- env[SUBAGENT_FANOUT_CHILD_ENV] = fanoutAuthorized ? "1" : "0";
226
- if (input.workflowSessionMetadata) {
227
- env[WORKFLOW_SESSION_METADATA_ENV] = JSON.stringify(input.workflowSessionMetadata);
228
- }
229
- if (input.codexFastModeSettings) {
230
- env[ENV_CODEX_FAST_MODE] = serializeChildCodexFastModeSettings(
231
- mapChildCodexFastModeSettings(input.codexFastModeSettings, input.codexFastModeScope ?? "chat"),
232
- );
233
- }
234
- const parentEventSinkEnv = getEnvValue(SUBAGENT_PARENT_EVENT_SINK_ENV);
235
- const parentControlInboxEnv = getEnvValue(SUBAGENT_PARENT_CONTROL_INBOX_ENV);
236
- const parentRootRunIdEnv = getEnvValue(SUBAGENT_PARENT_ROOT_RUN_ID_ENV);
237
- const parentRunIdEnv = getEnvValue(SUBAGENT_PARENT_RUN_ID_ENV);
238
- const parentChildIndexEnv = getEnvValue(SUBAGENT_PARENT_CHILD_INDEX_ENV);
239
- const parentDepthEnv = getEnvValue(SUBAGENT_PARENT_DEPTH_ENV);
240
- const parentPathEnv = getEnvValue(SUBAGENT_PARENT_PATH_ENV);
241
- const parentCapabilityTokenEnv = getEnvValue(SUBAGENT_PARENT_CAPABILITY_TOKEN_ENV);
242
- const inheritedNestedRoute = Boolean(parentEventSinkEnv && parentRootRunIdEnv && parentCapabilityTokenEnv);
243
- const parentRunId =
244
- input.parentRunId ??
245
- input.runId ??
246
- (inheritedNestedRoute ? getEnvValue(SUBAGENT_RUN_ID_ENV) : undefined) ??
247
- parentRunIdEnv ??
248
- "";
249
- const parentChildIndex =
250
- input.parentChildIndex !== undefined
251
- ? String(input.parentChildIndex)
252
- : input.childIndex !== undefined
253
- ? String(input.childIndex)
254
- : (parentChildIndexEnv ?? "");
255
- const inheritedDepth = Number(parentDepthEnv);
256
- const unclampedParentDepth =
257
- input.parentDepth ?? (inheritedNestedRoute && Number.isFinite(inheritedDepth) ? inheritedDepth + 1 : 1);
258
- const parentDepth = Math.min(Math.max(1, unclampedParentDepth), SUBAGENT_PARENT_MAX_DEPTH);
259
- const parentPath = input.parentPath ?? [
260
- ...parseNestedPathEnv(parentPathEnv),
261
- ...(parentRunId
262
- ? [
263
- {
264
- runId: parentRunId,
265
- ...(parentChildIndex && /^\d+$/.test(parentChildIndex)
266
- ? { stepIndex: Number(parentChildIndex) }
267
- : {}),
268
- ...(input.childAgentName ? { agent: input.childAgentName } : {}),
269
- },
270
- ]
271
- : []),
272
- ];
273
- env[SUBAGENT_PARENT_EVENT_SINK_ENV] = fanoutAuthorized ? (input.parentEventSink ?? parentEventSinkEnv ?? "") : "";
274
- env[SUBAGENT_PARENT_CONTROL_INBOX_ENV] = fanoutAuthorized
275
- ? (input.parentControlInbox ?? parentControlInboxEnv ?? "")
276
- : "";
277
- env[SUBAGENT_PARENT_ROOT_RUN_ID_ENV] = fanoutAuthorized
278
- ? (input.parentRootRunId ?? parentRootRunIdEnv ?? input.runId ?? "")
279
- : "";
280
- env[SUBAGENT_PARENT_RUN_ID_ENV] = fanoutAuthorized ? parentRunId : "";
281
- env[SUBAGENT_PARENT_CHILD_INDEX_ENV] = fanoutAuthorized ? parentChildIndex : "";
282
- env[SUBAGENT_PARENT_DEPTH_ENV] = fanoutAuthorized ? String(parentDepth) : "";
283
- env[SUBAGENT_PARENT_PATH_ENV] = fanoutAuthorized ? encodeNestedPathEnv(parentPath) : "";
284
- env[SUBAGENT_PARENT_CAPABILITY_TOKEN_ENV] = fanoutAuthorized
285
- ? (input.parentCapabilityToken ?? parentCapabilityTokenEnv ?? "")
286
- : "";
287
- env[SUBAGENT_INHERIT_PROJECT_CONTEXT_ENV] = input.inheritProjectContext ? "1" : "0";
288
- env[SUBAGENT_INHERIT_SKILLS_ENV] = input.inheritSkills ? "1" : "0";
289
- if (input.intercomSessionName) {
290
- env[SUBAGENT_INTERCOM_SESSION_NAME_ENV] = input.intercomSessionName;
291
- }
292
- if (input.orchestratorIntercomTarget) {
293
- env[SUBAGENT_ORCHESTRATOR_TARGET_ENV] = input.orchestratorIntercomTarget;
294
- }
295
- // Always override inherited capability metadata: a child must never pass its
296
- // own supervisor authority to a descendant that lacks a freshly issued grant.
297
- env[SUBAGENT_SUPERVISOR_CAPABILITY_ENV] = input.supervisorAuthorization?.capability ?? "";
298
- env[SUBAGENT_SUPERVISOR_SESSION_ID_ENV] = input.supervisorAuthorization?.supervisorSessionId ?? "";
299
- // Assign a workflow/explicit group only when the child has Intercom access;
300
- // otherwise clear ambient group state so a restricted child receives none.
301
- const hasIntercomAccess = Boolean(input.intercomSessionName || input.orchestratorIntercomTarget);
302
- if (!hasIntercomAccess) {
303
- env[INTERCOM_GROUP_ENV] = "";
304
- } else if (input.intercomGroup) {
305
- env[INTERCOM_GROUP_ENV] = input.intercomGroup;
306
- }
307
- if (input.runId) {
308
- env[SUBAGENT_RUN_ID_ENV] = input.runId;
309
- }
310
- if (input.childAgentName) {
311
- env[SUBAGENT_CHILD_AGENT_ENV] = input.childAgentName;
312
- }
313
- if (input.childIndex !== undefined) {
314
- env[SUBAGENT_CHILD_INDEX_ENV] = String(input.childIndex);
315
- }
316
- // Bare MCP_DIRECT_TOOLS is the MCP adapter contract: unset means config defaults, __none__ forces no direct tools.
317
- if (input.mcpDirectTools?.length) {
318
- env.MCP_DIRECT_TOOLS = input.mcpDirectTools.join(",");
319
- } else {
320
- env.MCP_DIRECT_TOOLS = "__none__";
321
- }
322
- if (input.structuredOutput) {
323
- env[STRUCTURED_OUTPUT_CAPTURE_ENV] = input.structuredOutput.outputPath;
324
- env[STRUCTURED_OUTPUT_SCHEMA_ENV] = input.structuredOutput.schemaPath;
325
- }
326
-
327
- return { args, env, tempDir };
328
- }
329
-
330
- export const parseParentPathEnv = parseNestedPathEnv;
331
-
332
- export function cleanupTempDir(tempDir: string | null | undefined): void {
333
- if (!tempDir) return;
334
- try {
335
- fs.rmSync(tempDir, { recursive: true, force: true });
336
- } catch {
337
- // Temp cleanup is best effort.
338
- }
339
- }
@@ -1,165 +0,0 @@
1
- import * as fs from "node:fs";
2
- import * as path from "node:path";
3
- import { fileURLToPath } from "node:url";
4
- import { APP_NAME, PACKAGE_NAME } from "@bastani/atomic";
5
-
6
- export const CODING_AGENT_PACKAGE = PACKAGE_NAME;
7
- export const PI_CODING_AGENT_PACKAGE = CODING_AGENT_PACKAGE;
8
-
9
- export function findPiPackageRootFromEntry(entryPoint: string): string | undefined {
10
- let dir = path.dirname(entryPoint);
11
- while (dir !== path.dirname(dir)) {
12
- const packageJsonPath = path.join(dir, "package.json");
13
- if (fs.existsSync(packageJsonPath)) {
14
- const pkg = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8")) as { name?: unknown };
15
- if (pkg.name === CODING_AGENT_PACKAGE) return dir;
16
- }
17
- dir = path.dirname(dir);
18
- }
19
- return undefined;
20
- }
21
-
22
- export function resolveInstalledPiPackageRoot(): string | undefined {
23
- return findPiPackageRootFromEntry(fileURLToPath(import.meta.resolve(CODING_AGENT_PACKAGE)));
24
- }
25
-
26
- export function resolvePiPackageRoot(): string | undefined {
27
- try {
28
- const entry = process.argv[1];
29
- return entry ? findPiPackageRootFromEntry(fs.realpathSync(entry)) : undefined;
30
- } catch {
31
- // process.argv[1] probing is best-effort; callers can fall back to PATH/package resolution.
32
- return undefined;
33
- }
34
- }
35
-
36
- export interface PiSpawnDeps {
37
- platform?: NodeJS.Platform;
38
- execPath?: string;
39
- argv1?: string;
40
- existsSync?: (filePath: string) => boolean;
41
- readFileSync?: (filePath: string, encoding: "utf-8") => string;
42
- resolvePackageJson?: () => string;
43
- resolvePackageEntry?: () => string;
44
- piPackageRoot?: string;
45
- statSync?: (filePath: string) => fs.Stats;
46
- }
47
-
48
- export type PiSpawnCwdValidationResult = { ok: true } | { ok: false; error: string };
49
-
50
- export function validatePiSpawnCwd(cwd: string, deps: PiSpawnDeps = {}): PiSpawnCwdValidationResult {
51
- const statSync = deps.statSync ?? fs.statSync;
52
- try {
53
- const cwdStats = statSync(cwd);
54
- if (!cwdStats.isDirectory()) return { ok: false, error: `cwd is not a directory: ${cwd}` };
55
- return { ok: true };
56
- } catch (error) {
57
- const fsError = error as NodeJS.ErrnoException;
58
- if (fsError.code === "ENOENT") return { ok: false, error: `cwd does not exist: ${cwd}` };
59
- if (fsError.code === "ENOTDIR")
60
- return { ok: false, error: `cwd path contains a non-directory component: ${cwd}` };
61
- const details = fsError.message ? ` (${fsError.message})` : "";
62
- return { ok: false, error: `cwd is not accessible: ${cwd}${details}` };
63
- }
64
- }
65
-
66
- export function formatPiSpawnError(error: Error, spawnSpec: PiSpawnCommand, cwd: string): string {
67
- const spawnError = error as NodeJS.ErrnoException;
68
- const message = error.message || String(error);
69
- if (spawnError.code === "ENOENT") {
70
- return `failed to spawn subagent runtime '${spawnSpec.command}' from cwd '${cwd}': runtime executable was not found or could not be launched (${message})`;
71
- }
72
- return `failed to spawn subagent runtime '${spawnSpec.command}' from cwd '${cwd}': ${message}`;
73
- }
74
-
75
- export interface PiSpawnCommand {
76
- command: string;
77
- args: string[];
78
- }
79
-
80
- function isGenericBunRuntime(execPath: string, platform: NodeJS.Platform): boolean {
81
- const pathImpl = platform === "win32" ? path.win32 : path;
82
- const executableName = pathImpl.basename(execPath).toLowerCase();
83
- return executableName === "bun" || executableName === "bun.exe";
84
- }
85
-
86
- function isRunnableCliScript(
87
- filePath: string,
88
- execPath: string,
89
- platform: NodeJS.Platform,
90
- existsSync: (filePath: string) => boolean,
91
- ): boolean {
92
- if (!existsSync(filePath)) return false;
93
- if (/\.(?:mjs|cjs|js)$/i.test(filePath)) return true;
94
- return /\.ts$/i.test(filePath) && isGenericBunRuntime(execPath, platform);
95
- }
96
-
97
- function normalizePath(filePath: string, platform: NodeJS.Platform): string {
98
- const pathImpl = platform === "win32" ? path.win32 : path;
99
- return pathImpl.isAbsolute(filePath) ? filePath : pathImpl.resolve(filePath);
100
- }
101
-
102
- export function resolvePiCliScript(deps: PiSpawnDeps = {}): string | undefined {
103
- const existsSync = deps.existsSync ?? fs.existsSync;
104
- const readFileSync = deps.readFileSync ?? ((filePath, encoding) => fs.readFileSync(filePath, encoding));
105
- const platform = deps.platform ?? process.platform;
106
- const execPath = deps.execPath ?? process.execPath;
107
- const argv1 = Object.hasOwn(deps, "argv1") ? deps.argv1 : process.argv[1];
108
- const pathImpl = platform === "win32" ? path.win32 : path;
109
-
110
- if (argv1) {
111
- const argvPath = normalizePath(argv1, platform);
112
- if (isRunnableCliScript(argvPath, execPath, platform, existsSync)) {
113
- return argvPath;
114
- }
115
- }
116
-
117
- try {
118
- const resolvePackageJson =
119
- deps.resolvePackageJson ??
120
- (() => {
121
- const root = deps.piPackageRoot ?? resolvePiPackageRoot();
122
- if (root) return pathImpl.join(root, "package.json");
123
- const packageRoot = deps.resolvePackageEntry
124
- ? findPiPackageRootFromEntry(deps.resolvePackageEntry())
125
- : resolveInstalledPiPackageRoot();
126
- if (!packageRoot) throw new Error(`Could not resolve ${CODING_AGENT_PACKAGE} package root`);
127
- return pathImpl.join(packageRoot, "package.json");
128
- });
129
- const packageJsonPath = resolvePackageJson();
130
- const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8")) as {
131
- bin?: string | Record<string, string>;
132
- };
133
- const binField = packageJson.bin;
134
- const binPath =
135
- typeof binField === "string"
136
- ? binField
137
- : (binField?.[APP_NAME] ?? binField?.pi ?? Object.values(binField ?? {})[0]);
138
- if (!binPath) return undefined;
139
- const candidate = pathImpl.resolve(pathImpl.dirname(packageJsonPath), binPath);
140
- if (isRunnableCliScript(candidate, execPath, platform, existsSync)) {
141
- return candidate;
142
- }
143
- } catch {
144
- // Windows CLI resolution is optional; falling back to the app command lets PATH handle execution.
145
- return undefined;
146
- }
147
-
148
- return undefined;
149
- }
150
-
151
- export function resolveWindowsPiCliScript(deps: PiSpawnDeps = {}): string | undefined {
152
- return resolvePiCliScript(deps);
153
- }
154
-
155
- export function getPiSpawnCommand(args: string[], deps: PiSpawnDeps = {}): PiSpawnCommand {
156
- const cliPath = resolvePiCliScript(deps);
157
- if (cliPath) {
158
- return {
159
- command: deps.execPath ?? process.execPath,
160
- args: [cliPath, ...args],
161
- };
162
- }
163
-
164
- return { command: APP_NAME, args };
165
- }
@@ -1,21 +0,0 @@
1
- import { scrubInteractiveEngineEnv } from "@bastani/atomic";
2
-
3
- /**
4
- * Build a child environment from ordered layers, then remove Atomic's
5
- * interactive-engine control variables.
6
- *
7
- * Atomic already deletes those variables from its own `process.env` at startup;
8
- * scrubbing here is defense in depth for a caller-supplied or shared
9
- * environment that reintroduces one. The scrub deliberately runs LAST, after
10
- * `process.env`, the caller environment, and the subagent depth/workflow guards
11
- * have been merged, so no later layer can put a key back.
12
- */
13
- export function buildSubagentSpawnEnv(
14
- ...layers: Array<NodeJS.ProcessEnv | Record<string, string> | undefined>
15
- ): NodeJS.ProcessEnv {
16
- const merged: NodeJS.ProcessEnv = {};
17
- for (const layer of layers) {
18
- if (layer) Object.assign(merged, layer);
19
- }
20
- return scrubInteractiveEngineEnv(merged);
21
- }
@@ -1,86 +0,0 @@
1
- import type { ChildProcess } from "node:child_process";
2
-
3
- interface PostExitStdioGuardOptions {
4
- idleMs: number;
5
- hardMs: number;
6
- }
7
-
8
- interface ChildWithPipedStdio {
9
- stdout: ChildProcess["stdout"];
10
- stderr: ChildProcess["stderr"];
11
- on: ChildProcess["on"];
12
- }
13
-
14
- interface ChildWithKill {
15
- kill(signal?: NodeJS.Signals | number): boolean;
16
- }
17
-
18
- export function trySignalChild(child: ChildWithKill, signal: NodeJS.Signals): boolean {
19
- try {
20
- return child.kill(signal);
21
- } catch {
22
- return false;
23
- }
24
- }
25
-
26
- export function attachPostExitStdioGuard(child: ChildWithPipedStdio, options: PostExitStdioGuardOptions): () => void {
27
- const { idleMs, hardMs } = options;
28
- let exited = false;
29
- let stdoutEnded = false;
30
- let stderrEnded = false;
31
- let idleTimer: NodeJS.Timeout | undefined;
32
- let hardTimer: NodeJS.Timeout | undefined;
33
-
34
- const destroyUnendedStdio = () => {
35
- if (!stdoutEnded) {
36
- try {
37
- child.stdout?.destroy();
38
- } catch {}
39
- }
40
- if (!stderrEnded) {
41
- try {
42
- child.stderr?.destroy();
43
- } catch {}
44
- }
45
- };
46
-
47
- const clearTimers = () => {
48
- if (idleTimer) {
49
- clearTimeout(idleTimer);
50
- idleTimer = undefined;
51
- }
52
- if (hardTimer) {
53
- clearTimeout(hardTimer);
54
- hardTimer = undefined;
55
- }
56
- };
57
-
58
- const armIdleTimer = () => {
59
- if (!exited) return;
60
- if (idleTimer) clearTimeout(idleTimer);
61
- idleTimer = setTimeout(destroyUnendedStdio, idleMs);
62
- idleTimer.unref?.();
63
- };
64
-
65
- child.stdout?.on("data", armIdleTimer);
66
- child.stderr?.on("data", armIdleTimer);
67
- child.stdout?.on("end", () => {
68
- stdoutEnded = true;
69
- if (stdoutEnded && stderrEnded) clearTimers();
70
- });
71
- child.stderr?.on("end", () => {
72
- stderrEnded = true;
73
- if (stdoutEnded && stderrEnded) clearTimers();
74
- });
75
- child.on("exit", () => {
76
- exited = true;
77
- armIdleTimer();
78
- if (hardTimer) return;
79
- hardTimer = setTimeout(destroyUnendedStdio, hardMs);
80
- hardTimer.unref?.();
81
- });
82
- child.on("close", clearTimers);
83
- child.on("error", clearTimers);
84
-
85
- return clearTimers;
86
- }