@selesai/code 0.12.0 → 0.13.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 (466) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/core/agent-session.d.ts +1 -1
  3. package/dist/core/agent-session.js +1 -1
  4. package/dist/core/sdk.d.ts +2 -2
  5. package/dist/core/sdk.js +1 -1
  6. package/dist/core/system-prompt.d.ts +1 -1
  7. package/dist/core/system-prompt.js +1 -1
  8. package/dist/core/usage-totals.d.ts +2 -0
  9. package/dist/core/usage-totals.js +10 -0
  10. package/dist/extensions/ascii.txt +9 -0
  11. package/dist/extensions/package.json +1 -2
  12. package/dist/extensions/pi-hermes-memory/CHANGELOG.md +371 -0
  13. package/dist/extensions/pi-hermes-memory/LICENSE +21 -0
  14. package/dist/extensions/pi-hermes-memory/README.md +643 -0
  15. package/dist/extensions/pi-hermes-memory/docs/0.1/TASKS.md +197 -0
  16. package/dist/extensions/pi-hermes-memory/docs/0.2/PLAN.md +290 -0
  17. package/dist/extensions/pi-hermes-memory/docs/0.2/TASKS.md +134 -0
  18. package/dist/extensions/pi-hermes-memory/docs/0.2/TEST-PLAN.md +216 -0
  19. package/dist/extensions/pi-hermes-memory/docs/0.3/PLAN.md +330 -0
  20. package/dist/extensions/pi-hermes-memory/docs/0.3/TASKS.md +125 -0
  21. package/dist/extensions/pi-hermes-memory/docs/0.4/PLAN.md +160 -0
  22. package/dist/extensions/pi-hermes-memory/docs/0.4/TASKS.md +113 -0
  23. package/dist/extensions/pi-hermes-memory/docs/0.6/CHANGELOG.md +57 -0
  24. package/dist/extensions/pi-hermes-memory/docs/0.6/PLAN.md +202 -0
  25. package/dist/extensions/pi-hermes-memory/docs/0.6/TASKS.md +144 -0
  26. package/dist/extensions/pi-hermes-memory/docs/0.7/PLAN.md +349 -0
  27. package/dist/extensions/pi-hermes-memory/docs/0.7/TASKS.md +110 -0
  28. package/dist/extensions/pi-hermes-memory/docs/PUBLISHING.md +149 -0
  29. package/dist/extensions/pi-hermes-memory/docs/ROADMAP.md +468 -0
  30. package/dist/extensions/pi-hermes-memory/docs/images/memory-architecture.svg +1 -0
  31. package/dist/extensions/pi-hermes-memory/docs/images/pi-logo.svg +22 -0
  32. package/dist/extensions/pi-hermes-memory/docs/images/pi_memory.png +0 -0
  33. package/dist/extensions/pi-hermes-memory/docs/images/pi_memory.svg +19 -0
  34. package/dist/extensions/pi-hermes-memory/docs/images/security-flow.svg +1 -0
  35. package/dist/extensions/pi-hermes-memory/docs/images/session-lifecycle.svg +1 -0
  36. package/dist/extensions/pi-hermes-memory/docs/images/source-architecture.svg +1 -0
  37. package/dist/extensions/pi-hermes-memory/docs/mermaid/memory-architecture.mmd +49 -0
  38. package/dist/extensions/pi-hermes-memory/docs/mermaid/security-flow.mmd +40 -0
  39. package/dist/extensions/pi-hermes-memory/docs/mermaid/session-lifecycle.mmd +56 -0
  40. package/dist/extensions/pi-hermes-memory/docs/mermaid/source-architecture.mmd +54 -0
  41. package/dist/extensions/pi-hermes-memory/package-lock.json +3799 -0
  42. package/dist/extensions/pi-hermes-memory/package.json +66 -0
  43. package/dist/extensions/pi-hermes-memory/scripts/check-min-sdk.mjs +99 -0
  44. package/dist/extensions/pi-hermes-memory/scripts/ensure-dev.mjs +57 -0
  45. package/dist/extensions/pi-hermes-memory/src/auto-consolidation-warning.ts +6 -0
  46. package/dist/extensions/pi-hermes-memory/src/config.ts +178 -0
  47. package/dist/extensions/pi-hermes-memory/src/constants.ts +424 -0
  48. package/dist/extensions/pi-hermes-memory/src/extension-root-migration.ts +639 -0
  49. package/dist/extensions/pi-hermes-memory/src/handlers/auto-consolidate.ts +401 -0
  50. package/dist/extensions/pi-hermes-memory/src/handlers/background-review.ts +297 -0
  51. package/dist/extensions/pi-hermes-memory/src/handlers/child-process-watchdog.mjs +90 -0
  52. package/dist/extensions/pi-hermes-memory/src/handlers/correction-detector.ts +300 -0
  53. package/dist/extensions/pi-hermes-memory/src/handlers/index-sessions.ts +86 -0
  54. package/dist/extensions/pi-hermes-memory/src/handlers/insights.ts +78 -0
  55. package/dist/extensions/pi-hermes-memory/src/handlers/interview.ts +37 -0
  56. package/dist/extensions/pi-hermes-memory/src/handlers/learn-memory.ts +186 -0
  57. package/dist/extensions/pi-hermes-memory/src/handlers/message-parts.ts +27 -0
  58. package/dist/extensions/pi-hermes-memory/src/handlers/pi-child-process.ts +485 -0
  59. package/dist/extensions/pi-hermes-memory/src/handlers/preview-context.ts +105 -0
  60. package/dist/extensions/pi-hermes-memory/src/handlers/review-memory-ops.ts +506 -0
  61. package/dist/extensions/pi-hermes-memory/src/handlers/session-backfill.ts +145 -0
  62. package/dist/extensions/pi-hermes-memory/src/handlers/session-flush.ts +151 -0
  63. package/dist/extensions/pi-hermes-memory/src/handlers/session-live-index.ts +94 -0
  64. package/dist/extensions/pi-hermes-memory/src/handlers/skills-command.ts +1334 -0
  65. package/dist/extensions/pi-hermes-memory/src/handlers/standing-pin.ts +111 -0
  66. package/dist/extensions/pi-hermes-memory/src/handlers/switch-project.ts +75 -0
  67. package/dist/extensions/pi-hermes-memory/src/handlers/sync-markdown-memories.ts +266 -0
  68. package/dist/extensions/pi-hermes-memory/src/index.ts +378 -0
  69. package/dist/extensions/pi-hermes-memory/src/lifecycle-timing.ts +54 -0
  70. package/dist/extensions/pi-hermes-memory/src/paths.ts +61 -0
  71. package/dist/extensions/pi-hermes-memory/src/project-context.ts +13 -0
  72. package/dist/extensions/pi-hermes-memory/src/project-memory-migration.ts +93 -0
  73. package/dist/extensions/pi-hermes-memory/src/project.ts +157 -0
  74. package/dist/extensions/pi-hermes-memory/src/prompt-context.ts +55 -0
  75. package/dist/extensions/pi-hermes-memory/src/store/atomic-lock-coordinator.ts +375 -0
  76. package/dist/extensions/pi-hermes-memory/src/store/canonical-storage-path.ts +54 -0
  77. package/dist/extensions/pi-hermes-memory/src/store/content-scanner.ts +101 -0
  78. package/dist/extensions/pi-hermes-memory/src/store/db.ts +1180 -0
  79. package/dist/extensions/pi-hermes-memory/src/store/fts-query.ts +101 -0
  80. package/dist/extensions/pi-hermes-memory/src/store/markdown-mutation-lock.ts +38 -0
  81. package/dist/extensions/pi-hermes-memory/src/store/memory-lookup.ts +24 -0
  82. package/dist/extensions/pi-hermes-memory/src/store/memory-store.ts +1191 -0
  83. package/dist/extensions/pi-hermes-memory/src/store/recovery-maintenance.ts +66 -0
  84. package/dist/extensions/pi-hermes-memory/src/store/schema.ts +118 -0
  85. package/dist/extensions/pi-hermes-memory/src/store/session-anchor-search.ts +472 -0
  86. package/dist/extensions/pi-hermes-memory/src/store/session-indexer.ts +511 -0
  87. package/dist/extensions/pi-hermes-memory/src/store/session-parser.ts +213 -0
  88. package/dist/extensions/pi-hermes-memory/src/store/session-search.ts +234 -0
  89. package/dist/extensions/pi-hermes-memory/src/store/skill-store.ts +950 -0
  90. package/dist/extensions/pi-hermes-memory/src/store/skill-utils.ts +133 -0
  91. package/dist/extensions/pi-hermes-memory/src/store/sqlite-memory-store.ts +1002 -0
  92. package/dist/extensions/pi-hermes-memory/src/store/sqlite-native.ts +241 -0
  93. package/dist/extensions/pi-hermes-memory/src/store/standing-instructions.ts +247 -0
  94. package/dist/extensions/pi-hermes-memory/src/tools/memory-search-tool.ts +95 -0
  95. package/dist/extensions/pi-hermes-memory/src/tools/memory-tool.ts +469 -0
  96. package/dist/extensions/pi-hermes-memory/src/tools/session-search-tool.ts +246 -0
  97. package/dist/extensions/pi-hermes-memory/src/tools/shared-output-view.ts +170 -0
  98. package/dist/extensions/pi-hermes-memory/src/tools/skill-tool.ts +333 -0
  99. package/dist/extensions/pi-hermes-memory/src/tools/tool-result-views.ts +105 -0
  100. package/dist/extensions/pi-hermes-memory/src/types.ts +214 -0
  101. package/dist/extensions/pi-hermes-memory/tests/config.test.ts +434 -0
  102. package/dist/extensions/pi-hermes-memory/tests/extension-root-migration.test.ts +368 -0
  103. package/dist/extensions/pi-hermes-memory/tests/handlers/auto-consolidate.test.ts +984 -0
  104. package/dist/extensions/pi-hermes-memory/tests/handlers/background-review.test.ts +950 -0
  105. package/dist/extensions/pi-hermes-memory/tests/handlers/correction-detector.test.ts +671 -0
  106. package/dist/extensions/pi-hermes-memory/tests/handlers/insights.test.ts +157 -0
  107. package/dist/extensions/pi-hermes-memory/tests/handlers/interview.test.ts +127 -0
  108. package/dist/extensions/pi-hermes-memory/tests/handlers/pi-child-process.test.ts +905 -0
  109. package/dist/extensions/pi-hermes-memory/tests/handlers/preview-context.test.ts +152 -0
  110. package/dist/extensions/pi-hermes-memory/tests/handlers/prompt-context.test.ts +166 -0
  111. package/dist/extensions/pi-hermes-memory/tests/handlers/resources-discover.test.ts +71 -0
  112. package/dist/extensions/pi-hermes-memory/tests/handlers/review-memory-ops.test.ts +614 -0
  113. package/dist/extensions/pi-hermes-memory/tests/handlers/session-backfill.test.ts +192 -0
  114. package/dist/extensions/pi-hermes-memory/tests/handlers/session-flush.test.ts +677 -0
  115. package/dist/extensions/pi-hermes-memory/tests/handlers/session-live-index.test.ts +225 -0
  116. package/dist/extensions/pi-hermes-memory/tests/handlers/skills-command.test.ts +827 -0
  117. package/dist/extensions/pi-hermes-memory/tests/handlers/standing-pin.test.ts +134 -0
  118. package/dist/extensions/pi-hermes-memory/tests/handlers/sync-markdown-memories.test.ts +491 -0
  119. package/dist/extensions/pi-hermes-memory/tests/handlers/system-prompt.test.ts +199 -0
  120. package/dist/extensions/pi-hermes-memory/tests/handlers/thinking-max.test.ts +64 -0
  121. package/dist/extensions/pi-hermes-memory/tests/index.test.ts +30 -0
  122. package/dist/extensions/pi-hermes-memory/tests/integration/flow.test.ts +126 -0
  123. package/dist/extensions/pi-hermes-memory/tests/lifecycle-timing.test.ts +76 -0
  124. package/dist/extensions/pi-hermes-memory/tests/paths.test.ts +23 -0
  125. package/dist/extensions/pi-hermes-memory/tests/project-memory-migration.test.ts +80 -0
  126. package/dist/extensions/pi-hermes-memory/tests/project-rebinding.test.ts +115 -0
  127. package/dist/extensions/pi-hermes-memory/tests/project.test.ts +120 -0
  128. package/dist/extensions/pi-hermes-memory/tests/run-all-timeout.test.ts +107 -0
  129. package/dist/extensions/pi-hermes-memory/tests/run-all.sh +45 -0
  130. package/dist/extensions/pi-hermes-memory/tests/store/atomic-lock-coordinator.test.ts +381 -0
  131. package/dist/extensions/pi-hermes-memory/tests/store/content-scanner.test.ts +388 -0
  132. package/dist/extensions/pi-hermes-memory/tests/store/db.test.ts +1046 -0
  133. package/dist/extensions/pi-hermes-memory/tests/store/markdown-mutation-lock.test.ts +34 -0
  134. package/dist/extensions/pi-hermes-memory/tests/store/memory-store.test.ts +2150 -0
  135. package/dist/extensions/pi-hermes-memory/tests/store/recovery-maintenance.test.ts +170 -0
  136. package/dist/extensions/pi-hermes-memory/tests/store/session-anchor-search.test.ts +210 -0
  137. package/dist/extensions/pi-hermes-memory/tests/store/session-indexer.test.ts +643 -0
  138. package/dist/extensions/pi-hermes-memory/tests/store/session-parser.test.ts +282 -0
  139. package/dist/extensions/pi-hermes-memory/tests/store/session-search.test.ts +287 -0
  140. package/dist/extensions/pi-hermes-memory/tests/store/skill-store.test.ts +678 -0
  141. package/dist/extensions/pi-hermes-memory/tests/store/skill-utils.test.ts +21 -0
  142. package/dist/extensions/pi-hermes-memory/tests/store/sqlite-lazy-load.test.ts +78 -0
  143. package/dist/extensions/pi-hermes-memory/tests/store/sqlite-memory-store.test.ts +543 -0
  144. package/dist/extensions/pi-hermes-memory/tests/store/sqlite-native.test.ts +164 -0
  145. package/dist/extensions/pi-hermes-memory/tests/store/standing-instructions.test.ts +171 -0
  146. package/dist/extensions/pi-hermes-memory/tests/tools/memory-search-tool.test.ts +84 -0
  147. package/dist/extensions/pi-hermes-memory/tests/tools/memory-tool.test.ts +709 -0
  148. package/dist/extensions/pi-hermes-memory/tests/tools/session-search-tool.test.ts +345 -0
  149. package/dist/extensions/pi-hermes-memory/tests/tools/shared-output-view.test.ts +362 -0
  150. package/dist/extensions/pi-hermes-memory/tests/tools/skill-tool.test.ts +478 -0
  151. package/dist/extensions/pi-hermes-memory/tests/tools/tool-result-renderer-wiring.test.ts +40 -0
  152. package/dist/extensions/pi-hermes-memory/tsconfig.json +19 -0
  153. package/dist/extensions/pi-subagents/.oxlintrc.json +43 -0
  154. package/dist/extensions/pi-subagents/AGENTS.md +5 -0
  155. package/dist/extensions/pi-subagents/CHANGELOG.md +157 -0
  156. package/dist/extensions/pi-subagents/README.md +12 -6
  157. package/dist/extensions/pi-subagents/VISION.md +81 -0
  158. package/dist/extensions/pi-subagents/agents/claude-code-writer.md +15 -0
  159. package/dist/extensions/pi-subagents/agents/claude-code.md +15 -0
  160. package/dist/extensions/pi-subagents/agents/codex-exec-writer.md +15 -0
  161. package/dist/extensions/pi-subagents/agents/codex-exec.md +15 -0
  162. package/dist/extensions/pi-subagents/agents/cursor-agent-writer.md +14 -0
  163. package/dist/extensions/pi-subagents/agents/cursor-agent.md +14 -0
  164. package/dist/extensions/pi-subagents/agents/reviewer.md +1 -3
  165. package/dist/extensions/pi-subagents/docs/agents.md +488 -0
  166. package/dist/extensions/pi-subagents/docs/configuration.md +46 -9
  167. package/dist/extensions/pi-subagents/docs/extension-api.md +42 -3
  168. package/dist/extensions/pi-subagents/docs/models.md +27 -4
  169. package/dist/extensions/pi-subagents/docs/observability.md +10 -9
  170. package/dist/extensions/pi-subagents/docs/tool-reference.md +102 -6
  171. package/dist/extensions/pi-subagents/docs/workflows.md +135 -0
  172. package/dist/extensions/pi-subagents/package-lock.json +389 -2
  173. package/dist/extensions/pi-subagents/package.json +3 -1
  174. package/dist/extensions/pi-subagents/prompts/review-loop.md +2 -2
  175. package/dist/extensions/pi-subagents/skills/council-mode/SKILL.md +1 -1
  176. package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +3 -1
  177. package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +7 -3
  178. package/dist/extensions/pi-subagents/skills/pi-subagents/references/management-authoring-rpc.md +2 -2
  179. package/dist/extensions/pi-subagents/skills/pi-subagents/references/prompting-and-roles.md +26 -5
  180. package/dist/extensions/pi-subagents/src/agents/agent-management.ts +41 -22
  181. package/dist/extensions/pi-subagents/src/agents/agent-refinements.ts +4 -4
  182. package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +9 -2
  183. package/dist/extensions/pi-subagents/src/agents/agents.ts +322 -75
  184. package/dist/extensions/pi-subagents/src/agents/builtin-names.ts +6 -0
  185. package/dist/extensions/pi-subagents/src/agents/runtime-agent-events.ts +70 -0
  186. package/dist/extensions/pi-subagents/src/agents/runtime-agent-registry.ts +27 -20
  187. package/dist/extensions/pi-subagents/src/api/agents.ts +10 -5
  188. package/dist/extensions/pi-subagents/src/api/background-work.ts +5 -1
  189. package/dist/extensions/pi-subagents/src/api/delegation.ts +0 -7
  190. package/dist/extensions/pi-subagents/src/api/preflight.ts +34 -12
  191. package/dist/extensions/pi-subagents/src/extension/config.ts +70 -0
  192. package/dist/extensions/pi-subagents/src/extension/doctor.ts +3 -3
  193. package/dist/extensions/pi-subagents/src/extension/fanout-child.ts +5 -3
  194. package/dist/extensions/pi-subagents/src/extension/index.ts +83 -30
  195. package/dist/extensions/pi-subagents/src/extension/public-execution.ts +44 -15
  196. package/dist/extensions/pi-subagents/src/extension/rpc.ts +55 -19
  197. package/dist/extensions/pi-subagents/src/extension/schemas.ts +41 -15
  198. package/dist/extensions/pi-subagents/src/extension/tool-description.ts +28 -31
  199. package/dist/extensions/pi-subagents/src/inspectors/herdr/actions.ts +2 -1
  200. package/dist/extensions/pi-subagents/src/inspectors/herdr/inspector-runner.ts +2 -10
  201. package/dist/extensions/pi-subagents/src/inspectors/herdr/session-roots-codec.ts +42 -0
  202. package/dist/extensions/pi-subagents/src/integrations/herdr-status.ts +51 -3
  203. package/dist/extensions/pi-subagents/src/intercom/result-intercom.ts +2 -0
  204. package/dist/extensions/pi-subagents/src/profiles/profiles.ts +5 -6
  205. package/dist/extensions/pi-subagents/src/runs/background/active-async-capacity.ts +77 -10
  206. package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +176 -53
  207. package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +19 -12
  208. package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +29 -27
  209. package/dist/extensions/pi-subagents/src/runs/background/async-retention.ts +20 -3
  210. package/dist/extensions/pi-subagents/src/runs/background/async-status-snapshot.ts +23 -261
  211. package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +73 -7
  212. package/dist/extensions/pi-subagents/src/runs/background/chain-append.ts +8 -3
  213. package/dist/extensions/pi-subagents/src/runs/background/chain-root-attachment.ts +74 -8
  214. package/dist/extensions/pi-subagents/src/runs/background/fleet-view.ts +37 -21
  215. package/dist/extensions/pi-subagents/src/runs/background/inspect-rpc.ts +8 -8
  216. package/dist/extensions/pi-subagents/src/runs/background/notify.ts +184 -9
  217. package/dist/extensions/pi-subagents/src/runs/background/result-delivery-ownership.ts +45 -0
  218. package/dist/extensions/pi-subagents/src/runs/background/result-files.ts +28 -14
  219. package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +38 -15
  220. package/dist/extensions/pi-subagents/src/runs/background/resume-guidance.ts +1 -1
  221. package/dist/extensions/pi-subagents/src/runs/background/retained-children.ts +1 -1
  222. package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +50 -13
  223. package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +93 -8
  224. package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +10 -4
  225. package/dist/extensions/pi-subagents/src/runs/background/steering.ts +4 -14
  226. package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +549 -377
  227. package/dist/extensions/pi-subagents/src/runs/background/subagent-wait.ts +58 -10
  228. package/dist/extensions/pi-subagents/src/runs/background/terminal-run-index.ts +1 -1
  229. package/dist/extensions/pi-subagents/src/runs/background/wait-completions.ts +26 -1
  230. package/dist/extensions/pi-subagents/src/runs/background/wait-config.ts +23 -9
  231. package/dist/extensions/pi-subagents/src/runs/background/wait-tool.ts +9 -2
  232. package/dist/extensions/pi-subagents/src/runs/foreground/async-steering-action.ts +2 -2
  233. package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +204 -129
  234. package/dist/extensions/pi-subagents/src/runs/foreground/foreground-control.ts +9 -0
  235. package/dist/extensions/pi-subagents/src/runs/foreground/foreground-history.ts +23 -1
  236. package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +773 -311
  237. package/dist/extensions/pi-subagents/src/runs/foreground/workflow-detach-reconcile.ts +140 -115
  238. package/dist/extensions/pi-subagents/src/runs/shared/abort-recovery.ts +119 -0
  239. package/dist/extensions/pi-subagents/src/runs/shared/async-status-projection.ts +463 -0
  240. package/dist/extensions/pi-subagents/src/runs/shared/child-identity.ts +19 -4
  241. package/dist/extensions/pi-subagents/src/runs/shared/child-launch-plan.ts +151 -0
  242. package/dist/extensions/pi-subagents/src/runs/shared/child-protocol.ts +21 -7
  243. package/dist/extensions/pi-subagents/src/runs/shared/claude-code-adapter.ts +129 -0
  244. package/dist/extensions/pi-subagents/src/runs/shared/codex-exec-adapter.ts +129 -0
  245. package/dist/extensions/pi-subagents/src/runs/shared/completion-evidence.ts +89 -0
  246. package/dist/extensions/pi-subagents/src/runs/shared/completion-guard.ts +5 -4
  247. package/dist/extensions/pi-subagents/src/runs/shared/cursor-agent-adapter.ts +114 -0
  248. package/dist/extensions/pi-subagents/src/runs/shared/dynamic-fanout.ts +3 -3
  249. package/dist/extensions/pi-subagents/src/runs/shared/external-cli-contract.ts +167 -0
  250. package/dist/extensions/pi-subagents/src/runs/shared/external-cli-preflight.ts +122 -0
  251. package/dist/extensions/pi-subagents/src/runs/shared/external-cli-runner.ts +348 -55
  252. package/dist/extensions/pi-subagents/src/runs/shared/fast-mode-extension.ts +5 -5
  253. package/dist/extensions/pi-subagents/src/runs/shared/host-step-status.ts +230 -0
  254. package/dist/extensions/pi-subagents/src/runs/shared/lane-metadata.ts +105 -0
  255. package/dist/extensions/pi-subagents/src/runs/shared/launch-cwd.ts +16 -0
  256. package/dist/extensions/pi-subagents/src/runs/shared/long-running-guard.ts +2 -1
  257. package/dist/extensions/pi-subagents/src/runs/shared/mcp-config-sources.ts +422 -0
  258. package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +221 -158
  259. package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-grant.ts +197 -0
  260. package/dist/extensions/pi-subagents/src/runs/shared/model-exclusions.ts +69 -7
  261. package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +47 -6
  262. package/dist/extensions/pi-subagents/src/runs/shared/mutation-evidence.ts +7 -2
  263. package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +9 -3
  264. package/dist/extensions/pi-subagents/src/runs/shared/nested-render.ts +9 -5
  265. package/dist/extensions/pi-subagents/src/runs/shared/parallel-handoff.ts +419 -7
  266. package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +15 -1
  267. package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +81 -8
  268. package/dist/extensions/pi-subagents/src/runs/shared/process-signal.ts +13 -0
  269. package/dist/extensions/pi-subagents/src/runs/shared/run-history.ts +21 -1
  270. package/dist/extensions/pi-subagents/src/runs/shared/single-output.ts +44 -4
  271. package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +98 -13
  272. package/dist/extensions/pi-subagents/src/runs/shared/subagent-startup-retry.ts +1 -1
  273. package/dist/extensions/pi-subagents/src/runs/shared/worktree-cleanup-plan.ts +847 -0
  274. package/dist/extensions/pi-subagents/src/runs/shared/worktree.ts +18 -0
  275. package/dist/extensions/pi-subagents/src/shared/child-session-name.ts +46 -0
  276. package/dist/extensions/pi-subagents/src/shared/extension-context.ts +24 -0
  277. package/dist/extensions/pi-subagents/src/shared/fork-context.ts +21 -0
  278. package/dist/extensions/pi-subagents/src/shared/formatters.ts +18 -3
  279. package/dist/extensions/pi-subagents/src/shared/launch-contract.ts +5 -1
  280. package/dist/extensions/pi-subagents/src/shared/pruned-fork.ts +450 -0
  281. package/dist/extensions/pi-subagents/src/shared/session-file-trust.ts +19 -0
  282. package/dist/extensions/pi-subagents/src/shared/session-tokens.ts +14 -3
  283. package/dist/extensions/pi-subagents/src/shared/settings.ts +19 -105
  284. package/dist/extensions/pi-subagents/src/shared/shortcuts.ts +17 -0
  285. package/dist/extensions/pi-subagents/src/shared/types.ts +359 -40
  286. package/dist/extensions/pi-subagents/src/shared/utils.ts +41 -84
  287. package/dist/extensions/pi-subagents/src/shared/workflow-child-permit.ts +116 -0
  288. package/dist/extensions/pi-subagents/src/slash/delegation-adapters.ts +1 -9
  289. package/dist/extensions/pi-subagents/src/slash/delegation-request.ts +0 -4
  290. package/dist/extensions/pi-subagents/src/slash/slash-bridge.ts +1 -2
  291. package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +378 -88
  292. package/dist/extensions/pi-subagents/src/slash/slash-live-state.ts +22 -11
  293. package/dist/extensions/pi-subagents/src/slash/subagents-admin.ts +3 -0
  294. package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +147 -79
  295. package/dist/extensions/pi-subagents/src/tui/fleet-transcript.ts +11 -5
  296. package/dist/extensions/pi-subagents/src/tui/fleet.ts +39 -18
  297. package/dist/extensions/pi-subagents/src/tui/render.ts +369 -46
  298. package/dist/extensions/pi-subagents/src/watchdog/turn-delta.ts +1 -1
  299. package/dist/extensions/pi-subagents/src/workflows/chat-progress.ts +6 -3
  300. package/dist/extensions/pi-subagents/src/workflows/host-command.ts +230 -0
  301. package/dist/extensions/pi-subagents/src/workflows/scripted-workflow.ts +740 -58
  302. package/dist/extensions/pi-subagents/src/workflows/workflow-child-summary.ts +121 -0
  303. package/dist/extensions/pi-subagents/src/workflows/workflow-preflight.ts +270 -0
  304. package/dist/extensions/pi-subagents/src/workflows/workflow-receipt.ts +195 -6
  305. package/dist/extensions/pi-subagents/src/workflows/workflow-settlement.ts +246 -0
  306. package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +2 -2
  307. package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +1114 -260
  308. package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +34 -0
  309. package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +150 -3
  310. package/dist/extensions/pi-subagents/test/integration/claude-code-smoke.test.ts +52 -0
  311. package/dist/extensions/pi-subagents/test/integration/claude-code-writer-smoke.test.ts +55 -0
  312. package/dist/extensions/pi-subagents/test/integration/codex-exec-smoke.test.ts +53 -0
  313. package/dist/extensions/pi-subagents/test/integration/codex-exec-writer-smoke.test.ts +57 -0
  314. package/dist/extensions/pi-subagents/test/integration/cursor-agent-smoke.test.ts +59 -0
  315. package/dist/extensions/pi-subagents/test/integration/cursor-agent-writer-smoke.test.ts +62 -0
  316. package/dist/extensions/pi-subagents/test/integration/error-handling.test.ts +57 -1
  317. package/dist/extensions/pi-subagents/test/integration/external-cli-runner.test.ts +1 -0
  318. package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +20 -0
  319. package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +4 -3
  320. package/dist/extensions/pi-subagents/test/integration/orca-progress-tabs.test.ts +2 -2
  321. package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +54 -4
  322. package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +482 -4
  323. package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +157 -9
  324. package/dist/extensions/pi-subagents/test/integration/session-tokens.test.ts +5 -5
  325. package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +1508 -291
  326. package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +423 -1
  327. package/dist/extensions/pi-subagents/test/integration/template-resolution.test.ts +8 -0
  328. package/dist/extensions/pi-subagents/test/support/cursor-smoke-inputs.ts +51 -0
  329. package/dist/extensions/pi-subagents/test/support/helpers.ts +2 -0
  330. package/dist/extensions/pi-subagents/test/support/mock-pi.ts +5 -5
  331. package/dist/extensions/pi-subagents/test/support/real-session-runner.ts +6 -6
  332. package/dist/extensions/pi-subagents/test/unit/abort-recovery.test.ts +152 -0
  333. package/dist/extensions/pi-subagents/test/unit/active-async-capacity.test.ts +48 -0
  334. package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +184 -6
  335. package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +66 -6
  336. package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +77 -0
  337. package/dist/extensions/pi-subagents/test/unit/agent-refinements.test.ts +18 -0
  338. package/dist/extensions/pi-subagents/test/unit/anti-slop-oxlint.test.ts +86 -0
  339. package/dist/extensions/pi-subagents/test/unit/artifacts.test.ts +1 -1
  340. package/dist/extensions/pi-subagents/test/unit/async-execution.test.ts +101 -1
  341. package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +121 -0
  342. package/dist/extensions/pi-subagents/test/unit/async-recovery-descriptor.test.ts +28 -0
  343. package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +14 -7
  344. package/dist/extensions/pi-subagents/test/unit/async-retention.test.ts +53 -0
  345. package/dist/extensions/pi-subagents/test/unit/async-status-projection.test.ts +190 -0
  346. package/dist/extensions/pi-subagents/test/unit/async-status-snapshot.test.ts +42 -0
  347. package/dist/extensions/pi-subagents/test/unit/auto-drain.test.ts +8 -4
  348. package/dist/extensions/pi-subagents/test/unit/background-work.test.ts +23 -0
  349. package/dist/extensions/pi-subagents/test/unit/chain-root-attachment.test.ts +78 -1
  350. package/dist/extensions/pi-subagents/test/unit/child-launch-plan.test.ts +94 -0
  351. package/dist/extensions/pi-subagents/test/unit/child-protocol.test.ts +21 -0
  352. package/dist/extensions/pi-subagents/test/unit/child-session-name.test.ts +50 -0
  353. package/dist/extensions/pi-subagents/test/unit/claude-code-adapter.test.ts +245 -0
  354. package/dist/extensions/pi-subagents/test/unit/codex-exec-adapter.test.ts +192 -0
  355. package/dist/extensions/pi-subagents/test/unit/compaction-resume.test.ts +27 -0
  356. package/dist/extensions/pi-subagents/test/unit/completion-evidence.test.ts +150 -0
  357. package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +21 -0
  358. package/dist/extensions/pi-subagents/test/unit/cursor-agent-adapter.test.ts +259 -0
  359. package/dist/extensions/pi-subagents/test/unit/cursor-smoke-inputs.test.ts +77 -0
  360. package/dist/extensions/pi-subagents/test/unit/delegation-api.test.ts +1 -4
  361. package/dist/extensions/pi-subagents/test/unit/doctor.test.ts +1 -1
  362. package/dist/extensions/pi-subagents/test/unit/extension-context.test.ts +27 -0
  363. package/dist/extensions/pi-subagents/test/unit/external-cli-runner.test.ts +223 -0
  364. package/dist/extensions/pi-subagents/test/unit/fast-mode-extension.test.ts +27 -0
  365. package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +208 -2
  366. package/dist/extensions/pi-subagents/test/unit/fleet-transcript.test.ts +29 -1
  367. package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +110 -1
  368. package/dist/extensions/pi-subagents/test/unit/foreground-control.test.ts +10 -0
  369. package/dist/extensions/pi-subagents/test/unit/formatters.test.ts +14 -0
  370. package/dist/extensions/pi-subagents/test/unit/herdr-inspector.test.ts +18 -9
  371. package/dist/extensions/pi-subagents/test/unit/herdr-session-roots-codec.test.ts +63 -0
  372. package/dist/extensions/pi-subagents/test/unit/herdr-shell-command.test.ts +2 -2
  373. package/dist/extensions/pi-subagents/test/unit/herdr-status-bridge.test.ts +132 -0
  374. package/dist/extensions/pi-subagents/test/unit/host-command.test.ts +156 -0
  375. package/dist/extensions/pi-subagents/test/unit/host-step-status.test.ts +98 -0
  376. package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +178 -26
  377. package/dist/extensions/pi-subagents/test/unit/index-segment.test.ts +2 -1
  378. package/dist/extensions/pi-subagents/test/unit/inspect-rpc.test.ts +21 -0
  379. package/dist/extensions/pi-subagents/test/unit/mcp-direct-tool-grant.test.ts +138 -0
  380. package/dist/extensions/pi-subagents/test/unit/mission-lifecycle.test.ts +1 -1
  381. package/dist/extensions/pi-subagents/test/unit/model-exclusions.test.ts +91 -0
  382. package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +72 -7
  383. package/dist/extensions/pi-subagents/test/unit/mutation-evidence.test.ts +21 -0
  384. package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +1 -0
  385. package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +20 -2
  386. package/dist/extensions/pi-subagents/test/unit/notify.test.ts +129 -1
  387. package/dist/extensions/pi-subagents/test/unit/orca-progress-tabs.test.ts +2 -2
  388. package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +4 -0
  389. package/dist/extensions/pi-subagents/test/unit/parallel-handoff.test.ts +358 -0
  390. package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +574 -21
  391. package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +109 -1
  392. package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +71 -1
  393. package/dist/extensions/pi-subagents/test/unit/profiles.test.ts +7 -7
  394. package/dist/extensions/pi-subagents/test/unit/pruned-fork.test.ts +214 -0
  395. package/dist/extensions/pi-subagents/test/unit/public-execution.test.ts +29 -8
  396. package/dist/extensions/pi-subagents/test/unit/render-helpers.test.ts +53 -0
  397. package/dist/extensions/pi-subagents/test/unit/result-delivery-ownership.test.ts +34 -0
  398. package/dist/extensions/pi-subagents/test/unit/result-files.test.ts +101 -3
  399. package/dist/extensions/pi-subagents/test/unit/retained-children.test.ts +1 -0
  400. package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +10 -8
  401. package/dist/extensions/pi-subagents/test/unit/run-fanout-budget.test.ts +71 -1
  402. package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +41 -7
  403. package/dist/extensions/pi-subagents/test/unit/runtime-agent-registration.test.ts +136 -2
  404. package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +137 -0
  405. package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +33 -12
  406. package/dist/extensions/pi-subagents/test/unit/scripted-workflow.test.ts +504 -1
  407. package/dist/extensions/pi-subagents/test/unit/single-output.test.ts +8 -0
  408. package/dist/extensions/pi-subagents/test/unit/skills-fallback.test.ts +1 -1
  409. package/dist/extensions/pi-subagents/test/unit/stale-run-reconciler.test.ts +12 -1
  410. package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +3 -5
  411. package/dist/extensions/pi-subagents/test/unit/steering.test.ts +5 -6
  412. package/dist/extensions/pi-subagents/test/unit/subagent-action-recovery.test.ts +0 -8
  413. package/dist/extensions/pi-subagents/test/unit/subagent-guide.test.ts +5 -0
  414. package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +157 -2
  415. package/dist/extensions/pi-subagents/test/unit/subagent-startup-retry.test.ts +1 -1
  416. package/dist/extensions/pi-subagents/test/unit/subagent-wait.test.ts +63 -4
  417. package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +27 -23
  418. package/dist/extensions/pi-subagents/test/unit/wait-completions.test.ts +44 -0
  419. package/dist/extensions/pi-subagents/test/unit/wait-subscriptions.test.ts +1 -0
  420. package/dist/extensions/pi-subagents/test/unit/widget-nested-render.test.ts +7 -5
  421. package/dist/extensions/pi-subagents/test/unit/workflow-chat-progress.test.ts +106 -0
  422. package/dist/extensions/pi-subagents/test/unit/workflow-detach-reconcile.test.ts +484 -9
  423. package/dist/extensions/pi-subagents/test/unit/workflow-launch-params.test.ts +38 -4
  424. package/dist/extensions/pi-subagents/test/unit/workflow-preflight.test.ts +155 -0
  425. package/dist/extensions/pi-subagents/test/unit/workflow-receipt.test.ts +318 -0
  426. package/dist/extensions/pi-subagents/test/unit/workflow-resume-hint.test.ts +365 -0
  427. package/dist/extensions/pi-subagents/test/unit/worktree-cleanup-plan.test.ts +349 -0
  428. package/dist/extensions/pi-subagents/test/unit/worktree.test.ts +21 -0
  429. package/dist/extensions/pi-subagents/test/unit/writer-budget-guidance.test.ts +2 -7
  430. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/effect/index.ts +13 -0
  431. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/effect/rules/no-service-constructor-imports.ts +52 -0
  432. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/index.ts +41 -0
  433. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-chained-type-assertions.ts +77 -0
  434. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-conditional-empty-object-spread.ts +49 -0
  435. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-known-value-widening.ts +247 -0
  436. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-module-mocking.ts +91 -0
  437. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-object-parameters.ts +126 -0
  438. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-reflect-apply.ts +28 -0
  439. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-reflect-get.ts +28 -0
  440. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-runtime-typeof.ts +67 -0
  441. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-shape-in-symbol-names.ts +39 -0
  442. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-unknown-parameters.ts +83 -0
  443. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-unknown-returns.ts +115 -0
  444. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-unknown-type-aliases.ts +72 -0
  445. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-unsafe-dictionary-type.ts +134 -0
  446. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/no-widen-then-assert.ts +366 -0
  447. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/rules/require-safety-comment-for-type-assertion.ts +62 -0
  448. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/shared/dictionary-types.ts +502 -0
  449. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/shared/lexical-type-parameters.ts +60 -0
  450. package/dist/extensions/pi-subagents/tools/oxlint/anti-slop/shared/reflect-method.ts +35 -0
  451. package/dist/extensions/pi-tool-display/tests/capabilities.test.ts +1 -1
  452. package/dist/extensions/pi-tool-display/tests/settings-inspector.test.ts +2 -2
  453. package/dist/extensions/pi-tool-display/tests/tool-overrides-mcp.test.ts +1 -1
  454. package/dist/extensions/pi-zentui/extensions/zentui/format.ts +2 -1
  455. package/dist/extensions/pi-zentui/test/format.test.ts +15 -1
  456. package/dist/modes/interactive/components/footer.js +2 -2
  457. package/dist/modes/interactive/interactive-mode.js +11 -11
  458. package/dist/skills/workflow/SKILL.md +65 -50
  459. package/package.json +112 -110
  460. package/dist/extensions/enable-readonly-tools.test.ts +0 -63
  461. package/dist/extensions/enable-readonly-tools.ts +0 -24
  462. package/dist/extensions/model-prompt-injector/config.json +0 -16
  463. package/dist/extensions/model-prompt-injector/index.test.ts +0 -102
  464. package/dist/extensions/model-prompt-injector/index.ts +0 -148
  465. package/dist/extensions/pi-subagents/src/runs/shared/turn-budget.ts +0 -98
  466. package/dist/extensions/pi-subagents/test/unit/turn-budget.test.ts +0 -250
