diff --git a/src/ai-repo-commander.user.js b/src/ai-repo-commander.user.js index c108747..cdd2d7c 100644 --- a/src/ai-repo-commander.user.js +++ b/src/ai-repo-commander.user.js @@ -18,7 +18,7 @@ // ---------------------- Config ---------------------- const CONFIG = { - ENABLE_API: false, // Master kill switch + ENABLE_API: true, // Master kill switch DEBUG_MODE: true, // Console logs DEBOUNCE_DELAY: 5000, // Bot typing protection MAX_RETRIES: 2, // Retry attempts (=> up to MAX_RETRIES+1 total tries) @@ -35,8 +35,8 @@ // ---------------------- Platform selectors ---------------------- const PLATFORM_SELECTORS = { - 'chat.openai.com': { messages: '[class*="message"]', input: '#prompt-textarea', content: '[class*="markdown"]' }, - 'chatgpt.com': { messages: '[class*="message"]', input: '#prompt-textarea', content: '[class*="markdown"]' }, + 'chat.openai.com': { messages: '[data-message-author-role]', input: '#prompt-textarea, textarea, [contenteditable="true"]', content: '.markdown' }, + 'chatgpt.com': { messages: '[data-message-author-role]', input: '#prompt-textarea, textarea, [contenteditable="true"]', content: '.markdown' }, 'claude.ai': { messages: '.chat-message', input: '[contenteditable="true"]', content: '.content' }, 'gemini.google.com': { messages: '.message-content', input: 'textarea, [contenteditable="true"]', content: '.message-text' } }; @@ -145,7 +145,7 @@ // defaults parsed.url = parsed.url || 'https://n8n.brrd.tech/webhook/ai-gitea-bridge'; - parsed.owner = parsed.owner || 'brrd'; + parsed.owner = parsed.owner || 'rob'; // expand owner/repo shorthand if (parsed.repo && typeof parsed.repo === 'string' && parsed.repo.includes('/')) { @@ -158,7 +158,7 @@ static extractCommandBlock(text) { // require ^%$bridge ... --- (tolerate trailing spaces and EOF) - const m = text.match(/^\^%\$bridge[ \t]*\n([\s\S]*?)\n---[ \t]*(?:\n|$)/m); + const m = text.match(/^\s*\^%\$bridge[ \t]*\n([\s\S]*?)\n---[ \t]*(?:\n|$)/m); return m ? m[1].trimEnd() : null; } @@ -350,7 +350,7 @@ } scanNode(node) { - if (node.querySelector && node.querySelector(this.currentPlatform.messages)) this.scanMessages(); + if (node.querySelector) this.scanMessages(); } scanExistingMessages() { setTimeout(() => this.scanMessages(), 1000); } @@ -376,11 +376,17 @@ extractText(element) { const c = element.querySelector(this.currentPlatform.content); - return (c ? c.textContent : element.textContent) || ''; + const target = c || element; + return (target.textContent || '').trim(); } // Always ignore commands shown inside code/pre blocks so you can discuss examples safely hasBridgeInCodeBlock(element) { + // If this is an assistant message, allow execution even when rendered as code. + // Rationale: assistant YAML often renders as
. We still want to execute.
+ const isAssistant = !!element.closest?.('[data-message-author-role="assistant"]');
+ if (isAssistant) return false;
+
const nodes = element.querySelectorAll('pre, code');
for (const el of nodes) {
if ((el.textContent || '').includes('^%$bridge')) return true;
@@ -402,7 +408,7 @@
if (!text) return;
// Require a full ^%$bridge ... --- block to avoid false positives
- const m = text.match(/^\^%\$bridge[ \t]*\n([\s\S]*?)\n---[ \t]*(?:\n|$)/m);
+ const m = text.match(/^\s*\^%\$bridge[ \t]*\n([\s\S]*?)\n---[ \t]*(?:\n|$)/m);
if (!m) return;
const wholeBlock = m[0];