claude-overnight 1.23.0 → 1.23.2

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.
@@ -1 +1 @@
1
- export declare const VERSION = "1.23.0";
1
+ export declare const VERSION = "1.23.2";
package/dist/_version.js CHANGED
@@ -1,2 +1,2 @@
1
1
  // Auto-generated by build — do not edit manually.
2
- export const VERSION = "1.23.0";
2
+ export const VERSION = "1.23.2";
package/dist/index.js CHANGED
@@ -221,7 +221,7 @@ async function main() {
221
221
  const proxyUp = await healthCheckCursorProxy();
222
222
  if (!proxyUp) {
223
223
  console.warn(chalk.yellow(`\n ⚠ ${savedCursorProviders.length} Cursor provider(s) saved but proxy is not running at ${PROXY_DEFAULT_URL}`));
224
- console.warn(chalk.yellow(` Start it: npx cursor-api-proxy`));
224
+ console.warn(chalk.yellow(` Start it: npx @claude-overnight/cursor-api-proxy`));
225
225
  console.warn(chalk.dim(` (Continuing — you can still use Anthropic models)\n`));
226
226
  }
227
227
  }
@@ -740,7 +740,8 @@ async function main() {
740
740
  setPlannerEnvResolver(envForModel);
741
741
  // Fail fast if a custom provider is misconfigured -- one bad key would
742
742
  // otherwise surface as N agent failures scattered across the run.
743
- if (plannerProvider || workerProvider || fastProvider) {
743
+ // Skip when NO_PREFLIGHT=1 (used by e2e tests).
744
+ if ((plannerProvider || workerProvider || fastProvider) && process.env.NO_PREFLIGHT !== "1") {
744
745
  const seen = new Set();
745
746
  const all = [
746
747
  ["planner", plannerProvider],
@@ -767,7 +768,7 @@ async function main() {
767
768
  if (!result.ok) {
768
769
  console.error(chalk.red(` ✗ ${role} preflight failed: ${chalk.dim(result.error)}`));
769
770
  if (isCursorProxyProvider(provider)) {
770
- console.error(chalk.yellow(` The proxy at ${PROXY_DEFAULT_URL} may have crashed. Start it: npx cursor-api-proxy`));
771
+ console.error(chalk.yellow(` The proxy at ${PROXY_DEFAULT_URL} may have crashed. Start it: npx @claude-overnight/cursor-api-proxy`));
771
772
  }
772
773
  else {
773
774
  console.error(chalk.red(` Fix the provider at ~/.claude/claude-overnight/providers.json and retry.`));
@@ -69,18 +69,14 @@ export declare function fetchCursorModels(baseUrl?: string): Promise<string[]>;
69
69
  /**
70
70
  * Auto-start the cursor-api-proxy as a detached background process.
71
71
  *
72
- * When the proxy is started, we also configure it to use system Node.js
73
- * for spawning the cursor-agent subprocess. The agent's bundled Node.js
74
- * segfaults with --list-models on macOS (exit 139), so we resolve the
75
- * system `node` binary and the agent's index.js, patch the proxy's env.js
76
- * to respect CURSOR_AGENT_NODE/SCRIPT on Unix, and pass those env vars.
72
+ * Passes CURSOR_AGENT_NODE/SCRIPT so the fork uses system Node.js for the
73
+ * agent subprocess (avoids segfaults with --list-models on macOS).
77
74
  *
78
75
  * Handles:
79
76
  * - Proxy already running and verified → returns true immediately
80
- * - Something on the port but not our proxy → warns, skips spawn
81
- * - Port in use by nothing responsive returns true (something bound it)
82
- * - Proxy not running spawns `npx cursor-api-proxy` detached, waits for health
83
- * - Spawn fails (not installed) → returns false, caller falls back to manual instructions
77
+ * - Something on the port but not our proxy → warns, kills, restarts
78
+ * - Proxy not runningspawns detached, waits for health
79
+ * - Spawn failsreturns false, caller falls back to manual instructions
84
80
  *
85
81
  * When `forceRestart` is true and a stale process is on the port, it will be
86
82
  * killed and the proxy restarted.
package/dist/providers.js CHANGED
@@ -1,4 +1,4 @@
1
- import { readFileSync, writeFileSync, mkdirSync, existsSync, chmodSync, realpathSync, readdirSync } from "fs";
1
+ import { readFileSync, writeFileSync, mkdirSync, existsSync, chmodSync, realpathSync } from "fs";
2
2
  import { homedir } from "os";
3
3
  import { join, dirname } from "path";
4
4
  import { execSync, spawn } from "child_process";
@@ -413,148 +413,17 @@ async function isPortInUse(port, host = "127.0.0.1") {
413
413
  return false;
414
414
  }
415
415
  }
416
- /**
417
- * Find the system `node` binary path. Uses `which` to bypass any bundled node.
418
- */
419
- function resolveSystemNode() {
420
- try {
421
- return execSync("which node 2>/dev/null", {
422
- timeout: 3_000, encoding: "utf-8", shell: "bash",
423
- }).trim() || null;
424
- }
425
- catch {
426
- return null;
427
- }
428
- }
429
- /**
430
- * Find the cursor-agent's index.js. Mirrors the logic in fetchLiveCursorModels:
431
- * resolves the `agent` symlink to find the version directory containing index.js.
432
- */
433
- function resolveAgentIndexJs() {
434
- try {
435
- const agentPath = execSync("command -v agent 2>/dev/null || command -v cursor-agent 2>/dev/null", {
436
- timeout: 3_000, encoding: "utf-8", shell: "bash",
437
- }).trim();
438
- if (!agentPath)
439
- return null;
440
- const dir = dirname(realpathSync(agentPath));
441
- const indexPath = `${dir}/index.js`;
442
- return existsSync(indexPath) ? indexPath : null;
443
- }
444
- catch {
445
- return null;
446
- }
447
- }
448
- /**
449
- * Patch the proxy's env.js to use CURSOR_AGENT_NODE + CURSOR_AGENT_SCRIPT on Unix.
450
- *
451
- * The proxy already reads these env vars (lines 152-153 of env.js) but only uses
452
- * them on Windows in resolveAgentCommand(). We inject a Unix code path before the
453
- * final `return { command: cmd, args, env }` so that when these vars are set,
454
- * the proxy spawns system node with the agent script instead of the bundled node
455
- * (which segfaults with --list-models on macOS).
456
- *
457
- * Safe to call repeatedly — the patch is idempotent.
458
- */
459
- function patchProxyEnvJs(proxyDir) {
460
- const envJs = join(proxyDir, "dist", "lib", "env.js");
461
- if (!existsSync(envJs))
462
- return false;
463
- const src = readFileSync(envJs, "utf-8");
464
- // Check if already patched
465
- if (src.includes("/* claude-overnight patch */"))
466
- return true;
467
- const patch = `\n/* claude-overnight patch: use CURSOR_AGENT_NODE+SCRIPT on unix */\n` +
468
- `if (platform !== "win32" && loaded.agentNode && loaded.agentScript) {\n` +
469
- ` return { command: loaded.agentNode, args: [loaded.agentScript, ...args], env: { ...env, CURSOR_INVOKED_AS: "agent" }, agentScriptPath: loaded.agentScript };\n` +
470
- `}`;
471
- // Insert before the final return in resolveAgentCommand
472
- const target = " return { command: cmd, args, env };\n}";
473
- if (!src.includes(target)) {
474
- // Try minified variant
475
- const target2 = "return{command:cmd,args,env}}";
476
- if (!src.includes(target2))
477
- return false;
478
- writeFileSync(envJs, src.replace(target2, patch + "\n" + target2), "utf-8");
479
- }
480
- else {
481
- writeFileSync(envJs, src.replace(target, patch + "\n" + target), "utf-8");
482
- }
483
- return true;
484
- }
485
- /**
486
- * Patch the proxy's token-cache.js to skip the macOS keychain read.
487
- *
488
- * The proxy calls `security find-generic-password -s "cursor-access-token" -w`
489
- * after every agent run to cache tokens for its multi-account pool feature.
490
- * This triggers a macOS keychain popup even though the key is not needed for
491
- * auth (the cursor-agent subprocess handles its own auth). We neutralize it.
492
- *
493
- * Safe to call repeatedly — the patch is idempotent.
494
- */
495
- function patchProxyTokenCacheJs(proxyDir) {
496
- const tcJs = join(proxyDir, "dist", "lib", "token-cache.js");
497
- if (!existsSync(tcJs))
498
- return false;
499
- const src = readFileSync(tcJs, "utf-8");
500
- // Check if already patched
501
- if (src.includes("/* claude-overnight patch: skip keychain */"))
502
- return true;
503
- const patch = `\n/* claude-overnight patch: skip keychain */\n` +
504
- `return undefined;`;
505
- // Replace the entire execSync chain inside readKeychainToken (multi-line)
506
- const target = `const t = execSync('security find-generic-password -s "cursor-access-token" -w', { stdio: ["pipe", "pipe", "pipe"], timeout: 5000 })
507
- .toString()
508
- .trim();`;
509
- if (!src.includes(target))
510
- return false;
511
- writeFileSync(tcJs, src.replace(target, patch + "\n// " + target.replace(/\n/g, "\n// ")), "utf-8");
512
- return true;
513
- }
514
- /**
515
- * Find the cursor-api-proxy package directory (npx cache or global install).
516
- */
517
- function findProxyPackageDir() {
518
- try {
519
- // Try npx cache first
520
- const npmCacheRoot = join(homedir(), ".npm", "_npx");
521
- if (existsSync(npmCacheRoot)) {
522
- const dirs = readdirSync(npmCacheRoot);
523
- for (const d of dirs) {
524
- const candidate = join(npmCacheRoot, d, "node_modules", "cursor-api-proxy");
525
- if (existsSync(join(candidate, "dist", "lib", "env.js")))
526
- return candidate;
527
- }
528
- }
529
- }
530
- catch { }
531
- // Try global install
532
- try {
533
- const globalDir = execSync("npm root -g 2>/dev/null", {
534
- timeout: 5_000, encoding: "utf-8", shell: "bash",
535
- }).trim();
536
- if (globalDir && existsSync(join(globalDir, "cursor-api-proxy", "dist", "lib", "env.js"))) {
537
- return join(globalDir, "cursor-api-proxy");
538
- }
539
- }
540
- catch { }
541
- return null;
542
- }
543
416
  /**
544
417
  * Auto-start the cursor-api-proxy as a detached background process.
545
418
  *
546
- * When the proxy is started, we also configure it to use system Node.js
547
- * for spawning the cursor-agent subprocess. The agent's bundled Node.js
548
- * segfaults with --list-models on macOS (exit 139), so we resolve the
549
- * system `node` binary and the agent's index.js, patch the proxy's env.js
550
- * to respect CURSOR_AGENT_NODE/SCRIPT on Unix, and pass those env vars.
419
+ * Passes CURSOR_AGENT_NODE/SCRIPT so the fork uses system Node.js for the
420
+ * agent subprocess (avoids segfaults with --list-models on macOS).
551
421
  *
552
422
  * Handles:
553
423
  * - Proxy already running and verified → returns true immediately
554
- * - Something on the port but not our proxy → warns, skips spawn
555
- * - Port in use by nothing responsive returns true (something bound it)
556
- * - Proxy not running spawns `npx cursor-api-proxy` detached, waits for health
557
- * - Spawn fails (not installed) → returns false, caller falls back to manual instructions
424
+ * - Something on the port but not our proxy → warns, kills, restarts
425
+ * - Proxy not runningspawns detached, waits for health
426
+ * - Spawn failsreturns false, caller falls back to manual instructions
558
427
  *
559
428
  * When `forceRestart` is true and a stale process is on the port, it will be
560
429
  * killed and the proxy restarted.
@@ -564,20 +433,8 @@ function findProxyPackageDir() {
564
433
  export async function ensureCursorProxyRunning(baseUrl = PROXY_DEFAULT_URL, forceRestart = false) {
565
434
  const url = new URL(baseUrl);
566
435
  const port = parseInt(url.port, 10) || 80;
567
- // Always patch the npx cache on startup so proxy skips keychain reads.
568
- // Idempotent — safe to call on every run.
569
- const proxyDir = findProxyPackageDir();
570
- if (proxyDir)
571
- patchProxyTokenCacheJs(proxyDir);
572
436
  // Already healthy?
573
437
  if (await healthCheckCursorProxy(baseUrl)) {
574
- // Proxy was running before the patch — restart it to load the patched token-cache.js.
575
- console.log(chalk.dim(` Proxy already running — restarting to pick up keychain patch…`));
576
- const killedPid = killProcessOnPort(port, url.hostname);
577
- if (killedPid) {
578
- await new Promise(r => setTimeout(r, 500));
579
- return startProxyProcess(baseUrl, url, port);
580
- }
581
438
  return true;
582
439
  }
583
440
  // Something bound the port — verify it's actually the cursor proxy
@@ -607,35 +464,37 @@ export async function ensureCursorProxyRunning(baseUrl = PROXY_DEFAULT_URL, forc
607
464
  /** Spawn the proxy process and wait for it to become healthy. */
608
465
  async function startProxyProcess(baseUrl, url, port) {
609
466
  console.log(chalk.yellow(`\n Proxy not running at ${baseUrl} — starting it for you…`));
610
- // Resolve system node and agent index.js so the proxy doesn't use the
611
- // agent's bundled node (segfaults with --list-models on macOS).
612
- const sysNode = resolveSystemNode();
613
- const agentJs = resolveAgentIndexJs();
614
- let patchedProxy = false;
615
- if (sysNode && agentJs) {
616
- const proxyDir = findProxyPackageDir();
617
- if (proxyDir) {
618
- patchedProxy = patchProxyEnvJs(proxyDir);
619
- if (patchedProxy) {
620
- console.log(chalk.dim(` Using system node for agent subprocess: ${sysNode}`));
621
- }
622
- else {
623
- console.log(chalk.yellow(` ⚠ Couldn't patch proxy env.js — /v1/models may fail`));
624
- }
467
+ // Resolve system node and agent index.js so the proxy uses system Node.js
468
+ // for the agent subprocess (avoids segfaults with --list-models on macOS).
469
+ let sysNode = null;
470
+ let agentJs = null;
471
+ try {
472
+ sysNode = execSync("which node 2>/dev/null", { timeout: 3_000, encoding: "utf-8", shell: "bash" }).trim() || null;
473
+ const agentPath = execSync("command -v agent 2>/dev/null || command -v cursor-agent 2>/dev/null", {
474
+ timeout: 3_000, encoding: "utf-8", shell: "bash",
475
+ }).trim();
476
+ if (agentPath) {
477
+ const agentDir = dirname(realpathSync(agentPath));
478
+ const indexPath = `${agentDir}/index.js`;
479
+ if (existsSync(indexPath))
480
+ agentJs = indexPath;
625
481
  }
626
482
  }
483
+ catch { }
627
484
  const proxyEnv = {
628
485
  ...Object.fromEntries(Object.entries(process.env).filter(([, v]) => v !== undefined)),
629
486
  CURSOR_BRIDGE_API_KEY: process.env.CURSOR_BRIDGE_API_KEY
630
487
  || loadProviders().find(p => p.cursorProxy)?.cursorApiKey
631
488
  || "unused",
489
+ CURSOR_SKIP_KEYCHAIN: "1",
632
490
  };
633
- if (patchedProxy && sysNode && agentJs) {
491
+ if (sysNode && agentJs) {
634
492
  proxyEnv.CURSOR_AGENT_NODE = sysNode;
635
493
  proxyEnv.CURSOR_AGENT_SCRIPT = agentJs;
494
+ console.log(chalk.dim(` Using system node for agent subprocess: ${sysNode}`));
636
495
  }
637
496
  try {
638
- const child = spawn("npx", ["cursor-api-proxy"], {
497
+ const child = spawn("npx", ["@claude-overnight/cursor-api-proxy"], {
639
498
  detached: true,
640
499
  stdio: "ignore",
641
500
  env: proxyEnv,
@@ -689,15 +548,15 @@ function setupSteps() {
689
548
  label: "cursor-api-proxy server",
690
549
  check: () => {
691
550
  try {
692
- execSync("npx cursor-api-proxy --help", { stdio: "pipe", timeout: 10_000 });
551
+ execSync("npx @claude-overnight/cursor-api-proxy --help", { stdio: "pipe", timeout: 10_000 });
693
552
  return true;
694
553
  }
695
554
  catch {
696
555
  return false;
697
556
  }
698
557
  },
699
- autoCmd: "npx cursor-api-proxy",
700
- manualCmd: "npx cursor-api-proxy",
558
+ autoCmd: "npx @claude-overnight/cursor-api-proxy",
559
+ manualCmd: "npx @claude-overnight/cursor-api-proxy",
701
560
  successMsg: "cursor-api-proxy available",
702
561
  },
703
562
  ];
@@ -812,24 +671,24 @@ export async function setupCursorProxy() {
812
671
  if (choice === "a") {
813
672
  console.log(chalk.dim(` Checking install…`));
814
673
  try {
815
- execSync("npx cursor-api-proxy --help", { stdio: "pipe", timeout: 15_000 });
674
+ execSync("npx @claude-overnight/cursor-api-proxy --help", { stdio: "pipe", timeout: 15_000 });
816
675
  console.log(chalk.green(` ✓ cursor-api-proxy is installed`));
817
676
  }
818
677
  catch {
819
678
  console.log(chalk.dim(` Installing…`));
820
679
  try {
821
- execSync("npm install -g cursor-api-proxy", { stdio: "inherit", timeout: 120_000 });
680
+ execSync("npm install -g @claude-overnight/cursor-api-proxy", { stdio: "inherit", timeout: 120_000 });
822
681
  console.log(chalk.green(` ✓ Installed`));
823
682
  }
824
683
  catch {
825
- console.log(chalk.yellow(" Install failed — try manual: npm install -g cursor-api-proxy"));
684
+ console.log(chalk.yellow(" Install failed — try manual: npm install -g @claude-overnight/cursor-api-proxy"));
826
685
  return false;
827
686
  }
828
687
  }
829
688
  }
830
689
  else if (choice === "m") {
831
- console.log(chalk.cyan(`\n Install: ${chalk.bold("npm install -g cursor-api-proxy")}`));
832
- console.log(chalk.cyan(` Start: ${chalk.bold("npx cursor-api-proxy")}\n`));
690
+ console.log(chalk.cyan(`\n Install: ${chalk.bold("npm install -g @claude-overnight/cursor-api-proxy")}`));
691
+ console.log(chalk.cyan(` Start: ${chalk.bold("npx @claude-overnight/cursor-api-proxy")}\n`));
833
692
  const ok = await selectKey(` Started it?`, [
834
693
  { key: "r", desc: "eady" },
835
694
  { key: "c", desc: "ancel" },
@@ -847,7 +706,7 @@ export async function setupCursorProxy() {
847
706
  return true;
848
707
  // Auto-start failed or not responding — offer manual fallback
849
708
  console.log(chalk.yellow(`\n Couldn't start the proxy automatically. Start it manually:`));
850
- console.log(chalk.white(` ${chalk.bold("npx cursor-api-proxy")}`));
709
+ console.log(chalk.white(` ${chalk.bold("npx @claude-overnight/cursor-api-proxy")}`));
851
710
  for (;;) {
852
711
  const choice = await selectKey(` Proxy started?`, [
853
712
  { key: "r", desc: "etry (re-attempt auto-start + kill stale)" },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-overnight",
3
- "version": "1.23.0",
3
+ "version": "1.23.2",
4
4
  "description": "Background lane for your Claude Max plan. Parallel Claude Agent SDK sessions in git worktrees with a usage cap that reserves headroom for your interactive Claude Code. Crash-safe resume. Provider-agnostic model catalog with capability-based planning.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -15,6 +15,7 @@
15
15
  },
16
16
  "dependencies": {
17
17
  "@anthropic-ai/claude-agent-sdk": "^0.2.92",
18
+ "@claude-overnight/cursor-api-proxy": "file:../cursor-api-proxy",
18
19
  "chalk": "^5.4.1",
19
20
  "jsonwebtoken": "^9.0.2"
20
21
  },
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-overnight",
3
- "version": "1.23.0",
3
+ "version": "1.23.2",
4
4
  "description": "Claude Code skill for understanding, installing, and inspecting claude-overnight runs -- parallel Claude agents in git worktrees with thinking waves, multi-wave steering, and crash-safe resume. Supports Cursor API Proxy, Qwen, OpenRouter.",
5
5
  "author": {
6
6
  "name": "Francesco Fornace"