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
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { AgentConfig } from "../agents/agent-config.ts";
|
|
2
|
+
import type { SkillDescriptor } from "../skills/discover-skills.ts";
|
|
2
3
|
import type { TeamConfig } from "../teams/team-config.ts";
|
|
4
|
+
import { resolveContainedPath } from "../utils/safe-paths.ts";
|
|
3
5
|
import type { WorkflowConfig } from "../workflows/workflow-config.ts";
|
|
4
|
-
import type { SkillDescriptor } from "../skills/discover-skills.ts";
|
|
5
|
-
import type { ExportContent } from "./types.ts";
|
|
6
6
|
import { adapterRegistry } from "./registry.ts";
|
|
7
|
-
import {
|
|
7
|
+
import type { ExportContent } from "./types.ts";
|
|
8
8
|
|
|
9
9
|
function slugify(value: string): string {
|
|
10
10
|
return value
|
|
@@ -30,9 +30,7 @@ export function agentToExportContent(agent: AgentConfig): ExportContent {
|
|
|
30
30
|
export function teamToExportContent(team: TeamConfig): ExportContent {
|
|
31
31
|
const category = team.routing?.category ?? "team";
|
|
32
32
|
const tags = team.routing?.triggers ?? [];
|
|
33
|
-
const rolesDesc = team.roles
|
|
34
|
-
.map((role) => `- **${role.name}**: ${role.description ?? role.agent}`)
|
|
35
|
-
.join("\n");
|
|
33
|
+
const rolesDesc = team.roles.map((role) => `- **${role.name}**: ${role.description ?? role.agent}`).join("\n");
|
|
36
34
|
const body = `${team.description}\n\n### Roles\n${rolesDesc}`;
|
|
37
35
|
return {
|
|
38
36
|
id: slugify(team.name),
|
|
@@ -46,9 +44,7 @@ export function teamToExportContent(team: TeamConfig): ExportContent {
|
|
|
46
44
|
}
|
|
47
45
|
|
|
48
46
|
export function workflowToExportContent(workflow: WorkflowConfig): ExportContent {
|
|
49
|
-
const stepsDesc = workflow.steps
|
|
50
|
-
.map((step) => `- **${step.id}** (${step.role}): ${step.task}`)
|
|
51
|
-
.join("\n");
|
|
47
|
+
const stepsDesc = workflow.steps.map((step) => `- **${step.id}** (${step.role}): ${step.task}`).join("\n");
|
|
52
48
|
const body = `${workflow.description}\n\n### Steps\n${stepsDesc}`;
|
|
53
49
|
return {
|
|
54
50
|
id: slugify(workflow.name),
|
|
@@ -105,14 +101,15 @@ export interface ToolExportResult {
|
|
|
105
101
|
files: Array<{ path: string; content: string }>;
|
|
106
102
|
}
|
|
107
103
|
|
|
108
|
-
export function generateToolExport(
|
|
109
|
-
toolId: string,
|
|
110
|
-
resources: ExportableResource[],
|
|
111
|
-
projectRoot?: string,
|
|
112
|
-
): ToolExportResult {
|
|
104
|
+
export function generateToolExport(toolId: string, resources: ExportableResource[], projectRoot?: string): ToolExportResult {
|
|
113
105
|
const adapter = adapterRegistry.get(toolId);
|
|
114
106
|
if (!adapter) {
|
|
115
|
-
throw new Error(
|
|
107
|
+
throw new Error(
|
|
108
|
+
`Unknown export adapter: ${toolId}. Available: ${adapterRegistry
|
|
109
|
+
.getAll()
|
|
110
|
+
.map((a) => a.toolId)
|
|
111
|
+
.join(", ")}`,
|
|
112
|
+
);
|
|
116
113
|
}
|
|
117
114
|
const contents = resourcesToExportContent(resources);
|
|
118
115
|
const files = contents.map((content): { path: string; content: string } => {
|
|
@@ -138,6 +135,9 @@ export function generateToolExport(
|
|
|
138
135
|
const existing = merged.get(f.path);
|
|
139
136
|
merged.set(f.path, existing ? `${existing}\n\n${f.content}` : f.content);
|
|
140
137
|
}
|
|
141
|
-
const mergedFiles = [...merged.entries()].map(([p, content]) => ({
|
|
138
|
+
const mergedFiles = [...merged.entries()].map(([p, content]) => ({
|
|
139
|
+
path: p,
|
|
140
|
+
content,
|
|
141
|
+
}));
|
|
142
142
|
return { toolId, files: mergedFiles };
|
|
143
143
|
}
|
package/src/adapters/index.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
export type { ExportContent, ExportAdapter, AdapterRegistry } from "./types.ts";
|
|
2
|
-
export { createAdapterRegistry, adapterRegistry } from "./registry.ts";
|
|
3
1
|
export { claudeAdapter } from "./claude-adapter.ts";
|
|
4
|
-
export { cursorAdapter } from "./cursor-adapter.ts";
|
|
5
2
|
export { codexAdapter } from "./codex-adapter.ts";
|
|
3
|
+
export { cursorAdapter } from "./cursor-adapter.ts";
|
|
6
4
|
export { generateToolExport, resourcesToExportContent } from "./export-util.ts";
|
|
5
|
+
export { adapterRegistry, createAdapterRegistry } from "./registry.ts";
|
|
6
|
+
export type { AdapterRegistry, ExportAdapter, ExportContent } from "./types.ts";
|
|
7
7
|
|
|
8
|
-
import { adapterRegistry } from "./registry.ts";
|
|
9
8
|
import { claudeAdapter } from "./claude-adapter.ts";
|
|
10
|
-
import { cursorAdapter } from "./cursor-adapter.ts";
|
|
11
9
|
import { codexAdapter } from "./codex-adapter.ts";
|
|
10
|
+
import { cursorAdapter } from "./cursor-adapter.ts";
|
|
11
|
+
import { adapterRegistry } from "./registry.ts";
|
|
12
12
|
|
|
13
13
|
adapterRegistry.register(claudeAdapter);
|
|
14
14
|
adapterRegistry.register(cursorAdapter);
|
|
@@ -9,15 +9,7 @@ import { getToolConfig } from "../config/role-tools.ts";
|
|
|
9
9
|
* the wildcard expansion will pick it up. The 7 names below are stable
|
|
10
10
|
* across pi v0.77+ and cover read, edit, write, bash, grep, find, ls.
|
|
11
11
|
*/
|
|
12
|
-
export const BUILTIN_TOOL_NAMES: readonly string[] = [
|
|
13
|
-
"read",
|
|
14
|
-
"edit",
|
|
15
|
-
"write",
|
|
16
|
-
"bash",
|
|
17
|
-
"grep",
|
|
18
|
-
"find",
|
|
19
|
-
"ls",
|
|
20
|
-
];
|
|
12
|
+
export const BUILTIN_TOOL_NAMES: readonly string[] = ["read", "edit", "write", "bash", "grep", "find", "ls"];
|
|
21
13
|
|
|
22
14
|
/**
|
|
23
15
|
* F1 (v0.7.9): normalize the raw `tools:` frontmatter CSV into a `string[]`.
|
|
@@ -41,7 +33,10 @@ export function parseToolsField(raw: unknown): string[] | undefined {
|
|
|
41
33
|
const lowered = s.toLowerCase();
|
|
42
34
|
if (lowered === "none" || lowered === "[]") return [];
|
|
43
35
|
if (lowered === "*" || lowered === "all") return [...BUILTIN_TOOL_NAMES];
|
|
44
|
-
const items = s
|
|
36
|
+
const items = s
|
|
37
|
+
.split(",")
|
|
38
|
+
.map((t) => t.trim())
|
|
39
|
+
.filter(Boolean);
|
|
45
40
|
return items;
|
|
46
41
|
}
|
|
47
42
|
|
|
@@ -160,12 +155,23 @@ function uniqueToolMerge(...lists: Array<string[] | undefined>): string[] | unde
|
|
|
160
155
|
export function resolveToolPolicy(agent: AgentConfig, role?: string): ResolvedToolPolicy {
|
|
161
156
|
const roleConfig = role ? getToolConfig(role) : {};
|
|
162
157
|
// allowlist: source-aware precedence (see doc above).
|
|
163
|
-
const explicitTools = agent.source === "builtin"
|
|
164
|
-
|
|
165
|
-
|
|
158
|
+
const explicitTools = agent.source === "builtin" ? (roleConfig.tools ?? agent.tools) : (agent.tools ?? roleConfig.tools);
|
|
159
|
+
// L5: when the agent opts into `loadMode: "lean"` AND provides a
|
|
160
|
+
// non-empty `defaultTools` list, merge that list into the resolved
|
|
161
|
+
// allowlist. The merge is additive (union, dedup, order-preserving) so
|
|
162
|
+
// the existing source-aware precedence is preserved and a lean agent
|
|
163
|
+
// gets a focused-but-non-empty tool set. Signal flow:
|
|
164
|
+
// agent YAML frontmatter (loadMode, defaultTools)
|
|
165
|
+
// → parsed into AgentConfig
|
|
166
|
+
// → resolveToolPolicy(agent, role) here
|
|
167
|
+
// → policy.tools returned to buildPiWorkerArgs
|
|
168
|
+
// → `args.push("--tools", policy.tools.join(","))` in pi-args.ts
|
|
169
|
+
// → child pi process sees the merged allowlist
|
|
170
|
+
const tools =
|
|
171
|
+
agent.loadMode === "lean" && agent.defaultTools?.length ? uniqueToolMerge(explicitTools, agent.defaultTools) : explicitTools;
|
|
166
172
|
// denylist: additive merge of role excludeTools + agent disallowedTools.
|
|
167
173
|
const excludeTools = uniqueToolMerge(roleConfig.excludeTools, agent.disallowedTools);
|
|
168
|
-
return { tools
|
|
174
|
+
return { tools, excludeTools };
|
|
169
175
|
}
|
|
170
176
|
|
|
171
177
|
/**
|
|
@@ -15,7 +15,7 @@ export function serializeAgent(agent: AgentConfig): string {
|
|
|
15
15
|
line("fallbackModels", agent.fallbackModels),
|
|
16
16
|
line("thinking", agent.thinking),
|
|
17
17
|
line("tools", agent.tools),
|
|
18
|
-
agent.extensions !== undefined ? line("extensions", agent.extensions) ?? "extensions:" : undefined,
|
|
18
|
+
agent.extensions !== undefined ? (line("extensions", agent.extensions) ?? "extensions:") : undefined,
|
|
19
19
|
line("skills", agent.skills),
|
|
20
20
|
line("systemPromptMode", agent.systemPromptMode),
|
|
21
21
|
line("inheritProjectContext", agent.inheritProjectContext),
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
|
-
import type
|
|
4
|
-
import { parseToolsField } from "./agent-config.ts";
|
|
5
|
-
import { loadConfig, type LoadedPiTeamsConfig } from "../config/config.ts";
|
|
3
|
+
import { type LoadedPiTeamsConfig, loadConfig } from "../config/config.ts";
|
|
6
4
|
import { parseCsv, parseFrontmatter } from "../utils/frontmatter.ts";
|
|
7
5
|
import { logInternalError } from "../utils/internal-error.ts";
|
|
8
|
-
import { packageRoot, projectCrewRoot, userPiRoot
|
|
6
|
+
import { findRepoRoot, packageRoot, projectCrewRoot, userPiRoot } from "../utils/paths.ts";
|
|
7
|
+
import type { AgentConfig, ResourceSource } from "./agent-config.ts";
|
|
8
|
+
import { parseToolsField } from "./agent-config.ts";
|
|
9
9
|
|
|
10
10
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
11
11
|
// SEC-001 Fix: Protected Agent Names Blocklist
|
|
@@ -21,7 +21,6 @@ import { packageRoot, projectCrewRoot, userPiRoot, findRepoRoot } from "../utils
|
|
|
21
21
|
// See: SECURITY-ISSUES.md SEC-005
|
|
22
22
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
23
23
|
|
|
24
|
-
|
|
25
24
|
/** Version counter for atomic cache invalidation. Incremented on every mutation. */
|
|
26
25
|
let cacheVersion = 0;
|
|
27
26
|
|
|
@@ -69,14 +68,23 @@ const PROTECTED_AGENT_PATTERNS: Array<{ pattern: RegExp; example: string }> = [
|
|
|
69
68
|
{ pattern: /^explorer[-_]/i, example: "explorer-debug" },
|
|
70
69
|
{ pattern: /^planner[-_]/i, example: "planner-v3" },
|
|
71
70
|
// Generic prefixes that could impersonate builtins
|
|
72
|
-
{
|
|
73
|
-
|
|
71
|
+
{
|
|
72
|
+
pattern: /^(my|custom|new|local)[-_](executor|test[-_]?engineer|explorer|planner)$/i,
|
|
73
|
+
example: "my-executor",
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
pattern: /^(executor|test[-_]?engineer|explorer|planner)[-_]?(proxy|hook|override)$/i,
|
|
77
|
+
example: "executor-override",
|
|
78
|
+
},
|
|
74
79
|
// Common typosquatting patterns (intentional misspellings)
|
|
75
80
|
{ pattern: /^exec[au]t[o0]r$/i, example: "execator" },
|
|
76
81
|
{ pattern: /^expl[o0]rer$/i, example: "explorer" },
|
|
77
82
|
{ pattern: /^plann[ae]r$/i, example: "plannar" },
|
|
78
83
|
// Suffixes that indicate override意图
|
|
79
|
-
{
|
|
84
|
+
{
|
|
85
|
+
pattern: /^(executor|test[-_]?engineer|explorer|planner)[-_]?(override|replacement|shadow)$/i,
|
|
86
|
+
example: "executor-override",
|
|
87
|
+
},
|
|
80
88
|
];
|
|
81
89
|
|
|
82
90
|
/**
|
|
@@ -123,11 +131,7 @@ function logSecurityEvent(event: SecurityEvent): void {
|
|
|
123
131
|
}
|
|
124
132
|
|
|
125
133
|
// Log security events via structured logger
|
|
126
|
-
logInternalError(
|
|
127
|
-
`security.${event.type}`,
|
|
128
|
-
undefined,
|
|
129
|
-
`agent="${event.name}" reason="${event.reason}"`,
|
|
130
|
-
);
|
|
134
|
+
logInternalError(`security.${event.type}`, undefined, `agent="${event.name}" reason="${event.reason}"`);
|
|
131
135
|
}
|
|
132
136
|
|
|
133
137
|
/**
|
|
@@ -167,7 +171,7 @@ function assertAgentNameAllowed(name: string): void {
|
|
|
167
171
|
});
|
|
168
172
|
throw new Error(
|
|
169
173
|
`SECURITY: Cannot register agent '${name}': protected builtin name. ` +
|
|
170
|
-
|
|
174
|
+
`Dynamic agents cannot shadow builtin agents (executor, explorer, planner, etc.) to prevent privilege escalation.`,
|
|
171
175
|
);
|
|
172
176
|
}
|
|
173
177
|
|
|
@@ -182,7 +186,7 @@ function assertAgentNameAllowed(name: string): void {
|
|
|
182
186
|
});
|
|
183
187
|
throw new Error(
|
|
184
188
|
`SECURITY: Cannot register agent '${name}': name matches protected pattern (${matchedPattern}). ` +
|
|
185
|
-
|
|
189
|
+
`This pattern is blocked to prevent privilege escalation via similar-named agents.`,
|
|
186
190
|
);
|
|
187
191
|
}
|
|
188
192
|
}
|
|
@@ -284,7 +288,7 @@ function sourceToTrustLevel(source: ResourceSource): TrustLevel {
|
|
|
284
288
|
case "user":
|
|
285
289
|
return "user";
|
|
286
290
|
case "project":
|
|
287
|
-
|
|
291
|
+
return "project";
|
|
288
292
|
default:
|
|
289
293
|
return "project";
|
|
290
294
|
}
|
|
@@ -305,10 +309,7 @@ function sourceToTrustLevel(source: ResourceSource): TrustLevel {
|
|
|
305
309
|
* - user: Standard sanitization
|
|
306
310
|
* - project: Strict sanitization (untrusted source)
|
|
307
311
|
*/
|
|
308
|
-
export function sanitizeAgentSystemPrompt(
|
|
309
|
-
content: string,
|
|
310
|
-
source: ResourceSource
|
|
311
|
-
): string {
|
|
312
|
+
export function sanitizeAgentSystemPrompt(content: string, source: ResourceSource): string {
|
|
312
313
|
const trustLevel = sourceToTrustLevel(source);
|
|
313
314
|
let sanitized = content;
|
|
314
315
|
|
|
@@ -323,7 +324,7 @@ export function sanitizeAgentSystemPrompt(
|
|
|
323
324
|
// Strip lines that look like system directives
|
|
324
325
|
sanitized = sanitized.replace(
|
|
325
326
|
/^\s*(?:SYSTEM|INSTRUCTION|IGNORE(?:\s+ALL)?\s+(?:PREVIOUS|INSTRUCTIONS)?|OVERRIDE|YOUR\s+ROLE\s+IS|MALICIOUS|BACKDOOR)\s*:.*$/gim,
|
|
326
|
-
""
|
|
327
|
+
"",
|
|
327
328
|
);
|
|
328
329
|
|
|
329
330
|
// Strip embedded instruction patterns in brackets
|
|
@@ -357,6 +358,17 @@ export function sanitizeAgentSystemPrompt(
|
|
|
357
358
|
return sanitized.trim();
|
|
358
359
|
}
|
|
359
360
|
|
|
361
|
+
/**
|
|
362
|
+
* M4: per-process dedup set of agent filePaths for which we've already
|
|
363
|
+
* emitted the `contextMode: fork` warn-only notice. Avoids spam when
|
|
364
|
+
* the discovery cache reloads or the same agent is parsed multiple
|
|
365
|
+
* times in a session. Exported for test reset.
|
|
366
|
+
*/
|
|
367
|
+
const warnedForkAgents = new Set<string>();
|
|
368
|
+
export function __test_resetForkWarnings(): void {
|
|
369
|
+
warnedForkAgents.clear();
|
|
370
|
+
}
|
|
371
|
+
|
|
360
372
|
function parseAgentFile(filePath: string, source: ResourceSource): AgentConfig | undefined {
|
|
361
373
|
try {
|
|
362
374
|
const content = fs.readFileSync(filePath, "utf-8");
|
|
@@ -373,6 +385,27 @@ function parseAgentFile(filePath: string, source: ResourceSource): AgentConfig |
|
|
|
373
385
|
const rawSystemPrompt = body.trim();
|
|
374
386
|
const systemPrompt = sanitizeAgentSystemPrompt(rawSystemPrompt, source);
|
|
375
387
|
|
|
388
|
+
const contextMode = parseContextMode(frontmatter.contextMode);
|
|
389
|
+
|
|
390
|
+
// M4: warn-only when contextMode=fork is configured but the
|
|
391
|
+
// runtime is the default child-process path. `contextMode: fork`
|
|
392
|
+
// is only effective in the live-session runtime (the experimental
|
|
393
|
+
// path that runs the agent IN the parent pi's session). The
|
|
394
|
+
// default child-process path (runChildPi in src/runtime/child-pi.ts)
|
|
395
|
+
// spawns a NEW pi process and has no parent session to inherit,
|
|
396
|
+
// so the agent will behave as `fresh` regardless of the setting.
|
|
397
|
+
// We warn (not throw) so existing configs that predate live-session
|
|
398
|
+
// keep working. Deduped per-filePath so we don't spam on cache
|
|
399
|
+
// reload. Use console.warn (no logger hook here yet; a future
|
|
400
|
+
// refactor could pipe through the same log channel as
|
|
401
|
+
// logInternalError below).
|
|
402
|
+
if (contextMode === "fork" && !warnedForkAgents.has(filePath)) {
|
|
403
|
+
console.warn(
|
|
404
|
+
"contextMode: 'fork' is only effective in live-session runtime; current default child-process will behave as 'fresh'. See docs/runtime-modes.md.",
|
|
405
|
+
);
|
|
406
|
+
warnedForkAgents.add(filePath);
|
|
407
|
+
}
|
|
408
|
+
|
|
376
409
|
return {
|
|
377
410
|
name,
|
|
378
411
|
description,
|
|
@@ -389,15 +422,21 @@ function parseAgentFile(filePath: string, source: ResourceSource): AgentConfig |
|
|
|
389
422
|
skills: parseCsv(frontmatter.skills ?? frontmatter.skill),
|
|
390
423
|
systemPromptMode: frontmatter.systemPromptMode === "append" ? "append" : "replace",
|
|
391
424
|
inheritProjectContext: frontmatter.inheritProjectContext === "true",
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
425
|
+
inheritSkills: frontmatter.inheritSkills === "true",
|
|
426
|
+
memory: parseMemory(frontmatter.memory),
|
|
427
|
+
loadMode: parseLoadMode(frontmatter.loadMode),
|
|
428
|
+
defaultTools: frontmatter.defaultTools !== undefined ? (parseCsv(frontmatter.defaultTools) ?? null) : undefined,
|
|
429
|
+
contextMode,
|
|
430
|
+
maxTurns: (() => {
|
|
431
|
+
const n = Number.parseInt(frontmatter.maxTurns, 10);
|
|
432
|
+
return Number.isFinite(n) && n > 0 ? n : undefined;
|
|
433
|
+
})(),
|
|
434
|
+
effort:
|
|
435
|
+
frontmatter.effort === "low" || frontmatter.effort === "medium" || frontmatter.effort === "high"
|
|
436
|
+
? frontmatter.effort
|
|
437
|
+
: undefined,
|
|
438
|
+
disabled: frontmatter.disabled === "true" || frontmatter.enabled === "false",
|
|
439
|
+
routing: triggers || useWhen || avoidWhen || cost || category ? { triggers, useWhen, avoidWhen, cost, category } : undefined,
|
|
401
440
|
};
|
|
402
441
|
} catch (error) {
|
|
403
442
|
logInternalError("discoverAgents.parseAgentFile", error, `filePath=${filePath}`);
|
|
@@ -407,7 +446,8 @@ function parseAgentFile(filePath: string, source: ResourceSource): AgentConfig |
|
|
|
407
446
|
|
|
408
447
|
function readAgentDir(dir: string, source: ResourceSource): AgentConfig[] {
|
|
409
448
|
if (!fs.existsSync(dir)) return [];
|
|
410
|
-
const agents = fs
|
|
449
|
+
const agents = fs
|
|
450
|
+
.readdirSync(dir)
|
|
411
451
|
.filter((entry) => entry.endsWith(".md") && !entry.endsWith(".team.md") && !entry.endsWith(".workflow.md"))
|
|
412
452
|
.map((entry) => parseAgentFile(path.join(dir, entry), source))
|
|
413
453
|
.filter((agent): agent is AgentConfig => agent !== undefined)
|
|
@@ -436,11 +476,11 @@ function applyAgentOverrides(agents: AgentConfig[], cwd: string, loadedConfig?:
|
|
|
436
476
|
return {
|
|
437
477
|
...agent,
|
|
438
478
|
disabled: override.disabled ?? agent.disabled,
|
|
439
|
-
model: override.model === false ? undefined : override.model ?? agent.model,
|
|
440
|
-
fallbackModels: override.fallbackModels === false ? undefined : override.fallbackModels ?? agent.fallbackModels,
|
|
441
|
-
thinking: override.thinking === false ? undefined : override.thinking ?? agent.thinking,
|
|
442
|
-
tools: override.tools === false ? undefined : override.tools ?? agent.tools,
|
|
443
|
-
skills: override.skills === false ? undefined : override.skills ?? agent.skills,
|
|
479
|
+
model: override.model === false ? undefined : (override.model ?? agent.model),
|
|
480
|
+
fallbackModels: override.fallbackModels === false ? undefined : (override.fallbackModels ?? agent.fallbackModels),
|
|
481
|
+
thinking: override.thinking === false ? undefined : (override.thinking ?? agent.thinking),
|
|
482
|
+
tools: override.tools === false ? undefined : (override.tools ?? agent.tools),
|
|
483
|
+
skills: override.skills === false ? undefined : (override.skills ?? agent.skills),
|
|
444
484
|
override: { source: "config", path: loaded.path },
|
|
445
485
|
};
|
|
446
486
|
});
|
|
@@ -454,7 +494,7 @@ const DISCOVERY_CACHE_TTL_MS = 500;
|
|
|
454
494
|
interface CachedDiscoveryEntry {
|
|
455
495
|
result: AgentDiscoveryResult;
|
|
456
496
|
expiresAt: number;
|
|
457
|
-
cacheVersion: number;
|
|
497
|
+
cacheVersion: number; // SEC-005: Version stamp for atomic invalidation
|
|
458
498
|
}
|
|
459
499
|
const discoveryCache = new Map<string, CachedDiscoveryEntry>();
|
|
460
500
|
const DISCOVERY_CACHE_MAX_ENTRIES = 32;
|
|
@@ -500,7 +540,11 @@ export function discoverAgents(cwd: string): AgentDiscoveryResult {
|
|
|
500
540
|
projectPi: applyAgentOverrides(readAgentDir(path.join(findRepoRoot(cwd) ?? cwd, ".pi", "agents"), "project-pi"), cwd, loaded),
|
|
501
541
|
};
|
|
502
542
|
// SEC-005: Store with current version stamp
|
|
503
|
-
discoveryCache.set(cwd, {
|
|
543
|
+
discoveryCache.set(cwd, {
|
|
544
|
+
result,
|
|
545
|
+
expiresAt: Date.now() + DISCOVERY_CACHE_TTL_MS,
|
|
546
|
+
cacheVersion: currentVersion,
|
|
547
|
+
});
|
|
504
548
|
while (discoveryCache.size > DISCOVERY_CACHE_MAX_ENTRIES) {
|
|
505
549
|
const oldest = discoveryCache.keys().next().value;
|
|
506
550
|
if (oldest !== undefined) discoveryCache.delete(oldest);
|
|
@@ -522,7 +566,7 @@ export function registerDynamicAgent(config: AgentConfig): void {
|
|
|
522
566
|
if (dynamicAgents.has(key)) {
|
|
523
567
|
throw new Error(`Agent already registered: ${config.name}`);
|
|
524
568
|
}
|
|
525
|
-
dynamicAgents.set(key, { ...config, source: "dynamic" });
|
|
569
|
+
dynamicAgents.set(key, { ...config, source: "dynamic" }); // Always "dynamic" — cannot be spoofed
|
|
526
570
|
invalidateAgentDiscoveryCache();
|
|
527
571
|
}
|
|
528
572
|
|
|
@@ -41,42 +41,42 @@ export interface BenchmarkResult {
|
|
|
41
41
|
* Uses comprehensive shell metacharacter blocking similar to safe-bash.ts.
|
|
42
42
|
*/
|
|
43
43
|
function validateCommand(command: string): void {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
44
|
+
// Basic allowlist - must start with an allowed command.
|
|
45
|
+
// SECURITY (H-7): `npx`/`node` were removed because they enable arbitrary code
|
|
46
|
+
// execution without any shell metacharacter (e.g. `npx --yes evil-package`
|
|
47
|
+
// or `node -e "require('fs')…"`). Use `npm test`/`npm run …` instead of raw
|
|
48
|
+
// `node`/`npx` in benchmark task definitions.
|
|
49
|
+
// `echo` is allowed because the metachar blocker (validateGateCommand) rejects
|
|
50
|
+
// command substitution (`$(...)`, backticks), so `echo $(evil)` cannot run;
|
|
51
|
+
// bare `echo …` only prints. It's the canonical exit-0 command used in
|
|
52
|
+
// benchmark fixtures across Linux/macOS/Windows(sh).
|
|
53
|
+
const allowlist = /^(pytest|grep|npm test|cargo test|cargo clippy|echo) /;
|
|
54
|
+
if (!allowlist.test(command)) {
|
|
55
|
+
throw new Error(`Command not allowed: ${command}. Only pytest, grep, npm test, cargo test/clippy, echo allowed.`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Block shell metacharacters after command name
|
|
59
|
+
const afterCommand = command.substring(command.indexOf(" ") + 1);
|
|
60
|
+
|
|
61
|
+
// Block dangerous shell metacharacters
|
|
62
|
+
const dangerousPatterns = [
|
|
63
|
+
/[;&|`$(){}[\]<>\\]/, // Shell metacharacters
|
|
64
|
+
/\$\([^)]*\)/, // Command substitution $(...)
|
|
65
|
+
/`[^`]*`/, // Backtick command substitution
|
|
66
|
+
/\|/, // Pipe
|
|
67
|
+
/&&/, // And
|
|
68
|
+
/\|\|/, // Or
|
|
69
|
+
/>>/, // Append redirect
|
|
70
|
+
/2>&1/, // stderr redirect
|
|
71
|
+
/>/, // Output redirect
|
|
72
|
+
/</, // Input redirect
|
|
73
|
+
];
|
|
74
|
+
|
|
75
|
+
for (const pattern of dangerousPatterns) {
|
|
76
|
+
if (pattern.test(afterCommand)) {
|
|
77
|
+
throw new Error(`Shell metacharacters not allowed in command arguments`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
/**
|
|
@@ -143,10 +143,18 @@ export async function runBenchmark(task: BenchmarkTask): Promise<BenchmarkResult
|
|
|
143
143
|
passed = true; // Command succeeded = pass
|
|
144
144
|
}
|
|
145
145
|
|
|
146
|
-
judgeResults.push({
|
|
146
|
+
judgeResults.push({
|
|
147
|
+
description: judge.description,
|
|
148
|
+
passed: passed ?? false,
|
|
149
|
+
output,
|
|
150
|
+
});
|
|
147
151
|
} catch (e: unknown) {
|
|
148
152
|
const error = e as { message?: string };
|
|
149
|
-
judgeResults.push({
|
|
153
|
+
judgeResults.push({
|
|
154
|
+
description: judge.description,
|
|
155
|
+
passed: false,
|
|
156
|
+
output: error.message ?? String(e),
|
|
157
|
+
});
|
|
150
158
|
}
|
|
151
159
|
}
|
|
152
160
|
|
|
@@ -200,9 +208,7 @@ export async function runBenchmarkSuite(
|
|
|
200
208
|
totalDurationMs: number;
|
|
201
209
|
totalCost: number;
|
|
202
210
|
}> {
|
|
203
|
-
const filtered = taskTypes
|
|
204
|
-
? tasks.filter((t) => t.taskType && taskTypes.includes(t.taskType))
|
|
205
|
-
: tasks;
|
|
211
|
+
const filtered = taskTypes ? tasks.filter((t) => t.taskType && taskTypes.includes(t.taskType)) : tasks;
|
|
206
212
|
|
|
207
213
|
const results: BenchmarkResult[] = [];
|
|
208
214
|
|
|
@@ -241,8 +247,7 @@ export function aggregateBenchmarkMetrics(results: BenchmarkResult[]): Aggregate
|
|
|
241
247
|
const totalTasks = group.length;
|
|
242
248
|
const passedTasks = group.filter((r) => r.passed).length;
|
|
243
249
|
const passRate = totalTasks > 0 ? passedTasks / totalTasks : 0;
|
|
244
|
-
const avgTimeMs =
|
|
245
|
-
totalTasks > 0 ? group.reduce((s, r) => s + r.durationMs, 0) / totalTasks : 0;
|
|
250
|
+
const avgTimeMs = totalTasks > 0 ? group.reduce((s, r) => s + r.durationMs, 0) / totalTasks : 0;
|
|
246
251
|
const totalCost = group.reduce((s, r) => s + r.cost, 0);
|
|
247
252
|
const avgCost = totalTasks > 0 ? totalCost / totalTasks : 0;
|
|
248
253
|
|
|
@@ -266,10 +271,7 @@ export function aggregateBenchmarkMetrics(results: BenchmarkResult[]): Aggregate
|
|
|
266
271
|
* @param results - Benchmark results to report.
|
|
267
272
|
* @param includeTaskTypeComparison - When true (default), appends a per-task-type aggregate table.
|
|
268
273
|
*/
|
|
269
|
-
export function generateBenchmarkReport(
|
|
270
|
-
results: BenchmarkResult[],
|
|
271
|
-
includeTaskTypeComparison = true,
|
|
272
|
-
): string {
|
|
274
|
+
export function generateBenchmarkReport(results: BenchmarkResult[], includeTaskTypeComparison = true): string {
|
|
273
275
|
const lines: string[] = ["# Benchmark Results", ""];
|
|
274
276
|
|
|
275
277
|
lines.push("| Task | Type | Status | Duration | Cost |");
|
|
@@ -298,9 +300,7 @@ export function generateBenchmarkReport(
|
|
|
298
300
|
const m = metrics[t];
|
|
299
301
|
const passRatePct = `${(m.passRate * 100).toFixed(1)}%`;
|
|
300
302
|
const avgCostStr = m.avgCost > 0 ? `$${m.avgCost.toFixed(4)}` : "—";
|
|
301
|
-
lines.push(
|
|
302
|
-
`| ${m.taskType} | ${m.totalTasks} | ${m.passedTasks} | ${passRatePct} | ${m.avgTimeMs}ms | ${avgCostStr} |`,
|
|
303
|
-
);
|
|
303
|
+
lines.push(`| ${m.taskType} | ${m.totalTasks} | ${m.passedTasks} | ${passRatePct} | ${m.avgTimeMs}ms | ${avgCostStr} |`);
|
|
304
304
|
}
|
|
305
305
|
}
|
|
306
306
|
}
|
|
@@ -310,4 +310,4 @@ export function generateBenchmarkReport(
|
|
|
310
310
|
lines.push(`**Total: ${passed}/${results.length} passed**`);
|
|
311
311
|
|
|
312
312
|
return lines.join("\n");
|
|
313
|
-
}
|
|
313
|
+
}
|