@quanta-intellect/vessel-browser 0.1.132 → 0.1.134

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
@@ -114,7 +114,7 @@ const defaults = {
114
114
  const SAVE_DEBOUNCE_MS$6 = 150;
115
115
  const CHAT_PROVIDER_SECRET_FILENAME = "vessel-chat-provider-secret";
116
116
  const CODEX_TOKENS_FILENAME = "vessel-codex-tokens";
117
- const logger$v = createLogger("Settings");
117
+ const logger$x = createLogger("Settings");
118
118
  const SETTABLE_KEYS = new Set(Object.keys(defaults));
119
119
  let settings = null;
120
120
  let settingsIssues = [];
@@ -139,7 +139,7 @@ function canUseSafeStorage$1() {
139
139
  try {
140
140
  return electron.safeStorage.isEncryptionAvailable();
141
141
  } catch (err) {
142
- logger$v.warn("safeStorage.isEncryptionAvailable() failed, assuming unavailable:", err);
142
+ logger$x.warn("safeStorage.isEncryptionAvailable() failed, assuming unavailable:", err);
143
143
  return false;
144
144
  }
145
145
  }
@@ -148,7 +148,7 @@ function writePrivateFile(filePath2, data) {
148
148
  try {
149
149
  fs.chmodSync(filePath2, 384);
150
150
  } catch (err) {
151
- logger$v.debug("Could not chmod private file (non-POSIX filesystem):", err);
151
+ logger$x.debug("Could not chmod private file (non-POSIX filesystem):", err);
152
152
  }
153
153
  }
154
154
  function assertSafeStorageAvailable() {
@@ -167,7 +167,7 @@ function readStoredProviderSecret() {
167
167
  }
168
168
  } catch (err) {
169
169
  if (!isMissingFileError(err)) {
170
- logger$v.warn("Could not read stored provider secret:", err);
170
+ logger$x.warn("Could not read stored provider secret:", err);
171
171
  }
172
172
  }
173
173
  return null;
@@ -185,7 +185,7 @@ function clearStoredProviderSecret() {
185
185
  fs.unlinkSync(getChatProviderSecretPath());
186
186
  } catch (err) {
187
187
  if (!isMissingFileError(err)) {
188
- logger$v.warn("Could not delete provider secret file:", err);
188
+ logger$x.warn("Could not delete provider secret file:", err);
189
189
  }
190
190
  }
191
191
  }
@@ -203,7 +203,7 @@ function readStoredCodexTokens() {
203
203
  }
204
204
  } catch (err) {
205
205
  if (!isMissingFileError(err)) {
206
- logger$v.warn("Could not read stored Codex tokens:", err);
206
+ logger$x.warn("Could not read stored Codex tokens:", err);
207
207
  }
208
208
  }
209
209
  return null;
@@ -221,7 +221,7 @@ function clearStoredCodexTokens() {
221
221
  fs.unlinkSync(getCodexTokensPath());
222
222
  } catch (err) {
223
223
  if (!isMissingFileError(err)) {
224
- logger$v.warn("Could not delete Codex token file:", err);
224
+ logger$x.warn("Could not delete Codex token file:", err);
225
225
  }
226
226
  }
227
227
  }
@@ -351,7 +351,9 @@ function persistNow() {
351
351
  JSON.stringify(buildPersistedSettings(settings), null, 2),
352
352
  { encoding: "utf-8", mode: 384 }
353
353
  )
354
- ).then(() => fs.promises.chmod(getSettingsPath(), 384).catch(() => void 0)).catch((err) => logger$v.error("Failed to save settings:", err));
354
+ ).then(() => fs.promises.chmod(getSettingsPath(), 384).catch((err) => {
355
+ logger$x.warn("Failed to chmod settings file:", err);
356
+ })).catch((err) => logger$x.error("Failed to save settings:", err));
355
357
  }
356
358
  function saveSettings() {
357
359
  saveDirty = true;
@@ -530,7 +532,7 @@ const urlSafety = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePro
530
532
  }, Symbol.toStringTag, { value: "Module" }));
531
533
  const MAX_CUSTOM_HISTORY = 50;
532
534
  const READER_MODE_DATA_URL_PREFIX = "data:text/html;charset=utf-8,";
533
- const logger$u = createLogger("Tab");
535
+ const logger$w = createLogger("Tab");
534
536
  const sessionCertExceptions = /* @__PURE__ */ new WeakMap();
535
537
  const sessionsWithVerifyProc = /* @__PURE__ */ new WeakSet();
536
538
  const CERT_VERIFY_TRUST = 0;
@@ -596,7 +598,7 @@ class Tab {
596
598
  guardedLoadURL(url, options) {
597
599
  const blockReason = this.getNavigationBlockReason(url);
598
600
  if (blockReason) {
599
- logger$u.warn(blockReason);
601
+ logger$w.warn(blockReason);
600
602
  return blockReason;
601
603
  }
602
604
  void this.view.webContents.loadURL(url, options);
@@ -680,7 +682,7 @@ class Tab {
680
682
  wc.setWindowOpenHandler(({ url, disposition }) => {
681
683
  const error = this.getNavigationBlockReason(url);
682
684
  if (error) {
683
- logger$u.warn(error);
685
+ logger$w.warn(error);
684
686
  return { action: "deny" };
685
687
  }
686
688
  this.onOpenUrl?.({
@@ -694,7 +696,7 @@ class Tab {
694
696
  const error = this.getNavigationBlockReason(url);
695
697
  if (!error) return;
696
698
  event.preventDefault();
697
- logger$u.warn(`${context}: ${error}`);
699
+ logger$w.warn(`${context}: ${error}`);
698
700
  };
699
701
  wc.on("will-navigate", (event, url) => {
700
702
  blockNavigation(event, url, "Blocked top-level navigation");
@@ -778,7 +780,7 @@ class Tab {
778
780
  ::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.12); border-radius: 999px; }
779
781
  ::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,0.22); }
780
782
  ::-webkit-scrollbar-corner { background: transparent; }
781
- `).catch((err) => logger$u.warn("Failed to inject scrollbar CSS:", err));
783
+ `).catch((err) => logger$w.warn("Failed to inject scrollbar CSS:", err));
782
784
  });
783
785
  wc.on("page-favicon-updated", (_, favicons) => {
784
786
  this._state.favicon = favicons[0] || "";
@@ -814,7 +816,7 @@ class Tab {
814
816
  ).then((highlightedText) => {
815
817
  this.buildContextMenu(wc, params, highlightedText.trim());
816
818
  }).catch((err) => {
817
- logger$u.warn("Failed to inspect highlighted text for context menu:", err);
819
+ logger$w.warn("Failed to inspect highlighted text for context menu:", err);
818
820
  this.buildContextMenu(wc, params, "");
819
821
  });
820
822
  });
@@ -1015,7 +1017,7 @@ class Tab {
1015
1017
  "document.documentElement.outerHTML"
1016
1018
  );
1017
1019
  } catch (err) {
1018
- logger$u.warn("Failed to retrieve page source:", err);
1020
+ logger$w.warn("Failed to retrieve page source:", err);
1019
1021
  return;
1020
1022
  }
1021
1023
  const escaped = html.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
@@ -1135,7 +1137,9 @@ class Tab {
1135
1137
  range.insertNode(mark);
1136
1138
  }
1137
1139
  }
1138
- } catch(e) {}
1140
+ } catch {
1141
+ // Swallow — complex cross-node selections may fail to wrap
1142
+ }
1139
1143
  sel.removeAllRanges();
1140
1144
  // Notify main process for persistence
1141
1145
  window.__vessel.notifyHighlightSelection(text);
@@ -1143,7 +1147,7 @@ class Tab {
1143
1147
  document.addEventListener('mouseup', window.__vesselHighlightHandler);
1144
1148
  }
1145
1149
  })()
