opencode-manifold 0.5.6 → 0.5.8

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 CHANGED
@@ -320,342 +320,206 @@ function extractTaskFromPlan(planContent, taskNumber) {
320
320
  }
321
321
  return null;
322
322
  }
323
- function runDispatcherLogic(args, state, settings) {
324
- const isNewTask = args.newTask === true;
325
- const taskNumber = args.task_number || (state?.task_number || 0);
326
- const planFile = args.plan_file || (state?.plan_file || "");
323
+ function runDispatcherLogic(args, state, settings, taskDescription) {
324
+ const taskNumber = args.task_number || state?.task_number || 0;
327
325
  const slug = state?.slug || "";
328
- let currentState;
329
- if (isNewTask || !state) {
330
- currentState = {
326
+ if (!state || state.phase === "init" || state.phase === "complete" || state.phase === "escalated") {
327
+ const newState = {
331
328
  task_number: taskNumber,
332
- plan_file: planFile,
329
+ plan_file: args.plan_file || state?.plan_file || "",
333
330
  slug,
331
+ phase: "awaiting_execution",
332
+ senior_output: "",
333
+ clerk_summary: "",
334
334
  loops: 0,
335
- clerkRetries: 0,
336
- researchSummary: "",
337
- implementationOutput: "",
338
- reviewFeedback: "",
339
- debugAnalysis: ""
335
+ clerk_retries: 0
340
336
  };
341
- } else {
342
- currentState = { ...state };
343
- }
344
- if (args.researchSummary)
345
- currentState.researchSummary = args.researchSummary;
346
- if (args.implementationOutput)
347
- currentState.implementationOutput = args.implementationOutput;
348
- if (args.reviewFeedback)
349
- currentState.reviewFeedback = args.reviewFeedback;
350
- if (args.debugAnalysis)
351
- currentState.debugAnalysis = args.debugAnalysis;
352
- if (isNewTask) {
353
337
  return {
354
- route: "research",
338
+ route: "execute",
355
339
  agent: "clerk",
356
- prompt: buildResearchPrompt(args, currentState, settings),
357
- state: {
358
- task_id: `${currentState.slug}-${currentState.task_number.toString().padStart(3, "0")}`,
359
- loops: 0,
360
- maxLoops: settings.maxLoops,
361
- clerkRetries: 0
362
- },
363
- message: "Researching codebase and wiki context"
364
- };
365
- }
366
- if (args.researchComplete === true && !args.hasImplementation) {
367
- return {
368
- route: "implement",
369
- agent: "senior-dev",
370
- prompt: buildScopedPrompt(currentState.researchSummary, args),
371
- state: {
372
- task_id: `${currentState.slug}-${currentState.task_number.toString().padStart(3, "0")}`,
373
- loops: 0,
374
- maxLoops: settings.maxLoops,
375
- clerkRetries: 0
376
- },
377
- message: "Sending to senior-dev for implementation"
378
- };
379
- }
380
- if (args.hasImplementation === true && args.reviewDone === false) {
381
- return {
382
- route: "review",
383
- agent: "junior-dev",
384
- prompt: buildReviewPrompt(currentState.implementationOutput, args),
340
+ prompt: buildExecutePrompt(taskNumber, taskDescription),
385
341
  state: {
386
- task_id: `${currentState.slug}-${currentState.task_number.toString().padStart(3, "0")}`,
387
- loops: 0,
388
- maxLoops: settings.maxLoops,
389
- clerkRetries: 0
342
+ task_id: `${slug}-${taskNumber.toString().padStart(3, "0")}`,
343
+ phase: "awaiting_execution"
390
344
  },
391
- message: "Sending to junior-dev for review"
345
+ message: "Ready to execute task"
392
346
  };
393
347
  }
394
- if (args.reviewDone === true && args.reviewPassed === true) {
348
+ if (state.phase === "awaiting_execution") {
395
349
  return {
396
- route: "logging",
350
+ route: "outcome_check",
397
351
  agent: "clerk",
398
- prompt: buildLoggingPrompt(currentState, args),
352
+ prompt: buildOutcomeCheckPrompt(),
399
353
  state: {
400
- task_id: `${currentState.slug}-${currentState.task_number.toString().padStart(3, "0")}`,
401
- loops: currentState.loops,
402
- maxLoops: settings.maxLoops,
403
- clerkRetries: currentState.clerkRetries
354
+ task_id: `${slug}-${taskNumber.toString().padStart(3, "0")}`,
355
+ phase: "awaiting_outcome"
404
356
  },
405
- message: "Logging task to wiki and graph"
357
+ message: "Waiting for senior dev outcome"
406
358
  };
407
359
  }
408
- if (args.reviewDone === true && args.reviewPassed === false) {
409
- currentState.loops++;
410
- if (currentState.loops >= settings.maxLoops) {
411
- if (!args.debugComplete && currentState.clerkRetries === 0) {
360
+ if (state.phase === "awaiting_outcome") {
361
+ const isSuccess = args.success === true;
362
+ if (isSuccess) {
363
+ return {
364
+ route: "logging",
365
+ agent: "clerk",
366
+ prompt: buildLoggingPrompt(state, taskDescription),
367
+ state: {
368
+ task_id: `${slug}-${taskNumber.toString().padStart(3, "0")}`,
369
+ phase: "logging"
370
+ },
371
+ message: "Task succeeded - logging results"
372
+ };
373
+ } else {
374
+ if (state.clerk_retries < settings.maxRetries) {
412
375
  return {
413
- route: "debug",
414
- agent: "debug",
415
- prompt: buildDebugPrompt(currentState, args),
376
+ route: "reprompt",
377
+ agent: "clerk",
378
+ prompt: buildRePromptPrompt(state, taskDescription),
416
379
  state: {
417
- task_id: `${currentState.slug}-${currentState.task_number.toString().padStart(3, "0")}`,
418
- loops: currentState.loops,
419
- maxLoops: settings.maxLoops,
420
- clerkRetries: 0
380
+ task_id: `${slug}-${taskNumber.toString().padStart(3, "0")}`,
381
+ phase: "awaiting_execution"
421
382
  },
422
- message: `Loop ${currentState.loops}/${settings.maxLoops} - escalating to debug`
383
+ message: `Retrying task (attempt ${state.clerk_retries + 1}/${settings.maxRetries})`
423
384
  };
424
- }
425
- if (args.debugComplete === true && settings.clerkRetryEnabled && currentState.clerkRetries === 0) {
426
- currentState.clerkRetries = 1;
427
- currentState.loops = 0;
385
+ } else {
428
386
  return {
429
- route: "re-research",
430
- agent: "clerk",
431
- prompt: buildReResearchPrompt(currentState, args),
387
+ route: "escalate",
388
+ agent: null,
389
+ prompt: buildEscalationPrompt(state, taskDescription),
432
390
  state: {
433
- task_id: `${currentState.slug}-${currentState.task_number.toString().padStart(3, "0")}`,
434
- loops: 0,
435
- maxLoops: settings.maxLoops,
436
- clerkRetries: 1
391
+ task_id: `${slug}-${taskNumber.toString().padStart(3, "0")}`,
392
+ phase: "escalated"
437
393
  },
438
- message: "Clerk re-researching with failure context"
394
+ message: "Escalating to user - all retries exhausted"
439
395
  };
440
396
  }
441
- return {
442
- route: "escalate_user",
443
- agent: null,
444
- prompt: `Task ${taskNumber} has exhausted all loops (${settings.maxLoops}) and debug analysis. Last feedback: ${currentState.reviewFeedback}`,
445
- state: {
446
- task_id: `${currentState.slug}-${currentState.task_number.toString().padStart(3, "0")}`,
447
- loops: currentState.loops,
448
- maxLoops: settings.maxLoops,
449
- clerkRetries: currentState.clerkRetries
450
- },
451
- message: "ESCALATING TO USER - all loops exhausted"
452
- };
453
397
  }
454
- return {
455
- route: "re-implement",
456
- agent: "senior-dev",
457
- prompt: buildReImplementPrompt(currentState, args),
458
- state: {
459
- task_id: `${currentState.slug}-${currentState.task_number.toString().padStart(3, "0")}`,
460
- loops: currentState.loops,
461
- maxLoops: settings.maxLoops,
462
- clerkRetries: currentState.clerkRetries
463
- },
464
- message: `Loop ${currentState.loops}/${settings.maxLoops} - re-implementing with junior feedback`
465
- };
466
- }
467
- if (args.debugComplete === true && args.reResearched === false) {
468
- return {
469
- route: "re-implement",
470
- agent: "senior-dev",
471
- prompt: buildDebugImplementPrompt(currentState, args),
472
- state: {
473
- task_id: `${currentState.slug}-${currentState.task_number.toString().padStart(3, "0")}`,
474
- loops: currentState.loops,
475
- maxLoops: settings.maxLoops,
476
- clerkRetries: currentState.clerkRetries
477
- },
478
- message: "Re-implementing with debug suggestion"
479
- };
480
- }
481
- if (args.reResearched === true) {
482
- currentState.loops = 0;
483
- return {
484
- route: "implement",
485
- agent: "senior-dev",
486
- prompt: buildScopedPrompt(currentState.researchSummary, args),
487
- state: {
488
- task_id: `${currentState.slug}-${currentState.task_number.toString().padStart(3, "0")}`,
489
- loops: 0,
490
- maxLoops: settings.maxLoops,
491
- clerkRetries: currentState.clerkRetries
492
- },
493
- message: "Starting fresh loop with new research"
494
- };
495
398
  }
496
399
  return {
497
- route: "escalate_user",
400
+ route: "escalate",
498
401
  agent: null,
499
- prompt: "Dispatcher encountered an unexpected state combination",
402
+ prompt: "Dispatcher encountered unexpected state",
500
403
  state: {
501
- task_id: `${currentState.slug}-${currentState.task_number.toString().padStart(3, "0")}`,
502
- loops: currentState.loops,
503
- maxLoops: settings.maxLoops,
504
- clerkRetries: currentState.clerkRetries
404
+ task_id: `${slug}-${taskNumber.toString().padStart(3, "0")}`,
405
+ phase: "escalated"
505
406
  },
506
- message: "ESCALATING TO USER - unexpected state"
407
+ message: "Unexpected state - escalating"
507
408
  };
508
409
  }
509
- function buildResearchPrompt(args, state, settings) {
510
- const needsTodo = args.needsDecomposition === true;
511
- return `You are the Clerk. Research this task and compose a scoped prompt.
512
-
513
- Task ${state.task_number}: ${args.description}
514
-
515
- Research steps:
516
- 1. Use codebase-index to search for relevant code (max ${settings.maxResults} results)
517
- 2. Read graph files from Manifold/graph/ for relevant files
518
- 3. Read recent task logs from Manifold/tasks/ (${settings.recentTaskCount} most recent)
519
- ${needsTodo ? `4. Read the full plan file (${args.plan_file}) for project-wide context` : ""}
520
-
521
- ${needsTodo ? `IMPORTANT: This task requires project-wide decomposition. After researching, you will need to:
522
- - Identify all files that need to be created or modified
523
- - Break the work into logical subtasks
524
- - Prepare context for each subtask` : ""}
525
-
526
- Output Format - STRICTLY FOLLOW THIS:
527
-
528
- ===SCOPED_PROMPT_START===
529
- [Your composed scoped prompt - include task goal, relevant code snippets, prior decisions, design guidelines]
530
- ===SCOPED_PROMPT_END===
531
-
532
- ===CONTEXT_USED_START===
533
- [List of context documents you used - file paths and brief descriptions]
534
- ===CONTEXT_USED_END===`;
410
+ function buildExecutePrompt(taskNumber, taskDescription) {
411
+ return `CLERK - EXECUTE TASK
412
+ TASK NUMBER: ${taskNumber}
413
+ TASK: ${taskDescription}
414
+
415
+ INSTRUCTIONS:
416
+
417
+ 1. RESEARCH
418
+ Use the Research skill with the given task to gather potentially relevant context.
419
+
420
+ 2. COMPOSE SCOPED PROMPT
421
+ Combine into a scoped prompt:
422
+ - Task goal (what Senior Dev must accomplish)
423
+ - Relevant code snippets from research (3-10, include file paths)
424
+ - Prior decisions from wiki logs
425
+ - Design guidelines (language/framework conventions, patterns)
426
+ Balance: enough to be useful, not overwhelming. Target ~800 words max.
427
+
428
+ 3. APPLY FRAMING
429
+ - Prefer "what data goes in and what comes out" framing when it makes the goal clearer
430
+ - If task has purity tag ([pure], [shell], [mixed]):
431
+ - [pure]: Frame as data transformation, specify input/output types, emphasize no IO/side effects
432
+ - [shell]: Clarify IO boundary, what external system involved
433
+ - [mixed]: Note where logic/IO boundary falls
434
+ - Don't force functional style if task is naturally imperative
435
+
436
+ 4. CREATE TASK LOG
437
+ Write initial entry to \`Manifold/tasks/<slug>-<task-number>.md\` (e.g., auth-fix-001.md):
438
+ - Header: Date, Status=IN_PROGRESS, Task Description
439
+ - Include the scoped prompt you composed
440
+ - List context documents used (files, wiki logs, graphs)
441
+
442
+ 5. CALL SENIOR-DEV
443
+ Call @senior-dev with the finalized scoped prompt. Wait for response.
444
+
445
+ 6. REPORT OUTCOME
446
+ When senior-dev returns, determine if it reported "task complete" or "task failure".
447
+ Call dispatchTask() again (no arguments needed - the tool will ask for the result next).
448
+
449
+ CONSTRAINTS:
450
+ - Do not make autonomous decisions about the task lifecycle.
451
+ - Wait for the dispatcher's next instruction after senior-dev completes.`;
535
452
  }
536
- function buildScopedPrompt(researchSummary, args) {
537
- return `You are the Senior Developer. Implement this task.
538
-
539
- Task: ${args.description}
540
-
541
- Research Context:
542
- ${researchSummary}
543
-
544
- Implement the task following the requirements and patterns from the research context.`;
545
- }
546
- function buildReviewPrompt(implementation, args) {
547
- return `You are the Junior Developer reviewing the Senior Developer's implementation.
548
-
549
- Task: ${args.description}
550
-
551
- Senior Developer's Implementation:
552
- ${implementation}
553
-
554
- Review the implementation against the task requirements. Your response MUST begin with exactly "COMPLETE" or "QUESTIONS" as the first word.
555
-
556
- If COMPLETE: Briefly explain why the implementation is acceptable.
557
- If QUESTIONS: List specific issues blocking approval with actionable feedback.`;
558
- }
559
- function buildReImplementPrompt(state, args) {
560
- return `You are the Senior Developer. Re-implement this task addressing the Junior Developer's feedback.
561
-
562
- Task: ${args.description}
563
-
564
- Original Scoped Prompt:
565
- ${state.researchSummary}
566
-
567
- Junior Developer's Feedback:
568
- ${state.reviewFeedback}
569
-
570
- Address these issues and resubmit your implementation.`;
571
- }
572
- function buildDebugPrompt(state, args) {
573
- return `You are the Debug Agent. The Senior/Junior loop has failed ${state.loops} times.
574
-
575
- Task: ${args.description}
576
-
577
- Research Context:
578
- ${state.researchSummary}
579
-
580
- Failed Implementation:
581
- ${state.implementationOutput}
582
-
583
- Junior Developer's Feedback:
584
- ${state.reviewFeedback}
585
-
586
- Analyze why the loop is stuck and suggest a concrete alternative approach.`;
587
- }
588
- function buildDebugImplementPrompt(state, args) {
589
- return `You are the Senior Developer. Implement the Debug Agent's suggestion.
590
-
591
- Task: ${args.description}
592
-
593
- Debug Agent's Analysis:
594
- ${state.debugAnalysis}
595
-
596
- Implement the task following the Debug agent's suggestion.`;
453
+ function buildOutcomeCheckPrompt() {
454
+ return `CLERK - OUTCOME CHECK
455
+ INSTRUCTIONS:
456
+ 1. Based on the senior-dev's response you just received, determine the outcome:
457
+ - If senior-dev said "task complete" (or similar), pass \`success: true\` on your next dispatchTask call
458
+ - If senior-dev said "task failure" (or similar), pass \`success: false\` on your next dispatchTask call
459
+
460
+ NEXT CALL:
461
+ Call dispatchTask({ success: true }) or dispatchTask({ success: false }) based on the outcome.`;
597
462
  }
598
- function buildReResearchPrompt(state, args) {
599
- return `You are the Clerk. The previous implementation attempt failed. Re-research with failure context.
600
-
601
- Original Task: ${args.description}
602
-
603
- Previous Implementation (failed):
604
- ${state.implementationOutput}
605
-
606
- Junior Developer's Feedback:
607
- ${state.reviewFeedback}
608
-
609
- Debug Agent's Suggestion (also didn't work):
610
- ${state.debugAnalysis}
611
-
612
- Re-research the task with this failure context and compose a new scoped prompt that addresses the underlying issues.`;
613
- }
614
- function buildLoggingPrompt(state, args) {
463
+ function buildLoggingPrompt(state, taskDescription) {
615
464
  const taskId = `${state.slug}-${state.task_number.toString().padStart(3, "0")}`;
616
465
  const date = new Date().toISOString().split("T")[0];
617
- return `You are the Clerk. Log the completed task to the project wiki.
618
-
619
- Task ID: ${taskId}
620
- Task Description: ${args.description}
621
- Date: ${date}
622
- Status: COMPLETED
623
- Loops: ${state.loops}
624
-
625
- Scoped Prompt Used:
626
- ${state.researchSummary}
627
-
628
- Senior Developer's Final Implementation:
629
- ${state.implementationOutput}
630
-
631
- Junior Developer's Approval Response:
632
- ${state.reviewFeedback}
633
-
634
- Please perform the following logging actions:
635
-
636
- 1. Create/Update Task File at \`Manifold/tasks/${taskId}.md\`:
637
- - Header with date, status, loops, task description
638
- - Scoped Prompt section
639
- - Design Decisions section (extract from Senior's implementation reasoning)
640
- - Files Touched section (extract file paths from Senior's implementation)
641
- - Complete Loop History section
642
-
643
- 2. Update \`Manifold/index.md\`:
644
- - Add entry under the plan's section:
645
- \`- [[${taskId}]] ${args.description} | ${date} | COMPLETED\`
466
+ return `CLERK - LOGGING PHASE
467
+ TASK: ${taskDescription}
468
+ TASK ID: ${taskId}
469
+
470
+ INSTRUCTIONS:
471
+ 1. Update task log at \`Manifold/tasks/${taskId}.md\`:
472
+ - Change Status from IN_PROGRESS to COMPLETED (or FAILED if applicable)
473
+ - Add senior-dev's final implementation summary
474
+ - Document what was done and files changed
475
+ - If failed: document what was tried and why it failed
476
+
477
+ 2. Update index at \`Manifold/index.md\`:
478
+ - Add: \`- [[${taskId}]] — ${taskDescription} | ${date} | COMPLETED\`
479
+
480
+ 3. Append to log at \`Manifold/log.md\`:
481
+ - Add: \`## [${date}] ${taskId} | ${taskDescription} | COMPLETED\`
482
+
483
+ 4. Update graph files for touched files:
484
+ - For each file touched, update/add \`Manifold/graph/<graph-name>.md\`
485
+ - Add task ID to "Tasks That Edited" section
486
+ - Replace \`/\` with \`__SL__\` and \`.\` with \`__DT__\` in filenames
487
+ - Example: \`src/middleware/auth.ts\` → \`Manifold/graph/src__SL__middleware__SL__auth__DT__ts.md\`
488
+
489
+ AFTER COMPLETING LOGGING:
490
+ Call dispatchTask() with no arguments. The dispatcher will complete the task and reset state.`;
491
+ }
492
+ function buildRePromptPrompt(state, taskDescription) {
493
+ const attemptNumber = state.clerk_retries + 1;
494
+ return `CLERK - RECOVERY ATTEMPT ${attemptNumber}
495
+ TASK: ${taskDescription}
496
+ PREVIOUS ATTEMPT FAILED
497
+
498
+ INSTRUCTIONS:
499
+ 1. Call @senior-dev again with the same task description
500
+ 2. Include context from the previous failure:
501
+ - The previous implementation was not accepted
502
+ - Senior-dev should try a different approach
503
+ 3. Senior-dev will again manage the review loop internally
504
+
505
+ NEXT:
506
+ After senior-dev completes, call dispatchTask() again to report outcome.`;
507
+ }
508
+ function buildEscalationPrompt(state, taskDescription) {
509
+ return `CLERK - ESCALATION
510
+ TASK: ${taskDescription}
646
511
 
647
- 3. Append to \`Manifold/log.md\`:
648
- \`## [${date}] ${taskId} | ${args.description} | COMPLETED | ${state.loops} loops\`
512
+ The task has failed after ${state.clerk_retries} recovery attempts.
649
513
 
650
- 4. Update graph files for each touched file:
651
- - Read the implementation and identify all files that were created or modified
652
- - For each file, create or update \`Manifold/graph/<graph-name>.md\`
653
- - Add the task ID to the "Tasks That Edited" section
654
- - Do NOT populate "Calls" or "Depends On" sections — those are synced automatically from the codebase index
655
- - Graph filename format: replace \`/\` with \`__SL__\` and \`.\` with \`__DT__\`, append \`.md\`
656
- - Example: \`src/middleware/auth.ts\` \`src__SL__middleware__SL__auth__DT__ts.md\`
514
+ INSTRUCTIONS:
515
+ 1. Log the failure to \`Manifold/tasks/<task-id>.md\` with status=FAILED
516
+ 2. Report to the user:
517
+ - Task description: ${taskDescription}
518
+ - Status: FAILED
519
+ - Attempts made: ${state.clerk_retries}
520
+ - Summary of what was tried and why it failed
657
521
 
658
- Extract the list of files touched from the Senior's implementation and include it in your response.`;
522
+ This task cannot be completed automatically. Human intervention required.`;
659
523
  }
660
524
  function getClient() {
661
525
  if (!pluginClient) {
@@ -664,44 +528,38 @@ function getClient() {
664
528
  return pluginClient;
665
529
  }
666
530
  var dispatchTaskTool = tool({
667
- description: "Dispatcher for the multi-agent development system. Returns routing instructions based on bool state. Clerk calls this to determine the next step in the task workflow.",
531
+ description: "Dispatcher for the multi-agent development system. Returns routing instructions based on task state. Clerk calls this with no arguments to get next prompt.",
668
532
  args: {
669
- task_number: tool.schema.number().optional().describe("Sequential task number (required on first call)"),
670
- plan_file: tool.schema.string().optional().describe("Path to the plan document (required on first call)"),
671
- newTask: tool.schema.boolean().optional().describe("TRUE: First call for this task. Resets all state."),
672
- researchComplete: tool.schema.boolean().optional().describe("TRUE: Clerk has finished researching the codebase"),
673
- hasImplementation: tool.schema.boolean().optional().describe("TRUE: Senior-dev returned working code"),
674
- reviewDone: tool.schema.boolean().optional().describe("TRUE: Junior-dev has responded (regardless of pass/fail)"),
675
- reviewPassed: tool.schema.boolean().optional().describe("TRUE: Junior-dev responded with COMPLETE"),
676
- needsDecomposition: tool.schema.boolean().optional().describe("TRUE: Task requires project-wide decomposition"),
677
- debugComplete: tool.schema.boolean().optional().describe("TRUE: Debug agent has finished analyzing"),
678
- reResearched: tool.schema.boolean().optional().describe("TRUE: Clerk has re-researched with failure context"),
679
- researchSummary: tool.schema.string().optional().describe("Clerk's research findings"),
680
- implementationOutput: tool.schema.string().optional().describe("Senior-dev's full output"),
681
- reviewFeedback: tool.schema.string().optional().describe("Junior-dev's full response"),
682
- debugAnalysis: tool.schema.string().optional().describe("Debug agent's full analysis"),
683
- notes: tool.schema.string().optional().describe("Optional free-text reasoning")
533
+ task_number: tool.schema.number().optional().describe("Task number"),
534
+ plan_file: tool.schema.string().optional().describe("Path to plan document"),
535
+ description: tool.schema.string().optional().describe("Task description"),
536
+ success: tool.schema.boolean().optional().describe("TRUE if senior-dev completed task successfully, FALSE if failed"),
537
+ senior_output: tool.schema.string().optional().describe("Senior dev's output/summary"),
538
+ clerk_summary: tool.schema.string().optional().describe("Clerk's summary of the task")
684
539
  },
685
540
  async execute(args, context) {
686
- const { task_number, plan_file } = args;
541
+ const { task_number, plan_file, description } = args;
687
542
  const client = getClient();
688
543
  const directory = context.directory;
689
544
  await client.app.log({
690
545
  body: {
691
546
  service: "opencode-manifold",
692
547
  level: "info",
693
- message: `dispatchTask called: task ${task_number || "unknown"} - ${args.newTask ? "new task" : "continuing"}`
548
+ message: `dispatchTask called: task ${task_number || "unknown"}`
694
549
  }
695
550
  });
696
551
  const settings = await readSettings(directory);
697
552
  const existingState = task_number ? await readDispatcherState(directory, task_number) : null;
698
- let taskInfo = null;
699
- if (args.newTask && plan_file) {
553
+ let taskDescription = description || "";
554
+ if (!taskDescription && args.plan_file && task_number) {
700
555
  try {
701
- const planPath = join2(directory, plan_file);
556
+ const planPath = join2(directory, args.plan_file);
702
557
  if (existsSync2(planPath)) {
703
558
  const planContent = await readFile2(planPath, "utf-8");
704
- taskInfo = extractTaskFromPlan(planContent, task_number);
559
+ const taskInfo = extractTaskFromPlan(planContent, task_number);
560
+ if (taskInfo) {
561
+ taskDescription = taskInfo.description;
562
+ }
705
563
  }
706
564
  } catch (error) {
707
565
  await client.app.log({
@@ -713,24 +571,46 @@ var dispatchTaskTool = tool({
713
571
  });
714
572
  }
715
573
  }
716
- const mergedArgs = {
717
- ...args,
718
- description: taskInfo?.description || args.description
719
- };
720
- const result = runDispatcherLogic(mergedArgs, existingState, settings);
574
+ const result = runDispatcherLogic(args, existingState, settings, taskDescription);
575
+ let newPhase = "init";
576
+ if (result.route === "execute")
577
+ newPhase = "awaiting_execution";
578
+ else if (result.route === "outcome_check")
579
+ newPhase = "awaiting_outcome";
580
+ else if (result.route === "logging")
581
+ newPhase = "logging";
582
+ else if (result.route === "complete")
583
+ newPhase = "complete";
584
+ else if (result.route === "escalate")
585
+ newPhase = "escalated";
586
+ else if (result.route === "reprompt")
587
+ newPhase = "awaiting_execution";
721
588
  if (task_number && result.state.task_id) {
722
- const newState = {
723
- task_number,
724
- plan_file: plan_file || "",
725
- slug: result.state.task_id.split("-")[0],
726
- loops: result.state.loops,
727
- clerkRetries: result.state.clerkRetries,
728
- researchSummary: args.researchSummary || existingState?.researchSummary || "",
729
- implementationOutput: args.implementationOutput || existingState?.implementationOutput || "",
730
- reviewFeedback: args.reviewFeedback || existingState?.reviewFeedback || "",
731
- debugAnalysis: args.debugAnalysis || existingState?.debugAnalysis || ""
732
- };
733
- await writeDispatcherState(directory, newState);
589
+ if (result.route === "logging" || result.route === "escalate") {
590
+ const newState = {
591
+ task_number,
592
+ plan_file: plan_file || "",
593
+ slug: result.state.task_id.split("-")[0],
594
+ phase: newPhase,
595
+ senior_output: args.senior_output || existingState?.senior_output || "",
596
+ clerk_summary: args.clerk_summary || existingState?.clerk_summary || "",
597
+ loops: existingState?.loops || 0,
598
+ clerk_retries: existingState?.clerk_retries || 0
599
+ };
600
+ await writeDispatcherState(directory, newState);
601
+ } else {
602
+ const newState = {
603
+ task_number,
604
+ plan_file: plan_file || "",
605
+ slug: result.state.task_id.split("-")[0],
606
+ phase: newPhase,
607
+ senior_output: args.senior_output || existingState?.senior_output || "",
608
+ clerk_summary: args.clerk_summary || existingState?.clerk_summary || "",
609
+ loops: existingState?.loops || 0,
610
+ clerk_retries: existingState?.clerk_retries || 0
611
+ };
612
+ await writeDispatcherState(directory, newState);
613
+ }
734
614
  }
735
615
  await client.app.log({
736
616
  body: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-manifold",
3
- "version": "0.5.6",
3
+ "version": "0.5.8",
4
4
  "description": "Multi-agent development system for opencode with persistent knowledge",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",