From 3981fc0528685c1b0a8579dd8956a776d2fe4a8b Mon Sep 17 00:00:00 2001 From: rob Date: Thu, 9 Oct 2025 18:34:45 +0000 Subject: [PATCH] Update src/ai-repo-commander.user.js MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Two Helper Methods (added to DebugConsole class): flashBtn(btn, label, ms) - Temporarily disables button, shows checkmark feedback toast(msg, ms) - Shows temporary toast notification in bottom-right of panel 2. Enhanced All Button Click Handlers: Copy buttons - Flash "Copied ✓" and show toast Pause/Resume - Flash "Paused ✓" or "Resumed ✓" with toast STOP API - Flash "Stopped ✓" with toast Clear History - Flash "Cleared ✓" with toast Toggles & Number inputs - Show inline toast feedback Save/Reset Config - Flash button and show toast Bridge Key buttons - Flash and show toast feedback Run Again buttons - Flash "Running ✓" or "Dismissed ✓" 3. Version Bump: Updated from v1.5.1 to v1.5.2 --- src/ai-repo-commander.user.js | 103 +++++++++++++++++++++++++--------- 1 file changed, 78 insertions(+), 25 deletions(-) diff --git a/src/ai-repo-commander.user.js b/src/ai-repo-commander.user.js index 1217d0b..7dde7c6 100644 --- a/src/ai-repo-commander.user.js +++ b/src/ai-repo-commander.user.js @@ -1,7 +1,7 @@ // ==UserScript== // @name AI Repo Commander // @namespace http://tampermonkey.net/ -// @version 1.5.1 +// @version 1.5.2 // @description Execute @bridge@ YAML commands from AI assistants (safe & robust): complete-block detection, streaming-settle, persistent dedupe, paste+autosubmit, debug console with Tools/Settings, draggable/collapsible panel // @author Your Name // @match https://chat.openai.com/* @@ -36,7 +36,7 @@ // Timing & API DEBOUNCE_DELAY: 3000, MAX_RETRIES: 2, - VERSION: '1.5.1', + VERSION: '1.5.2', API_TIMEOUT_MS: 60000, PROCESS_EXISTING: false, @@ -227,6 +227,43 @@ if (this.panel) this._renderRow(entry); } + _renderRow(e) { + if (!this.bodyLogs) return; + const row = document.createElement('div'); + row.style.cssText = 'padding:4px 0;border-bottom:1px dashed #2a2a34;white-space:pre-wrap;word-break:break-word;'; + row.textContent = `${e.ts} ${e.level.padEnd(5)} ${e.msg}${e.data? ' ' + JSON.stringify(e.data): ''}`; + this.bodyLogs.appendChild(row); + while (this.bodyLogs.children.length > this.cfg.DEBUG_MAX_LINES) this.bodyLogs.firstChild.remove(); + this.bodyLogs.scrollTop = this.bodyLogs.scrollHeight; + } + + flashBtn(btn, label = 'Done', ms = 900) { + if (!btn) return; + const old = btn.textContent; + btn.disabled = true; + btn.textContent = `${label} ✓`; + btn.style.opacity = '0.7'; + setTimeout(() => { + btn.disabled = false; + btn.textContent = old; + btn.style.opacity = ''; + }, ms); + } + + toast(msg, ms = 1200) { + if (!this.panel) return; + const t = document.createElement('div'); + t.textContent = msg; + t.style.cssText = ` + position:absolute; right:12px; bottom:12px; padding:6px 10px; + background:#111827; color:#e5e7eb; border:1px solid #374151; + border-radius:6px; font:12px ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; + opacity:.98; pointer-events:none; box-shadow:0 6px 20px rgba(0,0,0,.35) + `; + this.panel.appendChild(t); + setTimeout(() => t.remove(), ms); + } + mount() { if (!document.body) { setTimeout(() => this.mount(), 100); return; } @@ -341,8 +378,17 @@ sel.value = String(this.cfg.DEBUG_LEVEL); sel.addEventListener('change', () => this.setLevel(parseInt(sel.value,10))); - root.querySelector('.rc-copy').addEventListener('click', () => this.copyLast(50)); - root.querySelector('.rc-copy-200').addEventListener('click', () => this.copyLast(200)); + root.querySelector('.rc-copy').addEventListener('click', (e) => { + this.copyLast(50); + this.flashBtn(e.currentTarget, 'Copied'); + this.toast('Copied last 50 logs'); + }); + + root.querySelector('.rc-copy-200').addEventListener('click', (e) => { + this.copyLast(200); + this.flashBtn(e.currentTarget, 'Copied'); + this.toast('Copied last 200 logs'); + }); const pauseBtn = root.querySelector('.rc-pause'); pauseBtn.addEventListener('click', () => { @@ -351,11 +397,15 @@ pauseBtn.textContent = this.cfg.RUNTIME.PAUSED ? 'Resume' : 'Pause'; pauseBtn.style.background = this.cfg.RUNTIME.PAUSED ? '#f59e0b' : ''; pauseBtn.style.color = this.cfg.RUNTIME.PAUSED ? '#111827' : ''; + this.flashBtn(pauseBtn, this.cfg.RUNTIME.PAUSED ? 'Paused' : 'Resumed'); + this.toast(this.cfg.RUNTIME.PAUSED ? 'Paused scanning' : 'Resumed scanning'); this.info(`Runtime ${this.cfg.RUNTIME.PAUSED ? 'paused' : 'resumed'}`); }); - root.querySelector('.rc-stop').addEventListener('click', () => { + root.querySelector('.rc-stop').addEventListener('click', (e) => { window.AI_REPO_STOP?.(); + this.flashBtn(e.currentTarget, 'Stopped'); + this.toast('Emergency STOP activated'); this.warn('Emergency STOP activated'); }); @@ -428,15 +478,17 @@ }; // Tools: Clear History - root.querySelector('.rc-clear-history').addEventListener('click', () => { + root.querySelector('.rc-clear-history').addEventListener('click', (e) => { try { commandMonitor?.history?.resetAll?.(); RC_DEBUG?.info('Conversation history cleared'); - GM_notification({ title: 'AI Repo Commander', text: 'This conversation\'s execution marks cleared', timeout: 2500 }); + GM_notification({ title: 'AI Repo Commander', text: 'Execution marks cleared', timeout: 2500 }); } catch { localStorage.removeItem(STORAGE_KEYS.history); RC_DEBUG?.info('Legacy history key cleared'); } + this.flashBtn(e.currentTarget, 'Cleared'); + this.toast('Conversation marks cleared'); }); // Tools: toggles & numbers @@ -446,6 +498,7 @@ inp.addEventListener('change', () => { this.cfg[key] = !!inp.checked; saveConfig(this.cfg); + this.toast(`${key} = ${this.cfg[key] ? 'on' : 'off'}`); this.info(`Config ${key} => ${this.cfg[key]}`); }); }); @@ -456,13 +509,14 @@ if (!Number.isNaN(v)) { this.cfg[inp.dataset.key] = v; saveConfig(this.cfg); + this.toast(`${inp.dataset.key} = ${v}`); this.info(`Config ${inp.dataset.key} => ${v}`); } }); }); // Tools: JSON input - root.querySelector('.rc-save-json').addEventListener('click', () => { + root.querySelector('.rc-save-json').addEventListener('click', (e) => { try { const raw = root.querySelector('.rc-json').value; const parsed = JSON.parse(raw); @@ -483,18 +537,23 @@ if (dump.BRIDGE_KEY) dump.BRIDGE_KEY = '•'.repeat(8); root.querySelector('.rc-json').value = JSON.stringify(dump, null, 2); + this.flashBtn(e.currentTarget, 'Saved'); + this.toast('Config saved'); this.info('Config JSON saved'); - } catch (e) { - this.warn('Invalid JSON in config textarea', { error: String(e) }); + } catch (err) { + this.toast('Invalid JSON', 1500); + this.warn('Invalid JSON in config textarea', { error: String(err) }); } }); - root.querySelector('.rc-reset-defaults').addEventListener('click', () => { + root.querySelector('.rc-reset-defaults').addEventListener('click', (e) => { Object.assign(this.cfg, structuredClone(DEFAULT_CONFIG)); saveConfig(this.cfg); BRIDGE_KEY = null; const bridgeKeyInput = root.querySelector('.rc-bridge-key'); if (bridgeKeyInput) bridgeKeyInput.value = ''; + this.flashBtn(e.currentTarget, 'Reset'); + this.toast('Defaults restored'); this.info('Config reset to defaults'); }); @@ -509,7 +568,7 @@ const bridgeKeyInput = root.querySelector('.rc-bridge-key'); bridgeKeyInput.value = this.cfg.BRIDGE_KEY ? '•'.repeat(8) : ''; - root.querySelector('.rc-save-bridge-key').addEventListener('click', () => { + root.querySelector('.rc-save-bridge-key').addEventListener('click', (e) => { const raw = (bridgeKeyInput.value || '').trim(); if (/^•+$/.test(raw)) { this.info('Bridge key unchanged'); @@ -520,30 +579,24 @@ saveConfig(this.cfg); BRIDGE_KEY = raw || null; bridgeKeyInput.value = this.cfg.BRIDGE_KEY ? '•'.repeat(8) : ''; + this.flashBtn(e.currentTarget, 'Saved'); + this.toast('Bridge key saved'); this.info('Bridge key saved (masked)'); GM_notification({ title: 'AI Repo Commander', text: 'Bridge key saved', timeout: 2500 }); }); - root.querySelector('.rc-clear-bridge-key').addEventListener('click', () => { + root.querySelector('.rc-clear-bridge-key').addEventListener('click', (e) => { this.cfg.BRIDGE_KEY = ''; bridgeKeyInput.value = ''; saveConfig(this.cfg); BRIDGE_KEY = null; + this.flashBtn(e.currentTarget, 'Cleared'); + this.toast('Bridge key cleared'); this.info('Bridge key cleared'); GM_notification({ title: 'AI Repo Commander', text: 'Bridge key cleared', timeout: 2500 }); }); } - _renderRow(e) { - if (!this.bodyLogs) return; - const row = document.createElement('div'); - row.style.cssText = 'padding:4px 0;border-bottom:1px dashed #2a2a34;white-space:pre-wrap;word-break:break-word;'; - row.textContent = `${e.ts} ${e.level.padEnd(5)} ${e.msg}${e.data? ' ' + JSON.stringify(e.data): ''}`; - this.bodyLogs.appendChild(row); - while (this.bodyLogs.children.length > this.cfg.DEBUG_MAX_LINES) this.bodyLogs.firstChild.remove(); - this.bodyLogs.scrollTop = this.bodyLogs.scrollHeight; - } - destroy() { try { clearInterval(this.loopCleanupInterval); } catch {} if (this.panel && this.panel.parentNode) this.panel.parentNode.removeChild(this.panel); @@ -912,8 +965,8 @@ const dismiss = document.createElement('button'); dismiss.textContent = 'Dismiss'; dismiss.style.cssText = 'padding:4px 10px; border:1px solid #374151; border-radius:4px; background:#111827; color:#9ca3af;'; - run.onclick = onRun; - dismiss.onclick = () => bar.remove(); + run.onclick = (ev) => { RC_DEBUG?.flashBtn?.(ev.currentTarget, 'Running'); onRun(); }; + dismiss.onclick = (ev) => { RC_DEBUG?.flashBtn?.(ev.currentTarget, 'Dismissed'); bar.remove(); }; bar.append(msg, run, dismiss); containerEl.appendChild(bar); }