claude-overnight 1.11.4 → 1.11.6
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/README.md +12 -1
- package/dist/render.js +4 -5
- package/dist/run.js +28 -3
- package/dist/state.d.ts +18 -0
- package/dist/state.js +59 -0
- package/dist/swarm.d.ts +0 -1
- package/dist/swarm.js +56 -35
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -14,6 +14,15 @@ npm install -g claude-overnight
|
|
|
14
14
|
|
|
15
15
|
Requires Node.js >= 20 and Claude authentication (`claude auth login`, or set `ANTHROPIC_API_KEY`).
|
|
16
16
|
|
|
17
|
+
### Claude Code plugin
|
|
18
|
+
|
|
19
|
+
This repo also ships a Claude Code plugin so any Claude instance (inside this repo or any other) knows how to use, inspect, and resume `claude-overnight` runs:
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
/plugin marketplace add Fornace/claude-overnight
|
|
23
|
+
/plugin install claude-overnight
|
|
24
|
+
```
|
|
25
|
+
|
|
17
26
|
## Quick start
|
|
18
27
|
|
|
19
28
|
```bash
|
|
@@ -131,7 +140,9 @@ If the thinking phase succeeds but orchestration crashes, the next run detects t
|
|
|
131
140
|
|
|
132
141
|
**Knowledge carries forward** — new runs inherit knowledge from completed previous runs. Thinking agents and steering see what past runs built. Run 2 knows run 1 already built the auth system.
|
|
133
142
|
|
|
134
|
-
Add `.claude-overnight
|
|
143
|
+
Add `.claude-overnight/` to your `.gitignore` (with the trailing slash — see below).
|
|
144
|
+
|
|
145
|
+
A separate, tiny `claude-overnight.log.md` is also written at the repo root on every run. It's human-readable, append-only, one block per run (objective, start/finish, cost, outcome, branch), and is designed to be **committed** — so even after `.claude-overnight/` is cleaned up you can still recover which prompt produced which commits. Use `.claude-overnight/` (with trailing slash) in your gitignore so this file isn't matched by accident.
|
|
135
146
|
|
|
136
147
|
## Other usage modes
|
|
137
148
|
|
package/dist/render.js
CHANGED
|
@@ -80,10 +80,9 @@ function renderUsageBars(out, w, swarm) {
|
|
|
80
80
|
}
|
|
81
81
|
let label = `${Math.round(pct * 100)}% used`;
|
|
82
82
|
if (swarm.cappedOut) {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
label = chalk.yellow(`Capped at ${capFrac != null ? Math.round(capFrac * 100) : 100}% \u2014 finishing active`);
|
|
83
|
+
label = swarm.extraUsageBudget != null
|
|
84
|
+
? chalk.red(`Budget $${swarm.extraUsageBudget} exhausted \u2014 finishing active`)
|
|
85
|
+
: chalk.yellow(`Capped at ${capFrac != null ? Math.round(capFrac * 100) : 100}% \u2014 finishing active`);
|
|
87
86
|
}
|
|
88
87
|
else if (swarm.rateLimitPaused > 0) {
|
|
89
88
|
label = chalk.yellow(`Cooling down \u2014 ${swarm.rateLimitPaused} worker(s) waiting`);
|
|
@@ -94,7 +93,7 @@ function renderUsageBars(out, w, swarm) {
|
|
|
94
93
|
label = chalk.red(`Waiting for reset ${mm > 0 ? `${mm}m ${ss}s` : `${ss}s`}`);
|
|
95
94
|
}
|
|
96
95
|
if (swarm.isUsingOverage && !swarm.cappedOut)
|
|
97
|
-
label += chalk.red(" [
|
|
96
|
+
label += chalk.red(" [OVERAGE]");
|
|
98
97
|
const prefix = windowLabel ? chalk.dim(windowLabel.padEnd(6)) : chalk.dim("Usage ");
|
|
99
98
|
out.push(` ${prefix}${barStr} ${label}`);
|
|
100
99
|
};
|
package/dist/run.js
CHANGED
|
@@ -9,7 +9,7 @@ import { RunDisplay } from "./ui.js";
|
|
|
9
9
|
import { renderSummary } from "./render.js";
|
|
10
10
|
import { fmtTokens } from "./render.js";
|
|
11
11
|
import { isAuthError } from "./cli.js";
|
|
12
|
-
import { readRunMemory, writeStatus, writeGoalUpdate, saveRunState, saveWaveSession, loadWaveHistory, recordBranches, archiveMilestone, writeSteerInbox, consumeSteerInbox, countSteerInbox, } from "./state.js";
|
|
12
|
+
import { readRunMemory, writeStatus, writeGoalUpdate, saveRunState, saveWaveSession, loadWaveHistory, recordBranches, archiveMilestone, writeSteerInbox, consumeSteerInbox, countSteerInbox, appendOvernightLogStart, updateOvernightLogEnd, } from "./state.js";
|
|
13
13
|
export async function executeRun(cfg) {
|
|
14
14
|
const restore = () => { try {
|
|
15
15
|
process.stdout.write("\x1B[?25h\n");
|
|
@@ -160,6 +160,20 @@ export async function executeRun(cfg) {
|
|
|
160
160
|
catch { }
|
|
161
161
|
}
|
|
162
162
|
const waveMerge = (flex && runBranch) ? "yolo" : mergeStrategy;
|
|
163
|
+
const runId = runDir.split(/[/\\]/).pop() ?? "";
|
|
164
|
+
if (!cfg.resuming) {
|
|
165
|
+
try {
|
|
166
|
+
appendOvernightLogStart(cwd, runId, {
|
|
167
|
+
objective: objective || "",
|
|
168
|
+
model: workerModel,
|
|
169
|
+
budget: cfg.budget,
|
|
170
|
+
flex,
|
|
171
|
+
usageCap,
|
|
172
|
+
branch: runBranch,
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
catch { }
|
|
176
|
+
}
|
|
163
177
|
let stopping = false;
|
|
164
178
|
const gracefulStop = () => {
|
|
165
179
|
if (stopping) {
|
|
@@ -369,6 +383,17 @@ export async function executeRun(cfg) {
|
|
|
369
383
|
}
|
|
370
384
|
catch { }
|
|
371
385
|
}
|
|
386
|
+
try {
|
|
387
|
+
updateOvernightLogEnd(cwd, runId, {
|
|
388
|
+
cost: accCost,
|
|
389
|
+
completed: accCompleted,
|
|
390
|
+
failed: accFailed,
|
|
391
|
+
waves: waveNum + 1,
|
|
392
|
+
phase: finalPhase,
|
|
393
|
+
elapsedSec: Math.round((Date.now() - cfg.runStartedAt) / 1000),
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
catch { }
|
|
372
397
|
if (runBranch && originalRef) {
|
|
373
398
|
try {
|
|
374
399
|
execSync(`git checkout "${originalRef}"`, { cwd, encoding: "utf-8", stdio: "pipe" });
|
|
@@ -390,7 +415,7 @@ export async function executeRun(cfg) {
|
|
|
390
415
|
else if (remaining <= 0)
|
|
391
416
|
console.log(chalk.bold.yellow(` CLAUDE OVERNIGHT — BUDGET EXHAUSTED`));
|
|
392
417
|
else if (lastCapped)
|
|
393
|
-
console.log(chalk.bold.yellow(` CLAUDE OVERNIGHT —
|
|
418
|
+
console.log(chalk.bold.yellow(` CLAUDE OVERNIGHT — BUDGET EXHAUSTED`));
|
|
394
419
|
else if (stopping || lastAborted)
|
|
395
420
|
console.log(chalk.bold.yellow(` CLAUDE OVERNIGHT — INTERRUPTED`));
|
|
396
421
|
else
|
|
@@ -406,7 +431,7 @@ export async function executeRun(cfg) {
|
|
|
406
431
|
for (const [k1, v1, k2, v2] of statRows)
|
|
407
432
|
console.log(` ${k1} ${v1.padEnd(20)} ${k2} ${v2}`);
|
|
408
433
|
if (lastCapped)
|
|
409
|
-
console.log(` ${chalk.yellow(`
|
|
434
|
+
console.log(` ${chalk.yellow(`Overage budget exhausted`)}`);
|
|
410
435
|
console.log("");
|
|
411
436
|
const statusFile = join(runDir, "status.md");
|
|
412
437
|
if (existsSync(statusFile)) {
|
package/dist/state.d.ts
CHANGED
|
@@ -11,6 +11,24 @@ export declare function writeSteerInbox(runDir: string, text: string): string;
|
|
|
11
11
|
export declare function consumeSteerInbox(runDir: string, waveNum: number): number;
|
|
12
12
|
export declare function writeStatus(baseDir: string, status: string): void;
|
|
13
13
|
export declare function writeGoalUpdate(baseDir: string, update: string): void;
|
|
14
|
+
export interface OvernightLogStart {
|
|
15
|
+
objective: string;
|
|
16
|
+
model: string;
|
|
17
|
+
budget: number;
|
|
18
|
+
flex: boolean;
|
|
19
|
+
usageCap?: number;
|
|
20
|
+
branch?: string;
|
|
21
|
+
}
|
|
22
|
+
export interface OvernightLogEnd {
|
|
23
|
+
cost: number;
|
|
24
|
+
completed: number;
|
|
25
|
+
failed: number;
|
|
26
|
+
waves: number;
|
|
27
|
+
phase: string;
|
|
28
|
+
elapsedSec: number;
|
|
29
|
+
}
|
|
30
|
+
export declare function appendOvernightLogStart(cwd: string, runId: string, meta: OvernightLogStart): void;
|
|
31
|
+
export declare function updateOvernightLogEnd(cwd: string, runId: string, meta: OvernightLogEnd): void;
|
|
14
32
|
export declare function saveRunState(runDir: string, state: RunState): void;
|
|
15
33
|
export declare function loadRunState(runDir: string): RunState | null;
|
|
16
34
|
export declare function findIncompleteRuns(rootDir: string, filterCwd: string): {
|
package/dist/state.js
CHANGED
|
@@ -109,6 +109,65 @@ export function writeGoalUpdate(baseDir, update) {
|
|
|
109
109
|
const trimmed = full.length > 4000 ? full.slice(0, 1000) + "\n\n...\n\n" + full.slice(-3000) : full;
|
|
110
110
|
writeFileSync(goalPath, trimmed, "utf-8");
|
|
111
111
|
}
|
|
112
|
+
// ── Durable run log (claude-overnight.log.md, committed) ──
|
|
113
|
+
// Tiny human-readable record per run so the objective survives even after
|
|
114
|
+
// .claude-overnight/ is cleaned up. Append-only friendly: each run's block
|
|
115
|
+
// is keyed by runId (the run dir basename) so concurrent runs on different
|
|
116
|
+
// machines don't collide.
|
|
117
|
+
function escapeRegExp(s) {
|
|
118
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
119
|
+
}
|
|
120
|
+
export function appendOvernightLogStart(cwd, runId, meta) {
|
|
121
|
+
const path = join(cwd, "claude-overnight.log.md");
|
|
122
|
+
const startedAt = new Date().toISOString().replace("T", " ").slice(0, 19) + " UTC";
|
|
123
|
+
const capStr = meta.usageCap != null ? ` · **Cap:** ${meta.usageCap}%` : "";
|
|
124
|
+
const branchLine = meta.branch ? `\n- **Branch:** ${meta.branch}` : "";
|
|
125
|
+
const block = [
|
|
126
|
+
`## ${runId}`,
|
|
127
|
+
`- **Objective:** ${meta.objective || "(none)"}`,
|
|
128
|
+
`- **Started:** ${startedAt}`,
|
|
129
|
+
`- **Model:** ${meta.model} · **Budget:** ${meta.budget} · **Flex:** ${meta.flex ? "yes" : "no"}${capStr}${branchLine}`,
|
|
130
|
+
`- **Status:** running`,
|
|
131
|
+
"",
|
|
132
|
+
"",
|
|
133
|
+
].join("\n");
|
|
134
|
+
let existing = "";
|
|
135
|
+
try {
|
|
136
|
+
existing = readFileSync(path, "utf-8");
|
|
137
|
+
}
|
|
138
|
+
catch { }
|
|
139
|
+
const header = existing ? "" : "# claude-overnight — run history\n\n";
|
|
140
|
+
writeFileSync(path, header + existing + block, "utf-8");
|
|
141
|
+
}
|
|
142
|
+
export function updateOvernightLogEnd(cwd, runId, meta) {
|
|
143
|
+
const path = join(cwd, "claude-overnight.log.md");
|
|
144
|
+
let existing = "";
|
|
145
|
+
try {
|
|
146
|
+
existing = readFileSync(path, "utf-8");
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
const finishedAt = new Date().toISOString().replace("T", " ").slice(0, 19) + " UTC";
|
|
152
|
+
const sec = meta.elapsedSec;
|
|
153
|
+
const elapsed = sec < 60 ? `${sec}s` : sec < 3600 ? `${Math.floor(sec / 60)}m ${sec % 60}s` : `${Math.floor(sec / 3600)}h ${Math.floor((sec % 3600) / 60)}m`;
|
|
154
|
+
const outcome = meta.phase === "done" ? "✓ done" : meta.phase === "capped" ? "⊘ capped" : "⊘ stopped";
|
|
155
|
+
const endLines = [
|
|
156
|
+
`- **Finished:** ${finishedAt} (${elapsed})`,
|
|
157
|
+
`- **Cost:** $${meta.cost.toFixed(2)}`,
|
|
158
|
+
`- **Tasks:** ${meta.completed} done${meta.failed > 0 ? ` / ${meta.failed} failed` : ""} · **Waves:** ${meta.waves}`,
|
|
159
|
+
`- **Status:** ${outcome}`,
|
|
160
|
+
].join("\n");
|
|
161
|
+
const re = new RegExp(`(## ${escapeRegExp(runId)}\\n(?:(?!\\n## )[\\s\\S])*?)- \\*\\*Status:\\*\\* running`);
|
|
162
|
+
if (re.test(existing)) {
|
|
163
|
+
writeFileSync(path, existing.replace(re, `$1${endLines}`), "utf-8");
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
const header = existing ? "" : "# claude-overnight — run history\n\n";
|
|
167
|
+
const block = `## ${runId}\n${endLines}\n\n`;
|
|
168
|
+
writeFileSync(path, header + existing + block, "utf-8");
|
|
169
|
+
}
|
|
170
|
+
}
|
|
112
171
|
// ── Run state persistence ──
|
|
113
172
|
export function saveRunState(runDir, state) {
|
|
114
173
|
mkdirSync(runDir, { recursive: true });
|
package/dist/swarm.d.ts
CHANGED
package/dist/swarm.js
CHANGED
|
@@ -33,7 +33,6 @@ export class Swarm {
|
|
|
33
33
|
rateLimitWindows = new Map();
|
|
34
34
|
rateLimitPaused = 0;
|
|
35
35
|
isUsingOverage = false;
|
|
36
|
-
overageDisabledReason;
|
|
37
36
|
overageCostUsd = 0;
|
|
38
37
|
queue;
|
|
39
38
|
config;
|
|
@@ -180,43 +179,43 @@ export class Swarm {
|
|
|
180
179
|
async throttle() {
|
|
181
180
|
if (this.cappedOut)
|
|
182
181
|
return;
|
|
183
|
-
|
|
184
|
-
this.capForOverage(`Extra usage detected but not allowed — stopping dispatch`);
|
|
185
|
-
return;
|
|
186
|
-
}
|
|
182
|
+
// Hard stop: overage budget exhausted (only legitimate cap)
|
|
187
183
|
if (this.isUsingOverage && this.extraUsageBudget != null && this.overageCostUsd >= this.extraUsageBudget) {
|
|
188
184
|
this.capForOverage(`Extra usage budget $${this.extraUsageBudget} reached ($${this.overageCostUsd.toFixed(2)} spent) — stopping dispatch`);
|
|
189
185
|
return;
|
|
190
186
|
}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
187
|
+
// Wait loop: keep waiting until the blocking condition clears
|
|
188
|
+
// isUsingOverage is purely informational — the API enforces overage via 429s
|
|
189
|
+
// which the retry loop handles. Throttle only gates on actual rejections and user cap.
|
|
190
|
+
let consecutiveWaits = 0;
|
|
191
|
+
for (;;) {
|
|
192
|
+
if (this.aborted || this.cappedOut)
|
|
193
|
+
return;
|
|
194
|
+
const cap = this.usageCap;
|
|
195
|
+
const capExceeded = cap != null && cap < 1 && this.rateLimitUtilization >= cap;
|
|
196
|
+
const rejected = this.rateLimitResetsAt && this.rateLimitResetsAt > Date.now();
|
|
197
|
+
if (!capExceeded && !rejected)
|
|
198
|
+
break;
|
|
199
|
+
const fallbackMs = Math.min(300_000, 60_000 * (1 + consecutiveWaits * 2));
|
|
200
|
+
const waitMs = this.rateLimitResetsAt && this.rateLimitResetsAt > Date.now()
|
|
194
201
|
? Math.max(5000, this.rateLimitResetsAt - Date.now())
|
|
195
|
-
:
|
|
196
|
-
|
|
202
|
+
: fallbackMs;
|
|
203
|
+
const reason = capExceeded
|
|
204
|
+
? `Usage at ${Math.round(this.rateLimitUtilization * 100)}% (cap ${Math.round(cap * 100)}%)`
|
|
205
|
+
: "Rate limited";
|
|
206
|
+
this.log(-1, `${reason} — waiting ${Math.ceil(waitMs / 1000)}s then retrying`);
|
|
197
207
|
this.rateLimitPaused++;
|
|
198
208
|
await sleep(waitMs);
|
|
199
209
|
this.rateLimitPaused--;
|
|
200
210
|
this.rateLimitUtilization = 0;
|
|
201
211
|
this.rateLimitResetsAt = undefined;
|
|
202
|
-
|
|
203
|
-
}
|
|
204
|
-
if (this.rateLimitResetsAt) {
|
|
205
|
-
const resetTarget = this.rateLimitResetsAt;
|
|
206
|
-
const waitMs = resetTarget - Date.now();
|
|
207
|
-
if (waitMs > 0) {
|
|
208
|
-
this.log(-1, `Rate limited, pausing ${Math.ceil(waitMs / 1000)}s`);
|
|
209
|
-
this.rateLimitPaused++;
|
|
210
|
-
await sleep(waitMs);
|
|
211
|
-
this.rateLimitPaused--;
|
|
212
|
-
}
|
|
213
|
-
if (this.rateLimitResetsAt === resetTarget)
|
|
214
|
-
this.rateLimitResetsAt = undefined;
|
|
212
|
+
consecutiveWaits++;
|
|
215
213
|
}
|
|
216
|
-
|
|
214
|
+
// Soft delay: high utilization, pace requests
|
|
215
|
+
if (this.rateLimitUtilization > 0.75) {
|
|
217
216
|
const delay = Math.floor((this.rateLimitUtilization - 0.75) * 60000);
|
|
218
|
-
|
|
219
|
-
|
|
217
|
+
if (delay > 0)
|
|
218
|
+
await sleep(delay);
|
|
220
219
|
}
|
|
221
220
|
}
|
|
222
221
|
// ── Agent execution ──
|
|
@@ -370,6 +369,21 @@ export class Swarm {
|
|
|
370
369
|
catch (err) {
|
|
371
370
|
if (agent.status !== "running")
|
|
372
371
|
break;
|
|
372
|
+
// Rate-limit errors: wait and retry WITHOUT burning the retry budget
|
|
373
|
+
if (!this.aborted && isRateLimitError(err)) {
|
|
374
|
+
const waitMs = this.rateLimitResetsAt && this.rateLimitResetsAt > Date.now()
|
|
375
|
+
? Math.max(5000, this.rateLimitResetsAt - Date.now())
|
|
376
|
+
: 120_000;
|
|
377
|
+
this.log(id, `Rate limited — waiting ${Math.ceil(waitMs / 1000)}s (attempt not counted)`);
|
|
378
|
+
this.rateLimitPaused++;
|
|
379
|
+
await sleep(waitMs);
|
|
380
|
+
this.rateLimitPaused--;
|
|
381
|
+
this.isUsingOverage = false;
|
|
382
|
+
this.rateLimitUtilization = 0;
|
|
383
|
+
this.rateLimitResetsAt = undefined;
|
|
384
|
+
attempt--; // don't count this against retries
|
|
385
|
+
continue;
|
|
386
|
+
}
|
|
373
387
|
const canRetry = attempt < maxRetries && !this.aborted && isTransientError(err);
|
|
374
388
|
if (canRetry) {
|
|
375
389
|
this.log(id, `Transient error: ${String(err.message || err).slice(0, 80)}`);
|
|
@@ -460,26 +474,21 @@ export class Swarm {
|
|
|
460
474
|
const rl = msg;
|
|
461
475
|
const info = rl.rate_limit_info;
|
|
462
476
|
this.rateLimitUtilization = info.utilization ?? 0;
|
|
463
|
-
if (info.
|
|
477
|
+
if (info.resetsAt)
|
|
464
478
|
this.rateLimitResetsAt = info.resetsAt;
|
|
465
479
|
else if (info.status !== "rejected")
|
|
466
480
|
this.rateLimitResetsAt = undefined;
|
|
481
|
+
if (info.isUsingOverage)
|
|
482
|
+
this.isUsingOverage = true;
|
|
467
483
|
const windowType = info.rateLimitType;
|
|
468
484
|
if (windowType) {
|
|
469
485
|
this.rateLimitWindows.set(windowType, {
|
|
470
486
|
type: windowType, utilization: info.utilization ?? 0, status: info.status, resetsAt: info.resetsAt,
|
|
471
487
|
});
|
|
472
488
|
}
|
|
473
|
-
if (info.isUsingOverage)
|
|
474
|
-
this.isUsingOverage = true;
|
|
475
|
-
if (info.overageDisabledReason)
|
|
476
|
-
this.overageDisabledReason = info.overageDisabledReason;
|
|
477
|
-
if (this.isUsingOverage && !this.allowExtraUsage)
|
|
478
|
-
this.capForOverage(`Extra usage detected but not allowed — stopping dispatch`);
|
|
479
489
|
const pct = info.utilization != null ? `${Math.round(info.utilization * 100)}%` : "";
|
|
480
490
|
const overageTag = this.isUsingOverage ? " [EXTRA]" : "";
|
|
481
|
-
|
|
482
|
-
this.log(agent.id, `Rate: ${statusLabel} ${pct}${overageTag}${windowType ? ` (${windowType})` : ""}`);
|
|
491
|
+
this.log(agent.id, `Rate: ${info.status} ${pct}${overageTag}${windowType ? ` (${windowType})` : ""}`);
|
|
483
492
|
break;
|
|
484
493
|
}
|
|
485
494
|
}
|
|
@@ -491,6 +500,18 @@ class AgentTimeoutError extends Error {
|
|
|
491
500
|
this.name = "AgentTimeoutError";
|
|
492
501
|
}
|
|
493
502
|
}
|
|
503
|
+
function isRateLimitError(err) {
|
|
504
|
+
const status = err?.status ?? err?.statusCode;
|
|
505
|
+
if (status === 429)
|
|
506
|
+
return true;
|
|
507
|
+
const msg = String(err?.message || err).toLowerCase();
|
|
508
|
+
if (msg.includes("rate limit") || msg.includes("rate_limit") || msg.includes("too many requests"))
|
|
509
|
+
return true;
|
|
510
|
+
const cause = err?.cause;
|
|
511
|
+
if (cause && cause !== err)
|
|
512
|
+
return isRateLimitError(cause);
|
|
513
|
+
return false;
|
|
514
|
+
}
|
|
494
515
|
function isTransientError(err) {
|
|
495
516
|
if (err instanceof AgentTimeoutError)
|
|
496
517
|
return false;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-overnight",
|
|
3
|
-
"version": "1.11.
|
|
3
|
+
"version": "1.11.6",
|
|
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": {
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
"scripts": {
|
|
10
10
|
"build": "tsc",
|
|
11
11
|
"dev": "tsc --watch",
|
|
12
|
-
"start": "node dist/index.js"
|
|
12
|
+
"start": "node dist/index.js",
|
|
13
|
+
"prepublishOnly": "node scripts/sync-plugin-version.js"
|
|
13
14
|
},
|
|
14
15
|
"dependencies": {
|
|
15
16
|
"@anthropic-ai/claude-agent-sdk": "^0.2.92",
|