@selesai/code 0.5.28 → 0.6.1

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 (341) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +1 -1
  3. package/dist/cli/args.d.ts.map +1 -1
  4. package/dist/cli/args.js +9 -1
  5. package/dist/cli/args.js.map +1 -1
  6. package/dist/cli/config-selector.d.ts.map +1 -1
  7. package/dist/cli/config-selector.js +1 -1
  8. package/dist/cli/config-selector.js.map +1 -1
  9. package/dist/cli/credential-print.d.ts +23 -0
  10. package/dist/cli/credential-print.d.ts.map +1 -0
  11. package/dist/cli/credential-print.js +117 -0
  12. package/dist/cli/credential-print.js.map +1 -0
  13. package/dist/cli/startup-ui.d.ts.map +1 -1
  14. package/dist/cli/startup-ui.js +1 -1
  15. package/dist/cli/startup-ui.js.map +1 -1
  16. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  17. package/dist/core/agent-session-runtime.js +3 -0
  18. package/dist/core/agent-session-runtime.js.map +1 -1
  19. package/dist/core/agent-session.d.ts +12 -1
  20. package/dist/core/agent-session.d.ts.map +1 -1
  21. package/dist/core/agent-session.js +20 -14
  22. package/dist/core/agent-session.js.map +1 -1
  23. package/dist/core/compaction/compaction.d.ts.map +1 -1
  24. package/dist/core/compaction/compaction.js +11 -3
  25. package/dist/core/compaction/compaction.js.map +1 -1
  26. package/dist/core/extensions/runner.d.ts +1 -0
  27. package/dist/core/extensions/runner.d.ts.map +1 -1
  28. package/dist/core/extensions/runner.js +11 -0
  29. package/dist/core/extensions/runner.js.map +1 -1
  30. package/dist/core/extensions/types.d.ts +14 -1
  31. package/dist/core/extensions/types.d.ts.map +1 -1
  32. package/dist/core/extensions/types.js.map +1 -1
  33. package/dist/core/footer-data-provider.d.ts +10 -0
  34. package/dist/core/footer-data-provider.d.ts.map +1 -1
  35. package/dist/core/footer-data-provider.js +1 -1
  36. package/dist/core/footer-data-provider.js.map +1 -1
  37. package/dist/core/llama/provider.d.ts.map +1 -1
  38. package/dist/core/llama/provider.js +8 -3
  39. package/dist/core/llama/provider.js.map +1 -1
  40. package/dist/core/model-config.d.ts +30 -0
  41. package/dist/core/model-config.d.ts.map +1 -1
  42. package/dist/core/model-config.js +6 -0
  43. package/dist/core/model-config.js.map +1 -1
  44. package/dist/core/model-registry.d.ts.map +1 -1
  45. package/dist/core/model-registry.js +2 -2
  46. package/dist/core/model-registry.js.map +1 -1
  47. package/dist/core/model-resolver.d.ts +1 -0
  48. package/dist/core/model-resolver.d.ts.map +1 -1
  49. package/dist/core/model-resolver.js +20 -3
  50. package/dist/core/model-resolver.js.map +1 -1
  51. package/dist/core/model-runtime.d.ts +2 -0
  52. package/dist/core/model-runtime.d.ts.map +1 -1
  53. package/dist/core/model-runtime.js +5 -4
  54. package/dist/core/model-runtime.js.map +1 -1
  55. package/dist/core/package-manager.d.ts.map +1 -1
  56. package/dist/core/package-manager.js +13 -6
  57. package/dist/core/package-manager.js.map +1 -1
  58. package/dist/core/remote-catalog-provider.d.ts +1 -1
  59. package/dist/core/remote-catalog-provider.d.ts.map +1 -1
  60. package/dist/core/remote-catalog-provider.js +24 -11
  61. package/dist/core/remote-catalog-provider.js.map +1 -1
  62. package/dist/core/resource-loader.d.ts +15 -0
  63. package/dist/core/resource-loader.d.ts.map +1 -1
  64. package/dist/core/resource-loader.js +66 -9
  65. package/dist/core/resource-loader.js.map +1 -1
  66. package/dist/core/settings-manager.d.ts +1 -1
  67. package/dist/core/settings-manager.d.ts.map +1 -1
  68. package/dist/core/settings-manager.js.map +1 -1
  69. package/dist/core/system-prompt.d.ts.map +1 -1
  70. package/dist/core/system-prompt.js +19 -1
  71. package/dist/core/system-prompt.js.map +1 -1
  72. package/dist/core/system-prompt.test.d.ts +2 -0
  73. package/dist/core/system-prompt.test.d.ts.map +1 -0
  74. package/dist/core/system-prompt.test.js +89 -0
  75. package/dist/core/system-prompt.test.js.map +1 -0
  76. package/dist/core/tools/bash.d.ts +2 -0
  77. package/dist/core/tools/bash.d.ts.map +1 -1
  78. package/dist/core/tools/bash.js +34 -5
  79. package/dist/core/tools/bash.js.map +1 -1
  80. package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
  81. package/dist/core/tools/tool-definition-wrapper.js +3 -1
  82. package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
  83. package/dist/defaults/models.json +13 -45
  84. package/dist/defaults/settings.json +1 -2
  85. package/dist/extensions/copy-turn.test.ts +131 -0
  86. package/dist/extensions/copy-turn.ts +6 -1
  87. package/dist/extensions/package.json +0 -1
  88. package/dist/extensions/pi-intercom/CHANGELOG.md +249 -0
  89. package/dist/extensions/pi-intercom/README.md +102 -39
  90. package/dist/extensions/pi-intercom/broker/broker.ts +1233 -36
  91. package/dist/extensions/pi-intercom/broker/client.test.ts +83 -0
  92. package/dist/extensions/pi-intercom/broker/client.ts +315 -12
  93. package/dist/extensions/pi-intercom/broker/extension-state.ts +186 -0
  94. package/dist/extensions/pi-intercom/broker/extension.test.ts +387 -0
  95. package/dist/extensions/pi-intercom/broker/framing.test.ts +114 -0
  96. package/dist/extensions/pi-intercom/broker/framing.ts +82 -24
  97. package/dist/extensions/pi-intercom/broker/paths.test.ts +153 -0
  98. package/dist/extensions/pi-intercom/broker/paths.ts +117 -8
  99. package/dist/extensions/pi-intercom/broker/runtime-claim.test.ts +34 -0
  100. package/dist/extensions/pi-intercom/broker/runtime-claim.ts +21 -0
  101. package/dist/extensions/pi-intercom/broker/spawn.test.ts +160 -23
  102. package/dist/extensions/pi-intercom/broker/spawn.ts +113 -27
  103. package/dist/extensions/pi-intercom/config.test.ts +93 -0
  104. package/dist/extensions/pi-intercom/config.ts +55 -6
  105. package/dist/extensions/pi-intercom/cwd.test.ts +40 -0
  106. package/dist/extensions/pi-intercom/cwd.ts +31 -0
  107. package/dist/extensions/pi-intercom/extension-api.ts +44 -0
  108. package/dist/extensions/pi-intercom/format-context.test.ts +31 -0
  109. package/dist/extensions/pi-intercom/format-context.ts +32 -0
  110. package/dist/extensions/pi-intercom/index.ts +742 -145
  111. package/dist/extensions/pi-intercom/intercom.integration.test.ts +2646 -0
  112. package/dist/extensions/pi-intercom/package.json +15 -5
  113. package/dist/extensions/pi-intercom/reply-tracker.test.ts +134 -0
  114. package/dist/extensions/pi-intercom/reply-tracker.ts +31 -13
  115. package/dist/extensions/pi-intercom/skills/pi-intercom/SKILL.md +13 -11
  116. package/dist/extensions/pi-intercom/test/inline-message.test.ts +184 -0
  117. package/dist/extensions/pi-intercom/test/overlay-width.test.ts +66 -0
  118. package/dist/extensions/pi-intercom/types.ts +94 -4
  119. package/dist/extensions/pi-intercom/ui/compose.ts +8 -4
  120. package/dist/extensions/pi-intercom/ui/inline-message.ts +61 -25
  121. package/dist/extensions/pi-intercom/ui/session-list.ts +7 -3
  122. package/dist/extensions/pi-subagents/CHANGELOG.md +88 -0
  123. package/dist/extensions/pi-subagents/LICENSE +21 -0
  124. package/dist/extensions/pi-subagents/README.md +158 -69
  125. package/dist/extensions/pi-subagents/agents/architect.md +5 -4
  126. package/dist/extensions/pi-subagents/agents/builder.md +6 -4
  127. package/dist/extensions/pi-subagents/agents/commentator.md +3 -2
  128. package/dist/extensions/pi-subagents/agents/explorer.md +3 -2
  129. package/dist/extensions/pi-subagents/agents/recapper.md +3 -2
  130. package/dist/extensions/pi-subagents/agents/researcher.md +4 -3
  131. package/dist/extensions/pi-subagents/package-lock.json +2 -2
  132. package/dist/extensions/pi-subagents/package.json +3 -3
  133. package/dist/extensions/pi-subagents/prompts/review-loop.md +1 -1
  134. package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +22 -988
  135. package/dist/extensions/pi-subagents/skills/pi-subagents/references/constraints-and-recipes.md +257 -0
  136. package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +431 -0
  137. package/dist/extensions/pi-subagents/skills/pi-subagents/references/management-authoring-rpc.md +144 -0
  138. package/dist/extensions/pi-subagents/skills/pi-subagents/references/prompting-and-roles.md +281 -0
  139. package/dist/extensions/pi-subagents/src/agents/agent-management.ts +125 -37
  140. package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +4 -0
  141. package/dist/extensions/pi-subagents/src/agents/agents.ts +118 -9
  142. package/dist/extensions/pi-subagents/src/agents/skills.ts +14 -12
  143. package/dist/extensions/pi-subagents/src/agents/task-aware-routing.ts +125 -0
  144. package/dist/extensions/pi-subagents/src/api/delegation.ts +3 -0
  145. package/dist/extensions/pi-subagents/src/api/preflight.ts +17 -13
  146. package/dist/extensions/pi-subagents/src/extension/chain-validation.ts +17 -1
  147. package/dist/extensions/pi-subagents/src/extension/index.ts +22 -8
  148. package/dist/extensions/pi-subagents/src/extension/rpc.ts +248 -6
  149. package/dist/extensions/pi-subagents/src/extension/schemas.ts +33 -8
  150. package/dist/extensions/pi-subagents/src/extension/tool-description.ts +32 -14
  151. package/dist/extensions/pi-subagents/src/intercom/intercom-bridge.ts +9 -4
  152. package/dist/extensions/pi-subagents/src/intercom/result-intercom.ts +33 -4
  153. package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +86 -21
  154. package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +24 -13
  155. package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +7 -5
  156. package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +18 -2
  157. package/dist/extensions/pi-subagents/src/runs/background/chain-append.ts +48 -5
  158. package/dist/extensions/pi-subagents/src/runs/background/control-channel.ts +68 -1
  159. package/dist/extensions/pi-subagents/src/runs/background/notify.ts +56 -5
  160. package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +92 -11
  161. package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +29 -3
  162. package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +388 -29
  163. package/dist/extensions/pi-subagents/src/runs/foreground/async-stop-action.ts +65 -0
  164. package/dist/extensions/pi-subagents/src/runs/foreground/chain-clarify.ts +3 -3
  165. package/dist/extensions/pi-subagents/src/runs/foreground/chain-execution.ts +214 -60
  166. package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +546 -252
  167. package/dist/extensions/pi-subagents/src/runs/foreground/foreground-control.ts +42 -0
  168. package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +553 -154
  169. package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +19 -13
  170. package/dist/extensions/pi-subagents/src/runs/shared/capability-ceiling.ts +51 -19
  171. package/dist/extensions/pi-subagents/src/runs/shared/chain-outputs.ts +3 -1
  172. package/dist/extensions/pi-subagents/src/runs/shared/dynamic-fanout.ts +1 -1
  173. package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +44 -11
  174. package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +8 -0
  175. package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +97 -20
  176. package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +43 -12
  177. package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +52 -4
  178. package/dist/extensions/pi-subagents/src/runs/shared/process-signal.ts +19 -0
  179. package/dist/extensions/pi-subagents/src/runs/shared/run-history.ts +45 -9
  180. package/dist/extensions/pi-subagents/src/runs/shared/runtime-acknowledged-extensions.ts +71 -0
  181. package/dist/extensions/pi-subagents/src/runs/shared/single-output.ts +63 -9
  182. package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +31 -1
  183. package/dist/extensions/pi-subagents/src/runs/shared/subagent-startup-retry.ts +101 -0
  184. package/dist/extensions/pi-subagents/src/runs/shared/task-intent.ts +22 -1
  185. package/dist/extensions/pi-subagents/src/runs/shared/usage-budget.ts +65 -0
  186. package/dist/extensions/pi-subagents/src/runs/shared/workflow-graph.ts +26 -1
  187. package/dist/extensions/pi-subagents/src/shared/settings.ts +17 -1
  188. package/dist/extensions/pi-subagents/src/shared/types.ts +196 -12
  189. package/dist/extensions/pi-subagents/src/shared/utils.ts +102 -5
  190. package/dist/extensions/pi-subagents/src/slash/delegation-adapters.ts +10 -1
  191. package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +46 -4
  192. package/dist/extensions/pi-subagents/src/slash/slash-live-state.ts +5 -3
  193. package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +87 -24
  194. package/dist/extensions/pi-subagents/src/tui/fleet.ts +182 -9
  195. package/dist/extensions/pi-subagents/src/tui/render.ts +55 -34
  196. package/dist/extensions/pi-subagents/src/watchdog/register-main.ts +14 -7
  197. package/dist/extensions/pi-subagents/src/watchdog/review.ts +5 -4
  198. package/dist/extensions/pi-subagents/src/watchdog/runtime.ts +170 -17
  199. package/dist/extensions/pi-subagents/src/watchdog/scope.ts +62 -0
  200. package/dist/extensions/pi-subagents/src/watchdog/settings.ts +41 -1
  201. package/dist/extensions/pi-subagents/src/watchdog/types.ts +10 -0
  202. package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +113 -8
  203. package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +419 -47
  204. package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +84 -0
  205. package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +4 -2
  206. package/dist/extensions/pi-subagents/test/integration/chain-clarify.test.ts +51 -2
  207. package/dist/extensions/pi-subagents/test/integration/chain-execution.test.ts +62 -22
  208. package/dist/extensions/pi-subagents/test/integration/detect-error.test.ts +48 -0
  209. package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +8 -6
  210. package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +231 -19
  211. package/dist/extensions/pi-subagents/test/integration/parallel-execution.test.ts +48 -7
  212. package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +44 -0
  213. package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +199 -17
  214. package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +898 -16
  215. package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +112 -23
  216. package/dist/extensions/pi-subagents/test/support/mock-pi-script.mjs +17 -5
  217. package/dist/extensions/pi-subagents/test/support/mock-pi.ts +2 -0
  218. package/dist/extensions/pi-subagents/test/support/real-session-runner.ts +18 -2
  219. package/dist/extensions/pi-subagents/test/support/register-loader.mjs +3 -3
  220. package/dist/extensions/pi-subagents/test/unit/acceptance.test.ts +3 -1
  221. package/dist/extensions/pi-subagents/test/unit/agent-disabled.test.ts +1 -1
  222. package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +198 -6
  223. package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +161 -1
  224. package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +47 -2
  225. package/dist/extensions/pi-subagents/test/unit/async-recovery-descriptor.test.ts +60 -0
  226. package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +8 -0
  227. package/dist/extensions/pi-subagents/test/unit/builtin-agent-documentation.test.ts +63 -0
  228. package/dist/extensions/pi-subagents/test/unit/capability-ceiling-agent-allowlist.test.ts +136 -0
  229. package/dist/extensions/pi-subagents/test/unit/capability-ceiling.test.ts +1 -1
  230. package/dist/extensions/pi-subagents/test/unit/chain-append.test.ts +6 -0
  231. package/dist/extensions/pi-subagents/test/unit/chain-validation.test.ts +1 -1
  232. package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +48 -48
  233. package/dist/extensions/pi-subagents/test/unit/config-dir-runtime.test.ts +23 -0
  234. package/dist/extensions/pi-subagents/test/unit/control-channel.test.ts +27 -0
  235. package/dist/extensions/pi-subagents/test/unit/delegation-api.test.ts +28 -2
  236. package/dist/extensions/pi-subagents/test/unit/dynamic-fanout.test.ts +1 -0
  237. package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +176 -8
  238. package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +164 -5
  239. package/dist/extensions/pi-subagents/test/unit/foreground-control.test.ts +41 -1
  240. package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +17 -12
  241. package/dist/extensions/pi-subagents/test/unit/intercom-bridge.test.ts +18 -2
  242. package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +20 -1
  243. package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +30 -2
  244. package/dist/extensions/pi-subagents/test/unit/notify.test.ts +39 -2
  245. package/dist/extensions/pi-subagents/test/unit/parallel-utils.test.ts +22 -0
  246. package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +103 -0
  247. package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +18 -0
  248. package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +48 -0
  249. package/dist/extensions/pi-subagents/test/unit/render-helpers.test.ts +13 -1
  250. package/dist/extensions/pi-subagents/test/unit/result-intercom.test.ts +29 -4
  251. package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +223 -4
  252. package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +30 -0
  253. package/dist/extensions/pi-subagents/test/unit/runtime-acknowledged-extensions.test.ts +52 -0
  254. package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +46 -2
  255. package/dist/extensions/pi-subagents/test/unit/single-output.test.ts +91 -1
  256. package/dist/extensions/pi-subagents/test/unit/skills-fallback.test.ts +1 -1
  257. package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +1 -1
  258. package/dist/extensions/pi-subagents/test/unit/streamed-progress-bounds.test.ts +78 -0
  259. package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +41 -0
  260. package/dist/extensions/pi-subagents/test/unit/subagent-startup-retry.test.ts +77 -0
  261. package/dist/extensions/pi-subagents/test/unit/task-aware-routing.test.ts +213 -0
  262. package/dist/extensions/pi-subagents/test/unit/task-intent.test.ts +26 -1
  263. package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +61 -10
  264. package/dist/extensions/pi-subagents/test/unit/total-cost.test.ts +1 -0
  265. package/dist/extensions/pi-subagents/test/unit/watchdog-runtime.test.ts +210 -1
  266. package/dist/extensions/pi-subagents/test/unit/watchdog-scope.test.ts +33 -0
  267. package/dist/extensions/pi-subagents/test/unit/watchdog-settings.test.ts +32 -0
  268. package/dist/extensions/pi-subagents/test/unit/writer-budget-guidance.test.ts +1 -1
  269. package/dist/main.d.ts.map +1 -1
  270. package/dist/main.js +43 -0
  271. package/dist/main.js.map +1 -1
  272. package/dist/modes/interactive/components/custom-message.d.ts +3 -1
  273. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
  274. package/dist/modes/interactive/components/custom-message.js +10 -2
  275. package/dist/modes/interactive/components/custom-message.js.map +1 -1
  276. package/dist/modes/interactive/components/extension-editor.d.ts +1 -2
  277. package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
  278. package/dist/modes/interactive/components/extension-editor.js +16 -46
  279. package/dist/modes/interactive/components/extension-editor.js.map +1 -1
  280. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  281. package/dist/modes/interactive/components/model-selector.js +4 -1
  282. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  283. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  284. package/dist/modes/interactive/components/scoped-models-selector.js +22 -13
  285. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  286. package/dist/modes/interactive/external-editor.d.ts +12 -0
  287. package/dist/modes/interactive/external-editor.d.ts.map +1 -0
  288. package/dist/modes/interactive/external-editor.js +37 -0
  289. package/dist/modes/interactive/external-editor.js.map +1 -0
  290. package/dist/modes/interactive/interactive-mode.d.ts +1 -1
  291. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  292. package/dist/modes/interactive/interactive-mode.js +72 -64
  293. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  294. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  295. package/dist/modes/rpc/rpc-mode.js +14 -0
  296. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  297. package/dist/skills/ponytail/SKILL.md +1 -3
  298. package/dist/utils/clipboard.d.ts.map +1 -1
  299. package/dist/utils/clipboard.js +19 -8
  300. package/dist/utils/clipboard.js.map +1 -1
  301. package/dist/utils/version-check.d.ts.map +1 -1
  302. package/dist/utils/version-check.js +1 -1
  303. package/dist/utils/version-check.js.map +1 -1
  304. package/docs/compaction.md +1 -1
  305. package/docs/custom-provider.md +14 -5
  306. package/docs/environment-variables.md +86 -0
  307. package/docs/extensions.md +15 -5
  308. package/docs/index.md +1 -0
  309. package/docs/models.md +9 -2
  310. package/docs/plans/subagent-delegation/phase-0-correctness.md +265 -0
  311. package/docs/plans/subagent-delegation/phase-1-behavioral-contract.md +486 -0
  312. package/docs/plans/subagent-delegation/phase-2-context-controls.md +282 -0
  313. package/docs/plans/subagent-delegation/phase-3-advisory-routing.md +362 -0
  314. package/docs/plans/subagent-delegation/phase-4-optional-enforcement.md +381 -0
  315. package/docs/providers.md +21 -2
  316. package/docs/rpc.md +23 -6
  317. package/docs/session-format.md +2 -0
  318. package/docs/settings.md +1 -1
  319. package/docs/usage.md +0 -13
  320. package/examples/extensions/custom-compaction.ts +5 -2
  321. package/examples/extensions/custom-provider-anthropic/index.ts +9 -3
  322. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  323. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  324. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  325. package/examples/extensions/gondolin/package-lock.json +2 -2
  326. package/examples/extensions/gondolin/package.json +1 -1
  327. package/examples/extensions/handoff.ts +11 -3
  328. package/examples/extensions/message-renderer.ts +3 -3
  329. package/examples/extensions/sandbox/package-lock.json +2 -2
  330. package/examples/extensions/sandbox/package.json +1 -1
  331. package/examples/extensions/summarize.ts +5 -2
  332. package/examples/extensions/with-deps/package-lock.json +2 -2
  333. package/examples/extensions/with-deps/package.json +1 -1
  334. package/examples/sdk/12-full-control.ts +3 -1
  335. package/package.json +16 -7
  336. package/dist/extensions/caveman/caveman-instructions.cjs +0 -11
  337. package/dist/extensions/caveman/index.js +0 -118
  338. package/dist/extensions/caveman/package.json +0 -8
  339. package/dist/extensions/caveman/test/extension.test.js +0 -203
  340. package/dist/extensions/caveman/test/helpers.test.js +0 -58
  341. package/dist/skills/caveman/SKILL.md +0 -50
