pi-crew 0.9.16 → 0.9.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (432) hide show
  1. package/CHANGELOG.md +81 -0
  2. package/README.md +19 -0
  3. package/dist/build-meta.json +21790 -0
  4. package/dist/index.mjs +83070 -0
  5. package/dist/index.mjs.map +7 -0
  6. package/docs/A +358 -0
  7. package/docs/M-A +357 -0
  8. package/docs/REVIEW-FINDINGS-2026-06 +357 -0
  9. package/docs/Y +357 -0
  10. package/docs/a +357 -0
  11. package/docs/aA +358 -0
  12. package/docs/archive/README.md +91 -0
  13. package/docs/patterns/command-agent-skill.md +1 -1
  14. package/docs/skills/REFERENCE.md +0 -17
  15. package/docs//303/242mmaAAA/303/242 +357 -0
  16. package/index.bundle.ts +25 -0
  17. package/index.ts +95 -4
  18. package/package.json +15 -4
  19. package/skills/iterative-audit/SKILL.md +0 -1
  20. package/skills/widget-rendering/SKILL.md +17 -0
  21. package/src/adapters/claude-adapter.ts +1 -3
  22. package/src/adapters/export-util.ts +16 -16
  23. package/src/adapters/index.ts +5 -5
  24. package/src/agents/agent-config.ts +20 -14
  25. package/src/agents/agent-serializer.ts +1 -1
  26. package/src/agents/discover-agents.ts +83 -39
  27. package/src/benchmark/benchmark-runner.ts +51 -51
  28. package/src/benchmark/feedback-loop.ts +1 -1
  29. package/src/config/config.ts +166 -590
  30. package/src/config/defaults.ts +28 -2
  31. package/src/config/drift-detector.ts +11 -14
  32. package/src/config/markers.ts +201 -203
  33. package/src/config/resilient-parser.ts +14 -6
  34. package/src/config/role-tools.ts +3 -3
  35. package/src/config/suggestions.ts +5 -12
  36. package/src/config/types.ts +9 -25
  37. package/src/errors.ts +151 -157
  38. package/src/extension/action-suggestions.ts +54 -9
  39. package/src/extension/async-notifier.ts +43 -13
  40. package/src/extension/autonomous-policy.ts +77 -37
  41. package/src/extension/command-completions.ts +9 -8
  42. package/src/extension/context-status-injection.ts +14 -12
  43. package/src/extension/crew-autocomplete.ts +8 -16
  44. package/src/extension/crew-cleanup.ts +2 -1
  45. package/src/extension/crew-shortcuts.ts +9 -6
  46. package/src/extension/cross-extension-rpc.ts +136 -42
  47. package/src/extension/help.ts +1 -1
  48. package/src/extension/import-index.ts +10 -5
  49. package/src/extension/knowledge-injection.ts +88 -15
  50. package/src/extension/management.ts +89 -349
  51. package/src/extension/message-renderers.ts +3 -4
  52. package/src/extension/notification-router.ts +22 -5
  53. package/src/extension/notification-sink.ts +6 -3
  54. package/src/extension/pi-api.ts +17 -8
  55. package/src/extension/plan-orchestrate.ts +8 -27
  56. package/src/extension/project-init.ts +21 -6
  57. package/src/extension/register.ts +329 -975
  58. package/src/extension/registration/artifact-cleanup.ts +9 -4
  59. package/src/extension/registration/command-utils.ts +5 -1
  60. package/src/extension/registration/commands.ts +806 -314
  61. package/src/extension/registration/compaction-guard.ts +15 -15
  62. package/src/extension/registration/lifecycle.ts +259 -0
  63. package/src/extension/registration/observability.ts +293 -0
  64. package/src/extension/registration/subagent-helpers.ts +29 -7
  65. package/src/extension/registration/subagent-tools.ts +253 -44
  66. package/src/extension/registration/team-tool.ts +19 -84
  67. package/src/extension/registration/ui.ts +168 -0
  68. package/src/extension/registration/viewers.ts +64 -24
  69. package/src/extension/result-watcher.ts +18 -7
  70. package/src/extension/run-bundle-schema.ts +21 -6
  71. package/src/extension/run-export.ts +15 -6
  72. package/src/extension/run-import.ts +64 -29
  73. package/src/extension/run-index.ts +28 -9
  74. package/src/extension/run-maintenance.ts +32 -12
  75. package/src/extension/session-summary.ts +1 -1
  76. package/src/extension/team-manager-command.ts +64 -7
  77. package/src/extension/team-onboard.ts +151 -150
  78. package/src/extension/team-recommendation.ts +121 -21
  79. package/src/extension/team-tool/anchor.ts +31 -64
  80. package/src/extension/team-tool/api.ts +929 -141
  81. package/src/extension/team-tool/auto-summarize.ts +14 -26
  82. package/src/extension/team-tool/cache-control.ts +1 -5
  83. package/src/extension/team-tool/cancel.ts +138 -38
  84. package/src/extension/team-tool/chain-dispatch.ts +5 -13
  85. package/src/extension/team-tool/chain-executor.ts +29 -51
  86. package/src/extension/team-tool/config-patch.ts +1 -1
  87. package/src/extension/team-tool/context.ts +40 -20
  88. package/src/extension/team-tool/destructive-gate.ts +10 -5
  89. package/src/extension/team-tool/doctor.ts +170 -51
  90. package/src/extension/team-tool/explain.ts +228 -214
  91. package/src/extension/team-tool/failure-patterns.ts +3 -9
  92. package/src/extension/team-tool/goal-wrap.ts +71 -29
  93. package/src/extension/team-tool/goal.ts +185 -35
  94. package/src/extension/team-tool/handle-schedule.ts +34 -15
  95. package/src/extension/team-tool/handle-settings.ts +94 -56
  96. package/src/extension/team-tool/health-monitor.ts +27 -108
  97. package/src/extension/team-tool/inspect.ts +42 -9
  98. package/src/extension/team-tool/intent-policy.ts +4 -1
  99. package/src/extension/team-tool/lifecycle-actions.ts +244 -48
  100. package/src/extension/team-tool/orchestrate.ts +7 -18
  101. package/src/extension/team-tool/parallel-dispatch.ts +51 -29
  102. package/src/extension/team-tool/plan.ts +29 -5
  103. package/src/extension/team-tool/respond.ts +49 -16
  104. package/src/extension/team-tool/run-not-found.ts +3 -8
  105. package/src/extension/team-tool/run.ts +80 -317
  106. package/src/extension/team-tool/status.ts +135 -43
  107. package/src/extension/team-tool/workflow-manage.ts +92 -25
  108. package/src/extension/team-tool-types.ts +8 -1
  109. package/src/extension/team-tool.ts +142 -551
  110. package/src/extension/validate-resources.ts +39 -8
  111. package/src/hooks/registry.ts +66 -17
  112. package/src/hooks/types.ts +1 -1
  113. package/src/i18n.ts +25 -11
  114. package/src/observability/correlation.ts +17 -3
  115. package/src/observability/event-bus.ts +51 -56
  116. package/src/observability/event-to-metric.ts +117 -15
  117. package/src/observability/exporters/otlp-exporter.ts +56 -17
  118. package/src/observability/exporters/prometheus-exporter.ts +1 -1
  119. package/src/observability/metric-registry.ts +16 -4
  120. package/src/observability/metric-retention.ts +8 -2
  121. package/src/observability/metric-sink.ts +11 -3
  122. package/src/observability/metrics-primitives.ts +42 -9
  123. package/src/plugins/plugin-define.ts +2 -2
  124. package/src/plugins/plugin-registry.ts +25 -25
  125. package/src/plugins/plugins/index.ts +1 -1
  126. package/src/plugins/plugins/nextjs.ts +16 -16
  127. package/src/plugins/plugins/vite.ts +7 -11
  128. package/src/plugins/plugins/vitest.ts +6 -11
  129. package/src/runtime/adaptive-plan.ts +225 -40
  130. package/src/runtime/agent-control.ts +58 -15
  131. package/src/runtime/agent-memory.ts +15 -9
  132. package/src/runtime/agent-observability.ts +10 -2
  133. package/src/runtime/anchor-manager.ts +27 -25
  134. package/src/runtime/async-marker.ts +7 -1
  135. package/src/runtime/async-runner.ts +27 -23
  136. package/src/runtime/auto-summarize.ts +7 -13
  137. package/src/runtime/background-runner.ts +189 -251
  138. package/src/runtime/batch-barrier.ts +18 -16
  139. package/src/runtime/cancellation-token.ts +16 -6
  140. package/src/runtime/cancellation.ts +46 -8
  141. package/src/runtime/capability-inventory.ts +6 -4
  142. package/src/runtime/chain-parser.ts +44 -11
  143. package/src/runtime/chain-runner.ts +63 -69
  144. package/src/runtime/checkpoint.ts +12 -56
  145. package/src/runtime/child-pi.ts +343 -78
  146. package/src/runtime/coalesce-tasks.ts +268 -0
  147. package/src/runtime/code-summary.ts +71 -26
  148. package/src/runtime/compact-stages/index.ts +15 -5
  149. package/src/runtime/compact-stages/tail-capture-stage.ts +7 -2
  150. package/src/runtime/compact-stages/truncation-stage.ts +4 -1
  151. package/src/runtime/compaction-summary.ts +17 -10
  152. package/src/runtime/completion-guard.ts +33 -16
  153. package/src/runtime/crash-classification.ts +28 -7
  154. package/src/runtime/crash-recovery.ts +177 -37
  155. package/src/runtime/crew-agent-records.ts +145 -47
  156. package/src/runtime/crew-hooks.ts +9 -24
  157. package/src/runtime/cross-extension-rpc.ts +25 -23
  158. package/src/runtime/custom-tools/irc-tool.ts +43 -15
  159. package/src/runtime/custom-tools/submit-result-tool.ts +16 -5
  160. package/src/runtime/delivery-coordinator.ts +34 -7
  161. package/src/runtime/delta-conflict.ts +9 -21
  162. package/src/runtime/deterministic-ast.ts +1 -1
  163. package/src/runtime/diagnostic-export.ts +53 -20
  164. package/src/runtime/direct-run.ts +12 -2
  165. package/src/runtime/dwf-state-store.ts +1 -1
  166. package/src/runtime/dynamic-workflow-context.ts +186 -58
  167. package/src/runtime/dynamic-workflow-runner.ts +42 -20
  168. package/src/runtime/effectiveness.ts +16 -8
  169. package/src/runtime/errors/crew-errors.ts +7 -11
  170. package/src/runtime/event-stream-bridge.ts +9 -3
  171. package/src/runtime/foreground-control.ts +54 -14
  172. package/src/runtime/foreground-watchdog.ts +9 -6
  173. package/src/runtime/goal-achievement.ts +27 -10
  174. package/src/runtime/goal-evaluator.ts +54 -19
  175. package/src/runtime/goal-loop-runner.ts +280 -99
  176. package/src/runtime/goal-state-store.ts +27 -17
  177. package/src/runtime/green-contract.ts +11 -2
  178. package/src/runtime/group-join.ts +64 -31
  179. package/src/runtime/handoff-manager.ts +37 -42
  180. package/src/runtime/heartbeat-gradient.ts +10 -2
  181. package/src/runtime/heartbeat-watcher.ts +32 -6
  182. package/src/runtime/hidden-handoff.ts +12 -30
  183. package/src/runtime/important-line-classifier.ts +12 -2
  184. package/src/runtime/iteration-hooks.ts +25 -15
  185. package/src/runtime/live-agent-control.ts +55 -7
  186. package/src/runtime/live-agent-manager.ts +130 -27
  187. package/src/runtime/live-control-realtime.ts +23 -3
  188. package/src/runtime/live-irc.ts +4 -1
  189. package/src/runtime/live-session-health.ts +12 -4
  190. package/src/runtime/live-session-runtime.ts +379 -117
  191. package/src/runtime/manifest-cache.ts +28 -12
  192. package/src/runtime/mcp-proxy.ts +8 -16
  193. package/src/runtime/metric-parser.ts +1 -5
  194. package/src/runtime/model-fallback.ts +55 -18
  195. package/src/runtime/model-resolver.ts +2 -6
  196. package/src/runtime/model-scope.ts +19 -3
  197. package/src/runtime/notebook-helpers.ts +60 -62
  198. package/src/runtime/orphan-worker-registry.ts +37 -26
  199. package/src/runtime/output-validator.ts +18 -3
  200. package/src/runtime/overflow-recovery.ts +5 -4
  201. package/src/runtime/parallel-research.ts +29 -5
  202. package/src/runtime/parallel-utils.ts +9 -11
  203. package/src/runtime/path-overlap.ts +150 -0
  204. package/src/runtime/peer-dep.ts +12 -17
  205. package/src/runtime/per-write-validator.ts +1 -3
  206. package/src/runtime/phase-tracker.ts +342 -330
  207. package/src/runtime/pi-args.ts +26 -8
  208. package/src/runtime/pi-json-output.ts +1 -1
  209. package/src/runtime/pi-spawn.ts +30 -19
  210. package/src/runtime/pipeline-runner.ts +56 -55
  211. package/src/runtime/plan-templates.ts +5 -6
  212. package/src/runtime/policy-engine.ts +43 -7
  213. package/src/runtime/post-checks.ts +12 -4
  214. package/src/runtime/post-exit-stdio-guard.ts +2 -2
  215. package/src/runtime/process-lifecycle.ts +20 -10
  216. package/src/runtime/process-status.ts +16 -5
  217. package/src/runtime/progress-event-coalescer.ts +2 -1
  218. package/src/runtime/progress-tracker.ts +103 -103
  219. package/src/runtime/prose-compressor.ts +9 -11
  220. package/src/runtime/recovery-recipes.ts +118 -24
  221. package/src/runtime/replace.ts +25 -10
  222. package/src/runtime/resilient-edit.ts +10 -25
  223. package/src/runtime/result-extractor.ts +1 -2
  224. package/src/runtime/retry-executor.ts +20 -4
  225. package/src/runtime/retry-runner.ts +26 -50
  226. package/src/runtime/role-permission.ts +6 -1
  227. package/src/runtime/run-coalesced-task-group.ts +256 -0
  228. package/src/runtime/run-drift.ts +14 -15
  229. package/src/runtime/run-tracker.ts +6 -28
  230. package/src/runtime/runtime-policy.ts +1 -6
  231. package/src/runtime/runtime-resolver.ts +80 -15
  232. package/src/runtime/scheduler.ts +47 -18
  233. package/src/runtime/semaphore.ts +5 -7
  234. package/src/runtime/sensitive-paths.ts +2 -1
  235. package/src/runtime/session-usage.ts +1 -1
  236. package/src/runtime/settings-store.ts +16 -12
  237. package/src/runtime/sidechain-output.ts +6 -2
  238. package/src/runtime/single-agent-compose.ts +1 -4
  239. package/src/runtime/skill-effectiveness.ts +29 -97
  240. package/src/runtime/skill-instructions.ts +40 -83
  241. package/src/runtime/stale-reconciler.ts +73 -197
  242. package/src/runtime/stream-preview.ts +1 -1
  243. package/src/runtime/streaming-output.ts +1 -1
  244. package/src/runtime/subagent-manager.ts +44 -169
  245. package/src/runtime/subprocess-tool-registry.ts +4 -1
  246. package/src/runtime/supervisor-contact.ts +10 -5
  247. package/src/runtime/task-display.ts +19 -5
  248. package/src/runtime/task-graph-scheduler.ts +95 -21
  249. package/src/runtime/task-graph.ts +5 -11
  250. package/src/runtime/task-health.ts +54 -47
  251. package/src/runtime/task-id.ts +11 -18
  252. package/src/runtime/task-output-context.ts +265 -81
  253. package/src/runtime/task-packet.ts +12 -20
  254. package/src/runtime/task-quality.ts +6 -14
  255. package/src/runtime/task-runner/context-retrieval.ts +4 -13
  256. package/src/runtime/task-runner/live-executor.ts +114 -36
  257. package/src/runtime/task-runner/output-splitter.ts +152 -0
  258. package/src/runtime/task-runner/progress.ts +50 -12
  259. package/src/runtime/task-runner/prompt-builder.ts +31 -7
  260. package/src/runtime/task-runner/prompt-pipeline.ts +31 -7
  261. package/src/runtime/task-runner/result-utils.ts +3 -1
  262. package/src/runtime/task-runner/retrieval-orchestrator.ts +310 -0
  263. package/src/runtime/task-runner/run-projection.ts +27 -8
  264. package/src/runtime/task-runner/state-helpers.ts +29 -8
  265. package/src/runtime/task-runner/tail-read.ts +2 -6
  266. package/src/runtime/task-runner.ts +180 -326
  267. package/src/runtime/team-runner-artifacts.ts +13 -0
  268. package/src/runtime/team-runner.ts +456 -974
  269. package/src/runtime/tool-output-pruner.ts +6 -9
  270. package/src/runtime/tool-progress.ts +11 -21
  271. package/src/runtime/verification-gates.ts +33 -24
  272. package/src/runtime/verification-integrity.ts +1 -4
  273. package/src/runtime/verification-worktree.ts +62 -12
  274. package/src/runtime/worker-heartbeat.ts +5 -1
  275. package/src/runtime/worker-startup.ts +29 -5
  276. package/src/runtime/workflow-state.ts +17 -9
  277. package/src/runtime/workspace-lock.ts +30 -35
  278. package/src/runtime/workspace-tree.ts +20 -32
  279. package/src/runtime/yield-handler.ts +43 -9
  280. package/src/runtime/zombie-scanner.ts +5 -4
  281. package/src/schema/config-schema.ts +266 -172
  282. package/src/schema/team-tool-schema.ts +29 -74
  283. package/src/schema/validation-types.ts +25 -17
  284. package/src/skills/discover-skills.ts +35 -10
  285. package/src/skills/skill-templates.ts +109 -27
  286. package/src/skills/validate.ts +26 -8
  287. package/src/state/active-run-registry.ts +87 -28
  288. package/src/state/artifact-store.ts +9 -5
  289. package/src/state/atomic-write-v2.ts +85 -63
  290. package/src/state/atomic-write.ts +105 -26
  291. package/src/state/blob-store.ts +47 -20
  292. package/src/state/contracts.ts +20 -5
  293. package/src/state/crew-init.ts +5 -22
  294. package/src/state/decision-ledger.ts +19 -73
  295. package/src/state/event-log-rotation.ts +41 -15
  296. package/src/state/event-log.ts +168 -53
  297. package/src/state/event-reconstructor.ts +11 -1
  298. package/src/state/gitignore-manager.ts +2 -8
  299. package/src/state/health-store.ts +57 -57
  300. package/src/state/hook-instinct-bridge.ts +1 -1
  301. package/src/state/hook-integrations.ts +1 -1
  302. package/src/state/instinct-store.ts +17 -5
  303. package/src/state/jsonl-writer.ts +1 -1
  304. package/src/state/locks.ts +23 -9
  305. package/src/state/mailbox.ts +151 -28
  306. package/src/state/observation-store.ts +20 -14
  307. package/src/state/run-cache.ts +142 -135
  308. package/src/state/run-graph.ts +6 -15
  309. package/src/state/run-metrics.ts +5 -18
  310. package/src/state/schedule.ts +15 -9
  311. package/src/state/state-store.ts +129 -45
  312. package/src/state/task-claims.ts +12 -2
  313. package/src/state/tiered-eval.ts +52 -43
  314. package/src/state/types-eval.ts +2 -2
  315. package/src/state/types.ts +24 -20
  316. package/src/state/usage.ts +20 -4
  317. package/src/state/worker-atomic-writer.ts +6 -3
  318. package/src/subagents/index.ts +2 -2
  319. package/src/teams/discover-teams.ts +21 -6
  320. package/src/tools/safe-bash-extension.ts +5 -6
  321. package/src/tools/safe-bash.ts +10 -11
  322. package/src/types/new-api-types.ts +6 -10
  323. package/src/ui/agent-management-overlay.ts +52 -40
  324. package/src/ui/card-colors.ts +13 -4
  325. package/src/ui/crew-footer.ts +8 -7
  326. package/src/ui/crew-select-list.ts +1 -1
  327. package/src/ui/dashboard-panes/agents-pane.ts +41 -25
  328. package/src/ui/dashboard-panes/cancellation-pane.ts +1 -1
  329. package/src/ui/dashboard-panes/capability-pane.ts +32 -15
  330. package/src/ui/dashboard-panes/health-pane.ts +2 -1
  331. package/src/ui/dashboard-panes/metrics-pane.ts +4 -1
  332. package/src/ui/dashboard-panes/progress-pane.ts +12 -9
  333. package/src/ui/heartbeat-aggregator.ts +15 -4
  334. package/src/ui/keybinding-map.ts +40 -7
  335. package/src/ui/live-conversation-overlay.ts +36 -20
  336. package/src/ui/live-duration.ts +1 -4
  337. package/src/ui/live-run-sidebar.ts +88 -25
  338. package/src/ui/loaders.ts +2 -8
  339. package/src/ui/mascot.ts +20 -36
  340. package/src/ui/overlays/agent-picker-overlay.ts +11 -3
  341. package/src/ui/overlays/confirm-overlay.ts +4 -2
  342. package/src/ui/overlays/help-overlay.ts +25 -14
  343. package/src/ui/overlays/mailbox-compose-overlay.ts +48 -11
  344. package/src/ui/overlays/mailbox-compose-preview.ts +20 -5
  345. package/src/ui/overlays/mailbox-detail-overlay.ts +27 -6
  346. package/src/ui/pi-ui-compat.ts +7 -7
  347. package/src/ui/powerbar-publisher.ts +120 -42
  348. package/src/ui/render-diff.ts +10 -3
  349. package/src/ui/render-scheduler.ts +12 -4
  350. package/src/ui/run-action-dispatcher.ts +81 -18
  351. package/src/ui/run-dashboard.ts +172 -76
  352. package/src/ui/run-event-bus.ts +59 -37
  353. package/src/ui/run-snapshot-cache.ts +276 -86
  354. package/src/ui/settings-overlay.ts +361 -74
  355. package/src/ui/status-colors.ts +12 -1
  356. package/src/ui/syntax-highlight.ts +1 -1
  357. package/src/ui/theme-adapter.ts +16 -14
  358. package/src/ui/theme-discovery.ts +13 -2
  359. package/src/ui/tool-progress-formatter.ts +7 -7
  360. package/src/ui/tool-render.ts +128 -56
  361. package/src/ui/tool-renderers/brief-mode.ts +45 -27
  362. package/src/ui/tool-renderers/index.ts +109 -43
  363. package/src/ui/transcript-cache.ts +32 -6
  364. package/src/ui/transcript-entries.ts +25 -23
  365. package/src/ui/transcript-viewer.ts +78 -29
  366. package/src/ui/widget/index.ts +99 -40
  367. package/src/ui/widget/widget-formatters.ts +13 -6
  368. package/src/ui/widget/widget-model.ts +19 -8
  369. package/src/ui/widget/widget-renderer.ts +23 -13
  370. package/src/ui/widget/widget-types.ts +1 -1
  371. package/src/utils/bm25-search.ts +199 -199
  372. package/src/utils/conflict-detect.ts +22 -21
  373. package/src/utils/env-filter.ts +14 -7
  374. package/src/utils/file-coalescer.ts +5 -1
  375. package/src/utils/fingerprint.ts +3 -6
  376. package/src/utils/frontmatter.ts +3 -1
  377. package/src/utils/fs-watch.ts +2 -6
  378. package/src/utils/gh-protocol.ts +119 -44
  379. package/src/utils/git.ts +13 -15
  380. package/src/utils/guards.ts +2 -5
  381. package/src/utils/ids.ts +9 -2
  382. package/src/utils/incremental-reader.ts +14 -3
  383. package/src/utils/internal-error.ts +2 -1
  384. package/src/utils/names.ts +12 -3
  385. package/src/utils/paths.ts +49 -5
  386. package/src/utils/project-detector.ts +2 -2
  387. package/src/utils/redaction.ts +29 -19
  388. package/src/utils/resolve-shell.ts +9 -7
  389. package/src/utils/run-watcher-registry.ts +19 -31
  390. package/src/utils/safe-paths.ts +45 -24
  391. package/src/utils/scan-cache.ts +9 -2
  392. package/src/utils/session-utils.ts +2 -4
  393. package/src/utils/sleep.ts +12 -5
  394. package/src/utils/sse-parser.ts +5 -17
  395. package/src/utils/visual.ts +52 -32
  396. package/src/workflows/discover-workflows.ts +41 -109
  397. package/src/workflows/intermediate-store.ts +5 -21
  398. package/src/workflows/preflight-validator.ts +6 -33
  399. package/src/workflows/topology-analyzer.ts +5 -21
  400. package/src/workflows/workflow-config.ts +7 -6
  401. package/src/worktree/branch-freshness.ts +66 -8
  402. package/src/worktree/cleanup.ts +130 -20
  403. package/src/worktree/worktree-manager.ts +212 -69
  404. package/skills/artifact-analysis-loop/SKILL.md +0 -303
  405. package/skills/detection-pipeline-design/SKILL.md +0 -286
  406. package/skills/hunting-investigation-loop/SKILL.md +0 -402
  407. package/skills/incident-playbook-construction/SKILL.md +0 -384
  408. package/skills/security-review/SKILL.md +0 -561
  409. package/skills/threat-hypothesis-framework/SKILL.md +0 -176
  410. package/skills/ui-render-performance/SKILL.md +0 -58
  411. /package/docs/{followup-review-round3-2026-05-12.md → archive/followup-review-round3-2026-05-12.md} +0 -0
  412. /package/docs/{followup-review-round4-2026-05-13.md → archive/followup-review-round4-2026-05-13.md} +0 -0
  413. /package/docs/{pi-crew-bugs.md → archive/pi-crew-bugs.md} +0 -0
  414. /package/docs/{pi-crew-test-final.md → archive/pi-crew-test-final.md} +0 -0
  415. /package/docs/{pi-crew-test-results.md → archive/pi-crew-test-results.md} +0 -0
  416. /package/docs/{pi-crew-test-round2.md → archive/pi-crew-test-round2.md} +0 -0
  417. /package/docs/{pi-crew-test-round4.md → archive/pi-crew-test-round4.md} +0 -0
  418. /package/docs/{pi-crew-test-round5.md → archive/pi-crew-test-round5.md} +0 -0
  419. /package/docs/{pi-crew-test-round6.md → archive/pi-crew-test-round6.md} +0 -0
  420. /package/docs/{pi-crew-v0.5.10-audit-fix-plan.md → archive/pi-crew-v0.5.10-audit-fix-plan.md} +0 -0
  421. /package/docs/{pi-crew-v0.5.11-audit-fix-plan.md → archive/pi-crew-v0.5.11-audit-fix-plan.md} +0 -0
  422. /package/docs/{pi-crew-v0.5.12-audit-fix-plan.md → archive/pi-crew-v0.5.12-audit-fix-plan.md} +0 -0
  423. /package/docs/{pi-crew-v0.5.13-audit-fix-plan.md → archive/pi-crew-v0.5.13-audit-fix-plan.md} +0 -0
  424. /package/docs/{pi-crew-v0.5.14-audit-fix-plan.md → archive/pi-crew-v0.5.14-audit-fix-plan.md} +0 -0
  425. /package/docs/{pi-crew-v0.5.16-audit-fix-plan.md → archive/pi-crew-v0.5.16-audit-fix-plan.md} +0 -0
  426. /package/docs/{pi-crew-v0.5.17-audit-fix-plan.md → archive/pi-crew-v0.5.17-audit-fix-plan.md} +0 -0
  427. /package/docs/{pi-crew-v0.5.5-audit-fix-plan.md → archive/pi-crew-v0.5.5-audit-fix-plan.md} +0 -0
  428. /package/docs/{pi-crew-v0.5.9-audit-fix-plan.md → archive/pi-crew-v0.5.9-audit-fix-plan.md} +0 -0
  429. /package/docs/{pi-mono-opportunities.md → archive/pi-mono-opportunities.md} +0 -0
  430. /package/docs/{pi-mono-review.md → archive/pi-mono-review.md} +0 -0
  431. /package/docs/{pi-subagent4-comparison.md → archive/pi-subagent4-comparison.md} +0 -0
  432. /package/docs/{pi-subagents3-deep-analysis.md → archive/pi-subagents3-deep-analysis.md} +0 -0
