AI-Repo-Commander/src/main.js

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==