1146
- `).catch((err) => logger$u.warn("Failed to inject highlight listener:", err));
1150
+ `).catch((err) => logger$w.warn("Failed to inject highlight listener:", err));
1147
1151
  } else {
1148
1152
  void wc.executeJavaScript(`
1149
1153
  (function() {
@@ -1154,7 +1158,7 @@ class Tab {
1154
1158
  delete window.__vesselHighlightHandler;
1155
1159
  }
1156
1160
  })()
1157
- `).catch((err) => logger$u.warn("Failed to remove highlight listener:", err));
1161
+ `).catch((err) => logger$w.warn("Failed to remove highlight listener:", err));
1158
1162
  }
1159
1163
  }
1160
1164
  get webContentsId() {
@@ -1191,7 +1195,7 @@ const SEARCH_ENGINE_PRESETS = {
1191
1195
  ecosia: { label: "Ecosia", url: "https://www.ecosia.org/search?q=" },
1192
1196
  kagi: { label: "Kagi", url: "https://kagi.com/search?q=" }
1193
1197
  };
1194
- const logger$t = createLogger("JsonPersistence");
1198
+ const logger$v = createLogger("JsonPersistence");
1195
1199
  function canUseSafeStorage() {
1196
1200
  try {
1197
1201
  return electron.safeStorage.isEncryptionAvailable();
@@ -1256,7 +1260,9 @@ function createDebouncedJsonPersistence({
1256
1260
  data,
1257
1261
  typeof data === "string" ? { encoding: "utf-8", mode: 384 } : { mode: 384 }
1258
1262
  )
1259
- ).then(() => fs.promises.chmod(filePath2, 384).catch(() => void 0)).catch((err) => logger$t.error(`Failed to save ${logLabel}:`, err));
1263
+ ).then(() => fs.promises.chmod(filePath2, 384).catch((err) => {
1264
+ logger$v.warn(`Failed to chmod ${logLabel}:`, err);
1265
+ })).catch((err) => logger$v.error(`Failed to save ${logLabel}:`, err));
1260
1266
  };
1261
1267
  const schedule = () => {
1262
1268
  saveDirty2 = true;
@@ -1529,7 +1535,7 @@ function applyTextRangeMatch(match, solidColor, bgColor, fullText) {
1529
1535
  try {
1530
1536
  var mark = markTextSegment(segments[i], solidColor, bgColor, fullText);
1531
1537
  if (mark) marks.unshift(mark);
1532
- } catch (_e) {}
1538
+ } catch (_e) { /* text segment couldn't be marked — it may overlap other highlights */ }
1533
1539
  }
1534
1540
  return marks;
1535
1541
  }
@@ -1869,7 +1875,7 @@ async function highlightBatchOnPage(wc, entries) {
1869
1875
  el.style.setProperty('outline-color', c.solid, 'important');
1870
1876
  el.style.setProperty('box-shadow', '0 0 8px ' + c.glow, 'important');
1871
1877
  }
1872
- } catch (_e) {}
1878
+ } catch (_e) { /* selector may not exist on current page */ }
1873
1879
  }
1874
1880
  }
1875
1881
  })()
@@ -2948,7 +2954,7 @@ function destroySession(tabId) {
2948
2954
  sessions.delete(tabId);
2949
2955
  }
2950
2956
  }
2951
- const logger$s = createLogger("TabManager");
2957
+ const logger$u = createLogger("TabManager");
2952
2958
  function sanitizeFilename(title, ext) {
2953
2959
  const clean = title.replace(/[<>:"/\\|?*\x00-\x1f]/g, " ").replace(/\s+/g, " ").trim();
2954
2960
  const escapedExt = ext.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
@@ -3367,7 +3373,7 @@ class TabManager {
3367
3373
  }));
3368
3374
  if (entries.length > 0) {
3369
3375
  void highlightBatchOnPage(wc, entries).catch(
3370
- (err) => logger$s.warn("Failed to batch highlight:", err)
3376
+ (err) => logger$u.warn("Failed to batch highlight:", err)
3371
3377
  );
3372
3378
  }
3373
3379
  }
@@ -3389,12 +3395,12 @@ class TabManager {
3389
3395
  const result = await captureSelectionHighlight(wc);
3390
3396
  if (result.success && result.text) {
3391
3397
  await highlightOnPage(wc, null, result.text, void 0, void 0, "yellow").catch(
3392
- (err) => logger$s.warn("Failed to capture highlight:", err)
3398
+ (err) => logger$u.warn("Failed to capture highlight:", err)
3393
3399
  );
3394
3400
  }
3395
3401
  this.highlightCaptureCallback?.(result);
3396
3402
  } catch (err) {
3397
- logger$s.warn("Failed to capture highlight from page:", err);
3403
+ logger$u.warn("Failed to capture highlight from page:", err);
3398
3404
  this.highlightCaptureCallback?.({
3399
3405
  success: false,
3400
3406
  message: "Could not capture selection"
@@ -3419,7 +3425,7 @@ class TabManager {
3419
3425
  void this.removeHighlightMarksForText(wc, text);
3420
3426
  }
3421
3427
  } catch (err) {
3422
- logger$s.warn("Failed to remove highlight from matching tab:", err);
3428
+ logger$u.warn("Failed to remove highlight from matching tab:", err);
3423
3429
  }
3424
3430
  }
3425
3431
  this.highlightCaptureCallback?.({
@@ -3450,12 +3456,12 @@ class TabManager {
3450
3456
  void 0,
3451
3457
  color
3452
3458
  ).catch(
3453
- (err) => logger$s.warn("Failed to update highlight color:", err)
3459
+ (err) => logger$u.warn("Failed to update highlight color:", err)
3454
3460
  );
3455
3461
  });
3456
3462
  }
3457
3463
  } catch (err) {
3458
- logger$s.warn("Failed to iterate highlights for color change:", err);
3464
+ logger$u.warn("Failed to iterate highlights for color change:", err);
3459
3465
  }
3460
3466
  }
3461
3467
  this.highlightCaptureCallback?.({
@@ -3510,7 +3516,7 @@ class TabManager {
3510
3516
  });
3511
3517
  })()`
3512
3518
  ).catch(
3513
- (err) => logger$s.warn("Failed to remove highlight marks:", err)
3519
+ (err) => logger$u.warn("Failed to remove highlight marks:", err)
3514
3520
  );
3515
3521
  }
