pi-crew 0.9.16 → 0.9.18

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 (435) hide show
  1. package/CHANGELOG.md +130 -0
  2. package/README.md +19 -0
  3. package/dist/build-meta.json +21784 -0
  4. package/dist/index.mjs +83169 -0
  5. package/dist/index.mjs.map +7 -0
  6. package/docs/A +358 -0
  7. package/docs/M-A +357 -0
  8. package/docs/REVIEW-FINDINGS-2026-06 +357 -0
  9. package/docs/Y +357 -0
  10. package/docs/a +357 -0
  11. package/docs/aA +358 -0
  12. package/docs/archive/README.md +91 -0
  13. package/docs/migration/atomic-write-v2-migration.md +297 -0
  14. package/docs/patterns/command-agent-skill.md +1 -1
  15. package/docs/perf/performance-review-2026-07.md +287 -0
  16. package/docs/skills/REFERENCE.md +0 -17
  17. package/docs//303/242mmaAAA/303/242 +357 -0
  18. package/index.bundle.ts +25 -0
  19. package/index.ts +95 -4
  20. package/package.json +15 -4
  21. package/skills/iterative-audit/SKILL.md +0 -1
  22. package/skills/widget-rendering/SKILL.md +17 -0
  23. package/src/adapters/claude-adapter.ts +1 -3
  24. package/src/adapters/export-util.ts +16 -16
  25. package/src/adapters/index.ts +5 -5
  26. package/src/agents/agent-config.ts +20 -14
  27. package/src/agents/agent-serializer.ts +1 -1
  28. package/src/agents/discover-agents.ts +83 -39
  29. package/src/benchmark/benchmark-runner.ts +51 -51
  30. package/src/benchmark/feedback-loop.ts +1 -1
  31. package/src/config/config.ts +303 -591
  32. package/src/config/defaults.ts +28 -2
  33. package/src/config/drift-detector.ts +11 -14
  34. package/src/config/markers.ts +201 -203
  35. package/src/config/resilient-parser.ts +14 -6
  36. package/src/config/role-tools.ts +3 -3
  37. package/src/config/suggestions.ts +5 -12
  38. package/src/config/types.ts +9 -25
  39. package/src/errors.ts +151 -157
  40. package/src/extension/action-suggestions.ts +54 -9
  41. package/src/extension/async-notifier.ts +43 -13
  42. package/src/extension/autonomous-policy.ts +77 -37
  43. package/src/extension/command-completions.ts +9 -8
  44. package/src/extension/context-status-injection.ts +14 -12
  45. package/src/extension/crew-autocomplete.ts +8 -16
  46. package/src/extension/crew-cleanup.ts +2 -1
  47. package/src/extension/crew-shortcuts.ts +9 -6
  48. package/src/extension/cross-extension-rpc.ts +136 -42
  49. package/src/extension/help.ts +1 -1
  50. package/src/extension/import-index.ts +10 -5
  51. package/src/extension/knowledge-injection.ts +88 -15
  52. package/src/extension/management.ts +89 -349
  53. package/src/extension/message-renderers.ts +3 -4
  54. package/src/extension/notification-router.ts +22 -5
  55. package/src/extension/notification-sink.ts +6 -3
  56. package/src/extension/pi-api.ts +17 -8
  57. package/src/extension/plan-orchestrate.ts +8 -27
  58. package/src/extension/project-init.ts +21 -6
  59. package/src/extension/register.ts +329 -975
  60. package/src/extension/registration/artifact-cleanup.ts +9 -4
  61. package/src/extension/registration/command-utils.ts +5 -1
  62. package/src/extension/registration/commands.ts +806 -314
  63. package/src/extension/registration/compaction-guard.ts +15 -15
  64. package/src/extension/registration/lifecycle.ts +259 -0
  65. package/src/extension/registration/observability.ts +293 -0
  66. package/src/extension/registration/subagent-helpers.ts +29 -7
  67. package/src/extension/registration/subagent-tools.ts +253 -44
  68. package/src/extension/registration/team-tool.ts +19 -84
  69. package/src/extension/registration/ui.ts +168 -0
  70. package/src/extension/registration/viewers.ts +64 -24
  71. package/src/extension/result-watcher.ts +18 -7
  72. package/src/extension/run-bundle-schema.ts +21 -6
  73. package/src/extension/run-export.ts +15 -6
  74. package/src/extension/run-import.ts +64 -29
  75. package/src/extension/run-index.ts +28 -9
  76. package/src/extension/run-maintenance.ts +32 -12
  77. package/src/extension/session-summary.ts +1 -1
  78. package/src/extension/team-manager-command.ts +64 -7
  79. package/src/extension/team-onboard.ts +149 -150
  80. package/src/extension/team-recommendation.ts +121 -21
  81. package/src/extension/team-tool/anchor.ts +31 -64
  82. package/src/extension/team-tool/api.ts +929 -141
  83. package/src/extension/team-tool/auto-summarize.ts +14 -26
  84. package/src/extension/team-tool/cache-control.ts +1 -5
  85. package/src/extension/team-tool/cancel.ts +138 -38
  86. package/src/extension/team-tool/chain-dispatch.ts +5 -13
  87. package/src/extension/team-tool/chain-executor.ts +29 -51
  88. package/src/extension/team-tool/config-patch.ts +1 -1
  89. package/src/extension/team-tool/context.ts +40 -20
  90. package/src/extension/team-tool/destructive-gate.ts +10 -5
  91. package/src/extension/team-tool/doctor.ts +170 -51
  92. package/src/extension/team-tool/explain.ts +228 -214
  93. package/src/extension/team-tool/failure-patterns.ts +3 -9
  94. package/src/extension/team-tool/goal-wrap.ts +71 -29
  95. package/src/extension/team-tool/goal.ts +185 -35
  96. package/src/extension/team-tool/handle-schedule.ts +34 -15
  97. package/src/extension/team-tool/handle-settings.ts +94 -56
  98. package/src/extension/team-tool/health-monitor.ts +27 -108
  99. package/src/extension/team-tool/inspect.ts +42 -9
  100. package/src/extension/team-tool/intent-policy.ts +4 -1
  101. package/src/extension/team-tool/lifecycle-actions.ts +244 -48
  102. package/src/extension/team-tool/orchestrate.ts +7 -18
  103. package/src/extension/team-tool/parallel-dispatch.ts +51 -29
  104. package/src/extension/team-tool/plan.ts +29 -5
  105. package/src/extension/team-tool/respond.ts +49 -16
  106. package/src/extension/team-tool/run-not-found.ts +3 -8
  107. package/src/extension/team-tool/run.ts +80 -317
  108. package/src/extension/team-tool/status.ts +135 -43
  109. package/src/extension/team-tool/workflow-manage.ts +92 -25
  110. package/src/extension/team-tool-types.ts +8 -1
  111. package/src/extension/team-tool.ts +142 -551
  112. package/src/extension/validate-resources.ts +39 -8
  113. package/src/hooks/registry.ts +66 -17
  114. package/src/hooks/types.ts +1 -1
  115. package/src/i18n.ts +25 -11
  116. package/src/observability/correlation.ts +17 -3
  117. package/src/observability/event-bus.ts +51 -56
  118. package/src/observability/event-to-metric.ts +117 -15
  119. package/src/observability/exporters/otlp-exporter.ts +56 -17
  120. package/src/observability/exporters/prometheus-exporter.ts +1 -1
  121. package/src/observability/metric-registry.ts +16 -4
  122. package/src/observability/metric-retention.ts +8 -2
  123. package/src/observability/metric-sink.ts +11 -3
  124. package/src/observability/metrics-primitives.ts +42 -9
  125. package/src/plugins/plugin-define.ts +2 -2
  126. package/src/plugins/plugin-registry.ts +25 -25
  127. package/src/plugins/plugins/index.ts +1 -1
  128. package/src/plugins/plugins/nextjs.ts +16 -16
  129. package/src/plugins/plugins/vite.ts +7 -11
  130. package/src/plugins/plugins/vitest.ts +6 -11
  131. package/src/runtime/adaptive-plan.ts +225 -40
  132. package/src/runtime/agent-control.ts +58 -15
  133. package/src/runtime/agent-memory.ts +15 -9
  134. package/src/runtime/agent-observability.ts +10 -2
  135. package/src/runtime/anchor-manager.ts +27 -25
  136. package/src/runtime/async-marker.ts +7 -1
  137. package/src/runtime/async-runner.ts +39 -24
  138. package/src/runtime/auto-summarize.ts +7 -13
  139. package/src/runtime/background-runner.ts +189 -251
  140. package/src/runtime/batch-barrier.ts +18 -16
  141. package/src/runtime/cancellation-token.ts +16 -6
  142. package/src/runtime/cancellation.ts +46 -8
  143. package/src/runtime/capability-inventory.ts +6 -4
  144. package/src/runtime/chain-parser.ts +44 -11
  145. package/src/runtime/chain-runner.ts +63 -69
  146. package/src/runtime/checkpoint.ts +12 -56
  147. package/src/runtime/child-pi.ts +344 -79
  148. package/src/runtime/coalesce-tasks.ts +268 -0
  149. package/src/runtime/code-summary.ts +71 -26
  150. package/src/runtime/compact-stages/index.ts +15 -5
  151. package/src/runtime/compact-stages/tail-capture-stage.ts +7 -2
  152. package/src/runtime/compact-stages/truncation-stage.ts +4 -1
  153. package/src/runtime/compaction-summary.ts +17 -10
  154. package/src/runtime/completion-guard.ts +33 -16
  155. package/src/runtime/crash-classification.ts +28 -7
  156. package/src/runtime/crash-recovery.ts +177 -37
  157. package/src/runtime/crew-agent-records.ts +145 -47
  158. package/src/runtime/crew-hooks.ts +9 -24
  159. package/src/runtime/cross-extension-rpc.ts +25 -23
  160. package/src/runtime/custom-tools/irc-tool.ts +43 -15
  161. package/src/runtime/custom-tools/submit-result-tool.ts +16 -5
  162. package/src/runtime/delivery-coordinator.ts +34 -7
  163. package/src/runtime/delta-conflict.ts +9 -21
  164. package/src/runtime/deterministic-ast.ts +1 -1
  165. package/src/runtime/diagnostic-export.ts +53 -20
  166. package/src/runtime/direct-run.ts +12 -2
  167. package/src/runtime/dwf-state-store.ts +1 -1
  168. package/src/runtime/dynamic-workflow-context.ts +187 -59
  169. package/src/runtime/dynamic-workflow-runner.ts +42 -20
  170. package/src/runtime/effectiveness.ts +16 -8
  171. package/src/runtime/errors/crew-errors.ts +7 -11
  172. package/src/runtime/event-stream-bridge.ts +9 -3
  173. package/src/runtime/foreground-control.ts +54 -14
  174. package/src/runtime/foreground-watchdog.ts +9 -6
  175. package/src/runtime/goal-achievement.ts +27 -10
  176. package/src/runtime/goal-evaluator.ts +54 -19
  177. package/src/runtime/goal-loop-runner.ts +280 -99
  178. package/src/runtime/goal-state-store.ts +27 -17
  179. package/src/runtime/green-contract.ts +11 -2
  180. package/src/runtime/group-join.ts +64 -31
  181. package/src/runtime/handoff-manager.ts +37 -42
  182. package/src/runtime/heartbeat-gradient.ts +10 -2
  183. package/src/runtime/heartbeat-watcher.ts +32 -6
  184. package/src/runtime/hidden-handoff.ts +13 -31
  185. package/src/runtime/important-line-classifier.ts +12 -2
  186. package/src/runtime/iteration-hooks.ts +25 -15
  187. package/src/runtime/live-agent-control.ts +55 -7
  188. package/src/runtime/live-agent-manager.ts +130 -27
  189. package/src/runtime/live-control-realtime.ts +23 -3
  190. package/src/runtime/live-irc.ts +4 -1
  191. package/src/runtime/live-session-health.ts +12 -4
  192. package/src/runtime/live-session-runtime.ts +379 -117
  193. package/src/runtime/manifest-cache.ts +28 -12
  194. package/src/runtime/mcp-proxy.ts +10 -18
  195. package/src/runtime/metric-parser.ts +1 -5
  196. package/src/runtime/model-fallback.ts +55 -18
  197. package/src/runtime/model-resolver.ts +2 -6
  198. package/src/runtime/model-scope.ts +19 -3
  199. package/src/runtime/notebook-helpers.ts +60 -62
  200. package/src/runtime/orphan-worker-registry.ts +37 -26
  201. package/src/runtime/output-validator.ts +18 -3
  202. package/src/runtime/overflow-recovery.ts +5 -4
  203. package/src/runtime/parallel-research.ts +29 -5
  204. package/src/runtime/parallel-utils.ts +9 -11
  205. package/src/runtime/path-overlap.ts +150 -0
  206. package/src/runtime/peer-dep.ts +12 -17
  207. package/src/runtime/per-write-validator.ts +1 -3
  208. package/src/runtime/phase-tracker.ts +342 -330
  209. package/src/runtime/pi-args.ts +26 -8
  210. package/src/runtime/pi-json-output.ts +1 -1
  211. package/src/runtime/pi-spawn.ts +30 -19
  212. package/src/runtime/pipeline-runner.ts +56 -55
  213. package/src/runtime/plan-templates.ts +5 -6
  214. package/src/runtime/policy-engine.ts +43 -7
  215. package/src/runtime/post-checks.ts +12 -4
  216. package/src/runtime/post-exit-stdio-guard.ts +2 -2
  217. package/src/runtime/process-lifecycle.ts +20 -10
  218. package/src/runtime/process-status.ts +16 -5
  219. package/src/runtime/progress-event-coalescer.ts +2 -1
  220. package/src/runtime/progress-tracker.ts +103 -103
  221. package/src/runtime/prose-compressor.ts +9 -11
  222. package/src/runtime/recovery-recipes.ts +118 -24
  223. package/src/runtime/replace.ts +25 -10
  224. package/src/runtime/resilient-edit.ts +10 -25
  225. package/src/runtime/result-extractor.ts +2 -6
  226. package/src/runtime/retry-executor.ts +20 -4
  227. package/src/runtime/retry-runner.ts +27 -51
  228. package/src/runtime/role-permission.ts +6 -1
  229. package/src/runtime/run-coalesced-task-group.ts +256 -0
  230. package/src/runtime/run-drift.ts +14 -15
  231. package/src/runtime/run-tracker.ts +6 -28
  232. package/src/runtime/runtime-policy.ts +1 -6
  233. package/src/runtime/runtime-resolver.ts +80 -15
  234. package/src/runtime/scheduler.ts +47 -18
  235. package/src/runtime/semaphore.ts +5 -7
  236. package/src/runtime/sensitive-paths.ts +2 -1
  237. package/src/runtime/session-usage.ts +1 -1
  238. package/src/runtime/settings-store.ts +16 -12
  239. package/src/runtime/sidechain-output.ts +6 -2
  240. package/src/runtime/single-agent-compose.ts +1 -4
  241. package/src/runtime/skill-effectiveness.ts +29 -97
  242. package/src/runtime/skill-instructions.ts +40 -83
  243. package/src/runtime/stale-reconciler.ts +73 -197
  244. package/src/runtime/stream-preview.ts +1 -1
  245. package/src/runtime/streaming-output.ts +1 -1
  246. package/src/runtime/subagent-manager.ts +44 -169
  247. package/src/runtime/subprocess-tool-registry.ts +4 -1
  248. package/src/runtime/supervisor-contact.ts +10 -5
  249. package/src/runtime/task-display.ts +19 -5
  250. package/src/runtime/task-graph-scheduler.ts +95 -21
  251. package/src/runtime/task-graph.ts +5 -11
  252. package/src/runtime/task-health.ts +54 -47
  253. package/src/runtime/task-id.ts +12 -19
  254. package/src/runtime/task-output-context.ts +265 -81
  255. package/src/runtime/task-packet.ts +12 -20
  256. package/src/runtime/task-quality.ts +6 -14
  257. package/src/runtime/task-runner/context-retrieval.ts +4 -13
  258. package/src/runtime/task-runner/live-executor.ts +114 -36
  259. package/src/runtime/task-runner/output-splitter.ts +152 -0
  260. package/src/runtime/task-runner/progress.ts +50 -12
  261. package/src/runtime/task-runner/prompt-builder.ts +31 -7
  262. package/src/runtime/task-runner/prompt-pipeline.ts +31 -7
  263. package/src/runtime/task-runner/result-utils.ts +3 -1
  264. package/src/runtime/task-runner/retrieval-orchestrator.ts +310 -0
  265. package/src/runtime/task-runner/run-projection.ts +27 -8
  266. package/src/runtime/task-runner/state-helpers.ts +50 -14
  267. package/src/runtime/task-runner/tail-read.ts +2 -6
  268. package/src/runtime/task-runner.ts +180 -326
  269. package/src/runtime/team-runner-artifacts.ts +13 -0
  270. package/src/runtime/team-runner.ts +456 -974
  271. package/src/runtime/tool-output-pruner.ts +6 -9
  272. package/src/runtime/tool-progress.ts +11 -21
  273. package/src/runtime/verification-gates.ts +33 -24
  274. package/src/runtime/verification-integrity.ts +2 -7
  275. package/src/runtime/verification-worktree.ts +62 -12
  276. package/src/runtime/worker-heartbeat.ts +5 -1
  277. package/src/runtime/worker-startup.ts +29 -5
  278. package/src/runtime/workflow-state.ts +17 -9
  279. package/src/runtime/workspace-lock.ts +30 -35
  280. package/src/runtime/workspace-tree.ts +20 -32
  281. package/src/runtime/yield-handler.ts +43 -9
  282. package/src/runtime/zombie-scanner.ts +5 -4
  283. package/src/schema/config-schema.ts +266 -172
  284. package/src/schema/team-tool-schema.ts +29 -74
  285. package/src/schema/validation-types.ts +25 -17
  286. package/src/skills/discover-skills.ts +35 -10
  287. package/src/skills/skill-templates.ts +109 -27
  288. package/src/skills/validate.ts +26 -8
  289. package/src/state/active-run-registry.ts +87 -28
  290. package/src/state/artifact-store.ts +9 -5
  291. package/src/state/atomic-write-v2.ts +85 -63
  292. package/src/state/atomic-write.ts +106 -27
  293. package/src/state/blob-store.ts +47 -20
  294. package/src/state/contracts.ts +20 -5
  295. package/src/state/crew-init.ts +5 -22
  296. package/src/state/decision-ledger.ts +19 -73
  297. package/src/state/event-log-rotation.ts +41 -15
  298. package/src/state/event-log.ts +168 -53
  299. package/src/state/event-reconstructor.ts +11 -1
  300. package/src/state/gitignore-manager.ts +2 -8
  301. package/src/state/health-store.ts +57 -57
  302. package/src/state/hook-instinct-bridge.ts +1 -1
  303. package/src/state/hook-integrations.ts +1 -1
  304. package/src/state/instinct-store.ts +17 -5
  305. package/src/state/jsonl-writer.ts +1 -1
  306. package/src/state/locks.ts +23 -9
  307. package/src/state/mailbox.ts +151 -28
  308. package/src/state/observation-store.ts +20 -14
  309. package/src/state/run-cache.ts +142 -135
  310. package/src/state/run-graph.ts +6 -15
  311. package/src/state/run-metrics.ts +5 -18
  312. package/src/state/schedule.ts +15 -9
  313. package/src/state/state-store.ts +137 -47
  314. package/src/state/task-claims.ts +12 -2
  315. package/src/state/tiered-eval.ts +52 -43
  316. package/src/state/types-eval.ts +2 -2
  317. package/src/state/types.ts +24 -20
  318. package/src/state/usage.ts +20 -4
  319. package/src/state/worker-atomic-writer.ts +6 -3
  320. package/src/subagents/index.ts +2 -2
  321. package/src/teams/discover-teams.ts +21 -6
  322. package/src/tools/safe-bash-extension.ts +5 -6
  323. package/src/tools/safe-bash.ts +10 -11
  324. package/src/types/new-api-types.ts +6 -10
  325. package/src/ui/agent-management-overlay.ts +52 -40
  326. package/src/ui/card-colors.ts +13 -4
  327. package/src/ui/crew-footer.ts +8 -7
  328. package/src/ui/crew-select-list.ts +1 -1
  329. package/src/ui/dashboard-panes/agents-pane.ts +41 -25
  330. package/src/ui/dashboard-panes/cancellation-pane.ts +1 -1
  331. package/src/ui/dashboard-panes/capability-pane.ts +32 -15
  332. package/src/ui/dashboard-panes/health-pane.ts +2 -1
  333. package/src/ui/dashboard-panes/metrics-pane.ts +4 -1
  334. package/src/ui/dashboard-panes/progress-pane.ts +12 -9
  335. package/src/ui/heartbeat-aggregator.ts +15 -4
  336. package/src/ui/keybinding-map.ts +40 -7
  337. package/src/ui/live-conversation-overlay.ts +36 -20
  338. package/src/ui/live-duration.ts +1 -4
  339. package/src/ui/live-run-sidebar.ts +88 -25
  340. package/src/ui/loaders.ts +2 -8
  341. package/src/ui/mascot.ts +20 -36
  342. package/src/ui/overlays/agent-picker-overlay.ts +11 -3
  343. package/src/ui/overlays/confirm-overlay.ts +4 -2
  344. package/src/ui/overlays/help-overlay.ts +25 -14
  345. package/src/ui/overlays/mailbox-compose-overlay.ts +48 -11
  346. package/src/ui/overlays/mailbox-compose-preview.ts +20 -5
  347. package/src/ui/overlays/mailbox-detail-overlay.ts +27 -6
  348. package/src/ui/pi-ui-compat.ts +7 -7
  349. package/src/ui/powerbar-publisher.ts +120 -42
  350. package/src/ui/render-diff.ts +10 -3
  351. package/src/ui/render-scheduler.ts +12 -4
  352. package/src/ui/run-action-dispatcher.ts +81 -18
  353. package/src/ui/run-dashboard.ts +172 -76
  354. package/src/ui/run-event-bus.ts +59 -37
  355. package/src/ui/run-snapshot-cache.ts +276 -86
  356. package/src/ui/settings-overlay.ts +361 -74
  357. package/src/ui/status-colors.ts +12 -1
  358. package/src/ui/syntax-highlight.ts +1 -1
  359. package/src/ui/terminal-status.ts +1 -3
  360. package/src/ui/theme-adapter.ts +16 -14
  361. package/src/ui/theme-discovery.ts +13 -2
  362. package/src/ui/tool-progress-formatter.ts +7 -7
  363. package/src/ui/tool-render.ts +128 -56
  364. package/src/ui/tool-renderers/brief-mode.ts +45 -27
  365. package/src/ui/tool-renderers/index.ts +109 -43
  366. package/src/ui/transcript-cache.ts +32 -6
  367. package/src/ui/transcript-entries.ts +25 -23
  368. package/src/ui/transcript-viewer.ts +78 -29
  369. package/src/ui/widget/index.ts +99 -40
  370. package/src/ui/widget/widget-formatters.ts +13 -6
  371. package/src/ui/widget/widget-model.ts +19 -8
  372. package/src/ui/widget/widget-renderer.ts +23 -13
  373. package/src/ui/widget/widget-types.ts +1 -1
  374. package/src/utils/bm25-search.ts +199 -199
  375. package/src/utils/conflict-detect.ts +22 -21
  376. package/src/utils/env-filter.ts +14 -7
  377. package/src/utils/file-coalescer.ts +5 -1
  378. package/src/utils/fingerprint.ts +3 -6
  379. package/src/utils/frontmatter.ts +3 -1
  380. package/src/utils/fs-watch.ts +2 -6
  381. package/src/utils/gh-protocol.ts +119 -44
  382. package/src/utils/git.ts +13 -15
  383. package/src/utils/guards.ts +2 -5
  384. package/src/utils/ids.ts +9 -2
  385. package/src/utils/incremental-reader.ts +14 -3
  386. package/src/utils/internal-error.ts +2 -1
  387. package/src/utils/names.ts +12 -3
  388. package/src/utils/paths.ts +49 -5
  389. package/src/utils/project-detector.ts +2 -2
  390. package/src/utils/redaction.ts +29 -19
  391. package/src/utils/resolve-shell.ts +9 -7
  392. package/src/utils/run-watcher-registry.ts +19 -31
  393. package/src/utils/safe-paths.ts +46 -29
  394. package/src/utils/scan-cache.ts +9 -2
  395. package/src/utils/session-utils.ts +2 -4
  396. package/src/utils/sleep.ts +12 -5
  397. package/src/utils/sse-parser.ts +5 -17
  398. package/src/utils/visual.ts +52 -32
  399. package/src/workflows/discover-workflows.ts +41 -109
  400. package/src/workflows/intermediate-store.ts +5 -21
  401. package/src/workflows/preflight-validator.ts +6 -33
  402. package/src/workflows/topology-analyzer.ts +5 -21
  403. package/src/workflows/workflow-config.ts +7 -6
  404. package/src/worktree/branch-freshness.ts +66 -8
  405. package/src/worktree/cleanup.ts +130 -20
  406. package/src/worktree/worktree-manager.ts +212 -69
  407. package/skills/artifact-analysis-loop/SKILL.md +0 -303
  408. package/skills/detection-pipeline-design/SKILL.md +0 -286
  409. package/skills/hunting-investigation-loop/SKILL.md +0 -402
  410. package/skills/incident-playbook-construction/SKILL.md +0 -384
  411. package/skills/security-review/SKILL.md +0 -561
  412. package/skills/threat-hypothesis-framework/SKILL.md +0 -176
  413. package/skills/ui-render-performance/SKILL.md +0 -58
  414. /package/docs/{followup-review-round3-2026-05-12.md → archive/followup-review-round3-2026-05-12.md} +0 -0
  415. /package/docs/{followup-review-round4-2026-05-13.md → archive/followup-review-round4-2026-05-13.md} +0 -0
  416. /package/docs/{pi-crew-bugs.md → archive/pi-crew-bugs.md} +0 -0
  417. /package/docs/{pi-crew-test-final.md → archive/pi-crew-test-final.md} +0 -0
  418. /package/docs/{pi-crew-test-results.md → archive/pi-crew-test-results.md} +0 -0
  419. /package/docs/{pi-crew-test-round2.md → archive/pi-crew-test-round2.md} +0 -0
  420. /package/docs/{pi-crew-test-round4.md → archive/pi-crew-test-round4.md} +0 -0
  421. /package/docs/{pi-crew-test-round5.md → archive/pi-crew-test-round5.md} +0 -0
  422. /package/docs/{pi-crew-test-round6.md → archive/pi-crew-test-round6.md} +0 -0
  423. /package/docs/{pi-crew-v0.5.10-audit-fix-plan.md → archive/pi-crew-v0.5.10-audit-fix-plan.md} +0 -0
  424. /package/docs/{pi-crew-v0.5.11-audit-fix-plan.md → archive/pi-crew-v0.5.11-audit-fix-plan.md} +0 -0
  425. /package/docs/{pi-crew-v0.5.12-audit-fix-plan.md → archive/pi-crew-v0.5.12-audit-fix-plan.md} +0 -0
  426. /package/docs/{pi-crew-v0.5.13-audit-fix-plan.md → archive/pi-crew-v0.5.13-audit-fix-plan.md} +0 -0
  427. /package/docs/{pi-crew-v0.5.14-audit-fix-plan.md → archive/pi-crew-v0.5.14-audit-fix-plan.md} +0 -0
  428. /package/docs/{pi-crew-v0.5.16-audit-fix-plan.md → archive/pi-crew-v0.5.16-audit-fix-plan.md} +0 -0
  429. /package/docs/{pi-crew-v0.5.17-audit-fix-plan.md → archive/pi-crew-v0.5.17-audit-fix-plan.md} +0 -0
  430. /package/docs/{pi-crew-v0.5.5-audit-fix-plan.md → archive/pi-crew-v0.5.5-audit-fix-plan.md} +0 -0
  431. /package/docs/{pi-crew-v0.5.9-audit-fix-plan.md → archive/pi-crew-v0.5.9-audit-fix-plan.md} +0 -0
  432. /package/docs/{pi-mono-opportunities.md → archive/pi-mono-opportunities.md} +0 -0
  433. /package/docs/{pi-mono-review.md → archive/pi-mono-review.md} +0 -0
  434. /package/docs/{pi-subagent4-comparison.md → archive/pi-subagent4-comparison.md} +0 -0
  435. /package/docs/{pi-subagents3-deep-analysis.md → archive/pi-subagents3-deep-analysis.md} +0 -0
