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
|
@@ -32,6 +32,10 @@ export interface IterationState {
|
|
|
32
32
|
criteriaMet: number;
|
|
33
33
|
criteriaPartial: number;
|
|
34
34
|
criteriaUnmet: number;
|
|
35
|
+
/** Total criteria evaluated this sprint. Optional for back-compat with older
|
|
36
|
+
* persisted iterations; when present it fixes the phase-runner exit ratio + the
|
|
37
|
+
* sprint-review "met X/Y" count that previously read undefined. */
|
|
38
|
+
totalCriteria?: number;
|
|
35
39
|
costUsd: number;
|
|
36
40
|
lastVerifyResult: string;
|
|
37
41
|
/** Alias of costUsd kept for circuit-breaker history adapters (CB-1 reads actualCost). */
|
|
@@ -40,6 +44,16 @@ export interface IterationState {
|
|
|
40
44
|
score?: number;
|
|
41
45
|
crashed?: boolean;
|
|
42
46
|
retryOf?: number;
|
|
47
|
+
/**
|
|
48
|
+
* Carry-over focus for the NEXT sprint when this one did not satisfy the
|
|
49
|
+
* done-gate: the failed-condition focus (feedback-routing) plus any plan
|
|
50
|
+
* deviations that survived the adherence review. The phase-runner adapter
|
|
51
|
+
* threads this into the next sprint's `carryOver` so each iteration continues
|
|
52
|
+
* the specific unmet / risky parts instead of restarting blind — the mechanism
|
|
53
|
+
* behind "spawn to continue the risk parts → finished product after N sprints".
|
|
54
|
+
* Absent when the sprint passed.
|
|
55
|
+
*/
|
|
56
|
+
nextFocus?: string;
|
|
43
57
|
}
|
|
44
58
|
export interface DoneVerdict {
|
|
45
59
|
pass: boolean;
|
|
@@ -128,6 +142,18 @@ export interface DriverContext {
|
|
|
128
142
|
* without it; sprint-runner enforces presence at call time.
|
|
129
143
|
*/
|
|
130
144
|
processMessageFn?: (message: string) => AsyncGenerator<import("../types/index.js").StreamChunk, void, unknown>;
|
|
145
|
+
/**
|
|
146
|
+
* Bridge into the orchestrator's ISOLATED task-runner (Agent.runTaskRequest →
|
|
147
|
+
* StreamRunner). Unlike processMessageFn — which appends to the shared
|
|
148
|
+
* top-level context and therefore inherits the (large) council-debate history —
|
|
149
|
+
* each call here runs in a FRESH, budget-capped (getSubAgentBudgetChars) child
|
|
150
|
+
* context with independent in-loop compaction, and returns a compact ToolResult
|
|
151
|
+
* summary instead of streaming into the parent. Sprint-runner uses this for the
|
|
152
|
+
* implement stage so the impl never inherits the debate context (which caused a
|
|
153
|
+
* live ctx-overflow wedge). Optional: legacy/test drivers omit it → sprint-runner
|
|
154
|
+
* falls back to processMessageFn.
|
|
155
|
+
*/
|
|
156
|
+
runIsolatedTask?: (request: import("../types/index.js").TaskRequest) => Promise<import("../types/index.js").ToolResult>;
|
|
131
157
|
/**
|
|
132
158
|
* Optional bridge for verify-recipe detection. Mirrors `Orchestrator.detectVerifyRecipe`.
|
|
133
159
|
* If absent, sprint-runner uses a deterministic fallback based on the inferVerifyProjectProfile
|
|
@@ -185,7 +211,7 @@ export type ProductTypeT = "saas" | "internal-tool" | "consumer-app" | "b2b-plat
|
|
|
185
211
|
export type PlatformT = "web" | "mobile-ios" | "mobile-android" | "desktop-win" | "desktop-mac" | "desktop-linux" | "cli";
|
|
186
212
|
export type ScaleT = "1-100" | "100-1k" | "1k-100k" | "100k-1M" | "1M+";
|
|
187
213
|
export type BackendArchT = "monolith" | "modular-monolith" | "microservices" | "serverless" | "none";
|
|
188
|
-
export type DbModeT = "greenfield" | "existing-schema" | "migrate-from";
|
|
214
|
+
export type DbModeT = "none" | "greenfield" | "existing-schema" | "migrate-from";
|
|
189
215
|
export type FeLibraryT = "shadcn" | "radix" | "headlessui" | "none";
|
|
190
216
|
export interface AudienceCtx {
|
|
191
217
|
persona: string;
|
|
@@ -266,6 +292,17 @@ export interface ProjectContext {
|
|
|
266
292
|
idea: string;
|
|
267
293
|
detection: ExistingProjectSignals;
|
|
268
294
|
context: DiscoveryContext;
|
|
295
|
+
/**
|
|
296
|
+
* Agent-driven interview output. When the gather phase runs the unified
|
|
297
|
+
* clarifier (the same LLM-generates-its-own-questions engine `/council`
|
|
298
|
+
* uses — see runGatherPhase), it produces a rich `ClarifiedSpec` directly
|
|
299
|
+
* instead of the fixed-question `DiscoveryContext`. Stashed here (plain data,
|
|
300
|
+
* JSON round-trips through project-context.md) so `clarifiedSpecFromContext`
|
|
301
|
+
* can return the real LLM-synthesized successCriteria/constraints/scope
|
|
302
|
+
* verbatim rather than re-deriving a thin 2-item spec from persona+scale.
|
|
303
|
+
* Absent on the legacy fixed-question path (MUONROI_IDEAL_AGENT_INTERVIEW=0).
|
|
304
|
+
*/
|
|
305
|
+
clarified?: import("../council/types.js").ClarifiedSpec;
|
|
269
306
|
recommendations: {
|
|
270
307
|
byField: Record<string, RecommendationEntry>;
|
|
271
308
|
constraints: {
|
|
@@ -353,8 +390,12 @@ export interface PhaseDigestEntry {
|
|
|
353
390
|
* The UI (Task 5.2) wires each id to a concrete handler.
|
|
354
391
|
*/
|
|
355
392
|
export interface RecoveryOption {
|
|
356
|
-
/**
|
|
357
|
-
|
|
393
|
+
/**
|
|
394
|
+
* Stable key. Used by the UI to wire actions.
|
|
395
|
+
* - CB-3 halt (no recipe): init_new | point_to_existing | continue_as_council
|
|
396
|
+
* - Sprint break (A): resume | retry | skip_verify | abort
|
|
397
|
+
*/
|
|
398
|
+
id: "init_new" | "point_to_existing" | "continue_as_council" | "resume" | "retry" | "skip_verify" | "abort";
|
|
358
399
|
/** Label shown in the recovery card. */
|
|
359
400
|
label: string;
|
|
360
401
|
/** One-line user-facing description of what choosing this does. */
|
|
@@ -367,10 +408,22 @@ export interface RecoveryOption {
|
|
|
367
408
|
*/
|
|
368
409
|
export interface HaltChunk {
|
|
369
410
|
type: "halt";
|
|
370
|
-
/**
|
|
371
|
-
|
|
411
|
+
/**
|
|
412
|
+
* CB-3 emits "no_recipe" / "zero_coverage"; product-loop emits
|
|
413
|
+
* "budget_exhausted" when --budget-tokens trips; "sprint_failed" (A) when a
|
|
414
|
+
* sprint breaks mid-run (thrown implement/verify error, cap breach, etc.).
|
|
415
|
+
*/
|
|
416
|
+
reason: "no_recipe" | "zero_coverage" | "budget_exhausted" | "sprint_failed";
|
|
372
417
|
/** Optional human-readable detail rendered alongside the recovery card. */
|
|
373
418
|
detail?: string;
|
|
419
|
+
/**
|
|
420
|
+
* A — the run this halt belongs to. Lets the recovery card auto-wire
|
|
421
|
+
* Resume/Retry/Abort to `/ideal <action> <runId>` without the user knowing
|
|
422
|
+
* (or typing) the runId. Set on "sprint_failed" halts.
|
|
423
|
+
*/
|
|
424
|
+
runId?: string;
|
|
425
|
+
/** A — the sprint number that broke, for the "Sprint N failed" card title. */
|
|
426
|
+
sprintN?: number;
|
|
374
427
|
/** Actionable choices. UI renders these as buttons / list items. */
|
|
375
428
|
recovery_options: RecoveryOption[];
|
|
376
429
|
}
|
|
@@ -393,6 +446,9 @@ export interface RunPhasesOptions {
|
|
|
393
446
|
}) => Promise<Omit<CustomerDecision, "seq" | "timestampUtc" | "phaseId" | "sprintN">>;
|
|
394
447
|
suppressPush?: boolean;
|
|
395
448
|
backoffDelays?: number[];
|
|
449
|
+
/** Project repo cwd — hosts `.planning/` when MUONROI_GSD_NATIVE=1 */
|
|
450
|
+
projectCwd?: string;
|
|
451
|
+
idea?: string;
|
|
396
452
|
}
|
|
397
453
|
export type BacklogItemStatus = "backlog" | "in_sprint" | "in_progress" | "done" | "blocked";
|
|
398
454
|
export type MvpPriority = "v1" | "v2" | "later";
|
|
@@ -45,7 +45,7 @@ export declare function createAdapter(id: ProviderId, config: ProviderConfig): A
|
|
|
45
45
|
* Dispatch is registry-driven — no `if (id === "openai")` branching. To add
|
|
46
46
|
* OAuth for a new provider (Anthropic, etc.):
|
|
47
47
|
* 1. Register the provider in `providers/auth/registry.ts`.
|
|
48
|
-
* 2. Ensure its adapter honors `config.oauthHeaders` (see openai.ts/anthropic.ts
|
|
48
|
+
* 2. Ensure its adapter honors `config.oauthHeaders` (see openai.ts/anthropic.ts).
|
|
49
49
|
*
|
|
50
50
|
* Behavior per provider:
|
|
51
51
|
* - OAuth tokens present (auto-refreshed) → adapter built with Bearer headers,
|
|
@@ -32,7 +32,6 @@
|
|
|
32
32
|
import { createAnthropicAdapter } from "./anthropic.js";
|
|
33
33
|
import { getOAuthProviderConfig } from "./auth/registry.js";
|
|
34
34
|
import { apiBaseFor } from "./endpoints.js";
|
|
35
|
-
import { createGeminiAdapter } from "./gemini.js";
|
|
36
35
|
import { createOllamaAdapter } from "./ollama.js";
|
|
37
36
|
import { createOpenAIAdapter } from "./openai.js";
|
|
38
37
|
import { createOpenAICompatibleAdapter } from "./openai-compatible.js";
|
|
@@ -55,11 +54,11 @@ const ADAPTER_FACTORIES = {
|
|
|
55
54
|
anthropic: (config) => createAnthropicAdapter(config),
|
|
56
55
|
// Synchronous path: API-key only (no OAuth auto-load). Use createAdapterAsync for OAuth.
|
|
57
56
|
openai: (config) => createOpenAIAdapter(config),
|
|
58
|
-
google: (config) => createGeminiAdapter(config),
|
|
59
57
|
deepseek: (config) => createOpenAICompatibleAdapter({ ...config, id: "deepseek" }),
|
|
60
|
-
siliconflow: (config) => createOpenAICompatibleAdapter({ ...config, id: "siliconflow" }),
|
|
61
58
|
xai: (config) => createOpenAICompatibleAdapter({ ...config, id: "xai", baseURL: config.baseURL ?? apiBaseFor("xai") }),
|
|
62
59
|
ollama: (config) => createOllamaAdapter(config),
|
|
60
|
+
zai: (config) => createOpenAICompatibleAdapter({ ...config, id: "zai", baseURL: config.baseURL ?? apiBaseFor("zai") }),
|
|
61
|
+
"opencode-go": (config) => createOpenAICompatibleAdapter({ ...config, id: "opencode-go" }),
|
|
63
62
|
};
|
|
64
63
|
/**
|
|
65
64
|
* Create an Adapter for the given provider.
|
|
@@ -86,7 +85,7 @@ export function createAdapter(id, config) {
|
|
|
86
85
|
* Dispatch is registry-driven — no `if (id === "openai")` branching. To add
|
|
87
86
|
* OAuth for a new provider (Anthropic, etc.):
|
|
88
87
|
* 1. Register the provider in `providers/auth/registry.ts`.
|
|
89
|
-
* 2. Ensure its adapter honors `config.oauthHeaders` (see openai.ts/anthropic.ts
|
|
88
|
+
* 2. Ensure its adapter honors `config.oauthHeaders` (see openai.ts/anthropic.ts).
|
|
90
89
|
*
|
|
91
90
|
* Behavior per provider:
|
|
92
91
|
* - OAuth tokens present (auto-refreshed) → adapter built with Bearer headers,
|
|
@@ -2,16 +2,15 @@
|
|
|
2
2
|
* src/providers/anthropic.ts
|
|
3
3
|
*
|
|
4
4
|
* Anthropic-only provider shell for Phase 0.
|
|
5
|
-
* Implements TUI-02 (stub conversation), PROV-03 (BYOK
|
|
5
|
+
* Implements TUI-02 (stub conversation), PROV-03 (BYOK), PROV-07 (log redaction).
|
|
6
6
|
*
|
|
7
|
-
* Key loading
|
|
8
|
-
* 1.
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* Key loading:
|
|
8
|
+
* 1. ANTHROPIC_API_KEY env var (the env-store loads ~/.muonroi-cli/.env into
|
|
9
|
+
* process.env at startup; the real OS env also applies)
|
|
10
|
+
* 2. AnthropicKeyMissingError — user-facing error with remediation instructions
|
|
11
11
|
*
|
|
12
12
|
* Security invariants:
|
|
13
13
|
* - redactor.enrollSecret(key) is called BEFORE any log line that might contain the key.
|
|
14
|
-
* - keytar is loaded via dynamic import() so a missing/broken native module cannot crash boot.
|
|
15
14
|
* - Keys shorter than 20 characters are rejected early.
|
|
16
15
|
*
|
|
17
16
|
* Streaming (AI SDK v6 with @ai-sdk/anthropic):
|
|
@@ -32,13 +31,15 @@ export declare class AnthropicKeyMissingError extends Error {
|
|
|
32
31
|
constructor();
|
|
33
32
|
}
|
|
34
33
|
/**
|
|
35
|
-
* Load the Anthropic API key from the
|
|
34
|
+
* Load the Anthropic API key from the environment (the env-store loads
|
|
35
|
+
* `~/.muonroi-cli/.env` into process.env at startup; the real OS env also
|
|
36
|
+
* applies).
|
|
36
37
|
*
|
|
37
38
|
* Security contract:
|
|
38
39
|
* - redactor.enrollSecret(key) is called BEFORE any subsequent log line.
|
|
39
40
|
* - Keys < 20 chars are rejected (T-00.05-05: truncated key guard).
|
|
40
41
|
*
|
|
41
|
-
* @throws {AnthropicKeyMissingError} when
|
|
42
|
+
* @throws {AnthropicKeyMissingError} when no ANTHROPIC_API_KEY is present.
|
|
42
43
|
*/
|
|
43
44
|
export declare function loadAnthropicKey(): Promise<string>;
|
|
44
45
|
/**
|
|
@@ -2,16 +2,15 @@
|
|
|
2
2
|
* src/providers/anthropic.ts
|
|
3
3
|
*
|
|
4
4
|
* Anthropic-only provider shell for Phase 0.
|
|
5
|
-
* Implements TUI-02 (stub conversation), PROV-03 (BYOK
|
|
5
|
+
* Implements TUI-02 (stub conversation), PROV-03 (BYOK), PROV-07 (log redaction).
|
|
6
6
|
*
|
|
7
|
-
* Key loading
|
|
8
|
-
* 1.
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* Key loading:
|
|
8
|
+
* 1. ANTHROPIC_API_KEY env var (the env-store loads ~/.muonroi-cli/.env into
|
|
9
|
+
* process.env at startup; the real OS env also applies)
|
|
10
|
+
* 2. AnthropicKeyMissingError — user-facing error with remediation instructions
|
|
11
11
|
*
|
|
12
12
|
* Security invariants:
|
|
13
13
|
* - redactor.enrollSecret(key) is called BEFORE any log line that might contain the key.
|
|
14
|
-
* - keytar is loaded via dynamic import() so a missing/broken native module cannot crash boot.
|
|
15
14
|
* - Keys shorter than 20 characters are rejected early.
|
|
16
15
|
*
|
|
17
16
|
* Streaming (AI SDK v6 with @ai-sdk/anthropic):
|
|
@@ -43,58 +42,25 @@ export class AnthropicKeyMissingError extends Error {
|
|
|
43
42
|
this.name = "AnthropicKeyMissingError";
|
|
44
43
|
}
|
|
45
44
|
}
|
|
45
|
+
// ---------------------------------------------------------------------------
|
|
46
|
+
// Key loader
|
|
47
|
+
// ---------------------------------------------------------------------------
|
|
46
48
|
/**
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*/
|
|
51
|
-
async function loadKeytar() {
|
|
52
|
-
try {
|
|
53
|
-
// keytar exports named functions directly (no default export)
|
|
54
|
-
const mod = await import("keytar");
|
|
55
|
-
return mod;
|
|
56
|
-
}
|
|
57
|
-
catch {
|
|
58
|
-
return null;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* Load the Anthropic API key from the OS keychain first, then env var fallback.
|
|
49
|
+
* Load the Anthropic API key from the environment (the env-store loads
|
|
50
|
+
* `~/.muonroi-cli/.env` into process.env at startup; the real OS env also
|
|
51
|
+
* applies).
|
|
63
52
|
*
|
|
64
53
|
* Security contract:
|
|
65
54
|
* - redactor.enrollSecret(key) is called BEFORE any subsequent log line.
|
|
66
55
|
* - Keys < 20 chars are rejected (T-00.05-05: truncated key guard).
|
|
67
56
|
*
|
|
68
|
-
* @throws {AnthropicKeyMissingError} when
|
|
57
|
+
* @throws {AnthropicKeyMissingError} when no ANTHROPIC_API_KEY is present.
|
|
69
58
|
*/
|
|
70
59
|
export async function loadAnthropicKey() {
|
|
71
|
-
// --- Primary: OS keychain via dynamic import (B-2) ---
|
|
72
|
-
const keytarMod = await loadKeytar();
|
|
73
|
-
if (keytarMod) {
|
|
74
|
-
try {
|
|
75
|
-
const key = await keytarMod.getPassword("muonroi-cli", "anthropic");
|
|
76
|
-
if (key && key.length >= 20) {
|
|
77
|
-
// Enroll BEFORE any log that might emit the key
|
|
78
|
-
redactor.enrollSecret(key);
|
|
79
|
-
return key;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
catch (err) {
|
|
83
|
-
// keytar present but backend unavailable (e.g. Linux without libsecret/dbus)
|
|
84
|
-
console.warn("[muonroi-cli] keytar backend unavailable, falling back to env var:", redactor.redactError(err));
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
else {
|
|
88
|
-
console.warn("[muonroi-cli] keytar module not installed — using env-var path. " +
|
|
89
|
-
"Install keytar to enable OS keychain key storage.");
|
|
90
|
-
}
|
|
91
|
-
// --- Fallback: ANTHROPIC_API_KEY environment variable ---
|
|
92
60
|
const envKey = process.env.ANTHROPIC_API_KEY;
|
|
93
61
|
if (envKey && envKey.length >= 20) {
|
|
94
|
-
// Enroll BEFORE
|
|
62
|
+
// Enroll BEFORE any log that might mention the key path.
|
|
95
63
|
redactor.enrollSecret(envKey);
|
|
96
|
-
console.warn("[muonroi-cli] Using ANTHROPIC_API_KEY from environment. " +
|
|
97
|
-
"Prefer storing the key in your OS keychain (Phase 1 `muonroi-cli login` helper).");
|
|
98
64
|
return envKey;
|
|
99
65
|
}
|
|
100
66
|
throw new AnthropicKeyMissingError();
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Generic helpers for Authorization Code + PKCE browser-redirect OAuth flows.
|
|
5
5
|
* Usable for any provider that supports the standard OAuth 2.0 browser-redirect
|
|
6
|
-
* grant
|
|
6
|
+
* grant. Not for device-code flows (see device-flow.ts).
|
|
7
7
|
*
|
|
8
8
|
* Re-exports generatePKCE from device-flow.ts so callers need only one import.
|
|
9
9
|
*/
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Generic helpers for Authorization Code + PKCE browser-redirect OAuth flows.
|
|
5
5
|
* Usable for any provider that supports the standard OAuth 2.0 browser-redirect
|
|
6
|
-
* grant
|
|
6
|
+
* grant. Not for device-code flows (see device-flow.ts).
|
|
7
7
|
*
|
|
8
8
|
* Re-exports generatePKCE from device-flow.ts so callers need only one import.
|
|
9
9
|
*/
|
|
@@ -49,6 +49,7 @@ export declare class GrokOAuthProvider implements ProviderOAuth {
|
|
|
49
49
|
});
|
|
50
50
|
login(opts?: {
|
|
51
51
|
onUserCode?: (code: string, url: string) => void;
|
|
52
|
+
signal?: AbortSignal;
|
|
52
53
|
}): Promise<OAuthTokens>;
|
|
53
54
|
refresh(tokens: OAuthTokens): Promise<OAuthTokens>;
|
|
54
55
|
revoke(tokens: OAuthTokens): Promise<void>;
|
|
@@ -114,6 +114,7 @@ export class GrokOAuthProvider {
|
|
|
114
114
|
const state = randomBytes(16).toString("base64url");
|
|
115
115
|
const nonce = randomBytes(16).toString("base64url");
|
|
116
116
|
let callbackServer;
|
|
117
|
+
let manualPasteRl;
|
|
117
118
|
let authCode;
|
|
118
119
|
let receivedState = "";
|
|
119
120
|
try {
|
|
@@ -125,6 +126,19 @@ export class GrokOAuthProvider {
|
|
|
125
126
|
const loginTimeout = setTimeout(() => {
|
|
126
127
|
reject(new Error("OAuth browser callback timed out"));
|
|
127
128
|
}, CALLBACK_TIMEOUT_MS);
|
|
129
|
+
// Cancelling must END the flow, not just abandon it: the `finally`
|
|
130
|
+
// below is what closes the loopback server (and the readline), and an
|
|
131
|
+
// abandoned server holds its port for the full callback timeout, so the
|
|
132
|
+
// next sign-in cannot bind.
|
|
133
|
+
const onAbort = () => {
|
|
134
|
+
clearTimeout(loginTimeout);
|
|
135
|
+
reject(new OAuthLoginError("xai", "Sign-in cancelled."));
|
|
136
|
+
};
|
|
137
|
+
if (opts.signal?.aborted) {
|
|
138
|
+
onAbort();
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
opts.signal?.addEventListener("abort", onAbort, { once: true });
|
|
128
142
|
this.callbackServerFn({
|
|
129
143
|
onCode: (code, s) => {
|
|
130
144
|
receivedState = s;
|
|
@@ -146,15 +160,23 @@ export class GrokOAuthProvider {
|
|
|
146
160
|
});
|
|
147
161
|
opts.onUserCode?.(authorizeUrl, authorizeUrl);
|
|
148
162
|
this.openBrowserFn(authorizeUrl);
|
|
149
|
-
//
|
|
150
|
-
|
|
151
|
-
|
|
163
|
+
// Manual code-paste fallback (xAI's page sometimes shows a code
|
|
164
|
+
// instead of redirecting to the loopback URI).
|
|
165
|
+
//
|
|
166
|
+
// CLI only. `isRaw` means another consumer already owns stdin —
|
|
167
|
+
// inside the TUI that is OpenTUI's key handler. Attaching a readline
|
|
168
|
+
// there stole every keystroke, and on the normal HTTP-callback path
|
|
169
|
+
// it was never closed, so the TUI kept receiving nothing: Esc did
|
|
170
|
+
// not dismiss the provider dialog and only restarting the session
|
|
171
|
+
// recovered it. The console.log pair also printed into the TUI's
|
|
172
|
+
// alternate screen. Both are correct for `keys login`, wrong here.
|
|
173
|
+
if (process.stdin.isTTY && !process.stdin.isRaw) {
|
|
174
|
+
manualPasteRl = readline.createInterface({ input: process.stdin });
|
|
152
175
|
console.log(' If the xAI page shows a code ("Could not establish connection") instead of redirecting,');
|
|
153
176
|
console.log(" copy the code and paste it here then press Enter:");
|
|
154
|
-
|
|
177
|
+
manualPasteRl.on("line", (line) => {
|
|
155
178
|
const c = line.trim();
|
|
156
179
|
if (c.length > 30) {
|
|
157
|
-
rl.close();
|
|
158
180
|
clearTimeout(loginTimeout);
|
|
159
181
|
resolve(c);
|
|
160
182
|
}
|
|
@@ -174,6 +196,9 @@ export class GrokOAuthProvider {
|
|
|
174
196
|
}
|
|
175
197
|
finally {
|
|
176
198
|
callbackServer?.close();
|
|
199
|
+
// Unconditional: the old code only closed this when the user actually
|
|
200
|
+
// pasted a code, so the normal HTTP-callback path left stdin captured.
|
|
201
|
+
manualPasteRl?.close();
|
|
177
202
|
}
|
|
178
203
|
if (receivedState && receivedState !== state) {
|
|
179
204
|
throw new OAuthLoginError("xai", "OAuth state mismatch — possible CSRF, aborting.");
|
|
@@ -50,6 +50,7 @@ export declare class OpenAIOAuthProvider implements ProviderOAuth {
|
|
|
50
50
|
});
|
|
51
51
|
login(opts?: {
|
|
52
52
|
onUserCode?: (code: string, url: string) => void;
|
|
53
|
+
signal?: AbortSignal;
|
|
53
54
|
}): Promise<OAuthTokens>;
|
|
54
55
|
refresh(tokens: OAuthTokens): Promise<OAuthTokens>;
|
|
55
56
|
revoke(tokens: OAuthTokens): Promise<void>;
|
|
@@ -117,6 +117,20 @@ export class OpenAIOAuthProvider {
|
|
|
117
117
|
const loginTimeout = setTimeout(() => {
|
|
118
118
|
reject(new Error("OAuth browser callback timed out"));
|
|
119
119
|
}, CALLBACK_TIMEOUT_MS);
|
|
120
|
+
// Cancelling used to abandon this promise rather than end it: the
|
|
121
|
+
// loopback server then held its port for the full CALLBACK_TIMEOUT_MS
|
|
122
|
+
// (5 min) across only two ports, so the next sign-in could not bind and
|
|
123
|
+
// the user had to restart the CLI. Rejecting here runs the `finally`
|
|
124
|
+
// below, which closes the server and frees the port immediately.
|
|
125
|
+
const onAbort = () => {
|
|
126
|
+
clearTimeout(loginTimeout);
|
|
127
|
+
reject(new OAuthLoginError("openai", "Sign-in cancelled."));
|
|
128
|
+
};
|
|
129
|
+
if (opts.signal?.aborted) {
|
|
130
|
+
onAbort();
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
opts.signal?.addEventListener("abort", onAbort, { once: true });
|
|
120
134
|
const tryPorts = async () => {
|
|
121
135
|
let bindError;
|
|
122
136
|
for (const port of CODEX_PORTS) {
|
|
@@ -321,7 +335,7 @@ function extractIdTokenClaim(idToken, key) {
|
|
|
321
335
|
}
|
|
322
336
|
function buildOpenAIAuthorizeUrl(opts) {
|
|
323
337
|
// Build the query string by hand — generic helpers like buildAuthorizeUrl()
|
|
324
|
-
// inject
|
|
338
|
+
// inject extra params (access_type=offline, prompt=consent) that
|
|
325
339
|
// OpenAI's auth backend rejects with "Authentication Error".
|
|
326
340
|
const params = new URLSearchParams({
|
|
327
341
|
response_type: "code",
|
|
@@ -50,40 +50,6 @@ export async function loadOAuthRegistry() {
|
|
|
50
50
|
catch {
|
|
51
51
|
/* openai-oauth unavailable */
|
|
52
52
|
}
|
|
53
|
-
try {
|
|
54
|
-
const { agyOAuth, loadAgyTokensWithRefresh, loadCustomOAuthTokens } = await import("./gemini-oauth.js");
|
|
55
|
-
const { loadGcloudToken } = await import("./gcloud.js");
|
|
56
|
-
r.google = {
|
|
57
|
-
provider: agyOAuth,
|
|
58
|
-
displayName: "Agy",
|
|
59
|
-
// baseURL intentionally left undefined for the google provider.
|
|
60
|
-
// When OAuth tokens are present, the custom fetch-based provider in
|
|
61
|
-
// google.strategy.ts (Approach A) uses the user-specified baseURL from
|
|
62
|
-
// settings, or falls back to generativelanguage.googleapis.com/v1beta.
|
|
63
|
-
// The old hardcoded cloudcode-pa.googleapis.com endpoint is dead.
|
|
64
|
-
//
|
|
65
|
-
// Token loading chain (Approach B + C):
|
|
66
|
-
// 1. Custom OAuth client from env vars MUONROI_GOOGLE_CLIENT_ID/SECRET
|
|
67
|
-
// or settings providers.google.oauthClientId/oauthClientSecret
|
|
68
|
-
// 2. gcloud ADC (~/.config/gcloud/application_default_credentials.json)
|
|
69
|
-
// 3. Agy OAuth tokens from ~/.gemini/oauth_creds.json (legacy)
|
|
70
|
-
loadTokensWithRefresh: async () => {
|
|
71
|
-
// Approach C: try custom OAuth client first (user-registered GCP client)
|
|
72
|
-
const custom = await loadCustomOAuthTokens().catch(() => null);
|
|
73
|
-
if (custom)
|
|
74
|
-
return custom;
|
|
75
|
-
// Approach B: try gcloud ADC (works immediately after gcloud auth login)
|
|
76
|
-
const gcloud = await loadGcloudToken().catch(() => null);
|
|
77
|
-
if (gcloud)
|
|
78
|
-
return gcloud;
|
|
79
|
-
// Legacy fallback: Agy tokens from ~/.gemini/oauth_creds.json
|
|
80
|
-
return loadAgyTokensWithRefresh();
|
|
81
|
-
},
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
catch {
|
|
85
|
-
/* agy-oauth unavailable */
|
|
86
|
-
}
|
|
87
53
|
try {
|
|
88
54
|
const { grokOAuth, loadGrokTokensWithRefresh } = await import("./grok-oauth.js");
|
|
89
55
|
r.xai = {
|
|
@@ -2,10 +2,8 @@
|
|
|
2
2
|
* src/providers/auth/token-store.ts
|
|
3
3
|
*
|
|
4
4
|
* Persistent store for provider OAuth tokens.
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* Value: JSON-serialized OAuthTokens.
|
|
8
|
-
* Fallback: ~/.muonroi-cli/auth/<provider>.json, mode 0600.
|
|
5
|
+
* Storage: ~/.muonroi-cli/auth/<provider>.json, mode 0600 (JSON-serialized
|
|
6
|
+
* OAuthTokens). The OS keychain (keytar) has been removed.
|
|
9
7
|
*
|
|
10
8
|
* All token fields are enrolled in the redactor immediately after load.
|
|
11
9
|
*/
|
|
@@ -14,15 +12,17 @@ import type { OAuthTokens } from "./types.js";
|
|
|
14
12
|
* Enroll all token secrets so they are scrubbed from logs.
|
|
15
13
|
*/
|
|
16
14
|
export declare function enrollTokensInRedactor(tokens: OAuthTokens): void;
|
|
15
|
+
/**
|
|
16
|
+
* Persist OAuth tokens for a provider to ~/.muonroi-cli/auth/<provider>.json
|
|
17
|
+
* (mode 0600).
|
|
18
|
+
*/
|
|
17
19
|
export declare function saveTokens(provider: string, tokens: OAuthTokens): Promise<void>;
|
|
18
20
|
/**
|
|
19
|
-
* Load OAuth tokens for a provider.
|
|
20
|
-
* Returns null if no tokens are stored.
|
|
21
|
-
* Enrolled in redactor on load.
|
|
21
|
+
* Load OAuth tokens for a provider from the 0600 file store.
|
|
22
|
+
* Returns null if no tokens are stored. Enrolled in redactor on load.
|
|
22
23
|
*/
|
|
23
24
|
export declare function loadTokens(provider: string): Promise<OAuthTokens | null>;
|
|
24
25
|
/**
|
|
25
|
-
* Delete stored OAuth tokens for a provider.
|
|
26
|
-
* Attempts both keychain and file removal (either may or may not exist).
|
|
26
|
+
* Delete stored OAuth tokens for a provider (removes the 0600 file).
|
|
27
27
|
*/
|
|
28
28
|
export declare function deleteTokens(provider: string): Promise<void>;
|
|
@@ -2,10 +2,8 @@
|
|
|
2
2
|
* src/providers/auth/token-store.ts
|
|
3
3
|
*
|
|
4
4
|
* Persistent store for provider OAuth tokens.
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* Value: JSON-serialized OAuthTokens.
|
|
8
|
-
* Fallback: ~/.muonroi-cli/auth/<provider>.json, mode 0600.
|
|
5
|
+
* Storage: ~/.muonroi-cli/auth/<provider>.json, mode 0600 (JSON-serialized
|
|
6
|
+
* OAuthTokens). The OS keychain (keytar) has been removed.
|
|
9
7
|
*
|
|
10
8
|
* All token fields are enrolled in the redactor immediately after load.
|
|
11
9
|
*/
|
|
@@ -13,10 +11,6 @@ import { mkdir, readFile, unlink, writeFile } from "node:fs/promises";
|
|
|
13
11
|
import * as os from "node:os";
|
|
14
12
|
import * as path from "node:path";
|
|
15
13
|
import { redactor } from "../../utils/redactor.js";
|
|
16
|
-
const KEYCHAIN_SERVICE = "muonroi-cli";
|
|
17
|
-
function oauthAccount(provider) {
|
|
18
|
-
return `oauth:${provider}`;
|
|
19
|
-
}
|
|
20
14
|
/**
|
|
21
15
|
* Override for tests — set process.env.MUONROI_AUTH_DIR to point at a temp dir.
|
|
22
16
|
*/
|
|
@@ -38,68 +32,24 @@ export function enrollTokensInRedactor(tokens) {
|
|
|
38
32
|
if (tokens.idToken)
|
|
39
33
|
redactor.enrollSecret(tokens.idToken);
|
|
40
34
|
}
|
|
41
|
-
async function loadKeytar() {
|
|
42
|
-
try {
|
|
43
|
-
return (await import("keytar"));
|
|
44
|
-
}
|
|
45
|
-
catch {
|
|
46
|
-
return null;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
35
|
// ---------------------------------------------------------------------------
|
|
50
36
|
// Public API
|
|
51
37
|
// ---------------------------------------------------------------------------
|
|
52
38
|
/**
|
|
53
|
-
* Persist OAuth tokens for a provider
|
|
54
|
-
*
|
|
39
|
+
* Persist OAuth tokens for a provider to ~/.muonroi-cli/auth/<provider>.json
|
|
40
|
+
* (mode 0600).
|
|
55
41
|
*/
|
|
56
|
-
// Windows Credential Manager's stub rejects credentials larger than ~2.5 KiB
|
|
57
|
-
// with "The stub received bad data" — OAuth blobs routinely exceed that, so
|
|
58
|
-
// for anything over this threshold we skip keytar and go straight to the
|
|
59
|
-
// file fallback (mode 0600).
|
|
60
|
-
const KEYCHAIN_BLOB_LIMIT_BYTES = 2000;
|
|
61
42
|
export async function saveTokens(provider, tokens) {
|
|
62
43
|
enrollTokensInRedactor(tokens);
|
|
63
44
|
const json = JSON.stringify(tokens);
|
|
64
|
-
// Try keytar only for payloads small enough that Credential Manager will
|
|
65
|
-
// accept them. For larger blobs, write to the 0600 file fallback directly.
|
|
66
|
-
if (json.length <= KEYCHAIN_BLOB_LIMIT_BYTES) {
|
|
67
|
-
const kt = await loadKeytar();
|
|
68
|
-
if (kt) {
|
|
69
|
-
try {
|
|
70
|
-
await kt.setPassword(KEYCHAIN_SERVICE, oauthAccount(provider), json);
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
catch {
|
|
74
|
-
// fall through to file
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
45
|
await mkdir(fallbackDir(), { recursive: true });
|
|
79
46
|
await writeFile(fallbackPath(provider), json, { mode: 0o600, encoding: "utf8" });
|
|
80
47
|
}
|
|
81
48
|
/**
|
|
82
|
-
* Load OAuth tokens for a provider.
|
|
83
|
-
* Returns null if no tokens are stored.
|
|
84
|
-
* Enrolled in redactor on load.
|
|
49
|
+
* Load OAuth tokens for a provider from the 0600 file store.
|
|
50
|
+
* Returns null if no tokens are stored. Enrolled in redactor on load.
|
|
85
51
|
*/
|
|
86
52
|
export async function loadTokens(provider) {
|
|
87
|
-
// Try keychain first
|
|
88
|
-
const kt = await loadKeytar();
|
|
89
|
-
if (kt) {
|
|
90
|
-
try {
|
|
91
|
-
const raw = await kt.getPassword(KEYCHAIN_SERVICE, oauthAccount(provider));
|
|
92
|
-
if (raw) {
|
|
93
|
-
const tokens = JSON.parse(raw);
|
|
94
|
-
enrollTokensInRedactor(tokens);
|
|
95
|
-
return tokens;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
catch {
|
|
99
|
-
// fall through to file
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
// Try file fallback
|
|
103
53
|
try {
|
|
104
54
|
const raw = await readFile(fallbackPath(provider), "utf8");
|
|
105
55
|
const tokens = JSON.parse(raw);
|
|
@@ -107,23 +57,14 @@ export async function loadTokens(provider) {
|
|
|
107
57
|
return tokens;
|
|
108
58
|
}
|
|
109
59
|
catch {
|
|
60
|
+
// Missing/unreadable file → no tokens stored.
|
|
110
61
|
return null;
|
|
111
62
|
}
|
|
112
63
|
}
|
|
113
64
|
/**
|
|
114
|
-
* Delete stored OAuth tokens for a provider.
|
|
115
|
-
* Attempts both keychain and file removal (either may or may not exist).
|
|
65
|
+
* Delete stored OAuth tokens for a provider (removes the 0600 file).
|
|
116
66
|
*/
|
|
117
67
|
export async function deleteTokens(provider) {
|
|
118
|
-
const kt = await loadKeytar();
|
|
119
|
-
if (kt) {
|
|
120
|
-
try {
|
|
121
|
-
await kt.deletePassword(KEYCHAIN_SERVICE, oauthAccount(provider));
|
|
122
|
-
}
|
|
123
|
-
catch {
|
|
124
|
-
// ignore
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
68
|
try {
|
|
128
69
|
await unlink(fallbackPath(provider));
|
|
129
70
|
}
|