From b3dffacf8de89ea1bd4ddc4501c6eacc626aa19d Mon Sep 17 00:00:00 2001 From: rcholic Date: Tue, 6 Jan 2026 02:10:11 +0000 Subject: [PATCH] chore: sync extension files from sentience-chrome v2.2.0 --- sentience/extension/background.js | 8 - sentience/extension/content.js | 7 - sentience/extension/injected_api.js | 577 +++++++++++++++++- sentience/extension/manifest.json | 2 +- .../extension/pkg/sentience_core_bg.wasm | Bin 102522 -> 103409 bytes sentience/extension/release.json | 58 +- 6 files changed, 582 insertions(+), 70 deletions(-) diff --git a/sentience/extension/background.js b/sentience/extension/background.js index 1f64f84..6d0fe4a 100644 --- a/sentience/extension/background.js +++ b/sentience/extension/background.js @@ -6,7 +6,6 @@ import init, { analyze_page_with_options, analyze_page, prune_for_api } from '.. // This runs in an isolated environment, completely immune to page CSP policies -console.log('[Sentience Background] Initializing...'); // Global WASM initialization state let wasmReady = false; @@ -22,7 +21,6 @@ async function initWASM() { wasmInitPromise = (async () => { try { - console.log('[Sentience Background] Loading WASM module...'); // Define the js_click_element function that WASM expects // In Service Workers, use 'globalThis' instead of 'window' @@ -36,8 +34,6 @@ async function initWASM() { await init(); wasmReady = true; - console.log('[Sentience Background] ✓ WASM ready!'); - console.log( '[Sentience Background] Available functions: analyze_page, analyze_page_with_options, prune_for_api' ); } catch (error) { @@ -124,7 +120,6 @@ async function handleScreenshotCapture(_tabId, options = {}) { quality, }); - console.log( `[Sentience Background] Screenshot captured: ${format}, size: ${dataUrl.length} bytes` ); return dataUrl; @@ -166,7 +161,6 @@ async function handleSnapshotProcessing(rawData, options = {}) { throw new Error('WASM module not initialized'); } - console.log( `[Sentience Background] Processing ${rawData.length} elements with options:`, options ); @@ -213,7 +207,6 @@ async function handleSnapshotProcessing(rawData, options = {}) { } const duration = performance.now() - startTime; - console.log( `[Sentience Background] ✓ Processed: ${analyzedElements.length} analyzed, ${prunedRawData.length} pruned (${duration.toFixed(1)}ms)` ); @@ -228,7 +221,6 @@ async function handleSnapshotProcessing(rawData, options = {}) { } } -console.log('[Sentience Background] Service worker ready'); // Global error handlers to prevent extension crashes self.addEventListener('error', (event) => { diff --git a/sentience/extension/content.js b/sentience/extension/content.js index 931ef5a..7daa63b 100644 --- a/sentience/extension/content.js +++ b/sentience/extension/content.js @@ -4,12 +4,10 @@ 'use strict'; // content.js - ISOLATED WORLD (Bridge between Main World and Background) - console.log('[Sentience Bridge] Loaded.'); // Detect if we're in a child frame (for iframe support) const isChildFrame = window !== window.top; if (isChildFrame) { - console.log('[Sentience Bridge] Running in child frame:', window.location.href); } // 1. Pass Extension ID to Main World (So API knows where to find resources) @@ -118,7 +116,6 @@ } if (response?.success) { - console.log(`[Sentience Bridge] ✓ WASM processing complete in ${duration.toFixed(1)}ms`); window.postMessage( { type: 'SENTIENCE_SNAPSHOT_RESULT', @@ -292,12 +289,10 @@ shadow.appendChild(box); }); - console.log(`[Sentience Bridge] Overlay shown for ${elements.length} elements`); // Auto-remove after 5 seconds overlayTimeout = setTimeout(() => { removeOverlay(); - console.log('[Sentience Bridge] Overlay auto-cleared after 5 seconds'); }, 5000); } @@ -306,7 +301,6 @@ */ function handleClearOverlay() { removeOverlay(); - console.log('[Sentience Bridge] Overlay cleared manually'); } /** @@ -324,6 +318,5 @@ } } - // console.log('[Sentience Bridge] Ready - Extension ID:', chrome.runtime.id); })(); diff --git a/sentience/extension/injected_api.js b/sentience/extension/injected_api.js index 7438a60..4a99df1 100644 --- a/sentience/extension/injected_api.js +++ b/sentience/extension/injected_api.js @@ -34,6 +34,468 @@ return elements; } + // ============================================================================ + // LABEL INFERENCE SYSTEM + // ============================================================================ + + // Default inference configuration (conservative - Stage 1 equivalent) + const DEFAULT_INFERENCE_CONFIG = { + // Allowed tag names that can be inference sources + allowedTags: ['label', 'span', 'div'], + + // Allowed ARIA roles that can be inference sources + allowedRoles: [], + + // Class name patterns (substring match, case-insensitive) + allowedClassPatterns: [], + + // DOM tree traversal limits + maxParentDepth: 2, // Max 2 levels up DOM tree + maxSiblingDistance: 1, // Only immediate previous/next sibling + + // Container requirements (no distance-based checks) + requireSameContainer: true, // Must share common parent + containerTags: ['form', 'fieldset', 'div'], + + // Enable/disable specific inference methods + methods: { + explicitLabel: true, // el.labels API + ariaLabelledby: true, // aria-labelledby attribute + parentTraversal: true, // Check parent/grandparent + siblingProximity: true, // Check preceding sibling (same container only) + }, + }; + + // Merge user config with defaults + function mergeInferenceConfig(userConfig = {}) { + return { + ...DEFAULT_INFERENCE_CONFIG, + ...userConfig, + methods: { + ...DEFAULT_INFERENCE_CONFIG.methods, + ...(userConfig.methods || {}), + }, + }; + } + + // Check if element matches inference source criteria + function isInferenceSource(el, config) { + if (!el || !el.tagName) return false; + + const tag = el.tagName.toLowerCase(); + const role = el.getAttribute ? el.getAttribute('role') : ''; + const className = ((el.className || '') + '').toLowerCase(); + + // Check tag name + if (config.allowedTags.includes(tag)) { + return true; + } + + // Check role + if (config.allowedRoles.length > 0 && role && config.allowedRoles.includes(role)) { + return true; + } + + // Check class patterns + if (config.allowedClassPatterns.length > 0) { + for (const pattern of config.allowedClassPatterns) { + if (className.includes(pattern.toLowerCase())) { + return true; + } + } + } + + return false; + } + + // Helper: Find common parent element + function findCommonParent(el1, el2) { + if (!el1 || !el2) return null; + + // Get document reference safely for stopping conditions + // eslint-disable-next-line no-undef + const doc = + (typeof global !== 'undefined' && global.document) || + (typeof window !== 'undefined' && window.document) || + (typeof document !== 'undefined' && document) || + null; + + const parents1 = []; + let current = el1; + // Collect all parents (including el1 itself) + while (current) { + parents1.push(current); + // Stop if no parent + if (!current.parentElement) { + break; + } + // Stop at body or documentElement if they exist + if (doc && (current === doc.body || current === doc.documentElement)) { + break; + } + current = current.parentElement; + } + + // Check if el2 or any of its parents are in parents1 + current = el2; + while (current) { + // Use indexOf for more reliable comparison (handles object identity) + if (parents1.indexOf(current) !== -1) { + return current; + } + // Stop if no parent + if (!current.parentElement) { + break; + } + // Stop at body or documentElement if they exist + if (doc && (current === doc.body || current === doc.documentElement)) { + break; + } + current = current.parentElement; + } + + return null; + } + + // Helper: Check if element is a valid container + function isValidContainer(el, validTags) { + if (!el || !el.tagName) return false; + const tag = el.tagName.toLowerCase(); + // Handle both string and object className + let className = ''; + try { + className = (el.className || '') + ''; + } catch (e) { + className = ''; + } + return ( + validTags.includes(tag) || + className.toLowerCase().includes('form') || + className.toLowerCase().includes('field') + ); + } + + // Helper: Check container requirements (no distance-based checks) + function isInSameValidContainer(element, candidate, limits) { + if (!element || !candidate) return false; + + // Check same container requirement + if (limits.requireSameContainer) { + const commonParent = findCommonParent(element, candidate); + if (!commonParent) { + return false; + } + // Check if common parent is a valid container + if (!isValidContainer(commonParent, limits.containerTags)) { + return false; + } + } + + return true; + } + + // Main inference function + function getInferredLabel(el, options = {}) { + if (!el) return null; + + const { + enableInference = true, + inferenceConfig = {}, // User-provided config, merged with defaults + } = options; + + if (!enableInference) return null; + + // OPTIMIZATION: If element already has text or aria-label, skip inference entirely + // Check this BEFORE checking labels, so we don't infer if element already has text + // Note: For INPUT elements, we check value/placeholder, not innerText + // For IMG elements, we check alt, not innerText + // For other elements, innerText is considered explicit text + const ariaLabel = el.getAttribute ? el.getAttribute('aria-label') : null; + const hasAriaLabel = ariaLabel && ariaLabel.trim(); + const hasInputValue = el.tagName === 'INPUT' && (el.value || el.placeholder); + const hasImgAlt = el.tagName === 'IMG' && el.alt; + // For non-input/img elements, check innerText - but only if it's not empty + // Access innerText safely - it might be a getter or property + let innerTextValue = ''; + try { + innerTextValue = el.innerText || ''; + } catch (e) { + // If innerText access fails, treat as empty + innerTextValue = ''; + } + const hasInnerText = + el.tagName !== 'INPUT' && el.tagName !== 'IMG' && innerTextValue && innerTextValue.trim(); + + if (hasAriaLabel || hasInputValue || hasImgAlt || hasInnerText) { + return null; + } + + // Merge config with defaults + const config = mergeInferenceConfig(inferenceConfig); + + // Method 1: Explicit label association (el.labels API) + if (config.methods.explicitLabel && el.labels && el.labels.length > 0) { + const label = el.labels[0]; + if (isInferenceSource(label, config)) { + const text = (label.innerText || '').trim(); + if (text) { + return { + text, + source: 'explicit_label', + }; + } + } + } + + // Method 2: aria-labelledby (supports space-separated list of IDs) + // NOTE: aria-labelledby is an EXPLICIT reference, so it should work with ANY element + // regardless of inference source criteria. The config only controls whether this method runs. + if (config.methods.ariaLabelledby && el.hasAttribute && el.hasAttribute('aria-labelledby')) { + const labelIdsAttr = el.getAttribute('aria-labelledby'); + if (labelIdsAttr) { + // Split by whitespace to support multiple IDs (space-separated list) + const labelIds = labelIdsAttr.split(/\s+/).filter((id) => id.trim()); + const labelTexts = []; + + // Helper function to get document.getElementById from available contexts + const getDocument = () => { + // eslint-disable-next-line no-undef + if (typeof global !== 'undefined' && global.document) { + // eslint-disable-next-line no-undef + return global.document; + } + if (typeof window !== 'undefined' && window.document) { + return window.document; + } + if (typeof document !== 'undefined') { + return document; + } + return null; + }; + + const doc = getDocument(); + if (!doc || !doc.getElementById) ; else { + // Process each ID in the space-separated list + for (const labelId of labelIds) { + if (!labelId.trim()) continue; + + let labelEl = null; + try { + labelEl = doc.getElementById(labelId); + } catch (e) { + // If getElementById fails, skip this ID + continue; + } + + // aria-labelledby is an explicit reference - use ANY element, not just those matching inference criteria + // This follows ARIA spec: aria-labelledby can reference any element in the document + if (labelEl) { + // Extract text from the referenced element + let text = ''; + try { + // Try innerText first (preferred for visible text) + text = (labelEl.innerText || '').trim(); + // Fallback to textContent if innerText is empty + if (!text && labelEl.textContent) { + text = labelEl.textContent.trim(); + } + // Fallback to aria-label if available + if (!text && labelEl.getAttribute) { + const ariaLabel = labelEl.getAttribute('aria-label'); + if (ariaLabel) { + text = ariaLabel.trim(); + } + } + } catch (e) { + // If text extraction fails, skip this element + continue; + } + + if (text) { + labelTexts.push(text); + } + } + } + } + + // Combine multiple label texts (space-separated) + if (labelTexts.length > 0) { + return { + text: labelTexts.join(' '), + source: 'aria_labelledby', + }; + } + } + } + + // Method 3: Parent/grandparent traversal + if (config.methods.parentTraversal) { + let parent = el.parentElement; + let depth = 0; + while (parent && depth < config.maxParentDepth) { + if (isInferenceSource(parent, config)) { + const text = (parent.innerText || '').trim(); + if (text) { + return { + text, + source: 'parent_label', + }; + } + } + parent = parent.parentElement; + depth++; + } + } + + // Method 4: Preceding sibling (no distance-based checks, only DOM structure) + if (config.methods.siblingProximity) { + const prev = el.previousElementSibling; + if (prev && isInferenceSource(prev, config)) { + // Only check if they're in the same valid container (no pixel distance) + if ( + isInSameValidContainer(el, prev, { + requireSameContainer: config.requireSameContainer, + containerTags: config.containerTags, + }) + ) { + const text = (prev.innerText || '').trim(); + if (text) { + return { + text, + source: 'sibling_label', + }; + } + } + } + } + + return null; + } + + // Helper: Check if element is interactable (should have role inferred) + function isInteractableElement(el) { + if (!el || !el.tagName) return false; + + const tag = el.tagName.toLowerCase(); + const role = el.getAttribute ? el.getAttribute('role') : null; + const hasTabIndex = el.hasAttribute ? el.hasAttribute('tabindex') : false; + const hasHref = el.tagName === 'A' && (el.hasAttribute ? el.hasAttribute('href') : false); + + // Native interactive elements + const interactiveTags = [ + 'button', + 'input', + 'textarea', + 'select', + 'option', + 'details', + 'summary', + 'a', + ]; + if (interactiveTags.includes(tag)) { + // For , only if it has href + if (tag === 'a' && !hasHref) return false; + return true; + } + + // Elements with explicit interactive roles + const interactiveRoles = [ + 'button', + 'link', + 'tab', + 'menuitem', + 'checkbox', + 'radio', + 'switch', + 'slider', + 'combobox', + 'textbox', + 'searchbox', + 'spinbutton', + ]; + if (role && interactiveRoles.includes(role.toLowerCase())) { + return true; + } + + // Focusable elements (tabindex makes them interactive) + if (hasTabIndex) { + return true; + } + + // Elements with event handlers (custom interactive elements) + if (el.onclick || el.onkeydown || el.onkeypress || el.onkeyup) { + return true; + } + + // Check for inline event handlers via attributes + if (el.getAttribute) { + const hasInlineHandler = + el.getAttribute('onclick') || + el.getAttribute('onkeydown') || + el.getAttribute('onkeypress') || + el.getAttribute('onkeyup'); + if (hasInlineHandler) { + return true; + } + } + + return false; + } + + // Helper: Infer ARIA role for interactable elements + function getInferredRole(el, options = {}) { + const { + enableInference = true, + // inferenceConfig reserved for future extensibility + } = options; + + if (!enableInference) return null; + + // Only infer roles for interactable elements + if (!isInteractableElement(el)) { + return null; + } + + // CRITICAL: Only infer if element has NO aria-label AND NO explicit role + const hasAriaLabel = el.getAttribute ? el.getAttribute('aria-label') : null; + const hasExplicitRole = el.getAttribute ? el.getAttribute('role') : null; + + if (hasAriaLabel || hasExplicitRole) { + return null; // Skip inference if element already has aria-label or role + } + + // If element is native semantic HTML, it already has a role + const tag = el.tagName.toLowerCase(); + const semanticTags = ['button', 'a', 'input', 'textarea', 'select', 'option']; + if (semanticTags.includes(tag)) { + return null; // Native HTML already has role + } + + // Infer role based on element behavior or context + // Check for click handlers first (most common) + if (el.onclick || (el.getAttribute && el.getAttribute('onclick'))) { + return 'button'; + } + + // Check for keyboard handlers + if ( + el.onkeydown || + el.onkeypress || + el.onkeyup || + (el.getAttribute && + (el.getAttribute('onkeydown') || el.getAttribute('onkeypress') || el.getAttribute('onkeyup'))) + ) { + return 'button'; // Default to button for keyboard-interactive elements + } + + // Focusable div/span likely needs a role + if (el.hasAttribute && el.hasAttribute('tabindex') && (tag === 'div' || tag === 'span')) { + return 'button'; // Default assumption for focusable elements + } + + return null; + } + // --- HELPER: Smart Text Extractor --- function getText(el) { if (el.getAttribute('aria-label')) return el.getAttribute('aria-label'); @@ -42,6 +504,71 @@ return (el.innerText || '').replace(/\s+/g, ' ').trim().substring(0, 100); } + // Enhanced semantic text extractor with inference support + function getSemanticText(el, options = {}) { + if (!el) { + return { + text: '', + source: null, + }; + } + + // First check explicit aria-label (highest priority) + const explicitAriaLabel = el.getAttribute ? el.getAttribute('aria-label') : null; + if (explicitAriaLabel && explicitAriaLabel.trim()) { + return { + text: explicitAriaLabel.trim(), + source: 'explicit_aria_label', + }; + } + + // Check for existing text (visible text, input value, etc.) + // This matches the existing getText() logic + if (el.tagName === 'INPUT') { + const value = (el.value || el.placeholder || '').trim(); + if (value) { + return { + text: value, + source: 'input_value', + }; + } + } + + if (el.tagName === 'IMG') { + const alt = (el.alt || '').trim(); + if (alt) { + return { + text: alt, + source: 'img_alt', + }; + } + } + + const innerText = (el.innerText || '').trim(); + if (innerText) { + return { + text: innerText.substring(0, 100), // Match existing getText() limit + source: 'inner_text', + }; + } + + // Only try inference if we have NO explicit text/label + // Pass inferenceConfig from options to getInferredLabel + const inferred = getInferredLabel(el, { + enableInference: options.enableInference !== false, + inferenceConfig: options.inferenceConfig, // Pass config through + }); + if (inferred) { + return inferred; + } + + // Fallback: return empty with no source + return { + text: '', + source: null, + }; + } + // --- HELPER: Safe Class Name Extractor (Handles SVGAnimatedString) --- function getClassName(el) { if (!el || !el.className) return ''; @@ -745,7 +1272,6 @@ return iframeData; } - console.log(`[SentienceAPI] Found ${iframes.length} iframe(s), requesting snapshots...`); // Request snapshot from each iframe const iframePromises = iframes.map((iframe, idx) => { // OPTIMIZATION: Skip common ad domains to save time @@ -755,7 +1281,6 @@ src.includes('googleadservices') || src.includes('ads system') ) { - console.log(`[SentienceAPI] Skipping ad iframe: ${src.substring(0, 30)}...`); return Promise.resolve(null); } @@ -789,7 +1314,6 @@ resolve(null); } else { const elementCount = event.data.snapshot?.raw_elements?.length || 0; - console.log( `[SentienceAPI] ✓ Received ${elementCount} elements from Iframe ${idx} (id: ${requestId})` ); resolve({ @@ -806,7 +1330,6 @@ // 3. SEND REQUEST with error handling try { if (iframe.contentWindow) { - // console.log(`[SentienceAPI] Sending request to Iframe ${idx} (id: ${requestId})`); iframe.contentWindow.postMessage( { type: 'SENTIENCE_IFRAME_SNAPSHOT_REQUEST', @@ -842,7 +1365,6 @@ results.forEach((result, idx) => { if (result && result.data && !result.error) { iframeData.set(iframes[idx], result.data); - console.log(`[SentienceAPI] ✓ Collected snapshot from iframe ${idx}`); } else if (result && result.error) { console.warn(`[SentienceAPI] Iframe ${idx} snapshot error:`, result.error); } else if (!result) { @@ -928,7 +1450,18 @@ window.sentience_registry[idx] = el; - const textVal = getText(el); + // Use getSemanticText for inference support (falls back to getText if no inference) + const semanticText = getSemanticText(el, { + enableInference: options.enableInference !== false, // Default: true + inferenceConfig: options.inferenceConfig, // Pass configurable inference settings + }); + const textVal = semanticText.text || getText(el); // Fallback to getText for backward compat + + // Infer role for interactable elements (only if no aria-label and no explicit role) + const inferredRole = getInferredRole(el, { + enableInference: options.enableInference !== false, + inferenceConfig: options.inferenceConfig, + }); const inView = isInViewport(rect); // Get computed style once (needed for both occlusion check and data collection) @@ -960,7 +1493,19 @@ attributes: { role: toSafeString(el.getAttribute('role')), type_: toSafeString(el.getAttribute('type')), - aria_label: toSafeString(el.getAttribute('aria-label')), + aria_label: + semanticText?.source === 'explicit_aria_label' + ? semanticText.text + : toSafeString(el.getAttribute('aria-label')), // Keep original for backward compat + inferred_label: + semanticText?.source && + !['explicit_aria_label', 'input_value', 'img_alt', 'inner_text'].includes( + semanticText.source + ) + ? toSafeString(semanticText.text) + : null, + label_source: semanticText?.source || null, // Track source for gateway + inferred_role: inferredRole ? toSafeString(inferredRole) : null, // Inferred role for interactable elements href: toSafeString(el.href || el.getAttribute('href') || null), class: toSafeString(getClassName(el)), // Capture dynamic input state (not just initial attributes) @@ -976,7 +1521,6 @@ }); }); - console.log(`[SentienceAPI] Collected ${rawData.length} elements from main frame`); // Step 1.5: Collect iframe snapshots and FLATTEN immediately // "Flatten Early" architecture: Merge iframe elements into main array before WASM @@ -986,9 +1530,7 @@ if (options.collectIframes !== false) { try { - console.log(`[SentienceAPI] Starting iframe collection...`); const iframeSnapshots = await collectIframeSnapshots(options); - console.log( `[SentienceAPI] Iframe collection complete. Received ${iframeSnapshots.size} snapshot(s)` ); @@ -996,11 +1538,9 @@ // FLATTEN IMMEDIATELY: Don't nest them. Just append them with coordinate translation. iframeSnapshots.forEach((iframeSnapshot, iframeEl) => { // Debug: Log structure to verify data is correct - // console.log(`[SentienceAPI] Processing iframe snapshot:`, iframeSnapshot); if (iframeSnapshot && iframeSnapshot.raw_elements) { const rawElementsCount = iframeSnapshot.raw_elements.length; - console.log( `[SentienceAPI] Processing ${rawElementsCount} elements from iframe (src: ${iframeEl.src || 'unknown'})` ); // Get iframe's bounding rect (offset for coordinate translation) @@ -1045,7 +1585,6 @@ } }); - // console.log(`[SentienceAPI] Merged ${iframeSnapshots.size} iframe(s). Total elements: ${allRawElements.length} (${rawData.length} main + ${totalIframeElements} iframe)`); } } catch (error) { console.warn('[SentienceAPI] Iframe collection failed:', error); @@ -1055,7 +1594,6 @@ // Step 2: Send EVERYTHING to WASM (One giant flat list) // Now WASM prunes iframe elements and main elements in one pass! // No recursion needed - everything is already flat - console.log( `[SentienceAPI] Sending ${allRawElements.length} total elements to WASM (${rawData.length} main + ${totalIframeElements} iframe)` ); const processed = await processSnapshotInBackground(allRawElements, options); @@ -1083,7 +1621,6 @@ const totalRaw = cleanedRawElements.length; const iframeCount = totalIframeElements || 0; - console.log( `[SentienceAPI] ✓ Complete: ${totalCount} Smart Elements, ${totalRaw} Raw Elements (includes ${iframeCount} from iframes) (WASM took ${processed.duration?.toFixed(1)}ms)` ); @@ -1304,10 +1841,8 @@ keyboardShortcut = 'Ctrl+Shift+I', } = options; - console.log( '🔴 [Sentience] Recording Mode STARTED. Click an element to copy its Ground Truth JSON.' ); - console.log(` Press ${keyboardShortcut} or call stopRecording() to stop.`); // Validate registry is populated if (!window.sentience_registry || window.sentience_registry.length === 0) { @@ -1415,7 +1950,6 @@ navigator.clipboard .writeText(jsonString) .then(() => { - console.log('✅ Copied Ground Truth to clipboard:', snippet); // Flash green to indicate success highlightBox.style.border = `2px solid ${successColor}`; @@ -1463,7 +1997,6 @@ delete window.sentience_stopRecording; } - console.log('⚪ [Sentience] Recording Mode STOPPED.'); }; // Keyboard shortcut handler (defined after stopRecording) @@ -1483,7 +2016,6 @@ // Set up auto-disable timeout if (autoDisableTimeout > 0) { timeoutId = setTimeout(() => { - console.log('⏰ [Sentience] Recording Mode auto-disabled after timeout.'); stopRecording(); }, autoDisableTimeout); } @@ -1517,7 +2049,6 @@ '*' ); - console.log(`[Sentience] Overlay requested for ${elements.length} elements`); } /** @@ -1530,7 +2061,6 @@ }, '*' ); - console.log('[Sentience] Overlay cleared'); } // index.js - Main Entry Point for Injected API @@ -1538,7 +2068,6 @@ (async () => { - // console.log('[SentienceAPI] Initializing (CSP-Resistant Mode)...'); // Wait for Extension ID from content.js const getExtensionId = () => document.documentElement.dataset.sentienceExtensionId; @@ -1562,7 +2091,6 @@ return; } - // console.log('[SentienceAPI] Extension ID:', extId); // Registry for click actions (still needed for click() function) window.sentience_registry = []; @@ -1584,7 +2112,6 @@ window.sentience_iframe_handler_setup = true; } - console.log('[SentienceAPI] ✓ Ready! (CSP-Resistant - WASM runs in background)'); })(); })(); diff --git a/sentience/extension/manifest.json b/sentience/extension/manifest.json index 9df85db..456c1f5 100644 --- a/sentience/extension/manifest.json +++ b/sentience/extension/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 3, "name": "Sentience Semantic Visual Grounding Extractor", - "version": "2.1.0", + "version": "2.2.0", "description": "Extract semantic visual grounding data from web pages", "permissions": ["activeTab", "scripting"], "host_permissions": [""], diff --git a/sentience/extension/pkg/sentience_core_bg.wasm b/sentience/extension/pkg/sentience_core_bg.wasm index 5b6cbc962ee6eb70415973f79950e3e204049d82..259298c3d76174fd80a930f93c18a2f0caa24b6b 100644 GIT binary patch delta 17434 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 ODDNU}vEwwGshT4V;o?_al%2A8*`RBQLVtbYR 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 AtN;K2 delta 16554 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 diff --git a/sentience/extension/release.json b/sentience/extension/release.json index 237d107..89ef3af 100644 --- a/sentience/extension/release.json +++ b/sentience/extension/release.json @@ -1,9 +1,9 @@ { - "url": "https://api.github.com/repos/SentienceAPI/Sentience-Geometry-Chrome-Extension/releases/274139125", - "assets_url": "https://api.github.com/repos/SentienceAPI/Sentience-Geometry-Chrome-Extension/releases/274139125/assets", - "upload_url": "https://uploads.github.com/repos/SentienceAPI/Sentience-Geometry-Chrome-Extension/releases/274139125/assets{?name,label}", - "html_url": "https://github.com/SentienceAPI/Sentience-Geometry-Chrome-Extension/releases/tag/v2.1.0", - "id": 274139125, + "url": "https://api.github.com/repos/SentienceAPI/Sentience-Geometry-Chrome-Extension/releases/274391186", + "assets_url": "https://api.github.com/repos/SentienceAPI/Sentience-Geometry-Chrome-Extension/releases/274391186/assets", + "upload_url": "https://uploads.github.com/repos/SentienceAPI/Sentience-Geometry-Chrome-Extension/releases/274391186/assets{?name,label}", + "html_url": "https://github.com/SentienceAPI/Sentience-Geometry-Chrome-Extension/releases/tag/v2.2.0", + "id": 274391186, "author": { "login": "rcholic", "id": 135060, @@ -25,21 +25,21 @@ "user_view_type": "public", "site_admin": false }, - "node_id": "RE_kwDOQshiJ84QVwf1", - "tag_name": "v2.1.0", + "node_id": "RE_kwDOQshiJ84QWuCS", + "tag_name": "v2.2.0", "target_commitish": "main", - "name": "Release v2.1.0", + "name": "Release v2.2.0", "draft": false, "immutable": false, "prerelease": false, - "created_at": "2026-01-05T06:50:34Z", - "updated_at": "2026-01-05T06:52:25Z", - "published_at": "2026-01-05T06:51:51Z", + "created_at": "2026-01-06T01:49:12Z", + "updated_at": "2026-01-06T01:50:33Z", + "published_at": "2026-01-06T01:49:59Z", "assets": [ { - "url": "https://api.github.com/repos/SentienceAPI/Sentience-Geometry-Chrome-Extension/releases/assets/336451766", - "id": 336451766, - "node_id": "RA_kwDOQshiJ84UDdi2", + "url": "https://api.github.com/repos/SentienceAPI/Sentience-Geometry-Chrome-Extension/releases/assets/336789146", + "id": 336789146, + "node_id": "RA_kwDOQshiJ84UEv6a", "name": "extension-files.tar.gz", "label": "", "uploader": { @@ -65,17 +65,17 @@ }, "content_type": "application/gzip", "state": "uploaded", - "size": 78328, - "digest": "sha256:97f355bdb757cf0d399d3e0efeacbc66fa55f5f3e4e2755c533eeb133c77bc42", + "size": 82734, + "digest": "sha256:c02b99bc87733d0ec292da4d03c9e0d07f929be49fd590cb5988f6609b53bf56", "download_count": 0, - "created_at": "2026-01-05T06:52:25Z", - "updated_at": "2026-01-05T06:52:25Z", - "browser_download_url": "https://github.com/SentienceAPI/Sentience-Geometry-Chrome-Extension/releases/download/v2.1.0/extension-files.tar.gz" + "created_at": "2026-01-06T01:50:33Z", + "updated_at": "2026-01-06T01:50:33Z", + "browser_download_url": "https://github.com/SentienceAPI/Sentience-Geometry-Chrome-Extension/releases/download/v2.2.0/extension-files.tar.gz" }, { - "url": "https://api.github.com/repos/SentienceAPI/Sentience-Geometry-Chrome-Extension/releases/assets/336451765", - "id": 336451765, - "node_id": "RA_kwDOQshiJ84UDdi1", + "url": "https://api.github.com/repos/SentienceAPI/Sentience-Geometry-Chrome-Extension/releases/assets/336789145", + "id": 336789145, + "node_id": "RA_kwDOQshiJ84UEv6Z", "name": "extension-package.zip", "label": "", "uploader": { @@ -101,15 +101,15 @@ }, "content_type": "application/zip", "state": "uploaded", - "size": 80564, - "digest": "sha256:3260b70b684cdb2eddf210d29dc35134438549f7cb08c3557db5c792a126c693", + "size": 84405, + "digest": "sha256:658294bf95b077bea348c99fc2a82093eaeb46c9fc4253ccd3d24ab334a3fc45", "download_count": 0, - "created_at": "2026-01-05T06:52:25Z", - "updated_at": "2026-01-05T06:52:25Z", - "browser_download_url": "https://github.com/SentienceAPI/Sentience-Geometry-Chrome-Extension/releases/download/v2.1.0/extension-package.zip" + "created_at": "2026-01-06T01:50:33Z", + "updated_at": "2026-01-06T01:50:33Z", + "browser_download_url": "https://github.com/SentienceAPI/Sentience-Geometry-Chrome-Extension/releases/download/v2.2.0/extension-package.zip" } ], - "tarball_url": "https://api.github.com/repos/SentienceAPI/Sentience-Geometry-Chrome-Extension/tarball/v2.1.0", - "zipball_url": "https://api.github.com/repos/SentienceAPI/Sentience-Geometry-Chrome-Extension/zipball/v2.1.0", + "tarball_url": "https://api.github.com/repos/SentienceAPI/Sentience-Geometry-Chrome-Extension/tarball/v2.2.0", + "zipball_url": "https://api.github.com/repos/SentienceAPI/Sentience-Geometry-Chrome-Extension/zipball/v2.2.0", "body": "" }