@fitchmultz/pi-subagents 0.0.0-stage → 0.44.5

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 (347) hide show
  1. package/CHANGELOG.md +1654 -0
  2. package/LICENSE +21 -0
  3. package/README.md +1533 -2
  4. package/agents/context-builder.md +97 -0
  5. package/agents/debugger.md +51 -0
  6. package/agents/delegate.md +13 -0
  7. package/agents/fixer.md +37 -0
  8. package/agents/oracle.md +71 -0
  9. package/agents/planner.md +72 -0
  10. package/agents/researcher.md +51 -0
  11. package/agents/reviewer-claude.md +69 -0
  12. package/agents/reviewer-gpt.md +68 -0
  13. package/agents/reviewer-ponytail.md +82 -0
  14. package/agents/reviewer-security.md +81 -0
  15. package/agents/reviewer.md +69 -0
  16. package/agents/scout.md +66 -0
  17. package/agents/ui-designer.md +51 -0
  18. package/agents/watcher.md +26 -0
  19. package/agents/worker.md +46 -0
  20. package/agents/writer.md +36 -0
  21. package/dist/agents/agent-management.js +923 -0
  22. package/dist/agents/agent-scope.js +7 -0
  23. package/dist/agents/agent-selection.js +20 -0
  24. package/dist/agents/agent-serializer.js +100 -0
  25. package/dist/agents/agents.js +752 -0
  26. package/dist/agents/chain-serializer.js +367 -0
  27. package/dist/agents/frontmatter.js +21 -0
  28. package/dist/agents/identity.js +29 -0
  29. package/dist/agents/skills.js +570 -0
  30. package/dist/extension/build-info.js +1 -0
  31. package/dist/extension/compact-tools.js +112 -0
  32. package/dist/extension/config.js +22 -0
  33. package/dist/extension/control-notices.js +29 -0
  34. package/dist/extension/doctor.js +143 -0
  35. package/dist/extension/fanout-child.js +326 -0
  36. package/dist/extension/index.js +577 -0
  37. package/dist/extension/schemas.js +416 -0
  38. package/dist/extension/tool-input.js +20 -0
  39. package/dist/extension/tool-result.js +14 -0
  40. package/dist/history/canonical-result.js +81 -0
  41. package/dist/history/database.js +72 -0
  42. package/dist/history/index.js +199 -0
  43. package/dist/history/ingest.js +468 -0
  44. package/dist/history/queries.js +350 -0
  45. package/dist/history/store.js +216 -0
  46. package/dist/history/types.js +4 -0
  47. package/dist/history/worker.js +466 -0
  48. package/dist/intercom/intercom-bridge.js +112 -0
  49. package/dist/intercom/live-intercom.js +94 -0
  50. package/dist/intercom/result-intercom.js +373 -0
  51. package/dist/pi-intercom/agent-dir.js +10 -0
  52. package/dist/pi-intercom/bridge.js +750 -0
  53. package/dist/pi-intercom/broker/broker.js +426 -0
  54. package/dist/pi-intercom/broker/client.js +492 -0
  55. package/dist/pi-intercom/broker/framing.js +65 -0
  56. package/dist/pi-intercom/broker/paths.js +42 -0
  57. package/dist/pi-intercom/broker/pid.js +66 -0
  58. package/dist/pi-intercom/broker/spawn.js +221 -0
  59. package/dist/pi-intercom/config.js +102 -0
  60. package/dist/pi-intercom/index.js +2942 -0
  61. package/dist/pi-intercom/reply-tracker.js +182 -0
  62. package/dist/pi-intercom/session-targets.js +128 -0
  63. package/dist/pi-intercom/subagent-live-events.js +132 -0
  64. package/dist/pi-intercom/topics.js +157 -0
  65. package/dist/pi-intercom/types.js +163 -0
  66. package/dist/pi-intercom/ui/compose.js +269 -0
  67. package/dist/pi-intercom/ui/inline-message.js +80 -0
  68. package/dist/pi-intercom/ui/session-list.js +124 -0
  69. package/dist/runs/background/async-control.js +95 -0
  70. package/dist/runs/background/async-execution.js +676 -0
  71. package/dist/runs/background/async-job-tracker.js +383 -0
  72. package/dist/runs/background/async-result-file.js +58 -0
  73. package/dist/runs/background/async-resume.js +305 -0
  74. package/dist/runs/background/async-status.js +442 -0
  75. package/dist/runs/background/completion-dedupe.js +69 -0
  76. package/dist/runs/background/completion-delivery.js +245 -0
  77. package/dist/runs/background/notify.js +71 -0
  78. package/dist/runs/background/parallel-groups.js +55 -0
  79. package/dist/runs/background/result-watcher.js +426 -0
  80. package/dist/runs/background/run-id-resolver.js +64 -0
  81. package/dist/runs/background/run-status.js +382 -0
  82. package/dist/runs/background/stale-run-reconciler.js +335 -0
  83. package/dist/runs/background/subagent-runner-launcher.js +55 -0
  84. package/dist/runs/background/subagent-runner.js +1872 -0
  85. package/dist/runs/background/top-level-async.js +5 -0
  86. package/dist/runs/foreground/chain-clarify.js +1152 -0
  87. package/dist/runs/foreground/clarify-invocation.js +72 -0
  88. package/dist/runs/foreground/execution-input.js +423 -0
  89. package/dist/runs/foreground/foreground-control.js +817 -0
  90. package/dist/runs/foreground/question-control.js +88 -0
  91. package/dist/runs/foreground/run-async-path.js +205 -0
  92. package/dist/runs/foreground/subagent-executor.js +442 -0
  93. package/dist/runs/foreground/subagent-params.js +165 -0
  94. package/dist/runs/foreground/wait-run.js +141 -0
  95. package/dist/runs/shared/acceptance-contract.js +253 -0
  96. package/dist/runs/shared/acceptance-evaluation.js +256 -0
  97. package/dist/runs/shared/acceptance-finalization.js +280 -0
  98. package/dist/runs/shared/acceptance-reports.js +147 -0
  99. package/dist/runs/shared/acceptance.js +4 -0
  100. package/dist/runs/shared/chain-outputs.js +110 -0
  101. package/dist/runs/shared/child-attempt.js +693 -0
  102. package/dist/runs/shared/child-execution-cwd.js +96 -0
  103. package/dist/runs/shared/child-observations.js +114 -0
  104. package/dist/runs/shared/claude-code.js +199 -0
  105. package/dist/runs/shared/completion-guard.js +31 -0
  106. package/dist/runs/shared/dynamic-fanout.js +274 -0
  107. package/dist/runs/shared/history-index.js +72 -0
  108. package/dist/runs/shared/mcp-direct-tool-allowlist.js +334 -0
  109. package/dist/runs/shared/model-fallback.js +185 -0
  110. package/dist/runs/shared/mutating-tool-guard.js +170 -0
  111. package/dist/runs/shared/native-finalization.js +101 -0
  112. package/dist/runs/shared/native-usage.js +153 -0
  113. package/dist/runs/shared/nested-events.js +700 -0
  114. package/dist/runs/shared/nested-path.js +48 -0
  115. package/dist/runs/shared/nested-render.js +108 -0
  116. package/dist/runs/shared/parallel-utils.js +61 -0
  117. package/dist/runs/shared/parent-receipts.js +68 -0
  118. package/dist/runs/shared/parent-usage.js +121 -0
  119. package/dist/runs/shared/pi-args.js +310 -0
  120. package/dist/runs/shared/pi-spawn.js +52 -0
  121. package/dist/runs/shared/run-history-queries.js +45 -0
  122. package/dist/runs/shared/run-history.js +110 -0
  123. package/dist/runs/shared/run-id-ambiguity.js +4 -0
  124. package/dist/runs/shared/run-records.js +679 -0
  125. package/dist/runs/shared/session-cwd-preload.js +33 -0
  126. package/dist/runs/shared/single-output.js +222 -0
  127. package/dist/runs/shared/streaming-text.js +15 -0
  128. package/dist/runs/shared/structured-output.js +55 -0
  129. package/dist/runs/shared/subagent-control.js +179 -0
  130. package/dist/runs/shared/subagent-prompt-runtime.js +197 -0
  131. package/dist/runs/shared/subagent-tool-loop-guard.js +66 -0
  132. package/dist/runs/shared/supervisor-questions.js +350 -0
  133. package/dist/runs/shared/workflow-graph.js +214 -0
  134. package/dist/runs/shared/workflow-policy.js +84 -0
  135. package/dist/runs/shared/worktree.js +525 -0
  136. package/dist/shared/agent-context-policy.js +126 -0
  137. package/dist/shared/artifacts.js +96 -0
  138. package/dist/shared/atomic-json.js +13 -0
  139. package/dist/shared/cooperative.js +20 -0
  140. package/dist/shared/execution-cwd.js +14 -0
  141. package/dist/shared/file-coalescer.js +21 -0
  142. package/dist/shared/fork-context.js +49 -0
  143. package/dist/shared/formatters.js +85 -0
  144. package/dist/shared/journal-reader.js +407 -0
  145. package/dist/shared/lazy-tools.js +32 -0
  146. package/dist/shared/model-info.js +68 -0
  147. package/dist/shared/native-session.js +15 -0
  148. package/dist/shared/native-tui.js +18 -0
  149. package/dist/shared/native-typebox.js +20 -0
  150. package/dist/shared/post-exit-stdio-guard.js +197 -0
  151. package/dist/shared/prompt-sections.js +8 -0
  152. package/dist/shared/session-entries.js +52 -0
  153. package/dist/shared/session-identity.js +14 -0
  154. package/dist/shared/settings.js +254 -0
  155. package/dist/shared/status-format.js +111 -0
  156. package/dist/shared/temp-root.js +114 -0
  157. package/dist/shared/types.js +207 -0
  158. package/dist/shared/ui-mode.js +3 -0
  159. package/dist/shared/utils.js +334 -0
  160. package/dist/slash/prompt-template-bridge.js +298 -0
  161. package/dist/slash/slash-bridge.js +116 -0
  162. package/dist/slash/slash-commands.js +607 -0
  163. package/dist/slash/slash-live-state.js +246 -0
  164. package/dist/tui/action-hints.js +75 -0
  165. package/dist/tui/agent-history.js +197 -0
  166. package/dist/tui/agent-view.js +1656 -0
  167. package/dist/tui/render.js +1515 -0
  168. package/docs/intercom-bridge.md +212 -0
  169. package/docs/intercom.md +581 -0
  170. package/docs/performance.md +121 -0
  171. package/package.json +102 -4
  172. package/prompts/gather-context-and-clarify.md +14 -0
  173. package/prompts/parallel-cleanup.md +62 -0
  174. package/prompts/parallel-context-build.md +56 -0
  175. package/prompts/parallel-handoff-plan.md +62 -0
  176. package/prompts/parallel-research.md +51 -0
  177. package/prompts/parallel-review.md +59 -0
  178. package/prompts/review-loop.md +42 -0
  179. package/scripts/build.mjs +134 -0
  180. package/scripts/check-compat.mjs +48 -0
  181. package/scripts/compat-host.mjs +19 -0
  182. package/scripts/intercom-bridge-credentials.mjs +143 -0
  183. package/scripts/intercom-remote.mjs +103 -0
  184. package/scripts/linux-smoke.sh +51 -0
  185. package/scripts/local-install-smoke.mjs +66 -0
  186. package/scripts/native-package-smoke.mjs +82 -0
  187. package/scripts/package-smoke.mjs +209 -0
  188. package/scripts/prepare.mjs +67 -0
  189. package/scripts/real-pi-smoke.mjs +415 -0
  190. package/scripts/run-tests.mjs +149 -0
  191. package/skills/pi-intercom/SKILL.md +113 -0
  192. package/skills/pi-intercom/evals/evals.json +29 -0
  193. package/skills/pi-intercom/evals/trigger-evals.json +47 -0
  194. package/skills/pi-intercom/references/peer-sessions.md +69 -0
  195. package/skills/pi-subagents/SKILL.md +76 -0
  196. package/skills/pi-subagents/evals/evals.json +29 -0
  197. package/skills/pi-subagents/evals/trigger-evals.json +42 -0
  198. package/skills/pi-subagents/references/full-orchestration-guide.md +863 -0
  199. package/src/agents/agent-management.ts +813 -0
  200. package/src/agents/agent-scope.ts +7 -0
  201. package/src/agents/agent-selection.ts +23 -0
  202. package/src/agents/agent-serializer.ts +99 -0
  203. package/src/agents/agents.ts +916 -0
  204. package/src/agents/chain-serializer.ts +329 -0
  205. package/src/agents/frontmatter.ts +21 -0
  206. package/src/agents/identity.ts +30 -0
  207. package/src/agents/skills.ts +637 -0
  208. package/src/extension/build-info.ts +2 -0
  209. package/src/extension/compact-tools.ts +114 -0
  210. package/src/extension/config.ts +23 -0
  211. package/src/extension/control-notices.ts +47 -0
  212. package/src/extension/doctor.ts +171 -0
  213. package/src/extension/fanout-child.ts +312 -0
  214. package/src/extension/index.ts +649 -0
  215. package/src/extension/schemas.ts +444 -0
  216. package/src/extension/tool-input.ts +19 -0
  217. package/src/extension/tool-result.ts +16 -0
  218. package/src/history/canonical-result.ts +62 -0
  219. package/src/history/database.ts +59 -0
  220. package/src/history/index.ts +156 -0
  221. package/src/history/ingest.ts +349 -0
  222. package/src/history/queries.ts +241 -0
  223. package/src/history/store.ts +203 -0
  224. package/src/history/types.ts +166 -0
  225. package/src/history/worker.ts +321 -0
  226. package/src/intercom/intercom-bridge.ts +123 -0
  227. package/src/intercom/live-intercom.ts +104 -0
  228. package/src/intercom/result-intercom.ts +429 -0
  229. package/src/pi-intercom/agent-dir.ts +9 -0
  230. package/src/pi-intercom/bridge.ts +668 -0
  231. package/src/pi-intercom/broker/broker.ts +463 -0
  232. package/src/pi-intercom/broker/client.ts +558 -0
  233. package/src/pi-intercom/broker/framing.ts +77 -0
  234. package/src/pi-intercom/broker/paths.ts +47 -0
  235. package/src/pi-intercom/broker/pid.ts +59 -0
  236. package/src/pi-intercom/broker/spawn.ts +248 -0
  237. package/src/pi-intercom/config.ts +142 -0
  238. package/src/pi-intercom/index.ts +2929 -0
  239. package/src/pi-intercom/reply-tracker.ts +211 -0
  240. package/src/pi-intercom/session-targets.ts +172 -0
  241. package/src/pi-intercom/subagent-live-events.ts +133 -0
  242. package/src/pi-intercom/topics.ts +125 -0
  243. package/src/pi-intercom/types.ts +271 -0
  244. package/src/pi-intercom/ui/compose.ts +289 -0
  245. package/src/pi-intercom/ui/inline-message.ts +92 -0
  246. package/src/pi-intercom/ui/session-list.ts +139 -0
  247. package/src/runs/background/async-control.ts +89 -0
  248. package/src/runs/background/async-execution.ts +850 -0
  249. package/src/runs/background/async-job-tracker.ts +385 -0
  250. package/src/runs/background/async-result-file.ts +62 -0
  251. package/src/runs/background/async-resume.ts +333 -0
  252. package/src/runs/background/async-status.ts +481 -0
  253. package/src/runs/background/completion-dedupe.ts +79 -0
  254. package/src/runs/background/completion-delivery.ts +195 -0
  255. package/src/runs/background/notify.ts +123 -0
  256. package/src/runs/background/parallel-groups.ts +53 -0
  257. package/src/runs/background/result-watcher.ts +423 -0
  258. package/src/runs/background/run-id-resolver.ts +69 -0
  259. package/src/runs/background/run-status.ts +384 -0
  260. package/src/runs/background/stale-run-reconciler.ts +369 -0
  261. package/src/runs/background/subagent-runner-launcher.ts +56 -0
  262. package/src/runs/background/subagent-runner.ts +2053 -0
  263. package/src/runs/background/top-level-async.ts +13 -0
  264. package/src/runs/foreground/chain-clarify.ts +1340 -0
  265. package/src/runs/foreground/clarify-invocation.ts +77 -0
  266. package/src/runs/foreground/execution-input.ts +467 -0
  267. package/src/runs/foreground/foreground-control.ts +821 -0
  268. package/src/runs/foreground/question-control.ts +82 -0
  269. package/src/runs/foreground/run-async-path.ts +243 -0
  270. package/src/runs/foreground/subagent-executor.ts +501 -0
  271. package/src/runs/foreground/subagent-params.ts +320 -0
  272. package/src/runs/foreground/wait-run.ts +124 -0
  273. package/src/runs/shared/acceptance-contract.ts +257 -0
  274. package/src/runs/shared/acceptance-evaluation.ts +275 -0
  275. package/src/runs/shared/acceptance-finalization.ts +353 -0
  276. package/src/runs/shared/acceptance-reports.ts +152 -0
  277. package/src/runs/shared/acceptance.ts +33 -0
  278. package/src/runs/shared/chain-outputs.ts +114 -0
  279. package/src/runs/shared/child-attempt.ts +623 -0
  280. package/src/runs/shared/child-execution-cwd.ts +91 -0
  281. package/src/runs/shared/child-observations.ts +99 -0
  282. package/src/runs/shared/claude-code.ts +243 -0
  283. package/src/runs/shared/completion-guard.ts +35 -0
  284. package/src/runs/shared/dynamic-fanout.ts +295 -0
  285. package/src/runs/shared/history-index.ts +69 -0
  286. package/src/runs/shared/mcp-direct-tool-allowlist.ts +376 -0
  287. package/src/runs/shared/model-fallback.ts +219 -0
  288. package/src/runs/shared/mutating-tool-guard.ts +194 -0
  289. package/src/runs/shared/native-finalization.ts +128 -0
  290. package/src/runs/shared/native-usage.ts +113 -0
  291. package/src/runs/shared/nested-events.ts +752 -0
  292. package/src/runs/shared/nested-path.ts +52 -0
  293. package/src/runs/shared/nested-render.ts +119 -0
  294. package/src/runs/shared/parallel-utils.ts +153 -0
  295. package/src/runs/shared/parent-receipts.ts +59 -0
  296. package/src/runs/shared/parent-usage.ts +121 -0
  297. package/src/runs/shared/pi-args.ts +350 -0
  298. package/src/runs/shared/pi-spawn.ts +52 -0
  299. package/src/runs/shared/run-history-queries.ts +44 -0
  300. package/src/runs/shared/run-history.ts +100 -0
  301. package/src/runs/shared/run-id-ambiguity.ts +4 -0
  302. package/src/runs/shared/run-records.ts +607 -0
  303. package/src/runs/shared/session-cwd-preload.ts +27 -0
  304. package/src/runs/shared/single-output.ts +267 -0
  305. package/src/runs/shared/streaming-text.ts +18 -0
  306. package/src/runs/shared/structured-output.ts +68 -0
  307. package/src/runs/shared/subagent-control.ts +219 -0
  308. package/src/runs/shared/subagent-prompt-runtime.ts +201 -0
  309. package/src/runs/shared/subagent-tool-loop-guard.ts +89 -0
  310. package/src/runs/shared/supervisor-questions.ts +415 -0
  311. package/src/runs/shared/workflow-graph.ts +220 -0
  312. package/src/runs/shared/workflow-policy.ts +125 -0
  313. package/src/runs/shared/worktree.ts +635 -0
  314. package/src/shared/agent-context-policy.ts +184 -0
  315. package/src/shared/artifacts.ts +95 -0
  316. package/src/shared/atomic-json.ts +16 -0
  317. package/src/shared/cooperative.ts +21 -0
  318. package/src/shared/execution-cwd.ts +14 -0
  319. package/src/shared/file-coalescer.ts +29 -0
  320. package/src/shared/fork-context.ts +68 -0
  321. package/src/shared/formatters.ts +84 -0
  322. package/src/shared/journal-reader.ts +333 -0
  323. package/src/shared/lazy-tools.ts +36 -0
  324. package/src/shared/model-info.ts +81 -0
  325. package/src/shared/native-session.ts +8 -0
  326. package/src/shared/native-tui.ts +10 -0
  327. package/src/shared/native-typebox.ts +14 -0
  328. package/src/shared/post-exit-stdio-guard.ts +204 -0
  329. package/src/shared/prompt-sections.ts +10 -0
  330. package/src/shared/session-entries.ts +49 -0
  331. package/src/shared/session-identity.ts +18 -0
  332. package/src/shared/settings.ts +384 -0
  333. package/src/shared/status-format.ts +123 -0
  334. package/src/shared/temp-root.ts +107 -0
  335. package/src/shared/types.ts +1260 -0
  336. package/src/shared/ui-mode.ts +5 -0
  337. package/src/shared/utils.ts +342 -0
  338. package/src/slash/prompt-template-bridge.ts +408 -0
  339. package/src/slash/slash-bridge.ts +178 -0
  340. package/src/slash/slash-commands.ts +617 -0
  341. package/src/slash/slash-live-state.ts +292 -0
  342. package/src/tui/action-hints.ts +69 -0
  343. package/src/tui/agent-history.ts +210 -0
  344. package/src/tui/agent-view.ts +1323 -0
  345. package/src/tui/render.ts +1550 -0
  346. package/tsconfig.build.json +12 -0
  347. package/tsconfig.json +19 -0
