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:
28
docs/devlog/entries/20260412-003.md
Normal file
28
docs/devlog/entries/20260412-003.md
Normal 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 검증
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user