@@ -87,9 +87,7 @@ function parsePositiveInt(value: string): number | undefined {
87
87
  function parseListOptions(url: URL, scheme: "issue" | "pr", repo: string): ParsedListOptions {
88
88
  const allowedStates = scheme === "pr" ? ["open", "closed", "merged", "all"] : ["open", "closed", "all"];
89
89
  const stateRaw = url.searchParams.get("state");
90
- const state = (
91
- stateRaw && (allowedStates as string[]).includes(stateRaw) ? stateRaw : "open"
92
- ) as ParsedListOptions["state"];
90
+ const state = (stateRaw && (allowedStates as string[]).includes(stateRaw) ? stateRaw : "open") as ParsedListOptions["state"];
93
91
 
94
92
  let limit = LIST_LIMIT_DEFAULT;
95
93
  const limitRaw = url.searchParams.get("limit");
@@ -138,7 +136,12 @@ export function parseGitHubUrl(raw: string, scheme: "issue" | "pr"): Parsed {
138
136
 
139
137
  // Empty → list default repo
140
138
  if (!host && pathParts.length === 0) {
141
- return { kind: "list", repo: "", state: "open", limit: LIST_LIMIT_DEFAULT };
139
+ return {
140
+ kind: "list",
141
+ repo: "",
142
+ state: "open",
143
+ limit: LIST_LIMIT_DEFAULT,
144
+ };
142
145
  }
143
146
 
144
147
  // If host looks like a number, treat as single-item shorthand
@@ -147,24 +150,45 @@ export function parseGitHubUrl(raw: string, scheme: "issue" | "pr"): Parsed {
147
150
  // pathParts[0] === "diff" → scheme://N/diff[/sub] (PR diff, default repo)
148
151
  if (pathParts.length === 0) {
149
152
  const commentsParam = url.searchParams.get("comments");
150
- const comments = !(commentsParam === "0" || (commentsParam?.toLowerCase() === "false"));
151
- return { kind: "single", repo: undefined, number: parsePositiveInt(host)!, comments };
153
+ const comments = !(commentsParam === "0" || commentsParam?.toLowerCase() === "false");
154
+ return {
155
+ kind: "single",
156
+ repo: undefined,
157
+ number: parsePositiveInt(host)!,
158
+ comments,
159
+ };
152
160
  }
153
161
  if (pathParts[0] === "diff") {
154
162
  if (scheme !== "pr") throw new Error(`Invalid ${scheme}:// URL. Diff is only available for pr:// URLs.`);
155
163
  const number = parsePositiveInt(host)!;
156
164
  const diffParts = pathParts;
157
165
  if (diffParts.length === 1) {
158
- return { kind: "pr-diff", repo: undefined, number, mode: "list" };
166
+ return {
167
+ kind: "pr-diff",
168
+ repo: undefined,
169
+ number,
170
+ mode: "list",
171
+ };
159
172
  }
160
173
  if (diffParts[1] === "all") {
161
- return { kind: "pr-diff", repo: undefined, number, mode: "all" };
174
+ return {
175
+ kind: "pr-diff",
176
+ repo: undefined,
177
+ number,
178
+ mode: "all",
179
+ };
162
180
  }
163
181
  const idx = parsePositiveInt(diffParts[1]);
164
182
  if (idx === undefined) {
165
183
  throw new Error(`Invalid pr:// diff sub-path '${diffParts[1]}'. Use 'all' or a 1-indexed file number.`);
166
184
  }
167
- return { kind: "pr-diff", repo: undefined, number, mode: "slice", index: idx };
185
+ return {
186
+ kind: "pr-diff",
187
+ repo: undefined,
188
+ number,
189
+ mode: "slice",
190
+ index: idx,
191
+ };
168
192
  }
169
193
  // Numeric host with non-diff path — invalid number
170
194
  throw new Error(`Invalid ${scheme}:// number: ${host}`);
@@ -177,9 +201,7 @@ export function parseGitHubUrl(raw: string, scheme: "issue" | "pr"): Parsed {
177
201
  if (!host.includes(".")) {
178
202
  throw new Error(`Invalid ${scheme}:// number: ${host}`);
179
203
  }
180
- throw new Error(
181
- `Invalid ${scheme}:// URL. Expected ${scheme}://<owner>/<repo> or ${scheme}://<owner>/<repo>/<number>.`,
182
- );
204
+ throw new Error(`Invalid ${scheme}:// URL. Expected ${scheme}://<owner>/<repo> or ${scheme}://<owner>/<repo>/<number>.`);
183
205
  }
184
206
 
185
207
  // scheme://owner/repo → list
@@ -207,9 +229,7 @@ export function parseGitHubUrl(raw: string, scheme: "issue" | "pr"): Parsed {
207
229
  );
208
230
  }
209
231
  if (diffParts[0] !== "diff" || diffParts.length > 2) {
210
- throw new Error(
211
- `Invalid pr:// URL. Expected pr://<n>/diff, pr://<n>/diff/all, or pr://<n>/diff/<i>.`,
212
- );
232
+ throw new Error(`Invalid pr:// URL. Expected pr://<n>/diff, pr://<n>/diff/all, or pr://<n>/diff/<i>.`);
213
233
  }
214
234
  if (diffParts.length === 1) {
215
235
  return { kind: "pr-diff", repo, number: num, mode: "list" };
@@ -222,19 +242,30 @@ export function parseGitHubUrl(raw: string, scheme: "issue" | "pr"): Parsed {
222
242
  if (idx === undefined) {
223
243
  throw new Error(`Invalid pr:// diff sub-path '${sub}'. Use 'all' or a 1-indexed file number.`);
224
244
  }
225
- return { kind: "pr-diff", repo, number: num, mode: "slice", index: idx };
245
+ return {
246
+ kind: "pr-diff",
247
+ repo,
248
+ number: num,
249
+ mode: "slice",
250
+ index: idx,
251
+ };
226
252
  }
227
253
 
228
254
  const commentsParam2 = url.searchParams.get("comments");
229
- const comments = !(commentsParam2 === "0" || (commentsParam2?.toLowerCase() === "false"));
255
+ const comments = !(commentsParam2 === "0" || commentsParam2?.toLowerCase() === "false");
230
256
  return { kind: "single", repo, number: num, comments };
231
257
  }
232
258
 
233
259
  // scheme://N (numeric in path) — single, default repo
234
260
  if (pathParts.length === 1 && parsePositiveInt(pathParts[0]) !== undefined) {
235
261
  const commentsParam3 = url.searchParams.get("comments");
236
- const comments = !(commentsParam3 === "0" || (commentsParam3?.toLowerCase() === "false"));
237
- return { kind: "single", repo: undefined, number: parsePositiveInt(pathParts[0])!, comments };
262
+ const comments = !(commentsParam3 === "0" || commentsParam3?.toLowerCase() === "false");
263
+ return {
264
+ kind: "single",
265
+ repo: undefined,
266
+ number: parsePositiveInt(pathParts[0])!,
267
+ comments,
268
+ };
238
269
  }
239
270
 
240
271
  // Fallback: unrecognized shape
@@ -266,7 +297,7 @@ function formatListItem(scheme: "issue" | "pr", repo: string, item: GitHubListIt
266
297
  const updated = item.updatedAt ?? item.createdAt ?? "";
267
298
  const draftSuffix = scheme === "pr" && item.isDraft ? " [draft]" : "";
268
299
  const labels = (item.labels ?? [])
269
- .map(l => l.name)
300
+ .map((l) => l.name)
270
301
  .filter(Boolean)
271
302
  .join(", ");
272
303
  const labelSuffix = labels ? ` labels: ${labels}` : "";
@@ -290,7 +321,10 @@ function runGh(cwd: string, args: string[]): string {
290
321
 
291
322
  function ghJson<T>(cwd: string, args: string[]): T {
292
323
  const jsonOut = execFileSync("gh", args, {
293
- cwd, encoding: "utf-8", timeout: 30_000, stdio: ["pipe", "pipe", "pipe"],
324
+ cwd,
325
+ encoding: "utf-8",
326
+ timeout: 30_000,
327
+ stdio: ["pipe", "pipe", "pipe"],
294
328
  });
295
329
  try {
296
330
  return JSON.parse(jsonOut) as T;
@@ -316,17 +350,24 @@ export function resolveGitHubUrl(parsed: Parsed, scheme: "issue" | "pr", cwd: st
316
350
  // Resolve repo for list operations
317
351
  if (parsed.kind === "list") {
318
352
  const repo = parsed.repo || resolveDefaultRepo(cwd);
319
- const fields = scheme === "issue"
320
- ? ["number", "title", "state", "stateReason", "author", "labels", "createdAt", "updatedAt", "url"]
321
- : ["number", "title", "state", "isDraft", "author", "baseRefName", "headRefName", "labels", "createdAt", "updatedAt", "url"];
322
-
323
- const args = [
324
- scheme, "list",
325
- "--repo", repo,
326
- "--state", parsed.state,
327
- "--limit", String(parsed.limit),
328
- "--json", fields.join(","),
329
- ];
353
+ const fields =
354
+ scheme === "issue"
355
+ ? ["number", "title", "state", "stateReason", "author", "labels", "createdAt", "updatedAt", "url"]
356
+ : [
357
+ "number",
358
+ "title",
359
+ "state",
360
+ "isDraft",
361
+ "author",
362
+ "baseRefName",
363
+ "headRefName",
364
+ "labels",
365
+ "createdAt",
366
+ "updatedAt",
367
+ "url",
368
+ ];
369
+
370
+ const args = [scheme, "list", "--repo", repo, "--state", parsed.state, "--limit", String(parsed.limit), "--json", fields.join(",")];
330
371
  if (parsed.author) args.push("--author", parsed.author);
331
372
  if (parsed.label) args.push("--label", parsed.label);
332
373
 
@@ -339,9 +380,7 @@ export function resolveGitHubUrl(parsed: Parsed, scheme: "issue" | "pr", cwd: st
339
380
  }
340
381
 
341
382
  const header = `# ${scheme === "issue" ? "Issues" : "Pull Requests"} in ${repo} (${parsed.state}, up to ${parsed.limit})`;
342
- const body = items.length === 0
343
- ? "_No matches._"
344
- : items.map(item => formatListItem(scheme, repo, item)).join("\n\n");
383
+ const body = items.length === 0 ? "_No matches._" : items.map((item) => formatListItem(scheme, repo, item)).join("\n\n");
345
384
  const footer = `\n\n---\nRead a specific item: \`${scheme}://${repo}/<N>\` (or \`${scheme}://<N>\` for the current repo).`;
346
385
  return {
347
386
  content: `${header}\n\n${body}${footer}`,
@@ -386,14 +425,31 @@ export function resolveGitHubUrl(parsed: Parsed, scheme: "issue" | "pr", cwd: st
386
425
  if (parsed.mode === "list") {
387
426
  try {
388
427
  const raw = execFileSync(
389
- "gh", ["pr", "view", String(parsed.number), "--repo", repo, "--json", "files", "--jq", ".files[] | \"(.filename) +(.additions) -(.deletions) [(.status)]\""],
390
- { cwd, encoding: "utf-8", timeout: 30_000, stdio: ["pipe", "pipe", "pipe"] },
428
+ "gh",
429
+ [
430
+ "pr",
431
+ "view",
432
+ String(parsed.number),
433
+ "--repo",
434
+ repo,
435
+ "--json",
436
+ "files",
437
+ "--jq",
438
+ '.files[] | "(.filename) +(.additions) -(.deletions) [(.status)]"',
439
+ ],
440
+ {
441
+ cwd,
442
+ encoding: "utf-8",
443
+ timeout: 30_000,
444
+ stdio: ["pipe", "pipe", "pipe"],
445
+ },
391
446
  );
392
447
  const fileLines = raw.split("\n").filter(Boolean);
393
448
  const header = `# Pull Request Diff: ${repo}#${parsed.number} (${fileLines.length} file${fileLines.length === 1 ? "" : "s"})`;
394
- const body = fileLines.length === 0
395
- ? "_No file changes._"
396
- : fileLines.map((line, i) => `${i + 1}. ${line}\n pr://${repo}/${parsed.number}/diff/${i + 1}`).join("\n\n");
449
+ const body =
450
+ fileLines.length === 0
451
+ ? "_No file changes._"
452
+ : fileLines.map((line, i) => `${i + 1}. ${line}\n pr://${repo}/${parsed.number}/diff/${i + 1}`).join("\n\n");
397
453
  const footer = `\n\n---\nRead all: \`pr://${repo}/${parsed.number}/diff/all\`. Each file is also available as \`pr://${repo}/${parsed.number}/diff/<i>\`.`;
398
454
  return {
399
455
  content: `${header}\n\n${body}${footer}`,
@@ -408,8 +464,24 @@ export function resolveGitHubUrl(parsed: Parsed, scheme: "issue" | "pr", cwd: st
408
464
  if (parsed.mode === "slice" && parsed.index !== undefined) {
409
465
  try {
410
466
  const raw = execFileSync(
411
- "gh", ["pr", "view", String(parsed.number), "--repo", repo, "--json", "files", "--jq", ".files[] | \"(.filename) +(.additions) -(.deletions) [(.status)]\""],
412
- { cwd, encoding: "utf-8", timeout: 30_000, stdio: ["pipe", "pipe", "pipe"] },
467
+ "gh",
468
+ [
469
+ "pr",
470
+ "view",
471
+ String(parsed.number),
472
+ "--repo",
473
+ repo,
474
+ "--json",
475
+ "files",
476
+ "--jq",
477
+ '.files[] | "(.filename) +(.additions) -(.deletions) [(.status)]"',
478
+ ],
479
+ {
480
+ cwd,
481
+ encoding: "utf-8",
482
+ timeout: 30_000,
483
+ stdio: ["pipe", "pipe", "pipe"],
484
+ },
413
485
  );
414
486
  const fileLines = raw.split("\n").filter(Boolean);
415
487
  const targetIdx = parsed.index - 1;
@@ -417,7 +489,10 @@ export function resolveGitHubUrl(parsed: Parsed, scheme: "issue" | "pr", cwd: st
417
489
  throw new Error(`File index ${parsed.index} out of range (1..${fileLines.length}).`);
418
490
  }
419
491
  const fullDiff = execFileSync("gh", ["pr", "diff", String(parsed.number), "--repo", repo], {
420
- cwd, encoding: "utf-8", timeout: 30_000, stdio: ["pipe", "pipe", "pipe"],
492
+ cwd,
493
+ encoding: "utf-8",
494
+ timeout: 30_000,
495
+ stdio: ["pipe", "pipe", "pipe"],
421
496
  });
422
497
  // Extract the diff for the target file by splitting on "diff --git" headers
423
498
  const diffBlocks = fullDiff.split(/(?=diff --git )/);
@@ -477,4 +552,4 @@ export function resolveGitHubUrl(parsed: Parsed, scheme: "issue" | "pr", cwd: st
477
552
  function resolveGitHubProtocol(raw: string, scheme: "issue" | "pr", cwd: string): GhResult<unknown> {
478
553
  const parsed = parseGitHubUrl(raw, scheme);
479
554
  return resolveGitHubUrl(parsed, scheme, cwd);
480
- }
555
+ }
package/src/utils/git.ts CHANGED
@@ -206,11 +206,7 @@ export function parseGitUrl(source: string): GitSource | null {
206
206
  const normalizedSource = hasGitPrefix ? trimmed.slice(4).trim() : trimmed.replace(/^git\+/i, "");
207
207
  const url = normalizedSource;
208
208
 
209
- if (
210
- !hasGitPrefix &&
211
- !/^(https?|ssh|git):\/\//i.test(url) &&
212
- !/^git@[^:]+:/.test(url)
213
- ) {
209
+ if (!hasGitPrefix && !/^(https?|ssh|git):\/\//i.test(url) && !/^git@[^:]+:/.test(url)) {
214
210
  return null;
215
211
  }
216
212
 
@@ -227,9 +223,14 @@ export function parseGitUrl(source: string): GitSource | null {
227
223
  }
228
224
  return {
229
225
  type: "git",
230
- repo: split.repo.startsWith("http://") || split.repo.startsWith("https://") || split.repo.startsWith("ssh://") || split.repo.startsWith("git://") || split.repo.startsWith("git@")
231
- ? split.repo
232
- : `https://${split.repo}`,
226
+ repo:
227
+ split.repo.startsWith("http://") ||
228
+ split.repo.startsWith("https://") ||
229
+ split.repo.startsWith("ssh://") ||
230
+ split.repo.startsWith("git://") ||
231
+ split.repo.startsWith("git@")
232
+ ? split.repo
233
+ : `https://${split.repo}`,
233
234
  host: info.domain ?? "",
234
235
  path: `${info.user ?? ""}/${info.project ?? ""}`.replace(/\.git$/, ""),
235
236
  ref: info.committish || split.ref || undefined,
@@ -237,9 +238,7 @@ export function parseGitUrl(source: string): GitSource | null {
237
238
  };
238
239
  };
239
240
 
240
- const hostedCandidates = [split.ref ? `${split.repo}#${split.ref}` : undefined, url].filter((value): value is string =>
241
- Boolean(value),
242
- );
241
+ const hostedCandidates = [split.ref ? `${split.repo}#${split.ref}` : undefined, url].filter((value): value is string => Boolean(value));
243
242
  for (const candidate of hostedCandidates) {
244
243
  const info = parseCandidate(candidate);
245
244
  if (info) {
@@ -247,10 +246,9 @@ export function parseGitUrl(source: string): GitSource | null {
247
246
  }
248
247
  }
249
248
 
250
- const httpsCandidates = [
251
- split.ref ? `https://${split.repo}#${split.ref}` : undefined,
252
- `https://${url}`,
253
- ].filter((value): value is string => Boolean(value));
249
+ const httpsCandidates = [split.ref ? `https://${split.repo}#${split.ref}` : undefined, `https://${url}`].filter(
250
+ (value): value is string => Boolean(value),
251
+ );
254
252
  for (const candidate of httpsCandidates) {
255
253
  const info = parseCandidate(candidate);
256
254
  if (info) {
@@ -43,11 +43,8 @@ export function isStringArray(value: unknown): value is readonly string[] {
43
43
  * @example
44
44
  * const isNumberArray = isArrayOf(isNumber);
45
45
  */
46
- export function isArrayOf<T>(
47
- guard: (item: unknown) => item is T,
48
- ): (value: unknown) => value is readonly T[] {
49
- return (value: unknown): value is readonly T[] =>
50
- Array.isArray(value) && value.every(guard);
46
+ export function isArrayOf<T>(guard: (item: unknown) => item is T): (value: unknown) => value is readonly T[] {
47
+ return (value: unknown): value is readonly T[] => Array.isArray(value) && value.every(guard);
51
48
  }
52
49
 
53
50
  // ── Record field extractors ───────────────────────────────────────────
package/src/utils/ids.ts CHANGED
@@ -2,13 +2,20 @@ import { randomBytes } from "node:crypto";
2
2
  import { generateTaskName } from "./task-name-generator.ts";
3
3
 
4
4
  export function createRunId(prefix = "team"): string {
5
- const stamp = new Date().toISOString().replace(/[-:.TZ]/g, "").slice(0, 14);
5
+ const stamp = new Date()
6
+ .toISOString()
7
+ .replace(/[-:.TZ]/g, "")
8
+ .slice(0, 14);
6
9
  const suffix = randomBytes(8).toString("hex");
7
10
  return `${prefix}_${stamp}_${suffix}`;
8
11
  }
9
12
 
10
13
  export function createTaskId(stepId: string, index: number): string {
11
- const normalized = stepId.toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "") || "task";
14
+ const normalized =
15
+ stepId
16
+ .toLowerCase()
17
+ .replace(/[^a-z0-9-]+/g, "-")
18
+ .replace(/^-+|-+$/g, "") || "task";
12
19
  return `${String(index + 1).padStart(2, "0")}_${normalized}`;
13
20
  }
14
21
 
@@ -22,7 +22,11 @@ export function readLinesSince(filePath: string, state: IncrementalReadState): I
22
22
  try {
23
23
  fd = fs.openSync(filePath, "r");
24
24
  } catch {
25
- return { lines: [], state: { byteOffset: state.byteOffset, lineCount: state.lineCount }, eof: true };
25
+ return {
26
+ lines: [],
27
+ state: { byteOffset: state.byteOffset, lineCount: state.lineCount },
28
+ eof: true,
29
+ };
26
30
  }
27
31
 
28
32
  try {
@@ -75,7 +79,11 @@ export function readLinesSince(filePath: string, state: IncrementalReadState): I
75
79
  };
76
80
  } finally {
77
81
  if (fd !== undefined) {
78
- try { fs.closeSync(fd); } catch { /* ignore */ }
82
+ try {
83
+ fs.closeSync(fd);
84
+ } catch {
85
+ /* ignore */
86
+ }
79
87
  }
80
88
  }
81
89
  }
@@ -84,7 +92,10 @@ export function readLinesSince(filePath: string, state: IncrementalReadState): I
84
92
  * Read parsed JSON objects from a JSONL file since last known byte offset.
85
93
  * Skips malformed lines.
86
94
  */
87
- export function readJsonlSince<T>(filePath: string, state: IncrementalReadState): { items: T[]; state: IncrementalReadState; eof: boolean } {
95
+ export function readJsonlSince<T>(
96
+ filePath: string,
97
+ state: IncrementalReadState,
98
+ ): { items: T[]; state: IncrementalReadState; eof: boolean } {
88
99
  const result = readLinesSince(filePath, state);
89
100
  const items: T[] = [];
90
101
 
@@ -1,6 +1,7 @@
1
1
  export function logInternalError(scope: string, error: unknown, details?: string): void {
2
2
  if (!process.env.PI_TEAMS_DEBUG) return;
3
- const message = error instanceof Error ? error.message : (typeof error === "object" && error !== null ? JSON.stringify(error) : String(error));
3
+ const message =
4
+ error instanceof Error ? error.message : typeof error === "object" && error !== null ? JSON.stringify(error) : String(error);
4
5
  const suffix = details ? `: ${details}` : "";
5
6
  console.error(`[pi-crew:${scope}] ${message}${suffix}`);
6
7
  }
@@ -1,5 +1,11 @@
1
1
  export function sanitizeName(name: string): string {
2
- const result = name.toLowerCase().trim().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "").replace(/-+/g, "-").replace(/^-+|-+$/g, "");
2
+ const result = name
3
+ .toLowerCase()
4
+ .trim()
5
+ .replace(/\s+/g, "-")
6
+ .replace(/[^a-z0-9-]/g, "")
7
+ .replace(/-+/g, "-")
8
+ .replace(/^-+|-+$/g, "");
3
9
  return result || "unnamed";
4
10
  }
5
11
 
@@ -8,7 +14,10 @@ export function requireString(value: unknown, label: string): { value?: string;
8
14
  return { value: value.trim() };
9
15
  }
10
16
 
11
- export function parseConfigObject(config: unknown): { value?: Record<string, unknown>; error?: string } {
17
+ export function parseConfigObject(config: unknown): {
18
+ value?: Record<string, unknown>;
19
+ error?: string;
20
+ } {
12
21
  let parsed = config;
13
22
  if (typeof parsed === "string") {
14
23
  try {
@@ -23,5 +32,5 @@ export function parseConfigObject(config: unknown): { value?: Record<string, unk
23
32
  }
24
33
 
25
34
  export function hasOwn(obj: Record<string, unknown>, key: string): boolean {
26
- return Object.hasOwn(obj, key);
35
+ return Object.hasOwn(obj, key);
27
36
  }
@@ -4,6 +4,37 @@ import * as path from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
5
 
6
6
  export function packageRoot(): string {
7
+ // Phase 5 H2 follow-up: this function is called from both src/ paths
8
+ // (e.g. src/utils/paths.ts) AND from dist/index.mjs after bundling.
9
+ // The original 2-level walk only worked for src/ paths:
10
+ // src/utils/paths.ts → src/utils/ → src/ → packageRoot
11
+ // For dist/index.mjs we need only 1 level:
12
+ // dist/index.mjs → dist/ → packageRoot
13
+ // Heuristic: walk up from `import.meta.url`'s directory until we find
14
+ // a directory that contains `package.json` with our package name. This
15
+ // is robust to either entrypoint and to future relocation (e.g., a
16
+ // monorepo layout under `packages/pi-crew/dist/index.mjs` would walk
17
+ // 2 levels from dist).
18
+ let dir = path.dirname(fileURLToPath(import.meta.url));
19
+ for (let i = 0; i < 6; i++) {
20
+ const candidate = path.join(dir, "package.json");
21
+ if (fs.existsSync(candidate)) {
22
+ try {
23
+ const pkg = JSON.parse(fs.readFileSync(candidate, "utf-8")) as { name?: string };
24
+ if (pkg.name === "pi-crew") {
25
+ return dir;
26
+ }
27
+ } catch {
28
+ // Unreadable or invalid JSON — keep walking.
29
+ }
30
+ }
31
+ const parent = path.dirname(dir);
32
+ if (parent === dir) break;
33
+ dir = parent;
34
+ }
35
+ // Fallback: 2-level walk (matches original src/ semantics). Bundles
36
+ // that don't ship a package.json (very unusual) will get a wrong path
37
+ // here, but that's a build-pipeline bug we want to surface, not hide.
7
38
  return path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "..");
8
39
  }
9
40
 
@@ -27,8 +58,8 @@ export function userPiRoot(): string {
27
58
  if (isSymlink) {
28
59
  throw new Error(
29
60
  `userPiRoot: PI_TEAMS_HOME path "${resolved}" is a symlink. ` +
30
- "Symlinks are not supported for PI_TEAMS_HOME to prevent confusion attacks. " +
31
- "Set PI_TEAMS_HOME to a direct path owned by the current user.",
61
+ "Symlinks are not supported for PI_TEAMS_HOME to prevent confusion attacks. " +
62
+ "Set PI_TEAMS_HOME to a direct path owned by the current user.",
32
63
  );
33
64
  }
34
65
 
@@ -40,7 +71,7 @@ export function userPiRoot(): string {
40
71
  if (stats.uid !== os.userInfo().uid) {
41
72
  throw new Error(
42
73
  `userPiRoot: PI_TEAMS_HOME path "${resolved}" is not owned by the current user (uid=${os.userInfo().uid}, found uid=${stats.uid}). ` +
43
- "This violates security assumptions about file permissions. Set PI_TEAMS_HOME to a path owned by the current user, or unset it to use the default.",
74
+ "This violates security assumptions about file permissions. Set PI_TEAMS_HOME to a path owned by the current user, or unset it to use the default.",
44
75
  );
45
76
  }
46
77
  } catch (err: unknown) {
@@ -55,7 +86,16 @@ export function userPiRoot(): string {
55
86
  }
56
87
 
57
88
  const PROJECT_DIR_MARKERS = [".git", ".pi", ".crew", ".hg", ".svn", ".factory", ".omc"];
58
- const PROJECT_FILE_MARKERS = ["package.json", "pyproject.toml", "Cargo.toml", "go.mod", "pom.xml", "composer.json", "build.gradle", "build.gradle.kts"];
89
+ const PROJECT_FILE_MARKERS = [
90
+ "package.json",
91
+ "pyproject.toml",
92
+ "Cargo.toml",
93
+ "go.mod",
94
+ "pom.xml",
95
+ "composer.json",
96
+ "build.gradle",
97
+ "build.gradle.kts",
98
+ ];
59
99
 
60
100
  // 2.10 — cache findRepoRoot results so repeated lookups during render ticks
61
101
  // (loadConfig, state-store helpers, powerbar, snapshot-cache, ...) skip the
@@ -98,7 +138,11 @@ function canonicalizePath(p: string): string {
98
138
  const r = fs.realpathSync.native(p);
99
139
  return r.startsWith("\\\\?\\") ? r.slice(4) : r;
100
140
  } catch {
101
- try { return fs.realpathSync(p); } catch { return p; }
141
+ try {
142
+ return fs.realpathSync(p);
143
+ } catch {
144
+ return p;
145
+ }
102
146
  }
103
147
  }
104
148
 
@@ -1,5 +1,5 @@
1
- import { createHash } from "node:crypto";
2
1
  import { execFileSync } from "node:child_process";
2
+ import { createHash } from "node:crypto";
3
3
  import * as fs from "node:fs";
4
4
  import * as path from "node:path";
5
5
 
@@ -157,4 +157,4 @@ export function getProjectStorageDir(projectId: string, crewRoot: string): strin
157
157
  */
158
158
  export function getGlobalStorageDir(crewRoot: string): string {
159
159
  return path.join(crewRoot, "instincts", "global");
160
- }
160
+ }