@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,376 +0,0 @@
1
- import * as path from "node:path";
2
- import { resolveSubagentIntercomTarget } from "../../intercom/intercom-bridge.ts";
3
- import type { SupervisorAuthorization } from "../../intercom/supervisor-authorization.ts";
4
- import { appendJsonl } from "../../shared/artifacts.ts";
5
- import { resolveEffectiveThinking } from "../../shared/model-info.ts";
6
- import {
7
- collectDynamicResults,
8
- DynamicFanoutError,
9
- materializeDynamicParallelStep,
10
- validateDynamicCollection,
11
- } from "../shared/dynamic-fanout.ts";
12
- import { createMutatingFailureState } from "../shared/long-running-guard.ts";
13
- import { aggregateParallelOutputs, MAX_PARALLEL_CONCURRENCY, mapConcurrent } from "../shared/parallel-utils.ts";
14
- import {
15
- markDynamicGraphGroup,
16
- resetStepLiveDetail,
17
- updateStepFromChildEvent,
18
- updateStepModel,
19
- writeStatusPayload,
20
- } from "./subagent-runner-state.ts";
21
- import { runSingleStep } from "./subagent-runner-step.ts";
22
- import type { RunnerExecutionState, RunnerStatusStep, RunnerStep, SubagentStep } from "./subagent-runner-types.ts";
23
-
24
- export async function runDynamicGroup(
25
- state: RunnerExecutionState,
26
- step: RunnerStep,
27
- stepIndex: number,
28
- ): Promise<boolean> {
29
- const {
30
- outputs,
31
- statusPayload,
32
- asyncDir,
33
- id,
34
- cwd,
35
- placeholder,
36
- sessionEnabled,
37
- config,
38
- artifactsDir,
39
- artifactConfig,
40
- } = state;
41
- const groupStartFlatIndex = state.flatIndex;
42
- let materialized: ReturnType<typeof materializeDynamicParallelStep>;
43
- try {
44
- materialized = materializeDynamicParallelStep(
45
- step as Parameters<typeof materializeDynamicParallelStep>[0],
46
- outputs,
47
- stepIndex,
48
- { maxItems: config.dynamicFanoutMaxItems, allowRunnerFields: true },
49
- );
50
- if (materialized.collectedOnEmpty)
51
- validateDynamicCollection(
52
- (step as Parameters<typeof materializeDynamicParallelStep>[0]).collect.outputSchema,
53
- materialized.collectedOnEmpty,
54
- );
55
- } catch (error) {
56
- const now = Date.now();
57
- const message =
58
- error instanceof DynamicFanoutError ? error.message : error instanceof Error ? error.message : String(error);
59
- statusPayload.state = "failed";
60
- statusPayload.error = message;
61
- statusPayload.currentStep = state.flatIndex;
62
- const placeholderStep = statusPayload.steps[groupStartFlatIndex];
63
- if (placeholderStep) {
64
- placeholderStep.status = "failed";
65
- placeholderStep.error = message;
66
- placeholderStep.startedAt = now;
67
- placeholderStep.endedAt = now;
68
- placeholderStep.durationMs = 0;
69
- placeholderStep.exitCode = 1;
70
- }
71
- statusPayload.lastUpdate = now;
72
- markDynamicGraphGroup(state, stepIndex, "failed", message);
73
- writeStatusPayload(state);
74
- const dynamicStep = step as Parameters<typeof materializeDynamicParallelStep>[0];
75
- state.results.push({
76
- agent: dynamicStep.parallel.agent,
77
- output: message,
78
- error: message,
79
- success: false,
80
- exitCode: 1,
81
- });
82
- return false;
83
- }
84
-
85
- const dynamicStep = step as Parameters<typeof materializeDynamicParallelStep>[0];
86
- const parallelTemplate = dynamicStep.parallel as unknown as SubagentStep;
87
- if (materialized.parallel.length === 0) {
88
- const now = Date.now();
89
- const collection = materialized.collectedOnEmpty ?? [];
90
- outputs[dynamicStep.collect.as] = {
91
- text: JSON.stringify(collection),
92
- structured: collection,
93
- agent: dynamicStep.parallel.agent,
94
- stepIndex,
95
- };
96
- statusPayload.outputs = outputs;
97
- const placeholderStep = statusPayload.steps[groupStartFlatIndex];
98
- if (placeholderStep) {
99
- placeholderStep.status = "complete";
100
- placeholderStep.startedAt = now;
101
- placeholderStep.endedAt = now;
102
- placeholderStep.durationMs = 0;
103
- }
104
- state.previousOutput = "Dynamic fanout produced 0 results.";
105
- state.flatIndex++;
106
- statusPayload.lastUpdate = now;
107
- markDynamicGraphGroup(state, stepIndex, "completed");
108
- writeStatusPayload(state);
109
- return true;
110
- }
111
-
112
- const dynamicSteps: SubagentStep[] = materialized.parallel.map((task) => ({
113
- ...parallelTemplate,
114
- task: task.task ?? parallelTemplate.task,
115
- label: task.label ?? parallelTemplate.label,
116
- structuredOutput: undefined,
117
- structuredOutputSchema: parallelTemplate.structuredOutputSchema ?? parallelTemplate.structuredOutput?.schema,
118
- }));
119
- const dynamicStatusSteps: RunnerStatusStep[] = dynamicSteps.map((task) => ({
120
- agent: task.agent,
121
- phase: task.phase ?? dynamicStep.phase,
122
- label: task.label,
123
- outputName: undefined,
124
- structured: Boolean(task.structuredOutputSchema),
125
- status: "pending",
126
- ...(task.sessionFile ? { sessionFile: task.sessionFile } : {}),
127
- skills: task.skills,
128
- model: task.model,
129
- thinking: task.thinking,
130
- attemptedModels:
131
- task.modelCandidates && task.modelCandidates.length > 0
132
- ? task.modelCandidates
133
- : task.model
134
- ? [task.model]
135
- : undefined,
136
- recentTools: [],
137
- recentOutput: [],
138
- }));
139
- statusPayload.steps.splice(groupStartFlatIndex, 1, ...dynamicStatusSteps);
140
- if (config.childIntercomTargets)
141
- config.childIntercomTargets = statusPayload.steps.map((statusStep, index) =>
142
- resolveSubagentIntercomTarget(id, statusStep.agent, index),
143
- );
144
- const dynamicAuthorizations = config.dynamicSupervisorAuthorizations?.[stepIndex];
145
- if (dynamicAuthorizations) {
146
- const authorizations =
147
- config.supervisorAuthorizations ??
148
- new Array<SupervisorAuthorization | undefined>(
149
- statusPayload.steps.length - dynamicStatusSteps.length + 1,
150
- ).fill(undefined);
151
- authorizations.splice(groupStartFlatIndex, 1, ...dynamicSteps.map((_, index) => dynamicAuthorizations[index]));
152
- config.supervisorAuthorizations = authorizations;
153
- }
154
- state.mutatingFailureStates.splice(
155
- groupStartFlatIndex,
156
- 1,
157
- ...dynamicStatusSteps.map(() => createMutatingFailureState()),
158
- );
159
- state.pendingToolResults.splice(groupStartFlatIndex, 1, ...dynamicStatusSteps.map(() => undefined));
160
- const materializedDelta = dynamicStatusSteps.length - 1;
161
- for (const group of statusPayload.parallelGroups) {
162
- if (group.stepIndex === stepIndex) {
163
- group.start = groupStartFlatIndex;
164
- group.count = dynamicStatusSteps.length;
165
- } else if (group.start > groupStartFlatIndex) {
166
- group.start += materializedDelta;
167
- }
168
- }
169
- if (statusPayload.workflowGraph) {
170
- const shiftFlatIndexes = (nodes: NonNullable<typeof statusPayload.workflowGraph>["nodes"]): void => {
171
- for (const node of nodes) {
172
- if (
173
- node.stepIndex !== undefined &&
174
- node.stepIndex > stepIndex &&
175
- node.flatIndex !== undefined &&
176
- node.flatIndex >= groupStartFlatIndex
177
- )
178
- node.flatIndex += dynamicStatusSteps.length;
179
- if (node.children) shiftFlatIndexes(node.children);
180
- }
181
- };
182
- shiftFlatIndexes(statusPayload.workflowGraph.nodes);
183
- const groupNode = statusPayload.workflowGraph.nodes.find((node) => node.id === `step-${stepIndex}`);
184
- if (groupNode) {
185
- groupNode.children = materialized.items.map((item, itemIndex) => ({
186
- id: `step-${stepIndex}-item-${item.idKey}`,
187
- kind: "agent",
188
- agent: parallelTemplate.agent,
189
- phase: dynamicSteps[itemIndex]?.phase ?? dynamicStep.phase,
190
- label: dynamicSteps[itemIndex]?.label?.trim() || `${parallelTemplate.agent} ${item.key}`,
191
- status: "pending",
192
- flatIndex: groupStartFlatIndex + itemIndex,
193
- stepIndex,
194
- itemKey: item.key,
195
- structured: Boolean(dynamicSteps[itemIndex]?.structuredOutputSchema),
196
- }));
197
- }
198
- }
199
- writeStatusPayload(state);
200
-
201
- const concurrency = dynamicStep.concurrency ?? MAX_PARALLEL_CONCURRENCY;
202
- const failFast = dynamicStep.failFast ?? false;
203
- let aborted = false;
204
- const parallelResults = await mapConcurrent(dynamicSteps, concurrency, async (task, taskIdx) => {
205
- const fi = groupStartFlatIndex + taskIdx;
206
- if (aborted && failFast) {
207
- const skippedAt = Date.now();
208
- statusPayload.steps[fi].status = "failed";
209
- statusPayload.steps[fi].error = "Skipped due to fail-fast";
210
- statusPayload.steps[fi].startedAt = skippedAt;
211
- statusPayload.steps[fi].endedAt = skippedAt;
212
- statusPayload.steps[fi].durationMs = 0;
213
- statusPayload.steps[fi].exitCode = -1;
214
- statusPayload.lastUpdate = skippedAt;
215
- writeStatusPayload(state);
216
- return { agent: task.agent, output: "(skipped — fail-fast)", exitCode: -1 as number | null, skipped: true };
217
- }
218
- const taskStartTime = Date.now();
219
- statusPayload.currentStep = fi;
220
- statusPayload.steps[fi].status = "running";
221
- statusPayload.steps[fi].error = undefined;
222
- statusPayload.steps[fi].activityState = undefined;
223
- resetStepLiveDetail(statusPayload.steps[fi]);
224
- statusPayload.steps[fi].startedAt = taskStartTime;
225
- statusPayload.steps[fi].lastActivityAt = taskStartTime;
226
- statusPayload.outputFile = path.join(asyncDir, `output-${fi}.log`);
227
- statusPayload.lastActivityAt = taskStartTime;
228
- statusPayload.lastUpdate = taskStartTime;
229
- writeStatusPayload(state);
230
- appendJsonl(
231
- state.eventsPath,
232
- JSON.stringify({
233
- type: "subagent.step.started",
234
- ts: taskStartTime,
235
- runId: id,
236
- stepIndex: fi,
237
- agent: task.agent,
238
- }),
239
- );
240
- const singleResult = await runSingleStep(task, {
241
- previousOutput: state.previousOutput,
242
- placeholder,
243
- cwd,
244
- sessionEnabled,
245
- outputs,
246
- sessionDir: config.sessionDir ? path.join(config.sessionDir, `dynamic-${stepIndex}-${taskIdx}`) : undefined,
247
- artifactsDir,
248
- artifactConfig,
249
- id,
250
- flatIndex: fi,
251
- flatStepCount: Math.max(statusPayload.steps.length, 1),
252
- outputFile: path.join(asyncDir, `output-${fi}.log`),
253
- piPackageRoot: config.piPackageRoot,
254
- piArgv1: config.piArgv1,
255
- childIntercomTarget: config.childIntercomTargets?.[fi],
256
- orchestratorIntercomTarget: config.controlIntercomTarget,
257
- supervisorAuthorization: config.supervisorAuthorizations?.[fi],
258
- nestedRoute: config.nestedRoute,
259
- registerInterrupt: (interrupt) => {
260
- state.activeChildInterrupt = interrupt;
261
- },
262
- onAttemptStart: (attempt) => updateStepModel(state, fi, attempt.model, attempt.thinking),
263
- onChildEvent: (event) => updateStepFromChildEvent(state, fi, event),
264
- });
265
- const taskEndTime = Date.now();
266
- statusPayload.steps[fi].status = singleResult.exitCode === 0 ? "complete" : "failed";
267
- statusPayload.steps[fi].endedAt = taskEndTime;
268
- statusPayload.steps[fi].durationMs = taskEndTime - taskStartTime;
269
- statusPayload.steps[fi].exitCode = singleResult.exitCode;
270
- statusPayload.steps[fi].model = singleResult.model;
271
- statusPayload.steps[fi].thinking = resolveEffectiveThinking(singleResult.model, statusPayload.steps[fi].thinking);
272
- statusPayload.steps[fi].attemptedModels = singleResult.attemptedModels;
273
- statusPayload.steps[fi].modelAttempts = singleResult.modelAttempts;
274
- statusPayload.steps[fi].error = singleResult.error;
275
- statusPayload.steps[fi].structuredOutput = singleResult.structuredOutput;
276
- statusPayload.steps[fi].structuredOutputPath = singleResult.structuredOutputPath;
277
- statusPayload.steps[fi].structuredOutputSchemaPath = singleResult.structuredOutputSchemaPath;
278
- statusPayload.lastUpdate = taskEndTime;
279
- writeStatusPayload(state);
280
- appendJsonl(
281
- state.eventsPath,
282
- JSON.stringify({
283
- type: singleResult.exitCode === 0 ? "subagent.step.completed" : "subagent.step.failed",
284
- ts: taskEndTime,
285
- runId: id,
286
- stepIndex: fi,
287
- agent: task.agent,
288
- exitCode: singleResult.exitCode,
289
- durationMs: taskEndTime - taskStartTime,
290
- }),
291
- );
292
- if (singleResult.exitCode !== 0 && failFast) aborted = true;
293
- return { ...singleResult, skipped: false };
294
- });
295
-
296
- state.flatIndex += dynamicSteps.length;
297
- for (const pr of parallelResults)
298
- state.results.push({
299
- agent: pr.agent,
300
- output: pr.output,
301
- error: pr.error,
302
- success: pr.exitCode === 0,
303
- exitCode: pr.exitCode,
304
- skipped: pr.skipped,
305
- sessionFile: pr.sessionFile,
306
- intercomTarget: pr.intercomTarget,
307
- model: pr.model,
308
- attemptedModels: pr.attemptedModels,
309
- modelAttempts: pr.modelAttempts,
310
- artifactPaths: pr.artifactPaths,
311
- structuredOutput: pr.structuredOutput,
312
- structuredOutputPath: pr.structuredOutputPath,
313
- structuredOutputSchemaPath: pr.structuredOutputSchemaPath,
314
- });
315
- const collection = collectDynamicResults(
316
- dynamicStep as Parameters<typeof collectDynamicResults>[0],
317
- materialized.items,
318
- parallelResults as Parameters<typeof collectDynamicResults>[2],
319
- );
320
- const failures = parallelResults.filter((result) => result.exitCode !== 0 && result.exitCode !== -1);
321
- if (failures.length === 0) {
322
- try {
323
- validateDynamicCollection(dynamicStep.collect.outputSchema, collection);
324
- outputs[dynamicStep.collect.as] = {
325
- text: JSON.stringify(collection),
326
- structured: collection,
327
- agent: parallelTemplate.agent,
328
- stepIndex,
329
- };
330
- statusPayload.outputs = outputs;
331
- markDynamicGraphGroup(state, stepIndex, "completed");
332
- } catch (error) {
333
- const message =
334
- error instanceof DynamicFanoutError
335
- ? error.message
336
- : error instanceof Error
337
- ? error.message
338
- : String(error);
339
- state.results.push({
340
- agent: parallelTemplate.agent,
341
- output: message,
342
- error: message,
343
- success: false,
344
- exitCode: 1,
345
- structuredOutput: collection,
346
- });
347
- statusPayload.error = message;
348
- markDynamicGraphGroup(state, stepIndex, "failed", message);
349
- }
350
- }
351
- state.previousOutput = aggregateParallelOutputs(
352
- parallelResults.map((r, i) => ({
353
- agent: r.agent,
354
- taskIndex: i,
355
- output: r.output,
356
- exitCode: r.exitCode,
357
- error: r.error,
358
- })),
359
- (i, agent) => `=== Dynamic Item ${i + 1} (${agent}, key ${materialized.items[i]?.key ?? i}) ===`,
360
- );
361
- appendJsonl(
362
- state.eventsPath,
363
- JSON.stringify({
364
- type: "subagent.dynamic.completed",
365
- ts: Date.now(),
366
- runId: id,
367
- stepIndex,
368
- success: failures.length === 0,
369
- }),
370
- );
371
- if (failures.length > 0)
372
- markDynamicGraphGroup(state, stepIndex, "failed", failures[0]?.error ?? "Dynamic fanout child failed.");
373
- statusPayload.lastUpdate = Date.now();
374
- writeStatusPayload(state);
375
- return !(failures.length > 0 || statusPayload.error);
376
- }
@@ -1,150 +0,0 @@
1
- import * as path from "node:path";
2
- import { appendJsonl } from "../../shared/artifacts.ts";
3
- import { writeAtomicJson } from "../../shared/atomic-json.ts";
4
- import { DEFAULT_MAX_OUTPUT, truncateOutput } from "../../shared/types.ts";
5
- import { createShareLink, exportSessionHtml, writeRunLog } from "./subagent-runner-output.ts";
6
- import { cleanupActivityTimer, writeStatusPayload } from "./subagent-runner-state.ts";
7
- import type { RunnerExecutionState } from "./subagent-runner-types.ts";
8
- import { findLatestSessionFile } from "./subagent-runner-utils.ts";
9
-
10
- export async function finalizeRun(state: RunnerExecutionState): Promise<void> {
11
- const { config, results, maxOutput, flatSteps, statusPayload, artifactsDir, cwd, asyncDir, id } = state;
12
- let summary = results.map((r) => `${r.agent}:\n${r.output}`).join("\n\n");
13
- let truncated = false;
14
-
15
- if (maxOutput) {
16
- const config = { ...DEFAULT_MAX_OUTPUT, ...maxOutput };
17
- const lastArtifactPath = results[results.length - 1]?.artifactPaths?.outputPath;
18
- const truncResult = truncateOutput(summary, config, lastArtifactPath);
19
- if (truncResult.truncated) {
20
- summary = truncResult.text;
21
- truncated = true;
22
- }
23
- }
24
-
25
- const resultMode = config.resultMode ?? statusPayload.mode;
26
- const agentName =
27
- flatSteps.length === 1
28
- ? flatSteps[0].agent
29
- : resultMode === "parallel"
30
- ? `parallel:${flatSteps.map((s) => s.agent).join("+")}`
31
- : `chain:${flatSteps.map((s) => s.agent).join("->")}`;
32
- let sessionFile: string | undefined;
33
- let shareUrl: string | undefined;
34
- let gistUrl: string | undefined;
35
- let shareError: string | undefined;
36
-
37
- if (state.shareEnabled) {
38
- sessionFile = config.sessionDir ? (findLatestSessionFile(config.sessionDir) ?? undefined) : undefined;
39
- if (!sessionFile && state.latestSessionFile) sessionFile = state.latestSessionFile;
40
- if (sessionFile) {
41
- try {
42
- const exportDir = config.sessionDir ?? path.dirname(sessionFile);
43
- const htmlPath = await exportSessionHtml(sessionFile, exportDir, config.piPackageRoot);
44
- const share = createShareLink(htmlPath);
45
- if ("error" in share) shareError = share.error;
46
- else {
47
- shareUrl = share.shareUrl;
48
- gistUrl = share.gistUrl;
49
- }
50
- } catch (err) {
51
- shareError = String(err);
52
- }
53
- } else {
54
- shareError = "Session file not found.";
55
- }
56
- }
57
-
58
- cleanupActivityTimer(state);
59
- const effectiveSessionFile = sessionFile ?? state.latestSessionFile;
60
- const runEndedAt = Date.now();
61
- statusPayload.state = state.interrupted ? "paused" : results.every((r) => r.success) ? "complete" : "failed";
62
- statusPayload.activityState = undefined;
63
- statusPayload.endedAt = runEndedAt;
64
- statusPayload.lastUpdate = runEndedAt;
65
- statusPayload.sessionFile = effectiveSessionFile;
66
- statusPayload.shareUrl = shareUrl;
67
- statusPayload.gistUrl = gistUrl;
68
- statusPayload.shareError = shareError;
69
- if (statusPayload.state === "failed" && !statusPayload.error) {
70
- const failedStep = statusPayload.steps.find((s) => s.status === "failed");
71
- if (failedStep?.agent) statusPayload.error = `Step failed: ${failedStep.agent}`;
72
- }
73
- writeStatusPayload(state);
74
- appendJsonl(
75
- state.eventsPath,
76
- JSON.stringify({
77
- type: "subagent.run.completed",
78
- ts: runEndedAt,
79
- runId: id,
80
- status: statusPayload.state,
81
- durationMs: runEndedAt - state.overallStartTime,
82
- }),
83
- );
84
- writeRunLog(state.logPath, {
85
- id,
86
- mode: statusPayload.mode,
87
- cwd,
88
- startedAt: state.overallStartTime,
89
- endedAt: runEndedAt,
90
- steps: statusPayload.steps.map((step) => ({
91
- agent: step.agent,
92
- status: step.status,
93
- durationMs: step.durationMs,
94
- })),
95
- summary,
96
- truncated,
97
- artifactsDir,
98
- sessionFile: effectiveSessionFile,
99
- shareUrl,
100
- shareError,
101
- });
102
-
103
- try {
104
- writeAtomicJson(state.resultPath, {
105
- id,
106
- agent: agentName,
107
- mode: resultMode,
108
- success: !state.interrupted && results.every((r) => r.success),
109
- state: state.interrupted ? "paused" : results.every((r) => r.success) ? "complete" : "failed",
110
- summary: state.interrupted ? "Paused after interrupt. Waiting for explicit next action." : summary,
111
- results: results.map((r) => ({
112
- agent: r.agent,
113
- output: r.output,
114
- error: r.error,
115
- success: r.success,
116
- skipped: r.skipped || undefined,
117
- sessionFile: r.sessionFile,
118
- intercomTarget: r.intercomTarget,
119
- model: r.model,
120
- fastMode: r.fastMode,
121
- attemptedModels: r.attemptedModels,
122
- modelAttempts: r.modelAttempts,
123
- artifactPaths: r.artifactPaths,
124
- truncated: r.truncated,
125
- structuredOutput: r.structuredOutput,
126
- structuredOutputPath: r.structuredOutputPath,
127
- structuredOutputSchemaPath: r.structuredOutputSchemaPath,
128
- })),
129
- outputs: state.outputs,
130
- workflowGraph: statusPayload.workflowGraph,
131
- exitCode: state.interrupted || results.every((r) => r.success) ? 0 : 1,
132
- timestamp: runEndedAt,
133
- durationMs: runEndedAt - state.overallStartTime,
134
- truncated,
135
- artifactsDir,
136
- cwd,
137
- asyncDir,
138
- sessionId: config.sessionId,
139
- sessionFile: effectiveSessionFile,
140
- intercomTarget: config.controlIntercomTarget,
141
- shareUrl,
142
- gistUrl,
143
- shareError,
144
- ...(state.taskIndex !== undefined && { taskIndex: state.taskIndex }),
145
- ...(state.totalTasks !== undefined && { totalTasks: state.totalTasks }),
146
- });
147
- } catch (err) {
148
- console.error(`Failed to write result file ${state.resultPath}:`, err);
149
- }
150
- }
@@ -1,109 +0,0 @@
1
- import { spawnSync } from "node:child_process";
2
- import * as fs from "node:fs";
3
- import * as path from "node:path";
4
- import { pathToFileURL } from "node:url";
5
- import type { SubagentRunMode } from "../../shared/types.ts";
6
- import { PI_CODING_AGENT_PACKAGE, resolveInstalledPiPackageRoot } from "../shared/pi-spawn.ts";
7
- import { formatDuration } from "./subagent-runner-utils.ts";
8
-
9
- function resolvePiPackageRootFallback(): string {
10
- const root = resolveInstalledPiPackageRoot();
11
- if (root) return root;
12
- throw new Error(`Could not resolve ${PI_CODING_AGENT_PACKAGE} package root`);
13
- }
14
-
15
- export async function exportSessionHtml(
16
- sessionFile: string,
17
- outputDir: string,
18
- piPackageRoot?: string,
19
- ): Promise<string> {
20
- const pkgRoot = piPackageRoot ?? resolvePiPackageRootFallback();
21
- const exportModulePath = path.join(pkgRoot, "dist", "core", "export-html", "index.js");
22
- const moduleUrl = pathToFileURL(exportModulePath).href;
23
- const mod = await import(moduleUrl);
24
- const exportFromFile = (mod as { exportFromFile?: (inputPath: string, options?: { outputPath?: string }) => string })
25
- .exportFromFile;
26
- if (typeof exportFromFile !== "function") {
27
- throw new Error("exportFromFile not available");
28
- }
29
- const outputPath = path.join(outputDir, `${path.basename(sessionFile, ".jsonl")}.html`);
30
- return exportFromFile(sessionFile, { outputPath });
31
- }
32
-
33
- export function createShareLink(htmlPath: string): { shareUrl: string; gistUrl: string } | { error: string } {
34
- try {
35
- const auth = spawnSync("gh", ["auth", "status"], { encoding: "utf-8" });
36
- if (auth.status !== 0) {
37
- return { error: "GitHub CLI is not logged in. Run 'gh auth login' first." };
38
- }
39
- } catch {
40
- return { error: "GitHub CLI (gh) is not installed." };
41
- }
42
-
43
- try {
44
- const result = spawnSync("gh", ["gist", "create", htmlPath], { encoding: "utf-8" });
45
- if (result.status !== 0) {
46
- const err = (result.stderr || "").trim() || "Failed to create gist.";
47
- return { error: err };
48
- }
49
- const gistUrl = (result.stdout || "").trim();
50
- const gistId = gistUrl.split("/").pop();
51
- if (!gistId) return { error: "Failed to parse gist ID." };
52
- const shareUrl = `https://shittycodingagent.ai/session/?${gistId}`;
53
- return { shareUrl, gistUrl };
54
- } catch (err) {
55
- return { error: String(err) };
56
- }
57
- }
58
-
59
- export function writeRunLog(
60
- logPath: string,
61
- input: {
62
- id: string;
63
- mode: SubagentRunMode;
64
- cwd: string;
65
- startedAt: number;
66
- endedAt: number;
67
- steps: Array<{
68
- agent: string;
69
- status: string;
70
- durationMs?: number;
71
- }>;
72
- summary: string;
73
- truncated: boolean;
74
- artifactsDir?: string;
75
- sessionFile?: string;
76
- shareUrl?: string;
77
- shareError?: string;
78
- },
79
- ): void {
80
- const lines: string[] = [];
81
- lines.push(`# Subagent run ${input.id}`);
82
- lines.push("");
83
- lines.push(`- **Mode:** ${input.mode}`);
84
- lines.push(`- **CWD:** ${input.cwd}`);
85
- lines.push(`- **Started:** ${new Date(input.startedAt).toISOString()}`);
86
- lines.push(`- **Ended:** ${new Date(input.endedAt).toISOString()}`);
87
- lines.push(`- **Duration:** ${formatDuration(input.endedAt - input.startedAt)}`);
88
- if (input.sessionFile) lines.push(`- **Session:** ${input.sessionFile}`);
89
- if (input.shareUrl) lines.push(`- **Share:** ${input.shareUrl}`);
90
- if (input.shareError) lines.push(`- **Share error:** ${input.shareError}`);
91
- if (input.artifactsDir) lines.push(`- **Artifacts:** ${input.artifactsDir}`);
92
- lines.push("");
93
- lines.push("## Steps");
94
- lines.push("| Step | Agent | Status | Duration |");
95
- lines.push("| --- | --- | --- | --- |");
96
- input.steps.forEach((step, i) => {
97
- const duration = step.durationMs !== undefined ? formatDuration(step.durationMs) : "-";
98
- lines.push(`| ${i + 1} | ${step.agent} | ${step.status} | ${duration} |`);
99
- });
100
- lines.push("");
101
- lines.push("## Summary");
102
- if (input.truncated) {
103
- lines.push("_Output truncated_");
104
- lines.push("");
105
- }
106
- lines.push(input.summary.trim() || "(no output)");
107
- lines.push("");
108
- fs.writeFileSync(logPath, lines.join("\n"), "utf-8");
109
- }