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
|
@@ -4,7 +4,11 @@
|
|
|
4
4
|
* Serializes messages, extracts preserved blocks, compresses if over budget,
|
|
5
5
|
* then restores preserved blocks into the output.
|
|
6
6
|
*/
|
|
7
|
+
import { generateText } from "ai";
|
|
7
8
|
import { serializeConversation } from "../../orchestrator/compaction.js";
|
|
9
|
+
import { resolveModelRuntime, resolveTemperatureParam, } from "../../providers/runtime.js";
|
|
10
|
+
import { logger } from "../../utils/logger.js";
|
|
11
|
+
import { capCompactionInput } from "./input-guard.js";
|
|
8
12
|
import { extractPreservedBlocks, restorePreservedBlocks } from "./preserve.js";
|
|
9
13
|
/**
|
|
10
14
|
* Compress chat messages within a token budget.
|
|
@@ -12,9 +16,9 @@ import { extractPreservedBlocks, restorePreservedBlocks } from "./preserve.js";
|
|
|
12
16
|
* 1. Serialize messages via serializeConversation().
|
|
13
17
|
* 2. Extract preserved blocks.
|
|
14
18
|
* 3. If under budget, return as-is (with preserved blocks restored).
|
|
15
|
-
* 4. If over budget,
|
|
19
|
+
* 4. If over budget, compress via LLM (if provider given) or truncate, and restore blocks.
|
|
16
20
|
*/
|
|
17
|
-
export async function compressChat(messages, _systemPrompt, tokenBudget,
|
|
21
|
+
export async function compressChat(messages, _systemPrompt, tokenBudget, provider, modelId, customInstructions) {
|
|
18
22
|
const serialized = serializeConversation(messages);
|
|
19
23
|
const { cleaned, blocks } = extractPreservedBlocks(serialized);
|
|
20
24
|
// Estimate tokens of cleaned text
|
|
@@ -28,16 +32,49 @@ export async function compressChat(messages, _systemPrompt, tokenBudget, _provid
|
|
|
28
32
|
tokensAfter: Math.ceil(restored.length / 4),
|
|
29
33
|
};
|
|
30
34
|
}
|
|
31
|
-
// Over budget — truncate to fit budget while keeping preserved blocks
|
|
32
35
|
// Calculate space taken by preserved blocks
|
|
33
36
|
const preservedTokens = blocks.reduce((sum, b) => sum + Math.ceil(b.content.length / 4), 0);
|
|
34
37
|
const availableTokens = Math.max(0, tokenBudget - preservedTokens);
|
|
35
38
|
const availableChars = availableTokens * 4;
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
let compressedContent = cleaned;
|
|
40
|
+
let usedLLM = false;
|
|
41
|
+
if (provider && modelId) {
|
|
42
|
+
try {
|
|
43
|
+
const runtime = resolveModelRuntime(provider, modelId);
|
|
44
|
+
const extraPrompt = customInstructions ? `\n\nUSER FOCUS/INSTRUCTIONS:\n${customInstructions}\n` : "";
|
|
45
|
+
// Guard the compaction INPUT against the model's own context window —
|
|
46
|
+
// compaction fires when history is large, which is exactly when the full
|
|
47
|
+
// serialized text can overflow the summarizer. Keep head + tail.
|
|
48
|
+
const guardedInput = capCompactionInput(cleaned, runtime.modelInfo?.contextWindow ?? 0);
|
|
49
|
+
const result = await generateText({
|
|
50
|
+
model: runtime.model,
|
|
51
|
+
system: "You are an AI context compaction agent. Your job is to heavily summarize a chat history. Keep the core outcomes, the final state, and the technical context. Remove verbose pleasantries, step-by-step thinking, and irrelevant intermediate steps. Do NOT wrap in markdown unless it's code.",
|
|
52
|
+
prompt: `The following conversation exceeds the token budget. Please summarize it concisely, maintaining the essence of what was discussed, what code was written, and what decisions were reached:${extraPrompt}\n\n${guardedInput}`,
|
|
53
|
+
...resolveTemperatureParam(runtime, 0.1),
|
|
54
|
+
});
|
|
55
|
+
compressedContent = result.text.trim();
|
|
56
|
+
usedLLM = true;
|
|
57
|
+
}
|
|
58
|
+
catch (e) {
|
|
59
|
+
// Fall back to deterministic truncation below, but do NOT swallow the
|
|
60
|
+
// reason — a hidden compaction-LLM failure (auth, overflow, provider
|
|
61
|
+
// 400) is exactly what makes "why did compaction do nothing" undebuggable.
|
|
62
|
+
logger.error("orchestrator", "compressChat LLM summarize failed — falling back to truncation", {
|
|
63
|
+
modelId,
|
|
64
|
+
inputChars: cleaned.length,
|
|
65
|
+
message: e?.message,
|
|
66
|
+
stack: e?.stack?.split("\n").slice(0, 3),
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (!usedLLM) {
|
|
71
|
+
// Over budget — truncate to fit budget while keeping preserved blocks
|
|
72
|
+
compressedContent =
|
|
73
|
+
cleaned.length > availableChars
|
|
74
|
+
? `${cleaned.slice(0, availableChars)}\n\n[... ${cleaned.length - availableChars} characters truncated]`
|
|
75
|
+
: cleaned;
|
|
76
|
+
}
|
|
77
|
+
const restored = restorePreservedBlocks(compressedContent, blocks);
|
|
41
78
|
return {
|
|
42
79
|
summary: restored,
|
|
43
80
|
preservedBlocks: blocks,
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Scans for "Decision:", "Decided:", "Fact:", "Constraint:" patterns
|
|
6
6
|
* and content inside <!-- preserve --> blocks.
|
|
7
7
|
*/
|
|
8
|
-
import type
|
|
8
|
+
import { type ModelMessage } from "ai";
|
|
9
9
|
export interface ExtractedDecisions {
|
|
10
10
|
decisions: string[];
|
|
11
11
|
facts: string[];
|
|
@@ -14,10 +14,7 @@ export interface ExtractedDecisions {
|
|
|
14
14
|
/**
|
|
15
15
|
* Extract decisions, facts, and constraints from messages.
|
|
16
16
|
*
|
|
17
|
-
* Scans serialized conversation text for
|
|
18
|
-
*
|
|
19
|
-
* - Lines matching "Fact:" -> facts
|
|
20
|
-
* - Lines matching "Constraint:" -> constraints
|
|
21
|
-
* - All content inside <!-- preserve --> blocks -> decisions (verbatim)
|
|
17
|
+
* Scans serialized conversation text for explicit markers, but if provider
|
|
18
|
+
* and modelId are given, it asks the LLM to intelligently extract them.
|
|
22
19
|
*/
|
|
23
|
-
export declare function extractDecisions(messages: ModelMessage[]): ExtractedDecisions
|
|
20
|
+
export declare function extractDecisions(messages: ModelMessage[], provider?: unknown, modelId?: string, customInstructions?: string): Promise<ExtractedDecisions>;
|
|
@@ -5,7 +5,11 @@
|
|
|
5
5
|
* Scans for "Decision:", "Decided:", "Fact:", "Constraint:" patterns
|
|
6
6
|
* and content inside <!-- preserve --> blocks.
|
|
7
7
|
*/
|
|
8
|
+
import { generateText } from "ai";
|
|
8
9
|
import { serializeConversation } from "../../orchestrator/compaction.js";
|
|
10
|
+
import { resolveModelRuntime, resolveTemperatureParam, } from "../../providers/runtime.js";
|
|
11
|
+
import { logger } from "../../utils/logger.js";
|
|
12
|
+
import { capCompactionInput } from "./input-guard.js";
|
|
9
13
|
import { extractPreservedBlocks } from "./preserve.js";
|
|
10
14
|
const DECISION_RE = /(?:Decision|Decided):\s*(.+)/gi;
|
|
11
15
|
const FACT_RE = /Fact:\s*(.+)/gi;
|
|
@@ -23,13 +27,10 @@ function matchAll(text, re) {
|
|
|
23
27
|
/**
|
|
24
28
|
* Extract decisions, facts, and constraints from messages.
|
|
25
29
|
*
|
|
26
|
-
* Scans serialized conversation text for
|
|
27
|
-
*
|
|
28
|
-
* - Lines matching "Fact:" -> facts
|
|
29
|
-
* - Lines matching "Constraint:" -> constraints
|
|
30
|
-
* - All content inside <!-- preserve --> blocks -> decisions (verbatim)
|
|
30
|
+
* Scans serialized conversation text for explicit markers, but if provider
|
|
31
|
+
* and modelId are given, it asks the LLM to intelligently extract them.
|
|
31
32
|
*/
|
|
32
|
-
export function extractDecisions(messages) {
|
|
33
|
+
export async function extractDecisions(messages, provider, modelId, customInstructions) {
|
|
33
34
|
if (messages.length === 0) {
|
|
34
35
|
return { decisions: [], facts: [], constraints: [] };
|
|
35
36
|
}
|
|
@@ -37,10 +38,49 @@ export function extractDecisions(messages) {
|
|
|
37
38
|
// Extract preserved blocks as decisions
|
|
38
39
|
const { blocks } = extractPreservedBlocks(serialized);
|
|
39
40
|
const preservedDecisions = blocks.map((b) => b.content);
|
|
40
|
-
|
|
41
|
-
const
|
|
42
|
-
const
|
|
43
|
-
|
|
41
|
+
const decisions = [];
|
|
42
|
+
const facts = [];
|
|
43
|
+
const constraints = [];
|
|
44
|
+
let usedLLM = false;
|
|
45
|
+
if (provider && modelId) {
|
|
46
|
+
try {
|
|
47
|
+
const runtime = resolveModelRuntime(provider, modelId);
|
|
48
|
+
const extraPrompt = customInstructions ? `\n\nUSER FOCUS/INSTRUCTIONS:\n${customInstructions}\n` : "";
|
|
49
|
+
// Guard input against the summarizer's context window (see input-guard).
|
|
50
|
+
const guardedInput = capCompactionInput(serialized, runtime.modelInfo?.contextWindow ?? 0);
|
|
51
|
+
const result = await generateText({
|
|
52
|
+
model: runtime.model,
|
|
53
|
+
system: 'You are an AI context compaction agent. Extract all core decisions, technical facts, and project constraints from this conversation. Return strict JSON with { "decisions": string[], "facts": string[], "constraints": string[] }.',
|
|
54
|
+
prompt: `Current conversation messages:\n\n${guardedInput}\n\nExtract decisions, facts, and constraints.${extraPrompt} Return strict JSON ONLY.`,
|
|
55
|
+
...resolveTemperatureParam(runtime, 0.1),
|
|
56
|
+
});
|
|
57
|
+
const match = result.text.match(/\{[\s\S]*\}/);
|
|
58
|
+
if (match) {
|
|
59
|
+
const parsed = JSON.parse(match[0]);
|
|
60
|
+
if (Array.isArray(parsed.decisions))
|
|
61
|
+
decisions.push(...parsed.decisions);
|
|
62
|
+
if (Array.isArray(parsed.facts))
|
|
63
|
+
facts.push(...parsed.facts);
|
|
64
|
+
if (Array.isArray(parsed.constraints))
|
|
65
|
+
constraints.push(...parsed.constraints);
|
|
66
|
+
usedLLM = true;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
catch (e) {
|
|
70
|
+
// Fall back to regex extraction, but log the reason — a swallowed failure
|
|
71
|
+
// here silently degrades /compact to marker-only extraction.
|
|
72
|
+
logger.error("orchestrator", "extractDecisions LLM failed — falling back to regex", {
|
|
73
|
+
modelId,
|
|
74
|
+
message: e?.message,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (!usedLLM) {
|
|
79
|
+
decisions.push(...matchAll(serialized, DECISION_RE));
|
|
80
|
+
facts.push(...matchAll(serialized, FACT_RE));
|
|
81
|
+
constraints.push(...matchAll(serialized, CONSTRAINT_RE));
|
|
82
|
+
}
|
|
83
|
+
decisions.push(...preservedDecisions);
|
|
44
84
|
return { decisions, facts, constraints };
|
|
45
85
|
}
|
|
46
86
|
//# sourceMappingURL=extract.js.map
|
|
@@ -6,6 +6,18 @@
|
|
|
6
6
|
* Snapshot full chat to history/<timestamp>.md before compressing.
|
|
7
7
|
*/
|
|
8
8
|
import type { ModelMessage } from "ai";
|
|
9
|
+
/**
|
|
10
|
+
* Anti-mù for the deliberate (/compact) path — parity with the auto/tool-loop
|
|
11
|
+
* compaction which persists every elided tool output via persistArtifact.
|
|
12
|
+
*
|
|
13
|
+
* deliberateCompact rewrites the whole history into a prose summary, so without
|
|
14
|
+
* this the model loses the ability to `ee_query "tool-artifact id=<id>"` a
|
|
15
|
+
* specific tool result after /compact. We record each tool result into the
|
|
16
|
+
* in-process + disk artifact cache (the tier ee_query reads FIRST, before EE),
|
|
17
|
+
* and fire a best-effort EE extract so cross-session rehydrate also survives.
|
|
18
|
+
* Fail-open: a cache/EE hiccup never blocks the compaction.
|
|
19
|
+
*/
|
|
20
|
+
export declare function recordToolArtifactsForRehydrate(messages: ModelMessage[], projectPath: string): number;
|
|
9
21
|
export interface CompactionResult {
|
|
10
22
|
decisionsExtracted: number;
|
|
11
23
|
tokensBeforeCompress: number;
|
|
@@ -21,4 +33,4 @@ export interface CompactionResult {
|
|
|
21
33
|
* 3. Pass 2: compressChat -> compressed output
|
|
22
34
|
* 4. Return metrics
|
|
23
35
|
*/
|
|
24
|
-
export declare function deliberateCompact(flowDir: string, messages: ModelMessage[], systemPrompt: string, tokenBudget: number, provider?: unknown, modelId?: string): Promise<CompactionResult>;
|
|
36
|
+
export declare function deliberateCompact(flowDir: string, messages: ModelMessage[], systemPrompt: string, tokenBudget: number, provider?: unknown, modelId?: string, customInstructions?: string): Promise<CompactionResult>;
|
|
@@ -7,11 +7,74 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { promises as fs } from "node:fs";
|
|
9
9
|
import * as path from "node:path";
|
|
10
|
+
import { recordArtifact } from "../../ee/artifact-cache.js";
|
|
11
|
+
import { getDefaultEEClient } from "../../ee/intercept.js";
|
|
10
12
|
import { estimateConversationTokens, serializeConversation } from "../../orchestrator/compaction.js";
|
|
11
13
|
import { atomicWriteText } from "../../storage/atomic-io.js";
|
|
14
|
+
import { logger } from "../../utils/logger.js";
|
|
12
15
|
import { readArtifact, writeArtifact } from "../artifact-io.js";
|
|
13
16
|
import { compressChat } from "./compress.js";
|
|
14
17
|
import { extractDecisions } from "./extract.js";
|
|
18
|
+
/**
|
|
19
|
+
* Anti-mù for the deliberate (/compact) path — parity with the auto/tool-loop
|
|
20
|
+
* compaction which persists every elided tool output via persistArtifact.
|
|
21
|
+
*
|
|
22
|
+
* deliberateCompact rewrites the whole history into a prose summary, so without
|
|
23
|
+
* this the model loses the ability to `ee_query "tool-artifact id=<id>"` a
|
|
24
|
+
* specific tool result after /compact. We record each tool result into the
|
|
25
|
+
* in-process + disk artifact cache (the tier ee_query reads FIRST, before EE),
|
|
26
|
+
* and fire a best-effort EE extract so cross-session rehydrate also survives.
|
|
27
|
+
* Fail-open: a cache/EE hiccup never blocks the compaction.
|
|
28
|
+
*/
|
|
29
|
+
export function recordToolArtifactsForRehydrate(messages, projectPath) {
|
|
30
|
+
let recorded = 0;
|
|
31
|
+
for (const msg of messages) {
|
|
32
|
+
if (msg.role !== "tool" || !Array.isArray(msg.content))
|
|
33
|
+
continue;
|
|
34
|
+
for (const part of msg.content) {
|
|
35
|
+
if (part?.type !== "tool-result")
|
|
36
|
+
continue;
|
|
37
|
+
const toolCallId = typeof part.toolCallId === "string" ? part.toolCallId : "";
|
|
38
|
+
if (!toolCallId)
|
|
39
|
+
continue;
|
|
40
|
+
const toolName = typeof part.toolName === "string" ? part.toolName : "";
|
|
41
|
+
// AI SDK v5 tool-result payloads live under `output` (typed) or `result`.
|
|
42
|
+
const payload = part.output ?? part.result;
|
|
43
|
+
const content = typeof payload === "string"
|
|
44
|
+
? payload
|
|
45
|
+
: payload == null
|
|
46
|
+
? ""
|
|
47
|
+
: (() => {
|
|
48
|
+
try {
|
|
49
|
+
return JSON.stringify(payload);
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return String(payload);
|
|
53
|
+
}
|
|
54
|
+
})();
|
|
55
|
+
if (!content)
|
|
56
|
+
continue;
|
|
57
|
+
try {
|
|
58
|
+
recordArtifact(toolCallId, toolName, content);
|
|
59
|
+
recorded++;
|
|
60
|
+
getDefaultEEClient()
|
|
61
|
+
.extract({
|
|
62
|
+
transcript: content.slice(0, 8000),
|
|
63
|
+
projectPath,
|
|
64
|
+
meta: { source: "tool-artifact", toolCallId, toolName, reason: "deliberate-compact" },
|
|
65
|
+
}, AbortSignal.timeout(700))
|
|
66
|
+
.catch(() => { });
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
logger.error("orchestrator", "deliberate-compact artifact record failed", {
|
|
70
|
+
toolCallId,
|
|
71
|
+
message: err?.message,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return recorded;
|
|
77
|
+
}
|
|
15
78
|
/**
|
|
16
79
|
* Orchestrate two-pass deliberate compaction.
|
|
17
80
|
*
|
|
@@ -20,9 +83,13 @@ import { extractDecisions } from "./extract.js";
|
|
|
20
83
|
* 3. Pass 2: compressChat -> compressed output
|
|
21
84
|
* 4. Return metrics
|
|
22
85
|
*/
|
|
23
|
-
export async function deliberateCompact(flowDir, messages, systemPrompt, tokenBudget, provider, modelId) {
|
|
86
|
+
export async function deliberateCompact(flowDir, messages, systemPrompt, tokenBudget, provider, modelId, customInstructions) {
|
|
87
|
+
// Anti-mù parity: persist every tool result to the artifact cache (+ EE)
|
|
88
|
+
// BEFORE we summarize the history away, so the model can still rehydrate a
|
|
89
|
+
// specific tool output via ee_query "tool-artifact id=<id>" after /compact.
|
|
90
|
+
recordToolArtifactsForRehydrate(messages, flowDir);
|
|
24
91
|
// Pass 1: Extract decisions/facts/constraints
|
|
25
|
-
const extracted = extractDecisions(messages);
|
|
92
|
+
const extracted = await extractDecisions(messages, provider, modelId, customInstructions);
|
|
26
93
|
const totalExtracted = extracted.decisions.length + extracted.facts.length + extracted.constraints.length;
|
|
27
94
|
// Append to decisions.md
|
|
28
95
|
if (totalExtracted > 0) {
|
|
@@ -55,7 +122,7 @@ export async function deliberateCompact(flowDir, messages, systemPrompt, tokenBu
|
|
|
55
122
|
// Token estimation before
|
|
56
123
|
const tokensBefore = estimateConversationTokens(systemPrompt, messages);
|
|
57
124
|
// Pass 2: Compress
|
|
58
|
-
const compressed = await compressChat(messages, systemPrompt, tokenBudget, provider, modelId);
|
|
125
|
+
const compressed = await compressChat(messages, systemPrompt, tokenBudget, provider, modelId, customInstructions);
|
|
59
126
|
return {
|
|
60
127
|
decisionsExtracted: totalExtracted,
|
|
61
128
|
tokensBeforeCompress: tokensBefore,
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/flow/compaction/input-guard.ts
|
|
3
|
+
*
|
|
4
|
+
* Guard the INPUT of the deliberate-compaction LLM calls (extractDecisions +
|
|
5
|
+
* compressChat) against context-window overflow.
|
|
6
|
+
*
|
|
7
|
+
* Compaction fires precisely when a conversation has grown large — which is
|
|
8
|
+
* exactly when the full serialized history can EXCEED the compaction model's
|
|
9
|
+
* own context window. Both passes previously sent the whole serialized text as
|
|
10
|
+
* a single prompt with no bound, so on a very long session the summarizing call
|
|
11
|
+
* would fail (or the provider would hard-truncate the tail, dropping the most
|
|
12
|
+
* recent — most relevant — context) and fall back to a dumb truncation.
|
|
13
|
+
*
|
|
14
|
+
* This keeps the HEAD (task setup / early decisions) and the TAIL (most recent
|
|
15
|
+
* work) and elides the middle, so the summarizer always gets a coherent,
|
|
16
|
+
* in-window view of both ends. Pure + dependency-free.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Cap `text` to a safe char budget derived from the compaction model's context
|
|
20
|
+
* window. Returns the text unchanged when it already fits (or the window is
|
|
21
|
+
* unknown and the text is under the floor). Otherwise keeps head+tail and marks
|
|
22
|
+
* the elided middle.
|
|
23
|
+
*/
|
|
24
|
+
export declare function capCompactionInput(text: string, contextWindowTokens: number): string;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/flow/compaction/input-guard.ts
|
|
3
|
+
*
|
|
4
|
+
* Guard the INPUT of the deliberate-compaction LLM calls (extractDecisions +
|
|
5
|
+
* compressChat) against context-window overflow.
|
|
6
|
+
*
|
|
7
|
+
* Compaction fires precisely when a conversation has grown large — which is
|
|
8
|
+
* exactly when the full serialized history can EXCEED the compaction model's
|
|
9
|
+
* own context window. Both passes previously sent the whole serialized text as
|
|
10
|
+
* a single prompt with no bound, so on a very long session the summarizing call
|
|
11
|
+
* would fail (or the provider would hard-truncate the tail, dropping the most
|
|
12
|
+
* recent — most relevant — context) and fall back to a dumb truncation.
|
|
13
|
+
*
|
|
14
|
+
* This keeps the HEAD (task setup / early decisions) and the TAIL (most recent
|
|
15
|
+
* work) and elides the middle, so the summarizer always gets a coherent,
|
|
16
|
+
* in-window view of both ends. Pure + dependency-free.
|
|
17
|
+
*/
|
|
18
|
+
/** Fraction of the model window we allow the compaction INPUT to occupy. */
|
|
19
|
+
const INPUT_WINDOW_FRACTION = 0.55;
|
|
20
|
+
/** Chars-per-token estimate (matches the rest of the compaction code). */
|
|
21
|
+
const CHARS_PER_TOKEN = 4;
|
|
22
|
+
/** Absolute floor so a tiny/unknown window never collapses the input to nothing. */
|
|
23
|
+
const MIN_INPUT_CHARS = 24_000;
|
|
24
|
+
/**
|
|
25
|
+
* Cap `text` to a safe char budget derived from the compaction model's context
|
|
26
|
+
* window. Returns the text unchanged when it already fits (or the window is
|
|
27
|
+
* unknown and the text is under the floor). Otherwise keeps head+tail and marks
|
|
28
|
+
* the elided middle.
|
|
29
|
+
*/
|
|
30
|
+
export function capCompactionInput(text, contextWindowTokens) {
|
|
31
|
+
const windowBudget = contextWindowTokens > 0 ? Math.floor(contextWindowTokens * CHARS_PER_TOKEN * INPUT_WINDOW_FRACTION) : 0;
|
|
32
|
+
const budget = Math.max(MIN_INPUT_CHARS, windowBudget);
|
|
33
|
+
if (text.length <= budget)
|
|
34
|
+
return text;
|
|
35
|
+
// Split the budget between head and tail, reserving room for the marker.
|
|
36
|
+
const headChars = Math.floor(budget * 0.5);
|
|
37
|
+
const tailChars = budget - headChars;
|
|
38
|
+
const head = text.slice(0, headChars);
|
|
39
|
+
const tail = text.slice(text.length - tailChars);
|
|
40
|
+
const elided = text.length - headChars - tailChars;
|
|
41
|
+
return `${head}\n\n[... ${elided} characters of the middle of the conversation elided to fit the compaction model's context window; the head (task setup) and tail (most recent work) are preserved ...]\n\n${tail}`;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=input-guard.js.map
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fold `.planning/` into `.muonroi-flow/planning/` — net-new, non-destructive
|
|
3
|
+
* consolidation migration (Sprint-2 Part A, staged per REV-3 Kill B).
|
|
4
|
+
*
|
|
5
|
+
* WHY staged / copy-only:
|
|
6
|
+
* GSD phases are still CREATED by the external `gsd-tools.cjs` subprocess,
|
|
7
|
+
* which writes to `.planning/` (hardcoded). Until that writer is removed
|
|
8
|
+
* (Part B — deferred), `.planning/` must remain the live tree. So this
|
|
9
|
+
* migration COPIES `.planning/` into the consolidated location and NEVER
|
|
10
|
+
* deletes the original — the read layer (`paths.ts::planningRoot`) keeps
|
|
11
|
+
* preferring `.planning/` while it exists, so there is zero desync risk.
|
|
12
|
+
* Once Part B stops writing `.planning/`, the folded tree becomes the live
|
|
13
|
+
* source transparently via the same read fallback.
|
|
14
|
+
*
|
|
15
|
+
* Guarantees:
|
|
16
|
+
* - Idempotent: guarded by a `.migrated` marker (NOT by directory existence —
|
|
17
|
+
* an empty `.muonroi-flow/planning/` must not make the fold skip forever;
|
|
18
|
+
* see REV-2 Kill #2).
|
|
19
|
+
* - Non-destructive: source `.planning/` is left untouched.
|
|
20
|
+
* - Byte-preserving: every copied file is asserted equal in size to its source.
|
|
21
|
+
*/
|
|
22
|
+
export interface FoldResult {
|
|
23
|
+
/** True when a fold copy was performed this call. */
|
|
24
|
+
migrated: boolean;
|
|
25
|
+
/** Reason a fold was skipped (marker present / no source). */
|
|
26
|
+
skipReason?: "already-migrated" | "no-source";
|
|
27
|
+
/** Number of files copied. */
|
|
28
|
+
filesCopied: number;
|
|
29
|
+
/** Absolute path to the folded planning root. */
|
|
30
|
+
foldedRoot: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Perform the fold. Safe to call repeatedly; returns `{migrated:false}` when the
|
|
34
|
+
* marker is already present or there is no `.planning/` to fold.
|
|
35
|
+
*/
|
|
36
|
+
export declare function foldPlanningIntoFlow(cwd: string): Promise<FoldResult>;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fold `.planning/` into `.muonroi-flow/planning/` — net-new, non-destructive
|
|
3
|
+
* consolidation migration (Sprint-2 Part A, staged per REV-3 Kill B).
|
|
4
|
+
*
|
|
5
|
+
* WHY staged / copy-only:
|
|
6
|
+
* GSD phases are still CREATED by the external `gsd-tools.cjs` subprocess,
|
|
7
|
+
* which writes to `.planning/` (hardcoded). Until that writer is removed
|
|
8
|
+
* (Part B — deferred), `.planning/` must remain the live tree. So this
|
|
9
|
+
* migration COPIES `.planning/` into the consolidated location and NEVER
|
|
10
|
+
* deletes the original — the read layer (`paths.ts::planningRoot`) keeps
|
|
11
|
+
* preferring `.planning/` while it exists, so there is zero desync risk.
|
|
12
|
+
* Once Part B stops writing `.planning/`, the folded tree becomes the live
|
|
13
|
+
* source transparently via the same read fallback.
|
|
14
|
+
*
|
|
15
|
+
* Guarantees:
|
|
16
|
+
* - Idempotent: guarded by a `.migrated` marker (NOT by directory existence —
|
|
17
|
+
* an empty `.muonroi-flow/planning/` must not make the fold skip forever;
|
|
18
|
+
* see REV-2 Kill #2).
|
|
19
|
+
* - Non-destructive: source `.planning/` is left untouched.
|
|
20
|
+
* - Byte-preserving: every copied file is asserted equal in size to its source.
|
|
21
|
+
*/
|
|
22
|
+
import { promises as fs } from "node:fs";
|
|
23
|
+
import * as path from "node:path";
|
|
24
|
+
const FLOW_DIR = ".muonroi-flow";
|
|
25
|
+
const PLANNING_DIR = ".planning";
|
|
26
|
+
const FOLDED_SUBDIR = "planning";
|
|
27
|
+
const MARKER = ".migrated";
|
|
28
|
+
/** Recursively copy a directory, asserting byte-size preservation per file. */
|
|
29
|
+
async function copyTreePreserving(src, dest) {
|
|
30
|
+
let copied = 0;
|
|
31
|
+
const entries = await fs.readdir(src, { withFileTypes: true });
|
|
32
|
+
await fs.mkdir(dest, { recursive: true });
|
|
33
|
+
for (const entry of entries) {
|
|
34
|
+
const from = path.join(src, entry.name);
|
|
35
|
+
const to = path.join(dest, entry.name);
|
|
36
|
+
if (entry.isDirectory()) {
|
|
37
|
+
copied += await copyTreePreserving(from, to);
|
|
38
|
+
}
|
|
39
|
+
else if (entry.isFile()) {
|
|
40
|
+
await fs.copyFile(from, to);
|
|
41
|
+
const [srcStat, destStat] = await Promise.all([fs.stat(from), fs.stat(to)]);
|
|
42
|
+
if (srcStat.size !== destStat.size) {
|
|
43
|
+
throw new Error(`fold-planning: byte mismatch copying ${from} (${srcStat.size} != ${destStat.size})`);
|
|
44
|
+
}
|
|
45
|
+
copied += 1;
|
|
46
|
+
}
|
|
47
|
+
// Symlinks / other node types are intentionally skipped — .planning holds
|
|
48
|
+
// only regular files and dirs; a stray symlink is not worth following.
|
|
49
|
+
}
|
|
50
|
+
return copied;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Perform the fold. Safe to call repeatedly; returns `{migrated:false}` when the
|
|
54
|
+
* marker is already present or there is no `.planning/` to fold.
|
|
55
|
+
*/
|
|
56
|
+
export async function foldPlanningIntoFlow(cwd) {
|
|
57
|
+
const foldedRoot = path.join(cwd, FLOW_DIR, FOLDED_SUBDIR);
|
|
58
|
+
const markerPath = path.join(foldedRoot, MARKER);
|
|
59
|
+
// Marker guard — idempotent regardless of whether the folded dir is empty.
|
|
60
|
+
try {
|
|
61
|
+
await fs.access(markerPath);
|
|
62
|
+
return { migrated: false, skipReason: "already-migrated", filesCopied: 0, foldedRoot };
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
/* marker absent → proceed */
|
|
66
|
+
}
|
|
67
|
+
const source = path.join(cwd, PLANNING_DIR);
|
|
68
|
+
try {
|
|
69
|
+
const st = await fs.stat(source);
|
|
70
|
+
if (!st.isDirectory()) {
|
|
71
|
+
return { migrated: false, skipReason: "no-source", filesCopied: 0, foldedRoot };
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return { migrated: false, skipReason: "no-source", filesCopied: 0, foldedRoot };
|
|
76
|
+
}
|
|
77
|
+
const filesCopied = await copyTreePreserving(source, foldedRoot);
|
|
78
|
+
// Stamp the marker LAST so a crash mid-copy leaves no false "migrated" flag —
|
|
79
|
+
// the next call re-copies (copyFile overwrites, byte-assert still holds).
|
|
80
|
+
await fs.writeFile(markerPath, JSON.stringify({ migratedFrom: PLANNING_DIR, filesCopied, note: "copy-only; original left in place" }, null, 2), "utf8");
|
|
81
|
+
return { migrated: true, filesCopied, foldedRoot };
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=fold-planning.js.map
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Milestone → Phase → Run hierarchy for the Product Ideal Loop.
|
|
3
|
+
*
|
|
4
|
+
* Sprint-2 Part A (full plan, item 2 of the deferred list). Built as an ADDITIVE
|
|
5
|
+
* INDEX LAYER on top of `runs/<runId>/` (per REV-3 Kill B / REV-2 Kill #7): it
|
|
6
|
+
* groups runs under phases under milestones for navigation and cross-run memory,
|
|
7
|
+
* but does NOT reroute the numeric ROADMAP phases that phase-sync depends on. A
|
|
8
|
+
* phase here simply *references* the run IDs executed under it; the run
|
|
9
|
+
* artifacts remain the source of truth for sprint/verify state.
|
|
10
|
+
*
|
|
11
|
+
* .muonroi-flow/milestones/<mid>/milestone.json ← canonical record (read)
|
|
12
|
+
* .muonroi-flow/milestones/<mid>/milestone.md ← human-reviewable render
|
|
13
|
+
* .muonroi-flow/milestones/<mid>/phases/<pid>/phase.json
|
|
14
|
+
* .muonroi-flow/milestones/<mid>/phases/<pid>/phase.md
|
|
15
|
+
*
|
|
16
|
+
* The active milestone/phase pointers live in the top-level `state.md`
|
|
17
|
+
* ("Active Milestone" / "Active Phase" sections), alongside "Active Run".
|
|
18
|
+
*
|
|
19
|
+
* Records are JSON for reliable machine reads; the paired `.md` is a rendered
|
|
20
|
+
* summary only (never parsed back). Writes are atomic. Reads are tolerant: a
|
|
21
|
+
* missing/corrupt record returns null, never throws.
|
|
22
|
+
*/
|
|
23
|
+
export interface MilestoneRecord {
|
|
24
|
+
/** Sortable slug id, e.g. "m01-native-state". */
|
|
25
|
+
id: string;
|
|
26
|
+
/** Human title. */
|
|
27
|
+
title: string;
|
|
28
|
+
/** One-line goal / outcome the milestone delivers. */
|
|
29
|
+
goal: string;
|
|
30
|
+
/** Ordinal (1-based) — mirrors the numeric prefix in the id for stable sort. */
|
|
31
|
+
ordinal: number;
|
|
32
|
+
/** lifecycle status. */
|
|
33
|
+
status: "active" | "done" | "archived";
|
|
34
|
+
/** ISO creation timestamp. */
|
|
35
|
+
createdAt: string;
|
|
36
|
+
/** ISO last-update timestamp. */
|
|
37
|
+
updatedAt: string;
|
|
38
|
+
}
|
|
39
|
+
export interface PhaseRecord {
|
|
40
|
+
/** Sortable slug id, e.g. "p01-scoping". */
|
|
41
|
+
id: string;
|
|
42
|
+
/** Parent milestone id. */
|
|
43
|
+
milestoneId: string;
|
|
44
|
+
/** Human title. */
|
|
45
|
+
title: string;
|
|
46
|
+
/** One-line goal. */
|
|
47
|
+
goal: string;
|
|
48
|
+
/** Ordinal (1-based) within the milestone. */
|
|
49
|
+
ordinal: number;
|
|
50
|
+
/** lifecycle status. */
|
|
51
|
+
status: "active" | "done" | "archived";
|
|
52
|
+
/** Run IDs executed under this phase (the index link; runs stay canonical). */
|
|
53
|
+
runIds: string[];
|
|
54
|
+
/** ISO creation timestamp. */
|
|
55
|
+
createdAt: string;
|
|
56
|
+
/** ISO last-update timestamp. */
|
|
57
|
+
updatedAt: string;
|
|
58
|
+
}
|
|
59
|
+
export declare const MILESTONES_DIR = "milestones";
|
|
60
|
+
/** List all milestones, sorted by ordinal ascending. */
|
|
61
|
+
export declare function listMilestones(flowDir: string): Promise<MilestoneRecord[]>;
|
|
62
|
+
export declare function loadMilestone(flowDir: string, milestoneId: string): Promise<MilestoneRecord | null>;
|
|
63
|
+
/**
|
|
64
|
+
* Create a milestone. `nowIso` is injected (never Date.now here) so callers
|
|
65
|
+
* control the clock and tests stay deterministic. Ordinal is next-highest+1.
|
|
66
|
+
*/
|
|
67
|
+
export declare function createMilestone(flowDir: string, input: {
|
|
68
|
+
title: string;
|
|
69
|
+
goal?: string;
|
|
70
|
+
}, nowIso: string): Promise<MilestoneRecord>;
|
|
71
|
+
export declare function updateMilestone(flowDir: string, milestoneId: string, patch: Partial<Pick<MilestoneRecord, "title" | "goal" | "status">>, nowIso: string): Promise<MilestoneRecord | null>;
|
|
72
|
+
/** List phases under a milestone, sorted by ordinal ascending. */
|
|
73
|
+
export declare function listPhases(flowDir: string, milestoneId: string): Promise<PhaseRecord[]>;
|
|
74
|
+
export declare function loadPhase(flowDir: string, milestoneId: string, phaseId: string): Promise<PhaseRecord | null>;
|
|
75
|
+
export declare function createPhase(flowDir: string, milestoneId: string, input: {
|
|
76
|
+
title: string;
|
|
77
|
+
goal?: string;
|
|
78
|
+
runId?: string;
|
|
79
|
+
}, nowIso: string): Promise<PhaseRecord>;
|
|
80
|
+
export declare function updatePhase(flowDir: string, milestoneId: string, phaseId: string, patch: Partial<Pick<PhaseRecord, "title" | "goal" | "status">>, nowIso: string): Promise<PhaseRecord | null>;
|
|
81
|
+
/** Link a run to a phase (idempotent — no duplicate run ids). */
|
|
82
|
+
export declare function attachRunToPhase(flowDir: string, milestoneId: string, phaseId: string, runId: string, nowIso: string): Promise<PhaseRecord | null>;
|
|
83
|
+
/**
|
|
84
|
+
* Find the milestone+phase a run is already indexed under, scanning every
|
|
85
|
+
* milestone. Returns null when the run is not yet linked anywhere. Used to keep
|
|
86
|
+
* scoping wiring idempotent across `/ideal resume` (the scoping stage re-runs).
|
|
87
|
+
*/
|
|
88
|
+
export declare function findPhaseForRun(flowDir: string, runId: string): Promise<{
|
|
89
|
+
milestoneId: string;
|
|
90
|
+
phaseId: string;
|
|
91
|
+
} | null>;
|
|
92
|
+
/**
|
|
93
|
+
* Idempotently place a run in the hierarchy and mark it active. First call for a
|
|
94
|
+
* run creates (or reuses the active) milestone, opens a phase for the run, links
|
|
95
|
+
* it, and points the active-milestone/active-phase pointers at it. Subsequent
|
|
96
|
+
* calls (resume) are no-ops that just re-assert the pointers.
|
|
97
|
+
*
|
|
98
|
+
* The milestone groups an idea/product; the phase is one scoped iteration under
|
|
99
|
+
* it. This is purely an INDEX over `runs/<runId>/` — it never moves or rewrites
|
|
100
|
+
* run artifacts, and the numeric ROADMAP phases that phase-sync reads are
|
|
101
|
+
* untouched.
|
|
102
|
+
*/
|
|
103
|
+
export declare function ensureRunScoped(flowDir: string, input: {
|
|
104
|
+
runId: string;
|
|
105
|
+
milestoneTitle: string;
|
|
106
|
+
milestoneGoal?: string;
|
|
107
|
+
phaseTitle: string;
|
|
108
|
+
phaseGoal?: string;
|
|
109
|
+
}, nowIso: string): Promise<{
|
|
110
|
+
milestoneId: string;
|
|
111
|
+
phaseId: string;
|
|
112
|
+
}>;
|
|
113
|
+
/**
|
|
114
|
+
* One-time backfill: index any `runs/<id>/` not yet linked to a phase under a
|
|
115
|
+
* synthetic `m00-legacy` milestone (one phase per orphan run). Idempotent — runs
|
|
116
|
+
* already indexed are skipped, and re-running adds only newly-orphaned runs.
|
|
117
|
+
* Returns the number of runs newly indexed.
|
|
118
|
+
*
|
|
119
|
+
* `m00` (ordinal 0) sorts before any real milestone so legacy work stays visible
|
|
120
|
+
* but out of the way. The clock is injected for deterministic tests.
|
|
121
|
+
*/
|
|
122
|
+
export declare function migrateLegacyRuns(flowDir: string, nowIso: string): Promise<number>;
|
|
123
|
+
export interface ActivePointer {
|
|
124
|
+
milestoneId: string | null;
|
|
125
|
+
phaseId: string | null;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* F8 — the active milestone/phase are DERIVED from the single canonical focus,
|
|
129
|
+
* the active run, via the hierarchy index; they are NOT separately persisted.
|
|
130
|
+
*
|
|
131
|
+
* Previously `state.md` carried independent `Active Run` (set for chat-runs) and
|
|
132
|
+
* `Active Milestone`/`Active Phase` (set by `ensureRunScoped` for product-runs)
|
|
133
|
+
* pointers that routinely drifted out of sync — `/ideal` never updated `Active
|
|
134
|
+
* Run`, so it pointed at a stale skeleton run while the milestone/phase pointed
|
|
135
|
+
* at the product run. Council decision (5/5): collapse to one truth. Whatever run
|
|
136
|
+
* is active, its phase (and that phase's milestone) is the active one; a
|
|
137
|
+
* chat/skeleton run that was never indexed resolves to nulls.
|
|
138
|
+
*/
|
|
139
|
+
export declare function getActivePointer(flowDir: string): Promise<ActivePointer>;
|
|
140
|
+
/**
|
|
141
|
+
* Blank the legacy `Active Milestone`/`Active Phase` sections if an old
|
|
142
|
+
* `state.md` still carries them, so a stale value can never be mistaken for the
|
|
143
|
+
* (now derived) truth. One-time, idempotent; no-op when the sections are absent
|
|
144
|
+
* or already empty. Legacy files are otherwise read-as-junk — never migrated.
|
|
145
|
+
*/
|
|
146
|
+
export declare function clearLegacyActivePointerSections(flowDir: string): Promise<void>;
|