@quanta-intellect/vessel-browser 0.1.141 → 0.1.143
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/out/main/index.js
CHANGED
|
@@ -2221,6 +2221,19 @@ async function scrollToHighlight(wc, index) {
|
|
|
2221
2221
|
})()
|
|
2222
2222
|
`);
|
|
2223
2223
|
}
|
|
2224
|
+
async function getHighlightTextAtIndex(wc, index) {
|
|
2225
|
+
const safeIndex = Math.floor(Number(index));
|
|
2226
|
+
return wc.executeJavaScript(`
|
|
2227
|
+
(function() {
|
|
2228
|
+
var highlights = document.querySelectorAll(${HIGHLIGHT_SELECTOR});
|
|
2229
|
+
if (${safeIndex} < 0 || ${safeIndex} >= highlights.length) return null;
|
|
2230
|
+
var el = highlights[${safeIndex}];
|
|
2231
|
+
var text = el.getAttribute && el.getAttribute('data-vessel-highlight-text');
|
|
2232
|
+
if (!text && el.textContent) text = el.textContent;
|
|
2233
|
+
return text ? text.trim() : null;
|
|
2234
|
+
})()
|
|
2235
|
+
`);
|
|
2236
|
+
}
|
|
2224
2237
|
async function removeHighlightAtIndex(wc, index) {
|
|
2225
2238
|
const safeIndex = Math.floor(Number(index));
|
|
2226
2239
|
return wc.executeJavaScript(`
|
|
@@ -8751,7 +8764,24 @@ function recoverNarratedActionToolCalls(text, availableToolNames) {
|
|
|
8751
8764
|
}
|
|
8752
8765
|
return recovered;
|
|
8753
8766
|
}
|
|
8754
|
-
|
|
8767
|
+
function shouldRetryUnexecutedHighlightCompletion(userMessage, assistantText, successfulToolNames) {
|
|
8768
|
+
const userAskedForHighlights = /\b(?:highlight|highlights|mark|annotate)\b/i.test(
|
|
8769
|
+
userMessage
|
|
8770
|
+
);
|
|
8771
|
+
if (!userAskedForHighlights || successfulToolNames.includes("highlight")) {
|
|
8772
|
+
return false;
|
|
8773
|
+
}
|
|
8774
|
+
const normalizedAssistant = assistantText.toLowerCase();
|
|
8775
|
+
return /\b(?:highlighted|marked|annotated)\b/.test(normalizedAssistant) || /\b(?:green|yellow|red|blue|purple|orange)\s+highlights?\b/.test(
|
|
8776
|
+
normalizedAssistant
|
|
8777
|
+
) || /\bhighlights?\s+(?:added|shown|applied|visible|on the page)\b/.test(
|
|
8778
|
+
normalizedAssistant
|
|
8779
|
+
);
|
|
8780
|
+
}
|
|
8781
|
+
function buildHighlightToolCompletionPrompt() {
|
|
8782
|
+
return `The user asked you to highlight items on the page, but no highlight tool call succeeded. Do not claim visual highlights are present until you call the supported highlight tool. Use read_page only if you need current page text, then call highlight with {"text":"exact visible title or passage"} for each item you want to mark. Use an element index only when the latest read_page result gives the exact current index for that same item.`;
|
|
8783
|
+
}
|
|
8784
|
+
const DOLLAR_PRICE_RE = /\$\s?(?:\d{2,4}|\d{1,3}(?:,\d{3})+)(?:\.\d{2})?\b/;
|
|
8755
8785
|
const FLIGHT_TASK_RE = /\b(?:flight|flights|airfare|air fare|plane ticket|airline|airport|google flights|pdx|sfo|san francisco|portland)\b/i;
|
|
8756
8786
|
const SHOPPING_INTENT_RE = /\b(?:cheap|cheapest|price|prices|fare|fares|one[- ]?way|round[- ]?trip|depart|departure|arrive|arrival|from|to)\b/i;
|
|
8757
8787
|
const FLIGHT_CLAIM_CONTEXT_RE = /\b(?:flight|flights|airline|airlines|departure|arrival|depart|arrive|nonstop|non-stop|stops?|duration|alaska|united|delta|american|southwest|frontier|spirit|jetblue|hawaiian)\b/i;
|
|
@@ -8837,6 +8867,22 @@ function toOpenAIReasoningEffort(effort, providerId, model) {
|
|
|
8837
8867
|
return void 0;
|
|
8838
8868
|
}
|
|
8839
8869
|
}
|
|
8870
|
+
function openRouterRoutingOptions(providerId) {
|
|
8871
|
+
if (providerId !== "openrouter") return {};
|
|
8872
|
+
return {
|
|
8873
|
+
provider: {
|
|
8874
|
+
require_parameters: true,
|
|
8875
|
+
sort: "latency"
|
|
8876
|
+
}
|
|
8877
|
+
};
|
|
8878
|
+
}
|
|
8879
|
+
function buildOpenRouterAttributionHeaders() {
|
|
8880
|
+
return {
|
|
8881
|
+
"HTTP-Referer": "https://github.com/unmodeled-tyler/vessel-browser",
|
|
8882
|
+
"X-OpenRouter-Title": "Vessel Browser",
|
|
8883
|
+
"X-OpenRouter-Categories": "personal-agent,general-chat"
|
|
8884
|
+
};
|
|
8885
|
+
}
|
|
8840
8886
|
function followUpReminderForProfile(profile, userMessage, assistantText, latestToolResultPreview) {
|
|
8841
8887
|
if (profile !== "compact") return null;
|
|
8842
8888
|
const phaseReminder = buildPhaseReminder(userMessage, assistantText || "");
|
|
@@ -8978,6 +9024,37 @@ function buildLatestStateReminder(toolResultPreview) {
|
|
|
8978
9024
|
}
|
|
8979
9025
|
return "";
|
|
8980
9026
|
}
|
|
9027
|
+
function normalizedSearchToolQuery$1(name, args) {
|
|
9028
|
+
if (name !== "search" && name !== "web_search") return null;
|
|
9029
|
+
const raw = typeof args.query === "string" ? args.query : typeof args.text === "string" ? args.text : typeof args.term === "string" ? args.term : "";
|
|
9030
|
+
const normalized = raw.replace(/\s+/g, " ").trim().toLowerCase();
|
|
9031
|
+
return normalized || null;
|
|
9032
|
+
}
|
|
9033
|
+
function isOpenAIRealProgressToolForSearch(name) {
|
|
9034
|
+
return ![
|
|
9035
|
+
"read_page",
|
|
9036
|
+
"current_tab",
|
|
9037
|
+
"list_tabs",
|
|
9038
|
+
"screenshot",
|
|
9039
|
+
"clear_overlays",
|
|
9040
|
+
"accept_cookies",
|
|
9041
|
+
"dismiss_popup",
|
|
9042
|
+
"web_search",
|
|
9043
|
+
"search"
|
|
9044
|
+
].includes(name);
|
|
9045
|
+
}
|
|
9046
|
+
function buildOpenAIRepeatedSearchError(previousTool, previousQuery, latestToolResultPreview, mode) {
|
|
9047
|
+
const stateReminder = buildLatestStateReminder(latestToolResultPreview || "");
|
|
9048
|
+
const lines = [
|
|
9049
|
+
mode === "drifted" ? `Error: You already performed ${previousTool} successfully for this task.` : `Error: You already searched for "${previousQuery}" successfully with ${previousTool}.`,
|
|
9050
|
+
mode === "drifted" ? `Do not rewrite or broaden the query with another ${previousTool}; use the current search results instead.` : `Do not search the same query again with ${previousTool} or its search/web_search alias; use the current search results instead.`,
|
|
9051
|
+
`For named venues, businesses, organizations, schools, or local places, prefer opening the official site or clearly direct result from the current results page before answering. Do not switch to a site: restricted web_search when an official or direct result is already available. Next action: click a result, inspect a specific result, or answer from the result you already opened. Do not call any search tool again as preparation.`
|
|
9052
|
+
];
|
|
9053
|
+
if (stateReminder) {
|
|
9054
|
+
lines.push(stateReminder);
|
|
9055
|
+
}
|
|
9056
|
+
return lines.join(" ");
|
|
9057
|
+
}
|
|
8981
9058
|
function shouldRecoverCompactStall(text, userMessage) {
|
|
8982
9059
|
const trimmed = text.trim().toLowerCase();
|
|
8983
9060
|
if (!trimmed) return true;
|
|
@@ -9061,6 +9138,11 @@ function logAgentLoopDebug(payload) {
|
|
|
9061
9138
|
}
|
|
9062
9139
|
}
|
|
9063
9140
|
function formatOpenAICompatErrorMessage(providerId, message) {
|
|
9141
|
+
if (providerId === "openrouter" && /(timed out after \d+(?:\.\d+)? seconds|request timed out|returned none after all retries|no content|empty response)/i.test(
|
|
9142
|
+
message
|
|
9143
|
+
)) {
|
|
9144
|
+
return `${message} OpenRouter reported an upstream model timeout/no-content failure. If this persists, retry or pin a specific low-latency tool-calling model instead of the free router.`;
|
|
9145
|
+
}
|
|
9064
9146
|
if (providerId === "llama_cpp" && /(available context size|context size exceeded|exceeds the available context size|try increasing it)/i.test(
|
|
9065
9147
|
message
|
|
9066
9148
|
)) {
|
|
@@ -9083,10 +9165,7 @@ class OpenAICompatProvider {
|
|
|
9083
9165
|
apiKey: config.apiKey || "ollama",
|
|
9084
9166
|
baseURL,
|
|
9085
9167
|
...isOpenRouter && {
|
|
9086
|
-
defaultHeaders:
|
|
9087
|
-
"HTTP-Referer": "https://github.com/unmodeled/vessel-browser",
|
|
9088
|
-
"X-Title": "Vessel"
|
|
9089
|
-
}
|
|
9168
|
+
defaultHeaders: buildOpenRouterAttributionHeaders()
|
|
9090
9169
|
}
|
|
9091
9170
|
});
|
|
9092
9171
|
this.providerId = config.id;
|
|
@@ -9113,6 +9192,7 @@ class OpenAICompatProvider {
|
|
|
9113
9192
|
max_tokens: 4096,
|
|
9114
9193
|
stream: true,
|
|
9115
9194
|
messages,
|
|
9195
|
+
...openRouterRoutingOptions(this.providerId),
|
|
9116
9196
|
...openAIPromptCacheOptions({
|
|
9117
9197
|
providerId: this.providerId,
|
|
9118
9198
|
model: this.model,
|
|
@@ -9171,9 +9251,14 @@ class OpenAICompatProvider {
|
|
|
9171
9251
|
let iterationsUsed = 0;
|
|
9172
9252
|
let compactRecoveryCount = 0;
|
|
9173
9253
|
let flightPriceEvidenceRecoveryCount = 0;
|
|
9254
|
+
let highlightCompletionRecoveryCount = 0;
|
|
9174
9255
|
let compactCorrectionCount = 0;
|
|
9175
9256
|
const recentCompactToolSignatures = [];
|
|
9176
9257
|
const recentToolNames = [];
|
|
9258
|
+
const successfulToolNames = [];
|
|
9259
|
+
const recentSuccessfulSearchQueries = [];
|
|
9260
|
+
const recentSuccessfulSearchToolByQuery = /* @__PURE__ */ new Map();
|
|
9261
|
+
let lastSuccessfulWebSearchQuery = null;
|
|
9177
9262
|
let clickReadLoopNudged = false;
|
|
9178
9263
|
for (let i = 0; i < maxIterations; i++) {
|
|
9179
9264
|
iterationsUsed = i + 1;
|
|
@@ -9195,6 +9280,7 @@ class OpenAICompatProvider {
|
|
|
9195
9280
|
tools: openAITools,
|
|
9196
9281
|
tool_choice: "auto",
|
|
9197
9282
|
temperature: agentTemperatureForProfile(this.agentToolProfile),
|
|
9283
|
+
...openRouterRoutingOptions(this.providerId),
|
|
9198
9284
|
...openAIPromptCacheOptions({
|
|
9199
9285
|
providerId: this.providerId,
|
|
9200
9286
|
model: this.model,
|
|
@@ -9342,6 +9428,19 @@ class OpenAICompatProvider {
|
|
|
9342
9428
|
});
|
|
9343
9429
|
continue;
|
|
9344
9430
|
}
|
|
9431
|
+
if (highlightCompletionRecoveryCount < 1 && shouldRetryUnexecutedHighlightCompletion(
|
|
9432
|
+
userMessage,
|
|
9433
|
+
textAccum,
|
|
9434
|
+
successfulToolNames
|
|
9435
|
+
)) {
|
|
9436
|
+
highlightCompletionRecoveryCount += 1;
|
|
9437
|
+
if (textAccum.trim()) onChunk("<<erase_prev>>");
|
|
9438
|
+
messages.push({
|
|
9439
|
+
role: "user",
|
|
9440
|
+
content: `[System] ${buildHighlightToolCompletionPrompt()}`
|
|
9441
|
+
});
|
|
9442
|
+
continue;
|
|
9443
|
+
}
|
|
9345
9444
|
break;
|
|
9346
9445
|
}
|
|
9347
9446
|
compactRecoveryCount = 0;
|
|
@@ -9394,6 +9493,29 @@ class OpenAICompatProvider {
|
|
|
9394
9493
|
args = repairedArgs.args;
|
|
9395
9494
|
args = coerceToolArgsForExecution(tc.name, args);
|
|
9396
9495
|
const toolSignature = stableToolSignature(tc.name, args);
|
|
9496
|
+
const searchToolQuery = normalizedSearchToolQuery$1(tc.name, args);
|
|
9497
|
+
const isRepeatedSearchAcrossTools = searchToolQuery !== null && recentSuccessfulSearchQueries.includes(searchToolQuery);
|
|
9498
|
+
const isQueryDriftedWebSearch = tc.name === "web_search" && lastSuccessfulWebSearchQuery !== null && searchToolQuery !== null && searchToolQuery !== lastSuccessfulWebSearchQuery;
|
|
9499
|
+
if (isRepeatedSearchAcrossTools || isQueryDriftedWebSearch) {
|
|
9500
|
+
onChunk(`
|
|
9501
|
+
<<tool:${tc.name}:↻ duplicate suppressed>>
|
|
9502
|
+
`);
|
|
9503
|
+
const previousTool = isRepeatedSearchAcrossTools ? recentSuccessfulSearchToolByQuery.get(searchToolQuery ?? "") ?? (tc.name === "web_search" ? "search" : "web_search") : "web_search";
|
|
9504
|
+
const previousQuery = isRepeatedSearchAcrossTools ? searchToolQuery ?? "" : lastSuccessfulWebSearchQuery ?? "";
|
|
9505
|
+
const mode = isRepeatedSearchAcrossTools ? "repeated" : "drifted";
|
|
9506
|
+
messages.push({
|
|
9507
|
+
role: "tool",
|
|
9508
|
+
tool_call_id: tc.id,
|
|
9509
|
+
content: buildOpenAIRepeatedSearchError(
|
|
9510
|
+
previousTool,
|
|
9511
|
+
previousQuery,
|
|
9512
|
+
latestToolMessage ? String(latestToolMessage.content || "") : null,
|
|
9513
|
+
mode
|
|
9514
|
+
)
|
|
9515
|
+
});
|
|
9516
|
+
compactCorrectionCount += 1;
|
|
9517
|
+
continue;
|
|
9518
|
+
}
|
|
9397
9519
|
if (this.agentToolProfile === "compact" && tc.name === "click" && isTargetlessClickArgs(args)) {
|
|
9398
9520
|
onChunk(`
|
|
9399
9521
|
<<tool:${tc.name}:⚠ missing target>>
|
|
@@ -9468,6 +9590,25 @@ class OpenAICompatProvider {
|
|
|
9468
9590
|
recentCompactToolSignatures.shift();
|
|
9469
9591
|
}
|
|
9470
9592
|
}
|
|
9593
|
+
if (!/^Error:/i.test(toolContent.trim())) {
|
|
9594
|
+
successfulToolNames.push(tc.name);
|
|
9595
|
+
if (isOpenAIRealProgressToolForSearch(tc.name)) {
|
|
9596
|
+
lastSuccessfulWebSearchQuery = null;
|
|
9597
|
+
}
|
|
9598
|
+
if (searchToolQuery && !recentSuccessfulSearchQueries.includes(searchToolQuery)) {
|
|
9599
|
+
recentSuccessfulSearchQueries.push(searchToolQuery);
|
|
9600
|
+
recentSuccessfulSearchToolByQuery.set(searchToolQuery, tc.name);
|
|
9601
|
+
if (recentSuccessfulSearchQueries.length > 4) {
|
|
9602
|
+
const dropped = recentSuccessfulSearchQueries.shift();
|
|
9603
|
+
if (dropped) {
|
|
9604
|
+
recentSuccessfulSearchToolByQuery.delete(dropped);
|
|
9605
|
+
}
|
|
9606
|
+
}
|
|
9607
|
+
}
|
|
9608
|
+
if (tc.name === "web_search" && searchToolQuery) {
|
|
9609
|
+
lastSuccessfulWebSearchQuery = searchToolQuery;
|
|
9610
|
+
}
|
|
9611
|
+
}
|
|
9471
9612
|
recentToolNames.push(tc.name);
|
|
9472
9613
|
if (recentToolNames.length > 8) recentToolNames.shift();
|
|
9473
9614
|
if (!clickReadLoopNudged && recentToolNames.length >= 6 && isClickReadLoop(recentToolNames)) {
|
|
@@ -11529,13 +11670,15 @@ const TOOL_DEFINITIONS = [
|
|
|
11529
11670
|
{
|
|
11530
11671
|
name: "highlight",
|
|
11531
11672
|
title: "Highlight Element",
|
|
11532
|
-
description: "Visually highlight
|
|
11673
|
+
description: "Visually highlight page content for the user. For named items like story titles, result titles, links, headings, or article passages, prefer text with the exact visible title/text. Use index only when you have a current read_page element index for that exact item. Highlights persist until cleared.",
|
|
11533
11674
|
inputSchema: {
|
|
11534
|
-
index: zod.z.number().optional().describe("Element index from page content to highlight"),
|
|
11535
|
-
selector: zod.z.string().optional().describe("CSS selector of element to highlight"),
|
|
11536
11675
|
text: normalizedOptionalStringSchema().describe(
|
|
11537
|
-
"
|
|
11676
|
+
"Exact visible text/title to find and highlight on the page. Preferred for story titles, result titles, links, headings, and passages."
|
|
11538
11677
|
),
|
|
11678
|
+
index: zod.z.number().optional().describe(
|
|
11679
|
+
"Element index from the latest page content listing. Use only when it identifies the exact item to highlight."
|
|
11680
|
+
),
|
|
11681
|
+
selector: zod.z.string().optional().describe("CSS selector of element to highlight"),
|
|
11539
11682
|
label: zod.z.string().optional().describe("Annotation label to display near the highlight"),
|
|
11540
11683
|
durationMs: zod.z.number().optional().describe(
|
|
11541
11684
|
"Auto-clear after this many milliseconds (omit for permanent)"
|
|
@@ -11647,7 +11790,7 @@ const TOOL_DEFINITIONS = [
|
|
|
11647
11790
|
{
|
|
11648
11791
|
name: "web_search",
|
|
11649
11792
|
title: "Web Search",
|
|
11650
|
-
description: "Search the open web using the configured default search engine. Use this for broad discovery tasks instead of typing into the current page.",
|
|
11793
|
+
description: "Search the open web using the configured default search engine. Use this for broad discovery tasks instead of typing into the current page. For named venues, businesses, organizations, schools, or local places, use web search to find the official/direct result, then click that result; do not use site: queries as a substitute for opening an available official result.",
|
|
11651
11794
|
inputSchema: {
|
|
11652
11795
|
query: zod.z.string().describe("Web search query text")
|
|
11653
11796
|
},
|
|
@@ -12589,6 +12732,37 @@ function purchaseActionPriority(el) {
|
|
|
12589
12732
|
}
|
|
12590
12733
|
return Number.POSITIVE_INFINITY;
|
|
12591
12734
|
}
|
|
12735
|
+
function dateOrShowtimeControlPriority(el) {
|
|
12736
|
+
const haystack = normalizeComparable(
|
|
12737
|
+
[
|
|
12738
|
+
el.text,
|
|
12739
|
+
el.label,
|
|
12740
|
+
el.name,
|
|
12741
|
+
el.placeholder,
|
|
12742
|
+
el.description,
|
|
12743
|
+
el.href,
|
|
12744
|
+
el.role
|
|
12745
|
+
].filter(Boolean).join(" ")
|
|
12746
|
+
);
|
|
12747
|
+
if (!haystack) return Number.POSITIVE_INFINITY;
|
|
12748
|
+
if (/\b(today|tomorrow|mon(?:day)?|tue(?:s|sday)?|wed(?:nesday)?|thu(?:rs|rsday)?|fri(?:day)?|sat(?:urday)?|sun(?:day)?)\b/.test(
|
|
12749
|
+
haystack
|
|
12750
|
+
)) {
|
|
12751
|
+
return 0;
|
|
12752
|
+
}
|
|
12753
|
+
if (/\b(showtimes?|showings?|screenings?|movie times?|date|calendar)\b/.test(
|
|
12754
|
+
haystack
|
|
12755
|
+
)) {
|
|
12756
|
+
return 1;
|
|
12757
|
+
}
|
|
12758
|
+
if (/\b(ticketing|tickets?|formovietickets|seat selection)\b/.test(haystack)) {
|
|
12759
|
+
return 2;
|
|
12760
|
+
}
|
|
12761
|
+
return Number.POSITIVE_INFINITY;
|
|
12762
|
+
}
|
|
12763
|
+
function isDateOrShowtimeControl(el) {
|
|
12764
|
+
return Number.isFinite(dateOrShowtimeControlPriority(el));
|
|
12765
|
+
}
|
|
12592
12766
|
function isPurchaseActionElement(el) {
|
|
12593
12767
|
if (el.type !== "button" && el.type !== "link" && !(el.type === "input" && (el.inputType === "submit" || el.inputType === "button"))) {
|
|
12594
12768
|
return false;
|
|
@@ -12686,6 +12860,10 @@ function formatInteractiveElements(elements) {
|
|
|
12686
12860
|
if (Number.isFinite(purchasePriority)) {
|
|
12687
12861
|
s -= 25 - purchasePriority * 5;
|
|
12688
12862
|
}
|
|
12863
|
+
const datePriority = dateOrShowtimeControlPriority(el);
|
|
12864
|
+
if (Number.isFinite(datePriority)) {
|
|
12865
|
+
s -= 18 - datePriority * 4;
|
|
12866
|
+
}
|
|
12689
12867
|
if (el.visible === false) s += 100;
|
|
12690
12868
|
if (el.inViewport === false) s += 50;
|
|
12691
12869
|
if (el.context === "nav" || el.context === "footer" || el.context === "sidebar")
|
|
@@ -12722,8 +12900,9 @@ function formatInteractiveElements(elements) {
|
|
|
12722
12900
|
if (summary) parts.push(`${summary.label}="${summary.value}"`);
|
|
12723
12901
|
appendFieldAffordances(parts, el);
|
|
12724
12902
|
if (el.options?.length) {
|
|
12903
|
+
const maxOptions = isDateOrShowtimeControl(el) ? 10 : 5;
|
|
12725
12904
|
parts.push(
|
|
12726
|
-
`options=${el.options.slice(0,
|
|
12905
|
+
`options=${el.options.slice(0, maxOptions).map((o) => typeof o === "string" ? o : o.label || o.value).join("|")}`
|
|
12727
12906
|
);
|
|
12728
12907
|
}
|
|
12729
12908
|
} else if (el.type === "textarea") {
|
|
@@ -12785,8 +12964,9 @@ function formatForms(forms) {
|
|
|
12785
12964
|
if (summary) fieldParts.push(`${summary.label}="${summary.value}"`);
|
|
12786
12965
|
appendFieldAffordances(fieldParts, field);
|
|
12787
12966
|
if (field.options?.length) {
|
|
12967
|
+
const maxOptions = isDateOrShowtimeControl(field) ? 10 : 5;
|
|
12788
12968
|
fieldParts.push(
|
|
12789
|
-
`options=${field.options.slice(0,
|
|
12969
|
+
`options=${field.options.slice(0, maxOptions).map((o) => typeof o === "string" ? o : o.label || o.value).join("|")}`
|
|
12790
12970
|
);
|
|
12791
12971
|
}
|
|
12792
12972
|
} else if (field.type === "textarea") {
|
|
@@ -13052,6 +13232,7 @@ function chooseAgentReadMode(page) {
|
|
|
13052
13232
|
}
|
|
13053
13233
|
}
|
|
13054
13234
|
function isSearchOrListingPage(page) {
|
|
13235
|
+
if (isHackerNewsListingPage(page.url)) return true;
|
|
13055
13236
|
const haystack = normalizeComparable(
|
|
13056
13237
|
[
|
|
13057
13238
|
page.url,
|
|
@@ -13064,6 +13245,48 @@ function isSearchOrListingPage(page) {
|
|
|
13064
13245
|
haystack
|
|
13065
13246
|
);
|
|
13066
13247
|
}
|
|
13248
|
+
function isHackerNewsListingPage(url) {
|
|
13249
|
+
try {
|
|
13250
|
+
const parsed = new URL(url);
|
|
13251
|
+
if (parsed.hostname !== "news.ycombinator.com") return false;
|
|
13252
|
+
const pathname = parsed.pathname.replace(/\/+$/, "") || "/";
|
|
13253
|
+
return [
|
|
13254
|
+
"/",
|
|
13255
|
+
"/news",
|
|
13256
|
+
"/newest",
|
|
13257
|
+
"/front",
|
|
13258
|
+
"/ask",
|
|
13259
|
+
"/show",
|
|
13260
|
+
"/jobs",
|
|
13261
|
+
"/best",
|
|
13262
|
+
"/active",
|
|
13263
|
+
"/classic",
|
|
13264
|
+
"/noobstories"
|
|
13265
|
+
].includes(pathname);
|
|
13266
|
+
} catch {
|
|
13267
|
+
return false;
|
|
13268
|
+
}
|
|
13269
|
+
}
|
|
13270
|
+
function isHackerNewsUtilityLink(element) {
|
|
13271
|
+
if (!element.href) return false;
|
|
13272
|
+
let url;
|
|
13273
|
+
try {
|
|
13274
|
+
url = new URL(element.href);
|
|
13275
|
+
} catch {
|
|
13276
|
+
return false;
|
|
13277
|
+
}
|
|
13278
|
+
if (url.hostname !== "news.ycombinator.com") return false;
|
|
13279
|
+
const text = normalizeComparable(element.text || "");
|
|
13280
|
+
const pathname = url.pathname.replace(/\/+$/, "") || "/";
|
|
13281
|
+
if (/^(hide|past|favorite|unfavorite|flag|unflag|discuss|reply|parent|more)$/.test(
|
|
13282
|
+
text
|
|
13283
|
+
)) {
|
|
13284
|
+
return true;
|
|
13285
|
+
}
|
|
13286
|
+
if (/^\d+\s+(?:comments?|points?)$/.test(text)) return true;
|
|
13287
|
+
if (pathname === "/hide" || pathname === "/user") return true;
|
|
13288
|
+
return pathname === "/item" && /^(?:discuss|\d+\s+comments?)$/.test(text);
|
|
13289
|
+
}
|
|
13067
13290
|
function collectJsonLdEntityItems(input, results = []) {
|
|
13068
13291
|
if (!input) return results;
|
|
13069
13292
|
if (Array.isArray(input)) {
|
|
@@ -13103,7 +13326,7 @@ function getResultCandidates(page) {
|
|
|
13103
13326
|
const pageHost = normalizeUrlForMatch(page.url);
|
|
13104
13327
|
const searchOrListingPage = isSearchOrListingPage(page);
|
|
13105
13328
|
const scored = page.interactiveElements.filter(
|
|
13106
|
-
(element) => element.type === "link" && element.text?.trim() && element.href
|
|
13329
|
+
(element) => element.type === "link" && element.text?.trim() && element.href && !isHackerNewsUtilityLink(element)
|
|
13107
13330
|
).map((element) => {
|
|
13108
13331
|
const text = element.text?.trim() || "";
|
|
13109
13332
|
const comparableText = normalizeComparable(text);
|
|
@@ -13563,6 +13786,7 @@ function detectPageType(page) {
|
|
|
13563
13786
|
if (hasResults && hasSearchInput && listingLike) return "SEARCH_RESULTS";
|
|
13564
13787
|
if (hasCart) return "SHOPPING";
|
|
13565
13788
|
if (formCount > 0 && !hasPasswordField) return "FORM";
|
|
13789
|
+
if (isHackerNewsListingPage(page.url)) return "PAGINATED_LIST";
|
|
13566
13790
|
if (hasPagination && listingLike) return "PAGINATED_LIST";
|
|
13567
13791
|
if (hasSearchInput && !listingLike) return "SEARCH_READY";
|
|
13568
13792
|
if (page.content.length > 3e3 && page.interactiveElements.length < 10)
|
|
@@ -15111,7 +15335,7 @@ function vesselIsEditableElement(el) {
|
|
|
15111
15335
|
if (!(el instanceof HTMLElement)) return false;
|
|
15112
15336
|
var role = (el.getAttribute("role") || "").toLowerCase();
|
|
15113
15337
|
return el.isContentEditable ||
|
|
15114
|
-
el.getAttribute("contenteditable")
|
|
15338
|
+
(el.hasAttribute("contenteditable") && el.getAttribute("contenteditable") !== "false") ||
|
|
15115
15339
|
role === "textbox" ||
|
|
15116
15340
|
role === "searchbox";
|
|
15117
15341
|
}
|
|
@@ -15120,7 +15344,7 @@ function vesselResolveFillableControl(el) {
|
|
|
15120
15344
|
if (!el) return null;
|
|
15121
15345
|
if (vesselIsNativeField(el) || vesselIsEditableElement(el)) return el;
|
|
15122
15346
|
if (!(el instanceof Element)) return null;
|
|
15123
|
-
var nested = el.querySelector("input:not([type='hidden']):not([type='submit']):not([type='button']), textarea, select, [contenteditable='
|
|
15347
|
+
var nested = el.querySelector("input:not([type='hidden']):not([type='submit']):not([type='button']), textarea, select, [contenteditable]:not([contenteditable='false']), [role='textbox'], [role='searchbox']");
|
|
15124
15348
|
return nested instanceof HTMLElement ? nested : null;
|
|
15125
15349
|
}
|
|
15126
15350
|
|
|
@@ -15138,7 +15362,7 @@ function vesselFindVisibleFillableControl(original) {
|
|
|
15138
15362
|
|
|
15139
15363
|
var scopes = Array.from(document.querySelectorAll("dialog[open], [role='dialog'], [role='alertdialog'], [aria-modal='true'], [role='listbox'], [role='combobox'][aria-expanded='true']"));
|
|
15140
15364
|
scopes.push(document.body);
|
|
15141
|
-
var selector = "input:not([type='hidden']):not([type='submit']):not([type='button']), textarea, select, [contenteditable='
|
|
15365
|
+
var selector = "input:not([type='hidden']):not([type='submit']):not([type='button']), textarea, select, [contenteditable]:not([contenteditable='false']), [role='textbox'], [role='searchbox']";
|
|
15142
15366
|
for (var i = 0; i < scopes.length; i += 1) {
|
|
15143
15367
|
var scope = scopes[i];
|
|
15144
15368
|
if (!scope || !(scope instanceof Element)) continue;
|
|
@@ -15436,7 +15660,7 @@ async function resolveFieldSelector(wc, field) {
|
|
|
15436
15660
|
if (!(el instanceof HTMLElement)) return false;
|
|
15437
15661
|
var role = (el.getAttribute("role") || "").toLowerCase();
|
|
15438
15662
|
return el.isContentEditable ||
|
|
15439
|
-
el.getAttribute("contenteditable")
|
|
15663
|
+
(el.hasAttribute("contenteditable") && el.getAttribute("contenteditable") !== "false") ||
|
|
15440
15664
|
role === "textbox" ||
|
|
15441
15665
|
role === "searchbox" ||
|
|
15442
15666
|
role === "combobox";
|
|
@@ -15476,7 +15700,7 @@ async function resolveFieldSelector(wc, field) {
|
|
|
15476
15700
|
return score;
|
|
15477
15701
|
}
|
|
15478
15702
|
|
|
15479
|
-
const candidates = Array.from(document.querySelectorAll("input, textarea, select, [contenteditable='
|
|
15703
|
+
const candidates = Array.from(document.querySelectorAll("input, textarea, select, [contenteditable]:not([contenteditable='false']), [role='textbox'], [role='searchbox'], [role='combobox']"));
|
|
15480
15704
|
let best = null;
|
|
15481
15705
|
let bestScore = -1;
|
|
15482
15706
|
for (const el of candidates) {
|
|
@@ -17969,7 +18193,7 @@ async function locateImplicitTextTarget(wc) {
|
|
|
17969
18193
|
const role = normalize(el.getAttribute("role"));
|
|
17970
18194
|
if (
|
|
17971
18195
|
el.isContentEditable ||
|
|
17972
|
-
el.getAttribute("contenteditable")
|
|
18196
|
+
(el.hasAttribute("contenteditable") && el.getAttribute("contenteditable") !== "false") ||
|
|
17973
18197
|
role === "textbox" ||
|
|
17974
18198
|
role === "searchbox" ||
|
|
17975
18199
|
role === "combobox"
|
|
@@ -17993,7 +18217,7 @@ async function locateImplicitTextTarget(wc) {
|
|
|
17993
18217
|
}
|
|
17994
18218
|
|
|
17995
18219
|
const candidates = Array.from(
|
|
17996
|
-
document.querySelectorAll('input:not([type="hidden"]):not([type="submit"]):not([type="button"]):not([type="image"]), textarea, [contenteditable="
|
|
18220
|
+
document.querySelectorAll('input:not([type="hidden"]):not([type="submit"]):not([type="button"]):not([type="image"]), textarea, [contenteditable]:not([contenteditable="false"]), [role="textbox"], [role="searchbox"], [role="combobox"]')
|
|
17997
18221
|
).filter((el) => isFillable(el) && isVisible(el));
|
|
17998
18222
|
|
|
17999
18223
|
let best = null;
|
|
@@ -19608,9 +19832,11 @@ async function handleHighlight(ctx, args) {
|
|
|
19608
19832
|
}
|
|
19609
19833
|
return highlightOnPage(wc, selector, highlightText, args.label, args.durationMs, highlightColor);
|
|
19610
19834
|
}
|
|
19611
|
-
function handleClearHighlights(ctx) {
|
|
19835
|
+
async function handleClearHighlights(ctx) {
|
|
19612
19836
|
const wc = ctx.tabManager.getActiveTab()?.view.webContents;
|
|
19613
19837
|
if (!wc) return "Error: No active tab";
|
|
19838
|
+
const url = normalizeUrl$1(wc.getURL());
|
|
19839
|
+
clearHighlightsForUrl(url);
|
|
19614
19840
|
return clearHighlights(wc);
|
|
19615
19841
|
}
|
|
19616
19842
|
function trimText(value) {
|
|
@@ -22419,7 +22645,7 @@ function registerPrivateIpcHandlers(state2) {
|
|
|
22419
22645
|
});
|
|
22420
22646
|
ipc.handle(Channels.IS_PRIVATE_MODE, () => true);
|
|
22421
22647
|
ipc.handle(Channels.OPEN_PRIVATE_WINDOW, () => {
|
|
22422
|
-
|
|
22648
|
+
return openPrivateWindowSafely();
|
|
22423
22649
|
});
|
|
22424
22650
|
ipc.handle(Channels.OPEN_NEW_WINDOW, async () => {
|
|
22425
22651
|
const { createSecondaryWindow: createSecondaryWindow2 } = await Promise.resolve().then(() => window$1);
|
|
@@ -22463,70 +22689,120 @@ function registerPrivateIpcHandlers(state2) {
|
|
|
22463
22689
|
function createPrivateWindow() {
|
|
22464
22690
|
const privateSessionPartition = `private-${crypto$2.randomUUID()}`;
|
|
22465
22691
|
const privateSession = electron.session.fromPartition(privateSessionPartition);
|
|
22466
|
-
|
|
22467
|
-
|
|
22468
|
-
|
|
22469
|
-
|
|
22470
|
-
|
|
22471
|
-
|
|
22472
|
-
|
|
22473
|
-
|
|
22474
|
-
|
|
22475
|
-
|
|
22476
|
-
|
|
22477
|
-
|
|
22478
|
-
|
|
22479
|
-
|
|
22480
|
-
|
|
22481
|
-
|
|
22482
|
-
|
|
22692
|
+
let win = null;
|
|
22693
|
+
let tabManager = null;
|
|
22694
|
+
let state2 = null;
|
|
22695
|
+
try {
|
|
22696
|
+
privateSession.setUserAgent(electron.session.defaultSession.getUserAgent());
|
|
22697
|
+
win = new electron.BaseWindow({
|
|
22698
|
+
width: 1280,
|
|
22699
|
+
height: 800,
|
|
22700
|
+
minWidth: 800,
|
|
22701
|
+
minHeight: 600,
|
|
22702
|
+
frame: false,
|
|
22703
|
+
show: false,
|
|
22704
|
+
backgroundColor: "#1e1a2e",
|
|
22705
|
+
title: "Vessel - Private Browsing"
|
|
22706
|
+
});
|
|
22707
|
+
const chromeView = new electron.WebContentsView({
|
|
22708
|
+
webPreferences: {
|
|
22709
|
+
preload: path$1.join(__dirname, "../preload/index.js"),
|
|
22710
|
+
sandbox: true,
|
|
22711
|
+
contextIsolation: true,
|
|
22712
|
+
nodeIntegration: false
|
|
22713
|
+
}
|
|
22714
|
+
});
|
|
22715
|
+
chromeView.setBackgroundColor("#00000000");
|
|
22716
|
+
win.contentView.addChildView(chromeView);
|
|
22717
|
+
tabManager = new TabManager(
|
|
22718
|
+
win,
|
|
22719
|
+
(tabs, activeId) => {
|
|
22720
|
+
sendSafe(chromeView.webContents, Channels.TAB_STATE_UPDATE, tabs, activeId);
|
|
22721
|
+
if (state2) layoutPrivateViews(state2);
|
|
22722
|
+
},
|
|
22723
|
+
{ isPrivate: true, sessionPartition: privateSessionPartition }
|
|
22724
|
+
);
|
|
22725
|
+
state2 = {
|
|
22726
|
+
window: win,
|
|
22727
|
+
chromeView,
|
|
22728
|
+
tabManager,
|
|
22729
|
+
session: privateSession,
|
|
22730
|
+
sessionPartition: privateSessionPartition
|
|
22731
|
+
};
|
|
22732
|
+
installAdBlockingForSession(privateSession, tabManager);
|
|
22733
|
+
installDownloadHandlerForSession(privateSession, chromeView);
|
|
22734
|
+
registerPrivateIpcHandlers(state2);
|
|
22735
|
+
win.on("resize", () => {
|
|
22736
|
+
if (state2) layoutPrivateViews(state2);
|
|
22737
|
+
});
|
|
22738
|
+
win.on("show", () => {
|
|
22739
|
+
if (state2) layoutPrivateViews(state2);
|
|
22740
|
+
});
|
|
22741
|
+
win.on("closed", () => {
|
|
22742
|
+
if (!state2) return;
|
|
22743
|
+
privateWindows.delete(state2);
|
|
22744
|
+
tabManager?.destroyAllTabs();
|
|
22745
|
+
void Promise.all([
|
|
22746
|
+
privateSession.clearStorageData(),
|
|
22747
|
+
privateSession.clearCache()
|
|
22748
|
+
]).catch((error) => {
|
|
22749
|
+
logger$m.warn("Failed to clear private browsing session:", error);
|
|
22750
|
+
});
|
|
22751
|
+
});
|
|
22752
|
+
privateWindows.add(state2);
|
|
22753
|
+
chromeView.webContents.once("dom-ready", () => {
|
|
22754
|
+
try {
|
|
22755
|
+
tabManager?.createTab("about:blank");
|
|
22756
|
+
if (state2) layoutPrivateViews(state2);
|
|
22757
|
+
} catch (error) {
|
|
22758
|
+
logger$m.error("Failed to initialize private browsing tab:", error);
|
|
22759
|
+
try {
|
|
22760
|
+
win?.close();
|
|
22761
|
+
} catch (cleanupError) {
|
|
22762
|
+
logger$m.warn("Failed to close private window after tab init failure:", cleanupError);
|
|
22763
|
+
}
|
|
22764
|
+
}
|
|
22765
|
+
});
|
|
22766
|
+
loadPrivateRenderer(chromeView);
|
|
22767
|
+
win.show();
|
|
22768
|
+
logger$m.info("Private browsing window opened");
|
|
22769
|
+
return state2;
|
|
22770
|
+
} catch (error) {
|
|
22771
|
+
logger$m.error("Failed to create private browsing window:", error);
|
|
22772
|
+
if (state2) {
|
|
22773
|
+
privateWindows.delete(state2);
|
|
22774
|
+
}
|
|
22775
|
+
try {
|
|
22776
|
+
tabManager?.destroyAllTabs();
|
|
22777
|
+
} catch (cleanupError) {
|
|
22778
|
+
logger$m.warn("Failed to clean up private tabs after launch failure:", cleanupError);
|
|
22779
|
+
}
|
|
22780
|
+
try {
|
|
22781
|
+
win?.close();
|
|
22782
|
+
} catch (cleanupError) {
|
|
22783
|
+
logger$m.warn("Failed to close private window after launch failure:", cleanupError);
|
|
22483
22784
|
}
|
|
22484
|
-
});
|
|
22485
|
-
chromeView.setBackgroundColor("#00000000");
|
|
22486
|
-
win.contentView.addChildView(chromeView);
|
|
22487
|
-
const tabManager = new TabManager(
|
|
22488
|
-
win,
|
|
22489
|
-
(tabs, activeId) => {
|
|
22490
|
-
sendSafe(chromeView.webContents, Channels.TAB_STATE_UPDATE, tabs, activeId);
|
|
22491
|
-
layoutPrivateViews(state2);
|
|
22492
|
-
},
|
|
22493
|
-
{ isPrivate: true, sessionPartition: privateSessionPartition }
|
|
22494
|
-
);
|
|
22495
|
-
const state2 = {
|
|
22496
|
-
window: win,
|
|
22497
|
-
chromeView,
|
|
22498
|
-
tabManager,
|
|
22499
|
-
session: privateSession,
|
|
22500
|
-
sessionPartition: privateSessionPartition
|
|
22501
|
-
};
|
|
22502
|
-
installAdBlockingForSession(privateSession, tabManager);
|
|
22503
|
-
installDownloadHandlerForSession(privateSession, chromeView);
|
|
22504
|
-
registerPrivateIpcHandlers(state2);
|
|
22505
|
-
win.on("resize", () => layoutPrivateViews(state2));
|
|
22506
|
-
win.on("show", () => layoutPrivateViews(state2));
|
|
22507
|
-
win.on("closed", () => {
|
|
22508
|
-
privateWindows.delete(state2);
|
|
22509
|
-
tabManager.destroyAllTabs();
|
|
22510
22785
|
void Promise.all([
|
|
22511
22786
|
privateSession.clearStorageData(),
|
|
22512
22787
|
privateSession.clearCache()
|
|
22513
|
-
]).catch((
|
|
22514
|
-
logger$m.warn("Failed to clear private browsing session:",
|
|
22788
|
+
]).catch((cleanupError) => {
|
|
22789
|
+
logger$m.warn("Failed to clear failed private browsing session:", cleanupError);
|
|
22515
22790
|
});
|
|
22516
|
-
|
|
22517
|
-
|
|
22518
|
-
|
|
22519
|
-
|
|
22520
|
-
|
|
22521
|
-
|
|
22522
|
-
|
|
22523
|
-
|
|
22524
|
-
|
|
22525
|
-
|
|
22791
|
+
throw error;
|
|
22792
|
+
}
|
|
22793
|
+
}
|
|
22794
|
+
function openPrivateWindowSafely() {
|
|
22795
|
+
try {
|
|
22796
|
+
createPrivateWindow();
|
|
22797
|
+
return true;
|
|
22798
|
+
} catch {
|
|
22799
|
+
return false;
|
|
22800
|
+
}
|
|
22526
22801
|
}
|
|
22527
22802
|
const window$2 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
22528
22803
|
__proto__: null,
|
|
22529
|
-
createPrivateWindow
|
|
22804
|
+
createPrivateWindow,
|
|
22805
|
+
openPrivateWindowSafely
|
|
22530
22806
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
22531
22807
|
const secondaryWindows = /* @__PURE__ */ new Set();
|
|
22532
22808
|
function layoutSecondaryViews(state2) {
|
|
@@ -22644,8 +22920,8 @@ function registerSecondaryIpcHandlers(state2) {
|
|
|
22644
22920
|
);
|
|
22645
22921
|
ipc.handle(Channels.OPEN_NEW_WINDOW, () => createSecondaryWindow());
|
|
22646
22922
|
ipc.handle(Channels.OPEN_PRIVATE_WINDOW, async () => {
|
|
22647
|
-
const {
|
|
22648
|
-
|
|
22923
|
+
const { openPrivateWindowSafely: openPrivateWindowSafely2 } = await Promise.resolve().then(() => window$2);
|
|
22924
|
+
return openPrivateWindowSafely2();
|
|
22649
22925
|
});
|
|
22650
22926
|
ipc.handle(Channels.IS_PRIVATE_MODE, () => false);
|
|
22651
22927
|
ipc.handle(Channels.WINDOW_MINIMIZE, () => state2.window.minimize());
|
|
@@ -22733,7 +23009,7 @@ function registerTabHandlers(windowState, _sendToRendererViews) {
|
|
|
22733
23009
|
const { tabManager, mainWindow } = windowState;
|
|
22734
23010
|
electron.ipcMain.handle(Channels.OPEN_PRIVATE_WINDOW, (event) => {
|
|
22735
23011
|
assertTrustedIpcSender(event);
|
|
22736
|
-
|
|
23012
|
+
return openPrivateWindowSafely();
|
|
22737
23013
|
});
|
|
22738
23014
|
electron.ipcMain.handle(Channels.OPEN_NEW_WINDOW, (event) => {
|
|
22739
23015
|
assertTrustedIpcSender(event);
|
|
@@ -22951,10 +23227,11 @@ const SHARED_NAVIGATION_INSTRUCTIONS = [
|
|
|
22951
23227
|
"Prefer select_option for dropdowns and submit_form for forms instead of guessing with clicks.",
|
|
22952
23228
|
"After navigating to a new site, do not call read_page immediately unless you are genuinely stuck. Prefer the site's search box, known navigation patterns, or clicking a visible section first.",
|
|
22953
23229
|
"For open-web discovery, current facts, prices, flights, news, or search-engine home pages, call web_search(query). Use search(query) only to search within the current site or app.",
|
|
23230
|
+
"For questions about a named venue, business, organization, school, or local place, use search results to find the official site, then open that site and answer from its page. Do not keep rewriting generic web_search queries or switch to site: searches when an official or clearly direct result is available.",
|
|
22954
23231
|
"For flight price-shopping, include the route, date, and trip type in web_search(query); do not send vague or partial flight queries.",
|
|
22955
23232
|
"On flight/travel booking pages with visible route, destination, or date fields, use those visible controls before constructing direct Google Flights or travel-search URLs. Direct travel URLs are a fallback only after the visible controls fail or the page is unusable.",
|
|
22956
23233
|
"On retail and marketplace sites, prefer the site's visible search box, filters, and result pages over direct product URLs.",
|
|
22957
|
-
"For broad discovery tasks, prefer direct sources
|
|
23234
|
+
"For broad discovery tasks, prefer direct sources over generic search snippets. Use site-specific search only after opening the direct source fails to expose the needed information."
|
|
22958
23235
|
];
|
|
22959
23236
|
const VESSEL_SOURCE_INSTRUCTIONS = [
|
|
22960
23237
|
"When the user asks about Vessel, Vessel Browser, or Quanta Intellect, use these official sources directly instead of hunting around the open web first: Official page https://quantaintellect.com, GitHub repo https://github.com/unmodeled-tyler/vessel-browser, npm package https://www.npmjs.com/package/@quanta-intellect/vessel-browser.",
|
|
@@ -23911,8 +24188,16 @@ function registerHighlightHandlers(windowState, sendToRendererViews) {
|
|
|
23911
24188
|
const info = getActiveTabInfo(tabManager);
|
|
23912
24189
|
if (!info) return false;
|
|
23913
24190
|
try {
|
|
24191
|
+
const url = normalizeUrl$1(info.wc.getURL());
|
|
24192
|
+
const text = await getHighlightTextAtIndex(info.wc, validatedIndex);
|
|
23914
24193
|
const removed = await removeHighlightAtIndex(info.wc, validatedIndex);
|
|
23915
24194
|
if (removed) {
|
|
24195
|
+
if (text) {
|
|
24196
|
+
const persisted = findHighlightByText(url, text);
|
|
24197
|
+
if (persisted) {
|
|
24198
|
+
removeHighlight(persisted.id);
|
|
24199
|
+
}
|
|
24200
|
+
}
|
|
23916
24201
|
await emitHighlightCount();
|
|
23917
24202
|
}
|
|
23918
24203
|
return removed;
|
|
@@ -23926,6 +24211,8 @@ function registerHighlightHandlers(windowState, sendToRendererViews) {
|
|
|
23926
24211
|
const info = getActiveTabInfo(tabManager);
|
|
23927
24212
|
if (!info) return false;
|
|
23928
24213
|
try {
|
|
24214
|
+
const url = normalizeUrl$1(info.wc.getURL());
|
|
24215
|
+
clearHighlightsForUrl(url);
|
|
23929
24216
|
const cleared = await clearAllHighlightElements(info.wc);
|
|
23930
24217
|
if (cleared) {
|
|
23931
24218
|
await emitHighlightCount();
|
|
@@ -2195,7 +2195,24 @@ let pageDiffActivityThrottleTimer = null;
|
|
|
2195
2195
|
let lastPageDiffSignature = "";
|
|
2196
2196
|
const PAGE_DIFF_ACTIVITY_THROTTLE_MS = 350;
|
|
2197
2197
|
const PAGE_DIFF_MUTATION_DEBOUNCE_MS = 1200;
|
|
2198
|
-
const CUSTOM_TEXT_FIELD_SELECTOR = '[contenteditable="
|
|
2198
|
+
const CUSTOM_TEXT_FIELD_SELECTOR = '[contenteditable]:not([contenteditable="false"]), [role="textbox"], [role="searchbox"], [role="combobox"]';
|
|
2199
|
+
const ACTION_CONTROL_SELECTOR = [
|
|
2200
|
+
"button",
|
|
2201
|
+
'[role="button"]',
|
|
2202
|
+
'[role="tab"]',
|
|
2203
|
+
'[role="menuitem"]',
|
|
2204
|
+
'[role="option"]',
|
|
2205
|
+
'[role="radio"]',
|
|
2206
|
+
'[role="checkbox"]',
|
|
2207
|
+
'[role="switch"]',
|
|
2208
|
+
'input[type="submit"]',
|
|
2209
|
+
'input[type="button"]',
|
|
2210
|
+
'a[href^="#"][aria-selected]',
|
|
2211
|
+
'a[href^="#"][data-date]',
|
|
2212
|
+
'a[href^="#"][data-day]',
|
|
2213
|
+
'a[href^="#"][role="tab"]',
|
|
2214
|
+
'a[href^="#"][role="button"]'
|
|
2215
|
+
].join(", ");
|
|
2199
2216
|
function normalizeSignatureText(value) {
|
|
2200
2217
|
return (value || "").replace(/\s+/g, " ").trim();
|
|
2201
2218
|
}
|
|
@@ -2957,14 +2974,14 @@ function shouldExposeCustomTextField(el) {
|
|
|
2957
2974
|
if (!(el instanceof HTMLElement) || isNativeFormField(el)) return false;
|
|
2958
2975
|
if (!isElementVisible(el) || isElementDisabled(el)) return false;
|
|
2959
2976
|
const role = getElementRole(el);
|
|
2960
|
-
return el.isContentEditable || el.getAttribute("contenteditable")
|
|
2977
|
+
return el.isContentEditable || el.hasAttribute("contenteditable") && el.getAttribute("contenteditable") !== "false" || role === "textbox" || role === "searchbox" || role === "combobox";
|
|
2961
2978
|
}
|
|
2962
2979
|
function getCustomTextFieldInputType(el) {
|
|
2963
2980
|
const role = getElementRole(el);
|
|
2964
2981
|
if (role === "searchbox") return "search";
|
|
2965
2982
|
if (role === "combobox") return "combobox";
|
|
2966
2983
|
if (role === "textbox") return "text";
|
|
2967
|
-
return el
|
|
2984
|
+
return el instanceof HTMLElement && el.isContentEditable ? "text" : void 0;
|
|
2968
2985
|
}
|
|
2969
2986
|
function getCustomTextFieldHasValue(el) {
|
|
2970
2987
|
const value = getTrimmedText(el.textContent) || getTrimmedText(el.getAttribute("aria-valuetext")) || getTrimmedText(el.getAttribute("value"));
|
|
@@ -3066,6 +3083,29 @@ function buildBaseMetadata(el) {
|
|
|
3066
3083
|
ariaSelected: getAriaBoolean(el, "aria-selected")
|
|
3067
3084
|
};
|
|
3068
3085
|
}
|
|
3086
|
+
function isNavigableEmbeddedSrc(src) {
|
|
3087
|
+
const normalized = src.trim().toLowerCase();
|
|
3088
|
+
return Boolean(normalized) && !/^(about:blank|javascript:|data:)/.test(normalized);
|
|
3089
|
+
}
|
|
3090
|
+
function getEmbeddedFrameLabel(iframe) {
|
|
3091
|
+
const explicitLabel = getTrimmedText(iframe.getAttribute("title")) || getTrimmedText(iframe.getAttribute("aria-label")) || getTrimmedText(iframe.name) || getTrimmedText(iframe.id);
|
|
3092
|
+
if (explicitLabel) {
|
|
3093
|
+
return explicitLabel.slice(0, MAX_LABEL_LENGTH);
|
|
3094
|
+
}
|
|
3095
|
+
let host = "embedded page";
|
|
3096
|
+
try {
|
|
3097
|
+
host = new URL(iframe.src, window.location.href).hostname.replace(
|
|
3098
|
+
/^www\./,
|
|
3099
|
+
""
|
|
3100
|
+
);
|
|
3101
|
+
} catch {
|
|
3102
|
+
}
|
|
3103
|
+
const srcText = iframe.src.toLowerCase();
|
|
3104
|
+
const prefix = /\b(ticket|showtime|movie|cinema|theat(?:er|re))\b/.test(
|
|
3105
|
+
srcText
|
|
3106
|
+
) ? "Embedded ticketing page" : "Embedded page";
|
|
3107
|
+
return `${prefix}: ${host}`.slice(0, MAX_LABEL_LENGTH);
|
|
3108
|
+
}
|
|
3069
3109
|
function extractHeadings() {
|
|
3070
3110
|
return deepQuerySelectorAll("h1, h2, h3, h4, h5, h6").map((el) => {
|
|
3071
3111
|
const text = el.textContent?.trim() || "";
|
|
@@ -3126,9 +3166,7 @@ function getFieldMetadata(el) {
|
|
|
3126
3166
|
}
|
|
3127
3167
|
function extractInteractiveElements() {
|
|
3128
3168
|
const elements = [];
|
|
3129
|
-
deepQuerySelectorAll(
|
|
3130
|
-
'button, [role="button"], input[type="submit"], input[type="button"]'
|
|
3131
|
-
).forEach((btn) => {
|
|
3169
|
+
deepQuerySelectorAll(ACTION_CONTROL_SELECTOR).forEach((btn) => {
|
|
3132
3170
|
const { text, source } = getButtonTextWithSource(btn);
|
|
3133
3171
|
const role = getElementRole(btn);
|
|
3134
3172
|
elements.push({
|
|
@@ -3154,6 +3192,17 @@ function extractInteractiveElements() {
|
|
|
3154
3192
|
context
|
|
3155
3193
|
});
|
|
3156
3194
|
});
|
|
3195
|
+
deepQuerySelectorAll("iframe[src]").forEach((frame) => {
|
|
3196
|
+
const iframe = frame;
|
|
3197
|
+
if (!isNavigableEmbeddedSrc(iframe.src)) return;
|
|
3198
|
+
elements.push({
|
|
3199
|
+
type: "link",
|
|
3200
|
+
text: getEmbeddedFrameLabel(iframe),
|
|
3201
|
+
href: iframe.src.slice(0, MAX_HREF_LENGTH),
|
|
3202
|
+
...buildBaseMetadata(iframe),
|
|
3203
|
+
context: getElementContext(iframe)
|
|
3204
|
+
});
|
|
3205
|
+
});
|
|
3157
3206
|
deepQuerySelectorAll(
|
|
3158
3207
|
'input:not([type="hidden"]):not([type="submit"]):not([type="button"]), select, textarea'
|
|
3159
3208
|
).forEach((input) => {
|
|
@@ -3763,6 +3763,55 @@
|
|
|
3763
3763
|
background: var(--surface-active);
|
|
3764
3764
|
}
|
|
3765
3765
|
|
|
3766
|
+
.tool-chip-group {
|
|
3767
|
+
margin: 3px 0;
|
|
3768
|
+
}
|
|
3769
|
+
|
|
3770
|
+
.tool-chip-group .tool-chip {
|
|
3771
|
+
margin: 0;
|
|
3772
|
+
}
|
|
3773
|
+
|
|
3774
|
+
.tool-chip-summary {
|
|
3775
|
+
width: 100%;
|
|
3776
|
+
cursor: pointer;
|
|
3777
|
+
text-align: left;
|
|
3778
|
+
}
|
|
3779
|
+
|
|
3780
|
+
.tool-chip-group:not(.expanded) .tool-chip-group-items {
|
|
3781
|
+
display: none;
|
|
3782
|
+
}
|
|
3783
|
+
|
|
3784
|
+
.tool-chip-summary::after {
|
|
3785
|
+
content: "▸";
|
|
3786
|
+
margin-left: auto;
|
|
3787
|
+
color: var(--text-muted);
|
|
3788
|
+
font-size: 10px;
|
|
3789
|
+
transition: transform var(--duration-fast) var(--ease-in-out);
|
|
3790
|
+
}
|
|
3791
|
+
|
|
3792
|
+
.tool-chip-group.expanded .tool-chip-summary::after {
|
|
3793
|
+
transform: rotate(90deg);
|
|
3794
|
+
}
|
|
3795
|
+
|
|
3796
|
+
.tool-chip-count {
|
|
3797
|
+
padding: 1px 6px;
|
|
3798
|
+
border-radius: 999px;
|
|
3799
|
+
background: color-mix(in srgb, var(--accent-primary) 10%, transparent);
|
|
3800
|
+
color: var(--text-muted);
|
|
3801
|
+
font-size: 10px;
|
|
3802
|
+
font-weight: 600;
|
|
3803
|
+
line-height: 1.4;
|
|
3804
|
+
}
|
|
3805
|
+
|
|
3806
|
+
.tool-chip-group-items {
|
|
3807
|
+
display: flex;
|
|
3808
|
+
flex-direction: column;
|
|
3809
|
+
gap: 3px;
|
|
3810
|
+
margin: 4px 0 4px 14px;
|
|
3811
|
+
padding-left: 8px;
|
|
3812
|
+
border-left: 1px solid var(--border-subtle);
|
|
3813
|
+
}
|
|
3814
|
+
|
|
3766
3815
|
.tool-chip-failed {
|
|
3767
3816
|
border-left-color: color-mix(in srgb, var(--error) 60%, transparent);
|
|
3768
3817
|
background: color-mix(in srgb, var(--error) 8%, var(--surface-hover));
|
|
@@ -6515,11 +6515,11 @@ function createDOMPurify() {
|
|
|
6515
6515
|
const originalDocument = document2;
|
|
6516
6516
|
const currentScript = originalDocument.currentScript;
|
|
6517
6517
|
window2.DocumentFragment;
|
|
6518
|
-
const HTMLTemplateElement = window2.HTMLTemplateElement, Node = window2.Node,
|
|
6518
|
+
const HTMLTemplateElement = window2.HTMLTemplateElement, Node = window2.Node, Element2 = window2.Element, NodeFilter = window2.NodeFilter, _window$NamedNodeMap = window2.NamedNodeMap;
|
|
6519
6519
|
_window$NamedNodeMap === void 0 ? window2.NamedNodeMap || window2.MozNamedAttrMap : _window$NamedNodeMap;
|
|
6520
6520
|
window2.HTMLFormElement;
|
|
6521
6521
|
const DOMParser = window2.DOMParser, trustedTypes = window2.trustedTypes;
|
|
6522
|
-
const ElementPrototype =
|
|
6522
|
+
const ElementPrototype = Element2.prototype;
|
|
6523
6523
|
const cloneNode = lookupGetter(ElementPrototype, "cloneNode");
|
|
6524
6524
|
const remove = lookupGetter(ElementPrototype, "remove");
|
|
6525
6525
|
const getNextSibling = lookupGetter(ElementPrototype, "nextSibling");
|
|
@@ -7602,13 +7602,59 @@ const TOOL_ICONS = {
|
|
|
7602
7602
|
create_checkpoint: "⚑",
|
|
7603
7603
|
restore_checkpoint: "⟲"
|
|
7604
7604
|
};
|
|
7605
|
+
function formatToolName(name) {
|
|
7606
|
+
return name.replace(/_/g, " ");
|
|
7607
|
+
}
|
|
7605
7608
|
function renderToolChip(name, args) {
|
|
7606
7609
|
const icon = TOOL_ICONS[name] || "⚙";
|
|
7607
|
-
const displayName = name
|
|
7610
|
+
const displayName = formatToolName(name);
|
|
7608
7611
|
const failed = args.trim().startsWith("⚠");
|
|
7609
7612
|
const argsHtml = args ? `<span class="tool-chip-args">${escapeHtml(args.length > MAX_PREVIEW_TEXT ? args.slice(0, TRUNCATE_KEEP) + "..." : args)}</span>` : "";
|
|
7610
7613
|
return `<div class="tool-chip${failed ? " tool-chip-failed" : ""}"><span class="tool-chip-icon">${icon}</span><span class="tool-chip-name">${escapeHtml(displayName)}</span>${argsHtml}</div>`;
|
|
7611
7614
|
}
|
|
7615
|
+
function renderToolChipGroup(chips) {
|
|
7616
|
+
if (chips.length === 1) return chips[0].html;
|
|
7617
|
+
const first = chips[0];
|
|
7618
|
+
const icon = TOOL_ICONS[first.name] || "⚙";
|
|
7619
|
+
const failed = chips.some((chip) => chip.failed);
|
|
7620
|
+
const latestArgs = [...chips].reverse().find((chip) => chip.args)?.args ?? "";
|
|
7621
|
+
const argsHtml = latestArgs ? `<span class="tool-chip-args">${escapeHtml(latestArgs.length > MAX_PREVIEW_TEXT ? latestArgs.slice(0, TRUNCATE_KEEP) + "..." : latestArgs)}</span>` : "";
|
|
7622
|
+
return [
|
|
7623
|
+
`<div class="tool-chip-group${failed ? " tool-chip-group-failed" : ""}">`,
|
|
7624
|
+
`<div class="tool-chip tool-chip-summary${failed ? " tool-chip-failed" : ""}">`,
|
|
7625
|
+
`<span class="tool-chip-icon">${icon}</span>`,
|
|
7626
|
+
`<span class="tool-chip-name">${escapeHtml(formatToolName(first.name))}</span>`,
|
|
7627
|
+
`<span class="tool-chip-count">${chips.length} calls</span>`,
|
|
7628
|
+
argsHtml,
|
|
7629
|
+
`</div>`,
|
|
7630
|
+
`<div class="tool-chip-group-items">`,
|
|
7631
|
+
chips.map((chip) => chip.html).join(""),
|
|
7632
|
+
`</div>`,
|
|
7633
|
+
`</div>`
|
|
7634
|
+
].join("");
|
|
7635
|
+
}
|
|
7636
|
+
function collapseAdjacentToolTokens(html2, toolChips) {
|
|
7637
|
+
return html2.replace(/(?:\x00TC\d+\x00){2,}/g, (sequence) => {
|
|
7638
|
+
const indices = Array.from(
|
|
7639
|
+
sequence.matchAll(/\x00TC(\d+)\x00/g),
|
|
7640
|
+
(match) => Number(match[1])
|
|
7641
|
+
);
|
|
7642
|
+
const groups = [];
|
|
7643
|
+
for (const index of indices) {
|
|
7644
|
+
const chip = toolChips[index];
|
|
7645
|
+
if (!chip) continue;
|
|
7646
|
+
const current = groups[groups.length - 1];
|
|
7647
|
+
if (current && current[0]?.name === chip.name) {
|
|
7648
|
+
current.push(chip);
|
|
7649
|
+
} else {
|
|
7650
|
+
groups.push([chip]);
|
|
7651
|
+
}
|
|
7652
|
+
}
|
|
7653
|
+
return groups.map(
|
|
7654
|
+
(group) => group.length > 1 ? renderToolChipGroup(group) : `\0TC${toolChips.indexOf(group[0])}\0`
|
|
7655
|
+
).join("");
|
|
7656
|
+
});
|
|
7657
|
+
}
|
|
7612
7658
|
function renderMarkdown(source) {
|
|
7613
7659
|
const codeBlocks = [];
|
|
7614
7660
|
const toolChips = [];
|
|
@@ -7616,7 +7662,15 @@ function renderMarkdown(source) {
|
|
|
7616
7662
|
/<<tool:([^:>\n]+)(?::([^>\n]*))?>>/g,
|
|
7617
7663
|
(_, name, args) => {
|
|
7618
7664
|
const token = `\0TC${toolChips.length}\0`;
|
|
7619
|
-
|
|
7665
|
+
const normalizedName = name.trim();
|
|
7666
|
+
const normalizedArgs = (args || "").trim();
|
|
7667
|
+
toolChips.push({
|
|
7668
|
+
index: toolChips.length,
|
|
7669
|
+
name: normalizedName,
|
|
7670
|
+
args: normalizedArgs,
|
|
7671
|
+
html: renderToolChip(normalizedName, normalizedArgs),
|
|
7672
|
+
failed: normalizedArgs.startsWith("⚠")
|
|
7673
|
+
});
|
|
7620
7674
|
return `
|
|
7621
7675
|
|
|
7622
7676
|
${token}
|
|
@@ -7645,13 +7699,13 @@ ${token}
|
|
|
7645
7699
|
(_, _content) => ""
|
|
7646
7700
|
);
|
|
7647
7701
|
const cleaned = erased.replace(/\x00ERASE\x00/g, "");
|
|
7648
|
-
let output = cleaned;
|
|
7702
|
+
let output = collapseAdjacentToolTokens(cleaned, toolChips);
|
|
7649
7703
|
output = codeBlocks.reduce(
|
|
7650
7704
|
(out, snippet, index) => out.replace(`\0CB${index}\0`, snippet),
|
|
7651
7705
|
output
|
|
7652
7706
|
);
|
|
7653
7707
|
output = toolChips.reduce(
|
|
7654
|
-
(out, snippet, index) => out.replace(`\0TC${index}\0`, snippet),
|
|
7708
|
+
(out, snippet, index) => out.replace(`\0TC${index}\0`, snippet.html),
|
|
7655
7709
|
output
|
|
7656
7710
|
);
|
|
7657
7711
|
if (typeof purify?.sanitize !== "function") {
|
|
@@ -7687,7 +7741,14 @@ ${token}
|
|
|
7687
7741
|
"tr",
|
|
7688
7742
|
"ul"
|
|
7689
7743
|
],
|
|
7690
|
-
ALLOWED_ATTR: [
|
|
7744
|
+
ALLOWED_ATTR: [
|
|
7745
|
+
"href",
|
|
7746
|
+
"target",
|
|
7747
|
+
"rel",
|
|
7748
|
+
"data-language",
|
|
7749
|
+
"style",
|
|
7750
|
+
"class"
|
|
7751
|
+
]
|
|
7691
7752
|
});
|
|
7692
7753
|
}
|
|
7693
7754
|
function isPremiumStatus(status) {
|
|
@@ -9817,7 +9878,7 @@ const SidebarWindowControls = (props) => {
|
|
|
9817
9878
|
};
|
|
9818
9879
|
delegateEvents(["click"]);
|
|
9819
9880
|
const vesselLogo = "" + new URL("vessel-logo-transparent-IT25qr-Z.png", import.meta.url).href;
|
|
9820
|
-
var _tmpl$$a = /* @__PURE__ */ template(`<div class="message-content markdown-content">`), _tmpl$2$a = /* @__PURE__ */ template(`<div class=premium-inline-offer><div class=premium-inline-kicker>Vessel Premium</div><div class=premium-inline-title></div><p class=premium-inline-copy></p><div class=premium-inline-actions><button class="agent-primary-button premium-inline-primary"type=button>Start 7-day free trial — $5.99/mo after</button><button class="agent-control-button premium-inline-secondary"type=button>View details`), _tmpl$3$9 = /* @__PURE__ */ template(`<div class=sidebar-resize-handle>`), _tmpl$4$8 = /* @__PURE__ */ template(`<span class=sidebar-tab-badge>`), _tmpl$5$8 = /* @__PURE__ */ template(`<button class=agent-primary-button type=button>Undo last action`), _tmpl$6$8 = /* @__PURE__ */ template(`<div class=agent-section-title>Pending approvals`), _tmpl$7$6 = /* @__PURE__ */ template(`<button class=agent-section-toggle type=button>`), _tmpl$8$5 = /* @__PURE__ */ template(`<section class=agent-panel><div class=agent-panel-header><div><div class=agent-panel-title>Supervisor</div><div class=agent-panel-subtitle></div></div><span class=agent-status-pill></span></div><div class=agent-panel-controls><button class=agent-control-button type=button></button><button class=agent-control-button type=button>Restore session</button></div><div class=agent-muted></div><div class=agent-section-header><div class=agent-section-title>Recent actions`), _tmpl$9$4 = /* @__PURE__ */ template(`<span class=bookmark-status-pill>Saved`), _tmpl$0$3 = /* @__PURE__ */ template(`<div class=bookmark-export-message>`), _tmpl$1$3 = /* @__PURE__ */ template(`<div class=bookmark-save-body><div class=bookmark-export-actions><button class=bookmark-secondary-button type=button>Import HTML</button><button class=bookmark-secondary-button type=button>Import JSON`), _tmpl$10$3 = /* @__PURE__ */ template(`<div class=bookmark-save-card><div class=bookmark-current-title></div><div class=bookmark-current-url></div><div class=bookmark-save-controls><button class=bookmark-primary-button type=button>Save page</button></div><textarea class=bookmark-note-input placeholder="Optional note about why this matters"rows=2></textarea><textarea class=bookmark-note-input placeholder="Intent: what is this page for?"rows=1></textarea><textarea class=bookmark-note-input placeholder="Expected content: what should be here?"rows=1></textarea><input class=bookmark-input placeholder="Key fields (comma-separated)"><textarea class=bookmark-note-input placeholder="Agent hints (one key:value per line)"rows=2>`), _tmpl$11$3 = /* @__PURE__ */ template(`<section class=bookmark-panel><div class=bookmark-panel-header><div><div class=bookmark-panel-title>Bookmarks</div><div class=bookmark-panel-subtitle></div></div></div><input class="bookmark-input bookmark-search-input"placeholder="Search titles, URLs, notes, and folders"><div class=bookmark-export-card><div><div class=bookmark-panel-title>Export</div><div class=bookmark-panel-subtitle>Save browser-ready HTML or a full Vessel archive</div></div><div class=bookmark-export-actions><button class=bookmark-secondary-button type=button>Browser HTML</button><button class=bookmark-secondary-button type=button>HTML + notes</button><button class=bookmark-secondary-button type=button>Vessel JSON</button></div></div><div class=bookmark-import-shell><button class=bookmark-save-toggle type=button><span class=bookmark-save-toggle-copy><span class=bookmark-save-toggle-title>Import Bookmarks</span><span class=bookmark-save-toggle-subtitle>Import from HTML or Vessel JSON</span></span><span class=bookmark-save-toggle-caret aria-hidden=true>▾</span></button></div><div class=bookmark-save-shell><button class=bookmark-save-toggle type=button><span class=bookmark-save-toggle-copy><span class=bookmark-save-toggle-title>Save Current Page</span><span class=bookmark-save-toggle-subtitle>Manual bookmark save options</span></span><span class=bookmark-save-toggle-caret aria-hidden=true>▾</span></button></div><form class=bookmark-folder-create><div class=bookmark-folder-form-fields><input class=bookmark-input placeholder="Create a folder"><input class=bookmark-input placeholder="Optional one-line summary"></div><button class=bookmark-secondary-button type=submit>New folder</button></form><div class=bookmark-folder-list>`), _tmpl$12$3 = /* @__PURE__ */ template(`<div class=checkpoint-timeline>`), _tmpl$13$2 = /* @__PURE__ */ template(`<section class="agent-panel checkpoint-panel"><div class=agent-panel-header><div><div class=agent-panel-title>Checkpoints</div><div class=agent-panel-subtitle></div></div></div><div class=agent-panel-body><div class=agent-checkpoint-row><input class=agent-input placeholder="Checkpoint name"><textarea class=agent-textarea rows=2 placeholder="Optional note for this checkpoint"></textarea><button class=agent-primary-button type=button>Save checkpoint</button></div><div class=agent-section-title>Recent checkpoints`), _tmpl$14$2 = /* @__PURE__ */ template(`<button class=history-entry><span class=history-entry-title>Load more history</span><span class=history-entry-url>Showing <!> of `), _tmpl$15$2 = /* @__PURE__ */ template(`<p class=history-empty>No browsing history yet.`), _tmpl$16$1 = /* @__PURE__ */ template(`<div class=history-panel><div class=history-panel-header><span class=history-panel-title>Browsing History</span><div class=history-panel-actions><button class=history-clear-btn>Clear</button><button class=history-clear-btn>Export HTML</button><button class=history-clear-btn>Export JSON</button><button class=history-clear-btn>Import</button></div></div><div class=history-list>`), _tmpl$17$1 = /* @__PURE__ */ template(`<section class=agent-panel><div class=agent-panel-header><div class=agent-panel-title>What Changed</div><div class=agent-panel-subtitle>`), _tmpl$18$1 = /* @__PURE__ */ template(`<div class="kit-upsell premium-chat-banner"><p class=kit-upsell-title>Vessel Premium</p><p class="kit-upsell-body premium-chat-banner-body">Give the built-in agent a bigger toolbox and longer runway: screenshots, saved sessions, workflow tracking, table extraction, and up to 1,000 tool calls per turn.</p><div class="premium-inline-actions premium-chat-banner-actions"><button class="agent-primary-button premium-inline-primary"type=button>Start 7-day free trial — $5.99/mo after</button><button class="agent-control-button premium-inline-secondary"type=button>See Premium`), _tmpl$19$1 = /* @__PURE__ */ template(`<span>`), _tmpl$20$1 = /* @__PURE__ */ template(`<div><div class=streaming-status><span class=streaming-pulse aria-hidden=true></span><span>Generating`), _tmpl$21$1 = /* @__PURE__ */ template(`<div class="message message-assistant"><div class=message-content>`), _tmpl$22$1 = /* @__PURE__ */ template(`<div class=sidebar-empty><svg class=sidebar-empty-icon width=48 height=48 viewBox="0 0 48 48"aria-hidden=true><line x1=8 y1=8 x2=24 y2=5 stroke=var(--border-visible) stroke-width=1 opacity=0.4></line><line x1=24 y1=5 x2=40 y2=10 stroke=var(--border-visible) stroke-width=1 opacity=0.45></line><line x1=8 y1=8 x2=6 y2=24 stroke=var(--border-visible) stroke-width=1 opacity=0.4></line><line x1=40 y1=10 x2=44 y2=26 stroke=var(--border-visible) stroke-width=1 opacity=0.45></line><line x1=6 y1=24 x2=10 y2=38 stroke=var(--border-visible) stroke-width=1 opacity=0.4></line><line x1=44 y1=26 x2=38 y2=40 stroke=var(--border-visible) stroke-width=1 opacity=0.4></line><line x1=10 y1=38 x2=24 y2=44 stroke=var(--border-visible) stroke-width=1 opacity=0.35></line><line x1=38 y1=40 x2=24 y2=44 stroke=var(--border-visible) stroke-width=1 opacity=0.35></line><line x1=8 y1=8 x2=20 y2=18 stroke=var(--border-visible) stroke-width=1 opacity=0.5></line><line x1=24 y1=5 x2=20 y2=18 stroke=var(--border-visible) stroke-width=1 opacity=0.45></line><line x1=40 y1=10 x2=32 y2=20 stroke=var(--border-visible) stroke-width=1 opacity=0.5></line><line x1=20 y1=18 x2=32 y2=20 stroke=var(--accent-primary) stroke-width=0.75 opacity=0.3></line><line x1=6 y1=24 x2=18 y2=30 stroke=var(--border-visible) stroke-width=1 opacity=0.45></line><line x1=20 y1=18 x2=18 y2=30 stroke=var(--border-visible) stroke-width=1 opacity=0.45></line><line x1=32 y1=20 x2=36 y2=30 stroke=var(--border-visible) stroke-width=1 opacity=0.45></line><line x1=44 y1=26 x2=36 y2=30 stroke=var(--border-visible) stroke-width=1 opacity=0.45></line><line x1=18 y1=30 x2=36 y2=30 stroke=var(--accent-primary) stroke-width=0.75 opacity=0.25></line><line x1=18 y1=30 x2=10 y2=38 stroke=var(--border-visible) stroke-width=1 opacity=0.4></line><line x1=36 y1=30 x2=38 y2=40 stroke=var(--border-visible) stroke-width=1 opacity=0.4></line><line x1=18 y1=30 x2=24 y2=44 stroke=var(--accent-primary) stroke-width=0.75 opacity=0.2></line><line x1=36 y1=30 x2=24 y2=44 stroke=var(--accent-primary) stroke-width=0.75 opacity=0.2></line><circle cx=8 cy=8 r=2.5 fill=var(--bg-secondary) stroke=var(--accent-primary) stroke-width=1.5 opacity=0.55></circle><circle cx=24 cy=5 r=2 fill=var(--bg-secondary) stroke=var(--accent-primary) stroke-width=1.5 opacity=0.45></circle><circle cx=40 cy=10 r=3 fill=var(--bg-secondary) stroke=var(--accent-primary) stroke-width=1.5 opacity=0.7></circle><circle cx=6 cy=24 r=2 fill=var(--bg-secondary) stroke=var(--accent-primary) stroke-width=1.5 opacity=0.5></circle><circle cx=44 cy=26 r=2.5 fill=var(--bg-secondary) stroke=var(--accent-primary) stroke-width=1.5 opacity=0.55></circle><circle cx=10 cy=38 r=2.5 fill=var(--bg-secondary) stroke=var(--accent-primary) stroke-width=1.5 opacity=0.5></circle><circle cx=38 cy=40 r=2 fill=var(--bg-secondary) stroke=var(--accent-primary) stroke-width=1.5 opacity=0.45></circle><circle cx=24 cy=44 r=2.5 fill=var(--bg-secondary) stroke=var(--accent-primary) stroke-width=1.5 opacity=0.5></circle><circle cx=20 cy=18 r=3.5 fill=var(--bg-secondary) stroke=var(--accent-primary) stroke-width=1.5 opacity=0.85></circle><circle cx=32 cy=20 r=4 fill=var(--bg-secondary) stroke=var(--accent-primary) stroke-width=1.5 opacity=0.9></circle><circle cx=18 cy=30 r=3 fill=var(--bg-secondary) stroke=var(--accent-primary) stroke-width=1.5 opacity=0.75></circle><circle cx=36 cy=30 r=3.5 fill=var(--bg-secondary) stroke=var(--accent-primary) stroke-width=1.5 opacity=0.8></circle></svg><p class=sidebar-empty-title>Your move.</p><p class=sidebar-empty-hint>Configure a provider in Settings (Ctrl+,) then ask anything about the current page or beyond.`), _tmpl$23$1 = /* @__PURE__ */ template(`<button class=chat-action-btn title="Stop generating"><svg width=14 height=14 viewBox="0 0 14 14"fill=none aria-hidden=true><rect x=2 y=2 width=10 height=10 rx=1.5 fill=currentColor></rect></svg>Stop`), _tmpl$24$1 = /* @__PURE__ */ template(`<button class=chat-action-btn title="Retry last prompt"><svg width=14 height=14 viewBox="0 0 14 14"fill=none aria-hidden=true><path d="M11.5 7a4.5 4.5 0 1 1-1.3-3.2"stroke=currentColor stroke-width=1.5 stroke-linecap=round></path><path d="M10.5 1v3h-3"stroke=currentColor stroke-width=1.5 stroke-linecap=round stroke-linejoin=round></path></svg>Retry`), _tmpl$25$1 = /* @__PURE__ */ template(`<div class=chat-actions>`), _tmpl$26$1 = /* @__PURE__ */ template(`<div class=highlight-nav><button class=highlight-nav-btn type=button title="Previous highlight"><svg width=12 height=12 viewBox="0 0 12 12"fill=none aria-hidden=true><path d="M8 10L4 6l4-4"stroke=currentColor stroke-width=1.5 stroke-linecap=round stroke-linejoin=round></path></svg></button><button class=highlight-nav-label type=button title="Go to current highlight"><svg width=12 height=12 viewBox="0 0 12 12"fill=none aria-hidden=true><circle cx=6 cy=6 r=3 fill=var(--accent-primary) stroke=var(--accent-primary) stroke-width=1></circle></svg></button><button class=highlight-nav-btn type=button title="Next highlight"><svg width=12 height=12 viewBox="0 0 12 12"fill=none aria-hidden=true><path d="M4 2l4 4-4 4"stroke=currentColor stroke-width=1.5 stroke-linecap=round stroke-linejoin=round>`), _tmpl$27$1 = /* @__PURE__ */ template(`<button class=chat-queue-clear type=button>Clear queue`), _tmpl$28$1 = /* @__PURE__ */ template(`<div class=chat-queue-list>`), _tmpl$29$1 = /* @__PURE__ */ template(`<div class=chat-queue-status><div class=chat-queue-status-row><span>`), _tmpl$30 = /* @__PURE__ */ template(`<div class=chat-command-error><span></span><button class=chat-command-error-dismiss type=button aria-label="Dismiss command error">×`), _tmpl$31 = /* @__PURE__ */ template(`<div class=chat-skill-suggestions role=listbox>`), _tmpl$32 = /* @__PURE__ */ template(`<div class=sidebar-input-area><div class=sidebar-input-frame><textarea class=sidebar-input rows=2></textarea></div><button class=sidebar-send>`), _tmpl$33 = /* @__PURE__ */ template(`<div class=sidebar><div class=sidebar-header><div class=sidebar-brand><img class=sidebar-logo alt=Vessel><span class=sidebar-brand-text>Vessel Browser</span></div><div class=sidebar-header-actions><button class=sidebar-clear title="Clear chat">Clear</button></div></div><div class=sidebar-tabs role=tablist><button class=sidebar-tab role=tab>Supervisor</button><button class=sidebar-tab role=tab>Bookmarks</button><button class=sidebar-tab role=tab>Checkpoints</button><button class=sidebar-tab role=tab>Chat</button><button class=sidebar-tab role=tab>Skills</button><button class=sidebar-tab role=tab>History</button><button class=sidebar-tab role=tab>Changes</button><button class=sidebar-tab role=tab>Research<span class=sidebar-tab-beta>Beta</span></button></div><div class=sidebar-messages><div>`), _tmpl$34 = /* @__PURE__ */ template(`<div class=agent-muted>No pending approvals.`), _tmpl$35 = /* @__PURE__ */ template(`<div class="agent-card agent-card-approval"><div class=agent-card-approval-stripe aria-hidden=true></div><div class=agent-card-title></div><div class=agent-card-copy></div><div class=agent-card-copy></div><div class=agent-card-actions><button class=agent-primary-button type=button>Approve</button><button class=agent-control-button type=button>Reject`), _tmpl$36 = /* @__PURE__ */ template(`<div class=agent-muted>No actions yet.`), _tmpl$37 = /* @__PURE__ */ template(`<div class=agent-muted>Recent actions are collapsed to reduce noise.`), _tmpl$38 = /* @__PURE__ */ template(`<div class="agent-card-copy success">`), _tmpl$39 = /* @__PURE__ */ template(`<div class="agent-card-copy error">`), _tmpl$40 = /* @__PURE__ */ template(`<div class=agent-card><div class=agent-action-row><span class=agent-card-title></span><span></span></div><div class=agent-card-copy>`), _tmpl$41 = /* @__PURE__ */ template(`<div class=bookmark-empty-folder>`), _tmpl$42 = /* @__PURE__ */ template(`<div class=bookmark-folder-summary>`), _tmpl$43 = /* @__PURE__ */ template(`<div class=bookmark-folder-actions><button class=bookmark-ghost-button type=button>Rename</button><button class=bookmark-ghost-button type=button>Export</button><button class="bookmark-ghost-button danger"type=button>Delete`), _tmpl$44 = /* @__PURE__ */ template(`<button class=bookmark-ghost-button type=button>Keep bookmarks`), _tmpl$45 = /* @__PURE__ */ template(`<div class=bookmark-folder-delete-confirm><p class=bookmark-delete-prompt>Delete "<!>"?</p><div class=bookmark-delete-options><button class="bookmark-ghost-button danger"type=button></button><button class=bookmark-ghost-button type=button>Cancel`), _tmpl$46 = /* @__PURE__ */ template(`<div class=bookmark-folder-edit><div class=bookmark-folder-form-fields><input class=bookmark-input><input class=bookmark-input placeholder="Optional one-line summary"></div><button class=bookmark-secondary-button type=button>Save</button><button class=bookmark-ghost-button type=button>Cancel`), _tmpl$47 = /* @__PURE__ */ template(`<div class=bookmark-items>`), _tmpl$48 = /* @__PURE__ */ template(`<div class=bookmark-folder-section><div class="bookmark-folder-header clickable"role=button tabindex=0><div class=bookmark-folder-overview><span class=bookmark-folder-chevron aria-hidden=true>▸</span><div><div class=bookmark-folder-name></div><div class=bookmark-folder-meta> saved`), _tmpl$49 = /* @__PURE__ */ template(`<div class=bookmark-folder-collapsed-hint>Click to view saved links.`), _tmpl$50 = /* @__PURE__ */ template(`<div class=bookmark-empty-folder>No bookmarks in this folder yet.`), _tmpl$51 = /* @__PURE__ */ template(`<div class=bookmark-item-note>`), _tmpl$52 = /* @__PURE__ */ template(`<div><strong>Intent:</strong> `), _tmpl$53 = /* @__PURE__ */ template(`<div><strong>Expected:</strong> `), _tmpl$54 = /* @__PURE__ */ template(`<div><strong>Key fields:</strong> `), _tmpl$55 = /* @__PURE__ */ template(`<div><strong>Hints:</strong> `), _tmpl$56 = /* @__PURE__ */ template(`<div class=bookmark-folder-edit><input class=bookmark-input placeholder="Bookmark title"><textarea class=bookmark-note-input rows=2 placeholder="Why this bookmark matters"></textarea><textarea class=bookmark-note-input rows=1 placeholder=Intent></textarea><textarea class=bookmark-note-input rows=1 placeholder="Expected content"></textarea><input class=bookmark-input placeholder="Key fields (comma-separated)"><textarea class=bookmark-note-input rows=2 placeholder="Agent hints (one key:value per line)"></textarea><div class=bookmark-item-footer><button class=bookmark-secondary-button type=button>Save edits</button><button class=bookmark-ghost-button type=button>Cancel`), _tmpl$57 = /* @__PURE__ */ template(`<div class=bookmark-item><button class=bookmark-item-link type=button><span class=bookmark-item-title></span><span class=bookmark-item-url></span></button><div class=bookmark-item-footer><span class=bookmark-item-time></span><button class=bookmark-ghost-button type=button></button><button class="bookmark-ghost-button danger"type=button>Remove`), _tmpl$58 = /* @__PURE__ */ template(`<div class=agent-muted>No checkpoints yet.`), _tmpl$59 = /* @__PURE__ */ template(`<span class=checkpoint-timeline-line>`), _tmpl$60 = /* @__PURE__ */ template(`<div class=checkpoint-timeline-item><div class=checkpoint-timeline-rail><span class=checkpoint-timeline-dot></span></div><div class=checkpoint-timeline-content><div class=checkpoint-timeline-name></div><div class=checkpoint-timeline-time></div><textarea class=agent-textarea rows=2 placeholder="Add a note..."></textarea><button class=agent-control-button type=button>Restore`), _tmpl$61 = /* @__PURE__ */ template(`<button class=history-entry><span class=history-entry-title></span><span class=history-entry-url></span><span class=history-entry-time>`), _tmpl$62 = /* @__PURE__ */ template(`<div class="kit-upsell premium-chat-banner"><p class=kit-upsell-title>Vessel Premium</p><p class="kit-upsell-body premium-chat-banner-body">The Diff timeline is a premium feature. Upgrade to see a full history of what changed on this page.</p><div class="premium-inline-actions premium-chat-banner-actions"><button class="agent-primary-button premium-inline-primary"type=button>Start 7-day free trial — $5.99/mo after</button><button class="agent-control-button premium-inline-secondary"type=button>See Premium`), _tmpl$63 = /* @__PURE__ */ template(`<div>`), _tmpl$64 = /* @__PURE__ */ template(`<div class=thinking-state><div class=thinking-orb aria-hidden=true><span></span><span></span><span></span></div><div class=thinking-copy><div class=thinking-title>Thinking`), _tmpl$65 = /* @__PURE__ */ template(`<div class=chat-approval-detail>`), _tmpl$66 = /* @__PURE__ */ template(`<div class=chat-approval><div class=chat-approval-icon aria-hidden=true><svg width=16 height=16 viewBox="0 0 16 16"fill=none><path d="M8 1.5a6.5 6.5 0 100 13 6.5 6.5 0 000-13zM7.25 4.75a.75.75 0 011.5 0v3.5a.75.75 0 01-1.5 0v-3.5zM8 11.5a.75.75 0 110-1.5.75.75 0 010 1.5z"fill=currentColor></path></svg></div><div class=chat-approval-body><div class=chat-approval-title>Approval needed: <strong></strong></div><div class=chat-approval-detail></div><div class=chat-approval-actions><button class="chat-approval-btn chat-approval-approve"type=button>Approve</button><button class="chat-approval-btn chat-approval-reject"type=button>Reject`), _tmpl$67 = /* @__PURE__ */ template(`<div class=chat-queue-item><span class=chat-queue-text></span><button class=chat-queue-remove type=button>×`), _tmpl$68 = /* @__PURE__ */ template(`<button class=chat-skill-suggestion type=button role=option><span class=chat-skill-suggestion-command>/</span><span class=chat-skill-suggestion-body><span class=chat-skill-suggestion-name></span><span class=chat-skill-suggestion-desc>`), _tmpl$69 = /* @__PURE__ */ template(`<div class=sidebar-input-highlight aria-hidden=true><span class=sidebar-input-highlight-command>`);
|
|
9881
|
+
var _tmpl$$a = /* @__PURE__ */ template(`<div class="message-content markdown-content">`), _tmpl$2$a = /* @__PURE__ */ template(`<div class=premium-inline-offer><div class=premium-inline-kicker>Vessel Premium</div><div class=premium-inline-title></div><p class=premium-inline-copy></p><div class=premium-inline-actions><button class="agent-primary-button premium-inline-primary"type=button>Start 7-day free trial — $5.99/mo after</button><button class="agent-control-button premium-inline-secondary"type=button>View details`), _tmpl$3$9 = /* @__PURE__ */ template(`<div class=sidebar-resize-handle>`), _tmpl$4$8 = /* @__PURE__ */ template(`<span class=sidebar-tab-badge>`), _tmpl$5$8 = /* @__PURE__ */ template(`<button class=agent-primary-button type=button>Undo last action`), _tmpl$6$8 = /* @__PURE__ */ template(`<div class=agent-section-title>Pending approvals`), _tmpl$7$6 = /* @__PURE__ */ template(`<button class=agent-section-toggle type=button>`), _tmpl$8$5 = /* @__PURE__ */ template(`<section class=agent-panel><div class=agent-panel-header><div><div class=agent-panel-title>Supervisor</div><div class=agent-panel-subtitle></div></div><span class=agent-status-pill></span></div><div class=agent-panel-controls><button class=agent-control-button type=button></button><button class=agent-control-button type=button>Restore session</button></div><div class=agent-muted></div><div class=agent-section-header><div class=agent-section-title>Recent actions`), _tmpl$9$4 = /* @__PURE__ */ template(`<span class=bookmark-status-pill>Saved`), _tmpl$0$3 = /* @__PURE__ */ template(`<div class=bookmark-export-message>`), _tmpl$1$3 = /* @__PURE__ */ template(`<div class=bookmark-save-body><div class=bookmark-export-actions><button class=bookmark-secondary-button type=button>Import HTML</button><button class=bookmark-secondary-button type=button>Import JSON`), _tmpl$10$3 = /* @__PURE__ */ template(`<div class=bookmark-save-card><div class=bookmark-current-title></div><div class=bookmark-current-url></div><div class=bookmark-save-controls><button class=bookmark-primary-button type=button>Save page</button></div><textarea class=bookmark-note-input placeholder="Optional note about why this matters"rows=2></textarea><textarea class=bookmark-note-input placeholder="Intent: what is this page for?"rows=1></textarea><textarea class=bookmark-note-input placeholder="Expected content: what should be here?"rows=1></textarea><input class=bookmark-input placeholder="Key fields (comma-separated)"><textarea class=bookmark-note-input placeholder="Agent hints (one key:value per line)"rows=2>`), _tmpl$11$3 = /* @__PURE__ */ template(`<section class=bookmark-panel><div class=bookmark-panel-header><div><div class=bookmark-panel-title>Bookmarks</div><div class=bookmark-panel-subtitle></div></div></div><input class="bookmark-input bookmark-search-input"placeholder="Search titles, URLs, notes, and folders"><div class=bookmark-export-card><div><div class=bookmark-panel-title>Export</div><div class=bookmark-panel-subtitle>Save browser-ready HTML or a full Vessel archive</div></div><div class=bookmark-export-actions><button class=bookmark-secondary-button type=button>Browser HTML</button><button class=bookmark-secondary-button type=button>HTML + notes</button><button class=bookmark-secondary-button type=button>Vessel JSON</button></div></div><div class=bookmark-import-shell><button class=bookmark-save-toggle type=button><span class=bookmark-save-toggle-copy><span class=bookmark-save-toggle-title>Import Bookmarks</span><span class=bookmark-save-toggle-subtitle>Import from HTML or Vessel JSON</span></span><span class=bookmark-save-toggle-caret aria-hidden=true>▾</span></button></div><div class=bookmark-save-shell><button class=bookmark-save-toggle type=button><span class=bookmark-save-toggle-copy><span class=bookmark-save-toggle-title>Save Current Page</span><span class=bookmark-save-toggle-subtitle>Manual bookmark save options</span></span><span class=bookmark-save-toggle-caret aria-hidden=true>▾</span></button></div><form class=bookmark-folder-create><div class=bookmark-folder-form-fields><input class=bookmark-input placeholder="Create a folder"><input class=bookmark-input placeholder="Optional one-line summary"></div><button class=bookmark-secondary-button type=submit>New folder</button></form><div class=bookmark-folder-list>`), _tmpl$12$3 = /* @__PURE__ */ template(`<div class=checkpoint-timeline>`), _tmpl$13$2 = /* @__PURE__ */ template(`<section class="agent-panel checkpoint-panel"><div class=agent-panel-header><div><div class=agent-panel-title>Checkpoints</div><div class=agent-panel-subtitle></div></div></div><div class=agent-panel-body><div class=agent-checkpoint-row><input class=agent-input placeholder="Checkpoint name"><textarea class=agent-textarea rows=2 placeholder="Optional note for this checkpoint"></textarea><button class=agent-primary-button type=button>Save checkpoint</button></div><div class=agent-section-title>Recent checkpoints`), _tmpl$14$2 = /* @__PURE__ */ template(`<button class=history-entry><span class=history-entry-title>Load more history</span><span class=history-entry-url>Showing <!> of `), _tmpl$15$2 = /* @__PURE__ */ template(`<p class=history-empty>No browsing history yet.`), _tmpl$16$1 = /* @__PURE__ */ template(`<div class=history-panel><div class=history-panel-header><span class=history-panel-title>Browsing History</span><div class=history-panel-actions><button class=history-clear-btn>Clear</button><button class=history-clear-btn>Export HTML</button><button class=history-clear-btn>Export JSON</button><button class=history-clear-btn>Import</button></div></div><div class=history-list>`), _tmpl$17$1 = /* @__PURE__ */ template(`<section class=agent-panel><div class=agent-panel-header><div class=agent-panel-title>What Changed</div><div class=agent-panel-subtitle>`), _tmpl$18$1 = /* @__PURE__ */ template(`<div class="kit-upsell premium-chat-banner"><p class=kit-upsell-title>Vessel Premium</p><p class="kit-upsell-body premium-chat-banner-body">Give the built-in agent a bigger toolbox and longer runway: screenshots, saved sessions, workflow tracking, table extraction, and up to 1,000 tool calls per turn.</p><div class="premium-inline-actions premium-chat-banner-actions"><button class="agent-primary-button premium-inline-primary"type=button>Start 7-day free trial — $5.99/mo after</button><button class="agent-control-button premium-inline-secondary"type=button>See Premium`), _tmpl$19$1 = /* @__PURE__ */ template(`<span>`), _tmpl$20$1 = /* @__PURE__ */ template(`<div><div class=streaming-status><span class=streaming-pulse aria-hidden=true></span><span>Thinking`), _tmpl$21$1 = /* @__PURE__ */ template(`<div class="message message-assistant"><div class=message-content>`), _tmpl$22$1 = /* @__PURE__ */ template(`<div class=sidebar-empty><svg class=sidebar-empty-icon width=48 height=48 viewBox="0 0 48 48"aria-hidden=true><line x1=8 y1=8 x2=24 y2=5 stroke=var(--border-visible) stroke-width=1 opacity=0.4></line><line x1=24 y1=5 x2=40 y2=10 stroke=var(--border-visible) stroke-width=1 opacity=0.45></line><line x1=8 y1=8 x2=6 y2=24 stroke=var(--border-visible) stroke-width=1 opacity=0.4></line><line x1=40 y1=10 x2=44 y2=26 stroke=var(--border-visible) stroke-width=1 opacity=0.45></line><line x1=6 y1=24 x2=10 y2=38 stroke=var(--border-visible) stroke-width=1 opacity=0.4></line><line x1=44 y1=26 x2=38 y2=40 stroke=var(--border-visible) stroke-width=1 opacity=0.4></line><line x1=10 y1=38 x2=24 y2=44 stroke=var(--border-visible) stroke-width=1 opacity=0.35></line><line x1=38 y1=40 x2=24 y2=44 stroke=var(--border-visible) stroke-width=1 opacity=0.35></line><line x1=8 y1=8 x2=20 y2=18 stroke=var(--border-visible) stroke-width=1 opacity=0.5></line><line x1=24 y1=5 x2=20 y2=18 stroke=var(--border-visible) stroke-width=1 opacity=0.45></line><line x1=40 y1=10 x2=32 y2=20 stroke=var(--border-visible) stroke-width=1 opacity=0.5></line><line x1=20 y1=18 x2=32 y2=20 stroke=var(--accent-primary) stroke-width=0.75 opacity=0.3></line><line x1=6 y1=24 x2=18 y2=30 stroke=var(--border-visible) stroke-width=1 opacity=0.45></line><line x1=20 y1=18 x2=18 y2=30 stroke=var(--border-visible) stroke-width=1 opacity=0.45></line><line x1=32 y1=20 x2=36 y2=30 stroke=var(--border-visible) stroke-width=1 opacity=0.45></line><line x1=44 y1=26 x2=36 y2=30 stroke=var(--border-visible) stroke-width=1 opacity=0.45></line><line x1=18 y1=30 x2=36 y2=30 stroke=var(--accent-primary) stroke-width=0.75 opacity=0.25></line><line x1=18 y1=30 x2=10 y2=38 stroke=var(--border-visible) stroke-width=1 opacity=0.4></line><line x1=36 y1=30 x2=38 y2=40 stroke=var(--border-visible) stroke-width=1 opacity=0.4></line><line x1=18 y1=30 x2=24 y2=44 stroke=var(--accent-primary) stroke-width=0.75 opacity=0.2></line><line x1=36 y1=30 x2=24 y2=44 stroke=var(--accent-primary) stroke-width=0.75 opacity=0.2></line><circle cx=8 cy=8 r=2.5 fill=var(--bg-secondary) stroke=var(--accent-primary) stroke-width=1.5 opacity=0.55></circle><circle cx=24 cy=5 r=2 fill=var(--bg-secondary) stroke=var(--accent-primary) stroke-width=1.5 opacity=0.45></circle><circle cx=40 cy=10 r=3 fill=var(--bg-secondary) stroke=var(--accent-primary) stroke-width=1.5 opacity=0.7></circle><circle cx=6 cy=24 r=2 fill=var(--bg-secondary) stroke=var(--accent-primary) stroke-width=1.5 opacity=0.5></circle><circle cx=44 cy=26 r=2.5 fill=var(--bg-secondary) stroke=var(--accent-primary) stroke-width=1.5 opacity=0.55></circle><circle cx=10 cy=38 r=2.5 fill=var(--bg-secondary) stroke=var(--accent-primary) stroke-width=1.5 opacity=0.5></circle><circle cx=38 cy=40 r=2 fill=var(--bg-secondary) stroke=var(--accent-primary) stroke-width=1.5 opacity=0.45></circle><circle cx=24 cy=44 r=2.5 fill=var(--bg-secondary) stroke=var(--accent-primary) stroke-width=1.5 opacity=0.5></circle><circle cx=20 cy=18 r=3.5 fill=var(--bg-secondary) stroke=var(--accent-primary) stroke-width=1.5 opacity=0.85></circle><circle cx=32 cy=20 r=4 fill=var(--bg-secondary) stroke=var(--accent-primary) stroke-width=1.5 opacity=0.9></circle><circle cx=18 cy=30 r=3 fill=var(--bg-secondary) stroke=var(--accent-primary) stroke-width=1.5 opacity=0.75></circle><circle cx=36 cy=30 r=3.5 fill=var(--bg-secondary) stroke=var(--accent-primary) stroke-width=1.5 opacity=0.8></circle></svg><p class=sidebar-empty-title>Your move.</p><p class=sidebar-empty-hint>Configure a provider in Settings (Ctrl+,) then ask anything about the current page or beyond.`), _tmpl$23$1 = /* @__PURE__ */ template(`<button class=chat-action-btn title="Stop generating"><svg width=14 height=14 viewBox="0 0 14 14"fill=none aria-hidden=true><rect x=2 y=2 width=10 height=10 rx=1.5 fill=currentColor></rect></svg>Stop`), _tmpl$24$1 = /* @__PURE__ */ template(`<button class=chat-action-btn title="Retry last prompt"><svg width=14 height=14 viewBox="0 0 14 14"fill=none aria-hidden=true><path d="M11.5 7a4.5 4.5 0 1 1-1.3-3.2"stroke=currentColor stroke-width=1.5 stroke-linecap=round></path><path d="M10.5 1v3h-3"stroke=currentColor stroke-width=1.5 stroke-linecap=round stroke-linejoin=round></path></svg>Retry`), _tmpl$25$1 = /* @__PURE__ */ template(`<div class=chat-actions>`), _tmpl$26$1 = /* @__PURE__ */ template(`<div class=highlight-nav><button class=highlight-nav-btn type=button title="Previous highlight"><svg width=12 height=12 viewBox="0 0 12 12"fill=none aria-hidden=true><path d="M8 10L4 6l4-4"stroke=currentColor stroke-width=1.5 stroke-linecap=round stroke-linejoin=round></path></svg></button><button class=highlight-nav-label type=button title="Go to current highlight"><svg width=12 height=12 viewBox="0 0 12 12"fill=none aria-hidden=true><circle cx=6 cy=6 r=3 fill=var(--accent-primary) stroke=var(--accent-primary) stroke-width=1></circle></svg></button><button class=highlight-nav-btn type=button title="Next highlight"><svg width=12 height=12 viewBox="0 0 12 12"fill=none aria-hidden=true><path d="M4 2l4 4-4 4"stroke=currentColor stroke-width=1.5 stroke-linecap=round stroke-linejoin=round>`), _tmpl$27$1 = /* @__PURE__ */ template(`<button class=chat-queue-clear type=button>Clear queue`), _tmpl$28$1 = /* @__PURE__ */ template(`<div class=chat-queue-list>`), _tmpl$29$1 = /* @__PURE__ */ template(`<div class=chat-queue-status><div class=chat-queue-status-row><span>`), _tmpl$30 = /* @__PURE__ */ template(`<div class=chat-command-error><span></span><button class=chat-command-error-dismiss type=button aria-label="Dismiss command error">×`), _tmpl$31 = /* @__PURE__ */ template(`<div class=chat-skill-suggestions role=listbox>`), _tmpl$32 = /* @__PURE__ */ template(`<div class=sidebar-input-area><div class=sidebar-input-frame><textarea class=sidebar-input rows=2></textarea></div><button class=sidebar-send>`), _tmpl$33 = /* @__PURE__ */ template(`<div class=sidebar><div class=sidebar-header><div class=sidebar-brand><img class=sidebar-logo alt=Vessel><span class=sidebar-brand-text>Vessel Browser</span></div><div class=sidebar-header-actions><button class=sidebar-clear title="Clear chat">Clear</button></div></div><div class=sidebar-tabs role=tablist><button class=sidebar-tab role=tab>Supervisor</button><button class=sidebar-tab role=tab>Bookmarks</button><button class=sidebar-tab role=tab>Checkpoints</button><button class=sidebar-tab role=tab>Chat</button><button class=sidebar-tab role=tab>Skills</button><button class=sidebar-tab role=tab>History</button><button class=sidebar-tab role=tab>Changes</button><button class=sidebar-tab role=tab>Research<span class=sidebar-tab-beta>Beta</span></button></div><div class=sidebar-messages><div>`), _tmpl$34 = /* @__PURE__ */ template(`<div class=agent-muted>No pending approvals.`), _tmpl$35 = /* @__PURE__ */ template(`<div class="agent-card agent-card-approval"><div class=agent-card-approval-stripe aria-hidden=true></div><div class=agent-card-title></div><div class=agent-card-copy></div><div class=agent-card-copy></div><div class=agent-card-actions><button class=agent-primary-button type=button>Approve</button><button class=agent-control-button type=button>Reject`), _tmpl$36 = /* @__PURE__ */ template(`<div class=agent-muted>No actions yet.`), _tmpl$37 = /* @__PURE__ */ template(`<div class=agent-muted>Recent actions are collapsed to reduce noise.`), _tmpl$38 = /* @__PURE__ */ template(`<div class="agent-card-copy success">`), _tmpl$39 = /* @__PURE__ */ template(`<div class="agent-card-copy error">`), _tmpl$40 = /* @__PURE__ */ template(`<div class=agent-card><div class=agent-action-row><span class=agent-card-title></span><span></span></div><div class=agent-card-copy>`), _tmpl$41 = /* @__PURE__ */ template(`<div class=bookmark-empty-folder>`), _tmpl$42 = /* @__PURE__ */ template(`<div class=bookmark-folder-summary>`), _tmpl$43 = /* @__PURE__ */ template(`<div class=bookmark-folder-actions><button class=bookmark-ghost-button type=button>Rename</button><button class=bookmark-ghost-button type=button>Export</button><button class="bookmark-ghost-button danger"type=button>Delete`), _tmpl$44 = /* @__PURE__ */ template(`<button class=bookmark-ghost-button type=button>Keep bookmarks`), _tmpl$45 = /* @__PURE__ */ template(`<div class=bookmark-folder-delete-confirm><p class=bookmark-delete-prompt>Delete "<!>"?</p><div class=bookmark-delete-options><button class="bookmark-ghost-button danger"type=button></button><button class=bookmark-ghost-button type=button>Cancel`), _tmpl$46 = /* @__PURE__ */ template(`<div class=bookmark-folder-edit><div class=bookmark-folder-form-fields><input class=bookmark-input><input class=bookmark-input placeholder="Optional one-line summary"></div><button class=bookmark-secondary-button type=button>Save</button><button class=bookmark-ghost-button type=button>Cancel`), _tmpl$47 = /* @__PURE__ */ template(`<div class=bookmark-items>`), _tmpl$48 = /* @__PURE__ */ template(`<div class=bookmark-folder-section><div class="bookmark-folder-header clickable"role=button tabindex=0><div class=bookmark-folder-overview><span class=bookmark-folder-chevron aria-hidden=true>▸</span><div><div class=bookmark-folder-name></div><div class=bookmark-folder-meta> saved`), _tmpl$49 = /* @__PURE__ */ template(`<div class=bookmark-folder-collapsed-hint>Click to view saved links.`), _tmpl$50 = /* @__PURE__ */ template(`<div class=bookmark-empty-folder>No bookmarks in this folder yet.`), _tmpl$51 = /* @__PURE__ */ template(`<div class=bookmark-item-note>`), _tmpl$52 = /* @__PURE__ */ template(`<div><strong>Intent:</strong> `), _tmpl$53 = /* @__PURE__ */ template(`<div><strong>Expected:</strong> `), _tmpl$54 = /* @__PURE__ */ template(`<div><strong>Key fields:</strong> `), _tmpl$55 = /* @__PURE__ */ template(`<div><strong>Hints:</strong> `), _tmpl$56 = /* @__PURE__ */ template(`<div class=bookmark-folder-edit><input class=bookmark-input placeholder="Bookmark title"><textarea class=bookmark-note-input rows=2 placeholder="Why this bookmark matters"></textarea><textarea class=bookmark-note-input rows=1 placeholder=Intent></textarea><textarea class=bookmark-note-input rows=1 placeholder="Expected content"></textarea><input class=bookmark-input placeholder="Key fields (comma-separated)"><textarea class=bookmark-note-input rows=2 placeholder="Agent hints (one key:value per line)"></textarea><div class=bookmark-item-footer><button class=bookmark-secondary-button type=button>Save edits</button><button class=bookmark-ghost-button type=button>Cancel`), _tmpl$57 = /* @__PURE__ */ template(`<div class=bookmark-item><button class=bookmark-item-link type=button><span class=bookmark-item-title></span><span class=bookmark-item-url></span></button><div class=bookmark-item-footer><span class=bookmark-item-time></span><button class=bookmark-ghost-button type=button></button><button class="bookmark-ghost-button danger"type=button>Remove`), _tmpl$58 = /* @__PURE__ */ template(`<div class=agent-muted>No checkpoints yet.`), _tmpl$59 = /* @__PURE__ */ template(`<span class=checkpoint-timeline-line>`), _tmpl$60 = /* @__PURE__ */ template(`<div class=checkpoint-timeline-item><div class=checkpoint-timeline-rail><span class=checkpoint-timeline-dot></span></div><div class=checkpoint-timeline-content><div class=checkpoint-timeline-name></div><div class=checkpoint-timeline-time></div><textarea class=agent-textarea rows=2 placeholder="Add a note..."></textarea><button class=agent-control-button type=button>Restore`), _tmpl$61 = /* @__PURE__ */ template(`<button class=history-entry><span class=history-entry-title></span><span class=history-entry-url></span><span class=history-entry-time>`), _tmpl$62 = /* @__PURE__ */ template(`<div class="kit-upsell premium-chat-banner"><p class=kit-upsell-title>Vessel Premium</p><p class="kit-upsell-body premium-chat-banner-body">The Diff timeline is a premium feature. Upgrade to see a full history of what changed on this page.</p><div class="premium-inline-actions premium-chat-banner-actions"><button class="agent-primary-button premium-inline-primary"type=button>Start 7-day free trial — $5.99/mo after</button><button class="agent-control-button premium-inline-secondary"type=button>See Premium`), _tmpl$63 = /* @__PURE__ */ template(`<div>`), _tmpl$64 = /* @__PURE__ */ template(`<div class=thinking-state><div class=thinking-orb aria-hidden=true><span></span><span></span><span></span></div><div class=thinking-copy><div class=thinking-title>Thinking`), _tmpl$65 = /* @__PURE__ */ template(`<div class=chat-approval-detail>`), _tmpl$66 = /* @__PURE__ */ template(`<div class=chat-approval><div class=chat-approval-icon aria-hidden=true><svg width=16 height=16 viewBox="0 0 16 16"fill=none><path d="M8 1.5a6.5 6.5 0 100 13 6.5 6.5 0 000-13zM7.25 4.75a.75.75 0 011.5 0v3.5a.75.75 0 01-1.5 0v-3.5zM8 11.5a.75.75 0 110-1.5.75.75 0 010 1.5z"fill=currentColor></path></svg></div><div class=chat-approval-body><div class=chat-approval-title>Approval needed: <strong></strong></div><div class=chat-approval-detail></div><div class=chat-approval-actions><button class="chat-approval-btn chat-approval-approve"type=button>Approve</button><button class="chat-approval-btn chat-approval-reject"type=button>Reject`), _tmpl$67 = /* @__PURE__ */ template(`<div class=chat-queue-item><span class=chat-queue-text></span><button class=chat-queue-remove type=button>×`), _tmpl$68 = /* @__PURE__ */ template(`<button class=chat-skill-suggestion type=button role=option><span class=chat-skill-suggestion-command>/</span><span class=chat-skill-suggestion-body><span class=chat-skill-suggestion-name></span><span class=chat-skill-suggestion-desc>`), _tmpl$69 = /* @__PURE__ */ template(`<div class=sidebar-input-highlight aria-hidden=true><span class=sidebar-input-highlight-command>`);
|
|
9821
9882
|
const UNSORTED_FOLDER = {
|
|
9822
9883
|
id: "unsorted",
|
|
9823
9884
|
name: "Unsorted",
|
|
@@ -9825,8 +9886,19 @@ const UNSORTED_FOLDER = {
|
|
|
9825
9886
|
};
|
|
9826
9887
|
const MarkdownMessage = (props) => {
|
|
9827
9888
|
const html2 = createMemo(() => renderMarkdown(props.content));
|
|
9889
|
+
const handleClick = (event) => {
|
|
9890
|
+
const target = event.target;
|
|
9891
|
+
if (!(target instanceof Element)) return;
|
|
9892
|
+
const summary = target.closest(".tool-chip-summary");
|
|
9893
|
+
if (!(summary instanceof HTMLElement)) return;
|
|
9894
|
+
const group = summary.closest(".tool-chip-group");
|
|
9895
|
+
if (!(group instanceof HTMLElement)) return;
|
|
9896
|
+
const expanded = !group.classList.contains("expanded");
|
|
9897
|
+
group.classList.toggle("expanded", expanded);
|
|
9898
|
+
};
|
|
9828
9899
|
return (() => {
|
|
9829
9900
|
var _el$ = _tmpl$$a();
|
|
9901
|
+
_el$.$$click = handleClick;
|
|
9830
9902
|
createRenderEffect(() => _el$.innerHTML = html2());
|
|
9831
9903
|
return _el$;
|
|
9832
9904
|
})();
|
package/out/renderer/index.html
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; base-uri 'none'; object-src 'none'; frame-src 'none'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self'; font-src 'self' data:; form-action 'self';" />
|
|
7
7
|
<title>Vessel</title>
|
|
8
|
-
<script type="module" crossorigin src="./assets/index-
|
|
9
|
-
<link rel="stylesheet" crossorigin href="./assets/index-
|
|
8
|
+
<script type="module" crossorigin src="./assets/index-BW4Oa1R1.js"></script>
|
|
9
|
+
<link rel="stylesheet" crossorigin href="./assets/index-B4pY2BdC.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
12
12
|
<div id="root"></div>
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quanta-intellect/vessel-browser",
|
|
3
3
|
"mcpName": "io.github.unmodeled-tyler/vessel-browser",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.143",
|
|
5
5
|
"description": "AI-native web browser runtime for autonomous agents with human supervision",
|
|
6
6
|
"main": "./out/main/index.js",
|
|
7
7
|
"bin": {
|