pi-crew 0.9.16 → 0.9.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (435) hide show
  1. package/CHANGELOG.md +130 -0
  2. package/README.md +19 -0
  3. package/dist/build-meta.json +21784 -0
  4. package/dist/index.mjs +83169 -0
  5. package/dist/index.mjs.map +7 -0
  6. package/docs/A +358 -0
  7. package/docs/M-A +357 -0
  8. package/docs/REVIEW-FINDINGS-2026-06 +357 -0
  9. package/docs/Y +357 -0
  10. package/docs/a +357 -0
  11. package/docs/aA +358 -0
  12. package/docs/archive/README.md +91 -0
  13. package/docs/migration/atomic-write-v2-migration.md +297 -0
  14. package/docs/patterns/command-agent-skill.md +1 -1
  15. package/docs/perf/performance-review-2026-07.md +287 -0
  16. package/docs/skills/REFERENCE.md +0 -17
  17. package/docs//303/242mmaAAA/303/242 +357 -0
  18. package/index.bundle.ts +25 -0
  19. package/index.ts +95 -4
  20. package/package.json +15 -4
  21. package/skills/iterative-audit/SKILL.md +0 -1
  22. package/skills/widget-rendering/SKILL.md +17 -0
  23. package/src/adapters/claude-adapter.ts +1 -3
  24. package/src/adapters/export-util.ts +16 -16
  25. package/src/adapters/index.ts +5 -5
  26. package/src/agents/agent-config.ts +20 -14
  27. package/src/agents/agent-serializer.ts +1 -1
  28. package/src/agents/discover-agents.ts +83 -39
  29. package/src/benchmark/benchmark-runner.ts +51 -51
  30. package/src/benchmark/feedback-loop.ts +1 -1
  31. package/src/config/config.ts +303 -591
  32. package/src/config/defaults.ts +28 -2
  33. package/src/config/drift-detector.ts +11 -14
  34. package/src/config/markers.ts +201 -203
  35. package/src/config/resilient-parser.ts +14 -6
  36. package/src/config/role-tools.ts +3 -3
  37. package/src/config/suggestions.ts +5 -12
  38. package/src/config/types.ts +9 -25
  39. package/src/errors.ts +151 -157
  40. package/src/extension/action-suggestions.ts +54 -9
  41. package/src/extension/async-notifier.ts +43 -13
  42. package/src/extension/autonomous-policy.ts +77 -37
  43. package/src/extension/command-completions.ts +9 -8
  44. package/src/extension/context-status-injection.ts +14 -12
  45. package/src/extension/crew-autocomplete.ts +8 -16
  46. package/src/extension/crew-cleanup.ts +2 -1
  47. package/src/extension/crew-shortcuts.ts +9 -6
  48. package/src/extension/cross-extension-rpc.ts +136 -42
  49. package/src/extension/help.ts +1 -1
  50. package/src/extension/import-index.ts +10 -5
  51. package/src/extension/knowledge-injection.ts +88 -15
  52. package/src/extension/management.ts +89 -349
  53. package/src/extension/message-renderers.ts +3 -4
  54. package/src/extension/notification-router.ts +22 -5
  55. package/src/extension/notification-sink.ts +6 -3
  56. package/src/extension/pi-api.ts +17 -8
  57. package/src/extension/plan-orchestrate.ts +8 -27
  58. package/src/extension/project-init.ts +21 -6
  59. package/src/extension/register.ts +329 -975
  60. package/src/extension/registration/artifact-cleanup.ts +9 -4
  61. package/src/extension/registration/command-utils.ts +5 -1
  62. package/src/extension/registration/commands.ts +806 -314
  63. package/src/extension/registration/compaction-guard.ts +15 -15
  64. package/src/extension/registration/lifecycle.ts +259 -0
  65. package/src/extension/registration/observability.ts +293 -0
  66. package/src/extension/registration/subagent-helpers.ts +29 -7
  67. package/src/extension/registration/subagent-tools.ts +253 -44
  68. package/src/extension/registration/team-tool.ts +19 -84
  69. package/src/extension/registration/ui.ts +168 -0
  70. package/src/extension/registration/viewers.ts +64 -24
  71. package/src/extension/result-watcher.ts +18 -7
  72. package/src/extension/run-bundle-schema.ts +21 -6
  73. package/src/extension/run-export.ts +15 -6
  74. package/src/extension/run-import.ts +64 -29
  75. package/src/extension/run-index.ts +28 -9
  76. package/src/extension/run-maintenance.ts +32 -12
  77. package/src/extension/session-summary.ts +1 -1
  78. package/src/extension/team-manager-command.ts +64 -7
  79. package/src/extension/team-onboard.ts +149 -150
  80. package/src/extension/team-recommendation.ts +121 -21
  81. package/src/extension/team-tool/anchor.ts +31 -64
  82. package/src/extension/team-tool/api.ts +929 -141
  83. package/src/extension/team-tool/auto-summarize.ts +14 -26
  84. package/src/extension/team-tool/cache-control.ts +1 -5
  85. package/src/extension/team-tool/cancel.ts +138 -38
  86. package/src/extension/team-tool/chain-dispatch.ts +5 -13
  87. package/src/extension/team-tool/chain-executor.ts +29 -51
  88. package/src/extension/team-tool/config-patch.ts +1 -1
  89. package/src/extension/team-tool/context.ts +40 -20
  90. package/src/extension/team-tool/destructive-gate.ts +10 -5
  91. package/src/extension/team-tool/doctor.ts +170 -51
  92. package/src/extension/team-tool/explain.ts +228 -214
  93. package/src/extension/team-tool/failure-patterns.ts +3 -9
  94. package/src/extension/team-tool/goal-wrap.ts +71 -29
  95. package/src/extension/team-tool/goal.ts +185 -35
  96. package/src/extension/team-tool/handle-schedule.ts +34 -15
  97. package/src/extension/team-tool/handle-settings.ts +94 -56
  98. package/src/extension/team-tool/health-monitor.ts +27 -108
  99. package/src/extension/team-tool/inspect.ts +42 -9
  100. package/src/extension/team-tool/intent-policy.ts +4 -1
  101. package/src/extension/team-tool/lifecycle-actions.ts +244 -48
  102. package/src/extension/team-tool/orchestrate.ts +7 -18
  103. package/src/extension/team-tool/parallel-dispatch.ts +51 -29
  104. package/src/extension/team-tool/plan.ts +29 -5
  105. package/src/extension/team-tool/respond.ts +49 -16
  106. package/src/extension/team-tool/run-not-found.ts +3 -8
  107. package/src/extension/team-tool/run.ts +80 -317
  108. package/src/extension/team-tool/status.ts +135 -43
  109. package/src/extension/team-tool/workflow-manage.ts +92 -25
  110. package/src/extension/team-tool-types.ts +8 -1
  111. package/src/extension/team-tool.ts +142 -551
  112. package/src/extension/validate-resources.ts +39 -8
  113. package/src/hooks/registry.ts +66 -17
  114. package/src/hooks/types.ts +1 -1
  115. package/src/i18n.ts +25 -11
  116. package/src/observability/correlation.ts +17 -3
  117. package/src/observability/event-bus.ts +51 -56
  118. package/src/observability/event-to-metric.ts +117 -15
  119. package/src/observability/exporters/otlp-exporter.ts +56 -17
  120. package/src/observability/exporters/prometheus-exporter.ts +1 -1
  121. package/src/observability/metric-registry.ts +16 -4
  122. package/src/observability/metric-retention.ts +8 -2
  123. package/src/observability/metric-sink.ts +11 -3
  124. package/src/observability/metrics-primitives.ts +42 -9
  125. package/src/plugins/plugin-define.ts +2 -2
  126. package/src/plugins/plugin-registry.ts +25 -25
  127. package/src/plugins/plugins/index.ts +1 -1
  128. package/src/plugins/plugins/nextjs.ts +16 -16
  129. package/src/plugins/plugins/vite.ts +7 -11
  130. package/src/plugins/plugins/vitest.ts +6 -11
  131. package/src/runtime/adaptive-plan.ts +225 -40
  132. package/src/runtime/agent-control.ts +58 -15
  133. package/src/runtime/agent-memory.ts +15 -9
  134. package/src/runtime/agent-observability.ts +10 -2
  135. package/src/runtime/anchor-manager.ts +27 -25
  136. package/src/runtime/async-marker.ts +7 -1
  137. package/src/runtime/async-runner.ts +39 -24
  138. package/src/runtime/auto-summarize.ts +7 -13
  139. package/src/runtime/background-runner.ts +189 -251
  140. package/src/runtime/batch-barrier.ts +18 -16
  141. package/src/runtime/cancellation-token.ts +16 -6
  142. package/src/runtime/cancellation.ts +46 -8
  143. package/src/runtime/capability-inventory.ts +6 -4
  144. package/src/runtime/chain-parser.ts +44 -11
  145. package/src/runtime/chain-runner.ts +63 -69
  146. package/src/runtime/checkpoint.ts +12 -56
  147. package/src/runtime/child-pi.ts +344 -79
  148. package/src/runtime/coalesce-tasks.ts +268 -0
  149. package/src/runtime/code-summary.ts +71 -26
  150. package/src/runtime/compact-stages/index.ts +15 -5
  151. package/src/runtime/compact-stages/tail-capture-stage.ts +7 -2
  152. package/src/runtime/compact-stages/truncation-stage.ts +4 -1
  153. package/src/runtime/compaction-summary.ts +17 -10
  154. package/src/runtime/completion-guard.ts +33 -16
  155. package/src/runtime/crash-classification.ts +28 -7
  156. package/src/runtime/crash-recovery.ts +177 -37
  157. package/src/runtime/crew-agent-records.ts +145 -47
  158. package/src/runtime/crew-hooks.ts +9 -24
  159. package/src/runtime/cross-extension-rpc.ts +25 -23
  160. package/src/runtime/custom-tools/irc-tool.ts +43 -15
  161. package/src/runtime/custom-tools/submit-result-tool.ts +16 -5
  162. package/src/runtime/delivery-coordinator.ts +34 -7
  163. package/src/runtime/delta-conflict.ts +9 -21
  164. package/src/runtime/deterministic-ast.ts +1 -1
  165. package/src/runtime/diagnostic-export.ts +53 -20
  166. package/src/runtime/direct-run.ts +12 -2
  167. package/src/runtime/dwf-state-store.ts +1 -1
  168. package/src/runtime/dynamic-workflow-context.ts +187 -59
  169. package/src/runtime/dynamic-workflow-runner.ts +42 -20
  170. package/src/runtime/effectiveness.ts +16 -8
  171. package/src/runtime/errors/crew-errors.ts +7 -11
  172. package/src/runtime/event-stream-bridge.ts +9 -3
  173. package/src/runtime/foreground-control.ts +54 -14
  174. package/src/runtime/foreground-watchdog.ts +9 -6
  175. package/src/runtime/goal-achievement.ts +27 -10
  176. package/src/runtime/goal-evaluator.ts +54 -19
  177. package/src/runtime/goal-loop-runner.ts +280 -99
  178. package/src/runtime/goal-state-store.ts +27 -17
  179. package/src/runtime/green-contract.ts +11 -2
  180. package/src/runtime/group-join.ts +64 -31
  181. package/src/runtime/handoff-manager.ts +37 -42
  182. package/src/runtime/heartbeat-gradient.ts +10 -2
  183. package/src/runtime/heartbeat-watcher.ts +32 -6
  184. package/src/runtime/hidden-handoff.ts +13 -31
  185. package/src/runtime/important-line-classifier.ts +12 -2
  186. package/src/runtime/iteration-hooks.ts +25 -15
  187. package/src/runtime/live-agent-control.ts +55 -7
  188. package/src/runtime/live-agent-manager.ts +130 -27
  189. package/src/runtime/live-control-realtime.ts +23 -3
  190. package/src/runtime/live-irc.ts +4 -1
  191. package/src/runtime/live-session-health.ts +12 -4
  192. package/src/runtime/live-session-runtime.ts +379 -117
  193. package/src/runtime/manifest-cache.ts +28 -12
  194. package/src/runtime/mcp-proxy.ts +10 -18
  195. package/src/runtime/metric-parser.ts +1 -5
  196. package/src/runtime/model-fallback.ts +55 -18
  197. package/src/runtime/model-resolver.ts +2 -6
  198. package/src/runtime/model-scope.ts +19 -3
  199. package/src/runtime/notebook-helpers.ts +60 -62
  200. package/src/runtime/orphan-worker-registry.ts +37 -26
  201. package/src/runtime/output-validator.ts +18 -3
  202. package/src/runtime/overflow-recovery.ts +5 -4
  203. package/src/runtime/parallel-research.ts +29 -5
  204. package/src/runtime/parallel-utils.ts +9 -11
  205. package/src/runtime/path-overlap.ts +150 -0
  206. package/src/runtime/peer-dep.ts +12 -17
  207. package/src/runtime/per-write-validator.ts +1 -3
  208. package/src/runtime/phase-tracker.ts +342 -330
  209. package/src/runtime/pi-args.ts +26 -8
  210. package/src/runtime/pi-json-output.ts +1 -1
  211. package/src/runtime/pi-spawn.ts +30 -19
  212. package/src/runtime/pipeline-runner.ts +56 -55
  213. package/src/runtime/plan-templates.ts +5 -6
  214. package/src/runtime/policy-engine.ts +43 -7
  215. package/src/runtime/post-checks.ts +12 -4
  216. package/src/runtime/post-exit-stdio-guard.ts +2 -2
  217. package/src/runtime/process-lifecycle.ts +20 -10
  218. package/src/runtime/process-status.ts +16 -5
  219. package/src/runtime/progress-event-coalescer.ts +2 -1
  220. package/src/runtime/progress-tracker.ts +103 -103
  221. package/src/runtime/prose-compressor.ts +9 -11
  222. package/src/runtime/recovery-recipes.ts +118 -24
  223. package/src/runtime/replace.ts +25 -10
  224. package/src/runtime/resilient-edit.ts +10 -25
  225. package/src/runtime/result-extractor.ts +2 -6
  226. package/src/runtime/retry-executor.ts +20 -4
  227. package/src/runtime/retry-runner.ts +27 -51
  228. package/src/runtime/role-permission.ts +6 -1
  229. package/src/runtime/run-coalesced-task-group.ts +256 -0
  230. package/src/runtime/run-drift.ts +14 -15
  231. package/src/runtime/run-tracker.ts +6 -28
  232. package/src/runtime/runtime-policy.ts +1 -6
  233. package/src/runtime/runtime-resolver.ts +80 -15
  234. package/src/runtime/scheduler.ts +47 -18
  235. package/src/runtime/semaphore.ts +5 -7
  236. package/src/runtime/sensitive-paths.ts +2 -1
  237. package/src/runtime/session-usage.ts +1 -1
  238. package/src/runtime/settings-store.ts +16 -12
  239. package/src/runtime/sidechain-output.ts +6 -2
  240. package/src/runtime/single-agent-compose.ts +1 -4
  241. package/src/runtime/skill-effectiveness.ts +29 -97
  242. package/src/runtime/skill-instructions.ts +40 -83
  243. package/src/runtime/stale-reconciler.ts +73 -197
  244. package/src/runtime/stream-preview.ts +1 -1
  245. package/src/runtime/streaming-output.ts +1 -1
  246. package/src/runtime/subagent-manager.ts +44 -169
  247. package/src/runtime/subprocess-tool-registry.ts +4 -1
  248. package/src/runtime/supervisor-contact.ts +10 -5
  249. package/src/runtime/task-display.ts +19 -5
  250. package/src/runtime/task-graph-scheduler.ts +95 -21
  251. package/src/runtime/task-graph.ts +5 -11
  252. package/src/runtime/task-health.ts +54 -47
  253. package/src/runtime/task-id.ts +12 -19
  254. package/src/runtime/task-output-context.ts +265 -81
  255. package/src/runtime/task-packet.ts +12 -20
  256. package/src/runtime/task-quality.ts +6 -14
  257. package/src/runtime/task-runner/context-retrieval.ts +4 -13
  258. package/src/runtime/task-runner/live-executor.ts +114 -36
  259. package/src/runtime/task-runner/output-splitter.ts +152 -0
  260. package/src/runtime/task-runner/progress.ts +50 -12
  261. package/src/runtime/task-runner/prompt-builder.ts +31 -7
  262. package/src/runtime/task-runner/prompt-pipeline.ts +31 -7
  263. package/src/runtime/task-runner/result-utils.ts +3 -1
  264. package/src/runtime/task-runner/retrieval-orchestrator.ts +310 -0
  265. package/src/runtime/task-runner/run-projection.ts +27 -8
  266. package/src/runtime/task-runner/state-helpers.ts +50 -14
  267. package/src/runtime/task-runner/tail-read.ts +2 -6
  268. package/src/runtime/task-runner.ts +180 -326
  269. package/src/runtime/team-runner-artifacts.ts +13 -0
  270. package/src/runtime/team-runner.ts +456 -974
  271. package/src/runtime/tool-output-pruner.ts +6 -9
  272. package/src/runtime/tool-progress.ts +11 -21
  273. package/src/runtime/verification-gates.ts +33 -24
  274. package/src/runtime/verification-integrity.ts +2 -7
  275. package/src/runtime/verification-worktree.ts +62 -12
  276. package/src/runtime/worker-heartbeat.ts +5 -1
  277. package/src/runtime/worker-startup.ts +29 -5
  278. package/src/runtime/workflow-state.ts +17 -9
  279. package/src/runtime/workspace-lock.ts +30 -35
  280. package/src/runtime/workspace-tree.ts +20 -32
  281. package/src/runtime/yield-handler.ts +43 -9
  282. package/src/runtime/zombie-scanner.ts +5 -4
  283. package/src/schema/config-schema.ts +266 -172
  284. package/src/schema/team-tool-schema.ts +29 -74
  285. package/src/schema/validation-types.ts +25 -17
  286. package/src/skills/discover-skills.ts +35 -10
  287. package/src/skills/skill-templates.ts +109 -27
  288. package/src/skills/validate.ts +26 -8
  289. package/src/state/active-run-registry.ts +87 -28
  290. package/src/state/artifact-store.ts +9 -5
  291. package/src/state/atomic-write-v2.ts +85 -63
  292. package/src/state/atomic-write.ts +106 -27
  293. package/src/state/blob-store.ts +47 -20
  294. package/src/state/contracts.ts +20 -5
  295. package/src/state/crew-init.ts +5 -22
  296. package/src/state/decision-ledger.ts +19 -73
  297. package/src/state/event-log-rotation.ts +41 -15
  298. package/src/state/event-log.ts +168 -53
  299. package/src/state/event-reconstructor.ts +11 -1
  300. package/src/state/gitignore-manager.ts +2 -8
  301. package/src/state/health-store.ts +57 -57
  302. package/src/state/hook-instinct-bridge.ts +1 -1
  303. package/src/state/hook-integrations.ts +1 -1
  304. package/src/state/instinct-store.ts +17 -5
  305. package/src/state/jsonl-writer.ts +1 -1
  306. package/src/state/locks.ts +23 -9
  307. package/src/state/mailbox.ts +151 -28
  308. package/src/state/observation-store.ts +20 -14
  309. package/src/state/run-cache.ts +142 -135
  310. package/src/state/run-graph.ts +6 -15
  311. package/src/state/run-metrics.ts +5 -18
  312. package/src/state/schedule.ts +15 -9
  313. package/src/state/state-store.ts +137 -47
  314. package/src/state/task-claims.ts +12 -2
  315. package/src/state/tiered-eval.ts +52 -43
  316. package/src/state/types-eval.ts +2 -2
  317. package/src/state/types.ts +24 -20
  318. package/src/state/usage.ts +20 -4
  319. package/src/state/worker-atomic-writer.ts +6 -3
  320. package/src/subagents/index.ts +2 -2
  321. package/src/teams/discover-teams.ts +21 -6
  322. package/src/tools/safe-bash-extension.ts +5 -6
  323. package/src/tools/safe-bash.ts +10 -11
  324. package/src/types/new-api-types.ts +6 -10
  325. package/src/ui/agent-management-overlay.ts +52 -40
  326. package/src/ui/card-colors.ts +13 -4
  327. package/src/ui/crew-footer.ts +8 -7
  328. package/src/ui/crew-select-list.ts +1 -1
  329. package/src/ui/dashboard-panes/agents-pane.ts +41 -25
  330. package/src/ui/dashboard-panes/cancellation-pane.ts +1 -1
  331. package/src/ui/dashboard-panes/capability-pane.ts +32 -15
  332. package/src/ui/dashboard-panes/health-pane.ts +2 -1
  333. package/src/ui/dashboard-panes/metrics-pane.ts +4 -1
  334. package/src/ui/dashboard-panes/progress-pane.ts +12 -9
  335. package/src/ui/heartbeat-aggregator.ts +15 -4
  336. package/src/ui/keybinding-map.ts +40 -7
  337. package/src/ui/live-conversation-overlay.ts +36 -20
  338. package/src/ui/live-duration.ts +1 -4
  339. package/src/ui/live-run-sidebar.ts +88 -25
  340. package/src/ui/loaders.ts +2 -8
  341. package/src/ui/mascot.ts +20 -36
  342. package/src/ui/overlays/agent-picker-overlay.ts +11 -3
  343. package/src/ui/overlays/confirm-overlay.ts +4 -2
  344. package/src/ui/overlays/help-overlay.ts +25 -14
  345. package/src/ui/overlays/mailbox-compose-overlay.ts +48 -11
  346. package/src/ui/overlays/mailbox-compose-preview.ts +20 -5
  347. package/src/ui/overlays/mailbox-detail-overlay.ts +27 -6
  348. package/src/ui/pi-ui-compat.ts +7 -7
  349. package/src/ui/powerbar-publisher.ts +120 -42
  350. package/src/ui/render-diff.ts +10 -3
  351. package/src/ui/render-scheduler.ts +12 -4
  352. package/src/ui/run-action-dispatcher.ts +81 -18
  353. package/src/ui/run-dashboard.ts +172 -76
  354. package/src/ui/run-event-bus.ts +59 -37
  355. package/src/ui/run-snapshot-cache.ts +276 -86
  356. package/src/ui/settings-overlay.ts +361 -74
  357. package/src/ui/status-colors.ts +12 -1
  358. package/src/ui/syntax-highlight.ts +1 -1
  359. package/src/ui/terminal-status.ts +1 -3
  360. package/src/ui/theme-adapter.ts +16 -14
  361. package/src/ui/theme-discovery.ts +13 -2
  362. package/src/ui/tool-progress-formatter.ts +7 -7
  363. package/src/ui/tool-render.ts +128 -56
  364. package/src/ui/tool-renderers/brief-mode.ts +45 -27
  365. package/src/ui/tool-renderers/index.ts +109 -43
  366. package/src/ui/transcript-cache.ts +32 -6
  367. package/src/ui/transcript-entries.ts +25 -23
  368. package/src/ui/transcript-viewer.ts +78 -29
  369. package/src/ui/widget/index.ts +99 -40
  370. package/src/ui/widget/widget-formatters.ts +13 -6
  371. package/src/ui/widget/widget-model.ts +19 -8
  372. package/src/ui/widget/widget-renderer.ts +23 -13
  373. package/src/ui/widget/widget-types.ts +1 -1
  374. package/src/utils/bm25-search.ts +199 -199
  375. package/src/utils/conflict-detect.ts +22 -21
  376. package/src/utils/env-filter.ts +14 -7
  377. package/src/utils/file-coalescer.ts +5 -1
  378. package/src/utils/fingerprint.ts +3 -6
  379. package/src/utils/frontmatter.ts +3 -1
  380. package/src/utils/fs-watch.ts +2 -6
  381. package/src/utils/gh-protocol.ts +119 -44
  382. package/src/utils/git.ts +13 -15
  383. package/src/utils/guards.ts +2 -5
  384. package/src/utils/ids.ts +9 -2
  385. package/src/utils/incremental-reader.ts +14 -3
  386. package/src/utils/internal-error.ts +2 -1
  387. package/src/utils/names.ts +12 -3
  388. package/src/utils/paths.ts +49 -5
  389. package/src/utils/project-detector.ts +2 -2
  390. package/src/utils/redaction.ts +29 -19
  391. package/src/utils/resolve-shell.ts +9 -7
  392. package/src/utils/run-watcher-registry.ts +19 -31
  393. package/src/utils/safe-paths.ts +46 -29
  394. package/src/utils/scan-cache.ts +9 -2
  395. package/src/utils/session-utils.ts +2 -4
  396. package/src/utils/sleep.ts +12 -5
  397. package/src/utils/sse-parser.ts +5 -17
  398. package/src/utils/visual.ts +52 -32
  399. package/src/workflows/discover-workflows.ts +41 -109
  400. package/src/workflows/intermediate-store.ts +5 -21
  401. package/src/workflows/preflight-validator.ts +6 -33
  402. package/src/workflows/topology-analyzer.ts +5 -21
  403. package/src/workflows/workflow-config.ts +7 -6
  404. package/src/worktree/branch-freshness.ts +66 -8
  405. package/src/worktree/cleanup.ts +130 -20
  406. package/src/worktree/worktree-manager.ts +212 -69
  407. package/skills/artifact-analysis-loop/SKILL.md +0 -303
  408. package/skills/detection-pipeline-design/SKILL.md +0 -286
  409. package/skills/hunting-investigation-loop/SKILL.md +0 -402
  410. package/skills/incident-playbook-construction/SKILL.md +0 -384
  411. package/skills/security-review/SKILL.md +0 -561
  412. package/skills/threat-hypothesis-framework/SKILL.md +0 -176
  413. package/skills/ui-render-performance/SKILL.md +0 -58
  414. /package/docs/{followup-review-round3-2026-05-12.md → archive/followup-review-round3-2026-05-12.md} +0 -0
  415. /package/docs/{followup-review-round4-2026-05-13.md → archive/followup-review-round4-2026-05-13.md} +0 -0
  416. /package/docs/{pi-crew-bugs.md → archive/pi-crew-bugs.md} +0 -0
  417. /package/docs/{pi-crew-test-final.md → archive/pi-crew-test-final.md} +0 -0
  418. /package/docs/{pi-crew-test-results.md → archive/pi-crew-test-results.md} +0 -0
  419. /package/docs/{pi-crew-test-round2.md → archive/pi-crew-test-round2.md} +0 -0
  420. /package/docs/{pi-crew-test-round4.md → archive/pi-crew-test-round4.md} +0 -0
  421. /package/docs/{pi-crew-test-round5.md → archive/pi-crew-test-round5.md} +0 -0
  422. /package/docs/{pi-crew-test-round6.md → archive/pi-crew-test-round6.md} +0 -0
  423. /package/docs/{pi-crew-v0.5.10-audit-fix-plan.md → archive/pi-crew-v0.5.10-audit-fix-plan.md} +0 -0
  424. /package/docs/{pi-crew-v0.5.11-audit-fix-plan.md → archive/pi-crew-v0.5.11-audit-fix-plan.md} +0 -0
  425. /package/docs/{pi-crew-v0.5.12-audit-fix-plan.md → archive/pi-crew-v0.5.12-audit-fix-plan.md} +0 -0
  426. /package/docs/{pi-crew-v0.5.13-audit-fix-plan.md → archive/pi-crew-v0.5.13-audit-fix-plan.md} +0 -0
  427. /package/docs/{pi-crew-v0.5.14-audit-fix-plan.md → archive/pi-crew-v0.5.14-audit-fix-plan.md} +0 -0
  428. /package/docs/{pi-crew-v0.5.16-audit-fix-plan.md → archive/pi-crew-v0.5.16-audit-fix-plan.md} +0 -0
  429. /package/docs/{pi-crew-v0.5.17-audit-fix-plan.md → archive/pi-crew-v0.5.17-audit-fix-plan.md} +0 -0
  430. /package/docs/{pi-crew-v0.5.5-audit-fix-plan.md → archive/pi-crew-v0.5.5-audit-fix-plan.md} +0 -0
  431. /package/docs/{pi-crew-v0.5.9-audit-fix-plan.md → archive/pi-crew-v0.5.9-audit-fix-plan.md} +0 -0
  432. /package/docs/{pi-mono-opportunities.md → archive/pi-mono-opportunities.md} +0 -0
  433. /package/docs/{pi-mono-review.md → archive/pi-mono-review.md} +0 -0
  434. /package/docs/{pi-subagent4-comparison.md → archive/pi-subagent4-comparison.md} +0 -0
  435. /package/docs/{pi-subagents3-deep-analysis.md → archive/pi-subagents3-deep-analysis.md} +0 -0
