esque-bridge 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/index.js +65 -5
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -13,6 +13,7 @@
13
13
  * through the configured agent adapter, returning stdout
14
14
  *
15
15
  * npx esque-bridge # default: claude
16
+ * npx esque-bridge --agent codex # OpenAI Codex (ChatGPT) on this repo
16
17
  * npx esque-bridge --agent aider # Aider against the current repo
17
18
  * npx esque-bridge --agent custom --cmd 'mycli --prompt {prompt}'
18
19
  */
@@ -26,6 +27,10 @@ const fs = require('fs');
26
27
  const path = require('path');
27
28
  const os = require('os');
28
29
 
30
+ // Windows has no POSIX process groups or `.cmd`-aware spawn, so several
31
+ // process-management paths below branch on this.
32
+ const isWindows = process.platform === 'win32';
33
+
29
34
  // --- Config ---------------------------------------------------------------
30
35
 
31
36
  const argv = parseArgs(process.argv.slice(2));
@@ -36,13 +41,15 @@ if (argv.help || argv.h) {
36
41
  Esque Bridge — pair your phone with a local coding-agent CLI.
37
42
 
38
43
  USAGE
39
- esque-bridge [--agent claude|aider|custom] [--port 3030] [--workdir .]
44
+ esque-bridge [--agent claude|codex|aider|custom] [--port 3030] [--workdir .]
40
45
  [--cmd 'tool --prompt {prompt}'] [--bin <binary>]
41
46
  [--timeout 300000]
42
47
 
43
48
  AGENT ADAPTERS
44
49
  claude (default) — uses Claude Code CLI (\`claude --print --output-format json\`).
45
50
  Persists session ids so each conversation continues via --resume.
51
+ codex — uses OpenAI Codex CLI (\`codex exec\`, headless, auto-approve).
52
+ Drive ChatGPT's coding agent with your ChatGPT plan or API key.
46
53
  aider — uses Aider CLI (\`aider --message ... --yes-always --no-stream\`).
47
54
  Conversation continuity is handled by aider's own .aider.chat.history.md.
48
55
  custom — runs an arbitrary command. Pass --cmd 'tool --prompt {prompt}'
@@ -59,6 +66,7 @@ OPTIONS
59
66
 
60
67
  PREREQS
61
68
  Claude: npm install -g @anthropic-ai/claude-code && claude /login
69
+ Codex: npm install -g @openai/codex && codex login
62
70
  Aider: python -m pip install aider-chat
63
71
 
64
72
  OUTPUT
@@ -201,6 +209,37 @@ const ADAPTERS = {
201
209
  },
202
210
  },
203
211
 
212
+ codex: {
213
+ label: 'Codex',
214
+ defaultBin: 'codex',
215
+ install:
216
+ 'npm install -g @openai/codex, then `codex login` (ChatGPT plan or API key).',
217
+ // `exec` is Codex's non-interactive mode. The bypass flag is Codex's
218
+ // analogue of Claude's --dangerously-skip-permissions: in headless mode
219
+ // there's no human to approve file writes / shell commands (incl. the
220
+ // network installs a fresh scaffold needs), so without it the agent
221
+ // looks busy but can't touch the disk. Access is already gated by the
222
+ // pairing secret + the startup workdir confirmation. --skip-git-repo-check
223
+ // lets it run in a brand-new (not-yet-git) project dir for `fresh` builds.
224
+ buildArgs(_prompt, _prevSessionId) {
225
+ return [
226
+ 'exec',
227
+ '--dangerously-bypass-approvals-and-sandbox',
228
+ '--skip-git-repo-check',
229
+ ];
230
+ },
231
+ parseOutput(stdout) {
232
+ // `codex exec` streams its run to stdout and logs to stderr; the trimmed
233
+ // stdout is the agent's reply. (Codex has no stable resume-by-id we rely
234
+ // on here, so each turn is self-contained — Esque re-sends repo context.)
235
+ return {
236
+ text: stdout.trim() || '(codex returned no output)',
237
+ cliSessionId: null,
238
+ isError: false,
239
+ };
240
+ },
241
+ },
242
+
204
243
  aider: {
205
244
  label: 'Aider',
206
245
  defaultBin: 'aider',
@@ -296,14 +335,19 @@ function runAgent(prompt, esqueSessionId) {
296
335
  usesStdin = !argv.some((a) => a.includes(prompt));
297
336
  }
298
337
 
299
- // detached its own process group so we can kill the WHOLE tree (the
300
- // agent can spawn its own subprocesses) on timeout instead of orphaning
301
- // zombies.
338
+ // POSIX: detach into its own process group so we can kill the WHOLE tree
339
+ // (the agent spawns subprocesses) on timeout instead of orphaning zombies.
340
+ // Windows: no detach (it would pop a console window) — we kill the tree
341
+ // via `taskkill /T` instead; and `shell: true` so spawn can resolve the
342
+ // `.cmd` shims npm installs global bins as (claude.cmd / codex.cmd). Our
343
+ // built-in adapters pass fixed flag args (the prompt rides via stdin), so
344
+ // there's no shell-injection surface here.
302
345
  const child = spawn(bin, argv, {
303
346
  cwd: WORKDIR,
304
347
  env: process.env,
305
348
  stdio: ['pipe', 'pipe', 'pipe'],
306
- detached: true,
349
+ detached: !isWindows,
350
+ shell: isWindows,
307
351
  });
308
352
 
309
353
  const MAX_BUF = 16 * 1024 * 1024; // hard cap so a runaway agent can't OOM the bridge
@@ -321,6 +365,22 @@ function runAgent(prompt, esqueSessionId) {
321
365
  const rejectOnce = settle(reject);
322
366
 
323
367
  const killTree = (signal) => {
368
+ if (isWindows) {
369
+ // No process groups on Windows; force-kill the whole tree by PID.
370
+ // Signals don't map, so SIGTERM/SIGKILL both become a /F force-kill.
371
+ try {
372
+ spawn('taskkill', ['/pid', String(child.pid), '/T', '/F'], {
373
+ stdio: 'ignore',
374
+ });
375
+ } catch {
376
+ try {
377
+ child.kill();
378
+ } catch {
379
+ /* already gone */
380
+ }
381
+ }
382
+ return;
383
+ }
324
384
  try {
325
385
  process.kill(-child.pid, signal);
326
386
  } catch {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "esque-bridge",
3
- "version": "0.4.0",
3
+ "version": "0.6.0",
4
4
  "description": "Desktop-side receiver for the Esque Agent mobile app. Pairs your phone with a local coding-agent CLI (Claude Code, Aider, or any custom command) via a tunnel + QR code, so prompts run through your subscription instead of per-token API billing.",
5
5
  "bin": {
6
6
  "esque-bridge": "index.js"