muonroi-cli 1.8.4 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +17 -5
- package/dist/packages/agent-harness-core/src/driver.d.ts +27 -1
- package/dist/packages/agent-harness-core/src/driver.js +46 -0
- package/dist/packages/agent-harness-core/src/event-filter.js +11 -0
- package/dist/packages/agent-harness-core/src/event-redact.js +7 -0
- package/dist/packages/agent-harness-core/src/event-tee.d.ts +64 -0
- package/dist/packages/agent-harness-core/src/event-tee.js +104 -0
- package/dist/packages/agent-harness-core/src/mcp-server.d.ts +25 -0
- package/dist/packages/agent-harness-core/src/mcp-server.js +169 -21
- package/dist/packages/agent-harness-core/src/predicate.d.ts +1 -1
- package/dist/packages/agent-harness-core/src/protocol.d.ts +90 -4
- package/dist/packages/agent-harness-core/src/protocol.js +15 -0
- package/dist/packages/agent-harness-core/src/visual-quality.d.ts +58 -0
- package/dist/packages/agent-harness-core/src/visual-quality.js +141 -0
- package/dist/packages/agent-harness-opentui/src/agent-mode.d.ts +6 -0
- package/dist/packages/agent-harness-opentui/src/agent-mode.js +14 -1
- package/dist/packages/agent-harness-opentui/src/input-bridge.d.ts +2 -10
- package/dist/packages/agent-harness-opentui/src/input-bridge.js +103 -16
- package/dist/packages/agent-harness-opentui/src/install.d.ts +8 -0
- package/dist/packages/agent-harness-opentui/src/install.js +10 -0
- package/dist/packages/agent-harness-opentui/src/semantic.js +12 -10
- package/dist/packages/agent-harness-opentui/src/visual-capture.d.ts +56 -0
- package/dist/packages/agent-harness-opentui/src/visual-capture.js +103 -0
- package/dist/src/agent-harness/mock-model.d.ts +38 -0
- package/dist/src/agent-harness/mock-model.js +69 -3
- package/dist/src/agent-harness/test-spawn.js +31 -0
- package/dist/src/chat/chat-keychain.d.ts +7 -12
- package/dist/src/chat/chat-keychain.js +19 -86
- package/dist/src/cli/config/screen-providers.js +1 -1
- package/dist/src/cli/cost-forensics.d.ts +10 -0
- package/dist/src/cli/cost-forensics.js +18 -3
- package/dist/src/cli/keys-bundle.d.ts +1 -1
- package/dist/src/cli/keys-bundle.js +1 -1
- package/dist/src/cli/keys.d.ts +10 -47
- package/dist/src/cli/keys.js +31 -399
- package/dist/src/council/clarifier.d.ts +31 -3
- package/dist/src/council/clarifier.js +220 -32
- package/dist/src/council/context.js +49 -15
- package/dist/src/council/debate-checkpoint.d.ts +129 -0
- package/dist/src/council/debate-checkpoint.js +176 -0
- package/dist/src/council/debate-planner.js +54 -5
- package/dist/src/council/debate-summary.d.ts +25 -0
- package/dist/src/council/debate-summary.js +85 -0
- package/dist/src/council/debate.d.ts +169 -2
- package/dist/src/council/debate.js +1265 -135
- package/dist/src/council/index.d.ts +108 -1
- package/dist/src/council/index.js +670 -197
- package/dist/src/council/leader.d.ts +26 -0
- package/dist/src/council/leader.js +150 -9
- package/dist/src/council/llm.d.ts +94 -0
- package/dist/src/council/llm.js +348 -55
- package/dist/src/council/panel-select.d.ts +30 -0
- package/dist/src/council/panel-select.js +82 -0
- package/dist/src/council/planner.js +40 -0
- package/dist/src/council/preflight.d.ts +17 -0
- package/dist/src/council/preflight.js +50 -2
- package/dist/src/council/prompts.d.ts +39 -4
- package/dist/src/council/prompts.js +256 -69
- package/dist/src/council/stance-recall.d.ts +42 -0
- package/dist/src/council/stance-recall.js +57 -0
- package/dist/src/council/strip-think.d.ts +17 -0
- package/dist/src/council/strip-think.js +33 -0
- package/dist/src/council/types.d.ts +138 -0
- package/dist/src/ee/artifact-cache.d.ts +16 -0
- package/dist/src/ee/artifact-cache.js +32 -0
- package/dist/src/ee/auth.d.ts +20 -0
- package/dist/src/ee/auth.js +54 -2
- package/dist/src/ee/bridge.d.ts +10 -0
- package/dist/src/ee/bridge.js +58 -0
- package/dist/src/ee/client.js +109 -21
- package/dist/src/ee/ee-onboarding.js +6 -26
- package/dist/src/ee/export-transcripts.d.ts +1 -0
- package/dist/src/ee/export-transcripts.js +8 -10
- package/dist/src/ee/extract-session.js +29 -0
- package/dist/src/ee/extract-style.d.ts +58 -0
- package/dist/src/ee/extract-style.js +270 -0
- package/dist/src/ee/recall-ledger.d.ts +9 -0
- package/dist/src/ee/recall-ledger.js +3 -0
- package/dist/src/ee/scope.d.ts +1 -0
- package/dist/src/ee/scope.js +26 -1
- package/dist/src/ee/search.d.ts +7 -0
- package/dist/src/ee/search.js +24 -0
- package/dist/src/ee/transcript-emit.js +2 -0
- package/dist/src/ee/types.d.ts +22 -0
- package/dist/src/ee/who-am-i-brain.d.ts +35 -0
- package/dist/src/ee/who-am-i-brain.js +220 -0
- package/dist/src/ee/who-am-i.d.ts +10 -3
- package/dist/src/ee/who-am-i.js +12 -0
- package/dist/src/ee/workflow-event.d.ts +48 -0
- package/dist/src/ee/workflow-event.js +81 -0
- package/dist/src/flow/compaction/compress.d.ts +3 -3
- package/dist/src/flow/compaction/compress.js +58 -8
- package/dist/src/flow/compaction/extract.d.ts +4 -7
- package/dist/src/flow/compaction/extract.js +50 -10
- package/dist/src/flow/compaction/index.d.ts +14 -1
- package/dist/src/flow/compaction/index.js +96 -3
- package/dist/src/flow/compaction/input-guard.d.ts +24 -0
- package/dist/src/flow/compaction/input-guard.js +43 -0
- package/dist/src/flow/compaction/progress.d.ts +35 -0
- package/dist/src/flow/compaction/progress.js +35 -0
- package/dist/src/flow/fold-planning.d.ts +36 -0
- package/dist/src/flow/fold-planning.js +83 -0
- package/dist/src/flow/hierarchy.d.ts +146 -0
- package/dist/src/flow/hierarchy.js +427 -0
- package/dist/src/flow/index.d.ts +1 -0
- package/dist/src/flow/index.js +2 -0
- package/dist/src/flow/run-artifacts.d.ts +102 -0
- package/dist/src/flow/run-artifacts.js +208 -0
- package/dist/src/generated/version.d.ts +1 -1
- package/dist/src/generated/version.js +1 -1
- package/dist/src/gsd/assessment-schema.d.ts +44 -0
- package/dist/src/gsd/assessment-schema.js +134 -0
- package/dist/src/gsd/capability-registry.d.ts +45 -0
- package/dist/src/gsd/capability-registry.js +337 -0
- package/dist/src/gsd/complexity-assessor.d.ts +39 -0
- package/dist/src/gsd/complexity-assessor.js +152 -0
- package/dist/src/gsd/config-bridge.d.ts +7 -0
- package/dist/src/gsd/config-bridge.js +114 -0
- package/dist/src/gsd/config-loader.d.ts +27 -0
- package/dist/src/gsd/config-loader.js +50 -0
- package/dist/src/gsd/council-context.d.ts +44 -0
- package/dist/src/gsd/council-context.js +114 -0
- package/dist/src/gsd/ee-closure.d.ts +28 -0
- package/dist/src/gsd/ee-closure.js +49 -0
- package/dist/src/gsd/flags.d.ts +66 -0
- package/dist/src/gsd/flags.js +102 -0
- package/dist/src/gsd/gsd-dispatch.d.ts +58 -0
- package/dist/src/gsd/gsd-dispatch.js +131 -0
- package/dist/src/gsd/gsd-runtime.d.ts +22 -0
- package/dist/src/gsd/gsd-runtime.js +37 -0
- package/dist/src/gsd/host-adapter.d.ts +11 -0
- package/dist/src/gsd/host-adapter.js +29 -0
- package/dist/src/gsd/index.d.ts +24 -1
- package/dist/src/gsd/index.js +27 -0
- package/dist/src/gsd/loop-host-contract.d.ts +21 -0
- package/dist/src/gsd/loop-host-contract.js +39 -0
- package/dist/src/gsd/loop-host.d.ts +69 -0
- package/dist/src/gsd/loop-host.js +245 -0
- package/dist/src/gsd/loop-resolver.d.ts +36 -0
- package/dist/src/gsd/loop-resolver.js +79 -0
- package/dist/src/gsd/model-tier.d.ts +13 -0
- package/dist/src/gsd/model-tier.js +45 -0
- package/dist/src/gsd/mutation-gate.d.ts +16 -0
- package/dist/src/gsd/mutation-gate.js +41 -0
- package/dist/src/gsd/native-roadmap.d.ts +89 -0
- package/dist/src/gsd/native-roadmap.js +343 -0
- package/dist/src/gsd/native-state.d.ts +47 -0
- package/dist/src/gsd/native-state.js +220 -0
- package/dist/src/gsd/paths.d.ts +23 -0
- package/dist/src/gsd/paths.js +66 -0
- package/dist/src/gsd/phase-dag.d.ts +12 -0
- package/dist/src/gsd/phase-dag.js +94 -0
- package/dist/src/gsd/phase-sync.d.ts +42 -0
- package/dist/src/gsd/phase-sync.js +321 -0
- package/dist/src/gsd/pil-gate-context.d.ts +13 -0
- package/dist/src/gsd/pil-gate-context.js +64 -0
- package/dist/src/gsd/pil-gate-critic.d.ts +19 -0
- package/dist/src/gsd/pil-gate-critic.js +74 -0
- package/dist/src/gsd/plan-council-prompts.d.ts +25 -0
- package/dist/src/gsd/plan-council-prompts.js +79 -0
- package/dist/src/gsd/plan-council.d.ts +44 -0
- package/dist/src/gsd/plan-council.js +283 -0
- package/dist/src/gsd/plan-gate-vocabulary.d.ts +40 -0
- package/dist/src/gsd/plan-gate-vocabulary.js +64 -0
- package/dist/src/gsd/product-workspace.d.ts +13 -0
- package/dist/src/gsd/product-workspace.js +124 -0
- package/dist/src/gsd/ship-bridge.d.ts +25 -0
- package/dist/src/gsd/ship-bridge.js +65 -0
- package/dist/src/gsd/state-document.d.ts +40 -0
- package/dist/src/gsd/state-document.js +163 -0
- package/dist/src/gsd/verdict-schema.d.ts +39 -0
- package/dist/src/gsd/verdict-schema.js +144 -0
- package/dist/src/gsd/verify-context.d.ts +22 -0
- package/dist/src/gsd/verify-context.js +27 -0
- package/dist/src/gsd/verify-council-prompts.d.ts +19 -0
- package/dist/src/gsd/verify-council-prompts.js +85 -0
- package/dist/src/gsd/verify-council.d.ts +25 -0
- package/dist/src/gsd/verify-council.js +119 -0
- package/dist/src/gsd/verify-gate-vocabulary.d.ts +25 -0
- package/dist/src/gsd/verify-gate-vocabulary.js +46 -0
- package/dist/src/gsd/workflow-engine.d.ts +60 -0
- package/dist/src/gsd/workflow-engine.js +207 -0
- package/dist/src/gsd/workflow-tools.d.ts +13 -0
- package/dist/src/gsd/workflow-tools.js +277 -0
- package/dist/src/headless/council-answers.js +4 -0
- package/dist/src/hooks/index.js +1 -1
- package/dist/src/index.js +172 -270
- package/dist/src/lsp/builtins.js +3 -1
- package/dist/src/lsp/manager.d.ts +5 -1
- package/dist/src/lsp/manager.js +249 -3
- package/dist/src/lsp/npm-cache.d.ts +11 -1
- package/dist/src/lsp/npm-cache.js +17 -1
- package/dist/src/lsp/runtime.d.ts +6 -1
- package/dist/src/lsp/runtime.js +17 -1
- package/dist/src/lsp/types.d.ts +83 -1
- package/dist/src/lsp/types.js +10 -0
- package/dist/src/maintain/pr-builder.js +23 -13
- package/dist/src/mcp/auto-setup.js +57 -32
- package/dist/src/mcp/client-pool.js +44 -16
- package/dist/src/mcp/lsp-tools.d.ts +5 -1
- package/dist/src/mcp/lsp-tools.js +93 -2
- package/dist/src/mcp/mcp-keychain.d.ts +3 -5
- package/dist/src/mcp/mcp-keychain.js +9 -49
- package/dist/src/mcp/research-onboarding.js +8 -7
- package/dist/src/mcp/runtime.js +34 -2
- package/dist/src/mcp/setup-guide-text.d.ts +1 -1
- package/dist/src/mcp/setup-guide-text.js +22 -2
- package/dist/src/mcp/tools-server.d.ts +10 -0
- package/dist/src/mcp/tools-server.js +10 -2
- package/dist/src/models/catalog-client.d.ts +87 -0
- package/dist/src/models/catalog-client.js +105 -38
- package/dist/src/models/catalog.json +528 -265
- package/dist/src/models/registry.d.ts +22 -7
- package/dist/src/models/registry.js +73 -10
- package/dist/src/ops/doctor.js +1 -1
- package/dist/src/orchestrator/ask-user.d.ts +61 -0
- package/dist/src/orchestrator/ask-user.js +65 -0
- package/dist/src/orchestrator/auto-commit.js +1 -1
- package/dist/src/orchestrator/batch-turn-runner.js +2 -2
- package/dist/src/orchestrator/cache-prefix.d.ts +67 -0
- package/dist/src/orchestrator/cache-prefix.js +83 -0
- package/dist/src/orchestrator/compact-request.d.ts +32 -0
- package/dist/src/orchestrator/compact-request.js +41 -0
- package/dist/src/orchestrator/compaction.d.ts +12 -3
- package/dist/src/orchestrator/compaction.js +35 -15
- package/dist/src/orchestrator/council-manager.d.ts +12 -3
- package/dist/src/orchestrator/council-manager.js +74 -32
- package/dist/src/orchestrator/council-request.d.ts +49 -0
- package/dist/src/orchestrator/council-request.js +62 -0
- package/dist/src/orchestrator/cross-turn-dedup.d.ts +6 -0
- package/dist/src/orchestrator/cross-turn-dedup.js +22 -1
- package/dist/src/orchestrator/error-utils.d.ts +29 -0
- package/dist/src/orchestrator/error-utils.js +132 -24
- package/dist/src/orchestrator/grounding-check.js +39 -1
- package/dist/src/orchestrator/interactive-pause.d.ts +26 -0
- package/dist/src/orchestrator/interactive-pause.js +36 -0
- package/dist/src/orchestrator/message-processor.d.ts +4 -0
- package/dist/src/orchestrator/message-processor.js +268 -41
- package/dist/src/orchestrator/orchestrator.d.ts +64 -3
- package/dist/src/orchestrator/orchestrator.js +823 -120
- package/dist/src/orchestrator/preprocessor.js +3 -3
- package/dist/src/orchestrator/proactive-compact-detector.d.ts +26 -0
- package/dist/src/orchestrator/proactive-compact-detector.js +36 -0
- package/dist/src/orchestrator/prompts.js +17 -17
- package/dist/src/orchestrator/reactive-delegation.d.ts +39 -0
- package/dist/src/orchestrator/reactive-delegation.js +59 -0
- package/dist/src/orchestrator/retry-classifier.d.ts +2 -1
- package/dist/src/orchestrator/retry-classifier.js +46 -2
- package/dist/src/orchestrator/safety-askcard.d.ts +1 -1
- package/dist/src/orchestrator/safety-askcard.js +5 -2
- package/dist/src/orchestrator/safety-intercept.d.ts +50 -0
- package/dist/src/orchestrator/safety-intercept.js +62 -0
- package/dist/src/orchestrator/scope-reminder.js +1 -1
- package/dist/src/orchestrator/session-experience.d.ts +2 -1
- package/dist/src/orchestrator/session-experience.js +2 -1
- package/dist/src/orchestrator/should-run-gate.d.ts +5 -0
- package/dist/src/orchestrator/should-run-gate.js +18 -0
- package/dist/src/orchestrator/stall-watchdog.d.ts +31 -3
- package/dist/src/orchestrator/stall-watchdog.js +65 -10
- package/dist/src/orchestrator/stream-runner.d.ts +13 -3
- package/dist/src/orchestrator/stream-runner.js +115 -49
- package/dist/src/orchestrator/sub-agent-cap.d.ts +13 -1
- package/dist/src/orchestrator/sub-agent-cap.js +16 -1
- package/dist/src/orchestrator/sub-agent-model-tier.d.ts +13 -1
- package/dist/src/orchestrator/sub-agent-model-tier.js +16 -2
- package/dist/src/orchestrator/subagent-compactor.d.ts +53 -1
- package/dist/src/orchestrator/subagent-compactor.js +126 -15
- package/dist/src/orchestrator/tool-engine.d.ts +41 -0
- package/dist/src/orchestrator/tool-engine.js +846 -66
- package/dist/src/orchestrator/tool-limit-auto-recover.d.ts +22 -0
- package/dist/src/orchestrator/tool-limit-auto-recover.js +30 -0
- package/dist/src/orchestrator/turn-runner-deps.d.ts +19 -0
- package/dist/src/orchestrator/turn-watchdog.d.ts +44 -0
- package/dist/src/orchestrator/turn-watchdog.js +84 -0
- package/dist/src/pil/agent-operating-contract.d.ts +1 -1
- package/dist/src/pil/agent-operating-contract.js +6 -4
- package/dist/src/pil/cheap-model-playbook.d.ts +1 -1
- package/dist/src/pil/cheap-model-playbook.js +5 -1
- package/dist/src/pil/cheap-model-workbooks.d.ts +1 -1
- package/dist/src/pil/cheap-model-workbooks.js +1 -1
- package/dist/src/pil/discovery-types.d.ts +1 -0
- package/dist/src/pil/discovery.d.ts +1 -1
- package/dist/src/pil/discovery.js +18 -13
- package/dist/src/pil/layer1-intent.d.ts +18 -6
- package/dist/src/pil/layer1-intent.js +66 -757
- package/dist/src/pil/layer15-context-scan.js +15 -1
- package/dist/src/pil/layer1_5-complexity-size.d.ts +7 -0
- package/dist/src/pil/layer1_5-complexity-size.js +31 -5
- package/dist/src/pil/layer3-ee-injection.js +23 -8
- package/dist/src/pil/layer4-gsd.js +69 -16
- package/dist/src/pil/layer5-context.js +7 -3
- package/dist/src/pil/layer6-output.d.ts +23 -0
- package/dist/src/pil/layer6-output.js +5 -1
- package/dist/src/pil/llm-classify.d.ts +111 -5
- package/dist/src/pil/llm-classify.js +421 -189
- package/dist/src/pil/native-capabilities-workbook.d.ts +1 -1
- package/dist/src/pil/native-capabilities-workbook.js +8 -0
- package/dist/src/pil/pipeline.js +36 -2
- package/dist/src/pil/repo-grounding-probe.d.ts +15 -0
- package/dist/src/pil/repo-grounding-probe.js +136 -0
- package/dist/src/pil/repo-structure-hints.d.ts +7 -0
- package/dist/src/pil/repo-structure-hints.js +45 -0
- package/dist/src/pil/response-tools.js +5 -3
- package/dist/src/pil/schema.d.ts +1 -0
- package/dist/src/pil/schema.js +2 -0
- package/dist/src/pil/types.d.ts +18 -0
- package/dist/src/playbook/directives.d.ts +4 -0
- package/dist/src/playbook/directives.js +17 -5
- package/dist/src/product-loop/artifact-io.js +4 -0
- package/dist/src/product-loop/backlog-builder.d.ts +14 -1
- package/dist/src/product-loop/backlog-builder.js +30 -6
- package/dist/src/product-loop/criteria-seed.d.ts +51 -0
- package/dist/src/product-loop/criteria-seed.js +200 -0
- package/dist/src/product-loop/discovery-context-format.js +3 -1
- package/dist/src/product-loop/discovery-ecosystem.js +4 -1
- package/dist/src/product-loop/discovery-interview.d.ts +9 -0
- package/dist/src/product-loop/discovery-interview.js +60 -12
- package/dist/src/product-loop/discovery-recommender.js +2 -1
- package/dist/src/product-loop/discovery-schema.js +19 -2
- package/dist/src/product-loop/discovery-triage.d.ts +23 -0
- package/dist/src/product-loop/discovery-triage.js +109 -0
- package/dist/src/product-loop/gather.js +150 -2
- package/dist/src/product-loop/ideal-trace.d.ts +7 -0
- package/dist/src/product-loop/ideal-trace.js +64 -0
- package/dist/src/product-loop/index.d.ts +13 -1
- package/dist/src/product-loop/index.js +340 -52
- package/dist/src/product-loop/loop-driver.d.ts +7 -0
- package/dist/src/product-loop/loop-driver.js +330 -106
- package/dist/src/product-loop/phase-plan.d.ts +21 -0
- package/dist/src/product-loop/phase-plan.js +81 -6
- package/dist/src/product-loop/phase-rituals.d.ts +3 -0
- package/dist/src/product-loop/phase-rituals.js +8 -3
- package/dist/src/product-loop/phase-runner.js +39 -12
- package/dist/src/product-loop/plan-adherence-review.d.ts +26 -0
- package/dist/src/product-loop/plan-adherence-review.js +144 -0
- package/dist/src/product-loop/sprint-runner.d.ts +173 -0
- package/dist/src/product-loop/sprint-runner.js +863 -19
- package/dist/src/product-loop/types.d.ts +61 -5
- package/dist/src/providers/adapter.d.ts +1 -1
- package/dist/src/providers/adapter.js +3 -4
- package/dist/src/providers/anthropic.d.ts +9 -8
- package/dist/src/providers/anthropic.js +13 -47
- package/dist/src/providers/auth/browser-flow.d.ts +1 -1
- package/dist/src/providers/auth/browser-flow.js +1 -1
- package/dist/src/providers/auth/grok-oauth.d.ts +1 -0
- package/dist/src/providers/auth/grok-oauth.js +30 -5
- package/dist/src/providers/auth/openai-oauth.d.ts +1 -0
- package/dist/src/providers/auth/openai-oauth.js +15 -1
- package/dist/src/providers/auth/registry.js +0 -34
- package/dist/src/providers/auth/token-store.d.ts +9 -9
- package/dist/src/providers/auth/token-store.js +8 -67
- package/dist/src/providers/auth/types.d.ts +9 -1
- package/dist/src/providers/auth/types.js +1 -1
- package/dist/src/providers/capabilities.d.ts +24 -5
- package/dist/src/providers/capabilities.js +42 -24
- package/dist/src/providers/endpoints.d.ts +2 -2
- package/dist/src/providers/endpoints.js +11 -10
- package/dist/src/providers/env-store.d.ts +17 -0
- package/dist/src/providers/env-store.js +228 -0
- package/dist/src/providers/keychain.d.ts +22 -18
- package/dist/src/providers/keychain.js +127 -140
- package/dist/src/providers/mcp-vision-bridge.js +56 -146
- package/dist/src/providers/openai-compatible.js +8 -1
- package/dist/src/providers/pricing.d.ts +2 -2
- package/dist/src/providers/pricing.js +3 -13
- package/dist/src/providers/runtime.d.ts +43 -3
- package/dist/src/providers/runtime.js +88 -14
- package/dist/src/providers/strategies/base.strategy.d.ts +16 -0
- package/dist/src/providers/strategies/base.strategy.js +24 -1
- package/dist/src/providers/strategies/{siliconflow.strategy.d.ts → opencode-go.strategy.d.ts} +3 -3
- package/dist/src/providers/strategies/opencode-go.strategy.js +83 -0
- package/dist/src/providers/strategies/registry.js +4 -4
- package/dist/src/providers/strategies/thinking-mode.d.ts +109 -0
- package/dist/src/providers/strategies/thinking-mode.js +288 -1
- package/dist/src/providers/strategies/xai.strategy.js +27 -0
- package/dist/src/providers/strategies/zai.strategy.d.ts +14 -0
- package/dist/src/providers/strategies/zai.strategy.js +44 -0
- package/dist/src/providers/types.d.ts +5 -6
- package/dist/src/providers/types.js +2 -2
- package/dist/src/providers/vision-backend.d.ts +47 -0
- package/dist/src/providers/vision-backend.js +258 -0
- package/dist/src/providers/vision-proxy.d.ts +22 -9
- package/dist/src/providers/vision-proxy.js +63 -132
- package/dist/src/providers/warm.d.ts +65 -0
- package/dist/src/providers/warm.js +145 -0
- package/dist/src/providers/wire-debug.js +95 -0
- package/dist/src/router/decide.d.ts +13 -0
- package/dist/src/router/decide.js +138 -36
- package/dist/src/router/peak-hour.d.ts +38 -0
- package/dist/src/router/peak-hour.js +107 -0
- package/dist/src/router/step-router.js +3 -2
- package/dist/src/router/warm.js +4 -5
- package/dist/src/scaffold/continuation-prompt.d.ts +11 -0
- package/dist/src/scaffold/continuation-prompt.js +26 -0
- package/dist/src/scaffold/point-to-existing.d.ts +21 -0
- package/dist/src/scaffold/point-to-existing.js +25 -0
- package/dist/src/self-qa/agentic-loop.js +6 -5
- package/dist/src/{ui/state → state}/active-run.d.ts +19 -0
- package/dist/src/{ui/state → state}/active-run.js +21 -0
- package/dist/src/{ui/status-bar/store.d.ts → state/status-bar-store.d.ts} +4 -1
- package/dist/src/{ui/status-bar/store.js → state/status-bar-store.js} +12 -9
- package/dist/src/state/turn-trace.d.ts +43 -0
- package/dist/src/state/turn-trace.js +32 -0
- package/dist/src/storage/db.js +2 -1
- package/dist/src/storage/index.d.ts +1 -1
- package/dist/src/storage/index.js +1 -1
- package/dist/src/storage/interaction-log.d.ts +1 -1
- package/dist/src/storage/migrations.js +71 -1
- package/dist/src/storage/sessions.d.ts +28 -10
- package/dist/src/storage/sessions.js +78 -21
- package/dist/src/storage/transcript-view.js +1 -1
- package/dist/src/storage/transcript.d.ts +51 -0
- package/dist/src/storage/transcript.js +340 -15
- package/dist/src/tools/file.d.ts +15 -0
- package/dist/src/tools/file.js +32 -0
- package/dist/src/tools/git-safety.d.ts +19 -0
- package/dist/src/tools/git-safety.js +168 -0
- package/dist/src/tools/native-tools.d.ts +1 -1
- package/dist/src/tools/native-tools.js +81 -1
- package/dist/src/tools/registry.d.ts +20 -0
- package/dist/src/tools/registry.js +576 -23
- package/dist/src/tools/research.d.ts +29 -0
- package/dist/src/tools/research.js +233 -0
- package/dist/src/types/index.d.ts +147 -4
- package/dist/src/ui/app.js +0 -0
- package/dist/src/ui/cards/product-status-card.js +1 -1
- package/dist/src/ui/components/agent-rail-activities.d.ts +26 -0
- package/dist/src/ui/components/agent-rail-activities.js +47 -0
- package/dist/src/ui/components/bubble-body-guard.d.ts +27 -0
- package/dist/src/ui/components/bubble-body-guard.js +50 -0
- package/dist/src/ui/components/compact-progress-card.d.ts +24 -0
- package/dist/src/ui/components/compact-progress-card.js +42 -0
- package/dist/src/ui/components/context-rail.d.ts +26 -0
- package/dist/src/ui/components/context-rail.js +33 -0
- package/dist/src/ui/components/council-conclusion-card.d.ts +73 -0
- package/dist/src/ui/components/council-conclusion-card.js +420 -0
- package/dist/src/ui/components/council-debate-pill.d.ts +36 -0
- package/dist/src/ui/components/council-debate-pill.js +34 -0
- package/dist/src/ui/components/council-info-card.js +2 -2
- package/dist/src/ui/components/council-leader-bubble.d.ts +10 -3
- package/dist/src/ui/components/council-leader-bubble.js +21 -11
- package/dist/src/ui/components/council-message-bubble.d.ts +15 -2
- package/dist/src/ui/components/council-message-bubble.js +16 -15
- package/dist/src/ui/components/council-phase-timeline.d.ts +9 -1
- package/dist/src/ui/components/council-phase-timeline.js +66 -17
- package/dist/src/ui/components/council-placeholder-bubble.d.ts +16 -9
- package/dist/src/ui/components/council-placeholder-bubble.js +32 -29
- package/dist/src/ui/components/council-question-card.js +13 -12
- package/dist/src/ui/components/council-rail-rounds.d.ts +26 -0
- package/dist/src/ui/components/council-rail-rounds.js +57 -0
- package/dist/src/ui/components/council-round-group.d.ts +38 -0
- package/dist/src/ui/components/council-round-group.js +88 -0
- package/dist/src/ui/components/council-status-list.d.ts +3 -1
- package/dist/src/ui/components/council-status-list.js +36 -24
- package/dist/src/ui/components/council-synthesis-banner.d.ts +7 -2
- package/dist/src/ui/components/council-synthesis-banner.js +20 -5
- package/dist/src/ui/components/halt-recovery-card.js +9 -5
- package/dist/src/ui/components/jump-to-latest-pill.d.ts +11 -0
- package/dist/src/ui/components/jump-to-latest-pill.js +14 -0
- package/dist/src/ui/components/message-view.d.ts +15 -0
- package/dist/src/ui/components/message-view.js +50 -1
- package/dist/src/ui/components/prompt-box.js +18 -16
- package/dist/src/ui/components/session-tree-card.d.ts +14 -0
- package/dist/src/ui/components/session-tree-card.js +46 -0
- package/dist/src/ui/components/slash-inline-menu.d.ts +12 -0
- package/dist/src/ui/components/slash-inline-menu.js +26 -5
- package/dist/src/ui/components/task-list-panel.d.ts +14 -1
- package/dist/src/ui/components/task-list-panel.js +22 -2
- package/dist/src/ui/components/tool-group.d.ts +15 -3
- package/dist/src/ui/components/tool-group.js +69 -11
- package/dist/src/ui/containers/modals-layer.d.ts +4 -2
- package/dist/src/ui/containers/modals-layer.js +2 -2
- package/dist/src/ui/council-harness-event.d.ts +57 -0
- package/dist/src/ui/council-harness-event.js +46 -0
- package/dist/src/ui/heartbeat-debug.d.ts +29 -0
- package/dist/src/ui/heartbeat-debug.js +45 -0
- package/dist/src/ui/hooks/use-session-picker.d.ts +3 -3
- package/dist/src/ui/mcp-modal.js +2 -4
- package/dist/src/ui/modals/api-key-modal.js +1 -1
- package/dist/src/ui/modals/connect-modal.js +4 -3
- package/dist/src/ui/modals/model-picker-modal.d.ts +8 -18
- package/dist/src/ui/modals/model-picker-modal.js +8 -10
- package/dist/src/ui/modals/session-picker-modal.d.ts +2 -2
- package/dist/src/ui/modals/session-picker-modal.js +3 -5
- package/dist/src/ui/picker-providers.d.ts +1 -1
- package/dist/src/ui/picker-providers.js +1 -1
- package/dist/src/ui/primitives/index.d.ts +1 -0
- package/dist/src/ui/primitives/index.js +2 -0
- package/dist/src/ui/primitives/semantic-primitives.d.ts +76 -0
- package/dist/src/ui/primitives/semantic-primitives.js +81 -0
- package/dist/src/ui/slash/compact.js +5 -7
- package/dist/src/ui/slash/cost.js +1 -1
- package/dist/src/ui/slash/council.js +19 -1
- package/dist/src/ui/slash/debug.d.ts +3 -31
- package/dist/src/ui/slash/debug.js +9 -20
- package/dist/src/ui/slash/ee.js +81 -0
- package/dist/src/ui/slash/ideal.d.ts +6 -2
- package/dist/src/ui/slash/ideal.js +97 -7
- package/dist/src/ui/slash/menu-items.d.ts +7 -0
- package/dist/src/ui/slash/menu-items.js +23 -20
- package/dist/src/ui/slash/registry.d.ts +2 -0
- package/dist/src/ui/slash/registry.js +4 -0
- package/dist/src/ui/status-bar/cache-hit.d.ts +6 -0
- package/dist/src/ui/status-bar/cache-hit.js +9 -0
- package/dist/src/ui/status-bar/index.d.ts +1 -1
- package/dist/src/ui/status-bar/index.js +7 -3
- package/dist/src/ui/status-bar/usd-meter.d.ts +5 -4
- package/dist/src/ui/status-bar/usd-meter.js +6 -4
- package/dist/src/ui/theme.d.ts +1 -0
- package/dist/src/ui/theme.js +2 -0
- package/dist/src/ui/types.d.ts +7 -0
- package/dist/src/ui/use-app-logic.js +0 -0
- package/dist/src/ui/utils/agent-activities.d.ts +39 -0
- package/dist/src/ui/utils/agent-activities.js +96 -0
- package/dist/src/ui/utils/format.d.ts +14 -0
- package/dist/src/ui/utils/format.js +23 -3
- package/dist/src/ui/utils/group-tool-entries.d.ts +26 -0
- package/dist/src/ui/utils/group-tool-entries.js +111 -0
- package/dist/src/ui/utils/tool-summary.d.ts +21 -0
- package/dist/src/ui/utils/tool-summary.js +91 -0
- package/dist/src/usage/downgrade.js +2 -2
- package/dist/src/usage/product-ledger.js +2 -2
- package/dist/src/utils/event-loop-monitor.d.ts +85 -0
- package/dist/src/utils/event-loop-monitor.js +107 -0
- package/dist/src/utils/install-manager.js +2 -1
- package/dist/src/utils/llm-deadline.d.ts +14 -0
- package/dist/src/utils/llm-deadline.js +19 -0
- package/dist/src/utils/logger.js +2 -2
- package/dist/src/utils/loop-profiler.d.ts +102 -0
- package/dist/src/utils/loop-profiler.js +202 -0
- package/dist/src/utils/permission-mode.js +5 -3
- package/dist/src/utils/redactor.js +1 -1
- package/dist/src/utils/settings.d.ts +180 -5
- package/dist/src/utils/settings.js +271 -31
- package/dist/src/utils/side-question.d.ts +1 -2
- package/dist/src/utils/side-question.js +2 -2
- package/dist/src/utils/visible-retry.d.ts +11 -0
- package/dist/src/utils/visible-retry.js +10 -1
- package/dist/src/verify/entrypoint.d.ts +1 -1
- package/dist/src/verify/entrypoint.js +52 -17
- package/dist/src/verify/orchestrator.d.ts +1 -1
- package/dist/src/verify/orchestrator.js +20 -3
- package/dist/src/verify/recipes.d.ts +13 -0
- package/dist/src/verify/recipes.js +15 -0
- package/package.json +134 -132
- package/dist/src/cli/bw-vault.d.ts +0 -55
- package/dist/src/cli/bw-vault.js +0 -133
- package/dist/src/mcp/ee-tools.d.ts +0 -46
- package/dist/src/mcp/ee-tools.js +0 -193
- package/dist/src/providers/auth/gcloud.d.ts +0 -28
- package/dist/src/providers/auth/gcloud.js +0 -102
- package/dist/src/providers/auth/gemini-oauth.d.ts +0 -82
- package/dist/src/providers/auth/gemini-oauth.js +0 -472
- package/dist/src/providers/gemini.d.ts +0 -11
- package/dist/src/providers/gemini.js +0 -45
- package/dist/src/providers/siliconflow-sse-repair.d.ts +0 -58
- package/dist/src/providers/siliconflow-sse-repair.js +0 -177
- package/dist/src/providers/strategies/google.strategy.d.ts +0 -22
- package/dist/src/providers/strategies/google.strategy.js +0 -174
- package/dist/src/providers/strategies/siliconflow.strategy.js +0 -29
- package/dist/src/ui/containers/chat-feed.d.ts +0 -40
- package/dist/src/ui/containers/chat-feed.js +0 -66
|
@@ -1,49 +1,30 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* src/providers/keychain.ts
|
|
3
3
|
*
|
|
4
|
-
* Per-provider
|
|
5
|
-
*
|
|
6
|
-
* PROV-02 / PROV-03 requirements.
|
|
4
|
+
* Per-provider key store. Backed by the env-store (`.env` file + process.env +
|
|
5
|
+
* Windows registry mirror) — the OS keychain (keytar) has been removed.
|
|
7
6
|
*
|
|
8
|
-
*
|
|
7
|
+
* Source of truth: `process.env[ENV_BY_PROVIDER[provider]]`. Writes go through
|
|
8
|
+
* the env-store; reads come straight from process.env.
|
|
9
9
|
* Exception: ollama is keyless by default.
|
|
10
10
|
*/
|
|
11
11
|
import { redactor } from "../utils/redactor.js";
|
|
12
|
+
import { clearEnvVar, persistEnvVar } from "./env-store.js";
|
|
12
13
|
import { ALL_PROVIDER_IDS } from "./types.js";
|
|
13
14
|
function normalizeKeychainProvider(p) {
|
|
14
15
|
const lower = p.toLowerCase();
|
|
15
|
-
if (lower === "agy")
|
|
16
|
-
return "google"; // agy alias for google provider
|
|
17
16
|
if (ALL_PROVIDER_IDS.includes(lower))
|
|
18
17
|
return lower;
|
|
19
18
|
return null;
|
|
20
19
|
}
|
|
21
|
-
const
|
|
22
|
-
anthropic: "anthropic",
|
|
23
|
-
openai: "openai",
|
|
24
|
-
google: "google",
|
|
25
|
-
deepseek: "deepseek",
|
|
26
|
-
siliconflow: "siliconflow",
|
|
27
|
-
xai: "xai",
|
|
28
|
-
};
|
|
29
|
-
const KEYCHAIN_SERVICE = "muonroi-cli";
|
|
30
|
-
const ACCOUNT_BY_PROVIDER = {
|
|
31
|
-
anthropic: "anthropic",
|
|
32
|
-
openai: "openai",
|
|
33
|
-
google: "google",
|
|
34
|
-
deepseek: "deepseek",
|
|
35
|
-
siliconflow: "siliconflow",
|
|
36
|
-
xai: "xai",
|
|
37
|
-
ollama: "ollama",
|
|
38
|
-
};
|
|
39
|
-
const ENV_BY_PROVIDER = {
|
|
20
|
+
export const ENV_BY_PROVIDER = {
|
|
40
21
|
anthropic: "ANTHROPIC_API_KEY",
|
|
41
22
|
openai: "OPENAI_API_KEY",
|
|
42
|
-
google: "GOOGLE_API_KEY",
|
|
43
23
|
deepseek: "DEEPSEEK_API_KEY",
|
|
44
|
-
siliconflow: "SILICONFLOW_API_KEY",
|
|
45
24
|
xai: "XAI_API_KEY",
|
|
46
25
|
ollama: "OLLAMA_API_KEY",
|
|
26
|
+
zai: "ZAI_API_KEY",
|
|
27
|
+
"opencode-go": "OPENCODE_GO_API_KEY",
|
|
47
28
|
};
|
|
48
29
|
/**
|
|
49
30
|
* Thrown when no API key can be found for a provider.
|
|
@@ -56,147 +37,83 @@ export class ProviderKeyMissingError extends Error {
|
|
|
56
37
|
this.name = "ProviderKeyMissingError";
|
|
57
38
|
}
|
|
58
39
|
}
|
|
59
|
-
async function loadKeytar() {
|
|
60
|
-
try {
|
|
61
|
-
return (await import("keytar"));
|
|
62
|
-
}
|
|
63
|
-
catch {
|
|
64
|
-
return null;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
40
|
/**
|
|
68
|
-
* Providers that store an API key
|
|
69
|
-
*
|
|
70
|
-
* (keyless local server). Preserves the original ordering.
|
|
41
|
+
* Providers that store an API key (all except keyless ollama). Derived from
|
|
42
|
+
* `ALL_PROVIDER_IDS`; preserves the original ordering.
|
|
71
43
|
*/
|
|
72
44
|
export const KEYCHAIN_PROVIDER_IDS = ALL_PROVIDER_IDS.filter((p) => p !== "ollama");
|
|
73
45
|
/**
|
|
74
|
-
* Store a provider API key in the OS
|
|
75
|
-
*
|
|
46
|
+
* Store a provider API key in the OS environment (via the env-store: `.env`
|
|
47
|
+
* file + process.env + Windows registry mirror). Returns true on success.
|
|
76
48
|
*/
|
|
77
49
|
export async function setKeyForProvider(provider, key) {
|
|
78
50
|
const norm = normalizeKeychainProvider(provider) ?? provider;
|
|
79
51
|
if (!key || key.length < 20) {
|
|
80
52
|
throw new Error(`Key for '${provider}' is too short (< 20 chars).`);
|
|
81
53
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
redactor.enrollSecret(key);
|
|
54
|
+
persistEnvVar(ENV_BY_PROVIDER[norm], key);
|
|
55
|
+
// One auth mode per provider (OAuth XOR API key): setting an API key logs out
|
|
56
|
+
// any OAuth session for this provider so the two can never coexist.
|
|
86
57
|
try {
|
|
87
|
-
await
|
|
88
|
-
|
|
58
|
+
const { listOAuthProviderIds } = await import("./auth/registry.js");
|
|
59
|
+
if ((await listOAuthProviderIds()).includes(norm)) {
|
|
60
|
+
const { deleteTokens } = await import("./auth/token-store.js");
|
|
61
|
+
await deleteTokens(norm);
|
|
62
|
+
}
|
|
89
63
|
}
|
|
90
64
|
catch (err) {
|
|
91
|
-
//
|
|
92
|
-
//
|
|
93
|
-
//
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
console.error(`[keychain] setPassword backend error for ${provider}:`, err?.message || err);
|
|
65
|
+
// Best-effort: the key is already persisted; failing to clear tokens is
|
|
66
|
+
// non-fatal (resolution still prefers the freshly-set key path only if no
|
|
67
|
+
// token — but we log so a lingering token is diagnosable).
|
|
68
|
+
if (process.env.MUONROI_DEBUG_ENVSTORE) {
|
|
69
|
+
console.error(`[keychain] failed to clear OAuth for ${norm}: ${err instanceof Error ? err.message : String(err)}`);
|
|
97
70
|
}
|
|
98
|
-
return false;
|
|
99
71
|
}
|
|
72
|
+
return true;
|
|
100
73
|
}
|
|
101
74
|
/**
|
|
102
|
-
* Delete a stored key. Returns true if a key was
|
|
103
|
-
* present or keytar is unavailable.
|
|
75
|
+
* Delete a stored key from the env-store. Returns true if a key was present.
|
|
104
76
|
*/
|
|
105
77
|
export async function deleteKeyForProvider(provider) {
|
|
106
78
|
const norm = normalizeKeychainProvider(provider) ?? provider;
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
try {
|
|
111
|
-
return await kt.deletePassword(KEYCHAIN_SERVICE, ACCOUNT_BY_PROVIDER[norm]);
|
|
112
|
-
}
|
|
113
|
-
catch (err) {
|
|
114
|
-
if (process.env.DEBUG || process.env.MUONROI_DEBUG_KEYCHAIN) {
|
|
115
|
-
console.error(`[keychain] deletePassword backend error for ${provider}:`, err?.message || err);
|
|
116
|
-
}
|
|
117
|
-
return false;
|
|
118
|
-
}
|
|
79
|
+
const had = !!process.env[ENV_BY_PROVIDER[norm]];
|
|
80
|
+
clearEnvVar(ENV_BY_PROVIDER[norm]);
|
|
81
|
+
return had;
|
|
119
82
|
}
|
|
120
83
|
/**
|
|
121
|
-
* List provider IDs that currently have a key
|
|
122
|
-
* Empty array if keytar is unavailable.
|
|
84
|
+
* List provider IDs that currently have a key set in the environment.
|
|
123
85
|
*/
|
|
124
86
|
export async function listStoredProviders() {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
return
|
|
128
|
-
|
|
129
|
-
const creds = await kt.findCredentials(KEYCHAIN_SERVICE);
|
|
130
|
-
const validAccounts = new Set(Object.values(ACCOUNT_BY_PROVIDER));
|
|
131
|
-
return creds.filter((c) => validAccounts.has(c.account)).map((c) => c.account);
|
|
132
|
-
}
|
|
133
|
-
catch {
|
|
134
|
-
return [];
|
|
135
|
-
}
|
|
87
|
+
return KEYCHAIN_PROVIDER_IDS.filter((p) => {
|
|
88
|
+
const v = process.env[ENV_BY_PROVIDER[p]];
|
|
89
|
+
return !!v && v.length >= 20;
|
|
90
|
+
});
|
|
136
91
|
}
|
|
137
92
|
/**
|
|
138
|
-
* Load the API key for a given provider.
|
|
139
|
-
* Priority: OS keychain (keytar) > environment variable.
|
|
93
|
+
* Load the API key for a given provider from the environment.
|
|
140
94
|
* Ollama returns '' when no key is found (keyless).
|
|
141
95
|
*
|
|
142
96
|
* @throws {ProviderKeyMissingError} when no key found for non-ollama providers.
|
|
143
97
|
*/
|
|
144
98
|
export async function loadKeyForProvider(provider) {
|
|
145
|
-
const kt = await loadKeytar();
|
|
146
|
-
if (kt) {
|
|
147
|
-
try {
|
|
148
|
-
const k = await kt.getPassword(KEYCHAIN_SERVICE, ACCOUNT_BY_PROVIDER[provider]);
|
|
149
|
-
if (k && k.length >= 20) {
|
|
150
|
-
redactor.enrollSecret(k);
|
|
151
|
-
return k;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
catch {
|
|
155
|
-
/* ignore keytar backend failures */
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
99
|
const envKey = process.env[ENV_BY_PROVIDER[provider]];
|
|
159
100
|
if (envKey && envKey.length >= 20) {
|
|
160
101
|
redactor.enrollSecret(envKey);
|
|
161
102
|
return envKey;
|
|
162
103
|
}
|
|
163
|
-
// Fallback: check user-settings.json providers config (lazy import to avoid circular deps)
|
|
164
|
-
const settingsField = SETTINGS_KEY_MAP[provider];
|
|
165
|
-
if (settingsField) {
|
|
166
|
-
try {
|
|
167
|
-
const { loadUserSettings } = await import("../utils/settings.js");
|
|
168
|
-
const providers = loadUserSettings().providers;
|
|
169
|
-
const settingsKey = providers?.[settingsField]?.apiKey;
|
|
170
|
-
if (settingsKey && settingsKey.length >= 20) {
|
|
171
|
-
redactor.enrollSecret(settingsKey);
|
|
172
|
-
return settingsKey;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
catch {
|
|
176
|
-
/* settings load failed — continue to error */
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
104
|
// Ollama may be keyless
|
|
180
105
|
if (provider === "ollama")
|
|
181
106
|
return "";
|
|
182
107
|
throw new ProviderKeyMissingError(provider);
|
|
183
108
|
}
|
|
184
109
|
/**
|
|
185
|
-
* Return the list of providers that currently have credentials available —
|
|
186
|
-
*
|
|
110
|
+
* Return the list of providers that currently have credentials available —
|
|
111
|
+
* either an env API key or a stored OAuth token. `ollama` is always included
|
|
187
112
|
* because it is keyless. Order is stable for UI rendering.
|
|
188
113
|
*/
|
|
189
114
|
export async function getConfiguredProviders() {
|
|
190
115
|
const order = ALL_PROVIDER_IDS;
|
|
191
116
|
const stored = new Set(await listStoredProviders());
|
|
192
|
-
let settingsProviders = {};
|
|
193
|
-
try {
|
|
194
|
-
const { loadUserSettings } = await import("../utils/settings.js");
|
|
195
|
-
settingsProviders = (loadUserSettings().providers ?? {});
|
|
196
|
-
}
|
|
197
|
-
catch {
|
|
198
|
-
/* settings unreadable — keychain + env still work */
|
|
199
|
-
}
|
|
200
117
|
// OAuth-authenticated providers (no API key, but tokens stored via `keys
|
|
201
118
|
// login`) need to count as configured — otherwise the model picker silently
|
|
202
119
|
// hides them. Source the eligible provider list from the OAuth registry so
|
|
@@ -216,25 +133,8 @@ export async function getConfiguredProviders() {
|
|
|
216
133
|
}
|
|
217
134
|
const configured = [];
|
|
218
135
|
for (const p of order) {
|
|
219
|
-
if (p === "ollama") {
|
|
136
|
+
if (p === "ollama" || stored.has(p) || oauthAuthenticated.has(p)) {
|
|
220
137
|
configured.push(p);
|
|
221
|
-
continue;
|
|
222
|
-
}
|
|
223
|
-
if (stored.has(p) || oauthAuthenticated.has(p)) {
|
|
224
|
-
configured.push(p);
|
|
225
|
-
continue;
|
|
226
|
-
}
|
|
227
|
-
const envKey = process.env[ENV_BY_PROVIDER[p]];
|
|
228
|
-
if (envKey && envKey.length >= 20) {
|
|
229
|
-
configured.push(p);
|
|
230
|
-
continue;
|
|
231
|
-
}
|
|
232
|
-
const settingsField = SETTINGS_KEY_MAP[p];
|
|
233
|
-
if (settingsField) {
|
|
234
|
-
const k = settingsProviders[settingsField]?.apiKey;
|
|
235
|
-
if (k && k.length >= 20) {
|
|
236
|
-
configured.push(p);
|
|
237
|
-
}
|
|
238
138
|
}
|
|
239
139
|
}
|
|
240
140
|
return configured;
|
|
@@ -258,7 +158,7 @@ export async function getOAuthTokens(provider) {
|
|
|
258
158
|
}
|
|
259
159
|
/**
|
|
260
160
|
* Find the first provider with an available API key.
|
|
261
|
-
* Checks in priority order: anthropic, openai,
|
|
161
|
+
* Checks in priority order: anthropic, openai, deepseek, ollama.
|
|
262
162
|
* Returns null if no provider has a key (unlikely — ollama is keyless fallback).
|
|
263
163
|
*/
|
|
264
164
|
export async function firstAvailableProvider() {
|
|
@@ -277,4 +177,91 @@ export async function firstAvailableProvider() {
|
|
|
277
177
|
}
|
|
278
178
|
return null;
|
|
279
179
|
}
|
|
180
|
+
/**
|
|
181
|
+
* One-time migration: move any legacy API keys — OS keychain (keytar) or
|
|
182
|
+
* `settings.json` (`providers.<p>.apiKey`) — into the env-store, then remove
|
|
183
|
+
* the legacy copies. Best-effort, idempotent, and never throws. Guarded by
|
|
184
|
+
* `settings.keysMigratedToEnv`. Runs once at startup before key resolution.
|
|
185
|
+
*/
|
|
186
|
+
export async function migrateLegacyKeysToEnv() {
|
|
187
|
+
let settingsMod;
|
|
188
|
+
try {
|
|
189
|
+
settingsMod = await import("../utils/settings.js");
|
|
190
|
+
}
|
|
191
|
+
catch (err) {
|
|
192
|
+
if (process.env.MUONROI_DEBUG_ENVSTORE) {
|
|
193
|
+
console.error(`[keychain] migration: settings unavailable: ${err instanceof Error ? err.message : String(err)}`);
|
|
194
|
+
}
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
let settings;
|
|
198
|
+
try {
|
|
199
|
+
settings = settingsMod.loadUserSettings();
|
|
200
|
+
}
|
|
201
|
+
catch {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
if (settings.keysMigratedToEnv)
|
|
205
|
+
return;
|
|
206
|
+
// Legacy keytar reader — the dependency has been removed, so absence is the
|
|
207
|
+
// normal case. The specifier is assembled at runtime so the bundler
|
|
208
|
+
// (`bun build --compile`) does not try to statically resolve the missing
|
|
209
|
+
// module; when keytar isn't installed this import simply throws → null.
|
|
210
|
+
let keytar = null;
|
|
211
|
+
try {
|
|
212
|
+
const legacyKeytarSpecifier = ["key", "tar"].join("");
|
|
213
|
+
keytar = (await import(legacyKeytarSpecifier));
|
|
214
|
+
}
|
|
215
|
+
catch {
|
|
216
|
+
keytar = null;
|
|
217
|
+
}
|
|
218
|
+
const providersPatch = { ...(settings.providers ?? {}) };
|
|
219
|
+
let providersDirty = false;
|
|
220
|
+
for (const p of KEYCHAIN_PROVIDER_IDS) {
|
|
221
|
+
const envName = ENV_BY_PROVIDER[p];
|
|
222
|
+
if (process.env[envName])
|
|
223
|
+
continue; // already in env
|
|
224
|
+
let legacy = null;
|
|
225
|
+
if (keytar?.getPassword) {
|
|
226
|
+
try {
|
|
227
|
+
legacy = await keytar.getPassword("muonroi-cli", p);
|
|
228
|
+
}
|
|
229
|
+
catch {
|
|
230
|
+
legacy = null;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
if (!legacy)
|
|
234
|
+
legacy = providersPatch[p]?.apiKey ?? null;
|
|
235
|
+
if (legacy && legacy.length >= 20) {
|
|
236
|
+
persistEnvVar(envName, legacy);
|
|
237
|
+
if (keytar?.deletePassword) {
|
|
238
|
+
try {
|
|
239
|
+
await keytar.deletePassword("muonroi-cli", p);
|
|
240
|
+
}
|
|
241
|
+
catch {
|
|
242
|
+
/* best-effort keychain cleanup */
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
if (providersPatch[p]?.apiKey) {
|
|
246
|
+
delete providersPatch[p].apiKey;
|
|
247
|
+
providersDirty = true;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
const patch = { keysMigratedToEnv: true };
|
|
252
|
+
// Strip the legacy plaintext main key — it is no longer read (getApiKey is
|
|
253
|
+
// env-only). Passing undefined drops it from the persisted JSON.
|
|
254
|
+
if (settings.apiKey)
|
|
255
|
+
patch.apiKey = undefined;
|
|
256
|
+
if (providersDirty)
|
|
257
|
+
patch.providers = providersPatch;
|
|
258
|
+
try {
|
|
259
|
+
settingsMod.saveUserSettings(patch);
|
|
260
|
+
}
|
|
261
|
+
catch (err) {
|
|
262
|
+
if (process.env.MUONROI_DEBUG_ENVSTORE) {
|
|
263
|
+
console.error(`[keychain] migration: save failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
280
267
|
//# sourceMappingURL=keychain.js.map
|
|
@@ -12,16 +12,8 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import { existsSync, readFileSync } from "node:fs";
|
|
14
14
|
import { extname, resolve } from "node:path";
|
|
15
|
-
import {
|
|
16
|
-
import { loadKeyForProvider } from "./keychain.js";
|
|
15
|
+
import { callVisionBackend, formatNativeVisionObservation, formatNativeVisionUnavailable, looksLikeOcrIntent, resolveAvailableVisionChain, wrapAnalyzerInstructions, } from "./vision-backend.js";
|
|
17
16
|
import { needsVisionProxy } from "./vision-proxy.js";
|
|
18
|
-
const VISION_MODELS = [
|
|
19
|
-
"Qwen/Qwen3-VL-8B-Instruct",
|
|
20
|
-
"Qwen/Qwen3-VL-30B-A3B-Instruct",
|
|
21
|
-
"Qwen/Qwen3-VL-32B-Instruct",
|
|
22
|
-
];
|
|
23
|
-
const SILICONFLOW_BASE = apiBaseFor("siliconflow");
|
|
24
|
-
const REQUEST_TIMEOUT_MS = 90_000;
|
|
25
17
|
const IMAGE_CACHE_MAX = 20;
|
|
26
18
|
const IMAGE_CACHE_TTL_MS = 15 * 60 * 1000; // 15 minutes
|
|
27
19
|
/**
|
|
@@ -174,8 +166,8 @@ export async function bridgeMcpToolResult(toolName, toolOutput, modelId, signal,
|
|
|
174
166
|
}
|
|
175
167
|
// Detect context for better analysis prompt
|
|
176
168
|
const context = detectImageContext(toolName, toolOutput);
|
|
177
|
-
const
|
|
178
|
-
if (!
|
|
169
|
+
const rawObservation = await analyzeImages(images, context, signal);
|
|
170
|
+
if (!rawObservation) {
|
|
179
171
|
// Even when the vision proxy fails (no API key / network error), we MUST
|
|
180
172
|
// still strip the base64 payload from the tool output. Otherwise a single
|
|
181
173
|
// Playwright screenshot (~1.5MB of base64) lands in conversation history
|
|
@@ -187,15 +179,21 @@ export async function bridgeMcpToolResult(toolName, toolOutput, modelId, signal,
|
|
|
187
179
|
proxied: true,
|
|
188
180
|
};
|
|
189
181
|
}
|
|
190
|
-
const cachedIds = addToCache(images.map((img) => ({ ...img, source: baseName || toolName })),
|
|
182
|
+
const cachedIds = addToCache(images.map((img) => ({ ...img, source: baseName || toolName })), rawObservation, `${baseName} result`);
|
|
191
183
|
const cleanOutput = stripBase64FromOutput(toolOutput);
|
|
192
|
-
const
|
|
193
|
-
|
|
184
|
+
const fullDescription = formatNativeVisionObservation(rawObservation, {
|
|
185
|
+
imageCount: images.length,
|
|
186
|
+
cachedIds,
|
|
187
|
+
});
|
|
194
188
|
const enhanced = typeof cleanOutput === "string"
|
|
195
189
|
? `${cleanOutput}\n\n${fullDescription}`
|
|
196
|
-
: {
|
|
190
|
+
: {
|
|
191
|
+
...cleanOutput,
|
|
192
|
+
_visionDescription: fullDescription,
|
|
193
|
+
_cachedImageIds: cachedIds,
|
|
194
|
+
};
|
|
197
195
|
recordBridgedDescription(toolCallId, fullDescription);
|
|
198
|
-
return { output: enhanced, proxied: true, description, cachedImageIds: cachedIds };
|
|
196
|
+
return { output: enhanced, proxied: true, description: fullDescription, cachedImageIds: cachedIds };
|
|
199
197
|
}
|
|
200
198
|
/**
|
|
201
199
|
* Proactively analyze an image from a file path, URL, or raw base64.
|
|
@@ -246,12 +244,13 @@ export async function analyzeImageFromSource(source, question, cwd, signal) {
|
|
|
246
244
|
}
|
|
247
245
|
const context = question ? { type: "user-query", hint: question } : { type: "generic" };
|
|
248
246
|
const prompt = question ? buildFollowUpPrompt(question, images.length) : undefined;
|
|
249
|
-
const
|
|
250
|
-
if (!
|
|
251
|
-
|
|
247
|
+
const rawObservation = await analyzeImages(images, context, signal, prompt);
|
|
248
|
+
if (!rawObservation) {
|
|
249
|
+
const { collectVisionUnavailableReasons } = await import("./vision-backend.js");
|
|
250
|
+
return formatNativeVisionUnavailable(1, await collectVisionUnavailableReasons());
|
|
252
251
|
}
|
|
253
|
-
const cachedIds = addToCache(images,
|
|
254
|
-
return
|
|
252
|
+
const cachedIds = addToCache(images, rawObservation, source);
|
|
253
|
+
return formatNativeVisionObservation(rawObservation, { imageCount: images.length, cachedIds });
|
|
255
254
|
}
|
|
256
255
|
/**
|
|
257
256
|
* Ask a follow-up question about a previously cached image,
|
|
@@ -278,17 +277,10 @@ export async function askVisionProxy(question, imageIdOrPath, cwd, signal) {
|
|
|
278
277
|
}
|
|
279
278
|
return `No matching image. Available:\n${cached.map((c) => `- ${c.id}: ${c.label} (${c.age})`).join("\n")}\n\nSpecify image_id, or provide a file_path to analyze a new image.`;
|
|
280
279
|
}
|
|
281
|
-
let apiKey;
|
|
282
|
-
try {
|
|
283
|
-
apiKey = await loadKeyForProvider("siliconflow");
|
|
284
|
-
}
|
|
285
|
-
catch {
|
|
286
|
-
return "Vision proxy unavailable — SILICONFLOW_API_KEY not configured.";
|
|
287
|
-
}
|
|
288
280
|
const visionContent = [];
|
|
289
281
|
visionContent.push({
|
|
290
282
|
type: "text",
|
|
291
|
-
text: buildFollowUpPrompt(question, targets.length),
|
|
283
|
+
text: wrapAnalyzerInstructions(buildFollowUpPrompt(question, targets.length), looksLikeOcrIntent(question) ? "ocr" : "default"),
|
|
292
284
|
});
|
|
293
285
|
for (const img of targets) {
|
|
294
286
|
visionContent.push({
|
|
@@ -299,19 +291,15 @@ export async function askVisionProxy(question, imageIdOrPath, cwd, signal) {
|
|
|
299
291
|
},
|
|
300
292
|
});
|
|
301
293
|
}
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
}
|
|
309
|
-
catch (err) {
|
|
310
|
-
if (signal?.aborted)
|
|
311
|
-
throw err;
|
|
312
|
-
}
|
|
294
|
+
const kind = looksLikeOcrIntent(question) ? "ocr" : "default";
|
|
295
|
+
const result = await callVisionBackend(await resolveAvailableVisionChain(kind), visionContent, signal);
|
|
296
|
+
if (result.ok) {
|
|
297
|
+
return formatNativeVisionObservation(result.text, {
|
|
298
|
+
imageCount: targets.length,
|
|
299
|
+
cachedIds: targets.map((t) => t.id),
|
|
300
|
+
});
|
|
313
301
|
}
|
|
314
|
-
return
|
|
302
|
+
return formatNativeVisionUnavailable(targets.length, [result.reason]);
|
|
315
303
|
}
|
|
316
304
|
/**
|
|
317
305
|
* System prompt guidance for text-only models — UNIVERSAL, not Playwright-specific.
|
|
@@ -320,32 +308,27 @@ export function getVisionGuidanceForTextOnly(modelId) {
|
|
|
320
308
|
if (!needsVisionProxy(modelId))
|
|
321
309
|
return "";
|
|
322
310
|
return `
|
|
323
|
-
VISION
|
|
324
|
-
You
|
|
311
|
+
VISION (extended capability):
|
|
312
|
+
You have full visual understanding via auto-injected <vision-observation> blocks and vision tools.
|
|
313
|
+
Treat every <vision-observation> as YOUR direct sight — respond naturally as if you saw the image yourself.
|
|
325
314
|
|
|
326
|
-
TOOLS:
|
|
327
|
-
- analyze_image:
|
|
328
|
-
- ask_vision_proxy: Ask a
|
|
329
|
-
- list_vision_cache:
|
|
315
|
+
TOOLS (when you need a closer look or a new image):
|
|
316
|
+
- analyze_image: Inspect an image file path, data URI, or base64. Use when you encounter a new image or need a fresh screenshot analyzed.
|
|
317
|
+
- ask_vision_proxy: Ask a follow-up about a cached image (by ID) or a file path — zoom in on a region, read text, compare colors.
|
|
318
|
+
- list_vision_cache: List cached image IDs available for follow-up questions.
|
|
330
319
|
|
|
331
|
-
WHEN TO
|
|
332
|
-
- User mentions an image
|
|
333
|
-
-
|
|
334
|
-
-
|
|
335
|
-
-
|
|
336
|
-
- Debugging visual issues (CSS, layout, colors) → take screenshot, then ask_vision_proxy specific questions
|
|
337
|
-
- Comparing before/after → analyze both images, ask about differences
|
|
338
|
-
- Reading text from images (OCR) → analyze_image with a question like "transcribe all text"
|
|
339
|
-
- Any file with image extension (.png, .jpg, .gif, .webp, .svg, etc.) → analyze_image
|
|
320
|
+
WHEN TO ACT:
|
|
321
|
+
- User mentions an image → analyze_image immediately (do not guess)
|
|
322
|
+
- Tool results include <vision-observation> → use that as your sight; ask_vision_proxy if any detail is unclear
|
|
323
|
+
- UI debugging → screenshot + ask_vision_proxy for specific elements
|
|
324
|
+
- OCR / transcribe → analyze_image with question "transcribe all visible text"
|
|
340
325
|
|
|
341
|
-
|
|
342
|
-
1.
|
|
343
|
-
2.
|
|
344
|
-
3.
|
|
326
|
+
IF STILL UNCLEAR after an observation:
|
|
327
|
+
1. ask_vision_proxy with a precise question about the unclear region or text
|
|
328
|
+
2. analyze_image again on a new or higher-resolution file
|
|
329
|
+
3. Ask the user to share another screenshot or clarify what to focus on
|
|
345
330
|
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
IMPORTANT: Do NOT guess what an image contains. Always use the proxy to get accurate information.
|
|
331
|
+
Never invent visual details. Cached images: up to ${IMAGE_CACHE_MAX}, ${IMAGE_CACHE_TTL_MS / 60000}min TTL.
|
|
349
332
|
`;
|
|
350
333
|
}
|
|
351
334
|
// Keep backward compat export
|
|
@@ -380,17 +363,11 @@ async function analyzeImages(images, context, signal, customPrompt) {
|
|
|
380
363
|
const svgFast = trySvgFastPath(images, context);
|
|
381
364
|
if (svgFast)
|
|
382
365
|
return svgFast;
|
|
383
|
-
|
|
384
|
-
try {
|
|
385
|
-
apiKey = await loadKeyForProvider("siliconflow");
|
|
386
|
-
}
|
|
387
|
-
catch {
|
|
388
|
-
return null;
|
|
389
|
-
}
|
|
366
|
+
const kind = context.type === "design" ? "design" : customPrompt && looksLikeOcrIntent(customPrompt) ? "ocr" : "default";
|
|
390
367
|
const visionContent = [];
|
|
391
368
|
visionContent.push({
|
|
392
369
|
type: "text",
|
|
393
|
-
text: customPrompt ?? buildContextualPrompt(images.length, context),
|
|
370
|
+
text: wrapAnalyzerInstructions(customPrompt ?? buildContextualPrompt(images.length, context), kind),
|
|
394
371
|
});
|
|
395
372
|
for (const img of images) {
|
|
396
373
|
visionContent.push({
|
|
@@ -401,22 +378,10 @@ async function analyzeImages(images, context, signal, customPrompt) {
|
|
|
401
378
|
},
|
|
402
379
|
});
|
|
403
380
|
}
|
|
404
|
-
// Force JSON output for the design contract. Markdown narrative is fine for
|
|
405
|
-
// debug-style contexts (terminal, code) where the human reads the result,
|
|
406
|
-
// but design output is consumed machine-to-machine.
|
|
407
381
|
const responseFormat = context.type === "design" ? { type: "json_object" } : undefined;
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
if (result) {
|
|
412
|
-
return formatBridgeResult(result, images.length, model, context.type);
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
catch (err) {
|
|
416
|
-
if (signal?.aborted)
|
|
417
|
-
throw err;
|
|
418
|
-
}
|
|
419
|
-
}
|
|
382
|
+
const result = await callVisionBackend(await resolveAvailableVisionChain(kind), visionContent, signal, responseFormat);
|
|
383
|
+
if (result.ok)
|
|
384
|
+
return result.text;
|
|
420
385
|
return null;
|
|
421
386
|
}
|
|
422
387
|
function trySvgFastPath(images, context) {
|
|
@@ -437,11 +402,10 @@ function trySvgFastPath(images, context) {
|
|
|
437
402
|
return svg.length > 32_000 ? `${svg.slice(0, 32_000)}\n<!-- truncated -->` : svg;
|
|
438
403
|
})
|
|
439
404
|
.join("\n\n");
|
|
440
|
-
const
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
return `\n${header}${guidance}\n\`\`\`svg\n${decoded}\n\`\`\`\n[/Vision Bridge]\n`;
|
|
405
|
+
const observation = context.type === "design"
|
|
406
|
+
? `I see ${images.length} SVG source(s). Vector markup is exact — map nodes to:\n${UI_LAYOUT_SCHEMA_HINT}\n\n\`\`\`svg\n${decoded}\n\`\`\``
|
|
407
|
+
: `I see ${images.length} SVG source(s). Vector markup:\n\n\`\`\`svg\n${decoded}\n\`\`\``;
|
|
408
|
+
return observation;
|
|
445
409
|
}
|
|
446
410
|
function buildContextualPrompt(imageCount, context) {
|
|
447
411
|
const plural = imageCount > 1 ? `${imageCount} images` : "the image";
|
|
@@ -799,63 +763,9 @@ function walkAndStrip(obj) {
|
|
|
799
763
|
}
|
|
800
764
|
}
|
|
801
765
|
function wrapWithFallback(output, imageCount) {
|
|
802
|
-
const notice =
|
|
766
|
+
const notice = formatNativeVisionUnavailable(imageCount, ["auto-analysis failed"]);
|
|
803
767
|
if (typeof output === "string")
|
|
804
768
|
return `${output}\n${notice}`;
|
|
805
769
|
return { ...output, _visionNotice: notice };
|
|
806
770
|
}
|
|
807
|
-
async function callVisionModel(model, content, apiKey, signal, responseFormat) {
|
|
808
|
-
const controller = new AbortController();
|
|
809
|
-
let timedOut = false;
|
|
810
|
-
const timeout = setTimeout(() => {
|
|
811
|
-
timedOut = true;
|
|
812
|
-
controller.abort();
|
|
813
|
-
}, REQUEST_TIMEOUT_MS);
|
|
814
|
-
if (signal) {
|
|
815
|
-
signal.addEventListener("abort", () => controller.abort(), { once: true });
|
|
816
|
-
}
|
|
817
|
-
let res;
|
|
818
|
-
try {
|
|
819
|
-
res = await fetch(`${SILICONFLOW_BASE}/chat/completions`, {
|
|
820
|
-
method: "POST",
|
|
821
|
-
headers: {
|
|
822
|
-
"Content-Type": "application/json",
|
|
823
|
-
Authorization: `Bearer ${apiKey}`,
|
|
824
|
-
},
|
|
825
|
-
body: JSON.stringify({
|
|
826
|
-
model,
|
|
827
|
-
messages: [{ role: "user", content }],
|
|
828
|
-
max_tokens: 3072,
|
|
829
|
-
temperature: 0.1,
|
|
830
|
-
...(responseFormat ? { response_format: responseFormat } : {}),
|
|
831
|
-
}),
|
|
832
|
-
signal: controller.signal,
|
|
833
|
-
});
|
|
834
|
-
}
|
|
835
|
-
catch (err) {
|
|
836
|
-
clearTimeout(timeout);
|
|
837
|
-
if (timedOut) {
|
|
838
|
-
console.warn(`[vision-bridge] ${model} timed out after ${REQUEST_TIMEOUT_MS}ms`);
|
|
839
|
-
return null;
|
|
840
|
-
}
|
|
841
|
-
if (signal?.aborted)
|
|
842
|
-
throw err;
|
|
843
|
-
console.warn(`[vision-bridge] ${model} network error: ${err instanceof Error ? err.message : String(err)}`);
|
|
844
|
-
return null;
|
|
845
|
-
}
|
|
846
|
-
clearTimeout(timeout);
|
|
847
|
-
if (!res.ok) {
|
|
848
|
-
const errText = await res.text().catch(() => "");
|
|
849
|
-
console.warn(`[vision-bridge] ${model} HTTP ${res.status}: ${errText.slice(0, 200)}`);
|
|
850
|
-
return null;
|
|
851
|
-
}
|
|
852
|
-
const data = (await res.json().catch(() => null));
|
|
853
|
-
return data?.choices?.[0]?.message?.content ?? null;
|
|
854
|
-
}
|
|
855
|
-
function formatBridgeResult(description, imageCount, model, contextType) {
|
|
856
|
-
const header = imageCount > 1
|
|
857
|
-
? `[Vision Bridge — ${imageCount} images analyzed (${contextType}) via ${model}]`
|
|
858
|
-
: `[Vision Bridge — image analyzed (${contextType}) via ${model}]`;
|
|
859
|
-
return `\n${header}\n${description}\n[/Vision Bridge]\n`;
|
|
860
|
-
}
|
|
861
771
|
//# sourceMappingURL=mcp-vision-bridge.js.map
|