opencode-orchestrator 0.6.0 → 0.6.2

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
@@ -57,8 +57,10 @@ var PARALLEL_TASK = {
57
57
  // 10 per agent type
58
58
  MAX_CONCURRENCY: 50,
59
59
  // 50 total
60
- SYNC_TIMEOUT_MS: 10 * TIME.MINUTE
60
+ SYNC_TIMEOUT_MS: 10 * TIME.MINUTE,
61
61
  // 10 minutes for sync mode
62
+ MAX_DEPTH: 3
63
+ // Max nesting depth (Commander -> Agent -> Sub-task)
62
64
  };
63
65
  var MEMORY_LIMITS = {
64
66
  MAX_TASKS_IN_MEMORY: 1e3,
@@ -236,7 +238,7 @@ RECORD findings if on Deep Track.
236
238
  |-------|----------|
237
239
  | Fast | Use \`${AGENT_NAMES.BUILDER}\` directly. Skip \`${AGENT_NAMES.ARCHITECT}\`. |
238
240
  | Normal | Call \`${AGENT_NAMES.ARCHITECT}\` for lightweight plan. |
239
- | Deep | Full \`${AGENT_NAMES.ARCHITECT}\` DAG + \`${AGENT_NAMES.RECORDER}\` state tracking. |
241
+ | Deep | Full planning + \`${AGENT_NAMES.RECORDER}\` state tracking. |
240
242
 
241
243
  AVAILABLE AGENTS:
242
244
  - \`${AGENT_NAMES.ARCHITECT}\`: Task decomposition and planning
@@ -1003,70 +1005,6 @@ var AGENTS = {
1003
1005
  [AGENT_NAMES.RESEARCHER]: researcher
1004
1006
  };
1005
1007
 
1006
- // src/core/orchestrator/task-graph.ts
1007
- var TaskGraph = class _TaskGraph {
1008
- tasks = /* @__PURE__ */ new Map();
1009
- constructor(tasks) {
1010
- if (tasks) {
1011
- tasks.forEach((t) => this.addTask(t));
1012
- }
1013
- }
1014
- addTask(task) {
1015
- this.tasks.set(task.id, { ...task, status: "pending", retryCount: 0 });
1016
- }
1017
- getTask(id) {
1018
- return this.tasks.get(id);
1019
- }
1020
- updateTask(id, updates) {
1021
- const task = this.tasks.get(id);
1022
- if (task) {
1023
- this.tasks.set(id, { ...task, ...updates });
1024
- }
1025
- }
1026
- getReadyTasks() {
1027
- return Array.from(this.tasks.values()).filter((task) => {
1028
- if (task.status !== "pending") return false;
1029
- return task.dependencies.every((depId) => {
1030
- const dep = this.tasks.get(depId);
1031
- return dep && dep.status === "completed";
1032
- });
1033
- });
1034
- }
1035
- isCompleted() {
1036
- return Array.from(this.tasks.values()).every((t) => t.status === "completed");
1037
- }
1038
- hasFailed() {
1039
- return Array.from(this.tasks.values()).some((t) => t.status === "failed" && t.retryCount >= 3);
1040
- }
1041
- getTaskSummary() {
1042
- const tasks = Array.from(this.tasks.values());
1043
- const completed = tasks.filter((t) => t.status === "completed");
1044
- const notCompleted = tasks.filter((t) => t.status !== "completed");
1045
- let summary = "\u{1F4CB} **Mission Status**\n";
1046
- if (completed.length > 0) {
1047
- summary += `\u2705 Completed: ${completed.length} tasks
1048
- `;
1049
- }
1050
- for (const task of notCompleted) {
1051
- const icon = task.status === "running" ? "\u23F3" : task.status === "failed" ? "\u274C" : "\u{1F4A4}";
1052
- summary += `${icon} [${task.id}] ${task.description}
1053
- `;
1054
- }
1055
- return summary;
1056
- }
1057
- toJSON() {
1058
- return JSON.stringify(Array.from(this.tasks.values()), null, 2);
1059
- }
1060
- static fromJSON(json2) {
1061
- try {
1062
- const tasks = JSON.parse(json2);
1063
- return new _TaskGraph(tasks);
1064
- } catch {
1065
- return new _TaskGraph();
1066
- }
1067
- }
1068
- };
1069
-
1070
1008
  // src/core/orchestrator/state.ts
1071
1009
  var state = {
1072
1010
  missionActive: false,
@@ -1806,10 +1744,10 @@ function mergeDefs(...defs) {
1806
1744
  function cloneDef(schema) {
1807
1745
  return mergeDefs(schema._zod.def);
1808
1746
  }
1809
- function getElementAtPath(obj, path3) {
1810
- if (!path3)
1747
+ function getElementAtPath(obj, path4) {
1748
+ if (!path4)
1811
1749
  return obj;
1812
- return path3.reduce((acc, key) => acc?.[key], obj);
1750
+ return path4.reduce((acc, key) => acc?.[key], obj);
1813
1751
  }
1814
1752
  function promiseAllObject(promisesObj) {
1815
1753
  const keys = Object.keys(promisesObj);
@@ -2170,11 +2108,11 @@ function aborted(x, startIndex = 0) {
2170
2108
  }
2171
2109
  return false;
2172
2110
  }
2173
- function prefixIssues(path3, issues) {
2111
+ function prefixIssues(path4, issues) {
2174
2112
  return issues.map((iss) => {
2175
2113
  var _a;
2176
2114
  (_a = iss).path ?? (_a.path = []);
2177
- iss.path.unshift(path3);
2115
+ iss.path.unshift(path4);
2178
2116
  return iss;
2179
2117
  });
2180
2118
  }
@@ -2342,7 +2280,7 @@ function treeifyError(error45, _mapper) {
2342
2280
  return issue2.message;
2343
2281
  };
2344
2282
  const result = { errors: [] };
2345
- const processError = (error46, path3 = []) => {
2283
+ const processError = (error46, path4 = []) => {
2346
2284
  var _a, _b;
2347
2285
  for (const issue2 of error46.issues) {
2348
2286
  if (issue2.code === "invalid_union" && issue2.errors.length) {
@@ -2352,7 +2290,7 @@ function treeifyError(error45, _mapper) {
2352
2290
  } else if (issue2.code === "invalid_element") {
2353
2291
  processError({ issues: issue2.issues }, issue2.path);
2354
2292
  } else {
2355
- const fullpath = [...path3, ...issue2.path];
2293
+ const fullpath = [...path4, ...issue2.path];
2356
2294
  if (fullpath.length === 0) {
2357
2295
  result.errors.push(mapper(issue2));
2358
2296
  continue;
@@ -2384,8 +2322,8 @@ function treeifyError(error45, _mapper) {
2384
2322
  }
2385
2323
  function toDotPath(_path) {
2386
2324
  const segs = [];
2387
- const path3 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
2388
- for (const seg of path3) {
2325
+ const path4 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
2326
+ for (const seg of path4) {
2389
2327
  if (typeof seg === "number")
2390
2328
  segs.push(`[${seg}]`);
2391
2329
  else if (typeof seg === "symbol")
@@ -13504,7 +13442,7 @@ var callAgentTool = tool({
13504
13442
  <agents>
13505
13443
  | Agent | Role | When to Use |
13506
13444
  |-------|------|-------------|
13507
- | ${AGENT_NAMES.ARCHITECT} \u{1F3D7}\uFE0F | Planner | Complex task \u2192 DAG, OR 3+ failures \u2192 strategy |
13445
+ | ${AGENT_NAMES.ARCHITECT} \u{1F3D7}\uFE0F | Planner | Complex task \u2192 plan, OR 3+ failures \u2192 strategy |
13508
13446
  | ${AGENT_NAMES.BUILDER} \u{1F528} | Developer | Any code implementation (logic + UI) |
13509
13447
  | ${AGENT_NAMES.INSPECTOR} \u{1F50D} | Quality | Before completion, OR on errors (auto-fixes) |
13510
13448
  | ${AGENT_NAMES.RECORDER} \u{1F4BE} | Context | After each task, OR at session start |
@@ -13565,321 +13503,30 @@ Never claim completion without proof.
13565
13503
  });
13566
13504
 
13567
13505
  // src/tools/slashCommand.ts
13568
- var COMMANDER_MISSION_PROMPT = `<role>
13569
- You are Commander. Complete missions autonomously. Never stop until done.
13570
- </role>
13571
-
13572
- <core_rules>
13573
- 1. Never stop until "${MISSION.COMPLETE}"
13574
- 2. Never wait for user during execution
13575
- 3. Never stop because agent returned nothing
13576
- 4. Always survey environment & codebase BEFORE coding
13577
- 5. Always verify with evidence based on runtime context
13578
- </core_rules>
13579
-
13580
- <phase_0 name="TRIAGE">
13581
- Evaluate the complexity of the request:
13582
-
13583
- | Level | Signal | Track |
13584
- |-------|--------|-------|
13585
- | \u{1F7E2} L1: Simple | One file, clear fix, no dependencies | **FAST TRACK** |
13586
- | \u{1F7E1} L2: Feature | New functionality, clear patterns | **NORMAL TRACK** |
13587
- | \u{1F534} L3: Complex | Refactoring, infra change, unknown scope | **DEEP TRACK** |
13588
- </phase_0>
13589
-
13590
- <anti_hallucination>
13591
- CRITICAL: ELIMINATE GUESSING. VERIFY EVERYTHING.
13592
-
13593
- BEFORE ANY IMPLEMENTATION:
13594
- 1. If using unfamiliar API/library \u2192 RESEARCH FIRST
13595
- 2. If uncertain about patterns/syntax \u2192 SEARCH DOCUMENTATION
13596
- 3. NEVER assume - always verify from official sources
13597
-
13598
- RESEARCH WORKFLOW:
13599
- \`\`\`
13600
- // Step 1: Search for documentation
13601
- websearch({ query: "Next.js 14 app router official docs" })
13602
-
13603
- // Step 2: Fetch specific documentation
13604
- webfetch({ url: "https://nextjs.org/docs/app/..." })
13605
-
13606
- // Step 3: Check cached docs
13607
- cache_docs({ action: "list" })
13608
-
13609
- // Step 4: For complex research, delegate to Librarian
13610
- ${TOOL_NAMES.DELEGATE_TASK}({
13611
- agent: "${AGENT_NAMES.LIBRARIAN}",
13612
- description: "Research X API",
13613
- prompt: "Find official documentation for...",
13614
- background: false // Wait for research before implementing
13615
- })
13616
- \`\`\`
13617
-
13618
- MANDATORY RESEARCH TRIGGERS:
13619
- - New library/framework you haven't used in this session
13620
- - API syntax you're not 100% sure about
13621
- - Version-specific features (check version compatibility!)
13622
- - Configuration patterns (check official examples)
13623
-
13624
- WHEN CAUGHT GUESSING:
13625
- 1. STOP immediately
13626
- 2. Search for official documentation
13627
- 3. Cache important findings: webfetch({ url: "...", cache: true })
13628
- 4. Then proceed with verified information
13629
- </anti_hallucination>
13630
-
13631
- <phase_1 name="CONTEXT_GATHERING">
13632
- IF FAST TRACK (L1):
13633
- - Scan ONLY the target file and its immediate imports.
13634
- - Skip broad infra/domain/doc scans unless an error occurs.
13635
- - Proceed directly to execution.
13636
-
13637
- IF NORMAL/DEEP TRACK (L2/L3):
13638
- - **Deep Scan Required**: Execute the full "MANDATORY ENVIRONMENT SCAN".
13639
- - 1. Infra check (Docker/OS)
13640
- - 2. Domain & Stack check
13641
- - 3. Pattern check
13506
+ var TASK_TRIGGER_TEMPLATE = `<mission_mode>
13507
+ You are now in MISSION MODE. Execute the following task autonomously until complete.
13642
13508
 
13643
- RECORD findings if on Deep Track.
13644
- </phase_1>
13645
-
13646
- <phase_2 name="TOOL_AGENT_SELECTION">
13647
- | Track | Strategy |
13648
- |-------|----------|
13649
- | Fast | Use \`${AGENT_NAMES.BUILDER}\` directly. Skip \`${AGENT_NAMES.ARCHITECT}\`. |
13650
- | Normal | Call \`${AGENT_NAMES.ARCHITECT}\` for lightweight plan. |
13651
- | Deep | Full \`${AGENT_NAMES.ARCHITECT}\` DAG + \`${AGENT_NAMES.RECORDER}\` state tracking. |
13652
-
13653
- AVAILABLE AGENTS:
13654
- - \`${AGENT_NAMES.ARCHITECT}\`: Task decomposition and planning
13655
- - \`${AGENT_NAMES.BUILDER}\`: Code implementation
13656
- - \`${AGENT_NAMES.INSPECTOR}\`: Verification and bug fixing
13657
- - \`${AGENT_NAMES.RECORDER}\`: State tracking (Deep Track only)
13658
- - \`${AGENT_NAMES.LIBRARIAN}\`: Documentation research (Anti-Hallucination) \u2B50 NEW
13659
-
13660
- WHEN TO USE LIBRARIAN:
13661
- - Before using new APIs/libraries
13662
- - When error messages are unclear
13663
- - When implementing complex integrations
13664
- - When official documentation is needed
13665
-
13666
- DEFAULT to Deep Track if unsure to act safely.
13667
- </phase_2>
13668
-
13669
- <phase_3 name="DELEGATION">
13670
- <agent_calling>
13671
- CRITICAL: USE ${TOOL_NAMES.DELEGATE_TASK} FOR ALL DELEGATION
13672
-
13673
- ${TOOL_NAMES.DELEGATE_TASK} has THREE MODES:
13674
- - background=true: Non-blocking, parallel execution
13675
- - background=false: Blocking, waits for result
13676
- - resume: Continue existing session
13677
-
13678
- | Situation | How to Call |
13679
- |-----------|-------------|
13680
- | Multiple independent tasks | \`${TOOL_NAMES.DELEGATE_TASK}({ ..., background: true })\` for each |
13681
- | Single task, continue working | \`${TOOL_NAMES.DELEGATE_TASK}({ ..., background: true })\` |
13682
- | Need result for VERY next step | \`${TOOL_NAMES.DELEGATE_TASK}({ ..., background: false })\` |
13683
- | Retry after failure | \`${TOOL_NAMES.DELEGATE_TASK}({ ..., resume: "session_id", ... })\` |
13684
- | Follow-up question | \`${TOOL_NAMES.DELEGATE_TASK}({ ..., resume: "session_id", ... })\` |
13685
-
13686
- PREFER background=true (PARALLEL):
13687
- - Run multiple agents simultaneously
13688
- - Continue analysis while they work
13689
- - System notifies when ALL complete
13690
-
13691
- EXAMPLE - PARALLEL:
13692
- \`\`\`
13693
- // Multiple tasks in parallel
13694
- ${TOOL_NAMES.DELEGATE_TASK}({ agent: "${AGENT_NAMES.BUILDER}", description: "Implement X", prompt: "...", background: true })
13695
- ${TOOL_NAMES.DELEGATE_TASK}({ agent: "${AGENT_NAMES.INSPECTOR}", description: "Review Y", prompt: "...", background: true })
13696
-
13697
- // Continue other work (don't wait!)
13698
-
13699
- // When notified "All Complete":
13700
- ${TOOL_NAMES.GET_TASK_RESULT}({ taskId: "${ID_PREFIX.TASK}xxx" })
13701
- \`\`\`
13702
-
13703
- EXAMPLE - SYNC (rare):
13704
- \`\`\`
13705
- // Only when you absolutely need the result now
13706
- const result = ${TOOL_NAMES.DELEGATE_TASK}({ agent: "${AGENT_NAMES.BUILDER}", ..., background: false })
13707
- // Result is immediately available
13708
- \`\`\`
13709
-
13710
- EXAMPLE - RESUME (for retry or follow-up):
13711
- \`\`\`
13712
- // Previous task output shows: Session: \`${ID_PREFIX.SESSION}abc123\` (save for resume)
13713
-
13714
- // Retry after failure (keeps all context!)
13715
- ${TOOL_NAMES.DELEGATE_TASK}({
13716
- agent: "${AGENT_NAMES.BUILDER}",
13717
- description: "Fix previous error",
13718
- prompt: "The build failed with X. Please fix it.",
13719
- background: true,
13720
- resume: "${ID_PREFIX.SESSION}abc123" // \u2190 Continue existing session
13721
- })
13722
-
13723
- // Follow-up question (saves tokens!)
13724
- ${TOOL_NAMES.DELEGATE_TASK}({
13725
- agent: "${AGENT_NAMES.INSPECTOR}",
13726
- description: "Additional check",
13727
- prompt: "Also check for Y in the files you just reviewed.",
13728
- background: true,
13729
- resume: "${ID_PREFIX.SESSION}xyz789"
13730
- })
13731
- \`\`\`
13732
- </agent_calling>
13733
-
13734
- <delegation_template>
13735
- AGENT: [name]
13736
- TASK: [one atomic action]
13737
- ENVIRONMENT:
13738
- - Infra: [e.g. Docker + Volume mount]
13739
- - Stack: [e.g. Next.js + PostgreSQL]
13740
- - Patterns: [existing code conventions to follow]
13741
- MUST: [Specific requirements]
13742
- AVOID: [Restrictions]
13743
- VERIFY: [Success criteria with evidence]
13744
- </delegation_template>
13745
- </phase_3>
13746
-
13747
- <phase_4 name="EXECUTION_VERIFICATION">
13748
- During implementation:
13749
- - Match existing codebase style exactly
13750
- - Run lsp_diagnostics after each change
13751
-
13752
- <background_parallel_execution>
13753
- PARALLEL EXECUTION SYSTEM:
13754
-
13755
- You have access to a powerful parallel agent execution system.
13756
- Up to 50 agents can run simultaneously with automatic resource management.
13757
-
13758
- 1. **${TOOL_NAMES.DELEGATE_TASK}** - Launch agents in parallel or sync mode
13759
- \`\`\`
13760
- // PARALLEL (recommended - non-blocking)
13761
- ${TOOL_NAMES.DELEGATE_TASK}({
13762
- agent: "${AGENT_NAMES.BUILDER}",
13763
- description: "Implement X",
13764
- prompt: "...",
13765
- background: true
13766
- })
13767
-
13768
- // SYNC (blocking - wait for result)
13769
- ${TOOL_NAMES.DELEGATE_TASK}({
13770
- agent: "${AGENT_NAMES.LIBRARIAN}",
13771
- description: "Research Y",
13772
- prompt: "...",
13773
- background: false
13774
- })
13775
-
13776
- // RESUME (continue previous session)
13777
- ${TOOL_NAMES.DELEGATE_TASK}({
13778
- agent: "${AGENT_NAMES.BUILDER}",
13779
- description: "Fix error",
13780
- prompt: "...",
13781
- background: true,
13782
- resume: "${ID_PREFIX.SESSION}abc123" // From previous task output
13783
- })
13784
- \`\`\`
13785
-
13786
- 2. **${TOOL_NAMES.GET_TASK_RESULT}** - Retrieve completed task output
13787
- \`\`\`
13788
- ${TOOL_NAMES.GET_TASK_RESULT}({ taskId: "${ID_PREFIX.TASK}xxx" })
13789
- \`\`\`
13790
-
13791
- 3. **${TOOL_NAMES.LIST_TASKS}** - View all parallel tasks
13792
- \`\`\`
13793
- ${TOOL_NAMES.LIST_TASKS}({})
13794
- \`\`\`
13795
-
13796
- 4. **${TOOL_NAMES.CANCEL_TASK}** - Stop a running task
13797
- \`\`\`
13798
- ${TOOL_NAMES.CANCEL_TASK}({ taskId: "${ID_PREFIX.TASK}xxx" })
13799
- \`\`\`
13800
-
13801
- CONCURRENCY LIMITS:
13802
- - Max 10 tasks per agent type (queue automatically)
13803
- - Max 50 total parallel sessions
13804
- - Auto-timeout: 60 minutes
13805
- - Auto-cleanup: 30 min after completion \u2192 archived to disk
13806
-
13807
- SAFE PATTERNS:
13808
- \u2705 Builder on file A + Inspector on file B (different files)
13809
- \u2705 Multiple research agents (read-only)
13810
- \u2705 Build command + Test command (independent)
13811
- \u2705 Librarian research + Builder implementation (sequential deps)
13812
-
13813
- UNSAFE PATTERNS:
13814
- \u274C Multiple builders editing SAME FILE (conflict!)
13815
- \u274C Waiting synchronously for many tasks (use background=true)
13816
-
13817
- WORKFLOW:
13818
- 1. ${TOOL_NAMES.LIST_TASKS}: Check current status first
13819
- 2. ${TOOL_NAMES.DELEGATE_TASK} (background=true): Launch for INDEPENDENT tasks
13820
- 3. Continue working (NO WAITING)
13821
- 4. Wait for system notification "All Parallel Tasks Complete"
13822
- 5. ${TOOL_NAMES.GET_TASK_RESULT}: Retrieve each result
13823
- </background_parallel_execution>
13824
-
13825
- <verification_methods>
13826
- | Infra | Proof Method |
13827
- |-------|--------------|
13828
- | OS-Native | npm run build, cargo build, specific test runs |
13829
- | Container | Docker syntax check + config validation |
13830
- | Live API | curl /health if reachable, check logs |
13831
- | Generic | Manual audit by Inspector with logic summary |
13832
- </verification_methods>
13833
- </phase_4>
13834
-
13835
- <failure_recovery>
13836
- | Failures | Action |
13837
- |----------|--------|
13838
- | 1-2 | Adjust approach, retry |
13839
- | 3+ | STOP. Call ${AGENT_NAMES.ARCHITECT} for new strategy |
13840
-
13841
- <empty_responses>
13842
- | Agent Empty (or Gibberish) | Action |
13843
- |----------------------------|--------|
13844
- | ${AGENT_NAMES.RECORDER} | Fresh start. Proceed to survey. |
13845
- | ${AGENT_NAMES.ARCHITECT} | Try simpler plan yourself. |
13846
- | ${AGENT_NAMES.BUILDER} | Call ${AGENT_NAMES.INSPECTOR} to diagnose. |
13847
- | ${AGENT_NAMES.INSPECTOR} | Retry with more context. |
13848
- </empty_responses>
13849
-
13850
- STRICT RULE: If any agent output contains gibberish, mixed-language hallucinations, or fails the language rule, REJECT it immediately and trigger a "STRICT_CLEAN_START" retry.
13851
- </failure_recovery>
13852
-
13853
- <anti_patterns>
13854
- \u274C Delegate without environment/codebase context
13855
- \u274C Leave code broken or with LSP errors
13856
- \u274C Make random changes without understanding root cause
13857
- </anti_patterns>
13858
-
13859
- <completion>
13860
- Done when: Request fulfilled + lsp clean + build/test/audit pass.
13861
-
13862
- <output_format>
13863
- ${MISSION.COMPLETE}
13864
- Summary: [what was done]
13865
- Evidence: [Specific build/test/audit results]
13866
- </output_format>
13867
- </completion>
13868
-
13869
- <mission>
13509
+ <task>
13870
13510
  $ARGUMENTS
13871
- </mission>`;
13511
+ </task>
13512
+
13513
+ <execution_rules>
13514
+ 1. Complete this mission without user intervention
13515
+ 2. Use your full capabilities: research, implement, verify
13516
+ 3. Output "${MISSION.COMPLETE}" when done
13517
+ </execution_rules>
13518
+ </mission_mode>`;
13872
13519
  var COMMANDS = {
13873
13520
  "task": {
13874
- description: "\u{1F680} FULL COMMANDER MODE - Execute mission autonomously until complete",
13875
- template: COMMANDER_MISSION_PROMPT,
13521
+ description: "\u{1F680} MISSION MODE - Execute task autonomously until complete",
13522
+ template: TASK_TRIGGER_TEMPLATE,
13876
13523
  argumentHint: '"mission goal"'
13877
13524
  },
13878
13525
  "plan": {
13879
- description: "Create a parallel task DAG without executing",
13526
+ description: "Create a task plan without executing",
13880
13527
  template: `<delegate>
13881
13528
  <agent>${AGENT_NAMES.ARCHITECT}</agent>
13882
- <objective>Create parallel task DAG for: $ARGUMENTS</objective>
13529
+ <objective>Create parallel task plan for: $ARGUMENTS</objective>
13883
13530
  <success>Valid JSON with tasks array, each having id, description, agent, parallel_group, dependencies, and success criteria</success>
13884
13531
  <must_do>
13885
13532
  - Maximize parallelism by grouping independent tasks
@@ -13904,7 +13551,7 @@ var COMMANDS = {
13904
13551
  | Agent | Role | Responsibility |
13905
13552
  |-------|------|----------------|
13906
13553
  | Commander | Orchestrator | Relentless parallel execution until mission complete |
13907
- | ${AGENT_NAMES.ARCHITECT} | Planner | Decomposes complex tasks into parallel DAG |
13554
+ | ${AGENT_NAMES.ARCHITECT} | Planner | Decomposes complex tasks into parallel subtasks |
13908
13555
  | ${AGENT_NAMES.BUILDER} | Developer | Full-stack implementation (logic + UI combined) |
13909
13556
  | ${AGENT_NAMES.INSPECTOR} | Quality | 5-point audit + automatic bug fixing |
13910
13557
  | ${AGENT_NAMES.RECORDER} | Context | Persistent progress tracking across sessions |
@@ -13921,7 +13568,8 @@ THINK \u2192 ACT \u2192 OBSERVE \u2192 ADJUST \u2192 REPEAT
13921
13568
  - Auto-fix: Inspector repairs problems automatically
13922
13569
 
13923
13570
  ## Usage
13924
- Use \`/task "goal"\` for full Commander mode mission execution.`
13571
+ - Just select Commander agent and type your request
13572
+ - Or use \`/task "goal"\` for explicit mission mode`
13925
13573
  }
13926
13574
  };
