@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.
- package/dist/browser-ext/_locales/en/messages.json +215 -0
- package/dist/browser-ext/_locales/zh_CN/messages.json +215 -0
- package/dist/browser-ext/dist/assets/{auth-O8RiOF3l.js → auth-ClQTK565.js} +97 -38
- package/dist/browser-ext/dist/assets/{sidepanel-C86O7q5Y.css → sidepanel-CeGqObOa.css} +41 -20
- package/dist/browser-ext/dist/background.js +36 -4
- package/dist/browser-ext/dist/sidepanel.html +2 -2
- package/dist/browser-ext/dist/sidepanel.js +416 -299
- package/dist/browser-ext/manifest.json +6 -4
- package/dist/extensions/feishu/src/outbound/media-load.js +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-BckaANxj.js → agent-avatar-dicebear-sj_1IC5H.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-defaults-settings-panel-B8eyC6K1.js → agent-defaults-settings-panel-B5MRLEy8.js} +1 -1
- package/dist/gateway/static/root/assets/{agents-CSWj_yo1.js → agents-CIzev0Qj.js} +1 -1
- package/dist/gateway/static/root/assets/{app-management-settings-panel-DY-Zbgmt.js → app-management-settings-panel-DY3Vwxjq.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-CoJR7ZRl.js → appearance-settings-BeXvF-dZ.js} +1 -1
- package/dist/gateway/static/root/assets/apps-page-Ch_9Ffgk.js +1 -0
- package/dist/gateway/static/root/assets/{archive-plugin-BwAlRT53.js → archive-plugin-BSgaIIGE.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-R835uxgL.js → attachment-load-CGNt02hP.js} +1 -1
- package/dist/gateway/static/root/assets/{automations-page-BEZy0P_u.js → automations-page-DoafJiVA.js} +1 -1
- package/dist/gateway/static/root/assets/automations-workspace-MACr99IO.js +6 -0
- package/dist/gateway/static/root/assets/{binary-plugins-CESFx3yb.js → binary-plugins-BsAL26Aq.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-DDJcf2wR.js → block-editor-BxB7m8aI.js} +3 -3
- package/dist/gateway/static/root/assets/{browser-automations-page-BH4lSfr5.js → browser-automations-page-BNsO-Ip2.js} +2 -2
- package/dist/gateway/static/root/assets/browser-settings-page-Nvdoi0B1.js +8 -0
- package/dist/gateway/static/root/assets/capabilities-settings-panel-BluLJq5I.js +8 -0
- package/dist/gateway/static/root/assets/channels-settings-DYxxhcjb.js +1 -0
- package/dist/gateway/static/root/assets/{chat-terminal-dock-D8U97O95.js → chat-terminal-dock-ZCFwco1W.js} +2 -2
- package/dist/gateway/static/root/assets/connectors-page-Bpcp8UyE.js +2 -0
- package/dist/gateway/static/root/assets/{date-picker-7sDSMswL.js → date-picker-CpxFfgpg.js} +1 -1
- package/dist/gateway/static/root/assets/{dependency-picker-DMIC86ZW.js → dependency-picker-eCIGAfHa.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-BtdiY5jK.js → desktop-pet-_MSZvIDO.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-settings-D_B8azDH.js → desktop-pet-settings-feBnJWkV.js} +1 -1
- package/dist/gateway/static/root/assets/device-pairing-wizard-D_fB0fml.js +1 -0
- package/dist/gateway/static/root/assets/{extension-debug-page-CoFKb01d.js → extension-debug-page-CotBlxJ-.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-CEkNsCAY.js → extension-page-CFBmQ7U3.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-Bi2R8P5j.js → extension-settings-page-Cd1lfh8z.js} +1 -1
- package/dist/gateway/static/root/assets/gateway-settings-BH35C8RI.js +1 -0
- package/dist/gateway/static/root/assets/{heartbeat-settings-DQtelFiU.js → heartbeat-settings-DRG0u1ON.js} +1 -1
- package/dist/gateway/static/root/assets/home-page-BlZk-aD4.js +1 -0
- package/dist/gateway/static/root/assets/{index-SxqsTD4i.js → index-CfQor-TM.js} +34 -34
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-BuYmZS1K.js → keyboard-shortcuts-settings-BLHsdFIQ.js} +1 -1
- package/dist/gateway/static/root/assets/local-app-workbench-page-DJd71FlC.js +2 -0
- package/dist/gateway/static/root/assets/{local-apps-page-CExnZyGZ.js → local-apps-page-BjAj1xhq.js} +1 -1
- package/dist/gateway/static/root/assets/{logs-page-CA5ArMoN.js → logs-page-5MWeZ6Ae.js} +2 -2
- package/dist/gateway/static/root/assets/{management-settings-1UiJPrkX.js → management-settings-CPHxDaOw.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-nNFOk9HL.js → media-plugins-BUOzcXCL.js} +1 -1
- package/dist/gateway/static/root/assets/note-detail-panel-Bch98ut3.js +5 -0
- package/dist/gateway/static/root/assets/notes-page-CWO5dQKN.js +8 -0
- package/dist/gateway/static/root/assets/{page-tabs-CRombigq.js → page-tabs-BgEYFhqS.js} +1 -1
- package/dist/gateway/static/root/assets/{preview-open-alternatives-Bcuj43lk.js → preview-open-alternatives-C-pQIx6W.js} +1 -1
- package/dist/gateway/static/root/assets/{proactive-card-Cb3Xeoyx.js → proactive-card-DfjMVJUW.js} +1 -1
- package/dist/gateway/static/root/assets/{proactive-page-TbF9KVpm.js → proactive-page-BGVcVsbd.js} +1 -1
- package/dist/gateway/static/root/assets/project-detail-page-DZFVirjV.js +1 -0
- package/dist/gateway/static/root/assets/projects-page-B2g6inq-.js +1 -0
- package/dist/gateway/static/root/assets/remote-access-hub-CbkUOkQY.js +1 -0
- package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-BudlvBu-.js → runtime-tools-settings-panel-DkAjFJ-9.js} +2 -2
- package/dist/gateway/static/root/assets/{schema-form-Ch3MEX4h.js → schema-form-BpDcuSsl.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page--7-w-0WS.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-BvZrH_sp.js +1 -0
- package/dist/gateway/static/root/assets/{settings-form-section-CIA1AA-A.js → settings-form-section-RElRijJw.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-B0Khoduh.js → settings-page-CaixunoA.js} +1 -1
- package/dist/gateway/static/root/assets/setup-status-panel-Ul06Y5YX.js +1 -0
- package/dist/gateway/static/root/assets/{share-preview-page-Cj9XWg-X.js → share-preview-page-CC-bFOTf.js} +1 -1
- package/dist/gateway/static/root/assets/shares-settings-DwV2Wh7S.js +1 -0
- package/dist/gateway/static/root/assets/{skill-reload-api-BM4Ezjbx.js → skill-reload-api-CcOtxf53.js} +1 -1
- package/dist/gateway/static/root/assets/{skills-page-Dyh1kf9t.js → skills-page-DmRvRxtY.js} +1 -1
- package/dist/gateway/static/root/assets/{skills-page.utils-DsQZkMti.js → skills-page.utils-CT0-daZD.js} +1 -1
- package/dist/gateway/static/root/assets/{system-settings-panel-BSho_Tpk.js → system-settings-panel-DRIJ5mXq.js} +1 -1
- package/dist/gateway/static/root/assets/task-detail-page-BQjLHqSk.js +1 -0
- package/dist/gateway/static/root/assets/{tunnel-api-4DUHxSQG.js → tunnel-api-IvWcgZdD.js} +1 -1
- package/dist/gateway/static/root/assets/{use-autosave-BG8Yx7hj.js → use-autosave-Cq4--C1i.js} +1 -1
- package/dist/gateway/static/root/assets/user-model-page-hwc5-nqV.js +2 -0
- package/dist/gateway/static/root/assets/{voice-api-key-field-DYXwDhHq.js → voice-api-key-field-CbJ6tKGI.js} +1 -1
- package/dist/gateway/static/root/assets/{work-discovery-overlay-CQqjzaRo.js → work-discovery-overlay-BG2pmXL3.js} +1 -1
- package/dist/gateway/static/root/assets/{workflow-run-setup-panel-C5H-Fd-U.js → workflow-run-setup-panel-vw1229Fh.js} +2 -2
- package/dist/gateway/static/root/assets/workflows-page-DZWpJHDr.js +6 -0
- package/dist/gateway/static/root/index.html +1 -1
- package/dist/package.js +1 -1
- package/dist/src/agent/child-agent-factory.d.ts +3 -0
- package/dist/src/agent/child-agent-factory.js +2 -1
- package/dist/src/agent/external-tools/endpoint-provider.js +1 -1
- package/dist/src/agent/tools/factory.d.ts +1 -0
- package/dist/src/agent/tools/factory.js +21 -4
- package/dist/src/agent/workflow/workflow-child-tools.js +2 -0
- package/dist/src/browser/providers/browser-ext-install.d.ts +1 -1
- package/dist/src/browser/providers/browser-ext-install.js +86 -14
- package/dist/src/browser/providers/realtime-extension.d.ts +4 -1
- package/dist/src/browser/providers/realtime-extension.js +26 -10
- package/dist/src/browser/readiness.d.ts +4 -1
- package/dist/src/browser/readiness.js +11 -5
- package/dist/src/cli/commands/channels.js +1 -1
- package/dist/src/cli/commands/connectors.js +1 -1
- package/dist/src/cli/commands/extension-marketplace.js +2 -2
- package/dist/src/cli/commands/models.js +1 -1
- package/dist/src/cli/commands/onboard.js +1 -1
- package/dist/src/extensions/sdk/index.js +1 -1
- package/dist/src/extensions/update.js +1 -1
- package/dist/src/gateway/gateway-workflow-host.types.d.ts +2 -0
- package/dist/src/gateway/hono/routes/auth-registry-extensions.js +1 -1
- package/dist/src/gateway/hono/routes/browser.js +24 -11
- package/dist/src/gateway/hono/routes/endpoint-tools.js +9 -0
- package/dist/src/gateway/hono/routes/models.js +6 -0
- package/dist/src/gateway/service/config-coordinator.js +1 -1
- package/dist/src/gateway/service.js +3 -3
- package/dist/src/infra/update-runner.js +1 -1
- package/dist/src/providers/model-catalog-persistence.js +4 -0
- package/dist/src/providers/model-catalog-types.d.ts +1 -0
- package/dist/src/providers/xopc-cloud-model-source.js +12 -1
- package/dist/src/storage/sqlite/endpoint-session-binding-repository.d.ts +1 -0
- package/dist/src/storage/sqlite/endpoint-session-binding-repository.js +9 -1
- package/dist/src/storage/sqlite/index.d.ts +1 -1
- package/dist/src/storage/sqlite/index.js +2 -2
- package/dist/src/tui/backends/embedded-backend.js +1 -1
- package/dist/src/workflows/service/workflow-run-service.js +4 -1
- package/package.json +4 -4
- package/dist/gateway/static/root/assets/apps-page-CSMvkuot.js +0 -1
- package/dist/gateway/static/root/assets/automations-workspace-CpaI13J7.js +0 -6
- package/dist/gateway/static/root/assets/browser-settings-page-CbTooPd2.js +0 -8
- package/dist/gateway/static/root/assets/capabilities-settings-panel-C4LZWHhv.js +0 -8
- package/dist/gateway/static/root/assets/channels-settings-BAljmSa7.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-CVRMjNNr.js +0 -2
- package/dist/gateway/static/root/assets/device-pairing-wizard-Dmh3Nh4d.js +0 -1
- package/dist/gateway/static/root/assets/gateway-settings-q9p3sduo.js +0 -1
- package/dist/gateway/static/root/assets/home-page-COpGnTFZ.js +0 -1
- package/dist/gateway/static/root/assets/local-app-workbench-page-DV_17Zxc.js +0 -2
- package/dist/gateway/static/root/assets/note-detail-panel-B5OQ0fBY.js +0 -5
- package/dist/gateway/static/root/assets/notes-page-CVPPMVDl.js +0 -8
- package/dist/gateway/static/root/assets/project-detail-page-B9OQ2l9x.js +0 -1
- package/dist/gateway/static/root/assets/projects-page-DCqSTNkY.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-d9Fg70gX.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-D8RiQ-ag.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-DVH_l6Hr.js +0 -1
- package/dist/gateway/static/root/assets/setup-status-panel-COJFl4N_.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-_OuE6A0G.js +0 -1
- package/dist/gateway/static/root/assets/task-detail-page-B5HWM12k.js +0 -1
- package/dist/gateway/static/root/assets/user-model-page-IjVyv5jj.js +0 -2
- package/dist/gateway/static/root/assets/workflows-page-D1hMyPsY.js +0 -6
|
@@ -5782,6 +5782,62 @@ array(browserPageContextInputSchema).max(MAX_BROWSER_CONTEXTS_PER_TURN).superRef
|
|
|
5782
5782
|
}
|
|
5783
5783
|
});
|
|
5784
5784
|
|
|
5785
|
+
const LOCALE_STORAGE_KEY = "xopc.sidepanel.locale";
|
|
5786
|
+
const LOCALE_PATHS = {
|
|
5787
|
+
en: "_locales/en/messages.json",
|
|
5788
|
+
"zh-CN": "_locales/zh_CN/messages.json"
|
|
5789
|
+
};
|
|
5790
|
+
let activeLocale;
|
|
5791
|
+
let activeCatalog;
|
|
5792
|
+
function isExtensionLocale(value) {
|
|
5793
|
+
return value === "en" || value === "zh-CN";
|
|
5794
|
+
}
|
|
5795
|
+
function browserLocale() {
|
|
5796
|
+
return chrome.i18n.getUILanguage().replaceAll("_", "-").toLowerCase().startsWith("zh") ? "zh-CN" : "en";
|
|
5797
|
+
}
|
|
5798
|
+
function messageWithSubstitutions(entry, substitutions) {
|
|
5799
|
+
const values = substitutions === void 0 ? [] : Array.isArray(substitutions) ? substitutions : [substitutions];
|
|
5800
|
+
const valueAt = (content) => content.replace(/\$(\d+)/g, (_match, index) => values[Number(index) - 1] ?? "");
|
|
5801
|
+
let message = entry.message;
|
|
5802
|
+
for (const [name, placeholder] of Object.entries(entry.placeholders ?? {})) {
|
|
5803
|
+
message = message.replaceAll(new RegExp(`\\$${name}\\$`, "gi"), valueAt(placeholder.content));
|
|
5804
|
+
}
|
|
5805
|
+
let sequentialIndex = 0;
|
|
5806
|
+
return message.replace(/%(?:(\d+)\$)?s/g, (_match, position) => {
|
|
5807
|
+
const index = position ? Number(position) - 1 : sequentialIndex++;
|
|
5808
|
+
return values[index] ?? "";
|
|
5809
|
+
}).replace(/\$(\d+)/g, (_match, index) => values[Number(index) - 1] ?? "");
|
|
5810
|
+
}
|
|
5811
|
+
function t(key, substitutions) {
|
|
5812
|
+
const entry = activeCatalog?.[key];
|
|
5813
|
+
return entry ? messageWithSubstitutions(entry, substitutions) : chrome.i18n.getMessage(key, substitutions) || key;
|
|
5814
|
+
}
|
|
5815
|
+
function extensionLocale() {
|
|
5816
|
+
return activeLocale ?? chrome.i18n.getUILanguage().replaceAll("_", "-");
|
|
5817
|
+
}
|
|
5818
|
+
async function loadExtensionLocalePreference() {
|
|
5819
|
+
const stored = await chrome.storage.local.get(LOCALE_STORAGE_KEY);
|
|
5820
|
+
const locale = isExtensionLocale(stored[LOCALE_STORAGE_KEY]) ? stored[LOCALE_STORAGE_KEY] : browserLocale();
|
|
5821
|
+
await applyExtensionLocale(locale);
|
|
5822
|
+
return locale;
|
|
5823
|
+
}
|
|
5824
|
+
async function saveExtensionLocalePreference(locale) {
|
|
5825
|
+
await chrome.storage.local.set({ [LOCALE_STORAGE_KEY]: locale });
|
|
5826
|
+
await applyExtensionLocale(locale);
|
|
5827
|
+
}
|
|
5828
|
+
async function applyExtensionLocale(locale) {
|
|
5829
|
+
const response = await fetch(chrome.runtime.getURL(LOCALE_PATHS[locale]));
|
|
5830
|
+
if (!response.ok) throw new Error(`Could not load extension locale: ${locale}`);
|
|
5831
|
+
activeCatalog = await response.json();
|
|
5832
|
+
activeLocale = locale;
|
|
5833
|
+
initializeDocumentLocale();
|
|
5834
|
+
}
|
|
5835
|
+
function initializeDocumentLocale() {
|
|
5836
|
+
document.documentElement.lang = extensionLocale();
|
|
5837
|
+
document.documentElement.dir = chrome.i18n.getMessage("@@bidi_dir") || "ltr";
|
|
5838
|
+
document.title = t("appName");
|
|
5839
|
+
}
|
|
5840
|
+
|
|
5785
5841
|
const PENDING_CONTEXT_KEY = "xopc.browser.pending-context";
|
|
5786
5842
|
const TAB_BINDING_PREFIX = "xopc.browser.tab-binding.";
|
|
5787
5843
|
function truncateUtf8(value, maxBytes) {
|
|
@@ -5801,13 +5857,13 @@ function sanitizedUrl(raw) {
|
|
|
5801
5857
|
try {
|
|
5802
5858
|
url = new URL(raw);
|
|
5803
5859
|
} catch {
|
|
5804
|
-
throw new Error("
|
|
5860
|
+
throw new Error(t("errorInvalidWebAddress"));
|
|
5805
5861
|
}
|
|
5806
5862
|
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
5807
|
-
throw new Error(
|
|
5863
|
+
throw new Error(t("errorRestrictedPage"));
|
|
5808
5864
|
}
|
|
5809
5865
|
if (url.hostname === "chromewebstore.google.com" || url.hostname === "chrome.google.com" && url.pathname.startsWith("/webstore")) {
|
|
5810
|
-
throw new Error("
|
|
5866
|
+
throw new Error(t("errorWebStorePage"));
|
|
5811
5867
|
}
|
|
5812
5868
|
url.username = "";
|
|
5813
5869
|
url.password = "";
|
|
@@ -5818,14 +5874,14 @@ function siteAccessError(cause, url) {
|
|
|
5818
5874
|
const message = cause instanceof Error ? cause.message : String(cause);
|
|
5819
5875
|
const hostname = new URL(url).hostname;
|
|
5820
5876
|
if (/cannot access|cannot be scripted|missing host permission|extensions gallery|chrome web store/i.test(message)) {
|
|
5821
|
-
return new Error(
|
|
5877
|
+
return new Error(t("errorSiteAccessBlocked", hostname));
|
|
5822
5878
|
}
|
|
5823
5879
|
return cause instanceof Error ? cause : new Error(message);
|
|
5824
5880
|
}
|
|
5825
5881
|
async function runWithTabSiteAccess(tabId, operation) {
|
|
5826
5882
|
const tab = await chrome.tabs.get(tabId);
|
|
5827
5883
|
if (tab.id === void 0 || tab.windowId === void 0 || !tab.url) {
|
|
5828
|
-
throw new Error("
|
|
5884
|
+
throw new Error(t("errorTabUnavailable"));
|
|
5829
5885
|
}
|
|
5830
5886
|
const url = sanitizedUrl(tab.url);
|
|
5831
5887
|
const originPattern = `${new URL(url).origin}/*`;
|
|
@@ -5838,7 +5894,7 @@ async function runWithTabSiteAccess(tabId, operation) {
|
|
|
5838
5894
|
} catch (cause) {
|
|
5839
5895
|
throw siteAccessError(cause, url);
|
|
5840
5896
|
}
|
|
5841
|
-
if (!granted) throw new Error(
|
|
5897
|
+
if (!granted) throw new Error(t("errorSiteAccessRequired", new URL(url).hostname));
|
|
5842
5898
|
newlyGranted = true;
|
|
5843
5899
|
}
|
|
5844
5900
|
try {
|
|
@@ -5852,15 +5908,15 @@ async function sha256(value) {
|
|
|
5852
5908
|
const bytes = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(value));
|
|
5853
5909
|
return [...new Uint8Array(bytes)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
5854
5910
|
}
|
|
5855
|
-
function extractPage(mode) {
|
|
5911
|
+
function extractPage(mode, messages) {
|
|
5856
5912
|
const normalize = (value) => value.replace(/\s+/g, " ").trim();
|
|
5857
5913
|
const selection = normalize(window.getSelection()?.toString() ?? "");
|
|
5858
5914
|
if (mode === "selection") {
|
|
5859
|
-
if (!selection) throw new Error(
|
|
5915
|
+
if (!selection) throw new Error(messages.selectText);
|
|
5860
5916
|
return { title: document.title, url: location.href, timeOrigin: performance.timeOrigin, selection };
|
|
5861
5917
|
}
|
|
5862
5918
|
const source = document.querySelector("article, main") ?? document.body;
|
|
5863
|
-
if (!source) throw new Error(
|
|
5919
|
+
if (!source) throw new Error(messages.noReadableContent);
|
|
5864
5920
|
const clone = source.cloneNode(true);
|
|
5865
5921
|
clone.querySelectorAll([
|
|
5866
5922
|
"script",
|
|
@@ -5882,23 +5938,26 @@ function extractPage(mode) {
|
|
|
5882
5938
|
"[inert]"
|
|
5883
5939
|
].join(",")).forEach((element) => element.remove());
|
|
5884
5940
|
const text = normalize(clone.innerText || clone.textContent || "");
|
|
5885
|
-
if (!text) throw new Error(
|
|
5941
|
+
if (!text) throw new Error(messages.noReadableContent);
|
|
5886
5942
|
return { title: document.title, url: location.href, timeOrigin: performance.timeOrigin, text };
|
|
5887
5943
|
}
|
|
5888
5944
|
async function captureTabPage(tabId, mode) {
|
|
5889
5945
|
const tab = await chrome.tabs.get(tabId);
|
|
5890
|
-
if (!tab.url) throw new Error("
|
|
5946
|
+
if (!tab.url) throw new Error(t("errorTabUnavailable"));
|
|
5891
5947
|
sanitizedUrl(tab.url);
|
|
5892
5948
|
const result = await chrome.scripting.executeScript({
|
|
5893
5949
|
target: { tabId },
|
|
5894
5950
|
func: extractPage,
|
|
5895
|
-
args: [mode
|
|
5951
|
+
args: [mode, {
|
|
5952
|
+
selectText: t("errorSelectText"),
|
|
5953
|
+
noReadableContent: t("errorNoReadableContent")
|
|
5954
|
+
}]
|
|
5896
5955
|
});
|
|
5897
5956
|
const raw = result[0]?.result;
|
|
5898
|
-
if (!raw) throw new Error("
|
|
5957
|
+
if (!raw) throw new Error(t("errorReadPage"));
|
|
5899
5958
|
const url = sanitizedUrl(raw.url);
|
|
5900
5959
|
if (new URL(url).origin !== new URL(sanitizedUrl(tab.url)).origin) {
|
|
5901
|
-
throw new Error("
|
|
5960
|
+
throw new Error(t("errorPageChangedReading"));
|
|
5902
5961
|
}
|
|
5903
5962
|
const selected = raw.selection ? truncateUtf8(raw.selection, MAX_BROWSER_SELECTION_BYTES) : void 0;
|
|
5904
5963
|
const page = raw.text ? truncateUtf8(raw.text, MAX_BROWSER_PAGE_TEXT_BYTES) : void 0;
|
|
@@ -5927,17 +5986,17 @@ async function activeTabId() {
|
|
|
5927
5986
|
}
|
|
5928
5987
|
async function currentTabDescriptor() {
|
|
5929
5988
|
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
|
|
5930
|
-
if (tab.id === void 0 || tab.windowId === void 0 || !tab.url) throw new Error("
|
|
5989
|
+
if (tab.id === void 0 || tab.windowId === void 0 || !tab.url) throw new Error(t("errorNoActivePage"));
|
|
5931
5990
|
return runWithTabSiteAccess(tab.id, async (accessibleTab) => {
|
|
5932
5991
|
const result = await chrome.scripting.executeScript({
|
|
5933
5992
|
target: { tabId: accessibleTab.id },
|
|
5934
5993
|
func: () => ({ url: location.href, timeOrigin: performance.timeOrigin })
|
|
5935
5994
|
});
|
|
5936
5995
|
const marker = result[0]?.result;
|
|
5937
|
-
if (!marker) throw new Error("
|
|
5996
|
+
if (!marker) throw new Error(t("errorIdentifyPage"));
|
|
5938
5997
|
const currentUrl = sanitizedUrl(marker.url);
|
|
5939
5998
|
if (new URL(currentUrl).origin !== new URL(accessibleTab.url).origin) {
|
|
5940
|
-
throw new Error("
|
|
5999
|
+
throw new Error(t("errorPageChangedConnecting"));
|
|
5941
6000
|
}
|
|
5942
6001
|
return {
|
|
5943
6002
|
tabId: String(accessibleTab.id),
|
|
@@ -5961,7 +6020,7 @@ function openDatabase() {
|
|
|
5961
6020
|
}
|
|
5962
6021
|
};
|
|
5963
6022
|
request.onsuccess = () => resolve(request.result);
|
|
5964
|
-
request.onerror = () => reject(request.error ?? new Error("
|
|
6023
|
+
request.onerror = () => reject(request.error ?? new Error(t("errorOpenOutbox")));
|
|
5965
6024
|
});
|
|
5966
6025
|
}
|
|
5967
6026
|
function transactionResult(database, mode, createRequest) {
|
|
@@ -5972,10 +6031,10 @@ function transactionResult(database, mode, createRequest) {
|
|
|
5972
6031
|
request.onsuccess = () => {
|
|
5973
6032
|
result = request.result;
|
|
5974
6033
|
};
|
|
5975
|
-
request.onerror = () => reject(request.error ?? new Error("
|
|
6034
|
+
request.onerror = () => reject(request.error ?? new Error(t("errorOutboxRequest")));
|
|
5976
6035
|
transaction.oncomplete = () => resolve(result);
|
|
5977
|
-
transaction.onerror = () => reject(transaction.error ?? new Error("
|
|
5978
|
-
transaction.onabort = () => reject(transaction.error ?? new Error("
|
|
6036
|
+
transaction.onerror = () => reject(transaction.error ?? new Error(t("errorOutboxTransaction")));
|
|
6037
|
+
transaction.onabort = () => reject(transaction.error ?? new Error(t("errorOutboxAborted")));
|
|
5979
6038
|
});
|
|
5980
6039
|
}
|
|
5981
6040
|
async function readBrowserOutbox(sessionKey) {
|
|
@@ -6055,7 +6114,7 @@ async function discoverLocalGateway(options) {
|
|
|
6055
6114
|
}
|
|
6056
6115
|
);
|
|
6057
6116
|
if (response.ok !== true || typeof response.gatewayUrl !== "string" || typeof response.invitation !== "string" || typeof response.expiresAt !== "number") {
|
|
6058
|
-
if (options?.force) throw new Error(response.error || "
|
|
6117
|
+
if (options?.force) throw new Error(response.error || t("errorInvalidLocalHostResponse"));
|
|
6059
6118
|
return void 0;
|
|
6060
6119
|
}
|
|
6061
6120
|
return {
|
|
@@ -6138,12 +6197,12 @@ async function forgetIdentity() {
|
|
|
6138
6197
|
const request = indexedDB.deleteDatabase(KEY_DATABASE);
|
|
6139
6198
|
request.onsuccess = () => resolve();
|
|
6140
6199
|
request.onerror = () => reject(request.error);
|
|
6141
|
-
request.onblocked = () => reject(new Error("
|
|
6200
|
+
request.onblocked = () => reject(new Error(t("errorIdentityInUse")));
|
|
6142
6201
|
});
|
|
6143
6202
|
}
|
|
6144
6203
|
async function publicKeyJwk(pair) {
|
|
6145
6204
|
const exported = await crypto.subtle.exportKey("jwk", pair.publicKey);
|
|
6146
|
-
if (!exported.x || !exported.y) throw new Error("
|
|
6205
|
+
if (!exported.x || !exported.y) throw new Error(t("errorIdentityExport"));
|
|
6147
6206
|
return { kty: "EC", crv: "P-256", x: exported.x, y: exported.y };
|
|
6148
6207
|
}
|
|
6149
6208
|
async function sign(pair, text) {
|
|
@@ -6206,7 +6265,7 @@ async function post(origin, path, body) {
|
|
|
6206
6265
|
signal: controller.signal
|
|
6207
6266
|
});
|
|
6208
6267
|
} catch (cause) {
|
|
6209
|
-
if (controller.signal.aborted) throw new Error(
|
|
6268
|
+
if (controller.signal.aborted) throw new Error(t("errorGatewayTimeout", String(GATEWAY_REQUEST_TIMEOUT_MS / 1e3)));
|
|
6210
6269
|
throw cause;
|
|
6211
6270
|
} finally {
|
|
6212
6271
|
clearTimeout(timeout);
|
|
@@ -6214,7 +6273,7 @@ async function post(origin, path, body) {
|
|
|
6214
6273
|
const json = await response.json().catch(() => ({}));
|
|
6215
6274
|
if (!response.ok) {
|
|
6216
6275
|
throw new GatewayHttpError(
|
|
6217
|
-
json.error?.code ?? json.error?.message ??
|
|
6276
|
+
json.error?.code ?? json.error?.message ?? t("errorGatewayStatus", String(response.status)),
|
|
6218
6277
|
response.status
|
|
6219
6278
|
);
|
|
6220
6279
|
}
|
|
@@ -6242,14 +6301,14 @@ async function signedPairingRequest(pair, payload, origin, requestId, action, co
|
|
|
6242
6301
|
const path = action === "request" ? "/api/device-pairing/requests" : `/api/device-pairing/requests/${requestId}/${action}`;
|
|
6243
6302
|
const response = await post(origin, path, { ...body, signature });
|
|
6244
6303
|
if (typeof response.signedPayload !== "string" || typeof response.signature !== "string") {
|
|
6245
|
-
throw new Error("
|
|
6304
|
+
throw new Error(t("errorUnsignedPairing"));
|
|
6246
6305
|
}
|
|
6247
6306
|
if (!await verifyGateway(payload.gatewayPublicKey, response.signedPayload, response.signature)) {
|
|
6248
|
-
throw new Error("
|
|
6307
|
+
throw new Error(t("errorGatewayVerification"));
|
|
6249
6308
|
}
|
|
6250
6309
|
const decoded = decodeJson(response.signedPayload);
|
|
6251
6310
|
if (decoded.gateway.id !== payload.gatewayId || decoded.nonce !== nonce || decoded.request.requestId !== requestId) {
|
|
6252
|
-
throw new Error("
|
|
6311
|
+
throw new Error(t("errorPairingMismatch"));
|
|
6253
6312
|
}
|
|
6254
6313
|
return decoded;
|
|
6255
6314
|
}
|
|
@@ -6310,14 +6369,14 @@ ${nextRefreshToken}`;
|
|
|
6310
6369
|
}
|
|
6311
6370
|
}
|
|
6312
6371
|
if (!response || !gatewayUrl) {
|
|
6313
|
-
throw lastRouteError instanceof Error ? lastRouteError : new Error("
|
|
6372
|
+
throw lastRouteError instanceof Error ? lastRouteError : new Error(t("errorNoReachableGatewayRoute"));
|
|
6314
6373
|
}
|
|
6315
|
-
if (typeof response.signedPayload !== "string" || typeof response.signature !== "string" || !await verifyGateway(gateway.gatewayPublicKey, response.signedPayload, response.signature)) throw new Error("
|
|
6374
|
+
if (typeof response.signedPayload !== "string" || typeof response.signature !== "string" || !await verifyGateway(gateway.gatewayPublicKey, response.signedPayload, response.signature)) throw new Error(t("errorGatewayVerification"));
|
|
6316
6375
|
const responseProof = decodeJson(response.signedPayload);
|
|
6317
6376
|
if (responseProof.purpose !== "device-refresh-v3" || responseProof.gatewayId !== gateway.gatewayId || responseProof.requestId !== requestId || responseProof.nonce !== nonce || !(responseProof.expiresAt > Date.now()) || responseProof.expiresAt > Date.now() + 6e4) throw new Error("Gateway refresh response does not match this request");
|
|
6318
6377
|
const payload = responseProof.tokens;
|
|
6319
6378
|
if (!payload?.accessToken || !payload.accessTokenExpiresAt || payload.refreshToken !== nextRefreshToken) {
|
|
6320
|
-
throw new Error("
|
|
6379
|
+
throw new Error(t("errorInvalidCredentials"));
|
|
6321
6380
|
}
|
|
6322
6381
|
return { ...payload, gatewayUrl };
|
|
6323
6382
|
}
|
|
@@ -6341,7 +6400,7 @@ async function pairGateway(invitation, onApproval, requestedOrigin) {
|
|
|
6341
6400
|
throw new Error("PAIRING_ALREADY_PENDING");
|
|
6342
6401
|
}
|
|
6343
6402
|
if (!journal) {
|
|
6344
|
-
if (payload.expiresAt <= Date.now()) throw new Error("
|
|
6403
|
+
if (payload.expiresAt <= Date.now()) throw new Error(t("errorExpiredPairingLink"));
|
|
6345
6404
|
journal = {
|
|
6346
6405
|
invitation: invitation.trim(),
|
|
6347
6406
|
payload,
|
|
@@ -6381,7 +6440,7 @@ async function pairGateway(invitation, onApproval, requestedOrigin) {
|
|
|
6381
6440
|
}
|
|
6382
6441
|
if (result.request.status !== "approved" && result.request.status !== "completed") {
|
|
6383
6442
|
await chrome.storage.local.remove(PAIRING_JOURNAL_KEY);
|
|
6384
|
-
throw new Error(
|
|
6443
|
+
throw new Error(t("errorPairingStatus", result.request.status));
|
|
6385
6444
|
}
|
|
6386
6445
|
if (result.request.status !== "completed") {
|
|
6387
6446
|
const response = await signedPairingRequestAcrossRoutes(
|
|
@@ -6397,7 +6456,7 @@ async function pairGateway(invitation, onApproval, requestedOrigin) {
|
|
|
6397
6456
|
);
|
|
6398
6457
|
({ origin, result } = response);
|
|
6399
6458
|
}
|
|
6400
|
-
if (!result.request.deviceId) throw new Error("
|
|
6459
|
+
if (!result.request.deviceId) throw new Error(t("errorBrowserNotRegistered"));
|
|
6401
6460
|
journal.origin = origin;
|
|
6402
6461
|
journal.completed = { deviceId: result.request.deviceId, gatewayName: result.gateway.name };
|
|
6403
6462
|
journal.refresh ??= { requestId: crypto.randomUUID(), nextRefreshToken: createRefreshToken() };
|
|
@@ -6470,7 +6529,7 @@ async function readProfile() {
|
|
|
6470
6529
|
}
|
|
6471
6530
|
async function getAccessProfile() {
|
|
6472
6531
|
const profile = await readProfile();
|
|
6473
|
-
if (!profile) throw new Error("
|
|
6532
|
+
if (!profile) throw new Error(t("errorBrowserNotPaired"));
|
|
6474
6533
|
if (profile.accessTokenExpiresAt > Date.now() + 3e4) return profile;
|
|
6475
6534
|
if (refreshTask) return refreshTask;
|
|
6476
6535
|
refreshTask = (async () => {
|
|
@@ -6520,7 +6579,7 @@ async function registerBrowserEndpoint() {
|
|
|
6520
6579
|
publicKey
|
|
6521
6580
|
})
|
|
6522
6581
|
});
|
|
6523
|
-
if (!response.ok) throw new Error(
|
|
6582
|
+
if (!response.ok) throw new Error(t("errorEndpointRegistration", String(response.status)));
|
|
6524
6583
|
}
|
|
6525
6584
|
async function createBrowserEndpointHello(tools = []) {
|
|
6526
6585
|
const profile = await getAccessProfile();
|
|
@@ -6568,4 +6627,4 @@ async function revokeAndForgetProfile() {
|
|
|
6568
6627
|
}
|
|
6569
6628
|
}
|
|
6570
6629
|
|
|
6571
|
-
export { ENDPOINT_PROTOCOL_VERSION as E, PENDING_CONTEXT_KEY as P, RealtimeClient as R, TAB_BINDING_PREFIX as T, activeTabId as a, canonicalJson as b, cancelPendingBrowserPairing as c, captureTabWithPermission as d, createBrowserEndpointHello as e, currentTabDescriptor as f, deleteBrowserOutbox as g, discoverLocalGateway as h, endpointToolContentSchema as i,
|
|
6630
|
+
export { ENDPOINT_PROTOCOL_VERSION as E, PENDING_CONTEXT_KEY as P, RealtimeClient as R, TAB_BINDING_PREFIX as T, activeTabId as a, canonicalJson as b, cancelPendingBrowserPairing as c, captureTabWithPermission as d, createBrowserEndpointHello as e, currentTabDescriptor as f, deleteBrowserOutbox as g, discoverLocalGateway as h, endpointToolContentSchema as i, extensionLocale as j, gatewayFetch as k, getAccessProfile as l, loadExtensionLocalePreference as m, readPendingBrowserPairing as n, readProfile as o, pairGateway as p, registerBrowserEndpoint as q, readBrowserOutbox as r, revokeAndForgetProfile as s, runWithTabSiteAccess as t, saveExtensionLocalePreference as u, setAutoConnectEnabled as v, t as w, writeBrowserOutbox as x };
|
|
@@ -73,12 +73,26 @@ svg { display: block; }
|
|
|
73
73
|
.brand { display: flex; align-items: center; gap: 8px; flex: 1; font-size: 15px; font-weight: 700; letter-spacing: -.01em; }
|
|
74
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
75
|
.brand-mark svg { width: 15px; height: 15px; stroke-width: 1.7; }
|
|
76
|
-
.status {
|
|
76
|
+
.status { display: inline-flex; align-items: center; gap: 6px; font-size: 11px; color: var(--fg-muted); }
|
|
77
77
|
.status-dot, .mini-status { width: 7px; height: 7px; flex: 0 0 auto; border-radius: 999px; background: var(--fg-disabled); }
|
|
78
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
79
|
.status-dot.error { background: var(--danger); }
|
|
80
|
-
.
|
|
81
|
-
.
|
|
80
|
+
.header-actions { position: relative; flex: 0 0 auto; }
|
|
81
|
+
.header-icon-button { width: 32px; height: 32px; display: grid; place-items: center; border: 1px solid transparent; border-radius: 9px; background: transparent; color: var(--fg-muted); }
|
|
82
|
+
.header-icon-button:hover, .header-icon-button[aria-expanded='true'] { border-color: var(--edge); background: var(--surface-hover); color: var(--fg); }
|
|
83
|
+
.header-icon-button svg { width: 17px; height: 17px; }
|
|
84
|
+
.settings-menu { position: absolute; z-index: 30; top: calc(100% + 8px); right: 0; width: min(260px, calc(100vw - 28px)); overflow: hidden; border: 1px solid var(--edge-strong); border-radius: 13px; padding: 7px; background: var(--surface-panel); box-shadow: var(--shadow-popover); }
|
|
85
|
+
.settings-menu-title { padding: 7px 8px 9px; font-size: 12px; font-weight: 680; }
|
|
86
|
+
.settings-group { border-top: 1px solid var(--edge); padding: 8px 0; }
|
|
87
|
+
.settings-label { display: flex; align-items: center; gap: 7px; padding: 2px 8px 7px; color: var(--fg-subtle); font-size: 10px; font-weight: 650; }
|
|
88
|
+
.settings-label svg { width: 14px; height: 14px; }
|
|
89
|
+
.settings-options { display: grid; grid-template-columns: 1fr 1fr; gap: 5px; }
|
|
90
|
+
.settings-options button { min-width: 0; height: 34px; display: flex; align-items: center; justify-content: center; gap: 5px; border: 1px solid var(--edge); border-radius: 8px; background: var(--surface-base); color: var(--fg-muted); font-size: 11px; }
|
|
91
|
+
.settings-options button:hover { border-color: var(--edge-strong); background: var(--surface-hover); color: var(--fg); }
|
|
92
|
+
.settings-options button.active { border-color: color-mix(in srgb, var(--accent) 35%, var(--edge)); background: var(--accent-soft); color: var(--accent-fg); font-weight: 650; }
|
|
93
|
+
.settings-options button svg { width: 13px; height: 13px; }
|
|
94
|
+
.settings-disconnect { width: 100%; border: 0; border-top: 1px solid var(--edge); padding: 10px 8px 6px; background: transparent; color: var(--danger); font-size: 11px; text-align: left; }
|
|
95
|
+
.settings-disconnect:hover { color: color-mix(in srgb, var(--danger) 82%, var(--fg)); }
|
|
82
96
|
|
|
83
97
|
.center { flex: 1; display: grid; place-items: center; padding: 24px; overflow: auto; }
|
|
84
98
|
.card { width: min(100%, 420px); border: 1px solid var(--edge); border-radius: 16px; padding: 22px; background: var(--surface-panel); box-shadow: var(--shadow-surface); }
|
|
@@ -211,13 +225,14 @@ svg { display: block; }
|
|
|
211
225
|
@keyframes pulse { 50% { opacity: .35; transform: scale(.8); } }
|
|
212
226
|
@keyframes skeleton { to { background-position: -200% 0; } }
|
|
213
227
|
|
|
214
|
-
.composer { position: relative; flex: 0 0 auto; margin: 0
|
|
215
|
-
.composer:focus-within { border-color:
|
|
216
|
-
.composer.dragging { border-color: var(--accent); box-shadow: 0 0 0
|
|
217
|
-
.file-drop-overlay { position: absolute; z-index: 20; inset: 0; display: flex; align-items: center; justify-content: center; gap: 7px; border-radius:
|
|
228
|
+
.composer { position: relative; flex: 0 0 auto; margin: 0 12px 12px; overflow: visible; border: 1px solid var(--edge); border-radius: 18px; background: var(--surface-panel); padding: 10px 10px 8px; box-shadow: var(--shadow-surface); transition: border-color 120ms ease, box-shadow 120ms ease; }
|
|
229
|
+
.composer:focus-within { border-color: var(--edge-strong); box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 7%, transparent), var(--shadow-surface); }
|
|
230
|
+
.composer.dragging { border-color: var(--accent); box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 12%, transparent), var(--shadow-surface); }
|
|
231
|
+
.file-drop-overlay { position: absolute; z-index: 20; inset: 0; display: flex; align-items: center; justify-content: center; gap: 7px; border-radius: 17px; 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
232
|
.file-drop-overlay svg { width: 17px; height: 17px; }
|
|
219
|
-
.composer-input-row { min-height:
|
|
220
|
-
.composer textarea { min-width: 0; min-height:
|
|
233
|
+
.composer-input-row { min-height: 58px; display: block; }
|
|
234
|
+
.composer textarea { width: 100%; min-width: 0; min-height: 54px; max-height: 144px; display: block; resize: none; overflow-y: auto; border: 0; padding: 5px 8px 8px; outline: none; background: transparent; color: var(--fg); font-size: 14px; line-height: 1.55; }
|
|
235
|
+
.composer textarea::placeholder { color: var(--fg-disabled); }
|
|
221
236
|
.composer-icon-button { width: 34px; height: 34px; border-color: transparent; color: var(--fg-muted); }
|
|
222
237
|
.tools-anchor { position: relative; flex: 0 0 auto; }
|
|
223
238
|
.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); }
|
|
@@ -232,20 +247,23 @@ svg { display: block; }
|
|
|
232
247
|
.tools-menu button.active-access { background: var(--success-soft); }
|
|
233
248
|
.tools-menu button.active-access > svg { color: var(--success); }
|
|
234
249
|
.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:
|
|
250
|
+
.send-button { width: 34px; height: 34px; flex: 0 0 auto; display: grid; place-items: center; border: 0; border-radius: 9px; background: transparent; color: var(--accent-fg); transition: background-color 120ms ease, color 120ms ease, transform 120ms ease; }
|
|
236
251
|
.send-button svg { width: 17px; height: 17px; }
|
|
237
|
-
.send-button:hover:not(:disabled) { background: var(--accent-
|
|
238
|
-
.send-button:disabled { background:
|
|
239
|
-
.stop-button { background: var(--
|
|
240
|
-
.stop-button:hover:not(:disabled) { background: var(--
|
|
241
|
-
.composer-footer { min-height:
|
|
252
|
+
.send-button:hover:not(:disabled) { background: var(--accent-soft); transform: translateY(-1px); }
|
|
253
|
+
.send-button:disabled { background: transparent; color: var(--fg-disabled); }
|
|
254
|
+
.stop-button { background: var(--surface-hover); color: var(--fg-muted); }
|
|
255
|
+
.stop-button:hover:not(:disabled) { background: var(--surface-active); color: var(--fg); }
|
|
256
|
+
.composer-footer { min-height: 36px; display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 3px 0 0; }
|
|
257
|
+
.composer-toolbar-start, .composer-toolbar-end { min-width: 0; display: flex; align-items: center; gap: 6px; }
|
|
258
|
+
.composer-toolbar-end { margin-left: auto; }
|
|
242
259
|
.composer-state { min-width: 0; display: flex; align-items: center; gap: 5px; color: var(--fg-subtle); font-size: 9px; }
|
|
260
|
+
.composer-state-label { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
|
|
243
261
|
.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
262
|
.access-pill svg { width: 10px; height: 10px; }
|
|
245
|
-
.model-controls { min-width: 0;
|
|
246
|
-
.model-controls select { min-width: 0; max-width:
|
|
247
|
-
.model-controls select:hover { background: var(--surface-
|
|
248
|
-
.model-controls select:last-child { max-width:
|
|
263
|
+
.model-controls { min-width: 0; height: 32px; display: flex; align-items: center; gap: 0; border-radius: 9px; padding: 0 2px; background: var(--surface-hover); }
|
|
264
|
+
.model-controls select { min-width: 0; max-width: 118px; height: 28px; border: 0; border-radius: 7px; padding: 4px 5px; outline: none; background: transparent; color: var(--fg-muted); font-size: 10px; font-weight: 560; text-overflow: ellipsis; }
|
|
265
|
+
.model-controls select:hover, .model-controls select:focus { background: var(--surface-active); color: var(--fg); }
|
|
266
|
+
.model-controls select:last-child { max-width: 72px; color: var(--fg-subtle); }
|
|
249
267
|
|
|
250
268
|
.composer-contexts { display: flex; flex-wrap: wrap; gap: 5px; margin-bottom: 6px; }
|
|
251
269
|
.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; }
|
|
@@ -290,7 +308,10 @@ svg { display: block; }
|
|
|
290
308
|
.status { margin-right: 68px; }
|
|
291
309
|
.messages { padding-inline: 12px; }
|
|
292
310
|
.message.user { width: 92%; }
|
|
293
|
-
.
|
|
311
|
+
.composer { margin-inline: 8px; }
|
|
312
|
+
.composer-state-label { display: none; }
|
|
313
|
+
.model-controls select { max-width: 82px; }
|
|
314
|
+
.model-controls select:last-child { max-width: 58px; }
|
|
294
315
|
.quick-prompts { gap: 6px; }
|
|
295
316
|
}
|
|
296
317
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as endpointToolContentSchema, E as ENDPOINT_PROTOCOL_VERSION, b as canonicalJson, T as TAB_BINDING_PREFIX, d as captureTabWithPermission, P as PENDING_CONTEXT_KEY,
|
|
1
|
+
import { i as endpointToolContentSchema, E as ENDPOINT_PROTOCOL_VERSION, b as canonicalJson, T as TAB_BINDING_PREFIX, d as captureTabWithPermission, P as PENDING_CONTEXT_KEY, w as t, o as readProfile, q as registerBrowserEndpoint, l as getAccessProfile, R as RealtimeClient, e as createBrowserEndpointHello, k as gatewayFetch } from './assets/auth-ClQTK565.js';
|
|
2
2
|
|
|
3
3
|
const BROWSER_EXTENSION_PROTOCOL_VERSION = 4;
|
|
4
4
|
const BROWSER_CONTROL_ENDPOINT_TOOL_NAME = "browser.control";
|
|
@@ -1143,11 +1143,20 @@ function diff(previous, next) {
|
|
|
1143
1143
|
|
|
1144
1144
|
const log = createLogger("Background");
|
|
1145
1145
|
const BACKGROUND_CLIENT_ID_KEY = "xopc.browser.background-client-id";
|
|
1146
|
+
const RECONNECT_ALARM = "xopc.browser.reconnect";
|
|
1147
|
+
const RECONNECT_DELAY_MINUTES = 1;
|
|
1146
1148
|
let realtime;
|
|
1147
1149
|
let endpointClaim;
|
|
1148
1150
|
let lastConnectionError;
|
|
1149
1151
|
let connectTask;
|
|
1150
1152
|
let connectionGeneration = 0;
|
|
1153
|
+
function clearReconnectAlarm() {
|
|
1154
|
+
void chrome.alarms.clear(RECONNECT_ALARM);
|
|
1155
|
+
}
|
|
1156
|
+
function scheduleReconnectAlarm() {
|
|
1157
|
+
if (endpointClaim) return;
|
|
1158
|
+
chrome.alarms.create(RECONNECT_ALARM, { delayInMinutes: RECONNECT_DELAY_MINUTES });
|
|
1159
|
+
}
|
|
1151
1160
|
const browserToolRegistry = new EndpointToolRegistry([{
|
|
1152
1161
|
descriptor: BROWSER_CONTROL_ENDPOINT_DESCRIPTOR,
|
|
1153
1162
|
execute: async (args) => {
|
|
@@ -1210,7 +1219,11 @@ async function connect(generation) {
|
|
|
1210
1219
|
createWebSocket: (url) => new WebSocket(url),
|
|
1211
1220
|
onStateChange: (state, error) => {
|
|
1212
1221
|
lastConnectionError = error;
|
|
1213
|
-
if (state === "connected")
|
|
1222
|
+
if (state === "connected") {
|
|
1223
|
+
lastConnectionError = void 0;
|
|
1224
|
+
} else {
|
|
1225
|
+
scheduleReconnectAlarm();
|
|
1226
|
+
}
|
|
1214
1227
|
if (error) log.warn("Browser Realtime connection changed", { state, error });
|
|
1215
1228
|
}
|
|
1216
1229
|
});
|
|
@@ -1219,6 +1232,7 @@ async function connect(generation) {
|
|
|
1219
1232
|
onReady: ({ endpointId, turnToken }) => {
|
|
1220
1233
|
endpointClaim = { endpointId, token: turnToken };
|
|
1221
1234
|
lastConnectionError = void 0;
|
|
1235
|
+
clearReconnectAlarm();
|
|
1222
1236
|
endpointHost.connect((message) => client.sendEndpointMessage(message));
|
|
1223
1237
|
void chrome.runtime.sendMessage({ type: "browser/endpoint-ready", claim: endpointClaim }).catch(() => void 0);
|
|
1224
1238
|
log.info("Browser control connected through Gateway Realtime", { endpointId });
|
|
@@ -1229,6 +1243,7 @@ async function connect(generation) {
|
|
|
1229
1243
|
onDisconnected: () => {
|
|
1230
1244
|
endpointClaim = void 0;
|
|
1231
1245
|
endpointHost.disconnect();
|
|
1246
|
+
scheduleReconnectAlarm();
|
|
1232
1247
|
}
|
|
1233
1248
|
});
|
|
1234
1249
|
if (generation !== connectionGeneration || realtime) return;
|
|
@@ -1247,6 +1262,7 @@ function connectWithLogging() {
|
|
|
1247
1262
|
const generation = connectionGeneration;
|
|
1248
1263
|
connectTask = connect(generation).catch((error) => {
|
|
1249
1264
|
lastConnectionError = error instanceof Error ? error.message : String(error);
|
|
1265
|
+
scheduleReconnectAlarm();
|
|
1250
1266
|
log.warn("Could not connect browser Realtime transport", { error: lastConnectionError });
|
|
1251
1267
|
}).finally(() => {
|
|
1252
1268
|
connectTask = void 0;
|
|
@@ -1284,17 +1300,33 @@ chrome.runtime.onInstalled.addListener(() => {
|
|
|
1284
1300
|
chrome.contextMenus.removeAll(() => {
|
|
1285
1301
|
chrome.contextMenus.create({
|
|
1286
1302
|
id: "xopc-ask-selection",
|
|
1287
|
-
title: "
|
|
1303
|
+
title: t("contextMenuAskSelection"),
|
|
1288
1304
|
contexts: ["selection"]
|
|
1289
1305
|
});
|
|
1290
1306
|
});
|
|
1291
1307
|
connectWithLogging();
|
|
1292
1308
|
});
|
|
1293
1309
|
chrome.runtime.onStartup.addListener(connectWithLogging);
|
|
1310
|
+
chrome.alarms.onAlarm.addListener((alarm) => {
|
|
1311
|
+
if (alarm.name !== RECONNECT_ALARM) return;
|
|
1312
|
+
void readProfile().then((profile) => {
|
|
1313
|
+
if (!profile) {
|
|
1314
|
+
clearReconnectAlarm();
|
|
1315
|
+
return;
|
|
1316
|
+
}
|
|
1317
|
+
if (endpointClaim) {
|
|
1318
|
+
clearReconnectAlarm();
|
|
1319
|
+
return;
|
|
1320
|
+
}
|
|
1321
|
+
disconnect();
|
|
1322
|
+
connectWithLogging();
|
|
1323
|
+
});
|
|
1324
|
+
});
|
|
1294
1325
|
chrome.storage.onChanged.addListener((changes, area) => {
|
|
1295
1326
|
if (area === "local" && changes["xopc.browser.profile"]) {
|
|
1296
1327
|
disconnect();
|
|
1297
|
-
connectWithLogging();
|
|
1328
|
+
if (changes["xopc.browser.profile"].newValue) connectWithLogging();
|
|
1329
|
+
else clearReconnectAlarm();
|
|
1298
1330
|
}
|
|
1299
1331
|
});
|
|
1300
1332
|
void chrome.sidePanel.setPanelBehavior({ openPanelOnActionClick: true });
|
|
@@ -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-
|
|
9
|
-
<link rel="stylesheet" crossorigin href="./assets/sidepanel-
|
|
8
|
+
<link rel="modulepreload" crossorigin href="./assets/auth-ClQTK565.js">
|
|
9
|
+
<link rel="stylesheet" crossorigin href="./assets/sidepanel-CeGqObOa.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
12
12
|
<div id="root"></div>
|