pi-crew 0.9.16 → 0.9.17

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 (432) hide show
  1. package/CHANGELOG.md +81 -0
  2. package/README.md +19 -0
  3. package/dist/build-meta.json +21790 -0
  4. package/dist/index.mjs +83070 -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/patterns/command-agent-skill.md +1 -1
  14. package/docs/skills/REFERENCE.md +0 -17
  15. package/docs//303/242mmaAAA/303/242 +357 -0
  16. package/index.bundle.ts +25 -0
  17. package/index.ts +95 -4
  18. package/package.json +15 -4
  19. package/skills/iterative-audit/SKILL.md +0 -1
  20. package/skills/widget-rendering/SKILL.md +17 -0
  21. package/src/adapters/claude-adapter.ts +1 -3
  22. package/src/adapters/export-util.ts +16 -16
  23. package/src/adapters/index.ts +5 -5
  24. package/src/agents/agent-config.ts +20 -14
  25. package/src/agents/agent-serializer.ts +1 -1
  26. package/src/agents/discover-agents.ts +83 -39
  27. package/src/benchmark/benchmark-runner.ts +51 -51
  28. package/src/benchmark/feedback-loop.ts +1 -1
  29. package/src/config/config.ts +166 -590
  30. package/src/config/defaults.ts +28 -2
  31. package/src/config/drift-detector.ts +11 -14
  32. package/src/config/markers.ts +201 -203
  33. package/src/config/resilient-parser.ts +14 -6
  34. package/src/config/role-tools.ts +3 -3
  35. package/src/config/suggestions.ts +5 -12
  36. package/src/config/types.ts +9 -25
  37. package/src/errors.ts +151 -157
  38. package/src/extension/action-suggestions.ts +54 -9
  39. package/src/extension/async-notifier.ts +43 -13
  40. package/src/extension/autonomous-policy.ts +77 -37
  41. package/src/extension/command-completions.ts +9 -8
  42. package/src/extension/context-status-injection.ts +14 -12
  43. package/src/extension/crew-autocomplete.ts +8 -16
  44. package/src/extension/crew-cleanup.ts +2 -1
  45. package/src/extension/crew-shortcuts.ts +9 -6
  46. package/src/extension/cross-extension-rpc.ts +136 -42
  47. package/src/extension/help.ts +1 -1
  48. package/src/extension/import-index.ts +10 -5
  49. package/src/extension/knowledge-injection.ts +88 -15
  50. package/src/extension/management.ts +89 -349
  51. package/src/extension/message-renderers.ts +3 -4
  52. package/src/extension/notification-router.ts +22 -5
  53. package/src/extension/notification-sink.ts +6 -3
  54. package/src/extension/pi-api.ts +17 -8
  55. package/src/extension/plan-orchestrate.ts +8 -27
  56. package/src/extension/project-init.ts +21 -6
  57. package/src/extension/register.ts +329 -975
  58. package/src/extension/registration/artifact-cleanup.ts +9 -4
  59. package/src/extension/registration/command-utils.ts +5 -1
  60. package/src/extension/registration/commands.ts +806 -314
  61. package/src/extension/registration/compaction-guard.ts +15 -15
  62. package/src/extension/registration/lifecycle.ts +259 -0
  63. package/src/extension/registration/observability.ts +293 -0
  64. package/src/extension/registration/subagent-helpers.ts +29 -7
  65. package/src/extension/registration/subagent-tools.ts +253 -44
  66. package/src/extension/registration/team-tool.ts +19 -84
  67. package/src/extension/registration/ui.ts +168 -0
  68. package/src/extension/registration/viewers.ts +64 -24
  69. package/src/extension/result-watcher.ts +18 -7
  70. package/src/extension/run-bundle-schema.ts +21 -6
  71. package/src/extension/run-export.ts +15 -6
  72. package/src/extension/run-import.ts +64 -29
  73. package/src/extension/run-index.ts +28 -9
  74. package/src/extension/run-maintenance.ts +32 -12
  75. package/src/extension/session-summary.ts +1 -1
  76. package/src/extension/team-manager-command.ts +64 -7
  77. package/src/extension/team-onboard.ts +151 -150
  78. package/src/extension/team-recommendation.ts +121 -21
  79. package/src/extension/team-tool/anchor.ts +31 -64
  80. package/src/extension/team-tool/api.ts +929 -141
  81. package/src/extension/team-tool/auto-summarize.ts +14 -26
  82. package/src/extension/team-tool/cache-control.ts +1 -5
  83. package/src/extension/team-tool/cancel.ts +138 -38
  84. package/src/extension/team-tool/chain-dispatch.ts +5 -13
  85. package/src/extension/team-tool/chain-executor.ts +29 -51
  86. package/src/extension/team-tool/config-patch.ts +1 -1
  87. package/src/extension/team-tool/context.ts +40 -20
  88. package/src/extension/team-tool/destructive-gate.ts +10 -5
  89. package/src/extension/team-tool/doctor.ts +170 -51
  90. package/src/extension/team-tool/explain.ts +228 -214
  91. package/src/extension/team-tool/failure-patterns.ts +3 -9
  92. package/src/extension/team-tool/goal-wrap.ts +71 -29
  93. package/src/extension/team-tool/goal.ts +185 -35
  94. package/src/extension/team-tool/handle-schedule.ts +34 -15
  95. package/src/extension/team-tool/handle-settings.ts +94 -56
  96. package/src/extension/team-tool/health-monitor.ts +27 -108
  97. package/src/extension/team-tool/inspect.ts +42 -9
  98. package/src/extension/team-tool/intent-policy.ts +4 -1
  99. package/src/extension/team-tool/lifecycle-actions.ts +244 -48
  100. package/src/extension/team-tool/orchestrate.ts +7 -18
  101. package/src/extension/team-tool/parallel-dispatch.ts +51 -29
  102. package/src/extension/team-tool/plan.ts +29 -5
  103. package/src/extension/team-tool/respond.ts +49 -16
  104. package/src/extension/team-tool/run-not-found.ts +3 -8
  105. package/src/extension/team-tool/run.ts +80 -317
  106. package/src/extension/team-tool/status.ts +135 -43
  107. package/src/extension/team-tool/workflow-manage.ts +92 -25
  108. package/src/extension/team-tool-types.ts +8 -1
  109. package/src/extension/team-tool.ts +142 -551
  110. package/src/extension/validate-resources.ts +39 -8
  111. package/src/hooks/registry.ts +66 -17
  112. package/src/hooks/types.ts +1 -1
  113. package/src/i18n.ts +25 -11
  114. package/src/observability/correlation.ts +17 -3
  115. package/src/observability/event-bus.ts +51 -56
  116. package/src/observability/event-to-metric.ts +117 -15
  117. package/src/observability/exporters/otlp-exporter.ts +56 -17
  118. package/src/observability/exporters/prometheus-exporter.ts +1 -1
  119. package/src/observability/metric-registry.ts +16 -4
  120. package/src/observability/metric-retention.ts +8 -2
  121. package/src/observability/metric-sink.ts +11 -3
  122. package/src/observability/metrics-primitives.ts +42 -9
  123. package/src/plugins/plugin-define.ts +2 -2
  124. package/src/plugins/plugin-registry.ts +25 -25
  125. package/src/plugins/plugins/index.ts +1 -1
  126. package/src/plugins/plugins/nextjs.ts +16 -16
  127. package/src/plugins/plugins/vite.ts +7 -11
  128. package/src/plugins/plugins/vitest.ts +6 -11
  129. package/src/runtime/adaptive-plan.ts +225 -40
  130. package/src/runtime/agent-control.ts +58 -15
  131. package/src/runtime/agent-memory.ts +15 -9
  132. package/src/runtime/agent-observability.ts +10 -2
  133. package/src/runtime/anchor-manager.ts +27 -25
  134. package/src/runtime/async-marker.ts +7 -1
  135. package/src/runtime/async-runner.ts +27 -23
  136. package/src/runtime/auto-summarize.ts +7 -13
  137. package/src/runtime/background-runner.ts +189 -251
  138. package/src/runtime/batch-barrier.ts +18 -16
  139. package/src/runtime/cancellation-token.ts +16 -6
  140. package/src/runtime/cancellation.ts +46 -8
  141. package/src/runtime/capability-inventory.ts +6 -4
  142. package/src/runtime/chain-parser.ts +44 -11
  143. package/src/runtime/chain-runner.ts +63 -69
  144. package/src/runtime/checkpoint.ts +12 -56
  145. package/src/runtime/child-pi.ts +343 -78
  146. package/src/runtime/coalesce-tasks.ts +268 -0
  147. package/src/runtime/code-summary.ts +71 -26
  148. package/src/runtime/compact-stages/index.ts +15 -5
  149. package/src/runtime/compact-stages/tail-capture-stage.ts +7 -2
  150. package/src/runtime/compact-stages/truncation-stage.ts +4 -1
  151. package/src/runtime/compaction-summary.ts +17 -10
  152. package/src/runtime/completion-guard.ts +33 -16
  153. package/src/runtime/crash-classification.ts +28 -7
  154. package/src/runtime/crash-recovery.ts +177 -37
  155. package/src/runtime/crew-agent-records.ts +145 -47
  156. package/src/runtime/crew-hooks.ts +9 -24
  157. package/src/runtime/cross-extension-rpc.ts +25 -23
  158. package/src/runtime/custom-tools/irc-tool.ts +43 -15
  159. package/src/runtime/custom-tools/submit-result-tool.ts +16 -5
  160. package/src/runtime/delivery-coordinator.ts +34 -7
  161. package/src/runtime/delta-conflict.ts +9 -21
  162. package/src/runtime/deterministic-ast.ts +1 -1
  163. package/src/runtime/diagnostic-export.ts +53 -20
  164. package/src/runtime/direct-run.ts +12 -2
  165. package/src/runtime/dwf-state-store.ts +1 -1
  166. package/src/runtime/dynamic-workflow-context.ts +186 -58
  167. package/src/runtime/dynamic-workflow-runner.ts +42 -20
  168. package/src/runtime/effectiveness.ts +16 -8
  169. package/src/runtime/errors/crew-errors.ts +7 -11
  170. package/src/runtime/event-stream-bridge.ts +9 -3
  171. package/src/runtime/foreground-control.ts +54 -14
  172. package/src/runtime/foreground-watchdog.ts +9 -6
  173. package/src/runtime/goal-achievement.ts +27 -10
  174. package/src/runtime/goal-evaluator.ts +54 -19
  175. package/src/runtime/goal-loop-runner.ts +280 -99
  176. package/src/runtime/goal-state-store.ts +27 -17
  177. package/src/runtime/green-contract.ts +11 -2
  178. package/src/runtime/group-join.ts +64 -31
  179. package/src/runtime/handoff-manager.ts +37 -42
  180. package/src/runtime/heartbeat-gradient.ts +10 -2
  181. package/src/runtime/heartbeat-watcher.ts +32 -6
  182. package/src/runtime/hidden-handoff.ts +12 -30
  183. package/src/runtime/important-line-classifier.ts +12 -2
  184. package/src/runtime/iteration-hooks.ts +25 -15
  185. package/src/runtime/live-agent-control.ts +55 -7
  186. package/src/runtime/live-agent-manager.ts +130 -27
  187. package/src/runtime/live-control-realtime.ts +23 -3
  188. package/src/runtime/live-irc.ts +4 -1
  189. package/src/runtime/live-session-health.ts +12 -4
  190. package/src/runtime/live-session-runtime.ts +379 -117
  191. package/src/runtime/manifest-cache.ts +28 -12
  192. package/src/runtime/mcp-proxy.ts +8 -16
  193. package/src/runtime/metric-parser.ts +1 -5
  194. package/src/runtime/model-fallback.ts +55 -18
  195. package/src/runtime/model-resolver.ts +2 -6
  196. package/src/runtime/model-scope.ts +19 -3
  197. package/src/runtime/notebook-helpers.ts +60 -62
  198. package/src/runtime/orphan-worker-registry.ts +37 -26
  199. package/src/runtime/output-validator.ts +18 -3
  200. package/src/runtime/overflow-recovery.ts +5 -4
  201. package/src/runtime/parallel-research.ts +29 -5
  202. package/src/runtime/parallel-utils.ts +9 -11
  203. package/src/runtime/path-overlap.ts +150 -0
  204. package/src/runtime/peer-dep.ts +12 -17
  205. package/src/runtime/per-write-validator.ts +1 -3
  206. package/src/runtime/phase-tracker.ts +342 -330
  207. package/src/runtime/pi-args.ts +26 -8
  208. package/src/runtime/pi-json-output.ts +1 -1
  209. package/src/runtime/pi-spawn.ts +30 -19
  210. package/src/runtime/pipeline-runner.ts +56 -55
  211. package/src/runtime/plan-templates.ts +5 -6
  212. package/src/runtime/policy-engine.ts +43 -7
  213. package/src/runtime/post-checks.ts +12 -4
  214. package/src/runtime/post-exit-stdio-guard.ts +2 -2
  215. package/src/runtime/process-lifecycle.ts +20 -10
  216. package/src/runtime/process-status.ts +16 -5
  217. package/src/runtime/progress-event-coalescer.ts +2 -1
  218. package/src/runtime/progress-tracker.ts +103 -103
  219. package/src/runtime/prose-compressor.ts +9 -11
  220. package/src/runtime/recovery-recipes.ts +118 -24
  221. package/src/runtime/replace.ts +25 -10
  222. package/src/runtime/resilient-edit.ts +10 -25
  223. package/src/runtime/result-extractor.ts +1 -2
  224. package/src/runtime/retry-executor.ts +20 -4
  225. package/src/runtime/retry-runner.ts +26 -50
  226. package/src/runtime/role-permission.ts +6 -1
  227. package/src/runtime/run-coalesced-task-group.ts +256 -0
  228. package/src/runtime/run-drift.ts +14 -15
  229. package/src/runtime/run-tracker.ts +6 -28
  230. package/src/runtime/runtime-policy.ts +1 -6
  231. package/src/runtime/runtime-resolver.ts +80 -15
  232. package/src/runtime/scheduler.ts +47 -18
  233. package/src/runtime/semaphore.ts +5 -7
  234. package/src/runtime/sensitive-paths.ts +2 -1
  235. package/src/runtime/session-usage.ts +1 -1
  236. package/src/runtime/settings-store.ts +16 -12
  237. package/src/runtime/sidechain-output.ts +6 -2
  238. package/src/runtime/single-agent-compose.ts +1 -4
  239. package/src/runtime/skill-effectiveness.ts +29 -97
  240. package/src/runtime/skill-instructions.ts +40 -83
  241. package/src/runtime/stale-reconciler.ts +73 -197
  242. package/src/runtime/stream-preview.ts +1 -1
  243. package/src/runtime/streaming-output.ts +1 -1
  244. package/src/runtime/subagent-manager.ts +44 -169
  245. package/src/runtime/subprocess-tool-registry.ts +4 -1
  246. package/src/runtime/supervisor-contact.ts +10 -5
  247. package/src/runtime/task-display.ts +19 -5
  248. package/src/runtime/task-graph-scheduler.ts +95 -21
  249. package/src/runtime/task-graph.ts +5 -11
  250. package/src/runtime/task-health.ts +54 -47
  251. package/src/runtime/task-id.ts +11 -18
  252. package/src/runtime/task-output-context.ts +265 -81
  253. package/src/runtime/task-packet.ts +12 -20
  254. package/src/runtime/task-quality.ts +6 -14
  255. package/src/runtime/task-runner/context-retrieval.ts +4 -13
  256. package/src/runtime/task-runner/live-executor.ts +114 -36
  257. package/src/runtime/task-runner/output-splitter.ts +152 -0
  258. package/src/runtime/task-runner/progress.ts +50 -12
  259. package/src/runtime/task-runner/prompt-builder.ts +31 -7
  260. package/src/runtime/task-runner/prompt-pipeline.ts +31 -7
  261. package/src/runtime/task-runner/result-utils.ts +3 -1
  262. package/src/runtime/task-runner/retrieval-orchestrator.ts +310 -0
  263. package/src/runtime/task-runner/run-projection.ts +27 -8
  264. package/src/runtime/task-runner/state-helpers.ts +29 -8
  265. package/src/runtime/task-runner/tail-read.ts +2 -6
  266. package/src/runtime/task-runner.ts +180 -326
  267. package/src/runtime/team-runner-artifacts.ts +13 -0
  268. package/src/runtime/team-runner.ts +456 -974
  269. package/src/runtime/tool-output-pruner.ts +6 -9
  270. package/src/runtime/tool-progress.ts +11 -21
  271. package/src/runtime/verification-gates.ts +33 -24
  272. package/src/runtime/verification-integrity.ts +1 -4
  273. package/src/runtime/verification-worktree.ts +62 -12
  274. package/src/runtime/worker-heartbeat.ts +5 -1
  275. package/src/runtime/worker-startup.ts +29 -5
  276. package/src/runtime/workflow-state.ts +17 -9
  277. package/src/runtime/workspace-lock.ts +30 -35
  278. package/src/runtime/workspace-tree.ts +20 -32
  279. package/src/runtime/yield-handler.ts +43 -9
  280. package/src/runtime/zombie-scanner.ts +5 -4
  281. package/src/schema/config-schema.ts +266 -172
  282. package/src/schema/team-tool-schema.ts +29 -74
  283. package/src/schema/validation-types.ts +25 -17
  284. package/src/skills/discover-skills.ts +35 -10
  285. package/src/skills/skill-templates.ts +109 -27
  286. package/src/skills/validate.ts +26 -8
  287. package/src/state/active-run-registry.ts +87 -28
  288. package/src/state/artifact-store.ts +9 -5
  289. package/src/state/atomic-write-v2.ts +85 -63
  290. package/src/state/atomic-write.ts +105 -26
  291. package/src/state/blob-store.ts +47 -20
  292. package/src/state/contracts.ts +20 -5
  293. package/src/state/crew-init.ts +5 -22
  294. package/src/state/decision-ledger.ts +19 -73
  295. package/src/state/event-log-rotation.ts +41 -15
  296. package/src/state/event-log.ts +168 -53
  297. package/src/state/event-reconstructor.ts +11 -1
  298. package/src/state/gitignore-manager.ts +2 -8
  299. package/src/state/health-store.ts +57 -57
  300. package/src/state/hook-instinct-bridge.ts +1 -1
  301. package/src/state/hook-integrations.ts +1 -1
  302. package/src/state/instinct-store.ts +17 -5
  303. package/src/state/jsonl-writer.ts +1 -1
  304. package/src/state/locks.ts +23 -9
  305. package/src/state/mailbox.ts +151 -28
  306. package/src/state/observation-store.ts +20 -14
  307. package/src/state/run-cache.ts +142 -135
  308. package/src/state/run-graph.ts +6 -15
  309. package/src/state/run-metrics.ts +5 -18
  310. package/src/state/schedule.ts +15 -9
  311. package/src/state/state-store.ts +129 -45
  312. package/src/state/task-claims.ts +12 -2
  313. package/src/state/tiered-eval.ts +52 -43
  314. package/src/state/types-eval.ts +2 -2
  315. package/src/state/types.ts +24 -20
  316. package/src/state/usage.ts +20 -4
  317. package/src/state/worker-atomic-writer.ts +6 -3
  318. package/src/subagents/index.ts +2 -2
  319. package/src/teams/discover-teams.ts +21 -6
  320. package/src/tools/safe-bash-extension.ts +5 -6
  321. package/src/tools/safe-bash.ts +10 -11
  322. package/src/types/new-api-types.ts +6 -10
  323. package/src/ui/agent-management-overlay.ts +52 -40
  324. package/src/ui/card-colors.ts +13 -4
  325. package/src/ui/crew-footer.ts +8 -7
  326. package/src/ui/crew-select-list.ts +1 -1
  327. package/src/ui/dashboard-panes/agents-pane.ts +41 -25
  328. package/src/ui/dashboard-panes/cancellation-pane.ts +1 -1
  329. package/src/ui/dashboard-panes/capability-pane.ts +32 -15
  330. package/src/ui/dashboard-panes/health-pane.ts +2 -1
  331. package/src/ui/dashboard-panes/metrics-pane.ts +4 -1
  332. package/src/ui/dashboard-panes/progress-pane.ts +12 -9
  333. package/src/ui/heartbeat-aggregator.ts +15 -4
  334. package/src/ui/keybinding-map.ts +40 -7
  335. package/src/ui/live-conversation-overlay.ts +36 -20
  336. package/src/ui/live-duration.ts +1 -4
  337. package/src/ui/live-run-sidebar.ts +88 -25
  338. package/src/ui/loaders.ts +2 -8
  339. package/src/ui/mascot.ts +20 -36
  340. package/src/ui/overlays/agent-picker-overlay.ts +11 -3
  341. package/src/ui/overlays/confirm-overlay.ts +4 -2
  342. package/src/ui/overlays/help-overlay.ts +25 -14
  343. package/src/ui/overlays/mailbox-compose-overlay.ts +48 -11
  344. package/src/ui/overlays/mailbox-compose-preview.ts +20 -5
  345. package/src/ui/overlays/mailbox-detail-overlay.ts +27 -6
  346. package/src/ui/pi-ui-compat.ts +7 -7
  347. package/src/ui/powerbar-publisher.ts +120 -42
  348. package/src/ui/render-diff.ts +10 -3
  349. package/src/ui/render-scheduler.ts +12 -4
  350. package/src/ui/run-action-dispatcher.ts +81 -18
  351. package/src/ui/run-dashboard.ts +172 -76
  352. package/src/ui/run-event-bus.ts +59 -37
  353. package/src/ui/run-snapshot-cache.ts +276 -86
  354. package/src/ui/settings-overlay.ts +361 -74
  355. package/src/ui/status-colors.ts +12 -1
  356. package/src/ui/syntax-highlight.ts +1 -1
  357. package/src/ui/theme-adapter.ts +16 -14
  358. package/src/ui/theme-discovery.ts +13 -2
  359. package/src/ui/tool-progress-formatter.ts +7 -7
  360. package/src/ui/tool-render.ts +128 -56
  361. package/src/ui/tool-renderers/brief-mode.ts +45 -27
  362. package/src/ui/tool-renderers/index.ts +109 -43
  363. package/src/ui/transcript-cache.ts +32 -6
  364. package/src/ui/transcript-entries.ts +25 -23
  365. package/src/ui/transcript-viewer.ts +78 -29
  366. package/src/ui/widget/index.ts +99 -40
  367. package/src/ui/widget/widget-formatters.ts +13 -6
  368. package/src/ui/widget/widget-model.ts +19 -8
  369. package/src/ui/widget/widget-renderer.ts +23 -13
  370. package/src/ui/widget/widget-types.ts +1 -1
  371. package/src/utils/bm25-search.ts +199 -199
  372. package/src/utils/conflict-detect.ts +22 -21
  373. package/src/utils/env-filter.ts +14 -7
  374. package/src/utils/file-coalescer.ts +5 -1
  375. package/src/utils/fingerprint.ts +3 -6
  376. package/src/utils/frontmatter.ts +3 -1
  377. package/src/utils/fs-watch.ts +2 -6
  378. package/src/utils/gh-protocol.ts +119 -44
  379. package/src/utils/git.ts +13 -15
  380. package/src/utils/guards.ts +2 -5
  381. package/src/utils/ids.ts +9 -2
  382. package/src/utils/incremental-reader.ts +14 -3
  383. package/src/utils/internal-error.ts +2 -1
  384. package/src/utils/names.ts +12 -3
  385. package/src/utils/paths.ts +49 -5
  386. package/src/utils/project-detector.ts +2 -2
  387. package/src/utils/redaction.ts +29 -19
  388. package/src/utils/resolve-shell.ts +9 -7
  389. package/src/utils/run-watcher-registry.ts +19 -31
  390. package/src/utils/safe-paths.ts +45 -24
  391. package/src/utils/scan-cache.ts +9 -2
  392. package/src/utils/session-utils.ts +2 -4
  393. package/src/utils/sleep.ts +12 -5
  394. package/src/utils/sse-parser.ts +5 -17
  395. package/src/utils/visual.ts +52 -32
  396. package/src/workflows/discover-workflows.ts +41 -109
  397. package/src/workflows/intermediate-store.ts +5 -21
  398. package/src/workflows/preflight-validator.ts +6 -33
  399. package/src/workflows/topology-analyzer.ts +5 -21
  400. package/src/workflows/workflow-config.ts +7 -6
  401. package/src/worktree/branch-freshness.ts +66 -8
  402. package/src/worktree/cleanup.ts +130 -20
  403. package/src/worktree/worktree-manager.ts +212 -69
  404. package/skills/artifact-analysis-loop/SKILL.md +0 -303
  405. package/skills/detection-pipeline-design/SKILL.md +0 -286
  406. package/skills/hunting-investigation-loop/SKILL.md +0 -402
  407. package/skills/incident-playbook-construction/SKILL.md +0 -384
  408. package/skills/security-review/SKILL.md +0 -561
  409. package/skills/threat-hypothesis-framework/SKILL.md +0 -176
  410. package/skills/ui-render-performance/SKILL.md +0 -58
  411. /package/docs/{followup-review-round3-2026-05-12.md → archive/followup-review-round3-2026-05-12.md} +0 -0
  412. /package/docs/{followup-review-round4-2026-05-13.md → archive/followup-review-round4-2026-05-13.md} +0 -0
  413. /package/docs/{pi-crew-bugs.md → archive/pi-crew-bugs.md} +0 -0
  414. /package/docs/{pi-crew-test-final.md → archive/pi-crew-test-final.md} +0 -0
  415. /package/docs/{pi-crew-test-results.md → archive/pi-crew-test-results.md} +0 -0
  416. /package/docs/{pi-crew-test-round2.md → archive/pi-crew-test-round2.md} +0 -0
  417. /package/docs/{pi-crew-test-round4.md → archive/pi-crew-test-round4.md} +0 -0
  418. /package/docs/{pi-crew-test-round5.md → archive/pi-crew-test-round5.md} +0 -0
  419. /package/docs/{pi-crew-test-round6.md → archive/pi-crew-test-round6.md} +0 -0
  420. /package/docs/{pi-crew-v0.5.10-audit-fix-plan.md → archive/pi-crew-v0.5.10-audit-fix-plan.md} +0 -0
  421. /package/docs/{pi-crew-v0.5.11-audit-fix-plan.md → archive/pi-crew-v0.5.11-audit-fix-plan.md} +0 -0
  422. /package/docs/{pi-crew-v0.5.12-audit-fix-plan.md → archive/pi-crew-v0.5.12-audit-fix-plan.md} +0 -0
  423. /package/docs/{pi-crew-v0.5.13-audit-fix-plan.md → archive/pi-crew-v0.5.13-audit-fix-plan.md} +0 -0
  424. /package/docs/{pi-crew-v0.5.14-audit-fix-plan.md → archive/pi-crew-v0.5.14-audit-fix-plan.md} +0 -0
  425. /package/docs/{pi-crew-v0.5.16-audit-fix-plan.md → archive/pi-crew-v0.5.16-audit-fix-plan.md} +0 -0
  426. /package/docs/{pi-crew-v0.5.17-audit-fix-plan.md → archive/pi-crew-v0.5.17-audit-fix-plan.md} +0 -0
  427. /package/docs/{pi-crew-v0.5.5-audit-fix-plan.md → archive/pi-crew-v0.5.5-audit-fix-plan.md} +0 -0
  428. /package/docs/{pi-crew-v0.5.9-audit-fix-plan.md → archive/pi-crew-v0.5.9-audit-fix-plan.md} +0 -0
  429. /package/docs/{pi-mono-opportunities.md → archive/pi-mono-opportunities.md} +0 -0
  430. /package/docs/{pi-mono-review.md → archive/pi-mono-review.md} +0 -0
  431. /package/docs/{pi-subagent4-comparison.md → archive/pi-subagent4-comparison.md} +0 -0
  432. /package/docs/{pi-subagents3-deep-analysis.md → archive/pi-subagents3-deep-analysis.md} +0 -0
