@xopcai/xopc 0.0.267 → 0.0.268

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 (116) hide show
  1. package/dist/browser-ext/dist/assets/{auth-D_IL6naL.js → auth-cwEj8rFb.js} +140 -29
  2. package/dist/browser-ext/dist/assets/sidepanel-C86O7q5Y.css +299 -0
  3. package/dist/browser-ext/dist/background.js +2 -2
  4. package/dist/browser-ext/dist/sidepanel.html +2 -2
  5. package/dist/browser-ext/dist/sidepanel.js +9501 -427
  6. package/dist/browser-ext/manifest.json +1 -1
  7. package/dist/extensions/telegram/xopc.extension.json +1 -1
  8. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-ZrSAMchm.js → agent-avatar-dicebear-B9WObxjr.js} +1 -1
  9. package/dist/gateway/static/root/assets/{agent-defaults-settings-panel-DiNFN8qS.js → agent-defaults-settings-panel-J1YFNG26.js} +1 -1
  10. package/dist/gateway/static/root/assets/{agents-Bu6Hf59K.js → agents-BJuTIRPD.js} +1 -1
  11. package/dist/gateway/static/root/assets/{app-management-settings-panel-D-L6yjS7.js → app-management-settings-panel-Bbn9mDfL.js} +1 -1
  12. package/dist/gateway/static/root/assets/{appearance-settings-BW5eb53j.js → appearance-settings-Deo5EsIc.js} +1 -1
  13. package/dist/gateway/static/root/assets/{apps-page-CiQIdz3N.js → apps-page-Cz4d7ErX.js} +1 -1
  14. package/dist/gateway/static/root/assets/{archive-plugin-DwXvu1p9.js → archive-plugin-CxJTU8MU.js} +1 -1
  15. package/dist/gateway/static/root/assets/{attachment-load-DqU2BYBp.js → attachment-load-C71Cukgp.js} +1 -1
  16. package/dist/gateway/static/root/assets/{automations-page-C7qoj9Sd.js → automations-page-_J7UZ55Q.js} +1 -1
  17. package/dist/gateway/static/root/assets/{automations-workspace-CIARTLHO.js → automations-workspace-Bn8nwUOL.js} +1 -1
  18. package/dist/gateway/static/root/assets/{binary-plugins-CfplDak2.js → binary-plugins-CX8fC8Zt.js} +1 -1
  19. package/dist/gateway/static/root/assets/{block-editor-CzLs38ru.js → block-editor-Ci9fjoQL.js} +1 -1
  20. package/dist/gateway/static/root/assets/{browser-automations-page-_SKi8s9b.js → browser-automations-page-rDSx0ozx.js} +1 -1
  21. package/dist/gateway/static/root/assets/{browser-settings-page-DTdx66sX.js → browser-settings-page-B9RA6x4x.js} +1 -1
  22. package/dist/gateway/static/root/assets/{capabilities-settings-panel-Ck9U0Olx.js → capabilities-settings-panel-C1GUih8m.js} +1 -1
  23. package/dist/gateway/static/root/assets/{channels-settings-I_vDpbnl.js → channels-settings-CEhVLJNa.js} +1 -1
  24. package/dist/gateway/static/root/assets/{chat-terminal-dock-snvAu3hJ.js → chat-terminal-dock-DMSl8KxS.js} +1 -1
  25. package/dist/gateway/static/root/assets/{connectors-page-BmKTnzo1.js → connectors-page-IQAQDSmO.js} +1 -1
  26. package/dist/gateway/static/root/assets/{cron-expression-BhGZSbT6.js → cron-expression-BByq6Uh8.js} +1 -1
  27. package/dist/gateway/static/root/assets/{date-picker-Cep5f9b-.js → date-picker-m6JZCUEW.js} +1 -1
  28. package/dist/gateway/static/root/assets/{dependency-picker-BzSEBQku.js → dependency-picker-CwCAjbaJ.js} +1 -1
  29. package/dist/gateway/static/root/assets/{desktop-pet-BwX_6Gah.js → desktop-pet-DSmeEREd.js} +1 -1
  30. package/dist/gateway/static/root/assets/{desktop-pet-settings-WrbVsU2b.js → desktop-pet-settings-MfKceMoe.js} +1 -1
  31. package/dist/gateway/static/root/assets/{extension-debug-page-BdXSwtAZ.js → extension-debug-page-CwvWy26h.js} +1 -1
  32. package/dist/gateway/static/root/assets/{extension-page-I95ukbRb.js → extension-page-DLrbVBHM.js} +1 -1
  33. package/dist/gateway/static/root/assets/{extension-settings-page-8zUisBay.js → extension-settings-page-BI6C4PM-.js} +1 -1
  34. package/dist/gateway/static/root/assets/{gateway-settings-DGj5b9Yv.js → gateway-settings-B3H7Vfbh.js} +1 -1
  35. package/dist/gateway/static/root/assets/{heartbeat-settings-BGQxU-Ug.js → heartbeat-settings-CUl832Tb.js} +1 -1
  36. package/dist/gateway/static/root/assets/{home-page-BZPpK0A3.js → home-page-CT4JL2jm.js} +1 -1
  37. package/dist/gateway/static/root/assets/{index-D2OtD9Wa.js → index-wKE8Q2FX.js} +7 -7
  38. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-BUe_om99.js → keyboard-shortcuts-settings-r4DCS19O.js} +1 -1
  39. package/dist/gateway/static/root/assets/{local-app-workbench-page-CbQnffS9.js → local-app-workbench-page-qwLuir8A.js} +1 -1
  40. package/dist/gateway/static/root/assets/{local-apps-page-BZaLzfms.js → local-apps-page-DkfCRLUh.js} +1 -1
  41. package/dist/gateway/static/root/assets/{logs-page-WWCHqW_x.js → logs-page-DrNaaPWc.js} +1 -1
  42. package/dist/gateway/static/root/assets/{management-settings-Duf8w-Bl.js → management-settings-Cfx4ATTa.js} +1 -1
  43. package/dist/gateway/static/root/assets/{media-plugins-2-QfzHmg.js → media-plugins-DOLjWd3y.js} +1 -1
  44. package/dist/gateway/static/root/assets/{mobile-pairing-wizard-DRaVIAt1.js → mobile-pairing-wizard-BGW9joAb.js} +1 -1
  45. package/dist/gateway/static/root/assets/{note-detail-panel-BT-fWGxX.js → note-detail-panel-Dbj5OvXE.js} +3 -3
  46. package/dist/gateway/static/root/assets/{notes-page-C4705PzN.js → notes-page-5hRB3WXc.js} +1 -1
  47. package/dist/gateway/static/root/assets/{page-tabs-DaZ7QpNO.js → page-tabs-_SGXMT2O.js} +1 -1
  48. package/dist/gateway/static/root/assets/{preview-open-alternatives-CWEuqCmv.js → preview-open-alternatives-lVetfCWk.js} +1 -1
  49. package/dist/gateway/static/root/assets/{project-detail-page-BZegJ6an.js → project-detail-page-CblWLA8k.js} +1 -1
  50. package/dist/gateway/static/root/assets/{projects-page-B7hUHeLI.js → projects-page-CGk-kzqs.js} +1 -1
  51. package/dist/gateway/static/root/assets/{remote-access-hub-BE9hZpdh.js → remote-access-hub-Du8PweyU.js} +1 -1
  52. package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-CslkSM-m.js → runtime-tools-settings-panel-BDqVrUEj.js} +1 -1
  53. package/dist/gateway/static/root/assets/{schema-form-B2gvVrBq.js → schema-form-8RQgFJJO.js} +1 -1
  54. package/dist/gateway/static/root/assets/{sessions-page-DmAAPMo1.js → sessions-page-BFm94dJC.js} +1 -1
  55. package/dist/gateway/static/root/assets/settings-advanced-gate-C0H-cToA.js +1 -0
  56. package/dist/gateway/static/root/assets/{settings-form-section-CmlnuSO3.js → settings-form-section-j4UjGM-f.js} +1 -1
  57. package/dist/gateway/static/root/assets/{settings-page-DWWgyelT.js → settings-page-lMi50B_s.js} +1 -1
  58. package/dist/gateway/static/root/assets/{setup-status-panel-CJrN3m1o.js → setup-status-panel-Dx4Fy3rU.js} +1 -1
  59. package/dist/gateway/static/root/assets/{share-preview-page-C12oyIKk.js → share-preview-page-aSyKRH5y.js} +1 -1
  60. package/dist/gateway/static/root/assets/{shares-settings-D4BtSiLq.js → shares-settings-CqF9s0pl.js} +1 -1
  61. package/dist/gateway/static/root/assets/{skill-reload-api-CzKGn056.js → skill-reload-api-BBL_ZUSC.js} +1 -1
  62. package/dist/gateway/static/root/assets/{skills-page-yhW7LLqk.js → skills-page-C2_CAvxW.js} +1 -1
  63. package/dist/gateway/static/root/assets/{skills-page.utils-FaTlq8t-.js → skills-page.utils-B00e4Q30.js} +1 -1
  64. package/dist/gateway/static/root/assets/{system-settings-panel-CMrkoJLN.js → system-settings-panel-CulAkrsV.js} +1 -1
  65. package/dist/gateway/static/root/assets/{task-detail-page-BUaO62cy.js → task-detail-page-D1FmRFIn.js} +1 -1
  66. package/dist/gateway/static/root/assets/{tunnel-api-C2tAZaJz.js → tunnel-api-C01xgCWR.js} +1 -1
  67. package/dist/gateway/static/root/assets/{use-autosave-BsDRt4QI.js → use-autosave-DfSJ3c2p.js} +1 -1
  68. package/dist/gateway/static/root/assets/{user-model-page-Dy8h1SSJ.js → user-model-page-BGC_5baJ.js} +1 -1
  69. package/dist/gateway/static/root/assets/{voice-api-key-field-CS5heYMP.js → voice-api-key-field-9v-miN8o.js} +1 -1
  70. package/dist/gateway/static/root/assets/{work-discovery-overlay-BeSz5Th5.js → work-discovery-overlay-CREYgh-1.js} +1 -1
  71. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-BebW0CDK.js → workflow-run-setup-panel-BfCWdw8F.js} +1 -1
  72. package/dist/gateway/static/root/assets/{workflows-page-CU8jFgPF.js → workflows-page-CvmKQkD0.js} +1 -1
  73. package/dist/gateway/static/root/index.html +1 -1
  74. package/dist/package.js +1 -1
  75. package/dist/src/agent/agent-manager.js +4 -4
  76. package/dist/src/agent/background-review/run-background-review.js +1 -1
  77. package/dist/src/agent/embedded/model-runtime.js +1 -1
  78. package/dist/src/agent/embedded/run-for-session.js +1 -1
  79. package/dist/src/agent/image/tool-model-config.js +1 -1
  80. package/dist/src/agent/mcp/oauth/mcp-oauth-store.js +1 -1
  81. package/dist/src/agent/service.js +2 -2
  82. package/dist/src/agent/session/session-inspector.js +1 -1
  83. package/dist/src/agent/skills/hub-lock.js +1 -1
  84. package/dist/src/agent/tasks/task-judge-service.js +3 -3
  85. package/dist/src/ai-assist/text-assist.js +1 -1
  86. package/dist/src/auth/credentials.js +2 -2
  87. package/dist/src/auth/oauth/xopc-cloud.js +1 -1
  88. package/dist/src/auth/profiles/store.js +1 -1
  89. package/dist/src/auth/sync-provider-auth.js +2 -2
  90. package/dist/src/browser/providers/browser-ext-install.js +1 -1
  91. package/dist/src/browser/runtime/browser-runtime.js +3 -2
  92. package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
  93. package/dist/src/cli/commands/models.js +1 -1
  94. package/dist/src/config/index.js +4 -4
  95. package/dist/src/config/loader.js +2 -2
  96. package/dist/src/config/models-json.js +1 -1
  97. package/dist/src/extensions/lockfile.js +1 -1
  98. package/dist/src/gateway/agents-admin.js +1 -1
  99. package/dist/src/gateway/file-path-classifier.js +1 -1
  100. package/dist/src/gateway/heartbeat/service.js +1 -1
  101. package/dist/src/gateway/hono/lib/config-payload.js +1 -1
  102. package/dist/src/gateway/hono/routes/models.js +1 -1
  103. package/dist/src/gateway/service/config-coordinator.js +1 -1
  104. package/dist/src/gateway/service.js +4 -4
  105. package/dist/src/heartbeat/index.js +1 -1
  106. package/dist/src/providers/auth-runtime/resolve-auth.js +1 -1
  107. package/dist/src/providers/index.js +2 -2
  108. package/dist/src/providers/model-registry.js +1 -1
  109. package/dist/src/providers/register-runtime-providers.js +1 -1
  110. package/dist/src/tui/tui-startup-resources.js +1 -1
  111. package/dist/src/tui/tui.js +1 -1
  112. package/dist/src/work-discovery/service.js +1 -1
  113. package/dist/src/workflows/service/workflow-run-service.js +1 -1
  114. package/package.json +4 -4
  115. package/dist/browser-ext/dist/assets/sidepanel-CEPaVLjr.css +0 -155
  116. package/dist/gateway/static/root/assets/settings-advanced-gate-CvBocGDA.js +0 -1
