@fitchmultz/pi-subagents 0.44.7 → 0.46.0

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 (955) hide show
  1. package/CHANGELOG.md +264 -7
  2. package/LICENSE +1 -0
  3. package/README.md +58 -1483
  4. package/agents/context-builder.md +19 -1
  5. package/agents/debugger.md +10 -3
  6. package/agents/delegate.md +1 -0
  7. package/agents/fixer.md +4 -1
  8. package/agents/oracle.md +13 -2
  9. package/agents/planner.md +14 -3
  10. package/agents/researcher.md +11 -2
  11. package/agents/reviewer-claude.md +11 -2
  12. package/agents/reviewer-gpt.md +12 -2
  13. package/agents/reviewer-ponytail.md +11 -1
  14. package/agents/reviewer-security.md +13 -2
  15. package/agents/reviewer.md +12 -3
  16. package/agents/scout.md +12 -1
  17. package/agents/ui-designer.md +10 -3
  18. package/agents/watcher.md +1 -0
  19. package/agents/worker.md +8 -2
  20. package/agents/writer.md +6 -3
  21. package/dist/agents/agent-defaults.js +9 -0
  22. package/dist/agents/agent-definition.js +196 -0
  23. package/dist/agents/agent-management.js +64 -905
  24. package/dist/agents/agent-scope.js +4 -2
  25. package/dist/agents/agent-selection.js +10 -5
  26. package/dist/agents/agent-serializer.js +55 -67
  27. package/dist/agents/agents.js +75 -716
  28. package/dist/agents/builtin-overrides.js +218 -0
  29. package/dist/agents/chain-serializer.js +3 -367
  30. package/dist/agents/config-values.js +52 -0
  31. package/dist/agents/discovery-paths.js +91 -0
  32. package/dist/agents/frontmatter.js +15 -5
  33. package/dist/agents/identity.js +25 -8
  34. package/dist/agents/json-chain.js +254 -0
  35. package/dist/agents/management-config.js +332 -0
  36. package/dist/agents/management-format.js +231 -0
  37. package/dist/agents/management-persistence.js +287 -0
  38. package/dist/agents/management-targets.js +136 -0
  39. package/dist/agents/management-warnings.js +81 -0
  40. package/dist/agents/markdown-chain.js +210 -0
  41. package/dist/agents/package-agents.js +154 -0
  42. package/dist/agents/skill-files.js +157 -0
  43. package/dist/agents/skill-search-paths.js +246 -0
  44. package/dist/agents/skill-types.js +1 -0
  45. package/dist/agents/skills.js +54 -499
  46. package/dist/extension/acceptance-schema.js +55 -0
  47. package/dist/extension/build-info.js +1 -1
  48. package/dist/extension/chain-schema.js +196 -0
  49. package/dist/extension/child-runtime.js +237 -0
  50. package/dist/extension/compact-tools.js +122 -51
  51. package/dist/extension/config-schema.js +29 -0
  52. package/dist/extension/config.js +27 -11
  53. package/dist/extension/control-notice-schema.js +37 -0
  54. package/dist/extension/control-notices.js +13 -6
  55. package/dist/extension/delegation-bridges.js +43 -0
  56. package/dist/extension/doctor.js +48 -25
  57. package/dist/extension/everyday-schemas.js +207 -0
  58. package/dist/extension/fanout-child.js +18 -319
  59. package/dist/extension/index.js +8 -563
  60. package/dist/extension/message-renderers.js +225 -0
  61. package/dist/extension/nested-control-inbox.js +154 -0
  62. package/dist/extension/parent-runtime.js +339 -0
  63. package/dist/extension/primary-tool.js +69 -0
  64. package/dist/extension/result-snapshot.js +22 -0
  65. package/dist/extension/runtime-reload.js +62 -0
  66. package/dist/extension/runtime-storage.js +43 -0
  67. package/dist/extension/schema-overrides.js +75 -0
  68. package/dist/extension/schemas.js +265 -336
  69. package/dist/extension/tool-input.js +27 -12
  70. package/dist/extension/tool-result.js +19 -4
  71. package/dist/history/answer-texts.js +57 -0
  72. package/dist/history/canonical-result.js +76 -43
  73. package/dist/history/canonical-selection.js +40 -0
  74. package/dist/history/database-generation.js +82 -0
  75. package/dist/history/database.js +57 -33
  76. package/dist/history/entry-ingestion.js +61 -0
  77. package/dist/history/index.js +242 -97
  78. package/dist/history/ingest.js +168 -331
  79. package/dist/history/output-digests.js +40 -0
  80. package/dist/history/preview.js +210 -0
  81. package/dist/history/prune.js +33 -0
  82. package/dist/history/queries.js +60 -349
  83. package/dist/history/query-scope.js +190 -0
  84. package/dist/history/rows.js +77 -0
  85. package/dist/history/run-projection.js +137 -0
  86. package/dist/history/run-queries.js +153 -0
  87. package/dist/history/schema.js +31 -0
  88. package/dist/history/search-queries.js +163 -0
  89. package/dist/history/selected-record.js +108 -0
  90. package/dist/history/source-file.js +45 -0
  91. package/dist/history/source-watches.js +141 -0
  92. package/dist/history/store.js +164 -153
  93. package/dist/history/text-chunks.js +169 -0
  94. package/dist/history/text.js +35 -0
  95. package/dist/history/transcript-queries.js +177 -0
  96. package/dist/history/types.js +5 -1
  97. package/dist/history/values.js +36 -0
  98. package/dist/history/wire-inputs.js +122 -0
  99. package/dist/history/wire-models.js +38 -0
  100. package/dist/history/worker-runtime.js +441 -0
  101. package/dist/history/worker.js +66 -462
  102. package/dist/intercom/intercom-bridge.js +48 -20
  103. package/dist/intercom/live-intercom.js +80 -23
  104. package/dist/intercom/nested-result-tree.js +163 -0
  105. package/dist/intercom/result-delivery.js +40 -0
  106. package/dist/intercom/result-intercom.js +178 -261
  107. package/dist/pi-intercom/agent-dir.js +7 -3
  108. package/dist/pi-intercom/async.js +27 -0
  109. package/dist/pi-intercom/bridge-ask.js +57 -0
  110. package/dist/pi-intercom/bridge-config.js +89 -0
  111. package/dist/pi-intercom/bridge-http.js +86 -0
  112. package/dist/pi-intercom/bridge-launch-policy.js +88 -0
  113. package/dist/pi-intercom/bridge-launch.js +217 -0
  114. package/dist/pi-intercom/bridge-protocol.js +106 -0
  115. package/dist/pi-intercom/bridge-routes.js +72 -0
  116. package/dist/pi-intercom/bridge-rpc-process.js +264 -0
  117. package/dist/pi-intercom/bridge-session.js +420 -0
  118. package/dist/pi-intercom/bridge.js +221 -606
  119. package/dist/pi-intercom/broker/broker.js +236 -244
  120. package/dist/pi-intercom/broker/client.js +189 -304
  121. package/dist/pi-intercom/broker/connection.js +165 -0
  122. package/dist/pi-intercom/broker/framing.js +5 -3
  123. package/dist/pi-intercom/broker/paths.js +4 -1
  124. package/dist/pi-intercom/broker/pid.js +53 -25
  125. package/dist/pi-intercom/broker/snapshot-reader.js +78 -0
  126. package/dist/pi-intercom/broker/snapshots.js +188 -0
  127. package/dist/pi-intercom/broker/spawn.js +36 -25
  128. package/dist/pi-intercom/config.js +85 -71
  129. package/dist/pi-intercom/connection.js +297 -0
  130. package/dist/pi-intercom/identity.js +58 -0
  131. package/dist/pi-intercom/inbound-delivery.js +356 -0
  132. package/dist/pi-intercom/inbound-journal.js +303 -0
  133. package/dist/pi-intercom/inbound-record.js +113 -0
  134. package/dist/pi-intercom/inbound.js +179 -0
  135. package/dist/pi-intercom/index.js +79 -2933
  136. package/dist/pi-intercom/inspection.js +62 -0
  137. package/dist/pi-intercom/interview.js +236 -0
  138. package/dist/pi-intercom/lifecycle.js +168 -0
  139. package/dist/pi-intercom/message-format.js +69 -0
  140. package/dist/pi-intercom/outbound.js +304 -0
  141. package/dist/pi-intercom/peer-awareness.js +66 -0
  142. package/dist/pi-intercom/reply-tracker.js +62 -43
  143. package/dist/pi-intercom/reply-wait.js +201 -0
  144. package/dist/pi-intercom/runtime-types.js +3 -0
  145. package/dist/pi-intercom/session-events.js +180 -0
  146. package/dist/pi-intercom/session-targets.js +42 -34
  147. package/dist/pi-intercom/subagent-events.js +238 -0
  148. package/dist/pi-intercom/subagent-live-events.js +129 -86
  149. package/dist/pi-intercom/supervisor.js +282 -0
  150. package/dist/pi-intercom/tool-arguments.js +74 -0
  151. package/dist/pi-intercom/tool-registration.js +95 -0
  152. package/dist/pi-intercom/tool-results.js +38 -0
  153. package/dist/pi-intercom/tool-schemas.js +82 -0
  154. package/dist/pi-intercom/tools.js +51 -0
  155. package/dist/pi-intercom/topic-actions.js +177 -0
  156. package/dist/pi-intercom/topics.js +177 -92
  157. package/dist/pi-intercom/transport.js +1 -0
  158. package/dist/pi-intercom/types.js +151 -114
  159. package/dist/pi-intercom/ui/compose-paste.js +93 -0
  160. package/dist/pi-intercom/ui/compose.js +121 -143
  161. package/dist/pi-intercom/ui/inline-message.js +59 -59
  162. package/dist/pi-intercom/ui/message-renderers.js +147 -0
  163. package/dist/pi-intercom/ui/overlay.js +181 -0
  164. package/dist/pi-intercom/ui/session-format.js +124 -0
  165. package/dist/pi-intercom/ui/session-list.js +76 -43
  166. package/dist/pi-intercom/ui/tool-renderers.js +110 -0
  167. package/dist/pi-intercom/ui/topic-view.js +88 -0
  168. package/dist/pi-intercom/validation.js +59 -0
  169. package/dist/runs/background/async-chain-plan.js +265 -0
  170. package/dist/runs/background/async-control.js +134 -58
  171. package/dist/runs/background/async-execution.js +136 -633
  172. package/dist/runs/background/async-job-admission.js +40 -0
  173. package/dist/runs/background/async-job-projection.js +169 -0
  174. package/dist/runs/background/async-job-tracker.js +297 -327
  175. package/dist/runs/background/async-launch.js +216 -0
  176. package/dist/runs/background/async-plan.js +116 -0
  177. package/dist/runs/background/async-result-file.js +47 -23
  178. package/dist/runs/background/async-resume.js +195 -253
  179. package/dist/runs/background/async-run-discovery.js +213 -0
  180. package/dist/runs/background/async-run-location.js +135 -0
  181. package/dist/runs/background/async-run-record.js +1 -0
  182. package/dist/runs/background/async-run-repair.js +223 -0
  183. package/dist/runs/background/async-run-summary.js +1 -0
  184. package/dist/runs/background/async-single-plan.js +105 -0
  185. package/dist/runs/background/async-status-projection.js +155 -0
  186. package/dist/runs/background/async-status-render.js +117 -0
  187. package/dist/runs/background/async-status-validation.js +181 -0
  188. package/dist/runs/background/async-status.js +3 -442
  189. package/dist/runs/background/async-value.js +21 -0
  190. package/dist/runs/background/completion-dedupe.js +36 -12
  191. package/dist/runs/background/completion-delivery.js +211 -205
  192. package/dist/runs/background/completion-receipts.js +237 -0
  193. package/dist/runs/background/legacy-status-acceptance.js +34 -0
  194. package/dist/runs/background/notify.js +96 -48
  195. package/dist/runs/background/parallel-groups.js +36 -19
  196. package/dist/runs/background/result-payload.js +178 -0
  197. package/dist/runs/background/result-watcher.js +348 -339
  198. package/dist/runs/background/run-id-resolver.js +53 -33
  199. package/dist/runs/background/run-schemas.js +189 -0
  200. package/dist/runs/background/run-status-contracts.js +14 -0
  201. package/dist/runs/background/run-status-render.js +270 -0
  202. package/dist/runs/background/run-status.js +231 -339
  203. package/dist/runs/background/runner-attempt-output.js +155 -0
  204. package/dist/runs/background/runner-attempt.js +263 -0
  205. package/dist/runs/background/runner-child-executor.js +166 -0
  206. package/dist/runs/background/runner-child-observer.js +192 -0
  207. package/dist/runs/background/runner-completion-summary.js +71 -0
  208. package/dist/runs/background/runner-completion.js +211 -0
  209. package/dist/runs/background/runner-config.js +1 -0
  210. package/dist/runs/background/runner-contract.js +1 -0
  211. package/dist/runs/background/runner-dynamic.js +121 -0
  212. package/dist/runs/background/runner-finalization.js +149 -0
  213. package/dist/runs/background/runner-graph.js +68 -0
  214. package/dist/runs/background/runner-initial-status.js +60 -0
  215. package/dist/runs/background/runner-lifecycle.js +142 -0
  216. package/dist/runs/background/runner-monitor.js +309 -0
  217. package/dist/runs/background/runner-parallel.js +204 -0
  218. package/dist/runs/background/runner-prepare-step.js +86 -0
  219. package/dist/runs/background/runner-reporting.js +153 -0
  220. package/dist/runs/background/runner-status.js +148 -0
  221. package/dist/runs/background/runner-step-output.js +92 -0
  222. package/dist/runs/background/runner-step-record.js +45 -0
  223. package/dist/runs/background/runner-step.js +112 -0
  224. package/dist/runs/background/runner-streaming.js +173 -0
  225. package/dist/runs/background/runner-workflow.js +213 -0
  226. package/dist/runs/background/stale-run-reconciler.js +155 -292
  227. package/dist/runs/background/subagent-runner-launcher.js +33 -13
  228. package/dist/runs/background/subagent-runner.js +51 -1842
  229. package/dist/runs/background/top-level-async.js +2 -1
  230. package/dist/runs/foreground/chain-clarify.js +293 -1017
  231. package/dist/runs/foreground/clarification-draft.js +87 -0
  232. package/dist/runs/foreground/clarify-contracts.js +1 -0
  233. package/dist/runs/foreground/clarify-invocation.js +129 -38
  234. package/dist/runs/foreground/clarify-text-editor.js +210 -0
  235. package/dist/runs/foreground/clarify-view.js +167 -0
  236. package/dist/runs/foreground/execution-input.js +226 -353
  237. package/dist/runs/foreground/execution-routing.js +33 -0
  238. package/dist/runs/foreground/execution-timeout.js +81 -0
  239. package/dist/runs/foreground/foreground-control.js +222 -763
  240. package/dist/runs/foreground/foreground-memory.js +99 -0
  241. package/dist/runs/foreground/invocation-context.js +55 -0
  242. package/dist/runs/foreground/invocation-execution.js +331 -0
  243. package/dist/runs/foreground/invocation-expansion.js +48 -0
  244. package/dist/runs/foreground/management-actions.js +295 -0
  245. package/dist/runs/foreground/nested-control.js +179 -0
  246. package/dist/runs/foreground/question-continuation.js +78 -0
  247. package/dist/runs/foreground/question-control.js +155 -50
  248. package/dist/runs/foreground/resume-target.js +221 -0
  249. package/dist/runs/foreground/revival-launch-policy.js +58 -0
  250. package/dist/runs/foreground/run-async-path.js +190 -178
  251. package/dist/runs/foreground/run-interrupt.js +164 -0
  252. package/dist/runs/foreground/run-nudge.js +278 -0
  253. package/dist/runs/foreground/saved-revival.js +251 -0
  254. package/dist/runs/foreground/subagent-executor.js +135 -424
  255. package/dist/runs/foreground/subagent-params.js +67 -30
  256. package/dist/runs/foreground/wait-observation.js +104 -0
  257. package/dist/runs/foreground/wait-registration.js +17 -0
  258. package/dist/runs/foreground/wait-run.js +283 -123
  259. package/dist/runs/shared/acceptance-contract.js +193 -99
  260. package/dist/runs/shared/acceptance-defaults.js +1 -0
  261. package/dist/runs/shared/acceptance-evaluation.js +201 -181
  262. package/dist/runs/shared/acceptance-finalization.js +256 -180
  263. package/dist/runs/shared/acceptance-outcome.js +53 -0
  264. package/dist/runs/shared/acceptance-reports.js +137 -72
  265. package/dist/runs/shared/acceptance-submission.js +167 -0
  266. package/dist/runs/shared/acceptance-verification.js +100 -0
  267. package/dist/runs/shared/chain-outputs.js +80 -52
  268. package/dist/runs/shared/child-attempt-types.js +1 -0
  269. package/dist/runs/shared/child-attempt.js +314 -667
  270. package/dist/runs/shared/child-boundaries.js +173 -0
  271. package/dist/runs/shared/child-context-filter.js +44 -0
  272. package/dist/runs/shared/child-event-observer.js +390 -0
  273. package/dist/runs/shared/child-execution-cwd.js +73 -43
  274. package/dist/runs/shared/child-execution-outcome.js +72 -0
  275. package/dist/runs/shared/child-invocation.js +54 -0
  276. package/dist/runs/shared/child-message-validation.js +215 -0
  277. package/dist/runs/shared/child-native-accounting.js +106 -0
  278. package/dist/runs/shared/child-native-observation.js +69 -0
  279. package/dist/runs/shared/child-observation-spool.js +164 -0
  280. package/dist/runs/shared/child-observations.js +157 -76
  281. package/dist/runs/shared/child-presence.js +3 -0
  282. package/dist/runs/shared/child-route-env.js +119 -0
  283. package/dist/runs/shared/child-stream-observer.js +221 -0
  284. package/dist/runs/shared/child-stream-projection.js +137 -0
  285. package/dist/runs/shared/child-structured-tool.js +27 -0
  286. package/dist/runs/shared/claude-code.js +121 -158
  287. package/dist/runs/shared/claude-model.js +42 -0
  288. package/dist/runs/shared/claude-session.js +83 -0
  289. package/dist/runs/shared/claude-types.js +1 -0
  290. package/dist/runs/shared/completion-guard.js +18 -18
  291. package/dist/runs/shared/control-event-policy.js +8 -0
  292. package/dist/runs/shared/control-notification-owner.js +13 -0
  293. package/dist/runs/shared/dynamic-fanout.js +188 -173
  294. package/dist/runs/shared/dynamic-item.js +102 -0
  295. package/dist/runs/shared/history-index.js +62 -36
  296. package/dist/runs/shared/legacy-async-recovery.js +114 -0
  297. package/dist/runs/shared/legacy-output-recovery.js +148 -0
  298. package/dist/runs/shared/mcp-config-schema.js +36 -0
  299. package/dist/runs/shared/mcp-direct-tool-allowlist.js +147 -116
  300. package/dist/runs/shared/model-fallback.js +97 -38
  301. package/dist/runs/shared/mutating-tool-guard.js +128 -88
  302. package/dist/runs/shared/native-finalization-types.js +1 -0
  303. package/dist/runs/shared/native-finalization.js +155 -76
  304. package/dist/runs/shared/native-usage.js +238 -98
  305. package/dist/runs/shared/nested-control-records.js +128 -0
  306. package/dist/runs/shared/nested-events.js +8 -700
  307. package/dist/runs/shared/nested-path.js +32 -28
  308. package/dist/runs/shared/nested-projection.js +155 -0
  309. package/dist/runs/shared/nested-protocol.js +18 -0
  310. package/dist/runs/shared/nested-registry.js +191 -0
  311. package/dist/runs/shared/nested-render.js +106 -58
  312. package/dist/runs/shared/nested-route.js +220 -0
  313. package/dist/runs/shared/nested-validation.js +216 -0
  314. package/dist/runs/shared/owned-child-evidence.js +125 -0
  315. package/dist/runs/shared/owned-run-list.js +146 -0
  316. package/dist/runs/shared/owned-run-observation.js +267 -0
  317. package/dist/runs/shared/owned-run-progress.js +109 -0
  318. package/dist/runs/shared/owned-run-read-state.js +1 -0
  319. package/dist/runs/shared/owned-run-results.js +202 -0
  320. package/dist/runs/shared/owned-run-status.js +180 -0
  321. package/dist/runs/shared/owned-run-view.js +51 -0
  322. package/dist/runs/shared/owned-workflow-details.js +17 -0
  323. package/dist/runs/shared/owner-output.js +43 -0
  324. package/dist/runs/shared/parallel-utils.js +36 -28
  325. package/dist/runs/shared/parent-receipts.js +90 -32
  326. package/dist/runs/shared/parent-usage.js +169 -57
  327. package/dist/runs/shared/pi-args.js +108 -201
  328. package/dist/runs/shared/pi-launch-input.js +1 -0
  329. package/dist/runs/shared/pi-session-launch.js +86 -0
  330. package/dist/runs/shared/pi-spawn.js +35 -21
  331. package/dist/runs/shared/run-history-queries.js +126 -35
  332. package/dist/runs/shared/run-history.js +101 -35
  333. package/dist/runs/shared/run-metadata-paths.js +14 -0
  334. package/dist/runs/shared/run-metadata.js +158 -0
  335. package/dist/runs/shared/run-persistence.js +131 -0
  336. package/dist/runs/shared/run-records.js +9 -679
  337. package/dist/runs/shared/run-restoration.js +338 -0
  338. package/dist/runs/shared/run-state-owner.js +26 -0
  339. package/dist/runs/shared/session-cwd-preload.js +27 -18
  340. package/dist/runs/shared/single-output.js +148 -70
  341. package/dist/runs/shared/stable-value.js +15 -0
  342. package/dist/runs/shared/streaming-text.js +23 -12
  343. package/dist/runs/shared/structured-output.js +25 -13
  344. package/dist/runs/shared/subagent-control.js +167 -100
  345. package/dist/runs/shared/subagent-prompt-runtime.js +27 -130
  346. package/dist/runs/shared/subagent-tool-loop-guard.js +81 -52
  347. package/dist/runs/shared/supervisor-question-state.js +145 -0
  348. package/dist/runs/shared/supervisor-questions.js +185 -254
  349. package/dist/runs/shared/workflow-graph.js +259 -167
  350. package/dist/runs/shared/workflow-policy.js +120 -48
  351. package/dist/runs/shared/worktree-contract.js +1 -0
  352. package/dist/runs/shared/worktree-hook.js +138 -0
  353. package/dist/runs/shared/worktree-location.js +47 -0
  354. package/dist/runs/shared/worktree-preservation.js +8 -0
  355. package/dist/runs/shared/worktree-process.js +107 -0
  356. package/dist/runs/shared/worktree.js +183 -322
  357. package/dist/shared/agent-context-policy.js +34 -44
  358. package/dist/shared/agent-dir.js +14 -0
  359. package/dist/shared/artifacts.js +30 -12
  360. package/dist/shared/atomic-json.js +4 -1
  361. package/dist/shared/chain-files.js +72 -0
  362. package/dist/shared/concurrency.js +18 -0
  363. package/dist/shared/content-preview.js +115 -0
  364. package/dist/shared/cooperative.js +5 -2
  365. package/dist/shared/execution-cwd.js +13 -5
  366. package/dist/shared/file-coalescer.js +2 -1
  367. package/dist/shared/fork-context.js +10 -12
  368. package/dist/shared/formatters.js +45 -19
  369. package/dist/shared/journal-frames.js +164 -0
  370. package/dist/shared/journal-projections.js +121 -0
  371. package/dist/shared/journal-reader.js +6 -407
  372. package/dist/shared/json-projection.js +191 -0
  373. package/dist/shared/lazy-tools.js +19 -8
  374. package/dist/shared/message-output.js +116 -0
  375. package/dist/shared/model-info.js +31 -14
  376. package/dist/shared/native-import.js +20 -0
  377. package/dist/shared/native-journal.js +140 -0
  378. package/dist/shared/native-session-loader.js +17 -0
  379. package/dist/shared/native-session.js +2 -13
  380. package/dist/shared/native-tui.js +7 -2
  381. package/dist/shared/native-typebox.js +15 -3
  382. package/dist/shared/output-page.js +63 -0
  383. package/dist/shared/post-exit-stdio-guard.js +128 -88
  384. package/dist/shared/prompt-sections.js +2 -0
  385. package/dist/shared/session-entries.js +70 -35
  386. package/dist/shared/session-identity.js +5 -3
  387. package/dist/shared/settings.js +62 -192
  388. package/dist/shared/status-format.js +97 -37
  389. package/dist/shared/task-file-policy.js +24 -0
  390. package/dist/shared/temp-root.js +44 -15
  391. package/dist/shared/types/acceptance.js +1 -0
  392. package/dist/shared/types/async.js +1 -0
  393. package/dist/shared/types/config.js +1 -0
  394. package/dist/shared/types/details.js +1 -0
  395. package/dist/shared/types/history.js +1 -0
  396. package/dist/shared/types/inputs.js +1 -0
  397. package/dist/shared/types/intercom.js +1 -0
  398. package/dist/shared/types/launch.js +1 -0
  399. package/dist/shared/types/messages.js +1 -0
  400. package/dist/shared/types/nested.js +1 -0
  401. package/dist/shared/types/owned-runs.js +1 -0
  402. package/dist/shared/types/progress.js +1 -0
  403. package/dist/shared/types/questions.js +1 -0
  404. package/dist/shared/types/results.js +1 -0
  405. package/dist/shared/types/state.js +1 -0
  406. package/dist/shared/types/usage.js +1 -0
  407. package/dist/shared/types/workflow.js +1 -0
  408. package/dist/shared/types.js +75 -30
  409. package/dist/shared/unknown.js +52 -0
  410. package/dist/shared/utils.js +54 -260
  411. package/dist/slash/command-discovery.js +82 -0
  412. package/dist/slash/command-input.js +190 -0
  413. package/dist/slash/prompt-template-bridge.js +94 -270
  414. package/dist/slash/prompt-template-contract.js +77 -0
  415. package/dist/slash/prompt-template-results.js +125 -0
  416. package/dist/slash/request-protocol.js +68 -0
  417. package/dist/slash/result-delivery.js +237 -0
  418. package/dist/slash/saved-chain.js +78 -0
  419. package/dist/slash/slash-bridge.js +123 -89
  420. package/dist/slash/slash-commands.js +101 -572
  421. package/dist/slash/slash-live-state.js +68 -47
  422. package/dist/tui/action-hints.js +50 -22
  423. package/dist/tui/activity-lines.js +32 -0
  424. package/dist/tui/agent-browser.js +290 -0
  425. package/dist/tui/agent-controls.js +289 -0
  426. package/dist/tui/agent-conversation.js +444 -0
  427. package/dist/tui/agent-dock.js +171 -0
  428. package/dist/tui/agent-history.js +50 -183
  429. package/dist/tui/agent-model.js +62 -0
  430. package/dist/tui/agent-picker.js +262 -0
  431. package/dist/tui/agent-view.js +232 -1564
  432. package/dist/tui/compact-results.js +193 -0
  433. package/dist/tui/conversation-details.js +190 -0
  434. package/dist/tui/conversation-frame.js +135 -0
  435. package/dist/tui/conversation-history.js +201 -0
  436. package/dist/tui/conversation-menu.js +78 -0
  437. package/dist/tui/conversation-notices.js +79 -0
  438. package/dist/tui/conversation-selection.js +58 -0
  439. package/dist/tui/conversation-viewport.js +129 -0
  440. package/dist/tui/direction-message.js +27 -0
  441. package/dist/tui/display.js +282 -0
  442. package/dist/tui/editor-viewport.js +18 -0
  443. package/dist/tui/expanded-content.js +87 -0
  444. package/dist/tui/expanded-multi.js +170 -0
  445. package/dist/tui/expanded-single.js +65 -0
  446. package/dist/tui/history-cards.js +216 -0
  447. package/dist/tui/history-display.js +238 -0
  448. package/dist/tui/history-json.js +16 -0
  449. package/dist/tui/history-metadata.js +152 -0
  450. package/dist/tui/history-record.js +251 -0
  451. package/dist/tui/history-text.js +34 -0
  452. package/dist/tui/indexed-history.js +116 -0
  453. package/dist/tui/nested-widget.js +120 -0
  454. package/dist/tui/picker-page.js +59 -0
  455. package/dist/tui/render.js +58 -1501
  456. package/dist/tui/result-facts.js +64 -0
  457. package/dist/tui/task-observation.js +59 -0
  458. package/dist/tui/task-store.js +366 -0
  459. package/dist/tui/text-values.js +16 -0
  460. package/dist/tui/view-connections.js +47 -0
  461. package/dist/tui/view-model.js +94 -0
  462. package/dist/tui/view-persistence.js +51 -0
  463. package/dist/tui/view-ports.js +1 -0
  464. package/dist/tui/view-session.js +37 -0
  465. package/dist/tui/widget-details.js +144 -0
  466. package/dist/tui/widget-status.js +245 -0
  467. package/dist/tui/widget.js +145 -0
  468. package/dist/tui/workflow-labels.js +223 -0
  469. package/dist/tui/workflow-outcomes.js +124 -0
  470. package/docs/code-quality.md +38 -0
  471. package/docs/development.md +99 -0
  472. package/docs/intercom-bridge.md +77 -22
  473. package/docs/intercom.md +132 -106
  474. package/docs/performance.md +19 -17
  475. package/docs/reference.md +1472 -0
  476. package/generated/RunValidators.d.ts +28 -0
  477. package/generated/RunValidators.js +2 -0
  478. package/package.json +27 -6
  479. package/prompts/parallel-cleanup.md +3 -0
  480. package/prompts/parallel-context-build.md +3 -0
  481. package/prompts/parallel-handoff-plan.md +6 -0
  482. package/prompts/parallel-research.md +4 -0
  483. package/prompts/parallel-review.md +2 -0
  484. package/prompts/review-loop.md +2 -0
  485. package/scripts/build.mjs +129 -85
  486. package/scripts/check-compat.mjs +48 -11
  487. package/scripts/compat-host.mjs +35 -7
  488. package/scripts/generate-run-schemas.mjs +210 -0
  489. package/scripts/intercom-bridge-credentials.mjs +158 -29
  490. package/scripts/intercom-remote.mjs +213 -52
  491. package/scripts/local-install-smoke.mjs +47 -37
  492. package/scripts/native-package-smoke.mjs +135 -25
  493. package/scripts/package-smoke.mjs +360 -140
  494. package/scripts/prepare.mjs +54 -34
  495. package/scripts/real-pi-processes.mjs +261 -0
  496. package/scripts/real-pi-smoke.mjs +432 -351
  497. package/scripts/run-tests.mjs +29 -15
  498. package/skills/pi-intercom/SKILL.md +11 -11
  499. package/skills/pi-intercom/references/peer-sessions.md +7 -2
  500. package/skills/pi-subagents/SKILL.md +1 -1
  501. package/skills/pi-subagents/references/full-orchestration-guide.md +254 -112
  502. package/src/agents/agent-defaults.ts +13 -0
  503. package/src/agents/agent-definition.ts +253 -0
  504. package/src/agents/agent-management.ts +111 -808
  505. package/src/agents/agent-scope.ts +7 -3
  506. package/src/agents/agent-selection.ts +26 -16
  507. package/src/agents/agent-serializer.ts +84 -93
  508. package/src/agents/agents.ts +199 -906
  509. package/src/agents/builtin-overrides.ts +297 -0
  510. package/src/agents/chain-serializer.ts +3 -329
  511. package/src/agents/config-values.ts +57 -0
  512. package/src/agents/discovery-paths.ts +134 -0
  513. package/src/agents/frontmatter.ts +35 -17
  514. package/src/agents/identity.ts +49 -18
  515. package/src/agents/json-chain.ts +305 -0
  516. package/src/agents/management-config.ts +342 -0
  517. package/src/agents/management-format.ts +243 -0
  518. package/src/agents/management-persistence.ts +408 -0
  519. package/src/agents/management-targets.ts +260 -0
  520. package/src/agents/management-warnings.ts +115 -0
  521. package/src/agents/markdown-chain.ts +237 -0
  522. package/src/agents/package-agents.ts +231 -0
  523. package/src/agents/skill-files.ts +182 -0
  524. package/src/agents/skill-search-paths.ts +289 -0
  525. package/src/agents/skill-types.ts +31 -0
  526. package/src/agents/skills.ts +152 -610
  527. package/src/extension/acceptance-schema.ts +88 -0
  528. package/src/extension/chain-schema.ts +276 -0
  529. package/src/extension/child-runtime.ts +302 -0
  530. package/src/extension/compact-tools.ts +259 -102
  531. package/src/extension/config-schema.ts +59 -0
  532. package/src/extension/config.ts +39 -17
  533. package/src/extension/control-notice-schema.ts +55 -0
  534. package/src/extension/control-notices.ts +57 -33
  535. package/src/extension/delegation-bridges.ts +59 -0
  536. package/src/extension/doctor.ts +171 -135
  537. package/src/extension/everyday-schemas.ts +252 -0
  538. package/src/extension/fanout-child.ts +29 -308
  539. package/src/extension/index.ts +17 -642
  540. package/src/extension/message-renderers.ts +334 -0
  541. package/src/extension/nested-control-inbox.ts +196 -0
  542. package/src/extension/parent-runtime.ts +405 -0
  543. package/src/extension/primary-tool.ts +130 -0
  544. package/src/extension/result-snapshot.ts +35 -0
  545. package/src/extension/runtime-reload.ts +72 -0
  546. package/src/extension/runtime-storage.ts +49 -0
  547. package/src/extension/schema-overrides.ts +114 -0
  548. package/src/extension/schemas.ts +451 -418
  549. package/src/extension/tool-input.ts +40 -13
  550. package/src/extension/tool-result.ts +45 -14
  551. package/src/history/answer-texts.ts +74 -0
  552. package/src/history/canonical-result.ts +127 -51
  553. package/src/history/canonical-selection.ts +54 -0
  554. package/src/history/database-generation.ts +86 -0
  555. package/src/history/database.ts +86 -48
  556. package/src/history/entry-ingestion.ts +129 -0
  557. package/src/history/index.ts +426 -148
  558. package/src/history/ingest.ts +372 -342
  559. package/src/history/output-digests.ts +41 -0
  560. package/src/history/preview.ts +235 -0
  561. package/src/history/prune.ts +48 -0
  562. package/src/history/queries.ts +122 -256
  563. package/src/history/query-scope.ts +278 -0
  564. package/src/history/rows.ts +118 -0
  565. package/src/history/run-projection.ts +164 -0
  566. package/src/history/run-queries.ts +199 -0
  567. package/src/history/schema.ts +34 -0
  568. package/src/history/search-queries.ts +216 -0
  569. package/src/history/selected-record.ts +140 -0
  570. package/src/history/source-file.ts +51 -0
  571. package/src/history/source-watches.ts +156 -0
  572. package/src/history/store.ts +310 -197
  573. package/src/history/text-chunks.ts +181 -0
  574. package/src/history/text.ts +43 -0
  575. package/src/history/transcript-queries.ts +251 -0
  576. package/src/history/types.ts +27 -164
  577. package/src/history/values.ts +36 -0
  578. package/src/history/wire-inputs.ts +141 -0
  579. package/src/history/wire-models.ts +51 -0
  580. package/src/history/worker-runtime.ts +502 -0
  581. package/src/history/worker.ts +94 -336
  582. package/src/intercom/intercom-bridge.ts +136 -69
  583. package/src/intercom/live-intercom.ts +197 -92
  584. package/src/intercom/nested-result-tree.ts +213 -0
  585. package/src/intercom/result-delivery.ts +56 -0
  586. package/src/intercom/result-intercom.ts +364 -382
  587. package/src/pi-intercom/agent-dir.ts +9 -3
  588. package/src/pi-intercom/async.ts +33 -0
  589. package/src/pi-intercom/bridge-ask.ts +64 -0
  590. package/src/pi-intercom/bridge-config.ts +120 -0
  591. package/src/pi-intercom/bridge-http.ts +97 -0
  592. package/src/pi-intercom/bridge-launch-policy.ts +109 -0
  593. package/src/pi-intercom/bridge-launch.ts +317 -0
  594. package/src/pi-intercom/bridge-protocol.ts +123 -0
  595. package/src/pi-intercom/bridge-routes.ts +105 -0
  596. package/src/pi-intercom/bridge-rpc-process.ts +293 -0
  597. package/src/pi-intercom/bridge-session.ts +510 -0
  598. package/src/pi-intercom/bridge.ts +305 -549
  599. package/src/pi-intercom/broker/broker.ts +326 -263
  600. package/src/pi-intercom/broker/client.ts +273 -354
  601. package/src/pi-intercom/broker/connection.ts +192 -0
  602. package/src/pi-intercom/broker/framing.ts +11 -6
  603. package/src/pi-intercom/broker/paths.ts +28 -25
  604. package/src/pi-intercom/broker/pid.ts +68 -24
  605. package/src/pi-intercom/broker/snapshot-reader.ts +91 -0
  606. package/src/pi-intercom/broker/snapshots.ts +241 -0
  607. package/src/pi-intercom/broker/spawn.ts +58 -34
  608. package/src/pi-intercom/config.ts +113 -108
  609. package/src/pi-intercom/connection.ts +346 -0
  610. package/src/pi-intercom/identity.ts +71 -0
  611. package/src/pi-intercom/inbound-delivery.ts +450 -0
  612. package/src/pi-intercom/inbound-journal.ts +350 -0
  613. package/src/pi-intercom/inbound-record.ts +141 -0
  614. package/src/pi-intercom/inbound.ts +237 -0
  615. package/src/pi-intercom/index.ts +86 -2923
  616. package/src/pi-intercom/inspection.ts +82 -0
  617. package/src/pi-intercom/interview.ts +295 -0
  618. package/src/pi-intercom/lifecycle.ts +183 -0
  619. package/src/pi-intercom/message-format.ts +77 -0
  620. package/src/pi-intercom/outbound.ts +418 -0
  621. package/src/pi-intercom/peer-awareness.ts +84 -0
  622. package/src/pi-intercom/reply-tracker.ts +121 -59
  623. package/src/pi-intercom/reply-wait.ts +247 -0
  624. package/src/pi-intercom/runtime-types.ts +97 -0
  625. package/src/pi-intercom/session-events.ts +247 -0
  626. package/src/pi-intercom/session-targets.ts +124 -72
  627. package/src/pi-intercom/subagent-events.ts +299 -0
  628. package/src/pi-intercom/subagent-live-events.ts +212 -109
  629. package/src/pi-intercom/supervisor.ts +362 -0
  630. package/src/pi-intercom/tool-arguments.ts +120 -0
  631. package/src/pi-intercom/tool-registration.ts +121 -0
  632. package/src/pi-intercom/tool-results.ts +54 -0
  633. package/src/pi-intercom/tool-schemas.ts +134 -0
  634. package/src/pi-intercom/tools.ts +80 -0
  635. package/src/pi-intercom/topic-actions.ts +243 -0
  636. package/src/pi-intercom/topics.ts +267 -121
  637. package/src/pi-intercom/transport.ts +14 -0
  638. package/src/pi-intercom/types.ts +288 -190
  639. package/src/pi-intercom/ui/compose-paste.ts +109 -0
  640. package/src/pi-intercom/ui/compose.ts +173 -157
  641. package/src/pi-intercom/ui/inline-message.ts +80 -62
  642. package/src/pi-intercom/ui/message-renderers.ts +182 -0
  643. package/src/pi-intercom/ui/overlay.ts +238 -0
  644. package/src/pi-intercom/ui/session-format.ts +146 -0
  645. package/src/pi-intercom/ui/session-list.ts +145 -62
  646. package/src/pi-intercom/ui/tool-renderers.ts +148 -0
  647. package/src/pi-intercom/ui/topic-view.ts +107 -0
  648. package/src/pi-intercom/validation.ts +69 -0
  649. package/src/runs/background/async-chain-plan.ts +451 -0
  650. package/src/runs/background/async-control.ts +201 -71
  651. package/src/runs/background/async-execution.ts +206 -829
  652. package/src/runs/background/async-job-admission.ts +54 -0
  653. package/src/runs/background/async-job-projection.ts +225 -0
  654. package/src/runs/background/async-job-tracker.ts +416 -360
  655. package/src/runs/background/async-launch.ts +319 -0
  656. package/src/runs/background/async-plan.ts +285 -0
  657. package/src/runs/background/async-result-file.ts +79 -37
  658. package/src/runs/background/async-resume.ts +338 -285
  659. package/src/runs/background/async-run-discovery.ts +270 -0
  660. package/src/runs/background/async-run-location.ts +194 -0
  661. package/src/runs/background/async-run-record.ts +14 -0
  662. package/src/runs/background/async-run-repair.ts +307 -0
  663. package/src/runs/background/async-run-summary.ts +71 -0
  664. package/src/runs/background/async-single-plan.ts +168 -0
  665. package/src/runs/background/async-status-projection.ts +188 -0
  666. package/src/runs/background/async-status-render.ts +164 -0
  667. package/src/runs/background/async-status-validation.ts +238 -0
  668. package/src/runs/background/async-status.ts +9 -481
  669. package/src/runs/background/async-value.ts +29 -0
  670. package/src/runs/background/completion-dedupe.ts +103 -54
  671. package/src/runs/background/completion-delivery.ts +313 -187
  672. package/src/runs/background/completion-receipts.ts +309 -0
  673. package/src/runs/background/legacy-status-acceptance.ts +38 -0
  674. package/src/runs/background/notify.ts +167 -106
  675. package/src/runs/background/parallel-groups.ts +95 -46
  676. package/src/runs/background/result-payload.ts +268 -0
  677. package/src/runs/background/result-watcher.ts +484 -387
  678. package/src/runs/background/run-id-resolver.ts +126 -57
  679. package/src/runs/background/run-schemas.ts +240 -0
  680. package/src/runs/background/run-status-contracts.ts +46 -0
  681. package/src/runs/background/run-status-render.ts +364 -0
  682. package/src/runs/background/run-status.ts +338 -356
  683. package/src/runs/background/runner-attempt-output.ts +281 -0
  684. package/src/runs/background/runner-attempt.ts +354 -0
  685. package/src/runs/background/runner-child-executor.ts +232 -0
  686. package/src/runs/background/runner-child-observer.ts +270 -0
  687. package/src/runs/background/runner-completion-summary.ts +106 -0
  688. package/src/runs/background/runner-completion.ts +274 -0
  689. package/src/runs/background/runner-config.ts +52 -0
  690. package/src/runs/background/runner-contract.ts +51 -0
  691. package/src/runs/background/runner-dynamic.ts +185 -0
  692. package/src/runs/background/runner-finalization.ts +203 -0
  693. package/src/runs/background/runner-graph.ts +91 -0
  694. package/src/runs/background/runner-initial-status.ts +72 -0
  695. package/src/runs/background/runner-lifecycle.ts +159 -0
  696. package/src/runs/background/runner-monitor.ts +399 -0
  697. package/src/runs/background/runner-parallel.ts +280 -0
  698. package/src/runs/background/runner-prepare-step.ts +128 -0
  699. package/src/runs/background/runner-reporting.ts +192 -0
  700. package/src/runs/background/runner-status.ts +220 -0
  701. package/src/runs/background/runner-step-output.ts +158 -0
  702. package/src/runs/background/runner-step-record.ts +76 -0
  703. package/src/runs/background/runner-step.ts +150 -0
  704. package/src/runs/background/runner-streaming.ts +220 -0
  705. package/src/runs/background/runner-workflow.ts +284 -0
  706. package/src/runs/background/stale-run-reconciler.ts +279 -336
  707. package/src/runs/background/subagent-runner-launcher.ts +67 -35
  708. package/src/runs/background/subagent-runner.ts +80 -2048
  709. package/src/runs/background/top-level-async.ts +9 -7
  710. package/src/runs/foreground/chain-clarify.ts +499 -1334
  711. package/src/runs/foreground/clarification-draft.ts +92 -0
  712. package/src/runs/foreground/clarify-contracts.ts +33 -0
  713. package/src/runs/foreground/clarify-invocation.ts +192 -65
  714. package/src/runs/foreground/clarify-text-editor.ts +229 -0
  715. package/src/runs/foreground/clarify-view.ts +222 -0
  716. package/src/runs/foreground/execution-input.ts +358 -424
  717. package/src/runs/foreground/execution-routing.ts +41 -0
  718. package/src/runs/foreground/execution-timeout.ts +92 -0
  719. package/src/runs/foreground/foreground-control.ts +333 -812
  720. package/src/runs/foreground/foreground-memory.ts +132 -0
  721. package/src/runs/foreground/invocation-context.ts +88 -0
  722. package/src/runs/foreground/invocation-execution.ts +465 -0
  723. package/src/runs/foreground/invocation-expansion.ts +58 -0
  724. package/src/runs/foreground/management-actions.ts +360 -0
  725. package/src/runs/foreground/nested-control.ts +248 -0
  726. package/src/runs/foreground/question-continuation.ts +112 -0
  727. package/src/runs/foreground/question-control.ts +297 -70
  728. package/src/runs/foreground/resume-target.ts +330 -0
  729. package/src/runs/foreground/revival-launch-policy.ts +112 -0
  730. package/src/runs/foreground/run-async-path.ts +307 -223
  731. package/src/runs/foreground/run-interrupt.ts +202 -0
  732. package/src/runs/foreground/run-nudge.ts +355 -0
  733. package/src/runs/foreground/saved-revival.ts +356 -0
  734. package/src/runs/foreground/subagent-executor.ts +195 -493
  735. package/src/runs/foreground/subagent-params.ts +314 -242
  736. package/src/runs/foreground/wait-observation.ts +160 -0
  737. package/src/runs/foreground/wait-registration.ts +18 -0
  738. package/src/runs/foreground/wait-run.ts +361 -119
  739. package/src/runs/shared/acceptance-contract.ts +410 -209
  740. package/src/runs/shared/acceptance-defaults.ts +1 -0
  741. package/src/runs/shared/acceptance-evaluation.ts +314 -240
  742. package/src/runs/shared/acceptance-finalization.ts +447 -305
  743. package/src/runs/shared/acceptance-outcome.ts +69 -0
  744. package/src/runs/shared/acceptance-reports.ts +220 -126
  745. package/src/runs/shared/acceptance-submission.ts +251 -0
  746. package/src/runs/shared/acceptance-verification.ts +118 -0
  747. package/src/runs/shared/acceptance.ts +25 -25
  748. package/src/runs/shared/chain-outputs.ts +190 -98
  749. package/src/runs/shared/child-attempt-types.ts +118 -0
  750. package/src/runs/shared/child-attempt.ts +372 -608
  751. package/src/runs/shared/child-boundaries.ts +217 -0
  752. package/src/runs/shared/child-context-filter.ts +53 -0
  753. package/src/runs/shared/child-event-observer.ts +496 -0
  754. package/src/runs/shared/child-execution-cwd.ts +139 -68
  755. package/src/runs/shared/child-execution-outcome.ts +103 -0
  756. package/src/runs/shared/child-invocation.ts +74 -0
  757. package/src/runs/shared/child-message-validation.ts +233 -0
  758. package/src/runs/shared/child-native-accounting.ts +154 -0
  759. package/src/runs/shared/child-native-observation.ts +79 -0
  760. package/src/runs/shared/child-observation-spool.ts +188 -0
  761. package/src/runs/shared/child-observations.ts +219 -89
  762. package/src/runs/shared/child-presence.ts +6 -0
  763. package/src/runs/shared/child-route-env.ts +142 -0
  764. package/src/runs/shared/child-stream-observer.ts +302 -0
  765. package/src/runs/shared/child-stream-projection.ts +160 -0
  766. package/src/runs/shared/child-structured-tool.ts +38 -0
  767. package/src/runs/shared/claude-code.ts +201 -228
  768. package/src/runs/shared/claude-model.ts +67 -0
  769. package/src/runs/shared/claude-session.ts +124 -0
  770. package/src/runs/shared/claude-types.ts +31 -0
  771. package/src/runs/shared/completion-guard.ts +35 -26
  772. package/src/runs/shared/control-event-policy.ts +15 -0
  773. package/src/runs/shared/control-notification-owner.ts +20 -0
  774. package/src/runs/shared/dynamic-fanout.ts +402 -238
  775. package/src/runs/shared/dynamic-item.ts +114 -0
  776. package/src/runs/shared/history-index.ts +112 -51
  777. package/src/runs/shared/legacy-async-recovery.ts +153 -0
  778. package/src/runs/shared/legacy-output-recovery.ts +214 -0
  779. package/src/runs/shared/mcp-config-schema.ts +46 -0
  780. package/src/runs/shared/mcp-direct-tool-allowlist.ts +396 -307
  781. package/src/runs/shared/model-fallback.ts +302 -180
  782. package/src/runs/shared/mutating-tool-guard.ts +259 -158
  783. package/src/runs/shared/native-finalization-types.ts +29 -0
  784. package/src/runs/shared/native-finalization.ts +233 -109
  785. package/src/runs/shared/native-usage.ts +379 -96
  786. package/src/runs/shared/nested-control-records.ts +178 -0
  787. package/src/runs/shared/nested-events.ts +45 -752
  788. package/src/runs/shared/nested-path.ts +47 -34
  789. package/src/runs/shared/nested-projection.ts +230 -0
  790. package/src/runs/shared/nested-protocol.ts +67 -0
  791. package/src/runs/shared/nested-registry.ts +273 -0
  792. package/src/runs/shared/nested-render.ts +198 -100
  793. package/src/runs/shared/nested-route.ts +292 -0
  794. package/src/runs/shared/nested-validation.ts +291 -0
  795. package/src/runs/shared/owned-child-evidence.ts +184 -0
  796. package/src/runs/shared/owned-run-list.ts +187 -0
  797. package/src/runs/shared/owned-run-observation.ts +368 -0
  798. package/src/runs/shared/owned-run-progress.ts +172 -0
  799. package/src/runs/shared/owned-run-read-state.ts +7 -0
  800. package/src/runs/shared/owned-run-results.ts +289 -0
  801. package/src/runs/shared/owned-run-status.ts +239 -0
  802. package/src/runs/shared/owned-run-view.ts +65 -0
  803. package/src/runs/shared/owned-workflow-details.ts +24 -0
  804. package/src/runs/shared/owner-output.ts +73 -0
  805. package/src/runs/shared/parallel-utils.ts +93 -129
  806. package/src/runs/shared/parent-receipts.ts +177 -50
  807. package/src/runs/shared/parent-usage.ts +314 -91
  808. package/src/runs/shared/pi-args.ts +241 -311
  809. package/src/runs/shared/pi-launch-input.ts +48 -0
  810. package/src/runs/shared/pi-session-launch.ts +94 -0
  811. package/src/runs/shared/pi-spawn.ts +57 -33
  812. package/src/runs/shared/run-history-queries.ts +189 -38
  813. package/src/runs/shared/run-history.ts +197 -76
  814. package/src/runs/shared/run-id-ambiguity.ts +7 -3
  815. package/src/runs/shared/run-metadata-paths.ts +17 -0
  816. package/src/runs/shared/run-metadata.ts +240 -0
  817. package/src/runs/shared/run-persistence.ts +181 -0
  818. package/src/runs/shared/run-records.ts +19 -607
  819. package/src/runs/shared/run-restoration.ts +455 -0
  820. package/src/runs/shared/run-state-owner.ts +31 -0
  821. package/src/runs/shared/session-cwd-preload.ts +39 -19
  822. package/src/runs/shared/single-output.ts +358 -205
  823. package/src/runs/shared/stable-value.ts +15 -0
  824. package/src/runs/shared/streaming-text.ts +39 -12
  825. package/src/runs/shared/structured-output.ts +76 -46
  826. package/src/runs/shared/subagent-control.ts +330 -197
  827. package/src/runs/shared/subagent-prompt-runtime.ts +92 -174
  828. package/src/runs/shared/subagent-tool-loop-guard.ts +118 -68
  829. package/src/runs/shared/supervisor-question-state.ts +221 -0
  830. package/src/runs/shared/supervisor-questions.ts +396 -401
  831. package/src/runs/shared/workflow-graph.ts +400 -198
  832. package/src/runs/shared/workflow-policy.ts +245 -110
  833. package/src/runs/shared/worktree-contract.ts +29 -0
  834. package/src/runs/shared/worktree-hook.ts +181 -0
  835. package/src/runs/shared/worktree-location.ts +61 -0
  836. package/src/runs/shared/worktree-preservation.ts +10 -0
  837. package/src/runs/shared/worktree-process.ts +132 -0
  838. package/src/runs/shared/worktree.ts +459 -587
  839. package/src/shared/agent-context-policy.ts +176 -145
  840. package/src/shared/agent-dir.ts +15 -0
  841. package/src/shared/artifacts.ts +99 -68
  842. package/src/shared/atomic-json.ts +14 -11
  843. package/src/shared/chain-files.ts +72 -0
  844. package/src/shared/concurrency.ts +27 -0
  845. package/src/shared/content-preview.ts +117 -0
  846. package/src/shared/cooperative.ts +17 -13
  847. package/src/shared/execution-cwd.ts +34 -9
  848. package/src/shared/file-coalescer.ts +24 -22
  849. package/src/shared/fork-context.ts +52 -48
  850. package/src/shared/formatters.ts +88 -47
  851. package/src/shared/journal-frames.ts +197 -0
  852. package/src/shared/journal-projections.ts +133 -0
  853. package/src/shared/journal-reader.ts +18 -333
  854. package/src/shared/json-projection.ts +224 -0
  855. package/src/shared/lazy-tools.ts +76 -27
  856. package/src/shared/message-output.ts +146 -0
  857. package/src/shared/model-info.ts +94 -58
  858. package/src/shared/native-import.ts +25 -0
  859. package/src/shared/native-journal.ts +172 -0
  860. package/src/shared/native-session-loader.ts +13 -0
  861. package/src/shared/native-session.ts +3 -5
  862. package/src/shared/native-tui.ts +13 -3
  863. package/src/shared/native-typebox.ts +18 -3
  864. package/src/shared/output-page.ts +76 -0
  865. package/src/shared/post-exit-stdio-guard.ts +232 -172
  866. package/src/shared/prompt-sections.ts +13 -7
  867. package/src/shared/session-entries.ts +103 -44
  868. package/src/shared/session-identity.ts +17 -10
  869. package/src/shared/settings.ts +182 -367
  870. package/src/shared/status-format.ts +207 -98
  871. package/src/shared/stream-json.d.ts +10 -0
  872. package/src/shared/task-file-policy.ts +35 -0
  873. package/src/shared/temp-root.ts +122 -71
  874. package/src/shared/types/acceptance.ts +149 -0
  875. package/src/shared/types/async.ts +247 -0
  876. package/src/shared/types/config.ts +139 -0
  877. package/src/shared/types/details.ts +104 -0
  878. package/src/shared/types/history.ts +217 -0
  879. package/src/shared/types/inputs.ts +4 -0
  880. package/src/shared/types/intercom.ts +57 -0
  881. package/src/shared/types/launch.ts +39 -0
  882. package/src/shared/types/messages.ts +104 -0
  883. package/src/shared/types/nested.ts +153 -0
  884. package/src/shared/types/owned-runs.ts +148 -0
  885. package/src/shared/types/progress.ts +106 -0
  886. package/src/shared/types/questions.ts +103 -0
  887. package/src/shared/types/results.ts +119 -0
  888. package/src/shared/types/state.ts +56 -0
  889. package/src/shared/types/usage.ts +36 -0
  890. package/src/shared/types/workflow.ts +187 -0
  891. package/src/shared/types.ts +222 -1161
  892. package/src/shared/ui-mode.ts +1 -1
  893. package/src/shared/unknown.ts +59 -0
  894. package/src/shared/utils.ts +111 -305
  895. package/src/slash/command-discovery.ts +109 -0
  896. package/src/slash/command-input.ts +232 -0
  897. package/src/slash/prompt-template-bridge.ts +153 -400
  898. package/src/slash/prompt-template-contract.ts +152 -0
  899. package/src/slash/prompt-template-results.ts +189 -0
  900. package/src/slash/request-protocol.ts +87 -0
  901. package/src/slash/result-delivery.ts +312 -0
  902. package/src/slash/saved-chain.ts +115 -0
  903. package/src/slash/slash-bridge.ts +202 -156
  904. package/src/slash/slash-commands.ts +176 -598
  905. package/src/slash/slash-live-state.ts +287 -229
  906. package/src/tui/action-hints.ts +147 -61
  907. package/src/tui/activity-lines.ts +40 -0
  908. package/src/tui/agent-browser.ts +354 -0
  909. package/src/tui/agent-controls.ts +355 -0
  910. package/src/tui/agent-conversation.ts +514 -0
  911. package/src/tui/agent-dock.ts +250 -0
  912. package/src/tui/agent-history.ts +78 -203
  913. package/src/tui/agent-model.ts +78 -0
  914. package/src/tui/agent-picker.ts +325 -0
  915. package/src/tui/agent-view.ts +391 -1333
  916. package/src/tui/compact-results.ts +342 -0
  917. package/src/tui/conversation-details.ts +206 -0
  918. package/src/tui/conversation-frame.ts +184 -0
  919. package/src/tui/conversation-history.ts +246 -0
  920. package/src/tui/conversation-menu.ts +119 -0
  921. package/src/tui/conversation-notices.ts +116 -0
  922. package/src/tui/conversation-selection.ts +66 -0
  923. package/src/tui/conversation-viewport.ts +169 -0
  924. package/src/tui/direction-message.ts +35 -0
  925. package/src/tui/display.ts +409 -0
  926. package/src/tui/editor-viewport.ts +19 -0
  927. package/src/tui/expanded-content.ts +134 -0
  928. package/src/tui/expanded-multi.ts +264 -0
  929. package/src/tui/expanded-single.ts +92 -0
  930. package/src/tui/history-cards.ts +316 -0
  931. package/src/tui/history-display.ts +334 -0
  932. package/src/tui/history-json.ts +17 -0
  933. package/src/tui/history-metadata.ts +177 -0
  934. package/src/tui/history-record.ts +321 -0
  935. package/src/tui/history-text.ts +34 -0
  936. package/src/tui/indexed-history.ts +149 -0
  937. package/src/tui/nested-widget.ts +192 -0
  938. package/src/tui/picker-page.ts +80 -0
  939. package/src/tui/render.ts +100 -1546
  940. package/src/tui/result-facts.ts +99 -0
  941. package/src/tui/task-observation.ts +96 -0
  942. package/src/tui/task-store.ts +432 -0
  943. package/src/tui/text-values.ts +20 -0
  944. package/src/tui/view-connections.ts +64 -0
  945. package/src/tui/view-model.ts +181 -0
  946. package/src/tui/view-persistence.ts +57 -0
  947. package/src/tui/view-ports.ts +55 -0
  948. package/src/tui/view-session.ts +42 -0
  949. package/src/tui/widget-details.ts +220 -0
  950. package/src/tui/widget-status.ts +331 -0
  951. package/src/tui/widget.ts +208 -0
  952. package/src/tui/workflow-labels.ts +340 -0
  953. package/src/tui/workflow-outcomes.ts +150 -0
  954. package/tsconfig.build.json +11 -10
  955. package/tsconfig.json +30 -17
