@quanta-intellect/vessel-browser 0.1.25 → 0.1.27

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
@@ -2450,6 +2450,7 @@ const Channels = {
2450
2450
  PREMIUM_CHECKOUT: "premium:checkout",
2451
2451
  PREMIUM_PORTAL: "premium:portal",
2452
2452
  PREMIUM_RESET: "premium:reset",
2453
+ PREMIUM_TRACK_CONTEXT: "premium:track-context",
2453
2454
  PREMIUM_UPDATE: "premium:update",
2454
2455
  // Agent Credential Vault
2455
2456
  VAULT_LIST: "vault:list",
@@ -3471,6 +3472,9 @@ function stopBackgroundRevalidation() {
3471
3472
  revalidationTimer = null;
3472
3473
  }
3473
3474
  }
3475
+ function isPremiumActiveState(state2) {
3476
+ return state2.status === "active" || state2.status === "trialing";
3477
+ }
3474
3478
  const POSTHOG_API_KEY = process.env.POSTHOG_API_KEY || "phc_OMeM3P5cxJwl14lOKxYad0Yre52xvjNfkLEFnPtXyM";
3475
3479
  const POSTHOG_HOST = process.env.POSTHOG_HOST || "https://us.i.posthog.com";
3476
3480
  const BATCH_INTERVAL_MS = 6e4;
@@ -13743,6 +13747,69 @@ async function requestConsent(request) {
13743
13747
  }
13744
13748
  let httpServer = null;
13745
13749
  let mcpAuthToken = null;
13750
+ const MCP_AUTH_FILENAME = "mcp-auth.json";
13751
+ function getMcpAuthFilePath() {
13752
+ const configDir = process.env.VESSEL_CONFIG_DIR || path$1.join(
13753
+ process.env.XDG_CONFIG_HOME || path$1.join(os.homedir(), ".config"),
13754
+ "vessel"
13755
+ );
13756
+ return path$1.join(configDir, MCP_AUTH_FILENAME);
13757
+ }
13758
+ function readMcpAuthFile() {
13759
+ try {
13760
+ const raw = fs$1.readFileSync(getMcpAuthFilePath(), "utf8");
13761
+ const parsed = JSON.parse(raw);
13762
+ return parsed && typeof parsed === "object" ? parsed : null;
13763
+ } catch {
13764
+ return null;
13765
+ }
13766
+ }
13767
+ const MIN_TOKEN_LENGTH = 32;
13768
+ function getPersistentMcpAuthToken() {
13769
+ const existingToken = readMcpAuthFile()?.token?.trim();
13770
+ if (existingToken && existingToken.length >= MIN_TOKEN_LENGTH) {
13771
+ return existingToken;
13772
+ }
13773
+ return crypto$2.randomBytes(32).toString("hex");
13774
+ }
13775
+ function writeMcpAuthFile(endpoint, token) {
13776
+ try {
13777
+ const filePath = getMcpAuthFilePath();
13778
+ fs$1.mkdirSync(path$1.dirname(filePath), { recursive: true });
13779
+ fs$1.writeFileSync(
13780
+ filePath,
13781
+ JSON.stringify({ endpoint, token, pid: process.pid }, null, 2) + "\n",
13782
+ { mode: 384 }
13783
+ );
13784
+ } catch (err) {
13785
+ console.warn("[Vessel MCP] Failed to write auth file:", err);
13786
+ }
13787
+ }
13788
+ function clearMcpAuthFile() {
13789
+ const existingToken = readMcpAuthFile()?.token?.trim();
13790
+ if (!existingToken) {
13791
+ try {
13792
+ fs$1.unlinkSync(getMcpAuthFilePath());
13793
+ } catch {
13794
+ }
13795
+ return;
13796
+ }
13797
+ try {
13798
+ const filePath = getMcpAuthFilePath();
13799
+ fs$1.mkdirSync(path$1.dirname(filePath), { recursive: true });
13800
+ fs$1.writeFileSync(
13801
+ filePath,
13802
+ JSON.stringify(
13803
+ { endpoint: "", token: existingToken, pid: null },
13804
+ null,
13805
+ 2
13806
+ ) + "\n",
13807
+ { mode: 384 }
13808
+ );
13809
+ } catch (err) {
13810
+ console.warn("[Vessel MCP] Failed to clear auth file:", err);
13811
+ }
13812
+ }
13746
13813
  function asTextResponse(text) {
13747
13814
  return { content: [{ type: "text", text }] };
13748
13815
  }
