@selesai/code 0.6.2 → 0.7.0

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 (997) hide show
  1. package/CHANGELOG.md +16 -1
  2. package/README.md +1 -1
  3. package/dist/bun/cli.d.ts +0 -1
  4. package/dist/bun/cli.js +0 -1
  5. package/dist/bun/register-bedrock.d.ts +0 -1
  6. package/dist/bun/register-bedrock.js +0 -1
  7. package/dist/bun/restore-sandbox-env.d.ts +0 -1
  8. package/dist/bun/restore-sandbox-env.js +0 -1
  9. package/dist/cli/args.d.ts +0 -1
  10. package/dist/cli/args.js +0 -1
  11. package/dist/cli/config-selector.d.ts +0 -1
  12. package/dist/cli/config-selector.js +0 -1
  13. package/dist/cli/credential-print.d.ts +0 -1
  14. package/dist/cli/credential-print.js +0 -1
  15. package/dist/cli/file-processor.d.ts +0 -1
  16. package/dist/cli/file-processor.js +0 -1
  17. package/dist/cli/initial-message.d.ts +0 -1
  18. package/dist/cli/initial-message.js +0 -1
  19. package/dist/cli/list-models.d.ts +0 -1
  20. package/dist/cli/list-models.js +0 -1
  21. package/dist/cli/project-trust.d.ts +0 -1
  22. package/dist/cli/project-trust.js +0 -1
  23. package/dist/cli/session-picker.d.ts +0 -1
  24. package/dist/cli/session-picker.js +0 -1
  25. package/dist/cli/startup-ui.d.ts +0 -1
  26. package/dist/cli/startup-ui.js +0 -1
  27. package/dist/cli.d.ts +0 -1
  28. package/dist/cli.js +0 -1
  29. package/dist/config.d.ts +0 -1
  30. package/dist/config.js +0 -1
  31. package/dist/core/agent-session-auto-handoff.test.d.ts +0 -1
  32. package/dist/core/agent-session-auto-handoff.test.js +0 -1
  33. package/dist/core/agent-session-runtime.d.ts +0 -1
  34. package/dist/core/agent-session-runtime.js +0 -1
  35. package/dist/core/agent-session-services.d.ts +0 -1
  36. package/dist/core/agent-session-services.js +0 -1
  37. package/dist/core/agent-session-skill-block.test.d.ts +0 -1
  38. package/dist/core/agent-session-skill-block.test.js +0 -1
  39. package/dist/core/agent-session.d.ts +0 -1
  40. package/dist/core/agent-session.js +0 -1
  41. package/dist/core/agents.d.ts +0 -1
  42. package/dist/core/agents.js +0 -1
  43. package/dist/core/auth-guidance.d.ts +0 -1
  44. package/dist/core/auth-guidance.js +0 -1
  45. package/dist/core/auth-storage.d.ts +0 -1
  46. package/dist/core/auth-storage.js +0 -1
  47. package/dist/core/bash-executor.d.ts +0 -1
  48. package/dist/core/bash-executor.js +0 -1
  49. package/dist/core/built-in-extensions.d.ts +0 -1
  50. package/dist/core/built-in-extensions.js +0 -1
  51. package/dist/core/cache-stats.d.ts +0 -1
  52. package/dist/core/cache-stats.js +0 -1
  53. package/dist/core/compaction/branch-summarization.d.ts +0 -1
  54. package/dist/core/compaction/branch-summarization.js +0 -1
  55. package/dist/core/compaction/compaction.d.ts +0 -1
  56. package/dist/core/compaction/compaction.js +0 -1
  57. package/dist/core/compaction/index.d.ts +0 -1
  58. package/dist/core/compaction/index.js +0 -1
  59. package/dist/core/compaction/utils.d.ts +0 -1
  60. package/dist/core/compaction/utils.js +0 -1
  61. package/dist/core/defaults.d.ts +0 -1
  62. package/dist/core/defaults.js +0 -1
  63. package/dist/core/diagnostics.d.ts +0 -1
  64. package/dist/core/diagnostics.js +0 -1
  65. package/dist/core/event-bus.d.ts +0 -1
  66. package/dist/core/event-bus.js +0 -1
  67. package/dist/core/exec.d.ts +0 -1
  68. package/dist/core/exec.js +0 -1
  69. package/dist/core/experimental.d.ts +0 -1
  70. package/dist/core/experimental.js +0 -1
  71. package/dist/core/export-html/ansi-to-html.d.ts +0 -1
  72. package/dist/core/export-html/ansi-to-html.js +0 -1
  73. package/dist/core/export-html/index.d.ts +0 -1
  74. package/dist/core/export-html/index.js +0 -1
  75. package/dist/core/export-html/tool-renderer.d.ts +0 -1
  76. package/dist/core/export-html/tool-renderer.js +0 -1
  77. package/dist/core/extensions/index.d.ts +0 -1
  78. package/dist/core/extensions/index.js +0 -1
  79. package/dist/core/extensions/loader.d.ts +0 -1
  80. package/dist/core/extensions/loader.js +0 -1
  81. package/dist/core/extensions/runner.d.ts +0 -1
  82. package/dist/core/extensions/runner.js +0 -1
  83. package/dist/core/extensions/types.d.ts +0 -1
  84. package/dist/core/extensions/types.js +0 -1
  85. package/dist/core/extensions/wrapper.d.ts +0 -1
  86. package/dist/core/extensions/wrapper.js +0 -1
  87. package/dist/core/footer-data-provider.d.ts +0 -1
  88. package/dist/core/footer-data-provider.js +0 -1
  89. package/dist/core/git-command.d.ts +0 -1
  90. package/dist/core/git-command.js +0 -1
  91. package/dist/core/http-dispatcher.d.ts +0 -1
  92. package/dist/core/http-dispatcher.js +0 -1
  93. package/dist/core/index.d.ts +0 -1
  94. package/dist/core/index.js +0 -1
  95. package/dist/core/keybindings.d.ts +0 -1
  96. package/dist/core/keybindings.js +0 -1
  97. package/dist/core/llama/client.d.ts +0 -1
  98. package/dist/core/llama/client.js +0 -1
  99. package/dist/core/llama/huggingface.d.ts +0 -1
  100. package/dist/core/llama/huggingface.js +0 -1
  101. package/dist/core/llama/index.d.ts +0 -1
  102. package/dist/core/llama/index.js +0 -1
  103. package/dist/core/llama/provider.d.ts +0 -1
  104. package/dist/core/llama/provider.js +0 -1
  105. package/dist/core/llama/ui.d.ts +0 -1
  106. package/dist/core/llama/ui.js +0 -1
  107. package/dist/core/messages.d.ts +0 -1
  108. package/dist/core/messages.js +0 -1
  109. package/dist/core/model-config.d.ts +0 -1
  110. package/dist/core/model-config.js +0 -1
  111. package/dist/core/model-registry.d.ts +0 -1
  112. package/dist/core/model-registry.js +0 -1
  113. package/dist/core/model-resolver.d.ts +0 -1
  114. package/dist/core/model-resolver.js +0 -1
  115. package/dist/core/model-runtime.d.ts +0 -1
  116. package/dist/core/model-runtime.js +0 -1
  117. package/dist/core/models-store.d.ts +0 -1
  118. package/dist/core/models-store.js +0 -1
  119. package/dist/core/output-guard.d.ts +0 -1
  120. package/dist/core/output-guard.js +0 -1
  121. package/dist/core/package-manager.d.ts +0 -1
  122. package/dist/core/package-manager.js +0 -1
  123. package/dist/core/package-manager.test.d.ts +0 -1
  124. package/dist/core/package-manager.test.js +0 -1
  125. package/dist/core/project-trust.d.ts +0 -1
  126. package/dist/core/project-trust.js +0 -1
  127. package/dist/core/prompt-templates.d.ts +0 -1
  128. package/dist/core/prompt-templates.js +0 -1
  129. package/dist/core/provider-attribution.d.ts +0 -1
  130. package/dist/core/provider-attribution.js +0 -1
  131. package/dist/core/provider-composer.d.ts +0 -1
  132. package/dist/core/provider-composer.js +0 -1
  133. package/dist/core/radius.d.ts +0 -1
  134. package/dist/core/radius.js +0 -1
  135. package/dist/core/remote-catalog-provider.d.ts +0 -1
  136. package/dist/core/remote-catalog-provider.js +0 -1
  137. package/dist/core/resolve-config-value.d.ts +0 -1
  138. package/dist/core/resolve-config-value.js +0 -1
  139. package/dist/core/resource-loader.d.ts +0 -1
  140. package/dist/core/resource-loader.js +0 -1
  141. package/dist/core/runtime-credentials.d.ts +0 -1
  142. package/dist/core/runtime-credentials.js +0 -1
  143. package/dist/core/sdk.d.ts +0 -1
  144. package/dist/core/sdk.js +0 -1
  145. package/dist/core/session-cwd.d.ts +0 -1
  146. package/dist/core/session-cwd.js +0 -1
  147. package/dist/core/session-manager.d.ts +0 -1
  148. package/dist/core/session-manager.js +0 -1
  149. package/dist/core/settings-manager-auto-handoff.test.d.ts +0 -1
  150. package/dist/core/settings-manager-auto-handoff.test.js +0 -1
  151. package/dist/core/settings-manager.d.ts +0 -4
  152. package/dist/core/settings-manager.js +0 -12
  153. package/dist/core/skills.d.ts +0 -1
  154. package/dist/core/skills.js +0 -1
  155. package/dist/core/slash-commands.d.ts +0 -1
  156. package/dist/core/slash-commands.js +0 -1
  157. package/dist/core/source-info.d.ts +0 -1
  158. package/dist/core/source-info.js +0 -1
  159. package/dist/core/system-prompt.d.ts +0 -1
  160. package/dist/core/system-prompt.js +0 -1
  161. package/dist/core/system-prompt.test.d.ts +0 -1
  162. package/dist/core/system-prompt.test.js +0 -1
  163. package/dist/core/telemetry.d.ts +0 -1
  164. package/dist/core/telemetry.js +0 -1
  165. package/dist/core/timings.d.ts +0 -1
  166. package/dist/core/timings.js +0 -1
  167. package/dist/core/tools/bash.d.ts +0 -1
  168. package/dist/core/tools/bash.js +0 -1
  169. package/dist/core/tools/edit-diff.d.ts +0 -1
  170. package/dist/core/tools/edit-diff.js +0 -1
  171. package/dist/core/tools/edit.d.ts +0 -1
  172. package/dist/core/tools/edit.js +0 -1
  173. package/dist/core/tools/file-mutation-queue.d.ts +0 -1
  174. package/dist/core/tools/file-mutation-queue.js +0 -1
  175. package/dist/core/tools/find.d.ts +0 -1
  176. package/dist/core/tools/find.js +0 -1
  177. package/dist/core/tools/grep.d.ts +0 -1
  178. package/dist/core/tools/grep.js +0 -1
  179. package/dist/core/tools/index.d.ts +0 -1
  180. package/dist/core/tools/index.js +0 -1
  181. package/dist/core/tools/ls.d.ts +0 -1
  182. package/dist/core/tools/ls.js +0 -1
  183. package/dist/core/tools/output-accumulator.d.ts +0 -1
  184. package/dist/core/tools/output-accumulator.js +0 -1
  185. package/dist/core/tools/path-utils.d.ts +0 -1
  186. package/dist/core/tools/path-utils.js +0 -1
  187. package/dist/core/tools/read.d.ts +0 -1
  188. package/dist/core/tools/read.js +0 -1
  189. package/dist/core/tools/render-utils.d.ts +0 -1
  190. package/dist/core/tools/render-utils.js +0 -1
  191. package/dist/core/tools/tool-definition-wrapper.d.ts +0 -1
  192. package/dist/core/tools/tool-definition-wrapper.js +0 -1
  193. package/dist/core/tools/truncate.d.ts +0 -1
  194. package/dist/core/tools/truncate.js +0 -1
  195. package/dist/core/tools/write.d.ts +0 -1
  196. package/dist/core/tools/write.js +0 -1
  197. package/dist/core/trust-manager.d.ts +0 -1
  198. package/dist/core/trust-manager.js +0 -1
  199. package/dist/core/usage-totals.d.ts +0 -1
  200. package/dist/core/usage-totals.js +0 -1
  201. package/dist/defaults/models.json +8 -0
  202. package/dist/defaults/settings.json +6 -7
  203. package/dist/extensions/inline-skills.test.ts +13 -13
  204. package/dist/extensions/inline-skills.ts +6 -6
  205. package/dist/extensions/pi-subagents/CHANGELOG.md +89 -12
  206. package/dist/extensions/pi-subagents/README.md +339 -604
  207. package/dist/extensions/pi-subagents/package-lock.json +190 -2079
  208. package/dist/extensions/pi-subagents/package.json +13 -5
  209. package/dist/extensions/pi-subagents/prompts/parallel-context-build.md +1 -1
  210. package/dist/extensions/pi-subagents/prompts/parallel-handoff-plan.md +1 -1
  211. package/dist/extensions/pi-subagents/prompts/review-loop.md +1 -1
  212. package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +10 -10
  213. package/dist/extensions/pi-subagents/skills/pi-subagents/references/constraints-and-recipes.md +32 -43
  214. package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +106 -105
  215. package/dist/extensions/pi-subagents/skills/pi-subagents/references/management-authoring-rpc.md +3 -3
  216. package/dist/extensions/pi-subagents/skills/pi-subagents/references/prompting-and-roles.md +28 -35
  217. package/dist/extensions/pi-subagents/src/agents/agent-management.ts +167 -124
  218. package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +19 -0
  219. package/dist/extensions/pi-subagents/src/agents/agents.ts +163 -75
  220. package/dist/extensions/pi-subagents/src/agents/chain-serializer.ts +10 -7
  221. package/dist/extensions/pi-subagents/src/agents/frontmatter.ts +5 -3
  222. package/dist/extensions/pi-subagents/src/agents/identity.ts +1 -1
  223. package/dist/extensions/pi-subagents/src/agents/proactive-skills.ts +14 -11
  224. package/dist/extensions/pi-subagents/src/agents/skills.ts +23 -6
  225. package/dist/extensions/pi-subagents/src/agents/task-aware-routing.ts +8 -1
  226. package/dist/extensions/pi-subagents/src/api/control-channel.ts +4 -0
  227. package/dist/extensions/pi-subagents/src/api/delegation.ts +26 -194
  228. package/dist/extensions/pi-subagents/src/api/external-runs.ts +129 -0
  229. package/dist/extensions/pi-subagents/src/api/intercom-bridge.ts +3 -0
  230. package/dist/extensions/pi-subagents/src/api/pi-args.ts +5 -0
  231. package/dist/extensions/pi-subagents/src/api/preflight.ts +4 -4
  232. package/dist/extensions/pi-subagents/src/api/shared-types.ts +19 -0
  233. package/dist/extensions/pi-subagents/src/extension/config.ts +10 -0
  234. package/dist/extensions/pi-subagents/src/extension/control-notices.ts +5 -39
  235. package/dist/extensions/pi-subagents/src/extension/doctor.ts +10 -9
  236. package/dist/extensions/pi-subagents/src/extension/fanout-child.ts +7 -4
  237. package/dist/extensions/pi-subagents/src/extension/index.ts +243 -77
  238. package/dist/extensions/pi-subagents/src/extension/rpc.ts +18 -6
  239. package/dist/extensions/pi-subagents/src/extension/schemas.ts +50 -39
  240. package/dist/extensions/pi-subagents/src/extension/tool-description.ts +36 -103
  241. package/dist/extensions/pi-subagents/src/inspectors/herdr/actions.ts +229 -0
  242. package/dist/extensions/pi-subagents/src/inspectors/herdr/client.ts +130 -0
  243. package/dist/extensions/pi-subagents/src/inspectors/herdr/inspector-runner.ts +141 -0
  244. package/dist/extensions/pi-subagents/src/inspectors/herdr/project-panes.ts +154 -0
  245. package/dist/extensions/pi-subagents/src/integrations/herdr-status.ts +330 -0
  246. package/dist/extensions/pi-subagents/src/intercom/intercom-bridge.ts +3 -2
  247. package/dist/extensions/pi-subagents/src/intercom/result-intercom.ts +5 -1
  248. package/dist/extensions/pi-subagents/src/missions/actions.ts +372 -0
  249. package/dist/extensions/pi-subagents/src/missions/lifecycle.ts +314 -0
  250. package/dist/extensions/pi-subagents/src/missions/store.ts +442 -0
  251. package/dist/extensions/pi-subagents/src/missions/types.ts +135 -0
  252. package/dist/extensions/pi-subagents/src/policy/authority.ts +46 -0
  253. package/dist/extensions/pi-subagents/src/profiles/profiles.ts +32 -6
  254. package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +103 -72
  255. package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +10 -2
  256. package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +6 -6
  257. package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +29 -1
  258. package/dist/extensions/pi-subagents/src/runs/background/auto-drain.ts +3 -3
  259. package/dist/extensions/pi-subagents/src/runs/background/chain-append.ts +3 -2
  260. package/dist/extensions/pi-subagents/src/runs/background/control-channel.ts +9 -7
  261. package/dist/extensions/pi-subagents/src/runs/background/fleet-view.ts +3 -4
  262. package/dist/extensions/pi-subagents/src/runs/background/notify.ts +3 -28
  263. package/dist/extensions/pi-subagents/src/runs/background/process-terminal.ts +5 -5
  264. package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +18 -68
  265. package/dist/extensions/pi-subagents/src/runs/background/run-id-resolver.ts +3 -3
  266. package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +35 -8
  267. package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +602 -375
  268. package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +3 -3
  269. package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +612 -464
  270. package/dist/extensions/pi-subagents/src/runs/background/subagent-wait.ts +50 -9
  271. package/dist/extensions/pi-subagents/src/runs/background/wait-subscriptions.ts +253 -0
  272. package/dist/extensions/pi-subagents/src/runs/background/wait-tool.ts +12 -4
  273. package/dist/extensions/pi-subagents/src/runs/foreground/async-steering-action.ts +3 -3
  274. package/dist/extensions/pi-subagents/src/runs/foreground/chain-clarify.ts +8 -4
  275. package/dist/extensions/pi-subagents/src/runs/foreground/chain-execution.ts +74 -102
  276. package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +21 -22
  277. package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +1050 -396
  278. package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +44 -18
  279. package/dist/extensions/pi-subagents/src/runs/shared/capability-ceiling.ts +0 -1
  280. package/dist/extensions/pi-subagents/src/runs/shared/child-protocol.ts +302 -22
  281. package/dist/extensions/pi-subagents/src/runs/shared/dynamic-fanout.ts +1 -1
  282. package/dist/extensions/pi-subagents/src/runs/shared/external-cli-runner.ts +130 -0
  283. package/dist/extensions/pi-subagents/src/runs/shared/long-running-guard.ts +42 -1
  284. package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +1 -1
  285. package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +59 -5
  286. package/dist/extensions/pi-subagents/src/runs/shared/nested-render.ts +9 -4
  287. package/dist/extensions/pi-subagents/src/runs/shared/parallel-handoff.ts +86 -2
  288. package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +11 -2
  289. package/dist/extensions/pi-subagents/src/runs/shared/permissions.ts +95 -0
  290. package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +11 -1
  291. package/dist/extensions/pi-subagents/src/runs/shared/pi-spawn.ts +15 -6
  292. package/dist/extensions/pi-subagents/src/runs/shared/run-history.ts +1 -1
  293. package/dist/extensions/pi-subagents/src/runs/shared/single-output.ts +9 -63
  294. package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +37 -6
  295. package/dist/extensions/pi-subagents/src/runs/shared/subagent-startup-retry.ts +5 -2
  296. package/dist/extensions/pi-subagents/src/runs/shared/task-intent.ts +2 -23
  297. package/dist/extensions/pi-subagents/src/runs/shared/turn-budget.ts +6 -6
  298. package/dist/extensions/pi-subagents/src/runs/shared/worktree.ts +124 -13
  299. package/dist/extensions/pi-subagents/src/shared/accessible-dir.ts +29 -7
  300. package/dist/extensions/pi-subagents/src/shared/artifacts.ts +18 -1
  301. package/dist/extensions/pi-subagents/src/shared/fork-context.ts +3 -2
  302. package/dist/extensions/pi-subagents/src/shared/launch-contract.ts +1 -0
  303. package/dist/extensions/pi-subagents/src/shared/settings.ts +10 -0
  304. package/dist/extensions/pi-subagents/src/shared/types.ts +158 -55
  305. package/dist/extensions/pi-subagents/src/shared/utils.ts +16 -66
  306. package/dist/extensions/pi-subagents/src/slash/delegation-adapters.ts +33 -199
  307. package/dist/extensions/pi-subagents/src/slash/delegation-request.ts +43 -126
  308. package/dist/extensions/pi-subagents/src/slash/inline-subagents.ts +103 -0
  309. package/dist/extensions/pi-subagents/src/slash/prompt-template-bridge.ts +158 -205
  310. package/dist/extensions/pi-subagents/src/slash/prompt-workflows.ts +22 -58
  311. package/dist/extensions/pi-subagents/src/slash/slash-bridge.ts +14 -0
  312. package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +44 -642
  313. package/dist/extensions/pi-subagents/src/slash/subagents-admin.ts +18 -14
  314. package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +156 -21
  315. package/dist/extensions/pi-subagents/src/tui/fleet-transcript.ts +110 -5
  316. package/dist/extensions/pi-subagents/src/tui/fleet.ts +60 -24
  317. package/dist/extensions/pi-subagents/src/tui/render.ts +296 -140
  318. package/dist/extensions/pi-subagents/src/types/pi-runtime-compat.d.ts +14 -0
  319. package/dist/extensions/pi-subagents/src/watchdog/change-signature.ts +1 -1
  320. package/dist/extensions/pi-subagents/src/watchdog/lsp-diagnostics.ts +13 -7
  321. package/dist/extensions/pi-subagents/src/watchdog/model-selection.ts +2 -2
  322. package/dist/extensions/pi-subagents/src/watchdog/permission-arbiter.ts +145 -0
  323. package/dist/extensions/pi-subagents/src/watchdog/register-child.ts +1 -1
  324. package/dist/extensions/pi-subagents/src/watchdog/register-main.ts +1 -1
  325. package/dist/extensions/pi-subagents/src/watchdog/review.ts +4 -1
  326. package/dist/extensions/pi-subagents/src/watchdog/runtime.ts +3 -2
  327. package/dist/extensions/pi-subagents/src/workflows/chat-progress.ts +140 -0
  328. package/dist/extensions/pi-subagents/src/workflows/scripted-workflow.ts +415 -0
  329. package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +41 -144
  330. package/dist/extensions/pi-subagents/test/integration/acceptance-file-report.test.ts +16 -16
  331. package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +415 -298
  332. package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +149 -82
  333. package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +40 -40
  334. package/dist/extensions/pi-subagents/test/integration/chain-clarify.test.ts +15 -15
  335. package/dist/extensions/pi-subagents/test/integration/chain-execution.test.ts +193 -133
  336. package/dist/extensions/pi-subagents/test/integration/detect-error.test.ts +1 -49
  337. package/dist/extensions/pi-subagents/test/integration/external-cli-runner.test.ts +62 -0
  338. package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +56 -58
  339. package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +81 -68
  340. package/dist/extensions/pi-subagents/test/integration/parallel-execution.test.ts +20 -25
  341. package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +425 -317
  342. package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +73 -73
  343. package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +123 -98
  344. package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +653 -240
  345. package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +20 -1661
  346. package/dist/extensions/pi-subagents/test/integration/slash-live-state.test.ts +9 -9
  347. package/dist/extensions/pi-subagents/test/integration/template-resolution.test.ts +3 -3
  348. package/dist/extensions/pi-subagents/test/integration/top-level-async.test.ts +2 -2
  349. package/dist/extensions/pi-subagents/test/support/mock-pi-script.mjs +8 -5
  350. package/dist/extensions/pi-subagents/test/support/mock-pi.ts +6 -6
  351. package/dist/extensions/pi-subagents/test/support/real-session-runner.ts +4 -20
  352. package/dist/extensions/pi-subagents/test/unit/acceptance.test.ts +25 -4
  353. package/dist/extensions/pi-subagents/test/unit/agent-disabled.test.ts +1 -1
  354. package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +280 -295
  355. package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +47 -207
  356. package/dist/extensions/pi-subagents/test/unit/agent-memory.test.ts +26 -26
  357. package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +89 -89
  358. package/dist/extensions/pi-subagents/test/unit/agent-selection.test.ts +9 -9
  359. package/dist/extensions/pi-subagents/test/unit/artifacts.test.ts +10 -0
  360. package/dist/extensions/pi-subagents/test/unit/async-execution.test.ts +33 -9
  361. package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +24 -2
  362. package/dist/extensions/pi-subagents/test/unit/async-permission-session.test.ts +11 -9
  363. package/dist/extensions/pi-subagents/test/unit/async-recovery-descriptor.test.ts +2 -2
  364. package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +40 -40
  365. package/dist/extensions/pi-subagents/test/unit/authority-policy.test.ts +22 -0
  366. package/dist/extensions/pi-subagents/test/unit/background-work.test.ts +1 -1
  367. package/dist/extensions/pi-subagents/test/unit/capability-ceiling-agent-allowlist.test.ts +5 -39
  368. package/dist/extensions/pi-subagents/test/unit/chain-append.test.ts +19 -19
  369. package/dist/extensions/pi-subagents/test/unit/chain-root-attachment.test.ts +9 -9
  370. package/dist/extensions/pi-subagents/test/unit/chain-serializer.test.ts +20 -20
  371. package/dist/extensions/pi-subagents/test/unit/child-protocol.test.ts +99 -0
  372. package/dist/extensions/pi-subagents/test/unit/child-transcript.test.ts +9 -9
  373. package/dist/extensions/pi-subagents/test/unit/compaction-resume.test.ts +41 -0
  374. package/dist/extensions/pi-subagents/test/unit/completion-dedupe.test.ts +2 -2
  375. package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +35 -5
  376. package/dist/extensions/pi-subagents/test/unit/config-dir-runtime.test.ts +7 -0
  377. package/dist/extensions/pi-subagents/test/unit/control-notices.test.ts +16 -82
  378. package/dist/extensions/pi-subagents/test/unit/delegation-api.test.ts +162 -620
  379. package/dist/extensions/pi-subagents/test/unit/doctor.test.ts +1 -1
  380. package/dist/extensions/pi-subagents/test/unit/dynamic-fanout.test.ts +25 -25
  381. package/dist/extensions/pi-subagents/test/unit/ensure-accessible-dir.test.ts +125 -0
  382. package/dist/extensions/pi-subagents/test/unit/external-cli-runner.test.ts +94 -0
  383. package/dist/extensions/pi-subagents/test/unit/external-runs.test.ts +66 -0
  384. package/dist/extensions/pi-subagents/test/unit/extra-agent-dirs.test.ts +3 -3
  385. package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +242 -52
  386. package/dist/extensions/pi-subagents/test/unit/fleet-transcript.test.ts +127 -0
  387. package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +197 -36
  388. package/dist/extensions/pi-subagents/test/unit/foreground-control.test.ts +4 -4
  389. package/dist/extensions/pi-subagents/test/unit/herdr-inspector.test.ts +245 -0
  390. package/dist/extensions/pi-subagents/test/unit/herdr-status-bridge.test.ts +494 -0
  391. package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +261 -31
  392. package/dist/extensions/pi-subagents/test/unit/inline-subagents.test.ts +52 -0
  393. package/dist/extensions/pi-subagents/test/unit/intercom-bridge.test.ts +6 -6
  394. package/dist/extensions/pi-subagents/test/unit/mission-lifecycle.test.ts +217 -0
  395. package/dist/extensions/pi-subagents/test/unit/mission-store.test.ts +182 -0
  396. package/dist/extensions/pi-subagents/test/unit/mock-pi.test.ts +22 -0
  397. package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +1 -1
  398. package/dist/extensions/pi-subagents/test/unit/native-supervisor-channel.test.ts +10 -10
  399. package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +20 -12
  400. package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +47 -5
  401. package/dist/extensions/pi-subagents/test/unit/notify.test.ts +49 -55
  402. package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +20 -3
  403. package/dist/extensions/pi-subagents/test/unit/parallel-handoff.test.ts +37 -7
  404. package/dist/extensions/pi-subagents/test/unit/parallel-utils.test.ts +10 -10
  405. package/dist/extensions/pi-subagents/test/unit/path-handling.test.ts +3 -3
  406. package/dist/extensions/pi-subagents/test/unit/permissions.test.ts +46 -0
  407. package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +31 -10
  408. package/dist/extensions/pi-subagents/test/unit/pi-spawn.test.ts +40 -16
  409. package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +42 -44
  410. package/dist/extensions/pi-subagents/test/unit/proactive-skills.test.ts +13 -13
  411. package/dist/extensions/pi-subagents/test/unit/process-terminal.test.ts +4 -4
  412. package/dist/extensions/pi-subagents/test/unit/profiles.test.ts +75 -9
  413. package/dist/extensions/pi-subagents/test/unit/prompt-template-bridge.test.ts +20 -84
  414. package/dist/extensions/pi-subagents/test/unit/prompt-workflows.test.ts +15 -16
  415. package/dist/extensions/pi-subagents/test/unit/render-helpers.test.ts +28 -28
  416. package/dist/extensions/pi-subagents/test/unit/result-intercom.test.ts +19 -12
  417. package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +37 -21
  418. package/dist/extensions/pi-subagents/test/unit/run-id-resolver.test.ts +1 -1
  419. package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +50 -50
  420. package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +396 -433
  421. package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +76 -153
  422. package/dist/extensions/pi-subagents/test/unit/scripted-workflow.test.ts +411 -0
  423. package/dist/extensions/pi-subagents/test/unit/single-output.test.ts +1 -91
  424. package/dist/extensions/pi-subagents/test/unit/skills-fallback.test.ts +139 -0
  425. package/dist/extensions/pi-subagents/test/unit/slash-bridge.test.ts +29 -0
  426. package/dist/extensions/pi-subagents/test/unit/stale-run-reconciler.test.ts +13 -13
  427. package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +2 -2
  428. package/dist/extensions/pi-subagents/test/unit/steering.test.ts +2 -2
  429. package/dist/extensions/pi-subagents/test/unit/subagent-control.test.ts +35 -35
  430. package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +53 -18
  431. package/dist/extensions/pi-subagents/test/unit/subagent-startup-retry.test.ts +13 -1
  432. package/dist/extensions/pi-subagents/test/unit/subagent-wait.test.ts +44 -11
  433. package/dist/extensions/pi-subagents/test/unit/task-intent.test.ts +2 -26
  434. package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +24 -148
  435. package/dist/extensions/pi-subagents/test/unit/turn-budget.test.ts +11 -9
  436. package/dist/extensions/pi-subagents/test/unit/wait-subscriptions.test.ts +351 -0
  437. package/dist/extensions/pi-subagents/test/unit/watchdog-child-status.test.ts +13 -13
  438. package/dist/extensions/pi-subagents/test/unit/watchdog-lsp-diagnostics.test.ts +1 -1
  439. package/dist/extensions/pi-subagents/test/unit/watchdog-permission-arbiter.test.ts +79 -0
  440. package/dist/extensions/pi-subagents/test/unit/watchdog-runtime.test.ts +1 -1
  441. package/dist/extensions/pi-subagents/test/unit/watchdog-settings.test.ts +8 -8
  442. package/dist/extensions/pi-subagents/test/unit/widget-nested-render.test.ts +45 -9
  443. package/dist/extensions/pi-subagents/test/unit/workflow-chat-progress.test.ts +197 -0
  444. package/dist/extensions/pi-subagents/test/unit/workflow-graph.test.ts +8 -8
  445. package/dist/extensions/pi-subagents/test/unit/worktree.test.ts +142 -12
  446. package/dist/extensions/pi-subagents/tsconfig.json +15 -0
  447. package/dist/extensions/pi-web-agent/package.json +1 -1
  448. package/dist/extensions/rtk.test.ts +126 -0
  449. package/dist/extensions/rtk.ts +56 -20
  450. package/dist/index.d.ts +1 -1
  451. package/dist/index.js +1 -1
  452. package/dist/main.d.ts +0 -1
  453. package/dist/main.js +0 -1
  454. package/dist/migrations.d.ts +0 -1
  455. package/dist/migrations.js +0 -1
  456. package/dist/modes/index.d.ts +0 -1
  457. package/dist/modes/index.js +0 -1
  458. package/dist/modes/interactive/components/armin.d.ts +0 -1
  459. package/dist/modes/interactive/components/armin.js +0 -1
  460. package/dist/modes/interactive/components/assistant-message.d.ts +0 -1
  461. package/dist/modes/interactive/components/assistant-message.js +0 -1
  462. package/dist/modes/interactive/components/bash-execution.d.ts +0 -1
  463. package/dist/modes/interactive/components/bash-execution.js +0 -1
  464. package/dist/modes/interactive/components/bordered-loader.d.ts +0 -1
  465. package/dist/modes/interactive/components/bordered-loader.js +0 -1
  466. package/dist/modes/interactive/components/branch-summary-message.d.ts +0 -1
  467. package/dist/modes/interactive/components/branch-summary-message.js +0 -1
  468. package/dist/modes/interactive/components/compaction-summary-message.d.ts +0 -1
  469. package/dist/modes/interactive/components/compaction-summary-message.js +0 -1
  470. package/dist/modes/interactive/components/config-selector.d.ts +0 -1
  471. package/dist/modes/interactive/components/config-selector.js +0 -1
  472. package/dist/modes/interactive/components/countdown-timer.d.ts +0 -1
  473. package/dist/modes/interactive/components/countdown-timer.js +0 -1
  474. package/dist/modes/interactive/components/custom-editor.d.ts +0 -1
  475. package/dist/modes/interactive/components/custom-editor.js +0 -1
  476. package/dist/modes/interactive/components/custom-entry.d.ts +0 -1
  477. package/dist/modes/interactive/components/custom-entry.js +0 -1
  478. package/dist/modes/interactive/components/custom-message.d.ts +0 -1
  479. package/dist/modes/interactive/components/custom-message.js +0 -1
  480. package/dist/modes/interactive/components/daxnuts.d.ts +0 -1
  481. package/dist/modes/interactive/components/daxnuts.js +0 -1
  482. package/dist/modes/interactive/components/diff.d.ts +0 -1
  483. package/dist/modes/interactive/components/diff.js +0 -1
  484. package/dist/modes/interactive/components/dynamic-border.d.ts +0 -1
  485. package/dist/modes/interactive/components/dynamic-border.js +0 -1
  486. package/dist/modes/interactive/components/earendil-announcement.d.ts +0 -1
  487. package/dist/modes/interactive/components/earendil-announcement.js +0 -1
  488. package/dist/modes/interactive/components/extension-editor.d.ts +0 -1
  489. package/dist/modes/interactive/components/extension-editor.js +0 -1
  490. package/dist/modes/interactive/components/extension-input.d.ts +0 -1
  491. package/dist/modes/interactive/components/extension-input.js +0 -1
  492. package/dist/modes/interactive/components/extension-selector.d.ts +0 -1
  493. package/dist/modes/interactive/components/extension-selector.js +0 -1
  494. package/dist/modes/interactive/components/first-time-setup.d.ts +0 -1
  495. package/dist/modes/interactive/components/first-time-setup.js +0 -1
  496. package/dist/modes/interactive/components/footer.d.ts +0 -1
  497. package/dist/modes/interactive/components/footer.js +0 -1
  498. package/dist/modes/interactive/components/index.d.ts +0 -1
  499. package/dist/modes/interactive/components/index.js +0 -1
  500. package/dist/modes/interactive/components/keybinding-hints.d.ts +0 -1
  501. package/dist/modes/interactive/components/keybinding-hints.js +0 -1
  502. package/dist/modes/interactive/components/login-dialog.d.ts +0 -1
  503. package/dist/modes/interactive/components/login-dialog.js +0 -1
  504. package/dist/modes/interactive/components/model-selector.d.ts +0 -1
  505. package/dist/modes/interactive/components/model-selector.js +0 -1
  506. package/dist/modes/interactive/components/oauth-selector.d.ts +0 -1
  507. package/dist/modes/interactive/components/oauth-selector.js +0 -1
  508. package/dist/modes/interactive/components/scoped-models-selector.d.ts +0 -1
  509. package/dist/modes/interactive/components/scoped-models-selector.js +0 -1
  510. package/dist/modes/interactive/components/session-selector-search.d.ts +0 -1
  511. package/dist/modes/interactive/components/session-selector-search.js +0 -1
  512. package/dist/modes/interactive/components/session-selector.d.ts +0 -1
  513. package/dist/modes/interactive/components/session-selector.js +0 -1
  514. package/dist/modes/interactive/components/settings-selector.d.ts +0 -3
  515. package/dist/modes/interactive/components/settings-selector.js +1 -14
  516. package/dist/modes/interactive/components/show-images-selector.d.ts +0 -1
  517. package/dist/modes/interactive/components/show-images-selector.js +0 -1
  518. package/dist/modes/interactive/components/skill-invocation-message.d.ts +0 -1
  519. package/dist/modes/interactive/components/skill-invocation-message.js +0 -1
  520. package/dist/modes/interactive/components/status-indicator.d.ts +0 -1
  521. package/dist/modes/interactive/components/status-indicator.js +0 -1
  522. package/dist/modes/interactive/components/theme-selector.d.ts +0 -1
  523. package/dist/modes/interactive/components/theme-selector.js +0 -1
  524. package/dist/modes/interactive/components/thinking-selector.d.ts +0 -1
  525. package/dist/modes/interactive/components/thinking-selector.js +0 -1
  526. package/dist/modes/interactive/components/tool-execution.d.ts +0 -1
  527. package/dist/modes/interactive/components/tool-execution.js +0 -1
  528. package/dist/modes/interactive/components/tree-selector.d.ts +0 -1
  529. package/dist/modes/interactive/components/tree-selector.js +0 -1
  530. package/dist/modes/interactive/components/trust-selector.d.ts +0 -1
  531. package/dist/modes/interactive/components/trust-selector.js +0 -1
  532. package/dist/modes/interactive/components/user-message-selector.d.ts +0 -1
  533. package/dist/modes/interactive/components/user-message-selector.js +0 -1
  534. package/dist/modes/interactive/components/user-message.d.ts +0 -1
  535. package/dist/modes/interactive/components/user-message.js +0 -1
  536. package/dist/modes/interactive/components/visual-truncate.d.ts +0 -1
  537. package/dist/modes/interactive/components/visual-truncate.js +0 -1
  538. package/dist/modes/interactive/external-editor.d.ts +0 -1
  539. package/dist/modes/interactive/external-editor.js +0 -1
  540. package/dist/modes/interactive/interactive-mode.d.ts +0 -2
  541. package/dist/modes/interactive/interactive-mode.js +1 -22
  542. package/dist/modes/interactive/model-search.d.ts +0 -1
  543. package/dist/modes/interactive/model-search.js +0 -1
  544. package/dist/modes/interactive/theme/theme-controller.d.ts +0 -1
  545. package/dist/modes/interactive/theme/theme-controller.js +0 -1
  546. package/dist/modes/interactive/theme/theme.d.ts +0 -1
  547. package/dist/modes/interactive/theme/theme.js +0 -1
  548. package/dist/modes/print-mode.d.ts +0 -1
  549. package/dist/modes/print-mode.js +0 -1
  550. package/dist/modes/rpc/jsonl.d.ts +0 -1
  551. package/dist/modes/rpc/jsonl.js +0 -1
  552. package/dist/modes/rpc/rpc-client.d.ts +1 -2
  553. package/dist/modes/rpc/rpc-client.js +1 -2
  554. package/dist/modes/rpc/rpc-mode.d.ts +0 -1
  555. package/dist/modes/rpc/rpc-mode.js +0 -9
  556. package/dist/modes/rpc/rpc-types.d.ts +0 -1
  557. package/dist/modes/rpc/rpc-types.js +0 -1
  558. package/dist/package-manager-cli.d.ts +0 -1
  559. package/dist/package-manager-cli.js +0 -1
  560. package/dist/rpc-entry.d.ts +0 -1
  561. package/dist/rpc-entry.js +0 -1
  562. package/dist/utils/ansi.d.ts +0 -1
  563. package/dist/utils/ansi.js +0 -1
  564. package/dist/utils/changelog.d.ts +0 -1
  565. package/dist/utils/changelog.js +0 -1
  566. package/dist/utils/child-process.d.ts +0 -1
  567. package/dist/utils/child-process.js +0 -1
  568. package/dist/utils/clipboard-image.d.ts +0 -1
  569. package/dist/utils/clipboard-image.js +0 -1
  570. package/dist/utils/clipboard-native.d.ts +0 -1
  571. package/dist/utils/clipboard-native.js +0 -1
  572. package/dist/utils/clipboard.d.ts +0 -1
  573. package/dist/utils/clipboard.js +0 -1
  574. package/dist/utils/deprecation.d.ts +0 -1
  575. package/dist/utils/deprecation.js +0 -1
  576. package/dist/utils/exif-orientation.d.ts +0 -1
  577. package/dist/utils/exif-orientation.js +0 -1
  578. package/dist/utils/frontmatter.d.ts +0 -1
  579. package/dist/utils/frontmatter.js +0 -1
  580. package/dist/utils/fs-watch.d.ts +0 -1
  581. package/dist/utils/fs-watch.js +0 -1
  582. package/dist/utils/git.d.ts +0 -1
  583. package/dist/utils/git.js +0 -1
  584. package/dist/utils/html.d.ts +0 -1
  585. package/dist/utils/html.js +0 -1
  586. package/dist/utils/image-convert.d.ts +0 -1
  587. package/dist/utils/image-convert.js +0 -1
  588. package/dist/utils/image-process.d.ts +0 -1
  589. package/dist/utils/image-process.js +0 -1
  590. package/dist/utils/image-resize-core.d.ts +0 -1
  591. package/dist/utils/image-resize-core.js +0 -1
  592. package/dist/utils/image-resize-worker.d.ts +0 -1
  593. package/dist/utils/image-resize-worker.js +0 -1
  594. package/dist/utils/image-resize.d.ts +0 -1
  595. package/dist/utils/image-resize.js +0 -1
  596. package/dist/utils/json.d.ts +0 -1
  597. package/dist/utils/json.js +0 -1
  598. package/dist/utils/mime.d.ts +0 -1
  599. package/dist/utils/mime.js +0 -1
  600. package/dist/utils/open-browser.d.ts +0 -1
  601. package/dist/utils/open-browser.js +0 -1
  602. package/dist/utils/paths.d.ts +0 -1
  603. package/dist/utils/paths.js +0 -1
  604. package/dist/utils/photon.d.ts +0 -1
  605. package/dist/utils/photon.js +0 -1
  606. package/dist/utils/pi-user-agent.d.ts +0 -1
  607. package/dist/utils/pi-user-agent.js +0 -1
  608. package/dist/utils/shell.d.ts +0 -1
  609. package/dist/utils/shell.js +0 -1
  610. package/dist/utils/sleep.d.ts +0 -1
  611. package/dist/utils/sleep.js +0 -1
  612. package/dist/utils/syntax-highlight.d.ts +0 -1
  613. package/dist/utils/syntax-highlight.js +0 -1
  614. package/dist/utils/thinking-tags.d.ts +0 -1
  615. package/dist/utils/thinking-tags.js +0 -1
  616. package/dist/utils/tools-manager.d.ts +3 -3
  617. package/dist/utils/tools-manager.js +125 -42
  618. package/dist/utils/version-check.d.ts +0 -1
  619. package/dist/utils/version-check.js +0 -1
  620. package/dist/utils/windows-self-update.d.ts +0 -1
  621. package/dist/utils/windows-self-update.js +0 -1
  622. package/docs/rpc.md +1 -2
  623. package/docs/settings.md +0 -1
  624. package/docs/skills.md +10 -18
  625. package/package.json +4 -3
  626. package/dist/bun/cli.d.ts.map +0 -1
  627. package/dist/bun/cli.js.map +0 -1
  628. package/dist/bun/register-bedrock.d.ts.map +0 -1
  629. package/dist/bun/register-bedrock.js.map +0 -1
  630. package/dist/bun/restore-sandbox-env.d.ts.map +0 -1
  631. package/dist/bun/restore-sandbox-env.js.map +0 -1
  632. package/dist/cli/args.d.ts.map +0 -1
  633. package/dist/cli/args.js.map +0 -1
  634. package/dist/cli/config-selector.d.ts.map +0 -1
  635. package/dist/cli/config-selector.js.map +0 -1
  636. package/dist/cli/credential-print.d.ts.map +0 -1
  637. package/dist/cli/credential-print.js.map +0 -1
  638. package/dist/cli/file-processor.d.ts.map +0 -1
  639. package/dist/cli/file-processor.js.map +0 -1
  640. package/dist/cli/initial-message.d.ts.map +0 -1
  641. package/dist/cli/initial-message.js.map +0 -1
  642. package/dist/cli/list-models.d.ts.map +0 -1
  643. package/dist/cli/list-models.js.map +0 -1
  644. package/dist/cli/project-trust.d.ts.map +0 -1
  645. package/dist/cli/project-trust.js.map +0 -1
  646. package/dist/cli/session-picker.d.ts.map +0 -1
  647. package/dist/cli/session-picker.js.map +0 -1
  648. package/dist/cli/startup-ui.d.ts.map +0 -1
  649. package/dist/cli/startup-ui.js.map +0 -1
  650. package/dist/cli.d.ts.map +0 -1
  651. package/dist/cli.js.map +0 -1
  652. package/dist/config.d.ts.map +0 -1
  653. package/dist/config.js.map +0 -1
  654. package/dist/core/agent-session-auto-handoff.test.d.ts.map +0 -1
  655. package/dist/core/agent-session-auto-handoff.test.js.map +0 -1
  656. package/dist/core/agent-session-runtime.d.ts.map +0 -1
  657. package/dist/core/agent-session-runtime.js.map +0 -1
  658. package/dist/core/agent-session-services.d.ts.map +0 -1
  659. package/dist/core/agent-session-services.js.map +0 -1
  660. package/dist/core/agent-session-skill-block.test.d.ts.map +0 -1
  661. package/dist/core/agent-session-skill-block.test.js.map +0 -1
  662. package/dist/core/agent-session.d.ts.map +0 -1
  663. package/dist/core/agent-session.js.map +0 -1
  664. package/dist/core/agents.d.ts.map +0 -1
  665. package/dist/core/agents.js.map +0 -1
  666. package/dist/core/auth-guidance.d.ts.map +0 -1
  667. package/dist/core/auth-guidance.js.map +0 -1
  668. package/dist/core/auth-storage.d.ts.map +0 -1
  669. package/dist/core/auth-storage.js.map +0 -1
  670. package/dist/core/bash-executor.d.ts.map +0 -1
  671. package/dist/core/bash-executor.js.map +0 -1
  672. package/dist/core/built-in-extensions.d.ts.map +0 -1
  673. package/dist/core/built-in-extensions.js.map +0 -1
  674. package/dist/core/cache-stats.d.ts.map +0 -1
  675. package/dist/core/cache-stats.js.map +0 -1
  676. package/dist/core/compaction/branch-summarization.d.ts.map +0 -1
  677. package/dist/core/compaction/branch-summarization.js.map +0 -1
  678. package/dist/core/compaction/compaction.d.ts.map +0 -1
  679. package/dist/core/compaction/compaction.js.map +0 -1
  680. package/dist/core/compaction/index.d.ts.map +0 -1
  681. package/dist/core/compaction/index.js.map +0 -1
  682. package/dist/core/compaction/utils.d.ts.map +0 -1
  683. package/dist/core/compaction/utils.js.map +0 -1
  684. package/dist/core/defaults.d.ts.map +0 -1
  685. package/dist/core/defaults.js.map +0 -1
  686. package/dist/core/diagnostics.d.ts.map +0 -1
  687. package/dist/core/diagnostics.js.map +0 -1
  688. package/dist/core/event-bus.d.ts.map +0 -1
  689. package/dist/core/event-bus.js.map +0 -1
  690. package/dist/core/exec.d.ts.map +0 -1
  691. package/dist/core/exec.js.map +0 -1
  692. package/dist/core/experimental.d.ts.map +0 -1
  693. package/dist/core/experimental.js.map +0 -1
  694. package/dist/core/export-html/ansi-to-html.d.ts.map +0 -1
  695. package/dist/core/export-html/ansi-to-html.js.map +0 -1
  696. package/dist/core/export-html/index.d.ts.map +0 -1
  697. package/dist/core/export-html/index.js.map +0 -1
  698. package/dist/core/export-html/tool-renderer.d.ts.map +0 -1
  699. package/dist/core/export-html/tool-renderer.js.map +0 -1
  700. package/dist/core/extensions/index.d.ts.map +0 -1
  701. package/dist/core/extensions/index.js.map +0 -1
  702. package/dist/core/extensions/loader.d.ts.map +0 -1
  703. package/dist/core/extensions/loader.js.map +0 -1
  704. package/dist/core/extensions/runner.d.ts.map +0 -1
  705. package/dist/core/extensions/runner.js.map +0 -1
  706. package/dist/core/extensions/types.d.ts.map +0 -1
  707. package/dist/core/extensions/types.js.map +0 -1
  708. package/dist/core/extensions/wrapper.d.ts.map +0 -1
  709. package/dist/core/extensions/wrapper.js.map +0 -1
  710. package/dist/core/footer-data-provider.d.ts.map +0 -1
  711. package/dist/core/footer-data-provider.js.map +0 -1
  712. package/dist/core/git-command.d.ts.map +0 -1
  713. package/dist/core/git-command.js.map +0 -1
  714. package/dist/core/http-dispatcher.d.ts.map +0 -1
  715. package/dist/core/http-dispatcher.js.map +0 -1
  716. package/dist/core/index.d.ts.map +0 -1
  717. package/dist/core/index.js.map +0 -1
  718. package/dist/core/keybindings.d.ts.map +0 -1
  719. package/dist/core/keybindings.js.map +0 -1
  720. package/dist/core/llama/client.d.ts.map +0 -1
  721. package/dist/core/llama/client.js.map +0 -1
  722. package/dist/core/llama/huggingface.d.ts.map +0 -1
  723. package/dist/core/llama/huggingface.js.map +0 -1
  724. package/dist/core/llama/index.d.ts.map +0 -1
  725. package/dist/core/llama/index.js.map +0 -1
  726. package/dist/core/llama/provider.d.ts.map +0 -1
  727. package/dist/core/llama/provider.js.map +0 -1
  728. package/dist/core/llama/ui.d.ts.map +0 -1
  729. package/dist/core/llama/ui.js.map +0 -1
  730. package/dist/core/messages.d.ts.map +0 -1
  731. package/dist/core/messages.js.map +0 -1
  732. package/dist/core/model-config.d.ts.map +0 -1
  733. package/dist/core/model-config.js.map +0 -1
  734. package/dist/core/model-registry.d.ts.map +0 -1
  735. package/dist/core/model-registry.js.map +0 -1
  736. package/dist/core/model-resolver.d.ts.map +0 -1
  737. package/dist/core/model-resolver.js.map +0 -1
  738. package/dist/core/model-runtime.d.ts.map +0 -1
  739. package/dist/core/model-runtime.js.map +0 -1
  740. package/dist/core/models-store.d.ts.map +0 -1
  741. package/dist/core/models-store.js.map +0 -1
  742. package/dist/core/output-guard.d.ts.map +0 -1
  743. package/dist/core/output-guard.js.map +0 -1
  744. package/dist/core/package-manager.d.ts.map +0 -1
  745. package/dist/core/package-manager.js.map +0 -1
  746. package/dist/core/package-manager.test.d.ts.map +0 -1
  747. package/dist/core/package-manager.test.js.map +0 -1
  748. package/dist/core/project-trust.d.ts.map +0 -1
  749. package/dist/core/project-trust.js.map +0 -1
  750. package/dist/core/prompt-templates.d.ts.map +0 -1
  751. package/dist/core/prompt-templates.js.map +0 -1
  752. package/dist/core/provider-attribution.d.ts.map +0 -1
  753. package/dist/core/provider-attribution.js.map +0 -1
  754. package/dist/core/provider-composer.d.ts.map +0 -1
  755. package/dist/core/provider-composer.js.map +0 -1
  756. package/dist/core/radius.d.ts.map +0 -1
  757. package/dist/core/radius.js.map +0 -1
  758. package/dist/core/remote-catalog-provider.d.ts.map +0 -1
  759. package/dist/core/remote-catalog-provider.js.map +0 -1
  760. package/dist/core/resolve-config-value.d.ts.map +0 -1
  761. package/dist/core/resolve-config-value.js.map +0 -1
  762. package/dist/core/resource-loader.d.ts.map +0 -1
  763. package/dist/core/resource-loader.js.map +0 -1
  764. package/dist/core/runtime-credentials.d.ts.map +0 -1
  765. package/dist/core/runtime-credentials.js.map +0 -1
  766. package/dist/core/sdk.d.ts.map +0 -1
  767. package/dist/core/sdk.js.map +0 -1
  768. package/dist/core/session-cwd.d.ts.map +0 -1
  769. package/dist/core/session-cwd.js.map +0 -1
  770. package/dist/core/session-manager.d.ts.map +0 -1
  771. package/dist/core/session-manager.js.map +0 -1
  772. package/dist/core/settings-manager-auto-handoff.test.d.ts.map +0 -1
  773. package/dist/core/settings-manager-auto-handoff.test.js.map +0 -1
  774. package/dist/core/settings-manager.d.ts.map +0 -1
  775. package/dist/core/settings-manager.js.map +0 -1
  776. package/dist/core/skills.d.ts.map +0 -1
  777. package/dist/core/skills.js.map +0 -1
  778. package/dist/core/slash-commands.d.ts.map +0 -1
  779. package/dist/core/slash-commands.js.map +0 -1
  780. package/dist/core/source-info.d.ts.map +0 -1
  781. package/dist/core/source-info.js.map +0 -1
  782. package/dist/core/system-prompt.d.ts.map +0 -1
  783. package/dist/core/system-prompt.js.map +0 -1
  784. package/dist/core/system-prompt.test.d.ts.map +0 -1
  785. package/dist/core/system-prompt.test.js.map +0 -1
  786. package/dist/core/telemetry.d.ts.map +0 -1
  787. package/dist/core/telemetry.js.map +0 -1
  788. package/dist/core/timings.d.ts.map +0 -1
  789. package/dist/core/timings.js.map +0 -1
  790. package/dist/core/tools/bash.d.ts.map +0 -1
  791. package/dist/core/tools/bash.js.map +0 -1
  792. package/dist/core/tools/edit-diff.d.ts.map +0 -1
  793. package/dist/core/tools/edit-diff.js.map +0 -1
  794. package/dist/core/tools/edit.d.ts.map +0 -1
  795. package/dist/core/tools/edit.js.map +0 -1
  796. package/dist/core/tools/file-mutation-queue.d.ts.map +0 -1
  797. package/dist/core/tools/file-mutation-queue.js.map +0 -1
  798. package/dist/core/tools/find.d.ts.map +0 -1
  799. package/dist/core/tools/find.js.map +0 -1
  800. package/dist/core/tools/grep.d.ts.map +0 -1
  801. package/dist/core/tools/grep.js.map +0 -1
  802. package/dist/core/tools/index.d.ts.map +0 -1
  803. package/dist/core/tools/index.js.map +0 -1
  804. package/dist/core/tools/ls.d.ts.map +0 -1
  805. package/dist/core/tools/ls.js.map +0 -1
  806. package/dist/core/tools/output-accumulator.d.ts.map +0 -1
  807. package/dist/core/tools/output-accumulator.js.map +0 -1
  808. package/dist/core/tools/path-utils.d.ts.map +0 -1
  809. package/dist/core/tools/path-utils.js.map +0 -1
  810. package/dist/core/tools/read.d.ts.map +0 -1
  811. package/dist/core/tools/read.js.map +0 -1
  812. package/dist/core/tools/render-utils.d.ts.map +0 -1
  813. package/dist/core/tools/render-utils.js.map +0 -1
  814. package/dist/core/tools/tool-definition-wrapper.d.ts.map +0 -1
  815. package/dist/core/tools/tool-definition-wrapper.js.map +0 -1
  816. package/dist/core/tools/truncate.d.ts.map +0 -1
  817. package/dist/core/tools/truncate.js.map +0 -1
  818. package/dist/core/tools/write.d.ts.map +0 -1
  819. package/dist/core/tools/write.js.map +0 -1
  820. package/dist/core/trust-manager.d.ts.map +0 -1
  821. package/dist/core/trust-manager.js.map +0 -1
  822. package/dist/core/usage-totals.d.ts.map +0 -1
  823. package/dist/core/usage-totals.js.map +0 -1
  824. package/dist/extensions/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
  825. package/dist/extensions/pi-subagents/test/unit/slash-chain-groups.test.ts +0 -464
  826. package/dist/index.d.ts.map +0 -1
  827. package/dist/index.js.map +0 -1
  828. package/dist/main.d.ts.map +0 -1
  829. package/dist/main.js.map +0 -1
  830. package/dist/migrations.d.ts.map +0 -1
  831. package/dist/migrations.js.map +0 -1
  832. package/dist/modes/index.d.ts.map +0 -1
  833. package/dist/modes/index.js.map +0 -1
  834. package/dist/modes/interactive/components/armin.d.ts.map +0 -1
  835. package/dist/modes/interactive/components/armin.js.map +0 -1
  836. package/dist/modes/interactive/components/assistant-message.d.ts.map +0 -1
  837. package/dist/modes/interactive/components/assistant-message.js.map +0 -1
  838. package/dist/modes/interactive/components/bash-execution.d.ts.map +0 -1
  839. package/dist/modes/interactive/components/bash-execution.js.map +0 -1
  840. package/dist/modes/interactive/components/bordered-loader.d.ts.map +0 -1
  841. package/dist/modes/interactive/components/bordered-loader.js.map +0 -1
  842. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +0 -1
  843. package/dist/modes/interactive/components/branch-summary-message.js.map +0 -1
  844. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +0 -1
  845. package/dist/modes/interactive/components/compaction-summary-message.js.map +0 -1
  846. package/dist/modes/interactive/components/config-selector.d.ts.map +0 -1
  847. package/dist/modes/interactive/components/config-selector.js.map +0 -1
  848. package/dist/modes/interactive/components/countdown-timer.d.ts.map +0 -1
  849. package/dist/modes/interactive/components/countdown-timer.js.map +0 -1
  850. package/dist/modes/interactive/components/custom-editor.d.ts.map +0 -1
  851. package/dist/modes/interactive/components/custom-editor.js.map +0 -1
  852. package/dist/modes/interactive/components/custom-entry.d.ts.map +0 -1
  853. package/dist/modes/interactive/components/custom-entry.js.map +0 -1
  854. package/dist/modes/interactive/components/custom-message.d.ts.map +0 -1
  855. package/dist/modes/interactive/components/custom-message.js.map +0 -1
  856. package/dist/modes/interactive/components/daxnuts.d.ts.map +0 -1
  857. package/dist/modes/interactive/components/daxnuts.js.map +0 -1
  858. package/dist/modes/interactive/components/diff.d.ts.map +0 -1
  859. package/dist/modes/interactive/components/diff.js.map +0 -1
  860. package/dist/modes/interactive/components/dynamic-border.d.ts.map +0 -1
  861. package/dist/modes/interactive/components/dynamic-border.js.map +0 -1
  862. package/dist/modes/interactive/components/earendil-announcement.d.ts.map +0 -1
  863. package/dist/modes/interactive/components/earendil-announcement.js.map +0 -1
  864. package/dist/modes/interactive/components/extension-editor.d.ts.map +0 -1
  865. package/dist/modes/interactive/components/extension-editor.js.map +0 -1
  866. package/dist/modes/interactive/components/extension-input.d.ts.map +0 -1
  867. package/dist/modes/interactive/components/extension-input.js.map +0 -1
  868. package/dist/modes/interactive/components/extension-selector.d.ts.map +0 -1
  869. package/dist/modes/interactive/components/extension-selector.js.map +0 -1
  870. package/dist/modes/interactive/components/first-time-setup.d.ts.map +0 -1
  871. package/dist/modes/interactive/components/first-time-setup.js.map +0 -1
  872. package/dist/modes/interactive/components/footer.d.ts.map +0 -1
  873. package/dist/modes/interactive/components/footer.js.map +0 -1
  874. package/dist/modes/interactive/components/index.d.ts.map +0 -1
  875. package/dist/modes/interactive/components/index.js.map +0 -1
  876. package/dist/modes/interactive/components/keybinding-hints.d.ts.map +0 -1
  877. package/dist/modes/interactive/components/keybinding-hints.js.map +0 -1
  878. package/dist/modes/interactive/components/login-dialog.d.ts.map +0 -1
  879. package/dist/modes/interactive/components/login-dialog.js.map +0 -1
  880. package/dist/modes/interactive/components/model-selector.d.ts.map +0 -1
  881. package/dist/modes/interactive/components/model-selector.js.map +0 -1
  882. package/dist/modes/interactive/components/oauth-selector.d.ts.map +0 -1
  883. package/dist/modes/interactive/components/oauth-selector.js.map +0 -1
  884. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +0 -1
  885. package/dist/modes/interactive/components/scoped-models-selector.js.map +0 -1
  886. package/dist/modes/interactive/components/session-selector-search.d.ts.map +0 -1
  887. package/dist/modes/interactive/components/session-selector-search.js.map +0 -1
  888. package/dist/modes/interactive/components/session-selector.d.ts.map +0 -1
  889. package/dist/modes/interactive/components/session-selector.js.map +0 -1
  890. package/dist/modes/interactive/components/settings-selector.d.ts.map +0 -1
  891. package/dist/modes/interactive/components/settings-selector.js.map +0 -1
  892. package/dist/modes/interactive/components/show-images-selector.d.ts.map +0 -1
  893. package/dist/modes/interactive/components/show-images-selector.js.map +0 -1
  894. package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +0 -1
  895. package/dist/modes/interactive/components/skill-invocation-message.js.map +0 -1
  896. package/dist/modes/interactive/components/status-indicator.d.ts.map +0 -1
  897. package/dist/modes/interactive/components/status-indicator.js.map +0 -1
  898. package/dist/modes/interactive/components/theme-selector.d.ts.map +0 -1
  899. package/dist/modes/interactive/components/theme-selector.js.map +0 -1
  900. package/dist/modes/interactive/components/thinking-selector.d.ts.map +0 -1
  901. package/dist/modes/interactive/components/thinking-selector.js.map +0 -1
  902. package/dist/modes/interactive/components/tool-execution.d.ts.map +0 -1
  903. package/dist/modes/interactive/components/tool-execution.js.map +0 -1
  904. package/dist/modes/interactive/components/tree-selector.d.ts.map +0 -1
  905. package/dist/modes/interactive/components/tree-selector.js.map +0 -1
  906. package/dist/modes/interactive/components/trust-selector.d.ts.map +0 -1
  907. package/dist/modes/interactive/components/trust-selector.js.map +0 -1
  908. package/dist/modes/interactive/components/user-message-selector.d.ts.map +0 -1
  909. package/dist/modes/interactive/components/user-message-selector.js.map +0 -1
  910. package/dist/modes/interactive/components/user-message.d.ts.map +0 -1
  911. package/dist/modes/interactive/components/user-message.js.map +0 -1
  912. package/dist/modes/interactive/components/visual-truncate.d.ts.map +0 -1
  913. package/dist/modes/interactive/components/visual-truncate.js.map +0 -1
  914. package/dist/modes/interactive/external-editor.d.ts.map +0 -1
  915. package/dist/modes/interactive/external-editor.js.map +0 -1
  916. package/dist/modes/interactive/interactive-mode.d.ts.map +0 -1
  917. package/dist/modes/interactive/interactive-mode.js.map +0 -1
  918. package/dist/modes/interactive/model-search.d.ts.map +0 -1
  919. package/dist/modes/interactive/model-search.js.map +0 -1
  920. package/dist/modes/interactive/theme/theme-controller.d.ts.map +0 -1
  921. package/dist/modes/interactive/theme/theme-controller.js.map +0 -1
  922. package/dist/modes/interactive/theme/theme.d.ts.map +0 -1
  923. package/dist/modes/interactive/theme/theme.js.map +0 -1
  924. package/dist/modes/print-mode.d.ts.map +0 -1
  925. package/dist/modes/print-mode.js.map +0 -1
  926. package/dist/modes/rpc/jsonl.d.ts.map +0 -1
  927. package/dist/modes/rpc/jsonl.js.map +0 -1
  928. package/dist/modes/rpc/rpc-client.d.ts.map +0 -1
  929. package/dist/modes/rpc/rpc-client.js.map +0 -1
  930. package/dist/modes/rpc/rpc-mode.d.ts.map +0 -1
  931. package/dist/modes/rpc/rpc-mode.js.map +0 -1
  932. package/dist/modes/rpc/rpc-types.d.ts.map +0 -1
  933. package/dist/modes/rpc/rpc-types.js.map +0 -1
  934. package/dist/package-manager-cli.d.ts.map +0 -1
  935. package/dist/package-manager-cli.js.map +0 -1
  936. package/dist/rpc-entry.d.ts.map +0 -1
  937. package/dist/rpc-entry.js.map +0 -1
  938. package/dist/utils/ansi.d.ts.map +0 -1
  939. package/dist/utils/ansi.js.map +0 -1
  940. package/dist/utils/changelog.d.ts.map +0 -1
  941. package/dist/utils/changelog.js.map +0 -1
  942. package/dist/utils/child-process.d.ts.map +0 -1
  943. package/dist/utils/child-process.js.map +0 -1
  944. package/dist/utils/clipboard-image.d.ts.map +0 -1
  945. package/dist/utils/clipboard-image.js.map +0 -1
  946. package/dist/utils/clipboard-native.d.ts.map +0 -1
  947. package/dist/utils/clipboard-native.js.map +0 -1
  948. package/dist/utils/clipboard.d.ts.map +0 -1
  949. package/dist/utils/clipboard.js.map +0 -1
  950. package/dist/utils/deprecation.d.ts.map +0 -1
  951. package/dist/utils/deprecation.js.map +0 -1
  952. package/dist/utils/exif-orientation.d.ts.map +0 -1
  953. package/dist/utils/exif-orientation.js.map +0 -1
  954. package/dist/utils/frontmatter.d.ts.map +0 -1
  955. package/dist/utils/frontmatter.js.map +0 -1
  956. package/dist/utils/fs-watch.d.ts.map +0 -1
  957. package/dist/utils/fs-watch.js.map +0 -1
  958. package/dist/utils/git.d.ts.map +0 -1
  959. package/dist/utils/git.js.map +0 -1
  960. package/dist/utils/html.d.ts.map +0 -1
  961. package/dist/utils/html.js.map +0 -1
  962. package/dist/utils/image-convert.d.ts.map +0 -1
  963. package/dist/utils/image-convert.js.map +0 -1
  964. package/dist/utils/image-process.d.ts.map +0 -1
  965. package/dist/utils/image-process.js.map +0 -1
  966. package/dist/utils/image-resize-core.d.ts.map +0 -1
  967. package/dist/utils/image-resize-core.js.map +0 -1
  968. package/dist/utils/image-resize-worker.d.ts.map +0 -1
  969. package/dist/utils/image-resize-worker.js.map +0 -1
  970. package/dist/utils/image-resize.d.ts.map +0 -1
  971. package/dist/utils/image-resize.js.map +0 -1
  972. package/dist/utils/json.d.ts.map +0 -1
  973. package/dist/utils/json.js.map +0 -1
  974. package/dist/utils/mime.d.ts.map +0 -1
  975. package/dist/utils/mime.js.map +0 -1
  976. package/dist/utils/open-browser.d.ts.map +0 -1
  977. package/dist/utils/open-browser.js.map +0 -1
  978. package/dist/utils/paths.d.ts.map +0 -1
  979. package/dist/utils/paths.js.map +0 -1
  980. package/dist/utils/photon.d.ts.map +0 -1
  981. package/dist/utils/photon.js.map +0 -1
  982. package/dist/utils/pi-user-agent.d.ts.map +0 -1
  983. package/dist/utils/pi-user-agent.js.map +0 -1
  984. package/dist/utils/shell.d.ts.map +0 -1
  985. package/dist/utils/shell.js.map +0 -1
  986. package/dist/utils/sleep.d.ts.map +0 -1
  987. package/dist/utils/sleep.js.map +0 -1
  988. package/dist/utils/syntax-highlight.d.ts.map +0 -1
  989. package/dist/utils/syntax-highlight.js.map +0 -1
  990. package/dist/utils/thinking-tags.d.ts.map +0 -1
  991. package/dist/utils/thinking-tags.js.map +0 -1
  992. package/dist/utils/tools-manager.d.ts.map +0 -1
  993. package/dist/utils/tools-manager.js.map +0 -1
  994. package/dist/utils/version-check.d.ts.map +0 -1
  995. package/dist/utils/version-check.js.map +0 -1
  996. package/dist/utils/windows-self-update.d.ts.map +0 -1
  997. package/dist/utils/windows-self-update.js.map +0 -1