3516
3522
  broadcastState(meta = { persistSession: false }) {
@@ -3532,9 +3538,6 @@ const AIChannels = {
3532
3538
  AI_STREAM_END: "ai:stream-end",
3533
3539
  AI_STREAM_IDLE: "ai:stream-idle",
3534
3540
  AI_RESEARCH_CLARIFICATION: "ai:research-clarification",
3535
- AUTOMATION_ACTIVITY_START: "automation:activity-start",
3536
- AUTOMATION_ACTIVITY_CHUNK: "automation:activity-chunk",
3537
- AUTOMATION_ACTIVITY_END: "automation:activity-end",
3538
3541
  AI_CANCEL: "ai:cancel",
3539
3542
  AI_FETCH_MODELS: "ai:fetch-models",
3540
3543
  AGENT_RUNTIME_GET: "agent-runtime:get",
@@ -3561,6 +3564,9 @@ const AutomationChannels = {
3561
3564
  AUTOMATION_GET_INSTALLED: "automation:get-installed",
3562
3565
  AUTOMATION_INSTALL_FROM_FILE: "automation:install-from-file",
3563
3566
  AUTOMATION_UNINSTALL: "automation:uninstall",
3567
+ AUTOMATION_ACTIVITY_START: "automation:activity-start",
3568
+ AUTOMATION_ACTIVITY_CHUNK: "automation:activity-chunk",
3569
+ AUTOMATION_ACTIVITY_END: "automation:activity-end",
3564
3570
  SCHEDULE_GET_ALL: "schedule:get-all",
3565
3571
  SCHEDULE_CREATE: "schedule:create",
3566
3572
  SCHEDULE_UPDATE: "schedule:update",
@@ -3646,6 +3652,9 @@ const HumanVaultChannels = {
3646
3652
  HUMAN_VAULT_REMOVE: "human-vault:remove",
3647
3653
  HUMAN_VAULT_AUDIT_LOG: "human-vault:audit-log"
3648
3654
  };
3655
+ const McpChannels = {
3656
+ MCP_REGENERATE_TOKEN: "mcp:regenerate-token"
3657
+ };
3649
3658
  const OpenRouterChannels = {
3650
3659
  OPENROUTER_START_AUTH: "openrouter:start-auth",
3651
3660
  OPENROUTER_CANCEL_AUTH: "openrouter:cancel-auth",
@@ -3695,8 +3704,9 @@ const SettingsChannels = {
3695
3704
  SETTINGS_SET: "settings:set",
3696
3705
  SETTINGS_UPDATE: "settings:update",
3697
3706
  SETTINGS_HEALTH_GET: "settings:health:get",
3698
- SETTINGS_HEALTH_UPDATE: "settings:health:update",
3699
- MCP_REGENERATE_TOKEN: "mcp:regenerate-token",
3707
+ SETTINGS_HEALTH_UPDATE: "settings:health:update"
3708
+ };
3709
+ const SupportChannels = {
3700
3710
  SUPPORT_SUBMIT_FEEDBACK: "support:submit-feedback"
3701
3711
  };
3702
3712
  const TabChannels = {
@@ -3728,14 +3738,7 @@ const TabChannels = {
3728
3738
  TAB_TOGGLE_MUTE: "tab:toggle-mute",
3729
3739
  TAB_PRINT: "tab:print",
3730
3740
  TAB_PRINT_TO_PDF: "tab:print-to-pdf",
3731
- TAB_TOGGLE_PIP: "tab:toggle-pip",
3732
- OPEN_NEW_WINDOW: "window:open-new",
3733
- OPEN_PRIVATE_WINDOW: "private:open-window",
3734
- IS_PRIVATE_MODE: "private:is-private",
3735
- FIND_IN_PAGE_START: "find:start",
3736
- FIND_IN_PAGE_NEXT: "find:next",
3737
- FIND_IN_PAGE_STOP: "find:stop",
3738
- FIND_IN_PAGE_RESULT: "find:result"
3741
+ TAB_TOGGLE_PIP: "tab:toggle-pip"
3739
3742
  };
3740
3743
  const UIChannels = {
3741
3744
  SIDEBAR_TOGGLE: "ui:sidebar-toggle",
@@ -3764,7 +3767,14 @@ const VaultChannels = {
3764
3767
  const WindowControlChannels = {
3765
3768
  WINDOW_MINIMIZE: "window:minimize",
3766
3769
  WINDOW_MAXIMIZE: "window:maximize",
3767
- WINDOW_CLOSE: "window:close"
3770
+ WINDOW_CLOSE: "window:close",
3771
+ OPEN_NEW_WINDOW: "window:open-new",
3772
+ OPEN_PRIVATE_WINDOW: "private:open-window",
3773
+ IS_PRIVATE_MODE: "private:is-private",
3774
+ FIND_IN_PAGE_START: "find:start",
3775
+ FIND_IN_PAGE_NEXT: "find:next",
3776
+ FIND_IN_PAGE_STOP: "find:stop",
3777
+ FIND_IN_PAGE_RESULT: "find:result"
3768
3778
  };
3769
3779
  const Channels = {
3770
3780
  ...AIChannels,
@@ -3779,6 +3789,7 @@ const Channels = {
3779
3789
  ...HighlightChannels,
3780
3790
  ...HistoryChannels,
3781
3791
  ...HumanVaultChannels,
3792
+ ...McpChannels,
3782
3793
  ...OpenRouterChannels,
3783
3794
  ...PermissionChannels,
3784
3795
  ...PremiumChannels,
@@ -3786,6 +3797,7 @@ const Channels = {
3786
3797
  ...SecurityChannels,
3787
3798
  ...SessionChannels,
3788
3799
  ...SettingsChannels,
3800
+ ...SupportChannels,
3789
3801
  ...TabChannels,
3790
3802
  ...UIChannels,
3791
3803
  ...UpdateChannels,
@@ -4748,7 +4760,15 @@ function errorResult(error, value) {
4748
4760
  function getErrorMessage(error, fallback = "Unknown error") {
4749
4761
  return error instanceof Error && error.message ? error.message : fallback;
4750
4762
  }
4751
- const logger$r = createLogger("Premium");
4763
+ async function readJsonResponse(response, fallback, onError) {
4764
+ try {
4765
+ return await response.json();
4766
+ } catch (err) {
4767
+ onError(getErrorMessage(err, "JSON parse failed"));
4768
+ return fallback;
4769
+ }
4770
+ }
4771
+ const logger$t = createLogger("Premium");
4752
4772
  const VERIFICATION_API = process.env.VESSEL_PREMIUM_API || "https://vesselpremium.quantaintellect.com";
4753
4773
  const FREE_TOOL_ITERATION_LIMIT = 50;
4754
4774
  const REVALIDATION_INTERVAL_MS = 24 * 60 * 60 * 1e3;
@@ -4924,7 +4944,7 @@ async function verifySubscription$1(identifier) {
4924
4944
  });
4925
4945
  if (!res.ok) {
4926
4946
  const detail = await readApiErrorDetail(res);
4927
- logger$r.warn(
4947
+ logger$t.warn(
4928
4948
  "Verification API returned a non-OK status:",
4929
4949
  res.status,
4930
4950
  detail
@@ -4943,7 +4963,7 @@ async function verifySubscription$1(identifier) {
4943
4963
  setSetting("premium", updated);
4944
4964
  return updated;
4945
4965
  } catch (err) {
4946
- logger$r.warn("Verification failed:", err);
4966
+ logger$t.warn("Verification failed:", err);
4947
4967
  return current;
4948
4968
  }
4949
4969
  }
@@ -4961,7 +4981,11 @@ async function requestActivationCode(email) {
4961
4981
  headers: { "Content-Type": "application/json" },
4962
4982
  body: JSON.stringify({ email: normalizedEmail })
4963
4983
  });
4964
- const data = await res.json().catch(() => ({}));
4984
+ const data = await readJsonResponse(
4985
+ res,
4986
+ {},
4987
+ (msg) => logger$t.warn("Failed to parse premium activation response:", msg)
4988
+ );
4965
4989
  if (!res.ok || !data.challengeToken) {
4966
4990
  return errorResult(data.error || `HTTP ${res.status}`);
4967
4991
  }
@@ -5002,7 +5026,11 @@ async function verifyActivationCode(email, code, challengeToken) {
5002
5026
  challengeToken: challengeToken.trim()
5003
5027
  })
5004
5028
  });
5005
- const data = await res.json().catch(() => ({}));
5029
+ const data = await readJsonResponse(
5030
+ res,
5031
+ {},
5032
+ (msg) => logger$t.warn("Failed to parse premium verification response:", msg)
5033
+ );
5006
5034
  if (!res.ok) {
5007
5035
  return errorResult(data.error || `HTTP ${res.status}`, {
5008
5036
  state: getPremiumState()
@@ -5598,7 +5626,7 @@ const EXTRACT_TIMEOUT_MAX_MS = 2e4;
5598
5626
  const MUTATION_CAPTURE_INTERVAL_MS = 5e3;
5599
5627
  const MUTATION_SETTLE_AFTER_MS = 1500;
5600
5628
  const AGENT_STREAM_IDLE_TIMEOUT_MS = 3e4;
5601
- const logger$q = createLogger("Extractor");
5629
+ const logger$s = createLogger("Extractor");
5602
5630
  const EXTRACTION_CACHE_TTL_MS = 1500;
5603
5631
  const MAX_EXTRACTION_CACHE_ENTRIES = 50;
5604
5632
  const extractionCache = new BoundedCache(
@@ -5645,6 +5673,7 @@ const PRELOAD_EXTRACTION_SCRIPT = String.raw`
5645
5673
  }
5646
5674
  }
5647
5675
  } catch (_error) {
5676
+ // Structured extraction unavailable, fall through to direct extraction
5648
5677
  }
5649
5678
  return null;
5650
5679
  })()
@@ -6284,9 +6313,9 @@ const DIRECT_EXTRACTION_SCRIPT = String.raw`
6284
6313
  } else if (parsed && typeof parsed === "object") {
6285
6314
  jsonLd.push(parsed);
6286
6315
  }
6287
- } catch (_e) {}
6316
+ } catch (_e) { /* skip malformed JSON-LD block */ }
6288
6317
  });
6289
- } catch (_e) {}
6318
+ } catch (_e) { /* no JSON-LD scripts found or querySelectorAll failed */ }
6290
6319
 
6291
6320
  // Extract meta tags as fallback
6292
6321
  var metaTags = {};
@@ -6299,8 +6328,7 @@ const DIRECT_EXTRACTION_SCRIPT = String.raw`
6299
6328
  });
6300
6329
  var canonical = document.querySelector('link[rel="canonical"]');
6301
6330
  if (canonical && canonical.getAttribute("href")) metaTags["canonical"] = canonical.getAttribute("href");
6302
- } catch (_e) {}
6303
-
6331
+ } catch (_e) { /* meta tag extraction failed — non-critical */ }
6304
6332
  return {
6305
6333
  title: document.title,
6306
6334
  content: getCleanBodyText(),
@@ -6363,9 +6391,9 @@ async function executeScript(webContents, script, options = {}) {
6363
6391
  const message = err instanceof Error ? err.message : String(err);
6364
6392
  const detail = `Failed to execute page script${label} on ${url}: ${message}`;
6365
6393
  if (options.warnOnFailure) {
6366
- logger$q.warn(detail);
6394
+ logger$s.warn(detail);
6367
6395
  } else {
6368
- logger$q.debug(detail);
6396
+ logger$s.debug(detail);
6369
6397
  }
6370
6398
  return null;
6371
6399
  } finally {
@@ -6474,7 +6502,7 @@ async function estimateExtractionTimeout(webContents) {
6474
6502
  return EXTRACT_TIMEOUT_BASE_MS + extra;
6475
6503
  }
6476
6504
  } catch (err) {
6477
- logger$q.warn("Failed to estimate extraction timeout, using base timeout:", err);
6505
+ logger$s.warn("Failed to estimate extraction timeout, using base timeout:", err);
6478
6506
  }
6479
6507
  return EXTRACT_TIMEOUT_BASE_MS;
6480
6508
  }
@@ -7442,7 +7470,7 @@ function isClickReadLoop(names) {
7442
7470
  return clickReadPairs >= 2;
7443
7471
  }
7444
7472
  const TERMINAL_TOOL_RESULT = "__VESSEL_TERMINAL_TOOL_RESULT__";
7445
- const logger$p = createLogger("PromptCache");
7473
+ const logger$r = createLogger("PromptCache");
7446
7474
  function shortHash(value) {
7447
7475
  return crypto$2.createHash("sha256").update(value).digest("hex").slice(0, 12);
7448
7476
  }
@@ -7494,7 +7522,7 @@ function logOpenAIPromptCacheUsage(usage, context) {
7494
7522
  const details = record.prompt_tokens_details;
7495
7523
  const cachedTokens = details && typeof details === "object" ? numericField(details, "cached_tokens") : null;
7496
7524
  if (promptTokens === null && cachedTokens === null) return;
7497
- logger$p.debug("OpenAI prompt cache usage", {
7525
+ logger$r.debug("OpenAI prompt cache usage", {
7498
7526
  model: context.model,
7499
7527
  mode: context.mode,
7500
7528
  promptTokens,
@@ -7510,7 +7538,7 @@ function logAnthropicPromptCacheUsage(usage, context) {
7510
7538
  if (inputTokens === null && cacheCreationTokens === null && cacheReadTokens === null) {
7511
7539
  return;
7512
7540
  }
7513
- logger$p.debug("Anthropic prompt cache usage", {
7541
+ logger$r.debug("Anthropic prompt cache usage", {
7514
7542
  model: context.model,
7515
7543
  mode: context.mode,
7516
7544
  inputTokens,
@@ -8403,7 +8431,7 @@ function recoverNarratedActionToolCalls(text, availableToolNames) {
8403
8431
  }
8404
8432
  return recovered;
8405
8433
  }
8406
- const logger$o = createLogger("OpenAIProvider");
8434
+ const logger$q = createLogger("OpenAIProvider");
8407
8435
  function shouldDebugAgentLoop() {
8408
8436
  const value = process.env.VESSEL_DEBUG_AGENT_LOOP;
8409
8437
  return value === "1" || value === "true";
@@ -8671,9 +8699,9 @@ function shouldRetryCompactToolLoop(profile, text, hasToolHistory, userMessage)
8671
8699
  function logAgentLoopDebug(payload) {
8672
8700
  if (!shouldDebugAgentLoop()) return;
8673
8701
  try {
8674
- logger$o.info(`[agent-debug] ${JSON.stringify(payload)}`);
8702
+ logger$q.info(`[agent-debug] ${JSON.stringify(payload)}`);
8675
8703
  } catch (err) {
8676
- logger$o.warn("Failed to serialize debug payload:", err);
8704
+ logger$q.warn("Failed to serialize debug payload:", err);
8677
8705
  }
8678
8706
  }
8679
8707
  function formatOpenAICompatErrorMessage(providerId, message) {
@@ -9113,6 +9141,9 @@ class OpenAICompatProvider {
9113
9141
  this.abortController?.abort();
9114
9142
  }
9115
9143
  }
9144
+ function escapeHtml(value) {
9145
+ return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
9146
+ }
9116
9147
  async function openExternalAllowlisted(url, rule) {
9117
9148
  const parsed = new URL(url);
9118
9149
  const schemes = rule.schemes ?? ["https:"];
@@ -9297,7 +9328,7 @@ function createLocalPkceOAuthFlow(config) {
9297
9328
  isInProgress: () => activeFlow !== null
9298
9329
  };
9299
9330
  }
9300
- const logger$n = createLogger("CodexOAuth");
9331
+ const logger$p = createLogger("CodexOAuth");
9301
9332
  const ISSUER = "https://auth.openai.com";
9302
9333
  const CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann";
9303
9334
  const SCOPE = "openid profile email offline_access api.connectors.read api.connectors.invoke";
@@ -9423,12 +9454,9 @@ async function refreshAccessToken(tokens) {
9423
9454
  };
9424
9455
  return refreshedTokens;
9425
9456
  }
9426
- function escapeHtml$1(text) {
9427
- return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
9428
- }
9429
9457
  const codexOAuth = createLocalPkceOAuthFlow({
9430
9458
  name: "Codex",
9431
- logger: logger$n,
9459
+ logger: logger$p,
9432
9460
  preferredPorts: [PREFERRED_PORT$1, FALLBACK_PORT$1],
9433
9461
  timeoutMs: AUTH_TIMEOUT_MS$1,
9434
9462
  callbackPath: () => "/auth/callback",
@@ -9437,7 +9465,7 @@ const codexOAuth = createLocalPkceOAuthFlow({
9437
9465
  buildAuthorizeUrl: ({ callbackUrl, pkce, state: state2 }) => buildAuthorizeUrl(callbackUrl, pkce, state2),
9438
9466
  exchangeCode: ({ code, callbackUrl, codeVerifier }) => exchangeCodeForTokens(code, callbackUrl, codeVerifier),
9439
9467
  successHtml: (tokens) => {
9440
- const label = escapeHtml$1(tokens.accountEmail || tokens.accountId);
9468
+ const label = escapeHtml(tokens.accountEmail || tokens.accountId);
9441
9469
  return `<!DOCTYPE html>
9442
9470
  <html><head><meta charset="utf-8"><title>Vessel — Signed In</title>
9443
9471
  <style>body{font-family:system-ui,sans-serif;display:flex;align-items:center;justify-content:center;height:100vh;margin:0;background:#111;color:#eee}</style></head>
@@ -9452,7 +9480,7 @@ async function startCodexOAuth(onStatus) {
9452
9480
  function cancelCodexOAuth() {
9453
9481
  codexOAuth.cancel();
9454
9482
  }
9455
- const logger$m = createLogger("CodexProvider");
9483
+ const logger$o = createLogger("CodexProvider");
9456
9484
  const REFRESH_WINDOW_MS = 5 * 60 * 1e3;
9457
9485
  const CODEX_BACKEND_BASE_URL = "https://chatgpt.com/backend-api/codex";
9458
9486
  const CODEX_CLIENT_VERSION = "0.129.0";
@@ -9517,7 +9545,7 @@ class CodexProvider {
9517
9545
  async ensureFreshTokens() {
9518
9546
  if (Date.now() < this.tokens.expiresAt - REFRESH_WINDOW_MS) return;
9519
9547
  try {
9520
- logger$m.info("Refreshing Codex access token");
9548
+ logger$o.info("Refreshing Codex access token");
9521
9549
  const fresh = await refreshAccessToken(this.tokens);
9522
9550
  this.tokens = fresh;
9523
9551
  writeStoredCodexTokens(fresh);
@@ -9665,7 +9693,7 @@ class CodexProvider {
9665
9693
  } catch (err) {
9666
9694
  if (err.name !== "AbortError") {
9667
9695
  const msg = err instanceof Error ? err.message : String(err);
9668
- logger$m.error("Codex streamQuery error:", err);
9696
+ logger$o.error("Codex streamQuery error:", err);
9669
9697
  onChunk(`
9670
9698
 
9671
9699
  [Error: ${msg}]`);
@@ -9733,7 +9761,7 @@ class CodexProvider {
9733
9761
  } catch (err) {
9734
9762
  if (err.name !== "AbortError") {
9735
9763
  const msg = err instanceof Error ? err.message : String(err);
9736
- logger$m.error("Codex streamAgentQuery error:", err);
9764
+ logger$o.error("Codex streamAgentQuery error:", err);
9737
9765
  onChunk(`
9738
9766
 
9739
9767
  [Error: ${msg}]`);
@@ -10967,7 +10995,7 @@ function normalizeBookmarkMetadataUpdate(input) {
10967
10995
  }
10968
10996
  return normalized;
10969
10997
  }
10970
- const logger$l = createLogger("BookmarkManager");
10998
+ const logger$n = createLogger("BookmarkManager");
10971
10999
  const UNSORTED_ID = "unsorted";
10972
11000
  const ARCHIVE_FOLDER_NAME = "Archive";
10973
11001
  const NETSCAPE_BOOKMARKS_DOCTYPE = "<!DOCTYPE NETSCAPE-Bookmark-file-1>";
@@ -11540,7 +11568,7 @@ function importBookmarksFromJson(content) {
11540
11568
  emit$2();
11541
11569
  }
11542
11570
  } catch (err) {
11543
- logger$l.warn("Failed to import bookmarks from JSON:", err);
11571
+ logger$n.warn("Failed to import bookmarks from JSON:", err);
11544
11572
  errors++;
11545
11573
  }
11546
11574
  return { imported, skipped, errors };
@@ -11945,6 +11973,7 @@ async function resolveSelector(wc, index, selector) {
11945
11973
  if (extractedSelector) return extractedSelector;
11946
11974
  return null;
11947
11975
  }
11976
+ const logger$m = createLogger("LinkValidation");
11948
11977
  const DEAD_STATUS_CODES = /* @__PURE__ */ new Set([404, 410, 451]);
11949
11978
  const HEAD_FALLBACK_STATUS_CODES = /* @__PURE__ */ new Set([400, 403, 404, 405, 406, 500, 501]);
11950
11979
  function isHttpUrl(value) {
@@ -11967,7 +11996,9 @@ async function requestUrl(url, method, timeoutMs) {
11967
11996
  "user-agent": "Vessel/0.1.0 (+https://github.com/unmodeled-tyler/vessel-browser)"
11968
11997
  }
11969
11998
  });
11970
- await response.body?.cancel().catch(() => void 0);
11999
+ await response.body?.cancel().catch((err) => {
12000
+ logger$m.debug("Failed to cancel response body:", err);
12001
+ });
11971
12002
  return response;
11972
12003
  } finally {
11973
12004
  clearTimeout(timer);
@@ -12030,7 +12061,7 @@ function formatDeadLinkMessage(label, result) {
12030
12061
  const status = result.statusCode ? `HTTP ${result.statusCode}` : "dead link";
12031
12062
  return `Skipped stale link "${label}" because ${destination} returned ${status}. Try a different link or URL instead.`;
12032
12063
  }
12033
- const logger$k = createLogger("Screenshot");
12064
+ const logger$l = createLogger("Screenshot");
12034
12065
  const SCREENSHOT_RETRY_COUNT = 3;
12035
12066
  const SCREENSHOT_RETRY_BASE_DELAY_MS = 120;
12036
12067
  async function captureScreenshot(wc) {
@@ -12052,7 +12083,7 @@ async function captureScreenshot(wc) {
12052
12083
  }
12053
12084
  }
12054
12085
  } catch (err) {
12055
- logger$k.debug(
12086
+ logger$l.debug(
12056
12087
  `capturePage attempt ${attempt + 1} failed; retrying if attempts remain.`,
12057
12088
  getErrorMessage(err)
12058
12089
  );
@@ -14529,7 +14560,7 @@ class TabMutex {
14529
14560
  return run;
14530
14561
  }
14531
14562
  }
14532
- const logger$j = createLogger("PageActions");
14563
+ const logger$k = createLogger("PageActions");
14533
14564
  const DEFAULT_PAGE_SCRIPT_TIMEOUT_MS = 1500;
14534
14565
  const PAGE_SCRIPT_TIMEOUT = /* @__PURE__ */ Symbol("page-script-timeout");
14535
14566
  function pageBusyError(action) {
@@ -14557,7 +14588,7 @@ async function executePageScript(wc, script, options) {
14557
14588
  return result;
14558
14589
  } catch (err) {
14559
14590
  const label = options?.label ? ` (${options.label})` : "";
14560
- logger$j.warn(`Failed to execute page script${label}:`, err);
14591
+ logger$k.warn(`Failed to execute page script${label}:`, err);
14561
14592
  return null;
14562
14593
  } finally {
14563
14594
  if (timer) {
@@ -14754,7 +14785,9 @@ Page title: ${title}` : "";
14754
14785
  signals.push('consent-banner:' + consentSelectors[i]);
14755
14786
  break;
14756
14787
  }
14757
- } catch(e) {}
14788
+ } catch {
14789
+ // Swallow — cross-origin frames may block selector access
14790
+ }
14758
14791
  }
14759
14792
  var vw = window.innerWidth || 0;
14760
14793
  var vh = window.innerHeight || 0;
@@ -14797,7 +14830,7 @@ Search results snapshot:
14797
14830
  ${truncated}`;
14798
14831
  }
14799
14832
  } catch (err) {
14800
- logger$j.warn("Failed to build post-search summary, falling back to nav summary:", err);
14833
+ logger$k.warn("Failed to build post-search summary, falling back to nav summary:", err);
14801
14834
  }
14802
14835
  const fallback = await getPostNavSummary(wc);
14803
14836
  return fallback ? `${fallback}
@@ -14820,7 +14853,7 @@ Page snapshot after navigation:
14820
14853
  ${truncated}`;
14821
14854
  }
14822
14855
  } catch (err) {
14823
- logger$j.warn("Failed to build post-click navigation summary:", err);
14856
+ logger$k.warn("Failed to build post-click navigation summary:", err);
14824
14857
  }
14825
14858
  return "";
14826
14859
  }
@@ -15710,7 +15743,7 @@ async function restoreLocaleSnapshot(wc, snapshot2) {
15710
15743
  }
15711
15744
  }
15712
15745
  } catch (err) {
15713
- logger$j.warn("Failed to restore locale via history navigation, trying URL reload fallback:", err);
15746
+ logger$k.warn("Failed to restore locale via history navigation, trying URL reload fallback:", err);
15714
15747
  }
15715
15748
  if (snapshot2.url && snapshot2.url !== wc.getURL()) {
15716
15749
  try {
@@ -15719,7 +15752,7 @@ async function restoreLocaleSnapshot(wc, snapshot2) {
15719
15752
  await waitForLoad(wc, 3e3);
15720
15753
  return;
15721
15754
  } catch (err) {
15722
- logger$j.warn("Failed to restore locale via safe URL load, trying page reload fallback:", err);
15755
+ logger$k.warn("Failed to restore locale via safe URL load, trying page reload fallback:", err);
15723
15756
  }
15724
15757
  }
15725
15758
  if (snapshot2.url) {
@@ -15727,7 +15760,7 @@ async function restoreLocaleSnapshot(wc, snapshot2) {
15727
15760
  await wc.reload();
15728
15761
  await waitForLoad(wc, 3e3);
15729
15762
  } catch (err) {
15730
- logger$j.warn("Failed to restore locale via page reload:", err);
15763
+ logger$k.warn("Failed to restore locale via page reload:", err);
15731
15764
  }
15732
15765
  }
15733
15766
  }
@@ -15792,7 +15825,7 @@ async function followHrefFromClickResult(wc, beforeUrl, result, logMessage) {
15792
15825
  const hrefUrl = wc.getURL();
15793
15826
  if (hrefUrl !== beforeUrl) return `${result.split("\n")[0]} -> ${hrefUrl}`;
15794
15827
  } catch (err) {
15795
- logger$j.warn(logMessage, err);
15828
+ logger$k.warn(logMessage, err);
15796
15829
  }
15797
15830
  return null;
15798
15831
  }
@@ -16004,7 +16037,7 @@ ${postActivationOverlayHint}`;
16004
16037
  return `${clickText} -> ${hrefFallbackUrl} (recovered via href fallback)`;
16005
16038
  }
16006
16039
  } catch (err) {
16007
- logger$j.warn("Failed href fallback after click, returning generic click result:", err);
16040
+ logger$k.warn("Failed href fallback after click, returning generic click result:", err);
16008
16041
  }
16009
16042
  }
16010
16043
  }
@@ -16049,7 +16082,7 @@ async function tryAutoDismissCartDialog(wc) {
16049
16082
  return result;
16050
16083
  }
16051
16084
  } catch (err) {
16052
- logger$j.warn("Failed to auto-dismiss cart dialog, falling back to dialog actions:", err);
16085
+ logger$k.warn("Failed to auto-dismiss cart dialog, falling back to dialog actions:", err);
16053
16086
  }
16054
16087
  return null;
16055
16088
  }
@@ -16502,7 +16535,9 @@ async function tryDismissConsentIframe(wc) {
16502
16535
  return 'Clicked iframe consent button: ' + text.slice(0, 60);
16503
16536
  }
16504
16537
  }
16505
- } catch(e) {}
16538
+ } catch {
16539
+ // Swallow — selector may be invalid or cross-origin frame may block access
16540
+ }
16506
16541
  }
16507
16542
  // Text-match fallback on all buttons
16508
16543
  var buttons = document.querySelectorAll('button, [role="button"], a.message-component');
@@ -17809,60 +17844,7 @@ WARNING: This page shows no results. You likely clicked a filter or category lin
17809
17844
  }
17810
17845
  return "";
17811
17846
  }
17812
- const KNOWN_TOOLS = /* @__PURE__ */ new Set([
17813
- "current_tab",
17814
- "list_tabs",
17815
- "switch_tab",
17816
- "create_tab",
17817
- "navigate",
17818
- "go_back",
17819
- "go_forward",
17820
- "reload",
17821
- "click",
17822
- "inspect_element",
17823
- "type_text",
17824
- "select_option",
17825
- "submit_form",
17826
- "press_key",
17827
- "scroll",
17828
- "hover",
17829
- "focus",
17830
- "set_ad_blocking",
17831
- "dismiss_popup",
17832
- "clear_overlays",
17833
- "read_page",
17834
- "screenshot",
17835
- "wait_for",
17836
- "create_checkpoint",
17837
- "restore_checkpoint",
17838
- "save_session",
17839
- "load_session",
17840
- "list_sessions",
17841
- "delete_session",
17842
- "list_bookmarks",
17843
- "search_bookmarks",
17844
- "create_bookmark_folder",
17845
- "save_bookmark",
17846
- "organize_bookmark",
17847
- "archive_bookmark",
17848
- "open_bookmark",
17849
- "highlight",
17850
- "clear_highlights",
17851
- "flow_start",
17852
- "flow_advance",
17853
- "flow_status",
17854
- "flow_end",
17855
- "suggest",
17856
- "fill_form",
17857
- "login",
17858
- "search",
17859
- "paginate",
17860
- "accept_cookies",
17861
- "extract_table",
17862
- "scroll_to_element",
17863
- "metrics",
17864
- "wait_for_navigation"
17865
- ]);
17847
+ const KNOWN_TOOLS = new Set(TOOL_DEFINITIONS.map((d) => d.name));
17866
17848
  async function executeAction(name, args, ctx) {
17867
17849
  name = normalizeToolAlias(name);
17868
17850
  if (ctx.tabId && ctx._tabMutex) {
@@ -18204,7 +18186,7 @@ async function executeAction(name, args, ctx) {
18204
18186
  )
18205
18187
  ]);
18206
18188
  } catch (err) {
18207
- logger$j.warn("Failed to extract content for read_page, falling back to lighter recovery:", err);
18189
+ logger$k.warn("Failed to extract content for read_page, falling back to lighter recovery:", err);
18208
18190
  content = null;
18209
18191
  }
18210
18192
  if (!content || content.content.length === 0) {
@@ -18221,12 +18203,12 @@ async function executeAction(name, args, ctx) {
18221
18203
  new Promise((resolve) => setTimeout(() => resolve(null), 3e3))
18222
18204
  ]);
18223
18205
  } catch (err) {
18224
- logger$j.warn("Failed to re-extract content after iframe consent dismissal:", err);
18206
+ logger$k.warn("Failed to re-extract content after iframe consent dismissal:", err);
18225
18207
  content = null;
18226
18208
  }
18227
18209
  }
18228
18210
  } catch (err) {
18229
- logger$j.warn("Failed iframe consent dismissal during read_page recovery:", err);
18211
+ logger$k.warn("Failed iframe consent dismissal during read_page recovery:", err);
18230
18212
  }
18231
18213
  }
18232
18214
  if (content && content.content.length > 0) {
@@ -18639,7 +18621,7 @@ ${flow.steps.map((s, i) => ` ${i === 0 ? "→" : " "} ${s.label}`).join("\n")}`
18639
18621
  try {
18640
18622
  page = await extractContent(wc);
18641
18623
  } catch (err) {
18642
- logger$j.warn("Failed to extract content for suggest:", err);
18624
+ logger$k.warn("Failed to extract content for suggest:", err);
18643
18625
  return "Could not read page. Try navigate to a working URL.";
18644
18626
  }
18645
18627
  const suggestions = [];
@@ -19027,7 +19009,7 @@ WARNING: You have clicked ${clickStreakCount} elements on this page without veri
19027
19009
  }
19028
19010
  return formattedResult + await getPostActionState$1(ctx, name) + clickNavSummary + streakWarning + flowCtx;
19029
19011
  }
19030
- const logger$i = createLogger("ResearchOrchestrator");
19012
+ const logger$j = createLogger("ResearchOrchestrator");
19031
19013
  const MAX_THREADS = 5;
19032
19014
  const MAX_TRACE_ARGS_CHARS = 1200;
19033
19015
  const MAX_TRACE_RESULT_CHARS = 2e3;
@@ -19216,7 +19198,7 @@ class ResearchOrchestrator {
19216
19198
  }
19217
19199
  stopAndSynthesizeCurrentFindings() {
19218
19200
  if (this.state.phase !== "executing") {
19219
- logger$i.warn("Not executing, ignoring stopAndSynthesizeCurrentFindings");
19201
+ logger$j.warn("Not executing, ignoring stopAndSynthesizeCurrentFindings");
19220
19202
  return;
19221
19203
  }
19222
19204
  this.stopRequested = true;
@@ -19250,23 +19232,23 @@ class ResearchOrchestrator {
19250
19232
  async startBrief(userQuery) {
19251
19233
  const query = userQuery.trim();
19252
19234
  if (!query) {
19253
- logger$i.warn("Ignoring empty Research Desk query");
19235
+ logger$j.warn("Ignoring empty Research Desk query");
19254
19236
  return;
19255
19237
  }
19256
19238
  if (this.state.phase !== "idle") {
19257
- logger$i.warn("Research already in progress, ignoring startBrief");
19239
+ logger$j.warn("Research already in progress, ignoring startBrief");
19258
19240
  return;
19259
19241
  }
19260
19242
  this.state = this.initialState();
19261
19243
  this.state.originalQuery = query;
19262
19244
  this.state.startedAt = (/* @__PURE__ */ new Date()).toISOString();
19263
19245
  this.setPhase("briefing");
19264
- logger$i.info(`Brief started for query: ${query.slice(0, 120)}`);
19246
+ logger$j.info(`Brief started for query: ${query.slice(0, 120)}`);
19265
19247
  }
19266
19248
  // ── phase: briefing → planning ─────────────────────────────────
19267
19249
  confirmBrief() {
19268
19250
  if (this.state.phase !== "briefing") {
19269
- logger$i.warn("Not in briefing phase, ignoring confirmBrief");
19251
+ logger$j.warn("Not in briefing phase, ignoring confirmBrief");
19270
19252
  return;
19271
19253
  }
19272
19254
  this.setPhase("planning");
@@ -19274,7 +19256,7 @@ class ResearchOrchestrator {
19274
19256
  // ── phase: planning → awaiting_approval ────────────────────────
19275
19257
  setObjectives(objectives) {
19276
19258
  if (this.state.phase !== "planning") {
19277
- logger$i.warn("Not in planning phase, ignoring setObjectives");
19259
+ logger$j.warn("Not in planning phase, ignoring setObjectives");
19278
19260
  return;
19279
19261
  }
19280
19262
  const threads = objectives.threads.slice(0, MAX_THREADS).map(mergeBlockedSourceDomains);
@@ -19303,11 +19285,11 @@ class ResearchOrchestrator {
19303
19285
  try {
19304
19286
  const parsed = JSON.parse(json);
19305
19287
  if (typeof parsed.researchQuestion !== "string" || !parsed.researchQuestion.trim()) {
19306
- logger$i.warn("Missing researchQuestion in objectives JSON");
19288
+ logger$j.warn("Missing researchQuestion in objectives JSON");
19307
19289
  return false;
19308
19290
  }
19309
19291
  if (!Array.isArray(parsed.threads) || parsed.threads.length === 0) {
19310
- logger$i.warn("Missing or empty threads array in objectives JSON");
19292
+ logger$j.warn("Missing or empty threads array in objectives JSON");
19311
19293
  return false;
19312
19294
  }
19313
19295
  const threads = parsed.threads.map((t, i) => {
@@ -19325,7 +19307,7 @@ class ResearchOrchestrator {
19325
19307
  };
19326
19308
  }).filter((thread) => thread.question && thread.searchQueries.length > 0).slice(0, MAX_THREADS);
19327
19309
  if (threads.length === 0) {
19328
- logger$i.warn("Objectives JSON did not contain any valid research threads");
19310
+ logger$j.warn("Objectives JSON did not contain any valid research threads");
19329
19311
  return false;
19330
19312
  }
19331
19313
  const objectives = {
@@ -19336,17 +19318,17 @@ class ResearchOrchestrator {
19336
19318
  totalSourceBudget: threads.reduce((sum, t) => sum + t.sourceBudget, 0)
19337
19319
  };
19338
19320
  this.setObjectives(objectives);
19339
- logger$i.info(`Parsed ${objectives.threads.length} threads from objectives`);
19321
+ logger$j.info(`Parsed ${objectives.threads.length} threads from objectives`);
19340
19322
  return true;
19341
19323
  } catch (err) {
19342
- logger$i.warn("Failed to parse objectives JSON", err);
19324
+ logger$j.warn("Failed to parse objectives JSON", err);
19343
19325
  return false;
19344
19326
  }
19345
19327
  }
19346
19328
  // ── phase: awaiting_approval → executing ───────────────────────
19347
19329
  approveObjectives(mode, includeTraces) {
19348
19330
  if (this.state.phase !== "awaiting_approval") {
19349
- logger$i.warn("Not awaiting approval, ignoring approveObjectives");
19331
+ logger$j.warn("Not awaiting approval, ignoring approveObjectives");
19350
19332
  return;
19351
19333
  }
19352
19334
  if (mode) this.state.supervisionMode = mode;
@@ -19381,7 +19363,7 @@ class ResearchOrchestrator {
19381
19363
  this.state.threads.map((thread) => {
19382
19364
  if (this.state.phase !== "executing") return null;
19383
19365
  return this.runSubAgent(thread, tabMutex).catch((err) => {
19384
- logger$i.error(`Sub-agent "${thread.label}" failed`, err);
19366
+ logger$j.error(`Sub-agent "${thread.label}" failed`, err);
19385
19367
  return {
19386
19368
  threadLabel: thread.label,
19387
19369
  threadQuestion: thread.question,
@@ -19410,7 +19392,7 @@ class ResearchOrchestrator {
19410
19392
  try {
19411
19393
  await this.synthesizeReport();
19412
19394
  } catch (err) {
19413
- logger$i.error("Auto-synthesis failed", err);
19395
+ logger$j.error("Auto-synthesis failed", err);
19414
19396
  this.state.error = `Synthesis failed: ${String(err)}`;
19415
19397
  this.setPhase("delivered");
19416
19398
  }
@@ -19521,7 +19503,7 @@ Start by searching for: ${thread.searchQueries.join(" or ")}`;
19521
19503
  try {
19522
19504
  this.tabManager.closeTab(tabId);
19523
19505
  } catch (err) {
19524
- logger$i.warn(`Failed to close sub-agent tab ${tabId}`, err);
19506
+ logger$j.warn(`Failed to close sub-agent tab ${tabId}`, err);
19525
19507
  }
19526
19508
  }
19527
19509
  }
@@ -19530,7 +19512,7 @@ Start by searching for: ${thread.searchQueries.join(" or ")}`;
19530
19512
  try {
19531
19513
  claims = await this.extractClaimsFromTranscript(thread, transcript);
19532
19514
  } catch (err) {
19533
- logger$i.warn(`Claim extraction failed for "${thread.label}"`, err);
19515
+ logger$j.warn(`Claim extraction failed for "${thread.label}"`, err);
19534
19516
  }
19535
19517
  }
19536
19518
  if (this.state.phase === "executing" && this.state.includeTraces) {
@@ -19620,7 +19602,7 @@ ${transcript.slice(0, 32e3)}`;
19620
19602
  (claim) => claim.claim && claim.sourceUrl && claim.extractedQuote
19621
19603
  );
19622
19604
  } catch {
19623
- logger$i.warn(`Failed to parse claims JSON for "${thread.label}"`);
19605
+ logger$j.warn(`Failed to parse claims JSON for "${thread.label}"`);
19624
19606
  return [];
19625
19607
  }
19626
19608
  }
@@ -19705,7 +19687,7 @@ ${transcript.slice(0, 32e3)}`;
19705
19687
  objectives
19706
19688
  };
19707
19689
  } catch (err) {
19708
- logger$i.warn("Failed to parse synthesis JSON, using sourced fallback report", err);
19690
+ logger$j.warn("Failed to parse synthesis JSON, using sourced fallback report", err);
19709
19691
  return buildFallbackReport(objectives, findings, String(err));
19710
19692
  }
19711
19693
  }
@@ -20252,7 +20234,7 @@ function loadRenderers(chromeView, sidebarView, devtoolsPanelView) {
20252
20234
  });
20253
20235
  }
20254
20236
  }
20255
- const logger$h = createLogger("PrivateWindow");
20237
+ const logger$i = createLogger("PrivateWindow");
20256
20238
  const privateWindows = /* @__PURE__ */ new Set();
20257
20239
  function layoutPrivateViews(state2) {
20258
20240
  const { window: win, chromeView, tabManager } = state2;
@@ -20473,7 +20455,7 @@ function createPrivateWindow() {
20473
20455
  privateSession.clearStorageData(),
20474
20456
  privateSession.clearCache()
20475
20457
  ]).catch((error) => {
20476
- logger$h.warn("Failed to clear private browsing session:", error);
20458
+ logger$i.warn("Failed to clear private browsing session:", error);
20477
20459
  });
20478
20460
  });
20479
20461
  privateWindows.add(state2);
@@ -20483,7 +20465,7 @@ function createPrivateWindow() {
20483
20465
  });
20484
20466
  loadPrivateRenderer(chromeView);
20485
20467
  win.show();
20486
- logger$h.info("Private browsing window opened");
20468
+ logger$i.info("Private browsing window opened");
20487
20469
  return state2;
20488
20470
  }
20489
20471
  const window$2 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
@@ -20857,7 +20839,7 @@ function registerTabHandlers(windowState2, _sendToRendererViews) {
20857
20839
  });
20858
20840
  }
20859
20841
  const require$1 = node_module.createRequire(require("url").pathToFileURL(__filename).href);
20860
- const logger$g = createLogger("DevTrace");
20842
+ const logger$h = createLogger("DevTrace");
20861
20843
  let cachedFactory;
20862
20844
  function createNoopTraceSession() {
20863
20845
  return {
@@ -20890,7 +20872,7 @@ function loadLocalFactory() {
20890
20872
  return cachedFactory;
20891
20873
  }
20892
20874
  } catch (err) {
20893
- logger$g.warn("Failed to load local trace logger:", err);
20875
+ logger$h.warn("Failed to load local trace logger:", err);
20894
20876
  }
20895
20877
  }
20896
20878
  return cachedFactory;
@@ -21682,9 +21664,6 @@ function renderReaderContent(page) {
21682
21664
  }
21683
21665
  return source.split(/\n{2,}/).map((block) => block.trim()).filter(Boolean).map((block) => `<p>${escapeHtml(block).replace(/\n/g, "<br>")}</p>`).join("\n");
21684
21666
  }
21685
- function escapeHtml(str) {
21686
- return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
21687
- }
21688
21667
  function registerContentHandlers(windowState2) {
21689
21668
  const { tabManager } = windowState2;
21690
21669
  electron.ipcMain.handle(Channels.CONTENT_EXTRACT, async (event) => {
@@ -21721,7 +21700,7 @@ function registerContentHandlers(windowState2) {
21721
21700
  return windowState2.uiState.focusMode;
21722
21701
  });
21723
21702
  }
21724
- const logger$f = createLogger("HighlightIPC");
21703
+ const logger$g = createLogger("HighlightIPC");
21725
21704
  function registerHighlightHandlers(windowState2, sendToRendererViews) {
21726
21705
  const { tabManager, chromeView } = windowState2;
21727
21706
  const getActiveHighlightCountSafe = async () => {
@@ -21730,7 +21709,7 @@ function registerHighlightHandlers(windowState2, sendToRendererViews) {
21730
21709
  try {
21731
21710
  return await getHighlightCount(info.wc) ?? 0;
21732
21711
  } catch (err) {
21733
- logger$f.warn("Failed to get active highlight count:", err);
21712
+ logger$g.warn("Failed to get active highlight count:", err);
21734
21713
  return 0;
21735
21714
  }
21736
21715
  };
@@ -21755,13 +21734,13 @@ function registerHighlightHandlers(windowState2, sendToRendererViews) {
21755
21734
  const result = await captureSelectionHighlight(wc);
21756
21735
  if (result.success && result.text) {
21757
21736
  await highlightOnPage(wc, null, result.text, void 0, void 0, "yellow").catch(
21758
- (err) => logger$f.warn("Failed to highlight captured selection:", err)
21737
+ (err) => logger$g.warn("Failed to highlight captured selection:", err)
21759
21738
  );
21760
21739
  await emitHighlightCount();
21761
21740
  }
21762
21741
  return result;
21763
21742
  } catch (err) {
21764
- logger$f.warn("Failed to capture highlight from active tab:", err);
21743
+ logger$g.warn("Failed to capture highlight from active tab:", err);
21765
21744
  return { success: false, message: "Could not capture selection" };
21766
21745
  }
21767
21746
  });
@@ -21778,7 +21757,7 @@ function registerHighlightHandlers(windowState2, sendToRendererViews) {
21778
21757
  }
21779
21758
  });
21780
21759
  } catch (err) {
21781
- logger$f.warn("Failed to persist auto-highlight selection:", err);
21760
+ logger$g.warn("Failed to persist auto-highlight selection:", err);
21782
21761
  }
21783
21762
  });
21784
21763
  electron.ipcMain.handle(Channels.HIGHLIGHT_NAV_COUNT, (event) => {
@@ -21792,7 +21771,7 @@ function registerHighlightHandlers(windowState2, sendToRendererViews) {
21792
21771
  try {
21793
21772
  return scrollToHighlight(info.wc, index);
21794
21773
  } catch (err) {
21795
- logger$f.warn("Failed to scroll to highlight:", err);
21774
+ logger$g.warn("Failed to scroll to highlight:", err);
21796
21775
  return false;
21797
21776
  }
21798
21777
  });
@@ -21807,7 +21786,7 @@ function registerHighlightHandlers(windowState2, sendToRendererViews) {
21807
21786
  }
21808
21787
  return removed;
21809
21788
  } catch (err) {
21810
- logger$f.warn("Failed to remove highlight at index:", err);
21789
+ logger$g.warn("Failed to remove highlight at index:", err);
21811
21790
  return false;
21812
21791
  }
21813
21792
  });
