ur-agent 1.27.6 → 1.28.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/cli.js CHANGED
@@ -51195,13 +51195,1480 @@ var init_configs = __esm(() => {
51195
51195
  CANONICAL_ID_TO_KEY = Object.fromEntries(Object.entries(ALL_MODEL_CONFIGS).map(([key, cfg]) => [cfg.firstParty, key]));
51196
51196
  });
51197
51197
 
51198
+ // src/services/providers/providerRegistry.ts
51199
+ var exports_providerRegistry = {};
51200
+ __export(exports_providerRegistry, {
51201
+ validateProviderModelPair: () => validateProviderModelPair,
51202
+ validateProviderModelCompatibility: () => validateProviderModelCompatibility,
51203
+ setSafeProviderConfig: () => setSafeProviderConfig,
51204
+ setProviderModel: () => setProviderModel,
51205
+ resolveProviderId: () => resolveProviderId,
51206
+ providerForAuthAlias: () => providerForAuthAlias,
51207
+ providerAliasesFor: () => providerAliasesFor,
51208
+ listProviders: () => listProviders,
51209
+ listModelsForProviderWithSource: () => listModelsForProviderWithSource,
51210
+ listModelsForProvider: () => listModelsForProvider,
51211
+ launchProviderAuth: () => launchProviderAuth,
51212
+ isProviderId: () => isProviderId,
51213
+ isModelSupportedByProvider: () => isModelSupportedByProvider,
51214
+ getValidModelIdsForProvider: () => getValidModelIdsForProvider,
51215
+ getRuntimeProviderId: () => getRuntimeProviderId,
51216
+ getProviderStatus: () => getProviderStatus,
51217
+ getProviderRuntimeInfo: () => getProviderRuntimeInfo,
51218
+ getProviderRuntimeBackend: () => getProviderRuntimeBackend,
51219
+ getProviderFamily: () => getProviderFamily,
51220
+ getProviderDefinition: () => getProviderDefinition,
51221
+ getProviderAccessTypeLabel: () => getProviderAccessTypeLabel,
51222
+ getDefaultModelForProvider: () => getDefaultModelForProvider,
51223
+ getConnectionStatusFromDoctorResult: () => getConnectionStatusFromDoctorResult,
51224
+ getActiveProviderSettings: () => getActiveProviderSettings,
51225
+ formatProviderStatusLabel: () => formatProviderStatusLabel,
51226
+ formatProviderStatus: () => formatProviderStatus,
51227
+ formatProviderList: () => formatProviderList,
51228
+ formatProviderDoctor: () => formatProviderDoctor,
51229
+ formatInvalidProviderModelMessage: () => formatInvalidProviderModelMessage,
51230
+ doctorProvider: () => doctorProvider,
51231
+ doctorActiveProvider: () => doctorActiveProvider,
51232
+ credentialTypeLabel: () => credentialTypeLabel,
51233
+ clearProviderModelCacheForTests: () => clearProviderModelCacheForTests,
51234
+ classifyGeminiAccountSupport: () => classifyGeminiAccountSupport,
51235
+ cacheProviderModelsForProvider: () => cacheProviderModelsForProvider,
51236
+ buildProviderAuthCommand: () => buildProviderAuthCommand,
51237
+ authModeLabel: () => authModeLabel,
51238
+ authAliasForProvider: () => authAliasForProvider,
51239
+ PROVIDER_MODELS: () => PROVIDER_MODELS,
51240
+ PROVIDER_IDS: () => PROVIDER_IDS,
51241
+ PROVIDERS: () => PROVIDERS,
51242
+ DEFAULT_PROVIDER_ID: () => DEFAULT_PROVIDER_ID
51243
+ });
51244
+ import { spawn as spawn2 } from "child_process";
51245
+ function normalizeProviderInput(value) {
51246
+ return value.trim().toLowerCase().replace(/[_\s]+/g, "-");
51247
+ }
51248
+ function isProviderId(value) {
51249
+ return PROVIDER_IDS.includes(value);
51250
+ }
51251
+ function resolveProviderId(value) {
51252
+ const normalized = normalizeProviderInput(value);
51253
+ if (isProviderId(normalized)) {
51254
+ return normalized;
51255
+ }
51256
+ return PROVIDER_ALIASES[normalized] ?? null;
51257
+ }
51258
+ function providerAliasesFor(id) {
51259
+ return PROVIDER_ALIAS_ENTRIES.find((entry) => entry.canonical === id)?.aliases ?? [];
51260
+ }
51261
+ function getProviderDefinition(id) {
51262
+ return PROVIDERS[id];
51263
+ }
51264
+ function getActiveProviderSettings(settings = getInitialSettings()) {
51265
+ const configured = settings.provider ?? {};
51266
+ const active = configured.active ? resolveProviderId(configured.active) ?? DEFAULT_PROVIDER_ID : DEFAULT_PROVIDER_ID;
51267
+ const fallback = configured.fallback === "disabled" ? "disabled" : configured.fallback ? resolveProviderId(configured.fallback) ?? undefined : undefined;
51268
+ return {
51269
+ active,
51270
+ model: configured.model ?? (configured.active ? undefined : settings.model),
51271
+ baseUrl: configured.baseUrl,
51272
+ commandPath: configured.commandPath,
51273
+ fallback
51274
+ };
51275
+ }
51276
+ function getProviderRuntimeInfo(settings = getInitialSettings()) {
51277
+ const providerSettings = getActiveProviderSettings(settings);
51278
+ const provider = providerSettings.active ?? DEFAULT_PROVIDER_ID;
51279
+ const definition = getProviderDefinition(provider);
51280
+ return {
51281
+ provider,
51282
+ providerLabel: definition.statusBarName,
51283
+ accessType: definition.accessType,
51284
+ accessTypeLabel: getProviderAccessTypeLabel(definition),
51285
+ credentialType: definition.credentialType,
51286
+ runtimeBackend: getProviderRuntimeBackend(provider),
51287
+ authMode: definition.authMode,
51288
+ authLabel: authModeLabel(definition.authMode),
51289
+ model: providerSettings.model,
51290
+ baseUrl: providerSettings.baseUrl ?? definition.defaultBaseUrl,
51291
+ fallback: providerSettings.fallback
51292
+ };
51293
+ }
51294
+ function getProviderRuntimeBackend(providerId) {
51295
+ const provider = resolveProviderId(providerId);
51296
+ switch (provider) {
51297
+ case "ollama":
51298
+ return "ollama";
51299
+ case "lmstudio":
51300
+ return "openai-compatible:lmstudio";
51301
+ case "llama.cpp":
51302
+ return "openai-compatible:llama.cpp";
51303
+ case "vllm":
51304
+ return "openai-compatible:vllm";
51305
+ case "openai-compatible":
51306
+ return "openai-compatible";
51307
+ case "codex-cli":
51308
+ return "subscription-cli:codex";
51309
+ case "claude-code-cli":
51310
+ return "subscription-cli:claude-code";
51311
+ case "gemini-cli":
51312
+ return "subscription-cli:gemini";
51313
+ case "antigravity-cli":
51314
+ return "subscription-cli:antigravity";
51315
+ case "openai-api":
51316
+ return "api:openai";
51317
+ case "anthropic-api":
51318
+ return "api:anthropic";
51319
+ case "gemini-api":
51320
+ return "api:gemini";
51321
+ case "openrouter":
51322
+ return "api:openrouter";
51323
+ default:
51324
+ return `unknown:${providerId}`;
51325
+ }
51326
+ }
51327
+ function getProviderFamily(providerId) {
51328
+ const provider = resolveProviderId(providerId);
51329
+ return provider ? PROVIDER_FAMILIES[provider] : "openai-compatible";
51330
+ }
51331
+ function getRuntimeProviderId(settings = getInitialSettings()) {
51332
+ return getActiveProviderSettings(settings).active ?? DEFAULT_PROVIDER_ID;
51333
+ }
51334
+ function authModeLabel(mode) {
51335
+ switch (mode) {
51336
+ case "subscription":
51337
+ return "subscription";
51338
+ case "enterprise-login":
51339
+ return "enterprise-login";
51340
+ case "personal-login":
51341
+ return "personal-login";
51342
+ case "api":
51343
+ return "API";
51344
+ case "local":
51345
+ return "local";
51346
+ }
51347
+ }
51348
+ function getProviderAccessTypeLabel(provider) {
51349
+ return provider.accessTypeLabel ?? provider.accessType;
51350
+ }
51351
+ function credentialTypeLabel(type) {
51352
+ switch (type) {
51353
+ case "cli-login":
51354
+ return "subscription login";
51355
+ case "api-key":
51356
+ return "API key";
51357
+ case "local-runtime":
51358
+ return "local runtime";
51359
+ case "openai-compatible-endpoint":
51360
+ return "OpenAI-compatible endpoint";
51361
+ }
51362
+ }
51363
+ function listProviders() {
51364
+ return PROVIDER_IDS.map((id) => PROVIDERS[id]);
51365
+ }
51366
+ function hasSecretLikeValue(value) {
51367
+ const trimmed = value.trim();
51368
+ if (/^(sk-|sk_|sk-proj-|sk-ant-|xox[baprs]-|gh[pousr]_|AIza)/i.test(trimmed)) {
51369
+ return true;
51370
+ }
51371
+ if (/token|refresh|oauth|secret|api[_-]?key/i.test(trimmed)) {
51372
+ return true;
51373
+ }
51374
+ try {
51375
+ const url3 = new URL(trimmed);
51376
+ return Boolean(url3.username || url3.password);
51377
+ } catch {
51378
+ return false;
51379
+ }
51380
+ }
51381
+ function normalizeBaseUrl(value) {
51382
+ const trimmed = value.trim();
51383
+ const withScheme = /^https?:\/\//i.test(trimmed) ? trimmed : `http://${trimmed}`;
51384
+ const url3 = new URL(withScheme);
51385
+ if (url3.username || url3.password) {
51386
+ throw new Error("base_url must not contain embedded credentials");
51387
+ }
51388
+ return withScheme.replace(/\/$/, "");
51389
+ }
51390
+ function setSafeProviderConfig(key, value) {
51391
+ const trimmed = value.trim();
51392
+ if (!trimmed) {
51393
+ return { ok: false, message: `Missing value for ${key}.` };
51394
+ }
51395
+ if (hasSecretLikeValue(trimmed)) {
51396
+ return {
51397
+ ok: false,
51398
+ message: "Refusing to store credential-like data. Put API keys in environment variables and select API mode explicitly."
51399
+ };
51400
+ }
51401
+ let settings;
51402
+ let providerModelInvalidated = false;
51403
+ try {
51404
+ if (key === "provider") {
51405
+ const provider = resolveProviderId(trimmed);
51406
+ if (!provider) {
51407
+ return {
51408
+ ok: false,
51409
+ message: `Unknown provider "${trimmed}". Run: ur provider list`
51410
+ };
51411
+ }
51412
+ const currentSettings = getInitialSettings();
51413
+ const currentModel = getActiveProviderSettings(currentSettings).model;
51414
+ const nextProviderSettings = { active: provider };
51415
+ let invalidated = false;
51416
+ if (currentModel) {
51417
+ const validation = validateProviderModelPair(provider, currentModel);
51418
+ if (validation.valid === false) {
51419
+ nextProviderSettings.model = undefined;
51420
+ invalidated = true;
51421
+ providerModelInvalidated = true;
51422
+ }
51423
+ }
51424
+ settings = {
51425
+ provider: nextProviderSettings,
51426
+ ...invalidated ? { model: undefined } : {}
51427
+ };
51428
+ } else if (key === "provider.fallback") {
51429
+ const fallback = trimmed === "disabled" ? "disabled" : resolveProviderId(trimmed);
51430
+ if (!fallback) {
51431
+ return {
51432
+ ok: false,
51433
+ message: `Unknown fallback provider "${trimmed}". Run: ur provider list`
51434
+ };
51435
+ }
51436
+ settings = { provider: { fallback } };
51437
+ } else if (key === "provider.command_path") {
51438
+ settings = { provider: { commandPath: trimmed } };
51439
+ } else if (key === "model") {
51440
+ const currentSettings = getInitialSettings();
51441
+ const currentProvider = getActiveProviderSettings(currentSettings).active ?? "ollama";
51442
+ const validation = validateProviderModelPair(currentProvider, trimmed);
51443
+ if (validation.valid === false) {
51444
+ return {
51445
+ ok: false,
51446
+ message: validation.error
51447
+ };
51448
+ }
51449
+ settings = { provider: { model: trimmed }, model: trimmed };
51450
+ } else {
51451
+ settings = { provider: { baseUrl: normalizeBaseUrl(trimmed) } };
51452
+ }
51453
+ } catch (error40) {
51454
+ return {
51455
+ ok: false,
51456
+ message: error40 instanceof Error ? error40.message : String(error40)
51457
+ };
51458
+ }
51459
+ const result = updateSettingsForSource("userSettings", settings);
51460
+ if (result.error) {
51461
+ return {
51462
+ ok: false,
51463
+ message: `Failed to write UR-AGENT settings: ${result.error.message}`
51464
+ };
51465
+ }
51466
+ const savedValue = key === "provider" || key === "provider.fallback" ? key === "provider.fallback" && trimmed === "disabled" ? "disabled" : resolveProviderId(trimmed) ?? trimmed : trimmed;
51467
+ return {
51468
+ ok: true,
51469
+ message: `Set ${key} to ${savedValue}.${providerModelInvalidated ? " Cleared incompatible model for the new provider; run /model to choose a scoped model." : ""}`
51470
+ };
51471
+ }
51472
+ function outputText(result) {
51473
+ return `${result.stdout}
51474
+ ${result.stderr}
51475
+ ${result.error ?? ""}`.trim();
51476
+ }
51477
+ function classifiesAsLoggedIn(text) {
51478
+ return /logged in|authenticated|signed in|active account|using chatgpt/i.test(text);
51479
+ }
51480
+ function classifiesAsNotLoggedIn(text) {
51481
+ return /not logged in|not authenticated|not signed in|login required|unauthenticated/i.test(text);
51482
+ }
51483
+ function classifyGeminiAccountSupport(text) {
51484
+ if (/personal.*unsupported|unsupported.*personal|consumer.*unsupported/i.test(text)) {
51485
+ return "personal-unsupported";
51486
+ }
51487
+ if (/enterprise|standard|code assist|workspace/i.test(text)) {
51488
+ return "enterprise-supported";
51489
+ }
51490
+ return "unknown";
51491
+ }
51492
+ async function resolveCommand(definition, settings, adapters) {
51493
+ if (settings.commandPath) {
51494
+ return settings.commandPath;
51495
+ }
51496
+ for (const candidate of definition.commandCandidates ?? []) {
51497
+ const found = await (adapters.which ?? which)(candidate);
51498
+ if (found)
51499
+ return found;
51500
+ }
51501
+ return null;
51502
+ }
51503
+ async function runCommand(file2, args, adapters) {
51504
+ if (adapters.run) {
51505
+ return adapters.run(file2, args);
51506
+ }
51507
+ return execFileNoThrow(file2, args, {
51508
+ timeout: 15000,
51509
+ preserveOutputOnError: true,
51510
+ audit: false
51511
+ });
51512
+ }
51513
+ function addFailure(result, reason, fix) {
51514
+ result.ok = false;
51515
+ result.failureReason ??= reason;
51516
+ result.suggestedFix ??= fix;
51517
+ }
51518
+ function endpointUrl(baseUrl, kind) {
51519
+ const trimmed = baseUrl.replace(/\/$/, "");
51520
+ if (kind === "ollama") {
51521
+ return `${trimmed}/api/tags`;
51522
+ }
51523
+ return `${trimmed}/models`;
51524
+ }
51525
+ function isLocalBaseUrl(value) {
51526
+ return LOCALHOST_RE.test(value);
51527
+ }
51528
+ async function checkEndpoint(definition, settings, adapters, result) {
51529
+ if (!definition.endpointKind)
51530
+ return;
51531
+ const baseUrl = settings.baseUrl ?? (definition.id === "ollama" ? getOllamaBaseUrl() : definition.defaultBaseUrl);
51532
+ if (!baseUrl) {
51533
+ result.checks.push({
51534
+ name: "base_url",
51535
+ status: "fail",
51536
+ message: "No base_url configured."
51537
+ });
51538
+ addFailure(result, "missing base_url", "Run: ur config set base_url <url>");
51539
+ return;
51540
+ }
51541
+ const url3 = endpointUrl(baseUrl, definition.endpointKind);
51542
+ try {
51543
+ const response = await (adapters.fetch ?? fetch)(url3, {
51544
+ method: "GET",
51545
+ headers: definition.accessType === "api" && (adapters.env ?? process.env)[definition.envKey ?? ""] ? { Authorization: `Bearer ${(adapters.env ?? process.env)[definition.envKey ?? ""]}` } : undefined
51546
+ });
51547
+ if (!response.ok) {
51548
+ result.checks.push({
51549
+ name: "endpoint",
51550
+ status: "fail",
51551
+ message: `${url3} returned HTTP ${response.status}.`
51552
+ });
51553
+ addFailure(result, `endpoint returned HTTP ${response.status}`, `Start the provider server or update base_url: ur config set base_url ${baseUrl}`);
51554
+ return;
51555
+ }
51556
+ result.checks.push({
51557
+ name: "endpoint",
51558
+ status: "pass",
51559
+ message: `${url3} is reachable.`
51560
+ });
51561
+ if (settings.model) {
51562
+ const body = await response.text().catch(() => "");
51563
+ if (body && !body.includes(settings.model)) {
51564
+ result.checks.push({
51565
+ name: "model",
51566
+ status: "warn",
51567
+ message: `Model "${settings.model}" was not found in the detectable model list.`
51568
+ });
51569
+ } else {
51570
+ result.checks.push({
51571
+ name: "model",
51572
+ status: "pass",
51573
+ message: `Model "${settings.model}" is detectable.`
51574
+ });
51575
+ }
51576
+ }
51577
+ } catch (error40) {
51578
+ result.checks.push({
51579
+ name: "endpoint",
51580
+ status: "fail",
51581
+ message: `${url3} is not reachable.`
51582
+ });
51583
+ addFailure(result, error40 instanceof Error ? error40.message : "endpoint unavailable", `Start the provider server or update base_url: ur config set base_url ${baseUrl}`);
51584
+ }
51585
+ }
51586
+ async function checkSubscriptionProvider(definition, settings, adapters, result) {
51587
+ const commandPath = await resolveCommand(definition, settings, adapters);
51588
+ if (!commandPath) {
51589
+ const commands = definition.commandCandidates?.join(", ") ?? definition.id;
51590
+ result.checks.push({
51591
+ name: "cli",
51592
+ status: "fail",
51593
+ message: `No official CLI command found on PATH. Tried: ${commands}.`
51594
+ });
51595
+ addFailure(result, "CLI missing", `Install the official ${definition.displayName} CLI, then run ur auth ${authAliasForProvider(definition.id)}.`);
51596
+ return;
51597
+ }
51598
+ result.checks.push({
51599
+ name: "cli",
51600
+ status: "pass",
51601
+ message: `${commandPath} found.`
51602
+ });
51603
+ if (definition.versionArgs) {
51604
+ const version2 = await runCommand(commandPath, definition.versionArgs, adapters);
51605
+ result.checks.push({
51606
+ name: "version",
51607
+ status: version2.code === 0 ? "pass" : "warn",
51608
+ message: outputText(version2) || `${definition.displayName} version check exited ${version2.code}.`
51609
+ });
51610
+ }
51611
+ if (definition.id === "claude-code-cli" && (adapters.env ?? process.env).ANTHROPIC_API_KEY) {
51612
+ result.checks.push({
51613
+ name: "api_key_override",
51614
+ status: "warn",
51615
+ message: "ANTHROPIC_API_KEY is set and may override Claude Code subscription login. Unset it to test subscription auth."
51616
+ });
51617
+ }
51618
+ if (definition.id === "gemini-cli") {
51619
+ const versionText = result.checks.find((check3) => check3.name === "version")?.message ?? "";
51620
+ const support = classifyGeminiAccountSupport(versionText);
51621
+ if (support === "personal-unsupported") {
51622
+ result.checks.push({
51623
+ name: "account_type",
51624
+ status: "fail",
51625
+ message: definition.unsupportedPersonalAccountMessage ?? "Unsupported account type."
51626
+ });
51627
+ addFailure(result, "unsupported account type", "Use an official Gemini Code Assist Standard/Enterprise login path.");
51628
+ } else if (support === "enterprise-supported") {
51629
+ result.checks.push({
51630
+ name: "account_type",
51631
+ status: "pass",
51632
+ message: "Gemini Code Assist Standard/Enterprise path is supported by the detected CLI output."
51633
+ });
51634
+ } else {
51635
+ result.checks.push({
51636
+ name: "account_type",
51637
+ status: "warn",
51638
+ message: "Gemini CLI status is not exposed by this CLI. UR-AGENT will only use the official Gemini CLI flow and will not support personal-account bypasses."
51639
+ });
51640
+ }
51641
+ }
51642
+ if (!definition.statusArgs) {
51643
+ result.checks.push({
51644
+ name: "login_status",
51645
+ status: "skip",
51646
+ message: "No stable official status command is configured for this provider."
51647
+ });
51648
+ return;
51649
+ }
51650
+ const status = await runCommand(commandPath, definition.statusArgs, adapters);
51651
+ const text = outputText(status);
51652
+ if (status.code === 0 && !classifiesAsNotLoggedIn(text)) {
51653
+ result.checks.push({
51654
+ name: "login_status",
51655
+ status: classifiesAsLoggedIn(text) ? "pass" : "warn",
51656
+ message: text || "Status command succeeded."
51657
+ });
51658
+ return;
51659
+ }
51660
+ result.checks.push({
51661
+ name: "login_status",
51662
+ status: "fail",
51663
+ message: text || `${definition.displayName} is not logged in.`
51664
+ });
51665
+ addFailure(result, "not logged in", `Run: ur auth ${authAliasForProvider(definition.id)}`);
51666
+ }
51667
+ async function checkApiProvider(definition, settings, adapters, result) {
51668
+ const env4 = adapters.env ?? process.env;
51669
+ const baseUrl = settings.baseUrl ?? definition.defaultBaseUrl;
51670
+ const requiresKey = definition.id !== "openai-compatible" || !baseUrl || !isLocalBaseUrl(baseUrl);
51671
+ if (definition.envKey && requiresKey) {
51672
+ if (env4[definition.envKey]) {
51673
+ result.checks.push({
51674
+ name: "api_key",
51675
+ status: "pass",
51676
+ message: `${definition.envKey} is present.`
51677
+ });
51678
+ } else {
51679
+ result.checks.push({
51680
+ name: "api_key",
51681
+ status: "fail",
51682
+ message: `${definition.envKey} is not set.`
51683
+ });
51684
+ addFailure(result, "API key missing", `Set ${definition.envKey} in your environment or choose a subscription/local provider.`);
51685
+ }
51686
+ }
51687
+ await checkEndpoint(definition, settings, adapters, result);
51688
+ }
51689
+ function fallbackResult(settings, active, ok) {
51690
+ if (ok)
51691
+ return;
51692
+ if (!settings.fallback || settings.fallback === "disabled") {
51693
+ return {
51694
+ enabled: false,
51695
+ message: "Fallback is disabled. UR-AGENT will not silently switch providers. Optional: ur config set provider.fallback ollama"
51696
+ };
51697
+ }
51698
+ if (settings.fallback === active) {
51699
+ return {
51700
+ enabled: false,
51701
+ message: "Fallback points at the selected provider and will not be used."
51702
+ };
51703
+ }
51704
+ return {
51705
+ enabled: true,
51706
+ provider: settings.fallback,
51707
+ message: `Fallback is configured as ${settings.fallback}, but UR-AGENT will ask before using it.`
51708
+ };
51709
+ }
51710
+ async function doctorProvider(provider, options = {}) {
51711
+ const allSettings = options.settings ?? getInitialSettings();
51712
+ const providerSettings = getActiveProviderSettings(allSettings);
51713
+ const active = provider ?? providerSettings.active ?? DEFAULT_PROVIDER_ID;
51714
+ const definition = getProviderDefinition(active);
51715
+ const settingsForProvider = {
51716
+ ...providerSettings,
51717
+ active
51718
+ };
51719
+ const result = {
51720
+ provider: active,
51721
+ displayName: definition.displayName,
51722
+ accessType: definition.accessType,
51723
+ authMode: definition.authMode,
51724
+ selected: active === providerSettings.active,
51725
+ ok: true,
51726
+ checks: [
51727
+ {
51728
+ name: "legal_path",
51729
+ status: "pass",
51730
+ message: definition.legalPath
51731
+ }
51732
+ ]
51733
+ };
51734
+ if (definition.accessType === "subscription") {
51735
+ await checkSubscriptionProvider(definition, settingsForProvider, options.adapters ?? {}, result);
51736
+ } else if (definition.accessType === "api") {
51737
+ await checkApiProvider(definition, settingsForProvider, options.adapters ?? {}, result);
51738
+ } else if (definition.accessType === "local" || definition.accessType === "server") {
51739
+ await checkEndpoint(definition, settingsForProvider, options.adapters ?? {}, result);
51740
+ }
51741
+ result.fallback = fallbackResult(providerSettings, active, result.ok);
51742
+ return result;
51743
+ }
51744
+ async function doctorActiveProvider(options = {}) {
51745
+ const settings = options.settings ?? getInitialSettings();
51746
+ const active = getActiveProviderSettings(settings).active ?? DEFAULT_PROVIDER_ID;
51747
+ return doctorProvider(active, options);
51748
+ }
51749
+ function getConnectionStatusFromDoctorResult(result) {
51750
+ if (result.ok) {
51751
+ return "connected";
51752
+ }
51753
+ if (result.failureReason?.includes("CLI missing") || result.failureReason?.includes("not found")) {
51754
+ return "missing";
51755
+ }
51756
+ if (result.failureReason?.includes("not logged in") || result.failureReason?.includes("not authenticated") || result.failureReason?.includes("API key missing") || result.failureReason?.includes("endpoint") || result.failureReason?.includes("HTTP")) {
51757
+ return "unavailable";
51758
+ }
51759
+ return "unknown";
51760
+ }
51761
+ function formatProviderStatusLabel(status, provider, checks3) {
51762
+ switch (status) {
51763
+ case "connected":
51764
+ if (provider.credentialType === "api-key" && provider.envKey) {
51765
+ return `${provider.envKey} found`;
51766
+ }
51767
+ if (provider.id === "ollama") {
51768
+ return "localhost reachable";
51769
+ }
51770
+ if (provider.credentialType === "openai-compatible-endpoint") {
51771
+ return "OpenAI-compatible endpoint reachable";
51772
+ }
51773
+ if (provider.credentialType === "cli-login") {
51774
+ return "subscription login connected";
51775
+ }
51776
+ return "connected";
51777
+ case "missing":
51778
+ if (provider.commandCandidates) {
51779
+ return `CLI not found (tried: ${provider.commandCandidates.join(", ")})`;
51780
+ }
51781
+ return "missing";
51782
+ case "unavailable": {
51783
+ const failCheck = checks3.find((check3) => check3.status === "fail" || check3.status === "warn");
51784
+ return failCheck?.message ?? "unavailable";
51785
+ }
51786
+ case "unknown":
51787
+ return "status unknown";
51788
+ }
51789
+ }
51790
+ async function getProviderStatus(providerId, options = {}) {
51791
+ const provider = resolveProviderId(providerId);
51792
+ if (!provider) {
51793
+ throw new Error(`Unknown provider "${providerId}". Run: ur provider list`);
51794
+ }
51795
+ const definition = getProviderDefinition(provider);
51796
+ const doctor = await doctorProvider(provider, options);
51797
+ const status = getConnectionStatusFromDoctorResult(doctor);
51798
+ return {
51799
+ provider,
51800
+ displayName: definition.displayName,
51801
+ accessType: definition.accessType,
51802
+ accessTypeLabel: getProviderAccessTypeLabel(definition),
51803
+ credentialType: definition.credentialType,
51804
+ status,
51805
+ label: formatProviderStatusLabel(status, definition, doctor.checks),
51806
+ checks: doctor.checks,
51807
+ doctor
51808
+ };
51809
+ }
51810
+ function authAliasForProvider(provider) {
51811
+ switch (provider) {
51812
+ case "codex-cli":
51813
+ return "chatgpt";
51814
+ case "claude-code-cli":
51815
+ return "claude";
51816
+ case "gemini-cli":
51817
+ return "gemini";
51818
+ case "antigravity-cli":
51819
+ return "antigravity";
51820
+ default:
51821
+ return "provider";
51822
+ }
51823
+ }
51824
+ function providerForAuthAlias(alias) {
51825
+ switch (alias) {
51826
+ case "chatgpt":
51827
+ return "codex-cli";
51828
+ case "claude":
51829
+ return "claude-code-cli";
51830
+ case "gemini":
51831
+ return "gemini-cli";
51832
+ case "antigravity":
51833
+ return "antigravity-cli";
51834
+ default:
51835
+ return null;
51836
+ }
51837
+ }
51838
+ function buildProviderAuthCommand(provider, options = {}) {
51839
+ const definition = getProviderDefinition(provider);
51840
+ const command = definition.commandCandidates?.[0];
51841
+ if (!command)
51842
+ return null;
51843
+ const args = options.deviceAuth && definition.deviceLoginArgs ? definition.deviceLoginArgs : definition.loginArgs;
51844
+ if (!args)
51845
+ return null;
51846
+ if (provider === "gemini-cli") {
51847
+ return {
51848
+ command,
51849
+ args,
51850
+ instructions: "The detected Gemini CLI does not expose a stable non-interactive login subcommand. Launching the official Gemini CLI is the only supported path; complete the Gemini Code Assist login flow if prompted."
51851
+ };
51852
+ }
51853
+ if (provider === "antigravity-cli") {
51854
+ return {
51855
+ command,
51856
+ args,
51857
+ instructions: "UR-AGENT will only launch the official Antigravity CLI. Use its documented login flow where supported; UR-AGENT will not invent flags or reuse browser sessions."
51858
+ };
51859
+ }
51860
+ return {
51861
+ command,
51862
+ args,
51863
+ instructions: `Launching ${definition.legalPath}.`
51864
+ };
51865
+ }
51866
+ async function launchProviderAuth(alias, options = {}) {
51867
+ const provider = providerForAuthAlias(alias);
51868
+ if (!provider) {
51869
+ return { ok: false, message: `Unknown auth provider "${alias}".` };
51870
+ }
51871
+ const authCommand = buildProviderAuthCommand(provider, options);
51872
+ if (!authCommand) {
51873
+ return {
51874
+ ok: false,
51875
+ message: `No official login command is configured for ${provider}.`
51876
+ };
51877
+ }
51878
+ const commandPath = await resolveCommand(getProviderDefinition(provider), {}, {});
51879
+ if (!commandPath) {
51880
+ const commands = getProviderDefinition(provider).commandCandidates?.join(", ") ?? provider;
51881
+ return {
51882
+ ok: false,
51883
+ message: `No official ${getProviderDefinition(provider).displayName} CLI command found. Tried: ${commands}. Install the official CLI first.`
51884
+ };
51885
+ }
51886
+ const printableCommand = commandPath.split(/[\\/]/).pop() ?? authCommand.command;
51887
+ const printable = [printableCommand, ...authCommand.args].join(" ");
51888
+ if (options.dryRun || !process.stdin.isTTY || !process.stdout.isTTY) {
51889
+ return {
51890
+ ok: true,
51891
+ message: `${authCommand.instructions}
51892
+ Run: ${printable}`,
51893
+ command: printable
51894
+ };
51895
+ }
51896
+ await new Promise((resolve8, reject) => {
51897
+ const child = spawn2(commandPath, authCommand.args, {
51898
+ stdio: "inherit",
51899
+ env: process.env
51900
+ });
51901
+ child.on("error", reject);
51902
+ child.on("exit", (code) => {
51903
+ if (code === 0)
51904
+ resolve8();
51905
+ else
51906
+ reject(new Error(`${printable} exited with code ${code ?? 1}`));
51907
+ });
51908
+ });
51909
+ return { ok: true, message: `Completed: ${printable}`, command: printable };
51910
+ }
51911
+ function formatProviderList(json2 = false) {
51912
+ const providers = listProviders().map((provider) => ({
51913
+ id: provider.id,
51914
+ name: provider.displayName,
51915
+ aliases: providerAliasesFor(provider.id),
51916
+ accessType: provider.accessType,
51917
+ accessTypeLabel: getProviderAccessTypeLabel(provider),
51918
+ credentialType: provider.credentialType,
51919
+ modelDiscoveryType: provider.modelDiscoveryType,
51920
+ runtimeBackend: getProviderRuntimeBackend(provider.id),
51921
+ authMode: provider.authMode,
51922
+ accessPath: provider.accessPathLabel,
51923
+ legalPath: provider.legalPath
51924
+ }));
51925
+ if (json2) {
51926
+ return JSON.stringify(providers, null, 2);
51927
+ }
51928
+ return [
51929
+ "Provider | ID | Aliases | Access type | Credential | Model discovery | Runtime backend | Access path",
51930
+ "--- | --- | --- | --- | --- | --- | --- | ---",
51931
+ ...providers.map((provider) => `${provider.name} | ${provider.id} | ${provider.aliases.slice(0, 3).join(", ") || "-"} | ${provider.accessTypeLabel} | ${provider.credentialType} | ${provider.modelDiscoveryType} | ${provider.runtimeBackend} | ${provider.accessPath}`)
51932
+ ].join(`
51933
+ `);
51934
+ }
51935
+ function formatProviderDoctor(result, json2 = false) {
51936
+ if (json2) {
51937
+ return JSON.stringify(result, null, 2);
51938
+ }
51939
+ const lines = [
51940
+ `Provider: ${result.displayName} (${result.provider})`,
51941
+ `Access: ${getProviderAccessTypeLabel(getProviderDefinition(result.provider))}`,
51942
+ `Credential: ${getProviderDefinition(result.provider).credentialType}`,
51943
+ `Runtime backend: ${getProviderRuntimeBackend(result.provider)}`,
51944
+ `Auth: ${authModeLabel(result.authMode)}`,
51945
+ `Status: ${result.ok ? "ready" : "not ready"}`
51946
+ ];
51947
+ for (const check3 of result.checks) {
51948
+ lines.push(`- ${check3.status.toUpperCase()} ${check3.name}: ${check3.message}`);
51949
+ }
51950
+ if (result.failureReason) {
51951
+ lines.push(`Failure reason: ${result.failureReason}`);
51952
+ }
51953
+ if (result.suggestedFix) {
51954
+ lines.push(`Suggested fix: ${result.suggestedFix}`);
51955
+ }
51956
+ if (result.fallback) {
51957
+ lines.push(`Fallback: ${result.fallback.message}`);
51958
+ }
51959
+ return lines.join(`
51960
+ `);
51961
+ }
51962
+ function formatProviderStatus(result, json2 = false) {
51963
+ if (json2) {
51964
+ return JSON.stringify(result, null, 2);
51965
+ }
51966
+ const failure = result.failureReason ? `
51967
+ Failure reason: ${result.failureReason}` : "";
51968
+ const fix = result.suggestedFix ? `
51969
+ Suggested fix: ${result.suggestedFix}` : "";
51970
+ const definition = getProviderDefinition(result.provider);
51971
+ const settings = getActiveProviderSettings(getInitialSettings());
51972
+ const model = settings.model ? `
51973
+ Active model: ${settings.model}` : "";
51974
+ return `Selected provider: ${result.displayName} (${result.provider})
51975
+ Access type: ${getProviderAccessTypeLabel(definition)}
51976
+ Credential: ${definition.credentialType}
51977
+ Runtime backend: ${getProviderRuntimeBackend(result.provider)}${model}
51978
+ Auth mode: ${authModeLabel(result.authMode)}
51979
+ Ready: ${result.ok ? "yes" : "no"}${failure}${fix}`;
51980
+ }
51981
+ function clearProviderModelCacheForTests() {
51982
+ cachedModelsByProvider.clear();
51983
+ }
51984
+ function providerBaseUrl(provider, definition, settings) {
51985
+ const providerSettings = getActiveProviderSettings(settings);
51986
+ if (providerSettings.baseUrl) {
51987
+ return providerSettings.baseUrl;
51988
+ }
51989
+ if (provider === "ollama") {
51990
+ return getOllamaBaseUrl(process.env, settings);
51991
+ }
51992
+ return definition.defaultBaseUrl;
51993
+ }
51994
+ function parseOpenAICompatibleModelNames(value) {
51995
+ if (!value || typeof value !== "object") {
51996
+ return [];
51997
+ }
51998
+ const data = value.data ?? value.models;
51999
+ if (!Array.isArray(data)) {
52000
+ return [];
52001
+ }
52002
+ const names = data.flatMap((model) => {
52003
+ if (typeof model === "string") {
52004
+ const trimmed2 = model.trim();
52005
+ return trimmed2 ? [trimmed2] : [];
52006
+ }
52007
+ if (!model || typeof model !== "object") {
52008
+ return [];
52009
+ }
52010
+ const entry = model;
52011
+ const name = entry.id ?? entry.name ?? entry.model;
52012
+ if (typeof name !== "string") {
52013
+ return [];
52014
+ }
52015
+ const trimmed = name.trim();
52016
+ return trimmed ? [trimmed] : [];
52017
+ });
52018
+ return [...new Set(names)].sort((a2, b) => a2.localeCompare(b));
52019
+ }
52020
+ function parseOllamaModelNamesFromTags(value) {
52021
+ if (!value || typeof value !== "object" || !("models" in value)) {
52022
+ return [];
52023
+ }
52024
+ const models = value.models;
52025
+ if (!Array.isArray(models)) {
52026
+ return [];
52027
+ }
52028
+ const names = models.flatMap((model) => {
52029
+ if (!model || typeof model !== "object") {
52030
+ return [];
52031
+ }
52032
+ const entry = model;
52033
+ const name = entry.name ?? entry.model;
52034
+ if (typeof name !== "string") {
52035
+ return [];
52036
+ }
52037
+ const trimmed = name.trim();
52038
+ return trimmed ? [trimmed] : [];
52039
+ });
52040
+ return [...new Set(names)].sort((a2, b) => a2.localeCompare(b));
52041
+ }
52042
+ function modelDefinitionsFromNames(provider, names, source) {
52043
+ const providerName = getProviderDefinition(provider).displayName;
52044
+ return names.map((name) => ({
52045
+ id: name,
52046
+ displayName: name,
52047
+ description: source === "cache" ? `Cached ${providerName} model` : `Discovered from ${providerName}`
52048
+ }));
52049
+ }
52050
+ function getCachedProviderModels(provider) {
52051
+ return cachedModelsByProvider.get(provider) ?? [];
52052
+ }
52053
+ function cacheProviderModelsForProvider(providerId, models) {
52054
+ const provider = resolveProviderId(providerId);
52055
+ if (!provider) {
52056
+ return;
52057
+ }
52058
+ const definitions = typeof models[0] === "string" ? modelDefinitionsFromNames(provider, models, "cache") : models;
52059
+ if (definitions.length > 0) {
52060
+ cachedModelsByProvider.set(provider, definitions);
52061
+ }
52062
+ }
52063
+ function staticModelsForProvider(provider) {
52064
+ return (PROVIDER_MODELS[provider] ?? []).filter((model) => !model.isDynamic);
52065
+ }
52066
+ async function discoverLiveModelsForProvider(provider, options = {}) {
52067
+ const definition = getProviderDefinition(provider);
52068
+ if (!definition.endpointKind) {
52069
+ return [];
52070
+ }
52071
+ const settings = options.settings ?? getInitialSettings();
52072
+ const baseUrl = providerBaseUrl(provider, definition, settings);
52073
+ if (!baseUrl) {
52074
+ throw new Error(`No base_url configured for provider "${provider}".`);
52075
+ }
52076
+ const url3 = endpointUrl(baseUrl, definition.endpointKind);
52077
+ const env4 = options.adapters?.env ?? process.env;
52078
+ const response = await (options.adapters?.fetch ?? fetch)(url3, {
52079
+ method: "GET",
52080
+ signal: options.signal,
52081
+ headers: definition.accessType === "api" && definition.envKey && env4[definition.envKey] ? { Authorization: `Bearer ${env4[definition.envKey]}` } : undefined
52082
+ });
52083
+ if (!response.ok) {
52084
+ throw new Error(`${url3} returned HTTP ${response.status}.`);
52085
+ }
52086
+ const body = await response.json();
52087
+ const names = definition.endpointKind === "ollama" ? parseOllamaModelNamesFromTags(body) : parseOpenAICompatibleModelNames(body);
52088
+ return modelDefinitionsFromNames(provider, names, "live");
52089
+ }
52090
+ async function listModelsForProviderWithSource(providerId, options = {}) {
52091
+ const provider = resolveProviderId(providerId);
52092
+ if (!provider) {
52093
+ return {
52094
+ provider: "ollama",
52095
+ models: [],
52096
+ source: "static",
52097
+ warning: `Unknown provider "${providerId}". Run: ur provider list`
52098
+ };
52099
+ }
52100
+ const definition = getProviderDefinition(provider);
52101
+ if (definition.modelDiscoveryType === "static") {
52102
+ return {
52103
+ provider,
52104
+ models: staticModelsForProvider(provider),
52105
+ source: "static"
52106
+ };
52107
+ }
52108
+ try {
52109
+ const liveModels = await discoverLiveModelsForProvider(provider, options);
52110
+ if (liveModels.length > 0) {
52111
+ cachedModelsByProvider.set(provider, liveModels);
52112
+ return {
52113
+ provider,
52114
+ models: liveModels,
52115
+ source: "live"
52116
+ };
52117
+ }
52118
+ const cachedModels = getCachedProviderModels(provider);
52119
+ if (cachedModels.length > 0) {
52120
+ return {
52121
+ provider,
52122
+ models: cachedModels,
52123
+ source: "cache",
52124
+ warning: `Live model discovery for "${provider}" returned no models. Showing cached ${provider} models only.`
52125
+ };
52126
+ }
52127
+ const staticModels = staticModelsForProvider(provider);
52128
+ return {
52129
+ provider,
52130
+ models: staticModels,
52131
+ source: staticModels.length > 0 ? "static" : "live",
52132
+ warning: `Live model discovery for "${provider}" returned no models.`
52133
+ };
52134
+ } catch (error40) {
52135
+ const cachedModels = getCachedProviderModels(provider);
52136
+ if (cachedModels.length > 0) {
52137
+ return {
52138
+ provider,
52139
+ models: cachedModels,
52140
+ source: "cache",
52141
+ warning: `Live model discovery for "${provider}" failed: ${error40 instanceof Error ? error40.message : String(error40)}. Showing cached ${provider} models only.`
52142
+ };
52143
+ }
52144
+ const staticModels = staticModelsForProvider(provider);
52145
+ return {
52146
+ provider,
52147
+ models: staticModels,
52148
+ source: staticModels.length > 0 ? "static" : "live",
52149
+ warning: `Live model discovery for "${provider}" failed: ${error40 instanceof Error ? error40.message : String(error40)}.`
52150
+ };
52151
+ }
52152
+ }
52153
+ function listModelsForProvider(providerId) {
52154
+ const provider = resolveProviderId(providerId);
52155
+ if (!provider) {
52156
+ return [];
52157
+ }
52158
+ return PROVIDER_MODELS[provider] ?? [];
52159
+ }
52160
+ function isModelSupportedByProvider(providerId, modelId) {
52161
+ return validateProviderModelPair(providerId, modelId).valid;
52162
+ }
52163
+ function getDefaultModelForProvider(providerId) {
52164
+ const provider = resolveProviderId(providerId);
52165
+ if (!provider) {
52166
+ return;
52167
+ }
52168
+ const models = PROVIDER_MODELS[provider];
52169
+ if (!models) {
52170
+ return;
52171
+ }
52172
+ const defaultModel = models.find((m) => m.isDefault && !m.isDynamic) ?? models.find((m) => !m.isDynamic);
52173
+ return defaultModel?.id;
52174
+ }
52175
+ function getValidModelIdsForProvider(providerId) {
52176
+ const provider = resolveProviderId(providerId);
52177
+ if (!provider) {
52178
+ return [];
52179
+ }
52180
+ const cached2 = getCachedProviderModels(provider);
52181
+ if (cached2.length > 0) {
52182
+ return cached2.map((model) => model.id);
52183
+ }
52184
+ return staticModelsForProvider(provider).map((model) => model.id);
52185
+ }
52186
+ function formatInvalidProviderModelMessage(providerId, modelId, validModels, suggestedModel) {
52187
+ const provider = resolveProviderId(providerId) ?? String(providerId);
52188
+ const validList = validModels.length > 0 ? validModels.join(", ") : "(no models discovered)";
52189
+ const suggested = suggestedModel ?? validModels[0] ?? "<valid-model>";
52190
+ return `Model "${modelId}" is not available for provider "${provider}". Valid models for ${provider}: ${validList}. Run /model and choose a model from ${provider}, or run: ur config set model ${suggested}`;
52191
+ }
52192
+ function validateProviderModelPair(providerId, modelId, options = {}) {
52193
+ const provider = resolveProviderId(providerId);
52194
+ if (!provider) {
52195
+ return {
52196
+ valid: false,
52197
+ error: `Unknown provider "${providerId}". Run: ur provider list`,
52198
+ validModels: []
52199
+ };
52200
+ }
52201
+ const models = PROVIDER_MODELS[provider];
52202
+ if (!models) {
52203
+ return {
52204
+ valid: false,
52205
+ error: `No models defined for provider "${provider}".`,
52206
+ validModels: []
52207
+ };
52208
+ }
52209
+ const suppliedModels = (options.availableModels ?? []).map((model) => typeof model === "string" ? model : model.id);
52210
+ const cachedModels = getCachedProviderModels(provider).map((model) => model.id);
52211
+ const staticModelIds = staticModelsForProvider(provider).map((model) => model.id);
52212
+ const hasDynamicModels = models.some((model) => model.isDynamic);
52213
+ const validModelIds = suppliedModels.length > 0 ? suppliedModels : hasDynamicModels ? cachedModels.length > 0 ? cachedModels : staticModelIds : Array.from(new Set([...staticModelIds, ...cachedModels]));
52214
+ if (validModelIds.includes(modelId)) {
52215
+ return { valid: true };
52216
+ }
52217
+ if (hasDynamicModels && options.allowUncachedDynamic && validModelIds.length === 0) {
52218
+ return { valid: true };
52219
+ }
52220
+ const defaultModel = getDefaultModelForProvider(provider);
52221
+ return {
52222
+ valid: false,
52223
+ error: formatInvalidProviderModelMessage(provider, modelId, validModelIds, defaultModel),
52224
+ validModels: validModelIds,
52225
+ suggestedModel: defaultModel
52226
+ };
52227
+ }
52228
+ function setProviderModel(providerId, modelId, options = {}) {
52229
+ const provider = resolveProviderId(providerId);
52230
+ if (!provider) {
52231
+ return {
52232
+ ok: false,
52233
+ message: `Unknown provider "${providerId}". Run: ur provider list`
52234
+ };
52235
+ }
52236
+ const validation = validateProviderModelPair(provider, modelId, {
52237
+ availableModels: options.availableModels
52238
+ });
52239
+ if (validation.valid === false) {
52240
+ return {
52241
+ ok: false,
52242
+ message: validation.error
52243
+ };
52244
+ }
52245
+ const result = updateSettingsForSource("userSettings", {
52246
+ provider: {
52247
+ active: provider,
52248
+ model: modelId
52249
+ },
52250
+ model: modelId
52251
+ });
52252
+ if (result.error) {
52253
+ return {
52254
+ ok: false,
52255
+ message: `Failed to write UR-AGENT settings: ${result.error.message}`
52256
+ };
52257
+ }
52258
+ return {
52259
+ ok: true,
52260
+ message: `Selected provider ${provider} (${getProviderAccessTypeLabel(getProviderDefinition(provider))}) with model ${modelId} (${options.modelSource ?? "static"}).`,
52261
+ provider,
52262
+ model: modelId,
52263
+ modelSource: options.modelSource ?? "static"
52264
+ };
52265
+ }
52266
+ var PROVIDER_IDS, DEFAULT_PROVIDER_ID = "ollama", LOCALHOST_RE, PROVIDERS, PROVIDER_ALIAS_ENTRIES, PROVIDER_ALIASES, PROVIDER_FAMILIES, PROVIDER_MODELS, cachedModelsByProvider, validateProviderModelCompatibility;
52267
+ var init_providerRegistry = __esm(() => {
52268
+ init_execFileNoThrow();
52269
+ init_ollamaConfig();
52270
+ init_settings2();
52271
+ init_which();
52272
+ PROVIDER_IDS = [
52273
+ "codex-cli",
52274
+ "claude-code-cli",
52275
+ "gemini-cli",
52276
+ "antigravity-cli",
52277
+ "openai-api",
52278
+ "anthropic-api",
52279
+ "gemini-api",
52280
+ "openrouter",
52281
+ "openai-compatible",
52282
+ "ollama",
52283
+ "lmstudio",
52284
+ "llama.cpp",
52285
+ "vllm"
52286
+ ];
52287
+ LOCALHOST_RE = /^(https?:\/\/)?(localhost|127\.0\.0\.1|\[::1\]|::1)(:\d+)?(\/|$)/i;
52288
+ PROVIDERS = {
52289
+ "codex-cli": {
52290
+ id: "codex-cli",
52291
+ displayName: "Codex CLI",
52292
+ statusBarName: "Codex CLI",
52293
+ accessType: "subscription",
52294
+ credentialType: "cli-login",
52295
+ modelDiscoveryType: "static",
52296
+ statusCheck: "cli-login",
52297
+ listModels: "static",
52298
+ validateModel: "static-list",
52299
+ authMode: "subscription",
52300
+ legalPath: "official Codex CLI login",
52301
+ accessPathLabel: "subscription login via official Codex CLI",
52302
+ commandCandidates: ["codex"],
52303
+ versionArgs: ["--version"],
52304
+ statusArgs: ["login", "status"],
52305
+ loginArgs: ["login"],
52306
+ deviceLoginArgs: ["login", "--device-auth"]
52307
+ },
52308
+ "claude-code-cli": {
52309
+ id: "claude-code-cli",
52310
+ displayName: "Claude Code",
52311
+ statusBarName: "Claude Code",
52312
+ accessType: "subscription",
52313
+ credentialType: "cli-login",
52314
+ modelDiscoveryType: "static",
52315
+ statusCheck: "cli-login",
52316
+ listModels: "static",
52317
+ validateModel: "static-list",
52318
+ authMode: "subscription",
52319
+ legalPath: "official Claude Code CLI login",
52320
+ accessPathLabel: "subscription login via official Claude Code CLI",
52321
+ commandCandidates: ["claude"],
52322
+ versionArgs: ["--version"],
52323
+ statusArgs: ["auth", "status"],
52324
+ loginArgs: ["auth", "login"]
52325
+ },
52326
+ "gemini-cli": {
52327
+ id: "gemini-cli",
52328
+ displayName: "Gemini CLI",
52329
+ statusBarName: "Gemini CLI",
52330
+ accessType: "subscription",
52331
+ credentialType: "cli-login",
52332
+ modelDiscoveryType: "static",
52333
+ statusCheck: "cli-login",
52334
+ listModels: "static",
52335
+ validateModel: "static-list",
52336
+ authMode: "enterprise-login",
52337
+ legalPath: "official Gemini Code Assist login",
52338
+ accessPathLabel: "subscription login via official Gemini CLI",
52339
+ commandCandidates: ["gemini"],
52340
+ versionArgs: ["--version"],
52341
+ loginArgs: [],
52342
+ unsupportedPersonalAccountMessage: "Personal Google account login is not enabled by UR-AGENT. Use an official Gemini Code Assist Standard/Enterprise path if your Gemini CLI supports it."
52343
+ },
52344
+ "antigravity-cli": {
52345
+ id: "antigravity-cli",
52346
+ displayName: "Antigravity",
52347
+ statusBarName: "Antigravity",
52348
+ accessType: "subscription",
52349
+ credentialType: "cli-login",
52350
+ modelDiscoveryType: "static",
52351
+ statusCheck: "cli-login",
52352
+ listModels: "static",
52353
+ validateModel: "static-list",
52354
+ authMode: "personal-login",
52355
+ legalPath: "official Antigravity CLI login, where supported",
52356
+ accessPathLabel: "subscription login via official Antigravity CLI",
52357
+ commandCandidates: ["agy", "antigravity", "google-antigravity", "ag"],
52358
+ versionArgs: ["--version"],
52359
+ loginArgs: []
52360
+ },
52361
+ "openai-api": {
52362
+ id: "openai-api",
52363
+ displayName: "OpenAI API",
52364
+ statusBarName: "OpenAI",
52365
+ accessType: "api",
52366
+ credentialType: "api-key",
52367
+ modelDiscoveryType: "static",
52368
+ statusCheck: "api-key",
52369
+ listModels: "static",
52370
+ validateModel: "static-list",
52371
+ authMode: "api",
52372
+ legalPath: "OPENAI_API_KEY",
52373
+ accessPathLabel: "API key from OPENAI_API_KEY",
52374
+ envKey: "OPENAI_API_KEY"
52375
+ },
52376
+ "anthropic-api": {
52377
+ id: "anthropic-api",
52378
+ displayName: "Claude API",
52379
+ statusBarName: "Claude API",
52380
+ accessType: "api",
52381
+ credentialType: "api-key",
52382
+ modelDiscoveryType: "static",
52383
+ statusCheck: "api-key",
52384
+ listModels: "static",
52385
+ validateModel: "static-list",
52386
+ authMode: "api",
52387
+ legalPath: "ANTHROPIC_API_KEY",
52388
+ accessPathLabel: "API key from ANTHROPIC_API_KEY",
52389
+ envKey: "ANTHROPIC_API_KEY"
52390
+ },
52391
+ "gemini-api": {
52392
+ id: "gemini-api",
52393
+ displayName: "Gemini API",
52394
+ statusBarName: "Gemini API",
52395
+ accessType: "api",
52396
+ credentialType: "api-key",
52397
+ modelDiscoveryType: "static",
52398
+ statusCheck: "api-key",
52399
+ listModels: "static",
52400
+ validateModel: "static-list",
52401
+ authMode: "api",
52402
+ legalPath: "GEMINI_API_KEY",
52403
+ accessPathLabel: "API key from GEMINI_API_KEY",
52404
+ envKey: "GEMINI_API_KEY"
52405
+ },
52406
+ openrouter: {
52407
+ id: "openrouter",
52408
+ displayName: "OpenRouter",
52409
+ statusBarName: "OpenRouter",
52410
+ accessType: "api",
52411
+ credentialType: "api-key",
52412
+ modelDiscoveryType: "static",
52413
+ statusCheck: "api-key",
52414
+ listModels: "static",
52415
+ validateModel: "static-list",
52416
+ authMode: "api",
52417
+ legalPath: "OPENROUTER_API_KEY",
52418
+ accessPathLabel: "API key from OPENROUTER_API_KEY",
52419
+ envKey: "OPENROUTER_API_KEY"
52420
+ },
52421
+ "openai-compatible": {
52422
+ id: "openai-compatible",
52423
+ displayName: "OpenAI-compatible",
52424
+ statusBarName: "OpenAI-compatible",
52425
+ accessType: "api",
52426
+ accessTypeLabel: "server/api",
52427
+ credentialType: "openai-compatible-endpoint",
52428
+ modelDiscoveryType: "live",
52429
+ statusCheck: "endpoint",
52430
+ listModels: "openai-compatible-models",
52431
+ validateModel: "discovered-list",
52432
+ authMode: "api",
52433
+ legalPath: "user-selected OpenAI-compatible base URL with API key only when required by that endpoint",
52434
+ accessPathLabel: "OpenAI-compatible endpoint",
52435
+ envKey: "OPENAI_API_KEY",
52436
+ endpointKind: "openai-compatible"
52437
+ },
52438
+ ollama: {
52439
+ id: "ollama",
52440
+ displayName: "Ollama",
52441
+ statusBarName: "Ollama",
52442
+ accessType: "local",
52443
+ credentialType: "local-runtime",
52444
+ modelDiscoveryType: "live",
52445
+ statusCheck: "endpoint",
52446
+ listModels: "ollama-tags",
52447
+ validateModel: "discovered-list",
52448
+ authMode: "local",
52449
+ legalPath: "localhost Ollama runtime",
52450
+ accessPathLabel: "local Ollama runtime",
52451
+ defaultBaseUrl: "http://localhost:11434",
52452
+ endpointKind: "ollama"
52453
+ },
52454
+ lmstudio: {
52455
+ id: "lmstudio",
52456
+ displayName: "LM Studio",
52457
+ statusBarName: "LM Studio",
52458
+ accessType: "server",
52459
+ accessTypeLabel: "local/server",
52460
+ credentialType: "openai-compatible-endpoint",
52461
+ modelDiscoveryType: "live",
52462
+ statusCheck: "endpoint",
52463
+ listModels: "openai-compatible-models",
52464
+ validateModel: "discovered-list",
52465
+ authMode: "local",
52466
+ legalPath: "local OpenAI-compatible server",
52467
+ accessPathLabel: "local OpenAI-compatible endpoint",
52468
+ defaultBaseUrl: "http://localhost:1234/v1",
52469
+ endpointKind: "openai-compatible"
52470
+ },
52471
+ "llama.cpp": {
52472
+ id: "llama.cpp",
52473
+ displayName: "llama.cpp",
52474
+ statusBarName: "llama.cpp",
52475
+ accessType: "server",
52476
+ accessTypeLabel: "local/server",
52477
+ credentialType: "openai-compatible-endpoint",
52478
+ modelDiscoveryType: "live",
52479
+ statusCheck: "endpoint",
52480
+ listModels: "openai-compatible-models",
52481
+ validateModel: "discovered-list",
52482
+ authMode: "local",
52483
+ legalPath: "local OpenAI-compatible server",
52484
+ accessPathLabel: "local OpenAI-compatible endpoint",
52485
+ defaultBaseUrl: "http://localhost:8080/v1",
52486
+ endpointKind: "openai-compatible"
52487
+ },
52488
+ vllm: {
52489
+ id: "vllm",
52490
+ displayName: "vLLM",
52491
+ statusBarName: "vLLM",
52492
+ accessType: "server",
52493
+ accessTypeLabel: "local/server",
52494
+ credentialType: "openai-compatible-endpoint",
52495
+ modelDiscoveryType: "live",
52496
+ statusCheck: "endpoint",
52497
+ listModels: "openai-compatible-models",
52498
+ validateModel: "discovered-list",
52499
+ authMode: "local",
52500
+ legalPath: "OpenAI-compatible server",
52501
+ accessPathLabel: "OpenAI-compatible endpoint runtime",
52502
+ defaultBaseUrl: "http://localhost:8000/v1",
52503
+ endpointKind: "openai-compatible"
52504
+ }
52505
+ };
52506
+ PROVIDER_ALIAS_ENTRIES = [
52507
+ {
52508
+ canonical: "codex-cli",
52509
+ aliases: ["chatgpt", "codex", "codex cli", "openai codex", "chatgpt codex"]
52510
+ },
52511
+ {
52512
+ canonical: "claude-code-cli",
52513
+ aliases: ["claude", "claude code", "claude cli", "anthropic claude"]
52514
+ },
52515
+ {
52516
+ canonical: "gemini-cli",
52517
+ aliases: ["gemini", "gemini cli", "gemini code assist", "google gemini cli"]
52518
+ },
52519
+ {
52520
+ canonical: "antigravity-cli",
52521
+ aliases: ["antigravity", "antigravity cli", "agy", "ag", "google antigravity"]
52522
+ },
52523
+ {
52524
+ canonical: "openai-api",
52525
+ aliases: ["openai", "openai api"]
52526
+ },
52527
+ {
52528
+ canonical: "anthropic-api",
52529
+ aliases: ["anthropic", "anthropic claude api", "claude api"]
52530
+ },
52531
+ {
52532
+ canonical: "gemini-api",
52533
+ aliases: ["gemini api", "google gemini api"]
52534
+ },
52535
+ {
52536
+ canonical: "openrouter",
52537
+ aliases: ["openrouter api"]
52538
+ },
52539
+ {
52540
+ canonical: "openai-compatible",
52541
+ aliases: ["compatible", "openai compatible", "openai compatible api"]
52542
+ },
52543
+ {
52544
+ canonical: "ollama",
52545
+ aliases: ["ollama local"]
52546
+ },
52547
+ {
52548
+ canonical: "lmstudio",
52549
+ aliases: ["lm studio", "lm-studio"]
52550
+ },
52551
+ {
52552
+ canonical: "llama.cpp",
52553
+ aliases: ["llama cpp", "llamacpp", "llama-cpp"]
52554
+ },
52555
+ {
52556
+ canonical: "vllm",
52557
+ aliases: ["vllm server"]
52558
+ }
52559
+ ];
52560
+ PROVIDER_ALIASES = Object.fromEntries(PROVIDER_ALIAS_ENTRIES.flatMap((entry) => [
52561
+ [normalizeProviderInput(entry.canonical), entry.canonical],
52562
+ [entry.canonical, entry.canonical],
52563
+ ...entry.aliases.map((alias) => [normalizeProviderInput(alias), entry.canonical])
52564
+ ]));
52565
+ PROVIDER_FAMILIES = {
52566
+ "anthropic-api": "anthropic",
52567
+ "claude-code-cli": "anthropic",
52568
+ "openai-api": "openai",
52569
+ "codex-cli": "openai",
52570
+ "gemini-api": "google",
52571
+ "gemini-cli": "google",
52572
+ "antigravity-cli": "google",
52573
+ openrouter: "openai-compatible",
52574
+ "openai-compatible": "openai-compatible",
52575
+ lmstudio: "openai-compatible",
52576
+ "llama.cpp": "openai-compatible",
52577
+ vllm: "openai-compatible",
52578
+ ollama: "ollama"
52579
+ };
52580
+ PROVIDER_MODELS = {
52581
+ "codex-cli": [
52582
+ { id: "codex/gpt-5.5", displayName: "GPT-5.5 (Codex CLI)", description: "Subscription model through official Codex CLI login", isDefault: true },
52583
+ { id: "codex/gpt-5.4", displayName: "GPT-5.4 (Codex CLI)", description: "Subscription model through official Codex CLI login" },
52584
+ { id: "codex/gpt-5.4-mini", displayName: "GPT-5.4 Mini (Codex CLI)", description: "Fast subscription model through official Codex CLI login" },
52585
+ { id: "codex/gpt-4o", displayName: "GPT-4o (Codex CLI)", description: "Subscription model through official Codex CLI login" },
52586
+ { id: "codex/gpt-4o-mini", displayName: "GPT-4o Mini (Codex CLI)", description: "Fast subscription model through official Codex CLI login" },
52587
+ { id: "codex/o1", displayName: "o1 (Codex CLI)", description: "Reasoning model through official Codex CLI login" },
52588
+ { id: "codex/o3-mini", displayName: "o3-mini (Codex CLI)", description: "Fast reasoning model through official Codex CLI login" }
52589
+ ],
52590
+ "claude-code-cli": [
52591
+ { id: "claude-code/sonnet-5", displayName: "Claude Sonnet 5 (Claude Code)", description: "Subscription model through official Claude Code login", isDefault: true },
52592
+ { id: "claude-code/opus-4-8", displayName: "Claude Opus 4.8 (Claude Code)", description: "Subscription model through official Claude Code login" },
52593
+ { id: "claude-code/opus-4-7", displayName: "Claude Opus 4.7 (Claude Code)", description: "Subscription model through official Claude Code login" },
52594
+ { id: "claude-code/opus-4-6", displayName: "Claude Opus 4.6 (Claude Code)", description: "Subscription model through official Claude Code login" },
52595
+ { id: "claude-code/opus-4-5", displayName: "Claude Opus 4.5 (Claude Code)", description: "Subscription model through official Claude Code login" },
52596
+ { id: "claude-code/sonnet-4-6", displayName: "Claude Sonnet 4.6 (Claude Code)", description: "Subscription model through official Claude Code login" },
52597
+ { id: "claude-code/sonnet-4-5", displayName: "Claude Sonnet 4.5 (Claude Code)", description: "Subscription model through official Claude Code login" },
52598
+ { id: "claude-code/haiku-4-5", displayName: "Claude Haiku 4.5 (Claude Code)", description: "Subscription model through official Claude Code login" }
52599
+ ],
52600
+ "gemini-cli": [
52601
+ { id: "gemini-cli/gemini-3.5-flash", displayName: "Gemini 3.5 Flash (Gemini CLI)", description: "Subscription model through official Gemini CLI login", isDefault: true },
52602
+ { id: "gemini-cli/gemini-3.1-pro", displayName: "Gemini 3.1 Pro (Gemini CLI)", description: "Subscription model through official Gemini CLI login" },
52603
+ { id: "gemini-cli/gemini-3.1-flash-lite", displayName: "Gemini 3.1 Flash Lite (Gemini CLI)", description: "Subscription model through official Gemini CLI login" },
52604
+ { id: "gemini-cli/gemini-2.5-pro", displayName: "Gemini 2.5 Pro (Gemini CLI)", description: "Subscription model through official Gemini CLI login" },
52605
+ { id: "gemini-cli/gemini-2.5-flash", displayName: "Gemini 2.5 Flash (Gemini CLI)", description: "Subscription model through official Gemini CLI login" },
52606
+ { id: "gemini-cli/gemini-2.5-flash-lite", displayName: "Gemini 2.5 Flash Lite (Gemini CLI)", description: "Subscription model through official Gemini CLI login" }
52607
+ ],
52608
+ "antigravity-cli": [
52609
+ { id: "antigravity/gemini-3.5-flash", displayName: "Gemini 3.5 Flash (Antigravity)", description: "Subscription model through official Antigravity login", isDefault: true },
52610
+ { id: "antigravity/gemini-2.5-pro", displayName: "Gemini 2.5 Pro (Antigravity)", description: "Subscription model through official Antigravity login" },
52611
+ { id: "antigravity/gemini-2.5-flash", displayName: "Gemini 2.5 Flash (Antigravity)", description: "Subscription model through official Antigravity login" }
52612
+ ],
52613
+ "openai-api": [
52614
+ { id: "gpt-5.5", displayName: "GPT-5.5", description: "Latest OpenAI model", isDefault: true },
52615
+ { id: "gpt-5.4", displayName: "GPT-5.4", description: "Advanced reasoning and coding" },
52616
+ { id: "gpt-5.4-mini", displayName: "GPT-5.4 Mini", description: "Fast, efficient variant" },
52617
+ { id: "gpt-4o", displayName: "GPT-4o", description: "Previous generation flagship" },
52618
+ { id: "gpt-4o-mini", displayName: "GPT-4o Mini", description: "Fast GPT-4o variant" },
52619
+ { id: "o1", displayName: "o1", description: "Deep reasoning model" },
52620
+ { id: "o3-mini", displayName: "o3-mini", description: "Fast reasoning model" }
52621
+ ],
52622
+ "anthropic-api": [
52623
+ { id: "claude-sonnet-5", displayName: "Claude Sonnet 5", description: "Balanced performance and speed", isDefault: true },
52624
+ { id: "claude-opus-4-8", displayName: "Claude Opus 4.8", description: "Most powerful Claude model" },
52625
+ { id: "claude-opus-4-7", displayName: "Claude Opus 4.7", description: "High-end reasoning" },
52626
+ { id: "claude-opus-4-6", displayName: "Claude Opus 4.6", description: "Advanced problem solving" },
52627
+ { id: "claude-opus-4-5", displayName: "Claude Opus 4.5", description: "Previous Opus generation" },
52628
+ { id: "claude-sonnet-4-6", displayName: "Claude Sonnet 4.6", description: "Fast Sonnet variant" },
52629
+ { id: "claude-sonnet-4-5", displayName: "Claude Sonnet 4.5", description: "Previous Sonnet generation" },
52630
+ { id: "claude-haiku-4-5", displayName: "Claude Haiku 4.5", description: "Fastest Claude model" }
52631
+ ],
52632
+ "gemini-api": [
52633
+ { id: "gemini-3.5-flash", displayName: "Gemini 3.5 Flash", description: "Most intelligent for agentic tasks", isDefault: true },
52634
+ { id: "gemini-3.1-pro", displayName: "Gemini 3.1 Pro", description: "Advanced problem solving (preview)" },
52635
+ { id: "gemini-3.1-flash-lite", displayName: "Gemini 3.1 Flash Lite", description: "Budget-friendly performance" },
52636
+ { id: "gemini-2.5-pro", displayName: "Gemini 2.5 Pro", description: "Complex reasoning and coding" },
52637
+ { id: "gemini-2.5-flash", displayName: "Gemini 2.5 Flash", description: "Low-latency tasks" },
52638
+ { id: "gemini-2.5-flash-lite", displayName: "Gemini 2.5 Flash Lite", description: "Fastest Gemini model" }
52639
+ ],
52640
+ openrouter: [
52641
+ { id: "openai/gpt-5.5", displayName: "GPT-5.5", description: "OpenAI GPT-5.5 via OpenRouter", isDefault: true },
52642
+ { id: "openai/gpt-5.4", displayName: "GPT-5.4", description: "OpenAI GPT-5.4 via OpenRouter" },
52643
+ { id: "openai/gpt-4o", displayName: "GPT-4o", description: "OpenAI GPT-4o via OpenRouter" },
52644
+ { id: "anthropic/claude-sonnet-5", displayName: "Claude Sonnet 5", description: "Anthropic Claude via OpenRouter" },
52645
+ { id: "anthropic/claude-opus-4-8", displayName: "Claude Opus 4.8", description: "Anthropic Claude via OpenRouter" },
52646
+ { id: "google/gemini-3.5-flash", displayName: "Gemini 3.5 Flash", description: "Google Gemini via OpenRouter" },
52647
+ { id: "google/gemini-2.5-pro", displayName: "Gemini 2.5 Pro", description: "Google Gemini via OpenRouter" }
52648
+ ],
52649
+ "openai-compatible": [
52650
+ { id: "custom", displayName: "Custom Model", description: "Model name from provider endpoint", isDynamic: true }
52651
+ ],
52652
+ ollama: [
52653
+ { id: "dynamic", displayName: "Discovered Models", description: "Models discovered from Ollama server", isDynamic: true, isDefault: true }
52654
+ ],
52655
+ lmstudio: [
52656
+ { id: "dynamic", displayName: "Discovered Models", description: "Models discovered from LM Studio server", isDynamic: true, isDefault: true }
52657
+ ],
52658
+ "llama.cpp": [
52659
+ { id: "dynamic", displayName: "Discovered Models", description: "Models discovered from llama.cpp server", isDynamic: true, isDefault: true }
52660
+ ],
52661
+ vllm: [
52662
+ { id: "dynamic", displayName: "Discovered Models", description: "Models discovered from vLLM server", isDynamic: true, isDefault: true }
52663
+ ]
52664
+ };
52665
+ cachedModelsByProvider = new Map;
52666
+ validateProviderModelCompatibility = validateProviderModelPair;
52667
+ });
52668
+
51198
52669
  // src/utils/model/providers.ts
