claude-overnight 1.7.1 → 1.8.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.
package/dist/index.js CHANGED
@@ -1573,35 +1573,62 @@ async function main() {
1573
1573
  const elapsedStr = elapsed < 60 ? `${elapsed}s` : elapsed < 3600 ? `${Math.floor(elapsed / 60)}m ${elapsed % 60}s` : `${Math.floor(elapsed / 3600)}h ${Math.floor((elapsed % 3600) / 60)}m`;
1574
1574
  const totalMerged = branches.filter(b => b.status === "merged").length;
1575
1575
  const totalConflicts = branches.filter(b => b.status === "merge-failed").length;
1576
- console.log(chalk.dim(`\n ${"─".repeat(36)}`));
1577
- console.log(` ${accFailed === 0 ? chalk.green("✓") : chalk.yellow("⚠")} ${chalk.bold("Complete")}\n`);
1578
- const boxLines = [];
1579
- const statusLine = accFailed > 0 ? `${accCompleted} done · ${accFailed} failed` : `${accCompleted} done`;
1580
- boxLines.push(`${waves} wave${waves > 1 ? "s" : ""} · ${statusLine} · $${accCost.toFixed(2)}`);
1581
- boxLines.push(`${elapsedStr} · ${fmtTokens(accIn)} in / ${fmtTokens(accOut)} out · ${accTools} tools`);
1582
- if (totalMerged > 0 || totalConflicts > 0)
1583
- boxLines.push(`${totalMerged} merged${totalConflicts > 0 ? ` · ${totalConflicts} conflicts` : ""}`);
1576
+ const termW = Math.max((process.stdout.columns ?? 80) || 80, 50);
1577
+ // Banner
1578
+ console.log("");
1579
+ const bannerChar = accFailed === 0 ? "=" : "-";
1580
+ console.log(chalk.green(` ${bannerChar.repeat(Math.min(termW - 4, 60))}`));
1581
+ if (trulyDone) {
1582
+ console.log(chalk.bold.green(` CLAUDE OVERNIGHT COMPLETE`));
1583
+ }
1584
+ else {
1585
+ console.log(chalk.bold.yellow(` CLAUDE OVERNIGHT — BUDGET EXHAUSTED`));
1586
+ }
1587
+ console.log(chalk.green(` ${bannerChar.repeat(Math.min(termW - 4, 60))}`));
1588
+ console.log("");
1589
+ // Stats grid
1590
+ const statRows = [
1591
+ [chalk.bold("Waves"), String(waves), chalk.bold("Sessions"), `${accCompleted} done${accFailed > 0 ? ` / ${accFailed} failed` : ""}`],
1592
+ [chalk.bold("Cost"), chalk.green(`$${accCost.toFixed(2)}`), chalk.bold("Elapsed"), elapsedStr],
1593
+ [chalk.bold("Merged"), `${totalMerged} branches`, chalk.bold("Conflicts"), totalConflicts > 0 ? chalk.red(String(totalConflicts)) : chalk.green("0")],
1594
+ [chalk.bold("Tokens"), `${fmtTokens(accIn)} in / ${fmtTokens(accOut)} out`, chalk.bold("Tool calls"), String(accTools)],
1595
+ ];
1596
+ for (const [k1, v1, k2, v2] of statRows) {
1597
+ console.log(` ${k1} ${v1.padEnd(20)} ${k2} ${v2}`);
1598
+ }
1584
1599
  if (overheadBudgetUsed > 0)
1585
- boxLines.push(`${overheadBudgetUsed} overhead agents (review/verify/explore)`);
1600
+ console.log(` ${chalk.bold("Overhead")} ${overheadBudgetUsed} agents (review/verify/explore)`);
1586
1601
  if (lastCapped)
1587
- boxLines.push(chalk.yellow(`Capped at ${usageCap != null ? Math.round(usageCap * 100) : 100}%`));
1588
- const boxW = Math.max(...boxLines.map(l => l.replace(/\x1B\[[0-9;]*m/g, "").length)) + 4;
1589
- console.log(chalk.dim(` ╭${"─".repeat(boxW)}╮`));
1590
- for (const line of boxLines) {
1591
- const plainLen = line.replace(/\x1B\[[0-9;]*m/g, "").length;
1592
- console.log(chalk.dim(" │") + ` ${line}${" ".repeat(Math.max(0, boxW - 2 - plainLen))}` + chalk.dim("│"));
1593
- }
1594
- console.log(chalk.dim(` ╰${"─".repeat(boxW)}╯`));
1602
+ console.log(` ${chalk.yellow(`Capped at ${usageCap != null ? Math.round(usageCap * 100) : 100}%`)}`);
1603
+ console.log("");
1604
+ // Status summary (the product-level assessment from the planner)
1605
+ const statusFile = join(runDir, "status.md");
1606
+ if (existsSync(statusFile)) {
1607
+ const statusContent = readFileSync(statusFile, "utf-8").trim();
1608
+ if (statusContent) {
1609
+ console.log(chalk.dim(` ${"─".repeat(Math.min(termW - 4, 60))}`));
1610
+ console.log(chalk.bold(" Status"));
1611
+ console.log("");
1612
+ for (const line of statusContent.split("\n")) {
1613
+ console.log(` ${line}`);
1614
+ }
1615
+ console.log("");
1616
+ }
1617
+ }
1618
+ // Conflicts detail
1595
1619
  if (totalConflicts > 0) {
1620
+ console.log(chalk.dim(` ${"─".repeat(Math.min(termW - 4, 60))}`));
1596
1621
  const conflictBranches = branches.filter(b => b.status === "merge-failed");
1597
- console.log(chalk.red(`\n Unresolved conflicts:`));
1622
+ console.log(chalk.red(` Unresolved conflicts:`));
1598
1623
  for (const c of conflictBranches)
1599
1624
  console.log(chalk.red(` ${c.branch}`));
1600
1625
  console.log(chalk.dim(" git merge <branch> to resolve"));
1626
+ console.log("");
1601
1627
  }
1602
- if (runBranch) {
1603
- console.log(chalk.dim(`\n Branch: ${runBranch} git merge ${runBranch}`));
1604
- }
1628
+ // Footer
1629
+ console.log(chalk.dim(` ${"─".repeat(Math.min(termW - 4, 60))}`));
1630
+ if (runBranch)
1631
+ console.log(chalk.dim(` Branch: ${runBranch} — git merge ${runBranch}`));
1605
1632
  console.log(chalk.dim(` Run: ${runDir}`));
1606
1633
  if (currentSwarm?.logFile)
1607
1634
  console.log(chalk.dim(` Log: ${currentSwarm.logFile}`));
package/dist/planner.js CHANGED
@@ -691,10 +691,10 @@ You have full creative freedom. Design the wave that will have the highest impac
691
691
  **Synthesize** — An agent reads multiple alternatives or review findings and makes a decision. Writes the chosen approach or prioritized fix list.
692
692
  Example: 1 agent reads 3 design docs and writes the implementation plan
693
693
 
694
- **Verify** — Agents actually RUN the application: build it, start it, navigate it, click things, try edge cases. They report what works and what's broken. Not code reading — real testing.
694
+ **Verify** — Agents actually RUN the application: build it, start it, navigate it, click things, try edge cases. They report what works and what's broken. Not code reading — real testing. Always set "noWorktree": true so they run in the real project environment (env files, dependencies, config). Tell verify agents: you MUST get the app running and tested — do not give up. If auth is required, search the codebase for dev login routes, test tokens, seed users, env vars with keys/secrets, CLI auth commands, or any bypass. If a port is taken, use another. If a dependency is missing, install it. If a build fails, fix it or work around it. Exhaust every option before declaring something impossible.
695
695
  Example: 1 agent does end-to-end QA, writing a report with reproduction steps
696
696
 
697
- **User-test** — Agents emulate specific user personas interacting with the product. "First-time user who just downloaded this." "Power user trying to do X fast." They test from that perspective and report friction.
697
+ **User-test** — Agents emulate specific user personas interacting with the product. Always set "noWorktree": true. "First-time user who just downloaded this." "Power user trying to do X fast." They test from that perspective and report friction.
698
698
  Example: 2 agents, one new user, one power user, each writing a report
699
699
 
700
700
  **Polish** — Agents focus purely on feel: loading states, error messages, micro-interactions, empty states, responsiveness. Not features — the texture that makes users trust the product.
@@ -715,11 +715,13 @@ Respond with ONLY a JSON object (no markdown fences):
715
715
  "statusUpdate": "REQUIRED — concise project status: what's built, what works, what's rough, quality level, key gaps. This replaces the previous status.",
716
716
  "tasks": [
717
717
  {"prompt": "task instruction...", "model": "worker"},
718
- {"prompt": "review task...", "model": "planner"}
718
+ {"prompt": "review task...", "model": "planner"},
719
+ {"prompt": "verify the app end-to-end...", "model": "planner", "noWorktree": true}
719
720
  ]
720
721
  }
721
722
 
722
723
  The "model" field on each task: use "worker" (${workerModel}) for implementation tasks, "planner" (${plannerModel}) for review/analysis/verification tasks. Default is "worker".
724
+ Set "noWorktree": true for verify/user-test tasks — they run in the real project directory instead of an isolated worktree, with access to env files, installed dependencies, and local config.
723
725
 
724
726
  If done: {"done": true, "waveKind": "done", "reasoning": "...", "statusUpdate": "...", "tasks": []}`;
725
727
  onLog("Assessing...");
@@ -747,6 +749,7 @@ If done: {"done": true, "waveKind": "done", "reasoning": "...", "statusUpdate":
747
749
  id: String(i),
748
750
  prompt: typeof t === "string" ? t : t.prompt,
749
751
  ...(t.model && { model: t.model }),
752
+ ...(t.noWorktree && { noWorktree: true }),
750
753
  }));
751
754
  tasks = postProcess(tasks, remainingBudget, onLog);
752
755
  return { done: tasks.length === 0, tasks, reasoning: parsed.reasoning || "", waveKind: tasks.length === 0 ? "done" : waveKind, goalUpdate: parsed.goalUpdate, statusUpdate };
package/dist/swarm.js CHANGED
@@ -202,7 +202,7 @@ export class Swarm {
202
202
  this.agents.push(agent);
203
203
  // Create worktree if enabled
204
204
  let agentCwd = task.cwd || this.config.cwd;
205
- if (this.config.useWorktrees && this.worktreeBase) {
205
+ if (this.config.useWorktrees && this.worktreeBase && !task.noWorktree) {
206
206
  try {
207
207
  const branch = `swarm/task-${id}`;
208
208
  const dir = join(this.worktreeBase, `agent-${id}`);
@@ -238,11 +238,12 @@ export class Swarm {
238
238
  let resumeSessionId;
239
239
  let resumePrompt = "Continue. Complete the task.";
240
240
  const runOnce = async (isResume) => {
241
+ const preamble = "Keep files under ~500 lines. If a file would exceed that, split it.\n\n";
241
242
  const agentPrompt = isResume
242
243
  ? resumePrompt
243
- : this.config.useWorktrees
244
- ? `You are working in an isolated git worktree. Focus only on this task. Do NOT commit your changes — the framework handles that.\n\n${task.prompt}`
245
- : task.prompt;
244
+ : this.config.useWorktrees && !task.noWorktree
245
+ ? `You are working in an isolated git worktree. Focus only on this task. Do NOT commit your changes — the framework handles that.\n\n${preamble}${task.prompt}`
246
+ : `${preamble}${task.prompt}`;
246
247
  const agentQuery = query({
247
248
  prompt: agentPrompt,
248
249
  options: {
package/dist/types.d.ts CHANGED
@@ -8,6 +8,8 @@ export interface Task {
8
8
  cwd?: string;
9
9
  /** Claude model override for this specific task (e.g. "sonnet", "opus"). */
10
10
  model?: string;
11
+ /** When true, skip worktree isolation — run in the real project directory with env files, dependencies, and local config. */
12
+ noWorktree?: boolean;
11
13
  }
12
14
  /** Schema for a JSON task file that defines a batch of work for the swarm. */
13
15
  export interface TaskFile {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-overnight",
3
- "version": "1.7.1",
3
+ "version": "1.8.1",
4
4
  "description": "Run 10, 100, or 1000 Claude agents overnight. Parallel autonomous AI coding with thinking waves, iterative quality steering, crash recovery, and rate limit handling. Built on the Claude Agent SDK.",
5
5
  "type": "module",
6
6
  "bin": {