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.
Files changed (2) hide show
  1. package/dist/main.mjs +537 -222
  2. 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$2(snapshot)}`);
41451
- if (type == null) throw new OpenAIError(`missing choices[${index}].tool_calls[${i}].type\n${str$2(snapshot)}`);
41452
- if (name == null) throw new OpenAIError(`missing choices[${index}].tool_calls[${i}].function.name\n${str$2(snapshot)}`);
41453
- if (args == null) throw new OpenAIError(`missing choices[${index}].tool_calls[${i}].function.arguments\n${str$2(snapshot)}`);
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$2(x) {
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$25(value) {
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$25(parsed)) return void 0;
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$25(value)) return void 0;
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$25(error)) for (const key of NESTED_ERROR_KEYS) {
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$25(parsed)) data = parsed;
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$25(payload)) return {
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$25(raw)) return {};
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$25(raw)) return void 0;
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$25(raw)) return null;
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$25(raw)) return null;
60873
+ if (!isRecord$26(raw)) return null;
60874
60874
  const balance = raw["balance"];
60875
- if (!isRecord$25(balance)) return null;
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$25(existing) ? existing : {};
61004
- const overrides = cloneOverrides(isRecord$25(current["overrides"]) ? current["overrides"] : void 0);
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$25(item) || typeof item["id"] !== "string" || item["id"].length === 0) return;
61187
+ if (!isRecord$26(item) || typeof item["id"] !== "string" || item["id"].length === 0) return;
61188
61188
  const rawLimit = item["limit"];
61189
- const limit = isRecord$25(rawLimit) ? rawLimit : void 0;
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$25(rawModalities) ? parseStringArray(rawModalities["input"]) : void 0;
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$25(rawTools) && rawTools["dynamic_load"] === true;
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$25(value)) return {
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$25(rawEffort) ? rawEffort : void 0;
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$25(payload) || !Array.isArray(payload["data"])) throw new Error(`Unexpected models response for ${baseUrl}.`);
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$25(model) && model["provider"] === "managed:nexgenk" && !upstreamKeys.has(key)) delete existingModels[key];
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$25(existingModels[key]) ? existingModels[key] : {}, toManagedModelAlias(NEXGEN_PROVIDER_NAME, model), MANAGED_NEXGEN_MODEL_FIELDS);
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$25(model) && model["provider"] === providerId && !upstreamKeys.has(key)) delete existingModels[key];
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$25(existingModels[key]) ? existingModels[key] : {}, toManagedModelAlias(providerId, model), MANAGED_NEXGEN_MODEL_FIELDS);
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$25(model) || model["provider"] !== "managed:nexgenk") continue;
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$25(existing) && existing["provider"] !== "managed:nexgenk";
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$25(model) || model["provider"] !== "managed:nexgenk") continue;
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$25(payload)) return null;
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$25(raw)) return void 0;
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$25(payload)) return void 0;
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$25(item) || typeof item["id"] !== "string" || item["id"].length === 0) return;
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$25(payload) || !Array.isArray(payload["data"])) throw new Error(`Unexpected models response for ${platform.baseUrl}.`);
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$25(model) && model["provider"] === providerKey && !upstreamKeys.has(key)) delete existingModels[key];
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$25(existingModels[aliasKey]) ? existingModels[aliasKey] : {}, {
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$25(provider)) return void 0;
62597
+ if (!isRecord$26(provider)) return void 0;
62598
62598
  const candidate = provider["source"];
62599
- if (!isRecord$25(candidate) || candidate["kind"] !== "apiJson") return void 0;
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$25(provider)) return void 0;
62604
+ if (!isRecord$26(provider)) return void 0;
62605
62605
  const candidate = provider["source"];
62606
62606
  const url = customRegistrySourceUrl(provider);
62607
- const apiKey = isRecord$25(candidate) ? candidate["apiKey"] : void 0;
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$25(value)) return void 0;
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$25(limit)) {
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$25(modalities)) {
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$25(rawUpgrade)) throw new Error(`Invalid upgrade for model "${id}": expected an object.`);
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$25(value)) return void 0;
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$25(models)) return void 0;
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$25(payload)) throw new Error(`Unexpected custom registry response at ${source.url}: expected a JSON object keyed by provider id.`);
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$25(existing) && existing["oauth"] !== void 0) throw new Error(oauthManagedProviderMessage(entry.id));
62811
- if (!isRecord$25(existing) || readCustomRegistrySource$1(existing)?.url !== source.url) return;
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$25(alias) && alias["provider"] === providerKey && !upstreamKeys.has(key)) delete existingModels[key];
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$25(existingModels[aliasKey]) ? existingModels[aliasKey] : {};
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$25(alias) || alias["provider"] !== providerId) continue;
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$25(model) && isRecord$25(model["upgrade"]) ? nonEmptyString$5(model["upgrade"]["model"]) : void 0;
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$25(provider)) continue;
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$25(existingSource) && existingSource["kind"] === "apiJson" && existingSource["url"] === source.url;
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$25(provider)) continue;
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$25(model) && providerIds.has(String(model["provider"]))) modelIds.add(modelId);
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$25(provider.env)) {
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$1, 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;
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$1 = new type$2("tag:yaml.org,2002: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$1,
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$24(frontmatter)) throw new SkillParseError(`Frontmatter in ${options.skillMdPath} must be a mapping at the top level`);
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$24(value) {
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$23(data)) throw new Error("expected a JSON object");
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$23(raw)) throw new Error("\"mcpServers\" must be an object");
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$23(value) {
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$22(value) {
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$22(parsed)) throw configError(`Invalid MCP config in ${this.path}: expected a JSON object`);
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$22(rawServersValue)) throw configError(`Invalid MCP config in ${this.path}: "mcpServers" must be an object`);
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$21(frontmatter)) throw new AgentFileParseError(`Frontmatter in ${options.path} must be a mapping at the top level`);
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$21(value) {
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$20(obj) && (typeof obj["taskId"] === "string" || typeof obj["task_id"] === "string");
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$20(value) {
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$19(normalized)) throw new SyntaxRequestFormatError("JSON Schema root must normalize to an object.");
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$19(current)) {
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$19(node)) return;
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$19(value)) visit(value);
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$19(value)) for (const item of Object.values(value)) visit(item);
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$19(value)) visit(value);
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$19(node)) return;
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$19(value)) {
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$19(value) {
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$18(provider)) continue;
201626
+ if (!isRecord$19(provider)) continue;
201627
201627
  const source = provider["source"];
201628
- if (isRecord$18(source) && source["kind"] === "apiJson" && source["url"] === url) {
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$18(value) {
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$17(parsed.data) ? parsed.data : {};
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$17(value) {
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$16(parsed)) throw new TypeError("Plugin marketplace must be an object.");
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$16(value)) throw new TypeError(`Plugin marketplace entry ${index + 1} must be an object.`);
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$16(value) {
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$15(value) {
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$15(value) ? value : void 0, looseObject({
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$14(value) {
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$14(parsed) ? parsed : {}
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$14(parsed) ? parsed : {}
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$13(providers)) for (const prov of Object.values(providers)) {
289902
- if (!isRecord$13(prov)) continue;
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$13(oauth)) continue;
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$13(value) {
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$13(parsed)) return [];
290027
+ if (!isRecord$14(parsed)) return [];
290028
290028
  const servers = parsed["mcpServers"];
290029
- if (!isRecord$13(servers)) return [];
290029
+ if (!isRecord$14(servers)) return [];
290030
290030
  const out = [];
290031
- for (const [name, server] of Object.entries(servers)) if (isRecord$13(server) && server["auth"] === "oauth") out.push(name);
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$12(value) {
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$12(transformed) ? transformed["x"] : void 0;
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$12(entry) ? entry["type"] : void 0;
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$12(transformed) ? transformed["x"] : void 0;
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$12(value)) return `{${Object.keys(value).toSorted().map((k) => `${JSON.stringify(k)}:${stableKey(value[k])}`).join(",")}}`;
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$12(providers)) return parsed;
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$12(prov)) {
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$12(value)) {
290312
- const section = isRecord$12(merged[key]) ? { ...merged[key] } : {};
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$12(tp) ? tp : {};
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$12(targetParsed["providers"]) ? Object.keys(targetParsed["providers"]) : []);
290353
- const availableModelNames = new Set(isRecord$12(targetParsed["models"]) ? Object.keys(targetParsed["models"]) : []);
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$12(parsed["providers"])) for (const [name, prov] of Object.entries(parsed["providers"])) if (isRecord$12(prov) && providerIsSupported(prov)) keptProviders[name] = prov;
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$12(targetParsed["providers"]) ? targetParsed["providers"] : {};
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$12(parsed["models"])) for (const [name, mod] of Object.entries(parsed["models"])) {
290367
- if (!isRecord$12(mod) || !modelIsSupported(mod)) {
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$12(v)) {
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$12(v)) {
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$12(v)) {
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$11(value) {
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$11(sourceJson)) {
290603
+ if (isRecord$12(sourceJson)) {
290604
290604
  const raw = sourceJson["mcpServers"];
290605
- if (isRecord$11(raw)) for (const [name, srv] of Object.entries(raw)) srcServers[name] = srv;
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$11(parsed)) {
290617
+ if (isRecord$12(parsed)) {
290618
290618
  const raw = parsed["mcpServers"];
290619
- if (isRecord$11(raw)) for (const [name, srv] of Object.entries(raw)) mergedTargetServers[name] = srv;
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/sub/login-flow.ts
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 resolveApiKey$1(explicit) {
315029
- const candidate = explicit?.trim() ?? readEnv("NEXGEN_API_KEY");
315030
- if (candidate === void 0 || candidate === "") throw new Error("no API key. Pass --api-key <key>, or export NEXGEN_API_KEY with the key issued at https://ia.nexgen.systems.");
315031
- return candidate;
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("Validate your NexgenK API key and configure the default model.").option("--api-key <key>", "API key issued at https://ia.nexgen.systems. Defaults to NEXGEN_API_KEY.").option("--base-url <url>", "Router base URL. Defaults to NEXGEN_BASE_URL or https://ia.nexgen.systems/v1.").action(async (opts) => {
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
  }