@@ -1,8 +1,7 @@
1
1
  import * as fs from "node:fs";
2
- import { readEvents, type TeamEvent } from "./event-log.ts";
3
- import { atomicWriteFile } from "./atomic-write.ts";
4
2
  import { logInternalError } from "../utils/internal-error.ts";
5
- import { withEventLogLockSync } from "./event-log.ts";
3
+ import { atomicWriteFile } from "./atomic-write.ts";
4
+ import { readEvents, type TeamEvent, withEventLogLockSync } from "./event-log.ts";
6
5
 
7
6
  export interface RotationConfig {
8
7
  maxFileSizeBytes: number;
@@ -82,12 +81,25 @@ export function compactEventLog(eventsPath: string, config?: Partial<RotationCon
82
81
  /** Round 24 (BUG 1): the lock-free pre-read for compaction. Safe to run
83
82
  * outside the lock (read-only). Returns the compacted lines + stats needed
84
83
  * for the write phase. */
85
- export function prepareCompaction(eventsPath: string, config?: Partial<RotationConfig>):
86
- { lines: string; originalSize: number; originalCount: number; kept: TeamEvent[] } | undefined {
84
+ export function prepareCompaction(
85
+ eventsPath: string,
86
+ config?: Partial<RotationConfig>,
87
+ ):
88
+ | {
89
+ lines: string;
90
+ originalSize: number;
91
+ originalCount: number;
92
+ kept: TeamEvent[];
93
+ }
94
+ | undefined {
87
95
  if (!fs.existsSync(eventsPath)) return undefined;
88
96
  const cfg = resolveConfig(config);
89
97
  let originalSize: number;
90
- try { originalSize = fs.statSync(eventsPath).size; } catch { return undefined; }
98
+ try {
99
+ originalSize = fs.statSync(eventsPath).size;
100
+ } catch {
101
+ return undefined;
102
+ }
91
103
  const allEvents = readEvents(eventsPath);
92
104
  const originalCount = allEvents.length;
93
105
  if (originalCount <= cfg.compactToCount) return undefined;
@@ -100,7 +112,12 @@ export function prepareCompaction(eventsPath: string, config?: Partial<RotationC
100
112
  * caller ALREADY holds the event-log lock (or accepts the unlocked race). */
101
113
  export function applyCompactionUnlocked(
102
114
  eventsPath: string,
103
- prepared: { lines: string; originalSize: number; originalCount: number; kept: TeamEvent[] },
115
+ prepared: {
116
+ lines: string;
117
+ originalSize: number;
118
+ originalCount: number;
119
+ kept: TeamEvent[];
120
+ },
104
121
  ): CompactionResult | undefined {
105
122
  const { lines, originalSize, originalCount, kept } = prepared;
106
123
  try {
@@ -250,16 +267,24 @@ export function getEventLogStats(eventsPath: string): EventLogStats | undefined
250
267
  let searchFrom = tailStr.length;
251
268
  for (;;) {
252
269
  const nl = tailStr.lastIndexOf("\n", searchFrom - 1);
253
- if (nl < 0) { lastLine = tailStr.trim(); break; }
270
+ if (nl < 0) {
271
+ lastLine = tailStr.trim();
272
+ break;
273
+ }
254
274
  const candidate = tailStr.slice(nl + 1, searchFrom).trim();
255
- if (candidate) { lastLine = candidate; break; }
275
+ if (candidate) {
276
+ lastLine = candidate;
277
+ break;
278
+ }
256
279
  searchFrom = nl;
257
280
  }
258
281
  try {
259
282
  if (lastLine) {
260
283
  newestTimestamp = (JSON.parse(lastLine) as { time: string }).time;
261
284
  }
262
- } catch { /* corrupt tail */ }
285
+ } catch {
286
+ /* corrupt tail */
287
+ }
263
288
  }
264
289
 
265
290
  // Stream-scan to count newlines and find first line boundary.
@@ -280,9 +305,9 @@ export function getEventLogStats(eventsPath: string): EventLogStats | undefined
280
305
  }
281
306
  offset += bytesRead;
282
307
  }
283
- } finally {
284
- fs.closeSync(scanFd);
285
- }
308
+ } finally {
309
+ fs.closeSync(scanFd);
310
+ }
286
311
  eventCount = newlineCount;
287
312
 
288
313
  // Read first line for oldest timestamp.
@@ -300,7 +325,9 @@ export function getEventLogStats(eventsPath: string): EventLogStats | undefined
300
325
  if (firstLine) {
301
326
  oldestTimestamp = (JSON.parse(firstLine) as { time: string }).time;
302
327
  }
303
- } catch { /* corrupt head */ }
328
+ } catch {
329
+ /* corrupt head */
330
+ }
304
331
  }