@@ -1,817 +1,276 @@
1
- import { randomUUID } from "node:crypto";
2
- import { formatRunIdAmbiguity } from "../shared/run-id-ambiguity.js";
3
- import { resolveRootSessionId } from "../../shared/session-identity.js";
4
- import { writeAsyncControlRequest, writeAsyncInterruptRequest } from "../background/async-control.js";
5
- import { getRunMetadataDir, listSupervisorQuestions, questionProcessAlive, readQuestionContract, readRunJson, recordQuestionDelivery, saveQuestionOwner } from "../shared/supervisor-questions.js";
6
- import * as fs from "node:fs";
7
1
  import * as path from "node:path";
8
- import {} from "../../agents/agents.js";
9
- import { providerQualifiedModelId, toModelInfo } from "../../shared/model-info.js";
10
- import { normalizeSkillInput } from "../../agents/skills.js";
11
- import { resolveExecutionAgentScope } from "../../agents/agent-scope.js";
12
- import { executeAsyncSingle, formatAsyncStartedMessage } from "../background/async-execution.js";
13
- import { resolveConfiguredChildProjectTrustPolicy } from "../shared/pi-args.js";
14
- import { requestChildExecutionCwd } from "../shared/child-execution-cwd.js";
15
- import { resolveCurrentSessionId } from "../../shared/session-identity.js";
16
- import { resolveIntercomBridge, resolveIntercomSessionTarget, resolveOrchestratorIntercomTarget, resolveSubagentIntercomTarget } from "../../intercom/intercom-bridge.js";
17
- import { resolveControlConfig } from "../shared/subagent-control.js";
18
- import { readStatus } from "../../shared/utils.js";
2
+ import { errorMessage } from "../../shared/unknown.js";
3
+ import { listSupervisorQuestions, readQuestionContract } from "../shared/supervisor-questions.js";
19
4
  import { deliverSubagentIntercomMessageEvent } from "../../intercom/result-intercom.js";
