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
|
@@ -1,28 +1,46 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import { loadConfig } from "../../config/config.ts";
|
|
3
|
+
import { buildAgentDashboard, readAgentOutput } from "../../runtime/agent-observability.ts";
|
|
4
|
+
import { buildCapabilityInventory } from "../../runtime/capability-inventory.ts";
|
|
5
|
+
import { agentOutputPath, readCrewAgentEventsCursor, readCrewAgentStatus, readCrewAgents } from "../../runtime/crew-agent-records.ts";
|
|
6
|
+
import { readForegroundControlStatus, writeForegroundInterruptRequest } from "../../runtime/foreground-control.ts";
|
|
7
|
+
import { terminateLiveAgentsForRun } from "../../runtime/live-agent-manager.ts";
|
|
8
|
+
import { currentCrewRole, permissionForRole } from "../../runtime/role-permission.ts";
|
|
9
|
+
import { resolveCrewRuntime } from "../../runtime/runtime-resolver.ts";
|
|
10
|
+
import { touchWorkerHeartbeat } from "../../runtime/worker-heartbeat.ts";
|
|
3
11
|
import type { TeamToolParamsValue } from "../../schema/team-tool-schema.ts";
|
|
4
|
-
import { loadRunManifestById, saveRunManifest, saveRunTasks, updateRunStatus } from "../../state/state-store.ts";
|
|
5
|
-
import { withRunLockSync } from "../../state/locks.ts";
|
|
6
12
|
import { canTransitionTaskStatus, isTeamTaskStatus } from "../../state/contracts.ts";
|
|
7
|
-
import { claimTask, releaseTaskClaim, transitionClaimedTaskStatus } from "../../state/task-claims.ts";
|
|
8
|
-
import { acknowledgeMailboxMessage, appendFollowUpMessage, appendMailboxMessage, appendSteeringMessage, readDeliveryState, readMailbox, readMailboxMessage, validateMailbox, type MailboxDirection, type MailboxMessageKind } from "../../state/mailbox.ts";
|
|
9
13
|
import { appendEvent, readEvents, readEventsCursor } from "../../state/event-log.ts";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
import { withRunLockSync } from "../../state/locks.ts";
|
|
15
|
+
import {
|
|
16
|
+
acknowledgeMailboxMessage,
|
|
17
|
+
appendFollowUpMessage,
|
|
18
|
+
appendMailboxMessage,
|
|
19
|
+
appendSteeringMessage,
|
|
20
|
+
type MailboxDirection,
|
|
21
|
+
type MailboxMessageKind,
|
|
22
|
+
readDeliveryState,
|
|
23
|
+
readMailbox,
|
|
24
|
+
readMailboxMessage,
|
|
25
|
+
validateMailbox,
|
|
26
|
+
} from "../../state/mailbox.ts";
|
|
27
|
+
import { loadRunManifestById, saveRunManifest, saveRunTasks, updateRunStatus } from "../../state/state-store.ts";
|
|
28
|
+
import { claimTask, releaseTaskClaim, transitionClaimedTaskStatus } from "../../state/task-claims.ts";
|
|
19
29
|
import { appendLiveAgentControlRequest } from "../../subagents/live/control.ts";
|
|
30
|
+
import {
|
|
31
|
+
followUpLiveAgent,
|
|
32
|
+
getLiveAgent,
|
|
33
|
+
listActiveLiveAgents,
|
|
34
|
+
resumeLiveAgent,
|
|
35
|
+
steerLiveAgent,
|
|
36
|
+
stopLiveAgent,
|
|
37
|
+
} from "../../subagents/live/manager.ts";
|
|
20
38
|
import { liveControlRealtimeMessage, publishLiveControlRealtime } from "../../subagents/live/realtime.ts";
|
|
39
|
+
import { probeLiveSessionRuntime } from "../../subagents/live/session-runtime.ts";
|
|
21
40
|
import { logInternalError } from "../../utils/internal-error.ts";
|
|
22
|
-
import { buildCapabilityInventory } from "../../runtime/capability-inventory.ts";
|
|
23
41
|
import { resolveRealContainedPath } from "../../utils/safe-paths.ts";
|
|
24
|
-
import type { PiTeamsToolResult } from "../tool-result.ts";
|
|
25
42
|
import { locateRunCwd } from "../team-tool.ts";
|
|
43
|
+
import type { PiTeamsToolResult } from "../tool-result.ts";
|
|
26
44
|
import { configRecord, result, type TeamContext } from "./context.ts";
|
|
27
45
|
import { RUN_NOT_FOUND_HINT } from "./run-not-found.ts";
|
|
28
46
|
|
|
@@ -30,9 +48,9 @@ export function globMatch(value: string, pattern: string): boolean {
|
|
|
30
48
|
// Prevent ReDoS: reject excessively long patterns
|
|
31
49
|
if (pattern.length > 200) return false;
|
|
32
50
|
const regex = pattern
|
|
33
|
-
.replace(/[.+^${}()|[\]\\]/g, "\\$&")
|
|
34
|
-
.replace(/\*/g, "[^/]*")
|
|
35
|
-
.replace(/\?/g, "[^/]");
|
|
51
|
+
.replace(/[.+^${}()|[\]\\]/g, "\\$&") // escape regex special chars
|
|
52
|
+
.replace(/\*/g, "[^/]*") // * matches non-slash characters only
|
|
53
|
+
.replace(/\?/g, "[^/]"); // ? matches single non-slash
|
|
36
54
|
return new RegExp(`^${regex}$`).test(value);
|
|
37
55
|
}
|
|
38
56
|
|
|
@@ -68,7 +86,11 @@ function snapshotHasRunId(snapshot: { values?: unknown }, runId: string): boolea
|
|
|
68
86
|
function canApprovePlan(): { allowed: boolean; reason?: string } {
|
|
69
87
|
const role = currentCrewRole();
|
|
70
88
|
if (!role) return { allowed: true };
|
|
71
|
-
if (permissionForRole(role) === "read_only")
|
|
89
|
+
if (permissionForRole(role) === "read_only")
|
|
90
|
+
return {
|
|
91
|
+
allowed: false,
|
|
92
|
+
reason: `Role '${role}' is read-only and cannot approve or cancel plan gates.`,
|
|
93
|
+
};
|
|
72
94
|
return { allowed: true };
|
|
73
95
|
}
|
|
74
96
|
|
|
@@ -84,11 +106,18 @@ export async function handleApi(params: TeamToolParamsValue, ctx: TeamContext):
|
|
|
84
106
|
if (runIdFilter && !snapshotHasRunId(snapshot, runIdFilter)) return false;
|
|
85
107
|
return true;
|
|
86
108
|
});
|
|
87
|
-
return result(JSON.stringify(filtered, null, 2), {
|
|
109
|
+
return result(JSON.stringify(filtered, null, 2), {
|
|
110
|
+
action: "api",
|
|
111
|
+
status: "ok",
|
|
112
|
+
...(runIdFilter ? { runId: runIdFilter } : {}),
|
|
113
|
+
});
|
|
88
114
|
}
|
|
89
115
|
if (operation === "inventory") {
|
|
90
116
|
const inventory = buildCapabilityInventory(ctx.cwd, ctx.config);
|
|
91
|
-
return result(JSON.stringify(inventory, null, 2), {
|
|
117
|
+
return result(JSON.stringify(inventory, null, 2), {
|
|
118
|
+
action: "api",
|
|
119
|
+
status: "ok",
|
|
120
|
+
});
|
|
92
121
|
}
|
|
93
122
|
if (!params.runId) return result("API requires runId.", { action: "api", status: "error" }, true);
|
|
94
123
|
const runCwd = locateRunCwd(params.runId, ctx.cwd);
|
|
@@ -96,218 +125,737 @@ export async function handleApi(params: TeamToolParamsValue, ctx: TeamContext):
|
|
|
96
125
|
const loaded = loadRunManifestById(runCwd, params.runId); // NOTE: no withRunLock - best-effort only; concurrent writes may cause inconsistency
|
|
97
126
|
if (!loaded) return result(`Run '${params.runId}' not found.${RUN_NOT_FOUND_HINT}`, { action: "api", status: "error" }, true);
|
|
98
127
|
if (operation === "read-manifest") {
|
|
99
|
-
return result(JSON.stringify(loaded.manifest, null, 2), {
|
|
128
|
+
return result(JSON.stringify(loaded.manifest, null, 2), {
|
|
129
|
+
action: "api",
|
|
130
|
+
status: "ok",
|
|
131
|
+
runId: loaded.manifest.runId,
|
|
132
|
+
artifactsRoot: loaded.manifest.artifactsRoot,
|
|
133
|
+
});
|
|
100
134
|
}
|
|
101
135
|
if (operation === "approve-plan") {
|
|
102
136
|
const permission = canApprovePlan();
|
|
103
|
-
if (!permission.allowed)
|
|
137
|
+
if (!permission.allowed)
|
|
138
|
+
return result(
|
|
139
|
+
permission.reason ?? "Plan approval is not allowed in this context.",
|
|
140
|
+
{
|
|
141
|
+
action: "api",
|
|
142
|
+
status: "error",
|
|
143
|
+
runId: loaded.manifest.runId,
|
|
144
|
+
},
|
|
145
|
+
true,
|
|
146
|
+
);
|
|
104
147
|
try {
|
|
105
148
|
return withRunLockSync(loaded.manifest, () => {
|
|
106
149
|
const current = loadRunManifestById(ctx.cwd, loaded.manifest.runId) ?? loaded; // NOTE: inside withRunLockSync - consistent read
|
|
107
150
|
const approval = current.manifest.planApproval;
|
|
108
|
-
if (!approval?.required || approval.status !== "pending")
|
|
151
|
+
if (!approval?.required || approval.status !== "pending")
|
|
152
|
+
return result(
|
|
153
|
+
"Run has no pending plan approval request.",
|
|
154
|
+
{
|
|
155
|
+
action: "api",
|
|
156
|
+
status: "error",
|
|
157
|
+
runId: loaded.manifest.runId,
|
|
158
|
+
},
|
|
159
|
+
true,
|
|
160
|
+
);
|
|
109
161
|
const now = new Date().toISOString();
|
|
110
|
-
const manifest = {
|
|
162
|
+
const manifest = {
|
|
163
|
+
...current.manifest,
|
|
164
|
+
updatedAt: now,
|
|
165
|
+
planApproval: {
|
|
166
|
+
...approval,
|
|
167
|
+
status: "approved" as const,
|
|
168
|
+
approvedAt: now,
|
|
169
|
+
updatedAt: now,
|
|
170
|
+
},
|
|
171
|
+
};
|
|
111
172
|
saveRunManifest(manifest);
|
|
112
|
-
appendEvent(manifest.eventsPath, {
|
|
113
|
-
|
|
173
|
+
appendEvent(manifest.eventsPath, {
|
|
174
|
+
type: "plan.approved",
|
|
175
|
+
runId: manifest.runId,
|
|
176
|
+
taskId: approval.planTaskId,
|
|
177
|
+
message: "Adaptive implementation plan approved; resume the run to execute mutating tasks.",
|
|
178
|
+
metadata: { provenance: "api" },
|
|
179
|
+
});
|
|
180
|
+
return result(JSON.stringify(manifest.planApproval, null, 2), {
|
|
181
|
+
action: "api",
|
|
182
|
+
status: "ok",
|
|
183
|
+
runId: manifest.runId,
|
|
184
|
+
artifactsRoot: manifest.artifactsRoot,
|
|
185
|
+
});
|
|
114
186
|
});
|
|
115
187
|
} catch (error) {
|
|
116
188
|
const message = error instanceof Error ? error.message : String(error);
|
|
117
|
-
return result(
|
|
189
|
+
return result(
|
|
190
|
+
message,
|
|
191
|
+
{
|
|
192
|
+
action: "api",
|
|
193
|
+
status: "error",
|
|
194
|
+
runId: loaded.manifest.runId,
|
|
195
|
+
},
|
|
196
|
+
true,
|
|
197
|
+
);
|
|
118
198
|
}
|
|
119
199
|
}
|
|
120
200
|
if (operation === "cancel-plan") {
|
|
121
201
|
const permission = canApprovePlan();
|
|
122
|
-
if (!permission.allowed)
|
|
202
|
+
if (!permission.allowed)
|
|
203
|
+
return result(
|
|
204
|
+
permission.reason ?? "Plan approval cancellation is not allowed in this context.",
|
|
205
|
+
{
|
|
206
|
+
action: "api",
|
|
207
|
+
status: "error",
|
|
208
|
+
runId: loaded.manifest.runId,
|
|
209
|
+
},
|
|
210
|
+
true,
|
|
211
|
+
);
|
|
123
212
|
try {
|
|
124
213
|
return withRunLockSync(loaded.manifest, () => {
|
|
125
214
|
const current = loadRunManifestById(ctx.cwd, loaded.manifest.runId) ?? loaded; // NOTE: inside withRunLockSync - consistent read
|
|
126
215
|
const approval = current.manifest.planApproval;
|
|
127
|
-
if (!approval?.required || approval.status !== "pending")
|
|
216
|
+
if (!approval?.required || approval.status !== "pending")
|
|
217
|
+
return result(
|
|
218
|
+
"Run has no pending plan approval request.",
|
|
219
|
+
{
|
|
220
|
+
action: "api",
|
|
221
|
+
status: "error",
|
|
222
|
+
runId: loaded.manifest.runId,
|
|
223
|
+
},
|
|
224
|
+
true,
|
|
225
|
+
);
|
|
128
226
|
const now = new Date().toISOString();
|
|
129
|
-
const tasks = current.tasks.map((task) =>
|
|
130
|
-
|
|
227
|
+
const tasks = current.tasks.map((task) =>
|
|
228
|
+
task.status === "queued" || task.status === "running" || task.status === "waiting"
|
|
229
|
+
? {
|
|
230
|
+
...task,
|
|
231
|
+
status: "cancelled" as const,
|
|
232
|
+
finishedAt: now,
|
|
233
|
+
error: "Plan approval was cancelled.",
|
|
234
|
+
}
|
|
235
|
+
: task,
|
|
236
|
+
);
|
|
237
|
+
let manifest: typeof current.manifest = {
|
|
238
|
+
...current.manifest,
|
|
239
|
+
updatedAt: now,
|
|
240
|
+
planApproval: {
|
|
241
|
+
...approval,
|
|
242
|
+
status: "cancelled" as const,
|
|
243
|
+
cancelledAt: now,
|
|
244
|
+
updatedAt: now,
|
|
245
|
+
},
|
|
246
|
+
};
|
|
131
247
|
saveRunManifest(manifest);
|
|
132
248
|
saveRunTasks(manifest, tasks);
|
|
133
|
-
appendEvent(manifest.eventsPath, {
|
|
249
|
+
appendEvent(manifest.eventsPath, {
|
|
250
|
+
type: "plan.cancelled",
|
|
251
|
+
runId: manifest.runId,
|
|
252
|
+
taskId: approval.planTaskId,
|
|
253
|
+
message: "Adaptive implementation plan was cancelled.",
|
|
254
|
+
metadata: { provenance: "api" },
|
|
255
|
+
});
|
|
134
256
|
manifest = updateRunStatus(manifest, "cancelled", "Plan approval was cancelled.");
|
|
135
|
-
void terminateLiveAgentsForRun(manifest.runId, "cancelled", appendEvent, manifest.eventsPath).catch((error) =>
|
|
136
|
-
|
|
257
|
+
void terminateLiveAgentsForRun(manifest.runId, "cancelled", appendEvent, manifest.eventsPath).catch((error) =>
|
|
258
|
+
logInternalError("team-tool.cancel-plan.terminate", error, `runId=${manifest.runId}`),
|
|
259
|
+
);
|
|
260
|
+
return result(
|
|
261
|
+
JSON.stringify(
|
|
262
|
+
{
|
|
263
|
+
planApproval: manifest.planApproval,
|
|
264
|
+
cancelledTasks: tasks.filter((task) => task.status === "cancelled").map((task) => task.id),
|
|
265
|
+
},
|
|
266
|
+
null,
|
|
267
|
+
2,
|
|
268
|
+
),
|
|
269
|
+
{
|
|
270
|
+
action: "api",
|
|
271
|
+
status: "ok",
|
|
272
|
+
runId: manifest.runId,
|
|
273
|
+
artifactsRoot: manifest.artifactsRoot,
|
|
274
|
+
},
|
|
275
|
+
);
|
|
137
276
|
});
|
|
138
277
|
} catch (error) {
|
|
139
278
|
const message = error instanceof Error ? error.message : String(error);
|
|
140
|
-
return result(
|
|
279
|
+
return result(
|
|
280
|
+
message,
|
|
281
|
+
{
|
|
282
|
+
action: "api",
|
|
283
|
+
status: "error",
|
|
284
|
+
runId: loaded.manifest.runId,
|
|
285
|
+
},
|
|
286
|
+
true,
|
|
287
|
+
);
|
|
141
288
|
}
|
|
142
289
|
}
|
|
143
290
|
if (operation === "list-tasks") {
|
|
144
|
-
return result(JSON.stringify(loaded.tasks, null, 2), {
|
|
291
|
+
return result(JSON.stringify(loaded.tasks, null, 2), {
|
|
292
|
+
action: "api",
|
|
293
|
+
status: "ok",
|
|
294
|
+
runId: loaded.manifest.runId,
|
|
295
|
+
artifactsRoot: loaded.manifest.artifactsRoot,
|
|
296
|
+
});
|
|
145
297
|
}
|
|
146
298
|
if (operation === "read-task") {
|
|
147
299
|
const taskId = typeof cfg.taskId === "string" ? cfg.taskId : undefined;
|
|
148
300
|
const task = loaded.tasks.find((item) => item.id === taskId || item.stepId === taskId);
|
|
149
|
-
if (!task)
|
|
150
|
-
|
|
301
|
+
if (!task)
|
|
302
|
+
return result(
|
|
303
|
+
"API read-task requires config.taskId matching a task id or step id.",
|
|
304
|
+
{
|
|
305
|
+
action: "api",
|
|
306
|
+
status: "error",
|
|
307
|
+
runId: loaded.manifest.runId,
|
|
308
|
+
},
|
|
309
|
+
true,
|
|
310
|
+
);
|
|
311
|
+
return result(JSON.stringify(task, null, 2), {
|
|
312
|
+
action: "api",
|
|
313
|
+
status: "ok",
|
|
314
|
+
runId: loaded.manifest.runId,
|
|
315
|
+
artifactsRoot: loaded.manifest.artifactsRoot,
|
|
316
|
+
});
|
|
151
317
|
}
|
|
152
318
|
if (operation === "read-events") {
|
|
153
319
|
const sinceSeq = typeof cfg.sinceSeq === "number" ? cfg.sinceSeq : undefined;
|
|
154
320
|
const limit = typeof cfg.limit === "number" ? cfg.limit : undefined;
|
|
155
|
-
const payload =
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
321
|
+
const payload =
|
|
322
|
+
sinceSeq !== undefined || limit !== undefined
|
|
323
|
+
? readEventsCursor(loaded.manifest.eventsPath, {
|
|
324
|
+
sinceSeq,
|
|
325
|
+
limit,
|
|
326
|
+
})
|
|
327
|
+
: {
|
|
328
|
+
events: readEvents(loaded.manifest.eventsPath),
|
|
329
|
+
nextSeq: undefined,
|
|
330
|
+
total: undefined,
|
|
331
|
+
};
|
|
332
|
+
return result(JSON.stringify(payload, null, 2), {
|
|
333
|
+
action: "api",
|
|
334
|
+
status: "ok",
|
|
335
|
+
runId: loaded.manifest.runId,
|
|
336
|
+
artifactsRoot: loaded.manifest.artifactsRoot,
|
|
337
|
+
});
|
|
159
338
|
}
|
|
160
339
|
if (operation === "runtime-capabilities") {
|
|
161
340
|
const loadedConfig = loadConfig(ctx.cwd);
|
|
162
|
-
return result(JSON.stringify(await resolveCrewRuntime(loadedConfig.config), null, 2), {
|
|
341
|
+
return result(JSON.stringify(await resolveCrewRuntime(loadedConfig.config), null, 2), {
|
|
342
|
+
action: "api",
|
|
343
|
+
status: "ok",
|
|
344
|
+
runId: loaded.manifest.runId,
|
|
345
|
+
artifactsRoot: loaded.manifest.artifactsRoot,
|
|
346
|
+
});
|
|
163
347
|
}
|
|
164
348
|
if (operation === "probe-live-session") {
|
|
165
|
-
return result(JSON.stringify(await probeLiveSessionRuntime(), null, 2), {
|
|
349
|
+
return result(JSON.stringify(await probeLiveSessionRuntime(), null, 2), {
|
|
350
|
+
action: "api",
|
|
351
|
+
status: "ok",
|
|
352
|
+
runId: loaded.manifest.runId,
|
|
353
|
+
artifactsRoot: loaded.manifest.artifactsRoot,
|
|
354
|
+
});
|
|
166
355
|
}
|
|
167
356
|
if (operation === "list-agents") {
|
|
168
|
-
return result(JSON.stringify(readCrewAgents(loaded.manifest), null, 2), {
|
|
357
|
+
return result(JSON.stringify(readCrewAgents(loaded.manifest), null, 2), {
|
|
358
|
+
action: "api",
|
|
359
|
+
status: "ok",
|
|
360
|
+
runId: loaded.manifest.runId,
|
|
361
|
+
artifactsRoot: loaded.manifest.artifactsRoot,
|
|
362
|
+
});
|
|
169
363
|
}
|
|
170
364
|
if (operation === "get-agent-result") {
|
|
171
365
|
const agentId = typeof cfg.agentId === "string" ? cfg.agentId : undefined;
|
|
172
366
|
const agent = readCrewAgents(loaded.manifest).find((item) => item.id === agentId || item.taskId === agentId);
|
|
173
|
-
if (!agent)
|
|
367
|
+
if (!agent)
|
|
368
|
+
return result(
|
|
369
|
+
"API get-agent-result requires config.agentId matching an agent id or task id.",
|
|
370
|
+
{
|
|
371
|
+
action: "api",
|
|
372
|
+
status: "error",
|
|
373
|
+
runId: loaded.manifest.runId,
|
|
374
|
+
},
|
|
375
|
+
true,
|
|
376
|
+
);
|
|
174
377
|
const task = loaded.tasks.find((item) => item.id === agent.taskId);
|
|
175
378
|
const text = safeReadContainedFile(loaded.manifest.artifactsRoot, task?.resultArtifact?.path) ?? JSON.stringify(agent, null, 2);
|
|
176
|
-
return result(text, {
|
|
379
|
+
return result(text, {
|
|
380
|
+
action: "api",
|
|
381
|
+
status: "ok",
|
|
382
|
+
runId: loaded.manifest.runId,
|
|
383
|
+
artifactsRoot: loaded.manifest.artifactsRoot,
|
|
384
|
+
});
|
|
177
385
|
}
|
|
178
386
|
if (operation === "read-agent-status") {
|
|
179
387
|
const agentId = typeof cfg.agentId === "string" ? cfg.agentId : undefined;
|
|
180
388
|
const agent = agentId ? readCrewAgents(loaded.manifest).find((item) => item.id === agentId || item.taskId === agentId) : undefined;
|
|
181
|
-
const status = agent ? readCrewAgentStatus(loaded.manifest, agent.taskId) ?? agent : undefined;
|
|
182
|
-
if (!status)
|
|
183
|
-
|
|
389
|
+
const status = agent ? (readCrewAgentStatus(loaded.manifest, agent.taskId) ?? agent) : undefined;
|
|
390
|
+
if (!status)
|
|
391
|
+
return result(
|
|
392
|
+
"API read-agent-status requires config.agentId matching an agent id or task id.",
|
|
393
|
+
{
|
|
394
|
+
action: "api",
|
|
395
|
+
status: "error",
|
|
396
|
+
runId: loaded.manifest.runId,
|
|
397
|
+
},
|
|
398
|
+
true,
|
|
399
|
+
);
|
|
400
|
+
return result(JSON.stringify(status, null, 2), {
|
|
401
|
+
action: "api",
|
|
402
|
+
status: "ok",
|
|
403
|
+
runId: loaded.manifest.runId,
|
|
404
|
+
artifactsRoot: loaded.manifest.artifactsRoot,
|
|
405
|
+
});
|
|
184
406
|
}
|
|
185
407
|
if (operation === "read-agent-events") {
|
|
186
408
|
const agentId = typeof cfg.agentId === "string" ? cfg.agentId : undefined;
|
|
187
409
|
const agents = readCrewAgents(loaded.manifest);
|
|
188
410
|
const agent = agentId ? agents.find((item) => item.id === agentId || item.taskId === agentId) : agents[0];
|
|
189
|
-
if (!agent)
|
|
411
|
+
if (!agent)
|
|
412
|
+
return result(
|
|
413
|
+
"API read-agent-events requires config.agentId matching an agent id or task id, or at least one agent in the run.",
|
|
414
|
+
{
|
|
415
|
+
action: "api",
|
|
416
|
+
status: "error",
|
|
417
|
+
runId: loaded.manifest.runId,
|
|
418
|
+
},
|
|
419
|
+
true,
|
|
420
|
+
);
|
|
190
421
|
const sinceSeq = typeof cfg.sinceSeq === "number" ? cfg.sinceSeq : undefined;
|
|
191
422
|
const limit = typeof cfg.limit === "number" ? cfg.limit : undefined;
|
|
192
423
|
const cursorPayload = readCrewAgentEventsCursor(loaded.manifest, agent.taskId, { sinceSeq, limit });
|
|
193
|
-
const payload =
|
|
194
|
-
|
|
424
|
+
const payload =
|
|
425
|
+
sinceSeq !== undefined || limit !== undefined ? cursorPayload : { path: cursorPayload.path, events: cursorPayload.events };
|
|
426
|
+
return result(JSON.stringify(payload, null, 2), {
|
|
427
|
+
action: "api",
|
|
428
|
+
status: "ok",
|
|
429
|
+
runId: loaded.manifest.runId,
|
|
430
|
+
artifactsRoot: loaded.manifest.artifactsRoot,
|
|
431
|
+
});
|
|
195
432
|
}
|
|
196
433
|
if (operation === "read-agent-transcript") {
|
|
197
434
|
const agentId = typeof cfg.agentId === "string" ? cfg.agentId : undefined;
|
|
198
435
|
const agents = readCrewAgents(loaded.manifest);
|
|
199
436
|
const agent = agentId ? agents.find((item) => item.id === agentId || item.taskId === agentId) : agents[0];
|
|
200
|
-
if (!agent)
|
|
437
|
+
if (!agent)
|
|
438
|
+
return result(
|
|
439
|
+
"API read-agent-transcript requires config.agentId matching an agent id or task id, or at least one agent in the run.",
|
|
440
|
+
{
|
|
441
|
+
action: "api",
|
|
442
|
+
status: "error",
|
|
443
|
+
runId: loaded.manifest.runId,
|
|
444
|
+
},
|
|
445
|
+
true,
|
|
446
|
+
);
|
|
201
447
|
const artifactTranscriptPath = safeContainedPath(loaded.manifest.artifactsRoot, agent.transcriptPath);
|
|
202
448
|
const fallbackPath = agentOutputPath(loaded.manifest, agent.taskId);
|
|
203
|
-
const artifactText = artifactTranscriptPath
|
|
204
|
-
|
|
449
|
+
const artifactText = artifactTranscriptPath
|
|
450
|
+
? (safeReadContainedFile(loaded.manifest.artifactsRoot, artifactTranscriptPath) ?? "")
|
|
451
|
+
: "";
|
|
452
|
+
const fallbackText = artifactText ? "" : (safeReadContainedFile(loaded.manifest.stateRoot, fallbackPath) ?? "");
|
|
205
453
|
const transcriptPath = artifactText ? artifactTranscriptPath : fallbackPath;
|
|
206
454
|
const text = artifactText || fallbackText;
|
|
207
|
-
return result(text || `(no transcript at ${transcriptPath})`, {
|
|
455
|
+
return result(text || `(no transcript at ${transcriptPath})`, {
|
|
456
|
+
action: "api",
|
|
457
|
+
status: "ok",
|
|
458
|
+
runId: loaded.manifest.runId,
|
|
459
|
+
artifactsRoot: loaded.manifest.artifactsRoot,
|
|
460
|
+
});
|
|
208
461
|
}
|
|
209
462
|
if (operation === "read-agent-output") {
|
|
210
463
|
const agentId = typeof cfg.agentId === "string" ? cfg.agentId : undefined;
|
|
211
464
|
const agents = readCrewAgents(loaded.manifest);
|
|
212
465
|
const agent = agentId ? agents.find((item) => item.id === agentId || item.taskId === agentId) : agents[0];
|
|
213
|
-
if (!agent)
|
|
466
|
+
if (!agent)
|
|
467
|
+
return result(
|
|
468
|
+
"API read-agent-output requires config.agentId matching an agent id or task id, or at least one agent in the run.",
|
|
469
|
+
{
|
|
470
|
+
action: "api",
|
|
471
|
+
status: "error",
|
|
472
|
+
runId: loaded.manifest.runId,
|
|
473
|
+
},
|
|
474
|
+
true,
|
|
475
|
+
);
|
|
214
476
|
const maxBytes = typeof cfg.maxBytes === "number" ? cfg.maxBytes : undefined;
|
|
215
|
-
return result(JSON.stringify(readAgentOutput(loaded.manifest, agent.taskId, maxBytes), null, 2), {
|
|
477
|
+
return result(JSON.stringify(readAgentOutput(loaded.manifest, agent.taskId, maxBytes), null, 2), {
|
|
478
|
+
action: "api",
|
|
479
|
+
status: "ok",
|
|
480
|
+
runId: loaded.manifest.runId,
|
|
481
|
+
artifactsRoot: loaded.manifest.artifactsRoot,
|
|
482
|
+
});
|
|
216
483
|
}
|
|
217
484
|
if (operation === "agent-dashboard") {
|
|
218
|
-
return result(buildAgentDashboard(loaded.manifest).text, {
|
|
485
|
+
return result(buildAgentDashboard(loaded.manifest).text, {
|
|
486
|
+
action: "api",
|
|
487
|
+
status: "ok",
|
|
488
|
+
runId: loaded.manifest.runId,
|
|
489
|
+
artifactsRoot: loaded.manifest.artifactsRoot,
|
|
490
|
+
});
|
|
219
491
|
}
|
|
220
492
|
if (operation === "foreground-status") {
|
|
221
|
-
return result(JSON.stringify(readForegroundControlStatus(loaded.manifest, loaded.tasks), null, 2), {
|
|
493
|
+
return result(JSON.stringify(readForegroundControlStatus(loaded.manifest, loaded.tasks), null, 2), {
|
|
494
|
+
action: "api",
|
|
495
|
+
status: "ok",
|
|
496
|
+
runId: loaded.manifest.runId,
|
|
497
|
+
artifactsRoot: loaded.manifest.artifactsRoot,
|
|
498
|
+
});
|
|
222
499
|
}
|
|
223
500
|
if (operation === "foreground-interrupt") {
|
|
224
501
|
const reason = typeof cfg.reason === "string" && cfg.reason.trim() ? cfg.reason.trim() : undefined;
|
|
225
|
-
return result(JSON.stringify(writeForegroundInterruptRequest(loaded.manifest, reason), null, 2), {
|
|
502
|
+
return result(JSON.stringify(writeForegroundInterruptRequest(loaded.manifest, reason), null, 2), {
|
|
503
|
+
action: "api",
|
|
504
|
+
status: "ok",
|
|
505
|
+
runId: loaded.manifest.runId,
|
|
506
|
+
artifactsRoot: loaded.manifest.artifactsRoot,
|
|
507
|
+
});
|
|
226
508
|
}
|
|
227
509
|
if (operation === "nudge-agent") {
|
|
228
510
|
const agentId = typeof cfg.agentId === "string" ? cfg.agentId : undefined;
|
|
229
511
|
const agent = readCrewAgents(loaded.manifest).find((item) => item.id === agentId || item.taskId === agentId);
|
|
230
|
-
if (!agent)
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
512
|
+
if (!agent)
|
|
513
|
+
return result(
|
|
514
|
+
"API nudge-agent requires config.agentId matching an agent id or task id.",
|
|
515
|
+
{
|
|
516
|
+
action: "api",
|
|
517
|
+
status: "error",
|
|
518
|
+
runId: loaded.manifest.runId,
|
|
519
|
+
},
|
|
520
|
+
true,
|
|
521
|
+
);
|
|
522
|
+
const messageText =
|
|
523
|
+
typeof cfg.message === "string" && cfg.message.trim()
|
|
524
|
+
? cfg.message.trim()
|
|
525
|
+
: "Please report your current status, blocker, or smallest next step.";
|
|
526
|
+
const message = appendSteeringMessage(loaded.manifest, {
|
|
527
|
+
taskId: agent.taskId,
|
|
528
|
+
to: agent.taskId,
|
|
529
|
+
body: messageText,
|
|
530
|
+
priority: "normal",
|
|
531
|
+
data: { source: "nudge-agent" },
|
|
532
|
+
});
|
|
533
|
+
appendEvent(loaded.manifest.eventsPath, {
|
|
534
|
+
type: "agent.nudged",
|
|
535
|
+
runId: loaded.manifest.runId,
|
|
536
|
+
taskId: agent.taskId,
|
|
537
|
+
message: messageText,
|
|
538
|
+
data: { agentId: agent.id, mailboxMessageId: message.id },
|
|
539
|
+
});
|
|
540
|
+
ctx.events?.emit?.("crew.mailbox.message", {
|
|
541
|
+
runId: loaded.manifest.runId,
|
|
542
|
+
id: message.id,
|
|
543
|
+
direction: message.direction,
|
|
544
|
+
from: message.from,
|
|
545
|
+
to: message.to,
|
|
546
|
+
taskId: message.taskId,
|
|
547
|
+
source: "nudge-agent",
|
|
548
|
+
});
|
|
549
|
+
return result(JSON.stringify({ agentId: agent.id, mailboxMessage: message }, null, 2), {
|
|
550
|
+
action: "api",
|
|
551
|
+
status: "ok",
|
|
552
|
+
runId: loaded.manifest.runId,
|
|
553
|
+
artifactsRoot: loaded.manifest.artifactsRoot,
|
|
554
|
+
});
|
|
236
555
|
}
|
|
237
556
|
if (operation === "list-live-agents") {
|
|
238
|
-
return result(
|
|
557
|
+
return result(
|
|
558
|
+
JSON.stringify(
|
|
559
|
+
listActiveLiveAgents().filter((agent) => agent.runId === loaded.manifest.runId),
|
|
560
|
+
null,
|
|
561
|
+
2,
|
|
562
|
+
),
|
|
563
|
+
{
|
|
564
|
+
action: "api",
|
|
565
|
+
status: "ok",
|
|
566
|
+
runId: loaded.manifest.runId,
|
|
567
|
+
artifactsRoot: loaded.manifest.artifactsRoot,
|
|
568
|
+
},
|
|
569
|
+
);
|
|
239
570
|
}
|
|
240
|
-
if (
|
|
571
|
+
if (
|
|
572
|
+
operation === "steer-agent" ||
|
|
573
|
+
operation === "follow-up-agent" ||
|
|
574
|
+
operation === "stop-agent" ||
|
|
575
|
+
operation === "resume-agent" ||
|
|
576
|
+
operation === "interrupt-agent"
|
|
577
|
+
) {
|
|
241
578
|
const agentId = typeof cfg.agentId === "string" ? cfg.agentId : undefined;
|
|
242
|
-
if (!agentId)
|
|
579
|
+
if (!agentId)
|
|
580
|
+
return result(
|
|
581
|
+
`API ${operation} requires config.agentId.`,
|
|
582
|
+
{
|
|
583
|
+
action: "api",
|
|
584
|
+
status: "error",
|
|
585
|
+
runId: loaded.manifest.runId,
|
|
586
|
+
},
|
|
587
|
+
true,
|
|
588
|
+
);
|
|
243
589
|
const message = typeof cfg.message === "string" && cfg.message.trim() ? cfg.message.trim() : undefined;
|
|
244
590
|
const prompt = typeof cfg.prompt === "string" && cfg.prompt.trim() ? cfg.prompt.trim() : message;
|
|
245
591
|
try {
|
|
246
592
|
const live = getLiveAgent(agentId);
|
|
247
|
-
if (live && live.runId !== loaded.manifest.runId)
|
|
248
|
-
|
|
249
|
-
|
|
593
|
+
if (live && live.runId !== loaded.manifest.runId)
|
|
594
|
+
return result(
|
|
595
|
+
`Live agent '${agentId}' does not belong to run ${loaded.manifest.runId}.`,
|
|
596
|
+
{
|
|
597
|
+
action: "api",
|
|
598
|
+
status: "error",
|
|
599
|
+
runId: loaded.manifest.runId,
|
|
600
|
+
},
|
|
601
|
+
true,
|
|
602
|
+
);
|
|
603
|
+
if (live && live.workspaceId !== loaded.manifest.cwd)
|
|
604
|
+
return result(
|
|
605
|
+
`Live agent '${agentId}' does not belong to workspace ${loaded.manifest.cwd}.`,
|
|
606
|
+
{
|
|
607
|
+
action: "api",
|
|
608
|
+
status: "error",
|
|
609
|
+
runId: loaded.manifest.runId,
|
|
610
|
+
},
|
|
611
|
+
true,
|
|
612
|
+
);
|
|
613
|
+
if (!live && (operation === "steer-agent" || operation === "follow-up-agent"))
|
|
614
|
+
throw new Error(`Live agent '${agentId}' not found.`);
|
|
250
615
|
const liveTaskId = live?.taskId;
|
|
251
|
-
if ((operation === "steer-agent" || operation === "follow-up-agent") && !liveTaskId)
|
|
616
|
+
if ((operation === "steer-agent" || operation === "follow-up-agent") && !liveTaskId)
|
|
617
|
+
throw new Error(`Live agent '${agentId}' not found.`);
|
|
252
618
|
const targetTaskId = liveTaskId ?? agentId;
|
|
253
619
|
if (operation === "steer-agent") {
|
|
254
620
|
const text = message ?? "Please report current status and wrap up if possible.";
|
|
255
621
|
const realtime = await steerLiveAgent(agentId, text);
|
|
256
|
-
const mailboxMessage = appendSteeringMessage(loaded.manifest, {
|
|
257
|
-
|
|
622
|
+
const mailboxMessage = appendSteeringMessage(loaded.manifest, {
|
|
623
|
+
taskId: targetTaskId,
|
|
624
|
+
body: text,
|
|
625
|
+
status: "delivered",
|
|
626
|
+
data: { source: "steer-agent", realtime: true },
|
|
627
|
+
});
|
|
628
|
+
return result(JSON.stringify({ realtime, mailboxMessage }, null, 2), {
|
|
629
|
+
action: "api",
|
|
630
|
+
status: "ok",
|
|
631
|
+
runId: loaded.manifest.runId,
|
|
632
|
+
artifactsRoot: loaded.manifest.artifactsRoot,
|
|
633
|
+
});
|
|
258
634
|
}
|
|
259
635
|
if (operation === "follow-up-agent") {
|
|
260
|
-
if (!prompt)
|
|
636
|
+
if (!prompt)
|
|
637
|
+
return result(
|
|
638
|
+
"API follow-up-agent requires config.prompt or config.message.",
|
|
639
|
+
{
|
|
640
|
+
action: "api",
|
|
641
|
+
status: "error",
|
|
642
|
+
runId: loaded.manifest.runId,
|
|
643
|
+
},
|
|
644
|
+
true,
|
|
645
|
+
);
|
|
261
646
|
const realtime = await followUpLiveAgent(agentId, prompt);
|
|
262
|
-
const mailboxMessage = appendFollowUpMessage(loaded.manifest, {
|
|
263
|
-
|
|
647
|
+
const mailboxMessage = appendFollowUpMessage(loaded.manifest, {
|
|
648
|
+
taskId: targetTaskId,
|
|
649
|
+
body: prompt,
|
|
650
|
+
status: "delivered",
|
|
651
|
+
data: { source: "follow-up-agent", realtime: true },
|
|
652
|
+
});
|
|
653
|
+
return result(JSON.stringify({ realtime, mailboxMessage }, null, 2), {
|
|
654
|
+
action: "api",
|
|
655
|
+
status: "ok",
|
|
656
|
+
runId: loaded.manifest.runId,
|
|
657
|
+
artifactsRoot: loaded.manifest.artifactsRoot,
|
|
658
|
+
});
|
|
264
659
|
}
|
|
265
660
|
if (operation === "resume-agent") {
|
|
266
|
-
if (!prompt)
|
|
267
|
-
|
|
661
|
+
if (!prompt)
|
|
662
|
+
return result(
|
|
663
|
+
"API resume-agent requires config.prompt or config.message.",
|
|
664
|
+
{
|
|
665
|
+
action: "api",
|
|
666
|
+
status: "error",
|
|
667
|
+
runId: loaded.manifest.runId,
|
|
668
|
+
},
|
|
669
|
+
true,
|
|
670
|
+
);
|
|
671
|
+
return result(JSON.stringify(await resumeLiveAgent(agentId, prompt), null, 2), {
|
|
672
|
+
action: "api",
|
|
673
|
+
status: "ok",
|
|
674
|
+
runId: loaded.manifest.runId,
|
|
675
|
+
artifactsRoot: loaded.manifest.artifactsRoot,
|
|
676
|
+
});
|
|
268
677
|
}
|
|
269
|
-
return result(JSON.stringify(await stopLiveAgent(agentId), null, 2), {
|
|
678
|
+
return result(JSON.stringify(await stopLiveAgent(agentId), null, 2), {
|
|
679
|
+
action: "api",
|
|
680
|
+
status: "ok",
|
|
681
|
+
runId: loaded.manifest.runId,
|
|
682
|
+
artifactsRoot: loaded.manifest.artifactsRoot,
|
|
683
|
+
});
|
|
270
684
|
} catch (error) {
|
|
271
685
|
const agent = readCrewAgents(loaded.manifest).find((item) => item.id === agentId || item.taskId === agentId);
|
|
272
686
|
if (!agent) {
|
|
273
687
|
const err = error instanceof Error ? error.message : String(error);
|
|
274
|
-
return result(
|
|
688
|
+
return result(
|
|
689
|
+
err,
|
|
690
|
+
{
|
|
691
|
+
action: "api",
|
|
692
|
+
status: "error",
|
|
693
|
+
runId: loaded.manifest.runId,
|
|
694
|
+
},
|
|
695
|
+
true,
|
|
696
|
+
);
|
|
275
697
|
}
|
|
276
698
|
const task = loaded.tasks.find((item) => item.id === agent.taskId);
|
|
277
|
-
if (!task)
|
|
278
|
-
|
|
279
|
-
|
|
699
|
+
if (!task)
|
|
700
|
+
return result(
|
|
701
|
+
`API ${operation} agent '${agentId}' does not match a run task.`,
|
|
702
|
+
{
|
|
703
|
+
action: "api",
|
|
704
|
+
status: "error",
|
|
705
|
+
runId: loaded.manifest.runId,
|
|
706
|
+
},
|
|
707
|
+
true,
|
|
708
|
+
);
|
|
709
|
+
if (operation === "resume-agent" && !prompt)
|
|
710
|
+
return result(
|
|
711
|
+
"API resume-agent requires config.prompt or config.message.",
|
|
712
|
+
{
|
|
713
|
+
action: "api",
|
|
714
|
+
status: "error",
|
|
715
|
+
runId: loaded.manifest.runId,
|
|
716
|
+
},
|
|
717
|
+
true,
|
|
718
|
+
);
|
|
719
|
+
if (operation === "follow-up-agent" && !prompt)
|
|
720
|
+
return result(
|
|
721
|
+
"API follow-up-agent requires config.prompt or config.message.",
|
|
722
|
+
{
|
|
723
|
+
action: "api",
|
|
724
|
+
status: "error",
|
|
725
|
+
runId: loaded.manifest.runId,
|
|
726
|
+
},
|
|
727
|
+
true,
|
|
728
|
+
);
|
|
280
729
|
try {
|
|
281
|
-
const request = appendLiveAgentControlRequest(loaded.manifest, {
|
|
282
|
-
|
|
730
|
+
const request = appendLiveAgentControlRequest(loaded.manifest, {
|
|
731
|
+
taskId: task.id,
|
|
732
|
+
agentId: agent.id,
|
|
733
|
+
operation:
|
|
734
|
+
operation === "resume-agent"
|
|
735
|
+
? "resume"
|
|
736
|
+
: operation === "follow-up-agent"
|
|
737
|
+
? "follow-up"
|
|
738
|
+
: operation === "steer-agent"
|
|
739
|
+
? "steer"
|
|
740
|
+
: "stop",
|
|
741
|
+
message: operation === "resume-agent" || operation === "follow-up-agent" ? prompt : message,
|
|
742
|
+
});
|
|
743
|
+
const mailboxMessage =
|
|
744
|
+
operation === "steer-agent"
|
|
745
|
+
? appendSteeringMessage(loaded.manifest, {
|
|
746
|
+
taskId: task.id,
|
|
747
|
+
to: agent.id,
|
|
748
|
+
body: message ?? "Please report current status and wrap up if possible.",
|
|
749
|
+
status: "delivered",
|
|
750
|
+
data: {
|
|
751
|
+
source: "steer-agent",
|
|
752
|
+
liveControlRequestId: request.id,
|
|
753
|
+
},
|
|
754
|
+
})
|
|
755
|
+
: operation === "follow-up-agent" && prompt
|
|
756
|
+
? appendFollowUpMessage(loaded.manifest, {
|
|
757
|
+
taskId: task.id,
|
|
758
|
+
to: agent.id,
|
|
759
|
+
body: prompt,
|
|
760
|
+
status: "delivered",
|
|
761
|
+
data: {
|
|
762
|
+
source: "follow-up-agent",
|
|
763
|
+
liveControlRequestId: request.id,
|
|
764
|
+
},
|
|
765
|
+
})
|
|
766
|
+
: undefined;
|
|
283
767
|
publishLiveControlRealtime(request);
|
|
284
768
|
ctx.events?.emit?.("pi-crew:live-control", liveControlRealtimeMessage(request));
|
|
285
|
-
appendEvent(loaded.manifest.eventsPath, {
|
|
286
|
-
|
|
769
|
+
appendEvent(loaded.manifest.eventsPath, {
|
|
770
|
+
type: "agent.control.queued",
|
|
771
|
+
runId: loaded.manifest.runId,
|
|
772
|
+
taskId: agent.taskId,
|
|
773
|
+
message: `Queued ${request.operation} control request for live agent.`,
|
|
774
|
+
data: {
|
|
775
|
+
request,
|
|
776
|
+
mailboxMessageId: mailboxMessage?.id,
|
|
777
|
+
realtime: true,
|
|
778
|
+
},
|
|
779
|
+
});
|
|
780
|
+
return result(JSON.stringify({ queued: true, request, mailboxMessage }, null, 2), {
|
|
781
|
+
action: "api",
|
|
782
|
+
status: "ok",
|
|
783
|
+
runId: loaded.manifest.runId,
|
|
784
|
+
artifactsRoot: loaded.manifest.artifactsRoot,
|
|
785
|
+
});
|
|
287
786
|
} catch (queueError) {
|
|
288
787
|
const message = queueError instanceof Error ? queueError.message : String(queueError);
|
|
289
|
-
return result(
|
|
788
|
+
return result(
|
|
789
|
+
message,
|
|
790
|
+
{
|
|
791
|
+
action: "api",
|
|
792
|
+
status: "error",
|
|
793
|
+
runId: loaded.manifest.runId,
|
|
794
|
+
},
|
|
795
|
+
true,
|
|
796
|
+
);
|
|
290
797
|
}
|
|
291
798
|
}
|
|
292
799
|
}
|
|
293
800
|
if (operation === "read-mailbox") {
|
|
294
|
-
const direction = cfg.direction === "inbox" || cfg.direction === "outbox" ? cfg.direction as MailboxDirection : undefined;
|
|
801
|
+
const direction = cfg.direction === "inbox" || cfg.direction === "outbox" ? (cfg.direction as MailboxDirection) : undefined;
|
|
295
802
|
const taskId = typeof cfg.taskId === "string" ? cfg.taskId : undefined;
|
|
296
|
-
const kind =
|
|
297
|
-
|
|
803
|
+
const kind =
|
|
804
|
+
typeof cfg.kind === "string" && ["message", "steer", "follow-up", "response", "group_join"].includes(cfg.kind)
|
|
805
|
+
? (cfg.kind as MailboxMessageKind)
|
|
806
|
+
: undefined;
|
|
807
|
+
if (taskId && !loaded.tasks.some((task) => task.id === taskId))
|
|
808
|
+
return result(
|
|
809
|
+
`API read-mailbox taskId '${taskId}' does not match a run task.`,
|
|
810
|
+
{
|
|
811
|
+
action: "api",
|
|
812
|
+
status: "error",
|
|
813
|
+
runId: loaded.manifest.runId,
|
|
814
|
+
},
|
|
815
|
+
true,
|
|
816
|
+
);
|
|
298
817
|
try {
|
|
299
|
-
return result(JSON.stringify(readMailbox(loaded.manifest, direction, taskId, kind), null, 2), {
|
|
818
|
+
return result(JSON.stringify(readMailbox(loaded.manifest, direction, taskId, kind), null, 2), {
|
|
819
|
+
action: "api",
|
|
820
|
+
status: "ok",
|
|
821
|
+
runId: loaded.manifest.runId,
|
|
822
|
+
artifactsRoot: loaded.manifest.artifactsRoot,
|
|
823
|
+
});
|
|
300
824
|
} catch (error) {
|
|
301
825
|
const message = error instanceof Error ? error.message : String(error);
|
|
302
|
-
return result(
|
|
826
|
+
return result(
|
|
827
|
+
message,
|
|
828
|
+
{
|
|
829
|
+
action: "api",
|
|
830
|
+
status: "error",
|
|
831
|
+
runId: loaded.manifest.runId,
|
|
832
|
+
},
|
|
833
|
+
true,
|
|
834
|
+
);
|
|
303
835
|
}
|
|
304
836
|
}
|
|
305
837
|
if (operation === "validate-mailbox") {
|
|
306
|
-
const report = validateMailbox(loaded.manifest, {
|
|
307
|
-
|
|
838
|
+
const report = validateMailbox(loaded.manifest, {
|
|
839
|
+
repair: cfg.repair === true,
|
|
840
|
+
});
|
|
841
|
+
return result(
|
|
842
|
+
JSON.stringify(report, null, 2),
|
|
843
|
+
{
|
|
844
|
+
action: "api",
|
|
845
|
+
status: report.issues.some((issue) => issue.level === "error") && cfg.repair !== true ? "error" : "ok",
|
|
846
|
+
runId: loaded.manifest.runId,
|
|
847
|
+
artifactsRoot: loaded.manifest.artifactsRoot,
|
|
848
|
+
},
|
|
849
|
+
report.issues.some((issue) => issue.level === "error") && cfg.repair !== true,
|
|
850
|
+
);
|
|
308
851
|
}
|
|
309
852
|
if (operation === "read-delivery") {
|
|
310
|
-
return result(JSON.stringify(readDeliveryState(loaded.manifest), null, 2), {
|
|
853
|
+
return result(JSON.stringify(readDeliveryState(loaded.manifest), null, 2), {
|
|
854
|
+
action: "api",
|
|
855
|
+
status: "ok",
|
|
856
|
+
runId: loaded.manifest.runId,
|
|
857
|
+
artifactsRoot: loaded.manifest.artifactsRoot,
|
|
858
|
+
});
|
|
311
859
|
}
|
|
312
860
|
if (operation === "send-message") {
|
|
313
861
|
const direction = cfg.direction === "outbox" ? "outbox" : "inbox";
|
|
@@ -315,67 +863,198 @@ export async function handleApi(params: TeamToolParamsValue, ctx: TeamContext):
|
|
|
315
863
|
const to = typeof cfg.to === "string" && cfg.to.trim() ? cfg.to.trim() : "leader";
|
|
316
864
|
const body = typeof cfg.body === "string" && cfg.body.trim() ? cfg.body : undefined;
|
|
317
865
|
const taskId = typeof cfg.taskId === "string" && cfg.taskId.trim() ? cfg.taskId.trim() : undefined;
|
|
318
|
-
if (!body)
|
|
319
|
-
|
|
866
|
+
if (!body)
|
|
867
|
+
return result(
|
|
868
|
+
"API send-message requires config.body.",
|
|
869
|
+
{
|
|
870
|
+
action: "api",
|
|
871
|
+
status: "error",
|
|
872
|
+
runId: loaded.manifest.runId,
|
|
873
|
+
},
|
|
874
|
+
true,
|
|
875
|
+
);
|
|
876
|
+
if (taskId && !loaded.tasks.some((task) => task.id === taskId))
|
|
877
|
+
return result(
|
|
878
|
+
`API send-message taskId '${taskId}' does not match a run task.`,
|
|
879
|
+
{
|
|
880
|
+
action: "api",
|
|
881
|
+
status: "error",
|
|
882
|
+
runId: loaded.manifest.runId,
|
|
883
|
+
},
|
|
884
|
+
true,
|
|
885
|
+
);
|
|
320
886
|
try {
|
|
321
887
|
return withRunLockSync(loaded.manifest, () => {
|
|
322
|
-
const message = appendMailboxMessage(loaded.manifest, {
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
888
|
+
const message = appendMailboxMessage(loaded.manifest, {
|
|
889
|
+
direction,
|
|
890
|
+
from,
|
|
891
|
+
to,
|
|
892
|
+
body,
|
|
893
|
+
taskId,
|
|
894
|
+
});
|
|
895
|
+
appendEvent(loaded.manifest.eventsPath, {
|
|
896
|
+
type: "mailbox.message",
|
|
897
|
+
runId: loaded.manifest.runId,
|
|
898
|
+
data: { id: message.id, direction, from, to },
|
|
899
|
+
});
|
|
900
|
+
ctx.events?.emit?.("crew.mailbox.message", {
|
|
901
|
+
runId: loaded.manifest.runId,
|
|
902
|
+
id: message.id,
|
|
903
|
+
direction,
|
|
904
|
+
from,
|
|
905
|
+
to,
|
|
906
|
+
taskId,
|
|
907
|
+
source: "send-message",
|
|
908
|
+
});
|
|
909
|
+
return result(JSON.stringify(message, null, 2), {
|
|
910
|
+
action: "api",
|
|
911
|
+
status: "ok",
|
|
912
|
+
runId: loaded.manifest.runId,
|
|
913
|
+
artifactsRoot: loaded.manifest.artifactsRoot,
|
|
914
|
+
});
|
|
326
915
|
});
|
|
327
916
|
} catch (error) {
|
|
328
917
|
const message = error instanceof Error ? error.message : String(error);
|
|
329
|
-
return result(
|
|
918
|
+
return result(
|
|
919
|
+
message,
|
|
920
|
+
{
|
|
921
|
+
action: "api",
|
|
922
|
+
status: "error",
|
|
923
|
+
runId: loaded.manifest.runId,
|
|
924
|
+
},
|
|
925
|
+
true,
|
|
926
|
+
);
|
|
330
927
|
}
|
|
331
928
|
}
|
|
332
929
|
if (operation === "ack-message") {
|
|
333
930
|
const messageId = typeof cfg.messageId === "string" ? cfg.messageId : undefined;
|
|
334
|
-
if (!messageId)
|
|
931
|
+
if (!messageId)
|
|
932
|
+
return result(
|
|
933
|
+
"API ack-message requires config.messageId.",
|
|
934
|
+
{
|
|
935
|
+
action: "api",
|
|
936
|
+
status: "error",
|
|
937
|
+
runId: loaded.manifest.runId,
|
|
938
|
+
},
|
|
939
|
+
true,
|
|
940
|
+
);
|
|
335
941
|
try {
|
|
336
942
|
return withRunLockSync(loaded.manifest, () => {
|
|
337
943
|
const message = readMailboxMessage(loaded.manifest, messageId);
|
|
338
944
|
const delivery = acknowledgeMailboxMessage(loaded.manifest, messageId);
|
|
339
|
-
appendEvent(loaded.manifest.eventsPath, {
|
|
945
|
+
appendEvent(loaded.manifest.eventsPath, {
|
|
946
|
+
type: "mailbox.acknowledged",
|
|
947
|
+
runId: loaded.manifest.runId,
|
|
948
|
+
data: { messageId },
|
|
949
|
+
});
|
|
340
950
|
if (message?.data?.kind === "group_join" && typeof message.data.requestId === "string") {
|
|
341
951
|
appendEvent(loaded.manifest.eventsPath, {
|
|
342
952
|
type: "agent.group_join.acknowledged",
|
|
343
953
|
runId: loaded.manifest.runId,
|
|
344
954
|
message: "Group join delivery acknowledged via mailbox ack.",
|
|
345
|
-
data: {
|
|
955
|
+
data: {
|
|
956
|
+
requestId: message.data.requestId,
|
|
957
|
+
messageId,
|
|
958
|
+
batchId: message.data.batchId,
|
|
959
|
+
partial: message.data.partial,
|
|
960
|
+
acknowledgedAt: delivery.updatedAt,
|
|
961
|
+
acknowledgedBy: "leader",
|
|
962
|
+
},
|
|
346
963
|
metadata: { provenance: "api" },
|
|
347
964
|
});
|
|
348
965
|
}
|
|
349
|
-
ctx.events?.emit?.("crew.mailbox.acknowledged", {
|
|
350
|
-
|
|
966
|
+
ctx.events?.emit?.("crew.mailbox.acknowledged", {
|
|
967
|
+
runId: loaded.manifest.runId,
|
|
968
|
+
messageId,
|
|
969
|
+
delivery,
|
|
970
|
+
});
|
|
971
|
+
return result(JSON.stringify(delivery, null, 2), {
|
|
972
|
+
action: "api",
|
|
973
|
+
status: "ok",
|
|
974
|
+
runId: loaded.manifest.runId,
|
|
975
|
+
artifactsRoot: loaded.manifest.artifactsRoot,
|
|
976
|
+
});
|
|
351
977
|
});
|
|
352
978
|
} catch (error) {
|
|
353
979
|
const message = error instanceof Error ? error.message : String(error);
|
|
354
|
-
return result(
|
|
980
|
+
return result(
|
|
981
|
+
message,
|
|
982
|
+
{
|
|
983
|
+
action: "api",
|
|
984
|
+
status: "error",
|
|
985
|
+
runId: loaded.manifest.runId,
|
|
986
|
+
},
|
|
987
|
+
true,
|
|
988
|
+
);
|
|
355
989
|
}
|
|
356
990
|
}
|
|
357
991
|
if (operation === "read-heartbeat") {
|
|
358
992
|
const taskId = typeof cfg.taskId === "string" ? cfg.taskId : undefined;
|
|
359
993
|
const task = loaded.tasks.find((item) => item.id === taskId || item.stepId === taskId);
|
|
360
|
-
if (!task)
|
|
361
|
-
|
|
994
|
+
if (!task)
|
|
995
|
+
return result(
|
|
996
|
+
"API read-heartbeat requires config.taskId matching a task id or step id.",
|
|
997
|
+
{
|
|
998
|
+
action: "api",
|
|
999
|
+
status: "error",
|
|
1000
|
+
runId: loaded.manifest.runId,
|
|
1001
|
+
},
|
|
1002
|
+
true,
|
|
1003
|
+
);
|
|
1004
|
+
return result(JSON.stringify(task.heartbeat ?? null, null, 2), {
|
|
1005
|
+
action: "api",
|
|
1006
|
+
status: "ok",
|
|
1007
|
+
runId: loaded.manifest.runId,
|
|
1008
|
+
artifactsRoot: loaded.manifest.artifactsRoot,
|
|
1009
|
+
});
|
|
362
1010
|
}
|
|
363
1011
|
if (operation === "claim-task") {
|
|
364
1012
|
const taskId = typeof cfg.taskId === "string" ? cfg.taskId : undefined;
|
|
365
1013
|
const owner = typeof cfg.owner === "string" ? cfg.owner : "api";
|
|
366
1014
|
const task = loaded.tasks.find((item) => item.id === taskId || item.stepId === taskId);
|
|
367
|
-
if (!task)
|
|
1015
|
+
if (!task)
|
|
1016
|
+
return result(
|
|
1017
|
+
"API claim-task requires config.taskId matching a task id or step id.",
|
|
1018
|
+
{
|
|
1019
|
+
action: "api",
|
|
1020
|
+
status: "error",
|
|
1021
|
+
runId: loaded.manifest.runId,
|
|
1022
|
+
},
|
|
1023
|
+
true,
|
|
1024
|
+
);
|
|
368
1025
|
try {
|
|
369
1026
|
return withRunLockSync(loaded.manifest, () => {
|
|
370
1027
|
const updatedTask = claimTask(task, owner);
|
|
371
|
-
const tasks = loaded.tasks.map((item) => item.id === task.id ? updatedTask : item);
|
|
1028
|
+
const tasks = loaded.tasks.map((item) => (item.id === task.id ? updatedTask : item));
|
|
372
1029
|
saveRunTasks(loaded.manifest, tasks);
|
|
373
|
-
appendEvent(loaded.manifest.eventsPath, {
|
|
374
|
-
|
|
1030
|
+
appendEvent(loaded.manifest.eventsPath, {
|
|
1031
|
+
type: "task.claimed",
|
|
1032
|
+
runId: loaded.manifest.runId,
|
|
1033
|
+
taskId: task.id,
|
|
1034
|
+
data: {
|
|
1035
|
+
owner,
|
|
1036
|
+
token: "[REDACTED]",
|
|
1037
|
+
leasedUntil: updatedTask.claim?.leasedUntil,
|
|
1038
|
+
},
|
|
1039
|
+
});
|
|
1040
|
+
return result(JSON.stringify(updatedTask.claim, null, 2), {
|
|
1041
|
+
action: "api",
|
|
1042
|
+
status: "ok",
|
|
1043
|
+
runId: loaded.manifest.runId,
|
|
1044
|
+
artifactsRoot: loaded.manifest.artifactsRoot,
|
|
1045
|
+
});
|
|
375
1046
|
});
|
|
376
1047
|
} catch (error) {
|
|
377
1048
|
const message = error instanceof Error ? error.message : String(error);
|
|
378
|
-
return result(
|
|
1049
|
+
return result(
|
|
1050
|
+
message,
|
|
1051
|
+
{
|
|
1052
|
+
action: "api",
|
|
1053
|
+
status: "error",
|
|
1054
|
+
runId: loaded.manifest.runId,
|
|
1055
|
+
},
|
|
1056
|
+
true,
|
|
1057
|
+
);
|
|
379
1058
|
}
|
|
380
1059
|
}
|
|
381
1060
|
if (operation === "release-task-claim") {
|
|
@@ -383,18 +1062,45 @@ export async function handleApi(params: TeamToolParamsValue, ctx: TeamContext):
|
|
|
383
1062
|
const owner = typeof cfg.owner === "string" ? cfg.owner : undefined;
|
|
384
1063
|
const token = typeof cfg.token === "string" ? cfg.token : undefined;
|
|
385
1064
|
const task = loaded.tasks.find((item) => item.id === taskId || item.stepId === taskId);
|
|
386
|
-
if (!task || !owner || !token)
|
|
1065
|
+
if (!task || !owner || !token)
|
|
1066
|
+
return result(
|
|
1067
|
+
"API release-task-claim requires config.taskId, config.owner, and config.token.",
|
|
1068
|
+
{
|
|
1069
|
+
action: "api",
|
|
1070
|
+
status: "error",
|
|
1071
|
+
runId: loaded.manifest.runId,
|
|
1072
|
+
},
|
|
1073
|
+
true,
|
|
1074
|
+
);
|
|
387
1075
|
try {
|
|
388
1076
|
return withRunLockSync(loaded.manifest, () => {
|
|
389
1077
|
const updatedTask = releaseTaskClaim(task, owner, token);
|
|
390
|
-
const tasks = loaded.tasks.map((item) => item.id === task.id ? updatedTask : item);
|
|
1078
|
+
const tasks = loaded.tasks.map((item) => (item.id === task.id ? updatedTask : item));
|
|
391
1079
|
saveRunTasks(loaded.manifest, tasks);
|
|
392
|
-
appendEvent(loaded.manifest.eventsPath, {
|
|
393
|
-
|
|
1080
|
+
appendEvent(loaded.manifest.eventsPath, {
|
|
1081
|
+
type: "task.claim_released",
|
|
1082
|
+
runId: loaded.manifest.runId,
|
|
1083
|
+
taskId: task.id,
|
|
1084
|
+
data: { owner },
|
|
1085
|
+
});
|
|
1086
|
+
return result(JSON.stringify(updatedTask, null, 2), {
|
|
1087
|
+
action: "api",
|
|
1088
|
+
status: "ok",
|
|
1089
|
+
runId: loaded.manifest.runId,
|
|
1090
|
+
artifactsRoot: loaded.manifest.artifactsRoot,
|
|
1091
|
+
});
|
|
394
1092
|
});
|
|
395
1093
|
} catch (error) {
|
|
396
1094
|
const message = error instanceof Error ? error.message : String(error);
|
|
397
|
-
return result(
|
|
1095
|
+
return result(
|
|
1096
|
+
message,
|
|
1097
|
+
{
|
|
1098
|
+
action: "api",
|
|
1099
|
+
status: "error",
|
|
1100
|
+
runId: loaded.manifest.runId,
|
|
1101
|
+
},
|
|
1102
|
+
true,
|
|
1103
|
+
);
|
|
398
1104
|
}
|
|
399
1105
|
}
|
|
400
1106
|
if (operation === "transition-task-status") {
|
|
@@ -403,42 +1109,118 @@ export async function handleApi(params: TeamToolParamsValue, ctx: TeamContext):
|
|
|
403
1109
|
const token = typeof cfg.token === "string" ? cfg.token : undefined;
|
|
404
1110
|
const to = cfg.status;
|
|
405
1111
|
const task = loaded.tasks.find((item) => item.id === taskId || item.stepId === taskId);
|
|
406
|
-
if (!task || !owner || !token || !isTeamTaskStatus(to))
|
|
407
|
-
|
|
1112
|
+
if (!task || !owner || !token || !isTeamTaskStatus(to))
|
|
1113
|
+
return result(
|
|
1114
|
+
"API transition-task-status requires config.taskId, config.owner, config.token, and valid config.status.",
|
|
1115
|
+
{
|
|
1116
|
+
action: "api",
|
|
1117
|
+
status: "error",
|
|
1118
|
+
runId: loaded.manifest.runId,
|
|
1119
|
+
},
|
|
1120
|
+
true,
|
|
1121
|
+
);
|
|
1122
|
+
if (!canTransitionTaskStatus(task.status, to))
|
|
1123
|
+
return result(
|
|
1124
|
+
`Invalid task status transition: ${task.status} -> ${to}`,
|
|
1125
|
+
{
|
|
1126
|
+
action: "api",
|
|
1127
|
+
status: "error",
|
|
1128
|
+
runId: loaded.manifest.runId,
|
|
1129
|
+
},
|
|
1130
|
+
true,
|
|
1131
|
+
);
|
|
408
1132
|
try {
|
|
409
1133
|
return withRunLockSync(loaded.manifest, () => {
|
|
410
1134
|
const updatedTask = transitionClaimedTaskStatus(task, owner, token, to);
|
|
411
|
-
const tasks = loaded.tasks.map((item) => item.id === task.id ? updatedTask : item);
|
|
1135
|
+
const tasks = loaded.tasks.map((item) => (item.id === task.id ? updatedTask : item));
|
|
412
1136
|
saveRunTasks(loaded.manifest, tasks);
|
|
413
|
-
appendEvent(loaded.manifest.eventsPath, {
|
|
414
|
-
|
|
1137
|
+
appendEvent(loaded.manifest.eventsPath, {
|
|
1138
|
+
type: "task.status_transitioned",
|
|
1139
|
+
runId: loaded.manifest.runId,
|
|
1140
|
+
taskId: task.id,
|
|
1141
|
+
data: { owner, status: to },
|
|
1142
|
+
});
|
|
1143
|
+
return result(JSON.stringify(updatedTask, null, 2), {
|
|
1144
|
+
action: "api",
|
|
1145
|
+
status: "ok",
|
|
1146
|
+
runId: loaded.manifest.runId,
|
|
1147
|
+
artifactsRoot: loaded.manifest.artifactsRoot,
|
|
1148
|
+
});
|
|
415
1149
|
});
|
|
416
1150
|
} catch (error) {
|
|
417
1151
|
const message = error instanceof Error ? error.message : String(error);
|
|
418
|
-
return result(
|
|
1152
|
+
return result(
|
|
1153
|
+
message,
|
|
1154
|
+
{
|
|
1155
|
+
action: "api",
|
|
1156
|
+
status: "error",
|
|
1157
|
+
runId: loaded.manifest.runId,
|
|
1158
|
+
},
|
|
1159
|
+
true,
|
|
1160
|
+
);
|
|
419
1161
|
}
|
|
420
1162
|
}
|
|
421
1163
|
if (operation === "write-heartbeat") {
|
|
422
1164
|
const taskId = typeof cfg.taskId === "string" ? cfg.taskId : undefined;
|
|
423
1165
|
const task = loaded.tasks.find((item) => item.id === taskId || item.stepId === taskId);
|
|
424
|
-
if (!task)
|
|
1166
|
+
if (!task)
|
|
1167
|
+
return result(
|
|
1168
|
+
"API write-heartbeat requires config.taskId matching a task id or step id.",
|
|
1169
|
+
{
|
|
1170
|
+
action: "api",
|
|
1171
|
+
status: "error",
|
|
1172
|
+
runId: loaded.manifest.runId,
|
|
1173
|
+
},
|
|
1174
|
+
true,
|
|
1175
|
+
);
|
|
425
1176
|
try {
|
|
426
1177
|
return withRunLockSync(loaded.manifest, () => {
|
|
427
|
-
const heartbeat = touchWorkerHeartbeat(
|
|
428
|
-
|
|
1178
|
+
const heartbeat = touchWorkerHeartbeat(
|
|
1179
|
+
task.heartbeat ?? {
|
|
1180
|
+
workerId: task.id,
|
|
1181
|
+
lastSeenAt: new Date().toISOString(),
|
|
1182
|
+
},
|
|
1183
|
+
{
|
|
1184
|
+
alive: typeof cfg.alive === "boolean" ? cfg.alive : undefined,
|
|
1185
|
+
},
|
|
1186
|
+
);
|
|
1187
|
+
const tasks = loaded.tasks.map((item) => (item.id === task.id ? { ...item, heartbeat } : item));
|
|
429
1188
|
saveRunTasks(loaded.manifest, tasks);
|
|
430
|
-
appendEvent(loaded.manifest.eventsPath, {
|
|
431
|
-
|
|
1189
|
+
appendEvent(loaded.manifest.eventsPath, {
|
|
1190
|
+
type: "worker.heartbeat",
|
|
1191
|
+
runId: loaded.manifest.runId,
|
|
1192
|
+
taskId: task.id,
|
|
1193
|
+
data: { ...heartbeat },
|
|
1194
|
+
});
|
|
1195
|
+
return result(JSON.stringify(heartbeat, null, 2), {
|
|
1196
|
+
action: "api",
|
|
1197
|
+
status: "ok",
|
|
1198
|
+
runId: loaded.manifest.runId,
|
|
1199
|
+
artifactsRoot: loaded.manifest.artifactsRoot,
|
|
1200
|
+
});
|
|
432
1201
|
});
|
|
433
1202
|
} catch (error) {
|
|
434
1203
|
const message = error instanceof Error ? error.message : String(error);
|
|
435
|
-
return result(
|
|
1204
|
+
return result(
|
|
1205
|
+
message,
|
|
1206
|
+
{
|
|
1207
|
+
action: "api",
|
|
1208
|
+
status: "error",
|
|
1209
|
+
runId: loaded.manifest.runId,
|
|
1210
|
+
},
|
|
1211
|
+
true,
|
|
1212
|
+
);
|
|
436
1213
|
}
|
|
437
1214
|
}
|
|
438
1215
|
if (operation === "diff") {
|
|
439
|
-
const diffArtifacts = loaded.manifest.artifacts.filter(a => a.kind === "diff" || a.kind === "patch");
|
|
1216
|
+
const diffArtifacts = loaded.manifest.artifacts.filter((a) => a.kind === "diff" || a.kind === "patch");
|
|
440
1217
|
if (diffArtifacts.length === 0) {
|
|
441
|
-
return result(`No diff artifacts found for run ${loaded.manifest.runId}. Diffs are captured in worktree mode.`, {
|
|
1218
|
+
return result(`No diff artifacts found for run ${loaded.manifest.runId}. Diffs are captured in worktree mode.`, {
|
|
1219
|
+
action: "api",
|
|
1220
|
+
status: "ok",
|
|
1221
|
+
runId: loaded.manifest.runId,
|
|
1222
|
+
intent: `diff ${loaded.manifest.runId}: no diffs`,
|
|
1223
|
+
});
|
|
442
1224
|
}
|
|
443
1225
|
const parts: string[] = [`Diff artifacts for run ${loaded.manifest.runId}:`];
|
|
444
1226
|
for (const artifact of diffArtifacts) {
|
|
@@ -448,7 +1230,13 @@ export async function handleApi(params: TeamToolParamsValue, ctx: TeamContext):
|
|
|
448
1230
|
parts.push(`\n--- ${artifact.path} ---\n${display}`);
|
|
449
1231
|
}
|
|
450
1232
|
}
|
|
451
|
-
return result(parts.join("\n"), {
|
|
1233
|
+
return result(parts.join("\n"), {
|
|
1234
|
+
action: "api",
|
|
1235
|
+
status: "ok",
|
|
1236
|
+
runId: loaded.manifest.runId,
|
|
1237
|
+
artifactsRoot: loaded.manifest.artifactsRoot,
|
|
1238
|
+
intent: `diff ${loaded.manifest.runId}`,
|
|
1239
|
+
});
|
|
452
1240
|
}
|
|
453
1241
|
return result(`Unknown API operation: ${operation}`, { action: "api", status: "error", runId: loaded.manifest.runId }, true);
|
|
454
1242
|
}
|