305
332
 
306
333
  return {
@@ -313,4 +340,3 @@ export function getEventLogStats(eventsPath: string): EventLogStats | undefined
313
340
  return undefined;
314
341
  }
315
342
  }
316
-
@@ -1,16 +1,23 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import * as fs from "node:fs";
3
3
  import * as path from "node:path";
4
- import { isWorkerAtomicWriterEnabled, appendFileViaWorker } from "./worker-atomic-writer.ts";
5
4
  import { DEFAULT_EVENT_LOG } from "../config/defaults.ts";
6
- import { atomicWriteFile } from "./atomic-write.ts";
7
5
  import { errors } from "../errors.ts";
8
6
  import { emitFromTeamEvent } from "../ui/run-event-bus.ts";
7
+ import { type IncrementalReadState, readJsonlSince } from "../utils/incremental-reader.ts";
9
8
  import { logInternalError } from "../utils/internal-error.ts";
10
- import { readJsonlSince, type IncrementalReadState } from "../utils/incremental-reader.ts";
11
9
  import { redactSecrets } from "../utils/redaction.ts";
12
10
  import { sleepSync } from "../utils/sleep.ts";
13
- import { needsRotation, compactEventLog, rotateEventLog, applyCompactionUnlocked, prepareCompaction, rotateEventLogUnlocked } from "./event-log-rotation.ts";
11
+ import { atomicWriteFile } from "./atomic-write.ts";
12
+ import {
13
+ applyCompactionUnlocked,
14
+ compactEventLog,
15
+ needsRotation,
16
+ prepareCompaction,
17
+ rotateEventLog,
18
+ rotateEventLogUnlocked,
19
+ } from "./event-log-rotation.ts";
20
+ import { appendFileViaWorker, isWorkerAtomicWriterEnabled } from "./worker-atomic-writer.ts";
14
21
 