@@ -1,17 +1,10 @@
1
1
  import { statSync } from "node:fs";
2
- import type {
3
- ExtensionAPI,
4
- ExtensionContext,
5
- ToolDefinition,
6
- } from "@earendil-works/pi-coding-agent";
2
+ import type { ExtensionAPI, ExtensionContext, ToolDefinition } from "@earendil-works/pi-coding-agent";
7
3
  import { Text } from "@earendil-works/pi-tui";
8
4
  import { loadConfig } from "../../config/config.ts";
9
5
  import type { MetricRegistry } from "../../observability/metric-registry.ts";
10
6
  import type { createManifestCache } from "../../runtime/manifest-cache.ts";
11
- import {
12
- TeamToolParams,
13
- type TeamToolParamsValue,
14
- } from "../../schema/team-tool-schema.ts";
7
+ import { TeamToolParams, type TeamToolParamsValue } from "../../schema/team-tool-schema.ts";
15
8
  import { updatePiCrewPowerbar } from "../../ui/powerbar-publisher.ts";
16
9
  import type { createRunSnapshotCache } from "../../ui/run-snapshot-cache.ts";
17
10
  import { statusIcon, teamToolRenderer } from "../../ui/tool-renderers/index.ts";
@@ -47,17 +40,11 @@ type OnUpdate = (chunk: { content: { type: "text"; text: string }[] }) => void;
47
40
 
