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,12 +1,13 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
|
-
import
|
|
3
|
+
import { DEFAULT_OUTPUT_CONTEXT } from "../config/defaults.ts";
|
|
4
4
|
import { writeArtifact } from "../state/artifact-store.ts";
|
|
5
|
+
import type { ArtifactDescriptor, TeamRunManifest, TeamTaskState } from "../state/types.ts";
|
|
5
6
|
import { resolveRealContainedPath } from "../utils/safe-paths.ts";
|
|
6
7
|
import type { WorkflowStep } from "../workflows/workflow-config.ts";
|
|
7
|
-
import { pruneToolOutputs, type ToolResultEntry, type FileEditEvent, DEFAULT_PRUNE_CONFIG } from "./tool-output-pruner.ts";
|
|
8
8
|
import { applyCompactPipeline } from "./compact-pipeline.ts";
|
|
9
9
|
import { ANSI_STRIP_STAGE, BLANK_COLLAPSE_STAGE, TruncationStage } from "./compact-stages/index.ts";
|
|
10
|
+
import { DEFAULT_PRUNE_CONFIG, type FileEditEvent, pruneToolOutputs, type ToolResultEntry } from "./tool-output-pruner.ts";
|
|
10
11
|
|
|
11
12
|
export interface DependencyContextEntry {
|
|
12
13
|
taskId: string;
|
|
@@ -23,6 +24,21 @@ export interface DependencyContextEntry {
|
|
|
23
24
|
structuredResults?: Record<string, unknown>;
|
|
24
25
|
artifactsProduced?: string[];
|
|
25
26
|
usage?: { inputTokens: number; outputTokens: number; durationMs: number };
|
|
27
|
+
/** L4 total-budget: byte length of `resultSummary` (UTF-16 code units).
|
|
28
|
+
* Populated by `collectDependencyOutputContext` so the trim step can sum
|
|
29
|
+
* per-dep sizes without re-computing. Set to 0 when the dep is
|
|
30
|
+
* downgraded to path-only. Optional for backward-compat with existing
|
|
31
|
+
* test fixtures that build entry objects directly. */
|
|
32
|
+
inlineBytes?: number;
|
|
33
|
+
/** L4 priority sort key: derived from the upstream task's `finishedAt`
|
|
34
|
+
* (ms epoch). More recent = higher priority in the trim. Undefined
|
|
35
|
+
* when the dep task never finished (treated as 0). */
|
|
36
|
+
recency?: number;
|
|
37
|
+
/** L4 priority sort key: heuristic relevance in [0, 1]. Higher = more
|
|
38
|
+
* relevant. Derived from the upstream task's `dependsOn` position in
|
|
39
|
+
* the workflow (earlier deps = higher relevance because they were
|
|
40
|
+
* explicitly listed first). Defaults to 0.5 (neutral) when unknown. */
|
|
41
|
+
relevance?: number;
|
|
26
42
|
}
|
|
27
43
|
|
|
28
44
|
export interface DependencyOutputContext {
|
|
@@ -34,7 +50,12 @@ export interface DependencyOutputContext {
|
|
|
34
50
|
* and the path is exposed via `fullOutputPath` so the downstream worker
|
|
35
51
|
* can `read` it back if it needs the dropped middle.
|
|
36
52
|
*/
|
|
37
|
-
sharedReads: Array<{
|
|
53
|
+
sharedReads: Array<{
|
|
54
|
+
name: string;
|
|
55
|
+
path: string;
|
|
56
|
+
content: string;
|
|
57
|
+
fullOutputPath?: string;
|
|
58
|
+
}>;
|
|
38
59
|
}
|
|
39
60
|
|
|
40
61
|
function containedExists(filePath: string, baseDir?: string): boolean {
|
|
@@ -53,8 +74,26 @@ function containedExists(filePath: string, baseDir?: string): boolean {
|
|
|
53
74
|
* bounding memory. Larger than the old inconsistent per-call-site values
|
|
54
75
|
* (24K/40K/80K) which truncated the same artifact differently depending on
|
|
55
76
|
* which code path read it.
|
|
77
|
+
*
|
|
78
|
+
* Single source of truth: DEFAULT_OUTPUT_CONTEXT.maxResultInlineBytes
|
|
79
|
+
* (Round 25 / L6 — moved from hardcoded constant to config/defaults.ts).
|
|
80
|
+
*/
|
|
81
|
+
export const MAX_RESULT_INLINE_BYTES = DEFAULT_OUTPUT_CONTEXT.maxResultInlineBytes;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* L4 total-budget: cap on the SUM of inline bytes across ALL dependencies
|
|
85
|
+
* for a single downstream worker. 96KB is 3× the per-dep cap (3 × 32KB).
|
|
86
|
+
* Sized so a worker with 3 large dep outputs (e.g. 3 × 32KB truncated)
|
|
87
|
+
* stays below budget and the typical 1–2 dep case never hits the trim.
|
|
88
|
+
* When the sum exceeds this, the trim step in
|
|
89
|
+
* {@link collectDependencyOutputContext} downgrades the lowest-priority
|
|
90
|
+
* deps to path-only (resultPath + fullOutputPath, no inline text) so the
|
|
91
|
+
* downstream worker can `read` the full content on demand. The tee
|
|
92
|
+
* write happens BEFORE the trim, so fullOutputPath is always available.
|
|
93
|
+
*
|
|
94
|
+
* Single source of truth: DEFAULT_OUTPUT_CONTEXT.maxTotalDepInlineBytes.
|
|
56
95
|
*/
|
|
57
|
-
export const
|
|
96
|
+
export const MAX_TOTAL_DEP_INLINE_BYTES = DEFAULT_OUTPUT_CONTEXT.maxTotalDepInlineBytes;
|
|
58
97
|
|
|
59
98
|
/**
|
|
60
99
|
* Tee-recovery multiplier (R2). A shared artifact is teed to disk — so the
|
|
@@ -63,8 +102,10 @@ export const MAX_RESULT_INLINE_BYTES = 32_000;
|
|
|
63
102
|
* (64 KB) to 1.25 (40 KB) so the 32–64 KB band, where the head+tail split
|
|
64
103
|
* is already materially lossy for structured content, also gets a recovery
|
|
65
104
|
* path instead of losing the middle forever.
|
|
105
|
+
*
|
|
106
|
+
* Single source of truth: DEFAULT_OUTPUT_CONTEXT.teeThresholdMultiplier.
|
|
66
107
|
*/
|
|
67
|
-
export const TEE_THRESHOLD_MULTIPLIER =
|
|
108
|
+
export const TEE_THRESHOLD_MULTIPLIER = DEFAULT_OUTPUT_CONTEXT.teeThresholdMultiplier;
|
|
68
109
|
|
|
69
110
|
/**
|
|
70
111
|
* Read a file and return its content, truncating to a head+tail slice if it
|
|
@@ -161,7 +202,12 @@ export function readIfSmallWithTee(
|
|
|
161
202
|
BLANK_COLLAPSE_STAGE,
|
|
162
203
|
new TruncationStage(maxChars, {
|
|
163
204
|
preserveImportant: true,
|
|
164
|
-
marker: {
|
|
205
|
+
marker: {
|
|
206
|
+
verb: "truncated",
|
|
207
|
+
unit: "chars",
|
|
208
|
+
headSeparator: "\n\n",
|
|
209
|
+
tailSeparator: "\n",
|
|
210
|
+
},
|
|
165
211
|
}),
|
|
166
212
|
]);
|
|
167
213
|
return fullOutputPath ? { content: result.text, fullOutputPath } : { content: result.text };
|
|
@@ -190,7 +236,8 @@ export function readIfSmall(filePath: string, baseDir?: string): string | undefi
|
|
|
190
236
|
|
|
191
237
|
function safeSharedName(name: string): string {
|
|
192
238
|
const normalized = name.replaceAll("\\", "/").replace(/^\.\/+/, "");
|
|
193
|
-
if (!normalized || normalized.split("/").some((segment) => segment === "..") || path.isAbsolute(normalized))
|
|
239
|
+
if (!normalized || normalized.split("/").some((segment) => segment === "..") || path.isAbsolute(normalized))
|
|
240
|
+
throw new Error(`Invalid shared artifact name: ${name}`);
|
|
194
241
|
return normalized;
|
|
195
242
|
}
|
|
196
243
|
|
|
@@ -232,6 +279,66 @@ function aggregateUsage(task: TeamTaskState): DependencyContextEntry["usage"] {
|
|
|
232
279
|
return { inputTokens, outputTokens, durationMs };
|
|
233
280
|
}
|
|
234
281
|
|
|
282
|
+
/**
|
|
283
|
+
* L4 total-budget trim. When the SUM of `inlineBytes` across all deps
|
|
284
|
+
* exceeds {@link MAX_TOTAL_DEP_INLINE_BYTES}, downgrade the lowest-priority
|
|
285
|
+
* deps to path-only (clear inline text, keep resultPath + fullOutputPath)
|
|
286
|
+
* so the downstream worker can `read` the full content on demand.
|
|
287
|
+
*
|
|
288
|
+
* Priority order (highest kept first):
|
|
289
|
+
* 1. status in {failed, needs-attention} (worker MUST see the failure)
|
|
290
|
+
* 2. recency descending (newer outputs more relevant)
|
|
291
|
+
* 3. relevance descending (workflow author-declared order)
|
|
292
|
+
* 4. tie-breaker: original array index (stable sort)
|
|
293
|
+
*
|
|
294
|
+
* Algorithm: sort by priority (descending), then walk top-down, keeping
|
|
295
|
+
* each dep until the running total would exceed the budget. The remaining
|
|
296
|
+
* deps are returned with `resultSummary=""` and `inlineBytes=0`; the
|
|
297
|
+
* `resultPath` and `fullOutputPath` fields are preserved so the worker
|
|
298
|
+
* can `read` them. Stable: the original input order is preserved for
|
|
299
|
+
* entries at the same priority level.
|
|
300
|
+
*
|
|
301
|
+
* Pure function — no I/O. Exported for unit testing.
|
|
302
|
+
*/
|
|
303
|
+
export function enforceDependencyInlineBudget(dependencies: DependencyContextEntry[]): DependencyContextEntry[] {
|
|
304
|
+
if (dependencies.length === 0) return dependencies;
|
|
305
|
+
const totalInlineBytes = dependencies.reduce((sum, dep) => sum + (dep.inlineBytes ?? 0), 0);
|
|
306
|
+
if (totalInlineBytes <= MAX_TOTAL_DEP_INLINE_BYTES) return dependencies;
|
|
307
|
+
// Build an index-keyed array so we can sort AND preserve the original
|
|
308
|
+
// position (for stable output order). Each entry gets a numeric
|
|
309
|
+
// priority score (higher = more important) and a stable tie-breaker.
|
|
310
|
+
const indexed = dependencies.map((dep, originalIndex) => {
|
|
311
|
+
const highPriority = dep.status === "failed" || dep.status === "needs-attention";
|
|
312
|
+
// Score: (highPriority?1000:0) + (recency/1e10) + (relevance*10) - (index*0.001)
|
|
313
|
+
// The 1000 base ensures high-priority wins even with no recency/relevance.
|
|
314
|
+
// recency/1e10 keeps it in [0, 1] for ms timestamps up to 1e13 (~year 2286).
|
|
315
|
+
// relevance*10 puts it in [0, 10].
|
|
316
|
+
// index*0.001 keeps stable order within the same bucket.
|
|
317
|
+
const score = (highPriority ? 1000 : 0) + (dep.recency ?? 0) / 1e10 + (dep.relevance ?? 0) * 10 - originalIndex * 0.001;
|
|
318
|
+
return { dep, originalIndex, score };
|
|
319
|
+
});
|
|
320
|
+
const sorted = [...indexed].sort((a, b) => b.score - a.score);
|
|
321
|
+
let used = 0;
|
|
322
|
+
const keepSet = new Set<number>(); // originalIndex values to KEEP inline
|
|
323
|
+
for (const item of sorted) {
|
|
324
|
+
const next = used + (item.dep.inlineBytes ?? 0);
|
|
325
|
+
if (next <= MAX_TOTAL_DEP_INLINE_BYTES) {
|
|
326
|
+
used = next;
|
|
327
|
+
keepSet.add(item.originalIndex);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
// Return entries in original order; downgrade ones NOT in keepSet.
|
|
331
|
+
return dependencies.map((dep, originalIndex) => {
|
|
332
|
+
if (keepSet.has(originalIndex)) return dep;
|
|
333
|
+
return {
|
|
334
|
+
...dep,
|
|
335
|
+
resultSummary: "",
|
|
336
|
+
structuredResults: undefined,
|
|
337
|
+
inlineBytes: 0,
|
|
338
|
+
};
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
|
|
235
342
|
/**
|
|
236
343
|
* Apply staleness-aware pruning to shared reads before they are injected
|
|
237
344
|
* into a downstream worker's prompt. Converts shared reads to generic
|
|
@@ -273,66 +380,123 @@ function pruneSharedReads(
|
|
|
273
380
|
if (typeof artifact !== "string") continue;
|
|
274
381
|
// Map artifact path (relative to artifactsRoot) to absolute and
|
|
275
382
|
// check against read targets.
|
|
276
|
-
fileEdits.push({
|
|
383
|
+
fileEdits.push({
|
|
384
|
+
target: path.resolve(artifactsRoot, artifact),
|
|
385
|
+
index: reads.length + depIndex,
|
|
386
|
+
});
|
|
277
387
|
}
|
|
278
388
|
}
|
|
279
389
|
const pruned = pruneToolOutputs(entries, DEFAULT_PRUNE_CONFIG);
|
|
280
390
|
if (pruned.prunedCount === 0) return reads;
|
|
281
391
|
// Map pruned entries back to the shared-read shape.
|
|
282
|
-
return pruned.results.map((entry, index) => ({
|
|
392
|
+
return pruned.results.map((entry, index) => ({
|
|
393
|
+
...reads[index]!,
|
|
394
|
+
content: entry.content,
|
|
395
|
+
}));
|
|
283
396
|
}
|
|
284
397
|
|
|
285
|
-
export function collectDependencyOutputContext(
|
|
398
|
+
export function collectDependencyOutputContext(
|
|
399
|
+
manifest: TeamRunManifest,
|
|
400
|
+
tasks: TeamTaskState[],
|
|
401
|
+
task: TeamTaskState,
|
|
402
|
+
step: WorkflowStep,
|
|
403
|
+
): DependencyOutputContext {
|
|
286
404
|
const byStep = new Map(tasks.map((item) => [item.stepId, item]).filter((entry): entry is [string, TeamTaskState] => Boolean(entry[0])));
|
|
287
405
|
const byId = new Map(tasks.map((item) => [item.id, item]));
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
406
|
+
// L4 priority keys: build (a) the position of each dep in the workflow's
|
|
407
|
+
// `dependsOn:` list (earlier = more relevant because the workflow author
|
|
408
|
+
// declared it first), and (b) the finishedAt timestamp of each dep task
|
|
409
|
+
// (used for recency sort in the trim step). Both are looked up against
|
|
410
|
+
// `task.dependsOn` (the declared order) and `tasks` (finished timestamps).
|
|
411
|
+
const declaredOrder = new Map<string, number>();
|
|
412
|
+
task.dependsOn.forEach((depId, index) => declaredOrder.set(depId, index));
|
|
413
|
+
const recencyByTaskId = new Map<string, number>();
|
|
414
|
+
for (const item of tasks) {
|
|
415
|
+
if (!item.finishedAt) continue;
|
|
416
|
+
const ms = new Date(item.finishedAt).getTime();
|
|
417
|
+
if (Number.isFinite(ms)) recencyByTaskId.set(item.id, ms);
|
|
418
|
+
}
|
|
419
|
+
const dependencies = task.dependsOn
|
|
420
|
+
.map((dep) => byStep.get(dep) ?? byId.get(dep))
|
|
421
|
+
.filter((item): item is TeamTaskState => Boolean(item))
|
|
422
|
+
.map((item) => {
|
|
423
|
+
const fullOutputPath = item.resultArtifact ? teePathForArtifact(manifest.artifactsRoot, task.id, item.id) : undefined;
|
|
424
|
+
const teeResult = item.resultArtifact
|
|
425
|
+
? readIfSmallWithTee(item.resultArtifact.path, {
|
|
426
|
+
baseDir: manifest.artifactsRoot,
|
|
427
|
+
...(fullOutputPath ? { tee: { fullOutputPath } } : {}),
|
|
428
|
+
})
|
|
429
|
+
: undefined;
|
|
430
|
+
const resultText = teeResult?.content;
|
|
431
|
+
const inlineBytes = resultText?.length ?? 0;
|
|
432
|
+
// L4 priority keys: recency from the dep's finishedAt, relevance
|
|
433
|
+
// from the dep's declared position in `task.dependsOn` (inverted
|
|
434
|
+
// to [0,1]: position 0 → 1.0, position N → max(0, 1 - N*0.1)).
|
|
435
|
+
const position = declaredOrder.get(item.id) ?? declaredOrder.get(item.stepId ?? "") ?? 0;
|
|
436
|
+
const relevance = Math.max(0, 1 - position * 0.1);
|
|
437
|
+
return {
|
|
438
|
+
taskId: item.id,
|
|
439
|
+
role: item.role,
|
|
440
|
+
status: item.status,
|
|
441
|
+
resultSummary: resultText ?? "",
|
|
442
|
+
resultPath: item.resultArtifact?.path,
|
|
443
|
+
...(teeResult?.fullOutputPath ? { fullOutputPath: teeResult.fullOutputPath } : {}),
|
|
444
|
+
structuredResults: resultText ? tryParseJson(resultText) : undefined,
|
|
445
|
+
artifactsProduced: listTaskArtifacts(manifest, item.id),
|
|
446
|
+
usage: aggregateUsage(item),
|
|
447
|
+
inlineBytes,
|
|
448
|
+
recency: recencyByTaskId.get(item.id),
|
|
449
|
+
relevance,
|
|
450
|
+
};
|
|
320
451
|
});
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
452
|
+
// L4 total-budget trim: when the SUM of inline bytes across all deps
|
|
453
|
+
// exceeds MAX_TOTAL_DEP_INLINE_BYTES, downgrade the lowest-priority
|
|
454
|
+
// deps to path-only (clear inline text, keep resultPath +
|
|
455
|
+
// fullOutputPath). The downstream worker can `read` the full content
|
|
456
|
+
// on demand. Priority order (highest kept first):
|
|
457
|
+
// 1. status in {failed, needs-attention} (worker MUST see the failure)
|
|
458
|
+
// 2. recency descending (newer outputs more relevant)
|
|
459
|
+
// 3. relevance descending (workflow author-declared order)
|
|
460
|
+
// Tie-breakers within the same priority bucket are stable: the
|
|
461
|
+
// declaration order in `task.dependsOn` (earlier = more relevant).
|
|
462
|
+
const trimmedDependencies = enforceDependencyInlineBudget(dependencies);
|
|
463
|
+
const rawSharedReads = (step.reads === false ? [] : (step.reads ?? []))
|
|
464
|
+
.map((name) => {
|
|
465
|
+
const filePath = sharedPath(manifest, name);
|
|
466
|
+
// P1-A tee-recovery: when the shared artifact is large enough that the
|
|
467
|
+
// 75/25 head+tail split is materially lossy (>2× MAX_RESULT_INLINE_BYTES),
|
|
468
|
+
// tee the full content to ${artifactsRoot}/tee/${taskId}-${name}.full.txt
|
|
469
|
+
// and expose the path so the downstream worker can `read` the full file
|
|
470
|
+
// if it needs the dropped middle. The truncated content is still
|
|
471
|
+
// included inline; tee is an enhancement, not a hard dependency. Tee
|
|
472
|
+
// write is best-effort (writeTeeFile swallows I/O errors and the result
|
|
473
|
+
// simply omits fullOutputPath in that case).
|
|
474
|
+
const teePath = teePathForArtifact(manifest.artifactsRoot, task.id, name);
|
|
475
|
+
const teeResult = readIfSmallWithTee(filePath, {
|
|
476
|
+
baseDir: path.resolve(manifest.artifactsRoot, "shared"),
|
|
477
|
+
tee: { fullOutputPath: teePath },
|
|
478
|
+
});
|
|
479
|
+
if (teeResult === undefined) return { name, path: filePath, content: "" };
|
|
480
|
+
const entry: {
|
|
481
|
+
name: string;
|
|
482
|
+
path: string;
|
|
483
|
+
content: string;
|
|
484
|
+
fullOutputPath?: string;
|
|
485
|
+
} = {
|
|
486
|
+
name,
|
|
487
|
+
path: filePath,
|
|
488
|
+
content: teeResult.content,
|
|
489
|
+
};
|
|
490
|
+
if (teeResult.fullOutputPath) entry.fullOutputPath = teeResult.fullOutputPath;
|
|
491
|
+
return entry;
|
|
492
|
+
})
|
|
493
|
+
.filter((item) => item.content.trim().length > 0);
|
|
330
494
|
// Apply staleness-aware pruning to shared reads: drops superseded reads
|
|
331
495
|
// (same file re-read with different selectors) and replaces stale large
|
|
332
496
|
// outputs with compact digest notices before injecting into the worker
|
|
333
497
|
// prompt. OPT-IN: default config protects recent results.
|
|
334
|
-
const sharedReads = pruneSharedReads(rawSharedReads,
|
|
335
|
-
return { dependencies, sharedReads };
|
|
498
|
+
const sharedReads = pruneSharedReads(rawSharedReads, trimmedDependencies, manifest.artifactsRoot);
|
|
499
|
+
return { dependencies: trimmedDependencies, sharedReads };
|
|
336
500
|
}
|
|
337
501
|
|
|
338
502
|
export function renderDependencyOutputContext(context: DependencyOutputContext): string {
|
|
@@ -340,7 +504,14 @@ export function renderDependencyOutputContext(context: DependencyOutputContext):
|
|
|
340
504
|
if (context.dependencies.length) {
|
|
341
505
|
parts.push("# Dependency Outputs", "");
|
|
342
506
|
for (const dep of context.dependencies) {
|
|
343
|
-
parts.push(
|
|
507
|
+
parts.push(
|
|
508
|
+
`## ${dep.taskId} (${dep.role})`,
|
|
509
|
+
`Status: ${dep.status}`,
|
|
510
|
+
dep.resultPath ? `Result artifact: ${dep.resultPath}` : "",
|
|
511
|
+
"",
|
|
512
|
+
dep.resultSummary?.trim() || "(no result output)",
|
|
513
|
+
"",
|
|
514
|
+
);
|
|
344
515
|
// P1-A dependency tee-recovery hint: when the dependency's result was
|
|
345
516
|
// materially truncated (>1.25× MAX_RESULT_INLINE_BYTES) the full RAW
|
|
346
517
|
// content was teed to fullOutputPath. Mirrors the sharedReads hint so the
|
|
@@ -348,7 +519,11 @@ export function renderDependencyOutputContext(context: DependencyOutputContext):
|
|
|
348
519
|
if (dep.fullOutputPath) parts.push(`Full output (if you need the missing middle): ${dep.fullOutputPath}`, "");
|
|
349
520
|
if (dep.structuredResults) parts.push("Structured results:", JSON.stringify(dep.structuredResults, null, 2), "");
|
|
350
521
|
if (dep.artifactsProduced?.length) parts.push(`Artifacts produced: ${dep.artifactsProduced.join(", ")}`, "");
|
|
351
|
-
if (dep.usage)
|
|
522
|
+
if (dep.usage)
|
|
523
|
+
parts.push(
|
|
524
|
+
`Usage: ${dep.usage.inputTokens} input tokens, ${dep.usage.outputTokens} output tokens, ${dep.usage.durationMs}ms`,
|
|
525
|
+
"",
|
|
526
|
+
);
|
|
352
527
|
}
|
|
353
528
|
}
|
|
354
529
|
if (context.sharedReads.length) {
|
|
@@ -379,7 +554,11 @@ export function writeTaskSharedOutput(manifest: TeamRunManifest, step: WorkflowS
|
|
|
379
554
|
});
|
|
380
555
|
}
|
|
381
556
|
|
|
382
|
-
export function writeTaskInputsArtifact(
|
|
557
|
+
export function writeTaskInputsArtifact(
|
|
558
|
+
manifest: TeamRunManifest,
|
|
559
|
+
task: TeamTaskState,
|
|
560
|
+
context: DependencyOutputContext,
|
|
561
|
+
): ArtifactDescriptor {
|
|
383
562
|
return writeArtifact(manifest.artifactsRoot, {
|
|
384
563
|
kind: "metadata",
|
|
385
564
|
relativePath: `metadata/${task.id}.inputs.json`,
|
|
@@ -389,29 +568,34 @@ export function writeTaskInputsArtifact(manifest: TeamRunManifest, task: TeamTas
|
|
|
389
568
|
}
|
|
390
569
|
|
|
391
570
|
export function aggregateTaskOutputs(tasks: TeamTaskState[], manifest?: TeamRunManifest): string {
|
|
392
|
-
return tasks
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
571
|
+
return tasks
|
|
572
|
+
.map((task, index) => {
|
|
573
|
+
const body = task.resultArtifact ? readIfSmall(task.resultArtifact.path, manifest?.artifactsRoot) : undefined;
|
|
574
|
+
const hasBody = Boolean(body?.trim());
|
|
575
|
+
const expectedMissing = task.resultArtifact && !containedExists(task.resultArtifact.path, manifest?.artifactsRoot);
|
|
576
|
+
const status =
|
|
577
|
+
task.status === "skipped"
|
|
578
|
+
? "SKIPPED"
|
|
579
|
+
: task.status === "failed"
|
|
580
|
+
? `FAILED${task.exitCode !== undefined ? ` (exit code ${task.exitCode ?? "null"})` : ""}${task.error ? `: ${task.error}` : ""}`
|
|
581
|
+
: expectedMissing
|
|
582
|
+
? `EMPTY OUTPUT (expected result artifact missing: ${task.resultArtifact?.path})`
|
|
583
|
+
: !hasBody
|
|
584
|
+
? "EMPTY OUTPUT (no textual response returned)"
|
|
585
|
+
: task.status.toUpperCase();
|
|
586
|
+
return [
|
|
587
|
+
`=== Task ${index + 1}: ${task.id} (${task.agent}) ===`,
|
|
588
|
+
`Status: ${status}`,
|
|
589
|
+
task.role ? `Role: ${task.role}` : "",
|
|
590
|
+
task.resultArtifact?.path ? `Result artifact: ${task.resultArtifact.path}` : "",
|
|
591
|
+
task.logArtifact?.path ? `Log artifact: ${task.logArtifact.path}` : "",
|
|
592
|
+
task.transcriptArtifact?.path ? `Transcript: ${task.transcriptArtifact.path}` : "",
|
|
593
|
+
task.usage ? `Usage: ${JSON.stringify(task.usage)}` : "",
|
|
594
|
+
"",
|
|
595
|
+
hasBody ? body!.trim() : status,
|
|
596
|
+
]
|
|
597
|
+
.filter(Boolean)
|
|
598
|
+
.join("\n");
|
|
599
|
+
})
|
|
600
|
+
.join("\n\n");
|
|
417
601
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as path from "node:path";
|
|
2
|
-
import type {
|
|
2
|
+
import type { TaskPacket, TaskScope, TeamRunManifest, VerificationContract } from "../state/types.ts";
|
|
3
3
|
import type { WorkflowStep } from "../workflows/workflow-config.ts";
|
|
4
4
|
import { generateTaskHashId } from "./task-id.ts";
|
|
5
5
|
|
|
@@ -10,7 +10,6 @@ import { generateTaskHashId } from "./task-id.ts";
|
|
|
10
10
|
// See: SECURITY-ISSUES.md SEC-007
|
|
11
11
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
12
12
|
|
|
13
|
-
|
|
14
13
|
/**
|
|
15
14
|
* Sanitize workflow step task text to reduce injection risk.
|
|
16
15
|
*
|
|
@@ -33,7 +32,7 @@ export function sanitizeTaskText(task: string): string {
|
|
|
33
32
|
// 2. Strip known prompt injection directive patterns
|
|
34
33
|
sanitized = sanitized.replace(
|
|
35
34
|
/^\s*(?:SYSTEM|INSTRUCTION|IGNORE(?:\s+ALL)?\s+INSTRUCTIONS|OVERRIDE|YOUR\s+ROLE\s+IS|MALICIOUS)\s*:.*$/gim,
|
|
36
|
-
""
|
|
35
|
+
"",
|
|
37
36
|
);
|
|
38
37
|
|
|
39
38
|
// 3. Strip base64/hex encoded command payloads
|
|
@@ -62,7 +61,7 @@ export interface TaskPacketValidationResult {
|
|
|
62
61
|
}
|
|
63
62
|
|
|
64
63
|
export function inferTaskScope(step: WorkflowStep): TaskScope {
|
|
65
|
-
const reads = step.reads === false ? [] : step.reads ?? [];
|
|
64
|
+
const reads = step.reads === false ? [] : (step.reads ?? []);
|
|
66
65
|
if (reads.length === 1) return "single_file";
|
|
67
66
|
if (reads.length > 1) return "module";
|
|
68
67
|
return "workspace";
|
|
@@ -78,7 +77,7 @@ export function defaultVerificationContract(step: WorkflowStep): VerificationCon
|
|
|
78
77
|
|
|
79
78
|
export function buildTaskPacket(input: BuildTaskPacketInput): TaskPacket {
|
|
80
79
|
const scope = inferTaskScope(input.step);
|
|
81
|
-
const reads = input.step.reads === false ? [] : input.step.reads ?? [];
|
|
80
|
+
const reads = input.step.reads === false ? [] : (input.step.reads ?? []);
|
|
82
81
|
const scopePath = reads.length === 1 ? reads[0] : reads.length > 1 ? reads.join(", ") : undefined;
|
|
83
82
|
// SEC-007: Sanitize task text before inserting into task packet
|
|
84
83
|
const sanitizedTask = sanitizeTaskText(input.step.task);
|
|
@@ -87,11 +86,7 @@ export function buildTaskPacket(input: BuildTaskPacketInput): TaskPacket {
|
|
|
87
86
|
// Generate a deterministic hash-based task ID for traceability and logging.
|
|
88
87
|
// Uses goal + step ID + run ID as content parts.
|
|
89
88
|
// TODO: Once TaskPacket type gains a hashId field, include this in the packet.
|
|
90
|
-
const _taskHashId = generateTaskHashId([
|
|
91
|
-
input.manifest.goal,
|
|
92
|
-
input.step.id,
|
|
93
|
-
input.manifest.runId,
|
|
94
|
-
]);
|
|
89
|
+
const _taskHashId = generateTaskHashId([input.manifest.goal, input.step.id, input.manifest.runId]);
|
|
95
90
|
|
|
96
91
|
return {
|
|
97
92
|
objective: sanitizedTask.replaceAll("{goal}", sanitizedGoal),
|
|
@@ -99,11 +94,15 @@ export function buildTaskPacket(input: BuildTaskPacketInput): TaskPacket {
|
|
|
99
94
|
scopePath,
|
|
100
95
|
repo: path.basename(input.manifest.cwd) || input.manifest.cwd,
|
|
101
96
|
worktree: input.worktreePath,
|
|
102
|
-
branchPolicy:
|
|
97
|
+
branchPolicy:
|
|
98
|
+
input.manifest.workspaceMode === "worktree"
|
|
99
|
+
? "Use the assigned task worktree and avoid modifying the leader checkout."
|
|
100
|
+
: "Use the current checkout; do not create branches unless explicitly requested.",
|
|
103
101
|
acceptanceTests: [],
|
|
104
102
|
commitPolicy: "Do not commit unless explicitly requested by the user or workflow.",
|
|
105
103
|
reportingContract: "Report intended/changed files, verification evidence, blockers, conflict risks, and next recommended action.",
|
|
106
|
-
escalationPolicy:
|
|
104
|
+
escalationPolicy:
|
|
105
|
+
"Stop and report if scope is ambiguous, destructive action is needed, permissions are missing, verification cannot be completed, or edits may overlap with another worker/task.",
|
|
107
106
|
constraints: [
|
|
108
107
|
"Stay within the assigned task scope.",
|
|
109
108
|
"Do not claim completion without verification evidence.",
|
|
@@ -265,12 +264,5 @@ export function parseHandoffFromOutput(output: string): ParsedHandoff {
|
|
|
265
264
|
}
|
|
266
265
|
|
|
267
266
|
export function renderTaskPacket(packet: TaskPacket): string {
|
|
268
|
-
return [
|
|
269
|
-
"# Task Packet",
|
|
270
|
-
"",
|
|
271
|
-
"```json",
|
|
272
|
-
JSON.stringify(packet, null, 2),
|
|
273
|
-
"```",
|
|
274
|
-
"",
|
|
275
|
-
].join("\n");
|
|
267
|
+
return ["# Task Packet", "", "```json", JSON.stringify(packet, null, 2), "```", ""].join("\n");
|
|
276
268
|
}
|
|
@@ -104,7 +104,8 @@ function isResultDescriptive(task: TeamTaskState): boolean {
|
|
|
104
104
|
typeof task.diagnostics === "object" &&
|
|
105
105
|
typeof task.diagnostics.result === "string" &&
|
|
106
106
|
(task.diagnostics.result as string).trim().length > 0
|
|
107
|
-
)
|
|
107
|
+
)
|
|
108
|
+
return true;
|
|
108
109
|
|
|
109
110
|
return false;
|
|
110
111
|
}
|
|
@@ -138,22 +139,13 @@ function isDurationReasonable(task: TeamTaskState): boolean {
|
|
|
138
139
|
* @param artifactsDir - Optional path to the run artifacts directory
|
|
139
140
|
* @returns TaskQualityScore with numeric score, breakdown, and letter grade
|
|
140
141
|
*/
|
|
141
|
-
export function computeTaskQuality(
|
|
142
|
-
task: TeamTaskState,
|
|
143
|
-
artifactsDir?: string,
|
|
144
|
-
): TaskQualityScore {
|
|
142
|
+
export function computeTaskQuality(task: TeamTaskState, artifactsDir?: string): TaskQualityScore {
|
|
145
143
|
const hasDiagnostics =
|
|
146
|
-
task.diagnostics !== undefined &&
|
|
147
|
-
typeof task.diagnostics === "object" &&
|
|
148
|
-
Object.keys(task.diagnostics).length > 0;
|
|
144
|
+
task.diagnostics !== undefined && typeof task.diagnostics === "object" && Object.keys(task.diagnostics).length > 0;
|
|
149
145
|
|
|
150
|
-
const hasMetrics =
|
|
151
|
-
task.metrics !== undefined &&
|
|
152
|
-
typeof task.metrics === "object" &&
|
|
153
|
-
Object.keys(task.metrics).length > 0;
|
|
146
|
+
const hasMetrics = task.metrics !== undefined && typeof task.metrics === "object" && Object.keys(task.metrics).length > 0;
|
|
154
147
|
|
|
155
|
-
const producedArtifacts =
|
|
156
|
-
artifactsDir !== undefined && hasTaskArtifacts(task.id, artifactsDir);
|
|
148
|
+
const producedArtifacts = artifactsDir !== undefined && hasTaskArtifacts(task.id, artifactsDir);
|
|
157
149
|
|
|
158
150
|
const hasDescription = isResultDescriptive(task);
|
|
159
151
|
|
|
@@ -20,7 +20,7 @@ export interface RetrievalQuery {
|
|
|
20
20
|
|
|
21
21
|
export interface RelevanceEvaluation {
|
|
22
22
|
path: string;
|
|
23
|
-
relevance: number;
|
|
23
|
+
relevance: number; // 0.0–1.0
|
|
24
24
|
reason: string;
|
|
25
25
|
missingContext: string[];
|
|
26
26
|
}
|
|
@@ -45,11 +45,7 @@ export interface RetrievalResult {
|
|
|
45
45
|
* @param keywords - Task-relevant keywords
|
|
46
46
|
* @returns Relevance score 0.0–1.0
|
|
47
47
|
*/
|
|
48
|
-
export function scoreRelevance(
|
|
49
|
-
filePath: string,
|
|
50
|
-
fileContent: string,
|
|
51
|
-
keywords: string[],
|
|
52
|
-
): number {
|
|
48
|
+
export function scoreRelevance(filePath: string, fileContent: string, keywords: string[]): number {
|
|
53
49
|
if (keywords.length === 0) return 0;
|
|
54
50
|
|
|
55
51
|
const pathLower = filePath.toLowerCase();
|
|
@@ -96,9 +92,7 @@ export function hasConverged(evaluations: RelevanceEvaluation[]): boolean {
|
|
|
96
92
|
if (highRelevance.length < CONVERGENCE_MIN_HIGH_RELEVANCE) return false;
|
|
97
93
|
|
|
98
94
|
// Check for critical gaps — any evaluation with empty missingContext
|
|
99
|
-
const criticalGaps = evaluations.some(
|
|
100
|
-
(e) => e.relevance < 0.3 && e.missingContext.length > 0,
|
|
101
|
-
);
|
|
95
|
+
const criticalGaps = evaluations.some((e) => e.relevance < 0.3 && e.missingContext.length > 0);
|
|
102
96
|
|
|
103
97
|
return !criticalGaps;
|
|
104
98
|
}
|
|
@@ -115,10 +109,7 @@ export function hasConverged(evaluations: RelevanceEvaluation[]): boolean {
|
|
|
115
109
|
* @param evaluations - Results from the current cycle
|
|
116
110
|
* @returns Refined query for the next cycle
|
|
117
111
|
*/
|
|
118
|
-
export function refineQuery(
|
|
119
|
-
query: RetrievalQuery,
|
|
120
|
-
evaluations: RelevanceEvaluation[],
|
|
121
|
-
): RetrievalQuery {
|
|
112
|
+
export function refineQuery(query: RetrievalQuery, evaluations: RelevanceEvaluation[]): RetrievalQuery {
|
|
122
113
|
const newKeywords = new Set(query.keywords);
|
|
123
114
|
const newExcludes = new Set(query.excludes);
|
|
124
115
|
const newFocusAreas = new Set(query.focusAreas ?? []);
|