@@ -0,0 +1,607 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import * as fs from "node:fs";
3
+ import * as path from "node:path";
4
+ import { Key, matchesKey } from "@earendil-works/pi-tui";
5
+ import { discoverAgents, discoverAgentsAll } from "../agents/agents.js";
6
+ import { isDynamicParallelStep, isParallelStep } from "../shared/settings.js";
7
+ import { assertJsonSchemaObject } from "../runs/shared/structured-output.js";
8
+ import { applySlashUpdate, buildSlashInitialResult, failSlashResult, finalizeSlashResult, } from "./slash-live-state.js";
9
+ import { SLASH_RESULT_TYPE, SLASH_SUBAGENT_CANCEL_EVENT, SLASH_SUBAGENT_REQUEST_EVENT, SLASH_SUBAGENT_RESPONSE_EVENT, SLASH_SUBAGENT_STARTED_EVENT, SLASH_SUBAGENT_UPDATE_EVENT, } from "../shared/types.js";
10
+ import { isTuiContext } from "../shared/ui-mode.js";
11
+ import { resolveExecutionCwd } from "../shared/execution-cwd.js";
12
+ const parseInlineConfig = (raw) => {
13
+ const config = {};
14
+ for (const part of raw.split(",")) {
15
+ const trimmed = part.trim();
16
+ if (!trimmed)
17
+ continue;
18
+ const eq = trimmed.indexOf("=");
19
+ if (eq === -1) {
20
+ if (trimmed !== "progress")
21
+ throw new Error(`Unknown inline option '${trimmed}'.`);
22
+ config.progress = true;
23
+ continue;
24
+ }
25
+ const key = trimmed.slice(0, eq).trim();
26
+ const val = trimmed.slice(eq + 1).trim();
27
+ switch (key) {
28
+ case "output":
29
+ config.output = val === "false" ? false : val;
30
+ break;
31
+ case "outputMode":
32
+ if (val !== "inline" && val !== "file-only")
33
+ throw new Error("outputMode must be inline or file-only.");
34
+ config.outputMode = val;
35
+ break;
36
+ case "reads":
37
+ config.reads = val === "false" ? false : val.split("+").filter(Boolean);
38
+ break;
39
+ case "model":
40
+ config.model = val || undefined;
41
+ break;
42
+ case "skill":
43
+ case "skills":
44
+ config.skill = val === "false" ? false : val.split("+").filter(Boolean);
45
+ break;
46
+ case "progress":
47
+ if (val !== "true" && val !== "false")
48
+ throw new Error("progress must be true or false.");
49
+ config.progress = val === "true";
50
+ break;
51
+ default: throw new Error(`Unknown inline option '${key}'.`);
52
+ }
53
+ }
54
+ return config;
55
+ };
56
+ const parseAgentToken = (token) => {
57
+ const bracket = token.indexOf("[");
58
+ if (bracket === -1)
59
+ return { name: token, config: {} };
60
+ const end = token.lastIndexOf("]");
61
+ if (end !== token.length - 1 || end < bracket)
62
+ throw new Error(`Malformed inline options in '${token}'; close the trailing ].`);
63
+ const name = token.slice(0, bracket);
64
+ if (!name)
65
+ throw new Error("Agent name is required before inline options.");
66
+ return { name, config: parseInlineConfig(token.slice(bracket + 1, end)) };
67
+ };
68
+ const unwrapQuotedTask = (task) => {
69
+ const match = task.match(/^(?:"([\s\S]*)"|'([\s\S]*)')$/);
70
+ return match ? (match[1] ?? match[2] ?? "") : task;
71
+ };
72
+ const extractExecutionFlags = (rawArgs) => {
73
+ let args = rawArgs.trim();
74
+ let asyncMode;
75
+ let fork = false;
76
+ while (true) {
77
+ if (args.endsWith(" --bg") || args === "--bg") {
78
+ if (asyncMode === false)
79
+ return { args, fork, error: "Choose only one of --bg or --fg" };
80
+ asyncMode = true;
81
+ args = args === "--bg" ? "" : args.slice(0, -5).trim();
82
+ continue;
83
+ }
84
+ if (args.endsWith(" --fg") || args === "--fg") {
85
+ if (asyncMode === true)
86
+ return { args, fork, error: "Choose only one of --bg or --fg" };
87
+ asyncMode = false;
88
+ args = args === "--fg" ? "" : args.slice(0, -5).trim();
89
+ continue;
90
+ }
91
+ if (args.endsWith(" --fork") || args === "--fork") {
92
+ fork = true;
93
+ args = args === "--fork" ? "" : args.slice(0, -7).trim();
94
+ continue;
95
+ }
96
+ break;
97
+ }
98
+ return { args, async: asyncMode, fork };
99
+ };
100
+ const projectTrusted = (state) => state.lastUiContext ? state.lastUiContext.isProjectTrusted() : true;
101
+ const completionCwd = (pi, state) => {
102
+ try {
103
+ return state.lastUiContext ? resolveExecutionCwd(pi, state.lastUiContext) : state.baseCwd;
104
+ }
105
+ catch {
106
+ return null;
107
+ }
108
+ };
109
+ const makeAgentCompletions = (pi, state, multiAgent) => (prefix) => {
110
+ const cwd = completionCwd(pi, state);
111
+ if (!cwd)
112
+ return null;
113
+ const agents = discoverAgents(cwd, "both", { projectTrusted: projectTrusted(state) }).agents;
114
+ if (!multiAgent) {
115
+ if (prefix.includes(" "))
116
+ return null;
117
+ return agents.filter((a) => a.name.startsWith(prefix)).map((a) => ({ value: a.name, label: a.name }));
118
+ }
119
+ const lastArrow = prefix.lastIndexOf(" -> ");
120
+ const segment = lastArrow !== -1 ? prefix.slice(lastArrow + 4) : prefix;
121
+ if (segment.includes(" -- ") || segment.includes('"') || segment.includes("'"))
122
+ return null;
123
+ const lastWord = (prefix.match(/(\S*)$/) || ["", ""])[1];
124
+ const beforeLastWord = prefix.slice(0, prefix.length - lastWord.length);
125
+ if (lastWord === "->") {
126
+ return agents.map((a) => ({ value: `${prefix} ${a.name}`, label: a.name }));
127
+ }
128
+ return agents.filter((a) => a.name.startsWith(lastWord)).map((a) => ({ value: `${beforeLastWord}${a.name}`, label: a.name }));
129
+ };
130
+ const discoverSavedChains = (cwd, projectTrusted) => {
131
+ const chainsByName = new Map();
132
+ for (const chain of discoverAgentsAll(cwd, { projectTrusted }).chains) {
133
+ const existing = chainsByName.get(chain.name);
134
+ const projectOverride = existing?.source === "user" && chain.source === "project";
135
+ const sameScopeJsonOverride = existing?.source === chain.source && chain.filePath.endsWith(".chain.json") && !existing.filePath.endsWith(".chain.json");
136
+ if (!existing || projectOverride || sameScopeJsonOverride)
137
+ chainsByName.set(chain.name, chain);
138
+ }
139
+ return Array.from(chainsByName.values());
140
+ };
141
+ const makeChainCompletions = (pi, state) => (prefix) => {
142
+ const cwd = completionCwd(pi, state);
143
+ if (prefix.includes(" ") || !cwd)
144
+ return null;
145
+ return discoverSavedChains(cwd, projectTrusted(state))
146
+ .filter((chain) => chain.name.startsWith(prefix))
147
+ .map((chain) => ({ value: chain.name, label: chain.name }));
148
+ };
149
+ function loadSavedOutputSchema(chain, stepAgent, outputSchema) {
150
+ if (outputSchema === undefined)
151
+ return undefined;
152
+ if (typeof outputSchema === "string") {
153
+ const schemaPath = path.isAbsolute(outputSchema)
154
+ ? outputSchema
155
+ : path.join(path.dirname(chain.filePath), outputSchema);
156
+ const parsed = JSON.parse(fs.readFileSync(schemaPath, "utf-8"));
157
+ assertJsonSchemaObject(parsed, `outputSchema for chain '${chain.name}' step '${stepAgent}' (${schemaPath})`);
158
+ return parsed;
159
+ }
160
+ assertJsonSchemaObject(outputSchema, `outputSchema for chain '${chain.name}' step '${stepAgent}'`);
161
+ return outputSchema;
162
+ }
163
+ const mapSavedChainSteps = (chain, worktree = false) => {
164
+ return chain.steps.map((step) => {
165
+ if (isParallelStep(step)) {
166
+ const parallel = step.parallel.map((task) => {
167
+ const { outputSchema: rawOutputSchema, ...rest } = task;
168
+ const outputSchema = loadSavedOutputSchema(chain, task.agent, rawOutputSchema);
169
+ return { ...rest, ...(outputSchema ? { outputSchema } : {}) };
170
+ });
171
+ return { ...step, parallel, ...(worktree ? { worktree: true } : {}) };
172
+ }
173
+ if (isDynamicParallelStep(step)) {
174
+ const { outputSchema: rawOutputSchema, ...parallelRest } = step.parallel;
175
+ const outputSchema = loadSavedOutputSchema(chain, step.parallel.agent, rawOutputSchema);
176
+ const collectSchema = loadSavedOutputSchema(chain, `${step.collect.as} collection`, step.collect.outputSchema);
177
+ return {
178
+ ...step,
179
+ parallel: { ...parallelRest, ...(outputSchema ? { outputSchema } : {}) },
180
+ collect: { ...step.collect, ...(collectSchema ? { outputSchema: collectSchema } : {}) },
181
+ };
182
+ }
183
+ const outputSchema = loadSavedOutputSchema(chain, step.agent, step.outputSchema);
184
+ return {
185
+ agent: step.agent,
186
+ ...(step.task ? { task: step.task } : {}),
187
+ ...(step.cwd !== undefined ? { cwd: step.cwd } : {}),
188
+ ...(step.phase ? { phase: step.phase } : {}),
189
+ ...(step.label ? { label: step.label } : {}),
190
+ ...(step.as ? { as: step.as } : {}),
191
+ ...(outputSchema ? { outputSchema } : {}),
192
+ output: step.output,
193
+ outputMode: step.outputMode,
194
+ reads: step.reads,
195
+ progress: step.progress,
196
+ skill: step.skill ?? step.skills,
197
+ model: step.model,
198
+ ...(step.acceptance !== undefined ? { acceptance: step.acceptance } : {}),
199
+ };
200
+ });
201
+ };
202
+ async function requestSlashRun(pi, ctx, requestId, params, executionCwd) {
203
+ return new Promise((resolve, reject) => {
204
+ let done = false;
205
+ let started = false;
206
+ const startTimeoutMs = 15_000;
207
+ const startTimeout = setTimeout(() => {
208
+ finish(() => reject(new Error("Slash subagent bridge did not start within 15s. Ensure the extension is loaded correctly.")));
209
+ }, startTimeoutMs);
210
+ const onStarted = (data) => {
211
+ if (done || !data || typeof data !== "object")
212
+ return;
213
+ if (data.requestId !== requestId)
214
+ return;
215
+ started = true;
216
+ clearTimeout(startTimeout);
217
+ if (ctx.hasUI)
218
+ ctx.ui.setStatus("subagent-slash", "running...");
219
+ };
220
+ const onResponse = (data) => {
221
+ if (done || !data || typeof data !== "object")
222
+ return;
223
+ const response = data;
224
+ if (response.requestId !== requestId)
225
+ return;
226
+ clearTimeout(startTimeout);
227
+ finish(() => resolve(response));
228
+ };
229
+ const onUpdate = (data) => {
230
+ if (done || !data || typeof data !== "object")
231
+ return;
232
+ const update = data;
233
+ if (update.requestId !== requestId)
234
+ return;
235
+ applySlashUpdate(requestId, update);
236
+ if (!ctx.hasUI)
237
+ return;
238
+ const tool = update.currentTool ? ` ${update.currentTool}` : "";
239
+ const count = update.toolCount ?? 0;
240
+ ctx.ui.setStatus("subagent-slash", `${count} tools${tool}`);
241
+ };
242
+ const onTerminalInput = isTuiContext(ctx)
243
+ ? ctx.ui.onTerminalInput((input) => {
244
+ if (!matchesKey(input, Key.escape))
245
+ return undefined;
246
+ pi.events.emit(SLASH_SUBAGENT_CANCEL_EVENT, { requestId });
247
+ finish(() => reject(new Error("Cancelled")));
248
+ return { consume: true };
249
+ })
250
+ : undefined;
251
+ const unsubStarted = pi.events.on(SLASH_SUBAGENT_STARTED_EVENT, onStarted);
252
+ const unsubResponse = pi.events.on(SLASH_SUBAGENT_RESPONSE_EVENT, onResponse);
253
+ const unsubUpdate = pi.events.on(SLASH_SUBAGENT_UPDATE_EVENT, onUpdate);
254
+ const finish = (next) => {
255
+ if (done)
256
+ return;
257
+ done = true;
258
+ clearTimeout(startTimeout);
259
+ unsubStarted();
260
+ unsubResponse();
261
+ unsubUpdate();
262
+ onTerminalInput?.();
263
+ next();
264
+ };
265
+ pi.events.emit(SLASH_SUBAGENT_REQUEST_EVENT, { requestId, params, ...(executionCwd ? { executionCwd } : {}) });
266
+ // Bridge emits STARTED synchronously during REQUEST emit.
267
+ // If not started, no bridge received the request.
268
+ if (!started && done)
269
+ return;
270
+ if (!started) {
271
+ finish(() => reject(new Error("No slash subagent bridge responded. Ensure the subagent extension is loaded correctly.")));
272
+ }
273
+ });
274
+ }
275
+ function extractSlashMessageText(content) {
276
+ if (typeof content === "string")
277
+ return content;
278
+ if (!Array.isArray(content))
279
+ return "";
280
+ return content
281
+ .filter((part) => part?.type === "text" && typeof part.text === "string")
282
+ .map((part) => part.text)
283
+ .join("\n");
284
+ }
285
+ function formatExportPathList(paths) {
286
+ return paths.map((file) => `- \`${file}\``).join("\n");
287
+ }
288
+ function collectResultPaths(results, getPath) {
289
+ return results
290
+ .map(getPath)
291
+ .filter((file) => typeof file === "string" && file.length > 0);
292
+ }
293
+ function buildSlashExportText(response) {
294
+ const output = extractSlashMessageText(response.result.content) || response.errorText || "(no output)";
295
+ const results = response.result.details?.results ?? [];
296
+ const sessionFiles = collectResultPaths(results, (result) => result.sessionFile);
297
+ const savedOutputs = collectResultPaths(results, (result) => result.savedOutputPath);
298
+ const artifactOutputs = collectResultPaths(results, (result) => result.artifactPaths?.outputPath);
299
+ const sections = ["## Subagent result", output];
300
+ if (sessionFiles.length > 0)
301
+ sections.push("## Child session exports", formatExportPathList(sessionFiles));
302
+ if (savedOutputs.length > 0)
303
+ sections.push("## Saved outputs", formatExportPathList(savedOutputs));
304
+ if (artifactOutputs.length > 0)
305
+ sections.push("## Artifact outputs", formatExportPathList(artifactOutputs));
306
+ return sections.join("\n\n");
307
+ }
308
+ async function runSlashSubagent(pi, ctx, params, executionCwd) {
309
+ const requestId = randomUUID();
310
+ const initialDetails = buildSlashInitialResult(requestId, params);
311
+ const initialText = extractSlashMessageText(initialDetails.result.content) || "Running subagent...";
312
+ pi.sendMessage({
313
+ customType: SLASH_RESULT_TYPE,
314
+ content: initialText,
315
+ display: true,
316
+ details: initialDetails,
317
+ });
318
+ try {
319
+ const response = await requestSlashRun(pi, ctx, requestId, params, executionCwd);
320
+ const finalDetails = finalizeSlashResult(response);
321
+ pi.sendMessage({
322
+ customType: SLASH_RESULT_TYPE,
323
+ content: buildSlashExportText(response),
324
+ display: false,
325
+ details: finalDetails,
326
+ });
327
+ if (ctx.hasUI) {
328
+ ctx.ui.setStatus("subagent-slash", undefined);
329
+ }
330
+ if (response.isError && ctx.hasUI) {
331
+ ctx.ui.notify(response.errorText || "Subagent failed", "error");
332
+ }
333
+ }
334
+ catch (error) {
335
+ const message = error instanceof Error ? error.message : String(error);
336
+ const failedDetails = failSlashResult(requestId, params, message);
337
+ pi.sendMessage({
338
+ customType: SLASH_RESULT_TYPE,
339
+ content: `## Subagent result\n\n${message}`,
340
+ display: false,
341
+ details: failedDetails,
342
+ });
343
+ if (ctx.hasUI) {
344
+ ctx.ui.setStatus("subagent-slash", undefined);
345
+ }
346
+ if (message === "Cancelled") {
347
+ if (ctx.hasUI)
348
+ ctx.ui.notify("Cancelled", "warning");
349
+ return;
350
+ }
351
+ if (ctx.hasUI)
352
+ ctx.ui.notify(message, "error");
353
+ }
354
+ }
355
+ const parseAgentArgs = (cwd, args, command, ctx) => {
356
+ const input = args.trim();
357
+ const usage = `Usage: /${command} agent1 "task1" -> agent2 "task2"`;
358
+ let steps;
359
+ let sharedTask;
360
+ let perStep = false;
361
+ if (input.includes(" -> ")) {
362
+ perStep = true;
363
+ const segments = input.split(" -> ");
364
+ steps = [];
365
+ for (const seg of segments) {
366
+ const trimmed = seg.trim();
367
+ if (!trimmed)
368
+ continue;
369
+ let agentPart;
370
+ let task;
371
+ const qMatch = trimmed.match(/^(\S+(?:\[[^\]]*\])?)\s+(?:"([^"]*)"|'([^']*)')$/);
372
+ if (qMatch) {
373
+ agentPart = qMatch[1];
374
+ task = (qMatch[2] ?? qMatch[3]) || undefined;
375
+ }
376
+ else {
377
+ const dashIdx = trimmed.indexOf(" -- ");
378
+ if (dashIdx !== -1) {
379
+ agentPart = trimmed.slice(0, dashIdx).trim();
380
+ task = trimmed.slice(dashIdx + 4).trim() || undefined;
381
+ }
382
+ else {
383
+ agentPart = trimmed;
384
+ }
385
+ }
386
+ try {
387
+ const parsed = parseAgentToken(agentPart);
388
+ steps.push({ ...parsed, task });
389
+ }
390
+ catch (error) {
391
+ ctx.ui.notify(error instanceof Error ? error.message : String(error), "error");
392
+ return null;
393
+ }
394
+ }
395
+ sharedTask = steps.find((s) => s.task)?.task ?? "";
396
+ }
397
+ else {
398
+ const delimiterIndex = input.indexOf(" -- ");
399
+ if (delimiterIndex === -1) {
400
+ ctx.ui.notify(usage, "error");
401
+ return null;
402
+ }
403
+ const agentsPart = input.slice(0, delimiterIndex).trim();
404
+ sharedTask = input.slice(delimiterIndex + 4).trim();
405
+ if (!agentsPart || !sharedTask) {
406
+ ctx.ui.notify(usage, "error");
407
+ return null;
408
+ }
409
+ try {
410
+ steps = agentsPart.split(/\s+/).filter(Boolean).map((token) => parseAgentToken(token));
411
+ }
412
+ catch (error) {
413
+ ctx.ui.notify(error instanceof Error ? error.message : String(error), "error");
414
+ return null;
415
+ }
416
+ }
417
+ if (steps.length === 0) {
418
+ ctx.ui.notify(usage, "error");
419
+ return null;
420
+ }
421
+ const agents = discoverAgents(cwd, "both", { projectTrusted: ctx.isProjectTrusted() }).agents;
422
+ for (const step of steps) {
423
+ if (!agents.find((a) => a.name === step.name)) {
424
+ ctx.ui.notify(`Unknown agent: ${step.name}`, "error");
425
+ return null;
426
+ }
427
+ }
428
+ if (command === "chain" && !steps[0]?.task && (perStep || !sharedTask)) {
429
+ ctx.ui.notify(`First step must have a task: /chain agent "task" -> agent2`, "error");
430
+ return null;
431
+ }
432
+ if (command === "parallel" && !steps.some((s) => s.task) && !sharedTask) {
433
+ ctx.ui.notify("At least one step must have a task", "error");
434
+ return null;
435
+ }
436
+ return { steps, task: sharedTask };
437
+ };
438
+ export function registerSlashCommands(pi, state) {
439
+ pi.registerCommand("run", {
440
+ description: "Run a subagent directly: /run agent[output=file] [task] [--bg|--fg] [--fork]",
441
+ getArgumentCompletions: makeAgentCompletions(pi, state, false),
442
+ handler: async (args, ctx) => {
443
+ const flags = extractExecutionFlags(args);
444
+ if (flags.error) {
445
+ ctx.ui.notify(flags.error, "error");
446
+ return;
447
+ }
448
+ const { args: cleanedArgs, async: asyncMode, fork } = flags;
449
+ const input = cleanedArgs.trim();
450
+ const firstSpace = input.indexOf(" ");
451
+ if (!input) {
452
+ ctx.ui.notify("Usage: /run <agent> [task] [--bg|--fg] [--fork]", "error");
453
+ return;
454
+ }
455
+ let parsedAgent;
456
+ try {
457
+ parsedAgent = parseAgentToken(firstSpace === -1 ? input : input.slice(0, firstSpace));
458
+ }
459
+ catch (error) {
460
+ ctx.ui.notify(error instanceof Error ? error.message : String(error), "error");
461
+ return;
462
+ }
463
+ const { name: agentName, config: inline } = parsedAgent;
464
+ const task = firstSpace === -1 ? "" : unwrapQuotedTask(input.slice(firstSpace + 1).trim());
465
+ const cwd = resolveExecutionCwd(pi, ctx);
466
+ const agents = discoverAgents(cwd, "both", { projectTrusted: ctx.isProjectTrusted() }).agents;
467
+ if (!agents.find((a) => a.name === agentName)) {
468
+ ctx.ui.notify(`Unknown agent: ${agentName}`, "error");
469
+ return;
470
+ }
471
+ let finalTask = task;
472
+ if (inline.reads && Array.isArray(inline.reads) && inline.reads.length > 0) {
473
+ finalTask = `[Read from: ${inline.reads.join(", ")}]\n\n${finalTask}`;
474
+ }
475
+ const params = { agent: agentName, task: finalTask, clarify: false, agentScope: "both" };
476
+ if (inline.output !== undefined)
477
+ params.output = inline.output;
478
+ if (inline.outputMode !== undefined)
479
+ params.outputMode = inline.outputMode;
480
+ if (inline.skill !== undefined)
481
+ params.skill = inline.skill;
482
+ if (inline.model)
483
+ params.model = inline.model;
484
+ if (inline.progress !== undefined)
485
+ params.progress = inline.progress;
486
+ if (asyncMode !== undefined)
487
+ params.async = asyncMode;
488
+ if (fork)
489
+ params.context = "fork";
490
+ await runSlashSubagent(pi, ctx, params, cwd);
491
+ },
492
+ });
493
+ pi.registerCommand("chain", {
494
+ description: "Run agents in sequence: /chain scout \"task\" -> oracle [--bg|--fg] [--fork]",
495
+ getArgumentCompletions: makeAgentCompletions(pi, state, true),
496
+ handler: async (args, ctx) => {
497
+ const flags = extractExecutionFlags(args);
498
+ if (flags.error) {
499
+ ctx.ui.notify(flags.error, "error");
500
+ return;
501
+ }
502
+ const { args: cleanedArgs, async: asyncMode, fork } = flags;
503
+ const cwd = resolveExecutionCwd(pi, ctx);
504
+ const parsed = parseAgentArgs(cwd, cleanedArgs, "chain", ctx);
505
+ if (!parsed)
506
+ return;
507
+ const chain = parsed.steps.map(({ name, config, task: stepTask }, i) => ({
508
+ agent: name,
509
+ ...(stepTask ? { task: stepTask } : i === 0 && parsed.task ? { task: parsed.task } : {}),
510
+ ...(config.output !== undefined ? { output: config.output } : {}),
511
+ ...(config.outputMode !== undefined ? { outputMode: config.outputMode } : {}),
512
+ ...(config.reads !== undefined ? { reads: config.reads } : {}),
513
+ ...(config.model ? { model: config.model } : {}),
514
+ ...(config.skill !== undefined ? { skill: config.skill } : {}),
515
+ ...(config.progress !== undefined ? { progress: config.progress } : {}),
516
+ }));
517
+ const params = { chain, task: parsed.task, clarify: false, agentScope: "both" };
518
+ if (asyncMode !== undefined)
519
+ params.async = asyncMode;
520
+ if (fork)
521
+ params.context = "fork";
522
+ await runSlashSubagent(pi, ctx, params, cwd);
523
+ },
524
+ });
525
+ pi.registerCommand("run-chain", {
526
+ description: "Run a saved chain: /run-chain chainName -- task [--bg|--fg] [--fork]",
527
+ getArgumentCompletions: makeChainCompletions(pi, state),
528
+ handler: async (args, ctx) => {
529
+ const flags = extractExecutionFlags(args);
530
+ if (flags.error) {
531
+ ctx.ui.notify(flags.error, "error");
532
+ return;
533
+ }
534
+ const { args: cleanedArgs, async: asyncMode, fork } = flags;
535
+ const delimiterIndex = cleanedArgs.indexOf(" -- ");
536
+ const usage = "Usage: /run-chain <chainName> -- <task> [--bg|--fg] [--fork]";
537
+ if (delimiterIndex === -1) {
538
+ ctx.ui.notify(usage, "error");
539
+ return;
540
+ }
541
+ const chainName = cleanedArgs.slice(0, delimiterIndex).trim();
542
+ const task = cleanedArgs.slice(delimiterIndex + 4).trim();
543
+ if (!chainName || !task) {
544
+ ctx.ui.notify(usage, "error");
545
+ return;
546
+ }
547
+ const cwd = resolveExecutionCwd(pi, ctx);
548
+ const chain = discoverSavedChains(cwd, ctx.isProjectTrusted()).find((candidate) => candidate.name === chainName);
549
+ if (!chain) {
550
+ ctx.ui.notify(`Unknown chain: ${chainName}`, "error");
551
+ return;
552
+ }
553
+ let savedSteps;
554
+ try {
555
+ savedSteps = mapSavedChainSteps(chain);
556
+ }
557
+ catch (error) {
558
+ ctx.ui.notify(`Cannot load chain '${chainName}': ${error instanceof Error ? error.message : String(error)}`, "error");
559
+ return;
560
+ }
561
+ const params = { chain: savedSteps, task, clarify: false, agentScope: "both" };
562
+ if (asyncMode !== undefined)
563
+ params.async = asyncMode;
564
+ if (fork)
565
+ params.context = "fork";
566
+ await runSlashSubagent(pi, ctx, params, cwd);
567
+ },
568
+ });
569
+ pi.registerCommand("parallel", {
570
+ description: "Run agents in parallel: /parallel scout \"task1\" -> oracle \"task2\" [--bg|--fg] [--fork]",
571
+ getArgumentCompletions: makeAgentCompletions(pi, state, true),
572
+ handler: async (args, ctx) => {
573
+ const flags = extractExecutionFlags(args);
574
+ if (flags.error) {
575
+ ctx.ui.notify(flags.error, "error");
576
+ return;
577
+ }
578
+ const { args: cleanedArgs, async: asyncMode, fork } = flags;
579
+ const cwd = resolveExecutionCwd(pi, ctx);
580
+ const parsed = parseAgentArgs(cwd, cleanedArgs, "parallel", ctx);
581
+ if (!parsed)
582
+ return;
583
+ const tasks = parsed.steps.map(({ name, config, task: stepTask }) => ({
584
+ agent: name,
585
+ task: stepTask ?? parsed.task,
586
+ ...(config.output !== undefined ? { output: config.output } : {}),
587
+ ...(config.outputMode !== undefined ? { outputMode: config.outputMode } : {}),
588
+ ...(config.reads !== undefined ? { reads: config.reads } : {}),
589
+ ...(config.model ? { model: config.model } : {}),
590
+ ...(config.skill !== undefined ? { skill: config.skill } : {}),
591
+ ...(config.progress !== undefined ? { progress: config.progress } : {}),
592
+ }));
593
+ const params = { tasks, clarify: false, agentScope: "both" };
594
+ if (asyncMode !== undefined)
595
+ params.async = asyncMode;
596
+ if (fork)
597
+ params.context = "fork";
598
+ await runSlashSubagent(pi, ctx, params, cwd);
599
+ },
600
+ });
601
+ pi.registerCommand("subagents-doctor", {
602
+ description: "Show subagent diagnostics",
603
+ handler: async (_args, ctx) => {
604
+ await runSlashSubagent(pi, ctx, { action: "doctor" });
605
+ },
606
+ });
607
+ }