@quanta-intellect/vessel-browser 0.1.69 → 0.1.71
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/out/main/index.js
CHANGED
|
@@ -77,7 +77,7 @@ const defaults = {
|
|
|
77
77
|
};
|
|
78
78
|
const SAVE_DEBOUNCE_MS$6 = 150;
|
|
79
79
|
const CHAT_PROVIDER_SECRET_FILENAME = "vessel-chat-provider-secret";
|
|
80
|
-
const logger$
|
|
80
|
+
const logger$k = createLogger("Settings");
|
|
81
81
|
const SETTABLE_KEYS = new Set(Object.keys(defaults));
|
|
82
82
|
let settings = null;
|
|
83
83
|
let settingsIssues = [];
|
|
@@ -223,7 +223,7 @@ function persistNow() {
|
|
|
223
223
|
getSettingsPath(),
|
|
224
224
|
JSON.stringify(buildPersistedSettings(settings), null, 2)
|
|
225
225
|
)
|
|
226
|
-
).catch((err) => logger$
|
|
226
|
+
).catch((err) => logger$k.error("Failed to save settings:", err));
|
|
227
227
|
}
|
|
228
228
|
function saveSettings() {
|
|
229
229
|
saveDirty = true;
|
|
@@ -327,7 +327,7 @@ function assertPermittedNavigationURL(url) {
|
|
|
327
327
|
}
|
|
328
328
|
const MAX_CUSTOM_HISTORY = 50;
|
|
329
329
|
const READER_MODE_DATA_URL_PREFIX = "data:text/html;charset=utf-8,";
|
|
330
|
-
const logger$
|
|
330
|
+
const logger$j = createLogger("Tab");
|
|
331
331
|
class Tab {
|
|
332
332
|
id;
|
|
333
333
|
view;
|
|
@@ -368,7 +368,7 @@ class Tab {
|
|
|
368
368
|
guardedLoadURL(url, options) {
|
|
369
369
|
const blockReason = this.getNavigationBlockReason(url);
|
|
370
370
|
if (blockReason) {
|
|
371
|
-
logger$
|
|
371
|
+
logger$j.warn(blockReason);
|
|
372
372
|
return blockReason;
|
|
373
373
|
}
|
|
374
374
|
void this.view.webContents.loadURL(url, options);
|
|
@@ -383,14 +383,16 @@ class Tab {
|
|
|
383
383
|
this.onHighlightSelection = options?.onHighlightSelection;
|
|
384
384
|
this.onHighlightRemove = options?.onHighlightRemove;
|
|
385
385
|
this.onHighlightRecolor = options?.onHighlightRecolor;
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
386
|
+
const webPreferences = {
|
|
387
|
+
preload: path.join(__dirname, "../preload/content-script.js"),
|
|
388
|
+
sandbox: true,
|
|
389
|
+
contextIsolation: true,
|
|
390
|
+
nodeIntegration: false
|
|
391
|
+
};
|
|
392
|
+
if (options?.sessionPartition) {
|
|
393
|
+
webPreferences.session = electron.session.fromPartition(options.sessionPartition);
|
|
394
|
+
}
|
|
395
|
+
this.view = new electron.WebContentsView({ webPreferences });
|
|
394
396
|
const initialUrl = url || "about:blank";
|
|
395
397
|
this._state = {
|
|
396
398
|
id,
|
|
@@ -404,11 +406,26 @@ class Tab {
|
|
|
404
406
|
adBlockingEnabled: options?.adBlockingEnabled ?? true,
|
|
405
407
|
role: options?.role
|
|
406
408
|
};
|
|
407
|
-
this.view.webContents.on("before-input-event", (
|
|
409
|
+
this.view.webContents.on("before-input-event", (event, input) => {
|
|
408
410
|
if (!input.control && !input.meta) return;
|
|
409
411
|
if (input.type !== "keyDown") return;
|
|
410
412
|
const key = input.key.toLowerCase();
|
|
411
413
|
const wc = this.view.webContents;
|
|
414
|
+
if (key === "+" || key === "=") {
|
|
415
|
+
this.zoomIn();
|
|
416
|
+
event.preventDefault();
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
if (key === "-") {
|
|
420
|
+
this.zoomOut();
|
|
421
|
+
event.preventDefault();
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
if (key === "0") {
|
|
425
|
+
this.zoomReset();
|
|
426
|
+
event.preventDefault();
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
412
429
|
if (key === "c") wc.copy();
|
|
413
430
|
else if (key === "v") wc.paste();
|
|
414
431
|
else if (key === "x") wc.cut();
|
|
@@ -429,7 +446,7 @@ class Tab {
|
|
|
429
446
|
wc.setWindowOpenHandler(({ url, disposition }) => {
|
|
430
447
|
const error = this.getNavigationBlockReason(url);
|
|
431
448
|
if (error) {
|
|
432
|
-
logger$
|
|
449
|
+
logger$j.warn(error);
|
|
433
450
|
return { action: "deny" };
|
|
434
451
|
}
|
|
435
452
|
this.onOpenUrl?.({
|
|
@@ -443,7 +460,7 @@ class Tab {
|
|
|
443
460
|
const error = this.getNavigationBlockReason(url);
|
|
444
461
|
if (!error) return;
|
|
445
462
|
event.preventDefault();
|
|
446
|
-
logger$
|
|
463
|
+
logger$j.warn(`${context}: ${error}`);
|
|
447
464
|
};
|
|
448
465
|
wc.on("will-navigate", (event, url) => {
|
|
449
466
|
blockNavigation(event, url, "Blocked top-level navigation");
|
|
@@ -507,7 +524,7 @@ class Tab {
|
|
|
507
524
|
::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.12); border-radius: 999px; }
|
|
508
525
|
::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,0.22); }
|
|
509
526
|
::-webkit-scrollbar-corner { background: transparent; }
|
|
510
|
-
`).catch((err) => logger$
|
|
527
|
+
`).catch((err) => logger$j.warn("Failed to inject scrollbar CSS:", err));
|
|
511
528
|
});
|
|
512
529
|
wc.on("page-favicon-updated", (_, favicons) => {
|
|
513
530
|
this._state.favicon = favicons[0] || "";
|
|
@@ -530,7 +547,7 @@ class Tab {
|
|
|
530
547
|
).then((highlightedText) => {
|
|
531
548
|
this.buildContextMenu(wc, params, highlightedText.trim());
|
|
532
549
|
}).catch((err) => {
|
|
533
|
-
logger$
|
|
550
|
+
logger$j.warn("Failed to inspect highlighted text for context menu:", err);
|
|
534
551
|
this.buildContextMenu(wc, params, "");
|
|
535
552
|
});
|
|
536
553
|
});
|
|
@@ -676,6 +693,19 @@ class Tab {
|
|
|
676
693
|
reload() {
|
|
677
694
|
this.view.webContents.reload();
|
|
678
695
|
}
|
|
696
|
+
zoomIn() {
|
|
697
|
+
const wc = this.view.webContents;
|
|
698
|
+
const level = wc.getZoomLevel();
|
|
699
|
+
wc.setZoomLevel(level + 0.5);
|
|
700
|
+
}
|
|
701
|
+
zoomOut() {
|
|
702
|
+
const wc = this.view.webContents;
|
|
703
|
+
const level = wc.getZoomLevel();
|
|
704
|
+
wc.setZoomLevel(level - 0.5);
|
|
705
|
+
}
|
|
706
|
+
zoomReset() {
|
|
707
|
+
this.view.webContents.setZoomLevel(0);
|
|
708
|
+
}
|
|
679
709
|
setAdBlockingEnabled(enabled) {
|
|
680
710
|
if (this._state.adBlockingEnabled === enabled) return false;
|
|
681
711
|
this._state.adBlockingEnabled = enabled;
|
|
@@ -761,7 +791,7 @@ class Tab {
|
|
|
761
791
|
document.addEventListener('mouseup', window.__vesselHighlightHandler);
|
|
762
792
|
}
|
|
763
793
|
})()
|
|
764
|
-
`).catch((err) => logger$
|
|
794
|
+
`).catch((err) => logger$j.warn("Failed to inject highlight listener:", err));
|
|
765
795
|
} else {
|
|
766
796
|
void wc.executeJavaScript(`
|
|
767
797
|
(function() {
|
|
@@ -772,7 +802,7 @@ class Tab {
|
|
|
772
802
|
delete window.__vesselHighlightHandler;
|
|
773
803
|
}
|
|
774
804
|
})()
|
|
775
|
-
`).catch((err) => logger$
|
|
805
|
+
`).catch((err) => logger$j.warn("Failed to remove highlight listener:", err));
|
|
776
806
|
}
|
|
777
807
|
}
|
|
778
808
|
get webContentsId() {
|
|
@@ -783,7 +813,7 @@ class Tab {
|
|
|
783
813
|
this.view.webContents.close();
|
|
784
814
|
}
|
|
785
815
|
}
|
|
786
|
-
const logger$
|
|
816
|
+
const logger$i = createLogger("JsonPersistence");
|
|
787
817
|
function canUseSafeStorage() {
|
|
788
818
|
try {
|
|
789
819
|
return electron.safeStorage.isEncryptionAvailable();
|
|
@@ -848,7 +878,7 @@ function createDebouncedJsonPersistence({
|
|
|
848
878
|
data,
|
|
849
879
|
typeof data === "string" ? { encoding: "utf-8", mode: 384 } : { mode: 384 }
|
|
850
880
|
)
|
|
851
|
-
).catch((err) => logger$
|
|
881
|
+
).catch((err) => logger$i.error(`Failed to save ${logLabel}:`, err));
|
|
852
882
|
};
|
|
853
883
|
const schedule = () => {
|
|
854
884
|
saveDirty2 = true;
|
|
@@ -2336,13 +2366,7 @@ function destroySession(tabId) {
|
|
|
2336
2366
|
sessions.delete(tabId);
|
|
2337
2367
|
}
|
|
2338
2368
|
}
|
|
2339
|
-
|
|
2340
|
-
for (const session of sessions.values()) {
|
|
2341
|
-
session.destroy();
|
|
2342
|
-
}
|
|
2343
|
-
sessions.clear();
|
|
2344
|
-
}
|
|
2345
|
-
const logger$g = createLogger("TabManager");
|
|
2369
|
+
const logger$h = createLogger("TabManager");
|
|
2346
2370
|
class TabManager {
|
|
2347
2371
|
tabs = /* @__PURE__ */ new Map();
|
|
2348
2372
|
order = [];
|
|
@@ -2351,9 +2375,15 @@ class TabManager {
|
|
|
2351
2375
|
onStateChange;
|
|
2352
2376
|
highlightCaptureCallback = null;
|
|
2353
2377
|
pageLoadCallback = null;
|
|
2354
|
-
|
|
2378
|
+
closedTabs = [];
|
|
2379
|
+
MAX_CLOSED_TABS = 20;
|
|
2380
|
+
isPrivate;
|
|
2381
|
+
sessionPartition;
|
|
2382
|
+
constructor(window2, onStateChange, options) {
|
|
2355
2383
|
this.window = window2;
|
|
2356
2384
|
this.onStateChange = onStateChange;
|
|
2385
|
+
this.isPrivate = options?.isPrivate ?? false;
|
|
2386
|
+
this.sessionPartition = options?.sessionPartition ?? (this.isPrivate ? "private-mode" : void 0);
|
|
2357
2387
|
}
|
|
2358
2388
|
onPageLoad(cb) {
|
|
2359
2389
|
this.pageLoadCallback = cb;
|
|
@@ -2364,12 +2394,15 @@ class TabManager {
|
|
|
2364
2394
|
const tab = new Tab(id, url, () => this.broadcastState(), {
|
|
2365
2395
|
adBlockingEnabled: options?.adBlockingEnabled,
|
|
2366
2396
|
parentWindow: this.window,
|
|
2397
|
+
sessionPartition: this.sessionPartition,
|
|
2367
2398
|
onOpenUrl: ({ url: requestedUrl, background: background2, adBlockingEnabled }) => {
|
|
2368
2399
|
this.createTab(requestedUrl, { background: background2, adBlockingEnabled });
|
|
2369
2400
|
},
|
|
2370
2401
|
onPageLoad: (pageUrl, wc) => {
|
|
2371
2402
|
this.reapplyHighlights(pageUrl, wc);
|
|
2372
|
-
|
|
2403
|
+
if (!this.isPrivate) {
|
|
2404
|
+
addEntry$1(pageUrl, wc.getTitle());
|
|
2405
|
+
}
|
|
2373
2406
|
this.pageLoadCallback?.(pageUrl, wc);
|
|
2374
2407
|
},
|
|
2375
2408
|
onHighlightSelection: (wc) => this.captureHighlightFromPage(wc),
|
|
@@ -2401,6 +2434,14 @@ class TabManager {
|
|
|
2401
2434
|
closeTab(id) {
|
|
2402
2435
|
const tab = this.tabs.get(id);
|
|
2403
2436
|
if (!tab) return;
|
|
2437
|
+
this.closedTabs.push({
|
|
2438
|
+
url: tab.state.url,
|
|
2439
|
+
title: tab.state.title,
|
|
2440
|
+
adBlockingEnabled: tab.state.adBlockingEnabled
|
|
2441
|
+
});
|
|
2442
|
+
if (this.closedTabs.length > this.MAX_CLOSED_TABS) {
|
|
2443
|
+
this.closedTabs.shift();
|
|
2444
|
+
}
|
|
2404
2445
|
const wcId = tab.webContentsId;
|
|
2405
2446
|
if (wcId !== void 0) {
|
|
2406
2447
|
this.lastReapply.delete(wcId);
|
|
@@ -2434,6 +2475,25 @@ class TabManager {
|
|
|
2434
2475
|
reloadTab(id) {
|
|
2435
2476
|
this.tabs.get(id)?.reload();
|
|
2436
2477
|
}
|
|
2478
|
+
zoomIn(id) {
|
|
2479
|
+
this.tabs.get(id)?.zoomIn();
|
|
2480
|
+
}
|
|
2481
|
+
zoomOut(id) {
|
|
2482
|
+
this.tabs.get(id)?.zoomOut();
|
|
2483
|
+
}
|
|
2484
|
+
zoomReset(id) {
|
|
2485
|
+
this.tabs.get(id)?.zoomReset();
|
|
2486
|
+
}
|
|
2487
|
+
reopenClosedTab() {
|
|
2488
|
+
const last = this.closedTabs.pop();
|
|
2489
|
+
if (!last) return null;
|
|
2490
|
+
return this.createTab(last.url, { adBlockingEnabled: last.adBlockingEnabled });
|
|
2491
|
+
}
|
|
2492
|
+
duplicateTab(id) {
|
|
2493
|
+
const tab = this.tabs.get(id);
|
|
2494
|
+
if (!tab) return null;
|
|
2495
|
+
return this.createTab(tab.state.url, { adBlockingEnabled: tab.state.adBlockingEnabled });
|
|
2496
|
+
}
|
|
2437
2497
|
getActiveTab() {
|
|
2438
2498
|
return this.activeTabId ? this.tabs.get(this.activeTabId) : void 0;
|
|
2439
2499
|
}
|
|
@@ -2507,10 +2567,10 @@ class TabManager {
|
|
|
2507
2567
|
return ids;
|
|
2508
2568
|
}
|
|
2509
2569
|
destroyAllTabs() {
|
|
2510
|
-
|
|
2511
|
-
for (const id of this.order) {
|
|
2570
|
+
for (const id of [...this.order]) {
|
|
2512
2571
|
const tab = this.tabs.get(id);
|
|
2513
2572
|
if (!tab) continue;
|
|
2573
|
+
destroySession(id);
|
|
2514
2574
|
this.window.contentView.removeChildView(tab.view);
|
|
2515
2575
|
tab.destroy();
|
|
2516
2576
|
}
|
|
@@ -2536,7 +2596,7 @@ class TabManager {
|
|
|
2536
2596
|
}));
|
|
2537
2597
|
if (entries.length > 0) {
|
|
2538
2598
|
void highlightBatchOnPage(wc, entries).catch(
|
|
2539
|
-
(err) => logger$
|
|
2599
|
+
(err) => logger$h.warn("Failed to batch highlight:", err)
|
|
2540
2600
|
);
|
|
2541
2601
|
}
|
|
2542
2602
|
}
|
|
@@ -2558,12 +2618,12 @@ class TabManager {
|
|
|
2558
2618
|
const result = await captureSelectionHighlight(wc);
|
|
2559
2619
|
if (result.success && result.text) {
|
|
2560
2620
|
await highlightOnPage(wc, null, result.text, void 0, void 0, "yellow").catch(
|
|
2561
|
-
(err) => logger$
|
|
2621
|
+
(err) => logger$h.warn("Failed to capture highlight:", err)
|
|
2562
2622
|
);
|
|
2563
2623
|
}
|
|
2564
2624
|
this.highlightCaptureCallback?.(result);
|
|
2565
2625
|
} catch (err) {
|
|
2566
|
-
logger$
|
|
2626
|
+
logger$h.warn("Failed to capture highlight from page:", err);
|
|
2567
2627
|
this.highlightCaptureCallback?.({
|
|
2568
2628
|
success: false,
|
|
2569
2629
|
message: "Could not capture selection"
|
|
@@ -2588,7 +2648,7 @@ class TabManager {
|
|
|
2588
2648
|
void this.removeHighlightMarksForText(wc, text);
|
|
2589
2649
|
}
|
|
2590
2650
|
} catch (err) {
|
|
2591
|
-
logger$
|
|
2651
|
+
logger$h.warn("Failed to remove highlight from matching tab:", err);
|
|
2592
2652
|
}
|
|
2593
2653
|
}
|
|
2594
2654
|
this.highlightCaptureCallback?.({
|
|
@@ -2619,12 +2679,12 @@ class TabManager {
|
|
|
2619
2679
|
void 0,
|
|
2620
2680
|
color
|
|
2621
2681
|
).catch(
|
|
2622
|
-
(err) => logger$
|
|
2682
|
+
(err) => logger$h.warn("Failed to update highlight color:", err)
|
|
2623
2683
|
);
|
|
2624
2684
|
});
|
|
2625
2685
|
}
|
|
2626
2686
|
} catch (err) {
|
|
2627
|
-
logger$
|
|
2687
|
+
logger$h.warn("Failed to iterate highlights for color change:", err);
|
|
2628
2688
|
}
|
|
2629
2689
|
}
|
|
2630
2690
|
this.highlightCaptureCallback?.({
|
|
@@ -2646,7 +2706,7 @@ class TabManager {
|
|
|
2646
2706
|
});
|
|
2647
2707
|
})()`
|
|
2648
2708
|
).catch(
|
|
2649
|
-
(err) => logger$
|
|
2709
|
+
(err) => logger$h.warn("Failed to remove highlight marks:", err)
|
|
2650
2710
|
);
|
|
2651
2711
|
}
|
|
2652
2712
|
broadcastState() {
|
|
@@ -2733,6 +2793,17 @@ const Channels = {
|
|
|
2733
2793
|
DEVTOOLS_PANEL_RESIZE: "devtools-panel:resize",
|
|
2734
2794
|
// Ad blocking
|
|
2735
2795
|
TAB_TOGGLE_AD_BLOCK: "tab:toggle-ad-block",
|
|
2796
|
+
// Zoom
|
|
2797
|
+
TAB_ZOOM_IN: "tab:zoom-in",
|
|
2798
|
+
TAB_ZOOM_OUT: "tab:zoom-out",
|
|
2799
|
+
TAB_ZOOM_RESET: "tab:zoom-reset",
|
|
2800
|
+
// Closed tabs / duplication
|
|
2801
|
+
TAB_REOPEN_CLOSED: "tab:reopen-closed",
|
|
2802
|
+
TAB_DUPLICATE: "tab:duplicate",
|
|
2803
|
+
TAB_CONTEXT_MENU: "tab:context-menu",
|
|
2804
|
+
// Private browsing
|
|
2805
|
+
OPEN_PRIVATE_WINDOW: "private:open-window",
|
|
2806
|
+
IS_PRIVATE_MODE: "private:is-private",
|
|
2736
2807
|
// Find in page
|
|
2737
2808
|
FIND_IN_PAGE_START: "find:start",
|
|
2738
2809
|
FIND_IN_PAGE_NEXT: "find:next",
|
|
@@ -3750,7 +3821,7 @@ function errorResult(error, value) {
|
|
|
3750
3821
|
function getErrorMessage(error, fallback = "Unknown error") {
|
|
3751
3822
|
return error instanceof Error && error.message ? error.message : fallback;
|
|
3752
3823
|
}
|
|
3753
|
-
const logger$
|
|
3824
|
+
const logger$g = createLogger("Premium");
|
|
3754
3825
|
const VERIFICATION_API = process.env.VESSEL_PREMIUM_API || "https://vesselpremium.quantaintellect.com";
|
|
3755
3826
|
const FREE_TOOL_ITERATION_LIMIT = 50;
|
|
3756
3827
|
const REVALIDATION_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -3863,7 +3934,7 @@ async function verifySubscription(identifier) {
|
|
|
3863
3934
|
});
|
|
3864
3935
|
if (!res.ok) {
|
|
3865
3936
|
const detail = await readApiErrorDetail(res);
|
|
3866
|
-
logger$
|
|
3937
|
+
logger$g.warn(
|
|
3867
3938
|
"Verification API returned a non-OK status:",
|
|
3868
3939
|
res.status,
|
|
3869
3940
|
detail
|
|
@@ -3882,7 +3953,7 @@ async function verifySubscription(identifier) {
|
|
|
3882
3953
|
setSetting("premium", updated);
|
|
3883
3954
|
return updated;
|
|
3884
3955
|
} catch (err) {
|
|
3885
|
-
logger$
|
|
3956
|
+
logger$g.warn("Verification failed:", err);
|
|
3886
3957
|
return current;
|
|
3887
3958
|
}
|
|
3888
3959
|
}
|
|
@@ -4455,7 +4526,7 @@ const EXTRACT_TIMEOUT_MAX_MS = 2e4;
|
|
|
4455
4526
|
const MUTATION_CAPTURE_INTERVAL_MS = 5e3;
|
|
4456
4527
|
const MUTATION_SETTLE_AFTER_MS = 1500;
|
|
4457
4528
|
const AGENT_STREAM_IDLE_TIMEOUT_MS = 3e4;
|
|
4458
|
-
const logger$
|
|
4529
|
+
const logger$f = createLogger("Extractor");
|
|
4459
4530
|
const EMPTY_PAGE_CONTENT = {
|
|
4460
4531
|
title: "",
|
|
4461
4532
|
content: "",
|
|
@@ -5205,7 +5276,7 @@ async function executeScript(webContents, script) {
|
|
|
5205
5276
|
})
|
|
5206
5277
|
]);
|
|
5207
5278
|
} catch (err) {
|
|
5208
|
-
logger$
|
|
5279
|
+
logger$f.warn("Failed to execute page script:", err);
|
|
5209
5280
|
return null;
|
|
5210
5281
|
} finally {
|
|
5211
5282
|
if (timer) {
|
|
@@ -5312,7 +5383,7 @@ async function estimateExtractionTimeout(webContents) {
|
|
|
5312
5383
|
return EXTRACT_TIMEOUT_BASE_MS + extra;
|
|
5313
5384
|
}
|
|
5314
5385
|
} catch (err) {
|
|
5315
|
-
logger$
|
|
5386
|
+
logger$f.warn("Failed to estimate extraction timeout, using base timeout:", err);
|
|
5316
5387
|
}
|
|
5317
5388
|
return EXTRACT_TIMEOUT_BASE_MS;
|
|
5318
5389
|
}
|
|
@@ -5623,7 +5694,7 @@ function enableClipboardShortcuts(view) {
|
|
|
5623
5694
|
}
|
|
5624
5695
|
});
|
|
5625
5696
|
}
|
|
5626
|
-
const CHROME_HEIGHT = 110;
|
|
5697
|
+
const CHROME_HEIGHT$1 = 110;
|
|
5627
5698
|
const DEFAULT_DEVTOOLS_PANEL_HEIGHT = 250;
|
|
5628
5699
|
const MIN_DEVTOOLS_PANEL = 120;
|
|
5629
5700
|
const MAX_DEVTOOLS_PANEL = 600;
|
|
@@ -5838,7 +5909,7 @@ function layoutViews(state2) {
|
|
|
5838
5909
|
uiState
|
|
5839
5910
|
} = state2;
|
|
5840
5911
|
const [width, height] = mainWindow.getContentSize();
|
|
5841
|
-
const chromeHeight = uiState.focusMode ? 0 : CHROME_HEIGHT;
|
|
5912
|
+
const chromeHeight = uiState.focusMode ? 0 : CHROME_HEIGHT$1;
|
|
5842
5913
|
const sidebarWidth = uiState.sidebarOpen ? uiState.sidebarWidth : 0;
|
|
5843
5914
|
const devtoolsHeight = uiState.devtoolsPanelOpen ? uiState.devtoolsPanelHeight : 0;
|
|
5844
5915
|
const chromeNeedsFullHeight = uiState.settingsOpen;
|
|
@@ -5888,7 +5959,7 @@ function layoutViews(state2) {
|
|
|
5888
5959
|
function resizeSidebarViews(state2) {
|
|
5889
5960
|
const { mainWindow, sidebarView, devtoolsPanelView, tabManager, uiState } = state2;
|
|
5890
5961
|
const [width, height] = mainWindow.getContentSize();
|
|
5891
|
-
const chromeHeight = uiState.focusMode ? 0 : CHROME_HEIGHT;
|
|
5962
|
+
const chromeHeight = uiState.focusMode ? 0 : CHROME_HEIGHT$1;
|
|
5892
5963
|
const sidebarWidth = uiState.sidebarOpen ? uiState.sidebarWidth : 0;
|
|
5893
5964
|
const devtoolsHeight = uiState.devtoolsPanelOpen ? uiState.devtoolsPanelHeight : 0;
|
|
5894
5965
|
const resizeHandleOverlap = 6;
|
|
@@ -6618,7 +6689,7 @@ const MAX_MCP_NAV_CONTENT_LENGTH = 3e4;
|
|
|
6618
6689
|
const MAX_AGENT_DEBUG_CONTENT_LENGTH = 2e4;
|
|
6619
6690
|
const LLAMA_CPP_MIN_CTX_TOKENS = 16384;
|
|
6620
6691
|
const LLAMA_CPP_RECOMMENDED_CTX_TOKENS = 32768;
|
|
6621
|
-
const logger$
|
|
6692
|
+
const logger$e = createLogger("OpenAIProvider");
|
|
6622
6693
|
function shouldDebugAgentLoop() {
|
|
6623
6694
|
const value = process.env.VESSEL_DEBUG_AGENT_LOOP;
|
|
6624
6695
|
return value === "1" || value === "true";
|
|
@@ -7119,9 +7190,9 @@ function resolveToolCallName(rawName, args, availableToolNames) {
|
|
|
7119
7190
|
function logAgentLoopDebug(payload) {
|
|
7120
7191
|
if (!shouldDebugAgentLoop()) return;
|
|
7121
7192
|
try {
|
|
7122
|
-
logger$
|
|
7193
|
+
logger$e.info(`[agent-debug] ${JSON.stringify(payload)}`);
|
|
7123
7194
|
} catch (err) {
|
|
7124
|
-
logger$
|
|
7195
|
+
logger$e.warn("Failed to serialize debug payload:", err);
|
|
7125
7196
|
}
|
|
7126
7197
|
}
|
|
7127
7198
|
function recoverTextEncodedToolCalls(text, availableToolNames) {
|
|
@@ -7755,7 +7826,7 @@ function createProvider(config) {
|
|
|
7755
7826
|
return new OpenAICompatProvider(normalized);
|
|
7756
7827
|
}
|
|
7757
7828
|
const require$1 = node_module.createRequire(require("url").pathToFileURL(__filename).href);
|
|
7758
|
-
const logger$
|
|
7829
|
+
const logger$d = createLogger("DevTrace");
|
|
7759
7830
|
let cachedFactory;
|
|
7760
7831
|
function createNoopTraceSession() {
|
|
7761
7832
|
return {
|
|
@@ -7788,7 +7859,7 @@ function loadLocalFactory() {
|
|
|
7788
7859
|
return cachedFactory;
|
|
7789
7860
|
}
|
|
7790
7861
|
} catch (err) {
|
|
7791
|
-
logger$
|
|
7862
|
+
logger$d.warn("Failed to load local trace logger:", err);
|
|
7792
7863
|
}
|
|
7793
7864
|
}
|
|
7794
7865
|
return cachedFactory;
|
|
@@ -11603,7 +11674,7 @@ function formatDeadLinkMessage(label, result) {
|
|
|
11603
11674
|
const status = result.statusCode ? `HTTP ${result.statusCode}` : "dead link";
|
|
11604
11675
|
return `Skipped stale link "${label}" because ${destination} returned ${status}. Try a different link or URL instead.`;
|
|
11605
11676
|
}
|
|
11606
|
-
const logger$
|
|
11677
|
+
const logger$c = createLogger("Screenshot");
|
|
11607
11678
|
const SCREENSHOT_RETRY_COUNT = 3;
|
|
11608
11679
|
const SCREENSHOT_RETRY_BASE_DELAY_MS = 120;
|
|
11609
11680
|
async function captureScreenshot(wc) {
|
|
@@ -11625,7 +11696,7 @@ async function captureScreenshot(wc) {
|
|
|
11625
11696
|
}
|
|
11626
11697
|
}
|
|
11627
11698
|
} catch (err) {
|
|
11628
|
-
logger$
|
|
11699
|
+
logger$c.debug(
|
|
11629
11700
|
`capturePage attempt ${attempt + 1} failed; retrying if attempts remain.`,
|
|
11630
11701
|
getErrorMessage(err)
|
|
11631
11702
|
);
|
|
@@ -12499,7 +12570,7 @@ function buildHuggingFaceSearchShortcut(currentUrl, rawQuery) {
|
|
|
12499
12570
|
appliedFilters
|
|
12500
12571
|
};
|
|
12501
12572
|
}
|
|
12502
|
-
const logger$
|
|
12573
|
+
const logger$b = createLogger("PageActions");
|
|
12503
12574
|
function getBookmarkMetadataFromArgs(args) {
|
|
12504
12575
|
return normalizeBookmarkMetadata({
|
|
12505
12576
|
intent: args.intent ?? args.intent,
|
|
@@ -12685,7 +12756,7 @@ async function executePageScript(wc, script, options) {
|
|
|
12685
12756
|
return result;
|
|
12686
12757
|
} catch (err) {
|
|
12687
12758
|
const label = options?.label ? ` (${options.label})` : "";
|
|
12688
|
-
logger$
|
|
12759
|
+
logger$b.warn(`Failed to execute page script${label}:`, err);
|
|
12689
12760
|
return null;
|
|
12690
12761
|
} finally {
|
|
12691
12762
|
if (timer) {
|
|
@@ -12786,7 +12857,7 @@ Search results snapshot:
|
|
|
12786
12857
|
${truncated}`;
|
|
12787
12858
|
}
|
|
12788
12859
|
} catch (err) {
|
|
12789
|
-
logger$
|
|
12860
|
+
logger$b.warn("Failed to build post-search summary, falling back to nav summary:", err);
|
|
12790
12861
|
}
|
|
12791
12862
|
const fallback = await getPostNavSummary(wc);
|
|
12792
12863
|
return fallback ? `${fallback}
|
|
@@ -12809,7 +12880,7 @@ Page snapshot after navigation:
|
|
|
12809
12880
|
${truncated}`;
|
|
12810
12881
|
}
|
|
12811
12882
|
} catch (err) {
|
|
12812
|
-
logger$
|
|
12883
|
+
logger$b.warn("Failed to build post-click navigation summary:", err);
|
|
12813
12884
|
}
|
|
12814
12885
|
return "";
|
|
12815
12886
|
}
|
|
@@ -13303,7 +13374,7 @@ async function restoreLocaleSnapshot(wc, snapshot) {
|
|
|
13303
13374
|
}
|
|
13304
13375
|
}
|
|
13305
13376
|
} catch (err) {
|
|
13306
|
-
logger$
|
|
13377
|
+
logger$b.warn("Failed to restore locale via history navigation, trying URL reload fallback:", err);
|
|
13307
13378
|
}
|
|
13308
13379
|
if (snapshot.url && snapshot.url !== wc.getURL()) {
|
|
13309
13380
|
try {
|
|
@@ -13312,7 +13383,7 @@ async function restoreLocaleSnapshot(wc, snapshot) {
|
|
|
13312
13383
|
await waitForLoad(wc, 3e3);
|
|
13313
13384
|
return;
|
|
13314
13385
|
} catch (err) {
|
|
13315
|
-
logger$
|
|
13386
|
+
logger$b.warn("Failed to restore locale via safe URL load, trying page reload fallback:", err);
|
|
13316
13387
|
}
|
|
13317
13388
|
}
|
|
13318
13389
|
if (snapshot.url) {
|
|
@@ -13320,7 +13391,7 @@ async function restoreLocaleSnapshot(wc, snapshot) {
|
|
|
13320
13391
|
await wc.reload();
|
|
13321
13392
|
await waitForLoad(wc, 3e3);
|
|
13322
13393
|
} catch (err) {
|
|
13323
|
-
logger$
|
|
13394
|
+
logger$b.warn("Failed to restore locale via page reload:", err);
|
|
13324
13395
|
}
|
|
13325
13396
|
}
|
|
13326
13397
|
}
|
|
@@ -13672,7 +13743,7 @@ ${postActivationOverlayHint}`;
|
|
|
13672
13743
|
return `${clickText} -> ${hrefFallbackUrl} (recovered via href fallback)`;
|
|
13673
13744
|
}
|
|
13674
13745
|
} catch (err) {
|
|
13675
|
-
logger$
|
|
13746
|
+
logger$b.warn("Failed href fallback after click, returning generic click result:", err);
|
|
13676
13747
|
}
|
|
13677
13748
|
}
|
|
13678
13749
|
}
|
|
@@ -13717,7 +13788,7 @@ async function tryAutoDismissCartDialog(wc) {
|
|
|
13717
13788
|
return result;
|
|
13718
13789
|
}
|
|
13719
13790
|
} catch (err) {
|
|
13720
|
-
logger$
|
|
13791
|
+
logger$b.warn("Failed to auto-dismiss cart dialog, falling back to dialog actions:", err);
|
|
13721
13792
|
}
|
|
13722
13793
|
return null;
|
|
13723
13794
|
}
|
|
@@ -15987,7 +16058,7 @@ async function executeAction(name, args, ctx) {
|
|
|
15987
16058
|
)
|
|
15988
16059
|
]);
|
|
15989
16060
|
} catch (err) {
|
|
15990
|
-
logger$
|
|
16061
|
+
logger$b.warn("Failed to extract content for read_page, falling back to lighter recovery:", err);
|
|
15991
16062
|
content = null;
|
|
15992
16063
|
}
|
|
15993
16064
|
if (!content || content.content.length === 0) {
|
|
@@ -16004,12 +16075,12 @@ async function executeAction(name, args, ctx) {
|
|
|
16004
16075
|
new Promise((resolve) => setTimeout(() => resolve(null), 3e3))
|
|
16005
16076
|
]);
|
|
16006
16077
|
} catch (err) {
|
|
16007
|
-
logger$
|
|
16078
|
+
logger$b.warn("Failed to re-extract content after iframe consent dismissal:", err);
|
|
16008
16079
|
content = null;
|
|
16009
16080
|
}
|
|
16010
16081
|
}
|
|
16011
16082
|
} catch (err) {
|
|
16012
|
-
logger$
|
|
16083
|
+
logger$b.warn("Failed iframe consent dismissal during read_page recovery:", err);
|
|
16013
16084
|
}
|
|
16014
16085
|
}
|
|
16015
16086
|
if (content && content.content.length > 0) {
|
|
@@ -16422,7 +16493,7 @@ ${flow.steps.map((s, i) => ` ${i === 0 ? "→" : " "} ${s.label}`).join("\n")}`
|
|
|
16422
16493
|
try {
|
|
16423
16494
|
page = await extractContent(wc);
|
|
16424
16495
|
} catch (err) {
|
|
16425
|
-
logger$
|
|
16496
|
+
logger$b.warn("Failed to extract content for suggest:", err);
|
|
16426
16497
|
return "Could not read page. Try navigate to a working URL.";
|
|
16427
16498
|
}
|
|
16428
16499
|
const suggestions = [];
|
|
@@ -17753,7 +17824,7 @@ const ALGORITHM = "aes-256-gcm";
|
|
|
17753
17824
|
const IV_LENGTH = 12;
|
|
17754
17825
|
const AUTH_TAG_LENGTH = 16;
|
|
17755
17826
|
let cachedEntries = null;
|
|
17756
|
-
const logger$
|
|
17827
|
+
const logger$a = createLogger("Vault");
|
|
17757
17828
|
function getVaultDir() {
|
|
17758
17829
|
return electron.app.getPath("userData");
|
|
17759
17830
|
}
|
|
@@ -17820,7 +17891,7 @@ function loadVault() {
|
|
|
17820
17891
|
cachedEntries = JSON.parse(json);
|
|
17821
17892
|
return cachedEntries;
|
|
17822
17893
|
} catch (err) {
|
|
17823
|
-
logger$
|
|
17894
|
+
logger$a.error("Failed to load vault:", err);
|
|
17824
17895
|
throw new Error(
|
|
17825
17896
|
"Could not unlock the Agent Credential Vault. Check that OS secret storage is available and that the stored vault key can be decrypted."
|
|
17826
17897
|
);
|
|
@@ -17962,7 +18033,7 @@ async function requestConsent(request) {
|
|
|
17962
18033
|
}
|
|
17963
18034
|
const AUDIT_FILENAME = "vessel-vault-audit.jsonl";
|
|
17964
18035
|
const MAX_ENTRIES = 1e3;
|
|
17965
|
-
const logger$
|
|
18036
|
+
const logger$9 = createLogger("VaultAudit");
|
|
17966
18037
|
function getAuditPath() {
|
|
17967
18038
|
return path$1.join(electron.app.getPath("userData"), AUDIT_FILENAME);
|
|
17968
18039
|
}
|
|
@@ -17972,7 +18043,7 @@ function appendAuditEntry(entry) {
|
|
|
17972
18043
|
fs$1.mkdirSync(path$1.dirname(auditPath), { recursive: true });
|
|
17973
18044
|
fs$1.appendFileSync(auditPath, JSON.stringify(entry) + "\n");
|
|
17974
18045
|
} catch (err) {
|
|
17975
|
-
logger$
|
|
18046
|
+
logger$9.error("Failed to write audit log:", err);
|
|
17976
18047
|
}
|
|
17977
18048
|
}
|
|
17978
18049
|
function readAuditLog(limit = 100) {
|
|
@@ -17982,13 +18053,13 @@ function readAuditLog(limit = 100) {
|
|
|
17982
18053
|
const lines = fs$1.readFileSync(auditPath, "utf-8").split("\n").filter((l) => l.trim());
|
|
17983
18054
|
return lines.slice(-Math.min(limit, MAX_ENTRIES)).map((line) => JSON.parse(line)).reverse();
|
|
17984
18055
|
} catch (err) {
|
|
17985
|
-
logger$
|
|
18056
|
+
logger$9.error("Failed to read audit log:", err);
|
|
17986
18057
|
return [];
|
|
17987
18058
|
}
|
|
17988
18059
|
}
|
|
17989
18060
|
let httpServer = null;
|
|
17990
18061
|
let mcpAuthToken = null;
|
|
17991
|
-
const logger$
|
|
18062
|
+
const logger$8 = createLogger("MCP");
|
|
17992
18063
|
const MCP_AUTH_FILENAME = "mcp-auth.json";
|
|
17993
18064
|
function getMcpAuthFilePath() {
|
|
17994
18065
|
const configDir = process.env.VESSEL_CONFIG_DIR || path$1.join(
|
|
@@ -18024,7 +18095,7 @@ function writeMcpAuthFile(endpoint, token) {
|
|
|
18024
18095
|
{ mode: 384 }
|
|
18025
18096
|
);
|
|
18026
18097
|
} catch (err) {
|
|
18027
|
-
logger$
|
|
18098
|
+
logger$8.warn("Failed to write auth file:", err);
|
|
18028
18099
|
}
|
|
18029
18100
|
}
|
|
18030
18101
|
function clearMcpAuthFile() {
|
|
@@ -18049,7 +18120,7 @@ function clearMcpAuthFile() {
|
|
|
18049
18120
|
{ mode: 384 }
|
|
18050
18121
|
);
|
|
18051
18122
|
} catch (err) {
|
|
18052
|
-
logger$
|
|
18123
|
+
logger$8.warn("Failed to clear auth file:", err);
|
|
18053
18124
|
}
|
|
18054
18125
|
}
|
|
18055
18126
|
function asTextResponse(text) {
|
|
@@ -18139,7 +18210,7 @@ async function getPostActionState(tabManager, name) {
|
|
|
18139
18210
|
}
|
|
18140
18211
|
}
|
|
18141
18212
|
} catch (err) {
|
|
18142
|
-
logger$
|
|
18213
|
+
logger$8.warn("Failed to compute post-action state warning:", err);
|
|
18143
18214
|
}
|
|
18144
18215
|
return `${warning}
|
|
18145
18216
|
[state: url=${wc.getURL()}, canGoBack=${tab.canGoBack()}, canGoForward=${tab.canGoForward()}, loading=${wc.isLoading()}]`;
|
|
@@ -18241,7 +18312,7 @@ async function waitForConditionMcp(wc, text, selector, timeoutMs) {
|
|
|
18241
18312
|
}
|
|
18242
18313
|
})()
|
|
18243
18314
|
`).catch((err) => {
|
|
18244
|
-
logger$
|
|
18315
|
+
logger$8.warn("Failed to gather wait_for timeout diagnostic:", err);
|
|
18245
18316
|
return null;
|
|
18246
18317
|
});
|
|
18247
18318
|
if (typeof diagnostic === "string" && diagnostic.trim()) {
|
|
@@ -18328,7 +18399,7 @@ function registerTools(server, tabManager, runtime2) {
|
|
|
18328
18399
|
const page = await extractContent(wc);
|
|
18329
18400
|
pageType = detectPageType(page);
|
|
18330
18401
|
} catch (err) {
|
|
18331
|
-
logger$
|
|
18402
|
+
logger$8.warn("Failed to detect page type for tool scoring, falling back to GENERAL:", err);
|
|
18332
18403
|
}
|
|
18333
18404
|
}
|
|
18334
18405
|
const scored = TOOL_DEFINITIONS.map((def) => {
|
|
@@ -19612,7 +19683,7 @@ ${JSON.stringify(otherHighlights, null, 2)}`
|
|
|
19612
19683
|
void 0,
|
|
19613
19684
|
h.color
|
|
19614
19685
|
).catch(
|
|
19615
|
-
(err) => logger$
|
|
19686
|
+
(err) => logger$8.warn("Failed to restore highlight after removal:", err)
|
|
19616
19687
|
);
|
|
19617
19688
|
}
|
|
19618
19689
|
}
|
|
@@ -20460,7 +20531,7 @@ ${flow.steps.map((s, i) => ` ${i === 0 ? "→" : " "} ${s.label}`).join("\n")}`
|
|
|
20460
20531
|
try {
|
|
20461
20532
|
page = await extractContent(wc);
|
|
20462
20533
|
} catch (err) {
|
|
20463
|
-
logger$
|
|
20534
|
+
logger$8.warn("Failed to extract page while generating suggestions:", err);
|
|
20464
20535
|
return asTextResponse(
|
|
20465
20536
|
"Could not read page. Try navigate to a working URL."
|
|
20466
20537
|
);
|
|
@@ -21069,7 +21140,7 @@ ${JSON.stringify(tableJson, null, 2)}`;
|
|
|
21069
21140
|
try {
|
|
21070
21141
|
targetDomain = new URL(tab.state.url).hostname;
|
|
21071
21142
|
} catch (err) {
|
|
21072
|
-
logger$
|
|
21143
|
+
logger$8.warn("Failed to parse active tab URL for vault_status:", err);
|
|
21073
21144
|
return asErrorTextResponse("Could not parse active tab URL");
|
|
21074
21145
|
}
|
|
21075
21146
|
}
|
|
@@ -21135,7 +21206,7 @@ Use vault_login to fill the login form. Credentials are filled directly — you
|
|
|
21135
21206
|
try {
|
|
21136
21207
|
hostname = new URL(tab.state.url).hostname;
|
|
21137
21208
|
} catch (err) {
|
|
21138
|
-
logger$
|
|
21209
|
+
logger$8.warn("Failed to parse active tab URL for vault_login:", err);
|
|
21139
21210
|
return asErrorTextResponse("Could not parse active tab URL");
|
|
21140
21211
|
}
|
|
21141
21212
|
const matches = findEntriesForDomain(`https://${hostname}`);
|
|
@@ -21229,7 +21300,7 @@ Use vault_login to fill the login form. Credentials are filled directly — you
|
|
|
21229
21300
|
try {
|
|
21230
21301
|
hostname = new URL(tab.state.url).hostname;
|
|
21231
21302
|
} catch (err) {
|
|
21232
|
-
logger$
|
|
21303
|
+
logger$8.warn("Failed to parse active tab URL for vault_totp:", err);
|
|
21233
21304
|
return asErrorTextResponse("Could not parse active tab URL");
|
|
21234
21305
|
}
|
|
21235
21306
|
const matches = findEntriesForDomain(`https://${hostname}`);
|
|
@@ -21401,7 +21472,7 @@ function startMcpServer(tabManager, runtime2, port) {
|
|
|
21401
21472
|
await mcpServer.connect(transport);
|
|
21402
21473
|
await transport.handleRequest(req, res);
|
|
21403
21474
|
} catch (error) {
|
|
21404
|
-
logger$
|
|
21475
|
+
logger$8.error("Error handling request:", error);
|
|
21405
21476
|
if (!res.headersSent) {
|
|
21406
21477
|
res.writeHead(500, { "Content-Type": "application/json" });
|
|
21407
21478
|
res.end(
|
|
@@ -21420,7 +21491,7 @@ function startMcpServer(tabManager, runtime2, port) {
|
|
|
21420
21491
|
};
|
|
21421
21492
|
server.once("error", (error) => {
|
|
21422
21493
|
const message = error.code === "EADDRINUSE" ? `Port ${port} is already in use. MCP server not started.` : error.message;
|
|
21423
|
-
logger$
|
|
21494
|
+
logger$8.error("Server error:", error);
|
|
21424
21495
|
clearMcpAuthFile();
|
|
21425
21496
|
setMcpHealth({
|
|
21426
21497
|
configuredPort: port,
|
|
@@ -21452,7 +21523,7 @@ function startMcpServer(tabManager, runtime2, port) {
|
|
|
21452
21523
|
message: `MCP server listening on ${endpoint}.`
|
|
21453
21524
|
});
|
|
21454
21525
|
if (process.env.VESSEL_DEBUG_MCP === "1" || process.env.VESSEL_DEBUG_MCP === "true") {
|
|
21455
|
-
logger$
|
|
21526
|
+
logger$8.info(`Server listening on ${endpoint} (auth enabled)`);
|
|
21456
21527
|
}
|
|
21457
21528
|
if (mcpAuthToken) {
|
|
21458
21529
|
writeMcpAuthFile(endpoint, mcpAuthToken);
|
|
@@ -21491,7 +21562,7 @@ function stopMcpServer() {
|
|
|
21491
21562
|
message: "MCP server is stopped."
|
|
21492
21563
|
});
|
|
21493
21564
|
if (process.env.VESSEL_DEBUG_MCP === "1" || process.env.VESSEL_DEBUG_MCP === "true") {
|
|
21494
|
-
logger$
|
|
21565
|
+
logger$8.info("Server stopped");
|
|
21495
21566
|
}
|
|
21496
21567
|
resolve();
|
|
21497
21568
|
});
|
|
@@ -21512,7 +21583,7 @@ const KIT_ID_UNSAFE_CHAR_PATTERN = /[\/\\\0]/;
|
|
|
21512
21583
|
function isSafeAutomationKitId(id) {
|
|
21513
21584
|
return id.length > 0 && !KIT_ID_UNSAFE_CHAR_PATTERN.test(id);
|
|
21514
21585
|
}
|
|
21515
|
-
const logger$
|
|
21586
|
+
const logger$7 = createLogger("KitRegistry");
|
|
21516
21587
|
function getUserKitsDir() {
|
|
21517
21588
|
return path$1.join(electron.app.getPath("userData"), "kits");
|
|
21518
21589
|
}
|
|
@@ -21550,10 +21621,10 @@ function getInstalledKits() {
|
|
|
21550
21621
|
if (isValidKit(parsed)) {
|
|
21551
21622
|
kits.push(parsed);
|
|
21552
21623
|
} else {
|
|
21553
|
-
logger$
|
|
21624
|
+
logger$7.warn(`Skipping invalid kit file: ${file}`);
|
|
21554
21625
|
}
|
|
21555
21626
|
} catch (err) {
|
|
21556
|
-
logger$
|
|
21627
|
+
logger$7.warn(`Failed to read kit file: ${file}`, err);
|
|
21557
21628
|
}
|
|
21558
21629
|
}
|
|
21559
21630
|
return kits;
|
|
@@ -21625,7 +21696,7 @@ function uninstallKit(id, scheduledKitIds) {
|
|
|
21625
21696
|
return errorResult("Failed to remove the kit file.");
|
|
21626
21697
|
}
|
|
21627
21698
|
}
|
|
21628
|
-
const logger$
|
|
21699
|
+
const logger$6 = createLogger("Scheduler");
|
|
21629
21700
|
let jobs = [];
|
|
21630
21701
|
let removeIdleListener = null;
|
|
21631
21702
|
let broadcastFn = null;
|
|
@@ -21650,7 +21721,7 @@ function saveJobs() {
|
|
|
21650
21721
|
try {
|
|
21651
21722
|
fs$1.writeFileSync(getJobsPath(), JSON.stringify(jobs, null, 2), "utf-8");
|
|
21652
21723
|
} catch (err) {
|
|
21653
|
-
logger$
|
|
21724
|
+
logger$6.warn("Failed to save jobs:", err);
|
|
21654
21725
|
}
|
|
21655
21726
|
}
|
|
21656
21727
|
function normalizeJob(job, now = /* @__PURE__ */ new Date()) {
|
|
@@ -21772,7 +21843,7 @@ async function fireJob(job, windowState, runtime2) {
|
|
|
21772
21843
|
};
|
|
21773
21844
|
startActivity();
|
|
21774
21845
|
if (!settings2.chatProvider) {
|
|
21775
|
-
logger$
|
|
21846
|
+
logger$6.warn(`Job "${job.kitName}" skipped — no chat provider configured`);
|
|
21776
21847
|
appendActivity(
|
|
21777
21848
|
"Chat provider not configured. Open Settings (Ctrl+,) to choose a provider."
|
|
21778
21849
|
);
|
|
@@ -21780,7 +21851,7 @@ async function fireJob(job, windowState, runtime2) {
|
|
|
21780
21851
|
return;
|
|
21781
21852
|
}
|
|
21782
21853
|
if (process.env.VESSEL_DEBUG_SCHEDULER === "1" || process.env.VESSEL_DEBUG_SCHEDULER === "true") {
|
|
21783
|
-
logger$
|
|
21854
|
+
logger$6.info(`Firing scheduled job: ${job.kitName} (${job.id})`);
|
|
21784
21855
|
}
|
|
21785
21856
|
try {
|
|
21786
21857
|
const provider = createProvider(settings2.chatProvider);
|
|
@@ -21833,7 +21904,7 @@ function tick(windowState, runtime2) {
|
|
|
21833
21904
|
saveJobs();
|
|
21834
21905
|
broadcastFn?.(Channels.SCHEDULE_JOBS_UPDATE, jobs);
|
|
21835
21906
|
void fireJob(job, windowState, runtime2).catch((err) => {
|
|
21836
|
-
logger$
|
|
21907
|
+
logger$6.warn("Unexpected error firing job:", err);
|
|
21837
21908
|
}).finally(fireNext);
|
|
21838
21909
|
};
|
|
21839
21910
|
fireNext();
|
|
@@ -22403,93 +22474,540 @@ function registerWindowControlHandlers(mainWindow) {
|
|
|
22403
22474
|
mainWindow.close();
|
|
22404
22475
|
});
|
|
22405
22476
|
}
|
|
22406
|
-
|
|
22407
|
-
|
|
22408
|
-
|
|
22409
|
-
|
|
22410
|
-
|
|
22411
|
-
|
|
22412
|
-
|
|
22413
|
-
|
|
22414
|
-
|
|
22415
|
-
|
|
22416
|
-
|
|
22417
|
-
|
|
22418
|
-
|
|
22419
|
-
|
|
22420
|
-
|
|
22421
|
-
|
|
22422
|
-
|
|
22423
|
-
|
|
22424
|
-
|
|
22425
|
-
|
|
22426
|
-
|
|
22427
|
-
|
|
22428
|
-
|
|
22429
|
-
|
|
22430
|
-
|
|
22431
|
-
|
|
22432
|
-
|
|
22433
|
-
|
|
22434
|
-
|
|
22435
|
-
|
|
22436
|
-
|
|
22437
|
-
|
|
22438
|
-
|
|
22439
|
-
|
|
22440
|
-
|
|
22477
|
+
const BLOCKED_RESOURCE_TYPES = /* @__PURE__ */ new Set([
|
|
22478
|
+
"script",
|
|
22479
|
+
"image",
|
|
22480
|
+
"xhr",
|
|
22481
|
+
"fetch",
|
|
22482
|
+
"subFrame",
|
|
22483
|
+
"media",
|
|
22484
|
+
"ping",
|
|
22485
|
+
"webSocket"
|
|
22486
|
+
]);
|
|
22487
|
+
const BLOCKED_HOST_SUFFIXES = [
|
|
22488
|
+
"doubleclick.net",
|
|
22489
|
+
"googlesyndication.com",
|
|
22490
|
+
"googleadservices.com",
|
|
22491
|
+
"adservice.google.com",
|
|
22492
|
+
"adnxs.com",
|
|
22493
|
+
"adsrvr.org",
|
|
22494
|
+
"taboola.com",
|
|
22495
|
+
"outbrain.com",
|
|
22496
|
+
"criteo.com",
|
|
22497
|
+
"criteo.net",
|
|
22498
|
+
"pubmatic.com",
|
|
22499
|
+
"rubiconproject.com",
|
|
22500
|
+
"openx.net",
|
|
22501
|
+
"casalemedia.com",
|
|
22502
|
+
"advertising.com",
|
|
22503
|
+
"amazon-adsystem.com",
|
|
22504
|
+
"adsymptotic.com",
|
|
22505
|
+
"moatads.com",
|
|
22506
|
+
"quantserve.com",
|
|
22507
|
+
"scorecardresearch.com"
|
|
22508
|
+
];
|
|
22509
|
+
const THIRD_PARTY_PATH_PATTERNS = [
|
|
22510
|
+
/\/ads?[/?._-]/i,
|
|
22511
|
+
/\/adservice/i,
|
|
22512
|
+
/\/advert/i,
|
|
22513
|
+
/\/prebid/i,
|
|
22514
|
+
/\/banner/i,
|
|
22515
|
+
/\/sponsor/i,
|
|
22516
|
+
/\/promotions?\//i,
|
|
22517
|
+
/\/trk\//i,
|
|
22518
|
+
/\/track(ing)?\//i,
|
|
22519
|
+
/\/beacon/i,
|
|
22520
|
+
/\/pixel/i
|
|
22521
|
+
];
|
|
22522
|
+
let installed = false;
|
|
22523
|
+
function normalizeHostname(value) {
|
|
22524
|
+
return value.trim().toLowerCase().replace(/\.$/, "");
|
|
22525
|
+
}
|
|
22526
|
+
function hostnameMatches(hostname, suffix) {
|
|
22527
|
+
return hostname === suffix || hostname.endsWith(`.${suffix}`);
|
|
22528
|
+
}
|
|
22529
|
+
function parseHostname(url) {
|
|
22530
|
+
try {
|
|
22531
|
+
const parsed = new URL(url);
|
|
22532
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
22533
|
+
return null;
|
|
22441
22534
|
}
|
|
22442
|
-
|
|
22443
|
-
|
|
22444
|
-
|
|
22445
|
-
|
|
22446
|
-
|
|
22535
|
+
return normalizeHostname(parsed.hostname);
|
|
22536
|
+
} catch {
|
|
22537
|
+
return null;
|
|
22538
|
+
}
|
|
22539
|
+
}
|
|
22540
|
+
function isThirdParty(url, firstPartyHost) {
|
|
22541
|
+
if (!firstPartyHost) return true;
|
|
22542
|
+
const target = normalizeHostname(url.hostname);
|
|
22543
|
+
return !(target === firstPartyHost || target.endsWith(`.${firstPartyHost}`));
|
|
22544
|
+
}
|
|
22545
|
+
function shouldBlockRequest(details) {
|
|
22546
|
+
if (!BLOCKED_RESOURCE_TYPES.has(details.resourceType)) return false;
|
|
22547
|
+
let parsed;
|
|
22548
|
+
try {
|
|
22549
|
+
parsed = new URL(details.url);
|
|
22550
|
+
} catch {
|
|
22551
|
+
return false;
|
|
22552
|
+
}
|
|
22553
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
22554
|
+
return false;
|
|
22555
|
+
}
|
|
22556
|
+
const hostname = normalizeHostname(parsed.hostname);
|
|
22557
|
+
if (BLOCKED_HOST_SUFFIXES.some((suffix) => hostnameMatches(hostname, suffix))) {
|
|
22558
|
+
return true;
|
|
22559
|
+
}
|
|
22560
|
+
const firstPartyHost = parseHostname(details.referrer) || parseHostname(details.initiator || "");
|
|
22561
|
+
if (!isThirdParty(parsed, firstPartyHost)) return false;
|
|
22562
|
+
const candidate = `${hostname}${parsed.pathname}${parsed.search}`;
|
|
22563
|
+
return THIRD_PARTY_PATH_PATTERNS.some((pattern) => pattern.test(candidate));
|
|
22564
|
+
}
|
|
22565
|
+
function installAdBlocking(tabManager) {
|
|
22566
|
+
if (installed) return;
|
|
22567
|
+
installed = true;
|
|
22568
|
+
electron.session.defaultSession.webRequest.onBeforeRequest((details, callback) => {
|
|
22569
|
+
const webContentsId = typeof details.webContentsId === "number" ? details.webContentsId : null;
|
|
22570
|
+
if (webContentsId == null) {
|
|
22571
|
+
callback({});
|
|
22572
|
+
return;
|
|
22447
22573
|
}
|
|
22448
|
-
|
|
22449
|
-
|
|
22450
|
-
|
|
22451
|
-
pendingRuntimeState = state2;
|
|
22452
|
-
if (runtimeUpdateTimer) return;
|
|
22453
|
-
runtimeUpdateTimer = setTimeout(() => {
|
|
22454
|
-
flushRuntimeUpdate();
|
|
22455
|
-
}, 32);
|
|
22456
|
-
};
|
|
22457
|
-
electron.app.on("before-quit", () => {
|
|
22458
|
-
if (runtimeUpdateTimer) {
|
|
22459
|
-
clearTimeout(runtimeUpdateTimer);
|
|
22460
|
-
runtimeUpdateTimer = null;
|
|
22574
|
+
if (!tabManager.isAdBlockingEnabledForWebContents(webContentsId)) {
|
|
22575
|
+
callback({});
|
|
22576
|
+
return;
|
|
22461
22577
|
}
|
|
22462
|
-
|
|
22578
|
+
callback({ cancel: shouldBlockRequest(details) });
|
|
22463
22579
|
});
|
|
22464
|
-
|
|
22465
|
-
|
|
22466
|
-
|
|
22467
|
-
|
|
22468
|
-
|
|
22469
|
-
|
|
22470
|
-
|
|
22471
|
-
|
|
22472
|
-
if (!
|
|
22473
|
-
|
|
22474
|
-
|
|
22475
|
-
|
|
22476
|
-
|
|
22477
|
-
|
|
22580
|
+
}
|
|
22581
|
+
function installAdBlockingForSession(ses, tabManager) {
|
|
22582
|
+
ses.webRequest.onBeforeRequest((details, callback) => {
|
|
22583
|
+
const webContentsId = typeof details.webContentsId === "number" ? details.webContentsId : null;
|
|
22584
|
+
if (webContentsId == null) {
|
|
22585
|
+
callback({});
|
|
22586
|
+
return;
|
|
22587
|
+
}
|
|
22588
|
+
if (!tabManager.isAdBlockingEnabledForWebContents(webContentsId)) {
|
|
22589
|
+
callback({});
|
|
22590
|
+
return;
|
|
22591
|
+
}
|
|
22592
|
+
callback({ cancel: shouldBlockRequest(details) });
|
|
22593
|
+
});
|
|
22594
|
+
}
|
|
22595
|
+
function resolveDownloadPath(downloadDir, filename) {
|
|
22596
|
+
fs$1.mkdirSync(downloadDir, { recursive: true });
|
|
22597
|
+
const parsed = path.parse(filename);
|
|
22598
|
+
let attempt = 0;
|
|
22599
|
+
while (true) {
|
|
22600
|
+
const candidateName = attempt === 0 ? filename : `${parsed.name} (${attempt})${parsed.ext}`;
|
|
22601
|
+
const candidatePath = path.join(downloadDir, candidateName);
|
|
22602
|
+
if (!fs$1.existsSync(candidatePath)) {
|
|
22603
|
+
return candidatePath;
|
|
22604
|
+
}
|
|
22605
|
+
attempt += 1;
|
|
22606
|
+
}
|
|
22607
|
+
}
|
|
22608
|
+
function installDownloadHandler(chromeView) {
|
|
22609
|
+
installDownloadHandlerForSession(electron.session.defaultSession, chromeView);
|
|
22610
|
+
}
|
|
22611
|
+
function installDownloadHandlerForSession(targetSession, chromeView) {
|
|
22612
|
+
targetSession.on("will-download", (_event, item) => {
|
|
22613
|
+
const settings2 = loadSettings();
|
|
22614
|
+
const downloadDir = settings2.downloadPath.trim() || electron.app.getPath("downloads");
|
|
22615
|
+
const filename = item.getFilename();
|
|
22616
|
+
const savePath = resolveDownloadPath(downloadDir, filename);
|
|
22617
|
+
item.setSavePath(savePath);
|
|
22618
|
+
const info = {
|
|
22619
|
+
filename,
|
|
22620
|
+
savePath,
|
|
22621
|
+
totalBytes: item.getTotalBytes(),
|
|
22622
|
+
receivedBytes: 0,
|
|
22623
|
+
state: "progressing"
|
|
22478
22624
|
};
|
|
22479
|
-
|
|
22480
|
-
|
|
22481
|
-
|
|
22482
|
-
|
|
22483
|
-
|
|
22484
|
-
|
|
22485
|
-
|
|
22486
|
-
|
|
22487
|
-
|
|
22488
|
-
|
|
22489
|
-
|
|
22490
|
-
|
|
22491
|
-
|
|
22492
|
-
|
|
22625
|
+
if (!chromeView.webContents.isDestroyed()) {
|
|
22626
|
+
chromeView.webContents.send(Channels.DOWNLOAD_STARTED, info);
|
|
22627
|
+
}
|
|
22628
|
+
item.on("updated", (_event2, state2) => {
|
|
22629
|
+
info.receivedBytes = item.getReceivedBytes();
|
|
22630
|
+
info.totalBytes = item.getTotalBytes();
|
|
22631
|
+
info.state = state2 === "progressing" ? "progressing" : "interrupted";
|
|
22632
|
+
if (!chromeView.webContents.isDestroyed()) {
|
|
22633
|
+
chromeView.webContents.send(Channels.DOWNLOAD_PROGRESS, info);
|
|
22634
|
+
}
|
|
22635
|
+
});
|
|
22636
|
+
item.once("done", (_event2, state2) => {
|
|
22637
|
+
info.receivedBytes = item.getReceivedBytes();
|
|
22638
|
+
info.state = state2 === "completed" ? "completed" : "cancelled";
|
|
22639
|
+
if (!chromeView.webContents.isDestroyed()) {
|
|
22640
|
+
chromeView.webContents.send(Channels.DOWNLOAD_DONE, info);
|
|
22641
|
+
}
|
|
22642
|
+
});
|
|
22643
|
+
});
|
|
22644
|
+
}
|
|
22645
|
+
const logger$5 = createLogger("PrivateWindow");
|
|
22646
|
+
const CHROME_HEIGHT = 110;
|
|
22647
|
+
const privateWindows = /* @__PURE__ */ new Set();
|
|
22648
|
+
function resolveRendererFile$1() {
|
|
22649
|
+
const candidates = [
|
|
22650
|
+
path.join(__dirname, "../../out/renderer/index.html"),
|
|
22651
|
+
path.join(__dirname, "../../../out/renderer/index.html")
|
|
22652
|
+
];
|
|
22653
|
+
for (const c of candidates) {
|
|
22654
|
+
try {
|
|
22655
|
+
fs.accessSync(c);
|
|
22656
|
+
return c;
|
|
22657
|
+
} catch {
|
|
22658
|
+
}
|
|
22659
|
+
}
|
|
22660
|
+
return path.join(__dirname, "../../out/renderer/index.html");
|
|
22661
|
+
}
|
|
22662
|
+
function layoutPrivateViews(state2) {
|
|
22663
|
+
const { window: win, chromeView, tabManager } = state2;
|
|
22664
|
+
const [width, height] = win.getContentSize();
|
|
22665
|
+
chromeView.setBounds({ x: 0, y: 0, width, height: CHROME_HEIGHT });
|
|
22666
|
+
win.contentView.removeChildView(chromeView);
|
|
22667
|
+
win.contentView.addChildView(chromeView);
|
|
22668
|
+
const activeTab = tabManager.getActiveTab();
|
|
22669
|
+
if (activeTab) {
|
|
22670
|
+
activeTab.view.setBounds({
|
|
22671
|
+
x: 0,
|
|
22672
|
+
y: CHROME_HEIGHT,
|
|
22673
|
+
width,
|
|
22674
|
+
height: height - CHROME_HEIGHT
|
|
22675
|
+
});
|
|
22676
|
+
}
|
|
22677
|
+
}
|
|
22678
|
+
function loadPrivateRenderer(chromeView) {
|
|
22679
|
+
const devUrl = process.env.ELECTRON_RENDERER_URL;
|
|
22680
|
+
if (devUrl) {
|
|
22681
|
+
const url = new URL(devUrl);
|
|
22682
|
+
url.searchParams.set("view", "chrome");
|
|
22683
|
+
url.searchParams.set("private", "1");
|
|
22684
|
+
chromeView.webContents.loadURL(url.toString());
|
|
22685
|
+
} else {
|
|
22686
|
+
chromeView.webContents.loadFile(resolveRendererFile$1(), {
|
|
22687
|
+
query: { view: "chrome", private: "1" }
|
|
22688
|
+
});
|
|
22689
|
+
}
|
|
22690
|
+
}
|
|
22691
|
+
function registerPrivateIpcHandlers(state2) {
|
|
22692
|
+
const { chromeView, tabManager } = state2;
|
|
22693
|
+
const ipc = chromeView.webContents.ipc;
|
|
22694
|
+
let findResultListener = null;
|
|
22695
|
+
let findWiredWcId = null;
|
|
22696
|
+
const wireFindEvents = (wc) => {
|
|
22697
|
+
if (findWiredWcId === wc.id && findResultListener) return;
|
|
22698
|
+
if (findWiredWcId && findResultListener) {
|
|
22699
|
+
const previous = tabManager.findTabByWebContentsId(findWiredWcId);
|
|
22700
|
+
previous?.view.webContents.removeListener(
|
|
22701
|
+
"found-in-page",
|
|
22702
|
+
findResultListener
|
|
22703
|
+
);
|
|
22704
|
+
}
|
|
22705
|
+
findWiredWcId = wc.id;
|
|
22706
|
+
if (wc.isDestroyed()) return;
|
|
22707
|
+
const listener = (_event, result) => {
|
|
22708
|
+
if (!chromeView.webContents.isDestroyed()) {
|
|
22709
|
+
chromeView.webContents.send(Channels.FIND_IN_PAGE_RESULT, result);
|
|
22710
|
+
}
|
|
22711
|
+
};
|
|
22712
|
+
findResultListener = listener;
|
|
22713
|
+
wc.on("found-in-page", listener);
|
|
22714
|
+
const capturedWcId = wc.id;
|
|
22715
|
+
wc.once("destroyed", () => {
|
|
22716
|
+
if (findWiredWcId === capturedWcId) {
|
|
22717
|
+
findWiredWcId = null;
|
|
22718
|
+
findResultListener = null;
|
|
22719
|
+
}
|
|
22720
|
+
});
|
|
22721
|
+
};
|
|
22722
|
+
ipc.handle(Channels.TAB_CREATE, (_e, url) => {
|
|
22723
|
+
return tabManager.createTab(url);
|
|
22724
|
+
});
|
|
22725
|
+
ipc.handle(Channels.TAB_CLOSE, (_e, id) => {
|
|
22726
|
+
tabManager.closeTab(id);
|
|
22727
|
+
layoutPrivateViews(state2);
|
|
22728
|
+
});
|
|
22729
|
+
ipc.handle(Channels.TAB_SWITCH, (_e, id) => {
|
|
22730
|
+
tabManager.switchTab(id);
|
|
22731
|
+
layoutPrivateViews(state2);
|
|
22732
|
+
});
|
|
22733
|
+
ipc.handle(Channels.TAB_NAVIGATE, (_e, id, url) => {
|
|
22734
|
+
return tabManager.navigateTab(id, url);
|
|
22735
|
+
});
|
|
22736
|
+
ipc.handle(Channels.TAB_BACK, (_e, id) => {
|
|
22737
|
+
tabManager.goBack(id);
|
|
22738
|
+
});
|
|
22739
|
+
ipc.handle(Channels.TAB_FORWARD, (_e, id) => {
|
|
22740
|
+
tabManager.goForward(id);
|
|
22741
|
+
});
|
|
22742
|
+
ipc.handle(Channels.TAB_RELOAD, (_e, id) => {
|
|
22743
|
+
tabManager.reloadTab(id);
|
|
22744
|
+
});
|
|
22745
|
+
ipc.handle(Channels.TAB_TOGGLE_AD_BLOCK, (_e, id) => {
|
|
22746
|
+
const tab = tabManager.getTab(id);
|
|
22747
|
+
if (!tab) return null;
|
|
22748
|
+
const newState = !tab.state.adBlockingEnabled;
|
|
22749
|
+
tab.setAdBlockingEnabled(newState);
|
|
22750
|
+
return newState;
|
|
22751
|
+
});
|
|
22752
|
+
ipc.handle(Channels.TAB_ZOOM_IN, (_e, id) => {
|
|
22753
|
+
tabManager.zoomIn(id);
|
|
22754
|
+
});
|
|
22755
|
+
ipc.handle(Channels.TAB_ZOOM_OUT, (_e, id) => {
|
|
22756
|
+
tabManager.zoomOut(id);
|
|
22757
|
+
});
|
|
22758
|
+
ipc.handle(Channels.TAB_ZOOM_RESET, (_e, id) => {
|
|
22759
|
+
tabManager.zoomReset(id);
|
|
22760
|
+
});
|
|
22761
|
+
ipc.handle(Channels.TAB_STATE_GET, () => ({
|
|
22762
|
+
tabs: tabManager.getAllStates(),
|
|
22763
|
+
activeId: tabManager.getActiveTabId() || ""
|
|
22764
|
+
}));
|
|
22765
|
+
ipc.handle(Channels.TAB_REOPEN_CLOSED, () => {
|
|
22766
|
+
const id = tabManager.reopenClosedTab();
|
|
22767
|
+
if (id) layoutPrivateViews(state2);
|
|
22768
|
+
return id;
|
|
22769
|
+
});
|
|
22770
|
+
ipc.handle(Channels.TAB_DUPLICATE, (_e, id) => {
|
|
22771
|
+
const newId = tabManager.duplicateTab(id);
|
|
22772
|
+
if (newId) layoutPrivateViews(state2);
|
|
22773
|
+
return newId;
|
|
22774
|
+
});
|
|
22775
|
+
ipc.on(Channels.TAB_CONTEXT_MENU, (_e, id) => {
|
|
22776
|
+
const { Menu, MenuItem } = require("electron");
|
|
22777
|
+
const menu = new Menu();
|
|
22778
|
+
menu.append(
|
|
22779
|
+
new MenuItem({
|
|
22780
|
+
label: "Duplicate Tab",
|
|
22781
|
+
click: () => {
|
|
22782
|
+
const newId = tabManager.duplicateTab(id);
|
|
22783
|
+
if (newId) layoutPrivateViews(state2);
|
|
22784
|
+
}
|
|
22785
|
+
})
|
|
22786
|
+
);
|
|
22787
|
+
menu.append(
|
|
22788
|
+
new MenuItem({
|
|
22789
|
+
label: "Close Tab",
|
|
22790
|
+
click: () => {
|
|
22791
|
+
tabManager.closeTab(id);
|
|
22792
|
+
layoutPrivateViews(state2);
|
|
22793
|
+
}
|
|
22794
|
+
})
|
|
22795
|
+
);
|
|
22796
|
+
menu.popup({ window: state2.window });
|
|
22797
|
+
});
|
|
22798
|
+
ipc.handle(Channels.IS_PRIVATE_MODE, () => true);
|
|
22799
|
+
ipc.handle(Channels.OPEN_PRIVATE_WINDOW, () => {
|
|
22800
|
+
createPrivateWindow();
|
|
22801
|
+
});
|
|
22802
|
+
ipc.handle(Channels.WINDOW_MINIMIZE, () => {
|
|
22803
|
+
state2.window.minimize();
|
|
22804
|
+
});
|
|
22805
|
+
ipc.handle(Channels.WINDOW_MAXIMIZE, () => {
|
|
22806
|
+
if (state2.window.isMaximized()) {
|
|
22807
|
+
state2.window.unmaximize();
|
|
22808
|
+
} else {
|
|
22809
|
+
state2.window.maximize();
|
|
22810
|
+
}
|
|
22811
|
+
});
|
|
22812
|
+
ipc.handle(Channels.WINDOW_CLOSE, () => {
|
|
22813
|
+
state2.window.close();
|
|
22814
|
+
});
|
|
22815
|
+
ipc.handle(Channels.SETTINGS_VISIBILITY, () => {
|
|
22816
|
+
return false;
|
|
22817
|
+
});
|
|
22818
|
+
ipc.handle(Channels.FOCUS_MODE_TOGGLE, () => false);
|
|
22819
|
+
ipc.handle(Channels.SIDEBAR_TOGGLE, () => ({ open: false, width: 0 }));
|
|
22820
|
+
ipc.handle(Channels.DEVTOOLS_PANEL_TOGGLE, () => ({ open: false }));
|
|
22821
|
+
ipc.handle(
|
|
22822
|
+
Channels.FIND_IN_PAGE_START,
|
|
22823
|
+
(_e, text, options) => {
|
|
22824
|
+
const tab = tabManager.getActiveTab();
|
|
22825
|
+
if (!tab) return null;
|
|
22826
|
+
const wc = tab.view.webContents;
|
|
22827
|
+
if (wc.isDestroyed()) return null;
|
|
22828
|
+
wireFindEvents(wc);
|
|
22829
|
+
return wc.findInPage(text, {
|
|
22830
|
+
forward: options?.forward ?? true,
|
|
22831
|
+
findNext: options?.findNext ?? false
|
|
22832
|
+
});
|
|
22833
|
+
}
|
|
22834
|
+
);
|
|
22835
|
+
ipc.handle(Channels.FIND_IN_PAGE_NEXT, (_e, forward) => {
|
|
22836
|
+
const tab = tabManager.getActiveTab();
|
|
22837
|
+
if (!tab) return null;
|
|
22838
|
+
const wc = tab.view.webContents;
|
|
22839
|
+
if (wc.isDestroyed()) return null;
|
|
22840
|
+
wireFindEvents(wc);
|
|
22841
|
+
return wc.findInPage("", { forward: forward ?? true, findNext: true });
|
|
22842
|
+
});
|
|
22843
|
+
ipc.handle(
|
|
22844
|
+
Channels.FIND_IN_PAGE_STOP,
|
|
22845
|
+
(_e, action) => {
|
|
22846
|
+
const tab = tabManager.getActiveTab();
|
|
22847
|
+
if (!tab) return;
|
|
22848
|
+
const wc = tab.view.webContents;
|
|
22849
|
+
if (wc.isDestroyed()) return;
|
|
22850
|
+
wc.stopFindInPage(action ?? "clearSelection");
|
|
22851
|
+
}
|
|
22852
|
+
);
|
|
22853
|
+
}
|
|
22854
|
+
function createPrivateWindow() {
|
|
22855
|
+
const privateSessionPartition = `private-${crypto$1.randomUUID()}`;
|
|
22856
|
+
const privateSession = electron.session.fromPartition(privateSessionPartition);
|
|
22857
|
+
privateSession.setUserAgent(electron.session.defaultSession.getUserAgent());
|
|
22858
|
+
const win = new electron.BaseWindow({
|
|
22859
|
+
width: 1280,
|
|
22860
|
+
height: 800,
|
|
22861
|
+
minWidth: 800,
|
|
22862
|
+
minHeight: 600,
|
|
22863
|
+
frame: false,
|
|
22864
|
+
show: false,
|
|
22865
|
+
backgroundColor: "#1e1a2e",
|
|
22866
|
+
title: "Vessel - Private Browsing"
|
|
22867
|
+
});
|
|
22868
|
+
const chromeView = new electron.WebContentsView({
|
|
22869
|
+
webPreferences: {
|
|
22870
|
+
preload: path.join(__dirname, "../preload/index.js"),
|
|
22871
|
+
sandbox: true,
|
|
22872
|
+
contextIsolation: true,
|
|
22873
|
+
nodeIntegration: false
|
|
22874
|
+
}
|
|
22875
|
+
});
|
|
22876
|
+
chromeView.setBackgroundColor("#00000000");
|
|
22877
|
+
win.contentView.addChildView(chromeView);
|
|
22878
|
+
const tabManager = new TabManager(
|
|
22879
|
+
win,
|
|
22880
|
+
(tabs, activeId) => {
|
|
22881
|
+
if (!chromeView.webContents.isDestroyed()) {
|
|
22882
|
+
chromeView.webContents.send(Channels.TAB_STATE_UPDATE, tabs, activeId);
|
|
22883
|
+
}
|
|
22884
|
+
layoutPrivateViews(state2);
|
|
22885
|
+
},
|
|
22886
|
+
{ isPrivate: true, sessionPartition: privateSessionPartition }
|
|
22887
|
+
);
|
|
22888
|
+
const state2 = {
|
|
22889
|
+
window: win,
|
|
22890
|
+
chromeView,
|
|
22891
|
+
tabManager,
|
|
22892
|
+
session: privateSession,
|
|
22893
|
+
sessionPartition: privateSessionPartition
|
|
22894
|
+
};
|
|
22895
|
+
installAdBlockingForSession(privateSession, tabManager);
|
|
22896
|
+
installDownloadHandlerForSession(privateSession, chromeView);
|
|
22897
|
+
registerPrivateIpcHandlers(state2);
|
|
22898
|
+
win.on("resize", () => layoutPrivateViews(state2));
|
|
22899
|
+
win.on("show", () => layoutPrivateViews(state2));
|
|
22900
|
+
win.on("closed", () => {
|
|
22901
|
+
privateWindows.delete(state2);
|
|
22902
|
+
tabManager.destroyAllTabs();
|
|
22903
|
+
void Promise.all([
|
|
22904
|
+
privateSession.clearStorageData(),
|
|
22905
|
+
privateSession.clearCache()
|
|
22906
|
+
]).catch((error) => {
|
|
22907
|
+
logger$5.warn("Failed to clear private browsing session:", error);
|
|
22908
|
+
});
|
|
22909
|
+
});
|
|
22910
|
+
privateWindows.add(state2);
|
|
22911
|
+
chromeView.webContents.once("dom-ready", () => {
|
|
22912
|
+
tabManager.createTab("about:blank");
|
|
22913
|
+
layoutPrivateViews(state2);
|
|
22914
|
+
});
|
|
22915
|
+
loadPrivateRenderer(chromeView);
|
|
22916
|
+
win.show();
|
|
22917
|
+
logger$5.info("Private browsing window opened");
|
|
22918
|
+
return state2;
|
|
22919
|
+
}
|
|
22920
|
+
let activeChatProvider = null;
|
|
22921
|
+
const logger$4 = createLogger("IPC");
|
|
22922
|
+
const VALID_APPROVAL_MODES = ["auto", "confirm-dangerous", "manual"];
|
|
22923
|
+
function registerIpcHandlers(windowState, runtime2) {
|
|
22924
|
+
const { tabManager, chromeView, sidebarView, devtoolsPanelView, mainWindow } = windowState;
|
|
22925
|
+
electron.ipcMain.handle(Channels.OPEN_PRIVATE_WINDOW, () => {
|
|
22926
|
+
createPrivateWindow();
|
|
22927
|
+
});
|
|
22928
|
+
electron.ipcMain.handle(Channels.IS_PRIVATE_MODE, () => false);
|
|
22929
|
+
let sidebarResizeRecoveryTimer = null;
|
|
22930
|
+
let sidebarResizeActive = false;
|
|
22931
|
+
let runtimeUpdateTimer = null;
|
|
22932
|
+
let pendingRuntimeState = null;
|
|
22933
|
+
const premiumApiOrigin = process.env.VESSEL_PREMIUM_API ? new URL(process.env.VESSEL_PREMIUM_API).origin : "https://vesselpremium.quantaintellect.com";
|
|
22934
|
+
const clearSidebarResizeRecoveryTimer = () => {
|
|
22935
|
+
if (!sidebarResizeRecoveryTimer) return;
|
|
22936
|
+
clearTimeout(sidebarResizeRecoveryTimer);
|
|
22937
|
+
sidebarResizeRecoveryTimer = null;
|
|
22938
|
+
};
|
|
22939
|
+
const restoreSidebarLayoutAfterResize = () => {
|
|
22940
|
+
clearSidebarResizeRecoveryTimer();
|
|
22941
|
+
if (!sidebarResizeActive) return;
|
|
22942
|
+
sidebarResizeActive = false;
|
|
22943
|
+
layoutViews(windowState);
|
|
22944
|
+
};
|
|
22945
|
+
const scheduleSidebarResizeRecovery = () => {
|
|
22946
|
+
clearSidebarResizeRecoveryTimer();
|
|
22947
|
+
sidebarResizeRecoveryTimer = setTimeout(() => {
|
|
22948
|
+
restoreSidebarLayoutAfterResize();
|
|
22949
|
+
}, 1200);
|
|
22950
|
+
};
|
|
22951
|
+
const flushRuntimeUpdate = () => {
|
|
22952
|
+
runtimeUpdateTimer = null;
|
|
22953
|
+
if (!pendingRuntimeState) return;
|
|
22954
|
+
if (!chromeView.webContents.isDestroyed()) {
|
|
22955
|
+
chromeView.webContents.send(
|
|
22956
|
+
Channels.AGENT_RUNTIME_UPDATE,
|
|
22957
|
+
pendingRuntimeState
|
|
22958
|
+
);
|
|
22959
|
+
}
|
|
22960
|
+
if (!sidebarView.webContents.isDestroyed()) {
|
|
22961
|
+
sidebarView.webContents.send(
|
|
22962
|
+
Channels.AGENT_RUNTIME_UPDATE,
|
|
22963
|
+
pendingRuntimeState
|
|
22964
|
+
);
|
|
22965
|
+
}
|
|
22966
|
+
pendingRuntimeState = null;
|
|
22967
|
+
};
|
|
22968
|
+
const scheduleRuntimeUpdate = (state2) => {
|
|
22969
|
+
pendingRuntimeState = state2;
|
|
22970
|
+
if (runtimeUpdateTimer) return;
|
|
22971
|
+
runtimeUpdateTimer = setTimeout(() => {
|
|
22972
|
+
flushRuntimeUpdate();
|
|
22973
|
+
}, 32);
|
|
22974
|
+
};
|
|
22975
|
+
electron.app.on("before-quit", () => {
|
|
22976
|
+
if (runtimeUpdateTimer) {
|
|
22977
|
+
clearTimeout(runtimeUpdateTimer);
|
|
22978
|
+
runtimeUpdateTimer = null;
|
|
22979
|
+
}
|
|
22980
|
+
flushRuntimeUpdate();
|
|
22981
|
+
});
|
|
22982
|
+
const sendToRendererViews = (channel, ...args) => {
|
|
22983
|
+
chromeView.webContents.send(channel, ...args);
|
|
22984
|
+
sidebarView.webContents.send(channel, ...args);
|
|
22985
|
+
devtoolsPanelView.webContents.send(channel, ...args);
|
|
22986
|
+
};
|
|
22987
|
+
const watchPremiumCheckoutTab = (tabId) => {
|
|
22988
|
+
const tab = tabManager.getTab(tabId);
|
|
22989
|
+
const wc = tab?.view.webContents;
|
|
22990
|
+
if (!wc) return;
|
|
22991
|
+
let completed = false;
|
|
22992
|
+
const cleanup = () => {
|
|
22993
|
+
wc.removeListener("did-navigate", onNavigate);
|
|
22994
|
+
wc.removeListener("did-navigate-in-page", onNavigateInPage);
|
|
22995
|
+
wc.removeListener("destroyed", cleanup);
|
|
22996
|
+
};
|
|
22997
|
+
const handleUrl = async (rawUrl) => {
|
|
22998
|
+
if (completed) return;
|
|
22999
|
+
let parsed;
|
|
23000
|
+
try {
|
|
23001
|
+
parsed = new URL(rawUrl);
|
|
23002
|
+
} catch (err) {
|
|
23003
|
+
logger$4.warn("Failed to parse premium checkout URL while watching checkout tab:", err);
|
|
23004
|
+
return;
|
|
23005
|
+
}
|
|
23006
|
+
if (parsed.origin !== premiumApiOrigin) return;
|
|
23007
|
+
if (parsed.pathname === "/canceled") {
|
|
23008
|
+
completed = true;
|
|
23009
|
+
trackPremiumFunnel("checkout_canceled");
|
|
23010
|
+
cleanup();
|
|
22493
23011
|
return;
|
|
22494
23012
|
}
|
|
22495
23013
|
if (parsed.pathname !== "/success") return;
|
|
@@ -22595,6 +23113,52 @@ function registerIpcHandlers(windowState, runtime2) {
|
|
|
22595
23113
|
tab.setAdBlockingEnabled(newState);
|
|
22596
23114
|
return newState;
|
|
22597
23115
|
});
|
|
23116
|
+
electron.ipcMain.handle(Channels.TAB_ZOOM_IN, (_, id) => {
|
|
23117
|
+
assertString(id, "id");
|
|
23118
|
+
tabManager.zoomIn(id);
|
|
23119
|
+
});
|
|
23120
|
+
electron.ipcMain.handle(Channels.TAB_ZOOM_OUT, (_, id) => {
|
|
23121
|
+
assertString(id, "id");
|
|
23122
|
+
tabManager.zoomOut(id);
|
|
23123
|
+
});
|
|
23124
|
+
electron.ipcMain.handle(Channels.TAB_ZOOM_RESET, (_, id) => {
|
|
23125
|
+
assertString(id, "id");
|
|
23126
|
+
tabManager.zoomReset(id);
|
|
23127
|
+
});
|
|
23128
|
+
electron.ipcMain.handle(Channels.TAB_REOPEN_CLOSED, () => {
|
|
23129
|
+
const id = tabManager.reopenClosedTab();
|
|
23130
|
+
if (id) layoutViews(windowState);
|
|
23131
|
+
return id;
|
|
23132
|
+
});
|
|
23133
|
+
electron.ipcMain.handle(Channels.TAB_DUPLICATE, (_, id) => {
|
|
23134
|
+
assertString(id, "id");
|
|
23135
|
+
const newId = tabManager.duplicateTab(id);
|
|
23136
|
+
if (newId) layoutViews(windowState);
|
|
23137
|
+
return newId;
|
|
23138
|
+
});
|
|
23139
|
+
electron.ipcMain.on(Channels.TAB_CONTEXT_MENU, (_event, id) => {
|
|
23140
|
+
assertString(id, "id");
|
|
23141
|
+
const menu = new electron.Menu();
|
|
23142
|
+
menu.append(
|
|
23143
|
+
new electron.MenuItem({
|
|
23144
|
+
label: "Duplicate Tab",
|
|
23145
|
+
click: () => {
|
|
23146
|
+
const newId = tabManager.duplicateTab(id);
|
|
23147
|
+
if (newId) layoutViews(windowState);
|
|
23148
|
+
}
|
|
23149
|
+
})
|
|
23150
|
+
);
|
|
23151
|
+
menu.append(
|
|
23152
|
+
new electron.MenuItem({
|
|
23153
|
+
label: "Close Tab",
|
|
23154
|
+
click: () => {
|
|
23155
|
+
tabManager.closeTab(id);
|
|
23156
|
+
layoutViews(windowState);
|
|
23157
|
+
}
|
|
23158
|
+
})
|
|
23159
|
+
);
|
|
23160
|
+
menu.popup({ window: mainWindow });
|
|
23161
|
+
});
|
|
22598
23162
|
electron.ipcMain.handle(Channels.TAB_STATE_GET, () => ({
|
|
22599
23163
|
tabs: tabManager.getAllStates(),
|
|
22600
23164
|
activeId: tabManager.getActiveTabId() || ""
|
|
@@ -24102,157 +24666,6 @@ ${progress}
|
|
|
24102
24666
|
});
|
|
24103
24667
|
}
|
|
24104
24668
|
}
|
|
24105
|
-
const BLOCKED_RESOURCE_TYPES = /* @__PURE__ */ new Set([
|
|
24106
|
-
"script",
|
|
24107
|
-
"image",
|
|
24108
|
-
"xhr",
|
|
24109
|
-
"fetch",
|
|
24110
|
-
"subFrame",
|
|
24111
|
-
"media",
|
|
24112
|
-
"ping",
|
|
24113
|
-
"webSocket"
|
|
24114
|
-
]);
|
|
24115
|
-
const BLOCKED_HOST_SUFFIXES = [
|
|
24116
|
-
"doubleclick.net",
|
|
24117
|
-
"googlesyndication.com",
|
|
24118
|
-
"googleadservices.com",
|
|
24119
|
-
"adservice.google.com",
|
|
24120
|
-
"adnxs.com",
|
|
24121
|
-
"adsrvr.org",
|
|
24122
|
-
"taboola.com",
|
|
24123
|
-
"outbrain.com",
|
|
24124
|
-
"criteo.com",
|
|
24125
|
-
"criteo.net",
|
|
24126
|
-
"pubmatic.com",
|
|
24127
|
-
"rubiconproject.com",
|
|
24128
|
-
"openx.net",
|
|
24129
|
-
"casalemedia.com",
|
|
24130
|
-
"advertising.com",
|
|
24131
|
-
"amazon-adsystem.com",
|
|
24132
|
-
"adsymptotic.com",
|
|
24133
|
-
"moatads.com",
|
|
24134
|
-
"quantserve.com",
|
|
24135
|
-
"scorecardresearch.com"
|
|
24136
|
-
];
|
|
24137
|
-
const THIRD_PARTY_PATH_PATTERNS = [
|
|
24138
|
-
/\/ads?[/?._-]/i,
|
|
24139
|
-
/\/adservice/i,
|
|
24140
|
-
/\/advert/i,
|
|
24141
|
-
/\/prebid/i,
|
|
24142
|
-
/\/banner/i,
|
|
24143
|
-
/\/sponsor/i,
|
|
24144
|
-
/\/promotions?\//i,
|
|
24145
|
-
/\/trk\//i,
|
|
24146
|
-
/\/track(ing)?\//i,
|
|
24147
|
-
/\/beacon/i,
|
|
24148
|
-
/\/pixel/i
|
|
24149
|
-
];
|
|
24150
|
-
let installed = false;
|
|
24151
|
-
function normalizeHostname(value) {
|
|
24152
|
-
return value.trim().toLowerCase().replace(/\.$/, "");
|
|
24153
|
-
}
|
|
24154
|
-
function hostnameMatches(hostname, suffix) {
|
|
24155
|
-
return hostname === suffix || hostname.endsWith(`.${suffix}`);
|
|
24156
|
-
}
|
|
24157
|
-
function parseHostname(url) {
|
|
24158
|
-
try {
|
|
24159
|
-
const parsed = new URL(url);
|
|
24160
|
-
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
24161
|
-
return null;
|
|
24162
|
-
}
|
|
24163
|
-
return normalizeHostname(parsed.hostname);
|
|
24164
|
-
} catch {
|
|
24165
|
-
return null;
|
|
24166
|
-
}
|
|
24167
|
-
}
|
|
24168
|
-
function isThirdParty(url, firstPartyHost) {
|
|
24169
|
-
if (!firstPartyHost) return true;
|
|
24170
|
-
const target = normalizeHostname(url.hostname);
|
|
24171
|
-
return !(target === firstPartyHost || target.endsWith(`.${firstPartyHost}`));
|
|
24172
|
-
}
|
|
24173
|
-
function shouldBlockRequest(details) {
|
|
24174
|
-
if (!BLOCKED_RESOURCE_TYPES.has(details.resourceType)) return false;
|
|
24175
|
-
let parsed;
|
|
24176
|
-
try {
|
|
24177
|
-
parsed = new URL(details.url);
|
|
24178
|
-
} catch {
|
|
24179
|
-
return false;
|
|
24180
|
-
}
|
|
24181
|
-
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
24182
|
-
return false;
|
|
24183
|
-
}
|
|
24184
|
-
const hostname = normalizeHostname(parsed.hostname);
|
|
24185
|
-
if (BLOCKED_HOST_SUFFIXES.some((suffix) => hostnameMatches(hostname, suffix))) {
|
|
24186
|
-
return true;
|
|
24187
|
-
}
|
|
24188
|
-
const firstPartyHost = parseHostname(details.referrer) || parseHostname(details.initiator || "");
|
|
24189
|
-
if (!isThirdParty(parsed, firstPartyHost)) return false;
|
|
24190
|
-
const candidate = `${hostname}${parsed.pathname}${parsed.search}`;
|
|
24191
|
-
return THIRD_PARTY_PATH_PATTERNS.some((pattern) => pattern.test(candidate));
|
|
24192
|
-
}
|
|
24193
|
-
function installAdBlocking(tabManager) {
|
|
24194
|
-
if (installed) return;
|
|
24195
|
-
installed = true;
|
|
24196
|
-
electron.session.defaultSession.webRequest.onBeforeRequest((details, callback) => {
|
|
24197
|
-
const webContentsId = typeof details.webContentsId === "number" ? details.webContentsId : null;
|
|
24198
|
-
if (webContentsId == null) {
|
|
24199
|
-
callback({});
|
|
24200
|
-
return;
|
|
24201
|
-
}
|
|
24202
|
-
if (!tabManager.isAdBlockingEnabledForWebContents(webContentsId)) {
|
|
24203
|
-
callback({});
|
|
24204
|
-
return;
|
|
24205
|
-
}
|
|
24206
|
-
callback({ cancel: shouldBlockRequest(details) });
|
|
24207
|
-
});
|
|
24208
|
-
}
|
|
24209
|
-
function resolveDownloadPath(downloadDir, filename) {
|
|
24210
|
-
fs$1.mkdirSync(downloadDir, { recursive: true });
|
|
24211
|
-
const parsed = path.parse(filename);
|
|
24212
|
-
let attempt = 0;
|
|
24213
|
-
while (true) {
|
|
24214
|
-
const candidateName = attempt === 0 ? filename : `${parsed.name} (${attempt})${parsed.ext}`;
|
|
24215
|
-
const candidatePath = path.join(downloadDir, candidateName);
|
|
24216
|
-
if (!fs$1.existsSync(candidatePath)) {
|
|
24217
|
-
return candidatePath;
|
|
24218
|
-
}
|
|
24219
|
-
attempt += 1;
|
|
24220
|
-
}
|
|
24221
|
-
}
|
|
24222
|
-
function installDownloadHandler(chromeView) {
|
|
24223
|
-
electron.session.defaultSession.on("will-download", (_event, item) => {
|
|
24224
|
-
const settings2 = loadSettings();
|
|
24225
|
-
const downloadDir = settings2.downloadPath.trim() || electron.app.getPath("downloads");
|
|
24226
|
-
const filename = item.getFilename();
|
|
24227
|
-
const savePath = resolveDownloadPath(downloadDir, filename);
|
|
24228
|
-
item.setSavePath(savePath);
|
|
24229
|
-
const info = {
|
|
24230
|
-
filename,
|
|
24231
|
-
savePath,
|
|
24232
|
-
totalBytes: item.getTotalBytes(),
|
|
24233
|
-
receivedBytes: 0,
|
|
24234
|
-
state: "progressing"
|
|
24235
|
-
};
|
|
24236
|
-
if (!chromeView.webContents.isDestroyed()) {
|
|
24237
|
-
chromeView.webContents.send(Channels.DOWNLOAD_STARTED, info);
|
|
24238
|
-
}
|
|
24239
|
-
item.on("updated", (_event2, state2) => {
|
|
24240
|
-
info.receivedBytes = item.getReceivedBytes();
|
|
24241
|
-
info.totalBytes = item.getTotalBytes();
|
|
24242
|
-
info.state = state2 === "progressing" ? "progressing" : "interrupted";
|
|
24243
|
-
if (!chromeView.webContents.isDestroyed()) {
|
|
24244
|
-
chromeView.webContents.send(Channels.DOWNLOAD_PROGRESS, info);
|
|
24245
|
-
}
|
|
24246
|
-
});
|
|
24247
|
-
item.once("done", (_event2, state2) => {
|
|
24248
|
-
info.receivedBytes = item.getReceivedBytes();
|
|
24249
|
-
info.state = state2 === "completed" ? "completed" : "cancelled";
|
|
24250
|
-
if (!chromeView.webContents.isDestroyed()) {
|
|
24251
|
-
chromeView.webContents.send(Channels.DOWNLOAD_DONE, info);
|
|
24252
|
-
}
|
|
24253
|
-
});
|
|
24254
|
-
});
|
|
24255
|
-
}
|
|
24256
24669
|
const logger$2 = createLogger("Shortcuts");
|
|
24257
24670
|
function registerHighlightShortcut(mainWindow, tabManager) {
|
|
24258
24671
|
const register = () => {
|
|
@@ -24273,8 +24686,18 @@ function registerHighlightShortcut(mainWindow, tabManager) {
|
|
|
24273
24686
|
mainWindow.removeListener("focus", register);
|
|
24274
24687
|
};
|
|
24275
24688
|
}
|
|
24276
|
-
function setupAppMenu() {
|
|
24689
|
+
function setupAppMenu(handlers) {
|
|
24277
24690
|
const appMenu = electron.Menu.buildFromTemplate([
|
|
24691
|
+
{
|
|
24692
|
+
label: "File",
|
|
24693
|
+
submenu: [
|
|
24694
|
+
{
|
|
24695
|
+
label: "Reopen Closed Tab",
|
|
24696
|
+
accelerator: "CommandOrControl+Shift+T",
|
|
24697
|
+
click: handlers.reopenClosedTab
|
|
24698
|
+
}
|
|
24699
|
+
]
|
|
24700
|
+
},
|
|
24278
24701
|
{
|
|
24279
24702
|
label: "Edit",
|
|
24280
24703
|
submenu: [
|
|
@@ -24286,6 +24709,26 @@ function setupAppMenu() {
|
|
|
24286
24709
|
{ role: "paste" },
|
|
24287
24710
|
{ role: "selectAll" }
|
|
24288
24711
|
]
|
|
24712
|
+
},
|
|
24713
|
+
{
|
|
24714
|
+
label: "View",
|
|
24715
|
+
submenu: [
|
|
24716
|
+
{
|
|
24717
|
+
label: "Zoom In",
|
|
24718
|
+
accelerator: "CommandOrControl+Plus",
|
|
24719
|
+
click: handlers.zoomIn
|
|
24720
|
+
},
|
|
24721
|
+
{
|
|
24722
|
+
label: "Zoom Out",
|
|
24723
|
+
accelerator: "CommandOrControl+-",
|
|
24724
|
+
click: handlers.zoomOut
|
|
24725
|
+
},
|
|
24726
|
+
{
|
|
24727
|
+
label: "Actual Size",
|
|
24728
|
+
accelerator: "CommandOrControl+0",
|
|
24729
|
+
click: handlers.zoomReset
|
|
24730
|
+
}
|
|
24731
|
+
]
|
|
24289
24732
|
}
|
|
24290
24733
|
]);
|
|
24291
24734
|
electron.Menu.setApplicationMenu(appMenu);
|
|
@@ -24644,7 +25087,24 @@ async function bootstrap() {
|
|
|
24644
25087
|
});
|
|
24645
25088
|
registerIpcHandlers(windowState, runtime);
|
|
24646
25089
|
registerHighlightShortcut(windowState.mainWindow, tabManager);
|
|
24647
|
-
setupAppMenu(
|
|
25090
|
+
setupAppMenu({
|
|
25091
|
+
reopenClosedTab: () => {
|
|
25092
|
+
const id = tabManager.reopenClosedTab();
|
|
25093
|
+
if (id) layoutViews(windowState);
|
|
25094
|
+
},
|
|
25095
|
+
zoomIn: () => {
|
|
25096
|
+
const id = tabManager.getActiveTabId();
|
|
25097
|
+
if (id) tabManager.zoomIn(id);
|
|
25098
|
+
},
|
|
25099
|
+
zoomOut: () => {
|
|
25100
|
+
const id = tabManager.getActiveTabId();
|
|
25101
|
+
if (id) tabManager.zoomOut(id);
|
|
25102
|
+
},
|
|
25103
|
+
zoomReset: () => {
|
|
25104
|
+
const id = tabManager.getActiveTabId();
|
|
25105
|
+
if (id) tabManager.zoomReset(id);
|
|
25106
|
+
}
|
|
25107
|
+
});
|
|
24648
25108
|
subscribe((state2) => {
|
|
24649
25109
|
chromeView.webContents.send(Channels.BOOKMARKS_UPDATE, state2);
|
|
24650
25110
|
sidebarView.webContents.send(Channels.BOOKMARKS_UPDATE, state2);
|