@selesai/code 0.13.15 → 0.13.18

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 (473) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/README.md +2 -14
  3. package/dist/bun/cli.d.ts +3 -1
  4. package/dist/bun/cli.js +3 -9
  5. package/dist/bun/{register-bedrock.js → runtime-setup.js} +5 -0
  6. package/dist/bun/sandbox-env-setup.d.ts +1 -0
  7. package/dist/bun/sandbox-env-setup.js +3 -0
  8. package/dist/cli/auth-command.d.ts +23 -0
  9. package/dist/cli/auth-command.js +102 -0
  10. package/dist/cli/config-selector.js +2 -1
  11. package/dist/cli/setup.d.ts +1 -0
  12. package/dist/cli/setup.js +11 -0
  13. package/dist/cli.js +2 -14
  14. package/dist/config.d.ts +3 -2
  15. package/dist/config.js +9 -4
  16. package/dist/core/agent-session-runtime.js +15 -7
  17. package/dist/core/agent-session.d.ts +2 -6
  18. package/dist/core/agent-session.js +15 -4
  19. package/dist/core/compaction/branch-summarization.d.ts +1 -1
  20. package/dist/core/compaction/branch-summarization.js +2 -1
  21. package/dist/core/extensions/loader.js +3 -0
  22. package/dist/core/extensions/types.d.ts +16 -2
  23. package/dist/core/http-dispatcher.js +2 -0
  24. package/dist/core/keybindings.d.ts +5 -0
  25. package/dist/core/keybindings.js +4 -0
  26. package/dist/core/messages.d.ts +1 -1
  27. package/dist/core/model-config.d.ts +15 -0
  28. package/dist/core/model-config.js +3 -0
  29. package/dist/core/model-runtime.d.ts +1 -0
  30. package/dist/core/model-runtime.js +5 -2
  31. package/dist/core/provider-composer.js +8 -2
  32. package/dist/core/session-export.d.ts +3 -0
  33. package/dist/core/session-export.js +31 -0
  34. package/dist/core/session-manager.d.ts +3 -2
  35. package/dist/core/session-manager.js +40 -13
  36. package/dist/core/skills.d.ts +1 -1
  37. package/dist/core/skills.js +4 -2
  38. package/dist/core/system-prompt.js +10 -10
  39. package/dist/core/tools/bash.js +3 -117
  40. package/dist/core/tools/edit.d.ts +1 -12
  41. package/dist/core/tools/edit.js +5 -163
  42. package/dist/core/tools/find.js +4 -55
  43. package/dist/core/tools/grep.js +4 -60
  44. package/dist/core/tools/ls.js +4 -49
  45. package/dist/core/tools/read.d.ts +4 -0
  46. package/dist/core/tools/read.js +10 -122
  47. package/dist/core/tools/renderers/bash.d.ts +11 -0
  48. package/dist/core/tools/renderers/bash.js +129 -0
  49. package/dist/core/tools/renderers/edit.d.ts +22 -0
  50. package/dist/core/tools/renderers/edit.js +166 -0
  51. package/dist/core/tools/renderers/find.d.ts +9 -0
  52. package/dist/core/tools/renderers/find.js +63 -0
  53. package/dist/core/tools/renderers/grep.d.ts +9 -0
  54. package/dist/core/tools/renderers/grep.js +68 -0
  55. package/dist/core/tools/renderers/index.d.ts +27 -0
  56. package/dist/core/tools/renderers/index.js +46 -0
  57. package/dist/core/tools/renderers/ls.d.ts +9 -0
  58. package/dist/core/tools/renderers/ls.js +57 -0
  59. package/dist/core/tools/renderers/read.d.ts +10 -0
  60. package/dist/core/tools/renderers/read.js +128 -0
  61. package/dist/core/tools/renderers/write.d.ts +9 -0
  62. package/dist/core/tools/renderers/write.js +152 -0
  63. package/dist/core/tools/write.js +5 -146
  64. package/dist/extensions/capability-gateway/index.ts +12 -1
  65. package/dist/extensions/capability-gateway/integration.test.ts +23 -0
  66. package/dist/extensions/pi-hermes-memory/CHANGELOG.md +18 -0
  67. package/dist/extensions/pi-hermes-memory/README.md +16 -12
  68. package/dist/extensions/pi-hermes-memory/docs/ROADMAP.md +1 -1
  69. package/dist/extensions/pi-hermes-memory/package-lock.json +587 -62
  70. package/dist/extensions/pi-hermes-memory/package.json +4 -4
  71. package/dist/extensions/pi-hermes-memory/src/config.ts +32 -0
  72. package/dist/extensions/pi-hermes-memory/src/constants.ts +12 -2
  73. package/dist/extensions/pi-hermes-memory/src/handlers/background-review.ts +109 -51
  74. package/dist/extensions/pi-hermes-memory/src/handlers/index-sessions.ts +9 -3
  75. package/dist/extensions/pi-hermes-memory/src/handlers/review-memory-ops.ts +257 -98
  76. package/dist/extensions/pi-hermes-memory/src/handlers/session-backfill.ts +9 -2
  77. package/dist/extensions/pi-hermes-memory/src/handlers/sync-markdown-memories.ts +5 -0
  78. package/dist/extensions/pi-hermes-memory/src/index.ts +22 -2
  79. package/dist/extensions/pi-hermes-memory/src/paths.ts +1 -1
  80. package/dist/extensions/pi-hermes-memory/src/store/db.ts +6 -0
  81. package/dist/extensions/pi-hermes-memory/src/store/fts-query.ts +58 -1
  82. package/dist/extensions/pi-hermes-memory/src/store/memory-store.ts +60 -8
  83. package/dist/extensions/pi-hermes-memory/src/store/session-indexer.ts +169 -7
  84. package/dist/extensions/pi-hermes-memory/src/store/session-search.ts +7 -21
  85. package/dist/extensions/pi-hermes-memory/src/store/sqlite-memory-store.ts +134 -15
  86. package/dist/extensions/pi-hermes-memory/src/tools/memory-search-tool.ts +4 -2
  87. package/dist/extensions/pi-hermes-memory/src/tools/memory-tool.ts +24 -9
  88. package/dist/extensions/pi-hermes-memory/src/types.ts +11 -0
  89. package/dist/extensions/pi-hermes-memory/tests/config.test.ts +42 -0
  90. package/dist/extensions/pi-hermes-memory/tests/handlers/background-review.test.ts +159 -3
  91. package/dist/extensions/pi-hermes-memory/tests/handlers/review-memory-ops.test.ts +452 -0
  92. package/dist/extensions/pi-hermes-memory/tests/handlers/session-backfill.test.ts +39 -0
  93. package/dist/extensions/pi-hermes-memory/tests/integration/corruption-recovery-integration.test.ts +91 -0
  94. package/dist/extensions/pi-hermes-memory/tests/store/db.test.ts +29 -0
  95. package/dist/extensions/pi-hermes-memory/tests/store/fts-query.test.ts +116 -0
  96. package/dist/extensions/pi-hermes-memory/tests/store/memory-store.test.ts +163 -0
  97. package/dist/extensions/pi-hermes-memory/tests/store/session-indexer.test.ts +233 -0
  98. package/dist/extensions/pi-hermes-memory/tests/store/session-search.test.ts +12 -0
  99. package/dist/extensions/pi-hermes-memory/tests/store/sqlite-memory-store.test.ts +175 -0
  100. package/dist/extensions/pi-hermes-memory/tests/store/sqlite-native.test.ts +2 -2
  101. package/dist/extensions/pi-hermes-memory/tests/tools/memory-search-tool.test.ts +22 -0
  102. package/dist/extensions/pi-hermes-memory/tests/tools/memory-tool.test.ts +37 -1
  103. package/dist/extensions/pi-intercom/CHANGELOG.md +13 -0
  104. package/dist/extensions/pi-intercom/README.md +16 -2
  105. package/dist/extensions/pi-intercom/broker/spawn.test.ts +19 -2
  106. package/dist/extensions/pi-intercom/broker/spawn.ts +4 -4
  107. package/dist/extensions/pi-intercom/index.ts +1 -1
  108. package/dist/extensions/pi-intercom/intercom.integration.test.ts +121 -2
  109. package/dist/extensions/pi-intercom/package.json +1 -1
  110. package/dist/extensions/pi-intercom/project-agent.test.ts +1 -1
  111. package/dist/extensions/pi-intercom/project-agent.ts +1 -6
  112. package/dist/extensions/pi-intercom/skills/pi-intercom/SKILL.md +7 -6
  113. package/dist/extensions/pi-rewind-hook/index.test.ts +7 -0
  114. package/dist/extensions/pi-subagents/.github/workflows/test.yml +36 -4
  115. package/dist/extensions/pi-subagents/CHANGELOG.md +120 -0
  116. package/dist/extensions/pi-subagents/README.md +3 -3
  117. package/dist/extensions/pi-subagents/agents/researcher.md +23 -13
  118. package/dist/extensions/pi-subagents/agents/reviewer.md +1 -1
  119. package/dist/extensions/pi-subagents/agents/scout.md +1 -1
  120. package/dist/extensions/pi-subagents/docs/agents.md +32 -16
  121. package/dist/extensions/pi-subagents/docs/configuration.md +41 -15
  122. package/dist/extensions/pi-subagents/docs/extension-api.md +109 -6
  123. package/dist/extensions/pi-subagents/docs/missions.md +2 -0
  124. package/dist/extensions/pi-subagents/docs/models.md +58 -1
  125. package/dist/extensions/pi-subagents/docs/observability.md +50 -12
  126. package/dist/extensions/pi-subagents/docs/tool-reference.md +17 -10
  127. package/dist/extensions/pi-subagents/docs/watchdog.md +1 -1
  128. package/dist/extensions/pi-subagents/docs/workflows.md +26 -9
  129. package/dist/extensions/pi-subagents/package-lock.json +747 -177
  130. package/dist/extensions/pi-subagents/package.json +6 -4
  131. package/dist/extensions/pi-subagents/runner-server-preload.mjs +13 -0
  132. package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +2 -1
  133. package/dist/extensions/pi-subagents/skills/pi-subagents/references/constraints-and-recipes.md +1 -1
  134. package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +21 -4
  135. package/dist/extensions/pi-subagents/skills/pi-subagents/references/management-authoring-rpc.md +2 -1
  136. package/dist/extensions/pi-subagents/skills/pi-subagents/references/multi-lane-orchestration.md +2 -0
  137. package/dist/extensions/pi-subagents/src/agents/advertised-agent-prompt.ts +63 -0
  138. package/dist/extensions/pi-subagents/src/agents/agent-management.ts +61 -16
  139. package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +2 -0
  140. package/dist/extensions/pi-subagents/src/agents/agents.ts +8 -0
  141. package/dist/extensions/pi-subagents/src/api/capability-ceiling.ts +0 -1
  142. package/dist/extensions/pi-subagents/src/api/{pi-args.ts → child-tool-plan.ts} +1 -1
  143. package/dist/extensions/pi-subagents/src/api/preflight.ts +7 -4
  144. package/dist/extensions/pi-subagents/src/api/shared-types.ts +2 -2
  145. package/dist/extensions/pi-subagents/src/api/workflow-resources.ts +6 -0
  146. package/dist/extensions/pi-subagents/src/extension/config.ts +4 -2
  147. package/dist/extensions/pi-subagents/src/extension/doctor.ts +2 -10
  148. package/dist/extensions/pi-subagents/src/extension/fanout-child.ts +9 -11
  149. package/dist/extensions/pi-subagents/src/extension/index.ts +99 -10
  150. package/dist/extensions/pi-subagents/src/extension/public-execution.ts +13 -0
  151. package/dist/extensions/pi-subagents/src/extension/rpc.ts +7 -23
  152. package/dist/extensions/pi-subagents/src/extension/schemas.ts +11 -8
  153. package/dist/extensions/pi-subagents/src/extension/tool-description.ts +25 -7
  154. package/dist/extensions/pi-subagents/src/integrations/pi-web-session-liveness.ts +73 -0
  155. package/dist/extensions/pi-subagents/src/intercom/native-supervisor-channel.ts +228 -136
  156. package/dist/extensions/pi-subagents/src/intercom/supervisor-ui.ts +244 -0
  157. package/dist/extensions/pi-subagents/src/missions/workflow-state.ts +37 -16
  158. package/dist/extensions/pi-subagents/src/runs/background/active-async-capacity.ts +18 -18
  159. package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +51 -25
  160. package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +46 -3
  161. package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +14 -3
  162. package/dist/extensions/pi-subagents/src/runs/background/async-retention.ts +9 -0
  163. package/dist/extensions/pi-subagents/src/runs/background/async-status-snapshot.ts +10 -12
  164. package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +18 -15
  165. package/dist/extensions/pi-subagents/src/runs/background/auto-drain.ts +40 -29
  166. package/dist/extensions/pi-subagents/src/runs/background/chain-root-attachment.ts +8 -0
  167. package/dist/extensions/pi-subagents/src/runs/background/control-channel.ts +79 -247
  168. package/dist/extensions/pi-subagents/src/runs/background/notify.ts +88 -12
  169. package/dist/extensions/pi-subagents/src/runs/background/owned-process-tree.ts +6 -6
  170. package/dist/extensions/pi-subagents/src/runs/background/process-terminal.ts +24 -24
  171. package/dist/extensions/pi-subagents/src/runs/background/retained-nested-route-tracker.ts +96 -0
  172. package/dist/extensions/pi-subagents/src/runs/background/run-child-session.ts +642 -0
  173. package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +75 -6
  174. package/dist/extensions/pi-subagents/src/runs/background/runner-aliases.ts +163 -0
  175. package/dist/extensions/pi-subagents/src/runs/background/runner-child-launch.ts +86 -0
  176. package/dist/extensions/pi-subagents/src/runs/background/runner-child-sessions.ts +31 -0
  177. package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +18 -4
  178. package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +3 -1
  179. package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +597 -1092
  180. package/dist/extensions/pi-subagents/src/runs/background/subagent-wait.ts +3 -0
  181. package/dist/extensions/pi-subagents/src/runs/background/wait-completions.ts +4 -0
  182. package/dist/extensions/pi-subagents/src/runs/foreground/async-steering-action.ts +20 -17
  183. package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +296 -394
  184. package/dist/extensions/pi-subagents/src/runs/foreground/foreground-control.ts +4 -0
  185. package/dist/extensions/pi-subagents/src/runs/foreground/foreground-history.ts +3 -1
  186. package/dist/extensions/pi-subagents/src/runs/foreground/prompt-audit.ts +9 -5
  187. package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +630 -283
  188. package/dist/extensions/pi-subagents/src/runs/foreground/workflow-detach-reconcile.ts +8 -5
  189. package/dist/extensions/pi-subagents/src/runs/foreground/workflow-foreground-steering.ts +78 -98
  190. package/dist/extensions/pi-subagents/src/runs/shared/abort-recovery.ts +3 -3
  191. package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +16 -3
  192. package/dist/extensions/pi-subagents/src/runs/shared/agent-contract.ts +1 -1
  193. package/dist/extensions/pi-subagents/src/runs/shared/async-status-projection.ts +47 -47
  194. package/dist/extensions/pi-subagents/src/runs/shared/capability-ceiling.ts +1 -2
  195. package/dist/extensions/pi-subagents/src/runs/shared/child-hooks.ts +174 -0
  196. package/dist/extensions/pi-subagents/src/runs/shared/child-identity.ts +14 -3
  197. package/dist/extensions/pi-subagents/src/runs/shared/child-launch.ts +319 -0
  198. package/dist/extensions/pi-subagents/src/runs/shared/child-lifecycle.ts +25 -0
  199. package/dist/extensions/pi-subagents/src/runs/shared/child-runtime-config.ts +126 -0
  200. package/dist/extensions/pi-subagents/src/runs/shared/child-session.ts +373 -0
  201. package/dist/extensions/pi-subagents/src/runs/shared/child-tool-plan.ts +530 -0
  202. package/dist/extensions/pi-subagents/src/runs/shared/completion-evidence.ts +2 -2
  203. package/dist/extensions/pi-subagents/src/runs/shared/completion-guard.ts +2 -1
  204. package/dist/extensions/pi-subagents/src/runs/shared/external-cli-preflight.ts +16 -0
  205. package/dist/extensions/pi-subagents/src/runs/shared/host-step-status.ts +11 -11
  206. package/dist/extensions/pi-subagents/src/runs/shared/llm-intent-arbiter.ts +30 -20
  207. package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +5 -4
  208. package/dist/extensions/pi-subagents/src/runs/shared/model-exclusions.ts +84 -15
  209. package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +88 -12
  210. package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +37 -53
  211. package/dist/extensions/pi-subagents/src/runs/shared/nested-path.ts +1 -1
  212. package/dist/extensions/pi-subagents/src/runs/shared/orca-progress-tabs.ts +18 -7
  213. package/dist/extensions/pi-subagents/src/runs/shared/parallel-handoff.ts +57 -12
  214. package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +3 -4
  215. package/dist/extensions/pi-subagents/src/runs/shared/permissions.ts +0 -11
  216. package/dist/extensions/pi-subagents/src/runs/shared/process-signal.ts +4 -1
  217. package/dist/extensions/pi-subagents/src/runs/shared/readonly-drain-observation.ts +42 -0
  218. package/dist/extensions/pi-subagents/src/runs/shared/readonly-model-continuation.ts +69 -0
  219. package/dist/extensions/pi-subagents/src/runs/shared/readonly-session-evidence.ts +307 -0
  220. package/dist/extensions/pi-subagents/src/runs/shared/run-fanout-budget.ts +8 -21
  221. package/dist/extensions/pi-subagents/src/runs/shared/runtime-acknowledged-extensions.ts +3 -30
  222. package/dist/extensions/pi-subagents/src/runs/shared/structured-output.ts +17 -4
  223. package/dist/extensions/pi-subagents/src/runs/shared/subagent-control.ts +2 -0
  224. package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +99 -386
  225. package/dist/extensions/pi-subagents/src/runs/shared/tool-availability.ts +18 -62
  226. package/dist/extensions/pi-subagents/src/runs/shared/tool-budget.ts +0 -14
  227. package/dist/extensions/pi-subagents/src/runs/shared/worktree-cleanup-plan.ts +31 -9
  228. package/dist/extensions/pi-subagents/src/runs/shared/worktree-setup-command.ts +190 -0
  229. package/dist/extensions/pi-subagents/src/runs/shared/worktree.ts +506 -226
  230. package/dist/extensions/pi-subagents/src/shared/child-session-name.ts +1 -1
  231. package/dist/extensions/pi-subagents/src/shared/jsonl-writer.ts +11 -0
  232. package/dist/extensions/pi-subagents/src/shared/model-response-aliases.ts +13 -0
  233. package/dist/extensions/pi-subagents/src/shared/thinking-ceiling.ts +0 -6
  234. package/dist/extensions/pi-subagents/src/shared/types.ts +145 -89
  235. package/dist/extensions/pi-subagents/src/shared/utils.ts +13 -6
  236. package/dist/extensions/pi-subagents/src/shared/watch-strategy.ts +2 -0
  237. package/dist/extensions/pi-subagents/src/shared/workflow-child-permit.ts +18 -13
  238. package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +0 -6
  239. package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +1 -1
  240. package/dist/extensions/pi-subagents/src/tui/fleet.ts +11 -6
  241. package/dist/extensions/pi-subagents/src/tui/render.ts +277 -46
  242. package/dist/extensions/pi-subagents/src/watchdog/child-status.ts +0 -1
  243. package/dist/extensions/pi-subagents/src/watchdog/register-child.ts +12 -12
  244. package/dist/extensions/pi-subagents/src/workflows/chat-progress.ts +3 -3
  245. package/dist/extensions/pi-subagents/src/workflows/scripted-workflow.ts +116 -15
  246. package/dist/extensions/pi-subagents/src/workflows/workflow-checklist.ts +15 -18
  247. package/dist/extensions/pi-subagents/src/workflows/workflow-child-summary.ts +57 -8
  248. package/dist/extensions/pi-subagents/src/workflows/workflow-preflight.ts +19 -19
  249. package/dist/extensions/pi-subagents/src/workflows/workflow-receipt.ts +3 -3
  250. package/dist/extensions/pi-subagents/src/workflows/workflow-resources.ts +97 -22
  251. package/dist/extensions/pi-subagents/src/workflows/workflow-settlement.ts +3 -0
  252. package/dist/extensions/pi-subagents/test/integration/acceptance-file-report.test.ts +336 -21
  253. package/dist/extensions/pi-subagents/test/integration/async-execution.part-1.test.ts +1181 -0
  254. package/dist/extensions/pi-subagents/test/integration/async-execution.part-2.test.ts +2240 -0
  255. package/dist/extensions/pi-subagents/test/integration/async-execution.part-3.test.ts +2268 -0
  256. package/dist/extensions/pi-subagents/test/integration/async-execution.part-4.test.ts +1512 -0
  257. package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +231 -16
  258. package/dist/extensions/pi-subagents/test/integration/error-handling.test.ts +4 -18
  259. package/dist/extensions/pi-subagents/test/integration/foreign-workflow-steering.test.ts +95 -0
  260. package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +9 -15
  261. package/dist/extensions/pi-subagents/test/integration/in-process-child.test.ts +374 -0
  262. package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +20 -10
  263. package/dist/extensions/pi-subagents/test/integration/orca-progress-tabs.test.ts +18 -6
  264. package/dist/extensions/pi-subagents/test/integration/recovered-assistant-error.test.ts +151 -0
  265. package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +42 -1
  266. package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +150 -25
  267. package/dist/extensions/pi-subagents/test/integration/result-publication.test.ts +354 -0
  268. package/dist/extensions/pi-subagents/test/integration/shared-cwd-terminal-evidence.test.ts +117 -0
  269. package/dist/extensions/pi-subagents/test/integration/single-execution.part-1.test.ts +3678 -0
  270. package/dist/extensions/pi-subagents/test/integration/{single-execution.test.ts → single-execution.part-2.test.ts} +500 -4207
  271. package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +1 -2
  272. package/dist/extensions/pi-subagents/test/integration/workflow-result-publication.test.ts +127 -0
  273. package/dist/extensions/pi-subagents/test/integration/workflow-steer-inbox.test.ts +365 -0
  274. package/dist/extensions/pi-subagents/test/smoke/pi085-child.ts +31 -0
  275. package/dist/extensions/pi-subagents/test/smoke/pi085-clean-install.mjs +74 -0
  276. package/dist/extensions/pi-subagents/test/smoke/pi085-extension.ts +16 -0
  277. package/dist/extensions/pi-subagents/test/support/async-execution-fixture.ts +699 -0
  278. package/dist/extensions/pi-subagents/test/support/fake-child-session.ts +418 -0
  279. package/dist/extensions/pi-subagents/test/support/foreign-workflow-steer-host.mjs +13 -0
  280. package/dist/extensions/pi-subagents/test/support/mock-pi.ts +30 -76
  281. package/dist/extensions/pi-subagents/test/support/notify-diagnostics-fixture.ts +84 -0
  282. package/dist/extensions/pi-subagents/test/support/result-publication-capacity-preload.mjs +70 -0
  283. package/dist/extensions/pi-subagents/test/support/runner-child-session-factory.ts +17 -0
  284. package/dist/extensions/pi-subagents/test/support/single-execution-fixture.ts +390 -0
  285. package/dist/extensions/pi-subagents/test/unit/acceptance-compaction.test.ts +120 -0
  286. package/dist/extensions/pi-subagents/test/unit/acceptance.test.ts +24 -3
  287. package/dist/extensions/pi-subagents/test/unit/advertised-agent-prompt.test.ts +87 -0
  288. package/dist/extensions/pi-subagents/test/unit/advertised-agent-refresh.test.ts +163 -0
  289. package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +70 -31
  290. package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +78 -3
  291. package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +2 -8
  292. package/dist/extensions/pi-subagents/test/unit/async-execution.test.ts +1 -1
  293. package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +73 -66
  294. package/dist/extensions/pi-subagents/test/unit/async-recovery-descriptor.test.ts +51 -1
  295. package/dist/extensions/pi-subagents/test/unit/async-retention.test.ts +49 -1
  296. package/dist/extensions/pi-subagents/test/unit/async-spawn-preload.test.ts +103 -0
  297. package/dist/extensions/pi-subagents/test/unit/async-status-projection.test.ts +3 -3
  298. package/dist/extensions/pi-subagents/test/unit/capability-ceiling-agent-allowlist.test.ts +9 -8
  299. package/dist/extensions/pi-subagents/test/unit/capability-ceiling.test.ts +10 -7
  300. package/dist/extensions/pi-subagents/test/unit/chain-root-attachment.test.ts +48 -6
  301. package/dist/extensions/pi-subagents/test/unit/child-runtime-config.test.ts +90 -0
  302. package/dist/extensions/pi-subagents/test/unit/{pi-args-permission-system.test.ts → child-tool-plan-permission-system.test.ts} +48 -86
  303. package/dist/extensions/pi-subagents/test/unit/child-tool-plan.test.ts +33 -0
  304. package/dist/extensions/pi-subagents/test/unit/compaction-resume.test.ts +18 -18
  305. package/dist/extensions/pi-subagents/test/unit/completion-evidence.test.ts +9 -9
  306. package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +8 -7
  307. package/dist/extensions/pi-subagents/test/unit/control-channel.test.ts +225 -65
  308. package/dist/extensions/pi-subagents/test/unit/extension-bindings.test.ts +17 -22
  309. package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +11 -1
  310. package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +47 -3
  311. package/dist/extensions/pi-subagents/test/unit/foreign-workflow-steering.test.ts +74 -0
  312. package/dist/extensions/pi-subagents/test/unit/fork-cache-key.test.ts +23 -29
  313. package/dist/extensions/pi-subagents/test/unit/host-peer-runtime-imports.test.ts +96 -4
  314. package/dist/extensions/pi-subagents/test/unit/host-step-status.test.ts +4 -4
  315. package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +116 -55
  316. package/dist/extensions/pi-subagents/test/unit/index-segment.test.ts +58 -1
  317. package/dist/extensions/pi-subagents/test/unit/llm-intent-arbiter.test.ts +104 -3
  318. package/dist/extensions/pi-subagents/test/unit/mission-lifecycle.test.ts +10 -1
  319. package/dist/extensions/pi-subagents/test/unit/mission-store.test.ts +31 -1
  320. package/dist/extensions/pi-subagents/test/unit/model-exclusions.test.ts +102 -51
  321. package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +196 -6
  322. package/dist/extensions/pi-subagents/test/unit/native-supervisor-channel.test.ts +181 -38
  323. package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +62 -70
  324. package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +58 -53
  325. package/dist/extensions/pi-subagents/test/unit/notify-diagnostics.test.ts +42 -0
  326. package/dist/extensions/pi-subagents/test/unit/notify.test.ts +84 -0
  327. package/dist/extensions/pi-subagents/test/unit/orca-progress-tabs.test.ts +13 -5
  328. package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +21 -5
  329. package/dist/extensions/pi-subagents/test/unit/parallel-handoff.test.ts +5 -4
  330. package/dist/extensions/pi-subagents/test/unit/permissions.test.ts +2 -6
  331. package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +28 -2
  332. package/dist/extensions/pi-subagents/test/unit/pi-web-session-liveness.test.ts +209 -0
  333. package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +38 -1
  334. package/dist/extensions/pi-subagents/test/unit/prompt-audit-optional-peers.test.ts +43 -0
  335. package/dist/extensions/pi-subagents/test/unit/public-execution.test.ts +24 -2
  336. package/dist/extensions/pi-subagents/test/unit/readonly-drain-observation.test.ts +174 -0
  337. package/dist/extensions/pi-subagents/test/unit/readonly-model-continuation.test.ts +94 -0
  338. package/dist/extensions/pi-subagents/test/unit/readonly-session-evidence.test.ts +1329 -0
  339. package/dist/extensions/pi-subagents/test/unit/recursion-guard.test.ts +29 -80
  340. package/dist/extensions/pi-subagents/test/unit/render-helpers.test.ts +11 -8
  341. package/dist/extensions/pi-subagents/test/unit/result-files.test.ts +2 -2
  342. package/dist/extensions/pi-subagents/test/unit/retained-nested-route-tracker.test.ts +175 -0
  343. package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +38 -12
  344. package/dist/extensions/pi-subagents/test/unit/run-fanout-budget.test.ts +2 -5
  345. package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +89 -1
  346. package/dist/extensions/pi-subagents/test/unit/runtime-acknowledged-extensions.test.ts +2 -16
  347. package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +27 -3
  348. package/dist/extensions/pi-subagents/test/unit/scheduled-supervisor-demand.test.ts +215 -0
  349. package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +15 -11
  350. package/dist/extensions/pi-subagents/test/unit/scripted-workflow.test.ts +237 -1
  351. package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +2 -5
  352. package/dist/extensions/pi-subagents/test/unit/streamed-progress-bounds.test.ts +2 -2
  353. package/dist/extensions/pi-subagents/test/unit/subagent-guide.test.ts +14 -1
  354. package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +130 -739
  355. package/dist/extensions/pi-subagents/test/unit/supervisor-ask-registration.test.ts +682 -0
  356. package/dist/extensions/pi-subagents/test/unit/supervisor-ui.test.ts +137 -0
  357. package/dist/extensions/pi-subagents/test/unit/tool-budget.test.ts +1 -11
  358. package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +23 -3
  359. package/dist/extensions/pi-subagents/test/unit/wait-completions.test.ts +8 -1
  360. package/dist/extensions/pi-subagents/test/unit/watchdog-tool-actions.test.ts +19 -1
  361. package/dist/extensions/pi-subagents/test/unit/workflow-chat-progress.test.ts +72 -4
  362. package/dist/extensions/pi-subagents/test/unit/workflow-checklist.test.ts +17 -3
  363. package/dist/extensions/pi-subagents/test/unit/workflow-child-summary.test.ts +34 -0
  364. package/dist/extensions/pi-subagents/test/unit/workflow-detach-reconcile.test.ts +12 -2
  365. package/dist/extensions/pi-subagents/test/unit/workflow-launch-params.test.ts +46 -6
  366. package/dist/extensions/pi-subagents/test/unit/workflow-receipt.test.ts +3 -3
  367. package/dist/extensions/pi-subagents/test/unit/workflow-resources.test.ts +133 -1
  368. package/dist/extensions/pi-subagents/test/unit/workflow-resume-hint.test.ts +53 -2
  369. package/dist/extensions/pi-subagents/test/unit/worktree-cleanup-plan.test.ts +222 -14
  370. package/dist/extensions/pi-subagents/test/unit/worktree.test.ts +526 -85
  371. package/dist/extensions/pi-web-agent/src/backends/config.ts +1 -0
  372. package/dist/extensions/pi-web-agent/src/backends/settings-reader.ts +5 -3
  373. package/dist/extensions/pi-web-agent/src/search/tokenin.ts +7 -3
  374. package/dist/extensions/pi-web-agent/src/types.ts +1 -1
  375. package/dist/extensions/pi-zentui/README.md +17 -0
  376. package/dist/extensions/pi-zentui/assets/screenshots/footer-status-hyperlink.png +0 -0
  377. package/dist/extensions/pi-zentui/docs/configuration.md +71 -2
  378. package/dist/extensions/pi-zentui/extensions/zentui/config.ts +11 -0
  379. package/dist/extensions/pi-zentui/extensions/zentui/editor-transfer.ts +14 -0
  380. package/dist/extensions/pi-zentui/extensions/zentui/extension-status.ts +29 -13
  381. package/dist/extensions/pi-zentui/extensions/zentui/footer-layout.ts +5 -4
  382. package/dist/extensions/pi-zentui/extensions/zentui/footer-text.ts +11 -0
  383. package/dist/extensions/pi-zentui/extensions/zentui/footer.ts +11 -10
  384. package/dist/extensions/pi-zentui/extensions/zentui/index.ts +77 -3
  385. package/dist/extensions/pi-zentui/extensions/zentui/presets.ts +77 -0
  386. package/dist/extensions/pi-zentui/extensions/zentui/settings-command.ts +103 -2
  387. package/dist/extensions/pi-zentui/extensions/zentui/working-line-extension-segments.ts +115 -0
  388. package/dist/extensions/pi-zentui/extensions/zentui/working-line.ts +87 -5
  389. package/dist/extensions/pi-zentui/package-lock.json +277 -517
  390. package/dist/extensions/pi-zentui/package.json +7 -4
  391. package/dist/extensions/pi-zentui/test/config-presets.test.ts +238 -0
  392. package/dist/extensions/pi-zentui/test/editor-transfer.test.ts +24 -1
  393. package/dist/extensions/pi-zentui/test/extension-compliance.test.ts +570 -2
  394. package/dist/extensions/pi-zentui/test/extension-status.test.ts +90 -0
  395. package/dist/extensions/pi-zentui/test/footer-hyperlink.test.ts +243 -0
  396. package/dist/extensions/pi-zentui/test/package-contents.mjs +1 -0
  397. package/dist/extensions/pi-zentui/test/presets.test.ts +121 -0
  398. package/dist/extensions/pi-zentui/test/settings-command.test.ts +205 -1
  399. package/dist/extensions/pi-zentui/test/working-line-extension-segments.test.ts +139 -0
  400. package/dist/extensions/pi-zentui/test/working-line-lifecycle.integration.test.ts +237 -3
  401. package/dist/extensions/pi-zentui/test/working-line.test.ts +94 -2
  402. package/dist/index.d.ts +1 -1
  403. package/dist/main.js +4 -1
  404. package/dist/modes/interactive/chat-viewport.d.ts +19 -0
  405. package/dist/modes/interactive/chat-viewport.js +27 -0
  406. package/dist/modes/interactive/components/assistant-message.d.ts +6 -2
  407. package/dist/modes/interactive/components/assistant-message.js +30 -13
  408. package/dist/modes/interactive/components/custom-editor.d.ts +10 -1
  409. package/dist/modes/interactive/components/custom-editor.js +39 -1
  410. package/dist/modes/interactive/components/first-time-setup.js +1 -1
  411. package/dist/modes/interactive/components/index.d.ts +1 -1
  412. package/dist/modes/interactive/components/markdown-transform.d.ts +2 -0
  413. package/dist/modes/interactive/components/markdown-transform.js +18 -0
  414. package/dist/modes/interactive/components/model-selector.js +19 -17
  415. package/dist/modes/interactive/components/scoped-models-selector.js +21 -23
  416. package/dist/modes/interactive/components/settings-selector.d.ts +7 -1
  417. package/dist/modes/interactive/components/settings-selector.js +128 -20
  418. package/dist/modes/interactive/components/settings-submenu.d.ts +71 -0
  419. package/dist/modes/interactive/components/settings-submenu.js +164 -0
  420. package/dist/modes/interactive/components/status-indicator.d.ts +3 -1
  421. package/dist/modes/interactive/components/status-indicator.js +10 -3
  422. package/dist/modes/interactive/components/thinking-selector.d.ts +15 -3
  423. package/dist/modes/interactive/components/thinking-selector.js +75 -18
  424. package/dist/modes/interactive/components/tool-execution.d.ts +21 -4
  425. package/dist/modes/interactive/components/tool-execution.js +35 -33
  426. package/dist/modes/interactive/components/trust-selector.js +2 -2
  427. package/dist/modes/interactive/interactive-mode.d.ts +13 -15
  428. package/dist/modes/interactive/interactive-mode.js +144 -80
  429. package/dist/modes/interactive/session-share.d.ts +15 -0
  430. package/dist/modes/interactive/session-share.js +183 -0
  431. package/dist/modes/interactive/theme/dark.json +2 -1
  432. package/dist/modes/interactive/theme/light.json +2 -1
  433. package/dist/modes/interactive/theme/theme-controller.d.ts +1 -0
  434. package/dist/modes/interactive/theme/theme-controller.js +5 -0
  435. package/dist/modes/interactive/theme/theme-json.d.ts +83 -0
  436. package/dist/modes/interactive/theme/theme-json.js +129 -0
  437. package/dist/modes/interactive/theme/theme-schema.json +9 -1
  438. package/dist/modes/interactive/theme/theme.d.ts +14 -5
  439. package/dist/modes/interactive/theme/theme.js +18 -119
  440. package/dist/modes/interactive/tui-renderer.d.ts +20 -0
  441. package/dist/modes/interactive/tui-renderer.js +65 -0
  442. package/dist/utils/exif-orientation.js +2 -3
  443. package/dist/utils/management-http.d.ts +24 -0
  444. package/dist/utils/management-http.js +53 -0
  445. package/dist/utils/text.d.ts +7 -0
  446. package/dist/utils/text.js +8 -0
  447. package/dist/utils/tools-manager.d.ts +1 -0
  448. package/dist/utils/tools-manager.js +43 -21
  449. package/docs/docs.json +0 -4
  450. package/package.json +4 -4
  451. package/dist/extensions/pi-subagents/src/runs/shared/child-protocol.ts +0 -415
  452. package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +0 -1059
  453. package/dist/extensions/pi-subagents/src/runs/shared/subagent-startup-retry.ts +0 -116
  454. package/dist/extensions/pi-subagents/src/shared/post-exit-stdio-guard.ts +0 -85
  455. package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +0 -224
  456. package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +0 -6986
  457. package/dist/extensions/pi-subagents/test/support/mock-pi-script.mjs +0 -447
  458. package/dist/extensions/pi-subagents/test/support/real-session-child-cli.mjs +0 -185
  459. package/dist/extensions/pi-subagents/test/support/real-session-runner.ts +0 -311
  460. package/dist/extensions/pi-subagents/test/unit/capability-ceiling-pi-args.test.ts +0 -84
  461. package/dist/extensions/pi-subagents/test/unit/child-protocol.test.ts +0 -202
  462. package/dist/extensions/pi-subagents/test/unit/close-grace-timer.test.ts +0 -101
  463. package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +0 -2347
  464. package/dist/extensions/pi-subagents/test/unit/subagent-startup-retry.test.ts +0 -104
  465. package/dist/extensions/pi-subagents/test/unit/windows-hide-spawn.test.ts +0 -49
  466. package/dist/skills/imagegen-frontend-mobile/SKILL.md +0 -1465
  467. package/dist/skills/imagegen-frontend-web/SKILL.md +0 -987
  468. package/dist/skills/implanger/SKILL.md +0 -70
  469. package/dist/skills/output/SKILL.md +0 -49
  470. package/dist/skills/planger/SKILL.md +0 -167
  471. package/dist/skills/workflow/SKILL.md +0 -95
  472. package/docs/workflows.md +0 -18
  473. /package/dist/bun/{register-bedrock.d.ts → runtime-setup.d.ts} +0 -0
