pi-crew 0.9.53 → 0.9.55

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 (493) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/package.json +6 -3
  3. package/scripts/clean-strip-types.mjs +60 -0
  4. package/src/adapters/claude-adapter.ts +23 -0
  5. package/src/adapters/codex-adapter.ts +21 -0
  6. package/src/adapters/cursor-adapter.ts +17 -0
  7. package/src/adapters/export-util.ts +143 -0
  8. package/src/adapters/index.ts +15 -0
  9. package/src/adapters/registry.ts +18 -0
  10. package/src/adapters/types.ts +23 -0
  11. package/src/agents/agent-config.ts +194 -0
  12. package/src/agents/agent-search.ts +98 -0
  13. package/src/agents/agent-serializer.ts +38 -0
  14. package/src/agents/discover-agents.ts +623 -0
  15. package/src/benchmark/benchmark-runner.ts +313 -0
  16. package/src/benchmark/feedback-loop.ts +73 -0
  17. package/src/config/config.ts +1270 -0
  18. package/src/config/defaults.ts +193 -0
  19. package/src/config/drift-detector.ts +290 -0
  20. package/src/config/markers.ts +330 -0
  21. package/src/config/resilient-parser.ts +117 -0
  22. package/src/config/role-tools.ts +118 -0
  23. package/src/config/suggestions.ts +75 -0
  24. package/src/config/types.ts +280 -0
  25. package/src/errors.ts +194 -0
  26. package/src/extension/action-suggestions.ts +117 -0
  27. package/src/extension/async-notifier.ts +179 -0
  28. package/src/extension/autonomous-policy.ts +209 -0
  29. package/src/extension/command-completions.ts +120 -0
  30. package/src/extension/context-status-injection.ts +185 -0
  31. package/src/extension/crew-autocomplete.ts +131 -0
  32. package/src/extension/crew-cleanup.ts +168 -0
  33. package/src/extension/crew-input-router.ts +93 -0
  34. package/src/extension/crew-shortcuts.ts +87 -0
  35. package/src/extension/crew-vibes/cat-frames.ts +18 -0
  36. package/src/extension/crew-vibes/config.ts +195 -0
  37. package/src/extension/crew-vibes/figures.ts +101 -0
  38. package/src/extension/crew-vibes/font-detect.ts +71 -0
  39. package/src/extension/crew-vibes/footer.ts +292 -0
  40. package/src/extension/crew-vibes/index.ts +432 -0
  41. package/src/extension/crew-vibes/provider-usage.ts +396 -0
  42. package/src/extension/crew-vibes/render.ts +206 -0
  43. package/src/extension/crew-vibes/speed.ts +286 -0
  44. package/src/extension/cross-extension-rpc.ts +350 -0
  45. package/src/extension/help.ts +62 -0
  46. package/src/extension/import-index.ts +74 -0
  47. package/src/extension/knowledge-injection.ts +402 -0
  48. package/src/extension/management.ts +571 -0
  49. package/src/extension/message-renderers.ts +108 -0
  50. package/src/extension/notification-router.ts +152 -0
  51. package/src/extension/notification-sink.ts +54 -0
  52. package/src/extension/pi-api.ts +56 -0
  53. package/src/extension/plan-orchestrate.ts +302 -0
  54. package/src/extension/project-init.ts +170 -0
  55. package/src/extension/register.ts +113 -0
  56. package/src/extension/registration/artifact-cleanup.ts +20 -0
  57. package/src/extension/registration/command-registration.ts +58 -0
  58. package/src/extension/registration/command-utils.ts +58 -0
  59. package/src/extension/registration/commands.ts +1228 -0
  60. package/src/extension/registration/compaction-guard.ts +333 -0
  61. package/src/extension/registration/context-builder.ts +135 -0
  62. package/src/extension/registration/crash-recovery-cache.ts +54 -0
  63. package/src/extension/registration/foreground-run-controller.ts +238 -0
  64. package/src/extension/registration/hook-registration.ts +119 -0
  65. package/src/extension/registration/lazy-configurers.ts +124 -0
  66. package/src/extension/registration/lifecycle-handlers.ts +923 -0
  67. package/src/extension/registration/lifecycle.ts +259 -0
  68. package/src/extension/registration/observability.ts +322 -0
  69. package/src/extension/registration/registration-types.ts +158 -0
  70. package/src/extension/registration/runtime-cleanup.ts +230 -0
  71. package/src/extension/registration/subagent-helpers.ts +125 -0
  72. package/src/extension/registration/subagent-manager-setup.ts +330 -0
  73. package/src/extension/registration/subagent-tools.ts +456 -0
  74. package/src/extension/registration/team-tool.ts +225 -0
  75. package/src/extension/registration/tool-registration.ts +50 -0
  76. package/src/extension/registration/ui.ts +172 -0
  77. package/src/extension/registration/viewers.ts +121 -0
  78. package/src/extension/registration/wire-cross-extension.ts +37 -0
  79. package/src/extension/result-watcher.ts +139 -0
  80. package/src/extension/rpc-hmac.ts +256 -0
  81. package/src/extension/run-bundle-schema.ts +104 -0
  82. package/src/extension/run-export.ts +97 -0
  83. package/src/extension/run-import.ts +168 -0
  84. package/src/extension/run-index.ts +131 -0
  85. package/src/extension/run-maintenance.ts +190 -0
  86. package/src/extension/session-summary.ts +18 -0
  87. package/src/extension/team-manager-command.ts +153 -0
  88. package/src/extension/team-onboard.ts +180 -0
  89. package/src/extension/team-recommendation.ts +288 -0
  90. package/src/extension/team-tool/anchor.ts +172 -0
  91. package/src/extension/team-tool/api.ts +1244 -0
  92. package/src/extension/team-tool/auto-summarize.ts +142 -0
  93. package/src/extension/team-tool/cache-control.ts +19 -0
  94. package/src/extension/team-tool/cancel.ts +337 -0
  95. package/src/extension/team-tool/chain-dispatch.ts +95 -0
  96. package/src/extension/team-tool/chain-executor.ts +379 -0
  97. package/src/extension/team-tool/config-patch.ts +50 -0
  98. package/src/extension/team-tool/context.ts +149 -0
  99. package/src/extension/team-tool/destructive-gate.ts +52 -0
  100. package/src/extension/team-tool/dispatch/automate.ts +80 -0
  101. package/src/extension/team-tool/dispatch/control.ts +42 -0
  102. package/src/extension/team-tool/dispatch/index.ts +95 -0
  103. package/src/extension/team-tool/dispatch/manage.ts +161 -0
  104. package/src/extension/team-tool/dispatch/run.ts +53 -0
  105. package/src/extension/team-tool/dispatch/status.ts +187 -0
  106. package/src/extension/team-tool/doctor.ts +431 -0
  107. package/src/extension/team-tool/explain.ts +282 -0
  108. package/src/extension/team-tool/failure-patterns.ts +118 -0
  109. package/src/extension/team-tool/goal-wrap.ts +330 -0
  110. package/src/extension/team-tool/goal.ts +556 -0
  111. package/src/extension/team-tool/handle-schedule.ts +332 -0
  112. package/src/extension/team-tool/handle-settings.ts +520 -0
  113. package/src/extension/team-tool/health-monitor.ts +481 -0
  114. package/src/extension/team-tool/inspect.ts +88 -0
  115. package/src/extension/team-tool/intent-policy.ts +45 -0
  116. package/src/extension/team-tool/lifecycle-actions.ts +615 -0
  117. package/src/extension/team-tool/orchestrate.ts +98 -0
  118. package/src/extension/team-tool/parallel-dispatch.ts +183 -0
  119. package/src/extension/team-tool/plan.ts +50 -0
  120. package/src/extension/team-tool/respond.ts +150 -0
  121. package/src/extension/team-tool/run-deadline.ts +66 -0
  122. package/src/extension/team-tool/run-not-found.ts +49 -0
  123. package/src/extension/team-tool/run.ts +1051 -0
  124. package/src/extension/team-tool/status.ts +260 -0
  125. package/src/extension/team-tool/workflow-manage.ts +261 -0
  126. package/src/extension/team-tool-types.ts +26 -0
  127. package/src/extension/team-tool.ts +750 -0
  128. package/src/extension/tool-result.ts +16 -0
  129. package/src/extension/validate-resources.ts +108 -0
  130. package/src/hooks/registry.ts +200 -0
  131. package/src/hooks/types.ts +69 -0
  132. package/src/i18n.ts +212 -0
  133. package/src/observability/correlation.ts +50 -0
  134. package/src/observability/event-bus.ts +86 -0
  135. package/src/observability/event-to-metric.ts +170 -0
  136. package/src/observability/exporters/adapter.ts +27 -0
  137. package/src/observability/exporters/otlp-exporter.ts +356 -0
  138. package/src/observability/exporters/prometheus-exporter.ts +54 -0
  139. package/src/observability/metric-registry.ts +100 -0
  140. package/src/observability/metric-retention.ts +64 -0
  141. package/src/observability/metric-sink.ts +99 -0
  142. package/src/observability/metrics-primitives.ts +219 -0
  143. package/src/plugins/plugin-define.ts +6 -0
  144. package/src/plugins/plugin-registry.ts +32 -0
  145. package/src/plugins/plugins/index.ts +3 -0
  146. package/src/plugins/plugins/nextjs.ts +19 -0
  147. package/src/plugins/plugins/vite.ts +10 -0
  148. package/src/plugins/plugins/vitest.ts +9 -0
  149. package/src/prompt/prompt-runtime.ts +380 -0
  150. package/src/runtime/adaptive-plan.ts +563 -0
  151. package/src/runtime/agent-control.ts +215 -0
  152. package/src/runtime/agent-memory.ts +81 -0
  153. package/src/runtime/agent-observability.ts +122 -0
  154. package/src/runtime/anchor-manager.ts +475 -0
  155. package/src/runtime/async-marker.ts +32 -0
  156. package/src/runtime/async-runner.ts +381 -0
  157. package/src/runtime/attention-events.ts +28 -0
  158. package/src/runtime/auto-summarize.ts +344 -0
  159. package/src/runtime/background-runner.ts +840 -0
  160. package/src/runtime/batch-barrier.ts +147 -0
  161. package/src/runtime/broker-issuer.ts +39 -0
  162. package/src/runtime/cancellation-token.ts +99 -0
  163. package/src/runtime/cancellation.ts +99 -0
  164. package/src/runtime/capability-inventory.ts +137 -0
  165. package/src/runtime/chain-parser.ts +237 -0
  166. package/src/runtime/chain-runner.ts +606 -0
  167. package/src/runtime/checkpoint.ts +291 -0
  168. package/src/runtime/child-pi-constants.ts +42 -0
  169. package/src/runtime/child-pi-kill.ts +180 -0
  170. package/src/runtime/child-pi-pool.ts +68 -0
  171. package/src/runtime/child-pi-spawn.ts +287 -0
  172. package/src/runtime/child-pi-steering.ts +128 -0
  173. package/src/runtime/child-pi-streams.ts +296 -0
  174. package/src/runtime/child-pi-transcript.ts +169 -0
  175. package/src/runtime/child-pi.ts +1105 -0
  176. package/src/runtime/coalesce-tasks.ts +268 -0
  177. package/src/runtime/code-summary.ts +292 -0
  178. package/src/runtime/command-trace.ts +105 -0
  179. package/src/runtime/compact-pipeline.ts +56 -0
  180. package/src/runtime/compact-stages/ansi-strip-stage.ts +25 -0
  181. package/src/runtime/compact-stages/blank-collapse-stage.ts +31 -0
  182. package/src/runtime/compact-stages/deduplicate-stage.ts +34 -0
  183. package/src/runtime/compact-stages/head-snap-stage.ts +57 -0
  184. package/src/runtime/compact-stages/index.ts +23 -0
  185. package/src/runtime/compact-stages/tail-capture-stage.ts +77 -0
  186. package/src/runtime/compact-stages/truncation-stage.ts +74 -0
  187. package/src/runtime/compaction-summary.ts +278 -0
  188. package/src/runtime/completion-guard.ts +207 -0
  189. package/src/runtime/concurrency.ts +58 -0
  190. package/src/runtime/crash-classification.ts +229 -0
  191. package/src/runtime/crash-recovery.ts +594 -0
  192. package/src/runtime/crew-agent-records.ts +595 -0
  193. package/src/runtime/crew-agent-runtime.ts +62 -0
  194. package/src/runtime/crew-broker-child.ts +88 -0
  195. package/src/runtime/crew-broker-client.ts +673 -0
  196. package/src/runtime/crew-broker-tokens.ts +159 -0
  197. package/src/runtime/crew-broker.ts +1304 -0
  198. package/src/runtime/crew-hooks.ts +227 -0
  199. package/src/runtime/cross-extension-rpc.ts +143 -0
  200. package/src/runtime/custom-tools/irc-tool.ts +282 -0
  201. package/src/runtime/custom-tools/submit-result-tool.ts +102 -0
  202. package/src/runtime/deadletter.ts +47 -0
  203. package/src/runtime/delivery-coordinator.ts +211 -0
  204. package/src/runtime/delta-conflict.ts +348 -0
  205. package/src/runtime/deterministic-ast.ts +161 -0
  206. package/src/runtime/diagnostic-export.ts +171 -0
  207. package/src/runtime/direct-run.ts +45 -0
  208. package/src/runtime/dwf-state-store.ts +102 -0
  209. package/src/runtime/dynamic-workflow-context.ts +1013 -0
  210. package/src/runtime/dynamic-workflow-runner.ts +325 -0
  211. package/src/runtime/effectiveness.ts +90 -0
  212. package/src/runtime/errors/crew-errors.ts +162 -0
  213. package/src/runtime/event-stream-bridge.ts +98 -0
  214. package/src/runtime/foreground-control.ts +193 -0
  215. package/src/runtime/foreground-watchdog.ts +132 -0
  216. package/src/runtime/global-worker-cap.ts +96 -0
  217. package/src/runtime/goal-achievement.ts +148 -0
  218. package/src/runtime/goal-evaluator.ts +365 -0
  219. package/src/runtime/goal-loop-runner.ts +825 -0
  220. package/src/runtime/goal-state-store.ts +219 -0
  221. package/src/runtime/green-contract.ts +55 -0
  222. package/src/runtime/group-join.ts +267 -0
  223. package/src/runtime/handoff-manager.ts +598 -0
  224. package/src/runtime/heartbeat-gradient.ts +36 -0
  225. package/src/runtime/heartbeat-watcher.ts +239 -0
  226. package/src/runtime/hidden-handoff.ts +407 -0
  227. package/src/runtime/important-line-classifier.ts +140 -0
  228. package/src/runtime/intercom-bridge.ts +187 -0
  229. package/src/runtime/iteration-hooks.ts +305 -0
  230. package/src/runtime/live-agent-control.ts +136 -0
  231. package/src/runtime/live-agent-manager.ts +704 -0
  232. package/src/runtime/live-control-realtime.ts +56 -0
  233. package/src/runtime/live-extension-bridge.ts +148 -0
  234. package/src/runtime/live-irc.ts +97 -0
  235. package/src/runtime/live-session-health.ts +108 -0
  236. package/src/runtime/live-session-runtime.ts +1146 -0
  237. package/src/runtime/loop-gates.ts +128 -0
  238. package/src/runtime/manifest-cache.ts +375 -0
  239. package/src/runtime/mcp-proxy.ts +105 -0
  240. package/src/runtime/metric-parser.ts +36 -0
  241. package/src/runtime/model-fallback.ts +409 -0
  242. package/src/runtime/model-resolver.ts +126 -0
  243. package/src/runtime/model-scope.ts +158 -0
  244. package/src/runtime/orphan-worker-registry.ts +465 -0
  245. package/src/runtime/output-validator.ts +202 -0
  246. package/src/runtime/overflow-recovery.ts +206 -0
  247. package/src/runtime/parallel-research.ts +68 -0
  248. package/src/runtime/parallel-utils.ts +160 -0
  249. package/src/runtime/parent-guard.ts +134 -0
  250. package/src/runtime/path-overlap.ts +150 -0
  251. package/src/runtime/peer-dep.ts +292 -0
  252. package/src/runtime/per-write-validator.ts +181 -0
  253. package/src/runtime/phase-progress.ts +217 -0
  254. package/src/runtime/phase-tracker.ts +385 -0
  255. package/src/runtime/pi-args.ts +655 -0
  256. package/src/runtime/pi-json-output.ts +170 -0
  257. package/src/runtime/pi-spawn.ts +273 -0
  258. package/src/runtime/pipeline-runner.ts +523 -0
  259. package/src/runtime/plan-templates.ts +201 -0
  260. package/src/runtime/policy-engine.ts +115 -0
  261. package/src/runtime/post-checks.ts +142 -0
  262. package/src/runtime/post-exit-stdio-guard.ts +109 -0
  263. package/src/runtime/process-lifecycle.ts +491 -0
  264. package/src/runtime/process-status.ts +154 -0
  265. package/src/runtime/progress-event-coalescer.ts +44 -0
  266. package/src/runtime/progress-tracker.ts +124 -0
  267. package/src/runtime/prose-compressor.ts +162 -0
  268. package/src/runtime/recovery-recipes.ts +203 -0
  269. package/src/runtime/replace.ts +570 -0
  270. package/src/runtime/resilient-edit.ts +153 -0
  271. package/src/runtime/result-extractor.ts +217 -0
  272. package/src/runtime/retry-executor.ts +109 -0
  273. package/src/runtime/retry-runner.ts +336 -0
  274. package/src/runtime/role-permission.ts +59 -0
  275. package/src/runtime/run-coalesced-task-group.ts +308 -0
  276. package/src/runtime/run-drift.ts +219 -0
  277. package/src/runtime/run-tracker.ts +116 -0
  278. package/src/runtime/run-worker.ts +78 -0
  279. package/src/runtime/runtime-policy.ts +29 -0
  280. package/src/runtime/runtime-resolver.ts +172 -0
  281. package/src/runtime/runtime-warmup.ts +160 -0
  282. package/src/runtime/scheduler.ts +353 -0
  283. package/src/runtime/semaphore.ts +141 -0
  284. package/src/runtime/sensitive-paths.ts +93 -0
  285. package/src/runtime/session-resources.ts +25 -0
  286. package/src/runtime/session-snapshot.ts +59 -0
  287. package/src/runtime/session-usage.ts +79 -0
  288. package/src/runtime/settings-store.ts +155 -0
  289. package/src/runtime/sidechain-output.ts +35 -0
  290. package/src/runtime/single-agent-compose.ts +84 -0
  291. package/src/runtime/skill-effectiveness.ts +524 -0
  292. package/src/runtime/skill-instructions.ts +394 -0
  293. package/src/runtime/stale-reconciler.ts +680 -0
  294. package/src/runtime/stream-preview.ts +184 -0
  295. package/src/runtime/streaming-output.ts +50 -0
  296. package/src/runtime/subagent-manager.ts +561 -0
  297. package/src/runtime/subprocess-tool-registry.ts +70 -0
  298. package/src/runtime/supervisor-contact.ts +64 -0
  299. package/src/runtime/task-display.ts +52 -0
  300. package/src/runtime/task-graph-scheduler.ts +227 -0
  301. package/src/runtime/task-graph.ts +290 -0
  302. package/src/runtime/task-health.ts +83 -0
  303. package/src/runtime/task-id.ts +161 -0
  304. package/src/runtime/task-output-context.ts +602 -0
  305. package/src/runtime/task-packet.ts +268 -0
  306. package/src/runtime/task-quality.ts +199 -0
  307. package/src/runtime/task-runner/capabilities.ts +78 -0
  308. package/src/runtime/task-runner/child-executor.ts +790 -0
  309. package/src/runtime/task-runner/context-retrieval.ts +163 -0
  310. package/src/runtime/task-runner/live-executor.ts +227 -0
  311. package/src/runtime/task-runner/output-splitter.ts +152 -0
  312. package/src/runtime/task-runner/post-execution.ts +480 -0
  313. package/src/runtime/task-runner/pre-execution.ts +365 -0
  314. package/src/runtime/task-runner/progress.ts +157 -0
  315. package/src/runtime/task-runner/prompt-builder.ts +278 -0
  316. package/src/runtime/task-runner/prompt-pipeline.ts +88 -0
  317. package/src/runtime/task-runner/result-utils.ts +16 -0
  318. package/src/runtime/task-runner/retrieval-orchestrator.ts +310 -0
  319. package/src/runtime/task-runner/run-projection.ts +125 -0
  320. package/src/runtime/task-runner/scaffold-executor.ts +25 -0
  321. package/src/runtime/task-runner/state-helpers.ts +176 -0
  322. package/src/runtime/task-runner/tail-read.ts +34 -0
  323. package/src/runtime/task-runner.ts +216 -0
  324. package/src/runtime/team-runner-artifacts.ts +13 -0
  325. package/src/runtime/team-runner.ts +2396 -0
  326. package/src/runtime/tool-output-pruner.ts +333 -0
  327. package/src/runtime/tool-progress.ts +278 -0
  328. package/src/runtime/usage-tracker.ts +73 -0
  329. package/src/runtime/verification-gates.ts +579 -0
  330. package/src/runtime/verification-integrity.ts +108 -0
  331. package/src/runtime/verification-worktree.ts +186 -0
  332. package/src/runtime/worker-heartbeat.ts +25 -0
  333. package/src/runtime/worker-startup.ts +83 -0
  334. package/src/runtime/workflow-state.ts +195 -0
  335. package/src/runtime/workspace-lock.ts +443 -0
  336. package/src/runtime/workspace-tree.ts +312 -0
  337. package/src/runtime/yield-handler.ts +224 -0
  338. package/src/runtime/zombie-scanner.ts +298 -0
  339. package/src/schema/config-schema.ts +327 -0
  340. package/src/schema/team-tool-schema.ts +492 -0
  341. package/src/schema/validation-types.ts +159 -0
  342. package/src/skills/discover-skills.ts +203 -0
  343. package/src/skills/skill-templates.ts +456 -0
  344. package/src/skills/validate.ts +285 -0
  345. package/src/state/active-run-registry.ts +439 -0
  346. package/src/state/artifact-store.ts +176 -0
  347. package/src/state/atomic-write.ts +970 -0
  348. package/src/state/blob-store.ts +308 -0
  349. package/src/state/contracts.ts +160 -0
  350. package/src/state/crew-init.ts +269 -0
  351. package/src/state/decision-ledger.ts +372 -0
  352. package/src/state/event-log-rotation.ts +399 -0
  353. package/src/state/event-log.ts +1465 -0
  354. package/src/state/event-reconstructor.ts +229 -0
  355. package/src/state/gitignore-manager.ts +46 -0
  356. package/src/state/health-store.ts +79 -0
  357. package/src/state/hook-instinct-bridge.ts +94 -0
  358. package/src/state/hook-integrations.ts +51 -0
  359. package/src/state/instinct-store.ts +275 -0
  360. package/src/state/jsonl-writer.ts +107 -0
  361. package/src/state/locks.ts +562 -0
  362. package/src/state/mailbox.ts +916 -0
  363. package/src/state/observation-store.ts +176 -0
  364. package/src/state/run-cache.ts +193 -0
  365. package/src/state/run-graph.ts +183 -0
  366. package/src/state/run-metrics.ts +165 -0
  367. package/src/state/schedule.ts +166 -0
  368. package/src/state/session-state-map.ts +51 -0
  369. package/src/state/state-store.ts +973 -0
  370. package/src/state/task-claims.ts +61 -0
  371. package/src/state/tiered-eval.ts +480 -0
  372. package/src/state/types-eval.ts +58 -0
  373. package/src/state/types.ts +447 -0
  374. package/src/state/usage.ts +138 -0
  375. package/src/state/worker-atomic-writer.ts +198 -0
  376. package/src/subagents/async-entry.ts +1 -0
  377. package/src/subagents/index.ts +3 -0
  378. package/src/subagents/live/control.ts +1 -0
  379. package/src/subagents/live/manager.ts +1 -0
  380. package/src/subagents/live/realtime.ts +1 -0
  381. package/src/subagents/live/session-runtime.ts +1 -0
  382. package/src/subagents/manager.ts +1 -0
  383. package/src/subagents/spawn.ts +1 -0
  384. package/src/teams/discover-teams.ts +187 -0
  385. package/src/teams/team-config.ts +27 -0
  386. package/src/teams/team-serializer.ts +38 -0
  387. package/src/tools/safe-bash-extension.ts +54 -0
  388. package/src/tools/safe-bash.ts +505 -0
  389. package/src/types/diff.d.ts +18 -0
  390. package/src/types/new-api-types.ts +35 -0
  391. package/src/ui/agent-management-overlay.ts +160 -0
  392. package/src/ui/card-colors.ts +139 -0
  393. package/src/ui/crew-footer.ts +102 -0
  394. package/src/ui/crew-select-list.ts +112 -0
  395. package/src/ui/dashboard-panes/agents-pane.ts +164 -0
  396. package/src/ui/dashboard-panes/cancellation-pane.ts +66 -0
  397. package/src/ui/dashboard-panes/capability-pane.ts +77 -0
  398. package/src/ui/dashboard-panes/health-pane.ts +31 -0
  399. package/src/ui/dashboard-panes/mailbox-pane.ts +35 -0
  400. package/src/ui/dashboard-panes/metrics-pane.ts +37 -0
  401. package/src/ui/dashboard-panes/progress-pane.ts +38 -0
  402. package/src/ui/dashboard-panes/transcript-pane.ts +10 -0
  403. package/src/ui/deploy-bundled-themes.ts +71 -0
  404. package/src/ui/dwf-phase-display.ts +151 -0
  405. package/src/ui/dynamic-border.ts +35 -0
  406. package/src/ui/format-helpers.ts +31 -0
  407. package/src/ui/heartbeat-aggregator.ts +74 -0
  408. package/src/ui/key-utils.ts +42 -0
  409. package/src/ui/keybinding-map.ts +248 -0
  410. package/src/ui/layout-primitives.ts +106 -0
  411. package/src/ui/live-conversation-overlay.ts +183 -0
  412. package/src/ui/live-duration.ts +55 -0
  413. package/src/ui/live-run-sidebar.ts +293 -0
  414. package/src/ui/loaders.ts +6 -0
  415. package/src/ui/mascot.ts +449 -0
  416. package/src/ui/overlays/agent-picker-overlay.ts +66 -0
  417. package/src/ui/overlays/confirm-overlay.ts +60 -0
  418. package/src/ui/overlays/help-overlay.ts +177 -0
  419. package/src/ui/overlays/mailbox-compose-overlay.ts +181 -0
  420. package/src/ui/overlays/mailbox-compose-preview.ts +78 -0
  421. package/src/ui/overlays/mailbox-detail-overlay.ts +155 -0
  422. package/src/ui/pi-ui-compat.ts +68 -0
  423. package/src/ui/powerbar-publisher.ts +459 -0
  424. package/src/ui/render-coalescer.ts +101 -0
  425. package/src/ui/render-diff.ts +160 -0
  426. package/src/ui/render-scheduler.ts +278 -0
  427. package/src/ui/run-action-dispatcher.ts +182 -0
  428. package/src/ui/run-dashboard.ts +910 -0
  429. package/src/ui/run-event-bus.ts +381 -0
  430. package/src/ui/run-snapshot-cache.ts +1057 -0
  431. package/src/ui/settings-overlay.ts +1067 -0
  432. package/src/ui/shared-overlay-scheduler.ts +96 -0
  433. package/src/ui/snapshot-types.ts +90 -0
  434. package/src/ui/spinner.ts +17 -0
  435. package/src/ui/status-colors.ts +143 -0
  436. package/src/ui/syntax-highlight.ts +136 -0
  437. package/src/ui/terminal-status.ts +269 -0
  438. package/src/ui/theme-adapter.ts +271 -0
  439. package/src/ui/theme-discovery.ts +199 -0
  440. package/src/ui/tool-progress-formatter.ts +93 -0
  441. package/src/ui/tool-renderers/brief-mode.ts +225 -0
  442. package/src/ui/tool-renderers/index.ts +726 -0
  443. package/src/ui/transcript-cache.ts +128 -0
  444. package/src/ui/transcript-entries.ts +256 -0
  445. package/src/ui/transcript-viewer.ts +424 -0
  446. package/src/ui/widget/index.ts +418 -0
  447. package/src/ui/widget/widget-formatters.ts +182 -0
  448. package/src/ui/widget/widget-model.ts +110 -0
  449. package/src/ui/widget/widget-renderer.ts +182 -0
  450. package/src/ui/widget/widget-types.ts +36 -0
  451. package/src/utils/bm25-search.ts +235 -0
  452. package/src/utils/completion-dedupe.ts +63 -0
  453. package/src/utils/conflict-detect.ts +668 -0
  454. package/src/utils/env-allowlist.ts +30 -0
  455. package/src/utils/env-filter.ts +155 -0
  456. package/src/utils/file-coalescer.ts +98 -0
  457. package/src/utils/fingerprint.ts +180 -0
  458. package/src/utils/frontmatter.ts +70 -0
  459. package/src/utils/fs-watch.ts +37 -0
  460. package/src/utils/gh-protocol.ts +556 -0
  461. package/src/utils/git.ts +260 -0
  462. package/src/utils/guards.ts +107 -0
  463. package/src/utils/ids.ts +24 -0
  464. package/src/utils/incremental-reader.ts +220 -0
  465. package/src/utils/internal-error.ts +10 -0
  466. package/src/utils/names.ts +36 -0
  467. package/src/utils/ndjson.ts +115 -0
  468. package/src/utils/paths.ts +227 -0
  469. package/src/utils/project-detector.ts +160 -0
  470. package/src/utils/redaction.ts +370 -0
  471. package/src/utils/resolve-shell.ts +36 -0
  472. package/src/utils/run-watcher-registry.ts +152 -0
  473. package/src/utils/safe-paths.ts +393 -0
  474. package/src/utils/scan-cache.ts +144 -0
  475. package/src/utils/session-utils.ts +110 -0
  476. package/src/utils/sleep.ts +54 -0
  477. package/src/utils/socket-path.ts +164 -0
  478. package/src/utils/sse-parser.ts +131 -0
  479. package/src/utils/task-name-generator.ts +337 -0
  480. package/src/utils/timings.ts +33 -0
  481. package/src/utils/token-counter.ts +200 -0
  482. package/src/utils/visual.ts +207 -0
  483. package/src/workflows/cost-estimator.ts +34 -0
  484. package/src/workflows/discover-workflows.ts +308 -0
  485. package/src/workflows/intermediate-store.ts +166 -0
  486. package/src/workflows/preflight-validator.ts +168 -0
  487. package/src/workflows/topology-analyzer.ts +203 -0
  488. package/src/workflows/validate-workflow.ts +50 -0
  489. package/src/workflows/workflow-config.ts +75 -0
  490. package/src/workflows/workflow-serializer.ts +32 -0
  491. package/src/worktree/branch-freshness.ts +112 -0
  492. package/src/worktree/cleanup.ts +341 -0
  493. package/src/worktree/worktree-manager.ts +1204 -0
