diff --git a/sdk/.gitignore b/sdk/.gitignore index b592cbb0ad..0f7482c4bd 100644 --- a/sdk/.gitignore +++ b/sdk/.gitignore @@ -42,6 +42,9 @@ pnpm-lock.yaml # Session files / User data .cline/data .cline/tmp +.cline/**/managed.json +.cline/**/bundle.json + *.db *.db-shm *.db-wal diff --git a/sdk/apps/cli/src/tui/components/dialogs/provider-picker.tsx b/sdk/apps/cli/src/tui/components/dialogs/provider-picker.tsx index e64c117dc1..0a50665338 100644 --- a/sdk/apps/cli/src/tui/components/dialogs/provider-picker.tsx +++ b/sdk/apps/cli/src/tui/components/dialogs/provider-picker.tsx @@ -27,6 +27,7 @@ import { getDefaultAwsRegion, type ProviderConfigValues, resolveProviderConfigAwsRegion, + resolveProviderConfigSap, updateProviderConfigValue, } from "../../utils/provider-config-values"; import { getProviderSection } from "../../utils/provider-sections"; @@ -316,6 +317,11 @@ const DEFAULT_FIELD_LABELS: Partial> = { baseUrl: "Base URL", awsRegion: "AWS Region", awsProfile: "AWS Profile Name", + sapClientId: "Client ID", + sapClientSecret: "Client Secret", + sapTokenUrl: "Token URL", + sapResourceGroup: "Resource Group", + sapDeploymentId: "Deployment ID", }; const DEFAULT_FIELD_PLACEHOLDERS: Partial< @@ -325,6 +331,11 @@ const DEFAULT_FIELD_PLACEHOLDERS: Partial< baseUrl: "", awsRegion: "us-east-1", awsProfile: "default", + sapClientId: "sb-...|xsuaa_std!b...", + sapClientSecret: "SAP AI Core client secret", + sapTokenUrl: "https://.authentication.sap.hana.ondemand.com", + sapResourceGroup: "default", + sapDeploymentId: "", }; /** Render order for cycling focus with Tab. */ @@ -333,6 +344,11 @@ const FIELD_ORDER: ProviderConfigFieldKey[] = [ "baseUrl", "apiKey", "awsProfile", + "sapClientId", + "sapClientSecret", + "sapTokenUrl", + "sapResourceGroup", + "sapDeploymentId", ]; export type ProviderConfigInputFields = Partial< @@ -391,6 +407,19 @@ export function ProviderConfigInputContent( initial.apiKey = existingSettings?.apiKey?.trim() ?? ""; if (config.fields.awsProfile) initial.awsProfile = existingSettings?.aws?.profile?.trim() ?? ""; + if (config.fields.sapClientId) + initial.sapClientId = existingSettings?.sap?.clientId?.trim() ?? ""; + if (config.fields.sapClientSecret) + initial.sapClientSecret = + existingSettings?.sap?.clientSecret?.trim() ?? ""; + if (config.fields.sapTokenUrl) + initial.sapTokenUrl = existingSettings?.sap?.tokenUrl?.trim() ?? ""; + if (config.fields.sapResourceGroup) + initial.sapResourceGroup = + existingSettings?.sap?.resourceGroup?.trim() ?? "default"; + if (config.fields.sapDeploymentId) + initial.sapDeploymentId = + existingSettings?.sap?.deploymentId?.trim() ?? ""; return initial; }); @@ -402,6 +431,12 @@ export function ProviderConfigInputContent( const apiKey = values.apiKey?.trim(); const awsProfile = values.awsProfile?.trim(); const hasAwsFields = config.fields.awsRegion || config.fields.awsProfile; + const hasSapFields = + config.fields.sapClientId || + config.fields.sapClientSecret || + config.fields.sapTokenUrl || + config.fields.sapResourceGroup || + config.fields.sapDeploymentId; saveLocalProviderSettings(providerSettingsManager, { providerId, apiKey: config.fields.apiKey ? apiKey : undefined, @@ -413,6 +448,7 @@ export function ProviderConfigInputContent( profile: apiKey ? undefined : awsProfile || undefined, } : undefined, + sap: hasSapFields ? resolveProviderConfigSap(values) : undefined, }); resolve(true); }; diff --git a/sdk/apps/cli/src/tui/utils/provider-config-values.test.ts b/sdk/apps/cli/src/tui/utils/provider-config-values.test.ts index 52b492db40..92b75f69c7 100644 --- a/sdk/apps/cli/src/tui/utils/provider-config-values.test.ts +++ b/sdk/apps/cli/src/tui/utils/provider-config-values.test.ts @@ -5,6 +5,7 @@ import { afterEach, describe, expect, it } from "vitest"; import { getDefaultAwsRegion, resolveProviderConfigAwsRegion, + resolveProviderConfigSap, updateProviderConfigValue, } from "./provider-config-values"; @@ -64,4 +65,22 @@ describe("provider config values", () => { }), ).toBe("us-west-2"); }); + + it("resolves SAP AI Core field values into SAP settings", () => { + expect( + resolveProviderConfigSap({ + sapClientId: " client ", + sapClientSecret: " secret ", + sapTokenUrl: " https://auth.example ", + sapResourceGroup: " default ", + sapDeploymentId: " deployment ", + }), + ).toEqual({ + clientId: "client", + clientSecret: "secret", + tokenUrl: "https://auth.example", + resourceGroup: "default", + deploymentId: "deployment", + }); + }); }); diff --git a/sdk/apps/cli/src/tui/utils/provider-config-values.ts b/sdk/apps/cli/src/tui/utils/provider-config-values.ts index 49d819a36e..e78a089e11 100644 --- a/sdk/apps/cli/src/tui/utils/provider-config-values.ts +++ b/sdk/apps/cli/src/tui/utils/provider-config-values.ts @@ -20,6 +20,27 @@ export function resolveProviderConfigAwsRegion( return values.awsRegion?.trim() || getDefaultAwsRegion(values.awsProfile); } +export function resolveProviderConfigSap(values: ProviderConfigValues): + | { + clientId?: string; + clientSecret?: string; + tokenUrl?: string; + resourceGroup?: string; + deploymentId?: string; + } + | undefined { + const sap = { + clientId: values.sapClientId?.trim() || undefined, + clientSecret: values.sapClientSecret?.trim() || undefined, + tokenUrl: values.sapTokenUrl?.trim() || undefined, + resourceGroup: values.sapResourceGroup?.trim() || undefined, + deploymentId: values.sapDeploymentId?.trim() || undefined, + }; + return Object.values(sap).some((value) => value !== undefined) + ? sap + : undefined; +} + export function updateProviderConfigValue( previous: ProviderConfigValues, field: ProviderConfigFieldKey, diff --git a/sdk/apps/cli/src/tui/views/onboarding/controller.ts b/sdk/apps/cli/src/tui/views/onboarding/controller.ts index a814813b1e..a117780a8e 100644 --- a/sdk/apps/cli/src/tui/views/onboarding/controller.ts +++ b/sdk/apps/cli/src/tui/views/onboarding/controller.ts @@ -28,13 +28,14 @@ import { useSearchableList, } from "../../components/searchable-list"; import { palette } from "../../palette"; -import { getProviderSection } from "../../utils/provider-sections"; import { getDefaultAwsRegion, - resolveProviderConfigAwsRegion, - updateProviderConfigValue, type ProviderConfigValues, + resolveProviderConfigAwsRegion, + resolveProviderConfigSap, + updateProviderConfigValue, } from "../../utils/provider-config-values"; +import { getProviderSection } from "../../utils/provider-sections"; import { isOnboardingOAuthProviderId, type OnboardingOAuthProviderId, @@ -392,6 +393,24 @@ export function useOnboardingController(props: OnboardingControllerProps) { if (config.fields.awsProfile) { initialValues.awsProfile = existing?.aws?.profile?.trim() ?? ""; } + if (config.fields.sapClientId) { + initialValues.sapClientId = existing?.sap?.clientId?.trim() ?? ""; + } + if (config.fields.sapClientSecret) { + initialValues.sapClientSecret = + existing?.sap?.clientSecret?.trim() ?? ""; + } + if (config.fields.sapTokenUrl) { + initialValues.sapTokenUrl = existing?.sap?.tokenUrl?.trim() ?? ""; + } + if (config.fields.sapResourceGroup) { + initialValues.sapResourceGroup = + existing?.sap?.resourceGroup?.trim() ?? "default"; + } + if (config.fields.sapDeploymentId) { + initialValues.sapDeploymentId = + existing?.sap?.deploymentId?.trim() ?? ""; + } setByoValues(initialValues); // Focus the first visible field @@ -426,6 +445,12 @@ export function useOnboardingController(props: OnboardingControllerProps) { const apiKey = byoValues.apiKey?.trim(); const awsProfile = byoValues.awsProfile?.trim(); const hasAwsFields = byoFields.awsRegion || byoFields.awsProfile; + const hasSapFields = + byoFields.sapClientId || + byoFields.sapClientSecret || + byoFields.sapTokenUrl || + byoFields.sapResourceGroup || + byoFields.sapDeploymentId; saveLocalProviderSettings(providerSettingsManager, { providerId: activeProviderId, @@ -438,6 +463,7 @@ export function useOnboardingController(props: OnboardingControllerProps) { profile: apiKey ? undefined : awsProfile || undefined, } : undefined, + sap: hasSapFields ? resolveProviderConfigSap(byoValues) : undefined, }); // Emit a single `user.provider_configured` event mirroring the // `{ provider }` payload shape used by the auth funnel. The save above diff --git a/sdk/apps/cli/src/tui/views/onboarding/fields.ts b/sdk/apps/cli/src/tui/views/onboarding/fields.ts index 5973352d21..23c93b42d1 100644 --- a/sdk/apps/cli/src/tui/views/onboarding/fields.ts +++ b/sdk/apps/cli/src/tui/views/onboarding/fields.ts @@ -6,4 +6,9 @@ export const FIELD_ORDER: ProviderConfigFieldKey[] = [ "baseUrl", "apiKey", "awsProfile", + "sapClientId", + "sapClientSecret", + "sapTokenUrl", + "sapResourceGroup", + "sapDeploymentId", ]; diff --git a/sdk/apps/cli/src/tui/views/onboarding/screens.tsx b/sdk/apps/cli/src/tui/views/onboarding/screens.tsx index a1e3d167c6..5a23590e6b 100644 --- a/sdk/apps/cli/src/tui/views/onboarding/screens.tsx +++ b/sdk/apps/cli/src/tui/views/onboarding/screens.tsx @@ -224,6 +224,11 @@ const DEFAULT_FIELD_LABELS: Partial> = { baseUrl: "Base URL", awsRegion: "AWS Region", awsProfile: "AWS Profile Name", + sapClientId: "Client ID", + sapClientSecret: "Client Secret", + sapTokenUrl: "Token URL", + sapResourceGroup: "Resource Group", + sapDeploymentId: "Deployment ID", }; const DEFAULT_FIELD_PLACEHOLDERS: Partial< @@ -233,6 +238,11 @@ const DEFAULT_FIELD_PLACEHOLDERS: Partial< baseUrl: "", awsRegion: "us-east-1", awsProfile: "default", + sapClientId: "sb-...|xsuaa_std!b...", + sapClientSecret: "SAP AI Core client secret", + sapTokenUrl: "https://.authentication.sap.hana.ondemand.com", + sapResourceGroup: "default", + sapDeploymentId: "", }; export function OnboardingProviderConfigScreen(props: { diff --git a/sdk/apps/cli/src/utils/provider-readiness.test.ts b/sdk/apps/cli/src/utils/provider-readiness.test.ts index 687b6036d3..6536b5c969 100644 --- a/sdk/apps/cli/src/utils/provider-readiness.test.ts +++ b/sdk/apps/cli/src/utils/provider-readiness.test.ts @@ -142,6 +142,7 @@ describe("provider readiness", () => { expect( isProviderSettingsUsable("sapaicore", { provider: "sapaicore", + baseUrl: "https://api.ai.example.invalid", sap: { clientId: "client", clientSecret: "secret", @@ -149,5 +150,15 @@ describe("provider readiness", () => { }, } satisfies ProviderSettings), ).toBe(true); + expect( + isProviderSettingsUsable("sapaicore", { + provider: "sapaicore", + sap: { + clientId: "client", + clientSecret: "secret", + tokenUrl: "https://example.com/token", + }, + } satisfies ProviderSettings), + ).toBe(false); }); }); diff --git a/sdk/apps/cli/src/utils/provider-readiness.ts b/sdk/apps/cli/src/utils/provider-readiness.ts index a263e4104b..d804419068 100644 --- a/sdk/apps/cli/src/utils/provider-readiness.ts +++ b/sdk/apps/cli/src/utils/provider-readiness.ts @@ -45,7 +45,8 @@ function hasSapCredentials(settings: ProviderSettings): boolean { return ( hasText(sap?.clientId) && hasText(sap?.clientSecret) && - hasText(sap?.tokenUrl) + hasText(sap?.tokenUrl) && + hasText(settings.baseUrl) ); } @@ -68,6 +69,9 @@ export function isProviderSettingsUsable( hasAwsRegion(settings) ); } + if (normalizedProviderId === "sapaicore") { + return hasSapCredentials(settings); + } if (getPersistedProviderApiKey(normalizedProviderId, settings)) { return true; } @@ -84,9 +88,6 @@ export function isProviderSettingsUsable( if (normalizedProviderId === "azure") { return hasAzureCredentials(settings); } - if (normalizedProviderId === "sapaicore") { - return hasSapCredentials(settings); - } if (!fields.fields.baseUrl) { return false; } diff --git a/sdk/bun.lock b/sdk/bun.lock index e856c356a9..f63684ffee 100644 --- a/sdk/bun.lock +++ b/sdk/bun.lock @@ -19,7 +19,7 @@ }, "apps/cli": { "name": "@cline/cli", - "version": "3.0.11", + "version": "3.0.13", "bin": { "cline": "src/index.ts", }, @@ -350,6 +350,7 @@ "@ai-sdk/provider": "^3.0.8", "@aws-sdk/credential-providers": "^3.922.0", "@cline/shared": "workspace:*", + "@jerome-benoit/sap-ai-provider": "^4.6.0", "@langfuse/otel": "^4.0.0", "@opentelemetry/api": "^1.9.0", "@opentelemetry/sdk-trace-node": "^2.6.1", @@ -614,6 +615,10 @@ "@cline/vscode": ["@cline/vscode@workspace:apps/examples/vscode"], + "@colors/colors": ["@colors/colors@1.6.0", "", {}, "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA=="], + + "@dabh/diagnostics": ["@dabh/diagnostics@2.0.8", "", { "dependencies": { "@so-ric/colorspace": "^1.1.6", "enabled": "2.0.x", "kuler": "^2.0.0" } }, "sha512-R4MSXTVnuMzGD7bzHdW2ZhhdPC/igELENcq5IjEverBvq5hn1SXCWcsi6eSsdWP0/Ur+SItRRjAktmdoX/8R/Q=="], + "@date-fns/tz": ["@date-fns/tz@1.5.0", "", {}, "sha512-lwYN/vDPeNRULcepoE/LO2Pgx+7/RV+S9ARfbc9lr2DtGkOD7pAiruHvbR1RX3Qyf6ja47EWJDMsNK5vK08DJg=="], "@dimforge/rapier2d-simd-compat": ["@dimforge/rapier2d-simd-compat@0.17.3", "", {}, "sha512-bijvwWz6NHsNj5e5i1vtd3dU2pDhthSaTUZSh14DUGGKJfw8eMnlWZsxwHBxB/a3AXVNDjL9abuHw1k9FGR+jg=="], @@ -810,6 +815,8 @@ "@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="], + "@jerome-benoit/sap-ai-provider": ["@jerome-benoit/sap-ai-provider@4.6.9", "", { "dependencies": { "@ai-sdk/provider": "^3.0.10", "@ai-sdk/provider-utils": "^4.0.26", "@sap-ai-sdk/foundation-models": "^2.10.0", "@sap-ai-sdk/orchestration": "^2.10.0", "zod": "^4.4.2" }, "peerDependencies": { "ai": "^5.0.0 || ^6.0.0" } }, "sha512-z+ayDBasD2/PB4iAO6Lp6myQ96KZYjN/gBX3WAisaFKcCeRIsJyzHcBQh26lDu0cpzAybRmI5XUrWzn3nRaqgA=="], + "@jest/expect-utils": ["@jest/expect-utils@29.7.0", "", { "dependencies": { "jest-get-type": "^29.6.3" } }, "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA=="], "@jest/schemas": ["@jest/schemas@29.6.3", "", { "dependencies": { "@sinclair/typebox": "^0.27.8" } }, "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA=="], @@ -1186,6 +1193,30 @@ "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.1", "", {}, "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw=="], + "@sap-ai-sdk/ai-api": ["@sap-ai-sdk/ai-api@2.11.0", "", { "dependencies": { "@sap-ai-sdk/core": "^2.11.0", "@sap-cloud-sdk/connectivity": "^4.7.0", "@sap-cloud-sdk/util": "^4.7.0" } }, "sha512-KmBSIJfwSv7MlVFbNbZx9RQXT9P2hYvBQKPmAwURXc6Vh+UfNi1F2b45Nt8Yi90z+HFw0lsazgVN5wgav+qFGQ=="], + + "@sap-ai-sdk/core": ["@sap-ai-sdk/core@2.11.0", "", { "dependencies": { "@sap-cloud-sdk/connectivity": "^4.7.0", "@sap-cloud-sdk/http-client": "^4.7.0", "@sap-cloud-sdk/openapi": "^4.7.0", "@sap-cloud-sdk/util": "^4.7.0" } }, "sha512-6xJ0X88vi/eDG159rDs4S/g8Y6Gq9/B4O21oimIPccSJQF7WIB2+2Z4lFKTSBem/5E3FfxqknIZ/5bPX+/6lHA=="], + + "@sap-ai-sdk/foundation-models": ["@sap-ai-sdk/foundation-models@2.11.0", "", { "dependencies": { "@sap-ai-sdk/ai-api": "^2.11.0", "@sap-ai-sdk/core": "^2.11.0", "@sap-cloud-sdk/connectivity": "^4.7.0", "@sap-cloud-sdk/http-client": "^4.7.0", "@sap-cloud-sdk/util": "^4.7.0" } }, "sha512-AYRzR2+RA+9yCGzLymdUjcNPVDosXxHQrbFYNEcGicpYZu/Gy0WOc1GU/FCywfdqa0mGphSRpGCT+eduXLA1pw=="], + + "@sap-ai-sdk/orchestration": ["@sap-ai-sdk/orchestration@2.11.0", "", { "dependencies": { "@sap-ai-sdk/ai-api": "^2.11.0", "@sap-ai-sdk/core": "^2.11.0", "@sap-ai-sdk/prompt-registry": "^2.11.0", "@sap-cloud-sdk/util": "^4.6.0", "yaml": "^2.9.0" } }, "sha512-UR/erV97rtuEUXPGgMeDPmr3Yn2DLF5duQcvd4BleZ4bOSorarIj6igEd8XnBnGpSvcMCIgs5B6J2Vvi7E3+Ag=="], + + "@sap-ai-sdk/prompt-registry": ["@sap-ai-sdk/prompt-registry@2.11.0", "", { "dependencies": { "@sap-ai-sdk/core": "^2.11.0", "zod": "^4.4.3" } }, "sha512-1WrqGjwHltF/aOXoNDPYtvvaprQarPsKZUC0wSMeC6XZokoYvjvHNrltLm1IFygpjTr8yma45JJkKcwV1qzvDg=="], + + "@sap-cloud-sdk/connectivity": ["@sap-cloud-sdk/connectivity@4.7.0", "", { "dependencies": { "@sap-cloud-sdk/resilience": "^4.7.0", "@sap-cloud-sdk/util": "^4.7.0", "@sap/xsenv": "^6.2.0", "@sap/xssec": "^4.13.0", "async-retry": "^1.3.3", "axios": "^1.15.0", "jks-js": "^1.1.6", "jsonwebtoken": "^9.0.3", "safe-stable-stringify": "^2.5.0" } }, "sha512-+EgdTpGi3ZomPuv/ab+bWQIxUfJvownW2MzdYSvX7hkEkmKJfod0O6ja2OqC+OJBLm1TE0JpbJ6AcCkqeZYuOg=="], + + "@sap-cloud-sdk/http-client": ["@sap-cloud-sdk/http-client@4.7.0", "", { "dependencies": { "@sap-cloud-sdk/connectivity": "^4.7.0", "@sap-cloud-sdk/resilience": "^4.7.0", "@sap-cloud-sdk/util": "^4.7.0", "axios": "^1.15.0" } }, "sha512-7+S6ru7SrnyKA2MGimX09oix0EVwmPGcCAz0TRwFZVnglU+VTRmZ8QdcwcVTR26E9YhkR4OVl6EK7jb2Z0OxfQ=="], + + "@sap-cloud-sdk/openapi": ["@sap-cloud-sdk/openapi@4.7.0", "", { "dependencies": { "@sap-cloud-sdk/connectivity": "^4.7.0", "@sap-cloud-sdk/http-client": "^4.7.0", "@sap-cloud-sdk/resilience": "^4.7.0", "@sap-cloud-sdk/util": "^4.7.0", "axios": "^1.15.0" } }, "sha512-OKTEGVScCRsfgL9Lk/bEKcGnyfq0GgruXuZfsxoMbTqbe2f9X/fgHgXIWQEkTuXQplkrSDiNFRyvl0n/ON9Ycg=="], + + "@sap-cloud-sdk/resilience": ["@sap-cloud-sdk/resilience@4.7.0", "", { "dependencies": { "@sap-cloud-sdk/util": "^4.7.0", "async-retry": "^1.3.3", "axios": "^1.15.0", "opossum": "^9.0.0" } }, "sha512-L6PV49nNyZHnTNFbvaufadm+qOhaammXLXkDQmD7WIzMjhiYMqa/obK3NJoohe/kZ7q73jPB2vdLsAqopqTh0A=="], + + "@sap-cloud-sdk/util": ["@sap-cloud-sdk/util@4.7.0", "", { "dependencies": { "axios": "^1.15.0", "logform": "^2.7.0", "voca": "^1.4.1", "winston": "^3.19.0", "winston-transport": "^4.9.0" } }, "sha512-nWJXMdM0Pcx/ipM2+5BvSciQKyCc0LAAO+acCOAQp65SA4HEQ2Odp9yxidY4ijW42TVp3fSMBvGwVjbWWx9Uew=="], + + "@sap/xsenv": ["@sap/xsenv@6.2.1", "", { "dependencies": { "debug": "4.4.3", "node-cache": "^5.1.2", "verror": "1.10.1" } }, "sha512-R1p7VdD3N3jvdkL8av4vLqF+cTQihTz9mCqqF+oa9rVZvgLaCb4ODyZ1dln5/fBgg1OSuch0ESxu3AqZrXVknw=="], + + "@sap/xssec": ["@sap/xssec@4.13.0", "", { "dependencies": { "debug": "^4.4.3", "jwt-decode": "^4" } }, "sha512-8e+bU+OyAIpAGXQanOopZa5YEK+yHKw84dhhihcCotF40MSNFbVHjQ4xM5hf4QndlqDGfXIuvXmoOMuDATa/gA=="], + "@sapphire/async-queue": ["@sapphire/async-queue@1.5.5", "", {}, "sha512-cvGzxbba6sav2zZkH8GPf2oGk9yYoD5qrNWdu9fRehifgnFZJMV+nuy2nON2roRO4yQQ+v7MK/Pktl/HgfsUXg=="], "@sapphire/shapeshift": ["@sapphire/shapeshift@4.0.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "lodash": "^4.17.21" } }, "sha512-d9dUmWVA7MMiKobL3VpLF8P2aeanRTu6ypG2OIaEv/ZHH/SUQ2iHOVyi5wAPjQ+HmnMuL0whK9ez8I/raWbtIg=="], @@ -1246,6 +1277,8 @@ "@smithy/util-utf8": ["@smithy/util-utf8@4.3.4", "", { "dependencies": { "@smithy/core": "^3.24.4", "tslib": "^2.6.2" } }, "sha512-s8lfXcv+5C2GjBwGUBqFLgNmhyp9/n4TSKbOzKlIqJ/x0L/zwIxjNBC6DN4xUy59NvOrsiZI1t3tWi4ADUDyNw=="], + "@so-ric/colorspace": ["@so-ric/colorspace@1.1.6", "", { "dependencies": { "color": "^5.0.2", "text-hex": "1.0.x" } }, "sha512-/KiKkpHNOBgkFJwu9sh48LkHSMYGyuTcSFK/qMBdnOAlrRJzRSXAOFB5qwzaVQuDl8wAvHVMkaASQDReTahxuw=="], + "@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], "@streamdown/cjk": ["@streamdown/cjk@1.0.3", "", { "dependencies": { "remark-cjk-friendly": "^2.0.1", "remark-cjk-friendly-gfm-strikethrough": "^2.0.1", "unist-util-visit": "^5.0.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0" } }, "sha512-WRg8HR/gHbBoTgsMd91OKFUClIoDcEFVofJvluvEAyjx3KpU0aGgD9tGDqHkHj14ShoMSkX0IYetWGegTcwIJw=="], @@ -1470,6 +1503,8 @@ "@types/statuses": ["@types/statuses@2.0.6", "", {}, "sha512-xMAgYwceFhRA2zY+XbEA7mxYbA093wdiW8Vu6gZPGWy9cmOyU9XesH1tNcEWsKFd5Vzrqx5T3D38PWx1FIIXkA=="], + "@types/triple-beam": ["@types/triple-beam@1.3.5", "", {}, "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw=="], + "@types/trusted-types": ["@types/trusted-types@2.0.7", "", {}, "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw=="], "@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="], @@ -1580,10 +1615,18 @@ "aria-hidden": ["aria-hidden@1.2.6", "", { "dependencies": { "tslib": "^2.0.0" } }, "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA=="], + "asn1": ["asn1@0.2.6", "", { "dependencies": { "safer-buffer": "~2.1.0" } }, "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ=="], + + "assert-plus": ["assert-plus@1.0.0", "", {}, "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw=="], + "assertion-error": ["assertion-error@2.0.1", "", {}, "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA=="], "ast-types": ["ast-types@0.16.1", "", { "dependencies": { "tslib": "^2.0.1" } }, "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg=="], + "async": ["async@3.2.6", "", {}, "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA=="], + + "async-retry": ["async-retry@1.3.3", "", { "dependencies": { "retry": "0.13.1" } }, "sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw=="], + "asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="], "atomic-sleep": ["atomic-sleep@1.0.0", "", {}, "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ=="], @@ -1686,16 +1729,22 @@ "cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="], + "clone": ["clone@2.1.2", "", {}, "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w=="], + "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="], "cmdk": ["cmdk@1.1.1", "", { "dependencies": { "@radix-ui/react-compose-refs": "^1.1.1", "@radix-ui/react-dialog": "^1.1.6", "@radix-ui/react-id": "^1.1.0", "@radix-ui/react-primitive": "^2.0.2" }, "peerDependencies": { "react": "^18 || ^19 || ^19.0.0-rc", "react-dom": "^18 || ^19 || ^19.0.0-rc" } }, "sha512-Vsv7kFaXm+ptHDMZ7izaRsP70GgrW9NBNGswt9OZaVBLlE0SNpDq8eu/VGXyF9r7M0azK3Wy7OlYXsuyYLFzHg=="], "code-block-writer": ["code-block-writer@13.0.3", "", {}, "sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg=="], + "color": ["color@5.0.3", "", { "dependencies": { "color-convert": "^3.1.3", "color-string": "^2.1.3" } }, "sha512-ezmVcLR3xAVp8kYOm4GS45ZLLgIE6SPAFoduLr6hTDajwb3KZ2F46gulK3XpcwRFb5KKGCSezCBAY4Dw4HsyXA=="], + "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], + "color-string": ["color-string@2.1.4", "", { "dependencies": { "color-name": "^2.0.0" } }, "sha512-Bb6Cq8oq0IjDOe8wJmi4JeNn763Xs9cfrBcaylK1tPypWzyoy2G3l90v9k64kjphl/ZJjPIShFztenRomi8WTg=="], + "colorette": ["colorette@2.0.20", "", {}, "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w=="], "combined-stream": ["combined-stream@1.0.8", "", { "dependencies": { "delayed-stream": "~1.0.0" } }, "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg=="], @@ -1716,6 +1765,8 @@ "cookie-signature": ["cookie-signature@1.2.2", "", {}, "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg=="], + "core-util-is": ["core-util-is@1.0.2", "", {}, "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ=="], + "cors": ["cors@2.8.6", "", { "dependencies": { "object-assign": "^4", "vary": "^1" } }, "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw=="], "cose-base": ["cose-base@1.0.3", "", { "dependencies": { "layout-base": "^1.0.0" } }, "sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg=="], @@ -1878,6 +1929,8 @@ "emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="], + "enabled": ["enabled@2.0.0", "", {}, "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ=="], + "encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="], "enhanced-resolve": ["enhanced-resolve@5.22.0", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.3" } }, "sha512-xYcDWrpELkFzz9SpZ3PlI6Eu6eD93Yf0WLDRxikGhWJ3MAir2SNZTIVCVZqZ/NUyx8AdMc2gT9C0gPiw18kG+A=="], @@ -1968,6 +2021,8 @@ "extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="], + "extsprintf": ["extsprintf@1.4.1", "", {}, "sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA=="], + "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], "fast-equals": ["fast-equals@5.4.0", "", {}, "sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw=="], @@ -1994,6 +2049,8 @@ "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], + "fecha": ["fecha@4.2.3", "", {}, "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw=="], + "fetch-blob": ["fetch-blob@3.2.0", "", { "dependencies": { "node-domexception": "^1.0.0", "web-streams-polyfill": "^3.0.3" } }, "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ=="], "figures": ["figures@6.1.0", "", { "dependencies": { "is-unicode-supported": "^2.0.0" } }, "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg=="], @@ -2012,6 +2069,8 @@ "flatted": ["flatted@3.4.2", "", {}, "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA=="], + "fn.name": ["fn.name@1.1.0", "", {}, "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw=="], + "follow-redirects": ["follow-redirects@1.16.0", "", {}, "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw=="], "foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="], @@ -2224,6 +2283,8 @@ "jiti": ["jiti@2.7.0", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ=="], + "jks-js": ["jks-js@1.1.7", "", { "dependencies": { "node-forge": "^1.4.0", "node-int64": "^0.4.0", "node-rsa": "^1.1.1" } }, "sha512-BeiDRKsAi1NwEwgx2JB/9/0tar5BNGIv+foGm1G5GgiyR35s/iUnfd/BWqYd16mLDD8qTaAVBrIcOOuVqXJZNQ=="], + "jose": ["jose@6.2.3", "", {}, "sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw=="], "jpeg-js": ["jpeg-js@0.4.4", "", {}, "sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg=="], @@ -2258,10 +2319,14 @@ "jsonrepair": ["jsonrepair@3.14.0", "", { "bin": { "jsonrepair": "bin/cli.js" } }, "sha512-tWPGKMZf/8UPim+fcW2EfcQ/d/7aKUrP6IECz9G3Tu6Q5dX0orSleqJ9z6sSw7qrQkjF8/Edo4DvsWBZ8H+HNg=="], + "jsonwebtoken": ["jsonwebtoken@9.0.3", "", { "dependencies": { "jws": "^4.0.1", "lodash.includes": "^4.3.0", "lodash.isboolean": "^3.0.3", "lodash.isinteger": "^4.0.4", "lodash.isnumber": "^3.0.3", "lodash.isplainobject": "^4.0.6", "lodash.isstring": "^4.0.1", "lodash.once": "^4.0.0", "ms": "^2.1.1", "semver": "^7.5.4" } }, "sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g=="], + "jwa": ["jwa@2.0.1", "", { "dependencies": { "buffer-equal-constant-time": "^1.0.1", "ecdsa-sig-formatter": "1.0.11", "safe-buffer": "^5.0.1" } }, "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg=="], "jws": ["jws@4.0.1", "", { "dependencies": { "jwa": "^2.0.1", "safe-buffer": "^5.0.1" } }, "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA=="], + "jwt-decode": ["jwt-decode@4.0.0", "", {}, "sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA=="], + "katex": ["katex@0.16.47", "", { "dependencies": { "commander": "^8.3.0" }, "bin": { "katex": "cli.js" } }, "sha512-Eeo8Ys1doU1z+x8AZsPpQu+p/QcZBI5PeOo7QGQdy2x2m0MU/hYagBbGOmXwr5KVbEfVuWv9LpnQWeehogurjg=="], "keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="], @@ -2270,6 +2335,8 @@ "kleur": ["kleur@4.1.5", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="], + "kuler": ["kuler@2.0.0", "", {}, "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A=="], + "layout-base": ["layout-base@1.0.2", "", {}, "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg=="], "levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="], @@ -2312,14 +2379,30 @@ "lodash-es": ["lodash-es@4.18.1", "", {}, "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A=="], + "lodash.includes": ["lodash.includes@4.3.0", "", {}, "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w=="], + + "lodash.isboolean": ["lodash.isboolean@3.0.3", "", {}, "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg=="], + + "lodash.isinteger": ["lodash.isinteger@4.0.4", "", {}, "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA=="], + + "lodash.isnumber": ["lodash.isnumber@3.0.3", "", {}, "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw=="], + + "lodash.isplainobject": ["lodash.isplainobject@4.0.6", "", {}, "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA=="], + + "lodash.isstring": ["lodash.isstring@4.0.1", "", {}, "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw=="], + "lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="], + "lodash.once": ["lodash.once@4.1.1", "", {}, "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg=="], + "lodash.snakecase": ["lodash.snakecase@4.1.1", "", {}, "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw=="], "log-symbols": ["log-symbols@6.0.0", "", { "dependencies": { "chalk": "^5.3.0", "is-unicode-supported": "^1.3.0" } }, "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw=="], "log-update": ["log-update@6.1.0", "", { "dependencies": { "ansi-escapes": "^7.0.0", "cli-cursor": "^5.0.0", "slice-ansi": "^7.1.0", "strip-ansi": "^7.1.0", "wrap-ansi": "^9.0.0" } }, "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w=="], + "logform": ["logform@2.7.0", "", { "dependencies": { "@colors/colors": "1.6.0", "@types/triple-beam": "^1.3.2", "fecha": "^4.2.0", "ms": "^2.1.1", "safe-stable-stringify": "^2.3.1", "triple-beam": "^1.3.0" } }, "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ=="], + "long": ["long@5.3.2", "", {}, "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="], "longest-streak": ["longest-streak@3.1.0", "", {}, "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g=="], @@ -2490,16 +2573,24 @@ "node-addon-api": ["node-addon-api@7.1.1", "", {}, "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ=="], + "node-cache": ["node-cache@5.1.2", "", { "dependencies": { "clone": "2.x" } }, "sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg=="], + "node-domexception": ["node-domexception@1.0.0", "", {}, "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="], "node-fetch": ["node-fetch@3.3.2", "", { "dependencies": { "data-uri-to-buffer": "^4.0.0", "fetch-blob": "^3.1.4", "formdata-polyfill": "^4.0.10" } }, "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA=="], + "node-forge": ["node-forge@1.4.0", "", {}, "sha512-LarFH0+6VfriEhqMMcLX2F7SwSXeWwnEAJEsYm5QKWchiVYVvJyV9v7UDvUv+w5HO23ZpQTXDv/GxdDdMyOuoQ=="], + + "node-int64": ["node-int64@0.4.0", "", {}, "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw=="], + "node-machine-id": ["node-machine-id@1.1.12", "", {}, "sha512-QNABxbrPa3qEIfrE6GOJ7BYIuignnJw7iQ2YPbc3Nla1HzRJjXzZOiikfF8m7eAMfichLt3M4VgLOetqgDmgGQ=="], "node-pty": ["node-pty@1.2.0-beta.11", "", { "dependencies": { "node-addon-api": "^7.1.0" } }, "sha512-THcUyu1WwdgoIyUvgXOZ70EOMXzheGa0q3tbEb5kUIfKgcpBJ+AJ9Q1kq0bKtYmQzr77usXiTORZTLmAUQlnoQ=="], "node-releases": ["node-releases@2.0.46", "", {}, "sha512-GYVXHE2KnrzAfsAjl4uP++evGFCrAU1jta4ubEjIG7YWt/64Gqv66a30yKwWczVjA6j3bM4nBwH7Pk1JmDHaxQ=="], + "node-rsa": ["node-rsa@1.1.1", "", { "dependencies": { "asn1": "^0.2.4" } }, "sha512-Jd4cvbJMryN21r5HgxQOpMEqv+ooke/korixNNK3mGqfGJmy0M77WDDzo/05969+OkMy3XW1UuZsSmW9KQm7Fw=="], + "npm-run-path": ["npm-run-path@6.0.0", "", { "dependencies": { "path-key": "^4.0.0", "unicorn-magic": "^0.3.0" } }, "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA=="], "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], @@ -2518,6 +2609,8 @@ "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="], + "one-time": ["one-time@1.0.0", "", { "dependencies": { "fn.name": "1.x.x" } }, "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g=="], + "onetime": ["onetime@5.1.2", "", { "dependencies": { "mimic-fn": "^2.1.0" } }, "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="], "oniguruma-parser": ["oniguruma-parser@0.12.2", "", {}, "sha512-6HVa5oIrgMC6aA6WF6XyyqbhRPJrKR02L20+2+zpDtO5QAzGHAUGw5TKQvwi5vctNnRHkJYmjAhRVQF2EKdTQw=="], @@ -2528,6 +2621,8 @@ "opentui-spinner": ["opentui-spinner@0.0.6", "", { "dependencies": { "cli-spinners": "^3.3.0" }, "peerDependencies": { "@opentui/core": "^0.1.49", "@opentui/react": "^0.1.49", "@opentui/solid": "^0.1.49", "typescript": "^5" }, "optionalPeers": ["@opentui/react", "@opentui/solid"] }, "sha512-xupLOeVQEAXEvVJCvHkfX6fChDWmJIPHe5jyUrVb8+n4XVTX8mBNhitFfB9v2ZbkC1H2UwPab/ElePHoW37NcA=="], + "opossum": ["opossum@9.0.0", "", {}, "sha512-K76U0QkxOfUZamneQuzz+AP0fyfTJcCplZ2oZL93nxeupuJbN4s6uFNbmVCt4eWqqGqRnnowdFuBicJ1fLMVxw=="], + "optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="], "ora": ["ora@8.2.0", "", { "dependencies": { "chalk": "^5.3.0", "cli-cursor": "^5.0.0", "cli-spinners": "^2.9.2", "is-interactive": "^2.0.0", "is-unicode-supported": "^2.0.0", "log-symbols": "^6.0.0", "stdin-discarder": "^0.2.2", "string-width": "^7.2.0", "strip-ansi": "^7.1.0" } }, "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw=="], @@ -2686,7 +2781,7 @@ "react-transition-group": ["react-transition-group@4.4.5", "", { "dependencies": { "@babel/runtime": "^7.5.5", "dom-helpers": "^5.0.1", "loose-envify": "^1.4.0", "prop-types": "^15.6.2" }, "peerDependencies": { "react": ">=16.6.0", "react-dom": ">=16.6.0" } }, "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g=="], - "readable-stream": ["readable-stream@4.7.0", "", { "dependencies": { "abort-controller": "^3.0.0", "buffer": "^6.0.3", "events": "^3.3.0", "process": "^0.11.10", "string_decoder": "^1.3.0" } }, "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg=="], + "readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], "readable-web-to-node-stream": ["readable-web-to-node-stream@3.0.4", "", { "dependencies": { "readable-stream": "^4.7.0" } }, "sha512-9nX56alTf5bwXQ3ZDipHJhusu9NTQJ/CVPtb/XHAJCXihZeitfJvIRS4GqQ/mfIoOE3IelHMrpayVrosdHBuLw=="], @@ -2826,6 +2921,8 @@ "split2": ["split2@4.2.0", "", {}, "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg=="], + "stack-trace": ["stack-trace@0.0.10", "", {}, "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg=="], + "stack-utils": ["stack-utils@2.0.6", "", { "dependencies": { "escape-string-regexp": "^2.0.0" } }, "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ=="], "stackback": ["stackback@0.0.2", "", {}, "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw=="], @@ -2888,6 +2985,8 @@ "tapable": ["tapable@2.3.3", "", {}, "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A=="], + "text-hex": ["text-hex@1.0.0", "", {}, "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg=="], + "thread-stream": ["thread-stream@4.2.0", "", { "dependencies": { "real-require": "^1.0.0" } }, "sha512-e2zZ96wSChazBsbENf/Pcm/4swHt2cEKQ92rhUjkL9GCKiTDJIaTBenjE/m9DXi0QBmTMDkFDdOomUy20A1tDQ=="], "three": ["three@0.177.0", "", {}, "sha512-EiXv5/qWAaGI+Vz2A+JfavwYCMdGjxVsrn3oBwllUoqYeaBO75J63ZfyaQKoiLrqNHoTlUc6PFgMXnS0kI45zg=="], @@ -2922,6 +3021,8 @@ "trim-lines": ["trim-lines@3.0.1", "", {}, "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg=="], + "triple-beam": ["triple-beam@1.4.1", "", {}, "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg=="], + "trough": ["trough@2.2.0", "", {}, "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw=="], "ts-algebra": ["ts-algebra@2.0.0", "", {}, "sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw=="], @@ -3006,6 +3107,8 @@ "vaul": ["vaul@1.1.2", "", { "dependencies": { "@radix-ui/react-dialog": "^1.1.1" }, "peerDependencies": { "react": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-ZFkClGpWyI2WUQjdLJ/BaGuV6AVQiJ3uELGk3OYtP+B6yCO7Cmn9vPFXVJkRaGkOJu3m8bQMgtyzNHixULceQA=="], + "verror": ["verror@1.10.1", "", { "dependencies": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", "extsprintf": "^1.2.0" } }, "sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg=="], + "vfile": ["vfile@6.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile-message": "^4.0.0" } }, "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q=="], "vfile-location": ["vfile-location@5.0.3", "", { "dependencies": { "@types/unist": "^3.0.0", "vfile": "^6.0.0" } }, "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg=="], @@ -3018,6 +3121,8 @@ "vitest": ["vitest@4.1.7", "", { "dependencies": { "@vitest/expect": "4.1.7", "@vitest/mocker": "4.1.7", "@vitest/pretty-format": "4.1.7", "@vitest/runner": "4.1.7", "@vitest/snapshot": "4.1.7", "@vitest/spy": "4.1.7", "@vitest/utils": "4.1.7", "es-module-lexer": "^2.0.0", "expect-type": "^1.3.0", "magic-string": "^0.30.21", "obug": "^2.1.1", "pathe": "^2.0.3", "picomatch": "^4.0.3", "std-env": "^4.0.0-rc.1", "tinybench": "^2.9.0", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "tinyrainbow": "^3.1.0", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", "@vitest/browser-playwright": "4.1.7", "@vitest/browser-preview": "4.1.7", "@vitest/browser-webdriverio": "4.1.7", "@vitest/coverage-istanbul": "4.1.7", "@vitest/coverage-v8": "4.1.7", "@vitest/ui": "4.1.7", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@opentelemetry/api", "@types/node", "@vitest/browser-playwright", "@vitest/browser-preview", "@vitest/browser-webdriverio", "@vitest/coverage-istanbul", "@vitest/coverage-v8", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "vitest.mjs" } }, "sha512-flYyaFd2CgoCoU+0UKt3pxksgC+S02iTDN0n3LtqaMeXsI9SBcdNujc2k0DeFLzUn/0k538yNjOSdwgCqcrwJA=="], + "voca": ["voca@1.4.1", "", {}, "sha512-NJC/BzESaHT1p4B5k4JykxedeltmNbau4cummStd4RjFojgq/kLew5TzYge9N2geeWyI2w8T30wUET5v+F7ZHA=="], + "web-namespaces": ["web-namespaces@2.0.1", "", {}, "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ=="], "web-streams-polyfill": ["web-streams-polyfill@3.3.3", "", {}, "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw=="], @@ -3030,6 +3135,10 @@ "why-is-node-running": ["why-is-node-running@2.3.0", "", { "dependencies": { "siginfo": "^2.0.0", "stackback": "0.0.2" }, "bin": { "why-is-node-running": "cli.js" } }, "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w=="], + "winston": ["winston@3.19.0", "", { "dependencies": { "@colors/colors": "^1.6.0", "@dabh/diagnostics": "^2.0.8", "async": "^3.2.3", "is-stream": "^2.0.0", "logform": "^2.7.0", "one-time": "^1.0.0", "readable-stream": "^3.4.0", "safe-stable-stringify": "^2.3.1", "stack-trace": "0.0.x", "triple-beam": "^1.3.0", "winston-transport": "^4.9.0" } }, "sha512-LZNJgPzfKR+/J3cHkxcpHKpKKvGfDZVPS4hfJCc4cCG0CgYzvlD6yE/S3CIL/Yt91ak327YCpiF/0MyeZHEHKA=="], + + "winston-transport": ["winston-transport@4.9.0", "", { "dependencies": { "logform": "^2.7.0", "readable-stream": "^3.6.2", "triple-beam": "^1.3.0" } }, "sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A=="], + "word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="], "workerpool": ["workerpool@9.3.4", "", {}, "sha512-TmPRQYYSAnnDiEB0P/Ytip7bFGvqnSU6I2BcuSw7Hx+JSg/DsUi5ebYfc8GYaSdpuvOcEs6dXxPurOYpe9QFwg=="], @@ -3256,6 +3365,8 @@ "@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@5.0.1", "", {}, "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA=="], + "async-retry/retry": ["retry@0.13.1", "", {}, "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg=="], + "axios/https-proxy-agent": ["https-proxy-agent@5.0.1", "", { "dependencies": { "agent-base": "6", "debug": "4" } }, "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA=="], "cli-truncate/string-width": ["string-width@8.2.1", "", { "dependencies": { "get-east-asian-width": "^1.5.0", "strip-ansi": "^7.1.2" } }, "sha512-IIaP0g3iy9Cyy18w3M9YcaDudujEAVHKt3a3QJg1+sr/oX96TbaGUubG0hJyCjCBThFH+tFpcIyoUHUn1ogaLA=="], @@ -3268,6 +3379,10 @@ "cmdk/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.4", "", { "dependencies": { "@radix-ui/react-slot": "1.2.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg=="], + "color/color-convert": ["color-convert@3.1.3", "", { "dependencies": { "color-name": "^2.0.0" } }, "sha512-fasDH2ont2GqF5HpyO4w0+BcewlhHEZOFn9c1ckZdHpJ56Qb7MHhH/IcJZbBGgvdtwdwNbLvxiBEdg336iA9Sg=="], + + "color-string/color-name": ["color-name@2.1.0", "", {}, "sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg=="], + "cross-spawn/which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], "cytoscape-fcose/cose-base": ["cose-base@2.2.0", "", { "dependencies": { "layout-base": "^2.0.0" } }, "sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g=="], @@ -3378,6 +3493,8 @@ "react-jsx-parser/@types/react-dom": ["@types/react-dom@18.3.7", "", { "peerDependencies": { "@types/react": "^18.0.0" } }, "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ=="], + "readable-web-to-node-stream/readable-stream": ["readable-stream@4.7.0", "", { "dependencies": { "abort-controller": "^3.0.0", "buffer": "^6.0.3", "events": "^3.3.0", "process": "^0.11.10", "string_decoder": "^1.3.0" } }, "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg=="], + "restore-cursor/onetime": ["onetime@7.0.0", "", { "dependencies": { "mimic-function": "^5.0.0" } }, "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ=="], "restore-cursor/signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], @@ -3462,6 +3579,8 @@ "cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "color/color-convert/color-name": ["color-name@2.1.0", "", {}, "sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg=="], + "cross-spawn/which/isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], "cytoscape-fcose/cose-base/layout-base": ["layout-base@2.0.1", "", {}, "sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg=="], diff --git a/sdk/packages/core/src/services/providers/provider-config-fields.test.ts b/sdk/packages/core/src/services/providers/provider-config-fields.test.ts index ecd04d1870..a4cb014a2c 100644 --- a/sdk/packages/core/src/services/providers/provider-config-fields.test.ts +++ b/sdk/packages/core/src/services/providers/provider-config-fields.test.ts @@ -110,6 +110,25 @@ describe("getProviderConfigFields", () => { expect(result.fields.awsProfile?.optional).toBe(true); }); + it("returns SAP AI Core client credential fields instead of a generic API key", () => { + const result = getProviderConfigFields("sapaicore"); + expect(result.providerId).toBe("sapaicore"); + expect(result.authMethod).toBe("api-key"); + expect(result.description).toMatch(/not a generic API key/i); + expect(Object.keys(result.fields)).toEqual([ + "baseUrl", + "sapClientId", + "sapClientSecret", + "sapTokenUrl", + "sapResourceGroup", + "sapDeploymentId", + ]); + expect(result.fields.apiKey).toBeUndefined(); + expect(result.fields.baseUrl?.label).toBe("AI Core Base URL"); + expect(result.fields.sapResourceGroup?.optional).toBe(true); + expect(result.fields.sapDeploymentId?.optional).toBe(true); + }); + it("falls back to a single api-key field for unknown providers", () => { const result = getProviderConfigFields("not-a-real-provider"); expect(result.authMethod).toBe("api-key"); diff --git a/sdk/packages/core/src/services/providers/provider-config-fields.ts b/sdk/packages/core/src/services/providers/provider-config-fields.ts index 837fb06dd6..8c15ff7244 100644 --- a/sdk/packages/core/src/services/providers/provider-config-fields.ts +++ b/sdk/packages/core/src/services/providers/provider-config-fields.ts @@ -5,7 +5,12 @@ export type ProviderConfigFieldKey = | "apiKey" | "baseUrl" | "awsRegion" - | "awsProfile"; + | "awsProfile" + | "sapClientId" + | "sapClientSecret" + | "sapTokenUrl" + | "sapResourceGroup" + | "sapDeploymentId"; export interface ProviderConfigFieldRequirement { defaultValue?: string; @@ -30,6 +35,11 @@ const FIELD_KEYS: ProviderConfigFieldKey[] = [ "baseUrl", "awsRegion", "awsProfile", + "sapClientId", + "sapClientSecret", + "sapTokenUrl", + "sapResourceGroup", + "sapDeploymentId", ]; interface ProviderConfigFieldMetadata { @@ -71,6 +81,39 @@ const PROVIDER_CONFIG_FIELD_METADATA: Partial< }, }, }, + sapaicore: { + mode: "replace", + description: + "SAP AI Core uses OAuth client credentials and an AI Core API URL, not a generic API key.", + fields: { + baseUrl: { + label: "AI Core Base URL", + placeholder: "https://api.ai..aws.ml.hana.ondemand.com", + }, + sapClientId: { + label: "Client ID", + placeholder: "sb-...|xsuaa_std!b...", + }, + sapClientSecret: { + label: "Client Secret", + placeholder: "SAP AI Core client secret", + }, + sapTokenUrl: { + label: "Token URL", + placeholder: "https://.authentication.sap.hana.ondemand.com", + }, + sapResourceGroup: { + label: "Resource Group", + placeholder: "default", + optional: true, + }, + sapDeploymentId: { + label: "Deployment ID", + placeholder: "SAP AI Core deployment id", + optional: true, + }, + }, + }, }; function mergeFields( diff --git a/sdk/packages/core/src/services/storage/provider-settings-legacy-migration.test.ts b/sdk/packages/core/src/services/storage/provider-settings-legacy-migration.test.ts index 8328ed7ec8..36a82c61b3 100644 --- a/sdk/packages/core/src/services/storage/provider-settings-legacy-migration.test.ts +++ b/sdk/packages/core/src/services/storage/provider-settings-legacy-migration.test.ts @@ -352,6 +352,122 @@ describe("migrateLegacyProviderSettings", () => { }); expect(manager.read().providers.bedrock?.tokenSource).toBe("migration"); }); + + it("migrates legacy SAP AI Core credentials into SAP provider settings", () => { + const tempDir = mkdtempSync( + path.join(os.tmpdir(), "core-legacy-provider-"), + ); + tempDirs.push(tempDir); + const providersPath = path.join(tempDir, "settings", "providers.json"); + const manager = new ProviderSettingsManager({ filePath: providersPath }); + + writeFileSync( + path.join(tempDir, "globalState.json"), + JSON.stringify( + { + mode: "act", + actModeApiProvider: "sapaicore", + actModeApiModelId: "anthropic--claude-4.6-sonnet", + sapAiCoreBaseUrl: "https://api.ai.example.aws.ml.hana.ondemand.com", + sapAiCoreTokenUrl: + "https://example.authentication.sap.hana.ondemand.com", + sapAiResourceGroup: "default", + sapAiCoreUseOrchestrationMode: true, + actModeSapAiCoreDeploymentId: "deployment-id", + }, + null, + 2, + ), + ); + writeFileSync( + path.join(tempDir, "secrets.json"), + JSON.stringify( + { + sapAiCoreClientId: "sap-client", + sapAiCoreClientSecret: "sap-secret", + }, + null, + 2, + ), + ); + + const result = migrateLegacyProviderSettings({ + providerSettingsManager: manager, + dataDir: tempDir, + }); + + expect(result).toMatchObject({ + migrated: true, + providerCount: 1, + lastUsedProvider: "sapaicore", + }); + expect(manager.getProviderSettings("sapaicore")).toEqual({ + provider: "sapaicore", + model: "anthropic--claude-4.6-sonnet", + baseUrl: "https://api.ai.example.aws.ml.hana.ondemand.com", + sap: { + clientId: "sap-client", + clientSecret: "sap-secret", + tokenUrl: "https://example.authentication.sap.hana.ondemand.com", + resourceGroup: "default", + deploymentId: "deployment-id", + useOrchestrationMode: true, + }, + }); + expect(manager.read().providers.sapaicore?.tokenSource).toBe("migration"); + }); + + it("detects SAP AI Core legacy files even when provider mode is absent", () => { + const tempDir = mkdtempSync( + path.join(os.tmpdir(), "core-legacy-provider-"), + ); + tempDirs.push(tempDir); + const providersPath = path.join(tempDir, "settings", "providers.json"); + const manager = new ProviderSettingsManager({ filePath: providersPath }); + + writeFileSync( + path.join(tempDir, "globalState.json"), + JSON.stringify( + { + sapAiCoreBaseUrl: "https://api.ai.example.aws.ml.hana.ondemand.com", + sapAiCoreTokenUrl: + "https://example.authentication.sap.hana.ondemand.com", + }, + null, + 2, + ), + ); + writeFileSync( + path.join(tempDir, "secrets.json"), + JSON.stringify( + { + sapAiCoreClientId: "sap-client", + sapAiCoreClientSecret: "sap-secret", + }, + null, + 2, + ), + ); + + const result = migrateLegacyProviderSettings({ + providerSettingsManager: manager, + dataDir: tempDir, + }); + + expect(result).toMatchObject({ + migrated: true, + lastUsedProvider: "sapaicore", + }); + expect(manager.getProviderSettings("sapaicore")).toMatchObject({ + provider: "sapaicore", + baseUrl: "https://api.ai.example.aws.ml.hana.ondemand.com", + sap: { + clientId: "sap-client", + clientSecret: "sap-secret", + tokenUrl: "https://example.authentication.sap.hana.ondemand.com", + }, + }); + }); }); // ============================================================================= diff --git a/sdk/packages/core/src/services/storage/provider-settings-legacy-migration.ts b/sdk/packages/core/src/services/storage/provider-settings-legacy-migration.ts index 395aa6ff54..7b411ec101 100644 --- a/sdk/packages/core/src/services/storage/provider-settings-legacy-migration.ts +++ b/sdk/packages/core/src/services/storage/provider-settings-legacy-migration.ts @@ -460,7 +460,6 @@ function buildLegacyProviderSettings( aihubmix: legacySecrets.aihubmixApiKey, nousResearch: legacySecrets.nousResearchApiKey, oca: legacySecrets.ocaApiKey, - sapaicore: legacySecrets.sapAiCoreClientId, }; const providerSpecific: Partial = {}; @@ -674,6 +673,16 @@ function collectCandidateProviderIds( } if (trimNonEmpty(legacySecrets.clineApiKey)) candidates.add("cline"); if (trimNonEmpty(legacySecrets.ocaApiKey)) candidates.add("oca"); + if ( + trimNonEmpty(legacySecrets.sapAiCoreClientId) || + trimNonEmpty(legacySecrets.sapAiCoreClientSecret) || + trimNonEmpty(legacyGlobalState.sapAiCoreTokenUrl) || + trimNonEmpty(legacyGlobalState.sapAiCoreBaseUrl) || + trimNonEmpty(legacyGlobalState.sapAiResourceGroup) || + legacyGlobalState.sapAiCoreUseOrchestrationMode !== undefined + ) { + candidates.add("sapaicore"); + } return candidates; } diff --git a/sdk/packages/llms/CHANGELOG.md b/sdk/packages/llms/CHANGELOG.md index 68bdb84f26..1ac86d0bc5 100644 --- a/sdk/packages/llms/CHANGELOG.md +++ b/sdk/packages/llms/CHANGELOG.md @@ -2,5 +2,9 @@ ## Next Release +- SAP AI Core uses AI SDK community provider @jerome-benoit/sap-ai-provider https://ai-sdk.dev/providers/community-providers/sap-ai + +## 0.0.42 + - Supports Bedrock bearer API keys, direct IAM credentials, AWS profiles, and the default AWS SDK credential chain - Routes Z.AI GLM thinking through provider metadata while preserving generic thinking suppression for non-GLM Z.AI custom models diff --git a/sdk/packages/llms/package.json b/sdk/packages/llms/package.json index 3ea4976aa5..412fcf1d2a 100644 --- a/sdk/packages/llms/package.json +++ b/sdk/packages/llms/package.json @@ -54,6 +54,7 @@ "@ai-sdk/provider": "^3.0.8", "@aws-sdk/credential-providers": "^3.922.0", "@cline/shared": "workspace:*", + "@jerome-benoit/sap-ai-provider": "^4.6.0", "@langfuse/otel": "^4.0.0", "@opentelemetry/api": "^1.9.0", "@opentelemetry/sdk-trace-node": "^2.6.1", diff --git a/sdk/packages/llms/src/providers/ai-sdk.ts b/sdk/packages/llms/src/providers/ai-sdk.ts index fd293f44ad..818b25c1ff 100644 --- a/sdk/packages/llms/src/providers/ai-sdk.ts +++ b/sdk/packages/llms/src/providers/ai-sdk.ts @@ -857,6 +857,12 @@ async function createProviderModule( const { createDifyProviderModule } = await import("./vendors/community"); return createDifyProviderModule(config); } + case "sapaicore": { + const { createSapAiCoreProviderModule } = await import( + "./vendors/community" + ); + return createSapAiCoreProviderModule(config); + } } } @@ -994,3 +1000,4 @@ export const createClaudeCodeProvider = createAiSdkProvider("claude-code"); export const createOpenAICodexProvider = createAiSdkProvider("openai-codex"); export const createOpenCodeProvider = createAiSdkProvider("opencode"); export const createDifyProvider = createAiSdkProvider("dify"); +export const createSapAiCoreProvider = createAiSdkProvider("sapaicore"); diff --git a/sdk/packages/llms/src/providers/builtins-runtime.ts b/sdk/packages/llms/src/providers/builtins-runtime.ts index 602ee5337a..881918fe00 100644 --- a/sdk/packages/llms/src/providers/builtins-runtime.ts +++ b/sdk/packages/llms/src/providers/builtins-runtime.ts @@ -63,6 +63,10 @@ async function loadFamilyFactory( const module = await import("./ai-sdk"); return module.createDifyProvider; } + case "sap-ai-core": { + const module = await import("./ai-sdk"); + return module.createSapAiCoreProvider; + } } })(); diff --git a/sdk/packages/llms/src/providers/builtins.ts b/sdk/packages/llms/src/providers/builtins.ts index 7c0e831dd7..2171de9ef2 100644 --- a/sdk/packages/llms/src/providers/builtins.ts +++ b/sdk/packages/llms/src/providers/builtins.ts @@ -40,7 +40,8 @@ export type ProviderFamily = | "claude-code" | "openai-codex" | "opencode" - | "dify"; + | "dify" + | "sap-ai-core"; export interface BuiltinSpec { id: string; @@ -245,6 +246,7 @@ function inferClient(spec: BuiltinSpec): ProviderClient { case "openai-codex": case "opencode": case "dify": + case "sap-ai-core": return "ai-sdk-community"; default: return "openai-compatible"; @@ -638,18 +640,6 @@ const OPENAI_COMPATIBLE_SPECS: BuiltinSpec[] = [ modelsFactory: () => ({}), defaults: { baseUrl: "https://api.asksage.ai/server" }, }, - { - id: "sapaicore", - name: "SAP AI Core", - description: "SAP AI Core inference and orchestration platform", - family: "openai-compatible", - client: "ai-sdk-community", - capabilities: ["tools", "reasoning", "prompt-cache"], - defaultModelId: "anthropic--claude-3.5-sonnet", - apiKeyEnv: ["AICORE_SERVICE_KEY", "VCAP_SERVICES"], - modelsProviderId: "sapaicore", - metadata: ANTHROPIC_ROUTING_METADATA, - }, ]; export const BUILTIN_SPECS: BuiltinSpec[] = [ @@ -801,6 +791,18 @@ export const BUILTIN_SPECS: BuiltinSpec[] = [ apiKeyEnv: ["DIFY_API_KEY"], modelsFactory: () => ({}), }, + { + id: "sapaicore", + name: "SAP AI Core", + description: "SAP AI Core inference and orchestration platform", + family: "sap-ai-core", + client: "ai-sdk-community", + capabilities: ["tools", "reasoning", "prompt-cache"], + defaultModelId: "anthropic--claude-3.5-sonnet", + apiKeyEnv: ["AICORE_SERVICE_KEY", "VCAP_SERVICES"], + modelsProviderId: "sapaicore", + metadata: ANTHROPIC_ROUTING_METADATA, + }, ...OPENAI_COMPATIBLE_SPECS, ]; diff --git a/sdk/packages/llms/src/providers/compat.ts b/sdk/packages/llms/src/providers/compat.ts index 772eea309a..8b71d884d7 100644 --- a/sdk/packages/llms/src/providers/compat.ts +++ b/sdk/packages/llms/src/providers/compat.ts @@ -22,6 +22,7 @@ import { createOpenAICompatibleProvider, createOpenAIProvider, createOpenCodeProvider, + createSapAiCoreProvider, createVertexProvider, } from "./ai-sdk"; import { BUILTIN_PROVIDER_REGISTRATIONS } from "./builtins-runtime"; @@ -160,6 +161,8 @@ function resolveFactory( return createOpenCodeProvider; case "dify": return createDifyProvider; + case "sapaicore": + return createSapAiCoreProvider; default: return createOpenAICompatibleProvider; } diff --git a/sdk/packages/llms/src/providers/ids.test.ts b/sdk/packages/llms/src/providers/ids.test.ts index d760c63ccd..b2894927f0 100644 --- a/sdk/packages/llms/src/providers/ids.test.ts +++ b/sdk/packages/llms/src/providers/ids.test.ts @@ -1,5 +1,9 @@ import { describe, expect, it } from "vitest"; -import { createOpenAICompatibleProvider, createOpenAIProvider } from "./ai-sdk"; +import { + createOpenAICompatibleProvider, + createOpenAIProvider, + createSapAiCoreProvider, +} from "./ai-sdk"; import { BUILTIN_PROVIDER_REGISTRATIONS } from "./builtins-runtime"; import { createGateway } from "./gateway"; import { BUILT_IN_PROVIDER_IDS, normalizeProviderId } from "./ids"; @@ -120,4 +124,20 @@ describe("provider-ids", () => { }); } }); + + it("routes SAP AI Core through the SAP AI SDK provider factory", async () => { + await expect(getProvider("sapaicore")).resolves.toMatchObject({ + id: "sapaicore", + name: "SAP AI Core", + client: "ai-sdk-community", + defaultModelId: "anthropic--claude-3.5-sonnet", + }); + + const registration = BUILTIN_PROVIDER_REGISTRATIONS.find( + (item) => item.manifest.id === "sapaicore", + ); + await expect(registration?.loadProvider?.()).resolves.toMatchObject({ + createProvider: createSapAiCoreProvider, + }); + }); }); diff --git a/sdk/packages/llms/src/providers/routing/provider-options-types.ts b/sdk/packages/llms/src/providers/routing/provider-options-types.ts index 4fa439bb83..28468b1ea6 100644 --- a/sdk/packages/llms/src/providers/routing/provider-options-types.ts +++ b/sdk/packages/llms/src/providers/routing/provider-options-types.ts @@ -16,7 +16,8 @@ export type AiSdkProviderOptionsTarget = | "claude-code" | "openai-codex" | "opencode" - | "dify"; + | "dify" + | "sapaicore"; export type ProviderOptionSuppression = { genericThinking?: boolean; @@ -83,6 +84,8 @@ export function inferProviderOptionsTarget( return "opencode"; case "dify": return "dify"; + case "sapaicore": + return "sapaicore"; default: return "openai-compatible"; } diff --git a/sdk/packages/llms/src/providers/vendors/community.test.ts b/sdk/packages/llms/src/providers/vendors/community.test.ts new file mode 100644 index 0000000000..8911877120 --- /dev/null +++ b/sdk/packages/llms/src/providers/vendors/community.test.ts @@ -0,0 +1,55 @@ +import { afterEach, describe, expect, it } from "vitest"; +import { createSapAiCoreProviderModule } from "./community"; + +const originalServiceKey = process.env.AICORE_SERVICE_KEY; + +describe("createSapAiCoreProviderModule", () => { + afterEach(() => { + if (originalServiceKey === undefined) { + delete process.env.AICORE_SERVICE_KEY; + } else { + process.env.AICORE_SERVICE_KEY = originalServiceKey; + } + }); + + it("passes SAP credentials as a provider destination without mutating process env", async () => { + process.env.AICORE_SERVICE_KEY = "existing-service-key"; + + const provider = await createSapAiCoreProviderModule({ + providerId: "sapaicore", + baseUrl: "https://api.ai.example.aws.ml.hana.ondemand.com", + options: { + clientId: "sap-client", + clientSecret: "sap-secret", + tokenUrl: "https://auth.example", + deploymentId: "deployment-id", + }, + }); + + const model = provider.model("anthropic--claude-4.6-sonnet") as { + config?: { destination?: Record }; + }; + + expect(process.env.AICORE_SERVICE_KEY).toBe("existing-service-key"); + expect(model.config?.destination).toMatchObject({ + authentication: "OAuth2ClientCredentials", + clientId: "sap-client", + clientSecret: "sap-secret", + tokenServiceUrl: "https://auth.example/oauth/token", + url: "https://api.ai.example.aws.ml.hana.ondemand.com", + }); + }); + + it("fails fast for partial explicit SAP configuration", async () => { + await expect( + createSapAiCoreProviderModule({ + providerId: "sapaicore", + options: { + clientId: "sap-client", + clientSecret: "sap-secret", + tokenUrl: "https://auth.example", + }, + }), + ).rejects.toThrow(/baseUrl/); + }); +}); diff --git a/sdk/packages/llms/src/providers/vendors/community.ts b/sdk/packages/llms/src/providers/vendors/community.ts index 095662ea73..ce7e7cf6fb 100644 --- a/sdk/packages/llms/src/providers/vendors/community.ts +++ b/sdk/packages/llms/src/providers/vendors/community.ts @@ -1,10 +1,15 @@ import type { GatewayResolvedProviderConfig } from "@cline/shared"; +import type { SAPAIProviderSettings } from "@jerome-benoit/sap-ai-provider"; import { createClaudeCode } from "ai-sdk-provider-claude-code"; import { createCodexExec } from "ai-sdk-provider-codex-cli"; import { createDifyProvider } from "dify-ai-provider"; import { resolveApiKey } from "../http"; import type { ProviderFactoryResult } from "./types"; +type SapAiProviderModule = typeof import("@jerome-benoit/sap-ai-provider"); +type SapDestination = NonNullable; +const SAP_AI_PROVIDER_PACKAGE = "@jerome-benoit/sap-ai-provider"; + function readOptions( config: GatewayResolvedProviderConfig, ): Record { @@ -95,3 +100,108 @@ export async function createDifyProviderModule( }), }; } + +function readStringOption( + options: Record, + key: string, +): string | undefined { + const value = options[key]; + return typeof value === "string" && value.trim().length > 0 + ? value.trim() + : undefined; +} + +function normalizeSapTokenServiceUrl(tokenUrl: string): string { + const trimmed = tokenUrl.replace(/\/+$/, ""); + return /\/oauth\/token$/i.test(trimmed) ? trimmed : `${trimmed}/oauth/token`; +} + +function hasExplicitSapConnectionConfig( + config: GatewayResolvedProviderConfig, + options: Record, +): boolean { + return Boolean( + config.apiKey?.trim() || + config.baseUrl?.trim() || + readStringOption(options, "clientId") || + readStringOption(options, "clientSecret") || + readStringOption(options, "tokenUrl"), + ); +} + +function buildSapDestination( + config: GatewayResolvedProviderConfig, + options: Record, +): SapDestination | undefined { + const clientId = readStringOption(options, "clientId"); + const clientSecret = + readStringOption(options, "clientSecret") ?? config.apiKey?.trim(); + const tokenUrl = readStringOption(options, "tokenUrl"); + const baseUrl = config.baseUrl?.trim(); + if (!clientId || !clientSecret || !tokenUrl || !baseUrl) { + if (!hasExplicitSapConnectionConfig(config, options)) { + return undefined; + } + const missing = [ + !clientId ? "sap.clientId" : undefined, + !clientSecret ? "sap.clientSecret" : undefined, + !tokenUrl ? "sap.tokenUrl" : undefined, + !baseUrl ? "baseUrl" : undefined, + ].filter(Boolean); + throw new Error( + `SAP AI Core provider is missing required configuration: ${missing.join( + ", ", + )}.`, + ); + } + return { + authentication: "OAuth2ClientCredentials" as const, + clientId, + clientSecret, + name: config.providerId, + tokenServiceUrl: normalizeSapTokenServiceUrl(tokenUrl), + url: baseUrl.replace(/\/+$/, ""), + } satisfies SapDestination; +} + +function resolveSapApi(options: Record) { + const api = options.api; + if (api === "orchestration" || api === "foundation-models") { + return api; + } + if (options.useOrchestrationMode === false) { + return "foundation-models"; + } + return "orchestration"; +} + +async function importSapAiProvider(): Promise { + const specifier: string = SAP_AI_PROVIDER_PACKAGE; + return import(specifier) as Promise; +} + +export async function createSapAiCoreProviderModule( + config: GatewayResolvedProviderConfig, +): Promise { + const options = readOptions(config); + const destination = buildSapDestination(config, options); + + const { createSAPAIProvider } = await importSapAiProvider(); + const deploymentId = readStringOption(options, "deploymentId"); + const provider = createSAPAIProvider({ + name: config.providerId, + ...(deploymentId + ? { deploymentId } + : { resourceGroup: readStringOption(options, "resourceGroup") }), + api: resolveSapApi(options), + ...(destination ? { destination } : {}), + ...(typeof options.defaultSettings === "object" && + options.defaultSettings !== null && + !Array.isArray(options.defaultSettings) + ? { defaultSettings: options.defaultSettings } + : {}), + }); + return { + model: (modelId) => provider(modelId), + }; +}