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.
- package/CHANGELOG.md +81 -0
- package/README.md +19 -0
- package/dist/build-meta.json +21790 -0
- package/dist/index.mjs +83070 -0
- package/dist/index.mjs.map +7 -0
- package/docs/A +358 -0
- package/docs/M-A +357 -0
- package/docs/REVIEW-FINDINGS-2026-06 +357 -0
- package/docs/Y +357 -0
- package/docs/a +357 -0
- package/docs/aA +358 -0
- package/docs/archive/README.md +91 -0
- package/docs/patterns/command-agent-skill.md +1 -1
- package/docs/skills/REFERENCE.md +0 -17
- package/docs//303/242mmaAAA/303/242 +357 -0
- package/index.bundle.ts +25 -0
- package/index.ts +95 -4
- package/package.json +15 -4
- package/skills/iterative-audit/SKILL.md +0 -1
- package/skills/widget-rendering/SKILL.md +17 -0
- package/src/adapters/claude-adapter.ts +1 -3
- package/src/adapters/export-util.ts +16 -16
- package/src/adapters/index.ts +5 -5
- package/src/agents/agent-config.ts +20 -14
- package/src/agents/agent-serializer.ts +1 -1
- package/src/agents/discover-agents.ts +83 -39
- package/src/benchmark/benchmark-runner.ts +51 -51
- package/src/benchmark/feedback-loop.ts +1 -1
- package/src/config/config.ts +166 -590
- package/src/config/defaults.ts +28 -2
- package/src/config/drift-detector.ts +11 -14
- package/src/config/markers.ts +201 -203
- package/src/config/resilient-parser.ts +14 -6
- package/src/config/role-tools.ts +3 -3
- package/src/config/suggestions.ts +5 -12
- package/src/config/types.ts +9 -25
- package/src/errors.ts +151 -157
- package/src/extension/action-suggestions.ts +54 -9
- package/src/extension/async-notifier.ts +43 -13
- package/src/extension/autonomous-policy.ts +77 -37
- package/src/extension/command-completions.ts +9 -8
- package/src/extension/context-status-injection.ts +14 -12
- package/src/extension/crew-autocomplete.ts +8 -16
- package/src/extension/crew-cleanup.ts +2 -1
- package/src/extension/crew-shortcuts.ts +9 -6
- package/src/extension/cross-extension-rpc.ts +136 -42
- package/src/extension/help.ts +1 -1
- package/src/extension/import-index.ts +10 -5
- package/src/extension/knowledge-injection.ts +88 -15
- package/src/extension/management.ts +89 -349
- package/src/extension/message-renderers.ts +3 -4
- package/src/extension/notification-router.ts +22 -5
- package/src/extension/notification-sink.ts +6 -3
- package/src/extension/pi-api.ts +17 -8
- package/src/extension/plan-orchestrate.ts +8 -27
- package/src/extension/project-init.ts +21 -6
- package/src/extension/register.ts +329 -975
- package/src/extension/registration/artifact-cleanup.ts +9 -4
- package/src/extension/registration/command-utils.ts +5 -1
- package/src/extension/registration/commands.ts +806 -314
- package/src/extension/registration/compaction-guard.ts +15 -15
- package/src/extension/registration/lifecycle.ts +259 -0
- package/src/extension/registration/observability.ts +293 -0
- package/src/extension/registration/subagent-helpers.ts +29 -7
- package/src/extension/registration/subagent-tools.ts +253 -44
- package/src/extension/registration/team-tool.ts +19 -84
- package/src/extension/registration/ui.ts +168 -0
- package/src/extension/registration/viewers.ts +64 -24
- package/src/extension/result-watcher.ts +18 -7
- package/src/extension/run-bundle-schema.ts +21 -6
- package/src/extension/run-export.ts +15 -6
- package/src/extension/run-import.ts +64 -29
- package/src/extension/run-index.ts +28 -9
- package/src/extension/run-maintenance.ts +32 -12
- package/src/extension/session-summary.ts +1 -1
- package/src/extension/team-manager-command.ts +64 -7
- package/src/extension/team-onboard.ts +151 -150
- package/src/extension/team-recommendation.ts +121 -21
- package/src/extension/team-tool/anchor.ts +31 -64
- package/src/extension/team-tool/api.ts +929 -141
- package/src/extension/team-tool/auto-summarize.ts +14 -26
- package/src/extension/team-tool/cache-control.ts +1 -5
- package/src/extension/team-tool/cancel.ts +138 -38
- package/src/extension/team-tool/chain-dispatch.ts +5 -13
- package/src/extension/team-tool/chain-executor.ts +29 -51
- package/src/extension/team-tool/config-patch.ts +1 -1
- package/src/extension/team-tool/context.ts +40 -20
- package/src/extension/team-tool/destructive-gate.ts +10 -5
- package/src/extension/team-tool/doctor.ts +170 -51
- package/src/extension/team-tool/explain.ts +228 -214
- package/src/extension/team-tool/failure-patterns.ts +3 -9
- package/src/extension/team-tool/goal-wrap.ts +71 -29
- package/src/extension/team-tool/goal.ts +185 -35
- package/src/extension/team-tool/handle-schedule.ts +34 -15
- package/src/extension/team-tool/handle-settings.ts +94 -56
- package/src/extension/team-tool/health-monitor.ts +27 -108
- package/src/extension/team-tool/inspect.ts +42 -9
- package/src/extension/team-tool/intent-policy.ts +4 -1
- package/src/extension/team-tool/lifecycle-actions.ts +244 -48
- package/src/extension/team-tool/orchestrate.ts +7 -18
- package/src/extension/team-tool/parallel-dispatch.ts +51 -29
- package/src/extension/team-tool/plan.ts +29 -5
- package/src/extension/team-tool/respond.ts +49 -16
- package/src/extension/team-tool/run-not-found.ts +3 -8
- package/src/extension/team-tool/run.ts +80 -317
- package/src/extension/team-tool/status.ts +135 -43
- package/src/extension/team-tool/workflow-manage.ts +92 -25
- package/src/extension/team-tool-types.ts +8 -1
- package/src/extension/team-tool.ts +142 -551
- package/src/extension/validate-resources.ts +39 -8
- package/src/hooks/registry.ts +66 -17
- package/src/hooks/types.ts +1 -1
- package/src/i18n.ts +25 -11
- package/src/observability/correlation.ts +17 -3
- package/src/observability/event-bus.ts +51 -56
- package/src/observability/event-to-metric.ts +117 -15
- package/src/observability/exporters/otlp-exporter.ts +56 -17
- package/src/observability/exporters/prometheus-exporter.ts +1 -1
- package/src/observability/metric-registry.ts +16 -4
- package/src/observability/metric-retention.ts +8 -2
- package/src/observability/metric-sink.ts +11 -3
- package/src/observability/metrics-primitives.ts +42 -9
- package/src/plugins/plugin-define.ts +2 -2
- package/src/plugins/plugin-registry.ts +25 -25
- package/src/plugins/plugins/index.ts +1 -1
- package/src/plugins/plugins/nextjs.ts +16 -16
- package/src/plugins/plugins/vite.ts +7 -11
- package/src/plugins/plugins/vitest.ts +6 -11
- package/src/runtime/adaptive-plan.ts +225 -40
- package/src/runtime/agent-control.ts +58 -15
- package/src/runtime/agent-memory.ts +15 -9
- package/src/runtime/agent-observability.ts +10 -2
- package/src/runtime/anchor-manager.ts +27 -25
- package/src/runtime/async-marker.ts +7 -1
- package/src/runtime/async-runner.ts +27 -23
- package/src/runtime/auto-summarize.ts +7 -13
- package/src/runtime/background-runner.ts +189 -251
- package/src/runtime/batch-barrier.ts +18 -16
- package/src/runtime/cancellation-token.ts +16 -6
- package/src/runtime/cancellation.ts +46 -8
- package/src/runtime/capability-inventory.ts +6 -4
- package/src/runtime/chain-parser.ts +44 -11
- package/src/runtime/chain-runner.ts +63 -69
- package/src/runtime/checkpoint.ts +12 -56
- package/src/runtime/child-pi.ts +343 -78
- package/src/runtime/coalesce-tasks.ts +268 -0
- package/src/runtime/code-summary.ts +71 -26
- package/src/runtime/compact-stages/index.ts +15 -5
- package/src/runtime/compact-stages/tail-capture-stage.ts +7 -2
- package/src/runtime/compact-stages/truncation-stage.ts +4 -1
- package/src/runtime/compaction-summary.ts +17 -10
- package/src/runtime/completion-guard.ts +33 -16
- package/src/runtime/crash-classification.ts +28 -7
- package/src/runtime/crash-recovery.ts +177 -37
- package/src/runtime/crew-agent-records.ts +145 -47
- package/src/runtime/crew-hooks.ts +9 -24
- package/src/runtime/cross-extension-rpc.ts +25 -23
- package/src/runtime/custom-tools/irc-tool.ts +43 -15
- package/src/runtime/custom-tools/submit-result-tool.ts +16 -5
- package/src/runtime/delivery-coordinator.ts +34 -7
- package/src/runtime/delta-conflict.ts +9 -21
- package/src/runtime/deterministic-ast.ts +1 -1
- package/src/runtime/diagnostic-export.ts +53 -20
- package/src/runtime/direct-run.ts +12 -2
- package/src/runtime/dwf-state-store.ts +1 -1
- package/src/runtime/dynamic-workflow-context.ts +186 -58
- package/src/runtime/dynamic-workflow-runner.ts +42 -20
- package/src/runtime/effectiveness.ts +16 -8
- package/src/runtime/errors/crew-errors.ts +7 -11
- package/src/runtime/event-stream-bridge.ts +9 -3
- package/src/runtime/foreground-control.ts +54 -14
- package/src/runtime/foreground-watchdog.ts +9 -6
- package/src/runtime/goal-achievement.ts +27 -10
- package/src/runtime/goal-evaluator.ts +54 -19
- package/src/runtime/goal-loop-runner.ts +280 -99
- package/src/runtime/goal-state-store.ts +27 -17
- package/src/runtime/green-contract.ts +11 -2
- package/src/runtime/group-join.ts +64 -31
- package/src/runtime/handoff-manager.ts +37 -42
- package/src/runtime/heartbeat-gradient.ts +10 -2
- package/src/runtime/heartbeat-watcher.ts +32 -6
- package/src/runtime/hidden-handoff.ts +12 -30
- package/src/runtime/important-line-classifier.ts +12 -2
- package/src/runtime/iteration-hooks.ts +25 -15
- package/src/runtime/live-agent-control.ts +55 -7
- package/src/runtime/live-agent-manager.ts +130 -27
- package/src/runtime/live-control-realtime.ts +23 -3
- package/src/runtime/live-irc.ts +4 -1
- package/src/runtime/live-session-health.ts +12 -4
- package/src/runtime/live-session-runtime.ts +379 -117
- package/src/runtime/manifest-cache.ts +28 -12
- package/src/runtime/mcp-proxy.ts +8 -16
- package/src/runtime/metric-parser.ts +1 -5
- package/src/runtime/model-fallback.ts +55 -18
- package/src/runtime/model-resolver.ts +2 -6
- package/src/runtime/model-scope.ts +19 -3
- package/src/runtime/notebook-helpers.ts +60 -62
- package/src/runtime/orphan-worker-registry.ts +37 -26
- package/src/runtime/output-validator.ts +18 -3
- package/src/runtime/overflow-recovery.ts +5 -4
- package/src/runtime/parallel-research.ts +29 -5
- package/src/runtime/parallel-utils.ts +9 -11
- package/src/runtime/path-overlap.ts +150 -0
- package/src/runtime/peer-dep.ts +12 -17
- package/src/runtime/per-write-validator.ts +1 -3
- package/src/runtime/phase-tracker.ts +342 -330
- package/src/runtime/pi-args.ts +26 -8
- package/src/runtime/pi-json-output.ts +1 -1
- package/src/runtime/pi-spawn.ts +30 -19
- package/src/runtime/pipeline-runner.ts +56 -55
- package/src/runtime/plan-templates.ts +5 -6
- package/src/runtime/policy-engine.ts +43 -7
- package/src/runtime/post-checks.ts +12 -4
- package/src/runtime/post-exit-stdio-guard.ts +2 -2
- package/src/runtime/process-lifecycle.ts +20 -10
- package/src/runtime/process-status.ts +16 -5
- package/src/runtime/progress-event-coalescer.ts +2 -1
- package/src/runtime/progress-tracker.ts +103 -103
- package/src/runtime/prose-compressor.ts +9 -11
- package/src/runtime/recovery-recipes.ts +118 -24
- package/src/runtime/replace.ts +25 -10
- package/src/runtime/resilient-edit.ts +10 -25
- package/src/runtime/result-extractor.ts +1 -2
- package/src/runtime/retry-executor.ts +20 -4
- package/src/runtime/retry-runner.ts +26 -50
- package/src/runtime/role-permission.ts +6 -1
- package/src/runtime/run-coalesced-task-group.ts +256 -0
- package/src/runtime/run-drift.ts +14 -15
- package/src/runtime/run-tracker.ts +6 -28
- package/src/runtime/runtime-policy.ts +1 -6
- package/src/runtime/runtime-resolver.ts +80 -15
- package/src/runtime/scheduler.ts +47 -18
- package/src/runtime/semaphore.ts +5 -7
- package/src/runtime/sensitive-paths.ts +2 -1
- package/src/runtime/session-usage.ts +1 -1
- package/src/runtime/settings-store.ts +16 -12
- package/src/runtime/sidechain-output.ts +6 -2
- package/src/runtime/single-agent-compose.ts +1 -4
- package/src/runtime/skill-effectiveness.ts +29 -97
- package/src/runtime/skill-instructions.ts +40 -83
- package/src/runtime/stale-reconciler.ts +73 -197
- package/src/runtime/stream-preview.ts +1 -1
- package/src/runtime/streaming-output.ts +1 -1
- package/src/runtime/subagent-manager.ts +44 -169
- package/src/runtime/subprocess-tool-registry.ts +4 -1
- package/src/runtime/supervisor-contact.ts +10 -5
- package/src/runtime/task-display.ts +19 -5
- package/src/runtime/task-graph-scheduler.ts +95 -21
- package/src/runtime/task-graph.ts +5 -11
- package/src/runtime/task-health.ts +54 -47
- package/src/runtime/task-id.ts +11 -18
- package/src/runtime/task-output-context.ts +265 -81
- package/src/runtime/task-packet.ts +12 -20
- package/src/runtime/task-quality.ts +6 -14
- package/src/runtime/task-runner/context-retrieval.ts +4 -13
- package/src/runtime/task-runner/live-executor.ts +114 -36
- package/src/runtime/task-runner/output-splitter.ts +152 -0
- package/src/runtime/task-runner/progress.ts +50 -12
- package/src/runtime/task-runner/prompt-builder.ts +31 -7
- package/src/runtime/task-runner/prompt-pipeline.ts +31 -7
- package/src/runtime/task-runner/result-utils.ts +3 -1
- package/src/runtime/task-runner/retrieval-orchestrator.ts +310 -0
- package/src/runtime/task-runner/run-projection.ts +27 -8
- package/src/runtime/task-runner/state-helpers.ts +29 -8
- package/src/runtime/task-runner/tail-read.ts +2 -6
- package/src/runtime/task-runner.ts +180 -326
- package/src/runtime/team-runner-artifacts.ts +13 -0
- package/src/runtime/team-runner.ts +456 -974
- package/src/runtime/tool-output-pruner.ts +6 -9
- package/src/runtime/tool-progress.ts +11 -21
- package/src/runtime/verification-gates.ts +33 -24
- package/src/runtime/verification-integrity.ts +1 -4
- package/src/runtime/verification-worktree.ts +62 -12
- package/src/runtime/worker-heartbeat.ts +5 -1
- package/src/runtime/worker-startup.ts +29 -5
- package/src/runtime/workflow-state.ts +17 -9
- package/src/runtime/workspace-lock.ts +30 -35
- package/src/runtime/workspace-tree.ts +20 -32
- package/src/runtime/yield-handler.ts +43 -9
- package/src/runtime/zombie-scanner.ts +5 -4
- package/src/schema/config-schema.ts +266 -172
- package/src/schema/team-tool-schema.ts +29 -74
- package/src/schema/validation-types.ts +25 -17
- package/src/skills/discover-skills.ts +35 -10
- package/src/skills/skill-templates.ts +109 -27
- package/src/skills/validate.ts +26 -8
- package/src/state/active-run-registry.ts +87 -28
- package/src/state/artifact-store.ts +9 -5
- package/src/state/atomic-write-v2.ts +85 -63
- package/src/state/atomic-write.ts +105 -26
- package/src/state/blob-store.ts +47 -20
- package/src/state/contracts.ts +20 -5
- package/src/state/crew-init.ts +5 -22
- package/src/state/decision-ledger.ts +19 -73
- package/src/state/event-log-rotation.ts +41 -15
- package/src/state/event-log.ts +168 -53
- package/src/state/event-reconstructor.ts +11 -1
- package/src/state/gitignore-manager.ts +2 -8
- package/src/state/health-store.ts +57 -57
- package/src/state/hook-instinct-bridge.ts +1 -1
- package/src/state/hook-integrations.ts +1 -1
- package/src/state/instinct-store.ts +17 -5
- package/src/state/jsonl-writer.ts +1 -1
- package/src/state/locks.ts +23 -9
- package/src/state/mailbox.ts +151 -28
- package/src/state/observation-store.ts +20 -14
- package/src/state/run-cache.ts +142 -135
- package/src/state/run-graph.ts +6 -15
- package/src/state/run-metrics.ts +5 -18
- package/src/state/schedule.ts +15 -9
- package/src/state/state-store.ts +129 -45
- package/src/state/task-claims.ts +12 -2
- package/src/state/tiered-eval.ts +52 -43
- package/src/state/types-eval.ts +2 -2
- package/src/state/types.ts +24 -20
- package/src/state/usage.ts +20 -4
- package/src/state/worker-atomic-writer.ts +6 -3
- package/src/subagents/index.ts +2 -2
- package/src/teams/discover-teams.ts +21 -6
- package/src/tools/safe-bash-extension.ts +5 -6
- package/src/tools/safe-bash.ts +10 -11
- package/src/types/new-api-types.ts +6 -10
- package/src/ui/agent-management-overlay.ts +52 -40
- package/src/ui/card-colors.ts +13 -4
- package/src/ui/crew-footer.ts +8 -7
- package/src/ui/crew-select-list.ts +1 -1
- package/src/ui/dashboard-panes/agents-pane.ts +41 -25
- package/src/ui/dashboard-panes/cancellation-pane.ts +1 -1
- package/src/ui/dashboard-panes/capability-pane.ts +32 -15
- package/src/ui/dashboard-panes/health-pane.ts +2 -1
- package/src/ui/dashboard-panes/metrics-pane.ts +4 -1
- package/src/ui/dashboard-panes/progress-pane.ts +12 -9
- package/src/ui/heartbeat-aggregator.ts +15 -4
- package/src/ui/keybinding-map.ts +40 -7
- package/src/ui/live-conversation-overlay.ts +36 -20
- package/src/ui/live-duration.ts +1 -4
- package/src/ui/live-run-sidebar.ts +88 -25
- package/src/ui/loaders.ts +2 -8
- package/src/ui/mascot.ts +20 -36
- package/src/ui/overlays/agent-picker-overlay.ts +11 -3
- package/src/ui/overlays/confirm-overlay.ts +4 -2
- package/src/ui/overlays/help-overlay.ts +25 -14
- package/src/ui/overlays/mailbox-compose-overlay.ts +48 -11
- package/src/ui/overlays/mailbox-compose-preview.ts +20 -5
- package/src/ui/overlays/mailbox-detail-overlay.ts +27 -6
- package/src/ui/pi-ui-compat.ts +7 -7
- package/src/ui/powerbar-publisher.ts +120 -42
- package/src/ui/render-diff.ts +10 -3
- package/src/ui/render-scheduler.ts +12 -4
- package/src/ui/run-action-dispatcher.ts +81 -18
- package/src/ui/run-dashboard.ts +172 -76
- package/src/ui/run-event-bus.ts +59 -37
- package/src/ui/run-snapshot-cache.ts +276 -86
- package/src/ui/settings-overlay.ts +361 -74
- package/src/ui/status-colors.ts +12 -1
- package/src/ui/syntax-highlight.ts +1 -1
- package/src/ui/theme-adapter.ts +16 -14
- package/src/ui/theme-discovery.ts +13 -2
- package/src/ui/tool-progress-formatter.ts +7 -7
- package/src/ui/tool-render.ts +128 -56
- package/src/ui/tool-renderers/brief-mode.ts +45 -27
- package/src/ui/tool-renderers/index.ts +109 -43
- package/src/ui/transcript-cache.ts +32 -6
- package/src/ui/transcript-entries.ts +25 -23
- package/src/ui/transcript-viewer.ts +78 -29
- package/src/ui/widget/index.ts +99 -40
- package/src/ui/widget/widget-formatters.ts +13 -6
- package/src/ui/widget/widget-model.ts +19 -8
- package/src/ui/widget/widget-renderer.ts +23 -13
- package/src/ui/widget/widget-types.ts +1 -1
- package/src/utils/bm25-search.ts +199 -199
- package/src/utils/conflict-detect.ts +22 -21
- package/src/utils/env-filter.ts +14 -7
- package/src/utils/file-coalescer.ts +5 -1
- package/src/utils/fingerprint.ts +3 -6
- package/src/utils/frontmatter.ts +3 -1
- package/src/utils/fs-watch.ts +2 -6
- package/src/utils/gh-protocol.ts +119 -44
- package/src/utils/git.ts +13 -15
- package/src/utils/guards.ts +2 -5
- package/src/utils/ids.ts +9 -2
- package/src/utils/incremental-reader.ts +14 -3
- package/src/utils/internal-error.ts +2 -1
- package/src/utils/names.ts +12 -3
- package/src/utils/paths.ts +49 -5
- package/src/utils/project-detector.ts +2 -2
- package/src/utils/redaction.ts +29 -19
- package/src/utils/resolve-shell.ts +9 -7
- package/src/utils/run-watcher-registry.ts +19 -31
- package/src/utils/safe-paths.ts +45 -24
- package/src/utils/scan-cache.ts +9 -2
- package/src/utils/session-utils.ts +2 -4
- package/src/utils/sleep.ts +12 -5
- package/src/utils/sse-parser.ts +5 -17
- package/src/utils/visual.ts +52 -32
- package/src/workflows/discover-workflows.ts +41 -109
- package/src/workflows/intermediate-store.ts +5 -21
- package/src/workflows/preflight-validator.ts +6 -33
- package/src/workflows/topology-analyzer.ts +5 -21
- package/src/workflows/workflow-config.ts +7 -6
- package/src/worktree/branch-freshness.ts +66 -8
- package/src/worktree/cleanup.ts +130 -20
- package/src/worktree/worktree-manager.ts +212 -69
- package/skills/artifact-analysis-loop/SKILL.md +0 -303
- package/skills/detection-pipeline-design/SKILL.md +0 -286
- package/skills/hunting-investigation-loop/SKILL.md +0 -402
- package/skills/incident-playbook-construction/SKILL.md +0 -384
- package/skills/security-review/SKILL.md +0 -561
- package/skills/threat-hypothesis-framework/SKILL.md +0 -176
- package/skills/ui-render-performance/SKILL.md +0 -58
- /package/docs/{followup-review-round3-2026-05-12.md → archive/followup-review-round3-2026-05-12.md} +0 -0
- /package/docs/{followup-review-round4-2026-05-13.md → archive/followup-review-round4-2026-05-13.md} +0 -0
- /package/docs/{pi-crew-bugs.md → archive/pi-crew-bugs.md} +0 -0
- /package/docs/{pi-crew-test-final.md → archive/pi-crew-test-final.md} +0 -0
- /package/docs/{pi-crew-test-results.md → archive/pi-crew-test-results.md} +0 -0
- /package/docs/{pi-crew-test-round2.md → archive/pi-crew-test-round2.md} +0 -0
- /package/docs/{pi-crew-test-round4.md → archive/pi-crew-test-round4.md} +0 -0
- /package/docs/{pi-crew-test-round5.md → archive/pi-crew-test-round5.md} +0 -0
- /package/docs/{pi-crew-test-round6.md → archive/pi-crew-test-round6.md} +0 -0
- /package/docs/{pi-crew-v0.5.10-audit-fix-plan.md → archive/pi-crew-v0.5.10-audit-fix-plan.md} +0 -0
- /package/docs/{pi-crew-v0.5.11-audit-fix-plan.md → archive/pi-crew-v0.5.11-audit-fix-plan.md} +0 -0
- /package/docs/{pi-crew-v0.5.12-audit-fix-plan.md → archive/pi-crew-v0.5.12-audit-fix-plan.md} +0 -0
- /package/docs/{pi-crew-v0.5.13-audit-fix-plan.md → archive/pi-crew-v0.5.13-audit-fix-plan.md} +0 -0
- /package/docs/{pi-crew-v0.5.14-audit-fix-plan.md → archive/pi-crew-v0.5.14-audit-fix-plan.md} +0 -0
- /package/docs/{pi-crew-v0.5.16-audit-fix-plan.md → archive/pi-crew-v0.5.16-audit-fix-plan.md} +0 -0
- /package/docs/{pi-crew-v0.5.17-audit-fix-plan.md → archive/pi-crew-v0.5.17-audit-fix-plan.md} +0 -0
- /package/docs/{pi-crew-v0.5.5-audit-fix-plan.md → archive/pi-crew-v0.5.5-audit-fix-plan.md} +0 -0
- /package/docs/{pi-crew-v0.5.9-audit-fix-plan.md → archive/pi-crew-v0.5.9-audit-fix-plan.md} +0 -0
- /package/docs/{pi-mono-opportunities.md → archive/pi-mono-opportunities.md} +0 -0
- /package/docs/{pi-mono-review.md → archive/pi-mono-review.md} +0 -0
- /package/docs/{pi-subagent4-comparison.md → archive/pi-subagent4-comparison.md} +0 -0
- /package/docs/{pi-subagents3-deep-analysis.md → archive/pi-subagents3-deep-analysis.md} +0 -0
package/src/utils/gh-protocol.ts
CHANGED
|
@@ -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 {
|
|
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" ||
|
|
151
|
-
return {
|
|
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 {
|
|
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 {
|
|
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 {
|
|
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 {
|
|
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" ||
|
|
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" ||
|
|
237
|
-
return {
|
|
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,
|
|
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 =
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
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",
|
|
390
|
-
|
|
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 =
|
|
395
|
-
|
|
396
|
-
|
|
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",
|
|
412
|
-
|
|
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,
|
|
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:
|
|
231
|
-
|
|
232
|
-
|
|
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
|
-
|
|
252
|
-
|
|
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) {
|
package/src/utils/guards.ts
CHANGED
|
@@ -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
|
-
|
|
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()
|
|
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 =
|
|
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 {
|
|
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 {
|
|
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>(
|
|
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 =
|
|
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
|
}
|
package/src/utils/names.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
export function sanitizeName(name: string): string {
|
|
2
|
-
const result = name
|
|
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): {
|
|
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
|
|
35
|
+
return Object.hasOwn(obj, key);
|
|
27
36
|
}
|
package/src/utils/paths.ts
CHANGED
|
@@ -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
|
-
|
|
31
|
-
|
|
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
|
-
|
|
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 = [
|
|
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 {
|
|
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
|
+
}
|