claude-overnight 1.17.3 → 1.18.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.
@@ -0,0 +1,14 @@
1
+ export declare const CURSOR_PRIORITY_MODELS: Array<{
2
+ id: string;
3
+ label: string;
4
+ hint: string;
5
+ }>;
6
+ export declare const CURSOR_KNOWN_MODELS: Array<{
7
+ id: string;
8
+ label: string;
9
+ hint: string;
10
+ }>;
11
+ /** All known model IDs as a Set for quick membership checks. */
12
+ export declare const KNOWN_CURSOR_MODEL_IDS: Set<string>;
13
+ /** Display hint for a model ID — known ones get a hint, unknowns get a generic label. */
14
+ export declare function cursorModelHint(modelId: string): string;
@@ -0,0 +1,50 @@
1
+ // ── Cursor model constants ──
2
+ //
3
+ // Hardcoded model IDs returned by the Cursor API Proxy. These serve as a
4
+ // fallback when `agent --list-models` crashes (the bundled Node.js binary
5
+ // segfaults on some setups — the proxy inherits this bug).
6
+ //
7
+ // Update this list when Cursor adds/removes models. Run:
8
+ // node ~/.local/share/cursor-agent/versions/*/index.js --list-models
9
+ // to get the current list.
10
+ //
11
+ // The `priority` models always appear at the top of the picker in this order.
12
+ // `known` models appear after them. Anything the proxy returns dynamically
13
+ // that isn't in this list goes into a "more..." sub-menu.
14
+ import { CURSOR_MODEL_HINTS } from "./models.js";
15
+ export const CURSOR_PRIORITY_MODELS = [
16
+ { id: "composer-2", label: "composer-2", hint: "Cursor Composer 2 — latest, strongest Cursor model" },
17
+ { id: "composer-2-fast", label: "composer-2-fast", hint: "Cursor Composer 2 Fast — faster, cheaper variant" },
18
+ { id: "auto", label: "auto", hint: "auto-delegates to the best available model" },
19
+ ];
20
+ export const CURSOR_KNOWN_MODELS = [
21
+ { id: "composer", label: "composer", hint: "Cursor Composer — previous generation" },
22
+ ];
23
+ /** All known model IDs as a Set for quick membership checks. */
24
+ export const KNOWN_CURSOR_MODEL_IDS = new Set([
25
+ ...CURSOR_PRIORITY_MODELS.map(m => m.id),
26
+ ...CURSOR_KNOWN_MODELS.map(m => m.id),
27
+ ]);
28
+ /** Display hint for a model ID — known ones get a hint, unknowns get a generic label. */
29
+ export function cursorModelHint(modelId) {
30
+ const m = modelId.toLowerCase();
31
+ for (const entry of [...CURSOR_PRIORITY_MODELS, ...CURSOR_KNOWN_MODELS]) {
32
+ if (entry.id === m)
33
+ return entry.hint;
34
+ }
35
+ if (m.startsWith("composer"))
36
+ return "Cursor Composer model";
37
+ if (m.includes("opus"))
38
+ return CURSOR_MODEL_HINTS.opus;
39
+ if (m.includes("sonnet"))
40
+ return CURSOR_MODEL_HINTS.sonnet;
41
+ if (m.includes("haiku"))
42
+ return CURSOR_MODEL_HINTS.haiku;
43
+ if (m.startsWith("gpt-5"))
44
+ return "GPT model via Cursor";
45
+ if (m.startsWith("gemini"))
46
+ return "Gemini model via Cursor";
47
+ if (m.startsWith("grok"))
48
+ return "Grok model via Cursor";
49
+ return "Cursor model";
50
+ }
package/dist/index.js CHANGED
@@ -10,6 +10,7 @@ import { query } from "@anthropic-ai/claude-agent-sdk";
10
10
  import { Swarm } from "./swarm.js";
11
11
  import { planTasks, refinePlan, identifyThemes, buildThinkingTasks, orchestrate, salvageFromFile } from "./planner.js";
