@quanta-intellect/vessel-browser 0.1.60 → 0.1.63
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 +483 -202
- package/out/preload/index.js +11 -1
- package/out/renderer/assets/{index-CBe7EN_l.css → index-4OgPv5GF.css} +412 -331
- package/out/renderer/assets/{index-NKk_lpQh.js → index-B2vPgkX2.js} +139 -114
- package/out/renderer/index.html +2 -2
- package/package.json +1 -1
package/out/main/index.js
CHANGED
|
@@ -3903,10 +3903,8 @@ function startBackgroundRevalidation() {
|
|
|
3903
3903
|
}, REVALIDATION_INTERVAL_MS);
|
|
3904
3904
|
}
|
|
3905
3905
|
function stopBackgroundRevalidation() {
|
|
3906
|
-
|
|
3907
|
-
|
|
3908
|
-
revalidationTimer = null;
|
|
3909
|
-
}
|
|
3906
|
+
clearInterval(revalidationTimer);
|
|
3907
|
+
revalidationTimer = null;
|
|
3910
3908
|
}
|
|
3911
3909
|
function isPremiumActiveState(state2) {
|
|
3912
3910
|
return state2.status === "active" || state2.status === "trialing";
|
|
@@ -3940,6 +3938,7 @@ let flushTimer = null;
|
|
|
3940
3938
|
let sessionStartedAt = null;
|
|
3941
3939
|
function isEnabled() {
|
|
3942
3940
|
if (POSTHOG_API_KEY === "YOUR_POSTHOG_KEY_HERE") return false;
|
|
3941
|
+
if (process.env.VESSEL_DEV === "1") return false;
|
|
3943
3942
|
return loadSettings().telemetryEnabled !== false;
|
|
3944
3943
|
}
|
|
3945
3944
|
function trackEvent(event, properties = {}) {
|
|
@@ -4011,8 +4010,8 @@ function stopTelemetry() {
|
|
|
4011
4010
|
}
|
|
4012
4011
|
if (flushTimer) {
|
|
4013
4012
|
clearInterval(flushTimer);
|
|
4014
|
-
flushTimer = null;
|
|
4015
4013
|
}
|
|
4014
|
+
flushTimer = null;
|
|
4016
4015
|
void flush();
|
|
4017
4016
|
}
|
|
4018
4017
|
async function flush() {
|
|
@@ -4113,6 +4112,270 @@ function selectorHelpersJS(attributes = DEFAULT_SELECTOR_ATTRIBUTES) {
|
|
|
4113
4112
|
"}"
|
|
4114
4113
|
].join("\n");
|
|
4115
4114
|
}
|
|
4115
|
+
function normalizeString(value) {
|
|
4116
|
+
return (value ?? "").trim().toLowerCase();
|
|
4117
|
+
}
|
|
4118
|
+
function mapInputType(el) {
|
|
4119
|
+
const inputType = el.inputType ?? el.type ?? "text";
|
|
4120
|
+
switch (inputType.toLowerCase()) {
|
|
4121
|
+
case "email":
|
|
4122
|
+
return "email";
|
|
4123
|
+
case "password":
|
|
4124
|
+
return "password";
|
|
4125
|
+
case "number":
|
|
4126
|
+
case "range":
|
|
4127
|
+
return "number";
|
|
4128
|
+
case "select-one":
|
|
4129
|
+
case "select":
|
|
4130
|
+
return "select";
|
|
4131
|
+
case "checkbox":
|
|
4132
|
+
case "radio":
|
|
4133
|
+
return "checkbox";
|
|
4134
|
+
case "date":
|
|
4135
|
+
case "datetime-local":
|
|
4136
|
+
case "time":
|
|
4137
|
+
case "month":
|
|
4138
|
+
case "week":
|
|
4139
|
+
return "date";
|
|
4140
|
+
case "file":
|
|
4141
|
+
return "file";
|
|
4142
|
+
default:
|
|
4143
|
+
return "text";
|
|
4144
|
+
}
|
|
4145
|
+
}
|
|
4146
|
+
function mapFormFields(forms, interactiveElements) {
|
|
4147
|
+
const fields = [];
|
|
4148
|
+
const formFieldSelectors = /* @__PURE__ */ new Set();
|
|
4149
|
+
for (const form of forms) {
|
|
4150
|
+
for (const el of form.fields ?? []) {
|
|
4151
|
+
formFieldSelectors.add(el.selector || el.name || el.label || String(el.index));
|
|
4152
|
+
}
|
|
4153
|
+
}
|
|
4154
|
+
for (const el of interactiveElements) {
|
|
4155
|
+
const key = el.selector || el.name || el.label || String(el.index);
|
|
4156
|
+
if (formFieldSelectors.has(key)) {
|
|
4157
|
+
fields.push({
|
|
4158
|
+
name: el.name || el.label || key,
|
|
4159
|
+
type: mapInputType(el),
|
|
4160
|
+
label: el.label,
|
|
4161
|
+
required: el.required,
|
|
4162
|
+
selector: el.selector || ""
|
|
4163
|
+
});
|
|
4164
|
+
}
|
|
4165
|
+
}
|
|
4166
|
+
return fields;
|
|
4167
|
+
}
|
|
4168
|
+
function mapActionButtons(interactiveElements) {
|
|
4169
|
+
const buttons = [];
|
|
4170
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4171
|
+
for (const el of interactiveElements) {
|
|
4172
|
+
if (el.type !== "button" && el.type !== "submit" && el.type !== "reset") continue;
|
|
4173
|
+
const label = (el.label || el.textContent || "").trim();
|
|
4174
|
+
if (!label || seen.has(label)) continue;
|
|
4175
|
+
seen.add(label);
|
|
4176
|
+
let intent;
|
|
4177
|
+
const normalized = normalizeString(label);
|
|
4178
|
+
if (/\b(add to cart|buy now|add to bag|add to basket|shop now)\b/.test(normalized)) {
|
|
4179
|
+
intent = "addToCart";
|
|
4180
|
+
} else if (/\b(login|sign in|log in|signin|log-in)\b/.test(normalized)) {
|
|
4181
|
+
intent = "login";
|
|
4182
|
+
} else if (/\b(submit|send|continue|next|proceed|register|create account|sign up)\b/.test(normalized)) {
|
|
4183
|
+
intent = "submit";
|
|
4184
|
+
} else if (/\b(cancel|back|return|go back|close)\b/.test(normalized)) {
|
|
4185
|
+
intent = "cancel";
|
|
4186
|
+
} else if (/\b(download|export|save as)\b/.test(normalized)) {
|
|
4187
|
+
intent = "download";
|
|
4188
|
+
} else if (/\b(search|find|go|submit search)\b/.test(normalized)) {
|
|
4189
|
+
intent = "search";
|
|
4190
|
+
} else if (el.href || el.url) {
|
|
4191
|
+
intent = "navigate";
|
|
4192
|
+
}
|
|
4193
|
+
if (el.selector || el.name || el.label) {
|
|
4194
|
+
buttons.push({
|
|
4195
|
+
label,
|
|
4196
|
+
selector: el.selector || el.name || el.label,
|
|
4197
|
+
intent
|
|
4198
|
+
});
|
|
4199
|
+
}
|
|
4200
|
+
}
|
|
4201
|
+
return buttons;
|
|
4202
|
+
}
|
|
4203
|
+
function asStructuredObject(value) {
|
|
4204
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
4205
|
+
}
|
|
4206
|
+
function stringifyStructuredScalar(value) {
|
|
4207
|
+
if (typeof value === "string") {
|
|
4208
|
+
const trimmed = value.trim();
|
|
4209
|
+
return trimmed || void 0;
|
|
4210
|
+
}
|
|
4211
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
4212
|
+
return String(value);
|
|
4213
|
+
}
|
|
4214
|
+
return void 0;
|
|
4215
|
+
}
|
|
4216
|
+
function firstStructuredString(...values) {
|
|
4217
|
+
for (const value of values) {
|
|
4218
|
+
const normalized = stringifyStructuredScalar(value);
|
|
4219
|
+
if (normalized) return normalized;
|
|
4220
|
+
}
|
|
4221
|
+
return void 0;
|
|
4222
|
+
}
|
|
4223
|
+
function getOfferPrice(offers) {
|
|
4224
|
+
if (Array.isArray(offers)) {
|
|
4225
|
+
for (const offer2 of offers) {
|
|
4226
|
+
const price = getOfferPrice(offer2);
|
|
4227
|
+
if (price) return price;
|
|
4228
|
+
}
|
|
4229
|
+
return void 0;
|
|
4230
|
+
}
|
|
4231
|
+
const offer = asStructuredObject(offers);
|
|
4232
|
+
return firstStructuredString(offer?.price);
|
|
4233
|
+
}
|
|
4234
|
+
function extractPrimaryEntity(pageType, structuredData, metaTags) {
|
|
4235
|
+
if (pageType === "product") {
|
|
4236
|
+
const product = structuredData?.find(
|
|
4237
|
+
(e) => e.types.some((t) => /^product$/i.test(t))
|
|
4238
|
+
);
|
|
4239
|
+
if (product) {
|
|
4240
|
+
const attrs = product.attributes ?? {};
|
|
4241
|
+
const aggregateRating = asStructuredObject(attrs.aggregateRating);
|
|
4242
|
+
return {
|
|
4243
|
+
type: "Product",
|
|
4244
|
+
nameField: firstStructuredString(attrs.name),
|
|
4245
|
+
priceField: firstStructuredString(attrs.price) ?? getOfferPrice(attrs.offers),
|
|
4246
|
+
imageField: firstStructuredString(
|
|
4247
|
+
attrs.image,
|
|
4248
|
+
Array.isArray(attrs.image) ? attrs.image[0] : void 0
|
|
4249
|
+
),
|
|
4250
|
+
descriptionField: firstStructuredString(attrs.description),
|
|
4251
|
+
reviewsField: firstStructuredString(
|
|
4252
|
+
attrs.reviews,
|
|
4253
|
+
attrs.reviewCount,
|
|
4254
|
+
aggregateRating?.reviewCount,
|
|
4255
|
+
aggregateRating?.ratingCount
|
|
4256
|
+
),
|
|
4257
|
+
ratingField: firstStructuredString(
|
|
4258
|
+
attrs.rating,
|
|
4259
|
+
attrs.ratingValue,
|
|
4260
|
+
aggregateRating?.ratingValue
|
|
4261
|
+
),
|
|
4262
|
+
addToCartField: void 0
|
|
4263
|
+
};
|
|
4264
|
+
}
|
|
4265
|
+
}
|
|
4266
|
+
if (pageType === "article") {
|
|
4267
|
+
const article = structuredData?.find(
|
|
4268
|
+
(e) => e.types.some(
|
|
4269
|
+
(t) => /^(article|newsarticle|blogposting|webpage)$/i.test(t)
|
|
4270
|
+
)
|
|
4271
|
+
);
|
|
4272
|
+
if (article) {
|
|
4273
|
+
const attrs = article.attributes ?? {};
|
|
4274
|
+
return {
|
|
4275
|
+
type: article.types[0] ?? "Article",
|
|
4276
|
+
nameField: typeof attrs.headline === "string" ? attrs.headline : typeof attrs.name === "string" ? attrs.name : void 0,
|
|
4277
|
+
descriptionField: typeof attrs.articleBody === "string" ? attrs.articleBody : typeof attrs.description === "string" ? attrs.description : void 0
|
|
4278
|
+
};
|
|
4279
|
+
}
|
|
4280
|
+
}
|
|
4281
|
+
return void 0;
|
|
4282
|
+
}
|
|
4283
|
+
function inferPageSchema(page) {
|
|
4284
|
+
let pageType = "unknown";
|
|
4285
|
+
let confidence = 0.5;
|
|
4286
|
+
const structuredData = page.structuredData;
|
|
4287
|
+
const metaTags = page.metaTags;
|
|
4288
|
+
const url = page.url ?? "";
|
|
4289
|
+
const forms = page.forms ?? [];
|
|
4290
|
+
const interactiveElements = page.interactiveElements ?? [];
|
|
4291
|
+
const urlLower = normalizeString(url);
|
|
4292
|
+
const jsonLdTypes = [];
|
|
4293
|
+
for (const entity of structuredData ?? []) {
|
|
4294
|
+
jsonLdTypes.push(...entity.types);
|
|
4295
|
+
}
|
|
4296
|
+
const hasProduct = jsonLdTypes.some((t) => /^product$/i.test(t));
|
|
4297
|
+
const hasArticle = jsonLdTypes.some(
|
|
4298
|
+
(t) => /^(article|newsarticle|blogposting)$/i.test(t)
|
|
4299
|
+
);
|
|
4300
|
+
const hasEvent = jsonLdTypes.some((t) => /^event$/i.test(t));
|
|
4301
|
+
const hasSearchResults = jsonLdTypes.some((t) => /^searchresultspage$/i.test(t));
|
|
4302
|
+
if (hasProduct) {
|
|
4303
|
+
pageType = "product";
|
|
4304
|
+
confidence += 0.2;
|
|
4305
|
+
} else if (hasArticle) {
|
|
4306
|
+
pageType = "article";
|
|
4307
|
+
confidence += 0.2;
|
|
4308
|
+
} else if (hasEvent) {
|
|
4309
|
+
pageType = "form";
|
|
4310
|
+
confidence += 0.15;
|
|
4311
|
+
} else if (hasSearchResults) {
|
|
4312
|
+
pageType = "search";
|
|
4313
|
+
confidence += 0.2;
|
|
4314
|
+
}
|
|
4315
|
+
const ogType = metaTags?.["og:type"];
|
|
4316
|
+
if (ogType) {
|
|
4317
|
+
const normalized = normalizeString(ogType);
|
|
4318
|
+
if (/^product$/i.test(normalized) && pageType !== "product") {
|
|
4319
|
+
pageType = "product";
|
|
4320
|
+
confidence += 0.15;
|
|
4321
|
+
} else if (/^article|blog|news/i.test(normalized) && pageType !== "article") {
|
|
4322
|
+
pageType = "article";
|
|
4323
|
+
confidence += 0.15;
|
|
4324
|
+
}
|
|
4325
|
+
}
|
|
4326
|
+
if (/\/checkout|\/cart|\/payment|\/billing/i.test(urlLower) && pageType === "unknown") {
|
|
4327
|
+
pageType = "checkout";
|
|
4328
|
+
confidence += 0.1;
|
|
4329
|
+
} else if (/\/login|\/signin|\/auth/i.test(urlLower) && pageType === "unknown") {
|
|
4330
|
+
pageType = "login";
|
|
4331
|
+
confidence += 0.1;
|
|
4332
|
+
} else if (/\/dashboard|\/account|\/profile/i.test(urlLower) && pageType === "unknown") {
|
|
4333
|
+
pageType = "dashboard";
|
|
4334
|
+
confidence += 0.1;
|
|
4335
|
+
} else if (/\/search/i.test(urlLower) && pageType === "unknown") {
|
|
4336
|
+
pageType = "search";
|
|
4337
|
+
confidence += 0.1;
|
|
4338
|
+
}
|
|
4339
|
+
const hasFormWithSubmit = forms.some(
|
|
4340
|
+
(f) => f.fields.some(
|
|
4341
|
+
(el) => el.type === "submit" || normalizeString(el.inputType) === "submit" || normalizeString(el.name) === "submit"
|
|
4342
|
+
)
|
|
4343
|
+
);
|
|
4344
|
+
const hasPriceSelectors = interactiveElements.some(
|
|
4345
|
+
(el) => el.selector?.includes("price") || normalizeString(el.label).includes("price") || normalizeString(el.name).includes("price") || el.selector?.includes("cost") || el.selector?.includes("amount")
|
|
4346
|
+
);
|
|
4347
|
+
if (pageType === "unknown") {
|
|
4348
|
+
if (hasFormWithSubmit && forms.length > 0) {
|
|
4349
|
+
pageType = "form";
|
|
4350
|
+
confidence += 0.1;
|
|
4351
|
+
} else if (hasPriceSelectors) {
|
|
4352
|
+
pageType = "product";
|
|
4353
|
+
confidence += 0.1;
|
|
4354
|
+
}
|
|
4355
|
+
}
|
|
4356
|
+
if ((pageType === "checkout" || pageType === "unknown") && forms.length > 0) {
|
|
4357
|
+
if (hasFormWithSubmit) {
|
|
4358
|
+
if (pageType === "unknown") {
|
|
4359
|
+
pageType = "form";
|
|
4360
|
+
}
|
|
4361
|
+
confidence += 0.15;
|
|
4362
|
+
}
|
|
4363
|
+
}
|
|
4364
|
+
if (pageType === "unknown") {
|
|
4365
|
+
confidence = 0.5;
|
|
4366
|
+
}
|
|
4367
|
+
confidence = Math.min(0.95, confidence);
|
|
4368
|
+
const primaryEntity = extractPrimaryEntity(pageType, structuredData);
|
|
4369
|
+
const formFields = pageType === "form" || pageType === "checkout" || pageType === "login" ? mapFormFields(forms, interactiveElements) : void 0;
|
|
4370
|
+
const actionButtons = mapActionButtons(interactiveElements);
|
|
4371
|
+
return {
|
|
4372
|
+
pageType,
|
|
4373
|
+
primaryEntity,
|
|
4374
|
+
formFields,
|
|
4375
|
+
actionButtons,
|
|
4376
|
+
confidence
|
|
4377
|
+
};
|
|
4378
|
+
}
|
|
4116
4379
|
const EMPTY_PAGE_CONTENT = {
|
|
4117
4380
|
title: "",
|
|
4118
4381
|
content: "",
|
|
@@ -4826,156 +5089,6 @@ const DIRECT_EXTRACTION_SCRIPT = String.raw`
|
|
|
4826
5089
|
};
|
|
4827
5090
|
})()
|
|
4828
5091
|
`;
|
|
4829
|
-
const SAFE_EXTRACTION_SCRIPT = String.raw`
|
|
4830
|
-
(function() {
|
|
4831
|
-
function getCleanBodyText() {
|
|
4832
|
-
var removed = [];
|
|
4833
|
-
document
|
|
4834
|
-
.querySelectorAll('.__vessel-highlight-label[data-vessel-highlight]')
|
|
4835
|
-
.forEach(function(label) {
|
|
4836
|
-
var parent = label.parentNode;
|
|
4837
|
-
if (!parent) return;
|
|
4838
|
-
removed.push({ label: label, parent: parent, nextSibling: label.nextSibling });
|
|
4839
|
-
parent.removeChild(label);
|
|
4840
|
-
});
|
|
4841
|
-
try {
|
|
4842
|
-
return document.body?.innerText || document.documentElement?.innerText || "";
|
|
4843
|
-
} finally {
|
|
4844
|
-
for (var i = removed.length - 1; i >= 0; i--) {
|
|
4845
|
-
var entry = removed[i];
|
|
4846
|
-
entry.parent.insertBefore(entry.label, entry.nextSibling);
|
|
4847
|
-
}
|
|
4848
|
-
}
|
|
4849
|
-
}
|
|
4850
|
-
|
|
4851
|
-
function text(value) {
|
|
4852
|
-
const trimmed = value == null ? "" : String(value).trim();
|
|
4853
|
-
return trimmed || undefined;
|
|
4854
|
-
}
|
|
4855
|
-
|
|
4856
|
-
function labelFor(el) {
|
|
4857
|
-
const aria = text(el.getAttribute && el.getAttribute("aria-label"));
|
|
4858
|
-
if (aria) return aria;
|
|
4859
|
-
const placeholder = text(el.getAttribute && el.getAttribute("placeholder"));
|
|
4860
|
-
if (placeholder) return placeholder;
|
|
4861
|
-
if (el.id) {
|
|
4862
|
-
const directLabel = document.querySelector('label[for="' + String(el.id).replace(/["\\]/g, "\\$&") + '"]');
|
|
4863
|
-
const labelText = text(directLabel && directLabel.textContent);
|
|
4864
|
-
if (labelText) return labelText;
|
|
4865
|
-
}
|
|
4866
|
-
return text(el.textContent);
|
|
4867
|
-
}
|
|
4868
|
-
|
|
4869
|
-
let indexCounter = 0;
|
|
4870
|
-
function nextIndex() {
|
|
4871
|
-
indexCounter += 1;
|
|
4872
|
-
return indexCounter;
|
|
4873
|
-
}
|
|
4874
|
-
|
|
4875
|
-
const headings = Array.from(document.querySelectorAll("h1, h2, h3, h4, h5, h6"))
|
|
4876
|
-
.map((el) => {
|
|
4877
|
-
const headingText = text(el.textContent);
|
|
4878
|
-
if (!headingText) return null;
|
|
4879
|
-
return { level: Number.parseInt(el.tagName[1], 10), text: headingText };
|
|
4880
|
-
})
|
|
4881
|
-
.filter(Boolean);
|
|
4882
|
-
|
|
4883
|
-
const navigation = Array.from(document.querySelectorAll("nav a[href], [role='navigation'] a[href], header nav a[href]"))
|
|
4884
|
-
.map((el) => {
|
|
4885
|
-
const href = text(el.href || el.getAttribute("href"));
|
|
4886
|
-
const linkText = text(el.textContent);
|
|
4887
|
-
if (!href || href.startsWith("#") || !linkText) return null;
|
|
4888
|
-
return {
|
|
4889
|
-
type: "link",
|
|
4890
|
-
text: linkText.slice(0, 100),
|
|
4891
|
-
href: href.slice(0, 500),
|
|
4892
|
-
context: "nav",
|
|
4893
|
-
index: nextIndex(),
|
|
4894
|
-
visible: true,
|
|
4895
|
-
disabled: false,
|
|
4896
|
-
};
|
|
4897
|
-
})
|
|
4898
|
-
.filter(Boolean);
|
|
4899
|
-
|
|
4900
|
-
const interactiveElements = [];
|
|
4901
|
-
Array.from(document.querySelectorAll("button, [role='button'], input[type='submit'], input[type='button']"))
|
|
4902
|
-
.forEach((el) => {
|
|
4903
|
-
interactiveElements.push({
|
|
4904
|
-
type: "button",
|
|
4905
|
-
text: text(el.textContent || el.value || el.getAttribute("aria-label") || "Button")?.slice(0, 100),
|
|
4906
|
-
index: nextIndex(),
|
|
4907
|
-
visible: true,
|
|
4908
|
-
disabled: !!(el.hasAttribute && (el.hasAttribute("disabled") || el.getAttribute("aria-disabled") === "true")),
|
|
4909
|
-
});
|
|
4910
|
-
});
|
|
4911
|
-
|
|
4912
|
-
Array.from(document.querySelectorAll("a[href]")).forEach((el) => {
|
|
4913
|
-
const href = text(el.href || el.getAttribute("href"));
|
|
4914
|
-
const linkText = text(el.textContent);
|
|
4915
|
-
if (!href || href.startsWith("#") || !linkText) return;
|
|
4916
|
-
interactiveElements.push({
|
|
4917
|
-
type: "link",
|
|
4918
|
-
text: linkText.slice(0, 100),
|
|
4919
|
-
href: href.slice(0, 500),
|
|
4920
|
-
index: nextIndex(),
|
|
4921
|
-
visible: true,
|
|
4922
|
-
disabled: false,
|
|
4923
|
-
});
|
|
4924
|
-
});
|
|
4925
|
-
|
|
4926
|
-
Array.from(document.querySelectorAll("input:not([type='hidden']):not([type='submit']):not([type='button']), select, textarea"))
|
|
4927
|
-
.forEach((el) => {
|
|
4928
|
-
const tag = el.tagName.toLowerCase();
|
|
4929
|
-
var elType = (el.type || "").toLowerCase();
|
|
4930
|
-
interactiveElements.push({
|
|
4931
|
-
type: tag === "select" ? "select" : tag === "textarea" ? "textarea" : "input",
|
|
4932
|
-
label: labelFor(el)?.slice(0, 100),
|
|
4933
|
-
inputType: text(el.getAttribute && el.getAttribute("type")),
|
|
4934
|
-
placeholder: text(el.getAttribute && el.getAttribute("placeholder")),
|
|
4935
|
-
value: shouldExposeFieldValue(el) ? text(el.value) : undefined,
|
|
4936
|
-
options: tag === "select"
|
|
4937
|
-
? 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)
|
|
4938
|
-
: undefined,
|
|
4939
|
-
required: !!(el.hasAttribute && el.hasAttribute("required")) || undefined,
|
|
4940
|
-
index: nextIndex(),
|
|
4941
|
-
visible: true,
|
|
4942
|
-
disabled: !!(el.hasAttribute && (el.hasAttribute("disabled") || el.getAttribute("aria-disabled") === "true")),
|
|
4943
|
-
name: el.name || undefined,
|
|
4944
|
-
autocomplete: text(el.getAttribute && el.getAttribute("autocomplete")),
|
|
4945
|
-
checked: (elType === "checkbox" || elType === "radio") ? !!el.checked : undefined,
|
|
4946
|
-
});
|
|
4947
|
-
});
|
|
4948
|
-
|
|
4949
|
-
const forms = Array.from(document.querySelectorAll("form")).map((form) => ({
|
|
4950
|
-
id: text(form.id),
|
|
4951
|
-
action: text(form.getAttribute("action")),
|
|
4952
|
-
method: text(form.getAttribute("method")),
|
|
4953
|
-
fields: [],
|
|
4954
|
-
}));
|
|
4955
|
-
|
|
4956
|
-
return {
|
|
4957
|
-
title: document.title || "",
|
|
4958
|
-
content: getCleanBodyText(),
|
|
4959
|
-
htmlContent: "",
|
|
4960
|
-
byline: "",
|
|
4961
|
-
excerpt: "",
|
|
4962
|
-
url: window.location.href || "",
|
|
4963
|
-
headings,
|
|
4964
|
-
navigation,
|
|
4965
|
-
interactiveElements,
|
|
4966
|
-
forms,
|
|
4967
|
-
viewport: {
|
|
4968
|
-
width: window.innerWidth || document.documentElement?.clientWidth || 0,
|
|
4969
|
-
height: window.innerHeight || document.documentElement?.clientHeight || 0,
|
|
4970
|
-
scrollX: 0,
|
|
4971
|
-
scrollY: 0,
|
|
4972
|
-
},
|
|
4973
|
-
overlays: [],
|
|
4974
|
-
dormantOverlays: [],
|
|
4975
|
-
landmarks: [],
|
|
4976
|
-
};
|
|
4977
|
-
})()
|
|
4978
|
-
`;
|
|
4979
5092
|
function delay(ms) {
|
|
4980
5093
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
4981
5094
|
}
|
|
@@ -5012,7 +5125,7 @@ async function executeScript(webContents, script) {
|
|
|
5012
5125
|
} catch {
|
|
5013
5126
|
return null;
|
|
5014
5127
|
} finally {
|
|
5015
|
-
if (
|
|
5128
|
+
if (timer) {
|
|
5016
5129
|
clearTimeout(timer);
|
|
5017
5130
|
}
|
|
5018
5131
|
}
|
|
@@ -5087,10 +5200,17 @@ function mergePageContent(candidates, webContents) {
|
|
|
5087
5200
|
headings: mergedBase.headings,
|
|
5088
5201
|
metaTags: mergedBase.metaTags
|
|
5089
5202
|
});
|
|
5203
|
+
const pageSchema = inferPageSchema({
|
|
5204
|
+
...mergedBase,
|
|
5205
|
+
structuredData: normalizedStructuredData,
|
|
5206
|
+
title: mergedBase.title || webContents.getTitle() || "",
|
|
5207
|
+
url: mergedBase.url || webContents.getURL() || ""
|
|
5208
|
+
});
|
|
5090
5209
|
return {
|
|
5091
5210
|
...mergedBase,
|
|
5092
5211
|
structuredData: normalizedStructuredData,
|
|
5093
5212
|
pageIssues,
|
|
5213
|
+
pageSchema,
|
|
5094
5214
|
title: mergedBase.title || webContents.getTitle() || "",
|
|
5095
5215
|
url: mergedBase.url || webContents.getURL() || ""
|
|
5096
5216
|
};
|
|
@@ -5116,13 +5236,12 @@ async function estimateExtractionTimeout(webContents) {
|
|
|
5116
5236
|
}
|
|
5117
5237
|
async function extractContentInner(webContents) {
|
|
5118
5238
|
await waitForDomReady(webContents);
|
|
5119
|
-
const [preloadResult, directResult
|
|
5239
|
+
const [preloadResult, directResult] = await Promise.all([
|
|
5120
5240
|
executeScript(webContents, PRELOAD_EXTRACTION_SCRIPT),
|
|
5121
|
-
executeScript(webContents, DIRECT_EXTRACTION_SCRIPT)
|
|
5122
|
-
executeScript(webContents, SAFE_EXTRACTION_SCRIPT)
|
|
5241
|
+
executeScript(webContents, DIRECT_EXTRACTION_SCRIPT)
|
|
5123
5242
|
]);
|
|
5124
5243
|
return mergePageContent(
|
|
5125
|
-
[preloadResult, directResult
|
|
5244
|
+
[preloadResult, directResult],
|
|
5126
5245
|
webContents
|
|
5127
5246
|
);
|
|
5128
5247
|
}
|
|
@@ -5179,7 +5298,8 @@ function normalizePageContent(value) {
|
|
|
5179
5298
|
rdfa: Array.isArray(page.rdfa) ? page.rdfa : [],
|
|
5180
5299
|
metaTags: page.metaTags && typeof page.metaTags === "object" && !Array.isArray(page.metaTags) ? page.metaTags : {},
|
|
5181
5300
|
structuredData: Array.isArray(page.structuredData) ? page.structuredData : [],
|
|
5182
|
-
pageIssues: Array.isArray(page.pageIssues) ? page.pageIssues : []
|
|
5301
|
+
pageIssues: Array.isArray(page.pageIssues) ? page.pageIssues : [],
|
|
5302
|
+
pageSchema: page.pageSchema
|
|
5183
5303
|
};
|
|
5184
5304
|
}
|
|
5185
5305
|
const latestPageDiffs = /* @__PURE__ */ new Map();
|
|
@@ -5189,17 +5309,19 @@ const pendingPageSnapshotDueAt = /* @__PURE__ */ new Map();
|
|
|
5189
5309
|
const lastMutationSnapshotAt = /* @__PURE__ */ new Map();
|
|
5190
5310
|
const lastMutationActivityAt = /* @__PURE__ */ new Map();
|
|
5191
5311
|
const destroyListenerAttached = /* @__PURE__ */ new WeakSet();
|
|
5312
|
+
function cleanupTimersForWcId(wcId) {
|
|
5313
|
+
const timer = pendingPageSnapshotTimers.get(wcId);
|
|
5314
|
+
if (timer) clearTimeout(timer);
|
|
5315
|
+
pendingPageSnapshotTimers.delete(wcId);
|
|
5316
|
+
pendingPageSnapshotDueAt.delete(wcId);
|
|
5317
|
+
lastMutationSnapshotAt.delete(wcId);
|
|
5318
|
+
lastMutationActivityAt.delete(wcId);
|
|
5319
|
+
}
|
|
5192
5320
|
function attachDestroyCleanup(wc) {
|
|
5193
5321
|
if (destroyListenerAttached.has(wc)) return;
|
|
5194
5322
|
destroyListenerAttached.add(wc);
|
|
5195
5323
|
wc.once("destroyed", () => {
|
|
5196
|
-
|
|
5197
|
-
const timer = pendingPageSnapshotTimers.get(wcId);
|
|
5198
|
-
if (timer) clearTimeout(timer);
|
|
5199
|
-
pendingPageSnapshotTimers.delete(wcId);
|
|
5200
|
-
pendingPageSnapshotDueAt.delete(wcId);
|
|
5201
|
-
lastMutationSnapshotAt.delete(wcId);
|
|
5202
|
-
lastMutationActivityAt.delete(wcId);
|
|
5324
|
+
cleanupTimersForWcId(wc.id);
|
|
5203
5325
|
});
|
|
5204
5326
|
}
|
|
5205
5327
|
const MIN_MUTATION_CAPTURE_INTERVAL_MS = 5e3;
|
|
@@ -5271,8 +5393,7 @@ function scheduleTimerAt(wc, sendToRendererViews, dueAt) {
|
|
|
5271
5393
|
const existing = pendingPageSnapshotTimers.get(wcId);
|
|
5272
5394
|
if (existing) clearTimeout(existing);
|
|
5273
5395
|
const timer = setTimeout(() => {
|
|
5274
|
-
|
|
5275
|
-
pendingPageSnapshotDueAt.delete(wcId);
|
|
5396
|
+
cleanupTimersForWcId(wcId);
|
|
5276
5397
|
if (wc.isDestroyed()) return;
|
|
5277
5398
|
lastMutationSnapshotAt.set(wcId, Date.now());
|
|
5278
5399
|
void capturePageSnapshot(wc.getURL(), wc, sendToRendererViews);
|
|
@@ -5596,9 +5717,9 @@ function resizeSidebarViews(state2) {
|
|
|
5596
5717
|
const contentWidth = width - sidebarWidth;
|
|
5597
5718
|
sidebarView.setBounds({
|
|
5598
5719
|
x: width - sidebarWidth - resizeHandleOverlap,
|
|
5599
|
-
y:
|
|
5720
|
+
y: chromeHeight,
|
|
5600
5721
|
width: sidebarWidth + resizeHandleOverlap,
|
|
5601
|
-
height
|
|
5722
|
+
height: height - chromeHeight
|
|
5602
5723
|
});
|
|
5603
5724
|
if (uiState.devtoolsPanelOpen) {
|
|
5604
5725
|
devtoolsPanelView.setBounds({
|
|
@@ -9761,7 +9882,17 @@ const TOOL_DEFINITIONS = [
|
|
|
9761
9882
|
folderSummary: zod.z.string().optional().describe("Optional summary used if a new folder is created"),
|
|
9762
9883
|
createFolderIfMissing: zod.z.boolean().optional().describe("Create folderName automatically when it does not exist"),
|
|
9763
9884
|
note: zod.z.string().optional().describe("Optional note about why the page was saved"),
|
|
9764
|
-
onDuplicate: zod.z.enum(["ask", "update", "duplicate"]).optional().describe("How to handle duplicate URLs in the same folder")
|
|
9885
|
+
onDuplicate: zod.z.enum(["ask", "update", "duplicate"]).optional().describe("How to handle duplicate URLs in the same folder"),
|
|
9886
|
+
intent: zod.z.string().optional().describe(
|
|
9887
|
+
"Human-readable description of what this bookmark is for (e.g. 'expense reporting')"
|
|
9888
|
+
),
|
|
9889
|
+
expectedContent: zod.z.string().optional().describe(
|
|
9890
|
+
"Brief description of the content the agent should expect to find here"
|
|
9891
|
+
),
|
|
9892
|
+
keyFields: zod.z.array(zod.z.string()).optional().describe(
|
|
9893
|
+
"Important form field names for this page (e.g. ['receipt_id', 'date', 'amount'])"
|
|
9894
|
+
),
|
|
9895
|
+
agentHints: zod.z.record(zod.z.string(), zod.z.string()).optional().describe("Arbitrary key-value hints for the agent")
|
|
9765
9896
|
},
|
|
9766
9897
|
tier: 1
|
|
9767
9898
|
},
|
|
@@ -9780,7 +9911,11 @@ const TOOL_DEFINITIONS = [
|
|
|
9780
9911
|
folderSummary: zod.z.string().optional().describe("Optional summary for new folder"),
|
|
9781
9912
|
createFolderIfMissing: zod.z.boolean().optional().describe("Create folderName automatically when it does not exist"),
|
|
9782
9913
|
note: zod.z.string().optional().describe("Optional note"),
|
|
9783
|
-
archive: zod.z.boolean().optional().describe('If true, organize into the default "Archive" folder')
|
|
9914
|
+
archive: zod.z.boolean().optional().describe('If true, organize into the default "Archive" folder'),
|
|
9915
|
+
intent: zod.z.string().optional().describe("Human-readable description of what this bookmark is for"),
|
|
9916
|
+
expectedContent: zod.z.string().optional().describe("Brief description of content the agent should expect"),
|
|
9917
|
+
keyFields: zod.z.array(zod.z.string()).optional().describe("Important form field names for this page"),
|
|
9918
|
+
agentHints: zod.z.record(zod.z.string(), zod.z.string()).optional().describe("Arbitrary key-value hints for the agent")
|
|
9784
9919
|
},
|
|
9785
9920
|
tier: 2
|
|
9786
9921
|
},
|
|
@@ -10352,7 +10487,9 @@ const FIELD_WEIGHTS = {
|
|
|
10352
10487
|
note: 5,
|
|
10353
10488
|
folder: 3,
|
|
10354
10489
|
folderSummary: 2,
|
|
10355
|
-
url: 1
|
|
10490
|
+
url: 1,
|
|
10491
|
+
intent: 4,
|
|
10492
|
+
expectedContent: 3
|
|
10356
10493
|
};
|
|
10357
10494
|
function normalizeBookmarkSearchText(value) {
|
|
10358
10495
|
let normalized = value.toLowerCase();
|
|
@@ -10383,7 +10520,9 @@ function getBookmarkSearchMatch(args) {
|
|
|
10383
10520
|
url: args.url,
|
|
10384
10521
|
note: args.note,
|
|
10385
10522
|
folder: args.folder,
|
|
10386
|
-
folderSummary: args.folderSummary
|
|
10523
|
+
folderSummary: args.folderSummary,
|
|
10524
|
+
intent: args.intent,
|
|
10525
|
+
expectedContent: args.expectedContent
|
|
10387
10526
|
};
|
|
10388
10527
|
for (const field of Object.keys(values)) {
|
|
10389
10528
|
if (!bookmarkFieldMatchesQuery(values[field], normalizedQuery, tokens)) {
|
|
@@ -10523,7 +10662,9 @@ function searchBookmarks(query) {
|
|
|
10523
10662
|
url: bookmark.url,
|
|
10524
10663
|
note: bookmark.note,
|
|
10525
10664
|
folder: folder?.name,
|
|
10526
|
-
folderSummary: folder?.summary
|
|
10665
|
+
folderSummary: folder?.summary,
|
|
10666
|
+
intent: bookmark.intent,
|
|
10667
|
+
expectedContent: bookmark.expectedContent
|
|
10527
10668
|
});
|
|
10528
10669
|
return {
|
|
10529
10670
|
bookmark,
|
|
@@ -10603,6 +10744,9 @@ function saveBookmarkWithPolicy(url, title, folderId, note, options) {
|
|
|
10603
10744
|
if (note !== void 0) {
|
|
10604
10745
|
bookmark2.note = note.trim() || void 0;
|
|
10605
10746
|
}
|
|
10747
|
+
if (options?.extra) {
|
|
10748
|
+
Object.assign(bookmark2, options.extra);
|
|
10749
|
+
}
|
|
10606
10750
|
bookmark2.savedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
10607
10751
|
save();
|
|
10608
10752
|
emit();
|
|
@@ -10618,7 +10762,8 @@ function saveBookmarkWithPolicy(url, title, folderId, note, options) {
|
|
|
10618
10762
|
title: normalizedTitle,
|
|
10619
10763
|
note: note?.trim() || void 0,
|
|
10620
10764
|
folderId: targetId,
|
|
10621
|
-
savedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
10765
|
+
savedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
10766
|
+
...options?.extra
|
|
10622
10767
|
};
|
|
10623
10768
|
state$1.bookmarks.push(bookmark);
|
|
10624
10769
|
save();
|
|
@@ -10654,6 +10799,21 @@ function updateBookmark(id, updates) {
|
|
|
10654
10799
|
if (typeof updates.folderId === "string") {
|
|
10655
10800
|
bookmark.folderId = updates.folderId && updates.folderId !== UNSORTED_ID ? state$1.folders.find((item) => item.id === updates.folderId)?.id ?? UNSORTED_ID : UNSORTED_ID;
|
|
10656
10801
|
}
|
|
10802
|
+
if (typeof updates.intent === "string") {
|
|
10803
|
+
bookmark.intent = updates.intent.trim() || void 0;
|
|
10804
|
+
}
|
|
10805
|
+
if (typeof updates.expectedContent === "string") {
|
|
10806
|
+
bookmark.expectedContent = updates.expectedContent.trim() || void 0;
|
|
10807
|
+
}
|
|
10808
|
+
if (updates.keyFields !== void 0) {
|
|
10809
|
+
bookmark.keyFields = updates.keyFields;
|
|
10810
|
+
}
|
|
10811
|
+
if (updates.pageSchema !== void 0) {
|
|
10812
|
+
bookmark.pageSchema = updates.pageSchema;
|
|
10813
|
+
}
|
|
10814
|
+
if (updates.agentHints !== void 0) {
|
|
10815
|
+
bookmark.agentHints = updates.agentHints;
|
|
10816
|
+
}
|
|
10657
10817
|
save();
|
|
10658
10818
|
emit();
|
|
10659
10819
|
return { ...bookmark };
|
|
@@ -11634,6 +11794,33 @@ function formatCompactToolResult(name, result) {
|
|
|
11634
11794
|
return limitText(result, 18, 1400);
|
|
11635
11795
|
}
|
|
11636
11796
|
}
|
|
11797
|
+
function normalizeOptionalString(value) {
|
|
11798
|
+
if (typeof value !== "string") return void 0;
|
|
11799
|
+
const trimmed = value.trim();
|
|
11800
|
+
return trimmed || void 0;
|
|
11801
|
+
}
|
|
11802
|
+
function normalizeKeyFields(value) {
|
|
11803
|
+
if (!Array.isArray(value)) return void 0;
|
|
11804
|
+
const normalized = value.filter((field) => typeof field === "string").map((field) => field.trim()).filter(Boolean);
|
|
11805
|
+
return normalized.length > 0 ? normalized : void 0;
|
|
11806
|
+
}
|
|
11807
|
+
function normalizeAgentHints(value) {
|
|
11808
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
11809
|
+
return void 0;
|
|
11810
|
+
}
|
|
11811
|
+
const normalized = Object.fromEntries(
|
|
11812
|
+
Object.entries(value).map(([key, hint]) => [key.trim(), normalizeOptionalString(hint)]).filter((entry) => Boolean(entry[0] && entry[1]))
|
|
11813
|
+
);
|
|
11814
|
+
return Object.keys(normalized).length > 0 ? normalized : void 0;
|
|
11815
|
+
}
|
|
11816
|
+
function normalizeBookmarkMetadata(input) {
|
|
11817
|
+
return {
|
|
11818
|
+
intent: normalizeOptionalString(input.intent),
|
|
11819
|
+
expectedContent: normalizeOptionalString(input.expectedContent),
|
|
11820
|
+
keyFields: normalizeKeyFields(input.keyFields),
|
|
11821
|
+
agentHints: normalizeAgentHints(input.agentHints)
|
|
11822
|
+
};
|
|
11823
|
+
}
|
|
11637
11824
|
const HUGGING_FACE_HUB_HOSTS = /* @__PURE__ */ new Set(["huggingface.co", "www.huggingface.co"]);
|
|
11638
11825
|
const HUGGING_FACE_MODEL_TASKS = [
|
|
11639
11826
|
{
|
|
@@ -11894,6 +12081,14 @@ function buildHuggingFaceSearchShortcut(currentUrl, rawQuery) {
|
|
|
11894
12081
|
appliedFilters
|
|
11895
12082
|
};
|
|
11896
12083
|
}
|
|
12084
|
+
function getBookmarkMetadataFromArgs(args) {
|
|
12085
|
+
return normalizeBookmarkMetadata({
|
|
12086
|
+
intent: args.intent,
|
|
12087
|
+
expectedContent: args.expectedContent,
|
|
12088
|
+
keyFields: args.keyFields,
|
|
12089
|
+
agentHints: args.agentHints
|
|
12090
|
+
});
|
|
12091
|
+
}
|
|
11897
12092
|
const DEFAULT_PAGE_SCRIPT_TIMEOUT_MS = 1500;
|
|
11898
12093
|
const PAGE_SCRIPT_TIMEOUT = /* @__PURE__ */ Symbol("page-script-timeout");
|
|
11899
12094
|
async function loadPermittedUrl$1(wc, url) {
|
|
@@ -15558,7 +15753,10 @@ ${truncated}`;
|
|
|
15558
15753
|
source.title,
|
|
15559
15754
|
target.folderId,
|
|
15560
15755
|
note,
|
|
15561
|
-
{
|
|
15756
|
+
{
|
|
15757
|
+
onDuplicate,
|
|
15758
|
+
extra: getBookmarkMetadataFromArgs(args)
|
|
15759
|
+
}
|
|
15562
15760
|
);
|
|
15563
15761
|
if (result2.status === "conflict" && result2.existing) {
|
|
15564
15762
|
return composeFolderAwareResponse$1(
|
|
@@ -15597,7 +15795,8 @@ ${truncated}`;
|
|
|
15597
15795
|
const updated = updateBookmark(existing.id, {
|
|
15598
15796
|
folderId: target.folderId,
|
|
15599
15797
|
title: typeof args.title === "string" && args.title.trim() ? args.title.trim() : void 0,
|
|
15600
|
-
note
|
|
15798
|
+
note,
|
|
15799
|
+
...getBookmarkMetadataFromArgs(args)
|
|
15601
15800
|
});
|
|
15602
15801
|
if (!updated) {
|
|
15603
15802
|
return `Bookmark ${existing.id} not found`;
|
|
@@ -15608,12 +15807,18 @@ ${truncated}`;
|
|
|
15608
15807
|
);
|
|
15609
15808
|
}
|
|
15610
15809
|
if ("error" in source) return `Error: ${source.error}`;
|
|
15611
|
-
const
|
|
15810
|
+
const result2 = saveBookmarkWithPolicy(
|
|
15612
15811
|
source.url,
|
|
15613
15812
|
source.title,
|
|
15614
15813
|
target.folderId,
|
|
15615
|
-
note
|
|
15814
|
+
note,
|
|
15815
|
+
{
|
|
15816
|
+
onDuplicate: "update",
|
|
15817
|
+
extra: getBookmarkMetadataFromArgs(args)
|
|
15818
|
+
}
|
|
15616
15819
|
);
|
|
15820
|
+
const bookmark = result2.bookmark;
|
|
15821
|
+
if (!bookmark) return "Error: Bookmark save failed";
|
|
15617
15822
|
return composeFolderAwareResponse$1(
|
|
15618
15823
|
`Saved and organized "${bookmark.title}" (${bookmark.url}) into "${describeFolder$1(bookmark.folderId)}" (id=${bookmark.id})`,
|
|
15619
15824
|
target.createdFolder
|
|
@@ -17310,6 +17515,14 @@ function readAuditLog(limit = 100) {
|
|
|
17310
17515
|
}
|
|
17311
17516
|
let httpServer = null;
|
|
17312
17517
|
let mcpAuthToken = null;
|
|
17518
|
+
function getBookmarkMetadataFromToolArgs(args) {
|
|
17519
|
+
return normalizeBookmarkMetadata({
|
|
17520
|
+
intent: args.intent,
|
|
17521
|
+
expectedContent: args.expected_content,
|
|
17522
|
+
keyFields: args.key_fields,
|
|
17523
|
+
agentHints: args.agent_hints
|
|
17524
|
+
});
|
|
17525
|
+
}
|
|
17313
17526
|
const MCP_AUTH_FILENAME = "mcp-auth.json";
|
|
17314
17527
|
function getMcpAuthFilePath() {
|
|
17315
17528
|
const configDir = process.env.VESSEL_CONFIG_DIR || path$1.join(
|
|
@@ -20137,7 +20350,15 @@ ${JSON.stringify(otherHighlights, null, 2)}`
|
|
|
20137
20350
|
note: zod.z.string().optional().describe("Optional note about why this was bookmarked"),
|
|
20138
20351
|
on_duplicate: zod.z.enum(["ask", "update", "duplicate"]).optional().describe(
|
|
20139
20352
|
'How to handle an existing bookmark with the same URL in the same folder: "ask" (default), "update", or "duplicate"'
|
|
20140
|
-
)
|
|
20353
|
+
),
|
|
20354
|
+
intent: zod.z.string().optional().describe(
|
|
20355
|
+
"Human-readable description of what this bookmark is for"
|
|
20356
|
+
),
|
|
20357
|
+
expected_content: zod.z.string().optional().describe(
|
|
20358
|
+
"Brief description of the content the agent should expect to find here"
|
|
20359
|
+
),
|
|
20360
|
+
key_fields: zod.z.array(zod.z.string()).optional().describe("Important form field names for this page"),
|
|
20361
|
+
agent_hints: zod.z.record(zod.z.string(), zod.z.string()).optional().describe("Arbitrary key-value hints for the agent")
|
|
20141
20362
|
}
|
|
20142
20363
|
},
|
|
20143
20364
|
async ({
|
|
@@ -20150,7 +20371,11 @@ ${JSON.stringify(otherHighlights, null, 2)}`
|
|
|
20150
20371
|
folder_summary,
|
|
20151
20372
|
create_folder_if_missing,
|
|
20152
20373
|
note,
|
|
20153
|
-
on_duplicate
|
|
20374
|
+
on_duplicate,
|
|
20375
|
+
intent,
|
|
20376
|
+
expected_content,
|
|
20377
|
+
key_fields,
|
|
20378
|
+
agent_hints
|
|
20154
20379
|
}) => {
|
|
20155
20380
|
return withAction(
|
|
20156
20381
|
runtime2,
|
|
@@ -20165,7 +20390,11 @@ ${JSON.stringify(otherHighlights, null, 2)}`
|
|
|
20165
20390
|
folder_name,
|
|
20166
20391
|
folder_summary,
|
|
20167
20392
|
create_folder_if_missing,
|
|
20168
|
-
note
|
|
20393
|
+
note,
|
|
20394
|
+
intent,
|
|
20395
|
+
expected_content,
|
|
20396
|
+
key_fields,
|
|
20397
|
+
agent_hints
|
|
20169
20398
|
},
|
|
20170
20399
|
async () => {
|
|
20171
20400
|
const currentTab = tabManager.getActiveTab();
|
|
@@ -20195,7 +20424,15 @@ ${JSON.stringify(otherHighlights, null, 2)}`
|
|
|
20195
20424
|
source.title,
|
|
20196
20425
|
target.folderId,
|
|
20197
20426
|
note,
|
|
20198
|
-
{
|
|
20427
|
+
{
|
|
20428
|
+
onDuplicate: on_duplicate ?? "ask",
|
|
20429
|
+
extra: getBookmarkMetadataFromToolArgs({
|
|
20430
|
+
intent,
|
|
20431
|
+
expected_content,
|
|
20432
|
+
key_fields,
|
|
20433
|
+
agent_hints
|
|
20434
|
+
})
|
|
20435
|
+
}
|
|
20199
20436
|
);
|
|
20200
20437
|
if (result.status === "conflict" && result.existing) {
|
|
20201
20438
|
return composeFolderAwareResponse(
|
|
@@ -20292,7 +20529,11 @@ ${JSON.stringify(otherHighlights, null, 2)}`
|
|
|
20292
20529
|
folder_summary: zod.z.string().optional().describe("Optional summary used if a new folder is created"),
|
|
20293
20530
|
create_folder_if_missing: zod.z.boolean().optional().describe("Create folder_name automatically when it does not exist"),
|
|
20294
20531
|
note: zod.z.string().optional().describe("Optional note to attach or update on the bookmark"),
|
|
20295
|
-
archive: zod.z.boolean().optional().describe('If true, organize into the default "Archive" folder')
|
|
20532
|
+
archive: zod.z.boolean().optional().describe('If true, organize into the default "Archive" folder'),
|
|
20533
|
+
intent: zod.z.string().optional().describe("Human-readable description of what this bookmark is for"),
|
|
20534
|
+
expected_content: zod.z.string().optional().describe("Brief description of content the agent should expect"),
|
|
20535
|
+
key_fields: zod.z.array(zod.z.string()).optional().describe("Important form field names for this page"),
|
|
20536
|
+
agent_hints: zod.z.record(zod.z.string(), zod.z.string()).optional().describe("Arbitrary key-value hints for the agent")
|
|
20296
20537
|
}
|
|
20297
20538
|
},
|
|
20298
20539
|
async (args) => {
|
|
@@ -20328,7 +20569,8 @@ ${JSON.stringify(otherHighlights, null, 2)}`
|
|
|
20328
20569
|
const updated = updateBookmark(existing.id, {
|
|
20329
20570
|
folderId: target.folderId,
|
|
20330
20571
|
title: typeof args.title === "string" && args.title.trim() ? args.title.trim() : void 0,
|
|
20331
|
-
note
|
|
20572
|
+
note,
|
|
20573
|
+
...getBookmarkMetadataFromToolArgs(args)
|
|
20332
20574
|
});
|
|
20333
20575
|
if (!updated) {
|
|
20334
20576
|
return `Bookmark ${existing.id} not found`;
|
|
@@ -20339,12 +20581,18 @@ ${JSON.stringify(otherHighlights, null, 2)}`
|
|
|
20339
20581
|
);
|
|
20340
20582
|
}
|
|
20341
20583
|
if ("error" in source) return `Error: ${source.error}`;
|
|
20342
|
-
const
|
|
20584
|
+
const result = saveBookmarkWithPolicy(
|
|
20343
20585
|
source.url,
|
|
20344
20586
|
source.title,
|
|
20345
20587
|
target.folderId,
|
|
20346
|
-
note
|
|
20588
|
+
note,
|
|
20589
|
+
{
|
|
20590
|
+
onDuplicate: "update",
|
|
20591
|
+
extra: getBookmarkMetadataFromToolArgs(args)
|
|
20592
|
+
}
|
|
20347
20593
|
);
|
|
20594
|
+
const bookmark = result.bookmark;
|
|
20595
|
+
if (!bookmark) return "Error: Bookmark save failed";
|
|
20348
20596
|
return composeFolderAwareResponse(
|
|
20349
20597
|
`Saved and organized "${bookmark.title}" (${bookmark.url}) into "${describeFolder(bookmark.folderId)}" (id=${bookmark.id})`,
|
|
20350
20598
|
target.createdFolder
|
|
@@ -22798,7 +23046,7 @@ function registerWindowControlHandlers(mainWindow) {
|
|
|
22798
23046
|
});
|
|
22799
23047
|
}
|
|
22800
23048
|
let activeChatProvider = null;
|
|
22801
|
-
const VALID_APPROVAL_MODES =
|
|
23049
|
+
const VALID_APPROVAL_MODES = ["auto", "confirm-dangerous", "manual"];
|
|
22802
23050
|
function registerIpcHandlers(windowState, runtime2) {
|
|
22803
23051
|
const { tabManager, chromeView, sidebarView, devtoolsPanelView, mainWindow } = windowState;
|
|
22804
23052
|
let sidebarResizeRecoveryTimer = null;
|
|
@@ -22807,10 +23055,9 @@ function registerIpcHandlers(windowState, runtime2) {
|
|
|
22807
23055
|
let pendingRuntimeState = null;
|
|
22808
23056
|
const premiumApiOrigin = process.env.VESSEL_PREMIUM_API ? new URL(process.env.VESSEL_PREMIUM_API).origin : "https://vesselpremium.quantaintellect.com";
|
|
22809
23057
|
const clearSidebarResizeRecoveryTimer = () => {
|
|
22810
|
-
if (sidebarResizeRecoveryTimer)
|
|
22811
|
-
|
|
22812
|
-
|
|
22813
|
-
}
|
|
23058
|
+
if (!sidebarResizeRecoveryTimer) return;
|
|
23059
|
+
clearTimeout(sidebarResizeRecoveryTimer);
|
|
23060
|
+
sidebarResizeRecoveryTimer = null;
|
|
22814
23061
|
};
|
|
22815
23062
|
const restoreSidebarLayoutAfterResize = () => {
|
|
22816
23063
|
clearSidebarResizeRecoveryTimer();
|
|
@@ -23085,7 +23332,15 @@ function registerIpcHandlers(windowState, runtime2) {
|
|
|
23085
23332
|
sidebarResizeActive = true;
|
|
23086
23333
|
clearSidebarResizeRecoveryTimer();
|
|
23087
23334
|
const [width, height] = windowState.mainWindow.getContentSize();
|
|
23088
|
-
windowState.
|
|
23335
|
+
const chromeHeight = windowState.uiState.focusMode ? 0 : 110;
|
|
23336
|
+
const sidebarWidth = windowState.uiState.sidebarWidth;
|
|
23337
|
+
const resizeHandleOverlap = 6;
|
|
23338
|
+
windowState.sidebarView.setBounds({
|
|
23339
|
+
x: width - sidebarWidth - resizeHandleOverlap,
|
|
23340
|
+
y: chromeHeight,
|
|
23341
|
+
width: sidebarWidth + resizeHandleOverlap,
|
|
23342
|
+
height: height - chromeHeight
|
|
23343
|
+
});
|
|
23089
23344
|
scheduleSidebarResizeRecovery();
|
|
23090
23345
|
});
|
|
23091
23346
|
electron.ipcMain.handle(Channels.SIDEBAR_RESIZE, (_, width) => {
|
|
@@ -23093,7 +23348,6 @@ function registerIpcHandlers(windowState, runtime2) {
|
|
|
23093
23348
|
const clamped = Math.max(240, Math.min(800, Math.round(width)));
|
|
23094
23349
|
windowState.uiState.sidebarWidth = clamped;
|
|
23095
23350
|
resizeSidebarViews(windowState);
|
|
23096
|
-
scheduleSidebarResizeRecovery();
|
|
23097
23351
|
return clamped;
|
|
23098
23352
|
});
|
|
23099
23353
|
electron.ipcMain.handle(Channels.SIDEBAR_RESIZE_COMMIT, () => {
|
|
@@ -23152,7 +23406,7 @@ function registerIpcHandlers(windowState, runtime2) {
|
|
|
23152
23406
|
Channels.AGENT_SET_APPROVAL_MODE,
|
|
23153
23407
|
(_, mode) => {
|
|
23154
23408
|
assertString(mode, "mode");
|
|
23155
|
-
if (!VALID_APPROVAL_MODES.
|
|
23409
|
+
if (!VALID_APPROVAL_MODES.includes(mode)) {
|
|
23156
23410
|
throw new Error(`Invalid approval mode: ${mode}`);
|
|
23157
23411
|
}
|
|
23158
23412
|
trackApprovalModeChanged(mode);
|
|
@@ -23192,9 +23446,23 @@ function registerIpcHandlers(windowState, runtime2) {
|
|
|
23192
23446
|
);
|
|
23193
23447
|
electron.ipcMain.handle(
|
|
23194
23448
|
Channels.BOOKMARK_SAVE,
|
|
23195
|
-
(_, url, title, folderId, note) => {
|
|
23449
|
+
(_, url, title, folderId, note, intent, expectedContent, keyFields, agentHints) => {
|
|
23196
23450
|
trackBookmarkAction("save");
|
|
23197
|
-
|
|
23451
|
+
const result = saveBookmarkWithPolicy(url, title, folderId, note, {
|
|
23452
|
+
onDuplicate: "update",
|
|
23453
|
+
extra: {
|
|
23454
|
+
...normalizeBookmarkMetadata({
|
|
23455
|
+
intent,
|
|
23456
|
+
expectedContent,
|
|
23457
|
+
keyFields,
|
|
23458
|
+
agentHints
|
|
23459
|
+
})
|
|
23460
|
+
}
|
|
23461
|
+
});
|
|
23462
|
+
if (!result.bookmark) {
|
|
23463
|
+
throw new Error("Bookmark save failed");
|
|
23464
|
+
}
|
|
23465
|
+
return result.bookmark;
|
|
23198
23466
|
}
|
|
23199
23467
|
);
|
|
23200
23468
|
electron.ipcMain.handle(Channels.BOOKMARK_REMOVE, (_, id) => {
|
|
@@ -23308,6 +23576,7 @@ function registerIpcHandlers(windowState, runtime2) {
|
|
|
23308
23576
|
}
|
|
23309
23577
|
}
|
|
23310
23578
|
findWiredWcId = wc.id;
|
|
23579
|
+
if (wc.isDestroyed()) return;
|
|
23311
23580
|
const listener = (_event, result) => {
|
|
23312
23581
|
if (!chromeView.webContents.isDestroyed()) {
|
|
23313
23582
|
chromeView.webContents.send(Channels.FIND_IN_PAGE_RESULT, result);
|
|
@@ -23315,8 +23584,9 @@ function registerIpcHandlers(windowState, runtime2) {
|
|
|
23315
23584
|
};
|
|
23316
23585
|
findResultListener = listener;
|
|
23317
23586
|
wc.on("found-in-page", listener);
|
|
23587
|
+
const capturedWcId = wc.id;
|
|
23318
23588
|
wc.once("destroyed", () => {
|
|
23319
|
-
if (findWiredWcId ===
|
|
23589
|
+
if (findWiredWcId === capturedWcId) {
|
|
23320
23590
|
findWiredWcId = null;
|
|
23321
23591
|
findResultListener = null;
|
|
23322
23592
|
}
|
|
@@ -23424,9 +23694,20 @@ function registerIpcHandlers(windowState, runtime2) {
|
|
|
23424
23694
|
sendToRendererViews(Channels.PREMIUM_UPDATE, state2);
|
|
23425
23695
|
return state2;
|
|
23426
23696
|
});
|
|
23697
|
+
const PREMIUM_TRACKABLE_STEPS = [
|
|
23698
|
+
"chat_banner_viewed",
|
|
23699
|
+
"chat_banner_clicked",
|
|
23700
|
+
"settings_banner_viewed",
|
|
23701
|
+
"settings_banner_clicked",
|
|
23702
|
+
"welcome_banner_clicked",
|
|
23703
|
+
"premium_gate_seen",
|
|
23704
|
+
"premium_gate_clicked",
|
|
23705
|
+
"iteration_limit_seen",
|
|
23706
|
+
"iteration_limit_clicked"
|
|
23707
|
+
];
|
|
23427
23708
|
electron.ipcMain.handle(Channels.PREMIUM_TRACK_CONTEXT, (_, step) => {
|
|
23428
23709
|
assertString(step, "step");
|
|
23429
|
-
if (step
|
|
23710
|
+
if (PREMIUM_TRACKABLE_STEPS.includes(step)) {
|
|
23430
23711
|
trackPremiumFunnel(step);
|
|
23431
23712
|
}
|
|
23432
23713
|
});
|