@@ -9,76 +9,50 @@ import {
9
9
  type IntercomEventBus,
10
10
  type SingleResult,
11
11
  type SubagentState,
12
+ type WorkflowTerminalResolution,
12
13
  } from "../../shared/types.ts";
13
14
  import { updateActiveRunIndex } from "../background/active-run-index.ts";
14
15
  import { resultFilePath, writeAsyncResultFile } from "../background/result-files.ts";
15
16
  import { resolveAsyncResumeTarget } from "../background/async-resume.ts";
17
+ import { externalCliReceiptMetadata, normalizeExternalCliRunnerStatus } from "../shared/external-cli-contract.ts";
18
+ import { outputPathMappingFromTask } from "../shared/single-output.ts";
16
19
  import { readWorkflowReceipt, workflowReceiptPath, writeWorkflowReceipt, type WorkflowReceipt } from "../../workflows/workflow-receipt.ts";
17
-
18
- function cloneWorkflowStatus(status: AsyncStatus): AsyncStatus {
19
- return {
20
- ...status,
21
- steps: status.steps?.map((step) => ({ ...step })),
22
- workflow: status.workflow ? { ...status.workflow, trace: [...(status.workflow.trace ?? [])] } : status.workflow,
23
- };
24
- }
25
-
26
- function childSucceeded(result: Pick<SingleResult, "exitCode" | "error" | "interrupted">): boolean {
27
- return result.exitCode === 0 && !result.error && !result.interrupted;
28
- }
29
-
30
- const UNSUPPORTED_DETACHED_WORKFLOW_CONTINUATION = "unsupported-continuation: detached workflow child settled, but JavaScript workflow continuation was not persisted. Resume the workflow explicitly instead of treating the completed child as top-level workflow completion.";
31
- const INTERRUPTED_DETACHED_CHILD = "Interrupted. Waiting for explicit next action.";
20
+ import {
21
+ applyDetachedChildSettlement,
22
+ classifyWorkflowSettlement,
23
+ findWorkflowSettlementStep,
24
+ planWorkflowSettlement,
25
+ promoteSettledPausedWorkflow,
26
+ workflowOutputPathMappingSummary,
27
+ workflowRecoveryActions,
28
+ workflowTerminalOutcomeForResult,
29
+ type WorkflowPublicChild,
30
+ type WorkflowStatusStep,
31
+ } from "../../workflows/workflow-settlement.ts";
32
32
 