@@ -57,6 +57,7 @@ export function defaultInheritSkills(): boolean {
57
57
  }
58
58
 
59
59
  export interface BuiltinAgentOverrideBase {
60
+ description?: string;
60
61
  model?: string;
61
62
  fallbackModels?: string[];
62
63
  thinking?: string | false;
@@ -78,6 +79,7 @@ export interface BuiltinAgentOverrideBase {
78
79
  }
79
80
 
80
81
  interface BuiltinAgentOverrideConfig {
82
+ description?: string;
81
83
  model?: string | false;
82
84
  fallbackModels?: string[] | false;
83
85
  thinking?: string | false;
@@ -114,6 +116,7 @@ export interface AgentConfig {
114
116
  localName?: string;
115
117
  packageName?: string;
116
118
  description: string;
119
+ aliases?: string[];
117
120
  tools?: string[];
118
121
  mcpDirectTools?: string[];
119
122
  model?: string;
@@ -150,6 +153,8 @@ export interface AgentConfig {
150
153
  modelSource?: AgentModelSourceInfo;
151
154
  }
152
155
 
156
+ type ProjectRootResolution = "nearest" | "git-root";
157
+
153
158
  interface SubagentSettings {
154
159
  overrides: Record<string, BuiltinAgentOverrideConfig>;
155
160
  defaultModel?: string;
@@ -420,7 +425,7 @@ function collectSettingsPackageRoots(settingsFile: string, baseDir: string): str
420
425
 
421
426
  function collectPackageSubagentPaths(cwd: string, options: { includeUser: boolean; includeProject: boolean } = { includeUser: true, includeProject: true }): PackageSubagentPaths {
422
427
  const agentDir = getAgentDir();
423
- const projectRoot = findNearestProjectRoot(cwd) ?? cwd;
428
+ const projectRoot = findConfiguredProjectRoot(cwd) ?? cwd;
424
429
  const packageRoots = [
425
430
  projectRoot,
426
431
  ];
@@ -469,6 +474,41 @@ function collectPackageSubagentPaths(cwd: string, options: { includeUser: boolea
469
474
  return { agents, chains };
470
475
  }
471
476
 
477
+ function normalizeAgentAliases(rawAliases: string[] | undefined, agentName: string): string[] | undefined {
478
+ const aliases = [...new Set((rawAliases ?? []).map((alias) => alias.trim()).filter(Boolean))]
479
+ .filter((alias) => alias !== agentName);
480
+ return aliases.length > 0 ? aliases : undefined;
481
+ }
482
+
483
+ function effectiveAgentMatch(matches: AgentConfig[]): { agent?: AgentConfig; error?: string } {
484
+ const distinctNames = [...new Set(matches.map((agent) => agent.name))];
485
+ if (distinctNames.length === 1) {
486
+ const sourceRank = new Map<AgentConfig["source"], number>([["builtin", 0], ["package", 1], ["user", 2], ["project", 3]]);
487
+ return { agent: [...matches].sort((a, b) => (sourceRank.get(b.source) ?? 0) - (sourceRank.get(a.source) ?? 0))[0] };
488
+ }
489
+ return {};
490
+ }
491
+
492
+ export function resolveAgentName(name: string, agents: AgentConfig[]): { agent?: AgentConfig; error?: string } {
493
+ const raw = name.trim();
494
+ const exact = agents.filter((agent) => agent.name === raw || agent.localName === raw);
495
+ if (exact.length === 1) return { agent: exact[0] };
496
+ if (exact.length > 1) {
497
+ const effective = effectiveAgentMatch(exact);
498
+ if (effective.agent) return effective;
499
+ return { error: `Ambiguous agent name '${name}': ${exact.map((agent) => agent.name).join(", ")}` };
500
+ }
501
+
502
+ const aliases = agents.filter((agent) => agent.aliases?.includes(raw));
503
+ if (aliases.length === 1) return { agent: aliases[0] };
504
+ if (aliases.length > 1) {
505
+ const effective = effectiveAgentMatch(aliases);
506
+ if (effective.agent) return effective;
507
+ return { error: `Ambiguous agent alias '${name}': ${aliases.map((agent) => agent.name).join(", ")}` };
508
+ }
509
+ return {};
510
+ }
511
+
472
512
  function splitToolList(rawTools: string[] | undefined): { tools?: string[]; mcpDirectTools?: string[] } {
473
513
  const mcpDirectTools: string[] = [];
474
514
  const tools: string[] = [];
@@ -505,6 +545,7 @@ function arraysEqual(a: string[] | undefined, b: string[] | undefined): boolean
505
545
 
506
546
  function cloneOverrideBase(agent: AgentConfig): BuiltinAgentOverrideBase {
507
547
  return {
548
+ description: agent.description,
508
549
  model: agent.model,
509
550
  fallbackModels: agent.fallbackModels ? [...agent.fallbackModels] : undefined,
510
551
  thinking: agent.thinking,
@@ -528,6 +569,7 @@ function cloneOverrideBase(agent: AgentConfig): BuiltinAgentOverrideBase {
528
569
 
529
570
  function cloneOverrideValue(override: BuiltinAgentOverrideConfig): BuiltinAgentOverrideConfig {
530
571
  return {
572
+ ...(override.description !== undefined ? { description: override.description } : {}),
531
573
  ...(override.model !== undefined ? { model: override.model } : {}),
532
574
  ...(override.fallbackModels !== undefined
533
575
  ? { fallbackModels: override.fallbackModels === false ? false : [...override.fallbackModels] }
@@ -549,12 +591,26 @@ function cloneOverrideValue(override: BuiltinAgentOverrideConfig): BuiltinAgentO
549
591
  };
550
592
  }
551
593
 
552
- export function findNearestProjectRoot(cwd: string): string | null {
594
+ function isProjectRootCandidate(dir: string): boolean {
595
+ return isDirectory(getProjectConfigDir(dir)) || isDirectory(path.join(dir, ".agents"));
596
+ }
597
+
598
+ function findProjectRootCandidates(cwd: string): string[] {
599
+ const roots: string[] = [];
553
600
  let currentDir = cwd;
554
601
  while (true) {
555
- if (isDirectory(getProjectConfigDir(currentDir)) || isDirectory(path.join(currentDir, ".agents"))) {
556
- return currentDir;
557
- }
602
+ if (isProjectRootCandidate(currentDir)) roots.push(currentDir);
603
+
604
+ const parentDir = path.dirname(currentDir);
605
+ if (parentDir === currentDir) return roots;
606
+ currentDir = parentDir;
607
+ }
608
+ }
609
+
610
+ function findNearestGitRoot(cwd: string): string | null {
611
+ let currentDir = cwd;
612
+ while (true) {
613
+ if (fs.existsSync(path.join(currentDir, ".git"))) return currentDir;
558
614
 
559
615
  const parentDir = path.dirname(currentDir);
560
616
  if (parentDir === currentDir) return null;
@@ -562,12 +618,46 @@ export function findNearestProjectRoot(cwd: string): string | null {
562
618
  }
563
619
  }
564
620
 
621
+ function readProjectRootResolution(projectRoot: string): ProjectRootResolution | undefined {
622
+ const settingsPath = path.join(getProjectConfigDir(projectRoot), "settings.json");
623
+ if (!fs.existsSync(settingsPath)) return undefined;
624
+ const settings = readSettingsFileStrict(settingsPath);
625
+ const subagents = settings.subagents;
626
+ if (!subagents || typeof subagents !== "object" || Array.isArray(subagents)) return undefined;
627
+
628
+ const value = (subagents as Record<string, unknown>).projectRootResolution;
629
+ if (value === undefined) return undefined;
630
+ if (value === "nearest" || value === "git-root") return value;
631
+ throw new Error(`Subagent settings in '${settingsPath}' have invalid 'projectRootResolution'; expected 'nearest' or 'git-root'.`);
632
+ }
633
+
634
+ export function findNearestProjectRoot(cwd: string): string | null {
635
+ return findProjectRootCandidates(cwd)[0] ?? null;
636
+ }
637
+
638
+ function findConfiguredProjectRoot(cwd: string): string | null {
639
+ const candidates = findProjectRootCandidates(cwd);
640
+ const nearestRoot = candidates[0];
641
+ if (!nearestRoot) return null;
642
+
643
+ const nearestMode = readProjectRootResolution(nearestRoot);
644
+ if (nearestMode === "nearest") return nearestRoot;
645
+
646
+ const gitRoot = findNearestGitRoot(cwd);
647
+ const gitProjectRoot = gitRoot ? candidates.find((candidate) => path.resolve(candidate) === path.resolve(gitRoot)) : undefined;
648
+ if (gitProjectRoot && (nearestMode === "git-root" || readProjectRootResolution(gitProjectRoot) === "git-root")) {
649
+ return gitProjectRoot;
650
+ }
651
+
652
+ return nearestRoot;
653
+ }
654
+
565
655
  function getUserAgentSettingsPath(): string {
566
656
  return path.join(getAgentDir(), "settings.json");
567
657
  }
568
658
 
569
659
  function getProjectAgentSettingsPath(cwd: string): string | null {
570
- const projectRoot = findNearestProjectRoot(cwd);
660
+ const projectRoot = findConfiguredProjectRoot(cwd);
571
661
  return projectRoot ? path.join(getProjectConfigDir(projectRoot), "settings.json") : null;
572
662
  }
573
663
 
@@ -632,6 +722,14 @@ function parseBuiltinOverrideEntry(
632
722
  const input = value as Record<string, unknown>;
633
723
  const override: BuiltinAgentOverrideConfig = {};
634
724
 
725
+ if ("description" in input) {
726
+ if (typeof input.description === "string" && input.description.trim()) {
727
+ override.description = input.description.trim();
728
+ } else {
729
+ throw new Error(`Builtin override '${name}' in '${filePath}' has invalid 'description'; expected a non-empty string.`);
730
+ }
731
+ }
732
+
635
733
  if ("model" in input) {
636
734
  if (typeof input.model === "string" || input.model === false) override.model = input.model;
637
735
  else throw new Error(`Builtin override '${name}' in '${filePath}' has invalid 'model'; expected a string or false.`);
@@ -879,6 +977,7 @@ function applyBuiltinOverride(
879
977
  override: { ...meta, base: cloneOverrideBase(agent) },
880
978
  };
881
979
 
980
+ if (override.description !== undefined) next.description = override.description;
882
981
  if (override.model !== undefined) next.model = override.model === false ? undefined : override.model;
883
982
  if (override.fallbackModels !== undefined) {
884
983
  next.fallbackModels = override.fallbackModels === false ? undefined : [...override.fallbackModels];
@@ -999,6 +1098,10 @@ function applyCustomAgentOverride(
999
1098
  anyFilled = true;
1000
1099
  };
1001
1100
 
1101
+ if (override.description !== undefined) {
1102
+ mutable().description = override.description;
1103
+ anyFilled = true;
1104
+ }
1002
1105
  if (override.model !== undefined) {
1003
1106
  fill("model", ["model"], override.model === false ? undefined : override.model);
1004
1107
  }
@@ -1089,10 +1192,14 @@ function applyCustomAgentOverrides(
1089
1192
 
1090
1193
  export function buildBuiltinOverrideConfig(
1091
1194
  base: BuiltinAgentOverrideBase,
1092
- draft: Pick<AgentConfig, "model" | "fallbackModels" | "thinking" | "systemPromptMode" | "inheritProjectContext" | "inheritSkills" | "defaultContext" | "acceptanceRole" | "disabled" | "systemPrompt" | "skills" | "tools" | "mcpDirectTools" | "extensions" | "subagentOnlyExtensions" | "completionGuard" | "toolBudget">,
1195
+ draft: Pick<AgentConfig, "model" | "fallbackModels" | "thinking" | "systemPromptMode" | "inheritProjectContext" | "inheritSkills" | "defaultContext" | "acceptanceRole" | "disabled" | "systemPrompt" | "skills" | "tools" | "mcpDirectTools" | "extensions" | "subagentOnlyExtensions" | "completionGuard" | "toolBudget"> & Partial<Pick<AgentConfig, "description">>,
1093
1196
  ): BuiltinAgentOverrideConfig | undefined {
1094
1197
  const override: BuiltinAgentOverrideConfig = {};
1095
1198
 
1199
+ if (draft.description !== undefined) {
1200
+ const description = draft.description.trim();
1201
+ if (description && description !== base.description) override.description = description;
1202
+ }
1096
1203
  if (draft.model !== base.model) override.model = draft.model ?? false;
1097
1204
  if (!arraysEqual(draft.fallbackModels, base.fallbackModels)) override.fallbackModels = draft.fallbackModels ? [...draft.fallbackModels] : false;
1098
1205
  if (draft.thinking !== base.thinking) override.thinking = draft.thinking ?? false;
@@ -1333,6 +1440,7 @@ function loadAgentsFromDir(dir: string, source: AgentSource): AgentConfig[] {
1333
1440
  const tools = parsedTools.tools ?? [];
1334
1441
  const mcpDirectTools = parsedTools.mcpDirectTools ?? [];
1335
1442
  const defaultReads = parseFrontmatterList(frontmatter.defaultReads);
1443
+ const aliases = normalizeAgentAliases(parseFrontmatterList(frontmatter.aliases ?? frontmatter.alias), runtimeName);
1336
1444
  const skillStr = frontmatter.skill || frontmatter.skills;
1337
1445
  const skills = parseFrontmatterList(skillStr);
1338
1446
  const skillPath = parseFrontmatterList(frontmatter.skillPath);
@@ -1413,6 +1521,7 @@ function loadAgentsFromDir(dir: string, source: AgentSource): AgentConfig[] {
1413
1521
  localName,
1414
1522
  packageName,
1415
1523
  description: frontmatter.description,
1524
+ aliases,
1416
1525
  tools: rawTools !== undefined ? tools : undefined,
1417
1526
  mcpDirectTools: mcpDirectTools.length > 0 ? mcpDirectTools : undefined,
1418
1527
  model: frontmatter.model,
@@ -1489,7 +1598,7 @@ function isDirectory(p: string): boolean {
1489
1598
  }
1490
1599
 
1491
1600
  function resolveNearestProjectAgentDirs(cwd: string): { readDirs: string[]; preferredDir: string | null } {
1492
- const projectRoot = findNearestProjectRoot(cwd);
1601
+ const projectRoot = findConfiguredProjectRoot(cwd);
1493
1602
  if (!projectRoot) return { readDirs: [], preferredDir: null };
1494
1603
 
1495
1604
  const legacyDir = path.join(projectRoot, ".agents");
@@ -1505,7 +1614,7 @@ function resolveNearestProjectAgentDirs(cwd: string): { readDirs: string[]; pref
1505
1614
  }
1506
1615
 
1507
1616
  function resolveNearestProjectChainDirs(cwd: string): { readDirs: string[]; preferredDir: string | null } {
1508
- const projectRoot = findNearestProjectRoot(cwd);
1617
+ const projectRoot = findConfiguredProjectRoot(cwd);
1509
1618
  if (!projectRoot) return { readDirs: [], preferredDir: null };
1510
1619
 
1511
1620
  const preferredDir = path.join(getProjectConfigDir(projectRoot), "chains");
@@ -379,19 +379,21 @@ function chooseHigherPrioritySkill(existing: CachedSkillEntry | undefined, candi
379
379
  return candidate.order < existing.order ? candidate : existing;
380
380
  }
381
381
 
382
- function maybeReadSkillDescription(filePath: string): string | undefined {
383
- try {
384
- const content = fs.readFileSync(filePath, "utf-8");
385
- const normalized = content.replace(/\r\n/g, "\n");
386
- if (!normalized.startsWith("---")) return undefined;
382
+ function parseSkillDescription(content: string): string | undefined {
383
+ const normalized = content.replace(/\r\n/g, "\n");
384
+ if (!normalized.startsWith("---")) return undefined;
385
+
386
+ const endIndex = normalized.indexOf("\n---", 3);
387
+ if (endIndex === -1) return undefined;
387
388
 
388
- const endIndex = normalized.indexOf("\n---", 3);
389
- if (endIndex === -1) return undefined;
389
+ const frontmatter = normalized.slice(3, endIndex).trim();
390
+ const match = frontmatter.match(/^description:\s*(.+)$/m);
391
+ return match?.[1]?.trim().replace(/^['\"]|['\"]$/g, "");
392
+ }
390
393
 
391
- const frontmatter = normalized.slice(3, endIndex).trim();
392
- const match = frontmatter.match(/^description:\s*(.+)$/m);
393
- if (!match) return undefined;
394
- return match[1]?.trim().replace(/^['\"]|['\"]$/g, "");
394
+ function maybeReadSkillDescription(filePath: string): string | undefined {
395
+ try {
396
+ return parseSkillDescription(fs.readFileSync(filePath, "utf-8"));
395
397
  } catch {
396
398
  // Description parsing is best-effort metadata extraction.
397
399
  return undefined;
@@ -585,7 +587,7 @@ function readSkill(
585
587
 
586
588
  const raw = fs.readFileSync(skillPath, "utf-8");
587
589
  const content = stripSkillFrontmatter(raw);
588
- const description = maybeReadSkillDescription(skillPath);
590
+ const description = parseSkillDescription(raw);
589
591
  const skill: ResolvedSkill = {
590
592
  name: skillName,
591
593
  path: skillPath,
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Pure task-aware advisory agent recommender.
3
+ *
4
+ * Given an already-discovered, effective agent set and the current capability
5
+ * ceiling, deterministically selects at most one canonical agent to recommend
6
+ * for a task, or returns recovery guidance when intent is unknown or no safe
7
+ * candidate exists. This module is deliberately pure: it performs no
8
+ * filesystem/discovery access, no alias/chains/executor/RPC/preflight/settings
9
+ * access, no mutation, launch, scheduling, or persistence, and never writes to
10
+ * params. Launching stays explicit: the caller must make a separate execution
11
+ * call with the recommended canonical `agent.name`.
12
+ */
13
+
14
+ import type { AgentConfig, AgentSource } from "./agents.ts";
15
+ import { agentHasWriteTools } from "./agent-memory.ts";
16
+ import { classifyTaskMutationIntent, resolveAgentRoutingRole } from "../runs/shared/task-intent.ts";
17
+ import { isAgentAllowedByCapabilityCeiling, type ResolvedSubagentCapabilityCeiling } from "../runs/shared/capability-ceiling.ts";
18
+
19
+ /** Core tools that make an implementation agent able to write (matches agent-memory). */
20
+ const WRITER_TOOLS = new Set(["edit", "write", "bash"]);
21
+
22
+ /** Source precedence for deterministic ordering: project > user > package > builtin. */
23
+ const AGENT_SOURCE_PRECEDENCE: Record<AgentSource, number> = { builtin: 0, package: 1, user: 2, project: 3 };
24
+
25
+ export type TaskAwareAgentIntent = "implementation" | "read-only" | "unknown";
26
+
27
+ export interface TaskAwareAgentRecommendationAgent {
28
+ /** Canonical runtime agent name accepted by execution; never an alias. */
29
+ name: string;
30
+ source: AgentSource;
31
+ role: "writer" | "read-only";
32
+ roleBasis: "declared" | "inferred";
33
+ reason: string;
34
+ }
35
+
36
+ export interface TaskAwareAgentRecommendation {
37
+ intent: TaskAwareAgentIntent;
38
+ agent?: TaskAwareAgentRecommendationAgent;
39
+ /** Recovery guidance when no safe recommendation exists (unknown intent or no candidate). */
40
+ next?: string;
41
+ }
42
+
43
+ /**
44
+ * Recommend a canonical agent for a trimmed non-empty task, or `undefined` for
45
+ * an empty/whitespace task (no-op). Never recommends disabled or
46
+ * capability-disallowed agents, never guesses for unknown intent, and never
47
+ * outputs an alias or a role-incompatible agent.
48
+ */
49
+ export function recommendTaskAwareAgent(input: {
50
+ task: string;
51
+ agents: AgentConfig[];
52
+ capabilityCeiling?: ResolvedSubagentCapabilityCeiling;
53
+ }): TaskAwareAgentRecommendation | undefined {
54
+ const task = input.task.trim();
55
+ if (!task) return undefined;
56
+
57
+ const intent = classifyTaskMutationIntent("builder", task).kind;
58
+ if (intent === "unknown") {
59
+ return {
60
+ intent,
61
+ next: "Clarify whether the task is read-only analysis/review or implementation allowed to edit files.",
62
+ };
63
+ }
64
+
65
+ const candidates: TaskAwareAgentRecommendationAgent[] = [];
66
+ for (const agent of input.agents) {
67
+ if (agent.disabled) continue;
68
+ if (!isAgentAllowedByCapabilityCeiling(agent.name, input.capabilityCeiling)) continue;
69
+ const role = resolveAgentRoutingRole(agent.name, agent.acceptanceRole);
70
+ if (!role) continue;
71
+ const hasWriteTools = agentHasWriteTools(agent);
72
+ if (intent === "implementation") {
73
+ if (role !== "writer" || !hasWriteTools) continue;
74
+ const allowedTools = input.capabilityCeiling?.allowedTools;
75
+ if (allowedTools !== undefined && !allowedTools.some((tool) => WRITER_TOOLS.has(tool))) continue;
76
+ } else {
77
+ if (role !== "read-only" || hasWriteTools) continue;
78
+ }
79
+ const roleBasis = agent.acceptanceRole !== undefined ? "declared" : "inferred";
80
+ candidates.push({
81
+ name: agent.name,
82
+ source: agent.source,
83
+ role,
84
+ roleBasis,
85
+ reason: intent === "implementation"
86
+ ? `${roleBasis} writer role with write tools`
87
+ : `${roleBasis} read-only role without known write tools`,
88
+ });
89
+ }
90
+
91
+ candidates.sort((a, b) => {
92
+ const sourceOrder = AGENT_SOURCE_PRECEDENCE[b.source] - AGENT_SOURCE_PRECEDENCE[a.source];
93
+ if (sourceOrder !== 0) return sourceOrder;
94
+ const declaredOrder = (a.roleBasis === "declared" ? 0 : 1) - (b.roleBasis === "declared" ? 0 : 1);
95
+ if (declaredOrder !== 0) return declaredOrder;
96
+ return a.name < b.name ? -1 : a.name > b.name ? 1 : 0;
97
+ });
98
+
99
+ const agent = candidates[0];
100
+ if (!agent) {
101
+ return {
102
+ intent,
103
+ next: intent === "implementation"
104
+ ? "No executable agent has a writer role with write tools for this task. Check the executable/restricted sections above or adjust the capability ceiling."
105
+ : "No executable agent has a read-only role without known write tools for this task. Check the executable/restricted sections above.",
106
+ };
107
+ }
108
+ return { intent, agent };
109
+ }
110
+
111
+ /** Text-only advisory lines; `undefined` (empty-task no-op) renders nothing. */
112
+ export function formatTaskAwareAgentRecommendation(recommendation: TaskAwareAgentRecommendation | undefined): string[] {
113
+ if (!recommendation) return [];
114
+ const lines = ["Task-aware advisory routing:", `- Intent: ${recommendation.intent}`];
115
+ if (recommendation.agent) {
116
+ lines.push(`- Recommended: ${recommendation.agent.name} (${recommendation.agent.source})`);
117
+ lines.push(`- Reason: ${recommendation.agent.reason}`);
118
+ lines.push("- Advisory only: no subagent was launched. To proceed, explicitly call subagent with this canonical agent name and the task.");
119
+ } else {
120
+ lines.push("- Recommendation: none");
121
+ lines.push(`- Next: ${recommendation.next ?? "Refine the task wording and retry."}`);
122
+ lines.push("- Advisory only: no subagent was launched.");
123
+ }
124
+ return lines;
125
+ }
@@ -131,6 +131,7 @@ export interface SubagentDelegationStarted {
131
131
  }
132
132
 
133
133
  export interface SubagentDelegationUpdate extends SubagentDelegationStarted {
134
+ runId?: string;
134
135
  currentTool?: string;
135
136
  currentToolArgs?: string;
136
137
  recentOutput?: string;
@@ -230,6 +231,7 @@ export interface SubagentDelegationV2Started {
230
231
  }
231
232
 
232
233
  export interface SubagentDelegationV2Update extends SubagentDelegationV2Started {
234
+ runId?: string;
233
235
  currentTool?: string;
234
236
  currentToolArgs?: string;
235
237
  recentOutput?: string;
@@ -266,6 +268,7 @@ export interface SubagentDelegationV2TerminalResponse extends SubagentDelegation
266
268
  model?: string;
267
269
  thinking?: string;
268
270
  exitCode?: number;
271
+ launchContractDigest?: string;
269
272
  result?: SubagentDelegationV2Value;
270
273
  usage?: SubagentDelegationV2Usage;
271
274
  }
@@ -2,7 +2,7 @@ import { createHash } from "node:crypto";
2
2
  import * as fs from "node:fs";
3
3
  import * as path from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
- import { discoverAgents, discoverAgentsAll, type AgentConfig, type AgentScope, type AgentSource } from "../agents/agents.ts";
5
+ import { discoverAgents, discoverAgentsAll, resolveAgentName, type AgentConfig, type AgentScope, type AgentSource } from "../agents/agents.ts";
6
6
  import { resolveExecutionAgentScope } from "../agents/agent-scope.ts";
7
7
  import { buildSkillInjection, normalizeSkillInput, resolveSkillsWithFallback } from "../agents/skills.ts";
8
8
  import { buildAgentMemoryInjection } from "../agents/agent-memory.ts";
@@ -12,7 +12,7 @@ import { injectOutputPathSystemPrompt, normalizeSingleOutputOverride, resolveSin
12
12
  import { getArtifactPaths, getArtifactsDir } from "../shared/artifacts.ts";
13
13
  import { resolveEffectiveThinking } from "../shared/model-info.ts";
14
14
  import { SUBAGENT_LIFECYCLE_ARTIFACT_VERSION, type ArtifactDirPreference, type ArtifactPaths, type JsonSchemaObject, type OutputMode } from "../shared/types.ts";
15
- import type { ResolvedSubagentCapabilityCeiling, SubagentCapabilityAudit } from "../runs/shared/capability-ceiling.ts";
15
+ import { capabilityCeilingAgentRestrictionMessage, intersectSubagentCapabilityCeilings, type ResolvedSubagentCapabilityCeiling, type SubagentCapabilityAudit } from "../runs/shared/capability-ceiling.ts";
16
16
  import { appendTurnBudgetSystemPrompt } from "../runs/shared/turn-budget.ts";
17
17
  import type { ResolvedTurnBudget } from "../shared/types.ts";
18
18
  import type { ResolvedMcpDirectToolSelection } from "../runs/shared/mcp-direct-tool-allowlist.ts";
@@ -31,7 +31,8 @@ export type SubagentLaunchContractReasonCode =
31
31
  | "denied_required_tool"
32
32
  | "invalid_artifact_dir"
33
33
  | "invalid_cwd"
34
- | "unsupported_mode";
34
+ | "unsupported_mode"
35
+ | "restricted_agent";
35
36
 
36
37
  export interface SubagentLaunchContractDiagnostic {
37
38
  code: SubagentLaunchContractReasonCode | "host_required" | "snapshot_warning";
@@ -191,7 +192,7 @@ function normalizeAvailableModels(models: SubagentLaunchContractInput["available
191
192
  function candidateList(inputAgent: string, selected: AgentConfig | undefined, cwd: string): SubagentLaunchContractAgentCandidate[] {
192
193
  const all = discoverAgentsAll(cwd);
193
194
  return [...all.builtin, ...all.package, ...all.user, ...all.project]
194
- .filter((agent) => agent.name === inputAgent || agent.localName === inputAgent)
195
+ .filter((agent) => Boolean(resolveAgentName(inputAgent, [agent]).agent))
195
196
  .map((agent) => ({
196
197
  name: agent.name,
197
198
  ...(agent.localName ? { localName: agent.localName } : {}),
@@ -225,14 +226,17 @@ export async function resolveSubagentLaunchContract(input: SubagentLaunchContrac
225
226
  }
226
227
  const scope = resolveExecutionAgentScope(input.agentScope);
227
228
  const discovered = discoverAgents(effectiveCwd, scope);
228
- const matches = discovered.agents.filter((agent) => agent.name === input.agent || agent.localName === input.agent);
229
- if (matches.length === 0) {
230
- return { ok: false, code: "missing_agent", message: `Unknown agent: ${input.agent}`, diagnostics };
229
+ const resolvedAgent = resolveAgentName(input.agent, discovered.agents);
230
+ if (resolvedAgent.error) {
231
+ return { ok: false, code: "ambiguous_agent", message: resolvedAgent.error, diagnostics };
231
232
  }
232
- if (matches.length > 1) {
233
- return { ok: false, code: "ambiguous_agent", message: `Ambiguous agent: ${input.agent}`, diagnostics };
233
+ if (!resolvedAgent.agent) {
234
+ return { ok: false, code: "missing_agent", message: `Unknown agent: ${input.agent}`, diagnostics };
234
235
  }
235
- const agent = matches[0]!;
236
+ const agent = resolvedAgent.agent;
237
+ const effectiveCapabilityCeiling = intersectSubagentCapabilityCeilings(input.capabilityCeiling, input.inheritedCapabilityCeiling);
238
+ const restrictionMessage = capabilityCeilingAgentRestrictionMessage(agent.name, effectiveCapabilityCeiling);
239
+ if (restrictionMessage) return { ok: false, code: "restricted_agent", message: restrictionMessage, diagnostics };
236
240
  const runId = input.runId ?? "preflight";
237
241
  const skillInput = normalizeSkillInput(input.skill);
238
242
  const outputOverride = normalizeSingleOutputOverride(input.output, agent.output);
@@ -272,15 +276,15 @@ export async function resolveSubagentLaunchContract(input: SubagentLaunchContrac
272
276
  cwd: effectiveCwd,
273
277
  requireReadTool: resolvedSkills.resolved.length > 0,
274
278
  structuredOutput: Boolean(input.outputSchema),
275
- capabilityCeiling: input.capabilityCeiling,
276
- inheritedCapabilityCeiling: input.inheritedCapabilityCeiling,
279
+ capabilityCeiling: effectiveCapabilityCeiling,
280
+ agentName: agent.name,
277
281
  });
278
282
  } catch (error) {
279
283
  const message = error instanceof Error ? error.message : String(error);
280
284
  diagnostics.push({ code: "denied_required_tool", severity: "error", message });
281
285
  return { ok: false, code: "denied_required_tool", message, diagnostics };
282
286
  }
283
- const artifactsEnabled = input.artifacts !== false;
287
+ const artifactsEnabled = input.artifacts === true;
284
288
  const artifactsDir = artifactsEnabled ? getArtifactsDir(input.parentSessionFile ?? null, effectiveCwd, input.artifactDir ?? "project") : undefined;
285
289
  const artifactPaths = artifactsDir ? getArtifactPaths(artifactsDir, runId, agent.name, 0) : undefined;
286
290
  const outputPath = resolveSingleOutputPath(behavior.output, effectiveCwd, effectiveCwd, artifactsDir ? path.join(artifactsDir, "outputs", runId) : undefined);
@@ -43,7 +43,7 @@ export const EXPAND_KEYS = allowedKeysOf(DynamicExpandSchema);
43
43
  export const EXPAND_FROM_KEYS = allowedKeysOf(ExpandFromSchema);
44
44
  export const COLLECT_KEYS = allowedKeysOf(DynamicCollectSchema);
45
45
 
46
- const CHAIN_STEP_EXAMPLE = '{"agent": "builder", "task": "do X"}';
46
+ const CHAIN_STEP_EXAMPLE = '{"agent": "builder", "task": "do X"} or {"checkpoint": "review", "message": "Approve before implementation?"}';
47
47
  const PARALLEL_TASK_EXAMPLE = '{"agent": "builder", "task": "do X"}';
48
48
  const DYNAMIC_TEMPLATE_EXAMPLE = '{"agent": "builder", "task": "Review {item.path}"}';
49
49
  const EXPAND_EXAMPLE = '{"from": {"output": "targets", "path": "/items"}, "maxItems": 4}';
@@ -58,6 +58,21 @@ function disallowedKeys(value: Record<string, unknown>, allowed: readonly string
58
58
  return Object.keys(value).filter((key) => !allowed.includes(key));
59
59
  }
60
60
 
61
+ function validateCheckpointShape(step: Record<string, unknown>, path: string): void {
62
+ if (step.checkpoint === undefined) return;
63
+ const allowed = new Set(["checkpoint", "message", "phase", "label"]);
64
+ const mixed = Object.keys(step).filter((key) => !allowed.has(key));
65
+ if (mixed.length > 0) {
66
+ throw new Error(`subagent ${path}: checkpoint steps cannot be mixed with child-launch properties ${quoteList(mixed)}.\n\nExample: {"checkpoint": "review", "message": "Approve before implementation?"}`);
67
+ }
68
+ if (typeof step.checkpoint !== "string" || !step.checkpoint.trim()) {
69
+ throw new Error(`subagent ${path}.checkpoint: expected a non-empty string.`);
70
+ }
71
+ if (step.message !== undefined && typeof step.message !== "string") {
72
+ throw new Error(`subagent ${path}.message: expected a string.`);
73
+ }
74
+ }
75
+
61
76
  function typeName(value: unknown): string {
62
77
  if (Array.isArray(value)) return "array";
63
78
  return typeof value;
@@ -120,6 +135,7 @@ export function validateChainInput(args: unknown): void {
120
135
  const stepPath = `chain step validation failed at chain[${index}]`;
121
136
  expectObject(step, stepPath, CHAIN_STEP_KEYS, CHAIN_STEP_EXAMPLE);
122
137
  checkNoExtraKeys(step, stepPath, ChainItem, CHAIN_STEP_KEYS, CHAIN_STEP_EXAMPLE);
138
+ validateCheckpointShape(step, stepPath);
123
139
 
124
140
  if (step.expand !== undefined) {
125
141
  const expandPath = `${stepPath}.expand`;
@@ -27,7 +27,7 @@ import { resolveCurrentSessionId } from "../shared/session-identity.ts";
27
27
  import { cleanupOldChainDirs } from "../shared/settings.ts";
28
28
  import { clearLegacyResultAnimationTimer, renderSubagentResult } from "../tui/render.ts";
29
29
  import { openSubagentFleet } from "../tui/fleet.ts";
30
- import { SubagentFleetStatus } from "../tui/fleet-status.ts";
30
+ import { SubagentFleetStatus, resolveFleetViewPlacement } from "../tui/fleet-status.ts";
31
31
  import { SubagentParams } from "./schemas.ts";
32
32
  import { validateChainInput } from "./chain-validation.ts";
33
33
  import { createSubagentExecutor, type SubagentParamsLike } from "../runs/foreground/subagent-executor.ts";
@@ -51,7 +51,7 @@ import { SUBAGENT_CHILD_ENV, SUBAGENT_PARENT_SESSION_ENV } from "../runs/shared/
51
51
  import { resolveCurrentSubagentCapabilityCeiling } from "../runs/shared/capability-ceiling.ts";
52
52
  import { formatDuration, shortenPath } from "../shared/formatters.ts";
53
53
  import { loadConfig } from "./config.ts";
54
- import { buildSubagentToolDescription } from "./tool-description.ts";
54
+ import { buildSubagentToolDescription, SUBAGENT_PARENT_ROUTING_GUIDANCE } from "./tool-description.ts";
55
55
  import {
56
56
  type Details,
57
57
  type SubagentState,
@@ -144,10 +144,13 @@ function createSlashResultComponent(
144
144
  }
145
145
 
146
146
  class SubagentControlNoticeComponent implements Component {
147
- constructor(
148
- private readonly details: SubagentControlMessageDetails,
149
- private readonly theme: ExtensionContext["ui"]["theme"],
150
- ) {}
147
+ private readonly details: SubagentControlMessageDetails;
148
+ private readonly theme: ExtensionContext["ui"]["theme"];
149
+
150
+ constructor(details: SubagentControlMessageDetails, theme: ExtensionContext["ui"]["theme"]) {
151
+ this.details = details;
152
+ this.theme = theme;
153
+ }
151
154
 
152
155
  invalidate(): void {}
153
156
 
@@ -194,6 +197,7 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
194
197
  const waitToolConfig = resolveWaitToolConfig(config.waitTool);
195
198
  const asyncByDefault = config.asyncByDefault === true;
196
199
  const fleetViewEnabled = config.fleetView !== false;
200
+ const fleetViewPlacement = resolveFleetViewPlacement(config.fleetViewPlacement);
197
201
  const asyncWidgetEnabled = config.asyncWidget === true || (!fleetViewEnabled && config.asyncWidget !== false);
198
202
  const tempArtifactsDir = getArtifactsDir(null);
199
203
  cleanupAllArtifactDirs(DEFAULT_ARTIFACT_CONFIG.cleanupDays);
@@ -237,14 +241,17 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
237
241
  const ctx = state.lastUiContext;
238
242
  if (!ctx?.hasUI) return;
239
243
  await openSubagentFleet(ctx, state, { initialKey: itemKey });
240
- })
244
+ }, { placement: fleetViewPlacement })
241
245
  : undefined;
242
246
  const { startResultWatcher, primeExistingResults, stopResultWatcher } = createResultWatcher(
243
247
  pi,
244
248
  state,
245
249
  RESULTS_DIR,
246
250
  10 * 60 * 1000,
247
- { notifier: completionNotifier },
251
+ {
252
+ notifier: completionNotifier,
253
+ deliverIntercomResults: config.intercomBridge?.resultDelivery !== false,
254
+ },
248
255
  );
249
256
 
250
257
  const runtimeCleanup = () => {
@@ -383,6 +390,7 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
383
390
  events: pi.events,
384
391
  getContext: () => state.lastUiContext,
385
392
  execute: (id, params, signal, onUpdate, ctx) => executor.execute(id, params, signal, onUpdate, ctx),
393
+ state,
386
394
  });
387
395
 
388
396
  function effectiveParallelTaskCount(tasks: Array<{ count?: unknown }> | undefined): number {
@@ -397,6 +405,10 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
397
405
  name: "subagent",
398
406
  label: "Subagent",
399
407
  description: buildSubagentToolDescription(config),
408
+ // Always-visible active-tool path: rendered into the main system prompt by
409
+ // buildSystemPrompt (default and custom-prompt branches). Parent-only; the
410
+ // child-safe fanout registration must not receive this guidance.
411
+ promptGuidelines: [SUBAGENT_PARENT_ROUTING_GUIDANCE],
400
412
  parameters: SubagentParams,
401
413
 
402
414
  prepareArguments(args) {
@@ -551,6 +563,8 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
551
563
  state.lastUiContext = ctx;
552
564
  cleanupSessionArtifacts(ctx);
553
565
  clearPendingForegroundControlNotices(state);
566
+ state.foregroundControls.clear();
567
+ state.lastForegroundControlId = null;
554
568
  resetJobs(ctx);
555
569
  restoreActiveJobs(ctx);
556
570
  scheduledRunManager.bindSession(ctx);