@quanta-intellect/vessel-browser 0.1.53 → 0.1.58

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.
@@ -2143,6 +2143,105 @@ const elementSelectors = {};
2143
2143
  let indexedElements = /* @__PURE__ */ new WeakMap();
2144
2144
  const indexedElementRefs = {};
2145
2145
  let activeOverlays = [];
2146
+ let pageDiffMutationTimer = null;
2147
+ let pageDiffActivityThrottleTimer = null;
2148
+ let lastPageDiffSignature = "";
2149
+ const PAGE_DIFF_ACTIVITY_THROTTLE_MS = 350;
2150
+ const PAGE_DIFF_MUTATION_DEBOUNCE_MS = 1200;
2151
+ function normalizeSignatureText(value) {
2152
+ return (value || "").replace(/\s+/g, " ").trim();
2153
+ }
2154
+ function getPageDiffSignature() {
2155
+ const title = normalizeSignatureText(document.title);
2156
+ const headings = Array.from(document.querySelectorAll("h1, h2, h3")).slice(0, 8).map((el) => normalizeSignatureText(el.textContent)).filter(Boolean).join(" | ");
2157
+ const mainRoot = document.querySelector("main, article, [role='main']") || document.body;
2158
+ const visibleText = normalizeSignatureText(
2159
+ mainRoot instanceof HTMLElement ? mainRoot.innerText : document.body?.innerText || ""
2160
+ ).slice(0, 1200);
2161
+ return [window.location.href, title, headings, visibleText].join("\n");
2162
+ }
2163
+ function asElement(node) {
2164
+ if (node instanceof Element) return node;
2165
+ return node?.parentElement || null;
2166
+ }
2167
+ function isVesselOwnedNode(node) {
2168
+ const el = asElement(node);
2169
+ return !!el?.closest?.("[data-vessel-highlight], .__vessel-highlight-label");
2170
+ }
2171
+ function shouldIgnorePageDiffMutation(mutation) {
2172
+ if (mutation.type === "attributes") {
2173
+ return isVesselOwnedNode(mutation.target);
2174
+ }
2175
+ if (mutation.type === "characterData") {
2176
+ return isVesselOwnedNode(mutation.target);
2177
+ }
2178
+ if (mutation.type === "childList") {
2179
+ const added = Array.from(mutation.addedNodes);
2180
+ const removed = Array.from(mutation.removedNodes);
2181
+ return [...added, ...removed].every((node) => isVesselOwnedNode(node));
2182
+ }
2183
+ return false;
2184
+ }
2185
+ function emitPageDiffDirty() {
2186
+ const nextSignature = getPageDiffSignature();
2187
+ if (!nextSignature || nextSignature === lastPageDiffSignature) return;
2188
+ lastPageDiffSignature = nextSignature;
2189
+ electron.ipcRenderer.send("page:diff-dirty");
2190
+ }
2191
+ function notifyPageDiffActivity() {
2192
+ if (pageDiffActivityThrottleTimer) return;
2193
+ electron.ipcRenderer.send("page:diff-activity");
2194
+ pageDiffActivityThrottleTimer = setTimeout(() => {
2195
+ pageDiffActivityThrottleTimer = null;
2196
+ }, PAGE_DIFF_ACTIVITY_THROTTLE_MS);
2197
+ }
2198
+ function startPageDiffObserver() {
2199
+ if (typeof MutationObserver === "undefined") return;
2200
+ if (!document.documentElement) return;
2201
+ lastPageDiffSignature = getPageDiffSignature();
2202
+ const observer = new MutationObserver((mutations) => {
2203
+ if (mutations.every((mutation) => shouldIgnorePageDiffMutation(mutation))) {
2204
+ return;
2205
+ }
2206
+ notifyPageDiffActivity();
2207
+ if (pageDiffMutationTimer) {
2208
+ clearTimeout(pageDiffMutationTimer);
2209
+ }
2210
+ pageDiffMutationTimer = setTimeout(() => {
2211
+ pageDiffMutationTimer = null;
2212
+ emitPageDiffDirty();
2213
+ }, PAGE_DIFF_MUTATION_DEBOUNCE_MS);
2214
+ });
2215
+ observer.observe(document.documentElement, {
2216
+ subtree: true,
2217
+ childList: true,
2218
+ characterData: true,
2219
+ attributes: true,
2220
+ attributeFilter: [
2221
+ "class",
2222
+ "style",
2223
+ "hidden",
2224
+ "aria-hidden",
2225
+ "aria-expanded",
2226
+ "aria-selected",
2227
+ "aria-checked",
2228
+ "aria-label",
2229
+ "title",
2230
+ "open"
2231
+ ]
2232
+ });
2233
+ window.addEventListener("beforeunload", () => {
2234
+ observer.disconnect();
2235
+ if (pageDiffActivityThrottleTimer) {
2236
+ clearTimeout(pageDiffActivityThrottleTimer);
2237
+ pageDiffActivityThrottleTimer = null;
2238
+ }
2239
+ if (pageDiffMutationTimer) {
2240
+ clearTimeout(pageDiffMutationTimer);
2241
+ pageDiffMutationTimer = null;
2242
+ }
2243
+ });
2244
+ }
2146
2245
  const MAX_SHADOW_HOSTS = 150;
