claude-overnight 1.25.29 → 1.25.30

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.25.29";
1
+ export declare const VERSION = "1.25.30";
package/dist/_version.js CHANGED
@@ -1,2 +1,2 @@
1
1
  // Auto-generated by build — do not edit manually.
2
- export const VERSION = "1.25.29";
2
+ export const VERSION = "1.25.30";
package/dist/index.js CHANGED
@@ -10,6 +10,7 @@ import { planTasks, refinePlan, identifyThemes, buildThinkingTasks, orchestrate,
10
10
  import { modelDisplayName, formatContextWindow, DEFAULT_MODEL } from "./models.js";
11
11
  import { setPlannerEnvResolver } from "./planner-query.js";
12
12
  import { setTranscriptRunDir } from "./transcripts.js";
13
+ import { getProxyPort, buildProxyUrl } from "./proxy-port.js";
13
14
  import { pickModel, loadProviders, preflightProvider, buildEnvResolver, healthCheckCursorProxy, PROXY_DEFAULT_URL, isCursorProxyProvider, readCursorProxyLogTail, ensureCursorProxyRunning, bundledComposerProxyShellCommand, warnMacCursorAgentShellPatchIfNeeded, hasCursorAgentToken, } from "./providers.js";
14
15
  import { RunDisplay } from "./ui.js";
15
16
  import { renderSummary, wrap } from "./render.js";
@@ -889,7 +890,18 @@ async function main() {
889
890
  }
890
891
  // Auto-start cursor proxy before pinging (restarts when a token exists so stale listeners get CURSOR_API_KEY).
891
892
  if (cursorProxies.length > 0) {
892
- await ensureCursorProxyRunning();
893
+ const resolvedPort = getProxyPort(cwd);
894
+ const resolvedUrl = buildProxyUrl(resolvedPort);
895
+ await ensureCursorProxyRunning(resolvedUrl);
896
+ // Sync providers to the resolved port (may differ from default if per-project port was picked)
897
+ for (const p of cursorProxies) {
898
+ if (!p.baseURL || p.baseURL === PROXY_DEFAULT_URL) {
899
+ p.baseURL = resolvedUrl;
900
+ }
901
+ }
902
+ if (resolvedUrl !== PROXY_DEFAULT_URL) {
903
+ console.log(chalk.dim(` Proxy port: ${resolvedPort}`));
904
+ }
893
905
  if (!hasCursorAgentToken()) {
894
906
  console.error(chalk.red(` ✗ Cursor models require a User API key — add it via ${chalk.bold("Cursor…")} setup, or set ` +
895
907
  `${chalk.bold("CURSOR_API_KEY")} / ${chalk.bold("CURSOR_BRIDGE_API_KEY")}, or ${chalk.bold("cursorApiKey")} in providers.json.`));
@@ -108,6 +108,11 @@ export declare function healthCheckCursorProxy(baseUrl?: string): Promise<boolea
108
108
  * Returns model IDs like ["auto", "composer", "composer-2", "opus-4.6", ...].
109
109
  */
110
110
  export declare function fetchCursorModels(baseUrl?: string): Promise<string[]>;
111
+ /** Options for {@link ensureCursorProxyRunning}. */
112
+ export interface EnsureProxyOptions {
113
+ forceRestart?: boolean;
114
+ projectRoot?: string;
115
+ }
111
116
  /**
112
117
  * Auto-start the cursor-composer-in-claude as a detached background process.
113
118
  *
@@ -123,9 +128,13 @@ export declare function fetchCursorModels(baseUrl?: string): Promise<string[]>;
123
128
  * When `forceRestart` is true, any listener on the port is killed and the
124
129
  * bundled proxy is spawned (same as a version mismatch).
125
130
  *
126
- * Returns true when the proxy is reachable at PROXY_DEFAULT_URL.
131
+ * When `projectRoot` is provided and `baseUrl` is the default, a per-project
132
+ * port is resolved from `.claude-overnight/config.json` so concurrent runs
133
+ * in different repos don't collide on port 8765.
134
+ *
135
+ * Returns true when the proxy is reachable.
127
136
  */
128
- export declare function ensureCursorProxyRunning(baseUrl?: string, forceRestart?: boolean): Promise<boolean>;
137
+ export declare function ensureCursorProxyRunning(baseUrl?: string, opts?: EnsureProxyOptions): Promise<boolean>;
129
138
  /**
130
139
  * Full install + configure flow for cursor-composer-in-claude.
131
140
  * Walks through CLI install, API key config, and proxy start.
package/dist/providers.js CHANGED
@@ -11,6 +11,7 @@ import { getBearerToken, clearTokenCache } from "./auth.js";
11
11
  import { DEFAULT_MODEL } from "./models.js";
12
12
  import { CURSOR_PRIORITY_MODELS, CURSOR_KNOWN_MODELS, KNOWN_CURSOR_MODEL_IDS, cursorModelHint, } from "./cursor-models.js";
13
13
  import { VERSION } from "./_version.js";
14
+ import { getProxyPort, buildProxyUrl } from "./proxy-port.js";
14
15
  /** Cached system Node.js and agent script paths — resolved once, reused across envFor calls. */
15
16
  let _cachedAgentNode = null;
16
17
  let _cachedAgentScript = null;
@@ -812,13 +813,23 @@ async function isPortInUse(port, host = "127.0.0.1") {
812
813
  * When `forceRestart` is true, any listener on the port is killed and the
813
814
  * bundled proxy is spawned (same as a version mismatch).
814
815
  *
815
- * Returns true when the proxy is reachable at PROXY_DEFAULT_URL.
816
+ * When `projectRoot` is provided and `baseUrl` is the default, a per-project
817
+ * port is resolved from `.claude-overnight/config.json` so concurrent runs
818
+ * in different repos don't collide on port 8765.
819
+ *
820
+ * Returns true when the proxy is reachable.
816
821
  */
817
- export async function ensureCursorProxyRunning(baseUrl = PROXY_DEFAULT_URL, forceRestart = false) {
822
+ export async function ensureCursorProxyRunning(baseUrl = PROXY_DEFAULT_URL, opts) {
818
823
  warnMacCursorAgentShellPatchIfNeeded();
819
- const url = new URL(baseUrl);
820
- const port = parseInt(url.port, 10) || 80;
821
- // Stale listener on :8765 may have been started without CURSOR_API_KEY for the agent child.
824
+ // Resolve per-project port if no explicit base URL was given and projectRoot is available
825
+ const resolvedPort = opts?.projectRoot && baseUrl === PROXY_DEFAULT_URL
826
+ ? getProxyPort(opts.projectRoot)
827
+ : null;
828
+ const effectiveBaseUrl = resolvedPort != null ? buildProxyUrl(resolvedPort) : baseUrl;
829
+ const url = new URL(effectiveBaseUrl);
830
+ const port = resolvedPort ?? (parseInt(url.port, 10) || 80);
831
+ const forceRestart = opts?.forceRestart ?? false;
832
+ // Stale listener may have been started without CURSOR_API_KEY for the agent child.
822
833
  // When we have a token, replace the listener by default so the bundled proxy always inherits it.
823
834
  // Opt out: CURSOR_OVERNIGHT_NO_PROXY_RESTART=1 (e.g. shared port / external proxy).
824
835
  const token = resolveCursorAgentToken();
@@ -961,7 +972,7 @@ async function startProxyProcess(baseUrl, url, port) {
961
972
  catch { }
962
973
  const logFd = openSync(logPath, "a");
963
974
  console.log(chalk.dim(` Spawning proxy… ${chalk.dim(`(logs: ${logPath})`)}`));
964
- const child = spawn(process.execPath, [composerCli], {
975
+ const child = spawn(process.execPath, [composerCli, "--port", String(port)], {
965
976
  detached: true,
966
977
  stdio: ["ignore", logFd, logFd],
967
978
  env: proxyEnv,
@@ -1196,7 +1207,7 @@ export async function setupCursorProxy() {
1196
1207
  { key: "c", desc: "ancel" },
1197
1208
  ]);
1198
1209
  if (choice === "r") {
1199
- if (await ensureCursorProxyRunning(PROXY_DEFAULT_URL, true)) {
1210
+ if (await ensureCursorProxyRunning(PROXY_DEFAULT_URL, { forceRestart: true })) {
1200
1211
  console.log(chalk.green("\n ✓ Proxy is running and healthy"));
1201
1212
  return true;
1202
1213
  }
@@ -1262,7 +1273,7 @@ async function pickCursorModel() {
1262
1273
  { key: "c", desc: "ancel" },
1263
1274
  ]);
1264
1275
  if (choice === "r") {
1265
- if (await ensureCursorProxyRunning(PROXY_DEFAULT_URL, true)) {
1276
+ if (await ensureCursorProxyRunning(PROXY_DEFAULT_URL, { forceRestart: true })) {
1266
1277
  console.log(chalk.green(" ✓ Proxy started"));
1267
1278
  break;
1268
1279
  }
@@ -0,0 +1,4 @@
1
+ /** Resolve proxy port (reads from config, or allocates and persists a new one). */
2
+ export declare function getProxyPort(projectRoot: string): number;
3
+ /** Build the full proxy URL for a per-project port. */
4
+ export declare function buildProxyUrl(port: number): string;
@@ -0,0 +1,28 @@
1
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
2
+ import { join } from "path";
3
+ const CONFIG_FILE = "config.json";
4
+ /** Resolve proxy port (reads from config, or allocates and persists a new one). */
5
+ export function getProxyPort(projectRoot) {
6
+ const dir = join(projectRoot, ".claude-overnight");
7
+ const file = join(dir, CONFIG_FILE);
8
+ try {
9
+ const cfg = JSON.parse(readFileSync(file, "utf-8"));
10
+ if (typeof cfg.proxyPort === "number" && cfg.proxyPort >= 1024 && cfg.proxyPort <= 65535) {
11
+ return cfg.proxyPort;
12
+ }
13
+ }
14
+ catch { /* not found or malformed */ }
15
+ const port = 61000 + Math.floor(Math.random() * 4536);
16
+ try {
17
+ if (!existsSync(dir))
18
+ mkdirSync(dir, { recursive: true });
19
+ const existing = existsSync(file) ? JSON.parse(readFileSync(file, "utf-8")) : {};
20
+ writeFileSync(file, JSON.stringify({ ...existing, proxyPort: port }, null, 2));
21
+ }
22
+ catch { /* best effort */ }
23
+ return port;
24
+ }
25
+ /** Build the full proxy URL for a per-project port. */
26
+ export function buildProxyUrl(port) {
27
+ return `http://127.0.0.1:${port}`;
28
+ }
package/dist/swarm.js CHANGED
@@ -5,7 +5,7 @@ import chalk from "chalk";
5
5
  import { query } from "@anthropic-ai/claude-agent-sdk";
6
6
  import { NudgeError, RATE_LIMIT_WINDOW_SHORT, extractToolTarget, sumUsageTokens } from "./types.js";
7
7
  import { gitExec, autoCommit, mergeAllBranches, warnDirtyTree, cleanStaleWorktrees, writeSwarmLog } from "./merge.js";
8
- import { ensureCursorProxyRunning } from "./providers.js";
8
+ import { ensureCursorProxyRunning, PROXY_DEFAULT_URL } from "./providers.js";
9
9
  import { getModelCapability } from "./models.js";
10
10
  import { createTurn, beginTurn, endTurn, updateTurn } from "./turns.js";
11
11
  const SIMPLIFY_PROMPT = `You just finished your task. Now review and simplify your changes.
@@ -330,7 +330,7 @@ export class Swarm {
330
330
  // attempt to restart it before the next task.
331
331
  if (this.config.cursorProxy) {
332
332
  this.log(-1, " Checking cursor proxy health…");
333
- const restarted = await ensureCursorProxyRunning();
333
+ const restarted = await ensureCursorProxyRunning(PROXY_DEFAULT_URL, { projectRoot: this.config.cwd });
334
334
  if (!restarted) {
335
335
  this.log(-1, chalk.yellow(" ⚠ Proxy still down — remaining tasks may fail"));
336
336
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-overnight",
3
- "version": "1.25.29",
3
+ "version": "1.25.30",
4
4
  "description": "Parallel Claude agents in git worktrees with a usage cap that reserves headroom for your interactive Claude Code. Crash-safe resume. Provider-agnostic model catalog (Anthropic, Cursor, OpenAI, Gemini, DeepSeek, Llama, Qwen) with capability-based task scoping.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-overnight",
3
- "version": "1.25.29",
3
+ "version": "1.25.30",
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"