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:
parent
f341ffb39e
commit
3981fc0528
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue