@quanta-intellect/vessel-browser 0.1.58 → 0.1.61
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 +2 -0
- package/out/main/index.js +435 -194
- package/out/preload/content-script.js +5 -0
- package/out/preload/index.js +46 -1
- package/out/renderer/assets/{index-Bn4ixapT.css → index-CBe7EN_l.css} +492 -0
- package/out/renderer/assets/{index-DGIC7Iij.js → index-Di64dPm5.js} +1469 -727
- package/out/renderer/index.html +2 -2
- package/package.json +1 -1
package/out/main/index.js
CHANGED
|
@@ -2683,6 +2683,8 @@ const Channels = {
|
|
|
2683
2683
|
DEVTOOLS_PANEL_TOGGLE: "devtools-panel:toggle",
|
|
2684
2684
|
DEVTOOLS_PANEL_STATE: "devtools-panel:state",
|
|
2685
2685
|
DEVTOOLS_PANEL_RESIZE: "devtools-panel:resize",
|
|
2686
|
+
// Ad blocking
|
|
2687
|
+
TAB_TOGGLE_AD_BLOCK: "tab:toggle-ad-block",
|
|
2686
2688
|
// Find in page
|
|
2687
2689
|
FIND_IN_PAGE_START: "find:start",
|
|
2688
2690
|
FIND_IN_PAGE_NEXT: "find:next",
|
|
@@ -2706,6 +2708,11 @@ const Channels = {
|
|
|
2706
2708
|
PREMIUM_RESET: "premium:reset",
|
|
2707
2709
|
PREMIUM_TRACK_CONTEXT: "premium:track-context",
|
|
2708
2710
|
PREMIUM_UPDATE: "premium:update",
|
|
2711
|
+
// Named sessions
|
|
2712
|
+
SESSION_LIST: "session:list",
|
|
2713
|
+
SESSION_SAVE: "session:save",
|
|
2714
|
+
SESSION_LOAD: "session:load",
|
|
2715
|
+
SESSION_DELETE: "session:delete",
|
|
2709
2716
|
// Agent Credential Vault
|
|
2710
2717
|
VAULT_LIST: "vault:list",
|
|
2711
2718
|
VAULT_ADD: "vault:add",
|
|
@@ -2740,6 +2747,7 @@ const Channels = {
|
|
|
2740
2747
|
};
|
|
2741
2748
|
const MAX_DETAIL_ITEMS = 3;
|
|
2742
2749
|
const MIN_BLOCK_SIMILARITY = 0.82;
|
|
2750
|
+
const MAX_DIFF_BLOCKS = 500;
|
|
2743
2751
|
function normalizeText$2(value) {
|
|
2744
2752
|
return value.replace(/\s+/g, " ").trim();
|
|
2745
2753
|
}
|
|
@@ -2856,8 +2864,10 @@ function diffSnapshots(oldSnap, currentContent, currentTitle, currentHeadings) {
|
|
|
2856
2864
|
const oldHeadings = oldSnap.headings.split("\n").filter(Boolean);
|
|
2857
2865
|
const newHeadings = currentHeadings.split("\n").filter(Boolean);
|
|
2858
2866
|
if (oldHeadings.join("\n") !== newHeadings.join("\n")) {
|
|
2859
|
-
const
|
|
2860
|
-
const
|
|
2867
|
+
const oldSet = new Set(oldHeadings);
|
|
2868
|
+
const newSet = new Set(newHeadings);
|
|
2869
|
+
const added = newHeadings.filter((h) => !oldSet.has(h));
|
|
2870
|
+
const removed = oldHeadings.filter((h) => !newSet.has(h));
|
|
2861
2871
|
const parts = [];
|
|
2862
2872
|
if (added.length > 0) parts.push(`New: ${added.join(", ")}`);
|
|
2863
2873
|
if (removed.length > 0) parts.push(`Gone: ${removed.join(", ")}`);
|
|
@@ -2871,8 +2881,10 @@ function diffSnapshots(oldSnap, currentContent, currentTitle, currentHeadings) {
|
|
|
2871
2881
|
});
|
|
2872
2882
|
}
|
|
2873
2883
|
}
|
|
2874
|
-
const
|
|
2875
|
-
const
|
|
2884
|
+
const rawOldBlocks = extractTextBlocks(oldSnap.textContent);
|
|
2885
|
+
const rawNewBlocks = extractTextBlocks(currentContent);
|
|
2886
|
+
const oldBlocks = rawOldBlocks.slice(0, MAX_DIFF_BLOCKS);
|
|
2887
|
+
const newBlocks = rawNewBlocks.slice(0, MAX_DIFF_BLOCKS);
|
|
2876
2888
|
const overallSimilarity = similarityScore(oldSnap.textContent, currentContent);
|
|
2877
2889
|
if (overallSimilarity < 0.98) {
|
|
2878
2890
|
const ops = diffBlocks(oldBlocks, newBlocks);
|
|
@@ -3754,7 +3766,7 @@ async function getCheckoutUrl(email) {
|
|
|
3754
3766
|
async function getPortalUrl() {
|
|
3755
3767
|
return {
|
|
3756
3768
|
ok: false,
|
|
3757
|
-
error: "Billing portal access is temporarily disabled
|
|
3769
|
+
error: "Billing portal access is temporarily disabled until authenticated customer access is implemented."
|
|
3758
3770
|
};
|
|
3759
3771
|
}
|
|
3760
3772
|
async function verifySubscription(identifier) {
|
|
@@ -3891,10 +3903,8 @@ function startBackgroundRevalidation() {
|
|
|
3891
3903
|
}, REVALIDATION_INTERVAL_MS);
|
|
3892
3904
|
}
|
|
3893
3905
|
function stopBackgroundRevalidation() {
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
revalidationTimer = null;
|
|
3897
|
-
}
|
|
3906
|
+
clearInterval(revalidationTimer);
|
|
3907
|
+
revalidationTimer = null;
|
|
3898
3908
|
}
|
|
3899
3909
|
function isPremiumActiveState(state2) {
|
|
3900
3910
|
return state2.status === "active" || state2.status === "trialing";
|
|
@@ -3999,8 +4009,8 @@ function stopTelemetry() {
|
|
|
3999
4009
|
}
|
|
4000
4010
|
if (flushTimer) {
|
|
4001
4011
|
clearInterval(flushTimer);
|
|
4002
|
-
flushTimer = null;
|
|
4003
4012
|
}
|
|
4013
|
+
flushTimer = null;
|
|
4004
4014
|
void flush();
|
|
4005
4015
|
}
|
|
4006
4016
|
async function flush() {
|
|
@@ -4101,6 +4111,226 @@ function selectorHelpersJS(attributes = DEFAULT_SELECTOR_ATTRIBUTES) {
|
|
|
4101
4111
|
"}"
|
|
4102
4112
|
].join("\n");
|
|
4103
4113
|
}
|
|
4114
|
+
function normalizeString(value) {
|
|
4115
|
+
return (value ?? "").trim().toLowerCase();
|
|
4116
|
+
}
|
|
4117
|
+
function mapInputType(el) {
|
|
4118
|
+
const inputType = el.inputType ?? el.type ?? "text";
|
|
4119
|
+
switch (inputType.toLowerCase()) {
|
|
4120
|
+
case "email":
|
|
4121
|
+
return "email";
|
|
4122
|
+
case "password":
|
|
4123
|
+
return "password";
|
|
4124
|
+
case "number":
|
|
4125
|
+
case "range":
|
|
4126
|
+
return "number";
|
|
4127
|
+
case "select-one":
|
|
4128
|
+
case "select":
|
|
4129
|
+
return "select";
|
|
4130
|
+
case "checkbox":
|
|
4131
|
+
case "radio":
|
|
4132
|
+
return "checkbox";
|
|
4133
|
+
case "date":
|
|
4134
|
+
case "datetime-local":
|
|
4135
|
+
case "time":
|
|
4136
|
+
case "month":
|
|
4137
|
+
case "week":
|
|
4138
|
+
return "date";
|
|
4139
|
+
case "file":
|
|
4140
|
+
return "file";
|
|
4141
|
+
default:
|
|
4142
|
+
return "text";
|
|
4143
|
+
}
|
|
4144
|
+
}
|
|
4145
|
+
function mapFormFields(forms, interactiveElements) {
|
|
4146
|
+
const fields = [];
|
|
4147
|
+
const formFieldSelectors = /* @__PURE__ */ new Set();
|
|
4148
|
+
for (const form of forms) {
|
|
4149
|
+
for (const el of form.fields ?? []) {
|
|
4150
|
+
formFieldSelectors.add(el.selector || el.name || el.label || String(el.index));
|
|
4151
|
+
}
|
|
4152
|
+
}
|
|
4153
|
+
for (const el of interactiveElements) {
|
|
4154
|
+
const key = el.selector || el.name || el.label || String(el.index);
|
|
4155
|
+
if (formFieldSelectors.has(key)) {
|
|
4156
|
+
fields.push({
|
|
4157
|
+
name: el.name || el.label || key,
|
|
4158
|
+
type: mapInputType(el),
|
|
4159
|
+
label: el.label,
|
|
4160
|
+
required: el.required,
|
|
4161
|
+
selector: el.selector || ""
|
|
4162
|
+
});
|
|
4163
|
+
}
|
|
4164
|
+
}
|
|
4165
|
+
return fields;
|
|
4166
|
+
}
|
|
4167
|
+
function mapActionButtons(interactiveElements) {
|
|
4168
|
+
const buttons = [];
|
|
4169
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4170
|
+
for (const el of interactiveElements) {
|
|
4171
|
+
if (el.type !== "button" && el.type !== "submit" && el.type !== "reset") continue;
|
|
4172
|
+
const label = (el.label || el.textContent || "").trim();
|
|
4173
|
+
if (!label || seen.has(label)) continue;
|
|
4174
|
+
seen.add(label);
|
|
4175
|
+
let intent;
|
|
4176
|
+
const normalized = normalizeString(label);
|
|
4177
|
+
if (/\b(add to cart|buy now|add to bag|add to basket|shop now)\b/.test(normalized)) {
|
|
4178
|
+
intent = "addToCart";
|
|
4179
|
+
} else if (/\b(login|sign in|log in|signin|log-in)\b/.test(normalized)) {
|
|
4180
|
+
intent = "login";
|
|
4181
|
+
} else if (/\b(submit|send|continue|next|proceed|register|create account|sign up)\b/.test(normalized)) {
|
|
4182
|
+
intent = "submit";
|
|
4183
|
+
} else if (/\b(cancel|back|return|go back|close)\b/.test(normalized)) {
|
|
4184
|
+
intent = "cancel";
|
|
4185
|
+
} else if (/\b(download|export|save as)\b/.test(normalized)) {
|
|
4186
|
+
intent = "download";
|
|
4187
|
+
} else if (/\b(search|find|go|submit search)\b/.test(normalized)) {
|
|
4188
|
+
intent = "search";
|
|
4189
|
+
} else if (el.href || el.url) {
|
|
4190
|
+
intent = "navigate";
|
|
4191
|
+
}
|
|
4192
|
+
if (el.selector || el.name || el.label) {
|
|
4193
|
+
buttons.push({
|
|
4194
|
+
label,
|
|
4195
|
+
selector: el.selector || el.name || el.label,
|
|
4196
|
+
intent
|
|
4197
|
+
});
|
|
4198
|
+
}
|
|
4199
|
+
}
|
|
4200
|
+
return buttons;
|
|
4201
|
+
}
|
|
4202
|
+
function extractPrimaryEntity(pageType, structuredData, metaTags) {
|
|
4203
|
+
if (pageType === "product") {
|
|
4204
|
+
const product = structuredData?.find(
|
|
4205
|
+
(e) => e.types.some((t) => /^product$/i.test(t))
|
|
4206
|
+
);
|
|
4207
|
+
if (product) {
|
|
4208
|
+
const attrs = product.attributes ?? {};
|
|
4209
|
+
return {
|
|
4210
|
+
type: "Product",
|
|
4211
|
+
nameField: typeof attrs.name === "string" ? attrs.name : void 0,
|
|
4212
|
+
priceField: typeof attrs.price === "string" ? attrs.price : typeof attrs.offers === "object" && attrs.offers !== null ? String(attrs.offers["price"] ?? "") : void 0,
|
|
4213
|
+
imageField: typeof attrs.image === "string" ? attrs.image : Array.isArray(attrs.image) ? String(attrs.image[0]) : void 0,
|
|
4214
|
+
descriptionField: typeof attrs.description === "string" ? attrs.description : void 0,
|
|
4215
|
+
reviewsField: typeof attrs.reviews === "string" ? attrs.reviews : void 0,
|
|
4216
|
+
ratingField: typeof attrs.rating === "string" ? attrs.rating : void 0,
|
|
4217
|
+
addToCartField: void 0
|
|
4218
|
+
};
|
|
4219
|
+
}
|
|
4220
|
+
}
|
|
4221
|
+
if (pageType === "article") {
|
|
4222
|
+
const article = structuredData?.find(
|
|
4223
|
+
(e) => e.types.some(
|
|
4224
|
+
(t) => /^(article|newsarticle|blogposting|webpage)$/i.test(t)
|
|
4225
|
+
)
|
|
4226
|
+
);
|
|
4227
|
+
if (article) {
|
|
4228
|
+
const attrs = article.attributes ?? {};
|
|
4229
|
+
return {
|
|
4230
|
+
type: article.types[0] ?? "Article",
|
|
4231
|
+
nameField: typeof attrs.headline === "string" ? attrs.headline : typeof attrs.name === "string" ? attrs.name : void 0,
|
|
4232
|
+
descriptionField: typeof attrs.articleBody === "string" ? attrs.articleBody : typeof attrs.description === "string" ? attrs.description : void 0
|
|
4233
|
+
};
|
|
4234
|
+
}
|
|
4235
|
+
}
|
|
4236
|
+
return void 0;
|
|
4237
|
+
}
|
|
4238
|
+
function inferPageSchema(page) {
|
|
4239
|
+
let pageType = "unknown";
|
|
4240
|
+
let confidence = 0.5;
|
|
4241
|
+
const structuredData = page.structuredData;
|
|
4242
|
+
const metaTags = page.metaTags;
|
|
4243
|
+
const url = page.url ?? "";
|
|
4244
|
+
const forms = page.forms ?? [];
|
|
4245
|
+
const interactiveElements = page.interactiveElements ?? [];
|
|
4246
|
+
const urlLower = normalizeString(url);
|
|
4247
|
+
const jsonLdTypes = [];
|
|
4248
|
+
for (const entity of structuredData ?? []) {
|
|
4249
|
+
jsonLdTypes.push(...entity.types);
|
|
4250
|
+
}
|
|
4251
|
+
const hasProduct = jsonLdTypes.some((t) => /^product$/i.test(t));
|
|
4252
|
+
const hasArticle = jsonLdTypes.some(
|
|
4253
|
+
(t) => /^(article|newsarticle|blogposting)$/i.test(t)
|
|
4254
|
+
);
|
|
4255
|
+
const hasEvent = jsonLdTypes.some((t) => /^event$/i.test(t));
|
|
4256
|
+
const hasSearchResults = jsonLdTypes.some((t) => /^searchresultspage$/i.test(t));
|
|
4257
|
+
if (hasProduct) {
|
|
4258
|
+
pageType = "product";
|
|
4259
|
+
confidence += 0.2;
|
|
4260
|
+
} else if (hasArticle) {
|
|
4261
|
+
pageType = "article";
|
|
4262
|
+
confidence += 0.2;
|
|
4263
|
+
} else if (hasEvent) {
|
|
4264
|
+
pageType = "form";
|
|
4265
|
+
confidence += 0.15;
|
|
4266
|
+
} else if (hasSearchResults) {
|
|
4267
|
+
pageType = "search";
|
|
4268
|
+
confidence += 0.2;
|
|
4269
|
+
}
|
|
4270
|
+
const ogType = metaTags?.["og:type"];
|
|
4271
|
+
if (ogType) {
|
|
4272
|
+
const normalized = normalizeString(ogType);
|
|
4273
|
+
if (/^product$/i.test(normalized) && pageType !== "product") {
|
|
4274
|
+
pageType = "product";
|
|
4275
|
+
confidence += 0.15;
|
|
4276
|
+
} else if (/^article|blog|news/i.test(normalized) && pageType !== "article") {
|
|
4277
|
+
pageType = "article";
|
|
4278
|
+
confidence += 0.15;
|
|
4279
|
+
}
|
|
4280
|
+
}
|
|
4281
|
+
if (/\/checkout|\/cart|\/payment|\/billing/i.test(urlLower) && pageType === "unknown") {
|
|
4282
|
+
pageType = "checkout";
|
|
4283
|
+
confidence += 0.1;
|
|
4284
|
+
} else if (/\/login|\/signin|\/auth/i.test(urlLower) && pageType === "unknown") {
|
|
4285
|
+
pageType = "login";
|
|
4286
|
+
confidence += 0.1;
|
|
4287
|
+
} else if (/\/dashboard|\/account|\/profile/i.test(urlLower) && pageType === "unknown") {
|
|
4288
|
+
pageType = "dashboard";
|
|
4289
|
+
confidence += 0.1;
|
|
4290
|
+
} else if (/\/search/i.test(urlLower) && pageType === "unknown") {
|
|
4291
|
+
pageType = "search";
|
|
4292
|
+
confidence += 0.1;
|
|
4293
|
+
}
|
|
4294
|
+
const hasFormWithSubmit = forms.some(
|
|
4295
|
+
(f) => f.fields.some(
|
|
4296
|
+
(el) => el.type === "submit" || normalizeString(el.inputType) === "submit" || normalizeString(el.name) === "submit"
|
|
4297
|
+
)
|
|
4298
|
+
);
|
|
4299
|
+
const hasPriceSelectors = interactiveElements.some(
|
|
4300
|
+
(el) => el.selector?.includes("price") || normalizeString(el.label).includes("price") || normalizeString(el.name).includes("price") || el.selector?.includes("cost") || el.selector?.includes("amount")
|
|
4301
|
+
);
|
|
4302
|
+
if (pageType === "unknown") {
|
|
4303
|
+
if (hasFormWithSubmit && forms.length > 0) {
|
|
4304
|
+
pageType = "form";
|
|
4305
|
+
confidence += 0.1;
|
|
4306
|
+
} else if (hasPriceSelectors) {
|
|
4307
|
+
pageType = "product";
|
|
4308
|
+
confidence += 0.1;
|
|
4309
|
+
}
|
|
4310
|
+
}
|
|
4311
|
+
if ((pageType === "checkout" || pageType === "unknown") && forms.length > 0) {
|
|
4312
|
+
if (hasFormWithSubmit) {
|
|
4313
|
+
if (pageType === "unknown") {
|
|
4314
|
+
pageType = "form";
|
|
4315
|
+
}
|
|
4316
|
+
confidence += 0.15;
|
|
4317
|
+
}
|
|
4318
|
+
}
|
|
4319
|
+
if (pageType === "unknown") {
|
|
4320
|
+
confidence = 0.5;
|
|
4321
|
+
}
|
|
4322
|
+
confidence = Math.min(0.95, confidence);
|
|
4323
|
+
const primaryEntity = extractPrimaryEntity(pageType, structuredData);
|
|
4324
|
+
const formFields = pageType === "form" || pageType === "checkout" || pageType === "login" ? mapFormFields(forms, interactiveElements) : void 0;
|
|
4325
|
+
const actionButtons = mapActionButtons(interactiveElements);
|
|
4326
|
+
return {
|
|
4327
|
+
pageType,
|
|
4328
|
+
primaryEntity,
|
|
4329
|
+
formFields,
|
|
4330
|
+
actionButtons,
|
|
4331
|
+
confidence
|
|
4332
|
+
};
|
|
4333
|
+
}
|
|
4104
4334
|
const EMPTY_PAGE_CONTENT = {
|
|
4105
4335
|
title: "",
|
|
4106
4336
|
content: "",
|
|
@@ -4814,156 +5044,6 @@ const DIRECT_EXTRACTION_SCRIPT = String.raw`
|
|
|
4814
5044
|
};
|
|
4815
5045
|
})()
|
|
4816
5046
|
`;
|
|
4817
|
-
const SAFE_EXTRACTION_SCRIPT = String.raw`
|
|
4818
|
-
(function() {
|
|
4819
|
-
function getCleanBodyText() {
|
|
4820
|
-
var removed = [];
|
|
4821
|
-
document
|
|
4822
|
-
.querySelectorAll('.__vessel-highlight-label[data-vessel-highlight]')
|
|
4823
|
-
.forEach(function(label) {
|
|
4824
|
-
var parent = label.parentNode;
|
|
4825
|
-
if (!parent) return;
|
|
4826
|
-
removed.push({ label: label, parent: parent, nextSibling: label.nextSibling });
|
|
4827
|
-
parent.removeChild(label);
|
|
4828
|
-
});
|
|
4829
|
-
try {
|
|
4830
|
-
return document.body?.innerText || document.documentElement?.innerText || "";
|
|
4831
|
-
} finally {
|
|
4832
|
-
for (var i = removed.length - 1; i >= 0; i--) {
|
|
4833
|
-
var entry = removed[i];
|
|
4834
|
-
entry.parent.insertBefore(entry.label, entry.nextSibling);
|
|
4835
|
-
}
|
|
4836
|
-
}
|
|
4837
|
-
}
|
|
4838
|
-
|
|
4839
|
-
function text(value) {
|
|
4840
|
-
const trimmed = value == null ? "" : String(value).trim();
|
|
4841
|
-
return trimmed || undefined;
|
|
4842
|
-
}
|
|
4843
|
-
|
|
4844
|
-
function labelFor(el) {
|
|
4845
|
-
const aria = text(el.getAttribute && el.getAttribute("aria-label"));
|
|
4846
|
-
if (aria) return aria;
|
|
4847
|
-
const placeholder = text(el.getAttribute && el.getAttribute("placeholder"));
|
|
4848
|
-
if (placeholder) return placeholder;
|
|
4849
|
-
if (el.id) {
|
|
4850
|
-
const directLabel = document.querySelector('label[for="' + String(el.id).replace(/["\\]/g, "\\$&") + '"]');
|
|
4851
|
-
const labelText = text(directLabel && directLabel.textContent);
|
|
4852
|
-
if (labelText) return labelText;
|
|
4853
|
-
}
|
|
4854
|
-
return text(el.textContent);
|
|
4855
|
-
}
|
|
4856
|
-
|
|
4857
|
-
let indexCounter = 0;
|
|
4858
|
-
function nextIndex() {
|
|
4859
|
-
indexCounter += 1;
|
|
4860
|
-
return indexCounter;
|
|
4861
|
-
}
|
|
4862
|
-
|
|
4863
|
-
const headings = Array.from(document.querySelectorAll("h1, h2, h3, h4, h5, h6"))
|
|
4864
|
-
.map((el) => {
|
|
4865
|
-
const headingText = text(el.textContent);
|
|
4866
|
-
if (!headingText) return null;
|
|
4867
|
-
return { level: Number.parseInt(el.tagName[1], 10), text: headingText };
|
|
4868
|
-
})
|
|
4869
|
-
.filter(Boolean);
|
|
4870
|
-
|
|
4871
|
-
const navigation = Array.from(document.querySelectorAll("nav a[href], [role='navigation'] a[href], header nav a[href]"))
|
|
4872
|
-
.map((el) => {
|
|
4873
|
-
const href = text(el.href || el.getAttribute("href"));
|
|
4874
|
-
const linkText = text(el.textContent);
|
|
4875
|
-
if (!href || href.startsWith("#") || !linkText) return null;
|
|
4876
|
-
return {
|
|
4877
|
-
type: "link",
|
|
4878
|
-
text: linkText.slice(0, 100),
|
|
4879
|
-
href: href.slice(0, 500),
|
|
4880
|
-
context: "nav",
|
|
4881
|
-
index: nextIndex(),
|
|
4882
|
-
visible: true,
|
|
4883
|
-
disabled: false,
|
|
4884
|
-
};
|
|
4885
|
-
})
|
|
4886
|
-
.filter(Boolean);
|
|
4887
|
-
|
|
4888
|
-
const interactiveElements = [];
|
|
4889
|
-
Array.from(document.querySelectorAll("button, [role='button'], input[type='submit'], input[type='button']"))
|
|
4890
|
-
.forEach((el) => {
|
|
4891
|
-
interactiveElements.push({
|
|
4892
|
-
type: "button",
|
|
4893
|
-
text: text(el.textContent || el.value || el.getAttribute("aria-label") || "Button")?.slice(0, 100),
|
|
4894
|
-
index: nextIndex(),
|
|
4895
|
-
visible: true,
|
|
4896
|
-
disabled: !!(el.hasAttribute && (el.hasAttribute("disabled") || el.getAttribute("aria-disabled") === "true")),
|
|
4897
|
-
});
|
|
4898
|
-
});
|
|
4899
|
-
|
|
4900
|
-
Array.from(document.querySelectorAll("a[href]")).forEach((el) => {
|
|
4901
|
-
const href = text(el.href || el.getAttribute("href"));
|
|
4902
|
-
const linkText = text(el.textContent);
|
|
4903
|
-
if (!href || href.startsWith("#") || !linkText) return;
|
|
4904
|
-
interactiveElements.push({
|
|
4905
|
-
type: "link",
|
|
4906
|
-
text: linkText.slice(0, 100),
|
|
4907
|
-
href: href.slice(0, 500),
|
|
4908
|
-
index: nextIndex(),
|
|
4909
|
-
visible: true,
|
|
4910
|
-
disabled: false,
|
|
4911
|
-
});
|
|
4912
|
-
});
|
|
4913
|
-
|
|
4914
|
-
Array.from(document.querySelectorAll("input:not([type='hidden']):not([type='submit']):not([type='button']), select, textarea"))
|
|
4915
|
-
.forEach((el) => {
|
|
4916
|
-
const tag = el.tagName.toLowerCase();
|
|
4917
|
-
var elType = (el.type || "").toLowerCase();
|
|
4918
|
-
interactiveElements.push({
|
|
4919
|
-
type: tag === "select" ? "select" : tag === "textarea" ? "textarea" : "input",
|
|
4920
|
-
label: labelFor(el)?.slice(0, 100),
|
|
4921
|
-
inputType: text(el.getAttribute && el.getAttribute("type")),
|
|
4922
|
-
placeholder: text(el.getAttribute && el.getAttribute("placeholder")),
|
|
4923
|
-
value: shouldExposeFieldValue(el) ? text(el.value) : undefined,
|
|
4924
|
-
options: tag === "select"
|
|
4925
|
-
? Array.from(el.options || []).map(function(option) { return { label: text(option.textContent || option.value) || option.value, value: option.value }; }).filter(function(o) { return o.label || o.value; }).slice(0, 25)
|
|
4926
|
-
: undefined,
|
|
4927
|
-
required: !!(el.hasAttribute && el.hasAttribute("required")) || undefined,
|
|
4928
|
-
index: nextIndex(),
|
|
4929
|
-
visible: true,
|
|
4930
|
-
disabled: !!(el.hasAttribute && (el.hasAttribute("disabled") || el.getAttribute("aria-disabled") === "true")),
|
|
4931
|
-
name: el.name || undefined,
|
|
4932
|
-
autocomplete: text(el.getAttribute && el.getAttribute("autocomplete")),
|
|
4933
|
-
checked: (elType === "checkbox" || elType === "radio") ? !!el.checked : undefined,
|
|
4934
|
-
});
|
|
4935
|
-
});
|
|
4936
|
-
|
|
4937
|
-
const forms = Array.from(document.querySelectorAll("form")).map((form) => ({
|
|
4938
|
-
id: text(form.id),
|
|
4939
|
-
action: text(form.getAttribute("action")),
|
|
4940
|
-
method: text(form.getAttribute("method")),
|
|
4941
|
-
fields: [],
|
|
4942
|
-
}));
|
|
4943
|
-
|
|
4944
|
-
return {
|
|
4945
|
-
title: document.title || "",
|
|
4946
|
-
content: getCleanBodyText(),
|
|
4947
|
-
htmlContent: "",
|
|
4948
|
-
byline: "",
|
|
4949
|
-
excerpt: "",
|
|
4950
|
-
url: window.location.href || "",
|
|
4951
|
-
headings,
|
|
4952
|
-
navigation,
|
|
4953
|
-
interactiveElements,
|
|
4954
|
-
forms,
|
|
4955
|
-
viewport: {
|
|
4956
|
-
width: window.innerWidth || document.documentElement?.clientWidth || 0,
|
|
4957
|
-
height: window.innerHeight || document.documentElement?.clientHeight || 0,
|
|
4958
|
-
scrollX: 0,
|
|
4959
|
-
scrollY: 0,
|
|
4960
|
-
},
|
|
4961
|
-
overlays: [],
|
|
4962
|
-
dormantOverlays: [],
|
|
4963
|
-
landmarks: [],
|
|
4964
|
-
};
|
|
4965
|
-
})()
|
|
4966
|
-
`;
|
|
4967
5047
|
function delay(ms) {
|
|
4968
5048
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
4969
5049
|
}
|
|
@@ -5000,7 +5080,7 @@ async function executeScript(webContents, script) {
|
|
|
5000
5080
|
} catch {
|
|
5001
5081
|
return null;
|
|
5002
5082
|
} finally {
|
|
5003
|
-
if (
|
|
5083
|
+
if (timer) {
|
|
5004
5084
|
clearTimeout(timer);
|
|
5005
5085
|
}
|
|
5006
5086
|
}
|
|
@@ -5075,10 +5155,17 @@ function mergePageContent(candidates, webContents) {
|
|
|
5075
5155
|
headings: mergedBase.headings,
|
|
5076
5156
|
metaTags: mergedBase.metaTags
|
|
5077
5157
|
});
|
|
5158
|
+
const pageSchema = inferPageSchema({
|
|
5159
|
+
...mergedBase,
|
|
5160
|
+
structuredData: normalizedStructuredData,
|
|
5161
|
+
title: mergedBase.title || webContents.getTitle() || "",
|
|
5162
|
+
url: mergedBase.url || webContents.getURL() || ""
|
|
5163
|
+
});
|
|
5078
5164
|
return {
|
|
5079
5165
|
...mergedBase,
|
|
5080
5166
|
structuredData: normalizedStructuredData,
|
|
5081
5167
|
pageIssues,
|
|
5168
|
+
pageSchema,
|
|
5082
5169
|
title: mergedBase.title || webContents.getTitle() || "",
|
|
5083
5170
|
url: mergedBase.url || webContents.getURL() || ""
|
|
5084
5171
|
};
|
|
@@ -5104,13 +5191,12 @@ async function estimateExtractionTimeout(webContents) {
|
|
|
5104
5191
|
}
|
|
5105
5192
|
async function extractContentInner(webContents) {
|
|
5106
5193
|
await waitForDomReady(webContents);
|
|
5107
|
-
const [preloadResult, directResult
|
|
5194
|
+
const [preloadResult, directResult] = await Promise.all([
|
|
5108
5195
|
executeScript(webContents, PRELOAD_EXTRACTION_SCRIPT),
|
|
5109
|
-
executeScript(webContents, DIRECT_EXTRACTION_SCRIPT)
|
|
5110
|
-
executeScript(webContents, SAFE_EXTRACTION_SCRIPT)
|
|
5196
|
+
executeScript(webContents, DIRECT_EXTRACTION_SCRIPT)
|
|
5111
5197
|
]);
|
|
5112
5198
|
return mergePageContent(
|
|
5113
|
-
[preloadResult, directResult
|
|
5199
|
+
[preloadResult, directResult],
|
|
5114
5200
|
webContents
|
|
5115
5201
|
);
|
|
5116
5202
|
}
|
|
@@ -5167,7 +5253,8 @@ function normalizePageContent(value) {
|
|
|
5167
5253
|
rdfa: Array.isArray(page.rdfa) ? page.rdfa : [],
|
|
5168
5254
|
metaTags: page.metaTags && typeof page.metaTags === "object" && !Array.isArray(page.metaTags) ? page.metaTags : {},
|
|
5169
5255
|
structuredData: Array.isArray(page.structuredData) ? page.structuredData : [],
|
|
5170
|
-
pageIssues: Array.isArray(page.pageIssues) ? page.pageIssues : []
|
|
5256
|
+
pageIssues: Array.isArray(page.pageIssues) ? page.pageIssues : [],
|
|
5257
|
+
pageSchema: page.pageSchema
|
|
5171
5258
|
};
|
|
5172
5259
|
}
|
|
5173
5260
|
const latestPageDiffs = /* @__PURE__ */ new Map();
|
|
@@ -5176,6 +5263,22 @@ const pendingPageSnapshotTimers = /* @__PURE__ */ new Map();
|
|
|
5176
5263
|
const pendingPageSnapshotDueAt = /* @__PURE__ */ new Map();
|
|
5177
5264
|
const lastMutationSnapshotAt = /* @__PURE__ */ new Map();
|
|
5178
5265
|
const lastMutationActivityAt = /* @__PURE__ */ new Map();
|
|
5266
|
+
const destroyListenerAttached = /* @__PURE__ */ new WeakSet();
|
|
5267
|
+
function cleanupTimersForWcId(wcId) {
|
|
5268
|
+
const timer = pendingPageSnapshotTimers.get(wcId);
|
|
5269
|
+
if (timer) clearTimeout(timer);
|
|
5270
|
+
pendingPageSnapshotTimers.delete(wcId);
|
|
5271
|
+
pendingPageSnapshotDueAt.delete(wcId);
|
|
5272
|
+
lastMutationSnapshotAt.delete(wcId);
|
|
5273
|
+
lastMutationActivityAt.delete(wcId);
|
|
5274
|
+
}
|
|
5275
|
+
function attachDestroyCleanup(wc) {
|
|
5276
|
+
if (destroyListenerAttached.has(wc)) return;
|
|
5277
|
+
destroyListenerAttached.add(wc);
|
|
5278
|
+
wc.once("destroyed", () => {
|
|
5279
|
+
cleanupTimersForWcId(wc.id);
|
|
5280
|
+
});
|
|
5281
|
+
}
|
|
5179
5282
|
const MIN_MUTATION_CAPTURE_INTERVAL_MS = 5e3;
|
|
5180
5283
|
const SETTLE_AFTER_ACTIVITY_MS = 1500;
|
|
5181
5284
|
function getLatestPageDiff(rawUrl) {
|
|
@@ -5222,6 +5325,7 @@ async function capturePageSnapshot(url, wc, sendToRendererViews) {
|
|
|
5222
5325
|
sendToRendererViews(Channels.PAGE_CHANGED, enrichedDiff);
|
|
5223
5326
|
} else {
|
|
5224
5327
|
latestPageDiffs.delete(key);
|
|
5328
|
+
recentPageDiffBursts.delete(key);
|
|
5225
5329
|
}
|
|
5226
5330
|
} else {
|
|
5227
5331
|
latestPageDiffs.delete(key);
|
|
@@ -5239,12 +5343,12 @@ function computeNextSnapshotDueAt(wcId, now, delayMs) {
|
|
|
5239
5343
|
return Math.max(now + delayMs, earliestAllowedAt, stableAfterActivityAt);
|
|
5240
5344
|
}
|
|
5241
5345
|
function scheduleTimerAt(wc, sendToRendererViews, dueAt) {
|
|
5346
|
+
attachDestroyCleanup(wc);
|
|
5242
5347
|
const wcId = wc.id;
|
|
5243
5348
|
const existing = pendingPageSnapshotTimers.get(wcId);
|
|
5244
5349
|
if (existing) clearTimeout(existing);
|
|
5245
5350
|
const timer = setTimeout(() => {
|
|
5246
|
-
|
|
5247
|
-
pendingPageSnapshotDueAt.delete(wcId);
|
|
5351
|
+
cleanupTimersForWcId(wcId);
|
|
5248
5352
|
if (wc.isDestroyed()) return;
|
|
5249
5353
|
lastMutationSnapshotAt.set(wcId, Date.now());
|
|
5250
5354
|
void capturePageSnapshot(wc.getURL(), wc, sendToRendererViews);
|
|
@@ -5568,9 +5672,9 @@ function resizeSidebarViews(state2) {
|
|
|
5568
5672
|
const contentWidth = width - sidebarWidth;
|
|
5569
5673
|
sidebarView.setBounds({
|
|
5570
5674
|
x: width - sidebarWidth - resizeHandleOverlap,
|
|
5571
|
-
y:
|
|
5675
|
+
y: chromeHeight,
|
|
5572
5676
|
width: sidebarWidth + resizeHandleOverlap,
|
|
5573
|
-
height
|
|
5677
|
+
height: height - chromeHeight
|
|
5574
5678
|
});
|
|
5575
5679
|
if (uiState.devtoolsPanelOpen) {
|
|
5576
5680
|
devtoolsPanelView.setBounds({
|
|
@@ -9733,7 +9837,17 @@ const TOOL_DEFINITIONS = [
|
|
|
9733
9837
|
folderSummary: zod.z.string().optional().describe("Optional summary used if a new folder is created"),
|
|
9734
9838
|
createFolderIfMissing: zod.z.boolean().optional().describe("Create folderName automatically when it does not exist"),
|
|
9735
9839
|
note: zod.z.string().optional().describe("Optional note about why the page was saved"),
|
|
9736
|
-
onDuplicate: zod.z.enum(["ask", "update", "duplicate"]).optional().describe("How to handle duplicate URLs in the same folder")
|
|
9840
|
+
onDuplicate: zod.z.enum(["ask", "update", "duplicate"]).optional().describe("How to handle duplicate URLs in the same folder"),
|
|
9841
|
+
intent: zod.z.string().optional().describe(
|
|
9842
|
+
"Human-readable description of what this bookmark is for (e.g. 'expense reporting')"
|
|
9843
|
+
),
|
|
9844
|
+
expectedContent: zod.z.string().optional().describe(
|
|
9845
|
+
"Brief description of the content the agent should expect to find here"
|
|
9846
|
+
),
|
|
9847
|
+
keyFields: zod.z.array(zod.z.string()).optional().describe(
|
|
9848
|
+
"Important form field names for this page (e.g. ['receipt_id', 'date', 'amount'])"
|
|
9849
|
+
),
|
|
9850
|
+
agentHints: zod.z.record(zod.z.string(), zod.z.string()).optional().describe("Arbitrary key-value hints for the agent")
|
|
9737
9851
|
},
|
|
9738
9852
|
tier: 1
|
|
9739
9853
|
},
|
|
@@ -9752,7 +9866,11 @@ const TOOL_DEFINITIONS = [
|
|
|
9752
9866
|
folderSummary: zod.z.string().optional().describe("Optional summary for new folder"),
|
|
9753
9867
|
createFolderIfMissing: zod.z.boolean().optional().describe("Create folderName automatically when it does not exist"),
|
|
9754
9868
|
note: zod.z.string().optional().describe("Optional note"),
|
|
9755
|
-
archive: zod.z.boolean().optional().describe('If true, organize into the default "Archive" folder')
|
|
9869
|
+
archive: zod.z.boolean().optional().describe('If true, organize into the default "Archive" folder'),
|
|
9870
|
+
intent: zod.z.string().optional().describe("Human-readable description of what this bookmark is for"),
|
|
9871
|
+
expectedContent: zod.z.string().optional().describe("Brief description of content the agent should expect"),
|
|
9872
|
+
keyFields: zod.z.array(zod.z.string()).optional().describe("Important form field names for this page"),
|
|
9873
|
+
agentHints: zod.z.record(zod.z.string(), zod.z.string()).optional().describe("Arbitrary key-value hints for the agent")
|
|
9756
9874
|
},
|
|
9757
9875
|
tier: 2
|
|
9758
9876
|
},
|
|
@@ -10324,7 +10442,9 @@ const FIELD_WEIGHTS = {
|
|
|
10324
10442
|
note: 5,
|
|
10325
10443
|
folder: 3,
|
|
10326
10444
|
folderSummary: 2,
|
|
10327
|
-
url: 1
|
|
10445
|
+
url: 1,
|
|
10446
|
+
intent: 4,
|
|
10447
|
+
expectedContent: 3
|
|
10328
10448
|
};
|
|
10329
10449
|
function normalizeBookmarkSearchText(value) {
|
|
10330
10450
|
let normalized = value.toLowerCase();
|
|
@@ -10355,7 +10475,9 @@ function getBookmarkSearchMatch(args) {
|
|
|
10355
10475
|
url: args.url,
|
|
10356
10476
|
note: args.note,
|
|
10357
10477
|
folder: args.folder,
|
|
10358
|
-
folderSummary: args.folderSummary
|
|
10478
|
+
folderSummary: args.folderSummary,
|
|
10479
|
+
intent: args.intent,
|
|
10480
|
+
expectedContent: args.expectedContent
|
|
10359
10481
|
};
|
|
10360
10482
|
for (const field of Object.keys(values)) {
|
|
10361
10483
|
if (!bookmarkFieldMatchesQuery(values[field], normalizedQuery, tokens)) {
|
|
@@ -10495,7 +10617,9 @@ function searchBookmarks(query) {
|
|
|
10495
10617
|
url: bookmark.url,
|
|
10496
10618
|
note: bookmark.note,
|
|
10497
10619
|
folder: folder?.name,
|
|
10498
|
-
folderSummary: folder?.summary
|
|
10620
|
+
folderSummary: folder?.summary,
|
|
10621
|
+
intent: bookmark.intent,
|
|
10622
|
+
expectedContent: bookmark.expectedContent
|
|
10499
10623
|
});
|
|
10500
10624
|
return {
|
|
10501
10625
|
bookmark,
|
|
@@ -10575,6 +10699,9 @@ function saveBookmarkWithPolicy(url, title, folderId, note, options) {
|
|
|
10575
10699
|
if (note !== void 0) {
|
|
10576
10700
|
bookmark2.note = note.trim() || void 0;
|
|
10577
10701
|
}
|
|
10702
|
+
if (options?.extra) {
|
|
10703
|
+
Object.assign(bookmark2, options.extra);
|
|
10704
|
+
}
|
|
10578
10705
|
bookmark2.savedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
10579
10706
|
save();
|
|
10580
10707
|
emit();
|
|
@@ -10590,7 +10717,8 @@ function saveBookmarkWithPolicy(url, title, folderId, note, options) {
|
|
|
10590
10717
|
title: normalizedTitle,
|
|
10591
10718
|
note: note?.trim() || void 0,
|
|
10592
10719
|
folderId: targetId,
|
|
10593
|
-
savedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
10720
|
+
savedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
10721
|
+
...options?.extra
|
|
10594
10722
|
};
|
|
10595
10723
|
state$1.bookmarks.push(bookmark);
|
|
10596
10724
|
save();
|
|
@@ -10626,6 +10754,21 @@ function updateBookmark(id, updates) {
|
|
|
10626
10754
|
if (typeof updates.folderId === "string") {
|
|
10627
10755
|
bookmark.folderId = updates.folderId && updates.folderId !== UNSORTED_ID ? state$1.folders.find((item) => item.id === updates.folderId)?.id ?? UNSORTED_ID : UNSORTED_ID;
|
|
10628
10756
|
}
|
|
10757
|
+
if (typeof updates.intent === "string") {
|
|
10758
|
+
bookmark.intent = updates.intent.trim() || void 0;
|
|
10759
|
+
}
|
|
10760
|
+
if (typeof updates.expectedContent === "string") {
|
|
10761
|
+
bookmark.expectedContent = updates.expectedContent.trim() || void 0;
|
|
10762
|
+
}
|
|
10763
|
+
if (updates.keyFields !== void 0) {
|
|
10764
|
+
bookmark.keyFields = updates.keyFields;
|
|
10765
|
+
}
|
|
10766
|
+
if (updates.pageSchema !== void 0) {
|
|
10767
|
+
bookmark.pageSchema = updates.pageSchema;
|
|
10768
|
+
}
|
|
10769
|
+
if (updates.agentHints !== void 0) {
|
|
10770
|
+
bookmark.agentHints = updates.agentHints;
|
|
10771
|
+
}
|
|
10629
10772
|
save();
|
|
10630
10773
|
emit();
|
|
10631
10774
|
return { ...bookmark };
|
|
@@ -15530,7 +15673,17 @@ ${truncated}`;
|
|
|
15530
15673
|
source.title,
|
|
15531
15674
|
target.folderId,
|
|
15532
15675
|
note,
|
|
15533
|
-
{
|
|
15676
|
+
{
|
|
15677
|
+
onDuplicate,
|
|
15678
|
+
extra: {
|
|
15679
|
+
intent: typeof args.intent === "string" && args.intent.trim() ? args.intent.trim() : void 0,
|
|
15680
|
+
expectedContent: typeof args.expectedContent === "string" && args.expectedContent.trim() ? args.expectedContent.trim() : void 0,
|
|
15681
|
+
keyFields: Array.isArray(args.keyFields) ? args.keyFields.filter(
|
|
15682
|
+
(f) => typeof f === "string"
|
|
15683
|
+
) : void 0,
|
|
15684
|
+
agentHints: args.agentHints && typeof args.agentHints === "object" ? args.agentHints : void 0
|
|
15685
|
+
}
|
|
15686
|
+
}
|
|
15534
15687
|
);
|
|
15535
15688
|
if (result2.status === "conflict" && result2.existing) {
|
|
15536
15689
|
return composeFolderAwareResponse$1(
|
|
@@ -15569,7 +15722,13 @@ ${truncated}`;
|
|
|
15569
15722
|
const updated = updateBookmark(existing.id, {
|
|
15570
15723
|
folderId: target.folderId,
|
|
15571
15724
|
title: typeof args.title === "string" && args.title.trim() ? args.title.trim() : void 0,
|
|
15572
|
-
note
|
|
15725
|
+
note,
|
|
15726
|
+
intent: typeof args.intent === "string" && args.intent.trim() ? args.intent.trim() : void 0,
|
|
15727
|
+
expectedContent: typeof args.expectedContent === "string" && args.expectedContent.trim() ? args.expectedContent.trim() : void 0,
|
|
15728
|
+
keyFields: Array.isArray(args.keyFields) ? args.keyFields.filter(
|
|
15729
|
+
(f) => typeof f === "string"
|
|
15730
|
+
) : void 0,
|
|
15731
|
+
agentHints: args.agentHints && typeof args.agentHints === "object" ? args.agentHints : void 0
|
|
15573
15732
|
});
|
|
15574
15733
|
if (!updated) {
|
|
15575
15734
|
return `Bookmark ${existing.id} not found`;
|
|
@@ -15580,12 +15739,25 @@ ${truncated}`;
|
|
|
15580
15739
|
);
|
|
15581
15740
|
}
|
|
15582
15741
|
if ("error" in source) return `Error: ${source.error}`;
|
|
15583
|
-
const
|
|
15742
|
+
const result2 = saveBookmarkWithPolicy(
|
|
15584
15743
|
source.url,
|
|
15585
15744
|
source.title,
|
|
15586
15745
|
target.folderId,
|
|
15587
|
-
note
|
|
15746
|
+
note,
|
|
15747
|
+
{
|
|
15748
|
+
onDuplicate: "update",
|
|
15749
|
+
extra: {
|
|
15750
|
+
intent: typeof args.intent === "string" && args.intent.trim() ? args.intent.trim() : void 0,
|
|
15751
|
+
expectedContent: typeof args.expectedContent === "string" && args.expectedContent.trim() ? args.expectedContent.trim() : void 0,
|
|
15752
|
+
keyFields: Array.isArray(args.keyFields) ? args.keyFields.filter(
|
|
15753
|
+
(f) => typeof f === "string"
|
|
15754
|
+
) : void 0,
|
|
15755
|
+
agentHints: args.agentHints && typeof args.agentHints === "object" ? args.agentHints : void 0
|
|
15756
|
+
}
|
|
15757
|
+
}
|
|
15588
15758
|
);
|
|
15759
|
+
const bookmark = result2.bookmark;
|
|
15760
|
+
if (!bookmark) return "Error: Bookmark save failed";
|
|
15589
15761
|
return composeFolderAwareResponse$1(
|
|
15590
15762
|
`Saved and organized "${bookmark.title}" (${bookmark.url}) into "${describeFolder$1(bookmark.folderId)}" (id=${bookmark.id})`,
|
|
15591
15763
|
target.createdFolder
|
|
@@ -22770,7 +22942,7 @@ function registerWindowControlHandlers(mainWindow) {
|
|
|
22770
22942
|
});
|
|
22771
22943
|
}
|
|
22772
22944
|
let activeChatProvider = null;
|
|
22773
|
-
const VALID_APPROVAL_MODES =
|
|
22945
|
+
const VALID_APPROVAL_MODES = ["auto", "confirm-dangerous", "manual"];
|
|
22774
22946
|
function registerIpcHandlers(windowState, runtime2) {
|
|
22775
22947
|
const { tabManager, chromeView, sidebarView, devtoolsPanelView, mainWindow } = windowState;
|
|
22776
22948
|
let sidebarResizeRecoveryTimer = null;
|
|
@@ -22779,10 +22951,9 @@ function registerIpcHandlers(windowState, runtime2) {
|
|
|
22779
22951
|
let pendingRuntimeState = null;
|
|
22780
22952
|
const premiumApiOrigin = process.env.VESSEL_PREMIUM_API ? new URL(process.env.VESSEL_PREMIUM_API).origin : "https://vesselpremium.quantaintellect.com";
|
|
22781
22953
|
const clearSidebarResizeRecoveryTimer = () => {
|
|
22782
|
-
if (sidebarResizeRecoveryTimer)
|
|
22783
|
-
|
|
22784
|
-
|
|
22785
|
-
}
|
|
22954
|
+
if (!sidebarResizeRecoveryTimer) return;
|
|
22955
|
+
clearTimeout(sidebarResizeRecoveryTimer);
|
|
22956
|
+
sidebarResizeRecoveryTimer = null;
|
|
22786
22957
|
};
|
|
22787
22958
|
const restoreSidebarLayoutAfterResize = () => {
|
|
22788
22959
|
clearSidebarResizeRecoveryTimer();
|
|
@@ -22820,6 +22991,13 @@ function registerIpcHandlers(windowState, runtime2) {
|
|
|
22820
22991
|
flushRuntimeUpdate();
|
|
22821
22992
|
}, 32);
|
|
22822
22993
|
};
|
|
22994
|
+
electron.app.on("before-quit", () => {
|
|
22995
|
+
if (runtimeUpdateTimer) {
|
|
22996
|
+
clearTimeout(runtimeUpdateTimer);
|
|
22997
|
+
runtimeUpdateTimer = null;
|
|
22998
|
+
}
|
|
22999
|
+
flushRuntimeUpdate();
|
|
23000
|
+
});
|
|
22823
23001
|
const sendToRendererViews = (channel, ...args) => {
|
|
22824
23002
|
chromeView.webContents.send(channel, ...args);
|
|
22825
23003
|
sidebarView.webContents.send(channel, ...args);
|
|
@@ -22944,6 +23122,14 @@ function registerIpcHandlers(windowState, runtime2) {
|
|
|
22944
23122
|
electron.ipcMain.handle(Channels.TAB_RELOAD, (_, id) => {
|
|
22945
23123
|
tabManager.reloadTab(id);
|
|
22946
23124
|
});
|
|
23125
|
+
electron.ipcMain.handle(Channels.TAB_TOGGLE_AD_BLOCK, (_, id) => {
|
|
23126
|
+
assertString(id, "id");
|
|
23127
|
+
const tab = tabManager.getTab(id);
|
|
23128
|
+
if (!tab) return null;
|
|
23129
|
+
const newState = !tab.state.adBlockingEnabled;
|
|
23130
|
+
tab.setAdBlockingEnabled(newState);
|
|
23131
|
+
return newState;
|
|
23132
|
+
});
|
|
22947
23133
|
electron.ipcMain.handle(Channels.TAB_STATE_GET, () => ({
|
|
22948
23134
|
tabs: tabManager.getAllStates(),
|
|
22949
23135
|
activeId: tabManager.getActiveTabId() || ""
|
|
@@ -23042,7 +23228,15 @@ function registerIpcHandlers(windowState, runtime2) {
|
|
|
23042
23228
|
sidebarResizeActive = true;
|
|
23043
23229
|
clearSidebarResizeRecoveryTimer();
|
|
23044
23230
|
const [width, height] = windowState.mainWindow.getContentSize();
|
|
23045
|
-
windowState.
|
|
23231
|
+
const chromeHeight = windowState.uiState.focusMode ? 0 : 110;
|
|
23232
|
+
const sidebarWidth = windowState.uiState.sidebarWidth;
|
|
23233
|
+
const resizeHandleOverlap = 6;
|
|
23234
|
+
windowState.sidebarView.setBounds({
|
|
23235
|
+
x: width - sidebarWidth - resizeHandleOverlap,
|
|
23236
|
+
y: chromeHeight,
|
|
23237
|
+
width: sidebarWidth + resizeHandleOverlap,
|
|
23238
|
+
height: height - chromeHeight
|
|
23239
|
+
});
|
|
23046
23240
|
scheduleSidebarResizeRecovery();
|
|
23047
23241
|
});
|
|
23048
23242
|
electron.ipcMain.handle(Channels.SIDEBAR_RESIZE, (_, width) => {
|
|
@@ -23050,7 +23244,6 @@ function registerIpcHandlers(windowState, runtime2) {
|
|
|
23050
23244
|
const clamped = Math.max(240, Math.min(800, Math.round(width)));
|
|
23051
23245
|
windowState.uiState.sidebarWidth = clamped;
|
|
23052
23246
|
resizeSidebarViews(windowState);
|
|
23053
|
-
scheduleSidebarResizeRecovery();
|
|
23054
23247
|
return clamped;
|
|
23055
23248
|
});
|
|
23056
23249
|
electron.ipcMain.handle(Channels.SIDEBAR_RESIZE_COMMIT, () => {
|
|
@@ -23109,7 +23302,7 @@ function registerIpcHandlers(windowState, runtime2) {
|
|
|
23109
23302
|
Channels.AGENT_SET_APPROVAL_MODE,
|
|
23110
23303
|
(_, mode) => {
|
|
23111
23304
|
assertString(mode, "mode");
|
|
23112
|
-
if (!VALID_APPROVAL_MODES.
|
|
23305
|
+
if (!VALID_APPROVAL_MODES.includes(mode)) {
|
|
23113
23306
|
throw new Error(`Invalid approval mode: ${mode}`);
|
|
23114
23307
|
}
|
|
23115
23308
|
trackApprovalModeChanged(mode);
|
|
@@ -23149,9 +23342,16 @@ function registerIpcHandlers(windowState, runtime2) {
|
|
|
23149
23342
|
);
|
|
23150
23343
|
electron.ipcMain.handle(
|
|
23151
23344
|
Channels.BOOKMARK_SAVE,
|
|
23152
|
-
(_, url, title, folderId, note) => {
|
|
23345
|
+
(_, url, title, folderId, note, intent, expectedContent, keyFields, agentHints) => {
|
|
23153
23346
|
trackBookmarkAction("save");
|
|
23154
|
-
return
|
|
23347
|
+
return saveBookmarkWithPolicy(url, title, folderId, note, {
|
|
23348
|
+
extra: {
|
|
23349
|
+
intent: intent?.trim() || void 0,
|
|
23350
|
+
expectedContent: expectedContent?.trim() || void 0,
|
|
23351
|
+
keyFields,
|
|
23352
|
+
agentHints
|
|
23353
|
+
}
|
|
23354
|
+
});
|
|
23155
23355
|
}
|
|
23156
23356
|
);
|
|
23157
23357
|
electron.ipcMain.handle(Channels.BOOKMARK_REMOVE, (_, id) => {
|
|
@@ -23254,17 +23454,31 @@ function registerIpcHandlers(windowState, runtime2) {
|
|
|
23254
23454
|
}
|
|
23255
23455
|
});
|
|
23256
23456
|
let findWiredWcId = null;
|
|
23457
|
+
let findResultListener = null;
|
|
23257
23458
|
function wireFindEvents(wc) {
|
|
23258
23459
|
if (findWiredWcId === wc.id) return;
|
|
23259
|
-
if (findWiredWcId !== null) {
|
|
23460
|
+
if (findWiredWcId !== null && findResultListener) {
|
|
23260
23461
|
const prev = tabManager.findTabByWebContentsId(findWiredWcId);
|
|
23261
|
-
|
|
23462
|
+
const prevWc = prev?.view.webContents;
|
|
23463
|
+
if (prevWc && !prevWc.isDestroyed()) {
|
|
23464
|
+
prevWc.removeListener("found-in-page", findResultListener);
|
|
23465
|
+
}
|
|
23262
23466
|
}
|
|
23263
23467
|
findWiredWcId = wc.id;
|
|
23264
|
-
wc.
|
|
23468
|
+
if (wc.isDestroyed()) return;
|
|
23469
|
+
const listener = (_event, result) => {
|
|
23265
23470
|
if (!chromeView.webContents.isDestroyed()) {
|
|
23266
23471
|
chromeView.webContents.send(Channels.FIND_IN_PAGE_RESULT, result);
|
|
23267
23472
|
}
|
|
23473
|
+
};
|
|
23474
|
+
findResultListener = listener;
|
|
23475
|
+
wc.on("found-in-page", listener);
|
|
23476
|
+
const capturedWcId = wc.id;
|
|
23477
|
+
wc.once("destroyed", () => {
|
|
23478
|
+
if (findWiredWcId === capturedWcId) {
|
|
23479
|
+
findWiredWcId = null;
|
|
23480
|
+
findResultListener = null;
|
|
23481
|
+
}
|
|
23268
23482
|
});
|
|
23269
23483
|
}
|
|
23270
23484
|
electron.ipcMain.handle(Channels.FIND_IN_PAGE_START, (_, text, options) => {
|
|
@@ -23283,6 +23497,7 @@ function registerIpcHandlers(windowState, runtime2) {
|
|
|
23283
23497
|
if (!tab) return null;
|
|
23284
23498
|
const wc = tab.view.webContents;
|
|
23285
23499
|
if (wc.isDestroyed()) return null;
|
|
23500
|
+
wireFindEvents(wc);
|
|
23286
23501
|
return wc.findInPage("", { forward: forward ?? true, findNext: true });
|
|
23287
23502
|
});
|
|
23288
23503
|
electron.ipcMain.handle(Channels.FIND_IN_PAGE_STOP, (_, action) => {
|
|
@@ -23368,9 +23583,20 @@ function registerIpcHandlers(windowState, runtime2) {
|
|
|
23368
23583
|
sendToRendererViews(Channels.PREMIUM_UPDATE, state2);
|
|
23369
23584
|
return state2;
|
|
23370
23585
|
});
|
|
23586
|
+
const PREMIUM_TRACKABLE_STEPS = [
|
|
23587
|
+
"chat_banner_viewed",
|
|
23588
|
+
"chat_banner_clicked",
|
|
23589
|
+
"settings_banner_viewed",
|
|
23590
|
+
"settings_banner_clicked",
|
|
23591
|
+
"welcome_banner_clicked",
|
|
23592
|
+
"premium_gate_seen",
|
|
23593
|
+
"premium_gate_clicked",
|
|
23594
|
+
"iteration_limit_seen",
|
|
23595
|
+
"iteration_limit_clicked"
|
|
23596
|
+
];
|
|
23371
23597
|
electron.ipcMain.handle(Channels.PREMIUM_TRACK_CONTEXT, (_, step) => {
|
|
23372
23598
|
assertString(step, "step");
|
|
23373
|
-
if (step
|
|
23599
|
+
if (PREMIUM_TRACKABLE_STEPS.includes(step)) {
|
|
23374
23600
|
trackPremiumFunnel(step);
|
|
23375
23601
|
}
|
|
23376
23602
|
});
|
|
@@ -23382,6 +23608,21 @@ function registerIpcHandlers(windowState, runtime2) {
|
|
|
23382
23608
|
}
|
|
23383
23609
|
return result;
|
|
23384
23610
|
});
|
|
23611
|
+
electron.ipcMain.handle(Channels.SESSION_LIST, () => {
|
|
23612
|
+
return listNamedSessions();
|
|
23613
|
+
});
|
|
23614
|
+
electron.ipcMain.handle(Channels.SESSION_SAVE, async (_, name) => {
|
|
23615
|
+
assertString(name, "name");
|
|
23616
|
+
return await saveNamedSession(tabManager, name);
|
|
23617
|
+
});
|
|
23618
|
+
electron.ipcMain.handle(Channels.SESSION_LOAD, async (_, name) => {
|
|
23619
|
+
assertString(name, "name");
|
|
23620
|
+
return await loadNamedSession(tabManager, name);
|
|
23621
|
+
});
|
|
23622
|
+
electron.ipcMain.handle(Channels.SESSION_DELETE, (_, name) => {
|
|
23623
|
+
assertString(name, "name");
|
|
23624
|
+
return deleteNamedSession(name);
|
|
23625
|
+
});
|
|
23385
23626
|
registerVaultHandlers();
|
|
23386
23627
|
registerWindowControlHandlers(mainWindow);
|
|
23387
23628
|
electron.ipcMain.handle(Channels.AUTOMATION_GET_INSTALLED, () => {
|