@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,457 +0,0 @@
1
- import * as fs from "node:fs";
2
- import * as path from "node:path";
3
- import { writeAtomicJson } from "../../shared/atomic-json.ts";
4
- import { publishFileExclusive, unlinkIfPresent } from "../../shared/exclusive-file-publication.js";
5
- import {
6
- type AsyncParallelGroupStatus,
7
- type AsyncStatus,
8
- type NestedRunSummary,
9
- RESULTS_DIR,
10
- type SubagentRunMode,
11
- } from "../../shared/types.ts";
12
- import {
13
- type NestedRoute,
14
- nestedSummaryFromAsyncStatus,
15
- projectNestedEvents,
16
- resolveNestedAsyncDir,
17
- writeNestedEvent,
18
- } from "../shared/nested-events.ts";
19
- import { normalizeParallelGroups } from "./parallel-groups.ts";
20
-
21
- export type PidLiveness = "alive" | "dead" | "unknown";
22
-
23
- type KillFn = (pid: number, signal?: NodeJS.Signals | 0) => boolean;
24
-
25
- interface StartedRunMetadata {
26
- runId: string;
27
- pid?: number;
28
- sessionId?: string;
29
- mode?: SubagentRunMode;
30
- agents?: string[];
31
- chainStepCount?: number;
32
- parallelGroups?: AsyncParallelGroupStatus[];
33
- startedAt?: number;
34
- sessionFile?: string;
35
- }
36
-
37
- interface ReconcileAsyncRunOptions {
38
- resultsDir?: string;
39
- kill?: KillFn;
40
- now?: () => number;
41
- startedRun?: StartedRunMetadata;
42
- missingStatusGraceMs?: number;
43
- staleAlivePidMs?: number;
44
- publish?: (source: string, destination: string) => "published" | "exists";
45
- }
46
-
47
- interface ReconcileAsyncRunResult {
48
- status: AsyncStatus | null;
49
- repaired: boolean;
50
- resultPath?: string;
51
- message?: string;
52
- }
53
-
54
- function getErrorMessage(error: unknown): string {
55
- return error instanceof Error ? error.message : String(error);
56
- }
57
-
58
- function isNotFoundError(error: unknown): boolean {
59
- return (
60
- typeof error === "object" &&
61
- error !== null &&
62
- "code" in error &&
63
- (error as NodeJS.ErrnoException).code === "ENOENT"
64
- );
65
- }
66
-
67
- function appendJsonl(filePath: string, payload: object): void {
68
- fs.mkdirSync(path.dirname(filePath), { recursive: true });
69
- fs.appendFileSync(filePath, `${JSON.stringify(payload)}\n`, "utf-8");
70
- }
71
-
72
- function repairStagePath(resultPath: string): string {
73
- return path.join(path.dirname(resultPath), `.${path.basename(resultPath)}.stale-repair-stage`);
74
- }
75
-
76
- function readStagedRepair(resultPath: string): object | undefined {
77
- try {
78
- return JSON.parse(fs.readFileSync(repairStagePath(resultPath), "utf-8")) as object;
79
- } catch (error) {
80
- if (isNotFoundError(error)) return undefined;
81
- throw error;
82
- }
83
- }
84
-
85
- function stagedRepairMessage(staged: object): string | undefined {
86
- const summary = (staged as { summary?: unknown }).summary;
87
- return typeof summary === "string" ? summary : undefined;
88
- }
89
-
90
- function retireObsoleteStage(resultPath: string): void {
91
- const stagePath = repairStagePath(resultPath);
92
- const retiredPath = `${stagePath}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}.retired`;
93
- try {
94
- fs.renameSync(stagePath, retiredPath);
95
- try {
96
- fs.unlinkSync(retiredPath);
97
- } catch (error) {
98
- if (!isNotFoundError(error)) console.error(error);
99
- }
100
- } catch (error) {
101
- if (!isNotFoundError(error)) console.error(error);
102
- }
103
- }
104
-
105
- function publishStagedRepair(
106
- resultPath: string,
107
- status: AsyncStatus,
108
- staged: object,
109
- publish: (source: string, destination: string) => "published" | "exists" = publishFileExclusive,
110
- ): ReconcileAsyncRunResult {
111
- const stagePath = repairStagePath(resultPath);
112
- const outcome = publish(stagePath, resultPath);
113
- unlinkIfPresent(stagePath);
114
- return {
115
- status,
116
- repaired: outcome === "published",
117
- resultPath,
118
- message: outcome === "published" ? stagedRepairMessage(staged) : "A concurrently published result was preserved.",
119
- };
120
- }
121
-
122
- function readStatusFile(asyncDir: string): AsyncStatus | null {
123
- const statusPath = path.join(asyncDir, "status.json");
124
- let content: string;
125
- try {
126
- content = fs.readFileSync(statusPath, "utf-8");
127
- } catch (error) {
128
- if (isNotFoundError(error)) return null;
129
- throw new Error(`Failed to read async status file '${statusPath}': ${getErrorMessage(error)}`, {
130
- cause: error instanceof Error ? error : undefined,
131
- });
132
- }
133
- try {
134
- return JSON.parse(content) as AsyncStatus;
135
- } catch (error) {
136
- throw new Error(`Failed to parse async status file '${statusPath}': ${getErrorMessage(error)}`, {
137
- cause: error instanceof Error ? error : undefined,
138
- });
139
- }
140
- }
141
-
142
- interface ResultChildOutcome {
143
- agent?: string;
144
- success?: boolean;
145
- error?: string;
146
- sessionFile?: string;
147
- model?: string;
148
- fastMode?: boolean;
149
- attemptedModels?: string[];
150
- modelAttempts?: NonNullable<AsyncStatus["steps"]>[number]["modelAttempts"];
151
- }
152
-
153
- interface ResultRepairData {
154
- state: "complete" | "failed" | "paused";
155
- results?: ResultChildOutcome[];
156
- }
157
-
158
- function readResultRepairData(resultPath: string): ResultRepairData | undefined {
159
- try {
160
- const data = JSON.parse(fs.readFileSync(resultPath, "utf-8")) as {
161
- success?: boolean;
162
- state?: string;
163
- exitCode?: number;
164
- results?: ResultChildOutcome[];
165
- };
166
- const state = data.success ? "complete" : data.state === "paused" || data.exitCode === 0 ? "paused" : "failed";
167
- return { state, ...(Array.isArray(data.results) ? { results: data.results } : {}) };
168
- } catch (error) {
169
- if (isNotFoundError(error)) return undefined;
170
- throw new Error(`Failed to read async result file '${resultPath}': ${getErrorMessage(error)}`, {
171
- cause: error instanceof Error ? error : undefined,
172
- });
173
- }
174
- }
175
-
176
- function childState(
177
- overallState: ResultRepairData["state"],
178
- child: ResultChildOutcome | undefined,
179
- ): "complete" | "failed" | "paused" {
180
- if (child?.success === true) return "complete";
181
- if (child?.success === false) return "failed";
182
- return overallState;
183
- }
184
-
185
- function terminalStatusFromResult(status: AsyncStatus, resultPath: string, now: number): AsyncStatus | undefined {
186
- const repair = readResultRepairData(resultPath);
187
- if (!repair) return undefined;
188
- const steps = (status.steps ?? []).map((step, index) => {
189
- if (step.status !== "running" && step.status !== "pending") return step;
190
- const child = repair.results?.[index];
191
- const state = childState(repair.state, child);
192
- return {
193
- ...step,
194
- status: state === "complete" ? ("complete" as const) : state,
195
- endedAt: step.endedAt ?? now,
196
- durationMs:
197
- step.startedAt !== undefined && step.durationMs === undefined
198
- ? Math.max(0, now - step.startedAt)
199
- : step.durationMs,
200
- exitCode: step.exitCode ?? (state === "complete" || state === "paused" ? 0 : 1),
201
- error: state === "failed" ? (step.error ?? child?.error) : step.error,
202
- sessionFile: step.sessionFile ?? child?.sessionFile,
203
- model: step.model ?? child?.model,
204
- fastMode: step.fastMode ?? child?.fastMode,
205
- attemptedModels: step.attemptedModels ?? child?.attemptedModels,
206
- modelAttempts: step.modelAttempts ?? child?.modelAttempts,
207
- };
208
- });
209
- return {
210
- ...status,
211
- state: repair.state,
212
- activityState: undefined,
213
- lastUpdate: now,
214
- endedAt: status.endedAt ?? now,
215
- steps,
216
- };
217
- }
218
-
219
- function buildStartedStatus(asyncDir: string, startedRun: StartedRunMetadata, now: number): AsyncStatus {
220
- const startedAt = startedRun.startedAt ?? now;
221
- const agents = startedRun.agents?.length ? startedRun.agents : ["subagent"];
222
- const chainStepCount = startedRun.chainStepCount;
223
- const parallelGroups =
224
- chainStepCount !== undefined
225
- ? normalizeParallelGroups(startedRun.parallelGroups, agents.length, chainStepCount)
226
- : [];
227
- return {
228
- runId: startedRun.runId || path.basename(asyncDir),
229
- ...(startedRun.sessionId ? { sessionId: startedRun.sessionId } : {}),
230
- mode: startedRun.mode ?? "single",
231
- state: "running",
232
- pid: startedRun.pid,
233
- startedAt,
234
- lastUpdate: now,
235
- currentStep: 0,
236
- ...(chainStepCount !== undefined ? { chainStepCount } : {}),
237
- ...(parallelGroups.length ? { parallelGroups } : {}),
238
- steps: agents.map((agent) => ({
239
- agent,
240
- status: "running" as const,
241
- startedAt,
242
- })),
243
- ...(startedRun.sessionFile ? { sessionFile: startedRun.sessionFile } : {}),
244
- };
245
- }
246
-
247
- function buildFailedRepair(
248
- status: AsyncStatus,
249
- asyncDir: string,
250
- now: number,
251
- reason?: string,
252
- ): { status: AsyncStatus; result: object; message: string } {
253
- const runId = status.runId || path.basename(asyncDir);
254
- const pid = typeof status.pid === "number" ? status.pid : "unknown";
255
- const message =
256
- reason ??
257
- `Async runner process ${pid} exited or disappeared before writing a result. Marked run failed by stale-run reconciliation.`;
258
- const steps = status.steps?.length ? status.steps : [{ agent: "subagent", status: "running" as const }];
259
- const repairedSteps = steps.map((step) =>
260
- step.status === "running" || step.status === "pending"
261
- ? {
262
- ...step,
263
- status: "failed" as const,
264
- activityState: undefined,
265
- endedAt: step.endedAt ?? now,
266
- durationMs:
267
- step.startedAt !== undefined && step.durationMs === undefined
268
- ? Math.max(0, now - step.startedAt)
269
- : step.durationMs,
270
- exitCode: step.exitCode ?? 1,
271
- error: step.error ?? message,
272
- }
273
- : step,
274
- );
275
- const repairedStatus: AsyncStatus = {
276
- ...status,
277
- state: "failed",
278
- activityState: undefined,
279
- lastUpdate: now,
280
- endedAt: now,
281
- steps: repairedSteps,
282
- };
283
- const resultAgent = repairedSteps[status.currentStep ?? 0]?.agent ?? repairedSteps[0]?.agent ?? "subagent";
284
- return {
285
- status: repairedStatus,
286
- message,
287
- result: {
288
- id: runId,
289
- agent: resultAgent,
290
- mode: status.mode,
291
- success: false,
292
- state: "failed",
293
- summary: message,
294
- results: repairedSteps.map((step) => ({
295
- agent: step.agent,
296
- output: step.status === "complete" || step.status === "completed" ? "" : message,
297
- error: step.status === "complete" || step.status === "completed" ? undefined : (step.error ?? message),
298
- success: step.status === "complete" || step.status === "completed",
299
- model: step.model,
300
- fastMode: step.fastMode,
301
- attemptedModels: step.attemptedModels,
302
- modelAttempts: step.modelAttempts,
303
- sessionFile: step.sessionFile,
304
- })),
305
- exitCode: 1,
306
- timestamp: now,
307
- durationMs: Math.max(0, now - status.startedAt),
308
- asyncDir,
309
- sessionId: status.sessionId,
310
- sessionFile: status.sessionFile,
311
- },
312
- };
313
- }
314
-
315
- function writeFailedRepair(
316
- asyncDir: string,
317
- status: AsyncStatus,
318
- resultPath: string,
319
- now: number,
320
- reason?: string,
321
- publish?: ReconcileAsyncRunOptions["publish"],
322
- ): ReconcileAsyncRunResult {
323
- const repair = buildFailedRepair(status, asyncDir, now, reason);
324
- // Stage the exact public payload beside its destination. Publication consumes
325
- // the hidden stage with one atomic rename after terminal status is durable.
326
- writeAtomicJson(repairStagePath(resultPath), repair.result);
327
- writeAtomicJson(path.join(asyncDir, "status.json"), repair.status);
328
- try {
329
- appendJsonl(path.join(asyncDir, "events.jsonl"), {
330
- type: "subagent.run.repaired_stale",
331
- ts: now,
332
- runId: repair.status.runId,
333
- pid: status.pid,
334
- resultPath,
335
- message: repair.message,
336
- });
337
- } catch (error) {
338
- console.error(
339
- `Failed to append stale-repair event for '${asyncDir}'; publishing the recoverable result: ${getErrorMessage(error)}`,
340
- );
341
- }
342
- return publishStagedRepair(resultPath, repair.status, repair.result, publish);
343
- }
344
-
345
- function terminal(state: AsyncStatus["state"]): boolean {
346
- return state === "complete" || state === "failed" || state === "paused";
347
- }
348
-
349
- function* nestedRuns(children: NestedRunSummary[] | undefined): Generator<NestedRunSummary> {
350
- for (const child of children ?? []) {
351
- yield child;
352
- yield* nestedRuns(child.children);
353
- yield* nestedRuns(child.steps?.flatMap((step) => step.children ?? []));
354
- }
355
- }
356
-
357
- export function reconcileNestedAsyncDescendants(route: NestedRoute, options: ReconcileAsyncRunOptions = {}): void {
358
- const registry = projectNestedEvents(route);
359
- for (const run of nestedRuns(registry.children)) {
360
- if (run.state !== "running" && run.state !== "queued") continue;
361
- const asyncDir = resolveNestedAsyncDir(route.rootRunId, run);
362
- if (!asyncDir) continue;
363
- const result = reconcileAsyncRun(asyncDir, {
364
- ...options,
365
- resultsDir: path.join(options.resultsDir ?? RESULTS_DIR, "nested", route.rootRunId),
366
- });
367
- const status = result.status;
368
- if (!status) continue;
369
- if (!result.repaired && !terminal(status.state)) continue;
370
- const ts = options.now?.() ?? Date.now();
371
- writeNestedEvent(route, {
372
- type: terminal(status.state) ? "subagent.nested.completed" : "subagent.nested.updated",
373
- ts,
374
- parentRunId: run.parentRunId,
375
- parentStepIndex: run.parentStepIndex,
376
- child: nestedSummaryFromAsyncStatus(status, asyncDir, {
377
- id: run.id,
378
- parentRunId: run.parentRunId,
379
- parentStepIndex: run.parentStepIndex,
380
- depth: run.depth,
381
- path: run.path,
382
- mode: run.mode,
383
- ts,
384
- }),
385
- });
386
- }
387
- }
388
-
389
- export function checkPidLiveness(pid: number, kill: KillFn = process.kill): PidLiveness {
390
- try {
391
- kill(pid, 0);
392
- return "alive";
393
- } catch (error) {
394
- const code =
395
- typeof error === "object" && error !== null && "code" in error
396
- ? (error as NodeJS.ErrnoException).code
397
- : undefined;
398
- if (code === "ESRCH") return "dead";
399
- if (code === "EPERM") return "unknown";
400
- return "unknown";
401
- }
402
- }
403
-
404
- export function reconcileAsyncRun(asyncDir: string, options: ReconcileAsyncRunOptions = {}): ReconcileAsyncRunResult {
405
- const now = options.now?.() ?? Date.now();
406
- const status = readStatusFile(asyncDir);
407
- const startedStatus =
408
- !status && options.startedRun ? buildStartedStatus(asyncDir, options.startedRun, now) : undefined;
409
- const effectiveStatus = status ?? startedStatus;
410
- if (!effectiveStatus) return { status: null, repaired: false };
411
-
412
- const runId = effectiveStatus.runId || path.basename(asyncDir);
413
- const resultPath = path.join(options.resultsDir ?? RESULTS_DIR, `${runId}.json`);
414
- if (fs.existsSync(resultPath)) {
415
- retireObsoleteStage(resultPath);
416
- const terminalStatus =
417
- effectiveStatus.state === "running" || effectiveStatus.state === "queued"
418
- ? terminalStatusFromResult(effectiveStatus, resultPath, now)
419
- : undefined;
420
- if (terminalStatus) {
421
- writeAtomicJson(path.join(asyncDir, "status.json"), terminalStatus);
422
- return {
423
- status: terminalStatus,
424
- repaired: true,
425
- resultPath,
426
- message: "Existing async result file was used to repair stale running status.",
427
- };
428
- }
429
- return { status: effectiveStatus, repaired: false, resultPath };
430
- }
431
-
432
- const stagedRepair = readStagedRepair(resultPath);
433
- if (stagedRepair && terminal(effectiveStatus.state)) {
434
- return publishStagedRepair(resultPath, effectiveStatus, stagedRepair, options.publish);
435
- }
436
-
437
- if (effectiveStatus.state !== "running" || typeof effectiveStatus.pid !== "number") {
438
- return { status: status ?? null, repaired: false, resultPath };
439
- }
440
-
441
- if (!status) {
442
- const startedAt = options.startedRun?.startedAt ?? effectiveStatus.startedAt;
443
- if (now - startedAt < (options.missingStatusGraceMs ?? 1000)) {
444
- return { status: null, repaired: false, resultPath };
445
- }
446
- }
447
-
448
- const liveness = checkPidLiveness(effectiveStatus.pid, options.kill);
449
- if (liveness !== "dead") {
450
- const staleAfterMs = options.staleAlivePidMs ?? 24 * 60 * 60 * 1000;
451
- const lastUpdate = effectiveStatus.lastUpdate ?? effectiveStatus.startedAt;
452
- if (now - lastUpdate <= staleAfterMs) return { status: status ?? null, repaired: false, resultPath };
453
- const message = `Async runner process ${effectiveStatus.pid} still has a live PID, but status has not updated for ${now - lastUpdate}ms. Marked run failed by stale-run reconciliation because PID ownership cannot be verified.`;
454
- return writeFailedRepair(asyncDir, effectiveStatus, resultPath, now, message, options.publish);
455
- }
456
- return writeFailedRepair(asyncDir, effectiveStatus, resultPath, now, undefined, options.publish);
457
- }