@@ -0,0 +1,260 @@
1
+ import { loadConfig } from "../../config/config.ts";
2
+ import { applyAttentionState, formatActivityAge, resolveCrewControlConfig } from "../../runtime/agent-control.ts";
3
+ import { extractCommandTrace } from "../../runtime/command-trace.ts";
4
+ import { verifyTaskCompletion } from "../../runtime/completion-guard.ts";
5
+ import { readCrewAgents } from "../../runtime/crew-agent-records.ts";
6
+ import { evaluateRunEffectiveness } from "../../runtime/effectiveness.ts";
7
+ import { computePhaseProgress } from "../../runtime/phase-progress.ts";
8
+ import { checkProcessLiveness, isActiveRunStatus } from "../../runtime/process-status.ts";
9
+ import { formatTaskGraphLines, waitingReason } from "../../runtime/task-display.ts";
10
+ import type { TeamToolParamsValue } from "../../schema/team-tool-schema.ts";
11
+ import { appendEvent, readEvents } from "../../state/event-log.ts";
12
+ import { readDeliveryState, readMailbox } from "../../state/mailbox.ts";
13
+ import { loadRunManifestById, saveRunTasks, updateRunStatus } from "../../state/state-store.ts";
14
+ import { aggregateUsage, formatCost, formatUsage } from "../../state/usage.ts";
15
+ import { formatDuration } from "../../ui/format-helpers.ts";
16
+ import { locateRunCwd } from "../team-tool.ts";
17
+ import type { PiTeamsToolResult } from "../tool-result.ts";
18
+ import { result, type TeamContext } from "./context.ts";
19
+ import { RUN_NOT_FOUND_HINT } from "./run-not-found.ts";
20
+
21
+ export function handleStatus(params: TeamToolParamsValue, ctx: TeamContext): PiTeamsToolResult {
22
+ if (!params.runId) return result("Status requires runId.", { action: "status", status: "error" }, true);
23
+ const runCwd = locateRunCwd(params.runId, ctx.cwd);
24
+ if (!runCwd) return result(`Run '${params.runId}' not found.${RUN_NOT_FOUND_HINT}`, { action: "status", status: "error" }, true);
25
+ const loaded = loadRunManifestById(runCwd, params.runId); // NOTE: no withRunLock - best-effort only; concurrent writes may cause inconsistency
26
+ if (!loaded) return result(`Run '${params.runId}' not found.${RUN_NOT_FOUND_HINT}`, { action: "status", status: "error" }, true);
27
+ let { manifest, tasks } = loaded;
28
+ // DX (Round 16 F3): compact status mode. Default = full (backward compatible).
29
+ // details=false gives a tight summary (status, goal, counts, failed/attention
30
+ // errors) for quick checks without 40 lines of dense key=value noise.
31
+ const fullDetails = params.details !== false;
32
+ let asyncLivenessLine: string | undefined;
33
+ if (manifest.async) {
34
+ const asyncState = manifest.async;
35
+ const liveness = checkProcessLiveness(asyncState.pid);
36
+ asyncLivenessLine = `Async: pid=${asyncState.pid ?? "unknown"} alive=${liveness.alive ? "true" : "false"} detail=${liveness.detail} log=${asyncState.logPath} spawnedAt=${asyncState.spawnedAt}`;
37
+ if (!liveness.alive && isActiveRunStatus(manifest.status)) {
38
+ manifest = updateRunStatus(manifest, "failed", `Async process stale: ${liveness.detail}`);
39
+ tasks = tasks.map((task) =>
40
+ task.status === "running"
41
+ ? {
42
+ ...task,
43
+ status: "cancelled" as const,
44
+ finishedAt: new Date().toISOString(),
45
+ error: "Async process died; task was not completed.",
46
+ }
47
+ : task,
48
+ );
49
+ saveRunTasks(manifest, tasks);
50
+ appendEvent(manifest.eventsPath, {
51
+ type: "async.stale",
52
+ runId: manifest.runId,
53
+ message: liveness.detail,
54
+ data: { pid: asyncState.pid },
55
+ });
56
+ }
57
+ }
58
+ const counts = new Map<string, number>();
59
+ for (const task of tasks) counts.set(task.status, (counts.get(task.status) ?? 0) + 1);
60
+ const phaseProgress = computePhaseProgress(tasks);
61
+ const allEvents = readEvents(manifest.eventsPath);
62
+ const events = allEvents.slice(-8);
63
+ const attentionByTask = new Map(
64
+ allEvents.filter((event) => event.type === "task.attention" && event.taskId).map((event) => [event.taskId!, event]),
65
+ );
66
+ const controlConfig = resolveCrewControlConfig(loadConfig(ctx.cwd).config);
67
+ const crewAgents = readCrewAgents(manifest).map((agent) => applyAttentionState(manifest, agent, controlConfig));
68
+ const artifactLines = manifest.artifacts
69
+ .slice(-10)
70
+ .map(
71
+ (artifact) => `- ${artifact.kind}: ${artifact.path}${artifact.sizeBytes !== undefined ? ` (${artifact.sizeBytes} bytes)` : ""}`,
72
+ );
73
+ const deliveryState = readDeliveryState(manifest);
74
+ const ackTimeoutMs = loadConfig(ctx.cwd).config.runtime?.groupJoinAckTimeoutMs;
75
+ const groupJoinLines: string[] = [];
76
+ for (const message of readMailbox(manifest, "outbox")
77
+ .filter((m) => m.data?.kind === "group_join")
78
+ .slice(-5)) {
79
+ const ack = deliveryState.messages[message.id] === "acknowledged" ? "acknowledged" : "pending";
80
+ const ageMs = Date.now() - new Date(message.createdAt).getTime();
81
+ const requestId = String(message.data?.requestId ?? "unknown");
82
+ const timedOut = ack === "pending" && ackTimeoutMs !== undefined && Number.isFinite(ageMs) && ageMs > ackTimeoutMs;
83
+ if (timedOut && !allEvents.some((event) => event.type === "agent.group_join.ack_timeout" && event.data?.requestId === requestId)) {
84
+ appendEvent(manifest.eventsPath, {
85
+ type: "agent.group_join.ack_timeout",
86
+ runId: manifest.runId,
87
+ message: "Group join delivery ack timed out; mailbox delivery remains the fallback.",
88
+ data: {
89
+ requestId,
90
+ messageId: message.id,
91
+ batchId: message.data?.batchId,
92
+ partial: message.data?.partial,
93
+ ageMs,
94
+ ackTimeoutMs,
95
+ },
96
+ });
97
+ }
98
+ groupJoinLines.push(
99
+ `- ${String(message.data?.partial) === "true" ? "partial" : "completed"} request=${requestId} message=${message.id} ack=${timedOut ? "timeout" : ack}`,
100
+ );
101
+ }
102
+ const totalUsage = aggregateUsage(tasks);
103
+ const completedTasks = tasks.filter((task) => task.status === "completed");
104
+ const effectiveness = evaluateRunEffectiveness({
105
+ manifest,
106
+ tasks,
107
+ executeWorkers: manifest.runtimeResolution?.kind !== "scaffold",
108
+ runtimeConfig: loadConfig(ctx.cwd).config.runtime,
109
+ });
110
+ const noObservedWorkTasks = effectiveness.noObservedWorkTaskIds
111
+ .map((id) => tasks.find((task) => task.id === id))
112
+ .filter((task): task is (typeof tasks)[number] => task !== undefined);
113
+ const attentionTasks = effectiveness.needsAttentionTaskIds
114
+ .map((id) => tasks.find((task) => task.id === id))
115
+ .filter((task): task is (typeof tasks)[number] => task !== undefined);
116
+ const activeAgents = crewAgents.filter((agent) => agent.status === "running");
117
+ const completedAgents = crewAgents.filter((agent) => agent.status !== "running");
118
+ const waitingTasks = tasks.filter((task) => task.status === "queued" || task.status === "waiting");
119
+ const agentLine = (agent: (typeof crewAgents)[number]): string =>
120
+ `- ${agent.id} [${agent.status}] ${agent.role} -> ${agent.agent} runtime=${agent.runtime}${agent.model ? ` model=${agent.model}` : ""}${agent.usage ? ` usage=${formatUsage(agent.usage)}` : ""}${agent.usage?.cost ? ` cost=${formatCost(agent.usage.cost)}` : ""}${agent.progress?.activityState ? ` activityState=${agent.progress.activityState}` : ""}${formatActivityAge(agent) ? ` activity=${formatActivityAge(agent)}` : ""}${agent.progress?.currentTool ? ` tool=${agent.progress.currentTool}` : ""}${agent.toolUses ? ` tools=${agent.toolUses}` : ""}${!agent.usage && agent.progress?.tokens ? ` tokens=${agent.progress.tokens}` : ""}${agent.progress?.turns ? ` turns=${agent.progress.turns}` : ""}${agent.jsonEvents !== undefined ? ` jsonEvents=${agent.jsonEvents}` : ""}${agent.outputPath ? ` output=${agent.outputPath}` : ""}${agent.transcriptPath ? ` transcript=${agent.transcriptPath}` : ""}${agent.statusPath ? ` status=${agent.statusPath}` : ""}${agent.error ? ` error=${agent.error}` : ""}`;
121
+ const lines = [
122
+ `Run: ${manifest.runId}`,
123
+ `Team: ${manifest.team}`,
124
+ `Workflow: ${manifest.workflow ?? "(none)"}`,
125
+ `Status: ${manifest.status}`,
126
+ `Progress: ${phaseProgress.overallPercentage}% (~${formatDuration(phaseProgress.estimatedRemainingMs)} remaining)`,
127
+ `Workspace mode: ${manifest.workspaceMode}`,
128
+ ...(manifest.runtimeResolution
129
+ ? [
130
+ `Runtime: ${manifest.runtimeResolution.kind}`,
131
+ `Runtime safety: ${manifest.runtimeResolution.safety}`,
132
+ `Runtime requested: ${manifest.runtimeResolution.requestedMode}${manifest.runtimeResolution.reason ? ` (${manifest.runtimeResolution.reason})` : ""}`,
133
+ ]
134
+ : []),
135
+ `Goal: ${manifest.goal}`,
136
+ `Created: ${manifest.createdAt}`,
137
+ `Updated: ${manifest.updatedAt}`,
138
+ `State: ${manifest.stateRoot}`,
139
+ `Artifacts: ${manifest.artifactsRoot}`,
140
+ ...(asyncLivenessLine ? [asyncLivenessLine] : []),
141
+ "Task graph:",
142
+ ...formatTaskGraphLines(tasks),
143
+ "Tasks:",
144
+ ...(tasks.length
145
+ ? tasks.map(
146
+ (task) =>
147
+ `- ${task.id} [${task.status}] ${task.role} -> ${task.agent}${task.taskPacket ? ` scope=${task.taskPacket.scope}` : ""}${task.verification ? ` green=${task.verification.observedGreenLevel}/${task.verification.requiredGreenLevel}` : ""}${task.modelAttempts?.length ? ` attempts=${task.modelAttempts.length}` : ""}${task.modelRouting ? ` modelRouting=${task.modelRouting.requested ? `${task.modelRouting.requested}->` : ""}${task.modelRouting.resolved}${task.modelRouting.usedAttempt ? ` attempt=${task.modelRouting.usedAttempt + 1}` : ""}` : ""}${task.agentProgress?.activityState ? ` activityState=${task.agentProgress.activityState}` : ""}${(() => {
148
+ const t = extractCommandTrace(task.agentProgress?.recentTools);
149
+ return t.summary ? ` ${t.summary}` : "";
150
+ })()}${attentionByTask.get(task.id)?.data?.reason ? ` attention=${String(attentionByTask.get(task.id)?.data?.reason)}` : ""}${task.jsonEvents !== undefined ? ` jsonEvents=${task.jsonEvents}` : ""}${task.usage ? ` usage=${JSON.stringify(task.usage)}` : ""}${task.resultArtifact ? ` result=${task.resultArtifact.path}` : ""}${task.transcriptArtifact ? ` transcript=${task.transcriptArtifact.path}` : ""}${task.worktree ? ` worktree=${task.worktree.path}` : ""}${task.error ? ` error=${task.error}` : ""}`,
151
+ )
152
+ : ["- (none)"]),
153
+ `Task counts: ${[...counts.entries()].map(([status, count]) => `${status}=${count}`).join(", ") || "none"}`,
154
+ "Effectiveness:",
155
+ `- observable=${effectiveness.observable}/${Math.max(1, effectiveness.completed)} completed tasks`,
156
+ `- workerExecution=${effectiveness.workerExecution} guard=${effectiveness.guardMode} severity=${effectiveness.severity}`,
157
+ `- noObservedWork=${effectiveness.noObservedWorkTaskIds.length ? effectiveness.noObservedWorkTaskIds.join(",") : "none"}`,
158
+ `- needsAttention=${effectiveness.needsAttentionTaskIds.length ? effectiveness.needsAttentionTaskIds.join(",") : "none"}`,
159
+ "Completion verification",
160
+ ...(tasks.filter((t) => t.status === "completed").length
161
+ ? tasks
162
+ .filter((t) => t.status === "completed")
163
+ .map((t) => {
164
+ const guard = verifyTaskCompletion(t, manifest);
165
+ return `- ${t.id} green=${guard.greenLevel}/3${guard.warnings.length ? ` warnings=[${guard.warnings.join(", ")}]` : ""}`;
166
+ })
167
+ : ["- (no completed tasks)"]),
168
+ "Active agents:",
169
+ ...(activeAgents.length ? activeAgents.map(agentLine) : ["- (none)"]),
170
+ "Waiting tasks:",
171
+ ...(waitingTasks.length
172
+ ? waitingTasks.map((task) => `- ${task.id} [queued] ${task.role} -> ${task.agent} ${waitingReason(task, tasks) ?? "waiting"}`)
173
+ : ["- (none)"]),
174
+ "Completed agents:",
175
+ ...(completedAgents.length ? completedAgents.map(agentLine) : ["- (none)"]),
176
+ "Policy decisions:",
177
+ ...(manifest.policyDecisions?.length
178
+ ? manifest.policyDecisions.map(
179
+ (item) => `- ${item.action} (${item.reason})${item.taskId ? ` ${item.taskId}` : ""}: ${item.message}`,
180
+ )
181
+ : ["- (none)"]),
182
+ `Total usage: ${formatUsage(totalUsage)}`,
183
+ "Group joins:",
184
+ ...(groupJoinLines.length ? groupJoinLines : ["- (none)"]),
185
+ "",
186
+ "Recent artifacts:",
187
+ ...(artifactLines.length ? artifactLines : ["- (none)"]),
188
+ "",
189
+ "Recent events:",
190
+ ...(events.length
191
+ ? events.map(
192
+ (event) =>
193
+ `- ${event.time} ${event.type}${event.taskId ? ` ${event.taskId}` : ""}${event.message ? `: ${event.message}` : ""}`,
194
+ )
195
+ : ["- (none)"]),
196
+ ];
197
+ if (!fullDetails) {
198
+ return result(buildCompactStatus(manifest, tasks, counts, asyncLivenessLine, phaseProgress).join("\n"), {
199
+ action: "status",
200
+ status: "ok",
201
+ runId: manifest.runId,
202
+ artifactsRoot: manifest.artifactsRoot,
203
+ intent: `status ${manifest.runId}: ${manifest.status} (compact)`,
204
+ });
205
+ }
206
+ return result(lines.join("\n"), {
207
+ action: "status",
208
+ status: "ok",
209
+ runId: manifest.runId,
210
+ artifactsRoot: manifest.artifactsRoot,
211
+ intent: `status ${manifest.runId}: ${manifest.status}`,
212
+ });
213
+ }
214
+
215
+ /**
216
+ * Compact status builder (DX: Round 16 F3). A tight summary for quick checks:
217
+ * identity, status, goal, task counts, and ONLY failed / attention task
218
+ * errors — not the 40-line dense dump. Invoked when params.details === false.
219
+ *
220
+ * Exported for unit testing.
221
+ */
222
+ export function buildCompactStatus(
223
+ manifest: {
224
+ runId: string;
225
+ team: string;
226
+ workflow?: string;
227
+ status: string;
228
+ goal: string;
229
+ workspaceMode?: string;
230
+ },
231
+ tasks: Array<{
232
+ id: string;
233
+ status: string;
234
+ role: string;
235
+ agent: string;
236
+ error?: string;
237
+ }>,
238
+ counts: Map<string, number>,
239
+ asyncLivenessLine?: string,
240
+ progress?: { overallPercentage: number; estimatedRemainingMs: number },
241
+ ): string[] {
242
+ const failedOrAttention = tasks.filter((t) => t.status === "failed" || t.status === "needs_attention" || t.status === "cancelled");
243
+ const lines = [
244
+ `Run: ${manifest.runId}`,
245
+ `Team: ${manifest.team}${manifest.workflow ? ` (${manifest.workflow})` : ""}`,
246
+ `Status: ${manifest.status}`,
247
+ ...(progress ? [`Progress: ${progress.overallPercentage}% (~${formatDuration(progress.estimatedRemainingMs)} remaining)`] : []),
248
+ `Goal: ${manifest.goal}`,
249
+ ...(asyncLivenessLine ? [asyncLivenessLine] : []),
250
+ `Tasks: ${[...counts.entries()].map(([s, c]) => `${s}=${c}`).join(", ") || "none"}`,
251
+ ];
252
+ if (failedOrAttention.length > 0) {
253
+ lines.push("Issues:");
254
+ for (const t of failedOrAttention) {
255
+ lines.push(`- ${t.id} [${t.status}] ${t.role}: ${t.error ?? "(no error detail)"}`);
256
+ }
257
+ }
258
+ lines.push("Tip: pass details=true for full output (task graph, agents, effectiveness, events).");
259
+ return lines;
260
+ }
@@ -0,0 +1,261 @@
1
+ /**
2
+ * team-tool/workflow-manage.ts — Handlers for the 5 workflow-management actions (P3).
3
+ *
4
+ * Plan: 07-PLAN.md v3 P3 + §0c C3 (destructive-gate, NOT autonomous-policy) + C5 (paths).
5
+ *
6
+ * Actions:
7
+ * - workflow-create : write a .dwf.ts from params.config.script. SECURITY: gated by
8
+ * destructive-gate.ts (confirm:true required) + path-allowlist
9
+ * (resolveRealContainedPath) + content validation. NEVER auto-invoked
10
+ * by the agent (the gate enforces this).
11
+ * - workflow-get : return a workflow's source/metadata (read-only).
12
+ * - workflow-list : list all workflows incl. runtime discriminator (extends existing list).
13
+ * - workflow-save : persist an ephemeral script as a named reusable workflow.
14
+ * - workflow-delete : remove a dynamic workflow file (confirm-gated).
15
+ */
16
+
17
+ import { existsSync, readFileSync, rmSync, writeFileSync } from "node:fs";
18
+ import { dirname, join } from "node:path";
19
+ import type { TeamToolParamsValue } from "../../schema/team-tool-schema.ts";
20
+ import { logInternalError } from "../../utils/internal-error.ts";
21
+ import { packageRoot, projectCrewRoot, userPiRoot } from "../../utils/paths.ts";
22
+ import { assertSafePathId, resolveRealContainedPath } from "../../utils/safe-paths.ts";
23
+ import { allWorkflows, discoverWorkflows } from "../../workflows/discover-workflows.ts";
24
+ import { result, type TeamContext } from "./context.ts";
25
+
26
+ /** The 3 allowed bases for dynamic-workflow scripts (§0c C5). */
27
+ function allowedWorkflowDirs(cwd: string): string[] {
28
+ // Fix round-6: align with discoverWorkflows (which reads userPiRoot/workflows, NOT
29
+ // userCrewRoot/workflows). The old userCrewRoot path silently orphaned user-scope workflows.
30
+ return [join(projectCrewRoot(cwd), "workflows"), join(userPiRoot(), "workflows"), join(packageRoot(), "workflows")];
31
+ }
32
+
33
+ /** Best-effort ADVISORY content check (review H-3): trivially bypassable
34
+ * (require('child'+'_process'), globalThis.process.mainModule.require, dynamic import,
35
+ * String.fromCharCode, etc.). This is NOT a security boundary — it catches only
36
+ * the most obvious accidental violations. The real boundary is the path-allowlist
37
+ * + commit-review trust model. Do NOT rely on this for security. */
38
+ const FORBIDDEN_PATTERNS = [
39
+ /require\s*\(\s*['"]child_process['"]/,
40
+ /\bprocess\.exit\s*\(/,
41
+ /import\s+.*['"]net['"]/,
42
+ /import\s+.*['"]http['"]/,
43
+ /import\s+.*['"]https['"]/,
44
+ /eval\s*\(\s*new\s+Function/,
45
+ ];
46
+
47
+ function validateScriptContent(content: string): string | undefined {
48
+ for (const pattern of FORBIDDEN_PATTERNS) {
49
+ if (pattern.test(content)) {
50
+ return `Script content matches a forbidden pattern (${pattern.source}). Dynamic workflows must not spawn processes, exit, or make network calls directly — use ctx.agent().`;
51
+ }
52
+ }
53
+ return undefined;
54
+ }
55
+
56
+ /** Resolve a workflow name + scope to a safe write path inside an allowed dir. */
57
+ function resolveWorkflowWritePath(cwd: string, name: string, scope: "user" | "project" = "project"): string {
58
+ assertSafePathId("workflowName", name);
59
+ // Fix round-6: user scope must use userPiRoot/workflows (matches discovery), not userCrewRoot.
60
+ const base = scope === "user" ? join(userPiRoot(), "workflows") : join(projectCrewRoot(cwd), "workflows");
61
+ return resolveRealContainedPath(base, `${name}.dwf.ts`);
62
+ }
63
+
64
+ export function handleWorkflowCreate(params: TeamToolParamsValue, ctx: TeamContext): ReturnType<typeof result> {
65
+ // SECURITY (§0c C3): the destructive-gate.ts set enforces confirm:true BEFORE this handler
66
+ // runs (the run is blocked at the tool_call layer if confirm is missing). We re-check here
67
+ // as defense-in-depth in case the gate is bypassed.
68
+ if (params.confirm !== true) {
69
+ return result(
70
+ "workflow-create is a new arbitrary-code-execution surface and requires confirm:true. Add the action to DESTRUCTIVE_TEAM_ACTIONS (destructive-gate.ts) so the runtime gate enforces this.",
71
+ { action: "workflow-create", status: "error" },
72
+ true,
73
+ );
74
+ }
75
+ const name = params.config?.name as string | undefined;
76
+ const script = params.config?.script as string | undefined;
77
+ if (!name || typeof name !== "string") {
78
+ return result(
79
+ "workflow-create requires config.name (the workflow name, path-safe).",
80
+ { action: "workflow-create", status: "error" },
81
+ true,
82
+ );
83
+ }
84
+ if (!script || typeof script !== "string") {
85
+ return result("workflow-create requires config.script (the .dwf.ts source).", { action: "workflow-create", status: "error" }, true);
86
+ }
87
+ const validationError = validateScriptContent(script);
88
+ if (validationError) {
89
+ return result(`workflow-create rejected: ${validationError}`, { action: "workflow-create", status: "error" }, true);
90
+ }
91
+ try {
92
+ const scope = (params.scope === "user" ? "user" : "project") as "user" | "project";
93
+ const filePath = resolveWorkflowWritePath(ctx.cwd, name, scope);
94
+ writeFileSync(filePath, script, "utf-8");
95
+ return result(
96
+ `Dynamic workflow '${name}' created at ${filePath}.\n\nIt is now runnable via: team action='run' workflow='${name}' goal='...'\n/scripts are commit-reviewed (postinstall-equivalent trust — see docs/dynamic-workflows.md).`,
97
+ {
98
+ action: "workflow-create",
99
+ status: "ok",
100
+ data: { name, filePath, scope },
101
+ },
102
+ false,
103
+ );
104
+ } catch (error) {
105
+ const message = error instanceof Error ? error.message : String(error);
106
+ return result(`workflow-create failed: ${message}`, { action: "workflow-create", status: "error" }, true);
107
+ }
108
+ }
109
+
110
+ export function handleWorkflowGet(params: TeamToolParamsValue, ctx: TeamContext): ReturnType<typeof result> {
111
+ const name = (params.config?.name as string | undefined) ?? params.workflow;
112
+ if (!name) return result("workflow-get requires config.name or workflow.", { action: "workflow-get", status: "error" }, true);
113
+ const wf = allWorkflows(discoverWorkflows(ctx.cwd)).find((w) => w.name === name);
114
+ if (!wf) return result(`Workflow '${name}' not found.`, { action: "workflow-get", status: "error" }, true);
115
+ const isDynamic = wf.runtime === "dynamic";
116
+ let source = "(static workflow — no script source)";
117
+ if (isDynamic && wf.filePath && existsSync(wf.filePath)) {
118
+ try {
119
+ source = readFileSync(wf.filePath, "utf-8").slice(0, 8000);
120
+ } catch (error) {
121
+ logInternalError("workflow-manage.get", error, `filePath=${wf.filePath}`);
122
+ }
123
+ }
124
+ return result(
125
+ [
126
+ `Workflow: ${wf.name} [${isDynamic ? "dynamic" : "static"}]`,
127
+ ` description: ${wf.description}`,
128
+ ` source: ${wf.source}`,
129
+ ` filePath: ${wf.filePath}`,
130
+ isDynamic ? ` dynamicScript: ${wf.dynamicScript}` : ` steps: ${wf.steps.length}`,
131
+ "",
132
+ isDynamic ? "Script source:" : "",
133
+ isDynamic ? "```" : "",
134
+ isDynamic ? source : "",
135
+ isDynamic ? "```" : "",
136
+ ]
137
+ .filter(Boolean)
138
+ .join("\n"),
139
+ {
140
+ action: "workflow-get",
141
+ status: "ok",
142
+ data: {
143
+ name: wf.name,
144
+ runtime: wf.runtime ?? "static",
145
+ filePath: wf.filePath,
146
+ },
147
+ },
148
+ false,
149
+ );
150
+ }
151
+
152
+ export function handleWorkflowList(params: TeamToolParamsValue, ctx: TeamContext): ReturnType<typeof result> {
153
+ const workflows = allWorkflows(discoverWorkflows(ctx.cwd));
154
+ if (workflows.length === 0) return result("No workflows found.", { action: "workflow-list", status: "ok" }, false);
155
+ const lines = workflows.map((w) => {
156
+ const tag = w.runtime === "dynamic" ? "[dynamic]" : "[static] ";
157
+ const detail = w.runtime === "dynamic" ? (w.dynamicScript ?? w.filePath) : `${w.steps.length} steps`;
158
+ return ` ${tag} ${w.name.padEnd(20)} ${detail}`;
159
+ });
160
+ return result(
161
+ `Workflows (${workflows.length}):\n${lines.join("\n")}`,
162
+ {
163
+ action: "workflow-list",
164
+ status: "ok",
165
+ data: {
166
+ count: workflows.length,
167
+ workflows: workflows.map((w) => ({
168
+ name: w.name,
169
+ runtime: w.runtime ?? "static",
170
+ })),
171
+ },
172
+ },
173
+ false,
174
+ );
175
+ }
176
+
177
+ export function handleWorkflowSave(params: TeamToolParamsValue, ctx: TeamContext): ReturnType<typeof result> {
178
+ // H-1 (review): workflow-save writes an arbitrary .dwf.ts (ACE-equivalent) — gate it
179
+ // via destructive-gate.ts confirm:true (now in DESTRUCTIVE_TEAM_ACTIONS) + re-check here.
180
+ if (params.confirm !== true) {
181
+ return result(
182
+ "workflow-save writes an executable .dwf.ts and requires confirm:true (gated by destructive-gate.ts).",
183
+ { action: "workflow-save", status: "error" },
184
+ true,
185
+ );
186
+ }
187
+ // workflow-save: persist an ephemeral run's script as a named reusable workflow.
188
+ // Reads the source from config.script (the caller provides what to save).
189
+ const name = params.config?.name as string | undefined;
190
+ const script = params.config?.script as string | undefined;
191
+ if (!name || !script)
192
+ return result("workflow-save requires config.name + config.script.", { action: "workflow-save", status: "error" }, true);
193
+ const validationError = validateScriptContent(script);
194
+ if (validationError) return result(`workflow-save rejected: ${validationError}`, { action: "workflow-save", status: "error" }, true);
195
+ try {
196
+ const filePath = resolveWorkflowWritePath(ctx.cwd, name, "project");
197
+ writeFileSync(filePath, script, "utf-8");
198
+ return result(
199
+ `Saved dynamic workflow '${name}' → ${filePath}.`,
200
+ { action: "workflow-save", status: "ok", data: { name, filePath } },
201
+ false,
202
+ );
203
+ } catch (error) {
204
+ const message = error instanceof Error ? error.message : String(error);
205
+ return result(`workflow-save failed: ${message}`, { action: "workflow-save", status: "error" }, true);
206
+ }
207
+ }
208
+
209
+ export function handleWorkflowDelete(params: TeamToolParamsValue, ctx: TeamContext): ReturnType<typeof result> {
210
+ // workflow-delete is destructive (removes a file) — gated by destructive-gate.ts confirm:true.
211
+ if (params.confirm !== true) {
212
+ return result(
213
+ "workflow-delete requires confirm:true (gated by destructive-gate.ts).",
214
+ { action: "workflow-delete", status: "error" },
215
+ true,
216
+ );
217
+ }
218
+ const name = (params.config?.name as string | undefined) ?? params.workflow;
219
+ if (!name) return result("workflow-delete requires config.name.", { action: "workflow-delete", status: "error" }, true);
220
+ const wf = allWorkflows(discoverWorkflows(ctx.cwd)).find((w) => w.name === name);
221
+ if (!wf) return result(`Workflow '${name}' not found.`, { action: "workflow-delete", status: "error" }, true);
222
+ if (wf.runtime !== "dynamic")
223
+ return result(
224
+ `Workflow '${name}' is not a dynamic workflow (only .dwf.ts files can be deleted via this action).`,
225
+ { action: "workflow-delete", status: "error" },
226
+ true,
227
+ );
228
+ try {
229
+ assertSafePathId("workflowName", name);
230
+ // Verify the file is inside an allowed dir before deleting.
231
+ const allowed = allowedWorkflowDirs(ctx.cwd);
232
+ const contained = allowed.some((base) => {
233
+ try {
234
+ return resolveRealContainedPath(base, wf.filePath) === wf.filePath;
235
+ } catch {
236
+ return false;
237
+ }
238
+ });
239
+ if (!contained)
240
+ return result(
241
+ `Refusing to delete '${wf.filePath}': not inside an allowed workflows directory.`,
242
+ { action: "workflow-delete", status: "error" },
243
+ true,
244
+ );
245
+ rmSync(wf.filePath, { force: true });
246
+ return result(
247
+ `Deleted dynamic workflow '${name}' (${wf.filePath}).`,
248
+ {
249
+ action: "workflow-delete",
250
+ status: "ok",
251
+ data: { name, filePath: wf.filePath },
252
+ },
253
+ false,
254
+ );
255
+ } catch (error) {
256
+ const message = error instanceof Error ? error.message : String(error);
257
+ return result(`workflow-delete failed: ${message}`, { action: "workflow-delete", status: "error" }, true);
258
+ }
259
+ }
260
+
261
+ void dirname; // (import kept for future expansion; currently unused)
@@ -0,0 +1,26 @@
1
+ export interface TeamToolDetails {
2
+ action: string;
3
+ status: "ok" | "error" | "planned";
4
+ runId?: string;
5
+ artifactsRoot?: string;
6
+ abortedIds?: string[];
7
+ missingIds?: string[];
8
+ foreignIds?: string[];
9
+ intent?: string;
10
+ resumedIds?: string[];
11
+ retriedTaskIds?: string[];
12
+ mailboxIds?: string[];
13
+ /** Resource scope affected by the action (e.g. cleanup: "project"). */
14
+ scope?: string;
15
+ /** Run metrics for compact display in TUI tool result rendering. */
16
+ metrics?: {
17
+ taskCount?: number;
18
+ completedCount?: number;
19
+ totalTokens?: number;
20
+ totalCost?: number;
21
+ durationMs?: number;
22
+ consistencyScore?: number;
23
+ };
24
+ /** Structured data for programmatic consumption (e.g. TUI widgets). */
25
+ data?: Record<string, unknown>;
26
+ }