@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
@@ -115,6 +115,40 @@ describe("async chain root attachment", () => {
115
115
  assert.equal(result.exitCode, 0);
116
116
  });
117
117
 
118
+ for (const proofState of [undefined, "pending"]) it(`waits past the terminal grace for workflow-owned single publication with ${proofState ?? "absent"} root proof`, async (t) => {
119
+ t.mock.timers.enable({ apis: ["setTimeout", "Date"], now: 0 });
120
+ const importedRoot = { ...root(), resultPath: path.join(tempDir, "root-run", "workflow-result.json") };
121
+ writeJson(path.join(importedRoot.asyncDir, "status.json"), {
122
+ runId: importedRoot.runId,
123
+ mode: "single",
124
+ parentWorkflowRunId: "workflow-parent",
125
+ state: "running",
126
+ pid: process.pid,
127
+ startedAt: 1,
128
+ ...(proofState ? { processTerminal: { version: 1, runId: importedRoot.runId, runnerProcessInstanceId: "runner-instance", state: proofState } } : {}),
129
+ steps: [{ agent: "worker", status: "complete" }],
130
+ });
131
+
132
+ // The live publisher is this process; advance only the waiter's clock,
133
+ // leaving the real completed-step evidence intact until publication.
134
+ const waiting = waitForImportedAsyncRoot(importedRoot);
135
+ for (let poll = 0; poll < 3; poll++) {
136
+ t.mock.timers.tick(500);
137
+ await Promise.resolve();
138
+ }
139
+ assert.equal(Date.now(), 1_500);
140
+ assert.equal(fs.existsSync(importedRoot.resultPath), false);
141
+ writeJson(importedRoot.resultPath, {
142
+ state: "complete",
143
+ success: true,
144
+ results: [{ agent: "worker", output: "published after step completion", success: true }],
145
+ });
146
+ t.mock.timers.tick(500);
147
+ const result = await waiting;
148
+ assert.equal(result.success, true, result.error);
149
+ assert.equal(result.output, "published after step completion");
150
+ });
151
+
118
152
  it("imports a failed root as a failed first chain step", async () => {
119
153
  const importedRoot = root();
120
154
  writeJson(path.join(importedRoot.asyncDir, "status.json"), {
@@ -188,14 +222,21 @@ describe("async chain root attachment", () => {
188
222
  assert.deepEqual(result.effects?.fileMutation?.evidence?.changedFiles, ["input.md"]);
189
223
  });
190
224
 
191
- it("fails a terminal root that never produced a result file", async () => {
192
- const importedRoot = root();
225
+ for (const fixture of [
226
+ { name: "terminal root", status: { mode: "single", state: "complete" } },
227
+ { name: "terminal workflow-owned single", status: { mode: "single", state: "complete", parentWorkflowRunId: "workflow-parent" } },
228
+ { name: "running workflow-owned single with unavailable root proof", status: {
229
+ mode: "single", state: "running", parentWorkflowRunId: "workflow-parent",
230
+ processTerminal: { version: 1, runId: "root-run", runnerProcessInstanceId: "runner-instance", state: "unknown", reason: "runner-candidate-missing" },
231
+ } },
232
+ { name: "selected child of running workflow-owned parallel root", index: 1, status: { mode: "parallel", state: "running", parentWorkflowRunId: "workflow-parent" } },
233
+ ]) it(`fails closed without a result for ${fixture.name}`, async () => {
234
+ const importedRoot = root("root-run", fixture.index ?? 0);
193
235
  writeJson(path.join(importedRoot.asyncDir, "status.json"), {
194
236
  runId: importedRoot.runId,
195
- mode: "single",
196
- state: "complete",
237
+ ...fixture.status,
197
238
  startedAt: 1,
198
- steps: [{ agent: "worker", status: "complete" }],
239
+ steps: [...(fixture.index ? [{ agent: "first", status: "running" }] : []), { agent: "worker", status: "complete" }],
199
240
  });
200
241
 
201
242
  const result = await waitForImportedAsyncRoot(importedRoot, {
@@ -203,6 +244,7 @@ describe("async chain root attachment", () => {
203
244
  terminalResultGraceMs: 0,
204
245
  });
205
246
 
247
+ assert.equal(result.agent, "worker");
206
248
  assert.equal(result.exitCode, 1);
207
249
  assert.match(result.error ?? "", /ended without a result file/);
208
250
  });
@@ -233,4 +275,4 @@ describe("async chain root attachment", () => {
233
275
  assert.equal(result.error, "parent timed out");
234
276
  assert.equal(result.output, "parent timed out");
235
277
  });
236
- });
278
+ });
@@ -0,0 +1,90 @@
1
+ import assert from "node:assert/strict";
2
+ import { describe, it } from "node:test";
3
+ import { createChildHooks } from "../../src/runs/shared/child-hooks.ts";
4
+ import { childSupervisorMetadata, evaluateChildToolDiagnostic, type ChildRuntimeConfig } from "../../src/runs/shared/child-runtime-config.ts";
5
+
6
+ function baseConfig(overrides: Partial<ChildRuntimeConfig> = {}): ChildRuntimeConfig {
7
+ return { fanoutChild: false, depth: 1, waitTool: { enabled: true }, fast: false, ...overrides };
8
+ }
9
+
10
+ interface FakePi {
11
+ handlers: Map<string, Array<(event?: unknown, ctx?: unknown) => unknown>>;
12
+ tools: Array<{ name: string }>;
13
+ api: unknown;
14
+ }
15
+
16
+ function fakePi(available: string[]): FakePi {
17
+ const handlers = new Map<string, Array<(event?: unknown, ctx?: unknown) => unknown>>();
18
+ const tools: Array<{ name: string }> = [];
19
+ const api = {
20
+ on(event: string, handler: (event?: unknown, ctx?: unknown) => unknown) {
21
+ handlers.set(event, [...(handlers.get(event) ?? []), handler]);
22
+ },
23
+ registerTool(tool: { name: string }) { tools.push(tool); },
24
+ getAllTools: () => [...available, ...tools.map((tool) => tool.name)].map((name) => ({ name })),
25
+ events: { on() {}, emit() {} },
26
+ sendMessage() {},
27
+ getThinkingLevel: () => "off",
28
+ };
29
+ return { handlers, tools, api };
30
+ }
31
+
32
+ describe("child runtime config", () => {
33
+ it("creates the prompt runtime hook always and the fast and fanout hooks on demand", () => {
34
+ assert.deepEqual(createChildHooks(baseConfig()).map((hook) => hook.name), ["pi-subagents:prompt-runtime"]);
35
+ assert.deepEqual(createChildHooks(baseConfig({ fast: true })).map((hook) => hook.name), ["pi-subagents:prompt-runtime", "pi-subagents:fast-mode"]);
36
+ assert.deepEqual(createChildHooks(baseConfig({ fanoutChild: true })).map((hook) => hook.name), ["pi-subagents:prompt-runtime", "pi-subagents:fanout-child"]);
37
+ });
38
+
39
+ it("hooks read the config object", async () => {
40
+ const diagnostics: unknown[] = [];
41
+ const captured: unknown[] = [];
42
+ const config = baseConfig({
43
+ agent: "config-agent",
44
+ requiredTools: ["read", "fixture_search"],
45
+ toolDiagnostic: (diagnostic) => diagnostics.push(diagnostic),
46
+ structuredOutput: { schema: { type: "object" }, capture: (value) => captured.push(value) },
47
+ inheritProjectContext: true,
48
+ inheritGlobalContext: true,
49
+ inheritSkills: true,
50
+ });
51
+ const pi = fakePi(["read"]);
52
+ for (const hook of createChildHooks(config)) hook.factory(pi.api as never);
53
+
54
+ assert.throws(() => pi.handlers.get("agent_start")?.[0]?.({}), /Agent 'config-agent' requested unavailable child tools: fixture_search/);
55
+ assert.deepEqual(diagnostics, [{ agent: "config-agent", required: ["read", "fixture_search"], available: ["read", "bg_wait", "subagent_wait", "structured_output"], missing: ["fixture_search"] }]);
56
+
57
+ const structured = pi.tools.find((tool) => tool.name === "structured_output") as { execute: (id: string, params: { value: unknown }) => Promise<unknown> } | undefined;
58
+ assert.ok(structured, "structured_output tool registered from config");
59
+ await structured.execute("call-1", { value: { done: true } });
60
+ assert.deepEqual(captured, [{ done: true }]);
61
+
62
+ const rewritten = await pi.handlers.get("before_agent_start")?.[0]?.({ systemPrompt: "base prompt" }) as { systemPrompt: string } | undefined;
63
+ assert.match(rewritten?.systemPrompt ?? "", /strict structured output contract/);
64
+ });
65
+
66
+ it("evaluates the tool diagnostic against the available tools", () => {
67
+ assert.equal(evaluateChildToolDiagnostic(baseConfig(), ["read"]), undefined);
68
+ assert.equal(evaluateChildToolDiagnostic(baseConfig({ requiredTools: ["read"] }), ["read", "write"]), undefined);
69
+ assert.deepEqual(
70
+ evaluateChildToolDiagnostic(baseConfig({ agent: "worker", requiredTools: ["read", "mcp_search"], mcpDirectTools: ["mcp_search"] }), ["read"]),
71
+ { agent: "worker", required: ["read", "mcp_search"], available: ["read"], missing: ["mcp_search"], missingMcpDirectTools: ["mcp_search"] },
72
+ );
73
+ });
74
+
75
+ it("derives supervisor metadata only when the channel, run, agent, index, and orchestrator session are all set", () => {
76
+ assert.equal(childSupervisorMetadata(baseConfig({ supervisorChannelDir: "/tmp/channel", runId: "run-1", agent: "worker" })), undefined);
77
+ assert.deepEqual(
78
+ childSupervisorMetadata(baseConfig({
79
+ supervisorChannelDir: "/tmp/channel",
80
+ runId: "run-1",
81
+ agent: "worker",
82
+ childIndex: 2,
83
+ orchestratorSessionId: "session-1",
84
+ orchestratorTarget: "orchestrator",
85
+ intercomSessionName: "child-target",
86
+ })),
87
+ { channelDir: "/tmp/channel", runId: "run-1", agent: "worker", childIndex: 2, orchestratorTarget: "orchestrator", orchestratorSessionId: "session-1", childTarget: "child-target" },
88
+ );
89
+ });
90
+ });
@@ -9,11 +9,11 @@ import * as fs from "node:fs";
9
9
  import * as os from "node:os";
10
10
  import * as path from "node:path";
11
11
  import { afterEach, describe, it } from "node:test";
12
+ import { buildInProcessChildLaunch, type BuildInProcessChildLaunchInput } from "../../src/runs/shared/child-launch.ts";
12
13
  import {
13
- buildPiArgs,
14
14
  resolvePermissionSystemExtension,
15
15
  resolvePiLaunchToolPlan,
16
- } from "../../src/runs/shared/pi-args.ts";
16
+ } from "../../src/runs/shared/child-tool-plan.ts";
17
17
 
18
18
  const originalEnv = {
19
19
  HOME: process.env.HOME,
@@ -23,7 +23,7 @@ const originalEnv = {
23
23
  const tempRoots: string[] = [];
24
24
 
25
25
  function createFixture() {
26
- const root = fs.mkdtempSync(path.join(os.tmpdir(), "pi-args-perm-"));
26
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), "child-tool-plan-perm-"));
27
27
  tempRoots.push(root);
28
28
  const home = path.join(root, "home");
29
29
  const agentDir = path.join(home, ".selesai", "agent");
@@ -53,12 +53,25 @@ afterEach(() => {
53
53
  tempRoots.length = 0;
54
54
  });
55
55
 
56
- function readPromptFile(result: { tempDir?: string }): string {
57
- assert.ok(result.tempDir, "expected a temp dir from buildPiArgs");
58
- const files = fs.readdirSync(result.tempDir);
59
- const promptFile = files.find((f: string) => f.endsWith(".md") && f !== "task.md");
60
- assert.ok(promptFile, "expected a prompt.md file");
61
- return fs.readFileSync(path.join(result.tempDir, promptFile), "utf-8");
56
+ function childLaunch(overrides: Partial<BuildInProcessChildLaunchInput> = {}): BuildInProcessChildLaunchInput {
57
+ return {
58
+ host: "parent",
59
+ cwd: process.cwd(),
60
+ sessionEnabled: false,
61
+ inheritProjectContext: false,
62
+ inheritGlobalContext: false,
63
+ inheritSkills: false,
64
+ childAgentName: "worker",
65
+ childIndex: 0,
66
+ ...overrides,
67
+ };
68
+ }
69
+
70
+ /** The system prompt the child session receives (append mode by default). */
71
+ function childSystemPrompt(result: ReturnType<typeof buildInProcessChildLaunch>): string {
72
+ const prompt = result.session.systemPrompt ?? result.session.appendSystemPrompt;
73
+ assert.ok(prompt !== undefined, "expected a child system prompt");
74
+ return prompt;
62
75
  }
63
76
 
64
77
  function escapeRegExp(value: string): string {
@@ -235,20 +248,11 @@ describe("resolvePiLaunchToolPlan with permission system", () => {
235
248
  JSON.stringify({ name: "test", pi: { extensions: ["./src/index.ts"] } }),
236
249
  );
237
250
 
238
- const { args } = buildPiArgs({
239
- baseArgs: ["-p"],
240
- task: "test task",
241
- sessionEnabled: false,
242
- inheritProjectContext: false,
243
- inheritSkills: false,
244
- });
245
- const extensionArgs = args.filter(
246
- (arg, index) => args[index - 1] === "--extension",
247
- );
251
+ const { session } = buildInProcessChildLaunch(childLaunch());
248
252
  assert.equal(
249
- extensionArgs.includes(path.join(extDir, "src", "index.ts")),
253
+ session.extensionPaths.includes(path.join(extDir, "src", "index.ts")),
250
254
  false,
251
- "permission system extension should not be emitted without native rules",
255
+ "permission system extension should not be loaded without native rules",
252
256
  );
253
257
  });
254
258
 
@@ -266,20 +270,10 @@ describe("resolvePiLaunchToolPlan with permission system", () => {
266
270
  JSON.stringify({ name: "test", pi: { extensions: ["./src/index.ts"] } }),
267
271
  );
268
272
 
269
- const { args } = buildPiArgs({
270
- baseArgs: ["-p"],
271
- task: "test task",
272
- sessionEnabled: false,
273
- inheritProjectContext: false,
274
- inheritSkills: false,
275
- permissionRules: { write: "ask" },
276
- });
277
- const extensionArgs = args.filter(
278
- (arg, index) => args[index - 1] === "--extension",
279
- );
273
+ const { session } = buildInProcessChildLaunch(childLaunch({ permissionRules: { write: "ask" } }));
280
274
  assert.ok(
281
- extensionArgs.includes(path.join(extDir, "src", "index.ts")),
282
- "permission system extension should be emitted when native rules are active",
275
+ session.extensionPaths.includes(path.join(extDir, "src", "index.ts")),
276
+ "permission system extension should be loaded when native rules are active",
283
277
  );
284
278
  });
285
279
 
@@ -329,23 +323,15 @@ describe("resolvePiLaunchToolPlan with permission system", () => {
329
323
  });
330
324
  });
331
325
 
332
- describe("buildPiArgs <active_agent> tag injection", () => {
326
+ describe("child launch <active_agent> tag injection", () => {
333
327
  it("prepends <active_agent> tag when childAgentName is set", () => {
334
328
  const { agentDir } = createFixture();
335
329
  process.env.SELESAI_CODING_AGENT_DIR = agentDir;
336
330
 
337
- const result = buildPiArgs({
338
- baseArgs: ["-p"],
339
- task: "test task",
340
- sessionEnabled: false,
331
+ const promptContent = childSystemPrompt(buildInProcessChildLaunch(childLaunch({
341
332
  systemPrompt: "You are a helpful assistant.",
342
- inheritProjectContext: false,
343
- inheritSkills: false,
344
333
  childAgentName: "reviewer",
345
- promptFileStem: "reviewer",
346
- });
347
-
348
- const promptContent = readPromptFile(result);
334
+ })));
349
335
  assert.ok(
350
336
  promptContent.startsWith('<active_agent name="reviewer"/>'),
351
337
  `expected prompt to start with <active_agent> tag, got: ${promptContent.slice(0, 100)}`,
@@ -356,45 +342,29 @@ describe("buildPiArgs <active_agent> tag injection", () => {
356
342
  );
357
343
  });
358
344
 
359
- it("does NOT inject tag when childAgentName is not set", () => {
345
+ it("passes no system prompt when the agent has none", () => {
360
346
  const { agentDir } = createFixture();
361
347
  process.env.SELESAI_CODING_AGENT_DIR = agentDir;
362
348
 
363
- const result = buildPiArgs({
364
- baseArgs: ["-p"],
365
- task: "test task",
366
- sessionEnabled: false,
367
- systemPrompt: "You are a helper.",
368
- inheritProjectContext: false,
369
- inheritSkills: false,
370
- promptFileStem: "test",
371
- });
372
-
373
- const promptContent = readPromptFile(result);
374
- assert.equal(
375
- promptContent.includes("<active_agent"),
376
- false,
377
- "should not inject tag when no childAgentName",
378
- );
379
- assert.equal(promptContent, "You are a helper.");
349
+ const { session } = buildInProcessChildLaunch(childLaunch({ childAgentName: "helper" }));
350
+ assert.equal(session.systemPrompt, undefined);
351
+ assert.equal(session.appendSystemPrompt, undefined);
380
352
  });
381
353
 
382
- it("does NOT inject tag when systemPrompt is empty", () => {
354
+ it("replaces the system prompt in replace mode", () => {
383
355
  const { agentDir } = createFixture();
384
356
  process.env.SELESAI_CODING_AGENT_DIR = agentDir;
385
357
 
386
- const result = buildPiArgs({
387
- baseArgs: ["-p"],
388
- task: "test task",
389
- sessionEnabled: false,
390
- systemPrompt: "",
391
- inheritProjectContext: false,
392
- inheritSkills: false,
393
- childAgentName: "worker",
394
- promptFileStem: "worker",
395
- });
358
+ const { session } = buildInProcessChildLaunch(childLaunch({ systemPrompt: "You are a helper.", systemPromptMode: "replace", childAgentName: "helper" }));
359
+ assert.equal(session.systemPrompt, '<active_agent name="helper"/>\n\nYou are a helper.');
360
+ assert.equal(session.appendSystemPrompt, undefined);
361
+ });
362
+
363
+ it("injects the tag even when systemPrompt is empty", () => {
364
+ const { agentDir } = createFixture();
365
+ process.env.SELESAI_CODING_AGENT_DIR = agentDir;
396
366
 
397
- const promptContent = readPromptFile(result);
367
+ const promptContent = childSystemPrompt(buildInProcessChildLaunch(childLaunch({ systemPrompt: "", childAgentName: "worker" })));
398
368
  assert.ok(promptContent.startsWith('<active_agent name="worker"/>'));
399
369
  });
400
370
 
@@ -402,18 +372,10 @@ describe("buildPiArgs <active_agent> tag injection", () => {
402
372
  const { agentDir } = createFixture();
403
373
  process.env.SELESAI_CODING_AGENT_DIR = agentDir;
404
374
 
405
- const result = buildPiArgs({
406
- baseArgs: ["-p"],
407
- task: "test task",
408
- sessionEnabled: false,
375
+ const promptContent = childSystemPrompt(buildInProcessChildLaunch(childLaunch({
409
376
  systemPrompt: "System prompt here",
410
- inheritProjectContext: false,
411
- inheritSkills: false,
412
377
  childAgentName: 'my "special" agent',
413
- promptFileStem: "test",
414
- });
415
-
416
- const promptContent = readPromptFile(result);
378
+ })));
417
379
  assert.ok(
418
380
  promptContent.startsWith('<active_agent name="my &quot;special&quot; agent"/>'),
419
381
  `expected escaped tag, got: ${promptContent.slice(0, 120)}`,
@@ -434,4 +396,4 @@ describe("buildPiArgs <active_agent> tag injection", () => {
434
396
  "prompt runtime extension should always be included",
435
397
  );
436
398
  });
437
- });
399
+ });
@@ -0,0 +1,33 @@
1
+ import assert from "node:assert/strict";
2
+ import * as fs from "node:fs";
3
+ import * as os from "node:os";
4
+ import * as path from "node:path";
5
+ import { describe, it } from "node:test";
6
+ import { resolvePiLaunchToolPlan } from "../../src/runs/shared/child-tool-plan.ts";
7
+ import { MCP_RUNTIME_SNAPSHOT_EVENT, MCP_RUNTIME_SNAPSHOT_VERSION, type McpRuntimeSnapshotHost } from "../../src/runs/shared/mcp-direct-tool-allowlist.ts";
8
+
9
+ /** A parent whose pi-mcp-adapter answers snapshot requests for one runtime-only server. */
10
+ function runtimeSnapshotHost(serverName: string): McpRuntimeSnapshotHost {
11
+ return {
12
+ events: {
13
+ emit(event, request) {
14
+ if (event !== MCP_RUNTIME_SNAPSHOT_EVENT || request.version !== MCP_RUNTIME_SNAPSHOT_VERSION || request.name !== serverName) return;
15
+ request.result = { ok: true, snapshot: { name: serverName, runtime: true, persisted: false, definition: { command: "node", args: ["server.js"] } } };
16
+ },
17
+ },
18
+ };
19
+ }
20
+
21
+ describe("child tool plan", () => {
22
+ it("fails a launch that selects MCP tools from the adapter's runtime snapshot", () => {
23
+ const cwd = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagents-runtime-mcp-"));
24
+ try {
25
+ assert.throws(
26
+ () => resolvePiLaunchToolPlan({ tools: ["read"], mcpDirectTools: ["runtime-only/search"], cwd, agentName: "browser", runtimeSnapshotHost: runtimeSnapshotHost("runtime-only") }),
27
+ /cannot be provided to in-process children; MCP tools must come from an ambient adapter extension in a background child/,
28
+ );
29
+ } finally {
30
+ fs.rmSync(cwd, { recursive: true, force: true });
31
+ }
32
+ });
33
+ });
@@ -19,49 +19,49 @@ describe("async compaction resume", () => {
19
19
  let renders = 0;
20
20
  const pi = new Proxy({
21
21
  events,
22
- on(name, handler) { handlers.set(name, handler); },
22
+ on(name, handler) { handlers.set(name, [...(handlers.get(name) ?? []), handler]); },
23
23
  registerTool() {}, registerCommand() {}, registerShortcut() {}, registerMessageRenderer() {},
24
24
  sendMessage(message, options) { sent.push({ message, options }); }, getSessionName() { return undefined; },
25
25
  }, { get(target, prop) { return prop in target ? target[prop] : () => undefined; } });
26
26
  const ctx = { cwd: process.cwd(), hasUI: true, ui: { setWidget(key, value) { widgets.push([key, value]); }, requestRender() { renders++; }, onTerminalInput() { return () => {}; }, getEditorText() { return ""; }, notify() {}, theme: { fg(_name, text) { return text; }, bg(_name, text) { return text; }, bold(text) { return text; } } }, sessionManager: { getSessionId() { return "compact-session"; }, getSessionFile() { return null; }, getEntries() { return []; } }, modelRegistry: { getAvailable() { return []; } } };
27
27
  registerSubagentExtension(pi);
28
- handlers.get("session_start")({}, ctx);
28
+ for (const handler of handlers.get("session_start")) await handler({}, ctx);
29
29
  sent.length = 0;
30
30
  events.emit("subagent:async-started", { id: "running", pid: 1, sessionId: "compact-session", mode: "single", agent: "worker", asyncDir: path.join(os.tmpdir(), "pi-compaction-test-running") });
31
31
  widgets.length = 0;
32
32
  renders = 0;
33
- handlers.get("session_before_compact")({ reason: "threshold", signal: new AbortController().signal });
33
+ for (const handler of handlers.get("session_before_compact")) await handler({ reason: "threshold", signal: new AbortController().signal });
34
34
  const cleared = widgets.filter(([key, value]) => value === undefined).map(([key]) => key).sort();
35
35
  if (JSON.stringify(cleared) !== JSON.stringify(["subagent-async", "subagent-fleet-status"])) throw new Error(JSON.stringify(widgets));
36
36
  widgets.length = 0;
37
37
  events.emit("subagent:async-complete", { id: "running", sessionId: "compact-session", agent: "worker", success: true, summary: "done" });
38
38
  events.emit("subagent:async-started", { id: "running-2", pid: 2, sessionId: "compact-session", mode: "single", agent: "worker", asyncDir: path.join(os.tmpdir(), "pi-compaction-test-running-2") });
39
39
  if (widgets.length !== 0 || renders !== 0) throw new Error("widgets repainted during compaction");
40
- handlers.get("session_compact")({ reason: "threshold" });
40
+ for (const handler of handlers.get("session_compact")) await handler({ reason: "threshold" });
41
41
  if (widgets.length !== 0) throw new Error("widgets restored inside compaction hook");
42
- handlers.get("agent_start")();
42
+ for (const handler of handlers.get("agent_start")) await handler();
43
43
  const restored = widgets.filter(([_, value]) => value !== undefined).map(([key]) => key).sort();
44
44
  if (JSON.stringify(restored) !== JSON.stringify(["subagent-async", "subagent-fleet-status"])) throw new Error(JSON.stringify(widgets));
45
45
  if (sent.length !== 1 || sent[0].options?.triggerTurn !== true || sent[0].message?.customType !== "subagent-compaction-resume") throw new Error(JSON.stringify(sent));
46
46
 
47
47
  sent.length = 0;
48
48
  events.emit("subagent:async-complete", { id: "running-2", sessionId: "compact-session", agent: "worker", success: true, summary: "done" });
49
- handlers.get("session_before_compact")({ reason: "threshold", signal: new AbortController().signal });
50
- handlers.get("session_compact")({ reason: "threshold" });
51
- handlers.get("agent_settled")();
49
+ for (const handler of handlers.get("session_before_compact")) await handler({ reason: "threshold", signal: new AbortController().signal });
50
+ for (const handler of handlers.get("session_compact")) await handler({ reason: "threshold" });
51
+ for (const handler of handlers.get("agent_settled")) await handler();
52
52
  if (sent.some((entry) => entry.message?.customType === "subagent-compaction-resume")) throw new Error("resumed without active work");
53
53
 
54
54
  events.emit("subagent:async-started", { id: "running-3", pid: 3, sessionId: "compact-session", mode: "single", agent: "worker", asyncDir: path.join(os.tmpdir(), "pi-compaction-test-running-3") });
55
55
  widgets.length = 0;
56
- handlers.get("session_before_compact")({ reason: "overflow", signal: new AbortController().signal });
56
+ for (const handler of handlers.get("session_before_compact")) await handler({ reason: "overflow", signal: new AbortController().signal });
57
57
  widgets.length = 0;
58
- handlers.get("agent_settled")();
58
+ for (const handler of handlers.get("agent_settled")) await handler();
59
59
  if (!widgets.some(([_, value]) => value !== undefined)) throw new Error("widgets did not recover after compaction failure");
60
60
 
61
61
  widgets.length = 0;
62
- handlers.get("session_before_compact")({ reason: "manual", signal: new AbortController().signal });
62
+ for (const handler of handlers.get("session_before_compact")) await handler({ reason: "manual", signal: new AbortController().signal });
63
63
  if (widgets.length !== 0) throw new Error("manual compaction changed widget state");
64
- await handlers.get("session_shutdown")();
64
+ for (const handler of handlers.get("session_shutdown")) await handler();
65
65
  `;
66
66
  const env = { ...process.env };
67
67
  delete env.SELESAI_SUBAGENT_CHILD;
@@ -76,23 +76,23 @@ describe("async compaction resume", () => {
76
76
  const events = { listeners: new Map(), on(name, handler) { this.listeners.set(name, handler); return () => this.listeners.delete(name); }, emit(name, payload) { this.listeners.get(name)?.(payload); } };
77
77
  const pi = new Proxy({
78
78
  events,
79
- on(name, handler) { handlers.set(name, handler); },
79
+ on(name, handler) { handlers.set(name, [...(handlers.get(name) ?? []), handler]); },
80
80
  registerTool() {}, registerCommand() {}, registerShortcut() {}, registerMessageRenderer() {},
81
81
  sendMessage() {}, getSessionName() { return undefined; },
82
82
  }, { get(target, prop) { return prop in target ? target[prop] : () => undefined; } });
83
83
  let stale = false;
84
84
  const ctx = { cwd: process.cwd(), get hasUI() { if (stale) throw new Error("This extension ctx is stale after session replacement or reload."); return true; }, ui: { setWidget() {}, requestRender() {}, onTerminalInput() { return () => {}; }, getEditorText() { return ""; }, notify() {}, theme: { fg(_name, text) { return text; }, bg(_name, text) { return text; }, bold(text) { return text; } } }, sessionManager: { getSessionId() { return "stale-context-session"; }, getSessionFile() { return null; }, getEntries() { return []; } }, modelRegistry: { getAvailable() { return []; } } };
85
85
  registerSubagentExtension(pi);
86
- handlers.get("session_start")({}, ctx);
86
+ for (const handler of handlers.get("session_start")) await handler({}, ctx);
87
87
  events.emit("subagent:async-started", { id: "running", sessionId: "stale-context-session", mode: "single", agent: "worker", asyncDir: "/tmp/pi-stale-context-running" });
88
88
  stale = true;
89
- handlers.get("session_compact")({ reason: "threshold" });
90
- handlers.get("session_before_compact")({ reason: "threshold", signal: new AbortController().signal });
91
- await handlers.get("session_shutdown")();
89
+ for (const handler of handlers.get("session_compact")) await handler({ reason: "threshold" });
90
+ for (const handler of handlers.get("session_before_compact")) await handler({ reason: "threshold", signal: new AbortController().signal });
91
+ for (const handler of handlers.get("session_shutdown")) await handler();
92
92
  `;
93
93
  const env = { ...process.env };
94
94
  delete env.SELESAI_SUBAGENT_CHILD;
95
95
  execFileSync(process.execPath, ["--experimental-strip-types", "--import", "./test/support/register-loader.mjs", "--input-type=module", "--eval", script], { cwd: projectRoot, env, stdio: "pipe" });
96
96
  assert.ok(true);
97
97
  });
98
- });
98
+ });
@@ -23,7 +23,7 @@ describe("planCompletionEvidence", () => {
23
23
  implementationMutationExpected: true,
24
24
  mutationAttemptObserved: false,
25
25
  mutationEvidence: evidence,
26
- agentContractV1: false,
26
+ agentContractEnabled: false,
27
27
  });
28
28
 
29
29
  assert.equal(plan.guardTriggered, true);
@@ -37,14 +37,14 @@ describe("planCompletionEvidence", () => {
37
37
  });
38
38
  });
39
39
 
40
- it("keeps agent contract v1 rejection in evidence without forcing execution failure", () => {
40
+ it("keeps agent contract rejection in evidence without forcing execution failure", () => {
41
41
  const plan = planCompletionEvidence({
42
42
  guard: { expectedMutation: true, attemptedMutation: false, triggered: true, blocked: false },
43
43
  completionGuardEnabled: true,
44
44
  mutationCapable: true,
45
45
  implementationMutationExpected: true,
46
46
  mutationAttemptObserved: false,
47
- agentContractV1: true,
47
+ agentContractEnabled: true,
48
48
  });
49
49
 
50
50
  assert.equal(plan.guardTriggered, true);
@@ -59,7 +59,7 @@ describe("planCompletionEvidence", () => {
59
59
  mutationCapable: false,
60
60
  implementationMutationExpected: true,
61
61
  mutationAttemptObserved: true,
62
- agentContractV1: false,
62
+ agentContractEnabled: false,
63
63
  });
64
64
  assert.deepEqual(blocked.fileMutation, {
65
65
  status: "blocked",
@@ -86,7 +86,7 @@ describe("planCompletionEvidence", () => {
86
86
  implementationMutationExpected: true,
87
87
  mutationAttemptObserved: false,
88
88
  arbiterRescued: true,
89
- agentContractV1: false,
89
+ agentContractEnabled: false,
90
90
  });
91
91
  assert.deepEqual(rescued.fileMutation, {
92
92
  status: "not-applicable",
@@ -103,7 +103,7 @@ describe("planCompletionEvidence", () => {
103
103
  mutationCapable: true,
104
104
  implementationMutationExpected: true,
105
105
  mutationAttemptObserved: false,
106
- agentContractV1: false,
106
+ agentContractEnabled: false,
107
107
  });
108
108
  assert.equal(plan.mutationExpected, true);
109
109
  assert.equal(plan.fileMutation, undefined);
@@ -117,7 +117,7 @@ describe("projectSettlementDiagnostic", () => {
117
117
  mutationCapable: true,
118
118
  implementationMutationExpected: true,
119
119
  mutationAttemptObserved: false,
120
- agentContractV1: false,
120
+ agentContractEnabled: false,
121
121
  });
122
122
  assert.deepEqual(projectSettlementDiagnostic(plan, {
123
123
  terminalFailed: true,
@@ -139,7 +139,7 @@ describe("projectSettlementDiagnostic", () => {
139
139
  mutationCapable: false,
140
140
  implementationMutationExpected: false,
141
141
  mutationAttemptObserved: false,
142
- agentContractV1: false,
142
+ agentContractEnabled: false,
143
143
  });
144
144
  assert.equal(projectSettlementDiagnostic(plan, {
145
145
  terminalFailed: false,
@@ -147,4 +147,4 @@ describe("projectSettlementDiagnostic", () => {
147
147
  mutationObserved: false,
148
148
  }), undefined);
149
149
  });
150
- });
150
+ });
@@ -53,7 +53,7 @@ function revivedTask(followUp: string): string {
53
53
  "Original agent: worker",
54
54
  "Original session file: /tmp/session.jsonl",
55
55
  "",
56
- "Use the stored session context as background. Answer the orchestrator's follow-up below. Do not assume the original child process is still alive.",
56
+ "Use the stored session context as background. Answer the orchestrator's follow-up below. Do not assume the original child session is still running.",
57
57
  "",
58
58
  "Follow-up:",
59
59
  followUp,
@@ -241,12 +241,13 @@ test("implementation challenge reports with negated or uncertain no-better-chang
241
241
 
242
242
  });
243
243
 
244
- test("declared read-only builtin tools suppress implementation-word false positives", () => {
244
+ test("source_check read-only capability suppresses an implementation completion guard", () => {
245
+ assert.equal(expectsImplementationMutation("worker", "Implement the approved fix"), true);
245
246
  const result = evaluateCompletionMutationGuard({
246
- agent: "architect",
247
- task: "Produce a proposal that implements the approved fix",
248
- messages: [assistantText("Proposal only")],
249
- tools: ["read", "grep", "find", "ls"],
247
+ agent: "worker",
248
+ task: "Implement the approved fix",
249
+ messages: [assistantText("Source evidence only")],
250
+ tools: ["source_check"],
250
251
  });
251
252
 
252
253
  assert.deepEqual(result, {
@@ -750,4 +751,4 @@ test("read-only agents and pure extension workers keep their launch contracts",
750
751
  requestedTools: ["read"],
751
752
  completionGuard: false,
752
753
  }), undefined);
753
- });
754
+ });