@@ -1,28 +1,46 @@
1
1
  import * as fs from "node:fs";
2
2
  import { loadConfig } from "../../config/config.ts";
3
+ import { buildAgentDashboard, readAgentOutput } from "../../runtime/agent-observability.ts";
4
+ import { buildCapabilityInventory } from "../../runtime/capability-inventory.ts";
5
+ import { agentOutputPath, readCrewAgentEventsCursor, readCrewAgentStatus, readCrewAgents } from "../../runtime/crew-agent-records.ts";
6
+ import { readForegroundControlStatus, writeForegroundInterruptRequest } from "../../runtime/foreground-control.ts";
7
+ import { terminateLiveAgentsForRun } from "../../runtime/live-agent-manager.ts";
8
+ import { currentCrewRole, permissionForRole } from "../../runtime/role-permission.ts";
9
+ import { resolveCrewRuntime } from "../../runtime/runtime-resolver.ts";
10
+ import { touchWorkerHeartbeat } from "../../runtime/worker-heartbeat.ts";
3
11
  import type { TeamToolParamsValue } from "../../schema/team-tool-schema.ts";
4
- import { loadRunManifestById, saveRunManifest, saveRunTasks, updateRunStatus } from "../../state/state-store.ts";
5
- import { withRunLockSync } from "../../state/locks.ts";
6
12
  import { canTransitionTaskStatus, isTeamTaskStatus } from "../../state/contracts.ts";