12
12
  import { detectModelTier, setPlannerEnvResolver } from "./planner-query.js";
13
+ import { DEFAULT_MODEL } from "./models.js";
13
14
  import { pickModel, loadProviders, preflightProvider, buildEnvResolver, healthCheckCursorProxy, PROXY_DEFAULT_URL, isCursorProxyProvider } from "./providers.js";
14
15
  import { RunDisplay } from "./ui.js";
15
16
  import { renderSummary } from "./render.js";
@@ -665,7 +666,7 @@ async function main() {
665
666
  const defaultModel = activeProvider?.model
666
667
  ?? models[0]?.value
667
668
  ?? savedForCLI.find(p => p !== activeProvider)?.model
668
- ?? "claude-sonnet-4-6";
669
+ ?? DEFAULT_MODEL;
669
670
  workerModel = cliFlags.model ?? fileCfg?.model ?? defaultModel;
670
671
  plannerModel = activeProvider?.model ?? models[0]?.value ?? workerModel;
671
672
  // Auto-resolve a saved custom provider if --model matches its id or model id.
@@ -0,0 +1,27 @@
1
+ export declare const MODEL_TIER_OPUS = "opus";
2
+ export declare const MODEL_TIER_SONNET = "sonnet";
3
+ export declare const MODEL_TIER_HAIKU = "haiku";
4
+ export declare const MODEL_TIER_UNKNOWN = "unknown";
5
+ export type ModelTier = typeof MODEL_TIER_OPUS | typeof MODEL_TIER_SONNET | typeof MODEL_TIER_HAIKU | typeof MODEL_TIER_UNKNOWN;
6
+ export interface TierDetectionRule {
7
+ match: (model: string) => boolean;
8
+ tier: ModelTier;
9
+ }
10
+ export declare const TIER_DETECTION_RULES: TierDetectionRule[];
11
+ export declare function detectModelTier(model: string): ModelTier;
12
+ export declare const MODEL_CAPABILITY_DESCRIPTIONS: Record<ModelTier, string>;
13
+ export declare const UNKNOWN_MODEL_CAPABILITIES: Record<string, string>;
14
+ export declare function modelCapabilityBlock(model: string): string;
15
+ export declare const DEFAULT_MODEL = "claude-sonnet-4-6";
16
+ export declare const FALLBACK_MODEL = "claude-opus-4-6";
17
+ export declare const PLANNER_THRESHOLDS: {
18
+ opus: {
19
+ small: number;
20
+ medium: number;
21
+ };
22
+ default: {
23
+ small: number;
24
+ medium: number;
25
+ };
26
+ };
27
+ export declare const CURSOR_MODEL_HINTS: Record<string, string>;
package/dist/models.js ADDED
@@ -0,0 +1,60 @@
1
+ // ── Model tier constants ──
2
+ export const MODEL_TIER_OPUS = "opus";
3
+ export const MODEL_TIER_SONNET = "sonnet";
4
+ export const MODEL_TIER_HAIKU = "haiku";
5
+ export const MODEL_TIER_UNKNOWN = "unknown";
6
+ export const TIER_DETECTION_RULES = [
7
+ { match: m => m === "default" || m.includes("opus"), tier: MODEL_TIER_OPUS },
8
+ { match: m => m.includes("sonnet"), tier: MODEL_TIER_SONNET },
9
+ { match: m => m.includes("haiku"), tier: MODEL_TIER_HAIKU },
10
+ { match: m => m === "auto", tier: MODEL_TIER_UNKNOWN },
11
+ { match: m => m.startsWith("composer"), tier: MODEL_TIER_SONNET },
12
+ { match: m => m.startsWith("gpt-5") || m.startsWith("gemini") || m.startsWith("grok"), tier: MODEL_TIER_SONNET },
13
+ ];
14
+ export function detectModelTier(model) {
15
+ const m = model.toLowerCase();
16
+ for (const rule of TIER_DETECTION_RULES) {
17
+ if (rule.match(m))
18
+ return rule.tier;
19
+ }
20
+ return MODEL_TIER_UNKNOWN;
21
+ }
22
+ // ── Capability descriptions ──
23
+ export const MODEL_CAPABILITY_DESCRIPTIONS = {
24
+ opus: "Each agent runs Claude Opus with 1M context -- a powerhouse. It can own entire epics, do deep codebase research, make architectural decisions, implement complex multi-file systems end-to-end, use browser tools for analysis, and deliver expert-level work. These agents can work for 30+ minutes on the most complex tasks. Do NOT waste them on trivial edits -- give them ownership and autonomy.",
25
+ sonnet: "Each agent runs Claude Sonnet -- capable of substantial implementation, refactoring, testing, and design work. Can work autonomously for 10-20 minutes on complex tasks. Give agents meaningful scope -- not just single-line edits.",
26
+ haiku: "Each agent runs Claude Haiku -- fast and efficient, best for focused, well-specified tasks. Be explicit about files, functions, and expected changes. Keep tasks scoped to a clear, concrete deliverable.",
27
+ unknown: "", // handled by UNKNOWN_MODEL_CAPABILITIES below
28
+ };
29
+ export const UNKNOWN_MODEL_CAPABILITIES = {
30
+ composer: "Each agent runs a Cursor Composer model with full codebase access. Capable of focused implementation work. Be explicit about files, functions, and expected changes.",
31
+ "gpt-5": "Each agent runs a GPT model via Cursor with full codebase access. Capable of focused implementation work. Be explicit about files, functions, and expected changes.",
32
+ gemini: "Each agent runs a Gemini model via Cursor with full codebase access. Be explicit about files, functions, and expected changes.",
33
+ grok: "Each agent runs a Grok model via Cursor with full codebase access. Be explicit about files, functions, and expected changes.",
34
+ };
35
+ export function modelCapabilityBlock(model) {
36
+ const tier = detectModelTier(model);
37
+ const cap = MODEL_CAPABILITY_DESCRIPTIONS[tier];
38
+ if (cap)
39
+ return cap;
40
+ const m = model.toLowerCase();
41
+ for (const [prefix, desc] of Object.entries(UNKNOWN_MODEL_CAPABILITIES)) {
42
+ if (m.startsWith(prefix))
43
+ return desc;
44
+ }
45
+ return `Each agent has full codebase access and can work autonomously.`;
46
+ }
47
+ // ── Default / fallback models ──
48
+ export const DEFAULT_MODEL = "claude-sonnet-4-6";
49
+ export const FALLBACK_MODEL = "claude-opus-4-6"; // used for planner + worker recovery
50
+ // ── Planner thresholds (opus-tuned vs default) ──
51
+ export const PLANNER_THRESHOLDS = {
52
+ opus: { small: 5, medium: 30 },
53
+ default: { small: 15, medium: 50 },
54
+ };
55
+ // ── Cursor model hints ──
56
+ export const CURSOR_MODEL_HINTS = {
57
+ opus: "Opus-tier model via Cursor",
58
+ sonnet: "Sonnet-tier model via Cursor",
59
+ haiku: "Haiku-tier model via Cursor (fast)",
60
+ };
@@ -1,4 +1,6 @@
1
1
  import type { Task, PermMode, RateLimitWindow } from "./types.js";
2
+ import { detectModelTier, modelCapabilityBlock } from "./models.js";
3
+ export { detectModelTier, modelCapabilityBlock };
2
4
  /**
3
5
  * Logging callback used by planner/steering queries.
4
6
  * `kind` distinguishes ephemeral status updates (heartbeat ticker) from
@@ -25,9 +27,6 @@ export interface PlannerOpts {
25
27
  };
26
28
  }
27
29
  export declare function setPlannerEnvResolver(fn: ((model?: string) => Record<string, string> | undefined) | undefined): void;
28
- export type ModelTier = "opus" | "sonnet" | "haiku" | "unknown";
29
- export declare function detectModelTier(model: string): ModelTier;
30
- export declare function modelCapabilityBlock(model: string): string;
31
30
  export declare function getTotalPlannerCost(): number;
32
31
  export declare function getPlannerRateLimitInfo(): PlannerRateLimitInfo;
33
32
  export declare function runPlannerQuery(prompt: string, opts: PlannerOpts, onLog: PlannerLog): Promise<string>;
@@ -1,6 +1,9 @@
1
1
  import { query } from "@anthropic-ai/claude-agent-sdk";
2
2
  import { readFileSync } from "fs";
3
3
  import { NudgeError } from "./types.js";
4
+ import { detectModelTier, modelCapabilityBlock } from "./models.js";
5
+ // Re-export for consumers that import from planner-query (steering.ts, index.ts).
6
+ export { detectModelTier, modelCapabilityBlock };
4
7
  // ── Shared env resolver (set once at run start, used by every planner query) ──
5
8
  //
6
9
  // Swarm and planner calls share a model→env map so a custom provider configured
@@ -10,37 +13,6 @@ let _envResolver;
10
13
  export function setPlannerEnvResolver(fn) {
11
14
  _envResolver = fn;
12
15
  }
13
- export function detectModelTier(model) {
14
- const m = model.toLowerCase();
15
- if (m === "default" || m.includes("opus"))
16
- return "opus";
17
- if (m.includes("sonnet"))
18
- return "sonnet";
19
- if (m.includes("haiku"))
20
- return "haiku";
21
- // Cursor API Proxy models
22
- if (m === "auto")
23
- return "unknown";
24
- if (m.startsWith("composer"))
25
- return "sonnet";
26
- return "unknown";
27
- }
28
- export function modelCapabilityBlock(model) {
29
- switch (detectModelTier(model)) {
30
- case "opus":
31
- return `Each agent runs Claude Opus with 1M context -- a powerhouse. It can own entire epics, do deep codebase research, make architectural decisions, implement complex multi-file systems end-to-end, use browser tools for analysis, and deliver expert-level work. These agents can work for 30+ minutes on the most complex tasks. Do NOT waste them on trivial edits -- give them ownership and autonomy.`;
32
- case "sonnet":
33
- return `Each agent runs Claude Sonnet -- capable of substantial implementation, refactoring, testing, and design work. Can work autonomously for 10-20 minutes on complex tasks. Give agents meaningful scope -- not just single-line edits.`;
34
- case "haiku":
35
- return `Each agent runs Claude Haiku -- fast and efficient, best for focused, well-specified tasks. Be explicit about files, functions, and expected changes. Keep each task scoped to a clear, concrete deliverable.`;
36
- default:
37
- // Cursor API Proxy or unknown model — generic but mention Cursor context
38
- if (model.toLowerCase().startsWith("composer") || model.toLowerCase() === "auto") {
39
- return `Each agent runs a Cursor model with full codebase access. Capable of focused implementation work. Be explicit about files, functions, and expected changes.`;
40
- }
41
- return `Each agent has full codebase access and can work autonomously.`;
42
- }
43
- }
44
16
  // ── Rate limit tracking ──
45
17
  const RATE_LIMIT_PATTERNS = ["rate", "limit", "overloaded", "429", "hit your limit", "too many"];
46
18
  function isRateLimitError(err) {
package/dist/planner.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { readFileSync } from "fs";
2
- import { runPlannerQuery, extractTaskJson, attemptJsonParse, postProcess, detectModelTier, modelCapabilityBlock } from "./planner-query.js";
2
+ import { runPlannerQuery, extractTaskJson, attemptJsonParse, postProcess } from "./planner-query.js";
3
+ import { detectModelTier, modelCapabilityBlock, MODEL_TIER_HAIKU, MODEL_TIER_OPUS, PLANNER_THRESHOLDS } from "./models.js";
3
4
  // Resilience: if the planner query throws but the agent already wrote valid
4
5
  // tasks to `outFile` (via its Write tool), salvage them instead of discarding
5
6
  // expensive work. Returns salvaged tasks on success, null if nothing usable on
@@ -62,7 +63,7 @@ function plannerPrompt(objective, workerModel, budget, concurrency, flexNote) {
62
63
  ? `\n- ${concurrency} agents run in parallel -- tasks that run concurrently must touch DIFFERENT files to avoid merge conflicts`
63
64
  : "";
64
65
  const flexLine = flexNote ? `\n\n${flexNote}` : "";
65
- if (tier === "haiku") {
66
+ if (tier === MODEL_TIER_HAIKU) {
66
67
  return `You are a task coordinator for a parallel agent system. Analyze this codebase and break the following objective into independent tasks.
67
68
 
68
69
  Objective: ${objective}
@@ -84,8 +85,9 @@ Respond with ONLY a JSON object (no markdown fences):
84
85
  ]
85
86
  }`;
86
87
  }
87
- const smallThreshold = tier === "opus" ? 5 : 15;
88
- const mediumThreshold = tier === "opus" ? 30 : 50;
88
+ const thresholds = tier === MODEL_TIER_OPUS ? PLANNER_THRESHOLDS.opus : PLANNER_THRESHOLDS.default;
89
+ const smallThreshold = thresholds.small;
90
+ const mediumThreshold = thresholds.medium;
89
91
  if (b <= smallThreshold) {
90
92
  return `You are a task coordinator for a parallel agent system. Analyze this codebase and break the following objective into independent tasks.
91
93
 
package/dist/providers.js CHANGED
@@ -6,6 +6,8 @@ import chalk from "chalk";
6
6
  import { query } from "@anthropic-ai/claude-agent-sdk";
7
7
  import { ask, select, selectKey } from "./cli.js";
8
8
  import { getBearerToken, clearTokenCache } from "./auth.js";
9
+ import { DEFAULT_MODEL } from "./models.js";
10
+ import { CURSOR_PRIORITY_MODELS, CURSOR_KNOWN_MODELS, KNOWN_CURSOR_MODEL_IDS, cursorModelHint, } from "./cursor-models.js";
9
11
  // ── Store ──
10
12
  const STORE_PATH = join(homedir(), ".claude", "claude-overnight", "providers.json");
11
13
  export function getStorePath() { return STORE_PATH; }
@@ -99,8 +101,8 @@ export async function pickModel(label, anthropicModels, currentModelId) {
99
101
  // entry so the user isn't trapped if they cancel the Other… form.
100
102
  if (anthropicModels.length === 0) {
101
103
  items.push({
102
- name: "claude-sonnet-4-6",
103
- value: { kind: "anthropic", model: { value: "claude-sonnet-4-6", displayName: "claude-sonnet-4-6", description: "default (model list unavailable)" } },
104
+ name: DEFAULT_MODEL,
105
+ value: { kind: "anthropic", model: { value: DEFAULT_MODEL, displayName: DEFAULT_MODEL, description: "default (model list unavailable)" } },
104
106
  hint: "default -- Anthropic model list unavailable",
105
107
  });
106
108
  }
@@ -291,24 +293,48 @@ export async function fetchCursorModels(baseUrl = PROXY_DEFAULT_URL) {
291
293
  }
292
294
  }
293
295
  /**
294
- * Known Cursor model recommendations short hints to guide users.
296
+ * Try to fetch live Cursor model IDs. Falls back to an empty array — the
297
+ * caller merges with known constants, so the picker always has content.
298
+ *
299
+ * NOTE: `agent --list-models` segfaults with its bundled Node.js binary
300
+ * (exit 139). We work around this by running with the system `node` instead.
295
301
  */
296
- const CURSOR_MODEL_HINTS = {
297
- "auto": "fast delegates to best available model",
298
- "composer": "Cursor Composer good for focused tasks",
299
- "composer-2": "Cursor Composer 2 — latest, strongest Cursor model",
300
- };
301
- function cursorModelHint(modelId) {
302
- const m = modelId.toLowerCase();
303
- if (CURSOR_MODEL_HINTS[m])
304
- return CURSOR_MODEL_HINTS[m];
305
- if (m.includes("opus"))
306
- return "Opus-tier Cursor model";
307
- if (m.includes("sonnet"))
308
- return "Sonnet-tier Cursor model";
309
- if (m.includes("haiku"))
310
- return "Haiku-tier Cursor model (fast)";
311
- return "Cursor model";
302
+ async function fetchLiveCursorModels() {
303
+ // Try the proxy first (works when the bundled node doesn't crash)
304
+ const proxyModels = await fetchCursorModels();
305
+ if (proxyModels.length > 0)
306
+ return proxyModels;
307
+ // Fallback: run the cursor-agent CLI with system node
308
+ // Find the agent binary via command -v (alias-safe), then locate its index.js.
309
+ try {
310
+ // command -v handles symlinks and doesn't expand shell aliases
311
+ const agentPath = execSync("command -v agent 2>/dev/null || command -v cursor-agent 2>/dev/null", {
312
+ timeout: 3_000, encoding: "utf-8", shell: "bash",
313
+ }).trim();
314
+ if (!agentPath)
315
+ return [];
316
+ // Resolve the directory (realpath handles symlinks like agent → cursor-agent)
317
+ const dir = execSync(`dirname "$(realpath "${agentPath}")"`, {
318
+ timeout: 3_000, encoding: "utf-8", shell: "bash",
319
+ }).trim();
320
+ // The bundled index.js lives in the same directory as the agent script
321
+ const indexPath = `${dir}/index.js`;
322
+ const raw = execSync(`node "${indexPath}" --list-models 2>/dev/null`, {
323
+ timeout: 10_000, encoding: "utf-8",
324
+ });
325
+ // Strip ANSI escape codes (cursor uses \x1B[2K\r etc.)
326
+ const out = raw.replace(/\x1B\[[0-9;]*[a-zA-Z]/g, "");
327
+ // Parse lines like "composer-2-fast - Composer 2 Fast"
328
+ const ids = [];
329
+ for (const line of out.split("\n")) {
330
+ const match = line.match(/^([A-Za-z0-9][A-Za-z0-9._:/-]*)\s+-\s+/);
331
+ if (match)
332
+ ids.push(match[1]);
333
+ }
334
+ return ids;
335
+ }
336
+ catch { }
337
+ return [];
312
338
  }
313
339
  function setupSteps() {
314
340
  return [
@@ -490,7 +516,34 @@ export async function setupCursorProxy() {
490
516
  console.log(chalk.yellow("\n Proxy not reachable yet. You can start it later and add it via 'Cursor' in the model picker."));
491
517
  return false;
492
518
  }
493
- // ── Cursor model picker sub-flow ──
519
+ /**
520
+ * Build the full list of cursor model picker items. Priority models go first,
521
+ * then known models, then any extra live models we fetched. If there are more
522
+ * than a handful extras, they get a "more..." sub-menu.
523
+ */
524
+ async function buildCursorPicker() {
525
+ const liveIds = await fetchLiveCursorModels();
526
+ const extra = new Set();
527
+ for (const id of liveIds) {
528
+ if (!KNOWN_CURSOR_MODEL_IDS.has(id))
529
+ extra.add(id);
530
+ }
531
+ const top = [
532
+ ...CURSOR_PRIORITY_MODELS.map(m => ({ id: m.id, name: m.label, hint: m.hint })),
533
+ ...CURSOR_KNOWN_MODELS.map(m => ({ id: m.id, name: m.label, hint: m.hint })),
534
+ ];
535
+ // Only a few extras? show them inline. Otherwise defer to "more...".
536
+ const MORE_THRESHOLD = 6;
537
+ const more = [...extra].sort().map(id => ({
538
+ id,
539
+ name: id,
540
+ hint: cursorModelHint(id),
541
+ }));
542
+ if (more.length <= MORE_THRESHOLD) {
543
+ return { top: [...top, ...more], more: [] };
544
+ }
545
+ return { top, more };
546
+ }
494
547
  async function pickCursorModel() {
495
548
  console.log(chalk.dim("\n Cursor API Proxy Models"));
496
549
  console.log(chalk.dim(" " + "─".repeat(40)));
@@ -522,29 +575,39 @@ async function pickCursorModel() {
522
575
  return null;
523
576
  }
524
577
  }
525
- // Fetch live models
526
- const modelIds = await fetchCursorModels();
527
- if (modelIds.length === 0) {
528
- console.log(chalk.yellow(" No models returned from proxy"));
529
- return null;
578
+ const { top, more } = await buildCursorPicker();
579
+ // If there are more models available, add a "more…" entry
580
+ const items = top.map(m => ({
581
+ name: m.name,
582
+ value: m.id,
583
+ hint: m.hint,
584
+ }));
585
+ let hasMore = more.length > 0;
586
+ if (hasMore) {
587
+ items.push({ name: chalk.gray("more…"), value: "__more__", hint: `${more.length} additional models` });
530
588
  }
531
- const picked = await select(" Select a Cursor model:", modelIds.map(id => ({
532
- name: id,
533
- value: id,
534
- hint: cursorModelHint(id),
535
- })), 0);
589
+ const picked = await select(" Select a Cursor model:", items, 0);
590
+ // Handle "more…" sub-menu
591
+ if (picked === "__more__") {
592
+ const moreItems = more.map(m => ({ name: m.name, value: m.id, hint: m.hint }));
593
+ const morePicked = await select(" More Cursor models:", moreItems, 0);
594
+ return saveCursorPick(morePicked);
595
+ }
596
+ return saveCursorPick(picked);
597
+ }
598
+ function saveCursorPick(modelId) {
536
599
  const existingKey = loadProviders().find(p => p.id === CURSOR_KEY_PROVIDER_ID)?.cursorApiKey;
537
600
  const provider = {
538
- id: `cursor-${picked}`,
539
- displayName: `Cursor: ${picked}`,
601
+ id: `cursor-${modelId}`,
602
+ displayName: `Cursor: ${modelId}`,
540
603
  baseURL: PROXY_DEFAULT_URL,
541
- model: picked,
604
+ model: modelId,
542
605
  cursorProxy: true,
543
606
  ...(existingKey ? { cursorApiKey: existingKey } : {}),
544
607
  };
545
608
  saveProvider(provider);
546
609
  console.log(chalk.green(` ✓ Saved as provider: ${provider.displayName}`));
547
- return { model: picked, providerId: provider.id, provider };
610
+ return { model: modelId, providerId: provider.id, provider };
548
611
  }
549
612
  /**
550
613
  * Build a single resolver that swarm.ts and planner-query.ts share. Maps a
package/dist/state.js CHANGED
@@ -3,6 +3,7 @@ import { execSync } from "child_process";
3
3
  import { join } from "path";
4
4
  import chalk from "chalk";
5
5
  import { forceMergeOverlay } from "./merge.js";
6
+ import { FALLBACK_MODEL } from "./models.js";
6
7
  // ── File I/O helpers ──
7
8
  export function readMdDir(dir) {
8
9
  try {
@@ -267,7 +268,7 @@ export function backfillOrphanedPlans(rootDir, filterCwd) {
267
268
  id: d,
268
269
  objective: `(recovered pre-1.11.7 plan · ${taskCount} tasks)`,
269
270
  budget: taskCount, remaining: taskCount,
270
- workerModel: "claude-opus-4-6", plannerModel: "claude-opus-4-6",
271
+ workerModel: FALLBACK_MODEL, plannerModel: FALLBACK_MODEL,
271
272
  concurrency: 5, permissionMode: "bypassPermissions",
272
273
  flex: false, useWorktrees: true, mergeStrategy: "yolo",
273
274
  allowExtraUsage: false,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "claude-overnight",
3
- "version": "1.17.3",
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. Opus/Sonnet/Haiku + Cursor API Proxy + Qwen/OpenRouter.",
3
+ "version": "1.18.0",
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": {
7
7
  "claude-overnight": "dist/bin.js"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-overnight",
3
- "version": "1.17.3",
3
+ "version": "1.18.0",
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"