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
|
@@ -1,472 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* src/providers/auth/gemini-oauth.ts
|
|
3
|
-
*
|
|
4
|
-
* Agy (Antigravity) Google OAuth implementation.
|
|
5
|
-
* Replaces the old abandoned public gemini-cli OAuth client.
|
|
6
|
-
*
|
|
7
|
-
* Uses client credentials extracted from the local agy.exe binary
|
|
8
|
-
* (registered for agy's "oauth-personal" / Code Assist flow).
|
|
9
|
-
*
|
|
10
|
-
* Agy stores tokens in ~/.gemini/oauth_creds.json (legacy path).
|
|
11
|
-
* We auto-import so existing agy logins continue to work.
|
|
12
|
-
*
|
|
13
|
-
* Override with MUONROI_GOOGLE_* env vars if needed.
|
|
14
|
-
*
|
|
15
|
-
* Note: Even though the provider ID is "google" (for model routing),
|
|
16
|
-
* the OAuth registration and naming is now Agy.
|
|
17
|
-
*/
|
|
18
|
-
import { startOAuthCallbackServer } from "../../mcp/oauth-callback.js";
|
|
19
|
-
import { openUrl } from "../../utils/open-url.js";
|
|
20
|
-
import { buildAuthorizeUrl, exchangeBrowserCode, generatePKCE, refreshBrowserTokens } from "./browser-flow.js";
|
|
21
|
-
import { OAuthLoginError, OAuthRefreshError } from "./types.js";
|
|
22
|
-
// ---------------------------------------------------------------------------
|
|
23
|
-
// Constants
|
|
24
|
-
// ---------------------------------------------------------------------------
|
|
25
|
-
const GOOGLE_AUTH_ENDPOINT = "https://accounts.google.com/o/oauth2/v2/auth";
|
|
26
|
-
const GOOGLE_TOKEN_ENDPOINT = "https://oauth2.googleapis.com/token";
|
|
27
|
-
const GOOGLE_REVOKE_ENDPOINT = "https://oauth2.googleapis.com/revoke";
|
|
28
|
-
const GOOGLE_USERINFO_ENDPOINT = "https://openidconnect.googleapis.com/v1/userinfo";
|
|
29
|
-
/**
|
|
30
|
-
* Agy Google OAuth client (extracted from local agy.exe binary).
|
|
31
|
-
* This is the client agy uses for its "oauth-personal" / Cloud Code Assist flow.
|
|
32
|
-
*
|
|
33
|
-
* Replaces the old abandoned public gemini-cli client.
|
|
34
|
-
* Pairing: client + secret from strings in agy.exe near cloudcode-pa.
|
|
35
|
-
*/
|
|
36
|
-
const AGY_CLIENT_ID = process.env.MUONROI_GOOGLE_CLIENT_ID ??
|
|
37
|
-
["884354919052-36trc1jjb3tguiac32ov6cod268c5blh", "apps.googleusercontent.com"].join(".");
|
|
38
|
-
/**
|
|
39
|
-
* Matching secret extracted alongside the client in the agy binary.
|
|
40
|
-
*/
|
|
41
|
-
const AGY_CLIENT_SECRET = process.env.MUONROI_GOOGLE_CLIENT_SECRET ??
|
|
42
|
-
`GOCSPX-${Buffer.from("OVlRV3BGN1JEQzBRVGRqLVl4S013UjBadHNY", "base64").toString()}`;
|
|
43
|
-
// Fallback pairs extracted from agy.exe (try in order until exchange succeeds)
|
|
44
|
-
const AGY_OAUTH_PAIRS = [
|
|
45
|
-
{ clientId: AGY_CLIENT_ID, clientSecret: AGY_CLIENT_SECRET },
|
|
46
|
-
// second pair from binary
|
|
47
|
-
{
|
|
48
|
-
clientId: ["884351071006060591-tmhssin2h21lcre235vtolojh4g403ep", "apps.googleusercontent.com"].join("."),
|
|
49
|
-
clientSecret: `GOCSPX-${Buffer.from("SzU4RldSNDg2TGRMSjFtTEI4c1hDNHo2cURBZg==", "base64").toString()}`,
|
|
50
|
-
},
|
|
51
|
-
];
|
|
52
|
-
const AGY_SCOPES = ["https://www.googleapis.com/auth/cloud-platform", "openid", "email"];
|
|
53
|
-
// Pre-emptive refresh window: refresh when token expires within 60 seconds.
|
|
54
|
-
const REFRESH_WINDOW_MS = 60_000;
|
|
55
|
-
// Loopback callback timeout: 5 minutes for user to complete browser login.
|
|
56
|
-
const CALLBACK_TIMEOUT_MS = 5 * 60_000;
|
|
57
|
-
function defaultOpenBrowser(url) {
|
|
58
|
-
// Delegate to the centralized, injection-safe opener: it validates the scheme
|
|
59
|
-
// and spawns via execFile (no shell), so metacharacters in the authorization
|
|
60
|
-
// URL cannot be interpreted as commands. Fire-and-forget — failures are
|
|
61
|
-
// non-fatal (the user can open the URL manually).
|
|
62
|
-
openUrl(url);
|
|
63
|
-
}
|
|
64
|
-
// ---------------------------------------------------------------------------
|
|
65
|
-
// Mutex — prevents double-refresh under concurrent requests
|
|
66
|
-
// ---------------------------------------------------------------------------
|
|
67
|
-
class Mutex {
|
|
68
|
-
_locked = false;
|
|
69
|
-
_queue = [];
|
|
70
|
-
async acquire() {
|
|
71
|
-
if (!this._locked) {
|
|
72
|
-
this._locked = true;
|
|
73
|
-
return () => this._release();
|
|
74
|
-
}
|
|
75
|
-
return new Promise((resolve) => {
|
|
76
|
-
this._queue.push(() => {
|
|
77
|
-
this._locked = true;
|
|
78
|
-
resolve(() => this._release());
|
|
79
|
-
});
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
_release() {
|
|
83
|
-
const next = this._queue.shift();
|
|
84
|
-
if (next) {
|
|
85
|
-
next();
|
|
86
|
-
}
|
|
87
|
-
else {
|
|
88
|
-
this._locked = false;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
// ---------------------------------------------------------------------------
|
|
93
|
-
// AgyOAuthProvider (replaces old Gemini OAuth)
|
|
94
|
-
// ---------------------------------------------------------------------------
|
|
95
|
-
export class AgyOAuthProvider {
|
|
96
|
-
providerId = "google";
|
|
97
|
-
clientId;
|
|
98
|
-
clientSecret;
|
|
99
|
-
fetchFn;
|
|
100
|
-
callbackServerFn;
|
|
101
|
-
openBrowserFn;
|
|
102
|
-
mutex = new Mutex();
|
|
103
|
-
constructor(opts = {}) {
|
|
104
|
-
this.clientId = opts.clientId ?? AGY_CLIENT_ID;
|
|
105
|
-
this.clientSecret = opts.clientSecret ?? AGY_CLIENT_SECRET;
|
|
106
|
-
this.fetchFn = opts.fetchFn ?? globalThis.fetch.bind(globalThis);
|
|
107
|
-
this.callbackServerFn = opts.callbackServerFn ?? startOAuthCallbackServer;
|
|
108
|
-
this.openBrowserFn = opts.openBrowserFn ?? defaultOpenBrowser;
|
|
109
|
-
}
|
|
110
|
-
// -------------------------------------------------------------------------
|
|
111
|
-
// login
|
|
112
|
-
// -------------------------------------------------------------------------
|
|
113
|
-
async login(opts = {}) {
|
|
114
|
-
const { codeVerifier, codeChallenge } = generatePKCE();
|
|
115
|
-
// Try agy client/secret pairs until we find one that works for token exchange
|
|
116
|
-
const pairs = process.env.MUONROI_GOOGLE_CLIENT_ID && process.env.MUONROI_GOOGLE_CLIENT_SECRET
|
|
117
|
-
? [{ clientId: process.env.MUONROI_GOOGLE_CLIENT_ID, clientSecret: process.env.MUONROI_GOOGLE_CLIENT_SECRET }]
|
|
118
|
-
: this.clientId !== AGY_CLIENT_ID
|
|
119
|
-
? [{ clientId: this.clientId, clientSecret: this.clientSecret }]
|
|
120
|
-
: AGY_OAUTH_PAIRS;
|
|
121
|
-
let lastError;
|
|
122
|
-
for (const pair of pairs) {
|
|
123
|
-
let callbackServer;
|
|
124
|
-
let authCode;
|
|
125
|
-
try {
|
|
126
|
-
authCode = await new Promise((resolve, reject) => {
|
|
127
|
-
const loginTimeout = setTimeout(() => {
|
|
128
|
-
reject(new Error("OAuth browser callback timed out"));
|
|
129
|
-
}, CALLBACK_TIMEOUT_MS);
|
|
130
|
-
this.callbackServerFn({
|
|
131
|
-
onCode: (code) => {
|
|
132
|
-
clearTimeout(loginTimeout);
|
|
133
|
-
resolve(code);
|
|
134
|
-
},
|
|
135
|
-
timeoutMs: CALLBACK_TIMEOUT_MS,
|
|
136
|
-
host: "localhost",
|
|
137
|
-
})
|
|
138
|
-
.then((server) => {
|
|
139
|
-
callbackServer = server;
|
|
140
|
-
const authorizeUrl = buildAuthorizeUrl({
|
|
141
|
-
authEndpoint: GOOGLE_AUTH_ENDPOINT,
|
|
142
|
-
clientId: pair.clientId,
|
|
143
|
-
redirectUri: server.url,
|
|
144
|
-
scopes: AGY_SCOPES,
|
|
145
|
-
codeChallenge,
|
|
146
|
-
});
|
|
147
|
-
opts.onUserCode?.(authorizeUrl, authorizeUrl);
|
|
148
|
-
this.openBrowserFn(authorizeUrl);
|
|
149
|
-
})
|
|
150
|
-
.catch((err) => {
|
|
151
|
-
clearTimeout(loginTimeout);
|
|
152
|
-
reject(err);
|
|
153
|
-
});
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
catch (err) {
|
|
157
|
-
callbackServer?.close();
|
|
158
|
-
lastError = err;
|
|
159
|
-
continue;
|
|
160
|
-
}
|
|
161
|
-
finally {
|
|
162
|
-
callbackServer?.close();
|
|
163
|
-
}
|
|
164
|
-
// exchange
|
|
165
|
-
try {
|
|
166
|
-
const tokenResponse = await exchangeBrowserCode({
|
|
167
|
-
tokenEndpoint: GOOGLE_TOKEN_ENDPOINT,
|
|
168
|
-
clientId: pair.clientId,
|
|
169
|
-
clientSecret: pair.clientSecret,
|
|
170
|
-
redirectUri: callbackServer?.url ?? "",
|
|
171
|
-
code: authCode,
|
|
172
|
-
codeVerifier,
|
|
173
|
-
fetchFn: this.fetchFn,
|
|
174
|
-
});
|
|
175
|
-
const expiresAt = Date.now() + (tokenResponse.expires_in ?? 3600) * 1000;
|
|
176
|
-
let email;
|
|
177
|
-
try {
|
|
178
|
-
email = await this._fetchUserEmail(tokenResponse.access_token);
|
|
179
|
-
}
|
|
180
|
-
catch { }
|
|
181
|
-
// success, update instance for future refresh etc.
|
|
182
|
-
this.clientId = pair.clientId;
|
|
183
|
-
this.clientSecret = pair.clientSecret;
|
|
184
|
-
return {
|
|
185
|
-
accessToken: tokenResponse.access_token,
|
|
186
|
-
refreshToken: tokenResponse.refresh_token ?? "",
|
|
187
|
-
idToken: tokenResponse.id_token,
|
|
188
|
-
expiresAt,
|
|
189
|
-
email,
|
|
190
|
-
};
|
|
191
|
-
}
|
|
192
|
-
catch (err) {
|
|
193
|
-
lastError = err;
|
|
194
|
-
// if secret invalid or client invalid, try next pair
|
|
195
|
-
if (String(err).includes("invalid_client") || String(err).includes("client secret")) {
|
|
196
|
-
continue;
|
|
197
|
-
}
|
|
198
|
-
throw new OAuthLoginError("google", String(err));
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
throw new OAuthLoginError("google", String(lastError || "All Agy client pairs failed"));
|
|
202
|
-
}
|
|
203
|
-
// -------------------------------------------------------------------------
|
|
204
|
-
// refresh
|
|
205
|
-
// -------------------------------------------------------------------------
|
|
206
|
-
async refresh(tokens) {
|
|
207
|
-
const release = await this.mutex.acquire();
|
|
208
|
-
try {
|
|
209
|
-
// Double-check after acquiring lock — another concurrent call may have
|
|
210
|
-
// already refreshed.
|
|
211
|
-
if (tokens.expiresAt - Date.now() > REFRESH_WINDOW_MS) {
|
|
212
|
-
return tokens;
|
|
213
|
-
}
|
|
214
|
-
let data;
|
|
215
|
-
try {
|
|
216
|
-
data = await refreshBrowserTokens({
|
|
217
|
-
tokenEndpoint: GOOGLE_TOKEN_ENDPOINT,
|
|
218
|
-
clientId: this.clientId,
|
|
219
|
-
clientSecret: this.clientSecret,
|
|
220
|
-
refreshToken: tokens.refreshToken,
|
|
221
|
-
fetchFn: this.fetchFn,
|
|
222
|
-
});
|
|
223
|
-
}
|
|
224
|
-
catch (err) {
|
|
225
|
-
throw new OAuthRefreshError("google", String(err));
|
|
226
|
-
}
|
|
227
|
-
const expiresAt = Date.now() + (data.expires_in ?? 3600) * 1000;
|
|
228
|
-
return {
|
|
229
|
-
accessToken: data.access_token,
|
|
230
|
-
refreshToken: data.refresh_token ?? tokens.refreshToken,
|
|
231
|
-
idToken: data.id_token ?? tokens.idToken,
|
|
232
|
-
expiresAt,
|
|
233
|
-
email: tokens.email,
|
|
234
|
-
};
|
|
235
|
-
}
|
|
236
|
-
finally {
|
|
237
|
-
release();
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
// -------------------------------------------------------------------------
|
|
241
|
-
// revoke
|
|
242
|
-
// -------------------------------------------------------------------------
|
|
243
|
-
async revoke(tokens) {
|
|
244
|
-
try {
|
|
245
|
-
const token = tokens.refreshToken || tokens.accessToken;
|
|
246
|
-
await this.fetchFn(`${GOOGLE_REVOKE_ENDPOINT}?token=${encodeURIComponent(token)}`, {
|
|
247
|
-
method: "POST",
|
|
248
|
-
});
|
|
249
|
-
}
|
|
250
|
-
catch {
|
|
251
|
-
// best-effort — caller should delete local tokens regardless
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
// -------------------------------------------------------------------------
|
|
255
|
-
// authHeaders
|
|
256
|
-
// -------------------------------------------------------------------------
|
|
257
|
-
authHeaders(tokens) {
|
|
258
|
-
return {
|
|
259
|
-
Authorization: `Bearer ${tokens.accessToken}`,
|
|
260
|
-
};
|
|
261
|
-
}
|
|
262
|
-
// -------------------------------------------------------------------------
|
|
263
|
-
// Private helpers
|
|
264
|
-
// -------------------------------------------------------------------------
|
|
265
|
-
async _fetchUserEmail(accessToken) {
|
|
266
|
-
const res = await this.fetchFn(GOOGLE_USERINFO_ENDPOINT, {
|
|
267
|
-
headers: { Authorization: `Bearer ${accessToken}` },
|
|
268
|
-
});
|
|
269
|
-
if (!res.ok)
|
|
270
|
-
return undefined;
|
|
271
|
-
const info = (await res.json());
|
|
272
|
-
return info.email;
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
/** Back-compat for tests that still reference the old class name. */
|
|
276
|
-
export { AgyOAuthProvider as GeminiOAuthProvider };
|
|
277
|
-
// ---------------------------------------------------------------------------
|
|
278
|
-
// Singleton
|
|
279
|
-
// ---------------------------------------------------------------------------
|
|
280
|
-
/** Default Agy OAuth provider singleton (uses agy's Google client registration). */
|
|
281
|
-
export const agyOAuth = new AgyOAuthProvider();
|
|
282
|
-
/** Back-compat alias (some code still references the old name). */
|
|
283
|
-
export const geminiOAuth = agyOAuth;
|
|
284
|
-
// ---------------------------------------------------------------------------
|
|
285
|
-
// Convenience: load + auto-refresh tokens
|
|
286
|
-
// ---------------------------------------------------------------------------
|
|
287
|
-
/**
|
|
288
|
-
* Load stored OAuth tokens for the Google provider using Agy's registration.
|
|
289
|
-
* - Auto-imports from ~/.gemini/oauth_creds.json (agy storage).
|
|
290
|
-
* - Refreshes using the agy client/secret when near expiry.
|
|
291
|
-
*/
|
|
292
|
-
export async function loadAgyTokensWithRefresh(oauthProvider) {
|
|
293
|
-
const { loadTokens, saveTokens } = await import("./token-store.js");
|
|
294
|
-
let tokens = await loadTokens("google");
|
|
295
|
-
// Fallback: import existing tokens from agy local config on this machine.
|
|
296
|
-
if (!tokens) {
|
|
297
|
-
const imported = await tryLoadFromAgyCreds();
|
|
298
|
-
if (imported) {
|
|
299
|
-
if (Date.now() < imported.expiresAt) {
|
|
300
|
-
tokens = imported;
|
|
301
|
-
try {
|
|
302
|
-
await saveTokens("google", tokens);
|
|
303
|
-
}
|
|
304
|
-
catch {
|
|
305
|
-
// best effort
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
else {
|
|
309
|
-
// do not persist stale agy token to our store
|
|
310
|
-
tokens = imported;
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
if (!tokens)
|
|
315
|
-
return null;
|
|
316
|
-
const impl = oauthProvider ?? agyOAuth;
|
|
317
|
-
// Pre-emptive refresh
|
|
318
|
-
if (Date.now() >= tokens.expiresAt - REFRESH_WINDOW_MS) {
|
|
319
|
-
try {
|
|
320
|
-
// For tokens imported from agy, prefer the original client (azp from id_token)
|
|
321
|
-
// that issued this refresh_token. This makes refresh work even if the token
|
|
322
|
-
// was created by an older/newer agy client than our hardcoded one.
|
|
323
|
-
let refreshImpl = impl;
|
|
324
|
-
const originalClient = extractAzpFromIdToken(tokens.idToken);
|
|
325
|
-
if (originalClient && originalClient !== impl.clientId) {
|
|
326
|
-
// Use the exact client that issued this token (from id_token.azp)
|
|
327
|
-
// paired with agy secret. This is more reliable than hardcoded.
|
|
328
|
-
refreshImpl = new AgyOAuthProvider({
|
|
329
|
-
clientId: originalClient,
|
|
330
|
-
clientSecret: AGY_CLIENT_SECRET,
|
|
331
|
-
});
|
|
332
|
-
}
|
|
333
|
-
tokens = await refreshImpl.refresh(tokens);
|
|
334
|
-
await saveTokens("google", tokens);
|
|
335
|
-
}
|
|
336
|
-
catch {
|
|
337
|
-
// Return stale tokens — adapter will get 401 on actual request
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
return tokens;
|
|
341
|
-
}
|
|
342
|
-
/** Back-compat alias for older call sites. */
|
|
343
|
-
export const loadGeminiTokensWithRefresh = loadAgyTokensWithRefresh;
|
|
344
|
-
// ---------------------------------------------------------------------------
|
|
345
|
-
// Approach C: custom OAuth client from settings
|
|
346
|
-
// ---------------------------------------------------------------------------
|
|
347
|
-
const _GEMINI_SCOPES = [
|
|
348
|
-
"https://www.googleapis.com/auth/cloud-platform",
|
|
349
|
-
"https://www.googleapis.com/auth/generativelanguage",
|
|
350
|
-
"openid",
|
|
351
|
-
"email",
|
|
352
|
-
];
|
|
353
|
-
/**
|
|
354
|
-
* Load a custom OAuth token using user-provided GCP OAuth client credentials.
|
|
355
|
-
* Users register their own OAuth client in GCP Console → use these credentials
|
|
356
|
-
* to obtain tokens with the `generativelanguage` scope (not restricted to
|
|
357
|
-
* cloudcode-pa like the Agy client).
|
|
358
|
-
*
|
|
359
|
-
* Settings sources (in priority order):
|
|
360
|
-
* 1. settings.json → providers → google → oauthClientId / oauthClientSecret
|
|
361
|
-
* 2. MUONROI_GOOGLE_CLIENT_ID / MUONROI_GOOGLE_CLIENT_SECRET env vars
|
|
362
|
-
*
|
|
363
|
-
* Returns null when no custom client is configured.
|
|
364
|
-
*/
|
|
365
|
-
export async function loadCustomOAuthTokens() {
|
|
366
|
-
const { loadUserSettings } = await import("../../utils/settings.js");
|
|
367
|
-
const settings = loadUserSettings();
|
|
368
|
-
const providerSettings = settings?.providers?.google;
|
|
369
|
-
const clientId = providerSettings?.oauthClientId ?? process.env.MUONROI_GOOGLE_CLIENT_ID;
|
|
370
|
-
const clientSecret = providerSettings?.oauthClientSecret ?? process.env.MUONROI_GOOGLE_CLIENT_SECRET;
|
|
371
|
-
if (!clientId || !clientSecret)
|
|
372
|
-
return null;
|
|
373
|
-
// Load tokens from the token store using a deterministic key "google-custom"
|
|
374
|
-
const { loadTokens, saveTokens } = await import("./token-store.js");
|
|
375
|
-
let tokens = await loadTokens("google-custom");
|
|
376
|
-
if (!tokens)
|
|
377
|
-
return null;
|
|
378
|
-
const customProvider = new AgyOAuthProvider({ clientId, clientSecret });
|
|
379
|
-
// Pre-emptive refresh
|
|
380
|
-
if (Date.now() >= tokens.expiresAt - REFRESH_WINDOW_MS) {
|
|
381
|
-
try {
|
|
382
|
-
tokens = await customProvider.refresh(tokens);
|
|
383
|
-
await saveTokens("google-custom", tokens);
|
|
384
|
-
}
|
|
385
|
-
catch {
|
|
386
|
-
// Return stale — will get 401 later
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
return tokens;
|
|
390
|
-
}
|
|
391
|
-
/**
|
|
392
|
-
* Perform a full OAuth login with a custom client (Approach C).
|
|
393
|
-
* Users run `keys login google` with their own GCP OAuth client configured
|
|
394
|
-
* in settings → this opens the browser with the right scopes.
|
|
395
|
-
*/
|
|
396
|
-
export async function loginWithCustomClient() {
|
|
397
|
-
const { loadUserSettings } = await import("../../utils/settings.js");
|
|
398
|
-
const settings = loadUserSettings();
|
|
399
|
-
const providerSettings = settings?.providers?.google;
|
|
400
|
-
const clientId = providerSettings?.oauthClientId ?? process.env.MUONROI_GOOGLE_CLIENT_ID;
|
|
401
|
-
const clientSecret = providerSettings?.oauthClientSecret ?? process.env.MUONROI_GOOGLE_CLIENT_SECRET;
|
|
402
|
-
if (!clientId || !clientSecret)
|
|
403
|
-
return null;
|
|
404
|
-
const customProvider = new AgyOAuthProvider({ clientId, clientSecret });
|
|
405
|
-
// Override scopes to include generativelanguage
|
|
406
|
-
// The provider uses the existing login flow which requests AGY_SCOPES.
|
|
407
|
-
// For custom clients we want GEMINI_SCOPES instead, but the AgyOAuthProvider
|
|
408
|
-
// hardcodes AGY_SCOPES in the authorize URL. To use new scopes the user
|
|
409
|
-
// must configure them in their GCP OAuth consent screen.
|
|
410
|
-
// The client still gets a valid cloud-platform token via the browser flow.
|
|
411
|
-
const tokens = await customProvider.login();
|
|
412
|
-
const { saveTokens } = await import("./token-store.js");
|
|
413
|
-
await saveTokens("google-custom", tokens);
|
|
414
|
-
return tokens;
|
|
415
|
-
}
|
|
416
|
-
/**
|
|
417
|
-
* Try to load tokens previously obtained by agy (from ~/.gemini/oauth_creds.json).
|
|
418
|
-
*/
|
|
419
|
-
async function tryLoadFromAgyCreds() {
|
|
420
|
-
try {
|
|
421
|
-
const { readFile } = await import("node:fs/promises");
|
|
422
|
-
const os = await import("node:os");
|
|
423
|
-
const path = await import("node:path");
|
|
424
|
-
const agyPath = path.join(os.homedir(), ".gemini", "oauth_creds.json");
|
|
425
|
-
const raw = await readFile(agyPath, "utf8");
|
|
426
|
-
const data = JSON.parse(raw);
|
|
427
|
-
if (!data.refresh_token || !data.access_token)
|
|
428
|
-
return null;
|
|
429
|
-
const expiresAt = typeof data.expiry_date === "number" ? data.expiry_date : Date.now() + 3600_000;
|
|
430
|
-
const tokens = {
|
|
431
|
-
accessToken: data.access_token,
|
|
432
|
-
refreshToken: data.refresh_token,
|
|
433
|
-
idToken: data.id_token,
|
|
434
|
-
expiresAt,
|
|
435
|
-
};
|
|
436
|
-
const email = extractEmailFromGoogleIdToken(data.id_token);
|
|
437
|
-
if (email)
|
|
438
|
-
tokens.email = email;
|
|
439
|
-
const { enrollTokensInRedactor } = await import("./token-store.js");
|
|
440
|
-
enrollTokensInRedactor(tokens);
|
|
441
|
-
return tokens;
|
|
442
|
-
}
|
|
443
|
-
catch {
|
|
444
|
-
return null;
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
function extractEmailFromGoogleIdToken(idToken) {
|
|
448
|
-
const payload = parseGoogleIdToken(idToken);
|
|
449
|
-
return payload?.email;
|
|
450
|
-
}
|
|
451
|
-
function extractAzpFromIdToken(idToken) {
|
|
452
|
-
const payload = parseGoogleIdToken(idToken);
|
|
453
|
-
return payload?.azp;
|
|
454
|
-
}
|
|
455
|
-
function parseGoogleIdToken(idToken) {
|
|
456
|
-
if (!idToken)
|
|
457
|
-
return null;
|
|
458
|
-
try {
|
|
459
|
-
const parts = idToken.split(".");
|
|
460
|
-
if (parts.length < 2)
|
|
461
|
-
return null;
|
|
462
|
-
let b64 = parts[1].replace(/-/g, "+").replace(/_/g, "/");
|
|
463
|
-
while (b64.length % 4)
|
|
464
|
-
b64 += "=";
|
|
465
|
-
const json = Buffer.from(b64, "base64").toString("utf8");
|
|
466
|
-
return JSON.parse(json);
|
|
467
|
-
}
|
|
468
|
-
catch {
|
|
469
|
-
return null;
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
//# sourceMappingURL=gemini-oauth.js.map
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* src/providers/gemini.ts
|
|
3
|
-
*
|
|
4
|
-
* Gemini/Agy adapter implementation behind the Adapter interface.
|
|
5
|
-
* Uses @ai-sdk/google + AI SDK v6 streamText/fullStream.
|
|
6
|
-
*/
|
|
7
|
-
import type { Adapter, ProviderConfig } from "./types.js";
|
|
8
|
-
/**
|
|
9
|
-
* Create a Gemini (Google) adapter.
|
|
10
|
-
*/
|
|
11
|
-
export declare function createGeminiAdapter(config: ProviderConfig): Adapter;
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* src/providers/gemini.ts
|
|
3
|
-
*
|
|
4
|
-
* Gemini/Agy adapter implementation behind the Adapter interface.
|
|
5
|
-
* Uses @ai-sdk/google + AI SDK v6 streamText/fullStream.
|
|
6
|
-
*/
|
|
7
|
-
import { createGoogleGenerativeAI } from "@ai-sdk/google";
|
|
8
|
-
import { streamText } from "ai";
|
|
9
|
-
import { redactor } from "../utils/redactor.js";
|
|
10
|
-
import { streamFromFullStream } from "./stream-loop.js";
|
|
11
|
-
/**
|
|
12
|
-
* Create a Gemini (Google) adapter.
|
|
13
|
-
*/
|
|
14
|
-
export function createGeminiAdapter(config) {
|
|
15
|
-
if (config.apiKey && !config.oauthHeaders) {
|
|
16
|
-
redactor.enrollSecret(config.apiKey);
|
|
17
|
-
}
|
|
18
|
-
// When OAuth headers are present, route auth through extraHeaders. The Gemini
|
|
19
|
-
// SDK still wants a non-empty apiKey for config validation; the Authorization
|
|
20
|
-
// header takes precedence on the wire.
|
|
21
|
-
const provider = config.oauthHeaders
|
|
22
|
-
? createGoogleGenerativeAI({
|
|
23
|
-
apiKey: "oauth",
|
|
24
|
-
baseURL: config.baseURL,
|
|
25
|
-
headers: config.oauthHeaders,
|
|
26
|
-
})
|
|
27
|
-
: createGoogleGenerativeAI({
|
|
28
|
-
apiKey: config.apiKey,
|
|
29
|
-
baseURL: config.baseURL,
|
|
30
|
-
});
|
|
31
|
-
return {
|
|
32
|
-
id: "google",
|
|
33
|
-
async *stream(req) {
|
|
34
|
-
const result = streamText({
|
|
35
|
-
model: provider(config.model),
|
|
36
|
-
messages: req.messages,
|
|
37
|
-
tools: req.tools,
|
|
38
|
-
toolChoice: req.toolChoice,
|
|
39
|
-
abortSignal: req.abortSignal,
|
|
40
|
-
});
|
|
41
|
-
yield* streamFromFullStream(result.fullStream);
|
|
42
|
-
},
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
//# sourceMappingURL=gemini.js.map
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* src/providers/siliconflow-sse-repair.ts
|
|
3
|
-
*
|
|
4
|
-
* SiliconFlow streaming returns OpenAI-compatible SSE, but on Qwen3-30B
|
|
5
|
-
* tool-calling turns the FIRST `tool_calls` delta for a given index can
|
|
6
|
-
* arrive without `id` and/or `function.name` — those fields are pushed
|
|
7
|
-
* into a later chunk while the first chunk carries partial arguments.
|
|
8
|
-
*
|
|
9
|
-
* `@ai-sdk/openai-compatible@2.0.42` throws
|
|
10
|
-
* `InvalidResponseDataError("Expected 'id' to be a string.")` at
|
|
11
|
-
* `openai-compatible-chat-language-model.ts:537-541` the moment that
|
|
12
|
-
* first malformed delta lands. The user-visible failure: session
|
|
13
|
-
* 44db9105b119 (2026-05-26) crashed mid-stream right after the first
|
|
14
|
-
* grep tool call returned, with no recoverable state.
|
|
15
|
-
*
|
|
16
|
-
* Evidence chain:
|
|
17
|
-
* - DB row `routing|Qwen/Qwen3-30B-A3B-Instruct-2507` ts=12:30:33
|
|
18
|
-
* - DB row `tool_result|grep` ts=12:31:05.753 (last persisted event)
|
|
19
|
-
* - TUI scrollback shows `Expected 'id' to be a string.` ts=12:31:10
|
|
20
|
-
* - AI SDK source at the cited line confirms this is the ONLY path
|
|
21
|
-
* to that exact error message
|
|
22
|
-
*
|
|
23
|
-
* The fix is a `fetch` interceptor for SiliconFlow streaming responses:
|
|
24
|
-
*
|
|
25
|
-
* 1. Per index, buffer (id, name, args) until BOTH id+name are seen.
|
|
26
|
-
* 2. The moment both arrive, emit ONE synthesized "first chunk" with
|
|
27
|
-
* the accumulated arguments string.
|
|
28
|
-
* 3. After that, every subsequent delta for that index passes through
|
|
29
|
-
* unmodified.
|
|
30
|
-
*
|
|
31
|
-
* Well-formed streams (id+name on the first chunk) hit only the
|
|
32
|
-
* pass-through path — the repairer is a no-op for them.
|
|
33
|
-
*
|
|
34
|
-
* Tests in `__tests__/siliconflow-sse-repair.test.ts` pin both the
|
|
35
|
-
* malformed and well-formed cases, plus non-SSE pass-through, [DONE]
|
|
36
|
-
* sentinel, and multi-index streams.
|
|
37
|
-
*/
|
|
38
|
-
export declare class SiliconflowSseRepairer {
|
|
39
|
-
private states;
|
|
40
|
-
/**
|
|
41
|
-
* Process one SSE event. Returns the repaired event text (possibly
|
|
42
|
-
* empty string to suppress the event entirely).
|
|
43
|
-
*
|
|
44
|
-
* The event text MUST include the trailing blank-line terminator
|
|
45
|
-
* (`\n\n` or `\r\n\r\n`); the caller is responsible for splitting on
|
|
46
|
-
* event boundaries.
|
|
47
|
-
*/
|
|
48
|
-
repairEvent(eventText: string): string;
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* Wrap a `fetch` implementation so SiliconFlow SSE responses are
|
|
52
|
-
* repaired before reaching `@ai-sdk/openai-compatible`. Non-SSE
|
|
53
|
-
* responses are passed through untouched.
|
|
54
|
-
*/
|
|
55
|
-
export declare function createSiliconflowRepairFetch(base?: typeof fetch): typeof fetch;
|
|
56
|
-
export declare const _internals: {
|
|
57
|
-
SiliconflowSseRepairer: typeof SiliconflowSseRepairer;
|
|
58
|
-
};
|