nexgenk 1.0.1 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main.mjs +537 -222
- package/package.json +1 -1
package/dist/main.mjs
CHANGED
|
@@ -41447,10 +41447,10 @@ function finalizeChatCompletion(snapshot, params) {
|
|
|
41447
41447
|
tool_calls: tool_calls.map((tool_call, i) => {
|
|
41448
41448
|
const { function: fn, type, id, ...toolRest } = tool_call;
|
|
41449
41449
|
const { arguments: args, name, ...fnRest } = fn || {};
|
|
41450
|
-
if (id == null) throw new OpenAIError(`missing choices[${index}].tool_calls[${i}].id\n${str$
|
|
41451
|
-
if (type == null) throw new OpenAIError(`missing choices[${index}].tool_calls[${i}].type\n${str$
|
|
41452
|
-
if (name == null) throw new OpenAIError(`missing choices[${index}].tool_calls[${i}].function.name\n${str$
|
|
41453
|
-
if (args == null) throw new OpenAIError(`missing choices[${index}].tool_calls[${i}].function.arguments\n${str$
|
|
41450
|
+
if (id == null) throw new OpenAIError(`missing choices[${index}].tool_calls[${i}].id\n${str$3(snapshot)}`);
|
|
41451
|
+
if (type == null) throw new OpenAIError(`missing choices[${index}].tool_calls[${i}].type\n${str$3(snapshot)}`);
|
|
41452
|
+
if (name == null) throw new OpenAIError(`missing choices[${index}].tool_calls[${i}].function.name\n${str$3(snapshot)}`);
|
|
41453
|
+
if (args == null) throw new OpenAIError(`missing choices[${index}].tool_calls[${i}].function.arguments\n${str$3(snapshot)}`);
|
|
41454
41454
|
return {
|
|
41455
41455
|
...toolRest,
|
|
41456
41456
|
id,
|
|
@@ -41483,7 +41483,7 @@ function finalizeChatCompletion(snapshot, params) {
|
|
|
41483
41483
|
...system_fingerprint ? { system_fingerprint } : {}
|
|
41484
41484
|
}, params);
|
|
41485
41485
|
}
|
|
41486
|
-
function str$
|
|
41486
|
+
function str$3(x) {
|
|
41487
41487
|
return JSON.stringify(x);
|
|
41488
41488
|
}
|
|
41489
41489
|
var _ChatCompletionStream_instances, _ChatCompletionStream_params, _ChatCompletionStream_choiceEventStates, _ChatCompletionStream_currentChatCompletionSnapshot, _ChatCompletionStream_beginRequest, _ChatCompletionStream_getChoiceEventState, _ChatCompletionStream_addChunk, _ChatCompletionStream_emitToolCallDoneEvent, _ChatCompletionStream_emitContentDoneEvents, _ChatCompletionStream_endRequest, _ChatCompletionStream_getAutoParseableResponseFormat, _ChatCompletionStream_accumulateChatCompletion, ChatCompletionStream;
|
|
@@ -58702,7 +58702,7 @@ function tokenFromWire(wire) {
|
|
|
58702
58702
|
}
|
|
58703
58703
|
var init_types$28 = __esmMin((() => {}));
|
|
58704
58704
|
// ../../packages/nexgen-auth/src/utils.ts
|
|
58705
|
-
function isRecord$
|
|
58705
|
+
function isRecord$26(value) {
|
|
58706
58706
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
58707
58707
|
}
|
|
58708
58708
|
var init_utils$4 = __esmMin((() => {}));
|
|
@@ -58757,7 +58757,7 @@ var init_storage = __esmMin((() => {
|
|
|
58757
58757
|
} catch {
|
|
58758
58758
|
return;
|
|
58759
58759
|
}
|
|
58760
|
-
if (!isRecord$
|
|
58760
|
+
if (!isRecord$26(parsed)) return void 0;
|
|
58761
58761
|
return tokenFromWire(parsed);
|
|
58762
58762
|
}
|
|
58763
58763
|
async save(name, token) {
|
|
@@ -58810,7 +58810,7 @@ function extractApiErrorMessage(value) {
|
|
|
58810
58810
|
}
|
|
58811
58811
|
return;
|
|
58812
58812
|
}
|
|
58813
|
-
if (!isRecord$
|
|
58813
|
+
if (!isRecord$26(value)) return void 0;
|
|
58814
58814
|
for (const key of DIRECT_ERROR_KEYS) {
|
|
58815
58815
|
const message = stringField$7(value, key);
|
|
58816
58816
|
if (message !== void 0) return message;
|
|
@@ -58818,7 +58818,7 @@ function extractApiErrorMessage(value) {
|
|
|
58818
58818
|
const error = value["error"];
|
|
58819
58819
|
const errorString = nonEmptyString$6(error);
|
|
58820
58820
|
if (errorString !== void 0) return errorString;
|
|
58821
|
-
if (isRecord$
|
|
58821
|
+
if (isRecord$26(error)) for (const key of NESTED_ERROR_KEYS) {
|
|
58822
58822
|
const message = stringField$7(error, key);
|
|
58823
58823
|
if (message !== void 0) return message;
|
|
58824
58824
|
}
|
|
@@ -58907,7 +58907,7 @@ async function postForm(url, params, deviceHeaders, options) {
|
|
|
58907
58907
|
let data = {};
|
|
58908
58908
|
try {
|
|
58909
58909
|
const parsed = await response.json();
|
|
58910
|
-
if (isRecord$
|
|
58910
|
+
if (isRecord$26(parsed)) data = parsed;
|
|
58911
58911
|
} catch {}
|
|
58912
58912
|
return {
|
|
58913
58913
|
status,
|
|
@@ -60827,7 +60827,7 @@ function formatDuration$1(totalSeconds) {
|
|
|
60827
60827
|
return parts.length > 0 ? parts.join(" ") : "0s";
|
|
60828
60828
|
}
|
|
60829
60829
|
function parseManagedUsagePayload(payload) {
|
|
60830
|
-
if (!isRecord$
|
|
60830
|
+
if (!isRecord$26(payload)) return {
|
|
60831
60831
|
usages: {},
|
|
60832
60832
|
extraUsage: null
|
|
60833
60833
|
};
|
|
@@ -60837,7 +60837,7 @@ function parseManagedUsagePayload(payload) {
|
|
|
60837
60837
|
};
|
|
60838
60838
|
}
|
|
60839
60839
|
function parseQuotaUsages(raw) {
|
|
60840
|
-
if (!isRecord$
|
|
60840
|
+
if (!isRecord$26(raw)) return {};
|
|
60841
60841
|
return {
|
|
60842
60842
|
limit5h: parseQuotaEntry(raw["limit_5h"]),
|
|
60843
60843
|
limit7d: parseQuotaEntry(raw["limit_7d"]),
|
|
@@ -60846,7 +60846,7 @@ function parseQuotaUsages(raw) {
|
|
|
60846
60846
|
};
|
|
60847
60847
|
}
|
|
60848
60848
|
function parseQuotaEntry(raw) {
|
|
60849
|
-
if (!isRecord$
|
|
60849
|
+
if (!isRecord$26(raw)) return void 0;
|
|
60850
60850
|
const usedRatio = ratioValue(raw["used_ratio"]);
|
|
60851
60851
|
if (usedRatio === void 0) return void 0;
|
|
60852
60852
|
const resetAt = raw["reset_time"];
|
|
@@ -60861,7 +60861,7 @@ function fixedPointToCents(value) {
|
|
|
60861
60861
|
return Math.round(cents);
|
|
60862
60862
|
}
|
|
60863
60863
|
function parseMoney(raw) {
|
|
60864
|
-
if (!isRecord$
|
|
60864
|
+
if (!isRecord$26(raw)) return null;
|
|
60865
60865
|
const cents = intValue(raw["priceInCents"]);
|
|
60866
60866
|
if (cents === null) return null;
|
|
60867
60867
|
return {
|
|
@@ -60870,9 +60870,9 @@ function parseMoney(raw) {
|
|
|
60870
60870
|
};
|
|
60871
60871
|
}
|
|
60872
60872
|
function parseBoosterWallet(raw) {
|
|
60873
|
-
if (!isRecord$
|
|
60873
|
+
if (!isRecord$26(raw)) return null;
|
|
60874
60874
|
const balance = raw["balance"];
|
|
60875
|
-
if (!isRecord$
|
|
60875
|
+
if (!isRecord$26(balance)) return null;
|
|
60876
60876
|
if (balance["type"] !== "BOOSTER") return null;
|
|
60877
60877
|
const amountRaw = intValue(balance["amount"]);
|
|
60878
60878
|
if (amountRaw === null || amountRaw <= 0) return null;
|
|
@@ -61000,8 +61000,8 @@ function userExtras(existing, remoteOwnedFields) {
|
|
|
61000
61000
|
return out;
|
|
61001
61001
|
}
|
|
61002
61002
|
function mergeRefreshedModelAlias(existing, remote, remoteOwnedFields) {
|
|
61003
|
-
const current = isRecord$
|
|
61004
|
-
const overrides = cloneOverrides(isRecord$
|
|
61003
|
+
const current = isRecord$26(existing) ? existing : {};
|
|
61004
|
+
const overrides = cloneOverrides(isRecord$26(current["overrides"]) ? current["overrides"] : void 0);
|
|
61005
61005
|
return {
|
|
61006
61006
|
...userExtras(current, remoteOwnedFields),
|
|
61007
61007
|
...remote,
|
|
@@ -61184,19 +61184,19 @@ function resolveNexgenCodeLoginAuth(options) {
|
|
|
61184
61184
|
};
|
|
61185
61185
|
}
|
|
61186
61186
|
function toModelInfo$1(item) {
|
|
61187
|
-
if (!isRecord$
|
|
61187
|
+
if (!isRecord$26(item) || typeof item["id"] !== "string" || item["id"].length === 0) return;
|
|
61188
61188
|
const rawLimit = item["limit"];
|
|
61189
|
-
const limit = isRecord$
|
|
61189
|
+
const limit = isRecord$26(rawLimit) ? rawLimit : void 0;
|
|
61190
61190
|
const contextLength = Number(limit?.["context"]);
|
|
61191
61191
|
if (!Number.isInteger(contextLength) || contextLength <= 0) throw new Error(`NexgenK model "${item["id"]}" must include a positive limit.context.`);
|
|
61192
61192
|
const displayName = item["display_name"];
|
|
61193
61193
|
const normalizedDisplayName = typeof displayName === "string" && displayName.length > 0 ? displayName : void 0;
|
|
61194
61194
|
const supportsToolUse = Object.hasOwn(item, "supports_tool_use") ? Boolean(item["supports_tool_use"]) : true;
|
|
61195
61195
|
const rawModalities = item["modalities"];
|
|
61196
|
-
const inputModalities = isRecord$
|
|
61196
|
+
const inputModalities = isRecord$26(rawModalities) ? parseStringArray(rawModalities["input"]) : void 0;
|
|
61197
61197
|
const reasoning = parseModelReasoning(item["reasoning"]);
|
|
61198
61198
|
const rawTools = item["tools"];
|
|
61199
|
-
const supportsDynamicTools = isRecord$
|
|
61199
|
+
const supportsDynamicTools = isRecord$26(rawTools) && rawTools["dynamic_load"] === true;
|
|
61200
61200
|
return {
|
|
61201
61201
|
id: item["id"],
|
|
61202
61202
|
contextLength,
|
|
@@ -61222,7 +61222,7 @@ function toModelInfo$1(item) {
|
|
|
61222
61222
|
* that is not listed in `valid` is dropped.
|
|
61223
61223
|
*/
|
|
61224
61224
|
function parseModelReasoning(value) {
|
|
61225
|
-
if (!isRecord$
|
|
61225
|
+
if (!isRecord$26(value)) return {
|
|
61226
61226
|
supportsReasoning: false,
|
|
61227
61227
|
supportsThinkingType: "no",
|
|
61228
61228
|
supportEfforts: void 0,
|
|
@@ -61231,7 +61231,7 @@ function parseModelReasoning(value) {
|
|
|
61231
61231
|
const rawType = value["type"];
|
|
61232
61232
|
const supportsThinkingType = rawType === "only" || rawType === "both" ? rawType : rawType === "none" ? "no" : void 0;
|
|
61233
61233
|
const rawEffort = value["effort"];
|
|
61234
|
-
const effort = isRecord$
|
|
61234
|
+
const effort = isRecord$26(rawEffort) ? rawEffort : void 0;
|
|
61235
61235
|
const supportEfforts = effort !== void 0 ? parseStringArray(effort["valid"]) : void 0;
|
|
61236
61236
|
const rawDefault = effort?.["default"];
|
|
61237
61237
|
const parsedDefault = typeof rawDefault === "string" && rawDefault.length > 0 ? rawDefault : void 0;
|
|
@@ -61294,7 +61294,7 @@ async function fetchManagedNexgenCodeModels(options) {
|
|
|
61294
61294
|
throw new Error(message);
|
|
61295
61295
|
}
|
|
61296
61296
|
const payload = await response.json();
|
|
61297
|
-
if (!isRecord$
|
|
61297
|
+
if (!isRecord$26(payload) || !Array.isArray(payload["data"])) throw new Error(`Unexpected models response for ${baseUrl}.`);
|
|
61298
61298
|
return payload["data"].map((item) => toModelInfo$1(item)).filter((item) => item !== void 0);
|
|
61299
61299
|
}
|
|
61300
61300
|
/**
|
|
@@ -61331,10 +61331,10 @@ function applyManagedNexgenCodeConfig(config, options) {
|
|
|
61331
61331
|
apiKeyEnv: "NEXGEN_API_KEY"
|
|
61332
61332
|
};
|
|
61333
61333
|
const upstreamKeys = new Set(options.models.map((m) => managedModelKey(m.id)));
|
|
61334
|
-
for (const [key, model] of Object.entries(existingModels)) if (isRecord$
|
|
61334
|
+
for (const [key, model] of Object.entries(existingModels)) if (isRecord$26(model) && model["provider"] === "managed:nexgenk" && !upstreamKeys.has(key)) delete existingModels[key];
|
|
61335
61335
|
for (const model of options.models) {
|
|
61336
61336
|
const key = managedModelKey(model.id);
|
|
61337
|
-
existingModels[key] = mergeRefreshedModelAlias(isRecord$
|
|
61337
|
+
existingModels[key] = mergeRefreshedModelAlias(isRecord$26(existingModels[key]) ? existingModels[key] : {}, toManagedModelAlias(NEXGEN_PROVIDER_NAME, model), MANAGED_NEXGEN_MODEL_FIELDS);
|
|
61338
61338
|
}
|
|
61339
61339
|
config.models = existingModels;
|
|
61340
61340
|
config.defaultModel = selectedDefault.modelKey;
|
|
@@ -61370,10 +61370,10 @@ function applyManagedApiKeyProviderModels(config, providerId, models, aliasPrefi
|
|
|
61370
61370
|
for (const model of models) assertPositiveContextLength(model);
|
|
61371
61371
|
const existingModels = config.models ?? {};
|
|
61372
61372
|
const upstreamKeys = new Set(models.map((m) => `${aliasPrefix}${m.id}`));
|
|
61373
|
-
for (const [key, model] of Object.entries(existingModels)) if (isRecord$
|
|
61373
|
+
for (const [key, model] of Object.entries(existingModels)) if (isRecord$26(model) && model["provider"] === providerId && !upstreamKeys.has(key)) delete existingModels[key];
|
|
61374
61374
|
for (const model of models) {
|
|
61375
61375
|
const key = `${aliasPrefix}${model.id}`;
|
|
61376
|
-
existingModels[key] = mergeRefreshedModelAlias(isRecord$
|
|
61376
|
+
existingModels[key] = mergeRefreshedModelAlias(isRecord$26(existingModels[key]) ? existingModels[key] : {}, toManagedModelAlias(providerId, model), MANAGED_NEXGEN_MODEL_FIELDS);
|
|
61377
61377
|
}
|
|
61378
61378
|
config.models = existingModels;
|
|
61379
61379
|
}
|
|
@@ -61382,7 +61382,7 @@ function applyManagedNexgenCodeLogoutConfig(config) {
|
|
|
61382
61382
|
let removedDefaultModel = false;
|
|
61383
61383
|
const existingModels = config.models ?? {};
|
|
61384
61384
|
for (const [key, model] of Object.entries(existingModels)) {
|
|
61385
|
-
if (!isRecord$
|
|
61385
|
+
if (!isRecord$26(model) || model["provider"] !== "managed:nexgenk") continue;
|
|
61386
61386
|
delete existingModels[key];
|
|
61387
61387
|
if (config.defaultModel === key) removedDefaultModel = true;
|
|
61388
61388
|
}
|
|
@@ -61421,7 +61421,7 @@ function selectDefaultModel(config, models, options) {
|
|
|
61421
61421
|
function canPreserveDefaultModel(existingModels, defaultModel, managedModels) {
|
|
61422
61422
|
if (managedModels.has(defaultModel)) return true;
|
|
61423
61423
|
const existing = existingModels[defaultModel];
|
|
61424
|
-
return isRecord$
|
|
61424
|
+
return isRecord$26(existing) && existing["provider"] !== "managed:nexgenk";
|
|
61425
61425
|
}
|
|
61426
61426
|
function clearManagedNexgenCodeConfig(config) {
|
|
61427
61427
|
const removedProvider = Object.hasOwn(config.providers, NEXGEN_PROVIDER_NAME);
|
|
@@ -61429,7 +61429,7 @@ function clearManagedNexgenCodeConfig(config) {
|
|
|
61429
61429
|
const removedModels = [];
|
|
61430
61430
|
const models = config.models;
|
|
61431
61431
|
if (models !== void 0) for (const [key, model] of Object.entries(models)) {
|
|
61432
|
-
if (!isRecord$
|
|
61432
|
+
if (!isRecord$26(model) || model["provider"] !== "managed:nexgenk") continue;
|
|
61433
61433
|
delete models[key];
|
|
61434
61434
|
removedModels.push(key);
|
|
61435
61435
|
}
|
|
@@ -62003,7 +62003,7 @@ function nexgenkCodeUserInfoUrl() {
|
|
|
62003
62003
|
* string, is malformed; every other field degrades independently.
|
|
62004
62004
|
*/
|
|
62005
62005
|
function parseManagedUserInfoPayload(payload) {
|
|
62006
|
-
if (!isRecord$
|
|
62006
|
+
if (!isRecord$26(payload)) return null;
|
|
62007
62007
|
const userId = stringField$6(payload, "user_id");
|
|
62008
62008
|
if (userId === void 0) return null;
|
|
62009
62009
|
return {
|
|
@@ -62027,7 +62027,7 @@ function parseManagedUserInfoPayload(payload) {
|
|
|
62027
62027
|
};
|
|
62028
62028
|
}
|
|
62029
62029
|
function parsePhone(raw) {
|
|
62030
|
-
if (!isRecord$
|
|
62030
|
+
if (!isRecord$26(raw)) return void 0;
|
|
62031
62031
|
const countryCode = stringField$6(raw, "country_code") ?? "";
|
|
62032
62032
|
const number = stringField$6(raw, "number") ?? "";
|
|
62033
62033
|
if (countryCode === "" && number === "") return void 0;
|
|
@@ -62192,7 +62192,7 @@ async function fetchChatTitle(url, accessToken, chatContent, opts = {}) {
|
|
|
62192
62192
|
}
|
|
62193
62193
|
}
|
|
62194
62194
|
function parseChatTitle(payload) {
|
|
62195
|
-
if (!isRecord$
|
|
62195
|
+
if (!isRecord$26(payload)) return void 0;
|
|
62196
62196
|
const value = payload["title"];
|
|
62197
62197
|
if (typeof value !== "string") return void 0;
|
|
62198
62198
|
const title = value.trim();
|
|
@@ -62391,7 +62391,7 @@ function isOpenPlatformId(id) {
|
|
|
62391
62391
|
return OPEN_PLATFORMS.some((p) => p.id === id);
|
|
62392
62392
|
}
|
|
62393
62393
|
function toModelInfo(item) {
|
|
62394
|
-
if (!isRecord$
|
|
62394
|
+
if (!isRecord$26(item) || typeof item["id"] !== "string" || item["id"].length === 0) return;
|
|
62395
62395
|
const contextLength = Number(item["context_length"]);
|
|
62396
62396
|
if (!Number.isInteger(contextLength) || contextLength <= 0) throw new Error(`Model "${item["id"]}" must include a positive context_length.`);
|
|
62397
62397
|
const displayName = item["display_name"];
|
|
@@ -62440,7 +62440,7 @@ async function fetchOpenPlatformModels(platform, apiKey, fetchImpl = fetch, sign
|
|
|
62440
62440
|
});
|
|
62441
62441
|
if (!res.ok) throw new OpenPlatformApiError(await readApiErrorMessage(res, `Failed to list models (HTTP ${res.status}).`), res.status);
|
|
62442
62442
|
const payload = await res.json();
|
|
62443
|
-
if (!isRecord$
|
|
62443
|
+
if (!isRecord$26(payload) || !Array.isArray(payload["data"])) throw new Error(`Unexpected models response for ${platform.baseUrl}.`);
|
|
62444
62444
|
return payload["data"].map((item) => toModelInfo(item)).filter((item) => item !== void 0);
|
|
62445
62445
|
}
|
|
62446
62446
|
function filterModelsByPrefix(models, platform) {
|
|
@@ -62460,10 +62460,10 @@ function applyOpenPlatformConfig(config, options) {
|
|
|
62460
62460
|
};
|
|
62461
62461
|
const existingModels = config.models ?? {};
|
|
62462
62462
|
const upstreamKeys = new Set(options.models.map((m) => `${providerKey}/${m.id}`));
|
|
62463
|
-
for (const [key, model] of Object.entries(existingModels)) if (isRecord$
|
|
62463
|
+
for (const [key, model] of Object.entries(existingModels)) if (isRecord$26(model) && model["provider"] === providerKey && !upstreamKeys.has(key)) delete existingModels[key];
|
|
62464
62464
|
for (const model of options.models) {
|
|
62465
62465
|
const aliasKey = `${providerKey}/${model.id}`;
|
|
62466
|
-
existingModels[aliasKey] = mergeRefreshedModelAlias(isRecord$
|
|
62466
|
+
existingModels[aliasKey] = mergeRefreshedModelAlias(isRecord$26(existingModels[aliasKey]) ? existingModels[aliasKey] : {}, {
|
|
62467
62467
|
provider: providerKey,
|
|
62468
62468
|
model: model.id,
|
|
62469
62469
|
maxContextSize: model.contextLength,
|
|
@@ -62594,17 +62594,17 @@ var init_provider_credential = __esmMin((() => {}));
|
|
|
62594
62594
|
* is owned by a given registry URL.
|
|
62595
62595
|
*/
|
|
62596
62596
|
function customRegistrySourceUrl(provider) {
|
|
62597
|
-
if (!isRecord$
|
|
62597
|
+
if (!isRecord$26(provider)) return void 0;
|
|
62598
62598
|
const candidate = provider["source"];
|
|
62599
|
-
if (!isRecord$
|
|
62599
|
+
if (!isRecord$26(candidate) || candidate["kind"] !== "apiJson") return void 0;
|
|
62600
62600
|
const url = candidate["url"];
|
|
62601
62601
|
return typeof url === "string" && url.length > 0 ? url : void 0;
|
|
62602
62602
|
}
|
|
62603
62603
|
function readCustomRegistrySource$1(provider) {
|
|
62604
|
-
if (!isRecord$
|
|
62604
|
+
if (!isRecord$26(provider)) return void 0;
|
|
62605
62605
|
const candidate = provider["source"];
|
|
62606
62606
|
const url = customRegistrySourceUrl(provider);
|
|
62607
|
-
const apiKey = isRecord$
|
|
62607
|
+
const apiKey = isRecord$26(candidate) ? candidate["apiKey"] : void 0;
|
|
62608
62608
|
if (url === void 0 || typeof apiKey !== "string") return void 0;
|
|
62609
62609
|
return {
|
|
62610
62610
|
kind: "apiJson",
|
|
@@ -62650,14 +62650,14 @@ function isValidRetirementAt(value) {
|
|
|
62650
62650
|
return value === void 0 || value === null || typeof value === "string" && RFC3339_PATTERN.test(value) && Number.isFinite(Date.parse(value));
|
|
62651
62651
|
}
|
|
62652
62652
|
function toModelEntry(value) {
|
|
62653
|
-
if (!isRecord$
|
|
62653
|
+
if (!isRecord$26(value)) return void 0;
|
|
62654
62654
|
const id = value["id"];
|
|
62655
62655
|
if (typeof id !== "string" || id.length === 0) return void 0;
|
|
62656
62656
|
const entry = { id };
|
|
62657
62657
|
const name = value["name"];
|
|
62658
62658
|
if (typeof name === "string" && name.length > 0) entry.name = name;
|
|
62659
62659
|
const limit = value["limit"];
|
|
62660
|
-
if (isRecord$
|
|
62660
|
+
if (isRecord$26(limit)) {
|
|
62661
62661
|
const context = limit["context"];
|
|
62662
62662
|
const output = limit["output"];
|
|
62663
62663
|
const parsedLimit = {};
|
|
@@ -62672,7 +62672,7 @@ function toModelEntry(value) {
|
|
|
62672
62672
|
const defaultEffort = value["default_effort"];
|
|
62673
62673
|
if (typeof defaultEffort === "string" && defaultEffort.length > 0) entry.default_effort = defaultEffort;
|
|
62674
62674
|
const modalities = value["modalities"];
|
|
62675
|
-
if (isRecord$
|
|
62675
|
+
if (isRecord$26(modalities)) {
|
|
62676
62676
|
const input = toStringArrayOrUndefined(modalities["input"]);
|
|
62677
62677
|
const output = toStringArrayOrUndefined(modalities["output"]);
|
|
62678
62678
|
if (input !== void 0 || output !== void 0) entry.modalities = {
|
|
@@ -62682,7 +62682,7 @@ function toModelEntry(value) {
|
|
|
62682
62682
|
}
|
|
62683
62683
|
const rawUpgrade = value["upgrade"];
|
|
62684
62684
|
if (rawUpgrade !== void 0 && rawUpgrade !== null) {
|
|
62685
|
-
if (!isRecord$
|
|
62685
|
+
if (!isRecord$26(rawUpgrade)) throw new Error(`Invalid upgrade for model "${id}": expected an object.`);
|
|
62686
62686
|
const targetModel = nonEmptyString$5(rawUpgrade["model"]);
|
|
62687
62687
|
if (targetModel === void 0) throw new Error(`Invalid upgrade for model "${id}": expected a non-empty target model.`);
|
|
62688
62688
|
const migrationMarkdown = rawUpgrade["migration_markdown"];
|
|
@@ -62698,7 +62698,7 @@ function toModelEntry(value) {
|
|
|
62698
62698
|
return entry;
|
|
62699
62699
|
}
|
|
62700
62700
|
function toProviderEntry(value) {
|
|
62701
|
-
if (!isRecord$
|
|
62701
|
+
if (!isRecord$26(value)) return void 0;
|
|
62702
62702
|
const id = value["id"];
|
|
62703
62703
|
const name = value["name"];
|
|
62704
62704
|
const api = value["api"];
|
|
@@ -62708,7 +62708,7 @@ function toProviderEntry(value) {
|
|
|
62708
62708
|
if (typeof name !== "string" || name.length === 0) return void 0;
|
|
62709
62709
|
if (typeof api !== "string" || api.length === 0) return void 0;
|
|
62710
62710
|
if (!isAllowedProviderType(type)) return void 0;
|
|
62711
|
-
if (!isRecord$
|
|
62711
|
+
if (!isRecord$26(models)) return void 0;
|
|
62712
62712
|
const parsedModels = {};
|
|
62713
62713
|
for (const [key, raw] of Object.entries(models)) {
|
|
62714
62714
|
const modelEntry = toModelEntry(raw);
|
|
@@ -62746,7 +62746,7 @@ async function fetchCustomRegistry(source, options = {}) {
|
|
|
62746
62746
|
throw new CustomRegistryApiError(message, response.status);
|
|
62747
62747
|
}
|
|
62748
62748
|
const payload = await response.json();
|
|
62749
|
-
if (!isRecord$
|
|
62749
|
+
if (!isRecord$26(payload)) throw new Error(`Unexpected custom registry response at ${source.url}: expected a JSON object keyed by provider id.`);
|
|
62750
62750
|
const out = {};
|
|
62751
62751
|
for (const [key, raw] of Object.entries(payload)) {
|
|
62752
62752
|
const entry = toProviderEntry(raw);
|
|
@@ -62807,8 +62807,8 @@ function resolveCapabilities(model) {
|
|
|
62807
62807
|
*/
|
|
62808
62808
|
function retainedApiKeyEnv(existing, entry, source) {
|
|
62809
62809
|
assertCustomRegistryProviderId(entry.id);
|
|
62810
|
-
if (isRecord$
|
|
62811
|
-
if (!isRecord$
|
|
62810
|
+
if (isRecord$26(existing) && existing["oauth"] !== void 0) throw new Error(oauthManagedProviderMessage(entry.id));
|
|
62811
|
+
if (!isRecord$26(existing) || readCustomRegistrySource$1(existing)?.url !== source.url) return;
|
|
62812
62812
|
const apiKeyEnv = nonEmptyString$5(existing["apiKeyEnv"]);
|
|
62813
62813
|
if (apiKeyEnv !== void 0 && normalizedEndpoint(existing["baseUrl"]) !== normalizedEndpoint(entry.api)) throw new Error(`Custom registry provider "${entry.id}" changed endpoint while api_key_env is configured. Remove api_key_env, re-import the registry, verify the new endpoint, then restore api_key_env.`);
|
|
62814
62814
|
return apiKeyEnv;
|
|
@@ -62829,14 +62829,14 @@ function applyCustomRegistryProvider(config, entry, source, priorProviders) {
|
|
|
62829
62829
|
};
|
|
62830
62830
|
const existingModels = config.models ?? {};
|
|
62831
62831
|
const upstreamKeys = new Set(Object.keys(entry.models).map((modelKey) => `${providerKey}/${modelKey}`));
|
|
62832
|
-
for (const [key, alias] of Object.entries(existingModels)) if (isRecord$
|
|
62832
|
+
for (const [key, alias] of Object.entries(existingModels)) if (isRecord$26(alias) && alias["provider"] === providerKey && !upstreamKeys.has(key)) delete existingModels[key];
|
|
62833
62833
|
const modelEntries = Object.entries(entry.models);
|
|
62834
62834
|
for (const [modelKey, model] of modelEntries) {
|
|
62835
62835
|
const aliasKey = `${providerKey}/${modelKey}`;
|
|
62836
62836
|
const maxContextSize = resolveMaxContextSize(model);
|
|
62837
62837
|
const capabilities = resolveCapabilities(model);
|
|
62838
62838
|
const displayName = typeof model.name === "string" && model.name.length > 0 ? model.name : model.id;
|
|
62839
|
-
const existing = isRecord$
|
|
62839
|
+
const existing = isRecord$26(existingModels[aliasKey]) ? existingModels[aliasKey] : {};
|
|
62840
62840
|
const upgrade = model.upgrade;
|
|
62841
62841
|
const target = upgrade === void 0 ? void 0 : modelEntries.find(([, candidate]) => candidate.id === upgrade.model);
|
|
62842
62842
|
const targetAlias = target === void 0 || target[1].id === model.id ? void 0 : `${providerKey}/${target[0]}`;
|
|
@@ -62867,7 +62867,7 @@ function removeCustomRegistryProvider(config, providerId) {
|
|
|
62867
62867
|
let removedDefault = false;
|
|
62868
62868
|
const existingModels = config.models ?? {};
|
|
62869
62869
|
for (const [key, alias] of Object.entries(existingModels)) {
|
|
62870
|
-
if (!isRecord$
|
|
62870
|
+
if (!isRecord$26(alias) || alias["provider"] !== providerId) continue;
|
|
62871
62871
|
delete existingModels[key];
|
|
62872
62872
|
if (config.defaultModel === key) removedDefault = true;
|
|
62873
62873
|
}
|
|
@@ -62882,7 +62882,7 @@ function removeCustomRegistryProvider(config, providerId) {
|
|
|
62882
62882
|
*/
|
|
62883
62883
|
function declaredUpgradeTarget(config, alias) {
|
|
62884
62884
|
const model = alias === void 0 ? void 0 : config.models?.[alias];
|
|
62885
|
-
return isRecord$
|
|
62885
|
+
return isRecord$26(model) && isRecord$26(model["upgrade"]) ? nonEmptyString$5(model["upgrade"]["model"]) : void 0;
|
|
62886
62886
|
}
|
|
62887
62887
|
/**
|
|
62888
62888
|
* Surfaces the credential env var each entry declares via its `env` field, as
|
|
@@ -62922,10 +62922,10 @@ function removeCustomRegistryEntries(config, entries, source) {
|
|
|
62922
62922
|
previousDefaultProvider: config["defaultProvider"]
|
|
62923
62923
|
};
|
|
62924
62924
|
for (const [providerId, provider] of Object.entries(config.providers)) {
|
|
62925
|
-
if (!isRecord$
|
|
62925
|
+
if (!isRecord$26(provider)) continue;
|
|
62926
62926
|
if (provider["oauth"] !== void 0 || isReservedProviderId(providerId)) continue;
|
|
62927
62927
|
const existingSource = provider["source"];
|
|
62928
|
-
const sameRegistry = isRecord$
|
|
62928
|
+
const sameRegistry = isRecord$26(existingSource) && existingSource["kind"] === "apiJson" && existingSource["url"] === source.url;
|
|
62929
62929
|
if (surviving.has(providerId) || sameRegistry) removeCustomRegistryProvider(config, providerId);
|
|
62930
62930
|
}
|
|
62931
62931
|
return removal;
|
|
@@ -62933,12 +62933,12 @@ function removeCustomRegistryEntries(config, entries, source) {
|
|
|
62933
62933
|
function customRegistryReplacementKeys(config, entries, source) {
|
|
62934
62934
|
const providerIds = new Set(Object.values(entries).map((entry) => entry.id));
|
|
62935
62935
|
for (const [providerId, provider] of Object.entries(config.providers)) {
|
|
62936
|
-
if (!isRecord$
|
|
62936
|
+
if (!isRecord$26(provider)) continue;
|
|
62937
62937
|
if (provider["oauth"] !== void 0 || isReservedProviderId(providerId)) continue;
|
|
62938
62938
|
if (customRegistrySourceUrl(provider) === source.url) providerIds.add(providerId);
|
|
62939
62939
|
}
|
|
62940
62940
|
const modelIds = /* @__PURE__ */ new Set();
|
|
62941
|
-
for (const [modelId, model] of Object.entries(config.models ?? {})) if (isRecord$
|
|
62941
|
+
for (const [modelId, model] of Object.entries(config.models ?? {})) if (isRecord$26(model) && providerIds.has(String(model["provider"]))) modelIds.add(modelId);
|
|
62942
62942
|
for (const entry of Object.values(entries)) for (const modelId of Object.keys(entry.models)) modelIds.add(`${entry.id}/${modelId}`);
|
|
62943
62943
|
return {
|
|
62944
62944
|
providers: [...providerIds],
|
|
@@ -63266,7 +63266,7 @@ function resolveProviderApiKey(provider, providerName) {
|
|
|
63266
63266
|
if (value === void 0) throw new Error(apiKeyEnvMissingMessage(providerName, declared.apiKeyEnv));
|
|
63267
63267
|
return value;
|
|
63268
63268
|
}
|
|
63269
|
-
if (isRecord$
|
|
63269
|
+
if (isRecord$26(provider.env)) {
|
|
63270
63270
|
const fromEnv = nonEmptyString$5(provider.env["NEXGEN_API_KEY"]);
|
|
63271
63271
|
if (fromEnv !== void 0) {
|
|
63272
63272
|
if (provider.oauth !== void 0) throw new Error(credentialConflictMessage("Provider", providerName, "apiKey", "oauth"));
|
|
@@ -111182,7 +111182,7 @@ function dump$1(input, options) {
|
|
|
111182
111182
|
if (writeNode(state, 0, value, true, true)) return state.dump + "\n";
|
|
111183
111183
|
return "";
|
|
111184
111184
|
}
|
|
111185
|
-
var common, exception, snippet, TYPE_CONSTRUCTOR_OPTIONS, YAML_NODE_KINDS, type$2, schema, str$
|
|
111185
|
+
var common, exception, snippet, TYPE_CONSTRUCTOR_OPTIONS, YAML_NODE_KINDS, type$2, schema, str$2, seq, map, failsafe, _null, bool, int, YAML_FLOAT_PATTERN, SCIENTIFIC_WITHOUT_DOT, float, json, core, YAML_DATE_REGEXP, YAML_TIMESTAMP_REGEXP, timestamp$1, merge, BASE64_MAP, binary, _hasOwnProperty$3, _toString$2, omap, _toString$1, pairs, _hasOwnProperty$2, set$1, _default, _hasOwnProperty$1, CONTEXT_FLOW_IN, CONTEXT_FLOW_OUT, CONTEXT_BLOCK_IN, CONTEXT_BLOCK_OUT, CHOMPING_CLIP, CHOMPING_STRIP, CHOMPING_KEEP, PATTERN_NON_PRINTABLE, PATTERN_NON_ASCII_LINE_BREAKS, PATTERN_FLOW_INDICATORS, PATTERN_TAG_HANDLE, PATTERN_TAG_URI, simpleEscapeCheck, simpleEscapeMap, i$1, directiveHandlers, loader, _toString, _hasOwnProperty, CHAR_BOM, CHAR_TAB, CHAR_LINE_FEED, CHAR_CARRIAGE_RETURN, CHAR_SPACE, CHAR_EXCLAMATION, CHAR_DOUBLE_QUOTE, CHAR_SHARP, CHAR_PERCENT, CHAR_AMPERSAND, CHAR_SINGLE_QUOTE, CHAR_ASTERISK, CHAR_COMMA, CHAR_MINUS, CHAR_COLON, CHAR_EQUALS, CHAR_GREATER_THAN, CHAR_QUESTION, CHAR_COMMERCIAL_AT, CHAR_LEFT_SQUARE_BRACKET, CHAR_RIGHT_SQUARE_BRACKET, CHAR_GRAVE_ACCENT, CHAR_LEFT_CURLY_BRACKET, CHAR_VERTICAL_LINE, CHAR_RIGHT_CURLY_BRACKET, ESCAPE_SEQUENCES, DEPRECATED_BOOLEANS_SYNTAX, DEPRECATED_BASE60_SYNTAX, QUOTING_TYPE_SINGLE, QUOTING_TYPE_DOUBLE, STYLE_PLAIN, STYLE_SINGLE, STYLE_LITERAL, STYLE_FOLDED, STYLE_DOUBLE, dumper, load;
|
|
111186
111186
|
var init_js_yaml = __esmMin((() => {
|
|
111187
111187
|
common = {
|
|
111188
111188
|
isNothing,
|
|
@@ -111243,7 +111243,7 @@ var init_js_yaml = __esmMin((() => {
|
|
|
111243
111243
|
return result;
|
|
111244
111244
|
};
|
|
111245
111245
|
schema = Schema$1;
|
|
111246
|
-
str$
|
|
111246
|
+
str$2 = new type$2("tag:yaml.org,2002:str", {
|
|
111247
111247
|
kind: "scalar",
|
|
111248
111248
|
construct: function(data) {
|
|
111249
111249
|
return data !== null ? data : "";
|
|
@@ -111262,7 +111262,7 @@ var init_js_yaml = __esmMin((() => {
|
|
|
111262
111262
|
}
|
|
111263
111263
|
});
|
|
111264
111264
|
failsafe = new schema({ explicit: [
|
|
111265
|
-
str$
|
|
111265
|
+
str$2,
|
|
111266
111266
|
seq,
|
|
111267
111267
|
map
|
|
111268
111268
|
] });
|
|
@@ -111606,7 +111606,7 @@ function parseSkillText(options) {
|
|
|
111606
111606
|
throw error;
|
|
111607
111607
|
}
|
|
111608
111608
|
const frontmatter = parsed.data ?? {};
|
|
111609
|
-
if (!isRecord$
|
|
111609
|
+
if (!isRecord$25(frontmatter)) throw new SkillParseError(`Frontmatter in ${options.skillMdPath} must be a mapping at the top level`);
|
|
111610
111610
|
const metadata = normalizeMetadata(frontmatter);
|
|
111611
111611
|
if (!isSupportedSkillType(metadata.type)) throw new UnsupportedSkillTypeError(metadata.type ?? String(frontmatter["type"]));
|
|
111612
111612
|
const name = nonEmptyString$4(metadata.name);
|
|
@@ -111654,7 +111654,7 @@ function descriptionFromBody$1(body) {
|
|
|
111654
111654
|
function nonEmptyString$4(value) {
|
|
111655
111655
|
return typeof value === "string" && value.trim() !== "" ? value.trim() : void 0;
|
|
111656
111656
|
}
|
|
111657
|
-
function isRecord$
|
|
111657
|
+
function isRecord$25(value) {
|
|
111658
111658
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
111659
111659
|
}
|
|
111660
111660
|
var SkillParseError, UnsupportedSkillTypeError, FENCE, METADATA_ALIASES;
|
|
@@ -112197,10 +112197,10 @@ async function readMcpJson(fs, filePath, options = {}) {
|
|
|
112197
112197
|
}
|
|
112198
112198
|
}
|
|
112199
112199
|
function parseMcpJsonServers(data) {
|
|
112200
|
-
if (!isRecord$
|
|
112200
|
+
if (!isRecord$24(data)) throw new Error("expected a JSON object");
|
|
112201
112201
|
if (!("mcpServers" in data)) return {};
|
|
112202
112202
|
const raw = data["mcpServers"];
|
|
112203
|
-
if (!isRecord$
|
|
112203
|
+
if (!isRecord$24(raw)) throw new Error("\"mcpServers\" must be an object");
|
|
112204
112204
|
return Object.fromEntries(Object.entries(raw).map(([name, value]) => [name, McpServerConfigSchema.parse(value)]));
|
|
112205
112205
|
}
|
|
112206
112206
|
function normalizeMcpServers(servers, options) {
|
|
@@ -112221,7 +112221,7 @@ function mapValuesToPath(servers, path) {
|
|
|
112221
112221
|
for (const name of Object.keys(servers)) origins[name] = path;
|
|
112222
112222
|
return origins;
|
|
112223
112223
|
}
|
|
112224
|
-
function isRecord$
|
|
112224
|
+
function isRecord$24(value) {
|
|
112225
112225
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
112226
112226
|
}
|
|
112227
112227
|
function isFileNotFound(error) {
|
|
@@ -122943,7 +122943,7 @@ function configError(message, cause) {
|
|
|
122943
122943
|
function describeError$1(error) {
|
|
122944
122944
|
return error instanceof Error ? error.message : String(error);
|
|
122945
122945
|
}
|
|
122946
|
-
function isRecord$
|
|
122946
|
+
function isRecord$23(value) {
|
|
122947
122947
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
122948
122948
|
}
|
|
122949
122949
|
var IMcpConfigStore, CONFIG_SCOPE$1, MCP_CONFIG_KEY, textEncoder$6, textDecoder$6, McpConfigStore, NO_ABORT$5;
|
|
@@ -123054,9 +123054,9 @@ var init_configStore = __esmMin((() => {
|
|
|
123054
123054
|
} catch (error) {
|
|
123055
123055
|
throw configError(`Invalid JSON in ${this.path}: ${describeError$1(error)}`, error);
|
|
123056
123056
|
}
|
|
123057
|
-
if (!isRecord$
|
|
123057
|
+
if (!isRecord$23(parsed)) throw configError(`Invalid MCP config in ${this.path}: expected a JSON object`);
|
|
123058
123058
|
const rawServersValue = parsed["mcpServers"];
|
|
123059
|
-
if (rawServersValue !== void 0 && !isRecord$
|
|
123059
|
+
if (rawServersValue !== void 0 && !isRecord$23(rawServersValue)) throw configError(`Invalid MCP config in ${this.path}: "mcpServers" must be an object`);
|
|
123060
123060
|
const rawServers = rawServersValue ?? {};
|
|
123061
123061
|
const servers = Object.entries(rawServers).map(([name, value]) => parseServer(name, value));
|
|
123062
123062
|
return {
|
|
@@ -123967,7 +123967,7 @@ function parseAgentFileText(options) {
|
|
|
123967
123967
|
}
|
|
123968
123968
|
const frontmatter = parsed.data;
|
|
123969
123969
|
if (frontmatter === null) throw new AgentFileParseError(`Missing frontmatter in ${options.path}`);
|
|
123970
|
-
if (!isRecord$
|
|
123970
|
+
if (!isRecord$22(frontmatter)) throw new AgentFileParseError(`Frontmatter in ${options.path} must be a mapping at the top level`);
|
|
123971
123971
|
const nameField = frontmatter["name"];
|
|
123972
123972
|
if (nameField !== void 0 && nameField !== null && typeof nameField !== "string") throw new AgentFileParseError(`Frontmatter field "name" in ${options.path} must be a non-empty string`);
|
|
123973
123973
|
const name = nonEmptyString$3(nameField) ?? deriveNameFromPath(options.path);
|
|
@@ -124023,7 +124023,7 @@ function deriveNameFromPath(filePath) {
|
|
|
124023
124023
|
function nonEmptyString$3(value) {
|
|
124024
124024
|
return typeof value === "string" && value.trim() !== "" ? value.trim() : void 0;
|
|
124025
124025
|
}
|
|
124026
|
-
function isRecord$
|
|
124026
|
+
function isRecord$22(value) {
|
|
124027
124027
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
124028
124028
|
}
|
|
124029
124029
|
var AgentFileParseError, AGENT_NAME_PATTERN;
|
|
@@ -179733,12 +179733,12 @@ function legacyStatusToCurrent$1(task) {
|
|
|
179733
179733
|
return task.status;
|
|
179734
179734
|
}
|
|
179735
179735
|
function isReadablePersistedTask$1(obj) {
|
|
179736
|
-
return isRecord$
|
|
179736
|
+
return isRecord$21(obj) && (typeof obj["taskId"] === "string" || typeof obj["task_id"] === "string");
|
|
179737
179737
|
}
|
|
179738
179738
|
function isLegacyPersistedTask$1(task) {
|
|
179739
179739
|
return "task_id" in task;
|
|
179740
179740
|
}
|
|
179741
|
-
function isRecord$
|
|
179741
|
+
function isRecord$21(value) {
|
|
179742
179742
|
return typeof value === "object" && value !== null;
|
|
179743
179743
|
}
|
|
179744
179744
|
function optionalNonEmptyString$1(value) {
|
|
@@ -192132,7 +192132,7 @@ function normalizeNexgenToolSchema(schema) {
|
|
|
192132
192132
|
}
|
|
192133
192133
|
function ensureNexgenPropertyTypes(schema) {
|
|
192134
192134
|
const normalized = cloneJsonValue(schema);
|
|
192135
|
-
if (!isRecord$
|
|
192135
|
+
if (!isRecord$20(normalized)) throw new SyntaxRequestFormatError("JSON Schema root must normalize to an object.");
|
|
192136
192136
|
recurseSchema(normalized);
|
|
192137
192137
|
return normalized;
|
|
192138
192138
|
}
|
|
@@ -192193,7 +192193,7 @@ function resolveLocalJsonPointer(root, ref) {
|
|
|
192193
192193
|
let current = root;
|
|
192194
192194
|
for (const rawPart of ref.slice(2).split("/")) {
|
|
192195
192195
|
const part = unescapeJsonPointerPart(rawPart);
|
|
192196
|
-
if (isRecord$
|
|
192196
|
+
if (isRecord$20(current)) {
|
|
192197
192197
|
if (!hasOwn$1(current, part)) return { found: false };
|
|
192198
192198
|
current = current[part];
|
|
192199
192199
|
} else if (Array.isArray(current)) {
|
|
@@ -192215,20 +192215,20 @@ function parseJsonPointerArrayIndex(part) {
|
|
|
192215
192215
|
return Number(part);
|
|
192216
192216
|
}
|
|
192217
192217
|
function recurseSchema(node) {
|
|
192218
|
-
if (!isRecord$
|
|
192218
|
+
if (!isRecord$20(node)) return;
|
|
192219
192219
|
visitChildSchemas(node, normalizeProperty);
|
|
192220
192220
|
}
|
|
192221
192221
|
function visitChildSchemas(node, visit) {
|
|
192222
192222
|
for (const { key, kind } of CHILD_SCHEMA_SLOTS) {
|
|
192223
192223
|
const value = node[key];
|
|
192224
192224
|
if (kind === "single") {
|
|
192225
|
-
if (isRecord$
|
|
192225
|
+
if (isRecord$20(value)) visit(value);
|
|
192226
192226
|
} else if (kind === "array") {
|
|
192227
192227
|
if (Array.isArray(value)) for (const item of value) visit(item);
|
|
192228
192228
|
} else if (kind === "map") {
|
|
192229
|
-
if (isRecord$
|
|
192229
|
+
if (isRecord$20(value)) for (const item of Object.values(value)) visit(item);
|
|
192230
192230
|
} else if (kind === "schema-or-array") {
|
|
192231
|
-
if (isRecord$
|
|
192231
|
+
if (isRecord$20(value)) visit(value);
|
|
192232
192232
|
else if (Array.isArray(value)) for (const item of value) visit(item);
|
|
192233
192233
|
}
|
|
192234
192234
|
}
|
|
@@ -192240,7 +192240,7 @@ function childSchemaKeysForParentType(parentType) {
|
|
|
192240
192240
|
});
|
|
192241
192241
|
}
|
|
192242
192242
|
function normalizeProperty(node) {
|
|
192243
|
-
if (!isRecord$
|
|
192243
|
+
if (!isRecord$20(node)) return;
|
|
192244
192244
|
if (!hasOwn$1(node, "type") && !hasAnyKey(node, TYPE_COMPLETION_SKIP_KEYS)) {
|
|
192245
192245
|
const enumValues = node["enum"];
|
|
192246
192246
|
if (Array.isArray(enumValues) && enumValues.length > 0) node["type"] = inferTypeFromValues(enumValues);
|
|
@@ -192324,14 +192324,14 @@ function hasAnyKey(obj, keys) {
|
|
|
192324
192324
|
}
|
|
192325
192325
|
function cloneJsonValue(value) {
|
|
192326
192326
|
if (Array.isArray(value)) return value.map((item) => cloneJsonValue(item));
|
|
192327
|
-
if (isRecord$
|
|
192327
|
+
if (isRecord$20(value)) {
|
|
192328
192328
|
const cloned = {};
|
|
192329
192329
|
for (const [key, child] of Object.entries(value)) cloned[key] = cloneJsonValue(child);
|
|
192330
192330
|
return cloned;
|
|
192331
192331
|
}
|
|
192332
192332
|
return value;
|
|
192333
192333
|
}
|
|
192334
|
-
function isRecord$
|
|
192334
|
+
function isRecord$20(value) {
|
|
192335
192335
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
192336
192336
|
}
|
|
192337
192337
|
function hasOwn$1(obj, key) {
|
|
@@ -201623,15 +201623,15 @@ async function seedDefaultModelWhenUnset$1(config, alias) {
|
|
|
201623
201623
|
}
|
|
201624
201624
|
function registryKeyFromExisting(providers, url) {
|
|
201625
201625
|
for (const provider of Object.values(providers)) {
|
|
201626
|
-
if (!isRecord$
|
|
201626
|
+
if (!isRecord$19(provider)) continue;
|
|
201627
201627
|
const source = provider["source"];
|
|
201628
|
-
if (isRecord$
|
|
201628
|
+
if (isRecord$19(source) && source["kind"] === "apiJson" && source["url"] === url) {
|
|
201629
201629
|
const key = source["apiKey"];
|
|
201630
201630
|
if (typeof key === "string" && key.length > 0) return key;
|
|
201631
201631
|
}
|
|
201632
201632
|
}
|
|
201633
201633
|
}
|
|
201634
|
-
function isRecord$
|
|
201634
|
+
function isRecord$19(value) {
|
|
201635
201635
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
201636
201636
|
}
|
|
201637
201637
|
function truncateUpstreamMessage(err, limit = 300) {
|
|
@@ -201988,7 +201988,7 @@ var init_types$20 = __esmMin((() => {
|
|
|
201988
201988
|
function parseCommandText(input) {
|
|
201989
201989
|
const { text, commandPath, pluginId } = input;
|
|
201990
201990
|
const parsed = parseFrontmatter(text);
|
|
201991
|
-
const frontmatter = isRecord$
|
|
201991
|
+
const frontmatter = isRecord$18(parsed.data) ? parsed.data : {};
|
|
201992
201992
|
const baseName = input.fallbackName ?? nodePath.basename(commandPath).replace(/\.md$/i, "");
|
|
201993
201993
|
const name = nonEmptyString$2(frontmatter["name"]) ?? baseName;
|
|
201994
201994
|
const body = parsed.body.trim();
|
|
@@ -202025,7 +202025,7 @@ function descriptionFromBody(body) {
|
|
|
202025
202025
|
if (firstLine === void 0) return "No description provided.";
|
|
202026
202026
|
return firstLine.length > 240 ? `${firstLine.slice(0, 239)}…` : firstLine;
|
|
202027
202027
|
}
|
|
202028
|
-
function isRecord$
|
|
202028
|
+
function isRecord$18(value) {
|
|
202029
202029
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
202030
202030
|
}
|
|
202031
202031
|
var init_commands$1 = __esmMin((() => {
|
|
@@ -204879,7 +204879,7 @@ function parsePluginMarketplace(raw, location) {
|
|
|
204879
204879
|
} catch (error) {
|
|
204880
204880
|
throw new Error(`Plugin marketplace is not valid JSON: ${formatParseError(error)}`, { cause: error });
|
|
204881
204881
|
}
|
|
204882
|
-
if (!isRecord$
|
|
204882
|
+
if (!isRecord$17(parsed)) throw new TypeError("Plugin marketplace must be an object.");
|
|
204883
204883
|
const rawPlugins = parsed["plugins"];
|
|
204884
204884
|
if (!Array.isArray(rawPlugins)) throw new TypeError("Plugin marketplace must contain a \"plugins\" array.");
|
|
204885
204885
|
return {
|
|
@@ -204925,7 +204925,7 @@ async function readMarketplaceText(location, fetchImpl) {
|
|
|
204925
204925
|
return response.text();
|
|
204926
204926
|
}
|
|
204927
204927
|
function parseMarketplaceEntry(value, index, location) {
|
|
204928
|
-
if (!isRecord$
|
|
204928
|
+
if (!isRecord$17(value)) throw new TypeError(`Plugin marketplace entry ${index + 1} must be an object.`);
|
|
204929
204929
|
const id = requiredString(value, "id", index);
|
|
204930
204930
|
validateMarketplaceEntryType(value, id);
|
|
204931
204931
|
const source = stringField$4(value, "source") ?? stringField$4(value, "url") ?? stringField$4(value, "downloadUrl");
|
|
@@ -205053,7 +205053,7 @@ function stringArrayField(value, field) {
|
|
|
205053
205053
|
const out = raw.filter((item) => typeof item === "string").map((item) => item.trim()).filter((item) => item.length > 0);
|
|
205054
205054
|
return out.length > 0 ? out : void 0;
|
|
205055
205055
|
}
|
|
205056
|
-
function isRecord$
|
|
205056
|
+
function isRecord$17(value) {
|
|
205057
205057
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
205058
205058
|
}
|
|
205059
205059
|
function formatParseError(error) {
|
|
@@ -210968,7 +210968,7 @@ function killProcess(proc) {
|
|
|
210968
210968
|
proc.kill("SIGKILL");
|
|
210969
210969
|
}, KILL_GRACE_MS$1).unref();
|
|
210970
210970
|
}
|
|
210971
|
-
function isRecord$
|
|
210971
|
+
function isRecord$16(value) {
|
|
210972
210972
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
210973
210973
|
}
|
|
210974
210974
|
function errorMessage$17(error) {
|
|
@@ -210985,7 +210985,7 @@ var init_runHook = __esmMin((() => {
|
|
|
210985
210985
|
if (typeof value === "string") return value;
|
|
210986
210986
|
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") return String(value);
|
|
210987
210987
|
}, string().optional());
|
|
210988
|
-
HookSpecificOutputSchema = preprocess((value) => isRecord$
|
|
210988
|
+
HookSpecificOutputSchema = preprocess((value) => isRecord$16(value) ? value : void 0, looseObject({
|
|
210989
210989
|
message: OptionalStringSchema,
|
|
210990
210990
|
permissionDecision: unknown().optional(),
|
|
210991
210991
|
permissionDecisionReason: unknown().optional()
|
|
@@ -289438,7 +289438,7 @@ var init_paths$1 = __esmMin((() => {
|
|
|
289438
289438
|
siblingMcpJson = (tgt) => join(tgt, "mcp.migrated-from-nexgenk-cli.json");
|
|
289439
289439
|
}));
|
|
289440
289440
|
// ../../packages/migration-legacy/src/source-config.ts
|
|
289441
|
-
function isRecord$
|
|
289441
|
+
function isRecord$15(value) {
|
|
289442
289442
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
289443
289443
|
}
|
|
289444
289444
|
function isEnoent$1(error) {
|
|
@@ -289459,7 +289459,7 @@ async function readSourceConfig(sourceHome) {
|
|
|
289459
289459
|
const parsed = parse$9(tomlText);
|
|
289460
289460
|
return {
|
|
289461
289461
|
kind: "toml",
|
|
289462
|
-
parsed: isRecord$
|
|
289462
|
+
parsed: isRecord$15(parsed) ? parsed : {}
|
|
289463
289463
|
};
|
|
289464
289464
|
} catch {
|
|
289465
289465
|
return {
|
|
@@ -289482,7 +289482,7 @@ async function readSourceConfig(sourceHome) {
|
|
|
289482
289482
|
const parsed = JSON.parse(jsonText);
|
|
289483
289483
|
return {
|
|
289484
289484
|
kind: "json",
|
|
289485
|
-
parsed: isRecord$
|
|
289485
|
+
parsed: isRecord$15(parsed) ? parsed : {}
|
|
289486
289486
|
};
|
|
289487
289487
|
} catch {
|
|
289488
289488
|
return {
|
|
@@ -289898,10 +289898,10 @@ async function detectMigration(opts) {
|
|
|
289898
289898
|
const oauthCredentials = new Set(credentialFiles.map((n) => n.slice(0, -5)).filter((n) => n.length > 0));
|
|
289899
289899
|
if (sourceConfig.kind === "toml" || sourceConfig.kind === "json") {
|
|
289900
289900
|
const providers = sourceConfig.parsed["providers"];
|
|
289901
|
-
if (isRecord$
|
|
289902
|
-
if (!isRecord$
|
|
289901
|
+
if (isRecord$14(providers)) for (const prov of Object.values(providers)) {
|
|
289902
|
+
if (!isRecord$14(prov)) continue;
|
|
289903
289903
|
const oauth = prov["oauth"];
|
|
289904
|
-
if (!isRecord$
|
|
289904
|
+
if (!isRecord$14(oauth)) continue;
|
|
289905
289905
|
const key = oauth["key"];
|
|
289906
289906
|
if (typeof key !== "string" || key === "") continue;
|
|
289907
289907
|
const name = key.split("/").pop();
|
|
@@ -290005,7 +290005,7 @@ async function detectMigration(opts) {
|
|
|
290005
290005
|
function unknownWorkdirReason$1() {
|
|
290006
290006
|
return "No local workdir mapping was found for this legacy session bucket; nexgenk.json may be missing, unreadable, or not list the workdir.";
|
|
290007
290007
|
}
|
|
290008
|
-
function isRecord$
|
|
290008
|
+
function isRecord$14(value) {
|
|
290009
290009
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
290010
290010
|
}
|
|
290011
290011
|
async function dirHasEntries(dir) {
|
|
@@ -290024,11 +290024,11 @@ async function detectMcpOauthServers(src) {
|
|
|
290024
290024
|
}
|
|
290025
290025
|
try {
|
|
290026
290026
|
const parsed = JSON.parse(text);
|
|
290027
|
-
if (!isRecord$
|
|
290027
|
+
if (!isRecord$14(parsed)) return [];
|
|
290028
290028
|
const servers = parsed["mcpServers"];
|
|
290029
|
-
if (!isRecord$
|
|
290029
|
+
if (!isRecord$14(servers)) return [];
|
|
290030
290030
|
const out = [];
|
|
290031
|
-
for (const [name, server] of Object.entries(servers)) if (isRecord$
|
|
290031
|
+
for (const [name, server] of Object.entries(servers)) if (isRecord$14(server) && server["auth"] === "oauth") out.push(name);
|
|
290032
290032
|
return out;
|
|
290033
290033
|
} catch {
|
|
290034
290034
|
return [];
|
|
@@ -290206,7 +290206,7 @@ var init_stub_detect = __esmMin((() => {
|
|
|
290206
290206
|
init_dist$8();
|
|
290207
290207
|
}));
|
|
290208
290208
|
// ../../packages/migration-legacy/src/steps/config.ts
|
|
290209
|
-
function isRecord$
|
|
290209
|
+
function isRecord$13(value) {
|
|
290210
290210
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
290211
290211
|
}
|
|
290212
290212
|
function emptyResult$1() {
|
|
@@ -290242,20 +290242,20 @@ function filterRegisteredExperimentalFlags(value) {
|
|
|
290242
290242
|
* and its (already type-mapped) `type` is one the kosong runtime can construct. */
|
|
290243
290243
|
function providerIsSupported(prov) {
|
|
290244
290244
|
const transformed = providersFromToml({ x: prov });
|
|
290245
|
-
const entry = isRecord$
|
|
290245
|
+
const entry = isRecord$13(transformed) ? transformed["x"] : void 0;
|
|
290246
290246
|
if (entry === void 0) return false;
|
|
290247
290247
|
try {
|
|
290248
290248
|
ProviderConfigSchema.parse(entry);
|
|
290249
290249
|
} catch {
|
|
290250
290250
|
return false;
|
|
290251
290251
|
}
|
|
290252
|
-
const type = isRecord$
|
|
290252
|
+
const type = isRecord$13(entry) ? entry["type"] : void 0;
|
|
290253
290253
|
return typeof type === "string" && SUPPORTED_PROVIDER_TYPES.has(type);
|
|
290254
290254
|
}
|
|
290255
290255
|
/** True when the nexgenk-cli model entry validates against nexgenk's v2 schema. */
|
|
290256
290256
|
function modelIsSupported(mod) {
|
|
290257
290257
|
const transformed = modelsFromToml({ x: mod });
|
|
290258
|
-
const entry = isRecord$
|
|
290258
|
+
const entry = isRecord$13(transformed) ? transformed["x"] : void 0;
|
|
290259
290259
|
if (entry === void 0) return false;
|
|
290260
290260
|
try {
|
|
290261
290261
|
ModelRecordSchema.parse(entry);
|
|
@@ -290267,7 +290267,7 @@ function modelIsSupported(mod) {
|
|
|
290267
290267
|
/** Order-insensitive deep-equality key, so re-ordered tables are not conflicts. */
|
|
290268
290268
|
function stableKey(value) {
|
|
290269
290269
|
if (Array.isArray(value)) return `[${value.map(stableKey).join(",")}]`;
|
|
290270
|
-
if (isRecord$
|
|
290270
|
+
if (isRecord$13(value)) return `{${Object.keys(value).toSorted().map((k) => `${JSON.stringify(k)}:${stableKey(value[k])}`).join(",")}}`;
|
|
290271
290271
|
return JSON.stringify(value) ?? "null";
|
|
290272
290272
|
}
|
|
290273
290273
|
function deepEqual(a, b) {
|
|
@@ -290275,11 +290275,11 @@ function deepEqual(a, b) {
|
|
|
290275
290275
|
}
|
|
290276
290276
|
function mapLegacyProviderTypes(parsed) {
|
|
290277
290277
|
const providers = parsed["providers"];
|
|
290278
|
-
if (!isRecord$
|
|
290278
|
+
if (!isRecord$13(providers)) return parsed;
|
|
290279
290279
|
let changed = false;
|
|
290280
290280
|
const mapped = {};
|
|
290281
290281
|
for (const [name, prov] of Object.entries(providers)) {
|
|
290282
|
-
if (!isRecord$
|
|
290282
|
+
if (!isRecord$13(prov)) {
|
|
290283
290283
|
mapped[name] = prov;
|
|
290284
290284
|
continue;
|
|
290285
290285
|
}
|
|
@@ -290308,8 +290308,8 @@ function mergeConfig(target, migrated) {
|
|
|
290308
290308
|
const merged = { ...target };
|
|
290309
290309
|
const conflicts = [];
|
|
290310
290310
|
for (const [key, value] of Object.entries(migrated)) {
|
|
290311
|
-
if ((key === "providers" || key === "models") && isRecord$
|
|
290312
|
-
const section = isRecord$
|
|
290311
|
+
if ((key === "providers" || key === "models") && isRecord$13(value)) {
|
|
290312
|
+
const section = isRecord$13(merged[key]) ? { ...merged[key] } : {};
|
|
290313
290313
|
for (const [name, entry] of Object.entries(value)) if (section[name] === void 0) section[name] = entry;
|
|
290314
290314
|
else if (!deepEqual(section[name], entry)) conflicts.push(`${key}.${name}`);
|
|
290315
290315
|
merged[key] = section;
|
|
@@ -290344,18 +290344,18 @@ async function migrateConfigStep(input) {
|
|
|
290344
290344
|
if (targetText === void 0 || targetText === "# ~/.nexgenk/config.toml\n# Runtime settings for NexgenK.\n# This file starts empty so built-in defaults can apply.\n# Login will populate managed Nexgen provider and model entries.\n") targetMode = "overwrite";
|
|
290345
290345
|
else try {
|
|
290346
290346
|
const tp = parse$9(targetText);
|
|
290347
|
-
targetParsed = isRecord$
|
|
290347
|
+
targetParsed = isRecord$13(tp) ? tp : {};
|
|
290348
290348
|
targetMode = "merge";
|
|
290349
290349
|
} catch {
|
|
290350
290350
|
targetMode = "sibling";
|
|
290351
290351
|
}
|
|
290352
|
-
const availableProviderNames = new Set(isRecord$
|
|
290353
|
-
const availableModelNames = new Set(isRecord$
|
|
290352
|
+
const availableProviderNames = new Set(isRecord$13(targetParsed["providers"]) ? Object.keys(targetParsed["providers"]) : []);
|
|
290353
|
+
const availableModelNames = new Set(isRecord$13(targetParsed["models"]) ? Object.keys(targetParsed["models"]) : []);
|
|
290354
290354
|
const droppedProviders = [];
|
|
290355
290355
|
const keptProviders = {};
|
|
290356
|
-
if (isRecord$
|
|
290356
|
+
if (isRecord$13(parsed["providers"])) for (const [name, prov] of Object.entries(parsed["providers"])) if (isRecord$13(prov) && providerIsSupported(prov)) keptProviders[name] = prov;
|
|
290357
290357
|
else droppedProviders.push(name);
|
|
290358
|
-
const targetProviders = isRecord$
|
|
290358
|
+
const targetProviders = isRecord$13(targetParsed["providers"]) ? targetParsed["providers"] : {};
|
|
290359
290359
|
const conflictedProviderNames = /* @__PURE__ */ new Set();
|
|
290360
290360
|
for (const [name, prov] of Object.entries(keptProviders)) {
|
|
290361
290361
|
const targetProv = targetProviders[name];
|
|
@@ -290363,8 +290363,8 @@ async function migrateConfigStep(input) {
|
|
|
290363
290363
|
}
|
|
290364
290364
|
const droppedModels = [];
|
|
290365
290365
|
const keptModels = {};
|
|
290366
|
-
if (isRecord$
|
|
290367
|
-
if (!isRecord$
|
|
290366
|
+
if (isRecord$13(parsed["models"])) for (const [name, mod] of Object.entries(parsed["models"])) {
|
|
290367
|
+
if (!isRecord$13(mod) || !modelIsSupported(mod)) {
|
|
290368
290368
|
droppedModels.push(name);
|
|
290369
290369
|
continue;
|
|
290370
290370
|
}
|
|
@@ -290412,17 +290412,17 @@ async function migrateConfigStep(input) {
|
|
|
290412
290412
|
continue;
|
|
290413
290413
|
}
|
|
290414
290414
|
if (k === "default_model" && typeof v === "string" && keptModels[v] === void 0 && !availableModelNames.has(v)) continue;
|
|
290415
|
-
if (k === "loop_control" && isRecord$
|
|
290415
|
+
if (k === "loop_control" && isRecord$13(v)) {
|
|
290416
290416
|
const filteredLoopControl = filterFields(v, LOOP_CONTROL_FIELDS_TO_KEEP);
|
|
290417
290417
|
if (filteredLoopControl !== void 0) migratedTop[k] = filteredLoopControl;
|
|
290418
290418
|
continue;
|
|
290419
290419
|
}
|
|
290420
|
-
if (k === "background" && isRecord$
|
|
290420
|
+
if (k === "background" && isRecord$13(v)) {
|
|
290421
290421
|
const filteredBackground = filterFields(v, BACKGROUND_FIELDS_TO_KEEP);
|
|
290422
290422
|
if (filteredBackground !== void 0) migratedTop[k] = filteredBackground;
|
|
290423
290423
|
continue;
|
|
290424
290424
|
}
|
|
290425
|
-
if (k === "experimental" && isRecord$
|
|
290425
|
+
if (k === "experimental" && isRecord$13(v)) {
|
|
290426
290426
|
const filteredExperimental = filterRegisteredExperimentalFlags(v);
|
|
290427
290427
|
if (filteredExperimental !== void 0) migratedTop[k] = filteredExperimental;
|
|
290428
290428
|
continue;
|
|
@@ -290583,7 +290583,7 @@ function emptyResult(sourceUnreadable) {
|
|
|
290583
290583
|
function isEnoent(error) {
|
|
290584
290584
|
return typeof error === "object" && error !== null && error.code === "ENOENT";
|
|
290585
290585
|
}
|
|
290586
|
-
function isRecord$
|
|
290586
|
+
function isRecord$12(value) {
|
|
290587
290587
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
290588
290588
|
}
|
|
290589
290589
|
async function migrateMcpStep(input) {
|
|
@@ -290600,9 +290600,9 @@ async function migrateMcpStep(input) {
|
|
|
290600
290600
|
return emptyResult(true);
|
|
290601
290601
|
}
|
|
290602
290602
|
const srcServers = {};
|
|
290603
|
-
if (isRecord$
|
|
290603
|
+
if (isRecord$12(sourceJson)) {
|
|
290604
290604
|
const raw = sourceJson["mcpServers"];
|
|
290605
|
-
if (isRecord$
|
|
290605
|
+
if (isRecord$12(raw)) for (const [name, srv] of Object.entries(raw)) srcServers[name] = srv;
|
|
290606
290606
|
}
|
|
290607
290607
|
const mergedTargetServers = {};
|
|
290608
290608
|
let targetText;
|
|
@@ -290614,9 +290614,9 @@ async function migrateMcpStep(input) {
|
|
|
290614
290614
|
let targetUnparseable = false;
|
|
290615
290615
|
if (targetText !== void 0) try {
|
|
290616
290616
|
const parsed = JSON.parse(targetText);
|
|
290617
|
-
if (isRecord$
|
|
290617
|
+
if (isRecord$12(parsed)) {
|
|
290618
290618
|
const raw = parsed["mcpServers"];
|
|
290619
|
-
if (isRecord$
|
|
290619
|
+
if (isRecord$12(raw)) for (const [name, srv] of Object.entries(raw)) mergedTargetServers[name] = srv;
|
|
290620
290620
|
}
|
|
290621
290621
|
} catch {
|
|
290622
290622
|
targetUnparseable = true;
|
|
@@ -314977,11 +314977,366 @@ var init_esm = __esmMin((() => {
|
|
|
314977
314977
|
import_commander = /* @__PURE__ */ __toESM(require_commander(), 1);
|
|
314978
314978
|
({program, createCommand, createArgument, createOption, CommanderError, InvalidArgumentError, InvalidOptionArgumentError, Command, Argument, Option, Help} = import_commander.default);
|
|
314979
314979
|
}));
|
|
314980
|
-
// src/cli/
|
|
314980
|
+
// src/cli/sso/contract.ts
|
|
314981
314981
|
init_session_import();
|
|
314982
314982
|
init_esm();
|
|
314983
|
+
/**
|
|
314984
|
+
* Pure contract for the NexgenRouter SSO provisioning flow, ported from the
|
|
314985
|
+
* gateway client already in production (`nexgen-movil/src/lib/gateway/sso-contract.ts`).
|
|
314986
|
+
*
|
|
314987
|
+
* ```
|
|
314988
|
+
* 1. POST /sso/cli/start (public) -> { login_id, poll_secret, user_code, verification_uri_complete }
|
|
314989
|
+
* 2. open verification_uri_complete -> SSO login
|
|
314990
|
+
* 3. GET /sso/cli/poll/{login_id} [x-litellm-cli-poll-secret] -> pending… -> ready { key (JWT 24h), user_id, teams }
|
|
314991
|
+
* 3b. GET .../poll/{login_id}?team_id=<id> -> ready { key } when `requires_team_selection`
|
|
314992
|
+
* 4. POST /key/generate (Bearer JWT) -> durable key `sk-…`
|
|
314993
|
+
* ```
|
|
314994
|
+
*
|
|
314995
|
+
* Everything here is decided without network so the parsing rules stay testable:
|
|
314996
|
+
* the HTTP client that uses these pieces lives in `./client.ts`.
|
|
314997
|
+
*/
|
|
314998
|
+
/** Team alias in the gateway that carries the models a CLI key should be scoped to. */
|
|
314999
|
+
const NEXGEN_SSO_TEAM_ALIAS = "nexgen-desktop";
|
|
315000
|
+
var SsoError = class extends Error {
|
|
315001
|
+
code;
|
|
315002
|
+
constructor(code, message) {
|
|
315003
|
+
super(message);
|
|
315004
|
+
this.name = "SsoError";
|
|
315005
|
+
this.code = code;
|
|
315006
|
+
}
|
|
315007
|
+
};
|
|
315008
|
+
function isRecord$11(value) {
|
|
315009
|
+
return typeof value === "object" && value !== null;
|
|
315010
|
+
}
|
|
315011
|
+
function str$1(value) {
|
|
315012
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
315013
|
+
}
|
|
315014
|
+
function strArray(value) {
|
|
315015
|
+
if (!Array.isArray(value)) return void 0;
|
|
315016
|
+
return value.filter((item) => typeof item === "string");
|
|
315017
|
+
}
|
|
315018
|
+
function parseTeamDetails(value) {
|
|
315019
|
+
if (!Array.isArray(value)) return [];
|
|
315020
|
+
return value.filter(isRecord$11).map((item) => ({
|
|
315021
|
+
teamId: str$1(item["team_id"]),
|
|
315022
|
+
teamAlias: str$1(item["team_alias"]),
|
|
315023
|
+
teamModels: strArray(item["team_models"])
|
|
315024
|
+
}));
|
|
315025
|
+
}
|
|
315026
|
+
function parseSsoStart(body) {
|
|
315027
|
+
if (!isRecord$11(body)) throw new SsoError("start_malformed", "/sso/cli/start returned a non-JSON body.");
|
|
315028
|
+
const loginId = str$1(body["login_id"]);
|
|
315029
|
+
if (loginId === void 0) throw new SsoError("start_malformed", "/sso/cli/start did not return login_id.");
|
|
315030
|
+
const pollSecret = str$1(body["poll_secret"]);
|
|
315031
|
+
if (pollSecret === void 0) throw new SsoError("no_poll_secret", "/sso/cli/start did not return poll_secret, so the SSO state cannot be polled.");
|
|
315032
|
+
const expiresIn = typeof body["expires_in"] === "number" ? body["expires_in"] : void 0;
|
|
315033
|
+
return {
|
|
315034
|
+
loginId,
|
|
315035
|
+
pollSecret,
|
|
315036
|
+
userCode: typeof body["user_code"] === "string" ? body["user_code"] : "",
|
|
315037
|
+
verificationUriComplete: str$1(body["verification_uri_complete"]),
|
|
315038
|
+
expiresInSeconds: expiresIn
|
|
315039
|
+
};
|
|
315040
|
+
}
|
|
315041
|
+
function parseSsoPoll(body) {
|
|
315042
|
+
if (!isRecord$11(body)) throw new SsoError("malformed", "/sso/cli/poll returned a non-JSON body.");
|
|
315043
|
+
const status = str$1(body["status"]);
|
|
315044
|
+
if (status === void 0) throw new SsoError("malformed", "/sso/cli/poll did not return status.");
|
|
315045
|
+
return {
|
|
315046
|
+
status,
|
|
315047
|
+
key: str$1(body["key"]),
|
|
315048
|
+
userId: str$1(body["user_id"]),
|
|
315049
|
+
teams: strArray(body["teams"]) ?? [],
|
|
315050
|
+
teamDetails: parseTeamDetails(body["team_details"]),
|
|
315051
|
+
teamId: str$1(body["team_id"]),
|
|
315052
|
+
requiresTeamSelection: body["requires_team_selection"] === true
|
|
315053
|
+
};
|
|
315054
|
+
}
|
|
315055
|
+
function parseReady(body) {
|
|
315056
|
+
if (body.key === void 0) throw new SsoError("no_session_token", "the gateway returned no session token (key).");
|
|
315057
|
+
return {
|
|
315058
|
+
jwt: body.key,
|
|
315059
|
+
userId: body.userId,
|
|
315060
|
+
teams: body.teams,
|
|
315061
|
+
teamDetails: body.teamDetails,
|
|
315062
|
+
teamId: body.teamId
|
|
315063
|
+
};
|
|
315064
|
+
}
|
|
315065
|
+
const NO_TEAM_MESSAGE = `this account does not belong to the ${NEXGEN_SSO_TEAM_ALIAS} team — ask an administrator to add it`;
|
|
315066
|
+
const NO_MATCHING_TEAM_MESSAGE = `this account belongs to several teams and none is ${NEXGEN_SSO_TEAM_ALIAS} — ask an administrator to add it`;
|
|
315067
|
+
const NO_TEAM_MODELS_MESSAGE = `the ${NEXGEN_SSO_TEAM_ALIAS} team has no models assigned — ask an administrator to check the team`;
|
|
315068
|
+
function resolveLoginTeam(teams, details) {
|
|
315069
|
+
const byAlias = details.find((detail) => detail.teamAlias === "nexgen-desktop" && detail.teamId !== void 0)?.teamId;
|
|
315070
|
+
if (byAlias !== void 0) return { teamId: byAlias };
|
|
315071
|
+
if (teams.length === 0 && details.length === 0) return { reason: "no_teams" };
|
|
315072
|
+
if (teams.length === 1) return { teamId: teams[0] };
|
|
315073
|
+
if (teams.length === 0 && details.length === 1 && details[0].teamId !== void 0) return { teamId: details[0].teamId };
|
|
315074
|
+
return { reason: "no_matching_team" };
|
|
315075
|
+
}
|
|
315076
|
+
function teamHasModels(details, teamId, teams) {
|
|
315077
|
+
const target = teamId ?? (teams.length === 1 ? teams[0] : void 0);
|
|
315078
|
+
if (target === void 0) return void 0;
|
|
315079
|
+
const detail = details.find((item) => item.teamId === target);
|
|
315080
|
+
if (detail === void 0) return void 0;
|
|
315081
|
+
if (detail.teamModels !== void 0 && detail.teamModels.length === 0) return false;
|
|
315082
|
+
return true;
|
|
315083
|
+
}
|
|
315084
|
+
/**
|
|
315085
|
+
* `ready` without `key` is not the end of the flow: the gateway answers that
|
|
315086
|
+
* way while the account spans several teams and one must be picked, and also
|
|
315087
|
+
* transiently before minting the session token.
|
|
315088
|
+
*/
|
|
315089
|
+
function decideSsoPoll(body) {
|
|
315090
|
+
if (body.status !== "ready") return { action: "wait" };
|
|
315091
|
+
if (body.requiresTeamSelection) {
|
|
315092
|
+
const resolved = resolveLoginTeam(body.teams, body.teamDetails);
|
|
315093
|
+
if ("reason" in resolved) return {
|
|
315094
|
+
action: "fail",
|
|
315095
|
+
code: "no_team",
|
|
315096
|
+
message: resolved.reason === "no_teams" ? NO_TEAM_MESSAGE : NO_MATCHING_TEAM_MESSAGE
|
|
315097
|
+
};
|
|
315098
|
+
return {
|
|
315099
|
+
action: "select_team",
|
|
315100
|
+
teamId: resolved.teamId
|
|
315101
|
+
};
|
|
315102
|
+
}
|
|
315103
|
+
if (body.key === void 0) return { action: "wait" };
|
|
315104
|
+
if (body.teams.length === 0 && body.teamId === void 0) return {
|
|
315105
|
+
action: "fail",
|
|
315106
|
+
code: "no_team",
|
|
315107
|
+
message: NO_TEAM_MESSAGE
|
|
315108
|
+
};
|
|
315109
|
+
if (teamHasModels(body.teamDetails, body.teamId, body.teams) === false) return {
|
|
315110
|
+
action: "fail",
|
|
315111
|
+
code: "no_team",
|
|
315112
|
+
message: NO_TEAM_MODELS_MESSAGE
|
|
315113
|
+
};
|
|
315114
|
+
return {
|
|
315115
|
+
action: "ready",
|
|
315116
|
+
ready: parseReady(body)
|
|
315117
|
+
};
|
|
315118
|
+
}
|
|
315119
|
+
/** LiteLLM requires `key_alias` to be unique across the deployment, so each mint gets its own. */
|
|
315120
|
+
function keyAliasFor(userId, now = Date.now()) {
|
|
315121
|
+
return `nexgenk-${userId}-${now}`;
|
|
315122
|
+
}
|
|
315123
|
+
function isDurableKey(value) {
|
|
315124
|
+
return typeof value === "string" && value.startsWith("sk-");
|
|
315125
|
+
}
|
|
315126
|
+
function parseMintResponse(body, alias) {
|
|
315127
|
+
if (!isRecord$11(body)) throw new SsoError("malformed", "/key/generate returned a non-JSON body.");
|
|
315128
|
+
const key = body["key"];
|
|
315129
|
+
if (!isDurableKey(key)) throw new SsoError("malformed", "the generated key is not a durable `sk-…` key.");
|
|
315130
|
+
return {
|
|
315131
|
+
key,
|
|
315132
|
+
alias
|
|
315133
|
+
};
|
|
315134
|
+
}
|
|
315135
|
+
/** Fallback team pick for the mint when the poll did not scope a team. */
|
|
315136
|
+
function selectTeam(teams, details) {
|
|
315137
|
+
const byAlias = details.find((detail) => detail.teamAlias === NEXGEN_SSO_TEAM_ALIAS)?.teamId;
|
|
315138
|
+
if (byAlias !== void 0) return byAlias;
|
|
315139
|
+
const firstWithId = details.find((detail) => detail.teamId !== void 0)?.teamId;
|
|
315140
|
+
if (firstWithId !== void 0) return firstWithId;
|
|
315141
|
+
return teams.length === 1 ? teams[0] : void 0;
|
|
315142
|
+
}
|
|
315143
|
+
// src/cli/sso/client.ts
|
|
315144
|
+
/**
|
|
315145
|
+
* HTTP client for the NexgenRouter SSO provisioning flow described in
|
|
315146
|
+
* `./contract.ts`. It turns a browser login into the durable `sk-…` key the
|
|
315147
|
+
* CLI stores, mirroring the client already in production for the mobile and
|
|
315148
|
+
* desktop apps.
|
|
315149
|
+
*/
|
|
315150
|
+
const POLL_INTERVAL_MS$1 = 2e3;
|
|
315151
|
+
const DEFAULT_EXPIRES_IN_SECONDS = 600;
|
|
315152
|
+
const MAX_TEAM_SELECTIONS = 2;
|
|
315153
|
+
async function readJson(response) {
|
|
315154
|
+
const text = await response.text();
|
|
315155
|
+
try {
|
|
315156
|
+
return JSON.parse(text);
|
|
315157
|
+
} catch {
|
|
315158
|
+
throw new SsoError("malformed", `the gateway answered ${response.status} with a non-JSON body.`);
|
|
315159
|
+
}
|
|
315160
|
+
}
|
|
315161
|
+
async function startSso(input, signal) {
|
|
315162
|
+
const response = await fetch(`${input.gatewayUrl}/sso/cli/start`, {
|
|
315163
|
+
method: "POST",
|
|
315164
|
+
headers: { "Content-Type": "application/json" },
|
|
315165
|
+
body: "{}",
|
|
315166
|
+
signal
|
|
315167
|
+
});
|
|
315168
|
+
if (!response.ok) throw new SsoError("start_malformed", `/sso/cli/start answered HTTP ${response.status}.`);
|
|
315169
|
+
return parseSsoStart(await readJson(response));
|
|
315170
|
+
}
|
|
315171
|
+
async function pollOnce(input, start, teamId, signal) {
|
|
315172
|
+
const url = new URL(`${input.gatewayUrl}/sso/cli/poll/${encodeURIComponent(start.loginId)}`);
|
|
315173
|
+
if (teamId !== void 0) url.searchParams.set("team_id", teamId);
|
|
315174
|
+
const response = await fetch(url, {
|
|
315175
|
+
method: "GET",
|
|
315176
|
+
headers: { "x-litellm-cli-poll-secret": start.pollSecret },
|
|
315177
|
+
signal
|
|
315178
|
+
});
|
|
315179
|
+
if (!response.ok) throw new SsoError("malformed", `/sso/cli/poll answered HTTP ${response.status}.`);
|
|
315180
|
+
return parseSsoPoll(await readJson(response));
|
|
315181
|
+
}
|
|
315182
|
+
async function mintDurableKey(input, ready, signal) {
|
|
315183
|
+
const userId = ready.userId;
|
|
315184
|
+
if (userId === void 0) throw new SsoError("no_user_id", "the gateway returned no user_id, so the key alias cannot be built.");
|
|
315185
|
+
const teamId = ready.teamId ?? selectTeam(ready.teams, ready.teamDetails);
|
|
315186
|
+
if (teamId === void 0) throw new SsoError("no_team", "this account has no resolvable team in the gateway — ask an administrator to add it to nexgen-desktop.");
|
|
315187
|
+
const alias = keyAliasFor(userId, input.now?.());
|
|
315188
|
+
const response = await fetch(`${input.gatewayUrl}/key/generate`, {
|
|
315189
|
+
method: "POST",
|
|
315190
|
+
headers: {
|
|
315191
|
+
"Content-Type": "application/json",
|
|
315192
|
+
Authorization: `Bearer ${ready.jwt}`
|
|
315193
|
+
},
|
|
315194
|
+
body: JSON.stringify({
|
|
315195
|
+
key_alias: alias,
|
|
315196
|
+
team_id: teamId
|
|
315197
|
+
}),
|
|
315198
|
+
signal
|
|
315199
|
+
});
|
|
315200
|
+
const body = await readJson(response);
|
|
315201
|
+
if (!response.ok) throw new SsoError("malformed", `the gateway refused to create the key: ${typeof body === "object" && body !== null && "error" in body ? JSON.stringify(body.error).slice(0, 200) : `HTTP ${response.status}`}`);
|
|
315202
|
+
const minted = parseMintResponse(body, alias);
|
|
315203
|
+
return {
|
|
315204
|
+
key: minted.key,
|
|
315205
|
+
alias: minted.alias,
|
|
315206
|
+
userId
|
|
315207
|
+
};
|
|
315208
|
+
}
|
|
315209
|
+
/**
|
|
315210
|
+
* Runs the whole flow and returns the durable key. The caller persists nothing
|
|
315211
|
+
* until this resolves, so a cancelled login leaves no half-written state.
|
|
315212
|
+
*/
|
|
315213
|
+
async function provisionApiKeyViaSso(input) {
|
|
315214
|
+
const now = input.now ?? Date.now;
|
|
315215
|
+
const sleep = input.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
|
|
315216
|
+
const interval = input.pollIntervalMs ?? POLL_INTERVAL_MS$1;
|
|
315217
|
+
const start = await startSso(input, input.signal);
|
|
315218
|
+
const browserUrl = start.verificationUriComplete ?? `${input.gatewayUrl}/sso/key/generate?source=litellm-cli&key=${encodeURIComponent(start.loginId)}&user_code=${encodeURIComponent(start.userCode)}`;
|
|
315219
|
+
input.onStatus?.(`Opening browser to sign in: ${browserUrl}`);
|
|
315220
|
+
input.openBrowser?.(browserUrl);
|
|
315221
|
+
const deadline = now() + (start.expiresInSeconds ?? DEFAULT_EXPIRES_IN_SECONDS) * 1e3 - 5e3;
|
|
315222
|
+
let pendingTeamId;
|
|
315223
|
+
let chosenTeamId;
|
|
315224
|
+
let selections = 0;
|
|
315225
|
+
let sawReadyWithoutKey = false;
|
|
315226
|
+
for (;;) {
|
|
315227
|
+
if (input.signal?.aborted === true) throw new SsoError("sso_timeout", "login cancelled.");
|
|
315228
|
+
const body = await pollOnce(input, start, pendingTeamId, input.signal);
|
|
315229
|
+
if (pendingTeamId !== void 0) chosenTeamId = pendingTeamId;
|
|
315230
|
+
pendingTeamId = void 0;
|
|
315231
|
+
if (chosenTeamId !== void 0 && body.status === "ready" && body.key !== void 0) return mintDurableKey(input, {
|
|
315232
|
+
jwt: body.key,
|
|
315233
|
+
userId: body.userId,
|
|
315234
|
+
teamId: body.teamId ?? chosenTeamId,
|
|
315235
|
+
teams: body.teams,
|
|
315236
|
+
teamDetails: body.teamDetails
|
|
315237
|
+
}, input.signal);
|
|
315238
|
+
const decision = decideSsoPoll(body);
|
|
315239
|
+
if (decision.action === "ready") return mintDurableKey(input, decision.ready, input.signal);
|
|
315240
|
+
if (decision.action === "fail") throw new SsoError(decision.code, decision.message);
|
|
315241
|
+
if (decision.action === "select_team") {
|
|
315242
|
+
selections += 1;
|
|
315243
|
+
if (selections > MAX_TEAM_SELECTIONS) throw new SsoError("no_team", "the gateway keeps asking for a team selection that cannot be satisfied.");
|
|
315244
|
+
pendingTeamId = decision.teamId;
|
|
315245
|
+
continue;
|
|
315246
|
+
}
|
|
315247
|
+
if (body.status === "ready") sawReadyWithoutKey = true;
|
|
315248
|
+
if (now() >= deadline) throw new SsoError(sawReadyWithoutKey ? "no_session_token" : "sso_timeout", sawReadyWithoutKey ? "the SSO finished without a session token (the gateway never returned one)." : "the SSO did not finish in time — the browser login was never completed.");
|
|
315249
|
+
await sleep(interval);
|
|
315250
|
+
}
|
|
315251
|
+
}
|
|
315252
|
+
// src/utils/process/resolve-command.ts
|
|
315253
|
+
function pathExtensions(platform, env) {
|
|
315254
|
+
if (platform !== "win32") return [""];
|
|
315255
|
+
const raw = env["PATHEXT"];
|
|
315256
|
+
if (raw === void 0 || raw.trim().length === 0) return DEFAULT_WIN32_PATHEXT;
|
|
315257
|
+
return raw.split(";").map((ext) => ext.trim()).filter((ext) => ext.length > 0);
|
|
315258
|
+
}
|
|
315259
|
+
function candidateNames(command, extensions) {
|
|
315260
|
+
if (extensions.length === 1 && extensions[0] === "") return [command];
|
|
315261
|
+
const lower = command.toLowerCase();
|
|
315262
|
+
if (extensions.some((ext) => lower.endsWith(ext.toLowerCase()))) return [command, ...extensions.map((ext) => command + ext)];
|
|
315263
|
+
return extensions.map((ext) => command + ext);
|
|
315264
|
+
}
|
|
315265
|
+
function isExecutableFile(candidate, platform) {
|
|
315266
|
+
try {
|
|
315267
|
+
if (!statSync(candidate).isFile()) return false;
|
|
315268
|
+
if (platform !== "win32") accessSync(candidate, constants$1.X_OK);
|
|
315269
|
+
return true;
|
|
315270
|
+
} catch {
|
|
315271
|
+
return false;
|
|
315272
|
+
}
|
|
315273
|
+
}
|
|
315274
|
+
function isInsideCwd(candidate, cwd, platform) {
|
|
315275
|
+
let resolvedCandidate = resolve(candidate);
|
|
315276
|
+
let resolvedCwd = resolve(cwd);
|
|
315277
|
+
if (resolvedCwd === parse(resolvedCwd).root) return false;
|
|
315278
|
+
if (platform === "win32") {
|
|
315279
|
+
resolvedCandidate = resolvedCandidate.toLowerCase();
|
|
315280
|
+
resolvedCwd = resolvedCwd.toLowerCase();
|
|
315281
|
+
}
|
|
315282
|
+
const rel = relative(resolvedCwd, resolvedCandidate);
|
|
315283
|
+
return rel !== "" && !rel.startsWith("..") && !isAbsolute(rel);
|
|
315284
|
+
}
|
|
315285
|
+
/**
|
|
315286
|
+
* Resolve a bare command name to an absolute executable path by searching
|
|
315287
|
+
* PATH (PATHEXT-aware on Windows). Returns undefined when the command is not
|
|
315288
|
+
* found — or when the only hit lives inside `cwd`, since executing that would
|
|
315289
|
+
* run whatever a malicious workspace planted there.
|
|
315290
|
+
*/
|
|
315291
|
+
function resolveCommandPath(command, cwd = process.cwd()) {
|
|
315292
|
+
const platform = process.platform;
|
|
315293
|
+
const env = process.env;
|
|
315294
|
+
const names = candidateNames(command, pathExtensions(platform, env));
|
|
315295
|
+
const pathValue = env["PATH"] ?? "";
|
|
315296
|
+
const separator = platform === "win32" ? ";" : ":";
|
|
315297
|
+
for (const dir of pathValue.split(separator)) {
|
|
315298
|
+
if (dir === "") continue;
|
|
315299
|
+
for (const name of names) {
|
|
315300
|
+
const candidate = join(dir, name);
|
|
315301
|
+
if (!isExecutableFile(candidate, platform)) continue;
|
|
315302
|
+
if (isInsideCwd(candidate, cwd, platform)) continue;
|
|
315303
|
+
return resolve(candidate);
|
|
315304
|
+
}
|
|
315305
|
+
}
|
|
315306
|
+
}
|
|
315307
|
+
var DEFAULT_WIN32_PATHEXT;
|
|
315308
|
+
var init_resolve_command = __esmMin((() => {
|
|
315309
|
+
DEFAULT_WIN32_PATHEXT = [
|
|
315310
|
+
".COM",
|
|
315311
|
+
".EXE",
|
|
315312
|
+
".BAT",
|
|
315313
|
+
".CMD"
|
|
315314
|
+
];
|
|
315315
|
+
}));
|
|
315316
|
+
// src/utils/open-url.ts
|
|
315317
|
+
function openUrl(url, onError) {
|
|
315318
|
+
const command = process.platform === "darwin" ? ["open", [url]] : process.platform === "win32" ? ["powershell.exe", [
|
|
315319
|
+
"-NoProfile",
|
|
315320
|
+
"-NonInteractive",
|
|
315321
|
+
"-EncodedCommand",
|
|
315322
|
+
Buffer.from(`try { Start-Process -FilePath '${url.replaceAll("'", "''")}' -ErrorAction Stop } catch { exit 1 }`, "utf16le").toString("base64")
|
|
315323
|
+
]] : ["xdg-open", [url]];
|
|
315324
|
+
const executable = resolveCommandPath(command[0]);
|
|
315325
|
+
if (executable === void 0) {
|
|
315326
|
+
onError?.(/* @__PURE__ */ new Error(`Cannot find ${command[0]}`));
|
|
315327
|
+
return;
|
|
315328
|
+
}
|
|
315329
|
+
execFile(executable, command[1], { windowsHide: true }, (error) => {
|
|
315330
|
+
if (error) onError?.(error);
|
|
315331
|
+
});
|
|
315332
|
+
}
|
|
315333
|
+
var init_open_url = __esmMin((() => {
|
|
315334
|
+
init_resolve_command();
|
|
315335
|
+
}));
|
|
315336
|
+
// src/cli/sub/login-flow.ts
|
|
314983
315337
|
init_src$8();
|
|
314984
315338
|
init_version$2();
|
|
315339
|
+
init_open_url();
|
|
314985
315340
|
const DEFAULT_BASE_URL = "https://ia.nexgen.systems/v1";
|
|
314986
315341
|
const PROVIDER_ID = "nexgenk";
|
|
314987
315342
|
const PREFERRED_MODEL = "nexgen-auto";
|
|
@@ -314989,8 +315344,8 @@ const FALLBACK_MAX_CONTEXT_SIZE = 262144;
|
|
|
314989
315344
|
const MODELS_REQUEST_TIMEOUT_MS = 2e4;
|
|
314990
315345
|
async function runLoginFlow(options = {}) {
|
|
314991
315346
|
try {
|
|
314992
|
-
const apiKey = resolveApiKey$1(options.apiKey);
|
|
314993
315347
|
const baseUrl = normalizeBaseUrl(options.baseUrl ?? readEnv("NEXGEN_BASE_URL") ?? DEFAULT_BASE_URL);
|
|
315348
|
+
const { apiKey, source } = await obtainApiKey(options, baseUrl);
|
|
314994
315349
|
const models = await fetchRouterModels({
|
|
314995
315350
|
apiKey,
|
|
314996
315351
|
baseUrl
|
|
@@ -315007,7 +315362,7 @@ async function runLoginFlow(options = {}) {
|
|
|
315007
315362
|
}))).defaultModel ?? PREFERRED_MODEL;
|
|
315008
315363
|
process.stderr.write([
|
|
315009
315364
|
"",
|
|
315010
|
-
`Logged in to ${baseUrl} (${models.length} models available).`,
|
|
315365
|
+
`Logged in to ${baseUrl} (${models.length} models available) via ${source}.`,
|
|
315011
315366
|
` provider: ${PROVIDER_ID}`,
|
|
315012
315367
|
` default model: ${defaultModel}`,
|
|
315013
315368
|
` config: ${harness.configPath}`,
|
|
@@ -315025,10 +315380,49 @@ function readEnv(name) {
|
|
|
315025
315380
|
const value = process.env[name]?.trim();
|
|
315026
315381
|
return value === void 0 || value.length === 0 ? void 0 : value;
|
|
315027
315382
|
}
|
|
315028
|
-
function
|
|
315029
|
-
const
|
|
315030
|
-
if (
|
|
315031
|
-
|
|
315383
|
+
async function obtainApiKey(options, baseUrl) {
|
|
315384
|
+
const explicit = options.apiKey?.trim();
|
|
315385
|
+
if (explicit !== void 0 && explicit !== "") return {
|
|
315386
|
+
apiKey: explicit,
|
|
315387
|
+
source: "the provided API key"
|
|
315388
|
+
};
|
|
315389
|
+
const fromEnv = readEnv("NEXGEN_API_KEY");
|
|
315390
|
+
if (fromEnv !== void 0) return {
|
|
315391
|
+
apiKey: fromEnv,
|
|
315392
|
+
source: "NEXGEN_API_KEY"
|
|
315393
|
+
};
|
|
315394
|
+
process.stderr.write([
|
|
315395
|
+
"",
|
|
315396
|
+
"No API key found — signing in with SSO.",
|
|
315397
|
+
"A browser window will open; approve the login and this command finishes on its own.",
|
|
315398
|
+
""
|
|
315399
|
+
].join("\n"));
|
|
315400
|
+
const controller = new AbortController();
|
|
315401
|
+
const onSigint = () => controller.abort();
|
|
315402
|
+
process.once("SIGINT", onSigint);
|
|
315403
|
+
try {
|
|
315404
|
+
const provisioned = await provisionApiKeyViaSso({
|
|
315405
|
+
gatewayUrl: gatewayOrigin(baseUrl),
|
|
315406
|
+
signal: controller.signal,
|
|
315407
|
+
onStatus: (line) => process.stderr.write(`${line}\n`),
|
|
315408
|
+
openBrowser: (url) => {
|
|
315409
|
+
if (options.noBrowser === true) {
|
|
315410
|
+
process.stderr.write(`Open this URL to sign in: ${url}\n`);
|
|
315411
|
+
return;
|
|
315412
|
+
}
|
|
315413
|
+
process.stderr.write(`Waiting for the SSO login to complete…\n`);
|
|
315414
|
+
openUrl(url, (error) => {
|
|
315415
|
+
process.stderr.write(`Could not open a browser (${error.message}). Open this URL to sign in: ${url}\n`);
|
|
315416
|
+
});
|
|
315417
|
+
}
|
|
315418
|
+
});
|
|
315419
|
+
return {
|
|
315420
|
+
apiKey: provisioned.key,
|
|
315421
|
+
source: `SSO (key alias ${provisioned.alias})`
|
|
315422
|
+
};
|
|
315423
|
+
} finally {
|
|
315424
|
+
process.off("SIGINT", onSigint);
|
|
315425
|
+
}
|
|
315032
315426
|
}
|
|
315033
315427
|
function normalizeBaseUrl(raw) {
|
|
315034
315428
|
const trimmed = raw.trim().replace(/\/+$/, "");
|
|
@@ -315042,6 +315436,10 @@ function normalizeBaseUrl(raw) {
|
|
|
315042
315436
|
if (parsed.protocol !== "https:" && parsed.protocol !== "http:") throw new Error(`base URL must be http(s), got "${raw}".`);
|
|
315043
315437
|
return parsed.pathname === "" || parsed.pathname === "/" ? `${trimmed}/v1` : trimmed;
|
|
315044
315438
|
}
|
|
315439
|
+
function gatewayOrigin(baseUrl) {
|
|
315440
|
+
const parsed = new URL(baseUrl);
|
|
315441
|
+
return /\/v1\/?$/.test(parsed.pathname) ? parsed.origin : baseUrl.replace(/\/+$/, "");
|
|
315442
|
+
}
|
|
315045
315443
|
async function fetchRouterModels(input) {
|
|
315046
315444
|
const url = `${input.baseUrl}/models`;
|
|
315047
315445
|
let response;
|
|
@@ -322645,70 +323043,6 @@ function formatIssuePath(path) {
|
|
|
322645
323043
|
function camelToSnake$1(value) {
|
|
322646
323044
|
return value.replaceAll(/[A-Z]/g, (ch) => `_${ch.toLowerCase()}`);
|
|
322647
323045
|
}
|
|
322648
|
-
// src/utils/process/resolve-command.ts
|
|
322649
|
-
function pathExtensions(platform, env) {
|
|
322650
|
-
if (platform !== "win32") return [""];
|
|
322651
|
-
const raw = env["PATHEXT"];
|
|
322652
|
-
if (raw === void 0 || raw.trim().length === 0) return DEFAULT_WIN32_PATHEXT;
|
|
322653
|
-
return raw.split(";").map((ext) => ext.trim()).filter((ext) => ext.length > 0);
|
|
322654
|
-
}
|
|
322655
|
-
function candidateNames(command, extensions) {
|
|
322656
|
-
if (extensions.length === 1 && extensions[0] === "") return [command];
|
|
322657
|
-
const lower = command.toLowerCase();
|
|
322658
|
-
if (extensions.some((ext) => lower.endsWith(ext.toLowerCase()))) return [command, ...extensions.map((ext) => command + ext)];
|
|
322659
|
-
return extensions.map((ext) => command + ext);
|
|
322660
|
-
}
|
|
322661
|
-
function isExecutableFile(candidate, platform) {
|
|
322662
|
-
try {
|
|
322663
|
-
if (!statSync(candidate).isFile()) return false;
|
|
322664
|
-
if (platform !== "win32") accessSync(candidate, constants$1.X_OK);
|
|
322665
|
-
return true;
|
|
322666
|
-
} catch {
|
|
322667
|
-
return false;
|
|
322668
|
-
}
|
|
322669
|
-
}
|
|
322670
|
-
function isInsideCwd(candidate, cwd, platform) {
|
|
322671
|
-
let resolvedCandidate = resolve(candidate);
|
|
322672
|
-
let resolvedCwd = resolve(cwd);
|
|
322673
|
-
if (resolvedCwd === parse(resolvedCwd).root) return false;
|
|
322674
|
-
if (platform === "win32") {
|
|
322675
|
-
resolvedCandidate = resolvedCandidate.toLowerCase();
|
|
322676
|
-
resolvedCwd = resolvedCwd.toLowerCase();
|
|
322677
|
-
}
|
|
322678
|
-
const rel = relative(resolvedCwd, resolvedCandidate);
|
|
322679
|
-
return rel !== "" && !rel.startsWith("..") && !isAbsolute(rel);
|
|
322680
|
-
}
|
|
322681
|
-
/**
|
|
322682
|
-
* Resolve a bare command name to an absolute executable path by searching
|
|
322683
|
-
* PATH (PATHEXT-aware on Windows). Returns undefined when the command is not
|
|
322684
|
-
* found — or when the only hit lives inside `cwd`, since executing that would
|
|
322685
|
-
* run whatever a malicious workspace planted there.
|
|
322686
|
-
*/
|
|
322687
|
-
function resolveCommandPath(command, cwd = process.cwd()) {
|
|
322688
|
-
const platform = process.platform;
|
|
322689
|
-
const env = process.env;
|
|
322690
|
-
const names = candidateNames(command, pathExtensions(platform, env));
|
|
322691
|
-
const pathValue = env["PATH"] ?? "";
|
|
322692
|
-
const separator = platform === "win32" ? ";" : ":";
|
|
322693
|
-
for (const dir of pathValue.split(separator)) {
|
|
322694
|
-
if (dir === "") continue;
|
|
322695
|
-
for (const name of names) {
|
|
322696
|
-
const candidate = join(dir, name);
|
|
322697
|
-
if (!isExecutableFile(candidate, platform)) continue;
|
|
322698
|
-
if (isInsideCwd(candidate, cwd, platform)) continue;
|
|
322699
|
-
return resolve(candidate);
|
|
322700
|
-
}
|
|
322701
|
-
}
|
|
322702
|
-
}
|
|
322703
|
-
var DEFAULT_WIN32_PATHEXT;
|
|
322704
|
-
var init_resolve_command = __esmMin((() => {
|
|
322705
|
-
DEFAULT_WIN32_PATHEXT = [
|
|
322706
|
-
".COM",
|
|
322707
|
-
".EXE",
|
|
322708
|
-
".BAT",
|
|
322709
|
-
".CMD"
|
|
322710
|
-
];
|
|
322711
|
-
}));
|
|
322712
323046
|
// src/cli/update/types.ts
|
|
322713
323047
|
function emptyUpdateCache() {
|
|
322714
323048
|
return {
|
|
@@ -323147,26 +323481,6 @@ async function confirmPreviousSession(summary) {
|
|
|
323147
323481
|
function errorMessage$7(error) {
|
|
323148
323482
|
return error instanceof Error ? error.message : String(error);
|
|
323149
323483
|
}
|
|
323150
|
-
// src/utils/open-url.ts
|
|
323151
|
-
function openUrl(url, onError) {
|
|
323152
|
-
const command = process.platform === "darwin" ? ["open", [url]] : process.platform === "win32" ? ["powershell.exe", [
|
|
323153
|
-
"-NoProfile",
|
|
323154
|
-
"-NonInteractive",
|
|
323155
|
-
"-EncodedCommand",
|
|
323156
|
-
Buffer.from(`try { Start-Process -FilePath '${url.replaceAll("'", "''")}' -ErrorAction Stop } catch { exit 1 }`, "utf16le").toString("base64")
|
|
323157
|
-
]] : ["xdg-open", [url]];
|
|
323158
|
-
const executable = resolveCommandPath(command[0]);
|
|
323159
|
-
if (executable === void 0) {
|
|
323160
|
-
onError?.(/* @__PURE__ */ new Error(`Cannot find ${command[0]}`));
|
|
323161
|
-
return;
|
|
323162
|
-
}
|
|
323163
|
-
execFile(executable, command[1], { windowsHide: true }, (error) => {
|
|
323164
|
-
if (error) onError?.(error);
|
|
323165
|
-
});
|
|
323166
|
-
}
|
|
323167
|
-
var init_open_url = __esmMin((() => {
|
|
323168
|
-
init_resolve_command();
|
|
323169
|
-
}));
|
|
323170
323484
|
// src/cli/sub/app.ts
|
|
323171
323485
|
init_open_url();
|
|
323172
323486
|
function registerAppCommand(program) {
|
|
@@ -323192,10 +323506,11 @@ function registerInstallDesktopCommand(program) {
|
|
|
323192
323506
|
}
|
|
323193
323507
|
// src/cli/sub/login.ts
|
|
323194
323508
|
function registerLoginCommand(parent) {
|
|
323195
|
-
parent.command("login").description("
|
|
323509
|
+
parent.command("login").description("Sign in with SSO (or an API key) and configure the default model.").option("--api-key <key>", "Use this API key instead of the SSO flow. Defaults to NEXGEN_API_KEY.").option("--base-url <url>", "Router base URL. Defaults to NEXGEN_BASE_URL or https://ia.nexgen.systems/v1.").option("--no-browser", "Print the SSO URL instead of opening a browser (headless hosts).").action(async (opts) => {
|
|
323196
323510
|
await runLoginFlow({
|
|
323197
323511
|
apiKey: opts.apiKey,
|
|
323198
|
-
baseUrl: opts.baseUrl
|
|
323512
|
+
baseUrl: opts.baseUrl,
|
|
323513
|
+
noBrowser: opts.browser === false
|
|
323199
323514
|
});
|
|
323200
323515
|
});
|
|
323201
323516
|
}
|