@xopcai/xopc 0.0.274 → 0.0.276

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. package/dist/browser-ext/_locales/en/messages.json +215 -0
  2. package/dist/browser-ext/_locales/zh_CN/messages.json +215 -0
  3. package/dist/browser-ext/dist/assets/{auth-O8RiOF3l.js → auth-ClQTK565.js} +97 -38
  4. package/dist/browser-ext/dist/assets/{sidepanel-C86O7q5Y.css → sidepanel-CeGqObOa.css} +41 -20
  5. package/dist/browser-ext/dist/background.js +36 -4
  6. package/dist/browser-ext/dist/sidepanel.html +2 -2
  7. package/dist/browser-ext/dist/sidepanel.js +416 -299
  8. package/dist/browser-ext/manifest.json +6 -4
  9. package/dist/extensions/feishu/src/outbound/media-load.js +1 -1
  10. package/dist/extensions/telegram/xopc.extension.json +1 -1
  11. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-BckaANxj.js → agent-avatar-dicebear-sj_1IC5H.js} +1 -1
  12. package/dist/gateway/static/root/assets/{agent-defaults-settings-panel-B8eyC6K1.js → agent-defaults-settings-panel-B5MRLEy8.js} +1 -1
  13. package/dist/gateway/static/root/assets/{agents-CSWj_yo1.js → agents-CIzev0Qj.js} +1 -1
  14. package/dist/gateway/static/root/assets/{app-management-settings-panel-DY-Zbgmt.js → app-management-settings-panel-DY3Vwxjq.js} +1 -1
  15. package/dist/gateway/static/root/assets/{appearance-settings-CoJR7ZRl.js → appearance-settings-BeXvF-dZ.js} +1 -1
  16. package/dist/gateway/static/root/assets/apps-page-Ch_9Ffgk.js +1 -0
  17. package/dist/gateway/static/root/assets/{archive-plugin-BwAlRT53.js → archive-plugin-BSgaIIGE.js} +1 -1
  18. package/dist/gateway/static/root/assets/{attachment-load-R835uxgL.js → attachment-load-CGNt02hP.js} +1 -1
  19. package/dist/gateway/static/root/assets/{automations-page-BEZy0P_u.js → automations-page-DoafJiVA.js} +1 -1
  20. package/dist/gateway/static/root/assets/automations-workspace-MACr99IO.js +6 -0
  21. package/dist/gateway/static/root/assets/{binary-plugins-CESFx3yb.js → binary-plugins-BsAL26Aq.js} +1 -1
  22. package/dist/gateway/static/root/assets/{block-editor-DDJcf2wR.js → block-editor-BxB7m8aI.js} +3 -3
  23. package/dist/gateway/static/root/assets/{browser-automations-page-BH4lSfr5.js → browser-automations-page-BNsO-Ip2.js} +2 -2
  24. package/dist/gateway/static/root/assets/browser-settings-page-Nvdoi0B1.js +8 -0
  25. package/dist/gateway/static/root/assets/capabilities-settings-panel-BluLJq5I.js +8 -0
  26. package/dist/gateway/static/root/assets/channels-settings-DYxxhcjb.js +1 -0
  27. package/dist/gateway/static/root/assets/{chat-terminal-dock-D8U97O95.js → chat-terminal-dock-ZCFwco1W.js} +2 -2
  28. package/dist/gateway/static/root/assets/connectors-page-Bpcp8UyE.js +2 -0
  29. package/dist/gateway/static/root/assets/{date-picker-7sDSMswL.js → date-picker-CpxFfgpg.js} +1 -1
  30. package/dist/gateway/static/root/assets/{dependency-picker-DMIC86ZW.js → dependency-picker-eCIGAfHa.js} +1 -1
  31. package/dist/gateway/static/root/assets/{desktop-pet-BtdiY5jK.js → desktop-pet-_MSZvIDO.js} +1 -1
  32. package/dist/gateway/static/root/assets/{desktop-pet-settings-D_B8azDH.js → desktop-pet-settings-feBnJWkV.js} +1 -1
  33. package/dist/gateway/static/root/assets/device-pairing-wizard-D_fB0fml.js +1 -0
  34. package/dist/gateway/static/root/assets/{extension-debug-page-CoFKb01d.js → extension-debug-page-CotBlxJ-.js} +1 -1
  35. package/dist/gateway/static/root/assets/{extension-page-CEkNsCAY.js → extension-page-CFBmQ7U3.js} +1 -1
  36. package/dist/gateway/static/root/assets/{extension-settings-page-Bi2R8P5j.js → extension-settings-page-Cd1lfh8z.js} +1 -1
  37. package/dist/gateway/static/root/assets/gateway-settings-BH35C8RI.js +1 -0
  38. package/dist/gateway/static/root/assets/{heartbeat-settings-DQtelFiU.js → heartbeat-settings-DRG0u1ON.js} +1 -1
  39. package/dist/gateway/static/root/assets/home-page-BlZk-aD4.js +1 -0
  40. package/dist/gateway/static/root/assets/{index-SxqsTD4i.js → index-CfQor-TM.js} +34 -34
  41. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-BuYmZS1K.js → keyboard-shortcuts-settings-BLHsdFIQ.js} +1 -1
  42. package/dist/gateway/static/root/assets/local-app-workbench-page-DJd71FlC.js +2 -0
  43. package/dist/gateway/static/root/assets/{local-apps-page-CExnZyGZ.js → local-apps-page-BjAj1xhq.js} +1 -1
  44. package/dist/gateway/static/root/assets/{logs-page-CA5ArMoN.js → logs-page-5MWeZ6Ae.js} +2 -2
  45. package/dist/gateway/static/root/assets/{management-settings-1UiJPrkX.js → management-settings-CPHxDaOw.js} +1 -1
  46. package/dist/gateway/static/root/assets/{media-plugins-nNFOk9HL.js → media-plugins-BUOzcXCL.js} +1 -1
  47. package/dist/gateway/static/root/assets/note-detail-panel-Bch98ut3.js +5 -0
  48. package/dist/gateway/static/root/assets/notes-page-CWO5dQKN.js +8 -0
  49. package/dist/gateway/static/root/assets/{page-tabs-CRombigq.js → page-tabs-BgEYFhqS.js} +1 -1
  50. package/dist/gateway/static/root/assets/{preview-open-alternatives-Bcuj43lk.js → preview-open-alternatives-C-pQIx6W.js} +1 -1
  51. package/dist/gateway/static/root/assets/{proactive-card-Cb3Xeoyx.js → proactive-card-DfjMVJUW.js} +1 -1
  52. package/dist/gateway/static/root/assets/{proactive-page-TbF9KVpm.js → proactive-page-BGVcVsbd.js} +1 -1
  53. package/dist/gateway/static/root/assets/project-detail-page-DZFVirjV.js +1 -0
  54. package/dist/gateway/static/root/assets/projects-page-B2g6inq-.js +1 -0
  55. package/dist/gateway/static/root/assets/remote-access-hub-CbkUOkQY.js +1 -0
  56. package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-BudlvBu-.js → runtime-tools-settings-panel-DkAjFJ-9.js} +2 -2
  57. package/dist/gateway/static/root/assets/{schema-form-Ch3MEX4h.js → schema-form-BpDcuSsl.js} +1 -1
  58. package/dist/gateway/static/root/assets/sessions-page--7-w-0WS.js +1 -0
  59. package/dist/gateway/static/root/assets/settings-advanced-gate-BvZrH_sp.js +1 -0
  60. package/dist/gateway/static/root/assets/{settings-form-section-CIA1AA-A.js → settings-form-section-RElRijJw.js} +1 -1
  61. package/dist/gateway/static/root/assets/{settings-page-B0Khoduh.js → settings-page-CaixunoA.js} +1 -1
  62. package/dist/gateway/static/root/assets/setup-status-panel-Ul06Y5YX.js +1 -0
  63. package/dist/gateway/static/root/assets/{share-preview-page-Cj9XWg-X.js → share-preview-page-CC-bFOTf.js} +1 -1
  64. package/dist/gateway/static/root/assets/shares-settings-DwV2Wh7S.js +1 -0
  65. package/dist/gateway/static/root/assets/{skill-reload-api-BM4Ezjbx.js → skill-reload-api-CcOtxf53.js} +1 -1
  66. package/dist/gateway/static/root/assets/{skills-page-Dyh1kf9t.js → skills-page-DmRvRxtY.js} +1 -1
  67. package/dist/gateway/static/root/assets/{skills-page.utils-DsQZkMti.js → skills-page.utils-CT0-daZD.js} +1 -1
  68. package/dist/gateway/static/root/assets/{system-settings-panel-BSho_Tpk.js → system-settings-panel-DRIJ5mXq.js} +1 -1
  69. package/dist/gateway/static/root/assets/task-detail-page-BQjLHqSk.js +1 -0
  70. package/dist/gateway/static/root/assets/{tunnel-api-4DUHxSQG.js → tunnel-api-IvWcgZdD.js} +1 -1
  71. package/dist/gateway/static/root/assets/{use-autosave-BG8Yx7hj.js → use-autosave-Cq4--C1i.js} +1 -1
  72. package/dist/gateway/static/root/assets/user-model-page-hwc5-nqV.js +2 -0
  73. package/dist/gateway/static/root/assets/{voice-api-key-field-DYXwDhHq.js → voice-api-key-field-CbJ6tKGI.js} +1 -1
  74. package/dist/gateway/static/root/assets/{work-discovery-overlay-CQqjzaRo.js → work-discovery-overlay-BG2pmXL3.js} +1 -1
  75. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-C5H-Fd-U.js → workflow-run-setup-panel-vw1229Fh.js} +2 -2
  76. package/dist/gateway/static/root/assets/workflows-page-DZWpJHDr.js +6 -0
  77. package/dist/gateway/static/root/index.html +1 -1
  78. package/dist/package.js +1 -1
  79. package/dist/src/agent/child-agent-factory.d.ts +3 -0
  80. package/dist/src/agent/child-agent-factory.js +2 -1
  81. package/dist/src/agent/external-tools/endpoint-provider.js +1 -1
  82. package/dist/src/agent/tools/factory.d.ts +1 -0
  83. package/dist/src/agent/tools/factory.js +21 -4
  84. package/dist/src/agent/workflow/workflow-child-tools.js +2 -0
  85. package/dist/src/browser/providers/browser-ext-install.d.ts +1 -1
  86. package/dist/src/browser/providers/browser-ext-install.js +86 -14
  87. package/dist/src/browser/providers/realtime-extension.d.ts +4 -1
  88. package/dist/src/browser/providers/realtime-extension.js +26 -10
  89. package/dist/src/browser/readiness.d.ts +4 -1
  90. package/dist/src/browser/readiness.js +11 -5
  91. package/dist/src/cli/commands/channels.js +1 -1
  92. package/dist/src/cli/commands/connectors.js +1 -1
  93. package/dist/src/cli/commands/extension-marketplace.js +2 -2
  94. package/dist/src/cli/commands/models.js +1 -1
  95. package/dist/src/cli/commands/onboard.js +1 -1
  96. package/dist/src/extensions/sdk/index.js +1 -1
  97. package/dist/src/extensions/update.js +1 -1
  98. package/dist/src/gateway/gateway-workflow-host.types.d.ts +2 -0
  99. package/dist/src/gateway/hono/routes/auth-registry-extensions.js +1 -1
  100. package/dist/src/gateway/hono/routes/browser.js +24 -11
  101. package/dist/src/gateway/hono/routes/endpoint-tools.js +9 -0
  102. package/dist/src/gateway/hono/routes/models.js +6 -0
  103. package/dist/src/gateway/service/config-coordinator.js +1 -1
  104. package/dist/src/gateway/service.js +3 -3
  105. package/dist/src/infra/update-runner.js +1 -1
  106. package/dist/src/providers/model-catalog-persistence.js +4 -0
  107. package/dist/src/providers/model-catalog-types.d.ts +1 -0
  108. package/dist/src/providers/xopc-cloud-model-source.js +12 -1
  109. package/dist/src/storage/sqlite/endpoint-session-binding-repository.d.ts +1 -0
  110. package/dist/src/storage/sqlite/endpoint-session-binding-repository.js +9 -1
  111. package/dist/src/storage/sqlite/index.d.ts +1 -1
  112. package/dist/src/storage/sqlite/index.js +2 -2
  113. package/dist/src/tui/backends/embedded-backend.js +1 -1
  114. package/dist/src/workflows/service/workflow-run-service.js +4 -1
  115. package/package.json +4 -4
  116. package/dist/gateway/static/root/assets/apps-page-CSMvkuot.js +0 -1
  117. package/dist/gateway/static/root/assets/automations-workspace-CpaI13J7.js +0 -6
  118. package/dist/gateway/static/root/assets/browser-settings-page-CbTooPd2.js +0 -8
  119. package/dist/gateway/static/root/assets/capabilities-settings-panel-C4LZWHhv.js +0 -8
  120. package/dist/gateway/static/root/assets/channels-settings-BAljmSa7.js +0 -1
  121. package/dist/gateway/static/root/assets/connectors-page-CVRMjNNr.js +0 -2
  122. package/dist/gateway/static/root/assets/device-pairing-wizard-Dmh3Nh4d.js +0 -1
  123. package/dist/gateway/static/root/assets/gateway-settings-q9p3sduo.js +0 -1
  124. package/dist/gateway/static/root/assets/home-page-COpGnTFZ.js +0 -1
  125. package/dist/gateway/static/root/assets/local-app-workbench-page-DV_17Zxc.js +0 -2
  126. package/dist/gateway/static/root/assets/note-detail-panel-B5OQ0fBY.js +0 -5
  127. package/dist/gateway/static/root/assets/notes-page-CVPPMVDl.js +0 -8
  128. package/dist/gateway/static/root/assets/project-detail-page-B9OQ2l9x.js +0 -1
  129. package/dist/gateway/static/root/assets/projects-page-DCqSTNkY.js +0 -1
  130. package/dist/gateway/static/root/assets/remote-access-hub-d9Fg70gX.js +0 -1
  131. package/dist/gateway/static/root/assets/sessions-page-D8RiQ-ag.js +0 -1
  132. package/dist/gateway/static/root/assets/settings-advanced-gate-DVH_l6Hr.js +0 -1
  133. package/dist/gateway/static/root/assets/setup-status-panel-COJFl4N_.js +0 -1
  134. package/dist/gateway/static/root/assets/shares-settings-_OuE6A0G.js +0 -1
  135. package/dist/gateway/static/root/assets/task-detail-page-B5HWM12k.js +0 -1
  136. package/dist/gateway/static/root/assets/user-model-page-IjVyv5jj.js +0 -2
  137. package/dist/gateway/static/root/assets/workflows-page-D1hMyPsY.js +0 -6
