agentic-orchestrator 0.1.28 → 0.2.0
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/.claude/settings.local.json +46 -1
- package/.cortexrc +28 -0
- package/.github/agents/copilot-instructions.md +29 -0
- package/.github/copilot-instructions.md +93 -0
- package/.vscode/settings.json +13 -0
- package/.vscode/tms.code-snippets +223 -0
- package/AGENTS.md +72 -1
- package/Agentic-Orchestrator.iml +12 -11
- package/CLAUDE.md +72 -1
- package/CONSTITUTION.md +504 -0
- package/FUTURE-ENHANCEMENTS.md +85 -0
- package/NEXT-TASKS.md +25 -0
- package/PROMPTS.md +161 -0
- package/README.md +126 -29
- package/agentic/orchestrator/agents.yaml +4 -3
- package/agentic/orchestrator/defaults/policy.defaults.yaml +39 -3
- package/agentic/orchestrator/gates.yaml +15 -3
- package/agentic/orchestrator/policy.yaml +47 -3
- package/agentic/orchestrator/prompts/builder.system.md +69 -20
- package/agentic/orchestrator/prompts/planner-intake.system.md +149 -0
- package/agentic/orchestrator/prompts/planner.system.md +113 -40
- package/agentic/orchestrator/prompts/qa.system.md +73 -18
- package/agentic/orchestrator/prompts/reconciler.system.md +119 -0
- package/agentic/orchestrator/schemas/agents.schema.json +89 -1
- package/agentic/orchestrator/schemas/execution-control.schema.json +242 -0
- package/agentic/orchestrator/schemas/index.schema.json +234 -0
- package/agentic/orchestrator/schemas/intake.review.schema.json +82 -0
- package/agentic/orchestrator/schemas/organizer-ordering-artifact.schema.json +75 -0
- package/agentic/orchestrator/schemas/plan.schema.json +44 -0
- package/agentic/orchestrator/schemas/policy.schema.json +238 -9
- package/agentic/orchestrator/schemas/policy.user.schema.json +129 -1
- package/agentic/orchestrator/schemas/spec.manifest.bootstrap.schema.json +101 -0
- package/agentic/orchestrator/schemas/spec.manifest.verified.schema.json +80 -0
- package/agentic/orchestrator/schemas/state.schema.json +298 -3
- package/agentic/orchestrator/tools/catalog.json +145 -15
- package/agentic/orchestrator/tools/schemas/input/doctor.run.input.schema.json +18 -0
- package/agentic/orchestrator/tools/schemas/input/evidence.latest.input.schema.json +4 -0
- package/agentic/orchestrator/tools/schemas/input/evidence.verify_chain.input.schema.json +13 -0
- package/agentic/orchestrator/tools/schemas/input/feature.intake_submit.input.schema.json +11 -0
- package/agentic/orchestrator/tools/schemas/input/feature.question_answer.input.schema.json +15 -0
- package/agentic/orchestrator/tools/schemas/input/feature.question_create.input.schema.json +21 -0
- package/agentic/orchestrator/tools/schemas/input/feature.question_list.input.schema.json +13 -0
- package/agentic/orchestrator/tools/schemas/input/feature.ready_to_merge.input.schema.json +5 -0
- package/agentic/orchestrator/tools/schemas/input/feature.send_message.input.schema.json +1 -1
- package/agentic/orchestrator/tools/schemas/input/replay.timeline_get.input.schema.json +32 -0
- package/agentic/orchestrator/tools/schemas/input/repo.conflict_abort.input.schema.json +16 -0
- package/agentic/orchestrator/tools/schemas/input/repo.conflict_files.input.schema.json +16 -0
- package/agentic/orchestrator/tools/schemas/input/repo.reconcile_mainline.input.schema.json +37 -0
- package/agentic/orchestrator/tools/schemas/input/repo.resolve_conflict.input.schema.json +40 -0
- package/agentic/orchestrator/tools/schemas/input/runtime.execution_request_list.input.schema.json +7 -0
- package/agentic/orchestrator/tools/schemas/input/runtime.execution_request_submit.input.schema.json +25 -0
- package/agentic/orchestrator/tools/schemas/output/doctor.run.output.schema.json +34 -0
- package/agentic/orchestrator/tools/schemas/output/evidence.verify_chain.output.schema.json +23 -0
- package/agentic/orchestrator/tools/schemas/output/feature.get_context.output.schema.json +62 -2
- package/agentic/orchestrator/tools/schemas/output/feature.intake_submit.output.schema.json +24 -0
- package/agentic/orchestrator/tools/schemas/output/feature.question_answer.output.schema.json +21 -0
- package/agentic/orchestrator/tools/schemas/output/feature.question_create.output.schema.json +12 -0
- package/agentic/orchestrator/tools/schemas/output/feature.question_list.output.schema.json +14 -0
- package/agentic/orchestrator/tools/schemas/output/feature.ready_to_merge.output.schema.json +31 -0
- package/agentic/orchestrator/tools/schemas/output/feature.send_message.output.schema.json +8 -18
- package/agentic/orchestrator/tools/schemas/output/replay.timeline_get.output.schema.json +64 -0
- package/agentic/orchestrator/tools/schemas/output/repo.conflict_abort.output.schema.json +16 -0
- package/agentic/orchestrator/tools/schemas/output/repo.conflict_files.output.schema.json +22 -0
- package/agentic/orchestrator/tools/schemas/output/repo.reconcile_mainline.output.schema.json +61 -0
- package/agentic/orchestrator/tools/schemas/output/repo.resolve_conflict.output.schema.json +19 -0
- package/agentic/orchestrator/tools/schemas/output/report.dashboard.output.schema.json +26 -0
- package/agentic/orchestrator/tools/schemas/output/runtime.execution_request_list.output.schema.json +17 -0
- package/agentic/orchestrator/tools/schemas/output/runtime.execution_request_submit.output.schema.json +24 -0
- package/agentic/orchestrator/tools.md +13 -0
- package/apps/control-plane/scripts/validate-mcp-contracts.ts +1 -1
- package/apps/control-plane/src/application/kernel-tool-wiring.ts +140 -2
- package/apps/control-plane/src/application/services/activity-monitor-service.ts +44 -1
- package/apps/control-plane/src/application/services/bootstrap-manifest-generator-service.ts +251 -0
- package/apps/control-plane/src/application/services/checkpoint-service.ts +87 -27
- package/apps/control-plane/src/application/services/collision-override-service.ts +906 -0
- package/apps/control-plane/src/application/services/collision-queue-service.ts +129 -38
- package/apps/control-plane/src/application/services/cost-tracking-service.ts +94 -0
- package/apps/control-plane/src/application/services/execution-control-service.ts +599 -0
- package/apps/control-plane/src/application/services/feature-deletion-service.ts +37 -1
- package/apps/control-plane/src/application/services/feature-lifecycle-service.ts +182 -4
- package/apps/control-plane/src/application/services/feature-send-message-service.ts +17 -8
- package/apps/control-plane/src/application/services/feature-state-service.ts +191 -6
- package/apps/control-plane/src/application/services/gate-service.ts +121 -2
- package/apps/control-plane/src/application/services/git-reconciliation-service.ts +1591 -0
- package/apps/control-plane/src/application/services/intake-service.ts +1468 -0
- package/apps/control-plane/src/application/services/merge-service.ts +308 -17
- package/apps/control-plane/src/application/services/notifier-service.ts +3 -1
- package/apps/control-plane/src/application/services/performance-analytics-service.ts +75 -0
- package/apps/control-plane/src/application/services/plan-service.ts +336 -20
- package/apps/control-plane/src/application/services/question-service.ts +693 -0
- package/apps/control-plane/src/application/services/reactions-service.ts +73 -17
- package/apps/control-plane/src/application/services/replay-timeline-service.ts +295 -0
- package/apps/control-plane/src/application/services/reporting-service.ts +194 -10
- package/apps/control-plane/src/application/services/run-lease-service.ts +121 -5
- package/apps/control-plane/src/application/services/worktree-watchdog-service.ts +95 -8
- package/apps/control-plane/src/application/tools/tool-metadata.ts +7 -0
- package/apps/control-plane/src/application/usage-types.ts +138 -0
- package/apps/control-plane/src/cli/add-command-handler.ts +162 -0
- package/apps/control-plane/src/cli/answer-command-handler.ts +113 -0
- package/apps/control-plane/src/cli/attach-command-handler.ts +12 -3
- package/apps/control-plane/src/cli/cli-argument-parser.ts +133 -11
- package/apps/control-plane/src/cli/collision-command-handler.ts +113 -0
- package/apps/control-plane/src/cli/command-catalog.ts +479 -0
- package/apps/control-plane/src/cli/complete-command-handler.ts +23 -0
- package/apps/control-plane/src/cli/completion-command-handler.ts +25 -0
- package/apps/control-plane/src/cli/completion-resolver.ts +319 -0
- package/apps/control-plane/src/cli/completion-shell-renderer.ts +58 -0
- package/apps/control-plane/src/cli/dashboard-command-handler.ts +110 -1
- package/apps/control-plane/src/cli/dashboard-runtime-runner.ts +1036 -0
- package/apps/control-plane/src/cli/dashboard-runtime.ts +31 -0
- package/apps/control-plane/src/cli/help-command-handler.ts +17 -185
- package/apps/control-plane/src/cli/init-command-handler.ts +51 -6
- package/apps/control-plane/src/cli/merge-command-handler.ts +200 -0
- package/apps/control-plane/src/cli/questions-command-handler.ts +70 -0
- package/apps/control-plane/src/cli/replay-command-handler.ts +98 -0
- package/apps/control-plane/src/cli/resume-command-handler.ts +231 -16
- package/apps/control-plane/src/cli/retry-command-handler.ts +229 -17
- package/apps/control-plane/src/cli/retry-resume-decision.ts +75 -0
- package/apps/control-plane/src/cli/rollback-command-handler.ts +4 -2
- package/apps/control-plane/src/cli/run-command-handler.ts +35 -1
- package/apps/control-plane/src/cli/spec-ingestion-service.ts +45 -55
- package/apps/control-plane/src/cli/spec-preparation.ts +114 -0
- package/apps/control-plane/src/cli/spec-utils.ts +90 -11
- package/apps/control-plane/src/cli/status-command-handler.ts +122 -0
- package/apps/control-plane/src/cli/types.ts +41 -3
- package/apps/control-plane/src/core/collisions.ts +150 -31
- package/apps/control-plane/src/core/constants.ts +18 -1
- package/apps/control-plane/src/core/error-codes.ts +39 -0
- package/apps/control-plane/src/core/execution-control.ts +56 -0
- package/apps/control-plane/src/core/feature-resume-phase.ts +118 -0
- package/apps/control-plane/src/core/gate-freshness.ts +359 -0
- package/apps/control-plane/src/core/gate-log-extractor.ts +97 -0
- package/apps/control-plane/src/core/gates.ts +90 -1
- package/apps/control-plane/src/core/intake-artifacts.ts +295 -0
- package/apps/control-plane/src/core/kernel-types.ts +11 -0
- package/apps/control-plane/src/core/kernel.ts +604 -16
- package/apps/control-plane/src/core/mainline-conflict.ts +22 -0
- package/apps/control-plane/src/core/merge-repair.ts +149 -0
- package/apps/control-plane/src/core/path-layout.ts +46 -2
- package/apps/control-plane/src/core/path-rules.ts +11 -3
- package/apps/control-plane/src/core/plan-submit-recovery.ts +130 -0
- package/apps/control-plane/src/core/questions.ts +49 -0
- package/apps/control-plane/src/core/runtime-sessions.ts +4 -0
- package/apps/control-plane/src/core/schemas.ts +40 -1
- package/apps/control-plane/src/core/tool-caller.ts +25 -1
- package/apps/control-plane/src/core/utils/index-normalizer.ts +25 -4
- package/apps/control-plane/src/core/worktree-diff.ts +66 -0
- package/apps/control-plane/src/index.ts +29 -1
- package/apps/control-plane/src/interfaces/cli/bootstrap.ts +300 -6
- package/apps/control-plane/src/mcp/kernel-tool-executor.ts +17 -0
- package/apps/control-plane/src/mcp/tool-runtime.ts +63 -4
- package/apps/control-plane/src/providers/api-worker-provider.ts +62 -15
- package/apps/control-plane/src/providers/cli-worker-provider.ts +1037 -61
- package/apps/control-plane/src/providers/output-parsers/generic-output-parser.ts +99 -1
- package/apps/control-plane/src/providers/output-parsers/types.ts +2 -0
- package/apps/control-plane/src/providers/provider-defaults.ts +116 -7
- package/apps/control-plane/src/providers/providers.ts +225 -21
- package/apps/control-plane/src/providers/worker-provider-factory.ts +26 -2
- package/apps/control-plane/src/supervisor/artifact-stager.ts +52 -0
- package/apps/control-plane/src/supervisor/build-wave-executor.ts +477 -166
- package/apps/control-plane/src/supervisor/execution-enrollment-service.ts +408 -0
- package/apps/control-plane/src/supervisor/organizer-enrollment-scheduler.ts +117 -0
- package/apps/control-plane/src/supervisor/organizer-sidecar-service.ts +394 -0
- package/apps/control-plane/src/supervisor/plan-conformance-scorer.ts +2 -5
- package/apps/control-plane/src/supervisor/planner-phase.ts +85 -0
- package/apps/control-plane/src/supervisor/planning-wave-executor.ts +993 -64
- package/apps/control-plane/src/supervisor/prompt-bundle-loader.ts +20 -1
- package/apps/control-plane/src/supervisor/qa-wave-executor.ts +384 -177
- package/apps/control-plane/src/supervisor/run-coordinator.ts +723 -20
- package/apps/control-plane/src/supervisor/runtime.ts +485 -9
- package/apps/control-plane/src/supervisor/session-orchestrator.ts +220 -1
- package/apps/control-plane/src/supervisor/types.ts +152 -1
- package/apps/control-plane/src/supervisor/worker-decision-loop.ts +1030 -92
- package/apps/control-plane/test/activity-monitor.spec.ts +76 -0
- package/apps/control-plane/test/add-command-handler.spec.ts +189 -0
- package/apps/control-plane/test/application/services/feature-state-service.spec.ts +208 -0
- package/apps/control-plane/test/artifact-stager.spec.ts +93 -0
- package/apps/control-plane/test/batch-operations.spec.ts +58 -0
- package/apps/control-plane/test/bootstrap-edge-cases.spec.ts +50 -2
- package/apps/control-plane/test/bootstrap-manifest-generator-service.spec.ts +99 -0
- package/apps/control-plane/test/bootstrap.spec.ts +177 -4
- package/apps/control-plane/test/checkpoint-service.spec.ts +977 -29
- package/apps/control-plane/test/cli-argument-parser.spec.ts +119 -0
- package/apps/control-plane/test/cli-helpers.spec.ts +1202 -12
- package/apps/control-plane/test/cli.unit.spec.ts +797 -16
- package/apps/control-plane/test/collision-command-handler.spec.ts +182 -0
- package/apps/control-plane/test/collision-override-service.spec.ts +878 -0
- package/apps/control-plane/test/collision-queue.spec.ts +430 -2
- package/apps/control-plane/test/collisions.spec.ts +209 -1
- package/apps/control-plane/test/core-utils.spec.ts +61 -0
- package/apps/control-plane/test/cost-tracking.spec.ts +224 -0
- package/apps/control-plane/test/dashboard-api.integration.spec.ts +185 -5
- package/apps/control-plane/test/dashboard-client.spec.ts +948 -0
- package/apps/control-plane/test/dashboard-command.spec.ts +138 -6
- package/apps/control-plane/test/dashboard-runtime-runner.spec.ts +1550 -0
- package/apps/control-plane/test/dashboard-runtime.spec.ts +138 -0
- package/apps/control-plane/test/dashboard-ui-utils.spec.ts +56 -12
- package/apps/control-plane/test/dependency-scheduler.spec.ts +7 -1
- package/apps/control-plane/test/env-file.spec.ts +76 -0
- package/apps/control-plane/test/execution-control-service.spec.ts +535 -0
- package/apps/control-plane/test/execution-enrollment-service.spec.ts +648 -0
- package/apps/control-plane/test/feature-lifecycle.spec.ts +126 -0
- package/apps/control-plane/test/feature-resume-phase.spec.ts +164 -0
- package/apps/control-plane/test/feature-send-message-service.spec.ts +161 -0
- package/apps/control-plane/test/feature-state-service.spec.ts +295 -0
- package/apps/control-plane/test/fs.spec.ts +80 -0
- package/apps/control-plane/test/gate-freshness.spec.ts +590 -0
- package/apps/control-plane/test/gate-log-extractor.spec.ts +170 -0
- package/apps/control-plane/test/gates.spec.ts +108 -0
- package/apps/control-plane/test/git-reconciliation-service.spec.ts +2307 -0
- package/apps/control-plane/test/helpers.ts +65 -0
- package/apps/control-plane/test/incremental-gates.spec.ts +271 -0
- package/apps/control-plane/test/index-normalizer.spec.ts +98 -0
- package/apps/control-plane/test/init-wizard.spec.ts +17 -0
- package/apps/control-plane/test/intake-artifacts.spec.ts +203 -0
- package/apps/control-plane/test/intake-service.spec.ts +3176 -0
- package/apps/control-plane/test/kernel-collision-replay.spec.ts +3 -2
- package/apps/control-plane/test/kernel-tool-executor.spec.ts +77 -0
- package/apps/control-plane/test/kernel-tool-wiring.spec.ts +279 -0
- package/apps/control-plane/test/kernel.branches.spec.ts +15 -2
- package/apps/control-plane/test/kernel.coverage.spec.ts +7 -3
- package/apps/control-plane/test/kernel.coverage2.spec.ts +731 -2
- package/apps/control-plane/test/kernel.spec.ts +464 -2
- package/apps/control-plane/test/mainline-conflict.spec.ts +66 -0
- package/apps/control-plane/test/mcp-helpers.spec.ts +79 -0
- package/apps/control-plane/test/mcp.spec.ts +177 -13
- package/apps/control-plane/test/merge-command-handler.spec.ts +531 -0
- package/apps/control-plane/test/merge-service.spec.ts +570 -4
- package/apps/control-plane/test/notifier-service.spec.ts +26 -0
- package/apps/control-plane/test/organizer-enrollment-scheduler.spec.ts +340 -0
- package/apps/control-plane/test/organizer-ordering-artifact.spec.ts +95 -0
- package/apps/control-plane/test/organizer-sidecar-service.spec.ts +468 -0
- package/apps/control-plane/test/output-loop-detector.spec.ts +6 -0
- package/apps/control-plane/test/path-layout.spec.ts +70 -0
- package/apps/control-plane/test/performance-analytics.spec.ts +124 -0
- package/apps/control-plane/test/plan-conformance-scorer.spec.ts +53 -0
- package/apps/control-plane/test/plan-service.spec.ts +686 -4
- package/apps/control-plane/test/planning-wave-executor.spec.ts +3272 -86
- package/apps/control-plane/test/policy-loader-service.spec.ts +5 -0
- package/apps/control-plane/test/prompt-overlay.spec.ts +65 -0
- package/apps/control-plane/test/provider-command-runner-epipe.spec.ts +64 -0
- package/apps/control-plane/test/providers/api-worker-provider.spec.ts +129 -0
- package/apps/control-plane/test/providers/cli-worker-provider.spec.ts +148 -0
- package/apps/control-plane/test/providers/usage-types.spec.ts +98 -0
- package/apps/control-plane/test/providers.spec.ts +293 -16
- package/apps/control-plane/test/question-command-handlers.spec.ts +156 -0
- package/apps/control-plane/test/question-service.spec.ts +1119 -0
- package/apps/control-plane/test/reactions.spec.ts +114 -0
- package/apps/control-plane/test/replay-command-handler.spec.ts +144 -0
- package/apps/control-plane/test/replay-timeline-service.spec.ts +459 -0
- package/apps/control-plane/test/response.spec.ts +31 -0
- package/apps/control-plane/test/resume-command.spec.ts +757 -9
- package/apps/control-plane/test/retry-resume-decision.spec.ts +133 -0
- package/apps/control-plane/test/rollback-command-handler.spec.ts +334 -0
- package/apps/control-plane/test/rollback-command.spec.ts +120 -0
- package/apps/control-plane/test/run-coordinator.spec.ts +3062 -404
- package/apps/control-plane/test/schemas/state.schema.spec.ts +71 -0
- package/apps/control-plane/test/service-retry-paths.spec.ts +112 -0
- package/apps/control-plane/test/services.spec.ts +472 -2
- package/apps/control-plane/test/session-management.spec.ts +346 -1
- package/apps/control-plane/test/spec-ingestion.spec.ts +102 -28
- package/apps/control-plane/test/spec-preparation.spec.ts +182 -0
- package/apps/control-plane/test/supervisor-collaborators.spec.ts +191 -3
- package/apps/control-plane/test/supervisor.calltool.spec.ts +198 -0
- package/apps/control-plane/test/supervisor.spec.ts +95 -16
- package/apps/control-plane/test/supervisor.unit.spec.ts +385 -18
- package/apps/control-plane/test/tool-runtime.spec.ts +122 -0
- package/apps/control-plane/test/worker-decision-loop.spec.ts +3479 -476
- package/apps/control-plane/test/worker-execution-policy.spec.ts +1416 -6
- package/apps/control-plane/test/worker-provider-adapters.spec.ts +1894 -37
- package/apps/control-plane/test/worker-provider-factory.spec.ts +81 -0
- package/apps/control-plane/test/worktree-watchdog-service.spec.ts +125 -0
- package/apps/control-plane/vitest.config.ts +5 -0
- package/config/agentic/orchestrator/agents.yaml +22 -1
- package/config/agentic/orchestrator/gates.yaml +24 -7
- package/config/agentic/orchestrator/policy.yaml +23 -1
- package/config/agentic/orchestrator/prompts/builder.system.md +69 -20
- package/config/agentic/orchestrator/prompts/organizer.system.md +85 -0
- package/config/agentic/orchestrator/prompts/overrides/builder.claude.md +28 -0
- package/config/agentic/orchestrator/prompts/overrides/builder.codex.md +28 -0
- package/config/agentic/orchestrator/prompts/overrides/planner.claude.md +20 -0
- package/config/agentic/orchestrator/prompts/overrides/planner.codex.md +20 -0
- package/config/agentic/orchestrator/prompts/planner-intake.system.md +149 -0
- package/config/agentic/orchestrator/prompts/planner.system.md +113 -40
- package/config/agentic/orchestrator/prompts/qa.system.md +75 -18
- package/config/agentic/orchestrator/prompts/reconciler.system.md +119 -0
- package/dist/apps/control-plane/application/kernel-tool-wiring.d.ts +26 -2
- package/dist/apps/control-plane/application/kernel-tool-wiring.js +40 -2
- package/dist/apps/control-plane/application/kernel-tool-wiring.js.map +1 -1
- package/dist/apps/control-plane/application/services/activity-monitor-service.js +37 -1
- package/dist/apps/control-plane/application/services/activity-monitor-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/bootstrap-manifest-generator-service.d.ts +4 -0
- package/dist/apps/control-plane/application/services/bootstrap-manifest-generator-service.js +188 -0
- package/dist/apps/control-plane/application/services/bootstrap-manifest-generator-service.js.map +1 -0
- package/dist/apps/control-plane/application/services/checkpoint-service.d.ts +5 -0
- package/dist/apps/control-plane/application/services/checkpoint-service.js +69 -24
- package/dist/apps/control-plane/application/services/checkpoint-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/collision-override-service.d.ts +139 -0
- package/dist/apps/control-plane/application/services/collision-override-service.js +568 -0
- package/dist/apps/control-plane/application/services/collision-override-service.js.map +1 -0
- package/dist/apps/control-plane/application/services/collision-queue-service.d.ts +15 -0
- package/dist/apps/control-plane/application/services/collision-queue-service.js +92 -33
- package/dist/apps/control-plane/application/services/collision-queue-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/cost-tracking-service.d.ts +11 -0
- package/dist/apps/control-plane/application/services/cost-tracking-service.js +75 -0
- package/dist/apps/control-plane/application/services/cost-tracking-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/execution-control-service.d.ts +75 -0
- package/dist/apps/control-plane/application/services/execution-control-service.js +421 -0
- package/dist/apps/control-plane/application/services/execution-control-service.js.map +1 -0
- package/dist/apps/control-plane/application/services/feature-deletion-service.d.ts +1 -0
- package/dist/apps/control-plane/application/services/feature-deletion-service.js +23 -1
- package/dist/apps/control-plane/application/services/feature-deletion-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/feature-lifecycle-service.d.ts +24 -1
- package/dist/apps/control-plane/application/services/feature-lifecycle-service.js +132 -3
- package/dist/apps/control-plane/application/services/feature-lifecycle-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/feature-send-message-service.js +16 -8
- package/dist/apps/control-plane/application/services/feature-send-message-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/feature-state-service.d.ts +36 -0
- package/dist/apps/control-plane/application/services/feature-state-service.js +163 -6
- package/dist/apps/control-plane/application/services/feature-state-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/gate-service.d.ts +2 -1
- package/dist/apps/control-plane/application/services/gate-service.js +95 -5
- package/dist/apps/control-plane/application/services/gate-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/git-reconciliation-service.d.ts +92 -0
- package/dist/apps/control-plane/application/services/git-reconciliation-service.js +1097 -0
- package/dist/apps/control-plane/application/services/git-reconciliation-service.js.map +1 -0
- package/dist/apps/control-plane/application/services/intake-service.d.ts +63 -0
- package/dist/apps/control-plane/application/services/intake-service.js +1050 -0
- package/dist/apps/control-plane/application/services/intake-service.js.map +1 -0
- package/dist/apps/control-plane/application/services/merge-service.d.ts +5 -1
- package/dist/apps/control-plane/application/services/merge-service.js +233 -18
- package/dist/apps/control-plane/application/services/merge-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/notifier-service.d.ts +1 -1
- package/dist/apps/control-plane/application/services/notifier-service.js +1 -0
- package/dist/apps/control-plane/application/services/notifier-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/performance-analytics-service.d.ts +11 -0
- package/dist/apps/control-plane/application/services/performance-analytics-service.js +59 -0
- package/dist/apps/control-plane/application/services/performance-analytics-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/plan-service.d.ts +5 -0
- package/dist/apps/control-plane/application/services/plan-service.js +254 -15
- package/dist/apps/control-plane/application/services/plan-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/question-service.d.ts +72 -0
- package/dist/apps/control-plane/application/services/question-service.js +507 -0
- package/dist/apps/control-plane/application/services/question-service.js.map +1 -0
- package/dist/apps/control-plane/application/services/reactions-service.d.ts +2 -0
- package/dist/apps/control-plane/application/services/reactions-service.js +60 -17
- package/dist/apps/control-plane/application/services/reactions-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/replay-timeline-service.d.ts +39 -0
- package/dist/apps/control-plane/application/services/replay-timeline-service.js +205 -0
- package/dist/apps/control-plane/application/services/replay-timeline-service.js.map +1 -0
- package/dist/apps/control-plane/application/services/reporting-service.d.ts +59 -0
- package/dist/apps/control-plane/application/services/reporting-service.js +121 -9
- package/dist/apps/control-plane/application/services/reporting-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/run-lease-service.d.ts +20 -0
- package/dist/apps/control-plane/application/services/run-lease-service.js +81 -4
- package/dist/apps/control-plane/application/services/run-lease-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/worktree-watchdog-service.d.ts +10 -0
- package/dist/apps/control-plane/application/services/worktree-watchdog-service.js +65 -8
- package/dist/apps/control-plane/application/services/worktree-watchdog-service.js.map +1 -1
- package/dist/apps/control-plane/application/tools/tool-metadata.js +7 -0
- package/dist/apps/control-plane/application/tools/tool-metadata.js.map +1 -1
- package/dist/apps/control-plane/application/usage-types.d.ts +65 -0
- package/dist/apps/control-plane/application/usage-types.js +75 -0
- package/dist/apps/control-plane/application/usage-types.js.map +1 -0
- package/dist/apps/control-plane/cli/add-command-handler.d.ts +18 -0
- package/dist/apps/control-plane/cli/add-command-handler.js +110 -0
- package/dist/apps/control-plane/cli/add-command-handler.js.map +1 -0
- package/dist/apps/control-plane/cli/answer-command-handler.d.ts +8 -0
- package/dist/apps/control-plane/cli/answer-command-handler.js +96 -0
- package/dist/apps/control-plane/cli/answer-command-handler.js.map +1 -0
- package/dist/apps/control-plane/cli/attach-command-handler.js +8 -3
- package/dist/apps/control-plane/cli/attach-command-handler.js.map +1 -1
- package/dist/apps/control-plane/cli/cli-argument-parser.js +131 -11
- package/dist/apps/control-plane/cli/cli-argument-parser.js.map +1 -1
- package/dist/apps/control-plane/cli/collision-command-handler.d.ts +8 -0
- package/dist/apps/control-plane/cli/collision-command-handler.js +90 -0
- package/dist/apps/control-plane/cli/collision-command-handler.js.map +1 -0
- package/dist/apps/control-plane/cli/command-catalog.d.ts +21 -0
- package/dist/apps/control-plane/cli/command-catalog.js +416 -0
- package/dist/apps/control-plane/cli/command-catalog.js.map +1 -0
- package/dist/apps/control-plane/cli/complete-command-handler.d.ts +15 -0
- package/dist/apps/control-plane/cli/complete-command-handler.js +26 -0
- package/dist/apps/control-plane/cli/complete-command-handler.js.map +1 -0
- package/dist/apps/control-plane/cli/completion-command-handler.d.ts +8 -0
- package/dist/apps/control-plane/cli/completion-command-handler.js +20 -0
- package/dist/apps/control-plane/cli/completion-command-handler.js.map +1 -0
- package/dist/apps/control-plane/cli/completion-resolver.d.ts +1 -0
- package/dist/apps/control-plane/cli/completion-resolver.js +250 -0
- package/dist/apps/control-plane/cli/completion-resolver.js.map +1 -0
- package/dist/apps/control-plane/cli/completion-shell-renderer.d.ts +3 -0
- package/dist/apps/control-plane/cli/completion-shell-renderer.js +53 -0
- package/dist/apps/control-plane/cli/completion-shell-renderer.js.map +1 -0
- package/dist/apps/control-plane/cli/dashboard-command-handler.d.ts +1 -0
- package/dist/apps/control-plane/cli/dashboard-command-handler.js +83 -1
- package/dist/apps/control-plane/cli/dashboard-command-handler.js.map +1 -1
- package/dist/apps/control-plane/cli/dashboard-runtime-runner.d.ts +81 -0
- package/dist/apps/control-plane/cli/dashboard-runtime-runner.js +724 -0
- package/dist/apps/control-plane/cli/dashboard-runtime-runner.js.map +1 -0
- package/dist/apps/control-plane/cli/dashboard-runtime.d.ts +1 -0
- package/dist/apps/control-plane/cli/dashboard-runtime.js +26 -0
- package/dist/apps/control-plane/cli/dashboard-runtime.js.map +1 -0
- package/dist/apps/control-plane/cli/help-command-handler.js +13 -172
- package/dist/apps/control-plane/cli/help-command-handler.js.map +1 -1
- package/dist/apps/control-plane/cli/init-command-handler.js +51 -6
- package/dist/apps/control-plane/cli/init-command-handler.js.map +1 -1
- package/dist/apps/control-plane/cli/merge-command-handler.d.ts +8 -0
- package/dist/apps/control-plane/cli/merge-command-handler.js +139 -0
- package/dist/apps/control-plane/cli/merge-command-handler.js.map +1 -0
- package/dist/apps/control-plane/cli/questions-command-handler.d.ts +8 -0
- package/dist/apps/control-plane/cli/questions-command-handler.js +59 -0
- package/dist/apps/control-plane/cli/questions-command-handler.js.map +1 -0
- package/dist/apps/control-plane/cli/replay-command-handler.d.ts +15 -0
- package/dist/apps/control-plane/cli/replay-command-handler.js +55 -0
- package/dist/apps/control-plane/cli/replay-command-handler.js.map +1 -0
- package/dist/apps/control-plane/cli/resume-command-handler.d.ts +2 -0
- package/dist/apps/control-plane/cli/resume-command-handler.js +180 -17
- package/dist/apps/control-plane/cli/resume-command-handler.js.map +1 -1
- package/dist/apps/control-plane/cli/retry-command-handler.js +202 -16
- package/dist/apps/control-plane/cli/retry-command-handler.js.map +1 -1
- package/dist/apps/control-plane/cli/retry-resume-decision.d.ts +26 -0
- package/dist/apps/control-plane/cli/retry-resume-decision.js +61 -0
- package/dist/apps/control-plane/cli/retry-resume-decision.js.map +1 -0
- package/dist/apps/control-plane/cli/rollback-command-handler.js +3 -2
- package/dist/apps/control-plane/cli/rollback-command-handler.js.map +1 -1
- package/dist/apps/control-plane/cli/run-command-handler.js +26 -2
- package/dist/apps/control-plane/cli/run-command-handler.js.map +1 -1
- package/dist/apps/control-plane/cli/spec-ingestion-service.d.ts +2 -0
- package/dist/apps/control-plane/cli/spec-ingestion-service.js +37 -48
- package/dist/apps/control-plane/cli/spec-ingestion-service.js.map +1 -1
- package/dist/apps/control-plane/cli/spec-preparation.d.ts +14 -0
- package/dist/apps/control-plane/cli/spec-preparation.js +81 -0
- package/dist/apps/control-plane/cli/spec-preparation.js.map +1 -0
- package/dist/apps/control-plane/cli/spec-utils.d.ts +4 -0
- package/dist/apps/control-plane/cli/spec-utils.js +70 -11
- package/dist/apps/control-plane/cli/spec-utils.js.map +1 -1
- package/dist/apps/control-plane/cli/status-command-handler.js +69 -0
- package/dist/apps/control-plane/cli/status-command-handler.js.map +1 -1
- package/dist/apps/control-plane/cli/types.d.ts +41 -4
- package/dist/apps/control-plane/cli/types.js +9 -1
- package/dist/apps/control-plane/cli/types.js.map +1 -1
- package/dist/apps/control-plane/core/collisions.d.ts +37 -19
- package/dist/apps/control-plane/core/collisions.js +87 -12
- package/dist/apps/control-plane/core/collisions.js.map +1 -1
- package/dist/apps/control-plane/core/constants.d.ts +17 -1
- package/dist/apps/control-plane/core/constants.js +18 -1
- package/dist/apps/control-plane/core/constants.js.map +1 -1
- package/dist/apps/control-plane/core/error-codes.d.ts +39 -0
- package/dist/apps/control-plane/core/error-codes.js +39 -0
- package/dist/apps/control-plane/core/error-codes.js.map +1 -1
- package/dist/apps/control-plane/core/execution-control.d.ts +45 -0
- package/dist/apps/control-plane/core/execution-control.js +2 -0
- package/dist/apps/control-plane/core/execution-control.js.map +1 -0
- package/dist/apps/control-plane/core/feature-resume-phase.d.ts +3 -0
- package/dist/apps/control-plane/core/feature-resume-phase.js +88 -0
- package/dist/apps/control-plane/core/feature-resume-phase.js.map +1 -0
- package/dist/apps/control-plane/core/gate-freshness.d.ts +48 -0
- package/dist/apps/control-plane/core/gate-freshness.js +267 -0
- package/dist/apps/control-plane/core/gate-freshness.js.map +1 -0
- package/dist/apps/control-plane/core/gate-log-extractor.d.ts +22 -0
- package/dist/apps/control-plane/core/gate-log-extractor.js +66 -0
- package/dist/apps/control-plane/core/gate-log-extractor.js.map +1 -0
- package/dist/apps/control-plane/core/gates.d.ts +11 -2
- package/dist/apps/control-plane/core/gates.js +67 -3
- package/dist/apps/control-plane/core/gates.js.map +1 -1
- package/dist/apps/control-plane/core/intake-artifacts.d.ts +109 -0
- package/dist/apps/control-plane/core/intake-artifacts.js +143 -0
- package/dist/apps/control-plane/core/intake-artifacts.js.map +1 -0
- package/dist/apps/control-plane/core/kernel-types.d.ts +8 -0
- package/dist/apps/control-plane/core/kernel.d.ts +256 -8
- package/dist/apps/control-plane/core/kernel.js +400 -14
- package/dist/apps/control-plane/core/kernel.js.map +1 -1
- package/dist/apps/control-plane/core/mainline-conflict.d.ts +7 -0
- package/dist/apps/control-plane/core/mainline-conflict.js +20 -0
- package/dist/apps/control-plane/core/mainline-conflict.js.map +1 -0
- package/dist/apps/control-plane/core/merge-repair.d.ts +35 -0
- package/dist/apps/control-plane/core/merge-repair.js +99 -0
- package/dist/apps/control-plane/core/merge-repair.js.map +1 -0
- package/dist/apps/control-plane/core/path-layout.d.ts +10 -0
- package/dist/apps/control-plane/core/path-layout.js +32 -2
- package/dist/apps/control-plane/core/path-layout.js.map +1 -1
- package/dist/apps/control-plane/core/path-rules.js +9 -3
- package/dist/apps/control-plane/core/path-rules.js.map +1 -1
- package/dist/apps/control-plane/core/plan-submit-recovery.d.ts +22 -0
- package/dist/apps/control-plane/core/plan-submit-recovery.js +78 -0
- package/dist/apps/control-plane/core/plan-submit-recovery.js.map +1 -0
- package/dist/apps/control-plane/core/questions.d.ts +40 -0
- package/dist/apps/control-plane/core/questions.js +2 -0
- package/dist/apps/control-plane/core/questions.js.map +1 -0
- package/dist/apps/control-plane/core/runtime-sessions.d.ts +4 -0
- package/dist/apps/control-plane/core/schemas.d.ts +2 -0
- package/dist/apps/control-plane/core/schemas.js +31 -1
- package/dist/apps/control-plane/core/schemas.js.map +1 -1
- package/dist/apps/control-plane/core/tool-caller.d.ts +18 -1
- package/dist/apps/control-plane/core/utils/index-normalizer.js +17 -4
- package/dist/apps/control-plane/core/utils/index-normalizer.js.map +1 -1
- package/dist/apps/control-plane/core/worktree-diff.d.ts +4 -0
- package/dist/apps/control-plane/core/worktree-diff.js +52 -0
- package/dist/apps/control-plane/core/worktree-diff.js.map +1 -0
- package/dist/apps/control-plane/index.d.ts +10 -2
- package/dist/apps/control-plane/index.js +9 -2
- package/dist/apps/control-plane/index.js.map +1 -1
- package/dist/apps/control-plane/interfaces/cli/bootstrap.js +236 -6
- package/dist/apps/control-plane/interfaces/cli/bootstrap.js.map +1 -1
- package/dist/apps/control-plane/mcp/kernel-tool-executor.js +16 -0
- package/dist/apps/control-plane/mcp/kernel-tool-executor.js.map +1 -1
- package/dist/apps/control-plane/mcp/tool-runtime.d.ts +5 -0
- package/dist/apps/control-plane/mcp/tool-runtime.js +40 -5
- package/dist/apps/control-plane/mcp/tool-runtime.js.map +1 -1
- package/dist/apps/control-plane/providers/api-worker-provider.d.ts +2 -2
- package/dist/apps/control-plane/providers/api-worker-provider.js +40 -9
- package/dist/apps/control-plane/providers/api-worker-provider.js.map +1 -1
- package/dist/apps/control-plane/providers/cli-worker-provider.d.ts +59 -3
- package/dist/apps/control-plane/providers/cli-worker-provider.js +758 -46
- package/dist/apps/control-plane/providers/cli-worker-provider.js.map +1 -1
- package/dist/apps/control-plane/providers/output-parsers/generic-output-parser.js +91 -1
- package/dist/apps/control-plane/providers/output-parsers/generic-output-parser.js.map +1 -1
- package/dist/apps/control-plane/providers/output-parsers/types.d.ts +2 -0
- package/dist/apps/control-plane/providers/provider-defaults.d.ts +12 -0
- package/dist/apps/control-plane/providers/provider-defaults.js +103 -7
- package/dist/apps/control-plane/providers/provider-defaults.js.map +1 -1
- package/dist/apps/control-plane/providers/providers.d.ts +50 -4
- package/dist/apps/control-plane/providers/providers.js +145 -14
- package/dist/apps/control-plane/providers/providers.js.map +1 -1
- package/dist/apps/control-plane/providers/worker-provider-factory.d.ts +2 -0
- package/dist/apps/control-plane/providers/worker-provider-factory.js +8 -1
- package/dist/apps/control-plane/providers/worker-provider-factory.js.map +1 -1
- package/dist/apps/control-plane/supervisor/artifact-stager.d.ts +5 -0
- package/dist/apps/control-plane/supervisor/artifact-stager.js +45 -0
- package/dist/apps/control-plane/supervisor/artifact-stager.js.map +1 -0
- package/dist/apps/control-plane/supervisor/build-wave-executor.d.ts +24 -1
- package/dist/apps/control-plane/supervisor/build-wave-executor.js +362 -150
- package/dist/apps/control-plane/supervisor/build-wave-executor.js.map +1 -1
- package/dist/apps/control-plane/supervisor/execution-enrollment-service.d.ts +41 -0
- package/dist/apps/control-plane/supervisor/execution-enrollment-service.js +311 -0
- package/dist/apps/control-plane/supervisor/execution-enrollment-service.js.map +1 -0
- package/dist/apps/control-plane/supervisor/organizer-enrollment-scheduler.d.ts +15 -0
- package/dist/apps/control-plane/supervisor/organizer-enrollment-scheduler.js +93 -0
- package/dist/apps/control-plane/supervisor/organizer-enrollment-scheduler.js.map +1 -0
- package/dist/apps/control-plane/supervisor/organizer-sidecar-service.d.ts +44 -0
- package/dist/apps/control-plane/supervisor/organizer-sidecar-service.js +311 -0
- package/dist/apps/control-plane/supervisor/organizer-sidecar-service.js.map +1 -0
- package/dist/apps/control-plane/supervisor/plan-conformance-scorer.js +2 -5
- package/dist/apps/control-plane/supervisor/plan-conformance-scorer.js.map +1 -1
- package/dist/apps/control-plane/supervisor/planner-phase.d.ts +3 -0
- package/dist/apps/control-plane/supervisor/planner-phase.js +70 -0
- package/dist/apps/control-plane/supervisor/planner-phase.js.map +1 -0
- package/dist/apps/control-plane/supervisor/planning-wave-executor.d.ts +42 -0
- package/dist/apps/control-plane/supervisor/planning-wave-executor.js +753 -55
- package/dist/apps/control-plane/supervisor/planning-wave-executor.js.map +1 -1
- package/dist/apps/control-plane/supervisor/prompt-bundle-loader.js +19 -1
- package/dist/apps/control-plane/supervisor/prompt-bundle-loader.js.map +1 -1
- package/dist/apps/control-plane/supervisor/qa-wave-executor.d.ts +21 -0
- package/dist/apps/control-plane/supervisor/qa-wave-executor.js +287 -156
- package/dist/apps/control-plane/supervisor/qa-wave-executor.js.map +1 -1
- package/dist/apps/control-plane/supervisor/run-coordinator.d.ts +30 -1
- package/dist/apps/control-plane/supervisor/run-coordinator.js +561 -17
- package/dist/apps/control-plane/supervisor/run-coordinator.js.map +1 -1
- package/dist/apps/control-plane/supervisor/runtime.d.ts +84 -0
- package/dist/apps/control-plane/supervisor/runtime.js +393 -3
- package/dist/apps/control-plane/supervisor/runtime.js.map +1 -1
- package/dist/apps/control-plane/supervisor/session-orchestrator.d.ts +54 -0
- package/dist/apps/control-plane/supervisor/session-orchestrator.js +176 -1
- package/dist/apps/control-plane/supervisor/session-orchestrator.js.map +1 -1
- package/dist/apps/control-plane/supervisor/types.d.ts +142 -1
- package/dist/apps/control-plane/supervisor/types.js.map +1 -1
- package/dist/apps/control-plane/supervisor/worker-decision-loop.d.ts +68 -2
- package/dist/apps/control-plane/supervisor/worker-decision-loop.js +723 -89
- package/dist/apps/control-plane/supervisor/worker-decision-loop.js.map +1 -1
- package/docs/core/ARCHITECTURE.md +227 -0
- package/docs/core/DECISIONS.md +94 -0
- package/docs/core/DOMAIN-LOGIC.md +60 -0
- package/docs/core/PATTERNS.md +201 -0
- package/docs/core/TROUBLESHOOTING.md +347 -0
- package/docs/core/intentgraph-dependencies.json +39860 -0
- package/docs/core/intentgraph.index.json +46580 -0
- package/docs/plans/2026-03-10-gate-failure-targeted-repair-design.md +224 -0
- package/docs/plans/2026-03-10-gate-failure-targeted-repair.md +1032 -0
- package/docs/superpowers/plans/2026-03-16-provider-cli-config.md +743 -0
- package/docs/superpowers/plans/2026-03-23-reconcile-divergence-fix.md +777 -0
- package/docs/superpowers/plans/2026-03-28-ordering-agent-implementation.md +1754 -0
- package/docs/superpowers/plans/2026-03-29-drop-zone-and-provider-optimization.md +1108 -0
- package/docs/superpowers/plans/2026-03-29-merge-target-feature-branch.md +685 -0
- package/docs/superpowers/plans/2026-03-29-organizer-sidecar-runtime-loop.md +1289 -0
- package/docs/superpowers/specs/2026-03-23-reconcile-divergence-fix-design.md +118 -0
- package/docs/superpowers/specs/2026-03-28-ordering-agent-spec-audit-design.md +50 -0
- package/docs/superpowers/specs/2026-03-29-drop-zone-and-provider-optimization-design.md +254 -0
- package/docs/superpowers/specs/2026-03-29-merge-target-feature-branch-design.md +152 -0
- package/docs/superpowers/specs/2026-03-29-organizer-sidecar-runtime-loop-design.md +225 -0
- package/package.json +3 -2
- package/packages/web-dashboard/package.json +2 -1
- package/packages/web-dashboard/src/app/analytics/page.tsx +36 -2
- package/packages/web-dashboard/src/app/api/actions/route.ts +274 -63
- package/packages/web-dashboard/src/app/api/actions/status/route.ts +35 -0
- package/packages/web-dashboard/src/app/api/analytics/provider/route.ts +18 -0
- package/packages/web-dashboard/src/app/api/collisions/approve/route.ts +58 -0
- package/packages/web-dashboard/src/app/api/features/[id]/checkpoint-diff/route.ts +36 -0
- package/packages/web-dashboard/src/app/api/features/[id]/checkpoints/route.ts +29 -0
- package/packages/web-dashboard/src/app/api/features/[id]/conflicts/abort/route.ts +29 -0
- package/packages/web-dashboard/src/app/api/features/[id]/conflicts/files/route.ts +30 -0
- package/packages/web-dashboard/src/app/api/features/[id]/conflicts/resolve/route.ts +51 -0
- package/packages/web-dashboard/src/app/api/features/[id]/conflicts/route.ts +75 -0
- package/packages/web-dashboard/src/app/api/features/[id]/diff/route.ts +16 -2
- package/packages/web-dashboard/src/app/api/features/[id]/files/route.ts +26 -0
- package/packages/web-dashboard/src/app/api/features/[id]/gate-history/route.ts +27 -0
- package/packages/web-dashboard/src/app/api/features/[id]/genealogy/route.ts +26 -0
- package/packages/web-dashboard/src/app/api/features/[id]/history/run/[runId]/route.ts +20 -0
- package/packages/web-dashboard/src/app/api/features/[id]/history/runs/route.ts +34 -0
- package/packages/web-dashboard/src/app/api/features/[id]/intake-workspace/route.ts +20 -0
- package/packages/web-dashboard/src/app/api/features/[id]/live-output/route.ts +74 -0
- package/packages/web-dashboard/src/app/api/features/[id]/plan/amend/route.ts +21 -0
- package/packages/web-dashboard/src/app/api/features/[id]/plan-progress/route.ts +20 -0
- package/packages/web-dashboard/src/app/api/features/[id]/planner-artifacts/[artifact]/route.ts +78 -0
- package/packages/web-dashboard/src/app/api/features/[id]/planner-lifecycle/route.ts +20 -0
- package/packages/web-dashboard/src/app/api/features/[id]/planning-workspace/route.ts +20 -0
- package/packages/web-dashboard/src/app/api/features/[id]/questions/[questionId]/answer/route.ts +27 -0
- package/packages/web-dashboard/src/app/api/features/[id]/questions/route.ts +18 -0
- package/packages/web-dashboard/src/app/api/features/[id]/review/route.ts +14 -7
- package/packages/web-dashboard/src/app/api/features/[id]/route.ts +57 -2
- package/packages/web-dashboard/src/app/api/features/[id]/spec/route.ts +30 -0
- package/packages/web-dashboard/src/app/api/features/[id]/triage/route.ts +83 -0
- package/packages/web-dashboard/src/app/api/features/[id]/worker-events/route.ts +40 -0
- package/packages/web-dashboard/src/app/api/launch/preview/route.ts +86 -0
- package/packages/web-dashboard/src/app/api/launch/submit/route.ts +180 -0
- package/packages/web-dashboard/src/app/api/mainline/status/route.ts +74 -0
- package/packages/web-dashboard/src/app/api/merge-queue/route.ts +13 -0
- package/packages/web-dashboard/src/app/api/policy/budget/route.ts +14 -0
- package/packages/web-dashboard/src/app/api/projects/route.ts +11 -7
- package/packages/web-dashboard/src/app/api/reconciler/queue/route.ts +47 -0
- package/packages/web-dashboard/src/app/api/run/route.ts +26 -2
- package/packages/web-dashboard/src/app/api/runtime/events/route.ts +227 -0
- package/packages/web-dashboard/src/app/api/runtime/operations/route.ts +269 -0
- package/packages/web-dashboard/src/app/api/runtime/questions/route.ts +11 -0
- package/packages/web-dashboard/src/app/api/runtime/runs/route.ts +80 -0
- package/packages/web-dashboard/src/app/api/status/route.ts +4 -2
- package/packages/web-dashboard/src/app/feature/[id]/page.tsx +32 -42
- package/packages/web-dashboard/src/app/globals.css +34 -3
- package/packages/web-dashboard/src/app/launch/page.tsx +357 -0
- package/packages/web-dashboard/src/app/layout.tsx +23 -1
- package/packages/web-dashboard/src/app/page.tsx +263 -272
- package/packages/web-dashboard/src/components/dashboard/attention-strip.tsx +52 -0
- package/packages/web-dashboard/src/components/dashboard/collision-approval-drawer.tsx +185 -0
- package/packages/web-dashboard/src/components/dashboard/command-center-header.tsx +102 -0
- package/packages/web-dashboard/src/components/dashboard/mainline-status-banner.tsx +84 -0
- package/packages/web-dashboard/src/components/dashboard/merged-archive.tsx +36 -0
- package/packages/web-dashboard/src/components/dashboard/prioritized-queues.tsx +98 -0
- package/packages/web-dashboard/src/components/dashboard/reconciler-queue-card.tsx +115 -0
- package/packages/web-dashboard/src/components/dashboard/secondary-diagnostics-rail.tsx +48 -0
- package/packages/web-dashboard/src/components/dashboard/task-filter-bar.tsx +74 -0
- package/packages/web-dashboard/src/components/dashboard/triage-drawer.tsx +455 -0
- package/packages/web-dashboard/src/components/diff-viewer.tsx +19 -3
- package/packages/web-dashboard/src/components/evidence-viewer.tsx +65 -51
- package/packages/web-dashboard/src/components/feature-card.tsx +90 -7
- package/packages/web-dashboard/src/components/feature-cost-panel.tsx +112 -11
- package/packages/web-dashboard/src/components/feature-list-view.tsx +25 -4
- package/packages/web-dashboard/src/components/features/runtime-inspector/EventsTimelineView.tsx +260 -0
- package/packages/web-dashboard/src/components/features/runtime-inspector/OperationsListView.tsx +172 -0
- package/packages/web-dashboard/src/components/features/runtime-inspector/RuntimeInspectorPanel.tsx +896 -0
- package/packages/web-dashboard/src/components/filter-bar.tsx +7 -39
- package/packages/web-dashboard/src/components/focus/ActionableRiskList.tsx +46 -0
- package/packages/web-dashboard/src/components/focus/AgentRolePerformanceCard.tsx +200 -0
- package/packages/web-dashboard/src/components/focus/BlockedGuidanceBanner.tsx +149 -0
- package/packages/web-dashboard/src/components/focus/CheckpointInspector.tsx +123 -0
- package/packages/web-dashboard/src/components/focus/CheckpointRail.tsx +118 -0
- package/packages/web-dashboard/src/components/focus/CheckpointScrubber.tsx +249 -0
- package/packages/web-dashboard/src/components/focus/CollisionApprovalBanner.tsx +192 -0
- package/packages/web-dashboard/src/components/focus/CollisionRadar.tsx +136 -0
- package/packages/web-dashboard/src/components/focus/ConflictStatusCard.tsx +52 -0
- package/packages/web-dashboard/src/components/focus/ContextSidebar.tsx +108 -0
- package/packages/web-dashboard/src/components/focus/DiagnosisPanel.tsx +68 -0
- package/packages/web-dashboard/src/components/focus/FeatureDecisionBanner.tsx +68 -0
- package/packages/web-dashboard/src/components/focus/FeatureQuestionAnswerPanel.tsx +167 -0
- package/packages/web-dashboard/src/components/focus/FocusHeader.tsx +54 -0
- package/packages/web-dashboard/src/components/focus/FocusLayout.tsx +283 -0
- package/packages/web-dashboard/src/components/focus/GateFlakinessSummary.tsx +144 -0
- package/packages/web-dashboard/src/components/focus/GenealogyTree.tsx +34 -0
- package/packages/web-dashboard/src/components/focus/HeroBlock.tsx +67 -0
- package/packages/web-dashboard/src/components/focus/LiveAgentConsole.tsx +277 -0
- package/packages/web-dashboard/src/components/focus/MergeQueueCard.tsx +78 -0
- package/packages/web-dashboard/src/components/focus/OperationalSummaryCard.tsx +227 -0
- package/packages/web-dashboard/src/components/focus/PinnedActions.tsx +96 -0
- package/packages/web-dashboard/src/components/focus/PlanAmendmentPanel.tsx +250 -0
- package/packages/web-dashboard/src/components/focus/PlanProgressPanel.tsx +133 -0
- package/packages/web-dashboard/src/components/focus/PlannerArtifactViewer.tsx +158 -0
- package/packages/web-dashboard/src/components/focus/PlannerLifecycleHeader.tsx +141 -0
- package/packages/web-dashboard/src/components/focus/ProgressSnapshotCard.tsx +113 -0
- package/packages/web-dashboard/src/components/focus/RecentMaterialChanges.tsx +69 -0
- package/packages/web-dashboard/src/components/focus/RoleLogViewer.tsx +436 -0
- package/packages/web-dashboard/src/components/focus/RunHistoryBrowser.tsx +62 -0
- package/packages/web-dashboard/src/components/focus/SpecViewer.tsx +172 -0
- package/packages/web-dashboard/src/components/focus/TabBar.tsx +33 -0
- package/packages/web-dashboard/src/components/focus/UsageBurnChart.tsx +212 -0
- package/packages/web-dashboard/src/components/focus/VerificationSummaryCard.tsx +122 -0
- package/packages/web-dashboard/src/components/focus/tabs/ChangesTab.tsx +325 -0
- package/packages/web-dashboard/src/components/focus/tabs/ConflictsTab.tsx +395 -0
- package/packages/web-dashboard/src/components/focus/tabs/GatesQaTab.tsx +38 -0
- package/packages/web-dashboard/src/components/focus/tabs/HistoryTab.tsx +213 -0
- package/packages/web-dashboard/src/components/focus/tabs/IntakeTab.tsx +429 -0
- package/packages/web-dashboard/src/components/focus/tabs/OverviewTab.tsx +217 -0
- package/packages/web-dashboard/src/components/focus/tabs/PlanningTab.tsx +390 -0
- package/packages/web-dashboard/src/components/focus/tabs/ReviewTab.tsx +497 -0
- package/packages/web-dashboard/src/components/focus/tabs/RuntimeTab.tsx +213 -0
- package/packages/web-dashboard/src/components/focus/tabs/TranscriptTab.tsx +315 -0
- package/packages/web-dashboard/src/components/gate-results.tsx +2 -2
- package/packages/web-dashboard/src/components/human-input-panel.tsx +33 -57
- package/packages/web-dashboard/src/components/kanban-board.tsx +4 -0
- package/packages/web-dashboard/src/components/launch/launch-draft-card.tsx +131 -0
- package/packages/web-dashboard/src/components/plan-viewer.tsx +147 -69
- package/packages/web-dashboard/src/components/quick-launch-panel.tsx +20 -47
- package/packages/web-dashboard/src/components/summary-bar.tsx +30 -76
- package/packages/web-dashboard/src/lib/aop-client.ts +2484 -36
- package/packages/web-dashboard/src/lib/blocked-state-guidance.ts +475 -0
- package/packages/web-dashboard/src/lib/collision-radar.ts +136 -0
- package/packages/web-dashboard/src/lib/dashboard-action-states.ts +204 -0
- package/packages/web-dashboard/src/lib/dashboard-runtime-client.ts +439 -0
- package/packages/web-dashboard/src/lib/dashboard-utils.ts +179 -18
- package/packages/web-dashboard/src/lib/drop-zone-utils.ts +92 -0
- package/packages/web-dashboard/src/lib/focus-detail-derivations.ts +958 -0
- package/packages/web-dashboard/src/lib/focus-view.ts +300 -0
- package/packages/web-dashboard/src/lib/health-diagnosis.ts +356 -0
- package/packages/web-dashboard/src/lib/launch-contracts.ts +77 -0
- package/packages/web-dashboard/src/lib/launch-markdown.ts +107 -0
- package/packages/web-dashboard/src/lib/launch-page-preview.ts +89 -0
- package/packages/web-dashboard/src/lib/live-feed.ts +1 -1
- package/packages/web-dashboard/src/lib/multi-project-config.ts +33 -0
- package/packages/web-dashboard/src/lib/orchestrator-tools.ts +845 -59
- package/packages/web-dashboard/src/lib/planner-workspace.ts +1285 -0
- package/packages/web-dashboard/src/lib/review-contracts.ts +5 -3
- package/packages/web-dashboard/src/lib/runtime-files.ts +285 -0
- package/packages/web-dashboard/src/lib/tool-catalog.ts +51 -0
- package/packages/web-dashboard/src/lib/types.ts +731 -3
- package/packages/web-dashboard/src/lib/usage-burn.ts +175 -0
- package/packages/web-dashboard/src/lib/worktree-diff.ts +128 -0
- package/packages/web-dashboard/src/styles/dashboard.module.css +1742 -459
- package/packages/web-dashboard/test/api/actions/route.spec.ts +675 -0
- package/packages/web-dashboard/test/api/features/diff.route.spec.ts +57 -0
- package/packages/web-dashboard/test/api/features/feature.route.spec.ts +99 -0
- package/packages/web-dashboard/test/api/features/live-output.route.spec.ts +123 -0
- package/packages/web-dashboard/test/api/features/plan-amend.route.spec.ts +95 -0
- package/packages/web-dashboard/test/api/features/planner-workspaces.route.spec.ts +162 -0
- package/packages/web-dashboard/test/api/features/question-answer.route.spec.ts +99 -0
- package/packages/web-dashboard/test/api/features/triage.route.spec.ts +195 -0
- package/packages/web-dashboard/test/api/launch/preview.route.spec.ts +149 -0
- package/packages/web-dashboard/test/api/launch/submit.route.spec.ts +382 -0
- package/packages/web-dashboard/test/api/runtime/events/route.spec.ts +164 -0
- package/packages/web-dashboard/test/api/runtime/operations/route.spec.ts +156 -0
- package/packages/web-dashboard/test/api/runtime/runs/route.spec.ts +112 -0
- package/packages/web-dashboard/test/components/changes-tab.spec.tsx +76 -0
- package/packages/web-dashboard/test/components/command-center-root.spec.tsx +87 -0
- package/packages/web-dashboard/test/components/diagnosis-panel.spec.tsx +59 -0
- package/packages/web-dashboard/test/components/feature-card.spec.tsx +45 -0
- package/packages/web-dashboard/test/components/focus-layout.spec.tsx +299 -0
- package/packages/web-dashboard/test/components/gate-results.spec.tsx +39 -0
- package/packages/web-dashboard/test/components/gates-qa-tab.spec.tsx +118 -0
- package/packages/web-dashboard/test/components/human-input-panel.spec.tsx +54 -0
- package/packages/web-dashboard/test/components/intake-tab.spec.tsx +210 -0
- package/packages/web-dashboard/test/components/kanban-board.spec.tsx +35 -0
- package/packages/web-dashboard/test/components/launch-draft-card.spec.tsx +54 -0
- package/packages/web-dashboard/test/components/launch-page.spec.tsx +79 -0
- package/packages/web-dashboard/test/components/overview-tab.spec.tsx +236 -0
- package/packages/web-dashboard/test/components/planning-tab.spec.tsx +202 -0
- package/packages/web-dashboard/test/components/review-tab.spec.tsx +169 -0
- package/packages/web-dashboard/test/components/role-log-viewer.spec.ts +42 -0
- package/packages/web-dashboard/test/components/runtime-inspector.spec.tsx +22 -0
- package/packages/web-dashboard/test/components/runtime-tab.spec.tsx +133 -0
- package/packages/web-dashboard/test/components/transcript-tab.spec.tsx +46 -0
- package/packages/web-dashboard/test/components/triage-drawer.spec.tsx +159 -0
- package/packages/web-dashboard/test/lib/aop-client.spec.ts +235 -0
- package/packages/web-dashboard/test/lib/dashboard-runtime-client.spec.ts +144 -0
- package/packages/web-dashboard/test/lib/focus-detail-derivations.spec.ts +314 -0
- package/packages/web-dashboard/test/lib/focus-view.spec.ts +248 -0
- package/packages/web-dashboard/test/lib/health-diagnosis.spec.ts +277 -0
- package/packages/web-dashboard/test/lib/launch-markdown.spec.ts +36 -0
- package/packages/web-dashboard/test/lib/multi-project-config.spec.ts +54 -0
- package/packages/web-dashboard/test/lib/orchestrator-tools.spec.ts +352 -0
- package/packages/web-dashboard/test/lib/planner-workspace.spec.ts +289 -0
- package/packages/web-dashboard/test/lib/worktree-diff.spec.ts +119 -0
- package/packages/web-dashboard/vitest.config.ts +2 -0
- package/spec-files/completed/agentic_orchestrator_add_feature_to_active_execution_spec.md +557 -0
- package/spec-files/completed/agentic_orchestrator_dashboard_command_center_redesign_spec.md +1147 -0
- package/spec-files/completed/agentic_orchestrator_execution_mode_spec.md +18 -16
- package/spec-files/completed/agentic_orchestrator_feature_focus_view_track_a_spec.md +672 -0
- package/spec-files/completed/agentic_orchestrator_feature_focus_view_track_b_spec.md +794 -0
- package/spec-files/completed/agentic_orchestrator_feature_focus_view_track_c_decision_centric_remediation_spec.md +1037 -0
- package/spec-files/completed/agentic_orchestrator_feature_focus_view_ux_redesign_spec.md +1432 -0
- package/spec-files/completed/agentic_orchestrator_focus_plan_tab_intake_planning_workspace_spec.md +921 -0
- package/spec-files/completed/agentic_orchestrator_intentional_collision_override_spec.md +584 -0
- package/spec-files/completed/agentic_orchestrator_interactive_planning_intake_and_requirements_verification_spec.md +1185 -0
- package/spec-files/completed/agentic_orchestrator_reactive_execution_enrollment_spec.md +864 -0
- package/spec-files/{outstanding → completed}/agentic_orchestrator_runtime_inspection_spec.md +92 -19
- package/spec-files/completed/agentic_orchestrator_scope_aware_run_lease_spec.md +408 -0
- package/spec-files/completed/git-reconciliation-engine.md +827 -0
- package/spec-files/outstanding/agentic_orchestrator_dashboard_quick_launch_and_control_surface_spec.md +331 -0
- package/spec-files/outstanding/agentic_orchestrator_enterprise_governance_dashboard_spec.md +16 -6
- package/spec-files/outstanding/agentic_orchestrator_evidence_integrity_doctor_spec.md +60 -9
- package/spec-files/outstanding/agentic_orchestrator_focus_plan_tab_execution_contract_workspace_spec.md +616 -0
- package/spec-files/outstanding/agentic_orchestrator_headless_standby_dashboard_runtime_spec.md +310 -0
- package/spec-files/outstanding/agentic_orchestrator_human_input_interaction_protocol_spec.md +175 -72
- package/spec-files/outstanding/agentic_orchestrator_interactive_rename_cleanup_spec.md +197 -0
- package/spec-files/outstanding/agentic_orchestrator_interactive_resume_and_reconciliation_disposition_spec.md +412 -0
- package/spec-files/outstanding/agentic_orchestrator_knowledge_canary_spec.md +166 -137
- package/spec-files/outstanding/agentic_orchestrator_observability_replay_spec.md +3 -3
- package/spec-files/outstanding/agentic_orchestrator_phase_specific_agent_profiles_and_token_telemetry_spec.md +303 -0
- package/spec-files/outstanding/agentic_orchestrator_planning_review_quality_spec.md +18 -5
- package/spec-files/outstanding/agentic_orchestrator_policy_stratification_spec.md +225 -0
- package/spec-files/outstanding/agentic_orchestrator_quality_adoption_execution_spec.md +77 -50
- package/spec-files/outstanding/agentic_orchestrator_ready_to_merge_branch_handoff_spec.md +724 -0
- package/spec-files/outstanding/agentic_orchestrator_remove_deterministic_mode_spec.md +263 -0
- package/spec-files/outstanding/agentic_orchestrator_request_more_context_and_dashboard_human_input_spec.md +456 -0
- package/spec-files/outstanding/agentic_orchestrator_spec_coverage_and_reconciliation_enforcement_spec.md +1411 -0
- package/spec-files/outstanding/agentic_orchestrator_spec_ordering_agent_spec.md +370 -0
- package/spec-files/outstanding/shadow_workspace_implementation_spec.md +1 -1
- package/spec-files/progress.md +2026 -120
- package/specs/001-runtime-inspection/checklists/requirements.md +35 -0
- package/specs/001-runtime-inspection/design.md +338 -0
- package/specs/001-runtime-inspection/spec.md +95 -0
- package/specs/002-scope-aware-lease/checklists/requirements.md +35 -0
- package/specs/002-scope-aware-lease/contracts/lease-registry.schema.json +101 -0
- package/specs/002-scope-aware-lease/data-model.md +236 -0
- package/specs/002-scope-aware-lease/plan.md +766 -0
- package/specs/002-scope-aware-lease/quickstart.md +150 -0
- package/specs/002-scope-aware-lease/research.md +135 -0
- package/specs/002-scope-aware-lease/spec.md +128 -0
- package/specs/002-scope-aware-lease/tasks.md +767 -0
- package/tsconfig.json +1 -1
- package/vitest.config.ts +28 -0
- package/ARCHITECTURE_ADHERENCE_ANALYSIS.md +0 -871
- package/packages/web-dashboard/next-env.d.ts +0 -6
- package/packages/web-dashboard/src/components/detail-panel.tsx +0 -1124
- package/packages/web-dashboard/src/components/review-workspace.tsx +0 -1162
- /package/spec-files/{outstanding → completed}/agentic_orchestrator_artifact_database_publishing_spec.md +0 -0
- /package/spec-files/{outstanding → completed}/agentic_orchestrator_cli_shell_tab_completion_spec.md +0 -0
- /package/spec-files/{outstanding → completed}/agentic_orchestrator_dashboard_diff_and_agent_console_spec.md +0 -0
- /package/spec-files/{outstanding → completed}/agentic_orchestrator_performance_improvements_spec.md +0 -0
- /package/spec-files/{outstanding → completed}/agentic_orchestrator_persistent_worker_runtime_spec.md +0 -0
- /package/spec-files/{outstanding → completed}/agentic_orchestrator_provider_auth_bootstrap_spec.md +0 -0
- /package/spec-files/{outstanding → completed}/agentic_orchestrator_real_worker_provider_execution_spec.md +0 -0
|
@@ -1,7 +1,15 @@
|
|
|
1
|
-
import
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { STATUS, TOOLS } from '../core/constants.js';
|
|
2
3
|
import { ERROR_CODES } from '../core/error-codes.js';
|
|
3
|
-
import type {
|
|
4
|
+
import type {
|
|
5
|
+
ExecutionMode,
|
|
6
|
+
ProviderSelection,
|
|
7
|
+
WorkerProvider,
|
|
8
|
+
WorkerRunInput,
|
|
9
|
+
} from '../providers/providers.js';
|
|
10
|
+
import type { NormalizedUsageRecord } from '../application/usage-types.js';
|
|
4
11
|
import type { RuntimeRole, SupervisorToolCaller } from './types.js';
|
|
12
|
+
import { resolvePlannerPhaseFromContext } from './planner-phase.js';
|
|
5
13
|
import type { ActivityMonitorService } from '../application/services/activity-monitor-service.js';
|
|
6
14
|
import { appendWorkerRuntimeEvent } from './worker-event-journal.js';
|
|
7
15
|
import type {
|
|
@@ -22,6 +30,7 @@ const PLAN_TOP_LEVEL_KEYS = new Set([
|
|
|
22
30
|
'files',
|
|
23
31
|
'contracts',
|
|
24
32
|
'acceptance_criteria',
|
|
33
|
+
'plan_trace',
|
|
25
34
|
'gate_targets',
|
|
26
35
|
'risk',
|
|
27
36
|
'revision_of',
|
|
@@ -29,28 +38,71 @@ const PLAN_TOP_LEVEL_KEYS = new Set([
|
|
|
29
38
|
'verification_overrides',
|
|
30
39
|
]);
|
|
31
40
|
|
|
41
|
+
/** Input payload for a single worker decision turn. */
|
|
32
42
|
export interface WorkerDecisionInput {
|
|
43
|
+
/** Agent role executing this turn (planner, builder, or qa). */
|
|
33
44
|
role: RuntimeRole;
|
|
45
|
+
/** Target feature identifier. */
|
|
34
46
|
featureId: string;
|
|
47
|
+
/** Aggregated context bundle passed to the worker provider. */
|
|
35
48
|
contextBundle: AnyRecord;
|
|
49
|
+
/** Natural-language instructions for the worker. */
|
|
36
50
|
instructions: string;
|
|
51
|
+
/** Tool results from a previous turn, used for context-refresh retries. */
|
|
37
52
|
lastToolResults?: AnyRecord[];
|
|
38
53
|
}
|
|
39
54
|
|
|
55
|
+
/** Outcome of a single worker decision turn, summarising all actions taken and diagnostics. */
|
|
40
56
|
export interface WorkerDecisionResult {
|
|
57
|
+
/** Whether a plan was submitted during this turn. */
|
|
41
58
|
planSubmission: boolean;
|
|
59
|
+
/** Whether an intake manifest was submitted during this turn. */
|
|
60
|
+
intakeSubmission: boolean;
|
|
61
|
+
/** Whether at least one code patch was applied. */
|
|
42
62
|
patchApplied: boolean;
|
|
63
|
+
/** Whether a log note was recorded. */
|
|
43
64
|
noteLogged: boolean;
|
|
65
|
+
/** Whether a structured request (e.g. context refresh) was handled. */
|
|
44
66
|
requestHandled: boolean;
|
|
67
|
+
/** Whether the worker emitted a human-input question. */
|
|
68
|
+
questionRequested: boolean;
|
|
69
|
+
/** Whether the worker stalled requesting context without making progress. */
|
|
70
|
+
contextStall: boolean;
|
|
71
|
+
/** Number of context-refresh requests seen across outputs. */
|
|
72
|
+
contextRequestCount: number;
|
|
73
|
+
/** ISO timestamp of the most recent context-refresh request, if any. */
|
|
74
|
+
lastContextRequestAt: string | null;
|
|
75
|
+
/** Role that issued the most recent context-refresh request. */
|
|
76
|
+
lastContextRequestRole: RuntimeRole | null;
|
|
77
|
+
/** Whether the provider output failed validation. */
|
|
45
78
|
invalidOutput: boolean;
|
|
79
|
+
/** Structured error code if an error occurred, otherwise null. */
|
|
80
|
+
errorCode?: string | null;
|
|
81
|
+
/** True when the turn produced no forward progress. */
|
|
46
82
|
noProgress: boolean;
|
|
83
|
+
/** Classified output types emitted by the worker (e.g. PATCH, PLAN_SUBMISSION, NOTE). */
|
|
47
84
|
outputTypes: string[];
|
|
85
|
+
/** Raw output records returned by the provider. */
|
|
48
86
|
rawOutputs: AnyRecord[];
|
|
87
|
+
/** Priority-ordered list of output types processed. */
|
|
49
88
|
priorityOrder: string[];
|
|
89
|
+
/** Accumulated tool-call results from the turn. */
|
|
50
90
|
toolResults: AnyRecord[];
|
|
91
|
+
/** Outcome classification for interactive-mode executions. */
|
|
92
|
+
interactiveOutcome?:
|
|
93
|
+
| 'progress_applied'
|
|
94
|
+
| 'no_new_work'
|
|
95
|
+
| 'checkpoint_invalid'
|
|
96
|
+
| 'provider_output_invalid'
|
|
97
|
+
| null;
|
|
98
|
+
/** Worktree checkpoint captured at the end of an interactive turn. */
|
|
99
|
+
checkpoint?: CheckpointRecord | null;
|
|
100
|
+
usageRecords?: NormalizedUsageRecord[];
|
|
51
101
|
}
|
|
52
102
|
|
|
103
|
+
/** Strategy interface for executing a single worker decision turn. */
|
|
53
104
|
export interface WorkerDecisionRunner {
|
|
105
|
+
/** Run one decision turn for the given input and return the aggregated result. */
|
|
54
106
|
execute(input: WorkerDecisionInput): Promise<WorkerDecisionResult>;
|
|
55
107
|
}
|
|
56
108
|
|
|
@@ -58,6 +110,24 @@ function asRecord(value: unknown): AnyRecord {
|
|
|
58
110
|
return value && typeof value === 'object' ? (value as AnyRecord) : {};
|
|
59
111
|
}
|
|
60
112
|
|
|
113
|
+
function extractNonErrorMessage(value: unknown): string | null {
|
|
114
|
+
if (!value || typeof value !== 'object') {
|
|
115
|
+
return typeof value === 'string' ? value : null;
|
|
116
|
+
}
|
|
117
|
+
const obj = value as AnyRecord;
|
|
118
|
+
const normalized = obj['normalizedResponse'] as AnyRecord | undefined;
|
|
119
|
+
if (normalized?.['error'] && typeof normalized['error'] === 'object') {
|
|
120
|
+
const err = normalized['error'] as AnyRecord;
|
|
121
|
+
if (typeof err['message'] === 'string') {
|
|
122
|
+
return err['message'];
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (typeof obj['message'] === 'string') {
|
|
126
|
+
return obj['message'];
|
|
127
|
+
}
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
|
|
61
131
|
function asNonEmptyString(value: unknown): string | null {
|
|
62
132
|
if (typeof value !== 'string') {
|
|
63
133
|
return null;
|
|
@@ -106,21 +176,43 @@ function asOutputs(result: Record<string, unknown>): AnyRecord[] {
|
|
|
106
176
|
return [asRecord(result)];
|
|
107
177
|
}
|
|
108
178
|
|
|
179
|
+
function readInteractiveFallbackReason(result: Record<string, unknown>): string | null {
|
|
180
|
+
return asNonEmptyString(asRecord(result.provider_meta).parse_fallback_reason);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function isBlockingAskUserInputOutput(output: AnyRecord): boolean {
|
|
184
|
+
const request = asRecord(output.request ?? output);
|
|
185
|
+
const action = asNonEmptyString(request.action ?? request.request_type)?.toLowerCase();
|
|
186
|
+
const prompt = asNonEmptyString(request.prompt);
|
|
187
|
+
return action === 'ask_user_input' && prompt !== null;
|
|
188
|
+
}
|
|
189
|
+
|
|
109
190
|
function makeEmptyResult(): WorkerDecisionResult {
|
|
110
191
|
return {
|
|
111
192
|
planSubmission: false,
|
|
193
|
+
intakeSubmission: false,
|
|
112
194
|
patchApplied: false,
|
|
113
195
|
noteLogged: false,
|
|
114
196
|
requestHandled: false,
|
|
197
|
+
questionRequested: false,
|
|
198
|
+
contextStall: false,
|
|
199
|
+
contextRequestCount: 0,
|
|
200
|
+
lastContextRequestAt: null,
|
|
201
|
+
lastContextRequestRole: null,
|
|
115
202
|
invalidOutput: false,
|
|
203
|
+
errorCode: null,
|
|
116
204
|
noProgress: false,
|
|
117
205
|
outputTypes: [],
|
|
118
206
|
rawOutputs: [],
|
|
119
207
|
priorityOrder: [],
|
|
120
208
|
toolResults: [],
|
|
209
|
+
interactiveOutcome: null,
|
|
210
|
+
checkpoint: null,
|
|
211
|
+
usageRecords: [],
|
|
121
212
|
};
|
|
122
213
|
}
|
|
123
214
|
|
|
215
|
+
/** No-op decision runner that always returns an empty result with no progress. */
|
|
124
216
|
export const NOOP_WORKER_DECISION_RUNNER: WorkerDecisionRunner = {
|
|
125
217
|
execute: () => Promise.resolve(makeEmptyResult()),
|
|
126
218
|
};
|
|
@@ -132,6 +224,10 @@ interface WorkerDecisionLoopDependencies {
|
|
|
132
224
|
repoRoot?: string;
|
|
133
225
|
runId?: string | (() => string);
|
|
134
226
|
resolveExecutionMode?: (featureId: string, role: RuntimeRole) => Promise<ExecutionMode>;
|
|
227
|
+
resolveRuntimeSelection?: (
|
|
228
|
+
featureId: string,
|
|
229
|
+
role: RuntimeRole,
|
|
230
|
+
) => ProviderSelection | Promise<ProviderSelection>;
|
|
135
231
|
resolveInteractiveConfig?: () => InteractiveExecutionConfig;
|
|
136
232
|
watchdog?: WorktreeWatchdogService;
|
|
137
233
|
checkpointService?: CheckpointService;
|
|
@@ -141,11 +237,192 @@ interface WorkerDecisionLoopDependencies {
|
|
|
141
237
|
|
|
142
238
|
interface InteractiveRunSummary {
|
|
143
239
|
workerOutput: Record<string, unknown>;
|
|
144
|
-
finalCheckpoint: CheckpointRecord;
|
|
240
|
+
finalCheckpoint: CheckpointRecord | null;
|
|
145
241
|
changedFiles: string[];
|
|
242
|
+
hasNetNewWorktreeChanges: boolean;
|
|
146
243
|
checkpointInvalid: boolean;
|
|
244
|
+
fallbackReason: string | null;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
interface PlannerExecutionState {
|
|
248
|
+
currentPlanVersion: number | null;
|
|
249
|
+
planMutationApplied: boolean;
|
|
147
250
|
}
|
|
148
251
|
|
|
252
|
+
interface WorkerRunResult {
|
|
253
|
+
workerOutput: Record<string, unknown>;
|
|
254
|
+
interactiveSummary: InteractiveRunSummary | null;
|
|
255
|
+
executionMode: ExecutionMode;
|
|
256
|
+
runtimeSelection: ProviderSelection;
|
|
257
|
+
usage: NormalizedUsageRecord | null;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
interface RequestRoutingResult {
|
|
261
|
+
contextRefreshRequested: boolean;
|
|
262
|
+
refreshedContext: AnyRecord | null;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
interface IntakeClarificationAmbiguity {
|
|
266
|
+
id: string;
|
|
267
|
+
summary: string;
|
|
268
|
+
obligationIds: string[];
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
interface IntakeClarificationAnswer {
|
|
272
|
+
questionId: string;
|
|
273
|
+
ambiguityIds: string[];
|
|
274
|
+
answer: string;
|
|
275
|
+
answeredAt: string | null;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
interface ToolFailureDetails {
|
|
279
|
+
code: string | null;
|
|
280
|
+
message: string | null;
|
|
281
|
+
details: AnyRecord;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
function normalizeList(values: string[]): string[] {
|
|
285
|
+
return Array.from(new Set(values.map((item) => item.trim()).filter((item) => item.length > 0)));
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function readToolFailureDetails(error: unknown): ToolFailureDetails | null {
|
|
289
|
+
if (!error || typeof error !== 'object') {
|
|
290
|
+
return null;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const direct = asRecord((error as { error?: unknown }).error);
|
|
294
|
+
const normalized = asRecord(
|
|
295
|
+
asRecord((error as { normalizedResponse?: unknown }).normalizedResponse).error,
|
|
296
|
+
);
|
|
297
|
+
const payload = Object.keys(normalized).length > 0 ? normalized : direct;
|
|
298
|
+
if (Object.keys(payload).length === 0) {
|
|
299
|
+
return null;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
return {
|
|
303
|
+
code: asNonEmptyString(payload.code),
|
|
304
|
+
message: asNonEmptyString(payload.message),
|
|
305
|
+
details: asRecord(payload.details),
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
function readAllIntakeAmbiguities(contextBundle: AnyRecord): IntakeClarificationAmbiguity[] {
|
|
310
|
+
const intake = asRecord(contextBundle.intake);
|
|
311
|
+
const review = asRecord(intake.review);
|
|
312
|
+
const ambiguities = Array.isArray(review.ambiguities) ? review.ambiguities : [];
|
|
313
|
+
const results: IntakeClarificationAmbiguity[] = [];
|
|
314
|
+
for (const item of ambiguities) {
|
|
315
|
+
const record = asRecord(item);
|
|
316
|
+
const id = asNonEmptyString(record.id);
|
|
317
|
+
const summary = asNonEmptyString(record.summary);
|
|
318
|
+
if (!id || !summary) {
|
|
319
|
+
continue;
|
|
320
|
+
}
|
|
321
|
+
results.push({
|
|
322
|
+
id,
|
|
323
|
+
summary,
|
|
324
|
+
obligationIds: asStringArray(record.obligation_ids),
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
return results;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
function readOpenIntakeAmbiguities(contextBundle: AnyRecord): IntakeClarificationAmbiguity[] {
|
|
331
|
+
const intake = asRecord(contextBundle.intake);
|
|
332
|
+
const review = asRecord(intake.review);
|
|
333
|
+
const openIds = new Set(
|
|
334
|
+
(Array.isArray(review.ambiguities) ? review.ambiguities : [])
|
|
335
|
+
.map((item) => asRecord(item))
|
|
336
|
+
.filter((item) => asNonEmptyString(item.status) === 'open')
|
|
337
|
+
.map((item) => asNonEmptyString(item.id))
|
|
338
|
+
.filter((item): item is string => item !== null),
|
|
339
|
+
);
|
|
340
|
+
return readAllIntakeAmbiguities(contextBundle).filter((item) => openIds.has(item.id));
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
function readIntakeAmbiguitiesForRecovery(
|
|
344
|
+
contextBundle: AnyRecord,
|
|
345
|
+
ambiguityIds: string[],
|
|
346
|
+
): IntakeClarificationAmbiguity[] {
|
|
347
|
+
const normalizedIds = normalizeList(ambiguityIds);
|
|
348
|
+
if (normalizedIds.length === 0) {
|
|
349
|
+
return readOpenIntakeAmbiguities(contextBundle);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
const byId = new Map(readAllIntakeAmbiguities(contextBundle).map((item) => [item.id, item]));
|
|
353
|
+
return normalizedIds.map((ambiguityId) => {
|
|
354
|
+
const existing = byId.get(ambiguityId);
|
|
355
|
+
if (existing) {
|
|
356
|
+
return existing;
|
|
357
|
+
}
|
|
358
|
+
return {
|
|
359
|
+
id: ambiguityId,
|
|
360
|
+
summary: 'Clarify this ambiguity before verifying the intake manifest.',
|
|
361
|
+
obligationIds: [],
|
|
362
|
+
};
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
function hasOpenIntakeQuestion(contextBundle: AnyRecord): boolean {
|
|
367
|
+
const humanInput = asRecord(contextBundle.human_input);
|
|
368
|
+
const openQuestions = Array.isArray(humanInput.open_questions) ? humanInput.open_questions : [];
|
|
369
|
+
return openQuestions.length > 0;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
function readAnsweredIntakeClarifications(contextBundle: AnyRecord): IntakeClarificationAnswer[] {
|
|
373
|
+
const intake = asRecord(contextBundle.intake);
|
|
374
|
+
const review = asRecord(intake.review);
|
|
375
|
+
const clarificationAnswers = Array.isArray(review.clarification_answers)
|
|
376
|
+
? review.clarification_answers
|
|
377
|
+
: [];
|
|
378
|
+
return clarificationAnswers
|
|
379
|
+
.map((item) => asRecord(item))
|
|
380
|
+
.filter((item) => asStringArray(item.ambiguity_ids).length > 0)
|
|
381
|
+
.map((item) => ({
|
|
382
|
+
questionId: asNonEmptyString(item.question_id) ?? 'unknown',
|
|
383
|
+
ambiguityIds: asStringArray(item.ambiguity_ids),
|
|
384
|
+
answer:
|
|
385
|
+
typeof item.answer === 'string'
|
|
386
|
+
? item.answer
|
|
387
|
+
: JSON.stringify(asRecord(item.answer) ?? {}, null, 2),
|
|
388
|
+
answeredAt: asNonEmptyString(item.answered_at),
|
|
389
|
+
}));
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
function buildIntakeClarificationPrompt(
|
|
393
|
+
ambiguities: IntakeClarificationAmbiguity[],
|
|
394
|
+
recoveryReason: string,
|
|
395
|
+
priorAnswers: IntakeClarificationAnswer[],
|
|
396
|
+
): string {
|
|
397
|
+
const intro =
|
|
398
|
+
ambiguities.length === 1
|
|
399
|
+
? 'Execution planning cannot begin because this intake ambiguity is still unresolved:'
|
|
400
|
+
: 'Execution planning cannot begin because these intake ambiguities are still unresolved:';
|
|
401
|
+
const items = ambiguities.map((ambiguity) => `- ${ambiguity.id}: ${ambiguity.summary}`);
|
|
402
|
+
const priorAnswerLines = ambiguities.flatMap((ambiguity) =>
|
|
403
|
+
priorAnswers
|
|
404
|
+
.filter((answer) => answer.ambiguityIds.includes(ambiguity.id))
|
|
405
|
+
.map(
|
|
406
|
+
(answer) =>
|
|
407
|
+
`- ${ambiguity.id} via ${answer.questionId}${
|
|
408
|
+
answer.answeredAt ? ` at ${answer.answeredAt}` : ''
|
|
409
|
+
}: ${answer.answer}`,
|
|
410
|
+
),
|
|
411
|
+
);
|
|
412
|
+
const priorAnswersBlock =
|
|
413
|
+
priorAnswerLines.length > 0
|
|
414
|
+
? `\nPrior answered clarification evidence:\n${priorAnswerLines.join('\n')}\nUse this prior answer evidence. Only ask a narrower follow-up if it is still insufficient to resolve the ambiguity.`
|
|
415
|
+
: '';
|
|
416
|
+
return `${intro}\n${items.join('\n')}${priorAnswersBlock}\nRespond in free text and explicitly address each ambiguity ID. Recovery reason: ${recoveryReason}.`;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
/**
|
|
420
|
+
* Core decision loop that drives a single agent worker turn.
|
|
421
|
+
*
|
|
422
|
+
* Invokes the provider, classifies outputs (plans, patches, notes, requests),
|
|
423
|
+
* dispatches tool calls, handles context-refresh retries, and supports both
|
|
424
|
+
* deterministic and interactive execution modes.
|
|
425
|
+
*/
|
|
149
426
|
export class WorkerDecisionLoop implements WorkerDecisionRunner {
|
|
150
427
|
private readonly provider: WorkerProvider;
|
|
151
428
|
private readonly toolCaller: SupervisorToolCaller;
|
|
@@ -155,6 +432,9 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
|
|
|
155
432
|
private readonly resolveExecutionModeOverride:
|
|
156
433
|
| ((featureId: string, role: RuntimeRole) => Promise<ExecutionMode>)
|
|
157
434
|
| undefined;
|
|
435
|
+
private readonly resolveRuntimeSelectionOverride:
|
|
436
|
+
| ((featureId: string, role: RuntimeRole) => ProviderSelection | Promise<ProviderSelection>)
|
|
437
|
+
| undefined;
|
|
158
438
|
private readonly resolveInteractiveConfigOverride: (() => InteractiveExecutionConfig) | undefined;
|
|
159
439
|
private readonly watchdog: WorktreeWatchdogService | undefined;
|
|
160
440
|
private readonly checkpointService: CheckpointService | undefined;
|
|
@@ -170,6 +450,7 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
|
|
|
170
450
|
this.repoRoot = dependencies.repoRoot ?? null;
|
|
171
451
|
this.runId = dependencies.runId ?? null;
|
|
172
452
|
this.resolveExecutionModeOverride = dependencies.resolveExecutionMode;
|
|
453
|
+
this.resolveRuntimeSelectionOverride = dependencies.resolveRuntimeSelection;
|
|
173
454
|
this.resolveInteractiveConfigOverride = dependencies.resolveInteractiveConfig;
|
|
174
455
|
this.watchdog = dependencies.watchdog;
|
|
175
456
|
this.checkpointService = dependencies.checkpointService;
|
|
@@ -177,11 +458,21 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
|
|
|
177
458
|
this.resolveRoleSessionId = dependencies.resolveRoleSessionId;
|
|
178
459
|
}
|
|
179
460
|
|
|
461
|
+
/**
|
|
462
|
+
* Execute one decision turn: invoke the worker, process all outputs, and
|
|
463
|
+
* optionally retry once on a context-refresh request.
|
|
464
|
+
* @returns Aggregated result describing every action taken and diagnostics.
|
|
465
|
+
*/
|
|
180
466
|
async execute(input: WorkerDecisionInput): Promise<WorkerDecisionResult> {
|
|
181
467
|
const result = makeEmptyResult();
|
|
468
|
+
const plannerState: PlannerExecutionState = {
|
|
469
|
+
currentPlanVersion: readPlanVersion(asRecord(input.contextBundle.plan).plan_version),
|
|
470
|
+
planMutationApplied: false,
|
|
471
|
+
};
|
|
182
472
|
if (typeof this.provider.runWorker !== 'function') {
|
|
183
473
|
return result;
|
|
184
474
|
}
|
|
475
|
+
const runtimeSelection = await this.resolveRuntimeSelection(input.featureId, input.role);
|
|
185
476
|
const requestedExecutionMode = await this.resolveExecutionMode(input.featureId, input.role);
|
|
186
477
|
const interactiveEligible = this.isInteractiveEligible(requestedExecutionMode, input.role);
|
|
187
478
|
const executionMode: ExecutionMode =
|
|
@@ -201,6 +492,7 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
|
|
|
201
492
|
valid: true,
|
|
202
493
|
errorCode: null,
|
|
203
494
|
executionMode,
|
|
495
|
+
runtimeSelection,
|
|
204
496
|
});
|
|
205
497
|
}
|
|
206
498
|
await this.appendWorkerEvent({
|
|
@@ -215,17 +507,124 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
|
|
|
215
507
|
valid: true,
|
|
216
508
|
errorCode: null,
|
|
217
509
|
executionMode,
|
|
510
|
+
runtimeSelection,
|
|
511
|
+
});
|
|
512
|
+
let finalRun = await this.runWorkerTurn(
|
|
513
|
+
input,
|
|
514
|
+
executionMode,
|
|
515
|
+
runtimeSelection,
|
|
516
|
+
interactiveEligible,
|
|
517
|
+
);
|
|
518
|
+
if (finalRun.usage) {
|
|
519
|
+
result.usageRecords.push(finalRun.usage);
|
|
520
|
+
}
|
|
521
|
+
const firstPass = await this.processOutputs({
|
|
522
|
+
input,
|
|
523
|
+
workerRun: finalRun,
|
|
524
|
+
result,
|
|
525
|
+
plannerState,
|
|
526
|
+
allowContextRefreshRetry: true,
|
|
527
|
+
});
|
|
528
|
+
|
|
529
|
+
if (firstPass.contextRefreshRequested && firstPass.refreshedContext) {
|
|
530
|
+
finalRun = await this.runWorkerTurn(
|
|
531
|
+
{
|
|
532
|
+
...input,
|
|
533
|
+
contextBundle: firstPass.refreshedContext,
|
|
534
|
+
lastToolResults: this.buildContextRetryToolResults(input, firstPass.refreshedContext),
|
|
535
|
+
},
|
|
536
|
+
executionMode,
|
|
537
|
+
runtimeSelection,
|
|
538
|
+
interactiveEligible,
|
|
539
|
+
);
|
|
540
|
+
if (finalRun.usage) {
|
|
541
|
+
result.usageRecords.push(finalRun.usage);
|
|
542
|
+
}
|
|
543
|
+
const secondPass = await this.processOutputs({
|
|
544
|
+
input: {
|
|
545
|
+
...input,
|
|
546
|
+
contextBundle: firstPass.refreshedContext,
|
|
547
|
+
lastToolResults: this.buildContextRetryToolResults(input, firstPass.refreshedContext),
|
|
548
|
+
},
|
|
549
|
+
workerRun: finalRun,
|
|
550
|
+
result,
|
|
551
|
+
plannerState,
|
|
552
|
+
allowContextRefreshRetry: false,
|
|
553
|
+
});
|
|
554
|
+
|
|
555
|
+
if (secondPass.contextRefreshRequested) {
|
|
556
|
+
const hasInteractiveWork =
|
|
557
|
+
finalRun.interactiveSummary?.hasNetNewWorktreeChanges === true &&
|
|
558
|
+
finalRun.interactiveSummary.changedFiles.length > 0;
|
|
559
|
+
if (!hasInteractiveWork) {
|
|
560
|
+
result.contextStall = true;
|
|
561
|
+
result.errorCode = ERROR_CODES.PROVIDER_CONTEXT_STALL;
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
this.finalizeInteractiveOutcome(result, finalRun.interactiveSummary);
|
|
567
|
+
|
|
568
|
+
const hasProgress =
|
|
569
|
+
result.planSubmission ||
|
|
570
|
+
result.intakeSubmission ||
|
|
571
|
+
result.patchApplied ||
|
|
572
|
+
result.requestHandled ||
|
|
573
|
+
result.questionRequested;
|
|
574
|
+
result.noProgress = !hasProgress;
|
|
575
|
+
|
|
576
|
+
await this.appendWorkerEvent({
|
|
577
|
+
eventType: 'worker_completed',
|
|
578
|
+
featureId: input.featureId,
|
|
579
|
+
role: input.role,
|
|
580
|
+
outputTypes: result.outputTypes,
|
|
581
|
+
patchCount: result.outputTypes.filter((type) => type === 'PATCH').length,
|
|
582
|
+
planSubmissionCount: result.outputTypes.filter(
|
|
583
|
+
(type) => type === 'PLAN_SUBMISSION' || type === 'INTAKE_SUBMISSION',
|
|
584
|
+
).length,
|
|
585
|
+
requestCount: result.outputTypes.filter((type) => type === 'REQUEST').length,
|
|
586
|
+
noteCount: result.outputTypes.filter((type) => type === 'NOTE').length,
|
|
587
|
+
valid: !result.invalidOutput && result.errorCode === null,
|
|
588
|
+
errorCode: result.errorCode,
|
|
589
|
+
interactiveOutcome: result.interactiveOutcome ?? null,
|
|
590
|
+
checkpointId: result.checkpoint?.checkpoint_id ?? null,
|
|
591
|
+
checkpointDiffHash:
|
|
592
|
+
typeof result.checkpoint?.diff_hash === 'string' ? result.checkpoint.diff_hash : null,
|
|
593
|
+
checkpointNetNewWorktreeChange: result.checkpoint?.net_new_worktree_change ?? null,
|
|
594
|
+
checkpointValidationStatus:
|
|
595
|
+
typeof result.checkpoint?.validation_status === 'string'
|
|
596
|
+
? result.checkpoint.validation_status
|
|
597
|
+
: null,
|
|
598
|
+
executionMode,
|
|
599
|
+
runtimeSelection,
|
|
600
|
+
usage: finalRun.usage,
|
|
218
601
|
});
|
|
219
602
|
|
|
603
|
+
if (this.activityMonitor) {
|
|
604
|
+
await this.activityMonitor.checkAndNotifyStuck(input.featureId);
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
return result;
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
private async runWorkerTurn(
|
|
611
|
+
input: WorkerDecisionInput,
|
|
612
|
+
executionMode: ExecutionMode,
|
|
613
|
+
runtimeSelection: ProviderSelection,
|
|
614
|
+
interactiveEligible: boolean,
|
|
615
|
+
): Promise<WorkerRunResult> {
|
|
220
616
|
let workerOutput: Record<string, unknown>;
|
|
221
617
|
let interactiveSummary: InteractiveRunSummary | null = null;
|
|
222
618
|
try {
|
|
223
619
|
if (interactiveEligible) {
|
|
224
|
-
interactiveSummary =
|
|
620
|
+
interactiveSummary =
|
|
621
|
+
input.role === 'planner'
|
|
622
|
+
? await this.runInteractivePlanner(input, runtimeSelection)
|
|
623
|
+
: await this.runInteractiveWorker(input, runtimeSelection);
|
|
225
624
|
workerOutput = interactiveSummary.workerOutput;
|
|
226
625
|
} else {
|
|
227
626
|
workerOutput = await this.provider.runWorker(
|
|
228
|
-
this.buildRunInput(input, executionMode, undefined),
|
|
627
|
+
this.buildRunInput(input, executionMode, undefined, runtimeSelection),
|
|
229
628
|
);
|
|
230
629
|
}
|
|
231
630
|
} catch (error) {
|
|
@@ -270,92 +669,177 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
|
|
|
270
669
|
signal: typeof typed.details?.signal === 'string' ? typed.details.signal : null,
|
|
271
670
|
exitCode:
|
|
272
671
|
typeof typed.details?.exit_code === 'number' ? typed.details.exit_code : undefined,
|
|
672
|
+
stderr:
|
|
673
|
+
typeof typed.details?.stderr === 'string' && typed.details.stderr.length > 0
|
|
674
|
+
? typed.details.stderr
|
|
675
|
+
: undefined,
|
|
273
676
|
executionMode,
|
|
677
|
+
runtimeSelection,
|
|
274
678
|
});
|
|
275
679
|
throw error;
|
|
276
680
|
}
|
|
277
681
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
const
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
682
|
+
// Extract usage telemetry from provider output (if available).
|
|
683
|
+
const rawUsage = workerOutput.usage;
|
|
684
|
+
const usage: NormalizedUsageRecord | null =
|
|
685
|
+
rawUsage &&
|
|
686
|
+
typeof rawUsage === 'object' &&
|
|
687
|
+
'status' in rawUsage &&
|
|
688
|
+
typeof (rawUsage as NormalizedUsageRecord).status === 'string'
|
|
689
|
+
? (rawUsage as NormalizedUsageRecord)
|
|
690
|
+
: null;
|
|
691
|
+
|
|
692
|
+
return {
|
|
693
|
+
workerOutput,
|
|
694
|
+
interactiveSummary,
|
|
695
|
+
executionMode,
|
|
696
|
+
runtimeSelection,
|
|
697
|
+
usage,
|
|
698
|
+
};
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
private buildContextRetryToolResults(
|
|
702
|
+
input: WorkerDecisionInput,
|
|
703
|
+
refreshedContext: AnyRecord,
|
|
704
|
+
): AnyRecord[] {
|
|
705
|
+
return [
|
|
706
|
+
...(input.lastToolResults ?? []),
|
|
707
|
+
{
|
|
708
|
+
tool_name: TOOLS.FEATURE_GET_CONTEXT,
|
|
709
|
+
feature_id: input.featureId,
|
|
710
|
+
refreshed_context: structuredClone(refreshedContext),
|
|
711
|
+
},
|
|
712
|
+
];
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
private async processOutputs(input: {
|
|
716
|
+
input: WorkerDecisionInput;
|
|
717
|
+
workerRun: WorkerRunResult;
|
|
718
|
+
result: WorkerDecisionResult;
|
|
719
|
+
plannerState: PlannerExecutionState;
|
|
720
|
+
allowContextRefreshRetry: boolean;
|
|
721
|
+
}): Promise<RequestRoutingResult> {
|
|
722
|
+
const { result, plannerState, allowContextRefreshRetry } = input;
|
|
723
|
+
const workerInput = input.input;
|
|
724
|
+
const outputs = asOutputs(input.workerRun.workerOutput);
|
|
725
|
+
result.rawOutputs.push(...outputs.map((output) => structuredClone(output)));
|
|
726
|
+
|
|
727
|
+
const blockingQuestionOutput = outputs.find((output) => isBlockingAskUserInputOutput(output));
|
|
728
|
+
if (blockingQuestionOutput) {
|
|
729
|
+
result.outputTypes.push('REQUEST');
|
|
730
|
+
await this.routeRequest(
|
|
731
|
+
workerInput,
|
|
732
|
+
blockingQuestionOutput,
|
|
733
|
+
result,
|
|
734
|
+
plannerState,
|
|
735
|
+
allowContextRefreshRetry,
|
|
736
|
+
);
|
|
737
|
+
return { contextRefreshRequested: false, refreshedContext: null };
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
const allowedTypes = new Set([
|
|
741
|
+
'PLAN_SUBMISSION',
|
|
742
|
+
'INTAKE_SUBMISSION',
|
|
743
|
+
'PATCH',
|
|
744
|
+
'NOTE',
|
|
745
|
+
'REQUEST',
|
|
746
|
+
]);
|
|
285
747
|
for (const output of outputs) {
|
|
286
748
|
const outputType = asNonEmptyString(output.type)?.toUpperCase();
|
|
287
749
|
if (!outputType) {
|
|
288
750
|
result.invalidOutput = true;
|
|
751
|
+
result.errorCode = ERROR_CODES.PROVIDER_OUTPUT_INVALID;
|
|
752
|
+
result.interactiveOutcome = input.workerRun.interactiveSummary
|
|
753
|
+
? 'provider_output_invalid'
|
|
754
|
+
: null;
|
|
289
755
|
continue;
|
|
290
756
|
}
|
|
757
|
+
|
|
291
758
|
result.outputTypes.push(outputType);
|
|
292
759
|
if (!allowedTypes.has(outputType)) {
|
|
293
760
|
result.invalidOutput = true;
|
|
761
|
+
result.errorCode = ERROR_CODES.PROVIDER_OUTPUT_INVALID;
|
|
762
|
+
result.interactiveOutcome = input.workerRun.interactiveSummary
|
|
763
|
+
? 'provider_output_invalid'
|
|
764
|
+
: null;
|
|
294
765
|
continue;
|
|
295
766
|
}
|
|
296
767
|
|
|
297
768
|
if (outputType === 'PLAN_SUBMISSION') {
|
|
298
|
-
|
|
299
|
-
|
|
769
|
+
await this.routePlanSubmission(workerInput, output, result, plannerState);
|
|
770
|
+
continue;
|
|
771
|
+
}
|
|
772
|
+
if (outputType === 'INTAKE_SUBMISSION') {
|
|
773
|
+
await this.routeIntakeSubmission(workerInput, output, result, plannerState);
|
|
300
774
|
continue;
|
|
301
775
|
}
|
|
302
776
|
if (outputType === 'PATCH') {
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
const hasPatchPayload = Boolean(asNonEmptyString(output.unified_diff ?? output.diff));
|
|
306
|
-
if (hasPatchPayload) {
|
|
307
|
-
result.patchApplied = true;
|
|
308
|
-
}
|
|
309
|
-
} else {
|
|
310
|
-
await this.routePatch(input, output, result);
|
|
777
|
+
if (!input.workerRun.interactiveSummary) {
|
|
778
|
+
await this.routePatch(workerInput, output, result);
|
|
311
779
|
}
|
|
312
780
|
continue;
|
|
313
781
|
}
|
|
314
782
|
if (outputType === 'NOTE') {
|
|
315
|
-
|
|
316
|
-
|
|
783
|
+
if (
|
|
784
|
+
input.workerRun.interactiveSummary &&
|
|
785
|
+
input.workerRun.interactiveSummary.fallbackReason !== null &&
|
|
786
|
+
!input.workerRun.interactiveSummary.hasNetNewWorktreeChanges
|
|
787
|
+
) {
|
|
788
|
+
result.invalidOutput = true;
|
|
789
|
+
result.errorCode = ERROR_CODES.PROVIDER_OUTPUT_INVALID;
|
|
790
|
+
result.interactiveOutcome = 'provider_output_invalid';
|
|
791
|
+
continue;
|
|
792
|
+
}
|
|
793
|
+
await this.routeNote(workerInput.featureId, output, result);
|
|
317
794
|
continue;
|
|
318
795
|
}
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
796
|
+
|
|
797
|
+
const requestResult = await this.routeRequest(
|
|
798
|
+
workerInput,
|
|
799
|
+
output,
|
|
800
|
+
result,
|
|
801
|
+
plannerState,
|
|
802
|
+
allowContextRefreshRetry,
|
|
803
|
+
);
|
|
804
|
+
if (requestResult.contextRefreshRequested) {
|
|
805
|
+
return requestResult;
|
|
322
806
|
}
|
|
323
807
|
}
|
|
324
808
|
|
|
325
|
-
|
|
809
|
+
return { contextRefreshRequested: false, refreshedContext: null };
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
private finalizeInteractiveOutcome(
|
|
813
|
+
result: WorkerDecisionResult,
|
|
814
|
+
interactiveSummary: InteractiveRunSummary | null,
|
|
815
|
+
): void {
|
|
816
|
+
if (!interactiveSummary) {
|
|
817
|
+
return;
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
result.checkpoint = structuredClone(interactiveSummary.finalCheckpoint);
|
|
821
|
+
if (interactiveSummary.finalCheckpoint) {
|
|
326
822
|
result.toolResults.push({
|
|
327
823
|
checkpoint: structuredClone(interactiveSummary.finalCheckpoint),
|
|
328
824
|
});
|
|
329
|
-
if (interactiveSummary.changedFiles.length > 0) {
|
|
330
|
-
result.patchApplied = true;
|
|
331
|
-
}
|
|
332
|
-
if (interactiveSummary.checkpointInvalid) {
|
|
333
|
-
result.invalidOutput = true;
|
|
334
|
-
}
|
|
335
825
|
}
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
});
|
|
353
|
-
|
|
354
|
-
if (this.activityMonitor) {
|
|
355
|
-
await this.activityMonitor.checkAndNotifyStuck(input.featureId);
|
|
826
|
+
if (
|
|
827
|
+
interactiveSummary.finalCheckpoint &&
|
|
828
|
+
interactiveSummary.hasNetNewWorktreeChanges &&
|
|
829
|
+
interactiveSummary.changedFiles.length > 0
|
|
830
|
+
) {
|
|
831
|
+
result.patchApplied = true;
|
|
832
|
+
}
|
|
833
|
+
if (interactiveSummary.checkpointInvalid) {
|
|
834
|
+
result.errorCode = ERROR_CODES.INTERACTIVE_CHECKPOINT_INVALID;
|
|
835
|
+
result.interactiveOutcome = 'checkpoint_invalid';
|
|
836
|
+
} else if (result.invalidOutput) {
|
|
837
|
+
result.interactiveOutcome = 'provider_output_invalid';
|
|
838
|
+
} else if (result.patchApplied) {
|
|
839
|
+
result.interactiveOutcome = 'progress_applied';
|
|
840
|
+
} else if (!result.planSubmission && !result.requestHandled && !result.questionRequested) {
|
|
841
|
+
result.interactiveOutcome = 'no_new_work';
|
|
356
842
|
}
|
|
357
|
-
|
|
358
|
-
return result;
|
|
359
843
|
}
|
|
360
844
|
|
|
361
845
|
private async resolveExecutionMode(featureId: string, role: RuntimeRole): Promise<ExecutionMode> {
|
|
@@ -365,21 +849,37 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
|
|
|
365
849
|
return 'deterministic';
|
|
366
850
|
}
|
|
367
851
|
|
|
852
|
+
private async resolveRuntimeSelection(
|
|
853
|
+
featureId: string,
|
|
854
|
+
role: RuntimeRole,
|
|
855
|
+
): Promise<ProviderSelection> {
|
|
856
|
+
if (this.resolveRuntimeSelectionOverride) {
|
|
857
|
+
return await this.resolveRuntimeSelectionOverride(featureId, role);
|
|
858
|
+
}
|
|
859
|
+
return this.provider.selection;
|
|
860
|
+
}
|
|
861
|
+
|
|
368
862
|
private isInteractiveEligible(executionMode: ExecutionMode, role: RuntimeRole): boolean {
|
|
369
863
|
if (executionMode !== 'interactive') {
|
|
370
864
|
return false;
|
|
371
865
|
}
|
|
372
|
-
|
|
866
|
+
const capabilities = this.provider.getCapabilities?.();
|
|
867
|
+
const supportsInteractive = !capabilities
|
|
868
|
+
? true
|
|
869
|
+
: capabilities.supportsInteractiveMode && capabilities.supportsWorkingDirectory;
|
|
870
|
+
if (!supportsInteractive) {
|
|
373
871
|
return false;
|
|
374
872
|
}
|
|
375
|
-
if (
|
|
873
|
+
if (role === 'planner') {
|
|
874
|
+
return Boolean(this.repoRoot);
|
|
875
|
+
}
|
|
876
|
+
if (role !== 'builder' && role !== 'qa' && role !== 'reconciler') {
|
|
376
877
|
return false;
|
|
377
878
|
}
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
return true;
|
|
879
|
+
if (!this.repoRoot || !this.watchdog || !this.checkpointService || !this.resolveWorktreePath) {
|
|
880
|
+
return false;
|
|
381
881
|
}
|
|
382
|
-
return
|
|
882
|
+
return true;
|
|
383
883
|
}
|
|
384
884
|
|
|
385
885
|
private resolveInteractiveConfig(): InteractiveExecutionConfig {
|
|
@@ -400,17 +900,23 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
|
|
|
400
900
|
input: WorkerDecisionInput,
|
|
401
901
|
executionMode: ExecutionMode,
|
|
402
902
|
workingDirectory: string | undefined,
|
|
903
|
+
runtimeSelection: ProviderSelection,
|
|
403
904
|
): WorkerRunInput {
|
|
404
905
|
return {
|
|
405
906
|
role: input.role,
|
|
406
907
|
feature_id: input.featureId,
|
|
908
|
+
...(input.role === 'planner'
|
|
909
|
+
? { planner_phase: resolvePlannerPhaseFromContext(input.contextBundle) }
|
|
910
|
+
: {}),
|
|
407
911
|
context_bundle: input.contextBundle,
|
|
408
|
-
instructions: input
|
|
912
|
+
instructions: this.resolvePromptInstructions(input, executionMode),
|
|
409
913
|
last_tool_results: input.lastToolResults ?? [],
|
|
410
914
|
runtime_selection: {
|
|
411
|
-
provider:
|
|
412
|
-
model:
|
|
413
|
-
|
|
915
|
+
provider: runtimeSelection.provider,
|
|
916
|
+
model: runtimeSelection.model,
|
|
917
|
+
provider_config_env: runtimeSelection.provider_config_env ?? null,
|
|
918
|
+
provider_config_ref: runtimeSelection.provider_config_ref,
|
|
919
|
+
agent_config: runtimeSelection.agent_config ?? null,
|
|
414
920
|
},
|
|
415
921
|
execution_mode: executionMode,
|
|
416
922
|
working_directory: workingDirectory,
|
|
@@ -418,16 +924,21 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
|
|
|
418
924
|
};
|
|
419
925
|
}
|
|
420
926
|
|
|
421
|
-
private async runInteractiveWorker(
|
|
927
|
+
private async runInteractiveWorker(
|
|
928
|
+
input: WorkerDecisionInput,
|
|
929
|
+
runtimeSelection: ProviderSelection,
|
|
930
|
+
): Promise<InteractiveRunSummary> {
|
|
422
931
|
if (!this.repoRoot || !this.watchdog || !this.checkpointService || !this.resolveWorktreePath) {
|
|
423
932
|
const fallbackOutput = await this.provider.runWorker(
|
|
424
|
-
this.buildRunInput(input, 'deterministic', undefined),
|
|
933
|
+
this.buildRunInput(input, 'deterministic', undefined, runtimeSelection),
|
|
425
934
|
);
|
|
426
935
|
return {
|
|
427
936
|
workerOutput: fallbackOutput,
|
|
428
937
|
finalCheckpoint: this.createSyntheticCheckpoint(input.featureId),
|
|
429
938
|
changedFiles: [],
|
|
939
|
+
hasNetNewWorktreeChanges: false,
|
|
430
940
|
checkpointInvalid: false,
|
|
941
|
+
fallbackReason: readInteractiveFallbackReason(fallbackOutput),
|
|
431
942
|
};
|
|
432
943
|
}
|
|
433
944
|
|
|
@@ -444,6 +955,7 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
|
|
|
444
955
|
|
|
445
956
|
let latestCheckpoint: CheckpointRecord | null = null;
|
|
446
957
|
let checkpointInvalid = false;
|
|
958
|
+
let lastCheckpointFailureReason: string | null = null;
|
|
447
959
|
let lastCheckpointAt = 0;
|
|
448
960
|
const checkpointDebounceMs = 5_000;
|
|
449
961
|
let checkpointQueue = Promise.resolve();
|
|
@@ -464,10 +976,14 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
|
|
|
464
976
|
});
|
|
465
977
|
if (checkpoint) {
|
|
466
978
|
latestCheckpoint = checkpoint.checkpoint;
|
|
467
|
-
checkpointInvalid = checkpointInvalid ||
|
|
979
|
+
checkpointInvalid = checkpointInvalid || checkpoint.blockMerge;
|
|
468
980
|
}
|
|
469
|
-
} catch {
|
|
981
|
+
} catch (checkpointError: unknown) {
|
|
470
982
|
checkpointInvalid = true;
|
|
983
|
+
lastCheckpointFailureReason =
|
|
984
|
+
checkpointError instanceof Error
|
|
985
|
+
? checkpointError.message
|
|
986
|
+
: (extractNonErrorMessage(checkpointError) ?? 'checkpoint creation failed');
|
|
471
987
|
} finally {
|
|
472
988
|
lastCheckpointAt = Date.now();
|
|
473
989
|
}
|
|
@@ -491,15 +1007,20 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
|
|
|
491
1007
|
|
|
492
1008
|
try {
|
|
493
1009
|
const workerOutput = await this.provider.runWorker(
|
|
494
|
-
this.buildRunInput(input, 'interactive', worktreePath),
|
|
1010
|
+
this.buildRunInput(input, 'interactive', worktreePath, runtimeSelection),
|
|
495
1011
|
);
|
|
496
1012
|
await enqueueCheckpoint('final');
|
|
497
1013
|
const changedFiles = latestCheckpoint?.files_changed ?? [];
|
|
1014
|
+
const hasNetNewWorktreeChanges = latestCheckpoint?.net_new_worktree_change === true;
|
|
498
1015
|
return {
|
|
499
1016
|
workerOutput,
|
|
500
|
-
finalCheckpoint:
|
|
1017
|
+
finalCheckpoint:
|
|
1018
|
+
latestCheckpoint ??
|
|
1019
|
+
this.createSyntheticCheckpoint(input.featureId, lastCheckpointFailureReason),
|
|
501
1020
|
changedFiles,
|
|
1021
|
+
hasNetNewWorktreeChanges,
|
|
502
1022
|
checkpointInvalid,
|
|
1023
|
+
fallbackReason: readInteractiveFallbackReason(workerOutput),
|
|
503
1024
|
};
|
|
504
1025
|
} finally {
|
|
505
1026
|
clearInterval(timer);
|
|
@@ -509,34 +1030,152 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
|
|
|
509
1030
|
}
|
|
510
1031
|
}
|
|
511
1032
|
|
|
512
|
-
private createSyntheticCheckpoint(
|
|
1033
|
+
private createSyntheticCheckpoint(
|
|
1034
|
+
featureId: string,
|
|
1035
|
+
failureReason: string | null = null,
|
|
1036
|
+
): CheckpointRecord {
|
|
513
1037
|
return {
|
|
514
1038
|
checkpoint_id: `checkpoint-synthetic-${Date.now()}`,
|
|
515
1039
|
timestamp: new Date().toISOString(),
|
|
516
1040
|
files_changed: [],
|
|
517
|
-
validation_status: 'skipped',
|
|
518
|
-
violations: [],
|
|
1041
|
+
validation_status: failureReason ? 'invalid' : 'skipped',
|
|
1042
|
+
violations: failureReason ? [failureReason] : [],
|
|
519
1043
|
diff_snapshot: `.aop/features/${featureId}/checkpoints/synthetic.diff`,
|
|
1044
|
+
net_new_worktree_change: false,
|
|
520
1045
|
};
|
|
521
1046
|
}
|
|
522
1047
|
|
|
1048
|
+
private async runInteractivePlanner(
|
|
1049
|
+
input: WorkerDecisionInput,
|
|
1050
|
+
runtimeSelection: ProviderSelection,
|
|
1051
|
+
): Promise<InteractiveRunSummary> {
|
|
1052
|
+
const workerOutput = await this.provider.runWorker(
|
|
1053
|
+
this.buildRunInput(
|
|
1054
|
+
input,
|
|
1055
|
+
'interactive',
|
|
1056
|
+
this.resolvePlannerWorkingDirectory(input.featureId),
|
|
1057
|
+
runtimeSelection,
|
|
1058
|
+
),
|
|
1059
|
+
);
|
|
1060
|
+
return {
|
|
1061
|
+
workerOutput,
|
|
1062
|
+
finalCheckpoint: null,
|
|
1063
|
+
changedFiles: [],
|
|
1064
|
+
hasNetNewWorktreeChanges: false,
|
|
1065
|
+
checkpointInvalid: false,
|
|
1066
|
+
fallbackReason: readInteractiveFallbackReason(workerOutput),
|
|
1067
|
+
};
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
private resolvePromptInstructions(
|
|
1071
|
+
input: WorkerDecisionInput,
|
|
1072
|
+
executionMode: ExecutionMode,
|
|
1073
|
+
): string {
|
|
1074
|
+
const baseInstructions = input.instructions.trim();
|
|
1075
|
+
if (executionMode !== 'interactive') {
|
|
1076
|
+
return baseInstructions;
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
if (input.role === 'builder' || input.role === 'qa' || input.role === 'reconciler') {
|
|
1080
|
+
const interactiveOverride =
|
|
1081
|
+
input.role === 'builder'
|
|
1082
|
+
? [
|
|
1083
|
+
'Interactive mode override:',
|
|
1084
|
+
'- Edit planned files directly in the working directory.',
|
|
1085
|
+
'- Ignore any generic instruction that asks you to emit PATCH or unified diff output.',
|
|
1086
|
+
'- Use the accepted plan, allowed areas, planned file list, and latest evidence in the context summary below as your execution contract.',
|
|
1087
|
+
'- Return NOTE only after making planned file changes.',
|
|
1088
|
+
'- If the safe fix surface exceeds the accepted plan, return REQUEST.action=more_context with a concrete blocker.',
|
|
1089
|
+
'- Use ask_user_input only for genuine human decisions, approvals, or policy exceptions you cannot resolve from the plan and repo.',
|
|
1090
|
+
].join('\n')
|
|
1091
|
+
: input.role === 'qa'
|
|
1092
|
+
? [
|
|
1093
|
+
'Interactive mode override:',
|
|
1094
|
+
'- Edit files directly in the working directory.',
|
|
1095
|
+
'- Ignore any generic instruction that asks you to emit PATCH or unified diff output.',
|
|
1096
|
+
'- Use the accepted plan, qa_test_index, and latest evidence in the context summary below as your verification contract.',
|
|
1097
|
+
'- Return NOTE only after making file changes that address a reproduced failure or verification gap.',
|
|
1098
|
+
'- Use more_context/context_refresh only when evidence is stale or the accepted plan does not authorize the safe fix surface.',
|
|
1099
|
+
'- Use ask_user_input only for genuine operator decisions, approvals, or risk acknowledgements.',
|
|
1100
|
+
].join('\n')
|
|
1101
|
+
: [
|
|
1102
|
+
'Interactive mode override:',
|
|
1103
|
+
'- Edit files directly in the conflicted worktree.',
|
|
1104
|
+
'- Ignore any generic instruction that asks you to emit PATCH or unified diff output.',
|
|
1105
|
+
'- Use the spec, accepted plan, conflict status, approved collision context, and latest evidence in the context summary below as your reconciliation contract.',
|
|
1106
|
+
'- Return NOTE only after resolving conflicted files and performing proportionate verification.',
|
|
1107
|
+
'- Use more_context/context_refresh only when the conflict snapshot or surrounding repo state is stale.',
|
|
1108
|
+
'- Use ask_user_input only when preserving mainline semantics and feature intent requires an operator choice.',
|
|
1109
|
+
].join('\n');
|
|
1110
|
+
return baseInstructions.length > 0
|
|
1111
|
+
? `${interactiveOverride}\n\nAdditional task context:\n${baseInstructions}`
|
|
1112
|
+
: interactiveOverride;
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
if (input.role === 'planner') {
|
|
1116
|
+
const plannerOverride =
|
|
1117
|
+
resolvePlannerPhaseFromContext(input.contextBundle) === 'intake'
|
|
1118
|
+
? [
|
|
1119
|
+
'Interactive mode override:',
|
|
1120
|
+
'- Read and update the intake artifacts directly on disk.',
|
|
1121
|
+
'- Emit INTAKE_SUBMISSION when the verified manifest is ready.',
|
|
1122
|
+
'- Emit REQUEST.action=ask_user_input only for blocking requirement clarification.',
|
|
1123
|
+
'- If you ask for user input, stop there for the turn and wait for the persisted answer before promoting the manifest.',
|
|
1124
|
+
'- Never self-assert human_review_confirmed without an answered manifest-review confirmation question in context.',
|
|
1125
|
+
'- Return NOTE only when you intentionally keep intake unchanged and can justify that decision from the observed feature state.',
|
|
1126
|
+
].join('\n')
|
|
1127
|
+
: [
|
|
1128
|
+
'Interactive mode override:',
|
|
1129
|
+
'- Read and update the planning artifacts directly on disk.',
|
|
1130
|
+
'- Emit PLAN_SUBMISSION or REQUEST.action=amend_plan when the accepted plan must change.',
|
|
1131
|
+
'- Return NOTE only when you intentionally keep the accepted plan unchanged and can justify that decision from the observed feature state.',
|
|
1132
|
+
].join('\n');
|
|
1133
|
+
return baseInstructions.length > 0
|
|
1134
|
+
? `${plannerOverride}\n\nAdditional task context:\n${baseInstructions}`
|
|
1135
|
+
: plannerOverride;
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
return baseInstructions;
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
private resolvePlannerWorkingDirectory(featureId: string): string | undefined {
|
|
1142
|
+
if (!this.repoRoot) {
|
|
1143
|
+
return undefined;
|
|
1144
|
+
}
|
|
1145
|
+
return path.join(this.repoRoot, '.aop', 'features', featureId);
|
|
1146
|
+
}
|
|
1147
|
+
|
|
523
1148
|
private async routePlanSubmission(
|
|
524
1149
|
input: WorkerDecisionInput,
|
|
525
1150
|
output: AnyRecord,
|
|
526
1151
|
result: WorkerDecisionResult,
|
|
1152
|
+
plannerState: PlannerExecutionState,
|
|
527
1153
|
): Promise<void> {
|
|
528
1154
|
if (input.role !== 'planner') {
|
|
529
1155
|
return;
|
|
530
1156
|
}
|
|
531
1157
|
|
|
1158
|
+
if (plannerState.planMutationApplied) {
|
|
1159
|
+
return;
|
|
1160
|
+
}
|
|
1161
|
+
|
|
532
1162
|
const planJson = sanitizePlannerPlan(asRecord(output.plan_json ?? output.plan));
|
|
533
1163
|
if (Object.keys(planJson).length === 0) {
|
|
534
1164
|
return;
|
|
535
1165
|
}
|
|
536
1166
|
|
|
537
|
-
|
|
538
|
-
|
|
1167
|
+
if (
|
|
1168
|
+
(await this.requestIntakeClarificationForPlanMutation(
|
|
1169
|
+
input,
|
|
1170
|
+
result,
|
|
1171
|
+
ERROR_CODES.VERIFIED_MANIFEST_REQUIRED,
|
|
1172
|
+
)) === true
|
|
1173
|
+
) {
|
|
1174
|
+
return;
|
|
1175
|
+
}
|
|
1176
|
+
|
|
539
1177
|
const requestedExpectedVersion = readPlanVersion(output.expected_plan_version);
|
|
1178
|
+
const existingVersion = plannerState.currentPlanVersion;
|
|
540
1179
|
|
|
541
1180
|
if (existingVersion == null) {
|
|
542
1181
|
const response = await this.toolCaller.callTool('planner', TOOLS.PLAN_SUBMIT, {
|
|
@@ -544,6 +1183,7 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
|
|
|
544
1183
|
plan_json: planJson,
|
|
545
1184
|
});
|
|
546
1185
|
result.toolResults.push(asRecord(response.data));
|
|
1186
|
+
this.recordPlannerMutation(plannerState, response.data, planJson);
|
|
547
1187
|
result.planSubmission = true;
|
|
548
1188
|
return;
|
|
549
1189
|
}
|
|
@@ -555,15 +1195,102 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
|
|
|
555
1195
|
plan_json: planJson,
|
|
556
1196
|
});
|
|
557
1197
|
result.toolResults.push(asRecord(response.data));
|
|
1198
|
+
this.recordPlannerMutation(plannerState, response.data, planJson);
|
|
558
1199
|
result.planSubmission = true;
|
|
559
1200
|
}
|
|
560
1201
|
|
|
1202
|
+
private async routeIntakeSubmission(
|
|
1203
|
+
input: WorkerDecisionInput,
|
|
1204
|
+
output: AnyRecord,
|
|
1205
|
+
result: WorkerDecisionResult,
|
|
1206
|
+
plannerState: PlannerExecutionState,
|
|
1207
|
+
): Promise<void> {
|
|
1208
|
+
if (input.role !== 'planner' || plannerState.planMutationApplied) {
|
|
1209
|
+
return;
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
const intakeSubmission = asRecord(output.intake_submission);
|
|
1213
|
+
if (!intakeSubmission) {
|
|
1214
|
+
return;
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
try {
|
|
1218
|
+
const response = await this.toolCaller.callTool('planner', TOOLS.FEATURE_INTAKE_SUBMIT, {
|
|
1219
|
+
feature_id: input.featureId,
|
|
1220
|
+
intake_submission: intakeSubmission,
|
|
1221
|
+
});
|
|
1222
|
+
result.toolResults.push(asRecord(response.data));
|
|
1223
|
+
result.intakeSubmission = true;
|
|
1224
|
+
} catch (error) {
|
|
1225
|
+
const failure = readToolFailureDetails(error);
|
|
1226
|
+
const plannerPhase = resolvePlannerPhaseFromContext(input.contextBundle);
|
|
1227
|
+
if (failure?.code !== ERROR_CODES.INTAKE_SUBMISSION_INVALID || plannerPhase !== 'intake') {
|
|
1228
|
+
throw error;
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
const ambiguityIds = normalizeList([
|
|
1232
|
+
...asStringArray(failure.details.missing_ambiguity_evidence_ids),
|
|
1233
|
+
...asStringArray(failure.details.open_ambiguity_ids),
|
|
1234
|
+
]);
|
|
1235
|
+
if (!hasOpenIntakeQuestion(input.contextBundle)) {
|
|
1236
|
+
const ambiguities = readIntakeAmbiguitiesForRecovery(input.contextBundle, ambiguityIds);
|
|
1237
|
+
const priorAnswers = readAnsweredIntakeClarifications(input.contextBundle).filter(
|
|
1238
|
+
(answer) =>
|
|
1239
|
+
ambiguityIds.length === 0 ||
|
|
1240
|
+
answer.ambiguityIds.some((ambiguityId) => ambiguityIds.includes(ambiguityId)),
|
|
1241
|
+
);
|
|
1242
|
+
const sessionId =
|
|
1243
|
+
this.resolveRoleSessionId?.(input.role, input.featureId) ?? `bootstrap:${input.role}`;
|
|
1244
|
+
const response = await this.toolCaller.callTool(
|
|
1245
|
+
'orchestrator',
|
|
1246
|
+
TOOLS.FEATURE_QUESTION_CREATE,
|
|
1247
|
+
{
|
|
1248
|
+
feature_id: input.featureId,
|
|
1249
|
+
role: 'planner',
|
|
1250
|
+
session_id: sessionId,
|
|
1251
|
+
question_type: 'clarification',
|
|
1252
|
+
prompt: buildIntakeClarificationPrompt(
|
|
1253
|
+
ambiguities,
|
|
1254
|
+
failure.code ?? ERROR_CODES.INTAKE_SUBMISSION_INVALID,
|
|
1255
|
+
priorAnswers,
|
|
1256
|
+
),
|
|
1257
|
+
details: {
|
|
1258
|
+
ambiguity_ids: ambiguities.map((ambiguity) => ambiguity.id),
|
|
1259
|
+
obligation_ids: normalizeList(
|
|
1260
|
+
ambiguities.flatMap((ambiguity) => ambiguity.obligationIds),
|
|
1261
|
+
),
|
|
1262
|
+
prior_answered_ambiguity_ids: ambiguities
|
|
1263
|
+
.filter((ambiguity) =>
|
|
1264
|
+
priorAnswers.some((answer) => answer.ambiguityIds.includes(ambiguity.id)),
|
|
1265
|
+
)
|
|
1266
|
+
.map((ambiguity) => ambiguity.id),
|
|
1267
|
+
recovery_reason: failure.code ?? ERROR_CODES.INTAKE_SUBMISSION_INVALID,
|
|
1268
|
+
recovery_source: 'intake_submission_validation',
|
|
1269
|
+
validation_message: failure.message,
|
|
1270
|
+
},
|
|
1271
|
+
expected_answer: {
|
|
1272
|
+
kind: 'free_text',
|
|
1273
|
+
},
|
|
1274
|
+
blocking: true,
|
|
1275
|
+
phase: STATUS.INTAKE,
|
|
1276
|
+
request_action: 'ask_user_input',
|
|
1277
|
+
resume_status: STATUS.INTAKE,
|
|
1278
|
+
resume_phase: STATUS.INTAKE,
|
|
1279
|
+
},
|
|
1280
|
+
);
|
|
1281
|
+
result.toolResults.push(asRecord(response.data));
|
|
1282
|
+
}
|
|
1283
|
+
result.requestHandled = true;
|
|
1284
|
+
result.questionRequested = true;
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
|
|
561
1288
|
private async routePatch(
|
|
562
1289
|
input: WorkerDecisionInput,
|
|
563
1290
|
output: AnyRecord,
|
|
564
1291
|
result: WorkerDecisionResult,
|
|
565
1292
|
): Promise<void> {
|
|
566
|
-
if (input.role !== 'builder' && input.role !== 'qa') {
|
|
1293
|
+
if (input.role !== 'builder' && input.role !== 'qa' && input.role !== 'reconciler') {
|
|
567
1294
|
return;
|
|
568
1295
|
}
|
|
569
1296
|
|
|
@@ -602,11 +1329,13 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
|
|
|
602
1329
|
input: WorkerDecisionInput,
|
|
603
1330
|
output: AnyRecord,
|
|
604
1331
|
result: WorkerDecisionResult,
|
|
605
|
-
|
|
1332
|
+
plannerState: PlannerExecutionState,
|
|
1333
|
+
allowContextRefreshRetry: boolean,
|
|
1334
|
+
): Promise<RequestRoutingResult> {
|
|
606
1335
|
const request = asRecord(output.request ?? output);
|
|
607
1336
|
const action = asNonEmptyString(request.action ?? request.request_type)?.toLowerCase();
|
|
608
1337
|
if (!action) {
|
|
609
|
-
return;
|
|
1338
|
+
return { contextRefreshRequested: false, refreshedContext: null };
|
|
610
1339
|
}
|
|
611
1340
|
|
|
612
1341
|
if (action === 'prioritize') {
|
|
@@ -615,13 +1344,13 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
|
|
|
615
1344
|
result.priorityOrder = featureOrder;
|
|
616
1345
|
result.requestHandled = true;
|
|
617
1346
|
}
|
|
618
|
-
return;
|
|
1347
|
+
return { contextRefreshRequested: false, refreshedContext: null };
|
|
619
1348
|
}
|
|
620
1349
|
|
|
621
1350
|
if (action === 'lock_acquire') {
|
|
622
1351
|
const resources = asStringArray(request.resources);
|
|
623
1352
|
if (resources.length === 0) {
|
|
624
|
-
return;
|
|
1353
|
+
return { contextRefreshRequested: false, refreshedContext: null };
|
|
625
1354
|
}
|
|
626
1355
|
const response = await this.toolCaller.callTool('orchestrator', TOOLS.LOCKS_ACQUIRE, {
|
|
627
1356
|
feature_id: input.featureId,
|
|
@@ -629,13 +1358,13 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
|
|
|
629
1358
|
});
|
|
630
1359
|
result.toolResults.push(asRecord(response.data));
|
|
631
1360
|
result.requestHandled = true;
|
|
632
|
-
return;
|
|
1361
|
+
return { contextRefreshRequested: false, refreshedContext: null };
|
|
633
1362
|
}
|
|
634
1363
|
|
|
635
1364
|
if (action === 'lock_release') {
|
|
636
1365
|
const resources = asStringArray(request.resources);
|
|
637
1366
|
if (resources.length === 0) {
|
|
638
|
-
return;
|
|
1367
|
+
return { contextRefreshRequested: false, refreshedContext: null };
|
|
639
1368
|
}
|
|
640
1369
|
const response = await this.toolCaller.callTool('orchestrator', TOOLS.LOCKS_RELEASE, {
|
|
641
1370
|
feature_id: input.featureId,
|
|
@@ -643,36 +1372,108 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
|
|
|
643
1372
|
});
|
|
644
1373
|
result.toolResults.push(asRecord(response.data));
|
|
645
1374
|
result.requestHandled = true;
|
|
646
|
-
return;
|
|
1375
|
+
return { contextRefreshRequested: false, refreshedContext: null };
|
|
647
1376
|
}
|
|
648
1377
|
|
|
649
1378
|
if (action === 'more_context' || action === 'context_refresh') {
|
|
1379
|
+
result.contextRequestCount += 1;
|
|
1380
|
+
result.lastContextRequestAt = new Date().toISOString();
|
|
1381
|
+
result.lastContextRequestRole = input.role;
|
|
1382
|
+
if (!allowContextRefreshRetry) {
|
|
1383
|
+
return { contextRefreshRequested: true, refreshedContext: null };
|
|
1384
|
+
}
|
|
650
1385
|
const response = await this.toolCaller.callTool(input.role, TOOLS.FEATURE_GET_CONTEXT, {
|
|
651
1386
|
feature_id: input.featureId,
|
|
652
1387
|
});
|
|
653
1388
|
result.toolResults.push(asRecord(response.data));
|
|
1389
|
+
this.refreshPlannerStateFromContext(plannerState, response.data);
|
|
1390
|
+
return {
|
|
1391
|
+
contextRefreshRequested: true,
|
|
1392
|
+
refreshedContext: asRecord(response.data) ?? {},
|
|
1393
|
+
};
|
|
1394
|
+
}
|
|
1395
|
+
|
|
1396
|
+
if (action === 'ask_user_input') {
|
|
1397
|
+
const prompt = asNonEmptyString(request.prompt);
|
|
1398
|
+
if (!prompt) {
|
|
1399
|
+
return { contextRefreshRequested: false, refreshedContext: null };
|
|
1400
|
+
}
|
|
1401
|
+
const sessionId =
|
|
1402
|
+
this.resolveRoleSessionId?.(input.role, input.featureId) ?? `bootstrap:${input.role}`;
|
|
1403
|
+
const currentStatus = asNonEmptyString(
|
|
1404
|
+
asRecord(asRecord(input.contextBundle.state).front_matter).status,
|
|
1405
|
+
);
|
|
1406
|
+
const plannerPhase =
|
|
1407
|
+
input.role === 'planner' ? resolvePlannerPhaseFromContext(input.contextBundle) : 'planning';
|
|
1408
|
+
const response = await this.toolCaller.callTool(
|
|
1409
|
+
'orchestrator',
|
|
1410
|
+
TOOLS.FEATURE_QUESTION_CREATE,
|
|
1411
|
+
{
|
|
1412
|
+
feature_id: input.featureId,
|
|
1413
|
+
role: input.role,
|
|
1414
|
+
session_id: sessionId,
|
|
1415
|
+
question_type: asNonEmptyString(request.question_type) ?? 'clarification',
|
|
1416
|
+
prompt,
|
|
1417
|
+
details: asRecord(request.details) ?? {},
|
|
1418
|
+
expected_answer: asRecord(request.expected_answer) ?? undefined,
|
|
1419
|
+
blocking: request.blocking !== false,
|
|
1420
|
+
phase: plannerPhase === 'intake' ? STATUS.INTAKE : (currentStatus ?? input.role),
|
|
1421
|
+
request_action: action,
|
|
1422
|
+
resume_status: plannerPhase === 'intake' ? STATUS.INTAKE : undefined,
|
|
1423
|
+
resume_phase: plannerPhase === 'intake' ? STATUS.INTAKE : undefined,
|
|
1424
|
+
},
|
|
1425
|
+
);
|
|
1426
|
+
result.toolResults.push(asRecord(response.data));
|
|
654
1427
|
result.requestHandled = true;
|
|
655
|
-
|
|
1428
|
+
result.questionRequested = true;
|
|
1429
|
+
try {
|
|
1430
|
+
await this.toolCaller.callTool('orchestrator', TOOLS.FEATURE_LOG_APPEND, {
|
|
1431
|
+
feature_id: input.featureId,
|
|
1432
|
+
note: JSON.stringify({
|
|
1433
|
+
action,
|
|
1434
|
+
question_id: asRecord(response.data)?.question_id ?? null,
|
|
1435
|
+
role: input.role,
|
|
1436
|
+
prompt,
|
|
1437
|
+
}),
|
|
1438
|
+
});
|
|
1439
|
+
} catch (_error) {
|
|
1440
|
+
// Best effort log for observability.
|
|
1441
|
+
}
|
|
1442
|
+
return { contextRefreshRequested: false, refreshedContext: null };
|
|
656
1443
|
}
|
|
657
1444
|
|
|
658
1445
|
if (action === 'amend_plan' && input.role === 'planner') {
|
|
1446
|
+
if (plannerState.planMutationApplied) {
|
|
1447
|
+
return { contextRefreshRequested: false, refreshedContext: null };
|
|
1448
|
+
}
|
|
1449
|
+
|
|
659
1450
|
const planJson = sanitizePlannerPlan(asRecord(request.plan_json));
|
|
660
1451
|
if (Object.keys(planJson).length === 0) {
|
|
661
|
-
return;
|
|
1452
|
+
return { contextRefreshRequested: false, refreshedContext: null };
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
if (
|
|
1456
|
+
(await this.requestIntakeClarificationForPlanMutation(
|
|
1457
|
+
input,
|
|
1458
|
+
result,
|
|
1459
|
+
ERROR_CODES.VERIFIED_MANIFEST_REQUIRED,
|
|
1460
|
+
)) === true
|
|
1461
|
+
) {
|
|
1462
|
+
return { contextRefreshRequested: false, refreshedContext: null };
|
|
662
1463
|
}
|
|
663
1464
|
|
|
664
|
-
const contextPlan = asRecord(input.contextBundle.plan);
|
|
665
|
-
const existingVersion = readPlanVersion(contextPlan.plan_version);
|
|
666
1465
|
const requestedExpectedVersion = readPlanVersion(request.expected_plan_version);
|
|
1466
|
+
const existingVersion = plannerState.currentPlanVersion;
|
|
667
1467
|
if (existingVersion == null) {
|
|
668
1468
|
const response = await this.toolCaller.callTool('planner', TOOLS.PLAN_SUBMIT, {
|
|
669
1469
|
feature_id: input.featureId,
|
|
670
1470
|
plan_json: planJson,
|
|
671
1471
|
});
|
|
672
1472
|
result.toolResults.push(asRecord(response.data));
|
|
1473
|
+
this.recordPlannerMutation(plannerState, response.data, planJson);
|
|
673
1474
|
result.requestHandled = true;
|
|
674
1475
|
result.planSubmission = true;
|
|
675
|
-
return;
|
|
1476
|
+
return { contextRefreshRequested: false, refreshedContext: null };
|
|
676
1477
|
}
|
|
677
1478
|
|
|
678
1479
|
const response = await this.toolCaller.callTool('planner', TOOLS.PLAN_UPDATE, {
|
|
@@ -681,8 +1482,122 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
|
|
|
681
1482
|
plan_json: planJson,
|
|
682
1483
|
});
|
|
683
1484
|
result.toolResults.push(asRecord(response.data));
|
|
1485
|
+
this.recordPlannerMutation(plannerState, response.data, planJson);
|
|
684
1486
|
result.requestHandled = true;
|
|
685
1487
|
result.planSubmission = true;
|
|
1488
|
+
return { contextRefreshRequested: false, refreshedContext: null };
|
|
1489
|
+
}
|
|
1490
|
+
|
|
1491
|
+
try {
|
|
1492
|
+
await this.toolCaller.callTool('orchestrator', TOOLS.FEATURE_LOG_APPEND, {
|
|
1493
|
+
feature_id: input.featureId,
|
|
1494
|
+
note: JSON.stringify({
|
|
1495
|
+
action: 'unknown_request_action',
|
|
1496
|
+
requested_action: action,
|
|
1497
|
+
role: input.role,
|
|
1498
|
+
}),
|
|
1499
|
+
});
|
|
1500
|
+
} catch (_error) {
|
|
1501
|
+
// Best effort observability for unknown actions.
|
|
1502
|
+
}
|
|
1503
|
+
return { contextRefreshRequested: false, refreshedContext: null };
|
|
1504
|
+
}
|
|
1505
|
+
|
|
1506
|
+
private async requestIntakeClarificationForPlanMutation(
|
|
1507
|
+
input: WorkerDecisionInput,
|
|
1508
|
+
result: WorkerDecisionResult,
|
|
1509
|
+
recoveryReason: string,
|
|
1510
|
+
): Promise<boolean> {
|
|
1511
|
+
if (
|
|
1512
|
+
input.role !== 'planner' ||
|
|
1513
|
+
resolvePlannerPhaseFromContext(input.contextBundle) !== 'intake'
|
|
1514
|
+
) {
|
|
1515
|
+
return false;
|
|
1516
|
+
}
|
|
1517
|
+
|
|
1518
|
+
const verifiedManifest = asRecord(asRecord(input.contextBundle.intake).verified_manifest);
|
|
1519
|
+
if (Object.keys(verifiedManifest).length > 0) {
|
|
1520
|
+
return false;
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1523
|
+
if (hasOpenIntakeQuestion(input.contextBundle)) {
|
|
1524
|
+
result.requestHandled = true;
|
|
1525
|
+
return true;
|
|
1526
|
+
}
|
|
1527
|
+
|
|
1528
|
+
const ambiguities = readOpenIntakeAmbiguities(input.contextBundle);
|
|
1529
|
+
const priorAnswers = readAnsweredIntakeClarifications(input.contextBundle);
|
|
1530
|
+
if (ambiguities.length === 0) {
|
|
1531
|
+
result.requestHandled = true;
|
|
1532
|
+
return true;
|
|
1533
|
+
}
|
|
1534
|
+
|
|
1535
|
+
const sessionId =
|
|
1536
|
+
this.resolveRoleSessionId?.(input.role, input.featureId) ?? `bootstrap:${input.role}`;
|
|
1537
|
+
const response = await this.toolCaller.callTool('orchestrator', TOOLS.FEATURE_QUESTION_CREATE, {
|
|
1538
|
+
feature_id: input.featureId,
|
|
1539
|
+
role: input.role,
|
|
1540
|
+
session_id: sessionId,
|
|
1541
|
+
question_type: 'clarification',
|
|
1542
|
+
prompt: buildIntakeClarificationPrompt(ambiguities, recoveryReason, priorAnswers),
|
|
1543
|
+
details: {
|
|
1544
|
+
ambiguity_ids: ambiguities.map((ambiguity) => ambiguity.id),
|
|
1545
|
+
obligation_ids: ambiguities.flatMap((ambiguity) => ambiguity.obligationIds),
|
|
1546
|
+
recovery_reason: recoveryReason,
|
|
1547
|
+
recovery_source: 'worker_decision_loop',
|
|
1548
|
+
},
|
|
1549
|
+
expected_answer: {
|
|
1550
|
+
kind: 'free_text',
|
|
1551
|
+
},
|
|
1552
|
+
blocking: true,
|
|
1553
|
+
phase: STATUS.INTAKE,
|
|
1554
|
+
request_action: 'ask_user_input',
|
|
1555
|
+
resume_status: STATUS.INTAKE,
|
|
1556
|
+
resume_phase: STATUS.INTAKE,
|
|
1557
|
+
});
|
|
1558
|
+
result.toolResults.push(asRecord(response.data));
|
|
1559
|
+
result.requestHandled = true;
|
|
1560
|
+
result.questionRequested = true;
|
|
1561
|
+
|
|
1562
|
+
try {
|
|
1563
|
+
await this.toolCaller.callTool('orchestrator', TOOLS.FEATURE_LOG_APPEND, {
|
|
1564
|
+
feature_id: input.featureId,
|
|
1565
|
+
note: JSON.stringify({
|
|
1566
|
+
action: 'ask_user_input',
|
|
1567
|
+
question_id: asRecord(response.data)?.question_id ?? null,
|
|
1568
|
+
role: input.role,
|
|
1569
|
+
recovery_reason: recoveryReason,
|
|
1570
|
+
recovery_source: 'worker_decision_loop',
|
|
1571
|
+
ambiguity_ids: ambiguities.map((ambiguity) => ambiguity.id),
|
|
1572
|
+
}),
|
|
1573
|
+
});
|
|
1574
|
+
} catch (_error) {
|
|
1575
|
+
// Best effort observability for intake rerouting.
|
|
1576
|
+
}
|
|
1577
|
+
return true;
|
|
1578
|
+
}
|
|
1579
|
+
|
|
1580
|
+
private refreshPlannerStateFromContext(
|
|
1581
|
+
plannerState: PlannerExecutionState,
|
|
1582
|
+
context: unknown,
|
|
1583
|
+
): void {
|
|
1584
|
+
const refreshedPlanVersion = readPlanVersion(asRecord(asRecord(context).plan).plan_version);
|
|
1585
|
+
if (refreshedPlanVersion != null) {
|
|
1586
|
+
plannerState.currentPlanVersion = refreshedPlanVersion;
|
|
1587
|
+
}
|
|
1588
|
+
}
|
|
1589
|
+
|
|
1590
|
+
private recordPlannerMutation(
|
|
1591
|
+
plannerState: PlannerExecutionState,
|
|
1592
|
+
responseData: unknown,
|
|
1593
|
+
planJson: AnyRecord,
|
|
1594
|
+
): void {
|
|
1595
|
+
plannerState.planMutationApplied = true;
|
|
1596
|
+
const acceptedPlanVersion =
|
|
1597
|
+
readPlanVersion(asRecord(responseData).plan_version) ??
|
|
1598
|
+
readPlanVersion(planJson.plan_version);
|
|
1599
|
+
if (acceptedPlanVersion != null) {
|
|
1600
|
+
plannerState.currentPlanVersion = acceptedPlanVersion;
|
|
686
1601
|
}
|
|
687
1602
|
}
|
|
688
1603
|
|
|
@@ -709,6 +1624,11 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
|
|
|
709
1624
|
noteCount: number;
|
|
710
1625
|
valid: boolean;
|
|
711
1626
|
errorCode: string | null;
|
|
1627
|
+
interactiveOutcome?: WorkerDecisionResult['interactiveOutcome'];
|
|
1628
|
+
checkpointId?: string | null;
|
|
1629
|
+
checkpointDiffHash?: string | null;
|
|
1630
|
+
checkpointNetNewWorktreeChange?: boolean | null;
|
|
1631
|
+
checkpointValidationStatus?: string | null;
|
|
712
1632
|
watchdogReason?: string | null;
|
|
713
1633
|
timeoutMs?: number;
|
|
714
1634
|
idleTimeoutMs?: number;
|
|
@@ -717,6 +1637,9 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
|
|
|
717
1637
|
elapsedMs?: number;
|
|
718
1638
|
signal?: string | null;
|
|
719
1639
|
exitCode?: number;
|
|
1640
|
+
stderr?: string;
|
|
1641
|
+
runtimeSelection: ProviderSelection;
|
|
1642
|
+
usage?: NormalizedUsageRecord | null;
|
|
720
1643
|
}): Promise<void> {
|
|
721
1644
|
if (!this.repoRoot) {
|
|
722
1645
|
return;
|
|
@@ -738,8 +1661,22 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
|
|
|
738
1661
|
note_count: event.noteCount,
|
|
739
1662
|
valid: event.valid,
|
|
740
1663
|
error_code: event.errorCode,
|
|
741
|
-
|
|
742
|
-
|
|
1664
|
+
interactive_outcome: event.interactiveOutcome ?? null,
|
|
1665
|
+
checkpoint_id: event.checkpointId ?? null,
|
|
1666
|
+
checkpoint_diff_hash: event.checkpointDiffHash ?? null,
|
|
1667
|
+
checkpoint_net_new_worktree_change: event.checkpointNetNewWorktreeChange ?? null,
|
|
1668
|
+
checkpoint_validation_status: event.checkpointValidationStatus ?? null,
|
|
1669
|
+
provider: event.runtimeSelection.provider,
|
|
1670
|
+
model: event.runtimeSelection.model,
|
|
1671
|
+
usage: event.usage
|
|
1672
|
+
? {
|
|
1673
|
+
status: event.usage.status,
|
|
1674
|
+
input_tokens: event.usage.input_tokens,
|
|
1675
|
+
output_tokens: event.usage.output_tokens,
|
|
1676
|
+
total_tokens: event.usage.total_tokens,
|
|
1677
|
+
estimated_cost_usd: event.usage.estimated_cost_usd,
|
|
1678
|
+
}
|
|
1679
|
+
: null,
|
|
743
1680
|
watchdog_reason: event.watchdogReason ?? null,
|
|
744
1681
|
timeout_ms: event.timeoutMs,
|
|
745
1682
|
idle_timeout_ms: event.idleTimeoutMs,
|
|
@@ -748,6 +1685,7 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
|
|
|
748
1685
|
elapsed_ms: event.elapsedMs,
|
|
749
1686
|
signal: event.signal ?? null,
|
|
750
1687
|
exit_code: event.exitCode,
|
|
1688
|
+
stderr: event.stderr,
|
|
751
1689
|
};
|
|
752
1690
|
|
|
753
1691
|
await appendWorkerRuntimeEvent({
|