pi-subagents 0.70.1 → 0.72.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (275) hide show
  1. package/CHANGELOG.md +87 -0
  2. package/README.md +4 -2
  3. package/agents/worker.md +2 -2
  4. package/docs/agents.md +1 -1
  5. package/docs/configuration.md +18 -2
  6. package/docs/extension-api.md +67 -3
  7. package/docs/models.md +1 -1
  8. package/docs/observability.md +17 -13
  9. package/docs/tool-reference.md +14 -10
  10. package/docs/workflows.md +3 -1
  11. package/package.json +11 -4
  12. package/prompts/council.md +6 -3
  13. package/skills/pi-subagents/references/constraints-and-recipes.md +5 -2
  14. package/skills/pi-subagents/references/execution-controls.md +3 -3
  15. package/skills/pi-subagents/references/management-authoring-rpc.md +2 -2
  16. package/src/agents/agent-management.d.ts +2 -1
  17. package/src/agents/agent-management.d.ts.map +1 -1
  18. package/src/agents/agent-management.js +32 -29
  19. package/src/agents/agent-management.js.map +1 -1
  20. package/src/agents/agents.d.ts +7 -3
  21. package/src/agents/agents.d.ts.map +1 -1
  22. package/src/agents/agents.js +16 -15
  23. package/src/agents/agents.js.map +1 -1
  24. package/src/agents/global-npm-root.d.ts +7 -0
  25. package/src/agents/global-npm-root.d.ts.map +1 -0
  26. package/src/agents/global-npm-root.js +58 -0
  27. package/src/agents/global-npm-root.js.map +1 -0
  28. package/src/agents/proactive-skills.d.ts +1 -0
  29. package/src/agents/proactive-skills.d.ts.map +1 -1
  30. package/src/agents/proactive-skills.js +3 -1
  31. package/src/agents/proactive-skills.js.map +1 -1
  32. package/src/agents/skills.d.ts +2 -0
  33. package/src/agents/skills.d.ts.map +1 -1
  34. package/src/agents/skills.js +41 -8
  35. package/src/agents/skills.js.map +1 -1
  36. package/src/api/delegation.d.ts +14 -0
  37. package/src/api/delegation.d.ts.map +1 -1
  38. package/src/api/inspectors.d.ts +21 -0
  39. package/src/api/inspectors.d.ts.map +1 -0
  40. package/src/api/inspectors.js +12 -0
  41. package/src/api/inspectors.js.map +1 -0
  42. package/src/extension/fanout-child.d.ts.map +1 -1
  43. package/src/extension/fanout-child.js +9 -0
  44. package/src/extension/fanout-child.js.map +1 -1
  45. package/src/extension/index.d.ts.map +1 -1
  46. package/src/extension/index.js +76 -29
  47. package/src/extension/index.js.map +1 -1
  48. package/src/extension/rpc.d.ts +1 -1
  49. package/src/extension/rpc.d.ts.map +1 -1
  50. package/src/extension/rpc.js +11 -1
  51. package/src/extension/rpc.js.map +1 -1
  52. package/src/extension/schemas.js +5 -5
  53. package/src/extension/schemas.js.map +1 -1
  54. package/src/extension/subagent-guide.d.ts +1 -1
  55. package/src/extension/subagent-guide.d.ts.map +1 -1
  56. package/src/extension/subagent-guide.js +11 -4
  57. package/src/extension/subagent-guide.js.map +1 -1
  58. package/src/extension/tool-activation.d.ts +9 -0
  59. package/src/extension/tool-activation.d.ts.map +1 -0
  60. package/src/extension/tool-activation.js +182 -0
  61. package/src/extension/tool-activation.js.map +1 -0
  62. package/src/extension/tool-description.d.ts +4 -4
  63. package/src/extension/tool-description.d.ts.map +1 -1
  64. package/src/extension/tool-description.js +1 -1
  65. package/src/inspectors/plugins.d.ts +7 -2
  66. package/src/inspectors/plugins.d.ts.map +1 -1
  67. package/src/inspectors/plugins.js +78 -3
  68. package/src/inspectors/plugins.js.map +1 -1
  69. package/src/intercom/intercom-bridge.d.ts.map +1 -1
  70. package/src/intercom/intercom-bridge.js +2 -0
  71. package/src/intercom/intercom-bridge.js.map +1 -1
  72. package/src/intercom/native-supervisor-channel.d.ts.map +1 -1
  73. package/src/intercom/native-supervisor-channel.js +3 -1
  74. package/src/intercom/native-supervisor-channel.js.map +1 -1
  75. package/src/runs/background/active-async-capacity.d.ts.map +1 -1
  76. package/src/runs/background/active-async-capacity.js +4 -33
  77. package/src/runs/background/active-async-capacity.js.map +1 -1
  78. package/src/runs/background/async-execution.d.ts.map +1 -1
  79. package/src/runs/background/async-execution.js +7 -33
  80. package/src/runs/background/async-execution.js.map +1 -1
  81. package/src/runs/background/async-job-tracker.d.ts.map +1 -1
  82. package/src/runs/background/async-job-tracker.js +26 -39
  83. package/src/runs/background/async-job-tracker.js.map +1 -1
  84. package/src/runs/background/async-resume.d.ts +1 -1
  85. package/src/runs/background/async-resume.d.ts.map +1 -1
  86. package/src/runs/background/async-resume.js +7 -2
  87. package/src/runs/background/async-resume.js.map +1 -1
  88. package/src/runs/background/async-status.d.ts +1 -0
  89. package/src/runs/background/async-status.d.ts.map +1 -1
  90. package/src/runs/background/async-status.js +1 -0
  91. package/src/runs/background/async-status.js.map +1 -1
  92. package/src/runs/background/binary-bootstrap.d.ts.map +1 -1
  93. package/src/runs/background/binary-bootstrap.js +34 -6
  94. package/src/runs/background/binary-bootstrap.js.map +1 -1
  95. package/src/runs/background/fleet-view.d.ts.map +1 -1
  96. package/src/runs/background/fleet-view.js +26 -7
  97. package/src/runs/background/fleet-view.js.map +1 -1
  98. package/src/runs/background/notify.d.ts +11 -0
  99. package/src/runs/background/notify.d.ts.map +1 -1
  100. package/src/runs/background/notify.js +73 -3
  101. package/src/runs/background/notify.js.map +1 -1
  102. package/src/runs/background/pid-namespace.d.ts +3 -0
  103. package/src/runs/background/pid-namespace.d.ts.map +1 -0
  104. package/src/runs/background/pid-namespace.js +20 -0
  105. package/src/runs/background/pid-namespace.js.map +1 -0
  106. package/src/runs/background/process-terminal-candidate.d.ts +18 -0
  107. package/src/runs/background/process-terminal-candidate.d.ts.map +1 -0
  108. package/src/runs/background/process-terminal-candidate.js +97 -0
  109. package/src/runs/background/process-terminal-candidate.js.map +1 -0
  110. package/src/runs/background/process-terminal.d.ts +3 -15
  111. package/src/runs/background/process-terminal.d.ts.map +1 -1
  112. package/src/runs/background/process-terminal.js +19 -96
  113. package/src/runs/background/process-terminal.js.map +1 -1
  114. package/src/runs/background/retained-children.d.ts.map +1 -1
  115. package/src/runs/background/retained-children.js +3 -2
  116. package/src/runs/background/retained-children.js.map +1 -1
  117. package/src/runs/background/run-child-session.d.ts +2 -0
  118. package/src/runs/background/run-child-session.d.ts.map +1 -1
  119. package/src/runs/background/run-child-session.js +2 -0
  120. package/src/runs/background/run-child-session.js.map +1 -1
  121. package/src/runs/background/run-status.d.ts.map +1 -1
  122. package/src/runs/background/run-status.js +5 -1
  123. package/src/runs/background/run-status.js.map +1 -1
  124. package/src/runs/background/runner-aliases.d.ts.map +1 -1
  125. package/src/runs/background/runner-aliases.js +2 -1
  126. package/src/runs/background/runner-aliases.js.map +1 -1
  127. package/src/runs/background/runner-startup-failure.d.ts +14 -0
  128. package/src/runs/background/runner-startup-failure.d.ts.map +1 -0
  129. package/src/runs/background/runner-startup-failure.js +47 -0
  130. package/src/runs/background/runner-startup-failure.js.map +1 -0
  131. package/src/runs/background/stale-run-reconciler.d.ts +1 -0
  132. package/src/runs/background/stale-run-reconciler.d.ts.map +1 -1
  133. package/src/runs/background/stale-run-reconciler.js +18 -3
  134. package/src/runs/background/stale-run-reconciler.js.map +1 -1
  135. package/src/runs/background/subagent-runner-bootstrap.d.ts +14 -0
  136. package/src/runs/background/subagent-runner-bootstrap.d.ts.map +1 -0
  137. package/src/runs/background/subagent-runner-bootstrap.js +277 -0
  138. package/src/runs/background/subagent-runner-bootstrap.js.map +1 -0
  139. package/src/runs/background/subagent-runner.d.ts +4 -2
  140. package/src/runs/background/subagent-runner.d.ts.map +1 -1
  141. package/src/runs/background/subagent-runner.js +58 -180
  142. package/src/runs/background/subagent-runner.js.map +1 -1
  143. package/src/runs/background/workflow-terminal-proof.d.ts +18 -0
  144. package/src/runs/background/workflow-terminal-proof.d.ts.map +1 -0
  145. package/src/runs/background/workflow-terminal-proof.js +68 -0
  146. package/src/runs/background/workflow-terminal-proof.js.map +1 -0
  147. package/src/runs/foreground/execution.d.ts.map +1 -1
  148. package/src/runs/foreground/execution.js +43 -14
  149. package/src/runs/foreground/execution.js.map +1 -1
  150. package/src/runs/foreground/prompt-audit.d.ts.map +1 -1
  151. package/src/runs/foreground/prompt-audit.js +2 -6
  152. package/src/runs/foreground/prompt-audit.js.map +1 -1
  153. package/src/runs/foreground/subagent-executor.d.ts +2 -1
  154. package/src/runs/foreground/subagent-executor.d.ts.map +1 -1
  155. package/src/runs/foreground/subagent-executor.js +228 -24
  156. package/src/runs/foreground/subagent-executor.js.map +1 -1
  157. package/src/runs/shared/child-launch.d.ts.map +1 -1
  158. package/src/runs/shared/child-launch.js +3 -0
  159. package/src/runs/shared/child-launch.js.map +1 -1
  160. package/src/runs/shared/child-runtime-config.d.ts +4 -0
  161. package/src/runs/shared/child-runtime-config.d.ts.map +1 -1
  162. package/src/runs/shared/child-runtime-config.js.map +1 -1
  163. package/src/runs/shared/child-session.d.ts +1 -0
  164. package/src/runs/shared/child-session.d.ts.map +1 -1
  165. package/src/runs/shared/child-session.js +1 -0
  166. package/src/runs/shared/child-session.js.map +1 -1
  167. package/src/runs/shared/child-tool-plan.d.ts.map +1 -1
  168. package/src/runs/shared/child-tool-plan.js +4 -6
  169. package/src/runs/shared/child-tool-plan.js.map +1 -1
  170. package/src/runs/shared/external-cli-runner.d.ts.map +1 -1
  171. package/src/runs/shared/external-cli-runner.js +3 -1
  172. package/src/runs/shared/external-cli-runner.js.map +1 -1
  173. package/src/runs/shared/external-job-bridge.d.ts +7 -0
  174. package/src/runs/shared/external-job-bridge.d.ts.map +1 -1
  175. package/src/runs/shared/external-job-bridge.js +63 -0
  176. package/src/runs/shared/external-job-bridge.js.map +1 -1
  177. package/src/runs/shared/git-environment.d.ts +3 -0
  178. package/src/runs/shared/git-environment.d.ts.map +1 -0
  179. package/src/runs/shared/git-environment.js +28 -0
  180. package/src/runs/shared/git-environment.js.map +1 -0
  181. package/src/runs/shared/mcp-config-sources.d.ts +3 -0
  182. package/src/runs/shared/mcp-config-sources.d.ts.map +1 -1
  183. package/src/runs/shared/mcp-config-sources.js.map +1 -1
  184. package/src/runs/shared/mcp-direct-tool-allowlist.js +1 -1
  185. package/src/runs/shared/mcp-direct-tool-allowlist.js.map +1 -1
  186. package/src/runs/shared/mcp-direct-tool-grant.d.ts +3 -1
  187. package/src/runs/shared/mcp-direct-tool-grant.d.ts.map +1 -1
  188. package/src/runs/shared/mcp-direct-tool-grant.js +19 -5
  189. package/src/runs/shared/mcp-direct-tool-grant.js.map +1 -1
  190. package/src/runs/shared/model-resolution.d.ts.map +1 -1
  191. package/src/runs/shared/model-resolution.js +7 -1
  192. package/src/runs/shared/model-resolution.js.map +1 -1
  193. package/src/runs/shared/pi-spawn.d.ts +10 -1
  194. package/src/runs/shared/pi-spawn.d.ts.map +1 -1
  195. package/src/runs/shared/pi-spawn.js +86 -7
  196. package/src/runs/shared/pi-spawn.js.map +1 -1
  197. package/src/runs/shared/single-output.js +1 -1
  198. package/src/runs/shared/single-output.js.map +1 -1
  199. package/src/runs/shared/structured-output.d.ts +7 -0
  200. package/src/runs/shared/structured-output.d.ts.map +1 -1
  201. package/src/runs/shared/structured-output.js +74 -0
  202. package/src/runs/shared/structured-output.js.map +1 -1
  203. package/src/runs/shared/subagent-prompt-runtime.d.ts.map +1 -1
  204. package/src/runs/shared/subagent-prompt-runtime.js +23 -7
  205. package/src/runs/shared/subagent-prompt-runtime.js.map +1 -1
  206. package/src/runs/shared/tool-availability.js +2 -2
  207. package/src/runs/shared/tool-availability.js.map +1 -1
  208. package/src/runs/shared/worktree.d.ts.map +1 -1
  209. package/src/runs/shared/worktree.js +9 -3
  210. package/src/runs/shared/worktree.js.map +1 -1
  211. package/src/shared/child-session-name.d.ts.map +1 -1
  212. package/src/shared/child-session-name.js +4 -2
  213. package/src/shared/child-session-name.js.map +1 -1
  214. package/src/shared/fork-context.d.ts +4 -0
  215. package/src/shared/fork-context.d.ts.map +1 -1
  216. package/src/shared/fork-context.js +9 -4
  217. package/src/shared/fork-context.js.map +1 -1
  218. package/src/shared/pruned-fork.d.ts.map +1 -1
  219. package/src/shared/pruned-fork.js +68 -56
  220. package/src/shared/pruned-fork.js.map +1 -1
  221. package/src/shared/types.d.ts +31 -3
  222. package/src/shared/types.d.ts.map +1 -1
  223. package/src/shared/types.js +2 -0
  224. package/src/shared/types.js.map +1 -1
  225. package/src/slash/delegation-adapters.d.ts +7 -1
  226. package/src/slash/delegation-adapters.d.ts.map +1 -1
  227. package/src/slash/delegation-adapters.js +17 -0
  228. package/src/slash/delegation-adapters.js.map +1 -1
  229. package/src/slash/prompt-template-bridge.d.ts.map +1 -1
  230. package/src/slash/prompt-template-bridge.js +14 -1
  231. package/src/slash/prompt-template-bridge.js.map +1 -1
  232. package/src/slash/prompt-workflows.d.ts.map +1 -1
  233. package/src/slash/prompt-workflows.js +16 -2
  234. package/src/slash/prompt-workflows.js.map +1 -1
  235. package/src/slash/slash-commands.d.ts.map +1 -1
  236. package/src/slash/slash-commands.js +7 -253
  237. package/src/slash/slash-commands.js.map +1 -1
  238. package/src/slash/subagent-cost.d.ts +30 -0
  239. package/src/slash/subagent-cost.d.ts.map +1 -0
  240. package/src/slash/subagent-cost.js +307 -0
  241. package/src/slash/subagent-cost.js.map +1 -0
  242. package/src/tui/fleet-status.d.ts +2 -0
  243. package/src/tui/fleet-status.d.ts.map +1 -1
  244. package/src/tui/fleet-status.js +25 -2
  245. package/src/tui/fleet-status.js.map +1 -1
  246. package/src/tui/fleet.d.ts +1 -1
  247. package/src/tui/fleet.d.ts.map +1 -1
  248. package/src/tui/fleet.js +5 -1
  249. package/src/tui/fleet.js.map +1 -1
  250. package/src/tui/render.d.ts.map +1 -1
  251. package/src/tui/render.js +8 -4
  252. package/src/tui/render.js.map +1 -1
  253. package/src/watchdog/diff-tool.d.ts +2 -1
  254. package/src/watchdog/diff-tool.d.ts.map +1 -1
  255. package/src/watchdog/diff-tool.js +9 -3
  256. package/src/watchdog/diff-tool.js.map +1 -1
  257. package/src/watchdog/permission-arbiter.d.ts.map +1 -1
  258. package/src/watchdog/permission-arbiter.js +2 -7
  259. package/src/watchdog/permission-arbiter.js.map +1 -1
  260. package/src/watchdog/register-child.d.ts +3 -1
  261. package/src/watchdog/register-child.d.ts.map +1 -1
  262. package/src/watchdog/register-child.js +12 -3
  263. package/src/watchdog/register-child.js.map +1 -1
  264. package/src/watchdog/review.d.ts +1 -1
  265. package/src/watchdog/review.d.ts.map +1 -1
  266. package/src/watchdog/review.js +2 -7
  267. package/src/watchdog/review.js.map +1 -1
  268. package/src/watchdog/runtime.d.ts +1 -1
  269. package/src/watchdog/runtime.d.ts.map +1 -1
  270. package/src/watchdog/runtime.js +2 -1
  271. package/src/watchdog/runtime.js.map +1 -1
  272. package/src/watchdog/turn-delta.d.ts +5 -1
  273. package/src/watchdog/turn-delta.d.ts.map +1 -1
  274. package/src/watchdog/turn-delta.js +9 -5
  275. package/src/watchdog/turn-delta.js.map +1 -1