15
22
  export type TeamEventProvenance = "live_worker" | "test" | "healthcheck" | "replay" | "api" | "background" | "team_runner";
16
23
  export type TeamWatcherAction = "act" | "observe" | "ignore";
@@ -54,7 +61,9 @@ export interface TeamEvent {
54
61
  metadata?: TeamEventMetadata;
55
62
  }
56
63
 
57
- export type AppendTeamEvent = Omit<TeamEvent, "time" | "metadata"> & { metadata?: Partial<TeamEventMetadata> };
64
+ export type AppendTeamEvent = Omit<TeamEvent, "time" | "metadata"> & {
65
+ metadata?: Partial<TeamEventMetadata>;
66
+ };
58
67
 
59
68
  const TERMINAL_EVENT_TYPES = new Set<string>(DEFAULT_EVENT_LOG.terminalEventTypes);
60
69
  const MAX_EVENTS_BYTES = 50 * 1024 * 1024;
@@ -99,7 +108,11 @@ export function withEventLogLockSync<T>(eventsPath: string, fn: () => T, options
99
108
  // the stale lock in one operation, eliminating the race. The 5s timeout
100
109
  // (reduced from 120s) is appropriate.
101
110
  fs.mkdirSync(lockDir);
102
- try { fs.writeFileSync(pidFile, String(process.pid), "utf-8"); } catch { /* best-effort */ }
111
+ try {
112
+ fs.writeFileSync(pidFile, String(process.pid), "utf-8");
113
+ } catch {
114
+ /* best-effort */
115
+ }
103
116
  acquired = true;
104
117
  break;
105
118
  } catch {
@@ -122,7 +135,9 @@ export function withEventLogLockSync<T>(eventsPath: string, fn: () => T, options
122
135
  fs.rmSync(lockDir, { recursive: true, force: true });
123
136
  continue;
124
137
  }
125
- } catch { /* dir vanished — let loop retry */ }
138
+ } catch {
139
+ /* dir vanished — let loop retry */
140
+ }
126
141
  // Round 26 (BUG 4): the mtime check was previously NESTED inside
