local-operator-ui 0.39.5 → 0.39.6

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.
Files changed (91) hide show
  1. package/out/main/index.js +499 -70
  2. package/out/renderer/assets/{_basePickBy-BgM1I5lG.js → _basePickBy-CEM-62na.js} +1 -1
  3. package/out/renderer/assets/{_baseUniq-Bmkgy85v.js → _baseUniq-DKUG2lEn.js} +1 -1
  4. package/out/renderer/assets/{addressOverlayList-8wdZRD_t.css → addressOverlayList-B7X6o95l.css} +1 -1
  5. package/out/renderer/assets/{addressOverlayList-BEh9WU4R.js → addressOverlayList-SGt8bawf.js} +1 -1
  6. package/out/renderer/assets/{agent-details-page-Du26ZU6E.js → agent-details-page-uwmizvcA.js} +1 -1
  7. package/out/renderer/assets/{agent-hub-page-BwVMuSzt.js → agent-hub-page-DY0hrFjh.js} +1 -1
  8. package/out/renderer/assets/{agents-page-BhSbjEpr.js → agents-page-B82GhyEm.js} +3 -3
  9. package/out/renderer/assets/{arc-3zNC_x2n.js → arc-CwS59wEx.js} +1 -1
  10. package/out/renderer/assets/{architectureDiagram-IEHRJDOE-CtDg0QNg.js → architectureDiagram-IEHRJDOE-CrSOPHPj.js} +1 -1
  11. package/out/renderer/assets/{blockDiagram-JOT3LUYC-4XryKcIu.js → blockDiagram-JOT3LUYC-DOKW2aS1.js} +1 -1
  12. package/out/renderer/assets/{book-open-lnC7oth0.js → book-open-BrVlmR50.js} +1 -1
  13. package/out/renderer/assets/browser-page-kxT2NYqz.js +1 -0
  14. package/out/renderer/assets/{browser-webauthn-prompt-BTC3LWcr.js → browser-webauthn-prompt-D4Pmblc_.js} +1 -1
  15. package/out/renderer/assets/{building-2-CRI7K1ut.js → building-2-BbJxBV3t.js} +1 -1
  16. package/out/renderer/assets/{c4Diagram-VJAJSXHY-n2cPdK4v.js → c4Diagram-VJAJSXHY-BNZOSwVL.js} +1 -1
  17. package/out/renderer/assets/channel-D2-Cirxc.js +1 -0
  18. package/out/renderer/assets/{chunk-4BMEZGHF-P7BOtABr.js → chunk-4BMEZGHF-DatYJ8Pc.js} +1 -1
  19. package/out/renderer/assets/{chunk-A2AXSNBT-BmO2P02x.js → chunk-A2AXSNBT-kofNI-nh.js} +1 -1
  20. package/out/renderer/assets/{chunk-AEK57VVT-KMJMGzZF.js → chunk-AEK57VVT-RG-vyDkt.js} +1 -1
  21. package/out/renderer/assets/{chunk-D6G4REZN-WA3nwEd_.js → chunk-D6G4REZN-DbgxdXuD.js} +1 -1
  22. package/out/renderer/assets/{chunk-RZ5BOZE2-C4md2pdG.js → chunk-RZ5BOZE2-Pwbky5G7.js} +1 -1
  23. package/out/renderer/assets/{chunk-XZIHB7SX-MPSf1VFR.js → chunk-XZIHB7SX-nMQwH5Ev.js} +1 -1
  24. package/out/renderer/assets/classDiagram-GIVACNV2-D1u4IPED.js +1 -0
  25. package/out/renderer/assets/classDiagram-v2-COTLJTTW-D1u4IPED.js +1 -0
  26. package/out/renderer/assets/clone-D45gbF22.js +1 -0
  27. package/out/renderer/assets/{console-mirror-CnVv9rOt.js → console-mirror-B7HDmLVb.js} +1 -1
  28. package/out/renderer/assets/{consoleCapture-B_hi3E9g.js → consoleCapture-wuvuMPlf.js} +1 -1
  29. package/out/renderer/assets/{conversation-input-sync-CQ0nQbSV.js → conversation-input-sync-DeQTtOSG.js} +4 -4
  30. package/out/renderer/assets/{dagre-OKDRZEBW-QrYk8i27.js → dagre-OKDRZEBW-BXF3VqDs.js} +1 -1
  31. package/out/renderer/assets/{diagram-SSKATNLV-CpIwEDtE.js → diagram-SSKATNLV-C6ZzdCUp.js} +1 -1
  32. package/out/renderer/assets/{diagram-VNBRO52H-DtHOhSDJ.js → diagram-VNBRO52H-ND-gVRs3.js} +1 -1
  33. package/out/renderer/assets/{erDiagram-Q7BY3M3F-AEs8Bb_A.js → erDiagram-Q7BY3M3F-DJ8vCpMT.js} +1 -1
  34. package/out/renderer/assets/{error-boundary-CU2PiR3H.js → error-boundary-D81PAlVn.js} +1 -1
  35. package/out/renderer/assets/{flowDiagram-4HSFHLVR-CliaNR7R.js → flowDiagram-4HSFHLVR-C0lG2NYg.js} +1 -1
  36. package/out/renderer/assets/{ganttDiagram-APWFNJXF-Br5lLrlI.js → ganttDiagram-APWFNJXF-BBxt5Pgj.js} +1 -1
  37. package/out/renderer/assets/{gitGraphDiagram-7IBYFJ6S-D68CT6c8.js → gitGraphDiagram-7IBYFJ6S-B5eei6E_.js} +1 -1
  38. package/out/renderer/assets/{graph-LIDYSJHC.js → graph-lWFNtwh7.js} +1 -1
  39. package/out/renderer/assets/{hash-5VU7fofJ.js → hash-3k6_lTgk.js} +1 -1
  40. package/out/renderer/assets/{index-BoQsbSXg.js → index-BtI7uak5.js} +197 -192
  41. package/out/renderer/assets/index-DsY6xpO9.js +57 -0
  42. package/out/renderer/assets/{index-Bpi83aqM.js → index-FqHXqlQT.js} +1 -1
  43. package/out/renderer/assets/{index-BpJ3H71K.js → index-tyh1i-0R.js} +1 -1
  44. package/out/renderer/assets/{infoDiagram-PH2N3AL5-U0UUgi63.js → infoDiagram-PH2N3AL5-DfdIGj2q.js} +1 -1
  45. package/out/renderer/assets/{installer-9uv2KfFf.js → installer-OLhNHLbA.js} +1 -1
  46. package/out/renderer/assets/{journeyDiagram-U35MCT3I-FFIRpntM.js → journeyDiagram-U35MCT3I-DY36aDPm.js} +1 -1
  47. package/out/renderer/assets/{kanban-definition-NDS4AKOZ-BRpcp-A3.js → kanban-definition-NDS4AKOZ-DkmkP4pt.js} +1 -1
  48. package/out/renderer/assets/{layout-MxBLCasM.js → layout-Wh_eVbud.js} +1 -1
  49. package/out/renderer/assets/{legacy-agents-page-D-vnYlfr.js → legacy-agents-page-m5-4VKbu.js} +1 -1
  50. package/out/renderer/assets/{library-page-D5TOCNDL.js → library-page-vUP7gWsI.js} +3 -3
  51. package/out/renderer/assets/{mermaid.core-D0JYobPd.js → mermaid.core-CIUeSke9.js} +5 -5
  52. package/out/renderer/assets/{mesh-page-MMyOu2-i.js → mesh-page-CoUCZ19i.js} +1 -1
  53. package/out/renderer/assets/{mindmap-definition-ALO5MXBD-BSmr1_Tl.js → mindmap-definition-ALO5MXBD-E7Cl2drf.js} +1 -1
  54. package/out/renderer/assets/{mini-DX97EGZ9.js → mini-D6HdkQvd.js} +1 -1
  55. package/out/renderer/assets/{notebook-pen-CaY2CqYY.js → notebook-pen-CiUgTpp-.js} +1 -1
  56. package/out/renderer/assets/{org-access-D-BFcZvI.js → org-access-DMUk8SEr.js} +1 -1
  57. package/out/renderer/assets/{org-surface-gate-BmRiAyd4.js → org-surface-gate-DdKUA8S8.js} +1 -1
  58. package/out/renderer/assets/{page-header-B078STNU.js → page-header-DyRHEB-L.js} +1 -1
  59. package/out/renderer/assets/{pieDiagram-IB7DONF6-DkC-Pw7E.js → pieDiagram-IB7DONF6-C3KFzuOU.js} +1 -1
  60. package/out/renderer/assets/{projects-page-2kYMpXGt.js → projects-page-BdU99VZf.js} +1 -1
  61. package/out/renderer/assets/{publication-validation-Cp6mINOP.js → publication-validation-Cv6lnH83.js} +1 -1
  62. package/out/renderer/assets/{quadrantDiagram-7GDLP6J5-IVRMgBez.js → quadrantDiagram-7GDLP6J5-DommBk0z.js} +1 -1
  63. package/out/renderer/assets/{radar-MK3ICKWK-sedwCyEl.js → radar-MK3ICKWK-D5VUcmjY.js} +1 -1
  64. package/out/renderer/assets/{radient-auth-buttons-vFQgdlYP.js → radient-auth-buttons-BXc5xVU7.js} +1 -1
  65. package/out/renderer/assets/{requirementDiagram-KVF5MWMF-DwdfgrvA.js → requirementDiagram-KVF5MWMF-RSR1-rSs.js} +1 -1
  66. package/out/renderer/assets/{sankeyDiagram-QLVOVGJD-BPvKdY7g.js → sankeyDiagram-QLVOVGJD-Caojpkpm.js} +1 -1
  67. package/out/renderer/assets/{schedules-page-BWxSAtp5.js → schedules-page-BWM0NUo9.js} +1 -1
  68. package/out/renderer/assets/{sequenceDiagram-X6HHIX6F-swhS4JaV.js → sequenceDiagram-X6HHIX6F-CrZCUpMQ.js} +1 -1
  69. package/out/renderer/assets/{settings-page-CNeq8zEo.js → settings-page-sXBnyGof.js} +1 -1
  70. package/out/renderer/assets/{smartart-h3hobM9P.js → smartart-BJStpUh7.js} +1 -1
  71. package/out/renderer/assets/{stateDiagram-DGXRK772-DQjtzeCn.js → stateDiagram-DGXRK772-PFp2Dzsd.js} +1 -1
  72. package/out/renderer/assets/stateDiagram-v2-YXO3MK2T-DhzpDrem.js +1 -0
  73. package/out/renderer/assets/{team-bridge-page-DwXTOl4x.js → team-bridge-page-pZkYpCnA.js} +1 -1
  74. package/out/renderer/assets/{timeline-definition-BDJGKUSR-BE4DUnJN.js → timeline-definition-BDJGKUSR-BI2T4N_q.js} +1 -1
  75. package/out/renderer/assets/{ui-preferences-store-DUB1goHr.js → ui-preferences-store-BZs48Tq1.js} +1 -1
  76. package/out/renderer/assets/{use-download-agent-mutation-C_zKpXBu.js → use-download-agent-mutation-B3ghS441.js} +1 -1
  77. package/out/renderer/assets/{use-session-snapshot-B6UGWZI5.js → use-session-snapshot-BbulmIXL.js} +1 -1
  78. package/out/renderer/assets/{xychartDiagram-VJFVF3MP-D6nHKfw6.js → xychartDiagram-VJFVF3MP-CuNt7ik-.js} +1 -1
  79. package/out/renderer/browser-address-overlay-list.html +2 -2
  80. package/out/renderer/console-capture.html +4 -4
  81. package/out/renderer/index.html +6 -6
  82. package/out/renderer/installer.html +3 -3
  83. package/out/renderer/mini.html +6 -6
  84. package/package.json +2 -2
  85. package/out/renderer/assets/browser-page-CsoEGi9k.js +0 -1
  86. package/out/renderer/assets/channel-MJ9Q5Gdp.js +0 -1
  87. package/out/renderer/assets/classDiagram-GIVACNV2-PYFoG-nl.js +0 -1
  88. package/out/renderer/assets/classDiagram-v2-COTLJTTW-PYFoG-nl.js +0 -1
  89. package/out/renderer/assets/clone-BWjAp2XI.js +0 -1
  90. package/out/renderer/assets/index-B_mT8ft1.js +0 -57
  91. package/out/renderer/assets/stateDiagram-v2-YXO3MK2T-BoHuPFVZ.js +0 -1