13927
13575
  function createSlashcommandTool() {
@@ -13961,19 +13609,19 @@ import { existsSync } from "fs";
13961
13609
  var __dirname = dirname(fileURLToPath(import.meta.url));
13962
13610
  function getBinaryPath() {
13963
13611
  const binDir = join(__dirname, "..", "..", "bin");
13964
- const os = platform();
13612
+ const os2 = platform();
13965
13613
  const cpu = arch();
13966
13614
  let binaryName;
13967
- if (os === "win32") {
13615
+ if (os2 === "win32") {
13968
13616
  binaryName = "orchestrator-windows-x64.exe";
13969
- } else if (os === "darwin") {
13617
+ } else if (os2 === "darwin") {
13970
13618
  binaryName = cpu === "arm64" ? "orchestrator-macos-arm64" : "orchestrator-macos-x64";
13971
13619
  } else {
13972
13620
  binaryName = cpu === "arm64" ? "orchestrator-linux-arm64" : "orchestrator-linux-x64";
13973
13621
  }
13974
13622
  let binaryPath = join(binDir, binaryName);
13975
13623
  if (!existsSync(binaryPath)) {
13976
- binaryPath = join(binDir, os === "win32" ? "orchestrator.exe" : "orchestrator");
13624
+ binaryPath = join(binDir, os2 === "win32" ? "orchestrator.exe" : "orchestrator");
13977
13625
  }
13978
13626
  return binaryPath;
13979
13627
  }
@@ -14600,10 +14248,25 @@ var TaskStore = class {
14600
14248
  };
14601
14249
 
14602
14250
  // src/core/agents/logger.ts
14251
+ import * as fs2 from "fs";
14252
+ import * as os from "os";
14253
+ import * as path2 from "path";
14603
14254
  var DEBUG2 = process.env.DEBUG_PARALLEL_AGENT === "true";
14255
+ var LOG_FILE = path2.join(os.tmpdir(), "opencode-orchestrator.log");
14604
14256
  function log2(...args) {
14257
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
14258
+ const message = `[${timestamp}] [parallel-agent] ${args.map(
14259
+ (a) => typeof a === "object" ? JSON.stringify(a) : String(a)
14260
+ ).join(" ")}`;
14261
+ try {
14262
+ fs2.appendFileSync(LOG_FILE, message + "\n");
14263
+ } catch {
14264
+ }
14605
14265
  if (DEBUG2) console.log("[parallel-agent]", ...args);
14606
14266
  }
14267
+ function getLogPath() {
14268
+ return LOG_FILE;
14269
+ }
14607
14270
 
14608
14271
  // src/core/agents/format.ts
14609
14272
  function formatDuration(start, end) {
@@ -14638,8 +14301,10 @@ var TaskLauncher = class {
14638
14301
  this.startPolling = startPolling;
14639
14302
  }
14640
14303
  async launch(input) {
14304
+ log2("[task-launcher.ts] launch() called", { agent: input.agent, description: input.description, parent: input.parentSessionID });
14641
14305
  const concurrencyKey = input.agent;
14642
14306
  await this.concurrency.acquire(concurrencyKey);
14307
+ log2("[task-launcher.ts] concurrency acquired for", concurrencyKey);
14643
14308
  try {
14644
14309
  const createResult = await this.client.session.create({
14645
14310
  body: { parentID: input.parentSessionID, title: `Parallel: ${input.description}` },
@@ -14651,6 +14316,8 @@ var TaskLauncher = class {
14651
14316
  }
14652
14317
  const sessionID = createResult.data.id;
14653
14318
  const taskId = `${ID_PREFIX.TASK}${crypto.randomUUID().slice(0, 8)}`;
14319
+ const depth = (input.depth ?? 0) + 1;
14320
+ log2("[task-launcher.ts] Creating task with depth", depth);
14654
14321
  const task = {
14655
14322
  id: taskId,
14656
14323
  sessionID,
@@ -14660,14 +14327,25 @@ var TaskLauncher = class {
14660
14327
  agent: input.agent,
14661
14328
  status: TASK_STATUS.RUNNING,
14662
14329
  startedAt: /* @__PURE__ */ new Date(),
14663
- concurrencyKey
14330
+ concurrencyKey,
14331
+ depth
14664
14332
  };
14665
14333
  this.store.set(taskId, task);
14666
14334
  this.store.trackPending(input.parentSessionID, taskId);
14667
14335
  this.startPolling();
14668
14336
  this.client.session.prompt({
14669
14337
  path: { id: sessionID },
14670
- body: { agent: input.agent, parts: [{ type: PART_TYPES.TEXT, text: input.prompt }] }
14338
+ body: {
14339
+ agent: input.agent,
14340
+ tools: {
14341
+ // Prevent recursive task spawning from subagents
14342
+ delegate_task: false,
14343
+ get_task_result: false,
14344
+ list_tasks: false,
14345
+ cancel_task: false
14346
+ },
14347
+ parts: [{ type: PART_TYPES.TEXT, text: input.prompt }]
14348
+ }
14671
14349
  }).catch((error45) => {
14672
14350
  log2(`Prompt error for ${taskId}:`, error45);
14673
14351
  this.onTaskError(taskId, error45);
@@ -14746,6 +14424,7 @@ var TaskPoller = class {
14746
14424
  pollingInterval;
14747
14425
  start() {
14748
14426
  if (this.pollingInterval) return;
14427
+ log2("[task-poller.ts] start() - polling started");
14749
14428
  this.pollingInterval = setInterval(() => this.poll(), CONFIG.POLL_INTERVAL_MS);
14750
14429
  this.pollingInterval.unref();
14751
14430
  }
@@ -14765,6 +14444,7 @@ var TaskPoller = class {
14765
14444
  this.stop();
14766
14445
  return;
14767
14446
  }
14447
+ log2("[task-poller.ts] poll() checking", running.length, "running tasks");
14768
14448
  try {
14769
14449
  const statusResult = await this.client.session.status();
14770
14450
  const allStatuses = statusResult.data ?? {};
@@ -14804,6 +14484,7 @@ var TaskPoller = class {
14804
14484
  }
14805
14485
  }
14806
14486
  async completeTask(task) {
14487
+ log2("[task-poller.ts] completeTask() called for", task.id, task.agent);
14807
14488
  task.status = TASK_STATUS.COMPLETED;
14808
14489
  task.completedAt = /* @__PURE__ */ new Date();
14809
14490
  if (task.concurrencyKey) {
@@ -15348,6 +15029,7 @@ var createDelegateTaskTool = (manager, client) => tool({
15348
15029
  async execute(args, context) {
15349
15030
  const { agent, description, prompt, background, resume } = args;
15350
15031
  const ctx = context;
15032
+ log2("[delegate-task.ts] execute() called", { agent, description, background, resume, parentSession: ctx.sessionID });
15351
15033
  const sessionClient = client;
15352
15034
  if (background === void 0) {
15353
15035
  return `\u274C 'background' parameter is REQUIRED.`;
@@ -15423,7 +15105,16 @@ Session: \`${task.sessionID}\` (save for resume)`;
15423
15105
  const startTime = Date.now();
15424
15106
  await session.prompt({
15425
15107
  path: { id: sessionID },
15426
- body: { agent, parts: [{ type: PART_TYPES.TEXT, text: prompt }] }
15108
+ body: {
15109
+ agent,
15110
+ tools: {
15111
+ delegate_task: false,
15112
+ get_task_result: false,
15113
+ list_tasks: false,
15114
+ cancel_task: false
15115
+ },
15116
+ parts: [{ type: PART_TYPES.TEXT, text: prompt }]
15117
+ }
15427
15118
  });
15428
15119
  let stablePolls = 0, lastMsgCount = 0;
15429
15120
  while (Date.now() - startTime < 10 * 60 * 1e3) {
@@ -15677,15 +15368,15 @@ var METADATA_FILE = ".cache/docs/_metadata.json";
15677
15368
  var DEFAULT_TTL_MS = 24 * 60 * 60 * 1e3;
15678
15369
 
15679
15370
  // src/core/cache/operations.ts
15680
- import * as fs3 from "node:fs/promises";
15681
- import * as path2 from "node:path";
15371
+ import * as fs4 from "node:fs/promises";
15372
+ import * as path3 from "node:path";
15682
15373
 
15683
15374
  // src/core/cache/utils.ts
15684
- import * as fs2 from "node:fs/promises";
15375
+ import * as fs3 from "node:fs/promises";
15685
15376
  import { existsSync as existsSync3 } from "node:fs";
15686
15377
  async function ensureCacheDir() {
15687
15378
  if (!existsSync3(CACHE_DIR)) {
15688
- await fs2.mkdir(CACHE_DIR, { recursive: true });
15379
+ await fs3.mkdir(CACHE_DIR, { recursive: true });
15689
15380
  }
15690
15381
  }
15691
15382
  function urlToFilename(url2) {
@@ -15700,7 +15391,7 @@ function urlToFilename(url2) {
15700
15391
  }
15701
15392
  async function readMetadata() {
15702
15393
  try {
15703
- const content = await fs2.readFile(METADATA_FILE, "utf-8");
15394
+ const content = await fs3.readFile(METADATA_FILE, "utf-8");
15704
15395
  return JSON.parse(content);
15705
15396
  } catch {
15706
15397
  return { documents: {}, lastUpdated: (/* @__PURE__ */ new Date()).toISOString() };
@@ -15709,7 +15400,7 @@ async function readMetadata() {
15709
15400
  async function writeMetadata(metadata) {
15710
15401
  await ensureCacheDir();
15711
15402
  metadata.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
15712
- await fs2.writeFile(METADATA_FILE, JSON.stringify(metadata, null, 2));
15403
+ await fs3.writeFile(METADATA_FILE, JSON.stringify(metadata, null, 2));
15713
15404
  }
15714
15405
 
15715
15406
  // src/core/cache/operations.ts
@@ -15723,8 +15414,8 @@ async function get(url2) {
15723
15414
  return null;
15724
15415
  }
15725
15416
  try {
15726
- const filepath = path2.join(CACHE_DIR, filename);
15727
- const content = await fs3.readFile(filepath, "utf-8");
15417
+ const filepath = path3.join(CACHE_DIR, filename);
15418
+ const content = await fs4.readFile(filepath, "utf-8");
15728
15419
  return { ...entry, content };
15729
15420
  } catch {
15730
15421
  return null;
@@ -15735,8 +15426,8 @@ async function getByFilename(filename) {
15735
15426
  const entry = metadata.documents[filename];
15736
15427
  if (!entry) return null;
15737
15428
  try {
15738
- const filepath = path2.join(CACHE_DIR, filename);
15739
- const content = await fs3.readFile(filepath, "utf-8");
15429
+ const filepath = path3.join(CACHE_DIR, filename);
15430
+ const content = await fs4.readFile(filepath, "utf-8");
15740
15431
  return { ...entry, content };
15741
15432
  } catch {
15742
15433
  return null;
@@ -15745,7 +15436,7 @@ async function getByFilename(filename) {
15745
15436
  async function set2(url2, content, title, ttlMs = DEFAULT_TTL_MS) {
15746
15437
  await ensureCacheDir();
15747
15438
  const filename = urlToFilename(url2);
15748
- const filepath = path2.join(CACHE_DIR, filename);
15439
+ const filepath = path3.join(CACHE_DIR, filename);
15749
15440
  const now = /* @__PURE__ */ new Date();
15750
15441
  const header = `# ${title}
15751
15442
 
@@ -15756,7 +15447,7 @@ async function set2(url2, content, title, ttlMs = DEFAULT_TTL_MS) {
15756
15447
 
15757
15448
  `;
15758
15449
  const fullContent = header + content;
15759
- await fs3.writeFile(filepath, fullContent);
15450
+ await fs4.writeFile(filepath, fullContent);
15760
15451
  const metadata = await readMetadata();
15761
15452
  metadata.documents[filename] = {
15762
15453
  url: url2,
@@ -15770,9 +15461,9 @@ async function set2(url2, content, title, ttlMs = DEFAULT_TTL_MS) {
15770
15461
  }
15771
15462
  async function remove(url2) {
15772
15463
  const filename = urlToFilename(url2);
15773
- const filepath = path2.join(CACHE_DIR, filename);
15464
+ const filepath = path3.join(CACHE_DIR, filename);
15774
15465
  try {
15775
- await fs3.unlink(filepath);
15466
+ await fs4.unlink(filepath);
15776
15467
  const metadata = await readMetadata();
15777
15468
  delete metadata.documents[filename];
15778
15469
  await writeMetadata(metadata);
@@ -15794,9 +15485,9 @@ async function clear() {
15794
15485
  const metadata = await readMetadata();
15795
15486
  const count = Object.keys(metadata.documents).length;
15796
15487
  for (const filename of Object.keys(metadata.documents)) {
15797
- const filepath = path2.join(CACHE_DIR, filename);
15488
+ const filepath = path3.join(CACHE_DIR, filename);
15798
15489
  try {
15799
- await fs3.unlink(filepath);
15490
+ await fs4.unlink(filepath);
15800
15491
  } catch {
15801
15492
  }
15802
15493
  }
@@ -16686,11 +16377,14 @@ Then output: \u2705 MISSION COMPLETE
16686
16377
  var OrchestratorPlugin = async (input) => {
16687
16378
  const { directory, client } = input;
16688
16379
  console.log(`[orchestrator] v${PLUGIN_VERSION} loaded`);
16380
+ console.log(`[orchestrator] Log file: ${getLogPath()}`);
16381
+ log2("[index.ts] Plugin initialized", { version: PLUGIN_VERSION, directory });
16689
16382
  const disableAutoToasts = enableAutoToasts();
16690
- console.log(`[orchestrator] Toast notifications enabled`);
16383
+ log2("[index.ts] Toast notifications enabled");
16691
16384
  const sessions = /* @__PURE__ */ new Map();
16692
16385
  const parallelAgentManager2 = ParallelAgentManager.getInstance(client, directory);
16693
16386
  const asyncAgentTools = createAsyncAgentTools(parallelAgentManager2, client);
16387
+ log2("[index.ts] ParallelAgentManager initialized");
16694
16388
  return {
16695
16389
  // -----------------------------------------------------------------
16696
16390
  // Tools we expose to the LLM
@@ -16729,35 +16423,85 @@ var OrchestratorPlugin = async (input) => {
16729
16423
  argumentHint: cmd.argumentHint
16730
16424
  };
16731
16425
  }
16426
+ const commanderPrompt = AGENTS[AGENT_NAMES.COMMANDER]?.systemPrompt || "";
16427
+ console.log(`[orchestrator] Commander prompt length: ${commanderPrompt.length} chars`);
16732
16428
  const orchestratorAgents = {
16429
+ // Primary agent - the main orchestrator
16733
16430
  [AGENT_NAMES.COMMANDER]: {
16734
- name: AGENT_NAMES.COMMANDER,
16735
16431
  description: "Autonomous orchestrator - executes until mission complete",
16736
16432
  mode: "primary",
16737
- prompt: AGENTS[AGENT_NAMES.COMMANDER].systemPrompt,
16433
+ prompt: commanderPrompt,
16738
16434
  maxTokens: 64e3,
16739
16435
  thinking: { type: "enabled", budgetTokens: 32e3 },
16740
16436
  color: "#FF6B6B"
16741
16437
  },
16438
+ // Subagents - invoked by Commander via Task tool
16439
+ [AGENT_NAMES.ARCHITECT]: {
16440
+ description: "Task decomposition and planning specialist",
16441
+ mode: "subagent",
16442
+ hidden: true,
16443
+ // Only invoked programmatically
16444
+ prompt: AGENTS[AGENT_NAMES.ARCHITECT]?.systemPrompt || "",
16445
+ maxTokens: 32e3,
16446
+ color: "#9B59B6"
16447
+ },
16448
+ [AGENT_NAMES.BUILDER]: {
16449
+ description: "Full-stack code implementation",
16450
+ mode: "subagent",
16451
+ hidden: true,
16452
+ prompt: AGENTS[AGENT_NAMES.BUILDER]?.systemPrompt || "",
16453
+ maxTokens: 32e3,
16454
+ color: "#E67E22"
16455
+ },
16456
+ [AGENT_NAMES.INSPECTOR]: {
16457
+ description: "Quality verification and bug fixing",
16458
+ mode: "subagent",
16459
+ hidden: true,
16460
+ prompt: AGENTS[AGENT_NAMES.INSPECTOR]?.systemPrompt || "",
16461
+ maxTokens: 32e3,
16462
+ color: "#27AE60"
16463
+ },
16464
+ [AGENT_NAMES.RECORDER]: {
16465
+ description: "Persistent progress tracking across sessions",
16466
+ mode: "subagent",
16467
+ hidden: true,
16468
+ prompt: AGENTS[AGENT_NAMES.RECORDER]?.systemPrompt || "",
16469
+ maxTokens: 16e3,
16470
+ color: "#3498DB"
16471
+ },
16742
16472
  [AGENT_NAMES.LIBRARIAN]: {
16743
- name: AGENT_NAMES.LIBRARIAN,
16744
16473
  description: "Documentation research specialist - reduces hallucination",
16745
16474
  mode: "subagent",
16475
+ hidden: true,
16746
16476
  prompt: AGENTS[AGENT_NAMES.LIBRARIAN]?.systemPrompt || "",
16747
16477
  maxTokens: 16e3,
16748
16478
  color: "#4ECDC4"
16749
16479
  },
16750
16480
  [AGENT_NAMES.RESEARCHER]: {
16751
- name: AGENT_NAMES.RESEARCHER,
16752
16481
  description: "Pre-task investigation - gathers all info before implementation",
16753
16482
  mode: "subagent",
16483
+ hidden: true,
16754
16484
  prompt: AGENTS[AGENT_NAMES.RESEARCHER]?.systemPrompt || "",
16755
16485
  maxTokens: 16e3,
16756
16486
  color: "#45B7D1"
16757
16487
  }
16758
16488
  };
16489
+ const processedExistingAgents = { ...existingAgents };
16490
+ if (processedExistingAgents.build) {
16491
+ processedExistingAgents.build = {
16492
+ ...processedExistingAgents.build,
16493
+ mode: "subagent",
16494
+ hidden: true
16495
+ };
16496
+ }
16497
+ if (processedExistingAgents.plan) {
16498
+ processedExistingAgents.plan = {
16499
+ ...processedExistingAgents.plan,
16500
+ mode: "subagent"
16501
+ };
16502
+ }
16759
16503
  config2.command = { ...existingCommands, ...orchestratorCommands };
16760
- config2.agent = { ...existingAgents, ...orchestratorAgents };
16504
+ config2.agent = { ...processedExistingAgents, ...orchestratorAgents };
16761
16505
  config2.default_agent = AGENT_NAMES.COMMANDER;
16762
16506
  console.log(`[orchestrator] Registered agents: ${Object.keys(orchestratorAgents).join(", ")}`);
16763
16507
  console.log(`[orchestrator] Default agent: ${AGENT_NAMES.COMMANDER}`);
@@ -16850,7 +16594,6 @@ Anomaly count: ${stateSession.anomalyCount}
16850
16594
  const taskIdMatch = toolInput.arguments.task.match(/\[(TASK-\d+)\]/i);
16851
16595
  if (taskIdMatch) {
16852
16596
  stateSession.currentTask = taskIdMatch[1].toUpperCase();
16853
- stateSession.graph?.updateTask(stateSession.currentTask, { status: TASK_STATUS.RUNNING });
16854
16597
  }
16855
16598
  const agentName = toolInput.arguments.agent;
16856
16599
  const emoji3 = AGENT_EMOJI[agentName] || "\u{1F916}";
@@ -16863,41 +16606,21 @@ Anomaly count: ${stateSession.anomalyCount}
16863
16606
  state.missionActive = false;
16864
16607
  return;
16865
16608
  }
16866
- if (toolOutput.output.includes("[") && toolOutput.output.includes("{") && toolInput.tool === TOOL_NAMES.CALL_AGENT && stateSession) {
16867
- const jsonMatch = toolOutput.output.match(/```json\n([\s\S]*?)\n```/) || toolOutput.output.match(/\[\s*\{[\s\S]*?\}\s*\]/);
16868
- if (jsonMatch) {
16869
- try {
16870
- const tasks = JSON.parse(jsonMatch[1] || jsonMatch[0]);
16871
- if (Array.isArray(tasks) && tasks.length > 0) {
16872
- stateSession.graph = new TaskGraph(tasks);
16873
- toolOutput.output += `
16874
-
16875
- \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
16876
- \u2705 INITIALIZED
16877
- ${stateSession.graph.getTaskSummary()}`;
16878
- }
16879
- } catch {
16880
- }
16881
- }
16882
- }
16883
- if (stateSession?.graph) {
16609
+ if (stateSession) {
16884
16610
  const taskId = stateSession.currentTask;
16885
16611
  if (toolOutput.output.includes("\u2705 PASS") || toolOutput.output.includes("AUDIT RESULT: PASS")) {
16886
16612
  if (taskId) {
16887
- stateSession.graph.updateTask(taskId, { status: TASK_STATUS.COMPLETED });
16888
16613
  stateSession.taskRetries.clear();
16889
16614
  toolOutput.output += `
16890
16615
 
16891
16616
  \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
16892
- \u2705 ${taskId} VERIFIED
16893
- ${stateSession.graph.getTaskSummary()}`;
16617
+ \u2705 ${taskId} VERIFIED`;
16894
16618
  }
16895
16619
  } else if (toolOutput.output.includes("\u274C FAIL") || toolOutput.output.includes("AUDIT RESULT: FAIL")) {
16896
16620
  if (taskId) {
16897
16621
  const retries = (stateSession.taskRetries.get(taskId) || 0) + 1;
16898
16622
  stateSession.taskRetries.set(taskId, retries);
16899
16623
  if (retries >= state.maxRetries) {
16900
- stateSession.graph.updateTask(taskId, { status: TASK_STATUS.FAILED });
16901
16624
  toolOutput.output += `
16902
16625
 
16903
16626
  \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
@@ -16910,11 +16633,6 @@ ${stateSession.graph.getTaskSummary()}`;
16910
16633
  }
16911
16634
  }
16912
16635
  }
16913
- const readyTasks = stateSession.graph.getReadyTasks();
16914
- if (readyTasks.length > 0) {
16915
- toolOutput.output += `
16916
- \u{1F449} NEXT: ${readyTasks.map((t) => `[${t.id}]`).join(", ")}`;
16917
- }
16918
16636
  }
16919
16637
  const currentTime = formatTimestamp();
16920
16638
  toolOutput.output += `