@@ -21822,7 +21801,7 @@ function registerHighlightHandlers(windowState2, sendToRendererViews) {
21822
21801
  }
21823
21802
  return cleared;
21824
21803
  } catch (err) {
21825
- logger$f.warn("Failed to clear highlight elements:", err);
21804
+ logger$g.warn("Failed to clear highlight elements:", err);
21826
21805
  return false;
21827
21806
  }
21828
21807
  });
@@ -22791,7 +22770,7 @@ Exception: ${result.exceptionDetails}`);
22791
22770
  }
22792
22771
  );
22793
22772
  }
22794
- const logger$e = createLogger("MCP");
22773
+ const logger$f = createLogger("MCP");
22795
22774
  function asTextResponse(text) {
22796
22775
  return { content: [{ type: "text", text }] };
22797
22776
  }
@@ -22892,7 +22871,7 @@ async function getPostActionState(tabManager, name) {
22892
22871
  }
22893
22872
  }
22894
22873
  } catch (err) {
22895
- logger$e.warn("Failed to compute post-action state warning:", err);
22874
+ logger$f.warn("Failed to compute post-action state warning:", err);
22896
22875
  }
22897
22876
  return `${warning}
22898
22877
  [state: url=${wc.getURL()}, canGoBack=${tab.canGoBack()}, canGoForward=${tab.canGoForward()}, loading=${wc.isLoading()}]`;
@@ -22997,7 +22976,7 @@ async function waitForConditionMcp(wc, text, selector, timeoutMs) {
22997
22976
  }
22998
22977
  })()
22999
22978
  `).catch((err) => {
23000
- logger$e.warn("Failed to gather wait_for timeout diagnostic:", err);
22979
+ logger$f.warn("Failed to gather wait_for timeout diagnostic:", err);
23001
22980
  return null;
23002
22981
  });
