pi-crew 0.9.15 → 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 +145 -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 +193 -40
  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 +86 -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
@@ -120,7 +120,7 @@ export function isSecretKey(keyName: string): boolean {
120
120
  // Boundary chars that may precede an "authorization:" or "Bearer " keyword.
121
121
  // Includes '-' so prefixed headers (Proxy-Authorization, X-Authorization) and
122
122
  // '\t' so tab-indented headers are recognized. See security review L5.
123
- const AUTH_HEADER_BOUNDARY_CHARS = new Set([" ", ",", "{", "[", "\"", "\r", "\n", "-", "\t"]);
123
+ const AUTH_HEADER_BOUNDARY_CHARS = new Set([" ", ",", "{", "[", '"', "\r", "\n", "-", "\t"]);
124
124
  function isAuthHeaderBoundary(ch: string | undefined): boolean {
125
125
  return ch !== undefined && AUTH_HEADER_BOUNDARY_CHARS.has(ch);
126
126
  }
@@ -133,8 +133,8 @@ function isAuthHeaderBoundary(ch: string | undefined): boolean {
133
133
  export function redactAuthHeader(line: string): string {
134
134
  const lower = line.toLowerCase();
135
135
  let result = "";
136
- let i = 0; // emit cursor into the original `line`
137
- let searchFrom = 0; // cursor for the next indexOf scan
136
+ let i = 0; // emit cursor into the original `line`
137
+ let searchFrom = 0; // cursor for the next indexOf scan
138
138
  for (;;) {
139
139
  const authIdx = lower.indexOf("authorization:", searchFrom);
140
140
  if (authIdx === -1) {
@@ -172,7 +172,7 @@ export function redactBearerTokens(line: string): string {
172
172
  const upper = line.toUpperCase();
173
173
  const result: string[] = [];
174
174
  let i = 0;
175
-
175
+
176
176
  while (i < line.length) {
177
177
  if (upper.startsWith("BEARER ", i)) {
178
178
  // Check word boundary: start-of-string or a boundary char. Includes '-'
@@ -182,7 +182,7 @@ export function redactBearerTokens(line: string): string {
182
182
  i++;
183
183
  continue;
184
184
  }
185
-
185
+
186
186
  // Found "Bearer " - now find the token
187
187
  const bearerPrefix = line.substring(i, i + 7); // "Bearer "
188
188
  let j = i + 7;
@@ -191,7 +191,7 @@ export function redactBearerTokens(line: string): string {
191
191
  j++;
192
192
  tokenLen++;
193
193
  }
194
-
194
+
195
195
  if (tokenLen >= 8) {
196
196
  // Replace with Bearer + *** (redact the token)
197
197
  result.push(bearerPrefix + "***");
@@ -202,29 +202,30 @@ export function redactBearerTokens(line: string): string {
202
202
  result.push(line[i]);
203
203
  i++;
204
204
  }
205
-
205
+
206
206
  return result.join("");
207
207
  }
208
208
 
209
209
  function isRecord(value: unknown): value is Record<string, unknown> {
210
210
  if (!value || typeof value !== "object" || Array.isArray(value)) return false;
211
- if (value instanceof Date || value instanceof RegExp || value instanceof Error || value instanceof Map || value instanceof Set) return false;
211
+ if (value instanceof Date || value instanceof RegExp || value instanceof Error || value instanceof Map || value instanceof Set)
212
+ return false;
212
213
  return true;
213
214
  }
214
215
 
215
216
  export function redactSecretString(value: string): string {
216
217
  let result = value;
217
-
218
+
218
219
  // Replace PEM private keys
219
220
  result = result.replace(PEM_PRIVATE_KEY_PATTERN, "***");
220
-
221
+
221
222
  // Replace Authorization headers (non-Bearer format)
222
223
  result = redactAuthHeader(result);
223
-
224
+
224
225
  // Replace Bearer tokens (run before structured-token patterns so a
225
226
  // "Bearer <jwt>" pair is collapsed first; bare tokens are caught below).
226
227
  result = redactBearerTokens(result);
227
-
228
+
228
229
  // P1f: structured secret tokens (JWT / GitHub PAT / AWS keys + optional
229
230
  // Slack/Google/Stripe). Best-effort vs adversarial workers (see note above).
230
231
  result = result
@@ -234,10 +235,10 @@ export function redactSecretString(value: string): string {
234
235
  .replace(SLACK_TOKEN_PATTERN, "***")
235
236
  .replace(GOOGLE_API_KEY_PATTERN, "***")
236
237
  .replace(STRIPE_KEY_PATTERN, "***");
237
-
238
+
238
239
  // Replace inline secrets: key=value or key:value patterns
239
240
  result = redactInlineSecrets(result);
240
-
241
+
241
242
  return result;
242
243
  }
243
244
 
@@ -254,8 +255,8 @@ export function redactSecretString(value: string): string {
254
255
  function isKeyChar(c: string): boolean {
255
256
  const code = c.charCodeAt(0);
256
257
  return (
257
- (code >= 48 && code <= 57) || // 0-9
258
- (code >= 65 && code <= 90) || // A-Z
258
+ (code >= 48 && code <= 57) || // 0-9
259
+ (code >= 65 && code <= 90) || // A-Z
259
260
  (code >= 97 && code <= 122) || // a-z
260
261
  code === 95 || // _
261
262
  code === 45 // -
@@ -275,7 +276,7 @@ function redactInlineSecrets(value: string): string {
275
276
  const keyLen = j - i;
276
277
 
277
278
  let redacted = false;
278
- if (keyLen > 0 && j < value.length && (value[j] === '=' || value[j] === ':')) {
279
+ if (keyLen > 0 && j < value.length && (value[j] === "=" || value[j] === ":")) {
279
280
  const key = value.substring(i, j);
280
281
 
281
282
  // Check if this is a secret key
@@ -284,7 +285,16 @@ function redactInlineSecrets(value: string): string {
284
285
  const sep = value[j];
285
286
  let k = j + 1;
286
287
  let valLen = 0;
287
- while (k < value.length && valLen < 500 && value[k] !== ' ' && value[k] !== ',' && value[k] !== ';' && value[k] !== '"' && value[k] !== '\r' && value[k] !== '\n') {
288
+ while (
289
+ k < value.length &&
290
+ valLen < 500 &&
291
+ value[k] !== " " &&
292
+ value[k] !== "," &&
293
+ value[k] !== ";" &&
294
+ value[k] !== '"' &&
295
+ value[k] !== "\r" &&
296
+ value[k] !== "\n"
297
+ ) {
288
298
  k++;
289
299
  valLen++;
290
300
  }
@@ -334,4 +344,4 @@ export function redactJsonLine(line: string): string {
334
344
  } catch {
335
345
  return redactSecretString(line);
336
346
  }
337
- }
347
+ }
@@ -5,11 +5,7 @@ import * as fs from "node:fs";
5
5
  */
6
6
  export function resolveBashCmd(): string {
7
7
  if (process.platform !== "win32") return "bash";
8
- const candidates = [
9
- process.env.SHELL,
10
- "C:\\Program Files\\Git\\bin\\bash.exe",
11
- "C:\\Program Files (x86)\\Git\\bin\\bash.exe",
12
- ];
8
+ const candidates = [process.env.SHELL, "C:\\Program Files\\Git\\bin\\bash.exe", "C:\\Program Files (x86)\\Git\\bin\\bash.exe"];
13
9
  for (const cand of candidates) {
14
10
  if (cand && fs.existsSync(cand)) return cand;
15
11
  }
@@ -20,14 +16,20 @@ export function resolveBashCmd(): string {
20
16
  * Choose the right shell command and arguments for a script path.
21
17
  * On Windows, powershell (.ps1) and batch (.cmd/.bat) run natively.
22
18
  */
23
- export function resolveShellForScript(scriptPath: string): { command: string; args: string[] } {
19
+ export function resolveShellForScript(scriptPath: string): {
20
+ command: string;
21
+ args: string[];
22
+ } {
24
23
  if (process.platform === "win32") {
25
24
  if (scriptPath.endsWith(".ps1")) {
26
25
  return { command: "powershell", args: ["-File", scriptPath] };
27
26
  }
28
27
  if (scriptPath.endsWith(".cmd") || scriptPath.endsWith(".bat")) {
29
28
  // Node >= 20 blocks direct spawn of .bat/.cmd without shell (CVE-2024-27980)
30
- return { command: process.env.ComSpec ?? "cmd.exe", args: ["/d", "/s", "/c", scriptPath] };
29
+ return {
30
+ command: process.env.ComSpec ?? "cmd.exe",
31
+ args: ["/d", "/s", "/c", scriptPath],
32
+ };
31
33
  }
32
34
  }
33
35
  return { command: resolveBashCmd(), args: [scriptPath] };
@@ -46,29 +46,26 @@ export class RunWatcherRegistry {
46
46
  * brand-new run, because `crew.run.created` is never emitted by the runtime
47
47
  * (confirmed: only `crew.run.completed/failed/cancelled` are emitted).
48
48
  */
49
- setRootWatcher(
50
- runsDir: string,
51
- onNewRun: RunChangeCallback,
52
- onError?: ErrorCallback,
53
- ): void {
49
+ setRootWatcher(runsDir: string, onNewRun: RunChangeCallback, onError?: ErrorCallback): void {
54
50
  if (this.closed) return;
55
51
  // Replace any prior root watcher.
56
52
  closeWatcher(this.rootWatcher);
57
- this.rootWatcher = watchWithErrorHandler(
58
- runsDir,
59
- (_eventType, filename) => {
60
- if (typeof filename !== "string" || filename.length === 0) return;
61
- // fs.watch reports directory entries as bare names (no slash on Linux).
62
- // A new run dir appears as `runs/<runId>` filename = "<runId>".
63
- // Filter obviously-not-run-id noise (files, temp, etc.) defensively.
64
- const candidate = filename.replace(/\\/g, "/").split("/")[0];
65
- if (candidate.length === 0) return;
66
- onNewRun(candidate);
67
- },
68
- (error) => {
69
- if (onError) onError(error);
70
- },
71
- ) ?? undefined;
53
+ this.rootWatcher =
54
+ watchWithErrorHandler(
55
+ runsDir,
56
+ (_eventType, filename) => {
57
+ if (typeof filename !== "string" || filename.length === 0) return;
58
+ // fs.watch reports directory entries as bare names (no slash on Linux).
59
+ // A new run dir appears as `runs/<runId>` → filename = "<runId>".
60
+ // Filter obviously-not-run-id noise (files, temp, etc.) defensively.
61
+ const candidate = filename.replace(/\\/g, "/").split("/")[0];
62
+ if (candidate.length === 0) return;
63
+ onNewRun(candidate);
64
+ },
65
+ (error) => {
66
+ if (onError) onError(error);
67
+ },
68
+ ) ?? undefined;
72
69
  }
73
70
 
74
71
  /**
@@ -76,12 +73,7 @@ export class RunWatcherRegistry {
76
73
  * inotify watch. If a watcher for this runId already exists, close + replace.
77
74
  * Returns true if a watcher is now active for this runId.
78
75
  */
79
- addRunWatcher(
80
- runId: string,
81
- runDir: string,
82
- onChange: RunChangeCallback,
83
- onError?: ErrorCallback,
84
- ): boolean {
76
+ addRunWatcher(runId: string, runDir: string, onChange: RunChangeCallback, onError?: ErrorCallback): boolean {
85
77
  if (this.closed) return false;
86
78
  const existing = this.runWatchers.get(runId);
87
79
  if (existing) closeWatcher(existing);
@@ -121,11 +113,7 @@ export class RunWatcherRegistry {
121
113
  * not yet watched, remove watchers for runs that left the active set. Returns
122
114
  * which runIds were added / removed (useful for logging + tests).
123
115
  */
124
- reconcile(
125
- activeRuns: ActiveRun[],
126
- onChange: RunChangeCallback,
127
- onError?: ErrorCallback,
128
- ): ReconcileResult {
116
+ reconcile(activeRuns: ActiveRun[], onChange: RunChangeCallback, onError?: ErrorCallback): ReconcileResult {
129
117
  if (this.closed) return { added: [], removed: [] };
130
118
  const activeIds = new Set(activeRuns.map((r) => r.runId));
131
119
  const added: string[] = [];
@@ -11,7 +11,7 @@ export function assertSafePathId(kind: string, value: string): string {
11
11
  }
12
12
 
13
13
  export function resolveContainedPath(baseDir: string, targetPath: string): string {
14
- if (targetPath.includes('\0')) {
14
+ if (targetPath.includes("\0")) {
15
15
  throw new Error(`Security: path contains null byte`);
16
16
  }
17
17
  const base = path.resolve(baseDir);
@@ -23,9 +23,10 @@ export function resolveContainedPath(baseDir: string, targetPath: string): strin
23
23
  // OS-managed symlink is wrongly rejected as "outside" the base.
24
24
  const baseNorm = resolveCanonicalPath(base);
25
25
  const resolvedNorm = resolveCanonicalPath(resolved);
26
- const relative = process.platform === "win32"
27
- ? path.relative(baseNorm.toLowerCase(), resolvedNorm.toLowerCase())
28
- : path.relative(baseNorm, resolvedNorm);
26
+ const relative =
27
+ process.platform === "win32"
28
+ ? path.relative(baseNorm.toLowerCase(), resolvedNorm.toLowerCase())
29
+ : path.relative(baseNorm, resolvedNorm);
29
30
  if (relative.startsWith("..") || path.isAbsolute(relative)) throw new Error(`Path is outside ${baseDir}: ${targetPath}`);
30
31
  return resolved;
31
32
  }
@@ -57,7 +58,9 @@ function resolveCanonicalPath(p: string): string {
57
58
  let acc = real;
58
59
  for (let i = parts.length - 1; i >= 0; i--) acc = path.join(acc, parts[i]);
59
60
  return acc;
60
- } catch { /* keep walking up */ }
61
+ } catch {
62
+ /* keep walking up */
63
+ }
61
64
  parts.push(path.basename(current));
62
65
  current = path.dirname(current);
63
66
  }
@@ -91,14 +94,20 @@ function resolveWindowsCanonical(p: string): string {
91
94
  try {
92
95
  const real = fs.realpathSync(p);
93
96
  return real;
94
- } catch { /* proceed to ancestor walk */ }
97
+ } catch {
98
+ /* proceed to ancestor walk */
99
+ }
95
100
  // Walk up to find the deepest existing ancestor
96
101
  const parts: string[] = [];
97
102
  let current = p;
98
103
  while (current !== path.dirname(current)) {
99
104
  try {
100
105
  let real: string;
101
- try { real = fs.realpathSync.native(current); } catch { real = fs.realpathSync(current); }
106
+ try {
107
+ real = fs.realpathSync.native(current);
108
+ } catch {
109
+ real = fs.realpathSync(current);
110
+ }
102
111
  // Guard against NTFS internal paths
103
112
  if (real.includes("$Extend") || real.includes("$Deleted")) throw new Error("NTFS internal path");
104
113
  // Found existing ancestor — join with remaining parts in reverse order
@@ -107,7 +116,9 @@ function resolveWindowsCanonical(p: string): string {
107
116
  real = path.join(real, parts[i]);
108
117
  }
109
118
  return real;
110
- } catch { /* keep walking */ }
119
+ } catch {
120
+ /* keep walking */
121
+ }
111
122
  parts.push(path.basename(current));
112
123
  current = path.dirname(current);
113
124
  }
@@ -161,7 +172,7 @@ function resolveWindowsCanonical(p: string): string {
161
172
  * operation is atomic and prevents TOCTOU attacks.
162
173
  */
163
174
  export function resolveRealContainedPath(baseDir: string, targetPath: string): string {
164
- if (targetPath.includes('\0')) {
175
+ if (targetPath.includes("\0")) {
165
176
  throw new Error(`Security: path contains null byte`);
166
177
  }
167
178
  const resolved = resolveContainedPath(baseDir, targetPath);
@@ -179,7 +190,9 @@ export function resolveRealContainedPath(baseDir: string, targetPath: string): s
179
190
  fs.mkdirSync(baseDir, { recursive: true });
180
191
  baseFd = fs.openSync(baseDir, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW);
181
192
  } catch (retryError) {
182
- throw new Error(`Cannot open base directory ${baseDir}: ${retryError instanceof Error ? retryError.message : String(retryError)}`);
193
+ throw new Error(
194
+ `Cannot open base directory ${baseDir}: ${retryError instanceof Error ? retryError.message : String(retryError)}`,
195
+ );
183
196
  }
184
197
  } else if (errCode === "ELOOP") {
185
198
  // On macOS, system directories like /var → /private/var contain symlinks.
@@ -192,7 +205,9 @@ export function resolveRealContainedPath(baseDir: string, targetPath: string): s
192
205
  baseDir = realBaseDir; // update for later use
193
206
  // Fall through to fstatSync below
194
207
  }
195
- } catch { /* throw original */ }
208
+ } catch {
209
+ /* throw original */
210
+ }
196
211
  }
197
212
  if (baseFd === undefined) throw new Error("Refusing to resolve: baseDir path contains a symlink: " + baseDir);
198
213
  } else {
@@ -235,15 +250,15 @@ export function resolveRealContainedPath(baseDir: string, targetPath: string): s
235
250
  fs.closeSync(fd);
236
251
  } catch (error) {
237
252
  if ((error as NodeJS.ErrnoException).code === "ELOOP") {
238
- // On macOS, /var → /private/var, /tmp → /private/tmp, /etc → /private/etc
239
- // are system symlinks managed by the OS. Allow them.
240
- if (process.platform === "darwin") {
241
- const resolvedSymlink = resolvedAccumulated;
242
- const knownDarwinSymlinks = ["/var", "/tmp", "/etc", "/private/var", "/private/tmp", "/private/etc"];
243
- if (knownDarwinSymlinks.includes(resolvedSymlink)) continue;
253
+ // On macOS, /var → /private/var, /tmp → /private/tmp, /etc → /private/etc
254
+ // are system symlinks managed by the OS. Allow them.
255
+ if (process.platform === "darwin") {
256
+ const resolvedSymlink = resolvedAccumulated;
257
+ const knownDarwinSymlinks = ["/var", "/tmp", "/etc", "/private/var", "/private/tmp", "/private/etc"];
258
+ if (knownDarwinSymlinks.includes(resolvedSymlink)) continue;
259
+ }
260
+ throw new Error("Refusing to resolve: target path ancestor is a symlink: " + resolvedAccumulated);
244
261
  }
245
- throw new Error("Refusing to resolve: target path ancestor is a symlink: " + resolvedAccumulated);
246
- }
247
262
  // EPERM on Windows when opening a directory — skip validation
248
263
  if ((error as NodeJS.ErrnoException).code === "EPERM" && process.platform === "win32") continue;
249
264
  // ENOENT means component doesn't exist — that's OK. Only existing symlinks
@@ -265,7 +280,8 @@ export function resolveRealContainedPath(baseDir: string, targetPath: string): s
265
280
  try {
266
281
  targetFd = fs.openSync(resolved, O_RDONLY | O_NOFOLLOW);
267
282
  } catch (error) {
268
- if ((error as NodeJS.ErrnoException).code === "ELOOP") throw new Error("Refusing to resolve: target path is a symlink: " + resolved);
283
+ if ((error as NodeJS.ErrnoException).code === "ELOOP")
284
+ throw new Error("Refusing to resolve: target path is a symlink: " + resolved);
269
285
  // EPERM on Windows when opening a directory — treat as non-existent
270
286
  if ((error as NodeJS.ErrnoException).code === "EPERM" && process.platform === "win32") return resolved;
271
287
  if ((error as NodeJS.ErrnoException).code === "ENOENT") {
@@ -288,7 +304,9 @@ export function resolveRealContainedPath(baseDir: string, targetPath: string): s
288
304
  // We already validated all ancestors are not symlinks above.
289
305
  return resolved;
290
306
  }
291
- throw new Error(`Cannot resolve real path of ${resolved}: ${targetError instanceof Error ? targetError.message : String(targetError)}`);
307
+ throw new Error(
308
+ `Cannot resolve real path of ${resolved}: ${targetError instanceof Error ? targetError.message : String(targetError)}`,
309
+ );
292
310
  } finally {
293
311
  fs.closeSync(targetFd);
294
312
  }
@@ -330,7 +348,9 @@ export function resolveRealContainedPath(baseDir: string, targetPath: string): s
330
348
  // ENOENT on an ancestor of realTarget after realpathSync is concerning
331
349
  // — the path existed when we validated it but now doesn't. This could
332
350
  // indicate a race or attack. For safety, treat this as an error.
333
- throw new Error(`Cannot validate resolved path: ${ancestor} disappeared after realpathSync: ${error instanceof Error ? error.message : String(error)}`);
351
+ throw new Error(
352
+ `Cannot validate resolved path: ${ancestor} disappeared after realpathSync: ${error instanceof Error ? error.message : String(error)}`,
353
+ );
334
354
  }
335
355
  ancestor = path.dirname(ancestor);
336
356
  }
@@ -354,12 +374,13 @@ export function resolveRealContainedPath(baseDir: string, targetPath: string): s
354
374
  }
355
375
 
356
376
  export function resolveContainedRelativePath(baseDir: string, relativePath: string, kind = "path"): string {
357
- if (relativePath.includes('\0')) {
377
+ if (relativePath.includes("\0")) {
358
378
  throw new Error(`Security: path contains null byte: ${kind}`);
359
379
  }
360
380
  const normalized = relativePath.replace(/\\/g, "/").replace(/^\.\/+/, "");
361
381
  // Detect Windows absolute paths (C:\, \\server\share) that path.isAbsolute may miss after normalization
362
382
  if (/^[A-Za-z]:/.test(normalized)) throw new Error(`Invalid ${kind}: ${relativePath}`);
363
- if (!normalized || normalized.split("/").some((segment) => segment === "..") || path.isAbsolute(normalized)) throw new Error(`Invalid ${kind}: ${relativePath}`);
383
+ if (!normalized || normalized.split("/").some((segment) => segment === "..") || path.isAbsolute(normalized))
384
+ throw new Error(`Invalid ${kind}: ${relativePath}`);
364
385
  return resolveContainedPath(baseDir, path.resolve(baseDir, normalized));
365
386
  }
@@ -106,7 +106,14 @@ export class SharedScanCache {
106
106
  if (cached && cached.mtimeMs >= stat.mtimeMs && cached.sizeBytes === stat.size) return cached;
107
107
  const content = fs.readFileSync(filePath, "utf-8");
108
108
  const raw = parseJson ? JSON.parse(content) : content;
109
- const entry: ScanEntry = { key, path: filePath, raw, mtimeMs: stat.mtimeMs, sizeBytes: stat.size, loadedAtMs: this.#now() };
109
+ const entry: ScanEntry = {
110
+ key,
111
+ path: filePath,
112
+ raw,
113
+ mtimeMs: stat.mtimeMs,
114
+ sizeBytes: stat.size,
115
+ loadedAtMs: this.#now(),
116
+ };
110
117
  this.set(bucket, entry);
111
118
  return entry;
112
119
  } catch {
@@ -134,4 +141,4 @@ export class SharedScanCache {
134
141
  }
135
142
 
136
143
  /** Global shared scan cache instance. */
137
- export const sharedScanCache = new SharedScanCache();
144
+ export const sharedScanCache = new SharedScanCache();
@@ -14,9 +14,7 @@
14
14
  */
15
15
  export function assertValidSessionId(id: string): void {
16
16
  if (!id || !/^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/.test(id)) {
17
- throw new Error(
18
- `Invalid session id: must be non-empty, alphanumeric with '-', '_', '.' and start/end with alphanumeric`,
19
- );
17
+ throw new Error(`Invalid session id: must be non-empty, alphanumeric with '-', '_', '.' and start/end with alphanumeric`);
20
18
  }
21
19
  }
22
20
 
@@ -79,4 +77,4 @@ export function extractSessionId(ctx: unknown): string | undefined {
79
77
  }
80
78
  if (typeof raw !== "string" || raw.length === 0) return undefined;
81
79
  return raw;
82
- }
80
+ }
@@ -16,7 +16,10 @@ export function sleepSync(ms: number): void {
16
16
  // On Unix, try spawning the `sleep` command to avoid CPU busy-wait.
17
17
  if (process.platform !== "win32" && ms >= 10) {
18
18
  try {
19
- execFileSync("sleep", [(ms / 1000).toFixed(3)], { timeout: ms + 1000, stdio: "pipe" });
19
+ execFileSync("sleep", [(ms / 1000).toFixed(3)], {
20
+ timeout: ms + 1000,
21
+ stdio: "pipe",
22
+ });
20
23
  return;
21
24
  } catch {
22
25
  // sleep command unavailable — fall through to busy-wait
@@ -39,9 +42,13 @@ export function sleep(ms: number, signal?: AbortSignal): Promise<void> {
39
42
  if (signal?.aborted) return Promise.reject(new Error("aborted"));
40
43
  return new Promise<void>((resolve, reject) => {
41
44
  const timer = setTimeout(resolve, ms);
42
- signal?.addEventListener("abort", () => {
43
- clearTimeout(timer);
44
- reject(new Error("aborted"));
45
- }, { once: true });
45
+ signal?.addEventListener(
46
+ "abort",
47
+ () => {
48
+ clearTimeout(timer);
49
+ reject(new Error("aborted"));
50
+ },
51
+ { once: true },
52
+ );
46
53
  });
47
54
  }
@@ -12,10 +12,7 @@ const MAX_EVENT_LINES = 1000;
12
12
  const MAX_DATA_SIZE = 100000; // 100KB per line
13
13
 
14
14
  /** Read newline-delimited lines from a text ReadableStream, buffering partial chunks. */
15
- async function* readLines(
16
- stream: ReadableStream<string>,
17
- signal?: AbortSignal,
18
- ): AsyncGenerator<string> {
15
+ async function* readLines(stream: ReadableStream<string>, signal?: AbortSignal): AsyncGenerator<string> {
19
16
  const reader = stream.getReader();
20
17
  let buffer = "";
21
18
  try {
@@ -29,9 +26,7 @@ async function* readLines(
29
26
  buffer += value;
30
27
  let idx: number;
31
28
  while ((idx = buffer.indexOf("\n")) !== -1) {
32
- const line = buffer.endsWith("\r\n", idx + 1)
33
- ? buffer.slice(0, idx - 1)
34
- : buffer.slice(0, idx);
29
+ const line = buffer.endsWith("\r\n", idx + 1) ? buffer.slice(0, idx - 1) : buffer.slice(0, idx);
35
30
  yield line;
36
31
  buffer = buffer.slice(idx + 1);
37
32
  }
@@ -42,10 +37,7 @@ async function* readLines(
42
37
  }
43
38
 
44
39
  /** Parse SSE events from a byte stream */
45
- export async function* readSseEvents(
46
- stream: ReadableStream<Uint8Array>,
47
- signal?: AbortSignal,
48
- ): AsyncGenerator<ServerSentEvent> {
40
+ export async function* readSseEvents(stream: ReadableStream<Uint8Array>, signal?: AbortSignal): AsyncGenerator<ServerSentEvent> {
49
41
  const textStream = stream.pipeThrough(new TextDecoderStream() as unknown as TransformStream<Uint8Array, string>);
50
42
  let currentEvent: string | null = null;
51
43
  let currentData: string[] = [];
@@ -127,15 +119,11 @@ export async function* readSseEvents(
127
119
  }
128
120
 
129
121
  /** Parse SSE events and yield parsed JSON data objects */
130
- export async function* readSseJson<T>(
131
- stream: ReadableStream<Uint8Array>,
132
- signal?: AbortSignal,
133
- ): AsyncGenerator<T> {
122
+ export async function* readSseJson<T>(stream: ReadableStream<Uint8Array>, signal?: AbortSignal): AsyncGenerator<T> {
134
123
  for await (const evt of readSseEvents(stream, signal)) {
135
124
  try {
136
125
  const parsed: T = JSON.parse(evt.data) as T;
137
126
  yield parsed;
138
- } catch {
139
- }
127
+ } catch {}
140
128
  }
141
129
  }