package/out/main/index.js CHANGED
@@ -28848,7 +28848,6 @@ const ADDRESS_LIST_THEME_FALLBACK = "#1b1f24";
28848
28848
  const DIP_INT32_MAX$1 = 2 ** 31 - 1;
28849
28849
  const NOTICE_KINDS = [
28850
28850
  "error",
28851
- "hint",
28852
28851
  "empty",
28853
28852
  "no_match"
28854
28853
  ];
@@ -35358,11 +35357,15 @@ const enUiBrowser = {
35358
35357
  "ui.browser.browser_tab_strip.unmute_tab": "Unmute tab",
35359
35358
  "ui.browser.browser_tab_strip.watch": 'Watch "{title}"',
35360
35359
  "ui.browser.browser_url_bar.address": "Address",
35361
- "ui.browser.browser_url_bar.address_required": "Enter a web address or choose a suggestion.",
35360
+ "ui.browser.browser_url_bar.address_search_row": 'Search DuckDuckGo for "{query}"',
35361
+ "ui.browser.browser_url_bar.address_suggestion_open_tab": "Already open — {title}",
35362
+ "ui.browser.browser_url_bar.address_suggestion_open_tab_untitled": "Already open",
35362
35363
  "ui.browser.browser_url_bar.address_suggestions_available": "{count, plural, one {{count, number, ::group-off} suggestion available} other {{count, number, ::group-off} suggestions available}}",
35363
- "ui.browser.browser_url_bar.address_suggestions_empty": "No links from these tabs yet.",
35364
- "ui.browser.browser_url_bar.address_suggestions_label": "From this browser session",
35365
- "ui.browser.browser_url_bar.address_suggestions_no_match": "No matching links from this browser session.",
35364
+ "ui.browser.browser_url_bar.address_suggestions_blocked": "Only web addresses can open here.",
35365
+ "ui.browser.browser_url_bar.address_suggestions_empty": "No browsing history yet.",
35366
+ "ui.browser.browser_url_bar.address_suggestions_label": "From your history",
35367
+ "ui.browser.browser_url_bar.address_suggestions_label_mixed": "Suggestions",
35368
+ "ui.browser.browser_url_bar.address_suggestions_no_match": "No matching pages in your history.",
35366
35369
  "ui.browser.browser_url_bar.address_suggestions_unavailable": "Address suggestions are unavailable.",
35367
35370
  "ui.browser.browser_url_bar.approvals_waiting": "Approvals, {count, plural, other {{count, number, ::group-off} waiting}}",
35368
35371
  "ui.browser.browser_url_bar.back": "Back",
@@ -39088,11 +39091,15 @@ const esUiBrowser = {
39088
39091
  "ui.browser.browser_url_bar.stop_loading": "Detener carga",
39089
39092
  "ui.browser.browser_url_bar.reload": "Recargar",
39090
39093
  "ui.browser.browser_url_bar.address": "Dirección",
39091
- "ui.browser.browser_url_bar.address_required": "Escribe una dirección web o elige una sugerencia.",
39094
+ "ui.browser.browser_url_bar.address_search_row": "Buscar «{query}» en DuckDuckGo",
39095
+ "ui.browser.browser_url_bar.address_suggestion_open_tab": "Ya abierto — {title}",
39096
+ "ui.browser.browser_url_bar.address_suggestion_open_tab_untitled": "Ya abierto",
39092
39097
  "ui.browser.browser_url_bar.address_suggestions_available": "{count, plural, one {{count, number, ::group-off} sugerencia disponible} other {{count, number, ::group-off} sugerencias disponibles}}",
39093
- "ui.browser.browser_url_bar.address_suggestions_empty": "Aún no hay enlaces de estas pestañas.",
39094
- "ui.browser.browser_url_bar.address_suggestions_label": "De esta sesión del navegador",
39095
- "ui.browser.browser_url_bar.address_suggestions_no_match": "No hay enlaces que coincidan en esta sesión del navegador.",
39098
+ "ui.browser.browser_url_bar.address_suggestions_blocked": "Aquí solo se pueden abrir direcciones web.",
39099
+ "ui.browser.browser_url_bar.address_suggestions_empty": "Aún no hay historial de navegación.",
39100
+ "ui.browser.browser_url_bar.address_suggestions_label": "De tu historial",
39101
+ "ui.browser.browser_url_bar.address_suggestions_label_mixed": "Sugerencias",
39102
+ "ui.browser.browser_url_bar.address_suggestions_no_match": "No hay páginas coincidentes en tu historial.",
39096
39103
  "ui.browser.browser_url_bar.address_suggestions_unavailable": "Las sugerencias de direcciones no están disponibles.",
39097
39104
  "ui.browser.browser_url_bar.approvals_waiting": "Aprobaciones, {count, plural, other {{count, number, ::group-off} en espera}}",
39098
39105
  "ui.browser.browser_url_bar.home_destination": "Inicio — ir a la página inicial (en blanco)",
@@ -42665,11 +42672,15 @@ const frUiBrowser = {
42665
42672
  "ui.browser.browser_url_bar.stop_loading": "Arrêter le chargement",
42666
42673
  "ui.browser.browser_url_bar.reload": "Recharger",
42667
42674
  "ui.browser.browser_url_bar.address": "Adresse",
42668
- "ui.browser.browser_url_bar.address_required": "Saisissez une adresse web ou choisissez une suggestion.",
42675
+ "ui.browser.browser_url_bar.address_search_row": "Rechercher « {query} » sur DuckDuckGo",
42676
+ "ui.browser.browser_url_bar.address_suggestion_open_tab": "Déjà ouvert — {title}",
42677
+ "ui.browser.browser_url_bar.address_suggestion_open_tab_untitled": "Déjà ouvert",
42669
42678
  "ui.browser.browser_url_bar.address_suggestions_available": "{count, plural, one {{count, number, ::group-off} suggestion disponible} many {{count, number, ::group-off} de suggestions disponibles} other {{count, number, ::group-off} suggestions disponibles}}",
42670
- "ui.browser.browser_url_bar.address_suggestions_empty": "Aucun lien de ces onglets pour l’instant.",
42671
- "ui.browser.browser_url_bar.address_suggestions_label": "De cette session de navigation",
42672
- "ui.browser.browser_url_bar.address_suggestions_no_match": "Aucun lien correspondant dans cette session de navigation.",
42679
+ "ui.browser.browser_url_bar.address_suggestions_blocked": "Seules les adresses web peuvent s’ouvrir ici.",
42680
+ "ui.browser.browser_url_bar.address_suggestions_empty": "Pas encore d'historique de navigation.",
42681
+ "ui.browser.browser_url_bar.address_suggestions_label": "De votre historique",
42682
+ "ui.browser.browser_url_bar.address_suggestions_label_mixed": "Suggestions",
42683
+ "ui.browser.browser_url_bar.address_suggestions_no_match": "Aucune page correspondante dans votre historique.",
42673
42684
  "ui.browser.browser_url_bar.address_suggestions_unavailable": "Les suggestions d’adresses ne sont pas disponibles.",
42674
42685
  "ui.browser.browser_url_bar.approvals_waiting": "Approbations, {count, plural, one {{count, number, ::group-off} en attente} many {{count, number, ::group-off} en attente} other {{count, number, ::group-off} en attente}}",
42675
42686
  "ui.browser.browser_url_bar.home_destination": "Accueil — aller à la page de départ (vide)",
@@ -46241,11 +46252,15 @@ const hiUiBrowser = {
46241
46252
  "ui.browser.browser_tab_strip.unmute_tab": "टैब की आवाज़ चालू करें",
46242
46253
  "ui.browser.browser_tab_strip.watch": '"{title}" देखें',
46243
46254
  "ui.browser.browser_url_bar.address": "पता",
46244
- "ui.browser.browser_url_bar.address_required": "वेब पता दर्ज करें या कोई सुझाव चुनें।",
46255
+ "ui.browser.browser_url_bar.address_search_row": 'DuckDuckGo पर "{query}" खोजें',
46256
+ "ui.browser.browser_url_bar.address_suggestion_open_tab": "पहले से खुला — {title}",
46257
+ "ui.browser.browser_url_bar.address_suggestion_open_tab_untitled": "पहले से खुला",
46245
46258
  "ui.browser.browser_url_bar.address_suggestions_available": "{count, plural, one {{count, number, ::group-off} सुझाव उपलब्ध है} other {{count, number, ::group-off} सुझाव उपलब्ध हैं}}",
46246
- "ui.browser.browser_url_bar.address_suggestions_empty": "इन टैब से अभी कोई लिंक नहीं है।",
46247
- "ui.browser.browser_url_bar.address_suggestions_label": "इस ब्राउज़र सत्र से",
46248
- "ui.browser.browser_url_bar.address_suggestions_no_match": "इस ब्राउज़र सत्र में कोई मेल खाता लिंक नहीं है।",
46259
+ "ui.browser.browser_url_bar.address_suggestions_blocked": "यहाँ केवल वेब पते खुल सकते हैं।",
46260
+ "ui.browser.browser_url_bar.address_suggestions_empty": "अभी तक कोई ब्राउज़िंग इतिहास नहीं।",
46261
+ "ui.browser.browser_url_bar.address_suggestions_label": "आपके इतिहास से",
46262
+ "ui.browser.browser_url_bar.address_suggestions_label_mixed": "सुझाव",
46263
+ "ui.browser.browser_url_bar.address_suggestions_no_match": "आपके इतिहास में कोई मेल खाता पृष्ठ नहीं।",
46249
46264
  "ui.browser.browser_url_bar.address_suggestions_unavailable": "पते के सुझाव उपलब्ध नहीं हैं।",
46250
46265
  "ui.browser.browser_url_bar.approvals_waiting": "स्वीकृतियाँ, {count, plural, other {{count, number, ::group-off} इंतज़ार में}}",
46251
46266
  "ui.browser.browser_url_bar.back": "पीछे",
@@ -49595,11 +49610,15 @@ const ruUiBrowser = {
49595
49610
  "ui.browser.browser_tab_strip.unmute_tab": "Включить звук вкладки",
49596
49611
  "ui.browser.browser_tab_strip.watch": "Смотреть «{title}»",
49597
49612
  "ui.browser.browser_url_bar.address": "Адрес",
49598
- "ui.browser.browser_url_bar.address_required": "Введите веб-адрес или выберите подсказку.",
49613
+ "ui.browser.browser_url_bar.address_search_row": "Искать «{query}» в DuckDuckGo",
49614
+ "ui.browser.browser_url_bar.address_suggestion_open_tab": "Уже открыто — {title}",
49615
+ "ui.browser.browser_url_bar.address_suggestion_open_tab_untitled": "Уже открыто",
49599
49616
  "ui.browser.browser_url_bar.address_suggestions_available": "{count, plural, one {{count, number, ::group-off} подсказка доступна} few {{count, number, ::group-off} подсказки доступны} many {{count, number, ::group-off} подсказок доступно} other {{count, number, ::group-off} подсказки доступны}}",
49600
- "ui.browser.browser_url_bar.address_suggestions_empty": "В этих вкладках пока нет ссылок.",
49601
- "ui.browser.browser_url_bar.address_suggestions_label": "Из этой сессии браузера",
49602
- "ui.browser.browser_url_bar.address_suggestions_no_match": "В этой сессии браузера нет подходящих ссылок.",
49617
+ "ui.browser.browser_url_bar.address_suggestions_blocked": "Здесь можно открывать только веб-адреса.",
49618
+ "ui.browser.browser_url_bar.address_suggestions_empty": "Истории просмотров пока нет.",
49619
+ "ui.browser.browser_url_bar.address_suggestions_label": "Из вашей истории",
49620
+ "ui.browser.browser_url_bar.address_suggestions_label_mixed": "Подсказки",
49621
+ "ui.browser.browser_url_bar.address_suggestions_no_match": "В вашей истории нет подходящих страниц.",
49603
49622
  "ui.browser.browser_url_bar.address_suggestions_unavailable": "Подсказки адресов недоступны.",
49604
49623
  "ui.browser.browser_url_bar.approvals_waiting": "Одобрения, {count, plural, one {ожидает {count, number, ::group-off}} few {ожидают {count, number, ::group-off}} many {ожидают {count, number, ::group-off}} other {ожидают {count, number, ::group-off}}}",
49605
49624
  "ui.browser.browser_url_bar.back": "Назад",
@@ -53055,11 +53074,15 @@ const urUiBrowser = {
53055
53074
  "ui.browser.browser_tab_strip.unmute_tab": "ٹیب کی آواز بحال کریں",
53056
53075
  "ui.browser.browser_tab_strip.watch": "“{title}” پر نظر رکھیں",
53057
53076
  "ui.browser.browser_url_bar.address": "پتہ",
53058
- "ui.browser.browser_url_bar.address_required": "ویب پتہ درج کریں یا کوئی تجویز منتخب کریں۔",
53077
+ "ui.browser.browser_url_bar.address_search_row": 'DuckDuckGo پر "{query}" تلاش کریں',
53078
+ "ui.browser.browser_url_bar.address_suggestion_open_tab": "پہلے سے کھلا — {title}",
53079
+ "ui.browser.browser_url_bar.address_suggestion_open_tab_untitled": "پہلے سے کھلا",
53059
53080
  "ui.browser.browser_url_bar.address_suggestions_available": "{count, plural, one {{count, number, ::group-off} تجویز دستیاب ہے} other {{count, number, ::group-off} تجاویز دستیاب ہیں}}",
53060
- "ui.browser.browser_url_bar.address_suggestions_empty": "ان ٹیب سے ابھی کوئی لنک نہیں ہے۔",
53061
- "ui.browser.browser_url_bar.address_suggestions_label": "اس براؤزر سیشن سے",
53062
- "ui.browser.browser_url_bar.address_suggestions_no_match": "اس براؤزر سیشن میں کوئی مماثل لنک نہیں ہے۔",
53081
+ "ui.browser.browser_url_bar.address_suggestions_blocked": "یہاں صرف ویب پتے کھل سکتے ہیں۔",
53082
+ "ui.browser.browser_url_bar.address_suggestions_empty": "ابھی تک کوئی براؤزنگ سرگزشت نہیں۔",
53083
+ "ui.browser.browser_url_bar.address_suggestions_label": "آپ کی سرگزشت سے",
53084
+ "ui.browser.browser_url_bar.address_suggestions_label_mixed": "تجاویز",
53085
+ "ui.browser.browser_url_bar.address_suggestions_no_match": "آپ کی سرگزشت میں کوئی مماثل صفحہ نہیں۔",
53063
53086
  "ui.browser.browser_url_bar.address_suggestions_unavailable": "پتے کی تجاویز دستیاب نہیں ہیں۔",
53064
53087
  "ui.browser.browser_url_bar.approvals_waiting": "منظوریاں، {count, plural, other {{count, number, ::group-off} منتظر}}",
53065
53088
  "ui.browser.browser_url_bar.back": "پیچھے",
@@ -56429,11 +56452,15 @@ const viUiBrowser = {
56429
56452
  "ui.browser.browser_tab_strip.unmute_tab": "Bật tiếng tab",
56430
56453
  "ui.browser.browser_tab_strip.watch": 'Theo dõi "{title}"',
56431
56454
  "ui.browser.browser_url_bar.address": "Địa chỉ",
56432
- "ui.browser.browser_url_bar.address_required": "Nhập địa chỉ web hoặc chọn một gợi ý.",
56455
+ "ui.browser.browser_url_bar.address_search_row": 'Tìm "{query}" trên DuckDuckGo',
56456
+ "ui.browser.browser_url_bar.address_suggestion_open_tab": "Đã mở — {title}",
56457
+ "ui.browser.browser_url_bar.address_suggestion_open_tab_untitled": "Đã mở",
56433
56458
  "ui.browser.browser_url_bar.address_suggestions_available": "{count, plural, other {{count, number, ::group-off} gợi ý có sẵn}}",
56434
- "ui.browser.browser_url_bar.address_suggestions_empty": "Chưa có liên kết nào từ các tab này.",
56435
- "ui.browser.browser_url_bar.address_suggestions_label": "Từ phiên trình duyệt này",
56436
- "ui.browser.browser_url_bar.address_suggestions_no_match": "Không có liên kết phù hợp từ phiên trình duyệt này.",
56459
+ "ui.browser.browser_url_bar.address_suggestions_blocked": "Chỉ có thể mở địa chỉ web ở đây.",
56460
+ "ui.browser.browser_url_bar.address_suggestions_empty": "Chưa có lịch sử duyệt web.",
56461
+ "ui.browser.browser_url_bar.address_suggestions_label": "Từ lịch sử của bạn",
56462
+ "ui.browser.browser_url_bar.address_suggestions_label_mixed": "Gợi ý",
56463
+ "ui.browser.browser_url_bar.address_suggestions_no_match": "Không có trang nào phù hợp trong lịch sử của bạn.",
56437
56464
  "ui.browser.browser_url_bar.address_suggestions_unavailable": "Gợi ý địa chỉ không khả dụng.",
56438
56465
  "ui.browser.browser_url_bar.approvals_waiting": "Phê duyệt, {count, plural, other {{count, number, ::group-off} đang chờ}}",
56439
56466
  "ui.browser.browser_url_bar.back": "Quay lại",
@@ -59698,11 +59725,15 @@ const zhCNUiBrowser = {
59698
59725
  "ui.browser.browser_tab_strip.unmute_tab": "取消标签页静音",
59699
59726
  "ui.browser.browser_tab_strip.watch": "查看“{title}”",
59700
59727
  "ui.browser.browser_url_bar.address": "地址",
59701
- "ui.browser.browser_url_bar.address_required": "请输入地址或选择一条建议。",
59728
+ "ui.browser.browser_url_bar.address_search_row": "在 DuckDuckGo 中搜索“{query}”",
59729
+ "ui.browser.browser_url_bar.address_suggestion_open_tab": "已打开 — {title}",
59730
+ "ui.browser.browser_url_bar.address_suggestion_open_tab_untitled": "已打开",
59702
59731
  "ui.browser.browser_url_bar.address_suggestions_available": "{count, plural, other {{count, number, ::group-off}条建议可用}}",
59703
- "ui.browser.browser_url_bar.address_suggestions_empty": "这些标签页中还没有链接。",
59704
- "ui.browser.browser_url_bar.address_suggestions_label": "来自此浏览器会话",
59705
- "ui.browser.browser_url_bar.address_suggestions_no_match": "此浏览器会话中没有匹配的链接。",
59732
+ "ui.browser.browser_url_bar.address_suggestions_blocked": "此处只能打开网页地址。",
59733
+ "ui.browser.browser_url_bar.address_suggestions_empty": "还没有浏览历史记录。",
59734
+ "ui.browser.browser_url_bar.address_suggestions_label": "来自你的历史记录",
59735
+ "ui.browser.browser_url_bar.address_suggestions_label_mixed": "建议",
59736
+ "ui.browser.browser_url_bar.address_suggestions_no_match": "你的历史记录中没有匹配的页面。",
59706
59737
  "ui.browser.browser_url_bar.address_suggestions_unavailable": "地址建议不可用。",
59707
59738
  "ui.browser.browser_url_bar.approvals_waiting": "审批,{count, plural, other {{count, number, ::group-off}项待处理}}",
59708
59739
  "ui.browser.browser_url_bar.back": "后退",
@@ -65995,7 +66026,8 @@ const ADDRESS_HISTORY_MAX_ENTRIES_PER_TAB = 50;
65995
66026
  const ADDRESS_HISTORY_MAX_ENTRIES = 256;
65996
66027
  const ADDRESS_HISTORY_MAX_URL_LENGTH = 2048;
65997
66028
  const ADDRESS_HISTORY_MAX_TITLE_LENGTH = 256;
65998
- const ADDRESS_HISTORY_MAX_SESSION_ID_LENGTH = 256;
66029
+ const ADDRESS_HISTORY_MAX_QUERY_LENGTH = ADDRESS_HISTORY_MAX_URL_LENGTH;
66030
+ const ADDRESS_HISTORY_MAX_LIMIT = 20;
65999
66031
  const CONTROL_CHARS$1 = /[\p{Cc}]/u;
66000
66032
  function windowAround(entries, activeIndexRaw, max) {
66001
66033
  const activeIndex = Math.min(
@@ -66071,12 +66103,9 @@ function historyTitle(raw) {
66071
66103
  const cleaned = raw.replace(CONTROL_CHARS$1, " ").replace(/\s+/g, " ").trim();
66072
66104
  return cleaned.length > ADDRESS_HISTORY_MAX_TITLE_LENGTH ? cleaned.slice(0, ADDRESS_HISTORY_MAX_TITLE_LENGTH) : cleaned;
66073
66105
  }
66074
- function collectAddressHistory(tabs2, scope, activeTabId) {
66075
- const inScope = scope === "all" ? [...tabs2] : tabs2.filter(
66076
- (tab) => tab.sessionId !== null && tab.sessionId === scope.sessionId
66077
- );
66078
- const active = inScope.find((tab) => tab.tabId === activeTabId);
66079
- const ordered = active ? [active, ...inScope.filter((tab) => tab.tabId !== activeTabId)] : inScope;
66106
+ function collectAddressHistory(tabs2, activeTabId) {
66107
+ const active = tabs2.find((tab) => tab.tabId === activeTabId);
66108
+ const ordered = active ? [active, ...tabs2.filter((tab) => tab.tabId !== activeTabId)] : [...tabs2];
66080
66109
  const seen = /* @__PURE__ */ new Set();
66081
66110
  const entries = [];
66082
66111
  for (const tab of ordered.slice(0, ADDRESS_HISTORY_MAX_TABS)) {
@@ -66092,6 +66121,12 @@ function collectAddressHistory(tabs2, scope, activeTabId) {
66092
66121
  entries.push({
66093
66122
  url,
66094
66123
  title: historyTitle(entry.title),
66124
+ // A stack has no visit count and no visit timestamp. Zero is the
66125
+ // honest absence; the renderer treats a tab row's order as stack
66126
+ // distance, never as frequency.
66127
+ visitCount: 0,
66128
+ lastVisitedAt: 0,
66129
+ source: "tab",
66095
66130
  sourceTabId: tab.tabId,
66096
66131
  sourceIndex,
66097
66132
  activeTab: tab.tabId === activeTabId,
@@ -66105,6 +66140,38 @@ function collectAddressHistory(tabs2, scope, activeTabId) {
66105
66140
  }
66106
66141
  return { activeTabId, entries };
66107
66142
  }
66143
+ function foldAscii(value) {
66144
+ return value.replace(/[A-Z]/g, (letter) => letter.toLowerCase());
66145
+ }
66146
+ function mergeAddressHistory(tabEntries, historyEntries, query, limit) {
66147
+ const cap = Math.max(0, Math.floor(limit));
66148
+ if (cap === 0) return [];
66149
+ const seen = /* @__PURE__ */ new Set();
66150
+ const merged = [];
66151
+ for (const entry of historyEntries) {
66152
+ if (merged.length >= cap) break;
66153
+ const url = canonicalHistoryUrl(entry.url);
66154
+ if (!url || seen.has(url)) continue;
66155
+ seen.add(url);
66156
+ merged.push({
66157
+ url,
66158
+ title: historyTitle(entry.title),
66159
+ visitCount: entry.visitCount,
66160
+ lastVisitedAt: entry.lastVisitedAt,
66161
+ source: "history"
66162
+ });
66163
+ }
66164
+ const needle = foldAscii(query.trim());
66165
+ for (const entry of tabEntries) {
66166
+ if (merged.length >= cap) break;
66167
+ if (seen.has(entry.url)) continue;
66168
+ if (needle.length > 0 && !foldAscii(entry.url).includes(needle) && !foldAscii(entry.title).includes(needle))
66169
+ continue;
66170
+ seen.add(entry.url);
66171
+ merged.push(entry);
66172
+ }
66173
+ return merged;
66174
+ }
66108
66175
  class ChromeTabOrder {
66109
66176
  ids = [];
66110
66177
  customized = false;
@@ -66134,6 +66201,305 @@ class ChromeTabOrder {
66134
66201
  return true;
66135
66202
  }
66136
66203
  }
66204
+ const HISTORY_STORE_VERSION = 1;
66205
+ const HISTORY_STORE_MAX_ENTRIES = 5e3;
66206
+ const HISTORY_STORE_MAX_BYTES = 2 * 1024 * 1024;
66207
+ const HISTORY_STORE_WRITE_DEBOUNCE_MS = 500;
66208
+ const HISTORY_STORE_MAX_CANDIDATES = 200;
66209
+ const PREFIX_WIDTH = 3;
66210
+ const RECENCY_HALF_LIFE_DAYS = 7;
66211
+ const DAY_MS = 24 * 60 * 60 * 1e3;
66212
+ const SCHEME_PREFIX = /^([a-z][a-z0-9+.-]*):\/\//i;
66213
+ const PATH_OR_QUERY = /[/?#]/;
66214
+ function schemeLess(value) {
66215
+ const match = SCHEME_PREFIX.exec(value);
66216
+ return match ? value.slice(match[0].length) : value;
66217
+ }
66218
+ function stripWww(value) {
66219
+ return value.startsWith("www.") && value.length > "www.".length ? value.slice("www.".length) : value;
66220
+ }
66221
+ function matchKey(value) {
66222
+ return stripWww(schemeLess(value.trim()).toLowerCase());
66223
+ }
66224
+ function literalKey(value) {
66225
+ return schemeLess(value.trim()).toLowerCase();
66226
+ }
66227
+ function indexKeys(url) {
66228
+ const keys = /* @__PURE__ */ new Set([literalKey(url), matchKey(url)]);
66229
+ return [...keys].filter((key) => key.length > 0);
66230
+ }
66231
+ function queryNeedles(raw) {
66232
+ const literal = literalKey(raw);
66233
+ const keys = /* @__PURE__ */ new Set([literal, stripWww(literal)]);
66234
+ return [...keys].filter((key) => key.length > 0);
66235
+ }
66236
+ function matchesNeedle(value, needle) {
66237
+ if (!value.startsWith(needle)) return false;
66238
+ const hostOnly = !PATH_OR_QUERY.test(needle);
66239
+ if (!hostOnly) return true;
66240
+ if (!needle.includes(".") || needle.endsWith(".")) return true;
66241
+ const next = value.charAt(needle.length);
66242
+ return next === "" || next === "/" || next === "?" || next === "#" || next === ":";
66243
+ }
66244
+ function prefixKey(matchKeyValue) {
66245
+ return matchKeyValue.slice(0, PREFIX_WIDTH);
66246
+ }
66247
+ function historyScore(entry, now) {
66248
+ const ageDays = Math.max(0, now - entry.lastVisitedAt) / DAY_MS;
66249
+ return Math.log2(1 + entry.visitCount) + 0.5 ** (ageDays / RECENCY_HALF_LIFE_DAYS);
66250
+ }
66251
+ function compareEntries(now) {
66252
+ return (a, b) => {
66253
+ const scoreDiff = historyScore(b, now) - historyScore(a, now);
66254
+ if (scoreDiff !== 0) return scoreDiff;
66255
+ if (a.lastVisitedAt !== b.lastVisitedAt)
66256
+ return b.lastVisitedAt - a.lastVisitedAt;
66257
+ return a.url < b.url ? -1 : a.url > b.url ? 1 : 0;
66258
+ };
66259
+ }
66260
+ function storageUrl(raw) {
66261
+ const canonical = canonicalHistoryUrl(raw);
66262
+ if (!canonical) return null;
66263
+ const hash = canonical.indexOf("#");
66264
+ return hash < 0 ? canonical : canonical.slice(0, hash);
66265
+ }
66266
+ function isEntry(value) {
66267
+ if (typeof value !== "object" || value === null) return false;
66268
+ const record = value;
66269
+ return typeof record.url === "string" && typeof record.title === "string" && typeof record.host === "string" && Number.isSafeInteger(record.visitCount) && record.visitCount > 0 && typeof record.lastVisitedAt === "number" && Number.isFinite(record.lastVisitedAt);
66270
+ }
66271
+ function createBrowserHistoryStore(filePath, options = {}) {
66272
+ const now = options.now ?? Date.now;
66273
+ const byUrl = /* @__PURE__ */ new Map();
66274
+ const prefix = /* @__PURE__ */ new Map();
66275
+ let writeTimer = null;
66276
+ let approxBytes = 0;
66277
+ function estimate(entry) {
66278
+ return entry.url.length + entry.title.length + entry.host.length + 192;
66279
+ }
66280
+ function indexAdd(entry) {
66281
+ approxBytes += estimate(entry);
66282
+ for (const key of indexKeys(entry.url)) {
66283
+ const bucketKey = prefixKey(key);
66284
+ let bucket = prefix.get(bucketKey);
66285
+ if (!bucket) {
66286
+ bucket = /* @__PURE__ */ new Set();
66287
+ prefix.set(bucketKey, bucket);
66288
+ }
66289
+ bucket.add(entry.url);
66290
+ }
66291
+ }
66292
+ function indexRemove(entry) {
66293
+ approxBytes -= estimate(entry);
66294
+ for (const key of indexKeys(entry.url)) {
66295
+ const bucketKey = prefixKey(key);
66296
+ const bucket = prefix.get(bucketKey);
66297
+ bucket?.delete(entry.url);
66298
+ if (bucket?.size === 0) prefix.delete(bucketKey);
66299
+ }
66300
+ }
66301
+ function setTitle(entry, next) {
66302
+ const before = estimate(entry);
66303
+ entry.title = next;
66304
+ approxBytes += estimate(entry) - before;
66305
+ }
66306
+ function enforceBounds(at) {
66307
+ let changed = false;
66308
+ if (byUrl.size <= HISTORY_STORE_MAX_ENTRIES && approxBytes <= HISTORY_STORE_MAX_BYTES)
66309
+ return false;
66310
+ if (byUrl.size > HISTORY_STORE_MAX_ENTRIES) {
66311
+ const overflow = byUrl.size - HISTORY_STORE_MAX_ENTRIES;
66312
+ const victims = [...byUrl.values()].sort(compareEntries(at)).reverse().slice(0, overflow);
66313
+ for (const victim of victims) {
66314
+ byUrl.delete(victim.url);
66315
+ indexRemove(victim);
66316
+ changed = true;
66317
+ }
66318
+ }
66319
+ let guard = 0;
66320
+ while (guard < 200 && byUrl.size > 0) {
66321
+ guard += 1;
66322
+ const bytes = Buffer.byteLength(
66323
+ JSON.stringify(document(), null, 2),
66324
+ "utf8"
66325
+ );
66326
+ if (bytes <= HISTORY_STORE_MAX_BYTES) {
66327
+ approxBytes = bytes;
66328
+ break;
66329
+ }
66330
+ const batch = Math.max(1, Math.ceil(byUrl.size / 100));
66331
+ const victims = [...byUrl.values()].sort(compareEntries(at)).reverse().slice(0, batch);
66332
+ for (const victim of victims) {
66333
+ byUrl.delete(victim.url);
66334
+ indexRemove(victim);
66335
+ changed = true;
66336
+ }
66337
+ }
66338
+ return changed;
66339
+ }
66340
+ function document() {
66341
+ return {
66342
+ version: HISTORY_STORE_VERSION,
66343
+ entries: [...byUrl.values()]
66344
+ };
66345
+ }
66346
+ function writeNow() {
66347
+ if (writeTimer !== null) {
66348
+ clearTimeout(writeTimer);
66349
+ writeTimer = null;
66350
+ }
66351
+ writeJsonAtomic(filePath, document());
66352
+ }
66353
+ function scheduleWrite2() {
66354
+ if (writeTimer !== null) return;
66355
+ writeTimer = setTimeout(() => {
66356
+ writeTimer = null;
66357
+ writeJsonAtomic(filePath, document());
66358
+ }, HISTORY_STORE_WRITE_DEBOUNCE_MS);
66359
+ writeTimer.unref?.();
66360
+ }
66361
+ const loaded = readJson(filePath);
66362
+ if (loaded && loaded.version === HISTORY_STORE_VERSION && Array.isArray(loaded.entries)) {
66363
+ for (const raw of loaded.entries) {
66364
+ if (!isEntry(raw)) continue;
66365
+ const url = storageUrl(raw.url);
66366
+ if (!url) continue;
66367
+ const host = new URL(url).host;
66368
+ const existing = byUrl.get(url);
66369
+ if (existing) {
66370
+ existing.visitCount = Math.max(existing.visitCount, raw.visitCount);
66371
+ existing.lastVisitedAt = Math.max(
66372
+ existing.lastVisitedAt,
66373
+ raw.lastVisitedAt
66374
+ );
66375
+ if (existing.title.length === 0) {
66376
+ const title = historyTitle(raw.title);
66377
+ if (title.length > 0) setTitle(existing, title);
66378
+ }
66379
+ continue;
66380
+ }
66381
+ const entry = {
66382
+ url,
66383
+ title: historyTitle(raw.title),
66384
+ host,
66385
+ visitCount: raw.visitCount,
66386
+ lastVisitedAt: raw.lastVisitedAt
66387
+ };
66388
+ byUrl.set(url, entry);
66389
+ indexAdd(entry);
66390
+ }
66391
+ if (enforceBounds(now())) {
66392
+ writeNow();
66393
+ }
66394
+ }
66395
+ return {
66396
+ record(rawUrl, rawTitle, at = now()) {
66397
+ const url = storageUrl(rawUrl);
66398
+ if (!url) return;
66399
+ const title = historyTitle(rawTitle);
66400
+ const existing = byUrl.get(url);
66401
+ if (existing) {
66402
+ existing.visitCount += 1;
66403
+ existing.lastVisitedAt = at;
66404
+ if (title.length > 0 && title !== existing.title)
66405
+ setTitle(existing, title);
66406
+ } else {
66407
+ const entry = {
66408
+ url,
66409
+ title,
66410
+ host: new URL(url).host,
66411
+ visitCount: 1,
66412
+ lastVisitedAt: at
66413
+ };
66414
+ byUrl.set(url, entry);
66415
+ indexAdd(entry);
66416
+ }
66417
+ enforceBounds(at);
66418
+ scheduleWrite2();
66419
+ },
66420
+ updateTitle(rawUrl, rawTitle) {
66421
+ const url = storageUrl(rawUrl);
66422
+ if (!url) return;
66423
+ const entry = byUrl.get(url);
66424
+ if (!entry) return;
66425
+ const title = historyTitle(rawTitle);
66426
+ if (title.length === 0 || title === entry.title) return;
66427
+ setTitle(entry, title);
66428
+ enforceBounds(now());
66429
+ scheduleWrite2();
66430
+ },
66431
+ suggest(rawQuery, limit) {
66432
+ const wanted = Math.max(0, Math.floor(limit));
66433
+ if (wanted === 0 || byUrl.size === 0) return [];
66434
+ const at = now();
66435
+ if (rawQuery.length === 0) {
66436
+ return [...byUrl.values()].sort(compareEntries(at)).slice(0, wanted);
66437
+ }
66438
+ const needles = queryNeedles(rawQuery);
66439
+ if (needles.length === 0) return [];
66440
+ const bucketSet = /* @__PURE__ */ new Set();
66441
+ for (const needle of needles) {
66442
+ if (needle.length >= PREFIX_WIDTH) {
66443
+ const bucket = prefix.get(prefixKey(needle));
66444
+ if (bucket) bucketSet.add(bucket);
66445
+ } else {
66446
+ for (const [key, bucket] of prefix) {
66447
+ if (key.startsWith(needle)) bucketSet.add(bucket);
66448
+ }
66449
+ }
66450
+ }
66451
+ const buckets = [...bucketSet];
66452
+ if (buckets.length === 0) return [];
66453
+ const candidates = [];
66454
+ const seen = /* @__PURE__ */ new Set();
66455
+ for (const bucket of buckets) {
66456
+ for (const url of bucket) {
66457
+ if (candidates.length >= HISTORY_STORE_MAX_CANDIDATES) break;
66458
+ if (seen.has(url)) continue;
66459
+ const keys = indexKeys(url);
66460
+ const hit = needles.some(
66461
+ (needle) => keys.some((key) => matchesNeedle(key, needle))
66462
+ );
66463
+ if (!hit) continue;
66464
+ const entry = byUrl.get(url);
66465
+ if (!entry) continue;
66466
+ seen.add(url);
66467
+ candidates.push(entry);
66468
+ }
66469
+ if (candidates.length >= HISTORY_STORE_MAX_CANDIDATES) break;
66470
+ }
66471
+ candidates.sort(compareEntries(at));
66472
+ return candidates.slice(0, wanted);
66473
+ },
66474
+ size() {
66475
+ return byUrl.size;
66476
+ },
66477
+ clear() {
66478
+ byUrl.clear();
66479
+ prefix.clear();
66480
+ writeNow();
66481
+ },
66482
+ clearOrigin(rawOrigin) {
66483
+ let parsed;
66484
+ try {
66485
+ parsed = new URL(rawOrigin);
66486
+ } catch {
66487
+ return;
66488
+ }
66489
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return;
66490
+ const origin = parsed.origin;
66491
+ for (const [url, entry] of [...byUrl.entries()]) {
66492
+ if (new URL(url).origin !== origin) continue;
66493
+ byUrl.delete(url);
66494
+ indexRemove(entry);
66495
+ }
66496
+ writeNow();
66497
+ },
66498
+ flush() {
66499
+ if (writeTimer !== null) writeNow();
66500
+ }
66501
+ };
66502
+ }
66137
66503
  const PAGE_ZOOM_STEPS = [
66138
66504
  0.25,
66139
66505
  0.33,
@@ -66512,6 +66878,9 @@ class BrowserHost {
66512
66878
  * projection as the tabs, so the renderer has one source for "child or
66513
66879
  * fallback" and never guesses from a failed IPC call. */
66514
66880
  addressOverlayMode;
66881
+ /** One instance per host, constructed once in the constructor. `null` when
66882
+ * no path was supplied (see `BrowserHostOptions.historyFilePath`). */
66883
+ historyStore;
66515
66884
  /**
66516
66885
  * The last main-frame load failure per tab, cleared by the next load.
66517
66886
  *
@@ -66538,6 +66907,7 @@ class BrowserHost {
66538
66907
  this.facts = options.facts;
66539
66908
  this.forgetSiteData = options.forgetSiteData;
66540
66909
  this.addressOverlayMode = options.addressOverlayMode ?? (() => ({ mode: "suspend", reason: "unavailable" }));
66910
+ this.historyStore = options.historyFilePath ? createBrowserHistoryStore(options.historyFilePath) : null;
66541
66911
  }
66542
66912
  /** Answer one wire request. The only place a method name becomes an action. */
66543
66913
  async dispatch(method, params, requestId2) {
@@ -67405,8 +67775,13 @@ class BrowserHost {
67405
67775
  * no longer matches, which covers the race between this check and the reply
67406
67776
  * landing.
67407
67777
  *
67408
- * Collection is bounded and derived (`address-history.ts`); this method adds
67409
- * only the authority the collector must not pretend to own.
67778
+ * RANKING MOVED HERE with the persistent store: the renderer used to rank a
67779
+ * snapshot of every stack, which cannot scale to a 5000-entry history either
67780
+ * in memory or across IPC. Main now asks the store for its top matches, puts
67781
+ * them ahead of the live-tab rows (`mergeAddressHistory`), and bounds the
67782
+ * answer by `request.limit`. The renderer still derives display text, the
67783
+ * target URL and the inline suffix, because those depend on exactly what the
67784
+ * user typed.
67410
67785
  */
67411
67786
  addressHistory(request) {
67412
67787
  const activeTabId = this.registry.activeTab?.tabId ?? null;
@@ -67416,20 +67791,59 @@ class BrowserHost {
67416
67791
  "the active tab changed before suggestions were read"
67417
67792
  );
67418
67793
  }
67794
+ const live = collectAddressHistory(
67795
+ this.registry.list().map((record) => ({
67796
+ tabId: record.tabId,
67797
+ sessionId: record.sessionId,
67798
+ webContents: record.view.webContents,
67799
+ restoreRow: record.restoreRow ?? null
67800
+ })),
67801
+ activeTabId
67802
+ );
67803
+ const historyMatches = this.historyStore?.suggest(request.query, request.limit) ?? [];
67419
67804
  return {
67420
67805
  requestId: request.requestId,
67421
- ...collectAddressHistory(
67422
- this.registry.list().map((record) => ({
67423
- tabId: record.tabId,
67424
- sessionId: record.sessionId,
67425
- webContents: record.view.webContents,
67426
- restoreRow: record.restoreRow ?? null
67427
- })),
67428
- request.scope,
67429
- activeTabId
67806
+ activeTabId: live.activeTabId,
67807
+ entries: mergeAddressHistory(
67808
+ live.entries,
67809
+ historyMatches,
67810
+ request.query,
67811
+ request.limit
67430
67812
  )
67431
67813
  };
67432
67814
  }
67815
+ /**
67816
+ * Record one committed top-level navigation.
67817
+ *
67818
+ * Called from the per-view wiring in `index.ts`, which is the only place that
67819
+ * sees the event for every tab. A non-HTTP(S) URL is dropped by the store, so
67820
+ * `about:blank`, `chrome://` and a refused scheme never enter the document.
67821
+ * The title is filled in by `recordHistoryTitle` when Chromium announces it;
67822
+ * recording the visit first is deliberate, because the commit is the fact and
67823
+ * the title is a later, optional update.
67824
+ */
67825
+ recordHistoryVisit(url) {
67826
+ this.historyStore?.record(url, "");
67827
+ }
67828
+ /** Update the stored title for a URL that is already in the history. Never
67829
+ * increments a visit: `page-title-updated` fires for a page that has already
67830
+ * been counted, sometimes several times. */
67831
+ recordHistoryTitle(url, title) {
67832
+ this.historyStore?.updateTitle(url, title);
67833
+ }
67834
+ /** Write any debounced history change now (quit, and the host's own stop). */
67835
+ flushHistory() {
67836
+ this.historyStore?.flush();
67837
+ }
67838
+ /** "Clear everything" also forgets the suggestion history (`profile.ts` is
67839
+ * the path that calls this, so cookies/cache alone cannot reach it). */
67840
+ clearHistory() {
67841
+ this.historyStore?.clear();
67842
+ }
67843
+ /** "Forget this site" drops that origin's rows; other origins stay. */
67844
+ clearOriginHistory(origin) {
67845
+ this.historyStore?.clearOrigin(origin);
67846
+ }
67433
67847
  /**
67434
67848
  * A URL the USER typed goes through here, and it is deliberately different from
67435
67849
  * an agent navigation in one way and identical in another (design 6.1):
@@ -68889,21 +69303,17 @@ function addressHistoryRequestOrThrow(value) {
68889
69303
  const request = value;
68890
69304
  const requestId2 = numberOrThrow(request.requestId, "requestId");
68891
69305
  const expectedTabId = tabIdOrThrow(request.expectedTabId, "expectedTabId");
68892
- let scope;
68893
- if (request.scope === "all") {
68894
- scope = "all";
68895
- } else if (request.scope && typeof request.scope === "object" && typeof request.scope.sessionId === "string") {
68896
- const sessionId2 = request.scope.sessionId.trim();
68897
- if (!sessionId2 || sessionId2.length > ADDRESS_HISTORY_MAX_SESSION_ID_LENGTH || CONTROL_CHARS.test(sessionId2)) {
68898
- throw new Error(
68899
- "The address history scope needs a valid conversation id."
68900
- );
68901
- }
68902
- scope = { sessionId: sessionId2 };
68903
- } else {
68904
- throw new Error("The address history scope is invalid.");
69306
+ if (typeof request.query !== "string") {
69307
+ throw new Error("The address history query must be a string.");
69308
+ }
69309
+ const query = request.query;
69310
+ if (query.length > ADDRESS_HISTORY_MAX_QUERY_LENGTH || CONTROL_CHARS.test(query)) {
69311
+ throw new Error("The address history query is invalid.");
69312
+ }
69313
+ if (typeof request.limit !== "number" || !Number.isSafeInteger(request.limit) || request.limit < 1 || request.limit > ADDRESS_HISTORY_MAX_LIMIT) {
69314
+ throw new Error("The address history limit is invalid.");
68905
69315
  }
68906
- return { requestId: requestId2, expectedTabId, scope };
69316
+ return { requestId: requestId2, expectedTabId, query, limit: request.limit };
68907
69317
  }
68908
69318
  function closeTabsIntentOrThrow(value) {
68909
69319
  if (!value || typeof value !== "object") {
@@ -69422,7 +69832,7 @@ function installBrowserSessionHandlers(browserSession, hooks = {}) {
69422
69832
  browserSession.removeListener("will-download", onDownload);
69423
69833
  };
69424
69834
  }
69425
- async function clearBrowsingData(browserSession, what) {
69835
+ async function clearBrowsingData(browserSession, what, history) {
69426
69836
  browserSession.flushStorageData();
69427
69837
  if (what === "cache") {
69428
69838
  await browserSession.clearCache();
@@ -69444,8 +69854,9 @@ async function clearBrowsingData(browserSession, what) {
69444
69854
  }
69445
69855
  await browserSession.clearData();
69446
69856
  await browserSession.clearCache();
69857
+ history?.clear();
69447
69858
  }
69448
- async function clearOriginData(browserSession, origin) {
69859
+ async function clearOriginData(browserSession, origin, history) {
69449
69860
  browserSession.flushStorageData();
69450
69861
  await browserSession.clearData({
69451
69862
  origins: [origin],
@@ -69461,6 +69872,7 @@ async function clearOriginData(browserSession, origin) {
69461
69872
  "cache"
69462
69873
  ]
69463
69874
  });
69875
+ history?.clearOrigin(origin);
69464
69876
  }
69465
69877
  function flushBrowserStorage(browserSession) {
69466
69878
  try {
@@ -70747,6 +71159,9 @@ function refusesNavigation(rawUrl) {
70747
71159
  }
70748
71160
  }
70749
71161
  let activeHost = null;
71162
+ electron.app.on("before-quit", () => {
71163
+ activeHost?.host.flushHistory();
71164
+ });
70750
71165
  function routeBrowserZoomInput(event, input) {
70751
71166
  const candidate = browserChordIntent(
70752
71167
  { ...input, isAutoRepeat: false, isComposing: false },
@@ -71094,7 +71509,10 @@ async function initializeBrowserHost(options, bindings) {
71094
71509
  notifyChrome();
71095
71510
  });
71096
71511
  contents.on("did-stop-loading", notifyChrome);
71097
- contents.on("page-title-updated", notifyChrome);
71512
+ contents.on("page-title-updated", (_event, title) => {
71513
+ host.recordHistoryTitle(contents.getURL(), title);
71514
+ notifyChrome();
71515
+ });
71098
71516
  contents.on("render-process-gone", () => {
71099
71517
  addressOverlay?.onPageGone(tabId);
71100
71518
  });
@@ -71122,12 +71540,14 @@ async function initializeBrowserHost(options, bindings) {
71122
71540
  stopLogCapture(contents.id);
71123
71541
  startLogCapture(contents.id);
71124
71542
  log2(`[browser] tab ${tabId} navigated to ${url}`);
71543
+ host.recordHistoryVisit(url);
71125
71544
  notifyChanged();
71126
71545
  });
71127
71546
  contents.on("did-navigate-in-page", (_event, url, isMainFrame) => {
71128
71547
  if (!isMainFrame) return;
71129
71548
  registry.bumpEpoch(tabId, false);
71130
71549
  log2(`[browser] tab ${tabId} navigated in page to ${url}`);
71550
+ host.recordHistoryVisit(url);
71131
71551
  notifyChanged();
71132
71552
  });
71133
71553
  contents.on("destroyed", () => {
@@ -71266,6 +71686,9 @@ async function initializeBrowserHost(options, bindings) {
71266
71686
  rollback.add(() => webauthn.dispose());
71267
71687
  const detachWebauthn = attachWebauthnChooser(browserSession, webauthn, log2);
71268
71688
  rollback.add(detachWebauthn);
71689
+ const historyClearer = {
71690
+ current: null
71691
+ };
71269
71692
  const cookieJar = createHiddenCookieJarTarget(
71270
71693
  new electron.WebContentsView({
71271
71694
  webPreferences: { ...HIDDEN_COOKIE_JAR_WEB_PREFERENCES }
@@ -71277,7 +71700,7 @@ async function initializeBrowserHost(options, bindings) {
71277
71700
  cipher: browserProfileCipher(),
71278
71701
  ...sessionCookiePaths(options.userDataDir),
71279
71702
  flushStore: () => browserSession.cookies.flushStore(),
71280
- clearSessionData: (what) => clearBrowsingData(browserSession, what),
71703
+ clearSessionData: (what) => clearBrowsingData(browserSession, what, historyClearer.current),
71281
71704
  log: log2
71282
71705
  });
71283
71706
  let restoreReport = null;
@@ -71434,12 +71857,17 @@ async function initializeBrowserHost(options, bindings) {
71434
71857
  log: log2,
71435
71858
  onChanged: notifyChanged,
71436
71859
  facts: () => facts,
71437
- forgetSiteData: (origin) => clearOriginData(browserSession, origin),
71860
+ forgetSiteData: (origin) => clearOriginData(browserSession, origin, historyClearer.current),
71861
+ historyFilePath: path$1.join(options.userDataDir, "browser-history.json"),
71438
71862
  addressOverlayMode: () => addressOverlay ? addressOverlay.mode() : {
71439
71863
  mode: "suspend",
71440
71864
  reason: options.addressOverlay?.product === true ? "unavailable" : "platform"
71441
71865
  }
71442
71866
  });
71867
+ historyClearer.current = {
71868
+ clear: () => host.clearHistory(),
71869
+ clearOrigin: (origin) => host.clearOriginHistory(origin)
71870
+ };
71443
71871
  const ownsChrome = () => browserChromeOwnsChord({
71444
71872
  logicalFocus: host.chordFocus,
71445
71873
  chromeVisible: registry.chromeVisible,
@@ -71687,6 +72115,7 @@ async function initializeBrowserHost(options, bindings) {
71687
72115
  ...addressOverlay ? { addressOverlay: probeAddressOverlay } : {},
71688
72116
  stop: async () => {
71689
72117
  detachChords();
72118
+ host.flushHistory();
71690
72119
  const atStop = captureTabs(
71691
72120
  registry.list(),
71692
72121
  registry.activeTab?.tabId ?? null,