ask.js
1 import { cli, Strategy } from '@jackwener/opencli/registry'; 2 import { SelectorError } from '@jackwener/opencli/errors'; 3 export const askCommand = cli({ 4 site: 'cursor', 5 name: 'ask', 6 description: 'Send a prompt and wait for the AI response (send + wait + read)', 7 domain: 'localhost', 8 strategy: Strategy.UI, 9 browser: true, 10 args: [ 11 { name: 'text', required: true, positional: true, help: 'Prompt to send' }, 12 { name: 'timeout', required: false, help: 'Max seconds to wait for response (default: 30)', default: '30' }, 13 ], 14 columns: ['Role', 'Text'], 15 func: async (page, kwargs) => { 16 const text = kwargs.text; 17 const timeout = parseInt(kwargs.timeout, 10) || 30; 18 // Count existing messages before sending 19 const beforeCount = await page.evaluate(` 20 document.querySelectorAll('[data-message-role]').length 21 `); 22 // Inject text into the active editor and submit 23 const injected = await page.evaluate(`(function(text) { 24 let editor = document.querySelector('.aislash-editor-input, [data-lexical-editor="true"], [contenteditable="true"]'); 25 if (!editor) return false; 26 editor.focus(); 27 document.execCommand('insertText', false, text); 28 return true; 29 })(${JSON.stringify(text)})`); 30 if (!injected) 31 throw new SelectorError('Cursor input element'); 32 await page.wait(0.5); 33 await page.pressKey('Enter'); 34 // Poll until a new assistant message appears or timeout 35 const pollInterval = 2; // seconds 36 const maxPolls = Math.ceil(timeout / pollInterval); 37 let response = ''; 38 for (let i = 0; i < maxPolls; i++) { 39 await page.wait(pollInterval); 40 const result = await page.evaluate(` 41 (function(prevCount) { 42 const msgs = document.querySelectorAll('[data-message-role]'); 43 if (msgs.length <= prevCount) return null; 44 45 const lastMsg = msgs[msgs.length - 1]; 46 const role = lastMsg.getAttribute('data-message-role'); 47 if (role === 'human') return null; // Still waiting for assistant 48 49 const root = lastMsg.querySelector('.markdown-root'); 50 const text = root ? root.innerText : lastMsg.innerText; 51 return text ? text.trim() : null; 52 })(${beforeCount}) 53 `); 54 if (result) { 55 response = result; 56 break; 57 } 58 } 59 if (!response) { 60 return [ 61 { Role: 'User', Text: text }, 62 { Role: 'System', Text: `No response received within ${timeout}s. The AI may still be generating.` }, 63 ]; 64 } 65 return [ 66 { Role: 'User', Text: text }, 67 { Role: 'Assistant', Text: response }, 68 ]; 69 }, 70 });