@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
@@ -0,0 +1,241 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { isRecord, type UnknownRecord } from "../../shared/unknown.ts";
3
+ import {
4
+ isTopicUpdate,
5
+ isTopicSubscription,
6
+ type SessionInfo,
7
+ type TopicUpdate,
8
+ type Message,
9
+ type BrokerMessage,
10
+ type TopicSubscription,
11
+ type SendResult,
12
+ } from "../types.ts";
13
+ import { validateIntercomMessageSize } from "./framing.ts";
14
+
15
+ /** Direct messages and old clients receive identity, not potentially large topic state. */
16
+ export function messageSender(info: SessionInfo): SessionInfo {
17
+ const { topics: _topics, subscriptions: _subscriptions, ...identity } = info;
18
+ return identity;
19
+ }
20
+
21
+ function topicFrames(requestId: string, info: SessionInfo): BrokerMessage[] {
22
+ const frames: BrokerMessage[] = [
23
+ {
24
+ type: "sessions",
25
+ requestId,
26
+ sessions: [
27
+ {
28
+ ...messageSender(info),
29
+ ...(info.topics ? { topics: [] } : {}),
30
+ ...(info.subscriptions ? { subscriptions: [] } : {}),
31
+ },
32
+ ],
33
+ more: true,
34
+ },
35
+ ];
36
+ for (const topic of info.topics ?? []) {
37
+ frames.push({
38
+ type: "sessions",
39
+ requestId,
40
+ sessions: [{ id: info.id, topics: [topic] }],
41
+ more: true,
42
+ });
43
+ }
44
+ for (const subscription of info.subscriptions ?? []) {
45
+ frames.push({
46
+ type: "sessions",
47
+ requestId,
48
+ sessions: [{ id: info.id, subscriptions: [subscription] }],
49
+ more: true,
50
+ });
51
+ }
52
+ return frames;
53
+ }
54
+
55
+ export function snapshotFrames(
56
+ requestId: string,
57
+ infos: readonly SessionInfo[],
58
+ stream: boolean,
59
+ ): BrokerMessage[] {
60
+ // ponytail: one record per frame; pack records only if measured socket overhead warrants it.
61
+ const frames: BrokerMessage[] = stream
62
+ ? [
63
+ ...infos.flatMap((info) => topicFrames(requestId, info)),
64
+ { type: "sessions", requestId, sessions: [], more: false },
65
+ ]
66
+ : [{ type: "sessions", requestId, sessions: infos.map(messageSender) }];
67
+ for (const frame of frames) {
68
+ const error = validateIntercomMessageSize(frame);
69
+ if (error) {
70
+ throw error;
71
+ }
72
+ }
73
+ return frames;
74
+ }
75
+
76
+ type TopicMutation =
77
+ | { readonly kind: "publication"; readonly topic: TopicUpdate; readonly publish: boolean }
78
+ | { readonly kind: "subscription"; readonly subscription: TopicSubscription }
79
+ | { readonly kind: "unsubscribe"; readonly topic: string };
80
+
81
+ function validPublication(topic: unknown): TopicUpdate {
82
+ if (!isTopicUpdate(topic) || topic.text.trim().length === 0) {
83
+ throw new Error("Invalid topic publication");
84
+ }
85
+ if (
86
+ topic.event === "release" &&
87
+ ((topic.resource ?? "").length === 0 || topic.ownership !== "released")
88
+ ) {
89
+ throw new Error("Invalid topic publication");
90
+ }
91
+ return topic;
92
+ }
93
+
94
+ function topicMutation(change: UnknownRecord): TopicMutation {
95
+ if (change.action === "publish") {
96
+ return { kind: "publication", topic: validPublication(change.topic), publish: true };
97
+ }
98
+ if (change.action === "restore" && isTopicUpdate(change.topic)) {
99
+ return { kind: "publication", topic: validPublication(change.topic), publish: false };
100
+ }
101
+ if (
102
+ (change.action === "subscribe" || change.action === "restore") &&
103
+ isTopicSubscription(change.subscription)
104
+ ) {
105
+ return { kind: "subscription", subscription: change.subscription };
106
+ }
107
+ if (change.action === "unsubscribe" && typeof change.topic === "string") {
108
+ return { kind: "unsubscribe", topic: change.topic };
109
+ }
110
+ throw new Error("Invalid topic change");
111
+ }
112
+
113
+ function publicationUpdate(
114
+ topic: TopicUpdate,
115
+ previous: TopicUpdate | undefined,
116
+ publish: boolean,
117
+ ): TopicUpdate {
118
+ const revision = publish
119
+ ? Math.max(previous?.revision ?? 0, topic.revision - 1) + 1
120
+ : topic.revision;
121
+ if (!Number.isSafeInteger(revision) || revision <= 0) {
122
+ throw new Error("Invalid topic revision");
123
+ }
124
+ return { ...topic, revision };
125
+ }
126
+
127
+ class TopicSnapshot {
128
+ private readonly info: SessionInfo;
129
+ private readonly topics: Map<string, TopicUpdate>;
130
+ private readonly subscriptions: Map<string, TopicSubscription>;
131
+
132
+ constructor(info: SessionInfo) {
133
+ this.info = info;
134
+ this.topics = new Map((info.topics ?? []).map((topic) => [topic.topic, topic]));
135
+ this.subscriptions = new Map((info.subscriptions ?? []).map((entry) => [entry.topic, entry]));
136
+ }
137
+
138
+ apply(mutation: TopicMutation): TopicUpdate | undefined {
139
+ switch (mutation.kind) {
140
+ case "publication": {
141
+ const previous = this.topics.get(mutation.topic.topic);
142
+ const update = publicationUpdate(mutation.topic, previous, mutation.publish);
143
+ if (mutation.publish || (previous?.revision ?? 0) < update.revision) {
144
+ this.topics.set(update.topic, update);
145
+ }
146
+ if (mutation.publish) {
147
+ return update;
148
+ }
149
+ return;
150
+ }
151
+ case "subscription":
152
+ this.subscriptions.set(mutation.subscription.topic, mutation.subscription);
153
+ return;
154
+ case "unsubscribe":
155
+ this.subscriptions.delete(mutation.topic);
156
+ return;
157
+ }
158
+ }
159
+
160
+ snapshot(publication?: TopicUpdate): SessionInfo {
161
+ return {
162
+ ...this.info,
163
+ topics: [...this.topics.values()],
164
+ subscriptions: [...this.subscriptions.values()],
165
+ ...(publication ? { lastIntercomActivity: Date.now() } : {}),
166
+ };
167
+ }
168
+ }
169
+
170
+ /** Prepare a change without mutating the usable broker snapshot before frame validation. */
171
+ export function prepareTopicChange(
172
+ info: SessionInfo,
173
+ change: unknown,
174
+ supported: boolean,
175
+ ): {
176
+ readonly info: SessionInfo;
177
+ readonly publication?: TopicUpdate;
178
+ readonly restore: boolean;
179
+ } {
180
+ if (change === undefined) {
181
+ return { info, restore: false };
182
+ }
183
+ if (!supported || !isRecord(change)) {
184
+ throw new Error("Topic snapshots unavailable for this client");
185
+ }
186
+ const pending = new TopicSnapshot(info);
187
+ const publication = pending.apply(topicMutation(change));
188
+ return {
189
+ info: pending.snapshot(publication),
190
+ restore: change.action === "restore",
191
+ ...(publication ? { publication } : {}),
192
+ };
193
+ }
194
+
195
+ export function deliveryAcknowledgement(receipt: SendResult): BrokerMessage {
196
+ if (!receipt.accepted) {
197
+ return {
198
+ type: "delivery_failed",
199
+ messageId: receipt.id,
200
+ reason: receipt.reason ?? "Delivery failed",
201
+ };
202
+ }
203
+ if (receipt.queued === true) {
204
+ return {
205
+ type: "delivery_queued",
206
+ messageId: receipt.id,
207
+ reason: receipt.reason ?? "Queued for replace-mode delivery",
208
+ };
209
+ }
210
+ return { type: "delivered", messageId: receipt.id };
211
+ }
212
+
213
+ export function shouldReplaceDelivery(message: Message, info: SessionInfo): boolean {
214
+ if (
215
+ message.delivery !== "queue" ||
216
+ message.queueMode !== "replace" ||
217
+ (message.threadId ?? "").length === 0
218
+ ) {
219
+ return false;
220
+ }
221
+ const status = info.status ?? "";
222
+ return (
223
+ message.expectsReply === true ||
224
+ ((status === "idle" || status.startsWith("idle ")) && info.acceptsAsks !== false)
225
+ );
226
+ }
227
+
228
+ export function publicationMessage(publication: TopicUpdate, awaitRelease: boolean): Message {
229
+ const urgent =
230
+ publication.event === "blocker" ||
231
+ publication.event === "decision" ||
232
+ (publication.event === "release" && awaitRelease);
233
+ return {
234
+ id: randomUUID(),
235
+ timestamp: Date.now(),
236
+ topic: publication,
237
+ content: { text: publication.text },
238
+ delivery: urgent ? "steer" : "queue",
239
+ ...(urgent ? {} : { queueMode: "replace", threadId: `topic:${publication.topic}` }),
240
+ };
241
+ }
@@ -7,6 +7,7 @@ import net from "net";
7
7
  import { getPiAgentDir } from "../agent-dir.ts";
