claude-overnight 1.25.26 → 1.25.29

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.26";
1
+ export declare const VERSION = "1.25.29";
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.26";
2
+ export const VERSION = "1.25.29";
package/dist/index.js CHANGED
@@ -12,7 +12,7 @@ import { setPlannerEnvResolver } from "./planner-query.js";
12
12
  import { setTranscriptRunDir } from "./transcripts.js";
13
13
  import { pickModel, loadProviders, preflightProvider, buildEnvResolver, healthCheckCursorProxy, PROXY_DEFAULT_URL, isCursorProxyProvider, readCursorProxyLogTail, ensureCursorProxyRunning, bundledComposerProxyShellCommand, warnMacCursorAgentShellPatchIfNeeded, hasCursorAgentToken, } from "./providers.js";
14
14
  import { RunDisplay } from "./ui.js";
15
- import { renderSummary } from "./render.js";
15
+ import { renderSummary, wrap } from "./render.js";
16
16
  import { executeRun } from "./run.js";
17
17
  import { parseCliFlags, isAuthError, fetchModels, ask, select, selectKey, loadTaskFile, validateConcurrency, isGitRepo, validateGitRepo, showPlan, BRAILLE, makeProgressLog, } from "./cli.js";
18
18
  import { loadRunState, findIncompleteRuns, findOrphanedDesigns, backfillOrphanedPlans, formatTimeAgo, showRunHistory, readPreviousRunKnowledge, createRunDir, updateLatestSymlink, readMdDir, saveRunState, autoMergeBranches, } from "./state.js";