7
- import { claimTask, releaseTaskClaim, transitionClaimedTaskStatus } from "../../state/task-claims.ts";
8
- import { acknowledgeMailboxMessage, appendFollowUpMessage, appendMailboxMessage, appendSteeringMessage, readDeliveryState, readMailbox, readMailboxMessage, validateMailbox, type MailboxDirection, type MailboxMessageKind } from "../../state/mailbox.ts";
9
13
  import { appendEvent, readEvents, readEventsCursor } from "../../state/event-log.ts";
10
- import { resolveCrewRuntime } from "../../runtime/runtime-resolver.ts";
11
- import { probeLiveSessionRuntime } from "../../subagents/live/session-runtime.ts";
12
- import { currentCrewRole, permissionForRole } from "../../runtime/role-permission.ts";
13
- import { touchWorkerHeartbeat } from "../../runtime/worker-heartbeat.ts";
14
- import { agentOutputPath, readCrewAgentEventsCursor, readCrewAgentStatus, readCrewAgents } from "../../runtime/crew-agent-records.ts";
15
- import { terminateLiveAgentsForRun } from "../../runtime/live-agent-manager.ts";
16
- import { buildAgentDashboard, readAgentOutput } from "../../runtime/agent-observability.ts";
17
- import { readForegroundControlStatus, writeForegroundInterruptRequest } from "../../runtime/foreground-control.ts";
18
- import { followUpLiveAgent, getLiveAgent, listActiveLiveAgents, resumeLiveAgent, steerLiveAgent, stopLiveAgent } from "../../subagents/live/manager.ts";
14
+ import { withRunLockSync } from "../../state/locks.ts";
15
+ import {
16
+ acknowledgeMailboxMessage,
17
+ appendFollowUpMessage,
18
+ appendMailboxMessage,
19
+ appendSteeringMessage,
20
+ type MailboxDirection,
21
+ type MailboxMessageKind,
22
+ readDeliveryState,
23
+ readMailbox,
24
+ readMailboxMessage,
25
+ validateMailbox,
26
+ } from "../../state/mailbox.ts";
27
+ import { loadRunManifestById, saveRunManifest, saveRunTasks, updateRunStatus } from "../../state/state-store.ts";
28
+ import { claimTask, releaseTaskClaim, transitionClaimedTaskStatus } from "../../state/task-claims.ts";
19
29
  import { appendLiveAgentControlRequest } from "../../subagents/live/control.ts";
30
+ import {
31
+ followUpLiveAgent,
32
+ getLiveAgent,
33
+ listActiveLiveAgents,
34
+ resumeLiveAgent,
35
+ steerLiveAgent,
36
+ stopLiveAgent,
37
+ } from "../../subagents/live/manager.ts";
20
38
  import { liveControlRealtimeMessage, publishLiveControlRealtime } from "../../subagents/live/realtime.ts";
39
+ import { probeLiveSessionRuntime } from "../../subagents/live/session-runtime.ts";
21
40
  import { logInternalError } from "../../utils/internal-error.ts";
22
- import { buildCapabilityInventory } from "../../runtime/capability-inventory.ts";
23
41
  import { resolveRealContainedPath } from "../../utils/safe-paths.ts";
24
- import type { PiTeamsToolResult } from "../tool-result.ts";
25
42
  import { locateRunCwd } from "../team-tool.ts";
43
+ import type { PiTeamsToolResult } from "../tool-result.ts";
26
44
  import { configRecord, result, type TeamContext } from "./context.ts";
27
45
  import { RUN_NOT_FOUND_HINT } from "./run-not-found.ts";
28
46
 
@@ -30,9 +48,9 @@ export function globMatch(value: string, pattern: string): boolean {
30
48
  // Prevent ReDoS: reject excessively long patterns
31
49
  if (pattern.length > 200) return false;
32
50
  const regex = pattern
33
- .replace(/[.+^${}()|[\]\\]/g, "\\$&") // escape regex special chars
34
- .replace(/\*/g, "[^/]*") // * matches non-slash characters only
35
- .replace(/\?/g, "[^/]"); // ? matches single non-slash
51
+ .replace(/[.+^${}()|[\]\\]/g, "\\$&") // escape regex special chars
52
+ .replace(/\*/g, "[^/]*") // * matches non-slash characters only
53
+ .replace(/\?/g, "[^/]"); // ? matches single non-slash
36
54
  return new RegExp(`^${regex}$`).test(value);
37
55
  }
38
56
 
@@ -68,7 +86,11 @@ function snapshotHasRunId(snapshot: { values?: unknown }, runId: string): boolea
68
86
  function canApprovePlan(): { allowed: boolean; reason?: string } {
69
87
  const role = currentCrewRole();
70
88
  if (!role) return { allowed: true };
71
- if (permissionForRole(role) === "read_only") return { allowed: false, reason: `Role '${role}' is read-only and cannot approve or cancel plan gates.` };
89
+ if (permissionForRole(role) === "read_only")
90
+ return {
91
+ allowed: false,
92
+ reason: `Role '${role}' is read-only and cannot approve or cancel plan gates.`,
93
+ };
72
94
  return { allowed: true };
73
95
  }
74
96
 
@@ -84,11 +106,18 @@ export async function handleApi(params: TeamToolParamsValue, ctx: TeamContext):
84
106
  if (runIdFilter && !snapshotHasRunId(snapshot, runIdFilter)) return false;
85
107
  return true;
86
108
  });
87
- return result(JSON.stringify(filtered, null, 2), { action: "api", status: "ok", ...(runIdFilter ? { runId: runIdFilter } : {}) });
109
+ return result(JSON.stringify(filtered, null, 2), {
110
+ action: "api",
111
+ status: "ok",
112
+ ...(runIdFilter ? { runId: runIdFilter } : {}),
113
+ });
88
114
  }
89
115
  if (operation === "inventory") {
90
116
  const inventory = buildCapabilityInventory(ctx.cwd, ctx.config);
91
- return result(JSON.stringify(inventory, null, 2), { action: "api", status: "ok" });
117
+ return result(JSON.stringify(inventory, null, 2), {
118
+ action: "api",
119
+ status: "ok",
120
+ });
92
121
  }
93
122
  if (!params.runId) return result("API requires runId.", { action: "api", status: "error" }, true);
94
123
  const runCwd = locateRunCwd(params.runId, ctx.cwd);
@@ -96,218 +125,737 @@ export async function handleApi(params: TeamToolParamsValue, ctx: TeamContext):
96
125
  const loaded = loadRunManifestById(runCwd, params.runId); // NOTE: no withRunLock - best-effort only; concurrent writes may cause inconsistency
97
126
  if (!loaded) return result(`Run '${params.runId}' not found.${RUN_NOT_FOUND_HINT}`, { action: "api", status: "error" }, true);
98
127
  if (operation === "read-manifest") {
99
- return result(JSON.stringify(loaded.manifest, null, 2), { action: "api", status: "ok", runId: loaded.manifest.runId, artifactsRoot: loaded.manifest.artifactsRoot });
128
+ return result(JSON.stringify(loaded.manifest, null, 2), {
129
+ action: "api",
130
+ status: "ok",
131
+ runId: loaded.manifest.runId,
132
+ artifactsRoot: loaded.manifest.artifactsRoot,
133
+ });
100
134
  }