33
33
  export function applyDetachedChildToPausedWorkflow(
34
34
  status: AsyncStatus,
35
- input: { childRunId: string; result: Pick<SingleResult, "exitCode" | "error" | "interrupted" | "sessionFile">; workflowKey?: string },
35
+ input: { childRunId: string; result: Pick<SingleResult, "exitCode" | "error" | "interrupted" | "sessionFile" | "sessionName" | "stopped">; workflowKey?: string },
36
36
  ): AsyncStatus | undefined {
37
- if (status.mode !== "workflow" || status.state !== "paused") return undefined;
38
- const next = cloneWorkflowStatus(status);
39
- const step = next.steps?.find((candidate) => candidate.runId === input.childRunId)
40
- ?? (input.workflowKey ? next.steps?.find((candidate) => candidate.workflowKey === input.workflowKey) : undefined);
41
- if (!step) return undefined;
42
- const succeeded = childSucceeded(input.result);
43
- const failedSiblingError = next.steps?.find((candidate) => candidate !== step && candidate.status === "failed" && candidate.error)?.error;
44
- const updatedAt = Date.now();
45
- step.status = succeeded ? "completed" : "failed";
46
- step.endedAt = updatedAt;
47
- delete step.activityState;
48
- delete step.currentTool;
49
- delete step.currentToolStartedAt;
50
- if (input.result.sessionFile) step.sessionFile = input.result.sessionFile;
51
- if (succeeded) delete step.error;
52
- else if (input.result.interrupted) step.error = input.result.error ?? INTERRUPTED_DETACHED_CHILD;
53
- else if (input.result.error) step.error = input.result.error;
54
- next.lastUpdate = updatedAt;
55
- const promoted = promotePausedWorkflowIfSettled(next);
56
- if (promoted?.state === "failed" && input.result.interrupted && !failedSiblingError) promoted.error = input.result.error ?? INTERRUPTED_DETACHED_CHILD;
57
- else if (promoted?.state === "failed" && input.result.error) promoted.error = input.result.error;
58
- return promoted ?? next;
37
+ return applyDetachedChildSettlement(status, input);
59
38
  }
