const fs = require('fs'); const path = require('path'); const jsdom = require('jsdom'); const { JSDOM } = jsdom; const observerModule = require('./extension/out/observer-script.js'); const observerCode = observerModule.generateApprovalObserverScript(8080); const rawDump = JSON.parse(fs.readFileSync('C:/Users/Variet-Worker/.gemini/antigravity/bridge/dump_html.json', 'utf8')); // Instantiate DOM const dom = new JSDOM(rawDump.html, { runScripts: "dangerously", pretendToBeVisual: true, url: "http://localhost/" }); const window = dom.window; const document = window.document; // Polyfill offsetParent for visibility check Object.defineProperty(window.HTMLElement.prototype, 'offsetParent', { get() { return document.body; } }); Object.defineProperty(window.HTMLElement.prototype, 'style', { get() { return { display: 'block' }; } }); // Mock innerText (JSDOM does not fully support it, but generic walker uses nodeValue / textContent) // Our logic uses nodeValue for TextNodes, so it will work in JSDOM out of the box! // Setup the DOM tree to perfectly match a real Chat conversation const titleSpan = document.querySelector('span[title^="command("]'); if(!titleSpan) { console.error("COULD NOT FIND command SPAN in dump?!"); process.exit(1); } // Find the card container let toolContainer = titleSpan.parentElement; while(toolContainer && !toolContainer.className.includes("border-gray-500/10") && !toolContainer.className.includes("bg-gray-500/10")) { toolContainer = toolContainer.parentElement; } if(!toolContainer) toolContainer = titleSpan.parentElement; // fallback // Create an AI text block just above it const aiChat = document.createElement('div'); aiChat.className = 'markdown prose'; aiChat.innerHTML = '

안녕하세요! 시스템을 수정하기 위해 요청하신 작업을 시작합니다. 디스코드 릴레이 기능 복구를 위해 스크립트를 실행하겠습니다.

'; // Wrap them up in the turn container const parent = toolContainer.parentElement; const convoWrapper = document.createElement('div'); convoWrapper.className = 'bg-agent-convo-background'; parent.insertBefore(convoWrapper, toolContainer); convoWrapper.appendChild(aiChat); convoWrapper.appendChild(toolContainer); // Move tool inside the convo wrapper as a sibling to AI chat // Add action button to the tool container const btn = document.createElement('button'); btn.innerHTML = 'Allow'; toolContainer.appendChild(btn); console.log("Mock Button offsetParent:", btn.offsetParent ? btn.offsetParent.tagName : 'null'); console.log("Mock Button display:", btn.style.display); console.log("Mock Button text:", btn.textContent); // MOCK FETCH const fetchCalls = []; window.fetch = function(url, options) { fetchCalls.push({url, options}); if (url.includes('/ping')) { return Promise.resolve({ text: function() { return Promise.resolve('pong'); } }); } if (url.includes('/pending')) { return Promise.resolve({ json: function() { return Promise.resolve({ok: true, request_id: 'test-rid'}); } }); } return Promise.resolve({ json: function() { return Promise.resolve({}); } }); }; // Polyfill offsetParent for visibility check Object.defineProperty(window.HTMLElement.prototype, 'offsetParent', { get() { return document.body; } }); Object.defineProperty(window.HTMLElement.prototype, 'style', { get() { return { display: 'block' }; } }); const originalLog = console.log; window.console.log = function(...args) { if (args.length > 0 && typeof args[0] === 'string' && args[0].includes("NOT MATCHED")) { let txt = args[1]; let codes = []; if (txt) { for(let i=0; i { console.log("Triggering DOM mutation to force scan()..."); document.body.appendChild(document.createElement('span')); }, 1500); // Give it time to finish scan(). setTimeout(() => { console.log("\n====== FETCH CALLS ======"); if(fetchCalls.length === 0) console.log("NO FETCH CALLS MADE!"); fetchCalls.forEach(c => { console.log(`\n[${c.options ? c.options.method || 'GET' : 'GET'}] ${c.url}`); if(c.options && c.options.body) { try { let j = JSON.parse(c.options.body); console.log("[BODY] request_id:", j.request_id); console.log("[BODY] command:", j.command); console.log("[BODY] description:\n" + "=".repeat(40) + "\n" + j.description + "\n" + "=".repeat(40)); } catch(e) { console.log("[BODY]", c.options.body); } } }); // Determine success const pendingCall = fetchCalls.find(c => c.url.includes('/pending')); if(pendingCall && pendingCall.options && pendingCall.options.body) { const payload = JSON.parse(pendingCall.options.body); if(payload.description.includes("안녕하세요!") && payload.description.includes("METHOD=TITLE_SPAN")) { console.log("\n✅ SUCCESS: Both Chat Body & Tool Command effectively extracted!"); process.exit(0); } else { console.log("\n❌ FAIL: Payload description missing either chat text or command string!"); process.exit(1); } } else { console.log("\n❌ FAIL: /pending never called!"); process.exit(1); } }, 4000);