51199
52670
  function getAPIProvider() {
51200
- const activeProvider = getInitialSettings().provider?.active;
51201
- if (!activeProvider || activeProvider === "ollama") {
51202
- return "ollama";
51203
- }
51204
- return "foundry";
52671
+ return getRuntimeProviderId() === "ollama" ? "ollama" : "foundry";
51205
52672
  }
51206
52673
  function getAPIProviderForStatsig() {
51207
52674
  return getAPIProvider();
@@ -51210,7 +52677,7 @@ function isFirstPartyURHQBaseUrl() {
51210
52677
  return true;
51211
52678
  }
51212
52679
  var init_providers = __esm(() => {
51213
- init_settings2();
52680
+ init_providerRegistry();
51214
52681
  });
51215
52682
 
51216
52683
  // src/utils/model/modelStrings.ts
@@ -53024,1452 +54491,6 @@ var init_ollamaModels = __esm(() => {
53024
54491
  cachedOllamaModelNames = [];
53025
54492
  });
53026
54493
 
53027
- // src/services/providers/providerRegistry.ts
53028
- var exports_providerRegistry = {};
53029
- __export(exports_providerRegistry, {
53030
- validateProviderModelPair: () => validateProviderModelPair,
53031
- validateProviderModelCompatibility: () => validateProviderModelCompatibility,
53032
- setSafeProviderConfig: () => setSafeProviderConfig,
53033
- setProviderModel: () => setProviderModel,
53034
- resolveProviderId: () => resolveProviderId,
53035
- providerForAuthAlias: () => providerForAuthAlias,
53036
- providerAliasesFor: () => providerAliasesFor,
53037
- listProviders: () => listProviders,
53038
- listModelsForProviderWithSource: () => listModelsForProviderWithSource,
53039
- listModelsForProvider: () => listModelsForProvider,
53040
- launchProviderAuth: () => launchProviderAuth,
53041
- isProviderId: () => isProviderId,
53042
- isModelSupportedByProvider: () => isModelSupportedByProvider,
53043
- getValidModelIdsForProvider: () => getValidModelIdsForProvider,
53044
- getProviderStatus: () => getProviderStatus,
53045
- getProviderRuntimeInfo: () => getProviderRuntimeInfo,
53046
- getProviderRuntimeBackend: () => getProviderRuntimeBackend,
53047
- getProviderDefinition: () => getProviderDefinition,
53048
- getProviderAccessTypeLabel: () => getProviderAccessTypeLabel,
53049
- getDefaultModelForProvider: () => getDefaultModelForProvider,
53050
- getConnectionStatusFromDoctorResult: () => getConnectionStatusFromDoctorResult,
53051
- getActiveProviderSettings: () => getActiveProviderSettings,
53052
- formatProviderStatusLabel: () => formatProviderStatusLabel,
53053
- formatProviderStatus: () => formatProviderStatus,
53054
- formatProviderList: () => formatProviderList,
53055
- formatProviderDoctor: () => formatProviderDoctor,
53056
- formatInvalidProviderModelMessage: () => formatInvalidProviderModelMessage,
53057
- doctorProvider: () => doctorProvider,
53058
- doctorActiveProvider: () => doctorActiveProvider,
53059
- credentialTypeLabel: () => credentialTypeLabel,
53060
- clearProviderModelCacheForTests: () => clearProviderModelCacheForTests,
53061
- classifyGeminiAccountSupport: () => classifyGeminiAccountSupport,
53062
- cacheProviderModelsForProvider: () => cacheProviderModelsForProvider,
53063
- buildProviderAuthCommand: () => buildProviderAuthCommand,
53064
- authModeLabel: () => authModeLabel,
53065
- authAliasForProvider: () => authAliasForProvider,
53066
- PROVIDER_MODELS: () => PROVIDER_MODELS,
53067
- PROVIDER_IDS: () => PROVIDER_IDS,
53068
- PROVIDERS: () => PROVIDERS
53069
- });
53070
- import { spawn as spawn2 } from "child_process";
53071
- function normalizeProviderInput(value) {
53072
- return value.trim().toLowerCase().replace(/[_\s]+/g, "-");
53073
- }
53074
- function isProviderId(value) {
53075
- return PROVIDER_IDS.includes(value);
53076
- }
53077
- function resolveProviderId(value) {
53078
- const normalized = normalizeProviderInput(value);
53079
- if (isProviderId(normalized)) {
53080
- return normalized;
53081
- }
53082
- return PROVIDER_ALIASES[normalized] ?? null;
53083
- }
53084
- function providerAliasesFor(id) {
53085
- return PROVIDER_ALIAS_ENTRIES.find((entry) => entry.canonical === id)?.aliases ?? [];
53086
- }
53087
- function getProviderDefinition(id) {
53088
- return PROVIDERS[id];
53089
- }
53090
- function getActiveProviderSettings(settings = getInitialSettings()) {
53091
- const configured = settings.provider ?? {};
53092
- const active = configured.active ? resolveProviderId(configured.active) ?? "ollama" : "ollama";
53093
- const fallback = configured.fallback === "disabled" ? "disabled" : configured.fallback ? resolveProviderId(configured.fallback) ?? undefined : undefined;
53094
- return {
53095
- active,
53096
- model: configured.model ?? (configured.active ? undefined : settings.model),
53097
- baseUrl: configured.baseUrl,
53098
- commandPath: configured.commandPath,
53099
- fallback
53100
- };
53101
- }
53102
- function getProviderRuntimeInfo(settings = getInitialSettings()) {
53103
- const providerSettings = getActiveProviderSettings(settings);
53104
- const provider = providerSettings.active ?? "ollama";
53105
- const definition = getProviderDefinition(provider);
53106
- return {
53107
- provider,
53108
- providerLabel: definition.statusBarName,
53109
- accessType: definition.accessType,
53110
- accessTypeLabel: getProviderAccessTypeLabel(definition),
53111
- credentialType: definition.credentialType,
53112
- runtimeBackend: getProviderRuntimeBackend(provider),
53113
- authMode: definition.authMode,
53114
- authLabel: authModeLabel(definition.authMode),
53115
- model: providerSettings.model,
53116
- baseUrl: providerSettings.baseUrl ?? definition.defaultBaseUrl,
53117
- fallback: providerSettings.fallback
53118
- };
53119
- }
53120
- function getProviderRuntimeBackend(providerId) {
53121
- const provider = resolveProviderId(providerId);
53122
- switch (provider) {
53123
- case "ollama":
53124
- return "ollama";
53125
- case "lmstudio":
53126
- return "openai-compatible:lmstudio";
53127
- case "llama.cpp":
53128
- return "openai-compatible:llama.cpp";
53129
- case "vllm":
53130
- return "openai-compatible:vllm";
53131
- case "openai-compatible":
53132
- return "openai-compatible";
53133
- case "codex-cli":
53134
- return "subscription-cli:codex";
53135
- case "claude-code-cli":
53136
- return "subscription-cli:claude-code";
53137
- case "gemini-cli":
53138
- return "subscription-cli:gemini";
53139
- case "antigravity-cli":
53140
- return "subscription-cli:antigravity";
53141
- case "openai-api":
53142
- return "api:openai";
53143
- case "anthropic-api":
53144
- return "api:anthropic";
53145
- case "gemini-api":
53146
- return "api:gemini";
53147
- case "openrouter":
53148
- return "api:openrouter";
53149
- default:
53150
- return `unknown:${providerId}`;
53151
- }
53152
- }
53153
- function authModeLabel(mode) {
53154
- switch (mode) {
53155
- case "subscription":
53156
- return "subscription";
53157
- case "enterprise-login":
53158
- return "enterprise-login";
53159
- case "personal-login":
53160
- return "personal-login";
53161
- case "api":
53162
- return "API";
53163
- case "local":
53164
- return "local";
53165
- }
53166
- }
53167
- function getProviderAccessTypeLabel(provider) {
53168
- return provider.accessTypeLabel ?? provider.accessType;
53169
- }
53170
- function credentialTypeLabel(type) {
53171
- switch (type) {
53172
- case "cli-login":
53173
- return "subscription login";
53174
- case "api-key":
53175
- return "API key";
53176
- case "local-runtime":
53177
- return "local runtime";
53178
- case "openai-compatible-endpoint":
53179
- return "OpenAI-compatible endpoint";
53180
- }
53181
- }
53182
- function listProviders() {
53183
- return PROVIDER_IDS.map((id) => PROVIDERS[id]);
53184
- }
53185
- function hasSecretLikeValue(value) {
53186
- const trimmed = value.trim();
53187
- if (/^(sk-|sk_|sk-proj-|sk-ant-|xox[baprs]-|gh[pousr]_|AIza)/i.test(trimmed)) {
53188
- return true;
53189
- }
53190
- if (/token|refresh|oauth|secret|api[_-]?key/i.test(trimmed)) {
53191
- return true;
53192
- }
53193
- try {
53194
- const url3 = new URL(trimmed);
53195
- return Boolean(url3.username || url3.password);
53196
- } catch {
53197
- return false;
53198
- }
53199
- }
53200
- function normalizeBaseUrl(value) {
53201
- const trimmed = value.trim();
53202
- const withScheme = /^https?:\/\//i.test(trimmed) ? trimmed : `http://${trimmed}`;
53203
- const url3 = new URL(withScheme);
53204
- if (url3.username || url3.password) {
53205
- throw new Error("base_url must not contain embedded credentials");
53206
- }
53207
- return withScheme.replace(/\/$/, "");
53208
- }
53209
- function setSafeProviderConfig(key, value) {
53210
- const trimmed = value.trim();
53211
- if (!trimmed) {
53212
- return { ok: false, message: `Missing value for ${key}.` };
53213
- }
53214
- if (hasSecretLikeValue(trimmed)) {
53215
- return {
53216
- ok: false,
53217
- message: "Refusing to store credential-like data. Put API keys in environment variables and select API mode explicitly."
53218
- };
53219
- }
53220
- let settings;
53221
- let providerModelInvalidated = false;
53222
- try {
53223
- if (key === "provider") {
53224
- const provider = resolveProviderId(trimmed);
53225
- if (!provider) {
53226
- return {
53227
- ok: false,
53228
- message: `Unknown provider "${trimmed}". Run: ur provider list`
53229
- };
53230
- }
53231
- const currentSettings = getInitialSettings();
53232
- const currentModel = getActiveProviderSettings(currentSettings).model;
53233
- const nextProviderSettings = { active: provider };
53234
- let invalidated = false;
53235
- if (currentModel) {
53236
- const validation = validateProviderModelPair(provider, currentModel);
53237
- if (validation.valid === false) {
53238
- nextProviderSettings.model = undefined;
53239
- invalidated = true;
53240
- providerModelInvalidated = true;
53241
- }
53242
- }
53243
- settings = {
53244
- provider: nextProviderSettings,
53245
- ...invalidated ? { model: undefined } : {}
53246
- };
53247
- } else if (key === "provider.fallback") {
53248
- const fallback = trimmed === "disabled" ? "disabled" : resolveProviderId(trimmed);
53249
- if (!fallback) {
53250
- return {
53251
- ok: false,
53252
- message: `Unknown fallback provider "${trimmed}". Run: ur provider list`
53253
- };
53254
- }
53255
- settings = { provider: { fallback } };
53256
- } else if (key === "provider.command_path") {
53257
- settings = { provider: { commandPath: trimmed } };
53258
- } else if (key === "model") {
53259
- const currentSettings = getInitialSettings();
53260
- const currentProvider = getActiveProviderSettings(currentSettings).active ?? "ollama";
53261
- const validation = validateProviderModelPair(currentProvider, trimmed);
53262
- if (validation.valid === false) {
53263
- return {
53264
- ok: false,
53265
- message: validation.error
53266
- };
53267
- }
53268
- settings = { provider: { model: trimmed }, model: trimmed };
53269
- } else {
53270
- settings = { provider: { baseUrl: normalizeBaseUrl(trimmed) } };
53271
- }
53272
- } catch (error40) {
53273
- return {
53274
- ok: false,
53275
- message: error40 instanceof Error ? error40.message : String(error40)
53276
- };
53277
- }
53278
- const result = updateSettingsForSource("userSettings", settings);
53279
- if (result.error) {
53280
- return {
53281
- ok: false,
53282
- message: `Failed to write UR-AGENT settings: ${result.error.message}`
53283
- };
53284
- }
53285
- const savedValue = key === "provider" || key === "provider.fallback" ? key === "provider.fallback" && trimmed === "disabled" ? "disabled" : resolveProviderId(trimmed) ?? trimmed : trimmed;
53286
- return {
53287
- ok: true,
53288
- message: `Set ${key} to ${savedValue}.${providerModelInvalidated ? " Cleared incompatible model for the new provider; run /model to choose a scoped model." : ""}`
53289
- };
53290
- }
53291
- function outputText(result) {
53292
- return `${result.stdout}
53293
- ${result.stderr}
53294
- ${result.error ?? ""}`.trim();
53295
- }
53296
- function classifiesAsLoggedIn(text) {
53297
- return /logged in|authenticated|signed in|active account|using chatgpt/i.test(text);
53298
- }
53299
- function classifiesAsNotLoggedIn(text) {
53300
- return /not logged in|not authenticated|not signed in|login required|unauthenticated/i.test(text);
53301
- }
53302
- function classifyGeminiAccountSupport(text) {
53303
- if (/personal.*unsupported|unsupported.*personal|consumer.*unsupported/i.test(text)) {
53304
- return "personal-unsupported";
53305
- }
53306
- if (/enterprise|standard|code assist|workspace/i.test(text)) {
53307
- return "enterprise-supported";
53308
- }
53309
- return "unknown";
53310
- }
53311
- async function resolveCommand(definition, settings, adapters) {
53312
- if (settings.commandPath) {
53313
- return settings.commandPath;
53314
- }
53315
- for (const candidate of definition.commandCandidates ?? []) {
53316
- const found = await (adapters.which ?? which)(candidate);
53317
- if (found)
53318
- return found;
53319
- }
53320
- return null;
53321
- }
53322
- async function runCommand(file2, args, adapters) {
53323
- if (adapters.run) {
53324
- return adapters.run(file2, args);
53325
- }
53326
- return execFileNoThrow(file2, args, {
53327
- timeout: 15000,
53328
- preserveOutputOnError: true,
53329
- audit: false
53330
- });
53331
- }
53332
- function addFailure(result, reason, fix) {
53333
- result.ok = false;
53334
- result.failureReason ??= reason;
53335
- result.suggestedFix ??= fix;
53336
- }
53337
- function endpointUrl(baseUrl, kind) {
53338
- const trimmed = baseUrl.replace(/\/$/, "");
53339
- if (kind === "ollama") {
53340
- return `${trimmed}/api/tags`;
53341
- }
53342
- return `${trimmed}/models`;
53343
- }
53344
- function isLocalBaseUrl(value) {
53345
- return LOCALHOST_RE.test(value);
53346
- }
53347
- async function checkEndpoint(definition, settings, adapters, result) {
53348
- if (!definition.endpointKind)
53349
- return;
53350
- const baseUrl = settings.baseUrl ?? (definition.id === "ollama" ? getOllamaBaseUrl() : definition.defaultBaseUrl);
53351
- if (!baseUrl) {
53352
- result.checks.push({
53353
- name: "base_url",
53354
- status: "fail",
53355
- message: "No base_url configured."
53356
- });
53357
- addFailure(result, "missing base_url", "Run: ur config set base_url <url>");
53358
- return;
53359
- }
53360
- const url3 = endpointUrl(baseUrl, definition.endpointKind);
53361
- try {
53362
- const response = await (adapters.fetch ?? fetch)(url3, {
53363
- method: "GET",
53364
- headers: definition.accessType === "api" && (adapters.env ?? process.env)[definition.envKey ?? ""] ? { Authorization: `Bearer ${(adapters.env ?? process.env)[definition.envKey ?? ""]}` } : undefined
53365
- });
53366
- if (!response.ok) {
53367
- result.checks.push({
53368
- name: "endpoint",
53369
- status: "fail",
53370
- message: `${url3} returned HTTP ${response.status}.`
53371
- });
53372
- addFailure(result, `endpoint returned HTTP ${response.status}`, `Start the provider server or update base_url: ur config set base_url ${baseUrl}`);
53373
- return;
53374
- }
53375
- result.checks.push({
53376
- name: "endpoint",
53377
- status: "pass",
53378
- message: `${url3} is reachable.`
53379
- });
53380
- if (settings.model) {
53381
- const body = await response.text().catch(() => "");
53382
- if (body && !body.includes(settings.model)) {
53383
- result.checks.push({
53384
- name: "model",
53385
- status: "warn",
53386
- message: `Model "${settings.model}" was not found in the detectable model list.`
53387
- });
53388
- } else {
53389
- result.checks.push({
53390
- name: "model",
53391
- status: "pass",
53392
- message: `Model "${settings.model}" is detectable.`
53393
- });
53394
- }
53395
- }
53396
- } catch (error40) {
53397
- result.checks.push({
53398
- name: "endpoint",
53399
- status: "fail",
53400
- message: `${url3} is not reachable.`
53401
- });
53402
- addFailure(result, error40 instanceof Error ? error40.message : "endpoint unavailable", `Start the provider server or update base_url: ur config set base_url ${baseUrl}`);
53403
- }
53404
- }
53405
- async function checkSubscriptionProvider(definition, settings, adapters, result) {
53406
- const commandPath = await resolveCommand(definition, settings, adapters);
53407
- if (!commandPath) {
53408
- const commands = definition.commandCandidates?.join(", ") ?? definition.id;
53409
- result.checks.push({
53410
- name: "cli",
53411
- status: "fail",
53412
- message: `No official CLI command found on PATH. Tried: ${commands}.`
53413
- });
53414
- addFailure(result, "CLI missing", `Install the official ${definition.displayName} CLI, then run ur auth ${authAliasForProvider(definition.id)}.`);
53415
- return;
53416
- }
53417
- result.checks.push({
53418
- name: "cli",
53419
- status: "pass",
53420
- message: `${commandPath} found.`
53421
- });
53422
- if (definition.versionArgs) {
53423
- const version2 = await runCommand(commandPath, definition.versionArgs, adapters);
53424
- result.checks.push({
53425
- name: "version",
53426
- status: version2.code === 0 ? "pass" : "warn",
53427
- message: outputText(version2) || `${definition.displayName} version check exited ${version2.code}.`
53428
- });
53429
- }
53430
- if (definition.id === "claude-code-cli" && (adapters.env ?? process.env).ANTHROPIC_API_KEY) {
53431
- result.checks.push({
53432
- name: "api_key_override",
53433
- status: "warn",
53434
- message: "ANTHROPIC_API_KEY is set and may override Claude Code subscription login. Unset it to test subscription auth."
53435
- });
53436
- }
53437
- if (definition.id === "gemini-cli") {
53438
- const versionText = result.checks.find((check3) => check3.name === "version")?.message ?? "";
53439
- const support = classifyGeminiAccountSupport(versionText);
53440
- if (support === "personal-unsupported") {
53441
- result.checks.push({
53442
- name: "account_type",
53443
- status: "fail",
53444
- message: definition.unsupportedPersonalAccountMessage ?? "Unsupported account type."
53445
- });
53446
- addFailure(result, "unsupported account type", "Use an official Gemini Code Assist Standard/Enterprise login path.");
53447
- } else if (support === "enterprise-supported") {
53448
- result.checks.push({
53449
- name: "account_type",
53450
- status: "pass",
53451
- message: "Gemini Code Assist Standard/Enterprise path is supported by the detected CLI output."
53452
- });
53453
- } else {
53454
- result.checks.push({
53455
- name: "account_type",
53456
- status: "warn",
53457
- message: "Gemini CLI status is not exposed by this CLI. UR-AGENT will only use the official Gemini CLI flow and will not support personal-account bypasses."
53458
- });
53459
- }
53460
- }
53461
- if (!definition.statusArgs) {
53462
- result.checks.push({
53463
- name: "login_status",
53464
- status: "skip",
53465
- message: "No stable official status command is configured for this provider."
53466
- });
53467
- return;
53468
- }
53469
- const status = await runCommand(commandPath, definition.statusArgs, adapters);
53470
- const text = outputText(status);
53471
- if (status.code === 0 && !classifiesAsNotLoggedIn(text)) {
53472
- result.checks.push({
53473
- name: "login_status",
53474
- status: classifiesAsLoggedIn(text) ? "pass" : "warn",
53475
- message: text || "Status command succeeded."
53476
- });
53477
- return;
53478
- }
53479
- result.checks.push({
53480
- name: "login_status",
53481
- status: "fail",
53482
- message: text || `${definition.displayName} is not logged in.`
53483
- });
53484
- addFailure(result, "not logged in", `Run: ur auth ${authAliasForProvider(definition.id)}`);
53485
- }
53486
- async function checkApiProvider(definition, settings, adapters, result) {
53487
- const env4 = adapters.env ?? process.env;
53488
- const baseUrl = settings.baseUrl ?? definition.defaultBaseUrl;
53489
- const requiresKey = definition.id !== "openai-compatible" || !baseUrl || !isLocalBaseUrl(baseUrl);
53490
- if (definition.envKey && requiresKey) {
53491
- if (env4[definition.envKey]) {
53492
- result.checks.push({
53493
- name: "api_key",
53494
- status: "pass",
53495
- message: `${definition.envKey} is present.`
53496
- });
53497
- } else {
53498
- result.checks.push({
53499
- name: "api_key",
53500
- status: "fail",
53501
- message: `${definition.envKey} is not set.`
53502
- });
53503
- addFailure(result, "API key missing", `Set ${definition.envKey} in your environment or choose a subscription/local provider.`);
53504
- }
53505
- }
53506
- await checkEndpoint(definition, settings, adapters, result);
53507
- }
53508
- function fallbackResult(settings, active, ok) {
53509
- if (ok)
53510
- return;
53511
- if (!settings.fallback || settings.fallback === "disabled") {
53512
- return {
53513
- enabled: false,
53514
- message: "Fallback is disabled. UR-AGENT will not silently switch providers. Optional: ur config set provider.fallback ollama"
53515
- };
53516
- }
53517
- if (settings.fallback === active) {
53518
- return {
53519
- enabled: false,
53520
- message: "Fallback points at the selected provider and will not be used."
53521
- };
53522
- }
53523
- return {
53524
- enabled: true,
53525
- provider: settings.fallback,
53526
- message: `Fallback is configured as ${settings.fallback}, but UR-AGENT will ask before using it.`
53527
- };
53528
- }
53529
- async function doctorProvider(provider, options = {}) {
53530
- const allSettings = options.settings ?? getInitialSettings();
53531
- const providerSettings = getActiveProviderSettings(allSettings);
53532
- const active = provider ?? providerSettings.active ?? "ollama";
53533
- const definition = getProviderDefinition(active);
53534
- const settingsForProvider = {
53535
- ...providerSettings,
53536
- active
53537
- };
53538
- const result = {
53539
- provider: active,
53540
- displayName: definition.displayName,
53541
- accessType: definition.accessType,
53542
- authMode: definition.authMode,
53543
- selected: active === providerSettings.active,
53544
- ok: true,
53545
- checks: [
53546
- {
53547
- name: "legal_path",
53548
- status: "pass",
53549
- message: definition.legalPath
53550
- }
53551
- ]
53552
- };
53553
- if (definition.accessType === "subscription") {
53554
- await checkSubscriptionProvider(definition, settingsForProvider, options.adapters ?? {}, result);
53555
- } else if (definition.accessType === "api") {
53556
- await checkApiProvider(definition, settingsForProvider, options.adapters ?? {}, result);
53557
- } else if (definition.accessType === "local" || definition.accessType === "server") {
53558
- await checkEndpoint(definition, settingsForProvider, options.adapters ?? {}, result);
53559
- }
53560
- result.fallback = fallbackResult(providerSettings, active, result.ok);
53561
- return result;
53562
- }
53563
- async function doctorActiveProvider(options = {}) {
53564
- const settings = options.settings ?? getInitialSettings();
53565
- const active = getActiveProviderSettings(settings).active ?? "ollama";
53566
- return doctorProvider(active, options);
53567
- }
53568
- function getConnectionStatusFromDoctorResult(result) {
53569
- if (result.ok) {
53570
- return "connected";
53571
- }
53572
- if (result.failureReason?.includes("CLI missing") || result.failureReason?.includes("not found")) {
53573
- return "missing";
53574
- }
53575
- if (result.failureReason?.includes("not logged in") || result.failureReason?.includes("not authenticated") || result.failureReason?.includes("API key missing") || result.failureReason?.includes("endpoint") || result.failureReason?.includes("HTTP")) {
53576
- return "unavailable";
53577
- }
53578
- return "unknown";
53579
- }
53580
- function formatProviderStatusLabel(status, provider, checks3) {
53581
- switch (status) {
53582
- case "connected":
53583
- if (provider.credentialType === "api-key" && provider.envKey) {
53584
- return `${provider.envKey} found`;
53585
- }
53586
- if (provider.id === "ollama") {
53587
- return "localhost reachable";
53588
- }
53589
- if (provider.credentialType === "openai-compatible-endpoint") {
53590
- return "OpenAI-compatible endpoint reachable";
53591
- }
53592
- if (provider.credentialType === "cli-login") {
53593
- return "subscription login connected";
53594
- }
53595
- return "connected";
53596
- case "missing":
53597
- if (provider.commandCandidates) {
53598
- return `CLI not found (tried: ${provider.commandCandidates.join(", ")})`;
53599
- }
53600
- return "missing";
53601
- case "unavailable": {
53602
- const failCheck = checks3.find((check3) => check3.status === "fail" || check3.status === "warn");
53603
- return failCheck?.message ?? "unavailable";
53604
- }
53605
- case "unknown":
53606
- return "status unknown";
53607
- }
53608
- }
53609
- async function getProviderStatus(providerId, options = {}) {
53610
- const provider = resolveProviderId(providerId);
53611
- if (!provider) {
53612
- throw new Error(`Unknown provider "${providerId}". Run: ur provider list`);
53613
- }
53614
- const definition = getProviderDefinition(provider);
53615
- const doctor = await doctorProvider(provider, options);
53616
- const status = getConnectionStatusFromDoctorResult(doctor);
53617
- return {
53618
- provider,
53619
- displayName: definition.displayName,
53620
- accessType: definition.accessType,
53621
- accessTypeLabel: getProviderAccessTypeLabel(definition),
53622
- credentialType: definition.credentialType,
53623
- status,
53624
- label: formatProviderStatusLabel(status, definition, doctor.checks),
53625
- checks: doctor.checks,
53626
- doctor
53627
- };
53628
- }
53629
- function authAliasForProvider(provider) {
53630
- switch (provider) {
53631
- case "codex-cli":
53632
- return "chatgpt";
53633
- case "claude-code-cli":
53634
- return "claude";
53635
- case "gemini-cli":
53636
- return "gemini";
53637
- case "antigravity-cli":
53638
- return "antigravity";
53639
- default:
53640
- return "provider";
53641
- }
53642
- }
53643
- function providerForAuthAlias(alias) {
53644
- switch (alias) {
53645
- case "chatgpt":
53646
- return "codex-cli";
53647
- case "claude":
53648
- return "claude-code-cli";
53649
- case "gemini":
53650
- return "gemini-cli";
53651
- case "antigravity":
53652
- return "antigravity-cli";
53653
- default:
53654
- return null;
53655
- }
53656
- }
53657
- function buildProviderAuthCommand(provider, options = {}) {
53658
- const definition = getProviderDefinition(provider);
53659
- const command = definition.commandCandidates?.[0];
53660
- if (!command)
53661
- return null;
53662
- const args = options.deviceAuth && definition.deviceLoginArgs ? definition.deviceLoginArgs : definition.loginArgs;
53663
- if (!args)
53664
- return null;
53665
- if (provider === "gemini-cli") {
53666
- return {
53667
- command,
53668
- args,
53669
- instructions: "The detected Gemini CLI does not expose a stable non-interactive login subcommand. Launching the official Gemini CLI is the only supported path; complete the Gemini Code Assist login flow if prompted."
53670
- };
53671
- }
53672
- if (provider === "antigravity-cli") {
53673
- return {
53674
- command,
53675
- args,
53676
- instructions: "UR-AGENT will only launch the official Antigravity CLI. Use its documented login flow where supported; UR-AGENT will not invent flags or reuse browser sessions."
53677
- };
53678
- }
53679
- return {
53680
- command,
53681
- args,
53682
- instructions: `Launching ${definition.legalPath}.`
53683
- };
53684
- }
53685
- async function launchProviderAuth(alias, options = {}) {
53686
- const provider = providerForAuthAlias(alias);
53687
- if (!provider) {
53688
- return { ok: false, message: `Unknown auth provider "${alias}".` };
53689
- }
53690
- const authCommand = buildProviderAuthCommand(provider, options);
53691
- if (!authCommand) {
53692
- return {
53693
- ok: false,
53694
- message: `No official login command is configured for ${provider}.`
53695
- };
53696
- }
53697
- const commandPath = await resolveCommand(getProviderDefinition(provider), {}, {});
53698
- if (!commandPath) {
53699
- const commands = getProviderDefinition(provider).commandCandidates?.join(", ") ?? provider;
53700
- return {
53701
- ok: false,
53702
- message: `No official ${getProviderDefinition(provider).displayName} CLI command found. Tried: ${commands}. Install the official CLI first.`
53703
- };
53704
- }
53705
- const printableCommand = commandPath.split(/[\\/]/).pop() ?? authCommand.command;
53706
- const printable = [printableCommand, ...authCommand.args].join(" ");
53707
- if (options.dryRun || !process.stdin.isTTY || !process.stdout.isTTY) {
53708
- return {
53709
- ok: true,
53710
- message: `${authCommand.instructions}
53711
- Run: ${printable}`,
53712
- command: printable
53713
- };
53714
- }
53715
- await new Promise((resolve8, reject) => {
53716
- const child = spawn2(commandPath, authCommand.args, {
53717
- stdio: "inherit",
53718
- env: process.env
53719
- });
53720
- child.on("error", reject);
53721
- child.on("exit", (code) => {
53722
- if (code === 0)
53723
- resolve8();
53724
- else
53725
- reject(new Error(`${printable} exited with code ${code ?? 1}`));
53726
- });
53727
- });
53728
- return { ok: true, message: `Completed: ${printable}`, command: printable };
53729
- }
53730
- function formatProviderList(json2 = false) {
53731
- const providers = listProviders().map((provider) => ({
53732
- id: provider.id,
53733
- name: provider.displayName,
53734
- aliases: providerAliasesFor(provider.id),
53735
- accessType: provider.accessType,
53736
- accessTypeLabel: getProviderAccessTypeLabel(provider),
53737
- credentialType: provider.credentialType,
53738
- modelDiscoveryType: provider.modelDiscoveryType,
53739
- runtimeBackend: getProviderRuntimeBackend(provider.id),
53740
- authMode: provider.authMode,
53741
- accessPath: provider.accessPathLabel,
53742
- legalPath: provider.legalPath
53743
- }));
53744
- if (json2) {
53745
- return JSON.stringify(providers, null, 2);
53746
- }
53747
- return [
53748
- "Provider | ID | Aliases | Access type | Credential | Model discovery | Runtime backend | Access path",
53749
- "--- | --- | --- | --- | --- | --- | --- | ---",
53750
- ...providers.map((provider) => `${provider.name} | ${provider.id} | ${provider.aliases.slice(0, 3).join(", ") || "-"} | ${provider.accessTypeLabel} | ${provider.credentialType} | ${provider.modelDiscoveryType} | ${provider.runtimeBackend} | ${provider.accessPath}`)
53751
- ].join(`
53752
- `);
53753
- }
53754
- function formatProviderDoctor(result, json2 = false) {
53755
- if (json2) {
53756
- return JSON.stringify(result, null, 2);
53757
- }
53758
- const lines = [
53759
- `Provider: ${result.displayName} (${result.provider})`,
53760
- `Access: ${getProviderAccessTypeLabel(getProviderDefinition(result.provider))}`,
53761
- `Credential: ${getProviderDefinition(result.provider).credentialType}`,
53762
- `Runtime backend: ${getProviderRuntimeBackend(result.provider)}`,
53763
- `Auth: ${authModeLabel(result.authMode)}`,
53764
- `Status: ${result.ok ? "ready" : "not ready"}`
53765
- ];
53766
- for (const check3 of result.checks) {
53767
- lines.push(`- ${check3.status.toUpperCase()} ${check3.name}: ${check3.message}`);
53768
- }
53769
- if (result.failureReason) {
53770
- lines.push(`Failure reason: ${result.failureReason}`);
53771
- }
53772
- if (result.suggestedFix) {
53773
- lines.push(`Suggested fix: ${result.suggestedFix}`);
53774
- }
53775
- if (result.fallback) {
53776
- lines.push(`Fallback: ${result.fallback.message}`);
53777
- }
53778
- return lines.join(`
53779
- `);
53780
- }
53781
- function formatProviderStatus(result, json2 = false) {
53782
- if (json2) {
53783
- return JSON.stringify(result, null, 2);
53784
- }
53785
- const failure = result.failureReason ? `
53786
- Failure reason: ${result.failureReason}` : "";
53787
- const fix = result.suggestedFix ? `
53788
- Suggested fix: ${result.suggestedFix}` : "";
53789
- const definition = getProviderDefinition(result.provider);
53790
- const settings = getActiveProviderSettings(getInitialSettings());
53791
- const model = settings.model ? `
53792
- Active model: ${settings.model}` : "";
53793
- return `Selected provider: ${result.displayName} (${result.provider})
53794
- Access type: ${getProviderAccessTypeLabel(definition)}
53795
- Credential: ${definition.credentialType}
53796
- Runtime backend: ${getProviderRuntimeBackend(result.provider)}${model}
53797
- Auth mode: ${authModeLabel(result.authMode)}
53798
- Ready: ${result.ok ? "yes" : "no"}${failure}${fix}`;
53799
- }
53800
- function clearProviderModelCacheForTests() {
53801
- cachedModelsByProvider.clear();
53802
- }
53803
- function providerBaseUrl(provider, definition, settings) {
53804
- const providerSettings = getActiveProviderSettings(settings);
53805
- if (providerSettings.baseUrl) {
53806
- return providerSettings.baseUrl;
53807
- }
53808
- if (provider === "ollama") {
53809
- return getOllamaBaseUrl(process.env, settings);
53810
- }
53811
- return definition.defaultBaseUrl;
53812
- }
53813
- function parseOpenAICompatibleModelNames(value) {
53814
- if (!value || typeof value !== "object") {
53815
- return [];
53816
- }
53817
- const data = value.data ?? value.models;
53818
- if (!Array.isArray(data)) {
53819
- return [];
53820
- }
53821
- const names = data.flatMap((model) => {
53822
- if (typeof model === "string") {
53823
- const trimmed2 = model.trim();
53824
- return trimmed2 ? [trimmed2] : [];
53825
- }
53826
- if (!model || typeof model !== "object") {
53827
- return [];
53828
- }
53829
- const entry = model;
53830
- const name = entry.id ?? entry.name ?? entry.model;
53831
- if (typeof name !== "string") {
53832
- return [];
53833
- }
53834
- const trimmed = name.trim();
53835
- return trimmed ? [trimmed] : [];
53836
- });
53837
- return [...new Set(names)].sort((a2, b) => a2.localeCompare(b));
53838
- }
53839
- function parseOllamaModelNamesFromTags(value) {
53840
- if (!value || typeof value !== "object" || !("models" in value)) {
53841
- return [];
53842
- }
53843
- const models = value.models;
53844
- if (!Array.isArray(models)) {
53845
- return [];
53846
- }
53847
- const names = models.flatMap((model) => {
53848
- if (!model || typeof model !== "object") {
53849
- return [];
53850
- }
53851
- const entry = model;
53852
- const name = entry.name ?? entry.model;
53853
- if (typeof name !== "string") {
53854
- return [];
53855
- }
53856
- const trimmed = name.trim();
53857
- return trimmed ? [trimmed] : [];
53858
- });
53859
- return [...new Set(names)].sort((a2, b) => a2.localeCompare(b));
53860
- }
53861
- function modelDefinitionsFromNames(provider, names, source) {
53862
- const providerName = getProviderDefinition(provider).displayName;
53863
- return names.map((name) => ({
53864
- id: name,
53865
- displayName: name,
53866
- description: source === "cache" ? `Cached ${providerName} model` : `Discovered from ${providerName}`
53867
- }));
53868
- }
53869
- function getCachedProviderModels(provider) {
53870
- return cachedModelsByProvider.get(provider) ?? [];
53871
- }
53872
- function cacheProviderModelsForProvider(providerId, models) {
53873
- const provider = resolveProviderId(providerId);
53874
- if (!provider) {
53875
- return;
53876
- }
53877
- const definitions = typeof models[0] === "string" ? modelDefinitionsFromNames(provider, models, "cache") : models;
53878
- if (definitions.length > 0) {
53879
- cachedModelsByProvider.set(provider, definitions);
53880
- }
53881
- }
53882
- function staticModelsForProvider(provider) {
53883
- return (PROVIDER_MODELS[provider] ?? []).filter((model) => !model.isDynamic);
53884
- }
53885
- async function discoverLiveModelsForProvider(provider, options = {}) {
53886
- const definition = getProviderDefinition(provider);
53887
- if (!definition.endpointKind) {
53888
- return [];
53889
- }
53890
- const settings = options.settings ?? getInitialSettings();
53891
- const baseUrl = providerBaseUrl(provider, definition, settings);
53892
- if (!baseUrl) {
53893
- throw new Error(`No base_url configured for provider "${provider}".`);
53894
- }
53895
- const url3 = endpointUrl(baseUrl, definition.endpointKind);
53896
- const env4 = options.adapters?.env ?? process.env;
53897
- const response = await (options.adapters?.fetch ?? fetch)(url3, {
53898
- method: "GET",
53899
- signal: options.signal,
53900
- headers: definition.accessType === "api" && definition.envKey && env4[definition.envKey] ? { Authorization: `Bearer ${env4[definition.envKey]}` } : undefined
53901
- });
53902
- if (!response.ok) {
53903
- throw new Error(`${url3} returned HTTP ${response.status}.`);
53904
- }
53905
- const body = await response.json();
53906
- const names = definition.endpointKind === "ollama" ? parseOllamaModelNamesFromTags(body) : parseOpenAICompatibleModelNames(body);
53907
- return modelDefinitionsFromNames(provider, names, "live");
53908
- }
53909
- async function listModelsForProviderWithSource(providerId, options = {}) {
53910
- const provider = resolveProviderId(providerId);
53911
- if (!provider) {
53912
- return {
53913
- provider: "ollama",
53914
- models: [],
53915
- source: "static",
53916
- warning: `Unknown provider "${providerId}". Run: ur provider list`
53917
- };
53918
- }
53919
- const definition = getProviderDefinition(provider);
53920
- if (definition.modelDiscoveryType === "static") {
53921
- return {
53922
- provider,
53923
- models: staticModelsForProvider(provider),
53924
- source: "static"
53925
- };
53926
- }
53927
- try {
53928
- const liveModels = await discoverLiveModelsForProvider(provider, options);
53929
- if (liveModels.length > 0) {
53930
- cachedModelsByProvider.set(provider, liveModels);
53931
- return {
53932
- provider,
53933
- models: liveModels,
53934
- source: "live"
53935
- };
53936
- }
53937
- const cachedModels = getCachedProviderModels(provider);
53938
- if (cachedModels.length > 0) {
53939
- return {
53940
- provider,
53941
- models: cachedModels,
53942
- source: "cache",
53943
- warning: `Live model discovery for "${provider}" returned no models. Showing cached ${provider} models only.`
53944
- };
53945
- }
53946
- const staticModels = staticModelsForProvider(provider);
53947
- return {
53948
- provider,
53949
- models: staticModels,
53950
- source: staticModels.length > 0 ? "static" : "live",
53951
- warning: `Live model discovery for "${provider}" returned no models.`
53952
- };
53953
- } catch (error40) {
53954
- const cachedModels = getCachedProviderModels(provider);
53955
- if (cachedModels.length > 0) {
53956
- return {
53957
- provider,
53958
- models: cachedModels,
53959
- source: "cache",
53960
- warning: `Live model discovery for "${provider}" failed: ${error40 instanceof Error ? error40.message : String(error40)}. Showing cached ${provider} models only.`
53961
- };
53962
- }
53963
- const staticModels = staticModelsForProvider(provider);
53964
- return {
53965
- provider,
53966
- models: staticModels,
53967
- source: staticModels.length > 0 ? "static" : "live",
53968
- warning: `Live model discovery for "${provider}" failed: ${error40 instanceof Error ? error40.message : String(error40)}.`
53969
- };
53970
- }
53971
- }
53972
- function listModelsForProvider(providerId) {
53973
- const provider = resolveProviderId(providerId);
53974
- if (!provider) {
53975
- return [];
53976
- }
53977
- return PROVIDER_MODELS[provider] ?? [];
53978
- }
53979
- function isModelSupportedByProvider(providerId, modelId) {
53980
- return validateProviderModelPair(providerId, modelId).valid;
53981
- }
53982
- function getDefaultModelForProvider(providerId) {
53983
- const provider = resolveProviderId(providerId);
53984
- if (!provider) {
53985
- return;
53986
- }
53987
- const models = PROVIDER_MODELS[provider];
53988
- if (!models) {
53989
- return;
53990
- }
53991
- const defaultModel = models.find((m) => m.isDefault && !m.isDynamic) ?? models.find((m) => !m.isDynamic);
53992
- return defaultModel?.id;
53993
- }
53994
- function getValidModelIdsForProvider(providerId) {
53995
- const provider = resolveProviderId(providerId);
53996
- if (!provider) {
53997
- return [];
53998
- }
53999
- const cached2 = getCachedProviderModels(provider);
54000
- if (cached2.length > 0) {
54001
- return cached2.map((model) => model.id);
54002
- }
54003
- return staticModelsForProvider(provider).map((model) => model.id);
54004
- }
54005
- function formatInvalidProviderModelMessage(providerId, modelId, validModels, suggestedModel) {
54006
- const provider = resolveProviderId(providerId) ?? String(providerId);
54007
- const validList = validModels.length > 0 ? validModels.join(", ") : "(no models discovered)";
54008
- const suggested = suggestedModel ?? validModels[0] ?? "<valid-model>";
54009
- return `Model "${modelId}" is not available for provider "${provider}". Valid models for ${provider}: ${validList}. Run /model and choose a model from ${provider}, or run: ur config set model ${suggested}`;
54010
- }
54011
- function validateProviderModelPair(providerId, modelId, options = {}) {
54012
- const provider = resolveProviderId(providerId);
54013
- if (!provider) {
54014
- return {
54015
- valid: false,
54016
- error: `Unknown provider "${providerId}". Run: ur provider list`,
54017
- validModels: []
54018
- };
54019
- }
54020
- const models = PROVIDER_MODELS[provider];
54021
- if (!models) {
54022
- return {
54023
- valid: false,
54024
- error: `No models defined for provider "${provider}".`,
54025
- validModels: []
54026
- };
54027
- }
54028
- const suppliedModels = (options.availableModels ?? []).map((model) => typeof model === "string" ? model : model.id);
54029
- const cachedModels = getCachedProviderModels(provider).map((model) => model.id);
54030
- const staticModelIds = staticModelsForProvider(provider).map((model) => model.id);
54031
- const hasDynamicModels = models.some((model) => model.isDynamic);
54032
- const validModelIds = suppliedModels.length > 0 ? suppliedModels : hasDynamicModels ? cachedModels.length > 0 ? cachedModels : staticModelIds : Array.from(new Set([...staticModelIds, ...cachedModels]));
54033
- if (validModelIds.includes(modelId)) {
54034
- return { valid: true };
54035
- }
54036
- if (hasDynamicModels && options.allowUncachedDynamic && validModelIds.length === 0) {
54037
- return { valid: true };
54038
- }
54039
- const defaultModel = getDefaultModelForProvider(provider);
54040
- return {
54041
- valid: false,
54042
- error: formatInvalidProviderModelMessage(provider, modelId, validModelIds, defaultModel),
54043
- validModels: validModelIds,
54044
- suggestedModel: defaultModel
54045
- };
54046
- }
54047
- function setProviderModel(providerId, modelId, options = {}) {
54048
- const provider = resolveProviderId(providerId);
54049
- if (!provider) {
54050
- return {
54051
- ok: false,
54052
- message: `Unknown provider "${providerId}". Run: ur provider list`
54053
- };
54054
- }
54055
- const validation = validateProviderModelPair(provider, modelId, {
54056
- availableModels: options.availableModels
54057
- });
54058
- if (validation.valid === false) {
54059
- return {
54060
- ok: false,
54061
- message: validation.error
54062
- };
54063
- }
54064
- const result = updateSettingsForSource("userSettings", {
54065
- provider: {
54066
- active: provider,
54067
- model: modelId
54068
- },
54069
- model: modelId
54070
- });
54071
- if (result.error) {
54072
- return {
54073
- ok: false,
54074
- message: `Failed to write UR-AGENT settings: ${result.error.message}`
54075
- };
54076
- }
54077
- return {
54078
- ok: true,
54079
- message: `Selected provider ${provider} (${getProviderAccessTypeLabel(getProviderDefinition(provider))}) with model ${modelId} (${options.modelSource ?? "static"}).`,
54080
- provider,
54081
- model: modelId,
54082
- modelSource: options.modelSource ?? "static"
54083
- };
54084
- }
54085
- var PROVIDER_IDS, LOCALHOST_RE, PROVIDERS, PROVIDER_ALIAS_ENTRIES, PROVIDER_ALIASES, PROVIDER_MODELS, cachedModelsByProvider, validateProviderModelCompatibility;
54086
- var init_providerRegistry = __esm(() => {
54087
- init_execFileNoThrow();
54088
- init_ollamaConfig();
54089
- init_settings2();
54090
- init_which();
54091
- PROVIDER_IDS = [
54092
- "codex-cli",
54093
- "claude-code-cli",
54094
- "gemini-cli",
54095
- "antigravity-cli",
54096
- "openai-api",
54097
- "anthropic-api",
54098
- "gemini-api",
54099
- "openrouter",
54100
- "openai-compatible",
54101
- "ollama",
54102
- "lmstudio",
54103
- "llama.cpp",
54104
- "vllm"
54105
- ];
54106
- LOCALHOST_RE = /^(https?:\/\/)?(localhost|127\.0\.0\.1|\[::1\]|::1)(:\d+)?(\/|$)/i;
54107
- PROVIDERS = {
54108
- "codex-cli": {
54109
- id: "codex-cli",
54110
- displayName: "Codex CLI",
54111
- statusBarName: "Codex CLI",
54112
- accessType: "subscription",
54113
- credentialType: "cli-login",
54114
- modelDiscoveryType: "static",
54115
- statusCheck: "cli-login",
54116
- listModels: "static",
54117
- validateModel: "static-list",
54118
- authMode: "subscription",
54119
- legalPath: "official Codex CLI login",
54120
- accessPathLabel: "subscription login via official Codex CLI",
54121
- commandCandidates: ["codex"],
54122
- versionArgs: ["--version"],
54123
- statusArgs: ["login", "status"],
54124
- loginArgs: ["login"],
54125
- deviceLoginArgs: ["login", "--device-auth"]
54126
- },
54127
- "claude-code-cli": {
54128
- id: "claude-code-cli",
54129
- displayName: "Claude Code",
54130
- statusBarName: "Claude Code",
54131
- accessType: "subscription",
54132
- credentialType: "cli-login",
54133
- modelDiscoveryType: "static",
54134
- statusCheck: "cli-login",
54135
- listModels: "static",
54136
- validateModel: "static-list",
54137
- authMode: "subscription",
54138
- legalPath: "official Claude Code CLI login",
54139
- accessPathLabel: "subscription login via official Claude Code CLI",
54140
- commandCandidates: ["claude"],
54141
- versionArgs: ["--version"],
54142
- statusArgs: ["auth", "status"],
54143
- loginArgs: ["auth", "login"]
54144
- },
54145
- "gemini-cli": {
54146
- id: "gemini-cli",
54147
- displayName: "Gemini CLI",
54148
- statusBarName: "Gemini CLI",
54149
- accessType: "subscription",
54150
- credentialType: "cli-login",
54151
- modelDiscoveryType: "static",
54152
- statusCheck: "cli-login",
54153
- listModels: "static",
54154
- validateModel: "static-list",
54155
- authMode: "enterprise-login",
54156
- legalPath: "official Gemini Code Assist login",
54157
- accessPathLabel: "subscription login via official Gemini CLI",
54158
- commandCandidates: ["gemini"],
54159
- versionArgs: ["--version"],
54160
- loginArgs: [],
54161
- unsupportedPersonalAccountMessage: "Personal Google account login is not enabled by UR-AGENT. Use an official Gemini Code Assist Standard/Enterprise path if your Gemini CLI supports it."
54162
- },
54163
- "antigravity-cli": {
54164
- id: "antigravity-cli",
54165
- displayName: "Antigravity",
54166
- statusBarName: "Antigravity",
54167
- accessType: "subscription",
54168
- credentialType: "cli-login",
54169
- modelDiscoveryType: "static",
54170
- statusCheck: "cli-login",
54171
- listModels: "static",
54172
- validateModel: "static-list",
54173
- authMode: "personal-login",
54174
- legalPath: "official Antigravity CLI login, where supported",
54175
- accessPathLabel: "subscription login via official Antigravity CLI",
54176
- commandCandidates: ["agy", "antigravity", "google-antigravity", "ag"],
54177
- versionArgs: ["--version"],
54178
- loginArgs: []
54179
- },
54180
- "openai-api": {
54181
- id: "openai-api",
54182
- displayName: "OpenAI API",
54183
- statusBarName: "OpenAI",
54184
- accessType: "api",
54185
- credentialType: "api-key",
54186
- modelDiscoveryType: "static",
54187
- statusCheck: "api-key",
54188
- listModels: "static",
54189
- validateModel: "static-list",
54190
- authMode: "api",
54191
- legalPath: "OPENAI_API_KEY",
54192
- accessPathLabel: "API key from OPENAI_API_KEY",
54193
- envKey: "OPENAI_API_KEY"
54194
- },
54195
- "anthropic-api": {
54196
- id: "anthropic-api",
54197
- displayName: "Claude API",
54198
- statusBarName: "Claude API",
54199
- accessType: "api",
54200
- credentialType: "api-key",
54201
- modelDiscoveryType: "static",
54202
- statusCheck: "api-key",
54203
- listModels: "static",
54204
- validateModel: "static-list",
54205
- authMode: "api",
54206
- legalPath: "ANTHROPIC_API_KEY",
54207
- accessPathLabel: "API key from ANTHROPIC_API_KEY",
54208
- envKey: "ANTHROPIC_API_KEY"
54209
- },
54210
- "gemini-api": {
54211
- id: "gemini-api",
54212
- displayName: "Gemini API",
54213
- statusBarName: "Gemini API",
54214
- accessType: "api",
54215
- credentialType: "api-key",
54216
- modelDiscoveryType: "static",
54217
- statusCheck: "api-key",
54218
- listModels: "static",
54219
- validateModel: "static-list",
54220
- authMode: "api",
54221
- legalPath: "GEMINI_API_KEY",
54222
- accessPathLabel: "API key from GEMINI_API_KEY",
54223
- envKey: "GEMINI_API_KEY"
54224
- },
54225
- openrouter: {
54226
- id: "openrouter",
54227
- displayName: "OpenRouter",
54228
- statusBarName: "OpenRouter",
54229
- accessType: "api",
54230
- credentialType: "api-key",
54231
- modelDiscoveryType: "static",
54232
- statusCheck: "api-key",
54233
- listModels: "static",
54234
- validateModel: "static-list",
54235
- authMode: "api",
54236
- legalPath: "OPENROUTER_API_KEY",
54237
- accessPathLabel: "API key from OPENROUTER_API_KEY",
54238
- envKey: "OPENROUTER_API_KEY"
54239
- },
54240
- "openai-compatible": {
54241
- id: "openai-compatible",
54242
- displayName: "OpenAI-compatible",
54243
- statusBarName: "OpenAI-compatible",
54244
- accessType: "api",
54245
- accessTypeLabel: "server/api",
54246
- credentialType: "openai-compatible-endpoint",
54247
- modelDiscoveryType: "live",
54248
- statusCheck: "endpoint",
54249
- listModels: "openai-compatible-models",
54250
- validateModel: "discovered-list",
54251
- authMode: "api",
54252
- legalPath: "user-selected OpenAI-compatible base URL with API key only when required by that endpoint",
54253
- accessPathLabel: "OpenAI-compatible endpoint",
54254
- envKey: "OPENAI_API_KEY",
54255
- endpointKind: "openai-compatible"
54256
- },
54257
- ollama: {
54258
- id: "ollama",
54259
- displayName: "Ollama",
54260
- statusBarName: "Ollama",
54261
- accessType: "local",
54262
- credentialType: "local-runtime",
54263
- modelDiscoveryType: "live",
54264
- statusCheck: "endpoint",
54265
- listModels: "ollama-tags",
54266
- validateModel: "discovered-list",
54267
- authMode: "local",
54268
- legalPath: "localhost Ollama runtime",
54269
- accessPathLabel: "local Ollama runtime",
54270
- defaultBaseUrl: "http://localhost:11434",
54271
- endpointKind: "ollama"
54272
- },
54273
- lmstudio: {
54274
- id: "lmstudio",
54275
- displayName: "LM Studio",
54276
- statusBarName: "LM Studio",
54277
- accessType: "server",
54278
- accessTypeLabel: "local/server",
54279
- credentialType: "openai-compatible-endpoint",
54280
- modelDiscoveryType: "live",
54281
- statusCheck: "endpoint",
54282
- listModels: "openai-compatible-models",
54283
- validateModel: "discovered-list",
54284
- authMode: "local",
54285
- legalPath: "local OpenAI-compatible server",
54286
- accessPathLabel: "local OpenAI-compatible endpoint",
54287
- defaultBaseUrl: "http://localhost:1234/v1",
54288
- endpointKind: "openai-compatible"
54289
- },
54290
- "llama.cpp": {
54291
- id: "llama.cpp",
54292
- displayName: "llama.cpp",
54293
- statusBarName: "llama.cpp",
54294
- accessType: "server",
54295
- accessTypeLabel: "local/server",
54296
- credentialType: "openai-compatible-endpoint",
54297
- modelDiscoveryType: "live",
54298
- statusCheck: "endpoint",
54299
- listModels: "openai-compatible-models",
54300
- validateModel: "discovered-list",
54301
- authMode: "local",
54302
- legalPath: "local OpenAI-compatible server",
54303
- accessPathLabel: "local OpenAI-compatible endpoint",
54304
- defaultBaseUrl: "http://localhost:8080/v1",
54305
- endpointKind: "openai-compatible"
54306
- },
54307
- vllm: {
54308
- id: "vllm",
54309
- displayName: "vLLM",
54310
- statusBarName: "vLLM",
54311
- accessType: "server",
54312
- accessTypeLabel: "local/server",
54313
- credentialType: "openai-compatible-endpoint",
54314
- modelDiscoveryType: "live",
54315
- statusCheck: "endpoint",
54316
- listModels: "openai-compatible-models",
54317
- validateModel: "discovered-list",
54318
- authMode: "local",
54319
- legalPath: "OpenAI-compatible server",
54320
- accessPathLabel: "OpenAI-compatible endpoint runtime",
54321
- defaultBaseUrl: "http://localhost:8000/v1",
54322
- endpointKind: "openai-compatible"
54323
- }
54324
- };
54325
- PROVIDER_ALIAS_ENTRIES = [
54326
- {
54327
- canonical: "codex-cli",
54328
- aliases: ["chatgpt", "codex", "codex cli", "openai codex", "chatgpt codex"]
54329
- },
54330
- {
54331
- canonical: "claude-code-cli",
54332
- aliases: ["claude", "claude code", "claude cli", "anthropic claude"]
54333
- },
54334
- {
54335
- canonical: "gemini-cli",
54336
- aliases: ["gemini", "gemini cli", "gemini code assist", "google gemini cli"]
54337
- },
54338
- {
54339
- canonical: "antigravity-cli",
54340
- aliases: ["antigravity", "antigravity cli", "agy", "ag", "google antigravity"]
54341
- },
54342
- {
54343
- canonical: "openai-api",
54344
- aliases: ["openai", "openai api"]
54345
- },
54346
- {
54347
- canonical: "anthropic-api",
54348
- aliases: ["anthropic", "anthropic claude api", "claude api"]
54349
- },
54350
- {
54351
- canonical: "gemini-api",
54352
- aliases: ["gemini api", "google gemini api"]
54353
- },
54354
- {
54355
- canonical: "openrouter",
54356
- aliases: ["openrouter api"]
54357
- },
54358
- {
54359
- canonical: "openai-compatible",
54360
- aliases: ["compatible", "openai compatible", "openai compatible api"]
54361
- },
54362
- {
54363
- canonical: "ollama",
54364
- aliases: ["ollama local"]
54365
- },
54366
- {
54367
- canonical: "lmstudio",
54368
- aliases: ["lm studio", "lm-studio"]
54369
- },
54370
- {
54371
- canonical: "llama.cpp",
54372
- aliases: ["llama cpp", "llamacpp", "llama-cpp"]
54373
- },
54374
- {
54375
- canonical: "vllm",
54376
- aliases: ["vllm server"]
54377
- }
54378
- ];
54379
- PROVIDER_ALIASES = Object.fromEntries(PROVIDER_ALIAS_ENTRIES.flatMap((entry) => [
54380
- [normalizeProviderInput(entry.canonical), entry.canonical],
54381
- [entry.canonical, entry.canonical],
54382
- ...entry.aliases.map((alias) => [normalizeProviderInput(alias), entry.canonical])
54383
- ]));
54384
- PROVIDER_MODELS = {
54385
- "codex-cli": [
54386
- { id: "codex/gpt-5.5", displayName: "GPT-5.5 (Codex CLI)", description: "Subscription model through official Codex CLI login", isDefault: true },
54387
- { id: "codex/gpt-5.4", displayName: "GPT-5.4 (Codex CLI)", description: "Subscription model through official Codex CLI login" },
54388
- { id: "codex/gpt-5.4-mini", displayName: "GPT-5.4 Mini (Codex CLI)", description: "Fast subscription model through official Codex CLI login" },
54389
- { id: "codex/gpt-4o", displayName: "GPT-4o (Codex CLI)", description: "Subscription model through official Codex CLI login" },
54390
- { id: "codex/gpt-4o-mini", displayName: "GPT-4o Mini (Codex CLI)", description: "Fast subscription model through official Codex CLI login" },
54391
- { id: "codex/o1", displayName: "o1 (Codex CLI)", description: "Reasoning model through official Codex CLI login" },
54392
- { id: "codex/o3-mini", displayName: "o3-mini (Codex CLI)", description: "Fast reasoning model through official Codex CLI login" }
54393
- ],
54394
- "claude-code-cli": [
54395
- { id: "claude-code/sonnet-5", displayName: "Claude Sonnet 5 (Claude Code)", description: "Subscription model through official Claude Code login", isDefault: true },
54396
- { id: "claude-code/opus-4-8", displayName: "Claude Opus 4.8 (Claude Code)", description: "Subscription model through official Claude Code login" },
54397
- { id: "claude-code/opus-4-7", displayName: "Claude Opus 4.7 (Claude Code)", description: "Subscription model through official Claude Code login" },
54398
- { id: "claude-code/opus-4-6", displayName: "Claude Opus 4.6 (Claude Code)", description: "Subscription model through official Claude Code login" },
54399
- { id: "claude-code/opus-4-5", displayName: "Claude Opus 4.5 (Claude Code)", description: "Subscription model through official Claude Code login" },
54400
- { id: "claude-code/sonnet-4-6", displayName: "Claude Sonnet 4.6 (Claude Code)", description: "Subscription model through official Claude Code login" },
54401
- { id: "claude-code/sonnet-4-5", displayName: "Claude Sonnet 4.5 (Claude Code)", description: "Subscription model through official Claude Code login" },
54402
- { id: "claude-code/haiku-4-5", displayName: "Claude Haiku 4.5 (Claude Code)", description: "Subscription model through official Claude Code login" }
54403
- ],
54404
- "gemini-cli": [
54405
- { id: "gemini-cli/gemini-3.5-flash", displayName: "Gemini 3.5 Flash (Gemini CLI)", description: "Subscription model through official Gemini CLI login", isDefault: true },
54406
- { id: "gemini-cli/gemini-3.1-pro", displayName: "Gemini 3.1 Pro (Gemini CLI)", description: "Subscription model through official Gemini CLI login" },
54407
- { id: "gemini-cli/gemini-3.1-flash-lite", displayName: "Gemini 3.1 Flash Lite (Gemini CLI)", description: "Subscription model through official Gemini CLI login" },
54408
- { id: "gemini-cli/gemini-2.5-pro", displayName: "Gemini 2.5 Pro (Gemini CLI)", description: "Subscription model through official Gemini CLI login" },
54409
- { id: "gemini-cli/gemini-2.5-flash", displayName: "Gemini 2.5 Flash (Gemini CLI)", description: "Subscription model through official Gemini CLI login" },
54410
- { id: "gemini-cli/gemini-2.5-flash-lite", displayName: "Gemini 2.5 Flash Lite (Gemini CLI)", description: "Subscription model through official Gemini CLI login" }
54411
- ],
54412
- "antigravity-cli": [
54413
- { id: "antigravity/gemini-3.5-flash", displayName: "Gemini 3.5 Flash (Antigravity)", description: "Subscription model through official Antigravity login", isDefault: true },
54414
- { id: "antigravity/gemini-2.5-pro", displayName: "Gemini 2.5 Pro (Antigravity)", description: "Subscription model through official Antigravity login" },
54415
- { id: "antigravity/gemini-2.5-flash", displayName: "Gemini 2.5 Flash (Antigravity)", description: "Subscription model through official Antigravity login" }
54416
- ],
54417
- "openai-api": [
54418
- { id: "gpt-5.5", displayName: "GPT-5.5", description: "Latest OpenAI model", isDefault: true },
54419
- { id: "gpt-5.4", displayName: "GPT-5.4", description: "Advanced reasoning and coding" },
54420
- { id: "gpt-5.4-mini", displayName: "GPT-5.4 Mini", description: "Fast, efficient variant" },
54421
- { id: "gpt-4o", displayName: "GPT-4o", description: "Previous generation flagship" },
54422
- { id: "gpt-4o-mini", displayName: "GPT-4o Mini", description: "Fast GPT-4o variant" },
54423
- { id: "o1", displayName: "o1", description: "Deep reasoning model" },
54424
- { id: "o3-mini", displayName: "o3-mini", description: "Fast reasoning model" }
54425
- ],
54426
- "anthropic-api": [
54427
- { id: "claude-sonnet-5", displayName: "Claude Sonnet 5", description: "Balanced performance and speed", isDefault: true },
54428
- { id: "claude-opus-4-8", displayName: "Claude Opus 4.8", description: "Most powerful Claude model" },
54429
- { id: "claude-opus-4-7", displayName: "Claude Opus 4.7", description: "High-end reasoning" },
54430
- { id: "claude-opus-4-6", displayName: "Claude Opus 4.6", description: "Advanced problem solving" },
54431
- { id: "claude-opus-4-5", displayName: "Claude Opus 4.5", description: "Previous Opus generation" },
54432
- { id: "claude-sonnet-4-6", displayName: "Claude Sonnet 4.6", description: "Fast Sonnet variant" },
54433
- { id: "claude-sonnet-4-5", displayName: "Claude Sonnet 4.5", description: "Previous Sonnet generation" },
54434
- { id: "claude-haiku-4-5", displayName: "Claude Haiku 4.5", description: "Fastest Claude model" }
54435
- ],
54436
- "gemini-api": [
54437
- { id: "gemini-3.5-flash", displayName: "Gemini 3.5 Flash", description: "Most intelligent for agentic tasks", isDefault: true },
54438
- { id: "gemini-3.1-pro", displayName: "Gemini 3.1 Pro", description: "Advanced problem solving (preview)" },
54439
- { id: "gemini-3.1-flash-lite", displayName: "Gemini 3.1 Flash Lite", description: "Budget-friendly performance" },
54440
- { id: "gemini-2.5-pro", displayName: "Gemini 2.5 Pro", description: "Complex reasoning and coding" },
54441
- { id: "gemini-2.5-flash", displayName: "Gemini 2.5 Flash", description: "Low-latency tasks" },
54442
- { id: "gemini-2.5-flash-lite", displayName: "Gemini 2.5 Flash Lite", description: "Fastest Gemini model" }
54443
- ],
54444
- openrouter: [
54445
- { id: "openai/gpt-5.5", displayName: "GPT-5.5", description: "OpenAI GPT-5.5 via OpenRouter", isDefault: true },
54446
- { id: "openai/gpt-5.4", displayName: "GPT-5.4", description: "OpenAI GPT-5.4 via OpenRouter" },
54447
- { id: "openai/gpt-4o", displayName: "GPT-4o", description: "OpenAI GPT-4o via OpenRouter" },
54448
- { id: "anthropic/claude-sonnet-5", displayName: "Claude Sonnet 5", description: "Anthropic Claude via OpenRouter" },
54449
- { id: "anthropic/claude-opus-4-8", displayName: "Claude Opus 4.8", description: "Anthropic Claude via OpenRouter" },
54450
- { id: "google/gemini-3.5-flash", displayName: "Gemini 3.5 Flash", description: "Google Gemini via OpenRouter" },
54451
- { id: "google/gemini-2.5-pro", displayName: "Gemini 2.5 Pro", description: "Google Gemini via OpenRouter" }
54452
- ],
54453
- "openai-compatible": [
54454
- { id: "custom", displayName: "Custom Model", description: "Model name from provider endpoint", isDynamic: true }
54455
- ],
54456
- ollama: [
54457
- { id: "dynamic", displayName: "Discovered Models", description: "Models discovered from Ollama server", isDynamic: true, isDefault: true }
54458
- ],
54459
- lmstudio: [
54460
- { id: "dynamic", displayName: "Discovered Models", description: "Models discovered from LM Studio server", isDynamic: true, isDefault: true }
54461
- ],
54462
- "llama.cpp": [
54463
- { id: "dynamic", displayName: "Discovered Models", description: "Models discovered from llama.cpp server", isDynamic: true, isDefault: true }
54464
- ],
54465
- vllm: [
54466
- { id: "dynamic", displayName: "Discovered Models", description: "Models discovered from vLLM server", isDynamic: true, isDefault: true }
54467
- ]
54468
- };
54469
- cachedModelsByProvider = new Map;
54470
- validateProviderModelCompatibility = validateProviderModelPair;
54471
- });
54472
-
54473
54494
  // src/utils/model/model.ts
54474
54495
  var exports_model = {};
54475
54496
  __export(exports_model, {
@@ -56794,40 +56815,59 @@ var exports_urhqSubscription = {};
56794
56815
  __export(exports_urhqSubscription, {
56795
56816
  createURHQSubscriptionClient: () => createURHQSubscriptionClient
56796
56817
  });
56818
+ import { spawn as spawn3 } from "child_process";
56797
56819
  import { randomUUID as randomUUID5 } from "crypto";
56798
- async function createURHQSubscriptionClient(providerId, options) {
56799
- async function doRequest(params, extraHeaders) {
56800
- const clientRequestId = params?.headers?.["x-client-request-id"];
56820
+ function createURHQSubscriptionClient(providerId, options) {
56821
+ const spec = CLI_SPECS[providerId];
56822
+ if (!spec) {
56823
+ throw new Error(`No subscription CLI dispatch is configured for provider "${providerId}".`);
56824
+ }
56825
+ const run = options.runner ?? defaultRunner;
56826
+ async function doRequest(params, requestOptions) {
56827
+ const model = cliModelName(params.model ?? options.model ?? "");
56828
+ if (!model) {
56829
+ throw new Error(`Provider "${providerId}" requires a model to dispatch to its CLI.`);
56830
+ }
56831
+ const prompt = messagesToPrompt(params);
56832
+ const result = await run(options.commandPath, spec.args(model, prompt), {
56833
+ signal: requestOptions?.signal,
56834
+ timeoutMs: options.timeoutMs ?? 120000
56835
+ });
56836
+ if (result.code !== 0) {
56837
+ throw new Error(`Subscription CLI "${options.commandPath}" for ${providerId} exited ${result.code}: ${result.stderr.trim() || result.stdout.trim() || "no output"}`);
56838
+ }
56839
+ const text = extractText(result.stdout);
56840
+ if (!text) {
56841
+ throw new Error(`Subscription CLI "${options.commandPath}" for ${providerId} produced no output.`);
56842
+ }
56801
56843
  const data = {
56802
56844
  id: `${providerId}-${randomUUID5()}`,
56803
56845
  type: "message",
56804
56846
  role: "assistant",
56805
- model: params.model,
56806
- content: [{ type: "text", text: "Subscription CLI response" }],
56847
+ model: params.model ?? options.model,
56848
+ content: [{ type: "text", text }],
56807
56849
  stop_reason: "end_turn",
56808
56850
  stop_sequence: null,
56809
56851
  usage: {
56810
- input_tokens: 0,
56811
- output_tokens: 0,
56852
+ input_tokens: estimateTokens(prompt),
56853
+ output_tokens: estimateTokens(text),
56812
56854
  cache_creation_input_tokens: 0,
56813
56855
  cache_read_input_tokens: 0
56814
56856
  }
56815
56857
  };
56858
+ const clientRequestId = params?.headers?.["x-client-request-id"];
56816
56859
  return {
56817
56860
  data,
56818
- response: {
56819
- headers: clientRequestId ? { "x-client-request-id": clientRequestId } : {},
56820
- ...extraHeaders
56821
- }
56861
+ response: { headers: clientRequestId ? { "x-client-request-id": clientRequestId } : {} }
56822
56862
  };
56823
56863
  }
56824
56864
  const messagesAPI = {
56825
- create(params, options2) {
56865
+ create(params, requestOptions) {
56826
56866
  if (params.stream) {
56827
- const requestPromise = doRequest(params, options2?.headers);
56867
+ const pending = doRequest(params, requestOptions);
56828
56868
  return {
56829
56869
  async withResponse() {
56830
- const { response, data } = await requestPromise;
56870
+ const { response, data } = await pending;
56831
56871
  return {
56832
56872
  data: createOneShotMessageStream(data),
56833
56873
  response,
@@ -56836,33 +56876,121 @@ async function createURHQSubscriptionClient(providerId, options) {
56836
56876
  }
56837
56877
  };
56838
56878
  }
56839
- return doRequest(params, options2?.headers).then(({ response, data }) => ({
56879
+ return doRequest(params, requestOptions).then(({ response, data }) => ({
56840
56880
  ...data,
56841
- withResponse: () => ({
56842
- data,
56843
- response,
56844
- request_id: data.id
56845
- })
56881
+ withResponse: () => ({ data, response, request_id: data.id })
56846
56882
  }));
56847
56883
  },
56848
56884
  async countTokens(params) {
56849
- return {
56850
- input_tokens: estimateTokenCount(params)
56851
- };
56852
- }
56853
- };
56854
- return {
56855
- beta: {
56856
- messages: messagesAPI
56885
+ return { input_tokens: estimateTokens(messagesToPrompt(params)) };
56857
56886
  }
56858
56887
  };
56888
+ return { beta: { messages: messagesAPI } };
56859
56889
  }
56860
- function estimateTokenCount(params) {
56861
- const text = JSON.stringify(params.messages ?? []);
56862
- return Math.ceil(text.length / 4);
56890
+ function cliModelName(model) {
56891
+ const slash = model.indexOf("/");
56892
+ return slash >= 0 ? model.slice(slash + 1) : model;
56863
56893
  }
56894
+ function messagesToPrompt(params) {
56895
+ const parts = [];
56896
+ const system = systemToText3(params.system);
56897
+ if (system)
56898
+ parts.push(system);
56899
+ const messages = params.messages ?? [];
56900
+ const label = messages.length > 1;
56901
+ for (const message of messages) {
56902
+ const text = contentToText2(message.content);
56903
+ if (!text)
56904
+ continue;
56905
+ parts.push(label ? `${capitalize2(message.role)}: ${text}` : text);
56906
+ }
56907
+ return parts.join(`
56908
+
56909
+ `);
56910
+ }
56911
+ function extractText(stdout) {
56912
+ const raw = stdout.trim();
56913
+ if (!raw)
56914
+ return "";
56915
+ try {
56916
+ const parsed = JSON.parse(raw);
56917
+ if (typeof parsed === "string")
56918
+ return parsed;
56919
+ const candidate = parsed.result ?? parsed.response ?? parsed.text ?? parsed.output ?? parsed.message?.content ?? parsed.choices?.[0]?.message?.content ?? (Array.isArray(parsed.content) ? parsed.content.map((block) => block?.text ?? "").join("") : undefined);
56920
+ if (typeof candidate === "string" && candidate.trim())
56921
+ return candidate;
56922
+ } catch {}
56923
+ return raw;
56924
+ }
56925
+ function systemToText3(system) {
56926
+ if (!system)
56927
+ return "";
56928
+ if (typeof system === "string")
56929
+ return system;
56930
+ if (Array.isArray(system))
56931
+ return system.map((block) => block?.text ?? "").join(`
56932
+
56933
+ `);
56934
+ return "";
56935
+ }
56936
+ function contentToText2(content) {
56937
+ if (typeof content === "string")
56938
+ return content;
56939
+ if (!Array.isArray(content))
56940
+ return "";
56941
+ return content.map((block) => {
56942
+ if (typeof block === "string")
56943
+ return block;
56944
+ if (block?.type === "text")
56945
+ return block.text ?? "";
56946
+ if (block?.type === "tool_result")
56947
+ return contentToText2(block.content);
56948
+ return "";
56949
+ }).join(`
56950
+ `);
56951
+ }
56952
+ function capitalize2(value) {
56953
+ return value ? value[0].toUpperCase() + value.slice(1) : value;
56954
+ }
56955
+ function estimateTokens(text) {
56956
+ return Math.ceil((text?.length ?? 0) / 4);
56957
+ }
56958
+ var CLI_SPECS, defaultRunner = (command, args, options) => new Promise((resolve8, reject) => {
56959
+ const child = spawn3(command, args, { stdio: ["pipe", "pipe", "pipe"], signal: options.signal });
56960
+ let stdout = "";
56961
+ let stderr = "";
56962
+ const timer = options.timeoutMs ? setTimeout(() => child.kill("SIGKILL"), options.timeoutMs) : undefined;
56963
+ child.stdout?.on("data", (chunk) => {
56964
+ stdout += chunk;
56965
+ });
56966
+ child.stderr?.on("data", (chunk) => {
56967
+ stderr += chunk;
56968
+ });
56969
+ child.on("error", (error40) => {
56970
+ if (timer)
56971
+ clearTimeout(timer);
56972
+ reject(error40);
56973
+ });
56974
+ child.on("close", (code) => {
56975
+ if (timer)
56976
+ clearTimeout(timer);
56977
+ resolve8({ code: code ?? 1, stdout, stderr });
56978
+ });
56979
+ if (options.input) {
56980
+ child.stdin?.write(options.input);
56981
+ }
56982
+ child.stdin?.end();
56983
+ });
56864
56984
  var init_urhqSubscription = __esm(() => {
56865
56985
  init_streamingAdapters();
56986
+ CLI_SPECS = {
56987
+ "codex-cli": { args: (model, prompt) => ["exec", "--model", model, prompt] },
56988
+ "claude-code-cli": {
56989
+ args: (model, prompt) => ["-p", prompt, "--model", model, "--output-format", "json"]
56990
+ },
56991
+ "gemini-cli": { args: (model, prompt) => ["-p", prompt, "-m", model] },
56992
+ "antigravity-cli": { args: (model, prompt) => ["-p", prompt, "--model", model] }
56993
+ };
56866
56994
  });
56867
56995
 
56868
56996
  // src/services/api/openrouter.ts
@@ -56938,7 +57066,7 @@ async function createOpenRouterClient(options) {
56938
57066
  },
56939
57067
  async countTokens(params) {
56940
57068
  return {
56941
- input_tokens: estimateTokenCount2(params)
57069
+ input_tokens: estimateTokenCount(params)
56942
57070
  };
56943
57071
  }
56944
57072
  };
@@ -56948,7 +57076,7 @@ async function createOpenRouterClient(options) {
56948
57076
  }
56949
57077
  };
56950
57078
  }
56951
- function estimateTokenCount2(params) {
57079
+ function estimateTokenCount(params) {
56952
57080
  const text = JSON.stringify(params.messages ?? []);
56953
57081
  return Math.ceil(text.length / 4);
56954
57082
  }
@@ -56964,116 +57092,219 @@ __export(exports_standardAPI, {
56964
57092
  });
56965
57093
  import { randomUUID as randomUUID7 } from "crypto";
56966
57094
  async function createStandardAPIClient(options) {
56967
- const { providerId, apiKey, baseUrl, maxRetries } = options;
57095
+ const { providerId, apiKey, baseUrl } = options;
57096
+ const family = getProviderFamily(providerId);
56968
57097
  async function doRequest(params, extraHeaders) {
56969
- const endpoint = getAPIEndpoint(providerId, baseUrl);
57098
+ const endpoint = getAPIEndpoint(family, baseUrl, params.model);
56970
57099
  const clientRequestId = params?.headers?.["x-client-request-id"];
56971
- const response = await axios_default.post(endpoint, buildAPIRequest(providerId, params), {
57100
+ const response = await axios_default.post(endpoint, buildAPIRequest(family, params), {
56972
57101
  headers: {
56973
57102
  "Content-Type": "application/json",
56974
- Authorization: `Bearer ${apiKey}`,
57103
+ ...buildAuthHeaders(family, apiKey, params),
56975
57104
  ...clientRequestId && { "x-client-request-id": clientRequestId },
56976
57105
  ...extraHeaders
56977
57106
  },
56978
57107
  timeout: 60000
56979
57108
  });
56980
- return { response, data: parseAPIResponse(providerId, response.data) };
57109
+ return { response, data: parseAPIResponse(family, response.data, params.model) };
56981
57110
  }
56982
57111
  const messagesAPI = {
56983
- create(params, options2) {
57112
+ create(params, requestOptions) {
56984
57113
  if (params.stream) {
56985
- const requestPromise = doRequest(params, options2?.headers);
57114
+ const pending = doRequest(params, requestOptions?.headers);
56986
57115
  return {
56987
57116
  async withResponse() {
56988
- const { response, data } = await requestPromise;
57117
+ const { response, data } = await pending;
56989
57118
  return {
56990
57119
  data: createOneShotMessageStream(data),
56991
57120
  response,
56992
- request_id: response.data?.id ?? response.headers?.["x-request-id"] ?? randomUUID7()
57121
+ request_id: data.id ?? response.headers?.["x-request-id"] ?? randomUUID7()
56993
57122
  };
56994
57123
  }
56995
57124
  };
56996
57125
  }
56997
- return doRequest(params, options2?.headers).then(({ response, data }) => ({
57126
+ return doRequest(params, requestOptions?.headers).then(({ response, data }) => ({
56998
57127
  ...data,
56999
57128
  withResponse: () => ({
57000
57129
  data,
57001
57130
  response,
57002
- request_id: response.data?.id ?? response.headers?.["x-request-id"] ?? randomUUID7()
57131
+ request_id: data.id ?? response.headers?.["x-request-id"] ?? randomUUID7()
57003
57132
  })
57004
57133
  }));
57005
57134
  },
57006
57135
  async countTokens(params) {
57007
- return {
57008
- input_tokens: estimateTokenCount3(params)
57009
- };
57010
- }
57011
- };
57012
- return {
57013
- beta: {
57014
- messages: messagesAPI
57136
+ return { input_tokens: estimateTokenCount2(params) };
57015
57137
  }
57016
57138
  };
57139
+ return { beta: { messages: messagesAPI } };
57017
57140
  }
57018
- function getAPIEndpoint(providerId, baseUrl) {
57019
- switch (providerId) {
57020
- case "openai-api":
57141
+ function getAPIEndpoint(family, baseUrl, model) {
57142
+ switch (family) {
57143
+ case "openai":
57021
57144
  return baseUrl ?? "https://api.openai.com/v1/chat/completions";
57022
- case "anthropic-api":
57145
+ case "anthropic":
57023
57146
  return baseUrl ?? "https://api.anthropic.com/v1/messages";
57024
- case "gemini-api":
57025
- return baseUrl ?? "https://generativelanguage.googleapis.com/v1beta/models";
57147
+ case "google": {
57148
+ const root2 = baseUrl ?? "https://generativelanguage.googleapis.com/v1beta";
57149
+ return `${root2.replace(/\/$/, "")}/models/${model}:generateContent`;
57150
+ }
57026
57151
  default:
57027
57152
  return baseUrl ?? "";
57028
57153
  }
57029
57154
  }
57030
- function buildAPIRequest(providerId, params) {
57031
- switch (providerId) {
57032
- case "openai-api":
57155
+ function buildAuthHeaders(family, apiKey, params) {
57156
+ switch (family) {
57157
+ case "anthropic": {
57158
+ const headers = {
57159
+ "x-api-key": apiKey ?? "",
57160
+ "anthropic-version": ANTHROPIC_VERSION
57161
+ };
57162
+ if (Array.isArray(params.betas) && params.betas.length > 0) {
57163
+ headers["anthropic-beta"] = params.betas.join(",");
57164
+ }
57165
+ return headers;
57166
+ }
57167
+ case "google":
57168
+ return { "x-goog-api-key": apiKey ?? "" };
57169
+ default:
57170
+ return { Authorization: `Bearer ${apiKey ?? ""}` };
57171
+ }
57172
+ }
57173
+ function buildAPIRequest(family, params) {
57174
+ switch (family) {
57175
+ case "openai":
57033
57176
  return {
57034
57177
  model: params.model,
57035
57178
  messages: toOpenAIMessages2(params),
57036
57179
  max_tokens: params.max_tokens,
57180
+ ...params.temperature !== undefined && { temperature: params.temperature },
57037
57181
  stream: false
57038
57182
  };
57039
- case "anthropic-api":
57183
+ case "anthropic":
57040
57184
  return {
57041
57185
  model: params.model,
57186
+ ...params.system && { system: params.system },
57042
57187
  messages: params.messages,
57043
- max_tokens: params.max_tokens || 4096,
57188
+ max_tokens: params.max_tokens ?? 4096,
57189
+ ...params.temperature !== undefined && { temperature: params.temperature },
57044
57190
  stream: false
57045
57191
  };
57192
+ case "google":
57193
+ return {
57194
+ contents: toGeminiContents(params),
57195
+ ...geminiSystemInstruction(params) && {
57196
+ systemInstruction: geminiSystemInstruction(params)
57197
+ },
57198
+ generationConfig: {
57199
+ ...params.max_tokens && { maxOutputTokens: params.max_tokens },
57200
+ ...params.temperature !== undefined && { temperature: params.temperature }
57201
+ }
57202
+ };
57046
57203
  default:
57047
57204
  return params;
57048
57205
  }
57049
57206
  }
57207
+ function parseAPIResponse(family, data, fallbackModel) {
57208
+ switch (family) {
57209
+ case "openai":
57210
+ return {
57211
+ id: data.id ?? `openai-${randomUUID7()}`,
57212
+ type: "message",
57213
+ role: "assistant",
57214
+ model: data.model ?? fallbackModel,
57215
+ content: [{ type: "text", text: data.choices?.[0]?.message?.content ?? "" }],
57216
+ stop_reason: mapStopReason(data.choices?.[0]?.finish_reason),
57217
+ stop_sequence: null,
57218
+ usage: {
57219
+ input_tokens: data.usage?.prompt_tokens ?? 0,
57220
+ output_tokens: data.usage?.completion_tokens ?? 0,
57221
+ cache_creation_input_tokens: 0,
57222
+ cache_read_input_tokens: 0
57223
+ }
57224
+ };
57225
+ case "anthropic":
57226
+ return {
57227
+ id: data.id ?? `anthropic-${randomUUID7()}`,
57228
+ type: "message",
57229
+ role: "assistant",
57230
+ model: data.model ?? fallbackModel,
57231
+ content: Array.isArray(data.content) ? data.content.map((block) => ({ type: block.type, text: block.text })) : [{ type: "text", text: "" }],
57232
+ stop_reason: data.stop_reason ?? "end_turn",
57233
+ stop_sequence: data.stop_sequence ?? null,
57234
+ usage: {
57235
+ input_tokens: data.usage?.input_tokens ?? 0,
57236
+ output_tokens: data.usage?.output_tokens ?? 0,
57237
+ cache_creation_input_tokens: data.usage?.cache_creation_input_tokens ?? 0,
57238
+ cache_read_input_tokens: data.usage?.cache_read_input_tokens ?? 0
57239
+ }
57240
+ };
57241
+ case "google": {
57242
+ const parts = data.candidates?.[0]?.content?.parts ?? [];
57243
+ return {
57244
+ id: `gemini-${randomUUID7()}`,
57245
+ type: "message",
57246
+ role: "assistant",
57247
+ model: fallbackModel,
57248
+ content: [{ type: "text", text: parts.map((part) => part?.text ?? "").join("") }],
57249
+ stop_reason: mapStopReason(data.candidates?.[0]?.finishReason),
57250
+ stop_sequence: null,
57251
+ usage: {
57252
+ input_tokens: data.usageMetadata?.promptTokenCount ?? 0,
57253
+ output_tokens: data.usageMetadata?.candidatesTokenCount ?? 0,
57254
+ cache_creation_input_tokens: 0,
57255
+ cache_read_input_tokens: 0
57256
+ }
57257
+ };
57258
+ }
57259
+ default:
57260
+ return data;
57261
+ }
57262
+ }
57263
+ function mapStopReason(reason) {
57264
+ switch (reason) {
57265
+ case "length":
57266
+ case "MAX_TOKENS":
57267
+ return "max_tokens";
57268
+ case "stop":
57269
+ case "STOP":
57270
+ case undefined:
57271
+ return "end_turn";
57272
+ default:
57273
+ return "end_turn";
57274
+ }
57275
+ }
57050
57276
  function toOpenAIMessages2(params) {
57051
57277
  const messages = [];
57052
- const system = systemToText3(params.system);
57053
- if (system) {
57278
+ const system = systemToText4(params.system);
57279
+ if (system)
57054
57280
  messages.push({ role: "system", content: system });
57055
- }
57056
57281
  for (const message of params.messages ?? []) {
57057
- messages.push({
57058
- role: message.role,
57059
- content: contentToText2(message.content)
57060
- });
57282
+ messages.push({ role: message.role, content: contentToText3(message.content) });
57061
57283
  }
57062
57284
  return messages;
57063
57285
  }
57064
- function systemToText3(system) {
57286
+ function toGeminiContents(params) {
57287
+ return (params.messages ?? []).map((message) => ({
57288
+ role: message.role === "assistant" ? "model" : "user",
57289
+ parts: [{ text: contentToText3(message.content) }]
57290
+ }));
57291
+ }
57292
+ function geminiSystemInstruction(params) {
57293
+ const system = systemToText4(params.system);
57294
+ return system ? { parts: [{ text: system }] } : undefined;
57295
+ }
57296
+ function systemToText4(system) {
57065
57297
  if (!system)
57066
57298
  return "";
57067
57299
  if (typeof system === "string")
57068
57300
  return system;
57069
- if (Array.isArray(system)) {
57301
+ if (Array.isArray(system))
57070
57302
  return system.map((block) => block?.text ?? "").join(`
57071
57303
 
57072
57304
  `);
57073
- }
57074
57305
  return "";
57075
57306
  }
57076
- function contentToText2(content) {
57307
+ function contentToText3(content) {
57077
57308
  if (typeof content === "string")
57078
57309
  return content;
57079
57310
  if (!Array.isArray(content))
@@ -57084,55 +57315,18 @@ function contentToText2(content) {
57084
57315
  if (block?.type === "text")
57085
57316
  return block.text ?? "";
57086
57317
  if (block?.type === "tool_result")
57087
- return block.content ?? "";
57318
+ return contentToText3(block.content);
57088
57319
  return "";
57089
57320
  }).join(`
57090
57321
  `);
57091
57322
  }
57092
- function parseAPIResponse(providerId, data) {
57093
- switch (providerId) {
57094
- case "openai-api":
57095
- return {
57096
- id: `openai-${randomUUID7()}`,
57097
- type: "message",
57098
- role: "assistant",
57099
- model: data.model,
57100
- content: [{ type: "text", text: data.choices?.[0]?.message?.content ?? "" }],
57101
- stop_reason: data.choices?.[0]?.finish_reason ?? "end_turn",
57102
- stop_sequence: null,
57103
- usage: {
57104
- input_tokens: data.usage?.prompt_tokens ?? 0,
57105
- output_tokens: data.usage?.completion_tokens ?? 0,
57106
- cache_creation_input_tokens: 0,
57107
- cache_read_input_tokens: 0
57108
- }
57109
- };
57110
- case "anthropic-api":
57111
- return {
57112
- id: data.id,
57113
- type: "message",
57114
- role: "assistant",
57115
- model: data.model,
57116
- content: data.content?.map((c3) => ({ type: c3.type, text: c3.text })),
57117
- stop_reason: data.stop_reason ?? "end_turn",
57118
- stop_sequence: null,
57119
- usage: {
57120
- input_tokens: data.usage?.input_tokens ?? 0,
57121
- output_tokens: data.usage?.output_tokens ?? 0,
57122
- cache_creation_input_tokens: 0,
57123
- cache_read_input_tokens: 0
57124
- }
57125
- };
57126
- default:
57127
- return data;
57128
- }
57129
- }
57130
- function estimateTokenCount3(params) {
57131
- const text = JSON.stringify(params.messages ?? []);
57132
- return Math.ceil(text.length / 4);
57323
+ function estimateTokenCount2(params) {
57324
+ return Math.ceil(JSON.stringify(params.messages ?? []).length / 4);
57133
57325
  }
57326
+ var ANTHROPIC_VERSION = "2023-06-01";
57134
57327
  var init_standardAPI = __esm(() => {
57135
57328
  init_axios2();
57329
+ init_providerRegistry();
57136
57330
  init_streamingAdapters();
57137
57331
  });
57138
57332
 
@@ -57140,7 +57334,7 @@ var init_standardAPI = __esm(() => {
57140
57334
  function resolveActiveProviderModel(options = {}) {
57141
57335
  const settings = options.settings ?? getInitialSettings();
57142
57336
  const providerSettings = getActiveProviderSettings(settings);
57143
- const providerId = providerSettings.active ?? "ollama";
57337
+ const providerId = providerSettings.active ?? DEFAULT_PROVIDER_ID;
57144
57338
  const provider = getProviderDefinition(providerId);
57145
57339
  if (!provider) {
57146
57340
  throw new Error(`Provider "${providerId}" is selected, but no runtime provider is registered. Run: ur provider list`);
@@ -57153,7 +57347,7 @@ function resolveActiveProviderModel(options = {}) {
57153
57347
  throw new Error(`Provider "${providerId}" is selected, but no model is selected or discoverable. Run /model and choose a model from ${providerId}.`);
57154
57348
  }
57155
57349
  const validation = validateProviderModelPair(providerId, model, {
57156
- allowUncachedDynamic: providerId === "ollama" && !configuredModel
57350
+ allowUncachedDynamic: provider.modelDiscoveryType === "live"
57157
57351
  });
57158
57352
  if (validation.valid === false) {
57159
57353
  throw new Error(formatRuntimeDispatchError({
@@ -69063,7 +69257,7 @@ var init_auth = __esm(() => {
69063
69257
 
69064
69258
  // src/utils/userAgent.ts
69065
69259
  function getURCodeUserAgent() {
69066
- return `ur/${"1.27.6"}`;
69260
+ return `ur/${"1.28.0"}`;
69067
69261
  }
69068
69262
 
69069
69263
  // src/utils/workloadContext.ts
@@ -69085,7 +69279,7 @@ function getUserAgent() {
69085
69279
  const clientApp = process.env.UR_AGENT_SDK_CLIENT_APP ? `, client-app/${process.env.UR_AGENT_SDK_CLIENT_APP}` : "";
69086
69280
  const workload = getWorkload();
69087
69281
  const workloadSuffix = workload ? `, workload/${workload}` : "";
69088
- return `ur-cli/${"1.27.6"} (${process.env.USER_TYPE}, ${process.env.UR_CODE_ENTRYPOINT ?? "cli"}${agentSdkVersion}${clientApp}${workloadSuffix})`;
69282
+ return `ur-cli/${"1.28.0"} (${process.env.USER_TYPE}, ${process.env.UR_CODE_ENTRYPOINT ?? "cli"}${agentSdkVersion}${clientApp}${workloadSuffix})`;
69089
69283
  }
69090
69284
  function getMCPUserAgent() {
69091
69285
  const parts = [];
@@ -69099,7 +69293,7 @@ function getMCPUserAgent() {
69099
69293
  parts.push(`client-app/${process.env.UR_AGENT_SDK_CLIENT_APP}`);
69100
69294
  }
69101
69295
  const suffix = parts.length > 0 ? ` (${parts.join(", ")})` : "";
69102
- return `ur/${"1.27.6"}${suffix}`;
69296
+ return `ur/${"1.28.0"}${suffix}`;
69103
69297
  }
69104
69298
  function getWebFetchUserAgent() {
69105
69299
  return `UR-User (${getURCodeUserAgent()})`;
@@ -69237,7 +69431,7 @@ var init_user = __esm(() => {
69237
69431
  deviceId,
69238
69432
  sessionId: getSessionId(),
69239
69433
  email: getEmail(),
69240
- appVersion: "1.27.6",
69434
+ appVersion: "1.28.0",
69241
69435
  platform: getHostPlatformForAnalytics(),
69242
69436
  organizationUuid,
69243
69437
  accountUuid,
@@ -75754,7 +75948,7 @@ var init_metadata = __esm(() => {
75754
75948
  COMPOUND_OPERATOR_REGEX = /\s*(?:&&|\|\||[;|])\s*/;
75755
75949
  WHITESPACE_REGEX = /\s+/;
75756
75950
  getVersionBase = memoize_default(() => {
75757
- const match = "1.27.6".match(/^\d+\.\d+\.\d+(?:-[a-z]+)?/);
75951
+ const match = "1.28.0".match(/^\d+\.\d+\.\d+(?:-[a-z]+)?/);
75758
75952
  return match ? match[0] : undefined;
75759
75953
  });
75760
75954
  buildEnvContext = memoize_default(async () => {
@@ -75794,7 +75988,7 @@ var init_metadata = __esm(() => {
75794
75988
  isGithubAction: isEnvTruthy(process.env.GITHUB_ACTIONS),
75795
75989
  isURCodeAction: isEnvTruthy(process.env.UR_CODE_ACTION),
75796
75990
  isURAiAuth: isURAISubscriber2(),
75797
- version: "1.27.6",
75991
+ version: "1.28.0",
75798
75992
  versionBase: getVersionBase(),
75799
75993
  buildTime: "",
75800
75994
  deploymentEnvironment: env2.detectDeploymentEnvironment(),
@@ -76464,7 +76658,7 @@ function initialize1PEventLogging() {
76464
76658
  const platform2 = getPlatform();
76465
76659
  const attributes = {
76466
76660
  [import_semantic_conventions4.ATTR_SERVICE_NAME]: "ur",
76467
- [import_semantic_conventions4.ATTR_SERVICE_VERSION]: "1.27.6"
76661
+ [import_semantic_conventions4.ATTR_SERVICE_VERSION]: "1.28.0"
76468
76662
  };
76469
76663
  if (platform2 === "wsl") {
76470
76664
  const wslVersion = getWslVersion();
@@ -76491,7 +76685,7 @@ function initialize1PEventLogging() {
76491
76685
  })
76492
76686
  ]
76493
76687
  });
76494
- firstPartyEventLogger = firstPartyEventLoggerProvider.getLogger("com.urhq.ur.events", "1.27.6");
76688
+ firstPartyEventLogger = firstPartyEventLoggerProvider.getLogger("com.urhq.ur.events", "1.28.0");
76495
76689
  }
76496
76690
  async function reinitialize1PEventLoggingIfConfigChanged() {
76497
76691
  if (!is1PEventLoggingEnabled() || !firstPartyEventLoggerProvider) {
@@ -80807,7 +81001,7 @@ __export(exports_backgroundRunner, {
80807
81001
  backgroundDir: () => backgroundDir,
80808
81002
  appendBackgroundFeedback: () => appendBackgroundFeedback
80809
81003
  });
80810
- import { spawn as spawn3 } from "child_process";
81004
+ import { spawn as spawn4 } from "child_process";
80811
81005
  import {
80812
81006
  closeSync as closeSync3,
80813
81007
  existsSync as existsSync5,
@@ -81021,7 +81215,7 @@ async function spawnBackgroundWorker(task, bin) {
81021
81215
  const err = openSync3(task.logFile, "a");
81022
81216
  try {
81023
81217
  const env4 = await resolveTaskEnv(task);
81024
- const child = spawn3(entry.file, command, {
81218
+ const child = spawn4(entry.file, command, {
81025
81219
  cwd: task.cwd,
81026
81220
  detached: true,
81027
81221
  stdio: ["ignore", out, err],
@@ -81237,7 +81431,7 @@ async function runHeadlessAgent(task, cwd2) {
81237
81431
  if (sawResult)
81238
81432
  closeInputSoon();
81239
81433
  };
81240
- const child = spawn3(entry.file, args, {
81434
+ const child = spawn4(entry.file, args, {
81241
81435
  cwd: cwd2,
81242
81436
  stdio: ["pipe", "pipe", "pipe"],
81243
81437
  env: env4
@@ -81788,7 +81982,7 @@ function formatAgentTrendReport(report = buildAgentTrendReport()) {
81788
81982
  function formatA2AAgentCard(options = {}, pretty = true) {
81789
81983
  return JSON.stringify(buildA2AAgentCard(options), null, pretty ? 2 : 0);
81790
81984
  }
81791
- var urVersion = "1.27.6", coverage, priorityRoadmap;
81985
+ var urVersion = "1.28.0", coverage, priorityRoadmap;
81792
81986
  var init_trends = __esm(() => {
81793
81987
  coverage = [
81794
81988
  {
@@ -83781,7 +83975,7 @@ function getAttributionHeader(fingerprint) {
83781
83975
  if (!isAttributionHeaderEnabled()) {
83782
83976
  return "";
83783
83977
  }
83784
- const version2 = `${"1.27.6"}.${fingerprint}`;
83978
+ const version2 = `${"1.28.0"}.${fingerprint}`;
83785
83979
  const entrypoint = process.env.UR_CODE_ENTRYPOINT ?? "unknown";
83786
83980
  const cch = "";
83787
83981
  const workload = getWorkload();
@@ -84104,7 +84298,7 @@ var require_ignore = __commonJS((exports, module) => {
84104
84298
  // node_modules/tree-kill/index.js
84105
84299
  var require_tree_kill = __commonJS((exports, module) => {
84106
84300
  var childProcess = __require("child_process");
84107
- var spawn4 = childProcess.spawn;
84301
+ var spawn5 = childProcess.spawn;
84108
84302
  var exec2 = childProcess.exec;
84109
84303
  module.exports = function(pid, signal, callback) {
84110
84304
  if (typeof signal === "function" && callback === undefined) {
@@ -84129,14 +84323,14 @@ var require_tree_kill = __commonJS((exports, module) => {
84129
84323
  break;
84130
84324
  case "darwin":
84131
84325
  buildProcessTree(pid, tree, pidsToProcess, function(parentPid) {
84132
- return spawn4("pgrep", ["-P", parentPid]);
84326
+ return spawn5("pgrep", ["-P", parentPid]);
84133
84327
  }, function() {
84134
84328
  killAll(tree, signal, callback);
84135
84329
  });
84136
84330
  break;
84137
84331
  default:
84138
84332
  buildProcessTree(pid, tree, pidsToProcess, function(parentPid) {
84139
- return spawn4("ps", ["-o", "pid", "--no-headers", "--ppid", parentPid]);
84333
+ return spawn5("ps", ["-o", "pid", "--no-headers", "--ppid", parentPid]);
84140
84334
  }, function() {
84141
84335
  killAll(tree, signal, callback);
84142
84336
  });
@@ -123458,7 +123652,7 @@ var init_frontmatterParser = __esm(() => {
123458
123652
  });
123459
123653
 
123460
123654
  // src/utils/ripgrep.ts
123461
- import { execFile as execFile3, spawn as spawn4 } from "child_process";
123655
+ import { execFile as execFile3, spawn as spawn5 } from "child_process";
123462
123656
  import { existsSync as existsSync8 } from "fs";
123463
123657
  import { homedir as homedir10 } from "os";
123464
123658
  import * as path9 from "path";
@@ -123482,7 +123676,7 @@ function ripGrepRaw(args, target, abortSignal, callback, singleThread = false) {
123482
123676
  const parsedSeconds = parseInt(process.env.UR_CODE_GLOB_TIMEOUT_SECONDS || "", 10) || 0;
123483
123677
  const timeout = parsedSeconds > 0 ? parsedSeconds * 1000 : defaultTimeout;
123484
123678
  if (argv0) {
123485
- const child = spawn4(rgPath, fullArgs, {
123679
+ const child = spawn5(rgPath, fullArgs, {
123486
123680
  argv0,
123487
123681
  signal: abortSignal,
123488
123682
  windowsHide: true
@@ -123556,7 +123750,7 @@ async function ripGrepFileCount(args, target, abortSignal) {
123556
123750
  await codesignRipgrepIfNecessary();
123557
123751
  const { rgPath, rgArgs, argv0 } = ripgrepCommand();
123558
123752
  return new Promise((resolve15, reject) => {
123559
- const child = spawn4(rgPath, [...rgArgs, ...args, target], {
123753
+ const child = spawn5(rgPath, [...rgArgs, ...args, target], {
123560
123754
  argv0,
123561
123755
  signal: abortSignal,
123562
123756
  windowsHide: true,
@@ -141740,7 +141934,7 @@ var DEFAULT_REPEAT_THRESHOLD = 3;
141740
141934
  var init_loopDetector = () => {};
141741
141935
 
141742
141936
  // src/services/verifier/projectGates.ts
141743
- import { spawn as spawn5 } from "child_process";
141937
+ import { spawn as spawn6 } from "child_process";
141744
141938
  import { readFile as readFile9 } from "fs/promises";
141745
141939
  import { isAbsolute as isAbsolute9, join as join50, relative as relative8 } from "path";
141746
141940
  async function loadVerifyConfig(cwd2) {
@@ -141821,7 +142015,7 @@ async function runGateCommands(commands, cwd2, timeoutMs = DEFAULT_TIMEOUT_MS) {
141821
142015
  }
141822
142016
  function runSingleCommand(command, cwd2, timeoutMs) {
141823
142017
  return new Promise((resolve18) => {
141824
- const child = spawn5(command, {
142018
+ const child = spawn6(command, {
141825
142019
  cwd: cwd2,
141826
142020
  shell: true,
141827
142021
  stdio: ["ignore", "pipe", "pipe"]
@@ -191454,7 +191648,7 @@ function getTelemetryAttributes() {
191454
191648
  attributes["session.id"] = sessionId;
191455
191649
  }
191456
191650
  if (shouldIncludeAttribute("OTEL_METRICS_INCLUDE_VERSION")) {
191457
- attributes["app.version"] = "1.27.6";
191651
+ attributes["app.version"] = "1.28.0";
191458
191652
  }
191459
191653
  const oauthAccount = getOauthAccountInfo();
191460
191654
  if (oauthAccount) {
@@ -225425,14 +225619,14 @@ var init_upperFirst = __esm(() => {
225425
225619
  });
225426
225620
 
225427
225621
  // node_modules/lodash-es/capitalize.js
225428
- function capitalize2(string5) {
225622
+ function capitalize3(string5) {
225429
225623
  return upperFirst_default(toString_default(string5).toLowerCase());
225430
225624
  }
225431
225625
  var capitalize_default;
225432
225626
  var init_capitalize = __esm(() => {
225433
225627
  init_toString();
225434
225628
  init_upperFirst();
225435
- capitalize_default = capitalize2;
225629
+ capitalize_default = capitalize3;
225436
225630
  });
225437
225631
 
225438
225632
  // src/utils/jetbrains.ts
@@ -226856,7 +227050,7 @@ function getInstallationEnv() {
226856
227050
  return;
226857
227051
  }
226858
227052
  function getURCodeVersion() {
226859
- return "1.27.6";
227053
+ return "1.28.0";
226860
227054
  }
226861
227055
  async function getInstalledVSCodeExtensionVersion(command) {
226862
227056
  const { stdout } = await execFileNoThrow(command, ["--list-extensions", "--show-versions"], {
@@ -229695,7 +229889,7 @@ async function setupSdkMcpClients(sdkMcpConfigs, sendMcpMessage) {
229695
229889
  const client2 = new Client({
229696
229890
  name: "ur",
229697
229891
  title: "UR",
229698
- version: "1.27.6",
229892
+ version: "1.28.0",
229699
229893
  description: "UR-AGENT autonomous engineering workflow engine",
229700
229894
  websiteUrl: PRODUCT_URL
229701
229895
  }, {
@@ -230049,7 +230243,7 @@ var init_client5 = __esm(() => {
230049
230243
  const client2 = new Client({
230050
230244
  name: "ur",
230051
230245
  title: "UR",
230052
- version: "1.27.6",
230246
+ version: "1.28.0",
230053
230247
  description: "UR-AGENT autonomous engineering workflow engine",
230054
230248
  websiteUrl: PRODUCT_URL
230055
230249
  }, {
@@ -239865,9 +240059,9 @@ async function assertMinVersion() {
239865
240059
  if (false) {}
239866
240060
  try {
239867
240061
  const versionConfig = await getDynamicConfig_BLOCKS_ON_INIT("tengu_version_config", { minVersion: "0.0.0" });
239868
- if (versionConfig.minVersion && lt("1.27.6", versionConfig.minVersion)) {
240062
+ if (versionConfig.minVersion && lt("1.28.0", versionConfig.minVersion)) {
239869
240063
  console.error(`
239870
- It looks like your version of UR (${"1.27.6"}) needs an update.
240064
+ It looks like your version of UR (${"1.28.0"}) needs an update.
239871
240065
  A newer version (${versionConfig.minVersion} or higher) is required to continue.
239872
240066
 
239873
240067
  To update, please run:
@@ -240083,7 +240277,7 @@ async function installGlobalPackage(specificVersion) {
240083
240277
  logError2(new AutoUpdaterError("Another process is currently installing an update"));
240084
240278
  logEvent("tengu_auto_updater_lock_contention", {
240085
240279
  pid: process.pid,
240086
- currentVersion: "1.27.6"
240280
+ currentVersion: "1.28.0"
240087
240281
  });
240088
240282
  return "in_progress";
240089
240283
  }
@@ -240092,7 +240286,7 @@ async function installGlobalPackage(specificVersion) {
240092
240286
  if (!env2.isRunningWithBun() && env2.isNpmFromWindowsPath()) {
240093
240287
  logError2(new Error("Windows NPM detected in WSL environment"));
240094
240288
  logEvent("tengu_auto_updater_windows_npm_in_wsl", {
240095
- currentVersion: "1.27.6"
240289
+ currentVersion: "1.28.0"
240096
240290
  });
240097
240291
  console.error(`
240098
240292
  Error: Windows NPM detected in WSL
@@ -240627,7 +240821,7 @@ function detectLinuxGlobPatternWarnings() {
240627
240821
  }
240628
240822
  async function getDoctorDiagnostic() {
240629
240823
  const installationType = await getCurrentInstallationType();
240630
- const version2 = typeof MACRO !== "undefined" ? "1.27.6" : "unknown";
240824
+ const version2 = typeof MACRO !== "undefined" ? "1.28.0" : "unknown";
240631
240825
  const installationPath = await getInstallationPath();
240632
240826
  const invokedBinary = getInvokedBinary();
240633
240827
  const multipleInstallations = await detectMultipleInstallations();
@@ -241562,8 +241756,8 @@ async function updateLatest(channelOrVersion, forceReinstall = false) {
241562
241756
  const maxVersion = await getMaxVersion();
241563
241757
  if (maxVersion && gt(version2, maxVersion)) {
241564
241758
  logForDebugging(`Native installer: maxVersion ${maxVersion} is set, capping update from ${version2} to ${maxVersion}`);
241565
- if (gte("1.27.6", maxVersion)) {
241566
- logForDebugging(`Native installer: current version ${"1.27.6"} is already at or above maxVersion ${maxVersion}, skipping update`);
241759
+ if (gte("1.28.0", maxVersion)) {
241760
+ logForDebugging(`Native installer: current version ${"1.28.0"} is already at or above maxVersion ${maxVersion}, skipping update`);
241567
241761
  logEvent("tengu_native_update_skipped_max_version", {
241568
241762
  latency_ms: Date.now() - startTime,
241569
241763
  max_version: maxVersion,
@@ -241574,7 +241768,7 @@ async function updateLatest(channelOrVersion, forceReinstall = false) {
241574
241768
  version2 = maxVersion;
241575
241769
  }
241576
241770
  }
241577
- if (!forceReinstall && version2 === "1.27.6" && await versionIsAvailable(version2) && await isPossibleURBinary(executablePath)) {
241771
+ if (!forceReinstall && version2 === "1.28.0" && await versionIsAvailable(version2) && await isPossibleURBinary(executablePath)) {
241578
241772
  logForDebugging(`Found ${version2} at ${executablePath}, skipping install`);
241579
241773
  logEvent("tengu_native_update_complete", {
241580
241774
  latency_ms: Date.now() - startTime,
@@ -273959,7 +274153,7 @@ var exports_LSPClient = {};
273959
274153
  __export(exports_LSPClient, {
273960
274154
  createLSPClient: () => createLSPClient
273961
274155
  });
273962
- import { spawn as spawn7 } from "child_process";
274156
+ import { spawn as spawn8 } from "child_process";
273963
274157
  function createLSPClient(serverName, onCrash) {
273964
274158
  let process14;
273965
274159
  let connection;
@@ -273984,7 +274178,7 @@ function createLSPClient(serverName, onCrash) {
273984
274178
  },
273985
274179
  async start(command, args, options2) {
273986
274180
  try {
273987
- process14 = spawn7(command, args, {
274181
+ process14 = spawn8(command, args, {
273988
274182
  stdio: ["pipe", "pipe", "pipe"],
273989
274183
  env: { ...subprocessEnv(), ...options2?.env },
273990
274184
  cwd: options2?.cwd,
@@ -276448,7 +276642,7 @@ var init_powershellProvider = __esm(() => {
276448
276642
  });
276449
276643
 
276450
276644
  // src/utils/Shell.ts
276451
- import { execFileSync as execFileSync2, spawn as spawn8 } from "child_process";
276645
+ import { execFileSync as execFileSync2, spawn as spawn9 } from "child_process";
276452
276646
  import { constants as fsConstants4, readFileSync as readFileSync19, unlinkSync as unlinkSync2 } from "fs";
276453
276647
  import { mkdir as mkdir19, open as open9, realpath as realpath9 } from "fs/promises";
276454
276648
  import { isAbsolute as isAbsolute16, resolve as resolve25 } from "path";
@@ -276576,7 +276770,7 @@ async function exec3(command, abortSignal, shellType, options2) {
276576
276770
  outputHandle = await open9(taskOutput.path, process.platform === "win32" ? "w" : fsConstants4.O_WRONLY | fsConstants4.O_CREAT | fsConstants4.O_APPEND | O_NOFOLLOW);
276577
276771
  }
276578
276772
  try {
276579
- const childProcess = spawn8(spawnBinary, shellArgs, {
276773
+ const childProcess = spawn9(spawnBinary, shellArgs, {
276580
276774
  env: {
276581
276775
  ...subprocessEnv(),
276582
276776
  SHELL: shellType === "bash" ? binShell : undefined,
@@ -338499,7 +338693,7 @@ function Feedback({
338499
338693
  platform: env2.platform,
338500
338694
  gitRepo: envInfo.isGit,
338501
338695
  terminal: env2.terminal,
338502
- version: "1.27.6",
338696
+ version: "1.28.0",
338503
338697
  transcript: normalizeMessagesForAPI(messages),
338504
338698
  errors: sanitizedErrors,
338505
338699
  lastApiRequest: getLastAPIRequest(),
@@ -338691,7 +338885,7 @@ function Feedback({
338691
338885
  ", ",
338692
338886
  env2.terminal,
338693
338887
  ", v",
338694
- "1.27.6"
338888
+ "1.28.0"
338695
338889
  ]
338696
338890
  }, undefined, true, undefined, this)
338697
338891
  ]
@@ -338797,7 +338991,7 @@ ${sanitizedDescription}
338797
338991
  ` + `**Environment Info**
338798
338992
  ` + `- Platform: ${env2.platform}
338799
338993
  ` + `- Terminal: ${env2.terminal}
338800
- ` + `- Version: ${"1.27.6"}
338994
+ ` + `- Version: ${"1.28.0"}
338801
338995
  ` + `- Feedback ID: ${feedbackId}
338802
338996
  ` + `
338803
338997
  **Errors**
@@ -341908,7 +342102,7 @@ function buildPrimarySection() {
341908
342102
  }, undefined, false, undefined, this);
341909
342103
  return [{
341910
342104
  label: "Version",
341911
- value: "1.27.6"
342105
+ value: "1.28.0"
341912
342106
  }, {
341913
342107
  label: "Session name",
341914
342108
  value: nameValue
@@ -345208,7 +345402,7 @@ function Config({
345208
345402
  }
345209
345403
  }, undefined, false, undefined, this)
345210
345404
  }, undefined, false, undefined, this) : showSubmenu === "ChannelDowngrade" ? /* @__PURE__ */ jsx_dev_runtime177.jsxDEV(ChannelDowngradeDialog, {
345211
- currentVersion: "1.27.6",
345405
+ currentVersion: "1.28.0",
345212
345406
  onChoice: (choice) => {
345213
345407
  setShowSubmenu(null);
345214
345408
  setTabsHidden(false);
@@ -345220,7 +345414,7 @@ function Config({
345220
345414
  autoUpdatesChannel: "stable"
345221
345415
  };
345222
345416
  if (choice === "stay") {
345223
- newSettings.minimumVersion = "1.27.6";
345417
+ newSettings.minimumVersion = "1.28.0";
345224
345418
  }
345225
345419
  updateSettingsForSource("userSettings", newSettings);
345226
345420
  setSettingsData((prev_27) => ({
@@ -352123,7 +352317,7 @@ var init_MemoryUpdateNotification = __esm(() => {
352123
352317
 
352124
352318
  // src/utils/editor.ts
352125
352319
  import {
352126
- spawn as spawn9,
352320
+ spawn as spawn10,
352127
352321
  spawnSync as spawnSync3
352128
352322
  } from "child_process";
352129
352323
  import { basename as basename37 } from "path";
@@ -352157,9 +352351,9 @@ function openFileInExternalEditor(filePath, line) {
352157
352351
  let child;
352158
352352
  if (process.platform === "win32") {
352159
352353
  const gotoStr = gotoArgv.map((a2) => `"${a2}"`).join(" ");
352160
- child = spawn9(`${editor} ${gotoStr}`, { ...detachedOpts, shell: true });
352354
+ child = spawn10(`${editor} ${gotoStr}`, { ...detachedOpts, shell: true });
352161
352355
  } else {
352162
- child = spawn9(base2, [...editorArgs, ...gotoArgv], detachedOpts);
352356
+ child = spawn10(base2, [...editorArgs, ...gotoArgv], detachedOpts);
352163
352357
  }
352164
352358
  child.on("error", (e) => logForDebugging(`editor spawn failed: ${e}`, { level: "error" }));
352165
352359
  child.unref();
@@ -353290,7 +353484,7 @@ function HelpV2(t0) {
353290
353484
  let t6;
353291
353485
  if ($3[31] !== tabs) {
353292
353486
  t6 = /* @__PURE__ */ jsx_dev_runtime204.jsxDEV(Tabs, {
353293
- title: `UR v${"1.27.6"}`,
353487
+ title: `UR v${"1.28.0"}`,
353294
353488
  color: "professionalBlue",
353295
353489
  defaultTab: "general",
353296
353490
  children: tabs
@@ -373392,7 +373586,7 @@ function getAllReleaseNotes(changelogContent = getStoredChangelogFromMemory()) {
373392
373586
  return [];
373393
373587
  }
373394
373588
  }
373395
- async function checkForReleaseNotes(lastSeenVersion, currentVersion = "1.27.6") {
373589
+ async function checkForReleaseNotes(lastSeenVersion, currentVersion = "1.28.0") {
373396
373590
  if (process.env.USER_TYPE === "ant") {
373397
373591
  const changelog = "";
373398
373592
  if (changelog) {
@@ -373419,7 +373613,7 @@ async function checkForReleaseNotes(lastSeenVersion, currentVersion = "1.27.6")
373419
373613
  releaseNotes
373420
373614
  };
373421
373615
  }
373422
- function checkForReleaseNotesSync(lastSeenVersion, currentVersion = "1.27.6") {
373616
+ function checkForReleaseNotesSync(lastSeenVersion, currentVersion = "1.28.0") {
373423
373617
  if (process.env.USER_TYPE === "ant") {
373424
373618
  const changelog = "";
373425
373619
  if (changelog) {
@@ -374589,7 +374783,7 @@ function getRecentActivitySync() {
374589
374783
  return cachedActivity;
374590
374784
  }
374591
374785
  function getLogoDisplayData() {
374592
- const version2 = process.env.DEMO_VERSION ?? "1.27.6";
374786
+ const version2 = process.env.DEMO_VERSION ?? "1.28.0";
374593
374787
  const serverUrl = getDirectConnectServerUrl();
374594
374788
  const displayPath = process.env.DEMO_VERSION ? "/code/ur" : getDisplayPath(getCwd2());
374595
374789
  const cwd2 = serverUrl ? `${displayPath} in ${serverUrl.replace(/^https?:\/\//, "")}` : displayPath;
@@ -375378,7 +375572,7 @@ function LogoV2() {
375378
375572
  if ($3[2] === Symbol.for("react.memo_cache_sentinel")) {
375379
375573
  t2 = () => {
375380
375574
  const currentConfig = getGlobalConfig();
375381
- if (currentConfig.lastReleaseNotesSeen === "1.27.6") {
375575
+ if (currentConfig.lastReleaseNotesSeen === "1.28.0") {
375382
375576
  return;
375383
375577
  }
375384
375578
  saveGlobalConfig(_temp326);
@@ -376063,12 +376257,12 @@ function LogoV2() {
376063
376257
  return t41;
376064
376258
  }
376065
376259
  function _temp326(current) {
376066
- if (current.lastReleaseNotesSeen === "1.27.6") {
376260
+ if (current.lastReleaseNotesSeen === "1.28.0") {
376067
376261
  return current;
376068
376262
  }
376069
376263
  return {
376070
376264
  ...current,
376071
- lastReleaseNotesSeen: "1.27.6"
376265
+ lastReleaseNotesSeen: "1.28.0"
376072
376266
  };
376073
376267
  }
376074
376268
  function _temp243(s_0) {
@@ -383539,11 +383733,11 @@ async function pollForApprovedExitPlanMode(sessionId, timeoutMs, onPhaseChange,
383539
383733
  }
383540
383734
  throw new UltraplanPollError(scanner.everSeenPending ? `no approval after ${timeoutMs / 1000}s` : `ExitPlanMode never reached after ${timeoutMs / 1000}s (the remote container failed to start, or session ID mismatch?)`, scanner.everSeenPending ? "timeout_pending" : "timeout_no_plan", scanner.rejectCount);
383541
383735
  }
383542
- function contentToText3(content) {
383736
+ function contentToText4(content) {
383543
383737
  return typeof content === "string" ? content : Array.isArray(content) ? content.map((b) => ("text" in b) ? b.text : "").join("") : "";
383544
383738
  }
383545
383739
  function extractTeleportPlan(content) {
383546
- const text = contentToText3(content);
383740
+ const text = contentToText4(content);
383547
383741
  const marker = `${ULTRAPLAN_TELEPORT_SENTINEL}
383548
383742
  `;
383549
383743
  const idx = text.indexOf(marker);
@@ -383552,7 +383746,7 @@ function extractTeleportPlan(content) {
383552
383746
  return text.slice(idx + marker.length).trimEnd();
383553
383747
  }
383554
383748
  function extractApprovedPlan(content) {
383555
- const text = contentToText3(content);
383749
+ const text = contentToText4(content);
383556
383750
  const markers = [
383557
383751
  `## Approved Plan (edited by user):
383558
383752
  `,
@@ -389593,9 +389787,9 @@ var init_reports = __esm(() => {
389593
389787
  });
389594
389788
 
389595
389789
  // src/security/exec.ts
389596
- import { spawn as spawn10 } from "child_process";
389790
+ import { spawn as spawn11 } from "child_process";
389597
389791
  var MAX = 400000, spawnExec = (bin, args, opts = {}) => new Promise((resolve43) => {
389598
- const child = spawn10(bin, args, { cwd: opts.cwd });
389792
+ const child = spawn11(bin, args, { cwd: opts.cwd });
389599
389793
  let stdout = "";
389600
389794
  let stderr = "";
389601
389795
  child.stdout.on("data", (d) => {
@@ -393057,7 +393251,7 @@ function buildToolUseContext(tools, readFileStateCache) {
393057
393251
  async function handleInitialize() {
393058
393252
  return {
393059
393253
  name: "ur-agent",
393060
- version: "1.27.6",
393254
+ version: "1.28.0",
393061
393255
  protocolVersion: "0.1.0"
393062
393256
  };
393063
393257
  }
@@ -406518,7 +406712,7 @@ var init_code_index2 = __esm(() => {
406518
406712
 
406519
406713
  // node_modules/typescript/lib/typescript.js
406520
406714
  var require_typescript2 = __commonJS((exports, module) => {
406521
- var __dirname = "/Users/maith/Desktop/ur3-dev/UR-1.19.0/node_modules/typescript/lib", __filename = "/Users/maith/Desktop/ur3-dev/UR-1.19.0/node_modules/typescript/lib/typescript.js";
406715
+ var __dirname = "/sessions/confident-pensive-edison/mnt/UR-1.19.0/node_modules/typescript/lib", __filename = "/sessions/confident-pensive-edison/mnt/UR-1.19.0/node_modules/typescript/lib/typescript.js";
406522
406716
  /*! *****************************************************************************
406523
406717
  Copyright (c) Microsoft Corporation. All rights reserved.
406524
406718
  Licensed under the Apache License, Version 2.0 (the "License"); you may not use
@@ -592052,7 +592246,7 @@ async function captureMemoryDiagnostics(trigger2, dumpNumber = 0) {
592052
592246
  smapsRollup,
592053
592247
  platform: process.platform,
592054
592248
  nodeVersion: process.version,
592055
- ccVersion: "1.27.6"
592249
+ ccVersion: "1.28.0"
592056
592250
  };
592057
592251
  }
592058
592252
  async function performHeapDump(trigger2 = "manual", dumpNumber = 0) {
@@ -592638,7 +592832,7 @@ var init_bridge_kick = __esm(() => {
592638
592832
  var call136 = async () => {
592639
592833
  return {
592640
592834
  type: "text",
592641
- value: "1.27.6"
592835
+ value: "1.28.0"
592642
592836
  };
592643
592837
  }, version2, version_default;
592644
592838
  var init_version = __esm(() => {
@@ -596149,23 +596343,6 @@ function SetModelAndClose({
596149
596343
  }
596150
596344
  setModel(model);
596151
596345
  return;
596152
- try {
596153
- const {
596154
- valid,
596155
- error: error_0
596156
- } = await validateModel(model);
596157
- if (valid) {
596158
- setModel(model);
596159
- } else {
596160
- onDone(error_0 || `Model '${model}' not found`, {
596161
- display: "system"
596162
- });
596163
- }
596164
- } catch (error40) {
596165
- onDone(`Failed to validate model: ${error40.message}`, {
596166
- display: "system"
596167
- });
596168
- }
596169
596346
  }
596170
596347
  function setModel(modelValue) {
596171
596348
  setAppState((prev) => ({
@@ -596279,7 +596456,6 @@ var init_model2 = __esm(() => {
596279
596456
  init_check1mAccess();
596280
596457
  init_model();
596281
596458
  init_modelAllowlist();
596282
- init_validateModel();
596283
596459
  init_providerRegistry();
596284
596460
  init_settings2();
596285
596461
  import_compiler_runtime263 = __toESM(require_compiler_runtime(), 1);
@@ -602541,7 +602717,7 @@ function generateHtmlReport(data, insights) {
602541
602717
  </html>`;
602542
602718
  }
602543
602719
  function buildExportData(data, insights, facets, remoteStats) {
602544
- const version3 = typeof MACRO !== "undefined" ? "1.27.6" : "unknown";
602720
+ const version3 = typeof MACRO !== "undefined" ? "1.28.0" : "unknown";
602545
602721
  const remote_hosts_collected = remoteStats?.hosts.filter((h2) => h2.sessionCount > 0).map((h2) => h2.name);
602546
602722
  const facets_summary = {
602547
602723
  total: facets.size,
@@ -606819,7 +606995,7 @@ var init_sessionStorage = __esm(() => {
606819
606995
  init_settings2();
606820
606996
  init_slowOperations();
606821
606997
  init_uuid();
606822
- VERSION5 = typeof MACRO !== "undefined" ? "1.27.6" : "unknown";
606998
+ VERSION5 = typeof MACRO !== "undefined" ? "1.28.0" : "unknown";
606823
606999
  MAX_TOMBSTONE_REWRITE_BYTES = 50 * 1024 * 1024;
606824
607000
  SKIP_FIRST_PROMPT_PATTERN = /^(?:\s*<[a-z][\w-]*[\s>]|\[Request interrupted by user[^\]]*\])/;
606825
607001
  EPHEMERAL_PROGRESS_TYPES = new Set([
@@ -608024,7 +608200,7 @@ var init_filesystem = __esm(() => {
608024
608200
  });
608025
608201
  getBundledSkillsRoot = memoize_default(function getBundledSkillsRoot2() {
608026
608202
  const nonce = randomBytes18(16).toString("hex");
608027
- return join200(getURTempDir(), "bundled-skills", "1.27.6", nonce);
608203
+ return join200(getURTempDir(), "bundled-skills", "1.28.0", nonce);
608028
608204
  });
608029
608205
  getResolvedWorkingDirPaths = memoize_default(getPathsForPermissionCheck);
608030
608206
  });
@@ -609462,7 +609638,7 @@ __export(exports_hooks2, {
609462
609638
  createBaseHookInput: () => createBaseHookInput
609463
609639
  });
609464
609640
  import { basename as basename45 } from "path";
609465
- import { spawn as spawn11 } from "child_process";
609641
+ import { spawn as spawn12 } from "child_process";
609466
609642
  import { randomUUID as randomUUID39 } from "crypto";
609467
609643
  function getSessionEndHookTimeoutMs() {
609468
609644
  const raw = process.env.UR_CODE_SESSIONEND_HOOKS_TIMEOUT_MS;
@@ -609875,14 +610051,14 @@ async function execCommandHook(hook, hookEvent, hookName, jsonInput, signal, hoo
609875
610051
  if (!pwshPath) {
609876
610052
  throw new Error(`Hook "${hook.command}" has shell: 'powershell' but no PowerShell ` + `executable (pwsh or powershell) was found on PATH. Install ` + `PowerShell, or remove "shell": "powershell" to use bash.`);
609877
610053
  }
609878
- child = spawn11(pwshPath, buildPowerShellArgs(finalCommand), {
610054
+ child = spawn12(pwshPath, buildPowerShellArgs(finalCommand), {
609879
610055
  env: envVars,
609880
610056
  cwd: safeCwd,
609881
610057
  windowsHide: true
609882
610058
  });
609883
610059
  } else {
609884
610060
  const shell = isWindows2 ? findGitBashPath() : true;
609885
- child = spawn11(finalCommand, [], {
610061
+ child = spawn12(finalCommand, [], {
609886
610062
  env: envVars,
609887
610063
  cwd: safeCwd,
609888
610064
  shell,
@@ -614316,7 +614492,7 @@ function computeFingerprint(messageText2, version3) {
614316
614492
  }
614317
614493
  function computeFingerprintFromMessages(messages) {
614318
614494
  const firstMessageText = extractFirstMessageText(messages);
614319
- return computeFingerprint(firstMessageText, "1.27.6");
614495
+ return computeFingerprint(firstMessageText, "1.28.0");
614320
614496
  }
614321
614497
  var FINGERPRINT_SALT = "59cf53e54c78";
614322
614498
  var init_fingerprint = () => {};
@@ -616183,7 +616359,7 @@ async function sideQuery(opts) {
616183
616359
  betas.push(STRUCTURED_OUTPUTS_BETA_HEADER);
616184
616360
  }
616185
616361
  const messageText2 = extractFirstUserMessageText(messages);
616186
- const fingerprint = computeFingerprint(messageText2, "1.27.6");
616362
+ const fingerprint = computeFingerprint(messageText2, "1.28.0");
616187
616363
  const attributionHeader = getAttributionHeader(fingerprint);
616188
616364
  const systemBlocks = [
616189
616365
  attributionHeader ? { type: "text", text: attributionHeader } : null,
@@ -620428,7 +620604,7 @@ var init_IdleReturnDialog = __esm(() => {
620428
620604
  });
620429
620605
 
620430
620606
  // src/services/preventSleep.ts
620431
- import { spawn as spawn12 } from "child_process";
620607
+ import { spawn as spawn13 } from "child_process";
620432
620608
  function startPreventSleep() {
620433
620609
  refCount++;
620434
620610
  if (refCount === 1) {
@@ -620486,7 +620662,7 @@ function spawnCaffeinate() {
620486
620662
  });
620487
620663
  }
620488
620664
  try {
620489
- caffeinateProcess = spawn12("caffeinate", ["-i", "-t", String(CAFFEINATE_TIMEOUT_SECONDS)], {
620665
+ caffeinateProcess = spawn13("caffeinate", ["-i", "-t", String(CAFFEINATE_TIMEOUT_SECONDS)], {
620490
620666
  stdio: "ignore"
620491
620667
  });
620492
620668
  caffeinateProcess.unref();
@@ -620920,7 +621096,7 @@ function buildSystemInitMessage(inputs) {
620920
621096
  slash_commands: inputs.commands.filter((c4) => c4.userInvocable !== false).map((c4) => c4.name),
620921
621097
  apiKeySource: getURHQApiKeyWithSource().source,
620922
621098
  betas: getSdkBetas(),
620923
- ur_version: "1.27.6",
621099
+ ur_version: "1.28.0",
620924
621100
  output_style: outputStyle2,
620925
621101
  agents: inputs.agents.map((agent) => agent.agentType),
620926
621102
  skills: inputs.skills.filter((s) => s.userInvocable !== false).map((skill2) => skill2.name),
@@ -635548,7 +635724,7 @@ var init_useVoiceEnabled = __esm(() => {
635548
635724
  function getSemverPart(version3) {
635549
635725
  return `${import_semver13.major(version3, { loose: true })}.${import_semver13.minor(version3, { loose: true })}.${import_semver13.patch(version3, { loose: true })}`;
635550
635726
  }
635551
- function useUpdateNotification(updatedVersion, initialVersion = "1.27.6") {
635727
+ function useUpdateNotification(updatedVersion, initialVersion = "1.28.0") {
635552
635728
  const [lastNotifiedSemver, setLastNotifiedSemver] = import_react226.useState(() => getSemverPart(initialVersion));
635553
635729
  if (!updatedVersion) {
635554
635730
  return null;
@@ -635597,7 +635773,7 @@ function AutoUpdater({
635597
635773
  return;
635598
635774
  }
635599
635775
  if (false) {}
635600
- const currentVersion = "1.27.6";
635776
+ const currentVersion = "1.28.0";
635601
635777
  const channel = getInitialSettings()?.autoUpdatesChannel ?? "latest";
635602
635778
  let latestVersion = await getLatestVersion(channel);
635603
635779
  const isDisabled = isAutoUpdaterDisabled();
@@ -635826,12 +636002,12 @@ function NativeAutoUpdater({
635826
636002
  logEvent("tengu_native_auto_updater_start", {});
635827
636003
  try {
635828
636004
  const maxVersion = await getMaxVersion();
635829
- if (maxVersion && gt("1.27.6", maxVersion)) {
636005
+ if (maxVersion && gt("1.28.0", maxVersion)) {
635830
636006
  const msg = await getMaxVersionMessage();
635831
636007
  setMaxVersionIssue(msg ?? "affects your version");
635832
636008
  }
635833
636009
  const result = await installLatest(channel);
635834
- const currentVersion = "1.27.6";
636010
+ const currentVersion = "1.28.0";
635835
636011
  const latencyMs = Date.now() - startTime;
635836
636012
  if (result.lockFailed) {
635837
636013
  logEvent("tengu_native_auto_updater_lock_contention", {
@@ -635968,17 +636144,17 @@ function PackageManagerAutoUpdater(t0) {
635968
636144
  const maxVersion = await getMaxVersion();
635969
636145
  if (maxVersion && latest && gt(latest, maxVersion)) {
635970
636146
  logForDebugging(`PackageManagerAutoUpdater: maxVersion ${maxVersion} is set, capping update from ${latest} to ${maxVersion}`);
635971
- if (gte("1.27.6", maxVersion)) {
635972
- logForDebugging(`PackageManagerAutoUpdater: current version ${"1.27.6"} is already at or above maxVersion ${maxVersion}, skipping update`);
636147
+ if (gte("1.28.0", maxVersion)) {
636148
+ logForDebugging(`PackageManagerAutoUpdater: current version ${"1.28.0"} is already at or above maxVersion ${maxVersion}, skipping update`);
635973
636149
  setUpdateAvailable(false);
635974
636150
  return;
635975
636151
  }
635976
636152
  latest = maxVersion;
635977
636153
  }
635978
- const hasUpdate = latest && !gte("1.27.6", latest) && !shouldSkipVersion(latest);
636154
+ const hasUpdate = latest && !gte("1.28.0", latest) && !shouldSkipVersion(latest);
635979
636155
  setUpdateAvailable(!!hasUpdate);
635980
636156
  if (hasUpdate) {
635981
- logForDebugging(`PackageManagerAutoUpdater: Update available ${"1.27.6"} -> ${latest}`);
636157
+ logForDebugging(`PackageManagerAutoUpdater: Update available ${"1.28.0"} -> ${latest}`);
635982
636158
  }
635983
636159
  };
635984
636160
  $3[0] = t1;
@@ -636012,7 +636188,7 @@ function PackageManagerAutoUpdater(t0) {
636012
636188
  wrap: "truncate",
636013
636189
  children: [
636014
636190
  "currentVersion: ",
636015
- "1.27.6"
636191
+ "1.28.0"
636016
636192
  ]
636017
636193
  }, undefined, true, undefined, this);
636018
636194
  $3[3] = verbose;
@@ -648458,7 +648634,7 @@ function buildStatusLineCommandInput(permissionMode, exceeds200kTokens, settings
648458
648634
  project_dir: getOriginalCwd(),
648459
648635
  added_dirs: addedDirs
648460
648636
  },
648461
- version: "1.27.6",
648637
+ version: "1.28.0",
648462
648638
  output_style: {
648463
648639
  name: outputStyleName
648464
648640
  },
@@ -648533,7 +648709,7 @@ function StatusLineInner({
648533
648709
  const taskValues = Object.values(tasks2);
648534
648710
  const taskRunningCount = taskValues.filter((task2) => task2.status === "running" || task2.status === "pending").length;
648535
648711
  const defaultStatusLineText = buildDefaultStatusBar({
648536
- version: "1.27.6",
648712
+ version: "1.28.0",
648537
648713
  providerLabel: providerRuntime.providerLabel,
648538
648714
  authMode: providerRuntime.authLabel,
648539
648715
  model: providerRuntime.model ?? renderModelName(mainLoopModel),
@@ -660019,7 +660195,7 @@ async function submitTranscriptShare(messages, trigger2, appearanceId) {
660019
660195
  } catch {}
660020
660196
  const data = {
660021
660197
  trigger: trigger2,
660022
- version: "1.27.6",
660198
+ version: "1.28.0",
660023
660199
  platform: process.platform,
660024
660200
  transcript,
660025
660201
  subagentTranscripts: Object.keys(subagentTranscripts).length > 0 ? subagentTranscripts : undefined,
@@ -671903,7 +672079,7 @@ function WelcomeV2() {
671903
672079
  dimColor: true,
671904
672080
  children: [
671905
672081
  "v",
671906
- "1.27.6"
672082
+ "1.28.0"
671907
672083
  ]
671908
672084
  }, undefined, true, undefined, this)
671909
672085
  ]
@@ -673163,7 +673339,7 @@ function completeOnboarding() {
673163
673339
  saveGlobalConfig((current) => ({
673164
673340
  ...current,
673165
673341
  hasCompletedOnboarding: true,
673166
- lastOnboardingVersion: "1.27.6"
673342
+ lastOnboardingVersion: "1.28.0"
673167
673343
  }));
673168
673344
  }
673169
673345
  function showDialog(root2, renderer) {
@@ -678267,7 +678443,7 @@ function appendToLog(path24, message) {
678267
678443
  cwd: getFsImplementation().cwd(),
678268
678444
  userType: process.env.USER_TYPE,
678269
678445
  sessionId: getSessionId(),
678270
- version: "1.27.6"
678446
+ version: "1.28.0"
678271
678447
  };
678272
678448
  getLogWriter(path24).write(messageWithTimestamp);
678273
678449
  }
@@ -682361,8 +682537,8 @@ async function getEnvLessBridgeConfig() {
682361
682537
  }
682362
682538
  async function checkEnvLessBridgeMinVersion() {
682363
682539
  const cfg = await getEnvLessBridgeConfig();
682364
- if (cfg.min_version && lt("1.27.6", cfg.min_version)) {
682365
- return `Your version of UR (${"1.27.6"}) is too old for Remote Control.
682540
+ if (cfg.min_version && lt("1.28.0", cfg.min_version)) {
682541
+ return `Your version of UR (${"1.28.0"}) is too old for Remote Control.
682366
682542
  Version ${cfg.min_version} or higher is required. Run \`ur update\` to update.`;
682367
682543
  }
682368
682544
  return null;
@@ -682836,7 +683012,7 @@ async function initBridgeCore(params) {
682836
683012
  const rawApi = createBridgeApiClient({
682837
683013
  baseUrl,
682838
683014
  getAccessToken,
682839
- runnerVersion: "1.27.6",
683015
+ runnerVersion: "1.28.0",
682840
683016
  onDebug: logForDebugging,
682841
683017
  onAuth401,
682842
683018
  getTrustedDeviceToken
@@ -688518,7 +688694,7 @@ async function startMCPServer(cwd3, debug2, verbose) {
688518
688694
  setCwd(cwd3);
688519
688695
  const server2 = new Server({
688520
688696
  name: "ur/tengu",
688521
- version: "1.27.6"
688697
+ version: "1.28.0"
688522
688698
  }, {
688523
688699
  capabilities: {
688524
688700
  tools: {}
@@ -690331,7 +690507,7 @@ async function update() {
690331
690507
  logEvent("tengu_update_check", {});
690332
690508
  const diagnostic = await getDoctorDiagnostic();
690333
690509
  const result = await checkUpgradeStatus({
690334
- currentVersion: "1.27.6",
690510
+ currentVersion: "1.28.0",
690335
690511
  packageName: UR_AGENT_PACKAGE_NAME,
690336
690512
  installationType: diagnostic.installationType,
690337
690513
  latestVersion: () => getLatestNpmPackageVersion(UR_AGENT_PACKAGE_NAME)
@@ -691577,7 +691753,7 @@ ${customInstructions}` : customInstructions;
691577
691753
  }
691578
691754
  }
691579
691755
  logForDiagnosticsNoPII("info", "started", {
691580
- version: "1.27.6",
691756
+ version: "1.28.0",
691581
691757
  is_native_binary: isInBundledMode()
691582
691758
  });
691583
691759
  registerCleanup(async () => {
@@ -692361,7 +692537,7 @@ Usage: ur --remote "your task description"`, () => gracefulShutdown(1));
692361
692537
  pendingHookMessages
692362
692538
  }, renderAndRun);
692363
692539
  }
692364
- }).version("1.27.6 (UR-AGENT)", "-v, --version", "Output the version number");
692540
+ }).version("1.28.0 (UR-AGENT)", "-v, --version", "Output the version number");
692365
692541
  program2.option("-w, --worktree [name]", "Create a new git worktree for this session (optionally specify a name)");
692366
692542
  program2.option("--tmux", "Create a tmux session for the worktree (requires --worktree). Uses iTerm2 native panes when available; use --tmux=classic for traditional tmux.");
692367
692543
  if (canUserConfigureAdvisor()) {
@@ -693239,7 +693415,7 @@ if (false) {}
693239
693415
  async function main2() {
693240
693416
  const args = process.argv.slice(2);
693241
693417
  if (args.length === 1 && (args[0] === "--version" || args[0] === "-v" || args[0] === "-V")) {
693242
- console.log(`${"1.27.6"} (UR-AGENT)`);
693418
+ console.log(`${"1.28.0"} (UR-AGENT)`);
693243
693419
  return;
693244
693420
  }
693245
693421
  if (args[0] === "a2a" && args[1] === "serve" && !args.includes("--help") && !args.includes("-h")) {