@gajae-code/coding-agent 0.13.2 → 0.14.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 +215 -8
- package/README.md +2 -0
- package/bin/gajaessi.js +4 -0
- package/dist/types/async/job-manager.d.ts +55 -2
- package/dist/types/async/support.d.ts +14 -0
- package/dist/types/capability/mcp.d.ts +6 -0
- package/dist/types/capability/types.d.ts +6 -0
- package/dist/types/cli/accounts-cli.d.ts +19 -0
- package/dist/types/cli/args.d.ts +3 -0
- package/dist/types/cli/config-cli.d.ts +6 -0
- package/dist/types/cli/crash-cli.d.ts +10 -0
- package/dist/types/cli/customize-doctor.d.ts +145 -0
- package/dist/types/cli/daemon-cli.d.ts +3 -1
- package/dist/types/cli/mcp-cli.d.ts +11 -0
- package/dist/types/cli/notify-cli.d.ts +1 -1
- package/dist/types/cli/root-flags.d.ts +12 -0
- package/dist/types/cli/setup-cli.d.ts +3 -1
- package/dist/types/cli/skills-cli.d.ts +2 -1
- package/dist/types/cli/update-cli.d.ts +19 -1
- package/dist/types/cli.d.ts +6 -0
- package/dist/types/commands/accounts.d.ts +40 -0
- package/dist/types/commands/crash.d.ts +24 -0
- package/dist/types/commands/customize.d.ts +22 -0
- package/dist/types/commands/daemon.d.ts +1 -1
- package/dist/types/commands/launch.d.ts +6 -0
- package/dist/types/commands/setup.d.ts +6 -0
- package/dist/types/commands/skills.d.ts +6 -1
- package/dist/types/commands/update.d.ts +7 -0
- package/dist/types/config/atomic-yaml-patch-worker.d.ts +25 -0
- package/dist/types/config/atomic-yaml-patch.d.ts +62 -2
- package/dist/types/config/config-schema-version.d.ts +10 -0
- package/dist/types/config/file-lock.d.ts +18 -0
- package/dist/types/config/model-profile-activation.d.ts +3 -1
- package/dist/types/config/model-registry.d.ts +10 -1
- package/dist/types/config/models-config-schema.d.ts +2 -0
- package/dist/types/config/settings-schema.d.ts +73 -9
- package/dist/types/config/settings.d.ts +63 -0
- package/dist/types/config/skill-settings-defaults.d.ts +26 -0
- package/dist/types/config/task-delegation.d.ts +39 -0
- package/dist/types/config/update-channel.d.ts +10 -0
- package/dist/types/coordinator-mcp/server.d.ts +5 -1
- package/dist/types/crash/index-store.d.ts +87 -0
- package/dist/types/crash/nudge.d.ts +50 -0
- package/dist/types/crash/record-loader.d.ts +17 -0
- package/dist/types/crash/report.d.ts +134 -0
- package/dist/types/crash/sanitize.d.ts +25 -0
- package/dist/types/cursor.d.ts +13 -2
- package/dist/types/customization/import.d.ts +37 -0
- package/dist/types/customization/index.d.ts +4 -0
- package/dist/types/customization/inventory.d.ts +25 -0
- package/dist/types/customization/mutations.d.ts +32 -0
- package/dist/types/customization/types.d.ts +115 -0
- package/dist/types/daemon/control-types.d.ts +8 -1
- package/dist/types/daemon/operator-contract.d.ts +4 -4
- package/dist/types/discovery/claude.d.ts +39 -1
- package/dist/types/discovery/codex.d.ts +39 -1
- package/dist/types/discovery/index.d.ts +2 -0
- package/dist/types/discovery/mcp-compat.d.ts +30 -0
- package/dist/types/edit/renderer.d.ts +23 -0
- package/dist/types/extensibility/extensions/runner.d.ts +3 -0
- package/dist/types/extensibility/extensions/types.d.ts +21 -4
- package/dist/types/extensibility/gjc-plugins/observability.d.ts +6 -1
- package/dist/types/extensibility/gjc-plugins/registry.d.ts +8 -1
- package/dist/types/extensibility/hooks/loader.d.ts +19 -5
- package/dist/types/extensibility/runtime-skill-discovery.d.ts +22 -1
- package/dist/types/extensibility/skill-management.d.ts +107 -0
- package/dist/types/gjc-runtime/deep-interview-runtime.d.ts +3 -1
- package/dist/types/gjc-runtime/launch-worktree.d.ts +8 -0
- package/dist/types/gjc-runtime/linux-proc.d.ts +3 -0
- package/dist/types/gjc-runtime/ralplan-runtime.d.ts +10 -6
- package/dist/types/gjc-runtime/session-state-lock.d.ts +104 -0
- package/dist/types/gjc-runtime/session-state-sidecar.d.ts +120 -2
- package/dist/types/gjc-runtime/state-writer.d.ts +10 -1
- package/dist/types/gjc-runtime/ultragoal-guard.d.ts +4 -2
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +8 -6
- package/dist/types/gjc-runtime/workflow-settings.d.ts +109 -0
- package/dist/types/hooks/events.d.ts +60 -0
- package/dist/types/hooks/normalize.d.ts +83 -0
- package/dist/types/hooks/skill-state.d.ts +9 -2
- package/dist/types/main.d.ts +2 -1
- package/dist/types/modes/acp/abort-scope.d.ts +13 -0
- package/dist/types/modes/acp/acp-agent.d.ts +7 -4
- package/dist/types/modes/components/customization/customization-dashboard.d.ts +44 -0
- package/dist/types/modes/components/customization/import-wizard.d.ts +21 -0
- package/dist/types/modes/components/customization/index.d.ts +1 -0
- package/dist/types/modes/components/dynamic-theme-text.d.ts +9 -0
- package/dist/types/modes/components/gajae-pet-widget.d.ts +6 -28
- package/dist/types/modes/components/irc-sidebar.d.ts +1 -0
- package/dist/types/modes/components/iterm-pet-transport.d.ts +122 -0
- package/dist/types/modes/components/oauth-selector.d.ts +10 -4
- package/dist/types/modes/components/pet-capability.d.ts +7 -21
- package/dist/types/modes/components/settings-selector.d.ts +5 -0
- package/dist/types/modes/components/status-line/gh.d.ts +6 -2
- package/dist/types/modes/controllers/extension-ui-controller.d.ts +1 -1
- package/dist/types/modes/controllers/selector-controller.d.ts +7 -8
- package/dist/types/modes/controllers/stt-controller.d.ts +1 -1
- package/dist/types/modes/interactive-mode.d.ts +1 -0
- package/dist/types/modes/theme/defaults/index.d.ts +118 -0
- package/dist/types/modes/types.d.ts +1 -0
- package/dist/types/modes/utils/injected-user-submission.d.ts +10 -0
- package/dist/types/runtime-mcp/config.d.ts +9 -0
- package/dist/types/runtime-mcp/manager.d.ts +26 -1
- package/dist/types/runtime-mcp/oauth-discovery.d.ts +4 -0
- package/dist/types/runtime-mcp/oauth-flow.d.ts +24 -1
- package/dist/types/runtime-mcp/pool-key.d.ts +2 -0
- package/dist/types/runtime-mcp/protocol.d.ts +278 -0
- package/dist/types/runtime-mcp/scope-config.d.ts +29 -0
- package/dist/types/runtime-mcp/tool-bridge.d.ts +15 -13
- package/dist/types/runtime-mcp/transports/http.d.ts +9 -0
- package/dist/types/runtime-mcp/types.d.ts +102 -10
- package/dist/types/sdk/acp/adapter.d.ts +26 -5
- package/dist/types/sdk/broker/broker.d.ts +3 -55
- package/dist/types/sdk/broker/lifecycle.d.ts +18 -12
- package/dist/types/sdk/broker/session-index.d.ts +14 -5
- package/dist/types/sdk/broker/startup-failure.d.ts +16 -1
- package/dist/types/sdk/bus/chat-daemon-control.d.ts +51 -1
- package/dist/types/sdk/bus/chat-daemon-runtime.d.ts +4 -41
- package/dist/types/sdk/bus/config.d.ts +11 -0
- package/dist/types/sdk/bus/conversation-store.d.ts +0 -1
- package/dist/types/sdk/bus/daemon-paths.d.ts +6 -0
- package/dist/types/sdk/bus/discord-conversation.d.ts +2 -0
- package/dist/types/sdk/bus/discord-daemon.d.ts +17 -12
- package/dist/types/sdk/bus/existing-thread-readiness.d.ts +4 -34
- package/dist/types/sdk/bus/inbound-reaction-ordering.d.ts +61 -0
- package/dist/types/sdk/bus/index.d.ts +85 -99
- package/dist/types/sdk/bus/kind-aware-reconciliation.d.ts +29 -7
- package/dist/types/sdk/bus/managed-daemon.d.ts +2 -32
- package/dist/types/sdk/bus/notification-service.d.ts +52 -0
- package/dist/types/sdk/bus/operator-runtime.d.ts +1 -1
- package/dist/types/sdk/bus/prompt-reconciliation.d.ts +16 -5
- package/dist/types/sdk/bus/reconciliation-store.d.ts +113 -5
- package/dist/types/sdk/bus/session-control.d.ts +25 -1
- package/dist/types/sdk/bus/slack-conversation.d.ts +4 -0
- package/dist/types/sdk/bus/slack-daemon.d.ts +9 -17
- package/dist/types/sdk/bus/slack-live-provider.d.ts +3 -1
- package/dist/types/sdk/bus/slack-provider.d.ts +4 -0
- package/dist/types/sdk/bus/slack-thread-binding.d.ts +6 -40
- package/dist/types/sdk/bus/telegram-adoption-intent.d.ts +30 -104
- package/dist/types/sdk/bus/telegram-daemon-cli.d.ts +10 -0
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +262 -19
- package/dist/types/sdk/bus/telegram-daemon-orphan-reap.d.ts +125 -0
- package/dist/types/sdk/bus/telegram-daemon-owner-registry.d.ts +22 -0
- package/dist/types/sdk/bus/telegram-daemon.d.ts +119 -310
- package/dist/types/sdk/bus/telegram-reference.d.ts +1 -47
- package/dist/types/sdk/bus/threaded-render.d.ts +1 -0
- package/dist/types/sdk/bus/topic-registry.d.ts +33 -17
- package/dist/types/sdk/cli/rows.d.ts +2 -11
- package/dist/types/sdk/cli/session-cli.d.ts +15 -25
- package/dist/types/sdk/client/client.d.ts +97 -1
- package/dist/types/sdk/host/control/dispatch.d.ts +0 -7
- package/dist/types/sdk/host/control/index.d.ts +1 -1
- package/dist/types/sdk/host/control/operations.d.ts +18 -5
- package/dist/types/sdk/host/control/runtime-gate.d.ts +19 -0
- package/dist/types/sdk/host/host.d.ts +15 -1
- package/dist/types/sdk/host/query/handlers.d.ts +5 -0
- package/dist/types/sdk/host/reverse-leases.d.ts +1 -1
- package/dist/types/sdk/host/session-runtime.d.ts +127 -7
- package/dist/types/sdk/host/types.d.ts +1 -1
- package/dist/types/sdk/host/websocket-transport.d.ts +1 -1
- package/dist/types/sdk/index.d.ts +2 -1
- package/dist/types/sdk/lifecycle/broker-client.d.ts +8 -0
- package/dist/types/sdk/lifecycle/client.d.ts +59 -0
- package/dist/types/sdk/lifecycle/index.d.ts +3 -0
- package/dist/types/sdk/lifecycle/service.d.ts +232 -0
- package/dist/types/sdk/mcp/server.d.ts +9 -6
- package/dist/types/sdk/prompt-deadline-lease.d.ts +43 -0
- package/dist/types/sdk/prompt-deadline-manager.d.ts +28 -0
- package/dist/types/sdk/prompt-status.d.ts +10 -3
- package/dist/types/sdk/protocol/operation-registry.d.ts +5 -0
- package/dist/types/sdk/receipt-state.d.ts +17 -0
- package/dist/types/sdk/reconciliation-extensions.d.ts +2 -0
- package/dist/types/sdk/router/index.d.ts +1 -0
- package/dist/types/sdk/router/session-router.d.ts +152 -0
- package/dist/types/sdk/session-list.d.ts +22 -0
- package/dist/types/sdk/session-reconnect.d.ts +43 -1
- package/dist/types/sdk/session.d.ts +34 -1
- package/dist/types/sdk/transport/serve-cli.d.ts +1 -4
- package/dist/types/session/account-inventory.d.ts +86 -0
- package/dist/types/session/agent-session.d.ts +145 -6
- package/dist/types/session/agent-storage.d.ts +10 -0
- package/dist/types/session/coordinator-tool-label.d.ts +28 -0
- package/dist/types/session/internal/managed-session-storage.d.ts +23 -4
- package/dist/types/session/messages.d.ts +1 -1
- package/dist/types/session/secure-token-file.d.ts +3 -0
- package/dist/types/session/session-manager.d.ts +47 -1
- package/dist/types/session/startup-auth-config.d.ts +44 -0
- package/dist/types/session/terminal-abort.d.ts +378 -0
- package/dist/types/session/yield-queue.d.ts +7 -0
- package/dist/types/session-import/claude.d.ts +26 -0
- package/dist/types/session-import/codex.d.ts +88 -0
- package/dist/types/session-import/command.d.ts +35 -0
- package/dist/types/session-import/detect.d.ts +22 -0
- package/dist/types/session-import/index.d.ts +7 -0
- package/dist/types/session-import/provider-codex.d.ts +22 -0
- package/dist/types/session-import/provider-service.d.ts +38 -0
- package/dist/types/session-import/redact.d.ts +23 -0
- package/dist/types/session-import/service.d.ts +47 -0
- package/dist/types/session-import/types.d.ts +120 -0
- package/dist/types/setup/paseo/check.d.ts +16 -0
- package/dist/types/setup/paseo/install-saga.d.ts +115 -0
- package/dist/types/setup/paseo/json-publisher.d.ts +76 -0
- package/dist/types/setup/paseo/orchestration-preferences.d.ts +24 -0
- package/dist/types/setup/paseo/paseo-ownership.d.ts +87 -0
- package/dist/types/setup/paseo/paseo-setup.d.ts +29 -0
- package/dist/types/setup/paseo/provider-config.d.ts +35 -0
- package/dist/types/setup/paseo/remove.d.ts +14 -0
- package/dist/types/setup/paseo/result-types.d.ts +59 -0
- package/dist/types/setup/paseo/setup-deps.d.ts +73 -0
- package/dist/types/setup/paseo/skills-bridge.d.ts +44 -0
- package/dist/types/skill-state/active-state.d.ts +5 -1
- package/dist/types/slash-commands/acp-builtins.d.ts +5 -1
- package/dist/types/slash-commands/builtin-registry.d.ts +2 -0
- package/dist/types/slash-commands/helpers/credential-switch.d.ts +12 -0
- package/dist/types/slash-commands/helpers/usage-report.d.ts +5 -6
- package/dist/types/slash-commands/types.d.ts +7 -1
- package/dist/types/task/executor.d.ts +10 -0
- package/dist/types/task/index.d.ts +3 -1
- package/dist/types/tools/ask-answer-registry.d.ts +6 -3
- package/dist/types/tools/bash-sleep-advisory.d.ts +14 -0
- package/dist/types/tools/bash.d.ts +2 -6
- package/dist/types/tools/browser/attach.d.ts +11 -0
- package/dist/types/tools/browser/launch.d.ts +20 -0
- package/dist/types/tools/browser/profile-discovery.d.ts +6 -0
- package/dist/types/tools/browser/render.d.ts +1 -0
- package/dist/types/tools/browser.d.ts +3 -1
- package/dist/types/tools/image-gen.d.ts +10 -2
- package/dist/types/tools/index.d.ts +8 -0
- package/dist/types/tools/monitor.d.ts +1 -1
- package/dist/types/tools/skill-discovery.d.ts +8 -1
- package/dist/types/tools/subagent.d.ts +2 -0
- package/dist/types/tools/ultragoal-ask-guard.d.ts +2 -2
- package/dist/types/utils/herdr-pane.d.ts +76 -0
- package/package.json +19 -9
- package/scripts/build-binary.ts +2 -1
- package/scripts/build-sdk-package-smoke.ts +2 -13
- package/scripts/capture-sticky-viewport-showcase.ts +0 -1
- package/scripts/compile-args.ts +2 -0
- package/scripts/generate-sdk-adapter-parity-manifest.ts +31 -16
- package/scripts/generate-sdk-operation-inventory.ts +28 -0
- package/scripts/generate-telegram-baseline-manifest.ts +1 -0
- package/scripts/generate-tool-catalog.ts +6 -4
- package/scripts/verify-gjc-sdk-canonicalization.ts +5 -39
- package/src/async/job-manager.ts +352 -17
- package/src/async/support.ts +25 -0
- package/src/autoresearch/dashboard.ts +28 -13
- package/src/capability/index.ts +3 -1
- package/src/capability/mcp.ts +6 -0
- package/src/capability/types.ts +6 -0
- package/src/cli/accounts-cli.ts +395 -0
- package/src/cli/args.ts +23 -0
- package/src/cli/auth-broker-cli.ts +136 -66
- package/src/cli/auth-gateway-cli.ts +94 -70
- package/src/cli/config-cli.ts +27 -2
- package/src/cli/crash-cli.ts +78 -0
- package/src/cli/customize-doctor.ts +1605 -0
- package/src/cli/daemon-cli.ts +12 -3
- package/src/cli/fast-help.ts +1 -0
- package/src/cli/mcp-cli.ts +128 -60
- package/src/cli/notify-cli.ts +8 -14
- package/src/cli/root-flags.ts +8 -0
- package/src/cli/setup-cli.ts +145 -0
- package/src/cli/skills-cli.ts +38 -2
- package/src/cli/update-cli.ts +167 -12
- package/src/cli.ts +4 -0
- package/src/commands/accounts.ts +71 -0
- package/src/commands/crash.ts +35 -0
- package/src/commands/customize.ts +84 -0
- package/src/commands/daemon.ts +2 -2
- package/src/commands/deep-interview.ts +2 -0
- package/src/commands/launch.ts +1 -0
- package/src/commands/mcp.ts +12 -7
- package/src/commands/ralplan.ts +2 -0
- package/src/commands/sdk.ts +65 -32
- package/src/commands/setup.ts +5 -0
- package/src/commands/skills.ts +14 -4
- package/src/commands/ultragoal.ts +10 -1
- package/src/commands/update.ts +26 -15
- package/src/config/atomic-yaml-patch-worker.ts +57 -0
- package/src/config/atomic-yaml-patch.ts +769 -29
- package/src/config/config-schema-version.ts +10 -0
- package/src/config/file-lock.ts +70 -1
- package/src/config/mcp-schema.json +52 -14
- package/src/config/model-profile-activation.ts +23 -2
- package/src/config/model-profiles.ts +88 -21
- package/src/config/model-registry.ts +147 -21
- package/src/config/models-config-schema.ts +1 -1
- package/src/config/settings-schema.ts +77 -7
- package/src/config/settings.ts +4038 -199
- package/src/config/skill-settings-defaults.ts +41 -3
- package/src/config/task-delegation.ts +87 -0
- package/src/config/update-channel.ts +23 -0
- package/src/coordinator-mcp/server.ts +377 -308
- package/src/crash/index-store.ts +723 -0
- package/src/crash/nudge.ts +89 -0
- package/src/crash/record-loader.ts +149 -0
- package/src/crash/report.ts +551 -0
- package/src/crash/sanitize.ts +129 -0
- package/src/cursor.ts +36 -10
- package/src/customization/import.ts +946 -0
- package/src/customization/index.ts +4 -0
- package/src/customization/inventory.ts +335 -0
- package/src/customization/mutations.ts +141 -0
- package/src/customization/types.ts +223 -0
- package/src/daemon/control-types.ts +8 -1
- package/src/daemon/operator-contract.ts +6 -6
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/models/catalog.ts +31 -6
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +11 -22
- package/src/defaults/gjc/skills/ralplan/SKILL.md +36 -23
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +16 -0
- package/src/discovery/claude-hooks.ts +38 -0
- package/src/discovery/claude.ts +142 -209
- package/src/discovery/codex-hooks.ts +38 -0
- package/src/discovery/codex.ts +132 -198
- package/src/discovery/helpers.ts +8 -1
- package/src/discovery/index.ts +2 -0
- package/src/discovery/mcp-compat.ts +234 -0
- package/src/discovery/mcp-json.ts +6 -0
- package/src/edit/renderer.ts +40 -0
- package/src/edit/streaming.ts +4 -2
- package/src/exec/bash-executor.ts +24 -20
- package/src/export/html/index.ts +51 -2
- package/src/extensibility/extensions/loader.ts +9 -1
- package/src/extensibility/extensions/runner.ts +17 -4
- package/src/extensibility/extensions/types.ts +31 -6
- package/src/extensibility/gjc-plugins/constrained-hooks.ts +33 -0
- package/src/extensibility/gjc-plugins/installer.ts +9 -5
- package/src/extensibility/gjc-plugins/observability.ts +8 -2
- package/src/extensibility/gjc-plugins/registry.ts +13 -2
- package/src/extensibility/gjc-plugins/runtime-adapters.ts +3 -1
- package/src/extensibility/gjc-plugins/schema.ts +222 -39
- package/src/extensibility/hooks/loader.ts +154 -10
- package/src/extensibility/runtime-skill-discovery.ts +257 -60
- package/src/extensibility/skill-management.ts +368 -0
- package/src/extensibility/skills.ts +52 -16
- package/src/gjc-runtime/deep-interview-runtime.ts +45 -61
- package/src/gjc-runtime/launch-worktree.ts +56 -2
- package/src/gjc-runtime/linux-proc.ts +7 -1
- package/src/gjc-runtime/ralplan-runtime.ts +100 -164
- package/src/gjc-runtime/session-state-lock.ts +992 -0
- package/src/gjc-runtime/session-state-sidecar.ts +644 -142
- package/src/gjc-runtime/state-writer.ts +39 -14
- package/src/gjc-runtime/tmux-owner-isolation.ts +5 -4
- package/src/gjc-runtime/ultragoal-guard.ts +11 -4
- package/src/gjc-runtime/ultragoal-runtime.ts +44 -41
- package/src/gjc-runtime/workflow-settings.ts +596 -0
- package/src/goals/tools/goal-tool.ts +6 -1
- package/src/hooks/events.ts +291 -0
- package/src/hooks/native-skill-hook.ts +4 -0
- package/src/hooks/normalize.ts +369 -0
- package/src/hooks/skill-state.ts +165 -46
- package/src/internal-urls/docs-index.generated.ts +41 -32
- package/src/main.ts +36 -5
- package/src/migrate/mcp-mapper.ts +25 -2
- package/src/modes/acp/abort-scope.ts +29 -0
- package/src/modes/acp/acp-agent.ts +423 -98
- package/src/modes/components/assistant-message.ts +6 -1
- package/src/modes/components/chrome.ts +4 -3
- package/src/modes/components/customization/customization-dashboard.ts +443 -0
- package/src/modes/components/customization/import-wizard.ts +372 -0
- package/src/modes/components/customization/index.ts +1 -0
- package/src/modes/components/dynamic-theme-text.ts +22 -0
- package/src/modes/components/gajae-pet-widget.ts +607 -193
- package/src/modes/components/irc-sidebar.ts +11 -0
- package/src/modes/components/iterm-pet-transport.ts +585 -0
- package/src/modes/components/model-selector.ts +1 -6
- package/src/modes/components/oauth-selector.ts +277 -86
- package/src/modes/components/pet-capability.ts +35 -31
- package/src/modes/components/settings-selector.ts +29 -5
- package/src/modes/components/status-line/gh.ts +45 -1
- package/src/modes/components/status-line/segments.ts +19 -4
- package/src/modes/components/tool-status-header.ts +13 -3
- package/src/modes/controllers/command-controller.ts +20 -8
- package/src/modes/controllers/extension-ui-controller.ts +56 -257
- package/src/modes/controllers/input-controller.ts +10 -0
- package/src/modes/controllers/runtime-mcp-command-controller.ts +16 -3
- package/src/modes/controllers/selector-controller.ts +238 -77
- package/src/modes/controllers/stt-controller.ts +3 -3
- package/src/modes/interactive-mode.ts +88 -16
- package/src/modes/print-mode.ts +35 -6
- package/src/modes/runtime-init.ts +21 -68
- package/src/modes/theme/defaults/index.ts +2 -0
- package/src/modes/theme/defaults/ouroboros.json +118 -0
- package/src/modes/types.ts +1 -0
- package/src/modes/utils/injected-user-submission.ts +25 -0
- package/src/modes/utils/terminal-bell.ts +15 -1
- package/src/prompts/agent-fragments/ralplan-persistence.md +1 -1
- package/src/prompts/agent-fragments/restricted-bash.md +1 -1
- package/src/prompts/agents/critic.md +1 -1
- package/src/prompts/system/rlm-research.md +1 -1
- package/src/prompts/system/system-prompt.md +0 -2
- package/src/prompts/tools/bash.md +7 -1
- package/src/prompts/tools/browser.md +1 -1
- package/src/prompts/tools/cron.md +6 -6
- package/src/prompts/tools/read.md +0 -2
- package/src/prompts/tools/skill-discovery.md +4 -2
- package/src/runtime-mcp/client.ts +427 -23
- package/src/runtime-mcp/config.ts +37 -5
- package/src/runtime-mcp/manager-pool.test.ts +56 -0
- package/src/runtime-mcp/manager.ts +52 -2
- package/src/runtime-mcp/oauth-discovery.ts +13 -0
- package/src/runtime-mcp/oauth-flow.ts +46 -1
- package/src/runtime-mcp/pool-key.ts +5 -1
- package/src/runtime-mcp/pool.test.ts +9 -0
- package/src/runtime-mcp/protocol.test.ts +353 -0
- package/src/runtime-mcp/protocol.ts +624 -0
- package/src/runtime-mcp/scope-config.ts +78 -0
- package/src/runtime-mcp/tool-bridge.ts +44 -10
- package/src/runtime-mcp/transports/http.ts +84 -13
- package/src/runtime-mcp/types.ts +123 -12
- package/src/sdk/acp/adapter.ts +328 -97
- package/src/sdk/broker/broker.ts +160 -741
- package/src/sdk/broker/ensure.ts +9 -1
- package/src/sdk/broker/lifecycle.ts +510 -116
- package/src/sdk/broker/operation-receipt-ledger.ts +11 -2
- package/src/sdk/broker/process-incarnation.ts +19 -0
- package/src/sdk/broker/session-index.ts +516 -117
- package/src/sdk/broker/startup-failure.ts +28 -5
- package/src/sdk/broker/transport.ts +1 -13
- package/src/sdk/bus/chat-daemon-cli.ts +4 -2
- package/src/sdk/bus/chat-daemon-control.ts +67 -6
- package/src/sdk/bus/chat-daemon-runtime.ts +183 -859
- package/src/sdk/bus/config.ts +13 -0
- package/src/sdk/bus/conversation-store.ts +59 -171
- package/src/sdk/bus/daemon-paths.ts +20 -0
- package/src/sdk/bus/discord-conversation.ts +2 -0
- package/src/sdk/bus/discord-daemon.ts +524 -126
- package/src/sdk/bus/discord-live-provider.ts +206 -79
- package/src/sdk/bus/existing-thread-readiness.ts +4 -97
- package/src/sdk/bus/inbound-reaction-ordering.ts +122 -0
- package/src/sdk/bus/index.ts +2480 -456
- package/src/sdk/bus/kind-aware-reconciliation.ts +204 -34
- package/src/sdk/bus/lifecycle-commands.ts +2 -2
- package/src/sdk/bus/managed-daemon.ts +2 -145
- package/src/sdk/bus/notification-service.ts +196 -0
- package/src/sdk/bus/operator-runtime.ts +1 -1
- package/src/sdk/bus/prompt-reconciliation.ts +24 -15
- package/src/sdk/bus/reconciliation-store.ts +553 -24
- package/src/sdk/bus/session-control.ts +49 -3
- package/src/sdk/bus/slack-conversation.ts +4 -0
- package/src/sdk/bus/slack-daemon.ts +733 -134
- package/src/sdk/bus/slack-live-provider.ts +65 -15
- package/src/sdk/bus/slack-provider.ts +4 -0
- package/src/sdk/bus/slack-thread-binding.ts +9 -104
- package/src/sdk/bus/telegram-adoption-intent.ts +299 -209
- package/src/sdk/bus/telegram-daemon-cli.ts +194 -7
- package/src/sdk/bus/telegram-daemon-contract.ts +265 -19
- package/src/sdk/bus/telegram-daemon-control.ts +3 -13
- package/src/sdk/bus/telegram-daemon-orphan-reap.ts +498 -0
- package/src/sdk/bus/telegram-daemon-owner-registry.ts +176 -0
- package/src/sdk/bus/telegram-daemon.ts +2552 -2280
- package/src/sdk/bus/telegram-reference.ts +1 -226
- package/src/sdk/bus/telegram-setup.ts +2 -2
- package/src/sdk/bus/threaded-render.ts +1 -0
- package/src/sdk/bus/topic-registry.ts +279 -146
- package/src/sdk/cli/rows.ts +2 -35
- package/src/sdk/cli/session-cli.ts +776 -700
- package/src/sdk/client/client.ts +892 -1
- package/src/sdk/host/control/dispatch.ts +93 -58
- package/src/sdk/host/control/index.ts +1 -1
- package/src/sdk/host/control/operations.ts +18 -10
- package/src/sdk/host/control/runtime-gate.ts +40 -0
- package/src/sdk/host/host.ts +63 -12
- package/src/sdk/host/query/handlers.ts +66 -7
- package/src/sdk/host/reverse-leases.ts +2 -2
- package/src/sdk/host/sdk-surface-parity.test.ts +1 -1
- package/src/sdk/host/session-runtime.test.ts +2787 -34
- package/src/sdk/host/session-runtime.ts +1489 -101
- package/src/sdk/host/surface-policy.ts +12 -8
- package/src/sdk/host/types.ts +1 -1
- package/src/sdk/host/websocket-transport.lifecycle.test.ts +31 -59
- package/src/sdk/host/websocket-transport.ts +85 -50
- package/src/sdk/index.ts +2 -1
- package/src/sdk/lifecycle/broker-client.ts +53 -0
- package/src/sdk/lifecycle/client.ts +234 -0
- package/src/sdk/lifecycle/index.ts +3 -0
- package/src/sdk/{bus/recent-activity.ts → lifecycle/recent-sessions.ts} +5 -2
- package/src/sdk/lifecycle/service.ts +720 -0
- package/src/sdk/mcp/server.ts +226 -188
- package/src/sdk/prompt-deadline-lease.ts +55 -0
- package/src/sdk/prompt-deadline-manager.ts +148 -0
- package/src/sdk/prompt-status.ts +11 -3
- package/src/sdk/protocol/operation-inventory.generated.json +272 -129
- package/src/sdk/protocol/operation-registry.ts +71 -8
- package/src/sdk/receipt-state.ts +43 -0
- package/src/sdk/reconciliation-extensions.ts +14 -0
- package/src/sdk/router/index.ts +1 -0
- package/src/sdk/router/session-router.ts +1658 -0
- package/src/sdk/session-list.ts +93 -0
- package/src/sdk/session-reconnect.ts +45 -1
- package/src/sdk/session.ts +716 -120
- package/src/sdk/transport/serve-cli.ts +18 -34
- package/src/session/account-inventory.ts +603 -0
- package/src/session/agent-session.ts +2873 -559
- package/src/session/agent-storage.ts +35 -0
- package/src/session/blob-store.ts +32 -1
- package/src/session/coordinator-tool-label.ts +40 -0
- package/src/session/internal/managed-session-scope.ts +4 -0
- package/src/session/internal/managed-session-storage.ts +199 -31
- package/src/session/messages.ts +1 -1
- package/src/session/secure-token-file.ts +80 -0
- package/src/session/session-manager.ts +757 -57
- package/src/session/session-storage.ts +25 -16
- package/src/session/startup-auth-config.ts +297 -0
- package/src/session/terminal-abort.ts +1253 -0
- package/src/session/yield-queue.ts +57 -15
- package/src/session-import/claude.ts +334 -0
- package/src/session-import/codex.ts +1033 -0
- package/src/session-import/command.ts +77 -0
- package/src/session-import/detect.ts +133 -0
- package/src/session-import/index.ts +7 -0
- package/src/session-import/provider-codex.ts +327 -0
- package/src/session-import/provider-service.ts +457 -0
- package/src/session-import/redact.ts +128 -0
- package/src/session-import/service.ts +1264 -0
- package/src/session-import/types.ts +148 -0
- package/src/setup/paseo/check.ts +213 -0
- package/src/setup/paseo/install-saga.ts +293 -0
- package/src/setup/paseo/json-publisher.ts +263 -0
- package/src/setup/paseo/orchestration-preferences.ts +86 -0
- package/src/setup/paseo/paseo-ownership.ts +224 -0
- package/src/setup/paseo/paseo-setup.ts +253 -0
- package/src/setup/paseo/provider-config.ts +139 -0
- package/src/setup/paseo/remove.ts +183 -0
- package/src/setup/paseo/result-types.ts +79 -0
- package/src/setup/paseo/setup-deps.ts +175 -0
- package/src/setup/paseo/skills-bridge.ts +260 -0
- package/src/skill-state/active-state.ts +21 -11
- package/src/slash-commands/acp-builtins.ts +9 -1
- package/src/slash-commands/builtin-registry.ts +117 -19
- package/src/slash-commands/helpers/credential-switch.ts +143 -0
- package/src/slash-commands/helpers/mcp.ts +9 -3
- package/src/slash-commands/helpers/usage-report.ts +61 -56
- package/src/slash-commands/types.ts +7 -2
- package/src/task/executor.ts +30 -11
- package/src/task/index.ts +66 -7
- package/src/task/render.ts +23 -9
- package/src/tools/ask-answer-registry.ts +23 -7
- package/src/tools/ask.ts +8 -4
- package/src/tools/bash-sleep-advisory.ts +115 -0
- package/src/tools/bash.ts +98 -18
- package/src/tools/browser/attach.ts +71 -3
- package/src/tools/browser/launch.ts +86 -13
- package/src/tools/browser/profile-discovery.ts +57 -7
- package/src/tools/browser/render.ts +8 -1
- package/src/tools/browser.ts +130 -21
- package/src/tools/computer.enforcement.test.ts +1 -1
- package/src/tools/computer.ts +3 -2
- package/src/tools/cron.ts +12 -1
- package/src/tools/image-gen.ts +349 -142
- package/src/tools/index.ts +8 -0
- package/src/tools/job.ts +33 -6
- package/src/tools/monitor.ts +41 -2
- package/src/tools/skill-discovery.ts +21 -29
- package/src/tools/subagent.ts +142 -24
- package/src/tools/todo-contract.ts +55 -3
- package/src/tools/todo-write.ts +4 -3
- package/src/tools/tool-catalog.generated.ts +6 -6
- package/src/tools/ultragoal-ask-guard.ts +10 -3
- package/src/utils/herdr-pane.ts +345 -0
- package/src/utils/title-generator.ts +2 -0
- package/src/web/scrapers/index.ts +6 -4
- package/dist/types/cli/malloc-env-guard.test.d.ts +0 -1
- package/dist/types/defaults/gjc-defaults.test.d.ts +0 -1
- package/dist/types/memory-backend/lazy-loading.test.d.ts +0 -1
- package/dist/types/runtime/boot-ordering.test.d.ts +0 -1
- package/dist/types/runtime/lazy-service.test.d.ts +0 -1
- package/dist/types/runtime/network-prewarm-service.test.d.ts +0 -1
- package/dist/types/runtime/workspace-tree-service.test.d.ts +0 -1
- package/dist/types/runtime-mcp/config.test.d.ts +0 -1
- package/dist/types/runtime-mcp/http.test.d.ts +0 -1
- package/dist/types/runtime-mcp/manager-pool.test.d.ts +0 -1
- package/dist/types/runtime-mcp/pool-key.test.d.ts +0 -1
- package/dist/types/runtime-mcp/pool.test.d.ts +0 -1
- package/dist/types/sdk/bus/lifecycle-control-runtime.d.ts +0 -117
- package/dist/types/sdk/bus/lifecycle-orchestrator.d.ts +0 -141
- package/dist/types/sdk/bus/telegram-cli.d.ts +0 -31
- package/dist/types/sdk/elevation/allowlist.d.ts +0 -20
- package/dist/types/sdk/elevation/audit.d.ts +0 -93
- package/dist/types/sdk/elevation/capability.d.ts +0 -3
- package/dist/types/sdk/elevation/digest.d.ts +0 -72
- package/dist/types/sdk/elevation/dispatch-receipt.d.ts +0 -85
- package/dist/types/sdk/elevation/grant-ledger.d.ts +0 -163
- package/dist/types/sdk/elevation/owner.d.ts +0 -48
- package/dist/types/sdk/host/import-graph.test.d.ts +0 -1
- package/dist/types/sdk/host/sdk-surface-parity.test.d.ts +0 -1
- package/dist/types/sdk/host/session-runtime.test.d.ts +0 -1
- package/dist/types/sdk/host/websocket-transport.lifecycle.test.d.ts +0 -1
- package/dist/types/session/auth-broker-config.d.ts +0 -13
- package/dist/types/session/heap-eviction-artifacts.test.d.ts +0 -1
- package/dist/types/skills/skills.test.d.ts +0 -1
- package/dist/types/slash-commands/notify-command.test.d.ts +0 -1
- package/dist/types/task/token-log.test.d.ts +0 -1
- package/dist/types/tools/computer.enforcement.test.d.ts +0 -1
- package/dist/types/tools/descriptors.test.d.ts +0 -1
- package/scripts/g005-daemon-smoke.ts +0 -180
- package/scripts/g011-daemon-path-smoke.ts +0 -153
- package/src/sdk/bus/lifecycle-control-runtime.ts +0 -1733
- package/src/sdk/bus/lifecycle-orchestrator.ts +0 -489
- package/src/sdk/bus/telegram-cli.ts +0 -212
- package/src/sdk/elevation/allowlist.ts +0 -54
- package/src/sdk/elevation/audit.ts +0 -208
- package/src/sdk/elevation/capability.ts +0 -41
- package/src/sdk/elevation/digest.ts +0 -129
- package/src/sdk/elevation/dispatch-receipt.ts +0 -184
- package/src/sdk/elevation/grant-ledger.ts +0 -1142
- package/src/sdk/elevation/owner.ts +0 -109
- package/src/session/auth-broker-config.ts +0 -109
- /package/dist/types/{ai-core-import-gate.test.d.ts → discovery/claude-hooks.d.ts} +0 -0
- /package/dist/types/{cli/fixture-report.test.d.ts → discovery/codex-hooks.d.ts} +0 -0
- /package/dist/types/sdk/{bus/recent-activity.d.ts → lifecycle/recent-sessions.d.ts} +0 -0
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { getAgentDir } from "@gajae-code/utils";
|
|
2
2
|
import { CliParseError } from "@gajae-code/utils/cli";
|
|
3
3
|
import { readSdkBrokerDiscovery, SdkClient, SdkClientError } from "../client";
|
|
4
|
+
import { SessionListTraversalError, sessionListPageFromResponse, traverseSessionList } from "../session-list";
|
|
4
5
|
import { DEFAULT_PENDING_CEILING_BYTES, MIN_PENDING_CEILING_BYTES, startSocketServe, startStdioServe } from "./index";
|
|
5
6
|
|
|
6
|
-
const MAX_SESSION_LIST_PAGES = 10_000;
|
|
7
|
-
|
|
8
7
|
type ServeMode = { kind: "stdio" } | { kind: "socket"; socketPath: string };
|
|
9
8
|
|
|
10
9
|
interface ServeArguments {
|
|
@@ -85,32 +84,29 @@ function brokerResult(value: unknown): Record<string, unknown> {
|
|
|
85
84
|
return isRecord(value) && isRecord(value.result) ? value.result : {};
|
|
86
85
|
}
|
|
87
86
|
|
|
88
|
-
function brokerSessionRows(
|
|
89
|
-
|
|
90
|
-
return value.sessions.flatMap(item => {
|
|
87
|
+
function brokerSessionRows(sessions: readonly unknown[]): BrokerSessionRow[] {
|
|
88
|
+
return sessions.flatMap(item => {
|
|
91
89
|
if (!isRecord(item) || typeof item.sessionId !== "string" || !item.sessionId) return [];
|
|
92
90
|
return [{ sessionId: item.sessionId, live: item.live === true, ambiguous: item.ambiguous === true }];
|
|
93
91
|
});
|
|
94
92
|
}
|
|
95
93
|
|
|
96
|
-
/**
|
|
97
|
-
* Exhausts broker `session.list` cursor pagination (default page limit 100) to
|
|
98
|
-
* one full snapshot; exported for tests.
|
|
99
|
-
*/
|
|
94
|
+
/** Exhausts strict broker `session.list` pages into one full session snapshot. */
|
|
100
95
|
export async function listBrokerSessions(broker: SdkClient): Promise<BrokerSessionRow[]> {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
96
|
+
try {
|
|
97
|
+
const pages = await traverseSessionList(
|
|
98
|
+
{},
|
|
99
|
+
async input => await broker.global("session.list", input),
|
|
100
|
+
response => {
|
|
101
|
+
brokerResult(response);
|
|
102
|
+
return sessionListPageFromResponse(response);
|
|
103
|
+
},
|
|
104
|
+
);
|
|
105
|
+
return pages.flatMap(page => brokerSessionRows(page.sessions));
|
|
106
|
+
} catch (error) {
|
|
107
|
+
if (error instanceof SessionListTraversalError) throw new SdkClientError("protocol_error", error.message);
|
|
108
|
+
throw error;
|
|
112
109
|
}
|
|
113
|
-
throw new SdkClientError("protocol_error", "session.list exceeded the page budget.");
|
|
114
110
|
}
|
|
115
111
|
|
|
116
112
|
/** Selects the session to serve through broker `session.list` truth (C10); exported for tests. */
|
|
@@ -156,19 +152,7 @@ export async function runSdkServe(argv: string[]): Promise<void> {
|
|
|
156
152
|
const url = typeof endpoint.url === "string" && endpoint.url ? endpoint.url : undefined;
|
|
157
153
|
const token = typeof endpoint.token === "string" ? endpoint.token : "";
|
|
158
154
|
if (!url) throw new Error("unavailable: broker returned an invalid endpoint record");
|
|
159
|
-
const options = {
|
|
160
|
-
url,
|
|
161
|
-
token,
|
|
162
|
-
pendingCeilingBytes,
|
|
163
|
-
validateDownstreamFrame: (source: string): boolean => {
|
|
164
|
-
try {
|
|
165
|
-
const frame = JSON.parse(source) as { type?: unknown; elevationRequestId?: unknown };
|
|
166
|
-
return frame.type !== "control_request" || frame.elevationRequestId === undefined;
|
|
167
|
-
} catch {
|
|
168
|
-
return true;
|
|
169
|
-
}
|
|
170
|
-
},
|
|
171
|
-
};
|
|
155
|
+
const options = { url, token, pendingCeilingBytes };
|
|
172
156
|
const handle =
|
|
173
157
|
parsed.mode.kind === "stdio"
|
|
174
158
|
? await startStdioServe(options)
|
|
@@ -0,0 +1,603 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type AuthStorage,
|
|
3
|
+
type CachedCredentialHealth,
|
|
4
|
+
type CachedUsageReport,
|
|
5
|
+
type CredentialHealthResult,
|
|
6
|
+
type CredentialInventoryRecord,
|
|
7
|
+
getEnvApiKey,
|
|
8
|
+
listProvidersWithEnvKey,
|
|
9
|
+
type Provider,
|
|
10
|
+
type UsageLimit,
|
|
11
|
+
type UsageStatus,
|
|
12
|
+
type UsageUnit,
|
|
13
|
+
type UsageWindow,
|
|
14
|
+
} from "@gajae-code/ai/core";
|
|
15
|
+
import type { RawSettings, Settings, SettingsAtomicPatch } from "../config/settings";
|
|
16
|
+
import { parsePersistedCredentialSelector } from "./startup-auth-config";
|
|
17
|
+
|
|
18
|
+
/** A redacted usage observation attached to an account row. */
|
|
19
|
+
export interface AccountUsageCache extends CachedUsageReport {}
|
|
20
|
+
|
|
21
|
+
/** Safe account health state used by presentation surfaces. */
|
|
22
|
+
export interface AccountHealthCache extends CachedCredentialHealth {}
|
|
23
|
+
|
|
24
|
+
export type AccountInventorySource = "stored" | "env" | "config" | "runtime";
|
|
25
|
+
|
|
26
|
+
/** Fixed presentation classification for a persisted disabled credential. */
|
|
27
|
+
export type AccountInventoryDisabledCause = "auth_failure" | "user_removed" | "duplicate" | "replaced" | "unknown";
|
|
28
|
+
|
|
29
|
+
export interface AccountInventoryCapabilities {
|
|
30
|
+
canCheck: boolean;
|
|
31
|
+
canPin: boolean;
|
|
32
|
+
canRemove: boolean;
|
|
33
|
+
hasCachedUsage: boolean;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface AccountInventoryRouting {
|
|
37
|
+
/** True when this row is the session's last recorded stored credential. */
|
|
38
|
+
active: boolean;
|
|
39
|
+
/** True when this source is the effective source for the provider/session. */
|
|
40
|
+
selected: boolean;
|
|
41
|
+
marker: "active" | "selected" | "available";
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Payload-free account row for renderers. This type deliberately has no
|
|
46
|
+
* AuthCredential, API-key bytes, access token, refresh token, or raw usage.
|
|
47
|
+
*/
|
|
48
|
+
export interface AccountInventoryRow {
|
|
49
|
+
/** Stable, non-secret presentation id. */
|
|
50
|
+
id: string;
|
|
51
|
+
/** Numeric storage id when this is a persisted row. */
|
|
52
|
+
credentialId?: number;
|
|
53
|
+
provider: string;
|
|
54
|
+
credentialKind: "oauth" | "api_key";
|
|
55
|
+
source: AccountInventorySource;
|
|
56
|
+
sourceLabel: string;
|
|
57
|
+
identityLabel: string | null;
|
|
58
|
+
/** OAuth identity is intentionally limited to safe labels from inventory. */
|
|
59
|
+
oauthIdentity?: { label: string };
|
|
60
|
+
disabled: boolean;
|
|
61
|
+
disabledCause: AccountInventoryDisabledCause | null;
|
|
62
|
+
health: AccountHealthCache;
|
|
63
|
+
usage?: AccountUsageCache;
|
|
64
|
+
capabilities: AccountInventoryCapabilities;
|
|
65
|
+
routing: AccountInventoryRouting;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface AccountInventorySnapshot {
|
|
69
|
+
generatedAt: number;
|
|
70
|
+
generation: number;
|
|
71
|
+
rows: AccountInventoryRow[];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface AccountInventoryInput {
|
|
75
|
+
authStorage: AuthStorage;
|
|
76
|
+
modelRegistry?: {
|
|
77
|
+
getAvailable?: () => Array<{ provider: string }>;
|
|
78
|
+
getProviderBaseUrl?: (provider: string) => string | undefined;
|
|
79
|
+
};
|
|
80
|
+
sessionId?: string;
|
|
81
|
+
provider?: string;
|
|
82
|
+
nowMs?: number;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
type SyntheticAccountSource = Exclude<AccountInventorySource, "stored">;
|
|
86
|
+
|
|
87
|
+
/** Source-scoped cache hooks supplied by AuthStorage. */
|
|
88
|
+
interface SourceHealthStorage {
|
|
89
|
+
peekCachedCredentialHealthForSource: (provider: string, source: SyntheticAccountSource) => CachedCredentialHealth;
|
|
90
|
+
recordCredentialHealthForSource: (
|
|
91
|
+
provider: string,
|
|
92
|
+
source: SyntheticAccountSource,
|
|
93
|
+
health: CachedCredentialHealth,
|
|
94
|
+
) => void;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export interface AccountInventoryCheckResult {
|
|
98
|
+
rowId: string;
|
|
99
|
+
provider: string;
|
|
100
|
+
credentialId?: number;
|
|
101
|
+
ok: boolean | null;
|
|
102
|
+
reason?: string;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function asSafeLabel(value: unknown): string | null {
|
|
106
|
+
if (typeof value !== "string") return null;
|
|
107
|
+
const normalized = value
|
|
108
|
+
.replace(/\u001b\][^\u0007]*(?:\u0007|\u001b\\)/g, " ")
|
|
109
|
+
.replace(/\u001b\[[0-?]*[ -/]*[@-~]/g, " ")
|
|
110
|
+
.replace(/bearer\s+[^\s,;]+/gi, "Bearer [redacted]")
|
|
111
|
+
.replace(/(api[_-]?key|token|secret|authorization)[=:]\s*[^\s,;]+/gi, "$1=[redacted]")
|
|
112
|
+
.replace(/https?:\/\/[^\s?#]+(?:\?[^\s#]*)?/gi, value => value.split("?")[0] ?? "[redacted URL]")
|
|
113
|
+
.replace(/[\u0000-\u001f\u007f-\u009f]/g, " ")
|
|
114
|
+
.replace(/[\u061c\u200e\u200f\u200b-\u200d\u2060\u202a-\u202e\u2066-\u2069\ufeff]/g, "")
|
|
115
|
+
.replace(/\s+/g, " ")
|
|
116
|
+
.trim();
|
|
117
|
+
return normalized.length > 0 ? normalized.slice(0, 160) : null;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function safeProvider(value: unknown): string {
|
|
121
|
+
return asSafeLabel(value) ?? "unknown-provider";
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function optionalSafeLabel(value: unknown): string | undefined {
|
|
125
|
+
return asSafeLabel(value) ?? undefined;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function asRecord(value: unknown): Record<string, unknown> | undefined {
|
|
129
|
+
return value !== null && typeof value === "object" && !Array.isArray(value)
|
|
130
|
+
? (value as Record<string, unknown>)
|
|
131
|
+
: undefined;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function finiteNumber(value: unknown): number | undefined {
|
|
135
|
+
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function classifyDisabledCause(value: unknown, disabled: boolean): AccountInventoryDisabledCause | null {
|
|
139
|
+
if (!disabled) return null;
|
|
140
|
+
if (typeof value !== "string") return "unknown";
|
|
141
|
+
const cause = value.trim();
|
|
142
|
+
if (/^(?:deleted|logged out) by user(?:$|\b)/i.test(cause) || /^disabled via auth-broker$/i.test(cause)) {
|
|
143
|
+
return "user_removed";
|
|
144
|
+
}
|
|
145
|
+
if (/^deduplicated duplicate credential$/i.test(cause)) return "duplicate";
|
|
146
|
+
if (/^replaced by newer credential$/i.test(cause)) return "replaced";
|
|
147
|
+
if (
|
|
148
|
+
/^(?:oauth|auth-broker) refresh failed:/i.test(cause) ||
|
|
149
|
+
/invalid_grant|grant is invalid|invalid_token|revoked|unauthorized|expired.*refresh|refresh.*expired/i.test(
|
|
150
|
+
cause,
|
|
151
|
+
) ||
|
|
152
|
+
(/\b(401|403)\b/.test(cause) && !/timeout|network|fetch failed|ECONNREFUSED/i.test(cause))
|
|
153
|
+
) {
|
|
154
|
+
return "auth_failure";
|
|
155
|
+
}
|
|
156
|
+
return "unknown";
|
|
157
|
+
}
|
|
158
|
+
function sourceId(provider: string, source: AccountInventorySource, credentialId?: number): string {
|
|
159
|
+
const safe = safeProvider(provider);
|
|
160
|
+
return credentialId === undefined ? `${safe}:${source}` : `${safe}:stored:${credentialId}`;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function sourceLabel(source: AccountInventorySource): string {
|
|
164
|
+
switch (source) {
|
|
165
|
+
case "stored":
|
|
166
|
+
return "stored credential";
|
|
167
|
+
case "env":
|
|
168
|
+
return "environment API key";
|
|
169
|
+
case "config":
|
|
170
|
+
return "config API key";
|
|
171
|
+
case "runtime":
|
|
172
|
+
return "runtime API key";
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function providerSet(input: AccountInventoryInput, inventory: CredentialInventoryRecord[]): Set<string> {
|
|
177
|
+
const providers = new Set(inventory.flatMap(row => (typeof row.provider === "string" ? [row.provider] : [])));
|
|
178
|
+
for (const provider of input.modelRegistry?.getAvailable?.() ?? []) {
|
|
179
|
+
if (typeof provider?.provider === "string") providers.add(provider.provider);
|
|
180
|
+
}
|
|
181
|
+
// This only asks whether a known env-backed provider is present. The key value
|
|
182
|
+
// never enters the snapshot or any renderer.
|
|
183
|
+
for (const provider of listProvidersWithEnvKey()) {
|
|
184
|
+
if (getEnvApiKey(provider)) providers.add(provider);
|
|
185
|
+
}
|
|
186
|
+
return providers;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function storedHealth(authStorage: AuthStorage, row: CredentialInventoryRecord): AccountHealthCache {
|
|
190
|
+
const cached = asRecord(authStorage.getCachedCredentialHealth(row.id));
|
|
191
|
+
if (row.disabled) return { status: "failed", reason: null };
|
|
192
|
+
const status: AccountHealthCache["status"] =
|
|
193
|
+
cached?.status === "ok" ||
|
|
194
|
+
cached?.status === "failed" ||
|
|
195
|
+
cached?.status === "unverifiable" ||
|
|
196
|
+
cached?.status === "unknown"
|
|
197
|
+
? cached.status
|
|
198
|
+
: "unknown";
|
|
199
|
+
return {
|
|
200
|
+
status,
|
|
201
|
+
reason: asSafeLabel(cached?.reason),
|
|
202
|
+
...(finiteNumber(cached?.checkedAt) !== undefined ? { checkedAt: finiteNumber(cached?.checkedAt) } : {}),
|
|
203
|
+
...(finiteNumber(cached?.retainUntil) !== undefined ? { retainUntil: finiteNumber(cached?.retainUntil) } : {}),
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function storedUsage(authStorage: AuthStorage, row: CredentialInventoryRecord): AccountUsageCache | undefined {
|
|
208
|
+
return authStorage.getCachedUsageReport(row.provider as Provider, row.id);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function safeUsageUnit(value: unknown): UsageUnit {
|
|
212
|
+
return value === "percent" ||
|
|
213
|
+
value === "tokens" ||
|
|
214
|
+
value === "requests" ||
|
|
215
|
+
value === "usd" ||
|
|
216
|
+
value === "minutes" ||
|
|
217
|
+
value === "bytes" ||
|
|
218
|
+
value === "unknown"
|
|
219
|
+
? value
|
|
220
|
+
: "unknown";
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function safeUsageStatus(value: unknown): UsageStatus | undefined {
|
|
224
|
+
return value === "ok" || value === "warning" || value === "exhausted" || value === "unknown" ? value : undefined;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function redactUsageWindow(value: unknown): UsageWindow | undefined {
|
|
228
|
+
const window = asRecord(value);
|
|
229
|
+
if (!window) return undefined;
|
|
230
|
+
return {
|
|
231
|
+
id: asSafeLabel(window.id) ?? "usage-window",
|
|
232
|
+
label: asSafeLabel(window.label) ?? "usage window",
|
|
233
|
+
...(finiteNumber(window.durationMs) !== undefined ? { durationMs: finiteNumber(window.durationMs) } : {}),
|
|
234
|
+
...(finiteNumber(window.resetsAt) !== undefined ? { resetsAt: finiteNumber(window.resetsAt) } : {}),
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function redactUsageLimit(value: unknown, reportProvider: string): UsageLimit {
|
|
239
|
+
const limit = asRecord(value);
|
|
240
|
+
const scope = asRecord(limit?.scope);
|
|
241
|
+
const amount = asRecord(limit?.amount);
|
|
242
|
+
const used = finiteNumber(amount?.used);
|
|
243
|
+
const amountLimit = finiteNumber(amount?.limit);
|
|
244
|
+
const remaining = finiteNumber(amount?.remaining);
|
|
245
|
+
const usedFraction = finiteNumber(amount?.usedFraction);
|
|
246
|
+
const remainingFraction = finiteNumber(amount?.remainingFraction);
|
|
247
|
+
const notes = Array.isArray(limit?.notes)
|
|
248
|
+
? limit.notes.map(note => asSafeLabel(note)).filter((note): note is string => note !== null)
|
|
249
|
+
: undefined;
|
|
250
|
+
const status = safeUsageStatus(limit?.status);
|
|
251
|
+
const window = redactUsageWindow(limit?.window);
|
|
252
|
+
return {
|
|
253
|
+
id: asSafeLabel(limit?.id) ?? "usage-limit",
|
|
254
|
+
label: asSafeLabel(limit?.label) ?? "usage limit",
|
|
255
|
+
scope: {
|
|
256
|
+
provider: safeProvider(scope?.provider ?? reportProvider),
|
|
257
|
+
...(optionalSafeLabel(scope?.accountId) ? { accountId: optionalSafeLabel(scope?.accountId) } : {}),
|
|
258
|
+
...(optionalSafeLabel(scope?.projectId) ? { projectId: optionalSafeLabel(scope?.projectId) } : {}),
|
|
259
|
+
...(optionalSafeLabel(scope?.orgId) ? { orgId: optionalSafeLabel(scope?.orgId) } : {}),
|
|
260
|
+
...(optionalSafeLabel(scope?.modelId) ? { modelId: optionalSafeLabel(scope?.modelId) } : {}),
|
|
261
|
+
...(optionalSafeLabel(scope?.tier) ? { tier: optionalSafeLabel(scope?.tier) } : {}),
|
|
262
|
+
...(optionalSafeLabel(scope?.windowId) ? { windowId: optionalSafeLabel(scope?.windowId) } : {}),
|
|
263
|
+
...(typeof scope?.shared === "boolean" ? { shared: scope.shared } : {}),
|
|
264
|
+
},
|
|
265
|
+
...(window ? { window } : {}),
|
|
266
|
+
amount: {
|
|
267
|
+
...(used !== undefined ? { used } : {}),
|
|
268
|
+
...(amountLimit !== undefined ? { limit: amountLimit } : {}),
|
|
269
|
+
...(remaining !== undefined ? { remaining } : {}),
|
|
270
|
+
...(usedFraction !== undefined ? { usedFraction } : {}),
|
|
271
|
+
...(remainingFraction !== undefined ? { remainingFraction } : {}),
|
|
272
|
+
unit: safeUsageUnit(amount?.unit),
|
|
273
|
+
},
|
|
274
|
+
...(status !== undefined ? { status } : {}),
|
|
275
|
+
...(notes !== undefined ? { notes } : {}),
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function redactUsageReport(report: CachedUsageReport["report"]): CachedUsageReport["report"] {
|
|
280
|
+
const value = asRecord(report);
|
|
281
|
+
const provider = safeProvider(value?.provider);
|
|
282
|
+
const metadata = asRecord(value?.metadata);
|
|
283
|
+
const safeMetadata = metadata
|
|
284
|
+
? Object.fromEntries(
|
|
285
|
+
["email", "accountId", "account", "user", "projectId", "orgId"].flatMap(key => {
|
|
286
|
+
const safe = asSafeLabel(metadata[key]);
|
|
287
|
+
return safe ? [[key, safe]] : [];
|
|
288
|
+
}),
|
|
289
|
+
)
|
|
290
|
+
: undefined;
|
|
291
|
+
const limits = Array.isArray(value?.limits) ? value.limits.map(limit => redactUsageLimit(limit, provider)) : [];
|
|
292
|
+
return {
|
|
293
|
+
provider,
|
|
294
|
+
fetchedAt: finiteNumber(value?.fetchedAt) ?? 0,
|
|
295
|
+
limits,
|
|
296
|
+
...(safeMetadata && Object.keys(safeMetadata).length > 0 ? { metadata: safeMetadata } : {}),
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
function redactUsageCache(usage: CachedUsageReport | undefined): AccountUsageCache | undefined {
|
|
301
|
+
if (!usage || !asRecord(usage.report)) return undefined;
|
|
302
|
+
return {
|
|
303
|
+
report: redactUsageReport(usage.report),
|
|
304
|
+
fetchedAt: finiteNumber(usage.fetchedAt) ?? 0,
|
|
305
|
+
freshUntil: finiteNumber(usage.freshUntil) ?? 0,
|
|
306
|
+
retainUntil: finiteNumber(usage.retainUntil) ?? 0,
|
|
307
|
+
freshness: usage.freshness === "fresh" ? "fresh" : "stale-last-good",
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function canPinStoredOAuth(authStorage: AuthStorage, provider: string): boolean {
|
|
312
|
+
if (authStorage.hasRuntimeApiKey(provider) || authStorage.hasConfigApiKey(provider)) return false;
|
|
313
|
+
return !getEnvApiKey(provider);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
function sourceHealth(authStorage: AuthStorage, provider: string, source: SyntheticAccountSource): AccountHealthCache {
|
|
317
|
+
const getter = (authStorage as AuthStorage & SourceHealthStorage).peekCachedCredentialHealthForSource;
|
|
318
|
+
const cached = getter.call(authStorage, provider, source);
|
|
319
|
+
return {
|
|
320
|
+
status:
|
|
321
|
+
cached.status === "ok" ||
|
|
322
|
+
cached.status === "failed" ||
|
|
323
|
+
cached.status === "unverifiable" ||
|
|
324
|
+
cached.status === "unknown"
|
|
325
|
+
? cached.status
|
|
326
|
+
: "unknown",
|
|
327
|
+
reason: asSafeLabel(cached.reason),
|
|
328
|
+
...(finiteNumber(cached.checkedAt) !== undefined ? { checkedAt: finiteNumber(cached.checkedAt) } : {}),
|
|
329
|
+
...(finiteNumber(cached.retainUntil) !== undefined ? { retainUntil: finiteNumber(cached.retainUntil) } : {}),
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
function recordSourceHealth(
|
|
334
|
+
authStorage: AuthStorage,
|
|
335
|
+
provider: string,
|
|
336
|
+
source: SyntheticAccountSource,
|
|
337
|
+
ok: boolean | null,
|
|
338
|
+
reason: unknown,
|
|
339
|
+
): void {
|
|
340
|
+
const recorder = (authStorage as AuthStorage & SourceHealthStorage).recordCredentialHealthForSource;
|
|
341
|
+
const now = Date.now();
|
|
342
|
+
recorder.call(authStorage, provider, source, {
|
|
343
|
+
status: ok === true ? "ok" : ok === false ? "failed" : "unverifiable",
|
|
344
|
+
reason: asSafeLabel(reason),
|
|
345
|
+
checkedAt: now,
|
|
346
|
+
retainUntil: now + 24 * 60 * 60_000,
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
function addStoredRows(
|
|
351
|
+
rows: AccountInventoryRow[],
|
|
352
|
+
authStorage: AuthStorage,
|
|
353
|
+
inventory: CredentialInventoryRecord[],
|
|
354
|
+
sessionId: string | undefined,
|
|
355
|
+
): void {
|
|
356
|
+
const removalTargetIds = new Set(
|
|
357
|
+
(typeof authStorage.listCredentialRemovalTargets === "function"
|
|
358
|
+
? authStorage.listCredentialRemovalTargets()
|
|
359
|
+
: []
|
|
360
|
+
).map(target => target.id),
|
|
361
|
+
);
|
|
362
|
+
for (const record of inventory) {
|
|
363
|
+
const identityLabel = asSafeLabel(record.identityLabel);
|
|
364
|
+
const safeUsage = redactUsageCache(storedUsage(authStorage, record));
|
|
365
|
+
const active =
|
|
366
|
+
typeof record.provider === "string" &&
|
|
367
|
+
authStorage.getSessionCredentialRowId(record.provider, sessionId) === record.id;
|
|
368
|
+
const canPin =
|
|
369
|
+
record.credentialKind === "oauth" && !record.disabled && canPinStoredOAuth(authStorage, record.provider);
|
|
370
|
+
const canRemove = record.credentialKind === "oauth" && removalTargetIds.has(record.id);
|
|
371
|
+
rows.push({
|
|
372
|
+
id: sourceId(record.provider, "stored", record.id),
|
|
373
|
+
credentialId: record.id,
|
|
374
|
+
provider: safeProvider(record.provider),
|
|
375
|
+
credentialKind: record.credentialKind,
|
|
376
|
+
source: "stored",
|
|
377
|
+
sourceLabel: sourceLabel("stored"),
|
|
378
|
+
identityLabel,
|
|
379
|
+
...(record.credentialKind === "oauth" && identityLabel ? { oauthIdentity: { label: identityLabel } } : {}),
|
|
380
|
+
disabled: record.disabled,
|
|
381
|
+
disabledCause: classifyDisabledCause(record.disabledCause, record.disabled),
|
|
382
|
+
health: storedHealth(authStorage, record),
|
|
383
|
+
...(safeUsage ? { usage: safeUsage } : {}),
|
|
384
|
+
capabilities: {
|
|
385
|
+
canCheck: true,
|
|
386
|
+
canPin,
|
|
387
|
+
canRemove,
|
|
388
|
+
hasCachedUsage: safeUsage !== undefined,
|
|
389
|
+
},
|
|
390
|
+
routing: {
|
|
391
|
+
active,
|
|
392
|
+
selected: active,
|
|
393
|
+
marker: active ? "active" : "available",
|
|
394
|
+
},
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
function addSyntheticRows(
|
|
400
|
+
rows: AccountInventoryRow[],
|
|
401
|
+
authStorage: AuthStorage,
|
|
402
|
+
providers: Set<string>,
|
|
403
|
+
sessionId: string | undefined,
|
|
404
|
+
): void {
|
|
405
|
+
for (const provider of [...providers].sort((a, b) => a.localeCompare(b))) {
|
|
406
|
+
const runtime = authStorage.hasRuntimeApiKey(provider);
|
|
407
|
+
const config = authStorage.hasConfigApiKey(provider);
|
|
408
|
+
const env = Boolean(getEnvApiKey(provider));
|
|
409
|
+
const effectiveType = authStorage.getEffectiveCredentialType(provider, sessionId);
|
|
410
|
+
|
|
411
|
+
const add = (source: AccountInventorySource): void => {
|
|
412
|
+
const selected =
|
|
413
|
+
source === "runtime"
|
|
414
|
+
? runtime && effectiveType === "api_key"
|
|
415
|
+
: source === "config"
|
|
416
|
+
? config && effectiveType === "api_key" && !runtime
|
|
417
|
+
: env && effectiveType === "api_key" && !runtime && !config;
|
|
418
|
+
const id = sourceId(provider, source);
|
|
419
|
+
rows.push({
|
|
420
|
+
id,
|
|
421
|
+
provider: safeProvider(provider),
|
|
422
|
+
credentialKind: "api_key",
|
|
423
|
+
source,
|
|
424
|
+
sourceLabel: sourceLabel(source),
|
|
425
|
+
identityLabel: null,
|
|
426
|
+
disabled: false,
|
|
427
|
+
disabledCause: null,
|
|
428
|
+
health: sourceHealth(authStorage, provider, source as SyntheticAccountSource),
|
|
429
|
+
capabilities: {
|
|
430
|
+
canCheck: true,
|
|
431
|
+
canPin: false,
|
|
432
|
+
canRemove: false,
|
|
433
|
+
hasCachedUsage: false,
|
|
434
|
+
},
|
|
435
|
+
routing: {
|
|
436
|
+
active: false,
|
|
437
|
+
selected,
|
|
438
|
+
marker: selected ? "selected" : "available",
|
|
439
|
+
},
|
|
440
|
+
});
|
|
441
|
+
};
|
|
442
|
+
|
|
443
|
+
// Keep synthetic rows even when a stored row exists: they represent
|
|
444
|
+
// explicit sources that can shadow stored credentials.
|
|
445
|
+
if (runtime) add("runtime");
|
|
446
|
+
if (config) add("config");
|
|
447
|
+
if (env) add("env");
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/** Build a redacted, cache-only account snapshot. This function never probes. */
|
|
452
|
+
export function buildAccountInventorySnapshot(input: AccountInventoryInput): AccountInventorySnapshot {
|
|
453
|
+
const nowMs = input.nowMs ?? Date.now();
|
|
454
|
+
const inventory = input.authStorage.listCredentialInventory();
|
|
455
|
+
const rows: AccountInventoryRow[] = [];
|
|
456
|
+
addStoredRows(rows, input.authStorage, inventory, input.sessionId);
|
|
457
|
+
addSyntheticRows(rows, input.authStorage, providerSet(input, inventory), input.sessionId);
|
|
458
|
+
rows.sort((left, right) => left.id.localeCompare(right.id));
|
|
459
|
+
return { generatedAt: nowMs, generation: input.authStorage.getGeneration(), rows };
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/** Short alias used by command/report callers. */
|
|
463
|
+
export const buildAccountInventory = buildAccountInventorySnapshot;
|
|
464
|
+
|
|
465
|
+
function applyStoredCheck(
|
|
466
|
+
rows: AccountInventoryRow[],
|
|
467
|
+
authStorage: AuthStorage,
|
|
468
|
+
results: CredentialHealthResult[],
|
|
469
|
+
): AccountInventoryCheckResult[] {
|
|
470
|
+
const byId = new Map(rows.filter(row => row.credentialId !== undefined).map(row => [row.credentialId!, row]));
|
|
471
|
+
const checked: AccountInventoryCheckResult[] = [];
|
|
472
|
+
for (const result of results) {
|
|
473
|
+
const row = byId.get(result.id);
|
|
474
|
+
if (!row) continue;
|
|
475
|
+
row.health = {
|
|
476
|
+
status: result.ok === true ? "ok" : result.ok === false ? "failed" : "unverifiable",
|
|
477
|
+
reason: asSafeLabel(result.reason),
|
|
478
|
+
};
|
|
479
|
+
if (result.report) {
|
|
480
|
+
const cached =
|
|
481
|
+
row.credentialId === undefined
|
|
482
|
+
? undefined
|
|
483
|
+
: authStorage.getCachedUsageReport(row.provider as Provider, row.credentialId);
|
|
484
|
+
if (cached) {
|
|
485
|
+
row.usage = redactUsageCache(cached);
|
|
486
|
+
row.capabilities.hasCachedUsage = true;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
checked.push({
|
|
490
|
+
rowId: row.id,
|
|
491
|
+
provider: row.provider,
|
|
492
|
+
credentialId: row.credentialId,
|
|
493
|
+
ok: result.ok,
|
|
494
|
+
reason: asSafeLabel(result.reason) ?? undefined,
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
return checked;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
/**
|
|
501
|
+
* Run the explicit sequential checker and return a fresh redacted snapshot.
|
|
502
|
+
* AuthStorage.checkCredentials performs stored-row probes sequentially; the
|
|
503
|
+
* synthetic API-key probes below are also intentionally sequential.
|
|
504
|
+
*/
|
|
505
|
+
export async function checkAccountInventory(input: AccountInventoryInput): Promise<AccountInventorySnapshot> {
|
|
506
|
+
const fullSnapshot = buildAccountInventorySnapshot(input);
|
|
507
|
+
const rows = input.provider ? fullSnapshot.rows.filter(row => row.provider === input.provider) : fullSnapshot.rows;
|
|
508
|
+
const snapshot: AccountInventorySnapshot = { ...fullSnapshot, rows };
|
|
509
|
+
const authStorage = input.authStorage;
|
|
510
|
+
applyStoredCheck(
|
|
511
|
+
rows,
|
|
512
|
+
authStorage,
|
|
513
|
+
await authStorage.checkCredentials({
|
|
514
|
+
provider: input.provider,
|
|
515
|
+
baseUrlResolver: provider => input.modelRegistry?.getProviderBaseUrl?.(provider),
|
|
516
|
+
}),
|
|
517
|
+
);
|
|
518
|
+
const syntheticRows = rows.filter(row => row.source !== "stored");
|
|
519
|
+
for (const row of syntheticRows) {
|
|
520
|
+
let key: string | undefined;
|
|
521
|
+
if (row.source === "env") key = getEnvApiKey(row.provider);
|
|
522
|
+
else if (row.source === "runtime" && authStorage.hasRuntimeApiKey(row.provider))
|
|
523
|
+
key = await authStorage.peekApiKey(row.provider);
|
|
524
|
+
else if (
|
|
525
|
+
row.source === "config" &&
|
|
526
|
+
authStorage.hasConfigApiKey(row.provider) &&
|
|
527
|
+
!authStorage.hasRuntimeApiKey(row.provider)
|
|
528
|
+
) {
|
|
529
|
+
key = await authStorage.peekApiKey(row.provider);
|
|
530
|
+
}
|
|
531
|
+
const result = key
|
|
532
|
+
? await authStorage.checkApiKeyCredential(row.provider as Provider, key, {
|
|
533
|
+
baseUrl: input.modelRegistry?.getProviderBaseUrl?.(row.provider),
|
|
534
|
+
})
|
|
535
|
+
: { provider: row.provider, type: "api_key" as const, ok: null, reason: "API-key source is unavailable" };
|
|
536
|
+
row.health = {
|
|
537
|
+
status: result.ok === true ? "ok" : result.ok === false ? "failed" : "unverifiable",
|
|
538
|
+
reason: asSafeLabel(result.reason),
|
|
539
|
+
};
|
|
540
|
+
recordSourceHealth(authStorage, row.provider, row.source as SyntheticAccountSource, result.ok, result.reason);
|
|
541
|
+
if (result.report) {
|
|
542
|
+
row.usage = {
|
|
543
|
+
report: redactUsageReport(result.report),
|
|
544
|
+
fetchedAt: finiteNumber(result.report.fetchedAt) ?? 0,
|
|
545
|
+
freshUntil: Date.now() + 15 * 60_000,
|
|
546
|
+
retainUntil: Date.now() + 24 * 60 * 60_000,
|
|
547
|
+
freshness: "fresh",
|
|
548
|
+
};
|
|
549
|
+
row.capabilities.hasCachedUsage = true;
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
return snapshot;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
export const checkAccountInventorySnapshot = checkAccountInventory;
|
|
556
|
+
|
|
557
|
+
function selectorMatchesRemovedRow(
|
|
558
|
+
selector: string,
|
|
559
|
+
provider: string,
|
|
560
|
+
inventory: readonly CredentialInventoryRecord[],
|
|
561
|
+
removedIds: ReadonlySet<number>,
|
|
562
|
+
): boolean {
|
|
563
|
+
const parsed = parsePersistedCredentialSelector(selector);
|
|
564
|
+
if (!parsed) return false;
|
|
565
|
+
if (parsed.kind === "id") return removedIds.has(Number(parsed.value));
|
|
566
|
+
return inventory.some(
|
|
567
|
+
row =>
|
|
568
|
+
row.provider === provider &&
|
|
569
|
+
removedIds.has(row.id) &&
|
|
570
|
+
(parsed.kind === "email"
|
|
571
|
+
? row.email?.trim().toLowerCase() === parsed.value.trim().toLowerCase()
|
|
572
|
+
: parsed.kind === "account"
|
|
573
|
+
? row.accountId === parsed.value
|
|
574
|
+
: row.projectId === parsed.value),
|
|
575
|
+
);
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
/** Clear a global persistent pin only after its selected credential was removed. */
|
|
579
|
+
export async function clearPersistentPinForRemovedRows(
|
|
580
|
+
settings: Pick<Settings, "commitAtomicBatchWithCurrent">,
|
|
581
|
+
provider: string,
|
|
582
|
+
inventory: readonly CredentialInventoryRecord[],
|
|
583
|
+
removedIds: readonly number[],
|
|
584
|
+
): Promise<boolean> {
|
|
585
|
+
const removed = new Set(removedIds);
|
|
586
|
+
if (removed.size === 0) return false;
|
|
587
|
+
let cleared = false;
|
|
588
|
+
await settings.commitAtomicBatchWithCurrent(current => {
|
|
589
|
+
const auth = asRecord((current as RawSettings).auth);
|
|
590
|
+
const pins = asRecord(auth?.credentialPins);
|
|
591
|
+
const selector = pins?.[provider];
|
|
592
|
+
if (typeof selector !== "string" || !selectorMatchesRemovedRow(selector, provider, inventory, removed)) return [];
|
|
593
|
+
const nextPins = { ...pins };
|
|
594
|
+
delete nextPins[provider];
|
|
595
|
+
cleared = true;
|
|
596
|
+
const patches: SettingsAtomicPatch[] = [{ path: "auth.credentialPins", op: "set", value: nextPins }];
|
|
597
|
+
if (!Object.values(nextPins).some(value => typeof value === "string" && value.startsWith("id:"))) {
|
|
598
|
+
patches.push({ path: "auth.credentialPinStoreIdentity", op: "unset" });
|
|
599
|
+
}
|
|
600
|
+
return patches;
|
|
601
|
+
});
|
|
602
|
+
return cleared;
|
|
603
|
+
}
|