@@ -5757,15 +5757,57 @@ function truncateUtf8(value, maxBytes) {
5757
5757
  return { value: value.slice(0, low), truncated: true };
5758
5758
  }
5759
5759
  function sanitizedUrl(raw) {
5760
- const url = new URL(raw);
5760
+ let url;
5761
+ try {
5762
+ url = new URL(raw);
5763
+ } catch {
5764
+ throw new Error("This tab does not have a valid web address");
5765
+ }
5761
5766
  if (url.protocol !== "http:" && url.protocol !== "https:") {
5762
- throw new Error("This page cannot be attached");
5767
+ throw new Error("Chrome does not allow xopc to read this page. Open a regular http(s) page and try again.");
5768
+ }
5769
+ if (url.hostname === "chromewebstore.google.com" || url.hostname === "chrome.google.com" && url.pathname.startsWith("/webstore")) {
5770
+ throw new Error("Chrome does not allow extensions to read Chrome Web Store pages.");
5763
5771
  }
5764
5772
  url.username = "";
5765
5773
  url.password = "";
5766
5774
  url.hash = "";
5767
5775
  return url.toString();
5768
5776
  }
5777
+ function siteAccessError(cause, url) {
5778
+ const message = cause instanceof Error ? cause.message : String(cause);
5779
+ const hostname = new URL(url).hostname;
5780
+ if (/cannot access|cannot be scripted|missing host permission|extensions gallery|chrome web store/i.test(message)) {
5781
+ return new Error(`Chrome blocked access to ${hostname}. Check xopc's site access for this page and try again.`);
5782
+ }
5783
+ return cause instanceof Error ? cause : new Error(message);
5784
+ }
5785
+ async function runWithTabSiteAccess(tabId, operation) {
5786
+ const tab = await chrome.tabs.get(tabId);
5787
+ if (tab.id === void 0 || tab.windowId === void 0 || !tab.url) {
5788
+ throw new Error("The selected tab is no longer available");
5789
+ }
5790
+ const url = sanitizedUrl(tab.url);
5791
+ const originPattern = `${new URL(url).origin}/*`;
5792
+ const alreadyGranted = await chrome.permissions.contains({ origins: [originPattern] });
5793
+ let newlyGranted = false;
5794
+ if (!alreadyGranted) {
5795
+ let granted = false;
5796
+ try {
5797
+ granted = await chrome.permissions.request({ origins: [originPattern] });
5798
+ } catch (cause) {
5799
+ throw siteAccessError(cause, url);
5800
+ }
5801
+ if (!granted) throw new Error(`Allow xopc to access ${new URL(url).hostname} to continue.`);
5802
+ newlyGranted = true;
5803
+ }
5804
+ try {
5805
+ return await operation({ ...tab, id: tab.id, windowId: tab.windowId, url });
5806
+ } catch (cause) {
5807
+ if (newlyGranted) await chrome.permissions.remove({ origins: [originPattern] }).catch(() => false);
5808
+ throw siteAccessError(cause, url);
5809
+ }
5810
+ }
5769
5811
  async function sha256(value) {
5770
5812
  const bytes = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(value));