@@ -11,7 +11,7 @@ import { resolvePackageRoot } from "../../infra/update-check.js";
11
11
  import { dirname, join } from "node:path";
12
12
  import { chmodSync, existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
13
13
  import { fileURLToPath } from "node:url";
14
- import { spawn } from "node:child_process";
14
+ import { execFileSync, spawn } from "node:child_process";
15
15
  import { createHash } from "node:crypto";
16
16
  import { readFile, readdir, rm } from "node:fs/promises";
17
17
  import AdmZip from "adm-zip";
@@ -30,12 +30,15 @@ const STAGING_MAX_AGE_MS = 3600 * 1e3;
30
30
  const INSTALLED_ARTIFACT_NAMES = [
31
31
  "manifest.json",
32
32
  "dist",
33
- "icons"
33
+ "icons",
34
+ "_locales"
34
35
  ];
35
36
  const BROWSER_EXT_REQUIRED_FILES = [
36
37
  "manifest.json",
37
38
  "dist/background.js",
38
- "dist/sidepanel.html"
39
+ "dist/sidepanel.html",
40
+ "_locales/en/messages.json",
41
+ "_locales/zh_CN/messages.json"
39
42
  ];
40
43
  function moduleDir() {
41
44
  return dirname(fileURLToPath(import.meta.url));
@@ -53,7 +56,8 @@ function browserExtContentHash(dir) {
53
56
  const relativePaths = [
54
57
  "manifest.json",
55
58
  ...collectFiles("dist"),
56
- ...collectFiles("icons")
59
+ ...collectFiles("icons"),
60
+ ...collectFiles("_locales")
57
61
  ].sort();
58
62
  for (const relativePath of relativePaths) {
59
63
  hash.update(relativePath);
@@ -220,6 +224,7 @@ function copyBundledTree(src, dest) {
220
224
  mkdirSync(dest, { recursive: true });
221
225
  copyBundledFile(join(src, "manifest.json"), join(dest, "manifest.json"));
222
226
  copyBundledDirectory(join(src, "dist"), join(dest, "dist"));
227
+ copyBundledDirectory(join(src, "_locales"), join(dest, "_locales"));
223
228
  for (const icon of BROWSER_EXT_ICON_FILES) {
224
229
  const iconSrc = join(src, "icons", icon);
225
230
  if (existsSync(iconSrc)) copyBundledFile(iconSrc, join(dest, "icons", icon));
@@ -315,6 +320,42 @@ async function ensureBrowserExtensionArtifacts(opts) {
315
320
  function shellQuote(value) {
316
321
  return `'${value.replaceAll("'", "'\\''")}'`;
317
322
  }
323
+ const WINDOWS_NATIVE_HOST_KEYS = [
324
+ "Google\\Chrome",
325
+ "Chromium",
326
+ "Microsoft\\Edge",
327
+ "BraveSoftware\\Brave-Browser"
328
+ ].map((browser) => `HKCU\\Software\\${browser}\\NativeMessagingHosts\\${BROWSER_NATIVE_HOST_NAME}`);
329
+ function runNativeHostRegistry(args) {
330
+ return execFileSync("reg.exe", args, {
331
+ encoding: "utf8",
332
+ windowsHide: true,
333
+ stdio: [
334
+ "ignore",
335
+ "pipe",
336
+ "pipe"
337
+ ]
338
+ });
339
+ }
340
+ function windowsRegisteredNativeManifests() {
341
+ return [...new Set(WINDOWS_NATIVE_HOST_KEYS.flatMap((key) => {
342
+ try {
343
+ const path = runNativeHostRegistry([
344
+ "query",
345
+ key,
346
+ "/ve",
347
+ "/reg:32"
348
+ ]).match(/REG_SZ\s+([^\r\n]+)/)?.[1]?.trim();
349
+ return path ? [path] : [];
350
+ } catch {
351
+ return [];
352
+ }
353
+ }))];
354
+ }
355
+ function batchQuote(value) {
356
+ if (/["\r\n\0]/.test(value)) throw new Error("Invalid path in Windows native host launcher");
357
+ return `"${value.replaceAll("%", "%%")}"`;
358
+ }
318
359
  function browserNativeManifestDirectories(platform = process.platform, home = process.env.HOME || process.env.USERPROFILE || "") {
319
360
  if (!home) return [];
320
361
  if (platform === "darwin") return [
@@ -335,12 +376,12 @@ function browserNativeManifestDirectories(platform = process.platform, home = pr
335
376
  }
336
377
  function browserNativeHostDoctor(platform = process.platform, home = process.env.HOME || process.env.USERPROFILE || "") {
337
378
  const directories = browserNativeManifestDirectories(platform, home);
338
- if (directories.length === 0) return {
379
+ if (platform !== "win32" && directories.length === 0) return {
339
380
  installed: false,
340
381
  manifestPaths: [],
341
- reason: "Automatic local Gateway discovery is supported on macOS and Linux"
382
+ reason: "Automatic local Gateway discovery is supported on Windows, macOS and Linux"
342
383
  };
343
- const manifestPaths = directories.map((directory) => join(directory, `${BROWSER_NATIVE_HOST_NAME}.json`)).filter((manifestPath) => {
384
+ const manifestPaths = (platform === "win32" ? windowsRegisteredNativeManifests() : directories.map((directory) => join(directory, `${BROWSER_NATIVE_HOST_NAME}.json`))).filter((manifestPath) => {
344
385
  try {
345
386
  const manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
346
387
  return manifest.name === "ai.xopc.browser" && typeof manifest.path === "string" && existsSync(manifest.path) && Array.isArray(manifest.allowed_origins) && manifest.allowed_origins.includes(`chrome-extension://gopbfhaojnnhiheiikblejnpgmfmkmgd/`);
@@ -356,11 +397,12 @@ function browserNativeHostDoctor(platform = process.platform, home = process.env
356
397
  }
357
398
  /** Install the local-only bootstrap host used to discover and pair with a Gateway. */
358
399
  async function installBrowserNativeMessagingHost(opts) {
359
- const directories = browserNativeManifestDirectories(opts?.platform ?? process.platform, opts?.home);
360
- if (directories.length === 0) return {
400
+ const platform = opts?.platform ?? process.platform;
401
+ const directories = browserNativeManifestDirectories(platform, opts?.home);
402
+ if (platform !== "win32" && directories.length === 0) return {
361
403
  installed: false,
362
404
  manifestPaths: [],
363
- reason: "Automatic local Gateway discovery is supported on macOS and Linux"
405
+ reason: "Automatic local Gateway discovery is supported on Windows, macOS and Linux"
364
406
  };
365
407
  const cliPath = opts?.cliPath ?? process.argv[1];
366
408
  if (!cliPath) throw new Error("Unable to resolve the xopc CLI entry point");
@@ -376,12 +418,23 @@ async function installBrowserNativeMessagingHost(opts) {
376
418
  if (!existsSync(tsxPath)) throw new Error("Unable to install the browser native host in development: the tsx CLI entry was not found");
377
419
  executableArgs = [realpathSync(tsxPath), ...executableArgs];
378
420
  }
379
- const hostPath = join((opts?.cacheDir?.trim() ? assertCacheDir(opts.cacheDir) : resolveBinDir()) || resolveBinDir(), "browser-native-host");
421
+ const hostPath = join((opts?.cacheDir?.trim() ? assertCacheDir(opts.cacheDir) : resolveBinDir()) || resolveBinDir(), platform === "win32" ? "browser-native-host.cmd" : "browser-native-host");
380
422
  mkdirSync(dirname(hostPath), { recursive: true });
381
423
  const stateDir = opts?.stateDir ?? resolveStateDir();
382
424
  const configPath = opts?.configPath ?? resolveConfigPath();
383
- await writeTextAtomic(hostPath, `#!/bin/sh\nexec env ELECTRON_RUN_AS_NODE=1 XOPC_STATE_DIR=${shellQuote(stateDir)} XOPC_CONFIG_PATH=${shellQuote(configPath)} XOPC_LOG_CONSOLE=false ${shellQuote(executablePath)} ${executableArgs.map(shellQuote).join(" ")}\n`);
384
- chmodSync(hostPath, 493);
425
+ await writeTextAtomic(hostPath, platform === "win32" ? [
426
+ "@echo off",
427
+ "setlocal DisableDelayedExpansion",
428
+ "chcp 65001 >nul",
429
+ "set \"ELECTRON_RUN_AS_NODE=1\"",
430
+ `set ${batchQuote(`XOPC_STATE_DIR=${stateDir}`)}`,
431
+ `set ${batchQuote(`XOPC_CONFIG_PATH=${configPath}`)}`,
432
+ "set \"XOPC_LOG_CONSOLE=false\"",
433
+ `${batchQuote(executablePath)} ${executableArgs.map(batchQuote).join(" ")}`,
434
+ "exit /b %errorlevel%",
435
+ ""
436
+ ].join("\r\n") : `#!/bin/sh\nexec env ELECTRON_RUN_AS_NODE=1 XOPC_STATE_DIR=${shellQuote(stateDir)} XOPC_CONFIG_PATH=${shellQuote(configPath)} XOPC_LOG_CONSOLE=false ${shellQuote(executablePath)} ${executableArgs.map(shellQuote).join(" ")}\n`);
437
+ if (platform !== "win32") chmodSync(hostPath, 493);
385
438
  const manifest = JSON.stringify({
386
439
  name: BROWSER_NATIVE_HOST_NAME,
387
440
  description: "xopc local browser pairing bootstrap",
@@ -390,12 +443,31 @@ async function installBrowserNativeMessagingHost(opts) {
390
443
  allowed_origins: [`chrome-extension://${BROWSER_EXTENSION_ID}/`]
391
444
  }, null, 2);
392
445
  const manifestPaths = [];
393
- for (const directory of directories) {
446
+ for (const directory of platform === "win32" ? [dirname(hostPath)] : directories) {
394
447
  mkdirSync(directory, { recursive: true });
395
448
  const manifestPath = join(directory, `${BROWSER_NATIVE_HOST_NAME}.json`);
396
449
  await writeTextAtomic(manifestPath, manifest);
397
450
  manifestPaths.push(manifestPath);
398
451
  }
452
+ if (platform === "win32") try {
453
+ for (const key of WINDOWS_NATIVE_HOST_KEYS) runNativeHostRegistry([
454
+ "add",
455
+ key,
456
+ "/ve",
457
+ "/t",
458
+ "REG_SZ",
459
+ "/d",
460
+ manifestPaths[0],
461
+ "/f",
462
+ "/reg:32"
463
+ ]);
464
+ } catch (error) {
465
+ return {
466
+ installed: false,
467
+ manifestPaths,
468
+ reason: `Windows native host registration failed: ${error instanceof Error ? error.message : String(error)}`
469
+ };
470
+ }
399
471
  return {
400
472
  installed: true,
401
473
  manifestPaths
@@ -21,9 +21,12 @@ export declare class RealtimeExtensionBrowserProvider {
21
21
  expectedProtocolVersion: number;
22
22
  extensionVersion: string;
23
23
  principalId: string;
24
+ endpointCount: number;
25
+ selectionRequired: boolean;
24
26
  transport: "gateway-realtime";
25
27
  };
26
28
  shutdown(): Promise<void>;
27
29
  private endpointForInput;
28
- private currentEndpoint;
30
+ private defaultEndpoint;
31
+ private browserEndpoints;
29
32
  }
@@ -14,14 +14,18 @@ var RealtimeExtensionBrowserProvider = class {
14
14
  async start() {}
15
15
  async waitForConnection(timeoutMs = this.connectionTimeout) {
16
16
  const deadline = Date.now() + timeoutMs;
17
- while (!this.currentEndpoint()) {
17
+ while (this.browserEndpoints().length === 0) {
18
18
  if (Date.now() >= deadline) throw new Error(`Extension connection timeout after ${timeoutMs}ms. Open the xopc Chrome extension and connect it to this Gateway.`);
19
19
  await new Promise((resolve) => setTimeout(resolve, 200));
20
20
  }
21
21
  }
22
22
  async send(input, timeoutMs = this.commandTimeout, visualFallback = true) {
23
23
  const endpoint = this.endpointForInput(input);
24
- if (!endpoint) throw new Error("Extension not connected to this Gateway. Open the xopc Chrome extension and connect it first.");
24
+ if (!endpoint) {
25
+ if (input.target?.kind === "endpoint") throw new Error(`The Chrome endpoint bound to this Session is offline (${input.target.endpointId}). Reconnect that browser or bind another one.`);
26
+ if (this.browserEndpoints().length > 1) throw new Error("Multiple Chrome extensions are connected. Attach this Session to a tab or choose a browser device first.");
27
+ throw new Error("Extension not connected to this Gateway. Open the xopc Chrome extension and connect it first.");
28
+ }
25
29
  const tool = this.runtime.registry.getTool(endpoint.endpointId, BROWSER_CONTROL_ENDPOINT_TOOL_NAME);
26
30
  if (!tool) throw new Error("Connected browser extension does not support authenticated Realtime browser control. Reload or update the extension.");
27
31
  const id = crypto.randomUUID();
@@ -51,17 +55,20 @@ var RealtimeExtensionBrowserProvider = class {
51
55
  }
52
56
  }
53
57
  isConnected() {
54
- return Boolean(this.currentEndpoint());
58
+ return this.browserEndpoints().length > 0;
55
59
  }
56
60
  getConnectionStatus() {
57
- const endpoint = this.currentEndpoint();
61
+ const endpoints = this.browserEndpoints();
62
+ const endpoint = endpoints.length === 1 ? endpoints[0] : void 0;
58
63
  return {
59
- socketConnected: Boolean(endpoint),
60
- connected: Boolean(endpoint),
61
- protocolVersion: endpoint ? 4 : null,
64
+ socketConnected: endpoints.length > 0,
65
+ connected: endpoints.length > 0,
66
+ protocolVersion: endpoints.length > 0 ? 4 : null,
62
67
  expectedProtocolVersion: 4,
63
68
  extensionVersion: endpoint?.appVersion ?? null,
64
69
  principalId: endpoint?.principalId ?? null,
70
+ endpointCount: endpoints.length,
71
+ selectionRequired: endpoints.length > 1,
65
72
  transport: "gateway-realtime"
66
73
  };
67
74
  }
@@ -73,10 +80,19 @@ var RealtimeExtensionBrowserProvider = class {
73
80
  if (!binding || !endpoint || endpoint.principalId !== binding.principalId) return void 0;
74
81
  return endpoint;
75
82
  }
76
- return this.currentEndpoint();
83
+ if (input.target?.kind === "endpoint") {
84
+ const endpoint = this.runtime.registry.get(input.target.endpointId);
85
+ if (!endpoint || endpoint.kind !== "browser" || !endpoint.tools.some((tool) => tool.descriptor.name === "browser.control")) return;
86
+ return endpoint;
87
+ }
88
+ return this.defaultEndpoint();
89
+ }
90
+ defaultEndpoint() {
91
+ const endpoints = this.browserEndpoints();
92
+ return endpoints.length === 1 ? endpoints[0] : void 0;
77
93
  }
78
- currentEndpoint() {
79
- return this.runtime.registry.list().filter((endpoint) => endpoint.kind === "browser" && endpoint.tools.some((tool) => tool.descriptor.name === "browser.control")).sort((left, right) => right.lastHeartbeatAt - left.lastHeartbeatAt)[0];
94
+ browserEndpoints() {
95
+ return this.runtime.registry.list().filter((endpoint) => endpoint.kind === "browser" && endpoint.tools.some((tool) => tool.descriptor.name === "browser.control")).sort((left, right) => right.lastHeartbeatAt - left.lastHeartbeatAt);
80
96
  }
81
97
  };
82
98
  //#endregion
@@ -12,4 +12,7 @@ export declare class BrowserNotReadyError extends Error {
12
12
  constructor(hint: BrowserSetupHint);
13
13
  }
14
14
  export declare function buildBrowserSetupDeepLink(driver: BrowserDriverKind): string;
15
- export declare function checkBrowserReadiness(cfg: Config | undefined): Promise<BrowserNotReadyError | null>;
15
+ export declare function checkBrowserReadiness(cfg: Config | undefined, options?: {
16
+ extensionConnected?: boolean;
17
+ checkExtensionInstall?: boolean;
18
+ }): Promise<BrowserNotReadyError | null>;
@@ -14,17 +14,23 @@ var BrowserNotReadyError = class extends Error {
14
14
  function buildBrowserSetupDeepLink(driver) {
15
15
  return `/settings/agent-browser?driver=${driver}`;
16
16
  }
17
- async function checkBrowserReadiness(cfg) {
17
+ async function checkBrowserReadiness(cfg, options = {}) {
18
18
  if (!cfg?.browser.enabled) return null;
19
19
  const driver = cfg.browser.driver;
20
20
  let detail = null;
21
21
  let reason = null;
22
22
  try {
23
23
  if (driver.kind === "extension") {
24
- const { browserExtDoctor } = await import("./providers/browser-ext-install.js");
25
- if (!(await browserExtDoctor()).installed) {
26
- reason = "extension_not_installed";
27
- detail = "Chrome extension artifacts are not installed.";
24
+ if (options.extensionConnected) return null;
25
+ if (options.checkExtensionInstall === false) {
26
+ reason = "extension_not_connected";
27
+ detail = "No authenticated Chrome extension endpoint is connected.";
28
+ } else {
29
+ const { browserExtDoctor } = await import("./providers/browser-ext-install.js");
30
+ if (!(await browserExtDoctor()).installed) {
31
+ reason = "extension_not_installed";
32
+ detail = "Chrome extension artifacts are not installed.";
33
+ }
28
34
  }
29
35
  } else if (driver.kind === "playwright") if (driver.executablePath) await access(driver.executablePath);
30
36
  else {
@@ -1,8 +1,8 @@
1
1
  import { buildChannelCatalogForConfig, init_channel_catalog_service } from "../../channels/catalog/channel-catalog-service.js";
2
2
  import { init_loader, loadConfig, saveConfig } from "../../config/loader.js";
3
+ import { formatExamples, register } from "../registry.js";
3
4
  import { listChannelPairingState } from "../../channels/pairing/pairing-service.js";
4
5
  import { approveChannelPairingFromCli } from "../../channels/pairing/approve-cli.js";
5
- import { formatExamples, register } from "../registry.js";
6
6
  import { colors } from "../utils/colors.js";
7
7
  import { Command } from "commander";
8
8
  //#region src/cli/commands/channels.ts
@@ -1,8 +1,8 @@
1
1
  import { init_loader, loadConfig, saveConfig } from "../../config/loader.js";
2
2
  import { getStoreConnectorInstallPlan, installStoreConnector, listStoreConnectors } from "../../capabilities/store-connector.js";
3
3
  import { register } from "../registry.js";
4
- import { confirm } from "@inquirer/prompts";
5
4
  import { Command } from "commander";
5
+ import { confirm } from "@inquirer/prompts";
6
6
  //#region src/cli/commands/connectors.ts
7
7
  init_loader();
8
8
  function parsePairs(values, option) {
@@ -3,9 +3,9 @@ import { init_loader, loadConfig } from "../../config/loader.js";
3
3
  import { downloadExtensionStoreZipBuffer, resolveExtensionZipDownloadUrl, resolveExtensionsStoreBaseUrl, verifyStoreArtifactSha256 } from "../../agent/skills/marketplace/adapters/store/store-api-client.js";
4
4
  import { getContextWithOpts } from "../context.js";
5
5
  import { getExtensionLockfileManager } from "../../extensions/lockfile.js";
6
+ import { fetchRegistry, findExtension, getExtensionMarketplaceStoreBaseUrl, listExtensions, searchExtensions } from "../../extensions/marketplace.js";
6
7
  import { installFromLocal, installFromNpm, peekExtensionManifestFromStoreZip } from "../../extensions/install.js";
7
8
  import { commitStagedExtensionInstall, finalizeStagedExtensionInstall, rollbackStagedExtensionInstall, stageExtensionStoreZip } from "../../extensions/install-transaction.js";
8
- import { fetchRegistry, findExtension, getExtensionMarketplaceStoreBaseUrl, listExtensions, searchExtensions } from "../../extensions/marketplace.js";
9
9
  import { colors } from "../utils/colors.js";
10
10
  import { validateExtensionPackageDirectory } from "./extension-pack.js";
11
11
  import { join, resolve } from "node:path";
@@ -13,8 +13,8 @@ import { existsSync, readFileSync, rmSync, statSync } from "node:fs";
13
13
  import { execSync } from "node:child_process";
14
14
  import { createHash } from "node:crypto";
15
15
  import semver from "semver";
16
- import { confirm } from "@inquirer/prompts";
17
16
  import { Command } from "commander";
17
+ import { confirm } from "@inquirer/prompts";
18
18
  //#region src/cli/commands/extension-marketplace.ts
19
19
  init_loader();
20
20
  init_paths();
@@ -9,8 +9,8 @@ import { prepareUpdateGlobalDefaults } from "../../gateway/global-defaults-admin
9
9
  import { disconnectProvider } from "../../providers/provider-disconnect.js";
10
10
  import { colors } from "../utils/colors.js";
11
11
  import { runCliOAuthLogin } from "../utils/oauth-login.js";
12
- import { input } from "@inquirer/prompts";
13
12
  import { Command } from "commander";
13
+ import { input } from "@inquirer/prompts";
14
14
  //#region src/cli/commands/models.ts
15
15
  init_credentials();
16
16
  init_schema();
@@ -10,8 +10,8 @@ import { initWorkspace } from "../utils/init-workspace.js";
10
10
  import { setupModel } from "./onboard/model.js";
11
11
  import { getChannelConfigurators } from "./onboard/channels/registry.js";
12
12
  import { setupChannels } from "./onboard/channels/index.js";
13
- import { select } from "@inquirer/prompts";
14
13
  import { Command } from "commander";
14
+ import { select } from "@inquirer/prompts";
15
15
  //#region src/cli/commands/onboard.ts
16
16
  init_schema();
17
17
  init_paths_state();
@@ -7,8 +7,8 @@ import { SlotRegistry, getSlotRegistry, registerSlotType } from "../slots.js";
7
7
  import { ExtensionDiagnostics, ExtensionLoaderCacheImpl, getExtensionCache, getExtensionDiagnostics } from "../diagnostics.js";
8
8
  import "../loader.js";
9
9
  import { ExtensionHookRunner, createHookContext, isHookEvent } from "../hooks.js";
10
- import { defineChannelPluginEntry } from "./channel-entry.js";
11
10
  import { registerExtensionCliProgram } from "./channel-helpers.js";
11
+ import { defineChannelPluginEntry } from "./channel-entry.js";
12
12
  import { lazyFunction, lazyModule } from "./lazy.js";
13
13
  import { createMockExtensionApi, createTestGateway } from "./testing.js";
14
14
  //#region src/extensions/sdk/index.ts
@@ -4,8 +4,8 @@ import { init_paths, resolveBundledExtensionsDir, resolveExtensionsDir } from ".
4
4
  import { init_loader, loadConfig } from "../config/loader.js";
5
5
  import { downloadExtensionStoreZipBuffer, resolveExtensionZipDownloadUrl, resolveExtensionsStoreBaseUrl, verifyStoreArtifactSha256 } from "../agent/skills/marketplace/adapters/store/store-api-client.js";
6
6
  import { getExtensionLockfileManager } from "./lockfile.js";
7
- import { installExtensionFromStoreZip, installFromNpm } from "./install.js";
8
7
  import { findExtension } from "./marketplace.js";
8
+ import { installExtensionFromStoreZip, installFromNpm } from "./install.js";
9
9
  import { join } from "node:path";
10
10
  import { existsSync, readFileSync, readdirSync, rmSync } from "node:fs";
11
11
  import semver from "semver";
@@ -1,4 +1,5 @@
1
1
  import type { Config } from '../config/schema.js';
2
+ import type { EndpointToolRuntime } from '../endpoint-tools/index.js';
2
3
  import type { MessageBus } from '../infra/bus/index.js';
3
4
  import type { SessionStore } from '../session/store.js';
4
5
  export interface GatewayWorkflowAgentSurface {
@@ -10,6 +11,7 @@ export interface GatewayWorkflowHost {
10
11
  readonly currentWorkspacePath: string;
11
12
  readonly messageBusInstance: MessageBus;
12
13
  readonly agentService: GatewayWorkflowAgentSurface;
14
+ readonly endpointTools?: EndpointToolRuntime;
13
15
  emit(event: string, payload: unknown): void;
14
16
  readonly sessionIndexInstance: {
15
17
  getStore(): SessionStore;
@@ -1,8 +1,8 @@
1
1
  import { getAllModels, getAvailableModels, init_providers } from "../../../providers/index.js";
2
2
  import { ActivationPlanner } from "../../../extensions/activation-planner.js";
3
3
  import { mergeActivationContext } from "../../../extensions/activation-context.js";
4
- import { fetchRegistry, listExtensions, searchExtensions } from "../../../extensions/marketplace.js";
5
4
  import { buildWhenContextSnapshot } from "../../../extensions/when-context.js";
5
+ import { fetchRegistry, listExtensions, searchExtensions } from "../../../extensions/marketplace.js";
6
6
  import { createOAuthAsyncHandler } from "../oauth-async.js";
7
7
  import { createOAuthHandler } from "../oauth.js";
8
8
  import { extensionAssetMimeType } from "../lib/extension-assets.js";
@@ -10,12 +10,12 @@ import { getGatewayPrincipal } from "../../security/gateway-principal.js";
10
10
  import { getConnInfo } from "@hono/node-server/conninfo";
11
11
  //#region src/gateway/hono/routes/browser.ts
12
12
  /** Browser Control status, approvals, and driver diagnostics. */
13
- async function extensionStatus(service) {
14
- const endpoint = service.endpointTools.registry.list().filter((item) => item.kind === "browser" && item.tools.some((tool) => tool.descriptor.name === "browser.control")).sort((left, right) => right.lastHeartbeatAt - left.lastHeartbeatAt)[0];
15
- const connected = Boolean(endpoint);
13
+ async function extensionStatus(service, includeLocalArtifacts) {
14
+ const endpoints = service.endpointTools.registry.list().filter((item) => item.kind === "browser" && item.tools.some((tool) => tool.descriptor.name === "browser.control")).sort((left, right) => right.lastHeartbeatAt - left.lastHeartbeatAt);
15
+ const endpoint = endpoints[0];
16
+ const connected = endpoints.length > 0;
16
17
  const extensionVersion = endpoint?.appVersion ?? null;
17
- const { browserExtDoctor } = await import("../../../browser/providers/browser-ext-install.js");
18
- const doctor = await browserExtDoctor({ runtimeExtensionVersion: extensionVersion ?? void 0 });
18
+ const doctor = includeLocalArtifacts ? await import("../../../browser/providers/browser-ext-install.js").then(({ browserExtDoctor }) => browserExtDoctor({ runtimeExtensionVersion: extensionVersion ?? void 0 })) : void 0;
19
19
  return {
20
20
  running: true,
21
21
  socketConnected: connected,
@@ -24,7 +24,15 @@ async function extensionStatus(service) {
24
24
  protocolVersion: connected ? 4 : null,
25
25
  expectedProtocolVersion: 4,
26
26
  extensionVersion,
27
- artifacts: {
27
+ endpoints: endpoints.map((item) => ({
28
+ endpointId: item.endpointId,
29
+ principalId: item.principalId,
30
+ displayName: item.displayName,
31
+ platform: item.platform,
32
+ appVersion: item.appVersion,
33
+ lastHeartbeatAt: item.lastHeartbeatAt
34
+ })),
35
+ artifacts: { ...doctor ? {
28
36
  installed: doctor.installed,
29
37
  bundledAvailable: doctor.bundledAvailable,
30
38
  extensionDir: doctor.extensionDir,
@@ -33,9 +41,9 @@ async function extensionStatus(service) {
33
41
  needsRefresh: doctor.needsRefresh,
34
42
  needsChromeReload: doctor.needsChromeReload,
35
43
  nativeHost: doctor.nativeHost
36
- },
44
+ } : {} },
37
45
  bridgeHeld: false,
38
- refCount: connected ? 1 : 0,
46
+ refCount: endpoints.length,
39
47
  transport: "gateway-realtime"
40
48
  };
41
49
  }
@@ -148,7 +156,7 @@ function registerBrowserRoutes(authenticated, deps) {
148
156
  });
149
157
  authenticated.get("/api/browser/extension-status", async (c) => {
150
158
  try {
151
- return c.json(await extensionStatus(service));
159
+ return c.json(await extensionStatus(service, isLocalOwnerRequest(c, service)));
152
160
  } catch (error) {
153
161
  return c.json({
154
162
  running: false,
@@ -160,6 +168,7 @@ function registerBrowserRoutes(authenticated, deps) {
160
168
  });
161
169
  authenticated.get("/api/browser/status", async (c) => {
162
170
  const config = service.currentConfig.browser;
171
+ const localManagementAvailable = isLocalOwnerRequest(c, service);
163
172
  if (!config.enabled) return c.json({
164
173
  ok: true,
165
174
  payload: {
@@ -168,15 +177,19 @@ function registerBrowserRoutes(authenticated, deps) {
168
177
  state: "disabled"
169
178
  }
170
179
  });
171
- const readiness = await checkBrowserReadiness(service.currentConfig);
172
- const driverStatus = config.driver.kind === "extension" ? await extensionStatus(service).catch((error) => ({ error: error instanceof Error ? error.message : String(error) })) : config.driver.kind === "playwright" ? await import("../../../browser/providers/playwright-doctor.js").then(({ playwrightChromiumDoctor }) => playwrightChromiumDoctor()) : void 0;
180
+ const driverStatus = config.driver.kind === "extension" ? await extensionStatus(service, localManagementAvailable).catch((error) => ({ error: error instanceof Error ? error.message : String(error) })) : config.driver.kind === "playwright" ? await import("../../../browser/providers/playwright-doctor.js").then(({ playwrightChromiumDoctor }) => playwrightChromiumDoctor()) : void 0;
173
181
  const extensionConnected = config.driver.kind === "extension" ? driverStatus.connected === true : true;
182
+ const readiness = await checkBrowserReadiness(service.currentConfig, {
183
+ extensionConnected,
184
+ checkExtensionInstall: localManagementAvailable
185
+ });
174
186
  const extensionProtocolDetail = config.driver.kind === "extension" && "socketConnected" in driverStatus && driverStatus.socketConnected && !driverStatus.connected ? `Chrome extension protocol ${driverStatus.protocolVersion ?? "unknown"} does not match ${driverStatus.expectedProtocolVersion ?? "the gateway"}. Reload the extension in Chrome.` : void 0;
175
187
  return c.json({
176
188
  ok: true,
177
189
  payload: {
178
190
  enabled: true,
179
191
  driverKind: config.driver.kind,
192
+ localManagementAvailable,
180
193
  state: !readiness && extensionConnected ? "ready" : "needs_attention",
181
194
  reason: readiness?.hint.reason ?? (extensionConnected ? void 0 : "extension_not_connected"),
182
195
  detail: readiness?.hint.detail ?? extensionProtocolDetail,
@@ -177,6 +177,15 @@ function registerEndpointToolRoutes(authenticated, deps) {
177
177
  message: "Invalid endpoint binding"
178
178
  }
179
179
  }, 400);
180
+ const gatewayPrincipal = getGatewayPrincipal(c);
181
+ const endpoint = deps.service.endpointTools.registry.get(parsed.data.endpointId);
182
+ if (gatewayPrincipal.kind === "device" && (!endpoint || !gatewayPrincipal.deviceId || endpoint.principalId !== gatewayPrincipal.deviceId)) return c.json({
183
+ ok: false,
184
+ error: {
185
+ code: "FORBIDDEN",
186
+ message: "Endpoint does not belong to this device"
187
+ }
188
+ }, 403);
180
189
  try {
181
190
  const binding = deps.service.endpointTools.bindings.bind(c.req.param("sessionKey"), parsed.data.endpointId);
182
191
  return c.json({
@@ -28,6 +28,10 @@ init_providers();
28
28
  init_credentials();
29
29
  init_model_catalog_store();
30
30
  init_plugin_registry();
31
+ function catalogDisplayNames(providerId, modelId) {
32
+ const model = getModelCatalogStore().getSource(providerId)?.models.find((item) => item.id === modelId);
33
+ return model?.displayNames ? { displayNames: model.displayNames } : {};
34
+ }
31
35
  function readModelsJsonProviderApiKey(providerId) {
32
36
  const { config } = loadModelsJson(resolveModelsJsonPath());
33
37
  const key = (config.providers?.[providerId.trim()])?.apiKey;
@@ -292,6 +296,7 @@ function registerModelsRoutes(authenticated, deps) {
292
296
  const models = sortModelsForPicker(await getAvailableModels()).map((m) => ({
293
297
  id: `${m.provider}/${m.id}`,
294
298
  name: m.name,
299
+ ...catalogDisplayNames(m.provider, m.id),
295
300
  provider: m.provider,
296
301
  contextWindow: m.contextWindow ?? 128e3,
297
302
  maxTokens: m.maxTokens ?? 4096,
@@ -656,6 +661,7 @@ function registerModelsRoutes(authenticated, deps) {
656
661
  const models = sortModelsForPicker(allModels).map((m) => ({
657
662
  id: `${m.provider}/${m.id}`,
658
663
  name: m.name,
664
+ ...catalogDisplayNames(m.provider, m.id),
659
665
  provider: m.provider,
660
666
  contextWindow: m.contextWindow ?? 128e3,
661
667
  maxTokens: m.maxTokens ?? 4096,
@@ -8,8 +8,8 @@ import { reloadImageGenerationProviders } from "../../agent/image/generation/pro
8
8
  import "../../agent/mcp/bundle-mcp-tools.js";
9
9
  import { ConfigHotReloader } from "../../config/reload.js";
10
10
  import "../../config/index.js";
11
- import { computeBundledExtensionExtensionsPatch } from "../../extensions/bundled-extension-activation.js";
12
11
  import { sanitizeTunnelConfig } from "../../tunnel/tunnel-config.js";
12
+ import { computeBundledExtensionExtensionsPatch } from "../../extensions/bundled-extension-activation.js";
13
13
  //#region src/gateway/service/config-coordinator.ts
14
14
  init_providers();
15
15
  init_logger();
@@ -51,9 +51,6 @@ import { MessageBus, MessageBusShutdownError } from "../infra/bus/queue.js";
51
51
  import "../infra/bus/index.js";
52
52
  import { AgentService } from "../agent/service.js";
53
53
  import { ensureStarterAgentsInitialized } from "../agent/starter-agents.js";
54
- import { setPairingBroadcastSink } from "../channels/pairing/pairing-events.js";
55
- import { registerClarificationChannelRuntime } from "./clarify-runtime.js";
56
- import { ChannelManager } from "../channels/manager.js";
57
54
  import { getWorkspacePath } from "../config/workspace-path-helpers.js";
58
55
  import "../config/index.js";
59
56
  import { ManagedComposioEventPoller } from "../connectors/composio-managed-events.js";
@@ -71,6 +68,9 @@ import { DiscussionSealer } from "../discussions/sealer.js";
71
68
  import "../discussions/index.js";
72
69
  import { EndpointToolRuntime } from "../endpoint-tools/runtime.js";
73
70
  import "../endpoint-tools/index.js";
71
+ import { setPairingBroadcastSink } from "../channels/pairing/pairing-events.js";
72
+ import { registerClarificationChannelRuntime } from "./clarify-runtime.js";
73
+ import { ChannelManager } from "../channels/manager.js";
74
74
  import { assertGatewayAuthConfigured, extractToken, resolveGatewayAuth, validateToken } from "./auth.js";
75
75
  import { prepareAutomationAgentSession } from "./automation-agent-session.js";
76
76
  import { stopTailscaleExposure } from "./tailscale-lifecycle.js";
@@ -1,6 +1,6 @@
1
- import { runPostUpdateExtensionSync } from "../extensions/update.js";
2
1
  import "./update-channels.js";
3
2
  import { compareSemver, resolveNpmChannelTag } from "./update-check.js";
3
+ import { runPostUpdateExtensionSync } from "../extensions/update.js";
4
4
  import { readPackageName, readPackageVersion } from "./package-json.js";
5
5
  import { createDefaultCommandRunner, runCommandWithTimeout } from "./run-command.js";
6
6
  import { XOPC_PACKAGE_NAME, cleanupGlobalRenameDirs, createGlobalInstallEnv, detectGlobalInstallManagerForRoot, resolveGlobalInstallSpec, resolveGlobalInstallTarget } from "./update-global.js";
@@ -62,6 +62,10 @@ var init_model_catalog_persistence = __esmMin((() => {
62
62
  catalogModelSchema = z.object({
63
63
  id: z.string().min(1),
64
64
  name: z.string().min(1),
65
+ displayNames: z.object({
66
+ "zh-CN": z.string().min(1).optional(),
67
+ en: z.string().min(1).optional()
68
+ }).strict().optional(),
65
69
  availability: z.enum(["available", "unavailable"]),
66
70
  kind: z.enum([
67
71
  "language",
@@ -1,6 +1,7 @@
1
1
  export interface CatalogModel {
2
2
  id: string;
3
3
  name: string;
4
+ displayNames?: Partial<Record<'zh-CN' | 'en', string>>;
4
5
  availability: 'available' | 'unavailable';
5
6
  kind: 'language' | 'image' | 'stt' | 'tts';
6
7
  input: Array<'text' | 'image' | 'audio'>;
@@ -52,7 +52,8 @@ var XopcCloudModelSource = class {
52
52
  const tts = kind === "tts" ? parseTtsCapabilities(model.xopc?.capabilities, model.xopc?.defaultVoice) : void 0;
53
53
  const catalogModel = {
54
54
  id: model.id,
55
- name: model.id,
55
+ name: typeof model.xopc?.displayName === "string" && model.xopc.displayName.trim() ? model.xopc.displayName.trim() : model.id,
56
+ ...parseDisplayNames(model.xopc?.displayNames),
56
57
  kind,
57
58
  input,
58
59
  output,
@@ -180,5 +181,15 @@ function parseImageGenerationCapabilities(value) {
180
181
  maxInputImages: Number.isSafeInteger(raw.maxInputImages) && Number(raw.maxInputImages) > 0 ? Number(raw.maxInputImages) : 0
181
182
  };
182
183
  }
184
+ function parseDisplayNames(value) {
185
+ if (!value || typeof value !== "object" || Array.isArray(value)) return {};
186
+ const raw = value;
187
+ const displayNames = {};
188
+ for (const locale of ["zh-CN", "en"]) {
189
+ const name = raw[locale];
190
+ if (typeof name === "string" && name.trim()) displayNames[locale] = name.trim();
191
+ }
192
+ return Object.keys(displayNames).length ? { displayNames } : {};
193
+ }
183
194
  //#endregion
184
195
  export { XopcCloudModelError, XopcCloudModelSource };