@quanta-intellect/vessel-browser 0.1.67 → 0.1.68
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 +364 -62
- package/out/preload/index.js +17 -2
- package/out/renderer/assets/{index-BQjjFSb1.js → index-BCEB2epC.js} +745 -406
- 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
|
@@ -74,7 +74,7 @@ const defaults = {
|
|
|
74
74
|
expiresAt: ""
|
|
75
75
|
}
|
|
76
76
|
};
|
|
77
|
-
const SAVE_DEBOUNCE_MS$
|
|
77
|
+
const SAVE_DEBOUNCE_MS$6 = 150;
|
|
78
78
|
const CHAT_PROVIDER_SECRET_FILENAME = "vessel-chat-provider-secret";
|
|
79
79
|
const logger$j = createLogger("Settings");
|
|
80
80
|
const SETTABLE_KEYS = new Set(Object.keys(defaults));
|
|
@@ -232,7 +232,7 @@ function saveSettings() {
|
|
|
232
232
|
if (saveDirty) {
|
|
233
233
|
void persistNow();
|
|
234
234
|
}
|
|
235
|
-
}, SAVE_DEBOUNCE_MS$
|
|
235
|
+
}, SAVE_DEBOUNCE_MS$6);
|
|
236
236
|
}
|
|
237
237
|
function setSetting(key, value) {
|
|
238
238
|
loadSettings();
|
|
@@ -871,7 +871,7 @@ function createDebouncedJsonPersistence({
|
|
|
871
871
|
}
|
|
872
872
|
let state$4 = null;
|
|
873
873
|
const listeners$2 = /* @__PURE__ */ new Set();
|
|
874
|
-
const SAVE_DEBOUNCE_MS$
|
|
874
|
+
const SAVE_DEBOUNCE_MS$5 = 250;
|
|
875
875
|
function getHighlightsPath() {
|
|
876
876
|
return path.join(electron.app.getPath("userData"), "vessel-highlights.json");
|
|
877
877
|
}
|
|
@@ -889,15 +889,15 @@ function load$4() {
|
|
|
889
889
|
});
|
|
890
890
|
return state$4;
|
|
891
891
|
}
|
|
892
|
-
const persistence$
|
|
893
|
-
debounceMs: SAVE_DEBOUNCE_MS$
|
|
892
|
+
const persistence$5 = createDebouncedJsonPersistence({
|
|
893
|
+
debounceMs: SAVE_DEBOUNCE_MS$5,
|
|
894
894
|
filePath: getHighlightsPath(),
|
|
895
895
|
getValue: () => state$4,
|
|
896
896
|
logLabel: "highlights",
|
|
897
897
|
resetOnSchedule: true
|
|
898
898
|
});
|
|
899
899
|
function save$2() {
|
|
900
|
-
persistence$
|
|
900
|
+
persistence$5.schedule();
|
|
901
901
|
}
|
|
902
902
|
function emit$2() {
|
|
903
903
|
if (!state$4) return;
|
|
@@ -979,7 +979,7 @@ function clearHighlightsForUrl(url) {
|
|
|
979
979
|
return removed;
|
|
980
980
|
}
|
|
981
981
|
function flushPersist$4() {
|
|
982
|
-
return persistence$
|
|
982
|
+
return persistence$5.flush();
|
|
983
983
|
}
|
|
984
984
|
const SKIP_TAGS_JS = "var SKIP_TAGS = {SCRIPT:1,STYLE:1,NOSCRIPT:1,TEMPLATE:1,IFRAME:1,SVG:1};";
|
|
985
985
|
const CONTENT_ROOTS_JS = `
|
|
@@ -1551,7 +1551,7 @@ function persistHighlight(url, text) {
|
|
|
1551
1551
|
return { success: true, text: capped, id: highlight.id };
|
|
1552
1552
|
}
|
|
1553
1553
|
const MAX_HISTORY_ENTRIES = 5e3;
|
|
1554
|
-
const SAVE_DEBOUNCE_MS$
|
|
1554
|
+
const SAVE_DEBOUNCE_MS$4 = 250;
|
|
1555
1555
|
let state$3 = null;
|
|
1556
1556
|
const listeners$1 = /* @__PURE__ */ new Set();
|
|
1557
1557
|
function getHistoryPath() {
|
|
@@ -1571,14 +1571,14 @@ function load$3() {
|
|
|
1571
1571
|
});
|
|
1572
1572
|
return state$3;
|
|
1573
1573
|
}
|
|
1574
|
-
const persistence$
|
|
1575
|
-
debounceMs: SAVE_DEBOUNCE_MS$
|
|
1574
|
+
const persistence$4 = createDebouncedJsonPersistence({
|
|
1575
|
+
debounceMs: SAVE_DEBOUNCE_MS$4,
|
|
1576
1576
|
filePath: getHistoryPath(),
|
|
1577
1577
|
getValue: () => state$3,
|
|
1578
1578
|
logLabel: "history"
|
|
1579
1579
|
});
|
|
1580
1580
|
function save$1() {
|
|
1581
|
-
persistence$
|
|
1581
|
+
persistence$4.schedule();
|
|
1582
1582
|
}
|
|
1583
1583
|
function emit$1() {
|
|
1584
1584
|
if (!state$3) return;
|
|
@@ -1635,7 +1635,7 @@ function clearAll$1() {
|
|
|
1635
1635
|
emit$1();
|
|
1636
1636
|
}
|
|
1637
1637
|
function flushPersist$3() {
|
|
1638
|
-
return persistence$
|
|
1638
|
+
return persistence$4.flush();
|
|
1639
1639
|
}
|
|
1640
1640
|
const MAX_CONSOLE_ENTRIES = 500;
|
|
1641
1641
|
const MAX_NETWORK_ENTRIES = 200;
|
|
@@ -2684,6 +2684,8 @@ const Channels = {
|
|
|
2684
2684
|
AGENT_APPROVAL_RESOLVE: "agent:approval-resolve",
|
|
2685
2685
|
AGENT_CHECKPOINT_CREATE: "agent:checkpoint-create",
|
|
2686
2686
|
AGENT_CHECKPOINT_RESTORE: "agent:checkpoint-restore",
|
|
2687
|
+
AGENT_CHECKPOINT_UPDATE_NOTE: "agent:checkpoint-update-note",
|
|
2688
|
+
AGENT_UNDO_LAST_ACTION: "agent:undo-last-action",
|
|
2687
2689
|
AGENT_SESSION_CAPTURE: "agent:session-capture",
|
|
2688
2690
|
AGENT_SESSION_RESTORE: "agent:session-restore",
|
|
2689
2691
|
// Content
|
|
@@ -2691,6 +2693,7 @@ const Channels = {
|
|
|
2691
2693
|
READER_MODE_TOGGLE: "reader:toggle",
|
|
2692
2694
|
// UI state
|
|
2693
2695
|
SIDEBAR_TOGGLE: "ui:sidebar-toggle",
|
|
2696
|
+
SIDEBAR_NAVIGATE: "ui:sidebar-navigate",
|
|
2694
2697
|
SIDEBAR_RESIZE: "ui:sidebar-resize",
|
|
2695
2698
|
SIDEBAR_RESIZE_START: "ui:sidebar-resize-start",
|
|
2696
2699
|
SIDEBAR_RESIZE_COMMIT: "ui:sidebar-resize-commit",
|
|
@@ -2707,6 +2710,7 @@ const Channels = {
|
|
|
2707
2710
|
BOOKMARKS_GET: "bookmarks:get",
|
|
2708
2711
|
BOOKMARKS_UPDATE: "bookmarks:update",
|
|
2709
2712
|
BOOKMARK_SAVE: "bookmarks:save",
|
|
2713
|
+
BOOKMARK_UPDATE: "bookmarks:update-item",
|
|
2710
2714
|
BOOKMARK_REMOVE: "bookmarks:remove",
|
|
2711
2715
|
BOOKMARK_ADD_CONTEXT_TO_CHAT: "bookmarks:add-context-to-chat",
|
|
2712
2716
|
FOLDER_CREATE: "bookmarks:folder-create",
|
|
@@ -2786,6 +2790,7 @@ const Channels = {
|
|
|
2786
2790
|
PAGE_DIFF_ACTIVITY: "page:diff-activity",
|
|
2787
2791
|
PAGE_CHANGED: "page:changed",
|
|
2788
2792
|
PAGE_DIFF_GET: "page:diff-get",
|
|
2793
|
+
PAGE_DIFF_HISTORY: "page:diff-history",
|
|
2789
2794
|
PAGE_DIFF_DIRTY: "page:diff-dirty"
|
|
2790
2795
|
};
|
|
2791
2796
|
const MAX_DETAIL_ITEMS = 3;
|
|
@@ -3101,7 +3106,7 @@ function isTrackablePageUrl(rawUrl) {
|
|
|
3101
3106
|
return false;
|
|
3102
3107
|
}
|
|
3103
3108
|
}
|
|
3104
|
-
const SAVE_DEBOUNCE_MS$
|
|
3109
|
+
const SAVE_DEBOUNCE_MS$3 = 500;
|
|
3105
3110
|
const MAX_TEXT_LENGTH = 8e3;
|
|
3106
3111
|
let snapshots = null;
|
|
3107
3112
|
function getFilePath$1() {
|
|
@@ -3139,8 +3144,8 @@ function load$2() {
|
|
|
3139
3144
|
});
|
|
3140
3145
|
return snapshots;
|
|
3141
3146
|
}
|
|
3142
|
-
const persistence$
|
|
3143
|
-
debounceMs: SAVE_DEBOUNCE_MS$
|
|
3147
|
+
const persistence$3 = createDebouncedJsonPersistence({
|
|
3148
|
+
debounceMs: SAVE_DEBOUNCE_MS$3,
|
|
3144
3149
|
filePath: getFilePath$1(),
|
|
3145
3150
|
getValue: () => snapshots,
|
|
3146
3151
|
logLabel: "page snapshots",
|
|
@@ -3168,11 +3173,11 @@ function saveSnapshot(rawUrl, title, textContent, headings) {
|
|
|
3168
3173
|
};
|
|
3169
3174
|
s.delete(key);
|
|
3170
3175
|
s.set(key, snapshot);
|
|
3171
|
-
persistence$
|
|
3176
|
+
persistence$3.schedule();
|
|
3172
3177
|
return snapshot;
|
|
3173
3178
|
}
|
|
3174
3179
|
function flushPersist$2() {
|
|
3175
|
-
return persistence$
|
|
3180
|
+
return persistence$3.flush();
|
|
3176
3181
|
}
|
|
3177
3182
|
const SEARCH_ENGINE_HOSTS = [
|
|
3178
3183
|
"google.",
|
|
@@ -5355,8 +5360,32 @@ function normalizePageContent(value) {
|
|
|
5355
5360
|
pageSchema: page.pageSchema
|
|
5356
5361
|
};
|
|
5357
5362
|
}
|
|
5363
|
+
function normalizePageDiffHistoryItem(value) {
|
|
5364
|
+
if (!value || typeof value !== "object") return null;
|
|
5365
|
+
const raw = value;
|
|
5366
|
+
if (typeof raw.detectedAt !== "string" || typeof raw.summary !== "string") {
|
|
5367
|
+
return null;
|
|
5368
|
+
}
|
|
5369
|
+
return {
|
|
5370
|
+
detectedAt: raw.detectedAt,
|
|
5371
|
+
summary: raw.summary
|
|
5372
|
+
};
|
|
5373
|
+
}
|
|
5374
|
+
function prunePageDiffHistory(items, options) {
|
|
5375
|
+
const cutoff = (options.now ?? Date.now()) - options.maxAgeDays * 24 * 60 * 60 * 1e3;
|
|
5376
|
+
return items.filter((item) => {
|
|
5377
|
+
const detectedAt = Date.parse(item.detectedAt);
|
|
5378
|
+
return Number.isFinite(detectedAt) && detectedAt >= cutoff;
|
|
5379
|
+
}).sort(
|
|
5380
|
+
(left, right) => Date.parse(left.detectedAt) - Date.parse(right.detectedAt)
|
|
5381
|
+
).slice(-options.maxItems);
|
|
5382
|
+
}
|
|
5383
|
+
function appendPageDiffHistoryItem(items, next, options) {
|
|
5384
|
+
return prunePageDiffHistory([...items, next], options);
|
|
5385
|
+
}
|
|
5358
5386
|
const latestPageDiffs = /* @__PURE__ */ new Map();
|
|
5359
5387
|
const recentPageDiffBursts = /* @__PURE__ */ new Map();
|
|
5388
|
+
let historyLoaded = false;
|
|
5360
5389
|
const pendingPageSnapshotTimers = /* @__PURE__ */ new Map();
|
|
5361
5390
|
const pendingPageSnapshotDueAt = /* @__PURE__ */ new Map();
|
|
5362
5391
|
const lastMutationSnapshotAt = /* @__PURE__ */ new Map();
|
|
@@ -5377,10 +5406,81 @@ function attachDestroyCleanup(wc) {
|
|
|
5377
5406
|
cleanupTimersForWcId(wc.id);
|
|
5378
5407
|
});
|
|
5379
5408
|
}
|
|
5409
|
+
const MAX_PERSISTED_DIFF_BURSTS = 50;
|
|
5410
|
+
const MAX_HISTORY_DAYS = 30;
|
|
5411
|
+
const SAVE_DEBOUNCE_MS$2 = 500;
|
|
5412
|
+
function getHistoryFilePath() {
|
|
5413
|
+
return path.join(electron.app.getPath("userData"), "vessel-page-diff-history.json");
|
|
5414
|
+
}
|
|
5415
|
+
function loadHistory() {
|
|
5416
|
+
if (historyLoaded) return recentPageDiffBursts;
|
|
5417
|
+
historyLoaded = true;
|
|
5418
|
+
const loaded = loadJsonFile({
|
|
5419
|
+
filePath: getHistoryFilePath(),
|
|
5420
|
+
fallback: /* @__PURE__ */ new Map(),
|
|
5421
|
+
secure: true,
|
|
5422
|
+
parse: (raw) => {
|
|
5423
|
+
const next = /* @__PURE__ */ new Map();
|
|
5424
|
+
if (!Array.isArray(raw)) return next;
|
|
5425
|
+
for (const entry of raw) {
|
|
5426
|
+
if (!entry || typeof entry !== "object") continue;
|
|
5427
|
+
const record = entry;
|
|
5428
|
+
if (typeof record.url !== "string" || !Array.isArray(record.bursts)) {
|
|
5429
|
+
continue;
|
|
5430
|
+
}
|
|
5431
|
+
next.set(
|
|
5432
|
+
record.url,
|
|
5433
|
+
prunePageDiffHistory(
|
|
5434
|
+
record.bursts.map((item) => normalizePageDiffHistoryItem(item)).filter((item) => item !== null),
|
|
5435
|
+
{
|
|
5436
|
+
maxAgeDays: MAX_HISTORY_DAYS,
|
|
5437
|
+
maxItems: MAX_PERSISTED_DIFF_BURSTS
|
|
5438
|
+
}
|
|
5439
|
+
)
|
|
5440
|
+
);
|
|
5441
|
+
}
|
|
5442
|
+
return next;
|
|
5443
|
+
}
|
|
5444
|
+
});
|
|
5445
|
+
for (const [key, bursts] of loaded.entries()) {
|
|
5446
|
+
recentPageDiffBursts.set(key, bursts);
|
|
5447
|
+
}
|
|
5448
|
+
return recentPageDiffBursts;
|
|
5449
|
+
}
|
|
5450
|
+
const persistence$2 = createDebouncedJsonPersistence({
|
|
5451
|
+
debounceMs: SAVE_DEBOUNCE_MS$2,
|
|
5452
|
+
filePath: getHistoryFilePath(),
|
|
5453
|
+
getValue: () => recentPageDiffBursts,
|
|
5454
|
+
logLabel: "page diff history",
|
|
5455
|
+
secure: true,
|
|
5456
|
+
serialize: (value) => Array.from(value.entries()).map(([url, bursts]) => ({
|
|
5457
|
+
url,
|
|
5458
|
+
bursts
|
|
5459
|
+
}))
|
|
5460
|
+
});
|
|
5380
5461
|
function getLatestPageDiff(rawUrl) {
|
|
5381
5462
|
if (!shouldTrackSnapshotUrl(rawUrl)) return null;
|
|
5382
5463
|
return latestPageDiffs.get(normalizeUrl(rawUrl)) ?? null;
|
|
5383
5464
|
}
|
|
5465
|
+
function getPageDiffBursts(rawUrl) {
|
|
5466
|
+
if (!shouldTrackSnapshotUrl(rawUrl)) return [];
|
|
5467
|
+
const key = normalizeUrl(rawUrl);
|
|
5468
|
+
const history = loadHistory();
|
|
5469
|
+
const bursts = prunePageDiffHistory(history.get(key) ?? [], {
|
|
5470
|
+
maxAgeDays: MAX_HISTORY_DAYS,
|
|
5471
|
+
maxItems: MAX_PERSISTED_DIFF_BURSTS
|
|
5472
|
+
});
|
|
5473
|
+
const current = history.get(key) ?? [];
|
|
5474
|
+
if (current.length !== bursts.length) {
|
|
5475
|
+
if (bursts.length > 0) {
|
|
5476
|
+
history.set(key, bursts);
|
|
5477
|
+
} else {
|
|
5478
|
+
history.delete(key);
|
|
5479
|
+
}
|
|
5480
|
+
persistence$2.schedule();
|
|
5481
|
+
}
|
|
5482
|
+
return bursts.slice().reverse();
|
|
5483
|
+
}
|
|
5384
5484
|
function summarizeDiffBurst(diff) {
|
|
5385
5485
|
const items = diff.changes.slice(0, 2).map((change) => `${change.section}: ${change.summary}`);
|
|
5386
5486
|
return items.join(" | ");
|
|
@@ -5391,16 +5491,21 @@ function enrichWithBurstHistory(key, diff) {
|
|
|
5391
5491
|
detectedAt,
|
|
5392
5492
|
summary: summarizeDiffBurst(diff)
|
|
5393
5493
|
};
|
|
5394
|
-
const
|
|
5395
|
-
|
|
5396
|
-
|
|
5397
|
-
|
|
5494
|
+
const history = loadHistory();
|
|
5495
|
+
const bursts = appendPageDiffHistoryItem(history.get(key) ?? [], nextBurst, {
|
|
5496
|
+
maxAgeDays: MAX_HISTORY_DAYS,
|
|
5497
|
+
maxItems: MAX_PERSISTED_DIFF_BURSTS,
|
|
5498
|
+
now: Date.parse(detectedAt)
|
|
5499
|
+
});
|
|
5500
|
+
history.set(key, bursts);
|
|
5501
|
+
persistence$2.schedule();
|
|
5502
|
+
const recentBursts = bursts.slice(-5);
|
|
5398
5503
|
return {
|
|
5399
5504
|
...diff,
|
|
5400
5505
|
burstCount: bursts.length,
|
|
5401
5506
|
firstDetectedAt: bursts[0]?.detectedAt,
|
|
5402
5507
|
lastDetectedAt: bursts[bursts.length - 1]?.detectedAt,
|
|
5403
|
-
recentBursts:
|
|
5508
|
+
recentBursts: recentBursts.slice().reverse()
|
|
5404
5509
|
};
|
|
5405
5510
|
}
|
|
5406
5511
|
async function capturePageSnapshot(url, wc, sendToRendererViews) {
|
|
@@ -5421,11 +5526,9 @@ async function capturePageSnapshot(url, wc, sendToRendererViews) {
|
|
|
5421
5526
|
sendToRendererViews(Channels.PAGE_CHANGED, enrichedDiff);
|
|
5422
5527
|
} else {
|
|
5423
5528
|
latestPageDiffs.delete(key);
|
|
5424
|
-
recentPageDiffBursts.delete(key);
|
|
5425
5529
|
}
|
|
5426
5530
|
} else {
|
|
5427
5531
|
latestPageDiffs.delete(key);
|
|
5428
|
-
recentPageDiffBursts.delete(key);
|
|
5429
5532
|
}
|
|
5430
5533
|
saveSnapshot(url, title, textContent, headings);
|
|
5431
5534
|
} catch {
|
|
@@ -10080,6 +10183,13 @@ const TOOL_DEFINITIONS = [
|
|
|
10080
10183
|
tier: 2,
|
|
10081
10184
|
hiddenByDefault: true
|
|
10082
10185
|
},
|
|
10186
|
+
// --- Undo ---
|
|
10187
|
+
{
|
|
10188
|
+
name: "undo_last_action",
|
|
10189
|
+
title: "Undo Last Action",
|
|
10190
|
+
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.",
|
|
10191
|
+
tier: 1
|
|
10192
|
+
},
|
|
10083
10193
|
// --- Speedee System: Suggestion Engine ---
|
|
10084
10194
|
{
|
|
10085
10195
|
name: "suggest",
|
|
@@ -10604,6 +10714,60 @@ function getBookmarkSearchMatch(args) {
|
|
|
10604
10714
|
}
|
|
10605
10715
|
return { matchedFields, score };
|
|
10606
10716
|
}
|
|
10717
|
+
function normalizeOptionalString(value) {
|
|
10718
|
+
if (typeof value !== "string") return void 0;
|
|
10719
|
+
const trimmed = value.trim();
|
|
10720
|
+
return trimmed || void 0;
|
|
10721
|
+
}
|
|
10722
|
+
function normalizeKeyFields(value) {
|
|
10723
|
+
if (!Array.isArray(value)) return void 0;
|
|
10724
|
+
const normalized = value.filter((field) => typeof field === "string").map((field) => field.trim()).filter(Boolean);
|
|
10725
|
+
return normalized.length > 0 ? normalized : void 0;
|
|
10726
|
+
}
|
|
10727
|
+
function normalizeAgentHints(value) {
|
|
10728
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
10729
|
+
return void 0;
|
|
10730
|
+
}
|
|
10731
|
+
const normalized = Object.fromEntries(
|
|
10732
|
+
Object.entries(value).map(([key, hint]) => [key.trim(), normalizeOptionalString(hint)]).filter((entry) => Boolean(entry[0] && entry[1]))
|
|
10733
|
+
);
|
|
10734
|
+
return Object.keys(normalized).length > 0 ? normalized : void 0;
|
|
10735
|
+
}
|
|
10736
|
+
function hasOwn(value, key) {
|
|
10737
|
+
return Object.prototype.hasOwnProperty.call(value, key);
|
|
10738
|
+
}
|
|
10739
|
+
function normalizeBookmarkMetadata(input) {
|
|
10740
|
+
const normalized = {};
|
|
10741
|
+
const intent = normalizeOptionalString(input.intent);
|
|
10742
|
+
const expectedContent = normalizeOptionalString(input.expectedContent);
|
|
10743
|
+
const keyFields = normalizeKeyFields(input.keyFields);
|
|
10744
|
+
const agentHints = normalizeAgentHints(input.agentHints);
|
|
10745
|
+
if (intent !== void 0) normalized.intent = intent;
|
|
10746
|
+
if (expectedContent !== void 0) {
|
|
10747
|
+
normalized.expectedContent = expectedContent;
|
|
10748
|
+
}
|
|
10749
|
+
if (keyFields !== void 0) normalized.keyFields = keyFields;
|
|
10750
|
+
if (agentHints !== void 0) normalized.agentHints = agentHints;
|
|
10751
|
+
return normalized;
|
|
10752
|
+
}
|
|
10753
|
+
function normalizeBookmarkMetadataUpdate(input) {
|
|
10754
|
+
const normalized = {};
|
|
10755
|
+
if (hasOwn(input, "intent")) {
|
|
10756
|
+
normalized.intent = normalizeOptionalString(input.intent);
|
|
10757
|
+
}
|
|
10758
|
+
if (hasOwn(input, "expectedContent")) {
|
|
10759
|
+
normalized.expectedContent = normalizeOptionalString(
|
|
10760
|
+
input.expectedContent
|
|
10761
|
+
);
|
|
10762
|
+
}
|
|
10763
|
+
if (hasOwn(input, "keyFields")) {
|
|
10764
|
+
normalized.keyFields = normalizeKeyFields(input.keyFields);
|
|
10765
|
+
}
|
|
10766
|
+
if (hasOwn(input, "agentHints")) {
|
|
10767
|
+
normalized.agentHints = normalizeAgentHints(input.agentHints);
|
|
10768
|
+
}
|
|
10769
|
+
return normalized;
|
|
10770
|
+
}
|
|
10607
10771
|
const UNSORTED_ID = "unsorted";
|
|
10608
10772
|
const ARCHIVE_FOLDER_NAME = "Archive";
|
|
10609
10773
|
const SAVE_DEBOUNCE_MS$1 = 250;
|
|
@@ -10642,6 +10806,13 @@ const persistence$1 = createDebouncedJsonPersistence({
|
|
|
10642
10806
|
function save() {
|
|
10643
10807
|
persistence$1.schedule();
|
|
10644
10808
|
}
|
|
10809
|
+
function assignDefinedBookmarkFields(bookmark, fields) {
|
|
10810
|
+
if (!fields) return;
|
|
10811
|
+
for (const [key, value] of Object.entries(fields)) {
|
|
10812
|
+
if (value === void 0) continue;
|
|
10813
|
+
Object.assign(bookmark, { [key]: value });
|
|
10814
|
+
}
|
|
10815
|
+
}
|
|
10645
10816
|
function emit() {
|
|
10646
10817
|
if (!state$1) return;
|
|
10647
10818
|
const snapshot = cloneState(state$1);
|
|
@@ -10815,9 +10986,7 @@ function saveBookmarkWithPolicy(url, title, folderId, note, options) {
|
|
|
10815
10986
|
if (note !== void 0) {
|
|
10816
10987
|
bookmark2.note = note.trim() || void 0;
|
|
10817
10988
|
}
|
|
10818
|
-
|
|
10819
|
-
Object.assign(bookmark2, options.extra);
|
|
10820
|
-
}
|
|
10989
|
+
assignDefinedBookmarkFields(bookmark2, options?.extra);
|
|
10821
10990
|
bookmark2.savedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
10822
10991
|
save();
|
|
10823
10992
|
emit();
|
|
@@ -10859,6 +11028,12 @@ function updateBookmark(id, updates) {
|
|
|
10859
11028
|
load$1();
|
|
10860
11029
|
const bookmark = state$1.bookmarks.find((item) => item.id === id);
|
|
10861
11030
|
if (!bookmark) return null;
|
|
11031
|
+
const metadataUpdates = normalizeBookmarkMetadataUpdate({
|
|
11032
|
+
intent: updates.intent,
|
|
11033
|
+
expectedContent: updates.expectedContent,
|
|
11034
|
+
keyFields: updates.keyFields,
|
|
11035
|
+
agentHints: updates.agentHints
|
|
11036
|
+
});
|
|
10862
11037
|
if (typeof updates.title === "string") {
|
|
10863
11038
|
const trimmed = updates.title.trim();
|
|
10864
11039
|
bookmark.title = trimmed || bookmark.url;
|
|
@@ -10870,20 +11045,20 @@ function updateBookmark(id, updates) {
|
|
|
10870
11045
|
if (typeof updates.folderId === "string") {
|
|
10871
11046
|
bookmark.folderId = updates.folderId && updates.folderId !== UNSORTED_ID ? state$1.folders.find((item) => item.id === updates.folderId)?.id ?? UNSORTED_ID : UNSORTED_ID;
|
|
10872
11047
|
}
|
|
10873
|
-
if (
|
|
10874
|
-
bookmark.intent =
|
|
11048
|
+
if ("intent" in metadataUpdates) {
|
|
11049
|
+
bookmark.intent = metadataUpdates.intent;
|
|
10875
11050
|
}
|
|
10876
|
-
if (
|
|
10877
|
-
bookmark.expectedContent =
|
|
11051
|
+
if ("expectedContent" in metadataUpdates) {
|
|
11052
|
+
bookmark.expectedContent = metadataUpdates.expectedContent;
|
|
10878
11053
|
}
|
|
10879
|
-
if (
|
|
10880
|
-
bookmark.keyFields =
|
|
11054
|
+
if ("keyFields" in metadataUpdates) {
|
|
11055
|
+
bookmark.keyFields = metadataUpdates.keyFields;
|
|
10881
11056
|
}
|
|
10882
11057
|
if (updates.pageSchema !== void 0) {
|
|
10883
11058
|
bookmark.pageSchema = updates.pageSchema;
|
|
10884
11059
|
}
|
|
10885
|
-
if (
|
|
10886
|
-
bookmark.agentHints =
|
|
11060
|
+
if ("agentHints" in metadataUpdates) {
|
|
11061
|
+
bookmark.agentHints = metadataUpdates.agentHints;
|
|
10887
11062
|
}
|
|
10888
11063
|
save();
|
|
10889
11064
|
emit();
|
|
@@ -11878,33 +12053,6 @@ function formatCompactToolResult(name, result) {
|
|
|
11878
12053
|
return limitText(result, 18, 1400);
|
|
11879
12054
|
}
|
|
11880
12055
|
}
|
|
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
12056
|
const HUGGING_FACE_HUB_HOSTS = /* @__PURE__ */ new Set(["huggingface.co", "www.huggingface.co"]);
|
|
11909
12057
|
const HUGGING_FACE_MODEL_TASKS = [
|
|
11910
12058
|
{
|
|
@@ -16056,6 +16204,11 @@ ${flow.steps.map((s, i) => ` ${i === 0 ? "→" : " "} ${s.label}`).join("\n")}`
|
|
|
16056
16204
|
ctx.runtime.clearFlow();
|
|
16057
16205
|
return "Workflow ended.";
|
|
16058
16206
|
}
|
|
16207
|
+
case "undo_last_action": {
|
|
16208
|
+
const undone = ctx.runtime.undoLastAction();
|
|
16209
|
+
if (!undone) return "Nothing to undo. No undo snapshots available.";
|
|
16210
|
+
return `Undid action: ${undone}. Browser restored to state before that action.`;
|
|
16211
|
+
}
|
|
16059
16212
|
case "suggest": {
|
|
16060
16213
|
if (!wc) return "No active tab. Use navigate to open a page.";
|
|
16061
16214
|
let page;
|
|
@@ -20066,6 +20219,23 @@ ${flow.steps.map((s, i) => ` ${i === 0 ? "→" : " "} ${s.label}`).join("\n")}`
|
|
|
20066
20219
|
return asTextResponse("Workflow ended.");
|
|
20067
20220
|
}
|
|
20068
20221
|
);
|
|
20222
|
+
server.registerTool(
|
|
20223
|
+
"undo_last_action",
|
|
20224
|
+
{
|
|
20225
|
+
title: "Undo Last Action",
|
|
20226
|
+
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."
|
|
20227
|
+
},
|
|
20228
|
+
async () => {
|
|
20229
|
+
const undone = runtime2.undoLastAction();
|
|
20230
|
+
if (!undone)
|
|
20231
|
+
return asTextResponse(
|
|
20232
|
+
"Nothing to undo. No undo snapshots available."
|
|
20233
|
+
);
|
|
20234
|
+
return asTextResponse(
|
|
20235
|
+
`Undid action: ${undone}. Browser restored to state before that action.`
|
|
20236
|
+
);
|
|
20237
|
+
}
|
|
20238
|
+
);
|
|
20069
20239
|
server.registerTool(
|
|
20070
20240
|
"suggest",
|
|
20071
20241
|
{
|
|
@@ -21939,6 +22109,19 @@ function registerPageDiffHandlers(windowState, sendToRendererViews) {
|
|
|
21939
22109
|
if (!wc) return null;
|
|
21940
22110
|
return getLatestPageDiff(wc.getURL());
|
|
21941
22111
|
});
|
|
22112
|
+
electron.ipcMain.handle(Channels.PAGE_DIFF_HISTORY, () => {
|
|
22113
|
+
try {
|
|
22114
|
+
if (!isPremiumActiveState(getPremiumState())) {
|
|
22115
|
+
return { error: "Premium required" };
|
|
22116
|
+
}
|
|
22117
|
+
const activeTab = windowState.tabManager.getActiveTab();
|
|
22118
|
+
const wc = activeTab?.view.webContents;
|
|
22119
|
+
if (!wc) return [];
|
|
22120
|
+
return getPageDiffBursts(wc.getURL());
|
|
22121
|
+
} catch {
|
|
22122
|
+
return [];
|
|
22123
|
+
}
|
|
22124
|
+
});
|
|
21942
22125
|
electron.ipcMain.on(Channels.PAGE_DIFF_ACTIVITY, (event) => {
|
|
21943
22126
|
const wc = event.sender;
|
|
21944
22127
|
if (!wc || wc.isDestroyed()) return;
|
|
@@ -22299,6 +22482,20 @@ function registerIpcHandlers(windowState, runtime2) {
|
|
|
22299
22482
|
width: windowState.uiState.sidebarWidth
|
|
22300
22483
|
};
|
|
22301
22484
|
});
|
|
22485
|
+
electron.ipcMain.handle(Channels.SIDEBAR_NAVIGATE, (_, tab) => {
|
|
22486
|
+
assertString(tab, "tab");
|
|
22487
|
+
if (!windowState.uiState.sidebarOpen) {
|
|
22488
|
+
windowState.uiState.sidebarOpen = true;
|
|
22489
|
+
layoutViews(windowState);
|
|
22490
|
+
}
|
|
22491
|
+
if (!sidebarView.webContents.isDestroyed()) {
|
|
22492
|
+
sidebarView.webContents.send(Channels.SIDEBAR_NAVIGATE, tab);
|
|
22493
|
+
}
|
|
22494
|
+
return {
|
|
22495
|
+
open: windowState.uiState.sidebarOpen,
|
|
22496
|
+
width: windowState.uiState.sidebarWidth
|
|
22497
|
+
};
|
|
22498
|
+
});
|
|
22302
22499
|
electron.ipcMain.handle(Channels.SIDEBAR_RESIZE_START, () => {
|
|
22303
22500
|
sidebarResizeActive = true;
|
|
22304
22501
|
clearSidebarResizeRecoveryTimer();
|
|
@@ -22397,6 +22594,14 @@ function registerIpcHandlers(windowState, runtime2) {
|
|
|
22397
22594
|
Channels.AGENT_CHECKPOINT_RESTORE,
|
|
22398
22595
|
(_, checkpointId) => runtime2.restoreCheckpoint(checkpointId)
|
|
22399
22596
|
);
|
|
22597
|
+
electron.ipcMain.handle(
|
|
22598
|
+
Channels.AGENT_CHECKPOINT_UPDATE_NOTE,
|
|
22599
|
+
(_, checkpointId, note) => runtime2.updateCheckpointNote(checkpointId, note || "")
|
|
22600
|
+
);
|
|
22601
|
+
electron.ipcMain.handle(
|
|
22602
|
+
Channels.AGENT_UNDO_LAST_ACTION,
|
|
22603
|
+
() => runtime2.undoLastAction()
|
|
22604
|
+
);
|
|
22400
22605
|
electron.ipcMain.handle(
|
|
22401
22606
|
Channels.AGENT_SESSION_CAPTURE,
|
|
22402
22607
|
(_, note) => runtime2.captureSession(note)
|
|
@@ -22436,6 +22641,13 @@ function registerIpcHandlers(windowState, runtime2) {
|
|
|
22436
22641
|
return result.bookmark;
|
|
22437
22642
|
}
|
|
22438
22643
|
);
|
|
22644
|
+
electron.ipcMain.handle(
|
|
22645
|
+
Channels.BOOKMARK_UPDATE,
|
|
22646
|
+
(_, id, updates) => {
|
|
22647
|
+
trackBookmarkAction("save");
|
|
22648
|
+
return updateBookmark(id, updates);
|
|
22649
|
+
}
|
|
22650
|
+
);
|
|
22439
22651
|
electron.ipcMain.handle(Channels.BOOKMARK_REMOVE, (_, id) => {
|
|
22440
22652
|
trackBookmarkAction("remove");
|
|
22441
22653
|
return removeBookmark(id);
|
|
@@ -22725,6 +22937,41 @@ function registerIpcHandlers(windowState, runtime2) {
|
|
|
22725
22937
|
registerAutofillHandlers(windowState);
|
|
22726
22938
|
registerPageDiffHandlers(windowState, sendToRendererViews);
|
|
22727
22939
|
}
|
|
22940
|
+
const UNDOABLE_ACTIONS = /* @__PURE__ */ new Set([
|
|
22941
|
+
"accept_cookies",
|
|
22942
|
+
"clear_overlays",
|
|
22943
|
+
"click",
|
|
22944
|
+
"close_tab",
|
|
22945
|
+
"create_tab",
|
|
22946
|
+
"dismiss_popup",
|
|
22947
|
+
"fill_form",
|
|
22948
|
+
"focus",
|
|
22949
|
+
"go_back",
|
|
22950
|
+
"go_forward",
|
|
22951
|
+
"load_session",
|
|
22952
|
+
"login",
|
|
22953
|
+
"navigate",
|
|
22954
|
+
"open_bookmark",
|
|
22955
|
+
"paginate",
|
|
22956
|
+
"press_key",
|
|
22957
|
+
"reload",
|
|
22958
|
+
"restore_checkpoint",
|
|
22959
|
+
"scroll",
|
|
22960
|
+
"scroll_to_element",
|
|
22961
|
+
"search",
|
|
22962
|
+
"select_option",
|
|
22963
|
+
"set_ad_blocking",
|
|
22964
|
+
"submit_form",
|
|
22965
|
+
"switch_tab",
|
|
22966
|
+
"type_text"
|
|
22967
|
+
]);
|
|
22968
|
+
function isUndoableAction(name) {
|
|
22969
|
+
return UNDOABLE_ACTIONS.has(name);
|
|
22970
|
+
}
|
|
22971
|
+
function isUndoableResult(result) {
|
|
22972
|
+
const normalized = result.trim().toLowerCase();
|
|
22973
|
+
return normalized.length > 0 && !normalized.startsWith("error:") && !normalized.startsWith("nothing to ") && !normalized.startsWith("no active ") && !normalized.startsWith("action rejected:");
|
|
22974
|
+
}
|
|
22728
22975
|
function makeStep(label, status = "pending") {
|
|
22729
22976
|
return { label, status };
|
|
22730
22977
|
}
|
|
@@ -23121,6 +23368,7 @@ class AgentRuntime {
|
|
|
23121
23368
|
state;
|
|
23122
23369
|
updateListener = null;
|
|
23123
23370
|
pendingResolvers = /* @__PURE__ */ new Map();
|
|
23371
|
+
undoSnapshots = [];
|
|
23124
23372
|
setUpdateListener(listener) {
|
|
23125
23373
|
this.updateListener = listener;
|
|
23126
23374
|
if (listener) {
|
|
@@ -23130,6 +23378,8 @@ class AgentRuntime {
|
|
|
23130
23378
|
getState() {
|
|
23131
23379
|
const snapshot = clone(this.state);
|
|
23132
23380
|
snapshot.mcpStatus = getMcpStatus();
|
|
23381
|
+
snapshot.canUndo = this.canUndo();
|
|
23382
|
+
snapshot.undoInfo = this.getUndoInfo();
|
|
23133
23383
|
return snapshot;
|
|
23134
23384
|
}
|
|
23135
23385
|
onTabStateChanged() {
|
|
@@ -23172,6 +23422,37 @@ class AgentRuntime {
|
|
|
23172
23422
|
this.captureSession(`Restored ${checkpoint.name}`);
|
|
23173
23423
|
return clone(checkpoint);
|
|
23174
23424
|
}
|
|
23425
|
+
updateCheckpointNote(checkpointId, note) {
|
|
23426
|
+
const index = this.state.checkpoints.findIndex((item) => item.id === checkpointId);
|
|
23427
|
+
if (index === -1) return null;
|
|
23428
|
+
this.state.checkpoints[index] = {
|
|
23429
|
+
...this.state.checkpoints[index],
|
|
23430
|
+
note: note.trim() || void 0
|
|
23431
|
+
};
|
|
23432
|
+
this.emit();
|
|
23433
|
+
return clone(this.state.checkpoints[index]);
|
|
23434
|
+
}
|
|
23435
|
+
canUndo() {
|
|
23436
|
+
return this.undoSnapshots.length > 0;
|
|
23437
|
+
}
|
|
23438
|
+
getUndoInfo() {
|
|
23439
|
+
const latest = this.undoSnapshots[this.undoSnapshots.length - 1];
|
|
23440
|
+
if (!latest) return null;
|
|
23441
|
+
return { actionName: latest.actionName, capturedAt: latest.capturedAt };
|
|
23442
|
+
}
|
|
23443
|
+
undoLastAction() {
|
|
23444
|
+
const snapshot = this.undoSnapshots.at(-1);
|
|
23445
|
+
if (!snapshot) return null;
|
|
23446
|
+
try {
|
|
23447
|
+
this.tabManager.restoreSession(snapshot.snapshot);
|
|
23448
|
+
this.undoSnapshots.pop();
|
|
23449
|
+
} catch (error) {
|
|
23450
|
+
logger$3.error("Failed to restore undo snapshot", error);
|
|
23451
|
+
return null;
|
|
23452
|
+
}
|
|
23453
|
+
this.captureSession(`Undid ${snapshot.actionName}`);
|
|
23454
|
+
return snapshot.actionName;
|
|
23455
|
+
}
|
|
23175
23456
|
captureSession(note) {
|
|
23176
23457
|
const snapshot = this.tabManager.snapshotSession(note);
|
|
23177
23458
|
this.state.session = snapshot;
|
|
@@ -23321,6 +23602,7 @@ ${progress}
|
|
|
23321
23602
|
args = {},
|
|
23322
23603
|
tabId = null,
|
|
23323
23604
|
dangerous = false,
|
|
23605
|
+
undoable,
|
|
23324
23606
|
executor
|
|
23325
23607
|
}) {
|
|
23326
23608
|
const action = this.startAction({
|
|
@@ -23374,8 +23656,13 @@ ${progress}
|
|
|
23374
23656
|
streamId: transcriptStreamId,
|
|
23375
23657
|
mode: "replace"
|
|
23376
23658
|
});
|
|
23659
|
+
const shouldCaptureUndo = undoable ?? isUndoableAction(name);
|
|
23660
|
+
const undoSnapshot = shouldCaptureUndo ? this.createUndoSnapshot(name) : null;
|
|
23377
23661
|
try {
|
|
23378
23662
|
const result = await executor();
|
|
23663
|
+
if (undoSnapshot && isUndoableResult(result)) {
|
|
23664
|
+
this.pushUndoSnapshot(undoSnapshot);
|
|
23665
|
+
}
|
|
23379
23666
|
this.finishAction(action.id, "completed", summarizeText(result));
|
|
23380
23667
|
this.publishTranscript({
|
|
23381
23668
|
source,
|
|
@@ -23402,6 +23689,21 @@ ${progress}
|
|
|
23402
23689
|
throw error;
|
|
23403
23690
|
}
|
|
23404
23691
|
}
|
|
23692
|
+
createUndoSnapshot(name) {
|
|
23693
|
+
return {
|
|
23694
|
+
id: crypto$2.randomUUID(),
|
|
23695
|
+
actionName: name,
|
|
23696
|
+
snapshot: this.tabManager.snapshotSession(
|
|
23697
|
+
`Auto-checkpoint before ${name}`
|
|
23698
|
+
),
|
|
23699
|
+
capturedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
23700
|
+
};
|
|
23701
|
+
}
|
|
23702
|
+
pushUndoSnapshot(snapshot) {
|
|
23703
|
+
this.undoSnapshots = [...this.undoSnapshots, snapshot].slice(
|
|
23704
|
+
-10
|
|
23705
|
+
);
|
|
23706
|
+
}
|
|
23405
23707
|
resolveApproval(approvalId, approved) {
|
|
23406
23708
|
const approval = this.state.supervisor.pendingApprovals.find(
|
|
23407
23709
|
(item) => item.id === approvalId
|