@selesai/code 0.5.19 → 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 (265) 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-intercom/broker/spawn.test.ts +31 -0
  4. package/dist/extensions/pi-intercom/broker/spawn.ts +5 -3
  5. package/dist/extensions/pi-subagents/CHANGELOG.md +1367 -0
  6. package/dist/extensions/pi-subagents/README.md +602 -220
  7. package/dist/extensions/pi-subagents/banner.png +0 -0
  8. package/dist/extensions/pi-subagents/index.ts +1 -0
  9. package/dist/extensions/pi-subagents/install.mjs +3 -3
  10. package/dist/extensions/pi-subagents/package-lock.json +3405 -0
  11. package/dist/extensions/pi-subagents/package.json +26 -14
  12. package/dist/extensions/pi-subagents/prompts/gather-context-and-clarify.md +1 -1
  13. package/dist/extensions/pi-subagents/prompts/parallel-cleanup.md +9 -9
  14. package/dist/extensions/pi-subagents/prompts/parallel-context-build.md +3 -3
  15. package/dist/extensions/pi-subagents/prompts/parallel-handoff-plan.md +7 -7
  16. package/dist/extensions/pi-subagents/prompts/parallel-research.md +6 -6
  17. package/dist/extensions/pi-subagents/prompts/parallel-review.md +8 -8
  18. package/dist/extensions/pi-subagents/prompts/review-loop.md +13 -11
  19. package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +267 -176
  20. package/dist/extensions/pi-subagents/src/agents/agent-management.ts +89 -16
  21. package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +19 -0
  22. package/dist/extensions/pi-subagents/src/agents/agents.ts +218 -120
  23. package/dist/extensions/pi-subagents/src/agents/frontmatter.ts +67 -13
  24. package/dist/extensions/pi-subagents/src/agents/proactive-skills.ts +2 -2
  25. package/dist/extensions/pi-subagents/src/agents/skills.ts +25 -12
  26. package/dist/extensions/pi-subagents/src/api/background-work.ts +197 -0
  27. package/dist/extensions/pi-subagents/src/api/capability-ceiling.ts +17 -0
  28. package/dist/extensions/pi-subagents/src/api/delegation.ts +285 -0
  29. package/dist/extensions/pi-subagents/src/api/preflight.ts +399 -0
  30. package/dist/extensions/pi-subagents/src/extension/chain-validation.ts +165 -0
  31. package/dist/extensions/pi-subagents/src/extension/config.ts +7 -1
  32. package/dist/extensions/pi-subagents/src/extension/doctor.ts +15 -0
  33. package/dist/extensions/pi-subagents/src/extension/fanout-child.ts +3 -1
  34. package/dist/extensions/pi-subagents/src/extension/index.ts +113 -157
  35. package/dist/extensions/pi-subagents/src/extension/rpc.ts +41 -4
  36. package/dist/extensions/pi-subagents/src/extension/schemas.ts +45 -15
  37. package/dist/extensions/pi-subagents/src/extension/steering-notices.ts +35 -0
  38. package/dist/extensions/pi-subagents/src/extension/tool-description.ts +28 -15
  39. package/dist/extensions/pi-subagents/src/intercom/intercom-bridge.ts +4 -3
  40. package/dist/extensions/pi-subagents/src/intercom/native-supervisor-channel.ts +225 -29
  41. package/dist/extensions/pi-subagents/src/intercom/result-intercom.ts +11 -0
  42. package/dist/extensions/pi-subagents/src/profiles/profiles.ts +8 -10
  43. package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +452 -62
  44. package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +60 -9
  45. package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +198 -52
  46. package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +119 -21
  47. package/dist/extensions/pi-subagents/src/runs/background/auto-drain.ts +67 -0
  48. package/dist/extensions/pi-subagents/src/runs/background/chain-append.ts +2 -0
  49. package/dist/extensions/pi-subagents/src/runs/background/chain-root-attachment.ts +16 -8
  50. package/dist/extensions/pi-subagents/src/runs/background/completion-batcher.ts +6 -4
  51. package/dist/extensions/pi-subagents/src/runs/background/completion-dedupe.ts +2 -11
  52. package/dist/extensions/pi-subagents/src/runs/background/control-channel.ts +260 -13
  53. package/dist/extensions/pi-subagents/src/runs/background/fleet-view.ts +32 -6
  54. package/dist/extensions/pi-subagents/src/runs/background/notify.ts +171 -90
  55. package/dist/extensions/pi-subagents/src/runs/background/process-terminal.ts +280 -0
  56. package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +149 -88
  57. package/dist/extensions/pi-subagents/src/runs/background/run-id-resolver.ts +14 -2
  58. package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +33 -17
  59. package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +9 -1
  60. package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +38 -10
  61. package/dist/extensions/pi-subagents/src/runs/background/steering.ts +237 -0
  62. package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +1297 -307
  63. package/dist/extensions/pi-subagents/src/runs/background/subagent-wait.ts +610 -0
  64. package/dist/extensions/pi-subagents/src/runs/background/top-level-async.ts +2 -1
  65. package/dist/extensions/pi-subagents/src/runs/background/wait-config.ts +36 -0
  66. package/dist/extensions/pi-subagents/src/runs/background/wait-tool.ts +26 -0
  67. package/dist/extensions/pi-subagents/src/runs/foreground/async-steering-action.ts +230 -0
  68. package/dist/extensions/pi-subagents/src/runs/foreground/chain-clarify.ts +22 -6
  69. package/dist/extensions/pi-subagents/src/runs/foreground/chain-execution.ts +228 -140
  70. package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +452 -138
  71. package/dist/extensions/pi-subagents/src/runs/foreground/foreground-control.ts +90 -0
  72. package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +1001 -416
  73. package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +443 -132
  74. package/dist/extensions/pi-subagents/src/runs/shared/agent-contract.ts +38 -0
  75. package/dist/extensions/pi-subagents/src/runs/shared/capability-ceiling.ts +178 -0
  76. package/dist/extensions/pi-subagents/src/runs/shared/child-protocol.ts +121 -0
  77. package/dist/extensions/pi-subagents/src/runs/shared/completion-guard.ts +41 -93
  78. package/dist/extensions/pi-subagents/src/runs/shared/context-mode.ts +44 -0
  79. package/dist/extensions/pi-subagents/src/runs/shared/dynamic-fanout.ts +11 -9
  80. package/dist/extensions/pi-subagents/src/runs/shared/long-running-guard.ts +4 -0
  81. package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +12 -6
  82. package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +36 -0
  83. package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +44 -7
  84. package/dist/extensions/pi-subagents/src/runs/shared/nested-render.ts +4 -1
  85. package/dist/extensions/pi-subagents/src/runs/shared/parallel-handoff.ts +154 -0
  86. package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +18 -0
  87. package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +174 -54
  88. package/dist/extensions/pi-subagents/src/runs/shared/pi-spawn.ts +38 -31
  89. package/dist/extensions/pi-subagents/src/runs/shared/run-history.ts +90 -5
  90. package/dist/extensions/pi-subagents/src/runs/shared/session-lease.ts +299 -0
  91. package/dist/extensions/pi-subagents/src/runs/shared/single-output.ts +61 -6
  92. package/dist/extensions/pi-subagents/src/runs/shared/spawn-budget.ts +128 -0
  93. package/dist/extensions/pi-subagents/src/runs/shared/structured-output.ts +112 -7
  94. package/dist/extensions/pi-subagents/src/runs/shared/subagent-control.ts +14 -6
  95. package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +149 -36
  96. package/dist/extensions/pi-subagents/src/runs/shared/task-intent.ts +181 -0
  97. package/dist/extensions/pi-subagents/src/runs/shared/tool-availability.ts +83 -0
  98. package/dist/extensions/pi-subagents/src/runs/shared/tool-budget.ts +11 -5
  99. package/dist/extensions/pi-subagents/src/runs/shared/turn-budget.ts +50 -4
  100. package/dist/extensions/pi-subagents/src/runs/shared/worktree.ts +63 -14
  101. package/dist/extensions/pi-subagents/src/shared/accessible-dir.ts +25 -0
  102. package/dist/extensions/pi-subagents/src/shared/artifacts.ts +37 -7
  103. package/dist/extensions/pi-subagents/src/shared/atomic-json.ts +18 -43
  104. package/dist/extensions/pi-subagents/src/shared/child-transcript.ts +52 -0
  105. package/dist/extensions/pi-subagents/src/shared/env.ts +16 -0
  106. package/dist/extensions/pi-subagents/src/shared/file-system-retry.ts +47 -0
  107. package/dist/extensions/pi-subagents/src/shared/fork-context.ts +28 -3
  108. package/dist/extensions/pi-subagents/src/shared/launch-contract.ts +123 -0
  109. package/dist/extensions/pi-subagents/src/shared/model-info.ts +8 -5
  110. package/dist/extensions/pi-subagents/src/shared/settings.ts +9 -1
  111. package/dist/extensions/pi-subagents/src/shared/status-format.ts +7 -1
  112. package/dist/extensions/pi-subagents/src/shared/types.ts +522 -51
  113. package/dist/extensions/pi-subagents/src/shared/utils.ts +59 -53
  114. package/dist/extensions/pi-subagents/src/slash/delegation-adapters.ts +604 -0
  115. package/dist/extensions/pi-subagents/src/slash/delegation-json.ts +108 -0
  116. package/dist/extensions/pi-subagents/src/slash/delegation-request.ts +249 -0
  117. package/dist/extensions/pi-subagents/src/slash/prompt-template-bridge.ts +353 -345
  118. package/dist/extensions/pi-subagents/src/slash/prompt-workflows.ts +2 -2
  119. package/dist/extensions/pi-subagents/src/slash/selector.ts +147 -0
  120. package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +265 -23
  121. package/dist/extensions/pi-subagents/src/slash/slash-live-state.ts +2 -2
  122. package/dist/extensions/pi-subagents/src/slash/subagents-admin.ts +428 -0
  123. package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +362 -0
  124. package/dist/extensions/pi-subagents/src/tui/fleet-transcript.ts +472 -0
  125. package/dist/extensions/pi-subagents/src/tui/fleet.ts +664 -0
  126. package/dist/extensions/pi-subagents/src/tui/render.ts +115 -31
  127. package/dist/extensions/pi-subagents/src/watchdog/change-signature.ts +220 -0
  128. package/dist/extensions/pi-subagents/src/watchdog/child-status.ts +205 -0
  129. package/dist/extensions/pi-subagents/src/watchdog/emission-guard.ts +123 -0
  130. package/dist/extensions/pi-subagents/src/watchdog/lsp-diagnostics.ts +532 -0
  131. package/dist/extensions/pi-subagents/src/watchdog/model-selection.ts +167 -0
  132. package/dist/extensions/pi-subagents/src/watchdog/register-child.ts +117 -0
  133. package/dist/extensions/pi-subagents/src/watchdog/register-main.ts +433 -0
  134. package/dist/extensions/pi-subagents/src/watchdog/render.ts +54 -0
  135. package/dist/extensions/pi-subagents/src/watchdog/review.ts +298 -0
  136. package/dist/extensions/pi-subagents/src/watchdog/runtime.ts +714 -0
  137. package/dist/extensions/pi-subagents/src/watchdog/settings.ts +528 -0
  138. package/dist/extensions/pi-subagents/src/watchdog/tool-actions.ts +155 -0
  139. package/dist/extensions/pi-subagents/src/watchdog/turn-delta.ts +161 -0
  140. package/dist/extensions/pi-subagents/src/watchdog/types.ts +188 -0
  141. package/dist/extensions/pi-subagents/src/watchdog/warning-format.ts +73 -0
  142. package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +130 -2
  143. package/dist/extensions/pi-subagents/test/integration/acceptance-file-report.test.ts +439 -0
  144. package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +1632 -61
  145. package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +54 -1
  146. package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +112 -0
  147. package/dist/extensions/pi-subagents/test/integration/chain-clarify.test.ts +98 -1
  148. package/dist/extensions/pi-subagents/test/integration/chain-execution.test.ts +179 -9
  149. package/dist/extensions/pi-subagents/test/integration/detect-error.test.ts +16 -9
  150. package/dist/extensions/pi-subagents/test/integration/error-handling.test.ts +6 -5
  151. package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +589 -9
  152. package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +528 -21
  153. package/dist/extensions/pi-subagents/test/integration/parallel-execution.test.ts +227 -3
  154. package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +235 -7
  155. package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +27 -0
  156. package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +172 -2
  157. package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +1502 -18
  158. package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +993 -4
  159. package/dist/extensions/pi-subagents/test/integration/slash-live-state.test.ts +27 -0
  160. package/dist/extensions/pi-subagents/test/integration/top-level-async.test.ts +7 -1
  161. package/dist/extensions/pi-subagents/test/support/helpers.ts +32 -0
  162. package/dist/extensions/pi-subagents/test/support/mock-pi-script.mjs +59 -2
  163. package/dist/extensions/pi-subagents/test/support/mock-pi.ts +32 -6
  164. package/dist/extensions/pi-subagents/test/support/real-session-child-cli.mjs +25 -24
  165. package/dist/extensions/pi-subagents/test/support/real-session-runner.ts +59 -35
  166. package/dist/extensions/pi-subagents/test/support/session-lease-child.mjs +42 -0
  167. package/dist/extensions/pi-subagents/test/unit/acceptance.test.ts +703 -69
  168. package/dist/extensions/pi-subagents/test/unit/accessible-dir.test.ts +82 -0
  169. package/dist/extensions/pi-subagents/test/unit/agent-disabled.test.ts +15 -15
  170. package/dist/extensions/pi-subagents/test/unit/agent-eject-disable.test.ts +66 -66
  171. package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +478 -19
  172. package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +228 -7
  173. package/dist/extensions/pi-subagents/test/unit/agent-memory.test.ts +1 -1
  174. package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +198 -78
  175. package/dist/extensions/pi-subagents/test/unit/async-execution.test.ts +15 -1
  176. package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +102 -7
  177. package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +439 -6
  178. package/dist/extensions/pi-subagents/test/unit/atomic-json.test.ts +41 -1
  179. package/dist/extensions/pi-subagents/test/unit/auto-drain.test.ts +79 -0
  180. package/dist/extensions/pi-subagents/test/unit/background-work.test.ts +285 -0
  181. package/dist/extensions/pi-subagents/test/unit/capability-ceiling-pi-args.test.ts +84 -0
  182. package/dist/extensions/pi-subagents/test/unit/capability-ceiling.test.ts +68 -0
  183. package/dist/extensions/pi-subagents/test/unit/chain-validation.test.ts +326 -0
  184. package/dist/extensions/pi-subagents/test/unit/child-protocol.test.ts +82 -0
  185. package/dist/extensions/pi-subagents/test/unit/child-transcript.test.ts +46 -4
  186. package/dist/extensions/pi-subagents/test/unit/completion-batcher.test.ts +3 -1
  187. package/dist/extensions/pi-subagents/test/unit/completion-dedupe.test.ts +9 -17
  188. package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +175 -3
  189. package/dist/extensions/pi-subagents/test/unit/config-dir-runtime.test.ts +10 -5
  190. package/dist/extensions/pi-subagents/test/unit/control-channel.test.ts +126 -6
  191. package/dist/extensions/pi-subagents/test/unit/default-extensions.test.ts +219 -0
  192. package/dist/extensions/pi-subagents/test/unit/delegation-api.test.ts +913 -0
  193. package/dist/extensions/pi-subagents/test/unit/doctor.test.ts +13 -2
  194. package/dist/extensions/pi-subagents/test/unit/dynamic-fanout.test.ts +3 -3
  195. package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +351 -0
  196. package/dist/extensions/pi-subagents/test/unit/fleet-transcript.test.ts +280 -0
  197. package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +575 -0
  198. package/dist/extensions/pi-subagents/test/unit/foreground-control.test.ts +65 -0
  199. package/dist/extensions/pi-subagents/test/unit/fork-context.test.ts +94 -1
  200. package/dist/extensions/pi-subagents/test/unit/get-final-output.test.ts +23 -0
  201. package/dist/extensions/pi-subagents/test/unit/host-peer-runtime-imports.test.ts +157 -0
  202. package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +367 -5
  203. package/dist/extensions/pi-subagents/test/unit/intercom-bridge.test.ts +11 -0
  204. package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +36 -0
  205. package/dist/extensions/pi-subagents/test/unit/model-info.test.ts +25 -3
  206. package/dist/extensions/pi-subagents/test/unit/model-scope.test.ts +1 -1
  207. package/dist/extensions/pi-subagents/test/unit/native-supervisor-channel.test.ts +341 -10
  208. package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +16 -0
  209. package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +52 -0
  210. package/dist/extensions/pi-subagents/test/unit/notify.test.ts +168 -7
  211. package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +85 -7
  212. package/dist/extensions/pi-subagents/test/unit/parallel-handoff.test.ts +175 -0
  213. package/dist/extensions/pi-subagents/test/unit/path-resolution.test.ts +1 -1
  214. package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +243 -16
  215. package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +79 -36
  216. package/dist/extensions/pi-subagents/test/unit/pi-spawn.test.ts +174 -56
  217. package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +322 -0
  218. package/dist/extensions/pi-subagents/test/unit/process-terminal.test.ts +204 -0
  219. package/dist/extensions/pi-subagents/test/unit/recursion-guard.test.ts +20 -12
  220. package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +117 -4
  221. package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +40 -7
  222. package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +48 -1
  223. package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +21 -3
  224. package/dist/extensions/pi-subagents/test/unit/selector.test.ts +57 -0
  225. package/dist/extensions/pi-subagents/test/unit/session-lease.test.ts +326 -0
  226. package/dist/extensions/pi-subagents/test/unit/single-output.test.ts +101 -2
  227. package/dist/extensions/pi-subagents/test/unit/skills-fallback.test.ts +111 -1
  228. package/dist/extensions/pi-subagents/test/unit/spawn-budget.test.ts +124 -0
  229. package/dist/extensions/pi-subagents/test/unit/stale-run-reconciler.test.ts +6 -4
  230. package/dist/extensions/pi-subagents/test/unit/status-format.test.ts +7 -0
  231. package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +397 -0
  232. package/dist/extensions/pi-subagents/test/unit/steering-notices.test.ts +58 -0
  233. package/dist/extensions/pi-subagents/test/unit/steering.test.ts +173 -0
  234. package/dist/extensions/pi-subagents/test/unit/subagent-control.test.ts +25 -4
  235. package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +390 -25
  236. package/dist/extensions/pi-subagents/test/unit/subagent-wait.test.ts +837 -0
  237. package/dist/extensions/pi-subagents/test/unit/task-intent.test.ts +86 -0
  238. package/dist/extensions/pi-subagents/test/unit/tool-budget.test.ts +15 -0
  239. package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +47 -1
  240. package/dist/extensions/pi-subagents/test/unit/turn-budget.test.ts +56 -10
  241. package/dist/extensions/pi-subagents/test/unit/watchdog-change-signature.test.ts +387 -0
  242. package/dist/extensions/pi-subagents/test/unit/watchdog-child-status.test.ts +110 -0
  243. package/dist/extensions/pi-subagents/test/unit/watchdog-emission-guard.test.ts +62 -0
  244. package/dist/extensions/pi-subagents/test/unit/watchdog-lsp-diagnostics.test.ts +144 -0
  245. package/dist/extensions/pi-subagents/test/unit/watchdog-model-selection.test.ts +121 -0
  246. package/dist/extensions/pi-subagents/test/unit/watchdog-render.test.ts +76 -0
  247. package/dist/extensions/pi-subagents/test/unit/watchdog-review.test.ts +327 -0
  248. package/dist/extensions/pi-subagents/test/unit/watchdog-runtime.test.ts +863 -0
  249. package/dist/extensions/pi-subagents/test/unit/watchdog-settings.test.ts +290 -0
  250. package/dist/extensions/pi-subagents/test/unit/watchdog-tool-actions.test.ts +91 -0
  251. package/dist/extensions/pi-subagents/test/unit/watchdog-turn-delta.test.ts +130 -0
  252. package/dist/extensions/pi-subagents/test/unit/widget-nested-render.test.ts +32 -4
  253. package/dist/extensions/pi-subagents/test/unit/worktree.test.ts +5 -1
  254. package/dist/extensions/pi-subagents/test/unit/writer-budget-guidance.test.ts +30 -0
  255. package/dist/extensions/question/batch.ts +39 -0
  256. package/dist/extensions/question/dialog-adapter.ts +23 -1
  257. package/dist/extensions/question/index.ts +237 -7
  258. package/dist/extensions/question/schemas.ts +28 -15
  259. package/dist/extensions/question/tests/batch.test.ts +26 -0
  260. package/dist/extensions/question/tests/ui-protocol.test.ts +23 -3
  261. package/dist/extensions/question/tui-adapter.ts +2 -3
  262. package/dist/extensions/question/types.ts +37 -0
  263. package/dist/extensions/question/ui-protocol.ts +3 -3
  264. package/dist/skills/batch-grill-me/SKILL.md +3 -1
  265. package/package.json +2 -1
