sentienceapi 0.90.6 → 0.90.10

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.
Files changed (43) hide show
  1. package/README.md +81 -0
  2. package/dist/index.d.ts +1 -0
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +3 -1
  5. package/dist/index.js.map +1 -1
  6. package/dist/textSearch.d.ts +64 -0
  7. package/dist/textSearch.d.ts.map +1 -0
  8. package/dist/textSearch.js +87 -0
  9. package/dist/textSearch.js.map +1 -0
  10. package/dist/tracing/cloud-sink.d.ts +4 -0
  11. package/dist/tracing/cloud-sink.d.ts.map +1 -1
  12. package/dist/tracing/cloud-sink.js +15 -0
  13. package/dist/tracing/cloud-sink.js.map +1 -1
  14. package/dist/tracing/index-schema.d.ts +182 -0
  15. package/dist/tracing/index-schema.d.ts.map +1 -0
  16. package/dist/tracing/index-schema.js +150 -0
  17. package/dist/tracing/index-schema.js.map +1 -0
  18. package/dist/tracing/indexer.d.ts +17 -0
  19. package/dist/tracing/indexer.d.ts.map +1 -0
  20. package/dist/tracing/indexer.js +282 -0
  21. package/dist/tracing/indexer.js.map +1 -0
  22. package/dist/tracing/jsonl-sink.d.ts +4 -0
  23. package/dist/tracing/jsonl-sink.d.ts.map +1 -1
  24. package/dist/tracing/jsonl-sink.js +15 -0
  25. package/dist/tracing/jsonl-sink.js.map +1 -1
  26. package/dist/tracing/tracer-factory.d.ts +11 -5
  27. package/dist/tracing/tracer-factory.d.ts.map +1 -1
  28. package/dist/tracing/tracer-factory.js +16 -7
  29. package/dist/tracing/tracer-factory.js.map +1 -1
  30. package/dist/types.d.ts +98 -0
  31. package/dist/types.d.ts.map +1 -1
  32. package/package.json +1 -1
  33. package/src/extension/background.js +222 -52
  34. package/src/extension/content.js +285 -9
  35. package/src/extension/injected_api.js +1224 -189
  36. package/src/extension/manifest.json +10 -4
  37. package/src/extension/pkg/README.md +163 -2
  38. package/src/extension/pkg/sentience_core.d.ts +9 -0
  39. package/src/extension/pkg/sentience_core.js +16 -0
  40. package/src/extension/pkg/sentience_core_bg.wasm +0 -0
  41. package/src/extension/pkg/sentience_core_bg.wasm.d.ts +1 -0
  42. package/src/extension/release.json +115 -0
  43. package/src/extension/test-content.js +4 -0
@@ -1,22 +1,298 @@
1
- // content.js - ISOLATED WORLD
2
- console.log('[Sentience] Bridge loaded.');
1
+ // content.js - ISOLATED WORLD (Bridge between Main World and Background)
2
+ console.log('[Sentience Bridge] Loaded.');
3
3
 
4
- // 1. Pass Extension ID to Main World (So WASM knows where to load from)
4
+ // Detect if we're in a child frame (for iframe support)
5
+ const isChildFrame = window !== window.top;
6
+ if (isChildFrame) {
7
+ console.log('[Sentience Bridge] Running in child frame:', window.location.href);
8
+ }
9
+
10
+ // 1. Pass Extension ID to Main World (So API knows where to find resources)
5
11
  document.documentElement.dataset.sentienceExtensionId = chrome.runtime.id;
6
12
 
7
- // 2. Proxy for Screenshots (The only thing Isolated World needs to do)
13
+ // 2. Message Router - Handles all communication between page and background
8
14
  window.addEventListener('message', (event) => {
9
15
  // Security check: only accept messages from same window
10
- if (event.source !== window || event.data.type !== 'SENTIENCE_SCREENSHOT_REQUEST') return;
16
+ if (event.source !== window) return;
17
+
18
+ // Route different message types
19
+ switch (event.data.type) {
20
+ case 'SENTIENCE_SCREENSHOT_REQUEST':
21
+ handleScreenshotRequest(event.data);
22
+ break;
23
+
24
+ case 'SENTIENCE_SNAPSHOT_REQUEST':
25
+ handleSnapshotRequest(event.data);
26
+ break;
27
+
28
+ case 'SENTIENCE_SHOW_OVERLAY':
29
+ handleShowOverlay(event.data);
30
+ break;
31
+
32
+ case 'SENTIENCE_CLEAR_OVERLAY':
33
+ handleClearOverlay();
34
+ break;
35
+
36
+ default:
37
+ // Ignore unknown message types
38
+ break;
39
+ }
40
+ });
11
41
 