@@ -8,8 +8,11 @@ session, are the supervisor. You select the roster, curate cross-advisor packets
8
8
  decide which feedback is valid, and write the final memo. Advisors do not talk
9
9
  directly or see peer transcripts by default. This is not free-form agent chat.
10
10
 
11
- Before you orchestrate, read `skills/council-mode/SKILL.md` and
12
- `skills/pi-subagents/references/execution-controls.md`.
11
+ Before you orchestrate, load the council protocol with
12
+ `subagent({ action: "guide", topic: "council" })`. If only `subagents_enable`
13
+ is available, call it first; `subagent` is available on the next request. The
14
+ guide returns the packaged council-mode skill and the references it asks you to
15
+ read, so it also works when Pi runs with `--no-skills`.
13
16
 
14
17
  Parse the invocation yourself. The flags below are conventions, not runtime
15
18
  options. Record a brief with the question, scope, non-goals, evidence targets,
@@ -48,7 +51,7 @@ path if the run is not resumable.
48
51
  ## Run the protocol
49
52
 
50
53
  Use the canonical workflow, structured advisor contracts, aggregate pass receipts,
51
- and memo requirements in `skills/council-mode/SKILL.md`. Keep the parent as the
54
+ and memo requirements from the council guide. Keep the parent as the
52
55
  only synthesizer and decision maker. Do not introduce a chair advisor, peer chat,
