pi-crew 0.9.53 → 0.9.55
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 +45 -0
- package/package.json +6 -3
- package/scripts/clean-strip-types.mjs +60 -0
- package/src/adapters/claude-adapter.ts +23 -0
- package/src/adapters/codex-adapter.ts +21 -0
- package/src/adapters/cursor-adapter.ts +17 -0
- package/src/adapters/export-util.ts +143 -0
- package/src/adapters/index.ts +15 -0
- package/src/adapters/registry.ts +18 -0
- package/src/adapters/types.ts +23 -0
- package/src/agents/agent-config.ts +194 -0
- package/src/agents/agent-search.ts +98 -0
- package/src/agents/agent-serializer.ts +38 -0
- package/src/agents/discover-agents.ts +623 -0
- package/src/benchmark/benchmark-runner.ts +313 -0
- package/src/benchmark/feedback-loop.ts +73 -0
- package/src/config/config.ts +1270 -0
- package/src/config/defaults.ts +193 -0
- package/src/config/drift-detector.ts +290 -0
- package/src/config/markers.ts +330 -0
- package/src/config/resilient-parser.ts +117 -0
- package/src/config/role-tools.ts +118 -0
- package/src/config/suggestions.ts +75 -0
- package/src/config/types.ts +280 -0
- package/src/errors.ts +194 -0
- package/src/extension/action-suggestions.ts +117 -0
- package/src/extension/async-notifier.ts +179 -0
- package/src/extension/autonomous-policy.ts +209 -0
- package/src/extension/command-completions.ts +120 -0
- package/src/extension/context-status-injection.ts +185 -0
- package/src/extension/crew-autocomplete.ts +131 -0
- package/src/extension/crew-cleanup.ts +168 -0
- package/src/extension/crew-input-router.ts +93 -0
- package/src/extension/crew-shortcuts.ts +87 -0
- package/src/extension/crew-vibes/cat-frames.ts +18 -0
- package/src/extension/crew-vibes/config.ts +195 -0
- package/src/extension/crew-vibes/figures.ts +101 -0
- package/src/extension/crew-vibes/font-detect.ts +71 -0
- package/src/extension/crew-vibes/footer.ts +292 -0
- package/src/extension/crew-vibes/index.ts +432 -0
- package/src/extension/crew-vibes/provider-usage.ts +396 -0
- package/src/extension/crew-vibes/render.ts +206 -0
- package/src/extension/crew-vibes/speed.ts +286 -0
- package/src/extension/cross-extension-rpc.ts +350 -0
- package/src/extension/help.ts +62 -0
- package/src/extension/import-index.ts +74 -0
- package/src/extension/knowledge-injection.ts +402 -0
- package/src/extension/management.ts +571 -0
- package/src/extension/message-renderers.ts +108 -0
- package/src/extension/notification-router.ts +152 -0
- package/src/extension/notification-sink.ts +54 -0
- package/src/extension/pi-api.ts +56 -0
- package/src/extension/plan-orchestrate.ts +302 -0
- package/src/extension/project-init.ts +170 -0
- package/src/extension/register.ts +113 -0
- package/src/extension/registration/artifact-cleanup.ts +20 -0
- package/src/extension/registration/command-registration.ts +58 -0
- package/src/extension/registration/command-utils.ts +58 -0
- package/src/extension/registration/commands.ts +1228 -0
- package/src/extension/registration/compaction-guard.ts +333 -0
- package/src/extension/registration/context-builder.ts +135 -0
- package/src/extension/registration/crash-recovery-cache.ts +54 -0
- package/src/extension/registration/foreground-run-controller.ts +238 -0
- package/src/extension/registration/hook-registration.ts +119 -0
- package/src/extension/registration/lazy-configurers.ts +124 -0
- package/src/extension/registration/lifecycle-handlers.ts +923 -0
- package/src/extension/registration/lifecycle.ts +259 -0
- package/src/extension/registration/observability.ts +322 -0
- package/src/extension/registration/registration-types.ts +158 -0
- package/src/extension/registration/runtime-cleanup.ts +230 -0
- package/src/extension/registration/subagent-helpers.ts +125 -0
- package/src/extension/registration/subagent-manager-setup.ts +330 -0
- package/src/extension/registration/subagent-tools.ts +456 -0
- package/src/extension/registration/team-tool.ts +225 -0
- package/src/extension/registration/tool-registration.ts +50 -0
- package/src/extension/registration/ui.ts +172 -0
- package/src/extension/registration/viewers.ts +121 -0
- package/src/extension/registration/wire-cross-extension.ts +37 -0
- package/src/extension/result-watcher.ts +139 -0
- package/src/extension/rpc-hmac.ts +256 -0
- package/src/extension/run-bundle-schema.ts +104 -0
- package/src/extension/run-export.ts +97 -0
- package/src/extension/run-import.ts +168 -0
- package/src/extension/run-index.ts +131 -0
- package/src/extension/run-maintenance.ts +190 -0
- package/src/extension/session-summary.ts +18 -0
- package/src/extension/team-manager-command.ts +153 -0
- package/src/extension/team-onboard.ts +180 -0
- package/src/extension/team-recommendation.ts +288 -0
- package/src/extension/team-tool/anchor.ts +172 -0
- package/src/extension/team-tool/api.ts +1244 -0
- package/src/extension/team-tool/auto-summarize.ts +142 -0
- package/src/extension/team-tool/cache-control.ts +19 -0
- package/src/extension/team-tool/cancel.ts +337 -0
- package/src/extension/team-tool/chain-dispatch.ts +95 -0
- package/src/extension/team-tool/chain-executor.ts +379 -0
- package/src/extension/team-tool/config-patch.ts +50 -0
- package/src/extension/team-tool/context.ts +149 -0
- package/src/extension/team-tool/destructive-gate.ts +52 -0
- package/src/extension/team-tool/dispatch/automate.ts +80 -0
- package/src/extension/team-tool/dispatch/control.ts +42 -0
- package/src/extension/team-tool/dispatch/index.ts +95 -0
- package/src/extension/team-tool/dispatch/manage.ts +161 -0
- package/src/extension/team-tool/dispatch/run.ts +53 -0
- package/src/extension/team-tool/dispatch/status.ts +187 -0
- package/src/extension/team-tool/doctor.ts +431 -0
- package/src/extension/team-tool/explain.ts +282 -0
- package/src/extension/team-tool/failure-patterns.ts +118 -0
- package/src/extension/team-tool/goal-wrap.ts +330 -0
- package/src/extension/team-tool/goal.ts +556 -0
- package/src/extension/team-tool/handle-schedule.ts +332 -0
- package/src/extension/team-tool/handle-settings.ts +520 -0
- package/src/extension/team-tool/health-monitor.ts +481 -0
- package/src/extension/team-tool/inspect.ts +88 -0
- package/src/extension/team-tool/intent-policy.ts +45 -0
- package/src/extension/team-tool/lifecycle-actions.ts +615 -0
- package/src/extension/team-tool/orchestrate.ts +98 -0
- package/src/extension/team-tool/parallel-dispatch.ts +183 -0
- package/src/extension/team-tool/plan.ts +50 -0
- package/src/extension/team-tool/respond.ts +150 -0
- package/src/extension/team-tool/run-deadline.ts +66 -0
- package/src/extension/team-tool/run-not-found.ts +49 -0
- package/src/extension/team-tool/run.ts +1051 -0
- package/src/extension/team-tool/status.ts +260 -0
- package/src/extension/team-tool/workflow-manage.ts +261 -0
- package/src/extension/team-tool-types.ts +26 -0
- package/src/extension/team-tool.ts +750 -0
- package/src/extension/tool-result.ts +16 -0
- package/src/extension/validate-resources.ts +108 -0
- package/src/hooks/registry.ts +200 -0
- package/src/hooks/types.ts +69 -0
- package/src/i18n.ts +212 -0
- package/src/observability/correlation.ts +50 -0
- package/src/observability/event-bus.ts +86 -0
- package/src/observability/event-to-metric.ts +170 -0
- package/src/observability/exporters/adapter.ts +27 -0
- package/src/observability/exporters/otlp-exporter.ts +356 -0
- package/src/observability/exporters/prometheus-exporter.ts +54 -0
- package/src/observability/metric-registry.ts +100 -0
- package/src/observability/metric-retention.ts +64 -0
- package/src/observability/metric-sink.ts +99 -0
- package/src/observability/metrics-primitives.ts +219 -0
- package/src/plugins/plugin-define.ts +6 -0
- package/src/plugins/plugin-registry.ts +32 -0
- package/src/plugins/plugins/index.ts +3 -0
- package/src/plugins/plugins/nextjs.ts +19 -0
- package/src/plugins/plugins/vite.ts +10 -0
- package/src/plugins/plugins/vitest.ts +9 -0
- package/src/prompt/prompt-runtime.ts +380 -0
- package/src/runtime/adaptive-plan.ts +563 -0
- package/src/runtime/agent-control.ts +215 -0
- package/src/runtime/agent-memory.ts +81 -0
- package/src/runtime/agent-observability.ts +122 -0
- package/src/runtime/anchor-manager.ts +475 -0
- package/src/runtime/async-marker.ts +32 -0
- package/src/runtime/async-runner.ts +381 -0
- package/src/runtime/attention-events.ts +28 -0
- package/src/runtime/auto-summarize.ts +344 -0
- package/src/runtime/background-runner.ts +840 -0
- package/src/runtime/batch-barrier.ts +147 -0
- package/src/runtime/broker-issuer.ts +39 -0
- package/src/runtime/cancellation-token.ts +99 -0
- package/src/runtime/cancellation.ts +99 -0
- package/src/runtime/capability-inventory.ts +137 -0
- package/src/runtime/chain-parser.ts +237 -0
- package/src/runtime/chain-runner.ts +606 -0
- package/src/runtime/checkpoint.ts +291 -0
- package/src/runtime/child-pi-constants.ts +42 -0
- package/src/runtime/child-pi-kill.ts +180 -0
- package/src/runtime/child-pi-pool.ts +68 -0
- package/src/runtime/child-pi-spawn.ts +287 -0
- package/src/runtime/child-pi-steering.ts +128 -0
- package/src/runtime/child-pi-streams.ts +296 -0
- package/src/runtime/child-pi-transcript.ts +169 -0
- package/src/runtime/child-pi.ts +1105 -0
- package/src/runtime/coalesce-tasks.ts +268 -0
- package/src/runtime/code-summary.ts +292 -0
- package/src/runtime/command-trace.ts +105 -0
- package/src/runtime/compact-pipeline.ts +56 -0
- package/src/runtime/compact-stages/ansi-strip-stage.ts +25 -0
- package/src/runtime/compact-stages/blank-collapse-stage.ts +31 -0
- package/src/runtime/compact-stages/deduplicate-stage.ts +34 -0
- package/src/runtime/compact-stages/head-snap-stage.ts +57 -0
- package/src/runtime/compact-stages/index.ts +23 -0
- package/src/runtime/compact-stages/tail-capture-stage.ts +77 -0
- package/src/runtime/compact-stages/truncation-stage.ts +74 -0
- package/src/runtime/compaction-summary.ts +278 -0
- package/src/runtime/completion-guard.ts +207 -0
- package/src/runtime/concurrency.ts +58 -0
- package/src/runtime/crash-classification.ts +229 -0
- package/src/runtime/crash-recovery.ts +594 -0
- package/src/runtime/crew-agent-records.ts +595 -0
- package/src/runtime/crew-agent-runtime.ts +62 -0
- package/src/runtime/crew-broker-child.ts +88 -0
- package/src/runtime/crew-broker-client.ts +673 -0
- package/src/runtime/crew-broker-tokens.ts +159 -0
- package/src/runtime/crew-broker.ts +1304 -0
- package/src/runtime/crew-hooks.ts +227 -0
- package/src/runtime/cross-extension-rpc.ts +143 -0
- package/src/runtime/custom-tools/irc-tool.ts +282 -0
- package/src/runtime/custom-tools/submit-result-tool.ts +102 -0
- package/src/runtime/deadletter.ts +47 -0
- package/src/runtime/delivery-coordinator.ts +211 -0
- package/src/runtime/delta-conflict.ts +348 -0
- package/src/runtime/deterministic-ast.ts +161 -0
- package/src/runtime/diagnostic-export.ts +171 -0
- package/src/runtime/direct-run.ts +45 -0
- package/src/runtime/dwf-state-store.ts +102 -0
- package/src/runtime/dynamic-workflow-context.ts +1013 -0
- package/src/runtime/dynamic-workflow-runner.ts +325 -0
- package/src/runtime/effectiveness.ts +90 -0
- package/src/runtime/errors/crew-errors.ts +162 -0
- package/src/runtime/event-stream-bridge.ts +98 -0
- package/src/runtime/foreground-control.ts +193 -0
- package/src/runtime/foreground-watchdog.ts +132 -0
- package/src/runtime/global-worker-cap.ts +96 -0
- package/src/runtime/goal-achievement.ts +148 -0
- package/src/runtime/goal-evaluator.ts +365 -0
- package/src/runtime/goal-loop-runner.ts +825 -0
- package/src/runtime/goal-state-store.ts +219 -0
- package/src/runtime/green-contract.ts +55 -0
- package/src/runtime/group-join.ts +267 -0
- package/src/runtime/handoff-manager.ts +598 -0
- package/src/runtime/heartbeat-gradient.ts +36 -0
- package/src/runtime/heartbeat-watcher.ts +239 -0
- package/src/runtime/hidden-handoff.ts +407 -0
- package/src/runtime/important-line-classifier.ts +140 -0
- package/src/runtime/intercom-bridge.ts +187 -0
- package/src/runtime/iteration-hooks.ts +305 -0
- package/src/runtime/live-agent-control.ts +136 -0
- package/src/runtime/live-agent-manager.ts +704 -0
- package/src/runtime/live-control-realtime.ts +56 -0
- package/src/runtime/live-extension-bridge.ts +148 -0
- package/src/runtime/live-irc.ts +97 -0
- package/src/runtime/live-session-health.ts +108 -0
- package/src/runtime/live-session-runtime.ts +1146 -0
- package/src/runtime/loop-gates.ts +128 -0
- package/src/runtime/manifest-cache.ts +375 -0
- package/src/runtime/mcp-proxy.ts +105 -0
- package/src/runtime/metric-parser.ts +36 -0
- package/src/runtime/model-fallback.ts +409 -0
- package/src/runtime/model-resolver.ts +126 -0
- package/src/runtime/model-scope.ts +158 -0
- package/src/runtime/orphan-worker-registry.ts +465 -0
- package/src/runtime/output-validator.ts +202 -0
- package/src/runtime/overflow-recovery.ts +206 -0
- package/src/runtime/parallel-research.ts +68 -0
- package/src/runtime/parallel-utils.ts +160 -0
- package/src/runtime/parent-guard.ts +134 -0
- package/src/runtime/path-overlap.ts +150 -0
- package/src/runtime/peer-dep.ts +292 -0
- package/src/runtime/per-write-validator.ts +181 -0
- package/src/runtime/phase-progress.ts +217 -0
- package/src/runtime/phase-tracker.ts +385 -0
- package/src/runtime/pi-args.ts +655 -0
- package/src/runtime/pi-json-output.ts +170 -0
- package/src/runtime/pi-spawn.ts +273 -0
- package/src/runtime/pipeline-runner.ts +523 -0
- package/src/runtime/plan-templates.ts +201 -0
- package/src/runtime/policy-engine.ts +115 -0
- package/src/runtime/post-checks.ts +142 -0
- package/src/runtime/post-exit-stdio-guard.ts +109 -0
- package/src/runtime/process-lifecycle.ts +491 -0
- package/src/runtime/process-status.ts +154 -0
- package/src/runtime/progress-event-coalescer.ts +44 -0
- package/src/runtime/progress-tracker.ts +124 -0
- package/src/runtime/prose-compressor.ts +162 -0
- package/src/runtime/recovery-recipes.ts +203 -0
- package/src/runtime/replace.ts +570 -0
- package/src/runtime/resilient-edit.ts +153 -0
- package/src/runtime/result-extractor.ts +217 -0
- package/src/runtime/retry-executor.ts +109 -0
- package/src/runtime/retry-runner.ts +336 -0
- package/src/runtime/role-permission.ts +59 -0
- package/src/runtime/run-coalesced-task-group.ts +308 -0
- package/src/runtime/run-drift.ts +219 -0
- package/src/runtime/run-tracker.ts +116 -0
- package/src/runtime/run-worker.ts +78 -0
- package/src/runtime/runtime-policy.ts +29 -0
- package/src/runtime/runtime-resolver.ts +172 -0
- package/src/runtime/runtime-warmup.ts +160 -0
- package/src/runtime/scheduler.ts +353 -0
- package/src/runtime/semaphore.ts +141 -0
- package/src/runtime/sensitive-paths.ts +93 -0
- package/src/runtime/session-resources.ts +25 -0
- package/src/runtime/session-snapshot.ts +59 -0
- package/src/runtime/session-usage.ts +79 -0
- package/src/runtime/settings-store.ts +155 -0
- package/src/runtime/sidechain-output.ts +35 -0
- package/src/runtime/single-agent-compose.ts +84 -0
- package/src/runtime/skill-effectiveness.ts +524 -0
- package/src/runtime/skill-instructions.ts +394 -0
- package/src/runtime/stale-reconciler.ts +680 -0
- package/src/runtime/stream-preview.ts +184 -0
- package/src/runtime/streaming-output.ts +50 -0
- package/src/runtime/subagent-manager.ts +561 -0
- package/src/runtime/subprocess-tool-registry.ts +70 -0
- package/src/runtime/supervisor-contact.ts +64 -0
- package/src/runtime/task-display.ts +52 -0
- package/src/runtime/task-graph-scheduler.ts +227 -0
- package/src/runtime/task-graph.ts +290 -0
- package/src/runtime/task-health.ts +83 -0
- package/src/runtime/task-id.ts +161 -0
- package/src/runtime/task-output-context.ts +602 -0
- package/src/runtime/task-packet.ts +268 -0
- package/src/runtime/task-quality.ts +199 -0
- package/src/runtime/task-runner/capabilities.ts +78 -0
- package/src/runtime/task-runner/child-executor.ts +790 -0
- package/src/runtime/task-runner/context-retrieval.ts +163 -0
- package/src/runtime/task-runner/live-executor.ts +227 -0
- package/src/runtime/task-runner/output-splitter.ts +152 -0
- package/src/runtime/task-runner/post-execution.ts +480 -0
- package/src/runtime/task-runner/pre-execution.ts +365 -0
- package/src/runtime/task-runner/progress.ts +157 -0
- package/src/runtime/task-runner/prompt-builder.ts +278 -0
- package/src/runtime/task-runner/prompt-pipeline.ts +88 -0
- package/src/runtime/task-runner/result-utils.ts +16 -0
- package/src/runtime/task-runner/retrieval-orchestrator.ts +310 -0
- package/src/runtime/task-runner/run-projection.ts +125 -0
- package/src/runtime/task-runner/scaffold-executor.ts +25 -0
- package/src/runtime/task-runner/state-helpers.ts +176 -0
- package/src/runtime/task-runner/tail-read.ts +34 -0
- package/src/runtime/task-runner.ts +216 -0
- package/src/runtime/team-runner-artifacts.ts +13 -0
- package/src/runtime/team-runner.ts +2396 -0
- package/src/runtime/tool-output-pruner.ts +333 -0
- package/src/runtime/tool-progress.ts +278 -0
- package/src/runtime/usage-tracker.ts +73 -0
- package/src/runtime/verification-gates.ts +579 -0
- package/src/runtime/verification-integrity.ts +108 -0
- package/src/runtime/verification-worktree.ts +186 -0
- package/src/runtime/worker-heartbeat.ts +25 -0
- package/src/runtime/worker-startup.ts +83 -0
- package/src/runtime/workflow-state.ts +195 -0
- package/src/runtime/workspace-lock.ts +443 -0
- package/src/runtime/workspace-tree.ts +312 -0
- package/src/runtime/yield-handler.ts +224 -0
- package/src/runtime/zombie-scanner.ts +298 -0
- package/src/schema/config-schema.ts +327 -0
- package/src/schema/team-tool-schema.ts +492 -0
- package/src/schema/validation-types.ts +159 -0
- package/src/skills/discover-skills.ts +203 -0
- package/src/skills/skill-templates.ts +456 -0
- package/src/skills/validate.ts +285 -0
- package/src/state/active-run-registry.ts +439 -0
- package/src/state/artifact-store.ts +176 -0
- package/src/state/atomic-write.ts +970 -0
- package/src/state/blob-store.ts +308 -0
- package/src/state/contracts.ts +160 -0
- package/src/state/crew-init.ts +269 -0
- package/src/state/decision-ledger.ts +372 -0
- package/src/state/event-log-rotation.ts +399 -0
- package/src/state/event-log.ts +1465 -0
- package/src/state/event-reconstructor.ts +229 -0
- package/src/state/gitignore-manager.ts +46 -0
- package/src/state/health-store.ts +79 -0
- package/src/state/hook-instinct-bridge.ts +94 -0
- package/src/state/hook-integrations.ts +51 -0
- package/src/state/instinct-store.ts +275 -0
- package/src/state/jsonl-writer.ts +107 -0
- package/src/state/locks.ts +562 -0
- package/src/state/mailbox.ts +916 -0
- package/src/state/observation-store.ts +176 -0
- package/src/state/run-cache.ts +193 -0
- package/src/state/run-graph.ts +183 -0
- package/src/state/run-metrics.ts +165 -0
- package/src/state/schedule.ts +166 -0
- package/src/state/session-state-map.ts +51 -0
- package/src/state/state-store.ts +973 -0
- package/src/state/task-claims.ts +61 -0
- package/src/state/tiered-eval.ts +480 -0
- package/src/state/types-eval.ts +58 -0
- package/src/state/types.ts +447 -0
- package/src/state/usage.ts +138 -0
- package/src/state/worker-atomic-writer.ts +198 -0
- package/src/subagents/async-entry.ts +1 -0
- package/src/subagents/index.ts +3 -0
- package/src/subagents/live/control.ts +1 -0
- package/src/subagents/live/manager.ts +1 -0
- package/src/subagents/live/realtime.ts +1 -0
- package/src/subagents/live/session-runtime.ts +1 -0
- package/src/subagents/manager.ts +1 -0
- package/src/subagents/spawn.ts +1 -0
- package/src/teams/discover-teams.ts +187 -0
- package/src/teams/team-config.ts +27 -0
- package/src/teams/team-serializer.ts +38 -0
- package/src/tools/safe-bash-extension.ts +54 -0
- package/src/tools/safe-bash.ts +505 -0
- package/src/types/diff.d.ts +18 -0
- package/src/types/new-api-types.ts +35 -0
- package/src/ui/agent-management-overlay.ts +160 -0
- package/src/ui/card-colors.ts +139 -0
- package/src/ui/crew-footer.ts +102 -0
- package/src/ui/crew-select-list.ts +112 -0
- package/src/ui/dashboard-panes/agents-pane.ts +164 -0
- package/src/ui/dashboard-panes/cancellation-pane.ts +66 -0
- package/src/ui/dashboard-panes/capability-pane.ts +77 -0
- package/src/ui/dashboard-panes/health-pane.ts +31 -0
- package/src/ui/dashboard-panes/mailbox-pane.ts +35 -0
- package/src/ui/dashboard-panes/metrics-pane.ts +37 -0
- package/src/ui/dashboard-panes/progress-pane.ts +38 -0
- package/src/ui/dashboard-panes/transcript-pane.ts +10 -0
- package/src/ui/deploy-bundled-themes.ts +71 -0
- package/src/ui/dwf-phase-display.ts +151 -0
- package/src/ui/dynamic-border.ts +35 -0
- package/src/ui/format-helpers.ts +31 -0
- package/src/ui/heartbeat-aggregator.ts +74 -0
- package/src/ui/key-utils.ts +42 -0
- package/src/ui/keybinding-map.ts +248 -0
- package/src/ui/layout-primitives.ts +106 -0
- package/src/ui/live-conversation-overlay.ts +183 -0
- package/src/ui/live-duration.ts +55 -0
- package/src/ui/live-run-sidebar.ts +293 -0
- package/src/ui/loaders.ts +6 -0
- package/src/ui/mascot.ts +449 -0
- package/src/ui/overlays/agent-picker-overlay.ts +66 -0
- package/src/ui/overlays/confirm-overlay.ts +60 -0
- package/src/ui/overlays/help-overlay.ts +177 -0
- package/src/ui/overlays/mailbox-compose-overlay.ts +181 -0
- package/src/ui/overlays/mailbox-compose-preview.ts +78 -0
- package/src/ui/overlays/mailbox-detail-overlay.ts +155 -0
- package/src/ui/pi-ui-compat.ts +68 -0
- package/src/ui/powerbar-publisher.ts +459 -0
- package/src/ui/render-coalescer.ts +101 -0
- package/src/ui/render-diff.ts +160 -0
- package/src/ui/render-scheduler.ts +278 -0
- package/src/ui/run-action-dispatcher.ts +182 -0
- package/src/ui/run-dashboard.ts +910 -0
- package/src/ui/run-event-bus.ts +381 -0
- package/src/ui/run-snapshot-cache.ts +1057 -0
- package/src/ui/settings-overlay.ts +1067 -0
- package/src/ui/shared-overlay-scheduler.ts +96 -0
- package/src/ui/snapshot-types.ts +90 -0
- package/src/ui/spinner.ts +17 -0
- package/src/ui/status-colors.ts +143 -0
- package/src/ui/syntax-highlight.ts +136 -0
- package/src/ui/terminal-status.ts +269 -0
- package/src/ui/theme-adapter.ts +271 -0
- package/src/ui/theme-discovery.ts +199 -0
- package/src/ui/tool-progress-formatter.ts +93 -0
- package/src/ui/tool-renderers/brief-mode.ts +225 -0
- package/src/ui/tool-renderers/index.ts +726 -0
- package/src/ui/transcript-cache.ts +128 -0
- package/src/ui/transcript-entries.ts +256 -0
- package/src/ui/transcript-viewer.ts +424 -0
- package/src/ui/widget/index.ts +418 -0
- package/src/ui/widget/widget-formatters.ts +182 -0
- package/src/ui/widget/widget-model.ts +110 -0
- package/src/ui/widget/widget-renderer.ts +182 -0
- package/src/ui/widget/widget-types.ts +36 -0
- package/src/utils/bm25-search.ts +235 -0
- package/src/utils/completion-dedupe.ts +63 -0
- package/src/utils/conflict-detect.ts +668 -0
- package/src/utils/env-allowlist.ts +30 -0
- package/src/utils/env-filter.ts +155 -0
- package/src/utils/file-coalescer.ts +98 -0
- package/src/utils/fingerprint.ts +180 -0
- package/src/utils/frontmatter.ts +70 -0
- package/src/utils/fs-watch.ts +37 -0
- package/src/utils/gh-protocol.ts +556 -0
- package/src/utils/git.ts +260 -0
- package/src/utils/guards.ts +107 -0
- package/src/utils/ids.ts +24 -0
- package/src/utils/incremental-reader.ts +220 -0
- package/src/utils/internal-error.ts +10 -0
- package/src/utils/names.ts +36 -0
- package/src/utils/ndjson.ts +115 -0
- package/src/utils/paths.ts +227 -0
- package/src/utils/project-detector.ts +160 -0
- package/src/utils/redaction.ts +370 -0
- package/src/utils/resolve-shell.ts +36 -0
- package/src/utils/run-watcher-registry.ts +152 -0
- package/src/utils/safe-paths.ts +393 -0
- package/src/utils/scan-cache.ts +144 -0
- package/src/utils/session-utils.ts +110 -0
- package/src/utils/sleep.ts +54 -0
- package/src/utils/socket-path.ts +164 -0
- package/src/utils/sse-parser.ts +131 -0
- package/src/utils/task-name-generator.ts +337 -0
- package/src/utils/timings.ts +33 -0
- package/src/utils/token-counter.ts +200 -0
- package/src/utils/visual.ts +207 -0
- package/src/workflows/cost-estimator.ts +34 -0
- package/src/workflows/discover-workflows.ts +308 -0
- package/src/workflows/intermediate-store.ts +166 -0
- package/src/workflows/preflight-validator.ts +168 -0
- package/src/workflows/topology-analyzer.ts +203 -0
- package/src/workflows/validate-workflow.ts +50 -0
- package/src/workflows/workflow-config.ts +75 -0
- package/src/workflows/workflow-serializer.ts +32 -0
- package/src/worktree/branch-freshness.ts +112 -0
- package/src/worktree/cleanup.ts +341 -0
- package/src/worktree/worktree-manager.ts +1204 -0
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
export interface ParsedPiUsage {
|
|
2
|
+
input?: number;
|
|
3
|
+
output?: number;
|
|
4
|
+
cacheRead?: number;
|
|
5
|
+
cacheWrite?: number;
|
|
6
|
+
cost?: number;
|
|
7
|
+
turns?: number;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface ParsedPiJsonOutput {
|
|
11
|
+
jsonEvents: number;
|
|
12
|
+
textEvents: string[];
|
|
13
|
+
finalText?: string;
|
|
14
|
+
usage?: ParsedPiUsage;
|
|
15
|
+
/** Unified patches extracted from tool_result events (edit tool patch field) */
|
|
16
|
+
patches?: string[];
|
|
17
|
+
/** Model/provider error messages extracted from message_end events (e.g.
|
|
18
|
+
* "429 ... overloaded"). Used to detect runs that exited 0 but produced
|
|
19
|
+
* nothing because the model was rate-limited — see task-runner 429 fix. */
|
|
20
|
+
errorMessages?: string[];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function asRecord(value: unknown): Record<string, unknown> | undefined {
|
|
24
|
+
return value && typeof value === "object" && !Array.isArray(value) ? (value as Record<string, unknown>) : undefined;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function numberField(obj: Record<string, unknown>, keys: string[]): number | undefined {
|
|
28
|
+
for (const key of keys) {
|
|
29
|
+
const value = obj[key];
|
|
30
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
31
|
+
}
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function mergeUsage(target: ParsedPiUsage, source: ParsedPiUsage): ParsedPiUsage {
|
|
36
|
+
return {
|
|
37
|
+
input: source.input ?? target.input,
|
|
38
|
+
output: source.output ?? target.output,
|
|
39
|
+
cacheRead: source.cacheRead ?? target.cacheRead,
|
|
40
|
+
cacheWrite: source.cacheWrite ?? target.cacheWrite,
|
|
41
|
+
cost: source.cost ?? target.cost,
|
|
42
|
+
turns: source.turns ?? target.turns,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function extractUsage(value: unknown): ParsedPiUsage | undefined {
|
|
47
|
+
const obj = asRecord(value);
|
|
48
|
+
if (!obj) return undefined;
|
|
49
|
+
const direct: ParsedPiUsage = {
|
|
50
|
+
input: numberField(obj, ["input", "inputTokens", "input_tokens"]),
|
|
51
|
+
output: numberField(obj, ["output", "outputTokens", "output_tokens"]),
|
|
52
|
+
cacheRead: numberField(obj, ["cacheRead", "cache_read", "cacheReadTokens", "cache_read_tokens"]),
|
|
53
|
+
cacheWrite: numberField(obj, ["cacheWrite", "cache_write", "cacheWriteTokens", "cache_write_tokens"]),
|
|
54
|
+
cost: numberField(obj, ["cost", "costUsd", "cost_usd"]),
|
|
55
|
+
turns: numberField(obj, ["turns", "turnCount", "turn_count"]),
|
|
56
|
+
};
|
|
57
|
+
if (Object.values(direct).some((entry) => entry !== undefined)) return direct;
|
|
58
|
+
// Pi --mode json nests usage under message for message_end / turn_end events.
|
|
59
|
+
for (const key of ["usage", "message", "tokenUsage", "tokens", "stats"]) {
|
|
60
|
+
const nested = extractUsage(obj[key]);
|
|
61
|
+
if (nested) return nested;
|
|
62
|
+
}
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function textFromContent(content: unknown): string[] {
|
|
67
|
+
if (typeof content === "string") return [content];
|
|
68
|
+
if (!Array.isArray(content)) return [];
|
|
69
|
+
const text: string[] = [];
|
|
70
|
+
for (const part of content) {
|
|
71
|
+
const obj = asRecord(part);
|
|
72
|
+
if (!obj) continue;
|
|
73
|
+
if (obj.type === "text" && typeof obj.text === "string") text.push(obj.text);
|
|
74
|
+
else if (typeof obj.content === "string") text.push(obj.content);
|
|
75
|
+
}
|
|
76
|
+
return text;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Extract assistant-text fragments from a parsed Pi JSON event.
|
|
80
|
+
* Exported so {@link ChildPiLineObserver} can capture the RAW (uncapped)
|
|
81
|
+
* assistant text for the authoritative result, mirroring the extraction
|
|
82
|
+
* order this function uses inside {@link parsePiJsonOutput}. */
|
|
83
|
+
export function extractText(value: unknown): string[] {
|
|
84
|
+
const obj = asRecord(value);
|
|
85
|
+
if (!obj) return [];
|
|
86
|
+
const message = asRecord(obj.message);
|
|
87
|
+
if (message?.role !== undefined && message.role !== "assistant") return [];
|
|
88
|
+
const text: string[] = [];
|
|
89
|
+
if (typeof obj.text === "string") text.push(obj.text);
|
|
90
|
+
if (typeof obj.output === "string") text.push(obj.output);
|
|
91
|
+
if (typeof obj.finalOutput === "string") text.push(obj.finalOutput);
|
|
92
|
+
if (typeof obj.final_output === "string") text.push(obj.final_output);
|
|
93
|
+
if (!message) text.push(...textFromContent(obj.content));
|
|
94
|
+
if (message) text.push(...textFromContent(message.content));
|
|
95
|
+
return text.filter((entry) => entry.trim().length > 0);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function parsePiJsonOutput(stdout: string): ParsedPiJsonOutput {
|
|
99
|
+
let jsonEvents = 0;
|
|
100
|
+
const textEvents: string[] = [];
|
|
101
|
+
const patches: string[] = [];
|
|
102
|
+
const errorMessages: string[] = [];
|
|
103
|
+
let usage: ParsedPiUsage | undefined;
|
|
104
|
+
for (const line of stdout.split("\n")) {
|
|
105
|
+
const trimmed = line.trim();
|
|
106
|
+
if (!trimmed) continue;
|
|
107
|
+
let event: unknown;
|
|
108
|
+
try {
|
|
109
|
+
event = JSON.parse(trimmed) as unknown;
|
|
110
|
+
} catch {
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
jsonEvents++;
|
|
114
|
+
textEvents.push(...extractText(event));
|
|
115
|
+
// Extract unified patches from tool_result events
|
|
116
|
+
extractPatch(event, patches);
|
|
117
|
+
// Extract provider/model error messages from message_end events (429 fix).
|
|
118
|
+
const errMsg = extractErrorMessage(event);
|
|
119
|
+
if (errMsg) errorMessages.push(errMsg);
|
|
120
|
+
const eventUsage = extractUsage(event);
|
|
121
|
+
if (eventUsage) usage = mergeUsage(usage ?? {}, eventUsage);
|
|
122
|
+
}
|
|
123
|
+
return {
|
|
124
|
+
jsonEvents,
|
|
125
|
+
textEvents,
|
|
126
|
+
finalText: textEvents.length > 0 ? textEvents[textEvents.length - 1] : undefined,
|
|
127
|
+
usage,
|
|
128
|
+
patches: patches.length > 0 ? patches : undefined,
|
|
129
|
+
errorMessages: errorMessages.length > 0 ? errorMessages : undefined,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Pull the provider/model error message out of a `message_end` event. The shape
|
|
135
|
+
* is `{type:"message_end", message:{role:"assistant", content:[], errorMessage:"429 ...", stopReason:"error"}}`.
|
|
136
|
+
* Returns undefined for events without an errorMessage.
|
|
137
|
+
*/
|
|
138
|
+
function extractErrorMessage(event: unknown): string | undefined {
|
|
139
|
+
const obj = asRecord(event);
|
|
140
|
+
if (!obj) return undefined;
|
|
141
|
+
// message_end events carry the error on the nested message object.
|
|
142
|
+
const message = asRecord(obj.message) ?? obj;
|
|
143
|
+
const errorMessage = message.errorMessage;
|
|
144
|
+
return typeof errorMessage === "string" && errorMessage.trim() ? errorMessage.trim() : undefined;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Extract unified patches from a tool_result event.
|
|
149
|
+
* pi's edit tool now includes a `patch` field (standard unified diff format).
|
|
150
|
+
* We detect it by looking for lines starting with "---" or "+++" which indicate
|
|
151
|
+
* unified diff format.
|
|
152
|
+
*/
|
|
153
|
+
function extractPatch(event: unknown, patches: string[]): void {
|
|
154
|
+
const obj = asRecord(event);
|
|
155
|
+
if (obj?.type !== "tool_result") return;
|
|
156
|
+
|
|
157
|
+
const content = obj.content;
|
|
158
|
+
if (!Array.isArray(content)) return;
|
|
159
|
+
|
|
160
|
+
for (const item of content) {
|
|
161
|
+
const part = asRecord(item);
|
|
162
|
+
if (part?.type !== "text") continue;
|
|
163
|
+
const text = typeof part.text === "string" ? part.text : "";
|
|
164
|
+
|
|
165
|
+
// Check if this looks like a unified patch (starts with "---" or "+++")
|
|
166
|
+
if (text.includes("--- a/") || text.includes("diff ---")) {
|
|
167
|
+
patches.push(text);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
import { execSync } from "node:child_process";
|
|
2
|
+
import * as fs from "node:fs";
|
|
3
|
+
import * as os from "node:os";
|
|
4
|
+
import * as path from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
|
|
7
|
+
export interface PiSpawnCommand {
|
|
8
|
+
command: string;
|
|
9
|
+
args: string[];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const PI_PACKAGE_NAMES = ["@earendil-works/pi-coding-agent", "@mariozechner/pi-coding-agent"];
|
|
13
|
+
|
|
14
|
+
function isRunnableNodeScript(filePath: string): boolean {
|
|
15
|
+
return fs.existsSync(filePath) && /\.(?:mjs|cjs|js)$/i.test(filePath);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Check that a resolved path is within known safe prefixes.
|
|
20
|
+
* Allowed prefixes: npm global bin (APPDATA/npm), project node_modules/.bin,
|
|
21
|
+
* or the current process's execPath directory.
|
|
22
|
+
*/
|
|
23
|
+
function isWithinAllowedPrefixes(resolvedPath: string): boolean {
|
|
24
|
+
const normalized = path.resolve(resolvedPath).toLowerCase();
|
|
25
|
+
|
|
26
|
+
const allowedPrefixes: string[] = [];
|
|
27
|
+
|
|
28
|
+
// Current process execPath directory (e.g. node installation)
|
|
29
|
+
try {
|
|
30
|
+
const execDir = path.dirname(fs.realpathSync.native(process.execPath));
|
|
31
|
+
allowedPrefixes.push(execDir.toLowerCase());
|
|
32
|
+
allowedPrefixes.push(path.join(path.dirname(execDir), "lib", "node_modules").toLowerCase());
|
|
33
|
+
} catch {
|
|
34
|
+
/* ignore */
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// npm global bin via APPDATA
|
|
38
|
+
if (process.env.APPDATA) {
|
|
39
|
+
allowedPrefixes.push(path.join(process.env.APPDATA, "npm").toLowerCase());
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const npmPrefix = process.env.npm_config_prefix ?? process.env.NPM_CONFIG_PREFIX;
|
|
43
|
+
if (npmPrefix) {
|
|
44
|
+
allowedPrefixes.push(path.resolve(npmPrefix).toLowerCase());
|
|
45
|
+
allowedPrefixes.push(path.join(path.resolve(npmPrefix), "lib", "node_modules").toLowerCase());
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Project-local node_modules/.bin
|
|
49
|
+
try {
|
|
50
|
+
const projectBin = path.resolve("node_modules", ".bin");
|
|
51
|
+
allowedPrefixes.push(projectBin.toLowerCase());
|
|
52
|
+
} catch {
|
|
53
|
+
/* ignore */
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// User home npm-global
|
|
57
|
+
try {
|
|
58
|
+
const homeNpm = path.join(os.homedir(), ".npm-global", "bin");
|
|
59
|
+
allowedPrefixes.push(homeNpm.toLowerCase());
|
|
60
|
+
} catch {
|
|
61
|
+
/* ignore */
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// User home .local/bin
|
|
65
|
+
try {
|
|
66
|
+
const homeLocal = path.join(os.homedir(), ".local", "bin");
|
|
67
|
+
allowedPrefixes.push(homeLocal.toLowerCase());
|
|
68
|
+
} catch {
|
|
69
|
+
/* ignore */
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return allowedPrefixes.some((prefix) => normalized.startsWith(prefix));
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function resolvePiPackageRoot(): string | undefined {
|
|
76
|
+
try {
|
|
77
|
+
const entry = process.argv[1];
|
|
78
|
+
if (!entry) return undefined;
|
|
79
|
+
let dir = path.dirname(fs.realpathSync(entry));
|
|
80
|
+
while (dir !== path.dirname(dir)) {
|
|
81
|
+
try {
|
|
82
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(dir, "package.json"), "utf-8")) as { name?: string };
|
|
83
|
+
if (pkg.name && PI_PACKAGE_NAMES.includes(pkg.name)) return dir;
|
|
84
|
+
} catch {
|
|
85
|
+
// Continue walking upward.
|
|
86
|
+
}
|
|
87
|
+
dir = path.dirname(dir);
|
|
88
|
+
}
|
|
89
|
+
} catch {
|
|
90
|
+
return undefined;
|
|
91
|
+
}
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function packageBinScript(packageJsonPath: string): string | undefined {
|
|
96
|
+
try {
|
|
97
|
+
const pkg = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8")) as {
|
|
98
|
+
bin?: string | Record<string, string>;
|
|
99
|
+
};
|
|
100
|
+
const binPath = typeof pkg.bin === "string" ? pkg.bin : (pkg.bin?.pi ?? Object.values(pkg.bin ?? {})[0]);
|
|
101
|
+
if (!binPath) return undefined;
|
|
102
|
+
const candidate = path.resolve(path.dirname(packageJsonPath), binPath);
|
|
103
|
+
return isRunnableNodeScript(candidate) ? candidate : undefined;
|
|
104
|
+
} catch {
|
|
105
|
+
return undefined;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function findPiPackageJsonFrom(startDir: string): string | undefined {
|
|
110
|
+
let dir = startDir;
|
|
111
|
+
while (dir !== path.dirname(dir)) {
|
|
112
|
+
const direct = path.join(dir, "package.json");
|
|
113
|
+
try {
|
|
114
|
+
const pkg = JSON.parse(fs.readFileSync(direct, "utf-8")) as {
|
|
115
|
+
name?: string;
|
|
116
|
+
};
|
|
117
|
+
if (pkg.name && PI_PACKAGE_NAMES.includes(pkg.name)) return direct;
|
|
118
|
+
} catch {
|
|
119
|
+
// Continue searching upward and in node_modules.
|
|
120
|
+
}
|
|
121
|
+
for (const pkgName of PI_PACKAGE_NAMES) {
|
|
122
|
+
const [scope, name] = pkgName.replace("@", "").split("/");
|
|
123
|
+
const dependency = path.join(dir, "node_modules", `@${scope}`, name, "package.json");
|
|
124
|
+
if (fs.existsSync(dependency)) return dependency;
|
|
125
|
+
}
|
|
126
|
+
dir = path.dirname(dir);
|
|
127
|
+
}
|
|
128
|
+
return undefined;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Discover the real npm global node_modules directory at runtime.
|
|
133
|
+
*
|
|
134
|
+
* Why this exists (Issue #33): on Windows, pi may be installed somewhere
|
|
135
|
+
* other than %APPDATA%\npm — e.g. nvm-windows puts the global node_modules
|
|
136
|
+
* under %NVM_HOME%/<version>/node_modules, Volta under
|
|
137
|
+
* %LOCALAPPDATA%\Volta, fnm under %LOCALAPPDATA%\fnm_multishells. The static
|
|
138
|
+
* %APPDATA%\npm paths in resolvePiCliScript() miss all of those, and the
|
|
139
|
+
* fallback spawn("pi") then fails with ENOENT because child_process.spawn does
|
|
140
|
+
* NOT do PATHEXT resolution on Windows (only exec/execSync via cmd.exe do).
|
|
141
|
+
*
|
|
142
|
+
* `npm root -g` is the canonical way to find the global node_modules dir and
|
|
143
|
+
* works across every npm-based install layout. We run it via execSync, which
|
|
144
|
+
* DOES resolve `npm.cmd` through PATHEXT. Capped at 5s; any failure (npm not
|
|
145
|
+
* on PATH, slow start, etc.) just falls through to the other resolution roots.
|
|
146
|
+
*
|
|
147
|
+
* Memoized: the npm global root does not change during a process lifetime, so
|
|
148
|
+
* this is a one-time ~200ms cost rather than per-worker.
|
|
149
|
+
*
|
|
150
|
+
* @internal — exported for unit-test injection via __setNpmGlobalRootForTest.
|
|
151
|
+
*/
|
|
152
|
+
let cachedNpmGlobalRoot: string | undefined | null = null;
|
|
153
|
+
export function resolveNpmGlobalRoot(): string | undefined {
|
|
154
|
+
if (cachedNpmGlobalRoot !== null) {
|
|
155
|
+
return cachedNpmGlobalRoot ?? undefined;
|
|
156
|
+
}
|
|
157
|
+
let resolved: string | undefined;
|
|
158
|
+
try {
|
|
159
|
+
const out = execSync("npm root -g", {
|
|
160
|
+
encoding: "utf-8",
|
|
161
|
+
timeout: 5000,
|
|
162
|
+
stdio: ["pipe", "pipe", "pipe"], // suppress npm's stderr chatter
|
|
163
|
+
windowsHide: true,
|
|
164
|
+
}).trim();
|
|
165
|
+
resolved = out.length > 0 ? out : undefined;
|
|
166
|
+
} catch {
|
|
167
|
+
resolved = undefined;
|
|
168
|
+
}
|
|
169
|
+
cachedNpmGlobalRoot = resolved ?? null;
|
|
170
|
+
return resolved;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Given an npm global node_modules root, derive the candidate package dirs for
|
|
175
|
+
* each supported pi scope. Pure + exported so the mapping is unit-testable
|
|
176
|
+
* without spawning npm.
|
|
177
|
+
* @internal
|
|
178
|
+
*/
|
|
179
|
+
export function buildNpmGlobalPackageDirs(npmGlobalRoot: string): string[] {
|
|
180
|
+
return PI_PACKAGE_NAMES.map((pkgName) => path.join(npmGlobalRoot, ...pkgName.split("/")));
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/** @internal — test hook: inject a fake global root (or undefined) and reset the memo. */
|
|
184
|
+
export function __setNpmGlobalRootForTest(root: string | undefined): void {
|
|
185
|
+
cachedNpmGlobalRoot = root ?? null;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function resolvePiCliScript(): string | undefined {
|
|
189
|
+
const argv1 = process.argv[1];
|
|
190
|
+
if (argv1) {
|
|
191
|
+
const argvPath = path.isAbsolute(argv1) ? argv1 : path.resolve(argv1);
|
|
192
|
+
// Only trust argv1 if we can confirm the current process is running from
|
|
193
|
+
// the pi-coding-agent package directory. Otherwise, when pi-crew is invoked
|
|
194
|
+
// from a standalone test script (process.argv[1] = test script path),
|
|
195
|
+
// resolvePiCliScript would incorrectly return the test script as the pi
|
|
196
|
+
// CLI. resolvePiPackageRoot walks up from argv1 looking for a package.json
|
|
197
|
+
// named @earendil-works/pi-coding-agent or @mariozechner/pi-coding-agent.
|
|
198
|
+
if (resolvePiPackageRoot() && isRunnableNodeScript(argvPath)) return argvPath;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// npm-global package dirs derived from `npm root -g` — placed BEFORE the
|
|
202
|
+
// %APPDATA%\npm static paths and the cwd/import.meta fallbacks so that a pi
|
|
203
|
+
// install under nvm-windows / Volta / fnm is found even when %APPDATA%\npm
|
|
204
|
+
// doesn't contain it. Covers Issue #33.
|
|
205
|
+
const npmGlobalRoot = resolveNpmGlobalRoot();
|
|
206
|
+
const npmGlobalDirs = npmGlobalRoot ? buildNpmGlobalPackageDirs(npmGlobalRoot) : [];
|
|
207
|
+
|
|
208
|
+
const roots = [
|
|
209
|
+
resolvePiPackageRoot(),
|
|
210
|
+
...npmGlobalDirs,
|
|
211
|
+
process.env.APPDATA ? path.join(process.env.APPDATA, "npm", "node_modules", "@earendil-works", "pi-coding-agent") : undefined,
|
|
212
|
+
process.env.APPDATA ? path.join(process.env.APPDATA, "npm", "node_modules", "@mariozechner", "pi-coding-agent") : undefined,
|
|
213
|
+
path.dirname(fileURLToPath(import.meta.url)),
|
|
214
|
+
process.cwd(),
|
|
215
|
+
].filter((entry): entry is string => Boolean(entry));
|
|
216
|
+
|
|
217
|
+
for (const root of roots) {
|
|
218
|
+
const packageJsonPath = root.endsWith("package.json") ? root : (findPiPackageJsonFrom(root) ?? path.join(root, "package.json"));
|
|
219
|
+
const script = packageBinScript(packageJsonPath);
|
|
220
|
+
if (script) return script;
|
|
221
|
+
}
|
|
222
|
+
return undefined;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function validateExplicitBin(explicit: string): string | undefined {
|
|
226
|
+
const resolved = path.resolve(explicit);
|
|
227
|
+
if (!fs.existsSync(resolved)) return undefined;
|
|
228
|
+
// Reject paths outside allowed safe prefixes
|
|
229
|
+
if (!isWithinAllowedPrefixes(resolved)) {
|
|
230
|
+
throw new Error(
|
|
231
|
+
`PI_TEAMS_PI_BIN path '${resolved}' is outside allowed prefixes. ` +
|
|
232
|
+
`Allowed: npm global bin, project node_modules/.bin, APPDATA/npm, or process execPath directory.`,
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
// Reject if symlink points outside expected directories
|
|
236
|
+
try {
|
|
237
|
+
const real = fs.realpathSync(resolved);
|
|
238
|
+
if (!isWithinAllowedPrefixes(real)) {
|
|
239
|
+
throw new Error(`PI_TEAMS_PI_BIN symlink target '${real}' is outside allowed prefixes.`);
|
|
240
|
+
}
|
|
241
|
+
} catch (e) {
|
|
242
|
+
if (e instanceof Error && e.message.includes("allowed prefixes")) throw e;
|
|
243
|
+
console.error("[pi-spawn] validateExplicitBin: unexpected realpathSync error:", e);
|
|
244
|
+
return undefined;
|
|
245
|
+
}
|
|
246
|
+
return resolved;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
export function getPiSpawnCommand(args: string[]): PiSpawnCommand {
|
|
250
|
+
const explicit = process.env.PI_TEAMS_PI_BIN?.trim();
|
|
251
|
+
if (explicit) {
|
|
252
|
+
const validated = validateExplicitBin(explicit);
|
|
253
|
+
if (validated) {
|
|
254
|
+
if (isRunnableNodeScript(validated))
|
|
255
|
+
return {
|
|
256
|
+
command: process.execPath,
|
|
257
|
+
args: [validated, ...args],
|
|
258
|
+
};
|
|
259
|
+
return { command: validated, args };
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
if (process.platform === "win32") {
|
|
263
|
+
// Windows: resolve via resolvePiCliScript to find the bundled .js entry point
|
|
264
|
+
const script = resolvePiCliScript();
|
|
265
|
+
if (script) return { command: process.execPath, args: [script, ...args] };
|
|
266
|
+
}
|
|
267
|
+
// Linux/macOS: also resolve the full path so child processes can find 'pi' even if
|
|
268
|
+
// PATH is minimal (e.g. in detached background-runner processes). Fall back to "pi"
|
|
269
|
+
// only if resolution fails.
|
|
270
|
+
const script = resolvePiCliScript();
|
|
271
|
+
if (script) return { command: process.execPath, args: [script, ...args] };
|
|
272
|
+
return { command: "pi", args };
|
|
273
|
+
}
|