101
135
  if (operation === "approve-plan") {
102
136
  const permission = canApprovePlan();
103
- if (!permission.allowed) return result(permission.reason ?? "Plan approval is not allowed in this context.", { action: "api", status: "error", runId: loaded.manifest.runId }, true);
137
+ if (!permission.allowed)
138
+ return result(
139
+ permission.reason ?? "Plan approval is not allowed in this context.",
140
+ {
141
+ action: "api",
142
+ status: "error",
143
+ runId: loaded.manifest.runId,
144
+ },
145
+ true,
146
+ );
104
147
  try {
105
148
  return withRunLockSync(loaded.manifest, () => {
106
149
  const current = loadRunManifestById(ctx.cwd, loaded.manifest.runId) ?? loaded; // NOTE: inside withRunLockSync - consistent read
107
150
  const approval = current.manifest.planApproval;
108
- if (!approval?.required || approval.status !== "pending") return result("Run has no pending plan approval request.", { action: "api", status: "error", runId: loaded.manifest.runId }, true);
151
+ if (!approval?.required || approval.status !== "pending")
152
+ return result(
153
+ "Run has no pending plan approval request.",
154
+ {
155
+ action: "api",
156
+ status: "error",
157
+ runId: loaded.manifest.runId,
158
+ },
159
+ true,
160
+ );
109
161
  const now = new Date().toISOString();
110
- const manifest = { ...current.manifest, updatedAt: now, planApproval: { ...approval, status: "approved" as const, approvedAt: now, updatedAt: now } };
162
+ const manifest = {
163
+ ...current.manifest,
164
+ updatedAt: now,
165
+ planApproval: {
166
+ ...approval,
167
+ status: "approved" as const,
168
+ approvedAt: now,
169
+ updatedAt: now,
170
+ },
171
+ };
111
172
  saveRunManifest(manifest);
112
- appendEvent(manifest.eventsPath, { type: "plan.approved", runId: manifest.runId, taskId: approval.planTaskId, message: "Adaptive implementation plan approved; resume the run to execute mutating tasks.", metadata: { provenance: "api" } });
113
- return result(JSON.stringify(manifest.planApproval, null, 2), { action: "api", status: "ok", runId: manifest.runId, artifactsRoot: manifest.artifactsRoot });
173
+ appendEvent(manifest.eventsPath, {
174
+ type: "plan.approved",
175
+ runId: manifest.runId,
176
+ taskId: approval.planTaskId,
177
+ message: "Adaptive implementation plan approved; resume the run to execute mutating tasks.",
178
+ metadata: { provenance: "api" },
179
+ });
180
+ return result(JSON.stringify(manifest.planApproval, null, 2), {
181
+ action: "api",
182
+ status: "ok",
183
+ runId: manifest.runId,
184
+ artifactsRoot: manifest.artifactsRoot,
185
+ });
114
186
  });
115
187
  } catch (error) {
116
188
  const message = error instanceof Error ? error.message : String(error);
117
- return result(message, { action: "api", status: "error", runId: loaded.manifest.runId }, true);
189
+ return result(
190
+ message,
191
+ {
192
+ action: "api",
193
+ status: "error",
194
+ runId: loaded.manifest.runId,
195
+ },
196
+ true,
197
+ );
118
198
  }
119
199
  }
120
200
  if (operation === "cancel-plan") {
121
201
  const permission = canApprovePlan();
122
- if (!permission.allowed) return result(permission.reason ?? "Plan approval cancellation is not allowed in this context.", { action: "api", status: "error", runId: loaded.manifest.runId }, true);
202
+ if (!permission.allowed)
203
+ return result(
204
+ permission.reason ?? "Plan approval cancellation is not allowed in this context.",
205
+ {
206
+ action: "api",
207
+ status: "error",
208
+ runId: loaded.manifest.runId,
209
+ },
210
+ true,
211
+ );
123
212
  try {
124
213
  return withRunLockSync(loaded.manifest, () => {
125
214
  const current = loadRunManifestById(ctx.cwd, loaded.manifest.runId) ?? loaded; // NOTE: inside withRunLockSync - consistent read
126
215
  const approval = current.manifest.planApproval;
127
- if (!approval?.required || approval.status !== "pending") return result("Run has no pending plan approval request.", { action: "api", status: "error", runId: loaded.manifest.runId }, true);
216
+ if (!approval?.required || approval.status !== "pending")
217
+ return result(
218
+ "Run has no pending plan approval request.",
219
+ {
220
+ action: "api",
221
+ status: "error",
222
+ runId: loaded.manifest.runId,
223
+ },
224
+ true,
225
+ );
128
226
  const now = new Date().toISOString();
129
- const tasks = current.tasks.map((task) => task.status === "queued" || task.status === "running" || task.status === "waiting" ? { ...task, status: "cancelled" as const, finishedAt: now, error: "Plan approval was cancelled." } : task);
130
- let manifest: typeof current.manifest = { ...current.manifest, updatedAt: now, planApproval: { ...approval, status: "cancelled" as const, cancelledAt: now, updatedAt: now } };
227
+ const tasks = current.tasks.map((task) =>
228
+ task.status === "queued" || task.status === "running" || task.status === "waiting"
229
+ ? {
230
+ ...task,
231
+ status: "cancelled" as const,
232
+ finishedAt: now,
233
+ error: "Plan approval was cancelled.",
234
+ }
235
+ : task,
236
+ );
237
+ let manifest: typeof current.manifest = {
238
+ ...current.manifest,
239
+ updatedAt: now,
240
+ planApproval: {
241
+ ...approval,
242
+ status: "cancelled" as const,
243
+ cancelledAt: now,
244
+ updatedAt: now,
245
+ },
246
+ };
131
247
  saveRunManifest(manifest);
132
248
  saveRunTasks(manifest, tasks);
133
- appendEvent(manifest.eventsPath, { type: "plan.cancelled", runId: manifest.runId, taskId: approval.planTaskId, message: "Adaptive implementation plan was cancelled.", metadata: { provenance: "api" } });
249
+ appendEvent(manifest.eventsPath, {
250
+ type: "plan.cancelled",
251
+ runId: manifest.runId,
252
+ taskId: approval.planTaskId,
253
+ message: "Adaptive implementation plan was cancelled.",
254
+ metadata: { provenance: "api" },
255
+ });
134
256
  manifest = updateRunStatus(manifest, "cancelled", "Plan approval was cancelled.");
135
- void terminateLiveAgentsForRun(manifest.runId, "cancelled", appendEvent, manifest.eventsPath).catch((error) => logInternalError("team-tool.cancel-plan.terminate", error, `runId=${manifest.runId}`));
136
- return result(JSON.stringify({ planApproval: manifest.planApproval, cancelledTasks: tasks.filter((task) => task.status === "cancelled").map((task) => task.id) }, null, 2), { action: "api", status: "ok", runId: manifest.runId, artifactsRoot: manifest.artifactsRoot });
257
+ void terminateLiveAgentsForRun(manifest.runId, "cancelled", appendEvent, manifest.eventsPath).catch((error) =>
258
+ logInternalError("team-tool.cancel-plan.terminate", error, `runId=${manifest.runId}`),
259
+ );
260
+ return result(
261
+ JSON.stringify(
262
+ {
263
+ planApproval: manifest.planApproval,
264
+ cancelledTasks: tasks.filter((task) => task.status === "cancelled").map((task) => task.id),
265
+ },
266
+ null,
267
+ 2,
268
+ ),
269
+ {
270
+ action: "api",
271
+ status: "ok",
272
+ runId: manifest.runId,
273
+ artifactsRoot: manifest.artifactsRoot,
274
+ },
275
+ );
137
276
  });
138
277
  } catch (error) {
139
278
  const message = error instanceof Error ? error.message : String(error);
140
- return result(message, { action: "api", status: "error", runId: loaded.manifest.runId }, true);
279
+ return result(
280
+ message,
281
+ {
282
+ action: "api",
283
+ status: "error",
284
+ runId: loaded.manifest.runId,
285
+ },
286
+ true,
287
+ );
141
288
  }
142
289
  }
143
290
  if (operation === "list-tasks") {
144
- return result(JSON.stringify(loaded.tasks, null, 2), { action: "api", status: "ok", runId: loaded.manifest.runId, artifactsRoot: loaded.manifest.artifactsRoot });
291
+ return result(JSON.stringify(loaded.tasks, null, 2), {
292
+ action: "api",
293
+ status: "ok",
294
+ runId: loaded.manifest.runId,
295
+ artifactsRoot: loaded.manifest.artifactsRoot,
296
+ });
145
297
  }
146
298
  if (operation === "read-task") {
147
299
  const taskId = typeof cfg.taskId === "string" ? cfg.taskId : undefined;
148
300
  const task = loaded.tasks.find((item) => item.id === taskId || item.stepId === taskId);
149
- if (!task) return result("API read-task requires config.taskId matching a task id or step id.", { action: "api", status: "error", runId: loaded.manifest.runId }, true);
150
- return result(JSON.stringify(task, null, 2), { action: "api", status: "ok", runId: loaded.manifest.runId, artifactsRoot: loaded.manifest.artifactsRoot });
301
+ if (!task)
302
+ return result(
303
+ "API read-task requires config.taskId matching a task id or step id.",
304
+ {
305
+ action: "api",
306
+ status: "error",
307
+ runId: loaded.manifest.runId,
308
+ },
309
+ true,
310
+ );
311
+ return result(JSON.stringify(task, null, 2), {
312
+ action: "api",
313
+ status: "ok",
314
+ runId: loaded.manifest.runId,
315
+ artifactsRoot: loaded.manifest.artifactsRoot,
316
+ });
151
317
  }
152
318
  if (operation === "read-events") {
153
319
  const sinceSeq = typeof cfg.sinceSeq === "number" ? cfg.sinceSeq : undefined;
154
320
  const limit = typeof cfg.limit === "number" ? cfg.limit : undefined;
155
- const payload = sinceSeq !== undefined || limit !== undefined
156
- ? readEventsCursor(loaded.manifest.eventsPath, { sinceSeq, limit })
157
- : { events: readEvents(loaded.manifest.eventsPath), nextSeq: undefined, total: undefined };
158
- return result(JSON.stringify(payload, null, 2), { action: "api", status: "ok", runId: loaded.manifest.runId, artifactsRoot: loaded.manifest.artifactsRoot });
321
+ const payload =
322
+ sinceSeq !== undefined || limit !== undefined
323
+ ? readEventsCursor(loaded.manifest.eventsPath, {
324
+ sinceSeq,
325
+ limit,
326
+ })
327
+ : {
328
+ events: readEvents(loaded.manifest.eventsPath),
329
+ nextSeq: undefined,
330
+ total: undefined,
331
+ };
332
+ return result(JSON.stringify(payload, null, 2), {
333
+ action: "api",
334
+ status: "ok",
335
+ runId: loaded.manifest.runId,
336
+ artifactsRoot: loaded.manifest.artifactsRoot,
337
+ });
159
338
  }
160
339
  if (operation === "runtime-capabilities") {
161
340
  const loadedConfig = loadConfig(ctx.cwd);
162
- return result(JSON.stringify(await resolveCrewRuntime(loadedConfig.config), null, 2), { action: "api", status: "ok", runId: loaded.manifest.runId, artifactsRoot: loaded.manifest.artifactsRoot });
341
+ return result(JSON.stringify(await resolveCrewRuntime(loadedConfig.config), null, 2), {
342
+ action: "api",
343
+ status: "ok",
344
+ runId: loaded.manifest.runId,
345
+ artifactsRoot: loaded.manifest.artifactsRoot,
346
+ });
163
347
  }
164
348
  if (operation === "probe-live-session") {
165
- return result(JSON.stringify(await probeLiveSessionRuntime(), null, 2), { action: "api", status: "ok", runId: loaded.manifest.runId, artifactsRoot: loaded.manifest.artifactsRoot });
349
+ return result(JSON.stringify(await probeLiveSessionRuntime(), null, 2), {
350
+ action: "api",
351
+ status: "ok",
352
+ runId: loaded.manifest.runId,
353
+ artifactsRoot: loaded.manifest.artifactsRoot,
354
+ });
166
355
  }
167
356
  if (operation === "list-agents") {
168
- return result(JSON.stringify(readCrewAgents(loaded.manifest), null, 2), { action: "api", status: "ok", runId: loaded.manifest.runId, artifactsRoot: loaded.manifest.artifactsRoot });
357
+ return result(JSON.stringify(readCrewAgents(loaded.manifest), null, 2), {
358
+ action: "api",
359
+ status: "ok",
360
+ runId: loaded.manifest.runId,
361
+ artifactsRoot: loaded.manifest.artifactsRoot,
362
+ });
169
363
  }
170
364
  if (operation === "get-agent-result") {
171
365
  const agentId = typeof cfg.agentId === "string" ? cfg.agentId : undefined;
172
366
  const agent = readCrewAgents(loaded.manifest).find((item) => item.id === agentId || item.taskId === agentId);
173
- if (!agent) return result("API get-agent-result requires config.agentId matching an agent id or task id.", { action: "api", status: "error", runId: loaded.manifest.runId }, true);
367
+ if (!agent)
368
+ return result(
369
+ "API get-agent-result requires config.agentId matching an agent id or task id.",
370
+ {
371
+ action: "api",
372
+ status: "error",
373
+ runId: loaded.manifest.runId,
374
+ },
375
+ true,
376
+ );
174
377
  const task = loaded.tasks.find((item) => item.id === agent.taskId);
175
378
  const text = safeReadContainedFile(loaded.manifest.artifactsRoot, task?.resultArtifact?.path) ?? JSON.stringify(agent, null, 2);
176
- return result(text, { action: "api", status: "ok", runId: loaded.manifest.runId, artifactsRoot: loaded.manifest.artifactsRoot });
379
+ return result(text, {
380
+ action: "api",
381
+ status: "ok",
382
+ runId: loaded.manifest.runId,
383
+ artifactsRoot: loaded.manifest.artifactsRoot,
384
+ });
177
385
  }
