claude-overnight 1.25.9 → 1.25.10
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/_version.d.ts +1 -1
- package/dist/_version.js +1 -1
- package/dist/index.js +4 -3
- package/dist/render.js +12 -3
- package/dist/swarm.js +69 -13
- package/dist/types.d.ts +5 -1
- package/package.json +1 -1
- package/plugins/claude-overnight/.claude-plugin/plugin.json +1 -1
package/dist/_version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const VERSION = "1.25.
|
|
1
|
+
export declare const VERSION = "1.25.10";
|
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.
|
|
2
|
+
export const VERSION = "1.25.10";
|
package/dist/index.js
CHANGED
|
@@ -975,15 +975,16 @@ async function main() {
|
|
|
975
975
|
console.log("");
|
|
976
976
|
}
|
|
977
977
|
else {
|
|
978
|
-
const
|
|
978
|
+
const researchModel = fastModel ? workerModel : plannerModel;
|
|
979
|
+
const thinkingTasks = buildThinkingTasks(objective, themes, designDir, researchModel, previousKnowledge || undefined);
|
|
979
980
|
console.log(chalk.cyan(`\n ◆ Thinking: ${thinkingTasks.length} agents exploring...\n`));
|
|
980
981
|
const thinkingSwarm = new Swarm({
|
|
981
|
-
tasks: thinkingTasks, concurrency, cwd, model:
|
|
982
|
+
tasks: thinkingTasks, concurrency, cwd, model: researchModel, permissionMode,
|
|
982
983
|
useWorktrees: false, mergeStrategy: "yolo", agentTimeoutMs, usageCap, allowExtraUsage, extraUsageBudget,
|
|
983
984
|
envForModel,
|
|
984
985
|
cursorProxy: [plannerProvider, workerProvider, fastProvider].some(p => p && isCursorProxyProvider(p)),
|
|
985
986
|
});
|
|
986
|
-
const thinkRunInfo = { accIn: 0, accOut: 0, accCost: 0, accCompleted: 0, accFailed: 0, sessionsBudget: budget ?? 10, waveNum: -1, remaining: budget ?? 10, model:
|
|
987
|
+
const thinkRunInfo = { accIn: 0, accOut: 0, accCost: 0, accCompleted: 0, accFailed: 0, sessionsBudget: budget ?? 10, waveNum: -1, remaining: budget ?? 10, model: researchModel, startedAt: Date.now() };
|
|
987
988
|
const thinkDisplay = new RunDisplay(thinkRunInfo, { remaining: 0, usageCap, concurrency, paused: false, dirty: false });
|
|
988
989
|
thinkDisplay.setWave(thinkingSwarm);
|
|
989
990
|
thinkDisplay.start();
|
package/dist/render.js
CHANGED
|
@@ -510,6 +510,7 @@ export function renderSummary(swarm) {
|
|
|
510
510
|
out.push(chalk.gray(" " + "\u2500".repeat(Math.min(w - 4, fixedW + taskW))));
|
|
511
511
|
const groups = [
|
|
512
512
|
swarm.agents.filter(a => a.status === "running"),
|
|
513
|
+
swarm.agents.filter(a => a.status === "paused"),
|
|
513
514
|
swarm.agents.filter(a => a.status === "done"),
|
|
514
515
|
swarm.agents.filter(a => a.status === "error"),
|
|
515
516
|
].filter(g => g.length > 0);
|
|
@@ -521,7 +522,10 @@ export function renderSummary(swarm) {
|
|
|
521
522
|
for (const a of groups[gi]) {
|
|
522
523
|
const id = String(a.id).padStart(3);
|
|
523
524
|
const ok = a.status === "done";
|
|
524
|
-
const status = ok ? chalk.green("\u2713 done")
|
|
525
|
+
const status = ok ? chalk.green("\u2713 done")
|
|
526
|
+
: a.status === "running" ? chalk.blue("~ run ")
|
|
527
|
+
: a.status === "paused" ? chalk.yellow("\u23F8 paused")
|
|
528
|
+
: chalk.red("\u2717 err ");
|
|
525
529
|
const task = truncate(a.task.prompt, taskW).padEnd(taskW);
|
|
526
530
|
const durMs = a.startedAt != null ? (a.finishedAt ?? Date.now()) - a.startedAt : 0;
|
|
527
531
|
const dur = fmtDur(durMs).padStart(8);
|
|
@@ -532,7 +536,7 @@ export function renderSummary(swarm) {
|
|
|
532
536
|
totalFiles += a.filesChanged ?? 0;
|
|
533
537
|
totalTools += a.toolCalls;
|
|
534
538
|
totalCost += a.costUsd ?? 0;
|
|
535
|
-
const color = ok ? chalk.white : a.status === "running" ? chalk.blue : chalk.red;
|
|
539
|
+
const color = ok ? chalk.white : a.status === "running" ? chalk.blue : a.status === "paused" ? chalk.yellow : chalk.red;
|
|
536
540
|
out.push(color(` ${id} ${status} ${task} ${dur} ${files} ${tools} ${cost}`));
|
|
537
541
|
}
|
|
538
542
|
}
|
|
@@ -549,7 +553,8 @@ function fmtRow(a, w, selected = false) {
|
|
|
549
553
|
const spin = SPINNER[Math.floor(Date.now() / 250) % SPINNER.length];
|
|
550
554
|
const icon = a.status === "running"
|
|
551
555
|
? (a.blockedAt ? chalk.yellow("\u25CF blk") : chalk.blue(`${spin} run`)) + elapsed
|
|
552
|
-
: a.status === "
|
|
556
|
+
: a.status === "paused" ? chalk.yellow("\u23F8 paused")
|
|
557
|
+
: a.status === "done" ? chalk.green("\u2713 done") : chalk.red("\u2717 err ");
|
|
553
558
|
const taskW = Math.max(20, Math.min(36, w - 50));
|
|
554
559
|
const task = truncate(a.task.prompt, taskW).padEnd(taskW);
|
|
555
560
|
let action;
|
|
@@ -562,6 +567,10 @@ function fmtRow(a, w, selected = false) {
|
|
|
562
567
|
else if (a.status === "running") {
|
|
563
568
|
action = chalk.dim(truncate(a.lastText || "...", 24));
|
|
564
569
|
}
|
|
570
|
+
else if (a.status === "paused") {
|
|
571
|
+
const dur = fmtDur((Date.now()) - (a.startedAt || Date.now()));
|
|
572
|
+
action = chalk.yellow(`paused ${dur}`);
|
|
573
|
+
}
|
|
565
574
|
else if (a.status === "done") {
|
|
566
575
|
const dur = fmtDur((a.finishedAt || Date.now()) - (a.startedAt || Date.now()));
|
|
567
576
|
const cost = a.costUsd != null ? ` $${a.costUsd.toFixed(3)}` : "";
|
package/dist/swarm.js
CHANGED
|
@@ -126,6 +126,13 @@ export class Swarm {
|
|
|
126
126
|
return;
|
|
127
127
|
this.paused = b;
|
|
128
128
|
this.log(-1, b ? "Dispatch paused" : "Dispatch resumed");
|
|
129
|
+
if (b) {
|
|
130
|
+
// Instant: interrupt every active SDK session so agents stop mid-turn.
|
|
131
|
+
// After the interrupt, the for await loop exits, runOnce returns, and
|
|
132
|
+
// runAgent detects this.paused and re-queues the task with resume info.
|
|
133
|
+
this.activeQueries.forEach(q => { q.interrupt().catch(() => { }); });
|
|
134
|
+
this.log(-1, "Pausing agents…");
|
|
135
|
+
}
|
|
129
136
|
}
|
|
130
137
|
/** Returns the rate-limit window currently holding the swarm back -- rejected first, then highest utilization. */
|
|
131
138
|
mostConstrainedWindow() {
|
|
@@ -232,7 +239,7 @@ export class Swarm {
|
|
|
232
239
|
abort() {
|
|
233
240
|
this.aborted = true;
|
|
234
241
|
this.queue.length = 0;
|
|
235
|
-
this.activeQueries.forEach(q => q.
|
|
242
|
+
this.activeQueries.forEach(q => { q.interrupt().catch(() => { }); });
|
|
236
243
|
this.activeQueries.clear();
|
|
237
244
|
}
|
|
238
245
|
/** Re-queue all errored agents' tasks for retry within this wave. */
|
|
@@ -431,11 +438,17 @@ export class Swarm {
|
|
|
431
438
|
}
|
|
432
439
|
// ── Agent execution ──
|
|
433
440
|
async runAgent(task) {
|
|
441
|
+
// Guard: if pause was triggered between dispatch and here, re-queue immediately.
|
|
442
|
+
// The worker already shifted this task, so unshift puts it back for resume.
|
|
443
|
+
if (this.paused) {
|
|
444
|
+
this.queue.unshift(task);
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
434
447
|
const id = this.nextId++;
|
|
435
448
|
const agent = { id, task, status: "running", startedAt: Date.now(), toolCalls: 0 };
|
|
436
449
|
this.agents.push(agent);
|
|
437
|
-
let agentCwd = task.cwd || this.config.cwd;
|
|
438
|
-
if (this.config.useWorktrees && this.worktreeBase && !task.noWorktree) {
|
|
450
|
+
let agentCwd = task.agentCwd || task.cwd || this.config.cwd;
|
|
451
|
+
if (this.config.useWorktrees && this.worktreeBase && !task.noWorktree && !task.agentCwd) {
|
|
439
452
|
const branch = `swarm/task-${id}`;
|
|
440
453
|
const dir = join(this.worktreeBase, `agent-${id}`);
|
|
441
454
|
let baseRef;
|
|
@@ -477,7 +490,8 @@ export class Swarm {
|
|
|
477
490
|
this.log(id, `Worktree failed after retry -- running without isolation`);
|
|
478
491
|
}
|
|
479
492
|
}
|
|
480
|
-
|
|
493
|
+
const isResumed = !!task.resumeSessionId;
|
|
494
|
+
this.log(id, isResumed ? `Resuming: ${task.prompt.slice(0, 60)}` : `Starting: ${task.prompt.slice(0, 60)}`);
|
|
481
495
|
const maxRetries = this.config.maxRetries ?? 2;
|
|
482
496
|
const inactivityMs = this.config.agentTimeoutMs ?? 15 * 60 * 1000;
|
|
483
497
|
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
@@ -491,7 +505,7 @@ export class Swarm {
|
|
|
491
505
|
}
|
|
492
506
|
try {
|
|
493
507
|
const perm = this.config.permissionMode ?? "auto";
|
|
494
|
-
let resumeSessionId;
|
|
508
|
+
let resumeSessionId = task.resumeSessionId;
|
|
495
509
|
let resumePrompt = "Continue. Complete the task.";
|
|
496
510
|
const runOnce = async (isResume) => {
|
|
497
511
|
const preamble = "Keep files under ~500 lines. If a file would exceed that, split it.\n\n";
|
|
@@ -529,6 +543,16 @@ export class Swarm {
|
|
|
529
543
|
timer = setTimeout(check, timeoutMs);
|
|
530
544
|
});
|
|
531
545
|
this.activeQueries.add(agentQuery);
|
|
546
|
+
// Guard: if pause was triggered between runAgent check and here, close the query
|
|
547
|
+
// immediately so requeueIfPaused can catch it without running a turn.
|
|
548
|
+
if (this.paused) {
|
|
549
|
+
this.activeQueries.delete(agentQuery);
|
|
550
|
+
try {
|
|
551
|
+
agentQuery.close();
|
|
552
|
+
}
|
|
553
|
+
catch { }
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
532
556
|
try {
|
|
533
557
|
await Promise.race([
|
|
534
558
|
(async () => {
|
|
@@ -553,17 +577,47 @@ export class Swarm {
|
|
|
553
577
|
catch { }
|
|
554
578
|
}
|
|
555
579
|
};
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
580
|
+
// Helper: re-queue this task with resume info when paused mid-turn.
|
|
581
|
+
const requeueIfPaused = () => {
|
|
582
|
+
if (!this.paused || agent.status !== "running")
|
|
583
|
+
return false;
|
|
584
|
+
agent.status = "paused";
|
|
585
|
+
this.log(id, "Paused mid-task");
|
|
586
|
+
if (resumeSessionId) {
|
|
587
|
+
this.queue.unshift({ ...task, resumeSessionId, agentCwd });
|
|
588
|
+
}
|
|
589
|
+
return true;
|
|
590
|
+
};
|
|
591
|
+
if (isResumed && resumeSessionId) {
|
|
592
|
+
// Resumed task: continue the existing SDK session
|
|
593
|
+
try {
|
|
562
594
|
await runOnce(true);
|
|
563
595
|
}
|
|
564
|
-
|
|
565
|
-
|
|
596
|
+
catch (nudgeErr) {
|
|
597
|
+
if (nudgeErr instanceof NudgeError && resumeSessionId) {
|
|
598
|
+
this.log(id, `Silent ${Math.round(inactivityMs / 60000)}m -- resuming with continue`);
|
|
599
|
+
await runOnce(true);
|
|
600
|
+
}
|
|
601
|
+
else
|
|
602
|
+
throw nudgeErr;
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
else {
|
|
606
|
+
// Fresh task: start with the task prompt
|
|
607
|
+
try {
|
|
608
|
+
await runOnce(false);
|
|
609
|
+
}
|
|
610
|
+
catch (nudgeErr) {
|
|
611
|
+
if (nudgeErr instanceof NudgeError && resumeSessionId) {
|
|
612
|
+
this.log(id, `Silent ${Math.round(inactivityMs / 60000)}m -- resuming with continue`);
|
|
613
|
+
await runOnce(true);
|
|
614
|
+
}
|
|
615
|
+
else
|
|
616
|
+
throw nudgeErr;
|
|
617
|
+
}
|
|
566
618
|
}
|
|
619
|
+
if (requeueIfPaused())
|
|
620
|
+
return;
|
|
567
621
|
if (resumeSessionId && agent.status === "running") {
|
|
568
622
|
try {
|
|
569
623
|
this.log(id, "Simplify pass");
|
|
@@ -574,6 +628,8 @@ export class Swarm {
|
|
|
574
628
|
this.log(id, "Simplify pass skipped");
|
|
575
629
|
}
|
|
576
630
|
}
|
|
631
|
+
if (requeueIfPaused())
|
|
632
|
+
return;
|
|
577
633
|
if (agent.status === "running") {
|
|
578
634
|
agent.finishedAt = Date.now();
|
|
579
635
|
const duration = agent.finishedAt - (agent.startedAt || agent.finishedAt);
|
package/dist/types.d.ts
CHANGED
|
@@ -10,6 +10,10 @@ export interface Task {
|
|
|
10
10
|
model?: string;
|
|
11
11
|
/** When true, skip worktree isolation -- run in the real project directory with env files, dependencies, and local config. */
|
|
12
12
|
noWorktree?: boolean;
|
|
13
|
+
/** SDK session ID to resume from (set when task was paused mid-turn). */
|
|
14
|
+
resumeSessionId?: string;
|
|
15
|
+
/** Working directory preserved from a previous run (worktree dir for paused-and-resumed tasks). */
|
|
16
|
+
agentCwd?: string;
|
|
13
17
|
}
|
|
14
18
|
/** Schema for a JSON task file that defines a batch of work for the swarm. */
|
|
15
19
|
export interface TaskFile {
|
|
@@ -45,7 +49,7 @@ export interface TaskFile {
|
|
|
45
49
|
})[];
|
|
46
50
|
}
|
|
47
51
|
/** Lifecycle status of a single agent. */
|
|
48
|
-
export type AgentStatus = "pending" | "running" | "done" | "error";
|
|
52
|
+
export type AgentStatus = "pending" | "running" | "paused" | "done" | "error";
|
|
49
53
|
/** Live mutable state for one agent, used by the UI and orchestrator. */
|
|
50
54
|
export interface AgentState {
|
|
51
55
|
/** Sequential agent index (0-based), used for display and log correlation. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-overnight",
|
|
3
|
-
"version": "1.25.
|
|
3
|
+
"version": "1.25.10",
|
|
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.
|
|
3
|
+
"version": "1.25.10",
|
|
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"
|