127
142
  // `if (!alive)`, so a recycled PID (crashed holder's PID reused by an
128
143
  // unrelated live process) kept `alive=true` and the mtime check NEVER
@@ -135,11 +150,18 @@ export function withEventLogLockSync<T>(eventsPath: string, fn: () => T, options
135
150
  const ownerPid = Number.parseInt(raw, 10);
136
151
  if (!Number.isNaN(ownerPid) && ownerPid !== process.pid) {
137
152
  let alive = false;
138
- try { process.kill(ownerPid, 0); alive = true; } catch { /* dead */ }
153
+ try {
154
+ process.kill(ownerPid, 0);
155
+ alive = true;
156
+ } catch {
157
+ /* dead */
158
+ }
139
159
  // (mtime already handled above; nothing to do here for dead-but-fresh.)
140
160
  void alive;
141
161
  }
142
- } catch { /* no pid file — mtime check above already handles it */ }
162
+ } catch {
163
+ /* no pid file — mtime check above already handles it */
164
+ }
143
165
  sleepSync(10);
144
166
  }
145
167
  }
@@ -159,7 +181,9 @@ export function withEventLogLockSync<T>(eventsPath: string, fn: () => T, options
159
181
  if (currentPid === String(process.pid)) {
160
182
  fs.rmSync(lockDir, { recursive: true, force: true });
161
183
  }
162
- } catch { /* lock stolen or already gone — do not touch */ }
184
+ } catch {
185
+ /* lock stolen or already gone — do not touch */
186
+ }
163
187
  }
