@quanta-intellect/vessel-browser 0.1.10 → 0.1.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -1
- package/out/main/index.js +3356 -758
- package/out/preload/content-script.js +121 -9
- package/out/preload/index.js +20 -0
- package/out/renderer/assets/{index-Cud0VqFQ.css → index-DMd-y6tm.css} +267 -0
- package/out/renderer/assets/{index-CCVxW0YM.js → index-Do3B3G1W.js} +467 -211
- package/out/renderer/index.html +2 -2
- package/package.json +1 -1
|
@@ -2126,8 +2126,78 @@ function generateStableSelector(el) {
|
|
|
2126
2126
|
let elementIndex = 0;
|
|
2127
2127
|
const elementSelectors = {};
|
|
2128
2128
|
let indexedElements = /* @__PURE__ */ new WeakMap();
|
|
2129
|
+
const indexedElementRefs = {};
|
|
2129
2130
|
let activeOverlays = [];
|
|
2131
|
+
const MAX_SHADOW_HOSTS = 150;
|
|
2132
|
+
const MAX_SHADOW_DEPTH = 5;
|
|
2133
|
+
const MAX_WALK_ELEMENTS = 1e4;
|
|
2134
|
+
function collectShadowRoots(root) {
|
|
2135
|
+
const shadowRoots = [];
|
|
2136
|
+
let walked = 0;
|
|
2137
|
+
const walk = (node, depth) => {
|
|
2138
|
+
if (depth > MAX_SHADOW_DEPTH || shadowRoots.length >= MAX_SHADOW_HOSTS) return;
|
|
2139
|
+
const tw = document.createTreeWalker(node, NodeFilter.SHOW_ELEMENT);
|
|
2140
|
+
let el = tw.nextNode();
|
|
2141
|
+
while (el && walked < MAX_WALK_ELEMENTS && shadowRoots.length < MAX_SHADOW_HOSTS) {
|
|
2142
|
+
walked++;
|
|
2143
|
+
if (el.shadowRoot) {
|
|
2144
|
+
shadowRoots.push(el.shadowRoot);
|
|
2145
|
+
walk(el.shadowRoot, depth + 1);
|
|
2146
|
+
}
|
|
2147
|
+
el = tw.nextNode();
|
|
2148
|
+
}
|
|
2149
|
+
};
|
|
2150
|
+
walk(root, 0);
|
|
2151
|
+
return shadowRoots;
|
|
2152
|
+
}
|
|
2153
|
+
function deepQuerySelectorAll(selector, root = document) {
|
|
2154
|
+
const results = [];
|
|
2155
|
+
root.querySelectorAll(selector).forEach((el) => results.push(el));
|
|
2156
|
+
for (const sr of collectShadowRoots(root)) {
|
|
2157
|
+
sr.querySelectorAll(selector).forEach((el) => results.push(el));
|
|
2158
|
+
}
|
|
2159
|
+
return results;
|
|
2160
|
+
}
|
|
2161
|
+
function isInShadowDom(el) {
|
|
2162
|
+
return el.getRootNode() instanceof ShadowRoot;
|
|
2163
|
+
}
|
|
2164
|
+
function generateShadowPiercingSelector(el) {
|
|
2165
|
+
const segments = [];
|
|
2166
|
+
let current = el;
|
|
2167
|
+
while (current) {
|
|
2168
|
+
const rootNode = current.getRootNode();
|
|
2169
|
+
const innerSel = generateStableSelector(current);
|
|
2170
|
+
if (rootNode instanceof ShadowRoot) {
|
|
2171
|
+
segments.unshift(innerSel);
|
|
2172
|
+
current = rootNode.host;
|
|
2173
|
+
} else {
|
|
2174
|
+
segments.unshift(innerSel);
|
|
2175
|
+
break;
|
|
2176
|
+
}
|
|
2177
|
+
}
|
|
2178
|
+
if (segments.length <= 1) return null;
|
|
2179
|
+
return segments.join(" >>> ");
|
|
2180
|
+
}
|
|
2181
|
+
function resolveShadowSelector(selectorPath) {
|
|
2182
|
+
const segments = selectorPath.split(" >>> ").map((s) => s.trim());
|
|
2183
|
+
let scope = document;
|
|
2184
|
+
for (let i = 0; i < segments.length; i++) {
|
|
2185
|
+
const el = scope.querySelector(segments[i]);
|
|
2186
|
+
if (!el) return null;
|
|
2187
|
+
if (i < segments.length - 1) {
|
|
2188
|
+
if (!el.shadowRoot) return null;
|
|
2189
|
+
scope = el.shadowRoot;
|
|
2190
|
+
} else {
|
|
2191
|
+
return el;
|
|
2192
|
+
}
|
|
2193
|
+
}
|
|
2194
|
+
return null;
|
|
2195
|
+
}
|
|
2130
2196
|
function generateSelector(el) {
|
|
2197
|
+
if (isInShadowDom(el)) {
|
|
2198
|
+
const shadowPath = generateShadowPiercingSelector(el);
|
|
2199
|
+
if (shadowPath) return shadowPath;
|
|
2200
|
+
}
|
|
2131
2201
|
return generateStableSelector(el);
|
|
2132
2202
|
}
|
|
2133
2203
|
function assignIndex(el) {
|
|
@@ -2135,6 +2205,7 @@ function assignIndex(el) {
|
|
|
2135
2205
|
if (existing != null) return existing;
|
|
2136
2206
|
elementIndex += 1;
|
|
2137
2207
|
elementSelectors[elementIndex] = generateSelector(el);
|
|
2208
|
+
indexedElementRefs[elementIndex] = el;
|
|
2138
2209
|
indexedElements.set(el, elementIndex);
|
|
2139
2210
|
return elementIndex;
|
|
2140
2211
|
}
|
|
@@ -2475,7 +2546,7 @@ function buildBaseMetadata(el) {
|
|
|
2475
2546
|
};
|
|
2476
2547
|
}
|
|
2477
2548
|
function extractHeadings() {
|
|
2478
|
-
return
|
|
2549
|
+
return deepQuerySelectorAll("h1, h2, h3, h4, h5, h6").map((el) => {
|
|
2479
2550
|
const text = el.textContent?.trim() || "";
|
|
2480
2551
|
if (!text) return null;
|
|
2481
2552
|
return {
|
|
@@ -2486,10 +2557,10 @@ function extractHeadings() {
|
|
|
2486
2557
|
}
|
|
2487
2558
|
function extractNavigation() {
|
|
2488
2559
|
const navigation = [];
|
|
2489
|
-
|
|
2560
|
+
deepQuerySelectorAll(
|
|
2490
2561
|
'nav, [role="navigation"], header nav, [role="banner"] nav'
|
|
2491
2562
|
).forEach((nav) => {
|
|
2492
|
-
|
|
2563
|
+
deepQuerySelectorAll("a[href]", nav).forEach((link) => {
|
|
2493
2564
|
const anchor = link;
|
|
2494
2565
|
const text = anchor.textContent?.trim();
|
|
2495
2566
|
if (!text || anchor.getAttribute("href")?.startsWith("#")) return;
|
|
@@ -2534,7 +2605,7 @@ function getFieldMetadata(el) {
|
|
|
2534
2605
|
}
|
|
2535
2606
|
function extractInteractiveElements() {
|
|
2536
2607
|
const elements = [];
|
|
2537
|
-
|
|
2608
|
+
deepQuerySelectorAll(
|
|
2538
2609
|
'button, [role="button"], input[type="submit"], input[type="button"]'
|
|
2539
2610
|
).forEach((btn) => {
|
|
2540
2611
|
const input = btn;
|
|
@@ -2545,7 +2616,7 @@ function extractInteractiveElements() {
|
|
|
2545
2616
|
...buildBaseMetadata(btn)
|
|
2546
2617
|
});
|
|
2547
2618
|
});
|
|
2548
|
-
|
|
2619
|
+
deepQuerySelectorAll("a[href]").forEach((link) => {
|
|
2549
2620
|
const anchor = link;
|
|
2550
2621
|
const text = anchor.textContent?.trim();
|
|
2551
2622
|
if (!text || anchor.getAttribute("href")?.startsWith("#")) return;
|
|
@@ -2559,7 +2630,7 @@ function extractInteractiveElements() {
|
|
|
2559
2630
|
context
|
|
2560
2631
|
});
|
|
2561
2632
|
});
|
|
2562
|
-
|
|
2633
|
+
deepQuerySelectorAll(
|
|
2563
2634
|
'input:not([type="hidden"]):not([type="submit"]):not([type="button"]), select, textarea'
|
|
2564
2635
|
).forEach((input) => {
|
|
2565
2636
|
const element = input;
|
|
@@ -2587,7 +2658,8 @@ function extractForms() {
|
|
|
2587
2658
|
}
|
|
2588
2659
|
return el instanceof HTMLInputElement && (el.type === "submit" || el.type === "image") && el.form === form;
|
|
2589
2660
|
}
|
|
2590
|
-
|
|
2661
|
+
deepQuerySelectorAll("form").forEach((formEl) => {
|
|
2662
|
+
const form = formEl;
|
|
2591
2663
|
const fields = [];
|
|
2592
2664
|
form.querySelectorAll(
|
|
2593
2665
|
"input:not([type='hidden']):not([type='submit']):not([type='button']):not([type='image']), select, textarea"
|
|
@@ -2643,7 +2715,7 @@ function extractLandmarks() {
|
|
|
2643
2715
|
"dialog, [role='dialog'], [role='alertdialog']"
|
|
2644
2716
|
];
|
|
2645
2717
|
selectors.forEach((selector) => {
|
|
2646
|
-
|
|
2718
|
+
deepQuerySelectorAll(selector).forEach((el) => {
|
|
2647
2719
|
const tag = el.tagName.toLowerCase();
|
|
2648
2720
|
const role = el.getAttribute("role") || (tag === "header" ? "banner" : tag === "nav" ? "navigation" : tag === "main" ? "main" : tag === "aside" ? "complementary" : tag === "footer" ? "contentinfo" : tag === "article" ? "article" : tag === "section" ? "region" : tag === "dialog" ? "dialog" : "generic");
|
|
2649
2721
|
landmarks.push({
|
|
@@ -2784,9 +2856,12 @@ function getVisiblePageText() {
|
|
|
2784
2856
|
function vesselExtractContent() {
|
|
2785
2857
|
const extractStructuredContent = (article) => {
|
|
2786
2858
|
activeOverlays = detectOverlays();
|
|
2859
|
+
const readabilityText = article?.textContent || "";
|
|
2860
|
+
const visibleText = getVisiblePageText();
|
|
2861
|
+
const content = readabilityText.length > visibleText.length * 0.3 ? readabilityText : visibleText;
|
|
2787
2862
|
return {
|
|
2788
2863
|
title: article?.title || document.title,
|
|
2789
|
-
content
|
|
2864
|
+
content,
|
|
2790
2865
|
htmlContent: article?.content || "",
|
|
2791
2866
|
byline: article?.byline || "",
|
|
2792
2867
|
excerpt: article?.excerpt || "",
|
|
@@ -2813,6 +2888,9 @@ function vesselExtractContent() {
|
|
|
2813
2888
|
Object.keys(elementSelectors).forEach(
|
|
2814
2889
|
(key) => delete elementSelectors[key]
|
|
2815
2890
|
);
|
|
2891
|
+
Object.keys(indexedElementRefs).forEach(
|
|
2892
|
+
(key) => delete indexedElementRefs[key]
|
|
2893
|
+
);
|
|
2816
2894
|
const documentClone = document.cloneNode(true);
|
|
2817
2895
|
const reader = new readabilityExports.Readability(documentClone);
|
|
2818
2896
|
const article = reader.parse();
|
|
@@ -2825,9 +2903,43 @@ function vesselExtractContent() {
|
|
|
2825
2903
|
function resolveElementSelector(index) {
|
|
2826
2904
|
return elementSelectors[index] || null;
|
|
2827
2905
|
}
|
|
2906
|
+
function interactByIndex(index, action, value) {
|
|
2907
|
+
const el = indexedElementRefs[index];
|
|
2908
|
+
if (!el || !(el instanceof HTMLElement)) {
|
|
2909
|
+
return "Error[stale-index]: Element not found — the page may have changed. Call read_page to refresh.";
|
|
2910
|
+
}
|
|
2911
|
+
if (action === "click") {
|
|
2912
|
+
el.focus();
|
|
2913
|
+
el.click();
|
|
2914
|
+
return "Clicked: " + (el.getAttribute("aria-label") || el.textContent?.trim().slice(0, 60) || el.tagName.toLowerCase());
|
|
2915
|
+
}
|
|
2916
|
+
if (action === "focus") {
|
|
2917
|
+
el.focus();
|
|
2918
|
+
return "Focused: " + (el.getAttribute("aria-label") || el.textContent?.trim().slice(0, 60) || el.tagName.toLowerCase());
|
|
2919
|
+
}
|
|
2920
|
+
if (action === "value" && value != null) {
|
|
2921
|
+
if (!(el instanceof HTMLInputElement) && !(el instanceof HTMLTextAreaElement) && !(el instanceof HTMLSelectElement)) {
|
|
2922
|
+
return "Error[not-input]: Element is not a text input";
|
|
2923
|
+
}
|
|
2924
|
+
const proto = el instanceof HTMLTextAreaElement ? HTMLTextAreaElement.prototype : el instanceof HTMLSelectElement ? HTMLSelectElement.prototype : HTMLInputElement.prototype;
|
|
2925
|
+
const desc = Object.getOwnPropertyDescriptor(proto, "value");
|
|
2926
|
+
if (desc?.set) {
|
|
2927
|
+
desc.set.call(el, value);
|
|
2928
|
+
} else {
|
|
2929
|
+
el.value = value;
|
|
2930
|
+
}
|
|
2931
|
+
el.focus();
|
|
2932
|
+
el.dispatchEvent(new Event("input", { bubbles: true }));
|
|
2933
|
+
el.dispatchEvent(new Event("change", { bubbles: true }));
|
|
2934
|
+
return "Typed into: " + (el.getAttribute("aria-label") || el.placeholder || el.name || "input");
|
|
2935
|
+
}
|
|
2936
|
+
return "Error: Unknown action";
|
|
2937
|
+
}
|
|
2828
2938
|
electron.contextBridge.exposeInMainWorld("__vessel", {
|
|
2829
2939
|
extractContent: vesselExtractContent,
|
|
2830
2940
|
getElementSelector: resolveElementSelector,
|
|
2941
|
+
interactByIndex,
|
|
2942
|
+
resolveShadowSelector,
|
|
2831
2943
|
notifyHighlightSelection: (text) => {
|
|
2832
2944
|
if (typeof text === "string" && text.trim()) {
|
|
2833
2945
|
electron.ipcRenderer.send("vessel:highlight-selection", text.trim());
|
package/out/preload/index.js
CHANGED
|
@@ -35,6 +35,7 @@ const Channels = {
|
|
|
35
35
|
SIDEBAR_RESIZE: "ui:sidebar-resize",
|
|
36
36
|
SIDEBAR_RESIZE_START: "ui:sidebar-resize-start",
|
|
37
37
|
SIDEBAR_RESIZE_COMMIT: "ui:sidebar-resize-commit",
|
|
38
|
+
SIDEBAR_CONTEXT_MENU: "ui:sidebar-context-menu",
|
|
38
39
|
FOCUS_MODE_TOGGLE: "ui:focus-mode-toggle",
|
|
39
40
|
SETTINGS_VISIBILITY: "ui:settings-visibility",
|
|
40
41
|
// Settings
|
|
@@ -53,6 +54,11 @@ const Channels = {
|
|
|
53
54
|
// Highlights
|
|
54
55
|
HIGHLIGHT_CAPTURE: "highlights:capture",
|
|
55
56
|
HIGHLIGHT_CAPTURE_RESULT: "highlights:capture-result",
|
|
57
|
+
HIGHLIGHT_NAV_COUNT: "highlights:nav-count",
|
|
58
|
+
HIGHLIGHT_NAV_SCROLL: "highlights:nav-scroll",
|
|
59
|
+
HIGHLIGHT_NAV_REMOVE: "highlights:nav-remove",
|
|
60
|
+
HIGHLIGHT_NAV_CLEAR: "highlights:nav-clear",
|
|
61
|
+
SIDEBAR_HIGHLIGHT_ACTION: "highlights:sidebar-action",
|
|
56
62
|
// DevTools panel
|
|
57
63
|
DEVTOOLS_PANEL_TOGGLE: "devtools-panel:toggle",
|
|
58
64
|
DEVTOOLS_PANEL_STATE: "devtools-panel:state",
|
|
@@ -120,6 +126,15 @@ const api = {
|
|
|
120
126
|
const handler = (_, result) => cb(result);
|
|
121
127
|
electron.ipcRenderer.on(Channels.HIGHLIGHT_CAPTURE_RESULT, handler);
|
|
122
128
|
return () => electron.ipcRenderer.removeListener(Channels.HIGHLIGHT_CAPTURE_RESULT, handler);
|
|
129
|
+
},
|
|
130
|
+
getCount: () => electron.ipcRenderer.invoke(Channels.HIGHLIGHT_NAV_COUNT),
|
|
131
|
+
scrollTo: (index) => electron.ipcRenderer.invoke(Channels.HIGHLIGHT_NAV_SCROLL, index),
|
|
132
|
+
remove: (index) => electron.ipcRenderer.invoke(Channels.HIGHLIGHT_NAV_REMOVE, index),
|
|
133
|
+
clearAll: () => electron.ipcRenderer.invoke(Channels.HIGHLIGHT_NAV_CLEAR),
|
|
134
|
+
onSidebarAction: (cb) => {
|
|
135
|
+
const handler = (_, action) => cb(action);
|
|
136
|
+
electron.ipcRenderer.on(Channels.SIDEBAR_HIGHLIGHT_ACTION, handler);
|
|
137
|
+
return () => electron.ipcRenderer.removeListener(Channels.SIDEBAR_HIGHLIGHT_ACTION, handler);
|
|
123
138
|
}
|
|
124
139
|
},
|
|
125
140
|
ui: {
|
|
@@ -127,6 +142,11 @@ const api = {
|
|
|
127
142
|
startSidebarResize: () => electron.ipcRenderer.invoke(Channels.SIDEBAR_RESIZE_START),
|
|
128
143
|
resizeSidebar: (width) => electron.ipcRenderer.invoke(Channels.SIDEBAR_RESIZE, width),
|
|
129
144
|
commitSidebarResize: () => electron.ipcRenderer.invoke(Channels.SIDEBAR_RESIZE_COMMIT),
|
|
145
|
+
onSidebarContextMenu: (cb) => {
|
|
146
|
+
const handler = (_, position) => cb(position);
|
|
147
|
+
electron.ipcRenderer.on(Channels.SIDEBAR_CONTEXT_MENU, handler);
|
|
148
|
+
return () => electron.ipcRenderer.removeListener(Channels.SIDEBAR_CONTEXT_MENU, handler);
|
|
149
|
+
},
|
|
130
150
|
toggleFocusMode: () => electron.ipcRenderer.invoke(Channels.FOCUS_MODE_TOGGLE),
|
|
131
151
|
setSettingsVisibility: (open) => electron.ipcRenderer.invoke(Channels.SETTINGS_VISIBILITY, open)
|
|
132
152
|
},
|
|
@@ -2187,6 +2187,178 @@
|
|
|
2187
2187
|
margin: 14px 0;
|
|
2188
2188
|
}
|
|
2189
2189
|
|
|
2190
|
+
.markdown-content table {
|
|
2191
|
+
width: 100%;
|
|
2192
|
+
border-collapse: collapse;
|
|
2193
|
+
margin: 0 0 10px;
|
|
2194
|
+
font-size: 12.5px;
|
|
2195
|
+
line-height: 1.5;
|
|
2196
|
+
}
|
|
2197
|
+
|
|
2198
|
+
.markdown-content thead {
|
|
2199
|
+
border-bottom: 2px solid rgba(255, 255, 255, 0.12);
|
|
2200
|
+
}
|
|
2201
|
+
|
|
2202
|
+
.markdown-content th {
|
|
2203
|
+
text-align: left;
|
|
2204
|
+
font-weight: 600;
|
|
2205
|
+
color: var(--text-primary);
|
|
2206
|
+
padding: 6px 10px;
|
|
2207
|
+
}
|
|
2208
|
+
|
|
2209
|
+
.markdown-content td {
|
|
2210
|
+
padding: 5px 10px;
|
|
2211
|
+
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
|
|
2212
|
+
color: var(--text-secondary);
|
|
2213
|
+
}
|
|
2214
|
+
|
|
2215
|
+
.markdown-content tbody tr:hover {
|
|
2216
|
+
background: rgba(255, 255, 255, 0.03);
|
|
2217
|
+
}
|
|
2218
|
+
|
|
2219
|
+
|
|
2220
|
+
/* ═══════════════════════════════════════
|
|
2221
|
+
Tool call action chips
|
|
2222
|
+
═══════════════════════════════════════ */
|
|
2223
|
+
|
|
2224
|
+
.tool-chip {
|
|
2225
|
+
display: flex;
|
|
2226
|
+
align-items: center;
|
|
2227
|
+
gap: 6px;
|
|
2228
|
+
padding: 3px 10px 3px 7px;
|
|
2229
|
+
margin: 3px 0;
|
|
2230
|
+
background: rgba(255, 255, 255, 0.04);
|
|
2231
|
+
border-left: 2px solid rgba(196, 160, 90, 0.4);
|
|
2232
|
+
border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
|
|
2233
|
+
font-size: 11.5px;
|
|
2234
|
+
line-height: 1.5;
|
|
2235
|
+
color: var(--text-muted);
|
|
2236
|
+
font-family: var(--font-mono);
|
|
2237
|
+
transition: background var(--duration-fast) var(--ease-in-out);
|
|
2238
|
+
}
|
|
2239
|
+
|
|
2240
|
+
.tool-chip:hover {
|
|
2241
|
+
background: rgba(255, 255, 255, 0.07);
|
|
2242
|
+
}
|
|
2243
|
+
|
|
2244
|
+
.tool-chip-icon {
|
|
2245
|
+
flex-shrink: 0;
|
|
2246
|
+
width: 16px;
|
|
2247
|
+
text-align: center;
|
|
2248
|
+
font-size: 12px;
|
|
2249
|
+
color: rgba(196, 160, 90, 0.7);
|
|
2250
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
2251
|
+
}
|
|
2252
|
+
|
|
2253
|
+
.tool-chip-name {
|
|
2254
|
+
color: var(--text-secondary);
|
|
2255
|
+
font-weight: 500;
|
|
2256
|
+
letter-spacing: 0.01em;
|
|
2257
|
+
}
|
|
2258
|
+
|
|
2259
|
+
.tool-chip-args {
|
|
2260
|
+
color: var(--text-muted);
|
|
2261
|
+
opacity: 0.7;
|
|
2262
|
+
font-weight: 400;
|
|
2263
|
+
max-width: 200px;
|
|
2264
|
+
overflow: hidden;
|
|
2265
|
+
text-overflow: ellipsis;
|
|
2266
|
+
white-space: nowrap;
|
|
2267
|
+
}
|
|
2268
|
+
|
|
2269
|
+
.tool-chip-args::before {
|
|
2270
|
+
content: "·";
|
|
2271
|
+
margin-right: 5px;
|
|
2272
|
+
opacity: 0.4;
|
|
2273
|
+
}
|
|
2274
|
+
|
|
2275
|
+
|
|
2276
|
+
/* ═══════════════════════════════════════
|
|
2277
|
+
Inline approval prompts (chat tab)
|
|
2278
|
+
═══════════════════════════════════════ */
|
|
2279
|
+
|
|
2280
|
+
.chat-approval {
|
|
2281
|
+
display: flex;
|
|
2282
|
+
gap: 10px;
|
|
2283
|
+
margin: 8px 14px;
|
|
2284
|
+
padding: 10px 12px;
|
|
2285
|
+
background: rgba(224, 180, 80, 0.08);
|
|
2286
|
+
border: 1px solid rgba(224, 180, 80, 0.2);
|
|
2287
|
+
border-radius: var(--radius-md);
|
|
2288
|
+
animation: approval-appear 0.25s var(--ease-out-back);
|
|
2289
|
+
}
|
|
2290
|
+
|
|
2291
|
+
@keyframes approval-appear {
|
|
2292
|
+
from { opacity: 0; transform: translateY(6px); }
|
|
2293
|
+
to { opacity: 1; transform: translateY(0); }
|
|
2294
|
+
}
|
|
2295
|
+
|
|
2296
|
+
.chat-approval-icon {
|
|
2297
|
+
flex-shrink: 0;
|
|
2298
|
+
color: #e0b450;
|
|
2299
|
+
margin-top: 1px;
|
|
2300
|
+
}
|
|
2301
|
+
|
|
2302
|
+
.chat-approval-body {
|
|
2303
|
+
flex: 1;
|
|
2304
|
+
min-width: 0;
|
|
2305
|
+
}
|
|
2306
|
+
|
|
2307
|
+
.chat-approval-title {
|
|
2308
|
+
font-size: 12.5px;
|
|
2309
|
+
color: var(--text-primary);
|
|
2310
|
+
margin-bottom: 2px;
|
|
2311
|
+
}
|
|
2312
|
+
|
|
2313
|
+
.chat-approval-detail {
|
|
2314
|
+
font-size: 11.5px;
|
|
2315
|
+
color: var(--text-muted);
|
|
2316
|
+
overflow: hidden;
|
|
2317
|
+
text-overflow: ellipsis;
|
|
2318
|
+
white-space: nowrap;
|
|
2319
|
+
}
|
|
2320
|
+
|
|
2321
|
+
.chat-approval-actions {
|
|
2322
|
+
display: flex;
|
|
2323
|
+
gap: 6px;
|
|
2324
|
+
margin-top: 8px;
|
|
2325
|
+
}
|
|
2326
|
+
|
|
2327
|
+
.chat-approval-btn {
|
|
2328
|
+
font-size: 11.5px;
|
|
2329
|
+
padding: 4px 14px;
|
|
2330
|
+
border-radius: var(--radius-sm);
|
|
2331
|
+
border: none;
|
|
2332
|
+
cursor: pointer;
|
|
2333
|
+
font-weight: 500;
|
|
2334
|
+
transition:
|
|
2335
|
+
background var(--duration-fast) var(--ease-in-out),
|
|
2336
|
+
transform var(--duration-fast) var(--ease-out-back);
|
|
2337
|
+
}
|
|
2338
|
+
|
|
2339
|
+
.chat-approval-btn:active {
|
|
2340
|
+
transform: scale(0.95);
|
|
2341
|
+
}
|
|
2342
|
+
|
|
2343
|
+
.chat-approval-approve {
|
|
2344
|
+
background: rgba(224, 180, 80, 0.18);
|
|
2345
|
+
color: #e0c070;
|
|
2346
|
+
}
|
|
2347
|
+
|
|
2348
|
+
.chat-approval-approve:hover {
|
|
2349
|
+
background: rgba(224, 180, 80, 0.28);
|
|
2350
|
+
}
|
|
2351
|
+
|
|
2352
|
+
.chat-approval-reject {
|
|
2353
|
+
background: rgba(255, 255, 255, 0.06);
|
|
2354
|
+
color: var(--text-muted);
|
|
2355
|
+
}
|
|
2356
|
+
|
|
2357
|
+
.chat-approval-reject:hover {
|
|
2358
|
+
background: rgba(255, 255, 255, 0.1);
|
|
2359
|
+
color: var(--text-secondary);
|
|
2360
|
+
}
|
|
2361
|
+
|
|
2190
2362
|
|
|
2191
2363
|
/* ═══════════════════════════════════════
|
|
2192
2364
|
Thinking & streaming states
|
|
@@ -2361,6 +2533,101 @@
|
|
|
2361
2533
|
border-color: var(--border-visible);
|
|
2362
2534
|
}
|
|
2363
2535
|
|
|
2536
|
+
/* ═══════════════════════════════════════
|
|
2537
|
+
Highlight navigation bar
|
|
2538
|
+
═══════════════════════════════════════ */
|
|
2539
|
+
|
|
2540
|
+
.highlight-nav {
|
|
2541
|
+
display: flex;
|
|
2542
|
+
align-items: center;
|
|
2543
|
+
justify-content: flex-end;
|
|
2544
|
+
gap: 2px;
|
|
2545
|
+
padding: 4px 14px;
|
|
2546
|
+
flex-shrink: 0;
|
|
2547
|
+
}
|
|
2548
|
+
|
|
2549
|
+
.highlight-nav-btn {
|
|
2550
|
+
display: inline-flex;
|
|
2551
|
+
align-items: center;
|
|
2552
|
+
justify-content: center;
|
|
2553
|
+
width: 24px;
|
|
2554
|
+
height: 24px;
|
|
2555
|
+
padding: 0;
|
|
2556
|
+
color: var(--text-muted);
|
|
2557
|
+
background: transparent;
|
|
2558
|
+
border: 1px solid transparent;
|
|
2559
|
+
border-radius: var(--radius-sm);
|
|
2560
|
+
cursor: pointer;
|
|
2561
|
+
transition: color var(--duration-fast) var(--ease-in-out),
|
|
2562
|
+
background var(--duration-fast) var(--ease-in-out);
|
|
2563
|
+
}
|
|
2564
|
+
|
|
2565
|
+
.highlight-nav-btn:hover:not(:disabled) {
|
|
2566
|
+
color: var(--text-primary);
|
|
2567
|
+
background: var(--bg-tertiary);
|
|
2568
|
+
}
|
|
2569
|
+
|
|
2570
|
+
.highlight-nav-btn:disabled {
|
|
2571
|
+
opacity: 0.3;
|
|
2572
|
+
cursor: default;
|
|
2573
|
+
}
|
|
2574
|
+
|
|
2575
|
+
.highlight-nav-label {
|
|
2576
|
+
display: inline-flex;
|
|
2577
|
+
align-items: center;
|
|
2578
|
+
gap: 5px;
|
|
2579
|
+
padding: 3px 10px;
|
|
2580
|
+
font-size: 11px;
|
|
2581
|
+
font-weight: 500;
|
|
2582
|
+
color: rgba(196, 160, 90, 0.85);
|
|
2583
|
+
background: rgba(196, 160, 90, 0.08);
|
|
2584
|
+
border: 1px solid rgba(196, 160, 90, 0.2);
|
|
2585
|
+
border-radius: var(--radius-md);
|
|
2586
|
+
cursor: pointer;
|
|
2587
|
+
transition: background var(--duration-fast) var(--ease-in-out),
|
|
2588
|
+
border-color var(--duration-fast) var(--ease-in-out);
|
|
2589
|
+
white-space: nowrap;
|
|
2590
|
+
}
|
|
2591
|
+
|
|
2592
|
+
.highlight-nav-label:hover {
|
|
2593
|
+
background: rgba(196, 160, 90, 0.14);
|
|
2594
|
+
border-color: rgba(196, 160, 90, 0.35);
|
|
2595
|
+
}
|
|
2596
|
+
|
|
2597
|
+
.hl-context-menu {
|
|
2598
|
+
position: fixed;
|
|
2599
|
+
z-index: 9999;
|
|
2600
|
+
min-width: 160px;
|
|
2601
|
+
padding: 4px 0;
|
|
2602
|
+
background: var(--bg-secondary);
|
|
2603
|
+
border: 1px solid var(--border-visible);
|
|
2604
|
+
border-radius: var(--radius-md);
|
|
2605
|
+
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);
|
|
2606
|
+
}
|
|
2607
|
+
|
|
2608
|
+
.hl-context-item {
|
|
2609
|
+
display: block;
|
|
2610
|
+
width: 100%;
|
|
2611
|
+
padding: 6px 12px;
|
|
2612
|
+
font-size: 11.5px;
|
|
2613
|
+
color: var(--text-secondary);
|
|
2614
|
+
background: transparent;
|
|
2615
|
+
border: none;
|
|
2616
|
+
cursor: pointer;
|
|
2617
|
+
text-align: left;
|
|
2618
|
+
transition: background var(--duration-fast) var(--ease-in-out);
|
|
2619
|
+
}
|
|
2620
|
+
|
|
2621
|
+
.hl-context-item:hover {
|
|
2622
|
+
background: rgba(255, 255, 255, 0.06);
|
|
2623
|
+
color: var(--text-primary);
|
|
2624
|
+
}
|
|
2625
|
+
|
|
2626
|
+
.hl-context-danger:hover {
|
|
2627
|
+
color: #e06060;
|
|
2628
|
+
background: rgba(224, 96, 96, 0.08);
|
|
2629
|
+
}
|
|
2630
|
+
|
|
2364
2631
|
.sidebar-input-area {
|
|
2365
2632
|
display: flex;
|
|
2366
2633
|
gap: 6px;
|