20
- import { sendLiveSubagentMessage } from "../../intercom/live-intercom.js";
21
- import { buildRevivedAsyncTask, resolveAsyncResumeTarget } from "../background/async-resume.js";
22
- import { readNestedControlResults, resolveInheritedNestedRouteFromEnv, resolveNestedAsyncDir, resolveNestedParentAddressFromEnv, writeNestedControlRequest } from "../shared/nested-events.js";
23
- import { inspectSubagentStatus } from "../background/run-status.js";
24
5
  import { resolveSubagentRunId } from "../background/run-id-resolver.js";
25
6
  import { buildManagementControl, formatRunAction } from "../../shared/status-format.js";
26
- import { acceptanceInputFromResolved } from "../shared/acceptance.js";
27
- import { ownedRunStatusResult, ownedRunView, rememberOwnedRun, resolveOwnedRun } from "../shared/run-records.js";
28
- import { ASYNC_DIR, getAsyncConfigPath, RUNNER_ERROR_LOG_FILE, checkSubagentDepth, resolveCurrentMaxSubagentDepth, } from "../../shared/types.js";
29
- import {} from "./subagent-params.js";
7
+ import { ownedRunView, resolveOwnedRun } from "../shared/run-records.js";
8
+ import { nestedResolutionScopeForExecutor } from "./execution-routing.js";
9
+ import { resolveResumeTarget, resolveNestedResumeTarget, } from "./resume-target.js";
10
+ import { LIVE_ACCEPTANCE_OVERRIDE_NOTICE, resumeLiveNestedRun } from "./nested-control.js";
11
+ import { nudgeSubagentRun } from "./run-nudge.js";
12
+ import { reviveSavedSubagent } from "./saved-revival.js";
13
+ import { continueQuestionSession } from "./question-continuation.js";
30
14
  export { writeAsyncInterruptRequest } from "../background/async-control.js";