164
188
  }
165
189
  }
@@ -183,7 +207,12 @@ export function __test__sequenceCacheSize(): number {
183
207
 
184
208
  /** @internal — seed an entry into the sequence cache for testing. */
185
209
  export function __test__seedSequenceCache(eventsPath: string, lastAccessMs: number): void {
186
- sequenceCache.set(eventsPath, { size: 1, mtimeMs: 0, seq: 0, lastAccessMs });
210
+ sequenceCache.set(eventsPath, {
211
+ size: 1,
212
+ mtimeMs: 0,
213
+ seq: 0,
214
+ lastAccessMs,
215
+ });
187
216
  }
188
217
 
189
218
  /** @internal — expose eviction for testing. */
@@ -248,11 +277,21 @@ function nextSequence(eventsPath: string): number {
248
277
  const stored = readStoredSequence(eventsPath);
249
278
  const fileShrunk = cached && stat.size < cached.size;
250
279
  if (stored !== undefined && !fileShrunk) {
251
- sequenceCache.set(eventsPath, { size: stat.size, mtimeMs: stat.mtimeMs, seq: stored, lastAccessMs: Date.now() });
280
+ sequenceCache.set(eventsPath, {
281
+ size: stat.size,
282
+ mtimeMs: stat.mtimeMs,
283
+ seq: stored,
284
+ lastAccessMs: Date.now(),
285
+ });
252
286
  return stored + 1;
253
287
  }
254
288
  const current = scanSequence(eventsPath);
255
- sequenceCache.set(eventsPath, { size: stat.size, mtimeMs: stat.mtimeMs, seq: current, lastAccessMs: Date.now() });
289
+ sequenceCache.set(eventsPath, {
290
+ size: stat.size,
291
+ mtimeMs: stat.mtimeMs,
292
+ seq: current,
293
+ lastAccessMs: Date.now(),
294
+ });
256
295
  persistSequence(eventsPath, current);
257
296
  return current + 1;
258
297
  }
@@ -266,7 +305,17 @@ function persistSequence(eventsPath: string, seq: number): void {
266
305
  }
267
306
 
268
307
  export function computeEventFingerprint(event: Pick<TeamEvent, "type" | "runId" | "taskId" | "data">): string {
269
- return createHash("sha256").update(JSON.stringify({ type: event.type, runId: event.runId, taskId: event.taskId, data: event.data ?? null })).digest("hex").slice(0, 16);
308
+ return createHash("sha256")
309
+ .update(
310
+ JSON.stringify({
311
+ type: event.type,
312
+ runId: event.runId,
313
+ taskId: event.taskId,
314
+ data: event.data ?? null,
315
+ }),
316
+ )
317
+ .digest("hex")
318
+ .slice(0, 16);
270
319
  }
271
320
 
272
321
  /**
@@ -399,7 +448,10 @@ export async function appendEventAsync(eventsPath: string, event: AppendTeamEven
399
448
  metadata,
400
449
  };
401
450
  if (baseMetadata?.fingerprint || TERMINAL_EVENT_TYPES.has(fullEvent.type)) {
402
- metadata = { ...metadata, fingerprint: baseMetadata?.fingerprint ?? computeEventFingerprint(fullEvent) };
451
+ metadata = {
452
+ ...metadata,
453
+ fingerprint: baseMetadata?.fingerprint ?? computeEventFingerprint(fullEvent),
454
+ };
403
455
  fullEvent.metadata = metadata;
404
456
  }
405
457
 
@@ -409,7 +461,9 @@ export async function appendEventAsync(eventsPath: string, event: AppendTeamEven
409
461
  let fileStat: fs.Stats | undefined;
410
462
  try {
411
463
  fileStat = await fs.promises.stat(eventsPath).catch(() => undefined);
412
- } catch { /* file does not exist */ }
464
+ } catch {
465
+ /* file does not exist */
466
+ }
413
467
  if (!isTerminal && fileStat) {
414
468
  const stat = fileStat;
415
469
  if (stat.size > MAX_EVENTS_BYTES) {
@@ -421,7 +475,9 @@ export async function appendEventAsync(eventsPath: string, event: AppendTeamEven
421
475
  let afterCompactStat: fs.Stats | undefined;
422
476
  try {
423
477
  afterCompactStat = await fs.promises.stat(eventsPath).catch(() => undefined);
424
- } catch { /* file does not exist */ }
478
+ } catch {
479
+ /* file does not exist */
480
+ }
425
481
  if (afterCompactStat) {
426
482
  if (afterCompactStat.size > MAX_EVENTS_BYTES) {
427
483
  rotateEventLog(eventsPath);
@@ -432,10 +488,16 @@ export async function appendEventAsync(eventsPath: string, event: AppendTeamEven
432
488
  let sizeCheckStat: fs.Stats | undefined;
433
489
  try {
434
490
  sizeCheckStat = await fs.promises.stat(eventsPath).catch(() => undefined);
435
- } catch { /* file does not exist */ }
491
+ } catch {
492
+ /* file does not exist */
493
+ }
436
494
  try {
437
495
  if (sizeCheckStat && sizeCheckStat.size > MAX_EVENTS_BYTES) {
438
- logInternalError("event-log.size-limit", new Error(`events file ${eventsPath} exceeds ${MAX_EVENTS_BYTES} bytes after compaction`), `eventsPath=${eventsPath}`);
496
+ logInternalError(
497
+ "event-log.size-limit",
498
+ new Error(`events file ${eventsPath} exceeds ${MAX_EVENTS_BYTES} bytes after compaction`),
499
+ `eventsPath=${eventsPath}`,
500
+ );
439
501
  skippedDueToSize = true;
440
502
  }
441
503
  } catch (error) {
@@ -448,7 +510,10 @@ export async function appendEventAsync(eventsPath: string, event: AppendTeamEven
448
510
  if (isWorkerAtomicWriterEnabled()) {
449
511
  await appendFileViaWorker(eventsPath, line);
450
512
  } else {
451
- await fs.promises.appendFile(eventsPath, line, { encoding: "utf-8", flag: "a" });
513
+ await fs.promises.appendFile(eventsPath, line, {
514
+ encoding: "utf-8",
515
+ flag: "a",
516
+ });
452
517
  }
453
518
  // FIX: fsync to ensure event content is flushed to disk before persisting
454
519
  // the sequence number. This closes the crash window between appendFile and
@@ -466,9 +531,17 @@ export async function appendEventAsync(eventsPath: string, event: AppendTeamEven
466
531
  persistSequence(eventsPath, seq);
467
532
  }
468
533
  if (appendCounter % 100 === 0 && needsRotation(eventsPath)) {
469
- try { compactEventLog(eventsPath); } catch (error) { logInternalError("event-log.rotation", error, `eventsPath=${eventsPath}`); }
534
+ try {
535
+ compactEventLog(eventsPath);
536
+ } catch (error) {
537
+ logInternalError("event-log.rotation", error, `eventsPath=${eventsPath}`);
538
+ }
539
+ }
540
+ try {
541
+ emitFromTeamEvent(fullEvent);
542
+ } catch (error) {
543
+ logInternalError("event-log.emit", error);
470
544
  }
471
- try { emitFromTeamEvent(fullEvent); } catch (error) { logInternalError("event-log.emit", error); }
472
545
 
473
546
  // FIX: Sequence was persisted AFTER appendFile in the append block above.
474
547
  // Only update the cache here (the sidecar persist is already done).
@@ -477,12 +550,19 @@ export async function appendEventAsync(eventsPath: string, event: AppendTeamEven
477
550
  let statResult: fs.Stats | undefined;
478
551
  try {
479
552
  statResult = await fs.promises.stat(eventsPath).catch(() => undefined);
480
- } catch { /* file may not exist */ }
553
+ } catch {
554
+ /* file may not exist */
555
+ }
481
556
  if (statResult) {
482
557
  if (sequenceCache.size >= MAX_SEQUENCE_CACHE_ENTRIES) {
483
558
  evictOldestSequenceCacheEntries();
484
559
  }
485
- sequenceCache.set(eventsPath, { size: statResult.size, mtimeMs: statResult.mtimeMs, seq: finalSeq, lastAccessMs: Date.now() });
560
+ sequenceCache.set(eventsPath, {
561
+ size: statResult.size,
562
+ mtimeMs: statResult.mtimeMs,
563
+ seq: finalSeq,
564
+ lastAccessMs: Date.now(),
565
+ });
486
566
  }
487
567
  // Note: persistSequence is NOT called here again - it was already called
488
568
  // after the append to ensure the sidecar is current after the event is written.
@@ -491,22 +571,27 @@ export async function appendEventAsync(eventsPath: string, event: AppendTeamEven
491
571
  }
492
572
  return fullEvent;
493
573
  });
494
- asyncQueues.set(queueKey, next.then(
495
- () => { asyncQueues.delete(queueKey); },
496
- (error) => {
497
- // FIX: Wrap error handler in try-catch to ensure asyncQueues.delete
498
- // always runs, even if logging itself throws.
499
- try {
500
- logInternalError("event-log.async-queue", error, eventsPath);
501
- } catch {
502
- // logging failed ensure queue is still cleaned up
503
- }
504
- // FIX: Reset queue to a resolved state instead of deleting it.
505
- // This prevents cascading failures where a single transient error
506
- // (e.g., ENOSPC) causes all subsequent events on the same path to fail.
507
- asyncQueues.set(queueKey, Promise.resolve());
508
- },
509
- ));
574
+ asyncQueues.set(
575
+ queueKey,
576
+ next.then(
577
+ () => {
578
+ asyncQueues.delete(queueKey);
579
+ },
580
+ (error) => {
581
+ // FIX: Wrap error handler in try-catch to ensure asyncQueues.delete
582
+ // always runs, even if logging itself throws.
583
+ try {
584
+ logInternalError("event-log.async-queue", error, eventsPath);
585
+ } catch {
586
+ // logging failed ensure queue is still cleaned up
587
+ }
588
+ // FIX: Reset queue to a resolved state instead of deleting it.
589
+ // This prevents cascading failures where a single transient error
590
+ // (e.g., ENOSPC) causes all subsequent events on the same path to fail.
591
+ asyncQueues.set(queueKey, Promise.resolve());
592
+ },
593
+ ),
594
+ );
510
595
  return next;
511
596
  }
512
597
 
@@ -537,7 +622,10 @@ function appendEventInsideLock(eventsPath: string, event: AppendTeamEvent): Team
537
622
  metadata,
538
623
  };
539
624
  if (baseMetadata?.fingerprint || TERMINAL_EVENT_TYPES.has(fullEvent.type)) {
540
- metadata = { ...metadata, fingerprint: baseMetadata?.fingerprint ?? computeEventFingerprint(fullEvent) };
625
+ metadata = {
626
+ ...metadata,
627
+ fingerprint: baseMetadata?.fingerprint ?? computeEventFingerprint(fullEvent),
628
+ };
541
629
  fullEvent.metadata = metadata;
542
630
  }
543
631
  // H1 fix: handle overflow before appending.
@@ -573,7 +661,11 @@ function appendEventInsideLock(eventsPath: string, event: AppendTeamEvent): Team
573
661
  if (fs.existsSync(eventsPath) && fs.statSync(eventsPath).size > MAX_EVENTS_BYTES) {
574
662
  // Only reach here for non-terminal events that still overflow after compact+rotate.
575
663
  // Log and mark as not appended.
576
- logInternalError("event-log.size-limit", new Error(`events file ${eventsPath} exceeds ${MAX_EVENTS_BYTES} bytes after compaction`), `eventsPath=${eventsPath}`);
664
+ logInternalError(
665
+ "event-log.size-limit",
666
+ new Error(`events file ${eventsPath} exceeds ${MAX_EVENTS_BYTES} bytes after compaction`),
667
+ `eventsPath=${eventsPath}`,
668
+ );
577
669
  skippedDueToSize = true;
578
670
  }
579
671
  } catch (error) {
@@ -605,7 +697,12 @@ function appendEventInsideLock(eventsPath: string, event: AppendTeamEvent): Team
605
697
  if (sequenceCache.size >= MAX_SEQUENCE_CACHE_ENTRIES) {
606
698
  evictOldestSequenceCacheEntries();
607
699
  }
608
- sequenceCache.set(eventsPath, { size: stat.size, mtimeMs: stat.mtimeMs, seq, lastAccessMs: Date.now() });
700
+ sequenceCache.set(eventsPath, {
701
+ size: stat.size,
702
+ mtimeMs: stat.mtimeMs,
703
+ seq,
704
+ lastAccessMs: Date.now(),
705
+ });
609
706
  } catch (error) {
610
707
  logInternalError("event-log.persist-sequence", error, `eventsPath=${eventsPath}`);
611
708
  }
@@ -620,9 +717,15 @@ function appendEventInsideLock(eventsPath: string, event: AppendTeamEvent): Team
620
717
  try {
621
718
  const prepared = prepareCompaction(eventsPath);
622
719
  if (prepared) applyCompactionUnlocked(eventsPath, prepared);
623
- } catch (error) { logInternalError("event-log.rotation", error, `eventsPath=${eventsPath}`); }
720
+ } catch (error) {
721
+ logInternalError("event-log.rotation", error, `eventsPath=${eventsPath}`);
722
+ }
723
+ }
724
+ try {
725
+ emitFromTeamEvent(fullEvent);
726
+ } catch (error) {
727
+ logInternalError("event-log.emit", error);
624
728
  }
