muonroi-cli 1.8.4 → 1.9.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/LICENSE +17 -5
- package/dist/packages/agent-harness-core/src/driver.d.ts +27 -1
- package/dist/packages/agent-harness-core/src/driver.js +46 -0
- package/dist/packages/agent-harness-core/src/event-filter.js +11 -0
- package/dist/packages/agent-harness-core/src/event-redact.js +7 -0
- package/dist/packages/agent-harness-core/src/event-tee.d.ts +64 -0
- package/dist/packages/agent-harness-core/src/event-tee.js +104 -0
- package/dist/packages/agent-harness-core/src/mcp-server.d.ts +25 -0
- package/dist/packages/agent-harness-core/src/mcp-server.js +169 -21
- package/dist/packages/agent-harness-core/src/predicate.d.ts +1 -1
- package/dist/packages/agent-harness-core/src/protocol.d.ts +90 -4
- package/dist/packages/agent-harness-core/src/protocol.js +15 -0
- package/dist/packages/agent-harness-core/src/visual-quality.d.ts +58 -0
- package/dist/packages/agent-harness-core/src/visual-quality.js +141 -0
- package/dist/packages/agent-harness-opentui/src/agent-mode.d.ts +6 -0
- package/dist/packages/agent-harness-opentui/src/agent-mode.js +14 -1
- package/dist/packages/agent-harness-opentui/src/input-bridge.d.ts +2 -10
- package/dist/packages/agent-harness-opentui/src/input-bridge.js +103 -16
- package/dist/packages/agent-harness-opentui/src/install.d.ts +8 -0
- package/dist/packages/agent-harness-opentui/src/install.js +10 -0
- package/dist/packages/agent-harness-opentui/src/semantic.js +12 -10
- package/dist/packages/agent-harness-opentui/src/visual-capture.d.ts +56 -0
- package/dist/packages/agent-harness-opentui/src/visual-capture.js +103 -0
- package/dist/src/agent-harness/mock-model.d.ts +38 -0
- package/dist/src/agent-harness/mock-model.js +69 -3
- package/dist/src/agent-harness/test-spawn.js +31 -0
- package/dist/src/chat/chat-keychain.d.ts +7 -12
- package/dist/src/chat/chat-keychain.js +19 -86
- package/dist/src/cli/config/screen-providers.js +1 -1
- package/dist/src/cli/cost-forensics.d.ts +10 -0
- package/dist/src/cli/cost-forensics.js +18 -3
- package/dist/src/cli/keys-bundle.d.ts +1 -1
- package/dist/src/cli/keys-bundle.js +1 -1
- package/dist/src/cli/keys.d.ts +10 -47
- package/dist/src/cli/keys.js +31 -399
- package/dist/src/council/clarifier.d.ts +31 -3
- package/dist/src/council/clarifier.js +220 -32
- package/dist/src/council/context.js +49 -15
- package/dist/src/council/debate-checkpoint.d.ts +129 -0
- package/dist/src/council/debate-checkpoint.js +176 -0
- package/dist/src/council/debate-planner.js +54 -5
- package/dist/src/council/debate-summary.d.ts +25 -0
- package/dist/src/council/debate-summary.js +85 -0
- package/dist/src/council/debate.d.ts +169 -2
- package/dist/src/council/debate.js +1265 -135
- package/dist/src/council/index.d.ts +108 -1
- package/dist/src/council/index.js +670 -197
- package/dist/src/council/leader.d.ts +26 -0
- package/dist/src/council/leader.js +150 -9
- package/dist/src/council/llm.d.ts +94 -0
- package/dist/src/council/llm.js +348 -55
- package/dist/src/council/panel-select.d.ts +30 -0
- package/dist/src/council/panel-select.js +82 -0
- package/dist/src/council/planner.js +40 -0
- package/dist/src/council/preflight.d.ts +17 -0
- package/dist/src/council/preflight.js +50 -2
- package/dist/src/council/prompts.d.ts +39 -4
- package/dist/src/council/prompts.js +256 -69
- package/dist/src/council/stance-recall.d.ts +42 -0
- package/dist/src/council/stance-recall.js +57 -0
- package/dist/src/council/strip-think.d.ts +17 -0
- package/dist/src/council/strip-think.js +33 -0
- package/dist/src/council/types.d.ts +138 -0
- package/dist/src/ee/artifact-cache.d.ts +16 -0
- package/dist/src/ee/artifact-cache.js +32 -0
- package/dist/src/ee/auth.d.ts +20 -0
- package/dist/src/ee/auth.js +54 -2
- package/dist/src/ee/bridge.d.ts +10 -0
- package/dist/src/ee/bridge.js +58 -0
- package/dist/src/ee/client.js +109 -21
- package/dist/src/ee/ee-onboarding.js +6 -26
- package/dist/src/ee/export-transcripts.d.ts +1 -0
- package/dist/src/ee/export-transcripts.js +8 -10
- package/dist/src/ee/extract-session.js +29 -0
- package/dist/src/ee/extract-style.d.ts +58 -0
- package/dist/src/ee/extract-style.js +270 -0
- package/dist/src/ee/recall-ledger.d.ts +9 -0
- package/dist/src/ee/recall-ledger.js +3 -0
- package/dist/src/ee/scope.d.ts +1 -0
- package/dist/src/ee/scope.js +26 -1
- package/dist/src/ee/search.d.ts +7 -0
- package/dist/src/ee/search.js +24 -0
- package/dist/src/ee/transcript-emit.js +2 -0
- package/dist/src/ee/types.d.ts +22 -0
- package/dist/src/ee/who-am-i-brain.d.ts +35 -0
- package/dist/src/ee/who-am-i-brain.js +220 -0
- package/dist/src/ee/who-am-i.d.ts +10 -3
- package/dist/src/ee/who-am-i.js +12 -0
- package/dist/src/ee/workflow-event.d.ts +48 -0
- package/dist/src/ee/workflow-event.js +81 -0
- package/dist/src/flow/compaction/compress.d.ts +3 -3
- package/dist/src/flow/compaction/compress.js +58 -8
- package/dist/src/flow/compaction/extract.d.ts +4 -7
- package/dist/src/flow/compaction/extract.js +50 -10
- package/dist/src/flow/compaction/index.d.ts +14 -1
- package/dist/src/flow/compaction/index.js +96 -3
- package/dist/src/flow/compaction/input-guard.d.ts +24 -0
- package/dist/src/flow/compaction/input-guard.js +43 -0
- package/dist/src/flow/compaction/progress.d.ts +35 -0
- package/dist/src/flow/compaction/progress.js +35 -0
- package/dist/src/flow/fold-planning.d.ts +36 -0
- package/dist/src/flow/fold-planning.js +83 -0
- package/dist/src/flow/hierarchy.d.ts +146 -0
- package/dist/src/flow/hierarchy.js +427 -0
- package/dist/src/flow/index.d.ts +1 -0
- package/dist/src/flow/index.js +2 -0
- package/dist/src/flow/run-artifacts.d.ts +102 -0
- package/dist/src/flow/run-artifacts.js +208 -0
- package/dist/src/generated/version.d.ts +1 -1
- package/dist/src/generated/version.js +1 -1
- package/dist/src/gsd/assessment-schema.d.ts +44 -0
- package/dist/src/gsd/assessment-schema.js +134 -0
- package/dist/src/gsd/capability-registry.d.ts +45 -0
- package/dist/src/gsd/capability-registry.js +337 -0
- package/dist/src/gsd/complexity-assessor.d.ts +39 -0
- package/dist/src/gsd/complexity-assessor.js +152 -0
- package/dist/src/gsd/config-bridge.d.ts +7 -0
- package/dist/src/gsd/config-bridge.js +114 -0
- package/dist/src/gsd/config-loader.d.ts +27 -0
- package/dist/src/gsd/config-loader.js +50 -0
- package/dist/src/gsd/council-context.d.ts +44 -0
- package/dist/src/gsd/council-context.js +114 -0
- package/dist/src/gsd/ee-closure.d.ts +28 -0
- package/dist/src/gsd/ee-closure.js +49 -0
- package/dist/src/gsd/flags.d.ts +66 -0
- package/dist/src/gsd/flags.js +102 -0
- package/dist/src/gsd/gsd-dispatch.d.ts +58 -0
- package/dist/src/gsd/gsd-dispatch.js +131 -0
- package/dist/src/gsd/gsd-runtime.d.ts +22 -0
- package/dist/src/gsd/gsd-runtime.js +37 -0
- package/dist/src/gsd/host-adapter.d.ts +11 -0
- package/dist/src/gsd/host-adapter.js +29 -0
- package/dist/src/gsd/index.d.ts +24 -1
- package/dist/src/gsd/index.js +27 -0
- package/dist/src/gsd/loop-host-contract.d.ts +21 -0
- package/dist/src/gsd/loop-host-contract.js +39 -0
- package/dist/src/gsd/loop-host.d.ts +69 -0
- package/dist/src/gsd/loop-host.js +245 -0
- package/dist/src/gsd/loop-resolver.d.ts +36 -0
- package/dist/src/gsd/loop-resolver.js +79 -0
- package/dist/src/gsd/model-tier.d.ts +13 -0
- package/dist/src/gsd/model-tier.js +45 -0
- package/dist/src/gsd/mutation-gate.d.ts +16 -0
- package/dist/src/gsd/mutation-gate.js +41 -0
- package/dist/src/gsd/native-roadmap.d.ts +89 -0
- package/dist/src/gsd/native-roadmap.js +343 -0
- package/dist/src/gsd/native-state.d.ts +47 -0
- package/dist/src/gsd/native-state.js +220 -0
- package/dist/src/gsd/paths.d.ts +23 -0
- package/dist/src/gsd/paths.js +66 -0
- package/dist/src/gsd/phase-dag.d.ts +12 -0
- package/dist/src/gsd/phase-dag.js +94 -0
- package/dist/src/gsd/phase-sync.d.ts +42 -0
- package/dist/src/gsd/phase-sync.js +321 -0
- package/dist/src/gsd/pil-gate-context.d.ts +13 -0
- package/dist/src/gsd/pil-gate-context.js +64 -0
- package/dist/src/gsd/pil-gate-critic.d.ts +19 -0
- package/dist/src/gsd/pil-gate-critic.js +74 -0
- package/dist/src/gsd/plan-council-prompts.d.ts +25 -0
- package/dist/src/gsd/plan-council-prompts.js +79 -0
- package/dist/src/gsd/plan-council.d.ts +44 -0
- package/dist/src/gsd/plan-council.js +283 -0
- package/dist/src/gsd/plan-gate-vocabulary.d.ts +40 -0
- package/dist/src/gsd/plan-gate-vocabulary.js +64 -0
- package/dist/src/gsd/product-workspace.d.ts +13 -0
- package/dist/src/gsd/product-workspace.js +124 -0
- package/dist/src/gsd/ship-bridge.d.ts +25 -0
- package/dist/src/gsd/ship-bridge.js +65 -0
- package/dist/src/gsd/state-document.d.ts +40 -0
- package/dist/src/gsd/state-document.js +163 -0
- package/dist/src/gsd/verdict-schema.d.ts +39 -0
- package/dist/src/gsd/verdict-schema.js +144 -0
- package/dist/src/gsd/verify-context.d.ts +22 -0
- package/dist/src/gsd/verify-context.js +27 -0
- package/dist/src/gsd/verify-council-prompts.d.ts +19 -0
- package/dist/src/gsd/verify-council-prompts.js +85 -0
- package/dist/src/gsd/verify-council.d.ts +25 -0
- package/dist/src/gsd/verify-council.js +119 -0
- package/dist/src/gsd/verify-gate-vocabulary.d.ts +25 -0
- package/dist/src/gsd/verify-gate-vocabulary.js +46 -0
- package/dist/src/gsd/workflow-engine.d.ts +60 -0
- package/dist/src/gsd/workflow-engine.js +207 -0
- package/dist/src/gsd/workflow-tools.d.ts +13 -0
- package/dist/src/gsd/workflow-tools.js +277 -0
- package/dist/src/headless/council-answers.js +4 -0
- package/dist/src/hooks/index.js +1 -1
- package/dist/src/index.js +172 -270
- package/dist/src/lsp/builtins.js +3 -1
- package/dist/src/lsp/manager.d.ts +5 -1
- package/dist/src/lsp/manager.js +249 -3
- package/dist/src/lsp/npm-cache.d.ts +11 -1
- package/dist/src/lsp/npm-cache.js +17 -1
- package/dist/src/lsp/runtime.d.ts +6 -1
- package/dist/src/lsp/runtime.js +17 -1
- package/dist/src/lsp/types.d.ts +83 -1
- package/dist/src/lsp/types.js +10 -0
- package/dist/src/maintain/pr-builder.js +23 -13
- package/dist/src/mcp/auto-setup.js +57 -32
- package/dist/src/mcp/client-pool.js +44 -16
- package/dist/src/mcp/lsp-tools.d.ts +5 -1
- package/dist/src/mcp/lsp-tools.js +93 -2
- package/dist/src/mcp/mcp-keychain.d.ts +3 -5
- package/dist/src/mcp/mcp-keychain.js +9 -49
- package/dist/src/mcp/research-onboarding.js +8 -7
- package/dist/src/mcp/runtime.js +34 -2
- package/dist/src/mcp/setup-guide-text.d.ts +1 -1
- package/dist/src/mcp/setup-guide-text.js +22 -2
- package/dist/src/mcp/tools-server.d.ts +10 -0
- package/dist/src/mcp/tools-server.js +10 -2
- package/dist/src/models/catalog-client.d.ts +87 -0
- package/dist/src/models/catalog-client.js +105 -38
- package/dist/src/models/catalog.json +528 -265
- package/dist/src/models/registry.d.ts +22 -7
- package/dist/src/models/registry.js +73 -10
- package/dist/src/ops/doctor.js +1 -1
- package/dist/src/orchestrator/ask-user.d.ts +61 -0
- package/dist/src/orchestrator/ask-user.js +65 -0
- package/dist/src/orchestrator/auto-commit.js +1 -1
- package/dist/src/orchestrator/batch-turn-runner.js +2 -2
- package/dist/src/orchestrator/cache-prefix.d.ts +67 -0
- package/dist/src/orchestrator/cache-prefix.js +83 -0
- package/dist/src/orchestrator/compact-request.d.ts +32 -0
- package/dist/src/orchestrator/compact-request.js +41 -0
- package/dist/src/orchestrator/compaction.d.ts +12 -3
- package/dist/src/orchestrator/compaction.js +35 -15
- package/dist/src/orchestrator/council-manager.d.ts +12 -3
- package/dist/src/orchestrator/council-manager.js +74 -32
- package/dist/src/orchestrator/council-request.d.ts +49 -0
- package/dist/src/orchestrator/council-request.js +62 -0
- package/dist/src/orchestrator/cross-turn-dedup.d.ts +6 -0
- package/dist/src/orchestrator/cross-turn-dedup.js +22 -1
- package/dist/src/orchestrator/error-utils.d.ts +29 -0
- package/dist/src/orchestrator/error-utils.js +132 -24
- package/dist/src/orchestrator/grounding-check.js +39 -1
- package/dist/src/orchestrator/interactive-pause.d.ts +26 -0
- package/dist/src/orchestrator/interactive-pause.js +36 -0
- package/dist/src/orchestrator/message-processor.d.ts +4 -0
- package/dist/src/orchestrator/message-processor.js +268 -41
- package/dist/src/orchestrator/orchestrator.d.ts +64 -3
- package/dist/src/orchestrator/orchestrator.js +823 -120
- package/dist/src/orchestrator/preprocessor.js +3 -3
- package/dist/src/orchestrator/proactive-compact-detector.d.ts +26 -0
- package/dist/src/orchestrator/proactive-compact-detector.js +36 -0
- package/dist/src/orchestrator/prompts.js +17 -17
- package/dist/src/orchestrator/reactive-delegation.d.ts +39 -0
- package/dist/src/orchestrator/reactive-delegation.js +59 -0
- package/dist/src/orchestrator/retry-classifier.d.ts +2 -1
- package/dist/src/orchestrator/retry-classifier.js +46 -2
- package/dist/src/orchestrator/safety-askcard.d.ts +1 -1
- package/dist/src/orchestrator/safety-askcard.js +5 -2
- package/dist/src/orchestrator/safety-intercept.d.ts +50 -0
- package/dist/src/orchestrator/safety-intercept.js +62 -0
- package/dist/src/orchestrator/scope-reminder.js +1 -1
- package/dist/src/orchestrator/session-experience.d.ts +2 -1
- package/dist/src/orchestrator/session-experience.js +2 -1
- package/dist/src/orchestrator/should-run-gate.d.ts +5 -0
- package/dist/src/orchestrator/should-run-gate.js +18 -0
- package/dist/src/orchestrator/stall-watchdog.d.ts +31 -3
- package/dist/src/orchestrator/stall-watchdog.js +65 -10
- package/dist/src/orchestrator/stream-runner.d.ts +13 -3
- package/dist/src/orchestrator/stream-runner.js +115 -49
- package/dist/src/orchestrator/sub-agent-cap.d.ts +13 -1
- package/dist/src/orchestrator/sub-agent-cap.js +16 -1
- package/dist/src/orchestrator/sub-agent-model-tier.d.ts +13 -1
- package/dist/src/orchestrator/sub-agent-model-tier.js +16 -2
- package/dist/src/orchestrator/subagent-compactor.d.ts +53 -1
- package/dist/src/orchestrator/subagent-compactor.js +126 -15
- package/dist/src/orchestrator/tool-engine.d.ts +41 -0
- package/dist/src/orchestrator/tool-engine.js +846 -66
- package/dist/src/orchestrator/tool-limit-auto-recover.d.ts +22 -0
- package/dist/src/orchestrator/tool-limit-auto-recover.js +30 -0
- package/dist/src/orchestrator/turn-runner-deps.d.ts +19 -0
- package/dist/src/orchestrator/turn-watchdog.d.ts +44 -0
- package/dist/src/orchestrator/turn-watchdog.js +84 -0
- package/dist/src/pil/agent-operating-contract.d.ts +1 -1
- package/dist/src/pil/agent-operating-contract.js +6 -4
- package/dist/src/pil/cheap-model-playbook.d.ts +1 -1
- package/dist/src/pil/cheap-model-playbook.js +5 -1
- package/dist/src/pil/cheap-model-workbooks.d.ts +1 -1
- package/dist/src/pil/cheap-model-workbooks.js +1 -1
- package/dist/src/pil/discovery-types.d.ts +1 -0
- package/dist/src/pil/discovery.d.ts +1 -1
- package/dist/src/pil/discovery.js +18 -13
- package/dist/src/pil/layer1-intent.d.ts +18 -6
- package/dist/src/pil/layer1-intent.js +66 -757
- package/dist/src/pil/layer15-context-scan.js +15 -1
- package/dist/src/pil/layer1_5-complexity-size.d.ts +7 -0
- package/dist/src/pil/layer1_5-complexity-size.js +31 -5
- package/dist/src/pil/layer3-ee-injection.js +23 -8
- package/dist/src/pil/layer4-gsd.js +69 -16
- package/dist/src/pil/layer5-context.js +7 -3
- package/dist/src/pil/layer6-output.d.ts +23 -0
- package/dist/src/pil/layer6-output.js +5 -1
- package/dist/src/pil/llm-classify.d.ts +111 -5
- package/dist/src/pil/llm-classify.js +421 -189
- package/dist/src/pil/native-capabilities-workbook.d.ts +1 -1
- package/dist/src/pil/native-capabilities-workbook.js +8 -0
- package/dist/src/pil/pipeline.js +36 -2
- package/dist/src/pil/repo-grounding-probe.d.ts +15 -0
- package/dist/src/pil/repo-grounding-probe.js +136 -0
- package/dist/src/pil/repo-structure-hints.d.ts +7 -0
- package/dist/src/pil/repo-structure-hints.js +45 -0
- package/dist/src/pil/response-tools.js +5 -3
- package/dist/src/pil/schema.d.ts +1 -0
- package/dist/src/pil/schema.js +2 -0
- package/dist/src/pil/types.d.ts +18 -0
- package/dist/src/playbook/directives.d.ts +4 -0
- package/dist/src/playbook/directives.js +17 -5
- package/dist/src/product-loop/artifact-io.js +4 -0
- package/dist/src/product-loop/backlog-builder.d.ts +14 -1
- package/dist/src/product-loop/backlog-builder.js +30 -6
- package/dist/src/product-loop/criteria-seed.d.ts +51 -0
- package/dist/src/product-loop/criteria-seed.js +200 -0
- package/dist/src/product-loop/discovery-context-format.js +3 -1
- package/dist/src/product-loop/discovery-ecosystem.js +4 -1
- package/dist/src/product-loop/discovery-interview.d.ts +9 -0
- package/dist/src/product-loop/discovery-interview.js +60 -12
- package/dist/src/product-loop/discovery-recommender.js +2 -1
- package/dist/src/product-loop/discovery-schema.js +19 -2
- package/dist/src/product-loop/discovery-triage.d.ts +23 -0
- package/dist/src/product-loop/discovery-triage.js +109 -0
- package/dist/src/product-loop/gather.js +150 -2
- package/dist/src/product-loop/ideal-trace.d.ts +7 -0
- package/dist/src/product-loop/ideal-trace.js +64 -0
- package/dist/src/product-loop/index.d.ts +13 -1
- package/dist/src/product-loop/index.js +340 -52
- package/dist/src/product-loop/loop-driver.d.ts +7 -0
- package/dist/src/product-loop/loop-driver.js +330 -106
- package/dist/src/product-loop/phase-plan.d.ts +21 -0
- package/dist/src/product-loop/phase-plan.js +81 -6
- package/dist/src/product-loop/phase-rituals.d.ts +3 -0
- package/dist/src/product-loop/phase-rituals.js +8 -3
- package/dist/src/product-loop/phase-runner.js +39 -12
- package/dist/src/product-loop/plan-adherence-review.d.ts +26 -0
- package/dist/src/product-loop/plan-adherence-review.js +144 -0
- package/dist/src/product-loop/sprint-runner.d.ts +173 -0
- package/dist/src/product-loop/sprint-runner.js +863 -19
- package/dist/src/product-loop/types.d.ts +61 -5
- package/dist/src/providers/adapter.d.ts +1 -1
- package/dist/src/providers/adapter.js +3 -4
- package/dist/src/providers/anthropic.d.ts +9 -8
- package/dist/src/providers/anthropic.js +13 -47
- package/dist/src/providers/auth/browser-flow.d.ts +1 -1
- package/dist/src/providers/auth/browser-flow.js +1 -1
- package/dist/src/providers/auth/grok-oauth.d.ts +1 -0
- package/dist/src/providers/auth/grok-oauth.js +30 -5
- package/dist/src/providers/auth/openai-oauth.d.ts +1 -0
- package/dist/src/providers/auth/openai-oauth.js +15 -1
- package/dist/src/providers/auth/registry.js +0 -34
- package/dist/src/providers/auth/token-store.d.ts +9 -9
- package/dist/src/providers/auth/token-store.js +8 -67
- package/dist/src/providers/auth/types.d.ts +9 -1
- package/dist/src/providers/auth/types.js +1 -1
- package/dist/src/providers/capabilities.d.ts +24 -5
- package/dist/src/providers/capabilities.js +42 -24
- package/dist/src/providers/endpoints.d.ts +2 -2
- package/dist/src/providers/endpoints.js +11 -10
- package/dist/src/providers/env-store.d.ts +17 -0
- package/dist/src/providers/env-store.js +228 -0
- package/dist/src/providers/keychain.d.ts +22 -18
- package/dist/src/providers/keychain.js +127 -140
- package/dist/src/providers/mcp-vision-bridge.js +56 -146
- package/dist/src/providers/openai-compatible.js +8 -1
- package/dist/src/providers/pricing.d.ts +2 -2
- package/dist/src/providers/pricing.js +3 -13
- package/dist/src/providers/runtime.d.ts +43 -3
- package/dist/src/providers/runtime.js +88 -14
- package/dist/src/providers/strategies/base.strategy.d.ts +16 -0
- package/dist/src/providers/strategies/base.strategy.js +24 -1
- package/dist/src/providers/strategies/{siliconflow.strategy.d.ts → opencode-go.strategy.d.ts} +3 -3
- package/dist/src/providers/strategies/opencode-go.strategy.js +83 -0
- package/dist/src/providers/strategies/registry.js +4 -4
- package/dist/src/providers/strategies/thinking-mode.d.ts +109 -0
- package/dist/src/providers/strategies/thinking-mode.js +288 -1
- package/dist/src/providers/strategies/xai.strategy.js +27 -0
- package/dist/src/providers/strategies/zai.strategy.d.ts +14 -0
- package/dist/src/providers/strategies/zai.strategy.js +44 -0
- package/dist/src/providers/types.d.ts +5 -6
- package/dist/src/providers/types.js +2 -2
- package/dist/src/providers/vision-backend.d.ts +47 -0
- package/dist/src/providers/vision-backend.js +258 -0
- package/dist/src/providers/vision-proxy.d.ts +22 -9
- package/dist/src/providers/vision-proxy.js +63 -132
- package/dist/src/providers/warm.d.ts +65 -0
- package/dist/src/providers/warm.js +145 -0
- package/dist/src/providers/wire-debug.js +95 -0
- package/dist/src/router/decide.d.ts +13 -0
- package/dist/src/router/decide.js +138 -36
- package/dist/src/router/peak-hour.d.ts +38 -0
- package/dist/src/router/peak-hour.js +107 -0
- package/dist/src/router/step-router.js +3 -2
- package/dist/src/router/warm.js +4 -5
- package/dist/src/scaffold/continuation-prompt.d.ts +11 -0
- package/dist/src/scaffold/continuation-prompt.js +26 -0
- package/dist/src/scaffold/point-to-existing.d.ts +21 -0
- package/dist/src/scaffold/point-to-existing.js +25 -0
- package/dist/src/self-qa/agentic-loop.js +6 -5
- package/dist/src/{ui/state → state}/active-run.d.ts +19 -0
- package/dist/src/{ui/state → state}/active-run.js +21 -0
- package/dist/src/{ui/status-bar/store.d.ts → state/status-bar-store.d.ts} +4 -1
- package/dist/src/{ui/status-bar/store.js → state/status-bar-store.js} +12 -9
- package/dist/src/state/turn-trace.d.ts +43 -0
- package/dist/src/state/turn-trace.js +32 -0
- package/dist/src/storage/db.js +2 -1
- package/dist/src/storage/index.d.ts +1 -1
- package/dist/src/storage/index.js +1 -1
- package/dist/src/storage/interaction-log.d.ts +1 -1
- package/dist/src/storage/migrations.js +71 -1
- package/dist/src/storage/sessions.d.ts +28 -10
- package/dist/src/storage/sessions.js +78 -21
- package/dist/src/storage/transcript-view.js +1 -1
- package/dist/src/storage/transcript.d.ts +51 -0
- package/dist/src/storage/transcript.js +340 -15
- package/dist/src/tools/file.d.ts +15 -0
- package/dist/src/tools/file.js +32 -0
- package/dist/src/tools/git-safety.d.ts +19 -0
- package/dist/src/tools/git-safety.js +168 -0
- package/dist/src/tools/native-tools.d.ts +1 -1
- package/dist/src/tools/native-tools.js +81 -1
- package/dist/src/tools/registry.d.ts +20 -0
- package/dist/src/tools/registry.js +576 -23
- package/dist/src/tools/research.d.ts +29 -0
- package/dist/src/tools/research.js +233 -0
- package/dist/src/types/index.d.ts +147 -4
- package/dist/src/ui/app.js +0 -0
- package/dist/src/ui/cards/product-status-card.js +1 -1
- package/dist/src/ui/components/agent-rail-activities.d.ts +26 -0
- package/dist/src/ui/components/agent-rail-activities.js +47 -0
- package/dist/src/ui/components/bubble-body-guard.d.ts +27 -0
- package/dist/src/ui/components/bubble-body-guard.js +50 -0
- package/dist/src/ui/components/compact-progress-card.d.ts +24 -0
- package/dist/src/ui/components/compact-progress-card.js +42 -0
- package/dist/src/ui/components/context-rail.d.ts +26 -0
- package/dist/src/ui/components/context-rail.js +33 -0
- package/dist/src/ui/components/council-conclusion-card.d.ts +73 -0
- package/dist/src/ui/components/council-conclusion-card.js +420 -0
- package/dist/src/ui/components/council-debate-pill.d.ts +36 -0
- package/dist/src/ui/components/council-debate-pill.js +34 -0
- package/dist/src/ui/components/council-info-card.js +2 -2
- package/dist/src/ui/components/council-leader-bubble.d.ts +10 -3
- package/dist/src/ui/components/council-leader-bubble.js +21 -11
- package/dist/src/ui/components/council-message-bubble.d.ts +15 -2
- package/dist/src/ui/components/council-message-bubble.js +16 -15
- package/dist/src/ui/components/council-phase-timeline.d.ts +9 -1
- package/dist/src/ui/components/council-phase-timeline.js +66 -17
- package/dist/src/ui/components/council-placeholder-bubble.d.ts +16 -9
- package/dist/src/ui/components/council-placeholder-bubble.js +32 -29
- package/dist/src/ui/components/council-question-card.js +13 -12
- package/dist/src/ui/components/council-rail-rounds.d.ts +26 -0
- package/dist/src/ui/components/council-rail-rounds.js +57 -0
- package/dist/src/ui/components/council-round-group.d.ts +38 -0
- package/dist/src/ui/components/council-round-group.js +88 -0
- package/dist/src/ui/components/council-status-list.d.ts +3 -1
- package/dist/src/ui/components/council-status-list.js +36 -24
- package/dist/src/ui/components/council-synthesis-banner.d.ts +7 -2
- package/dist/src/ui/components/council-synthesis-banner.js +20 -5
- package/dist/src/ui/components/halt-recovery-card.js +9 -5
- package/dist/src/ui/components/jump-to-latest-pill.d.ts +11 -0
- package/dist/src/ui/components/jump-to-latest-pill.js +14 -0
- package/dist/src/ui/components/message-view.d.ts +15 -0
- package/dist/src/ui/components/message-view.js +50 -1
- package/dist/src/ui/components/prompt-box.js +18 -16
- package/dist/src/ui/components/session-tree-card.d.ts +14 -0
- package/dist/src/ui/components/session-tree-card.js +46 -0
- package/dist/src/ui/components/slash-inline-menu.d.ts +12 -0
- package/dist/src/ui/components/slash-inline-menu.js +26 -5
- package/dist/src/ui/components/task-list-panel.d.ts +14 -1
- package/dist/src/ui/components/task-list-panel.js +22 -2
- package/dist/src/ui/components/tool-group.d.ts +15 -3
- package/dist/src/ui/components/tool-group.js +69 -11
- package/dist/src/ui/containers/modals-layer.d.ts +4 -2
- package/dist/src/ui/containers/modals-layer.js +2 -2
- package/dist/src/ui/council-harness-event.d.ts +57 -0
- package/dist/src/ui/council-harness-event.js +46 -0
- package/dist/src/ui/heartbeat-debug.d.ts +29 -0
- package/dist/src/ui/heartbeat-debug.js +45 -0
- package/dist/src/ui/hooks/use-session-picker.d.ts +3 -3
- package/dist/src/ui/mcp-modal.js +2 -4
- package/dist/src/ui/modals/api-key-modal.js +1 -1
- package/dist/src/ui/modals/connect-modal.js +4 -3
- package/dist/src/ui/modals/model-picker-modal.d.ts +8 -18
- package/dist/src/ui/modals/model-picker-modal.js +8 -10
- package/dist/src/ui/modals/session-picker-modal.d.ts +2 -2
- package/dist/src/ui/modals/session-picker-modal.js +3 -5
- package/dist/src/ui/picker-providers.d.ts +1 -1
- package/dist/src/ui/picker-providers.js +1 -1
- package/dist/src/ui/primitives/index.d.ts +1 -0
- package/dist/src/ui/primitives/index.js +2 -0
- package/dist/src/ui/primitives/semantic-primitives.d.ts +76 -0
- package/dist/src/ui/primitives/semantic-primitives.js +81 -0
- package/dist/src/ui/slash/compact.js +5 -7
- package/dist/src/ui/slash/cost.js +1 -1
- package/dist/src/ui/slash/council.js +19 -1
- package/dist/src/ui/slash/debug.d.ts +3 -31
- package/dist/src/ui/slash/debug.js +9 -20
- package/dist/src/ui/slash/ee.js +81 -0
- package/dist/src/ui/slash/ideal.d.ts +6 -2
- package/dist/src/ui/slash/ideal.js +97 -7
- package/dist/src/ui/slash/menu-items.d.ts +7 -0
- package/dist/src/ui/slash/menu-items.js +23 -20
- package/dist/src/ui/slash/registry.d.ts +2 -0
- package/dist/src/ui/slash/registry.js +4 -0
- package/dist/src/ui/status-bar/cache-hit.d.ts +6 -0
- package/dist/src/ui/status-bar/cache-hit.js +9 -0
- package/dist/src/ui/status-bar/index.d.ts +1 -1
- package/dist/src/ui/status-bar/index.js +7 -3
- package/dist/src/ui/status-bar/usd-meter.d.ts +5 -4
- package/dist/src/ui/status-bar/usd-meter.js +6 -4
- package/dist/src/ui/theme.d.ts +1 -0
- package/dist/src/ui/theme.js +2 -0
- package/dist/src/ui/types.d.ts +7 -0
- package/dist/src/ui/use-app-logic.js +0 -0
- package/dist/src/ui/utils/agent-activities.d.ts +39 -0
- package/dist/src/ui/utils/agent-activities.js +96 -0
- package/dist/src/ui/utils/format.d.ts +14 -0
- package/dist/src/ui/utils/format.js +23 -3
- package/dist/src/ui/utils/group-tool-entries.d.ts +26 -0
- package/dist/src/ui/utils/group-tool-entries.js +111 -0
- package/dist/src/ui/utils/tool-summary.d.ts +21 -0
- package/dist/src/ui/utils/tool-summary.js +91 -0
- package/dist/src/usage/downgrade.js +2 -2
- package/dist/src/usage/product-ledger.js +2 -2
- package/dist/src/utils/event-loop-monitor.d.ts +85 -0
- package/dist/src/utils/event-loop-monitor.js +107 -0
- package/dist/src/utils/install-manager.js +2 -1
- package/dist/src/utils/llm-deadline.d.ts +14 -0
- package/dist/src/utils/llm-deadline.js +19 -0
- package/dist/src/utils/logger.js +2 -2
- package/dist/src/utils/loop-profiler.d.ts +102 -0
- package/dist/src/utils/loop-profiler.js +202 -0
- package/dist/src/utils/permission-mode.js +5 -3
- package/dist/src/utils/redactor.js +1 -1
- package/dist/src/utils/settings.d.ts +180 -5
- package/dist/src/utils/settings.js +271 -31
- package/dist/src/utils/side-question.d.ts +1 -2
- package/dist/src/utils/side-question.js +2 -2
- package/dist/src/utils/visible-retry.d.ts +11 -0
- package/dist/src/utils/visible-retry.js +10 -1
- package/dist/src/verify/entrypoint.d.ts +1 -1
- package/dist/src/verify/entrypoint.js +52 -17
- package/dist/src/verify/orchestrator.d.ts +1 -1
- package/dist/src/verify/orchestrator.js +20 -3
- package/dist/src/verify/recipes.d.ts +13 -0
- package/dist/src/verify/recipes.js +15 -0
- package/package.json +134 -132
- package/dist/src/cli/bw-vault.d.ts +0 -55
- package/dist/src/cli/bw-vault.js +0 -133
- package/dist/src/mcp/ee-tools.d.ts +0 -46
- package/dist/src/mcp/ee-tools.js +0 -193
- package/dist/src/providers/auth/gcloud.d.ts +0 -28
- package/dist/src/providers/auth/gcloud.js +0 -102
- package/dist/src/providers/auth/gemini-oauth.d.ts +0 -82
- package/dist/src/providers/auth/gemini-oauth.js +0 -472
- package/dist/src/providers/gemini.d.ts +0 -11
- package/dist/src/providers/gemini.js +0 -45
- package/dist/src/providers/siliconflow-sse-repair.d.ts +0 -58
- package/dist/src/providers/siliconflow-sse-repair.js +0 -177
- package/dist/src/providers/strategies/google.strategy.d.ts +0 -22
- package/dist/src/providers/strategies/google.strategy.js +0 -174
- package/dist/src/providers/strategies/siliconflow.strategy.js +0 -29
- package/dist/src/ui/containers/chat-feed.d.ts +0 -40
- package/dist/src/ui/containers/chat-feed.js +0 -66
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import * as path from "node:path";
|
|
2
2
|
import { runDebate } from "../council/debate.js";
|
|
3
|
+
import { deleteDebateInputs, readDebateCheckpoint, readDebateInputs, writeDebateInputs, } from "../council/debate-checkpoint.js";
|
|
4
|
+
import { resolveDebateSummary } from "../council/debate-summary.js";
|
|
3
5
|
import { resolveLeaderModelDetailed, resolveParticipants } from "../council/leader.js";
|
|
4
6
|
import { phaseStart } from "../council/phase-events.js";
|
|
5
7
|
import { runPreflight } from "../council/preflight.js";
|
|
8
|
+
import { makeStanceRecall } from "../council/stance-recall.js";
|
|
6
9
|
import { fetchBBContext, inferBBFromPrompt, renderBBContextBlock } from "../ee/bb-retrieval.js";
|
|
10
|
+
import { getDefaultEEClient } from "../ee/intercept.js";
|
|
11
|
+
import { fireAndForgetWorkflowEvent } from "../ee/workflow-event.js";
|
|
7
12
|
import { readArtifact, writeArtifact } from "../flow/artifact-io.js";
|
|
8
|
-
import {
|
|
13
|
+
import { ensureRunScoped } from "../flow/hierarchy.js";
|
|
14
|
+
import { renderResumeDigest, writeContextDoc, writeResearchDoc } from "../flow/run-artifacts.js";
|
|
15
|
+
import { logInteraction } from "../storage/index.js";
|
|
9
16
|
import { isCouncilMultiProviderPreferred } from "../utils/settings.js";
|
|
10
17
|
import { extractAssumptionsFromDebate, mergeAssumptions, renderLedgerSummary } from "./assumption-ledger.js";
|
|
11
18
|
import { buildPriorContext } from "./cross-run-memory.js";
|
|
@@ -17,60 +24,58 @@ import { recordPhaseEnd, recordPhaseStart } from "./phase-budget.js";
|
|
|
17
24
|
import { additionalPrefills, auditAsContextBlock, auditRepo } from "./repo-audit.js";
|
|
18
25
|
import { SEED_DIMENSIONS } from "./seed-questions.js";
|
|
19
26
|
import { deriveTasksFromSpec, writeTasks } from "./typed-artifacts.js";
|
|
27
|
+
// Council usage_events recording (source="council") now happens at the single
|
|
28
|
+
// source of truth inside createCouncilLLM (src/council/llm.ts → recordCouncilUsage),
|
|
29
|
+
// so it covers EVERY council entry point — the /council slash path, auto-council,
|
|
30
|
+
// and all /ideal phases (clarifier, research, generate, sprint) — not just this
|
|
31
|
+
// driver's runDebate call site. The former loop-driver-local wrapper only wrapped
|
|
32
|
+
// the debate llm and double-counted nothing else; recording at the source removes
|
|
33
|
+
// both the leak and the risk of a double count here.
|
|
20
34
|
/**
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
* The original onUsage (if any) is still called.
|
|
35
|
+
* Best-effort interaction_logs writer for the loop-driver. Logs and continues on
|
|
36
|
+
* failure so a broken DB never blocks the FSM. `ctx.sessionId` falls back to
|
|
37
|
+
* runId for legacy callers that don't pass a chat session id. `cols` carries
|
|
38
|
+
* fields that belong in real columns rather than metadata_json.
|
|
26
39
|
*/
|
|
27
|
-
function
|
|
28
|
-
const sid = ctx.sessionId ?? ctx.runId;
|
|
29
|
-
const recorder = (modelId) => (usage) => {
|
|
30
|
-
try {
|
|
31
|
-
recordUsageEvent(sid, "council", modelId, {
|
|
32
|
-
inputTokens: usage.inputTokens,
|
|
33
|
-
outputTokens: usage.outputTokens,
|
|
34
|
-
cacheReadTokens: usage.cachedInputTokens,
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
catch {
|
|
38
|
-
/* best-effort — never block the debate */
|
|
39
|
-
}
|
|
40
|
-
};
|
|
41
|
-
return {
|
|
42
|
-
generate: (modelId, system, prompt, maxTokens, onUsage, signal) => llm.generate(modelId, system, prompt, maxTokens, (u) => {
|
|
43
|
-
recorder(modelId)(u);
|
|
44
|
-
onUsage?.(u);
|
|
45
|
-
}, signal),
|
|
46
|
-
debate: (modelId, system, prompt, signal, persistTrace, options, onUsage) => llm.debate(modelId, system, prompt, signal, persistTrace, options, (u) => {
|
|
47
|
-
recorder(modelId)(u);
|
|
48
|
-
onUsage?.(u);
|
|
49
|
-
}),
|
|
50
|
-
research: (modelId, topic, conversationContext, signal, persistTrace, options, onUsage) => llm.research(modelId, topic, conversationContext, signal, persistTrace, options, (u) => {
|
|
51
|
-
recorder(modelId)(u);
|
|
52
|
-
onUsage?.(u);
|
|
53
|
-
}),
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Best-effort interaction_logs writer for the loop-driver. Swallows failures
|
|
58
|
-
* so a broken DB never blocks the FSM. `ctx.sessionId` falls back to runId
|
|
59
|
-
* for legacy callers that don't pass a chat session id.
|
|
60
|
-
*/
|
|
61
|
-
function logLoopEvent(ctx, subtype, data) {
|
|
40
|
+
function logLoopEvent(ctx, subtype, data, cols) {
|
|
62
41
|
try {
|
|
63
42
|
const sid = ctx.sessionId ?? ctx.runId;
|
|
64
43
|
// Stamp runId on every row so multi-run sessions can be demuxed during
|
|
65
44
|
// forensics — previously only route_decision carried this field. Caller
|
|
66
45
|
// overrides win if the payload already contained a runId.
|
|
67
46
|
const enriched = "runId" in data ? data : { ...data, runId: ctx.runId };
|
|
68
|
-
|
|
47
|
+
// `cols` promotes fields out of metadata_json into real columns so they are
|
|
48
|
+
// aggregatable in SQL. Without it every council_message row landed with
|
|
49
|
+
// duration_ms NULL, leaving `debate_complete` (the whole debate) as the only
|
|
50
|
+
// timed row — an aggregate that cannot name which speaker was slow.
|
|
51
|
+
logInteraction(sid, "council", {
|
|
52
|
+
eventSubtype: subtype,
|
|
53
|
+
data: enriched,
|
|
54
|
+
...(cols?.model ? { model: cols.model } : {}),
|
|
55
|
+
...(typeof cols?.durationMs === "number" ? { durationMs: cols.durationMs } : {}),
|
|
56
|
+
});
|
|
69
57
|
}
|
|
70
|
-
catch {
|
|
71
|
-
|
|
58
|
+
catch (err) {
|
|
59
|
+
// Audit trail only — never block the FSM. Logged so a broken DB surfaces
|
|
60
|
+
// instead of silently emptying the forensics table. (No-Silent-Catch.)
|
|
61
|
+
console.error(`[loop-driver] logLoopEvent failed for subtype "${subtype}": ${err instanceof Error ? err.message : String(err)}`);
|
|
72
62
|
}
|
|
73
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* Clamp a title for the milestone/phase index (F12): truncate at a word
|
|
66
|
+
* boundary when possible and strip trailing punctuation/whitespace so a raw
|
|
67
|
+
* slice can't leave a dangling "(" or a half word. Falls back to a hard slice
|
|
68
|
+
* for a single long token.
|
|
69
|
+
*/
|
|
70
|
+
export function clampTitle(raw, max) {
|
|
71
|
+
const s = (raw ?? "").trim();
|
|
72
|
+
if (s.length <= max)
|
|
73
|
+
return s.replace(/[\s([{<"'.,;:–—-]+$/u, "").trim() || s;
|
|
74
|
+
const hard = s.slice(0, max);
|
|
75
|
+
const lastSpace = hard.lastIndexOf(" ");
|
|
76
|
+
const base = lastSpace >= Math.floor(max * 0.6) ? hard.slice(0, lastSpace) : hard;
|
|
77
|
+
return base.replace(/[\s([{<"'.,;:–—-]+$/u, "").trim() || hard.trim();
|
|
78
|
+
}
|
|
74
79
|
function buildWorkspaceDiscoveryCard(d, a, priorRunCount) {
|
|
75
80
|
const sections = [];
|
|
76
81
|
if (!d.hasProject) {
|
|
@@ -157,6 +162,12 @@ export async function* runLoopDriver(ctx) {
|
|
|
157
162
|
let state = "idle";
|
|
158
163
|
let clarifiedSpec;
|
|
159
164
|
let debateState;
|
|
165
|
+
// Resolved once the research debate completes (F9): runningSummary, or a
|
|
166
|
+
// faithful fallback synthesized from participant positions when the debate
|
|
167
|
+
// returned after openings without a running summary. Reused across the
|
|
168
|
+
// research artifacts AND the scoping synthesis prompt so neither loses the
|
|
169
|
+
// debate. Empty until the research phase runs.
|
|
170
|
+
let resolvedDebateSummary = "";
|
|
160
171
|
let discovery;
|
|
161
172
|
let audit;
|
|
162
173
|
let productSpec;
|
|
@@ -168,6 +179,28 @@ export async function* runLoopDriver(ctx) {
|
|
|
168
179
|
const leaderResolution = await resolveLeaderModelDetailed(ctx.sessionModelId);
|
|
169
180
|
const leaderModelId = leaderResolution.modelId;
|
|
170
181
|
const councilParticipants = await resolveParticipants(ctx.sessionModelId, isCouncilMultiProviderPreferred());
|
|
182
|
+
// C-v2 cross-session resume — a persisted debate checkpoint means the council
|
|
183
|
+
// debate was interrupted in a PRIOR session (the process died mid-round; the
|
|
184
|
+
// in-process C-v1 retry only covers same-session throws). Skip the already-
|
|
185
|
+
// completed + persisted discovery + interview and jump straight to the
|
|
186
|
+
// research/debate stage with the restored gather outputs; the `research` case
|
|
187
|
+
// reads the checkpoint and resumes the debate from its last completed round.
|
|
188
|
+
const priorCheckpoint = await readDebateCheckpoint(runDir);
|
|
189
|
+
if (priorCheckpoint) {
|
|
190
|
+
const inputs = await readDebateInputs(runDir);
|
|
191
|
+
if (inputs) {
|
|
192
|
+
clarifiedSpec = inputs.clarifiedSpec;
|
|
193
|
+
conversationContext = inputs.conversationContext;
|
|
194
|
+
state = "research";
|
|
195
|
+
yield {
|
|
196
|
+
type: "content",
|
|
197
|
+
content: `\n> Resuming an interrupted council debate (round ${priorCheckpoint.roundCount + 1}) — skipping discovery + interview.\n`,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
console.error(`[loop-driver] debate checkpoint present but debate-inputs.json missing (run ${ctx.runId}); running the council FSM fresh.`);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
171
204
|
while (true) {
|
|
172
205
|
switch (state) {
|
|
173
206
|
case "idle": {
|
|
@@ -218,6 +251,21 @@ export async function* runLoopDriver(ctx) {
|
|
|
218
251
|
if (discoveryCard) {
|
|
219
252
|
yield { type: "council_info_card", councilInfoCard: discoveryCard };
|
|
220
253
|
}
|
|
254
|
+
// Part A — persist prior-run context as a first-class context.md. The
|
|
255
|
+
// digest is intentionally NOT re-injected into the live system prompt
|
|
256
|
+
// (PIL Layer 3 already does semantic injection), but writing it to disk
|
|
257
|
+
// makes it a reviewable, resumable surface — the run's inherited memory.
|
|
258
|
+
try {
|
|
259
|
+
const ctxParts = [`Prior runs on this workspace: ${prior.runs.length}`];
|
|
260
|
+
if (prior.digest?.trim())
|
|
261
|
+
ctxParts.push("", prior.digest.trim());
|
|
262
|
+
if (audit.hasProject)
|
|
263
|
+
ctxParts.push("", "## Repo audit", conversationContext);
|
|
264
|
+
await writeContextDoc(ctx.flowDir, ctx.runId, ctxParts.join("\n"));
|
|
265
|
+
}
|
|
266
|
+
catch {
|
|
267
|
+
/* non-critical — context.md is a review surface, never blocks the FSM */
|
|
268
|
+
}
|
|
221
269
|
// Persist discovery evidence + repo audit so resume can replay.
|
|
222
270
|
const stateMap = (await readArtifact(runDir, "state.md")) ?? { preamble: "", sections: new Map() };
|
|
223
271
|
if (discovery.evidence.length > 0) {
|
|
@@ -266,7 +314,12 @@ export async function* runLoopDriver(ctx) {
|
|
|
266
314
|
});
|
|
267
315
|
// Write Resume Digest to state.md
|
|
268
316
|
const stateMap = (await readArtifact(runDir, "state.md")) ?? { preamble: "", sections: new Map() };
|
|
269
|
-
stateMap.sections.set("Resume Digest",
|
|
317
|
+
stateMap.sections.set("Resume Digest", renderResumeDigest({
|
|
318
|
+
stage: "gather",
|
|
319
|
+
lastCompleted: "discover",
|
|
320
|
+
nextAction: "Answer clarification questions to define product dimensions",
|
|
321
|
+
updatedAt: new Date().toISOString(),
|
|
322
|
+
}));
|
|
270
323
|
await writeArtifact(runDir, "state.md", stateMap);
|
|
271
324
|
// runGatherPhase is async (not a generator), but the discovery
|
|
272
325
|
// interview emits askcard chunks via the io.emit callback. We collect
|
|
@@ -390,6 +443,9 @@ export async function* runLoopDriver(ctx) {
|
|
|
390
443
|
if (!clarifiedSpec) {
|
|
391
444
|
return { runId: ctx.runId, stage: "error", success: false, reason: "missing_spec_for_research" };
|
|
392
445
|
}
|
|
446
|
+
// Part E — web-research confidence for this run, filled when the
|
|
447
|
+
// Researcher stance is (re)assigned to a web-capable model below.
|
|
448
|
+
let researchWebConfidence;
|
|
393
449
|
const researchPhaseStartMs = Date.now();
|
|
394
450
|
yield phaseStart({
|
|
395
451
|
phaseId: "loop:research",
|
|
@@ -402,7 +458,12 @@ export async function* runLoopDriver(ctx) {
|
|
|
402
458
|
phase: "research",
|
|
403
459
|
});
|
|
404
460
|
const stateMap = (await readArtifact(runDir, "state.md")) ?? { preamble: "", sections: new Map() };
|
|
405
|
-
stateMap.sections.set("Resume Digest",
|
|
461
|
+
stateMap.sections.set("Resume Digest", renderResumeDigest({
|
|
462
|
+
stage: "research",
|
|
463
|
+
lastCompleted: "gather",
|
|
464
|
+
nextAction: "Run / resume the multi-expert council debate",
|
|
465
|
+
updatedAt: new Date().toISOString(),
|
|
466
|
+
}));
|
|
406
467
|
await writeArtifact(runDir, "state.md", stateMap);
|
|
407
468
|
// inside research phase, before building councilTopic:
|
|
408
469
|
const projectCtx = await readProjectContext(ctx.flowDir, ctx.runId);
|
|
@@ -456,6 +517,42 @@ export async function* runLoopDriver(ctx) {
|
|
|
456
517
|
stance: s,
|
|
457
518
|
};
|
|
458
519
|
});
|
|
520
|
+
// Part E — the Researcher stance MUST prefer a model with NATIVE online
|
|
521
|
+
// web research (its own web_search/browsing), so the research phase gets
|
|
522
|
+
// real online facts rather than codebase-only reasoning. If a web-capable
|
|
523
|
+
// model is reachable this session, route the Researcher to it; otherwise
|
|
524
|
+
// record degraded confidence into research.md (the fallback add-in path
|
|
525
|
+
// — Tavily/MCP — is untrusted per the owner's Part E principle).
|
|
526
|
+
const { modelHasNativeWebResearch, getWebResearchModel } = await import("../models/registry.js");
|
|
527
|
+
const reachableIds = new Set([...councilParticipants.map((p) => p.model), leaderModelId].filter(Boolean));
|
|
528
|
+
const researcherIdx = participants.findIndex((p) => p.stance?.name === "Researcher");
|
|
529
|
+
if (researcherIdx >= 0) {
|
|
530
|
+
const current = participants[researcherIdx].model;
|
|
531
|
+
if (!modelHasNativeWebResearch(current)) {
|
|
532
|
+
// ONLY reroute to a web-native model that is actually REACHABLE this
|
|
533
|
+
// session. A model whose provider has no factory wired (e.g. grok/xai
|
|
534
|
+
// when only opencode-go is authed) would fail council participant
|
|
535
|
+
// creation ("no factory for model's provider") and wedge the debate —
|
|
536
|
+
// so if no reachable web-native model exists, degrade gracefully and
|
|
537
|
+
// KEEP the current reachable model rather than swap in a dead id.
|
|
538
|
+
const webModel = getWebResearchModel(reachableIds);
|
|
539
|
+
if (webModel) {
|
|
540
|
+
participants[researcherIdx].model = webModel.id;
|
|
541
|
+
researchWebConfidence = { confidence: "native", model: webModel.id };
|
|
542
|
+
}
|
|
543
|
+
else {
|
|
544
|
+
researchWebConfidence = { confidence: "degraded" };
|
|
545
|
+
logLoopEvent(ctx, "research_web_degraded", {
|
|
546
|
+
phase: "research",
|
|
547
|
+
reason: "no reachable native_web_research model",
|
|
548
|
+
researcherModel: current,
|
|
549
|
+
});
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
else {
|
|
553
|
+
researchWebConfidence = { confidence: "native", model: current };
|
|
554
|
+
}
|
|
555
|
+
}
|
|
459
556
|
// CB-1 — BB-aware context injection. Runs before council debate fires so
|
|
460
557
|
// the research stances have access to relevant BB recipes and rules.
|
|
461
558
|
//
|
|
@@ -503,67 +600,125 @@ export async function* runLoopDriver(ctx) {
|
|
|
503
600
|
/* graceful degrade — never block the research phase */
|
|
504
601
|
}
|
|
505
602
|
}
|
|
506
|
-
|
|
507
|
-
|
|
603
|
+
// C-v2 — persist the minimal gather outputs so a fresh session can
|
|
604
|
+
// re-enter the debate (loop-driver resume entry above) without re-running
|
|
605
|
+
// the interactive discovery + interview. Written once here at debate start,
|
|
606
|
+
// captures the final conversationContext (after project + BB context).
|
|
607
|
+
// Deleted after scoping writes the spec. Non-fatal on failure.
|
|
608
|
+
await writeDebateInputs(runDir, {
|
|
609
|
+
version: 1,
|
|
610
|
+
problemStatement: clarifiedSpec.problemStatement,
|
|
611
|
+
clarifiedSpec,
|
|
508
612
|
conversationContext,
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
//
|
|
513
|
-
//
|
|
514
|
-
//
|
|
515
|
-
//
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
613
|
+
savedAt: new Date().toISOString(),
|
|
614
|
+
});
|
|
615
|
+
// C (mid-debate checkpoint) — runDebate snapshots its per-round state to
|
|
616
|
+
// `<runDir>/debate-checkpoint.json` after each completed round and deletes
|
|
617
|
+
// it on normal completion. If a prior attempt (this process, or a crashed
|
|
618
|
+
// earlier run of the SAME runId) left a checkpoint, seed it so the debate
|
|
619
|
+
// resumes from the last completed round instead of re-running rounds 1..N.
|
|
620
|
+
let resumeCheckpoint = (await readDebateCheckpoint(runDir)) ?? undefined;
|
|
621
|
+
// In-process resilience: a mid-debate throw (provider 5xx after the
|
|
622
|
+
// fallback budget, transient network) re-runs runDebate ONCE (default)
|
|
623
|
+
// from the freshly-written checkpoint, so a round-5 break loses one round,
|
|
624
|
+
// not five. Only retried when a checkpoint exists (≥1 round completed) —
|
|
625
|
+
// a pre-round-1 failure has nothing to resume and rethrows immediately.
|
|
626
|
+
const maxDebateRetries = (() => {
|
|
627
|
+
const raw = process.env.MUONROI_DEBATE_RESUME_RETRIES;
|
|
628
|
+
const n = raw ? Number.parseInt(raw, 10) : Number.NaN;
|
|
629
|
+
return Number.isFinite(n) && n >= 0 ? n : 1;
|
|
630
|
+
})();
|
|
631
|
+
for (let attempt = 0;; attempt++) {
|
|
632
|
+
const debateGen = runDebate(clarifiedSpec, {
|
|
633
|
+
topic: ctx.idea,
|
|
634
|
+
conversationContext,
|
|
635
|
+
leaderModelId,
|
|
636
|
+
participants,
|
|
637
|
+
runId: ctx.sessionId ?? ctx.runId,
|
|
638
|
+
checkpointDir: runDir,
|
|
639
|
+
resumeCheckpoint,
|
|
640
|
+
// Item 3 — per-stance recall: each participant opens grounded in the
|
|
641
|
+
// stance-weighted slice of the brain its lens cares about. Bounded +
|
|
642
|
+
// failure-tolerant; unavailable EE leaves openings unchanged.
|
|
643
|
+
stanceRecall: makeStanceRecall(getDefaultEEClient(), {
|
|
644
|
+
cwd: ctx.flowDir,
|
|
645
|
+
sourceSession: ctx.sessionId ?? ctx.runId,
|
|
646
|
+
}),
|
|
647
|
+
}, ctx.llm);
|
|
648
|
+
// Suppress raw debate content so the user is not confused by inter-role
|
|
649
|
+
// monologue ("Researcher → Architect ... Question back to you?") which
|
|
650
|
+
// is NOT addressed to them. We still pass through phase/status events
|
|
651
|
+
// so the UI keeps a live progress indicator. After the debate completes
|
|
652
|
+
// we emit a single condensed summary.
|
|
653
|
+
try {
|
|
654
|
+
while (true) {
|
|
655
|
+
const { value, done } = await debateGen.next();
|
|
656
|
+
if (done) {
|
|
657
|
+
debateState = value;
|
|
658
|
+
break;
|
|
659
|
+
}
|
|
660
|
+
const chunk = value;
|
|
661
|
+
if (chunk.type === "content")
|
|
662
|
+
continue;
|
|
663
|
+
// Persist debate speaker turns to interaction_logs so forensics
|
|
664
|
+
// can replay the debate text without relying on TUI scrollback
|
|
665
|
+
// (which currently holds the only copy — messages/usage_events
|
|
666
|
+
// tables stay empty for the debate path).
|
|
667
|
+
if (chunk.type === "council_message" && chunk.councilMessage) {
|
|
668
|
+
const cm = chunk.councilMessage;
|
|
669
|
+
logLoopEvent(ctx, "council_message", {
|
|
670
|
+
phase: "research",
|
|
671
|
+
kind: cm.kind,
|
|
672
|
+
speakerRole: cm.speaker.role,
|
|
673
|
+
speakerModel: cm.speaker.model,
|
|
674
|
+
partnerRole: cm.partner?.role ?? null,
|
|
675
|
+
round: cm.round ?? null,
|
|
676
|
+
attempts: cm.attempts ?? 1,
|
|
677
|
+
failureReason: cm.failureReason ?? null,
|
|
678
|
+
toolCalls: cm.toolCalls?.map((tc) => tc.name) ?? [],
|
|
679
|
+
// Cap at 4000 chars so a single row stays well under SQLite
|
|
680
|
+
// text limits even for the most verbose speaker turn.
|
|
681
|
+
textExcerpt: cm.text.slice(0, 4000),
|
|
682
|
+
textLength: cm.text.length,
|
|
683
|
+
durationMs: cm.durationMs ?? null,
|
|
684
|
+
}, { model: cm.speaker.model, durationMs: cm.durationMs });
|
|
685
|
+
}
|
|
686
|
+
yield chunk;
|
|
523
687
|
}
|
|
524
|
-
|
|
525
|
-
|
|
688
|
+
break; // debate completed — exit the retry loop.
|
|
689
|
+
}
|
|
690
|
+
catch (err) {
|
|
691
|
+
// The debate iterator hit an exception (e.g. provider 5xx after the
|
|
692
|
+
// retry budget). Persist an audit row so we have a forensics trail —
|
|
693
|
+
// without it the FSM unwinds silently and the session looks like
|
|
694
|
+
// "research = 0 word" in the DB.
|
|
695
|
+
const freshCp = (await readDebateCheckpoint(runDir)) ?? undefined;
|
|
696
|
+
logLoopEvent(ctx, "council_error", {
|
|
697
|
+
phase: "research",
|
|
698
|
+
stage: "debate",
|
|
699
|
+
error: err instanceof Error ? err.message : String(err),
|
|
700
|
+
roundCount: debateState?.roundCount ?? freshCp?.roundCount ?? 0,
|
|
701
|
+
participantCount: participants.length,
|
|
702
|
+
elapsedMs: Date.now() - researchPhaseStartMs,
|
|
703
|
+
});
|
|
704
|
+
// C — resume-from-checkpoint retry: only when a completed round was
|
|
705
|
+
// checkpointed and retries remain. Otherwise rethrow unchanged.
|
|
706
|
+
if (attempt < maxDebateRetries && freshCp && freshCp.roundCount >= 1) {
|
|
707
|
+
resumeCheckpoint = freshCp;
|
|
708
|
+
yield {
|
|
709
|
+
type: "content",
|
|
710
|
+
content: `\n> Debate interrupted (${err instanceof Error ? err.message : String(err)}); resuming from round ${freshCp.roundCount + 1}…\n`,
|
|
711
|
+
};
|
|
526
712
|
continue;
|
|
527
|
-
// Persist debate speaker turns to interaction_logs so forensics
|
|
528
|
-
// can replay the debate text without relying on TUI scrollback
|
|
529
|
-
// (which currently holds the only copy — messages/usage_events
|
|
530
|
-
// tables stay empty for the debate path).
|
|
531
|
-
if (chunk.type === "council_message" && chunk.councilMessage) {
|
|
532
|
-
const cm = chunk.councilMessage;
|
|
533
|
-
logLoopEvent(ctx, "council_message", {
|
|
534
|
-
phase: "research",
|
|
535
|
-
kind: cm.kind,
|
|
536
|
-
speakerRole: cm.speaker.role,
|
|
537
|
-
speakerModel: cm.speaker.model,
|
|
538
|
-
partnerRole: cm.partner?.role ?? null,
|
|
539
|
-
round: cm.round ?? null,
|
|
540
|
-
attempts: cm.attempts ?? 1,
|
|
541
|
-
failureReason: cm.failureReason ?? null,
|
|
542
|
-
toolCalls: cm.toolCalls?.map((tc) => tc.name) ?? [],
|
|
543
|
-
// Cap at 4000 chars so a single row stays well under SQLite
|
|
544
|
-
// text limits even for the most verbose speaker turn.
|
|
545
|
-
textExcerpt: cm.text.slice(0, 4000),
|
|
546
|
-
textLength: cm.text.length,
|
|
547
|
-
});
|
|
548
713
|
}
|
|
549
|
-
|
|
714
|
+
throw err;
|
|
550
715
|
}
|
|
551
716
|
}
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
logLoopEvent(ctx, "council_error", {
|
|
558
|
-
phase: "research",
|
|
559
|
-
stage: "debate",
|
|
560
|
-
error: err instanceof Error ? err.message : String(err),
|
|
561
|
-
roundCount: debateState?.roundCount ?? 0,
|
|
562
|
-
participantCount: participants.length,
|
|
563
|
-
elapsedMs: Date.now() - researchPhaseStartMs,
|
|
564
|
-
});
|
|
565
|
-
throw err;
|
|
566
|
-
}
|
|
717
|
+
// F9 — resolve the debate summary once (runningSummary or a fallback
|
|
718
|
+
// synthesized from participant positions) for reuse across the research
|
|
719
|
+
// artifacts + scoping synthesis.
|
|
720
|
+
if (debateState)
|
|
721
|
+
resolvedDebateSummary = resolveDebateSummary(debateState);
|
|
567
722
|
// Forensics row mirrors the council/index.ts council_summary record
|
|
568
723
|
// (which only fires for sprint planning via runCouncil). The /ideal
|
|
569
724
|
// initial debate goes through runDebate here and was previously
|
|
@@ -592,18 +747,47 @@ export async function* runLoopDriver(ctx) {
|
|
|
592
747
|
durationMs: Date.now() - researchPhaseStartMs,
|
|
593
748
|
});
|
|
594
749
|
}
|
|
595
|
-
const summaryText =
|
|
750
|
+
const summaryText = resolvedDebateSummary || "(debate produced no summary — using empty research findings)";
|
|
596
751
|
yield {
|
|
597
752
|
type: "council_info_card",
|
|
598
753
|
councilInfoCard: buildResearchSummaryCard(summaryText, debateState?.researchFindings),
|
|
599
754
|
};
|
|
600
|
-
// Append research summary to delegations.md
|
|
755
|
+
// Append research summary to delegations.md (kept for back-compat: the
|
|
756
|
+
// EE transcript extractor + legacy readers still read these sections).
|
|
757
|
+
// A debate that returns after openings (leader routes straight to the
|
|
758
|
+
// preflight gate) leaves runningSummary empty — synthesize a faithful
|
|
759
|
+
// fallback from the participants' positions so the canonical research
|
|
760
|
+
// artifacts never silently drop the whole debate.
|
|
601
761
|
const delegationsMap = (await readArtifact(runDir, "delegations.md")) ?? { preamble: "", sections: new Map() };
|
|
602
|
-
delegationsMap.sections.set("Research Summary",
|
|
762
|
+
delegationsMap.sections.set("Research Summary", resolvedDebateSummary);
|
|
603
763
|
if (debateState.researchFindings) {
|
|
604
764
|
delegationsMap.sections.set("Research Findings", debateState.researchFindings);
|
|
605
765
|
}
|
|
606
766
|
await writeArtifact(runDir, "delegations.md", delegationsMap);
|
|
767
|
+
// Part A — promote the debate output to a first-class research.md. This
|
|
768
|
+
// is the canonical, reviewable surface (`/ideal review`) and the home
|
|
769
|
+
// for the EE recall seed once per-turn grounding lands (deferred).
|
|
770
|
+
try {
|
|
771
|
+
await writeResearchDoc(ctx.flowDir, ctx.runId, {
|
|
772
|
+
summary: resolvedDebateSummary,
|
|
773
|
+
findings: debateState.researchFindings ?? undefined,
|
|
774
|
+
webResearch: researchWebConfidence,
|
|
775
|
+
});
|
|
776
|
+
// Part C — persist the debate as a workflow_debate experience so a
|
|
777
|
+
// future run on a similar topic can seed its stances with what this
|
|
778
|
+
// council concluded (gate-on-outcome: fired after the debate produced
|
|
779
|
+
// a summary, not per-turn — Kill #4/#5).
|
|
780
|
+
fireAndForgetWorkflowEvent({
|
|
781
|
+
kind: "council-debate",
|
|
782
|
+
phaseRef: `runs/${ctx.runId}#research`,
|
|
783
|
+
sessionId: ctx.sessionId ?? ctx.runId,
|
|
784
|
+
text: (debateState.runningSummary ?? "").slice(0, 2000) || `debate on: ${ctx.idea.slice(0, 200)}`,
|
|
785
|
+
payload: { topic: ctx.idea.slice(0, 200), roundCount: debateState.roundCount ?? 0 },
|
|
786
|
+
});
|
|
787
|
+
}
|
|
788
|
+
catch {
|
|
789
|
+
/* non-critical — research.md is a review surface, never blocks the FSM */
|
|
790
|
+
}
|
|
607
791
|
// P6 - extract assumptions from the research debate so foundational
|
|
608
792
|
// claims (perf budgets, SDK contracts, etc.) become trackable across
|
|
609
793
|
// sprints rather than buried in stance prose. Silent skip on
|
|
@@ -667,7 +851,12 @@ export async function* runLoopDriver(ctx) {
|
|
|
667
851
|
phase: "scoping",
|
|
668
852
|
});
|
|
669
853
|
const stateMap = (await readArtifact(runDir, "state.md")) ?? { preamble: "", sections: new Map() };
|
|
670
|
-
stateMap.sections.set("Resume Digest",
|
|
854
|
+
stateMap.sections.set("Resume Digest", renderResumeDigest({
|
|
855
|
+
stage: "scoping",
|
|
856
|
+
lastCompleted: "research",
|
|
857
|
+
nextAction: "Synthesize the ProductSpec and confirm the roadmap at the preflight gate",
|
|
858
|
+
updatedAt: new Date().toISOString(),
|
|
859
|
+
}));
|
|
671
860
|
await writeArtifact(runDir, "state.md", stateMap);
|
|
672
861
|
// Visible progress indicator — without this the TUI sits silent for
|
|
673
862
|
// 30-60s while ctx.llm.generate runs the synthesis call. Users read
|
|
@@ -687,7 +876,7 @@ export async function* runLoopDriver(ctx) {
|
|
|
687
876
|
const synthesisPrompt = `Synthesize a ProductSpec JSON based on the following:
|
|
688
877
|
Idea: ${ctx.idea}
|
|
689
878
|
Clarified Spec: ${JSON.stringify(clarifiedSpec)}
|
|
690
|
-
Debate Summary: ${debateState.runningSummary}
|
|
879
|
+
Debate Summary: ${resolvedDebateSummary || debateState.runningSummary}
|
|
691
880
|
Research Findings: ${debateState.researchFindings ?? "N/A"}
|
|
692
881
|
|
|
693
882
|
Output ONLY a JSON object matching this interface:
|
|
@@ -758,6 +947,41 @@ interface ProductSpec {
|
|
|
758
947
|
const roadmapMap = (await readArtifact(runDir, "roadmap.md")) ?? { preamble: "", sections: new Map() };
|
|
759
948
|
roadmapMap.sections.set("Product Specification", JSON.stringify(productSpec, null, 2));
|
|
760
949
|
await writeArtifact(runDir, "roadmap.md", roadmapMap);
|
|
950
|
+
// Part C — the synthesized spec IS the council's decision. Persist it as
|
|
951
|
+
// a workflow_decision experience so future runs don't re-litigate a
|
|
952
|
+
// settled architectural/scoping choice.
|
|
953
|
+
fireAndForgetWorkflowEvent({
|
|
954
|
+
kind: "decision",
|
|
955
|
+
phaseRef: `runs/${ctx.runId}#scoping`,
|
|
956
|
+
sessionId: ctx.sessionId ?? ctx.runId,
|
|
957
|
+
text: `Scoped "${ctx.idea.slice(0, 120)}": ${(productSpec?.architecture ?? "").slice(0, 400)}`,
|
|
958
|
+
payload: {
|
|
959
|
+
persona: productSpec?.persona ?? null,
|
|
960
|
+
mvp: productSpec?.mvp ?? [],
|
|
961
|
+
sprintEstimate: productSpec?.sprintEstimate ?? null,
|
|
962
|
+
},
|
|
963
|
+
});
|
|
964
|
+
// C-v2 — debate + scoping are done and the spec is persisted, so the
|
|
965
|
+
// cross-session resume inputs are obsolete (the checkpoint was already
|
|
966
|
+
// deleted by runDebate on completion). Clean them up so a later
|
|
967
|
+
// `/ideal resume` of this run does not re-enter the debate FSM.
|
|
968
|
+
await deleteDebateInputs(runDir);
|
|
969
|
+
// Hierarchy index — place this run under a milestone (the product idea)
|
|
970
|
+
// and a phase (this scoped iteration). Idempotent across resume; purely
|
|
971
|
+
// an index over runs/, never rewrites run artifacts or ROADMAP phases.
|
|
972
|
+
try {
|
|
973
|
+
const mvpHead = Array.isArray(productSpec?.mvp) && productSpec.mvp.length > 0 ? productSpec.mvp[0] : "";
|
|
974
|
+
await ensureRunScoped(ctx.flowDir, {
|
|
975
|
+
runId: ctx.runId,
|
|
976
|
+
milestoneTitle: clampTitle(ctx.idea, 60),
|
|
977
|
+
milestoneGoal: (productSpec?.architecture ?? "").slice(0, 200),
|
|
978
|
+
phaseTitle: clampTitle(mvpHead || ctx.idea, 50),
|
|
979
|
+
phaseGoal: (productSpec?.persona ?? "").slice(0, 200),
|
|
980
|
+
}, new Date().toISOString());
|
|
981
|
+
}
|
|
982
|
+
catch {
|
|
983
|
+
/* non-critical — hierarchy is an index; failure must not block scoping */
|
|
984
|
+
}
|
|
761
985
|
// P8 - derive tasks.json from the spec (canonical machine-readable
|
|
762
986
|
// surface for downstream /execute consumption). MVP items get
|
|
763
987
|
// sprint=1, phase2 gets sprint=2. Re-deriving the same spec is
|
|
@@ -3,6 +3,27 @@ import type { Migrator } from "./discovery-migrations.js";
|
|
|
3
3
|
import type { LeaderLike } from "./discovery-prompt-parser.js";
|
|
4
4
|
import type { PhasePlanArtifact, ProductRunManifest } from "./types.js";
|
|
5
5
|
export declare const PHASE_PLANNER_SYSTEM: string;
|
|
6
|
+
/**
|
|
7
|
+
* Normalise `id` + `dependsOn` on every phase to the canonical string form.
|
|
8
|
+
* Mutates and returns the same plan object. Safe on already-normalised plans.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Coerce a plan's per-phase `maxSprints` to a usable sprint COUNT: an integer
|
|
12
|
+
* in [1, 20]. This is a pure VALIDITY FLOOR — it does NOT allocate or divide any
|
|
13
|
+
* budget. The PO/leader decides each phase's `maxSprints` from that phase's
|
|
14
|
+
* difficulty (see PHASE_PLANNER_SYSTEM); this only defends the executor against a
|
|
15
|
+
* malformed value the model might still emit.
|
|
16
|
+
*
|
|
17
|
+
* The sprint loop is `for (sprintN = 1; sprintN <= phase.maxSprints; sprintN++)`,
|
|
18
|
+
* so any value < 1 makes `1 <= 0.n` false → the loop body NEVER runs → `runSprint`
|
|
19
|
+
* is never called → implementation is silently skipped (the historical
|
|
20
|
+
* "plan is great but implement never starts / hangs" bug — a small `--max-sprints`
|
|
21
|
+
* once made the old "divide the budget across phases" prompt emit fractions like
|
|
22
|
+
* `0.3 / 0.2 / 0.5`). Flooring to an integer ≥ 1 guarantees every planned phase
|
|
23
|
+
* executes at least one sprint regardless of what the model returns.
|
|
24
|
+
*/
|
|
25
|
+
export declare function clampMaxSprints(raw: unknown): number;
|
|
26
|
+
export declare function normalizePhasePlan(plan: PhasePlanArtifact): PhasePlanArtifact;
|
|
6
27
|
export declare function parsePhasePlanJson(raw: string): PhasePlanArtifact;
|
|
7
28
|
export declare function validatePhasePlan(plan: PhasePlanArtifact, spec: ClarifiedSpec): void;
|
|
8
29
|
export declare function fallbackSinglePhase(spec: ClarifiedSpec, manifest: ProductRunManifest): PhasePlanArtifact;
|