178
386
  if (operation === "read-agent-status") {
179
387
  const agentId = typeof cfg.agentId === "string" ? cfg.agentId : undefined;
180
388
  const agent = agentId ? readCrewAgents(loaded.manifest).find((item) => item.id === agentId || item.taskId === agentId) : undefined;
181
- const status = agent ? readCrewAgentStatus(loaded.manifest, agent.taskId) ?? agent : undefined;
182
- if (!status) return result("API read-agent-status requires config.agentId matching an agent id or task id.", { action: "api", status: "error", runId: loaded.manifest.runId }, true);
183
- return result(JSON.stringify(status, null, 2), { action: "api", status: "ok", runId: loaded.manifest.runId, artifactsRoot: loaded.manifest.artifactsRoot });
389
+ const status = agent ? (readCrewAgentStatus(loaded.manifest, agent.taskId) ?? agent) : undefined;
390
+ if (!status)
391
+ return result(
392
+ "API read-agent-status requires config.agentId matching an agent id or task id.",
393
+ {
394
+ action: "api",
395
+ status: "error",
396
+ runId: loaded.manifest.runId,
397
+ },
398
+ true,
399
+ );
400
+ return result(JSON.stringify(status, null, 2), {
401
+ action: "api",
402
+ status: "ok",
403
+ runId: loaded.manifest.runId,
404
+ artifactsRoot: loaded.manifest.artifactsRoot,
405
+ });
184
406
  }
185
407
  if (operation === "read-agent-events") {
186
408
  const agentId = typeof cfg.agentId === "string" ? cfg.agentId : undefined;
187
409
  const agents = readCrewAgents(loaded.manifest);
188
410
  const agent = agentId ? agents.find((item) => item.id === agentId || item.taskId === agentId) : agents[0];
189
- if (!agent) return result("API read-agent-events requires config.agentId matching an agent id or task id, or at least one agent in the run.", { action: "api", status: "error", runId: loaded.manifest.runId }, true);
411
+ if (!agent)
412
+ return result(
413
+ "API read-agent-events requires config.agentId matching an agent id or task id, or at least one agent in the run.",
414
+ {
415
+ action: "api",
416
+ status: "error",
417
+ runId: loaded.manifest.runId,
418
+ },
419
+ true,
420
+ );
190
421
  const sinceSeq = typeof cfg.sinceSeq === "number" ? cfg.sinceSeq : undefined;
191
422
  const limit = typeof cfg.limit === "number" ? cfg.limit : undefined;
192
423
  const cursorPayload = readCrewAgentEventsCursor(loaded.manifest, agent.taskId, { sinceSeq, limit });
193
- const payload = sinceSeq !== undefined || limit !== undefined ? cursorPayload : { path: cursorPayload.path, events: cursorPayload.events };
194
- return result(JSON.stringify(payload, null, 2), { action: "api", status: "ok", runId: loaded.manifest.runId, artifactsRoot: loaded.manifest.artifactsRoot });
424
+ const payload =
425
+ sinceSeq !== undefined || limit !== undefined ? cursorPayload : { path: cursorPayload.path, events: cursorPayload.events };
426
+ return result(JSON.stringify(payload, null, 2), {
427
+ action: "api",
428
+ status: "ok",
429
+ runId: loaded.manifest.runId,
430
+ artifactsRoot: loaded.manifest.artifactsRoot,
431
+ });
195
432
  }
196
433
  if (operation === "read-agent-transcript") {
197
434
  const agentId = typeof cfg.agentId === "string" ? cfg.agentId : undefined;
198
435
  const agents = readCrewAgents(loaded.manifest);
199
436
  const agent = agentId ? agents.find((item) => item.id === agentId || item.taskId === agentId) : agents[0];
200
- if (!agent) return result("API read-agent-transcript requires config.agentId matching an agent id or task id, or at least one agent in the run.", { action: "api", status: "error", runId: loaded.manifest.runId }, true);
437
+ if (!agent)
438
+ return result(
439
+ "API read-agent-transcript requires config.agentId matching an agent id or task id, or at least one agent in the run.",
440
+ {
441
+ action: "api",
442
+ status: "error",
443
+ runId: loaded.manifest.runId,
444
+ },
445
+ true,
446
+ );
201
447
  const artifactTranscriptPath = safeContainedPath(loaded.manifest.artifactsRoot, agent.transcriptPath);
202
448
  const fallbackPath = agentOutputPath(loaded.manifest, agent.taskId);
203
- const artifactText = artifactTranscriptPath ? safeReadContainedFile(loaded.manifest.artifactsRoot, artifactTranscriptPath) ?? "" : "";
204
- const fallbackText = artifactText ? "" : safeReadContainedFile(loaded.manifest.stateRoot, fallbackPath) ?? "";
449
+ const artifactText = artifactTranscriptPath
450
+ ? (safeReadContainedFile(loaded.manifest.artifactsRoot, artifactTranscriptPath) ?? "")
451
+ : "";
452
+ const fallbackText = artifactText ? "" : (safeReadContainedFile(loaded.manifest.stateRoot, fallbackPath) ?? "");
205
453
  const transcriptPath = artifactText ? artifactTranscriptPath : fallbackPath;
206
454
  const text = artifactText || fallbackText;
207
- return result(text || `(no transcript at ${transcriptPath})`, { action: "api", status: "ok", runId: loaded.manifest.runId, artifactsRoot: loaded.manifest.artifactsRoot });
455
+ return result(text || `(no transcript at ${transcriptPath})`, {
456
+ action: "api",
457
+ status: "ok",
458
+ runId: loaded.manifest.runId,
459
+ artifactsRoot: loaded.manifest.artifactsRoot,
460
+ });
208
461
  }
209
462
  if (operation === "read-agent-output") {
210
463
  const agentId = typeof cfg.agentId === "string" ? cfg.agentId : undefined;
211
464
  const agents = readCrewAgents(loaded.manifest);
212
465
  const agent = agentId ? agents.find((item) => item.id === agentId || item.taskId === agentId) : agents[0];
213
- if (!agent) return result("API read-agent-output requires config.agentId matching an agent id or task id, or at least one agent in the run.", { action: "api", status: "error", runId: loaded.manifest.runId }, true);
466
+ if (!agent)
467
+ return result(
468
+ "API read-agent-output requires config.agentId matching an agent id or task id, or at least one agent in the run.",
469
+ {
470
+ action: "api",
471
+ status: "error",
472
+ runId: loaded.manifest.runId,
473
+ },
474
+ true,
475
+ );
214
476
  const maxBytes = typeof cfg.maxBytes === "number" ? cfg.maxBytes : undefined;
215
- return result(JSON.stringify(readAgentOutput(loaded.manifest, agent.taskId, maxBytes), null, 2), { action: "api", status: "ok", runId: loaded.manifest.runId, artifactsRoot: loaded.manifest.artifactsRoot });
477
+ return result(JSON.stringify(readAgentOutput(loaded.manifest, agent.taskId, maxBytes), null, 2), {
478
+ action: "api",
479
+ status: "ok",
480
+ runId: loaded.manifest.runId,
481
+ artifactsRoot: loaded.manifest.artifactsRoot,
482
+ });
216
483
  }
217
484
  if (operation === "agent-dashboard") {
218
- return result(buildAgentDashboard(loaded.manifest).text, { action: "api", status: "ok", runId: loaded.manifest.runId, artifactsRoot: loaded.manifest.artifactsRoot });
485
+ return result(buildAgentDashboard(loaded.manifest).text, {
486
+ action: "api",
487
+ status: "ok",
488
+ runId: loaded.manifest.runId,
489
+ artifactsRoot: loaded.manifest.artifactsRoot,
490
+ });
219
491
  }
220
492
  if (operation === "foreground-status") {
221
- return result(JSON.stringify(readForegroundControlStatus(loaded.manifest, loaded.tasks), null, 2), { action: "api", status: "ok", runId: loaded.manifest.runId, artifactsRoot: loaded.manifest.artifactsRoot });
493
+ return result(JSON.stringify(readForegroundControlStatus(loaded.manifest, loaded.tasks), null, 2), {
494
+ action: "api",
495
+ status: "ok",
496
+ runId: loaded.manifest.runId,
497
+ artifactsRoot: loaded.manifest.artifactsRoot,
498
+ });
222
499
  }
223
500
  if (operation === "foreground-interrupt") {
224
501
  const reason = typeof cfg.reason === "string" && cfg.reason.trim() ? cfg.reason.trim() : undefined;
225
- return result(JSON.stringify(writeForegroundInterruptRequest(loaded.manifest, reason), null, 2), { action: "api", status: "ok", runId: loaded.manifest.runId, artifactsRoot: loaded.manifest.artifactsRoot });
502
+ return result(JSON.stringify(writeForegroundInterruptRequest(loaded.manifest, reason), null, 2), {
503
+ action: "api",
504
+ status: "ok",
505
+ runId: loaded.manifest.runId,
506
+ artifactsRoot: loaded.manifest.artifactsRoot,
507
+ });
226
508
  }
227
509
  if (operation === "nudge-agent") {
228
510
  const agentId = typeof cfg.agentId === "string" ? cfg.agentId : undefined;
229
511
  const agent = readCrewAgents(loaded.manifest).find((item) => item.id === agentId || item.taskId === agentId);
230
- if (!agent) return result("API nudge-agent requires config.agentId matching an agent id or task id.", { action: "api", status: "error", runId: loaded.manifest.runId }, true);
231
- const messageText = typeof cfg.message === "string" && cfg.message.trim() ? cfg.message.trim() : "Please report your current status, blocker, or smallest next step.";
232
- const message = appendSteeringMessage(loaded.manifest, { taskId: agent.taskId, to: agent.taskId, body: messageText, priority: "normal", data: { source: "nudge-agent" } });
233
- appendEvent(loaded.manifest.eventsPath, { type: "agent.nudged", runId: loaded.manifest.runId, taskId: agent.taskId, message: messageText, data: { agentId: agent.id, mailboxMessageId: message.id } });
234
- ctx.events?.emit?.("crew.mailbox.message", { runId: loaded.manifest.runId, id: message.id, direction: message.direction, from: message.from, to: message.to, taskId: message.taskId, source: "nudge-agent" });
235
- return result(JSON.stringify({ agentId: agent.id, mailboxMessage: message }, null, 2), { action: "api", status: "ok", runId: loaded.manifest.runId, artifactsRoot: loaded.manifest.artifactsRoot });
512
+ if (!agent)
513
+ return result(
514
+ "API nudge-agent requires config.agentId matching an agent id or task id.",
515
+ {
516
+ action: "api",
517
+ status: "error",
518
+ runId: loaded.manifest.runId,
519
+ },
520
+ true,
521
+ );
522
+ const messageText =
523
+ typeof cfg.message === "string" && cfg.message.trim()
524
+ ? cfg.message.trim()
525
+ : "Please report your current status, blocker, or smallest next step.";
526
+ const message = appendSteeringMessage(loaded.manifest, {
527
+ taskId: agent.taskId,
528
+ to: agent.taskId,
529
+ body: messageText,
530
+ priority: "normal",
531
+ data: { source: "nudge-agent" },
532
+ });
533
+ appendEvent(loaded.manifest.eventsPath, {
534
+ type: "agent.nudged",
535
+ runId: loaded.manifest.runId,
536
+ taskId: agent.taskId,
537
+ message: messageText,
538
+ data: { agentId: agent.id, mailboxMessageId: message.id },
539
+ });
540
+ ctx.events?.emit?.("crew.mailbox.message", {
541
+ runId: loaded.manifest.runId,
542
+ id: message.id,
543
+ direction: message.direction,
544
+ from: message.from,
545
+ to: message.to,
546
+ taskId: message.taskId,
547
+ source: "nudge-agent",
548
+ });
549
+ return result(JSON.stringify({ agentId: agent.id, mailboxMessage: message }, null, 2), {
550
+ action: "api",
551
+ status: "ok",
552
+ runId: loaded.manifest.runId,
553
+ artifactsRoot: loaded.manifest.artifactsRoot,
554
+ });
236
555
  }
237
556
  if (operation === "list-live-agents") {
238
- return result(JSON.stringify(listActiveLiveAgents().filter((agent) => agent.runId === loaded.manifest.runId), null, 2), { action: "api", status: "ok", runId: loaded.manifest.runId, artifactsRoot: loaded.manifest.artifactsRoot });
557
+ return result(
558
+ JSON.stringify(
559
+ listActiveLiveAgents().filter((agent) => agent.runId === loaded.manifest.runId),
560
+ null,
561
+ 2,
562
+ ),
563
+ {
564
+ action: "api",
565
+ status: "ok",
566
+ runId: loaded.manifest.runId,
567
+ artifactsRoot: loaded.manifest.artifactsRoot,
568
+ },
569
+ );
239
570
  }
