fix: SAP AI Core uses AI SDK community provider (CLINE-2307) (#11075)

This commit is contained in:
Bee
2026-05-27 20:12:01 -07:00
committed by GitHub
parent 9e942fbb6b
commit 33e521e551
24 changed files with 673 additions and 26 deletions
+3
View File
@@ -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
@@ -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<Record<ProviderConfigFieldKey, string>> = {
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://<subdomain>.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);
};
@@ -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",
});
});
});
@@ -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,
@@ -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
@@ -6,4 +6,9 @@ export const FIELD_ORDER: ProviderConfigFieldKey[] = [
"baseUrl",
"apiKey",
"awsProfile",
"sapClientId",
"sapClientSecret",
"sapTokenUrl",
"sapResourceGroup",
"sapDeploymentId",
];
@@ -224,6 +224,11 @@ const DEFAULT_FIELD_LABELS: Partial<Record<ProviderConfigFieldKey, string>> = {
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://<subdomain>.authentication.sap.hana.ondemand.com",
sapResourceGroup: "default",
sapDeploymentId: "",
};
export function OnboardingProviderConfigScreen(props: {
@@ -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);
});
});
+5 -4
View File
@@ -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;
}
+121 -2
View File
@@ -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=="],
@@ -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");
@@ -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.<region>.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://<subdomain>.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(
@@ -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",
},
});
});
});
// =============================================================================
@@ -460,7 +460,6 @@ function buildLegacyProviderSettings(
aihubmix: legacySecrets.aihubmixApiKey,
nousResearch: legacySecrets.nousResearchApiKey,
oca: legacySecrets.ocaApiKey,
sapaicore: legacySecrets.sapAiCoreClientId,
};
const providerSpecific: Partial<ProviderSettings> = {};
@@ -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;
}
+4
View File
@@ -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
+1
View File
@@ -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",
@@ -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");
@@ -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;
}
}
})();
+15 -13
View File
@@ -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,
];
@@ -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;
}
+21 -1
View File
@@ -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,
});
});
});
@@ -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";
}
@@ -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<string, unknown> };
};
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/);
});
});
+110
View File
@@ -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<SAPAIProviderSettings["destination"]>;
const SAP_AI_PROVIDER_PACKAGE = "@jerome-benoit/sap-ai-provider";
function readOptions(
config: GatewayResolvedProviderConfig,
): Record<string, unknown> {
@@ -95,3 +100,108 @@ export async function createDifyProviderModule(
}),
};
}
function readStringOption(
options: Record<string, unknown>,
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<string, unknown>,
): boolean {
return Boolean(
config.apiKey?.trim() ||
config.baseUrl?.trim() ||
readStringOption(options, "clientId") ||
readStringOption(options, "clientSecret") ||
readStringOption(options, "tokenUrl"),
);
}
function buildSapDestination(
config: GatewayResolvedProviderConfig,
options: Record<string, unknown>,
): 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<string, unknown>) {
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<SapAiProviderModule> {
const specifier: string = SAP_AI_PROVIDER_PACKAGE;
return import(specifier) as Promise<SapAiProviderModule>;
}
export async function createSapAiCoreProviderModule(
config: GatewayResolvedProviderConfig,
): Promise<ProviderFactoryResult> {
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),
};
}