@phi-code-admin/phi-code 0.58.4 → 0.58.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.
@@ -193,7 +193,7 @@ export default function orchestratorExtension(pi: ExtensionAPI) {
193
193
  });
194
194
  }
195
195
 
196
- // ─── Execute All Tasks ───────────────────────────────────────────
196
+ // ─── Execute All Tasks (parallel with dependency resolution) ─────
197
197
 
198
198
  async function executePlan(
199
199
  tasks: TaskDef[],
@@ -205,52 +205,133 @@ export default function orchestratorExtension(pi: ExtensionAPI) {
205
205
  const progressPath = join(plansDir, progressFile);
206
206
  let progress = `# Progress: ${todoFile}\n\n`;
207
207
  progress += `**Started:** ${new Date().toLocaleString()}\n`;
208
- progress += `**Tasks:** ${tasks.length}\n\n`;
208
+ progress += `**Tasks:** ${tasks.length}\n**Mode:** parallel (dependency-aware)\n\n`;
209
209
  await writeFile(progressPath, progress, "utf-8");
210
210
 
211
- notify(`🚀 Executing ${tasks.length} tasks with sub-agents...`, "info");
212
-
211
+ // Build dependency graph
212
+ // Task indices are 1-based in the plan files
213
+ const completed = new Set<number>();
214
+ const failed = new Set<number>();
213
215
  const results: TaskResult[] = [];
214
216
 
215
- for (let i = 0; i < tasks.length; i++) {
216
- const task = tasks[i];
217
- const agentType = task.agent || "code";
218
- notify(`⏳ Task ${i + 1}/${tasks.length}: **${task.title}** [${agentType}]`, "info");
219
-
220
- const result = await executeTask(task, agentDefs, process.cwd());
221
- result.taskIndex = i + 1;
222
- results.push(result);
223
-
224
- const icon = result.status === "success" ? "✅" : "❌";
225
- const duration = (result.durationMs / 1000).toFixed(1);
226
- const outputPreview = result.output.length > 500 ? result.output.slice(0, 500) + "..." : result.output;
227
- notify(`${icon} Task ${i + 1}: **${task.title}** (${duration}s)\n${outputPreview}`,
228
- result.status === "success" ? "info" : "error");
229
-
230
- progress += `## Task ${i + 1}: ${task.title}\n\n`;
231
- progress += `- **Status:** ${result.status}\n`;
232
- progress += `- **Agent:** ${result.agent}\n`;
233
- progress += `- **Duration:** ${duration}s\n`;
234
- progress += `- **Output:**\n\n\`\`\`\n${result.output.slice(0, 3000)}\n\`\`\`\n\n`;
217
+ // Check which tasks can run (all dependencies completed successfully)
218
+ function getReadyTasks(): number[] {
219
+ const ready: number[] = [];
220
+ for (let i = 0; i < tasks.length; i++) {
221
+ const taskNum = i + 1;
222
+ if (completed.has(taskNum) || failed.has(taskNum)) continue;
223
+
224
+ const deps = tasks[i].dependencies || [];
225
+ const allDepsMet = deps.every(d => completed.has(d));
226
+ const anyDepFailed = deps.some(d => failed.has(d));
227
+
228
+ if (anyDepFailed) {
229
+ // Skip tasks whose dependencies failed
230
+ failed.add(taskNum);
231
+ results.push({
232
+ taskIndex: taskNum,
233
+ title: tasks[i].title,
234
+ agent: tasks[i].agent || "code",
235
+ status: "skipped",
236
+ output: `Skipped: dependency #${deps.find(d => failed.has(d))} failed`,
237
+ durationMs: 0,
238
+ });
239
+ notify(`⏭️ Task ${taskNum}: **${tasks[i].title}** — skipped (dependency failed)`, "warning");
240
+ } else if (allDepsMet) {
241
+ ready.push(i);
242
+ }
243
+ }
244
+ return ready;
245
+ }
246
+
247
+ const totalTasks = tasks.length;
248
+ let wave = 1;
249
+
250
+ notify(`🚀 Executing ${totalTasks} tasks with sub-agents (parallel mode)...`, "info");
251
+
252
+ // Execute in waves — each wave runs independent tasks in parallel
253
+ while (completed.size + failed.size < totalTasks) {
254
+ const readyIndices = getReadyTasks();
255
+
256
+ if (readyIndices.length === 0) {
257
+ // Deadlock or all done
258
+ break;
259
+ }
260
+
261
+ const parallelCount = readyIndices.length;
262
+ if (parallelCount > 1) {
263
+ notify(`\n🔄 **Wave ${wave}** — ${parallelCount} tasks in parallel`, "info");
264
+ }
265
+
266
+ for (const idx of readyIndices) {
267
+ const t = tasks[idx];
268
+ notify(`⏳ Task ${idx + 1}: **${t.title}** [${t.agent || "code"}]`, "info");
269
+ }
270
+
271
+ // Launch all ready tasks simultaneously
272
+ const promises = readyIndices.map(async (idx) => {
273
+ const task = tasks[idx];
274
+ const result = await executeTask(task, agentDefs, process.cwd());
275
+ result.taskIndex = idx + 1;
276
+ return result;
277
+ });
278
+
279
+ const waveResults = await Promise.all(promises);
280
+
281
+ // Process results
282
+ for (const result of waveResults) {
283
+ results.push(result);
284
+
285
+ if (result.status === "success") {
286
+ completed.add(result.taskIndex);
287
+ } else {
288
+ failed.add(result.taskIndex);
289
+ }
290
+
291
+ const icon = result.status === "success" ? "✅" : "❌";
292
+ const duration = (result.durationMs / 1000).toFixed(1);
293
+ const outputPreview = result.output.length > 500 ? result.output.slice(0, 500) + "..." : result.output;
294
+ notify(`${icon} Task ${result.taskIndex}: **${result.title}** (${duration}s)\n${outputPreview}`,
295
+ result.status === "success" ? "info" : "error");
296
+
297
+ progress += `## Task ${result.taskIndex}: ${result.title}\n\n`;
298
+ progress += `- **Status:** ${result.status}\n`;
299
+ progress += `- **Agent:** ${result.agent}\n`;
300
+ progress += `- **Wave:** ${wave}\n`;
301
+ progress += `- **Duration:** ${duration}s\n`;
302
+ progress += `- **Output:**\n\n\`\`\`\n${result.output.slice(0, 3000)}\n\`\`\`\n\n`;
303
+ }
304
+
235
305
  await writeFile(progressPath, progress, "utf-8");
306
+ wave++;
236
307
  }
237
308
 
238
- const succeeded = results.filter(r => r.status === "success").length;
239
- const failed = results.filter(r => r.status === "error").length;
309
+ // Sort results by task index for consistent reporting
310
+ results.sort((a, b) => a.taskIndex - b.taskIndex);
311
+
312
+ const succeededCount = results.filter(r => r.status === "success").length;
313
+ const failedCount = results.filter(r => r.status === "error").length;
314
+ const skippedCount = results.filter(r => r.status === "skipped").length;
240
315
  const totalTime = results.reduce((sum, r) => sum + r.durationMs, 0);
241
316
 
242
317
  progress += `---\n\n## Summary\n\n`;
243
318
  progress += `- **Completed:** ${new Date().toLocaleString()}\n`;
244
- progress += `- **Succeeded:** ${succeeded}/${results.length}\n`;
245
- progress += `- **Failed:** ${failed}\n`;
319
+ progress += `- **Waves:** ${wave - 1}\n`;
320
+ progress += `- **Succeeded:** ${succeededCount}/${results.length}\n`;
321
+ progress += `- **Failed:** ${failedCount}\n`;
322
+ progress += `- **Skipped:** ${skippedCount}\n`;
246
323
  progress += `- **Total time:** ${(totalTime / 1000).toFixed(1)}s\n`;
247
324
  await writeFile(progressPath, progress, "utf-8");
248
325
 
326
+ const statusParts = [`✅ ${succeededCount} succeeded`];
327
+ if (failedCount > 0) statusParts.push(`❌ ${failedCount} failed`);
328
+ if (skippedCount > 0) statusParts.push(`⏭️ ${skippedCount} skipped`);
329
+
249
330
  notify(
250
- `\n🏁 **Execution complete!**\n` +
251
- `✅ ${succeeded}/${results.length} succeeded | ${failed} failed | ⏱️ ${(totalTime / 1000).toFixed(1)}s\n` +
331
+ `\n🏁 **Execution complete!** (${wave - 1} waves)\n` +
332
+ statusParts.join(" | ") + ` | ⏱️ ${(totalTime / 1000).toFixed(1)}s\n` +
252
333
  `Progress: \`${progressFile}\``,
253
- failed === 0 ? "info" : "warning"
334
+ failedCount === 0 ? "info" : "warning"
254
335
  );
255
336
 
256
337
  return { results, progressFile };
@@ -317,33 +398,36 @@ export default function orchestratorExtension(pi: ExtensionAPI) {
317
398
  pi.registerTool({
318
399
  name: "orchestrate",
319
400
  label: "Project Orchestrator",
320
- description: "Create a project plan AND automatically execute all tasks with sub-agents. Each agent gets its own isolated context, model, and system prompt. Call this after analyzing the user's project request.",
321
- promptSnippet: "Plan + execute projects. Creates spec/todo, then runs each task with an isolated sub-agent.",
401
+ description: "Create a project plan AND automatically execute all tasks with sub-agents in parallel. Each agent gets its own isolated context, model, and system prompt. Tasks without dependencies run simultaneously.",
402
+ promptSnippet: "Plan + execute projects in parallel waves. Each sub-agent gets isolated context + model. Use prompt-architect patterns for structured task descriptions.",
322
403
  promptGuidelines: [
323
- "When asked to plan or build a project: analyze the request, then call orchestrate. It will plan AND execute automatically.",
324
- "Break tasks into small, actionable items. Each task is executed by an isolated sub-agent.",
325
- "Assign agent types: 'explore' (analysis), 'plan' (design), 'code' (implementation), 'test' (validation), 'review' (quality).",
326
- "Order tasks by dependency. Sub-agents execute sequentially, respecting the order.",
404
+ "When asked to plan or build a project: analyze the request thoroughly, then call the orchestrate tool. It plans AND executes automatically.",
405
+ "CRITICAL: Each task description must be SELF-CONTAINED. The sub-agent has NO shared history, NO access to the conversation, NO memory of previous tasks. Include ALL context it needs: file paths, expected behavior, relevant code patterns, and success criteria.",
406
+ "Structure each task description using the prompt-architect pattern: [CONTEXT] what exists and why [TASK] what to do specifically → [FORMAT] expected output → [CONSTRAINTS] rules and limitations.",
407
+ "Assign agent types strategically: 'explore' (read-only analysis, codebase understanding), 'plan' (architecture, design decisions), 'code' (implementation, file creation/modification), 'test' (write + run tests, validate behavior), 'review' (security audit, quality check, read-only).",
408
+ "Set dependencies to maximize parallelism: tasks without dependencies run simultaneously in the same wave. Only add dependencies when a task truly needs another task's output.",
409
+ "Order tasks logically: explore → plan → code → test → review. But allow independent tasks at each stage to run in parallel.",
410
+ "Set priority=high for critical-path tasks, medium for standard work, low for nice-to-haves.",
327
411
  ],
328
412
  parameters: Type.Object({
329
- title: Type.String({ description: "Project title" }),
330
- description: Type.String({ description: "Full project description with context" }),
331
- goals: Type.Array(Type.String(), { description: "List of project goals" }),
413
+ title: Type.String({ description: "Concise project title" }),
414
+ description: Type.String({ description: "Full project description: what to build, why, and any relevant context" }),
415
+ goals: Type.Array(Type.String(), { description: "Measurable project goals (what success looks like)" }),
332
416
  requirements: Type.Array(Type.String(), { description: "Technical and functional requirements" }),
333
- architecture: Type.Optional(Type.Array(Type.String(), { description: "Architecture decisions" })),
417
+ architecture: Type.Optional(Type.Array(Type.String(), { description: "Architecture decisions, tech stack choices, trade-offs" })),
334
418
  tasks: Type.Array(
335
419
  Type.Object({
336
- title: Type.String({ description: "Task title" }),
337
- description: Type.String({ description: "Detailed task description with enough context for the agent to work independently" }),
338
- agent: Type.Optional(Type.String({ description: "Agent type: explore, plan, code, test, or review" })),
339
- priority: Type.Optional(Type.String({ description: "high, medium, or low" })),
340
- dependencies: Type.Optional(Type.Array(Type.Number(), { description: "IDs of prerequisite tasks (1-indexed)" })),
341
- subtasks: Type.Optional(Type.Array(Type.String(), { description: "Sub-task descriptions" })),
420
+ title: Type.String({ description: "Clear, action-oriented task title" }),
421
+ description: Type.String({ description: "SELF-CONTAINED task description. Include ALL context the sub-agent needs: file paths, expected behavior, code patterns, conventions. The agent has NO shared history." }),
422
+ agent: Type.Optional(Type.String({ description: "Agent type: explore (read-only analysis), plan (architecture), code (implementation), test (write+run tests), review (quality audit)" })),
423
+ priority: Type.Optional(Type.String({ description: "high (critical path), medium (standard), low (nice-to-have)" })),
424
+ dependencies: Type.Optional(Type.Array(Type.Number(), { description: "Task numbers this depends on (1-indexed). Only add when truly needed — fewer dependencies = more parallelism" })),
425
+ subtasks: Type.Optional(Type.Array(Type.String(), { description: "Specific sub-steps within this task" })),
342
426
  }),
343
- { description: "Ordered list of tasks to execute" }
427
+ { description: "Ordered list of tasks. Independent tasks run in parallel. Dependent tasks wait for prerequisites." }
344
428
  ),
345
- constraints: Type.Optional(Type.Array(Type.String(), { description: "Project constraints" })),
346
- successCriteria: Type.Optional(Type.Array(Type.String(), { description: "Completion criteria" })),
429
+ constraints: Type.Optional(Type.Array(Type.String(), { description: "Hard constraints: frameworks, patterns, rules, things to avoid" })),
430
+ successCriteria: Type.Optional(Type.Array(Type.String(), { description: "How to verify the project is complete and correct" })),
347
431
  }),
348
432
 
349
433
  async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
@@ -445,18 +529,36 @@ All files in \`.phi/plans/\``;
445
529
  }
446
530
 
447
531
  ctx.sendUserMessage(
448
- `Analyze this project request and execute it using the orchestrate tool.
449
- The orchestrate tool will create the plan AND execute all tasks automatically with sub-agents.
450
-
451
- Project: ${description}
452
-
453
- Instructions:
454
- - Identify goals, requirements, architecture decisions
455
- - Break into small tasks (each executable by one sub-agent independently)
456
- - Each task description must contain FULL context — the sub-agent has NO shared history
457
- - Assign agent types: explore (analysis), plan (design), code (implementation), test (validation), review (quality)
458
- - Set priorities and dependencies
459
- - Call the orchestrate tool — it handles everything from there`
532
+ `Analyze this project and call the orchestrate tool. It will create the plan AND execute all tasks automatically with parallel sub-agents.
533
+
534
+ ## Project
535
+ ${description}
536
+
537
+ ## Instructions
538
+
539
+ 1. **Analyze** the project: identify goals, requirements, technical constraints, and architecture decisions.
540
+
541
+ 2. **Decompose** into tasks. Each task will be executed by an isolated sub-agent that has:
542
+ - NO access to this conversation
543
+ - NO shared memory or context
544
+ - Its own model and system prompt
545
+ - Full tool access (read, write, edit, bash, grep, find, ls)
546
+
547
+ 3. **Write self-contained task descriptions** using this pattern:
548
+ - CONTEXT: What exists, relevant file paths, current state
549
+ - TASK: Exactly what to implement/analyze/test
550
+ - FORMAT: Expected output (files created, test results, etc.)
551
+ - CONSTRAINTS: Rules, conventions, things to avoid
552
+
553
+ 4. **Assign agents**: explore (read-only analysis), plan (design), code (implementation), test (write+run tests), review (quality audit)
554
+
555
+ 5. **Set dependencies** to maximize parallelism:
556
+ - Tasks without dependencies → same wave → run simultaneously
557
+ - Only add a dependency when a task truly needs another's output
558
+ - Typical flow: explore(wave 1) → plan(wave 2) → code(wave 3) → test(wave 4) → review(wave 5)
559
+ - But independent code tasks can run in parallel within the same wave
560
+
561
+ 6. **Call the orchestrate tool** with all structured data. It handles execution automatically.`
460
562
  );
461
563
  },
462
564
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@phi-code-admin/phi-code",
3
- "version": "0.58.4",
3
+ "version": "0.58.6",
4
4
  "description": "Coding agent CLI with read, bash, edit, write tools and session management",
5
5
  "type": "module",
6
6
  "piConfig": {