@quanta-intellect/vessel-browser 0.1.120 → 0.1.123
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/README.md +10 -4
- package/out/main/index.js +463 -133
- package/out/preload/index.js +10 -0
- package/out/renderer/assets/{index-COyRPuS5.js → index-Cvmlazb5.js} +1632 -806
- package/out/renderer/assets/{index-CFbT1_av.css → index-D2u6Brx4.css} +184 -0
- package/out/renderer/index.html +2 -2
- package/package.json +10 -5
package/out/main/index.js
CHANGED
|
@@ -52,10 +52,43 @@ function createLogger(scope) {
|
|
|
52
52
|
error: (...args) => writeLog("error", scope, args)
|
|
53
53
|
};
|
|
54
54
|
}
|
|
55
|
+
const SIDEBAR_MIN_WIDTH = 240;
|
|
56
|
+
const SIDEBAR_MAX_WIDTH = 800;
|
|
57
|
+
const SIDEBAR_RESIZE_HANDLE_OVERLAP = 6;
|
|
58
|
+
const DETACHED_SIDEBAR_MIN_WIDTH = 360;
|
|
59
|
+
const DETACHED_SIDEBAR_MIN_HEIGHT = 480;
|
|
60
|
+
const DETACHED_SIDEBAR_DEFAULT_WIDTH = 420;
|
|
61
|
+
const DETACHED_SIDEBAR_DEFAULT_HEIGHT = 760;
|
|
62
|
+
function clampSidebarWidth(width) {
|
|
63
|
+
return Math.max(
|
|
64
|
+
SIDEBAR_MIN_WIDTH,
|
|
65
|
+
Math.min(SIDEBAR_MAX_WIDTH, Math.round(width))
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
function sanitizeSidebarPanelMode(value) {
|
|
69
|
+
return value === "closed" || value === "docked" || value === "detached" ? value : "docked";
|
|
70
|
+
}
|
|
71
|
+
function sanitizeSidebarDetachedBounds(value) {
|
|
72
|
+
if (!value || typeof value !== "object") return null;
|
|
73
|
+
const bounds = value;
|
|
74
|
+
const width = Number(bounds.width);
|
|
75
|
+
const height = Number(bounds.height);
|
|
76
|
+
if (!Number.isFinite(width) || !Number.isFinite(height)) return null;
|
|
77
|
+
const x = Number(bounds.x);
|
|
78
|
+
const y = Number(bounds.y);
|
|
79
|
+
return {
|
|
80
|
+
...Number.isFinite(x) ? { x: Math.round(x) } : {},
|
|
81
|
+
...Number.isFinite(y) ? { y: Math.round(y) } : {},
|
|
82
|
+
width: Math.max(DETACHED_SIDEBAR_MIN_WIDTH, Math.round(width)),
|
|
83
|
+
height: Math.max(DETACHED_SIDEBAR_MIN_HEIGHT, Math.round(height))
|
|
84
|
+
};
|
|
85
|
+
}
|
|
55
86
|
const defaults = {
|
|
56
87
|
defaultUrl: "https://start.duckduckgo.com",
|
|
57
88
|
theme: "dark",
|
|
89
|
+
sidebarPanelMode: "docked",
|
|
58
90
|
sidebarWidth: 400,
|
|
91
|
+
sidebarDetachedBounds: null,
|
|
59
92
|
mcpPort: 3100,
|
|
60
93
|
autoRestoreSession: true,
|
|
61
94
|
clearBookmarksOnLaunch: false,
|
|
@@ -258,6 +291,10 @@ function loadSettings() {
|
|
|
258
291
|
mergeChatProviderSecret(parsed.chatProvider ?? null)
|
|
259
292
|
),
|
|
260
293
|
mcpPort: sanitizePort(parsed.mcpPort ?? defaults.mcpPort),
|
|
294
|
+
sidebarPanelMode: sanitizeSidebarPanelMode(parsed.sidebarPanelMode),
|
|
295
|
+
sidebarDetachedBounds: sanitizeSidebarDetachedBounds(
|
|
296
|
+
parsed.sidebarDetachedBounds
|
|
297
|
+
),
|
|
261
298
|
sourceDoNotAllowList: sanitizeStringList(
|
|
262
299
|
parsed.sourceDoNotAllowList ?? defaults.sourceDoNotAllowList
|
|
263
300
|
),
|
|
@@ -305,6 +342,10 @@ function setSetting(key2, value) {
|
|
|
305
342
|
loadSettings();
|
|
306
343
|
if (key2 === "mcpPort") {
|
|
307
344
|
settings.mcpPort = sanitizePort(value);
|
|
345
|
+
} else if (key2 === "sidebarPanelMode") {
|
|
346
|
+
settings.sidebarPanelMode = sanitizeSidebarPanelMode(value);
|
|
347
|
+
} else if (key2 === "sidebarDetachedBounds") {
|
|
348
|
+
settings.sidebarDetachedBounds = sanitizeSidebarDetachedBounds(value);
|
|
308
349
|
} else if (key2 === "sourceDoNotAllowList") {
|
|
309
350
|
settings.sourceDoNotAllowList = sanitizeStringList(value);
|
|
310
351
|
} else if (key2 === "chatProvider") {
|
|
@@ -343,8 +384,43 @@ function setSetting(key2, value) {
|
|
|
343
384
|
function flushPersist$5() {
|
|
344
385
|
return saveDirty ? persistNow() : Promise.resolve();
|
|
345
386
|
}
|
|
387
|
+
function isAirGapped() {
|
|
388
|
+
const hasAirGapSwitch = typeof electron.app?.commandLine?.hasSwitch === "function" && electron.app.commandLine.hasSwitch("air-gapped");
|
|
389
|
+
return hasAirGapSwitch || process.env.VESSEL_AIR_GAPPED === "1";
|
|
390
|
+
}
|
|
391
|
+
const LOCAL_PROVIDER_IDS = /* @__PURE__ */ new Set(["ollama", "llama_cpp"]);
|
|
392
|
+
function isLocalProvider(providerId) {
|
|
393
|
+
return LOCAL_PROVIDER_IDS.has(providerId);
|
|
394
|
+
}
|
|
395
|
+
function isLocalHostname(hostname) {
|
|
396
|
+
const normalized = hostname.toLowerCase();
|
|
397
|
+
return normalized === "localhost" || normalized === "127.0.0.1" || normalized === "::1" || normalized === "[::1]";
|
|
398
|
+
}
|
|
399
|
+
function isLocalBaseUrl(baseUrl) {
|
|
400
|
+
if (!baseUrl) return false;
|
|
401
|
+
try {
|
|
402
|
+
return isLocalHostname(new URL(baseUrl).hostname);
|
|
403
|
+
} catch {
|
|
404
|
+
return false;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
function getAirGapBlockReason(url) {
|
|
408
|
+
if (!isAirGapped()) return null;
|
|
409
|
+
let parsed;
|
|
410
|
+
try {
|
|
411
|
+
parsed = new URL(url);
|
|
412
|
+
} catch {
|
|
413
|
+
return null;
|
|
414
|
+
}
|
|
415
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
416
|
+
return null;
|
|
417
|
+
}
|
|
418
|
+
return isLocalHostname(parsed.hostname) ? null : `Air-gapped mode blocked network access to ${parsed.hostname}.`;
|
|
419
|
+
}
|
|
346
420
|
function checkDomainPolicy(url) {
|
|
347
421
|
if (!url || url.startsWith("about:")) return null;
|
|
422
|
+
const airGapBlockReason = getAirGapBlockReason(url);
|
|
423
|
+
if (airGapBlockReason) return airGapBlockReason;
|
|
348
424
|
const settings2 = loadSettings();
|
|
349
425
|
const policy = settings2.domainPolicy;
|
|
350
426
|
if (policy.allowedDomains.length === 0 && policy.blockedDomains.length === 0) {
|
|
@@ -3441,6 +3517,9 @@ const Channels = {
|
|
|
3441
3517
|
SIDEBAR_RESIZE: "ui:sidebar-resize",
|
|
3442
3518
|
SIDEBAR_RESIZE_START: "ui:sidebar-resize-start",
|
|
3443
3519
|
SIDEBAR_RESIZE_COMMIT: "ui:sidebar-resize-commit",
|
|
3520
|
+
SIDEBAR_POPOUT: "ui:sidebar-popout",
|
|
3521
|
+
SIDEBAR_DOCK: "ui:sidebar-dock",
|
|
3522
|
+
SIDEBAR_STATE_UPDATE: "ui:sidebar-state-update",
|
|
3444
3523
|
SIDEBAR_CONTEXT_MENU: "ui:sidebar-context-menu",
|
|
3445
3524
|
FOCUS_MODE_TOGGLE: "ui:focus-mode-toggle",
|
|
3446
3525
|
SETTINGS_VISIBILITY: "ui:settings-visibility",
|
|
@@ -4691,6 +4770,9 @@ function assertFeatureUnlocked(featureName, featureLabel = featureName) {
|
|
|
4691
4770
|
}
|
|
4692
4771
|
}
|
|
4693
4772
|
async function getCheckoutUrl(email) {
|
|
4773
|
+
if (isAirGapped()) {
|
|
4774
|
+
return errorResult("Checkout is unavailable in air-gapped mode.");
|
|
4775
|
+
}
|
|
4694
4776
|
try {
|
|
4695
4777
|
const params = new URLSearchParams();
|
|
4696
4778
|
if (email) params.set("email", email);
|
|
@@ -4709,6 +4791,9 @@ async function getCheckoutUrl(email) {
|
|
|
4709
4791
|
}
|
|
4710
4792
|
}
|
|
4711
4793
|
async function getPortalUrl() {
|
|
4794
|
+
if (isAirGapped()) {
|
|
4795
|
+
return errorResult("Billing portal is unavailable in air-gapped mode.");
|
|
4796
|
+
}
|
|
4712
4797
|
const current = loadSettings().premium;
|
|
4713
4798
|
const identifier = current.verificationToken;
|
|
4714
4799
|
if (!identifier) {
|
|
@@ -4736,6 +4821,9 @@ async function getPortalUrl() {
|
|
|
4736
4821
|
}
|
|
4737
4822
|
}
|
|
4738
4823
|
async function verifySubscription$1(identifier) {
|
|
4824
|
+
if (isAirGapped()) {
|
|
4825
|
+
return loadSettings().premium;
|
|
4826
|
+
}
|
|
4739
4827
|
const current = loadSettings().premium;
|
|
4740
4828
|
const verificationIdentifier = identifier || current.verificationToken || current.customerId;
|
|
4741
4829
|
if (!verificationIdentifier) {
|
|
@@ -4773,6 +4861,9 @@ async function verifySubscription$1(identifier) {
|
|
|
4773
4861
|
}
|
|
4774
4862
|
}
|
|
4775
4863
|
async function requestActivationCode(email) {
|
|
4864
|
+
if (isAirGapped()) {
|
|
4865
|
+
return errorResult("Activation codes are unavailable in air-gapped mode.");
|
|
4866
|
+
}
|
|
4776
4867
|
const normalizedEmail = email.trim().toLowerCase();
|
|
4777
4868
|
if (!normalizedEmail) {
|
|
4778
4869
|
return errorResult("Email is required");
|
|
@@ -4796,6 +4887,11 @@ async function requestActivationCode(email) {
|
|
|
4796
4887
|
}
|
|
4797
4888
|
}
|
|
4798
4889
|
async function verifyActivationCode(email, code, challengeToken) {
|
|
4890
|
+
if (isAirGapped()) {
|
|
4891
|
+
return errorResult("Activation codes are unavailable in air-gapped mode.", {
|
|
4892
|
+
state: getPremiumState()
|
|
4893
|
+
});
|
|
4894
|
+
}
|
|
4799
4895
|
const normalizedEmail = email.trim().toLowerCase();
|
|
4800
4896
|
const trimmedCode = code.trim();
|
|
4801
4897
|
if (!normalizedEmail) {
|
|
@@ -4844,6 +4940,7 @@ async function verifyActivationCode(email, code, challengeToken) {
|
|
|
4844
4940
|
let revalidationTimer = null;
|
|
4845
4941
|
function startBackgroundRevalidation() {
|
|
4846
4942
|
if (revalidationTimer) return;
|
|
4943
|
+
if (isAirGapped()) return;
|
|
4847
4944
|
const { premium } = loadSettings();
|
|
4848
4945
|
const identifier = premium.verificationToken || premium.customerId;
|
|
4849
4946
|
if (identifier) {
|
|
@@ -4919,6 +5016,7 @@ let eventQueue = [];
|
|
|
4919
5016
|
let flushTimer = null;
|
|
4920
5017
|
let sessionStartedAt = null;
|
|
4921
5018
|
function isEnabled() {
|
|
5019
|
+
if (isAirGapped()) return false;
|
|
4922
5020
|
if (POSTHOG_API_KEY === "YOUR_POSTHOG_KEY_HERE") return false;
|
|
4923
5021
|
if (process.env.VESSEL_DEV === "1") return false;
|
|
4924
5022
|
return loadSettings().telemetryEnabled !== false;
|
|
@@ -6577,6 +6675,159 @@ function schedulePageSnapshotCapture(wc, sendToRendererViews, delayMs = 0, optio
|
|
|
6577
6675
|
}
|
|
6578
6676
|
scheduleTimerAt(wc, sendToRendererViews, nextDueAt, options);
|
|
6579
6677
|
}
|
|
6678
|
+
function setSidebarPanelMode(state2, mode, reason = "user") {
|
|
6679
|
+
state2.uiState.sidebarPanelMode = mode;
|
|
6680
|
+
if (reason === "user") {
|
|
6681
|
+
setSetting("sidebarPanelMode", mode);
|
|
6682
|
+
}
|
|
6683
|
+
}
|
|
6684
|
+
function persistDetachedBounds(state2) {
|
|
6685
|
+
const sidebarWindow = state2.sidebarWindow;
|
|
6686
|
+
if (!sidebarWindow || sidebarWindow.isDestroyed()) return;
|
|
6687
|
+
const bounds = sidebarWindow.getBounds();
|
|
6688
|
+
state2.uiState.sidebarDetachedBounds = {
|
|
6689
|
+
x: bounds.x,
|
|
6690
|
+
y: bounds.y,
|
|
6691
|
+
width: bounds.width,
|
|
6692
|
+
height: bounds.height
|
|
6693
|
+
};
|
|
6694
|
+
setSetting("sidebarDetachedBounds", state2.uiState.sidebarDetachedBounds);
|
|
6695
|
+
}
|
|
6696
|
+
function closeDetachedSidebarWindow(state2) {
|
|
6697
|
+
const sidebarWindow = state2.sidebarWindow;
|
|
6698
|
+
if (!sidebarWindow) return false;
|
|
6699
|
+
state2.sidebarWindow = null;
|
|
6700
|
+
state2.sidebarWindowClosing = true;
|
|
6701
|
+
sidebarWindow.once("closed", () => {
|
|
6702
|
+
state2.sidebarWindowClosing = false;
|
|
6703
|
+
});
|
|
6704
|
+
sidebarWindow.close();
|
|
6705
|
+
return true;
|
|
6706
|
+
}
|
|
6707
|
+
function moveSidebarToMainWindow(state2) {
|
|
6708
|
+
state2.sidebarWindow?.contentView.removeChildView(state2.sidebarView);
|
|
6709
|
+
state2.mainWindow.contentView.addChildView(state2.sidebarView);
|
|
6710
|
+
}
|
|
6711
|
+
function getSidebarPanelState(state2) {
|
|
6712
|
+
return {
|
|
6713
|
+
open: state2.uiState.sidebarPanelMode !== "closed",
|
|
6714
|
+
width: state2.uiState.sidebarWidth,
|
|
6715
|
+
detached: state2.uiState.sidebarPanelMode === "detached"
|
|
6716
|
+
};
|
|
6717
|
+
}
|
|
6718
|
+
function emitSidebarPanelState(state2) {
|
|
6719
|
+
const panelState = getSidebarPanelState(state2);
|
|
6720
|
+
if (!state2.chromeView.webContents.isDestroyed()) {
|
|
6721
|
+
state2.chromeView.webContents.send(Channels.SIDEBAR_STATE_UPDATE, panelState);
|
|
6722
|
+
}
|
|
6723
|
+
if (!state2.sidebarView.webContents.isDestroyed()) {
|
|
6724
|
+
state2.sidebarView.webContents.send(
|
|
6725
|
+
Channels.SIDEBAR_STATE_UPDATE,
|
|
6726
|
+
panelState
|
|
6727
|
+
);
|
|
6728
|
+
}
|
|
6729
|
+
return panelState;
|
|
6730
|
+
}
|
|
6731
|
+
function isSidebarAttached(state2) {
|
|
6732
|
+
return state2.uiState.sidebarPanelMode === "docked";
|
|
6733
|
+
}
|
|
6734
|
+
function isSidebarDetached(state2) {
|
|
6735
|
+
return state2.uiState.sidebarPanelMode === "detached";
|
|
6736
|
+
}
|
|
6737
|
+
function closeSidebar(state2, relayout, reason = "user") {
|
|
6738
|
+
if (state2.sidebarWindow) {
|
|
6739
|
+
moveSidebarToMainWindow(state2);
|
|
6740
|
+
closeDetachedSidebarWindow(state2);
|
|
6741
|
+
}
|
|
6742
|
+
setSidebarPanelMode(state2, "closed", reason);
|
|
6743
|
+
relayout();
|
|
6744
|
+
return emitSidebarPanelState(state2);
|
|
6745
|
+
}
|
|
6746
|
+
function openDockedSidebar(state2, relayout) {
|
|
6747
|
+
setSidebarPanelMode(state2, "docked");
|
|
6748
|
+
relayout();
|
|
6749
|
+
return emitSidebarPanelState(state2);
|
|
6750
|
+
}
|
|
6751
|
+
function toggleDockedSidebar(state2, relayout) {
|
|
6752
|
+
if (isSidebarDetached(state2)) {
|
|
6753
|
+
state2.sidebarWindow?.focus();
|
|
6754
|
+
return getSidebarPanelState(state2);
|
|
6755
|
+
}
|
|
6756
|
+
setSidebarPanelMode(
|
|
6757
|
+
state2,
|
|
6758
|
+
state2.uiState.sidebarPanelMode === "docked" ? "closed" : "docked"
|
|
6759
|
+
);
|
|
6760
|
+
relayout();
|
|
6761
|
+
return emitSidebarPanelState(state2);
|
|
6762
|
+
}
|
|
6763
|
+
function layoutDetachedSidebar(state2) {
|
|
6764
|
+
if (!state2.sidebarWindow) return;
|
|
6765
|
+
const [width, height] = state2.sidebarWindow.getContentSize();
|
|
6766
|
+
state2.sidebarView.setBounds({ x: 0, y: 0, width, height });
|
|
6767
|
+
}
|
|
6768
|
+
function detachSidebar(state2, hooks) {
|
|
6769
|
+
if (state2.sidebarWindow) {
|
|
6770
|
+
state2.sidebarWindow.focus();
|
|
6771
|
+
return getSidebarPanelState(state2);
|
|
6772
|
+
}
|
|
6773
|
+
const detachedBounds = state2.uiState.sidebarDetachedBounds;
|
|
6774
|
+
const detachedWidth = detachedBounds?.width ?? Math.max(DETACHED_SIDEBAR_DEFAULT_WIDTH, state2.uiState.sidebarWidth);
|
|
6775
|
+
const detachedHeight = detachedBounds?.height ?? DETACHED_SIDEBAR_DEFAULT_HEIGHT;
|
|
6776
|
+
const sidebarWindow = new electron.BaseWindow({
|
|
6777
|
+
...typeof detachedBounds?.x === "number" ? { x: detachedBounds.x } : {},
|
|
6778
|
+
...typeof detachedBounds?.y === "number" ? { y: detachedBounds.y } : {},
|
|
6779
|
+
width: Math.max(DETACHED_SIDEBAR_MIN_WIDTH, Math.round(detachedWidth)),
|
|
6780
|
+
height: Math.max(DETACHED_SIDEBAR_MIN_HEIGHT, Math.round(detachedHeight)),
|
|
6781
|
+
minWidth: DETACHED_SIDEBAR_MIN_WIDTH,
|
|
6782
|
+
minHeight: DETACHED_SIDEBAR_MIN_HEIGHT,
|
|
6783
|
+
frame: true,
|
|
6784
|
+
show: false,
|
|
6785
|
+
backgroundColor: "#1a1a1e",
|
|
6786
|
+
title: "Vessel Agent",
|
|
6787
|
+
icon: hooks.getWindowIconPath()
|
|
6788
|
+
});
|
|
6789
|
+
state2.mainWindow.contentView.removeChildView(state2.sidebarView);
|
|
6790
|
+
sidebarWindow.contentView.addChildView(state2.sidebarView);
|
|
6791
|
+
state2.sidebarWindow = sidebarWindow;
|
|
6792
|
+
setSidebarPanelMode(state2, "detached");
|
|
6793
|
+
sidebarWindow.on("resize", () => {
|
|
6794
|
+
layoutDetachedSidebar(state2);
|
|
6795
|
+
persistDetachedBounds(state2);
|
|
6796
|
+
});
|
|
6797
|
+
sidebarWindow.on("move", () => persistDetachedBounds(state2));
|
|
6798
|
+
sidebarWindow.on("close", (event) => {
|
|
6799
|
+
if (state2.sidebarWindowClosing) return;
|
|
6800
|
+
event.preventDefault();
|
|
6801
|
+
dockSidebar(state2, hooks);
|
|
6802
|
+
});
|
|
6803
|
+
sidebarWindow.on("closed", () => {
|
|
6804
|
+
if (state2.sidebarWindow !== sidebarWindow) return;
|
|
6805
|
+
state2.sidebarWindow = null;
|
|
6806
|
+
setSidebarPanelMode(state2, "docked");
|
|
6807
|
+
state2.mainWindow.contentView.addChildView(state2.sidebarView);
|
|
6808
|
+
hooks.relayout();
|
|
6809
|
+
emitSidebarPanelState(state2);
|
|
6810
|
+
});
|
|
6811
|
+
hooks.relayout();
|
|
6812
|
+
layoutDetachedSidebar(state2);
|
|
6813
|
+
sidebarWindow.show();
|
|
6814
|
+
sidebarWindow.focus();
|
|
6815
|
+
return emitSidebarPanelState(state2);
|
|
6816
|
+
}
|
|
6817
|
+
function dockSidebar(state2, hooks) {
|
|
6818
|
+
const sidebarWindow = state2.sidebarWindow;
|
|
6819
|
+
if (!sidebarWindow) {
|
|
6820
|
+
setSidebarPanelMode(state2, "docked");
|
|
6821
|
+
hooks.relayout();
|
|
6822
|
+
return emitSidebarPanelState(state2);
|
|
6823
|
+
}
|
|
6824
|
+
setSidebarPanelMode(state2, "docked");
|
|
6825
|
+
moveSidebarToMainWindow(state2);
|
|
6826
|
+
hooks.relayout();
|
|
6827
|
+
closeDetachedSidebarWindow(state2);
|
|
6828
|
+
state2.mainWindow.focus();
|
|
6829
|
+
return emitSidebarPanelState(state2);
|
|
6830
|
+
}
|
|
6580
6831
|
function enableClipboardShortcuts(view) {
|
|
6581
6832
|
view.webContents.on("before-input-event", (event, input) => {
|
|
6582
6833
|
if (!input.control && !input.meta) return;
|
|
@@ -6757,10 +7008,6 @@ function createMainWindow(onTabStateChange) {
|
|
|
6757
7008
|
}
|
|
6758
7009
|
});
|
|
6759
7010
|
sidebarView.setBackgroundColor("#00000000");
|
|
6760
|
-
sidebarView.webContents.on("context-menu", (event, params) => {
|
|
6761
|
-
event.preventDefault();
|
|
6762
|
-
void showSidebarContextMenu(mainWindow, sidebarView, params);
|
|
6763
|
-
});
|
|
6764
7011
|
mainWindow.contentView.addChildView(sidebarView);
|
|
6765
7012
|
const devtoolsPanelView = new electron.WebContentsView({
|
|
6766
7013
|
webPreferences: {
|
|
@@ -6778,8 +7025,9 @@ function createMainWindow(onTabStateChange) {
|
|
|
6778
7025
|
enableClipboardShortcuts(devtoolsPanelView);
|
|
6779
7026
|
const settings2 = loadSettings();
|
|
6780
7027
|
const uiState = {
|
|
6781
|
-
|
|
7028
|
+
sidebarPanelMode: settings2.sidebarPanelMode === "detached" ? "docked" : settings2.sidebarPanelMode,
|
|
6782
7029
|
sidebarWidth: settings2.sidebarWidth,
|
|
7030
|
+
sidebarDetachedBounds: settings2.sidebarDetachedBounds,
|
|
6783
7031
|
focusMode: false,
|
|
6784
7032
|
settingsOpen: false,
|
|
6785
7033
|
devtoolsPanelOpen: false,
|
|
@@ -6797,6 +7045,8 @@ function createMainWindow(onTabStateChange) {
|
|
|
6797
7045
|
});
|
|
6798
7046
|
const state2 = {
|
|
6799
7047
|
mainWindow,
|
|
7048
|
+
sidebarWindow: null,
|
|
7049
|
+
sidebarWindowClosing: false,
|
|
6800
7050
|
chromeView,
|
|
6801
7051
|
sidebarView,
|
|
6802
7052
|
devtoolsPanelView,
|
|
@@ -6806,7 +7056,21 @@ function createMainWindow(onTabStateChange) {
|
|
|
6806
7056
|
mainWindow.on("resize", () => layoutViews(state2));
|
|
6807
7057
|
mainWindow.on("show", () => layoutViews(state2));
|
|
6808
7058
|
mainWindow.on("focus", () => layoutViews(state2));
|
|
7059
|
+
mainWindow.on("closed", () => {
|
|
7060
|
+
closeDetachedSidebarWindow(state2);
|
|
7061
|
+
});
|
|
7062
|
+
sidebarView.webContents.on("context-menu", (event, params) => {
|
|
7063
|
+
event.preventDefault();
|
|
7064
|
+
void showSidebarContextMenu(
|
|
7065
|
+
state2.sidebarWindow ?? state2.mainWindow,
|
|
7066
|
+
sidebarView,
|
|
7067
|
+
params
|
|
7068
|
+
);
|
|
7069
|
+
});
|
|
6809
7070
|
layoutViews(state2);
|
|
7071
|
+
if (settings2.sidebarPanelMode === "detached") {
|
|
7072
|
+
detachSidebar(state2, { relayout: () => layoutViews(state2), getWindowIconPath });
|
|
7073
|
+
}
|
|
6810
7074
|
return state2;
|
|
6811
7075
|
}
|
|
6812
7076
|
function layoutViews(state2) {
|
|
@@ -6820,7 +7084,8 @@ function layoutViews(state2) {
|
|
|
6820
7084
|
} = state2;
|
|
6821
7085
|
const [width, height] = mainWindow.getContentSize();
|
|
6822
7086
|
const chromeHeight = uiState.focusMode ? 0 : CHROME_HEIGHT;
|
|
6823
|
-
const
|
|
7087
|
+
const sidebarAttached = isSidebarAttached(state2);
|
|
7088
|
+
const sidebarWidth = sidebarAttached ? uiState.sidebarWidth : 0;
|
|
6824
7089
|
const devtoolsHeight = uiState.devtoolsPanelOpen ? uiState.devtoolsPanelHeight : 0;
|
|
6825
7090
|
const chromeNeedsFullHeight = uiState.settingsOpen;
|
|
6826
7091
|
if (chromeNeedsFullHeight) {
|
|
@@ -6828,15 +7093,14 @@ function layoutViews(state2) {
|
|
|
6828
7093
|
} else {
|
|
6829
7094
|
chromeView.setBounds({ x: 0, y: 0, width, height: chromeHeight });
|
|
6830
7095
|
}
|
|
6831
|
-
|
|
6832
|
-
if (uiState.sidebarOpen) {
|
|
7096
|
+
if (sidebarAttached) {
|
|
6833
7097
|
sidebarView.setBounds({
|
|
6834
|
-
x: width - sidebarWidth -
|
|
7098
|
+
x: width - sidebarWidth - SIDEBAR_RESIZE_HANDLE_OVERLAP,
|
|
6835
7099
|
y: chromeHeight,
|
|
6836
|
-
width: sidebarWidth +
|
|
7100
|
+
width: sidebarWidth + SIDEBAR_RESIZE_HANDLE_OVERLAP,
|
|
6837
7101
|
height: height - chromeHeight
|
|
6838
7102
|
});
|
|
6839
|
-
} else {
|
|
7103
|
+
} else if (uiState.sidebarPanelMode === "closed") {
|
|
6840
7104
|
sidebarView.setBounds({ x: width, y: 0, width: 0, height: 0 });
|
|
6841
7105
|
}
|
|
6842
7106
|
const contentWidth = width - sidebarWidth;
|
|
@@ -6852,8 +7116,10 @@ function layoutViews(state2) {
|
|
|
6852
7116
|
}
|
|
6853
7117
|
mainWindow.contentView.removeChildView(chromeView);
|
|
6854
7118
|
mainWindow.contentView.addChildView(chromeView);
|
|
6855
|
-
|
|
6856
|
-
|
|
7119
|
+
if (uiState.sidebarPanelMode !== "detached") {
|
|
7120
|
+
mainWindow.contentView.removeChildView(sidebarView);
|
|
7121
|
+
mainWindow.contentView.addChildView(sidebarView);
|
|
7122
|
+
}
|
|
6857
7123
|
mainWindow.contentView.removeChildView(devtoolsPanelView);
|
|
6858
7124
|
mainWindow.contentView.addChildView(devtoolsPanelView);
|
|
6859
7125
|
const activeTab = tabManager.getActiveTab();
|
|
@@ -6870,16 +7136,17 @@ function resizeSidebarViews(state2) {
|
|
|
6870
7136
|
const { mainWindow, sidebarView, devtoolsPanelView, tabManager, uiState } = state2;
|
|
6871
7137
|
const [width, height] = mainWindow.getContentSize();
|
|
6872
7138
|
const chromeHeight = uiState.focusMode ? 0 : CHROME_HEIGHT;
|
|
6873
|
-
const sidebarWidth =
|
|
7139
|
+
const sidebarWidth = isSidebarAttached(state2) ? uiState.sidebarWidth : 0;
|
|
6874
7140
|
const devtoolsHeight = uiState.devtoolsPanelOpen ? uiState.devtoolsPanelHeight : 0;
|
|
6875
|
-
const resizeHandleOverlap = 6;
|
|
6876
7141
|
const contentWidth = width - sidebarWidth;
|
|
6877
|
-
|
|
6878
|
-
|
|
6879
|
-
|
|
6880
|
-
|
|
6881
|
-
|
|
6882
|
-
|
|
7142
|
+
if (uiState.sidebarPanelMode !== "detached") {
|
|
7143
|
+
sidebarView.setBounds({
|
|
7144
|
+
x: width - sidebarWidth - SIDEBAR_RESIZE_HANDLE_OVERLAP,
|
|
7145
|
+
y: chromeHeight,
|
|
7146
|
+
width: sidebarWidth + SIDEBAR_RESIZE_HANDLE_OVERLAP,
|
|
7147
|
+
height: height - chromeHeight
|
|
7148
|
+
});
|
|
7149
|
+
}
|
|
6883
7150
|
if (uiState.devtoolsPanelOpen) {
|
|
6884
7151
|
devtoolsPanelView.setBounds({
|
|
6885
7152
|
x: 0,
|
|
@@ -7020,6 +7287,7 @@ const state$3 = {
|
|
|
7020
7287
|
userDataPath: "",
|
|
7021
7288
|
settingsPath: "",
|
|
7022
7289
|
startupIssues: [],
|
|
7290
|
+
airGapped: isAirGapped(),
|
|
7023
7291
|
mcp: {
|
|
7024
7292
|
configuredPort: 3100,
|
|
7025
7293
|
activePort: null,
|
|
@@ -7047,6 +7315,7 @@ function getRuntimeHealth() {
|
|
|
7047
7315
|
userDataPath: state$3.userDataPath,
|
|
7048
7316
|
settingsPath: state$3.settingsPath,
|
|
7049
7317
|
startupIssues: state$3.startupIssues.map((issue) => ({ ...issue })),
|
|
7318
|
+
airGapped: state$3.airGapped,
|
|
7050
7319
|
mcp: { ...state$3.mcp }
|
|
7051
7320
|
};
|
|
7052
7321
|
}
|
|
@@ -7577,8 +7846,8 @@ function isLoopbackBaseUrl(baseUrl) {
|
|
|
7577
7846
|
}
|
|
7578
7847
|
function resolveAgentToolProfile(config) {
|
|
7579
7848
|
const providerId = config.id;
|
|
7580
|
-
const
|
|
7581
|
-
if (!
|
|
7849
|
+
const isLocalProvider2 = providerId === "ollama" || providerId === "llama_cpp" || providerId === "custom" && isLoopbackBaseUrl(config.baseUrl);
|
|
7850
|
+
if (!isLocalProvider2) return "default";
|
|
7582
7851
|
const sizeInBillions = parseModelSizeInBillions(config.model);
|
|
7583
7852
|
if (sizeInBillions === null) {
|
|
7584
7853
|
return "compact";
|
|
@@ -9379,6 +9648,15 @@ function validateProviderConnection(config, options = { requireModel: true }) {
|
|
|
9379
9648
|
if (!meta) {
|
|
9380
9649
|
return "Selected AI provider is not supported.";
|
|
9381
9650
|
}
|
|
9651
|
+
if (isAirGapped()) {
|
|
9652
|
+
if (meta.id === "custom") {
|
|
9653
|
+
if (!isLocalBaseUrl(normalized.baseUrl)) {
|
|
9654
|
+
return "Air-gapped mode only allows local AI providers. Use a localhost base URL for custom providers.";
|
|
9655
|
+
}
|
|
9656
|
+
} else if (!isLocalProvider(meta.id)) {
|
|
9657
|
+
return `Air-gapped mode only allows local AI providers (Ollama, llama.cpp). ${meta.name} requires internet access.`;
|
|
9658
|
+
}
|
|
9659
|
+
}
|
|
9382
9660
|
if (meta.type !== "codex_oauth" && meta.requiresApiKey && !normalized.apiKey) {
|
|
9383
9661
|
return `${meta.name} requires an API key. Open settings (Ctrl+,) to add one.`;
|
|
9384
9662
|
}
|
|
@@ -11820,7 +12098,7 @@ const TOOL_DEFINITIONS = [
|
|
|
11820
12098
|
{
|
|
11821
12099
|
name: "select_option",
|
|
11822
12100
|
title: "Select Option",
|
|
11823
|
-
description: "Select an option in a <select> dropdown by visible label or option value. Only works on <select> elements
|
|
12101
|
+
description: "Select an option in a <select> dropdown by visible label or option value. Only works on <select> elements. For checkboxes or radio buttons use click instead.",
|
|
11824
12102
|
inputSchema: {
|
|
11825
12103
|
index: zod.z.number().optional().describe("The select element index number"),
|
|
11826
12104
|
selector: zod.z.string().optional().describe("CSS selector as fallback"),
|
|
@@ -11945,7 +12223,7 @@ const TOOL_DEFINITIONS = [
|
|
|
11945
12223
|
"full",
|
|
11946
12224
|
"debug"
|
|
11947
12225
|
]).optional().describe(
|
|
11948
|
-
"Read mode: glance (fastest
|
|
12226
|
+
"Read mode: glance (fastest: viewport snapshot, no JS extraction, ideal for heavy pages), visible_only/results_only/forms_only/summary/text_only for narrow reads, full/debug for the complete page dump"
|
|
11949
12227
|
)
|
|
11950
12228
|
},
|
|
11951
12229
|
tier: 0
|
|
@@ -11953,7 +12231,7 @@ const TOOL_DEFINITIONS = [
|
|
|
11953
12231
|
{
|
|
11954
12232
|
name: "screenshot",
|
|
11955
12233
|
title: "Screenshot",
|
|
11956
|
-
description: "Take a screenshot of the current page
|
|
12234
|
+
description: "Take a screenshot of the current page. Returns the image for visual analysis. Use when you need to verify visual layout, check what's actually rendered on screen, or when text extraction fails on heavy pages.",
|
|
11957
12235
|
inputSchema: {},
|
|
11958
12236
|
tier: 1
|
|
11959
12237
|
},
|
|
@@ -12287,7 +12565,7 @@ const TOOL_DEFINITIONS = [
|
|
|
12287
12565
|
inputSchema: {
|
|
12288
12566
|
index: zod.z.number().optional().describe("Element index of the table to extract"),
|
|
12289
12567
|
selector: zod.z.string().optional().describe(
|
|
12290
|
-
"CSS selector for the table (auto-detected if omitted
|
|
12568
|
+
"CSS selector for the table (auto-detected if omitted; uses first table)"
|
|
12291
12569
|
)
|
|
12292
12570
|
},
|
|
12293
12571
|
tier: 1,
|
|
@@ -26500,6 +26778,12 @@ function getAdBlockDecision(details) {
|
|
|
26500
26778
|
}
|
|
26501
26779
|
let installed = false;
|
|
26502
26780
|
const defaultSessionTabManagers = /* @__PURE__ */ new Set();
|
|
26781
|
+
function getRequestFilterDecision(details, adBlockingEnabled) {
|
|
26782
|
+
if (getAirGapBlockReason(details.url)) {
|
|
26783
|
+
return { cancel: true };
|
|
26784
|
+
}
|
|
26785
|
+
return adBlockingEnabled ? getAdBlockDecision(details) : null;
|
|
26786
|
+
}
|
|
26503
26787
|
function installAdBlocking(tabManager) {
|
|
26504
26788
|
defaultSessionTabManagers.add(tabManager);
|
|
26505
26789
|
if (installed) return;
|
|
@@ -26507,17 +26791,18 @@ function installAdBlocking(tabManager) {
|
|
|
26507
26791
|
electron.session.defaultSession.webRequest.onBeforeRequest((details, callback) => {
|
|
26508
26792
|
const webContentsId = typeof details.webContentsId === "number" ? details.webContentsId : null;
|
|
26509
26793
|
if (webContentsId == null) {
|
|
26510
|
-
callback({});
|
|
26794
|
+
callback(getRequestFilterDecision(details, false) ?? {});
|
|
26511
26795
|
return;
|
|
26512
26796
|
}
|
|
26513
26797
|
const manager = [...defaultSessionTabManagers].find(
|
|
26514
26798
|
(candidate) => candidate.findTabByWebContentsId(webContentsId)
|
|
26515
26799
|
);
|
|
26516
|
-
|
|
26517
|
-
|
|
26518
|
-
|
|
26519
|
-
|
|
26520
|
-
|
|
26800
|
+
callback(
|
|
26801
|
+
getRequestFilterDecision(
|
|
26802
|
+
details,
|
|
26803
|
+
manager?.isAdBlockingEnabledForWebContents(webContentsId) ?? false
|
|
26804
|
+
) ?? {}
|
|
26805
|
+
);
|
|
26521
26806
|
});
|
|
26522
26807
|
}
|
|
26523
26808
|
function unregisterAdBlockingTabManager(tabManager) {
|
|
@@ -26527,14 +26812,15 @@ function installAdBlockingForSession(ses, tabManager) {
|
|
|
26527
26812
|
ses.webRequest.onBeforeRequest((details, callback) => {
|
|
26528
26813
|
const webContentsId = typeof details.webContentsId === "number" ? details.webContentsId : null;
|
|
26529
26814
|
if (webContentsId == null) {
|
|
26530
|
-
callback({});
|
|
26531
|
-
return;
|
|
26532
|
-
}
|
|
26533
|
-
if (!tabManager.isAdBlockingEnabledForWebContents(webContentsId)) {
|
|
26534
|
-
callback({});
|
|
26815
|
+
callback(getRequestFilterDecision(details, false) ?? {});
|
|
26535
26816
|
return;
|
|
26536
26817
|
}
|
|
26537
|
-
callback(
|
|
26818
|
+
callback(
|
|
26819
|
+
getRequestFilterDecision(
|
|
26820
|
+
details,
|
|
26821
|
+
tabManager.isAdBlockingEnabledForWebContents(webContentsId)
|
|
26822
|
+
) ?? {}
|
|
26823
|
+
);
|
|
26538
26824
|
});
|
|
26539
26825
|
}
|
|
26540
26826
|
const filePath$1 = () => path$1.join(electron.app.getPath("userData"), "vessel-downloads.json");
|
|
@@ -27865,6 +28151,12 @@ const logger$7 = createLogger("CodexIPC");
|
|
|
27865
28151
|
function registerCodexHandlers() {
|
|
27866
28152
|
electron.ipcMain.handle(Channels.CODEX_START_AUTH, async (event) => {
|
|
27867
28153
|
assertTrustedIpcSender(event);
|
|
28154
|
+
if (isAirGapped()) {
|
|
28155
|
+
return {
|
|
28156
|
+
ok: false,
|
|
28157
|
+
error: "Codex authentication is unavailable in air-gapped mode."
|
|
28158
|
+
};
|
|
28159
|
+
}
|
|
27868
28160
|
const wc = event.sender;
|
|
27869
28161
|
if (!wc || wc.isDestroyed()) {
|
|
27870
28162
|
return {
|
|
@@ -27975,6 +28267,12 @@ const logger$5 = createLogger("OpenRouterIPC");
|
|
|
27975
28267
|
function registerOpenRouterHandlers(applySettingChange) {
|
|
27976
28268
|
electron.ipcMain.handle(Channels.OPENROUTER_START_AUTH, async (event) => {
|
|
27977
28269
|
assertTrustedIpcSender(event);
|
|
28270
|
+
if (isAirGapped()) {
|
|
28271
|
+
return {
|
|
28272
|
+
ok: false,
|
|
28273
|
+
error: "OpenRouter authentication is unavailable in air-gapped mode."
|
|
28274
|
+
};
|
|
28275
|
+
}
|
|
27978
28276
|
const wc = event.sender;
|
|
27979
28277
|
if (!wc || wc.isDestroyed()) {
|
|
27980
28278
|
return {
|
|
@@ -28019,6 +28317,116 @@ function registerOpenRouterHandlers(applySettingChange) {
|
|
|
28019
28317
|
return { ok: true };
|
|
28020
28318
|
});
|
|
28021
28319
|
}
|
|
28320
|
+
function registerSidebarHandlers(windowState, requireTrusted) {
|
|
28321
|
+
let sidebarResizeRecoveryTimer = null;
|
|
28322
|
+
let sidebarResizeActive = false;
|
|
28323
|
+
const relayout = () => layoutViews(windowState);
|
|
28324
|
+
const clearSidebarResizeRecoveryTimer = () => {
|
|
28325
|
+
if (!sidebarResizeRecoveryTimer) return;
|
|
28326
|
+
clearTimeout(sidebarResizeRecoveryTimer);
|
|
28327
|
+
sidebarResizeRecoveryTimer = null;
|
|
28328
|
+
};
|
|
28329
|
+
const stopSidebarResize = () => {
|
|
28330
|
+
sidebarResizeActive = false;
|
|
28331
|
+
clearSidebarResizeRecoveryTimer();
|
|
28332
|
+
};
|
|
28333
|
+
const restoreSidebarLayoutAfterResize = () => {
|
|
28334
|
+
clearSidebarResizeRecoveryTimer();
|
|
28335
|
+
if (!sidebarResizeActive) return;
|
|
28336
|
+
sidebarResizeActive = false;
|
|
28337
|
+
relayout();
|
|
28338
|
+
};
|
|
28339
|
+
const scheduleSidebarResizeRecovery = () => {
|
|
28340
|
+
clearSidebarResizeRecoveryTimer();
|
|
28341
|
+
sidebarResizeRecoveryTimer = setTimeout(() => {
|
|
28342
|
+
restoreSidebarLayoutAfterResize();
|
|
28343
|
+
}, 1200);
|
|
28344
|
+
};
|
|
28345
|
+
windowState.mainWindow.once("closed", stopSidebarResize);
|
|
28346
|
+
electron.ipcMain.handle(Channels.SIDEBAR_TOGGLE, (event) => {
|
|
28347
|
+
requireTrusted(event);
|
|
28348
|
+
return toggleDockedSidebar(windowState, relayout);
|
|
28349
|
+
});
|
|
28350
|
+
electron.ipcMain.handle(Channels.SIDEBAR_NAVIGATE, (event, tab) => {
|
|
28351
|
+
requireTrusted(event);
|
|
28352
|
+
assertString(tab, "tab");
|
|
28353
|
+
if (windowState.uiState.sidebarPanelMode === "closed") {
|
|
28354
|
+
openDockedSidebar(windowState, relayout);
|
|
28355
|
+
}
|
|
28356
|
+
if (!windowState.sidebarView.webContents.isDestroyed()) {
|
|
28357
|
+
windowState.sidebarView.webContents.send(Channels.SIDEBAR_NAVIGATE, tab);
|
|
28358
|
+
}
|
|
28359
|
+
windowState.sidebarWindow?.focus();
|
|
28360
|
+
return emitSidebarPanelState(windowState);
|
|
28361
|
+
});
|
|
28362
|
+
electron.ipcMain.handle(Channels.SIDEBAR_RESIZE_START, (event) => {
|
|
28363
|
+
requireTrusted(event);
|
|
28364
|
+
if (isSidebarDetached(windowState)) return;
|
|
28365
|
+
sidebarResizeActive = true;
|
|
28366
|
+
clearSidebarResizeRecoveryTimer();
|
|
28367
|
+
const [width, height] = windowState.mainWindow.getContentSize();
|
|
28368
|
+
const chromeHeight = windowState.uiState.focusMode ? 0 : CHROME_HEIGHT;
|
|
28369
|
+
const sidebarWidth = windowState.uiState.sidebarWidth;
|
|
28370
|
+
windowState.sidebarView.setBounds({
|
|
28371
|
+
x: width - sidebarWidth - SIDEBAR_RESIZE_HANDLE_OVERLAP,
|
|
28372
|
+
y: chromeHeight,
|
|
28373
|
+
width: sidebarWidth + SIDEBAR_RESIZE_HANDLE_OVERLAP,
|
|
28374
|
+
height: height - chromeHeight
|
|
28375
|
+
});
|
|
28376
|
+
scheduleSidebarResizeRecovery();
|
|
28377
|
+
});
|
|
28378
|
+
electron.ipcMain.handle(Channels.SIDEBAR_RESIZE, (event, width) => {
|
|
28379
|
+
requireTrusted(event);
|
|
28380
|
+
assertNumber(width, "width");
|
|
28381
|
+
if (isSidebarDetached(windowState)) {
|
|
28382
|
+
return windowState.uiState.sidebarWidth;
|
|
28383
|
+
}
|
|
28384
|
+
const clamped = clampSidebarWidth(width);
|
|
28385
|
+
windowState.uiState.sidebarWidth = clamped;
|
|
28386
|
+
resizeSidebarViews(windowState);
|
|
28387
|
+
emitSidebarPanelState(windowState);
|
|
28388
|
+
return clamped;
|
|
28389
|
+
});
|
|
28390
|
+
electron.ipcMain.handle(Channels.SIDEBAR_RESIZE_COMMIT, (event) => {
|
|
28391
|
+
requireTrusted(event);
|
|
28392
|
+
if (isSidebarDetached(windowState)) return;
|
|
28393
|
+
stopSidebarResize();
|
|
28394
|
+
setSetting("sidebarWidth", windowState.uiState.sidebarWidth);
|
|
28395
|
+
relayout();
|
|
28396
|
+
});
|
|
28397
|
+
electron.ipcMain.handle(Channels.SIDEBAR_POPOUT, (event) => {
|
|
28398
|
+
requireTrusted(event);
|
|
28399
|
+
stopSidebarResize();
|
|
28400
|
+
return detachSidebar(windowState, {
|
|
28401
|
+
relayout,
|
|
28402
|
+
getWindowIconPath
|
|
28403
|
+
});
|
|
28404
|
+
});
|
|
28405
|
+
electron.ipcMain.handle(Channels.SIDEBAR_DOCK, (event) => {
|
|
28406
|
+
requireTrusted(event);
|
|
28407
|
+
stopSidebarResize();
|
|
28408
|
+
return dockSidebar(windowState, { relayout });
|
|
28409
|
+
});
|
|
28410
|
+
electron.ipcMain.on(
|
|
28411
|
+
Channels.RENDERER_VIEW_READY,
|
|
28412
|
+
(event, view) => {
|
|
28413
|
+
requireTrusted(event);
|
|
28414
|
+
if (view !== "sidebar") return;
|
|
28415
|
+
emitSidebarPanelState(windowState);
|
|
28416
|
+
}
|
|
28417
|
+
);
|
|
28418
|
+
electron.ipcMain.handle(Channels.SETTINGS_VISIBILITY, (event, open) => {
|
|
28419
|
+
requireTrusted(event);
|
|
28420
|
+
windowState.uiState.settingsOpen = open;
|
|
28421
|
+
if (open) {
|
|
28422
|
+
closeSidebar(windowState, relayout, "temporary");
|
|
28423
|
+
} else {
|
|
28424
|
+
relayout();
|
|
28425
|
+
emitSidebarPanelState(windowState);
|
|
28426
|
+
}
|
|
28427
|
+
return windowState.uiState.settingsOpen;
|
|
28428
|
+
});
|
|
28429
|
+
}
|
|
28022
28430
|
const SUPPORT_API = process.env.VESSEL_SUPPORT_API || process.env.VESSEL_PREMIUM_API || "https://vesselpremium.quantaintellect.com";
|
|
28023
28431
|
const MAX_FEEDBACK_MESSAGE_LENGTH = 5e3;
|
|
28024
28432
|
const FEEDBACK_REQUEST_TIMEOUT_MS = 15e3;
|
|
@@ -28026,6 +28434,9 @@ function isValidEmail(email) {
|
|
|
28026
28434
|
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
|
|
28027
28435
|
}
|
|
28028
28436
|
async function submitFeedback(payload) {
|
|
28437
|
+
if (isAirGapped()) {
|
|
28438
|
+
return errorResult("Feedback submission is disabled in air-gapped mode.");
|
|
28439
|
+
}
|
|
28029
28440
|
const email = payload.email.trim().toLowerCase();
|
|
28030
28441
|
const message = payload.message.trim();
|
|
28031
28442
|
if (!isValidEmail(email)) {
|
|
@@ -28222,6 +28633,15 @@ function compareVersions(a, b) {
|
|
|
28222
28633
|
async function checkForUpdates() {
|
|
28223
28634
|
const currentVersion = electron.app.getVersion();
|
|
28224
28635
|
const checkedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
28636
|
+
if (isAirGapped()) {
|
|
28637
|
+
return {
|
|
28638
|
+
currentVersion,
|
|
28639
|
+
latestVersion: null,
|
|
28640
|
+
updateAvailable: false,
|
|
28641
|
+
checkedAt,
|
|
28642
|
+
error: "Update checks are disabled in air-gapped mode."
|
|
28643
|
+
};
|
|
28644
|
+
}
|
|
28225
28645
|
try {
|
|
28226
28646
|
const response = await fetch(GITHUB_LATEST_RELEASE_API_URL, {
|
|
28227
28647
|
headers: { accept: "application/vnd.github+json", "user-agent": `Vessel/${currentVersion}` }
|
|
@@ -28252,6 +28672,9 @@ async function checkForUpdates() {
|
|
|
28252
28672
|
}
|
|
28253
28673
|
}
|
|
28254
28674
|
async function openUpdateDownload() {
|
|
28675
|
+
if (isAirGapped()) {
|
|
28676
|
+
throw new Error("Update downloads are unavailable in air-gapped mode.");
|
|
28677
|
+
}
|
|
28255
28678
|
await openExternalAllowlisted(RELEASES_URL, { hosts: ["github.com"] });
|
|
28256
28679
|
}
|
|
28257
28680
|
let activeChatProvider = null;
|
|
@@ -28317,27 +28740,8 @@ function registerIpcHandlers(windowState, runtime2) {
|
|
|
28317
28740
|
requireTrusted(event);
|
|
28318
28741
|
return false;
|
|
28319
28742
|
});
|
|
28320
|
-
let sidebarResizeRecoveryTimer = null;
|
|
28321
|
-
let sidebarResizeActive = false;
|
|
28322
28743
|
let runtimeUpdateTimer = null;
|
|
28323
28744
|
let pendingRuntimeState = null;
|
|
28324
|
-
const clearSidebarResizeRecoveryTimer = () => {
|
|
28325
|
-
if (!sidebarResizeRecoveryTimer) return;
|
|
28326
|
-
clearTimeout(sidebarResizeRecoveryTimer);
|
|
28327
|
-
sidebarResizeRecoveryTimer = null;
|
|
28328
|
-
};
|
|
28329
|
-
const restoreSidebarLayoutAfterResize = () => {
|
|
28330
|
-
clearSidebarResizeRecoveryTimer();
|
|
28331
|
-
if (!sidebarResizeActive) return;
|
|
28332
|
-
sidebarResizeActive = false;
|
|
28333
|
-
layoutViews(windowState);
|
|
28334
|
-
};
|
|
28335
|
-
const scheduleSidebarResizeRecovery = () => {
|
|
28336
|
-
clearSidebarResizeRecoveryTimer();
|
|
28337
|
-
sidebarResizeRecoveryTimer = setTimeout(() => {
|
|
28338
|
-
restoreSidebarLayoutAfterResize();
|
|
28339
|
-
}, 1200);
|
|
28340
|
-
};
|
|
28341
28745
|
const flushRuntimeUpdate = () => {
|
|
28342
28746
|
runtimeUpdateTimer = null;
|
|
28343
28747
|
if (!pendingRuntimeState) return;
|
|
@@ -28652,87 +29056,12 @@ function registerIpcHandlers(windowState, runtime2) {
|
|
|
28652
29056
|
);
|
|
28653
29057
|
}
|
|
28654
29058
|
});
|
|
28655
|
-
electron.ipcMain.handle(Channels.SIDEBAR_TOGGLE, (event) => {
|
|
28656
|
-
requireTrusted(event);
|
|
28657
|
-
windowState.uiState.sidebarOpen = !windowState.uiState.sidebarOpen;
|
|
28658
|
-
layoutViews(windowState);
|
|
28659
|
-
return {
|
|
28660
|
-
open: windowState.uiState.sidebarOpen,
|
|
28661
|
-
width: windowState.uiState.sidebarWidth
|
|
28662
|
-
};
|
|
28663
|
-
});
|
|
28664
|
-
electron.ipcMain.handle(Channels.SIDEBAR_NAVIGATE, (event, tab) => {
|
|
28665
|
-
requireTrusted(event);
|
|
28666
|
-
assertString(tab, "tab");
|
|
28667
|
-
if (!windowState.uiState.sidebarOpen) {
|
|
28668
|
-
windowState.uiState.sidebarOpen = true;
|
|
28669
|
-
layoutViews(windowState);
|
|
28670
|
-
}
|
|
28671
|
-
if (!sidebarView.webContents.isDestroyed()) {
|
|
28672
|
-
sidebarView.webContents.send(Channels.SIDEBAR_NAVIGATE, tab);
|
|
28673
|
-
}
|
|
28674
|
-
return {
|
|
28675
|
-
open: windowState.uiState.sidebarOpen,
|
|
28676
|
-
width: windowState.uiState.sidebarWidth
|
|
28677
|
-
};
|
|
28678
|
-
});
|
|
28679
|
-
electron.ipcMain.handle(Channels.SIDEBAR_RESIZE_START, (event) => {
|
|
28680
|
-
requireTrusted(event);
|
|
28681
|
-
sidebarResizeActive = true;
|
|
28682
|
-
clearSidebarResizeRecoveryTimer();
|
|
28683
|
-
const [width, height] = windowState.mainWindow.getContentSize();
|
|
28684
|
-
const chromeHeight = windowState.uiState.focusMode ? 0 : CHROME_HEIGHT;
|
|
28685
|
-
const sidebarWidth = windowState.uiState.sidebarWidth;
|
|
28686
|
-
const resizeHandleOverlap = 6;
|
|
28687
|
-
windowState.sidebarView.setBounds({
|
|
28688
|
-
x: width - sidebarWidth - resizeHandleOverlap,
|
|
28689
|
-
y: chromeHeight,
|
|
28690
|
-
width: sidebarWidth + resizeHandleOverlap,
|
|
28691
|
-
height: height - chromeHeight
|
|
28692
|
-
});
|
|
28693
|
-
scheduleSidebarResizeRecovery();
|
|
28694
|
-
});
|
|
28695
|
-
electron.ipcMain.handle(Channels.SIDEBAR_RESIZE, (event, width) => {
|
|
28696
|
-
requireTrusted(event);
|
|
28697
|
-
assertNumber(width, "width");
|
|
28698
|
-
const clamped = Math.max(240, Math.min(800, Math.round(width)));
|
|
28699
|
-
windowState.uiState.sidebarWidth = clamped;
|
|
28700
|
-
resizeSidebarViews(windowState);
|
|
28701
|
-
return clamped;
|
|
28702
|
-
});
|
|
28703
|
-
electron.ipcMain.handle(Channels.SIDEBAR_RESIZE_COMMIT, (event) => {
|
|
28704
|
-
requireTrusted(event);
|
|
28705
|
-
sidebarResizeActive = false;
|
|
28706
|
-
clearSidebarResizeRecoveryTimer();
|
|
28707
|
-
setSetting("sidebarWidth", windowState.uiState.sidebarWidth);
|
|
28708
|
-
layoutViews(windowState);
|
|
28709
|
-
});
|
|
28710
|
-
electron.ipcMain.on(
|
|
28711
|
-
Channels.RENDERER_VIEW_READY,
|
|
28712
|
-
(event, view) => {
|
|
28713
|
-
requireTrusted(event);
|
|
28714
|
-
if (view !== "sidebar") return;
|
|
28715
|
-
if (!windowState.uiState.sidebarOpen) {
|
|
28716
|
-
windowState.uiState.sidebarOpen = true;
|
|
28717
|
-
layoutViews(windowState);
|
|
28718
|
-
}
|
|
28719
|
-
}
|
|
28720
|
-
);
|
|
28721
29059
|
electron.ipcMain.handle(Channels.FOCUS_MODE_TOGGLE, (event) => {
|
|
28722
29060
|
requireTrusted(event);
|
|
28723
29061
|
windowState.uiState.focusMode = !windowState.uiState.focusMode;
|
|
28724
29062
|
layoutViews(windowState);
|
|
28725
29063
|
return windowState.uiState.focusMode;
|
|
28726
29064
|
});
|
|
28727
|
-
electron.ipcMain.handle(Channels.SETTINGS_VISIBILITY, (event, open) => {
|
|
28728
|
-
requireTrusted(event);
|
|
28729
|
-
windowState.uiState.settingsOpen = open;
|
|
28730
|
-
if (open) {
|
|
28731
|
-
windowState.uiState.sidebarOpen = false;
|
|
28732
|
-
}
|
|
28733
|
-
layoutViews(windowState);
|
|
28734
|
-
return windowState.uiState.settingsOpen;
|
|
28735
|
-
});
|
|
28736
29065
|
electron.ipcMain.handle(Channels.SETTINGS_GET, (event) => {
|
|
28737
29066
|
requireTrusted(event);
|
|
28738
29067
|
return getRendererSettings();
|
|
@@ -28948,6 +29277,7 @@ function registerIpcHandlers(windowState, runtime2) {
|
|
|
28948
29277
|
registerWindowControlHandlers(mainWindow);
|
|
28949
29278
|
registerCodexHandlers();
|
|
28950
29279
|
registerOpenRouterHandlers(applySettingChange);
|
|
29280
|
+
registerSidebarHandlers(windowState, requireTrusted);
|
|
28951
29281
|
electron.ipcMain.handle(Channels.AUTOMATION_GET_INSTALLED, (event) => {
|
|
28952
29282
|
requireTrusted(event);
|
|
28953
29283
|
return getInstalledKits();
|