fix(observer): ensure inline script injection before </body> for Electron execution + add BEACON diagnostic ping

- html-patcher: relocate inline script from after </html> to before </body>
- html-patcher: clean up duplicate </html> tags from previous bad insertions
- observer-script: add immediate BEACON fetch to /ping on script load
- http-bridge: add diagnostic request logging for non-polling endpoints
- devlog 003: crash recovery session notes
This commit is contained in:
Variet Worker
2026-04-12 21:30:58 +09:00
parent 6dc0854c47
commit f45d2d970d
4 changed files with 58 additions and 8 deletions

View File

@@ -0,0 +1,28 @@
# Observer v8 Electron 실행 보장 + 진단 beacon 추가
- **시간**: 2026-04-12 21:00~21:30
- **Commit**: (이전 세션 크래시 복구 커밋)
## 배경
- 이전 세션(f9491880)에서 Observer v8이 렌더러에서 실행되지 않는 문제 디버깅 중 크래시 발생
- deep-inspect 엔드포인트가 `timeout` 반환 — 인라인 스크립트가 Electron에서 실행 안 됨
- 원인: 인라인 스크립트가 `</html>` 뒤에 삽입되어 Electron이 무시하는 것으로 추정
## 변경 사항
### observer-script.ts
- DIAGNOSTIC BEACON 추가: 스크립트 로드 즉시 `/ping?beacon=1`으로 fetch → 실행 여부 확인 가능
### html-patcher.ts
- 인라인 스크립트 삽입 위치를 `</html>` 앞에서 **`</body>` 앞**으로 변경
- 기존 잘못된 위치의 인라인 블록을 제거 후 재삽입하는 로직 추가
- 이전 패칭에서 발생한 중복 `</html>` 태그 정리 로직 추가
### http-bridge.ts
- 진단용 HTTP 요청 로깅 추가 (폴링 엔드포인트 제외)
## 미완료
- AG 리로드 후 observer 작동 확인 (beacon ping 수신 확인)
- deep-inspect로 실제 DOM 구조 캡처
- observer-script 셀렉터 미세조정 (bot-color 제거, MarkdownRenderer 타겟팅)
- Discord 릴레이 E2E 검증

View File

@@ -275,23 +275,33 @@ function _patchHtmlFiles(scriptDir: string, combinedScript: string, logToFile: (
logToFile(`[OBSERVER] removed external script tag from ${spec.name}`);
}
// Insert or update inline script
// Insert or update inline script — MUST be BEFORE </body> for Electron execution
const inlineMarkerStart = '<!-- AG SDK INLINE [variet-gravity-bridge] -->';
const inlineMarkerEnd = '<!-- /AG SDK INLINE [variet-gravity-bridge] -->';
const inlineBlock = `${inlineMarkerStart}\n<script>\n${combinedScript}\n</script>\n${inlineMarkerEnd}`;
if (html.includes(inlineMarkerStart)) {
// Remove existing block (may be in wrong position, e.g. after </body>)
const re = new RegExp(
inlineMarkerStart.replace(/[[\]]/g, '\\$&') +
'\\n?' + inlineMarkerStart.replace(/[[\]]/g, '\\$&') +
'[\\s\\S]*?' +
inlineMarkerEnd.replace(/[[\]]/g, '\\$&')
inlineMarkerEnd.replace(/[[\]]/g, '\\$&') + '\\n?'
);
html = html.replace(re,
`${inlineMarkerStart}\n<script>\n${combinedScript}\n</script>\n${inlineMarkerEnd}`);
logToFile(`[OBSERVER] ${spec.name} inline script UPDATED`);
html = html.replace(re, '');
// Remove duplicate </html> if present (from previous bad insertions)
html = html.replace(/(<\/html>\s*){2,}/gi, '</html>\n');
logToFile(`[OBSERVER] ${spec.name} removed old inline script block`);
}
// Insert BEFORE </body> (not </html>) to ensure Electron executes it
if (html.includes('</body>')) {
html = html.replace('</body>',
`\n${inlineBlock}\n</body>`);
logToFile(`[OBSERVER] ${spec.name} inline script INSERTED before </body>`);
} else {
// Fallback: insert before </html>
html = html.replace('</html>',
`\n${inlineMarkerStart}\n<script>\n${combinedScript}\n</script>\n${inlineMarkerEnd}\n</html>`);
logToFile(`[OBSERVER] ${spec.name} inline script INSERTED`);
`\n${inlineBlock}\n</html>`);
logToFile(`[OBSERVER] ${spec.name} inline script INSERTED before </html> (fallback)`);
}
// SAFETY: Final validation before write
if (html.length < 500 || !html.includes('<!DOCTYPE html>') || !html.includes(spec.requiredMarker)) {

View File

@@ -79,6 +79,11 @@ export function startHttpBridge(ctx: HttpBridgeContext, sdk: any): Promise<numbe
const url = new URL(req.url, `http://127.0.0.1`);
// DIAGNOSTIC: log ALL requests (except noisy polling endpoints)
if (!['/trigger-click', '/deep-inspect-trigger'].includes(url.pathname)) {
ctx.logToFile(`[HTTP-REQ] ${req.method} ${url.pathname}`);
}
// POST /pending — renderer reports a detected approval button
if (req.method === 'POST' && url.pathname === '/pending') {
_handlePending(req, res, ctx);

View File

@@ -12,6 +12,13 @@ export function generateApprovalObserverScript(_port: number): string {
function log(m){console.log('[GB Observer] '+m);}
log('v8 Script loaded — Full-DOM AG Native Parser');
// DIAGNOSTIC BEACON: immediate POST to confirm script execution in renderer
try {
fetch('http://127.0.0.1:${_port}/ping?beacon=1&t='+Date.now())
.then(function(r){log('BEACON ping OK: '+r.status);})
.catch(function(e){log('BEACON ping FAIL: '+e.message);});
} catch(e){ log('BEACON error: '+e); }
// React-Compatible Synthetic Clicker
function dispatchReactClick(el){
if (!el) return;