@@ -0,0 +1,244 @@
1
+ import type { EntryRenderOptions, MessageRenderOptions, Theme } from "@selesai/code";
2
+ import { truncateToWidth, visibleWidth, wrapTextWithAnsi, type Component } from "@earendil-works/pi-tui";
3
+ import { safeTerminalText } from "../shared/display-text.ts";
4
+
5
+ export const SUPERVISOR_REQUEST_MESSAGE_TYPE = "subagent_supervisor_request";
6
+ export const SUPERVISOR_REPLY_ENTRY_TYPE = "subagent_supervisor_reply";
7
+
8
+ export type SupervisorReason = "need_decision" | "interview_request" | "progress_update";
9
+
10
+ export interface SupervisorRequestMessageDetails {
11
+ id?: string;
12
+ requestId?: string;
13
+ reason?: SupervisorReason;
14
+ expectsReply?: boolean;
15
+ runId?: string;
16
+ agent?: string;
17
+ childIndex?: number;
18
+ childTarget?: string;
19
+ interview?: unknown;
20
+ requestBody?: string;
21
+ replyHint?: string;
22
+ }
23
+
24
+ export interface SupervisorReplyEntryData {
25
+ requestId: string;
26
+ reason?: SupervisorReason;
27
+ runId: string;
28
+ agent: string;
29
+ childIndex: number;
30
+ childTarget?: string;
31
+ message: string;
32
+ createdAt: number;
33
+ }
34
+
35
+ interface SupervisorMessageLike {
36
+ content: unknown;
37
+ details?: unknown;
38
+ }
39
+
40
+ interface SupervisorEntryLike {
41
+ data?: unknown;
42
+ }
43
+
44
+ const MAX_FIELD_CHARS = 512;
45
+ const MAX_BODY_CHARS = 8_000;
46
+ const MAX_INTERVIEW_CHARS = 4_000;
47
+ const MAX_RENDER_LINES = 36;
48
+ const TRUNCATION_MARKER = "[truncated]";
49
+
50
+ export function supervisorReplyHint(requestId: string): string {
51
+ return `subagent_supervisor({ action: "reply", replyTo: "${requestId}", message: "..." })`;
52
+ }
53
+
54
+ function boundedText(value: string, maxChars: number): string {
55
+ const safe = safeTerminalText(value);
56
+ if (safe.length <= maxChars) return safe;
57
+ const prefixLength = Math.max(0, maxChars - TRUNCATION_MARKER.length - 1);
58
+ let prefix = "";
59
+ for (const character of safe) {
60
+ if (prefix.length + character.length > prefixLength) break;
61
+ prefix += character;
62
+ }
63
+ return `${prefix} ${TRUNCATION_MARKER}`;
64
+ }
65
+
66
+ function displayText(value: string, maxChars: number, expanded: boolean): string {
67
+ return expanded ? safeTerminalText(value) : boundedText(value, maxChars);
68
+ }
69
+
70
+ function boundedField(value: unknown, fallback = "unknown"): string {
71
+ return boundedText(typeof value === "string" ? value : value === undefined ? fallback : String(value), MAX_FIELD_CHARS);
72
+ }
73
+
74
+ function contentText(content: unknown): string {
75
+ if (typeof content === "string") return content;
76
+ if (!Array.isArray(content)) return "";
77
+ return content
78
+ .map((part) => {
79
+ if (!part || typeof part !== "object") return "";
80
+ const text = (part as { text?: unknown }).text;
81
+ return typeof text === "string" ? text : "";
82
+ })
83
+ .filter(Boolean)
84
+ .join("\n");
85
+ }
86
+
87
+ function interviewText(interview: unknown, expanded: boolean): string {
88
+ let serialized: string;
89
+ try {
90
+ serialized = JSON.stringify(interview, null, 2) ?? String(interview);
91
+ } catch {
92
+ serialized = "[unavailable]";
93
+ }
94
+ return displayText(serialized, MAX_INTERVIEW_CHARS, expanded);
95
+ }
96
+
97
+ function isRecord(value: unknown): value is Record<string, unknown> {
98
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
99
+ }
100
+
101
+ function isSupervisorReason(value: unknown): value is SupervisorReason {
102
+ return value === "need_decision" || value === "interview_request" || value === "progress_update";
103
+ }
104
+
105
+ function optionalString(value: unknown): boolean {
106
+ return value === undefined || typeof value === "string";
107
+ }
108
+
109
+ function requestDetails(value: unknown): SupervisorRequestMessageDetails | undefined {
110
+ if (!isRecord(value)) return undefined;
111
+ if (!optionalString(value.id) || !optionalString(value.requestId) || !optionalString(value.replyHint) || !optionalString(value.requestBody) || !optionalString(value.runId) || !optionalString(value.agent) || !optionalString(value.childTarget)) return undefined;
112
+ if (value.reason !== undefined && !isSupervisorReason(value.reason)) return undefined;
113
+ if (value.expectsReply !== undefined && typeof value.expectsReply !== "boolean") return undefined;
114
+ if (value.childIndex !== undefined && (typeof value.childIndex !== "number" || !Number.isFinite(value.childIndex))) return undefined;
115
+ return value;
116
+ }
117
+
118
+ function replyData(value: unknown): SupervisorReplyEntryData | undefined {
119
+ if (!isRecord(value)) return undefined;
120
+ if (typeof value.requestId !== "string" || typeof value.runId !== "string" || typeof value.agent !== "string" || typeof value.message !== "string") return undefined;
121
+ if (value.reason !== undefined && !isSupervisorReason(value.reason)) return undefined;
122
+ if (value.childTarget !== undefined && typeof value.childTarget !== "string") return undefined;
123
+ if (typeof value.childIndex !== "number" || !Number.isFinite(value.childIndex) || typeof value.createdAt !== "number" || !Number.isFinite(value.createdAt)) return undefined;
124
+ return {
125
+ requestId: value.requestId,
126
+ ...(value.reason === undefined ? {} : { reason: value.reason }),
127
+ runId: value.runId,
128
+ agent: value.agent,
129
+ childIndex: value.childIndex,
130
+ ...(value.childTarget === undefined ? {} : { childTarget: value.childTarget }),
131
+ message: value.message,
132
+ createdAt: value.createdAt,
133
+ };
134
+ }
135
+
136
+ function withRequestId(details: SupervisorRequestMessageDetails): string {
137
+ return boundedField(details.requestId ?? details.id);
138
+ }
139
+
140
+ function requestHeading(reason: SupervisorReason | undefined): string {
141
+ if (reason === "interview_request") return "⚠ Supervisor interview request";
142
+ if (reason === "progress_update") return "ℹ Supervisor progress update";
143
+ return "⚠ Supervisor decision request";
144
+ }
145
+
146
+ function requestLines(message: SupervisorMessageLike, details: SupervisorRequestMessageDetails, expanded: boolean): string[] {
147
+ const requestId = withRequestId(details);
148
+ const lines = [
149
+ `Reason: ${boundedField(details.reason)}`,
150
+ `Run: ${boundedField(details.runId)}`,
151
+ `Agent: ${boundedField(details.agent)}`,
152
+ `Child index: ${boundedField(details.childIndex)}`,
153
+ ];
154
+ if (details.childTarget) lines.push(`Child target: ${boundedField(details.childTarget)}`);
155
+ lines.push(`Request ID: ${requestId}`);
156
+ if (details.expectsReply) lines.push(`Reply with: ${displayText(details.replyHint ?? supervisorReplyHint(requestId), MAX_BODY_CHARS, expanded)}`);
157
+ lines.push("", "Request:", displayText((details.requestBody ?? contentText(message.content)) || "(no request body)", MAX_BODY_CHARS, expanded));
158
+ if (details.interview !== undefined) lines.push("", "Interview shape:", interviewText(details.interview, expanded));
159
+ return lines;
160
+ }
161
+
162
+ function replyLines(data: SupervisorReplyEntryData, expanded: boolean): string[] {
163
+ const requestId = boundedField(data.requestId);
164
+ const lines = [
165
+ ...(data.reason ? [`Reason: ${boundedField(data.reason)}`] : []),
166
+ `Run: ${boundedField(data.runId)}`,
167
+ `Agent: ${boundedField(data.agent)}`,
168
+ `Child index: ${boundedField(data.childIndex)}`,
169
+ ];
170
+ if (data.childTarget) lines.push(`Child target: ${boundedField(data.childTarget)}`);
171
+ lines.push(`Reply to: ${requestId}`, "", "Reply:", displayText(data.message || "(empty reply)", MAX_BODY_CHARS, expanded));
172
+ return lines;
173
+ }
174
+
175
+ function renderCard(lines: string[], heading: string, theme: Theme, width: number, expanded: boolean): string[] {
176
+ const safeWidth = Math.max(0, Math.floor(width));
177
+ if (safeWidth < 3) return [truncateToWidth(heading, safeWidth, "")];
178
+ const bodyWidth = safeWidth - 2;
179
+ const headerText = truncateToWidth(` ${heading} `, bodyWidth, "");
180
+ const headerPadding = Math.max(0, bodyWidth - visibleWidth(headerText));
181
+ const border = (text: string) => theme.fg("accent", text);
182
+ const rendered = [border(`╭${headerText}${"─".repeat(headerPadding)}╮`)];
183
+ let hidden = false;
184
+ let interiorLines = 0;
185
+ for (const line of lines) {
186
+ const wrapped = wrapTextWithAnsi(line, Math.max(1, bodyWidth));
187
+ for (const wrappedLine of wrapped.length > 0 ? wrapped : [""]) {
188
+ if (!expanded && interiorLines >= MAX_RENDER_LINES) {
189
+ hidden = true;
190
+ break;
191
+ }
192
+ const text = truncateToWidth(wrappedLine, bodyWidth, "");
193
+ rendered.push(border(`│${text}${" ".repeat(Math.max(0, bodyWidth - visibleWidth(text)))}│`));
194
+ interiorLines++;
195
+ }
196
+ if (hidden) break;
197
+ }
198
+ if (hidden) {
199
+ const text = truncateToWidth(TRUNCATION_MARKER, bodyWidth, "");
200
+ rendered.push(border(`│${text}${" ".repeat(Math.max(0, bodyWidth - visibleWidth(text)))}│`));
201
+ }
202
+ rendered.push(border(`╰${"─".repeat(bodyWidth)}╯`));
203
+ return rendered;
204
+ }
205
+
206
+ class SupervisorCardComponent implements Component {
207
+ private readonly expanded: boolean;
208
+ private readonly heading: string;
209
+ private readonly lines: string[];
210
+ private readonly theme: Theme;
211
+
212
+ constructor(heading: string, lines: string[], theme: Theme, expanded: boolean) {
213
+ this.expanded = expanded;
214
+ this.heading = heading;
215
+ this.lines = lines;
216
+ this.theme = theme;
217
+ }
218
+
219
+ invalidate(): void {}
220
+
221
+ render(width: number): string[] {
222
+ return renderCard(this.lines, this.heading, this.theme, width, this.expanded);
223
+ }
224
+ }
225
+
226
+ export function renderSupervisorRequest(
227
+ message: SupervisorMessageLike,
228
+ options: MessageRenderOptions,
229
+ theme: Theme,
230
+ ): Component | undefined {
231
+ const details = requestDetails(message.details);
232
+ if (!details) return undefined;
233
+ return new SupervisorCardComponent(requestHeading(details.reason), requestLines(message, details, options.expanded), theme, options.expanded);
234
+ }
235
+
236
+ export function renderSupervisorReply(
237
+ entry: SupervisorEntryLike,
238
+ options: EntryRenderOptions,
239
+ theme: Theme,
240
+ ): Component | undefined {
241
+ const data = replyData(entry.data);
242
+ if (!data) return undefined;
243
+ return new SupervisorCardComponent("↩ Supervisor reply to child", replyLines(data, options.expanded), theme, options.expanded);
244
+ }
@@ -18,6 +18,12 @@ export interface MissionWorkflowState {
18
18
  set(key: string, value: unknown): void;
19
19
  }