31
- export const MUTATING_MANAGEMENT_ACTIONS = new Set(["create", "update", "delete"]);
32
- export function resolveRequestedCwd(runtimeCwd, requestedCwd) {
33
- return requestedCwd ? path.resolve(runtimeCwd, requestedCwd) : runtimeCwd;
34
- }
35
- export function nestedResolutionScopeForExecutor(deps) {
36
- if (deps.allowMutatingManagementActions !== false)
37
- return undefined;
38
- const route = resolveInheritedNestedRouteFromEnv();
39
- const address = route ? resolveNestedParentAddressFromEnv() : undefined;
40
- return {
41
- routes: route ? [route] : [],
42
- ...(address ? { descendantOf: { parentRunId: address.parentRunId, ...(address.parentStepIndex !== undefined ? { parentStepIndex: address.parentStepIndex } : {}) } } : {}),
43
- };
44
- }
45
- const LATEST_FOREGROUND_ALIASES = new Set(["last", "latest"]);
46
- export function resolveRememberedForegroundRun(requested, state) {
47
- if (!requested || !state.foregroundRuns?.size)
48
- return undefined;
49
- const normalized = requested.trim();
50
- if (!normalized)
51
- return undefined;
52
- if (LATEST_FOREGROUND_ALIASES.has(normalized)) {
53
- return [...state.foregroundRuns.values()].sort((left, right) => right.updatedAt - left.updatedAt)[0];
54
- }
55
- const direct = state.foregroundRuns.get(normalized);
56
- const matches = direct ? [direct] : [...state.foregroundRuns.values()].filter((run) => run.runId.startsWith(normalized));
57
- if (matches.length === 0)
58
- return undefined;
59
- if (matches.length > 1)
60
- throw new Error(formatRunIdAmbiguity("foreground", normalized, matches.map((run) => run.runId)));
61
- return matches[0];
62
- }
63
- function foregroundResumeGuidance(run, childSafe) {
64
- const childWithSession = run.children.find((child) => child.sessionFile && child.status !== "detached");
65
- if (!childWithSession && run.children.some((child) => child.status === "detached"))
66
- return `Completion unconfirmed. Check ${formatRunAction("questions", run.runId, {}, childSafe)} before continuing.`;
67
- if (run.children.length === 1 && childWithSession)
68
- return `Continue: ${formatRunAction("resume", run.runId, { message: "..." }, childSafe)}`;
69
- if (!childWithSession)
70
- return "Revive: unavailable; no child session file was persisted.";
71
- return `Continue child: ${formatRunAction("resume", run.runId, { index: childWithSession.index, message: "..." }, childSafe)}`;
72
- }
73
- function compactStatusText(value, maxLength = 240) {
74
- const normalized = value.replace(/\s+/g, " ").trim();
75
- return normalized.length > maxLength ? `${normalized.slice(0, maxLength - 1)}…` : normalized;
76
- }
77
- function foregroundResultChildren(run) {
78
- return run.children.map((child) => ({ child, finalOutput: child.summary }));
79
- }
80
- function rememberedForegroundState(children) {
81
- if (children.some(({ child }) => child.status === "failed" || child.status === "timed-out"))
82
- return "failed";
83
- if (children.some(({ child }) => child.status === "blocked"))
84
- return "blocked";
85
- if (children.some(({ child }) => child.status === "paused"))
86
- return "paused";
87
- return children.some(({ child }) => child.status === "detached") ? "unknown" : "completed";
88
- }
89
- export function rememberedForegroundStatusResult(run, childSafe = false) {
90
- const children = foregroundResultChildren(run);
91
- const childState = rememberedForegroundState(children);
92
- const state = run.error ? "failed" : childState === "completed" && run.pausedReason ? "paused" : childState;
93
- const resumable = children.find(({ child }) => child.sessionFile && child.status !== "detached")?.child;
94
- const lines = [
95
- `Run: ${run.runId}`,
96
- "State: remembered foreground",
97
- `Outcome: ${state}`,
98
- ...(run.error ? [`Error: ${run.error}`] : state === "paused" && run.pausedReason ? [run.pausedReason] : []),
99
- `Mode: ${run.mode}`,
100
- `Updated: ${new Date(run.updatedAt).toISOString()}`,
101
- `Launch cwd: ${run.cwd}`,
102
- "Children:",
103
- ...children.map(({ child, finalOutput }) => ` ${child.index + 1}. ${child.agent} ${child.status}${child.sessionFile ? `, session: ${child.sessionFile}` : ""}${child.artifactPath ? `, artifact: ${child.artifactPath}` : ""}${finalOutput ? `, final: ${compactStatusText(finalOutput)}` : ""}`),
104
- foregroundResumeGuidance(run, childSafe),
105
- `Status: ${formatRunAction("status", run.runId, {}, childSafe)}`,
106
- ];
15
+ export { MUTATING_MANAGEMENT_ACTIONS, resolveRequestedCwd, nestedResolutionScopeForExecutor, } from "./execution-routing.js";
16
+ export { rememberedForegroundStatusResult, resolveRememberedForegroundRun, } from "./foreground-memory.js";
17
+ export { extendAsyncTimeoutResult, interruptAsyncRun } from "./run-interrupt.js";
18
+ export { interruptNestedRun } from "./nested-control.js";
19
+ export { nudgeSubagentRun } from "./run-nudge.js";
20
+ export { reviveSavedSubagent } from "./saved-revival.js";
21
+ function failure(text) {
107
22
  return {
108
- content: [{ type: "text", text: lines.join("\n") }],
109
- details: {
110
- mode: "management", results: [],
111
- managementControl: buildManagementControl({ state, runId: run.runId, index: resumable?.index, canResume: Boolean(resumable) }),
112
- },
23
+ content: [{ type: "text", text }],
24
+ isError: true,
25
+ details: { mode: "management", results: [] },
113
26
  };
114
27
  }
115
- function resolveForegroundResumeTarget(params, state) {
116
- const requested = (params.id ?? params.runId)?.trim();
117
- const run = resolveRememberedForegroundRun(requested, state);
118
- if (!run)
119
- return undefined;
120
- if (run.children.length > 1 && params.index === undefined)
121
- throw new Error(`Foreground run '${run.runId}' has ${run.children.length} children. Provide index to choose one.`);
122
- const index = params.index ?? 0;
123
- if (!Number.isInteger(index))
124
- throw new Error(`Foreground run '${run.runId}' index must be an integer.`);
125
- if (index < 0 || index >= run.children.length)
126
- throw new Error(`Foreground run '${run.runId}' has ${run.children.length} children. Index ${index} is out of range.`);
127
- const child = run.children[index];
128
- if (child.status === "detached")
129
- throw new Error(`Foreground run '${run.runId}' child ${index} is detached for intercom coordination and cannot be revived safely from the remembered foreground state. Reply to the supervisor request first; after the child exits, start a fresh follow-up if needed.`);
130
- if (!child.sessionFile)
131
- throw new Error(`Foreground run '${run.runId}' child ${index} does not have a persisted session file to resume from.`);
132
- if (path.extname(child.sessionFile) !== ".jsonl")
133
- throw new Error(`Foreground run '${run.runId}' child ${index} session file must be a .jsonl file: ${child.sessionFile}`);
134
- const sessionFile = path.resolve(child.sessionFile);
135
- if (!fs.existsSync(sessionFile))
136
- throw new Error(`Foreground run '${run.runId}' child ${index} session file does not exist: ${child.sessionFile}`);
137
- return { runId: run.runId, mode: run.mode, state: "complete", agent: child.agent, index, intercomTarget: resolveSubagentIntercomTarget(run.runId, child.agent, index), cwd: run.cwd, sessionFile, effectiveAcceptance: child.effectiveAcceptance };
138
- }
139
- function isAsyncRunNotFound(error) {
140
- return error instanceof Error && error.message.startsWith("Async run not found.");
141
- }
142
- function isResumeAmbiguity(error) {
143
- return error instanceof Error && /Ambiguous .*run id prefix/.test(error.message);
28
+ function requestedOwnedId(params) {
29
+ const id = params.id ?? params.runId;
30
+ return id !== undefined && id.length > 0 && (params.dir === undefined || params.dir.length === 0)
31
+ ? id
32
+ : undefined;
144
33
  }
145
- function resumeTargetExact(target, requested) {
146
- return target?.runId === requested;
34
+ export function liveLaunchOverrideNotice(params) {
35
+ if (params.acceptance !== undefined) {
36
+ return LIVE_ACCEPTANCE_OVERRIDE_NOTICE;
37
+ }
38
+ return [
39
+ params.agent,
40
+ params.model,
41
+ params.cwd,
42
+ params.output,
43
+ params.outputMode,
44
+ params.outputSchema,
45
+ params.skill,
46
+ params.maxOutput,
47
+ params.control,
48
+ params.artifacts,
49
+ params.share,
50
+ ].some((value) => value !== undefined)
51
+ ? "Launch overrides change a newly started continuation, not this live child. No launch settings were changed."
52
+ : undefined;
147
53
  }
148
- function escapeRegExp(value) {
149
- return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
54
+ function withLiveNotice(result, params) {
55
+ const notice = liveLaunchOverrideNotice(params);
56
+ if (notice !== undefined) {
57
+ result.content.push({ type: "text", text: notice });
58
+ }
59
+ return result;
150
60
  }
151
- function isExactResumeError(error, source, requested) {
152
- if (!(error instanceof Error) || !requested)
153
- return false;
154
- return new RegExp(`\\b${source} run '${escapeRegExp(requested)}'`, "i").test(error.message);
61
+ function normalizedFollowUp(params) {
62
+ return (params.message ?? params.task ?? "").trim();
155
63
  }
156
- function resolveResumeTarget(params, state) {
157
- const requested = (params.id ?? params.runId)?.trim() ?? "";
158
- let foregroundTarget;
159
- let foregroundError;
160
- let asyncTarget;
161
- let asyncError;
162
- try {
163
- const target = resolveForegroundResumeTarget(params, state);
164
- if (target)
165
- foregroundTarget = { kind: "revive", source: "foreground", ...target };
166
- }
167
- catch (error) {
168
- foregroundError = error;
169
- }
170
- try {
171
- asyncTarget = { source: "async", ...resolveAsyncResumeTarget(params) };
172
- }
173
- catch (error) {
174
- asyncError = error;
175
- }
176
- if (foregroundTarget && asyncTarget) {
177
- const foregroundExact = resumeTargetExact(foregroundTarget, requested);
178
- const asyncExact = resumeTargetExact(asyncTarget, requested);
179
- if (foregroundExact && !asyncExact)
180
- return foregroundTarget;
181
- if (asyncExact && !foregroundExact)
182
- return asyncTarget;
183
- throw new Error(`Resume id '${requested}' is ambiguous between foreground run '${foregroundTarget.runId}' and async run '${asyncTarget.runId}'. Provide a full run id.`);
184
- }
185
- if (foregroundTarget) {
186
- if (isExactResumeError(asyncError, "async", requested))
187
- throw asyncError;
188
- if (isResumeAmbiguity(asyncError) && !resumeTargetExact(foregroundTarget, requested))
189
- throw asyncError;
190
- return foregroundTarget;
191
- }
192
- if (asyncTarget) {
193
- if (isExactResumeError(foregroundError, "foreground", requested))
194
- throw foregroundError;
195
- if (isResumeAmbiguity(foregroundError) && !resumeTargetExact(asyncTarget, requested))
196
- throw foregroundError;
197
- return asyncTarget;
198
- }
199
- if (foregroundError && !isAsyncRunNotFound(asyncError))
200
- throw foregroundError;
201
- if (foregroundError)
202
- throw foregroundError;
203
- if (asyncError)
204
- throw asyncError;
205
- throw new Error("Run not found. Provide id or runId.");
64
+ function usesSession(candidate, deps, sessionFile) {
65
+ return (candidate.children.some((child) => child.sessionFile === sessionFile) ||
66
+ deps.state.asyncJobs.get(candidate.runId)?.sessionFile === sessionFile);
206
67
  }
207
- function getAsyncInterruptTarget(state, runId) {
208
- if (runId) {
209
- const direct = state.asyncJobs.get(runId);
210
- if (direct)
211
- return { asyncId: direct.asyncId, asyncDir: direct.asyncDir };
212
- const owned = resolveOwnedRun(state, runId);
213
- return owned?.asyncDir ? { asyncId: owned.runId, asyncDir: owned.asyncDir } : undefined;
68
+ function nudgeContinuation(input, runId, sessionFile) {
69
+ if (sessionFile === undefined || sessionFile.length === 0) {
70
+ return;
214
71
  }
215
- let newest;
216
- for (const job of state.asyncJobs.values()) {
217
- if (job.status !== "running")
72
+ for (const candidate of input.deps.state.ownedRuns?.values() ?? []) {
73
+ if (candidate.runId === runId) {
218
74
  continue;
219
- if (!newest || (job.updatedAt ?? 0) > newest.updatedAt) {
220
- newest = { asyncId: job.asyncId, asyncDir: job.asyncDir, updatedAt: job.updatedAt ?? 0 };
221
75
  }
222
- }
223
- for (const run of state.ownedRuns?.values() ?? []) {
224
- if (!run.asyncDir || (newest && run.startedAt <= newest.updatedAt))
76
+ if (!usesSession(candidate, input.deps, sessionFile)) {
225
77
  continue;
226
- const status = readStatus(run.asyncDir);
227
- if (status ? status.state !== "running" && status.state !== "queued" : !run.pid || !questionProcessAlive({ pid: run.pid }))
78
+ }
79
+ const active = ownedRunView(candidate, input.deps.state, {
80
+ readConfiguration: false,
81
+ }).children.find((child) => child.sessionFile === sessionFile && child.state === "live");
82
+ if (!active) {
228
83
  continue;
229
- newest = { asyncId: run.runId, asyncDir: run.asyncDir, updatedAt: run.startedAt };
230
- }
231
- return newest ? { asyncId: newest.asyncId, asyncDir: newest.asyncDir } : undefined;
232
- }
233
- export function extendAsyncTimeoutResult(state, runId, extendMs) {
234
- const target = getAsyncInterruptTarget(state, runId);
235
- const status = target && readStatus(target.asyncDir);
236
- const launch = target && readRunJson(path.join(target.asyncDir, "launch.json"));
237
- const extendable = status ? status.runtimeVersion === 2 && status.state === "running" && !status.timedOut && status.timeoutAt
238
- : launch?.runtimeVersion === 2 && launch.timeoutMs;
239
- if (!target || !extendable)
240
- return {
241
- content: [{ type: "text", text: "No live run with an extendable timeout was found. No extension was requested." }], isError: true, details: { mode: "management", results: [] },
242
- };
243
- try {
244
- writeAsyncControlRequest(target.asyncDir, target.asyncId, "extend", undefined, extendMs);
245
- return { content: [{ type: "text", text: `Requested ${extendMs}ms more for run ${target.asyncId}. Inspect status for the owner's updated deadline.` }],
246
- details: { mode: "management", results: [], managementControl: buildManagementControl({ state: "live", runId: target.asyncId, canInterrupt: true, canExtend: true }) } };
247
- }
248
- catch (error) {
249
- return { content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }], isError: true, details: { mode: "management", results: [] } };
250
- }
251
- }
252
- export function interruptAsyncRun(state, runId, index) {
253
- const target = getAsyncInterruptTarget(state, runId);
254
- if (!target)
255
- return null;
256
- const status = readStatus(target.asyncDir);
257
- if (!status || status.runId !== target.asyncId || status.state !== "running") {
258
- return {
259
- content: [{ type: "text", text: `No running async run with a matching control channel was found for '${runId ?? "current"}'.` }],
260
- isError: true,
261
- details: { mode: "management", results: [] },
262
- };
263
- }
264
- if (index !== undefined && !status.indexedControl && (status.steps?.length ?? 0) > 1)
265
- return {
266
- content: [{ type: "text", text: "This older runner does not support selected-child stop. No stop was sent; whole-run stop remains an explicit separate action." }], isError: true, details: { mode: "management", results: [] },
267
- };
268
- if (index !== undefined && (!Number.isSafeInteger(index) || index < 0 || status.steps?.[index]?.status !== "running")) {
269
- return { content: [{ type: "text", text: `Async run ${target.asyncId} has no running child at index ${index}. No siblings were stopped.` }], isError: true, details: { mode: "management", results: [] } };
270
- }
271
- try {
272
- writeAsyncInterruptRequest(target.asyncDir, target.asyncId, index);
273
- const tracked = state.asyncJobs.get(target.asyncId);
274
- if (tracked) {
275
- tracked.activityState = undefined;
276
- tracked.updatedAt = Date.now();
277
84
  }
278
- return {
279
- content: [{ type: "text", text: `Interrupt requested for async run ${target.asyncId}${index !== undefined ? ` child ${index} only` : ""}. Agent and command exit are not yet confirmed.` }],
280
- details: { mode: "management", results: [], managementControl: buildManagementControl({ state: "live", runId: target.asyncId }) },
281
- };
282
- }
283
- catch (error) {
284
- const message = error instanceof Error ? error.message : String(error);
285
- return {
286
- content: [{ type: "text", text: `Failed to interrupt async run ${target.asyncId}: ${message}` }],
287
- isError: true,
288
- details: { mode: "management", results: [] },
289
- };
290
- }
291
- }
292
- function nestedRunSessionFile(run) {
293
- return run.sessionFile ?? (run.steps?.length === 1 ? run.steps[0]?.sessionFile : undefined);
294
- }
295
- function nestedRunAgent(run) {
296
- return run.agent ?? run.agents?.[0] ?? (run.steps?.length === 1 ? run.steps[0]?.agent : undefined);
297
- }
298
- function pathWithin(base, candidate) {
299
- const resolvedBase = path.resolve(base);
300
- const resolvedCandidate = path.resolve(candidate);
301
- return resolvedCandidate === resolvedBase || resolvedCandidate.startsWith(`${resolvedBase}${path.sep}`);
302
- }
303
- function validateNestedSessionFile(run, trustedSessionRoots) {
304
- const sessionFile = nestedRunSessionFile(run);
305
- if (!sessionFile)
306
- throw new Error(`Nested run '${run.id}' does not have a persisted session file to resume from.`);
307
- if (path.extname(sessionFile) !== ".jsonl")
308
- throw new Error(`Nested run '${run.id}' session file must be a .jsonl file: ${sessionFile}`);
309
- const resolved = path.resolve(sessionFile);
310
- if (!path.isAbsolute(sessionFile))
311
- throw new Error(`Nested run '${run.id}' session file must be absolute: ${sessionFile}`);
312
- if (!fs.existsSync(resolved))
313
- throw new Error(`Nested run '${run.id}' session file does not exist: ${sessionFile}`);
314
- const stat = fs.lstatSync(resolved);
315
- if (!stat.isFile() || stat.isSymbolicLink())
316
- throw new Error(`Nested run '${run.id}' session file is not a regular file: ${sessionFile}`);
317
- const realSessionFile = fs.realpathSync(resolved);
318
- const trustedRoots = trustedSessionRoots
319
- .filter((root) => fs.existsSync(root))
320
- .map((root) => fs.realpathSync(root));
321
- if (!trustedRoots.some((root) => pathWithin(root, realSessionFile))) {
322
- throw new Error(`Nested run '${run.id}' session file is outside trusted nested session roots: ${sessionFile}`);
85
+ return nudgeSubagentRun({
86
+ params: {
87
+ ...input.params,
88
+ dir: undefined,
89
+ id: candidate.runId,
90
+ index: active.index,
91
+ message: normalizedFollowUp(input.params),
92
+ },
93
+ deps: input.deps,
94
+ ctx: input.ctx,
95
+ }).then((result) => withLiveNotice(result, input.params));
96
+ }
97
+ return;
98
+ }
99
+ async function resumeOwned(
100
+ // Owned continuation may persist a new run; deps retains the actual session mutation owner.
101
+ input, owned) {
102
+ const view = ownedRunView(owned, input.deps.state);
103
+ if (view.children.length > 1 && input.params.index === undefined) {
104
+ throw new Error(`Run '${owned.runId}' has ${view.children.length} children. Provide index to choose one.`);
105
+ }
106
+ const child = view.children.find((entry) => entry.index === (input.params.index ?? 0));
107
+ if (!child) {
108
+ throw new Error(`Run '${owned.runId}' has no child at index ${input.params.index ?? 0}.`);
109
+ }
110
+ if (child.state === "live") {
111
+ return withLiveNotice(await nudgeSubagentRun({
112
+ params: {
113
+ ...input.params,
114
+ id: owned.runId,
115
+ message: normalizedFollowUp(input.params),
116
+ },
117
+ deps: input.deps,
118
+ ctx: input.ctx,
119
+ }), input.params);
323
120
  }
324
- if (!realSessionFile.split(path.sep).includes(run.id)) {
325
- throw new Error(`Nested run '${run.id}' session file is not under that nested run's session directory: ${sessionFile}`);
121
+ const liveContinuation = nudgeContinuation(input, owned.runId, child.sessionFile);
122
+ if (liveContinuation) {
123
+ return await liveContinuation;
326
124
  }
327
- return realSessionFile;
125
+ return reviveSavedSubagent(input, ownedRevivalTarget(owned, child));
328
126
  }
329
- function resolveNestedResumeTarget(match, trustedSessionRoots) {
330
- const run = match.match.run;
331
- if (run.state === "running" || run.state === "queued")
332
- throw new Error(`Nested run '${run.id}' is live; route the follow-up to the owner process instead.`);
333
- const agent = nestedRunAgent(run);
334
- if (!agent)
335
- throw new Error(`Could not determine child agent for nested run '${run.id}'.`);
336
- const state = run.state === "complete" || run.state === "failed" || run.state === "blocked" || run.state === "paused" ? run.state : "failed";
337
- const asyncDir = resolveNestedAsyncDir(match.match.rootRunId, run);
338
- const effectiveAcceptance = asyncDir ? readStatus(asyncDir)?.steps?.[0]?.acceptance?.effectiveAcceptance : undefined;
127
+ function ownedRevivalTarget(owned, child) {
128
+ const contract = readQuestionContract(owned.runId, child.index);
339
129
  return {
340
- kind: "revive",
341
- source: "nested",
342
- runId: run.id,
343
- state,
344
- agent,
345
- index: 0,
346
- intercomTarget: resolveSubagentIntercomTarget(run.id, agent, 0),
347
- cwd: asyncDir ? path.dirname(asyncDir) : undefined,
348
- sessionFile: validateNestedSessionFile(run, trustedSessionRoots),
349
- effectiveAcceptance,
130
+ ...contract,
131
+ runId: owned.runId,
132
+ agent: child.agent,
133
+ index: child.index,
134
+ source: owned.source,
135
+ cwd: child.launch?.cwd ?? owned.cwd,
136
+ sessionFile: child.sessionFile,
137
+ effectiveAcceptance: contract?.effectiveAcceptance ?? child.result?.acceptance?.effectiveAcceptance,
138
+ model: child.result?.model,
350
139
  };
351
140
  }
352
- async function waitForNestedControlResult(target, requestId, timeoutMs = 1_000) {
353
- const deadline = Date.now() + timeoutMs;
354
- while (Date.now() < deadline) {
355
- const result = readNestedControlResults(target.match.route).find((candidate) => candidate.requestId === requestId && candidate.targetRunId === target.match.run.id);
356
- if (result)
357
- return result;
358
- await new Promise((resolve) => setTimeout(resolve, 50));
141
+ function trustedSessionRoots(input, parentSessionFile) {
142
+ const roots = [];
143
+ const configured = input.deps.config.defaultSessionDir;
144
+ if (configured !== undefined && configured.length > 0) {
145
+ roots.push(path.resolve(input.deps.expandTilde(configured)));
146
+ }
147
+ if (parentSessionFile !== null && parentSessionFile.length > 0) {
148
+ roots.push(input.deps.getSubagentSessionRoot(parentSessionFile));
359
149
  }
360
- return undefined;
150
+ return roots;
361
151
  }
362
- async function sendNestedControlRequest(target, action, message, index) {
363
- const requestId = randomUUID();
364
- const targetChildIndex = target.match.run.path?.[0]?.stepIndex ?? target.match.run.parentStepIndex;
365
- writeNestedControlRequest(target.match.route, {
366
- ts: Date.now(),
367
- requestId,
368
- targetRunId: target.match.run.id,
369
- ...(targetChildIndex !== undefined ? { targetChildIndex } : {}),
370
- action,
371
- ...(index !== undefined ? { index } : {}),
372
- ...(message ? { message } : {}),
152
+ function resolveRequestedRun(params, deps) {
153
+ const id = params.id ?? params.runId;
154
+ if (id === undefined || id.length === 0) {
155
+ return;
156
+ }
157
+ return resolveSubagentRunId(id, {
158
+ state: deps.state,
159
+ nested: nestedResolutionScopeForExecutor(deps),
373
160
  });
374
- return waitForNestedControlResult(target, requestId);
375
161
  }
376
- function directNestedAsyncInterrupt(target, index) {
377
- const run = target.match.run;
378
- const asyncDir = resolveNestedAsyncDir(target.match.rootRunId, run);
379
- if (!asyncDir)
380
- return undefined;
381
- const status = readStatus(asyncDir);
382
- if (!status || status.runId !== run.id || status.state !== "running")
383
- return undefined;
384
- if (index !== undefined && !status.indexedControl && (status.steps?.length ?? 0) > 1)
385
- return undefined;
386
- if (index !== undefined && status.steps?.[index]?.status !== "running")
387
- return { content: [{ type: "text", text: `No running nested child at index ${index}. No siblings were stopped.` }], isError: true, details: { mode: "management", results: [] } };
388
- try {
389
- writeAsyncInterruptRequest(asyncDir, run.id, index);
390
- return { content: [{ type: "text", text: `Interrupt requested for nested async run ${run.id}.` }], details: { mode: "management", results: [], managementControl: buildManagementControl({ state: "live", runId: run.id, intercomTarget: run.intercomTarget ?? run.leafIntercomTarget, canInterrupt: true }) } };
162
+ async function resolveContinuation(
163
+ // Resolution includes question/owned revival, whose durable updates belong to this session owner.
164
+ input, parentSessionFile) {
165
+ const requested = requestedOwnedId(input.params);
166
+ const questions = requested !== undefined
167
+ ? listSupervisorQuestions(input.ctx.sessionManager.getSessionId(), requested).filter((question) => question.state === "awaiting_input" || question.state === "answer_pending")
168
+ : [];
169
+ if (questions.length > 0) {
170
+ return { kind: "result", result: continueQuestionSession(input, questions) };
171
+ }
172
+ const owned = requested !== undefined ? resolveOwnedRun(input.deps.state, requested) : undefined;
173
+ if (owned) {
174
+ return { kind: "result", result: await resumeOwned(input, owned) };
391
175
  }
392
- catch (error) {
393
- const message = error instanceof Error ? error.message : String(error);
394
- return { content: [{ type: "text", text: `Failed to interrupt nested async run ${run.id}: ${message}` }], isError: true, details: { mode: "management", results: [] } };
176
+ const resolved = resolveRequestedRun(input.params, input.deps);
177
+ if (resolved?.kind !== "nested") {
178
+ return { kind: "target", target: resolveResumeTarget(input.params, input.deps.state) };
395
179
  }
396
- }
397
- export async function interruptNestedRun(target, index) {
398
- const run = target.match.run;
399
- if (run.state === "complete")
400
- return { content: [{ type: "text", text: `Nested run ${run.id} is already complete and cannot be interrupted.` }], isError: true, details: { mode: "management", results: [] } };
401
- if (run.state === "failed")
402
- return { content: [{ type: "text", text: `Nested run ${run.id} has failed and cannot be interrupted.` }], isError: true, details: { mode: "management", results: [] } };
403
- if (run.state === "paused")
404
- return { content: [{ type: "text", text: `Nested run ${run.id} is already paused.` }], isError: true, details: { mode: "management", results: [] } };
405
- if (index !== undefined && run.indexedControl !== true)
406
- return directNestedAsyncInterrupt(target, index) ?? {
407
- content: [{ type: "text", text: "This nested owner does not advertise selected-child stop. No stop was sent; inspect the child or explicitly stop the whole run." }], isError: true, details: { mode: "management", results: [] },
408
- };
409
- const result = await sendNestedControlRequest(target, "interrupt", undefined, index);
410
- if (result?.ok)
180
+ if (resolved.match.run.state === "running" || resolved.match.run.state === "queued") {
411
181
  return {
412
- content: [{ type: "text", text: result.message }],
413
- details: {
414
- mode: "management", results: [],
415
- managementControl: buildManagementControl({ state: "live", runId: run.id, intercomTarget: run.intercomTarget ?? run.leafIntercomTarget, canResume: true, canInterrupt: true }),
416
- },
182
+ kind: "result",
183
+ result: await resumeLiveNestedRun({
184
+ target: resolved,
185
+ message: normalizedFollowUp(input.params),
186
+ index: input.params.index,
187
+ acceptanceOverrideSupplied: input.params.acceptance !== undefined,
188
+ pi: input.deps.pi,
189
+ childSafe: nestedResolutionScopeForExecutor(input.deps) !== undefined,
190
+ }),
417
191
  };
418
- const direct = directNestedAsyncInterrupt(target, index);
419
- if (direct)
420
- return direct;
421
- if (result)
422
- return { content: [{ type: "text", text: result.message }], isError: true, details: { mode: "management", results: [] } };
423
- return { content: [{ type: "text", text: `Nested run ${run.id} owner is not reachable and no safe direct async interrupt fallback is available.` }], isError: true, details: { mode: "management", results: [] } };
424
- }
425
- const LIVE_ACCEPTANCE_OVERRIDE_NOTICE = "Acceptance override applies only to revive and was not applied to this live delivery.";
426
- export function liveLaunchOverrideNotice(params) {
427
- if (params.acceptance !== undefined)
428
- return LIVE_ACCEPTANCE_OVERRIDE_NOTICE;
429
- return [params.agent, params.model, params.cwd, params.output, params.outputMode, params.outputSchema, params.skill, params.maxOutput, params.control, params.artifacts, params.share].some((value) => value !== undefined)
430
- ? "Launch overrides change a newly started continuation, not this live child. No launch settings were changed."
431
- : undefined;
432
- }
433
- async function resumeLiveNestedRun(input) {
434
- const run = input.target.match.run;
435
- const result = await sendNestedControlRequest(input.target, "resume", input.message, input.index);
436
- if (result?.ok) {
437
- return { content: [{ type: "text", text: [result.message, input.acceptanceOverrideSupplied ? LIVE_ACCEPTANCE_OVERRIDE_NOTICE : undefined].filter(Boolean).join("\n") }], details: { mode: "management", results: [] } };
438
192
  }
439
- const asyncDir = input.index !== undefined ? resolveNestedAsyncDir(input.target.match.rootRunId, run) : undefined;
440
- const selected = asyncDir ? readStatus(asyncDir)?.steps?.[input.index] : undefined;
441
- const directTarget = input.index === undefined ? run.leafIntercomTarget ?? run.intercomTarget
442
- : selected?.status === "running" ? resolveSubagentIntercomTarget(run.id, selected.agent, input.index) : undefined;
443
- if (directTarget) {
444
- const delivered = await deliverSubagentIntercomMessageEvent(input.pi.events, directTarget, `Follow-up for nested run ${run.id}:\n\n${input.message}`, 500, { source: "nested-resume-fallback", runId: run.id, agent: run.agent, index: input.index ?? run.currentStep });
445
- if (delivered) {
446
- return { content: [{ type: "text", text: [`Delivered follow-up directly to live nested run ${run.id}.`, input.acceptanceOverrideSupplied ? LIVE_ACCEPTANCE_OVERRIDE_NOTICE : undefined].filter(Boolean).join("\n") }], details: { mode: "management", results: [] } };
447
- }
448
- }
449
- if (result)
450
- return { content: [{ type: "text", text: result.message }], isError: true, details: { mode: "management", results: [] } };
451
- return { content: [{ type: "text", text: `Nested run ${run.id} appears live but its owner route is not reachable. Wait for completion, then retry ${formatRunAction("resume", run.id, { message: "..." }, input.childSafe)}.` }], isError: true, details: { mode: "management", results: [] } };
452
- }
453
- function terminalNudgeResult(runId, deps) {
454
- const owned = resolveOwnedRun(deps.state, runId);
455
- if (owned) {
456
- const result = ownedRunStatusResult(owned, deps.state, undefined, { childSafe: Boolean(nestedResolutionScopeForExecutor(deps)) });
457
- const state = result.details.run.state;
458
- if (state === "live")
459
- return undefined;
460
- return { ...result, content: [{ type: "text", text: `Nudge not sent: ${state === "unknown" ? "completion is unconfirmed" : `run is already ${state}`}. No child was restarted.\n\n${result.content.map((part) => part.type === "text" ? part.text : "").join("\n")}` }] };
461
- }
462
- const remembered = deps.state.foregroundRuns?.get(runId);
463
- const status = remembered
464
- ? rememberedForegroundStatusResult(remembered, Boolean(nestedResolutionScopeForExecutor(deps)))
465
- : inspectSubagentStatus({ id: runId }, { state: deps.state, nested: nestedResolutionScopeForExecutor(deps) });
466
- const state = status.details.managementControl?.state;
467
- if (status.isError || !state || state === "live" || state === "unknown")
468
- return undefined;
469
193
  return {
470
- ...status,
471
- content: [{ type: "text", text: `Nudge not sent: run is already ${state}. No child was restarted.\n\n${status.content.filter((part) => part.type === "text").map((part) => part.text).join("\n")}` }],
194
+ kind: "target",
195
+ target: resolveNestedResumeTarget(resolved, trustedSessionRoots(input, parentSessionFile)),
472
196
  };
473
197
  }
474
- export async function nudgeSubagentRun(input) {
475
- const message = input.params.message?.trim() || "What are you blocked on? Reply with the smallest next step, or state the exact decision you need.";
476
- const requestedId = input.params.id ?? input.params.runId;
477
- let runId;
478
- let agent;
479
- let index;
480
- let target;
481
- let resolvedRunId;
482
- try {
483
- const owned = input.params.dir ? undefined : resolveOwnedRun(input.deps.state, requestedId ?? getAsyncInterruptTarget(input.deps.state, undefined)?.asyncId ?? "latest");
484
- if (owned) {
485
- resolvedRunId = owned.runId;
486
- const terminal = terminalNudgeResult(owned.runId, input.deps);
487
- if (terminal)
488
- return terminal;
489
- const view = ownedRunView(owned, input.deps.state);
490
- const children = view.children.filter((child) => child.state === "live" && (input.params.index === undefined || input.params.index === child.index));
491
- if (children.length !== 1)
492
- throw new Error(`Run '${owned.runId}' has ${children.length} matching live children. Provide index to choose one.`);
493
- const child = children[0];
494
- if (child.activity?.status === "pending")
495
- throw new Error(`Child ${child.index} is waiting to start in run ${owned.runId}. No message was sent and no continuation was started.`);
496
- runId = owned.runId;
497
- agent = child.agent;
498
- index = child.index;
499
- target = resolveSubagentIntercomTarget(runId, agent, index);
500
- }
501
- else {
502
- const resolved = requestedId ? resolveSubagentRunId(requestedId, { state: input.deps.state, nested: nestedResolutionScopeForExecutor(input.deps) }) : undefined;
503
- const remembered = !resolved && requestedId ? resolveRememberedForegroundRun(requestedId, input.deps.state) : undefined;
504
- resolvedRunId = resolved?.id ?? remembered?.runId;
505
- const terminal = resolvedRunId ? terminalNudgeResult(resolvedRunId, input.deps) : undefined;
506
- if (terminal)
507
- return terminal;
508
- if (resolved?.kind === "nested") {
509
- const run = resolved.match.run;
510
- const state = run.state === "running" || run.state === "queued" ? "live" : run.state === "complete" ? "completed" : run.state === "paused" || run.state === "blocked" || run.state === "failed" ? run.state : "unknown";
511
- const intercomTarget = run.intercomTarget ?? run.leafIntercomTarget;
512
- const childSafe = Boolean(nestedResolutionScopeForExecutor(input.deps));
513
- const valid = [formatRunAction("status", run.id, {}, childSafe)];
514
- if (state === "live" || run.sessionFile)
515
- valid.push(formatRunAction("resume", run.id, { message: "..." }, childSafe));
516
- if (state === "live")
517
- valid.push(formatRunAction("interrupt", run.id, {}, childSafe));
518
- return {
519
- content: [{ type: "text", text: `Nested run ${run.id} cannot be nudged. Valid actions: ${valid.join(" or ")}${intercomTarget ? `. Intercom target: ${intercomTarget}` : "."}` }],
520
- isError: true,
521
- details: { mode: "management", results: [], managementControl: buildManagementControl({ state, runId: run.id, intercomTarget, canNudge: false, canResume: state === "live" || Boolean(run.sessionFile), canInterrupt: state === "live", unavailableActions: { nudge: "Nested runs do not support nudge; use an advertised exact action or intercom target." } }) },
522
- };
198
+ function lookupFailure(
199
+ // Recovery may revive a saved question; the real dependency state remains owned, not frozen.
200
+ input, error) {
201
+ const message = errorMessage(error), requested = requestedOwnedId(input.params);
202
+ const recoverable = (error instanceof Error && error.message.startsWith("Async run not found.")) ||
203
+ message.includes("is detached for intercom coordination");
204
+ if (requested !== undefined && recoverable) {
205
+ try {
206
+ const questions = listSupervisorQuestions(input.ctx.sessionManager.getSessionId(), requested);
207
+ if (questions.length > 0) {
208
+ return continueQuestionSession(input, questions);
523
209
  }
524
- if (remembered)
525
- return rememberedForegroundStatusResult(remembered, Boolean(nestedResolutionScopeForExecutor(input.deps)));
526
- const asyncTarget = resolveAsyncResumeTarget({ id: input.params.id ?? (!requestedId ? getAsyncInterruptTarget(input.deps.state, undefined)?.asyncId : undefined), runId: input.params.runId, dir: input.params.dir, index: input.params.index });
527
- if (asyncTarget.kind !== "live") {
528
- return terminalNudgeResult(asyncTarget.runId, input.deps)
529
- ?? inspectSubagentStatus({ id: asyncTarget.runId }, { state: input.deps.state, nested: nestedResolutionScopeForExecutor(input.deps) });
530
- }
531
- runId = asyncTarget.runId;
532
- agent = asyncTarget.agent;
533
- index = asyncTarget.index;
534
- target = asyncTarget.intercomTarget;
210
+ }
211
+ catch (questionError) {
212
+ return failure(errorMessage(questionError));
535
213
  }
536
214
  }
537
- catch (error) {
538
- const terminal = resolvedRunId ? terminalNudgeResult(resolvedRunId, input.deps) : undefined;
539
- if (terminal)
540
- return terminal;
541
- const text = error instanceof Error ? error.message : String(error);
542
- return { content: [{ type: "text", text }], isError: true, details: { mode: "management", results: [] } };
215
+ return failure(message);
216
+ }
217
+ async function deliverLiveContinuation(input, target) {
218
+ const followUp = normalizedFollowUp(input.params);
219
+ const delivered = await deliverSubagentIntercomMessageEvent(input.deps.pi.events, target.intercomTarget, `Follow-up for async run ${target.runId} (${target.agent}):\n\n${followUp}`, 500, { source: "async-resume", runId: target.runId, agent: target.agent, index: target.index });
220
+ if (!delivered) {
221
+ return failure([
222
+ "Async child appears live but its intercom target is not registered.",
223
+ `Run: ${target.runId}`,
224
+ `Intercom target: ${target.intercomTarget}`,
225
+ `Wait for completion, then retry ${formatRunAction("resume", target.runId, { message: "..." }, nestedResolutionScopeForExecutor(input.deps) !== undefined)}.`,
226
+ ].join("\n"));
543
227
  }
544
- const result = await sendLiveSubagentMessage(input.deps.pi.events, {
545
- to: target,
546
- message: `Nudge for subagent run ${runId} (${agent}${index !== undefined ? ` step ${index + 1}` : ""}):\n\n${message}`,
547
- delivery: "steer",
548
- extra: { source: "subagent-nudge", runId, agent, index },
549
- });
550
- if (!result.delivered) {
551
- const terminal = terminalNudgeResult(runId, input.deps);
552
- if (terminal)
553
- return terminal;
554
- return { content: [{ type: "text", text: [`Nudge was not delivered.`, `Run: ${runId}`, `Intercom target: ${target}`, result.reason ? `Reason: ${result.reason}` : undefined].filter((line) => Boolean(line)).join("\n") }], isError: true, details: { mode: "management", results: [] } };
228
+ const lines = [
229
+ "Delivered follow-up to live async child.",
230
+ `Run: ${target.runId}`,
231
+ `Intercom target: ${target.intercomTarget}`,
232
+ ];
233
+ if (input.params.acceptance !== undefined) {
234
+ lines.push(LIVE_ACCEPTANCE_OVERRIDE_NOTICE);
555
235
  }
556
236
  return {
557
- content: [{ type: "text", text: [`Nudge delivered to live subagent.`, `Run: ${runId}`, `Agent: ${agent}`, `Intercom target: ${target}`].join("\n") }],
558
- details: { mode: "management", results: [], managementControl: buildManagementControl({ state: "live", runId, index, intercomTarget: target, canNudge: true, canResume: true, canInterrupt: true }) },
237
+ content: [{ type: "text", text: lines.join("\n") }],
238
+ details: {
239
+ mode: "management",
240
+ results: [],
241
+ managementControl: buildManagementControl({
242
+ state: "live",
243
+ runId: target.runId,
244
+ index: target.index,
245
+ intercomTarget: target.intercomTarget,
246
+ canNudge: true,
247
+ canResume: true,
248
+ canInterrupt: true,
249
+ }),
250
+ },
559
251
  };
560
252
  }
561
- export async function resumeAsyncRun(input) {
562
- const followUp = (input.params.message ?? input.params.task ?? "").trim();
563
- if (!followUp) {
564
- return {
565
- content: [{ type: "text", text: "action='resume' requires message." }],
566
- isError: true,
567
- details: { mode: "management", results: [] },
568
- };
253
+ /** Pending question, owned/live continuation, then saved session revival—in that order. */
254
+ export async function resumeAsyncRun(
255
+ // Resume owns durable question delivery and newly launched continuation state through its helpers.
256
+ input) {
257
+ if (normalizedFollowUp(input.params).length === 0) {
258
+ return failure("action='resume' requires message.");
569
259
  }
570
- let target;
571
260
  const parentSessionFile = input.ctx.sessionManager.getSessionFile() ?? null;
572
- const nudgeContinuation = (runId, sessionFile) => {
573
- if (!sessionFile)
574
- return;
575
- for (const candidate of input.deps.state.ownedRuns?.values() ?? []) {
576
- if (candidate.runId === runId)
577
- continue;
578
- if (!candidate.children.some((child) => child.sessionFile === sessionFile)
579
- && input.deps.state.asyncJobs.get(candidate.runId)?.sessionFile !== sessionFile)
580
- continue;
581
- const active = ownedRunView(candidate, input.deps.state, { readConfiguration: false }).children.find((entry) => entry.sessionFile === sessionFile && entry.state === "live");
582
- if (!active)
583
- continue;
584
- return nudgeSubagentRun({ params: { ...input.params, dir: undefined, id: candidate.runId, index: active.index, message: followUp }, deps: input.deps, ctx: input.ctx }).then((result) => {
585
- const notice = liveLaunchOverrideNotice(input.params);
586
- if (notice)
587
- result.content.push({ type: "text", text: notice });
588
- return result;
589
- });
590
- }
591
- };
261
+ let resolution;
592
262
  try {
593
- const requestedId = input.params.id ?? input.params.runId;
594
- const pendingQuestions = requestedId && !input.params.dir
595
- ? listSupervisorQuestions(input.ctx.sessionManager.getSessionId(), requestedId).filter((question) => question.state === "awaiting_input" || question.state === "answer_pending")
596
- : [];
597
- if (pendingQuestions.length)
598
- return continueQuestionSession(input, pendingQuestions);
599
- const owned = requestedId && !input.params.dir ? resolveOwnedRun(input.deps.state, requestedId) : undefined;
600
- if (owned) {
601
- const view = ownedRunView(owned, input.deps.state);
602
- if (view.children.length > 1 && input.params.index === undefined)
603
- throw new Error(`Run '${owned.runId}' has ${view.children.length} children. Provide index to choose one.`);
604
- const child = view.children.find((entry) => entry.index === (input.params.index ?? 0));
605
- if (!child)
606
- throw new Error(`Run '${owned.runId}' has no child at index ${input.params.index ?? 0}.`);
607
- if (child.state === "live") {
608
- const result = await nudgeSubagentRun({ params: { ...input.params, id: owned.runId, message: followUp }, deps: input.deps, ctx: input.ctx });
609
- const notice = liveLaunchOverrideNotice(input.params);
610
- if (notice)
611
- result.content.push({ type: "text", text: notice });
612
- return result;
613
- }
614
- const continuation = nudgeContinuation(owned.runId, child.sessionFile);
615
- if (continuation)
616
- return await continuation;
617
- const contract = readQuestionContract(owned.runId, child.index);
618
- return reviveSavedSubagent(input, {
619
- ...contract, runId: owned.runId, agent: child.agent, index: child.index, source: owned.source,
620
- cwd: child.launch?.cwd ?? owned.cwd, sessionFile: child.sessionFile,
621
- effectiveAcceptance: contract?.effectiveAcceptance ?? child.result?.acceptance?.effectiveAcceptance,
622
- model: child.result?.model,
623
- });
624
- }
625
- const resolved = requestedId ? resolveSubagentRunId(requestedId, { state: input.deps.state, nested: nestedResolutionScopeForExecutor(input.deps) }) : undefined;
626
- if (resolved?.kind === "nested") {
627
- if (resolved.match.run.state === "running" || resolved.match.run.state === "queued") {
628
- return resumeLiveNestedRun({ target: resolved, message: followUp, index: input.params.index, acceptanceOverrideSupplied: input.params.acceptance !== undefined, pi: input.deps.pi, childSafe: Boolean(nestedResolutionScopeForExecutor(input.deps)) });
629
- }
630
- const trustedSessionRoots = [
631
- ...(input.deps.config.defaultSessionDir ? [path.resolve(input.deps.expandTilde(input.deps.config.defaultSessionDir))] : []),
632
- ...(parentSessionFile ? [input.deps.getSubagentSessionRoot(parentSessionFile)] : []),
633
- ];
634
- target = resolveNestedResumeTarget(resolved, trustedSessionRoots);
635
- }
636
- else {
637
- target = resolveResumeTarget(input.params, input.deps.state);
638
- }
263
+ resolution = await resolveContinuation(input, parentSessionFile);
639
264
  }
640
265
  catch (error) {
641
- const message = error instanceof Error ? error.message : String(error);
642
- const requestedId = input.params.id ?? input.params.runId;
643
- if (requestedId && !input.params.dir && (isAsyncRunNotFound(error) || message.includes("is detached for intercom coordination"))) {
644
- try {
645
- const questions = listSupervisorQuestions(input.ctx.sessionManager.getSessionId(), requestedId);
646
- if (questions.length)
647
- return continueQuestionSession(input, questions);
648
- }
649
- catch (questionError) {
650
- return { content: [{ type: "text", text: questionError instanceof Error ? questionError.message : String(questionError) }], isError: true, details: { mode: "management", results: [] } };
651
- }
652
- }
653
- return { content: [{ type: "text", text: message }], isError: true, details: { mode: "management", results: [] } };
654
- }
655
- if (target.kind === "live") {
656
- const delivered = await deliverSubagentIntercomMessageEvent(input.deps.pi.events, target.intercomTarget, `Follow-up for async run ${target.runId} (${target.agent}):\n\n${followUp}`, 500, { source: "async-resume", runId: target.runId, agent: target.agent, index: target.index });
657
- if (delivered) {
658
- return {
659
- content: [{ type: "text", text: [`Delivered follow-up to live async child.`, `Run: ${target.runId}`, `Intercom target: ${target.intercomTarget}`, input.params.acceptance !== undefined ? LIVE_ACCEPTANCE_OVERRIDE_NOTICE : undefined].filter(Boolean).join("\n") }],
660
- details: { mode: "management", results: [], managementControl: buildManagementControl({ state: "live", runId: target.runId, index: target.index, intercomTarget: target.intercomTarget, canNudge: true, canResume: true, canInterrupt: true }) },
661
- };
662
- }
663
- return {
664
- content: [{ type: "text", text: [`Async child appears live but its intercom target is not registered.`, `Run: ${target.runId}`, `Intercom target: ${target.intercomTarget}`, `Wait for completion, then retry ${formatRunAction("resume", target.runId, { message: "..." }, Boolean(nestedResolutionScopeForExecutor(input.deps)))}.`].join("\n") }],
665
- isError: true,
666
- details: { mode: "management", results: [] },
667
- };
668
- }
669
- return nudgeContinuation(target.runId, target.sessionFile) ?? reviveSavedSubagent(input, target);
670
- }
671
- function continueQuestionSession(input, questions) {
672
- if (input.params.index === undefined && new Set(questions.map((question) => question.index)).size > 1)
673
- throw new Error("Provide index to choose which child question to continue.");
674
- const question = questions.findLast((entry) => input.params.index === undefined || entry.index === input.params.index);
675
- if (!question)
676
- throw new Error("No saved question for that child index.");
677
- if (questionProcessAlive(question))
678
- throw new Error("The question's child is still alive. Answer the question or stop it before continuing.");
679
- if (question.delivery?.kind === "revive")
680
- throw new Error(`Use continue with the answer's continuation run ${question.delivery.runId}.`);
681
- const revival = question.revival;
682
- const prior = revival ? resolveSubagentRunId(revival.runId, { state: input.deps.state, nested: nestedResolutionScopeForExecutor(input.deps) }) : undefined;
683
- const priorExists = prior?.kind === "async"
684
- ? prior.location.resultPath || (prior.location.asyncDir && fs.existsSync(path.join(prior.location.asyncDir, "status.json")))
685
- : Boolean(prior);
686
- if (revival && (questionProcessAlive(revival) || priorExists || fs.existsSync(getAsyncConfigPath(revival.runId)) || fs.existsSync(path.join(getRunMetadataDir(revival.runId), "launch.json")) || fs.existsSync(path.join(ASYNC_DIR, revival.runId, RUNNER_ERROR_LOG_FILE)))) {
687
- throw new Error(`Continuation ${revival.runId} may already have launched. Inspect or continue that run; the original question was not restarted.`);
688
- }
689
- const message = [input.params.message ?? input.params.task, question.answer ? `Saved supervisor answer:\n${question.answer.message}\n\nOriginal question:\n${question.message}` : undefined].filter(Boolean).join("\n\n");
690
- const result = reviveSavedSubagent({ ...input, params: { ...input.params, message } }, { ...question, source: "question" });
691
- if (!result.isError && question.answer && !question.delivery)
692
- recordQuestionDelivery(question, { kind: "revive", runId: result.details.asyncId, deliveredAt: Date.now() });
693
- return result;
694
- }
695
- export function reviveSavedSubagent(input, target, runId = randomUUID()) {
696
- const followUp = (input.params.message ?? input.params.task ?? "").trim();
697
- const parentSessionFile = input.ctx.sessionManager.getSessionFile() ?? null;
698
- if (!target.sessionFile || path.extname(target.sessionFile) !== ".jsonl" || !fs.existsSync(target.sessionFile)) {
699
- return { content: [{ type: "text", text: `Saved child session file is unavailable: ${target.sessionFile ?? "none"}. No child was started; any saved answer remains pending.` }], isError: true, details: { mode: "management", results: [] } };
700
- }
701
- const { blocked, depth, maxDepth } = checkSubagentDepth(input.deps.config.maxSubagentDepth);
702
- if (blocked) {
703
- return {
704
- content: [{ type: "text", text: `Nested subagent resume blocked (depth=${depth}, max=${maxDepth}). Complete the follow-up directly instead.` }],
705
- isError: true,
706
- details: { mode: "management", results: [] },
707
- };
708
- }
709
- input.deps.state.currentSessionId = resolveCurrentSessionId(input.ctx.sessionManager);
710
- const contract = readQuestionContract(target.runId, target.index) ?? target;
711
- const savedLaunch = input.params.agent === undefined && contract.launch ? { ...contract.launch, ...contract.effectiveConfiguration } : undefined;
712
- const generatedOutputFilename = input.params.output === undefined ? contract.launch?.generatedOutputFilename : undefined;
713
- const effectiveCwd = input.params.cwd ?? savedLaunch?.cwd ?? target.cwd ?? input.requestCwd;
714
- const scope = resolveExecutionAgentScope(input.params.agentScope);
715
- if (!savedLaunch && !input.params.agent) {
716
- return { content: [{ type: "text", text: `Run '${target.runId}' predates saved launch configuration. Its session and known result remain available, but the original profile cannot be reconstructed safely. Continue with agent: '${target.agent}' to explicitly use that profile's current configuration, including model and thinking; known output and acceptance are retained unless overridden.` }], isError: true, details: { mode: "management", results: [] } };
266
+ return lookupFailure(input, error);
717
267
  }
718
- const discoveredAgents = savedLaunch ? [savedLaunch.agent] : input.deps.discoverAgents(effectiveCwd, scope, { projectTrusted: input.ctx.isProjectTrusted() }).agents;
719
- const fallbackTarget = resolveIntercomSessionTarget(input.deps.pi.getSessionName(), input.ctx.sessionManager.getSessionId());
720
- const orchestratorTarget = resolveOrchestratorIntercomTarget(input.deps.pi.events, fallbackTarget);
721
- const intercomBridge = resolveIntercomBridge(orchestratorTarget);
722
- const inheritedModel = providerQualifiedModelId(input.ctx.model?.provider, input.ctx.model?.id);
723
- const agents = savedLaunch ? discoveredAgents : discoveredAgents.map((agent) => agent.model || !inheritedModel ? agent : { ...agent, model: inheritedModel });
724
- const selectedAgent = input.params.agent ?? target.agent;
725
- const profile = agents.find((agent) => agent.name === selectedAgent);
726
- const agentConfig = profile && savedLaunch ? { ...profile, thinking: savedLaunch.thinking ?? profile.thinking, maxExecutionTimeMs: savedLaunch.maxExecutionTimeMs, maxTokens: savedLaunch.maxTokens } : profile;
727
- if (!agentConfig) {
728
- return {
729
- content: [{ type: "text", text: `Unknown agent for resume: ${selectedAgent}` }],
730
- isError: true,
731
- details: { mode: "management", results: [] },
732
- };
268
+ if (resolution.kind === "result") {
269
+ return resolution.result;
733
270
  }
734
- saveQuestionOwner(runId, input.ctx.sessionManager.getSessionId());
735
- const prior = input.deps.state.ownedRuns?.get(target.runId);
736
- rememberOwnedRun(input.deps.state, {
737
- runId, ownerSessionId: input.ctx.sessionManager.getSessionId(), rootRunId: prior?.rootRunId ?? target.runId,
738
- predecessorRunId: target.runId, predecessorIndex: target.index,
739
- source: "async", mode: "single", cwd: effectiveCwd, task: followUp, startedAt: Date.now(),
740
- children: [{ agent: selectedAgent, index: 0, task: followUp, label: prior?.children.find((child) => child.index === target.index)?.label, sessionFile: target.sessionFile }],
741
- });
742
- const modelOverride = input.params.model;
743
- const skill = normalizeSkillInput(input.params.skill);
744
- const availableModels = input.ctx.modelRegistry.getAvailable().map(toModelInfo);
745
- const launchInput = {
746
- agent: selectedAgent,
747
- task: buildRevivedAsyncTask(target, followUp, input.params.messageOrigin),
748
- agentConfig,
749
- ctx: {
750
- pi: input.deps.pi,
751
- cwd: input.requestCwd,
752
- currentSessionId: input.deps.state.currentSessionId,
753
- rootSessionId: resolveRootSessionId(input.ctx.sessionManager),
754
- currentModelProvider: input.ctx.model?.provider,
755
- projectTrusted: input.ctx.isProjectTrusted(),
756
- },
757
- cwd: effectiveCwd,
758
- maxOutput: input.params.maxOutput ?? savedLaunch?.maxOutput,
759
- artifactsDir: input.params.artifacts === false || (input.params.artifacts === undefined && savedLaunch?.artifacts === false) ? undefined : savedLaunch?.artifactsDir ?? input.deps.tempArtifactsDir,
760
- shareEnabled: input.params.share ?? savedLaunch?.share ?? false,
761
- sessionRoot: input.deps.getSubagentSessionRoot(parentSessionFile),
762
- sessionFile: target.sessionFile,
763
- maxSubagentDepth: savedLaunch?.maxSubagentDepth ?? resolveCurrentMaxSubagentDepth(input.deps.config.maxSubagentDepth),
764
- worktreeSetupHook: input.deps.config.worktreeSetupHook,
765
- worktreeSetupHookTimeoutMs: input.deps.config.worktreeSetupHookTimeoutMs,
766
- controlConfig: resolveControlConfig(savedLaunch?.controlConfig ?? input.deps.config.control, input.params.control),
767
- controlIntercomTarget: intercomBridge.orchestratorTarget,
768
- childIntercomTarget: (agent, index) => resolveSubagentIntercomTarget(runId, agent, index),
769
- availableModels, savedLaunch, modelOverride,
770
- skills: skill,
771
- acceptance: input.params.acceptance ?? acceptanceInputFromResolved(contract.effectiveAcceptance ?? savedLaunch?.effectiveAcceptance),
772
- output: input.params.output ?? (generatedOutputFilename ? true : savedLaunch?.output ?? contract.output),
773
- generatedOutputFilename,
774
- outputMode: input.params.outputMode ?? savedLaunch?.outputMode ?? contract.outputMode,
775
- outputSchema: input.params.outputSchema ?? savedLaunch?.outputSchema ?? contract.outputSchema,
776
- projectTrust: savedLaunch?.projectTrust ?? resolveConfiguredChildProjectTrustPolicy(input.deps.config.projectTrust),
777
- };
778
- const undoCwdRequest = input.params.cwd !== undefined ? requestChildExecutionCwd(target.sessionFile, effectiveCwd) : undefined;
779
- let result;
780
- try {
781
- result = executeAsyncSingle(runId, launchInput);
782
- }
783
- catch (error) {
784
- undoCwdRequest?.();
785
- throw error;
271
+ const { target } = resolution;
272
+ if (target.kind === "live") {
273
+ return deliverLiveContinuation(input, target);
786
274
  }
787
- if (result.isError)
788
- undoCwdRequest?.();
789
- const owned = input.deps.state.ownedRuns?.get(runId);
790
- if (owned)
791
- rememberOwnedRun(input.deps.state, { ...owned, asyncDir: result.details.asyncDir, pid: result.details.asyncPid ?? input.deps.state.asyncJobs.get(runId)?.pid, ...(result.isError ? { error: result.content.map((part) => part.text).join("\n") } : {}) });
792
- if (result.isError)
793
- return result;
794
- const revivedId = result.details.asyncId ?? runId;
795
- const revivedTarget = resolveSubagentIntercomTarget(revivedId, selectedAgent, 0);
796
- const sourceLabel = target.source;
797
- const lines = [
798
- `Revived ${sourceLabel} subagent from ${target.runId}.`,
799
- `Run mapping: ${target.runId} -> ${revivedId}`,
800
- `Revived run: ${revivedId}`,
801
- `Agent: ${selectedAgent}`,
802
- `Configuration: ${savedLaunch ? "saved effective launch" : "explicitly selected current profile"}${modelOverride ? `; model ${modelOverride}` : ""}`,
803
- `Root: ${prior?.rootRunId ?? target.runId}`,
804
- `Session: ${target.sessionFile}`,
805
- result.details.asyncDir ? `Async dir: ${result.details.asyncDir}` : undefined,
806
- revivedTarget ? `Intercom target: ${revivedTarget} (if registered)` : undefined,
807
- `Prior pending-reply context for ${target.runId} is invalid; use the revived run and target only.`,
808
- `Status if needed: ${formatRunAction("status", revivedId, {}, Boolean(nestedResolutionScopeForExecutor(input.deps)))}`,
809
- ].filter((line) => Boolean(line));
810
- return {
811
- content: [{ type: "text", text: formatAsyncStartedMessage(lines.join("\n"), Boolean(nestedResolutionScopeForExecutor(input.deps))) }],
812
- details: {
813
- ...result.details,
814
- managementControl: buildManagementControl({ state: "live", runId: revivedId, index: 0, intercomTarget: revivedTarget, canInterrupt: true, revivedFromRunId: target.runId }),
815
- },
816
- };
275
+ return (nudgeContinuation(input, target.runId, target.sessionFile) ?? reviveSavedSubagent(input, target));
817
276
  }