feat(observer): v11 — enhanced context extraction + 5-level sibling search + command enrichment (v0.5.42) #task-619

- extractContextFromNearby: span/div/p text fallback when pre/code not found (depth 0-8)
- collectSiblingButtons: extended to 5 parent levels, stop only when both action+reject found
- http-bridge: command enrichment — swap generic button text with actual command from description
- Fixes: cmd='Always run' now shows actual command text, Cancel button detection improved
This commit is contained in:
Variet Worker
2026-04-15 06:20:47 +09:00
parent 02d9799f20
commit ed63f65975
3 changed files with 58 additions and 25 deletions

View File

@@ -1,7 +1,7 @@
export function generateApprovalObserverScript(_port: number): string {
return `
// ── Gravity Bridge v9: Context-Aware AG Native Parser ──
// v9: Fixed 'Running N commands' false trigger + DOM-climbing context extraction
// ── Gravity Bridge v11: Enhanced Context Extraction ──
// v11: Extended span/div/p fallback for context, 5-level sibling search, improved command display
(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('v9 Script loaded — Context-Aware AG Native Parser');
log('v11 Script loaded — Enhanced Context Extraction');
// DIAGNOSTIC BEACON: immediate POST to confirm script execution in renderer
try {
@@ -109,11 +109,12 @@ export function generateApprovalObserverScript(_port: number): string {
return null;
}
// v9: Climb DOM tree to find pre/code content near the button (no data-step-index needed)
// v10-diag: Added diagnostic trail logging
// v11: Climb DOM tree to find context near the button
// Priority: pre/code > [class*=terminal] > substantial span/div/p text > aria-label > button text
function extractContextFromNearby(btn) {
var node = btn;
var _debugTrail = [];
var _fallbackText = ''; // Best span/div/p text found (used if no pre/code)
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)
@@ -136,30 +137,38 @@ export function generateApprovalObserverScript(_port: number): string {
var parts = [];
if (headerText) parts.push(headerText);
parts.push(codeText);
log('CONTEXT-OK d='+depth+' trail='+_debugTrail.join(' > '));
log('CONTEXT-OK d='+depth+' src=code trail='+_debugTrail.join(' > '));
_lastContextDebug = _debugTrail.join(' > ');
return parts.join(' — ');
}
}
// v10-diag: also look for any text-bearing elements (span, div, p) with substantial text
if (depth <= 5) {
// v11: Look for substantial text in span/div/p as fallback context
if (depth <= 8 && !_fallbackText) {
var textEls = node.querySelectorAll('span, div, p');
var foundTexts = [];
for (var ti = 0; ti < Math.min(textEls.length, 10); ti++) {
for (var ti = 0; ti < Math.min(textEls.length, 20); ti++) {
var tText = (textEls[ti].textContent || '').trim();
if (tText.length > 10 && tText.length < 300 && !isNoiseLine(tText)) {
foundTexts.push(tText.substring(0, 80));
if (tText.length > 10 && tText.length < 500 && !isNoiseLine(tText)) {
// Skip if it's just the button text itself
var btnTxt = cleanButtonText(btn);
if (tText !== btnTxt && tText.indexOf(btnTxt) !== 0) {
_fallbackText = tText.substring(0, 300);
_debugTrail.push('fallback_d='+depth+':'+_fallbackText.substring(0,40));
break;
}
}
}
if (foundTexts.length > 0) {
_debugTrail.push('texts=['+foundTexts.join('|')+']');
}
}
node = node.parentElement;
}
// v11: Use fallback text from span/div/p if available
if (_fallbackText && _fallbackText.length > 5) {
log('CONTEXT-OK src=fallback trail='+_debugTrail.join(' > '));
_lastContextDebug = _debugTrail.join(' > ');
return cleanLines(_fallbackText);
}
// Last resort: try aria-label or title on the button
var ariaLabel = btn.getAttribute('aria-label') || btn.getAttribute('title') || '';
log('CONTEXT-FAIL trail='+_debugTrail.join(' > '));
// v10-diag: dump button ancestor chain as diagnostic
_lastContextDebug = _debugTrail.join(' > ');
if (ariaLabel && ariaLabel.length > 5) return ariaLabel;
return cleanButtonText(btn);
@@ -233,12 +242,13 @@ export function generateApprovalObserverScript(_port: number): string {
function collectSiblingButtons(container,triggerBtn){
if(!container)return [];
// v9: Try multiple container levels (parent → grandparent → great-grandparent)
// to find all related approval buttons in wider DOM context
// v11: Try 5 container levels to find Cancel and other approval buttons
var containers = [container];
if (container.parentElement) containers.push(container.parentElement);
if (container.parentElement && container.parentElement.parentElement)
containers.push(container.parentElement.parentElement);
var cur = container;
for (var lvl = 0; lvl < 5 && cur.parentElement; lvl++) {
cur = cur.parentElement;
containers.push(cur);
}
var result=[];
var seen={};
for(var ci=0;ci<containers.length;ci++){
@@ -256,8 +266,13 @@ export function generateApprovalObserverScript(_port: number): string {
seen[stxt]=true;
result.push({btn:sb,text:stxt,isPrimary:(sb===triggerBtn)});
}
// If we found action buttons at this level, don't go wider
if(result.length > 0) break;
// v11: Only stop if we found BOTH action AND reject buttons at this level
var hasAction = false, hasReject = false;
for (var ri=0;ri<result.length;ri++) {
if (isActionBtn(result[ri].text)) hasAction = true;
if (isRejectBtn(result[ri].text)) hasReject = true;
}
if(hasAction && hasReject) break;
}
return result;
}