pi-crew 0.9.16 → 0.9.18
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 +130 -0
- package/README.md +19 -0
- package/dist/build-meta.json +21784 -0
- package/dist/index.mjs +83169 -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/migration/atomic-write-v2-migration.md +297 -0
- package/docs/patterns/command-agent-skill.md +1 -1
- package/docs/perf/performance-review-2026-07.md +287 -0
- 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 +303 -591
- 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 +149 -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 +39 -24
- 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 +344 -79
- 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 +187 -59
- 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 +13 -31
- 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 +10 -18
- 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 +2 -6
- package/src/runtime/retry-executor.ts +20 -4
- package/src/runtime/retry-runner.ts +27 -51
- 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 +12 -19
- 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 +50 -14
- 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 +2 -7
- 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 +106 -27
- 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 +137 -47
- 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/terminal-status.ts +1 -3
- 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 +46 -29
- 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
|
});
|
|
@@ -395,20 +422,34 @@ export function saveRunTasks(manifest: TeamRunManifest, tasks: TeamTaskState[]):
|
|
|
395
422
|
* see the previous on-disk content while the write is still buffered).
|
|
396
423
|
* Bulk update paths that fan out into multiple writer call sites are the
|
|
397
424
|
* intended use case. Single-update + read-update loops (e.g.
|
|
398
|
-
* persistSingleTaskUpdate) should keep using saveRunTasks
|
|
425
|
+
* persistSingleTaskUpdate) should keep using saveRunTasks — OR call
|
|
426
|
+
* `flushPendingAtomicWrites()` immediately before their read to force
|
|
427
|
+
* any pending coalesced writes to land on disk first.
|
|
428
|
+
*
|
|
429
|
+
* (perf review 2026-07 F4) — now used by persistSingleTaskUpdate's
|
|
430
|
+
* non-terminal checkpoint path; that caller calls flushPendingAtomicWrites()
|
|
431
|
+
* before its read-modify-write load to defeat the stale-read window.
|
|
399
432
|
*/
|
|
400
433
|
/** @internal */
|
|
401
|
-
function saveRunTasksCoalesced(manifest: TeamRunManifest, tasks: TeamTaskState[]): void {
|
|
434
|
+
export function saveRunTasksCoalesced(manifest: TeamRunManifest, tasks: TeamTaskState[]): void {
|
|
402
435
|
// FIX: Invalidate cache BEFORE atomic write to prevent stale cache serving.
|
|
403
436
|
invalidateRunCache(manifest.stateRoot);
|
|
404
|
-
try {
|
|
437
|
+
try {
|
|
438
|
+
fs.statSync(manifest.stateRoot);
|
|
439
|
+
} catch {
|
|
440
|
+
return;
|
|
441
|
+
}
|
|
405
442
|
atomicWriteJsonCoalesced(manifest.tasksPath, tasks);
|
|
406
443
|
}
|
|
407
444
|
|
|
408
445
|
export async function saveRunTasksAsync(manifest: TeamRunManifest, tasks: TeamTaskState[]): Promise<void> {
|
|
409
446
|
// FIX: Invalidate cache BEFORE atomic write to prevent stale cache serving.
|
|
410
447
|
invalidateRunCache(manifest.stateRoot);
|
|
411
|
-
try {
|
|
448
|
+
try {
|
|
449
|
+
fs.statSync(manifest.stateRoot);
|
|
450
|
+
} catch {
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
412
453
|
await atomicWriteJsonAsync(manifest.tasksPath, tasks);
|
|
413
454
|
}
|
|
414
455
|
|
|
@@ -490,18 +531,32 @@ export interface UpdateRunStatusOptions {
|
|
|
490
531
|
metadata?: Parameters<typeof appendEvent>[1]["metadata"];
|
|
491
532
|
}
|
|
492
533
|
|
|
493
|
-
export function updateRunStatus(
|
|
534
|
+
export function updateRunStatus(
|
|
535
|
+
manifest: TeamRunManifest,
|
|
536
|
+
status: TeamRunManifest["status"],
|
|
537
|
+
summary?: string,
|
|
538
|
+
options: UpdateRunStatusOptions = {},
|
|
539
|
+
): TeamRunManifest {
|
|
494
540
|
if (!canTransitionRunStatus(manifest.status, status)) {
|
|
495
541
|
throw errors.invalidStatusTransition(manifest.status, status);
|
|
496
542
|
}
|
|
497
|
-
const updated: TeamRunManifest = {
|
|
543
|
+
const updated: TeamRunManifest = {
|
|
544
|
+
...manifest,
|
|
545
|
+
status,
|
|
546
|
+
updatedAt: new Date().toISOString(),
|
|
547
|
+
summary: summary ?? manifest.summary,
|
|
548
|
+
};
|
|
498
549
|
saveRunManifest(updated);
|
|
499
550
|
// Unregister from active-run-index when run reaches a terminal status.
|
|
500
551
|
// Without this, stale entries accumulate (e.g. integration tests in /tmp) and
|
|
501
552
|
// Pi UI shows ghost "queued" runs that are actually completed/failed/cancelled.
|
|
502
553
|
// Note: "blocked" is excluded because blocked runs can be unblocked later.
|
|
503
554
|
if (status === "completed" || status === "failed" || status === "cancelled") {
|
|
504
|
-
try {
|
|
555
|
+
try {
|
|
556
|
+
unregisterActiveRun(updated.runId);
|
|
557
|
+
} catch {
|
|
558
|
+
/* non-critical */
|
|
559
|
+
}
|
|
505
560
|
}
|
|
506
561
|
appendEvent(updated.eventsPath, {
|
|
507
562
|
type: `run.${status}`,
|
|
@@ -510,8 +565,16 @@ export function updateRunStatus(manifest: TeamRunManifest, status: TeamRunManife
|
|
|
510
565
|
...(options.data ? { data: options.data } : {}),
|
|
511
566
|
metadata: {
|
|
512
567
|
provenance: "team_runner",
|
|
513
|
-
sessionIdentity: {
|
|
514
|
-
|
|
568
|
+
sessionIdentity: {
|
|
569
|
+
title: updated.team,
|
|
570
|
+
workspace: updated.cwd,
|
|
571
|
+
purpose: updated.goal,
|
|
572
|
+
},
|
|
573
|
+
ownership: {
|
|
574
|
+
owner: updated.team,
|
|
575
|
+
workflowScope: updated.workflow ?? "manual",
|
|
576
|
+
watcherAction: "act",
|
|
577
|
+
},
|
|
515
578
|
confidence: "high",
|
|
516
579
|
...options.metadata,
|
|
517
580
|
},
|
|
@@ -574,12 +637,12 @@ export function loadRunManifestById(cwd: string, runId: string): { manifest: Tea
|
|
|
574
637
|
}
|
|
575
638
|
const tasksMtimeMs = tasksStat?.mtimeMs ?? 0;
|
|
576
639
|
if (
|
|
577
|
-
cached
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
640
|
+
cached &&
|
|
641
|
+
cached.manifestMtimeMs === manifestStat.mtimeMs &&
|
|
642
|
+
cached.manifestSize === manifestStat.size &&
|
|
643
|
+
cached.tasksMtimeMs === tasksMtimeMs &&
|
|
644
|
+
cached.tasksSize === (tasksStat?.size ?? 0) &&
|
|
645
|
+
cached.generation === manifestCacheGeneration
|
|
583
646
|
) {
|
|
584
647
|
// TTL eviction: expire stale entries even if mtime matches
|
|
585
648
|
// FIX: Also evict entries where cachedAt is undefined — such entries are
|
|
@@ -592,7 +655,7 @@ export function loadRunManifestById(cwd: string, runId: string): { manifest: Tea
|
|
|
592
655
|
} else if (!validateRunManifestPaths(cwd, runId, cached.manifest, stateRoot, tasksPath)) {
|
|
593
656
|
manifestCache.delete(stateRoot);
|
|
594
657
|
return undefined;
|
|
595
|
-
|
|
658
|
+
} else if (!fs.existsSync(tasksPath)) {
|
|
596
659
|
// Tasks file was deleted after cache was populated — this is a cache miss,
|
|
597
660
|
// not a manifest inconsistency. The cache check passes because
|
|
598
661
|
// tasksMtimeMs=0 and tasksSize=0 match a cache entry written when tasks.json
|
|
@@ -621,8 +684,11 @@ export function loadRunManifestById(cwd: string, runId: string): { manifest: Tea
|
|
|
621
684
|
const freshTasksStat = fs.existsSync(tasksPath) ? fs.statSync(tasksPath) : undefined;
|
|
622
685
|
tasks = readJsonFile<TeamTaskState[]>(tasksPath) ?? [];
|
|
623
686
|
// If size/mtime didn't change between stat and read, we're consistent.
|
|
624
|
-
if (
|
|
625
|
-
|
|
687
|
+
if (
|
|
688
|
+
freshStat.mtimeMs === manifestStat.mtimeMs &&
|
|
689
|
+
freshStat.size === manifestStat.size &&
|
|
690
|
+
(!freshTasksStat || (freshTasksStat.mtimeMs === tasksStat?.mtimeMs && freshTasksStat.size === tasksStat?.size))
|
|
691
|
+
) {
|
|
626
692
|
break;
|
|
627
693
|
}
|
|
628
694
|
attempts += 1;
|
|
@@ -637,7 +703,9 @@ export function loadRunManifestById(cwd: string, runId: string): { manifest: Tea
|
|
|
637
703
|
// Round 19: downgrade to debug — retry-loop instability is expected under
|
|
638
704
|
// concurrent writes (live team runs constantly append to tasks.json).
|
|
639
705
|
// This is best-effort by design; strict consistency requires withRunLock().
|
|
640
|
-
console.debug(
|
|
706
|
+
console.debug(
|
|
707
|
+
`[state-store] loadRunManifestById: retry loop detected instability for run ${runId} after ${attempts} attempt(s) — best-effort only, use withRunLock() for strict consistency`,
|
|
708
|
+
);
|
|
641
709
|
}
|
|
642
710
|
// NOTE: manifest mtime may legitimately be >= tasks mtime because
|
|
643
711
|
// saveManifestAndTasksAtomicSync writes manifest before tasks. However,
|
|
@@ -659,7 +727,10 @@ export function loadRunManifestById(cwd: string, runId: string): { manifest: Tea
|
|
|
659
727
|
return { manifest, tasks: tasks ?? [] };
|
|
660
728
|
}
|
|
661
729
|
|
|
662
|
-
export async function loadRunManifestByIdAsync(
|
|
730
|
+
export async function loadRunManifestByIdAsync(
|
|
731
|
+
cwd: string,
|
|
732
|
+
runId: string,
|
|
733
|
+
): Promise<{ manifest: TeamRunManifest; tasks: TeamTaskState[] } | undefined> {
|
|
663
734
|
const stateRoot = resolveRunStateRoot(cwd, runId);
|
|
664
735
|
if (!stateRoot) return undefined;
|
|
665
736
|
const manifestPath = path.join(stateRoot, "manifest.json");
|
|
@@ -681,7 +752,14 @@ export async function loadRunManifestByIdAsync(cwd: string, runId: string): Prom
|
|
|
681
752
|
tasksStat = undefined;
|
|
682
753
|
}
|
|
683
754
|
const tasksMtimeMs = tasksStat?.mtimeMs ?? 0;
|
|
684
|
-
if (
|
|
755
|
+
if (
|
|
756
|
+
cached &&
|
|
757
|
+
cached.manifestMtimeMs === manifestStat.mtimeMs &&
|
|
758
|
+
cached.manifestSize === manifestStat.size &&
|
|
759
|
+
cached.tasksMtimeMs === tasksMtimeMs &&
|
|
760
|
+
cached.tasksSize === (tasksStat?.size ?? 0) &&
|
|
761
|
+
cached.generation === manifestCacheGeneration
|
|
762
|
+
) {
|
|
685
763
|
// TTL eviction: expire stale entries even if mtime matches
|
|
686
764
|
// FIX: Also evict entries where cachedAt is undefined — such entries are
|
|
687
765
|
// effectively immortal otherwise (the `cached.cachedAt &&` check would skip
|
|
@@ -693,10 +771,10 @@ export async function loadRunManifestByIdAsync(cwd: string, runId: string): Prom
|
|
|
693
771
|
} else if (!validateRunManifestPaths(cwd, runId, cached.manifest, stateRoot, tasksPath)) {
|
|
694
772
|
manifestCache.delete(stateRoot);
|
|
695
773
|
return undefined;
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
774
|
+
} else if (!fs.existsSync(tasksPath)) {
|
|
775
|
+
// Tasks file was deleted after cache was populated — do not serve stale cache.
|
|
776
|
+
manifestCache.delete(stateRoot);
|
|
777
|
+
return undefined;
|
|
700
778
|
} else {
|
|
701
779
|
return { manifest: cached.manifest, tasks: cached.tasks ?? [] };
|
|
702
780
|
}
|
|
@@ -714,8 +792,11 @@ export async function loadRunManifestByIdAsync(cwd: string, runId: string): Prom
|
|
|
714
792
|
const freshTasksStat = await fs.promises.stat(tasksPath).catch(() => undefined);
|
|
715
793
|
tasks = (await readJsonFileAsync<TeamTaskState[]>(tasksPath)) ?? [];
|
|
716
794
|
// If size/mtime didn't change between stat and read, we're consistent.
|
|
717
|
-
if (
|
|
718
|
-
|
|
795
|
+
if (
|
|
796
|
+
freshStat.mtimeMs === manifestStat.mtimeMs &&
|
|
797
|
+
freshStat.size === manifestStat.size &&
|
|
798
|
+
(!freshTasksStat || (freshTasksStat.mtimeMs === tasksStat?.mtimeMs && freshTasksStat.size === tasksStat?.size))
|
|
799
|
+
) {
|
|
719
800
|
break;
|
|
720
801
|
}
|
|
721
802
|
attempts += 1;
|
|
@@ -730,7 +811,9 @@ export async function loadRunManifestByIdAsync(cwd: string, runId: string): Prom
|
|
|
730
811
|
// Round 19: downgrade to debug — retry-loop instability is expected under
|
|
731
812
|
// concurrent writes (live team runs constantly append to tasks.json).
|
|
732
813
|
// This is best-effort by design; strict consistency requires withRunLock().
|
|
733
|
-
console.debug(
|
|
814
|
+
console.debug(
|
|
815
|
+
`[state-store] loadRunManifestByIdAsync: retry loop detected instability for run ${runId} after ${attempts} attempt(s) — best-effort only, use withRunLock() for strict consistency`,
|
|
816
|
+
);
|
|
734
817
|
}
|
|
735
818
|
// NOTE: manifest mtime may legitimately be >= tasks mtime because
|
|
736
819
|
// saveManifestAndTasksAtomicSync writes manifest before tasks. However,
|
|
@@ -742,6 +825,13 @@ export async function loadRunManifestByIdAsync(cwd: string, runId: string): Prom
|
|
|
742
825
|
// It does not indicate corruption on its own.
|
|
743
826
|
|
|
744
827
|
if (!manifest || !validateRunManifestPaths(cwd, runId, manifest, stateRoot, tasksPath)) return undefined;
|
|
745
|
-
setManifestCache(stateRoot, {
|
|
828
|
+
setManifestCache(stateRoot, {
|
|
829
|
+
manifest,
|
|
830
|
+
tasks: tasks ?? [],
|
|
831
|
+
manifestMtimeMs: manifestStat.mtimeMs,
|
|
832
|
+
manifestSize: manifestStat.size,
|
|
833
|
+
tasksMtimeMs,
|
|
834
|
+
tasksSize: tasksStat?.size ?? 0,
|
|
835
|
+
});
|
|
746
836
|
return { manifest, tasks: tasks ?? [] };
|
|
747
837
|
}
|
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
|