also looking at this
feat(engine): answer texts with Codex as well as Claude Code
#7
18 files
+1080
-142
Review threads live on the whole diff, not on one commit, so none are shown here - a thread's line means something in the branch's final form, and painting it into an intermediate step would put it on code it is not about.
| @@ -224,6 +224,7 @@ export async function startDesktopAgent(options: { version: string }): Promise<D | ||
| 224 | 224 | name: 'Read Messages', |
| 225 | 225 | ok: messages !== null, |
| 226 | 226 | detail: messages ? 'Full Disk Access granted' : (messagesError ?? 'Waiting for Full Disk Access'), |
| 227 | informational: false, | |
| 227 | 228 | }, |
| 228 | 229 | ...allEngines(config).map((engine) => { |
| 229 | 230 | const state = engines.get(engine.id) |
| @@ -245,6 +246,7 @@ export async function startDesktopAgent(options: { version: string }): Promise<D | ||
| 245 | 246 | name: 'Who can text it', |
| 246 | 247 | ok: allowed.length > 0, |
| 247 | 248 | detail: allowed.length > 0 ? allowed.join(', ') : 'No handles yet. Sign in to Messages, or add your number.', |
| 249 | informational: false, | |
| 248 | 250 | }, |
| 249 | 251 | ] |
| 250 | 252 | // An engine the person has not selected must not hold the app in setup. |
| @@ -64,8 +64,17 @@ function engine(bin: string, overrides: Partial<{ model: string | null, permissi | ||
| 64 | 64 | }) |
| 65 | 65 | } |
| 66 | 66 | |
| 67 | /** | |
| 68 | * The flags, one per line. The prompt is deliberately excluded: it carries the | |
| 69 | * system prompt and is many lines long, so it would otherwise be scattered | |
| 70 | * across this array. Use `rawArgsOf` to assert on it. | |
| 71 | */ | |
| 67 | 72 | function argsOf(bin: string): string[] { |
| 68 | return readFileSync(`${bin}.args`, 'utf8').trim().split('\n') | |
| 73 | return rawArgsOf(bin).split('\n').filter(line => line.startsWith('-') || !line.includes(' ')) | |
| 74 | } | |
| 75 | ||
| 76 | function rawArgsOf(bin: string): string { | |
| 77 | return readFileSync(`${bin}.args`, 'utf8').trim() | |
| 69 | 78 | } |
| 70 | 79 | |
| 71 | 80 | describe('CodexEngine', () => { |
| @@ -102,9 +111,11 @@ describe('CodexEngine', () => { | ||
| 102 | 111 | expect(args).toContain('--json') |
| 103 | 112 | expect(args.slice(args.indexOf('--cd'), args.indexOf('--cd') + 2)).toEqual(['--cd', dir]) |
| 104 | 113 | expect(args).toContain('--dangerously-bypass-approvals-and-sandbox') |
| 105 | // No --append-system-prompt exists, so the instructions ride on the prompt. | |
| 106 | expect(args[args.length - 1]).toContain('Answer in plain text.') | |
| 107 | expect(args[args.length - 1]).toContain('scores?') | |
| 114 | // No --append-system-prompt exists, so the instructions ride on the prompt, | |
| 115 | // which is why the prompt is many lines and the last argv line is not it. | |
| 116 | const raw = rawArgsOf(bin) | |
| 117 | expect(raw).toContain('Answer in plain text.') | |
| 118 | expect(raw).toEndWith('scores?') | |
| 108 | 119 | expect(readFileSync(`${bin}.cwd`, 'utf8').trim()).toEndWith(dir.replace(/^\/private/, '')) |
| 109 | 120 | }) |
| 110 | 121 | |