48
41
  export interface RegisterTeamToolDeps {
49
42
  foregroundControllers: Map<string | symbol, AbortController>;
50
- startForegroundRun: (
51
- ctx: ExtensionContext,
52
- runner: (signal?: AbortSignal) => Promise<void>,
53
- runId?: string,
54
- ) => void;
43
+ startForegroundRun: (ctx: ExtensionContext, runner: (signal?: AbortSignal) => Promise<void>, runId?: string) => void;
55
44
  abortForegroundRun: (runId: string) => boolean;
56
45
  openLiveSidebar: (ctx: ExtensionContext, runId: string) => void;
57
46
  getManifestCache: (cwd: string) => ReturnType<typeof createManifestCache>;
58
- getRunSnapshotCache?: (
59
- cwd: string,
60
- ) => ReturnType<typeof createRunSnapshotCache>;
47
+ getRunSnapshotCache?: (cwd: string) => ReturnType<typeof createRunSnapshotCache>;
61
48
  getMetricRegistry?: () => MetricRegistry | undefined;
62
49
  widgetState: CrewWidgetState;
63
50
  onJsonEvent?: (taskId: string, runId: string, event: unknown) => void;
@@ -83,10 +70,7 @@ export function resolveCwdOverride(
83
70
  }
84
71
  }