8
8
  import { getBrokerSocketPath, getLegacyBrokerSocketPath, isOwnedBrokerSocket } from "./paths.ts";
9
9
  import { isBrokerPidReused } from "./pid.ts";
10
+ import { errorMessage, hasErrorCode } from "../../shared/unknown.ts";
10
11
 
11
12
  const INTERCOM_DIR = join(getPiAgentDir(), "intercom");
12
13
  const EXTENSION_DIR = join(dirname(fileURLToPath(import.meta.url)), "..", "..", "..");
@@ -14,20 +15,24 @@ const BROKER_PID = join(INTERCOM_DIR, "broker.pid");
14
15
  const BROKER_SPAWN_LOCK = join(INTERCOM_DIR, "broker.spawn.lock");
15
16
 
16
17
  function sleep(ms: number): Promise<void> {
17
- return new Promise(resolve => setTimeout(resolve, ms));
18
+ return new Promise((resolve) => {
19
+ setTimeout(resolve, ms);
20
+ });
18
21
  }
19
22
 
20
- function usesLegacyTsxDefault(brokerCommand: string, brokerArgs: string[]): boolean {
21
- return brokerCommand === "npx"
22
- && brokerArgs.length === 2
23
- && brokerArgs[0] === "--no-install"
24
- && brokerArgs[1] === "tsx";
23
+ function usesLegacyTsxDefault(brokerCommand: string, brokerArgs: readonly string[]): boolean {
24
+ return (
25
+ brokerCommand === "npx" &&
26
+ brokerArgs.length === 2 &&
27
+ brokerArgs[0] === "--no-install" &&
28
+ brokerArgs[1] === "tsx"
29
+ );
25
30
  }
26
31
 
27
32
  export function getBrokerLaunchSpec(
28
33
  brokerPath: string,
29
34
  brokerCommand: string,
30
- brokerArgs: string[],
35
+ brokerArgs: readonly string[],
31
36
  ): { command: string; args: string[] } {
32
37
  if (usesLegacyTsxDefault(brokerCommand, brokerArgs)) {
33
38
  return {
@@ -57,10 +62,13 @@ export function getBrokerSpawnOptions(): {
57
62
  }
58
63
 
59
64
  function toError(error: unknown): Error {
60
- return error instanceof Error ? error : new Error(String(error));
65
+ return error instanceof Error ? error : new Error(errorMessage(error));
61
66
  }
62
67
 
63
- export async function spawnBrokerIfNeeded(brokerCommand: string, brokerArgs: string[]): Promise<void> {
68
+ export async function spawnBrokerIfNeeded(
69
+ brokerCommand: string,
70
+ brokerArgs: readonly string[],
71
+ ): Promise<void> {
64
72
  await mkdir(INTERCOM_DIR, { recursive: true });
65
73
 
66
74
  if (await isBrokerRunning()) {
@@ -93,14 +101,14 @@ export async function spawnBrokerIfNeeded(brokerCommand: string, brokerArgs: str
93
101
  child.off("exit", onExit);
94
102
  };
95
103
 
96
- const onError = (error: Error) => {
104
+ const onError = (error: Readonly<Error>) => {
97
105
  cleanup();
98
106
  reject(new Error(`Failed to spawn intercom broker: ${error.message}`, { cause: error }));
99
107
  };
100
108
 
101
109
  const onExit = (code: number | null, signal: NodeJS.Signals | null) => {
102
110
  cleanup();
103
- if (signal) {
111
+ if (signal !== null) {
104
112
  reject(new Error(`Intercom broker exited before startup with signal ${signal}`));
105
113
  return;
106
114
  }
@@ -109,13 +117,15 @@ export async function spawnBrokerIfNeeded(brokerCommand: string, brokerArgs: str
109
117
 
110
118
  child.once("error", onError);
111
119
  child.once("exit", onExit);
112
- waitForBroker().then(() => {
113
- cleanup();
114
- resolve();
115
- }, (error) => {
116
- cleanup();
117
- reject(toError(error));
118
- });
120
+ waitForBroker()
121
+ .then(() => {
122
+ cleanup();
123
+ resolve();
124
+ })
125
+ .catch((error: unknown) => {
126
+ cleanup();
127
+ reject(toError(error));
128
+ });
119
129
  });
120
130
  } finally {
121
131
  releaseSpawnLock();
@@ -127,7 +137,9 @@ export async function isBrokerRunning(): Promise<boolean> {
127
137
  }
128
138
 
129
139
  function readLivePid(): number | null {
130
- if (!existsSync(BROKER_PID)) return null;
140
+ if (!existsSync(BROKER_PID)) {
141
+ return null;
142
+ }
131
143
  let raw: string;
132
144
  try {
133
145
  raw = readFileSync(BROKER_PID, "utf-8");
@@ -135,27 +147,37 @@ function readLivePid(): number | null {
135
147
  return null;
136
148
  }
137
149
  const pid = parseInt(raw.trim(), 10);
138
- if (!Number.isFinite(pid) || pid <= 0) return null;
150
+ if (!Number.isFinite(pid) || pid <= 0) {
151
+ return null;
152
+ }
139
153
  try {
140
154
  process.kill(pid, 0);
141
155
  } catch (error) {
142
- return (error as NodeJS.ErrnoException).code === "EPERM" ? pid : null;
156
+ return hasErrorCode(error, "EPERM") ? pid : null;
143
157
  }
144
158
  return isBrokerPidReused(pid, raw) ? null : pid;
145
159
  }
146
160
 
147
161
  export async function stopUnhealthyBrokerBeforeSpawn(): Promise<void> {
148
- if (await checkSocketConnectable()) return;
162
+ if (await checkSocketConnectable()) {
163
+ return;
164
+ }
149
165
  const pid = readLivePid();
150
- if (pid === null) return;
151
- throw new Error(`Intercom broker PID ${pid} may still own accepted work but its socket is unhealthy; refusing to spawn a second broker. Let the broker exit normally, then retry.`);
166
+ if (pid === null) {
167
+ return;
168
+ }
169
+ throw new Error(
170
+ `Intercom broker PID ${pid} may still own accepted work but its socket is unhealthy; refusing to spawn a second broker. Let the broker exit normally, then retry.`,
171
+ );
152
172
  }
153
173
 
154
174
  async function checkSocketConnectable(): Promise<boolean> {
155
175
  const preferred = getBrokerSocketPath();
156
- if (isOwnedBrokerSocket(preferred) && await checkOneSocket(preferred)) return true;
176
+ if (isOwnedBrokerSocket(preferred) && (await checkOneSocket(preferred))) {
177
+ return true;
178
+ }
157
179
  const legacy = getLegacyBrokerSocketPath();
158
- return legacy !== preferred && isOwnedBrokerSocket(legacy) && await checkOneSocket(legacy);
180
+ return legacy !== preferred && isOwnedBrokerSocket(legacy) && (await checkOneSocket(legacy));
159
181
  }
160
182
 
161
183
  function checkOneSocket(brokerSocket: string): Promise<boolean> {
@@ -173,7 +195,7 @@ function checkOneSocket(brokerSocket: string): Promise<boolean> {
173
195
  socket.on("connect", onConnect);
174
196
  socket.on("error", onError);
175
197
  const timeout = setTimeout(() => finish(false), 1000);
176
- timeout.unref?.();
198
+ timeout.unref();
177
199
  });
178
200
  }
179
201
 
@@ -184,15 +206,11 @@ function acquireSpawnLock(): boolean {
184
206
  writeFileSync(BROKER_SPAWN_LOCK, `${process.pid}\n${Date.now()}\n`, { flag: "wx" });
185
207
  return true;
186
208
  } catch (error) {
187
- if (!(error instanceof Error) || (error as NodeJS.ErrnoException).code !== "EEXIST") {
209
+ if (!hasErrorCode(error, "EEXIST")) {
188
210
  throw error;
189
211
  }
190
212
  if (isSpawnLockStale()) {
191
- try {
192
- unlinkSync(BROKER_SPAWN_LOCK);
193
- } catch {
194
- // If we can't delete the stale lock, retry a few times before giving up
195
- }
213
+ releaseSpawnLock();
196
214
  continue;
197
215
  }
198
216
  return false;
@@ -207,7 +225,9 @@ function isSpawnLockStale(): boolean {
207
225
  }
208
226
 
209
227
  try {
210
- const [pidLine = "", createdAtLine = "0"] = readFileSync(BROKER_SPAWN_LOCK, "utf-8").trim().split("\n");
228
+ const [pidLine = "", createdAtLine = "0"] = readFileSync(BROKER_SPAWN_LOCK, "utf-8")
229
+ .trim()
230
+ .split("\n");
211
231
  const pid = Number.parseInt(pidLine, 10);
212
232
  const createdAt = Number.parseInt(createdAtLine, 10);
213
233
  const ageMs = Date.now() - createdAt;
@@ -239,9 +259,13 @@ function releaseSpawnLock(): void {
239
259
  async function waitForBroker(timeoutMs = 5000): Promise<void> {
240
260
  const start = Date.now();
241
261
  while (Date.now() - start < timeoutMs) {
262
+ // Each probe must finish before the next to avoid parallel socket attempts.
263
+ // oxlint-disable-next-line no-await-in-loop
242
264
  if (await checkSocketConnectable()) {
243
265
  return;
244
266
  }
267
+ // Polling waits between probes rather than starting an unbounded batch.
268
+ // oxlint-disable-next-line no-await-in-loop
245
269
  await sleep(100);
246
270
  }
247
271
  throw new Error("Broker failed to start within timeout");
@@ -1,41 +1,29 @@
1
- import { existsSync, readFileSync } from "fs";
2
- import { join } from "path";
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
3
  import { Key, type KeyId } from "@earendil-works/pi-tui";
4
4
  import { getPiAgentDir } from "./agent-dir.ts";
5
+ import { isRecord, isUnknownArray } from "./validation.ts";
5
6
 
6
7
  export interface IntercomConfig {
7
8
  /** Toggle owned agents, or open peer messaging when the agent view is unavailable. */
8
- shortcut: KeyId;
9
-
10
- /** Broker command used to spawn the broker process (for example, Node or Bun) */
11
- brokerCommand: string;
12
-
13
- /** Arguments passed to the broker command before the broker script path */
14
- brokerArgs: string[];
15
-
16
- /** Require confirmation before non-reply sends from interactive sessions */
17
- confirmSend: boolean;
18
-
19
- /** Optional custom status suffix shown after automatic lifecycle status */
20
- status?: string;
21
-
22
- /** Show reply hint in incoming messages (default: true) */
23
- replyHint: boolean;
24
-
25
- /** How long ordinary intercom `ask` waits for a reply before giving up, in ms (default: 120000 = 2 minutes). */
26
- askTimeoutMs: number;
27
-
28
- /** How long the client waits for the broker to acknowledge message delivery, in ms (default: 8000). */
29
- sendTimeoutMs: number;
30
-
31
- /** How long the client waits for a session list response, in ms (default: 5000). */
32
- listTimeoutMs: number;
33
- }
34
-
35
- function getConfigPath(): string {
36
- return join(getPiAgentDir(), "intercom", "config.json");
9
+ readonly shortcut: KeyId;
10
+ /** Broker command used to spawn the broker process (for example, Node or Bun). */
11
+ readonly brokerCommand: string;
12
+ /** Arguments passed to the broker command before the broker script path. */
13
+ readonly brokerArgs: readonly string[];
14
+ /** Require confirmation before non-reply sends from interactive sessions. */
15
+ readonly confirmSend: boolean;
16
+ /** Optional custom status suffix shown after automatic lifecycle status. */
17
+ readonly status?: string;
18
+ /** Show reply hint in incoming messages (default: true). */
19
+ readonly replyHint: boolean;
20
+ /** Ordinary ask reply timeout, in milliseconds (default: 120000 = 2 minutes). */
21
+ readonly askTimeoutMs: number;
22
+ /** Broker delivery acknowledgement timeout, in milliseconds (default: 8000). */
23
+ readonly sendTimeoutMs: number;
24
+ /** Session list response timeout, in milliseconds (default: 5000). */
25
+ readonly listTimeoutMs: number;
37
26
  }
38
-
39
27
  const defaults: IntercomConfig = {
40
28
  shortcut: Key.altShift("m"),
41
29
  brokerCommand: process.execPath,
@@ -46,95 +34,112 @@ const defaults: IntercomConfig = {
46
34
  sendTimeoutMs: 8000,
47
35
  listTimeoutMs: 5000,
48
36
  };
49
-
50
37
  const namedKeys = new Set<string>(Object.values(Key).filter((key) => typeof key === "string"));
51
38
  function isShortcut(value: string): value is KeyId {
52
39
  const prefix = value.match(/^(?:(?:ctrl|shift|alt|super)\+)+/)?.[0] ?? "";
53
40
  const modifiers = prefix.split("+").filter(Boolean);
54
41
  const key = value.slice(prefix.length);
55
- return new Set(modifiers).size === modifiers.length && (namedKeys.has(key) || /^[a-z0-9]$/.test(key));
42
+ return (
43
+ new Set(modifiers).size === modifiers.length && (namedKeys.has(key) || /^[a-z0-9]$/.test(key))
44
+ );
45
+ }
46
+ function configuredString(
47
+ parsed: Readonly<Record<string, unknown>>,
48
+ key: "brokerCommand" | "status",
49
+ ): string | undefined {
50
+ if (!Object.hasOwn(parsed, key)) {
51
+ return defaults[key];
52
+ }
53
+ const value = parsed[key];
54
+ if (typeof value !== "string") {
55
+ throw new Error(`"${key}" must be a string`);
56
+ }
57
+ if (key === "status") {
58
+ return value;
59
+ }
60
+ if (value.trim() === "") {
61
+ throw new Error('"brokerCommand" must not be empty');
62
+ }
63
+ return value.trim();
64
+ }
65
+ function brokerCommand(parsed: Readonly<Record<string, unknown>>): string {
66
+ return configuredString(parsed, "brokerCommand") ?? defaults.brokerCommand;
67
+ }
68
+ function configuredShortcut(parsed: Readonly<Record<string, unknown>>): KeyId {
69
+ if (!Object.hasOwn(parsed, "shortcut")) {
70
+ return defaults.shortcut;
71
+ }
72
+ if (typeof parsed.shortcut !== "string") {
73
+ throw new Error('"shortcut" must be a native key identifier');
74
+ }
75
+ const shortcut = parsed.shortcut.trim();
76
+ if (!isShortcut(shortcut)) {
77
+ throw new Error('"shortcut" must be a native key identifier, for example alt+shift+m');
78
+ }
79
+ return shortcut;
80
+ }
81
+ function configuredArgs(parsed: Readonly<Record<string, unknown>>): readonly string[] {
82
+ if (!Object.hasOwn(parsed, "brokerArgs")) {
83
+ return defaults.brokerArgs;
84
+ }
85
+ if (!isUnknownArray(parsed.brokerArgs)) {
86
+ throw new Error('"brokerArgs" must be an array');
87
+ }
88
+ return parsed.brokerArgs.map((arg) => {
89
+ if (typeof arg !== "string") {
90
+ throw new Error('"brokerArgs" items must be strings');
91
+ }
92
+ return arg;
93
+ });
94
+ }
95
+ function configuredBoolean(
96
+ parsed: Readonly<Record<string, unknown>>,
97
+ key: "confirmSend" | "replyHint",
98
+ ): boolean {
99
+ if (!Object.hasOwn(parsed, key)) {
100
+ return defaults[key];
101
+ }
102
+ const value = parsed[key];
103
+ if (typeof value !== "boolean") {
104
+ throw new Error(`"${key}" must be a boolean`);
105
+ }
106
+ return value;
107
+ }
108
+ function configuredTimeout(
109
+ parsed: Readonly<Record<string, unknown>>,
110
+ key: "askTimeoutMs" | "sendTimeoutMs" | "listTimeoutMs",
111
+ ): number {
112
+ if (!Object.hasOwn(parsed, key)) {
113
+ return defaults[key];
114
+ }
115
+ const value = parsed[key];
116
+ const min = key === "askTimeoutMs" ? 1000 : 500;
117
+ if (typeof value !== "number" || !Number.isFinite(value) || value < min) {
118
+ throw new Error(`"${key}" must be a finite number >= ${min}`);
119
+ }
120
+ return value;
56
121
  }
57
-
58
122
  export function loadConfig(): IntercomConfig {
59
- const configPath = getConfigPath();
123
+ const configPath = join(getPiAgentDir(), "intercom", "config.json");
60
124
  if (!existsSync(configPath)) {
61
125
  return { ...defaults };
62
126
  }
63
-
64
127
  try {
65
- const raw = readFileSync(configPath, "utf-8");
66
- const parsed: unknown = JSON.parse(raw);
67
- if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
128
+ const parsed: unknown = JSON.parse(readFileSync(configPath, "utf-8"));
129
+ if (!isRecord(parsed)) {
68
130
  throw new Error("Config must be a JSON object");
69
131
  }
70
-
71
- const parsedConfig = parsed as Record<string, unknown>;
72
- const config: IntercomConfig = { ...defaults };
73
-
74
- if (Object.hasOwn(parsedConfig, "shortcut")) {
75
- if (typeof parsedConfig.shortcut !== "string") throw new Error('"shortcut" must be a native key identifier');
76
- const shortcut = parsedConfig.shortcut.trim();
77
- if (!isShortcut(shortcut)) throw new Error('"shortcut" must be a native key identifier, for example alt+shift+m');
78
- config.shortcut = shortcut;
79
- }
80
-
81
- if (Object.hasOwn(parsedConfig, "brokerCommand")) {
82
- if (typeof parsedConfig.brokerCommand !== "string") {
83
- throw new Error(`"brokerCommand" must be a string`);
84
- }
85
- const brokerCommand = parsedConfig.brokerCommand.trim();
86
- if (!brokerCommand) {
87
- throw new Error(`"brokerCommand" must not be empty`);
88
- }
89
- config.brokerCommand = brokerCommand;
90
- }
91
-
92
- if (Object.hasOwn(parsedConfig, "brokerArgs")) {
93
- if (!Array.isArray(parsedConfig.brokerArgs)) {
94
- throw new Error(`"brokerArgs" must be an array`);
95
- }
96
- const brokerArgs: string[] = [];
97
- for (const arg of parsedConfig.brokerArgs) {
98
- if (typeof arg !== "string") {
99
- throw new Error(`"brokerArgs" items must be strings`);
100
- }
101
- brokerArgs.push(arg);
102
- }
103
- config.brokerArgs = brokerArgs;
104
- }
105
-
106
- if (Object.hasOwn(parsedConfig, "confirmSend")) {
107
- if (typeof parsedConfig.confirmSend !== "boolean") {
108
- throw new Error(`"confirmSend" must be a boolean`);
109
- }
110
- config.confirmSend = parsedConfig.confirmSend;
111
- }
112
-
113
- if (Object.hasOwn(parsedConfig, "replyHint")) {
114
- if (typeof parsedConfig.replyHint !== "boolean") {
115
- throw new Error(`"replyHint" must be a boolean`);
116
- }
117
- config.replyHint = parsedConfig.replyHint;
118
- }
119
-
120
- if (Object.hasOwn(parsedConfig, "status")) {
121
- if (typeof parsedConfig.status !== "string") {
122
- throw new Error(`"status" must be a string`);
123
- }
124
- config.status = parsedConfig.status;
125
- }
126
-
127
- for (const [key, min] of [["askTimeoutMs", 1000], ["sendTimeoutMs", 500], ["listTimeoutMs", 500]] as const) {
128
- if (Object.hasOwn(parsedConfig, key)) {
129
- const value = parsedConfig[key];
130
- if (typeof value !== "number" || !Number.isFinite(value) || value < min) {
131
- throw new Error(`"${key}" must be a finite number >= ${min}`);
132
- }
133
- config[key] = value;
134
- }
135
- }
136
-
137
- return config;
132
+ return {
133
+ shortcut: configuredShortcut(parsed),
134
+ brokerCommand: brokerCommand(parsed),
135
+ brokerArgs: configuredArgs(parsed),
136
+ confirmSend: configuredBoolean(parsed, "confirmSend"),
137
+ replyHint: configuredBoolean(parsed, "replyHint"),
138
+ status: configuredString(parsed, "status"),
139
+ askTimeoutMs: configuredTimeout(parsed, "askTimeoutMs"),
140
+ sendTimeoutMs: configuredTimeout(parsed, "sendTimeoutMs"),
141
+ listTimeoutMs: configuredTimeout(parsed, "listTimeoutMs"),
142
+ };
138
143
  } catch (error) {
139
144
  console.error(`Failed to load intercom config at ${configPath}:`, error);
140
145
  return { ...defaults };