@@ -366,11 +366,13 @@ async function main() {
366
366
  const ago = formatTimeAgo(prev.startedAt);
367
367
  let lastStatus = "";
368
368
  try {
369
- lastStatus = readFileSync(join(run.dir, "status.md"), "utf-8").trim().slice(0, 120);
369
+ lastStatus = readFileSync(join(run.dir, "status.md"), "utf-8").trim().slice(0, 200);
370
370
  }
371
371
  catch { }
372
372
  const planTaskCount = prev.phase === "planning" ? countTasksInFile(join(run.dir, "tasks.json")) : 0;
373
373
  console.log(chalk.yellow(`\n ⚠ Unfinished run`) + chalk.dim(` · ${ago}`));
374
+ const termW = Math.max(process.stdout.columns ?? 80, 60);
375
+ const statusMaxW = Math.min(termW - 8, 80);
374
376
  const boxLines = prev.phase === "planning" ? [
375
377
  `${obj}${obj.length >= 50 ? "…" : ""}`,
376
378
  `Plan ready · ${planTaskCount} tasks · budget ${prev.budget} · ${prev.concurrency}× concurrent`,
@@ -380,8 +382,10 @@ async function main() {
380
382
  `${prev.accCompleted}/${prev.budget} sessions · ${Math.max(1, (prev.budget ?? 0) - prev.accCompleted)} remaining · $${prev.accCost.toFixed(2)}`,
381
383
  `Wave ${prev.waveNum + 1} · ${prev.phase}`,
382
384
  ];
383
- if (lastStatus)
384
- boxLines.push(lastStatus);
385
+ if (lastStatus) {
386
+ for (const wl of wrap(lastStatus, statusMaxW))
387
+ boxLines.push(wl);
388
+ }
385
389
  if (merged + unmerged + failed > 0)
386
390
  boxLines.push(`${merged} merged · ${unmerged} unmerged · ${failed} failed`);
387
391
  const boxW = Math.max(...boxLines.map(l => l.length)) + 4;
@@ -415,7 +419,7 @@ async function main() {
415
419
  const merged = s.branches.filter(b => b.status === "merged").length;
416
420
  let lastStatus = "";
417
421
  try {
418
- lastStatus = readFileSync(join(shown[i].dir, "status.md"), "utf-8").trim().split("\n")[0].slice(0, 70);
422
+ lastStatus = readFileSync(join(shown[i].dir, "status.md"), "utf-8").trim().split("\n")[0].slice(0, 120);
419
423
  }
420
424
  catch { }
421
425
  console.log(chalk.cyan(` ${i + 1}`) + ` ${obj}${obj.length >= 50 ? "…" : ""}`);
@@ -426,8 +430,11 @@ async function main() {
426
430
  else {
427
431
  console.log(chalk.dim(` ${s.accCompleted}/${s.budget} · $${s.accCost.toFixed(2)} · ${ago} · ${s.phase} at wave ${s.waveNum + 1}${merged ? ` · ${merged} merged` : ""}`));
428
432
  }
429
- if (lastStatus)
430
- console.log(chalk.dim(` ${lastStatus}`));
433
+ if (lastStatus) {
434
+ const termW = Math.max(process.stdout.columns ?? 80, 60);
435
+ for (const wl of wrap(lastStatus, termW - 6))
436
+ console.log(chalk.dim(` ${wl}`));
437
+ }
431
438
  console.log("");
432
439
  }
433
440
  const action = await selectKey(` ${chalk.dim(`[1-${shown.length}] resume`)}`, [
@@ -17,6 +17,8 @@ export declare class InteractivePanel {
17
17
  preview: string;
18
18
  body: string;
19
19
  }): void;
20
+ /** Close the panel entirely (set mode to "none"). */
21
+ close(): void;
20
22
  collapse(): void;
21
23
  toggle(): void;
22
24
  scroll(direction: "up" | "down", visibleRows: number): void;
@@ -35,6 +35,12 @@ export class InteractivePanel {
35
35
  this._bodyLines = params.body.split("\n").filter(l => l.length > 0);
36
36
  this.state.scrollOffset = 0;
37
37
  }
38
+ /** Close the panel entirely (set mode to "none"). */
39
+ close() {
40
+ this.state.mode = "none";
41
+ this.state.expanded = false;
42
+ this.state.scrollOffset = 0;
43
+ }
38
44
  collapse() {
39
45
  this.state.expanded = false;
40
46
  this.state.scrollOffset = 0;
package/dist/render.d.ts CHANGED
@@ -31,6 +31,10 @@ export declare function renderWaitingIndicator(label: string, startedAt: number
31
31
  style?: "info" | "warn" | "wait" | "thinking";
32
32
  }): string;
33
33
  export declare function truncate(s: string, max: number): string;
34
+ /** Word-wrap text into lines of at most `max` chars.
35
+ * Splits on spaces; if a single word exceeds `max` it is hard-broken.
36
+ * Ignores ANSI escape codes for length calculation. */
37
+ export declare function wrap(s: string, max: number): string[];
34
38
  export declare function fmtTokens(n: number): string;
35
39
  export declare function fmtDur(ms: number): string;
36
40
  /** Context-fill percentage and color function for a token count vs safe limit. */
package/dist/render.js CHANGED
@@ -41,6 +41,36 @@ export function renderWaitingIndicator(label, startedAt, opts = {}) {
41
41
  export function truncate(s, max) {
42
42
  return s.length <= max ? s : s.slice(0, max - 1) + "\u2026";
43
43
  }
44
+ /** Word-wrap text into lines of at most `max` chars.
45
+ * Splits on spaces; if a single word exceeds `max` it is hard-broken.
46
+ * Ignores ANSI escape codes for length calculation. */
47
+ export function wrap(s, max) {
48
+ if (s.length <= max)
49
+ return [s];
50
+ // Strip ANSI for length calculation
51
+ const stripped = s.replace(/\x1b\[[0-9;]*m/g, "");
52
+ if (stripped.length <= max)
53
+ return [s];
54
+ const lines = [];
55
+ const words = stripped.split(/\s+/);
56
+ let cur = "";
57
+ for (const w of words) {
58
+ if (cur.length === 0) {
59
+ cur = w;
60
+ continue;
61
+ }
62
+ if (cur.length + 1 + w.length <= max) {
63
+ cur += " " + w;
64
+ }
65
+ else {
66
+ lines.push(cur);
67
+ cur = w;
68
+ }
69
+ }
70
+ if (cur)
71
+ lines.push(cur);
72
+ return lines;
73
+ }
44
74
  export function fmtTokens(n) {
45
75
  if (n >= 1_000_000)
46
76
  return `${(n / 1_000_000).toFixed(1)}M`;
@@ -412,12 +442,6 @@ export function renderFrame(swarm, showHotkeys, runInfo, selectedAgentId, maxRow
412
442
  // Build footer
413
443
  let hotkeyRow;
414
444
  const extraFooterRows = [];
415
- // Collapsed panel bar shown in footer area
416
- if (panel?.visible && !panel.state.expanded) {
417
- const bar = panel.renderCollapsed(Math.max((process.stdout.columns ?? 80) || 80, 60));
418
- if (bar)
419
- extraFooterRows.push(bar);
420
- }
421
445
  if (showHotkeys) {
422
446
  const pending = runInfo?.pendingSteer ?? 0;
423
447
  const chip = pending > 0 ? chalk.cyan(` \u270E ${pending} steer queued`) : "";
@@ -530,8 +554,12 @@ function renderStatusBlock(out, w, status) {
530
554
  if (lines.length === 0)
531
555
  return;
532
556
  section(out, w, "Status");
533
- for (const ln of lines)
534
- out.push(` ${chalk.dim(truncate(ln.trim(), w - 4))}`);
557
+ const indent = " ";
558
+ const maxW = w - indent.length;
559
+ for (const ln of lines) {
560
+ for (const wl of wrap(ln.trim(), maxW))
561
+ out.push(`${indent}${chalk.dim(wl)}`);
562
+ }
535
563
  }
536
564
  export function renderSteeringFrame(runInfo, data, showHotkeys, rlGetter, maxRows, panel) {
537
565
  const totalUsed = runInfo.accCompleted + runInfo.accFailed;
@@ -609,12 +637,6 @@ export function renderSteeringFrame(runInfo, data, showHotkeys, rlGetter, maxRow
609
637
  // Footer
610
638
  let hotkeyRow;
611
639
  const extraFooterRows = [];
612
- // Collapsed panel bar shown in footer area
613
- if (panel?.visible && !panel.state.expanded) {
614
- const bar = panel.renderCollapsed(Math.max((process.stdout.columns ?? 80) || 80, 60));
615
- if (bar)
616
- extraFooterRows.push(bar);
617
- }
618
640
  if (showHotkeys) {
619
641
  const pending = runInfo?.pendingSteer ?? 0;
620
642
  const chip = pending > 0 ? chalk.cyan(` \u270E ${pending} steer queued`) : "";
package/dist/steering.js CHANGED
@@ -60,7 +60,7 @@ ${constraint}
60
60
  ${DESIGN_THINKING}
61
61
  Total waves completed: ${history.length}
62
62
 
63
- Read the codebase. Assess from the user's chair: does this product do the job someone would hire it for? Does it feel fast, honest, and trustworthy? Not "is the code clean" -- "would I use this?"
63
+ Read the codebase efficiently — you have a hard cap of 100 tool calls. Be surgical: check for Postgres imports with targeted greps, read only the files you'll actually modify. Then compose the wave. Assess from the user's chair: does this product do the job someone would hire it for? Does it feel fast, honest, and trustworthy? Not "is the code clean" -- "would I use this?"
64
64
 
65
65
  If verification found issues, those are the priority. Fix what's broken before building what's missing. Iterate on what exists before expanding scope.
66
66
 
@@ -104,14 +104,14 @@ Respond with ONLY a JSON object (no markdown fences):
104
104
  "estimatedSessionsRemaining": 15,
105
105
  "tasks": [
106
106
  {"prompt": "task instruction...", "model": "worker"},
107
- {"prompt": "review task...", "model": "planner"},
108
- {"prompt": "verify the app end-to-end...", "model": "planner", "noWorktree": true}
107
+ {"prompt": "quick icon fix, verified by worker next wave...", "model": "fast"},
108
+ {"prompt": "verify the app end-to-end...", "model": "worker", "noWorktree": true}
109
109
  ]
110
110
  }
111
111
 
112
112
  "estimatedSessionsRemaining" is REQUIRED. Your best honest estimate of how many MORE agent sessions (beyond the wave you just composed above) are needed to reach 'amazing' -- include follow-up fixes, polish, verification, and anything else you'd want before shipping. Be realistic, not optimistic. Use 0 only if truly done.
113
113
 
114
- The "model" field on each task: use "worker" (${workerModel}) for implementation tasks, "planner" (${plannerModel}) for review/analysis/verification tasks, "fast" (${fastModel ?? workerModel}) for quick, well-scoped changes that will be checked by the worker model in the next wave. Default is "worker".
114
+ The "model" field on each task: use "worker" (${workerModel}) for all tasks. Use "fast" (${fastModel ?? "not set"}) for small, single-file changes that will be checked by the worker in the next wave.
115
115
  Set "noWorktree": true for verify/user-test tasks -- they need the real project directory with env files, dependencies, and local config.
116
116
 
117
117
  If done: {"done": true, "reasoning": "...", "statusUpdate": "...", "estimatedSessionsRemaining": 0, "tasks": []}`;
@@ -119,7 +119,7 @@ If done: {"done": true, "reasoning": "...", "statusUpdate": "...", "estimatedSes
119
119
  onLog(`Reading codebase -- wave ${history.length + 1}`, "event");
120
120
  const turn = createTurn("steer", `Steer wave ${history.length + 1}`, `steer-${history.length}`, plannerModel);
121
121
  beginTurn(turn);
122
- const resultText = await runPlannerQuery(prompt, { cwd, model: plannerModel, permissionMode, outputFormat: STEER_SCHEMA, transcriptName, turnId: turn.id }, onLog);
122
+ const resultText = await runPlannerQuery(prompt, { cwd, model: plannerModel, permissionMode, outputFormat: STEER_SCHEMA, transcriptName, turnId: turn.id, maxTurns: 100 }, onLog);
123
123
  const parsed = await (async () => {
124
124
  const first = attemptJsonParse(resultText);
125
125
  if (first)
package/dist/ui.js CHANGED
@@ -550,9 +550,14 @@ export class RunDisplay {
550
550
  }
551
551
  return false; // swallow other CSIs silently
552
552
  }
553
- // Bare ESC: collapse
553
+ // Bare ESC: collapse if expanded, close if collapsed
554
554
  if (s === "\x1B") {
555
- this.panel.collapse();
555
+ if (this.panel.state.expanded) {
556
+ this.panel.collapse();
557
+ }
558
+ else {
559
+ this.panel.close();
560
+ }
556
561
  return true;
557
562
  }
558
563
  // Ctrl-O: toggle (collapse)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-overnight",
3
- "version": "1.25.26",
3
+ "version": "1.25.29",
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.26",
3
+ "version": "1.25.29",
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"