fix(observer): regex → 문자열 비교로 isGenericDesc 수정 — template literal escaping 회피 (v0.5.84)

This commit is contained in:
Variet Worker
2026-04-19 07:02:04 +09:00
parent d027562f17
commit 1662ac4f6b
3 changed files with 51 additions and 45 deletions

View File

@@ -1,12 +1,12 @@
{ {
"name": "gravity-bridge", "name": "gravity-bridge",
"version": "0.5.83", "version": "0.5.84",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "gravity-bridge", "name": "gravity-bridge",
"version": "0.5.83", "version": "0.5.84",
"dependencies": { "dependencies": {
"cheerio": "^1.2.0", "cheerio": "^1.2.0",
"ws": "^8.19.0" "ws": "^8.19.0"

View File

@@ -2,7 +2,7 @@
"name": "gravity-bridge", "name": "gravity-bridge",
"displayName": "Gravity Bridge", "displayName": "Gravity Bridge",
"description": "Discord-based unified approval system for Antigravity AI interactions.", "description": "Discord-based unified approval system for Antigravity AI interactions.",
"version": "0.5.83", "version": "0.5.84",
"publisher": "variet", "publisher": "variet",
"engines": { "engines": {
"vscode": "^1.100.0" "vscode": "^1.100.0"

View File

@@ -1,6 +1,6 @@
export function generateApprovalObserverScript(_port: number): string { export function generateApprovalObserverScript(_port: number): string {
return ` return `
// ── Gravity Bridge v17: Always Run Auto-Approve + Retry Detection ── // ?€?€ Gravity Bridge v17: Always Run Auto-Approve + Retry Detection ?€?€
// v17: "Always run" auto-approve at bridge level + Retry button relay to Discord // v17: "Always run" auto-approve at bridge level + Retry button relay to Discord
(function(){ (function(){
'use strict'; 'use strict';
@@ -16,7 +16,7 @@ export function generateApprovalObserverScript(_port: number): string {
try { fetch(BASE+'/log', {method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({msg:m.substring(0,2000)})}); } catch(e){} try { fetch(BASE+'/log', {method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({msg:m.substring(0,2000)})}); } catch(e){}
} }
} }
log('v17 Script loaded Always Run Auto-Approve + Retry Detection'); log('v17 Script loaded ??Always Run Auto-Approve + Retry Detection');
// DIAGNOSTIC BEACON: immediate POST to confirm script execution in renderer // DIAGNOSTIC BEACON: immediate POST to confirm script execution in renderer
try { try {
@@ -39,7 +39,7 @@ export function generateApprovalObserverScript(_port: number): string {
} }
} }
// ── Noise filter: lines that are UI artifacts, not real content ── // ?€?€ Noise filter: lines that are UI artifacts, not real content ?€?€
var NOISE_RE = new RegExp( var NOISE_RE = new RegExp(
'^(' + '^(' +
'chevron_right|chevron_left|arrow_drop_down|arrow_drop_up|arrow_right|arrow_left|' + 'chevron_right|chevron_left|arrow_drop_down|arrow_drop_up|arrow_right|arrow_left|' +
@@ -114,10 +114,10 @@ export function generateApprovalObserverScript(_port: number): string {
return type+'|'+txt+'|'+idx; return type+'|'+txt+'|'+idx;
} }
// ══════════════════════════════════════════════════════════════════ // ?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧
// v7: STEP-AWARE CONTEXT EXTRACTION // v7: STEP-AWARE CONTEXT EXTRACTION
// Find the closest [data-step-index] ancestor, extract step info // Find the closest [data-step-index] ancestor, extract step info
// ══════════════════════════════════════════════════════════════════ // ?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧
function getStepContainer(el) { function getStepContainer(el) {
var node = el; var node = el;
@@ -129,9 +129,9 @@ export function generateApprovalObserverScript(_port: number): string {
} }
// v14: Climb DOM tree to find context near the button // v14: Climb DOM tree to find context near the button
// STRICT SCOPE: Only 5 levels up beyond that we're in unrelated UI territory. // STRICT SCOPE: Only 5 levels up ??beyond that we're in unrelated UI territory.
// JUNK FILTERS: CSS rules, source code, Material icon gluing are all rejected. // JUNK FILTERS: CSS rules, source code, Material icon gluing are all rejected.
// NO FALLBACK: span/div/p text collection is removed entirely it always grabs chat/UI text. // NO FALLBACK: span/div/p text collection is removed entirely ??it always grabs chat/UI text.
var PROMPT_ONLY_RE = /^[^\\n]*[\\/\>\\xbb$#]\\s*$/; var PROMPT_ONLY_RE = /^[^\\n]*[\\/\>\\xbb$#]\\s*$/;
// v14: Detect CSS rules, JS source code, or extension internals in code text // v14: Detect CSS rules, JS source code, or extension internals in code text
var JUNK_CODE_RE = /(!important|::selection|background-color:|var\\(--|font-size:|border-[a-z]|padding:|margin:|display:\\s|\\{[^}]*:[^}]*\\}|===|!==|\\|\\||\\bfunction\\s*\\(|\\bconst\\s+\\w+\\s*=|\\bvar\\s+\\w+\\s*=|\\bif\\s*\\(|\\breturn\\b|\\bimport\\s|\\bexport\\s|\\bclass\\s+\\w|\\bnew\\s+\\w|\\.test\\(|\\.match\\(|\\.replace\\(|_RE[.\\s]|\\brawDesc\\b|\\brawCmd\\b|\\benrichedCmd\\b|\\bquerySelector)/; var JUNK_CODE_RE = /(!important|::selection|background-color:|var\\(--|font-size:|border-[a-z]|padding:|margin:|display:\\s|\\{[^}]*:[^}]*\\}|===|!==|\\|\\||\\bfunction\\s*\\(|\\bconst\\s+\\w+\\s*=|\\bvar\\s+\\w+\\s*=|\\bif\\s*\\(|\\breturn\\b|\\bimport\\s|\\bexport\\s|\\bclass\\s+\\w|\\bnew\\s+\\w|\\.test\\(|\\.match\\(|\\.replace\\(|_RE[.\\s]|\\brawDesc\\b|\\brawCmd\\b|\\benrichedCmd\\b|\\bquerySelector)/;
@@ -144,7 +144,7 @@ export function generateApprovalObserverScript(_port: number): string {
var _bestCodeHeader = ''; var _bestCodeHeader = '';
var _sawCodeEls = false; var _sawCodeEls = false;
var _allSkipped = true; var _allSkipped = true;
// v22: Increased from 5 to 10 AG Native command display (SRi) can be many levels up // v22: Increased from 5 to 10 ??AG Native command display (SRi) can be many levels up
for (var depth = 0; depth < 10 && node; depth++) { for (var depth = 0; depth < 10 && node; depth++) {
if (!node.querySelector) { _debugTrail.push('d'+depth+':noQS'); node = node.parentElement; continue; } if (!node.querySelector) { _debugTrail.push('d'+depth+':noQS'); node = node.parentElement; continue; }
// v22: Prioritize pre.font-mono (AG Native command line display from SRi component) // v22: Prioritize pre.font-mono (AG Native command line display from SRi component)
@@ -205,7 +205,7 @@ export function generateApprovalObserverScript(_port: number): string {
_debugTrail.push('sibling_d'+depth+':tag='+siblings[si].tagName.toLowerCase()+',code='+sibCode.substring(0,40)); _debugTrail.push('sibling_d'+depth+':tag='+siblings[si].tagName.toLowerCase()+',code='+sibCode.substring(0,40));
_bestCodeText = sibCode; _bestCodeText = sibCode;
_allSkipped = false; _allSkipped = false;
// Found in sibling return immediately // Found in sibling ??return immediately
var sibParts = []; var sibParts = [];
var sibHdr = siblings[si].querySelector('h1, h2, h3, [class*="header"], [class*="title"], [class*="cursor-pointer"]'); var sibHdr = siblings[si].querySelector('h1, h2, h3, [class*="header"], [class*="title"], [class*="cursor-pointer"]');
if (sibHdr) sibParts.push(cleanLines((sibHdr.textContent || '').trim().substring(0, 200))); if (sibHdr) sibParts.push(cleanLines((sibHdr.textContent || '').trim().substring(0, 200)));
@@ -234,7 +234,7 @@ export function generateApprovalObserverScript(_port: number): string {
function extractStepContext(btn) { function extractStepContext(btn) {
var stepEl = getStepContainer(btn); var stepEl = getStepContainer(btn);
if (!stepEl) { if (!stepEl) {
// v9 FALLBACK: no data-step-index climb DOM for pre/code blocks // v9 FALLBACK: no data-step-index ??climb DOM for pre/code blocks
return extractContextFromNearby(btn); return extractContextFromNearby(btn);
} }
@@ -270,7 +270,7 @@ export function generateApprovalObserverScript(_port: number): string {
if (codeText && !headerText.includes(codeText.substring(0, 20))) parts.push(codeText); if (codeText && !headerText.includes(codeText.substring(0, 20))) parts.push(codeText);
if (ariaLabel && ariaLabel.length > 5 && !headerText.includes(ariaLabel)) parts.push(ariaLabel); if (ariaLabel && ariaLabel.length > 5 && !headerText.includes(ariaLabel)) parts.push(ariaLabel);
var result = parts.join(' '); var result = parts.join(' ??');
if (!result) result = cleanButtonText(btn); if (!result) result = cleanButtonText(btn);
return 'Step #' + stepIdx + ': ' + result; return 'Step #' + stepIdx + ': ' + result;
} }
@@ -286,7 +286,7 @@ export function generateApprovalObserverScript(_port: number): string {
for(var i=0; i<ACTION_WORDS.length; i++) { for(var i=0; i<ACTION_WORDS.length; i++) {
if(txt.indexOf(ACTION_WORDS[i]) !== -1) return true; if(txt.indexOf(ACTION_WORDS[i]) !== -1) return true;
} }
// v9: Removed "Running N commands" it's a group header, not an approval button // v9: Removed "Running N commands" ??it's a group header, not an approval button
return false; return false;
} }
function isRejectBtn(txt) { function isRejectBtn(txt) {
@@ -366,18 +366,18 @@ export function generateApprovalObserverScript(_port: number): string {
startObserver(); startObserver();
}); });
// ══════════════════════════════════════════════════════════════════ // ?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧
// v8: FULL DOM STRUCTURE DUMP (unconditional no selector dependency) // v8: FULL DOM STRUCTURE DUMP (unconditional ??no selector dependency)
// Dumps entire document.body tree to /dump-html for real DOM analysis // Dumps entire document.body tree to /dump-html for real DOM analysis
// Auto-triggers at 5s, 15s, 60s after load to capture React-rendered state // Auto-triggers at 5s, 15s, 60s after load to capture React-rendered state
// ══════════════════════════════════════════════════════════════════ // ?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧
var _dumpCount=0; var _dumpCount=0;
var MAX_DUMPS=8; var MAX_DUMPS=8;
var _conversationDumpCount=0; var _conversationDumpCount=0;
function walkNode(el, depth, maxDepth, maxChildren) { function walkNode(el, depth, maxDepth, maxChildren) {
if (depth > maxDepth) return {tag:'…',text:'depth limit'}; if (depth > maxDepth) return {tag:'??,text:'depth limit'};
if (!el || !el.tagName) return null; if (!el || !el.tagName) return null;
var info = { var info = {
tag: el.tagName ? el.tagName.toLowerCase() : '#text', tag: el.tagName ? el.tagName.toLowerCase() : '#text',
@@ -413,7 +413,7 @@ export function generateApprovalObserverScript(_port: number): string {
if (childInfo) info.children.push(childInfo); if (childInfo) info.children.push(childInfo);
} }
if (el.children.length > limit) { if (el.children.length > limit) {
info.children.push({tag: '…', text: '+' + (el.children.length - limit) + ' more children'}); info.children.push({tag: '??, text: '+' + (el.children.length - limit) + ' more children'});
} }
} }
return info; return info;
@@ -508,11 +508,11 @@ export function generateApprovalObserverScript(_port: number): string {
setTimeout(function(){ log('Auto-dump @60s'); dumpDOMStructure(); }, 60000); setTimeout(function(){ log('Auto-dump @60s'); dumpDOMStructure(); }, 60000);
} }
// ══════════════════════════════════════════════════════════════════ // ?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧
// v15: AG-NATIVE + CASCADE DUAL CHAT BODY SCANNING // v15: AG-NATIVE + CASCADE DUAL CHAT BODY SCANNING
// AG Native: #conversation > ... > .leading-relaxed.select-text // AG Native: #conversation > ... > .leading-relaxed.select-text
// Cascade: [data-testid="conversation-view"] > [data-step-index] // Cascade: [data-testid="conversation-view"] > [data-step-index]
// ══════════════════════════════════════════════════════════════════ // ?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧
var _lastScrapedStepIndex = -1; var _lastScrapedStepIndex = -1;
var _lastStepText = ''; var _lastStepText = '';
@@ -684,7 +684,7 @@ export function generateApprovalObserverScript(_port: number): string {
} }
} }
// v19: Post-process wrap markdown table patterns in code blocks for Discord // v19: Post-process ??wrap markdown table patterns in code blocks for Discord
// AG Native renders tables as divs, not <table> HTML, so DOM-level handler can't catch them. // AG Native renders tables as divs, not <table> HTML, so DOM-level handler can't catch them.
// Detect consecutive lines with pipe separators (| col1 | col2 |) and wrap in code block fences // Detect consecutive lines with pipe separators (| col1 | col2 |) and wrap in code block fences
var bt = String.fromCharCode(96, 96, 96); var bt = String.fromCharCode(96, 96, 96);
@@ -749,12 +749,12 @@ export function generateApprovalObserverScript(_port: number): string {
// One-time DOM dump // One-time DOM dump
dumpDOMStructure(); dumpDOMStructure();
// ── STRATEGY 1: AG Native #conversation or .antigravity-agent-side-panel ── // ?€?€ STRATEGY 1: AG Native ??#conversation or .antigravity-agent-side-panel ?€?€
var cv = document.querySelector('#conversation'); var cv = document.querySelector('#conversation');
if (!cv) { if (!cv) {
cv = document.querySelector('.antigravity-agent-side-panel'); cv = document.querySelector('.antigravity-agent-side-panel');
} }
// v19: Fallback find conversation by tracing from known content elements // v19: Fallback ??find conversation by tracing from known content elements
if (!cv) { if (!cv) {
var probe = document.querySelector('.leading-relaxed.select-text') || document.querySelector('.text-ide-message-block-bot-color'); var probe = document.querySelector('.leading-relaxed.select-text') || document.querySelector('.text-ide-message-block-bot-color');
if (probe) { if (probe) {
@@ -818,11 +818,11 @@ export function generateApprovalObserverScript(_port: number): string {
} }
// v22: AI response = .leading-relaxed.select-text, User message = .select-text.rounded-lg (Esn component, msn class) // v22: AI response = .leading-relaxed.select-text, User message = .select-text.rounded-lg (Esn component, msn class)
// Source: jetskiAgent/main.js msn="bg-gray-500/10 border border-gray-500/20 p-2 rounded-lg w-full text-sm select-text" // Source: jetskiAgent/main.js ??msn="bg-gray-500/10 border border-gray-500/20 p-2 rounded-lg w-full text-sm select-text"
var responseBlocks = cv.querySelectorAll('.leading-relaxed.select-text, .select-text.rounded-lg'); var responseBlocks = cv.querySelectorAll('.leading-relaxed.select-text, .select-text.rounded-lg');
if (responseBlocks.length > 0) { if (responseBlocks.length > 0) {
// v22: Filter out thinking/reasoning blocks they have ancestor with max-h-[200px] // v22: Filter out thinking/reasoning blocks ??they have ancestor with max-h-[200px]
// These are internal AI reasoning and should NOT be relayed to Discord // These are internal AI reasoning and should NOT be relayed to Discord
var filteredBlocks = []; var filteredBlocks = [];
for (var fbi = 0; fbi < responseBlocks.length; fbi++) { for (var fbi = 0; fbi < responseBlocks.length; fbi++) {
@@ -847,7 +847,7 @@ export function generateApprovalObserverScript(_port: number): string {
if (lastBlock.dataset.agChatScraped === 'true' || lastBlock.dataset.agChatScraped === 'pending') { if (lastBlock.dataset.agChatScraped === 'true' || lastBlock.dataset.agChatScraped === 'pending') {
// Check for NEW blocks since last scrape // Check for NEW blocks since last scrape
if (filteredBlocks.length > _lastResponseBlockCount) { if (filteredBlocks.length > _lastResponseBlockCount) {
// New block appeared process it // New block appeared ??process it
for (var rbi = filteredBlocks.length - 1; rbi >= 0; rbi--) { for (var rbi = filteredBlocks.length - 1; rbi >= 0; rbi--) {
if (filteredBlocks[rbi].dataset.agChatScraped !== 'true' && filteredBlocks[rbi].dataset.agChatScraped !== 'pending') { if (filteredBlocks[rbi].dataset.agChatScraped !== 'true' && filteredBlocks[rbi].dataset.agChatScraped !== 'pending') {
lastBlock = filteredBlocks[rbi]; lastBlock = filteredBlocks[rbi];
@@ -896,7 +896,7 @@ export function generateApprovalObserverScript(_port: number): string {
var waitTime = isUser ? 500 : 3000; var waitTime = isUser ? 500 : 3000;
if (Date.now() - _lastStepTextTime < waitTime) return; // Still waiting if (Date.now() - _lastStepTextTime < waitTime) return; // Still waiting
// v21: DOM-based chat relay RE-ENABLED GetCascadeTrajectorySteps does NOT // v21: DOM-based chat relay RE-ENABLED ??GetCascadeTrajectorySteps does NOT
// return steps for in-progress cascades, making Step Probe RT-CAPTURE useless. // return steps for in-progress cascades, making Step Probe RT-CAPTURE useless.
// Observer DOM extraction is the ONLY real-time path for AI response relay. // Observer DOM extraction is the ONLY real-time path for AI response relay.
_lastStepTextSent = true; _lastStepTextSent = true;
@@ -913,11 +913,11 @@ export function generateApprovalObserverScript(_port: number): string {
.catch(function(e) { el.dataset.agChatScraped = 'false'; log('AG-Native chat send error: ' + e.message); }); .catch(function(e) { el.dataset.agChatScraped = 'false'; log('AG-Native chat send error: ' + e.message); });
})(lastBlock, blockText, filteredBlocks.length, role); })(lastBlock, blockText, filteredBlocks.length, role);
} }
return; // AG Native path handled don't fall through to Cascade path return; // AG Native path handled ??don't fall through to Cascade path
} }
} }
// ── STRATEGY 2: Cascade [data-testid="conversation-view"] ── // ?€?€ STRATEGY 2: Cascade ??[data-testid="conversation-view"] ?€?€
cv = document.querySelector('[data-testid="conversation-view"]'); cv = document.querySelector('[data-testid="conversation-view"]');
if (!cv) { if (!cv) {
// FALLBACK: Try older selectors // FALLBACK: Try older selectors
@@ -989,7 +989,7 @@ export function generateApprovalObserverScript(_port: number): string {
if (_lastStepTextSent) continue; if (_lastStepTextSent) continue;
if (Date.now() - _lastStepTextTime < 3000) break; // Still waiting if (Date.now() - _lastStepTextTime < 3000) break; // Still waiting
// Content is stable send it // Content is stable ??send it
_lastStepTextSent = true; _lastStepTextSent = true;
_lastScrapedStepIndex = stepIdx; _lastScrapedStepIndex = stepIdx;
stepEl.dataset.agChatScraped = 'pending'; stepEl.dataset.agChatScraped = 'pending';
@@ -1007,9 +1007,9 @@ export function generateApprovalObserverScript(_port: number): string {
} }
} }
// ══════════════════════════════════════════════════════════════════ // ?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧
// BUTTON SCANNING (approval detection) // BUTTON SCANNING (approval detection)
// ══════════════════════════════════════════════════════════════════ // ?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧?먥븧
function scan(){ function scan(){
if(!_ready)return; if(!_ready)return;
@@ -1018,7 +1018,7 @@ export function generateApprovalObserverScript(_port: number): string {
var allBtns=document.querySelectorAll('button, [role="button"], a.monaco-button, .monaco-text-button, vscode-button'); var allBtns=document.querySelectorAll('button, [role="button"], a.monaco-button, .monaco-text-button, vscode-button');
if(!allBtns.length)return; if(!allBtns.length)return;
// v25: One-shot debug find Accept/Reject elements in ANY tag (run once per 30s) // v25: One-shot debug ??find Accept/Reject elements in ANY tag (run once per 30s)
if (!scan._lastAcceptScan || now - scan._lastAcceptScan > 30000) { if (!scan._lastAcceptScan || now - scan._lastAcceptScan > 30000) {
scan._lastAcceptScan = now; scan._lastAcceptScan = now;
var allEls = document.querySelectorAll('button, a, div, span, [role="button"]'); var allEls = document.querySelectorAll('button, a, div, span, [role="button"]');
@@ -1037,10 +1037,10 @@ export function generateApprovalObserverScript(_port: number): string {
var txt=cleanButtonText(b); var txt=cleanButtonText(b);
if(txt.length <= 1) continue; if(txt.length <= 1) continue;
// v9: Skip group header buttons not approval buttons // v9: Skip group header buttons ??not approval buttons
if (/^Running\\s*\\d+\\s*commands?$/i.test(txt)) continue; if (/^Running\\s*\\d+\\s*commands?$/i.test(txt)) continue;
// v24: Relaxed visibility check Accept all/Reject all buttons in AG Native // v24: Relaxed visibility check ??Accept all/Reject all buttons in AG Native
// editor bottom bar may have offsetParent===null (different rendering layer) // editor bottom bar may have offsetParent===null (different rendering layer)
var isDiffReviewBtn = txt.includes('Accept') || txt === 'Reject all'; var isDiffReviewBtn = txt.includes('Accept') || txt === 'Reject all';
if(!isDiffReviewBtn && (b.disabled||b.hidden||(!b.offsetParent&&b.style.display!=='fixed')))continue; if(!isDiffReviewBtn && (b.disabled||b.hidden||(!b.offsetParent&&b.style.display!=='fixed')))continue;
@@ -1081,15 +1081,20 @@ export function generateApprovalObserverScript(_port: number): string {
_sent[groupKey]={rid:rid,ts:now}; _sent[groupKey]={rid:rid,ts:now};
for(var mk=0;mk<bidList.length;mk++)_sent[bidList[mk]]={rid:rid,ts:now}; for(var mk=0;mk<bidList.length;mk++)_sent[bidList[mk]]={rid:rid,ts:now};
// v26: Deferred context — if desc is generic ("Always run", button text only), // v26: Deferred context (string match, not regex — avoids template literal escaping issues)
function _isGenericDesc(d) {
var t = d.trim().toLowerCase();
return t === 'always run' || t === 'run' || t === 'allow' || t === 'accept' || t === 'retry' || t === txt.toLowerCase();
}
// v26: Deferred context ??if desc is generic ("Always run", button text only),
// delay 500ms and re-extract to allow DOM rendering to complete // delay 500ms and re-extract to allow DOM rendering to complete
var isGenericDesc = /^(Always\\s+run|Run|Allow|Accept|Retry)$/i.test(desc.trim()) || desc === txt; var isGenericDesc = _isGenericDesc(desc);
if (isGenericDesc && matchedType === 'command') { if (isGenericDesc && matchedType === 'command') {
log('DEFERRED-CONTEXT: desc="' + desc.substring(0,30) + '" waiting 500ms for DOM render'); log('DEFERRED-CONTEXT: desc="' + desc.substring(0,30) + '" ??waiting 500ms for DOM render');
(function(b2, rid2, btnRefs2, bidList2, groupKey2, txt2, type2, buttonsArr2) { (function(b2, rid2, btnRefs2, bidList2, groupKey2, txt2, type2, buttonsArr2) {
setTimeout(function() { setTimeout(function() {
var retryDesc = extractContext(b2); var retryDesc = extractContext(b2);
var finalDesc = /^(Always\\s+run|Run|Allow|Accept|Retry)$/i.test(retryDesc.trim()) ? desc : retryDesc; var finalDesc = _isGenericDesc(retryDesc) ? desc : retryDesc;
log('DEFERRED-RESULT: "' + finalDesc.substring(0,80) + '"'); log('DEFERRED-RESULT: "' + finalDesc.substring(0,80) + '"');
var payload = { var payload = {
request_id: rid2, request_id: rid2,
@@ -1229,7 +1234,7 @@ export function generateApprovalObserverScript(_port: number): string {
function startObserver(){ function startObserver(){
if(_obs)return; if(_obs)return;
log('startObserver() scheduling auto-dumps and mutation observer'); log('startObserver() ??scheduling auto-dumps and mutation observer');
scheduleAutoDumps(); scheduleAutoDumps();
new MutationObserver(function(mutations){ new MutationObserver(function(mutations){
for(var i=0;i<mutations.length;i++){ for(var i=0;i<mutations.length;i++){
@@ -1241,7 +1246,7 @@ export function generateApprovalObserverScript(_port: number): string {
}).observe(document.body,{childList:true,subtree:true}); }).observe(document.body,{childList:true,subtree:true});
setInterval(scheduleScan,3000); setInterval(scheduleScan,3000);
// ── TRIGGER-CLICK POLLING ── // ?€?€ TRIGGER-CLICK POLLING ?€?€
(function pollTriggerClick(){ (function pollTriggerClick(){
if(_ready&&BASE){ if(_ready&&BASE){
fetch(BASE+'/trigger-click?t='+Date.now()).then(function(r){return r.json();}).then(function(d){ fetch(BASE+'/trigger-click?t='+Date.now()).then(function(r){return r.json();}).then(function(d){
@@ -1264,12 +1269,12 @@ export function generateApprovalObserverScript(_port: number): string {
setTimeout(pollTriggerClick, 2000); setTimeout(pollTriggerClick, 2000);
})(); })();
// ── DEEP-INSPECT POLLING (v8: full body dump) ── // ?€?€ DEEP-INSPECT POLLING (v8: full body dump) ?€?€
(function pollDeepInspect(){ (function pollDeepInspect(){
if(_ready&&BASE){ if(_ready&&BASE){
fetch(BASE+'/deep-inspect-trigger?t='+Date.now()).then(function(r){return r.json();}).then(function(d){ fetch(BASE+'/deep-inspect-trigger?t='+Date.now()).then(function(r){return r.json();}).then(function(d){
if(!d.inspect)return; if(!d.inspect)return;
log('Deep inspect triggered full body dump'); log('Deep inspect triggered ??full body dump');
// Force a fresh DOM dump // Force a fresh DOM dump
_dumpCount = Math.max(0, _dumpCount - 1); // allow one more dump _dumpCount = Math.max(0, _dumpCount - 1); // allow one more dump
dumpDOMStructure(); dumpDOMStructure();
@@ -1319,3 +1324,4 @@ export function generateApprovalObserverScript(_port: number): string {
})(); })();
`; `;
} }