Release v1.01 Enhanced: Vi Control, TUI Gen5, Core Stability
This commit is contained in:
@@ -31,11 +31,12 @@ const SYSTEM_PATHS = {
|
||||
* Task Type Detection
|
||||
*/
|
||||
const TASK_PATTERNS = {
|
||||
browser: /\b(website|browser|google|youtube|amazon|navigate|search online|open.*url|go to.*\.com|fill.*form|click.*button)\b/i,
|
||||
browser: /\b(website|browser|google|youtube|amazon|navigate|search online|search\b|open.*url|go to.*\.com|fill.*form|click.*button|chrome|chromium|edge|msedge|firefox)\b/i,
|
||||
desktop: /\b(open.*app|launch|click.*menu|type.*text|press.*key|screenshot|notepad|paint|calculator|telegram|discord)\b/i,
|
||||
code: /\b(write.*code|create.*file|function|class|module|implement|code.*for|script.*for)\b/i,
|
||||
file: /\b(create.*file|write.*file|save.*to|read.*file|edit.*file|delete.*file|rename)\b/i,
|
||||
shell: /\b(run.*command|terminal|shell|npm|node|pip|git|docker)\b/i,
|
||||
server: /\b(server|service|daemon|port|localhost|endpoint|api|health|status|logs|restart|start|stop|deploy|pm2|nginx|apache|systemctl)\b/i,
|
||||
query: /\b(what|how|why|explain|tell me|describe|list|show me)\b/i
|
||||
};
|
||||
|
||||
@@ -92,17 +93,23 @@ export async function executeAny(command, options = {}) {
|
||||
psCommand = ['-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', scriptPath, ...args.split(/\s+/).filter(Boolean)];
|
||||
}
|
||||
} else {
|
||||
// Need to extract script and add proper flags
|
||||
if (match) {
|
||||
const argsStr = match[2] || '';
|
||||
// Better regex to handle arguments with spaces inside quotes
|
||||
const args = argsStr.match(/(?:[^\s"]+|"[^"]*")+/g) || [];
|
||||
const cleanArgs = args.map(a => a.startsWith('"') && a.endsWith('"') ? a.slice(1, -1) : a);
|
||||
// Normalize common forms:
|
||||
// - powershell bin/input.ps1 <args...>
|
||||
// - powershell "bin/input.ps1" <args...>
|
||||
// - bin/input.ps1 <args...>
|
||||
const psPrefixStripped = command.replace(/^powershell\s*/i, '');
|
||||
const inputPs1Match =
|
||||
psPrefixStripped.match(/["']?([^"'\s]*input\.ps1)["']?\s*(.*)/i) ||
|
||||
command.match(/["']?([^"'\s]*input\.ps1)["']?\s*(.*)/i);
|
||||
|
||||
if (inputPs1Match) {
|
||||
const argsStr = (inputPs1Match[2] || '').trim();
|
||||
const args = argsStr.match(/"[^"]*"|'[^']*'|\S+/g) || [];
|
||||
const cleanArgs = args.map(a => a.replace(/^["']|["']$/g, ''));
|
||||
psCommand = ['-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', SYSTEM_PATHS.inputPs1, ...cleanArgs];
|
||||
} else {
|
||||
// Just run the command as-is
|
||||
psCommand = ['-Command', command.replace(/^powershell\s*/i, '')];
|
||||
// Fall back to running whatever was provided (no input.ps1 detected)
|
||||
psCommand = ['-Command', psPrefixStripped];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,12 +164,12 @@ export function extractExecutables(response) {
|
||||
const executables = [];
|
||||
|
||||
// Match all code blocks
|
||||
const codeBlockRegex = /```(\w*)\n([\s\S]*?)```/g;
|
||||
const codeBlockRegex = /```(\w*)(?::run)?\r?\n([\s\S]*?)```/g;
|
||||
let match;
|
||||
|
||||
while ((match = codeBlockRegex.exec(response)) !== null) {
|
||||
const lang = match[1].toLowerCase();
|
||||
const code = match[2].trim();
|
||||
const code = match[2].replace(/\r/g, '').trim();
|
||||
|
||||
if (['bash', 'shell', 'powershell', 'ps1', 'cmd', 'sh'].includes(lang) || lang === '') {
|
||||
// Command to execute
|
||||
@@ -179,6 +186,35 @@ export function extractExecutables(response) {
|
||||
return executables;
|
||||
}
|
||||
|
||||
function fallbackExtractCommandsFromText(response) {
|
||||
const lines = String(response || '')
|
||||
.replace(/\r/g, '')
|
||||
.split('\n')
|
||||
.map(l => l.trim())
|
||||
.filter(Boolean);
|
||||
|
||||
const commands = [];
|
||||
for (const line of lines) {
|
||||
if (/^(powershell|pwsh|cmd|node|npm|pnpm|yarn|git)\b/i.test(line)) {
|
||||
commands.push(line);
|
||||
}
|
||||
}
|
||||
return commands;
|
||||
}
|
||||
|
||||
function sanitizeExtractedExecutables(executables) {
|
||||
const out = [];
|
||||
for (const e of Array.isArray(executables) ? executables : []) {
|
||||
if (!e || e.type !== 'command') continue;
|
||||
const cmd = String(e.content || '').replace(/\r/g, '').trim();
|
||||
if (!cmd) continue;
|
||||
// Prevent garbage “commands” from slipping through (covers many “half formatted” model outputs)
|
||||
if (!/^(powershell|pwsh|cmd|node|npm|pnpm|yarn|git)\b/i.test(cmd)) continue;
|
||||
out.push({ ...e, content: cmd });
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if response indicates task completion
|
||||
*/
|
||||
@@ -271,6 +307,63 @@ YOUR TASK:
|
||||
`;
|
||||
}
|
||||
|
||||
function buildTranslationPrompt(userRequest) {
|
||||
const request = String(userRequest || '');
|
||||
const looksWeb =
|
||||
/\bhttps?:\/\//i.test(request) ||
|
||||
/\bwww\./i.test(request) ||
|
||||
/\bgoogle\.com\b/i.test(request) ||
|
||||
/\b(search|browse|navigate|open\s+.*url|go\s+to)\b/i.test(request) ||
|
||||
/\b(edge|msedge|chrome|chrom(e|ium)|firefox)\b/i.test(request);
|
||||
|
||||
return [
|
||||
'You are the IQ Exchange Translation Layer.',
|
||||
'Translate the USER REQUEST into executable commands.',
|
||||
'',
|
||||
'You may output Desktop automation, Browser automation, and/or Server/Shell commands.',
|
||||
'',
|
||||
looksWeb
|
||||
? 'IMPORTANT: This is a WEB task. Use ONLY BROWSER (Playwright bridge) commands. Do NOT use Desktop (input.ps1) to open Edge/Chrome or type into the address bar.'
|
||||
: 'IMPORTANT: If the request is about websites/URLs/search, use ONLY BROWSER (Playwright bridge) commands (not Desktop).',
|
||||
'',
|
||||
'DESKTOP (Windows UIAutomation via input.ps1):',
|
||||
`powershell -NoProfile -ExecutionPolicy Bypass -File "${SYSTEM_PATHS.inputPs1}" <verb> <args...>`,
|
||||
'Verbs: open, waitfor, app_state, ocr, screenshot, focus, uiclick, uipress, type, key, hotkey, startmenu, mouse, click, drag',
|
||||
'Tip: Use `startmenu` for opening the Windows Start menu (more reliable than `key LWIN`).',
|
||||
'',
|
||||
'BROWSER (Playwright bridge):',
|
||||
`node "${SYSTEM_PATHS.playwrightBridge}" <command> <args...>`,
|
||||
'Commands: navigate <url>, click <selectorOrText>, fill <selectorOrLabel> <text>, press <key>, type <text>, url, title, content, elements, screenshot <file>, wait <selector> <ms>, close',
|
||||
'',
|
||||
'SERVER/SHELL:',
|
||||
'- Prefer safe read-only checks (status/logs) before restarts/deploys.',
|
||||
'- Use powershell/cmd as appropriate. Keep commands explicit.',
|
||||
'',
|
||||
'RULES:',
|
||||
'- Output ONLY one fenced code block.',
|
||||
'- One command per line.',
|
||||
'- Use the absolute paths exactly as shown in the templates above.',
|
||||
'- Include verification steps after actions when possible (app_state/ocr, url/title, health checks).',
|
||||
'- Prefer uiclick/uipress over mouse/click unless unavoidable.',
|
||||
'',
|
||||
`USER REQUEST: ${userRequest}`
|
||||
].join('\n');
|
||||
}
|
||||
|
||||
function buildStrictTranslationPrompt(userRequest, previousResponse = '') {
|
||||
const tail = String(previousResponse || '').slice(0, 800);
|
||||
return [
|
||||
buildTranslationPrompt(userRequest),
|
||||
'',
|
||||
'STRICT MODE (must follow):',
|
||||
'- Output EXACTLY one fenced code block and nothing else.',
|
||||
'- One command per line; no numbering; no commentary.',
|
||||
'- If no action is possible, output a single comment line explaining why (inside the code block).',
|
||||
'',
|
||||
tail ? `Previous (bad) output (for debugging):\n${tail}` : ''
|
||||
].filter(Boolean).join('\n');
|
||||
}
|
||||
|
||||
/**
|
||||
* Main IQ Exchange Class - The Universal Self-Healing Brain
|
||||
*/
|
||||
@@ -293,7 +386,25 @@ export class IQExchange {
|
||||
* This acts as the "Translation Layer"
|
||||
*/
|
||||
async translateRequest(userRequest) {
|
||||
const prompt = `
|
||||
const prompt = buildTranslationPrompt(userRequest);
|
||||
const response = await this.sendToAI(prompt);
|
||||
const extracted = sanitizeExtractedExecutables(extractExecutables(response));
|
||||
if (extracted.length > 0) return extracted;
|
||||
|
||||
const fallback = fallbackExtractCommandsFromText(response);
|
||||
if (fallback.length > 0) {
|
||||
return sanitizeExtractedExecutables(fallback.map((cmd) => ({ type: 'command', content: cmd, lang: '' })));
|
||||
}
|
||||
|
||||
// Retry once in strict mode (models sometimes ignore formatting rules on first pass)
|
||||
const strictResponse = await this.sendToAI(buildStrictTranslationPrompt(userRequest, response));
|
||||
const strictExtracted = sanitizeExtractedExecutables(extractExecutables(strictResponse));
|
||||
if (strictExtracted.length > 0) return strictExtracted;
|
||||
|
||||
const strictFallback = fallbackExtractCommandsFromText(strictResponse);
|
||||
return sanitizeExtractedExecutables(strictFallback.map((cmd) => ({ type: 'command', content: cmd, lang: '' })));
|
||||
|
||||
const legacyPrompt = `
|
||||
═══════════════════════════════════════════════════════════════════════════════════
|
||||
AVAILABLE TOOLS (WINDOWS AUTOMATION):
|
||||
═══════════════════════════════════════════════════════════════════════════════════
|
||||
@@ -339,8 +450,8 @@ powershell bin/input.ps1 type "Hello World"
|
||||
\`\`\`
|
||||
`.trim();
|
||||
|
||||
const response = await this.sendToAI(prompt);
|
||||
return extractExecutables(response);
|
||||
const legacyResponse = await this.sendToAI(legacyPrompt);
|
||||
return extractExecutables(legacyResponse);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user