pi-crew 0.9.16 → 0.9.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +81 -0
- package/README.md +19 -0
- package/dist/build-meta.json +21790 -0
- package/dist/index.mjs +83070 -0
- package/dist/index.mjs.map +7 -0
- package/docs/A +358 -0
- package/docs/M-A +357 -0
- package/docs/REVIEW-FINDINGS-2026-06 +357 -0
- package/docs/Y +357 -0
- package/docs/a +357 -0
- package/docs/aA +358 -0
- package/docs/archive/README.md +91 -0
- package/docs/patterns/command-agent-skill.md +1 -1
- package/docs/skills/REFERENCE.md +0 -17
- package/docs//303/242mmaAAA/303/242 +357 -0
- package/index.bundle.ts +25 -0
- package/index.ts +95 -4
- package/package.json +15 -4
- package/skills/iterative-audit/SKILL.md +0 -1
- package/skills/widget-rendering/SKILL.md +17 -0
- package/src/adapters/claude-adapter.ts +1 -3
- package/src/adapters/export-util.ts +16 -16
- package/src/adapters/index.ts +5 -5
- package/src/agents/agent-config.ts +20 -14
- package/src/agents/agent-serializer.ts +1 -1
- package/src/agents/discover-agents.ts +83 -39
- package/src/benchmark/benchmark-runner.ts +51 -51
- package/src/benchmark/feedback-loop.ts +1 -1
- package/src/config/config.ts +166 -590
- package/src/config/defaults.ts +28 -2
- package/src/config/drift-detector.ts +11 -14
- package/src/config/markers.ts +201 -203
- package/src/config/resilient-parser.ts +14 -6
- package/src/config/role-tools.ts +3 -3
- package/src/config/suggestions.ts +5 -12
- package/src/config/types.ts +9 -25
- package/src/errors.ts +151 -157
- package/src/extension/action-suggestions.ts +54 -9
- package/src/extension/async-notifier.ts +43 -13
- package/src/extension/autonomous-policy.ts +77 -37
- package/src/extension/command-completions.ts +9 -8
- package/src/extension/context-status-injection.ts +14 -12
- package/src/extension/crew-autocomplete.ts +8 -16
- package/src/extension/crew-cleanup.ts +2 -1
- package/src/extension/crew-shortcuts.ts +9 -6
- package/src/extension/cross-extension-rpc.ts +136 -42
- package/src/extension/help.ts +1 -1
- package/src/extension/import-index.ts +10 -5
- package/src/extension/knowledge-injection.ts +88 -15
- package/src/extension/management.ts +89 -349
- package/src/extension/message-renderers.ts +3 -4
- package/src/extension/notification-router.ts +22 -5
- package/src/extension/notification-sink.ts +6 -3
- package/src/extension/pi-api.ts +17 -8
- package/src/extension/plan-orchestrate.ts +8 -27
- package/src/extension/project-init.ts +21 -6
- package/src/extension/register.ts +329 -975
- package/src/extension/registration/artifact-cleanup.ts +9 -4
- package/src/extension/registration/command-utils.ts +5 -1
- package/src/extension/registration/commands.ts +806 -314
- package/src/extension/registration/compaction-guard.ts +15 -15
- package/src/extension/registration/lifecycle.ts +259 -0
- package/src/extension/registration/observability.ts +293 -0
- package/src/extension/registration/subagent-helpers.ts +29 -7
- package/src/extension/registration/subagent-tools.ts +253 -44
- package/src/extension/registration/team-tool.ts +19 -84
- package/src/extension/registration/ui.ts +168 -0
- package/src/extension/registration/viewers.ts +64 -24
- package/src/extension/result-watcher.ts +18 -7
- package/src/extension/run-bundle-schema.ts +21 -6
- package/src/extension/run-export.ts +15 -6
- package/src/extension/run-import.ts +64 -29
- package/src/extension/run-index.ts +28 -9
- package/src/extension/run-maintenance.ts +32 -12
- package/src/extension/session-summary.ts +1 -1
- package/src/extension/team-manager-command.ts +64 -7
- package/src/extension/team-onboard.ts +151 -150
- package/src/extension/team-recommendation.ts +121 -21
- package/src/extension/team-tool/anchor.ts +31 -64
- package/src/extension/team-tool/api.ts +929 -141
- package/src/extension/team-tool/auto-summarize.ts +14 -26
- package/src/extension/team-tool/cache-control.ts +1 -5
- package/src/extension/team-tool/cancel.ts +138 -38
- package/src/extension/team-tool/chain-dispatch.ts +5 -13
- package/src/extension/team-tool/chain-executor.ts +29 -51
- package/src/extension/team-tool/config-patch.ts +1 -1
- package/src/extension/team-tool/context.ts +40 -20
- package/src/extension/team-tool/destructive-gate.ts +10 -5
- package/src/extension/team-tool/doctor.ts +170 -51
- package/src/extension/team-tool/explain.ts +228 -214
- package/src/extension/team-tool/failure-patterns.ts +3 -9
- package/src/extension/team-tool/goal-wrap.ts +71 -29
- package/src/extension/team-tool/goal.ts +185 -35
- package/src/extension/team-tool/handle-schedule.ts +34 -15
- package/src/extension/team-tool/handle-settings.ts +94 -56
- package/src/extension/team-tool/health-monitor.ts +27 -108
- package/src/extension/team-tool/inspect.ts +42 -9
- package/src/extension/team-tool/intent-policy.ts +4 -1
- package/src/extension/team-tool/lifecycle-actions.ts +244 -48
- package/src/extension/team-tool/orchestrate.ts +7 -18
- package/src/extension/team-tool/parallel-dispatch.ts +51 -29
- package/src/extension/team-tool/plan.ts +29 -5
- package/src/extension/team-tool/respond.ts +49 -16
- package/src/extension/team-tool/run-not-found.ts +3 -8
- package/src/extension/team-tool/run.ts +80 -317
- package/src/extension/team-tool/status.ts +135 -43
- package/src/extension/team-tool/workflow-manage.ts +92 -25
- package/src/extension/team-tool-types.ts +8 -1
- package/src/extension/team-tool.ts +142 -551
- package/src/extension/validate-resources.ts +39 -8
- package/src/hooks/registry.ts +66 -17
- package/src/hooks/types.ts +1 -1
- package/src/i18n.ts +25 -11
- package/src/observability/correlation.ts +17 -3
- package/src/observability/event-bus.ts +51 -56
- package/src/observability/event-to-metric.ts +117 -15
- package/src/observability/exporters/otlp-exporter.ts +56 -17
- package/src/observability/exporters/prometheus-exporter.ts +1 -1
- package/src/observability/metric-registry.ts +16 -4
- package/src/observability/metric-retention.ts +8 -2
- package/src/observability/metric-sink.ts +11 -3
- package/src/observability/metrics-primitives.ts +42 -9
- package/src/plugins/plugin-define.ts +2 -2
- package/src/plugins/plugin-registry.ts +25 -25
- package/src/plugins/plugins/index.ts +1 -1
- package/src/plugins/plugins/nextjs.ts +16 -16
- package/src/plugins/plugins/vite.ts +7 -11
- package/src/plugins/plugins/vitest.ts +6 -11
- package/src/runtime/adaptive-plan.ts +225 -40
- package/src/runtime/agent-control.ts +58 -15
- package/src/runtime/agent-memory.ts +15 -9
- package/src/runtime/agent-observability.ts +10 -2
- package/src/runtime/anchor-manager.ts +27 -25
- package/src/runtime/async-marker.ts +7 -1
- package/src/runtime/async-runner.ts +27 -23
- package/src/runtime/auto-summarize.ts +7 -13
- package/src/runtime/background-runner.ts +189 -251
- package/src/runtime/batch-barrier.ts +18 -16
- package/src/runtime/cancellation-token.ts +16 -6
- package/src/runtime/cancellation.ts +46 -8
- package/src/runtime/capability-inventory.ts +6 -4
- package/src/runtime/chain-parser.ts +44 -11
- package/src/runtime/chain-runner.ts +63 -69
- package/src/runtime/checkpoint.ts +12 -56
- package/src/runtime/child-pi.ts +343 -78
- package/src/runtime/coalesce-tasks.ts +268 -0
- package/src/runtime/code-summary.ts +71 -26
- package/src/runtime/compact-stages/index.ts +15 -5
- package/src/runtime/compact-stages/tail-capture-stage.ts +7 -2
- package/src/runtime/compact-stages/truncation-stage.ts +4 -1
- package/src/runtime/compaction-summary.ts +17 -10
- package/src/runtime/completion-guard.ts +33 -16
- package/src/runtime/crash-classification.ts +28 -7
- package/src/runtime/crash-recovery.ts +177 -37
- package/src/runtime/crew-agent-records.ts +145 -47
- package/src/runtime/crew-hooks.ts +9 -24
- package/src/runtime/cross-extension-rpc.ts +25 -23
- package/src/runtime/custom-tools/irc-tool.ts +43 -15
- package/src/runtime/custom-tools/submit-result-tool.ts +16 -5
- package/src/runtime/delivery-coordinator.ts +34 -7
- package/src/runtime/delta-conflict.ts +9 -21
- package/src/runtime/deterministic-ast.ts +1 -1
- package/src/runtime/diagnostic-export.ts +53 -20
- package/src/runtime/direct-run.ts +12 -2
- package/src/runtime/dwf-state-store.ts +1 -1
- package/src/runtime/dynamic-workflow-context.ts +186 -58
- package/src/runtime/dynamic-workflow-runner.ts +42 -20
- package/src/runtime/effectiveness.ts +16 -8
- package/src/runtime/errors/crew-errors.ts +7 -11
- package/src/runtime/event-stream-bridge.ts +9 -3
- package/src/runtime/foreground-control.ts +54 -14
- package/src/runtime/foreground-watchdog.ts +9 -6
- package/src/runtime/goal-achievement.ts +27 -10
- package/src/runtime/goal-evaluator.ts +54 -19
- package/src/runtime/goal-loop-runner.ts +280 -99
- package/src/runtime/goal-state-store.ts +27 -17
- package/src/runtime/green-contract.ts +11 -2
- package/src/runtime/group-join.ts +64 -31
- package/src/runtime/handoff-manager.ts +37 -42
- package/src/runtime/heartbeat-gradient.ts +10 -2
- package/src/runtime/heartbeat-watcher.ts +32 -6
- package/src/runtime/hidden-handoff.ts +12 -30
- package/src/runtime/important-line-classifier.ts +12 -2
- package/src/runtime/iteration-hooks.ts +25 -15
- package/src/runtime/live-agent-control.ts +55 -7
- package/src/runtime/live-agent-manager.ts +130 -27
- package/src/runtime/live-control-realtime.ts +23 -3
- package/src/runtime/live-irc.ts +4 -1
- package/src/runtime/live-session-health.ts +12 -4
- package/src/runtime/live-session-runtime.ts +379 -117
- package/src/runtime/manifest-cache.ts +28 -12
- package/src/runtime/mcp-proxy.ts +8 -16
- package/src/runtime/metric-parser.ts +1 -5
- package/src/runtime/model-fallback.ts +55 -18
- package/src/runtime/model-resolver.ts +2 -6
- package/src/runtime/model-scope.ts +19 -3
- package/src/runtime/notebook-helpers.ts +60 -62
- package/src/runtime/orphan-worker-registry.ts +37 -26
- package/src/runtime/output-validator.ts +18 -3
- package/src/runtime/overflow-recovery.ts +5 -4
- package/src/runtime/parallel-research.ts +29 -5
- package/src/runtime/parallel-utils.ts +9 -11
- package/src/runtime/path-overlap.ts +150 -0
- package/src/runtime/peer-dep.ts +12 -17
- package/src/runtime/per-write-validator.ts +1 -3
- package/src/runtime/phase-tracker.ts +342 -330
- package/src/runtime/pi-args.ts +26 -8
- package/src/runtime/pi-json-output.ts +1 -1
- package/src/runtime/pi-spawn.ts +30 -19
- package/src/runtime/pipeline-runner.ts +56 -55
- package/src/runtime/plan-templates.ts +5 -6
- package/src/runtime/policy-engine.ts +43 -7
- package/src/runtime/post-checks.ts +12 -4
- package/src/runtime/post-exit-stdio-guard.ts +2 -2
- package/src/runtime/process-lifecycle.ts +20 -10
- package/src/runtime/process-status.ts +16 -5
- package/src/runtime/progress-event-coalescer.ts +2 -1
- package/src/runtime/progress-tracker.ts +103 -103
- package/src/runtime/prose-compressor.ts +9 -11
- package/src/runtime/recovery-recipes.ts +118 -24
- package/src/runtime/replace.ts +25 -10
- package/src/runtime/resilient-edit.ts +10 -25
- package/src/runtime/result-extractor.ts +1 -2
- package/src/runtime/retry-executor.ts +20 -4
- package/src/runtime/retry-runner.ts +26 -50
- package/src/runtime/role-permission.ts +6 -1
- package/src/runtime/run-coalesced-task-group.ts +256 -0
- package/src/runtime/run-drift.ts +14 -15
- package/src/runtime/run-tracker.ts +6 -28
- package/src/runtime/runtime-policy.ts +1 -6
- package/src/runtime/runtime-resolver.ts +80 -15
- package/src/runtime/scheduler.ts +47 -18
- package/src/runtime/semaphore.ts +5 -7
- package/src/runtime/sensitive-paths.ts +2 -1
- package/src/runtime/session-usage.ts +1 -1
- package/src/runtime/settings-store.ts +16 -12
- package/src/runtime/sidechain-output.ts +6 -2
- package/src/runtime/single-agent-compose.ts +1 -4
- package/src/runtime/skill-effectiveness.ts +29 -97
- package/src/runtime/skill-instructions.ts +40 -83
- package/src/runtime/stale-reconciler.ts +73 -197
- package/src/runtime/stream-preview.ts +1 -1
- package/src/runtime/streaming-output.ts +1 -1
- package/src/runtime/subagent-manager.ts +44 -169
- package/src/runtime/subprocess-tool-registry.ts +4 -1
- package/src/runtime/supervisor-contact.ts +10 -5
- package/src/runtime/task-display.ts +19 -5
- package/src/runtime/task-graph-scheduler.ts +95 -21
- package/src/runtime/task-graph.ts +5 -11
- package/src/runtime/task-health.ts +54 -47
- package/src/runtime/task-id.ts +11 -18
- package/src/runtime/task-output-context.ts +265 -81
- package/src/runtime/task-packet.ts +12 -20
- package/src/runtime/task-quality.ts +6 -14
- package/src/runtime/task-runner/context-retrieval.ts +4 -13
- package/src/runtime/task-runner/live-executor.ts +114 -36
- package/src/runtime/task-runner/output-splitter.ts +152 -0
- package/src/runtime/task-runner/progress.ts +50 -12
- package/src/runtime/task-runner/prompt-builder.ts +31 -7
- package/src/runtime/task-runner/prompt-pipeline.ts +31 -7
- package/src/runtime/task-runner/result-utils.ts +3 -1
- package/src/runtime/task-runner/retrieval-orchestrator.ts +310 -0
- package/src/runtime/task-runner/run-projection.ts +27 -8
- package/src/runtime/task-runner/state-helpers.ts +29 -8
- package/src/runtime/task-runner/tail-read.ts +2 -6
- package/src/runtime/task-runner.ts +180 -326
- package/src/runtime/team-runner-artifacts.ts +13 -0
- package/src/runtime/team-runner.ts +456 -974
- package/src/runtime/tool-output-pruner.ts +6 -9
- package/src/runtime/tool-progress.ts +11 -21
- package/src/runtime/verification-gates.ts +33 -24
- package/src/runtime/verification-integrity.ts +1 -4
- package/src/runtime/verification-worktree.ts +62 -12
- package/src/runtime/worker-heartbeat.ts +5 -1
- package/src/runtime/worker-startup.ts +29 -5
- package/src/runtime/workflow-state.ts +17 -9
- package/src/runtime/workspace-lock.ts +30 -35
- package/src/runtime/workspace-tree.ts +20 -32
- package/src/runtime/yield-handler.ts +43 -9
- package/src/runtime/zombie-scanner.ts +5 -4
- package/src/schema/config-schema.ts +266 -172
- package/src/schema/team-tool-schema.ts +29 -74
- package/src/schema/validation-types.ts +25 -17
- package/src/skills/discover-skills.ts +35 -10
- package/src/skills/skill-templates.ts +109 -27
- package/src/skills/validate.ts +26 -8
- package/src/state/active-run-registry.ts +87 -28
- package/src/state/artifact-store.ts +9 -5
- package/src/state/atomic-write-v2.ts +85 -63
- package/src/state/atomic-write.ts +105 -26
- package/src/state/blob-store.ts +47 -20
- package/src/state/contracts.ts +20 -5
- package/src/state/crew-init.ts +5 -22
- package/src/state/decision-ledger.ts +19 -73
- package/src/state/event-log-rotation.ts +41 -15
- package/src/state/event-log.ts +168 -53
- package/src/state/event-reconstructor.ts +11 -1
- package/src/state/gitignore-manager.ts +2 -8
- package/src/state/health-store.ts +57 -57
- package/src/state/hook-instinct-bridge.ts +1 -1
- package/src/state/hook-integrations.ts +1 -1
- package/src/state/instinct-store.ts +17 -5
- package/src/state/jsonl-writer.ts +1 -1
- package/src/state/locks.ts +23 -9
- package/src/state/mailbox.ts +151 -28
- package/src/state/observation-store.ts +20 -14
- package/src/state/run-cache.ts +142 -135
- package/src/state/run-graph.ts +6 -15
- package/src/state/run-metrics.ts +5 -18
- package/src/state/schedule.ts +15 -9
- package/src/state/state-store.ts +129 -45
- package/src/state/task-claims.ts +12 -2
- package/src/state/tiered-eval.ts +52 -43
- package/src/state/types-eval.ts +2 -2
- package/src/state/types.ts +24 -20
- package/src/state/usage.ts +20 -4
- package/src/state/worker-atomic-writer.ts +6 -3
- package/src/subagents/index.ts +2 -2
- package/src/teams/discover-teams.ts +21 -6
- package/src/tools/safe-bash-extension.ts +5 -6
- package/src/tools/safe-bash.ts +10 -11
- package/src/types/new-api-types.ts +6 -10
- package/src/ui/agent-management-overlay.ts +52 -40
- package/src/ui/card-colors.ts +13 -4
- package/src/ui/crew-footer.ts +8 -7
- package/src/ui/crew-select-list.ts +1 -1
- package/src/ui/dashboard-panes/agents-pane.ts +41 -25
- package/src/ui/dashboard-panes/cancellation-pane.ts +1 -1
- package/src/ui/dashboard-panes/capability-pane.ts +32 -15
- package/src/ui/dashboard-panes/health-pane.ts +2 -1
- package/src/ui/dashboard-panes/metrics-pane.ts +4 -1
- package/src/ui/dashboard-panes/progress-pane.ts +12 -9
- package/src/ui/heartbeat-aggregator.ts +15 -4
- package/src/ui/keybinding-map.ts +40 -7
- package/src/ui/live-conversation-overlay.ts +36 -20
- package/src/ui/live-duration.ts +1 -4
- package/src/ui/live-run-sidebar.ts +88 -25
- package/src/ui/loaders.ts +2 -8
- package/src/ui/mascot.ts +20 -36
- package/src/ui/overlays/agent-picker-overlay.ts +11 -3
- package/src/ui/overlays/confirm-overlay.ts +4 -2
- package/src/ui/overlays/help-overlay.ts +25 -14
- package/src/ui/overlays/mailbox-compose-overlay.ts +48 -11
- package/src/ui/overlays/mailbox-compose-preview.ts +20 -5
- package/src/ui/overlays/mailbox-detail-overlay.ts +27 -6
- package/src/ui/pi-ui-compat.ts +7 -7
- package/src/ui/powerbar-publisher.ts +120 -42
- package/src/ui/render-diff.ts +10 -3
- package/src/ui/render-scheduler.ts +12 -4
- package/src/ui/run-action-dispatcher.ts +81 -18
- package/src/ui/run-dashboard.ts +172 -76
- package/src/ui/run-event-bus.ts +59 -37
- package/src/ui/run-snapshot-cache.ts +276 -86
- package/src/ui/settings-overlay.ts +361 -74
- package/src/ui/status-colors.ts +12 -1
- package/src/ui/syntax-highlight.ts +1 -1
- package/src/ui/theme-adapter.ts +16 -14
- package/src/ui/theme-discovery.ts +13 -2
- package/src/ui/tool-progress-formatter.ts +7 -7
- package/src/ui/tool-render.ts +128 -56
- package/src/ui/tool-renderers/brief-mode.ts +45 -27
- package/src/ui/tool-renderers/index.ts +109 -43
- package/src/ui/transcript-cache.ts +32 -6
- package/src/ui/transcript-entries.ts +25 -23
- package/src/ui/transcript-viewer.ts +78 -29
- package/src/ui/widget/index.ts +99 -40
- package/src/ui/widget/widget-formatters.ts +13 -6
- package/src/ui/widget/widget-model.ts +19 -8
- package/src/ui/widget/widget-renderer.ts +23 -13
- package/src/ui/widget/widget-types.ts +1 -1
- package/src/utils/bm25-search.ts +199 -199
- package/src/utils/conflict-detect.ts +22 -21
- package/src/utils/env-filter.ts +14 -7
- package/src/utils/file-coalescer.ts +5 -1
- package/src/utils/fingerprint.ts +3 -6
- package/src/utils/frontmatter.ts +3 -1
- package/src/utils/fs-watch.ts +2 -6
- package/src/utils/gh-protocol.ts +119 -44
- package/src/utils/git.ts +13 -15
- package/src/utils/guards.ts +2 -5
- package/src/utils/ids.ts +9 -2
- package/src/utils/incremental-reader.ts +14 -3
- package/src/utils/internal-error.ts +2 -1
- package/src/utils/names.ts +12 -3
- package/src/utils/paths.ts +49 -5
- package/src/utils/project-detector.ts +2 -2
- package/src/utils/redaction.ts +29 -19
- package/src/utils/resolve-shell.ts +9 -7
- package/src/utils/run-watcher-registry.ts +19 -31
- package/src/utils/safe-paths.ts +45 -24
- package/src/utils/scan-cache.ts +9 -2
- package/src/utils/session-utils.ts +2 -4
- package/src/utils/sleep.ts +12 -5
- package/src/utils/sse-parser.ts +5 -17
- package/src/utils/visual.ts +52 -32
- package/src/workflows/discover-workflows.ts +41 -109
- package/src/workflows/intermediate-store.ts +5 -21
- package/src/workflows/preflight-validator.ts +6 -33
- package/src/workflows/topology-analyzer.ts +5 -21
- package/src/workflows/workflow-config.ts +7 -6
- package/src/worktree/branch-freshness.ts +66 -8
- package/src/worktree/cleanup.ts +130 -20
- package/src/worktree/worktree-manager.ts +212 -69
- package/skills/artifact-analysis-loop/SKILL.md +0 -303
- package/skills/detection-pipeline-design/SKILL.md +0 -286
- package/skills/hunting-investigation-loop/SKILL.md +0 -402
- package/skills/incident-playbook-construction/SKILL.md +0 -384
- package/skills/security-review/SKILL.md +0 -561
- package/skills/threat-hypothesis-framework/SKILL.md +0 -176
- package/skills/ui-render-performance/SKILL.md +0 -58
- /package/docs/{followup-review-round3-2026-05-12.md → archive/followup-review-round3-2026-05-12.md} +0 -0
- /package/docs/{followup-review-round4-2026-05-13.md → archive/followup-review-round4-2026-05-13.md} +0 -0
- /package/docs/{pi-crew-bugs.md → archive/pi-crew-bugs.md} +0 -0
- /package/docs/{pi-crew-test-final.md → archive/pi-crew-test-final.md} +0 -0
- /package/docs/{pi-crew-test-results.md → archive/pi-crew-test-results.md} +0 -0
- /package/docs/{pi-crew-test-round2.md → archive/pi-crew-test-round2.md} +0 -0
- /package/docs/{pi-crew-test-round4.md → archive/pi-crew-test-round4.md} +0 -0
- /package/docs/{pi-crew-test-round5.md → archive/pi-crew-test-round5.md} +0 -0
- /package/docs/{pi-crew-test-round6.md → archive/pi-crew-test-round6.md} +0 -0
- /package/docs/{pi-crew-v0.5.10-audit-fix-plan.md → archive/pi-crew-v0.5.10-audit-fix-plan.md} +0 -0
- /package/docs/{pi-crew-v0.5.11-audit-fix-plan.md → archive/pi-crew-v0.5.11-audit-fix-plan.md} +0 -0
- /package/docs/{pi-crew-v0.5.12-audit-fix-plan.md → archive/pi-crew-v0.5.12-audit-fix-plan.md} +0 -0
- /package/docs/{pi-crew-v0.5.13-audit-fix-plan.md → archive/pi-crew-v0.5.13-audit-fix-plan.md} +0 -0
- /package/docs/{pi-crew-v0.5.14-audit-fix-plan.md → archive/pi-crew-v0.5.14-audit-fix-plan.md} +0 -0
- /package/docs/{pi-crew-v0.5.16-audit-fix-plan.md → archive/pi-crew-v0.5.16-audit-fix-plan.md} +0 -0
- /package/docs/{pi-crew-v0.5.17-audit-fix-plan.md → archive/pi-crew-v0.5.17-audit-fix-plan.md} +0 -0
- /package/docs/{pi-crew-v0.5.5-audit-fix-plan.md → archive/pi-crew-v0.5.5-audit-fix-plan.md} +0 -0
- /package/docs/{pi-crew-v0.5.9-audit-fix-plan.md → archive/pi-crew-v0.5.9-audit-fix-plan.md} +0 -0
- /package/docs/{pi-mono-opportunities.md → archive/pi-mono-opportunities.md} +0 -0
- /package/docs/{pi-mono-review.md → archive/pi-mono-review.md} +0 -0
- /package/docs/{pi-subagent4-comparison.md → archive/pi-subagent4-comparison.md} +0 -0
- /package/docs/{pi-subagents3-deep-analysis.md → archive/pi-subagents3-deep-analysis.md} +0 -0
|
@@ -17,26 +17,22 @@
|
|
|
17
17
|
* nonce-token feedback, worker cap, workspace lock) all apply.
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
-
import {
|
|
20
|
+
import { loadConfig } from "../../config/config.ts";
|
|
21
|
+
import type { GoalWrapWorkflowConfig } from "../../config/types.ts";
|
|
22
|
+
import { GoalStore } from "../../runtime/goal-state-store.ts";
|
|
23
|
+
import { snapshotManifests } from "../../runtime/verification-integrity.ts";
|
|
24
|
+
import type { TeamToolParamsValue } from "../../schema/team-tool-schema.ts";
|
|
21
25
|
import { atomicWriteJson } from "../../state/atomic-write.ts";
|
|
22
26
|
import { appendEvent } from "../../state/event-log.ts";
|
|
27
|
+
import { createRunPaths, saveRunManifest } from "../../state/state-store.ts";
|
|
28
|
+
import type { GoalLoopState, TeamRunManifest } from "../../state/types.ts";
|
|
23
29
|
import { spawnBackgroundTeamRun } from "../../subagents/async-entry.ts";
|
|
24
|
-
import { GoalStore } from "../../runtime/goal-state-store.ts";
|
|
25
|
-
import { snapshotManifests } from "../../runtime/verification-integrity.ts";
|
|
26
30
|
import { logInternalError } from "../../utils/internal-error.ts";
|
|
27
|
-
import { loadConfig } from "../../config/config.ts";
|
|
28
|
-
import type { GoalLoopState, TeamRunManifest } from "../../state/types.ts";
|
|
29
|
-
import type { GoalWrapWorkflowConfig } from "../../config/types.ts";
|
|
30
|
-
import type { TeamToolParamsValue } from "../../schema/team-tool-schema.ts";
|
|
31
31
|
import type { WorkflowConfig } from "../../workflows/workflow-config.ts";
|
|
32
32
|
import { result, type TeamContext } from "./context.ts";
|
|
33
33
|
|
|
34
34
|
/** Builtin workflows eligible for goal-wrap (have a clear "done" condition). */
|
|
35
|
-
export const GOAL_WRAP_ELIGIBLE_BUILTINS = new Set([
|
|
36
|
-
"implementation",
|
|
37
|
-
"fast-fix",
|
|
38
|
-
"default",
|
|
39
|
-
]);
|
|
35
|
+
export const GOAL_WRAP_ELIGIBLE_BUILTINS = new Set(["implementation", "fast-fix", "default"]);
|
|
40
36
|
|
|
41
37
|
/**
|
|
42
38
|
* Maximum number of workflow steps allowed for goal-wrap.
|
|
@@ -63,10 +59,7 @@ export const GOAL_WRAP_MAX_STEPS = 1;
|
|
|
63
59
|
export type { GoalWrapWorkflowConfig };
|
|
64
60
|
|
|
65
61
|
/** Read the goal-wrap config for a given workflow name (merged user + project config). */
|
|
66
|
-
export function readGoalWrapConfig(
|
|
67
|
-
cwd: string,
|
|
68
|
-
workflowName: string,
|
|
69
|
-
): GoalWrapWorkflowConfig | undefined {
|
|
62
|
+
export function readGoalWrapConfig(cwd: string, workflowName: string): GoalWrapWorkflowConfig | undefined {
|
|
70
63
|
const loaded = loadConfig(cwd);
|
|
71
64
|
const cfg = loaded.config?.goalWrap as Record<string, GoalWrapWorkflowConfig> | undefined;
|
|
72
65
|
if (!cfg) return undefined;
|
|
@@ -84,9 +77,7 @@ export function isGoalWrapEnabled(cwd: string, workflowName: string): boolean {
|
|
|
84
77
|
* Validate a goal-wrap config entry. Returns an error string if invalid, undefined if OK.
|
|
85
78
|
* Mirrors the Phase 1 validation: budget required (or unlimited), evaluatorModel required.
|
|
86
79
|
*/
|
|
87
|
-
export function validateGoalWrapConfig(
|
|
88
|
-
wc: GoalWrapWorkflowConfig,
|
|
89
|
-
): string | undefined {
|
|
80
|
+
export function validateGoalWrapConfig(wc: GoalWrapWorkflowConfig): string | undefined {
|
|
90
81
|
if (!wc.evaluatorModel) {
|
|
91
82
|
return "goalWrap config requires evaluatorModel (the goal-judge model). No silent default.";
|
|
92
83
|
}
|
|
@@ -125,7 +116,11 @@ export function persistAsyncOnGoalLoopManifest(
|
|
|
125
116
|
): void {
|
|
126
117
|
const asyncGoalManifest = {
|
|
127
118
|
...manifest,
|
|
128
|
-
async: {
|
|
119
|
+
async: {
|
|
120
|
+
pid: spawned.pid,
|
|
121
|
+
logPath: spawned.logPath,
|
|
122
|
+
spawnedAt: new Date().toISOString(),
|
|
123
|
+
},
|
|
129
124
|
};
|
|
130
125
|
atomicWriteJson(manifestPath, asyncGoalManifest);
|
|
131
126
|
}
|
|
@@ -146,14 +141,27 @@ export function persistAsyncOnGoalLoopManifest(
|
|
|
146
141
|
* goal-wrap is unsafe for a given workflow, silently fall back so the user
|
|
147
142
|
* still gets the workflow run they asked for.
|
|
148
143
|
*/
|
|
149
|
-
export function shouldGoalWrap(
|
|
144
|
+
export function shouldGoalWrap(
|
|
145
|
+
cwd: string,
|
|
146
|
+
workflow: WorkflowConfig,
|
|
147
|
+
):
|
|
148
|
+
| { enabled: true }
|
|
149
|
+
| {
|
|
150
|
+
enabled: false;
|
|
151
|
+
reason: "config-off" | "multi-step" | "invalid-config";
|
|
152
|
+
message?: string;
|
|
153
|
+
} {
|
|
150
154
|
const wc = readGoalWrapConfig(cwd, workflow.name);
|
|
151
155
|
if (!wc || wc.enabled !== true) {
|
|
152
156
|
return { enabled: false, reason: "config-off" };
|
|
153
157
|
}
|
|
154
158
|
const validationError = validateGoalWrapConfig(wc);
|
|
155
159
|
if (validationError) {
|
|
156
|
-
return {
|
|
160
|
+
return {
|
|
161
|
+
enabled: false,
|
|
162
|
+
reason: "invalid-config",
|
|
163
|
+
message: validationError,
|
|
164
|
+
};
|
|
157
165
|
}
|
|
158
166
|
if (workflow.steps.length > GOAL_WRAP_MAX_STEPS) {
|
|
159
167
|
return {
|
|
@@ -174,7 +182,11 @@ export async function startGoalWrappedRun(
|
|
|
174
182
|
const cwd = ctx.cwd;
|
|
175
183
|
const wc = readGoalWrapConfig(cwd, workflow.name);
|
|
176
184
|
if (!wc || wc.enabled !== true) {
|
|
177
|
-
return result(
|
|
185
|
+
return result(
|
|
186
|
+
`goal-wrap is not enabled for workflow '${workflow.name}' in .crew/config.json.`,
|
|
187
|
+
{ action: "run", status: "error" },
|
|
188
|
+
true,
|
|
189
|
+
);
|
|
178
190
|
}
|
|
179
191
|
const validationError = validateGoalWrapConfig(wc);
|
|
180
192
|
if (validationError) {
|
|
@@ -196,7 +208,10 @@ export async function startGoalWrappedRun(
|
|
|
196
208
|
verificationIntegrity = "none-text-only";
|
|
197
209
|
} else {
|
|
198
210
|
try {
|
|
199
|
-
verificationIntegrity = {
|
|
211
|
+
verificationIntegrity = {
|
|
212
|
+
snapshot: snapshotManifests(cwd),
|
|
213
|
+
takenAt: now,
|
|
214
|
+
};
|
|
200
215
|
} catch (error) {
|
|
201
216
|
logInternalError("goal-wrap.integritySnapshot", error, `goalId=${goalId}`);
|
|
202
217
|
verificationIntegrity = "none-text-only";
|
|
@@ -254,7 +269,16 @@ export async function startGoalWrappedRun(
|
|
|
254
269
|
runKind: "goal-loop",
|
|
255
270
|
};
|
|
256
271
|
saveRunManifest(goalLoopManifest);
|
|
257
|
-
appendEvent(paths.eventsPath, {
|
|
272
|
+
appendEvent(paths.eventsPath, {
|
|
273
|
+
type: "goal.loop_start",
|
|
274
|
+
runId: goalId,
|
|
275
|
+
data: {
|
|
276
|
+
goalId,
|
|
277
|
+
objective: goal,
|
|
278
|
+
maxTurns,
|
|
279
|
+
goalWrapWorkflow: workflow.name,
|
|
280
|
+
},
|
|
281
|
+
});
|
|
258
282
|
|
|
259
283
|
const spawned = await spawnBackgroundTeamRun(goalLoopManifest);
|
|
260
284
|
const pid = spawned.pid ?? 0;
|
|
@@ -264,8 +288,18 @@ export async function startGoalWrappedRun(
|
|
|
264
288
|
// background runner dies (it currently dies silently due to a multi-step
|
|
265
289
|
// atomic-write bug — see investigation report). Mirrors run.ts:371-372 which
|
|
266
290
|
// writes asyncManifest = { ...effectiveManifest, async: {...} } to manifestPath.
|
|
267
|
-
persistAsyncOnGoalLoopManifest(paths.manifestPath, goalLoopManifest, {
|
|
268
|
-
|
|
291
|
+
persistAsyncOnGoalLoopManifest(paths.manifestPath, goalLoopManifest, {
|
|
292
|
+
pid,
|
|
293
|
+
logPath: spawned.logPath,
|
|
294
|
+
});
|
|
295
|
+
const withAsync = {
|
|
296
|
+
...goalState,
|
|
297
|
+
async: {
|
|
298
|
+
pid,
|
|
299
|
+
logPath: spawned.logPath,
|
|
300
|
+
spawnedAt: new Date().toISOString(),
|
|
301
|
+
},
|
|
302
|
+
};
|
|
269
303
|
store.save(withAsync);
|
|
270
304
|
|
|
271
305
|
return result(
|
|
@@ -273,12 +307,20 @@ export async function startGoalWrappedRun(
|
|
|
273
307
|
`Goal-wrapped '${workflow.name}' started (background pid=${pid}).`,
|
|
274
308
|
`Goal ${goalId} [running] — worker = '${workflow.name}' workflow, judged each turn by ${wc.evaluatorModel}.`,
|
|
275
309
|
` turn: 0/${maxTurns} budget: ${wc.budgetUnlimited ? "∞ (unlimited)" : `${wc.budgetTotal}`}`,
|
|
276
|
-
verification?.commands?.length
|
|
310
|
+
verification?.commands?.length
|
|
311
|
+
? ` verification: ${verification.commands.join(", ")}`
|
|
312
|
+
: " verification: text-only (no objective oracle)",
|
|
277
313
|
``,
|
|
278
314
|
`Next: \`team action='goal' config.subAction='status' config.goalId='${goalId}'\`.`,
|
|
279
315
|
`Log: ${spawned.logPath}`,
|
|
280
316
|
].join("\n"),
|
|
281
|
-
{
|
|
317
|
+
{
|
|
318
|
+
action: "run",
|
|
319
|
+
status: "ok",
|
|
320
|
+
runId: goalId,
|
|
321
|
+
artifactsRoot: paths.artifactsRoot,
|
|
322
|
+
data: { goalId, goalWrap: true, workflow: workflow.name, pid },
|
|
323
|
+
},
|
|
282
324
|
false,
|
|
283
325
|
);
|
|
284
326
|
} catch (error) {
|
|
@@ -14,16 +14,16 @@
|
|
|
14
14
|
* §0c C11 (control path: cooperative flag + handleCancel(currentRunId) via abortOwned).
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import { result, type TeamContext } from "./context.ts";
|
|
18
|
-
import { createRunPaths, saveRunManifest } from "../../state/state-store.ts";
|
|
19
|
-
import { appendEvent } from "../../state/event-log.ts";
|
|
20
|
-
import { spawnBackgroundTeamRun } from "../../subagents/async-entry.ts";
|
|
21
17
|
import { GoalStore } from "../../runtime/goal-state-store.ts";
|
|
22
|
-
import { logInternalError } from "../../utils/internal-error.ts";
|
|
23
18
|
import { snapshotManifests } from "../../runtime/verification-integrity.ts";
|
|
24
19
|
import { acquireWorkspaceLock, isWorkspaceBusy, type WorkspaceLockHandle } from "../../runtime/workspace-lock.ts";
|
|
25
|
-
import type { GoalLoopState, GoalLoopStatus, TeamRunManifest } from "../../state/types.ts";
|
|
26
20
|
import type { TeamToolParamsValue } from "../../schema/team-tool-schema.ts";
|
|
21
|
+
import { appendEvent } from "../../state/event-log.ts";
|
|
22
|
+
import { createRunPaths, saveRunManifest } from "../../state/state-store.ts";
|
|
23
|
+
import type { GoalLoopState, GoalLoopStatus, TeamRunManifest } from "../../state/types.ts";
|
|
24
|
+
import { spawnBackgroundTeamRun } from "../../subagents/async-entry.ts";
|
|
25
|
+
import { logInternalError } from "../../utils/internal-error.ts";
|
|
26
|
+
import { result, type TeamContext } from "./context.ts";
|
|
27
27
|
|
|
28
28
|
const MAX_GOAL_OBJECTIVE_CHARS = 4000;
|
|
29
29
|
|
|
@@ -63,10 +63,14 @@ function formatGoalStatus(goal: GoalLoopState): string {
|
|
|
63
63
|
` objective: ${goal.objective.slice(0, 200)}${goal.objective.length > 200 ? "…" : ""}`,
|
|
64
64
|
` turn: ${goal.turnsUsed}/${goal.maxTurns} budget: ${goal.budgetUsed}/${goal.budgetTotal ?? "∞"} (${budgetPct})`,
|
|
65
65
|
` evaluator: ${goal.evaluatorModel} worker: ${goal.workerAgent ?? "executor"}`,
|
|
66
|
-
last
|
|
66
|
+
last
|
|
67
|
+
? ` last verdict (turn ${last.turn}): ${last.achieved ? "ACHIEVED" : "not-achieved"} — ${last.reason.slice(0, 300)}`
|
|
68
|
+
: " (no verdicts yet)",
|
|
67
69
|
goal.nextTurnFeedback ? ` next-turn feedback: ${goal.nextTurnFeedback.slice(0, 200)}` : "",
|
|
68
70
|
goal.currentRunId ? ` current turn runId: ${goal.currentRunId}` : "",
|
|
69
|
-
]
|
|
71
|
+
]
|
|
72
|
+
.filter(Boolean)
|
|
73
|
+
.join("\n");
|
|
70
74
|
}
|
|
71
75
|
|
|
72
76
|
/** `goal start` — create state + spawn background process (P0: writes state; spawn wiring TBD per host). */
|
|
@@ -79,16 +83,16 @@ async function handleStart(input: GoalSubActionInput): Promise<ReturnType<typeof
|
|
|
79
83
|
const goalId = store.createGoalId();
|
|
80
84
|
const ownerSessionId = ctx.sessionId ?? "unknown";
|
|
81
85
|
const now = new Date().toISOString();
|
|
82
|
-
const maxTurns = typeof params.config?.maxTurns === "number" && params.config.maxTurns > 0
|
|
83
|
-
? params.config.maxTurns
|
|
84
|
-
: 20; // Claude/Codex parity default
|
|
86
|
+
const maxTurns = typeof params.config?.maxTurns === "number" && params.config.maxTurns > 0 ? params.config.maxTurns : 20; // Claude/Codex parity default
|
|
85
87
|
// P1d (RFC v0.5 §P1d): budget is REQUIRED. Either an explicit budgetTotal (>=1000, enforced
|
|
86
88
|
// by schema) OR an explicit budgetUnlimited:true opt-out (audit-logged). No silent unbounded
|
|
87
89
|
// default — without a cap the loop could spend unboundedly across many turns × workers.
|
|
88
90
|
const budgetUnlimited = params.config?.budgetUnlimited === true;
|
|
89
91
|
const hasBudgetTotal = typeof params.budgetTotal === "number" && params.budgetTotal >= 1000;
|
|
90
92
|
if (!budgetUnlimited && !hasBudgetTotal) {
|
|
91
|
-
throw new Error(
|
|
93
|
+
throw new Error(
|
|
94
|
+
"`goal start` requires either config.budgetTotal (>=1000, schema-enforced) OR config.budgetUnlimited:true (audit-logged opt-out). No silent unbounded-spend default.",
|
|
95
|
+
);
|
|
92
96
|
}
|
|
93
97
|
// Cold-review #2 nit: reject the mutually-exclusive combination. If both are set the
|
|
94
98
|
// runner silently lets budgetUnlimited win, surprising the user.
|
|
@@ -101,9 +105,17 @@ async function handleStart(input: GoalSubActionInput): Promise<ReturnType<typeof
|
|
|
101
105
|
// acquiring. The authoritative acquisition happens in runGoalLoop.
|
|
102
106
|
const busyOwner = isWorkspaceBusy(cwd);
|
|
103
107
|
if (busyOwner) {
|
|
104
|
-
throw new Error(
|
|
108
|
+
throw new Error(
|
|
109
|
+
`Workspace '${cwd}' is already locked by goal '${busyOwner}'. Concurrent goals on the same single-workspace cwd are serialized to prevent edit clobbering. Stop the other goal first, or use a separate workspace.`,
|
|
110
|
+
);
|
|
105
111
|
}
|
|
106
|
-
const verification = params.config?.verification as
|
|
112
|
+
const verification = params.config?.verification as
|
|
113
|
+
| {
|
|
114
|
+
commands: string[];
|
|
115
|
+
allowManualEvidence?: boolean;
|
|
116
|
+
mode?: string;
|
|
117
|
+
}
|
|
118
|
+
| undefined;
|
|
107
119
|
const isTextOnly = verification?.mode === "text-only";
|
|
108
120
|
// P1a (RFC v0.5 §P1a): take manifest-integrity snapshot at start IF verification.commands
|
|
109
121
|
// declared. For text-only mode (no objective oracle), mark "none-text-only" explicitly so
|
|
@@ -180,22 +192,46 @@ async function handleStart(input: GoalSubActionInput): Promise<ReturnType<typeof
|
|
|
180
192
|
runKind: "goal-loop",
|
|
181
193
|
};
|
|
182
194
|
saveRunManifest(goalLoopManifest);
|
|
183
|
-
appendEvent(paths.eventsPath, {
|
|
195
|
+
appendEvent(paths.eventsPath, {
|
|
196
|
+
type: "goal.loop_start",
|
|
197
|
+
runId: goalId,
|
|
198
|
+
data: {
|
|
199
|
+
goalId,
|
|
200
|
+
objective,
|
|
201
|
+
maxTurns,
|
|
202
|
+
statePath: `${cwd}/.crew/state/goals/${goalId}.json`,
|
|
203
|
+
},
|
|
204
|
+
});
|
|
184
205
|
|
|
185
206
|
try {
|
|
186
207
|
const spawned = await spawnBackgroundTeamRun(goalLoopManifest);
|
|
187
208
|
const pid = spawned.pid ?? 0;
|
|
188
|
-
const withAsync = {
|
|
209
|
+
const withAsync = {
|
|
210
|
+
...goalState,
|
|
211
|
+
async: {
|
|
212
|
+
pid,
|
|
213
|
+
logPath: spawned.logPath,
|
|
214
|
+
spawnedAt: new Date().toISOString(),
|
|
215
|
+
},
|
|
216
|
+
};
|
|
189
217
|
store.save(withAsync);
|
|
190
218
|
return result(
|
|
191
219
|
`Goal loop started (background pid=${pid}).\n${formatGoalStatus(withAsync)}\n\nNext: \`team action='goal' config.subAction='status' config.goalId='${goalId}'\`. The loop runs up to ${maxTurns} turns, judging each against the objective. Log: ${spawned.logPath}`,
|
|
192
|
-
{
|
|
220
|
+
{
|
|
221
|
+
action: "goal",
|
|
222
|
+
status: "ok",
|
|
223
|
+
data: { goalId, state: goalState.state, maxTurns, pid },
|
|
224
|
+
},
|
|
193
225
|
false,
|
|
194
226
|
);
|
|
195
227
|
} catch (spawnError) {
|
|
196
228
|
const message = spawnError instanceof Error ? spawnError.message : String(spawnError);
|
|
197
229
|
store.setStatus(goalId, "blocked", paths.eventsPath);
|
|
198
|
-
return result(
|
|
230
|
+
return result(
|
|
231
|
+
`goal start: state saved but background spawn failed: ${message}`,
|
|
232
|
+
{ action: "goal", status: "error", data: { goalId } },
|
|
233
|
+
true,
|
|
234
|
+
);
|
|
199
235
|
}
|
|
200
236
|
} catch (error) {
|
|
201
237
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -210,11 +246,28 @@ function handleStatus(input: GoalSubActionInput): ReturnType<typeof result> {
|
|
|
210
246
|
if (goalId) {
|
|
211
247
|
const goal = store.load(goalId);
|
|
212
248
|
if (!goal) return result(`Goal '${goalId}' not found.`, { action: "goal", status: "error" }, true);
|
|
213
|
-
return result(
|
|
249
|
+
return result(
|
|
250
|
+
formatGoalStatus(goal),
|
|
251
|
+
{
|
|
252
|
+
action: "goal",
|
|
253
|
+
status: "ok",
|
|
254
|
+
data: { goalId, state: goal.state, turnsUsed: goal.turnsUsed },
|
|
255
|
+
},
|
|
256
|
+
false,
|
|
257
|
+
);
|
|
214
258
|
}
|
|
215
259
|
const goals = store.list();
|
|
216
|
-
if (goals.length === 0)
|
|
217
|
-
|
|
260
|
+
if (goals.length === 0)
|
|
261
|
+
return result(
|
|
262
|
+
"No goals found. Start one with `team action='goal' config.subAction='start' config.objective='...' config.evaluatorModel='...'`.",
|
|
263
|
+
{ action: "goal", status: "ok" },
|
|
264
|
+
false,
|
|
265
|
+
);
|
|
266
|
+
return result(
|
|
267
|
+
`Goals (${goals.length}):\n\n${goals.map(formatGoalStatus).join("\n\n")}`,
|
|
268
|
+
{ action: "goal", status: "ok", data: { count: goals.length } },
|
|
269
|
+
false,
|
|
270
|
+
);
|
|
218
271
|
}
|
|
219
272
|
|
|
220
273
|
/** Cooperative pause/resume/stop/clear — flip GoalLoopState.state. */
|
|
@@ -227,7 +280,15 @@ function assertGoalOwnership(goal: GoalLoopState, ctx: TeamContext, action: stri
|
|
|
227
280
|
// an in-flight turn potentially). Previously only 'running' was gated — a paused goal
|
|
228
281
|
// with an active currentRunId could be stop/cancelled by a foreign session without force.
|
|
229
282
|
if (owner && current && owner !== current && (goal.state === "running" || goal.state === "paused")) {
|
|
230
|
-
return result(
|
|
283
|
+
return result(
|
|
284
|
+
`Goal '${goal.goalId}' belongs to session '${owner}' (you are '${current}') and is still running. Use force:true to override.`,
|
|
285
|
+
{
|
|
286
|
+
action,
|
|
287
|
+
status: "error",
|
|
288
|
+
data: { goalId: goal.goalId, ownerSessionId: owner },
|
|
289
|
+
},
|
|
290
|
+
true,
|
|
291
|
+
);
|
|
231
292
|
}
|
|
232
293
|
return undefined;
|
|
233
294
|
}
|
|
@@ -245,7 +306,15 @@ function handleStateFlip(input: GoalSubActionInput, nextState: GoalLoopStatus, l
|
|
|
245
306
|
const eventsPath = createRunPaths(ctx.cwd, goalId).eventsPath;
|
|
246
307
|
const updated = store.setStatus(goalId, nextState, eventsPath);
|
|
247
308
|
if (!updated) return result(`Goal '${goalId}' not found.`, { action: "goal", status: "error" }, true);
|
|
248
|
-
return result(
|
|
309
|
+
return result(
|
|
310
|
+
`Goal ${goalId} ${label} (state='${updated.state}').`,
|
|
311
|
+
{
|
|
312
|
+
action: "goal",
|
|
313
|
+
status: "ok",
|
|
314
|
+
data: { goalId, state: updated.state },
|
|
315
|
+
},
|
|
316
|
+
false,
|
|
317
|
+
);
|
|
249
318
|
}
|
|
250
319
|
|
|
251
320
|
/**
|
|
@@ -269,15 +338,35 @@ async function handleStop(input: GoalSubActionInput): Promise<ReturnType<typeof
|
|
|
269
338
|
let cancelMsg = "";
|
|
270
339
|
if (updated.currentRunId) {
|
|
271
340
|
try {
|
|
272
|
-
|
|
341
|
+
// LAZY: defer dynamic import of ./cancel.ts to its call site.
|
|
273
342
|
const { handleCancel } = await import("./cancel.ts");
|
|
274
|
-
const cancelResult = await handleCancel(
|
|
343
|
+
const cancelResult = await handleCancel(
|
|
344
|
+
{
|
|
345
|
+
action: "cancel",
|
|
346
|
+
runId: updated.currentRunId,
|
|
347
|
+
force: true,
|
|
348
|
+
config: { intent: "user requested goal stop" },
|
|
349
|
+
},
|
|
350
|
+
ctx,
|
|
351
|
+
);
|
|
275
352
|
cancelMsg = ` In-flight turn ${updated.currentRunId} cancel: ${(cancelResult.content[0] as { text?: string } | undefined)?.text ?? "ok"}.`;
|
|
276
353
|
} catch (error) {
|
|
277
354
|
cancelMsg = ` (in-flight turn ${updated.currentRunId} cancel failed: ${error instanceof Error ? error.message : String(error)}; the loop will still exit at the next turn boundary.)`;
|
|
278
355
|
}
|
|
279
356
|
}
|
|
280
|
-
return result(
|
|
357
|
+
return result(
|
|
358
|
+
`Goal ${goalId} stopped (state='cancelled').${cancelMsg}`,
|
|
359
|
+
{
|
|
360
|
+
action: "goal",
|
|
361
|
+
status: "ok",
|
|
362
|
+
data: {
|
|
363
|
+
goalId,
|
|
364
|
+
state: "cancelled",
|
|
365
|
+
cancelledRunId: updated.currentRunId,
|
|
366
|
+
},
|
|
367
|
+
},
|
|
368
|
+
false,
|
|
369
|
+
);
|
|
281
370
|
}
|
|
282
371
|
|
|
283
372
|
/**
|
|
@@ -307,21 +396,37 @@ async function handleResume(input: GoalSubActionInput): Promise<ReturnType<typeo
|
|
|
307
396
|
// Only paused/stuck goals are resumable. (running = already running; terminal states
|
|
308
397
|
// achieved/max_turns/blocked/cancelled/budget_exceeded are done.)
|
|
309
398
|
if (existing.state !== "paused" && existing.state !== "stuck") {
|
|
310
|
-
return result(
|
|
399
|
+
return result(
|
|
400
|
+
`Goal '${goalId}' is in state '${existing.state}' — only 'paused' or 'stuck' goals can be resumed.`,
|
|
401
|
+
{
|
|
402
|
+
action: "goal",
|
|
403
|
+
status: "error",
|
|
404
|
+
data: { goalId, state: existing.state },
|
|
405
|
+
},
|
|
406
|
+
true,
|
|
407
|
+
);
|
|
311
408
|
}
|
|
312
409
|
const hint = typeof params.config?.hint === "string" ? params.config.hint.trim() : undefined;
|
|
313
410
|
const eventsPath = createRunPaths(ctx.cwd, goalId).eventsPath;
|
|
314
411
|
// CAS: only resume if the state is still what we loaded. A concurrent stop/cancel wins.
|
|
315
412
|
const updated = store.compareAndSetStatus(goalId, existing.state, "running", eventsPath);
|
|
316
413
|
if (!updated) {
|
|
317
|
-
return result(
|
|
414
|
+
return result(
|
|
415
|
+
`Goal '${goalId}' state changed concurrently (resume aborted; another actor won the race).`,
|
|
416
|
+
{ action: "goal", status: "error", data: { goalId } },
|
|
417
|
+
true,
|
|
418
|
+
);
|
|
318
419
|
}
|
|
319
420
|
// Inject the hint as next-turn feedback (applies to turn N+1's worker prompt).
|
|
320
421
|
let withHint = updated;
|
|
321
422
|
if (hint) {
|
|
322
423
|
withHint = store.patch(goalId, { nextTurnFeedback: hint }, eventsPath) ?? updated;
|
|
323
424
|
}
|
|
324
|
-
appendEvent(eventsPath, {
|
|
425
|
+
appendEvent(eventsPath, {
|
|
426
|
+
type: "goal.resumed",
|
|
427
|
+
runId: goalId,
|
|
428
|
+
data: { goalId, fromState: existing.state, hint: hint?.slice(0, 200) },
|
|
429
|
+
});
|
|
325
430
|
// Re-spawn the background loop. The loop checks goal.state === "running" before each
|
|
326
431
|
// turn; since we just set it to running, it proceeds.
|
|
327
432
|
try {
|
|
@@ -346,15 +451,40 @@ async function handleResume(input: GoalSubActionInput): Promise<ReturnType<typeo
|
|
|
346
451
|
runKind: "goal-loop",
|
|
347
452
|
};
|
|
348
453
|
const spawned = await spawnBackgroundTeamRun(manifest);
|
|
349
|
-
return result(
|
|
454
|
+
return result(
|
|
455
|
+
`Goal ${goalId} resumed from '${existing.state}' (background pid=${spawned.pid ?? 0}).${hint ? ` Hint injected for next turn.` : ""}`,
|
|
456
|
+
{
|
|
457
|
+
action: "goal",
|
|
458
|
+
status: "ok",
|
|
459
|
+
data: {
|
|
460
|
+
goalId,
|
|
461
|
+
state: "running",
|
|
462
|
+
fromState: existing.state,
|
|
463
|
+
pid: spawned.pid,
|
|
464
|
+
},
|
|
465
|
+
},
|
|
466
|
+
false,
|
|
467
|
+
);
|
|
350
468
|
} catch (spawnError) {
|
|
351
469
|
const msg = spawnError instanceof Error ? spawnError.message : String(spawnError);
|
|
352
470
|
// Cold-review #2 nit: roll back to the PRIOR state (paused/stuck) so the user can retry
|
|
353
471
|
// 'goal resume' (which requires paused/stuck). Leaving it at 'running' with no process made
|
|
354
472
|
// the goal un-resumable — the user had to pause-then-resume as a workaround.
|
|
355
473
|
store.compareAndSetStatus(goalId, "running", existing.state, eventsPath);
|
|
356
|
-
appendEvent(eventsPath, {
|
|
357
|
-
|
|
474
|
+
appendEvent(eventsPath, {
|
|
475
|
+
type: "goal.resume_spawn_failed",
|
|
476
|
+
runId: goalId,
|
|
477
|
+
data: { goalId, error: msg, rolledBackTo: existing.state },
|
|
478
|
+
});
|
|
479
|
+
return result(
|
|
480
|
+
`Goal ${goalId} background re-spawn failed: ${msg}. State rolled back to '${existing.state}'. Retry 'goal resume' to re-attempt.`,
|
|
481
|
+
{
|
|
482
|
+
action: "goal",
|
|
483
|
+
status: "error",
|
|
484
|
+
data: { goalId, spawnFailed: true, state: existing.state },
|
|
485
|
+
},
|
|
486
|
+
true,
|
|
487
|
+
);
|
|
358
488
|
}
|
|
359
489
|
}
|
|
360
490
|
|
|
@@ -388,17 +518,37 @@ export async function handleGoal(params: TeamToolParamsValue, ctx: TeamContext):
|
|
|
388
518
|
if (denied) return denied;
|
|
389
519
|
}
|
|
390
520
|
if (existing.state === "running" || existing.state === "paused") {
|
|
391
|
-
return result(
|
|
521
|
+
return result(
|
|
522
|
+
`Goal '${clearGoalId}' is still ${existing.state}. Stop it first (team action='goal' subAction='stop' goalId='${clearGoalId}'), then clear.`,
|
|
523
|
+
{
|
|
524
|
+
action: "goal",
|
|
525
|
+
status: "error",
|
|
526
|
+
data: { goalId: clearGoalId, state: existing.state },
|
|
527
|
+
},
|
|
528
|
+
true,
|
|
529
|
+
);
|
|
392
530
|
}
|
|
393
531
|
const removed = store.remove(clearGoalId);
|
|
394
532
|
if (!removed) return result(`Goal '${clearGoalId}' could not be removed.`, { action: "goal", status: "error" }, true);
|
|
395
|
-
return result(
|
|
533
|
+
return result(
|
|
534
|
+
`Goal '${clearGoalId}' cleared (file removed).`,
|
|
535
|
+
{
|
|
536
|
+
action: "goal",
|
|
537
|
+
status: "ok",
|
|
538
|
+
data: { goalId: clearGoalId, cleared: true },
|
|
539
|
+
},
|
|
540
|
+
false,
|
|
541
|
+
);
|
|
396
542
|
}
|
|
397
543
|
case "step":
|
|
398
544
|
// P0: step is a status-only stub — single-turn execution lands with P1.
|
|
399
545
|
return handleStatus(input);
|
|
400
546
|
default:
|
|
401
|
-
return result(
|
|
547
|
+
return result(
|
|
548
|
+
`Unknown goal subAction '${subAction}'. Known: start, status, pause, resume, stop, step, clear.`,
|
|
549
|
+
{ action: "goal", status: "error" },
|
|
550
|
+
true,
|
|
551
|
+
);
|
|
402
552
|
}
|
|
403
553
|
}
|
|
404
554
|
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import * as crypto from "node:crypto";
|
|
2
|
-
import type { PiTeamsToolResult } from "../tool-result.ts";
|
|
3
|
-
import type { TeamToolParamsValue } from "../../schema/team-tool-schema.ts";
|
|
4
|
-
import { result, type TeamContext } from "./context.ts";
|
|
5
2
|
import { humanizeSchedule, nextRunTime, parseSchedule } from "../../runtime/scheduler.ts";
|
|
6
3
|
import { loadCrewSettings, saveCrewSettings } from "../../runtime/settings-store.ts";
|
|
4
|
+
import type { TeamToolParamsValue } from "../../schema/team-tool-schema.ts";
|
|
5
|
+
import type { PiTeamsToolResult } from "../tool-result.ts";
|
|
6
|
+
import { result, type TeamContext } from "./context.ts";
|
|
7
7
|
|
|
8
8
|
// Global key for cross-module scheduler access.
|
|
9
9
|
const CREW_SCHEDULER_KEY = Symbol.for("pi-crew:scheduler");
|
|
10
|
-
type SchedulerRef = {
|
|
10
|
+
type SchedulerRef = {
|
|
11
|
+
add(job: import("../../runtime/scheduler.ts").ScheduledJob): void;
|
|
12
|
+
list(): import("../../runtime/scheduler.ts").ScheduledJob[];
|
|
13
|
+
};
|
|
11
14
|
|
|
12
15
|
function getCrewScheduler(): SchedulerRef | undefined {
|
|
13
16
|
return (globalThis as Record<symbol | string, unknown>)[CREW_SCHEDULER_KEY] as SchedulerRef | undefined;
|
|
@@ -36,13 +39,22 @@ function buildScheduleSpec(params: ScheduleParams): {
|
|
|
36
39
|
if (params.cron) {
|
|
37
40
|
const parsed = parseSchedule(params.cron);
|
|
38
41
|
if ("error" in parsed) throw new Error(parsed.error);
|
|
39
|
-
return {
|
|
42
|
+
return {
|
|
43
|
+
spec: parsed,
|
|
44
|
+
schedule: params.cron,
|
|
45
|
+
scheduleType: "cron" as const,
|
|
46
|
+
};
|
|
40
47
|
}
|
|
41
48
|
if (params.interval !== undefined && params.interval > 0) {
|
|
42
49
|
const specStr = `${params.interval}ms`;
|
|
43
50
|
const spec = parseSchedule(specStr);
|
|
44
51
|
if ("error" in spec) throw new Error(spec.error);
|
|
45
|
-
return {
|
|
52
|
+
return {
|
|
53
|
+
spec,
|
|
54
|
+
schedule: specStr,
|
|
55
|
+
scheduleType: "interval" as const,
|
|
56
|
+
intervalMs: params.interval,
|
|
57
|
+
};
|
|
46
58
|
}
|
|
47
59
|
if (params.once !== undefined) {
|
|
48
60
|
const ts = typeof params.once === "number" ? new Date(params.once).toISOString() : params.once;
|
|
@@ -155,7 +167,10 @@ function persistScheduledJob(cwd: string, job: import("../../runtime/scheduler.t
|
|
|
155
167
|
? ((settings as Record<string, unknown>).scheduledJobs as import("../../runtime/scheduler.ts").ScheduledJob[])
|
|
156
168
|
: [];
|
|
157
169
|
saveCrewSettings(
|
|
158
|
-
{
|
|
170
|
+
{
|
|
171
|
+
...settings,
|
|
172
|
+
scheduledJobs: [...existingJobs, job],
|
|
173
|
+
} as Parameters<typeof saveCrewSettings>[0],
|
|
159
174
|
cwd,
|
|
160
175
|
);
|
|
161
176
|
} catch {
|
|
@@ -172,11 +187,8 @@ export function persistScheduledJobUpdate(cwd: string, job: import("../../runtim
|
|
|
172
187
|
)
|
|
173
188
|
? ((settings as Record<string, unknown>).scheduledJobs as import("../../runtime/scheduler.ts").ScheduledJob[])
|
|
174
189
|
: [];
|
|
175
|
-
const updated = existingJobs.map((j) => j.id === job.id ? job : j);
|
|
176
|
-
saveCrewSettings(
|
|
177
|
-
{ ...settings, scheduledJobs: updated } as Parameters<typeof saveCrewSettings>[0],
|
|
178
|
-
cwd,
|
|
179
|
-
);
|
|
190
|
+
const updated = existingJobs.map((j) => (j.id === job.id ? job : j));
|
|
191
|
+
saveCrewSettings({ ...settings, scheduledJobs: updated } as Parameters<typeof saveCrewSettings>[0], cwd);
|
|
180
192
|
} catch {
|
|
181
193
|
/* best-effort persistence */
|
|
182
194
|
}
|
|
@@ -192,7 +204,10 @@ function persistScheduledJobRemove(cwd: string, jobId: string): void {
|
|
|
192
204
|
? ((settings as Record<string, unknown>).scheduledJobs as import("../../runtime/scheduler.ts").ScheduledJob[])
|
|
193
205
|
: [];
|
|
194
206
|
saveCrewSettings(
|
|
195
|
-
{
|
|
207
|
+
{
|
|
208
|
+
...settings,
|
|
209
|
+
scheduledJobs: existingJobs.filter((j) => j.id !== jobId),
|
|
210
|
+
} as Parameters<typeof saveCrewSettings>[0],
|
|
196
211
|
cwd,
|
|
197
212
|
);
|
|
198
213
|
} catch {
|
|
@@ -204,7 +219,11 @@ export function handleListScheduled(_params: TeamToolParamsValue, ctx: TeamConte
|
|
|
204
219
|
const scheduler = getCrewScheduler();
|
|
205
220
|
if (!scheduler) return result("Scheduler not running.", { action: "scheduled", status: "error" }, true);
|
|
206
221
|
const jobs = scheduler.list();
|
|
207
|
-
if (jobs.length === 0)
|
|
222
|
+
if (jobs.length === 0)
|
|
223
|
+
return result("No scheduled jobs.", {
|
|
224
|
+
action: "scheduled",
|
|
225
|
+
status: "ok",
|
|
226
|
+
});
|
|
208
227
|
const lines: string[] = [`Scheduled jobs (${jobs.length}):`];
|
|
209
228
|
for (const job of jobs) {
|
|
210
229
|
lines.push(
|
|
@@ -219,4 +238,4 @@ export function handleListScheduled(_params: TeamToolParamsValue, ctx: TeamConte
|
|
|
219
238
|
}
|
|
220
239
|
}
|
|
221
240
|
return result(lines.join("\n"), { action: "scheduled", status: "ok" });
|
|
222
|
-
}
|
|
241
|
+
}
|