23003
22982
  if (typeof diagnostic === "string" && diagnostic.trim()) {
@@ -23483,6 +23462,7 @@ function registerBookmarkTools(server, tabManager, runtime2) {
23483
23462
  return `Opened bookmark "${bookmark.title}" in new tab ${createdId}`;
23484
23463
  }
23485
23464
  const activeId = tabManager.getActiveTabId();
23465
+ if (!activeId) return "No active tab to open bookmark in";
23486
23466
  const activeTab = tabManager.getActiveTab();
23487
23467
  tabManager.navigateTab(activeId, bookmark.url);
23488
23468
  if (activeTab) {
@@ -23713,7 +23693,7 @@ function registerSessionTools(server, tabManager, runtime2) {
23713
23693
  )
23714
23694
  );
23715
23695
  }
23716
- const logger$d = createLogger("VaultShared");
23696
+ const logger$e = createLogger("VaultShared");
23717
23697
  const ALGORITHM = "aes-256-gcm";
23718
23698
  const IV_LENGTH = 12;
23719
23699
  const AUTH_TAG_LENGTH = 16;
@@ -23807,7 +23787,7 @@ function createVaultIO(vaultFilename, encrypt2, decrypt2) {
23807
23787
  cachedEntries = JSON.parse(json);
23808
23788
  return cachedEntries;
23809
23789
  } catch (err) {
23810
- logger$d.error("Failed to load vault:", err);
23790
+ logger$e.error("Failed to load vault:", err);
23811
23791
  throw new Error("Could not unlock the vault. Check OS secret storage availability.");
23812
23792
  }
