@quanta-intellect/vessel-browser 0.1.90 → 0.1.92
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
|
@@ -117,15 +117,15 @@ function readStoredProviderSecret() {
|
|
|
117
117
|
return null;
|
|
118
118
|
}
|
|
119
119
|
function writeStoredProviderSecret(secret) {
|
|
120
|
-
const
|
|
121
|
-
fs.mkdirSync(path.dirname(
|
|
120
|
+
const filePath2 = getChatProviderSecretPath();
|
|
121
|
+
fs.mkdirSync(path.dirname(filePath2), { recursive: true });
|
|
122
122
|
const payload = JSON.stringify(secret);
|
|
123
123
|
if (canUseSafeStorage$1()) {
|
|
124
124
|
const encrypted = electron.safeStorage.encryptString(payload);
|
|
125
|
-
fs.writeFileSync(
|
|
125
|
+
fs.writeFileSync(filePath2, encrypted, { mode: 384 });
|
|
126
126
|
return;
|
|
127
127
|
}
|
|
128
|
-
fs.writeFileSync(
|
|
128
|
+
fs.writeFileSync(filePath2, payload, { mode: 384 });
|
|
129
129
|
}
|
|
130
130
|
function clearStoredProviderSecret() {
|
|
131
131
|
try {
|
|
@@ -149,15 +149,15 @@ function readStoredCodexTokens() {
|
|
|
149
149
|
return null;
|
|
150
150
|
}
|
|
151
151
|
function writeStoredCodexTokens(tokens) {
|
|
152
|
-
const
|
|
153
|
-
fs.mkdirSync(path.dirname(
|
|
152
|
+
const filePath2 = getCodexTokensPath();
|
|
153
|
+
fs.mkdirSync(path.dirname(filePath2), { recursive: true });
|
|
154
154
|
const payload = JSON.stringify(tokens);
|
|
155
155
|
if (canUseSafeStorage$1()) {
|
|
156
156
|
const encrypted = electron.safeStorage.encryptString(payload);
|
|
157
|
-
fs.writeFileSync(
|
|
157
|
+
fs.writeFileSync(filePath2, encrypted, { mode: 384 });
|
|
158
158
|
return;
|
|
159
159
|
}
|
|
160
|
-
fs.writeFileSync(
|
|
160
|
+
fs.writeFileSync(filePath2, payload, { mode: 384 });
|
|
161
161
|
}
|
|
162
162
|
function clearStoredCodexTokens() {
|
|
163
163
|
try {
|
|
@@ -282,11 +282,11 @@ function saveSettings() {
|
|
|
282
282
|
}
|
|
283
283
|
}, SAVE_DEBOUNCE_MS$6);
|
|
284
284
|
}
|
|
285
|
-
function setSetting(
|
|
285
|
+
function setSetting(key2, value) {
|
|
286
286
|
loadSettings();
|
|
287
|
-
if (
|
|
287
|
+
if (key2 === "mcpPort") {
|
|
288
288
|
settings.mcpPort = sanitizePort(value);
|
|
289
|
-
} else if (
|
|
289
|
+
} else if (key2 === "chatProvider") {
|
|
290
290
|
const nextProvider = value;
|
|
291
291
|
if (!nextProvider) {
|
|
292
292
|
clearStoredProviderSecret();
|
|
@@ -314,7 +314,7 @@ function setSetting(key, value) {
|
|
|
314
314
|
};
|
|
315
315
|
}
|
|
316
316
|
} else {
|
|
317
|
-
settings[
|
|
317
|
+
settings[key2] = value;
|
|
318
318
|
}
|
|
319
319
|
saveSettings();
|
|
320
320
|
return { ...settings };
|
|
@@ -490,27 +490,27 @@ class Tab {
|
|
|
490
490
|
this.view.webContents.on("before-input-event", (event, input) => {
|
|
491
491
|
if (!input.control && !input.meta) return;
|
|
492
492
|
if (input.type !== "keyDown") return;
|
|
493
|
-
const
|
|
493
|
+
const key2 = input.key.toLowerCase();
|
|
494
494
|
const wc = this.view.webContents;
|
|
495
|
-
if (
|
|
495
|
+
if (key2 === "+" || key2 === "=") {
|
|
496
496
|
this.zoomIn();
|
|
497
497
|
event.preventDefault();
|
|
498
498
|
return;
|
|
499
499
|
}
|
|
500
|
-
if (
|
|
500
|
+
if (key2 === "-") {
|
|
501
501
|
this.zoomOut();
|
|
502
502
|
event.preventDefault();
|
|
503
503
|
return;
|
|
504
504
|
}
|
|
505
|
-
if (
|
|
505
|
+
if (key2 === "0") {
|
|
506
506
|
this.zoomReset();
|
|
507
507
|
event.preventDefault();
|
|
508
508
|
return;
|
|
509
509
|
}
|
|
510
|
-
if (
|
|
511
|
-
else if (
|
|
512
|
-
else if (
|
|
513
|
-
else if (
|
|
510
|
+
if (key2 === "c") wc.copy();
|
|
511
|
+
else if (key2 === "v") wc.paste();
|
|
512
|
+
else if (key2 === "x") wc.cut();
|
|
513
|
+
else if (key2 === "a") wc.selectAll();
|
|
514
514
|
});
|
|
515
515
|
this.setupListeners();
|
|
516
516
|
if (url) {
|
|
@@ -784,8 +784,8 @@ class Tab {
|
|
|
784
784
|
}
|
|
785
785
|
if (postBody) {
|
|
786
786
|
const params = new URLSearchParams();
|
|
787
|
-
for (const [
|
|
788
|
-
params.set(
|
|
787
|
+
for (const [key2, value] of Object.entries(postBody)) {
|
|
788
|
+
params.set(key2, value);
|
|
789
789
|
}
|
|
790
790
|
return this.guardedLoadURL(url, {
|
|
791
791
|
method: "POST",
|
|
@@ -1059,22 +1059,22 @@ function encodeStoredData(payload, secure) {
|
|
|
1059
1059
|
return payload;
|
|
1060
1060
|
}
|
|
1061
1061
|
function loadJsonFile({
|
|
1062
|
-
filePath,
|
|
1062
|
+
filePath: filePath2,
|
|
1063
1063
|
fallback,
|
|
1064
|
-
parse,
|
|
1064
|
+
parse: parse2,
|
|
1065
1065
|
secure = false
|
|
1066
1066
|
}) {
|
|
1067
1067
|
try {
|
|
1068
|
-
const raw = fs.readFileSync(
|
|
1068
|
+
const raw = fs.readFileSync(filePath2);
|
|
1069
1069
|
const decoded = decodeStoredData(raw, secure);
|
|
1070
|
-
return
|
|
1070
|
+
return parse2(JSON.parse(decoded));
|
|
1071
1071
|
} catch {
|
|
1072
1072
|
return fallback;
|
|
1073
1073
|
}
|
|
1074
1074
|
}
|
|
1075
1075
|
function createDebouncedJsonPersistence({
|
|
1076
1076
|
debounceMs,
|
|
1077
|
-
filePath,
|
|
1077
|
+
filePath: filePath2,
|
|
1078
1078
|
getValue,
|
|
1079
1079
|
logLabel,
|
|
1080
1080
|
resetOnSchedule = false,
|
|
@@ -1097,9 +1097,9 @@ function createDebouncedJsonPersistence({
|
|
|
1097
1097
|
2
|
|
1098
1098
|
);
|
|
1099
1099
|
const data = encodeStoredData(payload, secure);
|
|
1100
|
-
await fs.promises.mkdir(path.dirname(
|
|
1100
|
+
await fs.promises.mkdir(path.dirname(filePath2), { recursive: true }).then(
|
|
1101
1101
|
() => fs.promises.writeFile(
|
|
1102
|
-
|
|
1102
|
+
filePath2,
|
|
1103
1103
|
data,
|
|
1104
1104
|
typeof data === "string" ? { encoding: "utf-8", mode: 384 } : { mode: 384 }
|
|
1105
1105
|
)
|
|
@@ -1125,7 +1125,7 @@ function createDebouncedJsonPersistence({
|
|
|
1125
1125
|
flush: flush2
|
|
1126
1126
|
};
|
|
1127
1127
|
}
|
|
1128
|
-
let state$
|
|
1128
|
+
let state$5 = null;
|
|
1129
1129
|
const listeners$2 = /* @__PURE__ */ new Set();
|
|
1130
1130
|
const SAVE_DEBOUNCE_MS$5 = 250;
|
|
1131
1131
|
function getHighlightsPath() {
|
|
@@ -1135,19 +1135,19 @@ function createPersistence$1() {
|
|
|
1135
1135
|
return createDebouncedJsonPersistence({
|
|
1136
1136
|
debounceMs: SAVE_DEBOUNCE_MS$5,
|
|
1137
1137
|
filePath: getHighlightsPath(),
|
|
1138
|
-
getValue: () => state$
|
|
1138
|
+
getValue: () => state$5,
|
|
1139
1139
|
logLabel: "highlights",
|
|
1140
1140
|
resetOnSchedule: true
|
|
1141
1141
|
});
|
|
1142
1142
|
}
|
|
1143
|
-
let persistence$
|
|
1143
|
+
let persistence$7 = null;
|
|
1144
1144
|
function getPersistence$1() {
|
|
1145
|
-
persistence$
|
|
1146
|
-
return persistence$
|
|
1145
|
+
persistence$7 ??= createPersistence$1();
|
|
1146
|
+
return persistence$7;
|
|
1147
1147
|
}
|
|
1148
1148
|
function load$4() {
|
|
1149
|
-
if (state$
|
|
1150
|
-
state$
|
|
1149
|
+
if (state$5) return state$5;
|
|
1150
|
+
state$5 = loadJsonFile({
|
|
1151
1151
|
filePath: getHighlightsPath(),
|
|
1152
1152
|
fallback: { highlights: [] },
|
|
1153
1153
|
parse: (raw) => {
|
|
@@ -1157,14 +1157,14 @@ function load$4() {
|
|
|
1157
1157
|
};
|
|
1158
1158
|
}
|
|
1159
1159
|
});
|
|
1160
|
-
return state$
|
|
1160
|
+
return state$5;
|
|
1161
1161
|
}
|
|
1162
|
-
function save$
|
|
1162
|
+
function save$3() {
|
|
1163
1163
|
getPersistence$1().schedule();
|
|
1164
1164
|
}
|
|
1165
|
-
function emit$
|
|
1166
|
-
if (!state$
|
|
1167
|
-
const snapshot = { highlights: [...state$
|
|
1165
|
+
function emit$4() {
|
|
1166
|
+
if (!state$5) return;
|
|
1167
|
+
const snapshot = { highlights: [...state$5.highlights] };
|
|
1168
1168
|
for (const listener of listeners$2) {
|
|
1169
1169
|
listener(snapshot);
|
|
1170
1170
|
}
|
|
@@ -1180,12 +1180,12 @@ function normalizeUrl$1(rawUrl) {
|
|
|
1180
1180
|
}
|
|
1181
1181
|
function getState$2() {
|
|
1182
1182
|
load$4();
|
|
1183
|
-
return { highlights: [...state$
|
|
1183
|
+
return { highlights: [...state$5.highlights] };
|
|
1184
1184
|
}
|
|
1185
1185
|
function getHighlightsForUrl(url) {
|
|
1186
1186
|
load$4();
|
|
1187
1187
|
const normalized = normalizeUrl$1(url);
|
|
1188
|
-
return state$
|
|
1188
|
+
return state$5.highlights.filter((h) => h.url === normalized);
|
|
1189
1189
|
}
|
|
1190
1190
|
function addHighlight(url, selector, text, label, color, source) {
|
|
1191
1191
|
load$4();
|
|
@@ -1199,45 +1199,45 @@ function addHighlight(url, selector, text, label, color, source) {
|
|
|
1199
1199
|
source: source || void 0,
|
|
1200
1200
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1201
1201
|
};
|
|
1202
|
-
state$
|
|
1203
|
-
save$
|
|
1204
|
-
emit$
|
|
1202
|
+
state$5.highlights.push(highlight);
|
|
1203
|
+
save$3();
|
|
1204
|
+
emit$4();
|
|
1205
1205
|
return highlight;
|
|
1206
1206
|
}
|
|
1207
1207
|
function removeHighlight(id) {
|
|
1208
1208
|
load$4();
|
|
1209
|
-
const index = state$
|
|
1209
|
+
const index = state$5.highlights.findIndex((h) => h.id === id);
|
|
1210
1210
|
if (index === -1) return null;
|
|
1211
|
-
const [removed] = state$
|
|
1212
|
-
save$
|
|
1213
|
-
emit$
|
|
1211
|
+
const [removed] = state$5.highlights.splice(index, 1);
|
|
1212
|
+
save$3();
|
|
1213
|
+
emit$4();
|
|
1214
1214
|
return removed;
|
|
1215
1215
|
}
|
|
1216
1216
|
function findHighlightByText(url, text) {
|
|
1217
1217
|
load$4();
|
|
1218
1218
|
const normalized = normalizeUrl$1(url);
|
|
1219
|
-
return state$
|
|
1219
|
+
return state$5.highlights.find(
|
|
1220
1220
|
(h) => h.url === normalized && h.text && h.text === text
|
|
1221
1221
|
) ?? null;
|
|
1222
1222
|
}
|
|
1223
1223
|
function updateHighlightColor(id, color) {
|
|
1224
1224
|
load$4();
|
|
1225
|
-
const highlight = state$
|
|
1225
|
+
const highlight = state$5.highlights.find((h) => h.id === id);
|
|
1226
1226
|
if (!highlight) return null;
|
|
1227
1227
|
highlight.color = color;
|
|
1228
|
-
save$
|
|
1229
|
-
emit$
|
|
1228
|
+
save$3();
|
|
1229
|
+
emit$4();
|
|
1230
1230
|
return highlight;
|
|
1231
1231
|
}
|
|
1232
1232
|
function clearHighlightsForUrl(url) {
|
|
1233
1233
|
load$4();
|
|
1234
1234
|
const normalized = normalizeUrl$1(url);
|
|
1235
|
-
const before = state$
|
|
1236
|
-
state$
|
|
1237
|
-
const removed = before - state$
|
|
1235
|
+
const before = state$5.highlights.length;
|
|
1236
|
+
state$5.highlights = state$5.highlights.filter((h) => h.url !== normalized);
|
|
1237
|
+
const removed = before - state$5.highlights.length;
|
|
1238
1238
|
if (removed > 0) {
|
|
1239
|
-
save$
|
|
1240
|
-
emit$
|
|
1239
|
+
save$3();
|
|
1240
|
+
emit$4();
|
|
1241
1241
|
}
|
|
1242
1242
|
return removed;
|
|
1243
1243
|
}
|
|
@@ -1867,14 +1867,14 @@ function persistHighlight(url, text) {
|
|
|
1867
1867
|
}
|
|
1868
1868
|
const MAX_HISTORY_ENTRIES = 5e3;
|
|
1869
1869
|
const SAVE_DEBOUNCE_MS$4 = 250;
|
|
1870
|
-
let state$
|
|
1870
|
+
let state$4 = null;
|
|
1871
1871
|
const listeners$1 = /* @__PURE__ */ new Set();
|
|
1872
1872
|
function getHistoryPath() {
|
|
1873
1873
|
return path.join(electron.app.getPath("userData"), "vessel-history.json");
|
|
1874
1874
|
}
|
|
1875
1875
|
function load$3() {
|
|
1876
|
-
if (state$
|
|
1877
|
-
state$
|
|
1876
|
+
if (state$4) return state$4;
|
|
1877
|
+
state$4 = loadJsonFile({
|
|
1878
1878
|
filePath: getHistoryPath(),
|
|
1879
1879
|
fallback: { entries: [] },
|
|
1880
1880
|
parse: (raw) => {
|
|
@@ -1884,27 +1884,27 @@ function load$3() {
|
|
|
1884
1884
|
};
|
|
1885
1885
|
}
|
|
1886
1886
|
});
|
|
1887
|
-
return state$
|
|
1887
|
+
return state$4;
|
|
1888
1888
|
}
|
|
1889
|
-
const persistence$
|
|
1889
|
+
const persistence$6 = createDebouncedJsonPersistence({
|
|
1890
1890
|
debounceMs: SAVE_DEBOUNCE_MS$4,
|
|
1891
1891
|
filePath: getHistoryPath(),
|
|
1892
|
-
getValue: () => state$
|
|
1892
|
+
getValue: () => state$4,
|
|
1893
1893
|
logLabel: "history"
|
|
1894
1894
|
});
|
|
1895
|
-
function save$
|
|
1896
|
-
persistence$
|
|
1895
|
+
function save$2() {
|
|
1896
|
+
persistence$6.schedule();
|
|
1897
1897
|
}
|
|
1898
|
-
function emit$
|
|
1899
|
-
if (!state$
|
|
1900
|
-
const snapshot = { entries: [...state$
|
|
1898
|
+
function emit$3() {
|
|
1899
|
+
if (!state$4) return;
|
|
1900
|
+
const snapshot = { entries: [...state$4.entries] };
|
|
1901
1901
|
for (const listener of listeners$1) {
|
|
1902
1902
|
listener(snapshot);
|
|
1903
1903
|
}
|
|
1904
1904
|
}
|
|
1905
1905
|
function getState$1() {
|
|
1906
1906
|
load$3();
|
|
1907
|
-
return { entries: [...state$
|
|
1907
|
+
return { entries: [...state$4.entries] };
|
|
1908
1908
|
}
|
|
1909
1909
|
function subscribe$1(listener) {
|
|
1910
1910
|
listeners$1.add(listener);
|
|
@@ -1915,12 +1915,12 @@ function subscribe$1(listener) {
|
|
|
1915
1915
|
function addEntry$1(url, title) {
|
|
1916
1916
|
if (!url || url === "about:blank") return;
|
|
1917
1917
|
load$3();
|
|
1918
|
-
const last = state$
|
|
1918
|
+
const last = state$4.entries[0];
|
|
1919
1919
|
if (last && last.url === url) {
|
|
1920
1920
|
if (title && title !== last.title) {
|
|
1921
1921
|
last.title = title;
|
|
1922
|
-
save$
|
|
1923
|
-
emit$
|
|
1922
|
+
save$2();
|
|
1923
|
+
emit$3();
|
|
1924
1924
|
}
|
|
1925
1925
|
return;
|
|
1926
1926
|
}
|
|
@@ -1929,25 +1929,25 @@ function addEntry$1(url, title) {
|
|
|
1929
1929
|
title: title || url,
|
|
1930
1930
|
visitedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1931
1931
|
};
|
|
1932
|
-
state$
|
|
1933
|
-
if (state$
|
|
1934
|
-
state$
|
|
1932
|
+
state$4.entries.unshift(entry);
|
|
1933
|
+
if (state$4.entries.length > MAX_HISTORY_ENTRIES) {
|
|
1934
|
+
state$4.entries = state$4.entries.slice(0, MAX_HISTORY_ENTRIES);
|
|
1935
1935
|
}
|
|
1936
|
-
save$
|
|
1937
|
-
emit$
|
|
1936
|
+
save$2();
|
|
1937
|
+
emit$3();
|
|
1938
1938
|
}
|
|
1939
1939
|
function search(query, limit = 50) {
|
|
1940
1940
|
load$3();
|
|
1941
|
-
if (!query.trim()) return state$
|
|
1941
|
+
if (!query.trim()) return state$4.entries.slice(0, limit);
|
|
1942
1942
|
const normalized = query.toLowerCase();
|
|
1943
|
-
return state$
|
|
1943
|
+
return state$4.entries.filter(
|
|
1944
1944
|
(e) => e.url.toLowerCase().includes(normalized) || e.title.toLowerCase().includes(normalized)
|
|
1945
1945
|
).slice(0, limit);
|
|
1946
1946
|
}
|
|
1947
1947
|
function clearAll$1() {
|
|
1948
|
-
state$
|
|
1949
|
-
save$
|
|
1950
|
-
emit$
|
|
1948
|
+
state$4 = { entries: [] };
|
|
1949
|
+
save$2();
|
|
1950
|
+
emit$3();
|
|
1951
1951
|
}
|
|
1952
1952
|
function clearByTimeRange(timeRange) {
|
|
1953
1953
|
load$3();
|
|
@@ -1957,12 +1957,12 @@ function clearByTimeRange(timeRange) {
|
|
|
1957
1957
|
}
|
|
1958
1958
|
const now = Date.now();
|
|
1959
1959
|
const cutoff = new Date(now - timeRangeToMs(timeRange));
|
|
1960
|
-
state$
|
|
1960
|
+
state$4.entries = state$4.entries.filter((entry) => {
|
|
1961
1961
|
const visitedAt = new Date(entry.visitedAt).getTime();
|
|
1962
1962
|
return Number.isNaN(visitedAt) || visitedAt < cutoff.getTime();
|
|
1963
1963
|
});
|
|
1964
|
-
save$
|
|
1965
|
-
emit$
|
|
1964
|
+
save$2();
|
|
1965
|
+
emit$3();
|
|
1966
1966
|
}
|
|
1967
1967
|
function timeRangeToMs(range) {
|
|
1968
1968
|
switch (range) {
|
|
@@ -2016,7 +2016,7 @@ function importHistoryFromJson(content) {
|
|
|
2016
2016
|
const parsed = JSON.parse(content);
|
|
2017
2017
|
const entries = Array.isArray(parsed?.entries) ? parsed.entries : [];
|
|
2018
2018
|
load$3();
|
|
2019
|
-
const existingUrls = new Set(state$
|
|
2019
|
+
const existingUrls = new Set(state$4.entries.map((e) => e.url));
|
|
2020
2020
|
for (const entry of entries) {
|
|
2021
2021
|
if (!entry?.url || typeof entry.url !== "string") {
|
|
2022
2022
|
errors++;
|
|
@@ -2026,7 +2026,7 @@ function importHistoryFromJson(content) {
|
|
|
2026
2026
|
skipped++;
|
|
2027
2027
|
continue;
|
|
2028
2028
|
}
|
|
2029
|
-
state$
|
|
2029
|
+
state$4.entries.push({
|
|
2030
2030
|
url: entry.url,
|
|
2031
2031
|
title: typeof entry.title === "string" ? entry.title : entry.url,
|
|
2032
2032
|
visitedAt: typeof entry.visitedAt === "string" ? entry.visitedAt : (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -2034,14 +2034,14 @@ function importHistoryFromJson(content) {
|
|
|
2034
2034
|
existingUrls.add(entry.url);
|
|
2035
2035
|
imported++;
|
|
2036
2036
|
}
|
|
2037
|
-
state$
|
|
2037
|
+
state$4.entries.sort(
|
|
2038
2038
|
(a, b) => new Date(b.visitedAt).getTime() - new Date(a.visitedAt).getTime()
|
|
2039
2039
|
);
|
|
2040
|
-
if (state$
|
|
2041
|
-
state$
|
|
2040
|
+
if (state$4.entries.length > MAX_HISTORY_ENTRIES) {
|
|
2041
|
+
state$4.entries = state$4.entries.slice(0, MAX_HISTORY_ENTRIES);
|
|
2042
2042
|
}
|
|
2043
|
-
save$
|
|
2044
|
-
emit$
|
|
2043
|
+
save$2();
|
|
2044
|
+
emit$3();
|
|
2045
2045
|
} catch {
|
|
2046
2046
|
errors++;
|
|
2047
2047
|
}
|
|
@@ -2052,7 +2052,7 @@ function importHistoryFromHtml(content) {
|
|
|
2052
2052
|
let skipped = 0;
|
|
2053
2053
|
let errors = 0;
|
|
2054
2054
|
load$3();
|
|
2055
|
-
const existingUrls = new Set(state$
|
|
2055
|
+
const existingUrls = new Set(state$4.entries.map((e) => e.url));
|
|
2056
2056
|
const hrefRegex = /<A\s+[^>]*HREF="([^"]+)"[^>]*>([^<]*)<\/A>/gi;
|
|
2057
2057
|
let match;
|
|
2058
2058
|
while ((match = hrefRegex.exec(content)) !== null) {
|
|
@@ -2063,7 +2063,7 @@ function importHistoryFromHtml(content) {
|
|
|
2063
2063
|
else errors++;
|
|
2064
2064
|
continue;
|
|
2065
2065
|
}
|
|
2066
|
-
state$
|
|
2066
|
+
state$4.entries.push({
|
|
2067
2067
|
url,
|
|
2068
2068
|
title,
|
|
2069
2069
|
visitedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -2071,18 +2071,18 @@ function importHistoryFromHtml(content) {
|
|
|
2071
2071
|
existingUrls.add(url);
|
|
2072
2072
|
imported++;
|
|
2073
2073
|
}
|
|
2074
|
-
state$
|
|
2074
|
+
state$4.entries.sort(
|
|
2075
2075
|
(a, b) => new Date(b.visitedAt).getTime() - new Date(a.visitedAt).getTime()
|
|
2076
2076
|
);
|
|
2077
|
-
if (state$
|
|
2078
|
-
state$
|
|
2077
|
+
if (state$4.entries.length > MAX_HISTORY_ENTRIES) {
|
|
2078
|
+
state$4.entries = state$4.entries.slice(0, MAX_HISTORY_ENTRIES);
|
|
2079
2079
|
}
|
|
2080
|
-
save$
|
|
2081
|
-
emit$
|
|
2080
|
+
save$2();
|
|
2081
|
+
emit$3();
|
|
2082
2082
|
return { imported, skipped, errors };
|
|
2083
2083
|
}
|
|
2084
2084
|
function flushPersist$3() {
|
|
2085
|
-
return persistence$
|
|
2085
|
+
return persistence$6.flush();
|
|
2086
2086
|
}
|
|
2087
2087
|
const MAX_CONSOLE_ENTRIES = 500;
|
|
2088
2088
|
const MAX_NETWORK_ENTRIES = 200;
|
|
@@ -2439,18 +2439,18 @@ class DevToolsSession {
|
|
|
2439
2439
|
if (result?.__error) throw new Error(result.__error);
|
|
2440
2440
|
return { type, origin, entries: result ?? {} };
|
|
2441
2441
|
}
|
|
2442
|
-
async setStorage(type,
|
|
2442
|
+
async setStorage(type, key2, value) {
|
|
2443
2443
|
const storageType = type === "localStorage" ? "localStorage" : "sessionStorage";
|
|
2444
2444
|
if (value === null) {
|
|
2445
2445
|
await this.wc.executeJavaScript(
|
|
2446
|
-
`window.${storageType}.removeItem(${JSON.stringify(
|
|
2446
|
+
`window.${storageType}.removeItem(${JSON.stringify(key2)})`
|
|
2447
2447
|
);
|
|
2448
|
-
return `Removed "${
|
|
2448
|
+
return `Removed "${key2}" from ${type}`;
|
|
2449
2449
|
}
|
|
2450
2450
|
await this.wc.executeJavaScript(
|
|
2451
|
-
`window.${storageType}.setItem(${JSON.stringify(
|
|
2451
|
+
`window.${storageType}.setItem(${JSON.stringify(key2)}, ${JSON.stringify(value)})`
|
|
2452
2452
|
);
|
|
2453
|
-
return `Set ${type}["${
|
|
2453
|
+
return `Set ${type}["${key2}"] = ${value.length > 80 ? value.slice(0, 77) + "..." : value}`;
|
|
2454
2454
|
}
|
|
2455
2455
|
// ---------------------------------------------------------------------------
|
|
2456
2456
|
// Performance
|
|
@@ -3015,23 +3015,23 @@ class TabManager {
|
|
|
3015
3015
|
async saveTabAsPdf(id) {
|
|
3016
3016
|
const tab = this.tabs.get(id);
|
|
3017
3017
|
if (!tab) return null;
|
|
3018
|
-
const { canceled, filePath } = await electron.dialog.showSaveDialog({
|
|
3018
|
+
const { canceled, filePath: filePath2 } = await electron.dialog.showSaveDialog({
|
|
3019
3019
|
title: "Save Page as PDF",
|
|
3020
3020
|
defaultPath: sanitizePdfFilename(tab.state.title || "Vessel Page"),
|
|
3021
3021
|
filters: [{ name: "PDF", extensions: ["pdf"] }]
|
|
3022
3022
|
});
|
|
3023
|
-
if (canceled || !
|
|
3023
|
+
if (canceled || !filePath2) return null;
|
|
3024
3024
|
const data = await tab.view.webContents.printToPDF({
|
|
3025
3025
|
printBackground: true
|
|
3026
3026
|
});
|
|
3027
|
-
await fs.promises.writeFile(
|
|
3028
|
-
return
|
|
3027
|
+
await fs.promises.writeFile(filePath2, data);
|
|
3028
|
+
return filePath2;
|
|
3029
3029
|
}
|
|
3030
3030
|
async savePage(id, format = "MHTML") {
|
|
3031
3031
|
const tab = this.tabs.get(id);
|
|
3032
3032
|
if (!tab) return null;
|
|
3033
3033
|
const ext = format === "MHTML" ? "mhtml" : "html";
|
|
3034
|
-
const { canceled, filePath } = await electron.dialog.showSaveDialog({
|
|
3034
|
+
const { canceled, filePath: filePath2 } = await electron.dialog.showSaveDialog({
|
|
3035
3035
|
title: "Save Page As",
|
|
3036
3036
|
defaultPath: sanitizePageFilename(
|
|
3037
3037
|
tab.state.title || "Vessel Page",
|
|
@@ -3041,9 +3041,9 @@ class TabManager {
|
|
|
3041
3041
|
{ name: format === "MHTML" ? "MHTML" : "HTML", extensions: [ext] }
|
|
3042
3042
|
]
|
|
3043
3043
|
});
|
|
3044
|
-
if (canceled || !
|
|
3045
|
-
await tab.view.webContents.savePage(
|
|
3046
|
-
return
|
|
3044
|
+
if (canceled || !filePath2) return null;
|
|
3045
|
+
await tab.view.webContents.savePage(filePath2, format);
|
|
3046
|
+
return filePath2;
|
|
3047
3047
|
}
|
|
3048
3048
|
getActiveTab() {
|
|
3049
3049
|
return this.activeTabId ? this.tabs.get(this.activeTabId) : void 0;
|
|
@@ -3127,11 +3127,11 @@ class TabManager {
|
|
|
3127
3127
|
this.pinTab(ids[index]);
|
|
3128
3128
|
}
|
|
3129
3129
|
if (tab.groupName && ids[index]) {
|
|
3130
|
-
const
|
|
3131
|
-
let groupId = restoredGroups.get(
|
|
3130
|
+
const key2 = `${tab.groupName}|${tab.groupColor ?? "blue"}`;
|
|
3131
|
+
let groupId = restoredGroups.get(key2);
|
|
3132
3132
|
if (!groupId) {
|
|
3133
3133
|
groupId = crypto$1.randomUUID();
|
|
3134
|
-
restoredGroups.set(
|
|
3134
|
+
restoredGroups.set(key2, groupId);
|
|
3135
3135
|
this.tabGroups.set(groupId, {
|
|
3136
3136
|
id: groupId,
|
|
3137
3137
|
name: tab.groupName,
|
|
@@ -3456,6 +3456,11 @@ const Channels = {
|
|
|
3456
3456
|
DOWNLOAD_STARTED: "download:started",
|
|
3457
3457
|
DOWNLOAD_PROGRESS: "download:progress",
|
|
3458
3458
|
DOWNLOAD_DONE: "download:done",
|
|
3459
|
+
DOWNLOADS_GET: "downloads:get",
|
|
3460
|
+
DOWNLOADS_CLEAR: "downloads:clear",
|
|
3461
|
+
DOWNLOADS_OPEN: "downloads:open",
|
|
3462
|
+
DOWNLOADS_SHOW_IN_FOLDER: "downloads:show-in-folder",
|
|
3463
|
+
DOWNLOADS_UPDATE: "downloads:update",
|
|
3459
3464
|
// Premium
|
|
3460
3465
|
PREMIUM_GET_STATE: "premium:get-state",
|
|
3461
3466
|
PREMIUM_ACTIVATION_START: "premium:activation-start",
|
|
@@ -3518,7 +3523,14 @@ const Channels = {
|
|
|
3518
3523
|
CODEX_START_AUTH: "codex:start-auth",
|
|
3519
3524
|
CODEX_CANCEL_AUTH: "codex:cancel-auth",
|
|
3520
3525
|
CODEX_AUTH_STATUS: "codex:auth-status",
|
|
3521
|
-
CODEX_DISCONNECT: "codex:disconnect"
|
|
3526
|
+
CODEX_DISCONNECT: "codex:disconnect",
|
|
3527
|
+
// Updates
|
|
3528
|
+
UPDATES_CHECK: "updates:check",
|
|
3529
|
+
UPDATES_OPEN_DOWNLOAD: "updates:open-download",
|
|
3530
|
+
// Permissions
|
|
3531
|
+
PERMISSIONS_GET: "permissions:get",
|
|
3532
|
+
PERMISSIONS_CLEAR: "permissions:clear",
|
|
3533
|
+
PERMISSIONS_CLEAR_ORIGIN: "permissions:clear-origin"
|
|
3522
3534
|
};
|
|
3523
3535
|
const MAX_DETAIL_ITEMS = 3;
|
|
3524
3536
|
const MIN_BLOCK_SIMILARITY = 0.82;
|
|
@@ -3760,25 +3772,25 @@ function normalizeQueryValue(value) {
|
|
|
3760
3772
|
}
|
|
3761
3773
|
function serializeSnapshotParams(params) {
|
|
3762
3774
|
return params.map(
|
|
3763
|
-
([
|
|
3775
|
+
([key2, value]) => `${encodeURIComponent(key2)}=${encodeURIComponent(value)}`
|
|
3764
3776
|
).join("&");
|
|
3765
3777
|
}
|
|
3766
3778
|
function normalizeSnapshotParams(entries, pathname) {
|
|
3767
3779
|
return Array.from(entries).filter(
|
|
3768
|
-
([
|
|
3769
|
-
).map(([
|
|
3770
|
-
|
|
3780
|
+
([key2, value]) => shouldKeepSnapshotQueryParam(pathname, key2, value)
|
|
3781
|
+
).map(([key2, value]) => [
|
|
3782
|
+
key2.trim().toLowerCase(),
|
|
3771
3783
|
normalizeQueryValue(value)
|
|
3772
3784
|
]).sort(
|
|
3773
3785
|
([keyA, valueA], [keyB, valueB]) => keyA === keyB ? valueA.localeCompare(valueB) : keyA.localeCompare(keyB)
|
|
3774
3786
|
);
|
|
3775
3787
|
}
|
|
3776
3788
|
function shouldKeepSnapshotQueryParam(pathname, rawKey, value) {
|
|
3777
|
-
const
|
|
3778
|
-
if (!
|
|
3779
|
-
if (
|
|
3780
|
-
if (TRACKING_QUERY_KEYS.has(
|
|
3781
|
-
if (SNAPSHOT_QUERY_KEYS.has(
|
|
3789
|
+
const key2 = rawKey.trim().toLowerCase();
|
|
3790
|
+
if (!key2 || !value.trim()) return false;
|
|
3791
|
+
if (key2.startsWith("utm_")) return false;
|
|
3792
|
+
if (TRACKING_QUERY_KEYS.has(key2)) return false;
|
|
3793
|
+
if (SNAPSHOT_QUERY_KEYS.has(key2)) return true;
|
|
3782
3794
|
return /\/(search|results|browse|discover|find|category|tag|topics?|collections?|list)(\/|$)/i.test(
|
|
3783
3795
|
pathname
|
|
3784
3796
|
);
|
|
@@ -3871,7 +3883,7 @@ function load$2() {
|
|
|
3871
3883
|
});
|
|
3872
3884
|
return snapshots;
|
|
3873
3885
|
}
|
|
3874
|
-
const persistence$
|
|
3886
|
+
const persistence$5 = createDebouncedJsonPersistence({
|
|
3875
3887
|
debounceMs: SAVE_DEBOUNCE_MS$3,
|
|
3876
3888
|
filePath: getFilePath$1(),
|
|
3877
3889
|
getValue: () => snapshots,
|
|
@@ -3890,21 +3902,21 @@ function getSnapshot(normalizedUrl) {
|
|
|
3890
3902
|
}
|
|
3891
3903
|
function saveSnapshot(rawUrl, title, textContent, headings) {
|
|
3892
3904
|
const s = load$2();
|
|
3893
|
-
const
|
|
3905
|
+
const key2 = normalizeUrl(rawUrl);
|
|
3894
3906
|
const snapshot = {
|
|
3895
|
-
url:
|
|
3907
|
+
url: key2,
|
|
3896
3908
|
title,
|
|
3897
3909
|
textContent: textContent.slice(0, MAX_TEXT_LENGTH),
|
|
3898
3910
|
headings: headings.map((h) => `${"#".repeat(h.level)} ${h.text}`).join("\n"),
|
|
3899
3911
|
capturedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3900
3912
|
};
|
|
3901
|
-
s.delete(
|
|
3902
|
-
s.set(
|
|
3903
|
-
persistence$
|
|
3913
|
+
s.delete(key2);
|
|
3914
|
+
s.set(key2, snapshot);
|
|
3915
|
+
persistence$5.schedule();
|
|
3904
3916
|
return snapshot;
|
|
3905
3917
|
}
|
|
3906
3918
|
function flushPersist$2() {
|
|
3907
|
-
return persistence$
|
|
3919
|
+
return persistence$5.flush();
|
|
3908
3920
|
}
|
|
3909
3921
|
const SEARCH_ENGINE_HOSTS = [
|
|
3910
3922
|
"google.",
|
|
@@ -4219,11 +4231,11 @@ function sanitizeValue(value, depth = 0) {
|
|
|
4219
4231
|
const record = asRecord(value);
|
|
4220
4232
|
if (!record || depth >= MAX_DEPTH) return void 0;
|
|
4221
4233
|
const objectValue = {};
|
|
4222
|
-
for (const [
|
|
4223
|
-
if (SKIP_FIELDS.has(
|
|
4234
|
+
for (const [key2, entry] of Object.entries(record)) {
|
|
4235
|
+
if (SKIP_FIELDS.has(key2)) continue;
|
|
4224
4236
|
const normalized = sanitizeValue(entry, depth + 1);
|
|
4225
4237
|
if (normalized !== void 0) {
|
|
4226
|
-
objectValue[
|
|
4238
|
+
objectValue[key2] = normalized;
|
|
4227
4239
|
}
|
|
4228
4240
|
}
|
|
4229
4241
|
return Object.keys(objectValue).length > 0 ? objectValue : void 0;
|
|
@@ -4231,10 +4243,10 @@ function sanitizeValue(value, depth = 0) {
|
|
|
4231
4243
|
function buildNormalizedAttributes(record, types) {
|
|
4232
4244
|
const attributes = {};
|
|
4233
4245
|
const consumed = /* @__PURE__ */ new Set();
|
|
4234
|
-
const consume = (
|
|
4246
|
+
const consume = (key2, value) => {
|
|
4235
4247
|
if (value === void 0) return;
|
|
4236
|
-
consumed.add(
|
|
4237
|
-
attributes[
|
|
4248
|
+
consumed.add(key2);
|
|
4249
|
+
attributes[key2] = value;
|
|
4238
4250
|
};
|
|
4239
4251
|
if (types.includes("Recipe")) {
|
|
4240
4252
|
consume("yield", sanitizeValue(record.recipeYield));
|
|
@@ -4278,14 +4290,14 @@ function buildNormalizedAttributes(record, types) {
|
|
|
4278
4290
|
attributes.questions = questions;
|
|
4279
4291
|
}
|
|
4280
4292
|
}
|
|
4281
|
-
for (const [
|
|
4282
|
-
if (SKIP_FIELDS.has(
|
|
4283
|
-
if (
|
|
4293
|
+
for (const [key2, value] of Object.entries(record)) {
|
|
4294
|
+
if (SKIP_FIELDS.has(key2) || consumed.has(key2)) continue;
|
|
4295
|
+
if (key2 === "name" || key2 === "headline" || key2 === "url" || key2 === "description") {
|
|
4284
4296
|
continue;
|
|
4285
4297
|
}
|
|
4286
4298
|
const normalized = sanitizeValue(value);
|
|
4287
4299
|
if (normalized !== void 0) {
|
|
4288
|
-
attributes[
|
|
4300
|
+
attributes[key2] = normalized;
|
|
4289
4301
|
}
|
|
4290
4302
|
}
|
|
4291
4303
|
return attributes;
|
|
@@ -4305,7 +4317,7 @@ function collectCandidateEntities(value, results = [], seen = /* @__PURE__ */ ne
|
|
|
4305
4317
|
if (types.length > 0 || hasIdentity) {
|
|
4306
4318
|
results.push(record);
|
|
4307
4319
|
}
|
|
4308
|
-
for (const
|
|
4320
|
+
for (const key2 of [
|
|
4309
4321
|
"@graph",
|
|
4310
4322
|
"mainEntity",
|
|
4311
4323
|
"mainEntityOfPage",
|
|
@@ -4318,7 +4330,7 @@ function collectCandidateEntities(value, results = [], seen = /* @__PURE__ */ ne
|
|
|
4318
4330
|
"acceptedAnswer",
|
|
4319
4331
|
"suggestedAnswer"
|
|
4320
4332
|
]) {
|
|
4321
|
-
collectCandidateEntities(record[
|
|
4333
|
+
collectCandidateEntities(record[key2], results, seen);
|
|
4322
4334
|
}
|
|
4323
4335
|
return results;
|
|
4324
4336
|
}
|
|
@@ -4331,11 +4343,11 @@ function dedupeKey(entity) {
|
|
|
4331
4343
|
JSON.stringify(entity.attributes)
|
|
4332
4344
|
].join("::");
|
|
4333
4345
|
}
|
|
4334
|
-
function extractEntitiesFromRecords(
|
|
4335
|
-
if (!
|
|
4346
|
+
function extractEntitiesFromRecords(records2, source) {
|
|
4347
|
+
if (!records2 || records2.length === 0) return [];
|
|
4336
4348
|
const entities = [];
|
|
4337
4349
|
const seen = /* @__PURE__ */ new Set();
|
|
4338
|
-
for (const candidate of collectCandidateEntities(
|
|
4350
|
+
for (const candidate of collectCandidateEntities(records2)) {
|
|
4339
4351
|
const types = getTypes(candidate);
|
|
4340
4352
|
const name = firstString(candidate.name, candidate.headline);
|
|
4341
4353
|
const url = firstString(candidate.url, candidate["@id"]);
|
|
@@ -4355,9 +4367,9 @@ function extractEntitiesFromRecords(records, source) {
|
|
|
4355
4367
|
addIfPresent(entity, "name", name);
|
|
4356
4368
|
addIfPresent(entity, "url", url);
|
|
4357
4369
|
addIfPresent(entity, "description", description);
|
|
4358
|
-
const
|
|
4359
|
-
if (seen.has(
|
|
4360
|
-
seen.add(
|
|
4370
|
+
const key2 = dedupeKey(entity);
|
|
4371
|
+
if (seen.has(key2)) continue;
|
|
4372
|
+
seen.add(key2);
|
|
4361
4373
|
entities.push(entity);
|
|
4362
4374
|
}
|
|
4363
4375
|
return entities.slice(0, 25);
|
|
@@ -4380,13 +4392,13 @@ function extractEntityFromMetaTags(metaTags, pageTitle, pageUrl) {
|
|
|
4380
4392
|
const url = metaTags["og:url"] || metaTags.canonical || pageUrl;
|
|
4381
4393
|
const types = getMetaType(metaTags);
|
|
4382
4394
|
const attributes = {};
|
|
4383
|
-
for (const [
|
|
4384
|
-
if (
|
|
4395
|
+
for (const [key2, value] of Object.entries(metaTags)) {
|
|
4396
|
+
if (key2 === "og:title" || key2 === "twitter:title" || key2 === "title" || key2 === "og:description" || key2 === "description" || key2 === "twitter:description" || key2 === "og:url" || key2 === "canonical") {
|
|
4385
4397
|
continue;
|
|
4386
4398
|
}
|
|
4387
4399
|
const normalized = sanitizeValue(value);
|
|
4388
4400
|
if (normalized !== void 0) {
|
|
4389
|
-
attributes[
|
|
4401
|
+
attributes[key2] = normalized;
|
|
4390
4402
|
}
|
|
4391
4403
|
}
|
|
4392
4404
|
const entity = {
|
|
@@ -4439,9 +4451,9 @@ function extractStructuredDataFromJsonLd(jsonLd, microdata, rdfa, metaTags, page
|
|
|
4439
4451
|
const deduped = [];
|
|
4440
4452
|
const seen = /* @__PURE__ */ new Set();
|
|
4441
4453
|
for (const entity of candidates) {
|
|
4442
|
-
const
|
|
4443
|
-
if (seen.has(
|
|
4444
|
-
seen.add(
|
|
4454
|
+
const key2 = dedupeKey(entity);
|
|
4455
|
+
if (seen.has(key2)) continue;
|
|
4456
|
+
seen.add(key2);
|
|
4445
4457
|
deduped.push(entity);
|
|
4446
4458
|
}
|
|
4447
4459
|
if (deduped.length > 0) {
|
|
@@ -4455,9 +4467,9 @@ function extractStructuredDataFromJsonLd(jsonLd, microdata, rdfa, metaTags, page
|
|
|
4455
4467
|
pageHeadings
|
|
4456
4468
|
);
|
|
4457
4469
|
}
|
|
4458
|
-
function addIfPresent(target,
|
|
4470
|
+
function addIfPresent(target, key2, value) {
|
|
4459
4471
|
if (value !== void 0) {
|
|
4460
|
-
target[
|
|
4472
|
+
target[key2] = value;
|
|
4461
4473
|
}
|
|
4462
4474
|
}
|
|
4463
4475
|
function okResult(value) {
|
|
@@ -4770,8 +4782,8 @@ function trackProviderConfigured(providerId) {
|
|
|
4770
4782
|
provider_id: providerId
|
|
4771
4783
|
});
|
|
4772
4784
|
}
|
|
4773
|
-
function trackSettingChanged(
|
|
4774
|
-
trackEvent("setting_changed", { setting_key:
|
|
4785
|
+
function trackSettingChanged(key2) {
|
|
4786
|
+
trackEvent("setting_changed", { setting_key: key2 });
|
|
4775
4787
|
}
|
|
4776
4788
|
function trackApprovalModeChanged(mode) {
|
|
4777
4789
|
trackEvent("approval_mode_changed", { mode });
|
|
@@ -4953,10 +4965,10 @@ function mapFormFields(forms, interactiveElements) {
|
|
|
4953
4965
|
}
|
|
4954
4966
|
}
|
|
4955
4967
|
for (const el of interactiveElements) {
|
|
4956
|
-
const
|
|
4957
|
-
if (formFieldSelectors.has(
|
|
4968
|
+
const key2 = el.selector || el.name || el.label || String(el.index);
|
|
4969
|
+
if (formFieldSelectors.has(key2)) {
|
|
4958
4970
|
fields.push({
|
|
4959
|
-
name: el.name || el.label ||
|
|
4971
|
+
name: el.name || el.label || key2,
|
|
4960
4972
|
type: mapInputType(el),
|
|
4961
4973
|
label: el.label,
|
|
4962
4974
|
required: el.required,
|
|
@@ -6195,12 +6207,12 @@ function loadHistory() {
|
|
|
6195
6207
|
return next;
|
|
6196
6208
|
}
|
|
6197
6209
|
});
|
|
6198
|
-
for (const [
|
|
6199
|
-
recentPageDiffBursts.set(
|
|
6210
|
+
for (const [key2, bursts] of loaded.entries()) {
|
|
6211
|
+
recentPageDiffBursts.set(key2, bursts);
|
|
6200
6212
|
}
|
|
6201
6213
|
return recentPageDiffBursts;
|
|
6202
6214
|
}
|
|
6203
|
-
const persistence$
|
|
6215
|
+
const persistence$4 = createDebouncedJsonPersistence({
|
|
6204
6216
|
debounceMs: SAVE_DEBOUNCE_MS$2,
|
|
6205
6217
|
filePath: getHistoryFilePath(),
|
|
6206
6218
|
getValue: () => recentPageDiffBursts,
|
|
@@ -6217,20 +6229,20 @@ function getLatestPageDiff(rawUrl) {
|
|
|
6217
6229
|
}
|
|
6218
6230
|
function getPageDiffBursts(rawUrl) {
|
|
6219
6231
|
if (!shouldTrackSnapshotUrl(rawUrl)) return [];
|
|
6220
|
-
const
|
|
6232
|
+
const key2 = normalizeUrl(rawUrl);
|
|
6221
6233
|
const history = loadHistory();
|
|
6222
|
-
const bursts = prunePageDiffHistory(history.get(
|
|
6234
|
+
const bursts = prunePageDiffHistory(history.get(key2) ?? [], {
|
|
6223
6235
|
maxAgeDays: MAX_HISTORY_DAYS,
|
|
6224
6236
|
maxItems: MAX_PERSISTED_DIFF_BURSTS
|
|
6225
6237
|
});
|
|
6226
|
-
const current = history.get(
|
|
6238
|
+
const current = history.get(key2) ?? [];
|
|
6227
6239
|
if (current.length !== bursts.length) {
|
|
6228
6240
|
if (bursts.length > 0) {
|
|
6229
|
-
history.set(
|
|
6241
|
+
history.set(key2, bursts);
|
|
6230
6242
|
} else {
|
|
6231
|
-
history.delete(
|
|
6243
|
+
history.delete(key2);
|
|
6232
6244
|
}
|
|
6233
|
-
persistence$
|
|
6245
|
+
persistence$4.schedule();
|
|
6234
6246
|
}
|
|
6235
6247
|
return bursts.slice().reverse();
|
|
6236
6248
|
}
|
|
@@ -6238,20 +6250,20 @@ function summarizeDiffBurst(diff) {
|
|
|
6238
6250
|
const items = diff.changes.slice(0, 2).map((change) => `${change.section}: ${change.summary}`);
|
|
6239
6251
|
return items.join(" | ");
|
|
6240
6252
|
}
|
|
6241
|
-
function enrichWithBurstHistory(
|
|
6253
|
+
function enrichWithBurstHistory(key2, diff) {
|
|
6242
6254
|
const detectedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
6243
6255
|
const nextBurst = {
|
|
6244
6256
|
detectedAt,
|
|
6245
6257
|
summary: summarizeDiffBurst(diff)
|
|
6246
6258
|
};
|
|
6247
6259
|
const history = loadHistory();
|
|
6248
|
-
const bursts = appendPageDiffHistoryItem(history.get(
|
|
6260
|
+
const bursts = appendPageDiffHistoryItem(history.get(key2) ?? [], nextBurst, {
|
|
6249
6261
|
maxAgeDays: MAX_HISTORY_DAYS,
|
|
6250
6262
|
maxItems: MAX_PERSISTED_DIFF_BURSTS,
|
|
6251
6263
|
now: Date.parse(detectedAt)
|
|
6252
6264
|
});
|
|
6253
|
-
history.set(
|
|
6254
|
-
persistence$
|
|
6265
|
+
history.set(key2, bursts);
|
|
6266
|
+
persistence$4.schedule();
|
|
6255
6267
|
const recentBursts = bursts.slice(-5);
|
|
6256
6268
|
return {
|
|
6257
6269
|
...diff,
|
|
@@ -6264,8 +6276,8 @@ function enrichWithBurstHistory(key, diff) {
|
|
|
6264
6276
|
async function capturePageSnapshot(url, wc, sendToRendererViews) {
|
|
6265
6277
|
try {
|
|
6266
6278
|
if (!shouldTrackSnapshotUrl(url)) return;
|
|
6267
|
-
const
|
|
6268
|
-
const oldSnap = getSnapshot(
|
|
6279
|
+
const key2 = normalizeUrl(url);
|
|
6280
|
+
const oldSnap = getSnapshot(key2);
|
|
6269
6281
|
const content = await extractContent(wc);
|
|
6270
6282
|
const textContent = content.content || "";
|
|
6271
6283
|
const title = content.title || "";
|
|
@@ -6274,14 +6286,14 @@ async function capturePageSnapshot(url, wc, sendToRendererViews) {
|
|
|
6274
6286
|
if (oldSnap) {
|
|
6275
6287
|
const diff = diffSnapshots(oldSnap, textContent, title, currentHeadings);
|
|
6276
6288
|
if (diff.hasChanges) {
|
|
6277
|
-
const enrichedDiff = enrichWithBurstHistory(
|
|
6278
|
-
latestPageDiffs.set(
|
|
6289
|
+
const enrichedDiff = enrichWithBurstHistory(key2, diff);
|
|
6290
|
+
latestPageDiffs.set(key2, enrichedDiff);
|
|
6279
6291
|
sendToRendererViews(Channels.PAGE_CHANGED, enrichedDiff);
|
|
6280
6292
|
} else {
|
|
6281
|
-
latestPageDiffs.delete(
|
|
6293
|
+
latestPageDiffs.delete(key2);
|
|
6282
6294
|
}
|
|
6283
6295
|
} else {
|
|
6284
|
-
latestPageDiffs.delete(
|
|
6296
|
+
latestPageDiffs.delete(key2);
|
|
6285
6297
|
}
|
|
6286
6298
|
saveSnapshot(url, title, textContent, headings);
|
|
6287
6299
|
} catch {
|
|
@@ -6333,19 +6345,19 @@ function schedulePageSnapshotCapture(wc, sendToRendererViews, delayMs = 0) {
|
|
|
6333
6345
|
function enableClipboardShortcuts(view) {
|
|
6334
6346
|
view.webContents.on("before-input-event", (event, input) => {
|
|
6335
6347
|
if (!input.control && !input.meta) return;
|
|
6336
|
-
const
|
|
6348
|
+
const key2 = input.key.toLowerCase();
|
|
6337
6349
|
const wc = view.webContents;
|
|
6338
6350
|
if (input.type === "keyDown") {
|
|
6339
|
-
if (
|
|
6351
|
+
if (key2 === "c") {
|
|
6340
6352
|
wc.copy();
|
|
6341
6353
|
event.preventDefault();
|
|
6342
|
-
} else if (
|
|
6354
|
+
} else if (key2 === "v") {
|
|
6343
6355
|
wc.paste();
|
|
6344
6356
|
event.preventDefault();
|
|
6345
|
-
} else if (
|
|
6357
|
+
} else if (key2 === "x") {
|
|
6346
6358
|
wc.cut();
|
|
6347
6359
|
event.preventDefault();
|
|
6348
|
-
} else if (
|
|
6360
|
+
} else if (key2 === "a") {
|
|
6349
6361
|
wc.selectAll();
|
|
6350
6362
|
event.preventDefault();
|
|
6351
6363
|
}
|
|
@@ -6759,7 +6771,7 @@ function onRuntimeHealthChange(listener) {
|
|
|
6759
6771
|
};
|
|
6760
6772
|
}
|
|
6761
6773
|
function getMcpStatus() {
|
|
6762
|
-
return state$
|
|
6774
|
+
return state$3.mcp.status;
|
|
6763
6775
|
}
|
|
6764
6776
|
function emitRuntimeHealthChange() {
|
|
6765
6777
|
const snapshot = getRuntimeHealth();
|
|
@@ -6767,7 +6779,7 @@ function emitRuntimeHealthChange() {
|
|
|
6767
6779
|
listener(snapshot);
|
|
6768
6780
|
}
|
|
6769
6781
|
}
|
|
6770
|
-
const state$
|
|
6782
|
+
const state$3 = {
|
|
6771
6783
|
userDataPath: "",
|
|
6772
6784
|
settingsPath: "",
|
|
6773
6785
|
startupIssues: [],
|
|
@@ -6780,43 +6792,43 @@ const state$2 = {
|
|
|
6780
6792
|
}
|
|
6781
6793
|
};
|
|
6782
6794
|
function initializeRuntimeHealth(paths) {
|
|
6783
|
-
state$
|
|
6784
|
-
state$
|
|
6785
|
-
state$
|
|
6786
|
-
state$
|
|
6787
|
-
state$
|
|
6788
|
-
state$
|
|
6789
|
-
state$
|
|
6795
|
+
state$3.userDataPath = paths.userDataPath;
|
|
6796
|
+
state$3.settingsPath = paths.settingsPath;
|
|
6797
|
+
state$3.mcp.configuredPort = paths.configuredPort;
|
|
6798
|
+
state$3.mcp.activePort = null;
|
|
6799
|
+
state$3.mcp.endpoint = null;
|
|
6800
|
+
state$3.mcp.status = "stopped";
|
|
6801
|
+
state$3.mcp.message = "MCP server has not started yet.";
|
|
6790
6802
|
emitRuntimeHealthChange();
|
|
6791
6803
|
}
|
|
6792
6804
|
function setStartupIssues(issues) {
|
|
6793
|
-
state$
|
|
6805
|
+
state$3.startupIssues = issues.map((issue) => ({ ...issue }));
|
|
6794
6806
|
emitRuntimeHealthChange();
|
|
6795
6807
|
}
|
|
6796
6808
|
function getRuntimeHealth() {
|
|
6797
6809
|
return {
|
|
6798
|
-
userDataPath: state$
|
|
6799
|
-
settingsPath: state$
|
|
6800
|
-
startupIssues: state$
|
|
6801
|
-
mcp: { ...state$
|
|
6810
|
+
userDataPath: state$3.userDataPath,
|
|
6811
|
+
settingsPath: state$3.settingsPath,
|
|
6812
|
+
startupIssues: state$3.startupIssues.map((issue) => ({ ...issue })),
|
|
6813
|
+
mcp: { ...state$3.mcp }
|
|
6802
6814
|
};
|
|
6803
6815
|
}
|
|
6804
6816
|
function setMcpHealth(update) {
|
|
6805
6817
|
if (typeof update.configuredPort === "number") {
|
|
6806
|
-
state$
|
|
6818
|
+
state$3.mcp.configuredPort = update.configuredPort;
|
|
6807
6819
|
}
|
|
6808
6820
|
if ("activePort" in update) {
|
|
6809
|
-
state$
|
|
6821
|
+
state$3.mcp.activePort = update.activePort ?? null;
|
|
6810
6822
|
}
|
|
6811
6823
|
if ("endpoint" in update) {
|
|
6812
|
-
state$
|
|
6824
|
+
state$3.mcp.endpoint = update.endpoint ?? null;
|
|
6813
6825
|
}
|
|
6814
|
-
const prevStatus = state$
|
|
6815
|
-
state$
|
|
6816
|
-
state$
|
|
6817
|
-
if (prevStatus !== state$
|
|
6826
|
+
const prevStatus = state$3.mcp.status;
|
|
6827
|
+
state$3.mcp.status = update.status;
|
|
6828
|
+
state$3.mcp.message = update.message;
|
|
6829
|
+
if (prevStatus !== state$3.mcp.status) {
|
|
6818
6830
|
for (const listener of mcpStatusChangeListeners) {
|
|
6819
|
-
listener(state$
|
|
6831
|
+
listener(state$3.mcp.status);
|
|
6820
6832
|
}
|
|
6821
6833
|
}
|
|
6822
6834
|
emitRuntimeHealthChange();
|
|
@@ -7728,8 +7740,8 @@ function scalarArgsForTool(name, scalar) {
|
|
|
7728
7740
|
return null;
|
|
7729
7741
|
}
|
|
7730
7742
|
function firstStringArg(args, keys) {
|
|
7731
|
-
for (const
|
|
7732
|
-
const value = args[
|
|
7743
|
+
for (const key2 of keys) {
|
|
7744
|
+
const value = args[key2];
|
|
7733
7745
|
if (typeof value === "string" && value.trim()) {
|
|
7734
7746
|
return value.trim();
|
|
7735
7747
|
}
|
|
@@ -9020,8 +9032,8 @@ function extractLlamaCppCtxSize(payload) {
|
|
|
9020
9032
|
const current = queue.shift();
|
|
9021
9033
|
if (!current || typeof current !== "object" || visited.has(current)) continue;
|
|
9022
9034
|
visited.add(current);
|
|
9023
|
-
for (const [
|
|
9024
|
-
if (typeof value === "number" && Number.isFinite(value) && /^(n_ctx|ctx_size|context_size)$/i.test(
|
|
9035
|
+
for (const [key2, value] of Object.entries(current)) {
|
|
9036
|
+
if (typeof value === "number" && Number.isFinite(value) && /^(n_ctx|ctx_size|context_size)$/i.test(key2)) {
|
|
9025
9037
|
return value;
|
|
9026
9038
|
}
|
|
9027
9039
|
if (value && typeof value === "object") {
|
|
@@ -9243,14 +9255,14 @@ function normalizeStoredRadioOption(option) {
|
|
|
9243
9255
|
function dedupeCandidates(actions) {
|
|
9244
9256
|
const seen = /* @__PURE__ */ new Set();
|
|
9245
9257
|
return actions.filter((action) => {
|
|
9246
|
-
const
|
|
9258
|
+
const key2 = [
|
|
9247
9259
|
action.selector || "",
|
|
9248
9260
|
action.label || "",
|
|
9249
9261
|
action.role || "",
|
|
9250
9262
|
action.labelSource || ""
|
|
9251
9263
|
].join("::");
|
|
9252
|
-
if (seen.has(
|
|
9253
|
-
seen.add(
|
|
9264
|
+
if (seen.has(key2)) return false;
|
|
9265
|
+
seen.add(key2);
|
|
9254
9266
|
return true;
|
|
9255
9267
|
});
|
|
9256
9268
|
}
|
|
@@ -9495,11 +9507,11 @@ function getQuantityElements(page) {
|
|
|
9495
9507
|
];
|
|
9496
9508
|
return elements.filter((el) => {
|
|
9497
9509
|
if (!isQuantityLike(el)) return false;
|
|
9498
|
-
const
|
|
9510
|
+
const key2 = String(
|
|
9499
9511
|
el.index ?? el.selector ?? `${el.type}|${el.name || ""}|${el.label || ""}|${el.value || ""}`
|
|
9500
9512
|
);
|
|
9501
|
-
if (seen.has(
|
|
9502
|
-
seen.add(
|
|
9513
|
+
if (seen.has(key2)) return false;
|
|
9514
|
+
seen.add(key2);
|
|
9503
9515
|
return true;
|
|
9504
9516
|
});
|
|
9505
9517
|
}
|
|
@@ -9541,9 +9553,9 @@ function getCartItemLinks(page) {
|
|
|
9541
9553
|
return false;
|
|
9542
9554
|
}
|
|
9543
9555
|
if (blockedText.test(text) || blockedHref.test(href)) return false;
|
|
9544
|
-
const
|
|
9545
|
-
if (seen.has(
|
|
9546
|
-
seen.add(
|
|
9556
|
+
const key2 = `${normalizeComparable(text)}|${normalizeUrlForMatch(href) || href}`;
|
|
9557
|
+
if (seen.has(key2)) return false;
|
|
9558
|
+
seen.add(key2);
|
|
9547
9559
|
return true;
|
|
9548
9560
|
}).slice(0, 12);
|
|
9549
9561
|
}
|
|
@@ -9644,11 +9656,11 @@ function getPurchaseActionElements(page, options) {
|
|
|
9644
9656
|
if (!isPurchaseActionElement(el)) return false;
|
|
9645
9657
|
if (visibleOnly && !isVisibleToUser(el)) return false;
|
|
9646
9658
|
if (el.blockedByOverlay) return false;
|
|
9647
|
-
const
|
|
9659
|
+
const key2 = String(
|
|
9648
9660
|
el.index ?? el.selector ?? `${el.type}|${el.text || ""}|${el.label || ""}|${el.href || ""}`
|
|
9649
9661
|
);
|
|
9650
|
-
if (seen.has(
|
|
9651
|
-
seen.add(
|
|
9662
|
+
if (seen.has(key2)) return false;
|
|
9663
|
+
seen.add(key2);
|
|
9652
9664
|
return true;
|
|
9653
9665
|
}).sort((a, b) => {
|
|
9654
9666
|
const delta = purchaseActionPriority(a) - purchaseActionPriority(b);
|
|
@@ -9665,10 +9677,10 @@ function getOffscreenPurchaseActionElements(page) {
|
|
|
9665
9677
|
)
|
|
9666
9678
|
);
|
|
9667
9679
|
return getPurchaseActionElements(page, { visibleOnly: false }).filter((el) => {
|
|
9668
|
-
const
|
|
9680
|
+
const key2 = String(
|
|
9669
9681
|
el.index ?? el.selector ?? `${el.type}|${el.text || ""}|${el.label || ""}|${el.href || ""}`
|
|
9670
9682
|
);
|
|
9671
|
-
return !visibleKeys.has(
|
|
9683
|
+
return !visibleKeys.has(key2) && el.visible !== false;
|
|
9672
9684
|
});
|
|
9673
9685
|
}
|
|
9674
9686
|
function getDialogFocusedElements(page) {
|
|
@@ -9934,7 +9946,7 @@ function formatStructuredValue(value, depth = 0) {
|
|
|
9934
9946
|
const rendered = value.map((item) => formatStructuredValue(item, depth + 1)).filter(Boolean).slice(0, depth === 0 ? 8 : 5);
|
|
9935
9947
|
return rendered.join(depth === 0 ? ", " : " | ");
|
|
9936
9948
|
}
|
|
9937
|
-
const entries = Object.entries(value).slice(0, 6).map(([
|
|
9949
|
+
const entries = Object.entries(value).slice(0, 6).map(([key2, entry]) => `${key2}: ${formatStructuredValue(entry, depth + 1)}`).filter((entry) => !entry.endsWith(": "));
|
|
9938
9950
|
return entries.join(", ");
|
|
9939
9951
|
}
|
|
9940
9952
|
function formatStructuredEntities(entities) {
|
|
@@ -9949,13 +9961,13 @@ function formatStructuredEntities(entities) {
|
|
|
9949
9961
|
if (entity.url && entity.url !== entity.name) {
|
|
9950
9962
|
lines.push(` url: ${entity.url}`);
|
|
9951
9963
|
}
|
|
9952
|
-
for (const [
|
|
9964
|
+
for (const [key2, value] of Object.entries(entity.attributes).slice(
|
|
9953
9965
|
0,
|
|
9954
9966
|
8
|
|
9955
9967
|
)) {
|
|
9956
9968
|
const rendered = formatStructuredValue(value);
|
|
9957
9969
|
if (rendered) {
|
|
9958
|
-
lines.push(` ${
|
|
9970
|
+
lines.push(` ${key2}: ${rendered}`);
|
|
9959
9971
|
}
|
|
9960
9972
|
}
|
|
9961
9973
|
return lines.join("\n");
|
|
@@ -10053,17 +10065,17 @@ function formatJsonLd(items) {
|
|
|
10053
10065
|
}
|
|
10054
10066
|
return String(val);
|
|
10055
10067
|
};
|
|
10056
|
-
for (const
|
|
10057
|
-
if (
|
|
10058
|
-
seen.add(
|
|
10059
|
-
const rendered = renderValue(item[
|
|
10060
|
-
if (rendered) lines.push(` ${
|
|
10068
|
+
for (const key2 of priorityFields) {
|
|
10069
|
+
if (key2 in item) {
|
|
10070
|
+
seen.add(key2);
|
|
10071
|
+
const rendered = renderValue(item[key2]);
|
|
10072
|
+
if (rendered) lines.push(` ${key2}: ${rendered}`);
|
|
10061
10073
|
}
|
|
10062
10074
|
}
|
|
10063
|
-
for (const [
|
|
10064
|
-
if (seen.has(
|
|
10075
|
+
for (const [key2, val] of Object.entries(item)) {
|
|
10076
|
+
if (seen.has(key2) || SKIP.has(key2) || key2 === "@type") continue;
|
|
10065
10077
|
const rendered = renderValue(val);
|
|
10066
|
-
if (rendered) lines.push(` ${
|
|
10078
|
+
if (rendered) lines.push(` ${key2}: ${rendered}`);
|
|
10067
10079
|
}
|
|
10068
10080
|
lines.push("");
|
|
10069
10081
|
}
|
|
@@ -10198,9 +10210,9 @@ function getResultCandidates(page) {
|
|
|
10198
10210
|
);
|
|
10199
10211
|
const seen = /* @__PURE__ */ new Set();
|
|
10200
10212
|
return scored.map(({ element }) => element).filter((element) => {
|
|
10201
|
-
const
|
|
10202
|
-
if (seen.has(
|
|
10203
|
-
seen.add(
|
|
10213
|
+
const key2 = `${normalizeComparable(element.text || "")}|${normalizeUrlForMatch(element.href) || ""}`;
|
|
10214
|
+
if (seen.has(key2)) return false;
|
|
10215
|
+
seen.add(key2);
|
|
10204
10216
|
return true;
|
|
10205
10217
|
});
|
|
10206
10218
|
}
|
|
@@ -10997,9 +11009,9 @@ function getCompactPrimaryResultLinks(page, options) {
|
|
|
10997
11009
|
})).filter(({ score }) => score >= (listingLike ? 5 : 7)).sort(
|
|
10998
11010
|
(a, b) => b.score - a.score || (a.element.index ?? Number.MAX_SAFE_INTEGER) - (b.element.index ?? Number.MAX_SAFE_INTEGER)
|
|
10999
11011
|
).map(({ element }) => element).filter((element) => {
|
|
11000
|
-
const
|
|
11001
|
-
if (seen.has(
|
|
11002
|
-
seen.add(
|
|
11012
|
+
const key2 = `${normalizeComparable(element.text)}|${normalizeUrlForMatch(element.href) || ""}`;
|
|
11013
|
+
if (seen.has(key2)) return false;
|
|
11014
|
+
seen.add(key2);
|
|
11003
11015
|
return true;
|
|
11004
11016
|
}).slice(0, max);
|
|
11005
11017
|
}
|
|
@@ -11045,9 +11057,9 @@ function formatElement(element) {
|
|
|
11045
11057
|
function uniqueElements(elements) {
|
|
11046
11058
|
const seen = /* @__PURE__ */ new Set();
|
|
11047
11059
|
return elements.filter((element) => {
|
|
11048
|
-
const
|
|
11049
|
-
if (seen.has(
|
|
11050
|
-
seen.add(
|
|
11060
|
+
const key2 = `${element.index ?? ""}|${element.type}|${elementLabel(element)}|${element.href ?? ""}`;
|
|
11061
|
+
if (seen.has(key2)) return false;
|
|
11062
|
+
seen.add(key2);
|
|
11051
11063
|
return true;
|
|
11052
11064
|
});
|
|
11053
11065
|
}
|
|
@@ -12370,12 +12382,12 @@ function normalizeAgentHints(value) {
|
|
|
12370
12382
|
return void 0;
|
|
12371
12383
|
}
|
|
12372
12384
|
const normalized = Object.fromEntries(
|
|
12373
|
-
Object.entries(value).map(([
|
|
12385
|
+
Object.entries(value).map(([key2, hint]) => [key2.trim(), normalizeOptionalString(hint)]).filter((entry) => Boolean(entry[0] && entry[1]))
|
|
12374
12386
|
);
|
|
12375
12387
|
return Object.keys(normalized).length > 0 ? normalized : void 0;
|
|
12376
12388
|
}
|
|
12377
|
-
function hasOwn(value,
|
|
12378
|
-
return Object.prototype.hasOwnProperty.call(value,
|
|
12389
|
+
function hasOwn(value, key2) {
|
|
12390
|
+
return Object.prototype.hasOwnProperty.call(value, key2);
|
|
12379
12391
|
}
|
|
12380
12392
|
function normalizeBookmarkMetadata(input) {
|
|
12381
12393
|
const normalized = {};
|
|
@@ -12413,7 +12425,7 @@ const UNSORTED_ID = "unsorted";
|
|
|
12413
12425
|
const ARCHIVE_FOLDER_NAME = "Archive";
|
|
12414
12426
|
const NETSCAPE_BOOKMARKS_DOCTYPE = "<!DOCTYPE NETSCAPE-Bookmark-file-1>";
|
|
12415
12427
|
const SAVE_DEBOUNCE_MS$1 = 250;
|
|
12416
|
-
let state$
|
|
12428
|
+
let state$2 = null;
|
|
12417
12429
|
const listeners = /* @__PURE__ */ new Set();
|
|
12418
12430
|
function cloneState(current) {
|
|
12419
12431
|
return {
|
|
@@ -12428,18 +12440,18 @@ function createPersistence() {
|
|
|
12428
12440
|
return createDebouncedJsonPersistence({
|
|
12429
12441
|
debounceMs: SAVE_DEBOUNCE_MS$1,
|
|
12430
12442
|
filePath: getBookmarksPath(),
|
|
12431
|
-
getValue: () => state$
|
|
12443
|
+
getValue: () => state$2,
|
|
12432
12444
|
logLabel: "bookmarks"
|
|
12433
12445
|
});
|
|
12434
12446
|
}
|
|
12435
|
-
let persistence$
|
|
12447
|
+
let persistence$3 = null;
|
|
12436
12448
|
function getPersistence() {
|
|
12437
|
-
persistence$
|
|
12438
|
-
return persistence$
|
|
12449
|
+
persistence$3 ??= createPersistence();
|
|
12450
|
+
return persistence$3;
|
|
12439
12451
|
}
|
|
12440
12452
|
function load$1() {
|
|
12441
|
-
if (state$
|
|
12442
|
-
state$
|
|
12453
|
+
if (state$2) return state$2;
|
|
12454
|
+
state$2 = loadJsonFile({
|
|
12443
12455
|
filePath: getBookmarksPath(),
|
|
12444
12456
|
fallback: { folders: [], bookmarks: [] },
|
|
12445
12457
|
parse: (raw) => {
|
|
@@ -12450,21 +12462,21 @@ function load$1() {
|
|
|
12450
12462
|
};
|
|
12451
12463
|
}
|
|
12452
12464
|
});
|
|
12453
|
-
return state$
|
|
12465
|
+
return state$2;
|
|
12454
12466
|
}
|
|
12455
|
-
function save() {
|
|
12467
|
+
function save$1() {
|
|
12456
12468
|
getPersistence().schedule();
|
|
12457
12469
|
}
|
|
12458
12470
|
function assignDefinedBookmarkFields(bookmark, fields) {
|
|
12459
12471
|
if (!fields) return;
|
|
12460
|
-
for (const [
|
|
12472
|
+
for (const [key2, value] of Object.entries(fields)) {
|
|
12461
12473
|
if (value === void 0) continue;
|
|
12462
|
-
Object.assign(bookmark, { [
|
|
12474
|
+
Object.assign(bookmark, { [key2]: value });
|
|
12463
12475
|
}
|
|
12464
12476
|
}
|
|
12465
|
-
function emit() {
|
|
12466
|
-
if (!state$
|
|
12467
|
-
const snapshot = cloneState(state$
|
|
12477
|
+
function emit$2() {
|
|
12478
|
+
if (!state$2) return;
|
|
12479
|
+
const snapshot = cloneState(state$2);
|
|
12468
12480
|
for (const listener of listeners) {
|
|
12469
12481
|
listener(snapshot);
|
|
12470
12482
|
}
|
|
@@ -12483,7 +12495,7 @@ function getBookmarkDescription(bookmark) {
|
|
|
12483
12495
|
bookmark.intent ? `Intent: ${bookmark.intent}` : "",
|
|
12484
12496
|
bookmark.expectedContent ? `Expected content: ${bookmark.expectedContent}` : "",
|
|
12485
12497
|
bookmark.keyFields?.length ? `Key fields: ${bookmark.keyFields.join(", ")}` : "",
|
|
12486
|
-
bookmark.agentHints && Object.keys(bookmark.agentHints).length > 0 ? `Agent hints: ${Object.entries(bookmark.agentHints).map(([
|
|
12498
|
+
bookmark.agentHints && Object.keys(bookmark.agentHints).length > 0 ? `Agent hints: ${Object.entries(bookmark.agentHints).map(([key2, value]) => `${key2}: ${value}`).join("; ")}` : ""
|
|
12487
12499
|
].filter(Boolean);
|
|
12488
12500
|
return lines.join("\n");
|
|
12489
12501
|
}
|
|
@@ -12586,28 +12598,28 @@ function subscribe(listener) {
|
|
|
12586
12598
|
};
|
|
12587
12599
|
}
|
|
12588
12600
|
function clearAll() {
|
|
12589
|
-
state$
|
|
12590
|
-
save();
|
|
12591
|
-
emit();
|
|
12601
|
+
state$2 = { folders: [], bookmarks: [] };
|
|
12602
|
+
save$1();
|
|
12603
|
+
emit$2();
|
|
12592
12604
|
}
|
|
12593
12605
|
function getBookmark(id) {
|
|
12594
12606
|
load$1();
|
|
12595
|
-
const bookmark = state$
|
|
12607
|
+
const bookmark = state$2.bookmarks.find((item) => item.id === id);
|
|
12596
12608
|
return bookmark ? { ...bookmark } : null;
|
|
12597
12609
|
}
|
|
12598
12610
|
function getBookmarkByUrl(url) {
|
|
12599
12611
|
load$1();
|
|
12600
12612
|
const normalized = url.trim();
|
|
12601
12613
|
if (!normalized) return null;
|
|
12602
|
-
const bookmark = [...state$
|
|
12614
|
+
const bookmark = [...state$2.bookmarks].reverse().find((item) => item.url === normalized);
|
|
12603
12615
|
return bookmark ? { ...bookmark } : null;
|
|
12604
12616
|
}
|
|
12605
12617
|
function getBookmarkByUrlInFolder(url, folderId) {
|
|
12606
12618
|
load$1();
|
|
12607
12619
|
const normalizedUrl = url.trim();
|
|
12608
12620
|
if (!normalizedUrl) return null;
|
|
12609
|
-
const targetFolderId = folderId && folderId !== UNSORTED_ID ? state$
|
|
12610
|
-
const bookmark = [...state$
|
|
12621
|
+
const targetFolderId = folderId && folderId !== UNSORTED_ID ? state$2.folders.find((f) => f.id === folderId)?.id ?? UNSORTED_ID : UNSORTED_ID;
|
|
12622
|
+
const bookmark = [...state$2.bookmarks].reverse().find(
|
|
12611
12623
|
(item) => item.url === normalizedUrl && item.folderId === targetFolderId
|
|
12612
12624
|
);
|
|
12613
12625
|
return bookmark ? { ...bookmark } : null;
|
|
@@ -12615,14 +12627,14 @@ function getBookmarkByUrlInFolder(url, folderId) {
|
|
|
12615
12627
|
function getFolder(id) {
|
|
12616
12628
|
load$1();
|
|
12617
12629
|
if (!id || id === UNSORTED_ID) return null;
|
|
12618
|
-
const folder = state$
|
|
12630
|
+
const folder = state$2.folders.find((item) => item.id === id);
|
|
12619
12631
|
return folder ? { ...folder } : null;
|
|
12620
12632
|
}
|
|
12621
12633
|
function findFolderByName(name) {
|
|
12622
12634
|
load$1();
|
|
12623
12635
|
const normalized = name.trim().toLowerCase();
|
|
12624
12636
|
if (!normalized || normalized === "unsorted") return null;
|
|
12625
|
-
const folder = state$
|
|
12637
|
+
const folder = state$2.folders.find(
|
|
12626
12638
|
(item) => item.name.trim().toLowerCase() === normalized
|
|
12627
12639
|
);
|
|
12628
12640
|
return folder ? { ...folder } : null;
|
|
@@ -12630,7 +12642,7 @@ function findFolderByName(name) {
|
|
|
12630
12642
|
function listFolderOverviews() {
|
|
12631
12643
|
load$1();
|
|
12632
12644
|
const counts = /* @__PURE__ */ new Map();
|
|
12633
|
-
for (const bookmark of state$
|
|
12645
|
+
for (const bookmark of state$2.bookmarks) {
|
|
12634
12646
|
counts.set(bookmark.folderId, (counts.get(bookmark.folderId) ?? 0) + 1);
|
|
12635
12647
|
}
|
|
12636
12648
|
return [
|
|
@@ -12639,7 +12651,7 @@ function listFolderOverviews() {
|
|
|
12639
12651
|
name: "Unsorted",
|
|
12640
12652
|
count: counts.get(UNSORTED_ID) ?? 0
|
|
12641
12653
|
},
|
|
12642
|
-
...state$
|
|
12654
|
+
...state$2.folders.map((folder) => ({
|
|
12643
12655
|
id: folder.id,
|
|
12644
12656
|
name: folder.name,
|
|
12645
12657
|
summary: folder.summary,
|
|
@@ -12650,8 +12662,8 @@ function listFolderOverviews() {
|
|
|
12650
12662
|
function searchBookmarks(query) {
|
|
12651
12663
|
load$1();
|
|
12652
12664
|
if (!query.trim()) return [];
|
|
12653
|
-
return state$
|
|
12654
|
-
const folder = state$
|
|
12665
|
+
return state$2.bookmarks.map((bookmark) => {
|
|
12666
|
+
const folder = state$2.folders.find(
|
|
12655
12667
|
(item) => item.id === bookmark.folderId
|
|
12656
12668
|
);
|
|
12657
12669
|
const { matchedFields, score } = getBookmarkSearchMatch({
|
|
@@ -12689,9 +12701,9 @@ function createFolderWithSummary(name, summary) {
|
|
|
12689
12701
|
summary: summary?.trim() || void 0,
|
|
12690
12702
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
12691
12703
|
};
|
|
12692
|
-
state$
|
|
12693
|
-
save();
|
|
12694
|
-
emit();
|
|
12704
|
+
state$2.folders.push(folder);
|
|
12705
|
+
save$1();
|
|
12706
|
+
emit$2();
|
|
12695
12707
|
return folder;
|
|
12696
12708
|
}
|
|
12697
12709
|
function ensureFolder(name, summary) {
|
|
@@ -12720,7 +12732,7 @@ function saveBookmarkWithPolicy(url, title, folderId, note, options) {
|
|
|
12720
12732
|
throw new Error("Bookmark URL cannot be empty");
|
|
12721
12733
|
}
|
|
12722
12734
|
const normalizedTitle = title.trim() || normalizedUrl;
|
|
12723
|
-
const targetId = folderId && folderId !== UNSORTED_ID ? state$
|
|
12735
|
+
const targetId = folderId && folderId !== UNSORTED_ID ? state$2.folders.find((f) => f.id === folderId)?.id ?? UNSORTED_ID : UNSORTED_ID;
|
|
12724
12736
|
const duplicatePolicy = options?.onDuplicate ?? "ask";
|
|
12725
12737
|
const existing = getBookmarkByUrlInFolder(normalizedUrl, targetId);
|
|
12726
12738
|
if (existing) {
|
|
@@ -12731,7 +12743,7 @@ function saveBookmarkWithPolicy(url, title, folderId, note, options) {
|
|
|
12731
12743
|
};
|
|
12732
12744
|
}
|
|
12733
12745
|
if (duplicatePolicy === "update") {
|
|
12734
|
-
const bookmark2 = state$
|
|
12746
|
+
const bookmark2 = state$2.bookmarks.find((item) => item.id === existing.id);
|
|
12735
12747
|
if (!bookmark2) {
|
|
12736
12748
|
return {
|
|
12737
12749
|
status: "conflict",
|
|
@@ -12744,8 +12756,8 @@ function saveBookmarkWithPolicy(url, title, folderId, note, options) {
|
|
|
12744
12756
|
}
|
|
12745
12757
|
assignDefinedBookmarkFields(bookmark2, options?.extra);
|
|
12746
12758
|
bookmark2.savedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
12747
|
-
save();
|
|
12748
|
-
emit();
|
|
12759
|
+
save$1();
|
|
12760
|
+
emit$2();
|
|
12749
12761
|
return {
|
|
12750
12762
|
status: "updated",
|
|
12751
12763
|
bookmark: { ...bookmark2 }
|
|
@@ -12761,9 +12773,9 @@ function saveBookmarkWithPolicy(url, title, folderId, note, options) {
|
|
|
12761
12773
|
savedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12762
12774
|
...options?.extra
|
|
12763
12775
|
};
|
|
12764
|
-
state$
|
|
12765
|
-
save();
|
|
12766
|
-
emit();
|
|
12776
|
+
state$2.bookmarks.push(bookmark);
|
|
12777
|
+
save$1();
|
|
12778
|
+
emit$2();
|
|
12767
12779
|
return {
|
|
12768
12780
|
status: "created",
|
|
12769
12781
|
bookmark
|
|
@@ -12771,18 +12783,18 @@ function saveBookmarkWithPolicy(url, title, folderId, note, options) {
|
|
|
12771
12783
|
}
|
|
12772
12784
|
function removeBookmark(id) {
|
|
12773
12785
|
load$1();
|
|
12774
|
-
const before = state$
|
|
12775
|
-
state$
|
|
12776
|
-
if (state$
|
|
12777
|
-
save();
|
|
12778
|
-
emit();
|
|
12786
|
+
const before = state$2.bookmarks.length;
|
|
12787
|
+
state$2.bookmarks = state$2.bookmarks.filter((b) => b.id !== id);
|
|
12788
|
+
if (state$2.bookmarks.length !== before) {
|
|
12789
|
+
save$1();
|
|
12790
|
+
emit$2();
|
|
12779
12791
|
return true;
|
|
12780
12792
|
}
|
|
12781
12793
|
return false;
|
|
12782
12794
|
}
|
|
12783
12795
|
function updateBookmark(id, updates) {
|
|
12784
12796
|
load$1();
|
|
12785
|
-
const bookmark = state$
|
|
12797
|
+
const bookmark = state$2.bookmarks.find((item) => item.id === id);
|
|
12786
12798
|
if (!bookmark) return null;
|
|
12787
12799
|
const metadataUpdates = normalizeBookmarkMetadataUpdate({
|
|
12788
12800
|
intent: updates.intent,
|
|
@@ -12799,7 +12811,7 @@ function updateBookmark(id, updates) {
|
|
|
12799
12811
|
bookmark.note = trimmed || void 0;
|
|
12800
12812
|
}
|
|
12801
12813
|
if (typeof updates.folderId === "string") {
|
|
12802
|
-
bookmark.folderId = updates.folderId && updates.folderId !== UNSORTED_ID ? state$
|
|
12814
|
+
bookmark.folderId = updates.folderId && updates.folderId !== UNSORTED_ID ? state$2.folders.find((item) => item.id === updates.folderId)?.id ?? UNSORTED_ID : UNSORTED_ID;
|
|
12803
12815
|
}
|
|
12804
12816
|
if ("intent" in metadataUpdates) {
|
|
12805
12817
|
bookmark.intent = metadataUpdates.intent;
|
|
@@ -12816,36 +12828,36 @@ function updateBookmark(id, updates) {
|
|
|
12816
12828
|
if ("agentHints" in metadataUpdates) {
|
|
12817
12829
|
bookmark.agentHints = metadataUpdates.agentHints;
|
|
12818
12830
|
}
|
|
12819
|
-
save();
|
|
12820
|
-
emit();
|
|
12831
|
+
save$1();
|
|
12832
|
+
emit$2();
|
|
12821
12833
|
return { ...bookmark };
|
|
12822
12834
|
}
|
|
12823
12835
|
function removeFolder(id, deleteContents = false) {
|
|
12824
12836
|
load$1();
|
|
12825
|
-
const exists = state$
|
|
12837
|
+
const exists = state$2.folders.some((f) => f.id === id);
|
|
12826
12838
|
if (!exists) return false;
|
|
12827
12839
|
if (deleteContents) {
|
|
12828
|
-
state$
|
|
12840
|
+
state$2.bookmarks = state$2.bookmarks.filter((b) => b.folderId !== id);
|
|
12829
12841
|
} else {
|
|
12830
|
-
state$
|
|
12842
|
+
state$2.bookmarks = state$2.bookmarks.map(
|
|
12831
12843
|
(b) => b.folderId === id ? { ...b, folderId: UNSORTED_ID } : b
|
|
12832
12844
|
);
|
|
12833
12845
|
}
|
|
12834
|
-
state$
|
|
12835
|
-
save();
|
|
12836
|
-
emit();
|
|
12846
|
+
state$2.folders = state$2.folders.filter((f) => f.id !== id);
|
|
12847
|
+
save$1();
|
|
12848
|
+
emit$2();
|
|
12837
12849
|
return true;
|
|
12838
12850
|
}
|
|
12839
12851
|
function renameFolder(id, newName, summary) {
|
|
12840
12852
|
load$1();
|
|
12841
|
-
const folder = state$
|
|
12853
|
+
const folder = state$2.folders.find((f) => f.id === id);
|
|
12842
12854
|
if (!folder) return null;
|
|
12843
12855
|
const trimmed = newName.trim();
|
|
12844
12856
|
if (!trimmed) return null;
|
|
12845
12857
|
folder.name = trimmed;
|
|
12846
12858
|
folder.summary = summary?.trim() || void 0;
|
|
12847
|
-
save();
|
|
12848
|
-
emit();
|
|
12859
|
+
save$1();
|
|
12860
|
+
emit$2();
|
|
12849
12861
|
return { ...folder };
|
|
12850
12862
|
}
|
|
12851
12863
|
function flushPersist$1() {
|
|
@@ -12856,7 +12868,7 @@ function importBookmarksFromHtml(content) {
|
|
|
12856
12868
|
let skipped = 0;
|
|
12857
12869
|
let errors = 0;
|
|
12858
12870
|
load$1();
|
|
12859
|
-
const existingUrls = new Set(state$
|
|
12871
|
+
const existingUrls = new Set(state$2.bookmarks.map((b) => b.url));
|
|
12860
12872
|
let currentFolderId = UNSORTED_ID;
|
|
12861
12873
|
let currentFolderName = "Imported";
|
|
12862
12874
|
const lines = content.split("\n");
|
|
@@ -12865,7 +12877,7 @@ function importBookmarksFromHtml(content) {
|
|
|
12865
12877
|
const folderMatch = line.match(/<DT><H3[^>]*>([^<]+)<\/H3>/i);
|
|
12866
12878
|
if (folderMatch) {
|
|
12867
12879
|
currentFolderName = folderMatch[1].trim();
|
|
12868
|
-
const existing = state$
|
|
12880
|
+
const existing = state$2.folders.find(
|
|
12869
12881
|
(f) => f.name.toLowerCase() === currentFolderName.toLowerCase()
|
|
12870
12882
|
);
|
|
12871
12883
|
if (existing) {
|
|
@@ -12876,7 +12888,7 @@ function importBookmarksFromHtml(content) {
|
|
|
12876
12888
|
name: currentFolderName,
|
|
12877
12889
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
12878
12890
|
};
|
|
12879
|
-
state$
|
|
12891
|
+
state$2.folders.push(folder);
|
|
12880
12892
|
currentFolderId = folder.id;
|
|
12881
12893
|
}
|
|
12882
12894
|
continue;
|
|
@@ -12897,7 +12909,7 @@ function importBookmarksFromHtml(content) {
|
|
|
12897
12909
|
else errors++;
|
|
12898
12910
|
continue;
|
|
12899
12911
|
}
|
|
12900
|
-
state$
|
|
12912
|
+
state$2.bookmarks.push({
|
|
12901
12913
|
id: crypto$1.randomUUID(),
|
|
12902
12914
|
url,
|
|
12903
12915
|
title,
|
|
@@ -12909,8 +12921,8 @@ function importBookmarksFromHtml(content) {
|
|
|
12909
12921
|
}
|
|
12910
12922
|
}
|
|
12911
12923
|
if (imported > 0) {
|
|
12912
|
-
save();
|
|
12913
|
-
emit();
|
|
12924
|
+
save$1();
|
|
12925
|
+
emit$2();
|
|
12914
12926
|
}
|
|
12915
12927
|
return { imported, skipped, errors };
|
|
12916
12928
|
}
|
|
@@ -12923,14 +12935,14 @@ function importBookmarksFromJson(content) {
|
|
|
12923
12935
|
const incomingFolders = Array.isArray(parsed?.folders) ? parsed.folders : [];
|
|
12924
12936
|
const incomingBookmarks = Array.isArray(parsed?.bookmarks) ? parsed.bookmarks : [];
|
|
12925
12937
|
load$1();
|
|
12926
|
-
const existingUrls = new Set(state$
|
|
12938
|
+
const existingUrls = new Set(state$2.bookmarks.map((b) => b.url));
|
|
12927
12939
|
const folderIdMap = /* @__PURE__ */ new Map();
|
|
12928
12940
|
for (const folder of incomingFolders) {
|
|
12929
12941
|
if (!folder?.id || !folder?.name) {
|
|
12930
12942
|
errors++;
|
|
12931
12943
|
continue;
|
|
12932
12944
|
}
|
|
12933
|
-
const existing = state$
|
|
12945
|
+
const existing = state$2.folders.find(
|
|
12934
12946
|
(f) => f.name.toLowerCase() === folder.name.toLowerCase()
|
|
12935
12947
|
);
|
|
12936
12948
|
if (existing) {
|
|
@@ -12942,7 +12954,7 @@ function importBookmarksFromJson(content) {
|
|
|
12942
12954
|
summary: folder.summary?.trim() || void 0,
|
|
12943
12955
|
createdAt: folder.createdAt || (/* @__PURE__ */ new Date()).toISOString()
|
|
12944
12956
|
};
|
|
12945
|
-
state$
|
|
12957
|
+
state$2.folders.push(newFolder);
|
|
12946
12958
|
folderIdMap.set(folder.id, newFolder.id);
|
|
12947
12959
|
}
|
|
12948
12960
|
}
|
|
@@ -12956,7 +12968,7 @@ function importBookmarksFromJson(content) {
|
|
|
12956
12968
|
continue;
|
|
12957
12969
|
}
|
|
12958
12970
|
const mappedFolderId = bookmark.folderId ? folderIdMap.get(bookmark.folderId) ?? UNSORTED_ID : UNSORTED_ID;
|
|
12959
|
-
state$
|
|
12971
|
+
state$2.bookmarks.push({
|
|
12960
12972
|
id: crypto$1.randomUUID(),
|
|
12961
12973
|
url: bookmark.url.trim(),
|
|
12962
12974
|
title: typeof bookmark.title === "string" ? bookmark.title.trim() : bookmark.url,
|
|
@@ -12968,8 +12980,8 @@ function importBookmarksFromJson(content) {
|
|
|
12968
12980
|
imported++;
|
|
12969
12981
|
}
|
|
12970
12982
|
if (imported > 0 || errors > 0) {
|
|
12971
|
-
save();
|
|
12972
|
-
emit();
|
|
12983
|
+
save$1();
|
|
12984
|
+
emit$2();
|
|
12973
12985
|
}
|
|
12974
12986
|
} catch {
|
|
12975
12987
|
errors++;
|
|
@@ -13013,9 +13025,9 @@ async function captureLiveHighlightSnapshot(wc, savedHighlights = []) {
|
|
|
13013
13025
|
text: normalizeText(highlight.text),
|
|
13014
13026
|
color: highlight.color?.trim() || void 0
|
|
13015
13027
|
})).filter((highlight) => highlight.text.length > 0).filter((highlight) => {
|
|
13016
|
-
const
|
|
13017
|
-
if (seen.has(
|
|
13018
|
-
seen.add(
|
|
13028
|
+
const key2 = `${highlight.text}\0${highlight.color ?? ""}`;
|
|
13029
|
+
if (seen.has(key2)) return false;
|
|
13030
|
+
seen.add(key2);
|
|
13019
13031
|
return true;
|
|
13020
13032
|
}).map((highlight) => ({
|
|
13021
13033
|
...highlight,
|
|
@@ -13364,17 +13376,17 @@ function sessionFileName(name) {
|
|
|
13364
13376
|
function getSessionPath(name) {
|
|
13365
13377
|
return path$1.join(ensureSessionsDir(), sessionFileName(name));
|
|
13366
13378
|
}
|
|
13367
|
-
function writeSessionFile(
|
|
13379
|
+
function writeSessionFile(filePath2, data) {
|
|
13368
13380
|
fs$1.writeFileSync(
|
|
13369
|
-
|
|
13381
|
+
filePath2,
|
|
13370
13382
|
JSON.stringify({ version: SESSION_VERSION, ...data }, null, 2),
|
|
13371
13383
|
{ encoding: "utf-8", mode: 384 }
|
|
13372
13384
|
);
|
|
13373
|
-
fs$1.chmodSync(
|
|
13385
|
+
fs$1.chmodSync(filePath2, 384);
|
|
13374
13386
|
}
|
|
13375
|
-
function readSessionFile(
|
|
13387
|
+
function readSessionFile(filePath2) {
|
|
13376
13388
|
try {
|
|
13377
|
-
const raw = fs$1.readFileSync(
|
|
13389
|
+
const raw = fs$1.readFileSync(filePath2, "utf-8");
|
|
13378
13390
|
const parsed = JSON.parse(raw);
|
|
13379
13391
|
if (!parsed || typeof parsed.name !== "string") {
|
|
13380
13392
|
return null;
|
|
@@ -13595,9 +13607,9 @@ async function loadNamedSession(tabManager, name) {
|
|
|
13595
13607
|
};
|
|
13596
13608
|
}
|
|
13597
13609
|
function deleteNamedSession(name) {
|
|
13598
|
-
const
|
|
13599
|
-
if (!fs$1.existsSync(
|
|
13600
|
-
fs$1.unlinkSync(
|
|
13610
|
+
const filePath2 = getSessionPath(name);
|
|
13611
|
+
if (!fs$1.existsSync(filePath2)) return false;
|
|
13612
|
+
fs$1.unlinkSync(filePath2);
|
|
13601
13613
|
return true;
|
|
13602
13614
|
}
|
|
13603
13615
|
function isInvalidTextTargetQuery(rawQuery) {
|
|
@@ -15054,9 +15066,9 @@ function isAddToCartText(text) {
|
|
|
15054
15066
|
}
|
|
15055
15067
|
function recordCartClick(url, text) {
|
|
15056
15068
|
recentCartClicks.set(url, { text, ts: Date.now() });
|
|
15057
|
-
for (const [
|
|
15069
|
+
for (const [key2, entry] of recentCartClicks) {
|
|
15058
15070
|
if (Date.now() - entry.ts > CART_CLICK_COOLDOWN_MS) {
|
|
15059
|
-
recentCartClicks.delete(
|
|
15071
|
+
recentCartClicks.delete(key2);
|
|
15060
15072
|
}
|
|
15061
15073
|
}
|
|
15062
15074
|
}
|
|
@@ -15103,9 +15115,9 @@ function normalizeCartProductKey(url) {
|
|
|
15103
15115
|
}
|
|
15104
15116
|
}
|
|
15105
15117
|
function pruneCartAddedProducts(now = Date.now()) {
|
|
15106
|
-
for (const [
|
|
15118
|
+
for (const [key2, entry] of cartAddedProducts) {
|
|
15107
15119
|
if (now - entry.ts > CART_ADDED_TTL_MS) {
|
|
15108
|
-
cartAddedProducts.delete(
|
|
15120
|
+
cartAddedProducts.delete(key2);
|
|
15109
15121
|
}
|
|
15110
15122
|
}
|
|
15111
15123
|
}
|
|
@@ -15131,7 +15143,7 @@ function isProductAlreadyInCart(url) {
|
|
|
15131
15143
|
function getCartAddedSummary(url) {
|
|
15132
15144
|
pruneCartAddedProducts();
|
|
15133
15145
|
const origin = cartOrigin(url);
|
|
15134
|
-
const items = Array.from(cartAddedProducts.entries()).filter(([
|
|
15146
|
+
const items = Array.from(cartAddedProducts.entries()).filter(([key2]) => !origin || key2.startsWith(`${origin}/`)).map(([_path, info]) => `- ${info.title}`).join("\n");
|
|
15135
15147
|
if (!items) return "";
|
|
15136
15148
|
const count = items.split("\n").length;
|
|
15137
15149
|
return `
|
|
@@ -16787,8 +16799,8 @@ async function submitForm(wc, args) {
|
|
|
16787
16799
|
}
|
|
16788
16800
|
return "Submitted form";
|
|
16789
16801
|
}
|
|
16790
|
-
async function pressKeyDirect(wc,
|
|
16791
|
-
return pressKey(wc, { key, index, selector });
|
|
16802
|
+
async function pressKeyDirect(wc, key2, index, selector) {
|
|
16803
|
+
return pressKey(wc, { key: key2, index, selector });
|
|
16792
16804
|
}
|
|
16793
16805
|
async function submitFormDirect(wc, index, selector) {
|
|
16794
16806
|
return submitForm(wc, { index, selector });
|
|
@@ -17154,8 +17166,8 @@ async function searchPage(wc, args) {
|
|
|
17154
17166
|
return `Searched "${query}" (same page — results may have loaded dynamically)${await getPostSearchSummary(wc)}`;
|
|
17155
17167
|
}
|
|
17156
17168
|
async function pressKey(wc, args) {
|
|
17157
|
-
const
|
|
17158
|
-
if (!
|
|
17169
|
+
const key2 = typeof args.key === "string" ? args.key.trim() : "";
|
|
17170
|
+
if (!key2) return "Error: No key provided";
|
|
17159
17171
|
const selector = await resolveSelector(wc, args.index, args.selector);
|
|
17160
17172
|
const focusResult = await executePageScript(
|
|
17161
17173
|
wc,
|
|
@@ -17193,16 +17205,16 @@ async function pressKey(wc, args) {
|
|
|
17193
17205
|
return focusResult.error;
|
|
17194
17206
|
}
|
|
17195
17207
|
wc.focus();
|
|
17196
|
-
const normalizedKey =
|
|
17208
|
+
const normalizedKey = key2.length === 1 ? key2 : key2[0].toUpperCase() + key2.slice(1);
|
|
17197
17209
|
const electronKeyCode = normalizedKey === "Enter" ? "Return" : normalizedKey === "ArrowUp" ? "Up" : normalizedKey === "ArrowDown" ? "Down" : normalizedKey === "ArrowLeft" ? "Left" : normalizedKey === "ArrowRight" ? "Right" : normalizedKey;
|
|
17198
17210
|
wc.sendInputEvent({ type: "keyDown", keyCode: electronKeyCode });
|
|
17199
|
-
if (
|
|
17200
|
-
wc.sendInputEvent({ type: "char", keyCode:
|
|
17211
|
+
if (key2.length === 1) {
|
|
17212
|
+
wc.sendInputEvent({ type: "char", keyCode: key2 });
|
|
17201
17213
|
}
|
|
17202
17214
|
await sleep(16);
|
|
17203
17215
|
wc.sendInputEvent({ type: "keyUp", keyCode: electronKeyCode });
|
|
17204
17216
|
const label = "label" in focusResult && typeof focusResult.label === "string" ? focusResult.label : null;
|
|
17205
|
-
return label ? `Pressed key: ${
|
|
17217
|
+
return label ? `Pressed key: ${key2} on ${label}` : `Pressed key: ${key2}`;
|
|
17206
17218
|
}
|
|
17207
17219
|
async function getPostActionState$1(ctx, name) {
|
|
17208
17220
|
const tab = ctx.tabManager.getActiveTab();
|
|
@@ -17612,8 +17624,8 @@ async function executeAction(name, args, ctx) {
|
|
|
17612
17624
|
if (!wc) return "Error: No active tab";
|
|
17613
17625
|
const beforeUrl = wc.getURL();
|
|
17614
17626
|
const result2 = await pressKey(wc, args);
|
|
17615
|
-
const
|
|
17616
|
-
if (
|
|
17627
|
+
const key2 = typeof args.key === "string" ? args.key.trim() : "";
|
|
17628
|
+
if (key2 === "Enter") {
|
|
17617
17629
|
await waitForPotentialNavigation(wc, beforeUrl, 3e3);
|
|
17618
17630
|
const afterUrl = wc.getURL();
|
|
17619
17631
|
if (afterUrl !== beforeUrl) {
|
|
@@ -18718,17 +18730,17 @@ function escapeYaml(value) {
|
|
|
18718
18730
|
}
|
|
18719
18731
|
function renderFrontmatter(data) {
|
|
18720
18732
|
const lines = ["---"];
|
|
18721
|
-
for (const [
|
|
18733
|
+
for (const [key2, value] of Object.entries(data)) {
|
|
18722
18734
|
if (value == null) continue;
|
|
18723
18735
|
if (Array.isArray(value)) {
|
|
18724
18736
|
if (value.length === 0) continue;
|
|
18725
|
-
lines.push(`${
|
|
18737
|
+
lines.push(`${key2}:`);
|
|
18726
18738
|
for (const item of value) {
|
|
18727
18739
|
lines.push(` - ${escapeYaml(item)}`);
|
|
18728
18740
|
}
|
|
18729
18741
|
continue;
|
|
18730
18742
|
}
|
|
18731
|
-
lines.push(`${
|
|
18743
|
+
lines.push(`${key2}: ${escapeYaml(value)}`);
|
|
18732
18744
|
}
|
|
18733
18745
|
lines.push("---", "");
|
|
18734
18746
|
return lines.join("\n");
|
|
@@ -18781,11 +18793,11 @@ function parseFrontmatter(content) {
|
|
|
18781
18793
|
activeArrayKey = "";
|
|
18782
18794
|
const separatorIndex = trimmed.indexOf(":");
|
|
18783
18795
|
if (separatorIndex === -1) continue;
|
|
18784
|
-
const
|
|
18796
|
+
const key2 = trimmed.slice(0, separatorIndex).trim();
|
|
18785
18797
|
const value = trimmed.slice(separatorIndex + 1).trim();
|
|
18786
|
-
if (
|
|
18798
|
+
if (key2 === "title" && value) {
|
|
18787
18799
|
result.title = value.replace(/^["']|["']$/g, "");
|
|
18788
|
-
} else if (
|
|
18800
|
+
} else if (key2 === "tags") {
|
|
18789
18801
|
activeArrayKey = "tags";
|
|
18790
18802
|
if (value.startsWith("[") && value.endsWith("]")) {
|
|
18791
18803
|
const inline = value.slice(1, -1).split(",").map((item) => item.trim().replace(/^["']|["']$/g, "")).filter(Boolean);
|
|
@@ -19371,15 +19383,15 @@ Exception: ${result.exceptionDetails}`);
|
|
|
19371
19383
|
value: zod.z.string().nullable().describe("Value to set, or null to remove the key")
|
|
19372
19384
|
}
|
|
19373
19385
|
},
|
|
19374
|
-
async ({ type, key, value }) => {
|
|
19386
|
+
async ({ type, key: key2, value }) => {
|
|
19375
19387
|
return withDevToolsAction(
|
|
19376
19388
|
runtime2,
|
|
19377
19389
|
tabManager,
|
|
19378
19390
|
"devtools_set_storage",
|
|
19379
|
-
{ type, key, value: value ? value.slice(0, 100) : null },
|
|
19391
|
+
{ type, key: key2, value: value ? value.slice(0, 100) : null },
|
|
19380
19392
|
async () => {
|
|
19381
19393
|
const session = getOrCreateSession(tabManager);
|
|
19382
|
-
return session.setStorage(type,
|
|
19394
|
+
return session.setStorage(type, key2, value);
|
|
19383
19395
|
}
|
|
19384
19396
|
);
|
|
19385
19397
|
}
|
|
@@ -19471,11 +19483,11 @@ function getOrCreateEncryptionKey(keyFilename) {
|
|
|
19471
19483
|
const encryptedKey = fs$1.readFileSync(keyPath);
|
|
19472
19484
|
return Buffer.from(electron.safeStorage.decryptString(encryptedKey), "utf-8");
|
|
19473
19485
|
}
|
|
19474
|
-
const
|
|
19486
|
+
const key2 = crypto$2.randomBytes(32);
|
|
19475
19487
|
fs$1.mkdirSync(path$1.dirname(keyPath), { recursive: true });
|
|
19476
|
-
const encrypted = electron.safeStorage.encryptString(
|
|
19488
|
+
const encrypted = electron.safeStorage.encryptString(key2.toString("utf-8"));
|
|
19477
19489
|
fs$1.writeFileSync(keyPath, encrypted, { mode: 384 });
|
|
19478
|
-
return
|
|
19490
|
+
return key2;
|
|
19479
19491
|
}
|
|
19480
19492
|
function createEncryptDecrypt(keyFilename) {
|
|
19481
19493
|
let cachedKey = null;
|
|
@@ -19484,9 +19496,9 @@ function createEncryptDecrypt(keyFilename) {
|
|
|
19484
19496
|
return cachedKey;
|
|
19485
19497
|
}
|
|
19486
19498
|
function encrypt2(plaintext) {
|
|
19487
|
-
const
|
|
19499
|
+
const key2 = getKey();
|
|
19488
19500
|
const iv = crypto$2.randomBytes(IV_LENGTH);
|
|
19489
|
-
const cipher = crypto$2.createCipheriv(ALGORITHM,
|
|
19501
|
+
const cipher = crypto$2.createCipheriv(ALGORITHM, key2, iv, {
|
|
19490
19502
|
authTagLength: AUTH_TAG_LENGTH
|
|
19491
19503
|
});
|
|
19492
19504
|
const encrypted = Buffer.concat([
|
|
@@ -19497,11 +19509,11 @@ function createEncryptDecrypt(keyFilename) {
|
|
|
19497
19509
|
return Buffer.concat([iv, authTag, encrypted]);
|
|
19498
19510
|
}
|
|
19499
19511
|
function decrypt2(data) {
|
|
19500
|
-
const
|
|
19512
|
+
const key2 = getKey();
|
|
19501
19513
|
const iv = data.subarray(0, IV_LENGTH);
|
|
19502
19514
|
const authTag = data.subarray(IV_LENGTH, IV_LENGTH + AUTH_TAG_LENGTH);
|
|
19503
19515
|
const ciphertext = data.subarray(IV_LENGTH + AUTH_TAG_LENGTH);
|
|
19504
|
-
const decipher = crypto$2.createDecipheriv(ALGORITHM,
|
|
19516
|
+
const decipher = crypto$2.createDecipheriv(ALGORITHM, key2, iv, {
|
|
19505
19517
|
authTagLength: AUTH_TAG_LENGTH
|
|
19506
19518
|
});
|
|
19507
19519
|
decipher.setAuthTag(authTag);
|
|
@@ -19938,10 +19950,10 @@ function getPersistentMcpAuthToken() {
|
|
|
19938
19950
|
}
|
|
19939
19951
|
function writeMcpAuthFile(endpoint, token) {
|
|
19940
19952
|
try {
|
|
19941
|
-
const
|
|
19942
|
-
fs$1.mkdirSync(path$1.dirname(
|
|
19953
|
+
const filePath2 = getMcpAuthFilePath();
|
|
19954
|
+
fs$1.mkdirSync(path$1.dirname(filePath2), { recursive: true });
|
|
19943
19955
|
fs$1.writeFileSync(
|
|
19944
|
-
|
|
19956
|
+
filePath2,
|
|
19945
19957
|
JSON.stringify({ endpoint, token, pid: process.pid }, null, 2) + "\n",
|
|
19946
19958
|
{ mode: 384 }
|
|
19947
19959
|
);
|
|
@@ -19959,10 +19971,10 @@ function clearMcpAuthFile() {
|
|
|
19959
19971
|
return;
|
|
19960
19972
|
}
|
|
19961
19973
|
try {
|
|
19962
|
-
const
|
|
19963
|
-
fs$1.mkdirSync(path$1.dirname(
|
|
19974
|
+
const filePath2 = getMcpAuthFilePath();
|
|
19975
|
+
fs$1.mkdirSync(path$1.dirname(filePath2), { recursive: true });
|
|
19964
19976
|
fs$1.writeFileSync(
|
|
19965
|
-
|
|
19977
|
+
filePath2,
|
|
19966
19978
|
JSON.stringify(
|
|
19967
19979
|
{ endpoint: "", token: existingToken, pid: null },
|
|
19968
19980
|
null,
|
|
@@ -20978,19 +20990,19 @@ ${buildScopedContext(pageContent, mode)}`;
|
|
|
20978
20990
|
selector: zod.z.string().optional().describe("CSS selector to focus first")
|
|
20979
20991
|
}
|
|
20980
20992
|
},
|
|
20981
|
-
async ({ key, index, selector }) => {
|
|
20993
|
+
async ({ key: key2, index, selector }) => {
|
|
20982
20994
|
const tab = tabManager.getActiveTab();
|
|
20983
20995
|
if (!tab) return asNoActiveTabResponse();
|
|
20984
20996
|
return withAction(
|
|
20985
20997
|
runtime2,
|
|
20986
20998
|
tabManager,
|
|
20987
20999
|
"press_key",
|
|
20988
|
-
{ key, index, selector },
|
|
21000
|
+
{ key: key2, index, selector },
|
|
20989
21001
|
async () => {
|
|
20990
21002
|
const wc = tab.view.webContents;
|
|
20991
21003
|
const beforeUrl = wc.getURL();
|
|
20992
|
-
const result = await pressKeyDirect(wc,
|
|
20993
|
-
if (
|
|
21004
|
+
const result = await pressKeyDirect(wc, key2, index, selector);
|
|
21005
|
+
if (key2 === "Enter") {
|
|
20994
21006
|
await waitForPotentialNavigation$1(wc, beforeUrl, 3e3);
|
|
20995
21007
|
const afterUrl = wc.getURL();
|
|
20996
21008
|
if (afterUrl !== beforeUrl) {
|
|
@@ -21456,7 +21468,7 @@ To analyze visually, call vision_analyze with image_url="${screenshotPath}"`
|
|
|
21456
21468
|
)
|
|
21457
21469
|
}
|
|
21458
21470
|
},
|
|
21459
|
-
async ({ index, selector, text, label, durationMs, persist, color }) => {
|
|
21471
|
+
async ({ index, selector, text, label, durationMs, persist: persist2, color }) => {
|
|
21460
21472
|
const tab = tabManager.getActiveTab();
|
|
21461
21473
|
if (!tab) return asNoActiveTabResponse();
|
|
21462
21474
|
const normalizedText = normalizeLooseString(text);
|
|
@@ -21470,7 +21482,7 @@ To analyze visually, call vision_analyze with image_url="${screenshotPath}"`
|
|
|
21470
21482
|
text: normalizedText,
|
|
21471
21483
|
label,
|
|
21472
21484
|
durationMs,
|
|
21473
|
-
persist,
|
|
21485
|
+
persist: persist2,
|
|
21474
21486
|
color
|
|
21475
21487
|
},
|
|
21476
21488
|
async () => {
|
|
@@ -21484,7 +21496,7 @@ To analyze visually, call vision_analyze with image_url="${screenshotPath}"`
|
|
|
21484
21496
|
durationMs,
|
|
21485
21497
|
color
|
|
21486
21498
|
);
|
|
21487
|
-
if (
|
|
21499
|
+
if (persist2 && !durationMs && !result.startsWith("Error") && !result.includes("not found")) {
|
|
21488
21500
|
const url = normalizeUrl$1(wc.getURL());
|
|
21489
21501
|
addHighlight(
|
|
21490
21502
|
url,
|
|
@@ -24149,7 +24161,7 @@ const PROFILE_FIELDS = [
|
|
|
24149
24161
|
"postalCode",
|
|
24150
24162
|
"country"
|
|
24151
24163
|
];
|
|
24152
|
-
let state = null;
|
|
24164
|
+
let state$1 = null;
|
|
24153
24165
|
function getFilePath() {
|
|
24154
24166
|
return path.join(electron.app.getPath("userData"), "vessel-autofill.json");
|
|
24155
24167
|
}
|
|
@@ -24174,8 +24186,8 @@ function normalizeStoredProfile(value) {
|
|
|
24174
24186
|
return profile;
|
|
24175
24187
|
}
|
|
24176
24188
|
function load() {
|
|
24177
|
-
if (state) return state;
|
|
24178
|
-
state = loadJsonFile({
|
|
24189
|
+
if (state$1) return state$1;
|
|
24190
|
+
state$1 = loadJsonFile({
|
|
24179
24191
|
filePath: getFilePath(),
|
|
24180
24192
|
fallback: getDefaultState(),
|
|
24181
24193
|
secure: true,
|
|
@@ -24186,12 +24198,12 @@ function load() {
|
|
|
24186
24198
|
};
|
|
24187
24199
|
}
|
|
24188
24200
|
});
|
|
24189
|
-
return state;
|
|
24201
|
+
return state$1;
|
|
24190
24202
|
}
|
|
24191
|
-
const persistence = createDebouncedJsonPersistence({
|
|
24203
|
+
const persistence$2 = createDebouncedJsonPersistence({
|
|
24192
24204
|
debounceMs: SAVE_DEBOUNCE_MS,
|
|
24193
24205
|
filePath: getFilePath(),
|
|
24194
|
-
getValue: () => state,
|
|
24206
|
+
getValue: () => state$1,
|
|
24195
24207
|
logLabel: "autofill",
|
|
24196
24208
|
secure: true
|
|
24197
24209
|
});
|
|
@@ -24211,7 +24223,7 @@ function addProfile(input) {
|
|
|
24211
24223
|
updatedAt: now
|
|
24212
24224
|
};
|
|
24213
24225
|
s.profiles.push(profile);
|
|
24214
|
-
persistence.schedule();
|
|
24226
|
+
persistence$2.schedule();
|
|
24215
24227
|
return profile;
|
|
24216
24228
|
}
|
|
24217
24229
|
function updateProfile(id, updates) {
|
|
@@ -24223,7 +24235,7 @@ function updateProfile(id, updates) {
|
|
|
24223
24235
|
...updates,
|
|
24224
24236
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
24225
24237
|
};
|
|
24226
|
-
persistence.schedule();
|
|
24238
|
+
persistence$2.schedule();
|
|
24227
24239
|
return s.profiles[idx];
|
|
24228
24240
|
}
|
|
24229
24241
|
function deleteProfile(id) {
|
|
@@ -24231,11 +24243,11 @@ function deleteProfile(id) {
|
|
|
24231
24243
|
const len = s.profiles.length;
|
|
24232
24244
|
s.profiles = s.profiles.filter((p) => p.id !== id);
|
|
24233
24245
|
if (s.profiles.length === len) return false;
|
|
24234
|
-
persistence.schedule();
|
|
24246
|
+
persistence$2.schedule();
|
|
24235
24247
|
return true;
|
|
24236
24248
|
}
|
|
24237
24249
|
function flushPersist() {
|
|
24238
|
-
return persistence.flush();
|
|
24250
|
+
return persistence$2.flush();
|
|
24239
24251
|
}
|
|
24240
24252
|
const AUTOCOMPLETE_MAP = {
|
|
24241
24253
|
"given-name": "firstName",
|
|
@@ -24364,12 +24376,12 @@ function matchField(el, profile) {
|
|
|
24364
24376
|
if (inputType === "hidden" || inputType === "submit" || inputType === "button" || inputType === "file" || inputType === "image") return null;
|
|
24365
24377
|
if (inputType === "password" || inputType === "checkbox" || inputType === "radio") return null;
|
|
24366
24378
|
if (el.autocomplete) {
|
|
24367
|
-
const
|
|
24368
|
-
if (
|
|
24379
|
+
const key2 = el.autocomplete.replace(/section-\w+\s+/, "").replace(/^shipping\s+|^billing\s+/, "");
|
|
24380
|
+
if (key2 === "name" || key2 === "additional-name") {
|
|
24369
24381
|
const fullName = getFullName(profile);
|
|
24370
24382
|
if (fullName) return mk(fullName, 100, "autocomplete", "fullName");
|
|
24371
24383
|
}
|
|
24372
|
-
const pk = AUTOCOMPLETE_MAP[
|
|
24384
|
+
const pk = AUTOCOMPLETE_MAP[key2];
|
|
24373
24385
|
if (pk && profile[pk]) return mk(profile[pk], 100, "autocomplete", pk);
|
|
24374
24386
|
}
|
|
24375
24387
|
if (INPUT_TYPE_MAP[inputType]) {
|
|
@@ -24857,6 +24869,64 @@ function installAdBlockingForSession(ses, tabManager) {
|
|
|
24857
24869
|
callback(getAdBlockDecision(details));
|
|
24858
24870
|
});
|
|
24859
24871
|
}
|
|
24872
|
+
const filePath$1 = () => path$1.join(electron.app.getPath("userData"), "vessel-downloads.json");
|
|
24873
|
+
function parse(raw) {
|
|
24874
|
+
if (!raw || typeof raw !== "object") return { items: [] };
|
|
24875
|
+
const items = Array.isArray(raw.items) ? raw.items : [];
|
|
24876
|
+
return { items };
|
|
24877
|
+
}
|
|
24878
|
+
let state = loadJsonFile({ filePath: filePath$1(), fallback: { items: [] }, parse });
|
|
24879
|
+
const persistence$1 = createDebouncedJsonPersistence({
|
|
24880
|
+
debounceMs: 250,
|
|
24881
|
+
filePath: filePath$1(),
|
|
24882
|
+
getValue: () => state,
|
|
24883
|
+
logLabel: "downloads"
|
|
24884
|
+
});
|
|
24885
|
+
let broadcaster$1 = null;
|
|
24886
|
+
function persist() {
|
|
24887
|
+
state.items = state.items.slice(0, 200);
|
|
24888
|
+
persistence$1.schedule();
|
|
24889
|
+
}
|
|
24890
|
+
function emit$1() {
|
|
24891
|
+
broadcaster$1?.(Channels.DOWNLOADS_UPDATE, state.items);
|
|
24892
|
+
}
|
|
24893
|
+
function setDownloadBroadcaster(fn) {
|
|
24894
|
+
broadcaster$1 = fn;
|
|
24895
|
+
}
|
|
24896
|
+
function listDownloads() {
|
|
24897
|
+
return state.items;
|
|
24898
|
+
}
|
|
24899
|
+
function upsertDownload(input) {
|
|
24900
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
24901
|
+
const existing = state.items.find((item) => item.savePath === input.savePath);
|
|
24902
|
+
if (existing) {
|
|
24903
|
+
Object.assign(existing, input, { updatedAt: now });
|
|
24904
|
+
persist();
|
|
24905
|
+
emit$1();
|
|
24906
|
+
return existing;
|
|
24907
|
+
}
|
|
24908
|
+
const record = { id: crypto$2.randomUUID(), ...input, startedAt: now, updatedAt: now };
|
|
24909
|
+
state.items = [record, ...state.items];
|
|
24910
|
+
persist();
|
|
24911
|
+
emit$1();
|
|
24912
|
+
return record;
|
|
24913
|
+
}
|
|
24914
|
+
function clearDownloads() {
|
|
24915
|
+
state.items = [];
|
|
24916
|
+
persist();
|
|
24917
|
+
emit$1();
|
|
24918
|
+
}
|
|
24919
|
+
async function openDownload(id) {
|
|
24920
|
+
const item = state.items.find((d) => d.id === id);
|
|
24921
|
+
if (!item || !fs$1.existsSync(item.savePath)) return false;
|
|
24922
|
+
return await electron.shell.openPath(item.savePath) === "";
|
|
24923
|
+
}
|
|
24924
|
+
async function showDownloadInFolder(id) {
|
|
24925
|
+
const item = state.items.find((d) => d.id === id);
|
|
24926
|
+
if (!item || !fs$1.existsSync(item.savePath)) return false;
|
|
24927
|
+
electron.shell.showItemInFolder(item.savePath);
|
|
24928
|
+
return true;
|
|
24929
|
+
}
|
|
24860
24930
|
const defaultDownloadViews = /* @__PURE__ */ new Set();
|
|
24861
24931
|
let defaultDownloadHandlerInstalled = false;
|
|
24862
24932
|
function resolveDownloadPath(downloadDir, filename) {
|
|
@@ -24903,17 +24973,20 @@ function installDownloadHandlerForSession(targetSession, chromeView) {
|
|
|
24903
24973
|
receivedBytes: 0,
|
|
24904
24974
|
state: "progressing"
|
|
24905
24975
|
};
|
|
24906
|
-
|
|
24976
|
+
const record = upsertDownload(info);
|
|
24977
|
+
send(Channels.DOWNLOAD_STARTED, { ...info, id: record.id, startedAt: record.startedAt, updatedAt: record.updatedAt });
|
|
24907
24978
|
item.on("updated", (_event2, state2) => {
|
|
24908
24979
|
info.receivedBytes = item.getReceivedBytes();
|
|
24909
24980
|
info.totalBytes = item.getTotalBytes();
|
|
24910
24981
|
info.state = state2 === "progressing" ? "progressing" : "interrupted";
|
|
24911
|
-
|
|
24982
|
+
const record2 = upsertDownload(info);
|
|
24983
|
+
send(Channels.DOWNLOAD_PROGRESS, { ...info, id: record2.id, startedAt: record2.startedAt, updatedAt: record2.updatedAt });
|
|
24912
24984
|
});
|
|
24913
24985
|
item.once("done", (_event2, state2) => {
|
|
24914
24986
|
info.receivedBytes = item.getReceivedBytes();
|
|
24915
24987
|
info.state = state2 === "completed" ? "completed" : "cancelled";
|
|
24916
|
-
|
|
24988
|
+
const record2 = upsertDownload(info);
|
|
24989
|
+
send(Channels.DOWNLOAD_DONE, { ...info, id: record2.id, startedAt: record2.startedAt, updatedAt: record2.updatedAt });
|
|
24917
24990
|
});
|
|
24918
24991
|
});
|
|
24919
24992
|
}
|
|
@@ -25627,35 +25700,35 @@ function registerBookmarkHandlers() {
|
|
|
25627
25700
|
electron.ipcMain.handle(
|
|
25628
25701
|
Channels.BOOKMARKS_EXPORT_HTML,
|
|
25629
25702
|
async (_, options) => {
|
|
25630
|
-
const { canceled, filePath } = await electron.dialog.showSaveDialog({
|
|
25703
|
+
const { canceled, filePath: filePath2 } = await electron.dialog.showSaveDialog({
|
|
25631
25704
|
title: "Export Bookmarks",
|
|
25632
25705
|
defaultPath: "vessel-bookmarks.html",
|
|
25633
25706
|
filters: [{ name: "HTML Bookmarks", extensions: ["html"] }]
|
|
25634
25707
|
});
|
|
25635
|
-
if (canceled || !
|
|
25708
|
+
if (canceled || !filePath2) return null;
|
|
25636
25709
|
const content = exportBookmarksHtml({
|
|
25637
25710
|
includeNotes: options?.includeNotes ?? false
|
|
25638
25711
|
});
|
|
25639
|
-
await fs.promises.writeFile(
|
|
25712
|
+
await fs.promises.writeFile(filePath2, content, "utf-8");
|
|
25640
25713
|
trackBookmarkAction("export");
|
|
25641
25714
|
return {
|
|
25642
|
-
filePath,
|
|
25715
|
+
filePath: filePath2,
|
|
25643
25716
|
count: getState().bookmarks.length
|
|
25644
25717
|
};
|
|
25645
25718
|
}
|
|
25646
25719
|
);
|
|
25647
25720
|
electron.ipcMain.handle(Channels.BOOKMARKS_EXPORT_JSON, async () => {
|
|
25648
|
-
const { canceled, filePath } = await electron.dialog.showSaveDialog({
|
|
25721
|
+
const { canceled, filePath: filePath2 } = await electron.dialog.showSaveDialog({
|
|
25649
25722
|
title: "Export Vessel Bookmark Archive",
|
|
25650
25723
|
defaultPath: "vessel-bookmarks.json",
|
|
25651
25724
|
filters: [{ name: "Vessel Bookmark Archive", extensions: ["json"] }]
|
|
25652
25725
|
});
|
|
25653
|
-
if (canceled || !
|
|
25726
|
+
if (canceled || !filePath2) return null;
|
|
25654
25727
|
const content = exportBookmarksJson();
|
|
25655
|
-
await fs.promises.writeFile(
|
|
25728
|
+
await fs.promises.writeFile(filePath2, content, "utf-8");
|
|
25656
25729
|
trackBookmarkAction("export");
|
|
25657
25730
|
return {
|
|
25658
|
-
filePath,
|
|
25731
|
+
filePath: filePath2,
|
|
25659
25732
|
count: getState().bookmarks.length
|
|
25660
25733
|
};
|
|
25661
25734
|
});
|
|
@@ -25664,20 +25737,20 @@ function registerBookmarkHandlers() {
|
|
|
25664
25737
|
async (_, folderId, options) => {
|
|
25665
25738
|
const folder = getFolder(folderId);
|
|
25666
25739
|
if (!folder) return null;
|
|
25667
|
-
const { canceled, filePath } = await electron.dialog.showSaveDialog({
|
|
25740
|
+
const { canceled, filePath: filePath2 } = await electron.dialog.showSaveDialog({
|
|
25668
25741
|
title: `Export ${folder.name}`,
|
|
25669
25742
|
defaultPath: `vessel-bookmarks-${getSafeBookmarkExportName(folder.name)}.html`,
|
|
25670
25743
|
filters: [{ name: "HTML Bookmarks", extensions: ["html"] }]
|
|
25671
25744
|
});
|
|
25672
|
-
if (canceled || !
|
|
25745
|
+
if (canceled || !filePath2) return null;
|
|
25673
25746
|
const result = exportBookmarkFolderHtml(folderId, {
|
|
25674
25747
|
includeNotes: options?.includeNotes ?? true
|
|
25675
25748
|
});
|
|
25676
25749
|
if (!result) return null;
|
|
25677
|
-
await fs.promises.writeFile(
|
|
25750
|
+
await fs.promises.writeFile(filePath2, result.content, "utf-8");
|
|
25678
25751
|
trackBookmarkAction("export");
|
|
25679
25752
|
return {
|
|
25680
|
-
filePath,
|
|
25753
|
+
filePath: filePath2,
|
|
25681
25754
|
count: result.count
|
|
25682
25755
|
};
|
|
25683
25756
|
}
|
|
@@ -25730,26 +25803,26 @@ function registerHistoryHandlers() {
|
|
|
25730
25803
|
clearAll$1();
|
|
25731
25804
|
});
|
|
25732
25805
|
electron.ipcMain.handle(Channels.HISTORY_EXPORT_HTML, async () => {
|
|
25733
|
-
const { canceled, filePath } = await electron.dialog.showSaveDialog({
|
|
25806
|
+
const { canceled, filePath: filePath2 } = await electron.dialog.showSaveDialog({
|
|
25734
25807
|
title: "Export History",
|
|
25735
25808
|
defaultPath: "vessel-history.html",
|
|
25736
25809
|
filters: [{ name: "HTML", extensions: ["html"] }]
|
|
25737
25810
|
});
|
|
25738
|
-
if (canceled || !
|
|
25811
|
+
if (canceled || !filePath2) return null;
|
|
25739
25812
|
const content = exportHistoryHtml();
|
|
25740
|
-
await fs.promises.writeFile(
|
|
25741
|
-
return { filePath, count: getState$1().entries.length };
|
|
25813
|
+
await fs.promises.writeFile(filePath2, content, "utf-8");
|
|
25814
|
+
return { filePath: filePath2, count: getState$1().entries.length };
|
|
25742
25815
|
});
|
|
25743
25816
|
electron.ipcMain.handle(Channels.HISTORY_EXPORT_JSON, async () => {
|
|
25744
|
-
const { canceled, filePath } = await electron.dialog.showSaveDialog({
|
|
25817
|
+
const { canceled, filePath: filePath2 } = await electron.dialog.showSaveDialog({
|
|
25745
25818
|
title: "Export History",
|
|
25746
25819
|
defaultPath: "vessel-history.json",
|
|
25747
25820
|
filters: [{ name: "JSON", extensions: ["json"] }]
|
|
25748
25821
|
});
|
|
25749
|
-
if (canceled || !
|
|
25822
|
+
if (canceled || !filePath2) return null;
|
|
25750
25823
|
const content = exportHistoryJson();
|
|
25751
|
-
await fs.promises.writeFile(
|
|
25752
|
-
return { filePath, count: getState$1().entries.length };
|
|
25824
|
+
await fs.promises.writeFile(filePath2, content, "utf-8");
|
|
25825
|
+
return { filePath: filePath2, count: getState$1().entries.length };
|
|
25753
25826
|
});
|
|
25754
25827
|
electron.ipcMain.handle(Channels.HISTORY_IMPORT, async () => {
|
|
25755
25828
|
const { canceled, filePaths } = await electron.dialog.showOpenDialog({
|
|
@@ -25760,9 +25833,9 @@ function registerHistoryHandlers() {
|
|
|
25760
25833
|
properties: ["openFile"]
|
|
25761
25834
|
});
|
|
25762
25835
|
if (canceled || filePaths.length === 0) return null;
|
|
25763
|
-
const
|
|
25764
|
-
const content = await fs.promises.readFile(
|
|
25765
|
-
const result =
|
|
25836
|
+
const filePath2 = filePaths[0];
|
|
25837
|
+
const content = await fs.promises.readFile(filePath2, "utf-8");
|
|
25838
|
+
const result = filePath2.endsWith(".json") ? importHistoryFromJson(content) : importHistoryFromHtml(content);
|
|
25766
25839
|
return result;
|
|
25767
25840
|
});
|
|
25768
25841
|
}
|
|
@@ -26036,6 +26109,119 @@ function registerCodexHandlers() {
|
|
|
26036
26109
|
return { ok: true };
|
|
26037
26110
|
});
|
|
26038
26111
|
}
|
|
26112
|
+
const filePath = () => path$1.join(electron.app.getPath("userData"), "vessel-permissions.json");
|
|
26113
|
+
let records = loadJsonFile({
|
|
26114
|
+
filePath: filePath(),
|
|
26115
|
+
fallback: [],
|
|
26116
|
+
parse: (raw) => Array.isArray(raw) ? raw : []
|
|
26117
|
+
});
|
|
26118
|
+
const persistence = createDebouncedJsonPersistence({ debounceMs: 250, filePath: filePath(), getValue: () => records, logLabel: "permissions" });
|
|
26119
|
+
let broadcaster = null;
|
|
26120
|
+
function key(origin, permission) {
|
|
26121
|
+
return `${origin}
|
|
26122
|
+
${permission}`;
|
|
26123
|
+
}
|
|
26124
|
+
function emit() {
|
|
26125
|
+
broadcaster?.(Channels.PERMISSIONS_GET, records);
|
|
26126
|
+
}
|
|
26127
|
+
function save(origin, permission, decision) {
|
|
26128
|
+
const k = key(origin, permission);
|
|
26129
|
+
const existing = records.find((r) => key(r.origin, r.permission) === k);
|
|
26130
|
+
const updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
26131
|
+
if (existing) Object.assign(existing, { decision, updatedAt });
|
|
26132
|
+
else records.unshift({ origin, permission, decision, updatedAt });
|
|
26133
|
+
persistence.schedule();
|
|
26134
|
+
emit();
|
|
26135
|
+
}
|
|
26136
|
+
function listPermissions() {
|
|
26137
|
+
return records;
|
|
26138
|
+
}
|
|
26139
|
+
function clearPermissions() {
|
|
26140
|
+
records = [];
|
|
26141
|
+
persistence.schedule();
|
|
26142
|
+
emit();
|
|
26143
|
+
}
|
|
26144
|
+
function clearPermissionsForOrigin(origin) {
|
|
26145
|
+
records = records.filter((record) => record.origin !== origin);
|
|
26146
|
+
persistence.schedule();
|
|
26147
|
+
emit();
|
|
26148
|
+
}
|
|
26149
|
+
function setPermissionBroadcaster(fn) {
|
|
26150
|
+
broadcaster = fn;
|
|
26151
|
+
}
|
|
26152
|
+
function installPermissionHandler() {
|
|
26153
|
+
electron.session.defaultSession.setPermissionRequestHandler((webContents, permission, callback, details) => {
|
|
26154
|
+
const origin = new URL(details.requestingUrl || webContents.getURL()).origin;
|
|
26155
|
+
const existing = records.find((r) => r.origin === origin && r.permission === permission);
|
|
26156
|
+
if (existing) {
|
|
26157
|
+
callback(existing.decision === "allow");
|
|
26158
|
+
return;
|
|
26159
|
+
}
|
|
26160
|
+
const result = electron.dialog.showMessageBoxSync({
|
|
26161
|
+
type: "question",
|
|
26162
|
+
buttons: ["Deny", "Allow"],
|
|
26163
|
+
defaultId: 0,
|
|
26164
|
+
cancelId: 0,
|
|
26165
|
+
title: "Site permission request",
|
|
26166
|
+
message: `${origin} wants to use ${permission}`,
|
|
26167
|
+
detail: "Vessel will remember your choice. You can clear saved permissions in Settings > Privacy."
|
|
26168
|
+
});
|
|
26169
|
+
const decision = result === 1 ? "allow" : "deny";
|
|
26170
|
+
save(origin, permission, decision);
|
|
26171
|
+
callback(decision === "allow");
|
|
26172
|
+
});
|
|
26173
|
+
}
|
|
26174
|
+
const NPM_PACKAGE_URL = "https://registry.npmjs.org/@quanta-intellect%2Fvessel-browser/latest";
|
|
26175
|
+
const RELEASES_URL = "https://github.com/unmodeled-tyler/quanta-vessel-browser/releases/latest";
|
|
26176
|
+
function normalizeVersion(version) {
|
|
26177
|
+
return version.replace(/^v/i, "").split(/[.-]/).slice(0, 3).map((part) => {
|
|
26178
|
+
const n = Number.parseInt(part, 10);
|
|
26179
|
+
return Number.isFinite(n) ? n : 0;
|
|
26180
|
+
});
|
|
26181
|
+
}
|
|
26182
|
+
function compareVersions(a, b) {
|
|
26183
|
+
const av = normalizeVersion(a);
|
|
26184
|
+
const bv = normalizeVersion(b);
|
|
26185
|
+
for (let i = 0; i < 3; i += 1) {
|
|
26186
|
+
if ((av[i] ?? 0) > (bv[i] ?? 0)) return 1;
|
|
26187
|
+
if ((av[i] ?? 0) < (bv[i] ?? 0)) return -1;
|
|
26188
|
+
}
|
|
26189
|
+
return 0;
|
|
26190
|
+
}
|
|
26191
|
+
async function checkForUpdates() {
|
|
26192
|
+
const currentVersion = electron.app.getVersion();
|
|
26193
|
+
const checkedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
26194
|
+
try {
|
|
26195
|
+
const response = await fetch(NPM_PACKAGE_URL, {
|
|
26196
|
+
headers: { accept: "application/json", "user-agent": `Vessel/${currentVersion}` }
|
|
26197
|
+
});
|
|
26198
|
+
if (!response.ok) {
|
|
26199
|
+
throw new Error(`Registry responded with ${response.status}`);
|
|
26200
|
+
}
|
|
26201
|
+
const body = await response.json();
|
|
26202
|
+
const latestVersion = typeof body.version === "string" ? body.version : null;
|
|
26203
|
+
if (!latestVersion) throw new Error("Registry response did not include a version");
|
|
26204
|
+
return {
|
|
26205
|
+
currentVersion,
|
|
26206
|
+
latestVersion,
|
|
26207
|
+
updateAvailable: compareVersions(latestVersion, currentVersion) > 0,
|
|
26208
|
+
checkedAt,
|
|
26209
|
+
releaseUrl: RELEASES_URL
|
|
26210
|
+
};
|
|
26211
|
+
} catch (error) {
|
|
26212
|
+
return {
|
|
26213
|
+
currentVersion,
|
|
26214
|
+
latestVersion: null,
|
|
26215
|
+
updateAvailable: false,
|
|
26216
|
+
checkedAt,
|
|
26217
|
+
releaseUrl: RELEASES_URL,
|
|
26218
|
+
error: error instanceof Error ? error.message : "Update check failed"
|
|
26219
|
+
};
|
|
26220
|
+
}
|
|
26221
|
+
}
|
|
26222
|
+
async function openUpdateDownload() {
|
|
26223
|
+
await electron.shell.openExternal(RELEASES_URL);
|
|
26224
|
+
}
|
|
26039
26225
|
let activeChatProvider = null;
|
|
26040
26226
|
const logger$4 = createLogger("IPC");
|
|
26041
26227
|
const VALID_APPROVAL_MODES = ["auto", "confirm-dangerous", "manual"];
|
|
@@ -26433,18 +26619,18 @@ function registerIpcHandlers(windowState, runtime2) {
|
|
|
26433
26619
|
return getRendererSettings();
|
|
26434
26620
|
});
|
|
26435
26621
|
electron.ipcMain.handle(Channels.SETTINGS_HEALTH_GET, () => getRuntimeHealth());
|
|
26436
|
-
electron.ipcMain.handle(Channels.SETTINGS_SET, async (_,
|
|
26437
|
-
assertString(
|
|
26438
|
-
if (!SETTABLE_KEYS.has(
|
|
26439
|
-
throw new Error(`Unknown setting key: ${
|
|
26622
|
+
electron.ipcMain.handle(Channels.SETTINGS_SET, async (_, key2, value) => {
|
|
26623
|
+
assertString(key2, "key");
|
|
26624
|
+
if (!SETTABLE_KEYS.has(key2)) {
|
|
26625
|
+
throw new Error(`Unknown setting key: ${key2}`);
|
|
26440
26626
|
}
|
|
26441
|
-
const settingsKey =
|
|
26627
|
+
const settingsKey = key2;
|
|
26442
26628
|
const updatedSettings = setSetting(settingsKey, value);
|
|
26443
|
-
trackSettingChanged(
|
|
26444
|
-
if (
|
|
26629
|
+
trackSettingChanged(key2);
|
|
26630
|
+
if (key2 === "approvalMode") {
|
|
26445
26631
|
runtime2.setApprovalMode(value);
|
|
26446
26632
|
}
|
|
26447
|
-
if (
|
|
26633
|
+
if (key2 === "mcpPort") {
|
|
26448
26634
|
await stopMcpServer();
|
|
26449
26635
|
await startMcpServer(tabManager, runtime2, updatedSettings.mcpPort);
|
|
26450
26636
|
}
|
|
@@ -26638,6 +26824,26 @@ function registerIpcHandlers(windowState, runtime2) {
|
|
|
26638
26824
|
clearByTimeRange(timeRange);
|
|
26639
26825
|
}
|
|
26640
26826
|
});
|
|
26827
|
+
setDownloadBroadcaster(sendToRendererViews);
|
|
26828
|
+
setPermissionBroadcaster(sendToRendererViews);
|
|
26829
|
+
electron.ipcMain.handle(Channels.DOWNLOADS_GET, () => listDownloads());
|
|
26830
|
+
electron.ipcMain.handle(Channels.DOWNLOADS_CLEAR, () => {
|
|
26831
|
+
clearDownloads();
|
|
26832
|
+
return true;
|
|
26833
|
+
});
|
|
26834
|
+
electron.ipcMain.handle(Channels.DOWNLOADS_OPEN, (_event, id) => openDownload(id));
|
|
26835
|
+
electron.ipcMain.handle(Channels.DOWNLOADS_SHOW_IN_FOLDER, (_event, id) => showDownloadInFolder(id));
|
|
26836
|
+
electron.ipcMain.handle(Channels.PERMISSIONS_GET, () => listPermissions());
|
|
26837
|
+
electron.ipcMain.handle(Channels.PERMISSIONS_CLEAR, () => {
|
|
26838
|
+
clearPermissions();
|
|
26839
|
+
return true;
|
|
26840
|
+
});
|
|
26841
|
+
electron.ipcMain.handle(Channels.PERMISSIONS_CLEAR_ORIGIN, (_event, origin) => {
|
|
26842
|
+
clearPermissionsForOrigin(origin);
|
|
26843
|
+
return true;
|
|
26844
|
+
});
|
|
26845
|
+
electron.ipcMain.handle(Channels.UPDATES_CHECK, () => checkForUpdates());
|
|
26846
|
+
electron.ipcMain.handle(Channels.UPDATES_OPEN_DOWNLOAD, () => openUpdateDownload());
|
|
26641
26847
|
electron.ipcMain.handle(Channels.TAB_TOGGLE_PIP, async () => {
|
|
26642
26848
|
return togglePictureInPicture(tabManager);
|
|
26643
26849
|
});
|
|
@@ -27033,9 +27239,9 @@ function clone(value) {
|
|
|
27033
27239
|
function summarizeArgs(args) {
|
|
27034
27240
|
const entries = Object.entries(args).filter(([, value]) => value != null);
|
|
27035
27241
|
if (entries.length === 0) return "No arguments";
|
|
27036
|
-
return entries.map(([
|
|
27242
|
+
return entries.map(([key2, value]) => {
|
|
27037
27243
|
const rendered = typeof value === "string" ? value : JSON.stringify(value);
|
|
27038
|
-
return `${
|
|
27244
|
+
return `${key2}=${String(rendered).slice(0, 120)}`;
|
|
27039
27245
|
}).join(", ");
|
|
27040
27246
|
}
|
|
27041
27247
|
function summarizeText(value) {
|
|
@@ -28061,6 +28267,7 @@ async function bootstrap() {
|
|
|
28061
28267
|
sidebarView.webContents.send(Channels.HISTORY_UPDATE, state2);
|
|
28062
28268
|
});
|
|
28063
28269
|
installDownloadHandler(chromeView);
|
|
28270
|
+
installPermissionHandler();
|
|
28064
28271
|
startBackgroundRevalidation();
|
|
28065
28272
|
startTelemetry();
|
|
28066
28273
|
const initializeChromeRenderer = () => {
|