53
56
  or transcript sharing.
54
57
 
@@ -6,10 +6,13 @@ This file is a detailed reference loaded from `skills/pi-subagents/SKILL.md`.
6
6
 
7
7
  - **Explicit forking requires a persisted parent session.** If the current session
8
8
  does not have a persisted session file or current leaf, explicit `context: "fork"`
9
- fails. An agent-level `defaultContext: fork` is a preference: packaged `worker`,
10
- `oracle`, and `advisor` fall back to `fresh` when those fork preconditions are not
9
+ fails. An agent-level `defaultContext: fork` is a preference: packaged `oracle`
10
+ and `advisor` fall back to `fresh` when those fork preconditions are not
11
11
  met yet. Use `context: "fresh"` when you do not want a fork even after the parent
12
12
  session exists.
13
+ - **Packaged workers start fresh.** `worker` defaults to fresh context so its brief,
14
+ not the parent's unfinished agenda, controls the implementation. Pass explicit
15
+ `context: "fork"` when inherited conversation history is required.
13
16
  - **Forked runs inherit parent history.** They are branched threads, not fresh
14
17
  filtered contexts. Use fresh context for adversarial reviewers unless the user explicitly asks for forked context.
15
18
  - **Default subagent nesting depth is 2.** Deeper recursive delegation is blocked
