@quanta-intellect/vessel-browser 0.1.67 → 0.1.69
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/README.md +12 -7
- package/out/main/index.js +621 -91
- package/out/preload/index.js +17 -2
- package/out/renderer/assets/{index-BQjjFSb1.js → index-BYk0kH1i.js} +1072 -703
- package/out/renderer/assets/{index-4OgPv5GF.css → index-B_C8ayic.css} +13 -0
- package/out/renderer/index.html +2 -2
- package/package.json +1 -1
package/out/main/index.js
CHANGED
|
@@ -65,6 +65,7 @@ const defaults = {
|
|
|
65
65
|
domainPolicy: { allowedDomains: [], blockedDomains: [] },
|
|
66
66
|
downloadPath: "",
|
|
67
67
|
telemetryEnabled: true,
|
|
68
|
+
defaultSearchEngine: "duckduckgo",
|
|
68
69
|
premium: {
|
|
69
70
|
status: "free",
|
|
70
71
|
customerId: "",
|
|
@@ -74,7 +75,7 @@ const defaults = {
|
|
|
74
75
|
expiresAt: ""
|
|
75
76
|
}
|
|
76
77
|
};
|
|
77
|
-
const SAVE_DEBOUNCE_MS$
|
|
78
|
+
const SAVE_DEBOUNCE_MS$6 = 150;
|
|
78
79
|
const CHAT_PROVIDER_SECRET_FILENAME = "vessel-chat-provider-secret";
|
|
79
80
|
const logger$j = createLogger("Settings");
|
|
80
81
|
const SETTABLE_KEYS = new Set(Object.keys(defaults));
|
|
@@ -232,7 +233,7 @@ function saveSettings() {
|
|
|
232
233
|
if (saveDirty) {
|
|
233
234
|
void persistNow();
|
|
234
235
|
}
|
|
235
|
-
}, SAVE_DEBOUNCE_MS$
|
|
236
|
+
}, SAVE_DEBOUNCE_MS$6);
|
|
236
237
|
}
|
|
237
238
|
function setSetting(key, value) {
|
|
238
239
|
loadSettings();
|
|
@@ -871,7 +872,7 @@ function createDebouncedJsonPersistence({
|
|
|
871
872
|
}
|
|
872
873
|
let state$4 = null;
|
|
873
874
|
const listeners$2 = /* @__PURE__ */ new Set();
|
|
874
|
-
const SAVE_DEBOUNCE_MS$
|
|
875
|
+
const SAVE_DEBOUNCE_MS$5 = 250;
|
|
875
876
|
function getHighlightsPath() {
|
|
876
877
|
return path.join(electron.app.getPath("userData"), "vessel-highlights.json");
|
|
877
878
|
}
|
|
@@ -889,15 +890,15 @@ function load$4() {
|
|
|
889
890
|
});
|
|
890
891
|
return state$4;
|
|
891
892
|
}
|
|
892
|
-
const persistence$
|
|
893
|
-
debounceMs: SAVE_DEBOUNCE_MS$
|
|
893
|
+
const persistence$5 = createDebouncedJsonPersistence({
|
|
894
|
+
debounceMs: SAVE_DEBOUNCE_MS$5,
|
|
894
895
|
filePath: getHighlightsPath(),
|
|
895
896
|
getValue: () => state$4,
|
|
896
897
|
logLabel: "highlights",
|
|
897
898
|
resetOnSchedule: true
|
|
898
899
|
});
|
|
899
900
|
function save$2() {
|
|
900
|
-
persistence$
|
|
901
|
+
persistence$5.schedule();
|
|
901
902
|
}
|
|
902
903
|
function emit$2() {
|
|
903
904
|
if (!state$4) return;
|
|
@@ -979,7 +980,7 @@ function clearHighlightsForUrl(url) {
|
|
|
979
980
|
return removed;
|
|
980
981
|
}
|
|
981
982
|
function flushPersist$4() {
|
|
982
|
-
return persistence$
|
|
983
|
+
return persistence$5.flush();
|
|
983
984
|
}
|
|
984
985
|
const SKIP_TAGS_JS = "var SKIP_TAGS = {SCRIPT:1,STYLE:1,NOSCRIPT:1,TEMPLATE:1,IFRAME:1,SVG:1};";
|
|
985
986
|
const CONTENT_ROOTS_JS = `
|
|
@@ -1551,7 +1552,7 @@ function persistHighlight(url, text) {
|
|
|
1551
1552
|
return { success: true, text: capped, id: highlight.id };
|
|
1552
1553
|
}
|
|
1553
1554
|
const MAX_HISTORY_ENTRIES = 5e3;
|
|
1554
|
-
const SAVE_DEBOUNCE_MS$
|
|
1555
|
+
const SAVE_DEBOUNCE_MS$4 = 250;
|
|
1555
1556
|
let state$3 = null;
|
|
1556
1557
|
const listeners$1 = /* @__PURE__ */ new Set();
|
|
1557
1558
|
function getHistoryPath() {
|
|
@@ -1571,14 +1572,14 @@ function load$3() {
|
|
|
1571
1572
|
});
|
|
1572
1573
|
return state$3;
|
|
1573
1574
|
}
|
|
1574
|
-
const persistence$
|
|
1575
|
-
debounceMs: SAVE_DEBOUNCE_MS$
|
|
1575
|
+
const persistence$4 = createDebouncedJsonPersistence({
|
|
1576
|
+
debounceMs: SAVE_DEBOUNCE_MS$4,
|
|
1576
1577
|
filePath: getHistoryPath(),
|
|
1577
1578
|
getValue: () => state$3,
|
|
1578
1579
|
logLabel: "history"
|
|
1579
1580
|
});
|
|
1580
1581
|
function save$1() {
|
|
1581
|
-
persistence$
|
|
1582
|
+
persistence$4.schedule();
|
|
1582
1583
|
}
|
|
1583
1584
|
function emit$1() {
|
|
1584
1585
|
if (!state$3) return;
|
|
@@ -1635,7 +1636,7 @@ function clearAll$1() {
|
|
|
1635
1636
|
emit$1();
|
|
1636
1637
|
}
|
|
1637
1638
|
function flushPersist$3() {
|
|
1638
|
-
return persistence$
|
|
1639
|
+
return persistence$4.flush();
|
|
1639
1640
|
}
|
|
1640
1641
|
const MAX_CONSOLE_ENTRIES = 500;
|
|
1641
1642
|
const MAX_NETWORK_ENTRIES = 200;
|
|
@@ -2684,6 +2685,8 @@ const Channels = {
|
|
|
2684
2685
|
AGENT_APPROVAL_RESOLVE: "agent:approval-resolve",
|
|
2685
2686
|
AGENT_CHECKPOINT_CREATE: "agent:checkpoint-create",
|
|
2686
2687
|
AGENT_CHECKPOINT_RESTORE: "agent:checkpoint-restore",
|
|
2688
|
+
AGENT_CHECKPOINT_UPDATE_NOTE: "agent:checkpoint-update-note",
|
|
2689
|
+
AGENT_UNDO_LAST_ACTION: "agent:undo-last-action",
|
|
2687
2690
|
AGENT_SESSION_CAPTURE: "agent:session-capture",
|
|
2688
2691
|
AGENT_SESSION_RESTORE: "agent:session-restore",
|
|
2689
2692
|
// Content
|
|
@@ -2691,6 +2694,7 @@ const Channels = {
|
|
|
2691
2694
|
READER_MODE_TOGGLE: "reader:toggle",
|
|
2692
2695
|
// UI state
|
|
2693
2696
|
SIDEBAR_TOGGLE: "ui:sidebar-toggle",
|
|
2697
|
+
SIDEBAR_NAVIGATE: "ui:sidebar-navigate",
|
|
2694
2698
|
SIDEBAR_RESIZE: "ui:sidebar-resize",
|
|
2695
2699
|
SIDEBAR_RESIZE_START: "ui:sidebar-resize-start",
|
|
2696
2700
|
SIDEBAR_RESIZE_COMMIT: "ui:sidebar-resize-commit",
|
|
@@ -2707,6 +2711,7 @@ const Channels = {
|
|
|
2707
2711
|
BOOKMARKS_GET: "bookmarks:get",
|
|
2708
2712
|
BOOKMARKS_UPDATE: "bookmarks:update",
|
|
2709
2713
|
BOOKMARK_SAVE: "bookmarks:save",
|
|
2714
|
+
BOOKMARK_UPDATE: "bookmarks:update-item",
|
|
2710
2715
|
BOOKMARK_REMOVE: "bookmarks:remove",
|
|
2711
2716
|
BOOKMARK_ADD_CONTEXT_TO_CHAT: "bookmarks:add-context-to-chat",
|
|
2712
2717
|
FOLDER_CREATE: "bookmarks:folder-create",
|
|
@@ -2786,6 +2791,7 @@ const Channels = {
|
|
|
2786
2791
|
PAGE_DIFF_ACTIVITY: "page:diff-activity",
|
|
2787
2792
|
PAGE_CHANGED: "page:changed",
|
|
2788
2793
|
PAGE_DIFF_GET: "page:diff-get",
|
|
2794
|
+
PAGE_DIFF_HISTORY: "page:diff-history",
|
|
2789
2795
|
PAGE_DIFF_DIRTY: "page:diff-dirty"
|
|
2790
2796
|
};
|
|
2791
2797
|
const MAX_DETAIL_ITEMS = 3;
|
|
@@ -3101,7 +3107,7 @@ function isTrackablePageUrl(rawUrl) {
|
|
|
3101
3107
|
return false;
|
|
3102
3108
|
}
|
|
3103
3109
|
}
|
|
3104
|
-
const SAVE_DEBOUNCE_MS$
|
|
3110
|
+
const SAVE_DEBOUNCE_MS$3 = 500;
|
|
3105
3111
|
const MAX_TEXT_LENGTH = 8e3;
|
|
3106
3112
|
let snapshots = null;
|
|
3107
3113
|
function getFilePath$1() {
|
|
@@ -3139,8 +3145,8 @@ function load$2() {
|
|
|
3139
3145
|
});
|
|
3140
3146
|
return snapshots;
|
|
3141
3147
|
}
|
|
3142
|
-
const persistence$
|
|
3143
|
-
debounceMs: SAVE_DEBOUNCE_MS$
|
|
3148
|
+
const persistence$3 = createDebouncedJsonPersistence({
|
|
3149
|
+
debounceMs: SAVE_DEBOUNCE_MS$3,
|
|
3144
3150
|
filePath: getFilePath$1(),
|
|
3145
3151
|
getValue: () => snapshots,
|
|
3146
3152
|
logLabel: "page snapshots",
|
|
@@ -3168,11 +3174,11 @@ function saveSnapshot(rawUrl, title, textContent, headings) {
|
|
|
3168
3174
|
};
|
|
3169
3175
|
s.delete(key);
|
|
3170
3176
|
s.set(key, snapshot);
|
|
3171
|
-
persistence$
|
|
3177
|
+
persistence$3.schedule();
|
|
3172
3178
|
return snapshot;
|
|
3173
3179
|
}
|
|
3174
3180
|
function flushPersist$2() {
|
|
3175
|
-
return persistence$
|
|
3181
|
+
return persistence$3.flush();
|
|
3176
3182
|
}
|
|
3177
3183
|
const SEARCH_ENGINE_HOSTS = [
|
|
3178
3184
|
"google.",
|
|
@@ -3749,6 +3755,24 @@ const VERIFICATION_API = process.env.VESSEL_PREMIUM_API || "https://vesselpremiu
|
|
|
3749
3755
|
const FREE_TOOL_ITERATION_LIMIT = 50;
|
|
3750
3756
|
const REVALIDATION_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
3751
3757
|
const OFFLINE_GRACE_PERIOD_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
3758
|
+
const MAX_API_ERROR_LOG_LENGTH = 300;
|
|
3759
|
+
async function readApiErrorDetail(res) {
|
|
3760
|
+
try {
|
|
3761
|
+
const text = (await res.text()).trim();
|
|
3762
|
+
if (!text) return "";
|
|
3763
|
+
try {
|
|
3764
|
+
const data = JSON.parse(text);
|
|
3765
|
+
const detail = data.error || data.message;
|
|
3766
|
+
if (typeof detail === "string" && detail.trim()) {
|
|
3767
|
+
return detail.trim().slice(0, MAX_API_ERROR_LOG_LENGTH);
|
|
3768
|
+
}
|
|
3769
|
+
} catch {
|
|
3770
|
+
}
|
|
3771
|
+
return text.slice(0, MAX_API_ERROR_LOG_LENGTH);
|
|
3772
|
+
} catch {
|
|
3773
|
+
return "";
|
|
3774
|
+
}
|
|
3775
|
+
}
|
|
3752
3776
|
const PREMIUM_TOOLS = /* @__PURE__ */ new Set([
|
|
3753
3777
|
"screenshot",
|
|
3754
3778
|
"save_session",
|
|
@@ -3838,7 +3862,12 @@ async function verifySubscription(identifier) {
|
|
|
3838
3862
|
body: JSON.stringify({ identifier: verificationIdentifier })
|
|
3839
3863
|
});
|
|
3840
3864
|
if (!res.ok) {
|
|
3841
|
-
|
|
3865
|
+
const detail = await readApiErrorDetail(res);
|
|
3866
|
+
logger$f.warn(
|
|
3867
|
+
"Verification API returned a non-OK status:",
|
|
3868
|
+
res.status,
|
|
3869
|
+
detail
|
|
3870
|
+
);
|
|
3842
3871
|
return current;
|
|
3843
3872
|
}
|
|
3844
3873
|
const data = await res.json();
|
|
@@ -5355,8 +5384,32 @@ function normalizePageContent(value) {
|
|
|
5355
5384
|
pageSchema: page.pageSchema
|
|
5356
5385
|
};
|
|
5357
5386
|
}
|
|
5387
|
+
function normalizePageDiffHistoryItem(value) {
|
|
5388
|
+
if (!value || typeof value !== "object") return null;
|
|
5389
|
+
const raw = value;
|
|
5390
|
+
if (typeof raw.detectedAt !== "string" || typeof raw.summary !== "string") {
|
|
5391
|
+
return null;
|
|
5392
|
+
}
|
|
5393
|
+
return {
|
|
5394
|
+
detectedAt: raw.detectedAt,
|
|
5395
|
+
summary: raw.summary
|
|
5396
|
+
};
|
|
5397
|
+
}
|
|
5398
|
+
function prunePageDiffHistory(items, options) {
|
|
5399
|
+
const cutoff = (options.now ?? Date.now()) - options.maxAgeDays * 24 * 60 * 60 * 1e3;
|
|
5400
|
+
return items.filter((item) => {
|
|
5401
|
+
const detectedAt = Date.parse(item.detectedAt);
|
|
5402
|
+
return Number.isFinite(detectedAt) && detectedAt >= cutoff;
|
|
5403
|
+
}).sort(
|
|
5404
|
+
(left, right) => Date.parse(left.detectedAt) - Date.parse(right.detectedAt)
|
|
5405
|
+
).slice(-options.maxItems);
|
|
5406
|
+
}
|
|
5407
|
+
function appendPageDiffHistoryItem(items, next, options) {
|
|
5408
|
+
return prunePageDiffHistory([...items, next], options);
|
|
5409
|
+
}
|
|
5358
5410
|
const latestPageDiffs = /* @__PURE__ */ new Map();
|
|
5359
5411
|
const recentPageDiffBursts = /* @__PURE__ */ new Map();
|
|
5412
|
+
let historyLoaded = false;
|
|
5360
5413
|
const pendingPageSnapshotTimers = /* @__PURE__ */ new Map();
|
|
5361
5414
|
const pendingPageSnapshotDueAt = /* @__PURE__ */ new Map();
|
|
5362
5415
|
const lastMutationSnapshotAt = /* @__PURE__ */ new Map();
|
|
@@ -5377,10 +5430,81 @@ function attachDestroyCleanup(wc) {
|
|
|
5377
5430
|
cleanupTimersForWcId(wc.id);
|
|
5378
5431
|
});
|
|
5379
5432
|
}
|
|
5433
|
+
const MAX_PERSISTED_DIFF_BURSTS = 50;
|
|
5434
|
+
const MAX_HISTORY_DAYS = 30;
|
|
5435
|
+
const SAVE_DEBOUNCE_MS$2 = 500;
|
|
5436
|
+
function getHistoryFilePath() {
|
|
5437
|
+
return path.join(electron.app.getPath("userData"), "vessel-page-diff-history.json");
|
|
5438
|
+
}
|
|
5439
|
+
function loadHistory() {
|
|
5440
|
+
if (historyLoaded) return recentPageDiffBursts;
|
|
5441
|
+
historyLoaded = true;
|
|
5442
|
+
const loaded = loadJsonFile({
|
|
5443
|
+
filePath: getHistoryFilePath(),
|
|
5444
|
+
fallback: /* @__PURE__ */ new Map(),
|
|
5445
|
+
secure: true,
|
|
5446
|
+
parse: (raw) => {
|
|
5447
|
+
const next = /* @__PURE__ */ new Map();
|
|
5448
|
+
if (!Array.isArray(raw)) return next;
|
|
5449
|
+
for (const entry of raw) {
|
|
5450
|
+
if (!entry || typeof entry !== "object") continue;
|
|
5451
|
+
const record = entry;
|
|
5452
|
+
if (typeof record.url !== "string" || !Array.isArray(record.bursts)) {
|
|
5453
|
+
continue;
|
|
5454
|
+
}
|
|
5455
|
+
next.set(
|
|
5456
|
+
record.url,
|
|
5457
|
+
prunePageDiffHistory(
|
|
5458
|
+
record.bursts.map((item) => normalizePageDiffHistoryItem(item)).filter((item) => item !== null),
|
|
5459
|
+
{
|
|
5460
|
+
maxAgeDays: MAX_HISTORY_DAYS,
|
|
5461
|
+
maxItems: MAX_PERSISTED_DIFF_BURSTS
|
|
5462
|
+
}
|
|
5463
|
+
)
|
|
5464
|
+
);
|
|
5465
|
+
}
|
|
5466
|
+
return next;
|
|
5467
|
+
}
|
|
5468
|
+
});
|
|
5469
|
+
for (const [key, bursts] of loaded.entries()) {
|
|
5470
|
+
recentPageDiffBursts.set(key, bursts);
|
|
5471
|
+
}
|
|
5472
|
+
return recentPageDiffBursts;
|
|
5473
|
+
}
|
|
5474
|
+
const persistence$2 = createDebouncedJsonPersistence({
|
|
5475
|
+
debounceMs: SAVE_DEBOUNCE_MS$2,
|
|
5476
|
+
filePath: getHistoryFilePath(),
|
|
5477
|
+
getValue: () => recentPageDiffBursts,
|
|
5478
|
+
logLabel: "page diff history",
|
|
5479
|
+
secure: true,
|
|
5480
|
+
serialize: (value) => Array.from(value.entries()).map(([url, bursts]) => ({
|
|
5481
|
+
url,
|
|
5482
|
+
bursts
|
|
5483
|
+
}))
|
|
5484
|
+
});
|
|
5380
5485
|
function getLatestPageDiff(rawUrl) {
|
|
5381
5486
|
if (!shouldTrackSnapshotUrl(rawUrl)) return null;
|
|
5382
5487
|
return latestPageDiffs.get(normalizeUrl(rawUrl)) ?? null;
|
|
5383
5488
|
}
|
|
5489
|
+
function getPageDiffBursts(rawUrl) {
|
|
5490
|
+
if (!shouldTrackSnapshotUrl(rawUrl)) return [];
|
|
5491
|
+
const key = normalizeUrl(rawUrl);
|
|
5492
|
+
const history = loadHistory();
|
|
5493
|
+
const bursts = prunePageDiffHistory(history.get(key) ?? [], {
|
|
5494
|
+
maxAgeDays: MAX_HISTORY_DAYS,
|
|
5495
|
+
maxItems: MAX_PERSISTED_DIFF_BURSTS
|
|
5496
|
+
});
|
|
5497
|
+
const current = history.get(key) ?? [];
|
|
5498
|
+
if (current.length !== bursts.length) {
|
|
5499
|
+
if (bursts.length > 0) {
|
|
5500
|
+
history.set(key, bursts);
|
|
5501
|
+
} else {
|
|
5502
|
+
history.delete(key);
|
|
5503
|
+
}
|
|
5504
|
+
persistence$2.schedule();
|
|
5505
|
+
}
|
|
5506
|
+
return bursts.slice().reverse();
|
|
5507
|
+
}
|
|
5384
5508
|
function summarizeDiffBurst(diff) {
|
|
5385
5509
|
const items = diff.changes.slice(0, 2).map((change) => `${change.section}: ${change.summary}`);
|
|
5386
5510
|
return items.join(" | ");
|
|
@@ -5391,16 +5515,21 @@ function enrichWithBurstHistory(key, diff) {
|
|
|
5391
5515
|
detectedAt,
|
|
5392
5516
|
summary: summarizeDiffBurst(diff)
|
|
5393
5517
|
};
|
|
5394
|
-
const
|
|
5395
|
-
|
|
5396
|
-
|
|
5397
|
-
|
|
5518
|
+
const history = loadHistory();
|
|
5519
|
+
const bursts = appendPageDiffHistoryItem(history.get(key) ?? [], nextBurst, {
|
|
5520
|
+
maxAgeDays: MAX_HISTORY_DAYS,
|
|
5521
|
+
maxItems: MAX_PERSISTED_DIFF_BURSTS,
|
|
5522
|
+
now: Date.parse(detectedAt)
|
|
5523
|
+
});
|
|
5524
|
+
history.set(key, bursts);
|
|
5525
|
+
persistence$2.schedule();
|
|
5526
|
+
const recentBursts = bursts.slice(-5);
|
|
5398
5527
|
return {
|
|
5399
5528
|
...diff,
|
|
5400
5529
|
burstCount: bursts.length,
|
|
5401
5530
|
firstDetectedAt: bursts[0]?.detectedAt,
|
|
5402
5531
|
lastDetectedAt: bursts[bursts.length - 1]?.detectedAt,
|
|
5403
|
-
recentBursts:
|
|
5532
|
+
recentBursts: recentBursts.slice().reverse()
|
|
5404
5533
|
};
|
|
5405
5534
|
}
|
|
5406
5535
|
async function capturePageSnapshot(url, wc, sendToRendererViews) {
|
|
@@ -5421,11 +5550,9 @@ async function capturePageSnapshot(url, wc, sendToRendererViews) {
|
|
|
5421
5550
|
sendToRendererViews(Channels.PAGE_CHANGED, enrichedDiff);
|
|
5422
5551
|
} else {
|
|
5423
5552
|
latestPageDiffs.delete(key);
|
|
5424
|
-
recentPageDiffBursts.delete(key);
|
|
5425
5553
|
}
|
|
5426
5554
|
} else {
|
|
5427
5555
|
latestPageDiffs.delete(key);
|
|
5428
|
-
recentPageDiffBursts.delete(key);
|
|
5429
5556
|
}
|
|
5430
5557
|
saveSnapshot(url, title, textContent, headings);
|
|
5431
5558
|
} catch {
|
|
@@ -6223,7 +6350,7 @@ class AnthropicProvider {
|
|
|
6223
6350
|
});
|
|
6224
6351
|
continue;
|
|
6225
6352
|
}
|
|
6226
|
-
const argSummary = [tb.input.url, tb.input.text, tb.input.direction].map((v) => typeof v === "string" ? v : "").find((v) => v.length > 0) ?? "";
|
|
6353
|
+
const argSummary = [tb.input.url, tb.input.query, tb.input.text, tb.input.direction].map((v) => typeof v === "string" ? v : "").find((v) => v.length > 0) ?? "";
|
|
6227
6354
|
onChunk(`
|
|
6228
6355
|
<<tool:${tb.name}${argSummary ? ":" + argSummary : ""}>>
|
|
6229
6356
|
`);
|
|
@@ -6414,11 +6541,52 @@ const SAFE_TOOL_ALIASES = {
|
|
|
6414
6541
|
scroll_up: "scroll",
|
|
6415
6542
|
read: "read_page",
|
|
6416
6543
|
read_current_page: "read_page",
|
|
6417
|
-
scan_page: "read_page"
|
|
6544
|
+
scan_page: "read_page",
|
|
6545
|
+
save_bookmark: "save_bookmark",
|
|
6546
|
+
bookmark: "save_bookmark",
|
|
6547
|
+
bookmark_page: "save_bookmark",
|
|
6548
|
+
bookmark_url: "save_bookmark",
|
|
6549
|
+
add_bookmark: "save_bookmark",
|
|
6550
|
+
create_bookmark: "save_bookmark"
|
|
6418
6551
|
};
|
|
6552
|
+
const CANONICAL_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
6553
|
+
"archive_bookmark",
|
|
6554
|
+
"click",
|
|
6555
|
+
"create_bookmark_folder",
|
|
6556
|
+
"current_tab",
|
|
6557
|
+
"go_back",
|
|
6558
|
+
"go_forward",
|
|
6559
|
+
"inspect_element",
|
|
6560
|
+
"list_bookmarks",
|
|
6561
|
+
"navigate",
|
|
6562
|
+
"open_bookmark",
|
|
6563
|
+
"organize_bookmark",
|
|
6564
|
+
"read_page",
|
|
6565
|
+
"save_bookmark",
|
|
6566
|
+
"scroll",
|
|
6567
|
+
"search",
|
|
6568
|
+
"type_text"
|
|
6569
|
+
]);
|
|
6570
|
+
function repeatedTokenMatch(value, token) {
|
|
6571
|
+
if (value === token) return true;
|
|
6572
|
+
if (token.length === 0 || value.length <= token.length) return false;
|
|
6573
|
+
if (value.length % token.length !== 0) return false;
|
|
6574
|
+
return token.repeat(value.length / token.length) === value;
|
|
6575
|
+
}
|
|
6419
6576
|
function normalizeToolAlias(name) {
|
|
6420
6577
|
const normalized = name.trim().toLowerCase().replace(/[.\s/-]+/g, "_");
|
|
6421
|
-
|
|
6578
|
+
const direct = SAFE_TOOL_ALIASES[normalized] ?? normalized;
|
|
6579
|
+
if (CANONICAL_TOOL_NAMES.has(direct)) return direct;
|
|
6580
|
+
const knownTokens = [
|
|
6581
|
+
...Object.keys(SAFE_TOOL_ALIASES),
|
|
6582
|
+
...CANONICAL_TOOL_NAMES
|
|
6583
|
+
];
|
|
6584
|
+
for (const token of knownTokens) {
|
|
6585
|
+
if (repeatedTokenMatch(normalized, token)) {
|
|
6586
|
+
return SAFE_TOOL_ALIASES[token] ?? token;
|
|
6587
|
+
}
|
|
6588
|
+
}
|
|
6589
|
+
return name;
|
|
6422
6590
|
}
|
|
6423
6591
|
function parseModelSizeInBillions(model) {
|
|
6424
6592
|
const match = model.toLowerCase().match(/(?:^|[:/_\-\s])(\d+(?:\.\d+)?)b(?:$|[:/_\-\s])/i);
|
|
@@ -6742,8 +6910,62 @@ function scalarArgsForTool(name, scalar) {
|
|
|
6742
6910
|
const mode = trimmed.replace(/^["']|["']$/g, "").toLowerCase();
|
|
6743
6911
|
if (mode) return { mode };
|
|
6744
6912
|
}
|
|
6913
|
+
if (name === "save_bookmark") {
|
|
6914
|
+
const url = toLikelyUrl(trimmed);
|
|
6915
|
+
if (url) return { url };
|
|
6916
|
+
const lastSpace = trimmed.lastIndexOf(" ");
|
|
6917
|
+
if (lastSpace > 0) {
|
|
6918
|
+
const maybeUrl = toLikelyUrl(trimmed.slice(lastSpace + 1));
|
|
6919
|
+
if (maybeUrl) return { url: maybeUrl, title: trimmed.slice(0, lastSpace).replace(/^["']|["']$/g, "") };
|
|
6920
|
+
}
|
|
6921
|
+
}
|
|
6922
|
+
return null;
|
|
6923
|
+
}
|
|
6924
|
+
function firstStringArg(args, keys) {
|
|
6925
|
+
for (const key of keys) {
|
|
6926
|
+
const value = args[key];
|
|
6927
|
+
if (typeof value === "string" && value.trim()) {
|
|
6928
|
+
return value.trim();
|
|
6929
|
+
}
|
|
6930
|
+
}
|
|
6745
6931
|
return null;
|
|
6746
6932
|
}
|
|
6933
|
+
function normalizeElementTargetArgs(args) {
|
|
6934
|
+
const normalized = { ...args };
|
|
6935
|
+
if (typeof normalized.index === "string" && /^\d+$/.test(normalized.index.trim())) {
|
|
6936
|
+
normalized.index = Number(normalized.index.trim());
|
|
6937
|
+
}
|
|
6938
|
+
if (typeof normalized.selector !== "string" || !normalized.selector.trim()) {
|
|
6939
|
+
const selector = firstStringArg(normalized, [
|
|
6940
|
+
"cssSelector",
|
|
6941
|
+
"css_selector",
|
|
6942
|
+
"querySelector",
|
|
6943
|
+
"query_selector"
|
|
6944
|
+
]);
|
|
6945
|
+
if (selector) normalized.selector = selector;
|
|
6946
|
+
}
|
|
6947
|
+
if (typeof normalized.text !== "string" || !normalized.text.trim()) {
|
|
6948
|
+
const text = firstStringArg(normalized, [
|
|
6949
|
+
"label",
|
|
6950
|
+
"title",
|
|
6951
|
+
"name",
|
|
6952
|
+
"target",
|
|
6953
|
+
"element",
|
|
6954
|
+
"linkText",
|
|
6955
|
+
"link_text",
|
|
6956
|
+
"ariaLabel",
|
|
6957
|
+
"aria_label"
|
|
6958
|
+
]);
|
|
6959
|
+
if (text) normalized.text = text;
|
|
6960
|
+
}
|
|
6961
|
+
return normalized;
|
|
6962
|
+
}
|
|
6963
|
+
function hasElementTarget(args) {
|
|
6964
|
+
return typeof args.index === "number" || typeof args.selector === "string" && args.selector.trim().length > 0 || typeof args.text === "string" && args.text.trim().length > 0;
|
|
6965
|
+
}
|
|
6966
|
+
function isTargetlessClickArgs(args) {
|
|
6967
|
+
return !hasElementTarget(normalizeElementTargetArgs(args));
|
|
6968
|
+
}
|
|
6747
6969
|
function tryParseJsonWithCommonRepairs(raw) {
|
|
6748
6970
|
const trimmed = raw.trim();
|
|
6749
6971
|
if (!trimmed) return {};
|
|
@@ -6797,7 +7019,10 @@ function parseToolArgsWithRepair(name, argsJson) {
|
|
|
6797
7019
|
return scalarArgs ? { args: scalarArgs, repaired: true } : null;
|
|
6798
7020
|
}
|
|
6799
7021
|
function coerceToolArgsForExecution(name, args) {
|
|
6800
|
-
|
|
7022
|
+
let coerced = { ...args };
|
|
7023
|
+
if (name === "click" || name === "inspect_element" || name === "scroll_to_element") {
|
|
7024
|
+
coerced = normalizeElementTargetArgs(coerced);
|
|
7025
|
+
}
|
|
6801
7026
|
if (name === "search") {
|
|
6802
7027
|
if (typeof coerced.query !== "string" || !coerced.query.trim()) {
|
|
6803
7028
|
if (typeof coerced.text === "string" && coerced.text.trim()) {
|
|
@@ -6818,6 +7043,25 @@ function coerceToolArgsForExecution(name, args) {
|
|
|
6818
7043
|
}
|
|
6819
7044
|
}
|
|
6820
7045
|
}
|
|
7046
|
+
if (name === "save_bookmark") {
|
|
7047
|
+
if (typeof coerced.url !== "string" || !coerced.url.trim()) {
|
|
7048
|
+
if (typeof coerced.link === "string" && coerced.link.trim()) {
|
|
7049
|
+
coerced.url = coerced.link.trim();
|
|
7050
|
+
} else if (typeof coerced.href === "string" && coerced.href.trim()) {
|
|
7051
|
+
coerced.url = coerced.href.trim();
|
|
7052
|
+
}
|
|
7053
|
+
}
|
|
7054
|
+
if (typeof coerced.folderName !== "string" || !coerced.folderName.trim()) {
|
|
7055
|
+
if (typeof coerced.folder === "string" && coerced.folder.trim()) {
|
|
7056
|
+
coerced.folderName = coerced.folder.trim();
|
|
7057
|
+
} else if (typeof coerced.category === "string" && coerced.category.trim()) {
|
|
7058
|
+
coerced.folderName = coerced.category.trim();
|
|
7059
|
+
}
|
|
7060
|
+
}
|
|
7061
|
+
if (coerced.folderName && typeof coerced.createFolderIfMissing === "undefined") {
|
|
7062
|
+
coerced.createFolderIfMissing = true;
|
|
7063
|
+
}
|
|
7064
|
+
}
|
|
6821
7065
|
return coerced;
|
|
6822
7066
|
}
|
|
6823
7067
|
function canonicalizeArgsForTool(name, args) {
|
|
@@ -6834,6 +7078,24 @@ function canonicalizeArgsForTool(name, args) {
|
|
|
6834
7078
|
}
|
|
6835
7079
|
return canonical;
|
|
6836
7080
|
}
|
|
7081
|
+
function unsupportedToolHint(name) {
|
|
7082
|
+
const normalized = name.trim().toLowerCase().replace(/[.\s/-]+/g, "_");
|
|
7083
|
+
const BOOKMARK_NAMES = [
|
|
7084
|
+
"organize_bookmark",
|
|
7085
|
+
"organize_bookmarks",
|
|
7086
|
+
"manage_bookmark",
|
|
7087
|
+
"manage_bookmarks",
|
|
7088
|
+
"add_to_bookmarks",
|
|
7089
|
+
"save_to_bookmarks",
|
|
7090
|
+
"bookmark_link",
|
|
7091
|
+
"save_link",
|
|
7092
|
+
"store_bookmark"
|
|
7093
|
+
];
|
|
7094
|
+
if (BOOKMARK_NAMES.includes(normalized) || /bookmark|save.*link|organize/.test(normalized)) {
|
|
7095
|
+
return `Error: "${name}" is not a supported tool. Use save_bookmark to save a page as a bookmark, or create_bookmark_folder to create a folder. Example: save_bookmark with {"url": "...", "title": "...", "folderName": "..."}`;
|
|
7096
|
+
}
|
|
7097
|
+
return `Error: ${name} is not a supported tool. Choose one of the available browser tools instead.`;
|
|
7098
|
+
}
|
|
6837
7099
|
function resolveToolCallName(rawName, args, availableToolNames) {
|
|
6838
7100
|
const aliased = normalizeToolAlias(rawName);
|
|
6839
7101
|
if (availableToolNames.has(aliased)) return aliased;
|
|
@@ -7138,6 +7400,7 @@ class OpenAICompatProvider {
|
|
|
7138
7400
|
);
|
|
7139
7401
|
if (recoveredToolCalls.length > 0) {
|
|
7140
7402
|
toolCalls = recoveredToolCalls;
|
|
7403
|
+
if (textAccum.trim()) onChunk("<<erase_prev>>");
|
|
7141
7404
|
} else {
|
|
7142
7405
|
const narratedToolCalls = recoverNarratedActionToolCalls(
|
|
7143
7406
|
textAccum,
|
|
@@ -7145,6 +7408,7 @@ class OpenAICompatProvider {
|
|
|
7145
7408
|
);
|
|
7146
7409
|
if (narratedToolCalls.length > 0) {
|
|
7147
7410
|
toolCalls = narratedToolCalls;
|
|
7411
|
+
if (textAccum.trim()) onChunk("<<erase_prev>>");
|
|
7148
7412
|
}
|
|
7149
7413
|
}
|
|
7150
7414
|
}
|
|
@@ -7211,6 +7475,25 @@ class OpenAICompatProvider {
|
|
|
7211
7475
|
compactRecoveryCount = 0;
|
|
7212
7476
|
const iterationToolResultPreviews = [];
|
|
7213
7477
|
for (const tc of toolCalls) {
|
|
7478
|
+
if (!availableToolNames.has(tc.name)) {
|
|
7479
|
+
const hint = unsupportedToolHint(tc.name);
|
|
7480
|
+
onChunk(`
|
|
7481
|
+
<<tool:${tc.name}:⚠ unsupported>>
|
|
7482
|
+
`);
|
|
7483
|
+
messages.push({
|
|
7484
|
+
role: "tool",
|
|
7485
|
+
tool_call_id: tc.id,
|
|
7486
|
+
content: hint
|
|
7487
|
+
});
|
|
7488
|
+
compactCorrectionCount += 1;
|
|
7489
|
+
if (compactCorrectionCount >= 2) {
|
|
7490
|
+
messages.push({
|
|
7491
|
+
role: "user",
|
|
7492
|
+
content: `[System] You are calling unsupported tools. Stop inventing tool names. Use the supported tools you were given and take the next concrete step.`
|
|
7493
|
+
});
|
|
7494
|
+
}
|
|
7495
|
+
continue;
|
|
7496
|
+
}
|
|
7214
7497
|
if (malformedToolCalls.has(tc.id)) {
|
|
7215
7498
|
onChunk(`
|
|
7216
7499
|
<<tool:${tc.name}:⚠ invalid args>>
|
|
@@ -7237,25 +7520,23 @@ class OpenAICompatProvider {
|
|
|
7237
7520
|
}
|
|
7238
7521
|
args = repairedArgs.args;
|
|
7239
7522
|
args = coerceToolArgsForExecution(tc.name, args);
|
|
7240
|
-
|
|
7523
|
+
const toolSignature = stableToolSignature(tc.name, args);
|
|
7524
|
+
if (this.agentToolProfile === "compact" && tc.name === "click" && isTargetlessClickArgs(args)) {
|
|
7241
7525
|
onChunk(`
|
|
7242
|
-
<<tool
|
|
7526
|
+
<<tool:${tc.name}:⚠ missing target>>
|
|
7243
7527
|
`);
|
|
7244
7528
|
messages.push({
|
|
7245
7529
|
role: "tool",
|
|
7246
7530
|
tool_call_id: tc.id,
|
|
7247
|
-
content: `Error:
|
|
7531
|
+
content: `Error: click requires an element target. Use click with {"index": N} from the latest read_page result, or {"text": "exact visible link/button text"}. If you do not have a current result index, call read_page(mode="results_only") first and then click one listed result.`
|
|
7532
|
+
});
|
|
7533
|
+
messages.push({
|
|
7534
|
+
role: "user",
|
|
7535
|
+
content: `[System] Your last click had no target. Do not call click with empty arguments. Refresh the page state with read_page(mode="results_only") if needed, then click exactly one result by index or exact visible text.`
|
|
7248
7536
|
});
|
|
7249
7537
|
compactCorrectionCount += 1;
|
|
7250
|
-
if (compactCorrectionCount >= 2) {
|
|
7251
|
-
messages.push({
|
|
7252
|
-
role: "user",
|
|
7253
|
-
content: `[System] You are calling unsupported tools. Stop inventing tool names. Use the supported tools you were given and take the next concrete step.`
|
|
7254
|
-
});
|
|
7255
|
-
}
|
|
7256
7538
|
continue;
|
|
7257
7539
|
}
|
|
7258
|
-
const toolSignature = stableToolSignature(tc.name, args);
|
|
7259
7540
|
const neverSuppressDuplicate = [
|
|
7260
7541
|
"read_page",
|
|
7261
7542
|
"current_tab",
|
|
@@ -10080,6 +10361,13 @@ const TOOL_DEFINITIONS = [
|
|
|
10080
10361
|
tier: 2,
|
|
10081
10362
|
hiddenByDefault: true
|
|
10082
10363
|
},
|
|
10364
|
+
// --- Undo ---
|
|
10365
|
+
{
|
|
10366
|
+
name: "undo_last_action",
|
|
10367
|
+
title: "Undo Last Action",
|
|
10368
|
+
description: "Undo the most recent agent action by restoring the browser to its state before that action ran. Works for click, type, submit, navigate, and similar mutating actions. Returns the name of the undone action, or an error if nothing can be undone.",
|
|
10369
|
+
tier: 1
|
|
10370
|
+
},
|
|
10083
10371
|
// --- Speedee System: Suggestion Engine ---
|
|
10084
10372
|
{
|
|
10085
10373
|
name: "suggest",
|
|
@@ -10469,6 +10757,14 @@ function pruneToolsForContext(tools, pageType, query = "", options = {}) {
|
|
|
10469
10757
|
return description !== tool.description ? { ...tool, description } : tool;
|
|
10470
10758
|
});
|
|
10471
10759
|
}
|
|
10760
|
+
const SEARCH_ENGINE_PRESETS = {
|
|
10761
|
+
duckduckgo: { label: "DuckDuckGo", url: "https://duckduckgo.com/?q=" },
|
|
10762
|
+
google: { label: "Google", url: "https://www.google.com/search?q=" },
|
|
10763
|
+
bing: { label: "Bing", url: "https://www.bing.com/search?q=" },
|
|
10764
|
+
brave: { label: "Brave Search", url: "https://search.brave.com/search?q=" },
|
|
10765
|
+
ecosia: { label: "Ecosia", url: "https://www.ecosia.org/search?q=" },
|
|
10766
|
+
kagi: { label: "Kagi", url: "https://kagi.com/search?q=" }
|
|
10767
|
+
};
|
|
10472
10768
|
function trimText(value) {
|
|
10473
10769
|
return typeof value === "string" ? value.trim() : "";
|
|
10474
10770
|
}
|
|
@@ -10604,6 +10900,60 @@ function getBookmarkSearchMatch(args) {
|
|
|
10604
10900
|
}
|
|
10605
10901
|
return { matchedFields, score };
|
|
10606
10902
|
}
|
|
10903
|
+
function normalizeOptionalString(value) {
|
|
10904
|
+
if (typeof value !== "string") return void 0;
|
|
10905
|
+
const trimmed = value.trim();
|
|
10906
|
+
return trimmed || void 0;
|
|
10907
|
+
}
|
|
10908
|
+
function normalizeKeyFields(value) {
|
|
10909
|
+
if (!Array.isArray(value)) return void 0;
|
|
10910
|
+
const normalized = value.filter((field) => typeof field === "string").map((field) => field.trim()).filter(Boolean);
|
|
10911
|
+
return normalized.length > 0 ? normalized : void 0;
|
|
10912
|
+
}
|
|
10913
|
+
function normalizeAgentHints(value) {
|
|
10914
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
10915
|
+
return void 0;
|
|
10916
|
+
}
|
|
10917
|
+
const normalized = Object.fromEntries(
|
|
10918
|
+
Object.entries(value).map(([key, hint]) => [key.trim(), normalizeOptionalString(hint)]).filter((entry) => Boolean(entry[0] && entry[1]))
|
|
10919
|
+
);
|
|
10920
|
+
return Object.keys(normalized).length > 0 ? normalized : void 0;
|
|
10921
|
+
}
|
|
10922
|
+
function hasOwn(value, key) {
|
|
10923
|
+
return Object.prototype.hasOwnProperty.call(value, key);
|
|
10924
|
+
}
|
|
10925
|
+
function normalizeBookmarkMetadata(input) {
|
|
10926
|
+
const normalized = {};
|
|
10927
|
+
const intent = normalizeOptionalString(input.intent);
|
|
10928
|
+
const expectedContent = normalizeOptionalString(input.expectedContent);
|
|
10929
|
+
const keyFields = normalizeKeyFields(input.keyFields);
|
|
10930
|
+
const agentHints = normalizeAgentHints(input.agentHints);
|
|
10931
|
+
if (intent !== void 0) normalized.intent = intent;
|
|
10932
|
+
if (expectedContent !== void 0) {
|
|
10933
|
+
normalized.expectedContent = expectedContent;
|
|
10934
|
+
}
|
|
10935
|
+
if (keyFields !== void 0) normalized.keyFields = keyFields;
|
|
10936
|
+
if (agentHints !== void 0) normalized.agentHints = agentHints;
|
|
10937
|
+
return normalized;
|
|
10938
|
+
}
|
|
10939
|
+
function normalizeBookmarkMetadataUpdate(input) {
|
|
10940
|
+
const normalized = {};
|
|
10941
|
+
if (hasOwn(input, "intent")) {
|
|
10942
|
+
normalized.intent = normalizeOptionalString(input.intent);
|
|
10943
|
+
}
|
|
10944
|
+
if (hasOwn(input, "expectedContent")) {
|
|
10945
|
+
normalized.expectedContent = normalizeOptionalString(
|
|
10946
|
+
input.expectedContent
|
|
10947
|
+
);
|
|
10948
|
+
}
|
|
10949
|
+
if (hasOwn(input, "keyFields")) {
|
|
10950
|
+
normalized.keyFields = normalizeKeyFields(input.keyFields);
|
|
10951
|
+
}
|
|
10952
|
+
if (hasOwn(input, "agentHints")) {
|
|
10953
|
+
normalized.agentHints = normalizeAgentHints(input.agentHints);
|
|
10954
|
+
}
|
|
10955
|
+
return normalized;
|
|
10956
|
+
}
|
|
10607
10957
|
const UNSORTED_ID = "unsorted";
|
|
10608
10958
|
const ARCHIVE_FOLDER_NAME = "Archive";
|
|
10609
10959
|
const SAVE_DEBOUNCE_MS$1 = 250;
|
|
@@ -10642,6 +10992,13 @@ const persistence$1 = createDebouncedJsonPersistence({
|
|
|
10642
10992
|
function save() {
|
|
10643
10993
|
persistence$1.schedule();
|
|
10644
10994
|
}
|
|
10995
|
+
function assignDefinedBookmarkFields(bookmark, fields) {
|
|
10996
|
+
if (!fields) return;
|
|
10997
|
+
for (const [key, value] of Object.entries(fields)) {
|
|
10998
|
+
if (value === void 0) continue;
|
|
10999
|
+
Object.assign(bookmark, { [key]: value });
|
|
11000
|
+
}
|
|
11001
|
+
}
|
|
10645
11002
|
function emit() {
|
|
10646
11003
|
if (!state$1) return;
|
|
10647
11004
|
const snapshot = cloneState(state$1);
|
|
@@ -10815,9 +11172,7 @@ function saveBookmarkWithPolicy(url, title, folderId, note, options) {
|
|
|
10815
11172
|
if (note !== void 0) {
|
|
10816
11173
|
bookmark2.note = note.trim() || void 0;
|
|
10817
11174
|
}
|
|
10818
|
-
|
|
10819
|
-
Object.assign(bookmark2, options.extra);
|
|
10820
|
-
}
|
|
11175
|
+
assignDefinedBookmarkFields(bookmark2, options?.extra);
|
|
10821
11176
|
bookmark2.savedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
10822
11177
|
save();
|
|
10823
11178
|
emit();
|
|
@@ -10859,6 +11214,12 @@ function updateBookmark(id, updates) {
|
|
|
10859
11214
|
load$1();
|
|
10860
11215
|
const bookmark = state$1.bookmarks.find((item) => item.id === id);
|
|
10861
11216
|
if (!bookmark) return null;
|
|
11217
|
+
const metadataUpdates = normalizeBookmarkMetadataUpdate({
|
|
11218
|
+
intent: updates.intent,
|
|
11219
|
+
expectedContent: updates.expectedContent,
|
|
11220
|
+
keyFields: updates.keyFields,
|
|
11221
|
+
agentHints: updates.agentHints
|
|
11222
|
+
});
|
|
10862
11223
|
if (typeof updates.title === "string") {
|
|
10863
11224
|
const trimmed = updates.title.trim();
|
|
10864
11225
|
bookmark.title = trimmed || bookmark.url;
|
|
@@ -10870,20 +11231,20 @@ function updateBookmark(id, updates) {
|
|
|
10870
11231
|
if (typeof updates.folderId === "string") {
|
|
10871
11232
|
bookmark.folderId = updates.folderId && updates.folderId !== UNSORTED_ID ? state$1.folders.find((item) => item.id === updates.folderId)?.id ?? UNSORTED_ID : UNSORTED_ID;
|
|
10872
11233
|
}
|
|
10873
|
-
if (
|
|
10874
|
-
bookmark.intent =
|
|
11234
|
+
if ("intent" in metadataUpdates) {
|
|
11235
|
+
bookmark.intent = metadataUpdates.intent;
|
|
10875
11236
|
}
|
|
10876
|
-
if (
|
|
10877
|
-
bookmark.expectedContent =
|
|
11237
|
+
if ("expectedContent" in metadataUpdates) {
|
|
11238
|
+
bookmark.expectedContent = metadataUpdates.expectedContent;
|
|
10878
11239
|
}
|
|
10879
|
-
if (
|
|
10880
|
-
bookmark.keyFields =
|
|
11240
|
+
if ("keyFields" in metadataUpdates) {
|
|
11241
|
+
bookmark.keyFields = metadataUpdates.keyFields;
|
|
10881
11242
|
}
|
|
10882
11243
|
if (updates.pageSchema !== void 0) {
|
|
10883
11244
|
bookmark.pageSchema = updates.pageSchema;
|
|
10884
11245
|
}
|
|
10885
|
-
if (
|
|
10886
|
-
bookmark.agentHints =
|
|
11246
|
+
if ("agentHints" in metadataUpdates) {
|
|
11247
|
+
bookmark.agentHints = metadataUpdates.agentHints;
|
|
10887
11248
|
}
|
|
10888
11249
|
save();
|
|
10889
11250
|
emit();
|
|
@@ -11878,33 +12239,6 @@ function formatCompactToolResult(name, result) {
|
|
|
11878
12239
|
return limitText(result, 18, 1400);
|
|
11879
12240
|
}
|
|
11880
12241
|
}
|
|
11881
|
-
function normalizeOptionalString(value) {
|
|
11882
|
-
if (typeof value !== "string") return void 0;
|
|
11883
|
-
const trimmed = value.trim();
|
|
11884
|
-
return trimmed || void 0;
|
|
11885
|
-
}
|
|
11886
|
-
function normalizeKeyFields(value) {
|
|
11887
|
-
if (!Array.isArray(value)) return void 0;
|
|
11888
|
-
const normalized = value.filter((field) => typeof field === "string").map((field) => field.trim()).filter(Boolean);
|
|
11889
|
-
return normalized.length > 0 ? normalized : void 0;
|
|
11890
|
-
}
|
|
11891
|
-
function normalizeAgentHints(value) {
|
|
11892
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
11893
|
-
return void 0;
|
|
11894
|
-
}
|
|
11895
|
-
const normalized = Object.fromEntries(
|
|
11896
|
-
Object.entries(value).map(([key, hint]) => [key.trim(), normalizeOptionalString(hint)]).filter((entry) => Boolean(entry[0] && entry[1]))
|
|
11897
|
-
);
|
|
11898
|
-
return Object.keys(normalized).length > 0 ? normalized : void 0;
|
|
11899
|
-
}
|
|
11900
|
-
function normalizeBookmarkMetadata(input) {
|
|
11901
|
-
return {
|
|
11902
|
-
intent: normalizeOptionalString(input.intent),
|
|
11903
|
-
expectedContent: normalizeOptionalString(input.expectedContent),
|
|
11904
|
-
keyFields: normalizeKeyFields(input.keyFields),
|
|
11905
|
-
agentHints: normalizeAgentHints(input.agentHints)
|
|
11906
|
-
};
|
|
11907
|
-
}
|
|
11908
12242
|
const HUGGING_FACE_HUB_HOSTS = /* @__PURE__ */ new Set(["huggingface.co", "www.huggingface.co"]);
|
|
11909
12243
|
const HUGGING_FACE_MODEL_TASKS = [
|
|
11910
12244
|
{
|
|
@@ -14818,8 +15152,19 @@ function buildCommonSearchUrlShortcut(currentUrl, rawQuery) {
|
|
|
14818
15152
|
appliedFilters: existingParam ? [`updated ${existingParam} query`] : []
|
|
14819
15153
|
};
|
|
14820
15154
|
}
|
|
14821
|
-
function
|
|
14822
|
-
|
|
15155
|
+
function buildDefaultEngineShortcut(rawQuery) {
|
|
15156
|
+
const settings2 = loadSettings();
|
|
15157
|
+
const engineId = settings2.defaultSearchEngine ?? "duckduckgo";
|
|
15158
|
+
if (engineId === "none") return null;
|
|
15159
|
+
const preset = SEARCH_ENGINE_PRESETS[engineId];
|
|
15160
|
+
if (!preset) return null;
|
|
15161
|
+
const query = normalizeSearchQuery(rawQuery);
|
|
15162
|
+
if (!query) return null;
|
|
15163
|
+
return {
|
|
15164
|
+
url: preset.url + encodeURIComponent(query),
|
|
15165
|
+
source: "default search engine",
|
|
15166
|
+
appliedFilters: []
|
|
15167
|
+
};
|
|
14823
15168
|
}
|
|
14824
15169
|
async function locateSearchTarget(wc, explicitSelector) {
|
|
14825
15170
|
if (explicitSelector) {
|
|
@@ -14872,7 +15217,7 @@ async function locateSearchTarget(wc, explicitSelector) {
|
|
|
14872
15217
|
const seen = new Set();
|
|
14873
15218
|
const ordered = [];
|
|
14874
15219
|
const specific = document.querySelectorAll(
|
|
14875
|
-
'input[type="search"], input[name="q"], input[name="query"], input[name="search"], input[role="searchbox"], input[aria-label*="search" i], input[placeholder*="search" i]'
|
|
15220
|
+
'input[type="search"], input[name="q"], input[name="query"], input[name="search"], input[role="searchbox"], input[aria-label*="search" i], input[placeholder*="search" i], textarea[name="q"], textarea[name="query"], textarea[name="search"], textarea[role="searchbox"], textarea[aria-label*="search" i], textarea[placeholder*="search" i]'
|
|
14876
15221
|
);
|
|
14877
15222
|
specific.forEach((el) => {
|
|
14878
15223
|
if (!seen.has(el)) {
|
|
@@ -14880,7 +15225,7 @@ async function locateSearchTarget(wc, explicitSelector) {
|
|
|
14880
15225
|
ordered.push(el);
|
|
14881
15226
|
}
|
|
14882
15227
|
});
|
|
14883
|
-
document.querySelectorAll('input[type="text"], input:not([type])').forEach((el) => {
|
|
15228
|
+
document.querySelectorAll('input[type="text"], input:not([type]), textarea').forEach((el) => {
|
|
14884
15229
|
if (seen.has(el)) return;
|
|
14885
15230
|
const scope = nearestSearchScope(el);
|
|
14886
15231
|
if (!scope) return;
|
|
@@ -14891,9 +15236,10 @@ async function locateSearchTarget(wc, explicitSelector) {
|
|
|
14891
15236
|
}
|
|
14892
15237
|
|
|
14893
15238
|
function scoreInput(el) {
|
|
14894
|
-
if (!(el instanceof HTMLInputElement)) return -1;
|
|
15239
|
+
if (!(el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement)) return -1;
|
|
14895
15240
|
if (isDisabled(el) || !isVisible(el)) return -1;
|
|
14896
|
-
const
|
|
15241
|
+
const isTextarea = el instanceof HTMLTextAreaElement;
|
|
15242
|
+
const type = isTextarea ? "text" : normalize(el.getAttribute("type") || el.type);
|
|
14897
15243
|
if (type && !["search", "text", ""].includes(type)) return -1;
|
|
14898
15244
|
|
|
14899
15245
|
let score = 0;
|
|
@@ -15040,16 +15386,19 @@ async function searchPage(wc, args) {
|
|
|
15040
15386
|
if (looksLikeCurrentSiteNameQuery(query, wc.getURL(), wc.getTitle() || "")) {
|
|
15041
15387
|
return `Error: "${query}" looks like the current site's name, not a product query. You are already on ${wc.getURL()}. Open a section like staff picks/new releases or search for actual book titles, authors, or genres instead.`;
|
|
15042
15388
|
}
|
|
15389
|
+
const runShortcut = async (shortcut) => {
|
|
15390
|
+
const beforeUrl2 = wc.getURL();
|
|
15391
|
+
await loadPermittedUrl(wc, shortcut.url);
|
|
15392
|
+
await waitForPotentialNavigation(wc, beforeUrl2, 4e3);
|
|
15393
|
+
const afterUrl2 = wc.getURL();
|
|
15394
|
+
const applied = shortcut.appliedFilters.length > 0 ? ` (${shortcut.appliedFilters.join(", ")})` : "";
|
|
15395
|
+
const destination = shortcut.section ? ` ${shortcut.section}` : "";
|
|
15396
|
+
return `Searched "${query}" via ${shortcut.source}${destination} shortcut${applied} → ${afterUrl2}${await getPostSearchSummary(wc)}`;
|
|
15397
|
+
};
|
|
15043
15398
|
if (typeof args.selector !== "string") {
|
|
15044
|
-
const shortcut =
|
|
15399
|
+
const shortcut = buildHuggingFaceSearchShortcut(wc.getURL(), query) ?? buildCommonSearchUrlShortcut(wc.getURL(), query);
|
|
15045
15400
|
if (shortcut) {
|
|
15046
|
-
|
|
15047
|
-
await loadPermittedUrl(wc, shortcut.url);
|
|
15048
|
-
await waitForPotentialNavigation(wc, beforeUrl2, 4e3);
|
|
15049
|
-
const afterUrl2 = wc.getURL();
|
|
15050
|
-
const applied = shortcut.appliedFilters.length > 0 ? ` (${shortcut.appliedFilters.join(", ")})` : "";
|
|
15051
|
-
const destination = shortcut.section ? ` ${shortcut.section}` : "";
|
|
15052
|
-
return `Searched "${query}" via ${shortcut.source}${destination} shortcut${applied} → ${afterUrl2}${await getPostSearchSummary(wc)}`;
|
|
15401
|
+
return runShortcut(shortcut);
|
|
15053
15402
|
}
|
|
15054
15403
|
}
|
|
15055
15404
|
const searchInfo = await locateSearchTarget(
|
|
@@ -15060,6 +15409,12 @@ async function searchPage(wc, args) {
|
|
|
15060
15409
|
return pageBusyError("search");
|
|
15061
15410
|
}
|
|
15062
15411
|
if (!searchInfo?.selector) {
|
|
15412
|
+
if (typeof args.selector !== "string") {
|
|
15413
|
+
const fallback = buildDefaultEngineShortcut(query);
|
|
15414
|
+
if (fallback) {
|
|
15415
|
+
return runShortcut(fallback);
|
|
15416
|
+
}
|
|
15417
|
+
}
|
|
15063
15418
|
return 'Error: Could not find a visible search input. Try read_page(mode="visible_only") or provide a selector.';
|
|
15064
15419
|
}
|
|
15065
15420
|
const fillResult = await setElementValue(wc, searchInfo.selector, query);
|
|
@@ -16056,6 +16411,11 @@ ${flow.steps.map((s, i) => ` ${i === 0 ? "→" : " "} ${s.label}`).join("\n")}`
|
|
|
16056
16411
|
ctx.runtime.clearFlow();
|
|
16057
16412
|
return "Workflow ended.";
|
|
16058
16413
|
}
|
|
16414
|
+
case "undo_last_action": {
|
|
16415
|
+
const undone = ctx.runtime.undoLastAction();
|
|
16416
|
+
if (!undone) return "Nothing to undo. No undo snapshots available.";
|
|
16417
|
+
return `Undid action: ${undone}. Browser restored to state before that action.`;
|
|
16418
|
+
}
|
|
16059
16419
|
case "suggest": {
|
|
16060
16420
|
if (!wc) return "No active tab. Use navigate to open a page.";
|
|
16061
16421
|
let page;
|
|
@@ -20066,6 +20426,23 @@ ${flow.steps.map((s, i) => ` ${i === 0 ? "→" : " "} ${s.label}`).join("\n")}`
|
|
|
20066
20426
|
return asTextResponse("Workflow ended.");
|
|
20067
20427
|
}
|
|
20068
20428
|
);
|
|
20429
|
+
server.registerTool(
|
|
20430
|
+
"undo_last_action",
|
|
20431
|
+
{
|
|
20432
|
+
title: "Undo Last Action",
|
|
20433
|
+
description: "Undo the most recent agent action by restoring the browser to its state before that action ran. Works for click, type, submit, navigate, and similar mutating actions."
|
|
20434
|
+
},
|
|
20435
|
+
async () => {
|
|
20436
|
+
const undone = runtime2.undoLastAction();
|
|
20437
|
+
if (!undone)
|
|
20438
|
+
return asTextResponse(
|
|
20439
|
+
"Nothing to undo. No undo snapshots available."
|
|
20440
|
+
);
|
|
20441
|
+
return asTextResponse(
|
|
20442
|
+
`Undid action: ${undone}. Browser restored to state before that action.`
|
|
20443
|
+
);
|
|
20444
|
+
}
|
|
20445
|
+
);
|
|
20069
20446
|
server.registerTool(
|
|
20070
20447
|
"suggest",
|
|
20071
20448
|
{
|
|
@@ -21939,6 +22316,19 @@ function registerPageDiffHandlers(windowState, sendToRendererViews) {
|
|
|
21939
22316
|
if (!wc) return null;
|
|
21940
22317
|
return getLatestPageDiff(wc.getURL());
|
|
21941
22318
|
});
|
|
22319
|
+
electron.ipcMain.handle(Channels.PAGE_DIFF_HISTORY, () => {
|
|
22320
|
+
try {
|
|
22321
|
+
if (!isPremiumActiveState(getPremiumState())) {
|
|
22322
|
+
return { error: "Premium required" };
|
|
22323
|
+
}
|
|
22324
|
+
const activeTab = windowState.tabManager.getActiveTab();
|
|
22325
|
+
const wc = activeTab?.view.webContents;
|
|
22326
|
+
if (!wc) return [];
|
|
22327
|
+
return getPageDiffBursts(wc.getURL());
|
|
22328
|
+
} catch {
|
|
22329
|
+
return [];
|
|
22330
|
+
}
|
|
22331
|
+
});
|
|
21942
22332
|
electron.ipcMain.on(Channels.PAGE_DIFF_ACTIVITY, (event) => {
|
|
21943
22333
|
const wc = event.sender;
|
|
21944
22334
|
if (!wc || wc.isDestroyed()) return;
|
|
@@ -22299,6 +22689,20 @@ function registerIpcHandlers(windowState, runtime2) {
|
|
|
22299
22689
|
width: windowState.uiState.sidebarWidth
|
|
22300
22690
|
};
|
|
22301
22691
|
});
|
|
22692
|
+
electron.ipcMain.handle(Channels.SIDEBAR_NAVIGATE, (_, tab) => {
|
|
22693
|
+
assertString(tab, "tab");
|
|
22694
|
+
if (!windowState.uiState.sidebarOpen) {
|
|
22695
|
+
windowState.uiState.sidebarOpen = true;
|
|
22696
|
+
layoutViews(windowState);
|
|
22697
|
+
}
|
|
22698
|
+
if (!sidebarView.webContents.isDestroyed()) {
|
|
22699
|
+
sidebarView.webContents.send(Channels.SIDEBAR_NAVIGATE, tab);
|
|
22700
|
+
}
|
|
22701
|
+
return {
|
|
22702
|
+
open: windowState.uiState.sidebarOpen,
|
|
22703
|
+
width: windowState.uiState.sidebarWidth
|
|
22704
|
+
};
|
|
22705
|
+
});
|
|
22302
22706
|
electron.ipcMain.handle(Channels.SIDEBAR_RESIZE_START, () => {
|
|
22303
22707
|
sidebarResizeActive = true;
|
|
22304
22708
|
clearSidebarResizeRecoveryTimer();
|
|
@@ -22397,6 +22801,14 @@ function registerIpcHandlers(windowState, runtime2) {
|
|
|
22397
22801
|
Channels.AGENT_CHECKPOINT_RESTORE,
|
|
22398
22802
|
(_, checkpointId) => runtime2.restoreCheckpoint(checkpointId)
|
|
22399
22803
|
);
|
|
22804
|
+
electron.ipcMain.handle(
|
|
22805
|
+
Channels.AGENT_CHECKPOINT_UPDATE_NOTE,
|
|
22806
|
+
(_, checkpointId, note) => runtime2.updateCheckpointNote(checkpointId, note || "")
|
|
22807
|
+
);
|
|
22808
|
+
electron.ipcMain.handle(
|
|
22809
|
+
Channels.AGENT_UNDO_LAST_ACTION,
|
|
22810
|
+
() => runtime2.undoLastAction()
|
|
22811
|
+
);
|
|
22400
22812
|
electron.ipcMain.handle(
|
|
22401
22813
|
Channels.AGENT_SESSION_CAPTURE,
|
|
22402
22814
|
(_, note) => runtime2.captureSession(note)
|
|
@@ -22436,6 +22848,13 @@ function registerIpcHandlers(windowState, runtime2) {
|
|
|
22436
22848
|
return result.bookmark;
|
|
22437
22849
|
}
|
|
22438
22850
|
);
|
|
22851
|
+
electron.ipcMain.handle(
|
|
22852
|
+
Channels.BOOKMARK_UPDATE,
|
|
22853
|
+
(_, id, updates) => {
|
|
22854
|
+
trackBookmarkAction("save");
|
|
22855
|
+
return updateBookmark(id, updates);
|
|
22856
|
+
}
|
|
22857
|
+
);
|
|
22439
22858
|
electron.ipcMain.handle(Channels.BOOKMARK_REMOVE, (_, id) => {
|
|
22440
22859
|
trackBookmarkAction("remove");
|
|
22441
22860
|
return removeBookmark(id);
|
|
@@ -22725,6 +23144,41 @@ function registerIpcHandlers(windowState, runtime2) {
|
|
|
22725
23144
|
registerAutofillHandlers(windowState);
|
|
22726
23145
|
registerPageDiffHandlers(windowState, sendToRendererViews);
|
|
22727
23146
|
}
|
|
23147
|
+
const UNDOABLE_ACTIONS = /* @__PURE__ */ new Set([
|
|
23148
|
+
"accept_cookies",
|
|
23149
|
+
"clear_overlays",
|
|
23150
|
+
"click",
|
|
23151
|
+
"close_tab",
|
|
23152
|
+
"create_tab",
|
|
23153
|
+
"dismiss_popup",
|
|
23154
|
+
"fill_form",
|
|
23155
|
+
"focus",
|
|
23156
|
+
"go_back",
|
|
23157
|
+
"go_forward",
|
|
23158
|
+
"load_session",
|
|
23159
|
+
"login",
|
|
23160
|
+
"navigate",
|
|
23161
|
+
"open_bookmark",
|
|
23162
|
+
"paginate",
|
|
23163
|
+
"press_key",
|
|
23164
|
+
"reload",
|
|
23165
|
+
"restore_checkpoint",
|
|
23166
|
+
"scroll",
|
|
23167
|
+
"scroll_to_element",
|
|
23168
|
+
"search",
|
|
23169
|
+
"select_option",
|
|
23170
|
+
"set_ad_blocking",
|
|
23171
|
+
"submit_form",
|
|
23172
|
+
"switch_tab",
|
|
23173
|
+
"type_text"
|
|
23174
|
+
]);
|
|
23175
|
+
function isUndoableAction(name) {
|
|
23176
|
+
return UNDOABLE_ACTIONS.has(name);
|
|
23177
|
+
}
|
|
23178
|
+
function isUndoableResult(result) {
|
|
23179
|
+
const normalized = result.trim().toLowerCase();
|
|
23180
|
+
return normalized.length > 0 && !normalized.startsWith("error:") && !normalized.startsWith("nothing to ") && !normalized.startsWith("no active ") && !normalized.startsWith("action rejected:");
|
|
23181
|
+
}
|
|
22728
23182
|
function makeStep(label, status = "pending") {
|
|
22729
23183
|
return { label, status };
|
|
22730
23184
|
}
|
|
@@ -23121,6 +23575,7 @@ class AgentRuntime {
|
|
|
23121
23575
|
state;
|
|
23122
23576
|
updateListener = null;
|
|
23123
23577
|
pendingResolvers = /* @__PURE__ */ new Map();
|
|
23578
|
+
undoSnapshots = [];
|
|
23124
23579
|
setUpdateListener(listener) {
|
|
23125
23580
|
this.updateListener = listener;
|
|
23126
23581
|
if (listener) {
|
|
@@ -23130,6 +23585,8 @@ class AgentRuntime {
|
|
|
23130
23585
|
getState() {
|
|
23131
23586
|
const snapshot = clone(this.state);
|
|
23132
23587
|
snapshot.mcpStatus = getMcpStatus();
|
|
23588
|
+
snapshot.canUndo = this.canUndo();
|
|
23589
|
+
snapshot.undoInfo = this.getUndoInfo();
|
|
23133
23590
|
return snapshot;
|
|
23134
23591
|
}
|
|
23135
23592
|
onTabStateChanged() {
|
|
@@ -23137,6 +23594,21 @@ class AgentRuntime {
|
|
|
23137
23594
|
}
|
|
23138
23595
|
setApprovalMode(mode) {
|
|
23139
23596
|
this.state.supervisor.approvalMode = mode;
|
|
23597
|
+
if (mode === "auto" && !this.state.supervisor.paused) {
|
|
23598
|
+
const approvals = this.state.supervisor.pendingApprovals;
|
|
23599
|
+
if (approvals.length > 0) {
|
|
23600
|
+
const actionIds = new Set(approvals.map((approval) => approval.actionId));
|
|
23601
|
+
this.state.supervisor.pendingApprovals = [];
|
|
23602
|
+
this.state.actions = this.state.actions.map(
|
|
23603
|
+
(action) => actionIds.has(action.id) ? { ...action, status: "running", error: void 0 } : action
|
|
23604
|
+
);
|
|
23605
|
+
for (const approval of approvals) {
|
|
23606
|
+
const resolve = this.pendingResolvers.get(approval.id);
|
|
23607
|
+
this.pendingResolvers.delete(approval.id);
|
|
23608
|
+
resolve?.(true);
|
|
23609
|
+
}
|
|
23610
|
+
}
|
|
23611
|
+
}
|
|
23140
23612
|
this.emit();
|
|
23141
23613
|
return this.getState();
|
|
23142
23614
|
}
|
|
@@ -23172,6 +23644,37 @@ class AgentRuntime {
|
|
|
23172
23644
|
this.captureSession(`Restored ${checkpoint.name}`);
|
|
23173
23645
|
return clone(checkpoint);
|
|
23174
23646
|
}
|
|
23647
|
+
updateCheckpointNote(checkpointId, note) {
|
|
23648
|
+
const index = this.state.checkpoints.findIndex((item) => item.id === checkpointId);
|
|
23649
|
+
if (index === -1) return null;
|
|
23650
|
+
this.state.checkpoints[index] = {
|
|
23651
|
+
...this.state.checkpoints[index],
|
|
23652
|
+
note: note.trim() || void 0
|
|
23653
|
+
};
|
|
23654
|
+
this.emit();
|
|
23655
|
+
return clone(this.state.checkpoints[index]);
|
|
23656
|
+
}
|
|
23657
|
+
canUndo() {
|
|
23658
|
+
return this.undoSnapshots.length > 0;
|
|
23659
|
+
}
|
|
23660
|
+
getUndoInfo() {
|
|
23661
|
+
const latest = this.undoSnapshots[this.undoSnapshots.length - 1];
|
|
23662
|
+
if (!latest) return null;
|
|
23663
|
+
return { actionName: latest.actionName, capturedAt: latest.capturedAt };
|
|
23664
|
+
}
|
|
23665
|
+
undoLastAction() {
|
|
23666
|
+
const snapshot = this.undoSnapshots.at(-1);
|
|
23667
|
+
if (!snapshot) return null;
|
|
23668
|
+
try {
|
|
23669
|
+
this.tabManager.restoreSession(snapshot.snapshot);
|
|
23670
|
+
this.undoSnapshots.pop();
|
|
23671
|
+
} catch (error) {
|
|
23672
|
+
logger$3.error("Failed to restore undo snapshot", error);
|
|
23673
|
+
return null;
|
|
23674
|
+
}
|
|
23675
|
+
this.captureSession(`Undid ${snapshot.actionName}`);
|
|
23676
|
+
return snapshot.actionName;
|
|
23677
|
+
}
|
|
23175
23678
|
captureSession(note) {
|
|
23176
23679
|
const snapshot = this.tabManager.snapshotSession(note);
|
|
23177
23680
|
this.state.session = snapshot;
|
|
@@ -23321,6 +23824,7 @@ ${progress}
|
|
|
23321
23824
|
args = {},
|
|
23322
23825
|
tabId = null,
|
|
23323
23826
|
dangerous = false,
|
|
23827
|
+
undoable,
|
|
23324
23828
|
executor
|
|
23325
23829
|
}) {
|
|
23326
23830
|
const action = this.startAction({
|
|
@@ -23374,8 +23878,13 @@ ${progress}
|
|
|
23374
23878
|
streamId: transcriptStreamId,
|
|
23375
23879
|
mode: "replace"
|
|
23376
23880
|
});
|
|
23881
|
+
const shouldCaptureUndo = undoable ?? isUndoableAction(name);
|
|
23882
|
+
const undoSnapshot = shouldCaptureUndo ? this.createUndoSnapshot(name) : null;
|
|
23377
23883
|
try {
|
|
23378
23884
|
const result = await executor();
|
|
23885
|
+
if (undoSnapshot && isUndoableResult(result)) {
|
|
23886
|
+
this.pushUndoSnapshot(undoSnapshot);
|
|
23887
|
+
}
|
|
23379
23888
|
this.finishAction(action.id, "completed", summarizeText(result));
|
|
23380
23889
|
this.publishTranscript({
|
|
23381
23890
|
source,
|
|
@@ -23402,6 +23911,21 @@ ${progress}
|
|
|
23402
23911
|
throw error;
|
|
23403
23912
|
}
|
|
23404
23913
|
}
|
|
23914
|
+
createUndoSnapshot(name) {
|
|
23915
|
+
return {
|
|
23916
|
+
id: crypto$2.randomUUID(),
|
|
23917
|
+
actionName: name,
|
|
23918
|
+
snapshot: this.tabManager.snapshotSession(
|
|
23919
|
+
`Auto-checkpoint before ${name}`
|
|
23920
|
+
),
|
|
23921
|
+
capturedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
23922
|
+
};
|
|
23923
|
+
}
|
|
23924
|
+
pushUndoSnapshot(snapshot) {
|
|
23925
|
+
this.undoSnapshots = [...this.undoSnapshots, snapshot].slice(
|
|
23926
|
+
-10
|
|
23927
|
+
);
|
|
23928
|
+
}
|
|
23405
23929
|
resolveApproval(approvalId, approved) {
|
|
23406
23930
|
const approval = this.state.supervisor.pendingApprovals.find(
|
|
23407
23931
|
(item) => item.id === approvalId
|
|
@@ -23983,6 +24507,11 @@ function closeSplash(splash, delayMs = 0) {
|
|
|
23983
24507
|
}
|
|
23984
24508
|
const logger = createLogger("Bootstrap");
|
|
23985
24509
|
let runtime = null;
|
|
24510
|
+
function configureUserAgent() {
|
|
24511
|
+
const originalUA = electron.session.defaultSession.getUserAgent();
|
|
24512
|
+
const maskedUA = originalUA.replace(/ Electron\/[^\s]+/, "") + " Vessel/" + electron.app.getVersion();
|
|
24513
|
+
electron.session.defaultSession.setUserAgent(maskedUA);
|
|
24514
|
+
}
|
|
23986
24515
|
function checkWritableUserData(userDataPath) {
|
|
23987
24516
|
const issues = [];
|
|
23988
24517
|
try {
|
|
@@ -24046,6 +24575,7 @@ Action: Open Settings (Ctrl+,) to choose a different port, then save to restart
|
|
|
24046
24575
|
});
|
|
24047
24576
|
}
|
|
24048
24577
|
async function bootstrap() {
|
|
24578
|
+
configureUserAgent();
|
|
24049
24579
|
const splash = createSplashWindow();
|
|
24050
24580
|
const settings2 = loadSettings();
|
|
24051
24581
|
const userDataPath = electron.app.getPath("userData");
|