diff --git a/src/extension/injected_api.js b/src/extension/injected_api.js index 9becda7..65ef387 100644 --- a/src/extension/injected_api.js +++ b/src/extension/injected_api.js @@ -558,7 +558,103 @@ }(options.waitForStability || {}); const rawData = []; window.sentience_registry = []; - getAllElements().forEach((el, idx) => { + const nodes = getAllElements(), parseAriaInt = (el, attr) => { + try { + const raw = el.getAttribute ? el.getAttribute(attr) : null; + if (!raw) return null; + const n = parseInt(String(raw), 10); + return Number.isFinite(n) ? n : null; + } catch (e) { + return null; + } + }, safeKeyPart = (s, maxLen = 48) => String(s || "").replace(/\s+/g, " ").trim().slice(0, maxLen) || null, buildContainerKey = container => { + try { + const tag = container.tagName ? container.tagName.toLowerCase() : "div", role = container.getAttribute ? container.getAttribute("role") : null, id = container.id ? `#${safeKeyPart(container.id, 32)}` : null, cls = (() => { + if (!container.className) return null; + const parts = String(container.className).split(/\s+/).filter(Boolean).slice(0, 2); + return parts.length ? `.${safeKeyPart(parts.join("."), 48)}` : null; + })(), ariaLabel = container.getAttribute && container.getAttribute("aria-label") ? `aria=${safeKeyPart(container.getAttribute("aria-label"), 40)}` : null, parts = [ safeKeyPart(tag, 16), role ? `role=${safeKeyPart(role, 24)}` : null, id, cls, ariaLabel ].filter(Boolean); + return parts.length ? parts.join("|") : null; + } catch (e) { + return null; + } + }, computeContainerInfo = el => { + try { + if (!("A" === el.tagName && (el.getAttribute("href") || el.href) || "BUTTON" === el.tagName || el.getAttribute && ("link" === el.getAttribute("role") || "button" === el.getAttribute("role")) || isInteractableElement(el))) return null; + const candidates = []; + let node = el; + for (let depth = 0; depth < 6 && node && node.parentElement; depth++) { + const p = node.parentElement, tag = p.tagName ? p.tagName.toLowerCase() : "", role = p.getAttribute ? p.getAttribute("role") : null, isExplicit = "ul" === tag || "ol" === tag || "table" === tag || "tbody" === tag || "list" === role || "feed" === role || "grid" === role || "table" === role, childCount = p.children ? p.children.length : 0; + (isExplicit || childCount >= 6) && candidates.push({ + p: p, + depth: depth, + tag: tag, + role: role, + childCount: childCount + }), node = p; + } + if (!candidates.length) return null; + const pickItemNodes = (container, tag, role) => { + if ("ul" === tag || "ol" === tag || "list" === role) { + const lis = Array.from(container.children || []).filter(c => c && "LI" === c.tagName), filtered = lis.filter(li => { + if (!li || !li.querySelector) return !1; + const a = li.querySelector("a[href]"); + if (!a) return !1; + return (a.textContent || "").replace(/\s+/g, " ").trim().length >= 8; + }); + return filtered.length ? filtered : lis; + } + if ("table" === tag || "tbody" === tag || "table" === role || "grid" === role) { + const rows = Array.from(container.children || []).filter(c => c && "TR" === c.tagName), allRows = rows.length ? rows : Array.from(container.querySelectorAll("tr")), filtered = allRows.filter(tr => { + if (!tr || !tr.querySelector) return !1; + const links = Array.from(tr.querySelectorAll("a[href]")); + let bestLen = 0; + for (const a of links) { + const t = (a.textContent || "").replace(/\s+/g, " ").trim(); + t.length > bestLen && (bestLen = t.length); + } + return bestLen >= 12; + }); + return filtered.length ? filtered : allRows; + } + const kids = Array.from(container.children || []), items = kids.filter(c => { + if (!c || !c.querySelector) return !1; + if (!c.querySelector('a[href],button,[role="link"],[role="button"]')) return !1; + return (c.textContent || "").replace(/\s+/g, " ").trim().length >= 8; + }); + return items.length ? items : kids; + }; + let best = null; + for (const c of candidates) { + const items = pickItemNodes(c.p, c.tag, c.role), size = items.length || 0; + if (size < 4) continue; + let itemIndex = null; + for (let i = 0; i < items.length; i++) { + const it = items[i]; + if (it && (it === el || it.contains(el))) { + itemIndex = i; + break; + } + } + if (null === itemIndex) continue; + const score = size + ("ul" === c.tag || "ol" === c.tag || "table" === c.tag || c.role ? 2 : 0) - .4 * c.depth; + (!best || score > best.score) && (best = { + key: buildContainerKey(c.p), + index: itemIndex, + size: size, + score: score + }); + } + return best && best.key ? { + container_key: best.key, + index_in_container: best.index, + container_item_count: best.size + } : null; + } catch (e) { + return null; + } + }; + nodes.forEach((el, idx) => { if (!el.getBoundingClientRect) return; const rect = el.getBoundingClientRect(); if (rect.width < 5 || rect.height < 5) return; @@ -722,7 +818,7 @@ return text.length > maxLen && (text = text.slice(0, maxLen).trim()), text || null; }(el, { maxLen: 80 - }) : null; + }) : null, containerInfo = computeContainerInfo(el); rawData.push({ id: idx, tag: tagName, @@ -762,8 +858,15 @@ disabled: void 0 !== el.disabled ? String(el.disabled) : null, aria_checked: toSafeString(el.getAttribute("aria-checked")), aria_disabled: toSafeString(el.getAttribute("aria-disabled")), - aria_expanded: toSafeString(el.getAttribute("aria-expanded")) + aria_expanded: toSafeString(el.getAttribute("aria-expanded")), + aria_posinset: parseAriaInt(el, "aria-posinset"), + aria_setsize: parseAriaInt(el, "aria-setsize"), + aria_rowindex: parseAriaInt(el, "aria-rowindex"), + aria_colindex: parseAriaInt(el, "aria-colindex") }, + container_key: containerInfo ? containerInfo.container_key : null, + index_in_container: containerInfo ? containerInfo.index_in_container : null, + container_item_count: containerInfo ? containerInfo.container_item_count : null, text: toSafeString(textVal), in_viewport: inView, is_occluded: occluded, diff --git a/src/extension/manifest.json b/src/extension/manifest.json index e90a69d..aacb7c7 100644 --- a/src/extension/manifest.json +++ b/src/extension/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 3, "name": "Sentience Semantic Visual Grounding Extractor", - "version": "2.8.6", + "version": "2.9.0", "description": "Extract semantic visual grounding data from web pages", "permissions": ["activeTab", "scripting"], "host_permissions": [""], diff --git a/src/extension/pkg/sentience_core_bg.wasm b/src/extension/pkg/sentience_core_bg.wasm index 4ef5500..ead6d24 100644 Binary files a/src/extension/pkg/sentience_core_bg.wasm and b/src/extension/pkg/sentience_core_bg.wasm differ diff --git a/src/extension/release.json b/src/extension/release.json index 380abac..9446ac1 100644 --- a/src/extension/release.json +++ b/src/extension/release.json @@ -1,45 +1,45 @@ { - "url": "https://api.github.com/repos/SentienceAPI/Sentience-Geometry-Chrome-Extension/releases/279771305", - "assets_url": "https://api.github.com/repos/SentienceAPI/Sentience-Geometry-Chrome-Extension/releases/279771305/assets", - "upload_url": "https://uploads.github.com/repos/SentienceAPI/Sentience-Geometry-Chrome-Extension/releases/279771305/assets{?name,label}", - "html_url": "https://github.com/SentienceAPI/Sentience-Geometry-Chrome-Extension/releases/tag/v2.8.6", - "id": 279771305, + "url": "https://api.github.com/repos/SentienceAPI/Sentience-Geometry-Chrome-Extension/releases/285093610", + "assets_url": "https://api.github.com/repos/SentienceAPI/Sentience-Geometry-Chrome-Extension/releases/285093610/assets", + "upload_url": "https://uploads.github.com/repos/SentienceAPI/Sentience-Geometry-Chrome-Extension/releases/285093610/assets{?name,label}", + "html_url": "https://github.com/SentienceAPI/Sentience-Geometry-Chrome-Extension/releases/tag/v2.9.0", + "id": 285093610, "author": { - "login": "rcholic", - "id": 135060, - "node_id": "MDQ6VXNlcjEzNTA2MA==", - "avatar_url": "https://avatars.githubusercontent.com/u/135060?v=4", + "login": "github-actions[bot]", + "id": 41898282, + "node_id": "MDM6Qm90NDE4OTgyODI=", + "avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4", "gravatar_id": "", - "url": "https://api.github.com/users/rcholic", - "html_url": "https://github.com/rcholic", - "followers_url": "https://api.github.com/users/rcholic/followers", - "following_url": "https://api.github.com/users/rcholic/following{/other_user}", - "gists_url": "https://api.github.com/users/rcholic/gists{/gist_id}", - "starred_url": "https://api.github.com/users/rcholic/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/rcholic/subscriptions", - "organizations_url": "https://api.github.com/users/rcholic/orgs", - "repos_url": "https://api.github.com/users/rcholic/repos", - "events_url": "https://api.github.com/users/rcholic/events{/privacy}", - "received_events_url": "https://api.github.com/users/rcholic/received_events", - "type": "User", + "url": "https://api.github.com/users/github-actions%5Bbot%5D", + "html_url": "https://github.com/apps/github-actions", + "followers_url": "https://api.github.com/users/github-actions%5Bbot%5D/followers", + "following_url": "https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}", + "gists_url": "https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}", + "starred_url": "https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/github-actions%5Bbot%5D/subscriptions", + "organizations_url": "https://api.github.com/users/github-actions%5Bbot%5D/orgs", + "repos_url": "https://api.github.com/users/github-actions%5Bbot%5D/repos", + "events_url": "https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}", + "received_events_url": "https://api.github.com/users/github-actions%5Bbot%5D/received_events", + "type": "Bot", "user_view_type": "public", "site_admin": false }, - "node_id": "RE_kwDOQshiJ84QrPip", - "tag_name": "v2.8.6", + "node_id": "RE_kwDOQshiJ84Q_i7q", + "tag_name": "v2.9.0", "target_commitish": "main", - "name": "Release v2.8.6", + "name": "Release v2.9.0", "draft": false, "immutable": false, "prerelease": false, - "created_at": "2026-01-25T20:33:25Z", - "updated_at": "2026-01-25T20:34:33Z", - "published_at": "2026-01-25T20:33:51Z", + "created_at": "2026-02-11T04:42:28Z", + "updated_at": "2026-02-11T04:43:38Z", + "published_at": "2026-02-11T04:43:37Z", "assets": [ { - "url": "https://api.github.com/repos/SentienceAPI/Sentience-Geometry-Chrome-Extension/releases/assets/345751999", - "id": 345751999, - "node_id": "RA_kwDOQshiJ84Um8G_", + "url": "https://api.github.com/repos/SentienceAPI/Sentience-Geometry-Chrome-Extension/releases/assets/354007414", + "id": 354007414, + "node_id": "RA_kwDOQshiJ84VGbl2", "name": "extension-files.tar.gz", "label": "", "uploader": { @@ -65,17 +65,17 @@ }, "content_type": "application/gzip", "state": "uploaded", - "size": 79706, - "digest": "sha256:c2e5381ff623b044f18020ef5d0562378496314772b9494c3b2ce71ff63f2646", - "download_count": 2, - "created_at": "2026-01-25T20:34:33Z", - "updated_at": "2026-01-25T20:34:33Z", - "browser_download_url": "https://github.com/SentienceAPI/Sentience-Geometry-Chrome-Extension/releases/download/v2.8.6/extension-files.tar.gz" + "size": 81085, + "digest": "sha256:30397ec5b3500ddc33955d2e0dee67393920ac6798ae807f9f267b3ae869035c", + "download_count": 0, + "created_at": "2026-02-11T04:43:38Z", + "updated_at": "2026-02-11T04:43:38Z", + "browser_download_url": "https://github.com/SentienceAPI/Sentience-Geometry-Chrome-Extension/releases/download/v2.9.0/extension-files.tar.gz" }, { - "url": "https://api.github.com/repos/SentienceAPI/Sentience-Geometry-Chrome-Extension/releases/assets/345751998", - "id": 345751998, - "node_id": "RA_kwDOQshiJ84Um8G-", + "url": "https://api.github.com/repos/SentienceAPI/Sentience-Geometry-Chrome-Extension/releases/assets/354007415", + "id": 354007415, + "node_id": "RA_kwDOQshiJ84VGbl3", "name": "extension-package.zip", "label": "", "uploader": { @@ -101,15 +101,16 @@ }, "content_type": "application/zip", "state": "uploaded", - "size": 81339, - "digest": "sha256:35232bcde1fe0c8e6d0178b04377fe80f6442dcb01296a15dddf4639542f7354", + "size": 82665, + "digest": "sha256:dab6ffd92ac462890b88605effc088227dfe181a303ea6db41f93cfc6baecf38", "download_count": 0, - "created_at": "2026-01-25T20:34:33Z", - "updated_at": "2026-01-25T20:34:33Z", - "browser_download_url": "https://github.com/SentienceAPI/Sentience-Geometry-Chrome-Extension/releases/download/v2.8.6/extension-package.zip" + "created_at": "2026-02-11T04:43:38Z", + "updated_at": "2026-02-11T04:43:38Z", + "browser_download_url": "https://github.com/SentienceAPI/Sentience-Geometry-Chrome-Extension/releases/download/v2.9.0/extension-package.zip" } ], - "tarball_url": "https://api.github.com/repos/SentienceAPI/Sentience-Geometry-Chrome-Extension/tarball/v2.8.6", - "zipball_url": "https://api.github.com/repos/SentienceAPI/Sentience-Geometry-Chrome-Extension/zipball/v2.8.6", - "body": "" + "tarball_url": "https://api.github.com/repos/SentienceAPI/Sentience-Geometry-Chrome-Extension/tarball/v2.9.0", + "zipball_url": "https://api.github.com/repos/SentienceAPI/Sentience-Geometry-Chrome-Extension/zipball/v2.9.0", + "body": "## What's Changed\n* change release package by @rcholic in https://github.com/SentienceAPI/Sentience-Geometry-Chrome-Extension/pull/41\n\n\n**Full Changelog**: https://github.com/SentienceAPI/Sentience-Geometry-Chrome-Extension/compare/v2.8.6...v2.9.0", + "mentions_count": 1 }