625
- try { emitFromTeamEvent(fullEvent); } catch (error) { logInternalError("event-log.emit", error); }
626
729
  return fullEvent;
627
730
  }
628
731
 
@@ -692,13 +795,17 @@ async function flushOneEventLogBuffer(eventsPath: string): Promise<void> {
692
795
  const lastDroppedMeta = dropped[dropped.length - 1]?.event.metadata;
693
796
  logInternalError(
694
797
  "event-log.buffer-overflow",
695
- new Error(`Buffer overflow #${overflowCounter}: Dropped ${dropped.length} events: first seq=${firstDroppedMeta?.seq} type=${dropped[0]?.event.type}, last seq=${lastDroppedMeta?.seq} type=${dropped[dropped.length - 1]?.event.type}`),
798
+ new Error(
799
+ `Buffer overflow #${overflowCounter}: Dropped ${dropped.length} events: first seq=${firstDroppedMeta?.seq} type=${dropped[0]?.event.type}, last seq=${lastDroppedMeta?.seq} type=${dropped[dropped.length - 1]?.event.type}`,
800
+ ),
696
801
  `${eventsPath}: ${queue.length + dropped.length} entries > 1000 cap`,
697
802
  );
698
803
  for (const item of dropped) {
699
- item.reject(new Error(
700
- `Event log buffer overflow: ${queue.length + dropped.length} entries > 1000 cap; oldest ${dropped.length} dropped to keep memory bounded; first dropped seq=${firstDroppedMeta?.seq} type=${dropped[0]?.event.type}`,
701
- ));
804
+ item.reject(
805
+ new Error(
806
+ `Event log buffer overflow: ${queue.length + dropped.length} entries > 1000 cap; oldest ${dropped.length} dropped to keep memory bounded; first dropped seq=${firstDroppedMeta?.seq} type=${dropped[0]?.event.type}`,
807
+ ),
808
+ );
702
809
  }
703
810
  }
