Update src/ai-repo-commander.user.js

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
This commit is contained in:
rob 2025-10-09 18:34:45 +00:00
parent f341ffb39e
commit 3981fc0528
1 changed files with 78 additions and 25 deletions

View File

@ -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);
}