@fitchmultz/pi-subagents 0.44.7 → 0.45.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 (947) hide show
  1. package/CHANGELOG.md +258 -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 +79 -0
  111. package/dist/pi-intercom/bridge-http.js +86 -0
  112. package/dist/pi-intercom/bridge-protocol.js +106 -0
  113. package/dist/pi-intercom/bridge-routes.js +64 -0
  114. package/dist/pi-intercom/bridge-session.js +416 -0
  115. package/dist/pi-intercom/bridge.js +182 -603
  116. package/dist/pi-intercom/broker/broker.js +236 -244
  117. package/dist/pi-intercom/broker/client.js +189 -304
  118. package/dist/pi-intercom/broker/connection.js +165 -0
  119. package/dist/pi-intercom/broker/framing.js +5 -3
  120. package/dist/pi-intercom/broker/paths.js +4 -1
  121. package/dist/pi-intercom/broker/pid.js +53 -25
  122. package/dist/pi-intercom/broker/snapshot-reader.js +78 -0
  123. package/dist/pi-intercom/broker/snapshots.js +188 -0
  124. package/dist/pi-intercom/broker/spawn.js +36 -25
  125. package/dist/pi-intercom/config.js +85 -71
  126. package/dist/pi-intercom/connection.js +297 -0
  127. package/dist/pi-intercom/identity.js +58 -0
  128. package/dist/pi-intercom/inbound-delivery.js +356 -0
  129. package/dist/pi-intercom/inbound-journal.js +303 -0
  130. package/dist/pi-intercom/inbound-record.js +113 -0
  131. package/dist/pi-intercom/inbound.js +179 -0
  132. package/dist/pi-intercom/index.js +79 -2933
  133. package/dist/pi-intercom/inspection.js +62 -0
  134. package/dist/pi-intercom/interview.js +236 -0
  135. package/dist/pi-intercom/lifecycle.js +168 -0
  136. package/dist/pi-intercom/message-format.js +69 -0
  137. package/dist/pi-intercom/outbound.js +304 -0
  138. package/dist/pi-intercom/peer-awareness.js +66 -0
  139. package/dist/pi-intercom/reply-tracker.js +62 -43
  140. package/dist/pi-intercom/reply-wait.js +201 -0
  141. package/dist/pi-intercom/runtime-types.js +3 -0
  142. package/dist/pi-intercom/session-events.js +180 -0
  143. package/dist/pi-intercom/session-targets.js +42 -34
  144. package/dist/pi-intercom/subagent-events.js +238 -0
  145. package/dist/pi-intercom/subagent-live-events.js +129 -86
  146. package/dist/pi-intercom/supervisor.js +282 -0
  147. package/dist/pi-intercom/tool-arguments.js +74 -0
  148. package/dist/pi-intercom/tool-registration.js +95 -0
  149. package/dist/pi-intercom/tool-results.js +38 -0
  150. package/dist/pi-intercom/tool-schemas.js +82 -0
  151. package/dist/pi-intercom/tools.js +51 -0
  152. package/dist/pi-intercom/topic-actions.js +177 -0
  153. package/dist/pi-intercom/topics.js +177 -92
  154. package/dist/pi-intercom/transport.js +1 -0
  155. package/dist/pi-intercom/types.js +151 -114
  156. package/dist/pi-intercom/ui/compose-paste.js +93 -0
  157. package/dist/pi-intercom/ui/compose.js +121 -143
  158. package/dist/pi-intercom/ui/inline-message.js +59 -59
  159. package/dist/pi-intercom/ui/message-renderers.js +147 -0
  160. package/dist/pi-intercom/ui/overlay.js +181 -0
  161. package/dist/pi-intercom/ui/session-format.js +124 -0
  162. package/dist/pi-intercom/ui/session-list.js +76 -43
  163. package/dist/pi-intercom/ui/tool-renderers.js +110 -0
  164. package/dist/pi-intercom/ui/topic-view.js +88 -0
  165. package/dist/pi-intercom/validation.js +59 -0
  166. package/dist/runs/background/async-chain-plan.js +265 -0
  167. package/dist/runs/background/async-control.js +134 -58
  168. package/dist/runs/background/async-execution.js +136 -633
  169. package/dist/runs/background/async-job-admission.js +40 -0
  170. package/dist/runs/background/async-job-projection.js +169 -0
  171. package/dist/runs/background/async-job-tracker.js +297 -327
  172. package/dist/runs/background/async-launch.js +216 -0
  173. package/dist/runs/background/async-plan.js +116 -0
  174. package/dist/runs/background/async-result-file.js +47 -23
  175. package/dist/runs/background/async-resume.js +195 -253
  176. package/dist/runs/background/async-run-discovery.js +213 -0
  177. package/dist/runs/background/async-run-location.js +135 -0
  178. package/dist/runs/background/async-run-record.js +1 -0
  179. package/dist/runs/background/async-run-repair.js +223 -0
  180. package/dist/runs/background/async-run-summary.js +1 -0
  181. package/dist/runs/background/async-single-plan.js +105 -0
  182. package/dist/runs/background/async-status-projection.js +155 -0
  183. package/dist/runs/background/async-status-render.js +117 -0
  184. package/dist/runs/background/async-status-validation.js +181 -0
  185. package/dist/runs/background/async-status.js +3 -442
  186. package/dist/runs/background/async-value.js +21 -0
  187. package/dist/runs/background/completion-dedupe.js +36 -12
  188. package/dist/runs/background/completion-delivery.js +211 -205
  189. package/dist/runs/background/completion-receipts.js +237 -0
  190. package/dist/runs/background/legacy-status-acceptance.js +34 -0
  191. package/dist/runs/background/notify.js +96 -48
  192. package/dist/runs/background/parallel-groups.js +36 -19
  193. package/dist/runs/background/result-payload.js +178 -0
  194. package/dist/runs/background/result-watcher.js +348 -339
  195. package/dist/runs/background/run-id-resolver.js +53 -33
  196. package/dist/runs/background/run-schemas.js +189 -0
  197. package/dist/runs/background/run-status-contracts.js +14 -0
  198. package/dist/runs/background/run-status-render.js +270 -0
  199. package/dist/runs/background/run-status.js +231 -339
  200. package/dist/runs/background/runner-attempt-output.js +155 -0
  201. package/dist/runs/background/runner-attempt.js +263 -0
  202. package/dist/runs/background/runner-child-executor.js +166 -0
  203. package/dist/runs/background/runner-child-observer.js +192 -0
  204. package/dist/runs/background/runner-completion-summary.js +71 -0
  205. package/dist/runs/background/runner-completion.js +211 -0
  206. package/dist/runs/background/runner-config.js +1 -0
  207. package/dist/runs/background/runner-contract.js +1 -0
  208. package/dist/runs/background/runner-dynamic.js +121 -0
  209. package/dist/runs/background/runner-finalization.js +149 -0
  210. package/dist/runs/background/runner-graph.js +68 -0
  211. package/dist/runs/background/runner-initial-status.js +60 -0
  212. package/dist/runs/background/runner-lifecycle.js +142 -0
  213. package/dist/runs/background/runner-monitor.js +309 -0
  214. package/dist/runs/background/runner-parallel.js +204 -0
  215. package/dist/runs/background/runner-prepare-step.js +86 -0
  216. package/dist/runs/background/runner-reporting.js +153 -0
  217. package/dist/runs/background/runner-status.js +148 -0
  218. package/dist/runs/background/runner-step-output.js +92 -0
  219. package/dist/runs/background/runner-step-record.js +45 -0
  220. package/dist/runs/background/runner-step.js +112 -0
  221. package/dist/runs/background/runner-streaming.js +173 -0
  222. package/dist/runs/background/runner-workflow.js +213 -0
  223. package/dist/runs/background/stale-run-reconciler.js +155 -292
  224. package/dist/runs/background/subagent-runner-launcher.js +33 -13
  225. package/dist/runs/background/subagent-runner.js +51 -1842
  226. package/dist/runs/background/top-level-async.js +2 -1
  227. package/dist/runs/foreground/chain-clarify.js +293 -1017
  228. package/dist/runs/foreground/clarification-draft.js +87 -0
  229. package/dist/runs/foreground/clarify-contracts.js +1 -0
  230. package/dist/runs/foreground/clarify-invocation.js +129 -38
  231. package/dist/runs/foreground/clarify-text-editor.js +210 -0
  232. package/dist/runs/foreground/clarify-view.js +167 -0
  233. package/dist/runs/foreground/execution-input.js +226 -353
  234. package/dist/runs/foreground/execution-routing.js +33 -0
  235. package/dist/runs/foreground/execution-timeout.js +81 -0
  236. package/dist/runs/foreground/foreground-control.js +222 -763
  237. package/dist/runs/foreground/foreground-memory.js +99 -0
  238. package/dist/runs/foreground/invocation-context.js +55 -0
  239. package/dist/runs/foreground/invocation-execution.js +331 -0
  240. package/dist/runs/foreground/invocation-expansion.js +48 -0
  241. package/dist/runs/foreground/management-actions.js +295 -0
  242. package/dist/runs/foreground/nested-control.js +179 -0
  243. package/dist/runs/foreground/question-continuation.js +78 -0
  244. package/dist/runs/foreground/question-control.js +155 -50
  245. package/dist/runs/foreground/resume-target.js +221 -0
  246. package/dist/runs/foreground/revival-launch-policy.js +58 -0
  247. package/dist/runs/foreground/run-async-path.js +190 -178
  248. package/dist/runs/foreground/run-interrupt.js +164 -0
  249. package/dist/runs/foreground/run-nudge.js +278 -0
  250. package/dist/runs/foreground/saved-revival.js +251 -0
  251. package/dist/runs/foreground/subagent-executor.js +135 -424
  252. package/dist/runs/foreground/subagent-params.js +67 -30
  253. package/dist/runs/foreground/wait-observation.js +104 -0
  254. package/dist/runs/foreground/wait-registration.js +17 -0
  255. package/dist/runs/foreground/wait-run.js +283 -123
  256. package/dist/runs/shared/acceptance-contract.js +193 -99
  257. package/dist/runs/shared/acceptance-defaults.js +1 -0
  258. package/dist/runs/shared/acceptance-evaluation.js +201 -181
  259. package/dist/runs/shared/acceptance-finalization.js +256 -180
  260. package/dist/runs/shared/acceptance-outcome.js +53 -0
  261. package/dist/runs/shared/acceptance-reports.js +137 -72
  262. package/dist/runs/shared/acceptance-submission.js +167 -0
  263. package/dist/runs/shared/acceptance-verification.js +100 -0
  264. package/dist/runs/shared/chain-outputs.js +80 -52
  265. package/dist/runs/shared/child-attempt-types.js +1 -0
  266. package/dist/runs/shared/child-attempt.js +314 -667
  267. package/dist/runs/shared/child-boundaries.js +173 -0
  268. package/dist/runs/shared/child-context-filter.js +44 -0
  269. package/dist/runs/shared/child-event-observer.js +390 -0
  270. package/dist/runs/shared/child-execution-cwd.js +73 -43
  271. package/dist/runs/shared/child-execution-outcome.js +72 -0
  272. package/dist/runs/shared/child-invocation.js +54 -0
  273. package/dist/runs/shared/child-message-validation.js +215 -0
  274. package/dist/runs/shared/child-native-accounting.js +106 -0
  275. package/dist/runs/shared/child-native-observation.js +69 -0
  276. package/dist/runs/shared/child-observation-spool.js +164 -0
  277. package/dist/runs/shared/child-observations.js +157 -76
  278. package/dist/runs/shared/child-presence.js +3 -0
  279. package/dist/runs/shared/child-route-env.js +119 -0
  280. package/dist/runs/shared/child-stream-observer.js +221 -0
  281. package/dist/runs/shared/child-stream-projection.js +137 -0
  282. package/dist/runs/shared/child-structured-tool.js +27 -0
  283. package/dist/runs/shared/claude-code.js +121 -158
  284. package/dist/runs/shared/claude-model.js +42 -0
  285. package/dist/runs/shared/claude-session.js +83 -0
  286. package/dist/runs/shared/claude-types.js +1 -0
  287. package/dist/runs/shared/completion-guard.js +18 -18
  288. package/dist/runs/shared/control-event-policy.js +8 -0
  289. package/dist/runs/shared/control-notification-owner.js +13 -0
  290. package/dist/runs/shared/dynamic-fanout.js +188 -173
  291. package/dist/runs/shared/dynamic-item.js +102 -0
  292. package/dist/runs/shared/history-index.js +62 -36
  293. package/dist/runs/shared/legacy-async-recovery.js +114 -0
  294. package/dist/runs/shared/legacy-output-recovery.js +148 -0
  295. package/dist/runs/shared/mcp-config-schema.js +36 -0
  296. package/dist/runs/shared/mcp-direct-tool-allowlist.js +147 -116
  297. package/dist/runs/shared/model-fallback.js +97 -38
  298. package/dist/runs/shared/mutating-tool-guard.js +128 -88
  299. package/dist/runs/shared/native-finalization-types.js +1 -0
  300. package/dist/runs/shared/native-finalization.js +155 -76
  301. package/dist/runs/shared/native-usage.js +238 -98
  302. package/dist/runs/shared/nested-control-records.js +128 -0
  303. package/dist/runs/shared/nested-events.js +8 -700
  304. package/dist/runs/shared/nested-path.js +32 -28
  305. package/dist/runs/shared/nested-projection.js +155 -0
  306. package/dist/runs/shared/nested-protocol.js +18 -0
  307. package/dist/runs/shared/nested-registry.js +191 -0
  308. package/dist/runs/shared/nested-render.js +106 -58
  309. package/dist/runs/shared/nested-route.js +220 -0
  310. package/dist/runs/shared/nested-validation.js +216 -0
  311. package/dist/runs/shared/owned-child-evidence.js +125 -0
  312. package/dist/runs/shared/owned-run-list.js +146 -0
  313. package/dist/runs/shared/owned-run-observation.js +267 -0
  314. package/dist/runs/shared/owned-run-progress.js +109 -0
  315. package/dist/runs/shared/owned-run-read-state.js +1 -0
  316. package/dist/runs/shared/owned-run-results.js +202 -0
  317. package/dist/runs/shared/owned-run-status.js +180 -0
  318. package/dist/runs/shared/owned-run-view.js +51 -0
  319. package/dist/runs/shared/owned-workflow-details.js +17 -0
  320. package/dist/runs/shared/owner-output.js +43 -0
  321. package/dist/runs/shared/parallel-utils.js +36 -28
  322. package/dist/runs/shared/parent-receipts.js +90 -32
  323. package/dist/runs/shared/parent-usage.js +169 -57
  324. package/dist/runs/shared/pi-args.js +108 -201
  325. package/dist/runs/shared/pi-launch-input.js +1 -0
  326. package/dist/runs/shared/pi-session-launch.js +86 -0
  327. package/dist/runs/shared/pi-spawn.js +35 -21
  328. package/dist/runs/shared/run-history-queries.js +126 -35
  329. package/dist/runs/shared/run-history.js +101 -35
  330. package/dist/runs/shared/run-metadata-paths.js +14 -0
  331. package/dist/runs/shared/run-metadata.js +158 -0
  332. package/dist/runs/shared/run-persistence.js +131 -0
  333. package/dist/runs/shared/run-records.js +9 -679
  334. package/dist/runs/shared/run-restoration.js +338 -0
  335. package/dist/runs/shared/run-state-owner.js +26 -0
  336. package/dist/runs/shared/session-cwd-preload.js +27 -18
  337. package/dist/runs/shared/single-output.js +148 -70
  338. package/dist/runs/shared/stable-value.js +15 -0
  339. package/dist/runs/shared/streaming-text.js +23 -12
  340. package/dist/runs/shared/structured-output.js +25 -13
  341. package/dist/runs/shared/subagent-control.js +167 -100
  342. package/dist/runs/shared/subagent-prompt-runtime.js +27 -130
  343. package/dist/runs/shared/subagent-tool-loop-guard.js +81 -52
  344. package/dist/runs/shared/supervisor-question-state.js +145 -0
  345. package/dist/runs/shared/supervisor-questions.js +185 -254
  346. package/dist/runs/shared/workflow-graph.js +259 -167
  347. package/dist/runs/shared/workflow-policy.js +120 -48
  348. package/dist/runs/shared/worktree-contract.js +1 -0
  349. package/dist/runs/shared/worktree-hook.js +138 -0
  350. package/dist/runs/shared/worktree-location.js +47 -0
  351. package/dist/runs/shared/worktree-preservation.js +8 -0
  352. package/dist/runs/shared/worktree-process.js +107 -0
  353. package/dist/runs/shared/worktree.js +183 -322
  354. package/dist/shared/agent-context-policy.js +34 -44
  355. package/dist/shared/agent-dir.js +14 -0
  356. package/dist/shared/artifacts.js +30 -12
  357. package/dist/shared/atomic-json.js +4 -1
  358. package/dist/shared/chain-files.js +72 -0
  359. package/dist/shared/concurrency.js +18 -0
  360. package/dist/shared/content-preview.js +115 -0
  361. package/dist/shared/cooperative.js +5 -2
  362. package/dist/shared/execution-cwd.js +13 -5
  363. package/dist/shared/file-coalescer.js +2 -1
  364. package/dist/shared/fork-context.js +10 -12
  365. package/dist/shared/formatters.js +45 -19
  366. package/dist/shared/journal-frames.js +164 -0
  367. package/dist/shared/journal-projections.js +121 -0
  368. package/dist/shared/journal-reader.js +6 -407
  369. package/dist/shared/json-projection.js +191 -0
  370. package/dist/shared/lazy-tools.js +19 -8
  371. package/dist/shared/message-output.js +116 -0
  372. package/dist/shared/model-info.js +31 -14
  373. package/dist/shared/native-import.js +20 -0
  374. package/dist/shared/native-journal.js +140 -0
  375. package/dist/shared/native-session.js +5 -2
  376. package/dist/shared/native-tui.js +7 -2
  377. package/dist/shared/native-typebox.js +15 -3
  378. package/dist/shared/output-page.js +63 -0
  379. package/dist/shared/post-exit-stdio-guard.js +128 -88
  380. package/dist/shared/prompt-sections.js +2 -0
  381. package/dist/shared/session-entries.js +70 -35
  382. package/dist/shared/session-identity.js +5 -3
  383. package/dist/shared/settings.js +62 -192
  384. package/dist/shared/status-format.js +97 -37
  385. package/dist/shared/task-file-policy.js +24 -0
  386. package/dist/shared/temp-root.js +44 -15
  387. package/dist/shared/types/acceptance.js +1 -0
  388. package/dist/shared/types/async.js +1 -0
  389. package/dist/shared/types/config.js +1 -0
  390. package/dist/shared/types/details.js +1 -0
  391. package/dist/shared/types/history.js +1 -0
  392. package/dist/shared/types/inputs.js +1 -0
  393. package/dist/shared/types/intercom.js +1 -0
  394. package/dist/shared/types/launch.js +1 -0
  395. package/dist/shared/types/messages.js +1 -0
  396. package/dist/shared/types/nested.js +1 -0
  397. package/dist/shared/types/owned-runs.js +1 -0
  398. package/dist/shared/types/progress.js +1 -0
  399. package/dist/shared/types/questions.js +1 -0
  400. package/dist/shared/types/results.js +1 -0
  401. package/dist/shared/types/state.js +1 -0
  402. package/dist/shared/types/usage.js +1 -0
  403. package/dist/shared/types/workflow.js +1 -0
  404. package/dist/shared/types.js +75 -30
  405. package/dist/shared/unknown.js +52 -0
  406. package/dist/shared/utils.js +54 -260
  407. package/dist/slash/command-discovery.js +82 -0
  408. package/dist/slash/command-input.js +190 -0
  409. package/dist/slash/prompt-template-bridge.js +94 -270
  410. package/dist/slash/prompt-template-contract.js +77 -0
  411. package/dist/slash/prompt-template-results.js +125 -0
  412. package/dist/slash/request-protocol.js +68 -0
  413. package/dist/slash/result-delivery.js +237 -0
  414. package/dist/slash/saved-chain.js +78 -0
  415. package/dist/slash/slash-bridge.js +123 -89
  416. package/dist/slash/slash-commands.js +101 -572
  417. package/dist/slash/slash-live-state.js +68 -47
  418. package/dist/tui/action-hints.js +50 -22
  419. package/dist/tui/activity-lines.js +32 -0
  420. package/dist/tui/agent-browser.js +290 -0
  421. package/dist/tui/agent-controls.js +289 -0
  422. package/dist/tui/agent-conversation.js +444 -0
  423. package/dist/tui/agent-dock.js +171 -0
  424. package/dist/tui/agent-history.js +50 -183
  425. package/dist/tui/agent-model.js +62 -0
  426. package/dist/tui/agent-picker.js +262 -0
  427. package/dist/tui/agent-view.js +232 -1564
  428. package/dist/tui/compact-results.js +193 -0
  429. package/dist/tui/conversation-details.js +190 -0
  430. package/dist/tui/conversation-frame.js +135 -0
  431. package/dist/tui/conversation-history.js +201 -0
  432. package/dist/tui/conversation-menu.js +78 -0
  433. package/dist/tui/conversation-notices.js +79 -0
  434. package/dist/tui/conversation-selection.js +58 -0
  435. package/dist/tui/conversation-viewport.js +129 -0
  436. package/dist/tui/direction-message.js +27 -0
  437. package/dist/tui/display.js +282 -0
  438. package/dist/tui/editor-viewport.js +18 -0
  439. package/dist/tui/expanded-content.js +87 -0
  440. package/dist/tui/expanded-multi.js +170 -0
  441. package/dist/tui/expanded-single.js +65 -0
  442. package/dist/tui/history-cards.js +216 -0
  443. package/dist/tui/history-display.js +238 -0
  444. package/dist/tui/history-json.js +16 -0
  445. package/dist/tui/history-metadata.js +152 -0
  446. package/dist/tui/history-record.js +251 -0
  447. package/dist/tui/history-text.js +34 -0
  448. package/dist/tui/indexed-history.js +116 -0
  449. package/dist/tui/nested-widget.js +120 -0
  450. package/dist/tui/picker-page.js +59 -0
  451. package/dist/tui/render.js +58 -1501
  452. package/dist/tui/result-facts.js +64 -0
  453. package/dist/tui/task-observation.js +59 -0
  454. package/dist/tui/task-store.js +366 -0
  455. package/dist/tui/text-values.js +16 -0
  456. package/dist/tui/view-connections.js +47 -0
  457. package/dist/tui/view-model.js +94 -0
  458. package/dist/tui/view-persistence.js +51 -0
  459. package/dist/tui/view-ports.js +1 -0
  460. package/dist/tui/view-session.js +37 -0
  461. package/dist/tui/widget-details.js +144 -0
  462. package/dist/tui/widget-status.js +245 -0
  463. package/dist/tui/widget.js +145 -0
  464. package/dist/tui/workflow-labels.js +223 -0
  465. package/dist/tui/workflow-outcomes.js +124 -0
  466. package/docs/code-quality.md +38 -0
  467. package/docs/development.md +99 -0
  468. package/docs/intercom-bridge.md +22 -17
  469. package/docs/intercom.md +132 -106
  470. package/docs/performance.md +19 -17
  471. package/docs/reference.md +1472 -0
  472. package/generated/RunValidators.d.ts +28 -0
  473. package/generated/RunValidators.js +2 -0
  474. package/package.json +27 -6
  475. package/prompts/parallel-cleanup.md +3 -0
  476. package/prompts/parallel-context-build.md +3 -0
  477. package/prompts/parallel-handoff-plan.md +6 -0
  478. package/prompts/parallel-research.md +4 -0
  479. package/prompts/parallel-review.md +2 -0
  480. package/prompts/review-loop.md +2 -0
  481. package/scripts/build.mjs +129 -85
  482. package/scripts/check-compat.mjs +48 -11
  483. package/scripts/compat-host.mjs +35 -7
  484. package/scripts/generate-run-schemas.mjs +210 -0
  485. package/scripts/intercom-bridge-credentials.mjs +155 -28
  486. package/scripts/intercom-remote.mjs +175 -50
  487. package/scripts/local-install-smoke.mjs +47 -37
  488. package/scripts/native-package-smoke.mjs +135 -25
  489. package/scripts/package-smoke.mjs +360 -140
  490. package/scripts/prepare.mjs +54 -34
  491. package/scripts/real-pi-processes.mjs +261 -0
  492. package/scripts/real-pi-smoke.mjs +432 -351
  493. package/scripts/run-tests.mjs +29 -15
  494. package/skills/pi-intercom/SKILL.md +11 -11
  495. package/skills/pi-intercom/references/peer-sessions.md +7 -2
  496. package/skills/pi-subagents/SKILL.md +1 -1
  497. package/skills/pi-subagents/references/full-orchestration-guide.md +254 -112
  498. package/src/agents/agent-defaults.ts +13 -0
  499. package/src/agents/agent-definition.ts +253 -0
  500. package/src/agents/agent-management.ts +111 -808
  501. package/src/agents/agent-scope.ts +7 -3
  502. package/src/agents/agent-selection.ts +26 -16
  503. package/src/agents/agent-serializer.ts +84 -93
  504. package/src/agents/agents.ts +199 -906
  505. package/src/agents/builtin-overrides.ts +297 -0
  506. package/src/agents/chain-serializer.ts +3 -329
  507. package/src/agents/config-values.ts +57 -0
  508. package/src/agents/discovery-paths.ts +134 -0
  509. package/src/agents/frontmatter.ts +35 -17
  510. package/src/agents/identity.ts +49 -18
  511. package/src/agents/json-chain.ts +305 -0
  512. package/src/agents/management-config.ts +342 -0
  513. package/src/agents/management-format.ts +243 -0
  514. package/src/agents/management-persistence.ts +408 -0
  515. package/src/agents/management-targets.ts +260 -0
  516. package/src/agents/management-warnings.ts +115 -0
  517. package/src/agents/markdown-chain.ts +237 -0
  518. package/src/agents/package-agents.ts +231 -0
  519. package/src/agents/skill-files.ts +182 -0
  520. package/src/agents/skill-search-paths.ts +289 -0
  521. package/src/agents/skill-types.ts +31 -0
  522. package/src/agents/skills.ts +152 -610
  523. package/src/extension/acceptance-schema.ts +88 -0
  524. package/src/extension/chain-schema.ts +276 -0
  525. package/src/extension/child-runtime.ts +302 -0
  526. package/src/extension/compact-tools.ts +259 -102
  527. package/src/extension/config-schema.ts +59 -0
  528. package/src/extension/config.ts +39 -17
  529. package/src/extension/control-notice-schema.ts +55 -0
  530. package/src/extension/control-notices.ts +57 -33
  531. package/src/extension/delegation-bridges.ts +59 -0
  532. package/src/extension/doctor.ts +171 -135
  533. package/src/extension/everyday-schemas.ts +252 -0
  534. package/src/extension/fanout-child.ts +29 -308
  535. package/src/extension/index.ts +17 -642
  536. package/src/extension/message-renderers.ts +334 -0
  537. package/src/extension/nested-control-inbox.ts +196 -0
  538. package/src/extension/parent-runtime.ts +405 -0
  539. package/src/extension/primary-tool.ts +130 -0
  540. package/src/extension/result-snapshot.ts +35 -0
  541. package/src/extension/runtime-reload.ts +72 -0
  542. package/src/extension/runtime-storage.ts +49 -0
  543. package/src/extension/schema-overrides.ts +114 -0
  544. package/src/extension/schemas.ts +451 -418
  545. package/src/extension/tool-input.ts +40 -13
  546. package/src/extension/tool-result.ts +45 -14
  547. package/src/history/answer-texts.ts +74 -0
  548. package/src/history/canonical-result.ts +127 -51
  549. package/src/history/canonical-selection.ts +54 -0
  550. package/src/history/database-generation.ts +86 -0
  551. package/src/history/database.ts +86 -48
  552. package/src/history/entry-ingestion.ts +129 -0
  553. package/src/history/index.ts +426 -148
  554. package/src/history/ingest.ts +372 -342
  555. package/src/history/output-digests.ts +41 -0
  556. package/src/history/preview.ts +235 -0
  557. package/src/history/prune.ts +48 -0
  558. package/src/history/queries.ts +122 -256
  559. package/src/history/query-scope.ts +278 -0
  560. package/src/history/rows.ts +118 -0
  561. package/src/history/run-projection.ts +164 -0
  562. package/src/history/run-queries.ts +199 -0
  563. package/src/history/schema.ts +34 -0
  564. package/src/history/search-queries.ts +216 -0
  565. package/src/history/selected-record.ts +140 -0
  566. package/src/history/source-file.ts +51 -0
  567. package/src/history/source-watches.ts +156 -0
  568. package/src/history/store.ts +310 -197
  569. package/src/history/text-chunks.ts +181 -0
  570. package/src/history/text.ts +43 -0
  571. package/src/history/transcript-queries.ts +251 -0
  572. package/src/history/types.ts +27 -164
  573. package/src/history/values.ts +36 -0
  574. package/src/history/wire-inputs.ts +141 -0
  575. package/src/history/wire-models.ts +51 -0
  576. package/src/history/worker-runtime.ts +502 -0
  577. package/src/history/worker.ts +94 -336
  578. package/src/intercom/intercom-bridge.ts +136 -69
  579. package/src/intercom/live-intercom.ts +197 -92
  580. package/src/intercom/nested-result-tree.ts +213 -0
  581. package/src/intercom/result-delivery.ts +56 -0
  582. package/src/intercom/result-intercom.ts +364 -382
  583. package/src/pi-intercom/agent-dir.ts +9 -3
  584. package/src/pi-intercom/async.ts +33 -0
  585. package/src/pi-intercom/bridge-ask.ts +64 -0
  586. package/src/pi-intercom/bridge-config.ts +101 -0
  587. package/src/pi-intercom/bridge-http.ts +97 -0
  588. package/src/pi-intercom/bridge-protocol.ts +123 -0
  589. package/src/pi-intercom/bridge-routes.ts +90 -0
  590. package/src/pi-intercom/bridge-session.ts +506 -0
  591. package/src/pi-intercom/bridge.ts +258 -547
  592. package/src/pi-intercom/broker/broker.ts +326 -263
  593. package/src/pi-intercom/broker/client.ts +273 -354
  594. package/src/pi-intercom/broker/connection.ts +192 -0
  595. package/src/pi-intercom/broker/framing.ts +11 -6
  596. package/src/pi-intercom/broker/paths.ts +28 -25
  597. package/src/pi-intercom/broker/pid.ts +68 -24
  598. package/src/pi-intercom/broker/snapshot-reader.ts +91 -0
  599. package/src/pi-intercom/broker/snapshots.ts +241 -0
  600. package/src/pi-intercom/broker/spawn.ts +58 -34
  601. package/src/pi-intercom/config.ts +113 -108
  602. package/src/pi-intercom/connection.ts +346 -0
  603. package/src/pi-intercom/identity.ts +71 -0
  604. package/src/pi-intercom/inbound-delivery.ts +450 -0
  605. package/src/pi-intercom/inbound-journal.ts +350 -0
  606. package/src/pi-intercom/inbound-record.ts +141 -0
  607. package/src/pi-intercom/inbound.ts +237 -0
  608. package/src/pi-intercom/index.ts +86 -2923
  609. package/src/pi-intercom/inspection.ts +82 -0
  610. package/src/pi-intercom/interview.ts +295 -0
  611. package/src/pi-intercom/lifecycle.ts +183 -0
  612. package/src/pi-intercom/message-format.ts +77 -0
  613. package/src/pi-intercom/outbound.ts +418 -0
  614. package/src/pi-intercom/peer-awareness.ts +84 -0
  615. package/src/pi-intercom/reply-tracker.ts +121 -59
  616. package/src/pi-intercom/reply-wait.ts +247 -0
  617. package/src/pi-intercom/runtime-types.ts +97 -0
  618. package/src/pi-intercom/session-events.ts +247 -0
  619. package/src/pi-intercom/session-targets.ts +124 -72
  620. package/src/pi-intercom/subagent-events.ts +299 -0
  621. package/src/pi-intercom/subagent-live-events.ts +212 -109
  622. package/src/pi-intercom/supervisor.ts +362 -0
  623. package/src/pi-intercom/tool-arguments.ts +120 -0
  624. package/src/pi-intercom/tool-registration.ts +121 -0
  625. package/src/pi-intercom/tool-results.ts +54 -0
  626. package/src/pi-intercom/tool-schemas.ts +134 -0
  627. package/src/pi-intercom/tools.ts +80 -0
  628. package/src/pi-intercom/topic-actions.ts +243 -0
  629. package/src/pi-intercom/topics.ts +267 -121
  630. package/src/pi-intercom/transport.ts +14 -0
  631. package/src/pi-intercom/types.ts +288 -190
  632. package/src/pi-intercom/ui/compose-paste.ts +109 -0
  633. package/src/pi-intercom/ui/compose.ts +173 -157
  634. package/src/pi-intercom/ui/inline-message.ts +80 -62
  635. package/src/pi-intercom/ui/message-renderers.ts +182 -0
  636. package/src/pi-intercom/ui/overlay.ts +238 -0
  637. package/src/pi-intercom/ui/session-format.ts +146 -0
  638. package/src/pi-intercom/ui/session-list.ts +145 -62
  639. package/src/pi-intercom/ui/tool-renderers.ts +148 -0
  640. package/src/pi-intercom/ui/topic-view.ts +107 -0
  641. package/src/pi-intercom/validation.ts +69 -0
  642. package/src/runs/background/async-chain-plan.ts +451 -0
  643. package/src/runs/background/async-control.ts +201 -71
  644. package/src/runs/background/async-execution.ts +206 -829
  645. package/src/runs/background/async-job-admission.ts +54 -0
  646. package/src/runs/background/async-job-projection.ts +225 -0
  647. package/src/runs/background/async-job-tracker.ts +416 -360
  648. package/src/runs/background/async-launch.ts +319 -0
  649. package/src/runs/background/async-plan.ts +285 -0
  650. package/src/runs/background/async-result-file.ts +79 -37
  651. package/src/runs/background/async-resume.ts +338 -285
  652. package/src/runs/background/async-run-discovery.ts +270 -0
  653. package/src/runs/background/async-run-location.ts +194 -0
  654. package/src/runs/background/async-run-record.ts +14 -0
  655. package/src/runs/background/async-run-repair.ts +307 -0
  656. package/src/runs/background/async-run-summary.ts +71 -0
  657. package/src/runs/background/async-single-plan.ts +168 -0
  658. package/src/runs/background/async-status-projection.ts +188 -0
  659. package/src/runs/background/async-status-render.ts +164 -0
  660. package/src/runs/background/async-status-validation.ts +238 -0
  661. package/src/runs/background/async-status.ts +9 -481
  662. package/src/runs/background/async-value.ts +29 -0
  663. package/src/runs/background/completion-dedupe.ts +103 -54
  664. package/src/runs/background/completion-delivery.ts +313 -187
  665. package/src/runs/background/completion-receipts.ts +309 -0
  666. package/src/runs/background/legacy-status-acceptance.ts +38 -0
  667. package/src/runs/background/notify.ts +167 -106
  668. package/src/runs/background/parallel-groups.ts +95 -46
  669. package/src/runs/background/result-payload.ts +268 -0
  670. package/src/runs/background/result-watcher.ts +484 -387
  671. package/src/runs/background/run-id-resolver.ts +126 -57
  672. package/src/runs/background/run-schemas.ts +240 -0
  673. package/src/runs/background/run-status-contracts.ts +46 -0
  674. package/src/runs/background/run-status-render.ts +364 -0
  675. package/src/runs/background/run-status.ts +338 -356
  676. package/src/runs/background/runner-attempt-output.ts +281 -0
  677. package/src/runs/background/runner-attempt.ts +354 -0
  678. package/src/runs/background/runner-child-executor.ts +232 -0
  679. package/src/runs/background/runner-child-observer.ts +270 -0
  680. package/src/runs/background/runner-completion-summary.ts +106 -0
  681. package/src/runs/background/runner-completion.ts +274 -0
  682. package/src/runs/background/runner-config.ts +52 -0
  683. package/src/runs/background/runner-contract.ts +51 -0
  684. package/src/runs/background/runner-dynamic.ts +185 -0
  685. package/src/runs/background/runner-finalization.ts +203 -0
  686. package/src/runs/background/runner-graph.ts +91 -0
  687. package/src/runs/background/runner-initial-status.ts +72 -0
  688. package/src/runs/background/runner-lifecycle.ts +159 -0
  689. package/src/runs/background/runner-monitor.ts +399 -0
  690. package/src/runs/background/runner-parallel.ts +280 -0
  691. package/src/runs/background/runner-prepare-step.ts +128 -0
  692. package/src/runs/background/runner-reporting.ts +192 -0
  693. package/src/runs/background/runner-status.ts +220 -0
  694. package/src/runs/background/runner-step-output.ts +158 -0
  695. package/src/runs/background/runner-step-record.ts +76 -0
  696. package/src/runs/background/runner-step.ts +150 -0
  697. package/src/runs/background/runner-streaming.ts +220 -0
  698. package/src/runs/background/runner-workflow.ts +284 -0
  699. package/src/runs/background/stale-run-reconciler.ts +279 -336
  700. package/src/runs/background/subagent-runner-launcher.ts +67 -35
  701. package/src/runs/background/subagent-runner.ts +80 -2048
  702. package/src/runs/background/top-level-async.ts +9 -7
  703. package/src/runs/foreground/chain-clarify.ts +499 -1334
  704. package/src/runs/foreground/clarification-draft.ts +92 -0
  705. package/src/runs/foreground/clarify-contracts.ts +33 -0
  706. package/src/runs/foreground/clarify-invocation.ts +192 -65
  707. package/src/runs/foreground/clarify-text-editor.ts +229 -0
  708. package/src/runs/foreground/clarify-view.ts +222 -0
  709. package/src/runs/foreground/execution-input.ts +358 -424
  710. package/src/runs/foreground/execution-routing.ts +41 -0
  711. package/src/runs/foreground/execution-timeout.ts +92 -0
  712. package/src/runs/foreground/foreground-control.ts +333 -812
  713. package/src/runs/foreground/foreground-memory.ts +132 -0
  714. package/src/runs/foreground/invocation-context.ts +88 -0
  715. package/src/runs/foreground/invocation-execution.ts +465 -0
  716. package/src/runs/foreground/invocation-expansion.ts +58 -0
  717. package/src/runs/foreground/management-actions.ts +360 -0
  718. package/src/runs/foreground/nested-control.ts +248 -0
  719. package/src/runs/foreground/question-continuation.ts +112 -0
  720. package/src/runs/foreground/question-control.ts +297 -70
  721. package/src/runs/foreground/resume-target.ts +330 -0
  722. package/src/runs/foreground/revival-launch-policy.ts +112 -0
  723. package/src/runs/foreground/run-async-path.ts +307 -223
  724. package/src/runs/foreground/run-interrupt.ts +202 -0
  725. package/src/runs/foreground/run-nudge.ts +355 -0
  726. package/src/runs/foreground/saved-revival.ts +356 -0
  727. package/src/runs/foreground/subagent-executor.ts +195 -493
  728. package/src/runs/foreground/subagent-params.ts +314 -242
  729. package/src/runs/foreground/wait-observation.ts +160 -0
  730. package/src/runs/foreground/wait-registration.ts +18 -0
  731. package/src/runs/foreground/wait-run.ts +361 -119
  732. package/src/runs/shared/acceptance-contract.ts +410 -209
  733. package/src/runs/shared/acceptance-defaults.ts +1 -0
  734. package/src/runs/shared/acceptance-evaluation.ts +314 -240
  735. package/src/runs/shared/acceptance-finalization.ts +447 -305
  736. package/src/runs/shared/acceptance-outcome.ts +69 -0
  737. package/src/runs/shared/acceptance-reports.ts +220 -126
  738. package/src/runs/shared/acceptance-submission.ts +251 -0
  739. package/src/runs/shared/acceptance-verification.ts +118 -0
  740. package/src/runs/shared/acceptance.ts +25 -25
  741. package/src/runs/shared/chain-outputs.ts +190 -98
  742. package/src/runs/shared/child-attempt-types.ts +118 -0
  743. package/src/runs/shared/child-attempt.ts +372 -608
  744. package/src/runs/shared/child-boundaries.ts +217 -0
  745. package/src/runs/shared/child-context-filter.ts +53 -0
  746. package/src/runs/shared/child-event-observer.ts +496 -0
  747. package/src/runs/shared/child-execution-cwd.ts +139 -68
  748. package/src/runs/shared/child-execution-outcome.ts +103 -0
  749. package/src/runs/shared/child-invocation.ts +74 -0
  750. package/src/runs/shared/child-message-validation.ts +233 -0
  751. package/src/runs/shared/child-native-accounting.ts +154 -0
  752. package/src/runs/shared/child-native-observation.ts +79 -0
  753. package/src/runs/shared/child-observation-spool.ts +188 -0
  754. package/src/runs/shared/child-observations.ts +219 -89
  755. package/src/runs/shared/child-presence.ts +6 -0
  756. package/src/runs/shared/child-route-env.ts +142 -0
  757. package/src/runs/shared/child-stream-observer.ts +302 -0
  758. package/src/runs/shared/child-stream-projection.ts +160 -0
  759. package/src/runs/shared/child-structured-tool.ts +38 -0
  760. package/src/runs/shared/claude-code.ts +201 -228
  761. package/src/runs/shared/claude-model.ts +67 -0
  762. package/src/runs/shared/claude-session.ts +124 -0
  763. package/src/runs/shared/claude-types.ts +31 -0
  764. package/src/runs/shared/completion-guard.ts +35 -26
  765. package/src/runs/shared/control-event-policy.ts +15 -0
  766. package/src/runs/shared/control-notification-owner.ts +20 -0
  767. package/src/runs/shared/dynamic-fanout.ts +402 -238
  768. package/src/runs/shared/dynamic-item.ts +114 -0
  769. package/src/runs/shared/history-index.ts +112 -51
  770. package/src/runs/shared/legacy-async-recovery.ts +153 -0
  771. package/src/runs/shared/legacy-output-recovery.ts +214 -0
  772. package/src/runs/shared/mcp-config-schema.ts +46 -0
  773. package/src/runs/shared/mcp-direct-tool-allowlist.ts +396 -307
  774. package/src/runs/shared/model-fallback.ts +302 -180
  775. package/src/runs/shared/mutating-tool-guard.ts +259 -158
  776. package/src/runs/shared/native-finalization-types.ts +29 -0
  777. package/src/runs/shared/native-finalization.ts +233 -109
  778. package/src/runs/shared/native-usage.ts +379 -96
  779. package/src/runs/shared/nested-control-records.ts +178 -0
  780. package/src/runs/shared/nested-events.ts +45 -752
  781. package/src/runs/shared/nested-path.ts +47 -34
  782. package/src/runs/shared/nested-projection.ts +230 -0
  783. package/src/runs/shared/nested-protocol.ts +67 -0
  784. package/src/runs/shared/nested-registry.ts +273 -0
  785. package/src/runs/shared/nested-render.ts +198 -100
  786. package/src/runs/shared/nested-route.ts +292 -0
  787. package/src/runs/shared/nested-validation.ts +291 -0
  788. package/src/runs/shared/owned-child-evidence.ts +184 -0
  789. package/src/runs/shared/owned-run-list.ts +187 -0
  790. package/src/runs/shared/owned-run-observation.ts +368 -0
  791. package/src/runs/shared/owned-run-progress.ts +172 -0
  792. package/src/runs/shared/owned-run-read-state.ts +7 -0
  793. package/src/runs/shared/owned-run-results.ts +289 -0
  794. package/src/runs/shared/owned-run-status.ts +239 -0
  795. package/src/runs/shared/owned-run-view.ts +65 -0
  796. package/src/runs/shared/owned-workflow-details.ts +24 -0
  797. package/src/runs/shared/owner-output.ts +73 -0
  798. package/src/runs/shared/parallel-utils.ts +93 -129
  799. package/src/runs/shared/parent-receipts.ts +177 -50
  800. package/src/runs/shared/parent-usage.ts +314 -91
  801. package/src/runs/shared/pi-args.ts +241 -311
  802. package/src/runs/shared/pi-launch-input.ts +48 -0
  803. package/src/runs/shared/pi-session-launch.ts +94 -0
  804. package/src/runs/shared/pi-spawn.ts +57 -33
  805. package/src/runs/shared/run-history-queries.ts +189 -38
  806. package/src/runs/shared/run-history.ts +197 -76
  807. package/src/runs/shared/run-id-ambiguity.ts +7 -3
  808. package/src/runs/shared/run-metadata-paths.ts +17 -0
  809. package/src/runs/shared/run-metadata.ts +240 -0
  810. package/src/runs/shared/run-persistence.ts +181 -0
  811. package/src/runs/shared/run-records.ts +19 -607
  812. package/src/runs/shared/run-restoration.ts +455 -0
  813. package/src/runs/shared/run-state-owner.ts +31 -0
  814. package/src/runs/shared/session-cwd-preload.ts +39 -19
  815. package/src/runs/shared/single-output.ts +358 -205
  816. package/src/runs/shared/stable-value.ts +15 -0
  817. package/src/runs/shared/streaming-text.ts +39 -12
  818. package/src/runs/shared/structured-output.ts +76 -46
  819. package/src/runs/shared/subagent-control.ts +330 -197
  820. package/src/runs/shared/subagent-prompt-runtime.ts +92 -174
  821. package/src/runs/shared/subagent-tool-loop-guard.ts +118 -68
  822. package/src/runs/shared/supervisor-question-state.ts +221 -0
  823. package/src/runs/shared/supervisor-questions.ts +396 -401
  824. package/src/runs/shared/workflow-graph.ts +400 -198
  825. package/src/runs/shared/workflow-policy.ts +245 -110
  826. package/src/runs/shared/worktree-contract.ts +29 -0
  827. package/src/runs/shared/worktree-hook.ts +181 -0
  828. package/src/runs/shared/worktree-location.ts +61 -0
  829. package/src/runs/shared/worktree-preservation.ts +10 -0
  830. package/src/runs/shared/worktree-process.ts +132 -0
  831. package/src/runs/shared/worktree.ts +459 -587
  832. package/src/shared/agent-context-policy.ts +176 -145
  833. package/src/shared/agent-dir.ts +15 -0
  834. package/src/shared/artifacts.ts +99 -68
  835. package/src/shared/atomic-json.ts +14 -11
  836. package/src/shared/chain-files.ts +72 -0
  837. package/src/shared/concurrency.ts +27 -0
  838. package/src/shared/content-preview.ts +117 -0
  839. package/src/shared/cooperative.ts +17 -13
  840. package/src/shared/execution-cwd.ts +34 -9
  841. package/src/shared/file-coalescer.ts +24 -22
  842. package/src/shared/fork-context.ts +52 -48
  843. package/src/shared/formatters.ts +88 -47
  844. package/src/shared/journal-frames.ts +197 -0
  845. package/src/shared/journal-projections.ts +133 -0
  846. package/src/shared/journal-reader.ts +18 -333
  847. package/src/shared/json-projection.ts +224 -0
  848. package/src/shared/lazy-tools.ts +76 -27
  849. package/src/shared/message-output.ts +146 -0
  850. package/src/shared/model-info.ts +94 -58
  851. package/src/shared/native-import.ts +25 -0
  852. package/src/shared/native-journal.ts +172 -0
  853. package/src/shared/native-session.ts +8 -3
  854. package/src/shared/native-tui.ts +13 -3
  855. package/src/shared/native-typebox.ts +18 -3
  856. package/src/shared/output-page.ts +76 -0
  857. package/src/shared/post-exit-stdio-guard.ts +232 -172
  858. package/src/shared/prompt-sections.ts +13 -7
  859. package/src/shared/session-entries.ts +103 -44
  860. package/src/shared/session-identity.ts +17 -10
  861. package/src/shared/settings.ts +182 -367
  862. package/src/shared/status-format.ts +207 -98
  863. package/src/shared/stream-json.d.ts +10 -0
  864. package/src/shared/task-file-policy.ts +35 -0
  865. package/src/shared/temp-root.ts +122 -71
  866. package/src/shared/types/acceptance.ts +149 -0
  867. package/src/shared/types/async.ts +247 -0
  868. package/src/shared/types/config.ts +139 -0
  869. package/src/shared/types/details.ts +104 -0
  870. package/src/shared/types/history.ts +217 -0
  871. package/src/shared/types/inputs.ts +4 -0
  872. package/src/shared/types/intercom.ts +57 -0
  873. package/src/shared/types/launch.ts +39 -0
  874. package/src/shared/types/messages.ts +104 -0
  875. package/src/shared/types/nested.ts +153 -0
  876. package/src/shared/types/owned-runs.ts +148 -0
  877. package/src/shared/types/progress.ts +106 -0
  878. package/src/shared/types/questions.ts +103 -0
  879. package/src/shared/types/results.ts +119 -0
  880. package/src/shared/types/state.ts +56 -0
  881. package/src/shared/types/usage.ts +36 -0
  882. package/src/shared/types/workflow.ts +187 -0
  883. package/src/shared/types.ts +222 -1161
  884. package/src/shared/ui-mode.ts +1 -1
  885. package/src/shared/unknown.ts +59 -0
  886. package/src/shared/utils.ts +111 -305
  887. package/src/slash/command-discovery.ts +109 -0
  888. package/src/slash/command-input.ts +232 -0
  889. package/src/slash/prompt-template-bridge.ts +153 -400
  890. package/src/slash/prompt-template-contract.ts +152 -0
  891. package/src/slash/prompt-template-results.ts +189 -0
  892. package/src/slash/request-protocol.ts +87 -0
  893. package/src/slash/result-delivery.ts +312 -0
  894. package/src/slash/saved-chain.ts +115 -0
  895. package/src/slash/slash-bridge.ts +202 -156
  896. package/src/slash/slash-commands.ts +176 -598
  897. package/src/slash/slash-live-state.ts +287 -229
  898. package/src/tui/action-hints.ts +147 -61
  899. package/src/tui/activity-lines.ts +40 -0
  900. package/src/tui/agent-browser.ts +354 -0
  901. package/src/tui/agent-controls.ts +355 -0
  902. package/src/tui/agent-conversation.ts +514 -0
  903. package/src/tui/agent-dock.ts +250 -0
  904. package/src/tui/agent-history.ts +78 -203
  905. package/src/tui/agent-model.ts +78 -0
  906. package/src/tui/agent-picker.ts +325 -0
  907. package/src/tui/agent-view.ts +391 -1333
  908. package/src/tui/compact-results.ts +342 -0
  909. package/src/tui/conversation-details.ts +206 -0
  910. package/src/tui/conversation-frame.ts +184 -0
  911. package/src/tui/conversation-history.ts +246 -0
  912. package/src/tui/conversation-menu.ts +119 -0
  913. package/src/tui/conversation-notices.ts +116 -0
  914. package/src/tui/conversation-selection.ts +66 -0
  915. package/src/tui/conversation-viewport.ts +169 -0
  916. package/src/tui/direction-message.ts +35 -0
  917. package/src/tui/display.ts +409 -0
  918. package/src/tui/editor-viewport.ts +19 -0
  919. package/src/tui/expanded-content.ts +134 -0
  920. package/src/tui/expanded-multi.ts +264 -0
  921. package/src/tui/expanded-single.ts +92 -0
  922. package/src/tui/history-cards.ts +316 -0
  923. package/src/tui/history-display.ts +334 -0
  924. package/src/tui/history-json.ts +17 -0
  925. package/src/tui/history-metadata.ts +177 -0
  926. package/src/tui/history-record.ts +321 -0
  927. package/src/tui/history-text.ts +34 -0
  928. package/src/tui/indexed-history.ts +149 -0
  929. package/src/tui/nested-widget.ts +192 -0
  930. package/src/tui/picker-page.ts +80 -0
  931. package/src/tui/render.ts +100 -1546
  932. package/src/tui/result-facts.ts +99 -0
  933. package/src/tui/task-observation.ts +96 -0
  934. package/src/tui/task-store.ts +432 -0
  935. package/src/tui/text-values.ts +20 -0
  936. package/src/tui/view-connections.ts +64 -0
  937. package/src/tui/view-model.ts +181 -0
  938. package/src/tui/view-persistence.ts +57 -0
  939. package/src/tui/view-ports.ts +55 -0
  940. package/src/tui/view-session.ts +42 -0
  941. package/src/tui/widget-details.ts +220 -0
  942. package/src/tui/widget-status.ts +331 -0
  943. package/src/tui/widget.ts +208 -0
  944. package/src/tui/workflow-labels.ts +340 -0
  945. package/src/tui/workflow-outcomes.ts +150 -0
  946. package/tsconfig.build.json +11 -10
  947. 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 };