@@ -2,6 +2,8 @@ import assert from "node:assert/strict";
2
2
  import * as fs from "node:fs";
3
3
  import * as path from "node:path";
4
4
  import { describe, it } from "node:test";
5
+ import { getProjectArtifactsDir } from "../../src/shared/artifacts.ts";
6
+ import { SubagentFleetComponent } from "../../src/tui/fleet.ts";
5
7
  import { createTempDir, removeTempDir, tryImport } from "../support/helpers.ts";
6
8
 
7
9
  interface AsyncJobTrackerModule {
@@ -13,6 +15,7 @@ interface AsyncJobTrackerModule {
13
15
  completionRetentionMs?: number;
14
16
  pollIntervalMs?: number;
15
17
  resultsDir?: string;
18
+ widgetEnabled?: boolean;
16
19
  kill?: (pid: number, signal?: NodeJS.Signals | 0) => boolean;
17
20
  now?: () => number;
18
21
  },
@@ -33,6 +36,9 @@ function createState() {
33
36
  baseCwd: "/repo",
34
37
  currentSessionId: null,
35
38
  asyncJobs: new Map(),
39
+ fleetJobs: new Map(),
40
+ foregroundRuns: new Map(),
41
+ foregroundControls: new Map(),
36
42
  cleanupTimers: new Map(),
37
43
  lastUiContext: null,
38
44
  poller: null,
@@ -86,6 +92,7 @@ function createUiContext() {
86
92
  ui: {
87
93
  theme: {
88
94
  fg: (_theme: string, text: string) => text,
95
+ bold: (text: string) => text,
89
96
  },
90
97
  setWidget: (_key: string, value: unknown) => {
91
98
  widgets.push(value);
@@ -121,9 +128,11 @@ describe("async job tracker", { skip: !available ? "pi packages not available" :
121
128
  tracker.handleComplete({ id: "run-1", success: true });
122
129
 
123
130
  assert.equal(state.asyncJobs.size, 1);
131
+ assert.equal(state.fleetJobs.size, 1);
124
132
  await new Promise((resolve) => setTimeout(resolve, 40));
125
133
 
126
134
  assert.equal(state.asyncJobs.size, 0);
135
+ assert.equal(state.fleetJobs.get("run-1")?.status, "complete", "fleet history should outlive widget cleanup");
127
136
  assert.ok(ui.renderRequests > 0, "expected widget cleanup to request a rerender");
128
137
  assert.equal(ui.widgets.at(-1), undefined);
129
138
  } finally {
@@ -131,16 +140,44 @@ describe("async job tracker", { skip: !available ? "pi packages not available" :
131
140
  }
132
141
  });
133
142
 
143
+ it("keeps the async widget cleared when it is disabled", () => {
144
+ const asyncRoot = createTempDir("pi-async-job-widget-disabled-");
145
+ try {
146
+ const state = createState();
147
+ const ui = createUiContext();
148
+ const recorder = createEventRecorder();
149
+ const tracker = trackerMod!.createAsyncJobTracker(recorder.pi, state as never, asyncRoot, {
150
+ widgetEnabled: false,
151
+ });
152
+ tracker.resetJobs(ui.ctx as never);
153
+ tracker.handleStarted({ id: "run-hidden", asyncDir: path.join(asyncRoot, "run-hidden"), agent: "worker" });
154
+
155
+ assert.equal(state.asyncJobs.size, 1, "disabled rendering must not disable lifecycle tracking");
156
+ assert.ok(ui.widgets.length > 0, "expected widget clear calls");
157
+ assert.ok(ui.widgets.every((widget) => widget === undefined), "disabled widget must stay cleared");
158
+ tracker.resetJobs(ui.ctx as never);
159
+ assert.equal(state.fleetJobs.size, 0, "session reset should clear fleet history");
160
+ } finally {
161
+ removeTempDir(asyncRoot);
162
+ }
163
+ });
164
+
134
165
  it("restores active async runs into the widget after reset", async () => {
135
166
  const asyncRoot = createTempDir("pi-async-job-restore-");
136
167
  try {
137
168
  const runDir = path.join(asyncRoot, "run-restored");
169
+ const customCwd = path.join(asyncRoot, "custom-cwd");
170
+ const artifactsRoot = getProjectArtifactsDir(customCwd);
171
+ const transcriptPath = path.join(artifactsRoot, "run-restored_reviewer_transcript.jsonl");
138
172
  fs.mkdirSync(runDir, { recursive: true });
173
+ fs.mkdirSync(artifactsRoot, { recursive: true });
174
+ fs.writeFileSync(transcriptPath, `${JSON.stringify({ recordType: "message", role: "assistant", text: "Restored custom cwd transcript" })}\n`, "utf-8");
139
175
  fs.writeFileSync(path.join(runDir, "status.json"), JSON.stringify({
140
176
  runId: "run-restored",
141
177
  mode: "chain",
142
178
  state: "running",
143
179
  sessionId: "session-restored",
180
+ cwd: customCwd,
144
181
  startedAt: 1000,
145
182
  lastUpdate: 2000,
146
183
  currentStep: 1,
@@ -148,7 +185,7 @@ describe("async job tracker", { skip: !available ? "pi packages not available" :
148
185
  parallelGroups: [{ start: 1, count: 2, stepIndex: 1 }],
149
186
  steps: [
150
187
  { agent: "scout", status: "complete" },
151
- { agent: "reviewer", status: "running", currentTool: "read" },
188
+ { agent: "reviewer", status: "running", currentTool: "read", transcriptPath },
152
189
  { agent: "worker", status: "running" },
153
190
  { agent: "writer", status: "pending" },
154
191
  ],
@@ -180,6 +217,7 @@ describe("async job tracker", { skip: !available ? "pi packages not available" :
180
217
  assert.ok(job);
181
218
  assert.equal(job.status, "running");
182
219
  assert.equal(job.sessionId, "session-restored");
220
+ assert.equal(job.cwd, customCwd);
183
221
  assert.deepEqual(job.agents, ["reviewer", "worker"]);
184
222
  assert.deepEqual(job.steps?.map((step: { index?: number }) => step.index), [1, 2]);
185
223
  assert.equal(job.stepsTotal, 2);
@@ -190,6 +228,19 @@ describe("async job tracker", { skip: !available ? "pi packages not available" :
190
228
  assert.ok(ui.renderRequests >= 2, "expected reset and restore to request widget renders");
191
229
  assert.equal(typeof ui.widgets.at(-1), "function", "expected restored jobs to render the widget");
192
230
 
231
+ const component = new SubagentFleetComponent(
232
+ { terminal: { rows: 28, columns: 100 }, requestRender() {} } as never,
233
+ ui.ctx.ui.theme as never,
234
+ state as never,
235
+ () => {},
236
+ { refreshMs: 60_000 },
237
+ );
238
+ try {
239
+ assert.ok(component.render(100).some((line) => line.includes("Restored custom cwd transcript")));
240
+ } finally {
241
+ component.dispose();
242
+ }
243
+
193
244
  await new Promise((resolve) => setTimeout(resolve, 30));
194
245
  assert.equal(recorder.events.length, 0, "historical control events should not be replayed during restore");
195
246
  } finally {
@@ -303,6 +354,7 @@ describe("async job tracker", { skip: !available ? "pi packages not available" :
303
354
  tracker.handleStarted({
304
355
  id: "run-parallel-start",
305
356
  asyncDir: path.join(asyncRoot, "run-parallel-start"),
357
+ cwd: path.join(asyncRoot, "custom-cwd"),
306
358
  agent: "scout",
307
359
  agents: ["scout", "reviewer", "worker", "writer"],
308
360
  chain: ["[scout+reviewer+worker]", "writer"],
@@ -312,6 +364,7 @@ describe("async job tracker", { skip: !available ? "pi packages not available" :
312
364
 
313
365
  const job = state.asyncJobs.get("run-parallel-start");
314
366
  assert.deepEqual(job?.agents, ["scout", "reviewer", "worker"]);
367
+ assert.equal(job?.cwd, path.join(asyncRoot, "custom-cwd"));
315
368
  assert.equal(job?.chainStepCount, 2);
316
369
  assert.deepEqual(job?.parallelGroups, [{ start: 0, count: 3, stepIndex: 0 }]);
317
370
  assert.equal(job?.stepsTotal, 3);
@@ -53,6 +53,91 @@ describe("async status helpers", () => {
53
53
  }
54
54
  });
55
55
 
56
+ it("preserves agent contract projections on step summaries", () => {
57
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), "pi-async-status-contract-"));
58
+ try {
59
+ createAsyncDir(root, "run-contract", {
60
+ runId: "run-contract",
61
+ mode: "single",
62
+ state: "complete",
63
+ startedAt: 100,
64
+ lastUpdate: 200,
65
+ steps: [{
66
+ agent: "worker",
67
+ status: "complete",
68
+ agentContract: { version: 1 },
69
+ execution: { status: "completed", success: true, exitCode: 0 },
70
+ acceptance: { status: "rejected", effectiveAcceptance: { level: "checked", explicit: true } },
71
+ review: { status: "not-requested" },
72
+ effects: { fileMutation: { status: "missing", expected: true, attempted: false } },
73
+ }],
74
+ });
75
+
76
+ const runs = listAsyncRuns(root, { states: ["complete"] });
77
+ const step = runs[0]?.steps[0];
78
+ assert.equal(step?.agentContract?.version, 1);
79
+ assert.deepEqual(step?.execution, { status: "completed", success: true, exitCode: 0 });
80
+ assert.equal(step?.acceptance?.status, "rejected");
81
+ assert.equal(step?.review?.status, "not-requested");
82
+ assert.equal(step?.effects?.fileMutation?.status, "missing");
83
+ } finally {
84
+ fs.rmSync(root, { recursive: true, force: true });
85
+ }
86
+ });
87
+
88
+ it("preserves capability ceiling and audit projections on summaries", () => {
89
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), "pi-async-status-capability-"));
90
+ try {
91
+ const ceiling = { version: 1, allowedTools: ["read"], denyExtensions: true, sources: ["plan"] };
92
+ const audit = { ceiling, requestedTools: ["read", "write"], effectiveTools: ["read"], removedTools: ["write"], internalTools: [], extensionsDenied: true, removedExtensionCount: 1, requestedMcpToolCount: 0, effectiveMcpTools: [] };
93
+ createAsyncDir(root, "run-capability", {
94
+ runId: "run-capability",
95
+ mode: "single",
96
+ state: "complete",
97
+ startedAt: 100,
98
+ lastUpdate: 200,
99
+ capabilityCeiling: ceiling,
100
+ capabilityAudit: audit,
101
+ steps: [{ agent: "worker", status: "complete", capabilityCeiling: ceiling, capabilityAudit: audit }],
102
+ });
103
+
104
+ const runs = listAsyncRuns(root, { states: ["complete"] });
105
+ assert.deepEqual(runs[0]?.capabilityCeiling, ceiling);
106
+ assert.deepEqual(runs[0]?.capabilityAudit, audit);
107
+ assert.deepEqual(runs[0]?.steps[0]?.capabilityCeiling, ceiling);
108
+ assert.deepEqual(runs[0]?.steps[0]?.capabilityAudit, audit);
109
+ } finally {
110
+ fs.rmSync(root, { recursive: true, force: true });
111
+ }
112
+ });
113
+
114
+ it("formats async run and step context labels", () => {
115
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), "pi-async-status-context-"));
116
+ try {
117
+ createAsyncDir(root, "run-context", {
118
+ runId: "run-context",
119
+ mode: "parallel",
120
+ state: "running",
121
+ startedAt: 100,
122
+ lastUpdate: 200,
123
+ steps: [
124
+ { agent: "scout", context: "fresh", status: "running" },
125
+ { agent: "worker", context: "fork", status: "running" },
126
+ ],
127
+ });
128
+
129
+ const runs = listAsyncRuns(root, { states: ["running"] });
130
+ assert.equal(runs[0]?.context, "mixed");
131
+ assert.deepEqual(runs[0]?.steps.map((step) => step.context), ["fresh", "fork"]);
132
+ const text = formatAsyncRunList(runs);
133
+ assert.match(text, /run-context \| running .* \| parallel \[mixed\]/);
134
+ assert.match(text, /1\. scout \[fresh\] \| running/);
135
+ assert.match(text, /2\. worker \[fork\] \| running/);
136
+ } finally {
137
+ fs.rmSync(root, { recursive: true, force: true });
138
+ }
139
+ });
140
+
56
141
  it("formats model thinking in step summaries", () => {
57
142
  const root = fs.mkdtempSync(path.join(os.tmpdir(), "pi-async-status-model-thinking-"));
58
143
  try {
@@ -107,6 +192,33 @@ describe("async status helpers", () => {
107
192
  }
108
193
  });
109
194
 
195
+ it("renders deferred turn-budget termination distinctly from a soft wrap-up request", () => {
196
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), "pi-async-turn-budget-deferred-"));
197
+ try {
198
+ createAsyncDir(root, "run-deferred", {
199
+ runId: "run-deferred",
200
+ mode: "single",
201
+ state: "running",
202
+ startedAt: Date.now() - 1_000,
203
+ lastUpdate: Date.now(),
204
+ wrapUpRequested: true,
205
+ turnBudget: { maxTurns: 2, graceTurns: 1, turnCount: 3, outcome: "termination-deferred", wrapUpRequestedAtTurn: 2, terminationDeferredAtTurn: 3 },
206
+ steps: [{
207
+ agent: "worker",
208
+ status: "running",
209
+ wrapUpRequested: true,
210
+ turnBudget: { maxTurns: 2, graceTurns: 1, turnCount: 3, outcome: "termination-deferred", wrapUpRequestedAtTurn: 2, terminationDeferredAtTurn: 3 },
211
+ }],
212
+ });
213
+
214
+ const text = formatAsyncRunList(listAsyncRuns(root, { states: ["running"] }));
215
+ assert.match(text, /turn-budget termination deferred 3\/2\+1/);
216
+ assert.doesNotMatch(text, /wrap-up requested/);
217
+ } finally {
218
+ fs.rmSync(root, { recursive: true, force: true });
219
+ }
220
+ });
221
+
110
222
  it("does not infer attention state when the runner has not persisted one", () => {
111
223
  const root = fs.mkdtempSync(path.join(os.tmpdir(), "pi-async-no-derived-attention-"));
112
224
  try {
@@ -8,7 +8,7 @@ interface ClarifyTestModel {
8
8
  id: string;
9
9
  fullId: string;
10
10
  reasoning?: boolean;
11
- thinkingLevelMap?: Partial<Record<"off" | "minimal" | "low" | "medium" | "high" | "xhigh", string | null>>;
11
+ thinkingLevelMap?: Partial<Record<"off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max", string | null>>;
12
12
  }
13
13
 
14
14
  interface ClarifyTestComponent {
@@ -116,6 +116,38 @@ describe("chain clarify model display", { skip: !available ? "pi packages not av
116
116
  assert.doesNotMatch(rendered, /minimal - Brief reasoning/);
117
117
  assert.doesNotMatch(rendered, /low - Light reasoning/);
118
118
  assert.doesNotMatch(rendered, /medium - Moderate reasoning/);
119
+ assert.doesNotMatch(rendered, /max - Maximum available reasoning/);
120
+ });
121
+
122
+ it("renders the max thinking option when the selected model exposes it", () => {
123
+ const component = new ChainClarifyComponent(
124
+ { requestRender() {} },
125
+ { fg(_key: string, text: string) { return text; } },
126
+ [{
127
+ name: "worker",
128
+ description: "",
129
+ systemPrompt: "",
130
+ systemPromptMode: "replace",
131
+ inheritProjectContext: false,
132
+ inheritSkills: false,
133
+ source: "user",
134
+ filePath: "worker.md",
135
+ model: "openai/gpt-5",
136
+ }],
137
+ ["Task"],
138
+ "Task",
139
+ undefined,
140
+ [{ output: false, outputMode: "inline", reads: false, progress: false, skills: [], model: "openai/gpt-5" }],
141
+ [{ provider: "openai", id: "gpt-5", fullId: "openai/gpt-5", reasoning: true, thinkingLevelMap: { max: "max" } }],
142
+ "openai",
143
+ [],
144
+ () => {},
145
+ "single",
146
+ );
147
+ component.selectedStep = 0;
148
+ component.enterThinkingSelector();
149
+ const rendered = component.renderThinkingSelector().join("\n");
150
+ assert.match(rendered, /max - Maximum available reasoning/);
119
151
  });
120
152
 
121
153
  it("drops thinking when switching to a model that does not support it", () => {
@@ -271,4 +303,69 @@ describe("chain clarify model display", { skip: !available ? "pi packages not av
271
303
 
272
304
  assert.equal(component.getEffectiveModel(0), "github-copilot/gpt-5:high");
273
305
  });
306
+
307
+ it("labels every shortcut and keeps the clarify overlay within 84 columns", () => {
308
+ for (const mode of ["single", "parallel", "chain"] as const) {
309
+ const count = mode === "single" ? 1 : mode === "parallel" ? 2 : 4;
310
+ const component = new ChainClarifyComponent(
311
+ { requestRender() {} },
312
+ { fg(_key: string, text: string) { return `\u001b[31m${text}\u001b[0m`; } },
313
+ Array.from({ length: count }, (_, index) => ({
314
+ name: `agent-${index + 1}`,
315
+ description: "",
316
+ systemPrompt: "",
317
+ systemPromptMode: "replace",
318
+ inheritProjectContext: false,
319
+ inheritSkills: false,
320
+ source: "user",
321
+ filePath: `agent-${index + 1}.md`,
322
+ })),
323
+ Array.from({ length: count }, (_, index) => index === 0 ? "Task" : "Use {previous}"),
324
+ "Task",
325
+ undefined,
326
+ Array.from({ length: count }, () => ({
327
+ output: false,
328
+ outputMode: "inline",
329
+ reads: false,
330
+ progress: false,
331
+ skills: [],
332
+ model: undefined,
333
+ })),
334
+ [],
335
+ undefined,
336
+ [],
337
+ () => {},
338
+ mode,
339
+ );
340
+
341
+ const initialLines = component.render(84).map(stripAnsi);
342
+ const initial = initialLines.join("\n");
343
+ assert.match(initial, /\[e\]Task/);
344
+ assert.match(initial, /\[m\]Model/);
345
+ assert.match(initial, /\[t\]Think/);
346
+ assert.match(initial, /\[s\]Skills/);
347
+ assert.match(initial, /\[b\]Background:OFF/);
348
+ assert.doesNotMatch(initial, /• e m t/);
349
+ assert.match(initial, /\[Enter\] Run • \[Esc\] Cancel/);
350
+ if (mode === "single") {
351
+ assert.match(initial, /\[w\]Output/);
352
+ assert.doesNotMatch(initial, /\[↑↓\] Navigate/);
353
+ } else {
354
+ assert.match(initial, /\[↑↓\] Navigate/);
355
+ }
356
+ if (mode === "chain") {
357
+ assert.match(initial, /\[w\]Output/);
358
+ assert.match(initial, /\[r\]Reads/);
359
+ assert.match(initial, /\[p\]Prog/);
360
+ } else if (mode === "parallel") {
361
+ assert.doesNotMatch(initial, /\[w\]Output|\[r\]Reads|\[p\]Prog/);
362
+ }
363
+ for (const line of initialLines) {
364
+ assert.equal(visibleWidth(line), 84, `${mode} line did not match component width: ${line}`);
365
+ }
366
+
367
+ component.handleInput("b");
368
+ assert.match(component.render(84).map(stripAnsi).join("\n"), /\[b\]Background:ON/);
369
+ }
370
+ });
274
371
  });