pi-crew 0.9.15 → 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 +145 -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 +193 -40
- 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 +86 -169
- package/src/runtime/subprocess-tool-registry.ts +4 -1
- package/src/runtime/supervisor-contact.ts +10 -5
- package/src/runtime/task-display.ts +19 -5
- package/src/runtime/task-graph-scheduler.ts +95 -21
- package/src/runtime/task-graph.ts +5 -11
- package/src/runtime/task-health.ts +54 -47
- package/src/runtime/task-id.ts +11 -18
- package/src/runtime/task-output-context.ts +265 -81
- package/src/runtime/task-packet.ts +12 -20
- package/src/runtime/task-quality.ts +6 -14
- package/src/runtime/task-runner/context-retrieval.ts +4 -13
- package/src/runtime/task-runner/live-executor.ts +114 -36
- package/src/runtime/task-runner/output-splitter.ts +152 -0
- package/src/runtime/task-runner/progress.ts +50 -12
- package/src/runtime/task-runner/prompt-builder.ts +31 -7
- package/src/runtime/task-runner/prompt-pipeline.ts +31 -7
- package/src/runtime/task-runner/result-utils.ts +3 -1
- package/src/runtime/task-runner/retrieval-orchestrator.ts +310 -0
- package/src/runtime/task-runner/run-projection.ts +27 -8
- package/src/runtime/task-runner/state-helpers.ts +29 -8
- package/src/runtime/task-runner/tail-read.ts +2 -6
- package/src/runtime/task-runner.ts +180 -326
- package/src/runtime/team-runner-artifacts.ts +13 -0
- package/src/runtime/team-runner.ts +456 -974
- package/src/runtime/tool-output-pruner.ts +6 -9
- package/src/runtime/tool-progress.ts +11 -21
- package/src/runtime/verification-gates.ts +33 -24
- package/src/runtime/verification-integrity.ts +1 -4
- package/src/runtime/verification-worktree.ts +62 -12
- package/src/runtime/worker-heartbeat.ts +5 -1
- package/src/runtime/worker-startup.ts +29 -5
- package/src/runtime/workflow-state.ts +17 -9
- package/src/runtime/workspace-lock.ts +30 -35
- package/src/runtime/workspace-tree.ts +20 -32
- package/src/runtime/yield-handler.ts +43 -9
- package/src/runtime/zombie-scanner.ts +5 -4
- package/src/schema/config-schema.ts +266 -172
- package/src/schema/team-tool-schema.ts +29 -74
- package/src/schema/validation-types.ts +25 -17
- package/src/skills/discover-skills.ts +35 -10
- package/src/skills/skill-templates.ts +109 -27
- package/src/skills/validate.ts +26 -8
- package/src/state/active-run-registry.ts +87 -28
- package/src/state/artifact-store.ts +9 -5
- package/src/state/atomic-write-v2.ts +85 -63
- package/src/state/atomic-write.ts +105 -26
- package/src/state/blob-store.ts +47 -20
- package/src/state/contracts.ts +20 -5
- package/src/state/crew-init.ts +5 -22
- package/src/state/decision-ledger.ts +19 -73
- package/src/state/event-log-rotation.ts +41 -15
- package/src/state/event-log.ts +168 -53
- package/src/state/event-reconstructor.ts +11 -1
- package/src/state/gitignore-manager.ts +2 -8
- package/src/state/health-store.ts +57 -57
- package/src/state/hook-instinct-bridge.ts +1 -1
- package/src/state/hook-integrations.ts +1 -1
- package/src/state/instinct-store.ts +17 -5
- package/src/state/jsonl-writer.ts +1 -1
- package/src/state/locks.ts +23 -9
- package/src/state/mailbox.ts +151 -28
- package/src/state/observation-store.ts +20 -14
- package/src/state/run-cache.ts +142 -135
- package/src/state/run-graph.ts +6 -15
- package/src/state/run-metrics.ts +5 -18
- package/src/state/schedule.ts +15 -9
- package/src/state/state-store.ts +129 -45
- package/src/state/task-claims.ts +12 -2
- package/src/state/tiered-eval.ts +52 -43
- package/src/state/types-eval.ts +2 -2
- package/src/state/types.ts +24 -20
- package/src/state/usage.ts +20 -4
- package/src/state/worker-atomic-writer.ts +6 -3
- package/src/subagents/index.ts +2 -2
- package/src/teams/discover-teams.ts +21 -6
- package/src/tools/safe-bash-extension.ts +5 -6
- package/src/tools/safe-bash.ts +10 -11
- package/src/types/new-api-types.ts +6 -10
- package/src/ui/agent-management-overlay.ts +52 -40
- package/src/ui/card-colors.ts +13 -4
- package/src/ui/crew-footer.ts +8 -7
- package/src/ui/crew-select-list.ts +1 -1
- package/src/ui/dashboard-panes/agents-pane.ts +41 -25
- package/src/ui/dashboard-panes/cancellation-pane.ts +1 -1
- package/src/ui/dashboard-panes/capability-pane.ts +32 -15
- package/src/ui/dashboard-panes/health-pane.ts +2 -1
- package/src/ui/dashboard-panes/metrics-pane.ts +4 -1
- package/src/ui/dashboard-panes/progress-pane.ts +12 -9
- package/src/ui/heartbeat-aggregator.ts +15 -4
- package/src/ui/keybinding-map.ts +40 -7
- package/src/ui/live-conversation-overlay.ts +36 -20
- package/src/ui/live-duration.ts +1 -4
- package/src/ui/live-run-sidebar.ts +88 -25
- package/src/ui/loaders.ts +2 -8
- package/src/ui/mascot.ts +20 -36
- package/src/ui/overlays/agent-picker-overlay.ts +11 -3
- package/src/ui/overlays/confirm-overlay.ts +4 -2
- package/src/ui/overlays/help-overlay.ts +25 -14
- package/src/ui/overlays/mailbox-compose-overlay.ts +48 -11
- package/src/ui/overlays/mailbox-compose-preview.ts +20 -5
- package/src/ui/overlays/mailbox-detail-overlay.ts +27 -6
- package/src/ui/pi-ui-compat.ts +7 -7
- package/src/ui/powerbar-publisher.ts +120 -42
- package/src/ui/render-diff.ts +10 -3
- package/src/ui/render-scheduler.ts +12 -4
- package/src/ui/run-action-dispatcher.ts +81 -18
- package/src/ui/run-dashboard.ts +172 -76
- package/src/ui/run-event-bus.ts +59 -37
- package/src/ui/run-snapshot-cache.ts +276 -86
- package/src/ui/settings-overlay.ts +361 -74
- package/src/ui/status-colors.ts +12 -1
- package/src/ui/syntax-highlight.ts +1 -1
- package/src/ui/theme-adapter.ts +16 -14
- package/src/ui/theme-discovery.ts +13 -2
- package/src/ui/tool-progress-formatter.ts +7 -7
- package/src/ui/tool-render.ts +128 -56
- package/src/ui/tool-renderers/brief-mode.ts +45 -27
- package/src/ui/tool-renderers/index.ts +109 -43
- package/src/ui/transcript-cache.ts +32 -6
- package/src/ui/transcript-entries.ts +25 -23
- package/src/ui/transcript-viewer.ts +78 -29
- package/src/ui/widget/index.ts +99 -40
- package/src/ui/widget/widget-formatters.ts +13 -6
- package/src/ui/widget/widget-model.ts +19 -8
- package/src/ui/widget/widget-renderer.ts +23 -13
- package/src/ui/widget/widget-types.ts +1 -1
- package/src/utils/bm25-search.ts +199 -199
- package/src/utils/conflict-detect.ts +22 -21
- package/src/utils/env-filter.ts +14 -7
- package/src/utils/file-coalescer.ts +5 -1
- package/src/utils/fingerprint.ts +3 -6
- package/src/utils/frontmatter.ts +3 -1
- package/src/utils/fs-watch.ts +2 -6
- package/src/utils/gh-protocol.ts +119 -44
- package/src/utils/git.ts +13 -15
- package/src/utils/guards.ts +2 -5
- package/src/utils/ids.ts +9 -2
- package/src/utils/incremental-reader.ts +14 -3
- package/src/utils/internal-error.ts +2 -1
- package/src/utils/names.ts +12 -3
- package/src/utils/paths.ts +49 -5
- package/src/utils/project-detector.ts +2 -2
- package/src/utils/redaction.ts +29 -19
- package/src/utils/resolve-shell.ts +9 -7
- package/src/utils/run-watcher-registry.ts +19 -31
- package/src/utils/safe-paths.ts +45 -24
- package/src/utils/scan-cache.ts +9 -2
- package/src/utils/session-utils.ts +2 -4
- package/src/utils/sleep.ts +12 -5
- package/src/utils/sse-parser.ts +5 -17
- package/src/utils/visual.ts +52 -32
- package/src/workflows/discover-workflows.ts +41 -109
- package/src/workflows/intermediate-store.ts +5 -21
- package/src/workflows/preflight-validator.ts +6 -33
- package/src/workflows/topology-analyzer.ts +5 -21
- package/src/workflows/workflow-config.ts +7 -6
- package/src/worktree/branch-freshness.ts +66 -8
- package/src/worktree/cleanup.ts +130 -20
- package/src/worktree/worktree-manager.ts +212 -69
- package/skills/artifact-analysis-loop/SKILL.md +0 -303
- package/skills/detection-pipeline-design/SKILL.md +0 -286
- package/skills/hunting-investigation-loop/SKILL.md +0 -402
- package/skills/incident-playbook-construction/SKILL.md +0 -384
- package/skills/security-review/SKILL.md +0 -561
- package/skills/threat-hypothesis-framework/SKILL.md +0 -176
- package/skills/ui-render-performance/SKILL.md +0 -58
- /package/docs/{followup-review-round3-2026-05-12.md → archive/followup-review-round3-2026-05-12.md} +0 -0
- /package/docs/{followup-review-round4-2026-05-13.md → archive/followup-review-round4-2026-05-13.md} +0 -0
- /package/docs/{pi-crew-bugs.md → archive/pi-crew-bugs.md} +0 -0
- /package/docs/{pi-crew-test-final.md → archive/pi-crew-test-final.md} +0 -0
- /package/docs/{pi-crew-test-results.md → archive/pi-crew-test-results.md} +0 -0
- /package/docs/{pi-crew-test-round2.md → archive/pi-crew-test-round2.md} +0 -0
- /package/docs/{pi-crew-test-round4.md → archive/pi-crew-test-round4.md} +0 -0
- /package/docs/{pi-crew-test-round5.md → archive/pi-crew-test-round5.md} +0 -0
- /package/docs/{pi-crew-test-round6.md → archive/pi-crew-test-round6.md} +0 -0
- /package/docs/{pi-crew-v0.5.10-audit-fix-plan.md → archive/pi-crew-v0.5.10-audit-fix-plan.md} +0 -0
- /package/docs/{pi-crew-v0.5.11-audit-fix-plan.md → archive/pi-crew-v0.5.11-audit-fix-plan.md} +0 -0
- /package/docs/{pi-crew-v0.5.12-audit-fix-plan.md → archive/pi-crew-v0.5.12-audit-fix-plan.md} +0 -0
- /package/docs/{pi-crew-v0.5.13-audit-fix-plan.md → archive/pi-crew-v0.5.13-audit-fix-plan.md} +0 -0
- /package/docs/{pi-crew-v0.5.14-audit-fix-plan.md → archive/pi-crew-v0.5.14-audit-fix-plan.md} +0 -0
- /package/docs/{pi-crew-v0.5.16-audit-fix-plan.md → archive/pi-crew-v0.5.16-audit-fix-plan.md} +0 -0
- /package/docs/{pi-crew-v0.5.17-audit-fix-plan.md → archive/pi-crew-v0.5.17-audit-fix-plan.md} +0 -0
- /package/docs/{pi-crew-v0.5.5-audit-fix-plan.md → archive/pi-crew-v0.5.5-audit-fix-plan.md} +0 -0
- /package/docs/{pi-crew-v0.5.9-audit-fix-plan.md → archive/pi-crew-v0.5.9-audit-fix-plan.md} +0 -0
- /package/docs/{pi-mono-opportunities.md → archive/pi-mono-opportunities.md} +0 -0
- /package/docs/{pi-mono-review.md → archive/pi-mono-review.md} +0 -0
- /package/docs/{pi-subagent4-comparison.md → archive/pi-subagent4-comparison.md} +0 -0
- /package/docs/{pi-subagents3-deep-analysis.md → archive/pi-subagents3-deep-analysis.md} +0 -0
package/src/state/state-store.ts
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
|
-
import type { TeamRunManifest, TeamTaskState } from "./types.ts";
|
|
4
|
-
import { canTransitionRunStatus } from "./contracts.ts";
|
|
5
|
-
import { unregisterActiveRun } from "./active-run-registry.ts";
|
|
6
|
-
import { atomicWriteJson, atomicWriteJsonAsync, atomicWriteJsonCoalesced, readJsonFile } from "./atomic-write.ts";
|
|
7
|
-
import { appendEvent } from "./event-log.ts";
|
|
8
3
|
import { DEFAULT_CACHE, DEFAULT_PATHS } from "../config/defaults.ts";
|
|
4
|
+
import { errors } from "../errors.ts";
|
|
5
|
+
import type { TeamConfig } from "../teams/team-config.ts";
|
|
9
6
|
import { createRunId, createTaskId } from "../utils/ids.ts";
|
|
7
|
+
import { logInternalError } from "../utils/internal-error.ts";
|
|
10
8
|
import { findRepoRoot, projectCrewRoot, userCrewRoot } from "../utils/paths.ts";
|
|
11
9
|
import { assertSafePathId, resolveContainedRelativePath, resolveRealContainedPath } from "../utils/safe-paths.ts";
|
|
12
|
-
import { withRunLock, withRunLockSync } from "./locks.ts";
|
|
13
|
-
import { logInternalError } from "../utils/internal-error.ts";
|
|
14
|
-
import { errors } from "../errors.ts";
|
|
15
|
-
import type { TeamConfig } from "../teams/team-config.ts";
|
|
16
|
-
import type { WorkflowConfig } from "../workflows/workflow-config.ts";
|
|
17
10
|
import { toPiSessionId } from "../utils/session-utils.ts";
|
|
11
|
+
import type { WorkflowConfig } from "../workflows/workflow-config.ts";
|
|
12
|
+
import { unregisterActiveRun } from "./active-run-registry.ts";
|
|
13
|
+
import { atomicWriteJson, atomicWriteJsonAsync, atomicWriteJsonCoalesced, readJsonFile } from "./atomic-write.ts";
|
|
14
|
+
import { canTransitionRunStatus } from "./contracts.ts";
|
|
15
|
+
import { appendEvent } from "./event-log.ts";
|
|
18
16
|
import { HealthStore } from "./health-store.ts";
|
|
17
|
+
import { withRunLock, withRunLockSync } from "./locks.ts";
|
|
18
|
+
import type { TeamRunManifest, TeamTaskState } from "./types.ts";
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* stat() the manifest with a brief retry on Windows for the AV-scan window.
|
|
@@ -42,7 +42,9 @@ function statManifestWithWindowsRetry(manifestPath: string): fs.Stats {
|
|
|
42
42
|
const code = (error as NodeJS.ErrnoException).code;
|
|
43
43
|
if (!retryable.has(code ?? "")) throw error;
|
|
44
44
|
const end = Date.now() + Math.min(8, 1 * 2 ** attempt);
|
|
45
|
-
while (Date.now() < end) {
|
|
45
|
+
while (Date.now() < end) {
|
|
46
|
+
/* brief spin to ride out the AV scan window */
|
|
47
|
+
}
|
|
46
48
|
}
|
|
47
49
|
}
|
|
48
50
|
return fs.statSync(manifestPath); // last attempt — let caller's catch handle ENOENT
|
|
@@ -111,7 +113,10 @@ function setManifestCache(stateRoot: string, entry: ManifestCacheEntry): void {
|
|
|
111
113
|
let oldestTime = Infinity;
|
|
112
114
|
for (const [key, val] of manifestCache.entries()) {
|
|
113
115
|
const t = val.cachedAt ?? 0;
|
|
114
|
-
if (t < oldestTime) {
|
|
116
|
+
if (t < oldestTime) {
|
|
117
|
+
oldestTime = t;
|
|
118
|
+
oldestKey = key;
|
|
119
|
+
}
|
|
115
120
|
}
|
|
116
121
|
if (!oldestKey) break;
|
|
117
122
|
manifestCache.delete(oldestKey);
|
|
@@ -151,7 +156,13 @@ function validateRunManifestPaths(cwd: string, runId: string, manifest: TeamRunM
|
|
|
151
156
|
// Issue 2 fix: Reject manifests missing status field to prevent undefined
|
|
152
157
|
// behavior in callers like canTransitionRunStatus(manifest.status, newStatus).
|
|
153
158
|
if (!manifest.status || typeof manifest.status !== "string") return false;
|
|
154
|
-
if (
|
|
159
|
+
if (
|
|
160
|
+
manifest.runId !== runId ||
|
|
161
|
+
manifest.stateRoot !== stateRoot ||
|
|
162
|
+
manifest.tasksPath !== tasksPath ||
|
|
163
|
+
manifest.eventsPath !== path.join(stateRoot, "events.jsonl")
|
|
164
|
+
)
|
|
165
|
+
return false;
|
|
155
166
|
const artifactsParent = path.join(scopeBaseRoot(cwd), DEFAULT_PATHS.state.artifactsSubdir);
|
|
156
167
|
const expectedArtifactsRoot = resolveContainedRelativePath(artifactsParent, runId, "runId");
|
|
157
168
|
if (manifest.artifactsRoot !== expectedArtifactsRoot) return false;
|
|
@@ -197,7 +208,10 @@ export function createTasksFromWorkflow(runId: string, workflow: WorkflowConfig,
|
|
|
197
208
|
const role = team.roles.find((candidate) => candidate.name === step.role);
|
|
198
209
|
const id = stepToTaskId.get(step.id) ?? createTaskId(step.id, index);
|
|
199
210
|
const dependencies = step.dependsOn ?? [];
|
|
200
|
-
const children = workflow.steps
|
|
211
|
+
const children = workflow.steps
|
|
212
|
+
.filter((candidate) => candidate.dependsOn?.includes(step.id))
|
|
213
|
+
.map((candidate) => stepToTaskId.get(candidate.id))
|
|
214
|
+
.filter((childId): childId is string => childId !== undefined);
|
|
201
215
|
return {
|
|
202
216
|
id,
|
|
203
217
|
runId,
|
|
@@ -268,8 +282,13 @@ export function createRunManifest(params: {
|
|
|
268
282
|
// "unknown"). Include it explicitly in the thrown message so CI logs and
|
|
269
283
|
// production callers can see WHY the write failed instead of ": unknown".
|
|
270
284
|
const cause = result.error ? `: ${result.error}` : "";
|
|
271
|
-
throw errors
|
|
272
|
-
.
|
|
285
|
+
throw errors
|
|
286
|
+
.fileWrite(paths.stateRoot, {
|
|
287
|
+
code: "EWRITEFAIL",
|
|
288
|
+
} as NodeJS.ErrnoException)
|
|
289
|
+
.withContext(
|
|
290
|
+
`saveManifestAndTasksAtomicSync: manifestWritten=${result.manifestWritten}, tasksWritten=${result.tasksWritten}${cause}`,
|
|
291
|
+
);
|
|
273
292
|
}
|
|
274
293
|
appendEvent(paths.eventsPath, {
|
|
275
294
|
type: "run.created",
|
|
@@ -278,8 +297,16 @@ export function createRunManifest(params: {
|
|
|
278
297
|
metadata: {
|
|
279
298
|
seq: 1,
|
|
280
299
|
provenance: "team_runner",
|
|
281
|
-
sessionIdentity: {
|
|
282
|
-
|
|
300
|
+
sessionIdentity: {
|
|
301
|
+
title: params.team.name,
|
|
302
|
+
workspace: params.cwd,
|
|
303
|
+
purpose: params.goal,
|
|
304
|
+
},
|
|
305
|
+
ownership: {
|
|
306
|
+
owner: params.team.name,
|
|
307
|
+
workflowScope: params.workflow?.name ?? "manual",
|
|
308
|
+
watcherAction: "act",
|
|
309
|
+
},
|
|
283
310
|
confidence: "high",
|
|
284
311
|
},
|
|
285
312
|
});
|
|
@@ -401,14 +428,22 @@ export function saveRunTasks(manifest: TeamRunManifest, tasks: TeamTaskState[]):
|
|
|
401
428
|
function saveRunTasksCoalesced(manifest: TeamRunManifest, tasks: TeamTaskState[]): void {
|
|
402
429
|
// FIX: Invalidate cache BEFORE atomic write to prevent stale cache serving.
|
|
403
430
|
invalidateRunCache(manifest.stateRoot);
|
|
404
|
-
try {
|
|
431
|
+
try {
|
|
432
|
+
fs.statSync(manifest.stateRoot);
|
|
433
|
+
} catch {
|
|
434
|
+
return;
|
|
435
|
+
}
|
|
405
436
|
atomicWriteJsonCoalesced(manifest.tasksPath, tasks);
|
|
406
437
|
}
|
|
407
438
|
|
|
408
439
|
export async function saveRunTasksAsync(manifest: TeamRunManifest, tasks: TeamTaskState[]): Promise<void> {
|
|
409
440
|
// FIX: Invalidate cache BEFORE atomic write to prevent stale cache serving.
|
|
410
441
|
invalidateRunCache(manifest.stateRoot);
|
|
411
|
-
try {
|
|
442
|
+
try {
|
|
443
|
+
fs.statSync(manifest.stateRoot);
|
|
444
|
+
} catch {
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
412
447
|
await atomicWriteJsonAsync(manifest.tasksPath, tasks);
|
|
413
448
|
}
|
|
414
449
|
|
|
@@ -490,18 +525,32 @@ export interface UpdateRunStatusOptions {
|
|
|
490
525
|
metadata?: Parameters<typeof appendEvent>[1]["metadata"];
|
|
491
526
|
}
|
|
492
527
|
|
|
493
|
-
export function updateRunStatus(
|
|
528
|
+
export function updateRunStatus(
|
|
529
|
+
manifest: TeamRunManifest,
|
|
530
|
+
status: TeamRunManifest["status"],
|
|
531
|
+
summary?: string,
|
|
532
|
+
options: UpdateRunStatusOptions = {},
|
|
533
|
+
): TeamRunManifest {
|
|
494
534
|
if (!canTransitionRunStatus(manifest.status, status)) {
|
|
495
535
|
throw errors.invalidStatusTransition(manifest.status, status);
|
|
496
536
|
}
|
|
497
|
-
const updated: TeamRunManifest = {
|
|
537
|
+
const updated: TeamRunManifest = {
|
|
538
|
+
...manifest,
|
|
539
|
+
status,
|
|
540
|
+
updatedAt: new Date().toISOString(),
|
|
541
|
+
summary: summary ?? manifest.summary,
|
|
542
|
+
};
|
|
498
543
|
saveRunManifest(updated);
|
|
499
544
|
// Unregister from active-run-index when run reaches a terminal status.
|
|
500
545
|
// Without this, stale entries accumulate (e.g. integration tests in /tmp) and
|
|
501
546
|
// Pi UI shows ghost "queued" runs that are actually completed/failed/cancelled.
|
|
502
547
|
// Note: "blocked" is excluded because blocked runs can be unblocked later.
|
|
503
548
|
if (status === "completed" || status === "failed" || status === "cancelled") {
|
|
504
|
-
try {
|
|
549
|
+
try {
|
|
550
|
+
unregisterActiveRun(updated.runId);
|
|
551
|
+
} catch {
|
|
552
|
+
/* non-critical */
|
|
553
|
+
}
|
|
505
554
|
}
|
|
506
555
|
appendEvent(updated.eventsPath, {
|
|
507
556
|
type: `run.${status}`,
|
|
@@ -510,8 +559,16 @@ export function updateRunStatus(manifest: TeamRunManifest, status: TeamRunManife
|
|
|
510
559
|
...(options.data ? { data: options.data } : {}),
|
|
511
560
|
metadata: {
|
|
512
561
|
provenance: "team_runner",
|
|
513
|
-
sessionIdentity: {
|
|
514
|
-
|
|
562
|
+
sessionIdentity: {
|
|
563
|
+
title: updated.team,
|
|
564
|
+
workspace: updated.cwd,
|
|
565
|
+
purpose: updated.goal,
|
|
566
|
+
},
|
|
567
|
+
ownership: {
|
|
568
|
+
owner: updated.team,
|
|
569
|
+
workflowScope: updated.workflow ?? "manual",
|
|
570
|
+
watcherAction: "act",
|
|
571
|
+
},
|
|
515
572
|
confidence: "high",
|
|
516
573
|
...options.metadata,
|
|
517
574
|
},
|
|
@@ -574,12 +631,12 @@ export function loadRunManifestById(cwd: string, runId: string): { manifest: Tea
|
|
|
574
631
|
}
|
|
575
632
|
const tasksMtimeMs = tasksStat?.mtimeMs ?? 0;
|
|
576
633
|
if (
|
|
577
|
-
cached
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
634
|
+
cached &&
|
|
635
|
+
cached.manifestMtimeMs === manifestStat.mtimeMs &&
|
|
636
|
+
cached.manifestSize === manifestStat.size &&
|
|
637
|
+
cached.tasksMtimeMs === tasksMtimeMs &&
|
|
638
|
+
cached.tasksSize === (tasksStat?.size ?? 0) &&
|
|
639
|
+
cached.generation === manifestCacheGeneration
|
|
583
640
|
) {
|
|
584
641
|
// TTL eviction: expire stale entries even if mtime matches
|
|
585
642
|
// FIX: Also evict entries where cachedAt is undefined — such entries are
|
|
@@ -592,7 +649,7 @@ export function loadRunManifestById(cwd: string, runId: string): { manifest: Tea
|
|
|
592
649
|
} else if (!validateRunManifestPaths(cwd, runId, cached.manifest, stateRoot, tasksPath)) {
|
|
593
650
|
manifestCache.delete(stateRoot);
|
|
594
651
|
return undefined;
|
|
595
|
-
|
|
652
|
+
} else if (!fs.existsSync(tasksPath)) {
|
|
596
653
|
// Tasks file was deleted after cache was populated — this is a cache miss,
|
|
597
654
|
// not a manifest inconsistency. The cache check passes because
|
|
598
655
|
// tasksMtimeMs=0 and tasksSize=0 match a cache entry written when tasks.json
|
|
@@ -621,8 +678,11 @@ export function loadRunManifestById(cwd: string, runId: string): { manifest: Tea
|
|
|
621
678
|
const freshTasksStat = fs.existsSync(tasksPath) ? fs.statSync(tasksPath) : undefined;
|
|
622
679
|
tasks = readJsonFile<TeamTaskState[]>(tasksPath) ?? [];
|
|
623
680
|
// If size/mtime didn't change between stat and read, we're consistent.
|
|
624
|
-
if (
|
|
625
|
-
|
|
681
|
+
if (
|
|
682
|
+
freshStat.mtimeMs === manifestStat.mtimeMs &&
|
|
683
|
+
freshStat.size === manifestStat.size &&
|
|
684
|
+
(!freshTasksStat || (freshTasksStat.mtimeMs === tasksStat?.mtimeMs && freshTasksStat.size === tasksStat?.size))
|
|
685
|
+
) {
|
|
626
686
|
break;
|
|
627
687
|
}
|
|
628
688
|
attempts += 1;
|
|
@@ -637,7 +697,9 @@ export function loadRunManifestById(cwd: string, runId: string): { manifest: Tea
|
|
|
637
697
|
// Round 19: downgrade to debug — retry-loop instability is expected under
|
|
638
698
|
// concurrent writes (live team runs constantly append to tasks.json).
|
|
639
699
|
// This is best-effort by design; strict consistency requires withRunLock().
|
|
640
|
-
console.debug(
|
|
700
|
+
console.debug(
|
|
701
|
+
`[state-store] loadRunManifestById: retry loop detected instability for run ${runId} after ${attempts} attempt(s) — best-effort only, use withRunLock() for strict consistency`,
|
|
702
|
+
);
|
|
641
703
|
}
|
|
642
704
|
// NOTE: manifest mtime may legitimately be >= tasks mtime because
|
|
643
705
|
// saveManifestAndTasksAtomicSync writes manifest before tasks. However,
|
|
@@ -659,7 +721,10 @@ export function loadRunManifestById(cwd: string, runId: string): { manifest: Tea
|
|
|
659
721
|
return { manifest, tasks: tasks ?? [] };
|
|
660
722
|
}
|
|
661
723
|
|
|
662
|
-
export async function loadRunManifestByIdAsync(
|
|
724
|
+
export async function loadRunManifestByIdAsync(
|
|
725
|
+
cwd: string,
|
|
726
|
+
runId: string,
|
|
727
|
+
): Promise<{ manifest: TeamRunManifest; tasks: TeamTaskState[] } | undefined> {
|
|
663
728
|
const stateRoot = resolveRunStateRoot(cwd, runId);
|
|
664
729
|
if (!stateRoot) return undefined;
|
|
665
730
|
const manifestPath = path.join(stateRoot, "manifest.json");
|
|
@@ -681,7 +746,14 @@ export async function loadRunManifestByIdAsync(cwd: string, runId: string): Prom
|
|
|
681
746
|
tasksStat = undefined;
|
|
682
747
|
}
|
|
683
748
|
const tasksMtimeMs = tasksStat?.mtimeMs ?? 0;
|
|
684
|
-
if (
|
|
749
|
+
if (
|
|
750
|
+
cached &&
|
|
751
|
+
cached.manifestMtimeMs === manifestStat.mtimeMs &&
|
|
752
|
+
cached.manifestSize === manifestStat.size &&
|
|
753
|
+
cached.tasksMtimeMs === tasksMtimeMs &&
|
|
754
|
+
cached.tasksSize === (tasksStat?.size ?? 0) &&
|
|
755
|
+
cached.generation === manifestCacheGeneration
|
|
756
|
+
) {
|
|
685
757
|
// TTL eviction: expire stale entries even if mtime matches
|
|
686
758
|
// FIX: Also evict entries where cachedAt is undefined — such entries are
|
|
687
759
|
// effectively immortal otherwise (the `cached.cachedAt &&` check would skip
|
|
@@ -693,10 +765,10 @@ export async function loadRunManifestByIdAsync(cwd: string, runId: string): Prom
|
|
|
693
765
|
} else if (!validateRunManifestPaths(cwd, runId, cached.manifest, stateRoot, tasksPath)) {
|
|
694
766
|
manifestCache.delete(stateRoot);
|
|
695
767
|
return undefined;
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
768
|
+
} else if (!fs.existsSync(tasksPath)) {
|
|
769
|
+
// Tasks file was deleted after cache was populated — do not serve stale cache.
|
|
770
|
+
manifestCache.delete(stateRoot);
|
|
771
|
+
return undefined;
|
|
700
772
|
} else {
|
|
701
773
|
return { manifest: cached.manifest, tasks: cached.tasks ?? [] };
|
|
702
774
|
}
|
|
@@ -714,8 +786,11 @@ export async function loadRunManifestByIdAsync(cwd: string, runId: string): Prom
|
|
|
714
786
|
const freshTasksStat = await fs.promises.stat(tasksPath).catch(() => undefined);
|
|
715
787
|
tasks = (await readJsonFileAsync<TeamTaskState[]>(tasksPath)) ?? [];
|
|
716
788
|
// If size/mtime didn't change between stat and read, we're consistent.
|
|
717
|
-
if (
|
|
718
|
-
|
|
789
|
+
if (
|
|
790
|
+
freshStat.mtimeMs === manifestStat.mtimeMs &&
|
|
791
|
+
freshStat.size === manifestStat.size &&
|
|
792
|
+
(!freshTasksStat || (freshTasksStat.mtimeMs === tasksStat?.mtimeMs && freshTasksStat.size === tasksStat?.size))
|
|
793
|
+
) {
|
|
719
794
|
break;
|
|
720
795
|
}
|
|
721
796
|
attempts += 1;
|
|
@@ -730,7 +805,9 @@ export async function loadRunManifestByIdAsync(cwd: string, runId: string): Prom
|
|
|
730
805
|
// Round 19: downgrade to debug — retry-loop instability is expected under
|
|
731
806
|
// concurrent writes (live team runs constantly append to tasks.json).
|
|
732
807
|
// This is best-effort by design; strict consistency requires withRunLock().
|
|
733
|
-
console.debug(
|
|
808
|
+
console.debug(
|
|
809
|
+
`[state-store] loadRunManifestByIdAsync: retry loop detected instability for run ${runId} after ${attempts} attempt(s) — best-effort only, use withRunLock() for strict consistency`,
|
|
810
|
+
);
|
|
734
811
|
}
|
|
735
812
|
// NOTE: manifest mtime may legitimately be >= tasks mtime because
|
|
736
813
|
// saveManifestAndTasksAtomicSync writes manifest before tasks. However,
|
|
@@ -742,6 +819,13 @@ export async function loadRunManifestByIdAsync(cwd: string, runId: string): Prom
|
|
|
742
819
|
// It does not indicate corruption on its own.
|
|
743
820
|
|
|
744
821
|
if (!manifest || !validateRunManifestPaths(cwd, runId, manifest, stateRoot, tasksPath)) return undefined;
|
|
745
|
-
setManifestCache(stateRoot, {
|
|
822
|
+
setManifestCache(stateRoot, {
|
|
823
|
+
manifest,
|
|
824
|
+
tasks: tasks ?? [],
|
|
825
|
+
manifestMtimeMs: manifestStat.mtimeMs,
|
|
826
|
+
manifestSize: manifestStat.size,
|
|
827
|
+
tasksMtimeMs,
|
|
828
|
+
tasksSize: tasksStat?.size ?? 0,
|
|
829
|
+
});
|
|
746
830
|
return { manifest, tasks: tasks ?? [] };
|
|
747
831
|
}
|
package/src/state/task-claims.ts
CHANGED
|
@@ -8,7 +8,11 @@ export interface TaskClaimState {
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
export function createTaskClaim(owner: string, leaseMs = 5 * 60_000, now = new Date()): TaskClaimState {
|
|
11
|
-
return {
|
|
11
|
+
return {
|
|
12
|
+
owner,
|
|
13
|
+
token: randomUUID(),
|
|
14
|
+
leasedUntil: new Date(now.getTime() + leaseMs).toISOString(),
|
|
15
|
+
};
|
|
12
16
|
}
|
|
13
17
|
|
|
14
18
|
export function isTaskClaimExpired(claim: TaskClaimState | undefined, now = new Date()): boolean {
|
|
@@ -43,7 +47,13 @@ export function releaseTaskClaim<T extends TeamTaskState>(task: T, owner: string
|
|
|
43
47
|
return { ...task, claim: undefined };
|
|
44
48
|
}
|
|
45
49
|
|
|
46
|
-
export function transitionClaimedTaskStatus<T extends TeamTaskState>(
|
|
50
|
+
export function transitionClaimedTaskStatus<T extends TeamTaskState>(
|
|
51
|
+
task: T,
|
|
52
|
+
owner: string,
|
|
53
|
+
token: string,
|
|
54
|
+
status: T["status"],
|
|
55
|
+
now = new Date(),
|
|
56
|
+
): T {
|
|
47
57
|
if (!canUseTaskClaim(task, owner, token, now)) {
|
|
48
58
|
throw new Error(`Task '${task.id}' claim is not held by '${owner}' or has expired.`);
|
|
49
59
|
}
|
package/src/state/tiered-eval.ts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Tiered Evaluation System
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
4
|
* Inspired by agent-eval's judge tiers, this module provides a hierarchical
|
|
5
5
|
* evaluation system where checks are grouped by computational cost and reliability:
|
|
6
|
-
*
|
|
6
|
+
*
|
|
7
7
|
* - Tier 1 (deterministic): Fast checks (~1s timeout) - file exists, parse errors, etc.
|
|
8
8
|
* - Tier 2 (pattern): Medium checks (~5s timeout) - grep, regex, structural checks
|
|
9
9
|
* - Tier 3 (llm): Expensive checks (~60s timeout) - LLM-based evaluation
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import type { EvalTier, TierConfig
|
|
12
|
+
import type { EvalResult, EvalTier, TierConfig } from "./types-eval.ts";
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* Default tier configurations with increasing timeouts for more expensive evaluations.
|
|
@@ -40,7 +40,7 @@ export const TIER_CONFIGS: Record<EvalTier, TierConfig> = {
|
|
|
40
40
|
*/
|
|
41
41
|
export const DEFAULT_TIER_CONFIGS = TIER_CONFIGS;
|
|
42
42
|
|
|
43
|
-
export type { EvalTier, TierConfig
|
|
43
|
+
export type { EvalResult, EvalTier, TierConfig };
|
|
44
44
|
|
|
45
45
|
/**
|
|
46
46
|
* Individual evaluation check with its assigned tier.
|
|
@@ -99,21 +99,21 @@ export interface TieredEvalResult {
|
|
|
99
99
|
/**
|
|
100
100
|
* TieredEvalRunner executes evaluation checks in tiered order,
|
|
101
101
|
* with appropriate timeouts for each tier level.
|
|
102
|
-
*
|
|
102
|
+
*
|
|
103
103
|
* Supports two execution modes:
|
|
104
104
|
* - runTieredEval: Runs all checks regardless of failures
|
|
105
105
|
* - runTieredEvalFailFast: Stops at first failure (like ECC promotion gates)
|
|
106
|
-
*
|
|
106
|
+
*
|
|
107
107
|
* @example
|
|
108
108
|
* ```typescript
|
|
109
109
|
* const runner = new TieredEvalRunner();
|
|
110
|
-
*
|
|
110
|
+
*
|
|
111
111
|
* // Run all checks
|
|
112
112
|
* const allResults = await runner.runTieredEval('task-1', [
|
|
113
113
|
* { tier: 1, check: () => fs.existsSync('output.json') },
|
|
114
114
|
* { tier: 2, check: async () => (await run('grep', ['pattern', 'output.json'])).exitCode === 0 }
|
|
115
115
|
* ]);
|
|
116
|
-
*
|
|
116
|
+
*
|
|
117
117
|
* // Fail-fast mode
|
|
118
118
|
* const failFastResult = await runner.runTieredEvalFailFast('task-2', [
|
|
119
119
|
* { tier: 1, check: () => fs.existsSync('output.json') },
|
|
@@ -129,7 +129,7 @@ export class TieredEvalRunner {
|
|
|
129
129
|
|
|
130
130
|
/**
|
|
131
131
|
* Creates a new TieredEvalRunner instance.
|
|
132
|
-
*
|
|
132
|
+
*
|
|
133
133
|
* @param config - Optional configuration to override defaults
|
|
134
134
|
*/
|
|
135
135
|
constructor(config?: TieredEvalRunnerConfig) {
|
|
@@ -154,7 +154,7 @@ export class TieredEvalRunner {
|
|
|
154
154
|
|
|
155
155
|
/**
|
|
156
156
|
* Gets the effective timeout for a given tier.
|
|
157
|
-
*
|
|
157
|
+
*
|
|
158
158
|
* @param tier - The evaluation tier
|
|
159
159
|
* @returns The timeout in milliseconds (after multiplier is applied)
|
|
160
160
|
*/
|
|
@@ -164,7 +164,7 @@ export class TieredEvalRunner {
|
|
|
164
164
|
|
|
165
165
|
/**
|
|
166
166
|
* Gets the configuration for a specific tier.
|
|
167
|
-
*
|
|
167
|
+
*
|
|
168
168
|
* @param tier - The evaluation tier
|
|
169
169
|
* @returns The tier configuration
|
|
170
170
|
*/
|
|
@@ -174,15 +174,12 @@ export class TieredEvalRunner {
|
|
|
174
174
|
|
|
175
175
|
/**
|
|
176
176
|
* Runs a check with the specified timeout.
|
|
177
|
-
*
|
|
177
|
+
*
|
|
178
178
|
* @param check - The check function to run
|
|
179
179
|
* @param tier - The tier this check belongs to
|
|
180
180
|
* @returns The result of the check
|
|
181
181
|
*/
|
|
182
|
-
private async runCheckWithTimeout(
|
|
183
|
-
check: () => Promise<boolean> | boolean,
|
|
184
|
-
tier: EvalTier,
|
|
185
|
-
): Promise<CheckResult> {
|
|
182
|
+
private async runCheckWithTimeout(check: () => Promise<boolean> | boolean, tier: EvalTier): Promise<CheckResult> {
|
|
186
183
|
const timeout = this.getTimeout(tier);
|
|
187
184
|
const startTime = Date.now();
|
|
188
185
|
|
|
@@ -228,11 +225,11 @@ export class TieredEvalRunner {
|
|
|
228
225
|
|
|
229
226
|
/**
|
|
230
227
|
* Runs all evaluation checks and returns results for each.
|
|
231
|
-
*
|
|
228
|
+
*
|
|
232
229
|
* @param taskId - Identifier for the task being evaluated
|
|
233
230
|
* @param checks - Array of checks to run, each with a tier assignment
|
|
234
231
|
* @returns Array of evaluation results for each check
|
|
235
|
-
*
|
|
232
|
+
*
|
|
236
233
|
* @example
|
|
237
234
|
* ```typescript
|
|
238
235
|
* const results = await runner.runTieredEval('task-123', [
|
|
@@ -240,19 +237,20 @@ export class TieredEvalRunner {
|
|
|
240
237
|
* { tier: 2, check: async () => (await grep('output.json', 'pattern')).found },
|
|
241
238
|
* { tier: 3, check: async () => llmJudge.evaluate(output) }
|
|
242
239
|
* ]);
|
|
243
|
-
*
|
|
240
|
+
*
|
|
244
241
|
* // Check if all passed
|
|
245
242
|
* const allPassed = results.every(r => r.passed);
|
|
246
243
|
* ```
|
|
247
244
|
*/
|
|
248
245
|
async runTieredEval(
|
|
249
246
|
taskId: string,
|
|
250
|
-
checks: Array<{
|
|
247
|
+
checks: Array<{
|
|
248
|
+
tier: EvalTier;
|
|
249
|
+
check: () => Promise<boolean> | boolean;
|
|
250
|
+
}>,
|
|
251
251
|
): Promise<EvalResult[]> {
|
|
252
252
|
// Sort checks by tier if configured (lower tiers first)
|
|
253
|
-
const sortedChecks = this.sortByTier
|
|
254
|
-
? [...checks].sort((a, b) => a.tier - b.tier)
|
|
255
|
-
: checks;
|
|
253
|
+
const sortedChecks = this.sortByTier ? [...checks].sort((a, b) => a.tier - b.tier) : checks;
|
|
256
254
|
|
|
257
255
|
const results: EvalResult[] = [];
|
|
258
256
|
|
|
@@ -267,14 +265,14 @@ export class TieredEvalRunner {
|
|
|
267
265
|
|
|
268
266
|
/**
|
|
269
267
|
* Runs evaluation checks in fail-fast mode, stopping at the first failure.
|
|
270
|
-
*
|
|
268
|
+
*
|
|
271
269
|
* This is useful for promotion gates where cheaper checks should run first
|
|
272
270
|
* and any failure should stop the evaluation immediately.
|
|
273
|
-
*
|
|
271
|
+
*
|
|
274
272
|
* @param taskId - Identifier for the task being evaluated
|
|
275
273
|
* @param checks - Array of checks to run, each with a tier assignment
|
|
276
274
|
* @returns Array of evaluation results (may be shorter than input if fail-fast triggered)
|
|
277
|
-
*
|
|
275
|
+
*
|
|
278
276
|
* @example
|
|
279
277
|
* ```typescript
|
|
280
278
|
* const results = await runner.runTieredEvalFailFast('task-123', [
|
|
@@ -282,7 +280,7 @@ export class TieredEvalRunner {
|
|
|
282
280
|
* { tier: 2, check: async () => (await grep('output.json', 'pattern')).found },
|
|
283
281
|
* { tier: 3, check: async () => llmJudge.evaluate(output) }
|
|
284
282
|
* ]);
|
|
285
|
-
*
|
|
283
|
+
*
|
|
286
284
|
* if (results.length < checks.length) {
|
|
287
285
|
* console.log(`Failed at tier ${results[results.length - 1].tier}`);
|
|
288
286
|
* }
|
|
@@ -290,12 +288,13 @@ export class TieredEvalRunner {
|
|
|
290
288
|
*/
|
|
291
289
|
async runTieredEvalFailFast(
|
|
292
290
|
taskId: string,
|
|
293
|
-
checks: Array<{
|
|
291
|
+
checks: Array<{
|
|
292
|
+
tier: EvalTier;
|
|
293
|
+
check: () => Promise<boolean> | boolean;
|
|
294
|
+
}>,
|
|
294
295
|
): Promise<EvalResult[]> {
|
|
295
296
|
// Sort checks by tier if configured (lower tiers first)
|
|
296
|
-
const sortedChecks = this.sortByTier
|
|
297
|
-
? [...checks].sort((a, b) => a.tier - b.tier)
|
|
298
|
-
: checks;
|
|
297
|
+
const sortedChecks = this.sortByTier ? [...checks].sort((a, b) => a.tier - b.tier) : checks;
|
|
299
298
|
|
|
300
299
|
const results: EvalResult[] = [];
|
|
301
300
|
|
|
@@ -315,7 +314,7 @@ export class TieredEvalRunner {
|
|
|
315
314
|
|
|
316
315
|
/**
|
|
317
316
|
* Runs evaluation checks and returns a structured result object.
|
|
318
|
-
*
|
|
317
|
+
*
|
|
319
318
|
* @param taskId - Identifier for the task being evaluated
|
|
320
319
|
* @param checks - Array of checks to run, each with a tier assignment
|
|
321
320
|
* @param failFast - Whether to stop at first failure (default: false)
|
|
@@ -323,12 +322,13 @@ export class TieredEvalRunner {
|
|
|
323
322
|
*/
|
|
324
323
|
async runEval(
|
|
325
324
|
taskId: string,
|
|
326
|
-
checks: Array<{
|
|
325
|
+
checks: Array<{
|
|
326
|
+
tier: EvalTier;
|
|
327
|
+
check: () => Promise<boolean> | boolean;
|
|
328
|
+
}>,
|
|
327
329
|
failFast = false,
|
|
328
330
|
): Promise<TieredEvalResult> {
|
|
329
|
-
const sortedChecks = this.sortByTier
|
|
330
|
-
? [...checks].sort((a, b) => a.tier - b.tier)
|
|
331
|
-
: checks;
|
|
331
|
+
const sortedChecks = this.sortByTier ? [...checks].sort((a, b) => a.tier - b.tier) : checks;
|
|
332
332
|
|
|
333
333
|
const results: CheckResult[] = [];
|
|
334
334
|
let totalDurationMs = 0;
|
|
@@ -361,9 +361,9 @@ export class TieredEvalRunner {
|
|
|
361
361
|
|
|
362
362
|
/**
|
|
363
363
|
* Runs checks in parallel within each tier, but sequentially across tiers.
|
|
364
|
-
*
|
|
364
|
+
*
|
|
365
365
|
* This optimizes execution time when multiple checks exist at the same tier level.
|
|
366
|
-
*
|
|
366
|
+
*
|
|
367
367
|
* @param taskId - Identifier for the task being evaluated
|
|
368
368
|
* @param checks - Array of checks to run
|
|
369
369
|
* @param failFast - Whether to stop at first failure (default: false)
|
|
@@ -371,11 +371,20 @@ export class TieredEvalRunner {
|
|
|
371
371
|
*/
|
|
372
372
|
async runTieredEvalParallel(
|
|
373
373
|
taskId: string,
|
|
374
|
-
checks: Array<{
|
|
374
|
+
checks: Array<{
|
|
375
|
+
tier: EvalTier;
|
|
376
|
+
check: () => Promise<boolean> | boolean;
|
|
377
|
+
}>,
|
|
375
378
|
failFast = false,
|
|
376
379
|
): Promise<TieredEvalResult> {
|
|
377
380
|
// Group checks by tier
|
|
378
|
-
const checksByTier = new Map<
|
|
381
|
+
const checksByTier = new Map<
|
|
382
|
+
EvalTier,
|
|
383
|
+
Array<{
|
|
384
|
+
check: () => Promise<boolean> | boolean;
|
|
385
|
+
originalIndex: number;
|
|
386
|
+
}>
|
|
387
|
+
>();
|
|
379
388
|
|
|
380
389
|
checks.forEach((c, originalIndex) => {
|
|
381
390
|
const existing = checksByTier.get(c.tier) || [];
|
|
@@ -431,7 +440,7 @@ export class TieredEvalRunner {
|
|
|
431
440
|
|
|
432
441
|
/**
|
|
433
442
|
* Creates a new runner with overridden tier configurations.
|
|
434
|
-
*
|
|
443
|
+
*
|
|
435
444
|
* @param overrides - Tier configurations to override
|
|
436
445
|
* @returns A new TieredEvalRunner instance
|
|
437
446
|
*/
|
|
@@ -447,10 +456,10 @@ export class TieredEvalRunner {
|
|
|
447
456
|
|
|
448
457
|
/**
|
|
449
458
|
* Convenience function to create a TieredEvalRunner with default configuration.
|
|
450
|
-
*
|
|
459
|
+
*
|
|
451
460
|
* @param config - Optional configuration overrides
|
|
452
461
|
* @returns A new TieredEvalRunner instance
|
|
453
|
-
*
|
|
462
|
+
*
|
|
454
463
|
* @example
|
|
455
464
|
* ```typescript
|
|
456
465
|
* const runner = createRunner({
|
package/src/state/types-eval.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Types for the Tiered Evaluation System
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
4
|
* Inspired by agent-eval's judge tiers for hierarchical evaluation.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Evaluation tiers with increasing computational cost.
|
|
9
|
-
*
|
|
9
|
+
*
|
|
10
10
|
* - Tier 1: Deterministic, fast checks (file existence, parse errors)
|
|
11
11
|
* - Tier 2: Pattern matching, structural checks (grep, regex)
|
|
12
12
|
* - Tier 3: LLM-based evaluation for natural language checks
|