2147
2246
  const MAX_SHADOW_DEPTH = 5;
2148
2247
  const MAX_WALK_ELEMENTS = 1e4;
@@ -3288,3 +3387,14 @@ electron.contextBridge.exposeInMainWorld("__vessel", {
3288
3387
  }
3289
3388
  }
3290
3389
  });
3390
+ if (document.readyState === "loading") {
3391
+ window.addEventListener(
3392
+ "DOMContentLoaded",
3393
+ () => {
3394
+ startPageDiffObserver();
3395
+ },
3396
+ { once: true }
3397
+ );
3398
+ } else {
3399
+ startPageDiffObserver();
3400
+ }
@@ -9,7 +9,9 @@ const Channels = {
9
9
  TAB_BACK: "tab:back",
10
10
  TAB_FORWARD: "tab:forward",
11
11
  TAB_RELOAD: "tab:reload",
12
+ TAB_STATE_GET: "tab:state-get",
12
13
  TAB_STATE_UPDATE: "tab:state-update",
14
+ RENDERER_VIEW_READY: "renderer:view-ready",
13
15
  // AI
14
16
  AI_QUERY: "ai:query",
15
17
  AI_STREAM_START: "ai:stream-start",
@@ -108,7 +110,15 @@ const Channels = {
108
110
  // Window controls
109
111
  WINDOW_MINIMIZE: "window:minimize",
110
112
  WINDOW_MAXIMIZE: "window:maximize",
111
- WINDOW_CLOSE: "window:close"
113
+ WINDOW_CLOSE: "window:close",
114
+ // Autofill
115
+ AUTOFILL_LIST: "autofill:list",
116
+ AUTOFILL_ADD: "autofill:add",
117
+ AUTOFILL_UPDATE: "autofill:update",
118
+ AUTOFILL_DELETE: "autofill:delete",
119
+ AUTOFILL_FILL: "autofill:fill",
120
+ PAGE_CHANGED: "page:changed",
121
+ PAGE_DIFF_GET: "page:diff-get"
112
122
  };
113
123
  const api = {
114
124
  tabs: {
@@ -119,6 +129,7 @@ const api = {
119
129
  back: (id) => electron.ipcRenderer.invoke(Channels.TAB_BACK, id),
120
130
  forward: (id) => electron.ipcRenderer.invoke(Channels.TAB_FORWARD, id),
121
131
  reload: (id) => electron.ipcRenderer.invoke(Channels.TAB_RELOAD, id),
132
+ getState: () => electron.ipcRenderer.invoke(Channels.TAB_STATE_GET),
122
133
  onStateUpdate: (cb) => {
123
134
  const handler = (_, tabs, activeId) => cb(tabs, activeId);
124
135
  electron.ipcRenderer.on(Channels.TAB_STATE_UPDATE, handler);
@@ -210,6 +221,7 @@ const api = {
210
221
  startSidebarResize: () => electron.ipcRenderer.invoke(Channels.SIDEBAR_RESIZE_START),
211
222
  resizeSidebar: (width) => electron.ipcRenderer.invoke(Channels.SIDEBAR_RESIZE, width),
212
223
  commitSidebarResize: () => electron.ipcRenderer.invoke(Channels.SIDEBAR_RESIZE_COMMIT),
224
+ rendererReady: (view) => electron.ipcRenderer.send(Channels.RENDERER_VIEW_READY, view),
213
225
  onSidebarContextMenu: (cb) => {
214
226
  const handler = (_, position) => cb(position);
215
227
  electron.ipcRenderer.on(Channels.SIDEBAR_CONTEXT_MENU, handler);
@@ -330,6 +342,21 @@ const api = {
330
342
  minimize: () => electron.ipcRenderer.invoke(Channels.WINDOW_MINIMIZE),
331
343
  maximize: () => electron.ipcRenderer.invoke(Channels.WINDOW_MAXIMIZE),
332
344
  close: () => electron.ipcRenderer.invoke(Channels.WINDOW_CLOSE)
345
+ },
346
+ autofill: {
347
+ list: () => electron.ipcRenderer.invoke(Channels.AUTOFILL_LIST),
348
+ add: (profile) => electron.ipcRenderer.invoke(Channels.AUTOFILL_ADD, profile),
349
+ update: (id, updates) => electron.ipcRenderer.invoke(Channels.AUTOFILL_UPDATE, id, updates),
350
+ delete: (id) => electron.ipcRenderer.invoke(Channels.AUTOFILL_DELETE, id),
351
+ fill: (profileId) => electron.ipcRenderer.invoke(Channels.AUTOFILL_FILL, profileId)
352
+ },
353
+ pageDiff: {
354
+ onChanged: (cb) => {
355
+ const handler = (_, diff) => cb(diff);
356
+ electron.ipcRenderer.on(Channels.PAGE_CHANGED, handler);
357
+ return () => electron.ipcRenderer.removeListener(Channels.PAGE_CHANGED, handler);
358
+ },
359
+ get: () => electron.ipcRenderer.invoke(Channels.PAGE_DIFF_GET)
333
360
  }
334
361
  };
335
362
  electron.contextBridge.exposeInMainWorld("vessel", api);
@@ -901,6 +901,230 @@
901
901
  box-shadow: 0 0 0 0 rgba(34, 197, 94, 0);
902
902
  }
903
903
  }
904
+
905
+
906
+ /* ═══════════════════════════════════════
907
+ Page diff — "What Changed?" popup
908
+ ═══════════════════════════════════════ */
909
+
910
+ .page-diff-popup {
911
+ position: absolute;
912
+ top: calc(32px + var(--tab-height) + var(--address-bar-height) + 6px);
913
+ left: 50%;
914
+ transform: translateX(-50%);
915
+ width: min(400px, calc(100vw - 28px));
916
+ max-height: min(320px, calc(100vh - 120px));
917
+ display: flex;
918
+ flex-direction: column;
919
+ border: 1px solid rgba(245, 158, 11, 0.2);
920
+ border-radius: var(--radius-lg);
921
+ background: linear-gradient(
922
+ 180deg,
923
+ rgba(50, 50, 54, 0.97),
924
+ rgba(34, 34, 38, 0.97)
925
+ );
926
+ box-shadow:
927
+ 0 4px 12px rgba(0, 0, 0, 0.2),
928
+ 0 16px 40px rgba(0, 0, 0, 0.16);
929
+ backdrop-filter: blur(16px);
930
+ overflow-y: auto;
931
+ z-index: 50;
932
+ animation: page-diff-enter var(--duration-enter) var(--ease-out-expo) both;
933
+ }
934
+
935
+ @keyframes page-diff-enter {
936
+ from {
937
+ opacity: 0;
938
+ transform: translateX(-50%) translateY(-6px) scale(0.97);
939
+ }
940
+ to {
941
+ opacity: 1;
942
+ transform: translateX(-50%) translateY(0) scale(1);
943
+ }
944
+ }
945
+
946
+ .page-diff-popup-header {
947
+ display: flex;
948
+ align-items: center;
949
+ justify-content: space-between;
950
+ padding: 10px 14px;
951
+ border-bottom: 1px solid rgba(245, 158, 11, 0.1);
952
+ color: var(--text-secondary);
953
+ font-size: 11.5px;
954
+ font-weight: 600;
955
+ letter-spacing: 0.01em;
956
+ }
957
+
958
+ .page-diff-popup-header-copy {
959
+ display: flex;
960
+ flex-direction: column;
961
+ gap: 3px;
962
+ }
963
+
964
+ .page-diff-burst-meta {
965
+ color: var(--text-muted);
966
+ font-size: 10.5px;
967
+ font-weight: 500;
968
+ }
969
+
970
+ .page-diff-popup-close {
971
+ width: 22px;
972
+ height: 22px;
973
+ display: flex;
974
+ align-items: center;
975
+ justify-content: center;
976
+ border-radius: var(--radius-sm);
977
+ border: none;
978
+ background: transparent;
979
+ color: var(--text-muted);
980
+ font-size: 16px;
981
+ cursor: pointer;
982
+ transition:
983
+ background var(--duration-fast) var(--ease-in-out),
984
+ color var(--duration-fast) var(--ease-in-out);
985
+ }
986
+
987
+ .page-diff-popup-close:hover {
988
+ background: rgba(255, 255, 255, 0.06);
989
+ color: var(--text-primary);
990
+ }
991
+
992
+ .page-diff-burst-history {
993
+ display: flex;
994
+ flex-direction: column;
995
+ gap: 6px;
996
+ padding: 10px 14px;
997
+ border-bottom: 1px solid rgba(255, 255, 255, 0.05);
998
+ background: rgba(255, 255, 255, 0.02);
999
+ }
1000
+
1001
+ .page-diff-burst-history-label {
1002
+ color: var(--text-muted);
1003
+ font-size: 10.5px;
1004
+ font-weight: 700;
1005
+ letter-spacing: 0.04em;
1006
+ text-transform: uppercase;
1007
+ }
1008
+
1009
+ .page-diff-burst-row {
1010
+ display: grid;
1011
+ grid-template-columns: 60px 1fr;
1012
+ gap: 8px;
1013
+ align-items: start;
1014
+ }
1015
+
1016
+ .page-diff-burst-time {
1017
+ color: var(--text-muted);
1018
+ font-size: 11px;
1019
+ }
1020
+
1021
+ .page-diff-burst-summary {
1022
+ color: var(--text-secondary);
1023
+ font-size: 11.5px;
1024
+ line-height: 1.4;
1025
+ word-break: break-word;
1026
+ }
1027
+
1028
+ .page-diff-item {
1029
+ display: flex;
1030
+ flex-direction: column;
1031
+ align-items: stretch;
1032
+ gap: 8px;
1033
+ padding: 12px 14px;
1034
+ border-bottom: 1px solid rgba(255, 255, 255, 0.03);
1035
+ }
1036
+
1037
+ .page-diff-item:last-child {
1038
+ border-bottom: none;
1039
+ }
1040
+
1041
+ .page-diff-item-header {
1042
+ display: flex;
1043
+ flex-direction: column;
1044
+ gap: 4px;
1045
+ }
1046
+
1047
+ .page-diff-section {
1048
+ align-self: flex-start;
1049
+ padding: 2px 6px;
1050
+ border-radius: var(--radius-sm);
1051
+ background: rgba(255, 255, 255, 0.05);
1052
+ color: var(--text-muted);
1053
+ font-size: 10px;
1054
+ font-weight: 600;
1055
+ text-transform: uppercase;
1056
+ letter-spacing: 0.04em;
1057
+ }
1058
+
1059
+ .page-diff-summary {
1060
+ color: var(--text-secondary);
1061
+ font-size: 12px;
1062
+ line-height: 1.45;
1063
+ word-break: break-word;
1064
+ }
1065
+
1066
+ .page-diff-snippets {
1067
+ display: grid;
1068
+ gap: 6px;
1069
+ }
1070
+
1071
+ .page-diff-snippet {
1072
+ display: flex;
1073
+ flex-direction: column;
1074
+ gap: 3px;
1075
+ padding: 8px 10px;
1076
+ border-radius: var(--radius-md);
1077
+ background: rgba(255, 255, 255, 0.04);
1078
+ }
1079
+
1080
+ .page-diff-snippet-label,
1081
+ .page-diff-list-label {
1082
+ color: var(--text-muted);
1083
+ font-size: 10.5px;
1084
+ font-weight: 700;
1085
+ letter-spacing: 0.04em;
1086
+ text-transform: uppercase;
1087
+ }
1088
+
1089
+ .page-diff-snippet-text {
1090
+ color: var(--text-primary);
1091
+ font-size: 12px;
1092
+ line-height: 1.45;
1093
+ }
1094
+
1095
+ .page-diff-list-group {
1096
+ display: flex;
1097
+ flex-direction: column;
1098
+ gap: 4px;
1099
+ }
1100
+
1101
+ .page-diff-list {
1102
+ margin: 0;
1103
+ padding-left: 18px;
1104
+ color: var(--text-secondary);
1105
+ font-size: 12px;
1106
+ line-height: 1.45;
1107
+ }
1108
+
1109
+ .page-diff-list li + li {
1110
+ margin-top: 4px;
1111
+ }
1112
+
1113
+ .page-diff-added .page-diff-section {
1114
+ background: rgba(34, 197, 94, 0.1);
1115
+ color: #4ade80;
1116
+ }
1117
+
1118
+ .page-diff-removed .page-diff-section {
1119
+ background: rgba(239, 68, 68, 0.1);
1120
+ color: #f87171;
1121
+ }
1122
+
1123
+ .page-diff-changed .page-diff-section,
1124
+ .page-diff-modified .page-diff-section {
1125
+ background: rgba(245, 158, 11, 0.1);
1126
+ color: #fbbf24;
1127
+ }
904
1128
  /* ═══════════════════════════════════════
905
1129
  Command bar overlay — cinematic entrance
906
1130
  ═══════════════════════════════════════ */
@@ -1287,7 +1511,7 @@
1287
1511
 
1288
1512
  .sidebar-tab {
1289
1513
  position: relative;
1290
- padding: 9px 12px 10px;
1514
+ padding: 9px 8px 10px;
1291
1515
  font-size: 11.5px;
1292
1516
  white-space: nowrap;
1293
1517
  flex-shrink: 0;
@@ -4543,6 +4767,7 @@ button:active:not(:disabled) {
4543
4767
 
4544
4768
  .chrome {
4545
4769
  position: relative;
4770
+ -webkit-app-region: no-drag;
4546
4771
  }
4547
4772
 
4548
4773
  .loading-bar {