@selesai/code 0.5.20 → 0.5.21

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 (263) hide show
  1. package/dist/extensions/handoff-new.test.ts +8 -9
  2. package/dist/extensions/handoff-new.ts +6 -8
  3. package/dist/extensions/pi-subagents/CHANGELOG.md +1367 -0
  4. package/dist/extensions/pi-subagents/README.md +602 -220
  5. package/dist/extensions/pi-subagents/banner.png +0 -0
  6. package/dist/extensions/pi-subagents/index.ts +1 -0
  7. package/dist/extensions/pi-subagents/install.mjs +3 -3
  8. package/dist/extensions/pi-subagents/package-lock.json +3405 -0
  9. package/dist/extensions/pi-subagents/package.json +26 -14
  10. package/dist/extensions/pi-subagents/prompts/gather-context-and-clarify.md +1 -1
  11. package/dist/extensions/pi-subagents/prompts/parallel-cleanup.md +9 -9
  12. package/dist/extensions/pi-subagents/prompts/parallel-context-build.md +3 -3
  13. package/dist/extensions/pi-subagents/prompts/parallel-handoff-plan.md +7 -7
  14. package/dist/extensions/pi-subagents/prompts/parallel-research.md +6 -6
  15. package/dist/extensions/pi-subagents/prompts/parallel-review.md +8 -8
  16. package/dist/extensions/pi-subagents/prompts/review-loop.md +13 -11
  17. package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +267 -176
  18. package/dist/extensions/pi-subagents/src/agents/agent-management.ts +89 -16
  19. package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +19 -0
  20. package/dist/extensions/pi-subagents/src/agents/agents.ts +218 -120
  21. package/dist/extensions/pi-subagents/src/agents/frontmatter.ts +67 -13
  22. package/dist/extensions/pi-subagents/src/agents/proactive-skills.ts +2 -2
  23. package/dist/extensions/pi-subagents/src/agents/skills.ts +25 -12
  24. package/dist/extensions/pi-subagents/src/api/background-work.ts +197 -0
  25. package/dist/extensions/pi-subagents/src/api/capability-ceiling.ts +17 -0
  26. package/dist/extensions/pi-subagents/src/api/delegation.ts +285 -0
  27. package/dist/extensions/pi-subagents/src/api/preflight.ts +399 -0
  28. package/dist/extensions/pi-subagents/src/extension/chain-validation.ts +165 -0
  29. package/dist/extensions/pi-subagents/src/extension/config.ts +7 -1
  30. package/dist/extensions/pi-subagents/src/extension/doctor.ts +15 -0
  31. package/dist/extensions/pi-subagents/src/extension/fanout-child.ts +3 -1
  32. package/dist/extensions/pi-subagents/src/extension/index.ts +113 -157
  33. package/dist/extensions/pi-subagents/src/extension/rpc.ts +41 -4
  34. package/dist/extensions/pi-subagents/src/extension/schemas.ts +45 -15
  35. package/dist/extensions/pi-subagents/src/extension/steering-notices.ts +35 -0
  36. package/dist/extensions/pi-subagents/src/extension/tool-description.ts +28 -15
  37. package/dist/extensions/pi-subagents/src/intercom/intercom-bridge.ts +4 -3
  38. package/dist/extensions/pi-subagents/src/intercom/native-supervisor-channel.ts +225 -29
  39. package/dist/extensions/pi-subagents/src/intercom/result-intercom.ts +11 -0
  40. package/dist/extensions/pi-subagents/src/profiles/profiles.ts +8 -10
  41. package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +452 -62
  42. package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +60 -9
  43. package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +198 -52
  44. package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +119 -21
  45. package/dist/extensions/pi-subagents/src/runs/background/auto-drain.ts +67 -0
  46. package/dist/extensions/pi-subagents/src/runs/background/chain-append.ts +2 -0
  47. package/dist/extensions/pi-subagents/src/runs/background/chain-root-attachment.ts +16 -8
  48. package/dist/extensions/pi-subagents/src/runs/background/completion-batcher.ts +6 -4
  49. package/dist/extensions/pi-subagents/src/runs/background/completion-dedupe.ts +2 -11
  50. package/dist/extensions/pi-subagents/src/runs/background/control-channel.ts +260 -13
  51. package/dist/extensions/pi-subagents/src/runs/background/fleet-view.ts +32 -6
  52. package/dist/extensions/pi-subagents/src/runs/background/notify.ts +171 -90
  53. package/dist/extensions/pi-subagents/src/runs/background/process-terminal.ts +280 -0
  54. package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +149 -88
  55. package/dist/extensions/pi-subagents/src/runs/background/run-id-resolver.ts +14 -2
  56. package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +33 -17
  57. package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +9 -1
  58. package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +38 -10
  59. package/dist/extensions/pi-subagents/src/runs/background/steering.ts +237 -0
  60. package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +1297 -307
  61. package/dist/extensions/pi-subagents/src/runs/background/subagent-wait.ts +610 -0
  62. package/dist/extensions/pi-subagents/src/runs/background/top-level-async.ts +2 -1
  63. package/dist/extensions/pi-subagents/src/runs/background/wait-config.ts +36 -0
  64. package/dist/extensions/pi-subagents/src/runs/background/wait-tool.ts +26 -0
  65. package/dist/extensions/pi-subagents/src/runs/foreground/async-steering-action.ts +230 -0
  66. package/dist/extensions/pi-subagents/src/runs/foreground/chain-clarify.ts +22 -6
  67. package/dist/extensions/pi-subagents/src/runs/foreground/chain-execution.ts +228 -140
  68. package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +452 -138
  69. package/dist/extensions/pi-subagents/src/runs/foreground/foreground-control.ts +90 -0
  70. package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +1001 -416
  71. package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +443 -132
  72. package/dist/extensions/pi-subagents/src/runs/shared/agent-contract.ts +38 -0
  73. package/dist/extensions/pi-subagents/src/runs/shared/capability-ceiling.ts +178 -0
  74. package/dist/extensions/pi-subagents/src/runs/shared/child-protocol.ts +121 -0
  75. package/dist/extensions/pi-subagents/src/runs/shared/completion-guard.ts +41 -93
  76. package/dist/extensions/pi-subagents/src/runs/shared/context-mode.ts +44 -0
  77. package/dist/extensions/pi-subagents/src/runs/shared/dynamic-fanout.ts +11 -9
  78. package/dist/extensions/pi-subagents/src/runs/shared/long-running-guard.ts +4 -0
  79. package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +12 -6
  80. package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +36 -0
  81. package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +44 -7
  82. package/dist/extensions/pi-subagents/src/runs/shared/nested-render.ts +4 -1
  83. package/dist/extensions/pi-subagents/src/runs/shared/parallel-handoff.ts +154 -0
  84. package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +18 -0
  85. package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +174 -54
  86. package/dist/extensions/pi-subagents/src/runs/shared/pi-spawn.ts +38 -31
  87. package/dist/extensions/pi-subagents/src/runs/shared/run-history.ts +90 -5
  88. package/dist/extensions/pi-subagents/src/runs/shared/session-lease.ts +299 -0
  89. package/dist/extensions/pi-subagents/src/runs/shared/single-output.ts +61 -6
  90. package/dist/extensions/pi-subagents/src/runs/shared/spawn-budget.ts +128 -0
  91. package/dist/extensions/pi-subagents/src/runs/shared/structured-output.ts +112 -7
  92. package/dist/extensions/pi-subagents/src/runs/shared/subagent-control.ts +14 -6
  93. package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +149 -36
  94. package/dist/extensions/pi-subagents/src/runs/shared/task-intent.ts +181 -0
  95. package/dist/extensions/pi-subagents/src/runs/shared/tool-availability.ts +83 -0
  96. package/dist/extensions/pi-subagents/src/runs/shared/tool-budget.ts +11 -5
  97. package/dist/extensions/pi-subagents/src/runs/shared/turn-budget.ts +50 -4
  98. package/dist/extensions/pi-subagents/src/runs/shared/worktree.ts +63 -14
  99. package/dist/extensions/pi-subagents/src/shared/accessible-dir.ts +25 -0
  100. package/dist/extensions/pi-subagents/src/shared/artifacts.ts +37 -7
  101. package/dist/extensions/pi-subagents/src/shared/atomic-json.ts +18 -43
  102. package/dist/extensions/pi-subagents/src/shared/child-transcript.ts +52 -0
  103. package/dist/extensions/pi-subagents/src/shared/env.ts +16 -0
  104. package/dist/extensions/pi-subagents/src/shared/file-system-retry.ts +47 -0
  105. package/dist/extensions/pi-subagents/src/shared/fork-context.ts +28 -3
  106. package/dist/extensions/pi-subagents/src/shared/launch-contract.ts +123 -0
  107. package/dist/extensions/pi-subagents/src/shared/model-info.ts +8 -5
  108. package/dist/extensions/pi-subagents/src/shared/settings.ts +9 -1
  109. package/dist/extensions/pi-subagents/src/shared/status-format.ts +7 -1
  110. package/dist/extensions/pi-subagents/src/shared/types.ts +522 -51
  111. package/dist/extensions/pi-subagents/src/shared/utils.ts +59 -53
  112. package/dist/extensions/pi-subagents/src/slash/delegation-adapters.ts +604 -0
  113. package/dist/extensions/pi-subagents/src/slash/delegation-json.ts +108 -0
  114. package/dist/extensions/pi-subagents/src/slash/delegation-request.ts +249 -0
  115. package/dist/extensions/pi-subagents/src/slash/prompt-template-bridge.ts +353 -345
  116. package/dist/extensions/pi-subagents/src/slash/prompt-workflows.ts +2 -2
  117. package/dist/extensions/pi-subagents/src/slash/selector.ts +147 -0
  118. package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +265 -23
  119. package/dist/extensions/pi-subagents/src/slash/slash-live-state.ts +2 -2
  120. package/dist/extensions/pi-subagents/src/slash/subagents-admin.ts +428 -0
  121. package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +362 -0
  122. package/dist/extensions/pi-subagents/src/tui/fleet-transcript.ts +472 -0
  123. package/dist/extensions/pi-subagents/src/tui/fleet.ts +664 -0
  124. package/dist/extensions/pi-subagents/src/tui/render.ts +115 -31
  125. package/dist/extensions/pi-subagents/src/watchdog/change-signature.ts +220 -0
  126. package/dist/extensions/pi-subagents/src/watchdog/child-status.ts +205 -0
  127. package/dist/extensions/pi-subagents/src/watchdog/emission-guard.ts +123 -0
  128. package/dist/extensions/pi-subagents/src/watchdog/lsp-diagnostics.ts +532 -0
  129. package/dist/extensions/pi-subagents/src/watchdog/model-selection.ts +167 -0
  130. package/dist/extensions/pi-subagents/src/watchdog/register-child.ts +117 -0
  131. package/dist/extensions/pi-subagents/src/watchdog/register-main.ts +433 -0
  132. package/dist/extensions/pi-subagents/src/watchdog/render.ts +54 -0
  133. package/dist/extensions/pi-subagents/src/watchdog/review.ts +298 -0
  134. package/dist/extensions/pi-subagents/src/watchdog/runtime.ts +714 -0
  135. package/dist/extensions/pi-subagents/src/watchdog/settings.ts +528 -0
  136. package/dist/extensions/pi-subagents/src/watchdog/tool-actions.ts +155 -0
  137. package/dist/extensions/pi-subagents/src/watchdog/turn-delta.ts +161 -0
  138. package/dist/extensions/pi-subagents/src/watchdog/types.ts +188 -0
  139. package/dist/extensions/pi-subagents/src/watchdog/warning-format.ts +73 -0
  140. package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +130 -2
  141. package/dist/extensions/pi-subagents/test/integration/acceptance-file-report.test.ts +439 -0
  142. package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +1632 -61
  143. package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +54 -1
  144. package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +112 -0
  145. package/dist/extensions/pi-subagents/test/integration/chain-clarify.test.ts +98 -1
  146. package/dist/extensions/pi-subagents/test/integration/chain-execution.test.ts +179 -9
  147. package/dist/extensions/pi-subagents/test/integration/detect-error.test.ts +16 -9
  148. package/dist/extensions/pi-subagents/test/integration/error-handling.test.ts +6 -5
  149. package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +589 -9
  150. package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +528 -21
  151. package/dist/extensions/pi-subagents/test/integration/parallel-execution.test.ts +227 -3
  152. package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +235 -7
  153. package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +27 -0
  154. package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +172 -2
  155. package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +1502 -18
  156. package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +993 -4
  157. package/dist/extensions/pi-subagents/test/integration/slash-live-state.test.ts +27 -0
  158. package/dist/extensions/pi-subagents/test/integration/top-level-async.test.ts +7 -1
  159. package/dist/extensions/pi-subagents/test/support/helpers.ts +32 -0
  160. package/dist/extensions/pi-subagents/test/support/mock-pi-script.mjs +59 -2
  161. package/dist/extensions/pi-subagents/test/support/mock-pi.ts +32 -6
  162. package/dist/extensions/pi-subagents/test/support/real-session-child-cli.mjs +25 -24
  163. package/dist/extensions/pi-subagents/test/support/real-session-runner.ts +59 -35
  164. package/dist/extensions/pi-subagents/test/support/session-lease-child.mjs +42 -0
  165. package/dist/extensions/pi-subagents/test/unit/acceptance.test.ts +703 -69
  166. package/dist/extensions/pi-subagents/test/unit/accessible-dir.test.ts +82 -0
  167. package/dist/extensions/pi-subagents/test/unit/agent-disabled.test.ts +15 -15
  168. package/dist/extensions/pi-subagents/test/unit/agent-eject-disable.test.ts +66 -66
  169. package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +478 -19
  170. package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +228 -7
  171. package/dist/extensions/pi-subagents/test/unit/agent-memory.test.ts +1 -1
  172. package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +198 -78
  173. package/dist/extensions/pi-subagents/test/unit/async-execution.test.ts +15 -1
  174. package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +102 -7
  175. package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +439 -6
  176. package/dist/extensions/pi-subagents/test/unit/atomic-json.test.ts +41 -1
  177. package/dist/extensions/pi-subagents/test/unit/auto-drain.test.ts +79 -0
  178. package/dist/extensions/pi-subagents/test/unit/background-work.test.ts +285 -0
  179. package/dist/extensions/pi-subagents/test/unit/capability-ceiling-pi-args.test.ts +84 -0
  180. package/dist/extensions/pi-subagents/test/unit/capability-ceiling.test.ts +68 -0
  181. package/dist/extensions/pi-subagents/test/unit/chain-validation.test.ts +326 -0
  182. package/dist/extensions/pi-subagents/test/unit/child-protocol.test.ts +82 -0
  183. package/dist/extensions/pi-subagents/test/unit/child-transcript.test.ts +46 -4
  184. package/dist/extensions/pi-subagents/test/unit/completion-batcher.test.ts +3 -1
  185. package/dist/extensions/pi-subagents/test/unit/completion-dedupe.test.ts +9 -17
  186. package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +175 -3
  187. package/dist/extensions/pi-subagents/test/unit/config-dir-runtime.test.ts +10 -5
  188. package/dist/extensions/pi-subagents/test/unit/control-channel.test.ts +126 -6
  189. package/dist/extensions/pi-subagents/test/unit/default-extensions.test.ts +219 -0
  190. package/dist/extensions/pi-subagents/test/unit/delegation-api.test.ts +913 -0
  191. package/dist/extensions/pi-subagents/test/unit/doctor.test.ts +13 -2
  192. package/dist/extensions/pi-subagents/test/unit/dynamic-fanout.test.ts +3 -3
  193. package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +351 -0
  194. package/dist/extensions/pi-subagents/test/unit/fleet-transcript.test.ts +280 -0
  195. package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +575 -0
  196. package/dist/extensions/pi-subagents/test/unit/foreground-control.test.ts +65 -0
  197. package/dist/extensions/pi-subagents/test/unit/fork-context.test.ts +94 -1
  198. package/dist/extensions/pi-subagents/test/unit/get-final-output.test.ts +23 -0
  199. package/dist/extensions/pi-subagents/test/unit/host-peer-runtime-imports.test.ts +157 -0
  200. package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +367 -5
  201. package/dist/extensions/pi-subagents/test/unit/intercom-bridge.test.ts +11 -0
  202. package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +36 -0
  203. package/dist/extensions/pi-subagents/test/unit/model-info.test.ts +25 -3
  204. package/dist/extensions/pi-subagents/test/unit/model-scope.test.ts +1 -1
  205. package/dist/extensions/pi-subagents/test/unit/native-supervisor-channel.test.ts +341 -10
  206. package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +16 -0
  207. package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +52 -0
  208. package/dist/extensions/pi-subagents/test/unit/notify.test.ts +168 -7
  209. package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +85 -7
  210. package/dist/extensions/pi-subagents/test/unit/parallel-handoff.test.ts +175 -0
  211. package/dist/extensions/pi-subagents/test/unit/path-resolution.test.ts +1 -1
  212. package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +243 -16
  213. package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +79 -36
  214. package/dist/extensions/pi-subagents/test/unit/pi-spawn.test.ts +174 -56
  215. package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +322 -0
  216. package/dist/extensions/pi-subagents/test/unit/process-terminal.test.ts +204 -0
  217. package/dist/extensions/pi-subagents/test/unit/recursion-guard.test.ts +20 -12
  218. package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +117 -4
  219. package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +40 -7
  220. package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +48 -1
  221. package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +21 -3
  222. package/dist/extensions/pi-subagents/test/unit/selector.test.ts +57 -0
  223. package/dist/extensions/pi-subagents/test/unit/session-lease.test.ts +326 -0
  224. package/dist/extensions/pi-subagents/test/unit/single-output.test.ts +101 -2
  225. package/dist/extensions/pi-subagents/test/unit/skills-fallback.test.ts +111 -1
  226. package/dist/extensions/pi-subagents/test/unit/spawn-budget.test.ts +124 -0
  227. package/dist/extensions/pi-subagents/test/unit/stale-run-reconciler.test.ts +6 -4
  228. package/dist/extensions/pi-subagents/test/unit/status-format.test.ts +7 -0
  229. package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +397 -0
  230. package/dist/extensions/pi-subagents/test/unit/steering-notices.test.ts +58 -0
  231. package/dist/extensions/pi-subagents/test/unit/steering.test.ts +173 -0
  232. package/dist/extensions/pi-subagents/test/unit/subagent-control.test.ts +25 -4
  233. package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +390 -25
  234. package/dist/extensions/pi-subagents/test/unit/subagent-wait.test.ts +837 -0
  235. package/dist/extensions/pi-subagents/test/unit/task-intent.test.ts +86 -0
  236. package/dist/extensions/pi-subagents/test/unit/tool-budget.test.ts +15 -0
  237. package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +47 -1
  238. package/dist/extensions/pi-subagents/test/unit/turn-budget.test.ts +56 -10
  239. package/dist/extensions/pi-subagents/test/unit/watchdog-change-signature.test.ts +387 -0
  240. package/dist/extensions/pi-subagents/test/unit/watchdog-child-status.test.ts +110 -0
  241. package/dist/extensions/pi-subagents/test/unit/watchdog-emission-guard.test.ts +62 -0
  242. package/dist/extensions/pi-subagents/test/unit/watchdog-lsp-diagnostics.test.ts +144 -0
  243. package/dist/extensions/pi-subagents/test/unit/watchdog-model-selection.test.ts +121 -0
  244. package/dist/extensions/pi-subagents/test/unit/watchdog-render.test.ts +76 -0
  245. package/dist/extensions/pi-subagents/test/unit/watchdog-review.test.ts +327 -0
  246. package/dist/extensions/pi-subagents/test/unit/watchdog-runtime.test.ts +863 -0
  247. package/dist/extensions/pi-subagents/test/unit/watchdog-settings.test.ts +290 -0
  248. package/dist/extensions/pi-subagents/test/unit/watchdog-tool-actions.test.ts +91 -0
  249. package/dist/extensions/pi-subagents/test/unit/watchdog-turn-delta.test.ts +130 -0
  250. package/dist/extensions/pi-subagents/test/unit/widget-nested-render.test.ts +32 -4
  251. package/dist/extensions/pi-subagents/test/unit/worktree.test.ts +5 -1
  252. package/dist/extensions/pi-subagents/test/unit/writer-budget-guidance.test.ts +30 -0
  253. package/dist/extensions/question/batch.ts +39 -0
  254. package/dist/extensions/question/dialog-adapter.ts +23 -1
  255. package/dist/extensions/question/index.ts +237 -7
  256. package/dist/extensions/question/schemas.ts +28 -15
  257. package/dist/extensions/question/tests/batch.test.ts +26 -0
  258. package/dist/extensions/question/tests/ui-protocol.test.ts +23 -3
  259. package/dist/extensions/question/tui-adapter.ts +2 -3
  260. package/dist/extensions/question/types.ts +37 -0
  261. package/dist/extensions/question/ui-protocol.ts +3 -3
  262. package/dist/skills/batch-grill-me/SKILL.md +3 -1
  263. package/package.json +1 -1
