/ clis / codex / 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: 'codex',
 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: 60)', default: '60' },
13      ],
14      columns: ['Role', 'Text'],
15      func: async (page, kwargs) => {
16          const text = kwargs.text;
17          const timeout = parseInt(kwargs.timeout, 10) || 60;
18          // Snapshot the current content length before sending
19          const beforeLen = await page.evaluate(`
20        (function() {
21          const turns = document.querySelectorAll('[data-content-search-turn-key]');
22          return turns.length;
23        })()
24      `);
25          // Inject and send
26          const injected = await page.evaluate(`
27        (function(text) {
28          const editables = Array.from(document.querySelectorAll('[contenteditable="true"]'));
29          const composer = editables.length > 0 ? editables[editables.length - 1] : document.querySelector('textarea');
30          if (!composer) return false;
31          composer.focus();
32          document.execCommand('insertText', false, text);
33          return true;
34        })(${JSON.stringify(text)})
35      `);
36          if (!injected)
37              throw new SelectorError('Codex input element');
38          await page.wait(0.5);
39          await page.pressKey('Enter');
40          // Poll for new content
41          const pollInterval = 3;
42          const maxPolls = Math.ceil(timeout / pollInterval);
43          let response = '';
44          for (let i = 0; i < maxPolls; i++) {
45              await page.wait(pollInterval);
46              const result = await page.evaluate(`
47          (function(prevLen) {
48            const turns = document.querySelectorAll('[data-content-search-turn-key]');
49            if (turns.length <= prevLen) return null;
50            const lastTurn = turns[turns.length - 1];
51            const text = lastTurn.innerText || lastTurn.textContent;
52            return text ? text.trim() : null;
53          })(${beforeLen})
54        `);
55              if (result) {
56                  response = result;
57                  break;
58              }
59          }
60          if (!response) {
61              return [
62                  { Role: 'User', Text: text },
63                  { Role: 'System', Text: `No response within ${timeout}s. The agent may still be working.` },
64              ];
65          }
66          return [
67              { Role: 'User', Text: text },
68              { Role: 'Assistant', Text: response },
69          ];
70      },
71  });