60
39
 
61
40
  export function promotePausedWorkflowIfSettled(status: AsyncStatus): AsyncStatus | undefined {
62
- if (status.mode !== "workflow" || status.state !== "paused") return undefined;
63
- const next = cloneWorkflowStatus(status);
64
- const stillOpen = next.steps?.some((candidate) =>
65
- candidate.status === "running"
66
- || (candidate.status === "paused" && candidate.activityState === "needs_attention")
67
- ) === true;
68
- if (stillOpen || !next.steps?.length) return undefined;
69
- const failed = next.steps.some((candidate) => candidate.status === "failed");
70
- const updatedAt = Date.now();
71
- next.lastUpdate = updatedAt;
72
- next.state = "failed";
73
- next.endedAt = updatedAt;
74
- delete next.activityState;
75
- if (failed) return next;
76
- next.error = UNSUPPORTED_DETACHED_WORKFLOW_CONTINUATION;
77
- return next;
41
+ return promoteSettledPausedWorkflow(status);
78
42
  }
79
43
 
80
- function workflowResultChildren(status: AsyncStatus, childRunId: string, result: SingleResult, existingResults: unknown): unknown {
44
+ function usageWithValue(usage: SingleResult["usage"] | undefined): SingleResult["usage"] | undefined {
45
+ return usage && (usage.input !== 0 || usage.output !== 0 || usage.cacheRead !== 0 || usage.cacheWrite !== 0 || usage.cost !== 0 || usage.turns !== 0)
46
+ ? usage
47
+ : undefined;
48
+ }
49
+
50
+ function workflowResultChildren(status: AsyncStatus, childRunId: string, result: SingleResult, existingResults: unknown, receipt?: WorkflowReceipt): unknown {
81
51
  const output = getSingleResultOutput(result);
52
+ const outputReference = result.savedOutputPath ?? result.outputReference?.path;
53
+ const outputPathMapping = outputPathMappingFromTask(result.task, outputReference);
54
+ const terminalOutcome = workflowTerminalOutcomeForResult(result);
55
+ const usage = usageWithValue(result.usage);
82
56
  if (Array.isArray(existingResults)) {
83
57
  return existingResults.map((entry) => {
84
58
  if (!entry || typeof entry !== "object" || Array.isArray(entry)) return entry;
@@ -86,61 +60,45 @@ function workflowResultChildren(status: AsyncStatus, childRunId: string, result:
86
60
  if (child.runId !== childRunId) return child;
87
61
  return {
88
62
  ...child,
89
- success: childSucceeded(result),
63
+ success: result.exitCode === 0 && !result.error && !result.interrupted,
90
64
  output,
91
65
  outputState: output.trim() ? "present" : "absent",
92
66
  detached: undefined,
93
- ...(result.interrupted ? { interrupted: true } : {}),
67
+ ...(usage ? { usage } : {}),
68
+ ...(outputReference ? { outputReference } : {}),
69
+ ...(outputPathMapping ? { outputPathMapping } : {}),
70
+ ...(result.interrupted || result.stopped ? { interrupted: true } : {}),
71
+ ...(result.stopped ? { stopped: true } : {}),
72
+ ...(terminalOutcome ? { terminalOutcome } : {}),
73
+ ...(result.sessionName ? { sessionName: result.sessionName } : {}),
74
+ ...(result.sessionFile ? { sessionFile: result.sessionFile } : {}),
94
75
  ...(result.error ? { error: result.error } : {}),
95
76
  };
96
77
  });
97
78
  }
98
- return status.steps?.map((step) => ({
79
+ return status.steps?.map((step: WorkflowStatusStep) => ({
99
80
  workflowKey: step.workflowKey,
100
81
  agent: step.agent,
82
+ ...(step.sessionName ? { sessionName: step.sessionName } : {}),
101
83
  runId: step.runId,
102
84
  success: step.status === "completed" || step.status === "complete",
103
85
  output: step.runId === childRunId ? output : "",
104
86
  outputState: step.runId === childRunId && output.trim() ? "present" : "absent",
105
- ...(step.runId === childRunId && result.interrupted ? { interrupted: true } : {}),
87
+ ...(step.runId === childRunId ? { ...(usage ? { usage } : {}), ...(result.sessionFile ? { sessionFile: result.sessionFile } : {}) } : {}),
88
+ ...(step.runId === childRunId && outputReference ? { outputReference } : step.workflowKey && receipt?.entries[step.workflowKey]?.outputReference ? { outputReference: receipt.entries[step.workflowKey]!.outputReference } : {}),
89
+ ...(step.runId === childRunId && outputPathMapping ? { outputPathMapping } : step.outputPathMapping ? { outputPathMapping: step.outputPathMapping } : {}),
90
+ ...(step.interrupted ? { interrupted: true } : {}),
91
+ ...(step.runId === childRunId && terminalOutcome ? { terminalOutcome } : step.workflowKey && receipt?.entries[step.workflowKey]?.terminalOutcome ? { terminalOutcome: receipt.entries[step.workflowKey]!.terminalOutcome } : {}),
92
+ ...(step.stopped ? { stopped: true } : {}),
106
93
  ...(step.error ? { error: step.error } : {}),
107
94
  }));
108
95
  }
109
96
 
110
- function publishedWorkflowResult(status: AsyncStatus, childRunId: string, result: SingleResult, asyncDir: string, existing?: Record<string, unknown>, receipt?: WorkflowReceipt): Record<string, unknown> {
111
- const sessionId = status.sessionId ?? (typeof existing?.sessionId === "string" ? existing.sessionId : undefined);
112
- const summary = status.state === "complete"
113
- ? `Workflow completed after detached child ${childRunId} finished.`
114
- : status.error ?? (typeof existing?.summary === "string" ? existing.summary : undefined);
115
- return {
116
- ...(existing ?? {}),
117
- id: status.runId,
118
- runId: status.runId,
119
- toolCallId: status.toolCallId,
120
- agent: "workflow",
121
- mode: "workflow",
122
- success: status.state === "complete",
123
- state: status.state,
124
- summary,
125
- error: status.error,
126
- activityState: status.activityState,
127
- endedAt: status.endedAt,
128
- timestamp: Date.now(),
129
- results: workflowResultChildren(status, childRunId, result, existing?.results),
130
- workflow: status.workflow,
131
- reconciledFromDetachedChild: childRunId,
132
- ...(receipt ? { workflowReceipt: { path: path.join(asyncDir, "workflow-receipt.json"), receipt } } : {}),
133
- asyncDir,
134
- cwd: status.cwd,
135
- sessionId,
136
- completionOwnerId: status.completionOwnerId,
137
- };
138
- }
139
-
140
- function reconcileWorkflowReceipt(status: AsyncStatus, childRunId: string, result: SingleResult, asyncDir: string): WorkflowReceipt | undefined {
141
- const receiptPath = workflowReceiptPath(DIRS.async, status.runId);
97
+ function reconcileWorkflowReceipt(status: AsyncStatus, childRunId: string, result: SingleResult, asyncDir: string, resolution: WorkflowTerminalResolution | undefined): WorkflowReceipt | undefined {
98
+ const receiptRoot = path.dirname(asyncDir);
99
+ const receiptPath = workflowReceiptPath(receiptRoot, status.runId);
142
100
  if (!fs.existsSync(receiptPath)) return undefined;
143
- const receipt = readWorkflowReceipt(DIRS.async, status.runId);
101
+ const receipt = readWorkflowReceipt(receiptRoot, status.runId);
144
102
  const step = status.steps?.find((candidate) => candidate.runId === childRunId);
145
103
  const key = step?.workflowKey;
146
104
  if (!key) throw new Error(`Workflow receipt '${status.runId}' cannot identify detached child '${childRunId}' by stable key.`);
@@ -154,6 +112,13 @@ function reconcileWorkflowReceipt(status: AsyncStatus, childRunId: string, resul
154
112
  resumability = { state: "not-resumable", reason: error instanceof Error ? error.message : String(error) };
155
113
  }
156
114
  const outputReference = result.savedOutputPath ?? result.outputReference?.path ?? entry.outputReference;
115
+ const childStatus = readStatus(path.join(DIRS.async, childRunId));
116
+ const externalStep = childStatus?.steps?.length === 1 && childStatus.steps[0]?.runner?.type === "external-cli" ? childStatus.steps[0] : undefined;
117
+ const externalRunner = normalizeExternalCliRunnerStatus(result.runner?.type === "external-cli" ? result.runner : externalStep?.runner);
118
+ const externalProcess = result.externalProcess ?? externalStep?.externalProcess;
119
+ const externalAdapter = externalRunner ? externalCliReceiptMetadata({ runner: externalRunner, externalProcess, outputReference }) : entry.externalAdapter;
120
+ const childTerminalOutcome = workflowTerminalOutcomeForResult(result) ?? entry.terminalOutcome;
121
+ if (externalAdapter) resumability = { state: "not-resumable", reason: externalAdapter.nonResumableReason };
157
122
  const updatedEntry: WorkflowReceipt["entries"][string] = resumability.state === "resumable"
158
123
  ? {
159
124
  ...entry,
@@ -162,6 +127,8 @@ function reconcileWorkflowReceipt(status: AsyncStatus, childRunId: string, resul
162
127
  latestRunId: entry.latestRunId ?? childRunId,
163
128
  resumability,
164
129
  ...(outputReference ? { outputReference } : {}),
130
+ ...(childTerminalOutcome ? { terminalOutcome: childTerminalOutcome } : {}),
131
+ ...(externalAdapter ? { externalAdapter } : {}),
165
132
  }
166
133
  : {
167
134
  ...entry,
@@ -169,6 +136,8 @@ function reconcileWorkflowReceipt(status: AsyncStatus, childRunId: string, resul
169
136
  ...(step.context ? { resolvedContext: step.context } : {}),
170
137
  resumability,
171
138
  ...(outputReference ? { outputReference } : {}),
139
+ ...(childTerminalOutcome ? { terminalOutcome: childTerminalOutcome } : {}),
140
+ ...(externalAdapter ? { externalAdapter } : {}),
172
141
  };
173
142
  const next: WorkflowReceipt = {
174
143
  ...receipt,
@@ -177,7 +146,15 @@ function reconcileWorkflowReceipt(status: AsyncStatus, childRunId: string, resul
177
146
  ...receipt.entries,
178
147
  [key]: updatedEntry,
179
148
  },
149
+ workflowChildren: status.workflowChildren,
150
+ ...(receipt.terminalOutcome ? { terminalOutcome: receipt.terminalOutcome } : {}),
151
+ ...(resolution ? { workflowResolution: resolution } : {}),
180
152
  };
153
+ if (resolution) next.recovery = workflowRecoveryActions(next);
154
+ else {
155
+ delete next.workflowResolution;
156
+ delete next.recovery;
157
+ }
181
158
  writeWorkflowReceipt(asyncDir, next);
182
159
  return next;
183
160
  }
@@ -203,21 +180,26 @@ export function reconcileDetachedWorkflowChildCompletion(input: {
203
180
  const asyncDir = job?.asyncDir ?? path.join(DIRS.async, input.workflowRunId);
204
181
  const status = readStatus(asyncDir);
205
182
  if (!status) return false;
183
+ const matchingControls = input.workflowKey === undefined ? [] : [...(input.state.foregroundControls?.values() ?? [])].filter((control) =>
184
+ control.parentWorkflowRunId === input.workflowRunId && control.workflowKey === input.workflowKey
185
+ );
186
+ const confirmedLiveIdentity = matchingControls.length === 1 && matchingControls[0]?.runId === input.childRunId;
187
+ if (confirmedLiveIdentity) {
188
+ const candidates = status.steps?.filter((candidate) => candidate.workflowKey === input.workflowKey) ?? [];
189
+ const candidate = candidates.length === 1 ? candidates[0] : undefined;
190
+ if (candidate && candidate.runId === undefined && candidate.sessionFile === undefined
191
+ && candidate.status === "paused" && candidate.activityState === "needs_attention") candidate.runId = input.childRunId;
192
+ }
206
193
  const next = applyDetachedChildToPausedWorkflow(status, {
207
194
  childRunId: input.childRunId,
208
195
  result: input.result,
209
196
  workflowKey: input.workflowKey,
210
197
  });
211
198
  if (!next) return false;
212
- writeAtomicJson(path.join(asyncDir, "status.json"), next);
213
- updateActiveRunIndex(asyncDir, next.state, next.toolCallId);
214
- if (job) {
215
- job.status = next.state;
216
- job.updatedAt = next.lastUpdate;
217
- job.activityState = next.activityState;
218
- job.steps = next.steps?.map((step, index) => ({ ...step, index }));
219
- job.workflow = next.workflow;
220
- }
199
+ const outputReference = input.result.savedOutputPath ?? input.result.outputReference?.path;
200
+ const outputPathMapping = outputPathMappingFromTask(input.result.task, outputReference);
201
+ const settledStep = findWorkflowSettlementStep(next, input.childRunId);
202
+ if (settledStep && outputPathMapping) settledStep.outputPathMapping = outputPathMapping;
221
203
  const resultPath = resultFilePath(DIRS.results, input.workflowRunId);
222
204
  let existing: Record<string, unknown> | undefined;
223
205
  try {
@@ -228,13 +210,55 @@ export function reconcileDetachedWorkflowChildCompletion(input: {
228
210
  }
229
211
  let receipt: WorkflowReceipt | undefined;
230
212
  let receiptError: string | undefined;
213
+ const resolution = classifyWorkflowSettlement(next, input.result.interrupted);
231
214
  try {
232
- receipt = reconcileWorkflowReceipt(next, input.childRunId, input.result, asyncDir);
215
+ receipt = reconcileWorkflowReceipt(next, input.childRunId, input.result, asyncDir, resolution);
233
216
  } catch (error) {
234
217
  receiptError = `Failed to reconcile async workflow receipt: ${error instanceof Error ? error.message : String(error)}`;
235
218
  }
236
- const published = publishedWorkflowResult(next, input.childRunId, input.result, asyncDir, existing, receipt);
237
- writeAsyncResultFile(resultPath, published);
219
+ const results = workflowResultChildren(next, input.childRunId, input.result, existing?.results, receipt) as WorkflowPublicChild[];
220
+ const recovery = workflowRecoveryActions(receipt);
221
+ const summary = `${resolution === "settled-awaiting-resume"
222
+ ? `Workflow lanes settled after detached child ${input.childRunId} finished. JavaScript workflow continuation was not persisted.${recovery.length ? " Use the listed keyed recovery action to continue a child." : " No retained child is resumable."}`
223
+ : next.state === "complete"
224
+ ? `Workflow completed after detached child ${input.childRunId} finished.`
225
+ : next.error ?? (typeof existing?.summary === "string" ? existing.summary : "Workflow failed.")}${workflowOutputPathMappingSummary(results)}`;
226
+ const plan = planWorkflowSettlement({
227
+ status: next,
228
+ summary,
229
+ children: results,
230
+ baseResult: {
231
+ ...(existing ?? {}),
232
+ id: next.runId,
233
+ runId: next.runId,
234
+ toolCallId: next.toolCallId,
235
+ agent: "workflow",
236
+ mode: "workflow",
237
+ endedAt: next.endedAt,
238
+ workflow: next.workflow,
239
+ reconciledFromDetachedChild: input.childRunId,
240
+ asyncDir,
241
+ cwd: next.cwd,
242
+ sessionId: next.sessionId ?? (typeof existing?.sessionId === "string" ? existing.sessionId : undefined),
243
+ completionOwnerId: next.completionOwnerId,
244
+ },
245
+ receipt,
246
+ receiptPath: path.join(asyncDir, "workflow-receipt.json"),
247
+ receiptPersistenceError: receiptError,
248
+ resolution,
249
+ terminalOutcome: receipt?.terminalOutcome,
250
+ eventMetadata: { reconciledFromDetachedChild: input.childRunId },
251
+ });
252
+ writeAtomicJson(path.join(asyncDir, "status.json"), plan.status);
253
+ updateActiveRunIndex(asyncDir, plan.status.state, plan.status.toolCallId);
254
+ if (job) {
255
+ job.status = plan.status.state;
256
+ job.updatedAt = plan.status.lastUpdate;
257
+ job.activityState = plan.status.activityState;
258
+ job.steps = plan.status.steps?.map((step, index) => ({ ...step, index }));
259
+ job.workflow = plan.status.workflow;
260
+ }
261
+ writeAsyncResultFile(resultPath, plan.publicResult);
238
262
  if (receiptError) {
239
263
  appendDetachedWorkflowEvent(asyncDir, {
240
264
  ts: Date.now(),
@@ -244,14 +268,12 @@ export function reconcileDetachedWorkflowChildCompletion(input: {
244
268
  reconciledFromDetachedChild: input.childRunId,
245
269
  });
246
270
  }
247
- if (next.state === "complete" || next.state === "failed") {
271
+ if (plan.completionEvent) {
248
272
  appendDetachedWorkflowEvent(asyncDir, {
249
273
  ts: Date.now(),
250
274
  runId: input.workflowRunId,
251
- type: "subagent.workflow.completed",
252
- state: next.state,
253
- ...(next.error ? { error: next.error } : {}),
254
- reconciledFromDetachedChild: input.childRunId,
275
+ ...plan.completionEvent,
276
+ recovery: plan.recovery,
255
277
  });
256
278
  input.events?.emit(SUBAGENT_ASYNC_COMPLETE_EVENT, {
257
279
  id: input.workflowRunId,
@@ -259,13 +281,16 @@ export function reconcileDetachedWorkflowChildCompletion(input: {
259
281
  source: "async",
260
282
  mode: "workflow",
261
283
  agent: "workflow",
262
- success: next.state === "complete",
263
- state: next.state,
264
- summary: typeof published.summary === "string" ? published.summary : (next.state === "complete" ? "Workflow completed." : next.error),
284
+ success: plan.status.state === "complete",
285
+ state: plan.status.state,
286
+ ...(resolution ? { workflowResolution: resolution } : {}),
287
+ ...(plan.receipt?.terminalOutcome ? { terminalOutcome: plan.receipt.terminalOutcome } : {}),
288
+ recovery: plan.recovery,
289
+ summary: typeof plan.publicResult.summary === "string" ? plan.publicResult.summary : plan.status.error,
265
290
  reconciledFromDetachedChild: input.childRunId,
266
- ...(Array.isArray(published.results) ? { results: published.results } : {}),
267
- sessionId: next.sessionId,
268
- completionOwnerId: next.completionOwnerId,
291
+ results,
292
+ sessionId: plan.status.sessionId,
293
+ completionOwnerId: plan.status.completionOwnerId,
269
294
  timestamp: Date.now(),
270
295
  triggerTurn: true,
271
296
  });
@@ -0,0 +1,119 @@
1
+ import type { Message } from "@earendil-works/pi-ai";
2
+
3
+ export const ABORT_RECOVERY_PROMPT = "The prior run ended from a provider/transport abort after useful progress. Continue from the current files and transcript. Do not restart. Fix any validation failure or write the required report. Finish with final output.";
4
+
5
+ export type AbortRecoveryPlan =
6
+ | { action: "resume"; prompt: typeof ABORT_RECOVERY_PROMPT }
7
+ | { action: "settle"; reason: string; diagnostic?: string };
8
+
9
+ const PROVIDER_ABORT_PATTERN = /(?:provider|transport|connection|stream|socket|request).*(?:abort|closed|reset|ended|terminated|error|fail)|(?:abort|closed|reset|ended|terminated|error|fail).*(?:provider|transport|connection|stream|socket|request)/i;
10
+ const ABORT_ERROR_PATTERN = /\b(?:operation|request|response|stream|connection|transport|provider)?\s*(?:was\s+)?aborted\b/i;
11
+ const TOOL_FAILURE_PREFIX = /^[\w.:@/-]+ failed (?:(?:\(exit \d+\):)|(?:with exit code \d+))(?:\s|$)/i;
12
+
13
+ function isProviderAbortError(error: string): boolean {
14
+ return !TOOL_FAILURE_PREFIX.test(error.trim()) && (PROVIDER_ABORT_PATTERN.test(error) || ABORT_ERROR_PATTERN.test(error));
15
+ }
16
+
17
+ function record(value: unknown): Record<string, unknown> | undefined {
18
+ return value !== null && typeof value === "object" && !Array.isArray(value)
19
+ ? value as Record<string, unknown>
20
+ : undefined;
21
+ }
22
+
23
+ function contentParts(message: Record<string, unknown>): unknown[] {
24
+ return Array.isArray(message.content) ? message.content : [];
25
+ }
26
+
27
+ function terminalAssistant(messages: readonly Message[]): { message?: Record<string, unknown>; index: number } {
28
+ for (let index = messages.length - 1; index >= 0; index--) {
29
+ const message = record(messages[index]);
30
+ if (message?.role === "assistant") return { message, index };
31
+ }
32
+ return { index: messages.length };
33
+ }
34
+
35
+ function zeroOutputUsage(message: Record<string, unknown>): boolean {
36
+ const usage = record(message.usage);
37
+ return usage !== undefined && (usage.output ?? usage.outputTokens ?? 0) === 0;
38
+ }
39
+
40
+ function hasUsefulProgress(messages: readonly Message[], terminalIndex: number): boolean {
41
+ for (let index = 0; index < terminalIndex; index++) {
42
+ const message = record(messages[index]);
43
+ if (!message) continue;
44
+ if (message.role === "assistant" && contentParts(message).length > 0) return true;
45
+ if (message.role === "toolResult" && message.isError !== true) return true;
46
+ }
47
+ return false;
48
+ }
49
+
50
+ function hasUnresolvedToolCall(messages: readonly Message[]): boolean {
51
+ const pending = new Set<string>();
52
+ for (const rawMessage of messages) {
53
+ const message = record(rawMessage);
54
+ if (!message) continue;
55
+ if (message.role === "assistant") {
56
+ for (const rawPart of contentParts(message)) {
57
+ const part = record(rawPart);
58
+ if (part?.type === "toolCall" && typeof part.id === "string" && part.id) pending.add(part.id);
59
+ }
60
+ } else if (message.role === "toolResult" && typeof message.toolCallId === "string") {
61
+ pending.delete(message.toolCallId);
62
+ }
63
+ }
64
+ return pending.size > 0;
65
+ }
66
+
67
+ export function planAbortRecovery(input: {
68
+ messages: readonly Message[];
69
+ error?: string;
70
+ processSignal?: string | null;
71
+ sessionAvailable: boolean;
72
+ alreadyResumed: boolean;
73
+ stopped?: boolean;
74
+ interrupted?: boolean;
75
+ timedOut?: boolean;
76
+ toolBudgetExhausted?: boolean;
77
+ usageBudgetExhausted?: boolean;
78
+ structuredOutputFailed?: boolean;
79
+ acceptanceFailed?: boolean;
80
+ currentTool?: string;
81
+ afterCompactionSettlement?: boolean;
82
+ }): AbortRecoveryPlan {
83
+ const terminal = terminalAssistant(input.messages);
84
+ const message = terminal.message;
85
+ const terminalError = typeof message?.errorMessage === "string" ? message.errorMessage : undefined;
86
+ const emptyZeroUsageTerminal = message !== undefined
87
+ && contentParts(message).length === 0
88
+ && zeroOutputUsage(message);
89
+ const terminalAssistantAbort = message?.stopReason === "aborted"
90
+ || (message?.stopReason === "error" && terminalError !== undefined && isProviderAbortError(terminalError));
91
+ const abortCandidate = emptyZeroUsageTerminal && terminalAssistantAbort;
92
+ const compactionAbortCandidate = input.afterCompactionSettlement === true && abortCandidate;
93
+ const settle = (reason: string): AbortRecoveryPlan => ({
94
+ action: "settle",
95
+ reason,
96
+ ...(compactionAbortCandidate
97
+ ? { diagnostic: `Compaction-induced child abort could not be resumed safely: ${reason}.` }
98
+ : {}),
99
+ });
100
+
101
+ if (input.alreadyResumed) return settle("resume already attempted");
102
+ if (!input.sessionAvailable) return settle("retained session unavailable");
103
+ if (input.stopped || input.interrupted) return settle("explicit stop or interrupt");
104
+ // A compaction abort can leave the child process open until the runner's
105
+ // terminal drain sends SIGTERM. The compaction + settlement markers make
106
+ // that cleanup signal non-authoritative; explicit stop/interrupt still wins.
107
+ if (input.processSignal && !compactionAbortCandidate) return settle("process terminated by signal");
108
+ if (input.timedOut) return settle("elapsed timeout");
109
+ if (input.toolBudgetExhausted || input.usageBudgetExhausted) return settle("budget exhausted");
110
+ if (input.structuredOutputFailed) return settle("structured output failure");
111
+ if (input.acceptanceFailed) return settle("acceptance failure");
112
+ if (input.currentTool) return settle(`active tool '${input.currentTool.slice(0, 128)}' remains in flight`);
113
+ if (hasUnresolvedToolCall(input.messages)) return settle("unresolved tool call remains in transcript");
114
+ if (!input.afterCompactionSettlement) return settle("compaction settlement not verified");
115
+ if (!abortCandidate) return settle("terminal assistant abort evidence not verified");
116
+ const progressLimit = emptyZeroUsageTerminal ? terminal.index : input.messages.length;
117
+ if (!hasUsefulProgress(input.messages, progressLimit)) return settle("no useful prior progress");
118
+ return { action: "resume", prompt: ABORT_RECOVERY_PROMPT };
119
+ }