23813
23793
  }
@@ -23890,7 +23870,7 @@ function createAuditLog(filename, maxEntries) {
23890
23870
  } catch {
23891
23871
  }
23892
23872
  } catch (err) {
23893
- logger$d.error("Failed to write audit log:", err);
23873
+ logger$e.error("Failed to write audit log:", err);
23894
23874
  }
23895
23875
  }
23896
23876
  function readAuditLog2(limit = 100) {
@@ -23900,7 +23880,7 @@ function createAuditLog(filename, maxEntries) {
23900
23880
  const lines = fs$1.readFileSync(auditPath, "utf-8").split("\n").filter((l) => l.trim());
23901
23881
  return lines.slice(-Math.min(limit, maxEntries)).map((line) => JSON.parse(line)).reverse();
23902
23882
  } catch (err) {
23903
- logger$d.error("Failed to read audit log:", err);
23883
+ logger$e.error("Failed to read audit log:", err);
23904
23884
  return [];
23905
23885
  }
23906
23886
  }
@@ -23973,9 +23953,12 @@ async function requestConsent(request) {
23973
23953
  if (sessionTrustedDomains.has(domain)) {
23974
23954
  return { approved: true, trustForSession: true };
23975
23955
  }
23976
- const focusedWindow = electron.BrowserWindow.getFocusedWindow();
23956
+ const parentWindow = electron.BrowserWindow.getFocusedWindow() ?? electron.BrowserWindow.getAllWindows()[0];
23957
+ if (!parentWindow) {
23958
+ return { approved: false, trustForSession: false };
23959
+ }
23977
23960
  const { response } = await electron.dialog.showMessageBox(
23978
- focusedWindow ?? (electron.BrowserWindow.getAllWindows()[0] || null),
23961
+ parentWindow,
23979
23962
  {
23980
23963
  type: "question",
23981
23964
  title: "Agent Credential Access",
@@ -24004,7 +23987,7 @@ async function requestConsent(request) {
24004
23987
  }
24005
23988
  const AUDIT_FILENAME = "vessel-vault-audit.jsonl";
24006
23989
  const MAX_ENTRIES = 1e3;
24007
- const logger$c = createLogger("VaultAudit");
23990
+ const logger$d = createLogger("VaultAudit");
24008
23991
  function getAuditPath() {
24009
23992
  return path$1.join(electron.app.getPath("userData"), AUDIT_FILENAME);
24010
23993
  }
@@ -24018,7 +24001,7 @@ function appendAuditEntry(entry) {
24018
24001
  });
24019
24002
  fs$1.chmodSync(auditPath, 384);
24020
24003
  } catch (err) {
24021
- logger$c.error("Failed to write audit log:", err);
24004
+ logger$d.error("Failed to write audit log:", err);
24022
24005
  }
24023
24006
  }