@@ -32,7 +32,7 @@ An agent may set `runner.type: external-job` with a non-empty `provider` and opt
32
32
 
33
33
  External job profiles are async-only. The provider owns the remote job and Pi owns the async run record. Status persists provider name, provider job id, prompt digest, provider options, handle/conversation URLs when supplied, result artifact path, last known state, and provider failure code/message. Recovery uses existing provider job metadata to call `reattach` and `result`; it refuses to redispatch a prompt when the persisted provider job does not match the prompt digest.
34
34
 
35
- External job profiles do not support foreground/clarify, steer/resume, Pi models/tools/extensions/skills, tool budgets, structured output, native child permissions, or Pi child sessions. Capacity conflicts fail closed and include the blocking provider job id when the provider supplies it.
35
+ External job profiles do not support foreground/clarify, live steer or native session resume, Pi models/tools/extensions/skills, tool budgets, structured output, native child permissions, or Pi child sessions. Completed external-job runs can use `action: "resume"` for provider follow-up when the registered provider exposes `followUp(input)`; running jobs must finish first, and providers without follow-up support fail closed with an update/reload message. Capacity conflicts fail closed and include the blocking provider job id when the provider supplies it.
36
36
 
37
37
  ### Single agent
38
38
 
@@ -103,7 +103,7 @@ For a typed post-run check, pass the object form `gate: { command, output: "json
103
103
 
104
104
  If omitted, acceptance is inferred from role, mode, and risk. Use `level: "checked"` for ordinary writer evidence and `level: "verified"` when the runtime should run explicit validation commands. Independent review is orthogonal: use `review: { required: true, agent: "reviewer" }`; reviewer/read-only calls omit `acceptance`. `review-required` means evidence passed but review is pending; `reviewed` means an independent review found no blockers. Never request `level: "reviewed"`; it is recognized only so preflight can return an actionable correction. Disable gates with `{ level: "none", reason: "..." }`; bare `"none"` is rejected and `false` is only a deprecated shorthand. Child-reported command success is evidence, not runtime verification.
105
105
 
106
- Completed workflow children from this parent session stay addressable as retained children. `subagent({ action: "children.list" })` lists up to the last 10 with run ids and reports each row as `resumable` or `not resumable` with a reason. Resume only rows reported `resumable`. For a retained-child challenge, use `resume` instead of `steer` when the child is complete. If no retained child is resumable, launch a same-role fallback challenge and label it as fallback. A later workflow continues a resumable child with `runs.run(key, { resume: "<run-id>", task: "follow-up" })`. Inside `workflowScript`, awaiting that call waits for the revived child to finish and returns its completed output and new `runId`; top-level `{ action: "resume" }` remains detached. Pass explicit follow-up task text. Assign each returned child result back to the loop variable because every resume can return a new retained `runId`; always resume the latest returned id. `resume` and `agent` are mutually exclusive, the revived child keeps its stored agent/model/tool contract, and `gate` is rejected on retained resume items.
106
+ Completed workflow children from this parent session stay addressable as retained children. `subagent({ action: "children.list" })` lists up to the last 10 with run ids and reports each row as `resumable` or `not resumable` with a reason. This workflow-only roster is not an exhaustive list of direct native children. Resume only rows reported `resumable`. When the exact run id of an intended direct child is known, inspect it with `subagent({ action: "status", id: "<run-id>" })`; if status identifies the candidate, attempt `subagent({ action: "resume", id: "<run-id>", message: "..." })`. Resume performs the authoritative eligibility check and may reject the attempt. For a retained-child challenge, use `resume` instead of `steer` when the child is complete. Launch a same-role fallback challenge, labeled as fallback, only when no known candidate exists or resume rejects eligibility. A later workflow continues a resumable child with `runs.run(key, { resume: "<run-id>", task: "follow-up" })`. Inside `workflowScript`, awaiting that call waits for the revived child to finish and returns its completed output and new `runId`; top-level `{ action: "resume" }` remains detached. Pass explicit follow-up task text. Assign each returned child result back to the loop variable because every resume can return a new retained `runId`; always resume the latest returned id. `resume` and `agent` are mutually exclusive, the revived child keeps its stored agent/model/tool contract, and `gate` is rejected on retained resume items.
107
107
 
108
108
  Each workflow key identifies one result lane: use a new stable workflow key for every distinct retained resume pass; same-key calls are reused only when launch parameters are identical, and incompatible parameters are rejected.
109
109
 
@@ -493,7 +493,7 @@ subagent({
493
493
  workflowScript: `return runs.run("oracle-check", { agent: "oracle", task: "Review my current direction, challenge assumptions, and propose the best next move." })`
494
494
  })
495
495
 
496
- // Implementation only after explicit approval. Worker defaults to forked context.
496
+ // Implementation only after explicit approval. Worker defaults to fresh context.
497
497
  subagent({
498
498
  workflowScript: `return runs.run("implementation", { agent: "worker", task: "Implement the approved approach: ..." })`
499
499
  })
@@ -18,7 +18,7 @@ subagent({ action: "list" })
18
18
  subagent({ action: "children.list" })
19
19
  ```
20
20
 
21
- Lists up to the last 10 retained workflow children from this parent session with explicit `resumable` or `not resumable` rows. Resume only rows reported `resumable`. Send a simple follow-up or implementation challenge with `subagent({ action: "resume", id: "<run-id>", message: "..." })`. Continue one inside a workflow with `runs.run(key, { resume: "<run-id>", task: "follow-up" })`; each workflow key identifies one result lane, so use a new stable workflow key for every distinct retained resume pass. Same-key calls are reused only when launch parameters are identical, and incompatible parameters are rejected. The revived child keeps its stored agent, model, and tool contract. If no resumable child is listed, start a same-role fallback challenge and label it as fallback. `steer` with `mode: "follow_up"` only queues text for the next `resume` when the child has already completed.
21
+ Lists up to the last 10 retained workflow children from this parent session with explicit `resumable` or `not resumable` rows. This workflow-only roster is not an exhaustive list of direct native children. Resume only rows reported `resumable`. When the exact run id of an intended direct child is known, inspect it with `subagent({ action: "status", id: "<run-id>" })`; if status identifies the candidate, attempt `subagent({ action: "resume", id: "<run-id>", message: "..." })`. Resume performs the authoritative eligibility check and may reject the attempt. Continue one inside a workflow with `runs.run(key, { resume: "<run-id>", task: "follow-up" })`; each workflow key identifies one result lane, so use a new stable workflow key for every distinct retained resume pass. Same-key calls are reused only when launch parameters are identical, and incompatible parameters are rejected. The revived child keeps its stored agent, model, and tool contract. Start a same-role fallback challenge, labeled as fallback, only when no known candidate exists or resume rejects eligibility. `steer` with `mode: "follow_up"` only queues text for the next `resume` when the child has already completed.
22
22
 