@@ -364,7 +364,7 @@ describe("subagents watchdog slash command", { skip: !available ? "watchdog comm
364
364
  fs.writeFileSync(settingsPath, JSON.stringify({
365
365
  other: true,
366
366
  subagents: {
367
- agentOverrides: { scout: { model: "openai/test" } },
367
+ agentOverrides: { explorer: { model: "openai/test" } },
368
368
  watchdog: { agentEndTimeoutMs: 1234, main: { enabled: false, model: "openai/watchdog" } },
369
369
  },
370
370
  }, null, 2), "utf-8");
@@ -375,7 +375,7 @@ describe("subagents watchdog slash command", { skip: !available ? "watchdog comm
375
375
  await commands.get("subagents-watchdog")!.handler("on", createCommandContext({ cwd: root }));
376
376
  let settings = JSON.parse(fs.readFileSync(settingsPath, "utf-8"));
377
377
  assert.equal(settings.other, true);
378
- assert.equal(settings.subagents.agentOverrides.scout.model, "openai/test");
378
+ assert.equal(settings.subagents.agentOverrides.explorer.model, "openai/test");
379
379
  assert.equal(settings.subagents.watchdog.agentEndTimeoutMs, 1234);
380
380
  assert.equal(settings.subagents.watchdog.enabled, true);
381
381
  assert.equal(settings.subagents.watchdog.main.enabled, true);
@@ -678,1685 +678,44 @@ describe("slash command custom message delivery", { skip: !available ? "slash-co
678
678
  assert.equal((visibleSnapshot.result.content[0] as { text?: string }).text, "Subagent failed");
679
679
  });
680
680
 
681
- it("/parallel forwards inline output behavior config", async () => {
682
- const commands = new Map<string, { handler(args: string, ctx: unknown): Promise<void> }>();
683
- const events = createEventBus();
684
- let requestedParams: unknown;
685
- events.on(SLASH_SUBAGENT_REQUEST_EVENT, (data) => {
686
- const payload = data as { requestId: string; params?: unknown };
687
- requestedParams = payload.params;
688
- events.emit(SLASH_SUBAGENT_STARTED_EVENT, { requestId: payload.requestId });
689
- events.emit(SLASH_SUBAGENT_RESPONSE_EVENT, {
690
- requestId: payload.requestId,
691
- result: {
692
- content: [{ type: "text", text: "parallel finished" }],
693
- details: { mode: "parallel", results: [] },
694
- },
695
- isError: false,
696
- });
697
- });
698
-
699
- const pi = {
700
- events,
701
- registerCommand(name: string, spec: { handler(args: string, ctx: unknown): Promise<void> }) {
702
- commands.set(name, spec);
703
- },
704
- registerShortcut() {},
705
- sendMessage(_message: unknown) {},
706
- };
707
-
708
- registerSlashCommands!(pi, createState(process.cwd()));
709
- await commands.get("parallel")!.handler("explorer[output=x.md,outputMode=file-only,reads=a.md+b.md,progress] -- Review", createCommandContext());
710
-
711
- assert.deepEqual(requestedParams, {
712
- tasks: [{ agent: "explorer", task: "Review", output: "x.md", outputMode: "file-only", reads: ["a.md", "b.md"], progress: true }],
713
- clarify: false,
714
- agentScope: "both",
715
- });
716
- });
717
-
718
- it("/parallel no longer hard-blocks runs above the old 8-task limit before the executor responds", async () => {
719
- const sent: unknown[] = [];
720
- const commands = new Map<string, { handler(args: string, ctx: unknown): Promise<void> }>();
721
- const events = createEventBus();
722
- let requestedTasks = 0;
723
- events.on(SLASH_SUBAGENT_REQUEST_EVENT, (data) => {
724
- const payload = data as { requestId: string; params?: { tasks?: unknown[] } };
725
- requestedTasks = payload.params?.tasks?.length ?? 0;
726
- events.emit(SLASH_SUBAGENT_STARTED_EVENT, { requestId: payload.requestId });
727
- events.emit(SLASH_SUBAGENT_RESPONSE_EVENT, {
728
- requestId: payload.requestId,
729
- result: {
730
- content: [{ type: "text", text: "parallel finished" }],
731
- details: { mode: "parallel", results: [] },
732
- },
733
- isError: false,
734
- });
735
- });
736
-
737
- const pi = {
738
- events,
739
- registerCommand(name: string, spec: { handler(args: string, ctx: unknown): Promise<void> }) {
740
- commands.set(name, spec);
741
- },
742
- registerShortcut() {},
743
- sendMessage(message: unknown) {
744
- sent.push(message);
745
- },
746
- };
747
-
748
- registerSlashCommands!(pi, createState(process.cwd()));
749
- const args = Array.from({ length: 9 }, (_, index) => `explorer \"task ${index + 1}\"`).join(" -> ");
750
- await commands.get("parallel")!.handler(args, createCommandContext());
751
- await new Promise<void>((resolve) => setImmediate(resolve));
752
-
753
- assert.equal(requestedTasks, 9);
754
- assert.equal(sent.length, 2);
755
- assert.match((sent[1] as { content?: string }).content ?? "", /parallel finished/);
756
- });
757
- });
758
-
759
- describe("saved chain slash command", { skip: !available ? "slash-commands.ts not importable" : undefined }, () => {
760
- beforeEach(() => {
761
- clearSlashSnapshots?.();
762
- });
763
-
764
- it("/run and /chain accept dotted packaged runtime agent names", async () => {
681
+ it("/run accepts dotted packaged runtime agent names", async () => {
765
682
  await withTempProject("pi-packaged-agent-slash-", async (root) => {
766
- fs.writeFileSync(path.join(root, ".selesai", "agents", "code-analysis.scout.md"), `---
767
- name: scout
683
+ fs.writeFileSync(path.join(root, ".selesai", "agents", "code-analysis.explorer.md"), `---
684
+ name: explorer
768
685
  package: code-analysis
769
686
  description: Fast recon
770
687
  ---
771
688
 
772
689
  Inspect
773
690
  `, "utf-8");
774
- fs.writeFileSync(path.join(root, ".selesai", "agents", "documentation.writer.md"), `---
775
- name: writer
776
- package: documentation
777
- description: Writer
778
- ---
779
-
780
- Write
781
- `, "utf-8");
782
-
783
- const run = await captureSlashCommandParams("run", "code-analysis.scout Investigate", root);
784
- assert.deepEqual(run.params, { agent: "code-analysis.scout", task: "Investigate", clarify: false, agentScope: "both" });
785
-
786
- const chain = await captureSlashCommandParams("chain", "code-analysis.scout \"Scan\" -> documentation.writer", root);
787
- assert.deepEqual((chain.params as { chain?: Array<{ agent?: string; task?: string }> }).chain?.map(({ agent, task }) => ({ agent, task })), [
788
- { agent: "code-analysis.scout", task: "Scan" },
789
- { agent: "documentation.writer", task: undefined },
790
- ]);
791
-
792
- await withIsolatedHome(async () => {
793
- const commands = new Map<string, RegisteredSlashCommand>();
794
- const pi = {
795
- events: createEventBus(),
796
- registerCommand(name: string, spec: RegisteredSlashCommand) { commands.set(name, spec); },
797
- registerShortcut() {},
798
- sendMessage(_message: unknown) {},
799
- };
800
- registerSlashCommands!(pi, createState(root));
801
- const runCompletions = commands.get("run")!.getArgumentCompletions!("code-") as Array<{ value: string; label: string }>;
802
- assert.deepEqual(runCompletions.map((completion) => completion.value), ["code-analysis.scout"]);
803
- const chainCompletions = commands.get("chain")!.getArgumentCompletions!("code-analysis.scout \"Scan\" -> doc") as Array<{ value: string; label: string }>;
804
- assert.deepEqual(chainCompletions.map((completion) => completion.value), ["code-analysis.scout \"Scan\" -> documentation.writer"]);
805
- // Regression: bare group-ish syntax inside a `--` shared task is plain text, not
806
- // a group separator, so it must not resume agent completion past the task.
807
- const pipeInTask = commands.get("chain")!.getArgumentCompletions!("code-analysis.scout -- do x | doc");
808
- assert.equal(pipeInTask, null);
809
- const openParenInTask = commands.get("chain")!.getArgumentCompletions!("code-analysis.scout -- do (doc");
810
- assert.equal(openParenInTask, null);
811
- const closeParenInTask = commands.get("chain")!.getArgumentCompletions!("code-analysis.scout -- do ) doc");
812
- assert.equal(closeParenInTask, null);
813
- const balancedParenInTask = commands.get("chain")!.getArgumentCompletions!("code-analysis.scout -- do (x) doc");
814
- assert.equal(balancedParenInTask, null);
815
- // Inside an actual parallel group, `|` still separates tasks and completes agents.
816
- const groupCompletions = commands.get("chain")!.getArgumentCompletions!("code-analysis.scout \"Scan\" -> (documentation.writer \"w\" | code") as Array<{ value: string; label: string }>;
817
- assert.deepEqual(groupCompletions.map((completion) => completion.value), ["code-analysis.scout \"Scan\" -> (documentation.writer \"w\" | code-analysis.scout"]);
818
- });
819
- });
820
- });
821
-
822
- it("/run-chain launches a saved chain with a shared task", async () => {
823
- await withTempProject("pi-run-chain-success-", async (root) => {
824
- writeProjectChain(root, "review-flow.chain.md", `---
825
- name: review-flow
826
- description: Review flow
827
- ---
828
-
829
- ## scout
830
-
831
- Scan {task}
832
-
833
- ## reviewer
834
-
835
- Review {previous}
836
- `);
837
-
838
- const { params } = await captureSlashCommandParams("run-chain", "review-flow -- Audit the auth flow", root);
839
- const runParams = params as {
840
- chain?: Array<{ agent?: string; task?: string }>;
841
- task?: string;
842
- clarify?: boolean;
843
- agentScope?: string;
844
- async?: unknown;
845
- context?: unknown;
846
- };
847
-
848
- assert.deepEqual(runParams.chain?.map(({ agent, task }) => ({ agent, task })), [
849
- { agent: "scout", task: "Scan {task}" },
850
- { agent: "reviewer", task: "Review {previous}" },
851
- ]);
852
- assert.equal(runParams.task, "Audit the auth flow");
853
- assert.equal(runParams.clarify, false);
854
- assert.equal(runParams.agentScope, "both");
855
- assert.equal(runParams.async, undefined);
856
- assert.equal(runParams.context, undefined);
857
- });
858
- });
859
-
860
- it("/run-chain returns while its foreground subagent is still running", async () => {
861
- await withTempProject("pi-run-chain-nonblocking-", async (root) => {
862
- writeProjectChain(root, "slow.chain.md", `---
863
- name: slow
864
- description: Slow chain
865
- ---
866
-
867
- ## scout
868
-
869
- Think for a long time about {task}
870
- `);
871
- const commands = new Map<string, RegisteredSlashCommand>();
872
- const events = createEventBus();
873
- let requestId: string | undefined;
874
- events.on(SLASH_SUBAGENT_REQUEST_EVENT, (data) => {
875
- const payload = data as { requestId: string };
876
- requestId = payload.requestId;
877
- events.emit(SLASH_SUBAGENT_STARTED_EVENT, { requestId });
878
- });
879
- const pi = {
880
- events,
881
- registerCommand(name: string, spec: RegisteredSlashCommand) { commands.set(name, spec); },
882
- registerShortcut() {},
883
- sendMessage(_message: unknown) {},
884
- };
885
- registerSlashCommands!(pi, createState(root));
886
-
887
- const returned = await Promise.race([
888
- commands.get("run-chain")!.handler("slow -- test UI responsiveness", createCommandContext({ cwd: root })).then(() => true),
889
- new Promise<boolean>((resolve) => setTimeout(() => resolve(false), 25)),
890
- ]);
891
- assert.equal(returned, true, "the slash command should not hold the UI while the child runs");
892
- assert.ok(requestId);
893
- events.emit(SLASH_SUBAGENT_RESPONSE_EVENT, {
894
- requestId,
895
- result: { content: [{ type: "text", text: "done" }], details: { mode: "chain", results: [] } },
896
- isError: false,
897
- });
898
- });
899
- });
900
691
 
901
- it("/run-chain launches a saved JSON chain with dynamic fanout", async () => {
902
- await withTempProject("pi-run-chain-json-dynamic-", async (root) => {
903
- writeProjectChain(root, "dynamic-review.chain.json", JSON.stringify({
904
- name: "dynamic-review",
905
- description: "Dynamic review flow",
906
- chain: [
907
- { agent: "scout", task: "Return targets", as: "targets", outputSchema: { type: "object" } },
908
- {
909
- expand: { from: { output: "targets", path: "/items" }, item: "target", key: "/path", maxItems: 4 },
910
- parallel: { agent: "reviewer", task: "Review {target.path}", outputSchema: { type: "object" } },
911
- collect: { as: "reviews" },
912
- },
913
- ],
914
- }));
915
-
916
- const { params } = await captureSlashCommandParams("run-chain", "dynamic-review -- Audit", root);
917
- const runParams = params as { chain?: Array<Record<string, unknown>>; task?: string; clarify?: boolean; agentScope?: string };
918
-
919
- assert.equal(runParams.task, "Audit");
920
- assert.equal(runParams.clarify, false);
921
- assert.equal(runParams.agentScope, "both");
922
- assert.equal(runParams.chain?.[0]?.agent, "scout");
923
- assert.deepEqual(runParams.chain?.[1]?.expand, { from: { output: "targets", path: "/items" }, item: "target", key: "/path", maxItems: 4 });
924
- assert.deepEqual(runParams.chain?.[1]?.collect, { as: "reviews" });
925
- });
926
- });
927
-
928
- it("/run-chain preserves saved JSON chain acceptance contracts", async () => {
929
- await withTempProject("pi-run-chain-json-acceptance-", async (root) => {
930
- writeProjectChain(root, "verified-flow.chain.json", JSON.stringify({
931
- name: "verified-flow",
932
- description: "Verified flow",
933
- chain: [
934
- {
935
- agent: "worker",
936
- task: "Implement fix",
937
- acceptance: {
938
- level: "verified",
939
- verify: [{ id: "tests", command: "npm test" }],
940
- },
941
- },
942
- ],
943
- }));
944
-
945
- const { params } = await captureSlashCommandParams("run-chain", "verified-flow -- Audit", root);
946
- assert.deepEqual((params as { chain?: Array<{ acceptance?: unknown }> }).chain?.[0]?.acceptance, {
947
- level: "verified",
948
- verify: [{ id: "tests", command: "npm test" }],
949
- });
950
- });
951
- });
952
-
953
- it("/run-chain launches and completes packaged saved chains by dotted runtime name", async () => {
954
- await withTempProject("pi-run-chain-packaged-", async (root) => {
955
- writeProjectChain(root, "code-analysis.review-flow.chain.md", `---
956
- name: review-flow
957
- package: code-analysis
958
- description: Review flow
959
- ---
960
-
961
- ## code-analysis.scout
962
-
963
- Scan {task}
964
- `);
965
-
966
- const { params } = await captureSlashCommandParams("run-chain", "code-analysis.review-flow -- Audit", root);
967
- assert.equal((params as { task?: string }).task, "Audit");
968
- assert.deepEqual((params as { chain?: Array<{ agent?: string; task?: string }> }).chain?.map(({ agent, task }) => ({ agent, task })), [
969
- { agent: "code-analysis.scout", task: "Scan {task}" },
970
- ]);
692
+ const run = await captureSlashCommandParams("run", "code-analysis.explorer Investigate", root);
693
+ assert.deepEqual(run.params, { agent: "code-analysis.explorer", task: "Investigate", clarify: false, agentScope: "both" });
971
694
 
972
695
  await withIsolatedHome(async () => {
973
696
  const commands = new Map<string, RegisteredSlashCommand>();
974
- const pi = {
697
+ registerSlashCommands!({
975
698
  events: createEventBus(),
976
699
  registerCommand(name: string, spec: RegisteredSlashCommand) { commands.set(name, spec); },
977
700
  registerShortcut() {},
978
- sendMessage(_message: unknown) {},
979
- };
980
- registerSlashCommands!(pi, createState(root));
981
- const completions = commands.get("run-chain")!.getArgumentCompletions!("code-") as Array<{ value: string; label: string }>;
982
- assert.deepEqual(completions.map((completion) => completion.value), ["code-analysis.review-flow"]);
701
+ sendMessage() {},
702
+ } as never, createState(root));
703
+ const completions = commands.get("run")!.getArgumentCompletions!("code-") as Array<{ value: string }>;
704
+ assert.deepEqual(completions.map(({ value }) => value), ["code-analysis.explorer"]);
983
705
  });
984
706
  });
985
707
  });
986
708
 
987
- it("/run-chain reports an unknown saved chain without launching", async () => {
988
- await withTempProject("pi-run-chain-unknown-", async (root) => {
989
- const { params, notifications } = await captureSlashCommandParams("run-chain", "missing -- Do work", root);
990
-
991
- assert.equal(params, undefined);
992
- assert.deepEqual(notifications, ["Unknown chain: missing"]);
993
- });
994
- });
995
-
996
- it("/run-chain suggests saved chain names", async () => {
997
- await withTempProject("pi-run-chain-completions-", async (root) => {
998
- writeProjectChain(root, "review-flow.chain.md", `---
999
- name: review-flow
1000
- description: Review flow
1001
- ---
1002
-
1003
- ## scout
1004
-
1005
- Scan
1006
- `);
1007
- writeProjectChain(root, "release-flow.chain.md", `---
1008
- name: release-flow
1009
- description: Release flow
1010
- ---
1011
-
1012
- ## planner
1013
-
1014
- Plan
1015
- `);
1016
- writeProjectChain(root, "triage.chain.md", `---
1017
- name: triage
1018
- description: Triage flow
1019
- ---
1020
-
1021
- ## scout
1022
-
1023
- Triage
1024
- `);
1025
-
1026
- await withIsolatedHome(async () => {
1027
- const commands = new Map<string, RegisteredSlashCommand>();
1028
- const pi = {
1029
- events: createEventBus(),
1030
- registerCommand(name: string, spec: RegisteredSlashCommand) {
1031
- commands.set(name, spec);
1032
- },
1033
- registerShortcut() {},
1034
- sendMessage(_message: unknown) {},
1035
- };
1036
-
1037
- registerSlashCommands!(pi, createState(root));
1038
- const completions = commands.get("run-chain")!.getArgumentCompletions!("re") as Array<{ value: string; label: string }>;
1039
- assert.deepEqual(completions.map((completion) => completion.value).sort(), ["release-flow", "review-flow"]);
1040
- assert.deepEqual(completions.map((completion) => completion.label).sort(), ["release-flow", "review-flow"]);
1041
- assert.equal(commands.get("run-chain")!.getArgumentCompletions!("review-flow -- "), null);
1042
- });
1043
- });
1044
- });
1045
-
1046
- it("/run-chain maps --bg to async execution", async () => {
1047
- await withTempProject("pi-run-chain-bg-", async (root) => {
1048
- writeProjectChain(root, "review-flow.chain.md", `---
1049
- name: review-flow
1050
- description: Review flow
1051
- ---
1052
-
1053
- ## scout
1054
-
1055
- Scan
1056
- `);
1057
-
1058
- const { params } = await captureSlashCommandParams("run-chain", "review-flow -- Audit --bg", root);
1059
-
1060
- assert.equal((params as { async?: unknown }).async, true);
1061
- assert.equal((params as { context?: unknown }).context, undefined);
1062
- });
1063
- });
1064
-
1065
- it("/run-chain maps --fork to forked context", async () => {
1066
- await withTempProject("pi-run-chain-fork-", async (root) => {
1067
- writeProjectChain(root, "review-flow.chain.md", `---
1068
- name: review-flow
1069
- description: Review flow
1070
- ---
1071
-
1072
- ## scout
1073
-
1074
- Scan
1075
- `);
1076
-
1077
- const { params } = await captureSlashCommandParams("run-chain", "review-flow -- Audit --fork", root);
1078
-
1079
- assert.equal((params as { context?: unknown }).context, "fork");
1080
- assert.equal((params as { async?: unknown }).async, undefined);
1081
- });
1082
- });
1083
-
1084
- it("/run-chain prefers a project saved chain over a same-named user chain", async () => {
1085
- await withTempProject("pi-run-chain-priority-", async (root) => {
1086
- writeProjectChain(root, "review-flow.chain.md", `---
1087
- name: review-flow
1088
- description: Project review flow
1089
- ---
1090
-
1091
- ## scout
1092
-
1093
- Project chain task
1094
- `);
1095
-
1096
- const { params } = await captureSlashCommandParams("run-chain", "review-flow -- Shared task", root, () => {
1097
- const userChainsDir = path.join(os.homedir(), ".selesai", "agent", "chains");
1098
- fs.mkdirSync(userChainsDir, { recursive: true });
1099
- fs.writeFileSync(path.join(userChainsDir, "review-flow.chain.md"), `---
1100
- name: review-flow
1101
- description: User review flow
1102
- ---
1103
-
1104
- ## scout
1105
-
1106
- User chain task
1107
- `, "utf-8");
1108
- });
1109
-
1110
- assert.equal((params as { chain?: Array<{ task?: string }> }).chain?.[0]?.task, "Project chain task");
1111
- });
1112
- });
1113
-
1114
- it("/run-chain resolves saved outputSchema files at the command boundary", async () => {
1115
- await withTempProject("pi-run-chain-schema-", async (root) => {
1116
- const schemasDir = path.join(root, ".selesai", "chains", "schemas");
1117
- fs.mkdirSync(schemasDir, { recursive: true });
1118
- fs.writeFileSync(path.join(schemasDir, "finding.schema.json"), JSON.stringify({ type: "object", properties: { ok: { type: "boolean" } } }), "utf-8");
1119
- writeProjectChain(root, "schema-flow.chain.md", `---
1120
- name: schema-flow
1121
- description: Schema flow
1122
- ---
1123
-
1124
- ## scout
1125
- outputSchema: ./schemas/finding.schema.json
1126
-
1127
- Gather context
1128
- `);
1129
-
1130
- const { params } = await captureSlashCommandParams("run-chain", "schema-flow -- Shared task", root);
1131
-
1132
- assert.deepEqual((params as { chain?: Array<{ outputSchema?: unknown }> }).chain?.[0]?.outputSchema, {
1133
- type: "object",
1134
- properties: { ok: { type: "boolean" } },
1135
- });
1136
- });
1137
- });
1138
-
1139
- it("/run-chain preserves saved step behavior fields", async () => {
1140
- await withTempProject("pi-run-chain-fields-", async (root) => {
1141
- writeProjectChain(root, "field-flow.chain.md", `---
1142
- name: field-flow
1143
- description: Field flow
1144
- ---
1145
-
1146
- ## scout
1147
- output: context.md
1148
- outputMode: file-only
1149
- reads: input.md, notes.md
1150
- model: openai/gpt-5.5
1151
- skills: research, audit
1152
- progress: true
1153
-
1154
- Gather context
1155
- `);
1156
-
1157
- const { params } = await captureSlashCommandParams("run-chain", "field-flow -- Shared task", root);
1158
-
1159
- assert.deepEqual((params as { chain?: unknown[] }).chain?.[0], {
1160
- agent: "scout",
1161
- task: "Gather context",
1162
- output: "context.md",
1163
- outputMode: "file-only",
1164
- reads: ["input.md", "notes.md"],
1165
- progress: true,
1166
- skill: ["research", "audit"],
1167
- model: "openai/gpt-5.5",
1168
- });
1169
- });
1170
- });
1171
-
1172
- it("/chain parses a parenthesized parallel group into a { parallel: [...] } step", async () => {
1173
- await withTempProject("pi-chain-group-slash-", async (root) => {
1174
- for (const name of ["scout", "reviewer", "writer"]) {
1175
- fs.writeFileSync(path.join(root, ".selesai", "agents", `${name}.md`), `---\nname: ${name}\ndescription: ${name}\n---\n\nBody\n`, "utf-8");
1176
- }
1177
-
1178
- const { params, notifications } = await captureSlashCommandParams("chain", 'scout "scan" -> (reviewer "A" | reviewer "B") -> writer "fix"', root);
1179
- assert.deepEqual(notifications, []);
1180
- const built = params as { chain?: Array<Record<string, unknown>>; task?: string };
1181
- assert.equal(built.task, "scan");
1182
- assert.equal(built.chain?.length, 3);
1183
- assert.equal(built.chain?.[0]?.agent, "scout");
1184
- const parallel = built.chain?.[1]?.parallel as Array<{ agent: string; task: string }>;
1185
- assert.ok(Array.isArray(parallel), "second step should be a parallel group");
1186
- assert.deepEqual(parallel.map(({ agent, task }) => ({ agent, task })), [
1187
- { agent: "reviewer", task: "A" },
1188
- { agent: "reviewer", task: "B" },
1189
- ]);
1190
- assert.equal(built.chain?.[2]?.agent, "writer");
1191
- });
1192
- });
1193
-
1194
- it("/chain reports parallel-group errors as notifications and does not launch", async () => {
1195
- await withTempProject("pi-chain-group-error-", async (root) => {
1196
- for (const name of ["scout", "reviewer"]) {
1197
- fs.writeFileSync(path.join(root, ".selesai", "agents", `${name}.md`), `---\nname: ${name}\ndescription: ${name}\n---\n\nBody\n`, "utf-8");
1198
- }
1199
-
1200
- const { params, notifications } = await captureSlashCommandParams("chain", 'scout "scan" -> (reviewer "A")', root);
1201
- assert.equal(params, undefined);
1202
- assert.equal(notifications.length, 1);
1203
- assert.match(notifications[0] ?? "", /at least two/i);
1204
- });
1205
- });
1206
-
1207
- it("/chain carries inline metadata and group options through to params", async () => {
1208
- await withTempProject("pi-chain-group-meta-", async (root) => {
1209
- for (const name of ["scout", "reviewer", "writer"]) {
1210
- fs.writeFileSync(path.join(root, ".selesai", "agents", `${name}.md`), `---\nname: ${name}\ndescription: ${name}\n---\n\nBody\n`, "utf-8");
1211
- }
1212
-
1213
- const { params, notifications } = await captureSlashCommandParams(
1214
- "chain",
1215
- 'scout[as=ctx,phase=recon] "scan" -> (reviewer "A" | writer "B")[concurrency=2,failFast]',
1216
- root,
1217
- );
1218
- assert.deepEqual(notifications, []);
1219
- const built = params as { chain?: Array<Record<string, unknown>> };
1220
- assert.equal(built.chain?.[0]?.as, "ctx");
1221
- assert.equal(built.chain?.[0]?.phase, "recon");
1222
- const group = built.chain?.[1] as Record<string, unknown>;
1223
- assert.equal((group.parallel as unknown[]).length, 2);
1224
- assert.equal(group.concurrency, 2);
1225
- assert.equal(group.failFast, true);
1226
- });
1227
- });
1228
-
1229
- it("/chain tab-completion works inside parallel groups", async () => {
1230
- await withTempProject("pi-chain-group-complete-", async (root) => {
1231
- for (const name of ["scout", "reviewer", "writer"]) {
1232
- fs.writeFileSync(path.join(root, ".selesai", "agents", `${name}.md`), `---\nname: ${name}\ndescription: ${name}\n---\n\nBody\n`, "utf-8");
1233
- }
1234
- await withIsolatedHome(async () => {
1235
- const commands = new Map<string, RegisteredSlashCommand>();
1236
- const pi = {
1237
- events: createEventBus(),
1238
- registerCommand(name: string, spec: RegisteredSlashCommand) { commands.set(name, spec); },
1239
- registerShortcut() {},
1240
- sendMessage(_message: unknown) {},
1241
- };
1242
- registerSlashCommands!(pi, createState(root));
1243
- const complete = (prefix: string) =>
1244
- (commands.get("chain")!.getArgumentCompletions!(prefix) as Array<{ value: string }> | null)?.map((c) => c.value) ?? null;
1245
-
1246
- // after `(`
1247
- assert.deepEqual(complete('scout "scan" -> (rev'), ['scout "scan" -> (reviewer']);
1248
- // after `|`
1249
- assert.deepEqual(complete('scout "scan" -> (reviewer "A" | wr'), ['scout "scan" -> (reviewer "A" | writer']);
1250
- // after a bare `|` a space is inserted before every suggested agent
1251
- const barePipe = complete('scout "scan" -> (reviewer "A" |');
1252
- assert.ok(barePipe && barePipe.length > 0);
1253
- assert.ok(barePipe.every((v) => v.startsWith('scout "scan" -> (reviewer "A" | ')));
1254
- assert.ok(barePipe.includes('scout "scan" -> (reviewer "A" | writer'));
1255
- // inside an open quote: no agent completion
1256
- assert.equal(complete('scout "scan'), null);
1257
- });
1258
- });
1259
- });
1260
- });
1261
-
1262
-
1263
- describe("subagents-models slash command", { skip: !available ? "slash-commands.ts not importable" : undefined }, () => {
1264
- beforeEach(() => {
1265
- clearSlashSnapshots?.();
1266
- });
1267
-
1268
- it("routes to the models tool action", async () => {
1269
- const { params } = await captureSlashCommandParams("subagents-models", "", process.cwd());
1270
- assert.deepEqual(params, { action: "models" });
1271
- });
1272
-
1273
- it("passes an optional builtin filter", async () => {
1274
- const { params } = await captureSlashCommandParams("subagents-models", "explorer", process.cwd());
1275
- assert.deepEqual(params, { action: "models", agent: "explorer" });
1276
- });
1277
-
1278
- it("rejects invalid builtin filters without launching", async () => {
1279
- const { params, notifications } = await captureSlashCommandParams("subagents-models", "not-a-builtin", process.cwd());
1280
- assert.equal(params, undefined);
1281
- assert.deepEqual(notifications, ["Unknown builtin agent: not-a-builtin"]);
1282
- });
1283
-
1284
- it("suggests builtin agent names", async () => {
1285
- await withIsolatedHome(async () => {
1286
- const commands = new Map<string, RegisteredSlashCommand>();
1287
- const pi = {
1288
- events: createEventBus(),
1289
- registerCommand(name: string, spec: RegisteredSlashCommand) {
1290
- commands.set(name, spec);
1291
- },
1292
- registerShortcut() {},
1293
- sendMessage(_message: unknown) {},
1294
- };
1295
-
1296
- registerSlashCommands!(pi, createState(process.cwd()));
1297
- const completions = commands.get("subagents-models")!.getArgumentCompletions!("ex") as Array<{ value: string; label: string }>;
1298
- assert.deepEqual(completions.map((completion) => completion.value), ["explorer"]);
1299
- });
1300
- });
1301
- });
1302
-
1303
- describe("subagent cost slash command", { skip: !available ? "slash-commands.ts not importable" : undefined }, () => {
1304
- it("reports parent and child usage from the current session branch", async () => {
1305
- const sent: unknown[] = [];
1306
- const commands = new Map<string, RegisteredSlashCommand>();
1307
- const pi = {
1308
- events: createEventBus(),
1309
- registerCommand(name: string, spec: RegisteredSlashCommand) {
1310
- commands.set(name, spec);
1311
- },
1312
- registerShortcut() {},
1313
- sendMessage(message: unknown) { sent.push(message); },
1314
- };
1315
- const parentUsage = {
1316
- input: 100,
1317
- output: 50,
1318
- cacheRead: 10,
1319
- cacheWrite: 5,
1320
- cost: { input: 0.001, output: 0.002, cacheRead: 0, cacheWrite: 0, total: 0.003 },
1321
- };
1322
- const childUsage = { input: 20, output: 10, cacheRead: 2, cacheWrite: 1, cost: 0.004, turns: 1 };
1323
- const slashChildUsage = { input: 30, output: 15, cacheRead: 0, cacheWrite: 0, cost: 0.005, turns: 2 };
1324
- registerSlashCommands!(pi, createState(process.cwd()));
1325
- await commands.get("subagent-cost")!.handler("", createCommandContext({
1326
- sessionManager: {
1327
- getBranch: () => [
1328
- { type: "message", message: { role: "assistant", usage: parentUsage } },
1329
- {
1330
- type: "message",
1331
- message: {
1332
- role: "toolResult",
1333
- toolName: "subagent",
1334
- details: {
1335
- mode: "single",
1336
- results: [{ agent: "worker", task: "fix", exitCode: 0, messages: [], usage: childUsage, sessionFile: "/tmp/worker.jsonl" }],
1337
- },
1338
- },
1339
- },
1340
- {
1341
- type: "custom_message",
1342
- customType: SLASH_RESULT_TYPE,
1343
- details: {
1344
- requestId: "slash-1",
1345
- result: {
1346
- content: [{ type: "text", text: "done" }],
1347
- details: {
1348
- mode: "single",
1349
- results: [{ agent: "reviewer", task: "review", exitCode: 0, messages: [], usage: slashChildUsage }],
1350
- },
1351
- },
1352
- },
1353
- },
1354
- ],
1355
- },
1356
- }));
1357
-
1358
- const output = String((sent[0] as { content?: unknown }).content ?? "");
1359
- assert.match(output, /Parent: ↑100 ↓50 \$0\.0030/);
1360
- assert.match(output, /Child 1 \(worker\): ↑20 ↓10 \$0\.0040/);
1361
- assert.match(output, /Session: \/tmp\/worker\.jsonl/);
1362
- assert.match(output, /Child 2 \(reviewer\): ↑30 ↓15 \$0\.0050/);
1363
- assert.match(output, /Children: ↑50 ↓25 \$0\.0090/);
1364
- assert.match(output, /Total: ↑150 ↓75 \$0\.0120/);
1365
- });
1366
- });
1367
-
1368
- describe("subagent profiles slash commands", { skip: !available ? "slash-commands.ts not importable" : undefined }, () => {
1369
- it("lists saved profiles", async () => {
1370
- await withIsolatedHome(async () => {
1371
- const profilesDir = path.join(process.env.HOME!, ".selesai", "agent", "profiles", "pi-subagents");
1372
- fs.mkdirSync(profilesDir, { recursive: true });
1373
- fs.writeFileSync(path.join(profilesDir, "openai-codex.quota.json"), JSON.stringify({ subagents: { agentOverrides: {} } }));
1374
- fs.writeFileSync(path.join(profilesDir, "openai-codex.quality.json"), JSON.stringify({ subagents: { agentOverrides: {} } }));
1375
- const sent: unknown[] = [];
1376
- const commands = new Map<string, RegisteredSlashCommand>();
1377
- const pi = {
1378
- events: createEventBus(),
1379
- registerCommand(name: string, spec: RegisteredSlashCommand) {
1380
- commands.set(name, spec);
1381
- },
1382
- registerShortcut() {},
1383
- sendMessage(message: unknown) { sent.push(message); },
1384
- };
1385
- registerSlashCommands!(pi, createState(process.cwd()));
1386
- await commands.get("subagents-profiles")!.handler("", createCommandContext());
1387
- assert.match(String((sent[0] as { content?: unknown }).content ?? ""), /openai-codex\.quota/);
1388
- assert.match(String((sent[0] as { content?: unknown }).content ?? ""), /openai-codex\.quality/);
1389
- });
1390
- });
1391
-
1392
- it("loads a saved profile into user settings", async () => {
1393
- await withIsolatedHome(async () => {
1394
- const profilesDir = path.join(process.env.HOME!, ".selesai", "agent", "profiles", "pi-subagents");
1395
- fs.mkdirSync(profilesDir, { recursive: true });
1396
- fs.writeFileSync(path.join(profilesDir, "openai-codex.quota.json"), JSON.stringify({
1397
- subagents: { agentOverrides: {
1398
- scout: { model: "openai-codex/gpt-5.3-codex-spark" },
1399
- worker: { model: "openai-codex/gpt-5.4" },
1400
- } },
1401
- }, null, 2));
1402
- const sent: unknown[] = [];
1403
- const commands = new Map<string, RegisteredSlashCommand>();
1404
- const pi = {
1405
- events: createEventBus(),
1406
- registerCommand(name: string, spec: RegisteredSlashCommand) { commands.set(name, spec); },
1407
- registerShortcut() {},
1408
- sendMessage(message: unknown) { sent.push(message); },
1409
- };
1410
- registerSlashCommands!(pi, createState(process.cwd()));
1411
- await commands.get("subagents-load-profile")!.handler("openai-codex.quota", createCommandContext());
1412
- const settings = JSON.parse(fs.readFileSync(path.join(process.env.HOME!, ".selesai", "agent", "settings.json"), "utf-8"));
1413
- assert.equal(settings.subagents.agentOverrides.scout.model, "openai-codex/gpt-5.3-codex-spark");
1414
- assert.equal(settings.subagents.agentOverrides.worker.model, "openai-codex/gpt-5.4");
1415
- assert.doesNotMatch(String((sent[0] as { content?: unknown }).content ?? ""), /run \/reload/);
1416
- });
1417
- });
1418
-
1419
- it("can switch the current session model to the loaded profile worker model", async () => {
1420
- await withIsolatedHome(async () => {
1421
- const profilesDir = path.join(process.env.HOME!, ".selesai", "agent", "profiles", "pi-subagents");
1422
- fs.mkdirSync(profilesDir, { recursive: true });
1423
- fs.writeFileSync(path.join(profilesDir, "openai-codex.quota.json"), JSON.stringify({
1424
- subagents: { agentOverrides: { builder: { model: "gpt-5.4:high" } } },
1425
- }, null, 2));
1426
- const sent: unknown[] = [];
1427
- const commands = new Map<string, RegisteredSlashCommand>();
1428
- let setModelArg: unknown;
1429
- const resolvedModel = { provider: "openai-codex", id: "gpt-5.4" };
1430
- const pi = {
1431
- events: createEventBus(),
1432
- async setModel(model: unknown) { setModelArg = model; return true; },
1433
- registerCommand(name: string, spec: RegisteredSlashCommand) { commands.set(name, spec); },
1434
- registerShortcut() {},
1435
- sendMessage(message: unknown) { sent.push(message); },
1436
- };
1437
- registerSlashCommands!(pi as never, createState(process.cwd()));
1438
- await commands.get("subagents-load-profile")!.handler("openai-codex.quota", createCommandContext({
1439
- confirm: async () => true,
1440
- modelRegistry: {
1441
- getAvailable: () => [{ provider: "openai-codex", id: "gpt-5.4" }],
1442
- find: (provider, id) => provider === "openai-codex" && id === "gpt-5.4" ? resolvedModel : undefined,
1443
- },
1444
- }) as never);
1445
- assert.equal(setModelArg, resolvedModel);
1446
- assert.match(String((sent[0] as { content?: unknown }).content ?? ""), /Current session model switched to: openai-codex\/gpt-5.4/);
1447
- });
1448
- });
1449
-
1450
- it("refreshes a provider model catalog", async () => {
1451
- await withIsolatedHome(async () => {
1452
- const sent: unknown[] = [];
1453
- const commands = new Map<string, RegisteredSlashCommand>();
1454
- const pi = {
1455
- events: createEventBus(),
1456
- exec: async () => ({ stdout: "OK\n", stderr: "", code: 0, killed: false }),
1457
- registerCommand(name: string, spec: RegisteredSlashCommand) { commands.set(name, spec); },
1458
- registerShortcut() {},
1459
- sendMessage(message: unknown) { sent.push(message); },
1460
- };
1461
- registerSlashCommands!(pi, createState(process.cwd()));
1462
- await commands.get("subagents-refresh-provider-models")!.handler("openai-codex", createCommandContext({
1463
- cwd: process.cwd(),
1464
- modelRegistry: {
1465
- getAvailable: () => [
1466
- { provider: "openai-codex", id: "gpt-5.3-codex-spark", reasoning: true },
1467
- { provider: "openai-codex", id: "gpt-5.4-mini", reasoning: true },
1468
- ],
1469
- },
1470
- }) as never);
1471
- assert.match(String((sent[0] as { content?: unknown }).content ?? ""), /Provider: openai-codex/);
1472
- assert.match(String((sent[0] as { content?: unknown }).content ?? ""), /Warning: 2 models were classified with name heuristics fallback\./);
1473
- assert.equal(fs.existsSync(path.join(process.env.HOME!, ".selesai", "agent", "profiles", "pi-subagents", "providers", "openai-codex.models.json")), true);
1474
- });
1475
- });
1476
-
1477
- it("generates provider profiles", async () => {
1478
- await withIsolatedHome(async () => {
1479
- const sent: unknown[] = [];
1480
- const commands = new Map<string, RegisteredSlashCommand>();
1481
- const pi = {
1482
- events: createEventBus(),
1483
- exec: async () => ({ stdout: "OK\n", stderr: "", code: 0, killed: false }),
1484
- registerCommand(name: string, spec: RegisteredSlashCommand) { commands.set(name, spec); },
1485
- registerShortcut() {},
1486
- sendMessage(message: unknown) { sent.push(message); },
1487
- };
1488
- registerSlashCommands!(pi, createState(process.cwd()));
1489
- await commands.get("subagents-generate-profiles")!.handler("openai-codex", createCommandContext({
1490
- modelRegistry: {
1491
- getAvailable: () => [
1492
- { provider: "openai-codex", id: "gpt-5.3-codex-spark", reasoning: true },
1493
- { provider: "openai-codex", id: "gpt-5.4-mini", reasoning: true },
1494
- { provider: "openai-codex", id: "gpt-5.4", reasoning: true },
1495
- { provider: "openai-codex", id: "gpt-5.5", reasoning: true },
1496
- ],
1497
- },
1498
- }) as never);
1499
- assert.match(String((sent[0] as { content?: unknown }).content ?? ""), /Generated subagent profiles/);
1500
- assert.match(String((sent[0] as { content?: unknown }).content ?? ""), /Warning: generated profiles depend on heuristic-only classification for 4 selected models\./);
1501
- assert.equal(fs.existsSync(path.join(process.env.HOME!, ".selesai", "agent", "profiles", "pi-subagents", "openai-codex.quota.json")), true);
1502
- assert.equal(fs.existsSync(path.join(process.env.HOME!, ".selesai", "agent", "profiles", "pi-subagents", "openai-codex.quality.json")), true);
1503
- });
1504
- });
1505
-
1506
- it("checks a profile", async () => {
1507
- await withIsolatedHome(async () => {
1508
- const profilesDir = path.join(process.env.HOME!, ".selesai", "agent", "profiles", "pi-subagents");
1509
- fs.mkdirSync(profilesDir, { recursive: true });
1510
- fs.writeFileSync(path.join(profilesDir, "demo.json"), JSON.stringify({
1511
- subagents: { agentOverrides: { scout: { model: "openai-codex/gpt-5.3-codex-spark" } } },
1512
- }, null, 2));
1513
- const sent: unknown[] = [];
1514
- const commands = new Map<string, RegisteredSlashCommand>();
1515
- const pi = {
1516
- events: createEventBus(),
1517
- exec: async () => ({ stdout: "OK\n", stderr: "", code: 0, killed: false }),
1518
- registerCommand(name: string, spec: RegisteredSlashCommand) { commands.set(name, spec); },
1519
- registerShortcut() {},
1520
- sendMessage(message: unknown) { sent.push(message); },
1521
- };
1522
- registerSlashCommands!(pi, createState(process.cwd()));
1523
- await commands.get("subagents-check-profile")!.handler("demo", createCommandContext({
1524
- modelRegistry: { getAvailable: () => [{ provider: "openai-codex", id: "gpt-5.3-codex-spark" }] },
1525
- }) as never);
1526
- assert.match(String((sent[0] as { content?: unknown }).content ?? ""), /probe ok/);
1527
- });
1528
- });
1529
-
1530
- it("suggests provider names for refresh and generate commands", async () => {
1531
- await withIsolatedHome(async () => {
1532
- const commands = new Map<string, RegisteredSlashCommand>();
1533
- const pi = {
1534
- events: createEventBus(),
1535
- registerCommand(name: string, spec: RegisteredSlashCommand) { commands.set(name, spec); },
1536
- registerShortcut() {},
1537
- sendMessage(_message: unknown) {},
1538
- };
1539
- const state = createState(process.cwd());
1540
- state.lastUiContext = createCommandContext({
1541
- modelRegistry: {
1542
- getAvailable: () => [
1543
- { provider: "openai-codex", id: "gpt-5.4" },
1544
- { provider: "openai", id: "gpt-5" },
1545
- { provider: "anthropic", id: "claude-sonnet-4" },
1546
- ],
1547
- },
1548
- }) as never;
1549
- registerSlashCommands!(pi, state);
1550
- const refresh = commands.get("subagents-refresh-provider-models")!.getArgumentCompletions!("open") as Array<{ value: string; label: string }>;
1551
- const generate = commands.get("subagents-generate-profiles")!.getArgumentCompletions!("an") as Array<{ value: string; label: string }>;
1552
- assert.deepEqual(refresh.map((entry) => entry.value), ["openai", "openai-codex"]);
1553
- assert.deepEqual(generate.map((entry) => entry.value), ["anthropic"]);
1554
- });
1555
- });
1556
- });
1557
-
1558
- describe("subagents admin slash command", { skip: !available ? "slash-commands.ts not importable" : undefined }, () => {
1559
- beforeEach(() => {
1560
- clearSlashSnapshots?.();
1561
- });
1562
-
1563
- function registerAdmin(sent: unknown[]) {
1564
- const commands = new Map<string, RegisteredSlashCommand>();
1565
- const pi = {
1566
- events: createEventBus(),
1567
- registerCommand(name: string, spec: RegisteredSlashCommand) { commands.set(name, spec); },
1568
- registerShortcut() {},
1569
- sendMessage(message: unknown) { sent.push(message); },
1570
- };
1571
- registerSlashCommands!(pi, createState(process.cwd()));
1572
- return commands;
1573
- }
1574
-
1575
- it("registers /subagents", async () => {
1576
- await withIsolatedHome(async () => {
1577
- const commands = registerAdmin([]);
1578
- assert.equal(commands.has("subagents"), true);
1579
- });
1580
- });
1581
-
1582
- it("treats agent and scope selector cancellation as a silent no-op", async () => {
1583
- await withIsolatedHome(async () => {
1584
- await withTempProject("pi-subagents-admin-cancel-", async (root) => {
1585
- const sent: unknown[] = [];
1586
- const notifications: string[] = [];
1587
- const commands = registerAdmin(sent);
1588
-
1589
- await commands.get("subagents")!.handler("", createCommandContext({
1590
- cwd: root,
1591
- hasUI: true,
1592
- select: async () => undefined,
1593
- notify: (message) => notifications.push(message),
1594
- }));
1595
-
1596
- await commands.get("subagents")!.handler("builder model", createCommandContext({
1597
- cwd: root,
1598
- hasUI: true,
1599
- modelRegistry: { getAvailable: () => [{ provider: "test", id: "new-model", reasoning: true }] },
1600
- select: async (title) => title.startsWith("Select model") ? "test/new-model" : undefined,
1601
- notify: (message) => notifications.push(message),
1602
- }));
1603
-
1604
- assert.deepEqual(sent, []);
1605
- assert.deepEqual(notifications, []);
1606
- assert.equal(fs.existsSync(path.join(root, ".selesai", "settings.json")), false);
1607
- });
1608
- });
1609
- });
1610
-
1611
- it("reports duplicate names as ambiguous without UI", async () => {
1612
- await withIsolatedHome(async () => {
1613
- await withTempProject("pi-subagents-admin-ambiguous-", async (root) => {
1614
- fs.writeFileSync(path.join(root, ".selesai", "agents", "builder.md"), "---\nname: builder\ndescription: Project builder\n---\n\nWork.\n", "utf-8");
1615
- const sent: unknown[] = [];
1616
- const commands = registerAdmin(sent);
1617
- await commands.get("subagents")!.handler("builder", createCommandContext({ cwd: root }));
1618
- assert.equal(sent.length, 1);
1619
- const content = (sent[0] as { content?: string }).content ?? "";
1620
- assert.match(content, /Subagent 'builder' is ambiguous/);
1621
- assert.match(content, /project:/);
1622
- assert.match(content, /builtin:/);
1623
- });
1624
- });
1625
- });
1626
-
1627
- it("keeps same-source duplicate agents distinct in interactive pickers", async () => {
1628
- await withIsolatedHome(async () => {
1629
- await withTempProject("pi-subagents-admin-same-source-", async (root) => {
1630
- const localPath = path.join(process.env.SELESAI_CODING_AGENT_DIR!, "agents", "duplicate-admin-agent.md");
1631
- const extraDir = path.join(root, "extra-agents");
1632
- const extraPath = path.join(extraDir, "duplicate-admin-agent.md");
1633
- fs.mkdirSync(path.dirname(localPath), { recursive: true });
1634
- fs.mkdirSync(extraDir, { recursive: true });
1635
- const frontmatter = "---\nname: duplicate-admin-agent\ndescription: Duplicate agent\nmodel: test/model\n---\n\n";
1636
- fs.writeFileSync(localPath, `${frontmatter}Local prompt.\n`, "utf-8");
1637
- fs.writeFileSync(extraPath, `${frontmatter}Extra prompt.\n`, "utf-8");
1638
- const previousExtraDirs = process.env.SELESAI_SUBAGENT_EXTRA_AGENT_DIRS;
1639
- process.env.SELESAI_SUBAGENT_EXTRA_AGENT_DIRS = extraDir;
1640
- try {
1641
- const sent: unknown[] = [];
1642
- const commands = registerAdmin(sent);
1643
- await commands.get("subagents")!.handler("duplicate-admin-agent details", createCommandContext({
1644
- cwd: root,
1645
- hasUI: true,
1646
- select: async (_title, choices) => {
1647
- assert.equal(choices.length, 2);
1648
- assert.ok(choices.some((choice) => choice.includes(localPath)));
1649
- assert.ok(choices.some((choice) => choice.includes(extraPath)));
1650
- return choices.find((choice) => choice.includes(localPath));
1651
- },
1652
- }));
1653
- const content = (sent[0] as { content?: string }).content ?? "";
1654
- assert.ok(content.split("\n").includes(`Path: ${localPath}`));
1655
- } finally {
1656
- if (previousExtraDirs === undefined) delete process.env.SELESAI_SUBAGENT_EXTRA_AGENT_DIRS;
1657
- else process.env.SELESAI_SUBAGENT_EXTRA_AGENT_DIRS = previousExtraDirs;
1658
- }
1659
- });
1660
- });
1661
- });
1662
-
1663
- it("updates a project agent model without dumping metadata first", async () => {
1664
- await withIsolatedHome(async () => {
1665
- await withTempProject("pi-subagents-admin-model-", async (root) => {
1666
- const agentPath = path.join(root, ".selesai", "agents", "worker.md");
1667
- fs.writeFileSync(agentPath, `---\nname: worker\ndescription: Test worker\nmodel: anthropic/claude-sonnet-4-6\n---\n\nDo work.\n`, "utf-8");
1668
- const sent: unknown[] = [];
1669
- const commands = registerAdmin(sent);
1670
- let refreshes = 0;
1671
- await commands.get("subagents")!.handler("worker model", createCommandContext({
1672
- cwd: root,
1673
- hasUI: true,
1674
- modelRegistry: {
1675
- refresh: () => { refreshes++; },
1676
- getAvailable: () => [{ provider: "bluebox-azure-openai", id: "gpt-5_6-sol", reasoning: true }],
1677
- },
1678
- select: async (_title, choices) => {
1679
- const projectAgent = choices.find((choice) => choice.startsWith("worker [project]"));
1680
- if (projectAgent) return projectAgent;
1681
- assert.ok(choices.includes("bluebox-azure-openai/gpt-5_6-sol"));
1682
- return "bluebox-azure-openai/gpt-5_6-sol";
1683
- },
1684
- }));
1685
-
1686
- assert.equal(refreshes, 1);
1687
- assert.match(fs.readFileSync(agentPath, "utf-8"), /^model: bluebox-azure-openai\/gpt-5_6-sol$/m);
1688
- assert.equal(sent.length, 1, "only the compact confirmation should enter the conversation");
1689
- assert.match((sent[0] as { content?: string }).content ?? "", /Updated 'worker' model/);
1690
- });
1691
- });
1692
- });
1693
-
1694
- it("updates a profile-managed user agent through settings instead of pinning frontmatter", async () => {
1695
- await withIsolatedHome(async () => {
1696
- await withTempProject("pi-subagents-admin-profile-", async (root) => {
1697
- const userAgentDir = path.join(process.env.HOME!, ".selesai", "agent", "agents");
1698
- fs.mkdirSync(userAgentDir, { recursive: true });
1699
- const agentPath = path.join(userAgentDir, "worker.md");
1700
- fs.writeFileSync(agentPath, `---\nname: worker\ndescription: Profile worker\n---\n\nDo work.\n`, "utf-8");
1701
- const settingsPath = path.join(process.env.HOME!, ".selesai", "agent", "settings.json");
1702
- fs.writeFileSync(settingsPath, JSON.stringify({
1703
- subagents: { disableBuiltins: true, agentOverrides: { worker: { model: "anthropic/claude-opus-4-8" } } },
1704
- }, null, 2));
1705
-
1706
- const sent: unknown[] = [];
1707
- const commands = registerAdmin(sent);
1708
- await commands.get("subagents")!.handler("worker model", createCommandContext({
1709
- cwd: root,
1710
- hasUI: true,
1711
- modelRegistry: { getAvailable: () => [{ provider: "bluebox-azure-openai", id: "gpt-5_6-luna", reasoning: true }] },
1712
- select: async (_title, choices) =>
1713
- choices.find((choice) => choice.startsWith("worker [user]"))
1714
- ?? "bluebox-azure-openai/gpt-5_6-luna",
1715
- }));
1716
-
1717
- assert.doesNotMatch(fs.readFileSync(agentPath, "utf-8"), /^model:/m);
1718
- const settings = JSON.parse(fs.readFileSync(settingsPath, "utf-8"));
1719
- assert.equal(settings.subagents.disableBuiltins, true);
1720
- assert.equal(settings.subagents.agentOverrides.worker.model, "bluebox-azure-openai/gpt-5_6-luna");
1721
- });
1722
- });
1723
- });
1724
-
1725
- it("does not snapshot global disableThinking into an unrelated builtin override", async () => {
1726
- await withIsolatedHome(async () => {
1727
- await withTempProject("pi-subagents-admin-global-thinking-", async (root) => {
1728
- const settingsPath = path.join(process.env.SELESAI_CODING_AGENT_DIR!, "settings.json");
1729
- fs.mkdirSync(path.dirname(settingsPath), { recursive: true });
1730
- fs.writeFileSync(settingsPath, JSON.stringify({ subagents: { disableThinking: true } }, null, 2), "utf-8");
1731
- const commands = registerAdmin([]);
1732
- await commands.get("subagents")!.handler("builder model", createCommandContext({
1733
- cwd: root,
1734
- hasUI: true,
1735
- modelRegistry: { getAvailable: () => [{ provider: "test", id: "new-model", reasoning: true }] },
1736
- select: async () => "test/new-model",
1737
- }));
1738
-
1739
- assert.deepEqual(JSON.parse(fs.readFileSync(settingsPath, "utf-8")).subagents, {
1740
- disableThinking: true,
1741
- agentOverrides: { builder: { model: "test/new-model" } },
1742
- });
1743
- });
1744
- });
1745
- });
1746
-
1747
- it("offers and saves max thinking only when model metadata declares it", async () => {
1748
- await withIsolatedHome(async () => {
1749
- await withTempProject("pi-subagents-admin-thinking-", async (root) => {
1750
- const settingsPath = path.join(process.env.SELESAI_CODING_AGENT_DIR!, "settings.json");
1751
- fs.mkdirSync(path.dirname(settingsPath), { recursive: true });
1752
- fs.writeFileSync(settingsPath, JSON.stringify({
1753
- subagents: { agentOverrides: { worker: { model: "anthropic/claude-opus-4-8", thinking: "high" } } },
1754
- }, null, 2));
1755
- const agentPath = path.join(root, ".selesai", "agents", "worker.md");
1756
- fs.writeFileSync(agentPath, `---\nname: worker\ndescription: Test worker\nmodel: bluebox-azure-openai/gpt-5_6-sol\n---\n\nDo work.\n`, "utf-8");
1757
- const commands = registerAdmin([]);
1758
- await commands.get("subagents")!.handler("worker thinking", createCommandContext({
1759
- cwd: root,
1760
- hasUI: true,
1761
- modelRegistry: {
1762
- getAvailable: () => [{
1763
- provider: "bluebox-azure-openai",
1764
- id: "gpt-5_6-sol",
1765
- reasoning: true,
1766
- thinkingLevelMap: { minimal: null, xhigh: "xhigh", max: "max" },
1767
- }],
1768
- },
1769
- select: async (_title, choices) => {
1770
- const projectAgent = choices.find((choice) => choice.startsWith("worker [project]"));
1771
- if (projectAgent) return projectAgent;
1772
- assert.ok(choices.includes("max"));
1773
- assert.equal(choices.includes("minimal"), false);
1774
- return "max";
1775
- },
1776
- }));
1777
- assert.match(fs.readFileSync(agentPath, "utf-8"), /^thinking: max$/m);
1778
- assert.deepEqual(JSON.parse(fs.readFileSync(settingsPath, "utf-8")).subagents.agentOverrides.worker, {
1779
- model: "anthropic/claude-opus-4-8",
1780
- thinking: "high",
1781
- });
1782
- });
1783
- });
1784
- });
1785
-
1786
- it("uses the inherited session model's thinking capabilities and warns on refresh failure", async () => {
1787
- await withIsolatedHome(async () => {
1788
- await withTempProject("pi-subagents-admin-inherited-thinking-", async (root) => {
1789
- fs.writeFileSync(path.join(root, ".selesai", "agents", "auditor.md"), "---\nname: auditor\ndescription: Audit things\n---\n\nAudit.\n", "utf-8");
1790
- const notifications: Array<{ message: string; type?: string }> = [];
1791
- const commands = registerAdmin([]);
1792
- await commands.get("subagents")!.handler("auditor thinking", createCommandContext({
1793
- cwd: root,
1794
- hasUI: true,
1795
- model: { provider: "test", id: "plain-model" },
1796
- modelRegistry: {
1797
- refresh: () => { throw new Error("invalid models.json"); },
1798
- getAvailable: () => [{ provider: "test", id: "plain-model", reasoning: false }],
1799
- },
1800
- select: async (title, choices) => {
1801
- assert.match(title, /Session model: test\/plain-model/);
1802
- assert.deepEqual(choices, ["Default / inherit session thinking", "off"]);
1803
- return undefined;
1804
- },
1805
- notify: (message, type) => notifications.push({ message, type }),
1806
- }));
1807
-
1808
- assert.equal(notifications.length, 1);
1809
- assert.equal(notifications[0]?.type, "warning");
1810
- assert.match(notifications[0]?.message ?? "", /using the last loaded choices.*invalid models\.json/);
1811
- });
1812
- });
1813
- });
1814
-
1815
- it("does not pin inherited settings when editing a project-owned field", async () => {
1816
- await withIsolatedHome(async () => {
1817
- await withTempProject("pi-subagents-admin-cross-scope-", async (root) => {
1818
- const agentPath = path.join(root, ".selesai", "agents", "worker.md");
1819
- fs.writeFileSync(agentPath, "---\nname: worker\ndescription: Test worker\n---\n\nDo work.\n", "utf-8");
1820
- const settingsPath = path.join(process.env.HOME!, ".selesai", "agent", "settings.json");
1821
- fs.mkdirSync(path.dirname(settingsPath), { recursive: true });
1822
- fs.writeFileSync(settingsPath, JSON.stringify({
1823
- subagents: { agentOverrides: { worker: { thinking: "high" } } },
1824
- }, null, 2));
1825
-
1826
- const commands = registerAdmin([]);
1827
- await commands.get("subagents")!.handler("worker model", createCommandContext({
1828
- cwd: root,
1829
- hasUI: true,
1830
- modelRegistry: { getAvailable: () => [{ provider: "bluebox-azure-openai", id: "gpt-5_6-sol", reasoning: true }] },
1831
- select: async (_title, choices) => {
1832
- const projectAgent = choices.find((choice) => choice.startsWith("worker [project]"));
1833
- if (projectAgent) return projectAgent;
1834
- assert.ok(choices.includes("bluebox-azure-openai/gpt-5_6-sol"));
1835
- return "bluebox-azure-openai/gpt-5_6-sol";
1836
- },
1837
- }));
1838
-
1839
- const updated = fs.readFileSync(agentPath, "utf-8");
1840
- assert.match(updated, /^model: bluebox-azure-openai\/gpt-5_6-sol$/m);
1841
- assert.doesNotMatch(updated, /^thinking:/m);
1842
- assert.doesNotMatch(updated, /^systemPromptMode:/m);
1843
- assert.doesNotMatch(updated, /^inheritProjectContext:/m);
1844
- assert.equal(JSON.parse(fs.readFileSync(settingsPath, "utf-8")).subagents.agentOverrides.worker.thinking, "high");
1845
- });
1846
- });
1847
- });
1848
-
1849
- it("does not write definitions from SELESAI_SUBAGENT_EXTRA_AGENT_DIRS", async () => {
1850
- await withIsolatedHome(async () => {
1851
- await withTempProject("pi-subagents-admin-extra-", async (root) => {
1852
- const extraDir = path.join(root, "extra-agents");
1853
- const agentPath = path.join(extraDir, "worker.md");
1854
- fs.mkdirSync(extraDir, { recursive: true });
1855
- const original = "---\nname: worker\ndescription: Read-only worker\nmodel: anthropic/claude-sonnet-4-6\n---\n\nDo work.\n";
1856
- fs.writeFileSync(agentPath, original, "utf-8");
1857
- const previousExtraDirs = process.env.SELESAI_SUBAGENT_EXTRA_AGENT_DIRS;
1858
- process.env.SELESAI_SUBAGENT_EXTRA_AGENT_DIRS = extraDir;
1859
- try {
1860
- const commands = registerAdmin([]);
1861
- await commands.get("subagents")!.handler("worker model", createCommandContext({
1862
- cwd: root,
1863
- hasUI: true,
1864
- modelRegistry: { getAvailable: () => [{ provider: "bluebox-azure-openai", id: "gpt-5_6-sol", reasoning: true }] },
1865
- select: async (_title, choices) =>
1866
- choices.find((choice) => choice.startsWith("worker [user]"))
1867
- ?? "bluebox-azure-openai/gpt-5_6-sol",
1868
- }));
1869
- assert.equal(fs.readFileSync(agentPath, "utf-8"), original);
1870
- } finally {
1871
- if (previousExtraDirs === undefined) delete process.env.SELESAI_SUBAGENT_EXTRA_AGENT_DIRS;
1872
- else process.env.SELESAI_SUBAGENT_EXTRA_AGENT_DIRS = previousExtraDirs;
1873
- }
1874
- });
1875
- });
1876
- });
1877
-
1878
- it("respects package-owned fields and uses settings only for unset package fields", async () => {
1879
- await withIsolatedHome(async () => {
1880
- await withTempProject("pi-subagents-admin-package-", async (root) => {
1881
- const packageRoot = path.join(root, ".selesai", "npm", "node_modules", "admin-package");
1882
- const agentPath = path.join(packageRoot, "agents", "package-admin-agent.md");
1883
- fs.mkdirSync(path.dirname(agentPath), { recursive: true });
1884
- fs.writeFileSync(path.join(packageRoot, "package.json"), JSON.stringify({
1885
- name: "admin-package",
1886
- "pi-subagents": { agents: ["./agents"] },
1887
- }), "utf-8");
1888
- const original = "---\nname: package-admin-agent\ndescription: Package agent\nmodel: test/original\n---\n\nPackage prompt.\n";
1889
- fs.writeFileSync(agentPath, original, "utf-8");
1890
- const settingsPath = path.join(root, ".selesai", "settings.json");
1891
- fs.writeFileSync(settingsPath, JSON.stringify({
1892
- subagents: { agentOverrides: { "package-admin-agent": { thinking: "low" } } },
1893
- }, null, 2), "utf-8");
1894
-
1895
- const sent: unknown[] = [];
1896
- const commands = registerAdmin(sent);
1897
- await commands.get("subagents")!.handler("package-admin-agent model", createCommandContext({
1898
- cwd: root,
1899
- hasUI: true,
1900
- modelRegistry: { getAvailable: () => [{ provider: "test", id: "replacement", reasoning: true }] },
1901
- select: async () => "test/replacement",
1902
- }));
1903
- await commands.get("subagents")!.handler("package-admin-agent prompt", createCommandContext({
1904
- cwd: root,
1905
- hasUI: true,
1906
- }));
1907
-
1908
- assert.equal(fs.readFileSync(agentPath, "utf-8"), original);
1909
- assert.deepEqual(JSON.parse(fs.readFileSync(settingsPath, "utf-8")).subagents.agentOverrides, {
1910
- "package-admin-agent": { thinking: "low" },
1911
- });
1912
- assert.match((sent[0] as { content?: string }).content ?? "", /model.*read-only package definition/);
1913
- assert.match((sent[1] as { content?: string }).content ?? "", /systemPrompt.*read-only package definition/);
1914
-
1915
- const configurablePath = path.join(packageRoot, "agents", "configurable-package-agent.md");
1916
- const configurable = "---\nname: configurable-package-agent\ndescription: Configurable package agent\n---\n\nPackage prompt.\n";
1917
- fs.writeFileSync(configurablePath, configurable, "utf-8");
1918
- await commands.get("subagents")!.handler("configurable-package-agent model", createCommandContext({
1919
- cwd: root,
1920
- hasUI: true,
1921
- modelRegistry: { getAvailable: () => [{ provider: "test", id: "replacement", reasoning: true }] },
1922
- select: async (title) => title.startsWith("Select model") ? "test/replacement" : "project",
1923
- }));
1924
- assert.equal(fs.readFileSync(configurablePath, "utf-8"), configurable);
1925
- assert.deepEqual(JSON.parse(fs.readFileSync(settingsPath, "utf-8")).subagents.agentOverrides, {
1926
- "package-admin-agent": { thinking: "low" },
1927
- "configurable-package-agent": { model: "test/replacement" },
1928
- });
1929
- });
1930
- });
1931
- });
1932
-
1933
- it("edits a system prompt through Pi's native editor", async () => {
1934
- await withIsolatedHome(async () => {
1935
- await withTempProject("pi-subagents-admin-prompt-", async (root) => {
1936
- const agentPath = path.join(root, ".selesai", "agents", "worker.md");
1937
- fs.writeFileSync(agentPath, `---\nname: worker\ndescription: Test worker\n---\n\nOriginal prompt.\n`, "utf-8");
1938
- const status: Array<[string, string | undefined]> = [];
1939
- let editorArgs: [string, string] | undefined;
1940
- const commands = registerAdmin([]);
1941
- await commands.get("subagents")!.handler("worker prompt", createCommandContext({
1942
- cwd: root,
1943
- hasUI: true,
1944
- select: async (_title, choices) => choices.find((choice) => choice.startsWith("worker [project]")),
1945
- editor: async (title, prefill) => {
1946
- editorArgs = [title, prefill];
1947
- return "Edited prompt.\n";
1948
- },
1949
- setStatus: (key, text) => status.push([key, text]),
1950
- }));
1951
- assert.deepEqual(editorArgs, ["Edit 'worker' system prompt", "Original prompt."]);
1952
- assert.match(fs.readFileSync(agentPath, "utf-8"), /Edited prompt\./);
1953
- assert.deepEqual(status, []);
1954
- });
1955
- });
1956
- });
1957
-
1958
- it("cancels native system-prompt editing without mutation", async () => {
1959
- await withIsolatedHome(async () => {
1960
- await withTempProject("pi-subagents-admin-prompt-cancel-", async (root) => {
1961
- const agentPath = path.join(root, ".selesai", "agents", "worker.md");
1962
- const original = `---\nname: worker\ndescription: Test worker\n---\n\nOriginal prompt.\n`;
1963
- fs.writeFileSync(agentPath, original, "utf-8");
1964
- const sent: unknown[] = [];
1965
- const commands = registerAdmin(sent);
1966
- await commands.get("subagents")!.handler("worker prompt", createCommandContext({
1967
- cwd: root,
1968
- hasUI: true,
1969
- select: async (_title, choices) => choices.find((choice) => choice.startsWith("worker [project]")),
1970
- editor: async () => undefined,
1971
- }));
1972
- assert.equal(fs.readFileSync(agentPath, "utf-8"), original);
1973
- assert.deepEqual(sent, []);
1974
- });
1975
- });
1976
- });
1977
-
1978
- it("reports native-editor failures without rewriting the agent", async () => {
1979
- await withIsolatedHome(async () => {
1980
- await withTempProject("pi-subagents-admin-editor-failure-", async (root) => {
1981
- const agentPath = path.join(root, ".selesai", "agents", "worker.md");
1982
- const original = `---\nname: worker\ndescription: Test worker\n---\n\nOriginal prompt.\n`;
1983
- fs.writeFileSync(agentPath, original, "utf-8");
1984
- const sent: unknown[] = [];
1985
- const commands = registerAdmin(sent);
1986
- await commands.get("subagents")!.handler("worker prompt", createCommandContext({
1987
- cwd: root,
1988
- hasUI: true,
1989
- select: async (_title, choices) => choices.find((choice) => choice.startsWith("worker [project]")),
1990
- editor: async () => { throw new Error("editor unavailable"); },
1991
- }));
1992
- assert.equal(fs.readFileSync(agentPath, "utf-8"), original);
1993
- assert.match((sent.at(-1) as { content?: string }).content ?? "", /Failed to update 'worker': editor unavailable/);
1994
- });
1995
- });
1996
- });
1997
-
1998
- it("shows metadata for a named subagent without requiring UI", async () => {
1999
- await withIsolatedHome(async () => {
2000
- await withTempProject("pi-subagents-admin-metadata-", async (root) => {
2001
- fs.writeFileSync(path.join(root, ".selesai", "agents", "auditor.md"), `---\nname: auditor\ndescription: Audit things\nthinking: false\n---\n\nAudit.\n`, "utf-8");
2002
- const sent: unknown[] = [];
2003
- const commands = registerAdmin(sent);
2004
- await commands.get("subagents")!.handler("auditor", createCommandContext({ cwd: root }));
2005
- assert.equal(sent.length, 1);
2006
- const content = (sent[0] as { content?: string }).content ?? "";
2007
- assert.match(content, /Agent: auditor \(project\)/);
2008
- assert.match(content, /^Thinking: off$/m);
2009
- });
2010
- });
2011
- });
2012
- });
2013
-
2014
-
2015
- describe("subagents-doctor slash command", { skip: !available ? "slash-commands.ts not importable" : undefined }, () => {
2016
- beforeEach(() => {
2017
- clearSlashSnapshots?.();
2018
- });
2019
-
2020
- it("routes to the doctor tool action", async () => {
2021
- const { params } = await captureSlashCommandParams("subagents-doctor", "", process.cwd());
2022
- assert.deepEqual(params, { action: "doctor" });
2023
- });
2024
-
2025
- it("keeps the textual fleet status fallback when no UI is available", async () => {
2026
- const { params } = await captureSlashCommandParams("subagents-fleet", "", process.cwd());
2027
- assert.deepEqual(params, { action: "status", view: "fleet" });
2028
- });
2029
-
2030
- it("opens the native fleet from both the slash command and direct shortcut", async () => {
2031
- const commands = new Map<string, RegisteredSlashCommand>();
2032
- const shortcuts = new Map<string, { description: string; handler(ctx: unknown): Promise<void> }>();
2033
- let opened = 0;
2034
- let rendered = "";
2035
- const custom = async (factory: unknown, options: unknown) => {
2036
- opened++;
2037
- const component = (factory as (tui: unknown, theme: unknown, keybindings: unknown, done: (value: undefined) => void) => { render(width: number): string[]; dispose(): void })(
2038
- { terminal: { rows: 30, columns: 100 }, requestRender() {} },
2039
- { fg: (_name: string, text: string) => text, bold: (text: string) => text },
2040
- undefined,
2041
- () => {},
2042
- );
2043
- rendered = component.render(100).join("\n");
2044
- component.dispose();
2045
- assert.equal(options, undefined);
2046
- return undefined;
2047
- };
2048
- const pi = {
2049
- events: createEventBus(),
2050
- registerCommand(name: string, spec: RegisteredSlashCommand) { commands.set(name, spec); },
2051
- registerShortcut(key: string, spec: { description: string; handler(ctx: unknown): Promise<void> }) { shortcuts.set(key, spec); },
2052
- sendMessage(_message: unknown) {},
2053
- };
2054
- const state = createState(process.cwd());
2055
- const ctx = createCommandContext({ hasUI: true, custom });
2056
- registerSlashCommands!(pi, state);
2057
-
2058
- await commands.get("subagents-fleet")!.handler("", ctx);
2059
- assert.equal(shortcuts.size, 1);
2060
- const shortcut = [...shortcuts.values()][0]!;
2061
- assert.equal(shortcut.description, "Open subagent fleet inspector");
2062
- await shortcut.handler(ctx);
2063
-
2064
- assert.equal(opened, 2);
2065
- assert.match(rendered, /Subagent fleet/);
2066
- assert.match(rendered, /live controls/);
2067
- });
2068
-
2069
- it("routes subagents-stop with an id directly to the stop action", async () => {
2070
- const { params } = await captureSlashCommandParams("subagents-stop", "run-123", process.cwd());
2071
- assert.deepEqual(params, { action: "stop", id: "run-123" });
2072
- });
2073
-
2074
- it("detaches the latest active foreground single run without terminating it", async () => {
2075
- const commands = new Map<string, RegisteredSlashCommand>();
2076
- const sent: unknown[] = [];
2077
- const state = createState(process.cwd());
2078
- let detached = 0;
2079
- state.foregroundControls.set("foreground-single", {
2080
- runId: "foreground-single",
2081
- mode: "single",
2082
- startedAt: 1,
2083
- updatedAt: 2,
2084
- detach: () => { detached++; return true; },
2085
- });
2086
- state.foregroundControls.set("newer-parallel", {
2087
- runId: "newer-parallel",
2088
- mode: "parallel",
2089
- startedAt: 2,
2090
- updatedAt: 3,
2091
- });
2092
- state.lastForegroundControlId = "newer-parallel";
709
+ it("does not register legacy orchestration commands", async () => {
710
+ const commands = new Map<string, unknown>();
2093
711
  registerSlashCommands!({
2094
- events: createEventBus(),
2095
- registerCommand(name: string, spec: RegisteredSlashCommand) { commands.set(name, spec); },
712
+ registerCommand(name: string, command: unknown) { commands.set(name, command); },
2096
713
  registerShortcut() {},
2097
- sendMessage(message: unknown) { sent.push(message); },
2098
- }, state);
2099
-
2100
- await commands.get("subagents-detach")!.handler("", createCommandContext());
2101
-
2102
- assert.equal(detached, 1);
2103
- const content = String((sent[0] as { content?: unknown }).content ?? "");
2104
- assert.match(content, /Detached foreground run foreground-single without terminating its child/);
2105
- assert.match(content, /does not daemonize the process or guarantee survival across Pi reload\/restart/);
2106
- });
2107
-
2108
- it("reports missing and unsupported foreground detach targets", async () => {
2109
- const commands = new Map<string, RegisteredSlashCommand>();
2110
- const notifications: string[] = [];
2111
- const state = createState(process.cwd());
2112
- state.foregroundControls.set("parallel-run", {
2113
- runId: "parallel-run",
2114
- mode: "parallel",
2115
- startedAt: 1,
2116
- updatedAt: 1,
2117
- detach: () => true,
2118
- });
2119
- registerSlashCommands!({
2120
714
  events: createEventBus(),
2121
- registerCommand(name: string, spec: RegisteredSlashCommand) { commands.set(name, spec); },
2122
- registerShortcut() {},
2123
- sendMessage() {},
2124
- }, state);
2125
- const ctx = createCommandContext({ notify: (message) => notifications.push(message) });
2126
-
2127
- await commands.get("subagents-detach")!.handler("missing", ctx);
2128
- await commands.get("subagents-detach")!.handler("parallel", ctx);
2129
-
2130
- assert.match(notifications[0] ?? "", /No active foreground run found for 'missing'/);
2131
- assert.match(notifications[1] ?? "", /currently supports single-subagent runs only/);
2132
- });
2133
-
2134
- it("prints exact stop commands when subagents-stop has no UI", async () => {
2135
- await withIsolatedHome(async () => {
2136
- const runId = `slash-stop-${Date.now().toString(36)}`;
2137
- const asyncDir = path.join(ASYNC_DIR, runId);
2138
- fs.mkdirSync(asyncDir, { recursive: true });
2139
- fs.writeFileSync(path.join(asyncDir, "status.json"), JSON.stringify({
2140
- runId,
2141
- sessionId: "session-test",
2142
- mode: "single",
2143
- state: "running",
2144
- pid: process.pid,
2145
- startedAt: Date.now(),
2146
- lastUpdate: Date.now(),
2147
- steps: [{ agent: "worker", status: "running", startedAt: Date.now() }],
2148
- }, null, 2));
2149
- try {
2150
- const sent: unknown[] = [];
2151
- const commands = new Map<string, RegisteredSlashCommand>();
2152
- const pi = {
2153
- events: createEventBus(),
2154
- registerCommand(name: string, spec: RegisteredSlashCommand) { commands.set(name, spec); },
2155
- registerShortcut() {},
2156
- sendMessage(message: unknown) { sent.push(message); },
2157
- };
2158
- const state = createState(process.cwd());
2159
- state.currentSessionId = "session-test";
2160
- registerSlashCommands!(pi, state);
2161
- await commands.get("subagents-stop")!.handler("", createCommandContext({ hasUI: false }));
2162
-
2163
- const content = String((sent[0] as { content?: unknown }).content ?? "");
2164
- assert.match(content, new RegExp(`subagent\\({ action: "stop", id: "${runId}" }\\)`));
2165
- assert.match(content, new RegExp(`/subagents-stop ${runId}`));
2166
- } finally {
2167
- fs.rmSync(asyncDir, { recursive: true, force: true });
2168
- }
2169
- });
2170
- });
2171
-
2172
- it("prints cancel commands for scheduled subagent runs when subagents-stop has no UI", async () => {
2173
- await withIsolatedHome(async () => {
2174
- await withTempProject("pi-slash-stop-scheduled-", async (root) => {
2175
- const storePath = scheduledRunStorePath(root, "session-test");
2176
- fs.mkdirSync(path.dirname(storePath), { recursive: true });
2177
- fs.writeFileSync(storePath, JSON.stringify({
2178
- version: 1,
2179
- cwd: root,
2180
- sessionId: "session-test",
2181
- jobs: [{
2182
- id: "job-1",
2183
- name: "nightly scout",
2184
- schedule: "+10m",
2185
- runAt: Date.now() + 600_000,
2186
- state: "scheduled",
2187
- createdAt: Date.now(),
2188
- updatedAt: Date.now(),
2189
- cwd: root,
2190
- sessionId: "session-test",
2191
- params: { agent: "scout", task: "later", async: true },
2192
- }],
2193
- }, null, 2));
2194
- const sent: unknown[] = [];
2195
- const commands = new Map<string, RegisteredSlashCommand>();
2196
- const state = createState(root);
2197
- state.currentSessionId = "session-test";
2198
- const pi = {
2199
- events: createEventBus(),
2200
- registerCommand(name: string, spec: RegisteredSlashCommand) { commands.set(name, spec); },
2201
- registerShortcut() {},
2202
- sendMessage(message: unknown) { sent.push(message); },
2203
- };
2204
- registerSlashCommands!(pi, state);
2205
- await commands.get("subagents-stop")!.handler("", createCommandContext({ cwd: root, hasUI: false }));
2206
-
2207
- const content = String((sent[0] as { content?: unknown }).content ?? "");
2208
- assert.match(content, /job-1 · nightly scout/);
2209
- assert.match(content, /cancel scheduled run: subagent\({ action: "schedule-cancel", id: "job-1" }\)/);
2210
- assert.doesNotMatch(content, /\/subagents-stop job-1/);
2211
- });
2212
- });
715
+ } as never, { baseCwd: process.cwd() } as never);
716
+ assert.equal(commands.has("run"), true);
717
+ assert.equal(commands.has("chain"), false);
718
+ assert.equal(commands.has("parallel"), false);
719
+ assert.equal(commands.has("run-chain"), false);
2213
720
  });
2214
-
2215
- it("routes selected scheduled subagents-stop targets through schedule-cancel", async () => {
2216
- await withIsolatedHome(async () => {
2217
- await withTempProject("pi-slash-stop-selected-scheduled-", async (root) => {
2218
- const storePath = scheduledRunStorePath(root, "session-test");
2219
- fs.mkdirSync(path.dirname(storePath), { recursive: true });
2220
- fs.writeFileSync(storePath, JSON.stringify({
2221
- version: 1,
2222
- cwd: root,
2223
- sessionId: "session-test",
2224
- jobs: [{
2225
- id: "job-1",
2226
- name: "early scout",
2227
- schedule: "+5m",
2228
- runAt: Date.now() + 300_000,
2229
- state: "scheduled",
2230
- createdAt: Date.now(),
2231
- updatedAt: Date.now(),
2232
- cwd: root,
2233
- sessionId: "session-test",
2234
- params: { agent: "scout", task: "soon", async: true },
2235
- }, {
2236
- id: "job-2",
2237
- name: "delayed worker",
2238
- schedule: "+10m",
2239
- runAt: Date.now() + 600_000,
2240
- state: "scheduled",
2241
- createdAt: Date.now(),
2242
- updatedAt: Date.now(),
2243
- cwd: root,
2244
- sessionId: "session-test",
2245
- params: { agent: "worker", task: "later", async: true },
2246
- }],
2247
- }, null, 2));
2248
-
2249
- const commands = new Map<string, RegisteredSlashCommand>();
2250
- const events = createEventBus();
2251
- let requestedParams: unknown;
2252
- events.on(SLASH_SUBAGENT_REQUEST_EVENT, (data) => {
2253
- const payload = data as { requestId: string; params?: unknown };
2254
- requestedParams = payload.params;
2255
- events.emit(SLASH_SUBAGENT_STARTED_EVENT, { requestId: payload.requestId });
2256
- events.emit(SLASH_SUBAGENT_RESPONSE_EVENT, {
2257
- requestId: payload.requestId,
2258
- result: { content: [{ type: "text", text: "cancelled" }], details: { mode: "management", results: [] } },
2259
- isError: false,
2260
- });
2261
- });
2262
- const state = createState(root);
2263
- state.currentSessionId = "session-test";
2264
- const pi = {
2265
- events,
2266
- registerCommand(name: string, spec: RegisteredSlashCommand) { commands.set(name, spec); },
2267
- registerShortcut() {},
2268
- sendMessage(_message: unknown) {},
2269
- };
2270
- registerSlashCommands!(pi, state);
2271
- await commands.get("subagents-stop")!.handler("", createCommandContext({
2272
- cwd: root,
2273
- hasUI: true,
2274
- custom: async (...args: unknown[]) => new Promise((resolve) => {
2275
- const factory = args[0] as (
2276
- tui: { requestRender(): void },
2277
- theme: { fg(key: string, text: string): string; bold(text: string): string },
2278
- keybindings: unknown,
2279
- done: (result: unknown) => void,
2280
- ) => { handleInput(data: string): void; render(width: number): string[] };
2281
- const component = factory(
2282
- { requestRender() {} },
2283
- { fg(_key, text) { return text; }, bold(text) { return text; } },
2284
- {},
2285
- resolve,
2286
- );
2287
- assert.match(component.render(84).join("\n"), /↑↓\/jk select/);
2288
- component.handleInput("j");
2289
- assert.ok(component.render(84).some((line) => line.startsWith("›") && line.includes("job-2")));
2290
- component.handleInput("k");
2291
- assert.ok(component.render(84).some((line) => line.startsWith("›") && line.includes("job-1")));
2292
- component.handleInput("j");
2293
- component.handleInput("\r");
2294
- component.handleInput("y");
2295
- }),
2296
- }));
2297
-
2298
- assert.deepEqual(requestedParams, { action: "schedule-cancel", id: "job-2" });
2299
- });
2300
- });
2301
- });
2302
-
2303
- it("prints fallback text instead of opening or enumerating the selector in child-safe fanout mode", async () => {
2304
- await withIsolatedHome(async () => {
2305
- const previous = process.env[SUBAGENT_FANOUT_CHILD_ENV];
2306
- const runId = `slash-stop-child-safe-${Date.now().toString(36)}`;
2307
- const asyncDir = path.join(ASYNC_DIR, runId);
2308
- process.env[SUBAGENT_FANOUT_CHILD_ENV] = "1";
2309
- fs.mkdirSync(asyncDir, { recursive: true });
2310
- fs.writeFileSync(path.join(asyncDir, "status.json"), JSON.stringify({
2311
- runId,
2312
- sessionId: "session-test",
2313
- mode: "single",
2314
- state: "running",
2315
- pid: process.pid,
2316
- startedAt: Date.now(),
2317
- lastUpdate: Date.now(),
2318
- steps: [{ agent: "worker", status: "running", startedAt: Date.now() }],
2319
- }, null, 2));
2320
- try {
2321
- const sent: unknown[] = [];
2322
- const commands = new Map<string, RegisteredSlashCommand>();
2323
- const pi = {
2324
- events: createEventBus(),
2325
- registerCommand(name: string, spec: RegisteredSlashCommand) { commands.set(name, spec); },
2326
- registerShortcut() {},
2327
- sendMessage(message: unknown) { sent.push(message); },
2328
- };
2329
- const state = createState(process.cwd());
2330
- state.currentSessionId = "session-test";
2331
- registerSlashCommands!(pi, state);
2332
- await commands.get("subagents-stop")!.handler("", createCommandContext({ hasUI: true }));
2333
-
2334
- const content = String((sent[0] as { content?: unknown }).content ?? "");
2335
- assert.match(content, /Selector unavailable in child-safe fanout mode\./);
2336
- assert.doesNotMatch(content, new RegExp(runId));
2337
- } finally {
2338
- fs.rmSync(asyncDir, { recursive: true, force: true });
2339
- if (previous === undefined) delete process.env[SUBAGENT_FANOUT_CHILD_ENV];
2340
- else process.env[SUBAGENT_FANOUT_CHILD_ENV] = previous;
2341
- }
2342
- });
2343
- });
2344
-
2345
- it("does not register the removed subagents-status overlay command", async () => {
2346
- await withIsolatedHome(async () => {
2347
- const commands = new Map<string, RegisteredSlashCommand>();
2348
- const pi = {
2349
- events: createEventBus(),
2350
- registerCommand(name: string, spec: RegisteredSlashCommand) {
2351
- commands.set(name, spec);
2352
- },
2353
- registerShortcut() {},
2354
- sendMessage(_message: unknown) {},
2355
- };
2356
-
2357
- registerSlashCommands!(pi, createState(process.cwd()));
2358
- assert.equal(commands.has("subagents-status"), false);
2359
- });
2360
- });
2361
-
2362
721
  });