/ clis / cursor / ask.js
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  });