claude-overnight 1.23.0 → 1.23.1

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.1";
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.1";
@@ -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,32 +464,33 @@ 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",
632
489
  };
633
- if (patchedProxy && sysNode && agentJs) {
490
+ if (sysNode && agentJs) {
634
491
  proxyEnv.CURSOR_AGENT_NODE = sysNode;
635
492
  proxyEnv.CURSOR_AGENT_SCRIPT = agentJs;
493
+ console.log(chalk.dim(` Using system node for agent subprocess: ${sysNode}`));
636
494
  }
637
495
  try {
638
496
  const child = spawn("npx", ["cursor-api-proxy"], {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-overnight",
3
- "version": "1.23.0",
3
+ "version": "1.23.1",
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.1",
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"