@workermill/agent 0.7.18 → 0.7.19

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.
@@ -90,7 +90,7 @@ export declare function parseCriticResponse(text: string): CriticResult;
90
90
  * Run the critic via Claude CLI (lightweight — no tools, just reasoning).
91
91
  * Returns the raw text output.
92
92
  */
93
- export declare function runCriticCli(claudePath: string, model: string, prompt: string, env: Record<string, string | undefined>): Promise<string>;
93
+ export declare function runCriticCli(claudePath: string, model: string, prompt: string, env: Record<string, string | undefined>, taskId?: string): Promise<string>;
94
94
  /**
95
95
  * Format critic feedback for appending to the planner prompt on re-run.
96
96
  */
@@ -100,5 +100,5 @@ export declare function formatCriticFeedback(critic: CriticResult): string;
100
100
  * Routes to Claude CLI (Anthropic) or HTTP API (other providers).
101
101
  * Returns the critic result, or null if critic fails (non-blocking).
102
102
  */
103
- export declare function runCriticValidation(claudePath: string, model: string, prd: string, plan: ExecutionPlan, env: Record<string, string | undefined>, taskLabel: string, provider?: AIProvider, providerApiKey?: string): Promise<CriticResult | null>;
103
+ export declare function runCriticValidation(claudePath: string, model: string, prd: string, plan: ExecutionPlan, env: Record<string, string | undefined>, taskLabel: string, provider?: AIProvider, providerApiKey?: string, taskId?: string): Promise<CriticResult | null>;
104
104
  export { AUTO_APPROVAL_THRESHOLD };
@@ -12,6 +12,7 @@
12
12
  import { spawn } from "child_process";
13
13
  import chalk from "chalk";
14
14
  import { generateText } from "./providers.js";
15
+ import { api } from "./api.js";
15
16
  // ============================================================================
16
17
  // CONSTANTS
17
18
  // ============================================================================