42
+ /**
43
+ * Handle screenshot requests (existing functionality)
44
+ */
45
+ function handleScreenshotRequest(data) {
12
46
  chrome.runtime.sendMessage(
13
- { action: 'captureScreenshot', options: event.data.options },
47
+ { action: 'captureScreenshot', options: data.options },
14
48
  (response) => {
15
49
  window.postMessage({
16
50
  type: 'SENTIENCE_SCREENSHOT_RESULT',
17
- requestId: event.data.requestId,
18
- screenshot: response?.success ? response.screenshot : null
51
+ requestId: data.requestId,
52
+ screenshot: response?.success ? response.screenshot : null,
53
+ error: response?.error
19
54
  }, '*');
20
55
  }
21
56
  );
22
- });
57
+ }
58
+
59
+ /**
60
+ * Handle snapshot processing requests (NEW!)
61
+ * Sends raw DOM data to background worker for WASM processing
62
+ * Includes timeout protection to prevent extension crashes
63
+ */
64
+ function handleSnapshotRequest(data) {
65
+ const startTime = performance.now();
66
+ const TIMEOUT_MS = 20000; // 20 seconds (longer than injected_api timeout)
67
+ let responded = false;
68
+
69
+ // Timeout protection: if background doesn't respond, send error
70
+ const timeoutId = setTimeout(() => {
71
+ if (!responded) {
72
+ responded = true;
73
+ const duration = performance.now() - startTime;
74
+ console.error(`[Sentience Bridge] ⚠️ WASM processing timeout after ${duration.toFixed(1)}ms`);
75
+ window.postMessage({
76
+ type: 'SENTIENCE_SNAPSHOT_RESULT',
77
+ requestId: data.requestId,
78
+ error: 'WASM processing timeout - background script may be unresponsive',
79
+ duration: duration
80
+ }, '*');
81
+ }
82
+ }, TIMEOUT_MS);
83
+
84
+ try {
85
+ chrome.runtime.sendMessage(
86
+ {
87
+ action: 'processSnapshot',
88
+ rawData: data.rawData,
89
+ options: data.options
90
+ },
91
+ (response) => {
92
+ if (responded) return; // Already responded via timeout
93
+ responded = true;
94
+ clearTimeout(timeoutId);
95
+
96
+ const duration = performance.now() - startTime;
97
+
98
+ // Handle Chrome extension errors (e.g., background script crashed)
99
+ if (chrome.runtime.lastError) {
100
+ console.error('[Sentience Bridge] Chrome runtime error:', chrome.runtime.lastError.message);
101
+ window.postMessage({
102
+ type: 'SENTIENCE_SNAPSHOT_RESULT',
103
+ requestId: data.requestId,
104
+ error: `Chrome runtime error: ${chrome.runtime.lastError.message}`,
105
+ duration: duration
106
+ }, '*');
107
+ return;
108
+ }
109
+
110
+ if (response?.success) {
111
+ console.log(`[Sentience Bridge] ✓ WASM processing complete in ${duration.toFixed(1)}ms`);
112
+ window.postMessage({
113
+ type: 'SENTIENCE_SNAPSHOT_RESULT',
114
+ requestId: data.requestId,
115
+ elements: response.result.elements,
116
+ raw_elements: response.result.raw_elements,
117
+ duration: duration
118
+ }, '*');
119
+ } else {
120
+ console.error('[Sentience Bridge] WASM processing failed:', response?.error);
121
+ window.postMessage({
122
+ type: 'SENTIENCE_SNAPSHOT_RESULT',
123
+ requestId: data.requestId,
124
+ error: response?.error || 'Processing failed',
125
+ duration: duration
126
+ }, '*');
127
+ }
128
+ }
129
+ );
130
+ } catch (error) {
131
+ if (!responded) {
132
+ responded = true;
133
+ clearTimeout(timeoutId);
134
+ const duration = performance.now() - startTime;
135
+ console.error('[Sentience Bridge] Exception sending message:', error);
136
+ window.postMessage({
137
+ type: 'SENTIENCE_SNAPSHOT_RESULT',
138
+ requestId: data.requestId,
139
+ error: `Failed to send message: ${error.message}`,
140
+ duration: duration
141
+ }, '*');
142
+ }
143
+ }
144
+ }
145
+
146
+ // ============================================================================
147
+ // Visual Overlay - Shadow DOM Implementation
148
+ // ============================================================================
149
+
150
+ const OVERLAY_HOST_ID = 'sentience-overlay-host';
151
+ let overlayTimeout = null;
152
+
153
+ /**
154
+ * Show visual overlay highlighting elements using Shadow DOM
155
+ * @param {Object} data - Message data with elements and targetElementId
156
+ */
157
+ function handleShowOverlay(data) {
158
+ const { elements, targetElementId } = data;
159
+
160
+ if (!elements || !Array.isArray(elements)) {
161
+ console.warn('[Sentience Bridge] showOverlay: elements must be an array');
162
+ return;
163
+ }
164
+
165
+ removeOverlay();
166
+
167
+ // Create host with Shadow DOM for CSS isolation
168
+ const host = document.createElement('div');
169
+ host.id = OVERLAY_HOST_ID;
170
+ host.style.cssText = `
171
+ position: fixed !important;
172
+ top: 0 !important;
173
+ left: 0 !important;
174
+ width: 100vw !important;
175
+ height: 100vh !important;
176
+ pointer-events: none !important;
177
+ z-index: 2147483647 !important;
178
+ margin: 0 !important;
179
+ padding: 0 !important;
180
+ `;
181
+ document.body.appendChild(host);
182
+
183
+ // Attach shadow root (closed mode for security and CSS isolation)
184
+ const shadow = host.attachShadow({ mode: 'closed' });
185
+
186
+ // Calculate max importance for scaling
187
+ const maxImportance = Math.max(...elements.map(e => e.importance || 0), 1);
188
+
189
+ elements.forEach((element) => {
190
+ const bbox = element.bbox;
191
+ if (!bbox) return;
192
+
193
+ const isTarget = element.id === targetElementId;
194
+ const isPrimary = element.visual_cues?.is_primary || false;
195
+ const importance = element.importance || 0;
196
+
197
+ // Color: Red (target), Blue (primary), Green (regular)
198
+ let color;
199
+ if (isTarget) color = '#FF0000';
200
+ else if (isPrimary) color = '#0066FF';
201
+ else color = '#00FF00';
202
+
203
+ // Scale opacity and border width based on importance
204
+ const importanceRatio = maxImportance > 0 ? importance / maxImportance : 0.5;
205
+ const borderOpacity = isTarget ? 1.0 : (isPrimary ? 0.9 : Math.max(0.4, 0.5 + importanceRatio * 0.5));
206
+ const fillOpacity = borderOpacity * 0.2;
207
+ const borderWidth = isTarget ? 2 : (isPrimary ? 1.5 : Math.max(0.5, Math.round(importanceRatio * 2)));
208
+
209
+ // Convert fill opacity to hex for background-color
210
+ const hexOpacity = Math.round(fillOpacity * 255).toString(16).padStart(2, '0');
211
+
212
+ // Create box with semi-transparent fill
213
+ const box = document.createElement('div');
214
+ box.style.cssText = `
215
+ position: absolute;
216
+ left: ${bbox.x}px;
217
+ top: ${bbox.y}px;
218
+ width: ${bbox.width}px;
219
+ height: ${bbox.height}px;
220
+ border: ${borderWidth}px solid ${color};
221
+ background-color: ${color}${hexOpacity};
222
+ box-sizing: border-box;
223
+ opacity: ${borderOpacity};
224
+ pointer-events: none;
225
+ `;
226
+
227
+ // Add badge showing importance score
228
+ if (importance > 0 || isPrimary) {
229
+ const badge = document.createElement('span');
230
+ badge.textContent = isPrimary ? `⭐${importance}` : `${importance}`;
231
+ badge.style.cssText = `
232
+ position: absolute;
233
+ top: -18px;
234
+ left: 0;
235
+ background: ${color};
236
+ color: white;
237
+ font-size: 11px;
238
+ font-weight: bold;
239
+ padding: 2px 6px;
240
+ font-family: Arial, sans-serif;
241
+ border-radius: 3px;
242
+ opacity: 0.95;
243
+ white-space: nowrap;
244
+ pointer-events: none;
245
+ `;
246
+ box.appendChild(badge);
247
+ }
248
+
249
+ // Add target emoji for target element
250
+ if (isTarget) {
251
+ const targetIndicator = document.createElement('span');
252
+ targetIndicator.textContent = '🎯';
253
+ targetIndicator.style.cssText = `
254
+ position: absolute;
255
+ top: -18px;
256
+ right: 0;
257
+ font-size: 16px;
258
+ pointer-events: none;
259
+ `;
260
+ box.appendChild(targetIndicator);
261
+ }
262
+
263
+ shadow.appendChild(box);
264
+ });
265
+
266
+ console.log(`[Sentience Bridge] Overlay shown for ${elements.length} elements`);
267
+
268
+ // Auto-remove after 5 seconds
269
+ overlayTimeout = setTimeout(() => {
270
+ removeOverlay();
271
+ console.log('[Sentience Bridge] Overlay auto-cleared after 5 seconds');
272
+ }, 5000);
273
+ }
274
+
275
+ /**
276
+ * Clear overlay manually
277
+ */
278
+ function handleClearOverlay() {
279
+ removeOverlay();
280
+ console.log('[Sentience Bridge] Overlay cleared manually');
281
+ }
282
+
283
+ /**
284
+ * Remove overlay from DOM
285
+ */
286
+ function removeOverlay() {
287
+ const existing = document.getElementById(OVERLAY_HOST_ID);
288
+ if (existing) {
289
+ existing.remove();
290
+ }
291
+
292
+ if (overlayTimeout) {
293
+ clearTimeout(overlayTimeout);
294
+ overlayTimeout = null;
295
+ }
296
+ }
297
+
298
+ // console.log('[Sentience Bridge] Ready - Extension ID:', chrome.runtime.id);