@@ -10,6 +10,7 @@
10
10
 
11
11
  import { describe, it, before, after, beforeEach, afterEach } from "node:test";
12
12
  import assert from "node:assert/strict";
13
+ import { spawnSync } from "node:child_process";
13
14
  import * as fs from "node:fs";
14
15
  import * as path from "node:path";
15
16
  import type { MockPi } from "../support/helpers.ts";
@@ -40,6 +41,8 @@ interface TestSequentialStep {
40
41
  progress?: boolean;
41
42
  cwd?: string;
42
43
  acceptance?: unknown;
44
+ agentContract?: { version: 1 };
45
+ gateOn?: "execution" | "acceptance";
43
46
  }
44
47
 
45
48
  interface TestParallelTask {
@@ -57,6 +60,8 @@ interface TestParallelTask {
57
60
  progress?: boolean;
58
61
  cwd?: string;
59
62
  acceptance?: unknown;
63
+ agentContract?: { version: 1 };
64
+ gateOn?: "execution" | "acceptance";
60
65
  }
61
66
 
62
67
  type TestChainStep = TestSequentialStep | {
@@ -65,6 +70,8 @@ type TestChainStep = TestSequentialStep | {
65
70
  failFast?: boolean;
66
71
  worktree?: boolean;
67
72
  cwd?: string;
73
+ agentContract?: { version: 1 };
74
+ gateOn?: "execution" | "acceptance";
68
75
  } | {
69
76
  expand: {
70
77
  from: { output: string; path: string };
@@ -79,6 +86,8 @@ type TestChainStep = TestSequentialStep | {
79
86
  failFast?: boolean;
80
87
  label?: string;
81
88
  acceptance?: unknown;
89
+ agentContract?: { version: 1 };
90
+ gateOn?: "execution" | "acceptance";
82
91
  };
83
92
 
84
93
  interface ChainResultItem {
@@ -108,6 +117,7 @@ interface ChainExecutionResult {
108
117
  };
109
118
  currentStepIndex?: number;
110
119
  outputs?: Record<string, { text: string; structured?: unknown }>;
120
+ parallelHandoff?: { version: number; path: string; groupCount: number; childCount: number; cleanupState: string };
111
121
  };
112
122
  }
113
123
 
@@ -313,7 +323,7 @@ describe("chain execution — sequential", { skip: !available ? "pi packages not
313
323
 
314
324
  it("passes file-only saved-output references through {previous}", async () => {
315
325
  mockPi.onCall({ output: "full chain output\nwith details" });
316
- const agents = [makeAgent("analyst"), makeAgent("reporter")];
326
+ const agents = [makeAgent("analyst", { tools: ["read", "grep", "find", "ls"] }), makeAgent("reporter")];
317
327
 
318
328
  const result = await executeChain(
319
329
  makeChainParams(
@@ -327,6 +337,13 @@ describe("chain execution — sequential", { skip: !available ? "pi packages not
327
337
  );
328
338
 
329
339
  assert.ok(!result.isError, `chain should succeed: ${JSON.stringify(result.content)}`);
340
+ const firstTaskArg = readCallArgs(0).at(-1) ?? "";
341
+ assert.match(firstTaskArg, /Return the complete artifact in your final response\./);
342
+ assert.match(firstTaskArg, /runtime will persist it to exactly this path: .*analysis\.md/);
343
+ assert.match(firstTaskArg, /Do not call contact_supervisor merely because no write-capable tool is available\./);
344
+ assert.doesNotMatch(firstTaskArg, /\[Write to:|Write your findings to exactly this path/);
345
+ assert.ok(result.details.results[0]?.savedOutputPath);
346
+ assert.equal(fs.readFileSync(result.details.results[0].savedOutputPath, "utf-8"), "full chain output\nwith details");
330
347
  assert.match(result.details.results[0]?.finalOutput ?? "", /Output saved to:/);
331
348
  assert.doesNotMatch(result.details.results[0]?.finalOutput ?? "", /full chain output/);
332
349
  const secondTaskArg = readCallArgs(1).at(-1) ?? "";
@@ -375,7 +392,6 @@ describe("chain execution — sequential", { skip: !available ? "pi packages not
375
392
  JSON.stringify({
376
393
  criteriaSatisfied: [{ id: "criterion-1", status: "satisfied", evidence: "patched" }],
377
394
  changedFiles: ["src/file.ts"],
378
- testsAddedOrUpdated: [],
379
395
  commandsRun: [{ command: "npm test", result: "passed", summary: "passed" }],
380
396
  residualRisks: [],
381
397
  noStagedFiles: true,
@@ -661,7 +677,7 @@ describe("chain execution — sequential", { skip: !available ? "pi packages not
661
677
  assert.deepEqual(dynamicNode?.children?.map((child) => child.itemKey), ["src/a.ts", "src/b.ts"]);
662
678
  });
663
679
 
664
- it("persists checked acceptance status for dynamic fanout materialized children and aggregate group", async () => {
680
+ it("persists checked child evidence and pending aggregate review for dynamic fanout", async () => {
665
681
  mockPi.onCall({
666
682
  output: "targets",
667
683
  structuredOutput: { items: [{ path: "src/a.ts" }, { path: "src/b.ts" }] },
@@ -688,8 +704,80 @@ describe("chain execution — sequential", { skip: !available ? "pi packages not
688
704
 
689
705
  assert.ok(!result.isError, `chain should succeed: ${JSON.stringify(result.content)}`);
690
706
  const dynamicNode = result.details.workflowGraph?.nodes[1];
691
- assert.equal(dynamicNode?.acceptanceStatus, "checked");
707
+ assert.equal(dynamicNode?.acceptanceStatus, "review-required");
692
708
  assert.deepEqual(dynamicNode?.children?.map((child) => child.acceptanceStatus), ["checked", "checked"]);
709
+ assert.deepEqual(result.details.results.filter((child) => child.agent === "reviewer").map((child) => child.acceptance?.evidenceStatus), ["checked", "checked"]);
710
+ });
711
+
712
+ it("applies read-only acceptance roles to dynamic children and their aggregate group", async () => {
713
+ mockPi.onCall({
714
+ output: "targets",
715
+ structuredOutput: { items: [{ path: "src/a.ts" }, { path: "src/b.ts" }] },
716
+ });
717
+ const readOnlyReport = acceptanceReport({
718
+ changedFiles: [],
719
+ testsAddedOrUpdated: [],
720
+ commandsRun: [],
721
+ validationOutput: [],
722
+ reviewFindings: ["No blocking findings"],
723
+ });
724
+ mockPi.onCall({ output: readOnlyReport, structuredOutput: { ok: "a" } });
725
+ mockPi.onCall({ output: readOnlyReport, structuredOutput: { ok: "b" } });
726
+ const agents = [makeAgent("scout"), makeAgent("explorer", { acceptanceRole: "read-only" })];
727
+
728
+ const result = await executeChain(
729
+ makeChainParams(
730
+ [
731
+ { agent: "scout", task: "Return targets", as: "targets", outputSchema: { type: "object" } },
732
+ {
733
+ expand: { from: { output: "targets", path: "/items" }, key: "/path", maxItems: 4 },
734
+ parallel: { agent: "explorer", task: "Explore {item.path}", outputSchema: { type: "object" } },
735
+ collect: { as: "reviews" },
736
+ concurrency: 1,
737
+ },
738
+ ],
739
+ agents,
740
+ ),
741
+ );
742
+
743
+ assert.ok(!result.isError, `chain should succeed: ${JSON.stringify(result.content)}`);
744
+ const explorerResults = result.details.results.filter((child) => child.agent === "explorer");
745
+ assert.deepEqual(explorerResults.map((child) => child.acceptance?.effectiveAcceptance.level), ["attested", "attested"]);
746
+ const dynamicNode = result.details.workflowGraph?.nodes[1];
747
+ assert.equal(dynamicNode?.acceptanceStatus, "attested");
748
+ assert.deepEqual(dynamicNode?.children?.map((child) => child.acceptanceStatus), ["attested", "attested"]);
749
+ });
750
+
751
+ it("infers foreground dynamic acceptance after materializing item templates", async () => {
752
+ mockPi.onCall({
753
+ output: "targets",
754
+ structuredOutput: { items: [{ path: "src/a.ts" }, { path: "src/b.ts" }] },
755
+ });
756
+ mockPi.onCall({ output: acceptanceReport({ changedFiles: ["src/a.ts"] }), structuredOutput: { ok: "a" } });
757
+ mockPi.onCall({ output: acceptanceReport({ changedFiles: ["src/b.ts"] }), structuredOutput: { ok: "b" } });
758
+ const agents = [makeAgent("scout"), makeAgent("explorer", { acceptanceRole: "read-only" })];
759
+
760
+ const result = await executeChain(
761
+ makeChainParams(
762
+ [
763
+ { agent: "scout", task: "Return targets", as: "targets", outputSchema: { type: "object" } },
764
+ {
765
+ expand: { from: { output: "targets", path: "/items" }, key: "/path", maxItems: 4 },
766
+ parallel: { agent: "explorer", task: "Patch {item.path}", outputSchema: { type: "object" } },
767
+ collect: { as: "reviews" },
768
+ concurrency: 1,
769
+ },
770
+ ],
771
+ agents,
772
+ ),
773
+ );
774
+
775
+ assert.ok(!result.isError, `chain should succeed: ${JSON.stringify(result.content)}`);
776
+ const explorerResults = result.details.results.filter((child) => child.agent === "explorer");
777
+ assert.deepEqual(explorerResults.map((child) => child.acceptance?.effectiveAcceptance.level), ["checked", "checked"]);
778
+ const dynamicNode = result.details.workflowGraph?.nodes[1];
779
+ assert.equal(dynamicNode?.acceptanceStatus, "rejected");
780
+ assert.deepEqual(dynamicNode?.children?.map((child) => child.acceptanceStatus), ["rejected", "rejected"]);
693
781
  });
694
782
 
695
783
  it("does not expose collected dynamic output when a child fails", async () => {
@@ -992,6 +1080,50 @@ describe("chain execution — sequential", { skip: !available ? "pi packages not
992
1080
  assert.equal(result.details.results[0].exitCode, 1);
993
1081
  });
994
1082
 
1083
+ it("agent contract v1 chain defaults to execution gating after acceptance rejection", async () => {
1084
+ mockPi.onCall({ output: "Step 1 done\n```acceptance-report\n{\"criteriaSatisfied\":[{\"id\":\"criterion-1\",\"status\":\"not-satisfied\",\"evidence\":\"no proof\"}]}\n```" });
1085
+ mockPi.onCall({ output: "Step 2 ran" });
1086
+ const agents = [makeAgent("step1", { completionGuard: false }), makeAgent("step2", { completionGuard: false })];
1087
+
1088
+ const result = await executeChain(
1089
+ makeChainParams(
1090
+ [
1091
+ { agent: "step1", task: "First", acceptance: { level: "checked", criteria: ["Return required proof"] } },
1092
+ { agent: "step2", task: "Second receives {previous}" },
1093
+ ],
1094
+ agents,
1095
+ { task: "Original", agentContract: { version: 1 } },
1096
+ ),
1097
+ );
1098
+
1099
+ assert.equal(result.isError, undefined);
1100
+ assert.equal(result.details.results.length, 2);
1101
+ assert.equal(result.details.results[0]?.acceptance?.status, "rejected");
1102
+ assert.equal(result.details.results[0]?.exitCode, 0);
1103
+ assert.match(result.details.results[1]?.finalOutput ?? "", /Step 2 ran/);
1104
+ });
1105
+
1106
+ it("agent contract v1 chain can gate progression on acceptance", async () => {
1107
+ mockPi.onCall({ output: "Step 1 done\n```acceptance-report\n{\"criteriaSatisfied\":[{\"id\":\"criterion-1\",\"status\":\"not-satisfied\",\"evidence\":\"no proof\"}]}\n```" });
1108
+ const agents = [makeAgent("step1", { completionGuard: false }), makeAgent("step2", { completionGuard: false })];
1109
+
1110
+ const result = await executeChain(
1111
+ makeChainParams(
1112
+ [
1113
+ { agent: "step1", task: "First", acceptance: { level: "checked", criteria: ["Return required proof"] }, gateOn: "acceptance" },
1114
+ { agent: "step2", task: "Should not run" },
1115
+ ],
1116
+ agents,
1117
+ { task: "Original", agentContract: { version: 1 } },
1118
+ ),
1119
+ );
1120
+
1121
+ assert.equal(result.isError, true);
1122
+ assert.equal(result.details.results.length, 1);
1123
+ assert.equal(result.details.results[0]?.acceptance?.status, "rejected");
1124
+ assert.equal(mockPi.callCount(), 1);
1125
+ });
1126
+
995
1127
  it("runs a 3-step chain end-to-end", async () => {
996
1128
  mockPi.onCall({ output: "Step output" });
997
1129
  const agents = [makeAgent("scout"), makeAgent("planner"), makeAgent("executor")];
@@ -1183,6 +1315,12 @@ describe("chain execution — parallel steps", { skip: !available ? "pi packages
1183
1315
  };
1184
1316
  }
1185
1317
 
1318
+ function git(args: string[]): string {
1319
+ const result = spawnSync("git", args, { cwd: tempDir, encoding: "utf-8" });
1320
+ assert.equal(result.status, 0, result.stderr || result.stdout);
1321
+ return result.stdout.trim();
1322
+ }
1323
+
1186
1324
  function readCallArgs(index: number): string[] {
1187
1325
  const callFiles = fs.readdirSync(mockPi.dir)
1188
1326
  .filter((name) => name.startsWith("call-") && name.endsWith(".json"))
@@ -1225,6 +1363,38 @@ describe("chain execution — parallel steps", { skip: !available ? "pi packages
1225
1363
  assert.equal(result.details.results.length, 2);
1226
1364
  });
1227
1365
 
1366
+ it("aggregates worktree handoffs across foreground chain groups", { skip: process.platform === "win32" ? "worktree paths differ on Windows" : undefined }, async () => {
1367
+ git(["init"]);
1368
+ git(["config", "user.email", "test@example.com"]);
1369
+ git(["config", "user.name", "Test User"]);
1370
+ fs.writeFileSync(path.join(tempDir, "tracked.txt"), "base\n", "utf-8");
1371
+ git(["add", "tracked.txt"]);
1372
+ git(["commit", "-m", "initial"]);
1373
+ mockPi.onCall({ output: "Parallel task done" });
1374
+ const runId = "foreground-chain-handoff";
1375
+ const artifactsDir = path.join(tempDir, "artifacts");
1376
+ const result = await executeChain(
1377
+ makeChainParams(
1378
+ [{ parallel: [{ agent: "reviewer-a", task: "Review in isolation" }], worktree: true }],
1379
+ [makeAgent("reviewer-a")],
1380
+ { runId, artifactsDir },
1381
+ ),
1382
+ );
1383
+
1384
+ assert.equal(result.isError, undefined);
1385
+ assert.equal(result.details.parallelHandoff?.version, 1);
1386
+ assert.equal(result.details.parallelHandoff?.childCount, 1);
1387
+ assert.equal(result.details.parallelHandoff?.cleanupState, "complete");
1388
+ const handoff = JSON.parse(fs.readFileSync(result.details.parallelHandoff!.path, "utf-8")) as {
1389
+ groups: Array<{ stepIndex: number; children: Array<{ agent: string; patch: { path: string } }>; cleanup: { state: string } }>;
1390
+ };
1391
+ assert.equal(handoff.groups[0]!.stepIndex, 0);
1392
+ assert.equal(handoff.groups[0]!.children[0]!.agent, "reviewer-a");
1393
+ assert.equal(handoff.groups[0]!.cleanup.state, "complete");
1394
+ assert.equal(fs.existsSync(handoff.groups[0]!.children[0]!.patch.path), true);
1395
+ assert.match(handoff.groups[0]!.children[0]!.patch.path, /worktree-diffs\/foreground-chain-handoff\/step-0\//);
1396
+ });
1397
+
1228
1398
  it("aggregates parallel outputs for next sequential step", async () => {
1229
1399
  mockPi.onCall({ output: "Review findings here" });
1230
1400
  const agents = [makeAgent("reviewer-a"), makeAgent("reviewer-b"), makeAgent("synthesizer")];
@@ -1384,10 +1554,10 @@ describe("chain execution — parallel steps", { skip: !available ? "pi packages
1384
1554
  mockPi.onCall({
1385
1555
  steps: [
1386
1556
  { jsonl: [events.toolStart("intercom", { action: "send", to: "orchestrator" })] },
1387
- { delay: 1000, jsonl: [events.assistantMessage("after handoff")] },
1557
+ { delay: 25, jsonl: [events.assistantMessage("after handoff")] },
1388
1558
  ],
1389
1559
  });
1390
- mockPi.onCall({ output: "Other task done" });
1560
+ mockPi.onCall({ delay: 150, output: "Other task done" });
1391
1561
  const agents = [
1392
1562
  makeAgent("a", { systemPrompt: "Intercom orchestration channel:" }),
1393
1563
  makeAgent("b", { systemPrompt: "Intercom orchestration channel:" }),
@@ -1420,9 +1590,9 @@ describe("chain execution — parallel steps", { skip: !available ? "pi packages
1420
1590
 
1421
1591
  assert.equal(result.isError, undefined);
1422
1592
  assert.match(result.content[0]?.text ?? "", /Chain detached for intercom coordination/);
1423
- assert.doesNotMatch(result.content[0]?.text ?? "", /resume/);
1593
+ assert.match(result.content[0]?.text ?? "", /do not resume or launch a replacement/);
1424
1594
  assert.equal(detachEmitted, true);
1425
- assert.equal(result.details.results.some((entry) => entry.detached === true && entry.exitCode === 0), true);
1595
+ assert.equal(result.details.results.some((entry) => entry.detached === true && entry.exitCode === -2), true);
1426
1596
  });
1427
1597
 
1428
1598
  it("stops a sequential chain when a child detaches for intercom coordination", async () => {
@@ -1460,7 +1630,7 @@ describe("chain execution — parallel steps", { skip: !available ? "pi packages
1460
1630
 
1461
1631
  assert.equal(result.isError, undefined);
1462
1632
  assert.match(result.content[0]?.text ?? "", /Chain detached for intercom coordination/);
1463
- assert.doesNotMatch(result.content[0]?.text ?? "", /resume/);
1633
+ assert.match(result.content[0]?.text ?? "", /do not resume or launch a replacement/);
1464
1634
  assert.equal(detachEmitted, true);
1465
1635
  assert.equal(mockPi.callCount(), 1);
1466
1636
  });
@@ -69,6 +69,13 @@ describe("detectSubagentError", { skip: !available ? "utils not importable" : un
69
69
  assert.equal(detectSubagentError(messages).hasError, false);
70
70
  });
71
71
 
72
+ it("does not infer failure from successful bash output", () => {
73
+ const messages = [
74
+ toolResult("bash", "diff --git a/src/queue.ts b/src/queue.ts\n+ await new Promise((resolve) => setTimeout(resolve, 0))"),
75
+ ];
76
+ assert.equal(detectSubagentError(messages).hasError, false);
77
+ });
78
+
72
79
  it("detects isError tool result as failure (no assistant response)", () => {
73
80
  const messages = [
74
81
  toolResult("read", "file contents"),
@@ -80,18 +87,18 @@ describe("detectSubagentError", { skip: !available ? "utils not importable" : un
80
87
  assert.match(result.details!, /EISDIR/);
81
88
  });
82
89
 
83
- it("detects bash fatal pattern (permission denied, no assistant response)", () => {
90
+ it("detects bash error (permission denied, no assistant response)", () => {
84
91
  const messages = [
85
- toolResult("bash", "ls: permission denied: /root/secret"),
92
+ toolResult("bash", "ls: permission denied: /root/secret", true),
86
93
  ];
87
94
  const result = detectSubagentError(messages);
88
95
  assert.equal(result.hasError, true);
89
96
  assert.equal(result.errorType, "bash");
90
97
  });
91
98
 
92
- it("detects bash exit code in output", () => {
99
+ it("extracts a bash exit code from error output", () => {
93
100
  const messages = [
94
- toolResult("bash", "error: process exited with code 127"),
101
+ toolResult("bash", "error: process exited with code 127", true),
95
102
  ];
96
103
  const result = detectSubagentError(messages);
97
104
  assert.equal(result.hasError, true);
@@ -129,9 +136,9 @@ describe("detectSubagentError", { skip: !available ? "utils not importable" : un
129
136
  "agent produced substantive output after error — not a failure");
130
137
  });
131
138
 
132
- it("ignores bash fatal pattern when agent responded after", () => {
139
+ it("ignores bash error when agent responded after", () => {
133
140
  const messages = [
134
- toolResult("bash", "ls: permission denied: /root/secret"),
141
+ toolResult("bash", "ls: permission denied: /root/secret", true),
135
142
  assistantMsg("I couldn't access /root/secret, but I found the data elsewhere."),
136
143
  ];
137
144
  const result = detectSubagentError(messages);
@@ -145,7 +152,7 @@ describe("detectSubagentError", { skip: !available ? "utils not importable" : un
145
152
  const messages = [
146
153
  assistantMsg("Here is my analysis..."),
147
154
  toolResult("bash", "rm -rf /important", false),
148
- toolResult("bash", "error: process exited with code 1", false),
155
+ toolResult("bash", "error: process exited with code 1", true),
149
156
  ];
150
157
  const result = detectSubagentError(messages);
151
158
  assert.equal(result.hasError, true);
@@ -168,7 +175,7 @@ describe("detectSubagentError", { skip: !available ? "utils not importable" : un
168
175
  it("flags error when no assistant messages at all", () => {
169
176
  const messages = [
170
177
  toolResult("read", "ok"),
171
- toolResult("bash", "segmentation fault"),
178
+ toolResult("bash", "segmentation fault", true),
172
179
  ];
173
180
  const result = detectSubagentError(messages);
174
181
  assert.equal(result.hasError, true,
@@ -181,7 +188,7 @@ describe("detectSubagentError", { skip: !available ? "utils not importable" : un
181
188
  // assistant message doesn't count as recovery. The final tool result is
182
189
  // successful to ensure this test actually distinguishes correct behavior.
183
190
  const messages = [
184
- toolResult("bash", "permission denied: /etc/shadow"),
191
+ toolResult("bash", "permission denied: /etc/shadow", true),
185
192
  assistantToolCall("bash"),
186
193
  toolResult("bash", "command succeeded"),
187
194
  ];
@@ -49,13 +49,13 @@ describe("detectSubagentError", { skip: !detectSubagentError ? "utils not import
49
49
  assert.equal(result.hasError, false);
50
50
  });
51
51
 
52
- it("detects fatal bash error in last tool result", () => {
52
+ it("detects bash error in last tool result", () => {
53
53
  const messages = [
54
54
  { role: "assistant", content: [{ type: "text", text: "Running..." }] },
55
55
  {
56
56
  role: "toolResult",
57
57
  toolName: "bash",
58
- isError: false,
58
+ isError: true,
59
59
  content: [{ type: "text", text: "command not found" }],
60
60
  },
61
61
  ];
@@ -64,13 +64,13 @@ describe("detectSubagentError", { skip: !detectSubagentError ? "utils not import
64
64
  assert.equal(result.errorType, "bash");
65
65
  });
66
66
 
67
- it("detects non-zero exit code in bash output", () => {
67
+ it("extracts a non-zero exit code from bash error output", () => {
68
68
  const messages = [
69
69
  { role: "assistant", content: [{ type: "text", text: "Running..." }] },
70
70
  {
71
71
  role: "toolResult",
72
72
  toolName: "bash",
73
- isError: false,
73
+ isError: true,
74
74
  content: [{ type: "text", text: "Error: process exited with code 127" }],
75
75
  },
76
76
  ];
@@ -146,9 +146,10 @@ describe("runSync error handling", { skip: !piAvailable ? "pi packages not avail
146
146
  it("detectSubagentError overrides exit 0 on hidden failure", async () => {
147
147
  mockPi.onCall({
148
148
  jsonl: [
149
+ events.assistantMessage("Starting deployment"),
149
150
  events.toolStart("bash", { command: "deploy" }),
150
151
  events.toolEnd("bash"),
151
- events.toolResult("bash", "connection refused"),
152
+ events.toolResult("bash", "connection refused", true),
152
153
  ],
153
154
  });
154
155
  const agents = makeAgentConfigs(["deployer"]);