dsh-model-groups 0.0.0-stage → 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,17 @@
1
+ {
2
+ "version": "0.2.2-rc.1",
3
+ "packageName": "@deepseek-ai/dsh-api-remotes",
4
+ "target": "node_modules/@deepseek-ai/dsh-api-remotes/lib/client.js",
5
+ "baseSha256": "7e2fb3438bddc44c65a5448842b23397ce8a31b0591490386072a19d6b8ddf6c",
6
+ "resultSha256": "d51c84f824a36b9a9cf9fd0586f90d98887d1d4427631f3f9c8a253eccf796b8",
7
+ "replacements": [
8
+ {
9
+ "before": "\"apiKey\": zod.z.string().optional().describe(\"Credential for this interrogation alone; the harness never stores it.\")",
10
+ "after": "\"apiKey\": zod.z.string().optional().describe(\"Credential for this interrogation alone; the harness never stores it.\"),\n\t\t\t\"keyEntryId\": zod.z.string().optional().describe(\"Exact stored key entry to interrogate; never falls back to another entry credential.\")"
11
+ },
12
+ {
13
+ "before": "\"apiKey\": {\n\t\t\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\"description\": \"Credential for this interrogation alone; the harness never stores it.\"\n\t\t\t\t\t\t\t\t\t}",
14
+ "after": "\"apiKey\": {\n\t\t\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\"description\": \"Credential for this interrogation alone; the harness never stores it.\"\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"keyEntryId\": {\n\t\t\t\t\t\t\t\t\t\t\"type\": \"string\",\n\t\t\t\t\t\t\t\t\t\t\"description\": \"Exact stored key entry to interrogate; never falls back to another entry credential.\"\n\t\t\t\t\t\t\t\t\t}"
15
+ }
16
+ ]
17
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "version": "0.2.2-rc.1",
3
+ "packageName": "@deepseek-ai/dsh-llm",
4
+ "target": "node_modules/@deepseek-ai/dsh-llm/lib/typert.host.js",
5
+ "baseSha256": "f7ad1bf944fb7083c84a0626cf8e77d0ef037e12603ea6c2284794e6f20240de",
6
+ "resultSha256": "7aad76cf00885fa8a4ab0958903bd3fcdabd98ad7475271d16cd2ab3117c764f",
7
+ "replacements": [
8
+ {
9
+ "before": " 'apiKey': z.string().optional().describe('Credential for this interrogation alone; the harness never stores it.'),",
10
+ "after": " 'apiKey': z.string().optional().describe('Credential for this interrogation alone; the harness never stores it.'),\n 'keyEntryId': z.string().optional().describe('Exact stored key entry to interrogate; never falls back to another entry credential.'),"
11
+ },
12
+ {
13
+ "before": "\"apiKey\":{\"type\":\"string\",\"description\":\"Credential for this interrogation alone; the harness never stores it.\"}",
14
+ "after": "\"apiKey\":{\"type\":\"string\",\"description\":\"Credential for this interrogation alone; the harness never stores it.\"},\"keyEntryId\":{\"type\":\"string\",\"description\":\"Exact stored key entry to interrogate; never falls back to another entry credential.\"}"
15
+ },
16
+ {
17
+ "before": " apiKey?: string;\\n}",
18
+ "after": " apiKey?: string;\\n keyEntryId?: string;\\n}"
19
+ }
20
+ ]
21
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "version": "0.2.2-rc.1",
3
+ "packageName": "@deepseek-ai/dsh-llm",
4
+ "target": "node_modules/@deepseek-ai/dsh-llm/lib/typert.remote-client.js",
5
+ "baseSha256": "fea6401fe00567f6f25bd58057e30167bb38a7c09f00dcd626116e1bc6c1fde6",
6
+ "resultSha256": "b90bef9f8309491c5c84d193456bce8dd2e9672936a26f1adda51a6cc34e3f0c",
7
+ "replacements": [
8
+ {
9
+ "before": " 'apiKey': z.string().optional().describe('Credential for this interrogation alone; the harness never stores it.'),",
10
+ "after": " 'apiKey': z.string().optional().describe('Credential for this interrogation alone; the harness never stores it.'),\n 'keyEntryId': z.string().optional().describe('Exact stored key entry to interrogate; never falls back to another entry credential.'),"
11
+ },
12
+ {
13
+ "before": "\"apiKey\":{\"type\":\"string\",\"description\":\"Credential for this interrogation alone; the harness never stores it.\"}",
14
+ "after": "\"apiKey\":{\"type\":\"string\",\"description\":\"Credential for this interrogation alone; the harness never stores it.\"},\"keyEntryId\":{\"type\":\"string\",\"description\":\"Exact stored key entry to interrogate; never falls back to another entry credential.\"}"
15
+ }
16
+ ]
17
+ }
@@ -0,0 +1,85 @@
1
+ {
2
+ "version": "0.2.2-rc.1",
3
+ "packageName": "@deepseek-ai/dsh-llm-pi-ai",
4
+ "target": "node_modules/@deepseek-ai/dsh-llm-pi-ai/lib/index.js",
5
+ "baseSha256": "070c839e2c00e2d5f7c5d82307ca3d84dbb2323e46979daf265908751bbe8ae8",
6
+ "resultSha256": "a2b3bcda38015026ed58074cef0d508bbd2d7cb1423c00331651fcbd1a9f6b55",
7
+ "replacements": [
8
+ {
9
+ "before": "\t...modelFields\n});\n/** A {@link modelProfile} whose id lives in the `modelOverrides` dict key. */\nconst modelOverride = z.object(modelFields);\nconst profile = z.object({\n\tapiKeyEnv: z.string().role(\"credential-ref\"),\n\tdisplayName: z.string(),\n\tapi: z.union(supportedProtocols()),\n\tbaseURL: z.string(),\n",
10
+ "after": "\t...modelFields\n});\n/** A {@link modelProfile} whose id lives in the `modelOverrides` dict key. */\nconst modelOverride = z.object(modelFields);\n// Model selection carries an opaque entry identity, never a credential or a wire alias.\nconst KEY_MODEL_PREFIX = \"@dsh-key/\";\nconst KEY_ENTRY_ID = /^[A-Za-z0-9][A-Za-z0-9_-]{0,79}$/;\nconst FORBIDDEN_KEY_ENTRY_IDS = new Set([\"__proto__\", \"prototype\", \"constructor\"]);\nconst AUTH_HEADER_NAMES = new Set([\"authorization\", \"proxy-authorization\", \"x-api-key\", \"api-key\", \"cf-aig-authorization\"]);\nfunction validKeyEntryId(id) {\n\treturn KEY_ENTRY_ID.test(id) && !FORBIDDEN_KEY_ENTRY_IDS.has(id);\n}\nfunction keyModelId(entryId, model) {\n\treturn `${KEY_MODEL_PREFIX}${encodeURIComponent(entryId)}/${encodeURIComponent(model)}`;\n}\nfunction keyModelRoute(model) {\n\tif (!model.startsWith(KEY_MODEL_PREFIX)) return void 0;\n\ttry {\n\t\tconst parts = model.slice(KEY_MODEL_PREFIX.length).split(\"/\");\n\t\tif (parts.length === 2) {\n\t\t\tconst entryId = decodeURIComponent(parts[0]);\n\t\t\tconst wireModel = decodeURIComponent(parts[1]);\n\t\t\tif (validKeyEntryId(entryId) && wireModel.length > 0 && !wireModel.startsWith(KEY_MODEL_PREFIX) && keyModelId(entryId, wireModel) === model) return { entryId, wireModel };\n\t\t}\n\t} catch {}\n\tthrow new LlmError(`invalid multi-key model selection \"${model}\"`, \"UNKNOWN_MODEL\");\n}\nconst keyEntryProfile = z.object({\n\tname: z.string().max(120).required(),\n\tapiKeyEnv: z.string().role(\"credential-ref\").required(),\n\tmodels: z.array(modelProfile).required()\n});\nconst profile = z.object({\n\tmultiKey: z.boolean().default(false),\n\tkeyEntries: z.dict(keyEntryProfile).default({}),\n\tapiKeyEnv: z.string().role(\"credential-ref\"),\n\tdisplayName: z.string(),\n\tapi: z.union(supportedProtocols()),\n\tbaseURL: z.string(),\n"
11
+ },
12
+ {
13
+ "before": "* @param providers - configured provider profiles keyed by route.\n* @param validation - writes require a complete catalog; stored reads retain catalog diagnostics.\n* @returns validated profiles in configuration order.\n*/\nfunction resolveProfiles(providers, validation = \"strict\") {\n\tif (Array.isArray(providers)) throw new Error(\"llm-pi-ai: providers is now a dict keyed by provider route, not an array of profiles\");\n\tconst entries = Object.entries(providers ?? {});\n\tconst resolved = /* @__PURE__ */ new Map();\n\tfor (const [provider, source] of entries) {\n",
14
+ "after": "* @param providers - configured provider profiles keyed by route.\n* @param validation - writes require a complete catalog; stored reads retain catalog diagnostics.\n* @returns validated profiles in configuration order.\n*/\nfunction resolveProfiles(providers, validation = \"strict\", forKeyEntry = false) {\n\tif (Array.isArray(providers)) throw new Error(\"llm-pi-ai: providers is now a dict keyed by provider route, not an array of profiles\");\n\tconst entries = Object.entries(providers ?? {});\n\tconst resolved = /* @__PURE__ */ new Map();\n\tfor (const [provider, source] of entries) {\n"
15
+ },
16
+ {
17
+ "before": "\t\tif (provider.length === 0) throw new Error(\"llm-pi-ai: provider names must be non-empty\");\n\t\tif (source.baseURL !== void 0 && source.baseURL.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty baseURL`);\n\t\tif (source.displayName !== void 0 && source.displayName.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty displayName`);\n\t\tassertValidHeaders(provider, source.headers);\n\t\tconst streamIdleTimeoutMs = source.streamIdleTimeoutMs ?? 3e5;\n\t\tif (!Number.isFinite(streamIdleTimeoutMs) || streamIdleTimeoutMs <= 0 || streamIdleTimeoutMs > MAX_TIMER_DELAY_MS) throw new Error(`llm-pi-ai: provider \"${provider}\" streamIdleTimeoutMs must be a positive finite number no greater than ${MAX_TIMER_DELAY_MS}`);\n\t\tconst maxRequestImageBytes = source.maxRequestImageBytes ?? 20971520;\n\t\tif (!Number.isInteger(maxRequestImageBytes) || maxRequestImageBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" maxRequestImageBytes must be a positive integer`);\n",
18
+ "after": "\t\tif (provider.length === 0) throw new Error(\"llm-pi-ai: provider names must be non-empty\");\n\t\tif (source.baseURL !== void 0 && source.baseURL.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty baseURL`);\n\t\tif (source.displayName !== void 0 && source.displayName.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" has an empty displayName`);\n\t\tassertValidHeaders(provider, source.headers);\n\t\tconst entrySources = source.keyEntries ?? {};\n\t\tif (typeof entrySources !== \"object\" || entrySources === null || Array.isArray(entrySources)) throw new Error(`llm-pi-ai: provider \"${provider}\" keyEntries must be a dictionary`);\n\t\tconst assertWireModels = (models, site) => {\n\t\t\tfor (const model of models ?? []) if (typeof model.id !== \"string\" || model.id.length === 0 || model.id.startsWith(KEY_MODEL_PREFIX)) throw new Error(`llm-pi-ai: provider \"${provider}\" ${site} must use non-empty upstream model ids outside the reserved ${KEY_MODEL_PREFIX} prefix`);\n\t\t};\n\t\tassertWireModels(source.models, \"models\");\n\t\tfor (const id of Object.keys(source.modelOverrides ?? {})) if (id.startsWith(KEY_MODEL_PREFIX)) throw new Error(`llm-pi-ai: provider \"${provider}\" modelOverrides uses reserved prefix ${KEY_MODEL_PREFIX}`);\n\t\tfor (const [id, entry] of Object.entries(entrySources)) {\n\t\t\tif (!validKeyEntryId(id)) throw new Error(`llm-pi-ai: provider \"${provider}\" has an invalid key entry id \"${id}\"`);\n\t\t\tif (typeof entry !== \"object\" || entry === null || typeof entry.name !== \"string\" || entry.name.trim().length === 0 || entry.name.length > 120) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" needs a name of 1-120 characters`);\n\t\t\tif (typeof entry.apiKeyEnv !== \"string\" || entry.apiKeyEnv.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" needs its own apiKeyEnv`);\n\t\t\tcredentialRef(entry.apiKeyEnv);\n\t\t\tif (!Array.isArray(entry.models)) throw new Error(`llm-pi-ai: provider \"${provider}\" key entry \"${id}\" needs its own models list`);\n\t\t\tassertWireModels(entry.models, `key entry \"${id}\" models`);\n\t\t}\n\t\tconst assertEntryHeaders = (headers, site) => {\n\t\t\tfor (const name of Object.keys(headers ?? {})) if (AUTH_HEADER_NAMES.has(name.toLowerCase())) throw new Error(`llm-pi-ai: provider \"${provider}\" ${site} authentication header \"${name}\" would override the selected key; remove it before enabling multiKey`);\n\t\t};\n\t\tif (source.multiKey === true || forKeyEntry) {\n\t\t\tassertEntryHeaders(source.headers, \"shared\");\n\t\t\tfor (const model of source.models ?? []) assertEntryHeaders(model.headers, `model \"${model.id}\"`);\n\t\t\tfor (const [id, override] of Object.entries(source.modelOverrides ?? {})) assertEntryHeaders(override.headers, `model override \"${id}\"`);\n\t\t}\n\t\tconst streamIdleTimeoutMs = source.streamIdleTimeoutMs ?? 3e5;\n\t\tif (!Number.isFinite(streamIdleTimeoutMs) || streamIdleTimeoutMs <= 0 || streamIdleTimeoutMs > MAX_TIMER_DELAY_MS) throw new Error(`llm-pi-ai: provider \"${provider}\" streamIdleTimeoutMs must be a positive finite number no greater than ${MAX_TIMER_DELAY_MS}`);\n\t\tconst maxRequestImageBytes = source.maxRequestImageBytes ?? 20971520;\n\t\tif (!Number.isInteger(maxRequestImageBytes) || maxRequestImageBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" maxRequestImageBytes must be a positive integer`);\n"
19
+ },
20
+ {
21
+ "before": "\t\tif (!Number.isSafeInteger(requestImageMaxBytes) || requestImageMaxBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" requestImageMaxBytes must be a positive safe integer`);\n\t\tconst defaultInput = [...source.defaultInput ?? DEFAULT_INPUT];\n\t\tif (defaultInput.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" defaultInput must name at least one modality`);\n\t\tconst displayName = source.displayName ?? provider;\n\t\tlet catalog;\n\t\tlet piProvider;\n\t\tlet catalogError;\n\t\ttry {\n\t\t\tcatalog = resolveRouteModels({\n\t\t\t\tprovider,\n\t\t\t\t...source.api === void 0 ? {} : { api: source.api },\n\t\t\t\t...source.baseURL === void 0 ? {} : { baseURL: source.baseURL },\n\t\t\t\t...source.models === void 0 ? {} : { models: source.models },\n",
22
+ "after": "\t\tif (!Number.isSafeInteger(requestImageMaxBytes) || requestImageMaxBytes <= 0) throw new Error(`llm-pi-ai: provider \"${provider}\" requestImageMaxBytes must be a positive safe integer`);\n\t\tconst defaultInput = [...source.defaultInput ?? DEFAULT_INPUT];\n\t\tif (defaultInput.length === 0) throw new Error(`llm-pi-ai: provider \"${provider}\" defaultInput must name at least one modality`);\n\t\tconst displayName = source.displayName ?? provider;\n\t\tconst keyEntries = new Map();\n\t\t// Disabled entries remain stored, but cannot constrain legacy single-key runtime behavior.\n\t\tif (source.multiKey === true) for (const [id, entry] of Object.entries(entrySources)) {\n\t\t\tconst child = resolveProfiles({ [provider]: {\n\t\t\t\t...source,\n\t\t\t\tmultiKey: false,\n\t\t\t\tkeyEntries: {},\n\t\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\t\tmodels: entry.models,\n\t\t\t\tmodelOverrides: void 0\n\t\t\t} }, validation, true).get(provider);\n\t\t\t// Entry auth must not consult a catalog provider's ambient/OAuth credential or endpoint.\n\t\t\tkeyEntries.set(id, {\n\t\t\t\t...child,\n\t\t\t\tkeyEntryId: id,\n\t\t\t\tkeyEntryName: entry.name,\n\t\t\t\t...child.piProvider === void 0 ? {} : { piProvider: { ...child.piProvider, auth: { apiKey: harnessApiKeyAuth(entry.name) } } }\n\t\t\t});\n\t\t}\n\t\tlet catalog;\n\t\tlet piProvider;\n\t\tlet catalogError;\n\t\tconst entryOnly = forKeyEntry && source.models.length === 0 || source.multiKey === true && keyEntries.size > 0 && (source.models ?? []).length === 0 && catalogModels(provider).size === 0;\n\t\ttry {\n\t\t\tif (entryOnly) catalog = { models: [], configuredMaxTokens: new Map(), modelErrors: new Map() };\n\t\t\telse catalog = resolveRouteModels({\n\t\t\t\tprovider,\n\t\t\t\t...source.api === void 0 ? {} : { api: source.api },\n\t\t\t\t...source.baseURL === void 0 ? {} : { baseURL: source.baseURL },\n\t\t\t\t...source.models === void 0 ? {} : { models: source.models },\n"
23
+ },
24
+ {
25
+ "before": "\t\t\t}, validation);\n\t\t\tcatalogError = catalog.modelErrors.values().next().value;",
26
+ "after": "\t\t\t}, validation);\n\t\t\tif (source.multiKey === true || forKeyEntry) for (const model of catalog.models) assertEntryHeaders(model.headers, `resolved model \"${model.id}\"`);\n\t\t\tcatalogError = catalog.modelErrors.values().next().value;"
27
+ },
28
+ {
29
+ "before": "\t\tconst { apiKeyEnv, retryPolicy, models: _models, displayName: _displayName, ...rest } = source;\n\t\tresolved.set(provider, {\n\t\t\t...rest,\n\t\t\tprovider,\n\t\t\tdisplayName,\n\t\t\t...apiKeyEnv === void 0 ? {} : { apiKeyEnv: credentialRef(apiKeyEnv) },",
30
+ "after": "\t\tconst { apiKeyEnv, retryPolicy, models: _models, displayName: _displayName, keyEntries: _keyEntries, ...rest } = source;\n\t\tresolved.set(provider, {\n\t\t\t...rest,\n\t\t\tprovider,\n\t\t\tdisplayName,\n\t\t\tkeyEntries,\n\t\t\t...apiKeyEnv === void 0 ? {} : { apiKeyEnv: credentialRef(apiKeyEnv) },"
31
+ },
32
+ {
33
+ "before": "\t} catch (error) {\n\t\tthrow new LlmError(`pi-ai request header preparation failed for provider \"${options.provider}\": ${requestHeaderDiagnostic(error)}`, \"REQUEST_HEADERS\", { cause: error });\n\t}\n}\n/**\n* pi-ai-backed multi-provider adapter.",
34
+ "after": "\t} catch (error) {\n\t\tthrow new LlmError(`pi-ai request header preparation failed for provider \"${options.provider}\": ${requestHeaderDiagnostic(error)}`, \"REQUEST_HEADERS\", { cause: error });\n\t}\n}\n/** Decode only the selected replay owner at the pi boundary; never merge equal wire ids across keys. */\nfunction replayContextForRoute(context, provider, requestedModel, wireModel) {\n\tconst selectedEntry = requestedModel.startsWith(KEY_MODEL_PREFIX);\n\treturn {\n\t\t...context,\n\t\tmessages: context.messages.map((message) => {\n\t\t\tif (message.role !== \"assistant\") return message;\n\t\t\tif (message.provider === provider && message.model === requestedModel) return { ...message, model: wireModel.id };\n\t\t\tif (!message.model.startsWith(KEY_MODEL_PREFIX) && !(selectedEntry && message.provider === provider && message.model === wireModel.id)) return message;\n\t\t\treturn {\n\t\t\t\trole: \"assistant\",\n\t\t\t\tapi: \"dsh-foreign\",\n\t\t\t\tprovider: message.provider,\n\t\t\t\tmodel: \"dsh-foreign\",\n\t\t\t\tcontent: message.content.flatMap((block) => {\n\t\t\t\t\tif (block.type === \"thinking\") return [];\n\t\t\t\t\tif (block.type === \"text\") return [{ type: \"text\", text: block.text }];\n\t\t\t\t\tif (block.type === \"toolCall\") return [{ type: \"toolCall\", id: block.id, name: block.name, arguments: block.arguments }];\n\t\t\t\t\treturn [block];\n\t\t\t\t}),\n\t\t\t\tusage: message.usage,\n\t\t\t\tstopReason: message.stopReason,\n\t\t\t\ttimestamp: message.timestamp\n\t\t\t};\n\t\t})\n\t};\n}\n/**\n* pi-ai-backed multi-provider adapter."
35
+ },
36
+ {
37
+ "before": "\tcurrent() {\n\t\tconst profiles = this.config.profiles();\n\t\tif (this.snapshot?.profiles === profiles) return this.snapshot;\n\t\tconst models = createModels(this.config.auth);\n\t\tfor (const profile of profiles.values()) if (profile.piProvider !== void 0) models.setProvider(profile.piProvider);\n\t\tthis.snapshot = {\n\t\t\tprofiles,\n\t\t\tmodels\n\t\t};\n\t\treturn this.snapshot;\n\t}\n\t/** The profile for one route within one snapshot, or the not-owned failure. */\n",
38
+ "after": "\tcurrent() {\n\t\tconst profiles = this.config.profiles();\n\t\tif (this.snapshot?.profiles === profiles) return this.snapshot;\n\t\tconst models = createModels(this.config.auth);\n\t\tconst entryModels = new Map();\n\t\tfor (const [provider, profile] of profiles) {\n\t\t\tif (profile.piProvider !== void 0) models.setProvider(profile.piProvider);\n\t\t\tconst entries = new Map();\n\t\t\tfor (const [id, entry] of profile.keyEntries) {\n\t\t\t\tconst collection = createModels(this.config.auth);\n\t\t\t\tif (entry.piProvider !== void 0) collection.setProvider(entry.piProvider);\n\t\t\t\tentries.set(id, collection);\n\t\t\t}\n\t\t\tentryModels.set(provider, entries);\n\t\t}\n\t\tthis.snapshot = {\n\t\t\tprofiles,\n\t\t\tmodels,\n\t\t\tentryModels\n\t\t};\n\t\treturn this.snapshot;\n\t}\n\t/** The profile for one route within one snapshot, or the not-owned failure. */\n"
39
+ },
40
+ {
41
+ "before": "\t\tconst profile = snapshot.profiles.get(provider);\n\t\tif (profile === void 0) throw new LlmError(`pi-ai adapter does not own provider \"${provider}\"`, \"NO_ADAPTER\");\n\t\treturn profile;\n\t}\n\t/** The configured descriptor for one exact route/model pair within one snapshot. */\n\tmodelOf(snapshot, provider, model) {\n\t\tconst profile = this.profileOf(snapshot, provider);\n\t\tconst failure = profile.modelErrors.get(model) ?? (profile.piProvider === void 0 ? profile.catalogError : void 0);\n\t\tif (failure !== void 0) throw new LlmError(failure, \"INVALID_CONFIG\");\n\t\tconst resolved = snapshot.models.getModel(provider, model);\n\t\tif (resolved === void 0) throw new LlmError(`pi-ai provider \"${provider}\" has no configured model \"${model}\"`, \"UNKNOWN_MODEL\");\n\t\treturn resolved;\n\t}\n\tproviderInfo(provider) {\n",
42
+ "after": "\t\tconst profile = snapshot.profiles.get(provider);\n\t\tif (profile === void 0) throw new LlmError(`pi-ai adapter does not own provider \"${provider}\"`, \"NO_ADAPTER\");\n\t\treturn profile;\n\t}\n\t/** Bind the public selection to an exact profile, independent model collection, and upstream id. */\n\trouteOf(snapshot, provider, model) {\n\t\tconst root = this.profileOf(snapshot, provider);\n\t\tconst entry = keyModelRoute(model);\n\t\tif (entry === void 0) return { profile: root, models: snapshot.models, wireModel: model };\n\t\tif (root.multiKey !== true) throw new LlmError(`multi-key selection is disabled for provider \"${provider}\"`, \"UNKNOWN_MODEL\");\n\t\tconst profile = root.keyEntries.get(entry.entryId);\n\t\tconst models = snapshot.entryModels.get(provider)?.get(entry.entryId);\n\t\tif (profile === void 0 || models === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${entry.entryId}\"`, \"UNKNOWN_MODEL\");\n\t\treturn { profile, models, wireModel: entry.wireModel };\n\t}\n\t/** The configured descriptor for one exact route/model pair within one snapshot. */\n\tmodelOf(snapshot, provider, model) {\n\t\tconst route = this.routeOf(snapshot, provider, model);\n\t\tconst failure = route.profile.modelErrors.get(route.wireModel) ?? (route.profile.piProvider === void 0 ? route.profile.catalogError : void 0);\n\t\tif (failure !== void 0) throw new LlmError(failure, \"INVALID_CONFIG\");\n\t\tconst resolved = route.models.getModel(provider, route.wireModel);\n\t\tif (resolved === void 0) throw new LlmError(`pi-ai provider \"${provider}\" has no configured model \"${model}\"`, \"UNKNOWN_MODEL\");\n\t\treturn resolved;\n\t}\n\tproviderInfo(provider) {\n"
43
+ },
44
+ {
45
+ "before": "\tlistModels(provider) {\n\t\treturn Promise.resolve().then(async () => {\n\t\t\tconst snapshot = this.current();\n\t\t\tconst profile = this.profileOf(snapshot, provider);\n\t\t\ttry {\n\t\t\t\tawait this.config.resolveApiKey(provider, profile);\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof LlmError && error.code === \"MISSING_CREDENTIAL\") return [];\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\treturn snapshot.models.getModels(provider).map((model) => ({\n\t\t\t\tprovider,\n\t\t\t\tid: model.id,\n\t\t\t\tname: model.name,\n\t\t\t\tinputModalities: [...model.input]\n\t\t\t}));\n\t\t});\n\t}\n\tresolveModel(provider, model, _signal) {\n\t\treturn Promise.resolve().then(() => {\n",
46
+ "after": "\tlistModels(provider) {\n\t\treturn Promise.resolve().then(async () => {\n\t\t\tconst snapshot = this.current();\n\t\t\tconst profile = this.profileOf(snapshot, provider);\n\t\t\tconst listed = [];\n\t\t\tconst append = async (owner, models, entryId) => {\n\t\t\t\ttry {\n\t\t\t\t\tconst key = await this.config.resolveApiKey(provider, owner);\n\t\t\t\t\tif (entryId !== void 0 && (key === void 0 || key.length === 0)) return;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (error instanceof LlmError && error.code === \"MISSING_CREDENTIAL\") return;\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t\tfor (const model of models.getModels(provider)) listed.push({\n\t\t\t\t\tprovider,\n\t\t\t\t\tid: entryId === void 0 ? model.id : keyModelId(entryId, model.id),\n\t\t\t\t\tname: model.name,\n\t\t\t\t\tinputModalities: [...model.input]\n\t\t\t\t});\n\t\t\t};\n\t\t\t// Keep raw root models advertised so old sessions remain routable without changing keys.\n\t\t\tawait append(profile, snapshot.models);\n\t\t\tif (profile.multiKey === true) for (const [id, entry] of profile.keyEntries) await append(entry, snapshot.entryModels.get(provider).get(id), id);\n\t\t\treturn listed;\n\t\t});\n\t}\n\tresolveModel(provider, model, _signal) {\n\t\treturn Promise.resolve().then(() => {\n"
47
+ },
48
+ {
49
+ "before": "\t\t\treturn this.modelInfo(snapshot, provider, model);\n\t\t});\n\t}\n\tmodelInfo(snapshot, provider, model) {\n\t\tconst profile = this.profileOf(snapshot, provider);\n\t\tconst resolvedModel = this.modelOf(snapshot, provider, model);\n\t\tconst defaultLevel = describableReasoningLevel(resolvedModel, profile.reasoning);\n\t\tconst configuredMaxTokens = profile.configuredMaxTokens.get(model);\n\t\treturn {\n\t\t\tprovider,\n\t\t\tid: model,\n\t\t\tname: resolvedModel.name,\n",
50
+ "after": "\t\t\treturn this.modelInfo(snapshot, provider, model);\n\t\t});\n\t}\n\tmodelInfo(snapshot, provider, model) {\n\t\tconst { profile, wireModel } = this.routeOf(snapshot, provider, model);\n\t\tconst resolvedModel = this.modelOf(snapshot, provider, model);\n\t\tconst defaultLevel = describableReasoningLevel(resolvedModel, profile.reasoning);\n\t\tconst configuredMaxTokens = profile.configuredMaxTokens.get(wireModel);\n\t\treturn {\n\t\t\tprovider,\n\t\t\tid: model,\n\t\t\tname: resolvedModel.name,\n"
51
+ },
52
+ {
53
+ "before": "\tprepareCall(provider, model, _signal) {\n\t\tconst snapshot = this.current();\n\t\treturn Promise.resolve({\n\t\t\tmodel: this.modelInfo(snapshot, provider, model),\n\t\t\tstream: (options) => this.streamWithSnapshot(options, snapshot)\n\t\t});\n\t}\n\tstream(options) {\n\t\treturn this.streamWithSnapshot(options, this.current());\n\t}\n\tasync *streamWithSnapshot(options, snapshot) {\n\t\tconst env_1 = {\n\t\t\tstack: [],\n",
54
+ "after": "\tprepareCall(provider, model, _signal) {\n\t\tconst snapshot = this.current();\n\t\treturn Promise.resolve({\n\t\t\tmodel: this.modelInfo(snapshot, provider, model),\n\t\t\tstream: (options) => {\n\t\t\t\tif (options.provider !== provider || options.model !== model) throw new LlmError(\"prepared multi-key model selection changed before adapter dispatch\", \"INVALID_CONFIG\");\n\t\t\t\t// Async generators are lazy; pin the owner before returning one to caller-owned code.\n\t\t\t\treturn this.streamWithSnapshot({ ...options, provider, model }, snapshot);\n\t\t\t}\n\t\t});\n\t}\n\tstream(options) {\n\t\treturn this.streamWithSnapshot({ ...options }, this.current());\n\t}\n\tasync *streamWithSnapshot(options, snapshot) {\n\t\tconst env_1 = {\n\t\t\tstack: [],\n"
55
+ },
56
+ {
57
+ "before": "\t\t\thasError: false\n\t\t};\n\t\ttry {\n\t\t\tif (options.stop !== void 0) throw new LlmError(\"llm-pi-ai does not support GenerateOptions.stop\", \"UNSUPPORTED_OPTION\");\n\t\t\tconst profile = this.profileOf(snapshot, options.provider);\n\t\t\tconst model = this.modelOf(snapshot, options.provider, options.model);\n\t\t\tconst updates = conversationUpdates(model);\n\t\t\tconst tools = options.tools ?? [];\n\t\t\tconst request = model.api === \"anthropic-messages\" && updates.toolUpdate === \"in-history\" && tools.every((tool) => tool.deferLoading === true) && options.messages.some((message) => message.role === \"developer\" && message.content.some((block) => block.type === \"tool-addition\" || block.type === \"tool-removal\")) ? {\n",
58
+ "after": "\t\t\thasError: false\n\t\t};\n\t\ttry {\n\t\t\tif (options.stop !== void 0) throw new LlmError(\"llm-pi-ai does not support GenerateOptions.stop\", \"UNSUPPORTED_OPTION\");\n\t\t\tconst route = this.routeOf(snapshot, options.provider, options.model);\n\t\t\tconst profile = route.profile;\n\t\t\tconst model = this.modelOf(snapshot, options.provider, options.model);\n\t\t\tconst updates = conversationUpdates(model);\n\t\t\tconst tools = options.tools ?? [];\n\t\t\tconst request = model.api === \"anthropic-messages\" && updates.toolUpdate === \"in-history\" && tools.every((tool) => tool.deferLoading === true) && options.messages.some((message) => message.role === \"developer\" && message.content.some((block) => block.type === \"tool-addition\" || block.type === \"tool-removal\")) ? {\n"
59
+ },
60
+ {
61
+ "before": "\t\t\t\ttools: [ANTHROPIC_TOOL_UPDATE_PLACEHOLDER, ...tools]\n\t\t\t} : options;\n\t\t\tconst reasoning = resolveReasoningLevel(model, options.reasoningEffort ?? profile.reasoning);\n\t\t\tconst apiKey = await this.config.resolveApiKey(options.provider, profile);\n\t\t\tconst consumer = new AbortController();\n\t\t\tconst upstream = options.signal === void 0 ? consumer.signal : AbortSignal.any([options.signal, consumer.signal]);\n\t\t\tconst streamIdleTimeoutMs = profile.streamIdleTimeoutMs;\n\t\t\tconst watchdog = __addDisposableResource(env_1, idleWatchdog(upstream, streamIdleTimeoutMs, \"LLM_STREAM_IDLE_TIMEOUT\"), false);\n",
62
+ "after": "\t\t\t\ttools: [ANTHROPIC_TOOL_UPDATE_PLACEHOLDER, ...tools]\n\t\t\t} : options;\n\t\t\tconst reasoning = resolveReasoningLevel(model, options.reasoningEffort ?? profile.reasoning);\n\t\t\tconst apiKey = await this.config.resolveApiKey(options.provider, profile);\n\t\t\tif (profile.keyEntryId !== void 0 && (apiKey === void 0 || apiKey.length === 0)) throw new LlmError(`provider \"${options.provider}\" key entry \"${profile.keyEntryId}\" has no credential`, \"MISSING_CREDENTIAL\");\n\t\t\tconst consumer = new AbortController();\n\t\t\tconst upstream = options.signal === void 0 ? consumer.signal : AbortSignal.any([options.signal, consumer.signal]);\n\t\t\tconst streamIdleTimeoutMs = profile.streamIdleTimeoutMs;\n\t\t\tconst watchdog = __addDisposableResource(env_1, idleWatchdog(upstream, streamIdleTimeoutMs, \"LLM_STREAM_IDLE_TIMEOUT\"), false);\n"
63
+ },
64
+ {
65
+ "before": "\t\t\t\tconst iterator = toStreamChunks(snapshot.models.streamSimple(model, context, {\n\t\t\t\t\t...profileOptions(profile, reasoning, apiKey),\n\t\t\t\t\t...options.temperature === void 0 ? {} : { temperature: options.temperature },\n\t\t\t\t\t...options.maxTokens === void 0 ? {} : { maxTokens: options.maxTokens },\n\t\t\t\t\t...options.sessionId === void 0 ? {} : { sessionId: String(options.sessionId) },\n\t\t\t\t\tsignal: watchdog.signal,\n\t\t\t\t\theaders: requestHeaders(profile.headers, options, model.baseUrl, this.config.prepareHeaders)\n\t\t\t\t}), model.contextWindow, options.signal, model.id)[Symbol.asyncIterator]();",
66
+ "after": "\t\t\t\tconst iterator = toStreamChunks(route.models.streamSimple(model, replayContextForRoute(context, options.provider, options.model, model), {\n\t\t\t\t\t...profileOptions(profile, reasoning, apiKey),\n\t\t\t\t\t...options.temperature === void 0 ? {} : { temperature: options.temperature },\n\t\t\t\t\t...options.maxTokens === void 0 ? {} : { maxTokens: options.maxTokens },\n\t\t\t\t\t...options.sessionId === void 0 ? {} : { sessionId: String(options.sessionId) },\n\t\t\t\t\tsignal: watchdog.signal,\n\t\t\t\t\theaders: requestHeaders(profile.headers, options, model.baseUrl, this.config.prepareHeaders)\n\t\t\t\t}), model.contextWindow, options.signal, options.model)[Symbol.asyncIterator]();"
67
+ },
68
+ {
69
+ "before": "* @throws LlmError when the protocol has no readable listing, the endpoint\n* refuses or fails the request, or the reply is not a model listing.\n*/\nasync function discoverModels(request, storedProfile) {\n\tif (request.provider !== void 0) {\n\t\tconst installed = catalogModels(request.provider);\n\t\tif (installed.size > 0) return [...installed.values()].map((model) => ({\n\t\t\tid: model.id,\n",
70
+ "after": "* @throws LlmError when the protocol has no readable listing, the endpoint\n* refuses or fails the request, or the reply is not a model listing.\n*/\nasync function discoverModels(request, storedProfile) {\n\t// Validate host-owned entry identity even on the installed-catalog shortcut.\n\tconst selectedStored = request.keyEntryId === void 0 ? void 0 : storedProfile?.();\n\tif (request.keyEntryId !== void 0 && selectedStored === void 0) throw new LlmError(\"multi-key model discovery requires an existing provider key entry\", \"INVALID_CONFIG\");\n\tif (request.provider !== void 0) {\n\t\tconst installed = catalogModels(request.provider);\n\t\tif (installed.size > 0) return [...installed.values()].map((model) => ({\n\t\t\tid: model.id,\n"
71
+ },
72
+ {
73
+ "before": "\tif (request.baseURL === void 0 || request.baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tconst api = request.api ?? \"openai-completions\";\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(request.baseURL, api);\n\tconst stored = storedProfile?.();\n\tconst supplied = request.apiKey ?? await stored?.resolveApiKey();\n\tconst apiKey = supplied === void 0 ? void 0 : usableProbeKey(supplied);\n\tlet response;\n\ttry {\n",
74
+ "after": "\tif (request.baseURL === void 0 || request.baseURL.length === 0) throw new LlmError(`pi-ai ships no catalog for provider \"${request.provider ?? \"\"}\", so its models can only come from its endpoint; set a baseURL, or enter this provider's models by hand`, \"DISCOVERY_FAILED\");\n\tconst api = request.api ?? \"openai-completions\";\n\tif (!LISTABLE_PROTOCOLS.has(api)) throw new LlmError(`pi-ai protocol \"${api}\" has no model listing this build can read; enter this provider's models by hand`, \"DISCOVERY_UNSUPPORTED\");\n\tconst url = listingUrl(request.baseURL, api);\n\tconst stored = selectedStored ?? storedProfile?.();\n\tconst supplied = request.apiKey ?? await stored?.resolveApiKey();\n\tconst apiKey = supplied === void 0 ? void 0 : usableProbeKey(supplied);\n\tlet response;\n\ttry {\n"
75
+ },
76
+ {
77
+ "before": "function registrationFacts(profiles) {\n\treturn [...profiles.entries()].map(([provider, profile]) => ({\n\t\tprovider,\n\t\tdisplayName: profile.displayName,\n\t\tretryPolicy: profile.retryPolicy\n\t})).sort((left, right) => left.provider.localeCompare(right.provider));\n}\n/**\n* The configurable-provider directory: every installed catalog route, plus\n",
78
+ "after": "function registrationFacts(profiles) {\n\treturn [...profiles.entries()].map(([provider, profile]) => ({\n\t\tprovider,\n\t\tdisplayName: profile.displayName,\n\t\tretryPolicy: profile.retryPolicy,\n\t\tmultiKey: profile.multiKey === true,\n\t\tapiKeyEnv: profile.apiKeyEnv,\n\t\tmodels: profile.piProvider?.getModels(),\n\t\tmodelErrors: [...profile.modelErrors],\n\t\tkeyEntries: [...profile.keyEntries].map(([id, entry]) => ({\n\t\t\tid,\n\t\t\tname: entry.keyEntryName,\n\t\t\tapiKeyEnv: entry.apiKeyEnv,\n\t\t\tmodels: entry.piProvider?.getModels(),\n\t\t\tmodelErrors: [...entry.modelErrors]\n\t\t})).sort((left, right) => left.id.localeCompare(right.id))\n\t})).sort((left, right) => left.provider.localeCompare(right.provider));\n}\n/**\n* The configurable-provider directory: every installed catalog route, plus\n"
79
+ },
80
+ {
81
+ "before": "\t\tdirectoryFacts = entries;\n\t};\n\tensureDirectory();\n\t/** Host-owned request inputs for discovery of one configured route. */\n\tconst storedDiscoveryProfile = (provider) => {\n\t\tif (provider === void 0) return void 0;\n\t\tconst profile = profiles().get(provider);\n\t\tif (profile === void 0) return void 0;\n\t\treturn {\n\t\t\theaders: profile.headers,\n\t\t\tresolveApiKey: () => resolveApiKey(provider, profile)\n\t\t};\n\t};\n\tctx.llm.registerModelDiscovery(settingsNs, (request, signal) => discoverModels({\n\t\t...request,\n\t\t...signal === void 0 ? {} : { signal }\n\t}, () => storedDiscoveryProfile(request.provider)));\n\tlet registration;\n\tlet registeredFacts;\n\tconst ensureRegistrationFacts = () => {\n\t\tconst facts = registrationFacts(profiles());\n",
82
+ "after": "\t\tdirectoryFacts = entries;\n\t};\n\tensureDirectory();\n\t/** Host-owned request inputs for discovery of one configured route. */\n\tconst storedDiscoveryProfile = (provider, keyEntryId) => {\n\t\tif (provider === void 0) {\n\t\t\tif (keyEntryId !== void 0) throw new LlmError(\"multi-key discovery needs a provider id\", \"INVALID_CONFIG\");\n\t\t\treturn void 0;\n\t\t}\n\t\tconst root = profiles().get(provider);\n\t\tif (keyEntryId === void 0) return root === void 0 ? void 0 : { headers: root.headers, resolveApiKey: () => resolveApiKey(provider, root) };\n\t\tif (!validKeyEntryId(keyEntryId) || root?.multiKey !== true) throw new LlmError(`multi-key discovery is not enabled for provider \"${provider}\"`, \"INVALID_CONFIG\");\n\t\tconst profile = root.keyEntries.get(keyEntryId);\n\t\tif (profile === void 0) throw new LlmError(`provider \"${provider}\" has no key entry \"${keyEntryId}\"`, \"INVALID_CONFIG\");\n\t\treturn {\n\t\t\theaders: profile.headers,\n\t\t\tresolveApiKey: async () => {\n\t\t\t\tconst key = await resolveApiKey(provider, profile);\n\t\t\t\tif (key === void 0 || key.length === 0) throw new LlmError(`provider \"${provider}\" key entry \"${keyEntryId}\" has no credential`, \"MISSING_CREDENTIAL\");\n\t\t\t\treturn key;\n\t\t\t}\n\t\t};\n\t};\n\tctx.llm.registerModelDiscovery(settingsNs, (request, signal) => discoverModels({\n\t\t...request,\n\t\t...signal === void 0 ? {} : { signal }\n\t}, () => storedDiscoveryProfile(request.provider, request.keyEntryId)));\n\tlet registration;\n\tlet registeredFacts;\n\tconst ensureRegistrationFacts = () => {\n\t\tconst facts = registrationFacts(profiles());\n"
83
+ }
84
+ ]
85
+ }
@@ -0,0 +1,149 @@
1
+ {
2
+ "version": "0.2.2-rc.1",
3
+ "packageName": "@deepseek-ai/dsh-client-ui-settings-models",
4
+ "target": "node_modules/@deepseek-ai/dsh-client-ui-settings-models/lib/client.js",
5
+ "baseSha256": "e111ecefea8262e0426f528864b9681d818068042e93d053bcb0b6884b317278",
6
+ "resultSha256": "651052eccf0bdba6a8dd1624bfc25ce9215268cdd6a9a08b80e1095329c1ea5a",
7
+ "replacements": [
8
+ {
9
+ "before": "\t\t//#region lib/types/client/CustomProviderCard.js",
10
+ "after": "\t\t//#region dsh-model-groups/native/multikey\n\t\t// Entries live under one native provider. Secrets exist only in local drafts\n\t\t// and credentials/set; profile mutations contain credential references only.\n\t\tconst MULTI_KEY_ENTRY_ID = /^[A-Za-z0-9][A-Za-z0-9_-]{0,79}$/;\n\t\tconst MULTI_KEY_REF = /^[A-Za-z_][A-Za-z0-9_]*$/;\n\t\tconst MULTI_KEY_UNSAFE_IDS = new Set([\"__proto__\", \"prototype\", \"constructor\"]);\n\t\tfunction supportsMultiKeySchema(namespace, schema, path) {\n\t\t\tif (!namespace || !schema) return false;\n\t\t\tconst root = schema.rehydrate(namespace.schema);\n\t\t\tconst profile = schema.nodeAtPath(root, path);\n\t\t\treturn profile?.dict?.multiKey !== void 0 && profile?.dict?.keyEntries !== void 0;\n\t\t}\n\t\tfunction multiKeyRef(route, id) {\n\t\t\tconst normalized = route.toUpperCase().replace(/[^A-Z0-9]+/g, \"_\");\n\t\t\tconst stem = /^[A-Z_]/.test(normalized) ? normalized : `DSH_${normalized}`;\n\t\t\treturn `${stem}_MULTKEY_${id.toUpperCase().replace(/[^A-Z0-9]+/g, \"_\")}_API_KEY`;\n\t\t}\n\t\tfunction newMultiKeyEntry(route, source = {}) {\n\t\t\tconst id = `k${crypto.randomUUID()}`;\n\t\t\treturn [id, {\n\t\t\t\tname: source.name ?? \"\",\n\t\t\t\t...(typeof source.apiKeyEnv === \"string\" && source.apiKeyEnv.length > 0 ? { apiKeyEnv: source.apiKeyEnv } : {}),\n\t\t\t\tmodels: modelDrafts(source.models).map((model) => structuredClone(model))\n\t\t\t}];\n\t\t}\n\t\tfunction normalizedMultiKeyEntries(route, entries) {\n\t\t\treturn Object.fromEntries(Object.entries(entries).map(([id, entry]) => [id, {\n\t\t\t\t...entry,\n\t\t\t\tname: typeof entry?.name === \"string\" ? entry.name.trim() : \"\",\n\t\t\t\tapiKeyEnv: typeof entry?.apiKeyEnv === \"string\" && entry.apiKeyEnv.length > 0 ? entry.apiKeyEnv : multiKeyRef(route, id),\n\t\t\t\tmodels: modelDrafts(entry?.models).map((model) => structuredClone(model))\n\t\t\t}]));\n\t\t}\n\t\tfunction multiKeyFailure(route, entries, drafts, confirmations, t) {\n\t\t\tif (!entries || typeof entries !== \"object\" || Array.isArray(entries) || Object.keys(entries).length === 0) return t(\"multiKeyNeedsEntries\");\n\t\t\tconst refs = new Set();\n\t\t\tfor (const [id, entry] of Object.entries(entries)) {\n\t\t\t\tif (!MULTI_KEY_ENTRY_ID.test(id) || MULTI_KEY_UNSAFE_IDS.has(id)) return t(\"multiKeyInvalidId\");\n\t\t\t\tif (!entry || typeof entry.name !== \"string\" || entry.name.trim().length === 0 || entry.name.trim().length > 120) return t(\"multiKeyInvalidName\");\n\t\t\t\tconst ref = entry.apiKeyEnv ?? multiKeyRef(route, id);\n\t\t\t\tif (typeof ref !== \"string\" || !MULTI_KEY_REF.test(ref)) return t(\"multiKeyInvalidRef\");\n\t\t\t\tif (refs.has(ref)) return t(\"multiKeyDuplicateRef\");\n\t\t\t\trefs.add(ref);\n\t\t\t\tconst keyFailure = apiKeyFailure(drafts[id] ?? \"\");\n\t\t\t\tif (keyFailure !== void 0) return `${entry.name}: ${t(keyFailure)}`;\n\t\t\t\tif ((drafts[id] ?? \"\").trim().length > 0 && ref !== multiKeyRef(route, id) && confirmations[id] !== true) return `${entry.name}: ${t(\"multiKeyConfirmRequired\")}`;\n\t\t\t\tif (!Array.isArray(entry.models) || entry.models.length === 0) return `${entry.name}: ${t(\"multiKeyNeedsModels\")}`;\n\t\t\t\tconst modelFailure = validateDeepSeekModels(entry.models) ?? validateReasoningEfforts(entry.models);\n\t\t\t\tif (modelFailure !== void 0) return `${entry.name}: ${t(\"model\")} ${String(modelFailure.index + 1)}: ${t(modelFailure.key)}`;\n\t\t\t}\n\t\t}\n\t\tasync function storeMultiKeyDrafts(operations, entries, drafts, setDrafts) {\n\t\t\tfor (const [id, entry] of Object.entries(entries)) {\n\t\t\t\tconst draft = Object.hasOwn(drafts, id) ? drafts[id] : \"\";\n\t\t\t\tif (draft.trim().length === 0) continue;\n\t\t\t\tconst failure = await operations.storeCredential(entry.apiKeyEnv, draft.trim());\n\t\t\t\tif (failure !== void 0) return failure;\n\t\t\t\t// Clear only successful, unchanged drafts: partial failures retry just\n\t\t\t\t// the unfinished credentials without rewriting the provider profile.\n\t\t\t\tsetDrafts((current) => current[id] === draft ? { ...current, [id]: \"\" } : current);\n\t\t\t}\n\t\t}\n\t\tfunction hasMultiKeyDrafts(drafts) {\n\t\t\treturn Object.values(drafts).some((value) => typeof value === \"string\" && value.length > 0);\n\t\t}\n\t\tfunction MultiKeyToggle({ t, checked, disabled, onChange, hasUnsavedKeys = false }) {\n\t\t\tconst [confirmOff, setConfirmOff] = (0, react.useState)(false);\n\t\t\t(0, react.useEffect)(() => {\n\t\t\t\tif (!checked || disabled) setConfirmOff(false);\n\t\t\t}, [checked, disabled]);\n\t\t\tconst close = () => setConfirmOff(false);\n\t\t\treturn (0, react_jsx_runtime.jsxs)(\"div\", {\n\t\t\t\t\"data-multi-key-toggle\": true,\n\t\t\t\tclassName: ModelsSection_module_css_default[\"field\"],\n\t\t\t\tchildren: [(0, react_jsx_runtime.jsxs)(\"div\", {\n\t\t\t\t\tclassName: ModelsSection_module_css_default[\"modelReasoningHead\"],\n\t\t\t\t\tchildren: [(0, react_jsx_runtime.jsx)(\"span\", {\n\t\t\t\t\t\tclassName: ModelsSection_module_css_default[\"fieldLabel\"], children: t(\"multiKey\")\n\t\t\t\t\t}), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Switch, {\n\t\t\t\t\t\tchecked, label: t(\"multiKey\"), disabled,\n\t\t\t\t\t\tonChange: (enabled) => {\n\t\t\t\t\t\t\tif (disabled || enabled === checked) return;\n\t\t\t\t\t\t\tif (!enabled) setConfirmOff(true);\n\t\t\t\t\t\t\telse onChange(true);\n\t\t\t\t\t\t}\n\t\t\t\t\t})]\n\t\t\t\t}), (0, react_jsx_runtime.jsx)(\"p\", {\n\t\t\t\t\tclassName: ModelsSection_module_css_default[\"advancedHint\"], children: t(\"multiKeyHelp\")\n\t\t\t\t}), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {\n\t\t\t\t\topen: confirmOff && checked && !disabled, onClose: close,\n\t\t\t\t\ttitle: t(hasUnsavedKeys ? \"multiKeyUnsavedTitle\" : \"multiKeyDisableTitle\"),\n\t\t\t\t\tcloseLabel: t(\"close\"),\n\t\t\t\t\tdescription: t(hasUnsavedKeys ? \"multiKeyUnsavedKeys\" : \"multiKeyDisableDescription\"),\n\t\t\t\t\tclassName: ModelsSection_module_css_default[\"deleteDialog\"],\n\t\t\t\t\tfooter: (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [\n\t\t\t\t\t\t(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {\n\t\t\t\t\t\t\tvariant: \"outline\", \"data-modal-autofocus\": true, onClick: close,\n\t\t\t\t\t\t\tchildren: t(hasUnsavedKeys ? \"multiKeyReturnToEdit\" : \"multiKeyKeepEnabled\")\n\t\t\t\t\t\t}), hasUnsavedKeys ? null : (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {\n\t\t\t\t\t\t\tvariant: \"outline\", disabled,\n\t\t\t\t\t\t\tonClick: () => {\n\t\t\t\t\t\t\t\tif (disabled || !checked || hasUnsavedKeys) return;\n\t\t\t\t\t\t\t\tclose(); onChange(false);\n\t\t\t\t\t\t\t}, children: t(\"multiKeyDisableConfirm\")\n\t\t\t\t\t\t})\n\t\t\t\t\t] })\n\t\t\t\t})]\n\t\t\t});\n\t\t}\n\t\tfunction MultiKeyEntriesEditor(props) {\n\t\t\tconst { route, entries, keyDrafts, confirmations, onChange, onKeyDraftsChange, onConfirmationsChange, operations, t, disabled } = props;\n\t\t\tconst [busyEntries, setBusyEntries] = (0, react.useState)({});\n\t\t\tconst anyBusy = Object.values(busyEntries).some(Boolean);\n\t\t\tconst { onBusyChange } = props;\n\t\t\t(0, react.useEffect)(() => {\n\t\t\t\tonBusyChange?.(anyBusy);\n\t\t\t}, [anyBusy, onBusyChange]);\n\t\t\t(0, react.useEffect)(() => () => onBusyChange?.(false), [onBusyChange]);\n\t\t\tconst update = (id, patch) => onChange({ ...entries, [id]: { ...entries[id], ...patch } });\n\t\t\tconst remove = (id) => {\n\t\t\t\tconst { [id]: removed, ...remaining } = entries;\n\t\t\t\tonChange(remaining);\n\t\t\t\tonKeyDraftsChange((current) => { const { [id]: removed, ...rest } = current; return rest; });\n\t\t\t\tonConfirmationsChange((current) => { const { [id]: removed, ...rest } = current; return rest; });\n\t\t\t\tsetBusyEntries((current) => { const { [id]: removed, ...rest } = current; return rest; });\n\t\t\t};\n\t\t\treturn (0, react_jsx_runtime.jsxs)(\"div\", {\n\t\t\t\t\"data-multi-key-entries\": true,\n\t\t\t\tclassName: ModelsSection_module_css_default[\"modelList\"],\n\t\t\t\tchildren: [Object.entries(entries).map(([id, candidate], index) => {\n\t\t\t\t\tconst entry = candidate && typeof candidate === \"object\" && !Array.isArray(candidate) ? candidate : {};\n\t\t\t\t\tconst ref = entry.apiKeyEnv ?? multiKeyRef(route, id);\n\t\t\t\t\tconst draft = Object.hasOwn(keyDrafts, id) ? keyDrafts[id] : \"\";\n\t\t\t\t\tconst keyFailure = apiKeyFailure(draft);\n\t\t\t\t\tconst persisted = Object.hasOwn(props.persistedEntries ?? {}, id) && props.persistedEntries[id]?.apiKeyEnv === ref;\n\t\t\t\t\tconst info = props.credentialChecks?.[ref];\n\t\t\t\t\tconst status = info?.configured === true ? \"multiKeyConfigured\" : info?.configured === false ? \"multiKeyMissing\" : persisted ? \"multiKeySaved\" : \"multiKeyNew\";\n\t\t\t\t\tconst needsConfirmation = draft.trim().length > 0 && ref !== multiKeyRef(route, id);\n\t\t\t\t\tconst canUseStored = persisted && props.probe.provider !== void 0;\n\t\t\t\t\tconst probe = {\n\t\t\t\t\t\t...props.probe,\n\t\t\t\t\t\t...(canUseStored ? { keyEntryId: id } : {}),\n\t\t\t\t\t\t...(draft.trim().length > 0 ? { apiKey: draft.trim() } : {})\n\t\t\t\t\t};\n\t\t\t\t\tconst heading = typeof entry.name === \"string\" && entry.name.trim().length > 0 ? entry.name.trim() : `${t(\"multiKeyDefaultName\")} ${String(index + 1)}`;\n\t\t\t\t\treturn (0, react_jsx_runtime.jsxs)(\"div\", {\n\t\t\t\t\t\t\"data-key-entry-id\": id, role: \"group\", \"aria-label\": heading,\n\t\t\t\t\t\tclassName: ModelsSection_module_css_default[\"rowCard\"],\n\t\t\t\t\t\tstyle: { minWidth: 0 },\n\t\t\t\t\t\tchildren: [(0, react_jsx_runtime.jsxs)(\"div\", {\n\t\t\t\t\t\t\t\"data-key-entry-heading\": true,\n\t\t\t\t\t\t\tclassName: ModelsSection_module_css_default[\"rowHead\"],\n\t\t\t\t\t\t\tstyle: { flexWrap: \"wrap\" },\n\t\t\t\t\t\t\tchildren: [(0, react_jsx_runtime.jsx)(\"span\", {\n\t\t\t\t\t\t\t\tclassName: ModelsSection_module_css_default[\"rowName\"],\n\t\t\t\t\t\t\t\tstyle: { minWidth: 0, overflowWrap: \"anywhere\", flex: \"1 1 120px\" }, children: heading\n\t\t\t\t\t\t\t}), (0, react_jsx_runtime.jsx)(\"div\", {\n\t\t\t\t\t\t\t\tclassName: ModelsSection_module_css_default[\"rowActions\"],\n\t\t\t\t\t\t\t\tchildren: (0, react_jsx_runtime.jsx)(\"button\", {\n\t\t\t\t\t\t\t\t\ttype: \"button\", className: ModelsSection_module_css_default[\"secondaryButton\"], disabled,\n\t\t\t\t\t\t\t\t\tonClick: () => remove(id), children: t(\"multiKeyRemove\")\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t})]\n\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t(0, react_jsx_runtime.jsxs)(\"label\", {\n\t\t\t\t\t\t\t\tclassName: ModelsSection_module_css_default[\"field\"],\n\t\t\t\t\t\t\t\tchildren: [(0, react_jsx_runtime.jsx)(\"span\", { className: ModelsSection_module_css_default[\"fieldLabel\"], children: t(\"multiKeyEntryName\") }),\n\t\t\t\t\t\t\t\t\t(0, react_jsx_runtime.jsx)(\"input\", {\n\t\t\t\t\t\t\t\t\t\tclassName: ModelsSection_module_css_default[\"input\"], type: \"text\", value: entry.name ?? \"\", maxLength: 120,\n\t\t\t\t\t\t\t\t\t\t\"aria-label\": `${t(\"multiKeyEntryName\")} ${String(index + 1)}`, disabled,\n\t\t\t\t\t\t\t\t\t\tonChange: (event) => update(id, { name: event.target.value })\n\t\t\t\t\t\t\t\t\t})]\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t(0, react_jsx_runtime.jsxs)(\"div\", {\n\t\t\t\t\t\t\t\tclassName: ModelsSection_module_css_default[\"field\"],\n\t\t\t\t\t\t\t\tchildren: [(0, react_jsx_runtime.jsx)(\"span\", { className: ModelsSection_module_css_default[\"fieldLabel\"], children: t(\"keyInput\") }),\n\t\t\t\t\t\t\t\t\t(0, react_jsx_runtime.jsx)(ApiKeyInput, {\n\t\t\t\t\t\t\t\t\t\tt, value: draft, placeholder: t(persisted ? \"keyPlaceholderSaved\" : \"keyPlaceholder\"),\n\t\t\t\t\t\t\t\t\t\t\"aria-label\": `${t(\"keyInput\")} ${String(index + 1)}`, \"aria-invalid\": keyFailure !== void 0,\n\t\t\t\t\t\t\t\t\t\tdisabled: props.keyDisabled ?? disabled,\n\t\t\t\t\t\t\t\t\t\tonChange: (event) => {\n\t\t\t\t\t\t\t\t\t\t\tconst value = event.target.value;\n\t\t\t\t\t\t\t\t\t\t\tonKeyDraftsChange((current) => ({ ...current, [id]: value }));\n\t\t\t\t\t\t\t\t\t\t\tonConfirmationsChange((current) => ({ ...current, [id]: false }));\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t\t(0, react_jsx_runtime.jsx)(\"p\", { className: ModelsSection_module_css_default[\"advancedHint\"], children: t(status) }),\n\t\t\t\t\t\t\t\t\t(0, react_jsx_runtime.jsx)(\"p\", { className: ModelsSection_module_css_default[\"advancedHint\"], style: { overflowWrap: \"anywhere\" }, children: t(\"multiKeyRef\").replace(\"{ref}\", () => ref) }),\n\t\t\t\t\t\t\t\t\tkeyFailure === void 0 ? null : (0, react_jsx_runtime.jsx)(\"p\", { className: ModelsSection_module_css_default[\"error\"], children: t(keyFailure) })]\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\tneedsConfirmation ? (0, react_jsx_runtime.jsxs)(\"label\", {\n\t\t\t\t\t\t\t\tclassName: ModelsSection_module_css_default[\"fieldLabel\"],\n\t\t\t\t\t\t\t\tstyle: { display: \"flex\", alignItems: \"flex-start\", gap: 8, overflowWrap: \"anywhere\" },\n\t\t\t\t\t\t\t\tchildren: [(0, react_jsx_runtime.jsx)(\"input\", {\n\t\t\t\t\t\t\t\t\ttype: \"checkbox\", \"data-confirm-entry\": id, \"aria-label\": t(\"multiKeyReplaceConfirm\").replace(\"{ref}\", () => ref),\n\t\t\t\t\t\t\t\t\tchecked: confirmations[id] === true, disabled: props.keyDisabled ?? disabled,\n\t\t\t\t\t\t\t\t\tonChange: (event) => onConfirmationsChange((current) => ({ ...current, [id]: event.target.checked }))\n\t\t\t\t\t\t\t\t}), (0, react_jsx_runtime.jsx)(\"span\", { children: t(\"multiKeyReplaceConfirm\").replace(\"{ref}\", () => ref) })]\n\t\t\t\t\t\t\t}) : null,\n\t\t\t\t\t\t\t(0, react_jsx_runtime.jsx)(ModelListEditor, {\n\t\t\t\t\t\t\t\tmodels: modelDrafts(entry.models), onChange: (models) => update(id, { models }),\n\t\t\t\t\t\t\t\treasoningLevels: props.reasoningLevels, probe,\n\t\t\t\t\t\t\t\tprobeBlocked: keyFailure ?? props.probeBlocked ?? (!canUseStored && draft.trim().length === 0 ? \"multiKeyProbeNeedsKey\" : void 0),\n\t\t\t\t\t\t\t\toperations, t, disabled,\n\t\t\t\t\t\t\t\tonBusyChange: (value) => setBusyEntries((current) => current[id] === value ? current : { ...current, [id]: value })\n\t\t\t\t\t\t\t})]\n\t\t\t\t\t}, id);\n\t\t\t\t}), (0, react_jsx_runtime.jsx)(\"button\", {\n\t\t\t\t\ttype: \"button\", className: ModelsSection_module_css_default[\"addModelButton\"], disabled,\n\t\t\t\t\tonClick: () => {\n\t\t\t\t\t\tlet id, entry;\n\t\t\t\t\t\tdo { [id, entry] = newMultiKeyEntry(route, { name: `${t(\"multiKeyDefaultName\")} ${String(Object.keys(entries).length + 1)}` }); } while (Object.hasOwn(entries, id) || Object.values(entries).some((other) => other.apiKeyEnv === multiKeyRef(route, id)));\n\t\t\t\t\t\tonChange({ ...entries, [id]: entry });\n\t\t\t\t\t}, children: t(\"multiKeyAdd\")\n\t\t\t\t}), (0, react_jsx_runtime.jsx)(\"p\", { className: ModelsSection_module_css_default[\"advancedHint\"], children: t(\"multiKeyKeepCredentials\") })]\n\t\t\t});\n\t\t}\n\t\t//#endregion\n\n\t\t//#region lib/types/client/CustomProviderCard.js"
11
+ },
12
+ {
13
+ "before": "\t\t\t\t\t...probe.provider === void 0 ? {} : { provider: probe.provider },",
14
+ "after": "\t\t\t\t\t...probe.provider === void 0 ? {} : { provider: probe.provider },\n\t\t\t\t\t...probe.keyEntryId === void 0 ? {} : { keyEntryId: probe.keyEntryId },"
15
+ },
16
+ {
17
+ "before": "const { taken, protocols, reasoningLevels, operations, t, onBusyChange } = props;",
18
+ "after": "const { taken, protocols, reasoningLevels, operations, t, onBusyChange } = props;\n\t\t\tconst supportsMultiKey = supportsMultiKeySchema(props.namespace, props.schema, [\"providers\", PROBE_ROUTE]);"
19
+ },
20
+ {
21
+ "before": "const [models, setModels] = (0, react.useState)([]);\n\t\t\tconst [busy, setBusy]",
22
+ "after": "const [models, setModels] = (0, react.useState)([]);\n\t\t\tconst [multiKey, setMultiKey] = (0, react.useState)(false);\n\t\t\tconst [keyEntries, setKeyEntries] = (0, react.useState)({});\n\t\t\tconst [entryKeyDrafts, setEntryKeyDrafts] = (0, react.useState)({});\n\t\t\tconst [entryConfirmations, setEntryConfirmations] = (0, react.useState)({});\n\t\t\tconst saving = (0, react.useRef)(false);\n\t\t\tconst [busy, setBusy]"
23
+ },
24
+ {
25
+ "before": "const modelFailure = validateDeepSeekModels(models) ?? validateReasoningEfforts(models);\n\t\t\tconst keyFailure = apiKeyFailure(keyDraft);",
26
+ "after": "const modelFailure = multiKey ? void 0 : validateDeepSeekModels(models) ?? validateReasoningEfforts(models);\n\t\t\tconst entryFailure = multiKey ? multiKeyFailure(route, keyEntries, entryKeyDrafts, entryConfirmations, t) : void 0;\n\t\t\tconst keyFailure = multiKey ? void 0 : apiKeyFailure(keyDraft);"
27
+ },
28
+ {
29
+ "before": "const ready = route.length > 0 && !routeInvalid && !routeTaken && normalizedBaseURL.length > 0 && !baseUrlInvalid && models.length > 0 && modelFailure === void 0 && keyFailure === void 0;",
30
+ "after": "const ready = (committed || route.length > 0 && !routeInvalid && !routeTaken) && normalizedBaseURL.length > 0 && !baseUrlInvalid && (multiKey ? entryFailure === void 0 : models.length > 0 && modelFailure === void 0 && keyFailure === void 0);"
31
+ },
32
+ {
33
+ "before": "const hint = failure !== void 0 || ready || keyFailure !== void 0 || route.length === 0 || routeInvalid || routeTaken || baseUrlInvalid ? void 0 : normalizedBaseURL.length === 0 ? t(\"customNeedsBaseUrl\") : modelFailure !== void 0 ? `${t(\"model\")} ${String(modelFailure.index + 1)}: ${t(modelFailure.key)}` : t(\"customNeedsModels\");",
34
+ "after": "const hint = entryFailure ?? (failure !== void 0 || ready || keyFailure !== void 0 || route.length === 0 || routeInvalid || routeTaken || baseUrlInvalid ? void 0 : normalizedBaseURL.length === 0 ? t(\"customNeedsBaseUrl\") : modelFailure !== void 0 ? `${t(\"model\")} ${String(modelFailure.index + 1)}: ${t(modelFailure.key)}` : t(\"customNeedsModels\"));"
35
+ },
36
+ {
37
+ "before": "const keyRef = deriveKeyRef(route);\n\t\t\t\tconst storesKey = keyValue.length > 0;",
38
+ "after": "const entries = normalizedMultiKeyEntries(route, keyEntries);\n\t\t\t\tconst firstEntry = Object.values(entries)[0];\n\t\t\t\tconst keyRef = multiKey ? firstEntry?.apiKeyEnv : deriveKeyRef(route);\n\t\t\t\tconst storesKey = !multiKey && keyValue.length > 0;\n\t\t\t\tif (multiKey && entryFailure !== void 0) return entryFailure;"
39
+ },
40
+ {
41
+ "before": "...storesKey ? { apiKeyEnv: keyRef } : {},\n\t\t\t\t\t\tapi: protocol,\n\t\t\t\t\t\tbaseURL: normalizedBaseURL,\n\t\t\t\t\t\tmodels: models.map((model) => ({ ...model }))",
42
+ "after": "...storesKey || multiKey ? { apiKeyEnv: keyRef } : {},\n\t\t\t\t\t\tapi: protocol,\n\t\t\t\t\t\tbaseURL: normalizedBaseURL,\n\t\t\t\t\t\tmodels: (multiKey ? firstEntry.models : models).map((model) => ({ ...model })),\n\t\t\t\t\t\t...(multiKey || Object.keys(keyEntries).length > 0 ? { multiKey, keyEntries: entries } : {})"
43
+ },
44
+ {
45
+ "before": "\t\t\t\tif (storesKey) {\n\t\t\t\t\tconst stored = await operations.storeCredential(keyRef, keyValue);\n\t\t\t\t\tif (stored !== void 0) return stored;\n\t\t\t\t}\n\t\t\t};",
46
+ "after": "\t\t\t\tif (multiKey) return storeMultiKeyDrafts(operations, entries, entryKeyDrafts, setEntryKeyDrafts);\n\t\t\t\tif (storesKey) {\n\t\t\t\t\tconst stored = await operations.storeCredential(keyRef, keyValue);\n\t\t\t\t\tif (stored !== void 0) return stored;\n\t\t\t\t\tsetKeyDraft(\"\");\n\t\t\t\t}\n\t\t\t};"
47
+ },
48
+ {
49
+ "before": "const create = async () => {\n\t\t\t\tsetBusy(true);",
50
+ "after": "const create = async () => {\n\t\t\t\tif (saving.current || !ready || props.readOnly || listBusy) return;\n\t\t\t\tsaving.current = true;\n\t\t\t\tsetBusy(true);"
51
+ },
52
+ {
53
+ "before": "props.onClose(true);\n\t\t\t\t} finally {\n\t\t\t\t\tsetBusy(false);\n\t\t\t\t}\n\t\t\t};\n\t\t\treturn (0, react_jsx_runtime.jsxs)(\"div\", {",
54
+ "after": "props.onClose(true);\n\t\t\t\t} catch {\n\t\t\t\t\tsetFailure(t(\"multiKeySaveFailed\"));\n\t\t\t\t} finally {\n\t\t\t\t\tsaving.current = false;\n\t\t\t\t\tsetBusy(false);\n\t\t\t\t}\n\t\t\t};\n\t\t\treturn (0, react_jsx_runtime.jsxs)(\"div\", {"
55
+ },
56
+ {
57
+ "before": "\t\t\t\t\t(0, react_jsx_runtime.jsxs)(\"div\", {\n\t\t\t\t\t\tclassName: ModelsSection_module_css_default[\"field\"],\n\t\t\t\t\t\tchildren: [\n\t\t\t\t\t\t\t(0, react_jsx_runtime.jsx)(\"span\", {\n\t\t\t\t\t\t\t\tclassName: ModelsSection_module_css_default[\"fieldLabel\"],\n\t\t\t\t\t\t\t\tchildren: t(\"keyInput\")",
58
+ "after": "\t\t\t\t\tsupportsMultiKey ? (0, react_jsx_runtime.jsx)(MultiKeyToggle, {\n\t\t\t\t\t\tt, checked: multiKey, disabled: profileDisabled || listBusy, hasUnsavedKeys: hasMultiKeyDrafts(entryKeyDrafts),\n\t\t\t\t\t\tonChange: (enabled) => {\n\t\t\t\t\t\t\tif (enabled && Object.keys(keyEntries).length === 0) {\n\t\t\t\t\t\t\t\tconst [id, entry] = newMultiKeyEntry(route, { name: displayName || route || t(\"multiKeyDefaultName\"), models });\n\t\t\t\t\t\t\t\tsetKeyEntries({ [id]: entry });\n\t\t\t\t\t\t\t\tif (keyDraft.length > 0) setEntryKeyDrafts({ [id]: keyDraft });\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tsetMultiKey(enabled);\n\t\t\t\t\t\t}\n\t\t\t\t\t}) : null,\n\t\t\t\t\tmultiKey ? (0, react_jsx_runtime.jsx)(MultiKeyEntriesEditor, {\n\t\t\t\t\t\troute, entries: keyEntries, onChange: setKeyEntries,\n\t\t\t\t\t\tkeyDrafts: entryKeyDrafts, onKeyDraftsChange: setEntryKeyDrafts,\n\t\t\t\t\t\tconfirmations: entryConfirmations, onConfirmationsChange: setEntryConfirmations,\n\t\t\t\t\t\tpersistedEntries: committed ? normalizedMultiKeyEntries(route, keyEntries) : {},\n\t\t\t\t\t\tprobe: { settingsNs: NS$1, ...(committed ? { provider: route } : {}), baseURL: normalizedBaseURL, api: protocol },\n\t\t\t\t\t\tprobeBlocked: baseUrlInvalid ? \"customBaseUrlInvalid\" : normalizedBaseURL.length === 0 ? \"customNeedsBaseUrl\" : void 0,\n\t\t\t\t\t\treasoningLevels, operations, t, disabled: profileDisabled || listBusy, keyDisabled: disabled || listBusy, onBusyChange: setListBusy\n\t\t\t\t\t}) : null,\n\t\t\t\t\tmultiKey ? null : (0, react_jsx_runtime.jsxs)(\"div\", {\n\t\t\t\t\t\tclassName: ModelsSection_module_css_default[\"field\"],\n\t\t\t\t\t\tchildren: [\n\t\t\t\t\t\t\t(0, react_jsx_runtime.jsx)(\"span\", {\n\t\t\t\t\t\t\t\tclassName: ModelsSection_module_css_default[\"fieldLabel\"],\n\t\t\t\t\t\t\t\tchildren: t(\"keyInput\")"
59
+ },
60
+ {
61
+ "before": "\t\t\t\t\t(0, react_jsx_runtime.jsx)(ModelListEditor, {\n\t\t\t\t\t\tmodels,\n\t\t\t\t\t\tonChange: setModels,",
62
+ "after": "\t\t\t\t\t!multiKey ? (0, react_jsx_runtime.jsx)(ModelListEditor, {\n\t\t\t\t\t\tmodels,\n\t\t\t\t\t\tonChange: setModels,"
63
+ },
64
+ {
65
+ "before": "\t\t\t\t\t\tonBusyChange: setListBusy\n\t\t\t\t\t}),\n\t\t\t\t\tfailure !== void 0",
66
+ "after": "\t\t\t\t\t\tonBusyChange: setListBusy\n\t\t\t\t\t}) : null,\n\t\t\t\t\tfailure !== void 0"
67
+ },
68
+ {
69
+ "before": "submitDisabled: disabled || !ready,",
70
+ "after": "submitDisabled: disabled || listBusy || !ready,"
71
+ },
72
+ {
73
+ "before": "taken: state.rows.map((row) => row.entry.provider),\n\t\t\t\t\t\t\t\t\t\tprotocols,",
74
+ "after": "taken: state.rows.map((row) => row.entry.provider),\n\t\t\t\t\t\t\t\t\t\tnamespace: piAi,\n\t\t\t\t\t\t\t\t\t\tschema,\n\t\t\t\t\t\t\t\t\t\tprotocols,"
75
+ },
76
+ {
77
+ "before": "const [draft, setDraft] = (0, react.useState)(() => draftAt(schema, namespace, settingsPath));",
78
+ "after": "const [draft, setDraft] = (0, react.useState)(() => draftAt(schema, namespace, settingsPath));\n\t\t\tconst [entryKeyDrafts, setEntryKeyDrafts] = (0, react.useState)({});\n\t\t\tconst [entryConfirmations, setEntryConfirmations] = (0, react.useState)({});\n\t\t\tconst saving = (0, react.useRef)(false);"
79
+ },
80
+ {
81
+ "before": "const keyRef = refFor(schema, namespace, settingsPath, props.provider);",
82
+ "after": "const keyRef = refFor(schema, namespace, settingsPath, props.provider);\n\t\t\tconst supportsMultiKey = layout === \"pi-ai\" && props.declared === true && props.credentialOnly !== true && supportsMultiKeySchema(namespace, schema, settingsPath);\n\t\t\tconst multiKey = supportsMultiKey && (draft.multiKey ?? fallback?.multiKey) === true;\n\t\t\tconst keyEntries = draft.keyEntries ?? fallback?.keyEntries ?? {};\n\t\t\tconst entryFailure = multiKey ? multiKeyFailure(props.provider, keyEntries, entryKeyDrafts, entryConfirmations, t) : void 0;"
83
+ },
84
+ {
85
+ "before": "const modelFailure = validateModels(schema.getPath(draft, [\"models\"]));\n\t\t\tconst keyFailure = apiKeyFailure(keyDraft);",
86
+ "after": "const modelFailure = multiKey ? void 0 : validateModels(schema.getPath(draft, [\"models\"]));\n\t\t\tconst keyFailure = multiKey ? void 0 : apiKeyFailure(keyDraft);"
87
+ },
88
+ {
89
+ "before": "const next = layout === \"pi-ai\" && stringAt(draft, \"apiKeyEnv\") === void 0 && stringAt(fallback, \"apiKeyEnv\") === void 0 && keyValue.length > 0 ? schema.setPath(draft, [\"apiKeyEnv\"], keyRef) : draft;",
90
+ "after": "const normalizedDraft = supportsMultiKey && schema.hasPath(draft, [\"keyEntries\"]) ? schema.setPath(draft, [\"keyEntries\"], normalizedMultiKeyEntries(props.provider, keyEntries)) : draft;\n\t\t\t\tconst next = multiKey ? schema.setPath(normalizedDraft, [\"keyEntries\"], normalizedMultiKeyEntries(props.provider, keyEntries)) : layout === \"pi-ai\" && stringAt(draft, \"apiKeyEnv\") === void 0 && stringAt(fallback, \"apiKeyEnv\") === void 0 && keyValue.length > 0 ? schema.setPath(normalizedDraft, [\"apiKeyEnv\"], keyRef) : normalizedDraft;\n\t\t\t\tif (entryFailure !== void 0) return entryFailure;"
91
+ },
92
+ {
93
+ "before": "if (props.credentialOnly !== true) {\n\t\t\t\t\tconst failure = validateModels",
94
+ "after": "if (props.credentialOnly !== true && !multiKey) {\n\t\t\t\t\tconst failure = validateModels"
95
+ },
96
+ {
97
+ "before": "\t\t\t\tif (keyValue.length > 0) {\n\t\t\t\t\tconst stored = await operations.storeCredential(keyRef, keyValue);",
98
+ "after": "\t\t\t\tif (multiKey) return storeMultiKeyDrafts(operations, next.keyEntries, entryKeyDrafts, setEntryKeyDrafts);\n\t\t\t\tif (keyValue.length > 0) {\n\t\t\t\t\tconst stored = await operations.storeCredential(keyRef, keyValue);"
99
+ },
100
+ {
101
+ "before": "const apply = async () => {\n\t\t\t\tsetBusy(true);",
102
+ "after": "const apply = async () => {\n\t\t\t\tif (saving.current || props.readOnly || listBusy || entryFailure !== void 0) return;\n\t\t\t\tsaving.current = true;\n\t\t\t\tsetBusy(true);"
103
+ },
104
+ {
105
+ "before": "props.onClose(true);\n\t\t\t\t} finally {\n\t\t\t\t\tsetBusy(false);\n\t\t\t\t}\n\t\t\t};\n\t\t\tif (node === void 0)",
106
+ "after": "props.onClose(true);\n\t\t\t\t} catch {\n\t\t\t\t\tsetFailure(t(\"multiKeySaveFailed\"));\n\t\t\t\t} finally {\n\t\t\t\t\tsaving.current = false;\n\t\t\t\t\tsetBusy(false);\n\t\t\t\t}\n\t\t\t};\n\t\t\tif (node === void 0)"
107
+ },
108
+ {
109
+ "before": "return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [keylessNativeAuth ? null :",
110
+ "after": "return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [supportsMultiKey ? (0, react_jsx_runtime.jsx)(MultiKeyToggle, {\n\t\t\t\t\tt, checked: multiKey, disabled: disabled || listBusy, hasUnsavedKeys: hasMultiKeyDrafts(entryKeyDrafts),\n\t\t\t\t\tonChange: (enabled) => {\n\t\t\t\t\t\tlet updated = schema.setPath(draft, [\"multiKey\"], enabled);\n\t\t\t\t\t\tif (enabled && Object.keys(keyEntries).length === 0) {\n\t\t\t\t\t\t\tconst namedRef = stringAt(draft, \"apiKeyEnv\") ?? stringAt(fallback, \"apiKeyEnv\");\n\t\t\t\t\t\t\tconst [id, entry] = newMultiKeyEntry(props.provider, {\n\t\t\t\t\t\t\t\tname: stringAt(draft, \"displayName\") ?? stringAt(fallback, \"displayName\") ?? props.displayName ?? props.provider,\n\t\t\t\t\t\t\t\tapiKeyEnv: namedRef,\n\t\t\t\t\t\t\t\tmodels: draft.models ?? fallback?.models ?? inheritedModels()\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tif (keyDraft.length > 0) {\n\t\t\t\t\t\t\t\tsetEntryKeyDrafts({ [id]: keyDraft });\n\t\t\t\t\t\t\t\tif (namedRef === void 0) updated = schema.setPath(updated, [\"apiKeyEnv\"], multiKeyRef(props.provider, id));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tupdated = schema.setPath(updated, [\"keyEntries\"], { [id]: entry });\n\t\t\t\t\t\t}\n\t\t\t\t\t\tsetDraft(updated);\n\t\t\t\t\t}\n\t\t\t\t}) : null, multiKey ? (0, react_jsx_runtime.jsx)(MultiKeyEntriesEditor, {\n\t\t\t\t\troute: props.provider, entries: keyEntries,\n\t\t\t\t\tonChange: (entries) => setDraft((current) => schema.setPath(current, [\"keyEntries\"], entries)),\n\t\t\t\t\tkeyDrafts: entryKeyDrafts, onKeyDraftsChange: setEntryKeyDrafts,\n\t\t\t\t\tconfirmations: entryConfirmations, onConfirmationsChange: setEntryConfirmations,\n\t\t\t\t\tpersistedEntries: schema.getPath(committedOriginal, [\"keyEntries\"]) ?? fallback?.keyEntries ?? {},\n\t\t\t\t\tcredentialChecks: props.credentialChecks,\n\t\t\t\t\tprobe: { settingsNs: namespace.ns, provider: props.provider, ...(probeBaseURL === void 0 ? {} : { baseURL: probeBaseURL }), ...(probeApi === void 0 ? {} : { api: probeApi }) },\n\t\t\t\t\treasoningLevels, operations, t, disabled: disabled || listBusy, onBusyChange: setListBusy\n\t\t\t\t}) : null, multiKey || keylessNativeAuth ? null :"
111
+ },
112
+ {
113
+ "before": "family === \"deepseek\" ? (0, react_jsx_runtime.jsx)(DeepSeekModelsEditor, {",
114
+ "after": "multiKey ? null : family === \"deepseek\" ? (0, react_jsx_runtime.jsx)(DeepSeekModelsEditor, {"
115
+ },
116
+ {
117
+ "before": "\t\t\t\t\tfailure !== void 0 ? (0, react_jsx_runtime.jsx)(\"p\", {\n\t\t\t\t\t\tclassName: ModelsSection_module_css_default[\"error\"],\n\t\t\t\t\t\tchildren: failure\n\t\t\t\t\t}) : null,\n\t\t\t\t\tprops.credentialOnly",
118
+ "after": "\t\t\t\t\t(failure ?? entryFailure) !== void 0 ? (0, react_jsx_runtime.jsx)(\"p\", {\n\t\t\t\t\t\tclassName: ModelsSection_module_css_default[\"error\"],\n\t\t\t\t\t\tchildren: failure ?? entryFailure\n\t\t\t\t\t}) : null,\n\t\t\t\t\tprops.credentialOnly"
119
+ },
120
+ {
121
+ "before": "submitDisabled: disabled || layout === \"unknown\" || props.credentialOnly !== true && modelFailure !== void 0 || shownKeyFailure !== void 0 || props.credentialRequired === true && keyValue.length === 0,",
122
+ "after": "submitDisabled: disabled || listBusy || layout === \"unknown\" || entryFailure !== void 0 || props.credentialOnly !== true && modelFailure !== void 0 || !multiKey && (shownKeyFailure !== void 0 || props.credentialRequired === true && keyValue.length === 0),"
123
+ },
124
+ {
125
+ "before": "return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [supportsMultiKey ? (0, react_jsx_runtime.jsx)(MultiKeyToggle, {",
126
+ "after": "const credentials = (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [supportsMultiKey ? (0, react_jsx_runtime.jsx)(MultiKeyToggle, {"
127
+ },
128
+ {
129
+ "before": "\t\t\t\t}), props.credentialOnly === true ? null : (0, react_jsx_runtime.jsxs)(\"details\", {\n\t\t\t\t\tclassName: ModelsSection_module_css_default[\"customized\"],",
130
+ "after": "\t\t\t\t})] });\n\t\t\t\tconst customization = props.credentialOnly === true ? null : (0, react_jsx_runtime.jsxs)(\"details\", {\n\t\t\t\t\tclassName: ModelsSection_module_css_default[\"customized\"],\n\t\t\t\t\topen: supportsMultiKey ? true : void 0,\n\t\t\t\t\t\"data-multi-key-shared-settings\": supportsMultiKey ? true : void 0,"
131
+ },
132
+ {
133
+ "before": "children: t(\"customized\")\n\t\t\t\t\t}), (0, react_jsx_runtime.jsxs)(\"div\", {",
134
+ "after": "children: t(supportsMultiKey ? \"multiKeySharedSettings\" : \"customized\")\n\t\t\t\t\t}), (0, react_jsx_runtime.jsxs)(\"div\", {"
135
+ },
136
+ {
137
+ "before": "\t\t\t\t})] });\n\t\t\t};\n\t\t\treturn (0, react_jsx_runtime.jsxs)(\"div\", {\n\t\t\t\tclassName: props.credentialOnly",
138
+ "after": "\t\t\t\t});\n\t\t\t\treturn (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: supportsMultiKey ? [customization, credentials] : [credentials, customization] });\n\t\t\t};\n\t\t\treturn (0, react_jsx_runtime.jsxs)(\"div\", {\n\t\t\t\tclassName: props.credentialOnly"
139
+ },
140
+ {
141
+ "before": "\t\tconst en = {",
142
+ "after": "\t\tconst en = {\n\t\t\tmultiKey: \"Multiple key configurations\",\n\t\t\tmultiKeyHelp: \"Configurations share one provider ID, endpoint and protocol; each has its own name, API key and models. Turning this off restores the original single-key configuration without deleting entries or credentials.\",\n\t\t\tmultiKeySharedSettings: \"Shared settings\",\n\t\t\tmultiKeyAdd: \"Add key configuration\",\n\t\t\tmultiKeyRemove: \"Remove\",\n\t\t\tmultiKeyEntryName: \"Configuration name\",\n\t\t\tmultiKeyDefaultName: \"Key configuration\",\n\t\t\tmultiKeyDisableTitle: \"Turn off multiple key configurations?\",\n\t\t\tmultiKeyDisableDescription: \"After applying, this provider will use its original single-key configuration. Saved configurations and credentials will not be deleted. Sessions using a key configuration will need you to re-enable it or select a single-key model; no other key will be chosen automatically.\",\n\t\t\tmultiKeyKeepEnabled: \"Keep enabled\",\n\t\t\tmultiKeyDisableConfirm: \"Turn off in draft\",\n\t\t\tmultiKeyUnsavedTitle: \"Save the API keys before turning this off\",\n\t\t\tmultiKeyUnsavedKeys: \"Some API keys have been typed but not saved. Turning this off and applying would not store those inputs, so the switch will stay on. Return to the configurations and apply to save them, then reopen this card to turn it off. Nothing has been deleted.\",\n\t\t\tmultiKeyReturnToEdit: \"Return to configurations\",\n\t\t\tmultiKeyRef: \"Credential reference: {ref}\",\n\t\t\tmultiKeySaved: \"Saved reference; credential status not checked. Leave the key blank to keep it.\",\n\t\t\tmultiKeyNew: \"Not saved yet. An empty key does not create a credential.\",\n\t\t\tmultiKeyConfigured: \"Credential confirmed configured; leave blank to keep it.\",\n\t\t\tmultiKeyMissing: \"Credential confirmed missing. Enter a key or configure this reference.\",\n\t\t\tmultiKeyKeepCredentials: \"Removing a key configuration does not delete its stored credential.\",\n\t\t\tmultiKeyNeedsEntries: \"Add at least one key configuration.\",\n\t\t\tmultiKeyInvalidId: \"Invalid key-configuration ID; reopen this card or fix the profile.\",\n\t\t\tmultiKeyInvalidName: \"Each key configuration needs a name of 1–120 characters.\",\n\t\t\tmultiKeyInvalidRef: \"Invalid credential reference.\",\n\t\t\tmultiKeyDuplicateRef: \"Two configurations use the same credential reference. Each configuration must have its own reference.\",\n\t\t\tmultiKeyNeedsModels: \"Each key configuration needs at least one model.\",\n\t\t\tmultiKeyReplaceConfirm: \"Replace the key at {ref}. Other configurations sharing this reference will also be affected.\",\n\t\t\tmultiKeyConfirmRequired: \"Confirm the credential replacement before applying.\",\n\t\t\tmultiKeyProbeNeedsKey: \"Enter this configuration’s API key to discover models before saving. The provider’s original key will not be used.\",\n\t\t\tmultiKeySaveFailed: \"Saving did not complete. Keep this card open and retry; successful credential writes will not be repeated.\","
143
+ },
144
+ {
145
+ "before": "\t\tconst zh = {",
146
+ "after": "\t\tconst zh = {\n\t\t\tmultiKey: \"多密钥配置\",\n\t\t\tmultiKeyHelp: \"各配置共享 Provider ID、API 地址与协议,分别管理名称、API 密钥和模型。关闭后恢复原单密钥配置,已保存的配置与密钥不会删除。\",\n\t\t\tmultiKeySharedSettings: \"公共设置\",\n\t\t\tmultiKeyAdd: \"添加密钥配置\",\n\t\t\tmultiKeyRemove: \"移除\",\n\t\t\tmultiKeyEntryName: \"配置名称\",\n\t\t\tmultiKeyDefaultName: \"密钥配置\",\n\t\t\tmultiKeyDisableTitle: \"关闭多密钥配置?\",\n\t\t\tmultiKeyDisableDescription: \"应用后,此供应商将使用原单密钥配置,已保存的密钥配置与凭据不会删除。正在使用密钥配置的会话需要重新开启,或手动选择单密钥模型;不会自动换用其他密钥。\",\n\t\t\tmultiKeyKeepEnabled: \"保持开启\",\n\t\t\tmultiKeyDisableConfirm: \"确认关闭(待应用)\",\n\t\t\tmultiKeyUnsavedTitle: \"请先保存新输入的密钥\",\n\t\t\tmultiKeyUnsavedKeys: \"当前有尚未保存的 API 密钥输入。关闭后直接应用不会保存这些输入,因此开关将保持开启。请返回密钥配置并应用保存,再重新打开此卡片关闭;当前输入与已存储的密钥均未删除。\",\n\t\t\tmultiKeyReturnToEdit: \"返回密钥配置\",\n\t\t\tmultiKeyRef: \"密钥引用:{ref}\",\n\t\t\tmultiKeySaved: \"引用已保存,尚未检查密钥状态;输入留空可保留原密钥。\",\n\t\t\tmultiKeyNew: \"尚未保存;输入留空不会创建密钥。\",\n\t\t\tmultiKeyConfigured: \"已确认密钥已配置;留空可保留。\",\n\t\t\tmultiKeyMissing: \"已确认此引用缺少密钥,请输入或在环境中配置。\",\n\t\t\tmultiKeyKeepCredentials: \"移除密钥配置不会删除已存储的密钥。\",\n\t\t\tmultiKeyNeedsEntries: \"请至少添加一个密钥配置。\",\n\t\t\tmultiKeyInvalidId: \"密钥配置 ID 无效,请重新打开此卡片或修正配置。\",\n\t\t\tmultiKeyInvalidName: \"每个配置名称须为 1–120 个字符。\",\n\t\t\tmultiKeyInvalidRef: \"密钥引用无效。\",\n\t\t\tmultiKeyDuplicateRef: \"多个密钥配置使用了相同的密钥引用;每个配置必须使用独立引用。\",\n\t\t\tmultiKeyNeedsModels: \"每个密钥配置至少需要一个模型。\",\n\t\t\tmultiKeyReplaceConfirm: \"确认替换 {ref} 的密钥;共用此引用的其他配置也会受到影响。\",\n\t\t\tmultiKeyConfirmRequired: \"请先确认替换已引用的密钥,再应用。\",\n\t\t\tmultiKeyProbeNeedsKey: \"保存前请先输入此配置的 API 密钥再获取模型;不会使用供应商原来的密钥。\",\n\t\t\tmultiKeySaveFailed: \"保存尚未完成。请保留此卡片并重试;已成功写入的密钥不会重复写入。\","
147
+ }
148
+ ]
149
+ }
package/package.json CHANGED
@@ -1,6 +1,66 @@
1
1
  {
2
2
  "name": "dsh-model-groups",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.3.3",
4
+ "description": "DSH 网页模型选择器:供应商与密钥配置分层折叠、多密钥手动选择。支持 DSH 0.2.2-rc.1。",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/betsunninda9-lgtm/dsh-model-groups.git"
10
+ },
11
+ "homepage": "https://github.com/betsunninda9-lgtm/dsh-model-groups#readme",
12
+ "bugs": {
13
+ "url": "https://github.com/betsunninda9-lgtm/dsh-model-groups/issues"
14
+ },
15
+ "keywords": ["dsh", "deepseek-harness", "models", "multi-key", "model-picker"],
16
+ "publishConfig": {
17
+ "access": "public",
18
+ "registry": "https://registry.npmjs.org/"
19
+ },
20
+ "main": "./src/index.js",
21
+ "exports": {
22
+ ".": "./src/index.js",
23
+ "./client": "./lib/client.js",
24
+ "./package.json": "./package.json"
25
+ },
26
+ "files": [
27
+ "src",
28
+ "lib",
29
+ "native/*.patch.json",
30
+ "scripts",
31
+ "cordis.patch.yml",
32
+ "README.md",
33
+ "LICENSE"
34
+ ],
35
+ "engines": {
36
+ "node": ">=22",
37
+ "dsh": "0.2.2-rc.1"
38
+ },
39
+ "dsh": {
40
+ "bundle": {
41
+ "patch": "./cordis.patch.yml"
42
+ },
43
+ "client": {
44
+ "platform": "web",
45
+ "inject": [
46
+ "@deepseek-ai/dsh-client-ui-model-selection",
47
+ "@deepseek-ai/dsh-client-ui-renderer",
48
+ "@deepseek-ai/dsh-client-ui-settings-models"
49
+ ],
50
+ "external": [
51
+ "react",
52
+ "react-dom",
53
+ "react/jsx-runtime",
54
+ "@deepseek-ai/dsh-client-ui-primitives"
55
+ ]
56
+ }
57
+ },
58
+ "scripts": {
59
+ "build": "node scripts/build.mjs",
60
+ "check:build": "node scripts/build.mjs --check",
61
+ "test": "node --test test/*.test.mjs",
62
+ "test:ui": "node --test test/picker-ui.test.mjs",
63
+ "native:check": "node scripts/native-patches.mjs --check",
64
+ "prepack": "npm run build && npm run check:build"
65
+ }
66
+ }
@@ -0,0 +1,22 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+
5
+ const root = fileURLToPath(new URL('../', import.meta.url));
6
+ const read = name => fs.readFileSync(path.join(root, name), 'utf8');
7
+ const withoutExports = source => source.replace(/^export /gm, '');
8
+ // Styles belong to the mounted plugin, not to module materialization: a
9
+ // disposal removes them and a re-applied (memoized) module must restore them.
10
+ const styles = `\nconst MODEL_GROUPS_CSS = ${JSON.stringify(read('src/groups.css'))};\nfunction installModelGroupsStyles() {\n const tagId = 'dsh-model-groups/groups.css';\n if (document.querySelector('style[data-plugin-css="' + tagId + '"]') !== null) return;\n const style = document.createElement('style');\n style.dataset.plugin = 'dsh-model-groups';\n style.dataset.pluginCss = tagId;\n style.textContent = MODEL_GROUPS_CSS;\n document.head.appendChild(style);\n}\n`;
11
+ const source = `// Generated by scripts/build.mjs; edit src instead.\nwindow.__ModuleLoader__.load({\n id: 'dsh-model-groups',\n factory(require) {\n const react = require('react');\n const react_dom = require('react-dom');\n const react_jsx_runtime = require('react/jsx-runtime');\n const _deepseek_ai_dsh_client_ui_primitives = require('@deepseek-ai/dsh-client-ui-primitives');\n${withoutExports(read('src/group-state.js'))}\n${withoutExports(read('src/hierarchy.js')).replace(/^import .*;\n/gm, '')}\n${read('src/model-select.js')}\n${withoutExports(read('src/fallback.js'))}\n${styles}\n${withoutExports(read('src/client.js'))}\n return { apply, inject };\n },\n});\n`;
12
+ const target = path.join(root, 'lib/client.js');
13
+ // Compile the classic-script bundle before writing anything.
14
+ new Function(source);
15
+ if (process.argv.includes('--check')) {
16
+ if (!fs.existsSync(target) || fs.readFileSync(target, 'utf8') !== source) throw new Error('Client bundle is stale. Run npm run build.');
17
+ console.log('Client bundle is up to date.');
18
+ } else {
19
+ fs.mkdirSync(path.dirname(target), { recursive: true });
20
+ fs.writeFileSync(target, source);
21
+ console.log(`Built lib/client.js (${Buffer.byteLength(source)} bytes).`);
22
+ }