@selesai/code 0.5.19 → 0.5.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (265) hide show
  1. package/dist/extensions/handoff-new.test.ts +8 -9
  2. package/dist/extensions/handoff-new.ts +6 -8
  3. package/dist/extensions/pi-intercom/broker/spawn.test.ts +31 -0
  4. package/dist/extensions/pi-intercom/broker/spawn.ts +5 -3
  5. package/dist/extensions/pi-subagents/CHANGELOG.md +1367 -0
  6. package/dist/extensions/pi-subagents/README.md +602 -220
  7. package/dist/extensions/pi-subagents/banner.png +0 -0
  8. package/dist/extensions/pi-subagents/index.ts +1 -0
  9. package/dist/extensions/pi-subagents/install.mjs +3 -3
  10. package/dist/extensions/pi-subagents/package-lock.json +3405 -0
  11. package/dist/extensions/pi-subagents/package.json +26 -14
  12. package/dist/extensions/pi-subagents/prompts/gather-context-and-clarify.md +1 -1
  13. package/dist/extensions/pi-subagents/prompts/parallel-cleanup.md +9 -9
  14. package/dist/extensions/pi-subagents/prompts/parallel-context-build.md +3 -3
  15. package/dist/extensions/pi-subagents/prompts/parallel-handoff-plan.md +7 -7
  16. package/dist/extensions/pi-subagents/prompts/parallel-research.md +6 -6
  17. package/dist/extensions/pi-subagents/prompts/parallel-review.md +8 -8
  18. package/dist/extensions/pi-subagents/prompts/review-loop.md +13 -11
  19. package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +267 -176
  20. package/dist/extensions/pi-subagents/src/agents/agent-management.ts +89 -16
  21. package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +19 -0
  22. package/dist/extensions/pi-subagents/src/agents/agents.ts +218 -120
  23. package/dist/extensions/pi-subagents/src/agents/frontmatter.ts +67 -13
  24. package/dist/extensions/pi-subagents/src/agents/proactive-skills.ts +2 -2
  25. package/dist/extensions/pi-subagents/src/agents/skills.ts +25 -12
  26. package/dist/extensions/pi-subagents/src/api/background-work.ts +197 -0
  27. package/dist/extensions/pi-subagents/src/api/capability-ceiling.ts +17 -0
  28. package/dist/extensions/pi-subagents/src/api/delegation.ts +285 -0
  29. package/dist/extensions/pi-subagents/src/api/preflight.ts +399 -0
  30. package/dist/extensions/pi-subagents/src/extension/chain-validation.ts +165 -0
  31. package/dist/extensions/pi-subagents/src/extension/config.ts +7 -1
  32. package/dist/extensions/pi-subagents/src/extension/doctor.ts +15 -0
  33. package/dist/extensions/pi-subagents/src/extension/fanout-child.ts +3 -1
  34. package/dist/extensions/pi-subagents/src/extension/index.ts +113 -157
  35. package/dist/extensions/pi-subagents/src/extension/rpc.ts +41 -4
  36. package/dist/extensions/pi-subagents/src/extension/schemas.ts +45 -15
  37. package/dist/extensions/pi-subagents/src/extension/steering-notices.ts +35 -0
  38. package/dist/extensions/pi-subagents/src/extension/tool-description.ts +28 -15
  39. package/dist/extensions/pi-subagents/src/intercom/intercom-bridge.ts +4 -3
  40. package/dist/extensions/pi-subagents/src/intercom/native-supervisor-channel.ts +225 -29
  41. package/dist/extensions/pi-subagents/src/intercom/result-intercom.ts +11 -0
  42. package/dist/extensions/pi-subagents/src/profiles/profiles.ts +8 -10
  43. package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +452 -62
  44. package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +60 -9
  45. package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +198 -52
  46. package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +119 -21
  47. package/dist/extensions/pi-subagents/src/runs/background/auto-drain.ts +67 -0
  48. package/dist/extensions/pi-subagents/src/runs/background/chain-append.ts +2 -0
  49. package/dist/extensions/pi-subagents/src/runs/background/chain-root-attachment.ts +16 -8
  50. package/dist/extensions/pi-subagents/src/runs/background/completion-batcher.ts +6 -4
  51. package/dist/extensions/pi-subagents/src/runs/background/completion-dedupe.ts +2 -11
  52. package/dist/extensions/pi-subagents/src/runs/background/control-channel.ts +260 -13
  53. package/dist/extensions/pi-subagents/src/runs/background/fleet-view.ts +32 -6
  54. package/dist/extensions/pi-subagents/src/runs/background/notify.ts +171 -90
  55. package/dist/extensions/pi-subagents/src/runs/background/process-terminal.ts +280 -0
  56. package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +149 -88
  57. package/dist/extensions/pi-subagents/src/runs/background/run-id-resolver.ts +14 -2
  58. package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +33 -17
  59. package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +9 -1
  60. package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +38 -10
  61. package/dist/extensions/pi-subagents/src/runs/background/steering.ts +237 -0
  62. package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +1297 -307
  63. package/dist/extensions/pi-subagents/src/runs/background/subagent-wait.ts +610 -0
  64. package/dist/extensions/pi-subagents/src/runs/background/top-level-async.ts +2 -1
  65. package/dist/extensions/pi-subagents/src/runs/background/wait-config.ts +36 -0
  66. package/dist/extensions/pi-subagents/src/runs/background/wait-tool.ts +26 -0
  67. package/dist/extensions/pi-subagents/src/runs/foreground/async-steering-action.ts +230 -0
  68. package/dist/extensions/pi-subagents/src/runs/foreground/chain-clarify.ts +22 -6
  69. package/dist/extensions/pi-subagents/src/runs/foreground/chain-execution.ts +228 -140
  70. package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +452 -138
  71. package/dist/extensions/pi-subagents/src/runs/foreground/foreground-control.ts +90 -0
  72. package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +1001 -416
  73. package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +443 -132
  74. package/dist/extensions/pi-subagents/src/runs/shared/agent-contract.ts +38 -0
  75. package/dist/extensions/pi-subagents/src/runs/shared/capability-ceiling.ts +178 -0
  76. package/dist/extensions/pi-subagents/src/runs/shared/child-protocol.ts +121 -0
  77. package/dist/extensions/pi-subagents/src/runs/shared/completion-guard.ts +41 -93
  78. package/dist/extensions/pi-subagents/src/runs/shared/context-mode.ts +44 -0
  79. package/dist/extensions/pi-subagents/src/runs/shared/dynamic-fanout.ts +11 -9
  80. package/dist/extensions/pi-subagents/src/runs/shared/long-running-guard.ts +4 -0
  81. package/dist/extensions/pi-subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +12 -6
  82. package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +36 -0
  83. package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +44 -7
  84. package/dist/extensions/pi-subagents/src/runs/shared/nested-render.ts +4 -1
  85. package/dist/extensions/pi-subagents/src/runs/shared/parallel-handoff.ts +154 -0
  86. package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +18 -0
  87. package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +174 -54
  88. package/dist/extensions/pi-subagents/src/runs/shared/pi-spawn.ts +38 -31
  89. package/dist/extensions/pi-subagents/src/runs/shared/run-history.ts +90 -5
  90. package/dist/extensions/pi-subagents/src/runs/shared/session-lease.ts +299 -0
  91. package/dist/extensions/pi-subagents/src/runs/shared/single-output.ts +61 -6
  92. package/dist/extensions/pi-subagents/src/runs/shared/spawn-budget.ts +128 -0
  93. package/dist/extensions/pi-subagents/src/runs/shared/structured-output.ts +112 -7
  94. package/dist/extensions/pi-subagents/src/runs/shared/subagent-control.ts +14 -6
  95. package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +149 -36
  96. package/dist/extensions/pi-subagents/src/runs/shared/task-intent.ts +181 -0
  97. package/dist/extensions/pi-subagents/src/runs/shared/tool-availability.ts +83 -0
  98. package/dist/extensions/pi-subagents/src/runs/shared/tool-budget.ts +11 -5
  99. package/dist/extensions/pi-subagents/src/runs/shared/turn-budget.ts +50 -4
  100. package/dist/extensions/pi-subagents/src/runs/shared/worktree.ts +63 -14
  101. package/dist/extensions/pi-subagents/src/shared/accessible-dir.ts +25 -0
  102. package/dist/extensions/pi-subagents/src/shared/artifacts.ts +37 -7
  103. package/dist/extensions/pi-subagents/src/shared/atomic-json.ts +18 -43
  104. package/dist/extensions/pi-subagents/src/shared/child-transcript.ts +52 -0
  105. package/dist/extensions/pi-subagents/src/shared/env.ts +16 -0
  106. package/dist/extensions/pi-subagents/src/shared/file-system-retry.ts +47 -0
  107. package/dist/extensions/pi-subagents/src/shared/fork-context.ts +28 -3
  108. package/dist/extensions/pi-subagents/src/shared/launch-contract.ts +123 -0
  109. package/dist/extensions/pi-subagents/src/shared/model-info.ts +8 -5
  110. package/dist/extensions/pi-subagents/src/shared/settings.ts +9 -1
  111. package/dist/extensions/pi-subagents/src/shared/status-format.ts +7 -1
  112. package/dist/extensions/pi-subagents/src/shared/types.ts +522 -51
  113. package/dist/extensions/pi-subagents/src/shared/utils.ts +59 -53
  114. package/dist/extensions/pi-subagents/src/slash/delegation-adapters.ts +604 -0
  115. package/dist/extensions/pi-subagents/src/slash/delegation-json.ts +108 -0
  116. package/dist/extensions/pi-subagents/src/slash/delegation-request.ts +249 -0
  117. package/dist/extensions/pi-subagents/src/slash/prompt-template-bridge.ts +353 -345
  118. package/dist/extensions/pi-subagents/src/slash/prompt-workflows.ts +2 -2
  119. package/dist/extensions/pi-subagents/src/slash/selector.ts +147 -0
  120. package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +265 -23
  121. package/dist/extensions/pi-subagents/src/slash/slash-live-state.ts +2 -2
  122. package/dist/extensions/pi-subagents/src/slash/subagents-admin.ts +428 -0
  123. package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +362 -0
  124. package/dist/extensions/pi-subagents/src/tui/fleet-transcript.ts +472 -0
  125. package/dist/extensions/pi-subagents/src/tui/fleet.ts +664 -0
  126. package/dist/extensions/pi-subagents/src/tui/render.ts +115 -31
  127. package/dist/extensions/pi-subagents/src/watchdog/change-signature.ts +220 -0
  128. package/dist/extensions/pi-subagents/src/watchdog/child-status.ts +205 -0
  129. package/dist/extensions/pi-subagents/src/watchdog/emission-guard.ts +123 -0
  130. package/dist/extensions/pi-subagents/src/watchdog/lsp-diagnostics.ts +532 -0
  131. package/dist/extensions/pi-subagents/src/watchdog/model-selection.ts +167 -0
  132. package/dist/extensions/pi-subagents/src/watchdog/register-child.ts +117 -0
  133. package/dist/extensions/pi-subagents/src/watchdog/register-main.ts +433 -0
  134. package/dist/extensions/pi-subagents/src/watchdog/render.ts +54 -0
  135. package/dist/extensions/pi-subagents/src/watchdog/review.ts +298 -0
  136. package/dist/extensions/pi-subagents/src/watchdog/runtime.ts +714 -0
  137. package/dist/extensions/pi-subagents/src/watchdog/settings.ts +528 -0
  138. package/dist/extensions/pi-subagents/src/watchdog/tool-actions.ts +155 -0
  139. package/dist/extensions/pi-subagents/src/watchdog/turn-delta.ts +161 -0
  140. package/dist/extensions/pi-subagents/src/watchdog/types.ts +188 -0
  141. package/dist/extensions/pi-subagents/src/watchdog/warning-format.ts +73 -0
  142. package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +130 -2
  143. package/dist/extensions/pi-subagents/test/integration/acceptance-file-report.test.ts +439 -0
  144. package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +1632 -61
  145. package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +54 -1
  146. package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +112 -0
  147. package/dist/extensions/pi-subagents/test/integration/chain-clarify.test.ts +98 -1
  148. package/dist/extensions/pi-subagents/test/integration/chain-execution.test.ts +179 -9
  149. package/dist/extensions/pi-subagents/test/integration/detect-error.test.ts +16 -9
  150. package/dist/extensions/pi-subagents/test/integration/error-handling.test.ts +6 -5
  151. package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +589 -9
  152. package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +528 -21
  153. package/dist/extensions/pi-subagents/test/integration/parallel-execution.test.ts +227 -3
  154. package/dist/extensions/pi-subagents/test/integration/render-fork-badge.test.ts +235 -7
  155. package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +27 -0
  156. package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +172 -2
  157. package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +1502 -18
  158. package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +993 -4
  159. package/dist/extensions/pi-subagents/test/integration/slash-live-state.test.ts +27 -0
  160. package/dist/extensions/pi-subagents/test/integration/top-level-async.test.ts +7 -1
  161. package/dist/extensions/pi-subagents/test/support/helpers.ts +32 -0
  162. package/dist/extensions/pi-subagents/test/support/mock-pi-script.mjs +59 -2
  163. package/dist/extensions/pi-subagents/test/support/mock-pi.ts +32 -6
  164. package/dist/extensions/pi-subagents/test/support/real-session-child-cli.mjs +25 -24
  165. package/dist/extensions/pi-subagents/test/support/real-session-runner.ts +59 -35
  166. package/dist/extensions/pi-subagents/test/support/session-lease-child.mjs +42 -0
  167. package/dist/extensions/pi-subagents/test/unit/acceptance.test.ts +703 -69
  168. package/dist/extensions/pi-subagents/test/unit/accessible-dir.test.ts +82 -0
  169. package/dist/extensions/pi-subagents/test/unit/agent-disabled.test.ts +15 -15
  170. package/dist/extensions/pi-subagents/test/unit/agent-eject-disable.test.ts +66 -66
  171. package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +478 -19
  172. package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +228 -7
  173. package/dist/extensions/pi-subagents/test/unit/agent-memory.test.ts +1 -1
  174. package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +198 -78
  175. package/dist/extensions/pi-subagents/test/unit/async-execution.test.ts +15 -1
  176. package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +102 -7
  177. package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +439 -6
  178. package/dist/extensions/pi-subagents/test/unit/atomic-json.test.ts +41 -1
  179. package/dist/extensions/pi-subagents/test/unit/auto-drain.test.ts +79 -0
  180. package/dist/extensions/pi-subagents/test/unit/background-work.test.ts +285 -0
  181. package/dist/extensions/pi-subagents/test/unit/capability-ceiling-pi-args.test.ts +84 -0
  182. package/dist/extensions/pi-subagents/test/unit/capability-ceiling.test.ts +68 -0
  183. package/dist/extensions/pi-subagents/test/unit/chain-validation.test.ts +326 -0
  184. package/dist/extensions/pi-subagents/test/unit/child-protocol.test.ts +82 -0
  185. package/dist/extensions/pi-subagents/test/unit/child-transcript.test.ts +46 -4
  186. package/dist/extensions/pi-subagents/test/unit/completion-batcher.test.ts +3 -1
  187. package/dist/extensions/pi-subagents/test/unit/completion-dedupe.test.ts +9 -17
  188. package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +175 -3
  189. package/dist/extensions/pi-subagents/test/unit/config-dir-runtime.test.ts +10 -5
  190. package/dist/extensions/pi-subagents/test/unit/control-channel.test.ts +126 -6
  191. package/dist/extensions/pi-subagents/test/unit/default-extensions.test.ts +219 -0
  192. package/dist/extensions/pi-subagents/test/unit/delegation-api.test.ts +913 -0
  193. package/dist/extensions/pi-subagents/test/unit/doctor.test.ts +13 -2
  194. package/dist/extensions/pi-subagents/test/unit/dynamic-fanout.test.ts +3 -3
  195. package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +351 -0
  196. package/dist/extensions/pi-subagents/test/unit/fleet-transcript.test.ts +280 -0
  197. package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +575 -0
  198. package/dist/extensions/pi-subagents/test/unit/foreground-control.test.ts +65 -0
  199. package/dist/extensions/pi-subagents/test/unit/fork-context.test.ts +94 -1
  200. package/dist/extensions/pi-subagents/test/unit/get-final-output.test.ts +23 -0
  201. package/dist/extensions/pi-subagents/test/unit/host-peer-runtime-imports.test.ts +157 -0
  202. package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +367 -5
  203. package/dist/extensions/pi-subagents/test/unit/intercom-bridge.test.ts +11 -0
  204. package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +36 -0
  205. package/dist/extensions/pi-subagents/test/unit/model-info.test.ts +25 -3
  206. package/dist/extensions/pi-subagents/test/unit/model-scope.test.ts +1 -1
  207. package/dist/extensions/pi-subagents/test/unit/native-supervisor-channel.test.ts +341 -10
  208. package/dist/extensions/pi-subagents/test/unit/nested-control.test.ts +16 -0
  209. package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +52 -0
  210. package/dist/extensions/pi-subagents/test/unit/notify.test.ts +168 -7
  211. package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +85 -7
  212. package/dist/extensions/pi-subagents/test/unit/parallel-handoff.test.ts +175 -0
  213. package/dist/extensions/pi-subagents/test/unit/path-resolution.test.ts +1 -1
  214. package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +243 -16
  215. package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +79 -36
  216. package/dist/extensions/pi-subagents/test/unit/pi-spawn.test.ts +174 -56
  217. package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +322 -0
  218. package/dist/extensions/pi-subagents/test/unit/process-terminal.test.ts +204 -0
  219. package/dist/extensions/pi-subagents/test/unit/recursion-guard.test.ts +20 -12
  220. package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +117 -4
  221. package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +40 -7
  222. package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +48 -1
  223. package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +21 -3
  224. package/dist/extensions/pi-subagents/test/unit/selector.test.ts +57 -0
  225. package/dist/extensions/pi-subagents/test/unit/session-lease.test.ts +326 -0
  226. package/dist/extensions/pi-subagents/test/unit/single-output.test.ts +101 -2
  227. package/dist/extensions/pi-subagents/test/unit/skills-fallback.test.ts +111 -1
  228. package/dist/extensions/pi-subagents/test/unit/spawn-budget.test.ts +124 -0
  229. package/dist/extensions/pi-subagents/test/unit/stale-run-reconciler.test.ts +6 -4
  230. package/dist/extensions/pi-subagents/test/unit/status-format.test.ts +7 -0
  231. package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +397 -0
  232. package/dist/extensions/pi-subagents/test/unit/steering-notices.test.ts +58 -0
  233. package/dist/extensions/pi-subagents/test/unit/steering.test.ts +173 -0
  234. package/dist/extensions/pi-subagents/test/unit/subagent-control.test.ts +25 -4
  235. package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +390 -25
  236. package/dist/extensions/pi-subagents/test/unit/subagent-wait.test.ts +837 -0
  237. package/dist/extensions/pi-subagents/test/unit/task-intent.test.ts +86 -0
  238. package/dist/extensions/pi-subagents/test/unit/tool-budget.test.ts +15 -0
  239. package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +47 -1
  240. package/dist/extensions/pi-subagents/test/unit/turn-budget.test.ts +56 -10
  241. package/dist/extensions/pi-subagents/test/unit/watchdog-change-signature.test.ts +387 -0
  242. package/dist/extensions/pi-subagents/test/unit/watchdog-child-status.test.ts +110 -0
  243. package/dist/extensions/pi-subagents/test/unit/watchdog-emission-guard.test.ts +62 -0
  244. package/dist/extensions/pi-subagents/test/unit/watchdog-lsp-diagnostics.test.ts +144 -0
  245. package/dist/extensions/pi-subagents/test/unit/watchdog-model-selection.test.ts +121 -0
  246. package/dist/extensions/pi-subagents/test/unit/watchdog-render.test.ts +76 -0
  247. package/dist/extensions/pi-subagents/test/unit/watchdog-review.test.ts +327 -0
  248. package/dist/extensions/pi-subagents/test/unit/watchdog-runtime.test.ts +863 -0
  249. package/dist/extensions/pi-subagents/test/unit/watchdog-settings.test.ts +290 -0
  250. package/dist/extensions/pi-subagents/test/unit/watchdog-tool-actions.test.ts +91 -0
  251. package/dist/extensions/pi-subagents/test/unit/watchdog-turn-delta.test.ts +130 -0
  252. package/dist/extensions/pi-subagents/test/unit/widget-nested-render.test.ts +32 -4
  253. package/dist/extensions/pi-subagents/test/unit/worktree.test.ts +5 -1
  254. package/dist/extensions/pi-subagents/test/unit/writer-budget-guidance.test.ts +30 -0
  255. package/dist/extensions/question/batch.ts +39 -0
  256. package/dist/extensions/question/dialog-adapter.ts +23 -1
  257. package/dist/extensions/question/index.ts +237 -7
  258. package/dist/extensions/question/schemas.ts +28 -15
  259. package/dist/extensions/question/tests/batch.test.ts +26 -0
  260. package/dist/extensions/question/tests/ui-protocol.test.ts +23 -3
  261. package/dist/extensions/question/tui-adapter.ts +2 -3
  262. package/dist/extensions/question/types.ts +37 -0
  263. package/dist/extensions/question/ui-protocol.ts +3 -3
  264. package/dist/skills/batch-grill-me/SKILL.md +3 -1
  265. package/package.json +2 -1
