fix(observer): v12 — skip prompt-only code text + enrichment validation (v0.5.44) #task-619

- extractContextFromNearby: PROMPT_ONLY_RE skips code elements containing only terminal prompts (e.g. '\\gravity_control >')
- Multi-codeEl traversal: tries all code elements at each depth, picks longest non-prompt text
- http-bridge enrichment: validates extracted command is not just a prompt fragment before enriching
- Fixes: cmd='\\gravity_control >' (prompt-only) no longer sent to Discord as the command text
This commit is contained in:
Variet Worker
2026-04-15 07:43:15 +09:00
parent 59ddcbb612
commit 7ee5947b32
3 changed files with 43 additions and 19 deletions

View File

@@ -1,7 +1,7 @@
export function generateApprovalObserverScript(_port: number): string {
return `
// ── Gravity Bridge v11: Enhanced Context Extraction ──
// v11: Extended span/div/p fallback for context, 5-level sibling search, improved command display
// ── Gravity Bridge v12: Prompt-Skip + Multi-CodeEl Context Extraction ──
// v12: Skip prompt-only code text, try all codeEls, improved enrichment fallback
(function(){
'use strict';
var BASE='',_obs=false,_sent={},_ready=false;
@@ -10,7 +10,7 @@ export function generateApprovalObserverScript(_port: number): string {
var CLEANUP_MS=300000;
function log(m){console.log('[GB Observer] '+m);}
log('v11 Script loaded — Enhanced Context Extraction');
log('v12 Script loaded — Prompt-Skip Context Extraction');
// DIAGNOSTIC BEACON: immediate POST to confirm script execution in renderer
try {
@@ -109,12 +109,16 @@ export function generateApprovalObserverScript(_port: number): string {
return null;
}
// v11: Climb DOM tree to find context near the button
// Priority: pre/code > [class*=terminal] > substantial span/div/p text > aria-label > button text
// v12: Climb DOM tree to find context near the button
// Priority: pre/code (skip prompt-only) > substantial span/div/p text > aria-label > button text
// PROMPT_ONLY: matches terminal prompts like "...\project >" or "PS C:\...>" with no actual command
var PROMPT_ONLY_RE = /^(.*[\\/>»$#]\\s*)$/;
function extractContextFromNearby(btn) {
var node = btn;
var _debugTrail = [];
var _fallbackText = ''; // Best span/div/p text found (used if no pre/code)
var _bestCodeText = ''; // Best code text found across all depths
var _bestCodeHeader = '';
for (var depth = 0; depth < 20 && node; depth++) {
if (!node.querySelector) { _debugTrail.push('d'+depth+':noQS'); node = node.parentElement; continue; }
// Look for code/pre blocks (actual command text)
@@ -122,26 +126,37 @@ export function generateApprovalObserverScript(_port: number): string {
_debugTrail.push('d'+depth+':tag='+((node.tagName||'?').toLowerCase())+',cls='+(((typeof node.className==='string')?node.className:'').substring(0,60))+',codeEls='+codeEls.length);
for (var ci = 0; ci < codeEls.length; ci++) {
var codeText = cleanLines((codeEls[ci].textContent || '').trim().substring(0, 500));
if (codeText && codeText.length > 5 && !/^Running\\s*\\d/i.test(codeText)) {
if (!codeText || codeText.length <= 5) continue;
if (/^Running\\s*\\d/i.test(codeText)) continue;
// v12: Skip prompt-only text (e.g. "...\gravity_control >") - no actual command
if (PROMPT_ONLY_RE.test(codeText.trim())) {
_debugTrail.push('skip_prompt_ci='+ci+':'+codeText.substring(0,30));
continue;
}
// This code element has actual content - capture it
if (!_bestCodeText || codeText.length > _bestCodeText.length) {
_bestCodeText = codeText;
// Also try to get a header/title near this container
var headerEl = node.querySelector('h1, h2, h3, [class*="header"], [class*="title"], [class*="cursor-pointer"]');
var headerText = '';
if (headerEl) {
var hClone = headerEl.cloneNode(true);
var hRem = hClone.querySelectorAll('button, svg, [class*="icon"], .google-symbols');
for (var hi = 0; hi < hRem.length; hi++) {
if (hRem[hi].parentNode) hRem[hi].parentNode.removeChild(hRem[hi]);
}
headerText = cleanLines((hClone.textContent || '').trim().substring(0, 200));
_bestCodeHeader = cleanLines((hClone.textContent || '').trim().substring(0, 200));
}
var parts = [];
if (headerText) parts.push(headerText);
parts.push(codeText);
log('CONTEXT-OK d='+depth+' src=code trail='+_debugTrail.join(' > '));
_lastContextDebug = _debugTrail.join(' > ');
return parts.join(' — ');
}
}
// v12: If we found a good code text, return it immediately at this depth
if (_bestCodeText) {
var parts = [];
if (_bestCodeHeader) parts.push(_bestCodeHeader);
parts.push(_bestCodeText);
log('CONTEXT-OK d='+depth+' src=code trail='+_debugTrail.join(' > '));
_lastContextDebug = _debugTrail.join(' > ');
return parts.join(' — ');
}
// v11: Look for substantial text in span/div/p as fallback context
if (depth <= 8 && !_fallbackText) {
var textEls = node.querySelectorAll('span, div, p');