240
- if (operation === "steer-agent" || operation === "follow-up-agent" || operation === "stop-agent" || operation === "resume-agent" || operation === "interrupt-agent") {
571
+ if (
572
+ operation === "steer-agent" ||
573
+ operation === "follow-up-agent" ||
574
+ operation === "stop-agent" ||
575
+ operation === "resume-agent" ||
576
+ operation === "interrupt-agent"
577
+ ) {
241
578
  const agentId = typeof cfg.agentId === "string" ? cfg.agentId : undefined;
242
- if (!agentId) return result(`API ${operation} requires config.agentId.`, { action: "api", status: "error", runId: loaded.manifest.runId }, true);
579
+ if (!agentId)
580
+ return result(
581
+ `API ${operation} requires config.agentId.`,
582
+ {
583
+ action: "api",
584
+ status: "error",
585
+ runId: loaded.manifest.runId,
586
+ },
587
+ true,
588
+ );
243
589
  const message = typeof cfg.message === "string" && cfg.message.trim() ? cfg.message.trim() : undefined;
244
590
  const prompt = typeof cfg.prompt === "string" && cfg.prompt.trim() ? cfg.prompt.trim() : message;
245
591
  try {
246
592
  const live = getLiveAgent(agentId);
247
- if (live && live.runId !== loaded.manifest.runId) return result(`Live agent '${agentId}' does not belong to run ${loaded.manifest.runId}.`, { action: "api", status: "error", runId: loaded.manifest.runId }, true);
248
- if (live && live.workspaceId !== loaded.manifest.cwd) return result(`Live agent '${agentId}' does not belong to workspace ${loaded.manifest.cwd}.`, { action: "api", status: "error", runId: loaded.manifest.runId }, true);
249
- if (!live && (operation === "steer-agent" || operation === "follow-up-agent")) throw new Error(`Live agent '${agentId}' not found.`);
593
+ if (live && live.runId !== loaded.manifest.runId)
594
+ return result(
595
+ `Live agent '${agentId}' does not belong to run ${loaded.manifest.runId}.`,
596
+ {
597
+ action: "api",
598
+ status: "error",
599
+ runId: loaded.manifest.runId,
600
+ },
601
+ true,
602
+ );
603
+ if (live && live.workspaceId !== loaded.manifest.cwd)
604
+ return result(
605
+ `Live agent '${agentId}' does not belong to workspace ${loaded.manifest.cwd}.`,
606
+ {
607
+ action: "api",
608
+ status: "error",
609
+ runId: loaded.manifest.runId,
610
+ },
611
+ true,
612
+ );
613
+ if (!live && (operation === "steer-agent" || operation === "follow-up-agent"))
614
+ throw new Error(`Live agent '${agentId}' not found.`);
250
615
  const liveTaskId = live?.taskId;
251
- if ((operation === "steer-agent" || operation === "follow-up-agent") && !liveTaskId) throw new Error(`Live agent '${agentId}' not found.`);
616
+ if ((operation === "steer-agent" || operation === "follow-up-agent") && !liveTaskId)
617
+ throw new Error(`Live agent '${agentId}' not found.`);
252
618
  const targetTaskId = liveTaskId ?? agentId;
253
619
  if (operation === "steer-agent") {
254
620
  const text = message ?? "Please report current status and wrap up if possible.";
255
621
  const realtime = await steerLiveAgent(agentId, text);
256
- const mailboxMessage = appendSteeringMessage(loaded.manifest, { taskId: targetTaskId, body: text, status: "delivered", data: { source: "steer-agent", realtime: true } });
257
- return result(JSON.stringify({ realtime, mailboxMessage }, null, 2), { action: "api", status: "ok", runId: loaded.manifest.runId, artifactsRoot: loaded.manifest.artifactsRoot });
622
+ const mailboxMessage = appendSteeringMessage(loaded.manifest, {
623
+ taskId: targetTaskId,
624
+ body: text,
625
+ status: "delivered",
626
+ data: { source: "steer-agent", realtime: true },
627
+ });
628
+ return result(JSON.stringify({ realtime, mailboxMessage }, null, 2), {
629
+ action: "api",
630
+ status: "ok",
631
+ runId: loaded.manifest.runId,
632
+ artifactsRoot: loaded.manifest.artifactsRoot,
633
+ });
258
634
  }
259
635
  if (operation === "follow-up-agent") {
260
- if (!prompt) return result("API follow-up-agent requires config.prompt or config.message.", { action: "api", status: "error", runId: loaded.manifest.runId }, true);
636
+ if (!prompt)
637
+ return result(
638
+ "API follow-up-agent requires config.prompt or config.message.",
639
+ {
640
+ action: "api",
641
+ status: "error",
642
+ runId: loaded.manifest.runId,
643
+ },
644
+ true,
645
+ );
261
646
  const realtime = await followUpLiveAgent(agentId, prompt);
262
- const mailboxMessage = appendFollowUpMessage(loaded.manifest, { taskId: targetTaskId, body: prompt, status: "delivered", data: { source: "follow-up-agent", realtime: true } });
263
- return result(JSON.stringify({ realtime, mailboxMessage }, null, 2), { action: "api", status: "ok", runId: loaded.manifest.runId, artifactsRoot: loaded.manifest.artifactsRoot });
647
+ const mailboxMessage = appendFollowUpMessage(loaded.manifest, {
648
+ taskId: targetTaskId,
649
+ body: prompt,
650
+ status: "delivered",
651
+ data: { source: "follow-up-agent", realtime: true },
652
+ });
653
+ return result(JSON.stringify({ realtime, mailboxMessage }, null, 2), {
654
+ action: "api",
655
+ status: "ok",
656
+ runId: loaded.manifest.runId,
657
+ artifactsRoot: loaded.manifest.artifactsRoot,
658
+ });
264
659
  }
265
660
  if (operation === "resume-agent") {
266
- if (!prompt) return result("API resume-agent requires config.prompt or config.message.", { action: "api", status: "error", runId: loaded.manifest.runId }, true);
267
- return result(JSON.stringify(await resumeLiveAgent(agentId, prompt), null, 2), { action: "api", status: "ok", runId: loaded.manifest.runId, artifactsRoot: loaded.manifest.artifactsRoot });
661
+ if (!prompt)
662
+ return result(
663
+ "API resume-agent requires config.prompt or config.message.",
664
+ {
665
+ action: "api",
666
+ status: "error",
667
+ runId: loaded.manifest.runId,
668
+ },
669
+ true,
670
+ );
671
+ return result(JSON.stringify(await resumeLiveAgent(agentId, prompt), null, 2), {
672
+ action: "api",
673
+ status: "ok",
674
+ runId: loaded.manifest.runId,
675
+ artifactsRoot: loaded.manifest.artifactsRoot,
676
+ });
268
677
  }
269
- return result(JSON.stringify(await stopLiveAgent(agentId), null, 2), { action: "api", status: "ok", runId: loaded.manifest.runId, artifactsRoot: loaded.manifest.artifactsRoot });
678
+ return result(JSON.stringify(await stopLiveAgent(agentId), null, 2), {
679
+ action: "api",
680
+ status: "ok",
681
+ runId: loaded.manifest.runId,
682
+ artifactsRoot: loaded.manifest.artifactsRoot,
683
+ });
270
684
  } catch (error) {
271
685
  const agent = readCrewAgents(loaded.manifest).find((item) => item.id === agentId || item.taskId === agentId);
272
686
  if (!agent) {
273
687
  const err = error instanceof Error ? error.message : String(error);
274
- return result(err, { action: "api", status: "error", runId: loaded.manifest.runId }, true);
688
+ return result(
689
+ err,
690
+ {
691
+ action: "api",
692
+ status: "error",
693
+ runId: loaded.manifest.runId,
694
+ },
695
+ true,
696
+ );
275
697
  }
276
698
  const task = loaded.tasks.find((item) => item.id === agent.taskId);
277
- if (!task) return result(`API ${operation} agent '${agentId}' does not match a run task.`, { action: "api", status: "error", runId: loaded.manifest.runId }, true);
278
- if (operation === "resume-agent" && !prompt) return result("API resume-agent requires config.prompt or config.message.", { action: "api", status: "error", runId: loaded.manifest.runId }, true);
279
- if (operation === "follow-up-agent" && !prompt) return result("API follow-up-agent requires config.prompt or config.message.", { action: "api", status: "error", runId: loaded.manifest.runId }, true);
699
+ if (!task)
700
+ return result(
701
+ `API ${operation} agent '${agentId}' does not match a run task.`,
702
+ {
703
+ action: "api",
704
+ status: "error",
705
+ runId: loaded.manifest.runId,
706
+ },
707
+ true,
708
+ );
709
+ if (operation === "resume-agent" && !prompt)
710
+ return result(
711
+ "API resume-agent requires config.prompt or config.message.",
712
+ {
713
+ action: "api",
714
+ status: "error",
715
+ runId: loaded.manifest.runId,
716
+ },
717
+ true,
718
+ );
719
+ if (operation === "follow-up-agent" && !prompt)
720
+ return result(
721
+ "API follow-up-agent requires config.prompt or config.message.",
722
+ {
723
+ action: "api",
724
+ status: "error",
725
+ runId: loaded.manifest.runId,
726
+ },
727
+ true,
728
+ );
280
729
  try {
281
- const request = appendLiveAgentControlRequest(loaded.manifest, { taskId: task.id, agentId: agent.id, operation: operation === "resume-agent" ? "resume" : operation === "follow-up-agent" ? "follow-up" : operation === "steer-agent" ? "steer" : "stop", message: operation === "resume-agent" || operation === "follow-up-agent" ? prompt : message });
282
- const mailboxMessage = operation === "steer-agent" ? appendSteeringMessage(loaded.manifest, { taskId: task.id, to: agent.id, body: message ?? "Please report current status and wrap up if possible.", status: "delivered", data: { source: "steer-agent", liveControlRequestId: request.id } }) : operation === "follow-up-agent" && prompt ? appendFollowUpMessage(loaded.manifest, { taskId: task.id, to: agent.id, body: prompt, status: "delivered", data: { source: "follow-up-agent", liveControlRequestId: request.id } }) : undefined;
730
+ const request = appendLiveAgentControlRequest(loaded.manifest, {
731
+ taskId: task.id,
732
+ agentId: agent.id,
733
+ operation:
734
+ operation === "resume-agent"
735
+ ? "resume"
736
+ : operation === "follow-up-agent"
737
+ ? "follow-up"
738
+ : operation === "steer-agent"
739
+ ? "steer"
740
+ : "stop",
741
+ message: operation === "resume-agent" || operation === "follow-up-agent" ? prompt : message,
742
+ });
743
+ const mailboxMessage =
744
+ operation === "steer-agent"
745
+ ? appendSteeringMessage(loaded.manifest, {
746
+ taskId: task.id,
747
+ to: agent.id,
748
+ body: message ?? "Please report current status and wrap up if possible.",
749
+ status: "delivered",
750
+ data: {
751
+ source: "steer-agent",
752
+ liveControlRequestId: request.id,
753
+ },
754
+ })
755
+ : operation === "follow-up-agent" && prompt
756
+ ? appendFollowUpMessage(loaded.manifest, {
757
+ taskId: task.id,
758
+ to: agent.id,
759
+ body: prompt,
760
+ status: "delivered",
761
+ data: {
762
+ source: "follow-up-agent",
763
+ liveControlRequestId: request.id,
764
+ },
765
+ })
766
+ : undefined;
283
767
  publishLiveControlRealtime(request);
284
768
  ctx.events?.emit?.("pi-crew:live-control", liveControlRealtimeMessage(request));
285
- appendEvent(loaded.manifest.eventsPath, { type: "agent.control.queued", runId: loaded.manifest.runId, taskId: agent.taskId, message: `Queued ${request.operation} control request for live agent.`, data: { request, mailboxMessageId: mailboxMessage?.id, realtime: true } });
286
- return result(JSON.stringify({ queued: true, request, mailboxMessage }, null, 2), { action: "api", status: "ok", runId: loaded.manifest.runId, artifactsRoot: loaded.manifest.artifactsRoot });
769
+ appendEvent(loaded.manifest.eventsPath, {
770
+ type: "agent.control.queued",
771
+ runId: loaded.manifest.runId,
772
+ taskId: agent.taskId,
773
+ message: `Queued ${request.operation} control request for live agent.`,
774
+ data: {
775
+ request,
776
+ mailboxMessageId: mailboxMessage?.id,
777
+ realtime: true,
778
+ },
779
+ });
780
+ return result(JSON.stringify({ queued: true, request, mailboxMessage }, null, 2), {
781
+ action: "api",
782
+ status: "ok",
783
+ runId: loaded.manifest.runId,
784
+ artifactsRoot: loaded.manifest.artifactsRoot,
785
+ });
287
786
  } catch (queueError) {
288
787
  const message = queueError instanceof Error ? queueError.message : String(queueError);
289
- return result(message, { action: "api", status: "error", runId: loaded.manifest.runId }, true);
788
+ return result(
789
+ message,
790
+ {
791
+ action: "api",
792
+ status: "error",
793
+ runId: loaded.manifest.runId,
794
+ },
795
+ true,
796
+ );
290
797
  }
291
798
  }
292
799
  }
293
800
  if (operation === "read-mailbox") {
294
- const direction = cfg.direction === "inbox" || cfg.direction === "outbox" ? cfg.direction as MailboxDirection : undefined;
801
+ const direction = cfg.direction === "inbox" || cfg.direction === "outbox" ? (cfg.direction as MailboxDirection) : undefined;
295
802
  const taskId = typeof cfg.taskId === "string" ? cfg.taskId : undefined;
296
- const kind = typeof cfg.kind === "string" && ["message", "steer", "follow-up", "response", "group_join"].includes(cfg.kind) ? cfg.kind as MailboxMessageKind : undefined;
297
- if (taskId && !loaded.tasks.some((task) => task.id === taskId)) return result(`API read-mailbox taskId '${taskId}' does not match a run task.`, { action: "api", status: "error", runId: loaded.manifest.runId }, true);
803
+ const kind =
804
+ typeof cfg.kind === "string" && ["message", "steer", "follow-up", "response", "group_join"].includes(cfg.kind)
805
+ ? (cfg.kind as MailboxMessageKind)
806
+ : undefined;
807
+ if (taskId && !loaded.tasks.some((task) => task.id === taskId))
808
+ return result(
809
+ `API read-mailbox taskId '${taskId}' does not match a run task.`,
810
+ {
811
+ action: "api",
812
+ status: "error",
813
+ runId: loaded.manifest.runId,
814
+ },
815
+ true,
816
+ );
298
817
  try {
299
- return result(JSON.stringify(readMailbox(loaded.manifest, direction, taskId, kind), null, 2), { action: "api", status: "ok", runId: loaded.manifest.runId, artifactsRoot: loaded.manifest.artifactsRoot });
818
+ return result(JSON.stringify(readMailbox(loaded.manifest, direction, taskId, kind), null, 2), {
819
+ action: "api",
820
+ status: "ok",
821
+ runId: loaded.manifest.runId,
822
+ artifactsRoot: loaded.manifest.artifactsRoot,
823
+ });
300
824
  } catch (error) {
301
825
  const message = error instanceof Error ? error.message : String(error);
302
- return result(message, { action: "api", status: "error", runId: loaded.manifest.runId }, true);
826
+ return result(
827
+ message,
828
+ {
829
+ action: "api",
830
+ status: "error",
831
+ runId: loaded.manifest.runId,
832
+ },
833
+ true,
834
+ );
303
835
  }
304
836
  }
305
837
  if (operation === "validate-mailbox") {
306
- const report = validateMailbox(loaded.manifest, { repair: cfg.repair === true });
307
- return result(JSON.stringify(report, null, 2), { action: "api", status: report.issues.some((issue) => issue.level === "error") && cfg.repair !== true ? "error" : "ok", runId: loaded.manifest.runId, artifactsRoot: loaded.manifest.artifactsRoot }, report.issues.some((issue) => issue.level === "error") && cfg.repair !== true);
838
+ const report = validateMailbox(loaded.manifest, {
839
+ repair: cfg.repair === true,
840
+ });
841
+ return result(
842
+ JSON.stringify(report, null, 2),
843
+ {
844
+ action: "api",
845
+ status: report.issues.some((issue) => issue.level === "error") && cfg.repair !== true ? "error" : "ok",
846
+ runId: loaded.manifest.runId,
847
+ artifactsRoot: loaded.manifest.artifactsRoot,
848
+ },
849
+ report.issues.some((issue) => issue.level === "error") && cfg.repair !== true,
850
+ );
308
851
  }
309
852
  if (operation === "read-delivery") {
310
- return result(JSON.stringify(readDeliveryState(loaded.manifest), null, 2), { action: "api", status: "ok", runId: loaded.manifest.runId, artifactsRoot: loaded.manifest.artifactsRoot });
853
+ return result(JSON.stringify(readDeliveryState(loaded.manifest), null, 2), {
854
+ action: "api",
855
+ status: "ok",
856
+ runId: loaded.manifest.runId,
857
+ artifactsRoot: loaded.manifest.artifactsRoot,
858
+ });
311
859
  }
312
860
  if (operation === "send-message") {
313
861
  const direction = cfg.direction === "outbox" ? "outbox" : "inbox";
@@ -315,67 +863,198 @@ export async function handleApi(params: TeamToolParamsValue, ctx: TeamContext):
315
863
  const to = typeof cfg.to === "string" && cfg.to.trim() ? cfg.to.trim() : "leader";
316
864
  const body = typeof cfg.body === "string" && cfg.body.trim() ? cfg.body : undefined;
317
865
  const taskId = typeof cfg.taskId === "string" && cfg.taskId.trim() ? cfg.taskId.trim() : undefined;
318
- if (!body) return result("API send-message requires config.body.", { action: "api", status: "error", runId: loaded.manifest.runId }, true);
319
- if (taskId && !loaded.tasks.some((task) => task.id === taskId)) return result(`API send-message taskId '${taskId}' does not match a run task.`, { action: "api", status: "error", runId: loaded.manifest.runId }, true);
866
+ if (!body)
867
+ return result(
868
+ "API send-message requires config.body.",
869
+ {
870
+ action: "api",
871
+ status: "error",
872
+ runId: loaded.manifest.runId,
873
+ },
874
+ true,
875
+ );
876
+ if (taskId && !loaded.tasks.some((task) => task.id === taskId))
877
+ return result(
878
+ `API send-message taskId '${taskId}' does not match a run task.`,
879
+ {
880
+ action: "api",
881
+ status: "error",
882
+ runId: loaded.manifest.runId,
883
+ },
884
+ true,
885
+ );
320
886
  try {
321
887
  return withRunLockSync(loaded.manifest, () => {
322
- const message = appendMailboxMessage(loaded.manifest, { direction, from, to, body, taskId });
323
- appendEvent(loaded.manifest.eventsPath, { type: "mailbox.message", runId: loaded.manifest.runId, data: { id: message.id, direction, from, to } });
324
- ctx.events?.emit?.("crew.mailbox.message", { runId: loaded.manifest.runId, id: message.id, direction, from, to, taskId, source: "send-message" });
325
- return result(JSON.stringify(message, null, 2), { action: "api", status: "ok", runId: loaded.manifest.runId, artifactsRoot: loaded.manifest.artifactsRoot });
888
+ const message = appendMailboxMessage(loaded.manifest, {
889
+ direction,
890
+ from,
891
+ to,
892
+ body,
893
+ taskId,
894
+ });
895
+ appendEvent(loaded.manifest.eventsPath, {
896
+ type: "mailbox.message",
897
+ runId: loaded.manifest.runId,
898
+ data: { id: message.id, direction, from, to },
899
+ });
900
+ ctx.events?.emit?.("crew.mailbox.message", {
901
+ runId: loaded.manifest.runId,
902
+ id: message.id,
903
+ direction,
904
+ from,
905
+ to,
906
+ taskId,
907
+ source: "send-message",
908
+ });
909
+ return result(JSON.stringify(message, null, 2), {
910
+ action: "api",
911
+ status: "ok",
912
+ runId: loaded.manifest.runId,
913
+ artifactsRoot: loaded.manifest.artifactsRoot,
914
+ });
326
915
  });
327
916
  } catch (error) {
328
917
  const message = error instanceof Error ? error.message : String(error);
329
- return result(message, { action: "api", status: "error", runId: loaded.manifest.runId }, true);
918
+ return result(
919
+ message,
920
+ {
921
+ action: "api",
922
+ status: "error",
923
+ runId: loaded.manifest.runId,
924
+ },
925
+ true,
926
+ );
330
927
  }
331
928
  }
332
929
  if (operation === "ack-message") {
333
930
  const messageId = typeof cfg.messageId === "string" ? cfg.messageId : undefined;
334
- if (!messageId) return result("API ack-message requires config.messageId.", { action: "api", status: "error", runId: loaded.manifest.runId }, true);
931
+ if (!messageId)
932
+ return result(
933
+ "API ack-message requires config.messageId.",
934
+ {
935
+ action: "api",
936
+ status: "error",
937
+ runId: loaded.manifest.runId,
938
+ },
939
+ true,
940
+ );
335
941
  try {
336
942
  return withRunLockSync(loaded.manifest, () => {
337
943
  const message = readMailboxMessage(loaded.manifest, messageId);
338
944
  const delivery = acknowledgeMailboxMessage(loaded.manifest, messageId);
339
- appendEvent(loaded.manifest.eventsPath, { type: "mailbox.acknowledged", runId: loaded.manifest.runId, data: { messageId } });
945
+ appendEvent(loaded.manifest.eventsPath, {
946
+ type: "mailbox.acknowledged",
947
+ runId: loaded.manifest.runId,
948
+ data: { messageId },
949
+ });
340
950
  if (message?.data?.kind === "group_join" && typeof message.data.requestId === "string") {
341
951
  appendEvent(loaded.manifest.eventsPath, {
342
952
  type: "agent.group_join.acknowledged",
343
953
  runId: loaded.manifest.runId,
344
954
  message: "Group join delivery acknowledged via mailbox ack.",
345
- data: { requestId: message.data.requestId, messageId, batchId: message.data.batchId, partial: message.data.partial, acknowledgedAt: delivery.updatedAt, acknowledgedBy: "leader" },
955
+ data: {
956
+ requestId: message.data.requestId,
957
+ messageId,
958
+ batchId: message.data.batchId,
959
+ partial: message.data.partial,
960
+ acknowledgedAt: delivery.updatedAt,
961
+ acknowledgedBy: "leader",
962
+ },
346
963
  metadata: { provenance: "api" },
347
964
  });
348
965
  }
349
- ctx.events?.emit?.("crew.mailbox.acknowledged", { runId: loaded.manifest.runId, messageId, delivery });
350
- return result(JSON.stringify(delivery, null, 2), { action: "api", status: "ok", runId: loaded.manifest.runId, artifactsRoot: loaded.manifest.artifactsRoot });
966
+ ctx.events?.emit?.("crew.mailbox.acknowledged", {
967
+ runId: loaded.manifest.runId,
968
+ messageId,
969
+ delivery,
970
+ });
971
+ return result(JSON.stringify(delivery, null, 2), {
972
+ action: "api",
973
+ status: "ok",
974
+ runId: loaded.manifest.runId,
975
+ artifactsRoot: loaded.manifest.artifactsRoot,
976
+ });
351
977
  });
352
978
  } catch (error) {
353
979
  const message = error instanceof Error ? error.message : String(error);
354
- return result(message, { action: "api", status: "error", runId: loaded.manifest.runId }, true);
980
+ return result(
981
+ message,
982
+ {
983
+ action: "api",
984
+ status: "error",
985
+ runId: loaded.manifest.runId,
986
+ },
987
+ true,
988
+ );
355
989
  }
356
990
  }
357
991
  if (operation === "read-heartbeat") {
358
992
  const taskId = typeof cfg.taskId === "string" ? cfg.taskId : undefined;
359
993
  const task = loaded.tasks.find((item) => item.id === taskId || item.stepId === taskId);
360
- if (!task) return result("API read-heartbeat requires config.taskId matching a task id or step id.", { action: "api", status: "error", runId: loaded.manifest.runId }, true);
361
- return result(JSON.stringify(task.heartbeat ?? null, null, 2), { action: "api", status: "ok", runId: loaded.manifest.runId, artifactsRoot: loaded.manifest.artifactsRoot });
994
+ if (!task)
995
+ return result(
996
+ "API read-heartbeat requires config.taskId matching a task id or step id.",
997
+ {
998
+ action: "api",
999
+ status: "error",
1000
+ runId: loaded.manifest.runId,
1001
+ },
1002
+ true,
1003
+ );
1004
+ return result(JSON.stringify(task.heartbeat ?? null, null, 2), {
1005
+ action: "api",
1006
+ status: "ok",
1007
+ runId: loaded.manifest.runId,
1008
+ artifactsRoot: loaded.manifest.artifactsRoot,
1009
+ });
362
1010
  }
363
1011
  if (operation === "claim-task") {
364
1012
  const taskId = typeof cfg.taskId === "string" ? cfg.taskId : undefined;
365
1013
  const owner = typeof cfg.owner === "string" ? cfg.owner : "api";
366
1014
  const task = loaded.tasks.find((item) => item.id === taskId || item.stepId === taskId);
367
- if (!task) return result("API claim-task requires config.taskId matching a task id or step id.", { action: "api", status: "error", runId: loaded.manifest.runId }, true);
1015
+ if (!task)
1016
+ return result(
1017
+ "API claim-task requires config.taskId matching a task id or step id.",
1018
+ {
1019
+ action: "api",
1020
+ status: "error",
1021
+ runId: loaded.manifest.runId,
1022
+ },
1023
+ true,
1024
+ );
368
1025
  try {
369
1026
  return withRunLockSync(loaded.manifest, () => {
370
1027
  const updatedTask = claimTask(task, owner);
371
- const tasks = loaded.tasks.map((item) => item.id === task.id ? updatedTask : item);
1028
+ const tasks = loaded.tasks.map((item) => (item.id === task.id ? updatedTask : item));
372
1029
  saveRunTasks(loaded.manifest, tasks);
373
- appendEvent(loaded.manifest.eventsPath, { type: "task.claimed", runId: loaded.manifest.runId, taskId: task.id, data: { owner, token: "[REDACTED]", leasedUntil: updatedTask.claim?.leasedUntil } });
374
- return result(JSON.stringify(updatedTask.claim, null, 2), { action: "api", status: "ok", runId: loaded.manifest.runId, artifactsRoot: loaded.manifest.artifactsRoot });
1030
+ appendEvent(loaded.manifest.eventsPath, {
1031
+ type: "task.claimed",
1032
+ runId: loaded.manifest.runId,
1033
+ taskId: task.id,
1034
+ data: {
1035
+ owner,
1036
+ token: "[REDACTED]",
1037
+ leasedUntil: updatedTask.claim?.leasedUntil,
1038
+ },
1039
+ });
1040
+ return result(JSON.stringify(updatedTask.claim, null, 2), {
1041
+ action: "api",
1042
+ status: "ok",
1043
+ runId: loaded.manifest.runId,
1044
+ artifactsRoot: loaded.manifest.artifactsRoot,
1045
+ });
375
1046
  });
376
1047
  } catch (error) {
377
1048
  const message = error instanceof Error ? error.message : String(error);
378
- return result(message, { action: "api", status: "error", runId: loaded.manifest.runId }, true);
1049
+ return result(
1050
+ message,
1051
+ {
1052
+ action: "api",
1053
+ status: "error",
1054
+ runId: loaded.manifest.runId,
1055
+ },
1056
+ true,
1057
+ );
379
1058
  }
380
1059
  }
381
1060
  if (operation === "release-task-claim") {
@@ -383,18 +1062,45 @@ export async function handleApi(params: TeamToolParamsValue, ctx: TeamContext):
383
1062
  const owner = typeof cfg.owner === "string" ? cfg.owner : undefined;
384
1063
  const token = typeof cfg.token === "string" ? cfg.token : undefined;
385
1064
  const task = loaded.tasks.find((item) => item.id === taskId || item.stepId === taskId);
386
- if (!task || !owner || !token) return result("API release-task-claim requires config.taskId, config.owner, and config.token.", { action: "api", status: "error", runId: loaded.manifest.runId }, true);
1065
+ if (!task || !owner || !token)
1066
+ return result(
1067
+ "API release-task-claim requires config.taskId, config.owner, and config.token.",
1068
+ {
1069
+ action: "api",
1070
+ status: "error",
1071
+ runId: loaded.manifest.runId,
1072
+ },
1073
+ true,
1074
+ );
387
1075
  try {
388
1076
  return withRunLockSync(loaded.manifest, () => {
389
1077
  const updatedTask = releaseTaskClaim(task, owner, token);
390
- const tasks = loaded.tasks.map((item) => item.id === task.id ? updatedTask : item);
1078
+ const tasks = loaded.tasks.map((item) => (item.id === task.id ? updatedTask : item));
391
1079
  saveRunTasks(loaded.manifest, tasks);
392
- appendEvent(loaded.manifest.eventsPath, { type: "task.claim_released", runId: loaded.manifest.runId, taskId: task.id, data: { owner } });
393
- return result(JSON.stringify(updatedTask, null, 2), { action: "api", status: "ok", runId: loaded.manifest.runId, artifactsRoot: loaded.manifest.artifactsRoot });
1080
+ appendEvent(loaded.manifest.eventsPath, {
1081
+ type: "task.claim_released",
1082
+ runId: loaded.manifest.runId,
1083
+ taskId: task.id,
1084
+ data: { owner },
1085
+ });
1086
+ return result(JSON.stringify(updatedTask, null, 2), {
1087
+ action: "api",
1088
+ status: "ok",
1089
+ runId: loaded.manifest.runId,
1090
+ artifactsRoot: loaded.manifest.artifactsRoot,
1091
+ });
394
1092
  });
395
1093
  } catch (error) {
396
1094
  const message = error instanceof Error ? error.message : String(error);
397
- return result(message, { action: "api", status: "error", runId: loaded.manifest.runId }, true);
1095
+ return result(
1096
+ message,
1097
+ {
1098
+ action: "api",
1099
+ status: "error",
1100
+ runId: loaded.manifest.runId,
1101
+ },
1102
+ true,
1103
+ );
398
1104
  }
399
1105
  }
400
1106
  if (operation === "transition-task-status") {
@@ -403,42 +1109,118 @@ export async function handleApi(params: TeamToolParamsValue, ctx: TeamContext):
403
1109
  const token = typeof cfg.token === "string" ? cfg.token : undefined;
404
1110
  const to = cfg.status;
405
1111
  const task = loaded.tasks.find((item) => item.id === taskId || item.stepId === taskId);
406
- if (!task || !owner || !token || !isTeamTaskStatus(to)) return result("API transition-task-status requires config.taskId, config.owner, config.token, and valid config.status.", { action: "api", status: "error", runId: loaded.manifest.runId }, true);
407
- if (!canTransitionTaskStatus(task.status, to)) return result(`Invalid task status transition: ${task.status} -> ${to}`, { action: "api", status: "error", runId: loaded.manifest.runId }, true);
1112
+ if (!task || !owner || !token || !isTeamTaskStatus(to))
1113
+ return result(
1114
+ "API transition-task-status requires config.taskId, config.owner, config.token, and valid config.status.",
1115
+ {
1116
+ action: "api",
1117
+ status: "error",
1118
+ runId: loaded.manifest.runId,
1119
+ },
1120
+ true,
1121
+ );
1122
+ if (!canTransitionTaskStatus(task.status, to))
1123
+ return result(
1124
+ `Invalid task status transition: ${task.status} -> ${to}`,
1125
+ {
1126
+ action: "api",
1127
+ status: "error",
1128
+ runId: loaded.manifest.runId,
1129
+ },
1130
+ true,
1131
+ );
408
1132
  try {
409
1133
  return withRunLockSync(loaded.manifest, () => {
410
1134
  const updatedTask = transitionClaimedTaskStatus(task, owner, token, to);
411
- const tasks = loaded.tasks.map((item) => item.id === task.id ? updatedTask : item);
1135
+ const tasks = loaded.tasks.map((item) => (item.id === task.id ? updatedTask : item));
412
1136
  saveRunTasks(loaded.manifest, tasks);
413
- appendEvent(loaded.manifest.eventsPath, { type: "task.status_transitioned", runId: loaded.manifest.runId, taskId: task.id, data: { owner, status: to } });
414
- return result(JSON.stringify(updatedTask, null, 2), { action: "api", status: "ok", runId: loaded.manifest.runId, artifactsRoot: loaded.manifest.artifactsRoot });
1137
+ appendEvent(loaded.manifest.eventsPath, {
1138
+ type: "task.status_transitioned",
1139
+ runId: loaded.manifest.runId,
1140
+ taskId: task.id,
1141
+ data: { owner, status: to },
1142
+ });
1143
+ return result(JSON.stringify(updatedTask, null, 2), {
1144
+ action: "api",
1145
+ status: "ok",
1146
+ runId: loaded.manifest.runId,
1147
+ artifactsRoot: loaded.manifest.artifactsRoot,
1148
+ });
415
1149
  });
416
1150
  } catch (error) {
417
1151
  const message = error instanceof Error ? error.message : String(error);
418
- return result(message, { action: "api", status: "error", runId: loaded.manifest.runId }, true);
1152
+ return result(
1153
+ message,
1154
+ {
1155
+ action: "api",
1156
+ status: "error",
1157
+ runId: loaded.manifest.runId,
1158
+ },
1159
+ true,
1160
+ );
419
1161
  }
420
1162
  }
421
1163
  if (operation === "write-heartbeat") {
422
1164
  const taskId = typeof cfg.taskId === "string" ? cfg.taskId : undefined;
423
1165
  const task = loaded.tasks.find((item) => item.id === taskId || item.stepId === taskId);
424
- if (!task) return result("API write-heartbeat requires config.taskId matching a task id or step id.", { action: "api", status: "error", runId: loaded.manifest.runId }, true);
1166
+ if (!task)
1167
+ return result(
1168
+ "API write-heartbeat requires config.taskId matching a task id or step id.",
1169
+ {
1170
+ action: "api",
1171
+ status: "error",
1172
+ runId: loaded.manifest.runId,
1173
+ },
1174
+ true,
1175
+ );
425
1176
  try {
426
1177
  return withRunLockSync(loaded.manifest, () => {
427
- const heartbeat = touchWorkerHeartbeat(task.heartbeat ?? { workerId: task.id, lastSeenAt: new Date().toISOString() }, { alive: typeof cfg.alive === "boolean" ? cfg.alive : undefined });
428
- const tasks = loaded.tasks.map((item) => item.id === task.id ? { ...item, heartbeat } : item);
1178
+ const heartbeat = touchWorkerHeartbeat(
1179
+ task.heartbeat ?? {
1180
+ workerId: task.id,
1181
+ lastSeenAt: new Date().toISOString(),
1182
+ },
1183
+ {
1184
+ alive: typeof cfg.alive === "boolean" ? cfg.alive : undefined,
1185
+ },
1186
+ );
1187
+ const tasks = loaded.tasks.map((item) => (item.id === task.id ? { ...item, heartbeat } : item));
429
1188
  saveRunTasks(loaded.manifest, tasks);
430
- appendEvent(loaded.manifest.eventsPath, { type: "worker.heartbeat", runId: loaded.manifest.runId, taskId: task.id, data: { ...heartbeat } });
431
- return result(JSON.stringify(heartbeat, null, 2), { action: "api", status: "ok", runId: loaded.manifest.runId, artifactsRoot: loaded.manifest.artifactsRoot });
1189
+ appendEvent(loaded.manifest.eventsPath, {
1190
+ type: "worker.heartbeat",
1191
+ runId: loaded.manifest.runId,
1192
+ taskId: task.id,
1193
+ data: { ...heartbeat },
1194
+ });
1195
+ return result(JSON.stringify(heartbeat, null, 2), {
1196
+ action: "api",
1197
+ status: "ok",
1198
+ runId: loaded.manifest.runId,
1199
+ artifactsRoot: loaded.manifest.artifactsRoot,
1200
+ });
432
1201
  });
433
1202
  } catch (error) {
434
1203
  const message = error instanceof Error ? error.message : String(error);
435
- return result(message, { action: "api", status: "error", runId: loaded.manifest.runId }, true);
1204
+ return result(
1205
+ message,
1206
+ {
1207
+ action: "api",
1208
+ status: "error",
1209
+ runId: loaded.manifest.runId,
1210
+ },
1211
+ true,
1212
+ );
436
1213
  }
437
1214
  }
438
1215
  if (operation === "diff") {
439
- const diffArtifacts = loaded.manifest.artifacts.filter(a => a.kind === "diff" || a.kind === "patch");
1216
+ const diffArtifacts = loaded.manifest.artifacts.filter((a) => a.kind === "diff" || a.kind === "patch");
440
1217
  if (diffArtifacts.length === 0) {
441
- return result(`No diff artifacts found for run ${loaded.manifest.runId}. Diffs are captured in worktree mode.`, { action: "api", status: "ok", runId: loaded.manifest.runId, intent: `diff ${loaded.manifest.runId}: no diffs` });
1218
+ return result(`No diff artifacts found for run ${loaded.manifest.runId}. Diffs are captured in worktree mode.`, {
1219
+ action: "api",
1220
+ status: "ok",
1221
+ runId: loaded.manifest.runId,
1222
+ intent: `diff ${loaded.manifest.runId}: no diffs`,
1223
+ });
442
1224
  }
443
1225
  const parts: string[] = [`Diff artifacts for run ${loaded.manifest.runId}:`];
444
1226
  for (const artifact of diffArtifacts) {
@@ -448,7 +1230,13 @@ export async function handleApi(params: TeamToolParamsValue, ctx: TeamContext):
448
1230
  parts.push(`\n--- ${artifact.path} ---\n${display}`);
449
1231
  }
450
1232
  }
451
- return result(parts.join("\n"), { action: "api", status: "ok", runId: loaded.manifest.runId, artifactsRoot: loaded.manifest.artifactsRoot, intent: `diff ${loaded.manifest.runId}` });
1233
+ return result(parts.join("\n"), {
1234
+ action: "api",
1235
+ status: "ok",
1236
+ runId: loaded.manifest.runId,
1237
+ artifactsRoot: loaded.manifest.artifactsRoot,
1238
+ intent: `diff ${loaded.manifest.runId}`,
1239
+ });
452
1240
  }
453
1241
  return result(`Unknown API operation: ${operation}`, { action: "api", status: "error", runId: loaded.manifest.runId }, true);
454
1242
  }