85
72
 
86
- export function registerTeamTool(
87
- pi: ExtensionAPI,
88
- deps: RegisterTeamToolDeps,
89
- ): void {
73
+ export function registerTeamTool(pi: ExtensionAPI, deps: RegisterTeamToolDeps): void {
90
74
  const tool: ToolDefinition = {
91
75
  name: "team",
92
76
  label: "Team",
@@ -112,37 +96,22 @@ export function registerTeamTool(
112
96
  deps.foregroundControllers.set(toolKey, controller);
113
97
  const abort = (): void => controller.abort();
114
98
  signal?.addEventListener("abort", abort, { once: true });
115
- const stopProgress = startTeamToolProgressBinder(
116
- onUpdate as OnUpdate | undefined,
117
- );
99
+ const stopProgress = startTeamToolProgressBinder(onUpdate as OnUpdate | undefined);
118
100
  try {
119
101
  const resolved = params as TeamToolParamsValue;
120
102
  const cwdOverride = resolveCwdOverride(ctx.cwd, resolved.cwd);
121
- if (!cwdOverride.ok)
122
- return toolResult(
123
- cwdOverride.error,
124
- { action: resolved.action ?? "list", status: "error" },
125
- true,
126
- );
103
+ if (!cwdOverride.ok) return toolResult(cwdOverride.error, { action: resolved.action ?? "list", status: "error" }, true);
127
104
  const toolCtx = withSessionId({ ...ctx, cwd: cwdOverride.cwd });
128
105
  // Phase 1.5: Auto-set session name from team run context
129
- if (
130
- resolved.action === "run" &&
131
- resolved.goal &&
132
- !pi.getSessionName()
133
- ) {
134
- const runLabel =
135
- resolved.team ?? resolved.agent ?? "direct";
136
- pi.setSessionName(
137
- `pi-crew: ${runLabel}/${resolved.workflow ?? "default"} — ${resolved.goal.slice(0, 60)}`,
138
- );
106
+ if (resolved.action === "run" && resolved.goal && !pi.getSessionName()) {
107
+ const runLabel = resolved.team ?? resolved.agent ?? "direct";
108
+ pi.setSessionName(`pi-crew: ${runLabel}/${resolved.workflow ?? "default"} — ${resolved.goal.slice(0, 60)}`);
139
109
  }
140
110
  const output = await handleTeamTool(resolved, {
141
111
  ...toolCtx,
142
112
  signal: controller.signal,
143
113
  metricRegistry: deps.getMetricRegistry?.(),
144
- startForegroundRun: (runner, runId) =>
145
- deps.startForegroundRun(toolCtx, runner, runId),
114
+ startForegroundRun: (runner, runId) => deps.startForegroundRun(toolCtx, runner, runId),
146
115
  abortForegroundRun: deps.abortForegroundRun,
147
116
  onRunStarted: (runId) => {
148
117
  stopProgress.attach(toolCtx.cwd, runId);
@@ -151,11 +120,7 @@ export function registerTeamTool(
151
120
  onJsonEvent: deps.onJsonEvent,
152
121
  getRunSnapshotCache: deps.getRunSnapshotCache,
153
122
  });
154
- if (
155
- resolved.action === "run" &&
156
- !output.isError &&
157
- typeof output.details?.runId === "string"
158
- ) {
123
+ if (resolved.action === "run" && !output.isError && typeof output.details?.runId === "string") {
159
124
  pi.appendEntry("crew:run-started", {
160
125
  runId: output.details.runId,
161
126
  team: resolved.team,
@@ -169,21 +134,8 @@ export function registerTeamTool(
169
134
  const config = loadConfig(toolCtx.cwd).config.ui;
170
135
  const cache = deps.getManifestCache(toolCtx.cwd);
171
136
  const snapshotCache = deps.getRunSnapshotCache?.(toolCtx.cwd);
172
- updateCrewWidget(
173
- toolCtx,
174
- deps.widgetState,
175
- config,
176
- cache,
177
- snapshotCache,
178
- );
179
- updatePiCrewPowerbar(
180
- pi.events,
181
- toolCtx.cwd,
182
- config,
183
- cache,
184
- snapshotCache,
185
- toolCtx,
186
- );
137
+ updateCrewWidget(toolCtx, deps.widgetState, config, cache, snapshotCache);
138
+ updatePiCrewPowerbar(pi.events, toolCtx.cwd, config, cache, snapshotCache, toolCtx);
187
139
  return output;
188
140
  } finally {
189
141
  signal?.removeEventListener("abort", abort);
@@ -198,12 +150,7 @@ export function registerTeamTool(
198
150
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
199
151
  renderResult(result: any, options: any, theme: any, context: any): any {
200
152
  try {
201
- return teamToolRenderer.renderResult(
202
- result,
203
- options,
204
- theme,
205
- context,
206
- );
153
+ return teamToolRenderer.renderResult(result, options, theme, context);
207
154
  } catch {
208
155
  return new Text(statusIcon("completed", theme) + " done", 0, 0);
209
156
  }
@@ -217,9 +164,7 @@ interface TeamToolProgressBinder {
217
164
  stop: () => void;
218
165
  }
219
166
 
220
- function startTeamToolProgressBinder(
221
- onUpdate: OnUpdate | undefined,
222
- ): TeamToolProgressBinder {
167
+ function startTeamToolProgressBinder(onUpdate: OnUpdate | undefined): TeamToolProgressBinder {
223
168
  if (!onUpdate) {
224
169
  return { attach: () => {}, stop: () => {} };
225
170
  }
@@ -229,20 +174,14 @@ function startTeamToolProgressBinder(
229
174
  const tick = (): void => {
230
175
  try {
231
176
  if (!cwd || !runId) {
232
- const elapsed = Math.max(
233
- 0,
234
- Math.round((Date.now() - startedAt) / 1000),
235
- );
177
+ const elapsed = Math.max(0, Math.round((Date.now() - startedAt) / 1000));
236
178
  const msg = `team status=starting elapsed=${elapsed}s`;
237
179
  onUpdate({ content: [{ type: "text", text: msg }] });
238
180
  return;
239
181
  }
240
182
  const loaded = loadRunManifestById(cwd, runId);
241
183
  if (!loaded) {
242
- const elapsed = Math.max(
243
- 0,
244
- Math.round((Date.now() - startedAt) / 1000),
245
- );
184
+ const elapsed = Math.max(0, Math.round((Date.now() - startedAt) / 1000));
246
185
  const msg = `team run=${runId} elapsed=${elapsed}s (manifest pending)`;
247
186
  onUpdate({ content: [{ type: "text", text: msg }] });
248
187
  return;
@@ -264,11 +203,7 @@ function startTeamToolProgressBinder(
264
203
  });
265
204
  onUpdate({ content: [{ type: "text", text }] });
266
205
  } catch (error) {
267
- logInternalError(
268
- "team-tool.progress",
269
- error,
270
- `runId=${runId ?? ""}`,
271
- );
206
+ logInternalError("team-tool.progress", error, `runId=${runId ?? ""}`);
272
207
  }
273
208
  };
274
209
  tick();
@@ -0,0 +1,168 @@
1
+ /**
2
+ * UI installer (H3 + L2 — Phase 4 of cleanup plan).
3
+ *
4
+ * Owns the dashboard / sidebar / powerbar overlay logic that is gated on
5
+ * the user actually opening the dashboard (autoOpenDashboard flag) or a
6
+ * foreground run starting.
7
+ *
8
+ * Extracted from src/extension/register.ts. State holder is `UiState`;
9
+ * installer is `installLiveSidebar(ctx, runId, state, deps)`.
10
+ *
11
+ * Lazy by construction: the LiveRunSidebar class (and its transcript-viewer
12
+ * dependency tree) is only loaded when the user opens a sidebar overlay.
13
+ */
14
+ import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
15
+ import { loadConfig } from "../../config/config.ts";
16
+ import { DEFAULT_UI } from "../../config/defaults.ts";
17
+ import type { LiveRunSidebar as LiveRunSidebarType } from "../../ui/live-run-sidebar.ts";
18
+ import { requestRender, setExtensionWidget, showCustom } from "../../ui/pi-ui-compat.ts";
19
+ import {
20
+ clearPiCrewPowerbar,
21
+ registerPiCrewPowerbarSegments,
22
+ requestPowerbarUpdate,
23
+ resetPowerbarDedupState,
24
+ updatePiCrewPowerbar,
25
+ } from "../../ui/powerbar-publisher.ts";
26
+ import type { CrewWidgetState } from "../../ui/widget/index.ts";
27
+ import { stopCrewWidget, updateCrewWidget } from "../../ui/widget/index.ts";
28
+ import { logInternalError } from "../../utils/internal-error.ts";
29
+
30
+ /** Cached live-run-sidebar constructor (lazy-loaded on first overlay open). */
31
+ let _cachedLiveRunSidebar: typeof LiveRunSidebarType | undefined;
32
+ async function importLiveRunSidebar(): Promise<typeof LiveRunSidebarType> {
33
+ if (!_cachedLiveRunSidebar) {
34
+ // LAZY: defer LiveRunSidebar import until the user opens a sidebar overlay.
35
+ const mod = await import("../../ui/live-run-sidebar.ts");
36
+ _cachedLiveRunSidebar = mod.LiveRunSidebar;
37
+ }
38
+ return _cachedLiveRunSidebar;
39
+ }
40
+
41
+ /** Mutable state owned by register.ts. */
42
+ export interface UiState {
43
+ liveSidebarRunId: string | undefined;
44
+ dashboardOpened: boolean;
45
+ }
46
+
47
+ /** Dependencies passed in by register.ts. */
48
+ export interface UiDeps {
49
+ pi: ExtensionAPI;
50
+ widgetState: CrewWidgetState;
51
+ getManifestCache: (cwd: string) => ReturnType<typeof import("../../runtime/manifest-cache.ts").createManifestCache>;
52
+ getRunSnapshotCache: (cwd: string) => ReturnType<typeof import("../../ui/run-snapshot-cache.ts").createRunSnapshotCache>;
53
+ isCleanedUp: () => boolean;
54
+ getCurrentCtx: () => ExtensionContext | undefined;
55
+ }
56
+
57
+ /**
58
+ * Open the live-run sidebar overlay if autoOpenDashboard is enabled. Gated by
59
+ * ui.autoOpenDashboard / autoOpenDashboardForForegroundRuns / placement.
60
+ *
61
+ * Returns true if the sidebar was opened (or was already open for this runId),
62
+ * false if gated off.
63
+ */
64
+ export async function installLiveSidebar(ctx: ExtensionContext, runId: string, state: UiState, deps: UiDeps): Promise<boolean> {
65
+ const uiConfig = loadConfig(ctx.cwd).config.ui;
66
+ const autoOpen = uiConfig?.autoOpenDashboard === true;
67
+ const foregroundAutoOpen = uiConfig?.autoOpenDashboardForForegroundRuns ?? DEFAULT_UI.autoOpenDashboardForForegroundRuns;
68
+ if (!ctx.hasUI || !autoOpen || !foregroundAutoOpen || (uiConfig?.dashboardPlacement ?? DEFAULT_UI.dashboardPlacement) !== "right") {
69
+ return false;
70
+ }
71
+ if (state.liveSidebarRunId === runId) return true;
72
+ state.liveSidebarRunId = runId;
73
+ state.dashboardOpened = true;
74
+ const widgetPlacement = uiConfig?.widgetPlacement ?? DEFAULT_UI.widgetPlacement;
75
+ setExtensionWidget(ctx, "pi-crew", undefined, { placement: widgetPlacement });
76
+ setExtensionWidget(ctx, "pi-crew-active", undefined, { placement: widgetPlacement });
77
+ deps.widgetState.lastVisibility = "hidden";
78
+ deps.widgetState.lastPlacement = widgetPlacement;
79
+ deps.widgetState.lastKey = "pi-crew-active";
80
+ deps.widgetState.model = undefined;
81
+ const width = Math.min(90, Math.max(40, uiConfig?.dashboardWidth ?? DEFAULT_UI.dashboardWidth));
82
+
83
+ try {
84
+ const LiveRunSidebar = await importLiveRunSidebar();
85
+ if (deps.isCleanedUp() || !deps.getCurrentCtx()) return false;
86
+ void showCustom<undefined>(
87
+ ctx,
88
+ (_tui, theme, _keybindings, done) =>
89
+ new LiveRunSidebar({
90
+ cwd: ctx.cwd,
91
+ runId,
92
+ done,
93
+ theme,
94
+ config: uiConfig,
95
+ snapshotCache: deps.getRunSnapshotCache(ctx.cwd),
96
+ }),
97
+ {
98
+ overlay: true,
99
+ overlayOptions: {
100
+ width,
101
+ minWidth: 40,
102
+ maxHeight: "100%",
103
+ anchor: "top-right",
104
+ offsetX: 0,
105
+ offsetY: 0,
106
+ margin: { top: 0, right: 0, bottom: 0, left: 0 },
107
+ visible: (termWidth: number) => termWidth >= 100,
108
+ },
109
+ },
110
+ ).finally(() => {
111
+ if (state.liveSidebarRunId === runId) state.liveSidebarRunId = undefined;
112
+ const c = deps.getCurrentCtx();
113
+ if (!c) return;
114
+ updateCrewWidget(
115
+ c,
116
+ deps.widgetState,
117
+ loadConfig(c.cwd).config.ui,
118
+ deps.getManifestCache(c.cwd),
119
+ deps.getRunSnapshotCache(c.cwd),
120
+ );
121
+ });
122
+ return true;
123
+ } catch (error) {
124
+ logInternalError("register.live-sidebar-lazy-import", error);
125
+ return false;
126
+ }
127
+ }
128
+
129
+ /** Clear the powerbar (called on session switch). */
130
+ export function clearDashboardPowerbar(state: UiState, deps: UiDeps): void {
131
+ const c = deps.getCurrentCtx();
132
+ if (c) stopCrewWidget(c, deps.widgetState, loadConfig(c.cwd).config.ui);
133
+ clearPiCrewPowerbar(deps.pi.events);
134
+ resetPowerbarDedupState();
135
+ state.dashboardOpened = false;
136
+ }
137
+
138
+ /** Register powerbar segments for a session. Idempotent. */
139
+ export function registerPowerbarSegments(deps: UiDeps, uiConfig: unknown): void {
140
+ registerPiCrewPowerbarSegments(deps.pi.events, uiConfig as Parameters<typeof registerPiCrewPowerbarSegments>[1]);
141
+ }
142
+
143
+ /** Push a powerbar update with current run state. */
144
+ export function pushPowerbarUpdate(ctx: ExtensionContext, deps: UiDeps, notificationCount: number): void {
145
+ const config = loadConfig(ctx.cwd).config.ui;
146
+ requestPowerbarUpdate(
147
+ deps.pi.events,
148
+ ctx.cwd,
149
+ config,
150
+ deps.getManifestCache(ctx.cwd),
151
+ deps.getRunSnapshotCache(ctx.cwd),
152
+ ctx,
153
+ notificationCount,
154
+ );
155
+ }
156
+
157
+ /** Initial powerbar update after session_start. */
158
+ export function primePowerbarAndWidget(ctx: ExtensionContext, deps: UiDeps, notificationCount: number): void {
159
+ const uiConfig = loadConfig(ctx.cwd).config.ui;
160
+ const cache = deps.getManifestCache(ctx.cwd);
161
+ updateCrewWidget(ctx, deps.widgetState, uiConfig, cache, deps.getRunSnapshotCache(ctx.cwd));
162
+ updatePiCrewPowerbar(deps.pi.events, ctx.cwd, uiConfig, cache, deps.getRunSnapshotCache(ctx.cwd), ctx, notificationCount);
163
+ }
164
+
165
+ /** Force-render the current context (used by sidebar open path). */
166
+ export function requestUiRender(ctx: ExtensionContext): void {
167
+ requestRender(ctx);
168
+ }
@@ -1,12 +1,13 @@
1
1
  import type { ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
2
- import { loadRunManifestById } from "../../state/state-store.ts";
3
- import { readCrewAgents } from "../../runtime/crew-agent-records.ts";
4
2
  import { loadConfig } from "../../config/config.ts";
3
+ import { readCrewAgents } from "../../runtime/crew-agent-records.ts";
5
4
  import { listLiveAgents } from "../../runtime/live-agent-manager.ts";
5
+ import { loadRunManifestById } from "../../state/state-store.ts";
6
6
  import { LiveConversationOverlay } from "../../ui/live-conversation-overlay.ts";
7
7
  import { asCrewTheme } from "../../ui/theme-adapter.ts";
8
8
  // Lazy-loaded: DurableTranscriptViewer is 658ms — only needed for /crew transcript command
9
9
  import type { DurableTranscriptViewer as DurableTranscriptViewerType } from "../../ui/transcript-viewer.ts";
10
+
10
11
  let _cachedViewer: typeof DurableTranscriptViewerType | undefined;
11
12
  let _viewerPromise: Promise<typeof DurableTranscriptViewerType> | undefined;
12
13
  async function getViewer(): Promise<typeof DurableTranscriptViewerType> {
@@ -20,20 +21,31 @@ async function getViewer(): Promise<typeof DurableTranscriptViewerType> {
20
21
  return _viewerPromise;
21
22
  }
22
23
 
23
- export async function selectAgentTask(ctx: ExtensionCommandContext, runId: string | undefined, taskId?: string): Promise<{ runId: string; taskId?: string } | undefined> {
24
+ export async function selectAgentTask(
25
+ ctx: ExtensionCommandContext,
26
+ runId: string | undefined,
27
+ taskId?: string,
28
+ ): Promise<{ runId: string; taskId?: string } | undefined> {
24
29
  if (!runId) return undefined;
25
30
  if (taskId) return { runId, taskId };
26
31
  const loaded = loadRunManifestById(ctx.cwd, runId); // NOTE: no withRunLock - best-effort only; concurrent writes may cause inconsistency
27
32
  if (!loaded) return { runId };
28
33
  const agents = readCrewAgents(loaded.manifest);
29
34
  if (ctx.hasUI && agents.length > 1) {
30
- const choice = await ctx.ui.select("Select pi-crew agent", agents.map((agent) => `${agent.taskId} ${agent.role}→${agent.agent} [${agent.status}]`));
35
+ const choice = await ctx.ui.select(
36
+ "Select pi-crew agent",
37
+ agents.map((agent) => `${agent.taskId} ${agent.role}→${agent.agent} [${agent.status}]`),
38
+ );
31
39
  return { runId, taskId: choice?.split(" ")[0] };
32
40
  }
33
41
  return { runId, taskId: agents[0]?.taskId };
34
42
  }
35
43
 
36
- export async function openTranscriptViewer(ctx: ExtensionCommandContext, initialRunId: string | undefined, initialTaskId?: string): Promise<boolean> {
44
+ export async function openTranscriptViewer(
45
+ ctx: ExtensionCommandContext,
46
+ initialRunId: string | undefined,
47
+ initialTaskId?: string,
48
+ ): Promise<boolean> {
37
49
  const selected = await selectAgentTask(ctx, initialRunId, initialTaskId);
38
50
  if (!selected) return false;
39
51
  const runId = selected.runId;
@@ -43,15 +55,29 @@ export async function openTranscriptViewer(ctx: ExtensionCommandContext, initial
43
55
  if (!loaded) return false;
44
56
  const uiConfig = loadConfig(ctx.cwd).config.ui;
45
57
  const DurableTranscriptViewer = await getViewer();
46
- await ctx.ui.custom<undefined>((_tui, theme, _keybindings, done) => new DurableTranscriptViewer(loaded.manifest, theme, done, taskId, { maxTailBytes: uiConfig?.transcriptTailBytes }), {
47
- overlay: true,
48
- overlayOptions: { width: "90%", maxHeight: "85%", anchor: "center" },
49
- });
58
+ await ctx.ui.custom<undefined>(
59
+ (_tui, theme, _keybindings, done) =>
60
+ new DurableTranscriptViewer(loaded.manifest, theme, done, taskId, {
61
+ maxTailBytes: uiConfig?.transcriptTailBytes,
62
+ }),
63
+ {
64
+ overlay: true,
65
+ overlayOptions: {
66
+ width: "90%",
67
+ maxHeight: "85%",
68
+ anchor: "center",
69
+ },
70
+ },
71
+ );
50
72
  return true;
51
73
  }
52
74
 
53
75
  /** R2: Open live conversation overlay for a running live-session agent. */
54
- export async function openLiveConversation(ctx: ExtensionCommandContext, initialRunId: string | undefined, initialTaskId?: string): Promise<boolean> {
76
+ export async function openLiveConversation(
77
+ ctx: ExtensionCommandContext,
78
+ initialRunId: string | undefined,
79
+ initialTaskId?: string,
80
+ ): Promise<boolean> {
55
81
  const selected = await selectAgentTask(ctx, initialRunId, initialTaskId);
56
82
  if (!selected || !ctx.hasUI) return false;
57
83
  const liveAgents = listLiveAgents();
@@ -59,20 +85,34 @@ export async function openLiveConversation(ctx: ExtensionCommandContext, initial
59
85
  if (!handle) return false;
60
86
  const theme = asCrewTheme({});
61
87
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
62
- await ctx.ui.custom<undefined>((tui: any, _theme: any, _keybindings: any, done: (result: undefined) => void) => {
63
- const columns = tui?.terminal?.columns ?? 80;
64
- const rows = tui?.terminal?.rows ?? 24;
65
- const overlay = new LiveConversationOverlay(handle, theme, columns, rows);
66
- return {
67
- render(width: number) { return overlay.render(width); },
68
- handleInput(data: string) {
69
- if (data === "\x1b" || data === "q") { overlay.close(); done(undefined); }
88
+ await ctx.ui.custom<undefined>(
89
+ (tui: any, _theme: any, _keybindings: any, done: (result: undefined) => void) => {
90
+ const columns = tui?.terminal?.columns ?? 80;
91
+ const rows = tui?.terminal?.rows ?? 24;
92
+ const overlay = new LiveConversationOverlay(handle, theme, columns, rows);
93
+ return {
94
+ render(width: number) {
95
+ return overlay.render(width);
96
+ },
97
+ handleInput(data: string) {
98
+ if (data === "\x1b" || data === "q") {
99
+ overlay.close();
100
+ done(undefined);
101
+ }
102
+ },
103
+ invalidate() {
104
+ /* overlay polls */
105
+ },
106
+ };
107
+ },
108
+ {
109
+ overlay: true,
110
+ overlayOptions: {
111
+ width: "90%",
112
+ maxHeight: "85%",
113
+ anchor: "center",
70
114
  },
71
- invalidate() { /* overlay polls */ },
72
- };
73
- }, {
74
- overlay: true,
75
- overlayOptions: { width: "90%", maxHeight: "85%", anchor: "center" },
76
- });
115
+ },
116
+ );
77
117
  return true;
78
118
  }
@@ -1,8 +1,8 @@
1
1
  import * as fs from "node:fs";
2
2
  import * as path from "node:path";
3
3
  import { buildCompletionKey, getGlobalSeenMap, markSeenWithTtl } from "../utils/completion-dedupe.ts";
4
- import { closeWatcher, watchWithErrorHandler } from "../utils/fs-watch.ts";
5
4
  import { createFileCoalescer } from "../utils/file-coalescer.ts";
5
+ import { closeWatcher, watchWithErrorHandler } from "../utils/fs-watch.ts";
6
6
  import { logInternalError } from "../utils/internal-error.ts";
7
7
 
8
8
  export interface ResultWatcherEvents {
@@ -42,7 +42,11 @@ function readJson(filePath: string): unknown | undefined {
42
42
  }
43
43
  }
44
44
 
45
- export function createResultWatcher(events: ResultWatcherEvents, resultsDir: string, eventNameOrOptions: string | ResultWatcherOptions = "pi-crew:run-result"): ResultWatcherHandle {
45
+ export function createResultWatcher(
46
+ events: ResultWatcherEvents,
47
+ resultsDir: string,
48
+ eventNameOrOptions: string | ResultWatcherOptions = "pi-crew:run-result",
49
+ ): ResultWatcherHandle {
46
50
  const options: ResultWatcherOptions = typeof eventNameOrOptions === "string" ? { eventName: eventNameOrOptions } : eventNameOrOptions;
47
51
  const eventName = options.eventName ?? "pi-crew:run-result";
48
52
  const completionTtlMs = options.completionTtlMs ?? 5 * 60_000;
@@ -61,7 +65,10 @@ export function createResultWatcher(events: ResultWatcherEvents, resultsDir: str
61
65
  coalescer.schedule(file, RESULT_WATCHER_POLL_MS);
62
66
  return;
63
67
  }
64
- const key = buildCompletionKey(payload && typeof payload === "object" && !Array.isArray(payload) ? payload as Record<string, unknown> : {}, `file:${file}`);
68
+ const key = buildCompletionKey(
69
+ payload && typeof payload === "object" && !Array.isArray(payload) ? (payload as Record<string, unknown>) : {},
70
+ `file:${file}`,
71
+ );
65
72
  if (!markSeenWithTtl(seen, key, Date.now(), completionTtlMs)) {
66
73
  events.emit(eventName, payload);
67
74
  }
@@ -105,10 +112,14 @@ export function createResultWatcher(events: ResultWatcherEvents, resultsDir: str
105
112
  if (!isCurrent()) return;
106
113
  fs.mkdirSync(resultsDir, { recursive: true });
107
114
  if (watcher) closeWatcher(watcher);
108
- watcher = watch(resultsDir, (event, fileName) => {
109
- if (event !== "rename" || !fileName) return;
110
- coalescer.schedule(fileName.toString());
111
- }, scheduleRestart);
115
+ watcher = watch(
116
+ resultsDir,
117
+ (event, fileName) => {
118
+ if (event !== "rename" || !fileName) return;
119
+ coalescer.schedule(fileName.toString());
120
+ },
121
+ scheduleRestart,
122
+ );
112
123
  if (watcher) stopPolling();
113
124
  watcher?.unref();
114
125
  },
@@ -1,6 +1,6 @@
1
1
  import { isTeamRunStatus, isTeamTaskStatus } from "../state/contracts.ts";
2
- import type { TeamRunManifest, TeamTaskState, ArtifactDescriptor } from "../state/types.ts";
3
2
  import type { TeamEvent } from "../state/event-log.ts";
3
+ import type { ArtifactDescriptor, TeamRunManifest, TeamTaskState } from "../state/types.ts";
4
4
  import type { ExportedRunBundle } from "./run-export.ts";
5
5
 
6
6
  export interface BundleValidationResult {
@@ -22,7 +22,8 @@ function validateArtifact(value: unknown, index: number, errors: string[]): valu
22
22
  if (typeof value.path !== "string") errors.push(`manifest.artifacts[${index}].path must be a string.`);
23
23
  if (typeof value.createdAt !== "string") errors.push(`manifest.artifacts[${index}].createdAt must be a string.`);
24
24
  if (typeof value.producer !== "string") errors.push(`manifest.artifacts[${index}].producer must be a string.`);
25
- if (value.retention !== "run" && value.retention !== "project" && value.retention !== "temporary") errors.push(`manifest.artifacts[${index}].retention is invalid.`);
25
+ if (value.retention !== "run" && value.retention !== "project" && value.retention !== "temporary")
26
+ errors.push(`manifest.artifacts[${index}].retention is invalid.`);
26
27
  return errors.length === before;
27
28
  }
28
29
 
@@ -33,11 +34,23 @@ function validateManifest(value: unknown, errors: string[]): value is TeamRunMan
33
34
  }
34
35
  const before = errors.length;
35
36
  if (value.schemaVersion !== 1) errors.push("manifest.schemaVersion must be 1.");
36
- for (const field of ["runId", "team", "goal", "createdAt", "updatedAt", "cwd", "stateRoot", "artifactsRoot", "tasksPath", "eventsPath"] as const) {
37
+ for (const field of [
38
+ "runId",
39
+ "team",
40
+ "goal",
41
+ "createdAt",
42
+ "updatedAt",
43
+ "cwd",
44
+ "stateRoot",
45
+ "artifactsRoot",
46
+ "tasksPath",
47
+ "eventsPath",
48
+ ] as const) {
37
49
  if (typeof value[field] !== "string") errors.push(`manifest.${field} must be a string.`);
38
50
  }
39
51
  if (!isTeamRunStatus(value.status)) errors.push("manifest.status is invalid.");
40
- if (value.workspaceMode !== "single" && value.workspaceMode !== "worktree") errors.push("manifest.workspaceMode must be single or worktree.");
52
+ if (value.workspaceMode !== "single" && value.workspaceMode !== "worktree")
53
+ errors.push("manifest.workspaceMode must be single or worktree.");
41
54
  if (!Array.isArray(value.artifacts)) errors.push("manifest.artifacts must be an array.");
42
55
  else value.artifacts.forEach((artifact, index) => validateArtifact(artifact, index, errors));
43
56
  return errors.length === before;
@@ -79,11 +92,13 @@ export function validateRunBundle(value: unknown): BundleValidationResult {
79
92
  else value.tasks.forEach((task, index) => validateTask(task, index, errors));
80
93
  if (!Array.isArray(value.events)) errors.push("events must be an array.");
81
94
  else value.events.forEach((event, index) => validateEvent(event, index, errors));
82
- if (!Array.isArray(value.artifactPaths) || !value.artifactPaths.every((item) => typeof item === "string")) errors.push("artifactPaths must be an array of strings.");
95
+ if (!Array.isArray(value.artifactPaths) || !value.artifactPaths.every((item) => typeof item === "string"))
96
+ errors.push("artifactPaths must be an array of strings.");
83
97
  return { ok: errors.length === 0, errors };
84
98
  }
85
99
 
86
100
  export function assertRunBundle(value: unknown): asserts value is ExportedRunBundle {
87
101
  const validation = validateRunBundle(value);
88
- if (!validation.ok) throw new Error(`File is not a valid pi-crew exported run bundle:\n${validation.errors.map((error) => `- ${error}`).join("\n")}`);
102
+ if (!validation.ok)
103
+ throw new Error(`File is not a valid pi-crew exported run bundle:\n${validation.errors.map((error) => `- ${error}`).join("\n")}`);
89
104
  }
@@ -1,10 +1,10 @@
1
+ import * as crypto from "node:crypto";
1
2
  import * as fs from "node:fs";
2
- import * as path from "node:path";
3
3
  import * as os from "node:os";
4
- import * as crypto from "node:crypto";
5
- import type { TeamRunManifest, TeamTaskState } from "../state/types.ts";
4
+ import * as path from "node:path";
6
5
  import { writeArtifact } from "../state/artifact-store.ts";
7
6
  import { readEvents, type TeamEvent } from "../state/event-log.ts";
7
+ import type { TeamRunManifest, TeamTaskState } from "../state/types.ts";
8
8
  import { redactSecrets } from "../utils/redaction.ts";
9
9
 
10
10
  /** Replace absolute paths containing home directory with ~/ */
@@ -72,13 +72,22 @@ export function exportRunBundle(manifest: TeamRunManifest, tasks: TeamTaskState[
72
72
  `Goal: ${safeManifest.goal}`,
73
73
  "",
74
74
  "## Tasks",
75
- ...safeTasks.map((task) => `- ${task.id}: ${task.status} (${task.role} -> ${task.agent})${task.error ? ` - ${task.error}` : ""}`),
75
+ ...safeTasks.map(
76
+ (task) => `- ${task.id}: ${task.status} (${task.role} -> ${task.agent})${task.error ? ` - ${task.error}` : ""}`,
77
+ ),
76
78
  "",
77
79
  "## Artifacts",
78
- ...(safeManifest.artifacts.length ? safeManifest.artifacts.map((artifact) => `- ${artifact.kind}: ${artifact.path}`) : ["- (none)"]),
80
+ ...(safeManifest.artifacts.length
81
+ ? safeManifest.artifacts.map((artifact) => `- ${artifact.kind}: ${artifact.path}`)
82
+ : ["- (none)"]),
79
83
  "",
80
84
  "## Recent Events",
81
- ...(safeEvents.slice(-20).map((event) => `- ${event.time} ${event.type}${event.taskId ? ` ${event.taskId}` : ""}${event.message ? `: ${event.message}` : ""}`)),
85
+ ...safeEvents
86
+ .slice(-20)
87
+ .map(
88
+ (event) =>
89
+ `- ${event.time} ${event.type}${event.taskId ? ` ${event.taskId}` : ""}${event.message ? `: ${event.message}` : ""}`,
90
+ ),
82
91
  "",
83
92
  ].join("\n"),
84
93
  });