20
20
 
21
+ export interface MissionWorkflowStateOptions {
22
+ isProcessAlive?: (pid: number) => boolean;
23
+ getProcessStartKey?: (pid: number) => string | undefined;
24
+ retryDelaysMs?: readonly number[];
25
+ }
26
+
21
27
  export function missionStatePath(location: MissionStoreLocation, missionId: string): string {
22
28
  return path.join(location.missionDir, validateMissionId(missionId), "state.json");
23
29
  }
@@ -66,13 +72,22 @@ function windowsProcessStartKey(pid: number): string | undefined {
66
72
  }
67
73
  }
68
74
 
75
+ let currentProcessKey: string | undefined | null = null;
76
+
69
77
  function processStartKey(pid: number): string | undefined {
78
+ // Foreign PIDs can be reused while this process lives, so resolve them afresh.
79
+ if (pid !== process.pid) return computeProcessStartKey(pid);
80
+ if (currentProcessKey === null) currentProcessKey = computeProcessStartKey(pid);
81
+ return currentProcessKey;
82
+ }
83
+
84
+ function computeProcessStartKey(pid: number): string | undefined {
70
85
  if (process.platform === "linux") return linuxProcessStartKey(pid) ?? psProcessStartKey(pid);
71
86
  if (process.platform === "win32") return windowsProcessStartKey(pid);
72
87
  return undefined;
73
88
  }