24024
24007
  function readAuditLog$1(limit = 100) {
@@ -24028,7 +24011,7 @@ function readAuditLog$1(limit = 100) {
24028
24011
  const lines = fs$1.readFileSync(auditPath, "utf-8").split("\n").filter((l) => l.trim());
24029
24012
  return lines.slice(-Math.min(limit, MAX_ENTRIES)).map((line) => JSON.parse(line)).reverse();
24030
24013
  } catch (err) {
24031
- logger$c.error("Failed to read audit log:", err);
24014
+ logger$d.error("Failed to read audit log:", err);
24032
24015
  return [];
24033
24016
  }
24034
24017
  }
@@ -24198,7 +24181,7 @@ const mcpRuntimeState = {
24198
24181
  httpServer: null,
24199
24182
  authToken: null
24200
24183
  };
24201
- const logger$b = createLogger("MCP");
24184
+ const logger$c = createLogger("MCP");
24202
24185
  const MCP_AUTH_FILENAME = "mcp-auth.json";
24203
24186
  function getMcpAuthFilePath() {
24204
24187
  const configDir = process.env.VESSEL_CONFIG_DIR || path$1.join(
@@ -24235,7 +24218,7 @@ function writeMcpAuthFile(endpoint, token) {
24235
24218
  );
24236
24219
  fs$1.chmodSync(filePath2, 384);
24237
24220
  } catch (err) {
24238
- logger$b.warn("Failed to write auth file:", err);
24221
+ logger$c.warn("Failed to write auth file:", err);
24239
24222
  }
24240
24223
  }
24241
24224
  function clearMcpAuthFile() {
@@ -24261,7 +24244,7 @@ function clearMcpAuthFile() {
24261
24244
  );
24262
24245
  fs$1.chmodSync(filePath2, 384);
24263
24246
  } catch (err) {
24264
- logger$b.warn("Failed to clear auth file:", err);
24247
+ logger$c.warn("Failed to clear auth file:", err);
24265
24248
  }
24266
24249
  }
