@workermill/agent 0.4.3 → 0.4.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/dist/plan-validator.d.ts +1 -1
- package/dist/plan-validator.js +1 -1
- package/dist/planner.js +74 -27
- package/package.json +1 -1
package/dist/plan-validator.d.ts
CHANGED
|
@@ -39,7 +39,7 @@ export interface CriticResult {
|
|
|
39
39
|
suggestedChanges?: string[];
|
|
40
40
|
}>;
|
|
41
41
|
}
|
|
42
|
-
declare const AUTO_APPROVAL_THRESHOLD =
|
|
42
|
+
declare const AUTO_APPROVAL_THRESHOLD = 75;
|
|
43
43
|
/**
|
|
44
44
|
* Parse execution plan JSON from raw Claude CLI output.
|
|
45
45
|
* Mirrors server-side parseExecutionPlan() in planning-agent-local.ts.
|
package/dist/plan-validator.js
CHANGED
|
@@ -16,7 +16,7 @@ import { generateText } from "./providers.js";
|
|
|
16
16
|
// CONSTANTS
|
|
17
17
|
// ============================================================================
|
|
18
18
|
const MAX_TARGET_FILES = 5;
|
|
19
|
-
const AUTO_APPROVAL_THRESHOLD =
|
|
19
|
+
const AUTO_APPROVAL_THRESHOLD = 75;
|
|
20
20
|
// ============================================================================
|
|
21
21
|
// PLAN PARSING
|
|
22
22
|
// ============================================================================
|
package/dist/planner.js
CHANGED
|
@@ -297,8 +297,10 @@ async function cloneTargetRepo(repo, token, scmProvider, taskId) {
|
|
|
297
297
|
* Run an analyst agent via Claude CLI with tool access to the cloned repo.
|
|
298
298
|
* Returns the analyst's report text, or an empty string on failure.
|
|
299
299
|
*/
|
|
300
|
-
function runAnalyst(claudePath, model, prompt, repoPath, env, timeoutMs =
|
|
300
|
+
function runAnalyst(name, claudePath, model, prompt, repoPath, env, timeoutMs = 900_000) {
|
|
301
|
+
const label = chalk.blue(`[${name}]`);
|
|
301
302
|
return new Promise((resolve) => {
|
|
303
|
+
console.log(`${ts()} ${label} Starting (${chalk.dim(model)})...`);
|
|
302
304
|
const proc = spawn(claudePath, [
|
|
303
305
|
"--print",
|
|
304
306
|
"--verbose",
|
|
@@ -310,15 +312,23 @@ function runAnalyst(claudePath, model, prompt, repoPath, env, timeoutMs = 120_00
|
|
|
310
312
|
env,
|
|
311
313
|
stdio: ["pipe", "pipe", "pipe"],
|
|
312
314
|
});
|
|
313
|
-
// Write prompt via stdin (same as runClaudeCli
|
|
315
|
+
// Write prompt via stdin (same as runClaudeCli)
|
|
314
316
|
proc.stdin.write(prompt);
|
|
315
317
|
proc.stdin.end();
|
|
316
318
|
let resultText = "";
|
|
317
319
|
let fullText = "";
|
|
318
320
|
let stderrOutput = "";
|
|
319
321
|
let lineBuffer = "";
|
|
322
|
+
let toolCalls = 0;
|
|
323
|
+
let timedOut = false;
|
|
324
|
+
const startMs = Date.now();
|
|
320
325
|
proc.stderr.on("data", (chunk) => {
|
|
321
|
-
|
|
326
|
+
const text = chunk.toString();
|
|
327
|
+
stderrOutput += text;
|
|
328
|
+
// Show stderr in real-time so we can see what's happening
|
|
329
|
+
for (const line of text.split("\n").filter((l) => l.trim())) {
|
|
330
|
+
console.log(`${ts()} ${label} ${chalk.red("stderr:")} ${line.trim()}`);
|
|
331
|
+
}
|
|
322
332
|
});
|
|
323
333
|
proc.stdout.on("data", (data) => {
|
|
324
334
|
lineBuffer += data.toString();
|
|
@@ -333,6 +343,11 @@ function runAnalyst(claudePath, model, prompt, repoPath, env, timeoutMs = 120_00
|
|
|
333
343
|
if (event.type === "content_block_delta" && event.delta?.text) {
|
|
334
344
|
fullText += event.delta.text;
|
|
335
345
|
}
|
|
346
|
+
else if (event.type === "content_block_start" && event.content_block?.type === "tool_use") {
|
|
347
|
+
toolCalls++;
|
|
348
|
+
const toolName = event.content_block?.name || "unknown";
|
|
349
|
+
console.log(`${ts()} ${label} ${chalk.dim(`Tool: ${toolName}`)} (${toolCalls} total)`);
|
|
350
|
+
}
|
|
336
351
|
else if (event.type === "result" && event.result) {
|
|
337
352
|
resultText =
|
|
338
353
|
typeof event.result === "string" ? event.result : "";
|
|
@@ -344,19 +359,32 @@ function runAnalyst(claudePath, model, prompt, repoPath, env, timeoutMs = 120_00
|
|
|
344
359
|
}
|
|
345
360
|
});
|
|
346
361
|
const timeout = setTimeout(() => {
|
|
362
|
+
timedOut = true;
|
|
347
363
|
proc.kill("SIGTERM");
|
|
364
|
+
const elapsed = Math.round((Date.now() - startMs) / 1000);
|
|
365
|
+
console.log(`${ts()} ${label} ${chalk.yellow("⚠ Timed out")} after ${elapsed}s (${toolCalls} tool calls, ${fullText.length} chars)`);
|
|
348
366
|
resolve(resultText || fullText || "");
|
|
349
367
|
}, timeoutMs);
|
|
350
368
|
proc.on("exit", (code) => {
|
|
351
369
|
clearTimeout(timeout);
|
|
352
|
-
|
|
353
|
-
|
|
370
|
+
const elapsed = Math.round((Date.now() - startMs) / 1000);
|
|
371
|
+
if (timedOut)
|
|
372
|
+
return; // already resolved
|
|
373
|
+
const output = resultText || fullText || "";
|
|
374
|
+
if (code === 0 && output.length > 0) {
|
|
375
|
+
console.log(`${ts()} ${label} ${chalk.green("✓ Done")} in ${elapsed}s (${toolCalls} tool calls, ${output.length} chars)`);
|
|
354
376
|
}
|
|
355
|
-
|
|
377
|
+
else if (code !== 0) {
|
|
378
|
+
console.log(`${ts()} ${label} ${chalk.red(`✗ Exited ${code}`)} after ${elapsed}s — ${stderrOutput.substring(0, 150) || "no stderr"}`);
|
|
379
|
+
}
|
|
380
|
+
else {
|
|
381
|
+
console.log(`${ts()} ${label} ${chalk.yellow("⚠ Empty output")} after ${elapsed}s (${toolCalls} tool calls)`);
|
|
382
|
+
}
|
|
383
|
+
resolve(output);
|
|
356
384
|
});
|
|
357
385
|
proc.on("error", (err) => {
|
|
358
386
|
clearTimeout(timeout);
|
|
359
|
-
console.
|
|
387
|
+
console.log(`${ts()} ${label} ${chalk.red("✗ Spawn failed:")} ${err.message}`);
|
|
360
388
|
resolve("");
|
|
361
389
|
});
|
|
362
390
|
});
|
|
@@ -411,19 +439,44 @@ async function runTeamPlanning(task, basePrompt, claudePath, model, env, repoPat
|
|
|
411
439
|
await postLog(taskId, `${PREFIX} Team planning: running codebase, requirements, and risk analysts in parallel...`);
|
|
412
440
|
await postProgress(taskId, "reading_repo", Math.round((Date.now() - startTime) / 1000), "Running parallel analysis agents...", 0, 0);
|
|
413
441
|
const analysisModel = model.includes("opus") ? "sonnet" : model;
|
|
414
|
-
const
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
442
|
+
const MAX_TEAM_RETRIES = 3;
|
|
443
|
+
let codebaseReport = "";
|
|
444
|
+
let requirementsReport = "";
|
|
445
|
+
let riskReport = "";
|
|
446
|
+
for (let attempt = 1; attempt <= MAX_TEAM_RETRIES; attempt++) {
|
|
447
|
+
if (attempt > 1) {
|
|
448
|
+
console.log(`${ts()} ${taskLabel} ${chalk.magenta("◆ Team planning")} — retry ${attempt}/${MAX_TEAM_RETRIES}...`);
|
|
449
|
+
await postLog(taskId, `${PREFIX} Team analysis retry ${attempt}/${MAX_TEAM_RETRIES}...`);
|
|
450
|
+
}
|
|
451
|
+
const [codebaseResult, requirementsResult, riskResult] = await Promise.allSettled([
|
|
452
|
+
codebaseReport ? Promise.resolve(codebaseReport) : runAnalyst("Codebase", claudePath, analysisModel, CODEBASE_ANALYST_PROMPT, repoPath, env),
|
|
453
|
+
requirementsReport ? Promise.resolve(requirementsReport) : runAnalyst("Requirements", claudePath, analysisModel, makeRequirementsAnalystPrompt(task), repoPath, env),
|
|
454
|
+
riskReport ? Promise.resolve(riskReport) : runAnalyst("Risk", claudePath, analysisModel, makeRiskAssessorPrompt(task), repoPath, env),
|
|
455
|
+
]);
|
|
456
|
+
if (!codebaseReport && codebaseResult.status === "fulfilled") {
|
|
457
|
+
codebaseReport = codebaseResult.value;
|
|
458
|
+
}
|
|
459
|
+
if (!requirementsReport && requirementsResult.status === "fulfilled") {
|
|
460
|
+
requirementsReport = requirementsResult.value;
|
|
461
|
+
}
|
|
462
|
+
if (!riskReport && riskResult.status === "fulfilled") {
|
|
463
|
+
riskReport = riskResult.value;
|
|
464
|
+
}
|
|
465
|
+
const successCount = [codebaseReport, requirementsReport, riskReport].filter((r) => r.length > 0).length;
|
|
466
|
+
const analysisElapsed = Math.round((Date.now() - startTime) / 1000);
|
|
467
|
+
console.log(`${ts()} ${taskLabel} Analysis attempt ${attempt}: ${successCount}/3 reports (${analysisElapsed}s)`);
|
|
468
|
+
if (successCount > 0) {
|
|
469
|
+
console.log(`${ts()} ${taskLabel} ${chalk.green("✓")} Analysis complete: ${successCount}/3 reports (${analysisElapsed}s)`);
|
|
470
|
+
await postLog(taskId, `${PREFIX} Team analysis complete: ${successCount}/3 reports in ${formatElapsed(analysisElapsed)}. Synthesizing plan...`);
|
|
471
|
+
await postProgress(taskId, "analyzing", analysisElapsed, "Synthesizing analysis reports...", 0, 0);
|
|
472
|
+
break;
|
|
473
|
+
}
|
|
474
|
+
if (attempt === MAX_TEAM_RETRIES) {
|
|
475
|
+
console.log(`${ts()} ${taskLabel} ${chalk.yellow("⚠")} All analysts failed after ${MAX_TEAM_RETRIES} attempts, falling back to single-agent planning`);
|
|
476
|
+
await postLog(taskId, `${PREFIX} All analysis agents failed after ${MAX_TEAM_RETRIES} attempts — falling back to single-agent planning`);
|
|
477
|
+
return runClaudeCli(claudePath, model, basePrompt, env, taskId, startTime);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
427
480
|
// Build enhanced prompt with analysis reports
|
|
428
481
|
const sections = [];
|
|
429
482
|
if (codebaseReport) {
|
|
@@ -435,12 +488,6 @@ async function runTeamPlanning(task, basePrompt, claudePath, model, env, repoPat
|
|
|
435
488
|
if (riskReport) {
|
|
436
489
|
sections.push(`## Risk Assessment\n\n${riskReport}`);
|
|
437
490
|
}
|
|
438
|
-
if (sections.length === 0) {
|
|
439
|
-
// All analysts failed — fall through to regular planning
|
|
440
|
-
console.log(`${ts()} ${taskLabel} ${chalk.yellow("⚠")} All analysts failed, falling back to single-agent planning`);
|
|
441
|
-
await postLog(taskId, `${PREFIX} All analysis agents failed — falling back to single-agent planning`);
|
|
442
|
-
return runClaudeCli(claudePath, model, basePrompt, env, taskId, startTime);
|
|
443
|
-
}
|
|
444
491
|
const enhancedPrompt = basePrompt +
|
|
445
492
|
"\n\n" +
|
|
446
493
|
sections.join("\n\n") +
|
|
@@ -520,7 +567,7 @@ export async function planTask(task, config, credentials) {
|
|
|
520
567
|
// 2a. Generate plan via Claude CLI (Anthropic) or HTTP API (other providers)
|
|
521
568
|
let rawOutput;
|
|
522
569
|
try {
|
|
523
|
-
if (isAnthropicPlanning && config.teamPlanningEnabled && repoPath
|
|
570
|
+
if (isAnthropicPlanning && config.teamPlanningEnabled && repoPath) {
|
|
524
571
|
rawOutput = await runTeamPlanning(task, currentPrompt, claudePath, cliModel, cleanEnv, repoPath, task.id, startTime);
|
|
525
572
|
}
|
|
526
573
|
else if (isAnthropicPlanning) {
|