74
89
 
75
- const CURRENT_PROCESS_KEY = processStartKey(process.pid);
90
+ type StateLockOptions = Required<MissionWorkflowStateOptions>;
76
91
 
77
92
  function readStateLockOwner(lockPath: string): StateLockOwner | undefined {
78
93
  try {
@@ -91,13 +106,13 @@ function readStateLockOwner(lockPath: string): StateLockOwner | undefined {
91
106
  return undefined;
92
107
  }
93
108
 
94
- function stateLockIsStale(lockPath: string, now = Date.now()): boolean {
109
+ function stateLockIsStale(lockPath: string, options: StateLockOptions, now = Date.now()): boolean {
95
110
  const owner = readStateLockOwner(lockPath);
96
111
  if (owner) {
97
- if (!isProcessAlive(owner.pid)) return true;
112
+ if (!options.isProcessAlive(owner.pid)) return true;
98
113
  if (owner.processKey) {
99
- const currentProcessKey = owner.pid === process.pid ? CURRENT_PROCESS_KEY : processStartKey(owner.pid);
100
- if (currentProcessKey) return owner.processKey !== currentProcessKey;
114
+ const observedProcessKey = options.getProcessStartKey(owner.pid);
115
+ if (observedProcessKey) return owner.processKey !== observedProcessKey;
101
116
  if (owner.pid === process.pid) return true;
102
117
  }
103
118
  return false;
@@ -140,11 +155,11 @@ function waitForStateLock(delayMs: number | undefined, lockPath: string): void {
140
155
  waitForFileSystemRetry(delayMs);
141
156
  }
142
157
 
143
- function reclaimStaleStateLock(lockPath: string, reclaimPath: string): boolean {
144
- if (!stateLockIsStale(lockPath)) return false;
158
+ function reclaimStaleStateLock(lockPath: string, reclaimPath: string, options: StateLockOptions): boolean {
159
+ if (!stateLockIsStale(lockPath, options)) return false;
145
160
  if (!tryMakeDirectory(reclaimPath, 0o700)) return false;
146
161
  try {
147
- if (!stateLockIsStale(lockPath)) return false;
162
+ if (!stateLockIsStale(lockPath, options)) return false;
148
163
  fs.rmSync(lockPath, { recursive: true, force: true });
149
164
  return true;
150
165
  } finally {
@@ -152,7 +167,7 @@ function reclaimStaleStateLock(lockPath: string, reclaimPath: string): boolean {
152
167
  }
153
168
  }
154
169
 
155
- function withStateFileLock<T>(filePath: string, operation: () => T): T {
170
+ function withStateFileLock<T>(filePath: string, operation: () => T, options: StateLockOptions): T {
156
171
  fs.mkdirSync(path.dirname(filePath), { recursive: true });
157
172
  const lockPath = `${filePath}.lock`;
158
173
  const reclaimPath = `${lockPath}.reclaim`;
@@ -163,7 +178,7 @@ function withStateFileLock<T>(filePath: string, operation: () => T): T {
163
178
  fs.rmSync(reclaimPath, { recursive: true, force: true });
164
179
  continue;
165
180
  }
166
- waitForStateLock(DEFAULT_FILE_SYSTEM_RETRY_DELAYS_MS[attempt], lockPath);
181
+ waitForStateLock(options.retryDelaysMs[attempt], lockPath);
167
182
  continue;
168
183
  }
169
184
  let acquired = false;
@@ -171,17 +186,18 @@ function withStateFileLock<T>(filePath: string, operation: () => T): T {
171
186
  acquired = tryMakeDirectory(lockPath, 0o700);
172
187
  } catch (error) {
173
188
  if (isRetryableFileSystemError(error)) {
174
- waitForStateLock(DEFAULT_FILE_SYSTEM_RETRY_DELAYS_MS[attempt], lockPath);
189
+ waitForStateLock(options.retryDelaysMs[attempt], lockPath);
175
190
  continue;
176
191
  }
177
192
  throw new Error(`Failed to acquire mission state lock '${lockPath}': ${error instanceof Error ? error.message : String(error)}`);
178
193
  }
179
194
  if (!acquired) {
180
- if (reclaimStaleStateLock(lockPath, reclaimPath)) continue;
181
- waitForStateLock(DEFAULT_FILE_SYSTEM_RETRY_DELAYS_MS[attempt], lockPath);
195
+ if (reclaimStaleStateLock(lockPath, reclaimPath, options)) continue;
196
+ waitForStateLock(options.retryDelaysMs[attempt], lockPath);
182
197
  continue;
183
198
  }
184
- owner = { pid: process.pid, token: randomUUID(), createdAt: Date.now(), ...(CURRENT_PROCESS_KEY ? { processKey: CURRENT_PROCESS_KEY } : {}) };
199
+ const key = options.getProcessStartKey(process.pid);
200
+ owner = { pid: process.pid, token: randomUUID(), createdAt: Date.now(), ...(key ? { processKey: key } : {}) };
185
201
  try {
186
202
  fs.writeFileSync(path.join(lockPath, "owner.json"), JSON.stringify(owner), { encoding: "utf-8", mode: 0o600 });
187
203
  } catch (error) {
@@ -205,8 +221,13 @@ function validateStateKey(value: unknown): string {
205
221
  return value;
206
222
  }
207
223
 
208
- export function createMissionWorkflowState(location: MissionStoreLocation, missionId: string): MissionWorkflowState {
224
+ export function createMissionWorkflowState(location: MissionStoreLocation, missionId: string, options: MissionWorkflowStateOptions = {}): MissionWorkflowState {
209
225
  const filePath = missionStatePath(location, missionId);
226
+ const lockOptions: StateLockOptions = {
227
+ isProcessAlive: options.isProcessAlive ?? isProcessAlive,
228
+ getProcessStartKey: options.getProcessStartKey ?? processStartKey,
229
+ retryDelaysMs: options.retryDelaysMs ?? DEFAULT_FILE_SYSTEM_RETRY_DELAYS_MS,
230
+ };
210
231
  let loaded = false;
211
232
  let values: Record<string, unknown> = Object.create(null) as Record<string, unknown>;
212
233
 
@@ -254,7 +275,7 @@ export function createMissionWorkflowState(location: MissionStoreLocation, missi
254
275
  writePrivateAtomicJson(filePath, next);
255
276
  values = next;
256
277
  loaded = true;
257
- });
278
+ }, lockOptions);
258
279
  },
259
280
  };
260
281
  }
@@ -12,7 +12,7 @@ export const DEFAULT_ABANDONED_SLOT_RELEASE_AFTER_MS = 20 * 60 * 1000;
12
12
  export const MIN_ABANDONED_SLOT_RELEASE_AFTER_MS = 5 * 60 * 1000;
13
13
  export const MAX_ABANDONED_SLOT_RELEASE_AFTER_MS = 24 * 60 * 60 * 1000;
14
14
 
15
- export interface ActiveAsyncCapacityOwnerV1 {
15
+ export interface ActiveAsyncCapacityOwner {
16
16
  version: 1;
17
17
  reservationToken: string;
18
18
  ownerSessionId: string;
@@ -29,7 +29,7 @@ export interface ActiveAsyncCapacityOwnerV1 {
29
29
  }
30
30
 
31
31
  export interface ActiveAsyncCapacityHandle {
32
- readonly owner: ActiveAsyncCapacityOwnerV1;
32
+ readonly owner: ActiveAsyncCapacityOwner;
33
33
  markStarted(runnerProcessInstanceId: string): void;
34
34
  markWorkflowStarted(): void;
35
35
  rollback(): boolean;
@@ -44,7 +44,7 @@ interface CapacityOptions {
44
44
  abandonedSlotReleaseAfterMs?: number | false;
45
45
  pidLiveness?: (pid: number) => PidLiveness;
46
46
  afterSlotRename?: (releasedDir: string) => void;
47
- writeOwner?: (filePath: string, owner: ActiveAsyncCapacityOwnerV1) => void;
47
+ writeOwner?: (filePath: string, owner: ActiveAsyncCapacityOwner) => void;
48
48
  }
49
49
 
50
50
  export interface ActiveAsyncCapacityReleaseEvidence {
@@ -61,7 +61,7 @@ export type ActiveAsyncCapacityReleaseVerdict =
61
61
  | { state: "not-owned"; reason: string };
62
62
 
63
63
  export interface ActiveAsyncCapacityInspection {
64
- owner?: ActiveAsyncCapacityOwnerV1;
64
+ owner?: ActiveAsyncCapacityOwner;
65
65
  relation: "current" | "source" | "none";
66
66
  slotDir?: string;
67
67
  release: ActiveAsyncCapacityReleaseVerdict;
@@ -100,9 +100,9 @@ function slotDir(poolDir: string, slot: number): string {
100
100
  return path.join(poolDir, `slot-${slot}`);
101
101
  }
102
102
 
103
- function parseOwner(value: unknown): ActiveAsyncCapacityOwnerV1 | undefined {
103
+ function parseOwner(value: unknown): ActiveAsyncCapacityOwner | undefined {
104
104
  if (!value || typeof value !== "object" || Array.isArray(value)) return undefined;
105
- const owner = value as Partial<ActiveAsyncCapacityOwnerV1>;
105
+ const owner = value as Partial<ActiveAsyncCapacityOwner>;
106
106
  if (owner.version !== 1
107
107
  || typeof owner.reservationToken !== "string" || !owner.reservationToken
108
108
  || typeof owner.ownerSessionId !== "string" || !owner.ownerSessionId
@@ -116,10 +116,10 @@ function parseOwner(value: unknown): ActiveAsyncCapacityOwnerV1 | undefined {
116
116
  if (owner.sourceRunId !== undefined && typeof owner.sourceRunId !== "string") return undefined;
117
117
  if (owner.runnerProcessInstanceId !== undefined && (typeof owner.runnerProcessInstanceId !== "string" || !owner.runnerProcessInstanceId)) return undefined;
118
118
  if (owner.runnerStartedAt !== undefined && (typeof owner.runnerStartedAt !== "number" || !Number.isFinite(owner.runnerStartedAt))) return undefined;
119
- return owner as ActiveAsyncCapacityOwnerV1;
119
+ return owner as ActiveAsyncCapacityOwner;
120
120
  }
121
121
 
122
- function readOwner(dir: string): ActiveAsyncCapacityOwnerV1 | undefined {
122
+ function readOwner(dir: string): ActiveAsyncCapacityOwner | undefined {
123
123
  try {
124
124
  return parseOwner(JSON.parse(fs.readFileSync(path.join(dir, "owner.json"), "utf-8")));
125
125
  } catch {
@@ -142,7 +142,7 @@ function snapshotFor(sessionId: string, limit: number | undefined, rootDir: stri
142
142
  return { used: occupiedSlots(sessionDir(sessionId, rootDir)).length, limit: limit ?? 0 };
143
143
  }
144
144
 
145
- function matchingOwner(dir: string, expected: ActiveAsyncCapacityOwnerV1): ActiveAsyncCapacityOwnerV1 | undefined {
145
+ function matchingOwner(dir: string, expected: ActiveAsyncCapacityOwner): ActiveAsyncCapacityOwner | undefined {
146
146
  const owner = readOwner(dir);
147
147
  return owner?.reservationToken === expected.reservationToken
148
148
  && owner.runId === expected.runId
@@ -176,7 +176,7 @@ function withSlotClaim<T>(dir: string, operation: () => T): { acquired: true; va
176
176
  }
177
177
  }
178
178
 
179
- function removeOwnedSlot(dir: string, expected: ActiveAsyncCapacityOwnerV1, options: CapacityOptions, requireUnstarted = false, release?: ActiveAsyncCapacityReleaseVerdict): boolean {
179
+ function removeOwnedSlot(dir: string, expected: ActiveAsyncCapacityOwner, options: CapacityOptions, requireUnstarted = false, release?: ActiveAsyncCapacityReleaseVerdict): boolean {
180
180
  if (requireUnstarted && (expected.runnerProcessInstanceId || expected.runnerStartedAt)) return false;
181
181
  const claimed = withSlotClaim(dir, () => {
182
182
  const current = matchingOwner(dir, expected);
@@ -193,7 +193,7 @@ function removeOwnedSlot(dir: string, expected: ActiveAsyncCapacityOwnerV1, opti
193
193
  return claimed.acquired && claimed.value;
194
194
  }
195
195
 
196
- function appendAbandonedReleaseEvent(asyncDir: string, owner: ActiveAsyncCapacityOwnerV1, evidence: ActiveAsyncCapacityReleaseEvidence, now: number): void {
196
+ function appendAbandonedReleaseEvent(asyncDir: string, owner: ActiveAsyncCapacityOwner, evidence: ActiveAsyncCapacityReleaseEvidence, now: number): void {
197
197
  try {
198
198
  const eventsPath = path.join(asyncDir, "events.jsonl");
199
199
  fs.mkdirSync(path.dirname(eventsPath), { recursive: true });
@@ -213,7 +213,7 @@ function terminalState(state: AsyncStatus["state"]): boolean {
213
213
  return state !== "queued" && state !== "running" && state !== "paused";
214
214
  }
215
215
 
216
- function runnerReleaseVerdict(owner: ActiveAsyncCapacityOwnerV1, status: AsyncStatus | null, options: CapacityOptions): ActiveAsyncCapacityReleaseVerdict {
216
+ function runnerReleaseVerdict(owner: ActiveAsyncCapacityOwner, status: AsyncStatus | null, options: CapacityOptions): ActiveAsyncCapacityReleaseVerdict {
217
217
  if (!status) return { state: "retained", reason: "status file is missing or unreadable" };
218
218
  if (!owner.runnerProcessInstanceId) return { state: "retained", reason: "runner process identity has not been recorded" };
219
219
  if (status.sessionId !== owner.ownerSessionId) return { state: "retained", reason: `status session ${status.sessionId ?? "unknown"} does not match owner session ${owner.ownerSessionId}` };
@@ -262,7 +262,7 @@ function abandonedRunnerReleaseVerdict(status: AsyncStatus, proofState: string,
262
262
  };
263
263
  }
264
264
 
265
- function workflowReleaseVerdict(owner: ActiveAsyncCapacityOwnerV1, status: AsyncStatus | null, liveWorkflowRunIds: ReadonlySet<string>): ActiveAsyncCapacityReleaseVerdict {
265
+ function workflowReleaseVerdict(owner: ActiveAsyncCapacityOwner, status: AsyncStatus | null, liveWorkflowRunIds: ReadonlySet<string>): ActiveAsyncCapacityReleaseVerdict {
266
266
  if (!status) return { state: "retained", reason: "status file is missing or unreadable" };
267
267
  if (status.sessionId !== owner.ownerSessionId) return { state: "retained", reason: `status session ${status.sessionId ?? "unknown"} does not match owner session ${owner.ownerSessionId}` };
268
268
  if (status.runId !== owner.runId) return { state: "retained", reason: `status run ${status.runId} does not match owner run ${owner.runId}` };
@@ -289,7 +289,7 @@ function workflowReleaseVerdict(owner: ActiveAsyncCapacityOwnerV1, status: Async
289
289
  return { state: "releasable", reason: "workflow is terminal, controller is gone, and async children have observed proof" };
290
290
  }
291
291
 
292
- function ownerReleaseVerdict(owner: ActiveAsyncCapacityOwnerV1, liveWorkflowRunIds: ReadonlySet<string>, options: CapacityOptions): ActiveAsyncCapacityReleaseVerdict {
292
+ function ownerReleaseVerdict(owner: ActiveAsyncCapacityOwner, liveWorkflowRunIds: ReadonlySet<string>, options: CapacityOptions): ActiveAsyncCapacityReleaseVerdict {
293
293
  const status = readStatus(owner.asyncDir);
294
294
  return owner.kind === "runner"
295
295
  ? runnerReleaseVerdict(owner, status, options)
@@ -364,7 +364,7 @@ export function getActiveAsyncCapacitySnapshot(
364
364
  return reconcileActiveAsyncCapacity(sessionId, limit, options);
365
365
  }
366
366
 
367
- function createSlot(poolDir: string, owner: ActiveAsyncCapacityOwnerV1): boolean {
367
+ function createSlot(poolDir: string, owner: ActiveAsyncCapacityOwner): boolean {
368
368
  const destination = slotDir(poolDir, owner.slot);
369
369
  fs.mkdirSync(poolDir, { recursive: true, mode: 0o700 });
370
370
  try {
@@ -379,7 +379,7 @@ function createSlot(poolDir: string, owner: ActiveAsyncCapacityOwnerV1): boolean
379
379
  return true;
380
380
  }
381
381
 
382
- function handleFor(owner: ActiveAsyncCapacityOwnerV1, limit: number, options: CapacityOptions, rollbackOwner?: ActiveAsyncCapacityOwnerV1): ActiveAsyncCapacityHandle {
382
+ function handleFor(owner: ActiveAsyncCapacityOwner, limit: number, options: CapacityOptions, rollbackOwner?: ActiveAsyncCapacityOwner): ActiveAsyncCapacityHandle {
383
383
  const rootDir = options.rootDir ?? ACTIVE_ASYNC_CAPACITY_DIR;
384
384
  const writeOwner = options.writeOwner ?? writePrivateAtomicJson;
385
385
  const dir = slotDir(sessionDir(owner.ownerSessionId, rootDir), owner.slot);
@@ -462,7 +462,7 @@ export function acquireActiveAsyncCapacity(
462
462
  const poolDir = sessionDir(input.sessionId, rootDir);
463
463
  const token = options.token?.() ?? randomUUID();
464
464
  for (let slot = 0; slot < input.limit; slot++) {
465
- const owner: ActiveAsyncCapacityOwnerV1 = {
465
+ const owner: ActiveAsyncCapacityOwner = {
466
466
  version: 1,
467
467
  reservationToken: token,
468
468
  ownerSessionId: input.sessionId,
@@ -495,7 +495,7 @@ export function transferActiveAsyncCapacity(
495
495
  if (!current || !status || status.runId !== input.sourceRunId || status.state === "queued" || status.state === "running") {
496
496
  throw new Error(`Active async capacity source '${input.sourceRunId}' is not transferable.`);
497
497
  }
498
- const next: ActiveAsyncCapacityOwnerV1 = {
498
+ const next: ActiveAsyncCapacityOwner = {
499
499
  ...current,
500
500
  runId: input.runId,
501
501
  sourceRunId: input.sourceRunId,