muonroi-cli 1.8.4 → 1.8.5
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-tee.d.ts +48 -0
- package/dist/packages/agent-harness-core/src/event-tee.js +77 -0
- package/dist/packages/agent-harness-core/src/mcp-server.d.ts +11 -0
- package/dist/packages/agent-harness-core/src/mcp-server.js +87 -15
- package/dist/packages/agent-harness-core/src/protocol.d.ts +66 -2
- 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 +28 -0
- package/dist/src/agent-harness/mock-model.js +63 -1
- package/dist/src/agent-harness/test-spawn.js +31 -0
- 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 +2 -2
- package/dist/src/cli/keys.js +19 -81
- package/dist/src/council/clarifier.d.ts +28 -2
- package/dist/src/council/clarifier.js +81 -15
- 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 +51 -3
- 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 +1210 -134
- package/dist/src/council/index.d.ts +85 -1
- package/dist/src/council/index.js +634 -196
- package/dist/src/council/leader.d.ts +26 -0
- package/dist/src/council/leader.js +150 -9
- package/dist/src/council/llm.d.ts +32 -0
- package/dist/src/council/llm.js +231 -38
- package/dist/src/council/panel-select.d.ts +30 -0
- package/dist/src/council/panel-select.js +72 -0
- package/dist/src/council/planner.js +23 -0
- package/dist/src/council/preflight.d.ts +7 -0
- package/dist/src/council/preflight.js +14 -2
- package/dist/src/council/prompts.d.ts +30 -3
- package/dist/src/council/prompts.js +234 -64
- 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 +128 -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 +1 -0
- package/dist/src/ee/auth.js +15 -2
- package/dist/src/ee/bridge.d.ts +10 -0
- package/dist/src/ee/bridge.js +58 -0
- package/dist/src/ee/client.js +81 -18
- 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 +45 -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 +13 -1
- package/dist/src/flow/compaction/index.js +70 -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/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 +55 -0
- package/dist/src/gsd/flags.js +83 -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 +251 -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/hooks/index.js +1 -1
- package/dist/src/index.js +44 -11
- 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 +1 -1
- package/dist/src/mcp/ee-tools.js +1 -0
- package/dist/src/mcp/research-onboarding.js +8 -7
- package/dist/src/mcp/runtime.js +34 -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/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 +10 -0
- package/dist/src/orchestrator/compaction.js +27 -7
- package/dist/src/orchestrator/council-manager.d.ts +12 -3
- package/dist/src/orchestrator/council-manager.js +65 -24
- 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/message-processor.js +242 -33
- package/dist/src/orchestrator/orchestrator.d.ts +39 -3
- package/dist/src/orchestrator/orchestrator.js +651 -102
- package/dist/src/orchestrator/preprocessor.js +1 -1
- 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-intercept.d.ts +45 -0
- package/dist/src/orchestrator/safety-intercept.js +55 -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 +24 -3
- package/dist/src/orchestrator/stall-watchdog.js +47 -13
- package/dist/src/orchestrator/stream-runner.js +62 -29
- 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 +22 -0
- package/dist/src/orchestrator/tool-engine.js +620 -56
- 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 +37 -0
- package/dist/src/orchestrator/turn-watchdog.js +55 -0
- package/dist/src/pil/agent-operating-contract.d.ts +1 -1
- package/dist/src/pil/agent-operating-contract.js +1 -1
- 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.js +16 -11
- 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/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 +33 -2
- package/dist/src/pil/llm-classify.js +123 -131
- package/dist/src/pil/native-capabilities-workbook.d.ts +1 -1
- package/dist/src/pil/native-capabilities-workbook.js +1 -0
- package/dist/src/pil/pipeline.js +34 -2
- 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/backlog-builder.d.ts +14 -1
- package/dist/src/product-loop/backlog-builder.js +30 -6
- 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.js +32 -3
- package/dist/src/product-loop/discovery-schema.js +5 -1
- 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 +333 -52
- package/dist/src/product-loop/loop-driver.d.ts +7 -0
- package/dist/src/product-loop/loop-driver.js +310 -99
- package/dist/src/product-loop/phase-plan.d.ts +5 -0
- package/dist/src/product-loop/phase-plan.js +39 -2
- package/dist/src/product-loop/phase-runner.js +9 -1
- package/dist/src/product-loop/sprint-runner.d.ts +111 -0
- package/dist/src/product-loop/sprint-runner.js +559 -16
- package/dist/src/product-loop/types.d.ts +36 -5
- package/dist/src/providers/adapter.d.ts +1 -1
- package/dist/src/providers/adapter.js +3 -4
- 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/openai-oauth.js +1 -1
- package/dist/src/providers/auth/registry.js +0 -34
- package/dist/src/providers/auth/token-store.js +4 -1
- package/dist/src/providers/auth/types.d.ts +1 -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/keychain.d.ts +1 -1
- package/dist/src/providers/keychain.js +7 -9
- 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 +27 -2
- package/dist/src/providers/runtime.js +78 -15
- 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 +280 -1
- 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/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 +3 -3
- 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 +284 -13
- package/dist/src/tools/file.d.ts +15 -0
- package/dist/src/tools/file.js +32 -0
- package/dist/src/tools/native-tools.js +5 -0
- package/dist/src/tools/registry.d.ts +3 -0
- package/dist/src/tools/registry.js +460 -22
- package/dist/src/tools/research.d.ts +29 -0
- package/dist/src/tools/research.js +233 -0
- package/dist/src/types/index.d.ts +118 -3
- package/dist/src/ui/app.js +0 -0
- package/dist/src/ui/cards/product-status-card.js +1 -1
- 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/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 +49 -15
- 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 +12 -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/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/containers/modals-layer.d.ts +2 -1
- 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/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/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 +12 -18
- 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/format.d.ts +14 -0
- package/dist/src/ui/utils/format.js +23 -3
- package/dist/src/usage/downgrade.js +2 -2
- package/dist/src/usage/product-ledger.js +2 -2
- package/dist/src/utils/install-manager.js +2 -1
- package/dist/src/utils/logger.js +2 -2
- package/dist/src/utils/permission-mode.js +5 -3
- package/dist/src/utils/redactor.js +1 -1
- package/dist/src/utils/settings.d.ts +153 -5
- package/dist/src/utils/settings.js +233 -29
- 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 +1 -1
- package/dist/src/verify/recipes.d.ts +13 -0
- package/dist/src/verify/recipes.js +15 -0
- package/package.json +135 -132
- 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,21 +1,23 @@
|
|
|
1
1
|
import { promises as fs } from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
|
+
import { readDebateCheckpoint } from "../council/debate-checkpoint.js";
|
|
3
4
|
import { resolveLeaderModel } from "../council/leader.js";
|
|
4
5
|
import { routeModel as eeRouteModel } from "../ee/bridge.js";
|
|
5
6
|
import { fireAndForgetPhaseOutcome } from "../ee/phase-outcome.js";
|
|
6
7
|
import { readArtifact } from "../flow/artifact-io.js";
|
|
8
|
+
import { parseResumeDigest, readSprintOutcomes } from "../flow/run-artifacts.js";
|
|
7
9
|
import { createRun, loadRun } from "../flow/run-manager.js";
|
|
8
10
|
import { getModelsForProvider } from "../models/registry.js";
|
|
9
11
|
import { loadKeyForProvider } from "../providers/keychain.js";
|
|
10
12
|
import { ALL_PROVIDER_IDS } from "../providers/types.js";
|
|
11
13
|
import { defaultResolveChannelId, maybeAutoFire } from "../reporter/auto-fire.js";
|
|
14
|
+
import { clearWorkspaceFocus, setWorkspaceFocus } from "../state/active-run.js";
|
|
12
15
|
import { logInteraction, logUIInteraction } from "../storage/index.js";
|
|
13
|
-
import { activeRunStore } from "../ui/state/active-run.js";
|
|
14
16
|
import { markIterationCrashed, readIterations, readManifest, writeManifest } from "./artifact-io.js";
|
|
15
17
|
import { buildBacklog } from "./backlog-builder.js";
|
|
16
18
|
import { readBacklog, writeBacklog } from "./backlog-store.js";
|
|
17
19
|
import { formatCostPreview, previewRunCost } from "./cost-preview.js";
|
|
18
|
-
import { extractRunToEE } from "./cross-run-memory.js";
|
|
20
|
+
import { composeRunTranscript, extractRunToEE } from "./cross-run-memory.js";
|
|
19
21
|
import { buildContinueFeedback } from "./feedback-routing.js";
|
|
20
22
|
import { runLoopDriver } from "./loop-driver.js";
|
|
21
23
|
import { resolveRoles } from "./role-registry.js";
|
|
@@ -38,6 +40,8 @@ export async function* runProductLoop(opts) {
|
|
|
38
40
|
switch (sub) {
|
|
39
41
|
case "status":
|
|
40
42
|
return yield* runStatus(opts);
|
|
43
|
+
case "review":
|
|
44
|
+
return yield* runReview(opts);
|
|
41
45
|
case "resume":
|
|
42
46
|
return yield* runResume(opts);
|
|
43
47
|
case "abort":
|
|
@@ -46,14 +50,30 @@ export async function* runProductLoop(opts) {
|
|
|
46
50
|
return yield* runShip(opts);
|
|
47
51
|
default: {
|
|
48
52
|
// Mode C dispatch — see .planning/MAINTAIN-MODE.md "Trigger mechanism".
|
|
49
|
-
// 1. Explicit --maintain
|
|
50
|
-
// 2. Explicit --new
|
|
51
|
-
// 3.
|
|
52
|
-
// 4.
|
|
53
|
+
// 1. Explicit --maintain → Mode C (strongest signal; wins over --force-council)
|
|
54
|
+
// 2. Explicit --new → Mode A (skip recipe detection)
|
|
55
|
+
// 3. --force-council → Mode A (user explicitly wants the full Council/loop)
|
|
56
|
+
// 4. Auto-detect: verify recipe present in cwd → Mode C
|
|
57
|
+
// 5. Otherwise → Mode A
|
|
53
58
|
if (opts.mode === "maintain") {
|
|
54
59
|
return yield* runMaintain(opts);
|
|
55
60
|
}
|
|
56
|
-
|
|
61
|
+
// `--force-council` must bypass the recipe auto-detect. Without this,
|
|
62
|
+
// ANY recipe-bearing repo (package.json/*.csproj/…) routes to runMaintain
|
|
63
|
+
// here — BEFORE the forceCouncil checks below (:189 / :197) are ever
|
|
64
|
+
// reached — so `/ideal --force-council` in an existing project was silently
|
|
65
|
+
// downgraded to maint-edit (observed: route-decision forceCouncil:false,
|
|
66
|
+
// path:maintain). Explicit --maintain above still wins over --force-council.
|
|
67
|
+
//
|
|
68
|
+
// complexity==="high" ALSO bypasses the recipe auto-detect. An
|
|
69
|
+
// architectural change (migration, SDK removal, subsystem rewrite) in a
|
|
70
|
+
// recipe-bearing repo must still earn the full Council — the very intent
|
|
71
|
+
// the complexity gate at :196-207 (and comment :188-195) documents. Before
|
|
72
|
+
// this guard, that gate was dead code for any repo with a verify recipe
|
|
73
|
+
// (real orchestrator ALWAYS wires detectVerifyRecipe), so a high-complexity
|
|
74
|
+
// /ideal was silently downgraded to maint-edit and jumped straight to Edit
|
|
75
|
+
// with no debate (observed: route-decision complexity:high path:maintain).
|
|
76
|
+
if (opts.mode !== "new" && !opts.flags.forceCouncil && opts.complexity !== "high" && opts.detectVerifyRecipe) {
|
|
57
77
|
try {
|
|
58
78
|
const recipe = await opts.detectVerifyRecipe();
|
|
59
79
|
if (recipe) {
|
|
@@ -86,10 +106,18 @@ export async function* runProductLoop(opts) {
|
|
|
86
106
|
};
|
|
87
107
|
return yield* runStart(forcedOpts);
|
|
88
108
|
}
|
|
89
|
-
// Existing repo + complexity≠high → hot-path. The leader
|
|
90
|
-
// the source instead of interviewing the user.
|
|
91
|
-
//
|
|
92
|
-
|
|
109
|
+
// Existing repo + complexity≠high + well-specified → hot-path. The leader
|
|
110
|
+
// can grep the source instead of interviewing the user. Two things still
|
|
111
|
+
// warrant the full Council/interview path: an architectural change
|
|
112
|
+
// (complexity=high / heavy), OR a request the model flagged as
|
|
113
|
+
// UNDERSPECIFIED (needsClarification) — a standard task missing a target
|
|
114
|
+
// or design decision must be clarified before code. A `quick`
|
|
115
|
+
// (complexity=low) task always hot-paths (handled below) even when
|
|
116
|
+
// underspecified: a trivial ask never earns an interview.
|
|
117
|
+
if (existingRepoBypass &&
|
|
118
|
+
opts.complexity !== "high" &&
|
|
119
|
+
!(opts.needsClarification && opts.complexity !== "low") &&
|
|
120
|
+
!opts.flags.forceCouncil) {
|
|
93
121
|
return yield* runHotPath(opts);
|
|
94
122
|
}
|
|
95
123
|
if (opts.complexity === "low" && !opts.flags.forceCouncil) {
|
|
@@ -148,6 +176,22 @@ async function* runHotPath(opts) {
|
|
|
148
176
|
stack: flags.stack,
|
|
149
177
|
createdAt: new Date(),
|
|
150
178
|
});
|
|
179
|
+
if (opts.cwd) {
|
|
180
|
+
try {
|
|
181
|
+
const { isGsdNativeEnabled } = await import("../gsd/flags.js");
|
|
182
|
+
if (isGsdNativeEnabled()) {
|
|
183
|
+
const { ensureProductPlanningWorkspace } = await import("../gsd/product-workspace.js");
|
|
184
|
+
ensureProductPlanningWorkspace(opts.cwd, {
|
|
185
|
+
idea,
|
|
186
|
+
sessionModelId: opts.sessionModelId,
|
|
187
|
+
runId,
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
catch (err) {
|
|
192
|
+
console.error(`[ideal/hot-path] gsd product workspace bootstrap failed: ${err.message}`);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
151
195
|
yield {
|
|
152
196
|
type: "content",
|
|
153
197
|
content: "\n> hot-path: complexity=low → single sprint, no council debate\n",
|
|
@@ -160,6 +204,7 @@ async function* runHotPath(opts) {
|
|
|
160
204
|
kind: "route-decision",
|
|
161
205
|
path: "hot-path",
|
|
162
206
|
complexity: opts.complexity ?? "low",
|
|
207
|
+
underspecified: !!opts.needsClarification,
|
|
163
208
|
forceCouncil: false,
|
|
164
209
|
runId,
|
|
165
210
|
});
|
|
@@ -201,7 +246,7 @@ async function* runHotPath(opts) {
|
|
|
201
246
|
try {
|
|
202
247
|
const { productSlug: deriveSlug } = await import("./product-identity.js");
|
|
203
248
|
const slug = deriveSlug(idea);
|
|
204
|
-
|
|
249
|
+
await setWorkspaceFocus(flowDir, { runId, productSlug: slug, reason: "sprint-plan-committed" });
|
|
205
250
|
fireAutoReport("sprint-plan-committed", { runId, flowDir, productSlug: slug, sprintCount: 1 });
|
|
206
251
|
}
|
|
207
252
|
catch {
|
|
@@ -233,6 +278,7 @@ async function* runHotPath(opts) {
|
|
|
233
278
|
cwd: opts.cwd,
|
|
234
279
|
sessionId: opts.sessionId,
|
|
235
280
|
processMessageFn: opts.processMessageFn,
|
|
281
|
+
runIsolatedTask: opts.runIsolatedTask,
|
|
236
282
|
detectVerifyRecipe: opts.detectVerifyRecipe,
|
|
237
283
|
skipPriorContext: opts.skipPriorContext,
|
|
238
284
|
sufficiencyMissing: opts.sufficiencyMissing,
|
|
@@ -556,6 +602,22 @@ async function* runStart(opts) {
|
|
|
556
602
|
stack: flags.stack,
|
|
557
603
|
createdAt: new Date(),
|
|
558
604
|
});
|
|
605
|
+
if (opts.cwd) {
|
|
606
|
+
try {
|
|
607
|
+
const { isGsdNativeEnabled } = await import("../gsd/flags.js");
|
|
608
|
+
if (isGsdNativeEnabled()) {
|
|
609
|
+
const { ensureProductPlanningWorkspace } = await import("../gsd/product-workspace.js");
|
|
610
|
+
ensureProductPlanningWorkspace(opts.cwd, {
|
|
611
|
+
idea,
|
|
612
|
+
sessionModelId: opts.sessionModelId,
|
|
613
|
+
runId,
|
|
614
|
+
});
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
catch (err) {
|
|
618
|
+
console.error(`[ideal] gsd product workspace bootstrap failed: ${err.message}`);
|
|
619
|
+
}
|
|
620
|
+
}
|
|
559
621
|
// Surface a cost-vs-cap preview before the loop kicks off so $50 isn't
|
|
560
622
|
// an arbitrary number — show predicted spend per sprint × max-sprints
|
|
561
623
|
// against the configured cap, with a recommended max-sprints if it
|
|
@@ -574,6 +636,7 @@ async function* runStart(opts) {
|
|
|
574
636
|
kind: "route-decision",
|
|
575
637
|
path: "council",
|
|
576
638
|
complexity: opts.complexity ?? "unknown",
|
|
639
|
+
underspecified: !!opts.needsClarification,
|
|
577
640
|
forceCouncil: !!opts.flags.forceCouncil,
|
|
578
641
|
sufficiencyMissing: opts.sufficiencyMissing ?? [],
|
|
579
642
|
runId,
|
|
@@ -604,6 +667,7 @@ async function* runStart(opts) {
|
|
|
604
667
|
cwd: opts.cwd,
|
|
605
668
|
sessionId: opts.sessionId,
|
|
606
669
|
processMessageFn: opts.processMessageFn,
|
|
670
|
+
runIsolatedTask: opts.runIsolatedTask,
|
|
607
671
|
detectVerifyRecipe: opts.detectVerifyRecipe,
|
|
608
672
|
skipPriorContext: opts.skipPriorContext,
|
|
609
673
|
sufficiencyMissing: opts.sufficiencyMissing,
|
|
@@ -688,7 +752,7 @@ async function* runStart(opts) {
|
|
|
688
752
|
try {
|
|
689
753
|
const { productSlug: deriveSlug } = await import("./product-identity.js");
|
|
690
754
|
const slug = deriveSlug(idea);
|
|
691
|
-
|
|
755
|
+
await setWorkspaceFocus(flowDir, { runId, productSlug: slug, reason: "sprint-plan-committed" });
|
|
692
756
|
fireAutoReport("sprint-plan-committed", { runId, flowDir, productSlug: slug, sprintCount });
|
|
693
757
|
}
|
|
694
758
|
catch {
|
|
@@ -880,7 +944,7 @@ async function* drainSprints(args) {
|
|
|
880
944
|
const { productSlug: deriveSlug } = await import("./product-identity.js");
|
|
881
945
|
const slug = deriveSlug(productSpec.idea);
|
|
882
946
|
fireAutoReport("sprint-halt", { runId: ctx.runId, flowDir: ctx.flowDir, productSlug: slug, haltReason });
|
|
883
|
-
|
|
947
|
+
clearWorkspaceFocus();
|
|
884
948
|
}
|
|
885
949
|
catch {
|
|
886
950
|
/* best-effort */
|
|
@@ -934,7 +998,7 @@ async function* drainSprints(args) {
|
|
|
934
998
|
const { productSlug: deriveSlug } = await import("./product-identity.js");
|
|
935
999
|
const slug = deriveSlug(productSpec.idea);
|
|
936
1000
|
fireAutoReport("sprint-halt", { runId: ctx.runId, flowDir: ctx.flowDir, productSlug: slug, haltReason: msg });
|
|
937
|
-
|
|
1001
|
+
clearWorkspaceFocus();
|
|
938
1002
|
}
|
|
939
1003
|
catch {
|
|
940
1004
|
/* best-effort */
|
|
@@ -1028,7 +1092,7 @@ async function* drainSprints(args) {
|
|
|
1028
1092
|
}
|
|
1029
1093
|
}
|
|
1030
1094
|
// B1: clear active-run on successful ship.
|
|
1031
|
-
|
|
1095
|
+
clearWorkspaceFocus();
|
|
1032
1096
|
return {
|
|
1033
1097
|
runId: ctx.runId,
|
|
1034
1098
|
stage: "approved",
|
|
@@ -1052,7 +1116,7 @@ async function* drainSprints(args) {
|
|
|
1052
1116
|
content: `\n> Reached max-sprints (${flags.maxSprints}) without satisfying Definition-of-Done.\n`,
|
|
1053
1117
|
};
|
|
1054
1118
|
// B1: clear active-run when max-sprints reached.
|
|
1055
|
-
|
|
1119
|
+
clearWorkspaceFocus();
|
|
1056
1120
|
return {
|
|
1057
1121
|
runId: ctx.runId,
|
|
1058
1122
|
stage: "halted",
|
|
@@ -1247,6 +1311,8 @@ async function* runPhasesPath(args) {
|
|
|
1247
1311
|
remainingUsd: async () => Math.max(0, manifest.capUsd - (await getProductSpentUsd(ctx.runId))),
|
|
1248
1312
|
awaitCustomerVerdict,
|
|
1249
1313
|
sprintRunner,
|
|
1314
|
+
projectCwd: ctx.cwd,
|
|
1315
|
+
idea: ctx.idea,
|
|
1250
1316
|
});
|
|
1251
1317
|
let phaseOutcome = { pass: false };
|
|
1252
1318
|
while (true) {
|
|
@@ -1384,12 +1450,27 @@ async function* runStatus(opts) {
|
|
|
1384
1450
|
return { runId: opts.runId, stage: "error", success: false, reason: "not_found" };
|
|
1385
1451
|
}
|
|
1386
1452
|
const iters = await readIterations(opts.flowDir, opts.runId);
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1453
|
+
const digest = await readResumeDigest(opts.flowDir, opts.runId);
|
|
1454
|
+
const outcomes = await readSprintOutcomes(opts.flowDir, opts.runId).catch(() => []);
|
|
1455
|
+
const lines = [
|
|
1456
|
+
`Run ${opts.runId}: ${m.idea}`,
|
|
1457
|
+
`Cap: $${m.capUsd} MaxSprints: ${m.maxSprints} DoneThreshold: ${m.doneThreshold}`,
|
|
1458
|
+
`Iterations: ${iters.length} Aborted: ${m.aborted ?? false} DoneAt: ${m.doneAt?.toISOString() ?? "—"}`,
|
|
1459
|
+
];
|
|
1460
|
+
if (digest) {
|
|
1461
|
+
lines.push("", "Resume Digest:", ` Stage: ${digest.stage}` +
|
|
1462
|
+
(typeof digest.sprintN === "number" ? ` Sprint: ${digest.sprintN}` : "") +
|
|
1463
|
+
(typeof digest.score === "number" ? ` Score: ${digest.score.toFixed(2)}` : "") +
|
|
1464
|
+
(digest.verify ? ` Verify: ${digest.verify}` : ""), ` Next: ${digest.nextAction || "—"}`);
|
|
1465
|
+
}
|
|
1466
|
+
if (outcomes.length > 0) {
|
|
1467
|
+
lines.push("", "Sprints:");
|
|
1468
|
+
for (const o of outcomes) {
|
|
1469
|
+
lines.push(` #${o.sprintN} ${o.pass ? "✓ pass" : "✗ fail"} score=${o.score.toFixed(2)} verify=${o.verify}` +
|
|
1470
|
+
(o.failedCondition ? ` (${o.failedCondition})` : ""));
|
|
1471
|
+
}
|
|
1472
|
+
}
|
|
1473
|
+
yield { type: "content", content: `${lines.join("\n")}\n` };
|
|
1393
1474
|
return { runId: opts.runId, stage: "approved", success: true };
|
|
1394
1475
|
}
|
|
1395
1476
|
const lines = [`Active runs (${entries.length}):`];
|
|
@@ -1398,26 +1479,108 @@ async function* runStatus(opts) {
|
|
|
1398
1479
|
const iters = await readIterations(opts.flowDir, id).catch(() => []);
|
|
1399
1480
|
if (!m)
|
|
1400
1481
|
continue;
|
|
1401
|
-
|
|
1482
|
+
const digest = await readResumeDigest(opts.flowDir, id).catch(() => null);
|
|
1483
|
+
const stagePart = digest ? ` stage=${digest.stage}` : "";
|
|
1484
|
+
lines.push(` ${id} ${m.idea.slice(0, 60)} sprints=${iters.length}${stagePart} aborted=${m.aborted ?? false}`);
|
|
1402
1485
|
}
|
|
1403
1486
|
yield { type: "content", content: `${lines.join("\n")}\n` };
|
|
1404
1487
|
return { runId: "", stage: "approved", success: true };
|
|
1405
1488
|
}
|
|
1489
|
+
/**
|
|
1490
|
+
* Read + parse the structured Resume Digest from a run's top-level state.md.
|
|
1491
|
+
* Returns null when the run has no digest yet (or only a legacy one-liner).
|
|
1492
|
+
*/
|
|
1493
|
+
async function readResumeDigest(flowDir, runId) {
|
|
1494
|
+
const run = await loadRun(flowDir, runId).catch(() => null);
|
|
1495
|
+
if (!run)
|
|
1496
|
+
return null;
|
|
1497
|
+
return parseResumeDigest(run.state.sections.get("Resume Digest"));
|
|
1498
|
+
}
|
|
1499
|
+
/**
|
|
1500
|
+
* `/ideal review [runId]` — render a run's composed transcript plus a scored
|
|
1501
|
+
* sprint table. Read-only. With no runId, reviews the most recent run (any
|
|
1502
|
+
* status — review is a post-hoc lens, not restricted to incomplete runs).
|
|
1503
|
+
*/
|
|
1504
|
+
async function* runReview(opts) {
|
|
1505
|
+
let resolvedRunId = opts.runId;
|
|
1506
|
+
if (!resolvedRunId) {
|
|
1507
|
+
const runsRoot = path.join(opts.flowDir, "runs");
|
|
1508
|
+
let entries = [];
|
|
1509
|
+
try {
|
|
1510
|
+
entries = await fs.readdir(runsRoot);
|
|
1511
|
+
}
|
|
1512
|
+
catch {
|
|
1513
|
+
yield { type: "content", content: "No runs to review.\n" };
|
|
1514
|
+
return { runId: "", stage: "error", success: false, reason: "no_runs" };
|
|
1515
|
+
}
|
|
1516
|
+
const dated = [];
|
|
1517
|
+
for (const id of entries) {
|
|
1518
|
+
const m = await readManifest(opts.flowDir, id).catch(() => null);
|
|
1519
|
+
if (!m)
|
|
1520
|
+
continue;
|
|
1521
|
+
const createdAt = m.createdAt instanceof Date && !Number.isNaN(m.createdAt.getTime()) ? m.createdAt.getTime() : 0;
|
|
1522
|
+
dated.push({ id, createdAt });
|
|
1523
|
+
}
|
|
1524
|
+
if (dated.length === 0) {
|
|
1525
|
+
yield { type: "content", content: "No runs to review.\n" };
|
|
1526
|
+
return { runId: "", stage: "error", success: false, reason: "no_runs" };
|
|
1527
|
+
}
|
|
1528
|
+
dated.sort((a, b) => b.createdAt - a.createdAt);
|
|
1529
|
+
resolvedRunId = dated[0].id;
|
|
1530
|
+
}
|
|
1531
|
+
const manifest = await readManifest(opts.flowDir, resolvedRunId);
|
|
1532
|
+
if (!manifest) {
|
|
1533
|
+
yield { type: "content", content: `Run not found: ${resolvedRunId}\n` };
|
|
1534
|
+
return { runId: resolvedRunId, stage: "error", success: false, reason: "not_found" };
|
|
1535
|
+
}
|
|
1536
|
+
const header = [
|
|
1537
|
+
`# Review — run ${resolvedRunId}`,
|
|
1538
|
+
"",
|
|
1539
|
+
`Idea: ${manifest.idea}`,
|
|
1540
|
+
`Aborted: ${manifest.aborted ?? false} DoneAt: ${manifest.doneAt?.toISOString() ?? "—"}`,
|
|
1541
|
+
];
|
|
1542
|
+
const digest = await readResumeDigest(opts.flowDir, resolvedRunId);
|
|
1543
|
+
if (digest) {
|
|
1544
|
+
header.push(`Last stage: ${digest.stage} — ${digest.nextAction || "—"}`);
|
|
1545
|
+
}
|
|
1546
|
+
const outcomes = await readSprintOutcomes(opts.flowDir, resolvedRunId).catch(() => []);
|
|
1547
|
+
if (outcomes.length > 0) {
|
|
1548
|
+
header.push("", "## Sprint scores", "", "| Sprint | Result | Score | Verify | Failed condition |", "|---|---|---|---|---|");
|
|
1549
|
+
for (const o of outcomes) {
|
|
1550
|
+
header.push(`| ${o.sprintN} | ${o.pass ? "pass" : "fail"} | ${o.score.toFixed(2)} | ${o.verify} | ${o.failedCondition ?? "—"} |`);
|
|
1551
|
+
}
|
|
1552
|
+
}
|
|
1553
|
+
yield { type: "content", content: `${header.join("\n")}\n` };
|
|
1554
|
+
// The composed transcript (manifest/roadmap/delegations/gray-areas) rounds out
|
|
1555
|
+
// the review with the actual debate + spec text. Bounded to 32KB by the composer.
|
|
1556
|
+
const transcript = await composeRunTranscript(opts.flowDir, resolvedRunId).catch(() => "");
|
|
1557
|
+
if (transcript.trim()) {
|
|
1558
|
+
yield { type: "content", content: `\n## Transcript\n${transcript}\n` };
|
|
1559
|
+
}
|
|
1560
|
+
return { runId: resolvedRunId, stage: "approved", success: true };
|
|
1561
|
+
}
|
|
1406
1562
|
async function* runAbort(opts) {
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1563
|
+
// A/B — bare `/ideal abort` (no runId, e.g. the recovery card's Abort option):
|
|
1564
|
+
// auto-detect the newest incomplete run, mirroring resume.
|
|
1565
|
+
let resolvedRunId = opts.runId;
|
|
1566
|
+
if (!resolvedRunId) {
|
|
1567
|
+
const latest = await findLatestIncompleteRun(opts.flowDir);
|
|
1568
|
+
if (!latest) {
|
|
1569
|
+
yield { type: "content", content: "No incomplete run to abort.\n" };
|
|
1570
|
+
return { runId: "", stage: "error", success: false, reason: "no_incomplete_run" };
|
|
1571
|
+
}
|
|
1572
|
+
resolvedRunId = latest.id;
|
|
1410
1573
|
}
|
|
1411
|
-
const m = await readManifest(opts.flowDir,
|
|
1574
|
+
const m = await readManifest(opts.flowDir, resolvedRunId);
|
|
1412
1575
|
if (!m) {
|
|
1413
|
-
yield { type: "content", content: `Run not found: ${
|
|
1414
|
-
return { runId:
|
|
1576
|
+
yield { type: "content", content: `Run not found: ${resolvedRunId}\n` };
|
|
1577
|
+
return { runId: resolvedRunId, stage: "error", success: false, reason: "not_found" };
|
|
1415
1578
|
}
|
|
1416
|
-
await writeManifest(opts.flowDir,
|
|
1579
|
+
await writeManifest(opts.flowDir, resolvedRunId, { ...m, aborted: true, doneAt: new Date() });
|
|
1417
1580
|
// Fire-and-forget EE phase-outcome=aborted (extension landed in 13-05).
|
|
1418
1581
|
try {
|
|
1419
1582
|
fireAndForgetPhaseOutcome({
|
|
1420
|
-
sessionId:
|
|
1583
|
+
sessionId: resolvedRunId,
|
|
1421
1584
|
phaseName: "product-loop",
|
|
1422
1585
|
outcome: "aborted",
|
|
1423
1586
|
});
|
|
@@ -1431,9 +1594,9 @@ async function* runAbort(opts) {
|
|
|
1431
1594
|
// EE client is non-fatal (offline queue absorbs transport failures).
|
|
1432
1595
|
// P1.6: log telemetry for the extract outcome.
|
|
1433
1596
|
{
|
|
1434
|
-
const eeResult = await extractRunToEE(opts.flowDir,
|
|
1597
|
+
const eeResult = await extractRunToEE(opts.flowDir, resolvedRunId, opts.cwd ?? process.cwd());
|
|
1435
1598
|
try {
|
|
1436
|
-
logInteraction(opts.sessionId ??
|
|
1599
|
+
logInteraction(opts.sessionId ?? resolvedRunId ?? "abort", "ee_injection", {
|
|
1437
1600
|
eventSubtype: "extract",
|
|
1438
1601
|
durationMs: Math.round(eeResult.durationMs),
|
|
1439
1602
|
data: {
|
|
@@ -1447,39 +1610,106 @@ async function* runAbort(opts) {
|
|
|
1447
1610
|
// DB errors must not break /ideal
|
|
1448
1611
|
}
|
|
1449
1612
|
}
|
|
1450
|
-
yield { type: "content", content: `Aborted run ${
|
|
1451
|
-
return { runId:
|
|
1613
|
+
yield { type: "content", content: `Aborted run ${resolvedRunId}.\n` };
|
|
1614
|
+
return { runId: resolvedRunId, stage: "halted", success: false, reason: "aborted" };
|
|
1615
|
+
}
|
|
1616
|
+
/**
|
|
1617
|
+
* B — Auto-detect the newest resumable run.
|
|
1618
|
+
*
|
|
1619
|
+
* "Resumable" = a run that has a manifest (early pre-manifest crashes are not
|
|
1620
|
+
* replayable) AND is neither aborted nor terminal (`doneAt` is set on done-gate
|
|
1621
|
+
* pass / ship / abort). Sorted by manifest `createdAt` descending so a bare
|
|
1622
|
+
* `/ideal resume` continues the most recent incomplete run without the user
|
|
1623
|
+
* having to remember (or type) the runId.
|
|
1624
|
+
*/
|
|
1625
|
+
async function findLatestIncompleteRun(flowDir) {
|
|
1626
|
+
const runsRoot = path.join(flowDir, "runs");
|
|
1627
|
+
let entries;
|
|
1628
|
+
try {
|
|
1629
|
+
entries = await fs.readdir(runsRoot);
|
|
1630
|
+
}
|
|
1631
|
+
catch (err) {
|
|
1632
|
+
// No runs directory yet → nothing to resume. Not an error worth surfacing.
|
|
1633
|
+
if (err?.code !== "ENOENT") {
|
|
1634
|
+
console.error(`[product-loop] findLatestIncompleteRun: readdir failed: ${err?.message}`);
|
|
1635
|
+
}
|
|
1636
|
+
return null;
|
|
1637
|
+
}
|
|
1638
|
+
const candidates = [];
|
|
1639
|
+
for (const id of entries) {
|
|
1640
|
+
const m = await readManifest(flowDir, id).catch((e) => {
|
|
1641
|
+
console.error(`[product-loop] findLatestIncompleteRun: manifest read failed for ${id}: ${e?.message}`);
|
|
1642
|
+
return null;
|
|
1643
|
+
});
|
|
1644
|
+
if (!m)
|
|
1645
|
+
continue; // no manifest → not resumable
|
|
1646
|
+
if (m.aborted)
|
|
1647
|
+
continue; // hard-killed
|
|
1648
|
+
if (m.doneAt)
|
|
1649
|
+
continue; // terminal (done / shipped)
|
|
1650
|
+
const createdAt = m.createdAt instanceof Date && !Number.isNaN(m.createdAt.getTime()) ? m.createdAt.getTime() : 0;
|
|
1651
|
+
candidates.push({ id, idea: m.idea, createdAt });
|
|
1652
|
+
}
|
|
1653
|
+
if (candidates.length === 0)
|
|
1654
|
+
return null;
|
|
1655
|
+
candidates.sort((a, b) => b.createdAt - a.createdAt);
|
|
1656
|
+
const top = candidates[0];
|
|
1657
|
+
return { id: top.id, idea: top.idea };
|
|
1452
1658
|
}
|
|
1453
1659
|
async function* runResume(opts) {
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1660
|
+
// B — bare `/ideal resume` (no runId): auto-detect the newest incomplete run.
|
|
1661
|
+
let resolvedRunId = opts.runId;
|
|
1662
|
+
if (!resolvedRunId) {
|
|
1663
|
+
const latest = await findLatestIncompleteRun(opts.flowDir);
|
|
1664
|
+
if (!latest) {
|
|
1665
|
+
yield {
|
|
1666
|
+
type: "content",
|
|
1667
|
+
content: 'No incomplete run to resume. Start one with /ideal "<idea>".\n',
|
|
1668
|
+
};
|
|
1669
|
+
return { runId: "", stage: "error", success: false, reason: "no_incomplete_run" };
|
|
1670
|
+
}
|
|
1671
|
+
resolvedRunId = latest.id;
|
|
1672
|
+
yield {
|
|
1673
|
+
type: "content",
|
|
1674
|
+
content: `Resuming latest incomplete run ${resolvedRunId}: ${latest.idea.slice(0, 60)}\n`,
|
|
1675
|
+
};
|
|
1457
1676
|
}
|
|
1458
|
-
const run = await loadRun(opts.flowDir,
|
|
1677
|
+
const run = await loadRun(opts.flowDir, resolvedRunId);
|
|
1459
1678
|
if (!run) {
|
|
1460
|
-
yield { type: "content", content: `Run not found: ${
|
|
1461
|
-
return { runId:
|
|
1679
|
+
yield { type: "content", content: `Run not found: ${resolvedRunId}\n` };
|
|
1680
|
+
return { runId: resolvedRunId, stage: "error", success: false, reason: "not_found" };
|
|
1462
1681
|
}
|
|
1463
|
-
const manifest = await readManifest(opts.flowDir,
|
|
1682
|
+
const manifest = await readManifest(opts.flowDir, resolvedRunId);
|
|
1464
1683
|
if (!manifest) {
|
|
1465
|
-
yield { type: "content", content: `Manifest missing for ${
|
|
1466
|
-
return { runId:
|
|
1684
|
+
yield { type: "content", content: `Manifest missing for ${resolvedRunId}\n` };
|
|
1685
|
+
return { runId: resolvedRunId, stage: "error", success: false, reason: "manifest_missing" };
|
|
1467
1686
|
}
|
|
1468
1687
|
if (manifest.aborted) {
|
|
1469
|
-
yield { type: "content", content: `Run ${
|
|
1470
|
-
return { runId:
|
|
1688
|
+
yield { type: "content", content: `Run ${resolvedRunId} was aborted; cannot resume.\n` };
|
|
1689
|
+
return { runId: resolvedRunId, stage: "halted", success: false, reason: "aborted" };
|
|
1690
|
+
}
|
|
1691
|
+
// Surface the Resume Digest so the user sees where the run stopped and what
|
|
1692
|
+
// resuming will do — the whole point of giving the digest real content.
|
|
1693
|
+
{
|
|
1694
|
+
const digest = parseResumeDigest(run.state.sections.get("Resume Digest"));
|
|
1695
|
+
if (digest) {
|
|
1696
|
+
yield {
|
|
1697
|
+
type: "content",
|
|
1698
|
+
content: `> Resume Digest — stage: ${digest.stage}${typeof digest.sprintN === "number" ? ` (sprint ${digest.sprintN})` : ""} · next: ${digest.nextAction || "—"}\n`,
|
|
1699
|
+
};
|
|
1700
|
+
}
|
|
1471
1701
|
}
|
|
1472
1702
|
// Detect crashed in-flight sprint: an iterations.md entry without a closing
|
|
1473
1703
|
// Verify line is treated as crashed. Our schema always writes the Verify line
|
|
1474
1704
|
// before returning, so an iteration is "in-flight" iff the file has a Sprint
|
|
1475
1705
|
// heading but no matching Verify field. readIterations skips malformed
|
|
1476
1706
|
// entries — so we mark the highest sprint number as crashed regardless.
|
|
1477
|
-
const iters = await readIterations(opts.flowDir,
|
|
1707
|
+
const iters = await readIterations(opts.flowDir, resolvedRunId);
|
|
1478
1708
|
let nextSprint = iters.length + 1;
|
|
1479
1709
|
if (iters.length > 0) {
|
|
1480
1710
|
const last = iters[iters.length - 1];
|
|
1481
1711
|
if (!last.lastVerifyResult || last.lastVerifyResult === "UNKNOWN") {
|
|
1482
|
-
await markIterationCrashed(opts.flowDir,
|
|
1712
|
+
await markIterationCrashed(opts.flowDir, resolvedRunId, last.sprintN);
|
|
1483
1713
|
nextSprint = last.sprintN; // retry with retryOf metadata
|
|
1484
1714
|
yield {
|
|
1485
1715
|
type: "content",
|
|
@@ -1490,7 +1720,7 @@ async function* runResume(opts) {
|
|
|
1490
1720
|
// Fire EE phase-outcome=resumed (extension landed in 13-05).
|
|
1491
1721
|
try {
|
|
1492
1722
|
fireAndForgetPhaseOutcome({
|
|
1493
|
-
sessionId:
|
|
1723
|
+
sessionId: resolvedRunId,
|
|
1494
1724
|
phaseName: `sprint-${Math.max(1, nextSprint - 1)}`,
|
|
1495
1725
|
outcome: "resumed",
|
|
1496
1726
|
});
|
|
@@ -1499,9 +1729,8 @@ async function* runResume(opts) {
|
|
|
1499
1729
|
/* non-fatal */
|
|
1500
1730
|
}
|
|
1501
1731
|
// Resume into sprint loop with reconstructed history + manifest flags.
|
|
1502
|
-
const productSpec = await loadProductSpec(opts.flowDir, opts.runId, manifest.idea, manifest.stack);
|
|
1503
1732
|
const ctx = {
|
|
1504
|
-
runId:
|
|
1733
|
+
runId: resolvedRunId,
|
|
1505
1734
|
flowDir: opts.flowDir,
|
|
1506
1735
|
idea: manifest.idea,
|
|
1507
1736
|
sessionModelId: opts.sessionModelId,
|
|
@@ -1512,8 +1741,60 @@ async function* runResume(opts) {
|
|
|
1512
1741
|
cwd: opts.cwd,
|
|
1513
1742
|
sessionId: opts.sessionId,
|
|
1514
1743
|
processMessageFn: opts.processMessageFn,
|
|
1744
|
+
runIsolatedTask: opts.runIsolatedTask,
|
|
1515
1745
|
detectVerifyRecipe: opts.detectVerifyRecipe,
|
|
1516
1746
|
};
|
|
1747
|
+
// C-v2 cross-session debate resume — a persisted debate checkpoint means the
|
|
1748
|
+
// council debate was interrupted before it ever produced a spec, so the run
|
|
1749
|
+
// cannot go straight to sprints (loadProductSpec would return an empty stub).
|
|
1750
|
+
// Re-run the council FSM: loop-driver's resume entry skips discovery + the
|
|
1751
|
+
// interview and restores the debate from its checkpoint, then scoping writes
|
|
1752
|
+
// the spec. This mirrors runStart's phase-1 → phase-2 handoff.
|
|
1753
|
+
const runDir = path.join(opts.flowDir, "runs", resolvedRunId);
|
|
1754
|
+
const interruptedDebate = await readDebateCheckpoint(runDir);
|
|
1755
|
+
if (interruptedDebate) {
|
|
1756
|
+
yield {
|
|
1757
|
+
type: "content",
|
|
1758
|
+
content: `\n> Detected an interrupted council debate (round ${interruptedDebate.roundCount + 1}); resuming it before sprints.\n`,
|
|
1759
|
+
};
|
|
1760
|
+
const driverGen = runLoopDriver(ctx);
|
|
1761
|
+
let driverResult;
|
|
1762
|
+
try {
|
|
1763
|
+
while (true) {
|
|
1764
|
+
const { value, done } = await driverGen.next();
|
|
1765
|
+
if (done) {
|
|
1766
|
+
driverResult = value;
|
|
1767
|
+
break;
|
|
1768
|
+
}
|
|
1769
|
+
yield value;
|
|
1770
|
+
}
|
|
1771
|
+
}
|
|
1772
|
+
catch (err) {
|
|
1773
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1774
|
+
yield { type: "error", error: true, content: msg };
|
|
1775
|
+
return { runId: resolvedRunId, stage: "error", success: false, reason: msg };
|
|
1776
|
+
}
|
|
1777
|
+
if (!driverResult?.success || driverResult.stage !== "approved") {
|
|
1778
|
+
return { ...driverResult, runId: resolvedRunId };
|
|
1779
|
+
}
|
|
1780
|
+
// Build the sprint plan now that the spec exists (idempotent — skips when
|
|
1781
|
+
// backlog.json / sprint-plan.json already exist).
|
|
1782
|
+
const resumedSpec = await loadProductSpec(opts.flowDir, resolvedRunId, manifest.idea, manifest.stack);
|
|
1783
|
+
const { sprintCount } = await buildBacklogAndSprintPlan({
|
|
1784
|
+
flowDir: opts.flowDir,
|
|
1785
|
+
runId: resolvedRunId,
|
|
1786
|
+
productSpec: resumedSpec,
|
|
1787
|
+
ctx,
|
|
1788
|
+
sessionModelId: opts.sessionModelId,
|
|
1789
|
+
maxSprints: opts.flags.maxSprints,
|
|
1790
|
+
onChunk: (chunk) => void chunk,
|
|
1791
|
+
});
|
|
1792
|
+
yield {
|
|
1793
|
+
type: "content",
|
|
1794
|
+
content: `\n> Committed: ${sprintCount} sprint${sprintCount === 1 ? "" : "s"} planned. Sprint 1 active.\n`,
|
|
1795
|
+
};
|
|
1796
|
+
}
|
|
1797
|
+
const productSpec = await loadProductSpec(opts.flowDir, resolvedRunId, manifest.idea, manifest.stack);
|
|
1517
1798
|
const roleAssignments = opts.roleAssignments ?? (await resolveRoleAssignments(opts.sessionModelId));
|
|
1518
1799
|
// Subsystem E: phase-orchestrated path (default ON; set MUONROI_PHASE_MODE=0 for legacy).
|
|
1519
1800
|
if (process.env.MUONROI_PHASE_MODE !== "0") {
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import type { StreamChunk } from "../types/index.js";
|
|
2
2
|
import type { DriverContext, DriverResult, Stage } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Clamp a title for the milestone/phase index (F12): truncate at a word
|
|
5
|
+
* boundary when possible and strip trailing punctuation/whitespace so a raw
|
|
6
|
+
* slice can't leave a dangling "(" or a half word. Falls back to a hard slice
|
|
7
|
+
* for a single long token.
|
|
8
|
+
*/
|
|
9
|
+
export declare function clampTitle(raw: string, max: number): string;
|
|
3
10
|
export declare function runLoopDriver(ctx: DriverContext): AsyncGenerator<StreamChunk, DriverResult, unknown>;
|
|
4
11
|
export type { DriverContext, DriverResult, Stage };
|