5771
5813
  return [...new Uint8Array(bytes)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
@@ -5815,6 +5857,9 @@ async function captureTabPage(tabId, mode) {
5815
5857
  const raw = result[0]?.result;
5816
5858
  if (!raw) throw new Error("Could not read this page");
5817
5859
  const url = sanitizedUrl(raw.url);
5860
+ if (new URL(url).origin !== new URL(sanitizedUrl(tab.url)).origin) {
5861
+ throw new Error("The page changed while xopc was reading it. Try again.");
5862
+ }
5818
5863
  const selected = raw.selection ? truncateUtf8(raw.selection, MAX_BROWSER_SELECTION_BYTES) : void 0;
5819
5864
  const page = raw.text ? truncateUtf8(raw.text, MAX_BROWSER_PAGE_TEXT_BYTES) : void 0;
5820
5865
  const canonical = {
@@ -5834,16 +5879,8 @@ ${raw.timeOrigin}`),
5834
5879
  truncated: selected?.truncated === true || page?.truncated === true
5835
5880
  };
5836
5881
  }
5837
- async function captureTabWithPermission(tabId, url, mode) {
5838
- const originPattern = `${new URL(sanitizedUrl(url)).origin}/*`;
5839
- const alreadyGranted = await chrome.permissions.contains({ origins: [originPattern] });
5840
- const granted = alreadyGranted || await chrome.permissions.request({ origins: [originPattern] });
5841
- if (!granted) throw new Error("Site access is required to attach this tab");
5842
- try {
5843
- return await captureTabPage(tabId, mode);
5844
- } finally {
5845
- if (!alreadyGranted) await chrome.permissions.remove({ origins: [originPattern] });
5846
- }
5882
+ async function captureTabWithPermission(tabId, mode) {
5883
+ return runWithTabSiteAccess(tabId, () => captureTabPage(tabId, mode));
5847
5884
  }
5848
5885
  async function activeTabId() {
5849
5886
  return (await chrome.tabs.query({ active: true, currentWindow: true }))[0]?.id;
@@ -5851,21 +5888,91 @@ async function activeTabId() {
5851
5888
  async function currentTabDescriptor() {
5852
5889
  const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
5853
5890
  if (tab.id === void 0 || tab.windowId === void 0 || !tab.url) throw new Error("No active web page");
5854
- sanitizedUrl(tab.url);
5855
- const result = await chrome.scripting.executeScript({
5856
- target: { tabId: tab.id },
5857
- func: () => ({ url: location.href, timeOrigin: performance.timeOrigin })
5858
- });
5859
- const marker = result[0]?.result;
5860
- if (!marker) throw new Error("Could not identify this page");
5861
- const currentUrl = sanitizedUrl(marker.url);
5862
- return {
5863
- tabId: String(tab.id),
5864
- windowId: String(tab.windowId),
5865
- documentId: await sha256(`${currentUrl}
5891
+ return runWithTabSiteAccess(tab.id, async (accessibleTab) => {
5892
+ const result = await chrome.scripting.executeScript({
5893
+ target: { tabId: accessibleTab.id },
5894
+ func: () => ({ url: location.href, timeOrigin: performance.timeOrigin })
5895
+ });
5896
+ const marker = result[0]?.result;
5897
+ if (!marker) throw new Error("Could not identify this page");
5898
+ const currentUrl = sanitizedUrl(marker.url);
5899
+ if (new URL(currentUrl).origin !== new URL(accessibleTab.url).origin) {
5900
+ throw new Error("The page changed while xopc was connecting to it. Try again.");
5901
+ }
5902
+ return {
5903
+ tabId: String(accessibleTab.id),
5904
+ windowId: String(accessibleTab.windowId),
5905
+ documentId: await sha256(`${currentUrl}
5866
5906
  ${marker.timeOrigin}`),
5867
- urlOrigin: new URL(currentUrl).origin
5868
- };
5907
+ urlOrigin: new URL(currentUrl).origin
5908
+ };
5909
+ });
5910
+ }
5911
+
5912
+ const DATABASE_NAME = "xopc-browser-chat-state";
5913
+ const DATABASE_VERSION = 1;
5914
+ const OUTBOX_STORE = "outbox";
5915
+ function openDatabase() {
5916
+ return new Promise((resolve, reject) => {
5917
+ const request = indexedDB.open(DATABASE_NAME, DATABASE_VERSION);
5918
+ request.onupgradeneeded = () => {
5919
+ if (!request.result.objectStoreNames.contains(OUTBOX_STORE)) {
5920
+ request.result.createObjectStore(OUTBOX_STORE);
5921
+ }
5922
+ };
5923
+ request.onsuccess = () => resolve(request.result);
5924
+ request.onerror = () => reject(request.error ?? new Error("Could not open the browser chat outbox"));
5925
+ });
5926
+ }
5927
+ function transactionResult(database, mode, createRequest) {
5928
+ return new Promise((resolve, reject) => {
5929
+ const transaction = database.transaction(OUTBOX_STORE, mode);
5930
+ const request = createRequest(transaction.objectStore(OUTBOX_STORE));
5931
+ let result;
5932
+ request.onsuccess = () => {
5933
+ result = request.result;
5934
+ };
5935
+ request.onerror = () => reject(request.error ?? new Error("Browser chat outbox request failed"));
5936
+ transaction.oncomplete = () => resolve(result);
5937
+ transaction.onerror = () => reject(transaction.error ?? new Error("Browser chat outbox transaction failed"));
5938
+ transaction.onabort = () => reject(transaction.error ?? new Error("Browser chat outbox transaction was aborted"));
5939
+ });
5940
+ }
5941
+ async function readBrowserOutbox(sessionKey) {
5942
+ const database = await openDatabase();
5943
+ try {
5944
+ return await transactionResult(
5945
+ database,
5946
+ "readonly",
5947
+ (store) => store.get(sessionKey)
5948
+ );
5949
+ } finally {
5950
+ database.close();
5951
+ }
5952
+ }
5953
+ async function writeBrowserOutbox(sessionKey, value) {
5954
+ const database = await openDatabase();
5955
+ try {
5956
+ await transactionResult(database, "readwrite", (store) => store.put(value, sessionKey));
5957
+ } finally {
5958
+ database.close();
5959
+ }
5960
+ }
5961
+ async function deleteBrowserOutbox(sessionKey) {
5962
+ const database = await openDatabase();
5963
+ try {
5964
+ await transactionResult(database, "readwrite", (store) => store.delete(sessionKey));
5965
+ } finally {
5966
+ database.close();
5967
+ }
5968
+ }
5969
+ async function clearBrowserOutboxes() {
5970
+ const database = await openDatabase();
5971
+ try {
5972
+ await transactionResult(database, "readwrite", (store) => store.clear());
5973
+ } finally {
5974
+ database.close();
5975
+ }
5869
5976
  }
5870
5977
 
5871
5978
  const PROFILE_KEY = "xopc.browser.profile";
@@ -6234,11 +6341,15 @@ async function revokeAndForgetProfile() {
6234
6341
  } finally {
6235
6342
  await forgetProfile();
6236
6343
  try {
6237
- await forgetIdentity();
6344
+ await clearBrowserOutboxes();
6238
6345
  } finally {
6239
- await setAutoConnectEnabled(false);
6346
+ try {
6347
+ await forgetIdentity();
6348
+ } finally {
6349
+ await setAutoConnectEnabled(false);
6350
+ }
6240
6351
  }
6241
6352
  }
6242
6353
  }
6243
6354
 
6244
- export { ENDPOINT_PROTOCOL_VERSION as E, PENDING_CONTEXT_KEY as P, RealtimeClient as R, TAB_BINDING_PREFIX as T, activeTabId as a, captureTabPage as b, canonicalJson as c, captureTabWithPermission as d, createBrowserEndpointHello as e, currentTabDescriptor as f, discoverLocalGateway as g, endpointToolContentSchema as h, gatewayFetch as i, getAccessProfile as j, registerBrowserEndpoint as k, revokeAndForgetProfile as l, pairGateway as p, readProfile as r, setAutoConnectEnabled as s };
6355
+ export { ENDPOINT_PROTOCOL_VERSION as E, PENDING_CONTEXT_KEY as P, RealtimeClient as R, TAB_BINDING_PREFIX as T, activeTabId as a, captureTabWithPermission as b, canonicalJson as c, createBrowserEndpointHello as d, currentTabDescriptor as e, deleteBrowserOutbox as f, discoverLocalGateway as g, endpointToolContentSchema as h, gatewayFetch as i, getAccessProfile as j, readProfile as k, registerBrowserEndpoint as l, revokeAndForgetProfile as m, runWithTabSiteAccess as n, pairGateway as p, readBrowserOutbox as r, setAutoConnectEnabled as s, writeBrowserOutbox as w };
@@ -0,0 +1,299 @@
1
+ :root {
2
+ color-scheme: light dark;
3
+ font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", "SF Pro Display", system-ui, "Segoe UI", Roboto, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Noto Sans CJK SC", "Microsoft YaHei", sans-serif;
4
+
5
+ /* Keep the extension aligned with the Gateway's default Calm Intelligence theme. */
6
+ --surface-base: #f7f8fa;
7
+ --surface-panel: #ffffff;
8
+ --surface-hover: #e8ecf1;
9
+ --surface-active: #dfe5ec;
10
+ --fg: #111111;
11
+ --fg-muted: #666666;
12
+ --fg-subtle: #999999;
13
+ --fg-disabled: #b8b8b8;
14
+ --edge-subtle: #f2f2f2;
15
+ --edge: #ececec;
16
+ --edge-strong: #d8dce8;
17
+ --accent: #3a6bff;
18
+ --accent-hover: #315ce6;
19
+ --accent-soft: #eef3ff;
20
+ --accent-fg: #2f5ef6;
21
+ --success: #2ccb7f;
22
+ --success-soft: #e7fbf1;
23
+ --danger: #ff5d5d;
24
+ --danger-soft: #fff0f0;
25
+ --warning: #ffb84d;
26
+ --warning-soft: #fff7e8;
27
+ --shadow-surface: 0 1px 2px rgb(17 17 17 / 4%), 0 6px 18px rgb(17 17 17 / 4%);
28
+ --shadow-popover: 0 10px 32px rgb(17 17 17 / 10%), 0 2px 10px rgb(17 17 17 / 6%);
29
+
30
+ background: var(--surface-base);
31
+ color: var(--fg);
32
+ }
33
+
34
+ :root[data-theme='dark'] {
35
+ --surface-base: #14171c;
36
+ --surface-panel: #1b1f26;
37
+ --surface-hover: #242933;
38
+ --surface-active: #2e3440;
39
+ --fg: #f4f6f8;
40
+ --fg-muted: #b8bec8;
41
+ --fg-subtle: #87909d;
42
+ --fg-disabled: #626b78;
43
+ --edge-subtle: #252932;
44
+ --edge: #323844;
45
+ --edge-strong: #465061;
46
+ --accent: #3a6bff;
47
+ --accent-hover: #6f91ff;
48
+ --accent-soft: rgb(58 107 255 / 0.2);
49
+ --accent-fg: #adc0ff;
50
+ --success: #2ccb7f;
51
+ --success-soft: rgb(44 203 127 / 0.16);
52
+ --danger: #ff5d5d;
53
+ --danger-soft: rgb(255 93 93 / 0.16);
54
+ --warning: #ffb84d;
55
+ --warning-soft: rgb(255 184 77 / 0.16);
56
+ --shadow-surface: 0 0 0 1px rgb(255 255 255 / 4.5%);
57
+ --shadow-popover: 0 18px 54px rgb(0 0 0 / 38%), 0 0 0 1px rgb(255 255 255 / 5%);
58
+ }
59
+
60
+ * { box-sizing: border-box; }
61
+ html, body, #root { height: 100%; margin: 0; }
62
+ html { background: var(--surface-base); color: var(--fg); -webkit-font-smoothing: antialiased; }
63
+ body { overflow: hidden; font-size: 14px; }
64
+ button, input, textarea, select { font: inherit; }
65
+ button { cursor: pointer; color: inherit; }
66
+ button:disabled { cursor: default; }
67
+ button:focus-visible, input:focus-visible, textarea:focus-visible, select:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
68
+ input::placeholder, textarea::placeholder { color: var(--fg-disabled); }
69
+ svg { display: block; }
70
+
71
+ .shell { height: 100%; min-width: 300px; display: flex; flex-direction: column; background: var(--surface-base); }
72
+ .header { height: 48px; flex: 0 0 48px; padding: 0 14px; display: flex; align-items: center; gap: 10px; border-bottom: 1px solid var(--edge); background: color-mix(in srgb, var(--surface-panel) 92%, transparent); }
73
+ .brand { display: flex; align-items: center; gap: 8px; flex: 1; font-size: 15px; font-weight: 700; letter-spacing: -.01em; }
74
+ .brand-mark { width: 25px; height: 25px; display: grid; place-items: center; border: 1px solid var(--edge); border-radius: 8px; background: var(--surface-panel); color: var(--accent); box-shadow: 0 1px 2px rgb(17 17 17 / 5%); }
75
+ .brand-mark svg { width: 15px; height: 15px; stroke-width: 1.7; }
76
+ .status { margin-right: 76px; display: inline-flex; align-items: center; gap: 6px; font-size: 11px; color: var(--fg-muted); }
77
+ .status-dot, .mini-status { width: 7px; height: 7px; flex: 0 0 auto; border-radius: 999px; background: var(--fg-disabled); }
78
+ .status-dot.online, .mini-status.online { background: var(--success); box-shadow: 0 0 0 3px color-mix(in srgb, var(--success) 12%, transparent); }
79
+ .status-dot.error { background: var(--danger); }
80
+ .disconnect-link { position: absolute; z-index: 3; top: 13px; right: 13px; border: 0; border-radius: 6px; padding: 3px 7px; background: transparent; color: var(--fg-muted); font-size: 11px; }
81
+ .disconnect-link:hover { background: var(--surface-hover); color: var(--fg); }
82
+
83
+ .center { flex: 1; display: grid; place-items: center; padding: 24px; overflow: auto; }
84
+ .card { width: min(100%, 420px); border: 1px solid var(--edge); border-radius: 16px; padding: 22px; background: var(--surface-panel); box-shadow: var(--shadow-surface); }
85
+ .card h1 { margin: 0 0 8px; font-size: 20px; letter-spacing: -.02em; }
86
+ .muted { color: var(--fg-muted); line-height: 1.55; font-size: 13px; }
87
+ .field { display: grid; gap: 6px; margin-top: 14px; font-size: 13px; }
88
+ .field input, .field textarea { width: 100%; border: 1px solid var(--edge-strong); border-radius: 9px; padding: 10px 12px; background: var(--surface-panel); color: var(--fg); }
89
+ .primary { border: 0; border-radius: 9px; background: var(--accent); color: #fff; padding: 10px 14px; font-weight: 600; transition: background-color 150ms ease; }
90
+ .primary:hover:not(:disabled) { background: var(--accent-hover); }
91
+ .primary:disabled { background: var(--surface-active); color: var(--fg-disabled); }
92
+ .secondary { border: 1px solid var(--edge-strong); border-radius: 9px; background: var(--surface-panel); padding: 8px 12px; }
93
+ .secondary:hover { background: var(--surface-hover); }
94
+ .actions { display: flex; gap: 8px; margin-top: 16px; }
95
+ .local-connect { width: 100%; margin-top: 12px; }
96
+ .pairing-divider { display: flex; align-items: center; gap: 8px; margin-top: 16px; color: var(--fg-subtle); font-size: 11px; }
97
+ .pairing-divider::before, .pairing-divider::after { content: ""; height: 1px; flex: 1; background: var(--edge); }
98
+ .error-text { color: var(--danger); font-size: 13px; margin-top: 10px; }
99
+ .approval-code { font: 700 28px ui-monospace, "SF Mono", monospace; letter-spacing: 5px; margin: 18px 0; color: var(--accent-fg); }
100
+
101
+ .chat { min-height: 0; flex: 1; display: flex; flex-direction: column; position: relative; background: var(--surface-base); }
102
+ .chat-toolbar { min-height: 54px; flex: 0 0 54px; border-bottom: 1px solid var(--edge); display: flex; align-items: center; padding: 6px 12px; gap: 8px; background: var(--surface-panel); }
103
+ .session-trigger { min-width: 0; flex: 1; display: flex; align-items: center; gap: 7px; border: 0; border-radius: 9px; padding: 5px 7px; background: transparent; text-align: left; }
104
+ .session-trigger:hover { background: var(--surface-hover); }
105
+ .session-trigger-copy { min-width: 0; flex: 1; display: grid; gap: 1px; }
106
+ .session-title { overflow: hidden; color: var(--fg); font-size: 13px; font-weight: 650; white-space: nowrap; text-overflow: ellipsis; }
107
+ .session-status { display: flex; align-items: center; gap: 5px; color: var(--fg-subtle); font-size: 10px; }
108
+ .icon-sm { width: 15px; height: 15px; color: var(--fg-muted); }
109
+ .icon-button, .composer-icon-button { width: 34px; height: 34px; flex: 0 0 auto; display: grid; place-items: center; border: 1px solid var(--edge); border-radius: 9px; background: var(--surface-panel); transition: background-color 120ms ease, border-color 120ms ease; }
110
+ .icon-button svg, .composer-icon-button svg { width: 17px; height: 17px; }
111
+ .icon-button:hover, .composer-icon-button:hover, .composer-icon-button.active { border-color: var(--edge-strong); background: var(--surface-hover); }
112
+
113
+ .session-menu { position: absolute; z-index: 10; top: 8px; left: 10px; right: 10px; max-height: min(68vh, 520px); overflow: hidden; border: 1px solid var(--edge-strong); border-radius: 14px; background: var(--surface-panel); padding: 8px; box-shadow: var(--shadow-popover); }
114
+ .session-menu-header { height: 34px; display: flex; align-items: center; justify-content: space-between; padding: 0 5px 0 8px; font-size: 13px; }
115
+ .session-menu-header button { width: 27px; height: 27px; display: grid; place-items: center; border: 0; border-radius: 7px; background: transparent; color: var(--fg-muted); }
116
+ .session-menu-header button:hover { background: var(--surface-hover); }
117
+ .session-menu-header svg { width: 15px; height: 15px; }
118
+ .session-search { height: 36px; display: flex; align-items: center; gap: 7px; margin: 3px 2px 6px; border: 1px solid var(--edge); border-radius: 9px; padding: 0 10px; background: var(--surface-base); color: var(--fg-subtle); }
119
+ .session-search svg { width: 15px; height: 15px; }
120
+ .session-search input { min-width: 0; flex: 1; border: 0; outline: none; background: transparent; color: var(--fg); font-size: 12px; }
121
+ .session-list { overflow-y: auto; max-height: calc(min(68vh, 520px) - 95px); }
122
+ .session-list button { width: 100%; min-height: 48px; display: flex; align-items: center; gap: 8px; border: 0; border-radius: 9px; padding: 7px 9px; background: transparent; text-align: left; }
123
+ .session-list button:hover, .session-list button.active { background: var(--surface-hover); }
124
+ .session-list button:disabled { opacity: .55; }
125
+ .session-list button > svg { width: 15px; height: 15px; flex: 0 0 auto; color: var(--accent); }
126
+ .session-list-copy { min-width: 0; flex: 1; display: grid; gap: 3px; }
127
+ .session-list-copy span { overflow: hidden; font-size: 12px; font-weight: 550; white-space: nowrap; text-overflow: ellipsis; }
128
+ .session-list-copy small { color: var(--fg-subtle); font-size: 10px; }
129
+ .session-list-empty { padding: 24px 10px; color: var(--fg-subtle); font-size: 12px; text-align: center; }
130
+
131
+ .connection-banner { min-height: 38px; flex: 0 0 auto; display: flex; align-items: center; gap: 7px; border-bottom: 1px solid color-mix(in srgb, var(--danger) 18%, var(--edge)); padding: 7px 13px; background: var(--danger-soft); color: color-mix(in srgb, var(--danger) 78%, var(--fg)); font-size: 10px; line-height: 1.35; }
132
+ .connection-banner > svg { width: 14px; height: 14px; flex: 0 0 auto; }
133
+ .connection-banner > span { min-width: 0; flex: 1; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
134
+ .connection-banner button { flex: 0 0 auto; border: 1px solid color-mix(in srgb, var(--danger) 25%, var(--edge)); border-radius: 7px; padding: 4px 8px; background: var(--surface-panel); color: inherit; font-size: 10px; font-weight: 620; }
135
+ .connection-banner button:hover { background: var(--surface-hover); }
136
+ .messages-shell { min-height: 0; flex: 1; position: relative; display: flex; }
137
+ .messages { width: 100%; min-height: 0; flex: 1; overflow-y: auto; overscroll-behavior: contain; padding: 22px max(14px, calc((100% - 720px) / 2)) 20px; scrollbar-gutter: stable; }
138
+ .scroll-bottom-button { position: absolute; z-index: 4; right: 17px; bottom: 12px; width: 34px; height: 34px; display: grid; place-items: center; border: 1px solid var(--edge-strong); border-radius: 999px; background: color-mix(in srgb, var(--surface-panel) 94%, transparent); color: var(--fg-muted); box-shadow: var(--shadow-popover); backdrop-filter: blur(8px); }
139
+ .scroll-bottom-button:hover { background: var(--surface-hover); color: var(--fg); }
140
+ .scroll-bottom-button svg { width: 16px; height: 16px; }
141
+ .message-skeleton { width: min(100%, 720px); margin: 6px auto; display: grid; gap: 10px; }
142
+ .message-skeleton span { height: 12px; border-radius: 6px; background: linear-gradient(90deg, var(--surface-hover), var(--surface-active), var(--surface-hover)); background-size: 200% 100%; animation: skeleton 1.3s ease-in-out infinite; }
143
+ .message-skeleton span:nth-child(1) { width: 38%; }
144
+ .message-skeleton span:nth-child(2) { width: 92%; }
145
+ .message-skeleton span:nth-child(3) { width: 68%; }
146
+ .empty-chat { width: min(100%, 520px); min-height: 100%; margin: auto; display: flex; flex-direction: column; justify-content: center; align-items: center; padding: 24px 4px 48px; text-align: center; }
147
+ .empty-mark { width: 42px; height: 42px; display: grid; place-items: center; margin-bottom: 14px; border: 1px solid color-mix(in srgb, var(--accent) 20%, var(--edge)); border-radius: 13px; background: var(--accent-soft); color: var(--accent-fg); }
148
+ .empty-mark svg { width: 21px; height: 21px; }
149
+ .empty-chat h1 { margin: 0; font-size: 19px; font-weight: 680; letter-spacing: -.025em; }
150
+ .empty-chat > p { max-width: 390px; margin: 8px 0 20px; color: var(--fg-muted); font-size: 12px; line-height: 1.55; }
151
+ .quick-prompts { width: min(100%, 420px); display: grid; gap: 7px; }
152
+ .quick-prompts button { min-height: 42px; display: flex; align-items: center; gap: 10px; border: 1px solid var(--edge); border-radius: 11px; padding: 9px 12px; background: var(--surface-panel); color: var(--fg-muted); text-align: left; transition: border-color 120ms ease, background-color 120ms ease, transform 120ms ease; }
153
+ .quick-prompts button:hover { border-color: var(--edge-strong); background: var(--surface-hover); color: var(--fg); transform: translateY(-1px); }
154
+ .quick-prompts svg { width: 17px; height: 17px; color: var(--accent-fg); }
155
+ .quick-prompts span { font-size: 12px; font-weight: 550; }
156
+
157
+ .message { width: min(100%, 720px); margin: 0 auto 26px; color: var(--fg); }
158
+ .message-heading { min-height: 22px; display: flex; align-items: center; gap: 7px; margin-bottom: 5px; color: var(--fg-subtle); font-size: 10px; }
159
+ .message-author { color: var(--fg-muted); font-size: 11px; font-weight: 680; letter-spacing: .015em; }
160
+ .message-heading time { opacity: 0; transition: opacity 120ms ease; }
161
+ .message:hover .message-heading time { opacity: 1; }
162
+ .responding-label { display: inline-flex; align-items: center; gap: 4px; color: var(--accent-fg); }
163
+ .responding-label::before { content: ""; width: 5px; height: 5px; border-radius: 99px; background: var(--accent); animation: pulse 1.4s ease-in-out infinite; }
164
+ .message-body { min-width: 0; font-size: 14px; line-height: 1.65; overflow-wrap: anywhere; }
165
+ .message.user { width: min(88%, 620px); margin-right: max(0px, calc((100% - 720px) / 2)); }
166
+ .message.user .message-heading { justify-content: flex-end; padding-right: 4px; }
167
+ .message.user .message-body { border: 1px solid var(--edge); border-radius: 15px 15px 4px 15px; padding: 10px 13px; background: var(--surface-panel); box-shadow: 0 1px 2px rgb(17 17 17 / 3%); }
168
+ .message.system .message-body { border-left: 2px solid var(--edge-strong); padding-left: 11px; color: var(--fg-muted); font-size: 12px; }
169
+ .plain-message-content { white-space: pre-wrap; }
170
+ .message-sources { display: flex; flex-wrap: wrap; gap: 5px; margin-bottom: 8px; }
171
+ .source-badge { min-width: 0; max-width: 100%; display: inline-flex; align-items: center; gap: 5px; border: 1px solid color-mix(in srgb, var(--accent) 25%, var(--edge)); border-radius: 999px; padding: 4px 8px; color: var(--accent-fg); background: var(--accent-soft); font-size: 10px; }
172
+ .source-badge svg { width: 12px; height: 12px; flex: 0 0 auto; }
173
+ .source-badge span { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
174
+ .message-attachments { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 8px; }
175
+ .message-attachment { min-width: 0; max-width: 100%; display: flex; align-items: center; gap: 7px; border: 1px solid var(--edge); border-radius: 9px; padding: 6px 8px; background: var(--surface-base); color: var(--fg-muted); }
176
+ .message-attachment > svg { width: 15px; height: 15px; flex: 0 0 auto; color: var(--accent-fg); }
177
+ .message-attachment > span { min-width: 0; display: flex; align-items: baseline; gap: 6px; }
178
+ .message-attachment strong { max-width: min(280px, 58vw); overflow: hidden; font-size: 10px; font-weight: 620; white-space: nowrap; text-overflow: ellipsis; }
179
+ .message-attachment small { flex: 0 0 auto; color: var(--fg-subtle); font-size: 9px; }
180
+ .message-actions { height: 24px; display: flex; align-items: center; margin-top: 4px; opacity: 0; transition: opacity 120ms ease; }
181
+ .message:hover .message-actions, .message-actions:focus-within { opacity: 1; }
182
+ .message-actions button { display: inline-flex; align-items: center; gap: 4px; border: 0; border-radius: 6px; padding: 3px 6px; background: transparent; color: var(--fg-subtle); font-size: 10px; }
183
+ .message-actions button:hover { background: var(--surface-hover); color: var(--fg-muted); }
184
+ .message-actions svg { width: 13px; height: 13px; }
185
+
186
+ .markdown-content { min-width: 0; }
187
+ .markdown-content > div > :first-child { margin-top: 0; }
188
+ .markdown-content > div > :last-child { margin-bottom: 0; }
189
+ .markdown-content p { margin: 0 0 10px; }
190
+ .markdown-content h1, .markdown-content h2, .markdown-content h3, .markdown-content h4 { margin: 20px 0 8px; color: var(--fg); font-weight: 680; line-height: 1.3; letter-spacing: -.018em; }
191
+ .markdown-content h1 { font-size: 19px; }
192
+ .markdown-content h2 { font-size: 17px; }
193
+ .markdown-content h3 { font-size: 15px; }
194
+ .markdown-content h4 { font-size: 14px; }
195
+ .markdown-content ul, .markdown-content ol { margin: 8px 0 12px; padding-left: 22px; }
196
+ .markdown-content li { margin: 4px 0; padding-left: 2px; }
197
+ .markdown-content li::marker { color: var(--fg-subtle); }
198
+ .markdown-content strong { font-weight: 680; }
199
+ .markdown-content a { color: var(--accent-fg); text-decoration: none; }
200
+ .markdown-content a:hover { text-decoration: underline; text-underline-offset: 2px; }
201
+ .markdown-content blockquote { margin: 12px 0; border-left: 3px solid var(--edge-strong); padding: 2px 0 2px 12px; color: var(--fg-muted); }
202
+ .markdown-content code { border: 1px solid var(--edge); border-radius: 5px; padding: 1px 4px; background: var(--surface-hover); font: .88em ui-monospace, "SFMono-Regular", Consolas, monospace; }
203
+ .markdown-content pre { max-width: 100%; margin: 12px 0; overflow-x: auto; border: 1px solid var(--edge); border-radius: 10px; padding: 11px 12px; background: color-mix(in srgb, var(--surface-hover) 65%, var(--surface-panel)); font-size: 12px; line-height: 1.55; }
204
+ .markdown-content pre code { border: 0; padding: 0; background: transparent; font-size: inherit; }
205
+ .markdown-content table { width: 100%; display: block; margin: 12px 0; overflow-x: auto; border-collapse: collapse; font-size: 12px; }
206
+ .markdown-content th, .markdown-content td { border: 1px solid var(--edge); padding: 6px 8px; text-align: left; }
207
+ .markdown-content th { background: var(--surface-hover); font-weight: 650; }
208
+ .markdown-content hr { border: 0; border-top: 1px solid var(--edge); margin: 18px 0; }
209
+ .streaming-caret { display: inline-block; width: 6px; height: 14px; margin-left: 3px; vertical-align: -2px; border-radius: 2px; background: var(--accent); animation: blink 1s steps(1) infinite; }
210
+ @keyframes blink { 50% { opacity: 0; } }
211
+ @keyframes pulse { 50% { opacity: .35; transform: scale(.8); } }
212
+ @keyframes skeleton { to { background-position: -200% 0; } }
213
+
214
+ .composer { position: relative; flex: 0 0 auto; margin: 0 10px 10px; border: 1px solid var(--edge-strong); border-radius: 15px; background: var(--surface-panel); padding: 8px; box-shadow: var(--shadow-surface); transition: border-color 120ms ease, box-shadow 120ms ease; }
215
+ .composer:focus-within { border-color: color-mix(in srgb, var(--accent) 45%, var(--edge)); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 7%, transparent), var(--shadow-surface); }
216
+ .composer.dragging { border-color: var(--accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 12%, transparent), var(--shadow-surface); }
217
+ .file-drop-overlay { position: absolute; z-index: 20; inset: 0; display: flex; align-items: center; justify-content: center; gap: 7px; border-radius: 14px; background: color-mix(in srgb, var(--accent-soft) 94%, var(--surface-panel)); color: var(--accent-fg); font-size: 12px; font-weight: 650; pointer-events: none; }
218
+ .file-drop-overlay svg { width: 17px; height: 17px; }
219
+ .composer-input-row { min-height: 38px; display: flex; align-items: flex-end; gap: 7px; }
220
+ .composer textarea { min-width: 0; min-height: 34px; max-height: 144px; flex: 1; resize: none; overflow-y: auto; border: 0; padding: 7px 2px 6px; outline: none; background: transparent; color: var(--fg); font-size: 13px; line-height: 1.5; }
221
+ .composer-icon-button { width: 34px; height: 34px; border-color: transparent; color: var(--fg-muted); }
222
+ .tools-anchor { position: relative; flex: 0 0 auto; }
223
+ .tools-menu { position: absolute; z-index: 12; left: -1px; bottom: calc(100% + 9px); width: min(310px, calc(100vw - 38px)); overflow: hidden; border: 1px solid var(--edge-strong); border-radius: 13px; background: var(--surface-panel); padding: 6px; box-shadow: var(--shadow-popover); }
224
+ .tools-menu-section + .tools-menu-section { margin-top: 5px; border-top: 1px solid var(--edge); padding-top: 5px; }
225
+ .tools-menu-label { display: block; padding: 5px 8px 4px; color: var(--fg-subtle); font-size: 9px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; }
226
+ .tools-menu button { width: 100%; display: flex; align-items: center; gap: 10px; border: 0; border-radius: 8px; padding: 7px 8px; background: transparent; text-align: left; }
227
+ .tools-menu button:hover { background: var(--surface-hover); }
228
+ .tools-menu button > svg { width: 17px; height: 17px; flex: 0 0 auto; color: var(--fg-muted); }
229
+ .tools-menu button > span { min-width: 0; flex: 1; display: grid; gap: 1px; }
230
+ .tools-menu button strong { font-size: 11px; font-weight: 620; }
231
+ .tools-menu button small { overflow: hidden; color: var(--fg-subtle); font-size: 10px; white-space: nowrap; text-overflow: ellipsis; }
232
+ .tools-menu button.active-access { background: var(--success-soft); }
233
+ .tools-menu button.active-access > svg { color: var(--success); }
234
+ .tools-menu button.active-access > svg:last-child { width: 13px; height: 13px; color: var(--fg-subtle); }
235
+ .send-button { width: 34px; height: 34px; flex: 0 0 auto; display: grid; place-items: center; border: 0; border-radius: 10px; background: var(--accent); color: #fff; transition: background-color 120ms ease, transform 120ms ease; }
236
+ .send-button svg { width: 17px; height: 17px; }
237
+ .send-button:hover:not(:disabled) { background: var(--accent-hover); transform: translateY(-1px); }
238
+ .send-button:disabled { background: var(--surface-active); color: var(--fg-disabled); }
239
+ .stop-button { background: var(--fg); color: var(--surface-panel); }
240
+ .stop-button:hover:not(:disabled) { background: var(--fg-muted); }
241
+ .composer-footer { min-height: 25px; display: flex; align-items: center; gap: 8px; padding: 4px 3px 0 5px; }
242
+ .composer-state { min-width: 0; display: flex; align-items: center; gap: 5px; color: var(--fg-subtle); font-size: 9px; }
243
+ .access-pill { display: inline-flex; align-items: center; gap: 3px; border-radius: 999px; padding: 2px 5px; background: var(--success-soft); color: color-mix(in srgb, var(--success) 72%, var(--fg)); font-weight: 600; }
244
+ .access-pill svg { width: 10px; height: 10px; }
245
+ .model-controls { min-width: 0; margin-left: auto; display: flex; align-items: center; gap: 3px; }
246
+ .model-controls select { min-width: 0; max-width: 112px; border: 0; border-radius: 5px; padding: 2px 3px; outline: none; background: transparent; color: var(--fg-subtle); font-size: 9px; text-overflow: ellipsis; }
247
+ .model-controls select:hover { background: var(--surface-hover); color: var(--fg-muted); }
248
+ .model-controls select:last-child { max-width: 64px; }
249
+
250
+ .composer-contexts { display: flex; flex-wrap: wrap; gap: 5px; margin-bottom: 6px; }
251
+ .context-chip, .attachment-chip { min-width: 0; max-width: 100%; display: flex; align-items: center; gap: 5px; border: 1px solid color-mix(in srgb, var(--accent) 24%, var(--edge)); border-radius: 8px; padding: 5px 6px; color: var(--accent-fg); background: var(--accent-soft); font-size: 10px; }
252
+ .attachment-chip { border-color: var(--edge); color: var(--fg-muted); background: var(--surface-base); }
253
+ .context-chip > svg, .attachment-chip > svg { width: 13px; height: 13px; flex: 0 0 auto; }
254
+ .context-chip > span, .attachment-chip > span { min-width: 0; max-width: 310px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
255
+ .context-chip strong, .attachment-chip strong { font-weight: 650; }
256
+ .context-chip button { border: 0; border-radius: 5px; padding: 2px 4px; background: transparent; color: inherit; font-size: 9px; }
257
+ .context-chip button:hover { background: color-mix(in srgb, var(--accent) 10%, transparent); }
258
+ .context-chip.stale { border-color: color-mix(in srgb, var(--warning) 55%, var(--edge)); background: var(--warning-soft); color: color-mix(in srgb, var(--warning) 70%, var(--fg)); }
259
+ .chip-remove { width: 18px; height: 18px; display: grid; place-items: center; border: 0; border-radius: 5px; padding: 0; background: transparent; color: inherit; }
260
+ .chip-remove:hover { background: var(--surface-active); }
261
+ .chip-remove svg { width: 11px; height: 11px; }
262
+ .file-input { display: none; }
263
+ .composer-error { display: flex; align-items: flex-start; gap: 6px; margin: 0 2px 7px; border-radius: 8px; padding: 7px 8px; background: var(--danger-soft); color: var(--danger); font-size: 10px; line-height: 1.4; }
264
+ .composer-error svg { width: 13px; height: 13px; flex: 0 0 auto; }
265
+ .composer-notice { margin: 0 2px 7px; border-radius: 8px; padding: 7px 8px; background: var(--warning-soft); color: color-mix(in srgb, var(--warning) 72%, var(--fg)); font-size: 10px; line-height: 1.4; }
266
+
267
+ .tab-mention-menu { position: absolute; z-index: 13; left: 0; right: 0; bottom: calc(100% + 8px); max-height: min(45vh, 320px); overflow-y: auto; border: 1px solid var(--edge-strong); border-radius: 12px; background: var(--surface-panel); padding: 5px; box-shadow: var(--shadow-popover); }
268
+ .tab-mention-menu button { width: 100%; display: grid; gap: 2px; border: 0; border-radius: 8px; padding: 8px 10px; background: transparent; color: inherit; text-align: left; }
269
+ .tab-mention-menu button:hover, .tab-mention-menu button.selected { background: var(--accent-soft); }
270
+ .tab-mention-menu span, .tab-mention-menu small { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
271
+ .tab-mention-menu span { font-size: 12px; font-weight: 600; }
272
+ .tab-mention-menu small, .tab-mention-empty { color: var(--fg-muted); font-size: 10px; }
273
+ .tab-mention-empty { padding: 10px; }
274
+
275
+ .request-card { max-height: min(42vh, 310px); margin: 0 0 7px; overflow-y: auto; border: 1px solid color-mix(in srgb, var(--accent) 28%, var(--edge)); border-radius: 11px; padding: 10px; background: var(--accent-soft); }
276
+ .request-card-title { display: flex; align-items: center; gap: 6px; color: var(--accent-fg); }
277
+ .request-card-title svg { width: 14px; height: 14px; }
278
+ .request-card-title strong { font-size: 11px; }
279
+ .request-card p { margin: 6px 0 9px; font-size: 12px; line-height: 1.45; }
280
+ .request-actions, .choice-list { display: flex; flex-wrap: wrap; gap: 5px; }
281
+ .request-actions button, .choice-list button, .clarification-actions button, .clarification-answer button { border: 1px solid color-mix(in srgb, var(--accent) 28%, var(--edge)); border-radius: 7px; padding: 5px 8px; background: var(--surface-panel); color: var(--fg-muted); font-size: 10px; }
282
+ .request-actions button:hover, .choice-list button:hover, .clarification-actions button:hover, .clarification-answer button:hover { background: var(--surface-hover); color: var(--fg); }
283
+ .request-actions .request-primary { border-color: var(--accent); background: var(--accent); color: #fff; }
284
+ .clarification-answer { display: flex; gap: 6px; margin-top: 7px; }
285
+ .clarification-answer input { min-width: 0; flex: 1; border: 1px solid color-mix(in srgb, var(--accent) 28%, var(--edge)); border-radius: 7px; padding: 6px 8px; background: var(--surface-panel); color: var(--fg); font-size: 11px; }
286
+ .clarification-actions { display: flex; gap: 4px; margin-top: 4px; }
287
+ .clarification-actions button { border-color: transparent; background: transparent; }
288
+
289
+ @media (max-width: 380px) {
290
+ .status { margin-right: 68px; }
291
+ .messages { padding-inline: 12px; }
292
+ .message.user { width: 92%; }
293
+ .model-controls select { max-width: 86px; }
294
+ .quick-prompts { gap: 6px; }
295
+ }
296
+
297
+ @media (prefers-reduced-motion: reduce) {
298
+ *, *::before, *::after { scroll-behavior: auto !important; animation-duration: .01ms !important; animation-iteration-count: 1 !important; transition-duration: .01ms !important; }
299
+ }
@@ -1,4 +1,4 @@
1
- import { h as endpointToolContentSchema, E as ENDPOINT_PROTOCOL_VERSION, c as canonicalJson, T as TAB_BINDING_PREFIX, b as captureTabPage, P as PENDING_CONTEXT_KEY, r as readProfile, k as registerBrowserEndpoint, j as getAccessProfile, R as RealtimeClient, e as createBrowserEndpointHello, i as gatewayFetch } from './assets/auth-D_IL6naL.js';
1
+ import { h as endpointToolContentSchema, E as ENDPOINT_PROTOCOL_VERSION, c as canonicalJson, T as TAB_BINDING_PREFIX, b as captureTabWithPermission, P as PENDING_CONTEXT_KEY, k as readProfile, l as registerBrowserEndpoint, j as getAccessProfile, R as RealtimeClient, d as createBrowserEndpointHello, i as gatewayFetch } from './assets/auth-cwEj8rFb.js';
2
2
 
3
3
  const BROWSER_EXTENSION_PROTOCOL_VERSION = 4;
4
4
  const BROWSER_CONTROL_ENDPOINT_TOOL_NAME = "browser.control";
@@ -1270,7 +1270,7 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
1270
1270
  chrome.contextMenus.onClicked.addListener((info, tab) => {
1271
1271
  if (info.menuItemId !== "xopc-ask-selection" || !tab?.id) return;
1272
1272
  const tabId = tab.id;
1273
- void captureTabPage(tabId, "selection").then(async (context) => {
1273
+ void captureTabWithPermission(tabId, "selection").then(async (context) => {
1274
1274
  await chrome.storage.session.set({
1275
1275
  [PENDING_CONTEXT_KEY]: { context, tabId, source: "current_selection" }
1276
1276
  });
@@ -5,8 +5,8 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>xopc</title>
7
7
  <script type="module" crossorigin src="./sidepanel.js"></script>
8
- <link rel="modulepreload" crossorigin href="./assets/auth-D_IL6naL.js">
9
- <link rel="stylesheet" crossorigin href="./assets/sidepanel-CEPaVLjr.css">
8
+ <link rel="modulepreload" crossorigin href="./assets/auth-cwEj8rFb.js">
9
+ <link rel="stylesheet" crossorigin href="./assets/sidepanel-C86O7q5Y.css">
10
10
  </head>
11
11
  <body>
12
12
  <div id="root"></div>