open-multi-agent-kit 0.95.2 → 0.96.1
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 +60 -0
- package/README.md +37 -4
- package/dist/approvals/approval-receipt-store.d.ts.map +1 -1
- package/dist/approvals/approval-receipt-store.js +25 -0
- package/dist/approvals/approval-receipt-store.js.map +1 -1
- package/dist/commands/doctor-provider.d.ts.map +1 -1
- package/dist/commands/doctor-provider.js +15 -20
- package/dist/commands/doctor-provider.js.map +1 -1
- package/dist/commands/sdk-session-cli.d.ts +24 -0
- package/dist/commands/sdk-session-cli.d.ts.map +1 -0
- package/dist/commands/sdk-session-cli.js +225 -0
- package/dist/commands/sdk-session-cli.js.map +1 -0
- package/dist/core/advisory-judge-model.d.ts +18 -0
- package/dist/core/advisory-judge-model.d.ts.map +1 -0
- package/dist/core/advisory-judge-model.js +168 -0
- package/dist/core/advisory-judge-model.js.map +1 -0
- package/dist/core/advisory-judge-response.d.ts +8 -0
- package/dist/core/advisory-judge-response.d.ts.map +1 -0
- package/dist/core/advisory-judge-response.js +61 -0
- package/dist/core/advisory-judge-response.js.map +1 -0
- package/dist/core/advisory-judge-types.d.ts +53 -0
- package/dist/core/advisory-judge-types.d.ts.map +1 -0
- package/dist/core/advisory-judge-types.js +2 -0
- package/dist/core/advisory-judge-types.js.map +1 -0
- package/dist/core/advisory-judge.d.ts +8 -0
- package/dist/core/advisory-judge.d.ts.map +1 -0
- package/dist/core/advisory-judge.js +178 -0
- package/dist/core/advisory-judge.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 +6 -3
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +141 -184
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +28 -4
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/compaction-gate.d.ts +28 -0
- package/dist/core/compaction-gate.d.ts.map +1 -0
- package/dist/core/compaction-gate.js +34 -0
- package/dist/core/compaction-gate.js.map +1 -0
- package/dist/core/context-budget-system-prompt-items.d.ts.map +1 -1
- package/dist/core/context-budget-system-prompt-items.js +5 -3
- package/dist/core/context-budget-system-prompt-items.js.map +1 -1
- package/dist/core/domain-loadouts.d.ts.map +1 -1
- package/dist/core/domain-loadouts.js +2 -2
- package/dist/core/domain-loadouts.js.map +1 -1
- package/dist/core/durable-goal-checkpoint.d.ts +6 -0
- package/dist/core/durable-goal-checkpoint.d.ts.map +1 -0
- package/dist/core/durable-goal-checkpoint.js +195 -0
- package/dist/core/durable-goal-checkpoint.js.map +1 -0
- package/dist/core/durable-goal-parse.d.ts +3 -0
- package/dist/core/durable-goal-parse.d.ts.map +1 -0
- package/dist/core/durable-goal-parse.js +86 -0
- package/dist/core/durable-goal-parse.js.map +1 -0
- package/dist/core/durable-goal-reducer.d.ts +3 -0
- package/dist/core/durable-goal-reducer.d.ts.map +1 -0
- package/dist/core/durable-goal-reducer.js +175 -0
- package/dist/core/durable-goal-reducer.js.map +1 -0
- package/dist/core/durable-goal-store.d.ts +19 -0
- package/dist/core/durable-goal-store.d.ts.map +1 -0
- package/dist/core/durable-goal-store.js +126 -0
- package/dist/core/durable-goal-store.js.map +1 -0
- package/dist/core/durable-goal.d.ts +92 -0
- package/dist/core/durable-goal.d.ts.map +1 -0
- package/dist/core/durable-goal.js +62 -0
- package/dist/core/durable-goal.js.map +1 -0
- package/dist/core/extensions/builtin/goal-controller.d.ts +3 -0
- package/dist/core/extensions/builtin/goal-controller.d.ts.map +1 -0
- package/dist/core/extensions/builtin/goal-controller.js +125 -0
- package/dist/core/extensions/builtin/goal-controller.js.map +1 -0
- package/dist/core/extensions/builtin/identical-loop.d.ts +3 -0
- package/dist/core/extensions/builtin/identical-loop.d.ts.map +1 -0
- package/dist/core/extensions/builtin/identical-loop.js +31 -0
- package/dist/core/extensions/builtin/identical-loop.js.map +1 -0
- package/dist/core/extensions/builtin/prompt-preset.d.ts +3 -0
- package/dist/core/extensions/builtin/prompt-preset.d.ts.map +1 -0
- package/dist/core/extensions/builtin/prompt-preset.js +13 -0
- package/dist/core/extensions/builtin/prompt-preset.js.map +1 -0
- package/dist/core/extensions/builtin/tool-pair-repair.d.ts +3 -0
- package/dist/core/extensions/builtin/tool-pair-repair.d.ts.map +1 -0
- package/dist/core/extensions/builtin/tool-pair-repair.js +12 -0
- package/dist/core/extensions/builtin/tool-pair-repair.js.map +1 -0
- package/dist/core/extensions/types.d.ts +6 -2
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/goal-continuation.d.ts +13 -0
- package/dist/core/goal-continuation.d.ts.map +1 -0
- package/dist/core/goal-continuation.js +10 -0
- package/dist/core/goal-continuation.js.map +1 -0
- package/dist/core/grok-harness.d.ts +1 -1
- package/dist/core/grok-harness.d.ts.map +1 -1
- package/dist/core/grok-harness.js +1 -1
- package/dist/core/grok-harness.js.map +1 -1
- package/dist/core/grok-playbook.d.ts +1 -1
- package/dist/core/grok-playbook.d.ts.map +1 -1
- package/dist/core/grok-playbook.js +1 -1
- package/dist/core/grok-playbook.js.map +1 -1
- package/dist/core/identical-loop.d.ts +15 -0
- package/dist/core/identical-loop.d.ts.map +1 -0
- package/dist/core/identical-loop.js +34 -0
- package/dist/core/identical-loop.js.map +1 -0
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +1 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/model-prompt-policy.d.ts +11 -0
- package/dist/core/model-prompt-policy.d.ts.map +1 -0
- package/dist/core/model-prompt-policy.js +17 -0
- package/dist/core/model-prompt-policy.js.map +1 -0
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +16 -4
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +2 -2
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/prompt-budget.d.ts +21 -0
- package/dist/core/prompt-budget.d.ts.map +1 -0
- package/dist/core/prompt-budget.js +51 -0
- package/dist/core/prompt-budget.js.map +1 -0
- package/dist/core/prompt-cache.d.ts +14 -0
- package/dist/core/prompt-cache.d.ts.map +1 -0
- package/dist/core/prompt-cache.js +16 -0
- package/dist/core/prompt-cache.js.map +1 -0
- package/dist/core/prompt-preset.d.ts +8 -0
- package/dist/core/prompt-preset.d.ts.map +1 -0
- package/dist/core/prompt-preset.js +56 -0
- package/dist/core/prompt-preset.js.map +1 -0
- package/dist/core/provider-resilience.d.ts +23 -0
- package/dist/core/provider-resilience.d.ts.map +1 -1
- package/dist/core/provider-resilience.js +34 -1
- package/dist/core/provider-resilience.js.map +1 -1
- package/dist/core/provider-retry.d.ts +29 -0
- package/dist/core/provider-retry.d.ts.map +1 -0
- package/dist/core/provider-retry.js +49 -0
- package/dist/core/provider-retry.js.map +1 -0
- package/dist/core/provider-usage.d.ts +2 -1
- package/dist/core/provider-usage.d.ts.map +1 -1
- package/dist/core/provider-usage.js +40 -6
- package/dist/core/provider-usage.js.map +1 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +32 -0
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/sandbox/backend.d.ts +12 -0
- package/dist/core/sandbox/backend.d.ts.map +1 -1
- package/dist/core/sandbox/backend.js +52 -42
- package/dist/core/sandbox/backend.js.map +1 -1
- package/dist/core/sandbox/policy.d.ts +2 -0
- package/dist/core/sandbox/policy.d.ts.map +1 -1
- package/dist/core/sandbox/policy.js +2 -1
- package/dist/core/sandbox/policy.js.map +1 -1
- package/dist/core/sdk.d.ts +2 -0
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +1 -0
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-system-prompt.d.ts +28 -0
- package/dist/core/session-system-prompt.d.ts.map +1 -0
- package/dist/core/session-system-prompt.js +37 -0
- package/dist/core/session-system-prompt.js.map +1 -0
- package/dist/core/strict-record.d.ts +2 -0
- package/dist/core/strict-record.d.ts.map +1 -0
- package/dist/core/strict-record.js +9 -0
- package/dist/core/strict-record.js.map +1 -0
- package/dist/core/subagent-orchestration.d.ts.map +1 -1
- package/dist/core/subagent-orchestration.js +4 -2
- package/dist/core/subagent-orchestration.js.map +1 -1
- package/dist/core/tool-pair-repair.d.ts +11 -0
- package/dist/core/tool-pair-repair.d.ts.map +1 -0
- package/dist/core/tool-pair-repair.js +38 -0
- package/dist/core/tool-pair-repair.js.map +1 -0
- package/dist/core/tools/artifact-spill.d.ts +13 -0
- package/dist/core/tools/artifact-spill.d.ts.map +1 -0
- package/dist/core/tools/artifact-spill.js +26 -0
- package/dist/core/tools/artifact-spill.js.map +1 -0
- package/dist/core/tools/bash.d.ts +7 -4
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +8 -7
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/diagnostics.d.ts.map +1 -1
- package/dist/core/tools/diagnostics.js +8 -2
- package/dist/core/tools/diagnostics.js.map +1 -1
- package/dist/core/tools/index.d.ts +1 -1
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/read.d.ts +1 -0
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +10 -1
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
- package/dist/core/tools/tool-definition-wrapper.js +2 -0
- package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
- package/dist/guardrails/evidence-protocol.d.ts +10 -0
- package/dist/guardrails/evidence-protocol.d.ts.map +1 -0
- package/dist/guardrails/evidence-protocol.js +34 -0
- package/dist/guardrails/evidence-protocol.js.map +1 -0
- package/dist/guardrails/evidence-system.d.ts +3 -1
- package/dist/guardrails/evidence-system.d.ts.map +1 -1
- package/dist/guardrails/evidence-system.js +22 -14
- package/dist/guardrails/evidence-system.js.map +1 -1
- package/dist/guardrails/replay-ledger-lock-owner.d.ts.map +1 -1
- package/dist/guardrails/replay-ledger-lock-owner.js +3 -1
- package/dist/guardrails/replay-ledger-lock-owner.js.map +1 -1
- package/dist/guardrails/replay-payload-hash.d.ts +6 -0
- package/dist/guardrails/replay-payload-hash.d.ts.map +1 -0
- package/dist/guardrails/replay-payload-hash.js +24 -0
- package/dist/guardrails/replay-payload-hash.js.map +1 -0
- package/dist/index.d.ts +20 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +8 -0
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +14 -3
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/types/evidence.d.ts +11 -3
- package/dist/types/evidence.d.ts.map +1 -1
- package/dist/types/evidence.js.map +1 -1
- package/docs/adaptorch-preview-spec.md +1 -1
- package/docs/adaptorch-preview.md +2 -2
- package/docs/book-to-skill.md +79 -0
- package/docs/compaction.md +10 -0
- package/docs/containerization.md +9 -0
- package/docs/docs.json +18 -2
- package/docs/environment-variables.md +11 -4
- package/docs/extensions.md +14 -1
- package/docs/grok-harness.md +35 -12
- package/docs/index.md +9 -5
- package/docs/loadout-domains/grok-harness.md +2 -2
- package/docs/models.md +21 -8
- package/docs/provider-resilience.md +42 -55
- package/docs/providers.md +13 -4
- package/docs/run-protocol.md +104 -0
- package/docs/sdk.md +111 -5
- package/docs/security.md +22 -32
- package/docs/sessions.md +20 -0
- package/docs/settings.md +2 -0
- package/docs/skills.md +9 -1
- package/docs/usage.md +38 -16
- 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 +6 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +37 -15
- package/package.json +8 -5
- package/dist/core/context-budget-compressors.d.ts +0 -50
- package/dist/core/context-budget-compressors.d.ts.map +0 -1
- package/dist/core/context-budget-compressors.js +0 -166
- package/dist/core/context-budget-compressors.js.map +0 -1
- package/dist/core/extensions/loader.js.bak-sharedjiti-20260812-111246 +0 -553
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-storage.d.ts","sourceRoot":"","sources":["../../src/core/auth-storage.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Credential storage for API keys and OAuth tokens.\n * Handles loading, saving, and refreshing credentials from auth.json.\n *\n * Uses file locking to prevent race conditions when multiple OMK instances\n * try to refresh tokens simultaneously.\n */\n\nimport { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\nimport {\n\tfindEnvKeys,\n\tgetEnvApiKey,\n\ttype OAuthCredentials,\n\ttype OAuthLoginCallbacks,\n\ttype OAuthProviderId,\n} from \"omk-ai\";\nimport { getOAuthApiKey, getOAuthProvider, getOAuthProviders } from \"omk-ai/oauth\";\nimport { dirname, join } from \"path\";\nimport lockfile from \"proper-lockfile\";\nimport { getAgentDir } from \"../config.ts\";\nimport { stripAnsi } from \"../utils/ansi.ts\";\nimport { normalizePath } from \"../utils/paths.ts\";\nimport { resolveConfigValue } from \"./resolve-config-value.ts\";\n\nexport type ApiKeyCredential = {\n\ttype: \"api_key\";\n\tkey: string;\n};\n\nexport type OAuthCredential = {\n\ttype: \"oauth\";\n\t/** Complete account list when more than one subscription account is configured. */\n\taccounts?: OAuthCredentials[];\n\t/** Index of the account explicitly selected for this provider. */\n\tactiveAccount?: number;\n\t/** Legacy cursor accepted when migrating older auth.json files. */\n\tnextAccount?: number;\n} & OAuthCredentials;\n\nexport interface OAuthAccountSummary {\n\tindex: number;\n\tlabel: string;\n\tselected: boolean;\n}\n\nexport type AuthCredential = ApiKeyCredential | OAuthCredential;\n\nexport type AuthStorageData = Record<string, AuthCredential>;\n\nconst OAUTH_ACCOUNT_ID_FIELDS = [\"accountId\", \"email\", \"userId\", \"username\"] as const;\nconst OAUTH_ACCOUNT_LABEL_FIELDS = [\"email\", \"username\"] as const;\nconst OAUTH_ACCOUNT_LABEL_MAX_LENGTH = 96;\nconst UNSAFE_ACCOUNT_LABEL_PATTERN =\n\t/[\\u0000-\\u0008\\u000b\\u000c\\u000e-\\u001f\\u007f-\\u009f\\u200b-\\u200f\\u202a-\\u202e\\u2060-\\u206f\\ufeff]/g;\n\nfunction sanitizeOAuthAccountLabel(value: string): string | undefined {\n\tconst sanitized = stripAnsi(value)\n\t\t.replace(/[\\t\\r\\n]+/g, \" \")\n\t\t.replace(UNSAFE_ACCOUNT_LABEL_PATTERN, \"\")\n\t\t.replace(/\\s+/g, \" \")\n\t\t.trim()\n\t\t.slice(0, OAUTH_ACCOUNT_LABEL_MAX_LENGTH);\n\treturn sanitized || undefined;\n}\n\nfunction stripOAuthStorageMetadata(credential: OAuthCredential): OAuthCredentials {\n\tconst {\n\t\ttype: _type,\n\t\taccounts: _accounts,\n\t\tactiveAccount: _activeAccount,\n\t\tnextAccount: _nextAccount,\n\t\t...credentials\n\t} = credential;\n\treturn credentials;\n}\n\nfunction getOAuthAccounts(credential: OAuthCredential): OAuthCredentials[] {\n\tif (Array.isArray(credential.accounts) && credential.accounts.length > 0) {\n\t\treturn credential.accounts;\n\t}\n\treturn [stripOAuthStorageMetadata(credential)];\n}\n\nfunction normalizeOAuthAccountIndex(index: unknown, accountCount: number): number {\n\tif (accountCount <= 0 || typeof index !== \"number\" || !Number.isInteger(index)) {\n\t\treturn 0;\n\t}\n\treturn ((index % accountCount) + accountCount) % accountCount;\n}\n\nfunction getSelectedOAuthAccountIndex(credential: OAuthCredential, accountCount: number): number {\n\treturn normalizeOAuthAccountIndex(credential.activeAccount ?? credential.nextAccount, accountCount);\n}\n\nfunction createOAuthCredential(accounts: OAuthCredentials[], activeAccount = 0): OAuthCredential {\n\tconst selectedIndex = normalizeOAuthAccountIndex(activeAccount, accounts.length);\n\tconst selected = accounts[selectedIndex];\n\tif (!selected) {\n\t\tthrow new Error(\"OAuth credential must contain at least one account\");\n\t}\n\tif (accounts.length === 1) {\n\t\treturn { ...selected, type: \"oauth\" };\n\t}\n\treturn {\n\t\t...selected,\n\t\ttype: \"oauth\",\n\t\taccounts,\n\t\tactiveAccount: selectedIndex,\n\t};\n}\n\nfunction getOAuthAccountIdentity(credentials: OAuthCredentials): string | undefined {\n\tconst accountId = credentials.accountId;\n\tconst orgId = credentials.orgId;\n\tif (typeof accountId === \"string\" && accountId.trim() && typeof orgId === \"string\" && orgId.trim()) {\n\t\treturn `accountId:${accountId.trim().toLowerCase()}:orgId:${orgId.trim().toLowerCase()}`;\n\t}\n\tfor (const field of OAUTH_ACCOUNT_ID_FIELDS) {\n\t\tconst value = credentials[field];\n\t\tif (typeof value === \"string\" && value.trim()) {\n\t\t\treturn `${field}:${value.trim().toLowerCase()}`;\n\t\t}\n\t}\n\treturn undefined;\n}\n\nfunction getOAuthAccountDisplayLabel(providerId: string, credentials: OAuthCredentials): string | undefined {\n\tfor (const field of OAUTH_ACCOUNT_LABEL_FIELDS) {\n\t\tconst value = credentials[field];\n\t\tif (typeof value === \"string\" && value.trim()) {\n\t\t\tconst label = sanitizeOAuthAccountLabel(value);\n\t\t\tif (!label) continue;\n\t\t\tconst orgName =\n\t\t\t\ttypeof credentials.orgName === \"string\" ? sanitizeOAuthAccountLabel(credentials.orgName) : undefined;\n\t\t\treturn sanitizeOAuthAccountLabel(orgName ? `${label} (${orgName})` : label);\n\t\t}\n\t}\n\ttry {\n\t\tconst label = getOAuthProvider(providerId)?.getAccountLabel?.(credentials);\n\t\treturn typeof label === \"string\" ? sanitizeOAuthAccountLabel(label) : undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction findMatchingOAuthAccount(accounts: OAuthCredentials[], credentials: OAuthCredentials): number {\n\tconst identity = getOAuthAccountIdentity(credentials);\n\tif (identity) {\n\t\tconst exactMatch = accounts.findIndex((account) => getOAuthAccountIdentity(account) === identity);\n\t\tif (exactMatch >= 0) return exactMatch;\n\t}\n\n\t// Let newly enriched credentials update older entries that predate email/org metadata.\n\tfor (const field of OAUTH_ACCOUNT_ID_FIELDS) {\n\t\tconst value = credentials[field];\n\t\tif (typeof value !== \"string\" || !value.trim()) continue;\n\t\tconst normalizedValue = value.trim().toLowerCase();\n\t\tconst orgId = typeof credentials.orgId === \"string\" ? credentials.orgId.trim().toLowerCase() : \"\";\n\t\tconst compatibleMatch = accounts.findIndex((account) => {\n\t\t\tconst existingValue = account[field];\n\t\t\tif (typeof existingValue !== \"string\" || existingValue.trim().toLowerCase() !== normalizedValue) return false;\n\t\t\tconst existingOrgId = typeof account.orgId === \"string\" ? account.orgId.trim().toLowerCase() : \"\";\n\t\t\treturn !orgId || !existingOrgId || orgId === existingOrgId;\n\t\t});\n\t\tif (compatibleMatch >= 0) return compatibleMatch;\n\t}\n\n\treturn accounts.findIndex((account) => account.refresh === credentials.refresh);\n}\n\nexport type AuthStatus = {\n\tconfigured: boolean;\n\tsource?: \"stored\" | \"runtime\" | \"environment\" | \"fallback\" | \"models_json_key\" | \"models_json_command\";\n\tlabel?: string;\n};\n\ntype LockResult<T> = {\n\tresult: T;\n\tnext?: string;\n};\n\nconst AUTH_FILE_WRITE_OPTIONS = { encoding: \"utf-8\", mode: 0o600 } as const;\n\nexport interface AuthStorageBackend {\n\twithLock<T>(fn: (current: string | undefined) => LockResult<T>): T;\n\twithLockAsync<T>(fn: (current: string | undefined) => Promise<LockResult<T>>): Promise<T>;\n}\n\nexport class FileAuthStorageBackend implements AuthStorageBackend {\n\tprivate authPath: string;\n\n\tconstructor(authPath: string = join(getAgentDir(), \"auth.json\")) {\n\t\tthis.authPath = normalizePath(authPath);\n\t}\n\n\tprivate ensureParentDir(): void {\n\t\tconst dir = dirname(this.authPath);\n\t\tif (!existsSync(dir)) {\n\t\t\tmkdirSync(dir, { recursive: true, mode: 0o700 });\n\t\t}\n\t}\n\n\tprivate ensureFileExists(): void {\n\t\tif (!existsSync(this.authPath)) {\n\t\t\twriteFileSync(this.authPath, \"{}\", AUTH_FILE_WRITE_OPTIONS);\n\t\t\tchmodSync(this.authPath, 0o600);\n\t\t}\n\t}\n\n\tprivate acquireLockSyncWithRetry(path: string): () => void {\n\t\tconst maxAttempts = 10;\n\t\tconst delayMs = 20;\n\t\tlet lastError: unknown;\n\n\t\tfor (let attempt = 1; attempt <= maxAttempts; attempt++) {\n\t\t\ttry {\n\t\t\t\treturn lockfile.lockSync(path, { realpath: false });\n\t\t\t} catch (error) {\n\t\t\t\tconst code =\n\t\t\t\t\ttypeof error === \"object\" && error !== null && \"code\" in error\n\t\t\t\t\t\t? String((error as { code?: unknown }).code)\n\t\t\t\t\t\t: undefined;\n\t\t\t\tif (code !== \"ELOCKED\" || attempt === maxAttempts) {\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tlastError = error;\n\t\t\t\tconst start = Date.now();\n\t\t\t\twhile (Date.now() - start < delayMs) {\n\t\t\t\t\t// Sleep synchronously to avoid changing callers to async.\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthrow (lastError as Error) ?? new Error(\"Failed to acquire auth storage lock\");\n\t}\n\n\twithLock<T>(fn: (current: string | undefined) => LockResult<T>): T {\n\t\tthis.ensureParentDir();\n\t\tthis.ensureFileExists();\n\n\t\tlet release: (() => void) | undefined;\n\t\ttry {\n\t\t\trelease = this.acquireLockSyncWithRetry(this.authPath);\n\t\t\tconst current = existsSync(this.authPath) ? readFileSync(this.authPath, \"utf-8\") : undefined;\n\t\t\tconst { result, next } = fn(current);\n\t\t\tif (next !== undefined) {\n\t\t\t\twriteFileSync(this.authPath, next, AUTH_FILE_WRITE_OPTIONS);\n\t\t\t\tchmodSync(this.authPath, 0o600);\n\t\t\t}\n\t\t\treturn result;\n\t\t} finally {\n\t\t\tif (release) {\n\t\t\t\trelease();\n\t\t\t}\n\t\t}\n\t}\n\n\tasync withLockAsync<T>(fn: (current: string | undefined) => Promise<LockResult<T>>): Promise<T> {\n\t\tthis.ensureParentDir();\n\t\tthis.ensureFileExists();\n\n\t\tlet release: (() => Promise<void>) | undefined;\n\t\tlet lockCompromised = false;\n\t\tlet lockCompromisedError: Error | undefined;\n\t\tconst throwIfCompromised = () => {\n\t\t\tif (lockCompromised) {\n\t\t\t\tthrow lockCompromisedError ?? new Error(\"Auth storage lock was compromised\");\n\t\t\t}\n\t\t};\n\n\t\ttry {\n\t\t\trelease = await lockfile.lock(this.authPath, {\n\t\t\t\tretries: {\n\t\t\t\t\tretries: 10,\n\t\t\t\t\tfactor: 2,\n\t\t\t\t\tminTimeout: 100,\n\t\t\t\t\tmaxTimeout: 10000,\n\t\t\t\t\trandomize: true,\n\t\t\t\t},\n\t\t\t\tstale: 30000,\n\t\t\t\tonCompromised: (err) => {\n\t\t\t\t\tlockCompromised = true;\n\t\t\t\t\tlockCompromisedError = err;\n\t\t\t\t},\n\t\t\t});\n\n\t\t\tthrowIfCompromised();\n\t\t\tconst current = existsSync(this.authPath) ? readFileSync(this.authPath, \"utf-8\") : undefined;\n\t\t\tconst { result, next } = await fn(current);\n\t\t\tthrowIfCompromised();\n\t\t\tif (next !== undefined) {\n\t\t\t\twriteFileSync(this.authPath, next, AUTH_FILE_WRITE_OPTIONS);\n\t\t\t\tchmodSync(this.authPath, 0o600);\n\t\t\t}\n\t\t\tthrowIfCompromised();\n\t\t\treturn result;\n\t\t} finally {\n\t\t\tif (release) {\n\t\t\t\ttry {\n\t\t\t\t\tawait release();\n\t\t\t\t} catch {\n\t\t\t\t\t// Ignore unlock errors when lock is compromised.\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nexport class InMemoryAuthStorageBackend implements AuthStorageBackend {\n\tprivate value: string | undefined;\n\n\twithLock<T>(fn: (current: string | undefined) => LockResult<T>): T {\n\t\tconst { result, next } = fn(this.value);\n\t\tif (next !== undefined) {\n\t\t\tthis.value = next;\n\t\t}\n\t\treturn result;\n\t}\n\n\tasync withLockAsync<T>(fn: (current: string | undefined) => Promise<LockResult<T>>): Promise<T> {\n\t\tconst { result, next } = await fn(this.value);\n\t\tif (next !== undefined) {\n\t\t\tthis.value = next;\n\t\t}\n\t\treturn result;\n\t}\n}\n\n/**\n * Credential storage backed by a JSON file.\n */\nexport class AuthStorage {\n\tprivate data: AuthStorageData = {};\n\tprivate runtimeOverrides: Map<string, string> = new Map();\n\tprivate fallbackResolver?: (provider: string) => string | undefined;\n\tprivate loadError: Error | null = null;\n\tprivate errors: Error[] = [];\n\tprivate storage: AuthStorageBackend;\n\n\tprivate constructor(storage: AuthStorageBackend) {\n\t\tthis.storage = storage;\n\t\tthis.reload();\n\t}\n\n\tstatic create(authPath?: string): AuthStorage {\n\t\treturn new AuthStorage(new FileAuthStorageBackend(authPath ?? join(getAgentDir(), \"auth.json\")));\n\t}\n\n\tstatic fromStorage(storage: AuthStorageBackend): AuthStorage {\n\t\treturn new AuthStorage(storage);\n\t}\n\n\tstatic inMemory(data: AuthStorageData = {}): AuthStorage {\n\t\tconst storage = new InMemoryAuthStorageBackend();\n\t\tstorage.withLock(() => ({ result: undefined, next: JSON.stringify(data, null, 2) }));\n\t\treturn AuthStorage.fromStorage(storage);\n\t}\n\n\t/**\n\t * Set a runtime API key override (not persisted to disk).\n\t * Used for CLI --api-key flag.\n\t */\n\tsetRuntimeApiKey(provider: string, apiKey: string): void {\n\t\tthis.runtimeOverrides.set(provider, apiKey);\n\t}\n\n\t/**\n\t * Remove a runtime API key override.\n\t */\n\tremoveRuntimeApiKey(provider: string): void {\n\t\tthis.runtimeOverrides.delete(provider);\n\t}\n\n\t/**\n\t * Set a fallback resolver for API keys not found in auth.json or env vars.\n\t * Used for custom provider keys from models.json.\n\t */\n\tsetFallbackResolver(resolver: (provider: string) => string | undefined): void {\n\t\tthis.fallbackResolver = resolver;\n\t}\n\n\tprivate recordError(error: unknown): void {\n\t\tconst normalizedError = error instanceof Error ? error : new Error(String(error));\n\t\tthis.errors.push(normalizedError);\n\t}\n\n\tprivate parseStorageData(content: string | undefined): AuthStorageData {\n\t\tif (!content) {\n\t\t\treturn {};\n\t\t}\n\t\ttry {\n\t\t\treturn JSON.parse(content) as AuthStorageData;\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new Error(`Failed to parse auth storage: ${message}`);\n\t\t}\n\t}\n\n\t/**\n\t * Reload credentials from storage.\n\t */\n\treload(): void {\n\t\tlet content: string | undefined;\n\t\ttry {\n\t\t\tthis.storage.withLock((current) => {\n\t\t\t\tcontent = current;\n\t\t\t\treturn { result: undefined };\n\t\t\t});\n\t\t\tthis.data = this.parseStorageData(content);\n\t\t\tthis.loadError = null;\n\t\t} catch (error) {\n\t\t\tthis.loadError = error as Error;\n\t\t\tthis.recordError(error);\n\t\t}\n\t}\n\n\tprivate persistProviderChange(provider: string, credential: AuthCredential | undefined): void {\n\t\tif (this.loadError) {\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tthis.storage.withLock((current) => {\n\t\t\t\tconst currentData = this.parseStorageData(current);\n\t\t\t\tconst merged: AuthStorageData = { ...currentData };\n\t\t\t\tif (credential) {\n\t\t\t\t\tmerged[provider] = credential;\n\t\t\t\t} else {\n\t\t\t\t\tdelete merged[provider];\n\t\t\t\t}\n\t\t\t\treturn { result: undefined, next: JSON.stringify(merged, null, 2) };\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tthis.recordError(error);\n\t\t}\n\t}\n\n\t/**\n\t * Get credential for a provider.\n\t */\n\tget(provider: string): AuthCredential | undefined {\n\t\treturn this.data[provider] ?? undefined;\n\t}\n\n\t/**\n\t * Set credential for a provider.\n\t */\n\tset(provider: string, credential: AuthCredential): void {\n\t\tthis.data[provider] = credential;\n\t\tthis.persistProviderChange(provider, credential);\n\t}\n\n\t/**\n\t * Remove credential for a provider.\n\t */\n\tremove(provider: string): void {\n\t\tdelete this.data[provider];\n\t\tthis.persistProviderChange(provider, undefined);\n\t}\n\n\t/**\n\t * List all providers with credentials.\n\t */\n\tlist(): string[] {\n\t\treturn Object.keys(this.data);\n\t}\n\n\t/**\n\t * Check if credentials exist for a provider in auth.json.\n\t */\n\thas(provider: string): boolean {\n\t\treturn provider in this.data;\n\t}\n\n\t/**\n\t * Check if any form of auth is configured for a provider.\n\t * Unlike getApiKey(), this doesn't refresh OAuth tokens.\n\t */\n\thasAuth(provider: string): boolean {\n\t\tif (this.runtimeOverrides.has(provider)) return true;\n\t\tif (this.data[provider]) return true;\n\t\tif (getEnvApiKey(provider)) return true;\n\t\tif (this.fallbackResolver?.(provider)) return true;\n\t\treturn false;\n\t}\n\n\t/** Return the number of stored OAuth accounts for a provider. */\n\tgetOAuthAccountCount(provider: string): number {\n\t\tconst credential = this.data[provider];\n\t\treturn credential?.type === \"oauth\" ? getOAuthAccounts(credential).length : 0;\n\t}\n\n\t/** Return safe, human-readable labels for every stored OAuth account. */\n\tlistOAuthAccounts(provider: string): OAuthAccountSummary[] {\n\t\tconst credential = this.data[provider];\n\t\tif (credential?.type !== \"oauth\") return [];\n\t\tconst accounts = getOAuthAccounts(credential);\n\t\tconst selectedIndex = getSelectedOAuthAccountIndex(credential, accounts.length);\n\t\treturn accounts.map((account, index) => ({\n\t\t\tindex,\n\t\t\tlabel: getOAuthAccountDisplayLabel(provider, account) ?? `Account ${index + 1}`,\n\t\t\tselected: index === selectedIndex,\n\t\t}));\n\t}\n\n\t/** Return the human-readable label of the selected OAuth account. */\n\tgetOAuthAccountLabel(provider: string): string | undefined {\n\t\treturn this.listOAuthAccounts(provider).find((account) => account.selected)?.label;\n\t}\n\n\t/** Explicitly select and persist the OAuth account used by this provider. */\n\tselectOAuthAccount(provider: string, accountIndex: number): void {\n\t\tthis.storage.withLock((current) => {\n\t\t\tconst currentData = this.parseStorageData(current);\n\t\t\tconst credential = currentData[provider];\n\t\t\tif (credential?.type !== \"oauth\") {\n\t\t\t\tthrow new Error(`No OAuth accounts configured for ${provider}`);\n\t\t\t}\n\t\t\tconst accounts = [...getOAuthAccounts(credential)];\n\t\t\tif (!Number.isInteger(accountIndex) || accountIndex < 0 || accountIndex >= accounts.length) {\n\t\t\t\tthrow new Error(`Invalid OAuth account index ${accountIndex} for ${provider}`);\n\t\t\t}\n\t\t\tconst merged: AuthStorageData = {\n\t\t\t\t...currentData,\n\t\t\t\t[provider]: createOAuthCredential(accounts, accountIndex),\n\t\t\t};\n\t\t\tthis.data = merged;\n\t\t\tthis.loadError = null;\n\t\t\treturn { result: undefined, next: JSON.stringify(merged, null, 2) };\n\t\t});\n\t}\n\n\t/**\n\t * Return the explicitly selected OAuth credentials without refreshing tokens.\n\t * Used by provider model customization hooks.\n\t */\n\tgetOAuthCredentials(provider: string): OAuthCredentials | undefined {\n\t\tconst credential = this.data[provider];\n\t\tif (credential?.type !== \"oauth\") {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst accounts = getOAuthAccounts(credential);\n\t\treturn accounts[getSelectedOAuthAccountIndex(credential, accounts.length)];\n\t}\n\n\t/**\n\t * Return auth status without exposing credential values or refreshing tokens.\n\t */\n\tgetAuthStatus(provider: string): AuthStatus {\n\t\tif (this.data[provider]) {\n\t\t\treturn { configured: true, source: \"stored\" };\n\t\t}\n\n\t\tif (this.runtimeOverrides.has(provider)) {\n\t\t\treturn { configured: false, source: \"runtime\", label: \"--api-key\" };\n\t\t}\n\n\t\tconst envKeys = findEnvKeys(provider);\n\t\tif (envKeys?.[0]) {\n\t\t\treturn { configured: false, source: \"environment\", label: envKeys[0] };\n\t\t}\n\n\t\tif (this.fallbackResolver?.(provider)) {\n\t\t\treturn { configured: false, source: \"fallback\", label: \"custom provider config\" };\n\t\t}\n\n\t\treturn { configured: false };\n\t}\n\n\t/**\n\t * Get all credentials (for passing to getOAuthApiKey).\n\t */\n\tgetAll(): AuthStorageData {\n\t\treturn { ...this.data };\n\t}\n\n\tdrainErrors(): Error[] {\n\t\tconst drained = [...this.errors];\n\t\tthis.errors = [];\n\t\treturn drained;\n\t}\n\n\t/**\n\t * Login to an OAuth provider. Repeated logins append distinct accounts and\n\t * update an existing account when the provider exposes a stable identity.\n\t */\n\tasync login(providerId: OAuthProviderId, callbacks: OAuthLoginCallbacks): Promise<void> {\n\t\tconst provider = getOAuthProvider(providerId);\n\t\tif (!provider) {\n\t\t\tthrow new Error(`Unknown OAuth provider: ${providerId}`);\n\t\t}\n\n\t\tconst credentials = await provider.login(callbacks);\n\t\tif (this.loadError) {\n\t\t\tthis.data[providerId] = { type: \"oauth\", ...credentials };\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tthis.storage.withLock((current) => {\n\t\t\t\tconst currentData = this.parseStorageData(current);\n\t\t\t\tconst existing = currentData[providerId];\n\t\t\t\tlet credential: OAuthCredential;\n\n\t\t\t\tif (existing?.type === \"oauth\") {\n\t\t\t\t\tconst accounts = [...getOAuthAccounts(existing)];\n\t\t\t\t\tconst matchingIndex = findMatchingOAuthAccount(accounts, credentials);\n\t\t\t\t\tlet activeAccount: number;\n\t\t\t\t\tif (matchingIndex >= 0) {\n\t\t\t\t\t\taccounts[matchingIndex] = credentials;\n\t\t\t\t\t\tactiveAccount = matchingIndex;\n\t\t\t\t\t} else {\n\t\t\t\t\t\taccounts.push(credentials);\n\t\t\t\t\t\tactiveAccount = accounts.length - 1;\n\t\t\t\t\t}\n\t\t\t\t\tcredential = createOAuthCredential(accounts, activeAccount);\n\t\t\t\t} else {\n\t\t\t\t\tcredential = createOAuthCredential([credentials]);\n\t\t\t\t}\n\n\t\t\t\tconst merged: AuthStorageData = { ...currentData, [providerId]: credential };\n\t\t\t\tthis.data = merged;\n\t\t\t\tthis.loadError = null;\n\t\t\t\treturn { result: undefined, next: JSON.stringify(merged, null, 2) };\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tthis.recordError(error);\n\t\t}\n\t}\n\n\t/**\n\t * Logout from a provider.\n\t */\n\tlogout(provider: string): void {\n\t\tthis.remove(provider);\n\t}\n\n\t/** Resolve the explicitly selected account and refresh it under the storage lock. */\n\tprivate async resolveOAuthTokenWithLock(\n\t\tproviderId: OAuthProviderId,\n\t): Promise<{ apiKey: string; newCredentials: OAuthCredentials } | null> {\n\t\tconst provider = getOAuthProvider(providerId);\n\t\tif (!provider) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn this.storage.withLockAsync(async (current) => {\n\t\t\tconst currentData = this.parseStorageData(current);\n\t\t\tthis.data = currentData;\n\t\t\tthis.loadError = null;\n\n\t\t\tconst credential = currentData[providerId];\n\t\t\tif (credential?.type !== \"oauth\") {\n\t\t\t\treturn { result: null };\n\t\t\t}\n\n\t\t\tconst accounts = [...getOAuthAccounts(credential)];\n\t\t\tconst accountIndex = getSelectedOAuthAccountIndex(credential, accounts.length);\n\t\t\tconst account = accounts[accountIndex];\n\t\t\tif (!account) return { result: null };\n\n\t\t\tconst resolved =\n\t\t\t\tDate.now() < account.expires\n\t\t\t\t\t? { apiKey: provider.getApiKey(account), newCredentials: account }\n\t\t\t\t\t: await getOAuthApiKey(providerId, { [providerId]: account });\n\t\t\tif (!resolved) return { result: null };\n\n\t\t\tif (resolved.newCredentials === account) {\n\t\t\t\treturn { result: resolved };\n\t\t\t}\n\n\t\t\tconst newCredentials = { ...account, ...resolved.newCredentials };\n\t\t\taccounts[accountIndex] = newCredentials;\n\t\t\tconst merged: AuthStorageData = {\n\t\t\t\t...currentData,\n\t\t\t\t[providerId]: createOAuthCredential(accounts, accountIndex),\n\t\t\t};\n\t\t\tthis.data = merged;\n\t\t\treturn {\n\t\t\t\tresult: { ...resolved, newCredentials },\n\t\t\t\tnext: JSON.stringify(merged, null, 2),\n\t\t\t};\n\t\t});\n\t}\n\n\t/**\n\t * Get API key for a provider.\n\t * Priority:\n\t * 1. Runtime override (CLI --api-key)\n\t * 2. API key from auth.json\n\t * 3. OAuth token from auth.json (auto-refreshed with locking)\n\t * 4. Environment variable\n\t * 5. Fallback resolver (models.json custom providers)\n\t */\n\tasync getApiKey(providerId: string, options?: { includeFallback?: boolean }): Promise<string | undefined> {\n\t\t// Runtime override takes highest priority\n\t\tconst runtimeKey = this.runtimeOverrides.get(providerId);\n\t\tif (runtimeKey) {\n\t\t\treturn runtimeKey;\n\t\t}\n\n\t\tconst cred = this.data[providerId];\n\n\t\tif (cred?.type === \"api_key\") {\n\t\t\treturn resolveConfigValue(cred.key);\n\t\t}\n\n\t\tif (cred?.type === \"oauth\") {\n\t\t\ttry {\n\t\t\t\tconst result = await this.resolveOAuthTokenWithLock(providerId);\n\t\t\t\tif (result) {\n\t\t\t\t\treturn result.apiKey;\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tthis.recordError(error);\n\t\t\t\t// Credentials are preserved so a later request or /login can recover.\n\t\t\t\tthis.reload();\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t}\n\n\t\t// Fall back to environment variable\n\t\tconst envKey = getEnvApiKey(providerId);\n\t\tif (envKey) return envKey;\n\n\t\t// Fall back to custom resolver (e.g., models.json custom providers)\n\t\tif (options?.includeFallback !== false) {\n\t\t\treturn this.fallbackResolver?.(providerId) ?? undefined;\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Get all registered OAuth providers\n\t */\n\tgetOAuthProviders() {\n\t\treturn getOAuthProviders();\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"auth-storage.d.ts","sourceRoot":"","sources":["../../src/core/auth-storage.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Credential storage for API keys and OAuth tokens.\n * Handles loading, saving, and refreshing credentials from auth.json.\n *\n * Uses file locking to prevent race conditions when multiple OMK instances\n * try to refresh tokens simultaneously.\n */\n\nimport { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\nimport {\n\tfindEnvKeys,\n\tgetEnvApiKey,\n\ttype OAuthCredentials,\n\ttype OAuthLoginCallbacks,\n\ttype OAuthProviderId,\n} from \"omk-ai\";\nimport { getOAuthApiKey, getOAuthProvider, getOAuthProviders } from \"omk-ai/oauth\";\nimport { dirname, join } from \"path\";\nimport lockfile from \"proper-lockfile\";\nimport { getAgentDir } from \"../config.ts\";\nimport { stripAnsi } from \"../utils/ansi.ts\";\nimport { normalizePath } from \"../utils/paths.ts\";\nimport { resolveConfigValue } from \"./resolve-config-value.ts\";\n\nconst RETIRED_GROK_OAUTH_PROXY = \"grok-oauth-proxy\";\n\nfunction omitRetiredGrokOAuthProxy(data: AuthStorageData): AuthStorageData {\n\tif (!(RETIRED_GROK_OAUTH_PROXY in data)) return data;\n\tconst { [RETIRED_GROK_OAUTH_PROXY]: _retired, ...kept } = data;\n\treturn kept;\n}\n\nexport type ApiKeyCredential = {\n\ttype: \"api_key\";\n\tkey: string;\n};\n\nexport type OAuthCredential = {\n\ttype: \"oauth\";\n\t/** Complete account list when more than one subscription account is configured. */\n\taccounts?: OAuthCredentials[];\n\t/** Index of the account explicitly selected for this provider. */\n\tactiveAccount?: number;\n\t/** Legacy cursor accepted when migrating older auth.json files. */\n\tnextAccount?: number;\n} & OAuthCredentials;\n\nexport interface OAuthAccountSummary {\n\tindex: number;\n\tlabel: string;\n\tselected: boolean;\n}\n\nexport type AuthCredential = ApiKeyCredential | OAuthCredential;\n\nexport type AuthStorageData = Record<string, AuthCredential>;\n\nconst OAUTH_ACCOUNT_ID_FIELDS = [\"accountId\", \"email\", \"userId\", \"username\"] as const;\nconst OAUTH_ACCOUNT_LABEL_FIELDS = [\"email\", \"username\"] as const;\nconst OAUTH_ACCOUNT_LABEL_MAX_LENGTH = 96;\nconst UNSAFE_ACCOUNT_LABEL_PATTERN =\n\t/[\\u0000-\\u0008\\u000b\\u000c\\u000e-\\u001f\\u007f-\\u009f\\u200b-\\u200f\\u202a-\\u202e\\u2060-\\u206f\\ufeff]/g;\n\nfunction sanitizeOAuthAccountLabel(value: string): string | undefined {\n\tconst sanitized = stripAnsi(value)\n\t\t.replace(/[\\t\\r\\n]+/g, \" \")\n\t\t.replace(UNSAFE_ACCOUNT_LABEL_PATTERN, \"\")\n\t\t.replace(/\\s+/g, \" \")\n\t\t.trim()\n\t\t.slice(0, OAUTH_ACCOUNT_LABEL_MAX_LENGTH);\n\treturn sanitized || undefined;\n}\n\nfunction stripOAuthStorageMetadata(credential: OAuthCredential): OAuthCredentials {\n\tconst {\n\t\ttype: _type,\n\t\taccounts: _accounts,\n\t\tactiveAccount: _activeAccount,\n\t\tnextAccount: _nextAccount,\n\t\t...credentials\n\t} = credential;\n\treturn credentials;\n}\n\nfunction getOAuthAccounts(credential: OAuthCredential): OAuthCredentials[] {\n\tif (Array.isArray(credential.accounts) && credential.accounts.length > 0) {\n\t\treturn credential.accounts;\n\t}\n\treturn [stripOAuthStorageMetadata(credential)];\n}\n\nfunction normalizeOAuthAccountIndex(index: unknown, accountCount: number): number {\n\tif (accountCount <= 0 || typeof index !== \"number\" || !Number.isInteger(index)) {\n\t\treturn 0;\n\t}\n\treturn ((index % accountCount) + accountCount) % accountCount;\n}\n\nfunction getSelectedOAuthAccountIndex(credential: OAuthCredential, accountCount: number): number {\n\treturn normalizeOAuthAccountIndex(credential.activeAccount ?? credential.nextAccount, accountCount);\n}\n\nfunction createOAuthCredential(accounts: OAuthCredentials[], activeAccount = 0): OAuthCredential {\n\tconst selectedIndex = normalizeOAuthAccountIndex(activeAccount, accounts.length);\n\tconst selected = accounts[selectedIndex];\n\tif (!selected) {\n\t\tthrow new Error(\"OAuth credential must contain at least one account\");\n\t}\n\tif (accounts.length === 1) {\n\t\treturn { ...selected, type: \"oauth\" };\n\t}\n\treturn {\n\t\t...selected,\n\t\ttype: \"oauth\",\n\t\taccounts,\n\t\tactiveAccount: selectedIndex,\n\t};\n}\n\nfunction getOAuthAccountIdentity(credentials: OAuthCredentials): string | undefined {\n\tconst accountId = credentials.accountId;\n\tconst orgId = credentials.orgId;\n\tif (typeof accountId === \"string\" && accountId.trim() && typeof orgId === \"string\" && orgId.trim()) {\n\t\treturn `accountId:${accountId.trim().toLowerCase()}:orgId:${orgId.trim().toLowerCase()}`;\n\t}\n\tfor (const field of OAUTH_ACCOUNT_ID_FIELDS) {\n\t\tconst value = credentials[field];\n\t\tif (typeof value === \"string\" && value.trim()) {\n\t\t\treturn `${field}:${value.trim().toLowerCase()}`;\n\t\t}\n\t}\n\treturn undefined;\n}\n\nfunction getOAuthAccountDisplayLabel(providerId: string, credentials: OAuthCredentials): string | undefined {\n\tfor (const field of OAUTH_ACCOUNT_LABEL_FIELDS) {\n\t\tconst value = credentials[field];\n\t\tif (typeof value === \"string\" && value.trim()) {\n\t\t\tconst label = sanitizeOAuthAccountLabel(value);\n\t\t\tif (!label) continue;\n\t\t\tconst orgName =\n\t\t\t\ttypeof credentials.orgName === \"string\" ? sanitizeOAuthAccountLabel(credentials.orgName) : undefined;\n\t\t\treturn sanitizeOAuthAccountLabel(orgName ? `${label} (${orgName})` : label);\n\t\t}\n\t}\n\ttry {\n\t\tconst label = getOAuthProvider(providerId)?.getAccountLabel?.(credentials);\n\t\treturn typeof label === \"string\" ? sanitizeOAuthAccountLabel(label) : undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction findMatchingOAuthAccount(accounts: OAuthCredentials[], credentials: OAuthCredentials): number {\n\tconst identity = getOAuthAccountIdentity(credentials);\n\tif (identity) {\n\t\tconst exactMatch = accounts.findIndex((account) => getOAuthAccountIdentity(account) === identity);\n\t\tif (exactMatch >= 0) return exactMatch;\n\t}\n\n\t// Let newly enriched credentials update older entries that predate email/org metadata.\n\tfor (const field of OAUTH_ACCOUNT_ID_FIELDS) {\n\t\tconst value = credentials[field];\n\t\tif (typeof value !== \"string\" || !value.trim()) continue;\n\t\tconst normalizedValue = value.trim().toLowerCase();\n\t\tconst orgId = typeof credentials.orgId === \"string\" ? credentials.orgId.trim().toLowerCase() : \"\";\n\t\tconst compatibleMatch = accounts.findIndex((account) => {\n\t\t\tconst existingValue = account[field];\n\t\t\tif (typeof existingValue !== \"string\" || existingValue.trim().toLowerCase() !== normalizedValue) return false;\n\t\t\tconst existingOrgId = typeof account.orgId === \"string\" ? account.orgId.trim().toLowerCase() : \"\";\n\t\t\treturn !orgId || !existingOrgId || orgId === existingOrgId;\n\t\t});\n\t\tif (compatibleMatch >= 0) return compatibleMatch;\n\t}\n\n\treturn accounts.findIndex((account) => account.refresh === credentials.refresh);\n}\n\nexport type AuthStatus = {\n\tconfigured: boolean;\n\tsource?: \"stored\" | \"runtime\" | \"environment\" | \"fallback\" | \"models_json_key\" | \"models_json_command\";\n\tlabel?: string;\n};\n\ntype LockResult<T> = {\n\tresult: T;\n\tnext?: string;\n};\n\nconst AUTH_FILE_WRITE_OPTIONS = { encoding: \"utf-8\", mode: 0o600 } as const;\n\nexport interface AuthStorageBackend {\n\twithLock<T>(fn: (current: string | undefined) => LockResult<T>): T;\n\twithLockAsync<T>(fn: (current: string | undefined) => Promise<LockResult<T>>): Promise<T>;\n}\n\nexport class FileAuthStorageBackend implements AuthStorageBackend {\n\tprivate authPath: string;\n\n\tconstructor(authPath: string = join(getAgentDir(), \"auth.json\")) {\n\t\tthis.authPath = normalizePath(authPath);\n\t}\n\n\tprivate ensureParentDir(): void {\n\t\tconst dir = dirname(this.authPath);\n\t\tif (!existsSync(dir)) {\n\t\t\tmkdirSync(dir, { recursive: true, mode: 0o700 });\n\t\t}\n\t}\n\n\tprivate ensureFileExists(): void {\n\t\tif (!existsSync(this.authPath)) {\n\t\t\twriteFileSync(this.authPath, \"{}\", AUTH_FILE_WRITE_OPTIONS);\n\t\t\tchmodSync(this.authPath, 0o600);\n\t\t}\n\t}\n\n\tprivate acquireLockSyncWithRetry(path: string): () => void {\n\t\tconst maxAttempts = 10;\n\t\tconst delayMs = 20;\n\t\tlet lastError: unknown;\n\n\t\tfor (let attempt = 1; attempt <= maxAttempts; attempt++) {\n\t\t\ttry {\n\t\t\t\treturn lockfile.lockSync(path, { realpath: false });\n\t\t\t} catch (error) {\n\t\t\t\tconst code =\n\t\t\t\t\ttypeof error === \"object\" && error !== null && \"code\" in error\n\t\t\t\t\t\t? String((error as { code?: unknown }).code)\n\t\t\t\t\t\t: undefined;\n\t\t\t\tif (code !== \"ELOCKED\" || attempt === maxAttempts) {\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tlastError = error;\n\t\t\t\tconst start = Date.now();\n\t\t\t\twhile (Date.now() - start < delayMs) {\n\t\t\t\t\t// Sleep synchronously to avoid changing callers to async.\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthrow (lastError as Error) ?? new Error(\"Failed to acquire auth storage lock\");\n\t}\n\n\twithLock<T>(fn: (current: string | undefined) => LockResult<T>): T {\n\t\tthis.ensureParentDir();\n\t\tthis.ensureFileExists();\n\n\t\tlet release: (() => void) | undefined;\n\t\ttry {\n\t\t\trelease = this.acquireLockSyncWithRetry(this.authPath);\n\t\t\tconst current = existsSync(this.authPath) ? readFileSync(this.authPath, \"utf-8\") : undefined;\n\t\t\tconst { result, next } = fn(current);\n\t\t\tif (next !== undefined) {\n\t\t\t\twriteFileSync(this.authPath, next, AUTH_FILE_WRITE_OPTIONS);\n\t\t\t\tchmodSync(this.authPath, 0o600);\n\t\t\t}\n\t\t\treturn result;\n\t\t} finally {\n\t\t\tif (release) {\n\t\t\t\trelease();\n\t\t\t}\n\t\t}\n\t}\n\n\tasync withLockAsync<T>(fn: (current: string | undefined) => Promise<LockResult<T>>): Promise<T> {\n\t\tthis.ensureParentDir();\n\t\tthis.ensureFileExists();\n\n\t\tlet release: (() => Promise<void>) | undefined;\n\t\tlet lockCompromised = false;\n\t\tlet lockCompromisedError: Error | undefined;\n\t\tconst throwIfCompromised = () => {\n\t\t\tif (lockCompromised) {\n\t\t\t\tthrow lockCompromisedError ?? new Error(\"Auth storage lock was compromised\");\n\t\t\t}\n\t\t};\n\n\t\ttry {\n\t\t\trelease = await lockfile.lock(this.authPath, {\n\t\t\t\tretries: {\n\t\t\t\t\tretries: 10,\n\t\t\t\t\tfactor: 2,\n\t\t\t\t\tminTimeout: 100,\n\t\t\t\t\tmaxTimeout: 10000,\n\t\t\t\t\trandomize: true,\n\t\t\t\t},\n\t\t\t\tstale: 30000,\n\t\t\t\tonCompromised: (err) => {\n\t\t\t\t\tlockCompromised = true;\n\t\t\t\t\tlockCompromisedError = err;\n\t\t\t\t},\n\t\t\t});\n\n\t\t\tthrowIfCompromised();\n\t\t\tconst current = existsSync(this.authPath) ? readFileSync(this.authPath, \"utf-8\") : undefined;\n\t\t\tconst { result, next } = await fn(current);\n\t\t\tthrowIfCompromised();\n\t\t\tif (next !== undefined) {\n\t\t\t\twriteFileSync(this.authPath, next, AUTH_FILE_WRITE_OPTIONS);\n\t\t\t\tchmodSync(this.authPath, 0o600);\n\t\t\t}\n\t\t\tthrowIfCompromised();\n\t\t\treturn result;\n\t\t} finally {\n\t\t\tif (release) {\n\t\t\t\ttry {\n\t\t\t\t\tawait release();\n\t\t\t\t} catch {\n\t\t\t\t\t// Ignore unlock errors when lock is compromised.\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nexport class InMemoryAuthStorageBackend implements AuthStorageBackend {\n\tprivate value: string | undefined;\n\n\twithLock<T>(fn: (current: string | undefined) => LockResult<T>): T {\n\t\tconst { result, next } = fn(this.value);\n\t\tif (next !== undefined) {\n\t\t\tthis.value = next;\n\t\t}\n\t\treturn result;\n\t}\n\n\tasync withLockAsync<T>(fn: (current: string | undefined) => Promise<LockResult<T>>): Promise<T> {\n\t\tconst { result, next } = await fn(this.value);\n\t\tif (next !== undefined) {\n\t\t\tthis.value = next;\n\t\t}\n\t\treturn result;\n\t}\n}\n\n/**\n * Credential storage backed by a JSON file.\n */\nexport class AuthStorage {\n\tprivate data: AuthStorageData = {};\n\tprivate runtimeOverrides: Map<string, string> = new Map();\n\tprivate fallbackResolver?: (provider: string) => string | undefined;\n\tprivate loadError: Error | null = null;\n\tprivate errors: Error[] = [];\n\tprivate storage: AuthStorageBackend;\n\n\tprivate constructor(storage: AuthStorageBackend) {\n\t\tthis.storage = storage;\n\t\tthis.reload();\n\t}\n\n\tstatic create(authPath?: string): AuthStorage {\n\t\treturn new AuthStorage(new FileAuthStorageBackend(authPath ?? join(getAgentDir(), \"auth.json\")));\n\t}\n\n\tstatic fromStorage(storage: AuthStorageBackend): AuthStorage {\n\t\treturn new AuthStorage(storage);\n\t}\n\n\tstatic inMemory(data: AuthStorageData = {}): AuthStorage {\n\t\tconst storage = new InMemoryAuthStorageBackend();\n\t\tstorage.withLock(() => ({ result: undefined, next: JSON.stringify(data, null, 2) }));\n\t\treturn AuthStorage.fromStorage(storage);\n\t}\n\n\t/**\n\t * Set a runtime API key override (not persisted to disk).\n\t * Used for CLI --api-key flag.\n\t */\n\tsetRuntimeApiKey(provider: string, apiKey: string): void {\n\t\tthis.runtimeOverrides.set(provider, apiKey);\n\t}\n\n\t/**\n\t * Remove a runtime API key override.\n\t */\n\tremoveRuntimeApiKey(provider: string): void {\n\t\tthis.runtimeOverrides.delete(provider);\n\t}\n\n\t/**\n\t * Set a fallback resolver for API keys not found in auth.json or env vars.\n\t * Used for custom provider keys from models.json.\n\t */\n\tsetFallbackResolver(resolver: (provider: string) => string | undefined): void {\n\t\tthis.fallbackResolver = resolver;\n\t}\n\n\tprivate recordError(error: unknown): void {\n\t\tconst normalizedError = error instanceof Error ? error : new Error(String(error));\n\t\tthis.errors.push(normalizedError);\n\t}\n\n\tprivate parseStorageData(content: string | undefined): AuthStorageData {\n\t\tif (!content) {\n\t\t\treturn {};\n\t\t}\n\t\ttry {\n\t\t\treturn omitRetiredGrokOAuthProxy(JSON.parse(content) as AuthStorageData);\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new Error(`Failed to parse auth storage: ${message}`);\n\t\t}\n\t}\n\n\t/**\n\t * Reload credentials from storage.\n\t */\n\treload(): void {\n\t\tlet content: string | undefined;\n\t\ttry {\n\t\t\tthis.storage.withLock((current) => {\n\t\t\t\tcontent = current;\n\t\t\t\treturn { result: undefined };\n\t\t\t});\n\t\t\tthis.data = this.parseStorageData(content);\n\t\t\tthis.loadError = null;\n\t\t} catch (error) {\n\t\t\tthis.loadError = error as Error;\n\t\t\tthis.recordError(error);\n\t\t}\n\t}\n\n\tprivate persistProviderChange(provider: string, credential: AuthCredential | undefined): void {\n\t\tif (this.loadError) {\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tthis.storage.withLock((current) => {\n\t\t\t\tconst currentData = this.parseStorageData(current);\n\t\t\t\tconst merged: AuthStorageData = { ...currentData };\n\t\t\t\tif (provider === RETIRED_GROK_OAUTH_PROXY) {\n\t\t\t\t\tdelete merged[provider];\n\t\t\t\t} else if (credential) {\n\t\t\t\t\tmerged[provider] = credential;\n\t\t\t\t} else {\n\t\t\t\t\tdelete merged[provider];\n\t\t\t\t}\n\t\t\t\treturn { result: undefined, next: JSON.stringify(merged, null, 2) };\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tthis.recordError(error);\n\t\t}\n\t}\n\n\t/**\n\t * Get credential for a provider.\n\t */\n\tget(provider: string): AuthCredential | undefined {\n\t\tif (provider === RETIRED_GROK_OAUTH_PROXY) return undefined;\n\t\treturn this.data[provider] ?? undefined;\n\t}\n\n\t/**\n\t * Set credential for a provider.\n\t */\n\tset(provider: string, credential: AuthCredential): void {\n\t\tif (provider === RETIRED_GROK_OAUTH_PROXY) {\n\t\t\tdelete this.data[provider];\n\t\t\tthis.persistProviderChange(provider, undefined);\n\t\t\treturn;\n\t\t}\n\t\tthis.data[provider] = credential;\n\t\tthis.persistProviderChange(provider, credential);\n\t}\n\n\t/**\n\t * Remove credential for a provider.\n\t */\n\tremove(provider: string): void {\n\t\tdelete this.data[provider];\n\t\tthis.persistProviderChange(provider, undefined);\n\t}\n\n\t/**\n\t * List all providers with credentials.\n\t */\n\tlist(): string[] {\n\t\treturn Object.keys(this.data).filter((provider) => provider !== RETIRED_GROK_OAUTH_PROXY);\n\t}\n\n\t/**\n\t * Check if credentials exist for a provider in auth.json.\n\t */\n\thas(provider: string): boolean {\n\t\tif (provider === RETIRED_GROK_OAUTH_PROXY) return false;\n\t\treturn provider in this.data;\n\t}\n\n\t/**\n\t * Check if any form of auth is configured for a provider.\n\t * Unlike getApiKey(), this doesn't refresh OAuth tokens.\n\t */\n\thasAuth(provider: string): boolean {\n\t\tif (provider === RETIRED_GROK_OAUTH_PROXY) return false;\n\t\tif (this.runtimeOverrides.has(provider)) return true;\n\t\tif (this.data[provider]) return true;\n\t\tif (getEnvApiKey(provider)) return true;\n\t\tif (this.fallbackResolver?.(provider)) return true;\n\t\treturn false;\n\t}\n\n\t/** Return the number of stored OAuth accounts for a provider. */\n\tgetOAuthAccountCount(provider: string): number {\n\t\tconst credential = this.data[provider];\n\t\treturn credential?.type === \"oauth\" ? getOAuthAccounts(credential).length : 0;\n\t}\n\n\t/** Return safe, human-readable labels for every stored OAuth account. */\n\tlistOAuthAccounts(provider: string): OAuthAccountSummary[] {\n\t\tconst credential = this.data[provider];\n\t\tif (credential?.type !== \"oauth\") return [];\n\t\tconst accounts = getOAuthAccounts(credential);\n\t\tconst selectedIndex = getSelectedOAuthAccountIndex(credential, accounts.length);\n\t\treturn accounts.map((account, index) => ({\n\t\t\tindex,\n\t\t\tlabel: getOAuthAccountDisplayLabel(provider, account) ?? `Account ${index + 1}`,\n\t\t\tselected: index === selectedIndex,\n\t\t}));\n\t}\n\n\t/** Return the human-readable label of the selected OAuth account. */\n\tgetOAuthAccountLabel(provider: string): string | undefined {\n\t\treturn this.listOAuthAccounts(provider).find((account) => account.selected)?.label;\n\t}\n\n\t/** Explicitly select and persist the OAuth account used by this provider. */\n\tselectOAuthAccount(provider: string, accountIndex: number): void {\n\t\tthis.storage.withLock((current) => {\n\t\t\tconst currentData = this.parseStorageData(current);\n\t\t\tconst credential = currentData[provider];\n\t\t\tif (credential?.type !== \"oauth\") {\n\t\t\t\tthrow new Error(`No OAuth accounts configured for ${provider}`);\n\t\t\t}\n\t\t\tconst accounts = [...getOAuthAccounts(credential)];\n\t\t\tif (!Number.isInteger(accountIndex) || accountIndex < 0 || accountIndex >= accounts.length) {\n\t\t\t\tthrow new Error(`Invalid OAuth account index ${accountIndex} for ${provider}`);\n\t\t\t}\n\t\t\tconst merged: AuthStorageData = {\n\t\t\t\t...currentData,\n\t\t\t\t[provider]: createOAuthCredential(accounts, accountIndex),\n\t\t\t};\n\t\t\tthis.data = merged;\n\t\t\tthis.loadError = null;\n\t\t\treturn { result: undefined, next: JSON.stringify(merged, null, 2) };\n\t\t});\n\t}\n\n\t/**\n\t * Return the explicitly selected OAuth credentials without refreshing tokens.\n\t * Used by provider model customization hooks.\n\t */\n\tgetOAuthCredentials(provider: string): OAuthCredentials | undefined {\n\t\tconst credential = this.data[provider];\n\t\tif (credential?.type !== \"oauth\") {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst accounts = getOAuthAccounts(credential);\n\t\treturn accounts[getSelectedOAuthAccountIndex(credential, accounts.length)];\n\t}\n\n\t/**\n\t * Return auth status without exposing credential values or refreshing tokens.\n\t */\n\tgetAuthStatus(provider: string): AuthStatus {\n\t\tif (provider === RETIRED_GROK_OAUTH_PROXY) {\n\t\t\treturn { configured: false };\n\t\t}\n\t\tif (this.data[provider]) {\n\t\t\treturn { configured: true, source: \"stored\" };\n\t\t}\n\n\t\tif (this.runtimeOverrides.has(provider)) {\n\t\t\treturn { configured: false, source: \"runtime\", label: \"--api-key\" };\n\t\t}\n\n\t\tconst envKeys = findEnvKeys(provider);\n\t\tif (envKeys?.[0]) {\n\t\t\treturn { configured: false, source: \"environment\", label: envKeys[0] };\n\t\t}\n\n\t\tif (this.fallbackResolver?.(provider)) {\n\t\t\treturn { configured: false, source: \"fallback\", label: \"custom provider config\" };\n\t\t}\n\n\t\treturn { configured: false };\n\t}\n\n\t/**\n\t * Get all credentials (for passing to getOAuthApiKey).\n\t */\n\tgetAll(): AuthStorageData {\n\t\treturn omitRetiredGrokOAuthProxy({ ...this.data });\n\t}\n\n\tdrainErrors(): Error[] {\n\t\tconst drained = [...this.errors];\n\t\tthis.errors = [];\n\t\treturn drained;\n\t}\n\n\t/**\n\t * Login to an OAuth provider. Repeated logins append distinct accounts and\n\t * update an existing account when the provider exposes a stable identity.\n\t */\n\tasync login(providerId: OAuthProviderId, callbacks: OAuthLoginCallbacks): Promise<void> {\n\t\tconst provider = getOAuthProvider(providerId);\n\t\tif (!provider) {\n\t\t\tthrow new Error(`Unknown OAuth provider: ${providerId}`);\n\t\t}\n\n\t\tconst credentials = await provider.login(callbacks);\n\t\tif (this.loadError) {\n\t\t\tthis.data[providerId] = { type: \"oauth\", ...credentials };\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tthis.storage.withLock((current) => {\n\t\t\t\tconst currentData = this.parseStorageData(current);\n\t\t\t\tconst existing = currentData[providerId];\n\t\t\t\tlet credential: OAuthCredential;\n\n\t\t\t\tif (existing?.type === \"oauth\") {\n\t\t\t\t\tconst accounts = [...getOAuthAccounts(existing)];\n\t\t\t\t\tconst matchingIndex = findMatchingOAuthAccount(accounts, credentials);\n\t\t\t\t\tlet activeAccount: number;\n\t\t\t\t\tif (matchingIndex >= 0) {\n\t\t\t\t\t\taccounts[matchingIndex] = credentials;\n\t\t\t\t\t\tactiveAccount = matchingIndex;\n\t\t\t\t\t} else {\n\t\t\t\t\t\taccounts.push(credentials);\n\t\t\t\t\t\tactiveAccount = accounts.length - 1;\n\t\t\t\t\t}\n\t\t\t\t\tcredential = createOAuthCredential(accounts, activeAccount);\n\t\t\t\t} else {\n\t\t\t\t\tcredential = createOAuthCredential([credentials]);\n\t\t\t\t}\n\n\t\t\t\tconst merged: AuthStorageData = { ...currentData, [providerId]: credential };\n\t\t\t\tthis.data = merged;\n\t\t\t\tthis.loadError = null;\n\t\t\t\treturn { result: undefined, next: JSON.stringify(merged, null, 2) };\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tthis.recordError(error);\n\t\t}\n\t}\n\n\t/**\n\t * Logout from a provider.\n\t */\n\tlogout(provider: string): void {\n\t\tthis.remove(provider);\n\t}\n\n\t/** Resolve the explicitly selected account and refresh it under the storage lock. */\n\tprivate async resolveOAuthTokenWithLock(\n\t\tproviderId: OAuthProviderId,\n\t): Promise<{ apiKey: string; newCredentials: OAuthCredentials } | null> {\n\t\tconst provider = getOAuthProvider(providerId);\n\t\tif (!provider) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn this.storage.withLockAsync(async (current) => {\n\t\t\tconst currentData = this.parseStorageData(current);\n\t\t\tthis.data = currentData;\n\t\t\tthis.loadError = null;\n\n\t\t\tconst credential = currentData[providerId];\n\t\t\tif (credential?.type !== \"oauth\") {\n\t\t\t\treturn { result: null };\n\t\t\t}\n\n\t\t\tconst accounts = [...getOAuthAccounts(credential)];\n\t\t\tconst accountIndex = getSelectedOAuthAccountIndex(credential, accounts.length);\n\t\t\tconst account = accounts[accountIndex];\n\t\t\tif (!account) return { result: null };\n\n\t\t\tconst resolved =\n\t\t\t\tDate.now() < account.expires\n\t\t\t\t\t? { apiKey: provider.getApiKey(account), newCredentials: account }\n\t\t\t\t\t: await getOAuthApiKey(providerId, { [providerId]: account });\n\t\t\tif (!resolved) return { result: null };\n\n\t\t\tif (resolved.newCredentials === account) {\n\t\t\t\treturn { result: resolved };\n\t\t\t}\n\n\t\t\tconst newCredentials = { ...account, ...resolved.newCredentials };\n\t\t\taccounts[accountIndex] = newCredentials;\n\t\t\tconst merged: AuthStorageData = {\n\t\t\t\t...currentData,\n\t\t\t\t[providerId]: createOAuthCredential(accounts, accountIndex),\n\t\t\t};\n\t\t\tthis.data = merged;\n\t\t\treturn {\n\t\t\t\tresult: { ...resolved, newCredentials },\n\t\t\t\tnext: JSON.stringify(merged, null, 2),\n\t\t\t};\n\t\t});\n\t}\n\n\t/**\n\t * Get API key for a provider.\n\t * Priority:\n\t * 1. Runtime override (CLI --api-key)\n\t * 2. API key from auth.json\n\t * 3. OAuth token from auth.json (auto-refreshed with locking)\n\t * 4. Environment variable\n\t * 5. Fallback resolver (models.json custom providers)\n\t */\n\tasync getApiKey(providerId: string, options?: { includeFallback?: boolean }): Promise<string | undefined> {\n\t\t// Runtime override takes highest priority\n\t\tconst runtimeKey = this.runtimeOverrides.get(providerId);\n\t\tif (runtimeKey) {\n\t\t\treturn runtimeKey;\n\t\t}\n\n\t\tconst cred = this.data[providerId];\n\n\t\tif (cred?.type === \"api_key\") {\n\t\t\treturn resolveConfigValue(cred.key);\n\t\t}\n\n\t\tif (cred?.type === \"oauth\") {\n\t\t\ttry {\n\t\t\t\tconst result = await this.resolveOAuthTokenWithLock(providerId);\n\t\t\t\tif (result) {\n\t\t\t\t\treturn result.apiKey;\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tthis.recordError(error);\n\t\t\t\t// Credentials are preserved so a later request or /login can recover.\n\t\t\t\tthis.reload();\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t}\n\n\t\t// Fall back to environment variable\n\t\tconst envKey = getEnvApiKey(providerId);\n\t\tif (envKey) return envKey;\n\n\t\t// Fall back to custom resolver (e.g., models.json custom providers)\n\t\tif (options?.includeFallback !== false) {\n\t\t\treturn this.fallbackResolver?.(providerId) ?? undefined;\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Get all registered OAuth providers\n\t */\n\tgetOAuthProviders() {\n\t\treturn getOAuthProviders();\n\t}\n}\n"]}
|
|
@@ -14,6 +14,13 @@ import { getAgentDir } from "../config.js";
|
|
|
14
14
|
import { stripAnsi } from "../utils/ansi.js";
|
|
15
15
|
import { normalizePath } from "../utils/paths.js";
|
|
16
16
|
import { resolveConfigValue } from "./resolve-config-value.js";
|
|
17
|
+
const RETIRED_GROK_OAUTH_PROXY = "grok-oauth-proxy";
|
|
18
|
+
function omitRetiredGrokOAuthProxy(data) {
|
|
19
|
+
if (!(RETIRED_GROK_OAUTH_PROXY in data))
|
|
20
|
+
return data;
|
|
21
|
+
const { [RETIRED_GROK_OAUTH_PROXY]: _retired, ...kept } = data;
|
|
22
|
+
return kept;
|
|
23
|
+
}
|
|
17
24
|
const OAUTH_ACCOUNT_ID_FIELDS = ["accountId", "email", "userId", "username"];
|
|
18
25
|
const OAUTH_ACCOUNT_LABEL_FIELDS = ["email", "username"];
|
|
19
26
|
const OAUTH_ACCOUNT_LABEL_MAX_LENGTH = 96;
|
|
@@ -303,7 +310,7 @@ export class AuthStorage {
|
|
|
303
310
|
return {};
|
|
304
311
|
}
|
|
305
312
|
try {
|
|
306
|
-
return JSON.parse(content);
|
|
313
|
+
return omitRetiredGrokOAuthProxy(JSON.parse(content));
|
|
307
314
|
}
|
|
308
315
|
catch (error) {
|
|
309
316
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -336,7 +343,10 @@ export class AuthStorage {
|
|
|
336
343
|
this.storage.withLock((current) => {
|
|
337
344
|
const currentData = this.parseStorageData(current);
|
|
338
345
|
const merged = { ...currentData };
|
|
339
|
-
if (
|
|
346
|
+
if (provider === RETIRED_GROK_OAUTH_PROXY) {
|
|
347
|
+
delete merged[provider];
|
|
348
|
+
}
|
|
349
|
+
else if (credential) {
|
|
340
350
|
merged[provider] = credential;
|
|
341
351
|
}
|
|
342
352
|
else {
|
|
@@ -353,12 +363,19 @@ export class AuthStorage {
|
|
|
353
363
|
* Get credential for a provider.
|
|
354
364
|
*/
|
|
355
365
|
get(provider) {
|
|
366
|
+
if (provider === RETIRED_GROK_OAUTH_PROXY)
|
|
367
|
+
return undefined;
|
|
356
368
|
return this.data[provider] ?? undefined;
|
|
357
369
|
}
|
|
358
370
|
/**
|
|
359
371
|
* Set credential for a provider.
|
|
360
372
|
*/
|
|
361
373
|
set(provider, credential) {
|
|
374
|
+
if (provider === RETIRED_GROK_OAUTH_PROXY) {
|
|
375
|
+
delete this.data[provider];
|
|
376
|
+
this.persistProviderChange(provider, undefined);
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
362
379
|
this.data[provider] = credential;
|
|
363
380
|
this.persistProviderChange(provider, credential);
|
|
364
381
|
}
|
|
@@ -373,12 +390,14 @@ export class AuthStorage {
|
|
|
373
390
|
* List all providers with credentials.
|
|
374
391
|
*/
|
|
375
392
|
list() {
|
|
376
|
-
return Object.keys(this.data);
|
|
393
|
+
return Object.keys(this.data).filter((provider) => provider !== RETIRED_GROK_OAUTH_PROXY);
|
|
377
394
|
}
|
|
378
395
|
/**
|
|
379
396
|
* Check if credentials exist for a provider in auth.json.
|
|
380
397
|
*/
|
|
381
398
|
has(provider) {
|
|
399
|
+
if (provider === RETIRED_GROK_OAUTH_PROXY)
|
|
400
|
+
return false;
|
|
382
401
|
return provider in this.data;
|
|
383
402
|
}
|
|
384
403
|
/**
|
|
@@ -386,6 +405,8 @@ export class AuthStorage {
|
|
|
386
405
|
* Unlike getApiKey(), this doesn't refresh OAuth tokens.
|
|
387
406
|
*/
|
|
388
407
|
hasAuth(provider) {
|
|
408
|
+
if (provider === RETIRED_GROK_OAUTH_PROXY)
|
|
409
|
+
return false;
|
|
389
410
|
if (this.runtimeOverrides.has(provider))
|
|
390
411
|
return true;
|
|
391
412
|
if (this.data[provider])
|
|
@@ -455,6 +476,9 @@ export class AuthStorage {
|
|
|
455
476
|
* Return auth status without exposing credential values or refreshing tokens.
|
|
456
477
|
*/
|
|
457
478
|
getAuthStatus(provider) {
|
|
479
|
+
if (provider === RETIRED_GROK_OAUTH_PROXY) {
|
|
480
|
+
return { configured: false };
|
|
481
|
+
}
|
|
458
482
|
if (this.data[provider]) {
|
|
459
483
|
return { configured: true, source: "stored" };
|
|
460
484
|
}
|
|
@@ -474,7 +498,7 @@ export class AuthStorage {
|
|
|
474
498
|
* Get all credentials (for passing to getOAuthApiKey).
|
|
475
499
|
*/
|
|
476
500
|
getAll() {
|
|
477
|
-
return { ...this.data };
|
|
501
|
+
return omitRetiredGrokOAuthProxy({ ...this.data });
|
|
478
502
|
}
|
|
479
503
|
drainErrors() {
|
|
480
504
|
const drained = [...this.errors];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-storage.js","sourceRoot":"","sources":["../../src/core/auth-storage.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Credential storage for API keys and OAuth tokens.\n * Handles loading, saving, and refreshing credentials from auth.json.\n *\n * Uses file locking to prevent race conditions when multiple OMK instances\n * try to refresh tokens simultaneously.\n */\n\nimport { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\nimport {\n\tfindEnvKeys,\n\tgetEnvApiKey,\n\ttype OAuthCredentials,\n\ttype OAuthLoginCallbacks,\n\ttype OAuthProviderId,\n} from \"omk-ai\";\nimport { getOAuthApiKey, getOAuthProvider, getOAuthProviders } from \"omk-ai/oauth\";\nimport { dirname, join } from \"path\";\nimport lockfile from \"proper-lockfile\";\nimport { getAgentDir } from \"../config.ts\";\nimport { stripAnsi } from \"../utils/ansi.ts\";\nimport { normalizePath } from \"../utils/paths.ts\";\nimport { resolveConfigValue } from \"./resolve-config-value.ts\";\n\nexport type ApiKeyCredential = {\n\ttype: \"api_key\";\n\tkey: string;\n};\n\nexport type OAuthCredential = {\n\ttype: \"oauth\";\n\t/** Complete account list when more than one subscription account is configured. */\n\taccounts?: OAuthCredentials[];\n\t/** Index of the account explicitly selected for this provider. */\n\tactiveAccount?: number;\n\t/** Legacy cursor accepted when migrating older auth.json files. */\n\tnextAccount?: number;\n} & OAuthCredentials;\n\nexport interface OAuthAccountSummary {\n\tindex: number;\n\tlabel: string;\n\tselected: boolean;\n}\n\nexport type AuthCredential = ApiKeyCredential | OAuthCredential;\n\nexport type AuthStorageData = Record<string, AuthCredential>;\n\nconst OAUTH_ACCOUNT_ID_FIELDS = [\"accountId\", \"email\", \"userId\", \"username\"] as const;\nconst OAUTH_ACCOUNT_LABEL_FIELDS = [\"email\", \"username\"] as const;\nconst OAUTH_ACCOUNT_LABEL_MAX_LENGTH = 96;\nconst UNSAFE_ACCOUNT_LABEL_PATTERN =\n\t/[\\u0000-\\u0008\\u000b\\u000c\\u000e-\\u001f\\u007f-\\u009f\\u200b-\\u200f\\u202a-\\u202e\\u2060-\\u206f\\ufeff]/g;\n\nfunction sanitizeOAuthAccountLabel(value: string): string | undefined {\n\tconst sanitized = stripAnsi(value)\n\t\t.replace(/[\\t\\r\\n]+/g, \" \")\n\t\t.replace(UNSAFE_ACCOUNT_LABEL_PATTERN, \"\")\n\t\t.replace(/\\s+/g, \" \")\n\t\t.trim()\n\t\t.slice(0, OAUTH_ACCOUNT_LABEL_MAX_LENGTH);\n\treturn sanitized || undefined;\n}\n\nfunction stripOAuthStorageMetadata(credential: OAuthCredential): OAuthCredentials {\n\tconst {\n\t\ttype: _type,\n\t\taccounts: _accounts,\n\t\tactiveAccount: _activeAccount,\n\t\tnextAccount: _nextAccount,\n\t\t...credentials\n\t} = credential;\n\treturn credentials;\n}\n\nfunction getOAuthAccounts(credential: OAuthCredential): OAuthCredentials[] {\n\tif (Array.isArray(credential.accounts) && credential.accounts.length > 0) {\n\t\treturn credential.accounts;\n\t}\n\treturn [stripOAuthStorageMetadata(credential)];\n}\n\nfunction normalizeOAuthAccountIndex(index: unknown, accountCount: number): number {\n\tif (accountCount <= 0 || typeof index !== \"number\" || !Number.isInteger(index)) {\n\t\treturn 0;\n\t}\n\treturn ((index % accountCount) + accountCount) % accountCount;\n}\n\nfunction getSelectedOAuthAccountIndex(credential: OAuthCredential, accountCount: number): number {\n\treturn normalizeOAuthAccountIndex(credential.activeAccount ?? credential.nextAccount, accountCount);\n}\n\nfunction createOAuthCredential(accounts: OAuthCredentials[], activeAccount = 0): OAuthCredential {\n\tconst selectedIndex = normalizeOAuthAccountIndex(activeAccount, accounts.length);\n\tconst selected = accounts[selectedIndex];\n\tif (!selected) {\n\t\tthrow new Error(\"OAuth credential must contain at least one account\");\n\t}\n\tif (accounts.length === 1) {\n\t\treturn { ...selected, type: \"oauth\" };\n\t}\n\treturn {\n\t\t...selected,\n\t\ttype: \"oauth\",\n\t\taccounts,\n\t\tactiveAccount: selectedIndex,\n\t};\n}\n\nfunction getOAuthAccountIdentity(credentials: OAuthCredentials): string | undefined {\n\tconst accountId = credentials.accountId;\n\tconst orgId = credentials.orgId;\n\tif (typeof accountId === \"string\" && accountId.trim() && typeof orgId === \"string\" && orgId.trim()) {\n\t\treturn `accountId:${accountId.trim().toLowerCase()}:orgId:${orgId.trim().toLowerCase()}`;\n\t}\n\tfor (const field of OAUTH_ACCOUNT_ID_FIELDS) {\n\t\tconst value = credentials[field];\n\t\tif (typeof value === \"string\" && value.trim()) {\n\t\t\treturn `${field}:${value.trim().toLowerCase()}`;\n\t\t}\n\t}\n\treturn undefined;\n}\n\nfunction getOAuthAccountDisplayLabel(providerId: string, credentials: OAuthCredentials): string | undefined {\n\tfor (const field of OAUTH_ACCOUNT_LABEL_FIELDS) {\n\t\tconst value = credentials[field];\n\t\tif (typeof value === \"string\" && value.trim()) {\n\t\t\tconst label = sanitizeOAuthAccountLabel(value);\n\t\t\tif (!label) continue;\n\t\t\tconst orgName =\n\t\t\t\ttypeof credentials.orgName === \"string\" ? sanitizeOAuthAccountLabel(credentials.orgName) : undefined;\n\t\t\treturn sanitizeOAuthAccountLabel(orgName ? `${label} (${orgName})` : label);\n\t\t}\n\t}\n\ttry {\n\t\tconst label = getOAuthProvider(providerId)?.getAccountLabel?.(credentials);\n\t\treturn typeof label === \"string\" ? sanitizeOAuthAccountLabel(label) : undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction findMatchingOAuthAccount(accounts: OAuthCredentials[], credentials: OAuthCredentials): number {\n\tconst identity = getOAuthAccountIdentity(credentials);\n\tif (identity) {\n\t\tconst exactMatch = accounts.findIndex((account) => getOAuthAccountIdentity(account) === identity);\n\t\tif (exactMatch >= 0) return exactMatch;\n\t}\n\n\t// Let newly enriched credentials update older entries that predate email/org metadata.\n\tfor (const field of OAUTH_ACCOUNT_ID_FIELDS) {\n\t\tconst value = credentials[field];\n\t\tif (typeof value !== \"string\" || !value.trim()) continue;\n\t\tconst normalizedValue = value.trim().toLowerCase();\n\t\tconst orgId = typeof credentials.orgId === \"string\" ? credentials.orgId.trim().toLowerCase() : \"\";\n\t\tconst compatibleMatch = accounts.findIndex((account) => {\n\t\t\tconst existingValue = account[field];\n\t\t\tif (typeof existingValue !== \"string\" || existingValue.trim().toLowerCase() !== normalizedValue) return false;\n\t\t\tconst existingOrgId = typeof account.orgId === \"string\" ? account.orgId.trim().toLowerCase() : \"\";\n\t\t\treturn !orgId || !existingOrgId || orgId === existingOrgId;\n\t\t});\n\t\tif (compatibleMatch >= 0) return compatibleMatch;\n\t}\n\n\treturn accounts.findIndex((account) => account.refresh === credentials.refresh);\n}\n\nexport type AuthStatus = {\n\tconfigured: boolean;\n\tsource?: \"stored\" | \"runtime\" | \"environment\" | \"fallback\" | \"models_json_key\" | \"models_json_command\";\n\tlabel?: string;\n};\n\ntype LockResult<T> = {\n\tresult: T;\n\tnext?: string;\n};\n\nconst AUTH_FILE_WRITE_OPTIONS = { encoding: \"utf-8\", mode: 0o600 } as const;\n\nexport interface AuthStorageBackend {\n\twithLock<T>(fn: (current: string | undefined) => LockResult<T>): T;\n\twithLockAsync<T>(fn: (current: string | undefined) => Promise<LockResult<T>>): Promise<T>;\n}\n\nexport class FileAuthStorageBackend implements AuthStorageBackend {\n\tprivate authPath: string;\n\n\tconstructor(authPath: string = join(getAgentDir(), \"auth.json\")) {\n\t\tthis.authPath = normalizePath(authPath);\n\t}\n\n\tprivate ensureParentDir(): void {\n\t\tconst dir = dirname(this.authPath);\n\t\tif (!existsSync(dir)) {\n\t\t\tmkdirSync(dir, { recursive: true, mode: 0o700 });\n\t\t}\n\t}\n\n\tprivate ensureFileExists(): void {\n\t\tif (!existsSync(this.authPath)) {\n\t\t\twriteFileSync(this.authPath, \"{}\", AUTH_FILE_WRITE_OPTIONS);\n\t\t\tchmodSync(this.authPath, 0o600);\n\t\t}\n\t}\n\n\tprivate acquireLockSyncWithRetry(path: string): () => void {\n\t\tconst maxAttempts = 10;\n\t\tconst delayMs = 20;\n\t\tlet lastError: unknown;\n\n\t\tfor (let attempt = 1; attempt <= maxAttempts; attempt++) {\n\t\t\ttry {\n\t\t\t\treturn lockfile.lockSync(path, { realpath: false });\n\t\t\t} catch (error) {\n\t\t\t\tconst code =\n\t\t\t\t\ttypeof error === \"object\" && error !== null && \"code\" in error\n\t\t\t\t\t\t? String((error as { code?: unknown }).code)\n\t\t\t\t\t\t: undefined;\n\t\t\t\tif (code !== \"ELOCKED\" || attempt === maxAttempts) {\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tlastError = error;\n\t\t\t\tconst start = Date.now();\n\t\t\t\twhile (Date.now() - start < delayMs) {\n\t\t\t\t\t// Sleep synchronously to avoid changing callers to async.\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthrow (lastError as Error) ?? new Error(\"Failed to acquire auth storage lock\");\n\t}\n\n\twithLock<T>(fn: (current: string | undefined) => LockResult<T>): T {\n\t\tthis.ensureParentDir();\n\t\tthis.ensureFileExists();\n\n\t\tlet release: (() => void) | undefined;\n\t\ttry {\n\t\t\trelease = this.acquireLockSyncWithRetry(this.authPath);\n\t\t\tconst current = existsSync(this.authPath) ? readFileSync(this.authPath, \"utf-8\") : undefined;\n\t\t\tconst { result, next } = fn(current);\n\t\t\tif (next !== undefined) {\n\t\t\t\twriteFileSync(this.authPath, next, AUTH_FILE_WRITE_OPTIONS);\n\t\t\t\tchmodSync(this.authPath, 0o600);\n\t\t\t}\n\t\t\treturn result;\n\t\t} finally {\n\t\t\tif (release) {\n\t\t\t\trelease();\n\t\t\t}\n\t\t}\n\t}\n\n\tasync withLockAsync<T>(fn: (current: string | undefined) => Promise<LockResult<T>>): Promise<T> {\n\t\tthis.ensureParentDir();\n\t\tthis.ensureFileExists();\n\n\t\tlet release: (() => Promise<void>) | undefined;\n\t\tlet lockCompromised = false;\n\t\tlet lockCompromisedError: Error | undefined;\n\t\tconst throwIfCompromised = () => {\n\t\t\tif (lockCompromised) {\n\t\t\t\tthrow lockCompromisedError ?? new Error(\"Auth storage lock was compromised\");\n\t\t\t}\n\t\t};\n\n\t\ttry {\n\t\t\trelease = await lockfile.lock(this.authPath, {\n\t\t\t\tretries: {\n\t\t\t\t\tretries: 10,\n\t\t\t\t\tfactor: 2,\n\t\t\t\t\tminTimeout: 100,\n\t\t\t\t\tmaxTimeout: 10000,\n\t\t\t\t\trandomize: true,\n\t\t\t\t},\n\t\t\t\tstale: 30000,\n\t\t\t\tonCompromised: (err) => {\n\t\t\t\t\tlockCompromised = true;\n\t\t\t\t\tlockCompromisedError = err;\n\t\t\t\t},\n\t\t\t});\n\n\t\t\tthrowIfCompromised();\n\t\t\tconst current = existsSync(this.authPath) ? readFileSync(this.authPath, \"utf-8\") : undefined;\n\t\t\tconst { result, next } = await fn(current);\n\t\t\tthrowIfCompromised();\n\t\t\tif (next !== undefined) {\n\t\t\t\twriteFileSync(this.authPath, next, AUTH_FILE_WRITE_OPTIONS);\n\t\t\t\tchmodSync(this.authPath, 0o600);\n\t\t\t}\n\t\t\tthrowIfCompromised();\n\t\t\treturn result;\n\t\t} finally {\n\t\t\tif (release) {\n\t\t\t\ttry {\n\t\t\t\t\tawait release();\n\t\t\t\t} catch {\n\t\t\t\t\t// Ignore unlock errors when lock is compromised.\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nexport class InMemoryAuthStorageBackend implements AuthStorageBackend {\n\tprivate value: string | undefined;\n\n\twithLock<T>(fn: (current: string | undefined) => LockResult<T>): T {\n\t\tconst { result, next } = fn(this.value);\n\t\tif (next !== undefined) {\n\t\t\tthis.value = next;\n\t\t}\n\t\treturn result;\n\t}\n\n\tasync withLockAsync<T>(fn: (current: string | undefined) => Promise<LockResult<T>>): Promise<T> {\n\t\tconst { result, next } = await fn(this.value);\n\t\tif (next !== undefined) {\n\t\t\tthis.value = next;\n\t\t}\n\t\treturn result;\n\t}\n}\n\n/**\n * Credential storage backed by a JSON file.\n */\nexport class AuthStorage {\n\tprivate data: AuthStorageData = {};\n\tprivate runtimeOverrides: Map<string, string> = new Map();\n\tprivate fallbackResolver?: (provider: string) => string | undefined;\n\tprivate loadError: Error | null = null;\n\tprivate errors: Error[] = [];\n\tprivate storage: AuthStorageBackend;\n\n\tprivate constructor(storage: AuthStorageBackend) {\n\t\tthis.storage = storage;\n\t\tthis.reload();\n\t}\n\n\tstatic create(authPath?: string): AuthStorage {\n\t\treturn new AuthStorage(new FileAuthStorageBackend(authPath ?? join(getAgentDir(), \"auth.json\")));\n\t}\n\n\tstatic fromStorage(storage: AuthStorageBackend): AuthStorage {\n\t\treturn new AuthStorage(storage);\n\t}\n\n\tstatic inMemory(data: AuthStorageData = {}): AuthStorage {\n\t\tconst storage = new InMemoryAuthStorageBackend();\n\t\tstorage.withLock(() => ({ result: undefined, next: JSON.stringify(data, null, 2) }));\n\t\treturn AuthStorage.fromStorage(storage);\n\t}\n\n\t/**\n\t * Set a runtime API key override (not persisted to disk).\n\t * Used for CLI --api-key flag.\n\t */\n\tsetRuntimeApiKey(provider: string, apiKey: string): void {\n\t\tthis.runtimeOverrides.set(provider, apiKey);\n\t}\n\n\t/**\n\t * Remove a runtime API key override.\n\t */\n\tremoveRuntimeApiKey(provider: string): void {\n\t\tthis.runtimeOverrides.delete(provider);\n\t}\n\n\t/**\n\t * Set a fallback resolver for API keys not found in auth.json or env vars.\n\t * Used for custom provider keys from models.json.\n\t */\n\tsetFallbackResolver(resolver: (provider: string) => string | undefined): void {\n\t\tthis.fallbackResolver = resolver;\n\t}\n\n\tprivate recordError(error: unknown): void {\n\t\tconst normalizedError = error instanceof Error ? error : new Error(String(error));\n\t\tthis.errors.push(normalizedError);\n\t}\n\n\tprivate parseStorageData(content: string | undefined): AuthStorageData {\n\t\tif (!content) {\n\t\t\treturn {};\n\t\t}\n\t\ttry {\n\t\t\treturn JSON.parse(content) as AuthStorageData;\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new Error(`Failed to parse auth storage: ${message}`);\n\t\t}\n\t}\n\n\t/**\n\t * Reload credentials from storage.\n\t */\n\treload(): void {\n\t\tlet content: string | undefined;\n\t\ttry {\n\t\t\tthis.storage.withLock((current) => {\n\t\t\t\tcontent = current;\n\t\t\t\treturn { result: undefined };\n\t\t\t});\n\t\t\tthis.data = this.parseStorageData(content);\n\t\t\tthis.loadError = null;\n\t\t} catch (error) {\n\t\t\tthis.loadError = error as Error;\n\t\t\tthis.recordError(error);\n\t\t}\n\t}\n\n\tprivate persistProviderChange(provider: string, credential: AuthCredential | undefined): void {\n\t\tif (this.loadError) {\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tthis.storage.withLock((current) => {\n\t\t\t\tconst currentData = this.parseStorageData(current);\n\t\t\t\tconst merged: AuthStorageData = { ...currentData };\n\t\t\t\tif (credential) {\n\t\t\t\t\tmerged[provider] = credential;\n\t\t\t\t} else {\n\t\t\t\t\tdelete merged[provider];\n\t\t\t\t}\n\t\t\t\treturn { result: undefined, next: JSON.stringify(merged, null, 2) };\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tthis.recordError(error);\n\t\t}\n\t}\n\n\t/**\n\t * Get credential for a provider.\n\t */\n\tget(provider: string): AuthCredential | undefined {\n\t\treturn this.data[provider] ?? undefined;\n\t}\n\n\t/**\n\t * Set credential for a provider.\n\t */\n\tset(provider: string, credential: AuthCredential): void {\n\t\tthis.data[provider] = credential;\n\t\tthis.persistProviderChange(provider, credential);\n\t}\n\n\t/**\n\t * Remove credential for a provider.\n\t */\n\tremove(provider: string): void {\n\t\tdelete this.data[provider];\n\t\tthis.persistProviderChange(provider, undefined);\n\t}\n\n\t/**\n\t * List all providers with credentials.\n\t */\n\tlist(): string[] {\n\t\treturn Object.keys(this.data);\n\t}\n\n\t/**\n\t * Check if credentials exist for a provider in auth.json.\n\t */\n\thas(provider: string): boolean {\n\t\treturn provider in this.data;\n\t}\n\n\t/**\n\t * Check if any form of auth is configured for a provider.\n\t * Unlike getApiKey(), this doesn't refresh OAuth tokens.\n\t */\n\thasAuth(provider: string): boolean {\n\t\tif (this.runtimeOverrides.has(provider)) return true;\n\t\tif (this.data[provider]) return true;\n\t\tif (getEnvApiKey(provider)) return true;\n\t\tif (this.fallbackResolver?.(provider)) return true;\n\t\treturn false;\n\t}\n\n\t/** Return the number of stored OAuth accounts for a provider. */\n\tgetOAuthAccountCount(provider: string): number {\n\t\tconst credential = this.data[provider];\n\t\treturn credential?.type === \"oauth\" ? getOAuthAccounts(credential).length : 0;\n\t}\n\n\t/** Return safe, human-readable labels for every stored OAuth account. */\n\tlistOAuthAccounts(provider: string): OAuthAccountSummary[] {\n\t\tconst credential = this.data[provider];\n\t\tif (credential?.type !== \"oauth\") return [];\n\t\tconst accounts = getOAuthAccounts(credential);\n\t\tconst selectedIndex = getSelectedOAuthAccountIndex(credential, accounts.length);\n\t\treturn accounts.map((account, index) => ({\n\t\t\tindex,\n\t\t\tlabel: getOAuthAccountDisplayLabel(provider, account) ?? `Account ${index + 1}`,\n\t\t\tselected: index === selectedIndex,\n\t\t}));\n\t}\n\n\t/** Return the human-readable label of the selected OAuth account. */\n\tgetOAuthAccountLabel(provider: string): string | undefined {\n\t\treturn this.listOAuthAccounts(provider).find((account) => account.selected)?.label;\n\t}\n\n\t/** Explicitly select and persist the OAuth account used by this provider. */\n\tselectOAuthAccount(provider: string, accountIndex: number): void {\n\t\tthis.storage.withLock((current) => {\n\t\t\tconst currentData = this.parseStorageData(current);\n\t\t\tconst credential = currentData[provider];\n\t\t\tif (credential?.type !== \"oauth\") {\n\t\t\t\tthrow new Error(`No OAuth accounts configured for ${provider}`);\n\t\t\t}\n\t\t\tconst accounts = [...getOAuthAccounts(credential)];\n\t\t\tif (!Number.isInteger(accountIndex) || accountIndex < 0 || accountIndex >= accounts.length) {\n\t\t\t\tthrow new Error(`Invalid OAuth account index ${accountIndex} for ${provider}`);\n\t\t\t}\n\t\t\tconst merged: AuthStorageData = {\n\t\t\t\t...currentData,\n\t\t\t\t[provider]: createOAuthCredential(accounts, accountIndex),\n\t\t\t};\n\t\t\tthis.data = merged;\n\t\t\tthis.loadError = null;\n\t\t\treturn { result: undefined, next: JSON.stringify(merged, null, 2) };\n\t\t});\n\t}\n\n\t/**\n\t * Return the explicitly selected OAuth credentials without refreshing tokens.\n\t * Used by provider model customization hooks.\n\t */\n\tgetOAuthCredentials(provider: string): OAuthCredentials | undefined {\n\t\tconst credential = this.data[provider];\n\t\tif (credential?.type !== \"oauth\") {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst accounts = getOAuthAccounts(credential);\n\t\treturn accounts[getSelectedOAuthAccountIndex(credential, accounts.length)];\n\t}\n\n\t/**\n\t * Return auth status without exposing credential values or refreshing tokens.\n\t */\n\tgetAuthStatus(provider: string): AuthStatus {\n\t\tif (this.data[provider]) {\n\t\t\treturn { configured: true, source: \"stored\" };\n\t\t}\n\n\t\tif (this.runtimeOverrides.has(provider)) {\n\t\t\treturn { configured: false, source: \"runtime\", label: \"--api-key\" };\n\t\t}\n\n\t\tconst envKeys = findEnvKeys(provider);\n\t\tif (envKeys?.[0]) {\n\t\t\treturn { configured: false, source: \"environment\", label: envKeys[0] };\n\t\t}\n\n\t\tif (this.fallbackResolver?.(provider)) {\n\t\t\treturn { configured: false, source: \"fallback\", label: \"custom provider config\" };\n\t\t}\n\n\t\treturn { configured: false };\n\t}\n\n\t/**\n\t * Get all credentials (for passing to getOAuthApiKey).\n\t */\n\tgetAll(): AuthStorageData {\n\t\treturn { ...this.data };\n\t}\n\n\tdrainErrors(): Error[] {\n\t\tconst drained = [...this.errors];\n\t\tthis.errors = [];\n\t\treturn drained;\n\t}\n\n\t/**\n\t * Login to an OAuth provider. Repeated logins append distinct accounts and\n\t * update an existing account when the provider exposes a stable identity.\n\t */\n\tasync login(providerId: OAuthProviderId, callbacks: OAuthLoginCallbacks): Promise<void> {\n\t\tconst provider = getOAuthProvider(providerId);\n\t\tif (!provider) {\n\t\t\tthrow new Error(`Unknown OAuth provider: ${providerId}`);\n\t\t}\n\n\t\tconst credentials = await provider.login(callbacks);\n\t\tif (this.loadError) {\n\t\t\tthis.data[providerId] = { type: \"oauth\", ...credentials };\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tthis.storage.withLock((current) => {\n\t\t\t\tconst currentData = this.parseStorageData(current);\n\t\t\t\tconst existing = currentData[providerId];\n\t\t\t\tlet credential: OAuthCredential;\n\n\t\t\t\tif (existing?.type === \"oauth\") {\n\t\t\t\t\tconst accounts = [...getOAuthAccounts(existing)];\n\t\t\t\t\tconst matchingIndex = findMatchingOAuthAccount(accounts, credentials);\n\t\t\t\t\tlet activeAccount: number;\n\t\t\t\t\tif (matchingIndex >= 0) {\n\t\t\t\t\t\taccounts[matchingIndex] = credentials;\n\t\t\t\t\t\tactiveAccount = matchingIndex;\n\t\t\t\t\t} else {\n\t\t\t\t\t\taccounts.push(credentials);\n\t\t\t\t\t\tactiveAccount = accounts.length - 1;\n\t\t\t\t\t}\n\t\t\t\t\tcredential = createOAuthCredential(accounts, activeAccount);\n\t\t\t\t} else {\n\t\t\t\t\tcredential = createOAuthCredential([credentials]);\n\t\t\t\t}\n\n\t\t\t\tconst merged: AuthStorageData = { ...currentData, [providerId]: credential };\n\t\t\t\tthis.data = merged;\n\t\t\t\tthis.loadError = null;\n\t\t\t\treturn { result: undefined, next: JSON.stringify(merged, null, 2) };\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tthis.recordError(error);\n\t\t}\n\t}\n\n\t/**\n\t * Logout from a provider.\n\t */\n\tlogout(provider: string): void {\n\t\tthis.remove(provider);\n\t}\n\n\t/** Resolve the explicitly selected account and refresh it under the storage lock. */\n\tprivate async resolveOAuthTokenWithLock(\n\t\tproviderId: OAuthProviderId,\n\t): Promise<{ apiKey: string; newCredentials: OAuthCredentials } | null> {\n\t\tconst provider = getOAuthProvider(providerId);\n\t\tif (!provider) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn this.storage.withLockAsync(async (current) => {\n\t\t\tconst currentData = this.parseStorageData(current);\n\t\t\tthis.data = currentData;\n\t\t\tthis.loadError = null;\n\n\t\t\tconst credential = currentData[providerId];\n\t\t\tif (credential?.type !== \"oauth\") {\n\t\t\t\treturn { result: null };\n\t\t\t}\n\n\t\t\tconst accounts = [...getOAuthAccounts(credential)];\n\t\t\tconst accountIndex = getSelectedOAuthAccountIndex(credential, accounts.length);\n\t\t\tconst account = accounts[accountIndex];\n\t\t\tif (!account) return { result: null };\n\n\t\t\tconst resolved =\n\t\t\t\tDate.now() < account.expires\n\t\t\t\t\t? { apiKey: provider.getApiKey(account), newCredentials: account }\n\t\t\t\t\t: await getOAuthApiKey(providerId, { [providerId]: account });\n\t\t\tif (!resolved) return { result: null };\n\n\t\t\tif (resolved.newCredentials === account) {\n\t\t\t\treturn { result: resolved };\n\t\t\t}\n\n\t\t\tconst newCredentials = { ...account, ...resolved.newCredentials };\n\t\t\taccounts[accountIndex] = newCredentials;\n\t\t\tconst merged: AuthStorageData = {\n\t\t\t\t...currentData,\n\t\t\t\t[providerId]: createOAuthCredential(accounts, accountIndex),\n\t\t\t};\n\t\t\tthis.data = merged;\n\t\t\treturn {\n\t\t\t\tresult: { ...resolved, newCredentials },\n\t\t\t\tnext: JSON.stringify(merged, null, 2),\n\t\t\t};\n\t\t});\n\t}\n\n\t/**\n\t * Get API key for a provider.\n\t * Priority:\n\t * 1. Runtime override (CLI --api-key)\n\t * 2. API key from auth.json\n\t * 3. OAuth token from auth.json (auto-refreshed with locking)\n\t * 4. Environment variable\n\t * 5. Fallback resolver (models.json custom providers)\n\t */\n\tasync getApiKey(providerId: string, options?: { includeFallback?: boolean }): Promise<string | undefined> {\n\t\t// Runtime override takes highest priority\n\t\tconst runtimeKey = this.runtimeOverrides.get(providerId);\n\t\tif (runtimeKey) {\n\t\t\treturn runtimeKey;\n\t\t}\n\n\t\tconst cred = this.data[providerId];\n\n\t\tif (cred?.type === \"api_key\") {\n\t\t\treturn resolveConfigValue(cred.key);\n\t\t}\n\n\t\tif (cred?.type === \"oauth\") {\n\t\t\ttry {\n\t\t\t\tconst result = await this.resolveOAuthTokenWithLock(providerId);\n\t\t\t\tif (result) {\n\t\t\t\t\treturn result.apiKey;\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tthis.recordError(error);\n\t\t\t\t// Credentials are preserved so a later request or /login can recover.\n\t\t\t\tthis.reload();\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t}\n\n\t\t// Fall back to environment variable\n\t\tconst envKey = getEnvApiKey(providerId);\n\t\tif (envKey) return envKey;\n\n\t\t// Fall back to custom resolver (e.g., models.json custom providers)\n\t\tif (options?.includeFallback !== false) {\n\t\t\treturn this.fallbackResolver?.(providerId) ?? undefined;\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Get all registered OAuth providers\n\t */\n\tgetOAuthProviders() {\n\t\treturn getOAuthProviders();\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"auth-storage.js","sourceRoot":"","sources":["../../src/core/auth-storage.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Credential storage for API keys and OAuth tokens.\n * Handles loading, saving, and refreshing credentials from auth.json.\n *\n * Uses file locking to prevent race conditions when multiple OMK instances\n * try to refresh tokens simultaneously.\n */\n\nimport { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\nimport {\n\tfindEnvKeys,\n\tgetEnvApiKey,\n\ttype OAuthCredentials,\n\ttype OAuthLoginCallbacks,\n\ttype OAuthProviderId,\n} from \"omk-ai\";\nimport { getOAuthApiKey, getOAuthProvider, getOAuthProviders } from \"omk-ai/oauth\";\nimport { dirname, join } from \"path\";\nimport lockfile from \"proper-lockfile\";\nimport { getAgentDir } from \"../config.ts\";\nimport { stripAnsi } from \"../utils/ansi.ts\";\nimport { normalizePath } from \"../utils/paths.ts\";\nimport { resolveConfigValue } from \"./resolve-config-value.ts\";\n\nconst RETIRED_GROK_OAUTH_PROXY = \"grok-oauth-proxy\";\n\nfunction omitRetiredGrokOAuthProxy(data: AuthStorageData): AuthStorageData {\n\tif (!(RETIRED_GROK_OAUTH_PROXY in data)) return data;\n\tconst { [RETIRED_GROK_OAUTH_PROXY]: _retired, ...kept } = data;\n\treturn kept;\n}\n\nexport type ApiKeyCredential = {\n\ttype: \"api_key\";\n\tkey: string;\n};\n\nexport type OAuthCredential = {\n\ttype: \"oauth\";\n\t/** Complete account list when more than one subscription account is configured. */\n\taccounts?: OAuthCredentials[];\n\t/** Index of the account explicitly selected for this provider. */\n\tactiveAccount?: number;\n\t/** Legacy cursor accepted when migrating older auth.json files. */\n\tnextAccount?: number;\n} & OAuthCredentials;\n\nexport interface OAuthAccountSummary {\n\tindex: number;\n\tlabel: string;\n\tselected: boolean;\n}\n\nexport type AuthCredential = ApiKeyCredential | OAuthCredential;\n\nexport type AuthStorageData = Record<string, AuthCredential>;\n\nconst OAUTH_ACCOUNT_ID_FIELDS = [\"accountId\", \"email\", \"userId\", \"username\"] as const;\nconst OAUTH_ACCOUNT_LABEL_FIELDS = [\"email\", \"username\"] as const;\nconst OAUTH_ACCOUNT_LABEL_MAX_LENGTH = 96;\nconst UNSAFE_ACCOUNT_LABEL_PATTERN =\n\t/[\\u0000-\\u0008\\u000b\\u000c\\u000e-\\u001f\\u007f-\\u009f\\u200b-\\u200f\\u202a-\\u202e\\u2060-\\u206f\\ufeff]/g;\n\nfunction sanitizeOAuthAccountLabel(value: string): string | undefined {\n\tconst sanitized = stripAnsi(value)\n\t\t.replace(/[\\t\\r\\n]+/g, \" \")\n\t\t.replace(UNSAFE_ACCOUNT_LABEL_PATTERN, \"\")\n\t\t.replace(/\\s+/g, \" \")\n\t\t.trim()\n\t\t.slice(0, OAUTH_ACCOUNT_LABEL_MAX_LENGTH);\n\treturn sanitized || undefined;\n}\n\nfunction stripOAuthStorageMetadata(credential: OAuthCredential): OAuthCredentials {\n\tconst {\n\t\ttype: _type,\n\t\taccounts: _accounts,\n\t\tactiveAccount: _activeAccount,\n\t\tnextAccount: _nextAccount,\n\t\t...credentials\n\t} = credential;\n\treturn credentials;\n}\n\nfunction getOAuthAccounts(credential: OAuthCredential): OAuthCredentials[] {\n\tif (Array.isArray(credential.accounts) && credential.accounts.length > 0) {\n\t\treturn credential.accounts;\n\t}\n\treturn [stripOAuthStorageMetadata(credential)];\n}\n\nfunction normalizeOAuthAccountIndex(index: unknown, accountCount: number): number {\n\tif (accountCount <= 0 || typeof index !== \"number\" || !Number.isInteger(index)) {\n\t\treturn 0;\n\t}\n\treturn ((index % accountCount) + accountCount) % accountCount;\n}\n\nfunction getSelectedOAuthAccountIndex(credential: OAuthCredential, accountCount: number): number {\n\treturn normalizeOAuthAccountIndex(credential.activeAccount ?? credential.nextAccount, accountCount);\n}\n\nfunction createOAuthCredential(accounts: OAuthCredentials[], activeAccount = 0): OAuthCredential {\n\tconst selectedIndex = normalizeOAuthAccountIndex(activeAccount, accounts.length);\n\tconst selected = accounts[selectedIndex];\n\tif (!selected) {\n\t\tthrow new Error(\"OAuth credential must contain at least one account\");\n\t}\n\tif (accounts.length === 1) {\n\t\treturn { ...selected, type: \"oauth\" };\n\t}\n\treturn {\n\t\t...selected,\n\t\ttype: \"oauth\",\n\t\taccounts,\n\t\tactiveAccount: selectedIndex,\n\t};\n}\n\nfunction getOAuthAccountIdentity(credentials: OAuthCredentials): string | undefined {\n\tconst accountId = credentials.accountId;\n\tconst orgId = credentials.orgId;\n\tif (typeof accountId === \"string\" && accountId.trim() && typeof orgId === \"string\" && orgId.trim()) {\n\t\treturn `accountId:${accountId.trim().toLowerCase()}:orgId:${orgId.trim().toLowerCase()}`;\n\t}\n\tfor (const field of OAUTH_ACCOUNT_ID_FIELDS) {\n\t\tconst value = credentials[field];\n\t\tif (typeof value === \"string\" && value.trim()) {\n\t\t\treturn `${field}:${value.trim().toLowerCase()}`;\n\t\t}\n\t}\n\treturn undefined;\n}\n\nfunction getOAuthAccountDisplayLabel(providerId: string, credentials: OAuthCredentials): string | undefined {\n\tfor (const field of OAUTH_ACCOUNT_LABEL_FIELDS) {\n\t\tconst value = credentials[field];\n\t\tif (typeof value === \"string\" && value.trim()) {\n\t\t\tconst label = sanitizeOAuthAccountLabel(value);\n\t\t\tif (!label) continue;\n\t\t\tconst orgName =\n\t\t\t\ttypeof credentials.orgName === \"string\" ? sanitizeOAuthAccountLabel(credentials.orgName) : undefined;\n\t\t\treturn sanitizeOAuthAccountLabel(orgName ? `${label} (${orgName})` : label);\n\t\t}\n\t}\n\ttry {\n\t\tconst label = getOAuthProvider(providerId)?.getAccountLabel?.(credentials);\n\t\treturn typeof label === \"string\" ? sanitizeOAuthAccountLabel(label) : undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction findMatchingOAuthAccount(accounts: OAuthCredentials[], credentials: OAuthCredentials): number {\n\tconst identity = getOAuthAccountIdentity(credentials);\n\tif (identity) {\n\t\tconst exactMatch = accounts.findIndex((account) => getOAuthAccountIdentity(account) === identity);\n\t\tif (exactMatch >= 0) return exactMatch;\n\t}\n\n\t// Let newly enriched credentials update older entries that predate email/org metadata.\n\tfor (const field of OAUTH_ACCOUNT_ID_FIELDS) {\n\t\tconst value = credentials[field];\n\t\tif (typeof value !== \"string\" || !value.trim()) continue;\n\t\tconst normalizedValue = value.trim().toLowerCase();\n\t\tconst orgId = typeof credentials.orgId === \"string\" ? credentials.orgId.trim().toLowerCase() : \"\";\n\t\tconst compatibleMatch = accounts.findIndex((account) => {\n\t\t\tconst existingValue = account[field];\n\t\t\tif (typeof existingValue !== \"string\" || existingValue.trim().toLowerCase() !== normalizedValue) return false;\n\t\t\tconst existingOrgId = typeof account.orgId === \"string\" ? account.orgId.trim().toLowerCase() : \"\";\n\t\t\treturn !orgId || !existingOrgId || orgId === existingOrgId;\n\t\t});\n\t\tif (compatibleMatch >= 0) return compatibleMatch;\n\t}\n\n\treturn accounts.findIndex((account) => account.refresh === credentials.refresh);\n}\n\nexport type AuthStatus = {\n\tconfigured: boolean;\n\tsource?: \"stored\" | \"runtime\" | \"environment\" | \"fallback\" | \"models_json_key\" | \"models_json_command\";\n\tlabel?: string;\n};\n\ntype LockResult<T> = {\n\tresult: T;\n\tnext?: string;\n};\n\nconst AUTH_FILE_WRITE_OPTIONS = { encoding: \"utf-8\", mode: 0o600 } as const;\n\nexport interface AuthStorageBackend {\n\twithLock<T>(fn: (current: string | undefined) => LockResult<T>): T;\n\twithLockAsync<T>(fn: (current: string | undefined) => Promise<LockResult<T>>): Promise<T>;\n}\n\nexport class FileAuthStorageBackend implements AuthStorageBackend {\n\tprivate authPath: string;\n\n\tconstructor(authPath: string = join(getAgentDir(), \"auth.json\")) {\n\t\tthis.authPath = normalizePath(authPath);\n\t}\n\n\tprivate ensureParentDir(): void {\n\t\tconst dir = dirname(this.authPath);\n\t\tif (!existsSync(dir)) {\n\t\t\tmkdirSync(dir, { recursive: true, mode: 0o700 });\n\t\t}\n\t}\n\n\tprivate ensureFileExists(): void {\n\t\tif (!existsSync(this.authPath)) {\n\t\t\twriteFileSync(this.authPath, \"{}\", AUTH_FILE_WRITE_OPTIONS);\n\t\t\tchmodSync(this.authPath, 0o600);\n\t\t}\n\t}\n\n\tprivate acquireLockSyncWithRetry(path: string): () => void {\n\t\tconst maxAttempts = 10;\n\t\tconst delayMs = 20;\n\t\tlet lastError: unknown;\n\n\t\tfor (let attempt = 1; attempt <= maxAttempts; attempt++) {\n\t\t\ttry {\n\t\t\t\treturn lockfile.lockSync(path, { realpath: false });\n\t\t\t} catch (error) {\n\t\t\t\tconst code =\n\t\t\t\t\ttypeof error === \"object\" && error !== null && \"code\" in error\n\t\t\t\t\t\t? String((error as { code?: unknown }).code)\n\t\t\t\t\t\t: undefined;\n\t\t\t\tif (code !== \"ELOCKED\" || attempt === maxAttempts) {\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tlastError = error;\n\t\t\t\tconst start = Date.now();\n\t\t\t\twhile (Date.now() - start < delayMs) {\n\t\t\t\t\t// Sleep synchronously to avoid changing callers to async.\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthrow (lastError as Error) ?? new Error(\"Failed to acquire auth storage lock\");\n\t}\n\n\twithLock<T>(fn: (current: string | undefined) => LockResult<T>): T {\n\t\tthis.ensureParentDir();\n\t\tthis.ensureFileExists();\n\n\t\tlet release: (() => void) | undefined;\n\t\ttry {\n\t\t\trelease = this.acquireLockSyncWithRetry(this.authPath);\n\t\t\tconst current = existsSync(this.authPath) ? readFileSync(this.authPath, \"utf-8\") : undefined;\n\t\t\tconst { result, next } = fn(current);\n\t\t\tif (next !== undefined) {\n\t\t\t\twriteFileSync(this.authPath, next, AUTH_FILE_WRITE_OPTIONS);\n\t\t\t\tchmodSync(this.authPath, 0o600);\n\t\t\t}\n\t\t\treturn result;\n\t\t} finally {\n\t\t\tif (release) {\n\t\t\t\trelease();\n\t\t\t}\n\t\t}\n\t}\n\n\tasync withLockAsync<T>(fn: (current: string | undefined) => Promise<LockResult<T>>): Promise<T> {\n\t\tthis.ensureParentDir();\n\t\tthis.ensureFileExists();\n\n\t\tlet release: (() => Promise<void>) | undefined;\n\t\tlet lockCompromised = false;\n\t\tlet lockCompromisedError: Error | undefined;\n\t\tconst throwIfCompromised = () => {\n\t\t\tif (lockCompromised) {\n\t\t\t\tthrow lockCompromisedError ?? new Error(\"Auth storage lock was compromised\");\n\t\t\t}\n\t\t};\n\n\t\ttry {\n\t\t\trelease = await lockfile.lock(this.authPath, {\n\t\t\t\tretries: {\n\t\t\t\t\tretries: 10,\n\t\t\t\t\tfactor: 2,\n\t\t\t\t\tminTimeout: 100,\n\t\t\t\t\tmaxTimeout: 10000,\n\t\t\t\t\trandomize: true,\n\t\t\t\t},\n\t\t\t\tstale: 30000,\n\t\t\t\tonCompromised: (err) => {\n\t\t\t\t\tlockCompromised = true;\n\t\t\t\t\tlockCompromisedError = err;\n\t\t\t\t},\n\t\t\t});\n\n\t\t\tthrowIfCompromised();\n\t\t\tconst current = existsSync(this.authPath) ? readFileSync(this.authPath, \"utf-8\") : undefined;\n\t\t\tconst { result, next } = await fn(current);\n\t\t\tthrowIfCompromised();\n\t\t\tif (next !== undefined) {\n\t\t\t\twriteFileSync(this.authPath, next, AUTH_FILE_WRITE_OPTIONS);\n\t\t\t\tchmodSync(this.authPath, 0o600);\n\t\t\t}\n\t\t\tthrowIfCompromised();\n\t\t\treturn result;\n\t\t} finally {\n\t\t\tif (release) {\n\t\t\t\ttry {\n\t\t\t\t\tawait release();\n\t\t\t\t} catch {\n\t\t\t\t\t// Ignore unlock errors when lock is compromised.\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nexport class InMemoryAuthStorageBackend implements AuthStorageBackend {\n\tprivate value: string | undefined;\n\n\twithLock<T>(fn: (current: string | undefined) => LockResult<T>): T {\n\t\tconst { result, next } = fn(this.value);\n\t\tif (next !== undefined) {\n\t\t\tthis.value = next;\n\t\t}\n\t\treturn result;\n\t}\n\n\tasync withLockAsync<T>(fn: (current: string | undefined) => Promise<LockResult<T>>): Promise<T> {\n\t\tconst { result, next } = await fn(this.value);\n\t\tif (next !== undefined) {\n\t\t\tthis.value = next;\n\t\t}\n\t\treturn result;\n\t}\n}\n\n/**\n * Credential storage backed by a JSON file.\n */\nexport class AuthStorage {\n\tprivate data: AuthStorageData = {};\n\tprivate runtimeOverrides: Map<string, string> = new Map();\n\tprivate fallbackResolver?: (provider: string) => string | undefined;\n\tprivate loadError: Error | null = null;\n\tprivate errors: Error[] = [];\n\tprivate storage: AuthStorageBackend;\n\n\tprivate constructor(storage: AuthStorageBackend) {\n\t\tthis.storage = storage;\n\t\tthis.reload();\n\t}\n\n\tstatic create(authPath?: string): AuthStorage {\n\t\treturn new AuthStorage(new FileAuthStorageBackend(authPath ?? join(getAgentDir(), \"auth.json\")));\n\t}\n\n\tstatic fromStorage(storage: AuthStorageBackend): AuthStorage {\n\t\treturn new AuthStorage(storage);\n\t}\n\n\tstatic inMemory(data: AuthStorageData = {}): AuthStorage {\n\t\tconst storage = new InMemoryAuthStorageBackend();\n\t\tstorage.withLock(() => ({ result: undefined, next: JSON.stringify(data, null, 2) }));\n\t\treturn AuthStorage.fromStorage(storage);\n\t}\n\n\t/**\n\t * Set a runtime API key override (not persisted to disk).\n\t * Used for CLI --api-key flag.\n\t */\n\tsetRuntimeApiKey(provider: string, apiKey: string): void {\n\t\tthis.runtimeOverrides.set(provider, apiKey);\n\t}\n\n\t/**\n\t * Remove a runtime API key override.\n\t */\n\tremoveRuntimeApiKey(provider: string): void {\n\t\tthis.runtimeOverrides.delete(provider);\n\t}\n\n\t/**\n\t * Set a fallback resolver for API keys not found in auth.json or env vars.\n\t * Used for custom provider keys from models.json.\n\t */\n\tsetFallbackResolver(resolver: (provider: string) => string | undefined): void {\n\t\tthis.fallbackResolver = resolver;\n\t}\n\n\tprivate recordError(error: unknown): void {\n\t\tconst normalizedError = error instanceof Error ? error : new Error(String(error));\n\t\tthis.errors.push(normalizedError);\n\t}\n\n\tprivate parseStorageData(content: string | undefined): AuthStorageData {\n\t\tif (!content) {\n\t\t\treturn {};\n\t\t}\n\t\ttry {\n\t\t\treturn omitRetiredGrokOAuthProxy(JSON.parse(content) as AuthStorageData);\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new Error(`Failed to parse auth storage: ${message}`);\n\t\t}\n\t}\n\n\t/**\n\t * Reload credentials from storage.\n\t */\n\treload(): void {\n\t\tlet content: string | undefined;\n\t\ttry {\n\t\t\tthis.storage.withLock((current) => {\n\t\t\t\tcontent = current;\n\t\t\t\treturn { result: undefined };\n\t\t\t});\n\t\t\tthis.data = this.parseStorageData(content);\n\t\t\tthis.loadError = null;\n\t\t} catch (error) {\n\t\t\tthis.loadError = error as Error;\n\t\t\tthis.recordError(error);\n\t\t}\n\t}\n\n\tprivate persistProviderChange(provider: string, credential: AuthCredential | undefined): void {\n\t\tif (this.loadError) {\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tthis.storage.withLock((current) => {\n\t\t\t\tconst currentData = this.parseStorageData(current);\n\t\t\t\tconst merged: AuthStorageData = { ...currentData };\n\t\t\t\tif (provider === RETIRED_GROK_OAUTH_PROXY) {\n\t\t\t\t\tdelete merged[provider];\n\t\t\t\t} else if (credential) {\n\t\t\t\t\tmerged[provider] = credential;\n\t\t\t\t} else {\n\t\t\t\t\tdelete merged[provider];\n\t\t\t\t}\n\t\t\t\treturn { result: undefined, next: JSON.stringify(merged, null, 2) };\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tthis.recordError(error);\n\t\t}\n\t}\n\n\t/**\n\t * Get credential for a provider.\n\t */\n\tget(provider: string): AuthCredential | undefined {\n\t\tif (provider === RETIRED_GROK_OAUTH_PROXY) return undefined;\n\t\treturn this.data[provider] ?? undefined;\n\t}\n\n\t/**\n\t * Set credential for a provider.\n\t */\n\tset(provider: string, credential: AuthCredential): void {\n\t\tif (provider === RETIRED_GROK_OAUTH_PROXY) {\n\t\t\tdelete this.data[provider];\n\t\t\tthis.persistProviderChange(provider, undefined);\n\t\t\treturn;\n\t\t}\n\t\tthis.data[provider] = credential;\n\t\tthis.persistProviderChange(provider, credential);\n\t}\n\n\t/**\n\t * Remove credential for a provider.\n\t */\n\tremove(provider: string): void {\n\t\tdelete this.data[provider];\n\t\tthis.persistProviderChange(provider, undefined);\n\t}\n\n\t/**\n\t * List all providers with credentials.\n\t */\n\tlist(): string[] {\n\t\treturn Object.keys(this.data).filter((provider) => provider !== RETIRED_GROK_OAUTH_PROXY);\n\t}\n\n\t/**\n\t * Check if credentials exist for a provider in auth.json.\n\t */\n\thas(provider: string): boolean {\n\t\tif (provider === RETIRED_GROK_OAUTH_PROXY) return false;\n\t\treturn provider in this.data;\n\t}\n\n\t/**\n\t * Check if any form of auth is configured for a provider.\n\t * Unlike getApiKey(), this doesn't refresh OAuth tokens.\n\t */\n\thasAuth(provider: string): boolean {\n\t\tif (provider === RETIRED_GROK_OAUTH_PROXY) return false;\n\t\tif (this.runtimeOverrides.has(provider)) return true;\n\t\tif (this.data[provider]) return true;\n\t\tif (getEnvApiKey(provider)) return true;\n\t\tif (this.fallbackResolver?.(provider)) return true;\n\t\treturn false;\n\t}\n\n\t/** Return the number of stored OAuth accounts for a provider. */\n\tgetOAuthAccountCount(provider: string): number {\n\t\tconst credential = this.data[provider];\n\t\treturn credential?.type === \"oauth\" ? getOAuthAccounts(credential).length : 0;\n\t}\n\n\t/** Return safe, human-readable labels for every stored OAuth account. */\n\tlistOAuthAccounts(provider: string): OAuthAccountSummary[] {\n\t\tconst credential = this.data[provider];\n\t\tif (credential?.type !== \"oauth\") return [];\n\t\tconst accounts = getOAuthAccounts(credential);\n\t\tconst selectedIndex = getSelectedOAuthAccountIndex(credential, accounts.length);\n\t\treturn accounts.map((account, index) => ({\n\t\t\tindex,\n\t\t\tlabel: getOAuthAccountDisplayLabel(provider, account) ?? `Account ${index + 1}`,\n\t\t\tselected: index === selectedIndex,\n\t\t}));\n\t}\n\n\t/** Return the human-readable label of the selected OAuth account. */\n\tgetOAuthAccountLabel(provider: string): string | undefined {\n\t\treturn this.listOAuthAccounts(provider).find((account) => account.selected)?.label;\n\t}\n\n\t/** Explicitly select and persist the OAuth account used by this provider. */\n\tselectOAuthAccount(provider: string, accountIndex: number): void {\n\t\tthis.storage.withLock((current) => {\n\t\t\tconst currentData = this.parseStorageData(current);\n\t\t\tconst credential = currentData[provider];\n\t\t\tif (credential?.type !== \"oauth\") {\n\t\t\t\tthrow new Error(`No OAuth accounts configured for ${provider}`);\n\t\t\t}\n\t\t\tconst accounts = [...getOAuthAccounts(credential)];\n\t\t\tif (!Number.isInteger(accountIndex) || accountIndex < 0 || accountIndex >= accounts.length) {\n\t\t\t\tthrow new Error(`Invalid OAuth account index ${accountIndex} for ${provider}`);\n\t\t\t}\n\t\t\tconst merged: AuthStorageData = {\n\t\t\t\t...currentData,\n\t\t\t\t[provider]: createOAuthCredential(accounts, accountIndex),\n\t\t\t};\n\t\t\tthis.data = merged;\n\t\t\tthis.loadError = null;\n\t\t\treturn { result: undefined, next: JSON.stringify(merged, null, 2) };\n\t\t});\n\t}\n\n\t/**\n\t * Return the explicitly selected OAuth credentials without refreshing tokens.\n\t * Used by provider model customization hooks.\n\t */\n\tgetOAuthCredentials(provider: string): OAuthCredentials | undefined {\n\t\tconst credential = this.data[provider];\n\t\tif (credential?.type !== \"oauth\") {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst accounts = getOAuthAccounts(credential);\n\t\treturn accounts[getSelectedOAuthAccountIndex(credential, accounts.length)];\n\t}\n\n\t/**\n\t * Return auth status without exposing credential values or refreshing tokens.\n\t */\n\tgetAuthStatus(provider: string): AuthStatus {\n\t\tif (provider === RETIRED_GROK_OAUTH_PROXY) {\n\t\t\treturn { configured: false };\n\t\t}\n\t\tif (this.data[provider]) {\n\t\t\treturn { configured: true, source: \"stored\" };\n\t\t}\n\n\t\tif (this.runtimeOverrides.has(provider)) {\n\t\t\treturn { configured: false, source: \"runtime\", label: \"--api-key\" };\n\t\t}\n\n\t\tconst envKeys = findEnvKeys(provider);\n\t\tif (envKeys?.[0]) {\n\t\t\treturn { configured: false, source: \"environment\", label: envKeys[0] };\n\t\t}\n\n\t\tif (this.fallbackResolver?.(provider)) {\n\t\t\treturn { configured: false, source: \"fallback\", label: \"custom provider config\" };\n\t\t}\n\n\t\treturn { configured: false };\n\t}\n\n\t/**\n\t * Get all credentials (for passing to getOAuthApiKey).\n\t */\n\tgetAll(): AuthStorageData {\n\t\treturn omitRetiredGrokOAuthProxy({ ...this.data });\n\t}\n\n\tdrainErrors(): Error[] {\n\t\tconst drained = [...this.errors];\n\t\tthis.errors = [];\n\t\treturn drained;\n\t}\n\n\t/**\n\t * Login to an OAuth provider. Repeated logins append distinct accounts and\n\t * update an existing account when the provider exposes a stable identity.\n\t */\n\tasync login(providerId: OAuthProviderId, callbacks: OAuthLoginCallbacks): Promise<void> {\n\t\tconst provider = getOAuthProvider(providerId);\n\t\tif (!provider) {\n\t\t\tthrow new Error(`Unknown OAuth provider: ${providerId}`);\n\t\t}\n\n\t\tconst credentials = await provider.login(callbacks);\n\t\tif (this.loadError) {\n\t\t\tthis.data[providerId] = { type: \"oauth\", ...credentials };\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tthis.storage.withLock((current) => {\n\t\t\t\tconst currentData = this.parseStorageData(current);\n\t\t\t\tconst existing = currentData[providerId];\n\t\t\t\tlet credential: OAuthCredential;\n\n\t\t\t\tif (existing?.type === \"oauth\") {\n\t\t\t\t\tconst accounts = [...getOAuthAccounts(existing)];\n\t\t\t\t\tconst matchingIndex = findMatchingOAuthAccount(accounts, credentials);\n\t\t\t\t\tlet activeAccount: number;\n\t\t\t\t\tif (matchingIndex >= 0) {\n\t\t\t\t\t\taccounts[matchingIndex] = credentials;\n\t\t\t\t\t\tactiveAccount = matchingIndex;\n\t\t\t\t\t} else {\n\t\t\t\t\t\taccounts.push(credentials);\n\t\t\t\t\t\tactiveAccount = accounts.length - 1;\n\t\t\t\t\t}\n\t\t\t\t\tcredential = createOAuthCredential(accounts, activeAccount);\n\t\t\t\t} else {\n\t\t\t\t\tcredential = createOAuthCredential([credentials]);\n\t\t\t\t}\n\n\t\t\t\tconst merged: AuthStorageData = { ...currentData, [providerId]: credential };\n\t\t\t\tthis.data = merged;\n\t\t\t\tthis.loadError = null;\n\t\t\t\treturn { result: undefined, next: JSON.stringify(merged, null, 2) };\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tthis.recordError(error);\n\t\t}\n\t}\n\n\t/**\n\t * Logout from a provider.\n\t */\n\tlogout(provider: string): void {\n\t\tthis.remove(provider);\n\t}\n\n\t/** Resolve the explicitly selected account and refresh it under the storage lock. */\n\tprivate async resolveOAuthTokenWithLock(\n\t\tproviderId: OAuthProviderId,\n\t): Promise<{ apiKey: string; newCredentials: OAuthCredentials } | null> {\n\t\tconst provider = getOAuthProvider(providerId);\n\t\tif (!provider) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn this.storage.withLockAsync(async (current) => {\n\t\t\tconst currentData = this.parseStorageData(current);\n\t\t\tthis.data = currentData;\n\t\t\tthis.loadError = null;\n\n\t\t\tconst credential = currentData[providerId];\n\t\t\tif (credential?.type !== \"oauth\") {\n\t\t\t\treturn { result: null };\n\t\t\t}\n\n\t\t\tconst accounts = [...getOAuthAccounts(credential)];\n\t\t\tconst accountIndex = getSelectedOAuthAccountIndex(credential, accounts.length);\n\t\t\tconst account = accounts[accountIndex];\n\t\t\tif (!account) return { result: null };\n\n\t\t\tconst resolved =\n\t\t\t\tDate.now() < account.expires\n\t\t\t\t\t? { apiKey: provider.getApiKey(account), newCredentials: account }\n\t\t\t\t\t: await getOAuthApiKey(providerId, { [providerId]: account });\n\t\t\tif (!resolved) return { result: null };\n\n\t\t\tif (resolved.newCredentials === account) {\n\t\t\t\treturn { result: resolved };\n\t\t\t}\n\n\t\t\tconst newCredentials = { ...account, ...resolved.newCredentials };\n\t\t\taccounts[accountIndex] = newCredentials;\n\t\t\tconst merged: AuthStorageData = {\n\t\t\t\t...currentData,\n\t\t\t\t[providerId]: createOAuthCredential(accounts, accountIndex),\n\t\t\t};\n\t\t\tthis.data = merged;\n\t\t\treturn {\n\t\t\t\tresult: { ...resolved, newCredentials },\n\t\t\t\tnext: JSON.stringify(merged, null, 2),\n\t\t\t};\n\t\t});\n\t}\n\n\t/**\n\t * Get API key for a provider.\n\t * Priority:\n\t * 1. Runtime override (CLI --api-key)\n\t * 2. API key from auth.json\n\t * 3. OAuth token from auth.json (auto-refreshed with locking)\n\t * 4. Environment variable\n\t * 5. Fallback resolver (models.json custom providers)\n\t */\n\tasync getApiKey(providerId: string, options?: { includeFallback?: boolean }): Promise<string | undefined> {\n\t\t// Runtime override takes highest priority\n\t\tconst runtimeKey = this.runtimeOverrides.get(providerId);\n\t\tif (runtimeKey) {\n\t\t\treturn runtimeKey;\n\t\t}\n\n\t\tconst cred = this.data[providerId];\n\n\t\tif (cred?.type === \"api_key\") {\n\t\t\treturn resolveConfigValue(cred.key);\n\t\t}\n\n\t\tif (cred?.type === \"oauth\") {\n\t\t\ttry {\n\t\t\t\tconst result = await this.resolveOAuthTokenWithLock(providerId);\n\t\t\t\tif (result) {\n\t\t\t\t\treturn result.apiKey;\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tthis.recordError(error);\n\t\t\t\t// Credentials are preserved so a later request or /login can recover.\n\t\t\t\tthis.reload();\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t}\n\n\t\t// Fall back to environment variable\n\t\tconst envKey = getEnvApiKey(providerId);\n\t\tif (envKey) return envKey;\n\n\t\t// Fall back to custom resolver (e.g., models.json custom providers)\n\t\tif (options?.includeFallback !== false) {\n\t\t\treturn this.fallbackResolver?.(providerId) ?? undefined;\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Get all registered OAuth providers\n\t */\n\tgetOAuthProviders() {\n\t\treturn getOAuthProviders();\n\t}\n}\n"]}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { AssistantMessage } from "omk-ai";
|
|
2
|
+
/**
|
|
3
|
+
* Gates that run before any compaction evaluation. A message is skipped when
|
|
4
|
+
* compaction is disabled, when an aborted turn should not trigger it, or when
|
|
5
|
+
* the message predates the latest compaction boundary (stale usage/errors must
|
|
6
|
+
* not retrigger compaction right after one finished).
|
|
7
|
+
*/
|
|
8
|
+
export declare function shouldSkipCompactionCheck(input: {
|
|
9
|
+
readonly enabled: boolean;
|
|
10
|
+
readonly skipAbortedCheck: boolean;
|
|
11
|
+
readonly stopReason: string;
|
|
12
|
+
readonly messageTimestamp: number;
|
|
13
|
+
readonly latestCompactionTimestamp?: number;
|
|
14
|
+
}): boolean;
|
|
15
|
+
/**
|
|
16
|
+
* An overflow only counts as this session's own when the failing message came
|
|
17
|
+
* from the session model — or from the auto-routed vision model while the
|
|
18
|
+
* session model is text-only. Overflow from a model the user switched away
|
|
19
|
+
* from must not trigger compaction for the current one.
|
|
20
|
+
*/
|
|
21
|
+
export declare function isSessionModelOverflow(input: {
|
|
22
|
+
readonly message: AssistantMessage;
|
|
23
|
+
readonly contextWindow: number;
|
|
24
|
+
readonly sessionProvider?: string;
|
|
25
|
+
readonly sessionModelId?: string;
|
|
26
|
+
readonly sessionInputs?: readonly string[];
|
|
27
|
+
}): boolean;
|
|
28
|
+
//# sourceMappingURL=compaction-gate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compaction-gate.d.ts","sourceRoot":"","sources":["../../src/core/compaction-gate.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,QAAQ,CAAC;AAG/C;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE;IAChD,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC;IACnC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,yBAAyB,CAAC,EAAE,MAAM,CAAC;CAC5C,GAAG,OAAO,CAIV;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE;IAC7C,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAC;IACnC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC3C,GAAG,OAAO,CAYV","sourcesContent":["import { isVisionRouteModel } from \"omk-agent-core\";\nimport type { AssistantMessage } from \"omk-ai\";\nimport { isContextOverflow } from \"omk-ai\";\n\n/**\n * Gates that run before any compaction evaluation. A message is skipped when\n * compaction is disabled, when an aborted turn should not trigger it, or when\n * the message predates the latest compaction boundary (stale usage/errors must\n * not retrigger compaction right after one finished).\n */\nexport function shouldSkipCompactionCheck(input: {\n\treadonly enabled: boolean;\n\treadonly skipAbortedCheck: boolean;\n\treadonly stopReason: string;\n\treadonly messageTimestamp: number;\n\treadonly latestCompactionTimestamp?: number;\n}): boolean {\n\tif (!input.enabled) return true;\n\tif (input.skipAbortedCheck && input.stopReason === \"aborted\") return true;\n\treturn input.latestCompactionTimestamp !== undefined && input.messageTimestamp <= input.latestCompactionTimestamp;\n}\n\n/**\n * An overflow only counts as this session's own when the failing message came\n * from the session model — or from the auto-routed vision model while the\n * session model is text-only. Overflow from a model the user switched away\n * from must not trigger compaction for the current one.\n */\nexport function isSessionModelOverflow(input: {\n\treadonly message: AssistantMessage;\n\treadonly contextWindow: number;\n\treadonly sessionProvider?: string;\n\treadonly sessionModelId?: string;\n\treadonly sessionInputs?: readonly string[];\n}): boolean {\n\tconst sameModel =\n\t\tinput.sessionProvider !== undefined &&\n\t\tinput.sessionModelId !== undefined &&\n\t\tinput.message.provider === input.sessionProvider &&\n\t\tinput.message.model === input.sessionModelId;\n\tconst visionRouteOverflow =\n\t\tinput.sessionProvider !== undefined &&\n\t\t!(input.sessionInputs ?? []).includes(\"image\") &&\n\t\tisVisionRouteModel({ provider: input.message.provider, id: input.message.model });\n\tif (!sameModel && !visionRouteOverflow) return false;\n\treturn isContextOverflow(input.message, input.contextWindow);\n}\n"]}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { isVisionRouteModel } from "omk-agent-core";
|
|
2
|
+
import { isContextOverflow } from "omk-ai";
|
|
3
|
+
/**
|
|
4
|
+
* Gates that run before any compaction evaluation. A message is skipped when
|
|
5
|
+
* compaction is disabled, when an aborted turn should not trigger it, or when
|
|
6
|
+
* the message predates the latest compaction boundary (stale usage/errors must
|
|
7
|
+
* not retrigger compaction right after one finished).
|
|
8
|
+
*/
|
|
9
|
+
export function shouldSkipCompactionCheck(input) {
|
|
10
|
+
if (!input.enabled)
|
|
11
|
+
return true;
|
|
12
|
+
if (input.skipAbortedCheck && input.stopReason === "aborted")
|
|
13
|
+
return true;
|
|
14
|
+
return input.latestCompactionTimestamp !== undefined && input.messageTimestamp <= input.latestCompactionTimestamp;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* An overflow only counts as this session's own when the failing message came
|
|
18
|
+
* from the session model — or from the auto-routed vision model while the
|
|
19
|
+
* session model is text-only. Overflow from a model the user switched away
|
|
20
|
+
* from must not trigger compaction for the current one.
|
|
21
|
+
*/
|
|
22
|
+
export function isSessionModelOverflow(input) {
|
|
23
|
+
const sameModel = input.sessionProvider !== undefined &&
|
|
24
|
+
input.sessionModelId !== undefined &&
|
|
25
|
+
input.message.provider === input.sessionProvider &&
|
|
26
|
+
input.message.model === input.sessionModelId;
|
|
27
|
+
const visionRouteOverflow = input.sessionProvider !== undefined &&
|
|
28
|
+
!(input.sessionInputs ?? []).includes("image") &&
|
|
29
|
+
isVisionRouteModel({ provider: input.message.provider, id: input.message.model });
|
|
30
|
+
if (!sameModel && !visionRouteOverflow)
|
|
31
|
+
return false;
|
|
32
|
+
return isContextOverflow(input.message, input.contextWindow);
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=compaction-gate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compaction-gate.js","sourceRoot":"","sources":["../../src/core/compaction-gate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAEpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AAE3C;;;;;GAKG;AACH,MAAM,UAAU,yBAAyB,CAAC,KAMzC,EAAW;IACX,IAAI,CAAC,KAAK,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAChC,IAAI,KAAK,CAAC,gBAAgB,IAAI,KAAK,CAAC,UAAU,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IAC1E,OAAO,KAAK,CAAC,yBAAyB,KAAK,SAAS,IAAI,KAAK,CAAC,gBAAgB,IAAI,KAAK,CAAC,yBAAyB,CAAC;AAAA,CAClH;AAED;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CAAC,KAMtC,EAAW;IACX,MAAM,SAAS,GACd,KAAK,CAAC,eAAe,KAAK,SAAS;QACnC,KAAK,CAAC,cAAc,KAAK,SAAS;QAClC,KAAK,CAAC,OAAO,CAAC,QAAQ,KAAK,KAAK,CAAC,eAAe;QAChD,KAAK,CAAC,OAAO,CAAC,KAAK,KAAK,KAAK,CAAC,cAAc,CAAC;IAC9C,MAAM,mBAAmB,GACxB,KAAK,CAAC,eAAe,KAAK,SAAS;QACnC,CAAC,CAAC,KAAK,CAAC,aAAa,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC;QAC9C,kBAAkB,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;IACnF,IAAI,CAAC,SAAS,IAAI,CAAC,mBAAmB;QAAE,OAAO,KAAK,CAAC;IACrD,OAAO,iBAAiB,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC;AAAA,CAC7D","sourcesContent":["import { isVisionRouteModel } from \"omk-agent-core\";\nimport type { AssistantMessage } from \"omk-ai\";\nimport { isContextOverflow } from \"omk-ai\";\n\n/**\n * Gates that run before any compaction evaluation. A message is skipped when\n * compaction is disabled, when an aborted turn should not trigger it, or when\n * the message predates the latest compaction boundary (stale usage/errors must\n * not retrigger compaction right after one finished).\n */\nexport function shouldSkipCompactionCheck(input: {\n\treadonly enabled: boolean;\n\treadonly skipAbortedCheck: boolean;\n\treadonly stopReason: string;\n\treadonly messageTimestamp: number;\n\treadonly latestCompactionTimestamp?: number;\n}): boolean {\n\tif (!input.enabled) return true;\n\tif (input.skipAbortedCheck && input.stopReason === \"aborted\") return true;\n\treturn input.latestCompactionTimestamp !== undefined && input.messageTimestamp <= input.latestCompactionTimestamp;\n}\n\n/**\n * An overflow only counts as this session's own when the failing message came\n * from the session model — or from the auto-routed vision model while the\n * session model is text-only. Overflow from a model the user switched away\n * from must not trigger compaction for the current one.\n */\nexport function isSessionModelOverflow(input: {\n\treadonly message: AssistantMessage;\n\treadonly contextWindow: number;\n\treadonly sessionProvider?: string;\n\treadonly sessionModelId?: string;\n\treadonly sessionInputs?: readonly string[];\n}): boolean {\n\tconst sameModel =\n\t\tinput.sessionProvider !== undefined &&\n\t\tinput.sessionModelId !== undefined &&\n\t\tinput.message.provider === input.sessionProvider &&\n\t\tinput.message.model === input.sessionModelId;\n\tconst visionRouteOverflow =\n\t\tinput.sessionProvider !== undefined &&\n\t\t!(input.sessionInputs ?? []).includes(\"image\") &&\n\t\tisVisionRouteModel({ provider: input.message.provider, id: input.message.model });\n\tif (!sameModel && !visionRouteOverflow) return false;\n\treturn isContextOverflow(input.message, input.contextWindow);\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context-budget-system-prompt-items.d.ts","sourceRoot":"","sources":["../../src/core/context-budget-system-prompt-items.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,mBAAmB,EAAY,MAAM,iCAAiC,CAAC;AAErF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEzC,UAAU,2BAA2B;IACpC,QAAQ,CAAC,YAAY,EAAE,SAAS,WAAW,EAAE,CAAC;IAC9C,QAAQ,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,CAAC;IAClC,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC,QAAQ,CAAC,OAAO,EAAE;QACjB,QAAQ,CAAC,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;QAC9C,QAAQ,CAAC,qBAAqB,CAAC,EAAE,OAAO,CAAC;QACzC,QAAQ,CAAC,uBAAuB,CAAC,EAAE,OAAO,CAAC;QAC3C,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;QACpC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;KAC/B,CAAC;CACF;AAQD,wBAAgB,6BAA6B,CAC5C,KAAK,EAAE,2BAA2B,EAClC,cAAc,EAAE,MAAM,GACpB,mBAAmB,EAAE,
|
|
1
|
+
{"version":3,"file":"context-budget-system-prompt-items.d.ts","sourceRoot":"","sources":["../../src/core/context-budget-system-prompt-items.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,mBAAmB,EAAY,MAAM,iCAAiC,CAAC;AAErF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEzC,UAAU,2BAA2B;IACpC,QAAQ,CAAC,YAAY,EAAE,SAAS,WAAW,EAAE,CAAC;IAC9C,QAAQ,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,CAAC;IAClC,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC,QAAQ,CAAC,OAAO,EAAE;QACjB,QAAQ,CAAC,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;QAC9C,QAAQ,CAAC,qBAAqB,CAAC,EAAE,OAAO,CAAC;QACzC,QAAQ,CAAC,uBAAuB,CAAC,EAAE,OAAO,CAAC;QAC3C,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;QACpC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;KAC/B,CAAC;CACF;AAQD,wBAAgB,6BAA6B,CAC5C,KAAK,EAAE,2BAA2B,EAClC,cAAc,EAAE,MAAM,GACpB,mBAAmB,EAAE,CAqBvB;AAyID,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE7C","sourcesContent":["import { pathToFileURL } from \"node:url\";\nimport { type ContextBudgetItemV2, fnv1aHex } from \"./context-budget-governor-v2.ts\";\nimport { scoreContextFileRelevance, scoreSkillRelevance } from \"./context-budget-relevance.ts\";\nimport type { ContextFile } from \"./resource-loader.ts\";\nimport type { Skill } from \"./skills.ts\";\n\ninterface SystemPromptBudgetItemInput {\n\treadonly contextFiles: readonly ContextFile[];\n\treadonly skills: readonly Skill[];\n\treadonly includeSkills: boolean;\n\treadonly options: {\n\t\treadonly activeSkillNames?: readonly string[];\n\t\treadonly includeSkillInventory?: boolean;\n\t\treadonly includeFullContextFiles?: boolean;\n\t\treadonly maxInactiveSkills?: number;\n\t\treadonly queryContext?: string;\n\t};\n}\n\nconst CONTEXT_EXCERPT_CHARS = 1200;\nconst MIN_EXCERPT_CHARS = 400;\nconst MAX_EXCERPT_CHARS = 3000;\nconst MAX_INACTIVE_SKILLS = 15;\nconst CONTEXT_FULL_BUDGET_RATIO = 0.5;\n\nexport function createSystemPromptBudgetItems(\n\tinput: SystemPromptBudgetItemInput,\n\tresourceBudget: number,\n): ContextBudgetItemV2[] {\n\tconst items: ContextBudgetItemV2[] = [];\n\tconst contextFullCount = input.options.includeFullContextFiles !== false ? input.contextFiles.length : 0;\n\tconst excerptChars = computeExcerptChars(resourceBudget, contextFullCount);\n\n\tfor (const contextFile of input.contextFiles) {\n\t\tconst queryScore = scoreContextFileRelevance(\n\t\t\t{ path: contextFile.path, content: contextFile.content, isGlobal: contextFile.isGlobal ?? false },\n\t\t\tinput.options.queryContext,\n\t\t);\n\t\tpushContextItems(items, contextFile, queryScore, excerptChars, input.options.includeFullContextFiles !== false);\n\t}\n\n\tconst activeSkillNames = new Set(input.options.activeSkillNames ?? []);\n\tconst visibleSkills = input.skills.filter(\n\t\t(skill) => !skill.disableModelInvocation || activeSkillNames.has(skill.name),\n\t);\n\tif (input.includeSkills && input.options.includeSkillInventory !== false && visibleSkills.length > 0) {\n\t\tpushSkillItems(items, visibleSkills, input.options);\n\t}\n\treturn items;\n}\n\nfunction pushContextItems(\n\titems: ContextBudgetItemV2[],\n\tcontextFile: ContextFile,\n\tqueryScore: number,\n\texcerptChars: number,\n\tincludeFullContextFiles: boolean,\n): void {\n\tconst scope = contextFile.isGlobal ? \"parent\" : \"project\";\n\tconst tagName = contextFile.isGlobal ? \"parent_instructions\" : \"project_instructions\";\n\titems.push({\n\t\tid: `context-pointer:${contextFile.path}`,\n\t\ttier: contextFile.isGlobal ? \"system\" : \"current-files\",\n\t\tpriority: contextFile.isGlobal ? \"hard\" : \"high\",\n\t\trelevance: (contextFile.isGlobal ? 1 : 0.8) * 0.4 + queryScore * 0.6,\n\t\ttext: renderContextPointer(contextFile, scope),\n\t});\n\tif (!includeFullContextFiles) return;\n\titems.push({\n\t\tid: `context-full:${contextFile.path}`,\n\t\ttier: contextFile.isGlobal ? \"system\" : \"current-files\",\n\t\tpriority: contextFile.isGlobal ? \"high\" : \"medium\",\n\t\trelevance: (contextFile.isGlobal ? 0.9 : 0.6) * 0.4 + queryScore * 0.6,\n\t\tredundancyKey: contextFile.path,\n\t\tsourceRef: {\n\t\t\turi: pathToFileURL(contextFile.path).href,\n\t\t\tcontentHash: fnv1aHex(contextFile.content),\n\t\t\tretrievable: true,\n\t\t},\n\t\ttext: renderContextFull(contextFile, tagName, excerptChars),\n\t});\n}\n\nfunction pushSkillItems(\n\titems: ContextBudgetItemV2[],\n\tvisibleSkills: readonly Skill[],\n\toptions: SystemPromptBudgetItemInput[\"options\"],\n): void {\n\titems.push({ id: \"skill-header\", tier: \"skills\", priority: \"hard\", text: renderSkillHeader() });\n\tconst activeSkillNames = new Set(options.activeSkillNames ?? []);\n\tconst maxInactive = options.maxInactiveSkills ?? MAX_INACTIVE_SKILLS;\n\tfor (const skill of visibleSkills.filter((skill) => activeSkillNames.has(skill.name))) {\n\t\titems.push(renderSkillBudgetItem(skill, \"hard\", 1));\n\t}\n\n\tconst sortedInactive = visibleSkills\n\t\t.filter((skill) => !activeSkillNames.has(skill.name))\n\t\t.sort((a, b) => scoreSkillRelevance(b, options.queryContext) - scoreSkillRelevance(a, options.queryContext));\n\tfor (const skill of sortedInactive.slice(0, maxInactive)) {\n\t\titems.push(renderSkillBudgetItem(skill, \"low\", Math.max(0.25, scoreSkillRelevance(skill, options.queryContext))));\n\t}\n\titems.push({ id: \"skill-footer\", tier: \"skills\", priority: \"hard\", text: \"</available_skills>\" });\n\n\tconst omittedInactiveCount = sortedInactive.length - Math.min(sortedInactive.length, maxInactive);\n\tif (omittedInactiveCount > 0) {\n\t\titems.push({\n\t\t\tid: \"skill-omitted-summary\",\n\t\t\ttier: \"skills\",\n\t\t\tpriority: \"low\",\n\t\t\trelevance: 0.1,\n\t\t\ttext: `<!-- ${omittedInactiveCount} additional skills available. Use 'read' to load a specific skill file when a task matches. -->`,\n\t\t});\n\t}\n}\n\nfunction renderSkillBudgetItem(skill: Skill, priority: \"hard\" | \"low\", relevance: number): ContextBudgetItemV2 {\n\treturn {\n\t\tid: `skill:${skill.name}`,\n\t\ttier: \"skills\",\n\t\tpriority,\n\t\trelevance,\n\t\tredundancyKey: skill.name,\n\t\ttext: renderSkillEntry(skill, priority === \"hard\"),\n\t};\n}\n\nfunction computeExcerptChars(resourceBudget: number, contextFullCount: number): number {\n\tif (contextFullCount <= 0) {\n\t\treturn CONTEXT_EXCERPT_CHARS;\n\t}\n\tconst allocatedTokens = Math.floor(resourceBudget * CONTEXT_FULL_BUDGET_RATIO) / contextFullCount;\n\tconst estimatedChars = Math.floor(allocatedTokens * 4);\n\treturn Math.max(MIN_EXCERPT_CHARS, Math.min(MAX_EXCERPT_CHARS, estimatedChars));\n}\n\nfunction renderContextPointer(contextFile: ContextFile, scope: string): string {\n\tconst marker = contextFile.containsJailbreak ? \" sanitized=true\" : \"\";\n\treturn `<context_file_pointer scope=\"${escapeXml(scope)}\" path=\"${escapeXml(contextFile.path)}\"${marker} chars=\"${contextFile.content.length}\" />`;\n}\n\nfunction renderContextFull(contextFile: ContextFile, tagName: string, excerptChars = CONTEXT_EXCERPT_CHARS): string {\n\tconst content =\n\t\tcontextFile.content.length > excerptChars\n\t\t\t? boundedExcerpt(contextFile.content, excerptChars)\n\t\t\t: contextFile.content;\n\tconst truncated = content.length < contextFile.content.length ? \" truncated=true\" : \"\";\n\treturn `<${tagName} path=\"${escapeXml(contextFile.path)}\"${truncated}>\\n${escapeXmlText(content)}\\n</${tagName}>`;\n}\n\nfunction boundedExcerpt(content: string, excerptChars = CONTEXT_EXCERPT_CHARS): string {\n\tconst headChars = Math.floor(excerptChars * 0.7);\n\tconst tailChars = excerptChars - headChars;\n\tlet head = content.slice(0, headChars);\n\tconst lastSpace = head.search(/\\s+\\S*$/);\n\tif (lastSpace > headChars * 0.5) {\n\t\thead = head.slice(0, lastSpace);\n\t}\n\tlet tail = content.slice(-tailChars);\n\tconst firstSpace = tail.search(/\\S+\\s+/);\n\tif (firstSpace > 0 && firstSpace < tailChars * 0.5) {\n\t\ttail = tail.slice(firstSpace).trimStart();\n\t}\n\treturn `${head}\\n\\n[...context-budget excerpt omitted ${content.length - excerptChars} chars...]\\n\\n${tail}`;\n}\n\nfunction renderSkillHeader(): string {\n\treturn [\n\t\t\"\\n\\nThe following skills provide specialized instructions for specific tasks.\",\n\t\t\"Use the read tool to load a skill's file when the task matches its description.\",\n\t\t\"When a skill file references a relative path, resolve it against the skill directory (parent of SKILL.md / dirname of the path) and use that absolute path in tool commands.\",\n\t\t\"\",\n\t\t\"<available_skills>\",\n\t].join(\"\\n\");\n}\n\nfunction renderSkillEntry(skill: Skill, operatorDefault = false): string {\n\treturn [\n\t\t\" <skill>\",\n\t\t` <name>${escapeXml(skill.name)}</name>`,\n\t\t` <description>${escapeXml(skill.description)}</description>`,\n\t\t...(operatorDefault ? [\" <activation>operator-default</activation>\"] : []),\n\t\t` <location>${escapeXml(skill.filePath)}</location>`,\n\t\t\" </skill>\",\n\t].join(\"\\n\");\n}\n\nexport function escapeXmlText(str: string): string {\n\treturn str.replace(/&/g, \"&\").replace(/</g, \"<\").replace(/>/g, \">\");\n}\n\nexport function escapeXml(str: string): string {\n\treturn escapeXmlText(str).replace(/\"/g, \""\").replace(/'/g, \"'\");\n}\n"]}
|