@@ -277,7 +278,7 @@ export function parseCriticResponse(text) {
277
278
  * Run the critic via Claude CLI (lightweight — no tools, just reasoning).
278
279
  * Returns the raw text output.
279
280
  */
280
- export function runCriticCli(claudePath, model, prompt, env) {
281
+ export function runCriticCli(claudePath, model, prompt, env, taskId) {
281
282
  return new Promise((resolve, reject) => {
282
283
  const proc = spawn(claudePath, [
283
284
  "--print",
@@ -294,7 +295,21 @@ export function runCriticCli(claudePath, model, prompt, env) {
294
295
  let stdout = "";
295
296
  let stderr = "";
296
297
  proc.stdout.on("data", (data) => {
297
- stdout += data.toString();
298
+ const chunk = data.toString();
299
+ stdout += chunk;
300
+ // Stream critic reasoning to dashboard in real-time
301
+ const lines = chunk.split("\n").filter((l) => l.trim());
302
+ for (const line of lines) {
303
+ const trimmed = line.trim().length > 200
304
+ ? line.trim().substring(0, 200) + "…"
305
+ : line.trim();
306
+ if (trimmed) {
307
+ if (taskId) {
308
+ postLog(taskId, `${PREFIX} [critic] ${trimmed}`, "output");
309
+ }
310
+ console.log(`${ts()} ${chalk.dim("🔍")} ${chalk.dim(trimmed)}`);
311
+ }
312
+ }
298
313
  });
299
314
  proc.stderr.on("data", (data) => {
300
315
  stderr += data.toString();
@@ -358,23 +373,44 @@ export function formatCriticFeedback(critic) {
358
373
  lines.push("**You MUST address ALL feedback above.** Each story must target at most 5 files.", "Stories MUST NOT overlap on targetFiles. Generate a revised plan.");
359
374
  return lines.join("\n");
360
375
  }
376
+ /** Consistent prefix matching planner dashboard format */
377
+ const PREFIX = "[🗺️ planning_agent 🤖]";
361
378
  /** Timestamp prefix for console logs */
362
379
  function ts() {
363
380
  return chalk.dim(new Date().toLocaleTimeString());
364
381
  }
382
+ /**
383
+ * Post a log message to the cloud dashboard for real-time visibility.
384
+ */
385
+ async function postLog(taskId, message, type = "system", severity = "info") {
386
+ try {
387
+ await api.post("/api/control-center/logs", {
388
+ taskId,
389
+ type,
390
+ message,
391
+ severity,
392
+ });
393
+ }
394
+ catch {
395
+ // Fire and forget — don't block critic on log failures
396
+ }
397
+ }
365
398
  /**
366
399
  * Run critic validation on a parsed plan.
367
400
  * Routes to Claude CLI (Anthropic) or HTTP API (other providers).
368
401
  * Returns the critic result, or null if critic fails (non-blocking).
369
402
  */
370
- export async function runCriticValidation(claudePath, model, prd, plan, env, taskLabel, provider, providerApiKey) {
403
+ export async function runCriticValidation(claudePath, model, prd, plan, env, taskLabel, provider, providerApiKey, taskId) {
371
404
  const criticPrompt = buildCriticPrompt(prd, plan);
372
405
  const effectiveProvider = provider || "anthropic";
373
406
  console.log(`${ts()} ${taskLabel} ${chalk.dim(`Running critic validation (${effectiveProvider})...`)}`);
407
+ if (taskId) {
408
+ postLog(taskId, `${PREFIX} Running critic validation (${effectiveProvider})...`);
409
+ }
374
410
  try {
375
411
  let rawCriticOutput;
376
412
  if (effectiveProvider === "anthropic") {
377
- rawCriticOutput = await runCriticCli(claudePath, model, criticPrompt, env);
413
+ rawCriticOutput = await runCriticCli(claudePath, model, criticPrompt, env, taskId);
378
414
  }
379
415
  else {
380
416
  if (!providerApiKey) {
package/dist/planner.js CHANGED
@@ -238,6 +238,7 @@ function runClaudeCli(claudePath, model, prompt, env, taskId, startTime, disable
238
238
  if (block.type === "text" && block.text) {
239
239
  fullText += block.text;
240
240
  charsReceived += block.text.length;
241
+ textBuffer += block.text;
241
242
  if (!firstTextSeen) {
242
243
  firstTextSeen = true;
243
244
  if (toolCallCount > 0 && !milestoneSent.analyzing) {
@@ -263,6 +264,7 @@ function runClaudeCli(claudePath, model, prompt, env, taskId, startTime, disable
263
264
  else if (typeof content === "string" && content) {
264
265
  fullText += content;
265
266
  charsReceived += content.length;
267
+ textBuffer += content;
266
268
  }
267
269
  }
268
270
  else if (event.type === "content_block_delta" && event.delta?.text) {
@@ -919,7 +921,7 @@ export async function planTask(task, config, credentials) {
919
921
  console.log(`${ts()} ${taskLabel} Plan: ${chalk.bold(plan.stories.length)} stories (max ${maxStories})`);
920
922
  await postLog(task.id, `${PREFIX} Plan generated: ${plan.stories.length} stories (${formatElapsed(elapsed)}). Running critic validation...`);
921
923
  // 2d. Run critic validation
922
- const criticResult = await runCriticValidation(claudePath, cliModel, prd, plan, cleanEnv, taskLabel, provider, providerApiKey);
924
+ const criticResult = await runCriticValidation(claudePath, cliModel, prd, plan, cleanEnv, taskLabel, provider, providerApiKey, task.id);
923
925
  // Track best plan across iterations
924
926
  if (criticResult && criticResult.score > bestScore) {
925
927
  bestPlan = plan;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@workermill/agent",
3
- "version": "0.7.18",
3
+ "version": "0.7.19",
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",