@@ -4,19 +4,23 @@
4
4
 
5
5
  import { execSync } from "node:child_process";
6
6
  import * as fs from "node:fs";
7
+ import { parse as parseYaml } from "yaml";
7
8
  import * as os from "node:os";
9
+ import "../shared/env.ts";
8
10
  import * as path from "node:path";
9
11
  import { fileURLToPath } from "node:url";
10
- import type { AcceptanceInput, OutputMode, ToolBudgetConfig } from "../shared/types.ts";
12
+ import type { AcceptanceInput, AcceptanceRole, OutputMode, ToolBudgetConfig, TurnBudgetConfig } from "../shared/types.ts";
11
13
  import { getAgentDir, getProjectConfigDir } from "../shared/utils.ts";
12
14
  import { KNOWN_FIELDS } from "./agent-serializer.ts";
13
15
  import { parseChain, parseJsonChain } from "./chain-serializer.ts";
14
16
  import { mergeAgentsForScope } from "./agent-selection.ts";
15
- import { parseFrontmatter } from "./frontmatter.ts";
17
+ import { parseFrontmatter, parseFrontmatterList } from "./frontmatter.ts";
16
18
  import { buildRuntimeName, parsePackageName } from "./identity.ts";
17
19
  import { parseModelScopeConfig, type ModelScopeConfig } from "../runs/shared/model-scope.ts";
