esque-bridge 0.5.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 +29 -4
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -27,6 +27,10 @@ const fs = require('fs');
27
27
  const path = require('path');
28
28
  const os = require('os');
29
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
+
30
34
  // --- Config ---------------------------------------------------------------
31
35
 
32
36
  const argv = parseArgs(process.argv.slice(2));
@@ -331,14 +335,19 @@ function runAgent(prompt, esqueSessionId) {
331
335
  usesStdin = !argv.some((a) => a.includes(prompt));
332
336
  }
333
337
 
334
- // detached its own process group so we can kill the WHOLE tree (the
335
- // agent can spawn its own subprocesses) on timeout instead of orphaning
336
- // 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.
337
345
  const child = spawn(bin, argv, {
338
346
  cwd: WORKDIR,
339
347
  env: process.env,
340
348
  stdio: ['pipe', 'pipe', 'pipe'],
341
- detached: true,
349
+ detached: !isWindows,
350
+ shell: isWindows,
342
351
  });
343
352
 
344
353
  const MAX_BUF = 16 * 1024 * 1024; // hard cap so a runaway agent can't OOM the bridge
@@ -356,6 +365,22 @@ function runAgent(prompt, esqueSessionId) {
356
365
  const rejectOnce = settle(reject);
357
366
 
358
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
+ }
359
384
  try {
360
385
  process.kill(-child.pid, signal);
361
386
  } catch {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "esque-bridge",
3
- "version": "0.5.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"