|
|
|
|
@@ -1,7 +1,7 @@
|
|
|
|
|
export function generateApprovalObserverScript(_port: number): string {
|
|
|
|
|
return `
|
|
|
|
|
// ── Gravity Bridge v13: Prompt-Skip + Fallback Guard ──
|
|
|
|
|
// v13: When all code els are prompt-only, disable fallback text collection entirely
|
|
|
|
|
// ── Gravity Bridge v14: Strict Scope + Junk Filter ──
|
|
|
|
|
// v14: Strict 5-level DOM scope, CSS/source code/icon-glue filters, no 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('v13 Script loaded — Prompt-Skip + Fallback Guard');
|
|
|
|
|
log('v14 Script loaded — Strict Scope + Junk Filter');
|
|
|
|
|
|
|
|
|
|
// DIAGNOSTIC BEACON: immediate POST to confirm script execution in renderer
|
|
|
|
|
try {
|
|
|
|
|
@@ -109,40 +109,46 @@ export function generateApprovalObserverScript(_port: number): string {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// v13: 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 = /^[^\\n]*[\\/\>\xbb$#]\\s*$/;
|
|
|
|
|
// v14: Climb DOM tree to find context near the button
|
|
|
|
|
// STRICT SCOPE: Only 5 levels up — beyond that we're in unrelated UI territory.
|
|
|
|
|
// JUNK FILTERS: CSS rules, source code, Material icon gluing are all rejected.
|
|
|
|
|
// NO FALLBACK: span/div/p text collection is removed entirely — it always grabs chat/UI text.
|
|
|
|
|
var PROMPT_ONLY_RE = /^[^\\n]*[\\/\>\\xbb$#]\\s*$/;
|
|
|
|
|
// v14: Detect CSS rules, JS source code, or extension internals in code text
|
|
|
|
|
var JUNK_CODE_RE = /(!important|::selection|background-color:|var\\(--|font-size:|border-[a-z]|padding:|margin:|display:\\s|\\{[^}]*:[^}]*\\}|===|!==|\\|\\||\\bfunction\\s*\\(|\\bconst\\s+\\w+\\s*=|\\bvar\\s+\\w+\\s*=|\\bif\\s*\\(|\\breturn\\b|\\bimport\\s|\\bexport\\s|\\bclass\\s+\\w|\\bnew\\s+\\w|\\.test\\(|\\.match\\(|\\.replace\\(|_RE[.\\s]|\\brawDesc\\b|\\brawCmd\\b|\\benrichedCmd\\b|\\bquerySelector)/;
|
|
|
|
|
// v14: Detect Material icon text glued with content
|
|
|
|
|
var ICON_GLUE_RE = /(alternate_email|content_copy|content_paste|check_circle|chevron_right|chevron_left|keyboard_arrow|arrow_drop_down|arrow_drop_up|more_horiz|more_vert|expand_more|expand_less)[a-zA-Z]/;
|
|
|
|
|
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 _bestCodeText = '';
|
|
|
|
|
var _bestCodeHeader = '';
|
|
|
|
|
var _sawCodeEls = false; // v13: did we encounter any code/pre elements?
|
|
|
|
|
var _promptOnlySkipped = false; // v13: were ALL code elements prompt-only?
|
|
|
|
|
for (var depth = 0; depth < 20 && node; depth++) {
|
|
|
|
|
var _sawCodeEls = false;
|
|
|
|
|
var _allSkipped = true;
|
|
|
|
|
for (var depth = 0; depth < 5 && node; depth++) {
|
|
|
|
|
if (!node.querySelector) { _debugTrail.push('d'+depth+':noQS'); node = node.parentElement; continue; }
|
|
|
|
|
// Look for code/pre blocks (actual command text)
|
|
|
|
|
var codeEls = node.querySelectorAll('pre, code, [class*="terminal"]');
|
|
|
|
|
_debugTrail.push('d'+depth+':tag='+((node.tagName||'?').toLowerCase())+',cls='+(((typeof node.className==='string')?node.className:'').substring(0,60))+',codeEls='+codeEls.length);
|
|
|
|
|
var _depthHadCode = false;
|
|
|
|
|
var _depthAllPrompt = true;
|
|
|
|
|
for (var ci = 0; ci < codeEls.length; ci++) {
|
|
|
|
|
var codeText = cleanLines((codeEls[ci].textContent || '').trim().substring(0, 500));
|
|
|
|
|
if (!codeText || codeText.length <= 5) continue;
|
|
|
|
|
if (/^Running\\s*\\d/i.test(codeText)) continue;
|
|
|
|
|
_depthHadCode = true;
|
|
|
|
|
// v12: Skip prompt-only text (e.g. "...\gravity_control >") - no actual command
|
|
|
|
|
_sawCodeEls = true;
|
|
|
|
|
if (PROMPT_ONLY_RE.test(codeText.trim())) {
|
|
|
|
|
_debugTrail.push('skip_prompt_ci='+ci+':'+codeText.substring(0,30));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
_depthAllPrompt = false;
|
|
|
|
|
// This code element has actual content - capture it
|
|
|
|
|
if (JUNK_CODE_RE.test(codeText)) {
|
|
|
|
|
_debugTrail.push('skip_junk_ci='+ci+':'+codeText.substring(0,30));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (ICON_GLUE_RE.test(codeText)) {
|
|
|
|
|
_debugTrail.push('skip_iconglue_ci='+ci+':'+codeText.substring(0,30));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
_allSkipped = false;
|
|
|
|
|
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"]');
|
|
|
|
|
if (headerEl) {
|
|
|
|
|
var hClone = headerEl.cloneNode(true);
|
|
|
|
|
@@ -154,56 +160,21 @@ export function generateApprovalObserverScript(_port: number): string {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// v13: Track whether code elements were seen and all were prompt-only
|
|
|
|
|
if (_depthHadCode) {
|
|
|
|
|
_sawCodeEls = true;
|
|
|
|
|
if (_depthAllPrompt) _promptOnlySkipped = true;
|
|
|
|
|
}
|
|
|
|
|
// 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(' — ');
|
|
|
|
|
}
|
|
|
|
|
// v13: If we saw code elements but all were prompt-only, do NOT collect fallback text
|
|
|
|
|
// This prevents capturing chat messages / UI text from nearby DOM elements
|
|
|
|
|
if (_promptOnlySkipped) {
|
|
|
|
|
_debugTrail.push('fallback_blocked_prompt_only');
|
|
|
|
|
} else if (depth <= 8 && !_fallbackText) {
|
|
|
|
|
// v11: Look for substantial text in span/div/p as fallback context
|
|
|
|
|
var textEls = node.querySelectorAll('span, div, p');
|
|
|
|
|
for (var ti = 0; ti < Math.min(textEls.length, 20); ti++) {
|
|
|
|
|
var tText = (textEls[ti].textContent || '').trim();
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return parts.join(' \u2014 ');
|
|
|
|
|
}
|
|
|
|
|
node = node.parentElement;
|
|
|
|
|
}
|
|
|
|
|
// v13: If code elements existed but were all prompt-only, return just button text
|
|
|
|
|
// This ensures http-bridge's Run/Always run filter can handle it properly
|
|
|
|
|
if (_promptOnlySkipped) {
|
|
|
|
|
log('CONTEXT-PROMPT-ONLY trail='+_debugTrail.join(' > '));
|
|
|
|
|
if (_sawCodeEls && _allSkipped) {
|
|
|
|
|
log('CONTEXT-SKIP-ALL trail='+_debugTrail.join(' > '));
|
|
|
|
|
_lastContextDebug = _debugTrail.join(' > ');
|
|
|
|
|
return cleanButtonText(btn);
|
|
|
|
|
}
|
|
|
|
|
// 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(' > '));
|
|
|
|
|
_lastContextDebug = _debugTrail.join(' > ');
|
|
|
|
|
|