muonroi-cli 1.8.3 → 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 +21 -21
- package/README.md +133 -122
- 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 +30 -15
- 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 +254 -84
- 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/oauth-callback.js +2 -2
- package/dist/src/mcp/research-onboarding.js +8 -7
- package/dist/src/mcp/runtime.js +34 -2
- package/dist/src/mcp/setup-guide-text.d.ts +1 -1
- package/dist/src/mcp/setup-guide-text.js +77 -76
- 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 +8 -8
- 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 +159 -159
- 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 +26 -0
- package/dist/src/orchestrator/tool-engine.js +669 -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/layer2_5-ponytail.js +8 -8
- 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/done-gate.js +3 -3
- 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 +327 -116
- 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/progress-snapshot.js +4 -4
- 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 +82 -172
- 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/reporter/index.js +1 -1
- 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/bb-ecosystem-apply.js +47 -47
- package/dist/src/scaffold/bb-quality-gate.js +5 -5
- package/dist/src/scaffold/continuation-prompt.d.ts +11 -0
- package/dist/src/scaffold/continuation-prompt.js +86 -60
- package/dist/src/scaffold/init-new.js +453 -453
- 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 +22 -22
- 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/interaction-log.js +5 -5
- package/dist/src/storage/migrations.js +196 -126
- package/dist/src/storage/session-experience-store.js +4 -4
- package/dist/src/storage/sessions.d.ts +28 -10
- package/dist/src/storage/sessions.js +112 -55
- package/dist/src/storage/transcript-view.js +1 -1
- package/dist/src/storage/transcript.d.ts +51 -0
- package/dist/src/storage/transcript.js +383 -112
- package/dist/src/storage/usage.js +14 -14
- package/dist/src/storage/workspaces.js +12 -12
- 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-inspect.js +4 -4
- 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/clipboard-image.js +23 -23
- package/dist/src/utils/install-manager.js +14 -11
- 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/side-question.js +2 -2
- package/dist/src/utils/skills.js +3 -3
- 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
|
@@ -24,6 +24,15 @@ export interface RecallLedger {
|
|
|
24
24
|
clear(id: string): boolean;
|
|
25
25
|
/** Check if an id was ever cleared (fed back) in this session. Used by PIL Layer 3 to suppress re-injection. */
|
|
26
26
|
wasCleared(id: string): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Check if an id is currently PENDING (recorded as unrated debt, not yet fed
|
|
29
|
+
* back). PIL Layer 3 uses this to suppress re-injecting the FULL content of a
|
|
30
|
+
* hint it already surfaced earlier this session — the hit is already in the
|
|
31
|
+
* conversation history and still listed in the feedback nudge, so repeating
|
|
32
|
+
* its body every turn is pure token waste (the "hint lặp" repetition). First
|
|
33
|
+
* sighting is injected + recorded; subsequent turns skip the body.
|
|
34
|
+
*/
|
|
35
|
+
isPending(id: string): boolean;
|
|
27
36
|
/** Oldest-first list of still-unrated recalls. */
|
|
28
37
|
pending(): PendingRecall[];
|
|
29
38
|
pendingCount(): number;
|
|
@@ -45,6 +45,9 @@ export function createRecallLedger() {
|
|
|
45
45
|
wasCleared(id) {
|
|
46
46
|
return cleared.has(String(id ?? "").trim());
|
|
47
47
|
},
|
|
48
|
+
isPending(id) {
|
|
49
|
+
return map.has(String(id ?? "").trim());
|
|
50
|
+
},
|
|
48
51
|
pending() {
|
|
49
52
|
return [...map.values()].sort((a, b) => a.ts - b.ts);
|
|
50
53
|
},
|
package/dist/src/ee/scope.d.ts
CHANGED
package/dist/src/ee/scope.js
CHANGED
|
@@ -42,6 +42,30 @@ async function findGitRoot(start) {
|
|
|
42
42
|
}
|
|
43
43
|
return null;
|
|
44
44
|
}
|
|
45
|
+
export function sanitizeRemoteUrl(remoteUrl) {
|
|
46
|
+
const trimmed = remoteUrl.trim();
|
|
47
|
+
// If it starts with a scheme like http://, https://, ssh://, git:// etc.
|
|
48
|
+
if (/^[a-zA-Z0-9+-.]+:\/\//.test(trimmed)) {
|
|
49
|
+
try {
|
|
50
|
+
const parsed = new URL(trimmed);
|
|
51
|
+
if (parsed.protocol === "http:" ||
|
|
52
|
+
parsed.protocol === "https:" ||
|
|
53
|
+
parsed.protocol === "git+http:" ||
|
|
54
|
+
parsed.protocol === "git+https:") {
|
|
55
|
+
parsed.username = "";
|
|
56
|
+
parsed.password = "";
|
|
57
|
+
}
|
|
58
|
+
return parsed.toString();
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
// Fallback for valid scheme prefix but invalid URL syntax
|
|
62
|
+
return trimmed.replace(/^([^:]+:\/\/)[^@]+@/, "$1");
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// Prevent parsing exceptions on SSH remotes (e.g. git@github.com:...)
|
|
66
|
+
// SCP-like SSH remotes do not start with a scheme + "://"
|
|
67
|
+
return trimmed;
|
|
68
|
+
}
|
|
45
69
|
export async function buildScope(opts) {
|
|
46
70
|
if (cached && cachedFor === opts.cwd)
|
|
47
71
|
return cached;
|
|
@@ -53,7 +77,8 @@ export async function buildScope(opts) {
|
|
|
53
77
|
}
|
|
54
78
|
const head = await fs.readFile(path.join(root, ".git", "HEAD"), "utf8").catch(() => "");
|
|
55
79
|
const cfg = await fs.readFile(path.join(root, ".git", "config"), "utf8").catch(() => "");
|
|
56
|
-
const { remote } = parseGitConfig(cfg);
|
|
80
|
+
const { remote: rawRemote } = parseGitConfig(cfg);
|
|
81
|
+
const remote = rawRemote ? sanitizeRemoteUrl(rawRemote) : undefined;
|
|
57
82
|
const { branch } = parseHEAD(head);
|
|
58
83
|
// Ecosystem detection — check if remote matches any configured pattern
|
|
59
84
|
if (remote) {
|
package/dist/src/ee/search.d.ts
CHANGED
|
@@ -76,6 +76,13 @@ export interface FeedbackResult {
|
|
|
76
76
|
verdict?: string;
|
|
77
77
|
reason?: string;
|
|
78
78
|
error?: string;
|
|
79
|
+
/**
|
|
80
|
+
* True when the brain was unreachable/transient and the verdict was durably
|
|
81
|
+
* enqueued for later delivery instead of lost. Callers treat this as success
|
|
82
|
+
* (the agent discharged its rating) and clear their recall ledger so the
|
|
83
|
+
* mandatory-rating gate cannot loop while the brain is down.
|
|
84
|
+
*/
|
|
85
|
+
queued?: boolean;
|
|
79
86
|
}
|
|
80
87
|
/**
|
|
81
88
|
* Record an agent verdict on a recalled `[id col]` entry, byte-for-byte matching
|
package/dist/src/ee/search.js
CHANGED
|
@@ -173,6 +173,13 @@ export async function feedbackEE(pointId, collection, verdict, reason) {
|
|
|
173
173
|
/* non-JSON error body — fall through to status-based handling */
|
|
174
174
|
}
|
|
175
175
|
if (!res.ok) {
|
|
176
|
+
// Transient server-side failures (5xx / rate limit / timeout) must not lose
|
|
177
|
+
// the verdict OR block the agent: queue it for later delivery. Hard client
|
|
178
|
+
// errors (bad collection, unknown id) are the caller's fault — surface them.
|
|
179
|
+
const transient = res.status >= 500 || res.status === 429 || res.status === 408;
|
|
180
|
+
if (transient && (await tryEnqueueFeedback(body))) {
|
|
181
|
+
return { ok: true, resolvedId: pointId, verdict: wire, reason, queued: true };
|
|
182
|
+
}
|
|
176
183
|
return { ok: false, error: json?.error || text || `HTTP ${res.status}` };
|
|
177
184
|
}
|
|
178
185
|
const resolvedId = json?.resolvedId || pointId;
|
|
@@ -182,9 +189,26 @@ export async function feedbackEE(pointId, collection, verdict, reason) {
|
|
|
182
189
|
catch (err) {
|
|
183
190
|
const { logEeFailure, classifyEeError } = await import("../utils/ee-logger.js");
|
|
184
191
|
logEeFailure("search.feedbackEE", classifyEeError(err), err);
|
|
192
|
+
// Network-level failure (brain down, socket drop) — durably queue so the
|
|
193
|
+
// verdict survives and the agent's rating gate does not loop. Only report a
|
|
194
|
+
// hard failure if even the enqueue fails.
|
|
195
|
+
if (await tryEnqueueFeedback(body)) {
|
|
196
|
+
return { ok: true, resolvedId: pointId, verdict: wire, reason, queued: true };
|
|
197
|
+
}
|
|
185
198
|
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
186
199
|
}
|
|
187
200
|
}
|
|
201
|
+
/** Enqueue a /api/feedback body to the offline queue; false if enqueue itself fails. */
|
|
202
|
+
async function tryEnqueueFeedback(body) {
|
|
203
|
+
try {
|
|
204
|
+
const { enqueue } = await import("./offline-queue.js");
|
|
205
|
+
await enqueue({ endpoint: "/api/feedback", body, enqueuedAt: Date.now() });
|
|
206
|
+
return true;
|
|
207
|
+
}
|
|
208
|
+
catch {
|
|
209
|
+
return false;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
188
212
|
/**
|
|
189
213
|
* Mirror a feedback verdict as a LOCAL `op:'feedback'` activity row (parity with
|
|
190
214
|
* mirrorRecallLocally's `op:'recall'`). Lets the session-end nudge + forensics
|
|
@@ -23,6 +23,8 @@ import fs from "node:fs";
|
|
|
23
23
|
import os from "node:os";
|
|
24
24
|
import path from "node:path";
|
|
25
25
|
function experienceRoot() {
|
|
26
|
+
if (process.env.MUONROI_EXPERIENCE_ROOT_OVERRIDE)
|
|
27
|
+
return process.env.MUONROI_EXPERIENCE_ROOT_OVERRIDE;
|
|
26
28
|
return path.join(os.homedir(), ".experience");
|
|
27
29
|
}
|
|
28
30
|
function emitRoot() {
|
package/dist/src/ee/types.d.ts
CHANGED
|
@@ -125,6 +125,11 @@ export interface RouteModelRequest {
|
|
|
125
125
|
projectSize?: "small" | "medium" | "large";
|
|
126
126
|
filesTouched?: number;
|
|
127
127
|
mode?: string;
|
|
128
|
+
turnIndex?: number;
|
|
129
|
+
messageCount?: number;
|
|
130
|
+
compactionCount?: number;
|
|
131
|
+
totalSavedTokens?: number;
|
|
132
|
+
compactionSummary?: string;
|
|
128
133
|
};
|
|
129
134
|
runtime?: "claude" | "gemini" | "codex" | "opencode";
|
|
130
135
|
}
|
|
@@ -357,6 +362,15 @@ export interface EERecallOptions {
|
|
|
357
362
|
/** Override per-call timeout. Defaults to 15000ms — server bounds recall at ~8s internally; allow margin for embed + 3-leg search + network. */
|
|
358
363
|
timeoutMs?: number;
|
|
359
364
|
signal?: AbortSignal;
|
|
365
|
+
/**
|
|
366
|
+
* Council stance/role for per-stance recall weighting (Sprint-2 item 3). The
|
|
367
|
+
* server weights the recall collections toward the knowledge this stance cares
|
|
368
|
+
* about (researcher → principles, implementer → behavioral, verifier →
|
|
369
|
+
* self-QA). Unknown/absent stance is a no-op server-side.
|
|
370
|
+
*/
|
|
371
|
+
stance?: string;
|
|
372
|
+
/** Alias for stance; forwarded as body.role. Either resolves the same weights. */
|
|
373
|
+
role?: string;
|
|
360
374
|
}
|
|
361
375
|
export interface EEUserResponse {
|
|
362
376
|
user: string;
|
|
@@ -374,6 +388,14 @@ export interface BrainProxyOptions {
|
|
|
374
388
|
maxTokens?: number;
|
|
375
389
|
/** Override the brain provider (siliconflow | ollama | openai | ...). */
|
|
376
390
|
provider?: string;
|
|
391
|
+
/**
|
|
392
|
+
* Ask the server to use its stronger `brainExtractModel` (structured-extraction
|
|
393
|
+
* model) instead of the hot-path `brainModel`. Zero-hardcode by design: the client
|
|
394
|
+
* sends only this flag, the server resolves the model id from its own config + key.
|
|
395
|
+
* Used by the thin-client WhoAmI brain fallback, where the weak default model
|
|
396
|
+
* mis-spells the dim vocabulary. Ignored by servers that don't recognise it.
|
|
397
|
+
*/
|
|
398
|
+
useExtractModel?: boolean;
|
|
377
399
|
}
|
|
378
400
|
export interface EEClient {
|
|
379
401
|
health(): Promise<{
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type PrivacyLevel, type WhoAmIProfile } from "./who-am-i.js";
|
|
2
|
+
/** Feature flag — default ON, opt out with MUONROI_WHOAMI_BRAIN=0. */
|
|
3
|
+
export declare function isBrainWhoAmIEnabled(): boolean;
|
|
4
|
+
/**
|
|
5
|
+
* PURE: build the classify prompt. Asks the brain to distil the retrieved rules into
|
|
6
|
+
* a strict dims JSON using only the allowed names + vocabulary. Emitting fewer dims
|
|
7
|
+
* (only the confident ones) is explicitly encouraged — downstream drops the rest.
|
|
8
|
+
*/
|
|
9
|
+
export declare function buildStyleClassifyPrompt(rules: string[]): string;
|
|
10
|
+
/**
|
|
11
|
+
* PURE: coerce a brain reply (JSON string, fenced block, or already-parsed object)
|
|
12
|
+
* into a privacy-gated WhoAmIProfile. Reuses selectWhoAmIDims for the allowlist +
|
|
13
|
+
* confidence floor. Returns null when nothing usable survives.
|
|
14
|
+
*/
|
|
15
|
+
export declare function parseBrainProfile(raw: unknown, level?: PrivacyLevel): WhoAmIProfile | null;
|
|
16
|
+
export interface BrainWhoAmIDeps {
|
|
17
|
+
searchByText: (text: string, collections: string[], topK: number) => Promise<Array<{
|
|
18
|
+
payload?: {
|
|
19
|
+
text?: string;
|
|
20
|
+
};
|
|
21
|
+
}>>;
|
|
22
|
+
classifyViaBrain: (prompt: string, timeoutMs?: number, options?: {
|
|
23
|
+
systemPrompt?: string;
|
|
24
|
+
responseFormat?: {
|
|
25
|
+
type: string;
|
|
26
|
+
};
|
|
27
|
+
maxTokens?: number;
|
|
28
|
+
useExtractModel?: boolean;
|
|
29
|
+
}) => Promise<string | null>;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Derive a WhoAmIProfile from the behavioral brain. Search the user's style rules →
|
|
33
|
+
* classify them into dims via the brain LLM → privacy-gate locally. Fail-open null.
|
|
34
|
+
*/
|
|
35
|
+
export declare function deriveWhoAmIFromBrain(deps: BrainWhoAmIDeps, level?: PrivacyLevel): Promise<WhoAmIProfile | null>;
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
// src/ee/who-am-i-brain.ts
|
|
2
|
+
//
|
|
3
|
+
// Brain-derived "Who Am I" fallback for THIN-CLIENTS.
|
|
4
|
+
//
|
|
5
|
+
// The device-local profile.yaml pipeline (src/ee/who-am-i.ts) is full-brain-only:
|
|
6
|
+
// the EE prompt interceptor bails early on remote mode (`if (isRemoteMode()) return`),
|
|
7
|
+
// no /api/profile endpoint exists, and signal-extraction from transcripts never runs
|
|
8
|
+
// on a thin-client. So on a thin-client getWhoAmIProfile() is structurally always
|
|
9
|
+
// null and the PIL loses every style signal.
|
|
10
|
+
//
|
|
11
|
+
// The user's working style IS reachable though — it lives in the `experience-behavioral`
|
|
12
|
+
// brain (their own authored rules: "recommend, don't ask", "keep it concise", etc.),
|
|
13
|
+
// which the runtime already queries via searchByText() over /api/search. This module
|
|
14
|
+
// derives the SAME WhoAmIProfile shape from those rules so all existing PIL wiring
|
|
15
|
+
// (outputStyleFromProfile, the layer4/5/6 dim reads) works unchanged.
|
|
16
|
+
//
|
|
17
|
+
// Design guarantees:
|
|
18
|
+
// • Agent-first (no keyword regex): the rule→dim mapping is decided by the brain LLM
|
|
19
|
+
// itself (classifyViaBrain), honouring the repo rule that classification is never
|
|
20
|
+
// regex. The only regex here is tolerant JSON extraction from the LLM's reply.
|
|
21
|
+
// • Privacy: dims are re-gated locally through selectWhoAmIDims — the positive
|
|
22
|
+
// name-allowlist + per-tier confidence floor. Brain rules are user-authored style
|
|
23
|
+
// guidance (Tang-2 equivalent), so we gate at the "standard" tier; emotional.* can
|
|
24
|
+
// never surface (not on the allowlist). This is decoupled from the EE file
|
|
25
|
+
// privacyLevel (which governs the *auto-derived* on-device profile — a different,
|
|
26
|
+
// more sensitive data source that is off by default on thin-clients).
|
|
27
|
+
// • Fail-open: any gap (no rules, classifier null, unparseable output, dep throws)
|
|
28
|
+
// returns null → the PIL keeps its own per-turn default. Never throws.
|
|
29
|
+
import { selectWhoAmIDims } from "./who-am-i.js";
|
|
30
|
+
const BEHAVIORAL_COLLECTION = "experience-behavioral";
|
|
31
|
+
const BRAIN_TOPK = 12;
|
|
32
|
+
/** Brain rules are style-level guidance → the standard tier (never emotional). */
|
|
33
|
+
const BRAIN_TIER = "standard";
|
|
34
|
+
/**
|
|
35
|
+
* System prompt override — REQUIRED. The EE brain proxy's default system prompt is a
|
|
36
|
+
* tier-classifier ("output ONE word: fast|balanced|premium … ignore the task content"),
|
|
37
|
+
* which actively hijacks any structured-output request → malformed JSON. Verified on the
|
|
38
|
+
* live VPS (2026-07-05): omitting this made even DeepSeek-V3 emit garbage; supplying it
|
|
39
|
+
* makes the DEFAULT server model (Qwen2.5-7B) emit clean, accurate dims JSON. We do NOT
|
|
40
|
+
* override the model/provider — that would hardcode a model id (Zero-Hardcode Rule) and
|
|
41
|
+
* cost the user's own provider; the server's default brain model + key does the work.
|
|
42
|
+
*/
|
|
43
|
+
const STYLE_SYSTEM_PROMPT = "You extract a developer's working-style profile from their accumulated behavioral " +
|
|
44
|
+
"rules. Follow the user message instructions EXACTLY and output ONLY the requested " +
|
|
45
|
+
"JSON object. Do not classify task complexity, do not output single words, do not " +
|
|
46
|
+
"add prose before or after the JSON.";
|
|
47
|
+
/**
|
|
48
|
+
* Probe the behavioral brain for working-style rules. Free-text; the server embeds
|
|
49
|
+
* + searches Qdrant. Intentionally broad — it should surface brevity / decision /
|
|
50
|
+
* feedback / delegation / risk / conflict guidance the user has accumulated.
|
|
51
|
+
*/
|
|
52
|
+
const STYLE_PROBE = "the user's preferred working style: communication brevity, decision speed, " +
|
|
53
|
+
"feedback and correction style, delegation style, risk tolerance, conflict style";
|
|
54
|
+
// The dims the brain may emit, with the EXACT value vocabulary. Source of truth is
|
|
55
|
+
// the EE profile renderer (~/.experience/src/profile-render.js DIRECTIVES) — the same
|
|
56
|
+
// values the device-local profile uses and that the PIL layers compare against
|
|
57
|
+
// literally (e.g. layer4 tests delegation === "autonomous", layer6 tests
|
|
58
|
+
// feedback_style === "precise-correction"). A value outside this set would populate a
|
|
59
|
+
// dim that no lever reads → silently inert. Keep in lockstep with the EE enum.
|
|
60
|
+
const DIM_VOCAB = {
|
|
61
|
+
"communication.brevity": ["concise", "moderate", "verbose"],
|
|
62
|
+
"communication.feedback_style": ["implicit", "precise-correction"],
|
|
63
|
+
"communication.question_style": ["comparison", "debugging", "exploratory", "directive"],
|
|
64
|
+
"personality.decision_speed": ["fast-intuitive", "measured", "deliberate"],
|
|
65
|
+
"personality.risk_tolerance": ["experimental"],
|
|
66
|
+
"personality.conflict_style": ["direct-constructive", "authoritative", "cautious"],
|
|
67
|
+
"work_patterns.energy": ["night-owl", "daytime", "mixed"],
|
|
68
|
+
"work_patterns.multitasking": ["task-switcher", "sequential-deep"],
|
|
69
|
+
"work_patterns.session_length": ["short", "medium", "long"],
|
|
70
|
+
"work_patterns.delegation_style": ["autonomous", "collaborative"],
|
|
71
|
+
};
|
|
72
|
+
/** Feature flag — default ON, opt out with MUONROI_WHOAMI_BRAIN=0. */
|
|
73
|
+
export function isBrainWhoAmIEnabled() {
|
|
74
|
+
return process.env.MUONROI_WHOAMI_BRAIN !== "0";
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* PURE: build the classify prompt. Asks the brain to distil the retrieved rules into
|
|
78
|
+
* a strict dims JSON using only the allowed names + vocabulary. Emitting fewer dims
|
|
79
|
+
* (only the confident ones) is explicitly encouraged — downstream drops the rest.
|
|
80
|
+
*/
|
|
81
|
+
export function buildStyleClassifyPrompt(rules) {
|
|
82
|
+
const vocabLines = Object.entries(DIM_VOCAB)
|
|
83
|
+
.map(([name, values]) => ` "${name}": one of ${values.map((v) => `"${v}"`).join(" | ")}`)
|
|
84
|
+
.join("\n");
|
|
85
|
+
const ruleBlock = rules.length
|
|
86
|
+
? rules.map((r, i) => `${i + 1}. ${r}`).join("\n")
|
|
87
|
+
: "(no explicit rules retrieved — infer nothing; emit an empty dimensions object)";
|
|
88
|
+
return [
|
|
89
|
+
"You classify a developer's working style from their accumulated behavioral rules.",
|
|
90
|
+
"Output ONLY a JSON object of the form:",
|
|
91
|
+
'{"dimensions": {"<dim.name>": {"value": "<allowed value>", "confidence": 0.0-1.0, "sampleCount": <int>}}}',
|
|
92
|
+
"",
|
|
93
|
+
"Allowed dimensions and their vocabulary (use these names/values EXACTLY):",
|
|
94
|
+
vocabLines,
|
|
95
|
+
"",
|
|
96
|
+
"Rules:",
|
|
97
|
+
"- Include a dimension ONLY when the rules give clear evidence for it.",
|
|
98
|
+
"- Omit anything uncertain — a small, confident object beats a complete guess.",
|
|
99
|
+
"- confidence reflects how strongly the rules support the value; sampleCount = how many rules back it.",
|
|
100
|
+
"- Never invent dimension names or values outside the vocabulary above.",
|
|
101
|
+
"",
|
|
102
|
+
"Behavioral rules:",
|
|
103
|
+
ruleBlock,
|
|
104
|
+
].join("\n");
|
|
105
|
+
}
|
|
106
|
+
/** Tolerantly extract the first balanced JSON object from an LLM reply. */
|
|
107
|
+
function extractJsonObject(text) {
|
|
108
|
+
const start = text.indexOf("{");
|
|
109
|
+
if (start === -1)
|
|
110
|
+
return null;
|
|
111
|
+
let depth = 0;
|
|
112
|
+
let inStr = false;
|
|
113
|
+
let esc = false;
|
|
114
|
+
for (let i = start; i < text.length; i++) {
|
|
115
|
+
const ch = text[i];
|
|
116
|
+
if (inStr) {
|
|
117
|
+
if (esc)
|
|
118
|
+
esc = false;
|
|
119
|
+
else if (ch === "\\")
|
|
120
|
+
esc = true;
|
|
121
|
+
else if (ch === '"')
|
|
122
|
+
inStr = false;
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
if (ch === '"')
|
|
126
|
+
inStr = true;
|
|
127
|
+
else if (ch === "{")
|
|
128
|
+
depth++;
|
|
129
|
+
else if (ch === "}") {
|
|
130
|
+
depth--;
|
|
131
|
+
if (depth === 0)
|
|
132
|
+
return text.slice(start, i + 1);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* PURE: coerce a brain reply (JSON string, fenced block, or already-parsed object)
|
|
139
|
+
* into a privacy-gated WhoAmIProfile. Reuses selectWhoAmIDims for the allowlist +
|
|
140
|
+
* confidence floor. Returns null when nothing usable survives.
|
|
141
|
+
*/
|
|
142
|
+
export function parseBrainProfile(raw, level = BRAIN_TIER) {
|
|
143
|
+
let obj = raw;
|
|
144
|
+
if (typeof raw === "string") {
|
|
145
|
+
const json = extractJsonObject(raw);
|
|
146
|
+
if (!json)
|
|
147
|
+
return null;
|
|
148
|
+
try {
|
|
149
|
+
obj = JSON.parse(json);
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
if (!obj || typeof obj !== "object")
|
|
156
|
+
return null;
|
|
157
|
+
const gated = selectWhoAmIDims(obj, level);
|
|
158
|
+
// Value validation — the name allowlist in selectWhoAmIDims does NOT check the VALUE,
|
|
159
|
+
// and weaker brain models mis-spell the vocabulary (verified on the live VPS:
|
|
160
|
+
// Qwen2.5-7B emitted "precice-correction"). An off-vocab value populates a dim that
|
|
161
|
+
// the PIL layers — which compare literally — can never fire on, so it's worse than
|
|
162
|
+
// absent (looks set, does nothing). Drop any value not in DIM_VOCAB[name].
|
|
163
|
+
const dims = {};
|
|
164
|
+
for (const [name, dim] of Object.entries(gated)) {
|
|
165
|
+
const vocab = DIM_VOCAB[name];
|
|
166
|
+
if (vocab && !vocab.includes(dim.value))
|
|
167
|
+
continue;
|
|
168
|
+
dims[name] = dim;
|
|
169
|
+
}
|
|
170
|
+
if (Object.keys(dims).length === 0)
|
|
171
|
+
return null;
|
|
172
|
+
return { level, dims };
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Off the hot path (fire-and-forget boot warm), so a wide budget. The server's
|
|
176
|
+
* brainExtractModel is a REASONING model (deepseek-v4-flash) and the who-am-i prompt is large
|
|
177
|
+
* (12 retrieved rules + the full dim-vocabulary schema), so the think+emit cycle runs ~10-15s
|
|
178
|
+
* — verified live that a 15s cap intermittently truncated to a timeout/null. 25s clears the
|
|
179
|
+
* tail; the cost is nil because this never blocks anything (background warm).
|
|
180
|
+
*/
|
|
181
|
+
const BRAIN_CLASSIFY_TIMEOUT_MS = 25000;
|
|
182
|
+
/**
|
|
183
|
+
* The dims JSON is tiny (~200 tokens), but the server's extract model (deepseek-v4-flash) is a
|
|
184
|
+
* REASONING model — its thinking tokens count against this same budget (landing in a separate
|
|
185
|
+
* reasoning_content field, not the JSON). A tight cap let the reasoning consume the budget and
|
|
186
|
+
* truncate the actual JSON to empty → intermittent null profiles. Give thinking ample headroom
|
|
187
|
+
* so the dims JSON always survives; extra tokens are only spent when the model reasons, and
|
|
188
|
+
* this is an off-hot-path boot warm.
|
|
189
|
+
*/
|
|
190
|
+
const BRAIN_CLASSIFY_MAX_TOKENS = 3000;
|
|
191
|
+
/**
|
|
192
|
+
* Derive a WhoAmIProfile from the behavioral brain. Search the user's style rules →
|
|
193
|
+
* classify them into dims via the brain LLM → privacy-gate locally. Fail-open null.
|
|
194
|
+
*/
|
|
195
|
+
export async function deriveWhoAmIFromBrain(deps, level = BRAIN_TIER) {
|
|
196
|
+
try {
|
|
197
|
+
const points = await deps.searchByText(STYLE_PROBE, [BEHAVIORAL_COLLECTION], BRAIN_TOPK);
|
|
198
|
+
const rules = points
|
|
199
|
+
.map((p) => (typeof p.payload?.text === "string" ? p.payload.text.trim() : ""))
|
|
200
|
+
.filter((t) => t.length > 0);
|
|
201
|
+
if (rules.length === 0)
|
|
202
|
+
return null;
|
|
203
|
+
const reply = await deps.classifyViaBrain(buildStyleClassifyPrompt(rules), BRAIN_CLASSIFY_TIMEOUT_MS, {
|
|
204
|
+
systemPrompt: STYLE_SYSTEM_PROMPT,
|
|
205
|
+
responseFormat: { type: "json_object" },
|
|
206
|
+
maxTokens: BRAIN_CLASSIFY_MAX_TOKENS,
|
|
207
|
+
// Structured multi-dim extraction needs the server's stronger brainExtractModel;
|
|
208
|
+
// the hot-path model mis-spells the vocabulary (verified on the live VPS).
|
|
209
|
+
useExtractModel: true,
|
|
210
|
+
});
|
|
211
|
+
if (!reply)
|
|
212
|
+
return null;
|
|
213
|
+
return parseBrainProfile(reply, level);
|
|
214
|
+
}
|
|
215
|
+
catch {
|
|
216
|
+
// Fail-open — a degraded brain must never break the PIL hot path.
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
//# sourceMappingURL=who-am-i-brain.js.map
|
|
@@ -10,13 +10,13 @@ export interface WhoAmIProfile {
|
|
|
10
10
|
level: PrivacyLevel;
|
|
11
11
|
dims: Partial<Record<WhoAmIDimName, WhoAmIDim>>;
|
|
12
12
|
}
|
|
13
|
-
interface RawDim {
|
|
13
|
+
export interface RawDim {
|
|
14
14
|
value: string | null;
|
|
15
15
|
confidence?: number;
|
|
16
16
|
sampleCount?: number;
|
|
17
17
|
samples?: number;
|
|
18
18
|
}
|
|
19
|
-
interface RawProfile {
|
|
19
|
+
export interface RawProfile {
|
|
20
20
|
dimensions?: Record<string, RawDim>;
|
|
21
21
|
}
|
|
22
22
|
/**
|
|
@@ -38,4 +38,11 @@ export declare function outputStyleFromProfile(profile: WhoAmIProfile | null): O
|
|
|
38
38
|
export declare function getWhoAmIProfile(): WhoAmIProfile | null;
|
|
39
39
|
/** Clear the cache — test-only / after a known profile change. */
|
|
40
40
|
export declare function resetWhoAmICache(): void;
|
|
41
|
-
|
|
41
|
+
/**
|
|
42
|
+
* Prime the per-process cache with an externally-derived profile (e.g. the
|
|
43
|
+
* thin-client brain fallback in who-am-i-brain.ts, wired via the bridge). Only
|
|
44
|
+
* overwrites when the device-local read produced nothing (`_cache` is null/unset)
|
|
45
|
+
* so a real on-device profile always wins over a brain-derived one. No-op when a
|
|
46
|
+
* device-local profile is already loaded.
|
|
47
|
+
*/
|
|
48
|
+
export declare function primeWhoAmICache(profile: WhoAmIProfile | null): void;
|
package/dist/src/ee/who-am-i.js
CHANGED
|
@@ -110,6 +110,18 @@ export function getWhoAmIProfile() {
|
|
|
110
110
|
export function resetWhoAmICache() {
|
|
111
111
|
_cache = undefined;
|
|
112
112
|
}
|
|
113
|
+
/**
|
|
114
|
+
* Prime the per-process cache with an externally-derived profile (e.g. the
|
|
115
|
+
* thin-client brain fallback in who-am-i-brain.ts, wired via the bridge). Only
|
|
116
|
+
* overwrites when the device-local read produced nothing (`_cache` is null/unset)
|
|
117
|
+
* so a real on-device profile always wins over a brain-derived one. No-op when a
|
|
118
|
+
* device-local profile is already loaded.
|
|
119
|
+
*/
|
|
120
|
+
export function primeWhoAmICache(profile) {
|
|
121
|
+
if (_cache)
|
|
122
|
+
return;
|
|
123
|
+
_cache = profile;
|
|
124
|
+
}
|
|
113
125
|
function loadWhoAmIProfile() {
|
|
114
126
|
try {
|
|
115
127
|
const req = createRequire(import.meta.url);
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/ee/workflow-event.ts
|
|
3
|
+
*
|
|
4
|
+
* Part C/D client for the EE `/api/workflow-event` write-during-execution
|
|
5
|
+
* channel (added in experience-engine Part D). Lets the council workflow persist
|
|
6
|
+
* experience MID-RUN — per-round debate outcomes, sprint results, decisions,
|
|
7
|
+
* mistakes — into the `workflow_*` collections, so a later run (or a later
|
|
8
|
+
* sprint in the SAME run) can recall it.
|
|
9
|
+
*
|
|
10
|
+
* Contract with the two Kill findings from the plan review:
|
|
11
|
+
* - Kill #7: on a 404 (endpoint disabled / older server) DROP the event — do
|
|
12
|
+
* NOT enqueue. Queuing 404s head-of-line-poisons the offline queue against a
|
|
13
|
+
* server that will never accept them.
|
|
14
|
+
* - Kill #4/#5: writes are fire-and-forget and off the critical path. Recall of
|
|
15
|
+
* these hot entries stays gated on the server side (tier:"intra-session").
|
|
16
|
+
*
|
|
17
|
+
* On a transient network failure the event IS enqueued to the offline queue so
|
|
18
|
+
* a later drain retries it. Never throws; never blocks the workflow.
|
|
19
|
+
*/
|
|
20
|
+
import { enqueue } from "./offline-queue.js";
|
|
21
|
+
export type WorkflowEventKind = "council-debate" | "sprint-execution" | "decision" | "mistake";
|
|
22
|
+
export interface WorkflowEventPayload {
|
|
23
|
+
kind: WorkflowEventKind;
|
|
24
|
+
/** Run/phase reference, e.g. `runs/<runId>` or `runs/<runId>#sprint-3`. */
|
|
25
|
+
phaseRef: string;
|
|
26
|
+
sessionId?: string;
|
|
27
|
+
/** Short embeddable summary; falls back to a derived string server-side. */
|
|
28
|
+
text?: string;
|
|
29
|
+
/** Arbitrary structured detail persisted alongside the entry. */
|
|
30
|
+
payload?: Record<string, unknown>;
|
|
31
|
+
}
|
|
32
|
+
export interface FireWorkflowEventOpts {
|
|
33
|
+
baseUrl?: string;
|
|
34
|
+
authToken?: string;
|
|
35
|
+
timeoutMs?: number;
|
|
36
|
+
fetchImpl?: typeof fetch;
|
|
37
|
+
/** Test seam: override the offline-queue enqueue. */
|
|
38
|
+
enqueueImpl?: typeof enqueue;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* POST a workflow event. Returns `true` when the server accepted it, `false`
|
|
42
|
+
* otherwise (dropped on 404, enqueued on network error). Never throws.
|
|
43
|
+
*/
|
|
44
|
+
export declare function fireWorkflowEvent(payload: WorkflowEventPayload, opts?: FireWorkflowEventOpts): Promise<boolean>;
|
|
45
|
+
/** Fire-and-forget wrapper — never throws, never blocks the workflow. */
|
|
46
|
+
export declare function fireAndForgetWorkflowEvent(payload: WorkflowEventPayload, opts?: FireWorkflowEventOpts): void;
|
|
47
|
+
/** Test-only: reset the once-per-process warning latch. */
|
|
48
|
+
export declare function _resetWorkflowEventState(): void;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* src/ee/workflow-event.ts
|
|
3
|
+
*
|
|
4
|
+
* Part C/D client for the EE `/api/workflow-event` write-during-execution
|
|
5
|
+
* channel (added in experience-engine Part D). Lets the council workflow persist
|
|
6
|
+
* experience MID-RUN — per-round debate outcomes, sprint results, decisions,
|
|
7
|
+
* mistakes — into the `workflow_*` collections, so a later run (or a later
|
|
8
|
+
* sprint in the SAME run) can recall it.
|
|
9
|
+
*
|
|
10
|
+
* Contract with the two Kill findings from the plan review:
|
|
11
|
+
* - Kill #7: on a 404 (endpoint disabled / older server) DROP the event — do
|
|
12
|
+
* NOT enqueue. Queuing 404s head-of-line-poisons the offline queue against a
|
|
13
|
+
* server that will never accept them.
|
|
14
|
+
* - Kill #4/#5: writes are fire-and-forget and off the critical path. Recall of
|
|
15
|
+
* these hot entries stays gated on the server side (tier:"intra-session").
|
|
16
|
+
*
|
|
17
|
+
* On a transient network failure the event IS enqueued to the offline queue so
|
|
18
|
+
* a later drain retries it. Never throws; never blocks the workflow.
|
|
19
|
+
*/
|
|
20
|
+
import { classifyEeError, logEeFailure } from "../utils/ee-logger.js";
|
|
21
|
+
import { getCachedAuthToken, getCachedServerBaseUrl } from "./auth.js";
|
|
22
|
+
import { enqueue } from "./offline-queue.js";
|
|
23
|
+
const DEFAULT_BASE = "http://localhost:8082";
|
|
24
|
+
const DEFAULT_TIMEOUT_MS = 3000;
|
|
25
|
+
const ENDPOINT = "/api/workflow-event";
|
|
26
|
+
let _warnedOnce = false;
|
|
27
|
+
/**
|
|
28
|
+
* POST a workflow event. Returns `true` when the server accepted it, `false`
|
|
29
|
+
* otherwise (dropped on 404, enqueued on network error). Never throws.
|
|
30
|
+
*/
|
|
31
|
+
export async function fireWorkflowEvent(payload, opts = {}) {
|
|
32
|
+
const baseUrl = opts.baseUrl ?? getCachedServerBaseUrl() ?? DEFAULT_BASE;
|
|
33
|
+
const authToken = opts.authToken ?? getCachedAuthToken() ?? undefined;
|
|
34
|
+
const f = opts.fetchImpl ?? fetch;
|
|
35
|
+
const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
36
|
+
const doEnqueue = opts.enqueueImpl ?? enqueue;
|
|
37
|
+
const headers = { "Content-Type": "application/json" };
|
|
38
|
+
if (authToken)
|
|
39
|
+
headers.Authorization = `Bearer ${authToken}`;
|
|
40
|
+
try {
|
|
41
|
+
const resp = await f(`${baseUrl}${ENDPOINT}`, {
|
|
42
|
+
method: "POST",
|
|
43
|
+
headers,
|
|
44
|
+
body: JSON.stringify(payload),
|
|
45
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
46
|
+
});
|
|
47
|
+
if (resp.ok)
|
|
48
|
+
return true;
|
|
49
|
+
// 404 = endpoint disabled or older server → DROP (Kill #7: never queue 404s).
|
|
50
|
+
if (resp.status === 404)
|
|
51
|
+
return false;
|
|
52
|
+
// Other non-OK (5xx, etc.) → treat like a transient failure: enqueue.
|
|
53
|
+
await doEnqueue({ endpoint: ENDPOINT, body: payload, enqueuedAt: Date.now() }).catch(() => { });
|
|
54
|
+
if (!_warnedOnce) {
|
|
55
|
+
_warnedOnce = true;
|
|
56
|
+
console.warn(`[ee] workflow-event non-OK ${resp.status}; queued (silenced after first warning)`);
|
|
57
|
+
}
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
catch (err) {
|
|
61
|
+
// Network error / timeout → enqueue for later drain.
|
|
62
|
+
await doEnqueue({ endpoint: ENDPOINT, body: payload, enqueuedAt: Date.now() }).catch(() => { });
|
|
63
|
+
if (!_warnedOnce) {
|
|
64
|
+
_warnedOnce = true;
|
|
65
|
+
console.warn(`[ee] workflow-event failed: ${err.message}; queued (silenced after first warning)`);
|
|
66
|
+
}
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/** Fire-and-forget wrapper — never throws, never blocks the workflow. */
|
|
71
|
+
export function fireAndForgetWorkflowEvent(payload, opts = {}) {
|
|
72
|
+
void fireWorkflowEvent(payload, opts).catch((err) => {
|
|
73
|
+
logEeFailure("workflow-event.fireAndForgetWorkflowEvent", classifyEeError(err), err);
|
|
74
|
+
/* swallow */
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
/** Test-only: reset the once-per-process warning latch. */
|
|
78
|
+
export function _resetWorkflowEventState() {
|
|
79
|
+
_warnedOnce = false;
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=workflow-event.js.map
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Serializes messages, extracts preserved blocks, compresses if over budget,
|
|
5
5
|
* then restores preserved blocks into the output.
|
|
6
6
|
*/
|
|
7
|
-
import type
|
|
7
|
+
import { type ModelMessage } from "ai";
|
|
8
8
|
import { type PreservedBlock } from "./preserve.js";
|
|
9
9
|
export interface CompressResult {
|
|
10
10
|
summary: string;
|
|
@@ -17,6 +17,6 @@ export interface CompressResult {
|
|
|
17
17
|
* 1. Serialize messages via serializeConversation().
|
|
18
18
|
* 2. Extract preserved blocks.
|
|
19
19
|
* 3. If under budget, return as-is (with preserved blocks restored).
|
|
20
|
-
* 4. If over budget,
|
|
20
|
+
* 4. If over budget, compress via LLM (if provider given) or truncate, and restore blocks.
|
|
21
21
|
*/
|
|
22
|
-
export declare function compressChat(messages: ModelMessage[], _systemPrompt: string, tokenBudget: number,
|
|
22
|
+
export declare function compressChat(messages: ModelMessage[], _systemPrompt: string, tokenBudget: number, provider?: unknown, modelId?: string, customInstructions?: string): Promise<CompressResult>;
|