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