18
20
  export { buildRuntimeName, frontmatterNameForConfig, parsePackageName } from "./identity.ts";
19
21
  import { parseMemoryFrontmatter } from "./agent-memory.ts";
22
+ import { resolveTurnBudgetConfig } from "../runs/shared/turn-budget.ts";
23
+ import { validateAcceptanceInput } from "../runs/shared/acceptance.ts";
20
24
 
21
25
  export type AgentScope = "user" | "project" | "both";
22
26
 
@@ -32,14 +36,12 @@ export interface AgentMemoryConfig {
32
36
  }
33
37
 
34
38
  export const BUILTIN_AGENT_NAMES = [
35
- "context-builder",
36
- "delegate",
37
- "oracle",
38
- "planner",
39
+ "architect",
40
+ "builder",
41
+ "commentator",
42
+ "explorer",
43
+ "recapper",
39
44
  "researcher",
40
- "reviewer",
41
- "scout",
42
- "worker",
43
45
  ] as const;
44
46
 
45
47
  export function defaultSystemPromptMode(name: string): SystemPromptMode {
@@ -57,16 +59,19 @@ export function defaultInheritSkills(): boolean {
57
59
  export interface BuiltinAgentOverrideBase {
58
60
  model?: string;
59
61
  fallbackModels?: string[];
60
- thinking?: string;
62
+ thinking?: string | false;
61
63
  systemPromptMode: SystemPromptMode;
62
64
  inheritProjectContext: boolean;
63
65
  inheritSkills: boolean;
64
66
  defaultContext?: AgentDefaultContext;
67
+ acceptanceRole?: AcceptanceRole;
65
68
  disabled?: boolean;
66
69
  systemPrompt: string;
67
70
  skills?: string[];
71
+ skillPath?: string[];
68
72
  tools?: string[];
69
73
  mcpDirectTools?: string[];
74
+ extensions?: string[];
70
75
  subagentOnlyExtensions?: string[];
71
76
  completionGuard?: boolean;
72
77
  toolBudget?: ToolBudgetConfig;
@@ -80,10 +85,12 @@ interface BuiltinAgentOverrideConfig {
80
85
  inheritProjectContext?: boolean;
81
86
  inheritSkills?: boolean;
82
87
  defaultContext?: AgentDefaultContext | false;
88
+ acceptanceRole?: AcceptanceRole | false;
83
89
  disabled?: boolean;
84
90
  systemPrompt?: string;
85
91
  skills?: string[] | false;
86
92
  tools?: string[] | false;
93
+ extensions?: string[] | false;
87
94
  subagentOnlyExtensions?: string[] | false;
88
95
  completionGuard?: boolean;
89
96
  toolBudget?: ToolBudgetConfig | false;
@@ -111,16 +118,23 @@ export interface AgentConfig {
111
118
  mcpDirectTools?: string[];
112
119
  model?: string;
113
120
  fallbackModels?: string[];
114
- thinking?: string;
121
+ thinking?: string | false;
115
122
  systemPromptMode: SystemPromptMode;
116
123
  inheritProjectContext: boolean;
117
124
  inheritSkills: boolean;
118
125
  defaultContext?: AgentDefaultContext;
126
+ defaultAsync?: boolean;
127
+ defaultTimeoutMs?: number;
128
+ defaultTurnBudget?: TurnBudgetConfig;
129
+ defaultAcceptance?: AcceptanceInput;
130
+ acceptanceRole?: AcceptanceRole;
119
131
  systemPrompt: string;
120
132
  source: AgentSource;
121
133
  filePath: string;
122
134
  skills?: string[];
135
+ skillPath?: string[];
123
136
  extensions?: string[];
137
+ extensionsFromDefault?: boolean;
124
138
  subagentOnlyExtensions?: string[];
125
139
  output?: string;
126
140
  defaultReads?: string[];
@@ -139,6 +153,8 @@ export interface AgentConfig {
139
153
  interface SubagentSettings {
140
154
  overrides: Record<string, BuiltinAgentOverrideConfig>;
141
155
  defaultModel?: string;
156
+ defaultThinking?: string;
157
+ defaultExtensions?: string[];
142
158
  disableBuiltins?: boolean;
143
159
  disableThinking?: boolean;
144
160
  modelScope?: ModelScopeConfig;
@@ -301,6 +317,8 @@ function resolveSettingsPackageRoot(source: string, baseDir: string): string | u
301
317
  }
302
318
 
303
319
  function getGlobalNpmRoot(): string | null {
320
+ const offline = process.env.PI_OFFLINE?.toLowerCase();
321
+ if (offline === "1" || offline === "true" || offline === "yes") return null;
304
322
  if (cachedGlobalNpmRoot !== null) return cachedGlobalNpmRoot;
305
323
  try {
306
324
  cachedGlobalNpmRoot = fs.realpathSync(execSync("npm root -g", { encoding: "utf-8", timeout: 5000 }).trim());
@@ -462,7 +480,7 @@ function splitToolList(rawTools: string[] | undefined): { tools?: string[]; mcpD
462
480
  }
463
481
  }
464
482
  return {
465
- ...(tools.length > 0 ? { tools } : {}),
483
+ ...(rawTools !== undefined ? { tools } : {}),
466
484
  ...(mcpDirectTools.length > 0 ? { mcpDirectTools } : {}),
467
485
  };
468
486
  }
@@ -494,11 +512,14 @@ function cloneOverrideBase(agent: AgentConfig): BuiltinAgentOverrideBase {
494
512
  inheritProjectContext: agent.inheritProjectContext,
495
513
  inheritSkills: agent.inheritSkills,
496
514
  defaultContext: agent.defaultContext,
515
+ acceptanceRole: agent.acceptanceRole,
497
516
  disabled: agent.disabled,
498
517
  systemPrompt: agent.systemPrompt,
499
518
  skills: agent.skills ? [...agent.skills] : undefined,
519
+ skillPath: agent.skillPath ? [...agent.skillPath] : undefined,
500
520
  tools: agent.tools ? [...agent.tools] : undefined,
501
521
  mcpDirectTools: agent.mcpDirectTools ? [...agent.mcpDirectTools] : undefined,
522
+ extensions: agent.extensionsFromDefault ? undefined : agent.extensions ? [...agent.extensions] : undefined,
502
523
  subagentOnlyExtensions: agent.subagentOnlyExtensions ? [...agent.subagentOnlyExtensions] : undefined,
503
524
  completionGuard: agent.completionGuard,
504
525
  toolBudget: agent.toolBudget,
@@ -516,10 +537,12 @@ function cloneOverrideValue(override: BuiltinAgentOverrideConfig): BuiltinAgentO
516
537
  ...(override.inheritProjectContext !== undefined ? { inheritProjectContext: override.inheritProjectContext } : {}),
517
538
  ...(override.inheritSkills !== undefined ? { inheritSkills: override.inheritSkills } : {}),
518
539
  ...(override.defaultContext !== undefined ? { defaultContext: override.defaultContext } : {}),
540
+ ...(override.acceptanceRole !== undefined ? { acceptanceRole: override.acceptanceRole } : {}),
519
541
  ...(override.disabled !== undefined ? { disabled: override.disabled } : {}),
520
542
  ...(override.systemPrompt !== undefined ? { systemPrompt: override.systemPrompt } : {}),
521
543
  ...(override.skills !== undefined ? { skills: override.skills === false ? false : [...override.skills] } : {}),
522
544
  ...(override.tools !== undefined ? { tools: override.tools === false ? false : [...override.tools] } : {}),
545
+ ...(override.extensions !== undefined ? { extensions: override.extensions === false ? false : [...override.extensions] } : {}),
523
546
  ...(override.subagentOnlyExtensions !== undefined ? { subagentOnlyExtensions: override.subagentOnlyExtensions === false ? false : [...override.subagentOnlyExtensions] } : {}),
524
547
  ...(override.completionGuard !== undefined ? { completionGuard: override.completionGuard } : {}),
525
548
  ...(override.toolBudget !== undefined ? { toolBudget: override.toolBudget === false ? false : { ...override.toolBudget, ...(Array.isArray(override.toolBudget.block) ? { block: [...override.toolBudget.block] } : {}) } } : {}),
@@ -543,52 +566,6 @@ function getUserAgentSettingsPath(): string {
543
566
  return path.join(getAgentDir(), "settings.json");
544
567
  }
545
568
 
546
- /**
547
- * Seed the user-visible subagent configuration on first session startup.
548
- *
549
- * Builtin agents normally inherit the parent session model. Recording that
550
- * model as `subagents.defaultModel` makes the default explicit. Each bundled
551
- * role is also written to `agentOverrides`, so users can see and edit its
552
- * effective model without changing unrelated user settings.
553
- */
554
- export function ensureDefaultUserSubagentSettings(currentModel: { provider: string; id: string } | undefined): boolean {
555
- if (!currentModel?.provider || !currentModel.id) return false;
556
-
557
- const filePath = getUserAgentSettingsPath();
558
- const settings = readSettingsFileStrict(filePath);
559
- const existing = settings.subagents;
560
- if (existing !== undefined && (!existing || typeof existing !== "object" || Array.isArray(existing))) return false;
561
-
562
- const subagents = (existing ?? {}) as Record<string, unknown>;
563
- const currentModelId = `${currentModel.provider}/${currentModel.id}`;
564
- if ("defaultModel" in subagents && (typeof subagents.defaultModel !== "string" || !subagents.defaultModel.trim())) return false;
565
-
566
- let changed = false;
567
- if (!("defaultModel" in subagents)) {
568
- subagents.defaultModel = currentModelId;
569
- changed = true;
570
- }
571
-
572
- const defaultModel = subagents.defaultModel as string;
573
- const overrides = subagents.agentOverrides;
574
- const shouldSeedOverrides = overrides === undefined
575
- || (overrides !== null && typeof overrides === "object" && !Array.isArray(overrides) && Object.keys(overrides).length === 0);
576
- if (shouldSeedOverrides) {
577
- subagents.agentOverrides = Object.fromEntries(
578
- loadAgentsFromDir(BUILTIN_AGENTS_DIR, "builtin").map((agent) => [
579
- agent.name,
580
- { model: agent.model ?? defaultModel },
581
- ]),
582
- );
583
- changed = true;
584
- }
585
- if (!changed) return false;
586
-
587
- settings.subagents = subagents;
588
- writeSettingsFile(filePath, settings);
589
- return true;
590
- }
591
-
592
569
  function getProjectAgentSettingsPath(cwd: string): string | null {
593
570
  const projectRoot = findNearestProjectRoot(cwd);
594
571
  return projectRoot ? path.join(getProjectConfigDir(projectRoot), "settings.json") : null;
@@ -697,6 +674,14 @@ function parseBuiltinOverrideEntry(
697
674
  }
698
675
  }
699
676
 
677
+ if ("acceptanceRole" in input) {
678
+ if (input.acceptanceRole === "read-only" || input.acceptanceRole === "writer" || input.acceptanceRole === false) {
679
+ override.acceptanceRole = input.acceptanceRole;
680
+ } else {
681
+ throw new Error(`Builtin override '${name}' in '${filePath}' has invalid 'acceptanceRole'; expected 'read-only', 'writer', or false.`);
682
+ }
683
+ }
684
+
700
685
  if ("disabled" in input) {
701
686
  if (typeof input.disabled === "boolean") {
702
687
  override.disabled = input.disabled;
@@ -737,6 +722,9 @@ function parseBuiltinOverrideEntry(
737
722
  const tools = parseOverrideStringArrayOrFalse(input.tools, { filePath, name, field: "tools" });
738
723
  if (tools !== undefined) override.tools = tools;
739
724
 
725
+ const extensions = parseOverrideStringArrayOrFalse(input.extensions, { filePath, name, field: "extensions" });
726
+ if (extensions !== undefined) override.extensions = extensions;
727
+
740
728
  const subagentOnlyExtensions = parseOverrideStringArrayOrFalse(input.subagentOnlyExtensions, { filePath, name, field: "subagentOnlyExtensions" });
741
729
  if (subagentOnlyExtensions !== undefined) override.subagentOnlyExtensions = subagentOnlyExtensions;
742
730
 
@@ -774,18 +762,34 @@ function readSubagentSettings(filePath: string | null): SubagentSettings {
774
762
  throw new Error(`Subagent settings in '${filePath}' have invalid 'defaultModel'; expected a non-empty string.`);
775
763
  }
776
764
  }
765
+ let defaultThinking: string | undefined;
766
+ if ("defaultThinking" in subagentsObject) {
767
+ if (typeof subagentsObject.defaultThinking === "string" && subagentsObject.defaultThinking.trim()) {
768
+ defaultThinking = subagentsObject.defaultThinking.trim();
769
+ } else {
770
+ throw new Error(`Subagent settings in '${filePath}' have invalid 'defaultThinking'; expected a non-empty string.`);
771
+ }
772
+ }
773
+ let defaultExtensions: string[] | undefined;
774
+ if ("defaultExtensions" in subagentsObject) {
775
+ if (!Array.isArray(subagentsObject.defaultExtensions)
776
+ || subagentsObject.defaultExtensions.some((item) => typeof item !== "string" || !item.trim())) {
777
+ throw new Error(`Subagent settings in '${filePath}' have invalid 'defaultExtensions'; expected an array of non-empty strings.`);
778
+ }
779
+ defaultExtensions = subagentsObject.defaultExtensions.map((item) => item.trim());
780
+ }
777
781
  const modelScope = parseModelScopeConfig(subagentsObject.modelScope, { filePath });
778
782
 
779
783
  const parsed: Record<string, BuiltinAgentOverrideConfig> = {};
780
784
  const agentOverrides = subagentsObject.agentOverrides;
781
785
  if (!agentOverrides || typeof agentOverrides !== "object" || Array.isArray(agentOverrides)) {
782
- return { overrides: parsed, defaultModel, disableBuiltins, disableThinking, modelScope };
786
+ return { overrides: parsed, defaultModel, defaultThinking, defaultExtensions, disableBuiltins, disableThinking, modelScope };
783
787
  }
784
788
  for (const [name, value] of Object.entries(agentOverrides)) {
785
789
  const override = parseBuiltinOverrideEntry(name, value, filePath);
786
790
  if (override) parsed[name] = override;
787
791
  }
788
- return { overrides: parsed, defaultModel, disableBuiltins, disableThinking, modelScope };
792
+ return { overrides: parsed, defaultModel, defaultThinking, defaultExtensions, disableBuiltins, disableThinking, modelScope };
789
793
  }
790
794
 
791
795
  function resolveSubagentDefaultModel(
@@ -813,6 +817,58 @@ function applySubagentDefaultModel(agents: AgentConfig[], defaultModel: AgentMod
813
817
  });
814
818
  }
815
819
 
820
+ function resolveSubagentDefaultThinking(
821
+ userSettings: SubagentSettings,
822
+ projectSettings: SubagentSettings,
823
+ projectSettingsPath: string | null,
824
+ ): string | undefined {
825
+ if (projectSettingsPath && projectSettings.defaultThinking !== undefined) return projectSettings.defaultThinking;
826
+ return userSettings.defaultThinking;
827
+ }
828
+
829
+ function applySubagentDefaultThinking(agents: AgentConfig[], defaultThinking: string | undefined): AgentConfig[] {
830
+ if (defaultThinking === undefined) return agents;
831
+ return agents.map((agent) => {
832
+ if (agent.thinking !== undefined) return agent;
833
+ const next = { ...agent, thinking: defaultThinking };
834
+ const frontmatterFields = agentFrontmatterFields.get(agent);
835
+ if (frontmatterFields) agentFrontmatterFields.set(next, frontmatterFields);
836
+ return next;
837
+ });
838
+ }
839
+
840
+ function resolveSubagentDefaultExtensions(
841
+ userSettings: SubagentSettings,
842
+ projectSettings: SubagentSettings,
843
+ projectSettingsPath: string | null,
844
+ ): string[] | undefined {
845
+ if (projectSettingsPath && projectSettings.defaultExtensions !== undefined) return projectSettings.defaultExtensions;
846
+ return userSettings.defaultExtensions;
847
+ }
848
+
849
+ function applySubagentDefaultExtensions(agents: AgentConfig[], defaultExtensions: string[] | undefined): AgentConfig[] {
850
+ if (defaultExtensions === undefined) return agents;
851
+ return agents.map((agent) => {
852
+ if (agent.extensions !== undefined) return agent;
853
+ const next = { ...agent, extensions: [...defaultExtensions], extensionsFromDefault: true };
854
+ const frontmatterFields = agentFrontmatterFields.get(agent);
855
+ if (frontmatterFields) agentFrontmatterFields.set(next, frontmatterFields);
856
+ return next;
857
+ });
858
+ }
859
+
860
+ function applySubagentDefaults(
861
+ agents: AgentConfig[],
862
+ defaultModel: AgentModelSourceInfo | undefined,
863
+ defaultThinking: string | undefined,
864
+ defaultExtensions: string[] | undefined,
865
+ ): AgentConfig[] {
866
+ return applySubagentDefaultExtensions(
867
+ applySubagentDefaultThinking(applySubagentDefaultModel(agents, defaultModel), defaultThinking),
868
+ defaultExtensions,
869
+ );
870
+ }
871
+
816
872
  function applyBuiltinOverride(
817
873
  agent: AgentConfig,
818
874
  override: BuiltinAgentOverrideConfig,
@@ -832,6 +888,7 @@ function applyBuiltinOverride(
832
888
  if (override.inheritProjectContext !== undefined) next.inheritProjectContext = override.inheritProjectContext;
833
889
  if (override.inheritSkills !== undefined) next.inheritSkills = override.inheritSkills;
834
890
  if (override.defaultContext !== undefined) next.defaultContext = override.defaultContext === false ? undefined : override.defaultContext;
891
+ if (override.acceptanceRole !== undefined) next.acceptanceRole = override.acceptanceRole === false ? undefined : override.acceptanceRole;
835
892
  if (override.disabled !== undefined) next.disabled = override.disabled;
836
893
  if (override.systemPrompt !== undefined) next.systemPrompt = override.systemPrompt;
837
894
  if (override.skills !== undefined) next.skills = override.skills === false ? undefined : [...override.skills];
@@ -840,6 +897,7 @@ function applyBuiltinOverride(
840
897
  next.tools = tools;
841
898
  next.mcpDirectTools = mcpDirectTools;
842
899
  }
900
+ if (override.extensions !== undefined) next.extensions = override.extensions === false ? undefined : [...override.extensions];
843
901
  if (override.subagentOnlyExtensions !== undefined) {
844
902
  next.subagentOnlyExtensions = override.subagentOnlyExtensions === false ? undefined : [...override.subagentOnlyExtensions];
845
903
  }
@@ -913,7 +971,7 @@ function applyBuiltinOverrides(
913
971
  });
914
972
  }
915
973
 
916
- function customAgentHasFrontmatterField(agent: AgentConfig, ...fields: string[]): boolean {
974
+ export function agentHasFrontmatterField(agent: AgentConfig, ...fields: string[]): boolean {
917
975
  const frontmatterFields = agentFrontmatterFields.get(agent);
918
976
  return frontmatterFields ? fields.some((field) => frontmatterFields.has(field)) : false;
919
977
  }
@@ -936,7 +994,7 @@ function applyCustomAgentOverride(
936
994
  frontmatterFields: string[],
937
995
  value: AgentConfig[K],
938
996
  ): void => {
939
- if (customAgentHasFrontmatterField(agent, ...frontmatterFields)) return;
997
+ if (agentHasFrontmatterField(agent, ...frontmatterFields)) return;
940
998
  mutable()[field] = value;
941
999
  anyFilled = true;
942
1000
  };
@@ -966,6 +1024,9 @@ function applyCustomAgentOverride(
966
1024
  if (override.defaultContext !== undefined) {
967
1025
  fill("defaultContext", ["defaultContext"], override.defaultContext === false ? undefined : override.defaultContext);
968
1026
  }
1027
+ if (override.acceptanceRole !== undefined) {
1028
+ fill("acceptanceRole", ["acceptanceRole"], override.acceptanceRole === false ? undefined : override.acceptanceRole);
1029
+ }
969
1030
  if (override.disabled !== undefined && agent.disabled === undefined) {
970
1031
  mutable().disabled = override.disabled;
971
1032
  anyFilled = true;
@@ -973,13 +1034,16 @@ function applyCustomAgentOverride(
973
1034
  if (override.skills !== undefined) {
974
1035
  fill("skills", ["skill", "skills"], override.skills === false ? undefined : [...override.skills]);
975
1036
  }
976
- if (override.tools !== undefined && !customAgentHasFrontmatterField(agent, "tools")) {
1037
+ if (override.tools !== undefined && !agentHasFrontmatterField(agent, "tools")) {
977
1038
  const { tools, mcpDirectTools } = splitToolList(override.tools === false ? [] : override.tools);
978
1039
  const target = mutable();
979
1040
  target.tools = tools;
980
1041
  target.mcpDirectTools = mcpDirectTools;
981
1042
  anyFilled = true;
982
1043
  }
1044
+ if (override.extensions !== undefined) {
1045
+ fill("extensions", ["extensions"], override.extensions === false ? undefined : [...override.extensions]);
1046
+ }
983
1047
  if (override.subagentOnlyExtensions !== undefined) {
984
1048
  fill(
985
1049
  "subagentOnlyExtensions",
@@ -996,6 +1060,8 @@ function applyCustomAgentOverride(
996
1060
 
997
1061
  if (!anyFilled || !next) return agent;
998
1062
  next.override = { ...meta, base: cloneOverrideBase(agent) };
1063
+ const frontmatterFields = agentFrontmatterFields.get(agent);
1064
+ if (frontmatterFields) agentFrontmatterFields.set(next, frontmatterFields);
999
1065
  return next;
1000
1066
  }
1001
1067
 
@@ -1023,7 +1089,7 @@ function applyCustomAgentOverrides(
1023
1089
 
1024
1090
  export function buildBuiltinOverrideConfig(
1025
1091
  base: BuiltinAgentOverrideBase,
1026
- draft: Pick<AgentConfig, "model" | "fallbackModels" | "thinking" | "systemPromptMode" | "inheritProjectContext" | "inheritSkills" | "defaultContext" | "disabled" | "systemPrompt" | "skills" | "tools" | "mcpDirectTools" | "subagentOnlyExtensions" | "completionGuard" | "toolBudget">,
1092
+ draft: Pick<AgentConfig, "model" | "fallbackModels" | "thinking" | "systemPromptMode" | "inheritProjectContext" | "inheritSkills" | "defaultContext" | "acceptanceRole" | "disabled" | "systemPrompt" | "skills" | "tools" | "mcpDirectTools" | "extensions" | "subagentOnlyExtensions" | "completionGuard" | "toolBudget">,
1027
1093
  ): BuiltinAgentOverrideConfig | undefined {
1028
1094
  const override: BuiltinAgentOverrideConfig = {};
1029
1095
 
@@ -1034,6 +1100,7 @@ export function buildBuiltinOverrideConfig(
1034
1100
  if (draft.inheritProjectContext !== base.inheritProjectContext) override.inheritProjectContext = draft.inheritProjectContext;
1035
1101
  if (draft.inheritSkills !== base.inheritSkills) override.inheritSkills = draft.inheritSkills;
1036
1102
  if (draft.defaultContext !== base.defaultContext) override.defaultContext = draft.defaultContext ?? false;
1103
+ if (draft.acceptanceRole !== base.acceptanceRole) override.acceptanceRole = draft.acceptanceRole ?? false;
1037
1104
  if (draft.disabled !== base.disabled) override.disabled = draft.disabled ?? false;
1038
1105
  if (draft.systemPrompt !== base.systemPrompt) override.systemPrompt = draft.systemPrompt;
1039
1106
  if (!arraysEqual(draft.skills, base.skills)) override.skills = draft.skills ? [...draft.skills] : false;
@@ -1041,6 +1108,7 @@ export function buildBuiltinOverrideConfig(
1041
1108
  const baseTools = joinToolList(base);
1042
1109
  const draftTools = joinToolList(draft);
1043
1110
  if (!arraysEqual(draftTools, baseTools)) override.tools = draftTools ? [...draftTools] : false;
1111
+ if (!arraysEqual(draft.extensions, base.extensions)) override.extensions = draft.extensions ? [...draft.extensions] : false;
1044
1112
  if (!arraysEqual(draft.subagentOnlyExtensions, base.subagentOnlyExtensions)) {
1045
1113
  override.subagentOnlyExtensions = draft.subagentOnlyExtensions ? [...draft.subagentOnlyExtensions] : false;
1046
1114
  }
@@ -1173,7 +1241,19 @@ export function removeBuiltinAgentOverrideFields(
1173
1241
  return { path: filePath, removed: true };
1174
1242
  }
1175
1243
 
1176
- function listFilesRecursive(dir: string, predicate: (fileName: string) => boolean): string[] {
1244
+ const DISCOVERY_PRUNED_DIR_NAMES = new Set([".git", "node_modules"]);
1245
+
1246
+ function isDiscoveryNestedProjectRoot(dir: string): boolean {
1247
+ return isDirectory(getProjectConfigDir(dir)) || isDirectory(path.join(dir, ".agents"));
1248
+ }
1249
+
1250
+ function shouldPruneDiscoveryDir(rootDir: string, dir: string, dirName: string): boolean {
1251
+ if (DISCOVERY_PRUNED_DIR_NAMES.has(dirName)) return true;
1252
+ if (fs.existsSync(path.join(dir, ".git"))) return true;
1253
+ return path.resolve(dir) !== path.resolve(rootDir) && isDiscoveryNestedProjectRoot(dir);
1254
+ }
1255
+
1256
+ function listFilesRecursive(dir: string, predicate: (fileName: string) => boolean, rootDir = dir): string[] {
1177
1257
  const files: string[] = [];
1178
1258
  if (!fs.existsSync(dir)) return files;
1179
1259
 
@@ -1187,7 +1267,9 @@ function listFilesRecursive(dir: string, predicate: (fileName: string) => boolea
1187
1267
  for (const entry of entries) {
1188
1268
  const filePath = path.join(dir, entry.name);
1189
1269
  if (entry.isDirectory()) {
1190
- files.push(...listFilesRecursive(filePath, predicate));
1270
+ if (!shouldPruneDiscoveryDir(rootDir, filePath, entry.name)) {
1271
+ files.push(...listFilesRecursive(filePath, predicate, rootDir));
1272
+ }
1191
1273
  continue;
1192
1274
  }
1193
1275
  if (!entry.isFile() && !entry.isSymbolicLink()) continue;
@@ -1206,6 +1288,19 @@ function isLegacyAgentSkillPath(rootDir: string, filePath: string): boolean {
1206
1288
  return parts.some((part, index) => part === ".agents" && parts[index + 1] === "skills");
1207
1289
  }
1208
1290
 
1291
+ function parseAgentAcceptanceFrontmatter(raw: string | undefined, agentName: string): AcceptanceInput | undefined {
1292
+ if (raw === undefined || !raw.trim()) return undefined;
1293
+ let parsed: unknown;
1294
+ try {
1295
+ parsed = parseYaml(raw);
1296
+ } catch (error) {
1297
+ throw new Error(`Agent '${agentName}' has invalid acceptance frontmatter: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
1298
+ }
1299
+ const errors = validateAcceptanceInput(parsed, `Agent '${agentName}' acceptance frontmatter`);
1300
+ if (errors.length > 0) throw new Error(errors.join(" "));
1301
+ return parsed as AcceptanceInput;
1302
+ }
1303
+
1209
1304
  function loadAgentsFromDir(dir: string, source: AgentSource): AgentConfig[] {
1210
1305
  const agents: AgentConfig[] = [];
1211
1306
 
@@ -1233,37 +1328,15 @@ function loadAgentsFromDir(dir: string, source: AgentSource): AgentConfig[] {
1233
1328
  const packageName = parsedPackage.packageName;
1234
1329
  const runtimeName = buildRuntimeName(localName, packageName);
1235
1330
 
1236
- const rawTools = frontmatter.tools
1237
- ?.split(",")
1238
- .map((t) => t.trim())
1239
- .filter(Boolean);
1240
-
1241
- const mcpDirectTools: string[] = [];
1242
- const tools: string[] = [];
1243
- if (rawTools) {
1244
- for (const tool of rawTools) {
1245
- if (tool.startsWith("mcp:")) {
1246
- mcpDirectTools.push(tool.slice(4));
1247
- } else {
1248
- tools.push(tool);
1249
- }
1250
- }
1251
- }
1252
-
1253
- const defaultReads = frontmatter.defaultReads
1254
- ?.split(",")
1255
- .map((f) => f.trim())
1256
- .filter(Boolean);
1257
-
1331
+ const rawTools = parseFrontmatterList(frontmatter.tools);
1332
+ const parsedTools = splitToolList(rawTools);
1333
+ const tools = parsedTools.tools ?? [];
1334
+ const mcpDirectTools = parsedTools.mcpDirectTools ?? [];
1335
+ const defaultReads = parseFrontmatterList(frontmatter.defaultReads);
1258
1336
  const skillStr = frontmatter.skill || frontmatter.skills;
1259
- const skills = skillStr
1260
- ?.split(",")
1261
- .map((s) => s.trim())
1262
- .filter(Boolean);
1263
- const fallbackModels = frontmatter.fallbackModels
1264
- ?.split(",")
1265
- .map((model) => model.trim())
1266
- .filter(Boolean);
1337
+ const skills = parseFrontmatterList(skillStr);
1338
+ const skillPath = parseFrontmatterList(frontmatter.skillPath);
1339
+ const fallbackModels = parseFrontmatterList(frontmatter.fallbackModels);
1267
1340
  const systemPromptMode = frontmatter.systemPromptMode === "replace"
1268
1341
  ? "replace"
1269
1342
  : frontmatter.systemPromptMode === "append"
@@ -1284,21 +1357,36 @@ function loadAgentsFromDir(dir: string, source: AgentSource): AgentConfig[] {
1284
1357
  : frontmatter.defaultContext === "fresh"
1285
1358
  ? "fresh" as const
1286
1359
  : undefined;
1287
-
1288
- let extensions: string[] | undefined;
1289
- if (frontmatter.extensions !== undefined) {
1290
- extensions = frontmatter.extensions
1291
- .split(",")
1292
- .map((e) => e.trim())
1293
- .filter(Boolean);
1360
+ let defaultAsync: boolean | undefined;
1361
+ if (frontmatter.async !== undefined) {
1362
+ if (frontmatter.async === "true") defaultAsync = true;
1363
+ else if (frontmatter.async === "false") defaultAsync = false;
1364
+ else throw new Error(`Agent '${localName}' has invalid async frontmatter; expected true or false.`);
1294
1365
  }
1295
- let subagentOnlyExtensions: string[] | undefined;
1296
- if (frontmatter.subagentOnlyExtensions !== undefined) {
1297
- subagentOnlyExtensions = frontmatter.subagentOnlyExtensions
1298
- .split(",")
1299
- .map((e) => e.trim())
1300
- .filter(Boolean);
1366
+ let defaultTimeoutMs: number | undefined;
1367
+ if (frontmatter.timeoutMs !== undefined) {
1368
+ const parsed = Number(frontmatter.timeoutMs);
1369
+ if (!Number.isInteger(parsed) || parsed <= 0) {
1370
+ throw new Error(`Agent '${localName}' has invalid timeoutMs frontmatter; expected a positive integer.`);
1371
+ }
1372
+ defaultTimeoutMs = parsed;
1373
+ }
1374
+ let defaultTurnBudget: TurnBudgetConfig | undefined;
1375
+ if (frontmatter.turnBudget !== undefined && frontmatter.turnBudget.trim()) {
1376
+ const parsed = JSON.parse(frontmatter.turnBudget) as unknown;
1377
+ const resolved = resolveTurnBudgetConfig(parsed, `Agent '${localName}' turnBudget frontmatter`);
1378
+ if (resolved.error) throw new Error(resolved.error);
1379
+ defaultTurnBudget = resolved.turnBudget;
1301
1380
  }
1381
+ const defaultAcceptance = parseAgentAcceptanceFrontmatter(frontmatter.acceptance, localName);
1382
+ let acceptanceRole: AcceptanceRole | undefined;
1383
+ if (frontmatter.acceptanceRole !== undefined && frontmatter.acceptanceRole.trim()) {
1384
+ if (frontmatter.acceptanceRole === "read-only" || frontmatter.acceptanceRole === "writer") acceptanceRole = frontmatter.acceptanceRole;
1385
+ else throw new Error(`Agent '${localName}' has invalid acceptanceRole frontmatter; expected 'read-only' or 'writer'.`);
1386
+ }
1387
+
1388
+ const extensions = parseFrontmatterList(frontmatter.extensions);
1389
+ const subagentOnlyExtensions = parseFrontmatterList(frontmatter.subagentOnlyExtensions);
1302
1390
 
1303
1391
  const extraFields: Record<string, string> = {};
1304
1392
  for (const [key, value] of Object.entries(frontmatter)) {
@@ -1325,19 +1413,25 @@ function loadAgentsFromDir(dir: string, source: AgentSource): AgentConfig[] {
1325
1413
  localName,
1326
1414
  packageName,
1327
1415
  description: frontmatter.description,
1328
- tools: tools.length > 0 ? tools : undefined,
1416
+ tools: rawTools !== undefined ? tools : undefined,
1329
1417
  mcpDirectTools: mcpDirectTools.length > 0 ? mcpDirectTools : undefined,
1330
1418
  model: frontmatter.model,
1331
1419
  fallbackModels: fallbackModels && fallbackModels.length > 0 ? fallbackModels : undefined,
1332
- thinking: frontmatter.thinking,
1420
+ thinking: frontmatter.thinking === "false" ? false : frontmatter.thinking,
1333
1421
  systemPromptMode,
1334
1422
  inheritProjectContext,
1335
1423
  inheritSkills,
1336
1424
  defaultContext,
1425
+ defaultAsync,
1426
+ defaultTimeoutMs,
1427
+ defaultTurnBudget,
1428
+ defaultAcceptance,
1429
+ acceptanceRole,
1337
1430
  systemPrompt: body,
1338
1431
  source,
1339
1432
  filePath,
1340
1433
  skills: skills && skills.length > 0 ? skills : undefined,
1434
+ skillPath: skillPath && skillPath.length > 0 ? skillPath : undefined,
1341
1435
  extensions,
1342
1436
  subagentOnlyExtensions,
1343
1437
  output: frontmatter.output,
@@ -1447,6 +1541,8 @@ export function discoverAgents(cwd: string, scope: AgentScope): AgentDiscoveryRe
1447
1541
  const userSettings = scope === "project" ? EMPTY_SUBAGENT_SETTINGS : readSubagentSettings(userSettingsPath);
1448
1542
  const projectSettings = scope === "user" ? EMPTY_SUBAGENT_SETTINGS : readSubagentSettings(projectSettingsPath);
1449
1543
  const defaultModel = resolveSubagentDefaultModel(userSettings, projectSettings, userSettingsPath, projectSettingsPath);
1544
+ const defaultThinking = resolveSubagentDefaultThinking(userSettings, projectSettings, projectSettingsPath);
1545
+ const defaultExtensions = resolveSubagentDefaultExtensions(userSettings, projectSettings, projectSettingsPath);
1450
1546
  const modelScope = projectSettings.modelScope ?? userSettings.modelScope;
1451
1547
  const packageSubagentPaths = collectPackageSubagentPaths(cwd, {
1452
1548
  includeUser: scope !== "project",
@@ -1454,7 +1550,7 @@ export function discoverAgents(cwd: string, scope: AgentScope): AgentDiscoveryRe
1454
1550
  });
1455
1551
 
1456
1552
  const builtinAgents = applyBuiltinOverrides(
1457
- applySubagentDefaultModel(loadAgentsFromDir(BUILTIN_AGENTS_DIR, "builtin"), defaultModel),
1553
+ applySubagentDefaults(loadAgentsFromDir(BUILTIN_AGENTS_DIR, "builtin"), defaultModel, defaultThinking, defaultExtensions),
1458
1554
  userSettings,
1459
1555
  projectSettings,
1460
1556
  userSettingsPath,
@@ -1465,7 +1561,7 @@ export function discoverAgents(cwd: string, scope: AgentScope): AgentDiscoveryRe
1465
1561
  const userAgentsOld = scope === "project" ? [] : loadAgentsFromDir(userDirOld, "user");
1466
1562
  const userAgentsNew = scope === "project" ? [] : loadAgentsFromDir(userDirNew, "user");
1467
1563
  const userAgents = applyCustomAgentOverrides(
1468
- applySubagentDefaultModel([...userAgentsExtra, ...userAgentsOld, ...userAgentsNew], defaultModel),
1564
+ applySubagentDefaults([...userAgentsExtra, ...userAgentsOld, ...userAgentsNew], defaultModel, defaultThinking, defaultExtensions),
1469
1565
  userSettings,
1470
1566
  projectSettings,
1471
1567
  userSettingsPath,
@@ -1473,14 +1569,14 @@ export function discoverAgents(cwd: string, scope: AgentScope): AgentDiscoveryRe
1473
1569
  );
1474
1570
 
1475
1571
  const projectAgents = applyCustomAgentOverrides(
1476
- applySubagentDefaultModel(scope === "user" ? [] : projectAgentDirs.flatMap((dir) => loadAgentsFromDir(dir, "project")), defaultModel),
1572
+ applySubagentDefaults(scope === "user" ? [] : projectAgentDirs.flatMap((dir) => loadAgentsFromDir(dir, "project")), defaultModel, defaultThinking, defaultExtensions),
1477
1573
  userSettings,
1478
1574
  projectSettings,
1479
1575
  userSettingsPath,
1480
1576
  projectSettingsPath,
1481
1577
  );
1482
1578
  const packageAgents = applyCustomAgentOverrides(
1483
- applySubagentDefaultModel(packageSubagentPaths.agents.flatMap((dir) => loadAgentsFromDir(dir, "package")), defaultModel),
1579
+ applySubagentDefaults(packageSubagentPaths.agents.flatMap((dir) => loadAgentsFromDir(dir, "package")), defaultModel, defaultThinking, defaultExtensions),
1484
1580
  userSettings,
1485
1581
  projectSettings,
1486
1582
  userSettingsPath,
@@ -1516,21 +1612,23 @@ export function discoverAgentsAll(cwd: string): {
1516
1612
  const userSettings = readSubagentSettings(userSettingsPath);
1517
1613
  const projectSettings = readSubagentSettings(projectSettingsPath);
1518
1614
  const defaultModel = resolveSubagentDefaultModel(userSettings, projectSettings, userSettingsPath, projectSettingsPath);
1615
+ const defaultThinking = resolveSubagentDefaultThinking(userSettings, projectSettings, projectSettingsPath);
1616
+ const defaultExtensions = resolveSubagentDefaultExtensions(userSettings, projectSettings, projectSettingsPath);
1519
1617
  const packageSubagentPaths = collectPackageSubagentPaths(cwd);
1520
1618
 
1521
1619
  const builtin = applyBuiltinOverrides(
1522
- applySubagentDefaultModel(loadAgentsFromDir(BUILTIN_AGENTS_DIR, "builtin"), defaultModel),
1620
+ applySubagentDefaults(loadAgentsFromDir(BUILTIN_AGENTS_DIR, "builtin"), defaultModel, defaultThinking, defaultExtensions),
1523
1621
  userSettings,
1524
1622
  projectSettings,
1525
1623
  userSettingsPath,
1526
1624
  projectSettingsPath,
1527
1625
  );
1528
1626
  const user = applyCustomAgentOverrides(
1529
- applySubagentDefaultModel([
1627
+ applySubagentDefaults([
1530
1628
  ...extraUserAgentDirs().flatMap((dir) => loadAgentsFromDir(dir, "user")),
1531
1629
  ...loadAgentsFromDir(userDirOld, "user"),
1532
1630
  ...loadAgentsFromDir(userDirNew, "user"),
1533
- ], defaultModel),
1631
+ ], defaultModel, defaultThinking, defaultExtensions),
1534
1632
  userSettings,
1535
1633
  projectSettings,
1536
1634
  userSettingsPath,
@@ -1543,7 +1641,7 @@ export function discoverAgentsAll(cwd: string): {
1543
1641
  }
1544
1642
  }
1545
1643
  const packageAgents = applyCustomAgentOverrides(
1546
- applySubagentDefaultModel(Array.from(packageMap.values()), defaultModel),
1644
+ applySubagentDefaults(Array.from(packageMap.values()), defaultModel, defaultThinking, defaultExtensions),
1547
1645
  userSettings,
1548
1646
  projectSettings,
1549
1647
  userSettingsPath,
@@ -1556,7 +1654,7 @@ export function discoverAgentsAll(cwd: string): {
1556
1654
  }
1557
1655
  }
1558
1656
  const project = applyCustomAgentOverrides(
1559
- applySubagentDefaultModel(Array.from(projectMap.values()), defaultModel),
1657
+ applySubagentDefaults(Array.from(projectMap.values()), defaultModel, defaultThinking, defaultExtensions),
1560
1658
  userSettings,
1561
1659
  projectSettings,
1562
1660
  userSettingsPath,