@@ -15198,7 +15265,7 @@ function registerTools(server, tabManager, runtime2) {
15198
15265
  else if (tier === 1) score = 30;
15199
15266
  else score = 40;
15200
15267
  return {
15201
- name: `vessel_${def.name}`,
15268
+ name: def.name,
15202
15269
  title: def.title,
15203
15270
  description: def.description,
15204
15271
  tier,
@@ -15230,10 +15297,10 @@ function registerTools(server, tabManager, runtime2) {
15230
15297
  }
15231
15298
  );
15232
15299
  server.registerTool(
15233
- "vessel_current_tab",
15300
+ "current_tab",
15234
15301
  {
15235
15302
  title: "Get Active Tab",
15236
- description: "Return the browser tab the human is actively looking at right now. Use this instead of vessel_list_tabs when you only need the focused tab."
15303
+ description: "Return the browser tab the human is actively looking at right now. Use this instead of list_tabs when you only need the focused tab."
15237
15304
  },
15238
15305
  async () => {
15239
15306
  const activeTab = getActiveTabSummary(tabManager);
@@ -15242,7 +15309,7 @@ function registerTools(server, tabManager, runtime2) {
15242
15309
  }
15243
15310
  );
15244
15311
  server.registerTool(
15245
- "vessel_publish_transcript",
15312
+ "publish_transcript",
15246
15313
  {
15247
15314
  title: "Publish Agent Transcript",
15248
15315
  description: "Publish or stream agent reasoning/status text into Vessel's in-browser transcript monitor. Intended for external harnesses that want to mirror live thinking into the browser UI.",
@@ -15283,7 +15350,7 @@ function registerTools(server, tabManager, runtime2) {
15283
15350
  }
15284
15351
  );
15285
15352
  server.registerTool(
15286
- "vessel_clear_transcript",
15353
+ "clear_transcript",
15287
15354
  {
15288
15355
  title: "Clear Agent Transcript",
15289
15356
  description: "Clear the in-browser transcript monitor state."
@@ -15334,7 +15401,7 @@ ${buildScopedContext(pageContent, mode)}`;
15334
15401
  ${buildScopedContext(pageContent, mode)}`;
15335
15402
  }
15336
15403
  server.registerTool(
15337
- "vessel_extract_content",
15404
+ "extract_content",
15338
15405
  {
15339
15406
  title: "Extract Page Content",
15340
15407
  description: "Extract structured content from the current page. Modes: 'full' (default, everything), 'summary' (title+headings+stats), 'interactives_only' (clickable elements with indices), 'forms_only' (form fields only), 'text_only' (page text, no interactives), 'visible_only' (only currently visible, in-viewport, unobstructed elements plus active overlays), 'results_only' (likely primary search/result links only).",
@@ -15366,7 +15433,7 @@ ${buildScopedContext(pageContent, mode)}`;
15366
15433
  }
15367
15434
  );
15368
15435
  server.registerTool(
15369
- "vessel_read_page",
15436
+ "read_page",
15370
15437
  {
15371
15438
  title: "Read Page",
15372
15439
  description: "Read the active tab's page content. Includes saved highlights plus any active text selection or visible unsaved highlights on the page. Supports modes: full (default — includes highlights section), summary, interactives_only, forms_only, text_only, visible_only, results_only.",
@@ -15398,7 +15465,7 @@ ${buildScopedContext(pageContent, mode)}`;
15398
15465
  }
15399
15466
  );
15400
15467
  server.registerTool(
15401
- "vessel_list_tabs",
15468
+ "list_tabs",
15402
15469
  {
15403
15470
  title: "List Tabs",
15404
15471
  description: "List all open browser tabs with their IDs, titles, and URLs."
@@ -15414,7 +15481,7 @@ ${buildScopedContext(pageContent, mode)}`;
15414
15481
  }
15415
15482
  );
15416
15483
  server.registerTool(
15417
- "vessel_navigate",
15484
+ "navigate",
15418
15485
  {
15419
15486
  title: "Navigate",
15420
15487
  description: "Navigate the active browser tab to a URL. Use postBody to submit data via POST request (e.g. form submissions).",
@@ -15455,7 +15522,7 @@ ${buildScopedContext(pageContent, mode)}`;
15455
15522
  }
15456
15523
  );
15457
15524
  server.registerTool(
15458
- "vessel_set_ad_blocking",
15525
+ "set_ad_blocking",
15459
15526
  {
15460
15527
  title: "Set Ad Blocking",
15461
15528
  description: "Enable or disable ad blocking for the active tab or a matched tab. Reload after changes unless reload is false.",
@@ -15500,7 +15567,7 @@ ${buildScopedContext(pageContent, mode)}`;
15500
15567
  }
15501
15568
  );
15502
15569
  server.registerTool(
15503
- "vessel_extract_structured_data",
15570
+ "extract_structured_data",
15504
15571
  {
15505
15572
  title: "Extract Structured Data",
15506
15573
  description: "Return normalized structured data derived from page JSON-LD, microdata, RDFa, and high-signal meta tags. Useful for recipes, products, articles, events, FAQs, and other schema-rich pages.",
@@ -15553,7 +15620,7 @@ ${buildScopedContext(pageContent, mode)}`;
15553
15620
  }
15554
15621
  );
15555
15622
  server.registerTool(
15556
- "vessel_go_back",
15623
+ "go_back",
15557
15624
  {
15558
15625
  title: "Go Back",
15559
15626
  description: "Go back in browser history."
@@ -15574,7 +15641,7 @@ ${buildScopedContext(pageContent, mode)}`;
15574
15641
  }
15575
15642
  );
15576
15643
  server.registerTool(
15577
- "vessel_go_forward",
15644
+ "go_forward",
15578
15645
  {
15579
15646
  title: "Go Forward",
15580
15647
  description: "Go forward in browser history."
@@ -15595,7 +15662,7 @@ ${buildScopedContext(pageContent, mode)}`;
15595
15662
  }
15596
15663
  );
15597
15664
  server.registerTool(
15598
- "vessel_reload",
15665
+ "reload",
15599
15666
  {
15600
15667
  title: "Reload",
15601
15668
  description: "Reload the current page."
@@ -15611,7 +15678,7 @@ ${buildScopedContext(pageContent, mode)}`;
15611
15678
  }
15612
15679
  );
15613
15680
  server.registerTool(
15614
- "vessel_click",
15681
+ "click",
15615
15682
  {
15616
15683
  title: "Click Element",
15617
15684
  description: "Click an element on the page by its index number or CSS selector.",
@@ -15640,7 +15707,7 @@ ${buildScopedContext(pageContent, mode)}`;
15640
15707
  }
15641
15708
  );
15642
15709
  server.registerTool(
15643
- "vessel_hover",
15710
+ "hover",
15644
15711
  {
15645
15712
  title: "Hover Element",
15646
15713
  description: "Move the mouse pointer over an element to trigger hover states, tooltips, or dropdown menus.",
@@ -15669,7 +15736,7 @@ ${buildScopedContext(pageContent, mode)}`;
15669
15736
  }
15670
15737
  );
15671
15738
  server.registerTool(
15672
- "vessel_focus",
15739
+ "focus",
15673
15740
  {
15674
15741
  title: "Focus Element",
15675
15742
  description: "Focus an input, button, or interactive element. Useful before pressing keys or to trigger focus-dependent UI.",
@@ -15698,7 +15765,7 @@ ${buildScopedContext(pageContent, mode)}`;
15698
15765
  }
15699
15766
  );
15700
15767
  server.registerTool(
15701
- "vessel_extract_text",
15768
+ "extract_text",
15702
15769
  {
15703
15770
  title: "Extract Element Text",
15704
15771
  description: "Extract the text content of a specific element by its index number or CSS selector.",
@@ -15779,7 +15846,7 @@ ${buildScopedContext(pageContent, mode)}`;
15779
15846
  }
15780
15847
  );
15781
15848
  server.registerTool(
15782
- "vessel_type",
15849
+ "type",
15783
15850
  {
15784
15851
  title: "Type Text",
15785
15852
  description: "Type text into an input field or textarea. Clears existing content first.",
@@ -15818,10 +15885,10 @@ ${buildScopedContext(pageContent, mode)}`;
15818
15885
  }
15819
15886
  );
15820
15887
  server.registerTool(
15821
- "vessel_type_text",
15888
+ "type_text",
15822
15889
  {
15823
15890
  title: "Type Text",
15824
- description: "Alias for vessel_type. Type text into an input field or textarea.",
15891
+ description: "Alias for type. Type text into an input field or textarea.",
15825
15892
  inputSchema: {
15826
15893
  index: zod.z.number().optional().describe("Element index from the page content listing"),
15827
15894
  selector: zod.z.string().optional().describe("CSS selector as fallback"),
@@ -15857,7 +15924,7 @@ ${buildScopedContext(pageContent, mode)}`;
15857
15924
  }
15858
15925
  );
15859
15926
  server.registerTool(
15860
- "vessel_select_option",
15927
+ "select_option",
15861
15928
  {
15862
15929
  title: "Select Option",
15863
15930
  description: "Select an option in a dropdown by label or value.",
@@ -15881,7 +15948,7 @@ ${buildScopedContext(pageContent, mode)}`;
15881
15948
  }
15882
15949
  );
15883
15950
  server.registerTool(
15884
- "vessel_submit_form",
15951
+ "submit_form",
15885
15952
  {
15886
15953
  title: "Submit Form",
15887
15954
  description: "Submit a form using a field index, submit button index, form selector, or button selector.",
@@ -15913,7 +15980,7 @@ ${buildScopedContext(pageContent, mode)}`;
15913
15980
  }
15914
15981
  );
15915
15982
  server.registerTool(
15916
- "vessel_press_key",
15983
+ "press_key",
15917
15984
  {
15918
15985
  title: "Press Key",
15919
15986
  description: "Press a keyboard key, optionally after focusing an element.",
@@ -15948,7 +16015,7 @@ ${buildScopedContext(pageContent, mode)}`;
15948
16015
  }
15949
16016
  );
15950
16017
  server.registerTool(
15951
- "vessel_scroll",
16018
+ "scroll",
15952
16019
  {
15953
16020
  title: "Scroll Page",
15954
16021
  description: "Scroll the page up or down.",
@@ -15977,7 +16044,7 @@ ${buildScopedContext(pageContent, mode)}`;
15977
16044
  }
15978
16045
  );
15979
16046
  server.registerTool(
15980
- "vessel_dismiss_popup",
16047
+ "dismiss_popup",
15981
16048
  {
15982
16049
  title: "Dismiss Popup",
15983
16050
  description: "Dismiss a modal, popup, newsletter gate, cookie banner, or blocking overlay using common close and decline actions."
@@ -15995,7 +16062,7 @@ ${buildScopedContext(pageContent, mode)}`;
15995
16062
  }
15996
16063
  );
15997
16064
  server.registerTool(
15998
- "vessel_clear_overlays",
16065
+ "clear_overlays",
15999
16066
  {
16000
16067
  title: "Clear Overlays",
16001
16068
  description: "Work through blocking overlays and modals until the page is unblocked, using overlay-specific heuristics for consent banners and radio-selection dialogs.",
@@ -16021,7 +16088,7 @@ ${buildScopedContext(pageContent, mode)}`;
16021
16088
  }
16022
16089
  );
16023
16090
  server.registerTool(
16024
- "vessel_wait_for",
16091
+ "wait_for",
16025
16092
  {
16026
16093
  title: "Wait For",
16027
16094
  description: "Wait for text or a selector to appear on the current page.",
@@ -16044,7 +16111,7 @@ ${buildScopedContext(pageContent, mode)}`;
16044
16111
  }
16045
16112
  );
16046
16113
  server.registerTool(
16047
- "vessel_create_tab",
16114
+ "create_tab",
16048
16115
  {
16049
16116
  title: "Create Tab",
16050
16117
  description: "Open a new browser tab, optionally navigating to a URL.",
@@ -16062,7 +16129,7 @@ ${buildScopedContext(pageContent, mode)}`;
16062
16129
  })
16063
16130
  );
16064
16131
  server.registerTool(
16065
- "vessel_switch_tab",
16132
+ "switch_tab",
16066
16133
  {
16067
16134
  title: "Switch Tab",
16068
16135
  description: "Switch to a different browser tab by ID or title/URL match.",
@@ -16087,7 +16154,7 @@ ${buildScopedContext(pageContent, mode)}`;
16087
16154
  )
16088
16155
  );
16089
16156
  server.registerTool(
16090
- "vessel_close_tab",
16157
+ "close_tab",
16091
16158
  {
16092
16159
  title: "Close Tab",
16093
16160
  description: "Close a browser tab by its ID.",
@@ -16101,7 +16168,7 @@ ${buildScopedContext(pageContent, mode)}`;
16101
16168
  })
16102
16169
  );
16103
16170
  server.registerTool(
16104
- "vessel_checkpoint_create",
16171
+ "checkpoint_create",
16105
16172
  {
16106
16173
  title: "Create Checkpoint",
16107
16174
  description: "Capture the current session as a named checkpoint.",
@@ -16122,7 +16189,7 @@ ${buildScopedContext(pageContent, mode)}`;
16122
16189
  )
16123
16190
  );
16124
16191
  server.registerTool(
16125
- "vessel_checkpoint_restore",
16192
+ "checkpoint_restore",
16126
16193
  {
16127
16194
  title: "Restore Checkpoint",
16128
16195
  description: "Restore a saved checkpoint by ID or exact name.",
@@ -16148,7 +16215,7 @@ ${buildScopedContext(pageContent, mode)}`;
16148
16215
  )
16149
16216
  );
16150
16217
  server.registerTool(
16151
- "vessel_save_session",
16218
+ "save_session",
16152
16219
  {
16153
16220
  title: "Save Session",
16154
16221
  description: "Persist the current cookies, localStorage, and tab layout under a reusable session name.",
@@ -16165,7 +16232,7 @@ ${buildScopedContext(pageContent, mode)}`;
16165
16232
  })
16166
16233
  );
16167
16234
  server.registerTool(
16168
- "vessel_load_session",
16235
+ "load_session",
16169
16236
  {
16170
16237
  title: "Load Session",
16171
16238
  description: "Load a previously saved named session, restoring cookies, localStorage, and saved tabs.",
@@ -16182,7 +16249,7 @@ ${buildScopedContext(pageContent, mode)}`;
16182
16249
  })
16183
16250
  );
16184
16251
  server.registerTool(
16185
- "vessel_list_sessions",
16252
+ "list_sessions",
16186
16253
  {
16187
16254
  title: "List Sessions",
16188
16255
  description: "List previously saved named browser sessions with cookie and storage counts."
@@ -16196,7 +16263,7 @@ ${buildScopedContext(pageContent, mode)}`;
16196
16263
  })
16197
16264
  );
16198
16265
  server.registerTool(
16199
- "vessel_delete_session",
16266
+ "delete_session",
16200
16267
  {
16201
16268
  title: "Delete Session",
16202
16269
  description: "Delete a previously saved named browser session.",
@@ -16213,7 +16280,7 @@ ${buildScopedContext(pageContent, mode)}`;
16213
16280
  )
16214
16281
  );
16215
16282
  server.registerTool(
16216
- "vessel_screenshot",
16283
+ "screenshot",
16217
16284
  {
16218
16285
  title: "Screenshot",
16219
16286
  description: "Capture a screenshot of the current page. Returns a base64-encoded PNG image."
@@ -16265,7 +16332,7 @@ To analyze visually, call vision_analyze with image_url="${screenshotPath}"`
16265
16332
  }
16266
16333
  );
16267
16334
  server.registerTool(
16268
- "vessel_highlight",
16335
+ "highlight",
16269
16336
  {
16270
16337
  title: "Highlight Element",
16271
16338
  description: "Visually highlight an element or text on the page for the user. Use to draw attention to specific parts of the page. Highlights persist until cleared. Set persist=true to save the highlight so it re-appears when the user revisits this page.",
@@ -16332,7 +16399,7 @@ To analyze visually, call vision_analyze with image_url="${screenshotPath}"`
16332
16399
  }
16333
16400
  );
16334
16401
  server.registerTool(
16335
- "vessel_clear_highlights",
16402
+ "clear_highlights",
16336
16403
  {
16337
16404
  title: "Clear Highlights",
16338
16405
  description: "Remove all visual highlights from the current page, including any saved persistent highlights for this URL."
@@ -16355,7 +16422,7 @@ To analyze visually, call vision_analyze with image_url="${screenshotPath}"`
16355
16422
  }
16356
16423
  );
16357
16424
  server.registerTool(
16358
- "vessel_list_highlights",
16425
+ "list_highlights",
16359
16426
  {
16360
16427
  title: "List Highlights",
16361
16428
  description: "List highlights related to the current browsing session. Includes saved persistent highlights plus the active tab's live text selection and any visible unsaved highlight marks. IMPORTANT: When the user says they highlighted or selected text, call this tool before falling back to screenshots or vision.",
@@ -16447,10 +16514,10 @@ ${JSON.stringify(otherHighlights, null, 2)}`
16447
16514
  }
16448
16515
  );
16449
16516
  server.registerTool(
16450
- "vessel_remove_highlight",
16517
+ "remove_highlight",
16451
16518
  {
16452
16519
  title: "Remove Persistent Highlight",
16453
- description: "Remove a persistent highlight by ID and clear it from any open tab. Use vessel_list_highlights to find IDs.",
16520
+ description: "Remove a persistent highlight by ID and clear it from any open tab. Use list_highlights to find IDs.",
16454
16521
  inputSchema: {
16455
16522
  id: zod.z.string().describe("ID of the highlight to remove")
16456
16523
  }
@@ -16486,7 +16553,7 @@ ${JSON.stringify(otherHighlights, null, 2)}`
16486
16553
  }
16487
16554
  );
16488
16555
  server.registerTool(
16489
- "vessel_create_folder",
16556
+ "create_folder",
16490
16557
  {
16491
16558
  title: "Create Bookmark Folder",
16492
16559
  description: "Create a named folder for organizing bookmarks. If a folder with the same name already exists, return it instead of duplicating it.",
@@ -16517,7 +16584,7 @@ ${JSON.stringify(otherHighlights, null, 2)}`
16517
16584
  }
16518
16585
  );
16519
16586
  server.registerTool(
16520
- "vessel_bookmark_save",
16587
+ "bookmark_save",
16521
16588
  {
16522
16589
  title: "Save Bookmark",
16523
16590
  description: "Save the current page, a specific URL, or a link target from the current page into a bookmark folder. You can provide folder_id or folder_name; missing folder names can be created automatically.",
@@ -16627,7 +16694,7 @@ ${JSON.stringify(otherHighlights, null, 2)}`
16627
16694
  }
16628
16695
  );
16629
16696
  server.registerTool(
16630
- "vessel_bookmark_list",
16697
+ "bookmark_list",
16631
16698
  {
16632
16699
  title: "List Bookmarks",
16633
16700
  description: "List all bookmark folders and their contents. Optionally filter by folder.",
@@ -16677,7 +16744,7 @@ ${JSON.stringify(otherHighlights, null, 2)}`
16677
16744
  }
16678
16745
  );
16679
16746
  server.registerTool(
16680
- "vessel_bookmark_organize",
16747
+ "bookmark_organize",
16681
16748
  {
16682
16749
  title: "Organize Bookmark",
16683
16750
  description: "Organize a bookmark by intent: save or move a bookmark into a folder, creating the folder if needed. Works with bookmark_id, url, a link target from the current page, or the current page itself.",
@@ -16760,7 +16827,7 @@ ${JSON.stringify(otherHighlights, null, 2)}`
16760
16827
  }
16761
16828
  );
16762
16829
  server.registerTool(
16763
- "vessel_bookmark_search",
16830
+ "bookmark_search",
16764
16831
  {
16765
16832
  title: "Search Bookmarks",
16766
16833
  description: "Search bookmarks by title, URL, note, folder name, or folder summary.",
@@ -16791,7 +16858,7 @@ ${JSON.stringify(otherHighlights, null, 2)}`
16791
16858
  }
16792
16859
  );
16793
16860
  server.registerTool(
16794
- "vessel_bookmark_remove",
16861
+ "bookmark_remove",
16795
16862
  {
16796
16863
  title: "Remove Bookmark",
16797
16864
  description: "Remove a specific bookmark by its ID.",
@@ -16813,7 +16880,7 @@ ${JSON.stringify(otherHighlights, null, 2)}`
16813
16880
  }
16814
16881
  );
16815
16882
  server.registerTool(
16816
- "vessel_bookmark_archive",
16883
+ "bookmark_archive",
16817
16884
  {
16818
16885
  title: "Archive Bookmark",
16819
16886
  description: 'Archive the current page, a URL, a link target from the current page, or an existing bookmark into the default "Archive" folder.',
@@ -16893,7 +16960,7 @@ ${JSON.stringify(otherHighlights, null, 2)}`
16893
16960
  }
16894
16961
  );
16895
16962
  server.registerTool(
16896
- "vessel_bookmark_open",
16963
+ "bookmark_open",
16897
16964
  {
16898
16965
  title: "Open Bookmark",
16899
16966
  description: "Open a saved bookmark by bookmark ID. Optionally open it in a new tab.",
@@ -16937,7 +17004,7 @@ ${JSON.stringify(otherHighlights, null, 2)}`
16937
17004
  }
16938
17005
  );
16939
17006
  server.registerTool(
16940
- "vessel_folder_remove",
17007
+ "folder_remove",
16941
17008
  {
16942
17009
  title: "Remove Bookmark Folder",
16943
17010
  description: "Remove a folder. Bookmarks in it are moved to Unsorted.",
@@ -16961,7 +17028,7 @@ ${JSON.stringify(otherHighlights, null, 2)}`
16961
17028
  }
16962
17029
  );
16963
17030
  server.registerTool(
16964
- "vessel_folder_rename",
17031
+ "folder_rename",
16965
17032
  {
16966
17033
  title: "Rename Bookmark Folder",
16967
17034
  description: "Rename an existing bookmark folder.",
@@ -16995,7 +17062,7 @@ ${JSON.stringify(otherHighlights, null, 2)}`
16995
17062
  }
16996
17063
  );
16997
17064
  server.registerTool(
16998
- "vessel_memory_note_create",
17065
+ "memory_note_create",
16999
17066
  {
17000
17067
  title: "Create Memory Note",
17001
17068
  description: "Write a markdown note into the configured Obsidian vault for research notes, breadcrumbs, or synthesis.",
@@ -17022,7 +17089,7 @@ ${JSON.stringify(otherHighlights, null, 2)}`
17022
17089
  }
17023
17090
  );
17024
17091
  server.registerTool(
17025
- "vessel_memory_append",
17092
+ "memory_append",
17026
17093
  {
17027
17094
  title: "Append Memory Note",
17028
17095
  description: "Append markdown content to an existing note in the configured Obsidian vault.",
@@ -17050,7 +17117,7 @@ ${JSON.stringify(otherHighlights, null, 2)}`
17050
17117
  }
17051
17118
  );
17052
17119
  server.registerTool(
17053
- "vessel_memory_list",
17120
+ "memory_list",
17054
17121
  {
17055
17122
  title: "List Memory Notes",
17056
17123
  description: "List recent markdown notes in the configured Obsidian vault.",
@@ -17078,7 +17145,7 @@ ${JSON.stringify(otherHighlights, null, 2)}`
17078
17145
  }
17079
17146
  );
17080
17147
  server.registerTool(
17081
- "vessel_memory_search",
17148
+ "memory_search",
17082
17149
  {
17083
17150
  title: "Search Memory Notes",
17084
17151
  description: "Search markdown notes in the configured Obsidian vault by title, path, body, and optional tags.",
@@ -17108,7 +17175,7 @@ ${JSON.stringify(otherHighlights, null, 2)}`
17108
17175
  }
17109
17176
  );
17110
17177
  server.registerTool(
17111
- "vessel_memory_page_capture",
17178
+ "memory_page_capture",
17112
17179
  {
17113
17180
  title: "Capture Page To Memory",
17114
17181
  description: "Capture the current page into the configured Obsidian vault as a markdown note with URL, excerpt, and content snapshot.",
@@ -17144,7 +17211,7 @@ ${JSON.stringify(otherHighlights, null, 2)}`
17144
17211
  }
17145
17212
  );
17146
17213
  server.registerTool(
17147
- "vessel_memory_link_bookmark",
17214
+ "memory_link_bookmark",
17148
17215
  {
17149
17216
  title: "Link Bookmark To Memory",
17150
17217
  description: "Create a note for a bookmark or append bookmark details into an existing memory note.",
@@ -17184,7 +17251,7 @@ ${JSON.stringify(otherHighlights, null, 2)}`
17184
17251
  }
17185
17252
  );
17186
17253
  server.registerTool(
17187
- "vessel_flow_start",
17254
+ "flow_start",
17188
17255
  {
17189
17256
  title: "Start Workflow",
17190
17257
  description: "Begin tracking a multi-step web workflow. Vessel will show progress after every action so you always know where you are in the flow.",
@@ -17212,7 +17279,7 @@ ${flow.steps.map((s, i) => ` ${i === 0 ? "→" : " "} ${s.label}`).join("\n")}`
17212
17279
  }
17213
17280
  );
17214
17281
  server.registerTool(
17215
- "vessel_flow_advance",
17282
+ "flow_advance",
17216
17283
  {
17217
17284
  title: "Advance Workflow Step",
17218
17285
  description: "Mark the current workflow step as done and move to the next one. Call this after completing each step.",
@@ -17228,7 +17295,7 @@ ${flow.steps.map((s, i) => ` ${i === 0 ? "→" : " "} ${s.label}`).join("\n")}`
17228
17295
  }
17229
17296
  );
17230
17297
  server.registerTool(
17231
- "vessel_flow_status",
17298
+ "flow_status",
17232
17299
  {
17233
17300
  title: "Workflow Status",
17234
17301
  description: "Check the current workflow progress."
@@ -17240,7 +17307,7 @@ ${flow.steps.map((s, i) => ` ${i === 0 ? "→" : " "} ${s.label}`).join("\n")}`
17240
17307
  }
17241
17308
  );
17242
17309
  server.registerTool(
17243
- "vessel_flow_end",
17310
+ "flow_end",
17244
17311
  {
17245
17312
  title: "End Workflow",
17246
17313
  description: "Clear the active workflow tracker."
@@ -17251,7 +17318,7 @@ ${flow.steps.map((s, i) => ` ${i === 0 ? "→" : " "} ${s.label}`).join("\n")}`
17251
17318
  }
17252
17319
  );
17253
17320
  server.registerTool(
17254
- "vessel_suggest",
17321
+ "suggest",
17255
17322
  {
17256
17323
  title: "What Should I Do?",
17257
17324
  description: "Analyze the current page and return the most relevant tools and suggested next actions. Call this when you're unsure what to do next — it reads the page context and tells you the optimal approach."
@@ -17260,7 +17327,7 @@ ${flow.steps.map((s, i) => ` ${i === 0 ? "→" : " "} ${s.label}`).join("\n")}`
17260
17327
  const tab = tabManager.getActiveTab();
17261
17328
  if (!tab)
17262
17329
  return asTextResponse(
17263
- "No active tab. Use vessel_navigate to open a page."
17330
+ "No active tab. Use navigate to open a page."
17264
17331
  );
17265
17332
  const wc = tab.view.webContents;
17266
17333
  let page;
@@ -17268,7 +17335,7 @@ ${flow.steps.map((s, i) => ` ${i === 0 ? "→" : " "} ${s.label}`).join("\n")}`
17268
17335
  page = await extractContent(wc);
17269
17336
  } catch {
17270
17337
  return asTextResponse(
17271
- "Could not read page. Try vessel_navigate to a working URL."
17338
+ "Could not read page. Try navigate to a working URL."
17272
17339
  );
17273
17340
  }
17274
17341
  const suggestions = [];
@@ -17298,50 +17365,50 @@ ${flow.steps.map((s, i) => ` ${i === 0 ? "→" : " "} ${s.label}`).join("\n")}`
17298
17365
  const hasOverlays = page.overlays.some((o) => o.blocksInteraction);
17299
17366
  if (hasOverlays) {
17300
17367
  suggestions.push("⚠ BLOCKING OVERLAY detected — dismiss it first:");
17301
- suggestions.push(" → vessel_clear_overlays for stacked modals");
17302
- suggestions.push(" → or vessel_dismiss_popup for a single popup");
17368
+ suggestions.push(" → clear_overlays for stacked modals");
17369
+ suggestions.push(" → or dismiss_popup for a single popup");
17303
17370
  suggestions.push("");
17304
17371
  }
17305
17372
  if (hasPasswordField) {
17306
17373
  suggestions.push("🔑 LOGIN PAGE detected:");
17307
17374
  suggestions.push(
17308
- " → vessel_login(username, password) — handles the full flow"
17375
+ " → login(username, password) — handles the full flow"
17309
17376
  );
17310
17377
  suggestions.push(
17311
- " → Or vessel_fill_form + vessel_submit_form for manual control"
17378
+ " → Or fill_form + submit_form for manual control"
17312
17379
  );
17313
17380
  } else if (hasSearchInput && linkCount < 10) {
17314
17381
  suggestions.push("🔍 SEARCH PAGE detected:");
17315
17382
  suggestions.push(
17316
- " → vessel_search(query) — finds the box, types, submits"
17383
+ " → search(query) — finds the box, types, submits"
17317
17384
  );
17318
17385
  } else if (hasSearchInput && linkCount >= 10) {
17319
17386
  suggestions.push("📋 SEARCH RESULTS detected:");
17320
- suggestions.push(" → vessel_click on a result link");
17387
+ suggestions.push(" → click on a result link");
17321
17388
  if (hasPagination) {
17322
- suggestions.push(" → vessel_paginate('next') for more results");
17389
+ suggestions.push(" → paginate('next') for more results");
17323
17390
  }
17324
17391
  } else if (formCount > 0) {
17325
17392
  suggestions.push(`📝 FORM detected (${totalFields} fields):`);
17326
17393
  suggestions.push(
17327
- " → vessel_fill_form(fields) — fill all fields at once"
17394
+ " → fill_form(fields) — fill all fields at once"
17328
17395
  );
17329
- suggestions.push(" → Or vessel_type for individual fields");
17396
+ suggestions.push(" → Or type for individual fields");
17330
17397
  } else if (hasPagination) {
17331
17398
  suggestions.push("📄 PAGINATED CONTENT:");
17332
- suggestions.push(" → vessel_extract_content to read this page");
17333
- suggestions.push(" → vessel_paginate('next') for the next page");
17399
+ suggestions.push(" → extract_content to read this page");
17400
+ suggestions.push(" → paginate('next') for the next page");
17334
17401
  } else if (page.content.length > 3e3 && page.interactiveElements.length < 10) {
17335
17402
  suggestions.push("📖 ARTICLE/CONTENT page:");
17336
- suggestions.push(" → vessel_extract_content for readable text");
17337
- suggestions.push(" → vessel_scroll to see more");
17403
+ suggestions.push(" → extract_content for readable text");
17404
+ suggestions.push(" → scroll to see more");
17338
17405
  } else {
17339
17406
  suggestions.push("🌐 GENERAL PAGE:");
17340
17407
  suggestions.push(
17341
- " → vessel_extract_content to understand the page structure"
17408
+ " → extract_content to understand the page structure"
17342
17409
  );
17343
- suggestions.push(" → vessel_click on any element by index");
17344
- suggestions.push(" → vessel_navigate to go somewhere new");
17410
+ suggestions.push(" → click on any element by index");
17411
+ suggestions.push(" → navigate to go somewhere new");
17345
17412
  }
17346
17413
  suggestions.push("");
17347
17414
  suggestions.push(
@@ -17351,7 +17418,7 @@ ${flow.steps.map((s, i) => ` ${i === 0 ? "→" : " "} ${s.label}`).join("\n")}`
17351
17418
  }
17352
17419
  );
17353
17420
  server.registerTool(
17354
- "vessel_fill_form",
17421
+ "fill_form",
17355
17422
  {
17356
17423
  title: "Fill Form",
17357
17424
  description: "Fill multiple form fields at once. Provide a map of field identifiers to values. Fields are matched by index, name, label, or placeholder. Much faster than calling type for each field individually.",
@@ -17402,7 +17469,7 @@ ${results.join("\n")}`;
17402
17469
  }
17403
17470
  );
17404
17471
  server.registerTool(
17405
- "vessel_login",
17472
+ "login",
17406
17473
  {
17407
17474
  title: "Login",
17408
17475
  description: "Compound action: navigate to a login page, fill credentials, and submit. Handles the full login flow in one call.",
@@ -17493,7 +17560,7 @@ ${steps.join("\n")}`;
17493
17560
  }
17494
17561
  );
17495
17562
  server.registerTool(
17496
- "vessel_search",
17563
+ "search",
17497
17564
  {
17498
17565
  title: "Search",
17499
17566
  description: "Compound action: find a search box on the current page, type a query, and submit. Returns the resulting page state.",
@@ -17576,7 +17643,7 @@ ${steps.join("\n")}`;
17576
17643
  }
17577
17644
  );
17578
17645
  server.registerTool(
17579
- "vessel_paginate",
17646
+ "paginate",
17580
17647
  {
17581
17648
  title: "Paginate",
17582
17649
  description: "Navigate to the next or previous page of results. Auto-detects pagination controls.",
@@ -17632,7 +17699,7 @@ ${steps.join("\n")}`;
17632
17699
  }
17633
17700
  );
17634
17701
  server.registerTool(
17635
- "vessel_accept_cookies",
17702
+ "accept_cookies",
17636
17703
  {
17637
17704
  title: "Accept Cookies",
17638
17705
  description: "Dismiss cookie consent banners (OneTrust, CookieBot, GDPR popups, etc.).",
@@ -17644,7 +17711,7 @@ ${steps.join("\n")}`;
17644
17711
  return withAction(
17645
17712
  runtime2,
17646
17713
  tabManager,
17647
- "vessel_accept_cookies",
17714
+ "accept_cookies",
17648
17715
  {},
17649
17716
  async () => {
17650
17717
  const wc = tab.view.webContents;
@@ -17681,13 +17748,13 @@ ${steps.join("\n")}`;
17681
17748
  return null;
17682
17749
  })()
17683
17750
  `);
17684
- return dismissed || "No cookie consent banner detected. Try vessel_dismiss_popup for other overlays.";
17751
+ return dismissed || "No cookie consent banner detected. Try dismiss_popup for other overlays.";
17685
17752
  }
17686
17753
  );
17687
17754
  }
17688
17755
  );
17689
17756
  server.registerTool(
17690
- "vessel_extract_table",
17757
+ "extract_table",
17691
17758
  {
17692
17759
  title: "Extract Table",
17693
17760
  description: "Extract a table from the page as structured JSON rows with headers.",
@@ -17702,7 +17769,7 @@ ${steps.join("\n")}`;
17702
17769
  return withAction(
17703
17770
  runtime2,
17704
17771
  tabManager,
17705
- "vessel_extract_table",
17772
+ "extract_table",
17706
17773
  { index, selector: rawSelector },
17707
17774
  async () => {
17708
17775
  const wc = tab.view.webContents;
@@ -17741,7 +17808,7 @@ ${JSON.stringify(tableJson, null, 2)}`;
17741
17808
  }
17742
17809
  );
17743
17810
  server.registerTool(
17744
- "vessel_scroll_to_element",
17811
+ "scroll_to_element",
17745
17812
  {
17746
17813
  title: "Scroll To Element",
17747
17814
  description: "Scroll a specific element into view by index or selector.",
@@ -17757,7 +17824,7 @@ ${JSON.stringify(tableJson, null, 2)}`;
17757
17824
  return withAction(
17758
17825
  runtime2,
17759
17826
  tabManager,
17760
- "vessel_scroll_to_element",
17827
+ "scroll_to_element",
17761
17828
  { index, selector: rawSelector, position },
17762
17829
  async () => {
17763
17830
  const wc = tab.view.webContents;
@@ -17801,7 +17868,7 @@ ${JSON.stringify(tableJson, null, 2)}`;
17801
17868
  }
17802
17869
  );
17803
17870
  server.registerTool(
17804
- "vessel_wait_for_navigation",
17871
+ "wait_for_navigation",
17805
17872
  {
17806
17873
  title: "Wait For Navigation",
17807
17874
  description: "Wait for the current page to finish loading after a click or form submission.",
@@ -17815,7 +17882,7 @@ ${JSON.stringify(tableJson, null, 2)}`;
17815
17882
  return withAction(
17816
17883
  runtime2,
17817
17884
  tabManager,
17818
- "vessel_wait_for_navigation",
17885
+ "wait_for_navigation",
17819
17886
  { timeoutMs },
17820
17887
  async () => {
17821
17888
  const wc = tab.view.webContents;
@@ -17857,7 +17924,7 @@ ${JSON.stringify(tableJson, null, 2)}`;
17857
17924
  }
17858
17925
  );
17859
17926
  server.registerTool(
17860
- "vessel_vault_status",
17927
+ "vault_status",
17861
17928
  {
17862
17929
  title: "Check Vault Credentials",
17863
17930
  description: "Check whether stored credentials exist for a domain. Returns credential labels and usernames but NEVER password values. Use this before vault_login to verify credentials are available.",
@@ -17899,12 +17966,12 @@ ${JSON.stringify(tableJson, null, 2)}`;
17899
17966
  `Found ${matches.length} credential(s) for ${targetDomain}:
17900
17967
  ${summary}
17901
17968
 
17902
- Use vessel_vault_login to fill the login form. Credentials are filled directly — you will NOT see the password values.`
17969
+ Use vault_login to fill the login form. Credentials are filled directly — you will NOT see the password values.`
17903
17970
  );
17904
17971
  }
17905
17972
  );
17906
17973
  server.registerTool(
17907
- "vessel_vault_login",
17974
+ "vault_login",
17908
17975
  {
17909
17976
  title: "Fill Login with Vault Credentials",
17910
17977
  description: "Fill a login form on the current page using stored credentials from the Agent Credential Vault. The credential values are filled directly into the page — they are NEVER returned in this response. The user will see a consent dialog before credentials are used.",
@@ -18010,7 +18077,7 @@ Use vessel_vault_login to fill the login form. Credentials are filled directly
18010
18077
  }
18011
18078
  );
18012
18079
  server.registerTool(
18013
- "vessel_vault_totp",
18080
+ "vault_totp",
18014
18081
  {
18015
18082
  title: "Fill TOTP Code from Vault",
18016
18083
  description: "Generate a TOTP 2FA code from a stored secret and fill it into a code input field. The TOTP secret and generated code are NEVER returned — only filled directly into the page.",
@@ -18095,7 +18162,7 @@ Use vessel_vault_login to fill the login form. Credentials are filled directly
18095
18162
  }
18096
18163
  );
18097
18164
  server.registerTool(
18098
- "vessel_metrics",
18165
+ "metrics",
18099
18166
  {
18100
18167
  title: "Session Metrics",
18101
18168
  description: "Show performance metrics: total tool calls, average duration, per-tool breakdown.",
@@ -18279,7 +18346,7 @@ function startMcpServer(tabManager, runtime2, port) {
18279
18346
  status: "starting",
18280
18347
  message: `Starting MCP server on port ${port}.`
18281
18348
  });
18282
- mcpAuthToken = crypto$2.randomBytes(32).toString("hex");
18349
+ mcpAuthToken = getPersistentMcpAuthToken();
18283
18350
  return new Promise((resolve) => {
18284
18351
  const server = http.createServer(async (req, res) => {
18285
18352
  const url = new URL(req.url || "/", `http://localhost:${port}`);
@@ -18306,7 +18373,11 @@ function startMcpServer(tabManager, runtime2, port) {
18306
18373
  return;
18307
18374
  }
18308
18375
  const authHeader = req.headers.authorization;
18309
- if (!authHeader || authHeader !== `Bearer ${mcpAuthToken}`) {
18376
+ const expected = `Bearer ${mcpAuthToken}`;
18377
+ const headerBuf = Buffer.from(authHeader ?? "");
18378
+ const expectedBuf = Buffer.from(expected);
18379
+ const tokenValid = headerBuf.length === expectedBuf.length && crypto$2.timingSafeEqual(headerBuf, expectedBuf);
18380
+ if (!authHeader || !tokenValid) {
18310
18381
  res.writeHead(401, { "Content-Type": "application/json" });
18311
18382
  res.end(JSON.stringify({ error: "Unauthorized — missing or invalid bearer token" }));
18312
18383
  return;
@@ -18339,6 +18410,7 @@ function startMcpServer(tabManager, runtime2, port) {
18339
18410
  server.once("error", (error) => {
18340
18411
  const message = error.code === "EADDRINUSE" ? `Port ${port} is already in use. MCP server not started.` : error.message;
18341
18412
  console.error("[Vessel MCP] Server error:", error);
18413
+ clearMcpAuthFile();
18342
18414
  setMcpHealth({
18343
18415
  configuredPort: port,
18344
18416
  activePort: null,
@@ -18371,6 +18443,9 @@ function startMcpServer(tabManager, runtime2, port) {
18371
18443
  message: `MCP server listening on ${endpoint}.`
18372
18444
  });
18373
18445
  console.log(`[Vessel MCP] Server listening on ${endpoint} (auth enabled)`);
18446
+ if (mcpAuthToken) {
18447
+ writeMcpAuthFile(endpoint, mcpAuthToken);
18448
+ }
18374
18449
  finish({
18375
18450
  ok: true,
18376
18451
  configuredPort: port,
@@ -18396,6 +18471,7 @@ function stopMcpServer() {
18396
18471
  const server = httpServer;
18397
18472
  httpServer = null;
18398
18473
  mcpAuthToken = null;
18474
+ clearMcpAuthFile();
18399
18475
  server.close(() => {
18400
18476
  setMcpHealth({
18401
18477
  activePort: null,
@@ -18787,11 +18863,77 @@ function assertNumber(value, name) {
18787
18863
  const VALID_APPROVAL_MODES = /* @__PURE__ */ new Set(["auto", "confirm-dangerous", "manual"]);
18788
18864
  function registerIpcHandlers(windowState, runtime2) {
18789
18865
  const { tabManager, chromeView, sidebarView, devtoolsPanelView, mainWindow } = windowState;
18866
+ const premiumApiOrigin = process.env.VESSEL_PREMIUM_API ? new URL(process.env.VESSEL_PREMIUM_API).origin : "https://vesselpremium.quantaintellect.com";
18790
18867
  const sendToRendererViews = (channel, ...args) => {
18791
18868
  chromeView.webContents.send(channel, ...args);
18792
18869
  sidebarView.webContents.send(channel, ...args);
18793
18870
  devtoolsPanelView.webContents.send(channel, ...args);
18794
18871
  };
18872
+ const watchPremiumCheckoutTab = (tabId) => {
18873
+ const tab = tabManager.getTab(tabId);
18874
+ const wc = tab?.view.webContents;
18875
+ if (!wc) return;
18876
+ let completed = false;
18877
+ const cleanup = () => {
18878
+ wc.removeListener("did-navigate", onNavigate);
18879
+ wc.removeListener("did-navigate-in-page", onNavigateInPage);
18880
+ wc.removeListener("destroyed", cleanup);
18881
+ };
18882
+ const handleUrl = async (rawUrl) => {
18883
+ if (completed) return;
18884
+ let parsed;
18885
+ try {
18886
+ parsed = new URL(rawUrl);
18887
+ } catch {
18888
+ return;
18889
+ }
18890
+ if (parsed.origin !== premiumApiOrigin) return;
18891
+ if (parsed.pathname === "/canceled") {
18892
+ completed = true;
18893
+ trackPremiumFunnel("checkout_canceled");
18894
+ cleanup();
18895
+ return;
18896
+ }
18897
+ if (parsed.pathname !== "/success") return;
18898
+ completed = true;
18899
+ trackPremiumFunnel("checkout_success_seen");
18900
+ const sessionId = parsed.searchParams.get("session_id")?.trim();
18901
+ if (!sessionId) {
18902
+ trackPremiumFunnel("auto_activation_failed", {
18903
+ reason: "missing_session_id"
18904
+ });
18905
+ cleanup();
18906
+ return;
18907
+ }
18908
+ trackPremiumFunnel("auto_activation_attempted");
18909
+ const state2 = await verifySubscription(sessionId);
18910
+ if (isPremiumActiveState(state2)) {
18911
+ sendToRendererViews(Channels.PREMIUM_UPDATE, state2);
18912
+ trackPremiumFunnel("auto_activation_succeeded", {
18913
+ status: state2.status
18914
+ });
18915
+ } else {
18916
+ trackPremiumFunnel("auto_activation_failed", {
18917
+ status: state2.status
18918
+ });
18919
+ }
18920
+ cleanup();
18921
+ };
18922
+ const onNavigate = (_event, url) => {
18923
+ void handleUrl(url);
18924
+ };
18925
+ const onNavigateInPage = (_event, url, isMainFrame) => {
18926
+ if (!isMainFrame) return;
18927
+ void handleUrl(url);
18928
+ };
18929
+ wc.on("did-navigate", onNavigate);
18930
+ wc.on("did-navigate-in-page", onNavigateInPage);
18931
+ wc.on("destroyed", cleanup);
18932
+ const currentUrl = wc.getURL();
18933
+ if (currentUrl) {
18934
+ void handleUrl(currentUrl);
18935
+ }
18936
+ };
18795
18937
  const getActiveHighlightCountSafe = async () => {
18796
18938
  const tab = tabManager.getActiveTab();
18797
18939
  if (!tab) return 0;
@@ -19211,7 +19353,8 @@ function registerIpcHandlers(windowState, runtime2) {
19211
19353
  trackPremiumFunnel("checkout_clicked");
19212
19354
  const result = await getCheckoutUrl(email);
19213
19355
  if (result.ok && result.url) {
19214
- tabManager.createTab(result.url);
19356
+ const tabId = tabManager.createTab(result.url);
19357
+ watchPremiumCheckoutTab(tabId);
19215
19358
  }
19216
19359
  return result;
19217
19360
  });
@@ -19221,6 +19364,12 @@ function registerIpcHandlers(windowState, runtime2) {
19221
19364
  sendToRendererViews(Channels.PREMIUM_UPDATE, state2);
19222
19365
  return state2;
19223
19366
  });
19367
+ electron.ipcMain.handle(Channels.PREMIUM_TRACK_CONTEXT, (_, step) => {
19368
+ assertString(step, "step");
19369
+ if (step === "chat_banner_viewed" || step === "chat_banner_clicked" || step === "settings_banner_viewed" || step === "settings_banner_clicked" || step === "welcome_banner_clicked" || step === "premium_gate_seen" || step === "premium_gate_clicked" || step === "iteration_limit_seen" || step === "iteration_limit_clicked") {
19370
+ trackPremiumFunnel(step);
19371
+ }
19372
+ });
19224
19373
  electron.ipcMain.handle(Channels.PREMIUM_PORTAL, async () => {
19225
19374
  trackPremiumFunnel("portal_opened");
19226
19375
  const result = await getPortalUrl();