claude-overnight 1.50.5 → 1.51.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/core/_version.d.ts +1 -1
- package/dist/core/_version.js +1 -1
- package/dist/planner/query.js +20 -10
- package/dist/planner/steering.js +5 -1
- package/dist/providers/index.js +0 -3
- package/dist/run/run.js +11 -3
- package/dist/run/summary.d.ts +2 -0
- package/dist/run/summary.js +52 -28
- package/dist/run/wave-loop.js +2 -1
- package/dist/skills/librarian.js +28 -29
- package/package.json +1 -1
- package/plugins/claude-overnight/.claude-plugin/plugin.json +1 -1
package/dist/core/_version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const VERSION = "1.
|
|
1
|
+
export declare const VERSION = "1.51.1";
|
package/dist/core/_version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Auto-generated by build — do not edit manually.
|
|
2
|
-
export const VERSION = "1.
|
|
2
|
+
export const VERSION = "1.51.1";
|
package/dist/planner/query.js
CHANGED
|
@@ -21,10 +21,16 @@ let _envResolver;
|
|
|
21
21
|
export function setPlannerEnvResolver(fn) {
|
|
22
22
|
_envResolver = fn;
|
|
23
23
|
}
|
|
24
|
-
// ──
|
|
25
|
-
//
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
// ── Direct HTTP bypass for non-Anthropic endpoints ──
|
|
25
|
+
// The Claude Code CLI subprocess spawned by @anthropic-ai/claude-agent-sdk validates
|
|
26
|
+
// model names against its built-in Anthropic list and rejects custom ids (qwen3.6-plus,
|
|
27
|
+
// composer-2, etc.) pre-flight, even when ANTHROPIC_BASE_URL points at an Anthropic-
|
|
28
|
+
// compatible proxy. Bypass the SDK with a direct POST for any non-anthropic.com base.
|
|
29
|
+
function shouldUseDirectFetch(env) {
|
|
30
|
+
const base = env?.ANTHROPIC_BASE_URL;
|
|
31
|
+
if (!base)
|
|
32
|
+
return false;
|
|
33
|
+
return !/^https?:\/\/(api\.)?anthropic\.com/i.test(base);
|
|
28
34
|
}
|
|
29
35
|
async function runViaDirectFetch(prompt, opts, onLog) {
|
|
30
36
|
const env = opts.env ?? _envResolver?.(opts.model);
|
|
@@ -39,30 +45,34 @@ async function runViaDirectFetch(prompt, opts, onLog) {
|
|
|
39
45
|
await apiEndpointLimiter.waitIfNeeded();
|
|
40
46
|
const waited = await rl.waitIfNeeded();
|
|
41
47
|
if (waited > 0)
|
|
42
|
-
onLog(`
|
|
48
|
+
onLog(`Planner proxy rate gate — waited ${Math.round(waited / 1000)}s`, "event");
|
|
43
49
|
const res = await fetch(`${baseUrl}/v1/messages`, {
|
|
44
50
|
method: "POST",
|
|
45
|
-
headers: {
|
|
51
|
+
headers: {
|
|
52
|
+
"Content-Type": "application/json",
|
|
53
|
+
"Authorization": `Bearer ${authToken}`,
|
|
54
|
+
"anthropic-version": "2023-06-01",
|
|
55
|
+
},
|
|
46
56
|
body: JSON.stringify({ model: opts.model, max_tokens: 8192, messages: [{ role: "user", content: prompt }] }),
|
|
47
57
|
});
|
|
48
58
|
if (res.status === 429 && attempt < MAX_RETRIES) {
|
|
49
59
|
const waitMs = BACKOFF[attempt];
|
|
50
|
-
onLog(`
|
|
60
|
+
onLog(`Planner proxy rate limited — waiting ${Math.round(waitMs / 1000)}s`, "event");
|
|
51
61
|
await sleep(waitMs);
|
|
52
62
|
continue;
|
|
53
63
|
}
|
|
54
64
|
if (!res.ok)
|
|
55
|
-
throw new Error(`
|
|
65
|
+
throw new Error(`Planner proxy ${res.status}: ${(await res.text().catch(() => ""))}`);
|
|
56
66
|
rl.record();
|
|
57
67
|
apiEndpointLimiter.record();
|
|
58
68
|
const data = await res.json();
|
|
59
69
|
return data.content?.[0]?.text ?? "";
|
|
60
70
|
}
|
|
61
|
-
throw new Error("
|
|
71
|
+
throw new Error("Planner proxy direct fetch failed after retries");
|
|
62
72
|
}
|
|
63
73
|
export async function runPlannerQuery(prompt, opts, onLog) {
|
|
64
74
|
const env = opts.env ?? _envResolver?.(opts.model);
|
|
65
|
-
if (
|
|
75
|
+
if (shouldUseDirectFetch(env))
|
|
66
76
|
return runViaDirectFetch(prompt, opts, onLog);
|
|
67
77
|
const MAX_RETRIES = 3;
|
|
68
78
|
const BACKOFF = [30_000, 60_000, 120_000];
|
package/dist/planner/steering.js
CHANGED
|
@@ -27,7 +27,11 @@ export const STEER_SCHEMA = {
|
|
|
27
27
|
required: ["done", "tasks", "reasoning", "statusUpdate", "estimatedSessionsRemaining"],
|
|
28
28
|
},
|
|
29
29
|
};
|
|
30
|
-
|
|
30
|
+
// The base 30-1_steer template alone is ~7 KB, so any budget below that is
|
|
31
|
+
// unreachable no matter how aggressively we trim variables. 20 KB leaves room
|
|
32
|
+
// for the template + moderate run memory while still being a tiny fraction of
|
|
33
|
+
// any planner's context window.
|
|
34
|
+
const PROMPT_BUDGET = 20_000;
|
|
31
35
|
const DEFAULT_CAPS = {
|
|
32
36
|
milestones: 2000, designs: 1500, reflections: 1000,
|
|
33
37
|
verifications: 1000, previousRuns: 800, userGuidance: 4000,
|
package/dist/providers/index.js
CHANGED
|
@@ -109,9 +109,6 @@ export function envFor(p) {
|
|
|
109
109
|
base.ANTHROPIC_AUTH_TOKEN = key;
|
|
110
110
|
}
|
|
111
111
|
delete base.ANTHROPIC_API_KEY;
|
|
112
|
-
// Prevent CURSOR_API_KEY from leaking into non-proxy envs — would trip
|
|
113
|
-
// isCursorProxyEnv false-positive, silently rerouting through direct fetch
|
|
114
|
-
// which ignores outputFormat (no JSON schema enforcement).
|
|
115
112
|
delete base.CURSOR_API_KEY;
|
|
116
113
|
delete base.CURSOR_AUTH_TOKEN;
|
|
117
114
|
return base;
|
package/dist/run/run.js
CHANGED
|
@@ -545,10 +545,18 @@ export async function executeRun(cfg) {
|
|
|
545
545
|
display.stop();
|
|
546
546
|
// ── Finalize ──
|
|
547
547
|
const trulyDone = objectiveComplete || (!flex && remaining <= 0);
|
|
548
|
-
// User-initiated quit (or abort via 'q' / SIGINT / stall-watchdog) ⇒ save as
|
|
549
|
-
// "stopped" so resume.ts offers the run and the incomplete work comes back.
|
|
550
548
|
const userQuit = stopping || lastAborted;
|
|
551
549
|
const wasCapped = lastCapped && !userQuit;
|
|
550
|
+
// Determine specific exit reason for the end brief
|
|
551
|
+
let exitReason;
|
|
552
|
+
if (trulyDone)
|
|
553
|
+
exitReason = "done";
|
|
554
|
+
else if (userQuit)
|
|
555
|
+
exitReason = "user-interrupted";
|
|
556
|
+
else if (wasCapped || remaining <= 0)
|
|
557
|
+
exitReason = "budget-exhausted";
|
|
558
|
+
else
|
|
559
|
+
exitReason = "planner-gave-up"; // steering returned false, planner couldn't produce tasks
|
|
552
560
|
const finalPhase = trulyDone ? "done"
|
|
553
561
|
: userQuit ? "stopped"
|
|
554
562
|
: wasCapped ? "capped"
|
|
@@ -632,7 +640,7 @@ export async function executeRun(cfg) {
|
|
|
632
640
|
runDir, runBranch, objective, waveNum, runStartedAt: cfg.runStartedAt,
|
|
633
641
|
branches, waveHistory,
|
|
634
642
|
accCost, accCompleted, accFailed, accTools, accIn, accOut,
|
|
635
|
-
remaining, lastCapped, lastAborted, stopping, trulyDone,
|
|
643
|
+
remaining, lastCapped, lastAborted, stopping, trulyDone, exitReason,
|
|
636
644
|
peakWorkerCtxTokens, peakWorkerCtxPct,
|
|
637
645
|
currentSwarmLogFile: currentSwarm?.logFile,
|
|
638
646
|
narrativeDeps: {
|
package/dist/run/summary.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ export interface FinalNarrativeDeps {
|
|
|
11
11
|
/** Generate a longer narrative summary at run end. Awaited (not fire-and-forget)
|
|
12
12
|
* because the caller wants the text inline in the final status block. */
|
|
13
13
|
export declare function generateFinalNarrative(deps: FinalNarrativeDeps, phase: string): Promise<string>;
|
|
14
|
+
export type ExitReason = "done" | "budget-exhausted" | "user-interrupted" | "planner-gave-up" | "circuit-breaker" | "stalled";
|
|
14
15
|
export interface SummaryArgs {
|
|
15
16
|
runDir: string;
|
|
16
17
|
runBranch?: string;
|
|
@@ -30,6 +31,7 @@ export interface SummaryArgs {
|
|
|
30
31
|
lastAborted: boolean;
|
|
31
32
|
stopping: boolean;
|
|
32
33
|
trulyDone: boolean;
|
|
34
|
+
exitReason: ExitReason;
|
|
33
35
|
peakWorkerCtxTokens: number;
|
|
34
36
|
peakWorkerCtxPct: number;
|
|
35
37
|
currentSwarmLogFile?: string;
|
package/dist/run/summary.js
CHANGED
|
@@ -32,7 +32,7 @@ export async function generateFinalNarrative(deps, phase) {
|
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
export async function printFinalSummary(args) {
|
|
35
|
-
const { runDir, runBranch, objective, waveNum, runStartedAt, branches, waveHistory, accCost, accCompleted, accFailed, accTools, accIn, accOut, remaining, lastCapped,
|
|
35
|
+
const { runDir, runBranch, objective, waveNum, runStartedAt, branches, waveHistory, accCost, accCompleted, accFailed, accTools, accIn, accOut, remaining, lastCapped, exitReason, peakWorkerCtxTokens, peakWorkerCtxPct, currentSwarmLogFile, narrativeDeps, } = args;
|
|
36
36
|
const waves = waveNum + 1;
|
|
37
37
|
const elapsed = Math.round((Date.now() - runStartedAt) / 1000);
|
|
38
38
|
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`;
|
|
@@ -40,26 +40,31 @@ export async function printFinalSummary(args) {
|
|
|
40
40
|
const totalConflicts = branches.filter(b => b.status === "merge-failed").length;
|
|
41
41
|
const termW = Math.max((process.stdout.columns ?? 80) || 80, 50);
|
|
42
42
|
const rule = (c = "─") => chalk.dim(` ${c.repeat(Math.min(termW - 4, 60))}`);
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
const bannerChar = accFailed === 0 ? "━" : "─";
|
|
44
|
+
// Banner: title + subtitle explaining why the run ended
|
|
45
|
+
const banner = {
|
|
46
|
+
done: { icon: "✓", title: "CLAUDE OVERNIGHT -- COMPLETE", color: chalk.green, explain: "The planner determined the objective was achieved." },
|
|
47
|
+
"budget-exhausted": { icon: "⚠", title: "CLAUDE OVERNIGHT -- BUDGET EXHAUSTED", color: chalk.yellow, explain: "All allocated sessions were consumed." },
|
|
48
|
+
"user-interrupted": { icon: "⚠", title: "CLAUDE OVERNIGHT -- INTERRUPTED", color: chalk.yellow, explain: "You quit mid-run with [q] or a signal." },
|
|
49
|
+
"planner-gave-up": { icon: "⚠", title: "CLAUDE OVERNIGHT -- PLANNER GAVE UP", color: chalk.magenta, explain: "The planner could not decompose the remaining work into actionable tasks." },
|
|
50
|
+
"circuit-breaker": { icon: "⚠", title: "CLAUDE OVERNIGHT -- HALTED", color: chalk.red, explain: "2+ consecutive waves produced no merged changes." },
|
|
51
|
+
stalled: { icon: "⚠", title: "CLAUDE OVERNIGHT -- STALLED", color: chalk.magenta, explain: "No progress detected; the run was halted to preserve budget." },
|
|
52
|
+
}[exitReason] ?? { icon: "⚠", title: "CLAUDE OVERNIGHT -- STOPPED", color: chalk.magenta, explain: "The run ended without a clear reason." };
|
|
53
|
+
const narrativePhase = exitReason === "done" ? "complete"
|
|
54
|
+
: exitReason === "budget-exhausted" ? "budget exhausted"
|
|
55
|
+
: exitReason === "user-interrupted" ? "interrupted"
|
|
56
|
+
: exitReason === "planner-gave-up" ? "planner gave up"
|
|
57
|
+
: exitReason === "circuit-breaker" ? "circuit breaker"
|
|
58
|
+
: exitReason === "stalled" ? "stalled"
|
|
59
|
+
: "stopped";
|
|
47
60
|
process.stdout.write(chalk.dim(`\n Writing final summary…`));
|
|
48
|
-
const narrative = await generateFinalNarrative(narrativeDeps,
|
|
61
|
+
const narrative = await generateFinalNarrative(narrativeDeps, narrativePhase);
|
|
49
62
|
process.stdout.write("\r" + " ".repeat(40) + "\r");
|
|
50
63
|
console.log("");
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
console.log(
|
|
54
|
-
|
|
55
|
-
console.log(chalk.bold.green(` ✓ CLAUDE OVERNIGHT -- COMPLETE`));
|
|
56
|
-
else if (remaining <= 0 || lastCapped)
|
|
57
|
-
console.log(chalk.bold.yellow(` ⚠ CLAUDE OVERNIGHT -- BUDGET EXHAUSTED`));
|
|
58
|
-
else if (stopping || lastAborted)
|
|
59
|
-
console.log(chalk.bold.yellow(` ⚠ CLAUDE OVERNIGHT -- INTERRUPTED`));
|
|
60
|
-
else
|
|
61
|
-
console.log(chalk.bold.yellow(` ⚠ CLAUDE OVERNIGHT -- STOPPED`));
|
|
62
|
-
console.log(bannerColor(` ${bannerChar.repeat(Math.min(termW - 4, 60))}`));
|
|
64
|
+
console.log(banner.color(` ${bannerChar.repeat(Math.min(termW - 4, 60))}`));
|
|
65
|
+
console.log(chalk.bold(banner.color(` ${banner.icon} ${banner.title}`)));
|
|
66
|
+
console.log(chalk.dim(` ${banner.explain}`));
|
|
67
|
+
console.log(banner.color(` ${bannerChar.repeat(Math.min(termW - 4, 60))}`));
|
|
63
68
|
console.log("");
|
|
64
69
|
if (objective) {
|
|
65
70
|
console.log(chalk.bold(" Objective"));
|
|
@@ -162,15 +167,34 @@ export async function printFinalSummary(args) {
|
|
|
162
167
|
if (currentSwarmLogFile)
|
|
163
168
|
console.log(chalk.dim(` Log: ${currentSwarmLogFile}`));
|
|
164
169
|
console.log("");
|
|
165
|
-
console.log(
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
170
|
+
console.log(banner.color(` ${bannerChar.repeat(Math.min(termW - 4, 60))}`));
|
|
171
|
+
// Actionable next-steps based on exit reason
|
|
172
|
+
const endMsg = (() => {
|
|
173
|
+
switch (exitReason) {
|
|
174
|
+
case "done":
|
|
175
|
+
return "Review the diff, then ship it.";
|
|
176
|
+
case "budget-exhausted":
|
|
177
|
+
return remaining > 0
|
|
178
|
+
? "Budget sessions remaining but usage cap hit. Raise the cap or re-run with --resume."
|
|
179
|
+
: "All sessions spent. Re-run with --resume to continue, or raise the budget.";
|
|
180
|
+
case "user-interrupted":
|
|
181
|
+
return "Run preserved. Use --resume to pick up where this left off.";
|
|
182
|
+
case "planner-gave-up": {
|
|
183
|
+
const lines = ["Planner could not decompose remaining work."];
|
|
184
|
+
if (remaining > 0)
|
|
185
|
+
lines.push(`${remaining} sessions unused — the work may be too vague or out of scope.`);
|
|
186
|
+
lines.push("Refine the objective or break it down manually, then re-run.");
|
|
187
|
+
return lines.join(" ");
|
|
188
|
+
}
|
|
189
|
+
case "circuit-breaker":
|
|
190
|
+
return "No changes landed in 2+ waves. Check for merge conflicts or agent errors in the log.";
|
|
191
|
+
case "stalled":
|
|
192
|
+
return "Run halted to preserve budget. Inspect status.md for blockers, then --resume.";
|
|
193
|
+
default:
|
|
194
|
+
return "Run preserved. --resume to continue.";
|
|
195
|
+
}
|
|
196
|
+
})();
|
|
197
|
+
console.log(chalk.bold(banner.color(` ${endMsg}`)));
|
|
198
|
+
console.log(banner.color(` ${bannerChar.repeat(Math.min(termW - 4, 60))}`));
|
|
175
199
|
console.log("");
|
|
176
200
|
}
|
package/dist/run/wave-loop.js
CHANGED
|
@@ -362,12 +362,13 @@ export async function runWaveLoop(host, ctx) {
|
|
|
362
362
|
const librarianStart = Date.now();
|
|
363
363
|
let librarianPromoted = 0, librarianPatched = 0, librarianQuarantined = 0, librarianRejected = 0;
|
|
364
364
|
try {
|
|
365
|
+
const librarianModel = host.fastModel ?? host.workerModel;
|
|
365
366
|
const lr = await runLibrarian({
|
|
366
367
|
fingerprint: host.repoFingerprint,
|
|
367
368
|
runId: host.runId,
|
|
368
369
|
wave: host.waveNum,
|
|
369
370
|
cwd: ctx.cwd,
|
|
370
|
-
model:
|
|
371
|
+
model: librarianModel,
|
|
371
372
|
envForModel: ctx.envForModel,
|
|
372
373
|
});
|
|
373
374
|
librarianPromoted = lr.promoted;
|
package/dist/skills/librarian.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { query } from "@anthropic-ai/claude-agent-sdk";
|
|
2
1
|
import { readFileSync, writeFileSync, mkdirSync, renameSync, existsSync, readdirSync, appendFileSync, } from "node:fs";
|
|
3
2
|
import { join } from "node:path";
|
|
4
3
|
import { openSkillsDb } from "./index-db.js";
|
|
@@ -84,44 +83,44 @@ function buildSubagentInput(canon, candidates, abOutcomes) {
|
|
|
84
83
|
return JSON.stringify({ canon, candidates, ab_outcomes: abOutcomes });
|
|
85
84
|
}
|
|
86
85
|
// ── Subagent call ──
|
|
86
|
+
// Direct POST /v1/messages — no tools needed, so the Agent SDK's CLI subprocess
|
|
87
|
+
// (with its multi-KB built-in system prompt and turn loop) is pure overhead and
|
|
88
|
+
// also pre-flight-rejects non-Anthropic model ids (qwen, composer-2, ...) even
|
|
89
|
+
// when routed through an Anthropic-compatible proxy.
|
|
87
90
|
async function callLibrarianSubagent(input, data) {
|
|
88
91
|
const env = input.envForModel?.(input.model);
|
|
89
92
|
const prompt = renderPrompt("40_skills/40-3_librarian-wrap", { vars: { data } });
|
|
90
|
-
|
|
91
|
-
const
|
|
93
|
+
const baseUrl = (env?.ANTHROPIC_BASE_URL ?? process.env.ANTHROPIC_BASE_URL ?? "https://api.anthropic.com").replace(/\/$/, "");
|
|
94
|
+
const headers = {
|
|
95
|
+
"Content-Type": "application/json",
|
|
96
|
+
"anthropic-version": "2023-06-01",
|
|
97
|
+
};
|
|
98
|
+
const bearer = env?.ANTHROPIC_AUTH_TOKEN ?? process.env.ANTHROPIC_AUTH_TOKEN;
|
|
99
|
+
const apiKey = env?.ANTHROPIC_API_KEY ?? process.env.ANTHROPIC_API_KEY;
|
|
100
|
+
if (bearer)
|
|
101
|
+
headers["Authorization"] = `Bearer ${bearer}`;
|
|
102
|
+
else if (apiKey)
|
|
103
|
+
headers["x-api-key"] = apiKey;
|
|
92
104
|
try {
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
permissionMode: "bypassPermissions",
|
|
99
|
-
allowDangerouslySkipPermissions: true,
|
|
100
|
-
maxTurns: 8,
|
|
101
|
-
...(env && { env }),
|
|
102
|
-
},
|
|
105
|
+
const res = await fetch(`${baseUrl}/v1/messages`, {
|
|
106
|
+
method: "POST",
|
|
107
|
+
headers,
|
|
108
|
+
body: JSON.stringify({ model: input.model, max_tokens: 8192, messages: [{ role: "user", content: prompt }] }),
|
|
109
|
+
signal: AbortSignal.timeout(LIBRARIAN_TIMEOUT_MS),
|
|
103
110
|
});
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
if (timedOut) {
|
|
107
|
-
pq.interrupt().catch(() => { });
|
|
108
|
-
break;
|
|
109
|
-
}
|
|
110
|
-
if (msg.type === "result" && msg.subtype === "success") {
|
|
111
|
-
resultText = msg.result || "";
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
pq.close();
|
|
115
|
-
if (timedOut) {
|
|
116
|
-
process.stderr.write("[librarian] subagent timed out\n");
|
|
111
|
+
if (!res.ok) {
|
|
112
|
+
process.stderr.write(`[librarian] HTTP ${res.status}: ${(await res.text().catch(() => "")).slice(0, 200)}\n`);
|
|
117
113
|
return null;
|
|
118
114
|
}
|
|
119
|
-
|
|
115
|
+
const body = await res.json();
|
|
116
|
+
const resultText = body.content?.map(c => c.text ?? "").join("") ?? "";
|
|
120
117
|
const cleaned = resultText.replace(/^```(?:json)?\s*\n([\s\S]*?)\n```\s*$/, "$1").trim();
|
|
121
118
|
return JSON.parse(cleaned);
|
|
122
119
|
}
|
|
123
|
-
|
|
124
|
-
|
|
120
|
+
catch (err) {
|
|
121
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
122
|
+
process.stderr.write(`[librarian] ${msg.includes("aborted") ? "timed out" : `error: ${msg}`}\n`);
|
|
123
|
+
return null;
|
|
125
124
|
}
|
|
126
125
|
}
|
|
127
126
|
// ── Action application ──
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-overnight",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.51.1",
|
|
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.
|
|
3
|
+
"version": "1.51.1",
|
|
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"
|