23
23
  ### Refinement overlays
24
24
 
@@ -158,4 +158,4 @@ Additional user prompt templates can delegate into `pi-subagents` through the na
158
158
 
159
159
  Other Pi extensions can call `pi-subagents` through the in-process event bus. The RPC channels are `subagents:rpc:v1:ready`, `subagents:rpc:v1:request`, and per-request replies at `subagents:rpc:v1:reply:<requestId>`. Envelopes use `{ version: 1, requestId, method, params }`, and replies use `{ version: 1, requestId, success, data | error }`. `ping` advertises the exact process-local async completion event as `events.asyncComplete` for RPC-spawn consumers.
160
160
 
161
- Methods: `ping`, `status`, `spawn`, `steer`, `interrupt`, `resume`, and `stop`. `ping` capability metadata advertises optional projections: `capabilities.fleetStatus: { version: 1 }` adds bounded current-session `data.fleet` records (opaque reconciliation `key`, resolved `agent`, optional `role`, `model`, `effort`, caller-facing `goal`, `startedAt`, split `{ input, output, total }` tokens, plus `totalActive`/`omitted` overflow counts) to successful `status` replies; `capabilities.launchResolvedExtensions` advertises parent-resolved opaque launch-extension identifiers in status details; `capabilities.runtimeAcknowledgedExtensions` advertises the best-effort child-runtime acknowledgement projection fed by cooperating extensions emitting `subagent:acknowledge-extension`. Foreground `details.results[]` rows carry a stable numeric `index`; correlate children by `(runId, index)` rather than row position. Consumers should read status/result artifacts and RPC projections instead of scraping terminal output and must ignore unknown fields. `spawn` requires `workflowScript`, is async-only, and rejects management actions, `async: false`, or `clarify: true`; it reuses the normal executor, so discovery, validation, session attribution, configured spawn caps, child-safety depth, artifacts, and async status are shared with the `subagent` tool. `status`, acknowledged async `steer`, and `interrupt` map to the normal control actions. RPC steer disables pause-and-revive recovery and advertises `capabilities.nonRecoveringSteer`, preserving the caller's authority over the exact spawned child. `resume` requires a target plus non-empty message and delegates to the package-owned revival path; it may set a caller-owned `file-only` output path but cannot override the persisted child model, tools, budgets, session ownership, or exclusive session lease. For retained-child workflows, list children first and resume only rows reported `resumable`; otherwise start a same-role fallback challenge and label it as fallback. `stop` targets running async runs through the existing timeout control channel. `pi.events` is process-local, so separate Pi processes and child subagents need lifecycle artifact files or `pi-intercom` instead.
161
+ Methods: `ping`, `status`, `manage`, `spawn`, `steer`, `interrupt`, `resume`, `stop`, and `cost`. `ping` capability metadata advertises optional projections: `capabilities.fleetStatus: { version: 1 }` adds bounded current-session `data.fleet` records (opaque reconciliation `key`, resolved `agent`, optional `role`, `model`, `effort`, caller-facing `goal`, `startedAt`, split `{ input, output, total }` tokens, plus `totalActive`/`omitted` overflow counts) to successful `status` replies; `capabilities.launchResolvedExtensions` advertises parent-resolved opaque launch-extension identifiers in status details; `capabilities.runtimeAcknowledgedExtensions` advertises the best-effort child-runtime acknowledgement projection fed by cooperating extensions emitting `subagent:acknowledge-extension`; `capabilities.cost: { version: 1 }` advertises parent-plus-child accounting as data. Foreground `details.results[]` rows carry a stable numeric `index`; correlate children by `(runId, index)` rather than row position. Consumers should read status/result artifacts and RPC projections instead of scraping terminal output and must ignore unknown fields. `spawn` accepts either `{ agent, task? }`, an inline `workflowScript`, or `workflowScriptPath`; it is async-only and rejects management actions, `async: false`, or `clarify: true`. It reuses the normal executor, so discovery, validation, session attribution, configured spawn caps, child-safety depth, artifacts, and async status are shared with the `subagent` tool. `manage` accepts only the schedule actions advertised by `ping.capabilities.managementActions`. `status`, acknowledged async `steer`, and `interrupt` map to the normal control actions. RPC steer disables pause-and-revive recovery and advertises `capabilities.nonRecoveringSteer`, preserving the caller's authority over the exact spawned child. `resume` requires a target plus non-empty message and delegates to the package-owned revival path; it may set a caller-owned `file-only` output path but cannot override the persisted child model, tools, budgets, session ownership, or exclusive session lease. For retained-child workflows, resume only roster rows reported `resumable`; because that workflow-only roster is not exhaustive, inspect the exact status of a known direct-run candidate and attempt the authoritative resume when status identifies it. Start a labeled same-role fallback only when there is no known candidate or resume rejects eligibility. `stop` targets running async runs through the existing timeout control channel. `pi.events` is process-local, so separate Pi processes and child subagents need lifecycle artifact files or `pi-intercom` instead.
@@ -1,6 +1,6 @@
1
1
  import type { AgentToolResult } from "@earendil-works/pi-agent-core";
2
2
  import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
3
- import { type AgentConfig } from "./agents.ts";
3
+ import { type AgentConfig, discoverAgentsAll } from "./agents.ts";
4
4
  import type { Details, ExtensionConfig } from "../shared/types.ts";
5
5
  import { type RuntimeAgentOwner } from "./runtime-agent-registry.ts";
