162 lines
6.0 KiB
JavaScript
162 lines
6.0 KiB
JavaScript
// ==MAIN START==
|
|
(function () {
|
|
'use strict';
|
|
|
|
if (!window.AI_REPO_CONFIG || !window.AI_REPO_LOGGER || !window.AI_REPO_HISTORY || !window.AI_REPO_PARSER || !window.AI_REPO_EXECUTOR) {
|
|
console.error('AI Repo Commander: Core modules not loaded');
|
|
return;
|
|
}
|
|
|
|
const logger = window.AI_REPO_LOGGER;
|
|
const config = window.AI_REPO_CONFIG;
|
|
const history = window.AI_REPO_HISTORY;
|
|
|
|
class AIRepoCommander {
|
|
constructor() {
|
|
this.isInitialized = false;
|
|
this.observer = null;
|
|
this.processed = new WeakSet();
|
|
this.messageSelectors = [
|
|
'[data-message-author-role="assistant"]',
|
|
'.chat-message:not([data-message-author-role="user"])',
|
|
'.message-content'
|
|
];
|
|
}
|
|
|
|
initialize() {
|
|
if (this.isInitialized) return;
|
|
logger.info('AI Repo Commander initializing', {
|
|
version: config.get('meta.version'),
|
|
debugLevel: config.get('debug.level'),
|
|
apiEnabled: config.get('api.enabled')
|
|
});
|
|
|
|
this.startObserver();
|
|
if (config.get('ui.processExisting')) this.scanExisting();
|
|
this.exposeAPI();
|
|
|
|
this.isInitialized = true;
|
|
logger.info('AI Repo Commander initialized');
|
|
}
|
|
|
|
startObserver() {
|
|
this.observer = new MutationObserver((mutations) => {
|
|
if (config.get('runtime.paused')) return;
|
|
for (const m of mutations) {
|
|
if (m.type !== 'childList') continue;
|
|
for (const n of m.addedNodes) {
|
|
if (n.nodeType !== 1) continue;
|
|
if (this.isAssistantMessage(n)) this.processMessage(n);
|
|
const inner = n.querySelectorAll?.(this.messageSelectors.join(',')) || [];
|
|
inner.forEach(el => this.isAssistantMessage(el) && this.processMessage(el));
|
|
}
|
|
}
|
|
});
|
|
this.observer.observe(document.body, { childList: true, subtree: true });
|
|
}
|
|
|
|
isAssistantMessage(el) {
|
|
return this.messageSelectors.some(sel => el.matches?.(sel));
|
|
}
|
|
|
|
processMessage(el) {
|
|
if (this.processed.has(el)) return;
|
|
const commands = this.extractCommands(el);
|
|
if (!commands.length) return;
|
|
|
|
this.processed.add(el);
|
|
commands.slice(0, config.get('queue.maxPerMessage')).forEach((cmdText, idx) => {
|
|
if (history.isProcessed(el, idx)) {
|
|
this.addRetryButton(el, cmdText, idx);
|
|
} else {
|
|
this.run(el, cmdText, idx);
|
|
}
|
|
});
|
|
}
|
|
|
|
extractCommands(el) {
|
|
const text = el.textContent || '';
|
|
const out = [];
|
|
const re = /@bridge@[\s\S]*?@end@/g;
|
|
let m;
|
|
while ((m = re.exec(text)) !== null) out.push(m[0]);
|
|
return out;
|
|
}
|
|
|
|
async run(el, commandText, index) {
|
|
try {
|
|
history.markProcessed(el, index);
|
|
|
|
const parsed = window.AI_REPO_PARSER.parse(commandText);
|
|
const validation = window.AI_REPO_PARSER.validate(parsed);
|
|
if (!validation.isValid) {
|
|
logger.error('Command validation failed', { errors: validation.errors, command: parsed.action });
|
|
this.addRetryButton(el, commandText, index);
|
|
return;
|
|
}
|
|
if (validation.example) {
|
|
logger.info('Skipping example command');
|
|
return;
|
|
}
|
|
|
|
await this.delay(config.get('execution.debounceDelay') || 0);
|
|
const label = `Command ${index + 1}`;
|
|
await window.AI_REPO_EXECUTOR.execute(parsed, el, label);
|
|
|
|
} catch (e) {
|
|
logger.error('Command execution failed', { error: e.message, commandIndex: index });
|
|
this.addRetryButton(el, commandText, index);
|
|
}
|
|
}
|
|
|
|
addRetryButton(el, commandText, idx) {
|
|
const btn = document.createElement('button');
|
|
btn.textContent = `Run Again #${idx + 1}`;
|
|
btn.style.cssText = `
|
|
padding:4px 8px;margin:4px;border:1px solid #374151;border-radius:4px;
|
|
background:#1f2937;color:#e5e7eb;cursor:pointer;
|
|
`;
|
|
btn.addEventListener('click', () => this.run(el, commandText, idx));
|
|
el.appendChild(btn);
|
|
}
|
|
|
|
scanExisting() {
|
|
const nodes = document.querySelectorAll(this.messageSelectors.join(','));
|
|
nodes.forEach(el => this.isAssistantMessage(el) && this.processMessage(el));
|
|
}
|
|
|
|
exposeAPI() {
|
|
window.AI_REPO_COMMANDER = {
|
|
version: config.get('meta.version'),
|
|
config,
|
|
logger,
|
|
history,
|
|
pause: () => { config.set('runtime.paused', true); logger.info('Paused'); },
|
|
resume: () => { config.set('runtime.paused', false); logger.info('Resumed'); },
|
|
clearHistory: () => { history.clear(); logger.info('History cleared'); }
|
|
};
|
|
}
|
|
|
|
delay(ms) { return new Promise(r => setTimeout(r, ms)); }
|
|
destroy() {
|
|
this.observer?.disconnect();
|
|
this.processed = new WeakSet();
|
|
this.isInitialized = false;
|
|
logger.info('AI Repo Commander destroyed');
|
|
}
|
|
}
|
|
|
|
if (document.readyState === 'loading') {
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
window.AI_REPO_MAIN = new AIRepoCommander();
|
|
window.AI_REPO_MAIN.initialize();
|
|
});
|
|
} else {
|
|
window.AI_REPO_MAIN = new AIRepoCommander();
|
|
window.AI_REPO_MAIN.initialize();
|
|
// Kick off the advanced detector (restores settle/debounce, multi-block, cluster rescan)
|
|
window.AI_REPO_DETECTOR?.start();
|
|
}
|
|
})();
|
|
// ==MAIN END==
|