@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
@@ -0,0 +1,86 @@
1
+ import assert from "node:assert/strict";
2
+ import { describe, it } from "node:test";
3
+ import { classifyTaskMutationIntent, expectsImplementationMutation, taskMayMutate } from "../../src/runs/shared/task-intent.ts";
4
+
5
+ describe("classifyTaskMutationIntent", () => {
6
+ it("keeps write imperatives despite investigative wording", () => {
7
+ assert.equal(classifyTaskMutationIntent("builder", "Inspect the failure and implement the fix").kind, "implementation");
8
+ assert.equal(classifyTaskMutationIntent("builder", "Research the current code path and patch the bug").kind, "implementation");
9
+ });
10
+
11
+ it("does not broaden the shared completion-guard classifier for role-only path patches", () => {
12
+ assert.equal(classifyTaskMutationIntent("builder", "Patch src/auth.ts").kind, "unknown");
13
+ });
14
+
15
+ it("treats scoped no-edit constraints as constraints, not task intent", () => {
16
+ assert.equal(classifyTaskMutationIntent("builder", "Do not modify tests; implement the fix").kind, "implementation");
17
+ assert.equal(classifyTaskMutationIntent("builder", "Fix the bug. Do not edit files outside src/.").kind, "implementation");
18
+ assert.equal(classifyTaskMutationIntent("builder", "Must not touch the production database; implement the fix locally").kind, "implementation");
19
+ });
20
+
21
+ it("stops the prohibition object before a following implementation clause", () => {
22
+ for (const task of [
23
+ "Do not modify tests but implement the fix",
24
+ "Do not modify tests and implement the fix",
25
+ "Do not modify tests: implement the fix",
26
+ "Do not modify tests? Implement the fix",
27
+ "Do not modify tests - implement the fix",
28
+ "Do not modify tests – implement the fix",
29
+ "Do not modify tests — implement the fix",
30
+ ]) {
31
+ assert.equal(classifyTaskMutationIntent("builder", task).kind, "implementation", task);
32
+ }
33
+ assert.equal(classifyTaskMutationIntent("builder", "Do not modify tests and fixtures").kind, "read-only");
34
+ });
35
+
36
+ it("lets blanket no-edit prohibitions win over write verbs", () => {
37
+ assert.equal(classifyTaskMutationIntent("builder", "Implement this. Do not edit files.").kind, "read-only");
38
+ assert.equal(classifyTaskMutationIntent("builder", "Do not edit files. Tell me how to fix the bug.").kind, "read-only");
39
+ assert.equal(classifyTaskMutationIntent("builder", "Report on the extraction pipeline. Do not modify project/source files.").kind, "read-only");
40
+ assert.equal(classifyTaskMutationIntent("commentator", "Final correctness review after prior fixes. Inspect all changed files and tests. Do not modify project/source files. Report findings.").kind, "read-only");
41
+ });
42
+
43
+ it("strips repeated prohibition phrases before testing write intent", () => {
44
+ assert.equal(classifyTaskMutationIntent("builder", "Do not modify vendor/. Do not modify generated/. Summarize the build.").kind, "read-only");
45
+ assert.equal(classifyTaskMutationIntent("builder", "Do not modify vendor/. Do not modify generated/. Implement the fix in src/.").kind, "implementation");
46
+ });
47
+
48
+ it("classifies research agents and commentator-style tasks as read-only", () => {
49
+ assert.equal(classifyTaskMutationIntent("researcher", "Research this and patch the bug").kind, "read-only");
50
+ assert.equal(classifyTaskMutationIntent("commentator", "Review this and fix any real issues").kind, "read-only");
51
+ assert.equal(classifyTaskMutationIntent("commentator", "Review findings and determine what to implement with playbooks instead of before").kind, "read-only");
52
+ assert.equal(classifyTaskMutationIntent("commentator", "Review findings and determine what to implement with playbooks instead of before").kind, "read-only");
53
+ assert.equal(classifyTaskMutationIntent("commentator", "Review this; regardless of findings, apply changes directly").kind, "implementation");
54
+ assert.equal(classifyTaskMutationIntent("commentator", "Implement the approved file changes").kind, "implementation");
55
+ assert.equal(classifyTaskMutationIntent("commentator", "Implement the approved file changes").kind, "implementation");
56
+ });
57
+
58
+ it("keeps report-writing deliverables read-only", () => {
59
+ assert.equal(classifyTaskMutationIntent("builder", "Write a report on the API").kind, "read-only");
60
+ assert.equal(classifyTaskMutationIntent("builder", "Create a summary").kind, "unknown");
61
+ });
62
+
63
+ it("expectsImplementationMutation mirrors the classifier", () => {
64
+ assert.equal(expectsImplementationMutation("builder", "Do not modify tests; implement the fix"), true);
65
+ assert.equal(expectsImplementationMutation("builder", "Review the diff and suggest fixes only. Do not edit files."), false);
66
+ });
67
+ });
68
+
69
+ describe("taskMayMutate", () => {
70
+ it("treats any bare write verb as write-capable", () => {
71
+ for (const task of ["Write the code", "Commit the changes", "Delete temporary data", "Remove obsolete assets", "Update dependencies"]) {
72
+ assert.equal(taskMayMutate(task), true, task);
73
+ }
74
+ });
75
+
76
+ it("does not count verbs inside prohibitions or read-only deliverables", () => {
77
+ assert.equal(taskMayMutate("Do not modify project/source files. Report findings."), false);
78
+ assert.equal(taskMayMutate("Write a report on the API"), false);
79
+ assert.equal(taskMayMutate("Summarize the build output"), false);
80
+ });
81
+
82
+ it("keeps verbs that survive outside a scoped prohibition", () => {
83
+ assert.equal(taskMayMutate("Do not modify tests but implement the fix"), true);
84
+ assert.equal(taskMayMutate("Do not modify tests; update the parser"), true);
85
+ });
86
+ });
@@ -23,6 +23,17 @@ describe("tool-budget module", () => {
23
23
  assert.deepEqual(resolved.budget, { soft: 2, hard: 4, block: "*" });
24
24
  });
25
25
 
26
+ it("accepts a zero hard limit only when the internal minimum opts in", () => {
27
+ assert.deepEqual(
28
+ validateToolBudgetConfig({ hard: 0, block: "*" }, "toolBudget", { minimumHard: 0 }).budget,
29
+ { hard: 0, block: "*" },
30
+ );
31
+ assert.equal(
32
+ validateToolBudgetConfig({ soft: 0, hard: 0, block: "*" }, "toolBudget", { minimumHard: 0 }).error,
33
+ "toolBudget.soft must be an integer >= 1 when provided.",
34
+ );
35
+ });
36
+
26
37
  it("rejects unsafe configs", () => {
27
38
  assert.equal(validateToolBudgetConfig({ hard: 0 }).error, "toolBudget.hard must be an integer >= 1.");
28
39
  assert.equal(validateToolBudgetConfig({ soft: 5, hard: 4 }).error, "toolBudget.soft must be <= toolBudget.hard.");
@@ -33,6 +44,9 @@ describe("tool-budget module", () => {
33
44
  it("serializes and decodes env config", () => {
34
45
  const budget = { soft: 2, hard: 4, block: ["read"] };
35
46
  assert.deepEqual(decodeToolBudgetEnv(encodeToolBudgetEnv(budget)), budget);
47
+ const zeroBudget = { hard: 0, block: "*" as const };
48
+ assert.throws(() => decodeToolBudgetEnv(encodeToolBudgetEnv(zeroBudget)), /SELESAI_SUBAGENT_TOOL_BUDGET\.hard must be an integer >= 1/);
49
+ assert.deepEqual(decodeToolBudgetEnv(encodeToolBudgetEnv(zeroBudget), { allowZero: true }), zeroBudget);
36
50
  });
37
51
 
38
52
  it("tracks state and block decisions", () => {
@@ -42,6 +56,7 @@ describe("tool-budget module", () => {
42
56
  assert.equal(toolBudgetState(budget, 4, "read").outcome, "hard-blocked");
43
57
  assert.equal(shouldBlockToolForBudget(budget, "read", 4), true);
44
58
  assert.equal(shouldBlockToolForBudget(budget, "write", 4), false);
59
+ assert.equal(shouldBlockToolForBudget({ hard: 0, block: "*" }, "read", 1), true);
45
60
  });
46
61
 
47
62
  it("formats user-facing budget messages", () => {
@@ -34,6 +34,8 @@ describe("registered subagent tool description", () => {
34
34
  for (const builtinName of ["scout", "worker", "planner"]) {
35
35
  assert.doesNotMatch(description, new RegExp(`\\b${builtinName}\\b`));
36
36
  }
37
+ assert.match(description, /^To delegate work, call with \{ agent, task \}, \{ tasks \}, or \{ chain \}; omit action\./i);
38
+ assert.match(description, /Use action only for management\/control actions listed below/i);
37
39
  assert.match(description, /use \{ action: "list" \} to inspect configured agents\/chains/i);
38
40
  assert.match(description, /executable\/non-disabled/i);
39
41
  assert.match(description, /proactive skill subagent suggestions/i);
@@ -42,10 +44,17 @@ describe("registered subagent tool description", () => {
42
44
  assert.match(description, /timeoutMs/i);
43
45
  assert.match(description, /maxRuntimeMs/i);
44
46
  assert.match(description, /foreground and async\/background runs/i);
47
+ assert.match(description, /omit acceptance for reviewer\/read-only calls/i);
48
+ assert.match(description, /acceptance\.review\.required/i);
49
+ assert.match(description, /reviewed is achieved only after an independent reviewer result/i);
45
50
  assert.doesNotMatch(description, /only for foreground runs/i);
46
51
  assert.doesNotMatch(description, /omit for async\/background runs/i);
47
52
  assert.match(description, /SAFETY-CRITICAL SUBAGENT GUIDANCE/);
48
53
  assert.match(description, /Do not sleep or poll status just to wait/i);
54
+ assert.match(description, /use subagent_wait/i);
55
+ assert.match(description, /interactive session.*normally return control/i);
56
+ assert.match(description, /Headless sessions auto-drain current-session work at agent_end/i);
57
+ assert.doesNotMatch(description, /MUST call subagent_wait/i);
49
58
  assert.match(description, /ordinary child subagents are not orchestrators/i);
50
59
  assert.match(description, /keep one writer/i);
51
60
  assert.match(description, /view: "fleet"/);
@@ -54,31 +63,68 @@ describe("registered subagent tool description", () => {
54
63
  assert.match(description, /schedule-list/);
55
64
  assert.match(description, /action: "eject"/);
56
65
  assert.match(description, /action: "disable"/);
66
+ assert.match(description, /action: "grant-spawn-budget"/);
67
+ assert.match(description, /root interactive parent/i);
68
+ assert.match(description, /cumulative grants cannot exceed the original configured cap/i);
69
+ assert.match(description, /acceptanceRole affects inferred acceptance only/i);
70
+ assert.match(description, /Explicit task mutation\/no-edit intent wins/i);
71
+ assert.match(description, /omission preserves name heuristics/i);
72
+ assert.match(description, /false or an empty string to clear it/i);
57
73
  assert.match(description, /status\.json/);
58
74
  assert.match(description, /events\.jsonl/);
75
+ // Chain quick-reference: both sequential and parallel fan-out examples (#417)
76
+ assert.match(description, /CHAIN EXAMPLES/i);
77
+ assert.match(
78
+ description,
79
+ /chain:\s*\[\s*\{\s*agent:\s*"[\w-]+",\s*task:\s*"[^"]*"\s*\}\s*,\s*\{\s*agent:\s*"[\w-]+",\s*task:\s*"[^"]*\{previous\}[^"]*"\s*\}\s*\]/,
80
+ "full mode should show a sequential chain example using {previous}",
81
+ );
82
+ assert.match(
83
+ description,
84
+ /\{\s*parallel:\s*\[\s*\{\s*agent:\s*"[\w-]+",\s*task:\s*"[^"]*",\s*count:\s*\d+\s*\}\s*\]\s*\}/,
85
+ "full mode should show a parallel fan-out chain example with count",
86
+ );
59
87
  });
60
88
 
61
89
  it("offers a compact mode that keeps safety-critical guidance", () => {
62
90
  const description = buildSubagentToolDescription({ toolDescriptionMode: "compact" });
63
91
 
64
92
  assert.equal(description, COMPACT_SUBAGENT_TOOL_DESCRIPTION);
93
+ assert.match(description, /^To delegate work, call with \{ agent, task \}, \{ tasks \}, or \{ chain \}; omit action\./i);
94
+ assert.match(description, /Use action only for management\/control actions listed below/i);
65
95
  assert.ok(description.length < FULL_SUBAGENT_TOOL_DESCRIPTION.length * 0.8, "compact mode should be materially shorter than full mode");
66
96
  assert.match(description, /SINGLE/);
67
97
  assert.match(description, /PARALLEL/);
68
98
  assert.match(description, /CHAIN/);
69
99
  assert.match(description, /action without execution fields/i);
70
- assert.match(description, /wait tool/i);
100
+ assert.match(description, /subagent_wait/i);
101
+ assert.match(description, /interactive session.*normally return control/i);
102
+ assert.match(description, /Non-interactive runs.*auto-drain current-session work at agent_end/i);
103
+ assert.doesNotMatch(description, /MUST call subagent_wait/i);
71
104
  assert.match(description, /Do not sleep or poll/i);
72
105
  assert.match(description, /ordinary child subagents are not orchestrators/i);
73
106
  assert.match(description, /one writer/i);
107
+ assert.match(description, /omit acceptance for reviewer\/read-only calls/i);
108
+ assert.match(description, /acceptance\.review\.required/i);
109
+ assert.match(description, /reviewed is an achieved status/i);
74
110
  assert.match(description, /view:"fleet"/);
75
111
  assert.match(description, /view:"transcript"/);
76
112
  assert.match(description, /steer/);
77
113
  assert.match(description, /schedule-list/);
78
114
  assert.match(description, /eject/);
79
115
  assert.match(description, /disable/);
116
+ assert.match(description, /grant-spawn-budget/);
117
+ assert.match(description, /acceptanceRole.*affects inferred acceptance only/i);
118
+ assert.match(description, /Explicit task intent wins/i);
119
+ assert.match(description, /omission keeps name heuristics/i);
120
+ assert.match(description, /false or an empty string to clear it/i);
80
121
  assert.match(description, /status\.json/);
81
122
  assert.match(description, /events\.jsonl/);
123
+ // Compact mode keeps a chain quick-reference too (#417)
124
+ assert.match(description, /chain example/i);
125
+ assert.match(description, /\{previous\}/);
126
+ assert.match(description, /parallel:/);
127
+ assert.match(description, /count:/);
82
128
  });
83
129
 
84
130
  it("renders a custom project description with placeholders and mandatory safety guidance", () => {
@@ -6,7 +6,9 @@ import {
6
6
  appendTurnBudgetSystemPrompt,
7
7
  formatTurnBudgetOutput,
8
8
  initialTurnBudgetState,
9
- shouldAbortForTurnBudget,
9
+ resolveTurnBudgetConfig,
10
+ turnBudgetDecision,
11
+ turnBudgetDeferredState,
10
12
  turnBudgetExceededMessage,
11
13
  turnBudgetSoftNote,
12
14
  turnBudgetState,
@@ -23,6 +25,29 @@ describe("turn-budget module", () => {
23
25
  });
24
26
  });
25
27
 
28
+ describe("resolveTurnBudgetConfig", () => {
29
+ it("resolves valid budgets and supplies the default grace turn", () => {
30
+ assert.deepEqual(resolveTurnBudgetConfig({ maxTurns: 5 }), {
31
+ turnBudget: { maxTurns: 5, graceTurns: 1 },
32
+ });
33
+ assert.deepEqual(resolveTurnBudgetConfig({ maxTurns: 5, graceTurns: 0 }), {
34
+ turnBudget: { maxTurns: 5, graceTurns: 0 },
35
+ });
36
+ });
37
+
38
+ it("rejects invalid values with the caller's boundary label", () => {
39
+ assert.deepEqual(resolveTurnBudgetConfig({ maxTurns: 0 }, "agent.turnBudget"), {
40
+ error: "agent.turnBudget.maxTurns must be an integer >= 1.",
41
+ });
42
+ assert.deepEqual(resolveTurnBudgetConfig({ maxTurns: 2, graceTurns: -1 }), {
43
+ error: "turnBudget.graceTurns must be an integer >= 0.",
44
+ });
45
+ assert.deepEqual(resolveTurnBudgetConfig({ maxTurns: 2, extra: true }), {
46
+ error: "turnBudget.extra is not supported.",
47
+ });
48
+ });
49
+ });
50
+
26
51
  describe("appendTurnBudgetSystemPrompt", () => {
27
52
  it("returns the system prompt unchanged when no budget is configured", () => {
28
53
  assert.equal(appendTurnBudgetSystemPrompt("You are a reviewer.", undefined), "You are a reviewer.");
@@ -152,22 +177,43 @@ describe("turn-budget module", () => {
152
177
  });
153
178
  });
154
179
 
155
- describe("shouldAbortForTurnBudget", () => {
156
- it("allows a terminal assistant response on the final grace turn", () => {
157
- assert.equal(shouldAbortForTurnBudget(budget({ maxTurns: 3, graceTurns: 1 }), 4, true), false);
180
+ describe("turnBudgetDecision", () => {
181
+ it("continues below the hard limit and for a terminal response on the final grace turn", () => {
182
+ assert.equal(turnBudgetDecision(budget({ maxTurns: 3, graceTurns: 1 }), 3, false, false), "continue");
183
+ assert.equal(turnBudgetDecision(budget({ maxTurns: 3, graceTurns: 1 }), 4, true, false), "continue");
184
+ });
185
+
186
+ it("defers termination when the hard-limit assistant response starts tool work", () => {
187
+ assert.equal(turnBudgetDecision(budget({ maxTurns: 3, graceTurns: 1 }), 4, false, true), "defer");
188
+ assert.equal(turnBudgetDecision(budget({ maxTurns: 3, graceTurns: 1 }), 5, false, true), "defer");
158
189
  });
159
190
 
160
- it("aborts a non-terminal assistant response on the final grace turn", () => {
161
- assert.equal(shouldAbortForTurnBudget(budget({ maxTurns: 3, graceTurns: 1 }), 4, false), true);
191
+ it("enforces the hard limit for strict foreground delegation but allows the exact terminal boundary", () => {
192
+ assert.equal(turnBudgetDecision(budget({ maxTurns: 3, graceTurns: 1 }), 4, false, true, true), "abort");
193
+ assert.equal(turnBudgetDecision(budget({ maxTurns: 3, graceTurns: 1 }), 4, true, true, true), "continue");
162
194
  });
163
195
 
164
- it("aborts turns beyond the grace window even if the message is terminal", () => {
165
- assert.equal(shouldAbortForTurnBudget(budget({ maxTurns: 3, graceTurns: 1 }), 5, true), true);
196
+ it("aborts at the next safe assistant boundary", () => {
197
+ assert.equal(turnBudgetDecision(budget({ maxTurns: 3, graceTurns: 1 }), 4, false, false), "abort");
198
+ assert.equal(turnBudgetDecision(budget({ maxTurns: 3, graceTurns: 1 }), 5, true, false), "abort");
166
199
  });
167
200
 
168
201
  it("allows a terminal response at the soft limit when grace turns are zero", () => {
169
- assert.equal(shouldAbortForTurnBudget(budget({ maxTurns: 2, graceTurns: 0 }), 2, true), false);
170
- assert.equal(shouldAbortForTurnBudget(budget({ maxTurns: 2, graceTurns: 0 }), 2, false), true);
202
+ assert.equal(turnBudgetDecision(budget({ maxTurns: 2, graceTurns: 0 }), 2, true, false), "continue");
203
+ assert.equal(turnBudgetDecision(budget({ maxTurns: 2, graceTurns: 0 }), 2, false, false), "abort");
204
+ });
205
+ });
206
+
207
+ describe("turnBudgetDeferredState", () => {
208
+ it("records the exact turn where hard termination became pending", () => {
209
+ assert.deepEqual(turnBudgetDeferredState(budget({ maxTurns: 2, graceTurns: 0 }), 2), {
210
+ maxTurns: 2,
211
+ graceTurns: 0,
212
+ turnCount: 2,
213
+ outcome: "termination-deferred",
214
+ wrapUpRequestedAtTurn: 2,
215
+ terminationDeferredAtTurn: 2,
216
+ });
171
217
  });
172
218
  });
173
219