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
package/dist/src/ee/client.js
CHANGED
|
@@ -1,6 +1,29 @@
|
|
|
1
|
+
import * as os from "node:os";
|
|
1
2
|
import { classifyEeError, logEeFailure } from "../utils/ee-logger.js";
|
|
3
|
+
import { redactor } from "../utils/redactor.js";
|
|
2
4
|
import { drainQueue, enqueue } from "./offline-queue.js";
|
|
3
5
|
const DEFAULT_BASE = "http://localhost:8082";
|
|
6
|
+
function relativizePath(p) {
|
|
7
|
+
if (!p)
|
|
8
|
+
return p;
|
|
9
|
+
let normalized = p.replace(/\\/g, "/");
|
|
10
|
+
const home = os.homedir().replace(/\\/g, "/");
|
|
11
|
+
const normalizedHome = home.endsWith("/") ? home.slice(0, -1) : home;
|
|
12
|
+
if (normalized.startsWith(normalizedHome)) {
|
|
13
|
+
normalized = "~" + normalized.slice(normalizedHome.length);
|
|
14
|
+
}
|
|
15
|
+
return normalized;
|
|
16
|
+
}
|
|
17
|
+
function redactPayload(payload) {
|
|
18
|
+
if (!payload)
|
|
19
|
+
return payload;
|
|
20
|
+
try {
|
|
21
|
+
return JSON.parse(redactor.redact(JSON.stringify(payload)));
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return payload;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
4
27
|
/**
|
|
5
28
|
* Intercept timeout budget.
|
|
6
29
|
* Local: 100ms (localhost p99 is <10ms, 100ms catches wedged server).
|
|
@@ -195,8 +218,12 @@ export function createEEClient(opts = {}) {
|
|
|
195
218
|
}
|
|
196
219
|
},
|
|
197
220
|
async intercept(req) {
|
|
221
|
+
const redactedReq = {
|
|
222
|
+
...req,
|
|
223
|
+
cwd: relativizePath(req.cwd),
|
|
224
|
+
};
|
|
198
225
|
// 1. Cache hit — skip network entirely
|
|
199
|
-
const cached = getCached(
|
|
226
|
+
const cached = getCached(redactedReq);
|
|
200
227
|
if (cached)
|
|
201
228
|
return cached;
|
|
202
229
|
// 2. Circuit breaker — skip if open
|
|
@@ -207,7 +234,7 @@ export function createEEClient(opts = {}) {
|
|
|
207
234
|
const resp = await f(`${baseUrl}/api/intercept`, {
|
|
208
235
|
method: "POST",
|
|
209
236
|
headers: headers(),
|
|
210
|
-
body: JSON.stringify({ ...
|
|
237
|
+
body: JSON.stringify(redactPayload({ ...redactedReq, skipRoute: true })),
|
|
211
238
|
signal: AbortSignal.timeout(interceptTimeoutMs),
|
|
212
239
|
});
|
|
213
240
|
if (!resp.ok) {
|
|
@@ -221,7 +248,7 @@ export function createEEClient(opts = {}) {
|
|
|
221
248
|
const raw = (await resp.json());
|
|
222
249
|
const result = normalizeInterceptResponse(raw);
|
|
223
250
|
recordCircuitSuccess({ fetchImpl: f, headers: headers(), baseUrl });
|
|
224
|
-
setCached(
|
|
251
|
+
setCached(redactedReq, result);
|
|
225
252
|
return result;
|
|
226
253
|
}
|
|
227
254
|
catch (err) {
|
|
@@ -231,10 +258,14 @@ export function createEEClient(opts = {}) {
|
|
|
231
258
|
}
|
|
232
259
|
},
|
|
233
260
|
async posttool(payload) {
|
|
261
|
+
const redactedPayload = {
|
|
262
|
+
...payload,
|
|
263
|
+
cwd: relativizePath(payload.cwd),
|
|
264
|
+
};
|
|
234
265
|
await f(`${baseUrl}/api/posttool`, {
|
|
235
266
|
method: "POST",
|
|
236
267
|
headers: headers(),
|
|
237
|
-
body: JSON.stringify(
|
|
268
|
+
body: JSON.stringify(redactPayload(redactedPayload)),
|
|
238
269
|
signal: AbortSignal.timeout(postToolTimeoutMs),
|
|
239
270
|
}).catch((err) => {
|
|
240
271
|
logEeFailure("client.posttool", classifyEeError(err), err);
|
|
@@ -243,6 +274,10 @@ export function createEEClient(opts = {}) {
|
|
|
243
274
|
},
|
|
244
275
|
async routeModel(req, signal) {
|
|
245
276
|
try {
|
|
277
|
+
const redactedReq = {
|
|
278
|
+
...req,
|
|
279
|
+
cwd: relativizePath(req.cwd),
|
|
280
|
+
};
|
|
246
281
|
const ctrl = new AbortController();
|
|
247
282
|
const t = setTimeout(() => ctrl.abort(), 250);
|
|
248
283
|
if (signal)
|
|
@@ -250,7 +285,7 @@ export function createEEClient(opts = {}) {
|
|
|
250
285
|
const resp = await f(`${baseUrl}/api/route-model`, {
|
|
251
286
|
method: "POST",
|
|
252
287
|
headers: headers(),
|
|
253
|
-
body: JSON.stringify(
|
|
288
|
+
body: JSON.stringify(redactPayload(redactedReq)),
|
|
254
289
|
signal: ctrl.signal,
|
|
255
290
|
});
|
|
256
291
|
clearTimeout(t);
|
|
@@ -264,6 +299,10 @@ export function createEEClient(opts = {}) {
|
|
|
264
299
|
},
|
|
265
300
|
async coldRoute(req, signal) {
|
|
266
301
|
try {
|
|
302
|
+
const redactedReq = {
|
|
303
|
+
...req,
|
|
304
|
+
cwd: relativizePath(req.cwd),
|
|
305
|
+
};
|
|
267
306
|
const ctrl = new AbortController();
|
|
268
307
|
const t = setTimeout(() => ctrl.abort(), 1000);
|
|
269
308
|
if (signal)
|
|
@@ -271,7 +310,7 @@ export function createEEClient(opts = {}) {
|
|
|
271
310
|
const resp = await f(`${baseUrl}/api/cold-route`, {
|
|
272
311
|
method: "POST",
|
|
273
312
|
headers: headers(),
|
|
274
|
-
body: JSON.stringify(
|
|
313
|
+
body: JSON.stringify(redactPayload(redactedReq)),
|
|
275
314
|
signal: ctrl.signal,
|
|
276
315
|
});
|
|
277
316
|
clearTimeout(t);
|
|
@@ -284,13 +323,14 @@ export function createEEClient(opts = {}) {
|
|
|
284
323
|
}
|
|
285
324
|
},
|
|
286
325
|
feedback(payload) {
|
|
326
|
+
const redactedPayload = redactPayload(payload);
|
|
287
327
|
f(`${baseUrl}/api/feedback`, {
|
|
288
328
|
method: "POST",
|
|
289
329
|
headers: headers(),
|
|
290
|
-
body: JSON.stringify(
|
|
330
|
+
body: JSON.stringify(redactedPayload),
|
|
291
331
|
}).catch((err) => {
|
|
292
332
|
logEeFailure("client.feedback", classifyEeError(err), err);
|
|
293
|
-
void enqueue({ endpoint: "/api/feedback", body:
|
|
333
|
+
void enqueue({ endpoint: "/api/feedback", body: redactedPayload, enqueuedAt: Date.now() });
|
|
294
334
|
});
|
|
295
335
|
},
|
|
296
336
|
/**
|
|
@@ -300,7 +340,7 @@ export function createEEClient(opts = {}) {
|
|
|
300
340
|
* stale_rule). Fire-and-forget; queued offline like standard feedback.
|
|
301
341
|
*/
|
|
302
342
|
noiseFeedback(payload) {
|
|
303
|
-
const body = { ...payload, verdict: "IRRELEVANT" };
|
|
343
|
+
const body = redactPayload({ ...payload, verdict: "IRRELEVANT" });
|
|
304
344
|
f(`${baseUrl}/api/feedback`, {
|
|
305
345
|
method: "POST",
|
|
306
346
|
headers: headers(),
|
|
@@ -322,10 +362,11 @@ export function createEEClient(opts = {}) {
|
|
|
322
362
|
},
|
|
323
363
|
// ─── P0: Route feedback (fire-and-forget) ─────────────────────────────────
|
|
324
364
|
routeFeedback(payload) {
|
|
365
|
+
const redactedPayload = redactPayload(payload);
|
|
325
366
|
f(`${baseUrl}/api/route-feedback`, {
|
|
326
367
|
method: "POST",
|
|
327
368
|
headers: headers(),
|
|
328
|
-
body: JSON.stringify(
|
|
369
|
+
body: JSON.stringify(redactedPayload),
|
|
329
370
|
}).catch((err) => {
|
|
330
371
|
logEeFailure("client.routeFeedback", classifyEeError(err), err);
|
|
331
372
|
/* fire-and-forget */
|
|
@@ -333,41 +374,54 @@ export function createEEClient(opts = {}) {
|
|
|
333
374
|
},
|
|
334
375
|
// ─── P1: Prompt-stale reconciliation ──────────────────────────────────────
|
|
335
376
|
async promptStale(req) {
|
|
377
|
+
const redactedReq = redactPayload({
|
|
378
|
+
...req,
|
|
379
|
+
nextPromptMeta: req.nextPromptMeta
|
|
380
|
+
? {
|
|
381
|
+
...req.nextPromptMeta,
|
|
382
|
+
cwd: req.nextPromptMeta.cwd ? relativizePath(req.nextPromptMeta.cwd) : undefined,
|
|
383
|
+
}
|
|
384
|
+
: undefined,
|
|
385
|
+
});
|
|
336
386
|
try {
|
|
337
387
|
const resp = await f(`${baseUrl}/api/prompt-stale`, {
|
|
338
388
|
method: "POST",
|
|
339
389
|
headers: headers(),
|
|
340
|
-
body: JSON.stringify(
|
|
390
|
+
body: JSON.stringify(redactedReq),
|
|
341
391
|
signal: AbortSignal.timeout(2000),
|
|
342
392
|
});
|
|
343
393
|
if (!resp.ok) {
|
|
344
|
-
void enqueue({ endpoint: "/api/prompt-stale", body:
|
|
394
|
+
void enqueue({ endpoint: "/api/prompt-stale", body: redactedReq, enqueuedAt: Date.now() });
|
|
345
395
|
return null;
|
|
346
396
|
}
|
|
347
397
|
return (await resp.json());
|
|
348
398
|
}
|
|
349
399
|
catch {
|
|
350
|
-
void enqueue({ endpoint: "/api/prompt-stale", body:
|
|
400
|
+
void enqueue({ endpoint: "/api/prompt-stale", body: redactedReq, enqueuedAt: Date.now() });
|
|
351
401
|
return null;
|
|
352
402
|
}
|
|
353
403
|
},
|
|
354
404
|
// ─── P1: Session extract ──────────────────────────────────────────────────
|
|
355
405
|
async extract(req, signal) {
|
|
406
|
+
const redactedReq = redactPayload({
|
|
407
|
+
...req,
|
|
408
|
+
projectPath: relativizePath(req.projectPath),
|
|
409
|
+
});
|
|
356
410
|
try {
|
|
357
411
|
const resp = await f(`${baseUrl}/api/extract`, {
|
|
358
412
|
method: "POST",
|
|
359
413
|
headers: headers(),
|
|
360
|
-
body: JSON.stringify(
|
|
414
|
+
body: JSON.stringify(redactedReq),
|
|
361
415
|
signal: signal ?? AbortSignal.timeout(10_000),
|
|
362
416
|
});
|
|
363
417
|
if (!resp.ok) {
|
|
364
|
-
void enqueue({ endpoint: "/api/extract", body:
|
|
418
|
+
void enqueue({ endpoint: "/api/extract", body: redactedReq, enqueuedAt: Date.now() });
|
|
365
419
|
return null;
|
|
366
420
|
}
|
|
367
421
|
return (await resp.json());
|
|
368
422
|
}
|
|
369
423
|
catch {
|
|
370
|
-
void enqueue({ endpoint: "/api/extract", body:
|
|
424
|
+
void enqueue({ endpoint: "/api/extract", body: redactedReq, enqueuedAt: Date.now() });
|
|
371
425
|
return null;
|
|
372
426
|
}
|
|
373
427
|
},
|
|
@@ -527,11 +581,18 @@ export function createEEClient(opts = {}) {
|
|
|
527
581
|
async recall(query, opts = {}) {
|
|
528
582
|
const body = { query };
|
|
529
583
|
if (opts.cwd)
|
|
530
|
-
body.cwd = opts.cwd;
|
|
584
|
+
body.cwd = relativizePath(opts.cwd);
|
|
531
585
|
if (opts.project)
|
|
532
586
|
body.project_slug = opts.project;
|
|
533
587
|
if (opts.sourceSession)
|
|
534
588
|
body.sourceSession = opts.sourceSession;
|
|
589
|
+
// Per-stance recall weighting (item 3): forward the council stance/role so
|
|
590
|
+
// the server weights recall collections toward what this stance cares about.
|
|
591
|
+
if (opts.stance)
|
|
592
|
+
body.stance = opts.stance;
|
|
593
|
+
if (opts.role)
|
|
594
|
+
body.role = opts.role;
|
|
595
|
+
const redactedBody = redactPayload(body);
|
|
535
596
|
// Server bounds the recall pipeline at ~8s internally (handleRecall's
|
|
536
597
|
// AbortSignal.timeout(8000)); embedding + 3-leg search + network push real
|
|
537
598
|
// wall-time past that (measured ~9.3s on a warm VPS). An 8s client ceiling
|
|
@@ -542,7 +603,7 @@ export function createEEClient(opts = {}) {
|
|
|
542
603
|
const resp = await f(`${baseUrl}/api/recall`, {
|
|
543
604
|
method: "POST",
|
|
544
605
|
headers: headers(),
|
|
545
|
-
body: JSON.stringify(
|
|
606
|
+
body: JSON.stringify(redactedBody),
|
|
546
607
|
signal: opts.signal ?? AbortSignal.timeout(timeoutMs),
|
|
547
608
|
});
|
|
548
609
|
if (!resp.ok)
|
|
@@ -588,6 +649,8 @@ export function createEEClient(opts = {}) {
|
|
|
588
649
|
body.maxTokens = options.maxTokens;
|
|
589
650
|
if (options.provider)
|
|
590
651
|
body.provider = options.provider;
|
|
652
|
+
if (options.useExtractModel)
|
|
653
|
+
body.useExtractModel = true;
|
|
591
654
|
}
|
|
592
655
|
const resp = await f(`${baseUrl}/api/brain`, {
|
|
593
656
|
method: "POST",
|
|
@@ -10,9 +10,7 @@
|
|
|
10
10
|
* recover lessons from sessions that pre-date the transcript-emit feature.
|
|
11
11
|
* Idempotent: re-running overwrites the same per-session JSONL.
|
|
12
12
|
*/
|
|
13
|
-
import
|
|
14
|
-
import os from "node:os";
|
|
15
|
-
import path from "node:path";
|
|
13
|
+
import { getDatabase } from "../storage/db.js";
|
|
16
14
|
import { emitTranscriptToDisk, getEmitRoot } from "./transcript-emit.js";
|
|
17
15
|
async function openDb(dbPath) {
|
|
18
16
|
// Prefer better-sqlite3 (sync), fall back to bun:sqlite when running under Bun.
|
|
@@ -52,17 +50,15 @@ export async function exportTranscripts(opts = {}) {
|
|
|
52
50
|
const maxAgeDays = opts.maxAgeDays ?? 30;
|
|
53
51
|
const minMessages = opts.minMessages ?? 4;
|
|
54
52
|
const dryRun = opts.dryRun ?? false;
|
|
55
|
-
const
|
|
56
|
-
if (!fs.existsSync(dbPath)) {
|
|
57
|
-
throw new Error(`muonroi.db not found at ${dbPath}`);
|
|
58
|
-
}
|
|
59
|
-
const db = await openDb(dbPath);
|
|
53
|
+
const db = opts.dbOverride ?? getDatabase();
|
|
60
54
|
try {
|
|
61
55
|
const cutoff = Date.now() - maxAgeDays * 86400_000;
|
|
62
56
|
const cutoffIso = new Date(cutoff).toISOString();
|
|
63
57
|
// Pull sessions touched in window. cwd_last is the cwd at session-end —
|
|
64
58
|
// critical for EE scope detection so framework/lang resolve correctly.
|
|
65
|
-
const sessions = db
|
|
59
|
+
const sessions = db
|
|
60
|
+
.prepare(`SELECT id, updated_at, cwd_last FROM sessions WHERE updated_at >= '${cutoffIso}' ORDER BY updated_at DESC`)
|
|
61
|
+
.all();
|
|
66
62
|
const out = {
|
|
67
63
|
totalSessions: sessions.length,
|
|
68
64
|
written: 0,
|
|
@@ -71,7 +67,9 @@ export async function exportTranscripts(opts = {}) {
|
|
|
71
67
|
outputRoot: getEmitRoot(),
|
|
72
68
|
};
|
|
73
69
|
for (const s of sessions) {
|
|
74
|
-
const rows = db
|
|
70
|
+
const rows = db
|
|
71
|
+
.prepare(`SELECT session_id, seq, role, message_json FROM messages WHERE session_id = '${s.id.replace(/'/g, "''")}' ORDER BY seq ASC`)
|
|
72
|
+
.all();
|
|
75
73
|
if (rows.length === 0) {
|
|
76
74
|
out.skippedEmpty++;
|
|
77
75
|
continue;
|
|
@@ -47,9 +47,38 @@ export async function extractSession(messages, projectPath, source, sessionId) {
|
|
|
47
47
|
getDefaultEEClient()
|
|
48
48
|
.evolve("post-extract")
|
|
49
49
|
.catch(() => { });
|
|
50
|
+
// WRITE arm of the who-am-i loop — fire-and-forget. Mine the user's working style from
|
|
51
|
+
// this transcript and persist it to experience-behavioral, which who-am-i-brain reads
|
|
52
|
+
// back next session (READ arm). Deliberately NOT awaited: the classify is a ~9s brain
|
|
53
|
+
// call and must not block cli-exit (same rationale as the async extract). It completes on
|
|
54
|
+
// cli-clear (process stays alive) and is best-effort on cli-exit — style converges over
|
|
55
|
+
// sessions, so a missed teardown is harmless. Fail-open, gated behind its own flag.
|
|
56
|
+
void writeStyleSignalsFireAndForget(transcript);
|
|
50
57
|
}
|
|
51
58
|
catch {
|
|
52
59
|
// D-05: swallow all errors silently
|
|
53
60
|
}
|
|
54
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* Fire-and-forget bridge from extractSession into the style WRITE arm. Kept separate so the
|
|
64
|
+
* bridge/search imports stay lazy (only paid when a real session ends) and so every failure
|
|
65
|
+
* mode — flag off, EE unreachable, classifier null, write error — degrades to a no-op.
|
|
66
|
+
*/
|
|
67
|
+
async function writeStyleSignalsFireAndForget(transcript) {
|
|
68
|
+
try {
|
|
69
|
+
const { isStyleExtractEnabled, writeStyleSignals } = await import("./extract-style.js");
|
|
70
|
+
if (!isStyleExtractEnabled())
|
|
71
|
+
return;
|
|
72
|
+
const { classifyViaBrain } = await import("./bridge.js");
|
|
73
|
+
const { writeExperienceEE } = await import("./search.js");
|
|
74
|
+
// No projectSlug: working style is a cross-repo property of the user, so style rules are
|
|
75
|
+
// written GLOBAL (unscoped) — who-am-i-brain searches experience-behavioral broadly and a
|
|
76
|
+
// repo-scoped style rule would be needlessly narrow. (Contrast the technical-lesson extract,
|
|
77
|
+
// which IS repo-scoped because a bug fix is repo-specific.)
|
|
78
|
+
await writeStyleSignals({ classifyViaBrain, writeExperience: writeExperienceEE }, transcript);
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
// swallow — style extraction is strictly best-effort
|
|
82
|
+
}
|
|
83
|
+
}
|
|
55
84
|
//# sourceMappingURL=extract-session.js.map
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { WriteExperienceResult } from "./search.js";
|
|
2
|
+
/** Feature flag — default ON, opt out with MUONROI_STYLE_EXTRACT=0. */
|
|
3
|
+
export declare function isStyleExtractEnabled(): boolean;
|
|
4
|
+
/**
|
|
5
|
+
* PURE: build the style-mining prompt. Asks the brain to emit 0..N natural-language style
|
|
6
|
+
* rules about the USER (never the task), each standalone and reusable as future guidance,
|
|
7
|
+
* with a self-reported confidence. Emitting NOTHING when the transcript shows no clear style
|
|
8
|
+
* is explicitly the right answer — we would rather miss a session than pollute the brain.
|
|
9
|
+
*/
|
|
10
|
+
export declare function buildStyleExtractPrompt(transcript: string): string;
|
|
11
|
+
export interface StyleRule {
|
|
12
|
+
rule: string;
|
|
13
|
+
confidence: number;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* PURE: coerce a brain reply (JSON string, fenced block, or already-parsed object) into a
|
|
17
|
+
* gated list of style rules. Applies the confidence floor, length bounds, dedup by normalized
|
|
18
|
+
* text, and the per-session cap. Returns [] when nothing usable survives (fail-open).
|
|
19
|
+
*/
|
|
20
|
+
export declare function parseStyleRules(raw: unknown): StyleRule[];
|
|
21
|
+
/**
|
|
22
|
+
* PURE: a stable title for a style rule so repeated sessions MERGE server-side instead of
|
|
23
|
+
* accreting near-duplicates. Derived deterministically from the rule text (lowercased, first
|
|
24
|
+
* few significant words) — same recurring preference → same title → storeImportedExperience
|
|
25
|
+
* can collapse them. Marked with a "user-style:" prefix so the entries are identifiable and
|
|
26
|
+
* prunable as a class.
|
|
27
|
+
*/
|
|
28
|
+
export declare function styleRuleTitle(rule: string): string;
|
|
29
|
+
export interface StyleExtractDeps {
|
|
30
|
+
classifyViaBrain: (prompt: string, timeoutMs?: number, options?: {
|
|
31
|
+
systemPrompt?: string;
|
|
32
|
+
responseFormat?: {
|
|
33
|
+
type: string;
|
|
34
|
+
};
|
|
35
|
+
maxTokens?: number;
|
|
36
|
+
useExtractModel?: boolean;
|
|
37
|
+
}) => Promise<string | null>;
|
|
38
|
+
writeExperience: (lesson: string, opts: {
|
|
39
|
+
collection?: string;
|
|
40
|
+
title?: string;
|
|
41
|
+
projectSlug?: string;
|
|
42
|
+
confidence?: number;
|
|
43
|
+
}) => Promise<WriteExperienceResult>;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Classify the transcript into gated style rules. Fail-open []: a degraded brain must never
|
|
47
|
+
* break session teardown.
|
|
48
|
+
*/
|
|
49
|
+
export declare function extractStyleSignals(deps: StyleExtractDeps, transcript: string): Promise<StyleRule[]>;
|
|
50
|
+
/**
|
|
51
|
+
* End-to-end WRITE arm: mine style rules from the transcript and persist each to
|
|
52
|
+
* experience-behavioral. Returns the number written. Fire-and-forget from extractSession —
|
|
53
|
+
* fail-open, never throws. `projectSlug` scopes the rule; confidence carries through so the
|
|
54
|
+
* brain can weight it.
|
|
55
|
+
*/
|
|
56
|
+
export declare function writeStyleSignals(deps: StyleExtractDeps, transcript: string, opts?: {
|
|
57
|
+
projectSlug?: string;
|
|
58
|
+
}): Promise<number>;
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
// src/ee/extract-style.ts
|
|
2
|
+
//
|
|
3
|
+
// Personality / working-style extraction — the WRITE arm that CLOSES the who-am-i loop.
|
|
4
|
+
//
|
|
5
|
+
// The READ arm (who-am-i-brain.ts) derives a WhoAmIProfile from the `experience-behavioral`
|
|
6
|
+
// brain: it searches the user's accumulated style rules and classifies them into dims that
|
|
7
|
+
// the PIL layers read. But on a thin-client NOTHING was feeding that collection with style
|
|
8
|
+
// signals mined from the user's OWN muonroi-cli sessions — the general server extract
|
|
9
|
+
// (`extractFromSession`) only mines TECHNICAL mistakes/lessons (detectExperience → extractQA),
|
|
10
|
+
// never "the user prefers concise answers / rejects hand-holding / decides fast". So the loop
|
|
11
|
+
// was open: who-am-i could only read rules the user hand-authored or the Claude Code Stop hook
|
|
12
|
+
// happened to capture.
|
|
13
|
+
//
|
|
14
|
+
// This module runs at session-end (alongside extractSession) and mines the transcript for the
|
|
15
|
+
// USER's working-style, writing each high-confidence signal as a natural-language behavioral
|
|
16
|
+
// rule into `experience-behavioral` via writeExperienceEE. Next session, who-am-i-brain reads
|
|
17
|
+
// those rules back and classifies them into dims → the loop is closed.
|
|
18
|
+
//
|
|
19
|
+
// Design guarantees:
|
|
20
|
+
// • Agent-first (no keyword regex): the transcript→style mapping is decided by the brain LLM
|
|
21
|
+
// (classifyViaBrain), honouring the repo rule that classification is never regex. The only
|
|
22
|
+
// regex here is tolerant JSON extraction from the LLM reply.
|
|
23
|
+
// • Natural-language interface (NOT a shared enum): the WRITE side emits plain style
|
|
24
|
+
// sentences; the READ side (who-am-i-brain) re-classifies them with its own DIM_VOCAB.
|
|
25
|
+
// Neither side imports the other's vocabulary — so there is no cross-module enum coupling
|
|
26
|
+
// to drift (contrast the EE-side DIM_VOCAB lockstep this deliberately avoids).
|
|
27
|
+
// • Anti-pollution: experience-behavioral also drives passive hint injection, so a wrong or
|
|
28
|
+
// low-confidence guess is actively harmful (it feeds who-am-i AND every passive hint). We
|
|
29
|
+
// gate HARD — high confidence floor, length bounds, a small per-session cap, and a stable
|
|
30
|
+
// per-signal title so repeated sessions MERGE instead of accreting near-duplicates.
|
|
31
|
+
// • Fail-open: any gap (classifier null, unparseable output, dep throws, EE down) writes
|
|
32
|
+
// nothing and never throws. Style converges over many sessions; missing one is harmless.
|
|
33
|
+
/** The collection who-am-i-brain reads back — keep in lockstep with BEHAVIORAL_COLLECTION there. */
|
|
34
|
+
const BEHAVIORAL_COLLECTION = "experience-behavioral";
|
|
35
|
+
/**
|
|
36
|
+
* Only signals at/above this confidence are written. High on purpose: a style rule that lands
|
|
37
|
+
* in experience-behavioral influences who-am-i AND passive hints, so a confident-but-wrong
|
|
38
|
+
* guess is worse than silence. The brain self-reports confidence per the prompt contract.
|
|
39
|
+
*/
|
|
40
|
+
const STYLE_WRITE_MIN_CONFIDENCE = 0.7;
|
|
41
|
+
/** At most this many style rules per session — style is slow-moving; a burst is almost always noise. */
|
|
42
|
+
const MAX_STYLE_RULES_PER_SESSION = 3;
|
|
43
|
+
/** A style rule shorter than this is too vague to guide anything; longer than this is task prose leaking in. */
|
|
44
|
+
const MIN_RULE_CHARS = 15;
|
|
45
|
+
const MAX_RULE_CHARS = 240;
|
|
46
|
+
/**
|
|
47
|
+
* Off the hot path (fire-and-forget at session-end), so a wide budget. The server's strong
|
|
48
|
+
* brainExtractModel is a reasoning model (deepseek-v4-flash) whose think+emit cycle runs
|
|
49
|
+
* ~4-10s on this transcript-sized prompt (verified live). 20s clears the tail; it never blocks
|
|
50
|
+
* anything (background). Mirrors who-am-i-brain's budget.
|
|
51
|
+
*/
|
|
52
|
+
const STYLE_CLASSIFY_TIMEOUT_MS = 20000;
|
|
53
|
+
/**
|
|
54
|
+
* The rules JSON itself is tiny (~150 tokens), but the server's extract model
|
|
55
|
+
* (deepseek-v4-flash) is a REASONING model — its thinking tokens count against this same
|
|
56
|
+
* budget and land in a separate reasoning_content field, NOT the JSON. A tight cap (500) let
|
|
57
|
+
* the reasoning consume the whole budget and truncate the actual JSON to empty → intermittent
|
|
58
|
+
* zero-rule results (verified live: identical input gave 3 rules then 0). Give thinking ample
|
|
59
|
+
* headroom so the JSON always survives; the extra tokens are only spent when the model
|
|
60
|
+
* actually reasons, and this is an off-hot-path background call.
|
|
61
|
+
*/
|
|
62
|
+
const STYLE_CLASSIFY_MAX_TOKENS = 3000;
|
|
63
|
+
/**
|
|
64
|
+
* System-prompt override — REQUIRED, same reason as who-am-i-brain: the EE brain proxy's
|
|
65
|
+
* default system prompt is a tier-classifier ("output ONE word … ignore content") that
|
|
66
|
+
* hijacks structured output into garbage. Verified on the live VPS (2026-07-05).
|
|
67
|
+
*/
|
|
68
|
+
const STYLE_SYSTEM_PROMPT = "You mine a developer's WORKING STYLE from a session transcript — how they prefer to " +
|
|
69
|
+
"communicate, decide, delegate, receive feedback, and handle risk. Follow the user " +
|
|
70
|
+
"message instructions EXACTLY and output ONLY the requested JSON object. Do not classify " +
|
|
71
|
+
"task complexity, do not output single words, do not add prose before or after the JSON.";
|
|
72
|
+
/** Feature flag — default ON, opt out with MUONROI_STYLE_EXTRACT=0. */
|
|
73
|
+
export function isStyleExtractEnabled() {
|
|
74
|
+
return process.env.MUONROI_STYLE_EXTRACT !== "0";
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* PURE: build the style-mining prompt. Asks the brain to emit 0..N natural-language style
|
|
78
|
+
* rules about the USER (never the task), each standalone and reusable as future guidance,
|
|
79
|
+
* with a self-reported confidence. Emitting NOTHING when the transcript shows no clear style
|
|
80
|
+
* is explicitly the right answer — we would rather miss a session than pollute the brain.
|
|
81
|
+
*/
|
|
82
|
+
export function buildStyleExtractPrompt(transcript) {
|
|
83
|
+
return [
|
|
84
|
+
"From the session transcript below, extract DURABLE signals about the DEVELOPER's working",
|
|
85
|
+
"style — not the task, not the code. Look for how they prefer to communicate (concise vs",
|
|
86
|
+
"detailed), decide (fast/intuitive vs deliberate), delegate (autonomous vs collaborative),",
|
|
87
|
+
"receive feedback (blunt correction vs gentle), and tolerate risk.",
|
|
88
|
+
"",
|
|
89
|
+
"Output ONLY a JSON object of the form:",
|
|
90
|
+
'{"rules": [{"rule": "<one imperative sentence of durable style guidance>", "confidence": 0.0-1.0}]}',
|
|
91
|
+
"",
|
|
92
|
+
"Rules:",
|
|
93
|
+
'- Each `rule` must be a standalone, reusable instruction (e.g. "The user prefers concise',
|
|
94
|
+
' answers — skip preamble and lead with the recommendation."). NOT a fact about this task.',
|
|
95
|
+
"- Emit a signal ONLY when the transcript gives clear, repeated evidence. When in doubt, omit it.",
|
|
96
|
+
"- An EMPTY array is the correct answer for a task-only session with no style signal.",
|
|
97
|
+
"- Never invent a preference the transcript does not actually demonstrate.",
|
|
98
|
+
"- confidence reflects how strongly the transcript supports the rule.",
|
|
99
|
+
"",
|
|
100
|
+
"Transcript:",
|
|
101
|
+
transcript,
|
|
102
|
+
].join("\n");
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* PURE: coerce a brain reply (JSON string, fenced block, or already-parsed object) into a
|
|
106
|
+
* gated list of style rules. Applies the confidence floor, length bounds, dedup by normalized
|
|
107
|
+
* text, and the per-session cap. Returns [] when nothing usable survives (fail-open).
|
|
108
|
+
*/
|
|
109
|
+
export function parseStyleRules(raw) {
|
|
110
|
+
let obj = raw;
|
|
111
|
+
if (typeof raw === "string") {
|
|
112
|
+
const json = extractJsonObject(raw);
|
|
113
|
+
if (!json)
|
|
114
|
+
return [];
|
|
115
|
+
try {
|
|
116
|
+
obj = JSON.parse(json);
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
return [];
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if (!obj || typeof obj !== "object")
|
|
123
|
+
return [];
|
|
124
|
+
const arr = obj.rules;
|
|
125
|
+
if (!Array.isArray(arr))
|
|
126
|
+
return [];
|
|
127
|
+
const seen = new Set();
|
|
128
|
+
const out = [];
|
|
129
|
+
for (const item of arr) {
|
|
130
|
+
if (!item || typeof item !== "object")
|
|
131
|
+
continue;
|
|
132
|
+
const rule = typeof item.rule === "string" ? item.rule.trim() : "";
|
|
133
|
+
const confidence = Number(item.confidence);
|
|
134
|
+
if (!rule || !Number.isFinite(confidence))
|
|
135
|
+
continue;
|
|
136
|
+
if (confidence < STYLE_WRITE_MIN_CONFIDENCE)
|
|
137
|
+
continue;
|
|
138
|
+
if (rule.length < MIN_RULE_CHARS || rule.length > MAX_RULE_CHARS)
|
|
139
|
+
continue;
|
|
140
|
+
const norm = rule.toLowerCase().replace(/\s+/g, " ");
|
|
141
|
+
if (seen.has(norm))
|
|
142
|
+
continue;
|
|
143
|
+
seen.add(norm);
|
|
144
|
+
out.push({ rule, confidence });
|
|
145
|
+
if (out.length >= MAX_STYLE_RULES_PER_SESSION)
|
|
146
|
+
break;
|
|
147
|
+
}
|
|
148
|
+
return out;
|
|
149
|
+
}
|
|
150
|
+
/** Tolerantly extract the first balanced JSON object from an LLM reply. */
|
|
151
|
+
function extractJsonObject(text) {
|
|
152
|
+
const start = text.indexOf("{");
|
|
153
|
+
if (start === -1)
|
|
154
|
+
return null;
|
|
155
|
+
let depth = 0;
|
|
156
|
+
let inStr = false;
|
|
157
|
+
let esc = false;
|
|
158
|
+
for (let i = start; i < text.length; i++) {
|
|
159
|
+
const ch = text[i];
|
|
160
|
+
if (inStr) {
|
|
161
|
+
if (esc)
|
|
162
|
+
esc = false;
|
|
163
|
+
else if (ch === "\\")
|
|
164
|
+
esc = true;
|
|
165
|
+
else if (ch === '"')
|
|
166
|
+
inStr = false;
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
if (ch === '"')
|
|
170
|
+
inStr = true;
|
|
171
|
+
else if (ch === "{")
|
|
172
|
+
depth++;
|
|
173
|
+
else if (ch === "}") {
|
|
174
|
+
depth--;
|
|
175
|
+
if (depth === 0)
|
|
176
|
+
return text.slice(start, i + 1);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* PURE: a stable title for a style rule so repeated sessions MERGE server-side instead of
|
|
183
|
+
* accreting near-duplicates. Derived deterministically from the rule text (lowercased, first
|
|
184
|
+
* few significant words) — same recurring preference → same title → storeImportedExperience
|
|
185
|
+
* can collapse them. Marked with a "user-style:" prefix so the entries are identifiable and
|
|
186
|
+
* prunable as a class.
|
|
187
|
+
*/
|
|
188
|
+
export function styleRuleTitle(rule) {
|
|
189
|
+
const words = rule
|
|
190
|
+
.toLowerCase()
|
|
191
|
+
.replace(/[^a-z0-9\s]/g, " ")
|
|
192
|
+
.split(/\s+/)
|
|
193
|
+
.filter((w) => w.length > 3 && !STOPWORDS.has(w))
|
|
194
|
+
.slice(0, 5)
|
|
195
|
+
.join("-");
|
|
196
|
+
return `user-style:${words || "general"}`;
|
|
197
|
+
}
|
|
198
|
+
const STOPWORDS = new Set([
|
|
199
|
+
"the",
|
|
200
|
+
"user",
|
|
201
|
+
"prefers",
|
|
202
|
+
"wants",
|
|
203
|
+
"with",
|
|
204
|
+
"that",
|
|
205
|
+
"this",
|
|
206
|
+
"they",
|
|
207
|
+
"them",
|
|
208
|
+
"their",
|
|
209
|
+
"when",
|
|
210
|
+
"into",
|
|
211
|
+
"over",
|
|
212
|
+
"from",
|
|
213
|
+
"answers",
|
|
214
|
+
"answer",
|
|
215
|
+
"reply",
|
|
216
|
+
"replies",
|
|
217
|
+
]);
|
|
218
|
+
/**
|
|
219
|
+
* Classify the transcript into gated style rules. Fail-open []: a degraded brain must never
|
|
220
|
+
* break session teardown.
|
|
221
|
+
*/
|
|
222
|
+
export async function extractStyleSignals(deps, transcript) {
|
|
223
|
+
try {
|
|
224
|
+
if (!transcript || transcript.trim().length < 100)
|
|
225
|
+
return [];
|
|
226
|
+
const reply = await deps.classifyViaBrain(buildStyleExtractPrompt(transcript), STYLE_CLASSIFY_TIMEOUT_MS, {
|
|
227
|
+
systemPrompt: STYLE_SYSTEM_PROMPT,
|
|
228
|
+
responseFormat: { type: "json_object" },
|
|
229
|
+
maxTokens: STYLE_CLASSIFY_MAX_TOKENS,
|
|
230
|
+
// Structured multi-signal extraction needs the server's stronger brainExtractModel;
|
|
231
|
+
// the hot-path model is too weak (verified on the live VPS for the READ side too).
|
|
232
|
+
useExtractModel: true,
|
|
233
|
+
});
|
|
234
|
+
if (!reply)
|
|
235
|
+
return [];
|
|
236
|
+
return parseStyleRules(reply);
|
|
237
|
+
}
|
|
238
|
+
catch {
|
|
239
|
+
return [];
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* End-to-end WRITE arm: mine style rules from the transcript and persist each to
|
|
244
|
+
* experience-behavioral. Returns the number written. Fire-and-forget from extractSession —
|
|
245
|
+
* fail-open, never throws. `projectSlug` scopes the rule; confidence carries through so the
|
|
246
|
+
* brain can weight it.
|
|
247
|
+
*/
|
|
248
|
+
export async function writeStyleSignals(deps, transcript, opts = {}) {
|
|
249
|
+
if (!isStyleExtractEnabled())
|
|
250
|
+
return 0;
|
|
251
|
+
const rules = await extractStyleSignals(deps, transcript);
|
|
252
|
+
let written = 0;
|
|
253
|
+
for (const r of rules) {
|
|
254
|
+
try {
|
|
255
|
+
const res = await deps.writeExperience(r.rule, {
|
|
256
|
+
collection: BEHAVIORAL_COLLECTION,
|
|
257
|
+
title: styleRuleTitle(r.rule),
|
|
258
|
+
projectSlug: opts.projectSlug,
|
|
259
|
+
confidence: r.confidence,
|
|
260
|
+
});
|
|
261
|
+
if (res.ok)
|
|
262
|
+
written++;
|
|
263
|
+
}
|
|
264
|
+
catch {
|
|
265
|
+
// fail-open per rule — one bad write must not abort the rest
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
return written;
|
|
269
|
+
}
|
|
270
|
+
//# sourceMappingURL=extract-style.js.map
|