6
6
  type ManagementContext = Pick<ExtensionContext, "cwd" | "modelRegistry"> & {
@@ -9,6 +9,7 @@ type ManagementContext = Pick<ExtensionContext, "cwd" | "modelRegistry"> & {
9
9
  currentSessionId?: string;
10
10
  runtimeAgentOwner?: RuntimeAgentOwner;
11
11
  onAgentsChanged?: () => void;
12
+ discoverAgentsAll?: typeof discoverAgentsAll;
12
13
  };
13
14
  interface ManagementParams {
14
15
  action?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"agent-management.d.ts","sourceRoot":"","sources":["../../../src/agents/agent-management.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,EACN,KAAK,WAAW,EAiBhB,MAAM,aAAa,CAAC;AAcrB,OAAO,KAAK,EAAkE,OAAO,EAAE,eAAe,EAAoB,MAAM,oBAAoB,CAAC;AAIrJ,OAAO,EAAsB,KAAK,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAKzF,KAAK,iBAAiB,GAAG,IAAI,CAAC,gBAAgB,EAAE,KAAK,GAAG,eAAe,CAAC,GAAG;IAAE,KAAK,CAAC,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAAC,MAAM,CAAC,EAAE,eAAe,CAAC;IAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAAC,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IAAC,eAAe,CAAC,EAAE,MAAM,IAAI,CAAA;CAAE,CAAC;AAE3O,UAAU,gBAAgB;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,MAAM,CAAC,EAAE,OAAO,CAAC;CACjB;AAoMD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,WAAW,GAAG,WAAW,CA8EnE;AAWD,wBAAgB,+BAA+B,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,CAsD7G;AA8jBD,wBAAgB,UAAU,CAAC,MAAM,EAAE,gBAAgB,EAAE,GAAG,EAAE,iBAAiB,GAAG,eAAe,CAAC,OAAO,CAAC,CAuCrG;AAmID,wBAAgB,YAAY,CAAC,MAAM,EAAE,gBAAgB,EAAE,GAAG,EAAE,iBAAiB,GAAG,eAAe,CAAC,OAAO,CAAC,CAiDvG;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,gBAAgB,EAAE,GAAG,EAAE,iBAAiB,GAAG,eAAe,CAAC,OAAO,CAAC,CA+DvG;AAoJD,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,gBAAgB,EAAE,GAAG,EAAE,iBAAiB,GAAG,eAAe,CAAC,OAAO,CAAC,CAcjI"}
1
+ {"version":3,"file":"agent-management.d.ts","sourceRoot":"","sources":["../../../src/agents/agent-management.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,EACN,KAAK,WAAW,EAQhB,iBAAiB,EASjB,MAAM,aAAa,CAAC;AAcrB,OAAO,KAAK,EAAkE,OAAO,EAAE,eAAe,EAAoB,MAAM,oBAAoB,CAAC;AAIrJ,OAAO,EAAsB,KAAK,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAKzF,KAAK,iBAAiB,GAAG,IAAI,CAAC,gBAAgB,EAAE,KAAK,GAAG,eAAe,CAAC,GAAG;IAAE,KAAK,CAAC,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAAC,MAAM,CAAC,EAAE,eAAe,CAAC;IAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAAC,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IAAC,eAAe,CAAC,EAAE,MAAM,IAAI,CAAC;IAAC,iBAAiB,CAAC,EAAE,OAAO,iBAAiB,CAAA;CAAE,CAAC;AAMzR,UAAU,gBAAgB;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,MAAM,CAAC,EAAE,OAAO,CAAC;CACjB;AAoMD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,WAAW,GAAG,WAAW,CA8EnE;AAWD,wBAAgB,+BAA+B,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,CAsD7G;AA+jBD,wBAAgB,UAAU,CAAC,MAAM,EAAE,gBAAgB,EAAE,GAAG,EAAE,iBAAiB,GAAG,eAAe,CAAC,OAAO,CAAC,CAuCrG;AAmID,wBAAgB,YAAY,CAAC,MAAM,EAAE,gBAAgB,EAAE,GAAG,EAAE,iBAAiB,GAAG,eAAe,CAAC,OAAO,CAAC,CAiDvG;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,gBAAgB,EAAE,GAAG,EAAE,iBAAiB,GAAG,eAAe,CAAC,OAAO,CAAC,CA+DvG;AAoJD,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,gBAAgB,EAAE,GAAG,EAAE,iBAAiB,GAAG,eAAe,CAAC,OAAO,CAAC,CAcjI"}
@@ -17,6 +17,9 @@ import { previewDisplayText } from "../shared/display-text.js";
17
17
  import { capabilityCeilingAgentRestrictionSources, isAgentAllowedByCapabilityCeiling, resolveCurrentSubagentCapabilityCeiling } from "../runs/shared/capability-ceiling.js";
18
18
  import { mergeRuntimeAgents } from "./runtime-agent-registry.js";
19
19
  import { listExternalJobProviders } from "../api/external-job-provider.js";
20
+ function discoverCatalog(ctx, cwd = ctx.cwd, provider) {
21
+ return (ctx.discoverAgentsAll ?? discoverAgentsAll)(cwd, provider);
22
+ }
20
23
  function result(text, isError = false, details) {
21
24
  return { content: [{ type: "text", text }], isError, details: { mode: "management", results: [], ...details } };
22
25
  }
@@ -97,8 +100,8 @@ function availableAgentNamesFromDiscovery(d, runtimeAgentOwner, preferredModelPr
97
100
  const agents = runtimeAgentOwner ? effectiveAgentsForScope("both", d, runtimeAgentOwner, preferredModelProvider) : allAgents(d);
98
101
  return [...new Set(agents.map((agent) => agent.name))].sort((a, b) => a.localeCompare(b));
99
102
  }
100
- function availableAgentNames(cwd) {
101
- return availableAgentNamesFromDiscovery(discoverAgentsAll(cwd));
103
+ function availableAgentNames(ctx, cwd = ctx.cwd) {
104
+ return availableAgentNamesFromDiscovery(discoverCatalog(ctx, cwd));
102
105
  }
103
106
  function findAgentsInDiscovery(name, d, scope = "both", runtimeAgentOwner, preferredModelProvider) {
104
107
  const raw = name.trim();
@@ -114,8 +117,8 @@ function findAgentsInDiscovery(name, d, scope = "both", runtimeAgentOwner, prefe
114
117
  || (sanitized !== raw && Boolean(resolveAgentName(sanitized, [agent]).agent)))
115
118
  .sort((a, b) => a.source.localeCompare(b.source));
116
119
  }
117
- function findAgents(name, cwd, scope = "both") {
118
- return findAgentsInDiscovery(name, discoverAgentsAll(cwd), scope);
120
+ function findAgents(name, ctx, scope = "both") {
121
+ return findAgentsInDiscovery(name, discoverCatalog(ctx), scope);
119
122
  }
120
123
  function diagnosticsForScope(diagnostics, scope) {
121
124
  if (scope === "both")
@@ -142,8 +145,8 @@ function resolveEffectiveAgent(d, name) {
142
145
  const matches = candidates.filter((agent) => agent.name === resolved.agent.name);
143
146
  return { agent: matches.reduce((best, agent) => (AGENT_SOURCE_PRECEDENCE[agent.source] > AGENT_SOURCE_PRECEDENCE[best.source] ? agent : best)) };
144
147
  }
145
- function nameExistsInScope(cwd, scope, name, excludePath) {
146
- const d = discoverAgentsAll(cwd);
148
+ function nameExistsInScope(ctx, scope, name, excludePath) {
149
+ const d = discoverCatalog(ctx);
147
150
  for (const a of scope === "user" ? d.user : d.project) {
148
151
  if (a.name === name && a.filePath !== excludePath)
149
152
  return true;
@@ -664,7 +667,7 @@ function applyAgentConfig(target, cfg) {
664
667
  }
665
668
  return undefined;
666
669
  }
667
- function resolveTarget(name, matches, cwd, scopeHint) {
670
+ function resolveTarget(name, matches, cwd, ctx, scopeHint) {
668
671
  const distinctNames = [...new Set(matches.map((match) => match.name))];
669
672
  if (distinctNames.length > 1)
670
673
  return result(`Ambiguous agent alias or name '${name}': ${distinctNames.sort((a, b) => a.localeCompare(b)).join(", ")}`, true);
@@ -672,7 +675,7 @@ function resolveTarget(name, matches, cwd, scopeHint) {
672
675
  if (mutable.length === 0) {
673
676
  if (matches.length > 0)
674
677
  return result(`Agent '${name}' is read-only and cannot be modified. Create a same-named agent in user or project scope to override it.`, true);
675
- return result(`Agent '${name}' not found. Available: ${availableAgentNames(cwd).join(", ") || "none"}.`, true);
678
+ return result(`Agent '${name}' not found. Available: ${availableAgentNames(ctx, cwd).join(", ") || "none"}.`, true);
676
679
  }
677
680
  if (mutable.length === 1)
678
681
  return mutable[0];
@@ -688,8 +691,8 @@ function resolveTarget(name, matches, cwd, scopeHint) {
688
691
  return result(`Multiple agents named '${name}' found in scope '${scope}': ${scoped.map((match) => match.filePath).join(", ")}`, true);
689
692
  return scoped[0];
690
693
  }
691
- function renamePath(currentPath, newName, scope, cwd) {
692
- if (nameExistsInScope(cwd, scope, newName, currentPath))
694
+ function renamePath(currentPath, newName, scope, ctx) {
695
+ if (nameExistsInScope(ctx, scope, newName, currentPath))
693
696
  return { error: `Name '${newName}' already exists in ${scope} scope.` };
694
697
  const filePath = path.join(path.dirname(currentPath), `${newName}.md`);
695
698
  if (fs.existsSync(filePath) && filePath !== currentPath)
@@ -1017,7 +1020,7 @@ function formatAgentDetail(agent) {
1017
1020
  }
1018
1021
  export function handleList(params, ctx) {
1019
1022
  const scope = normalizeListScope(params.agentScope) ?? "both";
1020
- const d = discoverAgentsAll(ctx.cwd, ctx.model?.provider);
1023
+ const d = discoverCatalog(ctx, ctx.cwd, ctx.model?.provider);
1021
1024
  let scopedAgents = effectiveAgentsForScope(scope, d, ctx.runtimeAgentOwner, ctx.model?.provider);
1022
1025
  scopedAgents = scopedAgents
1023
1026
  .sort((a, b) => a.name.localeCompare(b.name));
@@ -1074,7 +1077,7 @@ function handleModels(params, ctx) {
1074
1077
  const scope = normalizeListScope(params.agentScope);
1075
1078
  if (!scope)
1076
1079
  return result("agentScope must be 'user', 'project', or 'both' for models.", true);
1077
- const discovered = discoverAgentsAll(ctx.cwd, ctx.model?.provider);
1080
+ const discovered = discoverCatalog(ctx, ctx.cwd, ctx.model?.provider);
1078
1081
  const effectiveAgents = effectiveAgentsForScope(scope, discovered, ctx.runtimeAgentOwner, ctx.model?.provider)
1079
1082
  .sort((a, b) => a.name.localeCompare(b.name));
1080
1083
  const availableModels = ctx.modelRegistry.getAvailable().map(toModelInfo);
@@ -1174,7 +1177,7 @@ function handleGet(params, ctx) {
1174
1177
  const scope = normalizeListScope(params.agentScope);
1175
1178
  if (!scope)
1176
1179
  return result("agentScope must be 'user', 'project', or 'both' for get.", true);
1177
- const discovered = discoverAgentsAll(ctx.cwd, ctx.model?.provider);
1180
+ const discovered = discoverCatalog(ctx, ctx.cwd, ctx.model?.provider);
1178
1181
  const matches = findAgentsInDiscovery(params.agent, discovered, scope);
1179
1182
  const diagnostics = diagnosticsForScope(discovered.agentDiagnostics, scope);
1180
1183
  const rawName = params.agent.trim();
@@ -1215,11 +1218,11 @@ export function handleCreate(params, ctx) {
1215
1218
  const scope = scopeRaw;
1216
1219
  if (hasKey(cfg, "steps"))
1217
1220
  return result("Durable chain definitions were removed; use workflowScript or /prompt-workflow for repeatable workflows.", true);
1218
- const d = discoverAgentsAll(ctx.cwd);
1221
+ const d = discoverCatalog(ctx);
1219
1222
  const projectConfigDir = getProjectConfigDir(ctx.cwd);
1220
1223
  const targetDir = scope === "user" ? d.userDir : d.projectDir ?? path.join(projectConfigDir, "agents");
1221
1224
  fs.mkdirSync(targetDir, { recursive: true });
1222
- if (nameExistsInScope(ctx.cwd, scope, runtimeName))
1225
+ if (nameExistsInScope(ctx, scope, runtimeName))
1223
1226
  return result(`Name '${runtimeName}' already exists in ${scope} scope. Use update instead.`, true);
1224
1227
  const targetPath = path.join(targetDir, `${runtimeName}.md`);
1225
1228
  if (fs.existsSync(targetPath))
@@ -1269,7 +1272,7 @@ export function handleUpdate(params, ctx) {
1269
1272
  return result("Durable chain definitions were removed; use workflowScript or /prompt-workflow for repeatable workflows.", true);
1270
1273
  const warnings = [];
1271
1274
  const scopeHint = asDisambiguationScope(params.agentScope);
1272
- const targetOrError = resolveTarget(params.agent, findAgents(params.agent, ctx.cwd, scopeHint ?? "both"), ctx.cwd, scopeHint);
1275
+ const targetOrError = resolveTarget(params.agent, findAgents(params.agent, ctx, scopeHint ?? "both"), ctx.cwd, ctx, scopeHint);
1273
1276
  if ("content" in targetOrError)
1274
1277
  return targetOrError;
1275
1278
  const target = targetOrError;
@@ -1327,7 +1330,7 @@ export function handleUpdate(params, ctx) {
1327
1330
  warnings.push(sw);
1328
1331
  }
1329
1332
  if (updated.name !== oldName) {
1330
- const renamed = renamePath(target.filePath, updated.name, target.source, ctx.cwd);
1333
+ const renamed = renamePath(target.filePath, updated.name, target.source, ctx);
1331
1334
  if (renamed.error)
1332
1335
  return result(renamed.error, true);
1333
1336
  updated.filePath = renamed.filePath;
@@ -1343,7 +1346,7 @@ function handleDelete(params, ctx) {
1343
1346
  if (!params.agent)
1344
1347
  return result("Specify 'agent' for delete.", true);
1345
1348
  const scopeHint = asDisambiguationScope(params.agentScope);
1346
- const targetOrError = resolveTarget(params.agent, findAgents(params.agent, ctx.cwd, scopeHint ?? "both"), ctx.cwd, scopeHint);
1349
+ const targetOrError = resolveTarget(params.agent, findAgents(params.agent, ctx, scopeHint ?? "both"), ctx.cwd, ctx, scopeHint);
1347
1350
  if ("content" in targetOrError)
1348
1351
  return targetOrError;
1349
1352
  const target = targetOrError;
@@ -1360,17 +1363,17 @@ function handleEject(params, ctx) {
1360
1363
  if (parsedScope.error)
1361
1364
  return parsedScope.error;
1362
1365
  const scope = parsedScope.scope;
1363
- const d = discoverAgentsAll(ctx.cwd);
1366
+ const d = discoverCatalog(ctx);
1364
1367
  const source = [...d.package, ...d.builtin].find((a) => a.name === raw || a.name === sanitized);
1365
1368
  if (!source) {
1366
- return result(`Agent '${raw}' not found or is not a bundled/package agent. eject copies a builtin or package agent to ${scope} scope so it can be customized. Available: ${availableAgentNames(ctx.cwd).join(", ") || "none"}.`, true);
1369
+ return result(`Agent '${raw}' not found or is not a bundled/package agent. eject copies a builtin or package agent to ${scope} scope so it can be customized. Available: ${availableAgentNames(ctx).join(", ") || "none"}.`, true);
1367
1370
  }
1368
1371
  const runtimeName = source.name;
1369
1372
  const existingCustom = (scope === "user" ? d.user : d.project).find((a) => a.name === runtimeName);
1370
1373
  if (existingCustom) {
1371
1374
  return result(`Agent '${runtimeName}' is already a custom ${scope} agent at ${existingCustom.filePath}. Edit it with { action: "update", agent: "${runtimeName}" } or delete it first.`, true);
1372
1375
  }
1373
- if (nameExistsInScope(ctx.cwd, scope, runtimeName)) {
1376
+ if (nameExistsInScope(ctx, scope, runtimeName)) {
1374
1377
  return result(`An agent named '${runtimeName}' already exists in ${scope} scope. Remove or rename it first.`, true);
1375
1378
  }
1376
1379
  const projectConfigDir = getProjectConfigDir(ctx.cwd);
@@ -1400,7 +1403,7 @@ function handleDisable(params, ctx) {
1400
1403
  if (parsedScope.error)
1401
1404
  return parsedScope.error;
1402
1405
  const scope = parsedScope.scope;
1403
- const d = discoverAgentsAll(ctx.cwd);
1406
+ const d = discoverCatalog(ctx);
1404
1407
  if (scope === "project" && d.projectSettingsPath === null) {
1405
1408
  return result("Project override is not available here: no project config root (.pi or .agents) was found above the cwd. Use agentScope: 'user' or run from inside a project.", true);
1406
1409
  }
@@ -1408,11 +1411,11 @@ function handleDisable(params, ctx) {
1408
1411
  if (effective.error)
1409
1412
  return result(effective.error, true);
1410
1413
  if (!effective.agent) {
1411
- return result(`Agent '${raw}' not found. Available: ${availableAgentNames(ctx.cwd).join(", ") || "none"}.`, true);
1414
+ return result(`Agent '${raw}' not found. Available: ${availableAgentNames(ctx).join(", ") || "none"}.`, true);
1412
1415
  }
1413
1416
  const runtimeName = effective.agent.name;
1414
1417
  const settingsPath = mergeBuiltinAgentOverride(ctx.cwd, runtimeName, scope, { disabled: true });
1415
- const after = resolveEffectiveAgent(discoverAgentsAll(ctx.cwd), raw).agent;
1418
+ const after = resolveEffectiveAgent(discoverCatalog(ctx), raw).agent;
1416
1419
  if (after?.disabled === true) {
1417
1420
  ctx.onAgentsChanged?.();
1418
1421
  return result(`Disabled agent '${runtimeName}' via ${scope} settings override at ${settingsPath}. It is now hidden from runtime discovery and { action: "list" }.`);
@@ -1427,7 +1430,7 @@ function handleEnable(params, ctx) {
1427
1430
  if (parsedScope.error)
1428
1431
  return parsedScope.error;
1429
1432
  const scope = parsedScope.scope;
1430
- const d = discoverAgentsAll(ctx.cwd);
1433
+ const d = discoverCatalog(ctx);
1431
1434
  if (scope === "project" && d.projectSettingsPath === null) {
1432
1435
  return result("Project override is not available here: no project config root (.pi or .agents) was found above the cwd. Use agentScope: 'user' or run from inside a project.", true);
1433
1436
  }
@@ -1435,11 +1438,11 @@ function handleEnable(params, ctx) {
1435
1438
  if (effective.error)
1436
1439
  return result(effective.error, true);
1437
1440
  if (!effective.agent) {
1438
- return result(`Agent '${raw}' not found. Available: ${availableAgentNames(ctx.cwd).join(", ") || "none"}.`, true);
1441
+ return result(`Agent '${raw}' not found. Available: ${availableAgentNames(ctx).join(", ") || "none"}.`, true);
1439
1442
  }
1440
1443
  const runtimeName = effective.agent.name;
1441
1444
  const { path: settingsPath, removed } = removeBuiltinAgentOverrideFields(ctx.cwd, runtimeName, scope, ["disabled"]);
1442
- const after = resolveEffectiveAgent(discoverAgentsAll(ctx.cwd), raw).agent;
1445
+ const after = resolveEffectiveAgent(discoverCatalog(ctx), raw).agent;
1443
1446
  if (after && after.disabled !== true) {
1444
1447
  if (removed)
1445
1448
  ctx.onAgentsChanged?.();
@@ -1461,7 +1464,7 @@ function handleReset(params, ctx) {
1461
1464
  if (parsedScope.error)
1462
1465
  return parsedScope.error;
1463
1466
  const scope = parsedScope.scope;
1464
- const d = discoverAgentsAll(ctx.cwd);
1467
+ const d = discoverCatalog(ctx);
1465
1468
  if (scope === "project" && d.projectSettingsPath === null) {
1466
1469
  return result("Project override is not available here: no project config root (.pi or .agents) was found above the cwd. Use agentScope: 'user' or run from inside a project.", true);
1467
1470
  }
@@ -1471,7 +1474,7 @@ function handleReset(params, ctx) {
1471
1474
  if (custom) {
1472
1475
  return result(`Agent '${raw}' has no bundled default to reset to. Use { action: "delete", agent: "${custom.name}" } to remove the custom ${custom.source} agent.`, true);
1473
1476
  }
1474
- return result(`Agent '${raw}' not found. Available: ${availableAgentNames(ctx.cwd).join(", ") || "none"}.`, true);
1477
+ return result(`Agent '${raw}' not found. Available: ${availableAgentNames(ctx).join(", ") || "none"}.`, true);
1475
1478
  }
1476
1479
  const runtimeName = bundled.name;
1477
1480
  const custom = (scope === "user" ? d.user : d.project).find((a) => a.name === raw || a.name === sanitized);