@workermill/agent 0.6.0 → 0.6.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.
@@ -183,8 +183,8 @@ export function runCriticCli(claudePath, model, prompt, env) {
183
183
  });
184
184
  const timeout = setTimeout(() => {
185
185
  proc.kill("SIGTERM");
186
- reject(new Error("Critic CLI timed out after 3 minutes"));
187
- }, 180_000);
186
+ reject(new Error("Critic CLI timed out after 10 minutes"));
187
+ }, 600_000);
188
188
  proc.on("exit", (code) => {
189
189
  clearTimeout(timeout);
190
190
  if (code !== 0) {
@@ -262,7 +262,7 @@ export async function runCriticValidation(claudePath, model, prd, plan, env, tas
262
262
  if (!providerApiKey) {
263
263
  throw new Error(`No API key for critic provider "${effectiveProvider}"`);
264
264
  }
265
- rawCriticOutput = await generateText(effectiveProvider, model, criticPrompt, providerApiKey, { maxTokens: 4096, temperature: 0.3, timeoutMs: 180_000 });
265
+ rawCriticOutput = await generateText(effectiveProvider, model, criticPrompt, providerApiKey, { maxTokens: 4096, temperature: 0.3, timeoutMs: 600_000 });
266
266
  }
267
267
  const result = parseCriticResponse(rawCriticOutput);
268
268
  const statusIcon = result.score >= AUTO_APPROVAL_THRESHOLD
package/dist/planner.js CHANGED
@@ -456,7 +456,15 @@ Keep your report under 1500 words. Only report facts you verified with tools.`;
456
456
  *
457
457
  * Falls back to single-agent planning if anything goes wrong.
458
458
  */
459
- async function runTeamPlanning(task, basePrompt, claudePath, model, env, repoPath, taskId, startTime) {
459
+ /**
460
+ * Run team analysis: spawn 3 parallel analyst agents once, then return
461
+ * an enhanced prompt with their reports appended. Returns null if all
462
+ * analysts fail (caller should fall back to basePrompt).
463
+ *
464
+ * This runs ONCE before the planner-critic loop — analyst prompts don't
465
+ * include critic feedback, so re-running them on iteration 2+ is waste.
466
+ */
467
+ async function runTeamAnalysis(task, basePrompt, claudePath, model, env, repoPath, taskId, startTime) {
460
468
  const taskLabel = chalk.cyan(taskId.slice(0, 8));
461
469
  console.log(`${ts()} ${taskLabel} ${chalk.magenta("◆ Team planning")} — running 3 analysts in parallel...`);
462
470
  await postLog(taskId, `${PREFIX} Team planning: running codebase, requirements, and risk analysts in parallel...`);
@@ -497,7 +505,7 @@ async function runTeamPlanning(task, basePrompt, claudePath, model, env, repoPat
497
505
  if (attempt === MAX_TEAM_RETRIES) {
498
506
  console.log(`${ts()} ${taskLabel} ${chalk.yellow("⚠")} All analysts failed after ${MAX_TEAM_RETRIES} attempts, falling back to single-agent planning`);
499
507
  await postLog(taskId, `${PREFIX} All analysis agents failed after ${MAX_TEAM_RETRIES} attempts — falling back to single-agent planning`);
500
- return runClaudeCli(claudePath, model, basePrompt, env, taskId, startTime);
508
+ return null;
501
509
  }
502
510
  }
503
511
  // Build enhanced prompt with analysis reports
@@ -511,14 +519,12 @@ async function runTeamPlanning(task, basePrompt, claudePath, model, env, repoPat
511
519
  if (riskReport) {
512
520
  sections.push(`## Risk Assessment\n\n${riskReport}`);
513
521
  }
514
- const enhancedPrompt = basePrompt +
522
+ return (basePrompt +
515
523
  "\n\n" +
516
524
  sections.join("\n\n") +
517
525
  "\n\n" +
518
526
  "Use these analyses to produce a more accurate execution plan.\n" +
519
- "Prefer actual file paths discovered in the codebase analysis over guessed paths.";
520
- // Run the final synthesizer planner with the enhanced prompt
521
- return runClaudeCli(claudePath, model, enhancedPrompt, env, taskId, startTime);
527
+ "Prefer actual file paths discovered in the codebase analysis over guessed paths.");
522
528
  }
523
529
  /**
524
530
  * Run planning for a task with Planner-Critic validation loop.
@@ -552,8 +558,11 @@ export async function planTask(task, config, credentials) {
552
558
  const startTime = Date.now();
553
559
  // PRD for critic validation: use task description, fall back to summary
554
560
  const prd = task.description || task.summary;
555
- // Clone repo for team planning if enabled
561
+ // Run team analysis ONCE before the planner-critic loop.
562
+ // Analyst prompts don't include critic feedback, so re-running them
563
+ // on iteration 2+ wastes compute (they'd produce the same reports).
556
564
  let repoPath = null;
565
+ let enhancedBasePrompt = basePrompt;
557
566
  if (isAnthropicPlanning && config.teamPlanningEnabled && task.githubRepo) {
558
567
  const scmProvider = task.scmProvider || "github";
559
568
  const scmToken = scmProvider === "bitbucket"
@@ -567,9 +576,18 @@ export async function planTask(task, config, credentials) {
567
576
  else {
568
577
  console.log(`${ts()} ${taskLabel} ${chalk.yellow("⚠")} No SCM token for ${scmProvider}, skipping team planning`);
569
578
  }
579
+ if (repoPath) {
580
+ const analysisResult = await runTeamAnalysis(task, basePrompt, claudePath, cliModel, cleanEnv, repoPath, task.id, startTime);
581
+ if (analysisResult) {
582
+ enhancedBasePrompt = analysisResult;
583
+ }
584
+ // else: all analysts failed, fall back to basePrompt
585
+ }
570
586
  }
571
587
  // 2. Planner-Critic iteration loop
572
- let currentPrompt = basePrompt;
588
+ // Use enhancedBasePrompt (with analyst reports) as the base for all iterations.
589
+ // Critic feedback gets appended on re-plan, but analyst reports are fixed.
590
+ let currentPrompt = enhancedBasePrompt;
573
591
  let bestPlan = null;
574
592
  let bestScore = 0;
575
593
  // Track critic history across iterations for analytics
@@ -590,10 +608,7 @@ export async function planTask(task, config, credentials) {
590
608
  // 2a. Generate plan via Claude CLI (Anthropic) or HTTP API (other providers)
591
609
  let rawOutput;
592
610
  try {
593
- if (isAnthropicPlanning && config.teamPlanningEnabled && repoPath) {
594
- rawOutput = await runTeamPlanning(task, currentPrompt, claudePath, cliModel, cleanEnv, repoPath, task.id, startTime);
595
- }
596
- else if (isAnthropicPlanning) {
611
+ if (isAnthropicPlanning) {
597
612
  rawOutput = await runClaudeCli(claudePath, cliModel, currentPrompt, cleanEnv, task.id, startTime);
598
613
  }
599
614
  else {
@@ -690,7 +705,7 @@ export async function planTask(task, config, credentials) {
690
705
  // 2f. Rejected — append critic feedback for next iteration
691
706
  if (iteration < MAX_ITERATIONS) {
692
707
  const feedback = formatCriticFeedback(criticResult);
693
- currentPrompt = basePrompt + "\n\n" + feedback;
708
+ currentPrompt = enhancedBasePrompt + "\n\n" + feedback;
694
709
  const msg = `${PREFIX} Critic rejected (score: ${criticResult.score}/100, threshold: ${AUTO_APPROVAL_THRESHOLD}). Re-planning with feedback...`;
695
710
  console.log(`${ts()} ${taskLabel} ${chalk.yellow("⚠")} ${msg}`);
696
711
  await postLog(task.id, msg);
package/dist/spawner.js CHANGED
@@ -218,7 +218,7 @@ export async function spawnWorker(task, config, orgConfig, credentials) {
218
218
  EXISTING_PR_URL: task.githubPrUrl || "",
219
219
  EXISTING_PR_NUMBER: task.githubPrNumber ? String(task.githubPrNumber) : "",
220
220
  // PRD Orchestration
221
- PARENT_TASK_ID: task.parentTaskId || "",
221
+ PARENT_TASK_ID: task.parentTaskId || task.id,
222
222
  PARENT_JIRA_KEY: task.jiraIssueKey && /-S\d+$/.test(task.jiraIssueKey)
223
223
  ? task.jiraFields?.parentJiraKey || ""
224
224
  : "",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@workermill/agent",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "description": "WorkerMill Remote Agent - Run AI workers locally with your Claude Max subscription",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",