@humain/terminal 0.0.2 → 0.0.3-beta.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/CHANGELOG.md +241 -24
- package/README.md +143 -119
- package/dist/cli/args.d.ts +4 -2
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +37 -39
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/auth-check.d.ts +19 -0
- package/dist/cli/auth-check.d.ts.map +1 -0
- package/dist/cli/auth-check.js +50 -0
- package/dist/cli/auth-check.js.map +1 -0
- package/dist/cli/auth-command.d.ts +24 -0
- package/dist/cli/auth-command.d.ts.map +1 -0
- package/dist/cli/auth-command.js +103 -0
- package/dist/cli/auth-command.js.map +1 -0
- package/dist/cli/config-selector.d.ts.map +1 -1
- package/dist/cli/config-selector.js +2 -2
- package/dist/cli/config-selector.js.map +1 -1
- package/dist/cli/credential-print.d.ts +5 -15
- package/dist/cli/credential-print.d.ts.map +1 -1
- package/dist/cli/credential-print.js +42 -83
- package/dist/cli/credential-print.js.map +1 -1
- package/dist/cli/experimental/auth.d.ts +16 -0
- package/dist/cli/experimental/auth.d.ts.map +1 -0
- package/dist/cli/experimental/auth.js +13 -0
- package/dist/cli/experimental/auth.js.map +1 -0
- package/dist/cli/experimental/cli.d.ts +6 -0
- package/dist/cli/experimental/cli.d.ts.map +1 -0
- package/dist/cli/experimental/cli.js +5 -0
- package/dist/cli/experimental/cli.js.map +1 -0
- package/dist/cli/experimental/command-options.d.ts +17 -0
- package/dist/cli/experimental/command-options.d.ts.map +1 -0
- package/dist/cli/experimental/command-options.js +35 -0
- package/dist/cli/experimental/command-options.js.map +1 -0
- package/dist/cli/experimental/command.d.ts +63 -0
- package/dist/cli/experimental/command.d.ts.map +1 -0
- package/dist/cli/experimental/command.js +130 -0
- package/dist/cli/experimental/command.js.map +1 -0
- package/dist/cli/experimental/commands/client.d.ts +13 -0
- package/dist/cli/experimental/commands/client.d.ts.map +1 -0
- package/dist/cli/experimental/commands/client.js +25 -0
- package/dist/cli/experimental/commands/client.js.map +1 -0
- package/dist/cli/experimental/commands/pi.d.ts +15 -0
- package/dist/cli/experimental/commands/pi.d.ts.map +1 -0
- package/dist/cli/experimental/commands/pi.js +28 -0
- package/dist/cli/experimental/commands/pi.js.map +1 -0
- package/dist/cli/experimental/commands/server.d.ts +13 -0
- package/dist/cli/experimental/commands/server.d.ts.map +1 -0
- package/dist/cli/experimental/commands/server.js +25 -0
- package/dist/cli/experimental/commands/server.js.map +1 -0
- package/dist/cli/experimental/transport-address.d.ts +10 -0
- package/dist/cli/experimental/transport-address.d.ts.map +1 -0
- package/dist/cli/experimental/transport-address.js +38 -0
- package/dist/cli/experimental/transport-address.js.map +1 -0
- package/dist/cli/list-models.d.ts +1 -1
- package/dist/cli/list-models.d.ts.map +1 -1
- package/dist/cli/list-models.js +2 -2
- package/dist/cli/list-models.js.map +1 -1
- package/dist/cli/startup-ui.d.ts +1 -1
- package/dist/cli/startup-ui.d.ts.map +1 -1
- package/dist/cli/startup-ui.js +2 -2
- package/dist/cli/startup-ui.js.map +1 -1
- package/dist/client/index.d.ts +3 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +3 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/remote-session.d.ts +53 -0
- package/dist/client/remote-session.d.ts.map +1 -0
- package/dist/client/remote-session.js +340 -0
- package/dist/client/remote-session.js.map +1 -0
- package/dist/client/transcript.d.ts +12 -0
- package/dist/client/transcript.d.ts.map +1 -0
- package/dist/client/transcript.js +98 -0
- package/dist/client/transcript.js.map +1 -0
- package/dist/core/agent-session-services.d.ts +1 -0
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js +1 -0
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session.d.ts +1 -10
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +72 -70
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-storage.d.ts +25 -9
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +237 -39
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +60 -41
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +2 -1
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +3 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +27 -4
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/http-dispatcher.d.ts.map +1 -1
- package/dist/core/http-dispatcher.js +5 -0
- package/dist/core/http-dispatcher.js.map +1 -1
- package/dist/core/keybindings.d.ts +45 -5
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/model-config.d.ts +29 -5
- package/dist/core/model-config.d.ts.map +1 -1
- package/dist/core/model-config.js +4 -0
- package/dist/core/model-config.js.map +1 -1
- package/dist/core/model-registry.d.ts +5 -3
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +13 -10
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-resolver.d.ts +4 -3
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +42 -10
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/model-runtime.d.ts +30 -13
- package/dist/core/model-runtime.d.ts.map +1 -1
- package/dist/core/model-runtime.js +233 -73
- package/dist/core/model-runtime.js.map +1 -1
- package/dist/core/models-store.d.ts +12 -7
- package/dist/core/models-store.d.ts.map +1 -1
- package/dist/core/models-store.js +83 -14
- package/dist/core/models-store.js.map +1 -1
- package/dist/core/package-manager.d.ts +6 -3
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +80 -61
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/pi-manifest.d.ts +8 -0
- package/dist/core/pi-manifest.d.ts.map +1 -0
- package/dist/core/pi-manifest.js +28 -0
- package/dist/core/pi-manifest.js.map +1 -0
- package/dist/core/provider-composer.d.ts +4 -1
- package/dist/core/provider-composer.d.ts.map +1 -1
- package/dist/core/provider-composer.js +36 -15
- package/dist/core/provider-composer.js.map +1 -1
- package/dist/core/remote-catalog-provider.d.ts.map +1 -1
- package/dist/core/remote-catalog-provider.js +73 -67
- package/dist/core/remote-catalog-provider.js.map +1 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +2 -2
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/runtime-credentials.d.ts +5 -5
- package/dist/core/runtime-credentials.d.ts.map +1 -1
- package/dist/core/runtime-credentials.js +11 -8
- package/dist/core/runtime-credentials.js.map +1 -1
- package/dist/core/sdk.d.ts +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +2 -2
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +3 -1
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +12 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +40 -16
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +8 -0
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/bash.d.ts +5 -1
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +16 -15
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/edit.d.ts +4 -0
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +11 -7
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/find.d.ts +7 -0
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js +16 -19
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/grep.d.ts +4 -0
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +5 -1
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/ls.d.ts +4 -0
- package/dist/core/tools/ls.d.ts.map +1 -1
- package/dist/core/tools/ls.js +5 -1
- package/dist/core/tools/ls.js.map +1 -1
- package/dist/core/tools/read.d.ts +4 -0
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +7 -3
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/write.d.ts +4 -0
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js +6 -2
- package/dist/core/tools/write.js.map +1 -1
- package/dist/extensions/llama/index.d.ts.map +1 -1
- package/dist/extensions/llama/index.js +11 -2
- package/dist/extensions/llama/index.js.map +1 -1
- package/dist/extensions/llama/provider.d.ts.map +1 -1
- package/dist/extensions/llama/provider.js +21 -7
- package/dist/extensions/llama/provider.js.map +1 -1
- package/dist/humain/agent-execution-protocol.d.ts +218 -0
- package/dist/humain/agent-execution-protocol.d.ts.map +1 -0
- package/dist/humain/agent-execution-protocol.js +204 -0
- package/dist/humain/agent-execution-protocol.js.map +1 -0
- package/dist/humain/agent-execution-runtime.d.ts +35 -0
- package/dist/humain/agent-execution-runtime.d.ts.map +1 -0
- package/dist/humain/agent-execution-runtime.js +170 -0
- package/dist/humain/agent-execution-runtime.js.map +1 -0
- package/dist/humain/index.d.ts.map +1 -1
- package/dist/humain/index.js +8 -7
- package/dist/humain/index.js.map +1 -1
- package/dist/humain/mcp-adapter/vendor/CHANGELOG.md +660 -0
- package/dist/humain/mcp-adapter/vendor/LICENSE +21 -0
- package/dist/humain/mcp-adapter/vendor/README.md +733 -0
- package/dist/humain/mcp-adapter/vendor/abort.ts +34 -0
- package/dist/humain/mcp-adapter/vendor/agent-dir.ts +60 -0
- package/dist/humain/mcp-adapter/vendor/agent-plugin-loader.ts +377 -0
- package/dist/humain/mcp-adapter/vendor/app-bridge.bundle.js +67 -0
- package/dist/humain/mcp-adapter/vendor/banner.png +0 -0
- package/dist/humain/mcp-adapter/vendor/cli.js +209 -0
- package/dist/humain/mcp-adapter/vendor/commands.ts +627 -0
- package/dist/humain/mcp-adapter/vendor/config.ts +1226 -0
- package/dist/humain/mcp-adapter/vendor/consent-manager.ts +64 -0
- package/dist/humain/mcp-adapter/vendor/direct-tools.ts +604 -0
- package/dist/humain/mcp-adapter/vendor/elicitation-handler.ts +348 -0
- package/dist/humain/mcp-adapter/vendor/error-signal.ts +21 -0
- package/dist/humain/mcp-adapter/vendor/errors.ts +223 -0
- package/dist/humain/mcp-adapter/vendor/glimpse-ui.ts +80 -0
- package/dist/humain/mcp-adapter/vendor/host-html-template.ts +461 -0
- package/dist/humain/mcp-adapter/vendor/index.bundle.d.mts +4 -0
- package/dist/humain/mcp-adapter/vendor/index.bundle.mjs +15923 -0
- package/dist/humain/mcp-adapter/vendor/index.ts +898 -0
- package/dist/humain/mcp-adapter/vendor/init.ts +649 -0
- package/dist/humain/mcp-adapter/vendor/json-schema-validator.ts +69 -0
- package/dist/humain/mcp-adapter/vendor/lifecycle.ts +147 -0
- package/dist/humain/mcp-adapter/vendor/logger.ts +169 -0
- package/dist/humain/mcp-adapter/vendor/mcp-auth-flow.ts +993 -0
- package/dist/humain/mcp-adapter/vendor/mcp-auth.ts +1000 -0
- package/dist/humain/mcp-adapter/vendor/mcp-callback-server.ts +510 -0
- package/dist/humain/mcp-adapter/vendor/mcp-code.ts +354 -0
- package/dist/humain/mcp-adapter/vendor/mcp-keyring-helper.cjs +89 -0
- package/dist/humain/mcp-adapter/vendor/mcp-oauth-provider.ts +616 -0
- package/dist/humain/mcp-adapter/vendor/mcp-output-guard.ts +408 -0
- package/dist/humain/mcp-adapter/vendor/mcp-panel.ts +1015 -0
- package/dist/humain/mcp-adapter/vendor/mcp-probe.ts +187 -0
- package/dist/humain/mcp-adapter/vendor/mcp-script-worker.mjs +130 -0
- package/dist/humain/mcp-adapter/vendor/mcp-setup-panel.ts +666 -0
- package/dist/humain/mcp-adapter/vendor/mcp-status.ts +109 -0
- package/dist/humain/mcp-adapter/vendor/mcp-trace.ts +306 -0
- package/dist/humain/mcp-adapter/vendor/metadata-cache.ts +353 -0
- package/dist/humain/mcp-adapter/vendor/npx-resolver.ts +543 -0
- package/dist/humain/mcp-adapter/vendor/oauth-handler.ts +30 -0
- package/dist/humain/mcp-adapter/vendor/oauth.ts +48 -0
- package/dist/humain/mcp-adapter/vendor/onboarding-state.ts +76 -0
- package/dist/humain/mcp-adapter/vendor/package.json +178 -0
- package/dist/humain/mcp-adapter/vendor/panel-keys.ts +53 -0
- package/dist/humain/mcp-adapter/vendor/prompts.ts +353 -0
- package/dist/humain/mcp-adapter/vendor/proxy-modes.ts +1331 -0
- package/dist/humain/mcp-adapter/vendor/resource-tools.ts +17 -0
- package/dist/humain/mcp-adapter/vendor/runtime-owner.ts +91 -0
- package/dist/humain/mcp-adapter/vendor/sampling-handler.ts +284 -0
- package/dist/humain/mcp-adapter/vendor/search-ranking.ts +206 -0
- package/dist/humain/mcp-adapter/vendor/server-manager.ts +1124 -0
- package/dist/humain/mcp-adapter/vendor/session-recovery.ts +151 -0
- package/dist/humain/mcp-adapter/vendor/skills/mcp-scripting/SKILL.md +38 -0
- package/dist/humain/mcp-adapter/vendor/state.ts +62 -0
- package/dist/humain/mcp-adapter/vendor/tool-approval.ts +182 -0
- package/dist/humain/mcp-adapter/vendor/tool-metadata.ts +276 -0
- package/dist/humain/mcp-adapter/vendor/tool-registrar.ts +253 -0
- package/dist/humain/mcp-adapter/vendor/tool-result-renderer.ts +423 -0
- package/dist/humain/mcp-adapter/vendor/ts-shape.ts +149 -0
- package/dist/humain/mcp-adapter/vendor/types.ts +859 -0
- package/dist/humain/mcp-adapter/vendor/ui-app-bridge-helpers.ts +40 -0
- package/dist/humain/mcp-adapter/vendor/ui-resource-handler.ts +250 -0
- package/dist/humain/mcp-adapter/vendor/ui-server.ts +866 -0
- package/dist/humain/mcp-adapter/vendor/ui-session.ts +570 -0
- package/dist/humain/mcp-adapter/vendor/ui-stream-types.ts +89 -0
- package/dist/humain/mcp-adapter/vendor/ui-tool-visibility.ts +25 -0
- package/dist/humain/mcp-adapter/vendor/unix-socket-transport.ts +85 -0
- package/dist/humain/mcp-adapter/vendor/utils.ts +310 -0
- package/dist/humain/mcp-adapter.d.ts +3 -0
- package/dist/humain/mcp-adapter.d.ts.map +1 -0
- package/dist/humain/mcp-adapter.js +5 -0
- package/dist/humain/mcp-adapter.js.map +1 -0
- package/dist/humain/pi-agent-execution-host.d.ts +34 -0
- package/dist/humain/pi-agent-execution-host.d.ts.map +1 -0
- package/dist/humain/pi-agent-execution-host.js +77 -0
- package/dist/humain/pi-agent-execution-host.js.map +1 -0
- package/dist/humain/web-access/host.d.ts +4 -0
- package/dist/humain/web-access/host.d.ts.map +1 -0
- package/dist/humain/web-access/host.js +3 -0
- package/dist/humain/web-access/host.js.map +1 -0
- package/dist/humain/web-access/index.d.ts +3 -0
- package/dist/humain/web-access/index.d.ts.map +1 -0
- package/dist/humain/web-access/index.js +5 -0
- package/dist/humain/web-access/index.js.map +1 -0
- package/dist/humain/web-access/vendor/activity.d.ts +34 -0
- package/dist/humain/web-access/vendor/activity.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/activity.js +68 -0
- package/dist/humain/web-access/vendor/activity.js.map +1 -0
- package/dist/humain/web-access/vendor/anysearch.d.ts +8 -0
- package/dist/humain/web-access/vendor/anysearch.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/anysearch.js +167 -0
- package/dist/humain/web-access/vendor/anysearch.js.map +1 -0
- package/dist/humain/web-access/vendor/bocha.d.ts +4 -0
- package/dist/humain/web-access/vendor/bocha.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/bocha.js +219 -0
- package/dist/humain/web-access/vendor/bocha.js.map +1 -0
- package/dist/humain/web-access/vendor/brave.d.ts +4 -0
- package/dist/humain/web-access/vendor/brave.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/brave.js +194 -0
- package/dist/humain/web-access/vendor/brave.js.map +1 -0
- package/dist/humain/web-access/vendor/brightdata-unlocker.d.ts +12 -0
- package/dist/humain/web-access/vendor/brightdata-unlocker.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/brightdata-unlocker.js +230 -0
- package/dist/humain/web-access/vendor/brightdata-unlocker.js.map +1 -0
- package/dist/humain/web-access/vendor/brightdata.d.ts +8 -0
- package/dist/humain/web-access/vendor/brightdata.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/brightdata.js +519 -0
- package/dist/humain/web-access/vendor/brightdata.js.map +1 -0
- package/dist/humain/web-access/vendor/chrome-cookies.d.ts +10 -0
- package/dist/humain/web-access/vendor/chrome-cookies.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/chrome-cookies.js +438 -0
- package/dist/humain/web-access/vendor/chrome-cookies.js.map +1 -0
- package/dist/humain/web-access/vendor/content-find.d.ts +11 -0
- package/dist/humain/web-access/vendor/content-find.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/content-find.js +117 -0
- package/dist/humain/web-access/vendor/content-find.js.map +1 -0
- package/dist/humain/web-access/vendor/credential-source.d.ts +28 -0
- package/dist/humain/web-access/vendor/credential-source.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/credential-source.js +151 -0
- package/dist/humain/web-access/vendor/credential-source.js.map +1 -0
- package/dist/humain/web-access/vendor/curator-page.d.ts +29 -0
- package/dist/humain/web-access/vendor/curator-page.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/curator-page.js +3554 -0
- package/dist/humain/web-access/vendor/curator-page.js.map +1 -0
- package/dist/humain/web-access/vendor/curator-server.d.ts +93 -0
- package/dist/humain/web-access/vendor/curator-server.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/curator-server.js +688 -0
- package/dist/humain/web-access/vendor/curator-server.js.map +1 -0
- package/dist/humain/web-access/vendor/datalab-pdf-extract.d.ts +60 -0
- package/dist/humain/web-access/vendor/datalab-pdf-extract.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/datalab-pdf-extract.js +416 -0
- package/dist/humain/web-access/vendor/datalab-pdf-extract.js.map +1 -0
- package/dist/humain/web-access/vendor/declared-web-links.d.ts +16 -0
- package/dist/humain/web-access/vendor/declared-web-links.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/declared-web-links.js +168 -0
- package/dist/humain/web-access/vendor/declared-web-links.js.map +1 -0
- package/dist/humain/web-access/vendor/duckduckgo.d.ts +4 -0
- package/dist/humain/web-access/vendor/duckduckgo.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/duckduckgo.js +123 -0
- package/dist/humain/web-access/vendor/duckduckgo.js.map +1 -0
- package/dist/humain/web-access/vendor/exa.d.ts +10 -0
- package/dist/humain/web-access/vendor/exa.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/exa.js +426 -0
- package/dist/humain/web-access/vendor/exa.js.map +1 -0
- package/dist/humain/web-access/vendor/extract.d.ts +46 -0
- package/dist/humain/web-access/vendor/extract.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/extract.js +1064 -0
- package/dist/humain/web-access/vendor/extract.js.map +1 -0
- package/dist/humain/web-access/vendor/feature-config.d.ts +3 -0
- package/dist/humain/web-access/vendor/feature-config.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/feature-config.js +27 -0
- package/dist/humain/web-access/vendor/feature-config.js.map +1 -0
- package/dist/humain/web-access/vendor/fetch-params.d.ts +25 -0
- package/dist/humain/web-access/vendor/fetch-params.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/fetch-params.js +57 -0
- package/dist/humain/web-access/vendor/fetch-params.js.map +1 -0
- package/dist/humain/web-access/vendor/firecrawl.d.ts +12 -0
- package/dist/humain/web-access/vendor/firecrawl.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/firecrawl.js +239 -0
- package/dist/humain/web-access/vendor/firecrawl.js.map +1 -0
- package/dist/humain/web-access/vendor/gemini-api.d.ts +27 -0
- package/dist/humain/web-access/vendor/gemini-api.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/gemini-api.js +230 -0
- package/dist/humain/web-access/vendor/gemini-api.js.map +1 -0
- package/dist/humain/web-access/vendor/gemini-pdf-extract.d.ts +9 -0
- package/dist/humain/web-access/vendor/gemini-pdf-extract.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/gemini-pdf-extract.js +85 -0
- package/dist/humain/web-access/vendor/gemini-pdf-extract.js.map +1 -0
- package/dist/humain/web-access/vendor/gemini-search.d.ts +40 -0
- package/dist/humain/web-access/vendor/gemini-search.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/gemini-search.js +814 -0
- package/dist/humain/web-access/vendor/gemini-search.js.map +1 -0
- package/dist/humain/web-access/vendor/gemini-url-context.d.ts +4 -0
- package/dist/humain/web-access/vendor/gemini-url-context.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/gemini-url-context.js +101 -0
- package/dist/humain/web-access/vendor/gemini-url-context.js.map +1 -0
- package/dist/humain/web-access/vendor/gemini-web-config.d.ts +4 -0
- package/dist/humain/web-access/vendor/gemini-web-config.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/gemini-web-config.js +42 -0
- package/dist/humain/web-access/vendor/gemini-web-config.js.map +1 -0
- package/dist/humain/web-access/vendor/gemini-web.d.ts +18 -0
- package/dist/humain/web-access/vendor/gemini-web.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/gemini-web.js +385 -0
- package/dist/humain/web-access/vendor/gemini-web.js.map +1 -0
- package/dist/humain/web-access/vendor/github-api.d.ts +7 -0
- package/dist/humain/web-access/vendor/github-api.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/github-api.js +160 -0
- package/dist/humain/web-access/vendor/github-api.js.map +1 -0
- package/dist/humain/web-access/vendor/github-extract.d.ts +13 -0
- package/dist/humain/web-access/vendor/github-extract.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/github-extract.js +635 -0
- package/dist/humain/web-access/vendor/github-extract.js.map +1 -0
- package/dist/humain/web-access/vendor/index.d.ts +4 -0
- package/dist/humain/web-access/vendor/index.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/index.js +3002 -0
- package/dist/humain/web-access/vendor/index.js.map +1 -0
- package/dist/humain/web-access/vendor/jina-search.d.ts +8 -0
- package/dist/humain/web-access/vendor/jina-search.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/jina-search.js +255 -0
- package/dist/humain/web-access/vendor/jina-search.js.map +1 -0
- package/dist/humain/web-access/vendor/kagi.d.ts +15 -0
- package/dist/humain/web-access/vendor/kagi.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/kagi.js +262 -0
- package/dist/humain/web-access/vendor/kagi.js.map +1 -0
- package/dist/humain/web-access/vendor/ollama.d.ts +15 -0
- package/dist/humain/web-access/vendor/ollama.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/ollama.js +216 -0
- package/dist/humain/web-access/vendor/ollama.js.map +1 -0
- package/dist/humain/web-access/vendor/openai-search.d.ts +15 -0
- package/dist/humain/web-access/vendor/openai-search.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/openai-search.js +459 -0
- package/dist/humain/web-access/vendor/openai-search.js.map +1 -0
- package/dist/humain/web-access/vendor/page-query.d.ts +16 -0
- package/dist/humain/web-access/vendor/page-query.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/page-query.js +79 -0
- package/dist/humain/web-access/vendor/page-query.js.map +1 -0
- package/dist/humain/web-access/vendor/parallel.d.ts +12 -0
- package/dist/humain/web-access/vendor/parallel.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/parallel.js +343 -0
- package/dist/humain/web-access/vendor/parallel.js.map +1 -0
- package/dist/humain/web-access/vendor/pdf-extract.d.ts +44 -0
- package/dist/humain/web-access/vendor/pdf-extract.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/pdf-extract.js +298 -0
- package/dist/humain/web-access/vendor/pdf-extract.js.map +1 -0
- package/dist/humain/web-access/vendor/perplexity.d.ts +20 -0
- package/dist/humain/web-access/vendor/perplexity.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/perplexity.js +159 -0
- package/dist/humain/web-access/vendor/perplexity.js.map +1 -0
- package/dist/humain/web-access/vendor/querit.d.ts +10 -0
- package/dist/humain/web-access/vendor/querit.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/querit.js +335 -0
- package/dist/humain/web-access/vendor/querit.js.map +1 -0
- package/dist/humain/web-access/vendor/render-search-error.d.ts +57 -0
- package/dist/humain/web-access/vendor/render-search-error.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/render-search-error.js +130 -0
- package/dist/humain/web-access/vendor/render-search-error.js.map +1 -0
- package/dist/humain/web-access/vendor/rsc-extract.d.ts +12 -0
- package/dist/humain/web-access/vendor/rsc-extract.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/rsc-extract.js +329 -0
- package/dist/humain/web-access/vendor/rsc-extract.js.map +1 -0
- package/dist/humain/web-access/vendor/search1api.d.ts +10 -0
- package/dist/humain/web-access/vendor/search1api.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/search1api.js +251 -0
- package/dist/humain/web-access/vendor/search1api.js.map +1 -0
- package/dist/humain/web-access/vendor/searchinfinity.d.ts +8 -0
- package/dist/humain/web-access/vendor/searchinfinity.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/searchinfinity.js +229 -0
- package/dist/humain/web-access/vendor/searchinfinity.js.map +1 -0
- package/dist/humain/web-access/vendor/searxng.d.ts +4 -0
- package/dist/humain/web-access/vendor/searxng.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/searxng.js +238 -0
- package/dist/humain/web-access/vendor/searxng.js.map +1 -0
- package/dist/humain/web-access/vendor/serpbase.d.ts +4 -0
- package/dist/humain/web-access/vendor/serpbase.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/serpbase.js +211 -0
- package/dist/humain/web-access/vendor/serpbase.js.map +1 -0
- package/dist/humain/web-access/vendor/serpdive.d.ts +8 -0
- package/dist/humain/web-access/vendor/serpdive.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/serpdive.js +267 -0
- package/dist/humain/web-access/vendor/serpdive.js.map +1 -0
- package/dist/humain/web-access/vendor/source-check.d.ts +99 -0
- package/dist/humain/web-access/vendor/source-check.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/source-check.js +205 -0
- package/dist/humain/web-access/vendor/source-check.js.map +1 -0
- package/dist/humain/web-access/vendor/ssrf-protection.d.ts +50 -0
- package/dist/humain/web-access/vendor/ssrf-protection.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/ssrf-protection.js +466 -0
- package/dist/humain/web-access/vendor/ssrf-protection.js.map +1 -0
- package/dist/humain/web-access/vendor/storage.d.ts +55 -0
- package/dist/humain/web-access/vendor/storage.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/storage.js +485 -0
- package/dist/humain/web-access/vendor/storage.js.map +1 -0
- package/dist/humain/web-access/vendor/summary-model-scope.d.ts +25 -0
- package/dist/humain/web-access/vendor/summary-model-scope.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/summary-model-scope.js +98 -0
- package/dist/humain/web-access/vendor/summary-model-scope.js.map +1 -0
- package/dist/humain/web-access/vendor/summary-review.d.ts +24 -0
- package/dist/humain/web-access/vendor/summary-review.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/summary-review.js +341 -0
- package/dist/humain/web-access/vendor/summary-review.js.map +1 -0
- package/dist/humain/web-access/vendor/tavily.d.ts +8 -0
- package/dist/humain/web-access/vendor/tavily.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/tavily.js +194 -0
- package/dist/humain/web-access/vendor/tavily.js.map +1 -0
- package/dist/humain/web-access/vendor/tinyfish.d.ts +11 -0
- package/dist/humain/web-access/vendor/tinyfish.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/tinyfish.js +331 -0
- package/dist/humain/web-access/vendor/tinyfish.js.map +1 -0
- package/dist/humain/web-access/vendor/utils.d.ts +20 -0
- package/dist/humain/web-access/vendor/utils.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/utils.js +91 -0
- package/dist/humain/web-access/vendor/utils.js.map +1 -0
- package/dist/humain/web-access/vendor/video-extract.d.ts +16 -0
- package/dist/humain/web-access/vendor/video-extract.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/video-extract.js +335 -0
- package/dist/humain/web-access/vendor/video-extract.js.map +1 -0
- package/dist/humain/web-access/vendor/xai-search.d.ts +13 -0
- package/dist/humain/web-access/vendor/xai-search.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/xai-search.js +331 -0
- package/dist/humain/web-access/vendor/xai-search.js.map +1 -0
- package/dist/humain/web-access/vendor/youtube-extract.d.ts +27 -0
- package/dist/humain/web-access/vendor/youtube-extract.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/youtube-extract.js +282 -0
- package/dist/humain/web-access/vendor/youtube-extract.js.map +1 -0
- package/dist/index.d.ts +7 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -2
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts +2 -2
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +169 -102
- package/dist/main.js.map +1 -1
- package/dist/modes/agent-exec-mode.d.ts +14 -0
- package/dist/modes/agent-exec-mode.d.ts.map +1 -0
- package/dist/modes/agent-exec-mode.js +92 -0
- package/dist/modes/agent-exec-mode.js.map +1 -0
- package/dist/modes/index.d.ts +4 -2
- package/dist/modes/index.d.ts.map +1 -1
- package/dist/modes/index.js +2 -1
- package/dist/modes/index.js.map +1 -1
- package/dist/modes/interactive/components/assistant-message.d.ts +5 -2
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +13 -4
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-editor.js +7 -0
- package/dist/modes/interactive/components/custom-editor.js.map +1 -1
- package/dist/modes/interactive/components/earendil-announcement.d.ts +5 -0
- package/dist/modes/interactive/components/earendil-announcement.d.ts.map +1 -0
- package/dist/modes/interactive/components/earendil-announcement.js +40 -0
- package/dist/modes/interactive/components/earendil-announcement.js.map +1 -0
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +1 -1
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/markdown-transform.d.ts +3 -0
- package/dist/modes/interactive/components/markdown-transform.d.ts.map +1 -0
- package/dist/modes/interactive/components/markdown-transform.js +19 -0
- package/dist/modes/interactive/components/markdown-transform.js.map +1 -0
- package/dist/modes/interactive/components/mermaid.d.ts +11 -0
- package/dist/modes/interactive/components/mermaid.d.ts.map +1 -0
- package/dist/modes/interactive/components/mermaid.js +75 -0
- package/dist/modes/interactive/components/mermaid.js.map +1 -0
- package/dist/modes/interactive/components/model-selector.d.ts +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +16 -4
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.d.ts +4 -0
- package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.js +26 -0
- package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +8 -2
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +30 -0
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/user-message.d.ts +3 -1
- package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message.js +9 -2
- package/dist/modes/interactive/components/user-message.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +45 -9
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +581 -211
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/dark.json +1 -0
- package/dist/modes/interactive/theme/light.json +1 -0
- package/dist/modes/interactive/theme/theme-controller.d.ts +3 -0
- package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme-controller.js +10 -1
- package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
- package/dist/modes/interactive/theme/theme-schema.json +5 -1
- package/dist/modes/interactive/theme/theme.d.ts +2 -2
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +24 -6
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/modes/json-event.d.ts +28 -0
- package/dist/modes/json-event.d.ts.map +1 -0
- package/dist/modes/json-event.js +12 -0
- package/dist/modes/json-event.js.map +1 -0
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +12 -2
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts +12 -5
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +55 -1
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +13 -3
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +15 -0
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/package-manager-cli.d.ts.map +1 -1
- package/dist/package-manager-cli.js +11 -9
- package/dist/package-manager-cli.js.map +1 -1
- package/dist/rpc-entry.d.ts.map +1 -1
- package/dist/rpc-entry.js +3 -2
- package/dist/rpc-entry.js.map +1 -1
- package/dist/server/create-harness.d.ts +26 -0
- package/dist/server/create-harness.d.ts.map +1 -0
- package/dist/server/create-harness.js +104 -0
- package/dist/server/create-harness.js.map +1 -0
- package/dist/utils/abort.d.ts +5 -0
- package/dist/utils/abort.d.ts.map +1 -0
- package/dist/utils/abort.js +48 -0
- package/dist/utils/abort.js.map +1 -0
- package/dist/utils/clipboard.d.ts +1 -1
- package/dist/utils/clipboard.d.ts.map +1 -1
- package/dist/utils/clipboard.js +22 -2
- package/dist/utils/clipboard.js.map +1 -1
- package/dist/utils/management-http.d.ts +23 -0
- package/dist/utils/management-http.d.ts.map +1 -0
- package/dist/utils/management-http.js +50 -0
- package/dist/utils/management-http.js.map +1 -0
- package/dist/utils/paths.d.ts +3 -0
- package/dist/utils/paths.d.ts.map +1 -1
- package/dist/utils/paths.js +23 -1
- package/dist/utils/paths.js.map +1 -1
- package/dist/utils/tool-result-images.d.ts +19 -0
- package/dist/utils/tool-result-images.d.ts.map +1 -0
- package/dist/utils/tool-result-images.js +45 -0
- package/dist/utils/tool-result-images.js.map +1 -0
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js +13 -25
- package/dist/utils/tools-manager.js.map +1 -1
- package/dist/utils/version-check.d.ts +4 -0
- package/dist/utils/version-check.d.ts.map +1 -1
- package/dist/utils/version-check.js +23 -5
- package/dist/utils/version-check.js.map +1 -1
- package/docs/compaction.md +2 -2
- package/docs/custom-provider.md +7 -5
- package/docs/extensions.md +30 -5
- package/docs/humain-terminal.md +21 -1
- package/docs/json.md +24 -19
- package/docs/keybindings.md +46 -14
- package/docs/models.md +32 -11
- package/docs/providers.md +9 -1
- package/docs/quickstart.md +39 -37
- package/docs/rpc.md +31 -11
- package/docs/sdk.md +21 -2
- package/docs/security.md +21 -21
- package/docs/session-format.md +14 -14
- package/docs/settings.md +4 -1
- package/docs/themes.md +5 -3
- package/docs/usage.md +7 -0
- package/examples/extensions/custom-compaction.ts +3 -18
- package/examples/extensions/custom-provider-anthropic/index.ts +5 -1
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/index.ts +5 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/doom-overlay/wad-finder.ts +7 -3
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/handoff.ts +4 -13
- package/examples/extensions/qna.ts +5 -9
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/summarize.ts +9 -20
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/examples/rpc-extension-ui.ts +11 -2
- package/examples/sdk/02-custom-model.ts +2 -3
- package/examples/sdk/09-api-keys-and-oauth.ts +1 -1
- package/examples/sdk/12-full-control.ts +1 -1
- package/examples/sdk/README.md +1 -1
- package/npm-shrinkwrap.json +2771 -535
- package/package.json +40 -11
- package/src/humain/mcp-adapter/UPSTREAM.md +15 -0
- package/src/humain/mcp-adapter/upstream.json +7 -0
- package/src/humain/mcp-adapter/vendor/CHANGELOG.md +660 -0
- package/src/humain/mcp-adapter/vendor/LICENSE +21 -0
- package/src/humain/web-access/UPSTREAM.md +17 -0
- package/src/humain/web-access/upstream.json +23 -0
- package/src/humain/web-access/vendor/LICENSE +21 -0
|
@@ -0,0 +1,1000 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Auth Storage Module
|
|
3
|
+
*
|
|
4
|
+
* Handles secure storage of OAuth credentials, tokens, client information,
|
|
5
|
+
* and legacy PKCE state for MCP servers.
|
|
6
|
+
*
|
|
7
|
+
* Persistent OAuth entries are stored in the operating system credential store.
|
|
8
|
+
* Legacy plaintext entries are imported from $MCP_OAUTH_DIR/sha256-<server-hash>/tokens.json
|
|
9
|
+
* when set, otherwise <Pi agent dir>/mcp-oauth/sha256-<server-hash>/tokens.json,
|
|
10
|
+
* then the plaintext file is removed.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { spawnSync } from 'child_process';
|
|
14
|
+
import { createHash } from 'crypto';
|
|
15
|
+
import { createRequire } from 'module';
|
|
16
|
+
import { readFileSync, existsSync, rmSync } from 'fs';
|
|
17
|
+
import { dirname, join } from 'path';
|
|
18
|
+
import { fileURLToPath } from 'url';
|
|
19
|
+
import { getAgentPath } from './agent-dir.ts';
|
|
20
|
+
import { resolveConfiguredOAuthDir } from './config.ts';
|
|
21
|
+
|
|
22
|
+
const require = createRequire(import.meta.url);
|
|
23
|
+
const AUTH_SECRET_SERVICE = 'pi-mcp-adapter.oauth';
|
|
24
|
+
const TEST_AUTH_STORE_ENV = 'PI_MCP_ADAPTER_TEST_AUTH_STORE';
|
|
25
|
+
/**
|
|
26
|
+
* Windows Credential Manager caps one value at CRED_MAX_CREDENTIAL_BLOB_SIZE
|
|
27
|
+
* (2560 bytes) and stores it as UTF-16, so the real ceiling is
|
|
28
|
+
* AUTH_SECRET_VALUE_LIMIT characters. Chunks must stay below that, and so must
|
|
29
|
+
* the threshold that decides whether to chunk at all, or oversized records still
|
|
30
|
+
* fail to persist on Windows.
|
|
31
|
+
*/
|
|
32
|
+
const AUTH_SECRET_CHUNK_SIZE = 1000;
|
|
33
|
+
/** Largest single value the strictest supported credential store accepts. */
|
|
34
|
+
const AUTH_SECRET_VALUE_LIMIT = 1280;
|
|
35
|
+
const KEYRING_RECOVERY_DISABLED_ENV = 'PI_MCP_ADAPTER_DISABLE_KEYRING_RECOVERY';
|
|
36
|
+
const KEYRING_RECOVERY_KEYCTL_ENV = 'PI_MCP_ADAPTER_KEYRING_RECOVERY_KEYCTL';
|
|
37
|
+
const KEYRING_RECOVERY_NODE_ENV = 'PI_MCP_ADAPTER_KEYRING_RECOVERY_NODE';
|
|
38
|
+
const KEYRING_RECOVERY_HELPER_ENV = 'PI_MCP_ADAPTER_KEYRING_RECOVERY_HELPER';
|
|
39
|
+
const TEST_LINUX_KEYRING_RECOVERY_ENV = 'PI_MCP_ADAPTER_TEST_LINUX_KEYRING_RECOVERY';
|
|
40
|
+
const AUTH_CACHE_DISABLED_ENV = 'PI_MCP_ADAPTER_DISABLE_AUTH_CACHE';
|
|
41
|
+
const KEYRING_RECOVERY_TIMEOUT_MS = 10_000;
|
|
42
|
+
const AUTH_CHUNK_MANIFEST_KEY = '__piMcpAdapterOAuthChunked';
|
|
43
|
+
|
|
44
|
+
/** OAuth token storage format */
|
|
45
|
+
export interface StoredTokens {
|
|
46
|
+
accessToken: string;
|
|
47
|
+
refreshToken?: string;
|
|
48
|
+
expiresAt?: number; // Unix timestamp in seconds
|
|
49
|
+
scope?: string;
|
|
50
|
+
/** SEP-2352 authorization-server issuer binding */
|
|
51
|
+
issuer?: string;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** OAuth client information from dynamic or static registration */
|
|
55
|
+
export interface StoredClientInfo {
|
|
56
|
+
clientId: string;
|
|
57
|
+
clientSecret?: string;
|
|
58
|
+
clientIdIssuedAt?: number;
|
|
59
|
+
clientSecretExpiresAt?: number;
|
|
60
|
+
redirectUris?: string[];
|
|
61
|
+
/** SEP-2352 authorization-server issuer binding */
|
|
62
|
+
issuer?: string;
|
|
63
|
+
/**
|
|
64
|
+
* True when this entry is a secretless SEP-2352 issuer stub persisted for a
|
|
65
|
+
* config-pre-registered client (written by the config-clientId path of
|
|
66
|
+
* saveClientInformation). Such a stub is only usable when paired with the
|
|
67
|
+
* config that supplies the client secret; it must never be served as
|
|
68
|
+
* standalone client information.
|
|
69
|
+
*/
|
|
70
|
+
configPreRegistered?: boolean;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Complete auth entry for a server */
|
|
74
|
+
export interface AuthEntry {
|
|
75
|
+
tokens?: StoredTokens;
|
|
76
|
+
clientInfo?: StoredClientInfo;
|
|
77
|
+
codeVerifier?: string;
|
|
78
|
+
oauthState?: string;
|
|
79
|
+
serverUrl?: string; // Track the URL these credentials are for
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface AuthStorageOptions {
|
|
83
|
+
/** Legacy plaintext import directory. Persistent secrets no longer use this as their store. */
|
|
84
|
+
baseDir?: string;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export class OAuthCredentialStoreError extends Error {
|
|
88
|
+
readonly code = 'OAUTH_CREDENTIAL_STORE_UNAVAILABLE';
|
|
89
|
+
|
|
90
|
+
constructor(
|
|
91
|
+
message: string,
|
|
92
|
+
readonly operation: 'read' | 'write' | 'remove',
|
|
93
|
+
cause: unknown,
|
|
94
|
+
) {
|
|
95
|
+
super(message, { cause });
|
|
96
|
+
this.name = 'OAuthCredentialStoreError';
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export type OAuthCredentialStatus =
|
|
101
|
+
| { status: 'present'; entry: AuthEntry }
|
|
102
|
+
| { status: 'absent' }
|
|
103
|
+
| { status: 'unavailable'; message: string };
|
|
104
|
+
|
|
105
|
+
function causeChainContains(error: unknown, pattern: RegExp): boolean {
|
|
106
|
+
const seen = new Set<unknown>();
|
|
107
|
+
let current = error;
|
|
108
|
+
while ((typeof current === 'object' && current !== null) || typeof current === 'function') {
|
|
109
|
+
if (seen.has(current)) break;
|
|
110
|
+
seen.add(current);
|
|
111
|
+
const candidate = current as { name?: unknown; message?: unknown; code?: unknown; cause?: unknown };
|
|
112
|
+
if ([candidate.name, candidate.message, candidate.code].some(value => typeof value === 'string' && pattern.test(value))) {
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
115
|
+
current = candidate.cause;
|
|
116
|
+
}
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function formatOAuthCredentialStoreUnavailable(error: OAuthCredentialStoreError): string {
|
|
121
|
+
if (process.platform === 'linux' && causeChainContains(error, /key\s*(?:has been\s*)?revoked|keyrevoked/i)) {
|
|
122
|
+
return 'OAuth credential store unavailable: the Linux session keyring may be revoked. Start Pi from a fresh login/keyring session and retry.';
|
|
123
|
+
}
|
|
124
|
+
return 'OAuth credential store unavailable. Configure or unlock the OS credential store and retry.';
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
interface KeyringEntry {
|
|
128
|
+
getPassword(): string | null;
|
|
129
|
+
setPassword(password: string): void;
|
|
130
|
+
deleteCredential(): boolean;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
type KeyringEntryConstructor = new (service: string, account: string) => KeyringEntry;
|
|
134
|
+
type KeyringModule = { Entry: KeyringEntryConstructor };
|
|
135
|
+
type KeyringRequire = ((id: string) => unknown) & { resolve(id: string): string };
|
|
136
|
+
|
|
137
|
+
interface AuthSecretStore {
|
|
138
|
+
read(account: string): string | undefined;
|
|
139
|
+
write(account: string, payload: string): void;
|
|
140
|
+
remove(account: string): void;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
interface AuthEntryChunkManifest {
|
|
144
|
+
[AUTH_CHUNK_MANIFEST_KEY]: 1;
|
|
145
|
+
chunkCount: number;
|
|
146
|
+
chunkDigest: string;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
let KeyringEntryClass: KeyringEntryConstructor | undefined;
|
|
150
|
+
const memoryAuthEntries = new Map<string, string>();
|
|
151
|
+
|
|
152
|
+
let testAuthSecretStoreReadCount = 0;
|
|
153
|
+
const authEntryCache = new Map<string, AuthEntry | undefined>();
|
|
154
|
+
|
|
155
|
+
function isAuthEntryCacheEnabled(): boolean {
|
|
156
|
+
return process.env[AUTH_CACHE_DISABLED_ENV] !== '1';
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function cloneAuthEntry(entry: AuthEntry | undefined): AuthEntry | undefined {
|
|
160
|
+
return entry === undefined ? undefined : structuredClone(entry);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const memoryAuthSecretStore: AuthSecretStore = {
|
|
164
|
+
read(account) {
|
|
165
|
+
testAuthSecretStoreReadCount++;
|
|
166
|
+
return memoryAuthEntries.get(account);
|
|
167
|
+
},
|
|
168
|
+
write(account, payload) {
|
|
169
|
+
memoryAuthEntries.set(account, payload);
|
|
170
|
+
},
|
|
171
|
+
remove(account) {
|
|
172
|
+
memoryAuthEntries.delete(account);
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
const keyringAuthSecretStore: AuthSecretStore = {
|
|
177
|
+
read(account) {
|
|
178
|
+
return getKeyringEntry(account).getPassword() ?? undefined;
|
|
179
|
+
},
|
|
180
|
+
write(account, payload) {
|
|
181
|
+
getKeyringEntry(account).setPassword(payload);
|
|
182
|
+
},
|
|
183
|
+
remove(account) {
|
|
184
|
+
getKeyringEntry(account).deleteCredential();
|
|
185
|
+
},
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
/** Mimics the Windows Credential Manager per-value ceiling for tests. */
|
|
189
|
+
const sizeLimitedAuthSecretStore: AuthSecretStore = {
|
|
190
|
+
read(account) {
|
|
191
|
+
testAuthSecretStoreReadCount++;
|
|
192
|
+
return memoryAuthEntries.get(account);
|
|
193
|
+
},
|
|
194
|
+
write(account, payload) {
|
|
195
|
+
if (payload.length > AUTH_SECRET_VALUE_LIMIT) {
|
|
196
|
+
throw new Error(`Value of 'password encoded as UTF-16' is longer than the platform limit of ${AUTH_SECRET_VALUE_LIMIT * 2} chars`);
|
|
197
|
+
}
|
|
198
|
+
memoryAuthEntries.set(account, payload);
|
|
199
|
+
},
|
|
200
|
+
remove(account) {
|
|
201
|
+
memoryAuthEntries.delete(account);
|
|
202
|
+
},
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
const unavailableAuthSecretStore: AuthSecretStore = {
|
|
206
|
+
read() {
|
|
207
|
+
testAuthSecretStoreReadCount++;
|
|
208
|
+
throw new Error('simulated secure credential store unavailable');
|
|
209
|
+
},
|
|
210
|
+
write() {
|
|
211
|
+
throw new Error('simulated secure credential store unavailable');
|
|
212
|
+
},
|
|
213
|
+
remove() {
|
|
214
|
+
throw new Error('simulated secure credential store unavailable');
|
|
215
|
+
},
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
function createKeyRevokedTestError(): Error {
|
|
219
|
+
return new Error("Couldn't access platform storage: KeyRevoked", { cause: new Error('KeyRevoked') });
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const keyRevokedAuthSecretStore: AuthSecretStore = {
|
|
223
|
+
read() {
|
|
224
|
+
testAuthSecretStoreReadCount++;
|
|
225
|
+
throw createKeyRevokedTestError();
|
|
226
|
+
},
|
|
227
|
+
write() {
|
|
228
|
+
throw createKeyRevokedTestError();
|
|
229
|
+
},
|
|
230
|
+
remove() {
|
|
231
|
+
throw createKeyRevokedTestError();
|
|
232
|
+
},
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
export function resetTestAuthSecretStore(): void {
|
|
236
|
+
memoryAuthEntries.clear();
|
|
237
|
+
authEntryCache.clear();
|
|
238
|
+
testAuthSecretStoreReadCount = 0;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
export function resetAuthEntryCache(): void {
|
|
242
|
+
authEntryCache.clear();
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
export function getTestAuthSecretStoreReadCount(): number {
|
|
246
|
+
return testAuthSecretStoreReadCount;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
export function getTestAuthSecretStoreEntries(): [string, string][] {
|
|
250
|
+
return [...memoryAuthEntries.entries()];
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
export function removeTestAuthSecretStoreEntry(account: string): void {
|
|
254
|
+
memoryAuthEntries.delete(account);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function getAuthSecretStore(): AuthSecretStore {
|
|
258
|
+
if (process.env[TEST_AUTH_STORE_ENV] === 'memory') return memoryAuthSecretStore;
|
|
259
|
+
if (process.env[TEST_AUTH_STORE_ENV] === 'sizelimited') return sizeLimitedAuthSecretStore;
|
|
260
|
+
if (process.env[TEST_AUTH_STORE_ENV] === 'unavailable') return unavailableAuthSecretStore;
|
|
261
|
+
if (process.env[TEST_AUTH_STORE_ENV] === 'keyrevoked') return keyRevokedAuthSecretStore;
|
|
262
|
+
return keyringAuthSecretStore;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function getKeyringEntry(account: string): KeyringEntry {
|
|
266
|
+
try {
|
|
267
|
+
KeyringEntryClass ??= loadKeyringEntryClass();
|
|
268
|
+
return new KeyringEntryClass(AUTH_SECRET_SERVICE, account);
|
|
269
|
+
} catch (error) {
|
|
270
|
+
throw new Error('OAuth secure credential storage is unavailable. Configure the OS credential store and retry authentication.', { cause: error });
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
function loadKeyringEntryClass(keyringRequire: KeyringRequire = require, platform: NodeJS.Platform = process.platform, arch: NodeJS.Architecture = process.arch): KeyringEntryConstructor {
|
|
275
|
+
try {
|
|
276
|
+
return (keyringRequire('@napi-rs/keyring') as KeyringModule).Entry;
|
|
277
|
+
} catch (loaderError) {
|
|
278
|
+
try {
|
|
279
|
+
return loadKeyringNativeBindingFallback(keyringRequire, platform, arch).Entry;
|
|
280
|
+
} catch (fallbackError) {
|
|
281
|
+
throw new Error(`Failed to load @napi-rs/keyring; absolute-path native binding fallback also failed: ${formatErrorMessage(fallbackError)}`, {
|
|
282
|
+
cause: loaderError,
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function loadKeyringNativeBindingFallback(keyringRequire: KeyringRequire, platform: NodeJS.Platform, arch: NodeJS.Architecture): KeyringModule {
|
|
289
|
+
const targets = getKeyringNativeBindingTargets(platform, arch);
|
|
290
|
+
if (targets.length === 0) {
|
|
291
|
+
throw new Error(`Unsupported @napi-rs/keyring native binding target: ${platform}-${arch}`);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
let lastError: unknown;
|
|
295
|
+
for (const target of targets) {
|
|
296
|
+
try {
|
|
297
|
+
const packageJsonPath = keyringRequire.resolve(`${target.packageName}/package.json`);
|
|
298
|
+
return keyringRequire(join(dirname(packageJsonPath), target.bindingFile)) as KeyringModule;
|
|
299
|
+
} catch (error) {
|
|
300
|
+
lastError = error;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
throw lastError instanceof Error ? lastError : new Error(String(lastError));
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
function getKeyringNativeBindingTargets(platform: NodeJS.Platform, arch: NodeJS.Architecture): { packageName: string; bindingFile: string }[] {
|
|
308
|
+
return getKeyringNativeBindingSuffixes(platform, arch).map(suffix => ({
|
|
309
|
+
packageName: `@napi-rs/keyring-${suffix}`,
|
|
310
|
+
bindingFile: `keyring.${suffix}.node`,
|
|
311
|
+
}));
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
function getKeyringNativeBindingSuffixes(platform: NodeJS.Platform, arch: NodeJS.Architecture): string[] {
|
|
315
|
+
if (platform === 'darwin') {
|
|
316
|
+
if (arch === 'arm64') return ['darwin-arm64'];
|
|
317
|
+
if (arch === 'x64') return ['darwin-x64'];
|
|
318
|
+
}
|
|
319
|
+
if (platform === 'win32') {
|
|
320
|
+
if (arch === 'arm64') return ['win32-arm64-msvc'];
|
|
321
|
+
if (arch === 'x64') return ['win32-x64-msvc'];
|
|
322
|
+
if (arch === 'ia32') return ['win32-ia32-msvc'];
|
|
323
|
+
}
|
|
324
|
+
if (platform === 'linux') {
|
|
325
|
+
if (arch === 'arm64') return ['linux-arm64-gnu', 'linux-arm64-musl'];
|
|
326
|
+
if (arch === 'arm') return ['linux-arm-gnueabihf'];
|
|
327
|
+
if (arch === 'riscv64') return ['linux-riscv64-gnu'];
|
|
328
|
+
if (arch === 'x64') return ['linux-x64-gnu', 'linux-x64-musl'];
|
|
329
|
+
}
|
|
330
|
+
if (platform === 'freebsd' && arch === 'x64') return ['freebsd-x64'];
|
|
331
|
+
return [];
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
function formatErrorMessage(error: unknown): string {
|
|
335
|
+
return error instanceof Error ? error.message : String(error);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
type KeyringRecoveryOperation = 'read' | 'write' | 'remove';
|
|
339
|
+
|
|
340
|
+
type KeyringRecoveryResponse =
|
|
341
|
+
| { ok: true; found?: boolean; value?: string }
|
|
342
|
+
| { ok: false; error?: string };
|
|
343
|
+
|
|
344
|
+
function isLinuxKeyringRecoveryEnabled(): boolean {
|
|
345
|
+
if (process.env[KEYRING_RECOVERY_DISABLED_ENV] === '1') return false;
|
|
346
|
+
return process.platform === 'linux' || process.env[TEST_LINUX_KEYRING_RECOVERY_ENV] === '1';
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
function shouldAttemptLinuxKeyringRecovery(error: unknown): boolean {
|
|
350
|
+
return isLinuxKeyringRecoveryEnabled()
|
|
351
|
+
&& causeChainContains(error, /key\s*(?:has been\s*)?revoked|keyrevoked/i);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
function runLinuxKeyringRecoveryOperation(operation: KeyringRecoveryOperation, account: string, payload?: string): KeyringRecoveryResponse {
|
|
355
|
+
const keyctl = process.env[KEYRING_RECOVERY_KEYCTL_ENV]?.trim() || 'keyctl';
|
|
356
|
+
const node = process.env[KEYRING_RECOVERY_NODE_ENV]?.trim() || 'node';
|
|
357
|
+
const helper = process.env[KEYRING_RECOVERY_HELPER_ENV]?.trim()
|
|
358
|
+
|| fileURLToPath(new URL('./mcp-keyring-helper.cjs', import.meta.url));
|
|
359
|
+
const request = JSON.stringify({ operation, service: AUTH_SECRET_SERVICE, account, payload });
|
|
360
|
+
const result = spawnSync(keyctl, ['session', '-', node, helper], {
|
|
361
|
+
input: `${request}\n`,
|
|
362
|
+
encoding: 'utf8',
|
|
363
|
+
maxBuffer: 1024 * 1024,
|
|
364
|
+
timeout: KEYRING_RECOVERY_TIMEOUT_MS,
|
|
365
|
+
windowsHide: true,
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
if (result.error) {
|
|
369
|
+
throw new Error(`Linux keyring recovery helper could not start: ${result.error.message}`, { cause: result.error });
|
|
370
|
+
}
|
|
371
|
+
if (result.status !== 0) {
|
|
372
|
+
throw new Error(`Linux keyring recovery helper failed with exit code ${result.status ?? 'unknown'}`);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
let response: unknown;
|
|
376
|
+
try {
|
|
377
|
+
response = JSON.parse(result.stdout.trim()) as unknown;
|
|
378
|
+
} catch (error) {
|
|
379
|
+
throw new Error('Linux keyring recovery helper returned invalid JSON', { cause: error });
|
|
380
|
+
}
|
|
381
|
+
if (typeof response !== 'object' || response === null || typeof (response as { ok?: unknown }).ok !== 'boolean') {
|
|
382
|
+
throw new Error('Linux keyring recovery helper returned an invalid response');
|
|
383
|
+
}
|
|
384
|
+
const typedResponse = response as KeyringRecoveryResponse;
|
|
385
|
+
if (typedResponse.ok === false) {
|
|
386
|
+
throw new Error(typedResponse.error || 'Linux keyring recovery helper failed');
|
|
387
|
+
}
|
|
388
|
+
if (operation === 'read' && typedResponse.found === true && typeof typedResponse.value !== 'string') {
|
|
389
|
+
throw new Error('Linux keyring recovery helper returned an invalid read response');
|
|
390
|
+
}
|
|
391
|
+
return typedResponse;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
const linuxKeyringRecoveryAuthSecretStore: AuthSecretStore = {
|
|
395
|
+
read(account) {
|
|
396
|
+
const response = runLinuxKeyringRecoveryOperation('read', account);
|
|
397
|
+
return response.ok && response.found === true ? response.value : undefined;
|
|
398
|
+
},
|
|
399
|
+
write(account, payload) {
|
|
400
|
+
runLinuxKeyringRecoveryOperation('write', account, payload);
|
|
401
|
+
},
|
|
402
|
+
remove(account) {
|
|
403
|
+
runLinuxKeyringRecoveryOperation('remove', account);
|
|
404
|
+
},
|
|
405
|
+
};
|
|
406
|
+
|
|
407
|
+
export function loadTestKeyringEntryClass(keyringRequire: KeyringRequire, platform: NodeJS.Platform, arch: NodeJS.Architecture): KeyringEntryConstructor {
|
|
408
|
+
return loadKeyringEntryClass(keyringRequire, platform, arch);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
export function getAuthStorageOptions(oauthDir: unknown, cwd = process.cwd()): AuthStorageOptions {
|
|
412
|
+
const baseDir = resolveConfiguredOAuthDir(oauthDir, cwd);
|
|
413
|
+
return baseDir ? { baseDir } : {};
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
export function getAuthBaseDir(options: AuthStorageOptions = {}): string {
|
|
417
|
+
const override = process.env.MCP_OAUTH_DIR?.trim();
|
|
418
|
+
if (override) return override;
|
|
419
|
+
return options.baseDir ?? getAgentPath('mcp-oauth');
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Get the legacy server-specific directory path.
|
|
424
|
+
*/
|
|
425
|
+
function getServerDir(serverName: string, options?: AuthStorageOptions): string {
|
|
426
|
+
if (typeof serverName !== 'string') {
|
|
427
|
+
throw new Error(`Invalid MCP server name: ${JSON.stringify(serverName)}`);
|
|
428
|
+
}
|
|
429
|
+
const storageKey = getAuthEntryAccount(serverName);
|
|
430
|
+
return join(getAuthBaseDir(options), storageKey);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
function getAuthEntryAccount(serverName: string): string {
|
|
434
|
+
if (typeof serverName !== 'string') {
|
|
435
|
+
throw new Error(`Invalid MCP server name: ${JSON.stringify(serverName)}`);
|
|
436
|
+
}
|
|
437
|
+
return `sha256-${createHash('sha256').update(serverName, 'utf8').digest('hex')}`;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
/**
|
|
441
|
+
* Get the legacy plaintext tokens file path for a server.
|
|
442
|
+
*/
|
|
443
|
+
export function getAuthEntryFilePath(serverName: string, options?: AuthStorageOptions): string {
|
|
444
|
+
return join(getServerDir(serverName, options), 'tokens.json');
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
function parseJsonPayload(serverName: string, payload: string, source: string): unknown {
|
|
448
|
+
try {
|
|
449
|
+
return JSON.parse(payload) as unknown;
|
|
450
|
+
} catch (error) {
|
|
451
|
+
throw new Error(`Failed to parse OAuth credentials for ${serverName} from ${source}`, { cause: error });
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
function parseAuthEntryPayload(serverName: string, payload: string, source: string): AuthEntry {
|
|
456
|
+
const parsed = parseJsonPayload(serverName, payload, source);
|
|
457
|
+
const entry = toAuthEntry(parsed);
|
|
458
|
+
if (!entry) {
|
|
459
|
+
throw new Error(`Failed to parse OAuth credentials for ${serverName} from ${source}: invalid credential shape`);
|
|
460
|
+
}
|
|
461
|
+
return entry;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
function toAuthEntry(value: unknown): AuthEntry | undefined {
|
|
465
|
+
const entry = toRecord(value);
|
|
466
|
+
if (!entry) return undefined;
|
|
467
|
+
|
|
468
|
+
const codeVerifier = optionalString(entry.codeVerifier);
|
|
469
|
+
const oauthState = optionalString(entry.oauthState);
|
|
470
|
+
const serverUrl = optionalString(entry.serverUrl);
|
|
471
|
+
if (codeVerifier === null || oauthState === null || serverUrl === null) return undefined;
|
|
472
|
+
|
|
473
|
+
const tokens = entry.tokens === undefined ? undefined : toStoredTokens(entry.tokens);
|
|
474
|
+
const clientInfo = entry.clientInfo === undefined ? undefined : toStoredClientInfo(entry.clientInfo);
|
|
475
|
+
if ((entry.tokens !== undefined && !tokens) || (entry.clientInfo !== undefined && !clientInfo)) return undefined;
|
|
476
|
+
|
|
477
|
+
const authEntry: AuthEntry = {};
|
|
478
|
+
if (tokens) authEntry.tokens = tokens;
|
|
479
|
+
if (clientInfo) authEntry.clientInfo = clientInfo;
|
|
480
|
+
if (codeVerifier !== undefined) authEntry.codeVerifier = codeVerifier;
|
|
481
|
+
if (oauthState !== undefined) authEntry.oauthState = oauthState;
|
|
482
|
+
if (serverUrl !== undefined) authEntry.serverUrl = serverUrl;
|
|
483
|
+
return authEntry;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
function toStoredTokens(value: unknown): StoredTokens | undefined {
|
|
487
|
+
const tokens = toRecord(value);
|
|
488
|
+
if (!tokens || typeof tokens.accessToken !== 'string') return undefined;
|
|
489
|
+
|
|
490
|
+
const refreshToken = optionalString(tokens.refreshToken);
|
|
491
|
+
const scope = optionalString(tokens.scope);
|
|
492
|
+
const issuer = optionalString(tokens.issuer);
|
|
493
|
+
const expiresAt = optionalNumber(tokens.expiresAt);
|
|
494
|
+
if (refreshToken === null || scope === null || issuer === null || expiresAt === null) return undefined;
|
|
495
|
+
|
|
496
|
+
const storedTokens: StoredTokens = { accessToken: tokens.accessToken };
|
|
497
|
+
if (refreshToken !== undefined) storedTokens.refreshToken = refreshToken;
|
|
498
|
+
if (expiresAt !== undefined) storedTokens.expiresAt = expiresAt;
|
|
499
|
+
if (scope !== undefined) storedTokens.scope = scope;
|
|
500
|
+
if (issuer !== undefined) storedTokens.issuer = issuer;
|
|
501
|
+
return storedTokens;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
function toStoredClientInfo(value: unknown): StoredClientInfo | undefined {
|
|
505
|
+
const clientInfo = toRecord(value);
|
|
506
|
+
if (!clientInfo || typeof clientInfo.clientId !== 'string') return undefined;
|
|
507
|
+
|
|
508
|
+
const clientSecret = optionalString(clientInfo.clientSecret);
|
|
509
|
+
const issuer = optionalString(clientInfo.issuer);
|
|
510
|
+
const clientIdIssuedAt = optionalNumber(clientInfo.clientIdIssuedAt);
|
|
511
|
+
const clientSecretExpiresAt = optionalNumber(clientInfo.clientSecretExpiresAt);
|
|
512
|
+
const configPreRegistered = optionalBoolean(clientInfo.configPreRegistered);
|
|
513
|
+
if (clientSecret === null || issuer === null || clientIdIssuedAt === null || clientSecretExpiresAt === null || configPreRegistered === null) return undefined;
|
|
514
|
+
|
|
515
|
+
const storedClient: StoredClientInfo = { clientId: clientInfo.clientId };
|
|
516
|
+
const redirectUris = stringArray(clientInfo.redirectUris);
|
|
517
|
+
if (clientSecret !== undefined) storedClient.clientSecret = clientSecret;
|
|
518
|
+
if (clientIdIssuedAt !== undefined) storedClient.clientIdIssuedAt = clientIdIssuedAt;
|
|
519
|
+
if (clientSecretExpiresAt !== undefined) storedClient.clientSecretExpiresAt = clientSecretExpiresAt;
|
|
520
|
+
if (redirectUris !== undefined) storedClient.redirectUris = redirectUris;
|
|
521
|
+
if (issuer !== undefined) storedClient.issuer = issuer;
|
|
522
|
+
if (configPreRegistered !== undefined) storedClient.configPreRegistered = configPreRegistered;
|
|
523
|
+
return storedClient;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
function toRecord(value: unknown): Record<string, unknown> | undefined {
|
|
527
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
528
|
+
? value as Record<string, unknown>
|
|
529
|
+
: undefined;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
function optionalString(value: unknown): string | null | undefined {
|
|
533
|
+
if (value === undefined) return undefined;
|
|
534
|
+
return typeof value === 'string' ? value : null;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
function optionalNumber(value: unknown): number | null | undefined {
|
|
538
|
+
if (value === undefined) return undefined;
|
|
539
|
+
return typeof value === 'number' ? value : null;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
function optionalBoolean(value: unknown): boolean | null | undefined {
|
|
543
|
+
if (value === undefined) return undefined;
|
|
544
|
+
return typeof value === 'boolean' ? value : null;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
function stringArray(value: unknown): string[] | undefined {
|
|
548
|
+
return Array.isArray(value) && value.every(uri => typeof uri === 'string') ? value : undefined;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
function isAuthEntryChunkManifest(value: unknown): value is AuthEntryChunkManifest {
|
|
552
|
+
if (typeof value !== 'object' || value === null) return false;
|
|
553
|
+
const manifest = value as Partial<AuthEntryChunkManifest>;
|
|
554
|
+
return manifest[AUTH_CHUNK_MANIFEST_KEY] === 1
|
|
555
|
+
&& typeof manifest.chunkCount === 'number'
|
|
556
|
+
&& Number.isInteger(manifest.chunkCount)
|
|
557
|
+
&& manifest.chunkCount > 0
|
|
558
|
+
&& typeof manifest.chunkDigest === 'string'
|
|
559
|
+
&& /^[a-f0-9]{16}$/.test(manifest.chunkDigest);
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
function getAuthEntryChunkAccount(account: string, manifest: AuthEntryChunkManifest, index: number): string {
|
|
563
|
+
return `${account}.chunk.${manifest.chunkDigest}.${index}`;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
function getAuthEntryChunkAccounts(account: string, manifest: AuthEntryChunkManifest): string[] {
|
|
567
|
+
return Array.from({ length: manifest.chunkCount }, (_, index) => getAuthEntryChunkAccount(account, manifest, index));
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
function readChunkManifestFromPayload(serverName: string, payload: string, source: string): AuthEntryChunkManifest | undefined {
|
|
571
|
+
const parsed = parseJsonPayload(serverName, payload, source);
|
|
572
|
+
return isAuthEntryChunkManifest(parsed) ? parsed : undefined;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
function readExistingChunkManifest(store: AuthSecretStore, serverName: string, account: string): AuthEntryChunkManifest | undefined {
|
|
576
|
+
try {
|
|
577
|
+
const payload = store.read(account);
|
|
578
|
+
return payload === undefined ? undefined : readChunkManifestFromPayload(serverName, payload, 'OS secure credential store');
|
|
579
|
+
} catch {
|
|
580
|
+
return undefined;
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
function removeChunkPayloads(store: AuthSecretStore, account: string, manifest: AuthEntryChunkManifest): void {
|
|
585
|
+
for (const chunkAccount of getAuthEntryChunkAccounts(account, manifest)) {
|
|
586
|
+
store.remove(chunkAccount);
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
function tryRemoveChunkPayloads(store: AuthSecretStore, account: string, manifest: AuthEntryChunkManifest | undefined): void {
|
|
591
|
+
if (!manifest) return;
|
|
592
|
+
try {
|
|
593
|
+
removeChunkPayloads(store, account, manifest);
|
|
594
|
+
} catch {
|
|
595
|
+
// Stale chunk cleanup must not hide a successful credential write.
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
function createChunkManifest(payload: string): AuthEntryChunkManifest {
|
|
600
|
+
return {
|
|
601
|
+
[AUTH_CHUNK_MANIFEST_KEY]: 1,
|
|
602
|
+
chunkCount: Math.ceil(payload.length / AUTH_SECRET_CHUNK_SIZE),
|
|
603
|
+
chunkDigest: createHash('sha256').update(payload, 'utf8').digest('hex').slice(0, 16),
|
|
604
|
+
};
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
function readChunkedAuthEntry(store: AuthSecretStore, serverName: string, account: string, manifest: AuthEntryChunkManifest): AuthEntry {
|
|
608
|
+
const chunks = getAuthEntryChunkAccounts(account, manifest).map((chunkAccount) => {
|
|
609
|
+
try {
|
|
610
|
+
const chunk = store.read(chunkAccount);
|
|
611
|
+
if (chunk === undefined) {
|
|
612
|
+
throw new Error(`Missing OAuth credential chunk ${chunkAccount} for ${serverName}`);
|
|
613
|
+
}
|
|
614
|
+
return chunk;
|
|
615
|
+
} catch (error) {
|
|
616
|
+
throw new OAuthCredentialStoreError(
|
|
617
|
+
`Failed to read OAuth credentials for ${serverName} from the OS secure credential store`,
|
|
618
|
+
'read',
|
|
619
|
+
error,
|
|
620
|
+
);
|
|
621
|
+
}
|
|
622
|
+
});
|
|
623
|
+
return parseAuthEntryPayload(serverName, chunks.join(''), 'OS secure credential store chunks');
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
function readLegacyAuthEntry(serverName: string, options?: AuthStorageOptions): AuthEntry | undefined {
|
|
627
|
+
const filePath = getAuthEntryFilePath(serverName, options);
|
|
628
|
+
if (!existsSync(filePath)) return undefined;
|
|
629
|
+
const data = readFileSync(filePath, 'utf-8');
|
|
630
|
+
return parseAuthEntryPayload(serverName, data, filePath);
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
function removeLegacyAuthEntry(serverName: string, options?: AuthStorageOptions): void {
|
|
634
|
+
const filePath = getAuthEntryFilePath(serverName, options);
|
|
635
|
+
if (!existsSync(filePath)) return;
|
|
636
|
+
try {
|
|
637
|
+
rmSync(filePath, { force: true });
|
|
638
|
+
} catch (error) {
|
|
639
|
+
throw new Error(`Failed to remove legacy plaintext OAuth credentials for ${serverName} at ${filePath}`, { cause: error });
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
const dir = getServerDir(serverName, options);
|
|
643
|
+
try {
|
|
644
|
+
rmSync(dir, { recursive: true });
|
|
645
|
+
} catch {
|
|
646
|
+
// Directory may contain future non-secret metadata; the plaintext file was already removed.
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
function writeSecureAuthEntryToStore(store: AuthSecretStore, serverName: string, entry: AuthEntry): void {
|
|
651
|
+
const account = getAuthEntryAccount(serverName);
|
|
652
|
+
const payload = JSON.stringify(entry);
|
|
653
|
+
const previousManifest = readExistingChunkManifest(store, serverName, account);
|
|
654
|
+
const manifest = payload.length > AUTH_SECRET_CHUNK_SIZE ? createChunkManifest(payload) : undefined;
|
|
655
|
+
|
|
656
|
+
try {
|
|
657
|
+
if (manifest) {
|
|
658
|
+
for (let index = 0; index < manifest.chunkCount; index++) {
|
|
659
|
+
const chunk = payload.slice(index * AUTH_SECRET_CHUNK_SIZE, (index + 1) * AUTH_SECRET_CHUNK_SIZE);
|
|
660
|
+
store.write(getAuthEntryChunkAccount(account, manifest, index), chunk);
|
|
661
|
+
}
|
|
662
|
+
store.write(account, JSON.stringify(manifest));
|
|
663
|
+
} else {
|
|
664
|
+
// Compact: multiline secrets corrupt gnome-keyring plaintext (GKeyFile) collections.
|
|
665
|
+
store.write(account, payload);
|
|
666
|
+
}
|
|
667
|
+
if (previousManifest?.chunkDigest !== manifest?.chunkDigest) {
|
|
668
|
+
tryRemoveChunkPayloads(store, account, previousManifest);
|
|
669
|
+
}
|
|
670
|
+
} catch (error) {
|
|
671
|
+
tryRemoveChunkPayloads(store, account, manifest);
|
|
672
|
+
throw new OAuthCredentialStoreError(
|
|
673
|
+
`Failed to write OAuth credentials for ${serverName} to the OS secure credential store`,
|
|
674
|
+
'write',
|
|
675
|
+
error,
|
|
676
|
+
);
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
publishAuthEntryToCache(serverName, payload);
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
function publishAuthEntryToCache(serverName: string, payload: string): void {
|
|
683
|
+
if (!isAuthEntryCacheEnabled()) return;
|
|
684
|
+
// Cache the same normalized shape a fresh persistent-store read returns.
|
|
685
|
+
const normalized = toAuthEntry(JSON.parse(payload) as unknown);
|
|
686
|
+
if (!normalized) {
|
|
687
|
+
authEntryCache.delete(serverName);
|
|
688
|
+
return;
|
|
689
|
+
}
|
|
690
|
+
authEntryCache.set(serverName, cloneAuthEntry(normalized));
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
function writeSecureAuthEntry(serverName: string, entry: AuthEntry): void {
|
|
694
|
+
try {
|
|
695
|
+
writeSecureAuthEntryToStore(getAuthSecretStore(), serverName, entry);
|
|
696
|
+
} catch (error) {
|
|
697
|
+
if (!shouldAttemptLinuxKeyringRecovery(error)) throw error;
|
|
698
|
+
writeSecureAuthEntryToStore(linuxKeyringRecoveryAuthSecretStore, serverName, entry);
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
/**
|
|
703
|
+
* Read the auth entry for a server from the OS secure store, importing and
|
|
704
|
+
* deleting a legacy plaintext entry when present.
|
|
705
|
+
*/
|
|
706
|
+
function readAuthEntryFromStore(
|
|
707
|
+
store: AuthSecretStore,
|
|
708
|
+
serverName: string,
|
|
709
|
+
options?: AuthStorageOptions,
|
|
710
|
+
behavior: { migrateLegacy?: boolean } = {},
|
|
711
|
+
): AuthEntry | undefined {
|
|
712
|
+
const account = getAuthEntryAccount(serverName);
|
|
713
|
+
let payload: string | undefined;
|
|
714
|
+
try {
|
|
715
|
+
payload = store.read(account);
|
|
716
|
+
} catch (error) {
|
|
717
|
+
throw new OAuthCredentialStoreError(
|
|
718
|
+
`Failed to read OAuth credentials for ${serverName} from the OS secure credential store`,
|
|
719
|
+
'read',
|
|
720
|
+
error,
|
|
721
|
+
);
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
if (payload !== undefined) {
|
|
725
|
+
const manifest = readChunkManifestFromPayload(serverName, payload, 'OS secure credential store');
|
|
726
|
+
const entry = manifest
|
|
727
|
+
? readChunkedAuthEntry(store, serverName, account, manifest)
|
|
728
|
+
: parseAuthEntryPayload(serverName, payload, 'OS secure credential store');
|
|
729
|
+
removeLegacyAuthEntry(serverName, options);
|
|
730
|
+
return entry;
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
const legacyEntry = readLegacyAuthEntry(serverName, options);
|
|
734
|
+
if (!legacyEntry) return undefined;
|
|
735
|
+
if (behavior.migrateLegacy === false) return legacyEntry;
|
|
736
|
+
writeSecureAuthEntryToStore(store, serverName, legacyEntry);
|
|
737
|
+
removeLegacyAuthEntry(serverName, options);
|
|
738
|
+
return legacyEntry;
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
function readAuthEntry(
|
|
742
|
+
serverName: string,
|
|
743
|
+
options?: AuthStorageOptions,
|
|
744
|
+
behavior: { migrateLegacy?: boolean } = {},
|
|
745
|
+
): AuthEntry | undefined {
|
|
746
|
+
// Status-only reads deliberately bypass the cache because they do not
|
|
747
|
+
// migrate legacy entries.
|
|
748
|
+
const cacheable = behavior.migrateLegacy !== false && isAuthEntryCacheEnabled();
|
|
749
|
+
if (cacheable && authEntryCache.has(serverName)) {
|
|
750
|
+
return cloneAuthEntry(authEntryCache.get(serverName));
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
let entry: AuthEntry | undefined;
|
|
754
|
+
try {
|
|
755
|
+
entry = readAuthEntryFromStore(getAuthSecretStore(), serverName, options, behavior);
|
|
756
|
+
} catch (error) {
|
|
757
|
+
if (!shouldAttemptLinuxKeyringRecovery(error)) throw error;
|
|
758
|
+
entry = readAuthEntryFromStore(linuxKeyringRecoveryAuthSecretStore, serverName, options, behavior);
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
if (cacheable) authEntryCache.set(serverName, cloneAuthEntry(entry));
|
|
762
|
+
return entry;
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
/**
|
|
766
|
+
* Get auth entry for a server.
|
|
767
|
+
*/
|
|
768
|
+
export function getAuthEntry(serverName: string, options?: AuthStorageOptions): AuthEntry | undefined {
|
|
769
|
+
return readAuthEntry(serverName, options);
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
/**
|
|
773
|
+
* Get auth entry and validate it's for the correct URL.
|
|
774
|
+
* Returns undefined if URL has changed (credentials are invalid).
|
|
775
|
+
*/
|
|
776
|
+
export function getAuthForUrl(serverName: string, serverUrl: string, options?: AuthStorageOptions): AuthEntry | undefined {
|
|
777
|
+
const entry = getAuthEntry(serverName, options);
|
|
778
|
+
if (!entry) return undefined;
|
|
779
|
+
|
|
780
|
+
// If no serverUrl is stored, this is from an old version - consider it invalid
|
|
781
|
+
if (!entry.serverUrl) return undefined;
|
|
782
|
+
|
|
783
|
+
// If URL has changed, credentials are invalid
|
|
784
|
+
if (entry.serverUrl !== serverUrl) return undefined;
|
|
785
|
+
|
|
786
|
+
return entry;
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
/**
|
|
790
|
+
* Inspect credentials for status-only UI paths without treating an unavailable
|
|
791
|
+
* secure store as missing credentials. Authentication operations continue to
|
|
792
|
+
* use getAuthForUrl() directly and therefore remain fail-closed.
|
|
793
|
+
*/
|
|
794
|
+
export function inspectAuthForUrl(
|
|
795
|
+
serverName: string,
|
|
796
|
+
serverUrl: string,
|
|
797
|
+
options?: AuthStorageOptions,
|
|
798
|
+
): OAuthCredentialStatus {
|
|
799
|
+
try {
|
|
800
|
+
const entry = readAuthEntry(serverName, options, { migrateLegacy: false });
|
|
801
|
+
if (!entry?.serverUrl || entry.serverUrl !== serverUrl) return { status: 'absent' };
|
|
802
|
+
return { status: 'present', entry };
|
|
803
|
+
} catch (error) {
|
|
804
|
+
if (!(error instanceof OAuthCredentialStoreError)) throw error;
|
|
805
|
+
return { status: 'unavailable', message: formatOAuthCredentialStoreUnavailable(error) };
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
/**
|
|
810
|
+
* Save auth entry for a server.
|
|
811
|
+
*/
|
|
812
|
+
export function saveAuthEntry(serverName: string, entry: AuthEntry, serverUrl?: string, options?: AuthStorageOptions): void {
|
|
813
|
+
// Always update serverUrl if provided
|
|
814
|
+
if (serverUrl) {
|
|
815
|
+
entry.serverUrl = serverUrl;
|
|
816
|
+
}
|
|
817
|
+
writeSecureAuthEntry(serverName, entry);
|
|
818
|
+
removeLegacyAuthEntry(serverName, options);
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
/**
|
|
822
|
+
* Remove auth entry for a server.
|
|
823
|
+
*/
|
|
824
|
+
function removeAuthEntryFromStore(store: AuthSecretStore, serverName: string): void {
|
|
825
|
+
const account = getAuthEntryAccount(serverName);
|
|
826
|
+
try {
|
|
827
|
+
const payload = store.read(account);
|
|
828
|
+
const manifest = payload === undefined ? undefined : readChunkManifestFromPayload(serverName, payload, 'OS secure credential store');
|
|
829
|
+
if (manifest) removeChunkPayloads(store, account, manifest);
|
|
830
|
+
store.remove(account);
|
|
831
|
+
} catch (error) {
|
|
832
|
+
throw new OAuthCredentialStoreError(
|
|
833
|
+
`Failed to remove OAuth credentials for ${serverName} from the OS secure credential store`,
|
|
834
|
+
'remove',
|
|
835
|
+
error,
|
|
836
|
+
);
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
export function removeAuthEntry(serverName: string, options?: AuthStorageOptions): void {
|
|
841
|
+
try {
|
|
842
|
+
removeAuthEntryFromStore(getAuthSecretStore(), serverName);
|
|
843
|
+
} catch (error) {
|
|
844
|
+
if (!shouldAttemptLinuxKeyringRecovery(error)) throw error;
|
|
845
|
+
removeAuthEntryFromStore(linuxKeyringRecoveryAuthSecretStore, serverName);
|
|
846
|
+
}
|
|
847
|
+
authEntryCache.delete(serverName);
|
|
848
|
+
removeLegacyAuthEntry(serverName, options);
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
/**
|
|
852
|
+
* Forget a cached entry so the next ordinary read reloads secure storage.
|
|
853
|
+
*/
|
|
854
|
+
export function invalidateAuthEntryCache(serverName: string): void {
|
|
855
|
+
authEntryCache.delete(serverName);
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
/**
|
|
859
|
+
* Update tokens for a server.
|
|
860
|
+
*/
|
|
861
|
+
export function updateTokens(
|
|
862
|
+
serverName: string,
|
|
863
|
+
tokens: StoredTokens,
|
|
864
|
+
serverUrl?: string,
|
|
865
|
+
options?: AuthStorageOptions
|
|
866
|
+
): void {
|
|
867
|
+
const entry = getAuthEntry(serverName, options) ?? {};
|
|
868
|
+
if (serverUrl && entry.serverUrl !== serverUrl) {
|
|
869
|
+
delete entry.clientInfo;
|
|
870
|
+
delete entry.codeVerifier;
|
|
871
|
+
delete entry.oauthState;
|
|
872
|
+
}
|
|
873
|
+
entry.tokens = tokens;
|
|
874
|
+
saveAuthEntry(serverName, entry, serverUrl, options);
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
/**
|
|
878
|
+
* Update client info for a server.
|
|
879
|
+
*/
|
|
880
|
+
export function updateClientInfo(
|
|
881
|
+
serverName: string,
|
|
882
|
+
clientInfo: StoredClientInfo,
|
|
883
|
+
serverUrl?: string,
|
|
884
|
+
options?: AuthStorageOptions
|
|
885
|
+
): void {
|
|
886
|
+
const entry = getAuthEntry(serverName, options) ?? {};
|
|
887
|
+
if (serverUrl && entry.serverUrl !== serverUrl) {
|
|
888
|
+
delete entry.tokens;
|
|
889
|
+
delete entry.codeVerifier;
|
|
890
|
+
delete entry.oauthState;
|
|
891
|
+
}
|
|
892
|
+
entry.clientInfo = clientInfo;
|
|
893
|
+
saveAuthEntry(serverName, entry, serverUrl, options);
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
/**
|
|
897
|
+
* Update code verifier for a server.
|
|
898
|
+
*/
|
|
899
|
+
export function updateCodeVerifier(serverName: string, codeVerifier: string, serverUrl?: string, options?: AuthStorageOptions): void {
|
|
900
|
+
const entry = getAuthEntry(serverName, options) ?? {};
|
|
901
|
+
if (serverUrl && entry.serverUrl !== serverUrl) {
|
|
902
|
+
delete entry.tokens;
|
|
903
|
+
delete entry.clientInfo;
|
|
904
|
+
delete entry.oauthState;
|
|
905
|
+
}
|
|
906
|
+
entry.codeVerifier = codeVerifier;
|
|
907
|
+
saveAuthEntry(serverName, entry, serverUrl, options);
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
/**
|
|
911
|
+
* Clear code verifier for a server.
|
|
912
|
+
*/
|
|
913
|
+
export function clearCodeVerifier(serverName: string, options?: AuthStorageOptions): void {
|
|
914
|
+
const entry = getAuthEntry(serverName, options);
|
|
915
|
+
if (entry) {
|
|
916
|
+
delete entry.codeVerifier;
|
|
917
|
+
saveAuthEntry(serverName, entry, undefined, options);
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
/**
|
|
922
|
+
* Update OAuth state for a server.
|
|
923
|
+
*/
|
|
924
|
+
export function updateOAuthState(serverName: string, state: string, serverUrl?: string, options?: AuthStorageOptions): void {
|
|
925
|
+
const entry = getAuthEntry(serverName, options) ?? {};
|
|
926
|
+
if (serverUrl && entry.serverUrl !== serverUrl) {
|
|
927
|
+
delete entry.tokens;
|
|
928
|
+
delete entry.clientInfo;
|
|
929
|
+
delete entry.codeVerifier;
|
|
930
|
+
}
|
|
931
|
+
entry.oauthState = state;
|
|
932
|
+
saveAuthEntry(serverName, entry, serverUrl, options);
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
/**
|
|
936
|
+
* Get OAuth state for a server.
|
|
937
|
+
*/
|
|
938
|
+
export function getOAuthState(serverName: string, options?: AuthStorageOptions): string | undefined {
|
|
939
|
+
const entry = getAuthEntry(serverName, options);
|
|
940
|
+
return entry?.oauthState;
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
/**
|
|
944
|
+
* Clear OAuth state for a server.
|
|
945
|
+
*/
|
|
946
|
+
export function clearOAuthState(serverName: string, options?: AuthStorageOptions): void {
|
|
947
|
+
const entry = getAuthEntry(serverName, options);
|
|
948
|
+
if (entry) {
|
|
949
|
+
delete entry.oauthState;
|
|
950
|
+
saveAuthEntry(serverName, entry, undefined, options);
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
/**
|
|
955
|
+
* Check if stored tokens are expired.
|
|
956
|
+
* Returns null if no tokens exist, false if no expiry or not expired, true if expired.
|
|
957
|
+
*/
|
|
958
|
+
export function isTokenExpired(serverName: string, options?: AuthStorageOptions): boolean | null {
|
|
959
|
+
const entry = getAuthEntry(serverName, options);
|
|
960
|
+
if (!entry?.tokens) return null;
|
|
961
|
+
if (!entry.tokens.expiresAt) return false;
|
|
962
|
+
return entry.tokens.expiresAt < Date.now() / 1000;
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
/**
|
|
966
|
+
* Check if a server has stored tokens.
|
|
967
|
+
*/
|
|
968
|
+
export function hasStoredTokens(serverName: string, options?: AuthStorageOptions): boolean {
|
|
969
|
+
const entry = getAuthEntry(serverName, options);
|
|
970
|
+
return !!entry?.tokens;
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
/**
|
|
974
|
+
* Clear all credentials for a server.
|
|
975
|
+
*/
|
|
976
|
+
export function clearAllCredentials(serverName: string, options?: AuthStorageOptions): void {
|
|
977
|
+
removeAuthEntry(serverName, options);
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
/**
|
|
981
|
+
* Clear only client info for a server.
|
|
982
|
+
*/
|
|
983
|
+
export function clearClientInfo(serverName: string, options?: AuthStorageOptions): void {
|
|
984
|
+
const entry = getAuthEntry(serverName, options);
|
|
985
|
+
if (entry) {
|
|
986
|
+
delete entry.clientInfo;
|
|
987
|
+
saveAuthEntry(serverName, entry, undefined, options);
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
/**
|
|
992
|
+
* Clear only tokens for a server.
|
|
993
|
+
*/
|
|
994
|
+
export function clearTokens(serverName: string, options?: AuthStorageOptions): void {
|
|
995
|
+
const entry = getAuthEntry(serverName, options);
|
|
996
|
+
if (entry) {
|
|
997
|
+
delete entry.tokens;
|
|
998
|
+
saveAuthEntry(serverName, entry, undefined, options);
|
|
999
|
+
}
|
|
1000
|
+
}
|