24267
24250
  function regenerateMcpAuthToken() {
@@ -24271,7 +24254,7 @@ function regenerateMcpAuthToken() {
24271
24254
  writeMcpAuthFile(endpoint, mcpRuntimeState.authToken);
24272
24255
  return { endpoint };
24273
24256
  }
24274
- const logger$a = createLogger("MCP");
24257
+ const logger$b = createLogger("MCP");
24275
24258
  function registerTools(server, tabManager, runtime2) {
24276
24259
  server.registerPrompt(
24277
24260
  "vessel-supervisor-brief",
@@ -24350,7 +24333,7 @@ function registerTools(server, tabManager, runtime2) {
24350
24333
  const page = await extractContent$1(wc);
24351
24334
  pageType = detectPageType(page);
24352
24335
  } catch (err) {
24353
- logger$a.warn("Failed to detect page type for tool scoring, falling back to GENERAL:", err);
24336
+ logger$b.warn("Failed to detect page type for tool scoring, falling back to GENERAL:", err);
24354
24337
  }
24355
24338
  }
24356
24339
  const scored = TOOL_DEFINITIONS.map((def) => {
@@ -24608,6 +24591,7 @@ ${buildScopedContext(pageContent, mode)}`;
24608
24591
  }
24609
24592
  return withAction(runtime2, tabManager, "navigate", { url }, async () => {
24610
24593
  const id = tabManager.getActiveTabId();
24594
+ if (!id) return asNoActiveTabResponse();
24611
24595
  const navError = tabManager.navigateTab(id, url, postBody);
24612
24596
  if (navError) return navError;
24613
24597
  const { httpStatus } = await waitForLoadWithStatus(
@@ -24731,7 +24715,9 @@ ${buildScopedContext(pageContent, mode)}`;
24731
24715
  return "No previous page in history";
24732
24716
  }
24733
24717
  const beforeUrl = tab.view.webContents.getURL();
24734
- tabManager.goBack(tabManager.getActiveTabId());
24718
+ const backId = tabManager.getActiveTabId();
24719
+ if (!backId) return asNoActiveTabResponse();
24720
+ tabManager.goBack(backId);
24735
24721
  await waitForLoad(tab.view.webContents);
24736
24722
  const afterUrl = tab.view.webContents.getURL();
24737
24723
  return afterUrl !== beforeUrl ? `Went back to ${afterUrl}` : `Back action completed but page stayed on ${afterUrl}`;
@@ -24752,7 +24738,9 @@ ${buildScopedContext(pageContent, mode)}`;
24752
24738
  return "No forward page in history";
24753
24739
  }
24754
24740
  const beforeUrl = tab.view.webContents.getURL();
24755
- tabManager.goForward(tabManager.getActiveTabId());
24741
+ const forwardId = tabManager.getActiveTabId();
24742
+ if (!forwardId) return asNoActiveTabResponse();
24743
+ tabManager.goForward(forwardId);
24756
24744
  await waitForLoad(tab.view.webContents);
24757
24745
  const afterUrl = tab.view.webContents.getURL();
24758
24746
  return afterUrl !== beforeUrl ? `Went forward to ${afterUrl}` : `Forward action completed but page stayed on ${afterUrl}`;
@@ -24769,7 +24757,9 @@ ${buildScopedContext(pageContent, mode)}`;
24769
24757
  const tab = tabManager.getActiveTab();
24770
24758
  if (!tab) return asNoActiveTabResponse();
24771
24759
  return withAction(runtime2, tabManager, "reload", {}, async () => {
24772
- tabManager.reloadTab(tabManager.getActiveTabId());
24760
+ const reloadId = tabManager.getActiveTabId();
24761
+ if (!reloadId) return asNoActiveTabResponse();
24762
+ tabManager.reloadTab(reloadId);
24773
24763
  await waitForLoad(tab.view.webContents);
24774
24764
  return `Reloaded ${tab.view.webContents.getURL()}`;
24775
24765
  });
@@ -25638,7 +25628,7 @@ ${JSON.stringify(otherHighlights, null, 2)}`
25638
25628
  void 0,
25639
25629
  h.color
25640
25630
  ).catch(
25641
- (err) => logger$a.warn("Failed to restore highlight after removal:", err)
25631
+ (err) => logger$b.warn("Failed to restore highlight after removal:", err)
25642
25632
  );
25643
25633
  }
25644
25634
  }
@@ -25905,7 +25895,7 @@ ${flow.steps.map((s, i) => ` ${i === 0 ? "→" : " "} ${s.label}`).join("\n")}`
25905
25895
  try {
25906
25896
  page = await extractContent$1(wc);
25907
25897
  } catch (err) {
25908
- logger$a.warn("Failed to extract page while generating suggestions:", err);
25898
+ logger$b.warn("Failed to extract page while generating suggestions:", err);
25909
25899
  return asTextResponse(
25910
25900
  "Could not read page. Try navigate to a working URL."
25911
25901
  );
@@ -26079,6 +26069,7 @@ ${results.join("\n")}`;
26079
26069
  const steps = [];
26080
26070
  if (url) {
26081
26071
  const id = tabManager.getActiveTabId();
26072
+ if (!id) return asNoActiveTabResponse();
26082
26073
  tabManager.navigateTab(id, url);
26083
26074
  await waitForLoad(wc);
26084
26075
  steps.push(`Navigated to ${wc.getURL()}`);
@@ -26515,7 +26506,7 @@ ${JSON.stringify(tableJson, null, 2)}`;
26515
26506
  try {
26516
26507
  targetDomain = new URL(tab.state.url).hostname;
26517
26508
  } catch (err) {
26518
- logger$a.warn("Failed to parse active tab URL for vault_status:", err);
26509
+ logger$b.warn("Failed to parse active tab URL for vault_status:", err);
26519
26510
  return asErrorTextResponse("Could not parse active tab URL");
26520
26511
  }
26521
26512
  }
@@ -26583,7 +26574,7 @@ Use vault_login to fill the login form. Credentials are filled directly — you
26583
26574
  try {
26584
26575
  hostname = new URL(tab.state.url).hostname;
26585
26576
  } catch (err) {
26586
- logger$a.warn("Failed to parse active tab URL for vault_login:", err);
26577
+ logger$b.warn("Failed to parse active tab URL for vault_login:", err);
26587
26578
  return asErrorTextResponse("Could not parse active tab URL");
26588
26579
  }
26589
26580
  const matches = findEntriesForDomain(`https://${hostname}`);
@@ -26679,7 +26670,7 @@ Use vault_login to fill the login form. Credentials are filled directly — you
26679
26670
  try {
26680
26671
  hostname = new URL(tab.state.url).hostname;
26681
26672
  } catch (err) {
26682
- logger$a.warn("Failed to parse active tab URL for vault_totp:", err);
26673
+ logger$b.warn("Failed to parse active tab URL for vault_totp:", err);
26683
26674
  return asErrorTextResponse("Could not parse active tab URL");
26684
26675
  }
26685
26676
  const matches = findEntriesForDomain(`https://${hostname}`);
@@ -27027,7 +27018,7 @@ function startMcpServer(tabManager, runtime2, port) {
27027
27018
  await mcpServer.connect(transport);
27028
27019
  await transport.handleRequest(req, res);
27029
27020
  } catch (error) {
27030
- logger$a.error("Error handling request:", error);
27021
+ logger$b.error("Error handling request:", error);
27031
27022
  if (!res.headersSent) {
27032
27023
  res.writeHead(500, { "Content-Type": "application/json" });
27033
27024
  res.end(
@@ -27046,7 +27037,7 @@ function startMcpServer(tabManager, runtime2, port) {
27046
27037
  };
27047
27038
  server.once("error", (error) => {
27048
27039
  const message = error.code === "EADDRINUSE" ? `Port ${port} is already in use. MCP server not started.` : error.message;
27049
- logger$a.error("Server error:", error);
27040
+ logger$b.error("Server error:", error);
27050
27041
  clearMcpAuthFile();
27051
27042
  setMcpHealth({
27052
27043
  configuredPort: port,
@@ -27078,7 +27069,7 @@ function startMcpServer(tabManager, runtime2, port) {
27078
27069
  message: `MCP server listening on ${endpoint}.`
27079
27070
  });
27080
27071
  if (process.env.VESSEL_DEBUG_MCP === "1" || process.env.VESSEL_DEBUG_MCP === "true") {
27081
- logger$a.info(`Server listening on ${endpoint} (auth enabled)`);
27072
+ logger$b.info(`Server listening on ${endpoint} (auth enabled)`);
27082
27073
  }
27083
27074
  if (mcpRuntimeState.authToken) {
27084
27075
  writeMcpAuthFile(endpoint, mcpRuntimeState.authToken);
@@ -27117,12 +27108,13 @@ function stopMcpServer() {
27117
27108
  message: "MCP server is stopped."
27118
27109
  });
27119
27110
  if (process.env.VESSEL_DEBUG_MCP === "1" || process.env.VESSEL_DEBUG_MCP === "true") {
27120
- logger$a.info("Server stopped");
27111
+ logger$b.info("Server stopped");
27121
27112
  }
27122
27113
  resolve();
27123
27114
  });
27124
27115
  });
27125
27116
  }
27117
+ const logger$a = createLogger("Feedback");
27126
27118
  const SUPPORT_API = process.env.VESSEL_SUPPORT_API || process.env.VESSEL_PREMIUM_API || "https://vesselpremium.quantaintellect.com";
27127
27119
  const MAX_FEEDBACK_MESSAGE_LENGTH = 5e3;
27128
27120
  const FEEDBACK_REQUEST_TIMEOUT_MS = 15e3;
@@ -27158,7 +27150,11 @@ async function submitFeedback(payload) {
27158
27150
  source: payload.source
27159
27151
  })
27160
27152
  });
27161
- const data = await res.json().catch(() => ({}));
27153
+ const data = await readJsonResponse(
27154
+ res,
27155
+ {},
27156
+ (msg) => logger$a.warn("Failed to parse feedback response:", msg)
27157
+ );
27162
27158
  if (!res.ok) {
27163
27159
  return errorResult(data.error || `HTTP ${res.status}`);
27164
27160
  }
@@ -29480,12 +29476,14 @@ function renderReportAsMarkdown(report, traces) {
29480
29476
  }
29481
29477
  const logger$4 = createLogger("ResearchIPC");
29482
29478
  function registerResearchHandlers(getOrchestrator) {
29483
- electron.ipcMain.handle(Channels.RESEARCH_STATE_GET, () => {
29479
+ electron.ipcMain.handle(Channels.RESEARCH_STATE_GET, (event) => {
29480
+ assertTrustedIpcSender(event);
29484
29481
  return getOrchestrator().getState();
29485
29482
  });
29486
29483
  electron.ipcMain.handle(
29487
29484
  Channels.RESEARCH_START_BRIEF,
29488
- async (_event, query) => {
29485
+ async (event, query) => {
29486
+ assertTrustedIpcSender(event);
29489
29487
  try {
29490
29488
  const trimmedQuery = query.trim();
29491
29489
  if (!trimmedQuery) {
@@ -29502,7 +29500,8 @@ function registerResearchHandlers(getOrchestrator) {
29502
29500
  }
29503
29501
  }
29504
29502
  );
29505
- electron.ipcMain.handle(Channels.RESEARCH_CONFIRM_BRIEF, () => {
29503
+ electron.ipcMain.handle(Channels.RESEARCH_CONFIRM_BRIEF, (event) => {
29504
+ assertTrustedIpcSender(event);
29506
29505
  try {
29507
29506
  if (isToolGated("research_confirm_brief")) {
29508
29507
  return { accepted: false, reason: "premium" };
@@ -29520,7 +29519,8 @@ function registerResearchHandlers(getOrchestrator) {
29520
29519
  });
29521
29520
  electron.ipcMain.handle(
29522
29521
  Channels.RESEARCH_APPROVE_OBJECTIVES,
29523
- (_event, options) => {
29522
+ (event, options) => {
29523
+ assertTrustedIpcSender(event);
29524
29524
  try {
29525
29525
  if (isToolGated("research_approve_objectives")) {
29526
29526
  return { accepted: false, reason: "premium" };
@@ -29546,23 +29546,28 @@ function registerResearchHandlers(getOrchestrator) {
29546
29546
  );
29547
29547
  electron.ipcMain.handle(
29548
29548
  Channels.RESEARCH_SET_MODE,
29549
- (_event, mode) => {
29549
+ (event, mode) => {
29550
+ assertTrustedIpcSender(event);
29550
29551
  getOrchestrator().setSupervisionMode(mode);
29551
29552
  }
29552
29553
  );
29553
29554
  electron.ipcMain.handle(
29554
29555
  Channels.RESEARCH_SET_TRACES,
29555
- (_event, include) => {
29556
+ (event, include) => {
29557
+ assertTrustedIpcSender(event);
29556
29558
  getOrchestrator().setIncludeTraces(include);
29557
29559
  }
29558
29560
  );
29559
- electron.ipcMain.handle(Channels.RESEARCH_CANCEL, () => {
29561
+ electron.ipcMain.handle(Channels.RESEARCH_CANCEL, (event) => {
29562
+ assertTrustedIpcSender(event);
29560
29563
  getOrchestrator().cancel();
29561
29564
  });
29562
- electron.ipcMain.handle(Channels.RESEARCH_STOP_AND_SYNTHESIZE, () => {
29565
+ electron.ipcMain.handle(Channels.RESEARCH_STOP_AND_SYNTHESIZE, (event) => {
29566
+ assertTrustedIpcSender(event);
29563
29567
  getOrchestrator().stopAndSynthesizeCurrentFindings();
29564
29568
  });
29565
- electron.ipcMain.handle(Channels.RESEARCH_EXPORT_REPORT, async () => {
29569
+ electron.ipcMain.handle(Channels.RESEARCH_EXPORT_REPORT, async (event) => {
29570
+ assertTrustedIpcSender(event);
29566
29571
  try {
29567
29572
  if (isToolGated("research_export_report")) {
29568
29573
  return { accepted: false, reason: "premium" };