claude-overnight 1.0.0 → 1.0.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 +72 -38
- package/dist/planner.d.ts +2 -2
- package/dist/planner.js +58 -47
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -330,6 +330,24 @@ function findIncompleteRun(rootDir) {
|
|
|
330
330
|
catch { }
|
|
331
331
|
return null;
|
|
332
332
|
}
|
|
333
|
+
/** Find orphaned designs: a run where thinking succeeded but orchestration crashed (has designs, no run.json). */
|
|
334
|
+
function findOrphanedDesigns(rootDir) {
|
|
335
|
+
const runsDir = join(rootDir, "runs");
|
|
336
|
+
try {
|
|
337
|
+
const dirs = readdirSync(runsDir).sort().reverse();
|
|
338
|
+
for (const d of dirs) {
|
|
339
|
+
const runDir = join(runsDir, d);
|
|
340
|
+
const hasState = existsSync(join(runDir, "run.json"));
|
|
341
|
+
if (hasState)
|
|
342
|
+
continue; // has state — either complete or properly resumable
|
|
343
|
+
const designs = readMdDir(join(runDir, "designs"));
|
|
344
|
+
if (designs)
|
|
345
|
+
return runDir;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
catch { }
|
|
349
|
+
return null;
|
|
350
|
+
}
|
|
333
351
|
/** Read final status + goal from all completed previous runs (newest first, max 5). */
|
|
334
352
|
function readPreviousRunKnowledge(rootDir) {
|
|
335
353
|
const runsDir = join(rootDir, "runs");
|
|
@@ -769,8 +787,9 @@ async function main() {
|
|
|
769
787
|
let thinkingUsed = 0;
|
|
770
788
|
let thinkingCost = 0, thinkingIn = 0, thinkingOut = 0, thinkingTools = 0;
|
|
771
789
|
let thinkingHistory;
|
|
772
|
-
// Create run directory
|
|
773
|
-
const
|
|
790
|
+
// Create run directory — reuse orphaned run (thinking succeeded, orchestration crashed) if available
|
|
791
|
+
const orphanedDir = !resuming ? findOrphanedDesigns(rootDir) : null;
|
|
792
|
+
const runDir = resuming && resumeRunDir ? resumeRunDir : (orphanedDir ?? createRunDir(rootDir));
|
|
774
793
|
const previousKnowledge = readPreviousRunKnowledge(rootDir);
|
|
775
794
|
// ── Plan phase (interactive: review loop, non-interactive: auto-plan or skip) ──
|
|
776
795
|
const needsPlan = tasks.length === 0;
|
|
@@ -839,56 +858,71 @@ async function main() {
|
|
|
839
858
|
}
|
|
840
859
|
// ── From here, fully autonomous — no more user interaction ──
|
|
841
860
|
process.stdout.write("\x1B[?25l");
|
|
842
|
-
// Phase 2: Thinking wave
|
|
861
|
+
// Phase 2: Thinking wave — skip if design docs already exist (e.g. previous orchestration failed)
|
|
843
862
|
mkdirSync(designDir, { recursive: true });
|
|
844
|
-
const
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
tasks: thinkingTasks, concurrency, cwd,
|
|
848
|
-
model: plannerModel,
|
|
849
|
-
permissionMode,
|
|
850
|
-
useWorktrees: false,
|
|
851
|
-
mergeStrategy: "yolo",
|
|
852
|
-
agentTimeoutMs,
|
|
853
|
-
usageCap,
|
|
854
|
-
});
|
|
855
|
-
const stopThinkRender = startRenderLoop(thinkingSwarm);
|
|
856
|
-
try {
|
|
857
|
-
await thinkingSwarm.run();
|
|
863
|
+
const existingDesigns = readMdDir(designDir);
|
|
864
|
+
if (existingDesigns) {
|
|
865
|
+
console.log(chalk.green(`\n ✓ Reusing ${readdirSync(designDir).filter(f => f.endsWith(".md")).length} existing design docs`) + chalk.dim(` (from prior attempt)\n`));
|
|
858
866
|
}
|
|
859
|
-
|
|
860
|
-
|
|
867
|
+
else {
|
|
868
|
+
const thinkingTasks = buildThinkingTasks(objective, themes, designDir, plannerModel, previousKnowledge || undefined);
|
|
869
|
+
console.log(chalk.cyan(`\n ◆ Thinking: ${thinkingTasks.length} agents exploring...\n`));
|
|
870
|
+
const thinkingSwarm = new Swarm({
|
|
871
|
+
tasks: thinkingTasks, concurrency, cwd,
|
|
872
|
+
model: plannerModel,
|
|
873
|
+
permissionMode,
|
|
874
|
+
useWorktrees: false,
|
|
875
|
+
mergeStrategy: "yolo",
|
|
876
|
+
agentTimeoutMs,
|
|
877
|
+
usageCap,
|
|
878
|
+
});
|
|
879
|
+
const stopThinkRender = startRenderLoop(thinkingSwarm);
|
|
880
|
+
try {
|
|
881
|
+
await thinkingSwarm.run();
|
|
882
|
+
}
|
|
883
|
+
finally {
|
|
884
|
+
stopThinkRender();
|
|
885
|
+
}
|
|
886
|
+
console.log(renderSummary(thinkingSwarm));
|
|
887
|
+
thinkingUsed = thinkingSwarm.completed + thinkingSwarm.failed;
|
|
888
|
+
thinkingCost = thinkingSwarm.totalCostUsd;
|
|
889
|
+
thinkingIn = thinkingSwarm.totalInputTokens;
|
|
890
|
+
thinkingOut = thinkingSwarm.totalOutputTokens;
|
|
891
|
+
thinkingTools = thinkingSwarm.agents.reduce((sum, a) => sum + a.toolCalls, 0);
|
|
892
|
+
// Record thinking wave so steering knows what happened
|
|
893
|
+
thinkingHistory = {
|
|
894
|
+
wave: -1,
|
|
895
|
+
kind: "think",
|
|
896
|
+
tasks: thinkingSwarm.agents.map(a => ({
|
|
897
|
+
prompt: a.task.prompt.slice(0, 200),
|
|
898
|
+
status: a.status,
|
|
899
|
+
filesChanged: a.filesChanged,
|
|
900
|
+
error: a.error,
|
|
901
|
+
})),
|
|
902
|
+
};
|
|
903
|
+
// Wait for rate limit reset before orchestration
|
|
904
|
+
if (thinkingSwarm.rateLimitResetsAt) {
|
|
905
|
+
const waitMs = thinkingSwarm.rateLimitResetsAt - Date.now();
|
|
906
|
+
if (waitMs > 0) {
|
|
907
|
+
console.log(chalk.dim(` Waiting ${Math.ceil(waitMs / 1000)}s for rate limit reset...`));
|
|
908
|
+
await new Promise(r => setTimeout(r, waitMs + 2000));
|
|
909
|
+
}
|
|
910
|
+
}
|
|
861
911
|
}
|
|
862
|
-
console.log(renderSummary(thinkingSwarm));
|
|
863
|
-
thinkingUsed = thinkingSwarm.completed + thinkingSwarm.failed;
|
|
864
|
-
thinkingCost = thinkingSwarm.totalCostUsd;
|
|
865
|
-
thinkingIn = thinkingSwarm.totalInputTokens;
|
|
866
|
-
thinkingOut = thinkingSwarm.totalOutputTokens;
|
|
867
|
-
thinkingTools = thinkingSwarm.agents.reduce((sum, a) => sum + a.toolCalls, 0);
|
|
868
|
-
// Record thinking wave so steering knows what happened
|
|
869
|
-
thinkingHistory = {
|
|
870
|
-
wave: -1,
|
|
871
|
-
kind: "think",
|
|
872
|
-
tasks: thinkingSwarm.agents.map(a => ({
|
|
873
|
-
prompt: a.task.prompt.slice(0, 200),
|
|
874
|
-
status: a.status,
|
|
875
|
-
filesChanged: a.filesChanged,
|
|
876
|
-
error: a.error,
|
|
877
|
-
})),
|
|
878
|
-
};
|
|
879
912
|
// Phase 3: Orchestrate from design docs
|
|
880
913
|
const designs = readMdDir(designDir);
|
|
914
|
+
const taskFile = join(runDir, "tasks.json");
|
|
881
915
|
if (designs) {
|
|
882
916
|
const orchBudget = Math.min(50, Math.max(concurrency, Math.ceil(((budget ?? 10) - thinkingUsed) * 0.5)));
|
|
883
917
|
const flexNote = `This is wave 1 of an adaptive multi-wave run (total budget: ${(budget ?? 10) - thinkingUsed}). Plan the highest-impact foundational work first. Future waves will iterate based on what's learned.`;
|
|
884
918
|
console.log(chalk.cyan(`\n ◆ Orchestrating plan...\n`));
|
|
885
|
-
tasks = await orchestrate(objective, designs, cwd, plannerModel, workerModel, permissionMode, orchBudget, concurrency, makeProgressLog(), flexNote);
|
|
919
|
+
tasks = await orchestrate(objective, designs, cwd, plannerModel, workerModel, permissionMode, orchBudget, concurrency, makeProgressLog(), flexNote, taskFile);
|
|
886
920
|
process.stdout.write(`\x1B[2K\r ${chalk.green(`\u2713 ${tasks.length} tasks`)}\n\n`);
|
|
887
921
|
}
|
|
888
922
|
else {
|
|
889
923
|
console.log(chalk.yellow(`\n No design docs — falling back to direct planning\n`));
|
|
890
924
|
const waveBudget = Math.min(50, Math.max(concurrency, Math.ceil(((budget ?? 10) - thinkingUsed) * 0.5)));
|
|
891
|
-
tasks = await planTasks(objective, cwd, plannerModel, workerModel, permissionMode, waveBudget, concurrency, makeProgressLog());
|
|
925
|
+
tasks = await planTasks(objective, cwd, plannerModel, workerModel, permissionMode, waveBudget, concurrency, makeProgressLog(), undefined, taskFile);
|
|
892
926
|
process.stdout.write(`\x1B[2K\r ${chalk.green(`\u2713 ${tasks.length} tasks`)}\n\n`);
|
|
893
927
|
}
|
|
894
928
|
}
|
package/dist/planner.d.ts
CHANGED
|
@@ -27,10 +27,10 @@ export interface RunMemory {
|
|
|
27
27
|
}
|
|
28
28
|
export type ModelTier = "opus" | "sonnet" | "haiku" | "unknown";
|
|
29
29
|
export declare function detectModelTier(model: string): ModelTier;
|
|
30
|
-
export declare function planTasks(objective: string, cwd: string, plannerModel: string, workerModel: string, permissionMode: PermMode, budget: number | undefined, concurrency: number, onLog: (text: string) => void, flexNote?: string): Promise<Task[]>;
|
|
30
|
+
export declare function planTasks(objective: string, cwd: string, plannerModel: string, workerModel: string, permissionMode: PermMode, budget: number | undefined, concurrency: number, onLog: (text: string) => void, flexNote?: string, outFile?: string): Promise<Task[]>;
|
|
31
31
|
export declare function identifyThemes(objective: string, count: number, model: string, permissionMode: PermMode): Promise<string[]>;
|
|
32
32
|
export declare function buildThinkingTasks(objective: string, themes: string[], designDir: string, plannerModel: string, previousKnowledge?: string): Task[];
|
|
33
33
|
export declare function buildReflectionTasks(objective: string, goal: string, reflectionDir: string, waveNum: number, plannerModel: string): Task[];
|
|
34
|
-
export declare function orchestrate(objective: string, designDocs: string, cwd: string, plannerModel: string, workerModel: string, permissionMode: PermMode, budget: number, concurrency: number, onLog: (text: string) => void, flexNote?: string): Promise<Task[]>;
|
|
34
|
+
export declare function orchestrate(objective: string, designDocs: string, cwd: string, plannerModel: string, workerModel: string, permissionMode: PermMode, budget: number, concurrency: number, onLog: (text: string) => void, flexNote?: string, outFile?: string): Promise<Task[]>;
|
|
35
35
|
export declare function refinePlan(objective: string, previousTasks: Task[], feedback: string, cwd: string, plannerModel: string, workerModel: string, permissionMode: PermMode, budget: number | undefined, concurrency: number, onLog: (text: string) => void): Promise<Task[]>;
|
|
36
36
|
export declare function steerWave(objective: string, history: WaveSummary[], remainingBudget: number, cwd: string, plannerModel: string, workerModel: string, permissionMode: PermMode, concurrency: number, onLog: (text: string) => void, runMemory?: RunMemory): Promise<SteerResult>;
|
package/dist/planner.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { query } from "@anthropic-ai/claude-agent-sdk";
|
|
2
|
+
import { readFileSync } from "fs";
|
|
2
3
|
const INACTIVITY_MS = 5 * 60 * 1000;
|
|
3
4
|
export function detectModelTier(model) {
|
|
4
5
|
const m = model.toLowerCase();
|
|
@@ -179,8 +180,8 @@ async function runPlannerQueryOnce(prompt, opts, onLog) {
|
|
|
179
180
|
options: {
|
|
180
181
|
cwd: opts.cwd,
|
|
181
182
|
model: opts.model,
|
|
182
|
-
tools: ["Read", "Glob", "Grep"],
|
|
183
|
-
allowedTools: ["Read", "Glob", "Grep"],
|
|
183
|
+
tools: ["Read", "Glob", "Grep", "Write"],
|
|
184
|
+
allowedTools: ["Read", "Glob", "Grep", "Write"],
|
|
184
185
|
permissionMode: opts.permissionMode,
|
|
185
186
|
...(opts.permissionMode === "bypassPermissions" && { allowDangerouslySkipPermissions: true }),
|
|
186
187
|
persistSession: false,
|
|
@@ -311,21 +312,15 @@ function postProcess(raw, budget, onLog) {
|
|
|
311
312
|
tasks = tasks.map((t, i) => ({ ...t, id: String(i) }));
|
|
312
313
|
return tasks;
|
|
313
314
|
}
|
|
314
|
-
export async function planTasks(objective, cwd, plannerModel, workerModel, permissionMode, budget, concurrency, onLog, flexNote) {
|
|
315
|
+
export async function planTasks(objective, cwd, plannerModel, workerModel, permissionMode, budget, concurrency, onLog, flexNote, outFile) {
|
|
315
316
|
onLog("Analyzing codebase...");
|
|
316
|
-
const
|
|
317
|
+
const prompt = plannerPrompt(objective, workerModel, budget, concurrency, flexNote);
|
|
318
|
+
const fileInstruction = outFile ? `\n\nAFTER generating the JSON, also write it to ${outFile} using the Write tool.` : "";
|
|
319
|
+
const resultText = await runPlannerQuery(prompt + fileInstruction, { cwd, model: plannerModel, permissionMode }, onLog);
|
|
317
320
|
const parsed = await extractTaskJson(resultText, async () => {
|
|
318
|
-
onLog("Retrying
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
prompt: `Your previous response did not contain valid JSON. Output ONLY a JSON object:\n{"tasks":[{"prompt":"..."}]}`,
|
|
322
|
-
options: { cwd, model: plannerModel, permissionMode, ...(permissionMode === "bypassPermissions" && { allowDangerouslySkipPermissions: true }), persistSession: false },
|
|
323
|
-
})) {
|
|
324
|
-
if (msg.type === "result" && msg.subtype === "success")
|
|
325
|
-
retryText = msg.result || "";
|
|
326
|
-
}
|
|
327
|
-
return retryText;
|
|
328
|
-
});
|
|
321
|
+
onLog("Retrying...");
|
|
322
|
+
return runPlannerQuery(`Your previous response was not valid JSON. Respond with ONLY a JSON object {"tasks":[{"prompt":"..."}]}.\n\n${prompt}`, { cwd, model: plannerModel, permissionMode }, onLog);
|
|
323
|
+
}, onLog, outFile);
|
|
329
324
|
let tasks = (parsed.tasks || []).map((t, i) => ({
|
|
330
325
|
id: String(i),
|
|
331
326
|
prompt: typeof t === "string" ? t : t.prompt,
|
|
@@ -428,9 +423,10 @@ End with ## Priorities: rank the top 3 things that would most improve the result
|
|
|
428
423
|
},
|
|
429
424
|
];
|
|
430
425
|
}
|
|
431
|
-
export async function orchestrate(objective, designDocs, cwd, plannerModel, workerModel, permissionMode, budget, concurrency, onLog, flexNote) {
|
|
426
|
+
export async function orchestrate(objective, designDocs, cwd, plannerModel, workerModel, permissionMode, budget, concurrency, onLog, flexNote, outFile) {
|
|
432
427
|
const capability = modelCapabilityBlock(workerModel);
|
|
433
428
|
const flexLine = flexNote ? `\n\n${flexNote}` : "";
|
|
429
|
+
const fileInstruction = outFile ? `\n\nAFTER generating the JSON, also write it to ${outFile} using the Write tool.` : "";
|
|
434
430
|
const prompt = `You are a tech lead planning a sprint based on your team's codebase research.
|
|
435
431
|
|
|
436
432
|
Objective: ${objective}
|
|
@@ -452,21 +448,13 @@ Requirements:
|
|
|
452
448
|
- Priority order: foundational first, polish last${flexLine}
|
|
453
449
|
|
|
454
450
|
Respond with ONLY a JSON object (no markdown fences):
|
|
455
|
-
{"tasks": [{"prompt": "..."}]}`;
|
|
451
|
+
{"tasks": [{"prompt": "..."}]}${fileInstruction}`;
|
|
456
452
|
onLog("Synthesizing...");
|
|
457
453
|
const resultText = await runPlannerQuery(prompt, { cwd, model: plannerModel, permissionMode }, onLog);
|
|
458
454
|
const parsed = await extractTaskJson(resultText, async () => {
|
|
459
455
|
onLog("Retrying...");
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
prompt: `Output ONLY a JSON object:\n{"tasks":[{"prompt":"..."}]}`,
|
|
463
|
-
options: { cwd, model: plannerModel, permissionMode, ...(permissionMode === "bypassPermissions" && { allowDangerouslySkipPermissions: true }), persistSession: false },
|
|
464
|
-
})) {
|
|
465
|
-
if (msg.type === "result" && msg.subtype === "success")
|
|
466
|
-
retryText = msg.result || "";
|
|
467
|
-
}
|
|
468
|
-
return retryText;
|
|
469
|
-
});
|
|
456
|
+
return runPlannerQuery(`Your previous response was not valid JSON. Respond with ONLY a JSON object {"tasks":[{"prompt":"..."}]}.\n\n${prompt}`, { cwd, model: plannerModel, permissionMode }, onLog);
|
|
457
|
+
}, onLog, outFile);
|
|
470
458
|
let tasks = (parsed.tasks || []).map((t, i) => ({
|
|
471
459
|
id: String(i),
|
|
472
460
|
prompt: typeof t === "string" ? t : t.prompt,
|
|
@@ -505,16 +493,8 @@ Respond with ONLY a JSON object (no markdown):
|
|
|
505
493
|
const resultText = await runPlannerQuery(prompt, { cwd, model: plannerModel, permissionMode }, onLog);
|
|
506
494
|
const parsed = await extractTaskJson(resultText, async () => {
|
|
507
495
|
onLog("Retrying...");
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
prompt: `Output ONLY a JSON object:\n{"tasks":[{"prompt":"..."}]}`,
|
|
511
|
-
options: { cwd, model: plannerModel, permissionMode, ...(permissionMode === "bypassPermissions" && { allowDangerouslySkipPermissions: true }), persistSession: false },
|
|
512
|
-
})) {
|
|
513
|
-
if (msg.type === "result" && msg.subtype === "success")
|
|
514
|
-
retryText = msg.result || "";
|
|
515
|
-
}
|
|
516
|
-
return retryText;
|
|
517
|
-
});
|
|
496
|
+
return runPlannerQuery(`Your previous response was not valid JSON. Respond with ONLY a JSON object {"tasks":[{"prompt":"..."}]}.\n\n${prompt}`, { cwd, model: plannerModel, permissionMode }, onLog);
|
|
497
|
+
}, onLog);
|
|
518
498
|
let tasks = (parsed.tasks || []).map((t, i) => ({
|
|
519
499
|
id: String(i),
|
|
520
500
|
prompt: typeof t === "string" ? t : t.prompt,
|
|
@@ -574,17 +554,55 @@ function attemptJsonParse(text) {
|
|
|
574
554
|
catch { }
|
|
575
555
|
}
|
|
576
556
|
}
|
|
557
|
+
// Salvage truncated task JSON — find last complete task object and close
|
|
558
|
+
const tasksMatch = text.match(/\{\s*"tasks"\s*:\s*\[/);
|
|
559
|
+
if (tasksMatch) {
|
|
560
|
+
const lastBrace = text.lastIndexOf("}");
|
|
561
|
+
if (lastBrace > tasksMatch.index) {
|
|
562
|
+
const salvaged = text.slice(tasksMatch.index, lastBrace + 1) + "]}";
|
|
563
|
+
try {
|
|
564
|
+
const obj = JSON.parse(salvaged);
|
|
565
|
+
if (obj?.tasks?.length > 0)
|
|
566
|
+
return obj;
|
|
567
|
+
}
|
|
568
|
+
catch { }
|
|
569
|
+
}
|
|
570
|
+
}
|
|
577
571
|
return null;
|
|
578
572
|
}
|
|
579
|
-
/** Extract task JSON
|
|
580
|
-
async function extractTaskJson(raw, retry) {
|
|
573
|
+
/** Extract task JSON: try file first, then in-memory parse, then retry with context. */
|
|
574
|
+
async function extractTaskJson(raw, retry, onLog, outFile) {
|
|
575
|
+
// 1. Try reading from file (most resilient — survives truncated output)
|
|
576
|
+
if (outFile) {
|
|
577
|
+
try {
|
|
578
|
+
const fileContent = readFileSync(outFile, "utf-8");
|
|
579
|
+
const fromFile = attemptJsonParse(fileContent);
|
|
580
|
+
if (fromFile?.tasks)
|
|
581
|
+
return fromFile;
|
|
582
|
+
}
|
|
583
|
+
catch { }
|
|
584
|
+
}
|
|
585
|
+
// 2. Try parsing result text
|
|
581
586
|
const first = attemptJsonParse(raw);
|
|
582
587
|
if (first?.tasks)
|
|
583
588
|
return first;
|
|
589
|
+
onLog?.(`Parse failed (${raw.length} chars): ${raw.slice(0, 300)}`);
|
|
590
|
+
// 3. Retry with full context
|
|
584
591
|
const retryText = await retry();
|
|
592
|
+
// Re-check file in case retry wrote it
|
|
593
|
+
if (outFile) {
|
|
594
|
+
try {
|
|
595
|
+
const fileContent = readFileSync(outFile, "utf-8");
|
|
596
|
+
const fromFile = attemptJsonParse(fileContent);
|
|
597
|
+
if (fromFile?.tasks)
|
|
598
|
+
return fromFile;
|
|
599
|
+
}
|
|
600
|
+
catch { }
|
|
601
|
+
}
|
|
585
602
|
const second = attemptJsonParse(retryText);
|
|
586
603
|
if (second?.tasks)
|
|
587
604
|
return second;
|
|
605
|
+
onLog?.(`Retry failed (${retryText.length} chars): ${retryText.slice(0, 300)}`);
|
|
588
606
|
throw new Error("Planner did not return valid task JSON after retry");
|
|
589
607
|
}
|
|
590
608
|
// ── Wave steering ──
|
|
@@ -655,14 +673,7 @@ Respond with ONLY a JSON object (no markdown fences):
|
|
|
655
673
|
if (first)
|
|
656
674
|
return first;
|
|
657
675
|
onLog("Retrying...");
|
|
658
|
-
|
|
659
|
-
for await (const msg of query({
|
|
660
|
-
prompt: `Output ONLY a JSON object: {"action":"execute"|"reflect"|"done","done":true/false,"reasoning":"...","tasks":[{"prompt":"..."}]}`,
|
|
661
|
-
options: { cwd, model: plannerModel, permissionMode, ...(permissionMode === "bypassPermissions" && { allowDangerouslySkipPermissions: true }), persistSession: false },
|
|
662
|
-
})) {
|
|
663
|
-
if (msg.type === "result" && msg.subtype === "success")
|
|
664
|
-
retryText = msg.result || "";
|
|
665
|
-
}
|
|
676
|
+
const retryText = await runPlannerQuery(`Your previous response was not valid JSON. Respond with ONLY a JSON object {"action":"execute"|"reflect"|"done","done":true/false,"reasoning":"...","tasks":[{"prompt":"..."}]}.\n\n${prompt}`, { cwd, model: plannerModel, permissionMode }, onLog);
|
|
666
677
|
return attemptJsonParse(retryText) ?? { action: "done", done: true, reasoning: "Could not parse steering response" };
|
|
667
678
|
})();
|
|
668
679
|
const action = parsed.action || (parsed.done ? "done" : "execute");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-overnight",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.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": {
|