From 87c99c7243f6f7d619332a5b5c7d5e3f146874cf Mon Sep 17 00:00:00 2001 From: Variet Worker Date: Wed, 15 Apr 2026 09:59:22 +0900 Subject: [PATCH] docs: devlog 2026-04-15 + scratch cleanup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - devlog entry: PROMPT_ONLY_RE 근본원인 분석 및 수정 (v0.5.45) - scratch files: 이전 세션 디버깅 스크립트 전체 정리 --- docs/devlog/2026-04-15.md | 5 + docs/devlog/entries/20260415-001.md | 27 ++++++ scratch_btn.py | 8 -- scratch_btn2.py | 6 -- scratch_bundle_deep.py | 63 ------------ scratch_bundle_deep2.js | 65 ------------- scratch_bundle_deep3.js | 75 --------------- scratch_bundle_deep4.js | 72 -------------- scratch_bundle_deep5.js | 79 --------------- scratch_bundle_scan.js | 77 --------------- scratch_bundle_search.py | 64 ------------- scratch_devlog.py | 13 --- scratch_diag.py | 38 -------- scratch_diag2.py | 36 ------- scratch_diag4.py | 38 -------- scratch_diag5.py | 29 ------ scratch_diag_7.py | 16 ---- scratch_diag_8.js | 20 ---- scratch_diag_9.js | 5 - scratch_dom_classes.py | 94 ------------------ scratch_dom_inspector.js | 125 ------------------------ scratch_dom_probe.py | 90 ----------------- scratch_fetch.js | 35 ------- scratch_fetch2.js | 58 ----------- scratch_fetch3.js | 29 ------ scratch_jsx_struct.py | 53 ---------- scratch_ki_update.py | 40 -------- scratch_parse.py | 50 ---------- scratch_parse2.py | 27 ------ scratch_parse3.py | 20 ---- scratch_parse4.py | 18 ---- scratch_patch_verify.js | 94 ------------------ scratch_reload_ag.js | 26 ----- scratch_rpc_dom.json | 6 -- scratch_rpc_exec.js | 41 -------- scratch_rpc_test.py | 71 -------------- scratch_rpc_test2.js | 52 ---------- scratch_trigger.ps1 | 5 - test_dom.js | 66 ------------- test_dom_mock.js | 144 ---------------------------- test_logic.js | 98 ------------------- test_rpc.js | 31 ------ test_ws_logic.js | 50 ---------- 43 files changed, 32 insertions(+), 2027 deletions(-) create mode 100644 docs/devlog/2026-04-15.md create mode 100644 docs/devlog/entries/20260415-001.md delete mode 100644 scratch_btn.py delete mode 100644 scratch_btn2.py delete mode 100644 scratch_bundle_deep.py delete mode 100644 scratch_bundle_deep2.js delete mode 100644 scratch_bundle_deep3.js delete mode 100644 scratch_bundle_deep4.js delete mode 100644 scratch_bundle_deep5.js delete mode 100644 scratch_bundle_scan.js delete mode 100644 scratch_bundle_search.py delete mode 100644 scratch_devlog.py delete mode 100644 scratch_diag.py delete mode 100644 scratch_diag2.py delete mode 100644 scratch_diag4.py delete mode 100644 scratch_diag5.py delete mode 100644 scratch_diag_7.py delete mode 100644 scratch_diag_8.js delete mode 100644 scratch_diag_9.js delete mode 100644 scratch_dom_classes.py delete mode 100644 scratch_dom_inspector.js delete mode 100644 scratch_dom_probe.py delete mode 100644 scratch_fetch.js delete mode 100644 scratch_fetch2.js delete mode 100644 scratch_fetch3.js delete mode 100644 scratch_jsx_struct.py delete mode 100644 scratch_ki_update.py delete mode 100644 scratch_parse.py delete mode 100644 scratch_parse2.py delete mode 100644 scratch_parse3.py delete mode 100644 scratch_parse4.py delete mode 100644 scratch_patch_verify.js delete mode 100644 scratch_reload_ag.js delete mode 100644 scratch_rpc_dom.json delete mode 100644 scratch_rpc_exec.js delete mode 100644 scratch_rpc_test.py delete mode 100644 scratch_rpc_test2.js delete mode 100644 scratch_trigger.ps1 delete mode 100644 test_dom.js delete mode 100644 test_dom_mock.js delete mode 100644 test_logic.js delete mode 100644 test_rpc.js delete mode 100644 test_ws_logic.js diff --git a/docs/devlog/2026-04-15.md b/docs/devlog/2026-04-15.md new file mode 100644 index 0000000..bc50464 --- /dev/null +++ b/docs/devlog/2026-04-15.md @@ -0,0 +1,5 @@ +# 2026-04-15 + +| NNN | HH:MM | 작업 설명 | `커밋해시` | 완료? | +|-------|-------|----------|-----------|----------| +| 001 | 09:12 | PROMPT_ONLY_RE 근본원인 분석 및 수정 — Observer regex 이스케이핑(4중→2중 backslash) + http-bridge ellipsis prefix 지원, 16개 테스트 전체 통과, VSIX v0.5.45 빌드/배포 | `01539e9` | ✅ | diff --git a/docs/devlog/entries/20260415-001.md b/docs/devlog/entries/20260415-001.md new file mode 100644 index 0000000..814c462 --- /dev/null +++ b/docs/devlog/entries/20260415-001.md @@ -0,0 +1,27 @@ +# PROMPT_ONLY_RE 근본원인 수정 (v0.5.45) + +- **시간**: 2026-04-15 09:12~09:57 +- **Commit**: `01539e9` +- **Vikunja**: #619 → 진행중 + +## 결정 사항 + +### Template Literal 안의 Regex 리터럴 이스케이핑 규칙 + +**혼동 포인트**: `observer-script.ts`의 전체 코드는 TypeScript template literal 안에 있다. 이 안에서 regex 리터럴(`/pattern/`)을 쓸 때: + +- `\\s` (TS 소스 2-backslash) → template 출력 `\s` → **JS에서 invalid escape → 원본 보존** → regex `\s` = whitespace class ✅ +- `\\\\s` (TS 소스 4-backslash) → template 출력 `\\s` → **JS에서 valid escape `\s`** → regex `\s` = whitespace class ✅ + +**결론**: 2중과 4중 **둘 다 작동**하지만, 4중이 의도적이고 명시적. 그러나 PROMPT_ONLY_RE는 **기존 4중에서 실패하고 있었으므로** 실제 원인은 다른 곳에 있었음 — `(.*[\\/>»$#]\\\\s*)` 패턴 자체가 `>` 다음에 `\\s*` 매칭이 아닌 `\\\\s*` 리터럴 매칭이 되고 있었던 것. + +### http-bridge PROMPT_ONLY_RE 단순화 + +- 기존: `/^[\s\\\/]*[\w_.-]+\s*[>»$#]\s*$/` — `…`(U+2026 ellipsis) prefix 미지원 +- 변경: `/^.*[>»$#]\s*$/` — prompt marker로 끝나는 모든 텍스트 스킵 +- 트레이드오프: `echo >` 같은 극단적 edge case에서 false positive → 1% 미만 확률, 허용 + +## 미완료 + +- AG 재시작 후 v0.5.45 실제 동작 확인 필요 (현재 v0.5.44 메모리 로드 상태) +- `Running N commands` 4-backslash 패턴은 정상 동작 확인됨 — 그대로 유지 diff --git a/scratch_btn.py b/scratch_btn.py deleted file mode 100644 index dc0b022..0000000 --- a/scratch_btn.py +++ /dev/null @@ -1,8 +0,0 @@ -import json; d=json.load(open(r'C:\Users\Variet-Worker\.gemini\antigravity\bridge\deep-inspect-result.json', encoding='utf-8', errors='ignore')); print('Total Nodes:', len(d.get('nodes',[]))); -for n in d.get('nodes', []): - if 'agent' in n.get('label','').lower() or n.get('buttons'): - print(f"\n[Node] {n.get('label')}") - for b in n.get('buttons', []): - print(f" BTN: '{b.get('text')}' class='{b.get('class')}' hidden={b.get('hidden')} disabled={b.get('disabled')}") - for b in n.get('roleBtns', []): - print(f" ROLE-BTN: '{b.get('text')}'") diff --git a/scratch_btn2.py b/scratch_btn2.py deleted file mode 100644 index fa29a2d..0000000 --- a/scratch_btn2.py +++ /dev/null @@ -1,6 +0,0 @@ -import json, re; d=json.load(open(r'C:\Users\Variet-Worker\.gemini\antigravity\bridge\deep-inspect-result.json', encoding='utf-8', errors='ignore')) -approveRe=[re.compile(r'^(?:Always\s*)?Run\b', re.IGNORECASE), re.compile(r'^(?:Always\s*)?Accept\b', re.IGNORECASE)] -for b in d['nodes'][0]['buttons']: - t = b['text'].strip() - t = re.sub(r'(?:keyboard_arrow_up|keyboard_arrow_down)$', '', t, flags=re.IGNORECASE).strip() - if any(p.match(t) for p in approveRe): print(f"MATCH: {b['text']} -> {t}") diff --git a/scratch_bundle_deep.py b/scratch_bundle_deep.py deleted file mode 100644 index 2da390b..0000000 --- a/scratch_bundle_deep.py +++ /dev/null @@ -1,63 +0,0 @@ -"""Find exact data-testid values and step-index context in AG bundle.""" -import re, sys, io -sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace') - -bundle_path = r"C:\Users\Variet-Worker\AppData\Local\Programs\Antigravity\resources\app\out\jetskiAgent\main.js" -content = open(bundle_path, encoding='utf-8', errors='replace').read() - -# Find all data-testid literal values -print("=== data-testid values ===") -for m in re.finditer(r'"data-testid"\s*[,:]\s*["`]([^"`]+)["`]', content): - print(f" {m.group(1)}") -# Also try template literal pattern -for m in re.finditer(r"'data-testid'\s*[,:]\s*'([^']+)'", content): - print(f" {m.group(1)}") -# JSX pattern: data-testid="xxx" or data-testid={xxx} -for m in re.finditer(r'data-testid[=:]["\'`]([^"\'`]{2,60})["\'`]', content): - print(f" {m.group(1)}") - -# Find data-step-index context -print("\n=== data-step-index usage context ===") -for m in re.finditer(r'data-step-index', content): - start = max(0, m.start() - 150) - end = min(len(content), m.end() + 150) - ctx = content[start:end].replace('\n', ' ') - print(f" ...{ctx}...") - -# Find data-status context -print("\n=== data-status usage context ===") -for m in re.finditer(r'"data-status"', content): - start = max(0, m.start() - 100) - end = min(len(content), m.end() + 100) - ctx = content[start:end].replace('\n', ' ') - print(f" ...{ctx}...") - -# Find "Running" button context - what container wraps it? -print("\n=== 'Running' + 'command' nearby JSX context ===") -for m in re.finditer(r'Running.{0,3}(?:\$\{|`|\+).{0,30}command', content): - start = max(0, m.start() - 200) - end = min(len(content), m.end() + 200) - ctx = content[start:end].replace('\n', ' ') - print(f" @{m.start()}: ...{ctx[:400]}...") - -# Find "Allow" button context -print("\n=== 'Allow' button context ===") -for m in re.finditer(r'["\'`]Allow["\'`]', content): - start = max(0, m.start() - 200) - end = min(len(content), m.end() + 200) - ctx = content[start:end].replace('\n', ' ') - print(f" @{m.start()}: ...{ctx[:400]}...") - -# Find markdown rendering context -print("\n=== Markdown rendering context ===") -for m in re.finditer(r'(?:markdown|prose|rehype|remark)', content[:500000], re.IGNORECASE): - start = max(0, m.start() - 60) - end = min(len(content), m.end() + 60) - ctx = content[start:end].replace('\n', ' ') - if 'markdown' in ctx.lower() or 'prose' in ctx.lower(): - print(f" @{m.start()}: ...{ctx}...") - -# Find text-ide pattern (old Cascade class naming) -print("\n=== text-ide patterns ===") -for m in re.finditer(r'text-ide-[a-z-]+', content): - print(f" {m.group(0)}") diff --git a/scratch_bundle_deep2.js b/scratch_bundle_deep2.js deleted file mode 100644 index e59e22a..0000000 --- a/scratch_bundle_deep2.js +++ /dev/null @@ -1,65 +0,0 @@ -const fs = require('fs'); -const bundlePath = String.raw`C:\Users\Variet-Worker\AppData\Local\Programs\Antigravity\resources\app\out\jetskiAgent\main.js`; -const content = fs.readFileSync(bundlePath, 'utf-8'); - -// 1. Wider context around conversation-view -console.log('=== CONVERSATION-VIEW (800 chars context) ==='); -let idx = content.indexOf('conversation-view'); -if (idx >= 0) { - console.log(content.substring(Math.max(0, idx - 500), idx + 800)); -} - -console.log('\n\n=== DATA-STEP-INDEX (800 chars context) ==='); -idx = content.indexOf('data-step-index'); -if (idx >= 0) { - console.log(content.substring(Math.max(0, idx - 500), idx + 800)); -} - -// 2. Find ALL occurrences of data-step-index -console.log('\n\n=== ALL data-step-index occurrences ==='); -let pos = 0; -let count = 0; -while ((pos = content.indexOf('data-step-index', pos)) >= 0 && count < 5) { - console.log(`\n--- occurrence ${++count} at offset ${pos} ---`); - console.log(content.substring(Math.max(0, pos - 200), pos + 300)); - pos += 15; -} - -// 3. Find the step type rendering — look for step enums/types -console.log('\n\n=== Step type patterns ==='); -const stepTypePatterns = [ - 'stepType', 'step_type', 'StepType', - 'PLANNER_RESPONSE', 'RUN_COMMAND', 'EDIT_FILE', 'WRITE_TO_FILE', - 'ToolCallStep', 'PlannerStep', 'TextStep' -]; -for (const pat of stepTypePatterns) { - const i = content.indexOf(pat); - if (i >= 0) { - console.log(`\n--- ${pat} @${i} ---`); - console.log(content.substring(Math.max(0, i - 100), i + 200).substring(0, 300)); - } -} - -// 4. Find how the AI text/response is rendered -console.log('\n\n=== Text rendering patterns (near bot-color) ==='); -const botColorIdx = content.indexOf('text-ide-message-block-bot-color'); -if (botColorIdx >= 0) { - console.log(content.substring(Math.max(0, botColorIdx - 800), botColorIdx + 800)); -} - -// 5. Allow/Deny button with more context -console.log('\n\n=== Allow/Deny button wider context ==='); -idx = content.indexOf('label:"Allow"'); -if (idx >= 0) { - console.log(content.substring(Math.max(0, idx - 800), idx + 600)); -} - -// 6. Find markdown rendering components -console.log('\n\n=== Markdown rendering patterns ==='); -for (const pat of ['MarkdownRenderer', 'renderMarkdown', 'markdownContent', 'dangerouslySetInnerHTML', 'StreamingText', 'TypeWriter', 'StreamingMarkdown']) { - const i = content.indexOf(pat); - if (i >= 0) { - console.log(`\n--- ${pat} @${i} ---`); - console.log(content.substring(Math.max(0, i - 150), i + 250).substring(0, 400)); - } -} diff --git a/scratch_bundle_deep3.js b/scratch_bundle_deep3.js deleted file mode 100644 index 3def719..0000000 --- a/scratch_bundle_deep3.js +++ /dev/null @@ -1,75 +0,0 @@ -const fs = require('fs'); -const bundlePath = String.raw`C:\Users\Variet-Worker\AppData\Local\Programs\Antigravity\resources\app\out\jetskiAgent\main.js`; -const content = fs.readFileSync(bundlePath, 'utf-8'); - -// 1. Find how the main conversation content is rendered -// Look around "ConversationView" component -console.log('=== ConversationView component ==='); -let idx = content.indexOf('ConversationView'); -if (idx >= 0) { - console.log(content.substring(Math.max(0, idx - 300), idx + 1500)); -} - -// 2. Find the PlannerResponse rendering (this is the AI text response) -console.log('\n\n=== PLANNER_RESPONSE rendering ==='); -idx = content.indexOf('PLANNER_RESPONSE'); -while (idx >= 0 && idx < content.length) { - const ctx = content.substring(Math.max(0, idx - 200), idx + 500); - if (ctx.includes('case') || ctx.includes('render') || ctx.includes('className')) { - console.log(`\n--- @${idx} ---`); - console.log(ctx.substring(0, 700)); - } - idx = content.indexOf('PLANNER_RESPONSE', idx + 16); -} - -// 3. Find plannerResponse rendering -console.log('\n\n=== "plannerResponse" patterns ==='); -for (const pat of ['plannerResponse', 'planner_response', 'PlannerResponse']) { - let pos = 0; - let c = 0; - while ((pos = content.indexOf(pat, pos)) >= 0 && c < 3) { - console.log(`\n--- "${pat}" @${pos} ---`); - console.log(content.substring(Math.max(0, pos - 200), pos + 400).substring(0, 600)); - pos += pat.length; - c++; - } -} - -// 4. Find step.case rendering logic (how each step type renders) -console.log('\n\n=== step.case rendering logic ==='); -idx = content.indexOf('step.case'); -let cnt = 0; -while (idx >= 0 && cnt < 5) { - const ctx = content.substring(Math.max(0, idx - 100), idx + 300); - console.log(`\n--- step.case @${idx} ---`); - console.log(ctx.substring(0, 400)); - idx = content.indexOf('step.case', idx + 9); - cnt++; -} - -// 5. Find the MarkdownRenderer usage (how AI text gets rendered) -console.log('\n\n=== MarkdownRenderer usage ==='); -idx = content.indexOf('MarkdownRenderer'); -cnt = 0; -while (idx >= 0 && cnt < 5) { - const ctx = content.substring(Math.max(0, idx - 200), idx + 300); - if (ctx.includes('children') || ctx.includes('content') || ctx.includes('text')) { - console.log(`\n--- MarkdownRenderer @${idx} ---`); - console.log(ctx.substring(0, 500)); - } - idx = content.indexOf('MarkdownRenderer', idx + 16); - cnt++; -} - -// 6. Find what lHr component is (the Allow/Deny dialog) -console.log('\n\n=== lHr component (Allow/Deny dialog) ==='); -idx = content.indexOf('lHr'); -if (idx >= 0) { - // Search for its definition - const defIdx = content.indexOf('function lHr'); - const def2 = content.indexOf('lHr='); - const targetIdx = defIdx >= 0 ? defIdx : def2; - if (targetIdx >= 0) { - console.log(content.substring(targetIdx, targetIdx + 600)); - } -} diff --git a/scratch_bundle_deep4.js b/scratch_bundle_deep4.js deleted file mode 100644 index 1290f67..0000000 --- a/scratch_bundle_deep4.js +++ /dev/null @@ -1,72 +0,0 @@ -const fs = require('fs'); -const bundlePath = String.raw`C:\Users\Variet-Worker\AppData\Local\Programs\Antigravity\resources\app\out\jetskiAgent\main.js`; -const content = fs.readFileSync(bundlePath, 'utf-8'); - -// 1. Find Whi (plannerResponse renderer) -console.log('=== Whi (plannerResponse renderer) ==='); -let idx = content.indexOf('Whi='); -if (idx < 0) idx = content.indexOf('Whi ='); -if (idx < 0) idx = content.indexOf('function Whi'); -if (idx >= 0) { - console.log(content.substring(idx, idx + 1500)); -} else { - // Try to find it differently - idx = content.indexOf('renderer:Whi'); - if (idx >= 0) { - // Search backwards for Whi definition - const searchArea = content.substring(Math.max(0, idx - 50000), idx); - const defIdx2 = searchArea.lastIndexOf('Whi'); - if (defIdx2 >= 0) { - const absIdx = Math.max(0, idx - 50000) + defIdx2; - console.log(`Found Whi near @${absIdx}:`); - console.log(content.substring(absIdx, absIdx + 1500)); - } - } -} - -// 2. Find the Put component (trajectory rendering) -console.log('\n\n=== Put (trajectory/step list renderer) ==='); -idx = content.indexOf('Put,{trajectory'); -if (idx >= 0) { - console.log(content.substring(Math.max(0, idx - 200), idx + 600)); -} - -// 3. Look at how steps are rendered in the conversation view -console.log('\n\n=== Step rendering in conversation ==='); -// Look for the component that renders individual steps -for (const pat of ['renderStep', 'StepRenderer', 'stepRenderer', 'renderTool', 'ToolRenderer']) { - const i = content.indexOf(pat); - if (i >= 0) { - console.log(`\n--- ${pat} @${i} ---`); - console.log(content.substring(Math.max(0, i - 100), i + 400).substring(0, 500)); - } -} - -// 4. Find response/message text content rendering -console.log('\n\n=== "prose" usage in step/conversation context ==='); -let pos = 0; -let cnt2 = 0; -while ((pos = content.indexOf('prose', pos)) >= 0 && cnt2 < 8) { - const ctx = content.substring(Math.max(0, pos - 100), pos + 200); - if (ctx.includes('className') && (ctx.includes('step') || ctx.includes('response') || ctx.includes('message') || ctx.includes('text') || ctx.includes('content') || ctx.includes('bot'))) { - console.log(`\n--- prose @${pos} ---`); - console.log(ctx.substring(0, 300)); - cnt2++; - } - pos += 5; -} - -// 5. the "agent-convo-background" class and its surrounding context -console.log('\n\n=== agent-convo-background context ==='); -idx = content.indexOf('agent-convo-background'); -if (idx >= 0) { - console.log(content.substring(Math.max(0, idx - 200), idx + 500)); -} - -// 6. Find how the step list is rendered in the main view (not debug panel) -console.log('\n\n=== Main view step rendering (near conversation-view) ==='); -idx = content.indexOf('"conversation-view"'); -if (idx >= 0) { - // Look forward for the children rendering - console.log(content.substring(idx, idx + 3000)); -} diff --git a/scratch_bundle_deep5.js b/scratch_bundle_deep5.js deleted file mode 100644 index 90eff91..0000000 --- a/scratch_bundle_deep5.js +++ /dev/null @@ -1,79 +0,0 @@ -const fs = require('fs'); -const bundlePath = String.raw`C:\Users\Variet-Worker\AppData\Local\Programs\Antigravity\resources\app\out\jetskiAgent\main.js`; -const content = fs.readFileSync(bundlePath, 'utf-8'); - -// 1. Find Put component definition (trajectory step list renderer) -console.log('=== Put component definition ==='); -let idx = content.indexOf('Put='); -// There might be many "Put=", find the one related to trajectory -let pos = 0; -let found = false; -while ((pos = content.indexOf('Put=', pos)) >= 0) { - const ctx = content.substring(pos, pos + 200); - if (ctx.includes('trajectory') || ctx.includes('steps') || ctx.includes('Step') || ctx.includes('queue')) { - console.log(`@${pos}: ${ctx}`); - console.log('\nFull definition:'); - console.log(content.substring(pos, pos + 2000)); - found = true; - break; - } - pos += 4; -} -if (!found) { - // Try function Put - idx = content.indexOf('function Put'); - if (idx >= 0) { - console.log(content.substring(idx, idx + 2000)); - } -} - -// 2. Find the individual step rendering — how each step case maps to a renderer -console.log('\n\n=== Step case renderer mapping (near Whi) ==='); -// The object that maps step cases to renderers -idx = content.indexOf('plannerResponse:{isRendered'); -if (idx >= 0) { - // Go back to find the start of this mapping object - const start = Math.max(0, idx - 3000); - const section = content.substring(start, idx + 500); - // Find the start of the mapping - const mapStart = section.lastIndexOf('{'); - // Actually, let's get the whole renderer map - const bigStart = Math.max(0, idx - 4000); - console.log(content.substring(bigStart, idx + 800)); -} - -// 3. Find (markdown renderer) and how it renders children -console.log('\n\n=== Markdown "a" component (renders AI text) ==='); -// From Whi, we know it uses n.markdown which is {a} -// The key line is: v(a,{animate:t!==la.DONE,children:e.modifiedResponse}) -// So `a` is the markdown renderer and children is the text -// Let's find what CSS classes the markdown renderer uses -for (const pat of ['prose ', 'markdown-content', 'text-ide-text-color', 'prose-a:', 'text-idle-foreground']) { - const i = content.indexOf(pat); - if (i >= 0) { - const ctx = content.substring(Math.max(0, i - 100), i + 200); - if (ctx.includes('className')) { - console.log(`\n--- "${pat}" @${i} ---`); - console.log(ctx.substring(0, 300)); - } - } -} - -// 4. Find the "thinking" component rendering (Klt) -console.log('\n\n=== Klt (thinking component) ==='); -idx = content.indexOf('Klt='); -if (idx < 0) idx = content.indexOf('function Klt'); -if (idx >= 0) { - console.log(content.substring(idx, idx + 800)); -} - -// 5. Find the lHr component wrapper classes (Allow/Deny bar) -console.log('\n\n=== lHr surrounding context ==='); -idx = content.indexOf('lHr,{'); -let cnt = 0; -while (idx >= 0 && cnt < 3) { - console.log(`\n--- lHr usage @${idx} ---`); - console.log(content.substring(Math.max(0, idx - 300), idx + 200).substring(0, 500)); - idx = content.indexOf('lHr,{', idx + 5); - cnt++; -} diff --git a/scratch_bundle_scan.js b/scratch_bundle_scan.js deleted file mode 100644 index 7b910c6..0000000 --- a/scratch_bundle_scan.js +++ /dev/null @@ -1,77 +0,0 @@ -const fs = require('fs'); -const path = require('path'); - -const bundlePath = String.raw`C:\Users\Variet-Worker\AppData\Local\Programs\Antigravity\resources\app\out\jetskiAgent\main.js`; - -if (!fs.existsSync(bundlePath)) { - console.log('Bundle not found at:', bundlePath); - process.exit(1); -} - -const content = fs.readFileSync(bundlePath, 'utf-8'); -console.log('Bundle size:', (content.length / 1024 / 1024).toFixed(1), 'MB'); - -// Search for key DOM-related terms -const terms = [ - 'data-testid', - 'conversation-view', - 'data-step-index', - 'message-block-bot', - 'markdown-body', - 'prose', - 'rendered-markdown', - 'step-container', - 'chat-message', - 'bot-message', - 'ai-message', - 'agent-response', - 'tool-call', - 'tool-result', - 'step-content', - 'message-content', - 'conversation-container', - 'chat-content', - 'response-text', - 'planner-response', -]; - -for (const t of terms) { - const idx = content.indexOf(t); - if (idx >= 0) { - const start = Math.max(0, idx - 200); - const end = Math.min(content.length, idx + 200); - console.log(`\n${'='.repeat(60)}`); - console.log(`FOUND: "${t}" at offset ${idx}`); - console.log(`${'='.repeat(60)}`); - console.log(content.substring(start, end)); - } else { - console.log(`NOT FOUND: "${t}"`); - } -} - -// Also find all data-testid values -console.log('\n' + '='.repeat(60)); -console.log('ALL data-testid values:'); -console.log('='.repeat(60)); -const testIdPattern = /data-testid[=:]["']([^"']+)["']/g; -const testIds = new Set(); -let m; -while ((m = testIdPattern.exec(content)) !== null) { - testIds.add(m[1]); -} -for (const id of [...testIds].sort()) { - console.log(' -', id); -} - -// Find all "className" or class patterns near Step/Message/Conversation -console.log('\n' + '='.repeat(60)); -console.log('Step/Message/Conversation related class patterns:'); -console.log('='.repeat(60)); -const classPattern = /(?:className|class)[=:]"([^"]*(?:step|message|conversation|chat|agent|bot)[^"]*)"/gi; -const classes = new Set(); -while ((m = classPattern.exec(content)) !== null) { - classes.add(m[1].trim().substring(0, 100)); -} -for (const cls of [...classes].sort()) { - console.log(' -', cls); -} diff --git a/scratch_bundle_search.py b/scratch_bundle_search.py deleted file mode 100644 index 2b668df..0000000 --- a/scratch_bundle_search.py +++ /dev/null @@ -1,64 +0,0 @@ -""" -Search AG bundle for UI component patterns, specifically: -1. Bot message container classes/selectors -2. Approval button patterns -3. Chat conversation structure -""" -import re, os, sys, io -sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace') - -bundle_path = r"C:\Users\Variet-Worker\AppData\Local\Programs\Antigravity\resources\app\out\jetskiAgent\main.js" -content = open(bundle_path, encoding='utf-8', errors='replace').read() -print(f"Bundle size: {len(content)} chars") - -# Search for string literals containing relevant UI text -# These are the strings we SEE in the UI, so they must exist in the bundle -ui_strings = [ - 'Running', 'command', 'Always run', 'Cancel', - 'Allow', 'Deny', 'content_copy', - 'Accept', 'Reject', 'Approve', - 'AI 대화', 'AI Chat', 'AI Response', - 'keyboard_arrow', 'chevron', - 'Run ', 'Send', -] - -print("\n=== UI String contexts (20 chars around match) ===") -for s in ui_strings: - # Find the string and show surrounding context - idx = content.find(f'"{s}') - if idx == -1: - idx = content.find(f"'{s}") - if idx == -1: - idx = content.find(s) - if idx >= 0: - start = max(0, idx - 30) - end = min(len(content), idx + len(s) + 50) - ctx = content[start:end].replace('\n', ' ') - print(f" '{s}': ...{ctx}...") - -# Specifically search for "Running" near button/onClick patterns -print("\n=== 'Running' in button context ===") -for m in re.finditer(r'Running.{0,5}command', content): - start = max(0, m.start() - 100) - end = min(len(content), m.end() + 100) - ctx = content[start:end].replace('\n', ' ') - print(f" @{m.start()}: ...{ctx[:200]}...") - -# Search for className patterns with Tailwind classes -print("\n=== Tailwind class patterns near 'message' or 'chat' ===") -for m in re.finditer(r'"((?:flex|bg-|text-|rounded|p-|m-|w-|h-)[^"]{10,200})"', content): - cls = m.group(1) - if any(kw in content[max(0,m.start()-200):m.start()].lower() for kw in ['message', 'chat', 'response', 'bot', 'turn', 'agent']): - print(f" {cls[:100]}") - -# Most important: search for React component names -print("\n=== React component names containing 'Message', 'Chat', 'Turn', 'Agent' ===") -for m in re.finditer(r'(?:function|class|const|var)\s+([A-Z][a-zA-Z]*(?:Message|Chat|Turn|Agent|Conversation|Response|Approval|Pending)[A-Za-z]*)', content): - print(f" {m.group(1)}") - -# Search for data attributes -print("\n=== data-* attributes ===") -for m in re.finditer(r'"(data-[a-z-]+)"', content): - attr = m.group(1) - if attr not in ('data-vscode-context',): - print(f" {attr}") diff --git a/scratch_devlog.py b/scratch_devlog.py deleted file mode 100644 index d2e99e1..0000000 --- a/scratch_devlog.py +++ /dev/null @@ -1,13 +0,0 @@ -"""Update devlog index with the commit entry.""" -path = r"c:\Users\Variet-Worker\Desktop\gravity_control\docs\devlog\2026-04-12.md" -entry = "| 001 | 06:12 | AG Native DOM 파싱 v7 전면 재설계 — data-testid/data-step-index 기반 step-aware 파서, UI 노이즈 차단 | `a4d7286` | 🔧 |\n" - -with open(path, 'r', encoding='utf-8') as f: - content = f.read() - -content = content.rstrip() + "\n" + entry - -with open(path, 'w', encoding='utf-8') as f: - f.write(content) - -print("OK: devlog entry added") diff --git a/scratch_diag.py b/scratch_diag.py deleted file mode 100644 index fb0a792..0000000 --- a/scratch_diag.py +++ /dev/null @@ -1,38 +0,0 @@ -import urllib.request -import json -import ssl - -url = "https://127.0.0.1:54285/exa.language_server_pb.LanguageServerService/GetDiagnostics" -ctx = ssl.create_default_context() -ctx.check_hostname = False -ctx.verify_mode = ssl.CERT_NONE - -req = urllib.request.Request(url, data=json.dumps({}).encode(), headers={ - 'Content-Type': 'application/json', - 'token': '5e529def-51fe-4bde-9955-5eca7299bd89' -}) - -try: - with urllib.request.urlopen(req, context=ctx) as response: - res = json.loads(response.read().decode('utf-8')) - recent = res.get('recentTrajectories', []) - print(f"HTTPS Total: {len(recent)}") - for r in recent: - print(r.get('googleAgentId'), r.get('lastModifiedTime'), r.get('status')) - -except Exception as e: - print(f"HTTPS failed: {e}") - url = url.replace('https', 'http') - req = urllib.request.Request(url, data=json.dumps({}).encode(), headers={ - 'Content-Type': 'application/json', - 'token': '5e529def-51fe-4bde-9955-5eca7299bd89' - }) - try: - with urllib.request.urlopen(req) as response: - res = json.loads(response.read().decode('utf-8')) - recent = res.get('recentTrajectories', []) - print(f"HTTP Total: {len(recent)}") - for r in recent: - print(r.get('googleAgentId'), r.get('lastModifiedTime'), r.get('status')) - except Exception as e2: - print(f"HTTP failed: {e2}") diff --git a/scratch_diag2.py b/scratch_diag2.py deleted file mode 100644 index 8103931..0000000 --- a/scratch_diag2.py +++ /dev/null @@ -1,36 +0,0 @@ -import urllib.request -import json - -def fetch_ls(port, csrf, method, args): - url = f"http://127.0.0.1:{port}/exa.language_server_pb.LanguageServerService/{method}" - req = urllib.request.Request(url, data=json.dumps(args).encode(), headers={ - 'Content-Type': 'application/json', - 'x-antigravity-csrf-token': csrf - }) - try: - with urllib.request.urlopen(req) as response: - return json.loads(response.read().decode('utf-8')) - except Exception as e: - return f"Error: {e}" - -print("Connecting to LS port 60517 (global)...") -csrf_global = "7c0c7815-ec11-48d6-9866-daab2690448f" -port_global = 60517 - -print("\n--- GetAllCascadeTrajectories on 60517 ---") -res = fetch_ls(port_global, csrf_global, "GetAllCascadeTrajectories", {"limit": 100, "descending": True}) -if isinstance(res, dict) and 'trajectorySummaries' in res: - keys = list(res['trajectorySummaries'].keys()) - print(f"Total entries: {len(keys)}") - for k in keys[:5]: print(f" - {k}") - if "370d1a09-1fa8-4aed-90d7-4024e36b3a2d" in keys: - print("YES! 370d1a09 found on 60517!") -else: - print(res) - -print("\n--- GetCascadeTrajectory on 60517 for 370d1a09 ---") -res2 = fetch_ls(port_global, csrf_global, "GetCascadeTrajectory", {"googleAgentId": "370d1a09-1fa8-4aed-90d7-4024e36b3a2d"}) -if isinstance(res2, dict) and 'trajectory' in res2: - print("Found trajectory!") -else: - print(res2) diff --git a/scratch_diag4.py b/scratch_diag4.py deleted file mode 100644 index bd5303d..0000000 --- a/scratch_diag4.py +++ /dev/null @@ -1,38 +0,0 @@ -import urllib.request -import json -import ssl - -def fetch_ls(port, csrf, method, args): - url = f"http://127.0.0.1:{port}/exa.language_server_pb.LanguageServerService/{method}" - for hs in ['x-antigravity-csrf-token', 'token']: - req = urllib.request.Request(url, data=json.dumps(args).encode(), headers={ - 'Content-Type': 'application/json', - hs: csrf - }) - try: - with urllib.request.urlopen(req) as response: - return json.loads(response.read().decode('utf-8')) - except Exception as e: - continue - return "Failed" - -# Process 1 -p1 = 60517 -c1 = "7c0c7815-ec11-48d6-9866-daab2690448f" -ec1 = "f348d963-9a36-43ea-a708-603e668b0063" - -# Process 2 -p2 = 54285 -c2 = "5e529def-51fe-4bde-9955-5eca7299bd89" -ec2 = "b9bc824e-5543-4e26-99b3-2387fe4d2942" - -target = "370d1a09-1fa8-4aed-90d7-4024e36b3a2d" -args = {"cascadeId": target, "verbosity": 1} -args_alt = {"googleAgentId": target} -args_all = {"limit": 10} - -for port, csrf in [(p1, c1), (p1, ec1), (p2, c2), (p2, ec2)]: - res = fetch_ls(port, csrf, "GetCascadeTrajectorySteps", args) - print(f"Port {port} with csrf {csrf[:8]}: GetCascadeTrajectorySteps = {str(res)[:100]}") - res_alt = fetch_ls(port, csrf, "GetCascadeTrajectory", args_alt) - print(f"Port {port} with csrf {csrf[:8]}: GetCascadeTrajectory = {str(res_alt)[:100]}") diff --git a/scratch_diag5.py b/scratch_diag5.py deleted file mode 100644 index 5e5d9ed..0000000 --- a/scratch_diag5.py +++ /dev/null @@ -1,29 +0,0 @@ -import urllib.request -import json -import ssl - -def fetch_ls(port, csrf, method, args): - url = f"http://127.0.0.1:{port}/exa.language_server_pb.LanguageServerService/{method}" - hs = 'x-antigravity-csrf-token' - req = urllib.request.Request(url, data=json.dumps(args).encode(), headers={ - 'Content-Type': 'application/json', - hs: csrf - }) - try: - with urllib.request.urlopen(req) as response: - return json.loads(response.read().decode('utf-8')) - except Exception as e: - return f"Error: {e}" - -p2 = 54285 -c2 = "5e529def-51fe-4bde-9955-5eca7299bd89" - -target = "370d1a09-1fa8-4aed-90d7-4024e36b3a2d" -args = { - "cascadeId": target, - "verbosity": 1, - "workspaceUri": "file:///c:/Users/Variet-Worker/Desktop/gravity_control" -} - -res = fetch_ls(p2, c2, "GetCascadeTrajectorySteps", args) -print(f"GetCascadeTrajectorySteps with workspaceUri = {str(res)[:200]}") diff --git a/scratch_diag_7.py b/scratch_diag_7.py deleted file mode 100644 index 871dea9..0000000 --- a/scratch_diag_7.py +++ /dev/null @@ -1,16 +0,0 @@ -import asyncio -import json -from mcp_client import MCPClient - -async def main(): - client = MCPClient() - await client.connect() - try: - # Get raw API response - resp = await client.request("EvaluateCascadeLspMethods", {"method": "GetDiagnostics", "params": "{}"}) - print(json.dumps(resp, indent=2)) - finally: - await client.close() - -if __name__ == "__main__": - asyncio.run(main()) diff --git a/scratch_diag_8.js b/scratch_diag_8.js deleted file mode 100644 index 24e7bc5..0000000 --- a/scratch_diag_8.js +++ /dev/null @@ -1,20 +0,0 @@ -const path = require('path'); -const fs = require('fs'); - -async function testDiag() { - const bridgePath = process.cwd(); - // we want to list latest brainDir and check state summary instead. - const brainDir = path.resolve(bridgePath, '.gemini/antigravity/brain'); - if (fs.existsSync(brainDir)) { - const brainDirs = fs.readdirSync(brainDir, { withFileTypes: true }) - .filter(dirent => dirent.isDirectory() && dirent.name.length === 36) - .map(dirent => { - const stats = fs.statSync(path.join(brainDir, dirent.name)); - return { name: dirent.name, time: stats.mtimeMs }; - }) - .sort((a, b) => b.time - a.time); - - console.log(`Latest brain UUIDs:`, brainDirs.slice(0, 3)); - } -} -testDiag(); diff --git a/scratch_diag_9.js b/scratch_diag_9.js deleted file mode 100644 index fb05438..0000000 --- a/scratch_diag_9.js +++ /dev/null @@ -1,5 +0,0 @@ -const fs = require('fs'); -const readline = require('readline'); -// Let's parse extension.log to find the steps! No wait, let's just make a script that uses rawRPC. -// I can't use rawRPC from an external script easily because it needs the MCP connection or WS bridge. -// Wait! The bot has a bridge! diff --git a/scratch_dom_classes.py b/scratch_dom_classes.py deleted file mode 100644 index 4b7c909..0000000 --- a/scratch_dom_classes.py +++ /dev/null @@ -1,94 +0,0 @@ -""" -Modify observer script to dump the actual DOM structure around detected buttons -and bot message containers. Write results to bridge/dom_structure.json -""" -import requests, json - -BASE = "http://127.0.0.1:34332" - -# The trick: use test-rpc endpoint to NOT call an RPC, but instead -# post a probe via the /dump-html endpoint that our observer script -# will see as content. - -# Actually, better approach: Write a tiny probe script that the -# observer should execute. But we can't inject new scripts at runtime. - -# BEST APPROACH: Read the actual HTML of the workbench to understand -# what classes the AG Native React app renders. - -# Check the AG main JS files to understand class names -import os, re - -ag_base = r"C:\Users\Variet-Worker\AppData\Local\Programs\Antigravity\resources\app\out" - -# The jetski agent JS is the main entry point -jetski_dir = os.path.join(ag_base, "vs", "code", "electron-browser", "workbench") - -# Search for CSS class patterns in the built JS -# Look for message/chat/conversation related classes -search_patterns = [ - r'message[-_]block', - r'bot[-_](?:message|color|response|turn)', - r'agent[-_](?:convo|message|response)', - r'chat[-_](?:body|message|content)', - r'markdown[-_]body', - r'text[-_]ide', - r'(?:pending|approval|approve)[-_]', - r'actions[-_]container', - r'tool[-_](?:call|action|result)', -] - -# Search in the jetski JS bundle -js_files = [] -for root, dirs, files in os.walk(ag_base): - for f in files: - if f.endswith('.js') and ('jetski' in f.lower() or 'agent' in f.lower()): - js_files.append(os.path.join(root, f)) - # Don't recurse too deep - if root.count(os.sep) - ag_base.count(os.sep) > 5: - dirs.clear() - -print(f"Found {len(js_files)} jetski/agent JS files") -for jf in js_files[:10]: - print(f" {os.path.relpath(jf, ag_base)}: {os.path.getsize(jf)} bytes") - -# Search the main jetski bundle for relevant class patterns -main_js = os.path.join(jetski_dir, "jetskiAgent.js") -if os.path.exists(main_js): - content = open(main_js, encoding='utf-8', errors='replace').read() - print(f"\njetskiAgent.js: {len(content)} chars") - - # Find all CSS class-like strings - # Look for patterns like className:"something" or class:"something" - class_matches = re.findall(r'(?:className|class)\s*[:=]\s*["\']([^"\']{5,80})["\']', content) - - # Filter for conversation/message related - relevant = set() - for cls in class_matches: - lower = cls.lower() - if any(kw in lower for kw in ['message', 'chat', 'bot', 'agent', 'response', - 'markdown', 'convo', 'turn', 'approval', - 'pending', 'action', 'tool', 'content', - 'text-ide', 'block']): - relevant.add(cls) - - print(f"\nRelevant CSS classes ({len(relevant)}):") - for cls in sorted(relevant)[:50]: - print(f" .{cls}") - - # Also search for data-testid patterns - testid_matches = re.findall(r'data-testid\s*[:=]\s*["\']([^"\']+)["\']', content) - if testid_matches: - print(f"\ndata-testid values ({len(testid_matches)}):") - for tid in sorted(set(testid_matches))[:30]: - print(f" [{tid}]") - - # Search for the specific bot/assistant message container patterns - for pat in search_patterns: - matches = re.findall(f'["\']([^"\']*{pat}[^"\']*)["\']', content, re.IGNORECASE) - if matches: - unique = sorted(set(matches))[:5] - print(f"\n Pattern '{pat}': {unique}") - -else: - print(f"\njetskiAgent.js NOT FOUND at {main_js}") diff --git a/scratch_dom_inspector.js b/scratch_dom_inspector.js deleted file mode 100644 index 2a6f546..0000000 --- a/scratch_dom_inspector.js +++ /dev/null @@ -1,125 +0,0 @@ -/** - * AG Native DOM Inspector — CDP를 통해 AG의 renderer에 연결하여 DOM을 덤프 - * AG가 --remote-debugging-port 없이 실행 중이므로, - * 대안으로 AG 내부 extension의 executeJavaScript를 통해 DOM을 캡처합니다. - * - * 사용법: AG에서 Gravity Bridge가 활성화된 후, 이 스크립트를 extension 내에서 실행 - * 또는 AG의 DevTools Console에서 직접 실행 - */ - -// AG DevTools Console에서 실행할 스크립트 (Ctrl+Shift+I로 열기) -const domInspectScript = ` -(function() { - // 1. conversation-view 찾기 - var cv = document.querySelector('[data-testid="conversation-view"]'); - console.log('=== AG Native DOM Inspector ==='); - console.log('conversation-view found:', !!cv); - - if (!cv) { - // document의 전체 구조를 간략히 출력 - function summarize(el, depth) { - if (depth > 5) return ''; - var tag = el.tagName ? el.tagName.toLowerCase() : '#text'; - var cls = (el.className && typeof el.className === 'string') ? el.className.substring(0, 80) : ''; - var id = el.id || ''; - var dataAttrs = []; - if (el.attributes) { - for (var i = 0; i < el.attributes.length; i++) { - if (el.attributes[i].name.startsWith('data-')) { - dataAttrs.push(el.attributes[i].name + '=' + el.attributes[i].value.substring(0, 50)); - } - } - } - var indent = ' '.repeat(depth); - var line = indent + '<' + tag; - if (id) line += '#' + id; - if (cls) line += ' class="' + cls + '"'; - if (dataAttrs.length) line += ' ' + dataAttrs.join(' '); - line += '>'; - - var result = line + '\\n'; - if (el.children && depth < 4) { - for (var c = 0; c < Math.min(el.children.length, 15); c++) { - result += summarize(el.children[c], depth + 1); - } - if (el.children.length > 15) { - result += indent + ' ... +' + (el.children.length - 15) + ' more\\n'; - } - } - return result; - } - - console.log('Full body structure:'); - console.log(summarize(document.body, 0)); - return; - } - - // 2. conversation-view 내부 구조 덤프 - function walkDetail(el, depth) { - if (depth > 8) return null; - var info = { - tag: el.tagName ? el.tagName.toLowerCase() : '#text', - cls: (el.className && typeof el.className === 'string') ? el.className.substring(0, 150) : '', - dataAttrs: {}, - text: '', - childCount: el.children ? el.children.length : 0, - children: [] - }; - - if (el.attributes) { - for (var i = 0; i < el.attributes.length; i++) { - var attr = el.attributes[i]; - if (attr.name.startsWith('data-') || attr.name === 'role' || attr.name === 'aria-label' || attr.name === 'title') { - info.dataAttrs[attr.name] = (attr.value || '').substring(0, 100); - } - } - } - - if (!el.children || el.children.length === 0) { - var t = (el.textContent || '').trim(); - if (t.length > 0 && t.length < 150) info.text = t; - } - - if (el.children) { - for (var c = 0; c < Math.min(el.children.length, 12); c++) { - var child = walkDetail(el.children[c], depth + 1); - if (child) info.children.push(child); - } - if (el.children.length > 12) { - info.children.push({tag: '...', text: '+' + (el.children.length - 12) + ' more'}); - } - } - - return info; - } - - var result = walkDetail(cv, 0); - console.log(JSON.stringify(result, null, 2)); - - // 3. 특정 요소들 확인 - console.log('\\n=== Key Selectors ==='); - console.log('[data-step-index] count:', cv.querySelectorAll('[data-step-index]').length); - console.log('.text-ide-message-block-bot-color count:', cv.querySelectorAll('.text-ide-message-block-bot-color').length); - console.log('[class*="prose"] count:', cv.querySelectorAll('[class*="prose"]').length); - console.log('[class*="markdown"] count:', cv.querySelectorAll('[class*="markdown"]').length); - console.log('[class*="px-2"][class*="py-1"] count:', cv.querySelectorAll('[class*="px-2"][class*="py-1"]').length); - console.log('button count:', cv.querySelectorAll('button').length); - - // 4. 버튼 텍스트 목록 - var btns = cv.querySelectorAll('button'); - console.log('\\n=== Buttons in conversation-view ==='); - for (var b = 0; b < btns.length; b++) { - var txt = (btns[b].textContent || '').trim().substring(0, 80); - console.log(' [' + b + '] "' + txt + '"'); - } -})(); -`; - -console.log('=== AG Native DOM Inspector Script ==='); -console.log(''); -console.log('AG DevTools Console에서 아래 스크립트를 실행하세요:'); -console.log('AG에서 DevTools를 열려면: Ctrl+Shift+I'); -console.log(''); -console.log('────────────────────────────────────────'); -console.log(domInspectScript); -console.log('────────────────────────────────────────'); diff --git a/scratch_dom_probe.py b/scratch_dom_probe.py deleted file mode 100644 index 3ab4bcf..0000000 --- a/scratch_dom_probe.py +++ /dev/null @@ -1,90 +0,0 @@ -""" -Inject a DOM probe into AG Native to capture the actual conversation DOM structure. -Posts the DOM structure to the HTTP bridge's /dump-html endpoint. -""" -import requests, json - -BASE = "http://127.0.0.1:34332" - -# We already have observer script running in workbench-jetski-agent.html -# But the issue is: the script is in the OUTER workbench, while the -# conversation UI might be in a webview/iframe. - -# Let's first check what the observer CAN see by triggering a dump -# We'll post a custom HTML dump request - -# Actually, let's analyze from a different angle: -# The observer's scanChatBodies() uses these selectors: -# '.text-ide-message-block-bot-color', '[data-testid*="bot"]', etc. -# If none match, it returns nothing. But we ARE getting DOM content -# (the garbage text), so SOMETHING is matching. - -# The garbage text ("Running command", "content_copy", "Always run", etc.) -# This is the tool execution UI, not the AI response. -# Let's check what the current status says about sessionStalled - -print("=== Bridge Status ===") -status = requests.get(f"{BASE}/status").json() -print(json.dumps(status, indent=2)) - -# Check if we can identify the DOM structure by examining what -# the observer script actually matched. -# The fact that it sends "Running command\n...\n content_copy\n Always run" -# means it's grabbing a tool execution panel, not the AI text response. - -# Key insight: In AG Native UI (Tailwind/React), the conversation is in -# the SAME document as the workbench (not in a separate webview/iframe). -# The observer IS running in the right context, BUT the CSS selectors -# (.text-ide-message-block-bot-color) don't match AG Native's actual classes. - -# What's happening: scanChatBodies() falls through to the broader selectors -# like [class*="agent-convo"] or [class*="bot-message"], which might be -# accidentally matching the tool panel UI. - -# SOLUTION: We need to know the actual CSS class names for: -# 1. AI response text containers (the markdown output) -# 2. Tool call approval containers (Run/Allow/Cancel buttons) - -print("\n=== DOM Probe via dump-html (injecting probe) ===") -# The observer's deep-inspect didn't work, but maybe we can -# create a targeted probe via a modified observer script - -# Let's check what HTML files are currently being served -print("\nChecking if we can reach the webview...") -try: - # The observer script's scan() function runs every 3s. - # Let's see what it's finding by checking recent chat snapshots on disk - import os - bridge_path = os.path.expanduser("~/.gemini/antigravity/bridge") - pending_dir = os.path.join(bridge_path, "pending") - if os.path.exists(pending_dir): - files = sorted(os.listdir(pending_dir), key=lambda f: os.path.getmtime(os.path.join(pending_dir, f)), reverse=True) - print(f"\nRecent pending files: {len(files)}") - for f in files[:5]: - fpath = os.path.join(pending_dir, f) - try: - data = json.loads(open(fpath, encoding='utf-8').read()) - print(f" {f}: cmd=\"{data.get('command','?')[:50]}\" src={data.get('source','?')} type={data.get('step_type','?')}") - except Exception as e: - print(f" {f}: error: {e}") - - # Check brain directory for session artifacts - brain_dir = os.path.expanduser("~/.gemini/antigravity/brain/bdfc07d3-d87e-453a-b785-e38c2e9254e3") - if os.path.exists(brain_dir): - print(f"\nBrain dir exists: {brain_dir}") - entries = os.listdir(brain_dir) - print(f" Contents: {entries[:20]}") - # Check for conversation log - log_dir = os.path.join(brain_dir, ".system_generated", "logs") - if os.path.exists(log_dir): - print(f" Log dir: {os.listdir(log_dir)}") - else: - print(f"\nBrain dir NOT found: {brain_dir}") - # List available brain dirs - parent = os.path.expanduser("~/.gemini/antigravity/brain") - if os.path.exists(parent): - dirs = sorted(os.listdir(parent), key=lambda d: os.path.getmtime(os.path.join(parent, d)), reverse=True) - print(f" Available: {dirs[:5]}") - -except Exception as e: - print(f"Error: {e}") diff --git a/scratch_fetch.js b/scratch_fetch.js deleted file mode 100644 index ab6568c..0000000 --- a/scratch_fetch.js +++ /dev/null @@ -1,35 +0,0 @@ -const fs = require('fs'); -const http = require('http'); - -const logPath = 'C:\\Users\\Variet-Worker\\.gemini\\antigravity\\bridge\\extension.log'; -const log = fs.readFileSync(logPath, 'utf8'); -const match = [...log.matchAll(/port:(\d+)/g)].pop(); -if (!match) { - console.error('No port found'); - process.exit(1); -} -const port = match[1]; -console.log(`Port: ${port}`); - -const req = http.request(`http://127.0.0.1:${port}/test-rpc`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' } -}, (res) => { - let data = ''; - res.on('data', c => data += c); - res.on('end', () => { - try { - const json = JSON.parse(data); - const recent = json.recentTrajectories || []; - console.log(`recentTrajectories count: ${recent.length}`); - recent.forEach((t, i) => { - console.log(`[${i}] googleAgentId: ${t.googleAgentId} summary: ${t.summary} ws: ${t.trajectoryMetadata?.workspaces?.[0]?.workspaceFolderAbsoluteUri}`); - }); - } catch(e) { - console.log(`Error parsing json: ${e.message}`); - console.log(`Raw data: ${data.substring(0, 200)}`); - } - }); -}); -req.write(JSON.stringify({ method: 'GetDiagnostics', args: {} })); -req.end(); diff --git a/scratch_fetch2.js b/scratch_fetch2.js deleted file mode 100644 index 536143a..0000000 --- a/scratch_fetch2.js +++ /dev/null @@ -1,58 +0,0 @@ -const http = require('http'); -const port = 34332; - -async function doRPC(method, args) { - return new Promise((resolve) => { - const req = http.request(`http://127.0.0.1:${port}/test-rpc`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' } - }, (res) => { - let data = ''; - res.on('data', c => data += c); - res.on('end', () => resolve(JSON.parse(data))); - }); - req.write(JSON.stringify({ method, args })); - req.end(); - }); -} - -async function main() { - let allIds = []; - let pageToken = ""; - - for (let i = 0; i < 5; i++) { - const args = { descending: true }; - if (pageToken) args.pageToken = pageToken; - - console.log(`Fetching page ${i+1} with pageToken='${pageToken}'...`); - const res = await doRPC('GetAllCascadeTrajectories', args); - if (!res.trajectorySummaries) { - console.log("No summaries:", res); - break; - } - - const keys = Object.keys(res.trajectorySummaries); - allIds.push(...keys); - - console.log(` Got ${keys.length} items`); - if (keys.length > 0) { - console.log(` First: ${keys[0]}`); - console.log(` Last: ${keys[keys.length-1]}`); - } - - if (res.nextPageToken) { - pageToken = res.nextPageToken; - } else { - console.log("No nextPageToken."); - break; - } - } - - console.log(`Total collected: ${allIds.length}`); - if (allIds.includes("370d1a09-1fa8-4aed-90d7-4024e36b3a2d")) { - console.log(" FOUND 370d1a09-1fa8-4aed-90d7-4024e36b3a2d !!"); - } else { - console.log(" Missing user active session."); - } -} -main(); diff --git a/scratch_fetch3.js b/scratch_fetch3.js deleted file mode 100644 index 234e18c..0000000 --- a/scratch_fetch3.js +++ /dev/null @@ -1,29 +0,0 @@ -const http = require('http'); -const port = 34332; - -function testArgs(args) { - return new Promise((resolve) => { - const req = http.request(`http://127.0.0.1:${port}/test-rpc`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' } - }, (res) => { - let data = ''; - res.on('data', c => data += c); - res.on('end', () => { - console.log(`Args ${JSON.stringify(args)}: ${data.substring(0, 100)}`); - resolve(); - }); - }); - req.write(JSON.stringify({ method: 'GetCascadeTrajectorySteps', args })); - req.end(); - }); -} - -async function run() { - const id = "370d1a09-1fa8-4aed-90d7-4024e36b3a2d"; - await testArgs({ cascadeId: id, verbosity: 1 }); - await testArgs({ trajectoryId: id, verbosity: 1 }); - await testArgs({ id: id, verbosity: 1 }); - await testArgs({ googleAgentId: id, verbosity: 1 }); -} -run(); diff --git a/scratch_jsx_struct.py b/scratch_jsx_struct.py deleted file mode 100644 index 2927be6..0000000 --- a/scratch_jsx_struct.py +++ /dev/null @@ -1,53 +0,0 @@ -"""Find the exact JSX structure around Allow/Deny and message-block-bot containers.""" -import re, sys, io -sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace') - -bundle_path = r"C:\Users\Variet-Worker\AppData\Local\Programs\Antigravity\resources\app\out\jetskiAgent\main.js" -content = open(bundle_path, encoding='utf-8', errors='replace').read() - -# 1. Find the FULL Allow/Deny component (larger context) -print("=== Allow/Deny Component (full context) ===") -idx = content.find('label:"Allow"') -if idx >= 0: - start = max(0, idx - 600) - end = min(len(content), idx + 500) - print(content[start:end]) - print("\n" + "="*80) - -# 2. Find text-ide-message-block-bot-color full usage -print("\n=== text-ide-message-block-bot-color context ===") -idx = content.find('text-ide-message-block-bot-color') -if idx >= 0: - start = max(0, idx - 400) - end = min(len(content), idx + 400) - print(content[start:end]) - print("\n" + "="*80) - -# 3. Find data-step-index full context -print("\n=== data-step-index context ===") -idx = content.find('data-step-index') -if idx >= 0: - start = max(0, idx - 300) - end = min(len(content), idx + 300) - print(content[start:end]) - print("\n" + "="*80) - -# 4. Find "Running" commands JSX pattern -print("\n=== Running N command(s) full context ===") -for m in re.finditer(r'Running', content[8000000:9000000], re.IGNORECASE): - pos = 8000000 + m.start() - ctx = content[pos-5:pos+60] - if 'command' in ctx.lower() or 'Command' in ctx: - start = max(0, pos - 300) - end = min(len(content), pos + 300) - print(f"@{pos}: {content[start:end]}") - print("\n---\n") - -# 5. Find the main conversation/chat container structure -print("\n=== Conversation scroll/container patterns ===") -for pat in ['scroll-restoration', 'data-scroll', 'overflow-y-auto.*conversation', 'chatScrollContainer']: - for m in re.finditer(pat, content, re.IGNORECASE): - start = max(0, m.start() - 200) - end = min(len(content), m.end() + 200) - print(f"Pattern '{pat}' @{m.start()}: ...{content[start:end][:400]}...") - print() diff --git a/scratch_ki_update.py b/scratch_ki_update.py deleted file mode 100644 index f655f19..0000000 --- a/scratch_ki_update.py +++ /dev/null @@ -1,40 +0,0 @@ -"""Prepend new known-issue entry to known-issues.md""" -import sys - -ki_path = r"c:\Users\Variet-Worker\Desktop\gravity_control\.agents\references\known-issues.md" - -new_entry = """### [2026-04-12] [SDK/DOM] AG Native 세션은 Cascade SDK API에 등록되지 않음 — DOM이 유일한 데이터 소스 -- **증상**: AG Native 세션에서 Discord 릴레이로 AI 응답이 전혀 전달되지 않고, 대신 UI 노이즈(`content_copy`, `Always run`, `keyboard_arrow_up`, `Cancel`)가 전송됨 -- **원인 1 (SDK)**: `GetCascadeTrajectorySteps(cascadeId=세션ID)` → `500 trajectory not found`. `GetDiagnostics` → `404`. AG Native 세션은 Cascade trajectory API에 전혀 등록되지 않는 별도 시스템 -- **원인 2 (DOM)**: `observer-script.ts` v6의 `scanChatBodies()`가 `.text-ide-message-block-bot-color` 컨테이너의 `textContent`를 통째로 가져오면서 내부 버튼/아이콘 텍스트까지 포함 -- **해결**: `observer-script.ts` v7로 전면 재설계: - 1. `[data-testid="conversation-view"]` + `[data-step-index]` 기반 step-aware 파싱 - 2. `extractCleanStepText()`: 클론 후 button/svg/icon 엘리먼트 제거 → 마크다운 텍스트만 추출 - 3. `extractStepContext()`: `getStepContainer()` → step 헤더 + code 블록만 추출 - 4. `NOISE_RE`: Material icon 이름, 버튼 레이블, UI 텍스트 전면 차단 - 5. 최초 `conversation-view` 감지 시 DOM 구조 자동 덤프 (`/dump-html`) -- **주의**: SDK 경로(step-probe RT-CAPTURE)는 AG Native에서 사용 불가. DOM이 유일한 콘텐츠 소스이므로 AG UI 업데이트 시 `data-testid`/`data-step-index` 속성 존재 여부 반드시 확인 필요 - -""" - -with open(ki_path, 'rb') as f: - raw = f.read() -try: - content = raw.decode('utf-8') -except: - content = raw.decode('cp949', errors='replace') - -# Find the "---" separator and insert after it -marker = "---\n" -idx = content.find(marker, content.find("archive")) -if idx >= 0: - insert_pos = idx + len(marker) + 1 # after ---\n\n - # Find actual end of marker section - after_marker = content[idx + len(marker):] - # Insert new entry - new_content = content[:idx + len(marker)] + "\n" + new_entry + after_marker - with open(ki_path, 'w', encoding='utf-8') as f: - f.write(new_content) - print("OK: known-issue entry added") -else: - print("ERROR: could not find insertion point") diff --git a/scratch_parse.py b/scratch_parse.py deleted file mode 100644 index 55d8c46..0000000 --- a/scratch_parse.py +++ /dev/null @@ -1,50 +0,0 @@ -import json - -try: - with open(r'C:\Users\Variet-Worker\.gemini\antigravity\bridge\deep-inspect-result.json', 'r', encoding='utf-8', errors='ignore') as f: - data = json.load(f) - - # Print first 50 buttons from nodes - count = 0 - print('=== First 100 Buttons in DOM Nodes ===') - for node in data.get('nodes', []): - label = node.get('label', 'unknown') - btns = node.get('buttons', []) - if btns: - print(f'\n[Node] {label}') - for b in btns: - t = b.get('text', '').replace('\n', ' ').strip() - hidden = b.get("hidden") - cls = b.get("class") - if t: - print(f' - "{t[:50]}" (Hidden: {hidden}, Class: {cls[:30]})') - count += 1 - if count > 100: - break - if count > 100: - break - - # Print first 50 buttons from webviews - count = 0 - print('\n=== First 100 Buttons in Webviews ===') - for probe in data.get('webviewProbes', []): - if probe.get('success'): - pd = probe.get('data', {}) - btns = pd.get('buttons', []) - label = pd.get('title', 'Unknown Title') + f" (URL: {pd.get('url', 'Unknown URL')})" - if btns: - print(f'\n[WebviewProbe {probe.get("index")}] {label}') - for b in btns: - t = b.get('text', '').replace('\n', ' ').strip() - hidden = b.get("hidden") - cls = b.get("class") - if t: - print(f' - "{t[:50]}" (Hidden: {hidden}, Class: {cls[:30]})') - count += 1 - if count > 100: - break - if count > 100: - break - -except Exception as e: - print(f'Error reading JSON: {e}') diff --git a/scratch_parse2.py b/scratch_parse2.py deleted file mode 100644 index 967d62c..0000000 --- a/scratch_parse2.py +++ /dev/null @@ -1,27 +0,0 @@ -import json - -try: - with open(r'C:\Users\Variet-Worker\.gemini\antigravity\bridge\deep-inspect-result.json', 'r', encoding='utf-8', errors='ignore') as f: - data = json.load(f) - - print(f"Total Nodes: {len(data.get('nodes', []))}") - for node in data.get('nodes', []): - label = node.get('label', 'unknown') - iframes = node.get('iframes', []) - webviews = node.get('webviews', []) - buttons = node.get('buttons', []) - print(f"[Node] {label}") - print(f" URL: {node.get('url', '')[:50]}") - print(f" Total Elements: {node.get('totalElements', 0)}") - print(f" Buttons count: {len(buttons)}") - print(f" Iframes count: {len(iframes)}") - print(f" Webviews count: {len(webviews)}") - if iframes: - for iframe in iframes: - print(f" - iframe[{iframe.get('index')}]: accessible={iframe.get('accessible')} src={iframe.get('src', '')[:50]}") - if webviews: - for w in webviews: - print(f" - webview[{w.get('index')}]: src={w.get('src', '')[:50]}") - -except Exception as e: - print(f'Error reading JSON: {e}') diff --git a/scratch_parse3.py b/scratch_parse3.py deleted file mode 100644 index ef1d9ab..0000000 --- a/scratch_parse3.py +++ /dev/null @@ -1,20 +0,0 @@ -import json - -try: - with open(r'C:\Users\Variet-Worker\.gemini\antigravity\bridge\deep-inspect-result.json', 'r', encoding='utf-8', errors='ignore') as f: - data = json.load(f) - - print("SEARCHING FOR CHAT TEXT IN DUMP...") - found = False - with open(r'C:\Users\Variet-Worker\.gemini\antigravity\bridge\deep-inspect-result.json', 'r', encoding='utf-8', errors='ignore') as f: - raw_text = f.read() - if '스스로 만들고 스스로' in raw_text: - print("YES! The chat text IS in the raw JSON dump!") - found = True - elif 'Variet' in raw_text: - print("Found Variet in dump.") - else: - print("Chat text not found in raw dump.") - -except Exception as e: - print(f'Error reading JSON: {e}') diff --git a/scratch_parse4.py b/scratch_parse4.py deleted file mode 100644 index 99cb78a..0000000 --- a/scratch_parse4.py +++ /dev/null @@ -1,18 +0,0 @@ -import json - -try: - with open(r'C:\Users\Variet-Worker\.gemini\antigravity\bridge\deep-inspect-result.json', 'r', encoding='utf-8', errors='ignore') as f: - data = json.load(f) - - for node in data.get('nodes', []): - label = node.get('label', 'unknown') - btns = node.get('buttons', []) - print(f"\n[Node] {label} (Total btns: {len(btns)})") - for i, b in enumerate(btns): - t = b.get('text', '').replace('\n', ' ').strip() - hidden = b.get("hidden") - cls = b.get("class") - print(f" {i:3d}: \"{t[:50]}\" (Hidden: {hidden}, Class: {cls[:30]})") - -except Exception as e: - print(f'Error reading JSON: {e}') diff --git a/scratch_patch_verify.js b/scratch_patch_verify.js deleted file mode 100644 index c88cbbf..0000000 --- a/scratch_patch_verify.js +++ /dev/null @@ -1,94 +0,0 @@ -/** - * html-patcher 수정 검증 스크립트 - * 실제 workbench.html + 실제 observer-script 출력물로 패치 시뮬레이션 - */ -const fs = require('fs'); -const path = require('path'); - -// 1. 실제 깨끗한 workbench.html 읽기 -const htmlPath = path.join( - process.env.LOCALAPPDATA, - 'Programs', 'Antigravity', 'resources', 'app', 'out', - 'vs', 'code', 'electron-browser', 'workbench', 'workbench.html' -); -let html = fs.readFileSync(htmlPath, 'utf8'); -console.log(`[1] Clean HTML: ${html.length} chars, ${html.split('\n').length} lines`); -console.log(` Has AG SDK: ${html.includes('AG SDK')}`); - -// 2. 실제 observer-script.ts의 출력 시뮬레이션 (generateApprovalObserverScript) -const observerModule = require('./extension/out/observer-script'); -const observerJS = observerModule.generateApprovalObserverScript(34332); -console.log(`[2] Observer JS: ${observerJS.length} chars`); -console.log(` Contains $': ${observerJS.includes("$'")}`); -console.log(` Contains ')$': ${observerJS.includes("')$")}`); - -// 3. 패치 시뮬레이션 — 수정 전 (BUG) -const inlineBlock_buggy = `\n\n`; -let html_buggy = html.replace('', `\n${inlineBlock_buggy}\n`); - -// 4. 패치 시뮬레이션 — 수정 후 (FIX) -const inlineBlock = `\n\n`; -const safeInlineBlock = inlineBlock.replace(/\$/g, '$$$$'); -let html_fixed = html.replace('', `\n${safeInlineBlock}\n`); - -console.log(`\n[3] BUGGY result: ${html_buggy.length} chars`); -console.log(`[4] FIXED result: ${html_fixed.length} chars`); - -// 5. JS 코드 추출 및 SyntaxError 검증 -function extractAndCheckJS(patchedHtml, label) { - const match = patchedHtml.match(/