704
811
 
@@ -757,7 +864,11 @@ process.on("SIGINT", () => setImmediate(() => flushEventLogBuffer()));
757
864
  // abandoned on crash; clearing the map prevents memory leaks and stale state.
758
865
  // Note: SIGKILL (kill -9) cannot be intercepted and is not handled.
759
866
  process.on("uncaughtException", (error) => {
760
- try { flushEventLogBuffer(); } catch { /* best-effort */ }
867
+ try {
868
+ flushEventLogBuffer();
869
+ } catch {
870
+ /* best-effort */
871
+ }
761
872
  // FIX (Issue 1): Drain asyncQueues before clearing to minimize event loss.
762
873
  drainAsyncQueues();
763
874
  asyncQueues.clear();
@@ -767,13 +878,17 @@ process.on("uncaughtException", (error) => {
767
878
 
768
879
  export function readEvents(eventsPath: string): TeamEvent[] {
769
880
  if (!fs.existsSync(eventsPath)) return [];
770
- return fs.readFileSync(eventsPath, "utf-8")
881
+ return fs
882
+ .readFileSync(eventsPath, "utf-8")
771
883
  .split("\n")
772
884
  .map((line) => line.trim())
773
885
  .filter(Boolean)
774
886
  .flatMap((line) => {
775
- try { return [JSON.parse(line) as TeamEvent]; }
776
- catch { return []; }
887
+ try {
888
+ return [JSON.parse(line) as TeamEvent];
889
+ } catch {
890
+ return [];
891
+ }
777
892
  });
778
893
  }
779
894
 
@@ -11,7 +11,17 @@ import type { TeamEvent } from "./event-log.ts";
11
11
  import { readEvents } from "./event-log.ts";
12
12
 
13
13
  /** Task status values that can be reconstructed from lifecycle events. */
14
- const RECONSTRUCTABLE_STATUSES = new Set(["created", "queued", "running", "completed", "failed", "cancelled", "skipped", "waiting", "needs_attention"]);
14
+ const RECONSTRUCTABLE_STATUSES = new Set([
15
+ "created",
16
+ "queued",
17
+ "running",
18
+ "completed",
19
+ "failed",
20
+ "cancelled",
21
+ "skipped",
22
+ "waiting",
23
+ "needs_attention",
24
+ ]);
15
25
 
16
26
  /** Event types that carry task lifecycle state transitions. */
17
27
  const TASK_LIFECYCLE_EVENT_TYPES = new Set([
@@ -25,18 +25,12 @@ const CREW_GITIGNORE_ENTRIES = [
25
25
  */
26
26
  export async function updateGitignore(gitignorePath: string): Promise<void> {
27
27
  if (!fs.existsSync(gitignorePath)) {
28
- fs.writeFileSync(
29
- gitignorePath,
30
- CREW_GITIGNORE_ENTRIES.join("\n") + "\n",
31
- "utf-8",
32
- );
28
+ fs.writeFileSync(gitignorePath, CREW_GITIGNORE_ENTRIES.join("\n") + "\n", "utf-8");
33
29
  return;
34
30
  }
35
31
 
36
32
  const current = fs.readFileSync(gitignorePath, "utf-8");
37
- const existingLines = new Set(
38
- current.split("\n").map((line) => line.trim()),
39
- );
33
+ const existingLines = new Set(current.split("\n").map((line) => line.trim()));
40
34
 
41
35
  let appended = "";
42
36
  for (const entry of CREW_GITIGNORE_ENTRIES) {