opencode-orchestrator 0.1.56 → 0.1.57

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/README.md CHANGED
@@ -20,7 +20,7 @@ A 6-agent collaborative system that turns **affordable LLMs into reliable engine
20
20
  - **PDCA Loop** — Plan → Do → Check → Act (self-correcting)
21
21
  - **Parallel DAG** — Independent tasks run concurrently
22
22
  - **Quality Gate** — Reviewer catches all errors before merge
23
-
23
+ - **Structure** — **TypeScript Brain** for logic + **Rust Muscle** for speed
24
24
  ---
25
25
 
26
26
  ## Installation
Binary file
Binary file
@@ -0,0 +1,2 @@
1
+ import { AgentDefinition } from "./types.js";
2
+ export declare const coder: AgentDefinition;
@@ -0,0 +1,2 @@
1
+ import { AgentDefinition } from "./types.js";
2
+ export declare const AGENTS: Record<string, AgentDefinition>;
@@ -0,0 +1,2 @@
1
+ import { AgentDefinition } from "./types.js";
2
+ export declare const fixer: AgentDefinition;
@@ -0,0 +1,2 @@
1
+ import { AgentDefinition } from "./types.js";
2
+ export declare const orchestrator: AgentDefinition;
@@ -0,0 +1,2 @@
1
+ import { AgentDefinition } from "./types.js";
2
+ export declare const planner: AgentDefinition;
@@ -0,0 +1,2 @@
1
+ import { AgentDefinition } from "./types.js";
2
+ export declare const reviewer: AgentDefinition;
@@ -0,0 +1,2 @@
1
+ import { AgentDefinition } from "./types.js";
2
+ export declare const searcher: AgentDefinition;
@@ -0,0 +1,7 @@
1
+ export interface AgentDefinition {
2
+ id: string;
3
+ description: string;
4
+ systemPrompt: string;
5
+ canWrite: boolean;
6
+ canBash: boolean;
7
+ }
package/dist/cli.js CHANGED
@@ -2,13 +2,17 @@
2
2
 
3
3
  // src/cli.ts
4
4
  import { spawn } from "child_process";
5
+ import { existsSync as existsSync2 } from "fs";
6
+ import { platform as platform2, arch as arch2 } from "os";
7
+
8
+ // src/utils/binary.ts
5
9
  import { join, dirname } from "path";
6
10
  import { fileURLToPath } from "url";
7
11
  import { platform, arch } from "os";
8
12
  import { existsSync } from "fs";
9
13
  var __dirname = dirname(fileURLToPath(import.meta.url));
10
14
  function getBinaryPath() {
11
- const binDir = join(__dirname, "..", "bin");
15
+ const binDir = join(__dirname, "..", "..", "bin");
12
16
  const os = platform();
13
17
  const cpu = arch();
14
18
  let binaryName;
@@ -25,10 +29,12 @@ function getBinaryPath() {
25
29
  }
26
30
  return binaryPath;
27
31
  }
32
+
33
+ // src/cli.ts
28
34
  var binary = getBinaryPath();
29
35
  var args = process.argv.slice(2);
30
- if (!existsSync(binary)) {
31
- console.error(`Error: Orchestrator binary not found for your platform (${platform()} ${arch()})`);
36
+ if (!existsSync2(binary)) {
37
+ console.error(`Error: Orchestrator binary not found for your platform (${platform2()} ${arch2()})`);
32
38
  console.error(`Expected at: ${binary}`);
33
39
  process.exit(1);
34
40
  }
@@ -0,0 +1,14 @@
1
+ import { TaskGraph } from "./tasks.js";
2
+ export interface SessionState {
3
+ enabled: boolean;
4
+ iterations: number;
5
+ taskRetries: Map<string, number>;
6
+ currentTask: string;
7
+ graph?: TaskGraph;
8
+ }
9
+ export declare const state: {
10
+ missionActive: boolean;
11
+ maxIterations: number;
12
+ maxRetries: number;
13
+ sessions: Map<string, SessionState>;
14
+ };
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Task management for DAG-based orchestration
3
+ */
4
+ export type TaskStatus = "pending" | "running" | "completed" | "failed";
5
+ export interface Task {
6
+ id: string;
7
+ description: string;
8
+ action: string;
9
+ file: string;
10
+ dependencies: string[];
11
+ status: TaskStatus;
12
+ result?: string;
13
+ retryCount: number;
14
+ complexity: number;
15
+ type: "infrastructure" | "logic" | "integration";
16
+ }
17
+ export declare class TaskGraph {
18
+ private tasks;
19
+ constructor(tasks?: Task[]);
20
+ addTask(task: Task): void;
21
+ getTask(id: string): Task | undefined;
22
+ updateTask(id: string, updates: Partial<Task>): void;
23
+ getReadyTasks(): Task[];
24
+ isCompleted(): boolean;
25
+ hasFailed(): boolean;
26
+ getTaskSummary(): string;
27
+ toJSON(): string;
28
+ static fromJSON(json: string): TaskGraph;
29
+ }
package/dist/index.js CHANGED
@@ -1,86 +1,8 @@
1
- // src/index.ts
2
- import { spawn } from "child_process";
3
- import { join, dirname } from "path";
4
- import { fileURLToPath } from "url";
5
- import { existsSync } from "fs";
6
- import { platform, arch } from "os";
7
- import { tool } from "@opencode-ai/plugin";
8
-
9
- // src/tasks.ts
10
- var TaskGraph = class _TaskGraph {
11
- tasks = /* @__PURE__ */ new Map();
12
- constructor(tasks) {
13
- if (tasks) {
14
- tasks.forEach((t) => this.addTask(t));
15
- }
16
- }
17
- addTask(task) {
18
- this.tasks.set(task.id, { ...task, status: "pending", retryCount: 0 });
19
- }
20
- getTask(id) {
21
- return this.tasks.get(id);
22
- }
23
- updateTask(id, updates) {
24
- const task = this.tasks.get(id);
25
- if (task) {
26
- this.tasks.set(id, { ...task, ...updates });
27
- }
28
- }
29
- getReadyTasks() {
30
- return Array.from(this.tasks.values()).filter((task) => {
31
- if (task.status !== "pending") return false;
32
- return task.dependencies.every((depId) => {
33
- const dep = this.tasks.get(depId);
34
- return dep && dep.status === "completed";
35
- });
36
- });
37
- }
38
- isCompleted() {
39
- return Array.from(this.tasks.values()).every((t) => t.status === "completed");
40
- }
41
- hasFailed() {
42
- return Array.from(this.tasks.values()).some((t) => t.status === "failed" && t.retryCount >= 3);
43
- }
44
- getTaskSummary() {
45
- const tasks = Array.from(this.tasks.values());
46
- const completed = tasks.filter((t) => t.status === "completed");
47
- const notCompleted = tasks.filter((t) => t.status !== "completed");
48
- let summary = "\u{1F4CB} **Mission Status**\n";
49
- if (completed.length > 0) {
50
- summary += `\u2705 Completed: ${completed.length} tasks (Hidden to save tokens)
51
- `;
52
- }
53
- for (const task of notCompleted) {
54
- const icon = task.status === "running" ? "\u23F3" : task.status === "failed" ? "\u274C" : "\u{1F4A4}";
55
- summary += `${icon} [${task.id}] ${task.description}
56
- `;
57
- }
58
- return summary;
59
- }
60
- toJSON() {
61
- return JSON.stringify(Array.from(this.tasks.values()), null, 2);
62
- }
63
- static fromJSON(json) {
64
- try {
65
- const tasks = JSON.parse(json);
66
- return new _TaskGraph(tasks);
67
- } catch (e) {
68
- console.error("Failed to parse TaskGraph JSON:", e);
69
- return new _TaskGraph();
70
- }
71
- }
72
- };
73
-
74
- // src/index.ts
75
- var __dirname = dirname(fileURLToPath(import.meta.url));
76
- var AGENTS = {
77
- // ═══════════════════════════════════════════════════════════════
78
- // ORCHESTRATOR - Team Leader & Decision Maker
79
- // ═══════════════════════════════════════════════════════════════
80
- orchestrator: {
81
- id: "orchestrator",
82
- description: "Team leader - manages the Mission and parallel work streams",
83
- systemPrompt: `You are the Orchestrator - the mission commander.
1
+ // src/agents/orchestrator.ts
2
+ var orchestrator = {
3
+ id: "orchestrator",
4
+ description: "Team leader - manages the Mission and parallel work streams",
5
+ systemPrompt: `You are the Orchestrator - the mission commander.
84
6
 
85
7
  ## Core Philosophy: Micro-Tasking & Quality Gates
86
8
  - Even small models (Phi, Gemma) succeed when tasks are tiny and verified.
@@ -88,51 +10,86 @@ var AGENTS = {
88
10
  - NEVER proceed to a task if its dependencies are not 100% VERIFIED.
89
11
 
90
12
  ## Operational SOP (Standard Operating Procedure)
91
- 1. **PHASE 0: TRADE-OFF ANALYSIS**:
92
- - **Cost vs. Value**: Is the DAG overhead justified?
93
- - **Complexity**: If task is trivial, execute linearly (1-Node DAG).
94
- - Only engage full DAG if complexity > 3 or multiple files involved.
95
- 2. **ANALYSIS PHASE (THINK FIRST)**:
96
- - Call **searcher** to read docs.
97
- ## Operational SOP
98
- 1. PHASE 0: COMPLEXITY AUDIT. Hotfix (Linear) vs System Overhaul (Flow)?
99
- 2. ANALYSIS: MapReduce data. Shard huge context.
100
- 3. CONTRACT: Define Interface Agreement (\`_interface_contract.md\`) if parallel dependencies exist.
101
- 4. PLAN: Decompose & Alloc. Assign Agents/Tools dynamically.
102
- 5. SCHEDULE: Identify ready tasks.
103
- 6. EXECUTE: search -> code -> review.
104
- 7. GLOBAL SYNC GATE: Reviewer must verify cross-task consistency against Contract.
105
- 8. **CLEANUP**: Automatically delete the temporary mission state file (*.mission.md) AND all \`temp_context_*.md\` shards upon completion.
106
-
107
- ## Verification
108
- - Ensure you are not "guessing" libraries.
109
- - If a function signature is needed for a parallel task, READ \`_interface_contract.md\`.
110
- - If no contract exists, CREATE one.
13
+
14
+ 1. **PHASE 0: INTENT GATE & CLASSIFICATION**
15
+ - **Trivial**: Single file, direct answer -> Execute linearly.
16
+ - **Complex**: Multiple modules, "Refactor", "Add feature" -> **Engage Planner**.
17
+ - **GitHub Work**: Mentions of PR/Issue -> Cycle: Investigate -> Implement -> Verify (STOP).
18
+
19
+ ### Intent Classification Table
20
+ | Type | Action |
21
+ |------|--------|
22
+ | **Trivial** | Direct tools only |
23
+ | **Explicit** | Execute directly |
24
+ | **Exploratory** | Fire searcher + tools in parallel |
25
+ | **GitHub Work** | Investigate \u2192 Implement \u2192 Verify \u2192 Report Ready |
26
+ | **Ambiguous** | Ask ONE clarifying question |
27
+
28
+ 2. **PHASE 1: RESEARCH & PLAN**
29
+ - Call **searcher** to read docs and find patterns.
30
+ - **Tool Selection**:
31
+ - \`grep\`, \`glob\`, \`lsp_*\`: Standard search.
32
+ - \`searcher\` agent: Contextual/Reference search (docs, examples).
33
+ - **MapReduce**: Shard huge context into temporary files (\`temp_context_*.md\`).
34
+
35
+ 3. **PHASE 2: EXECUTE (The Loop)**
36
+ - Execute tasks in DAG order.
37
+
38
+ ### Frontend Decision Gate (CRITICAL)
39
+ Before touching .tsx/.css files, ask: **"Is this LOOKS or WORKS?"**
40
+ - **LOOKS** (Visual/UI): Delegate to human or specialized UI agent.
41
+ - **WORKS** (Logic): Call **coder** for atomic implementation.
42
+
43
+ ### Delegation Prompt Structure (MANDATORY)
44
+ When calling subagents, your prompt MUST include:
45
+ 1. **TASK**: Atomic, specific goal
46
+ 2. **EXPECTED OUTCOME**: Concrete deliverables
47
+ 3. **REQUIRED TOOLS**: Explicit tool whitelist
48
+ 4. **MUST DO**: Exhaustive requirements
49
+ 5. **MUST NOT DO**: Forbidden actions
50
+ 6. **CONTEXT**: File paths, patterns, constraints
51
+
52
+ 4. **PHASE 3: VERIFY & FIX**
53
+ - Call **reviewer** after EVERY implementation step.
54
+ - **5-Point Check**: Syntax, Style, Logic, Integrity, Data Flow.
55
+ - **Evidence Requirements**:
56
+ - File edit: \`lsp_diagnostics\` clean
57
+ - Build/Test: Exit code 0
58
+ - If Fail: Call **fixer** (minimal changes).
59
+
60
+ 5. **PHASE 4: COMPLETION**
61
+ - Confirm all planned tasks are done.
62
+ - **Cleanup**: Delete temporary mission/shard files.
63
+ - **Final Report**: "\u2705 MISSION COMPLETE"
64
+
65
+ ## GitHub Workflow (If mentioned in PR/Issue)
66
+ 1. **Investigate**: Read issue, search codebase.
67
+ 2. **Implement**: Minimal changes, follow patterns.
68
+ 3. **Verify**: Build, Test, Check Regressions.
69
+ 4. **Report**: State "Ready for human review/PR". **DO NOT push or create PR yourself.**
70
+
71
+ ## Hard Rules (NEVER violate)
72
+ - **NO GIT PUSH**: You are NOT allowed to push code.
73
+ - **NO PR CREATION**: Do not create Pull Requests.
74
+ - **NO GIT COMMITS**: Do not commit unless explicitly asked by user.
75
+
76
+ ## Oracle Usage (Senior Advisor)
77
+ Use **searcher** (context) for most things. Use **Oracle** (high-IQ) ONLY for:
78
+ - Complex architecture design
79
+ - 2+ failed fix attempts
80
+ - Multi-system tradeoffs
81
+
82
+ ## Communication Style
83
+ - **Concise**: Start work immediately. No "I'm on it".
84
+ - **Direct**: Answer directly without preamble.
85
+ - **No Flattery**: No "Great question!".
86
+ - **Status Not Updates**: Use "Mission Status" block instead of chatty updates.
111
87
 
112
88
  ## Global Consistency Rules (Mandatory)
113
89
  - **State Persistence**: Independent nodes MUST communicate via files, not memory.
114
90
  - **Import Sync**: Any export change MUST trigger an update in all importing files.
115
- - **Signature Sync**: Function signature changes MUST be propagated to all callers in the same DAG layer.
116
- - **Type Sync**: Shared types MUST be modified in isolation before logic implementation.
117
91
  - **Atomic Integrity**: Parallel tasks MUST NOT modify the same line of code in the same file.
118
-
119
- ## Memory Management Strategy (Infinite Context Simulation)
120
- - **Sharding**: Never hold raw code in context. Write it to a file, keep the reference.
121
- - **Garbage Collection**: If a task is done, summarize its outcome ("Task A: Success, Output at /file/path") and FORGET the details.
122
- - **Value Judgment**: Do not summarize "process". Summarize "state changes".
123
-
124
- ## Safety & Boundary SOP
125
- - **Safety Gate**: Verify alignment with project core before any execution.
126
- - **Sync Sentinel**: You are responsible for cross-task logic consistency. If tasks drift, HALT and re-sync.
127
-
128
- ## Failure Recovery SOP
129
- - **Error 1-2**: Call fixer as usual.
130
- - **Error 3**: Pivot. Call searcher for similar fixes or planner to split the task further.
131
- - **Syntax Error**: Fixer MUST only fix syntax, no logic changes.
132
-
133
- ## Reliable Execution with Fixed Models
134
- - This system is optimized for fixed, low-performance models (Phi, Gemma, etc.).
135
- - Performance is achieved through granularity, not model upgrades.
92
+ - **Trust No One**: Subagents can hallucinate. Verify their outputs with tools.
136
93
 
137
94
  ## Progress Status
138
95
  Always show the Mission status at the end of your turns:
@@ -140,16 +97,15 @@ Always show the Mission status at the end of your turns:
140
97
  [TASK-001] \u2705 Completed
141
98
  [TASK-002] \u23F3 Running
142
99
  [TASK-003] \u{1F4A4} Pending`,
143
- canWrite: false,
144
- canBash: false
145
- },
146
- // ═══════════════════════════════════════════════════════════════
147
- // PLANNER - Atomic Task Decomposition
148
- // ═══════════════════════════════════════════════════════════════
149
- planner: {
150
- id: "planner",
151
- description: "Architect - decomposes work into a JSON Mission",
152
- systemPrompt: `You are the Planner - the master architect.
100
+ canWrite: false,
101
+ canBash: false
102
+ };
103
+
104
+ // src/agents/planner.ts
105
+ var planner = {
106
+ id: "planner",
107
+ description: "Architect - decomposes work into a JSON Mission",
108
+ systemPrompt: `You are the Planner - the master architect.
153
109
 
154
110
  ## Your Mission
155
111
  1. **Understand & Filter**: Read documentation, but **FILTER** out irrelevant parts. determine what is truly important.
@@ -197,16 +153,15 @@ Produce a JSON array of tasks:
197
153
  - Break circular dependencies.
198
154
  - Ensure all files are identified by absolute or relative path from project root.
199
155
  - Keep complexity < 7. If higher, split the task.`,
200
- canWrite: false,
201
- canBash: false
202
- },
203
- // ═══════════════════════════════════════════════════════════════
204
- // CODER - Single Task Implementation
205
- // ═══════════════════════════════════════════════════════════════
206
- coder: {
207
- id: "coder",
208
- description: "Implementation - executes one atomic task with complete, working code",
209
- systemPrompt: `You are the Coder - implementation specialist.
156
+ canWrite: false,
157
+ canBash: false
158
+ };
159
+
160
+ // src/agents/coder.ts
161
+ var coder = {
162
+ id: "coder",
163
+ description: "Implementation - executes one atomic task with complete, working code",
164
+ systemPrompt: `You are the Coder - implementation specialist.
210
165
 
211
166
  ## Your Job
212
167
  Execute the ONE atomic task you're given. Produce complete, working code.
@@ -253,16 +208,15 @@ Provide COMPLETE code that:
253
208
  \`\`\`
254
209
 
255
210
  Brief explanation if needed.`,
256
- canWrite: true,
257
- canBash: true
258
- },
259
- // ═══════════════════════════════════════════════════════════════
260
- // REVIEWER - Quality Gate
261
- // ═══════════════════════════════════════════════════════════════
262
- reviewer: {
263
- id: "reviewer",
264
- description: "Style Guardian & Sync Sentinel - ensures total code consistency",
265
- systemPrompt: `You are the Reviewer - the Style Guardian and Sync Sentinel.
211
+ canWrite: true,
212
+ canBash: true
213
+ };
214
+
215
+ // src/agents/reviewer.ts
216
+ var reviewer = {
217
+ id: "reviewer",
218
+ description: "Style Guardian & Sync Sentinel - ensures total code consistency",
219
+ systemPrompt: `You are the Reviewer - the Style Guardian and Sync Sentinel.
266
220
 
267
221
  ## Your Job
268
222
  1. **Task Review**: Verify individual code changes (Syntax, Style, Logic).
@@ -293,16 +247,15 @@ Brief explanation if needed.`,
293
247
  ...
294
248
  \`\`\`
295
249
  `,
296
- canWrite: false,
297
- canBash: true
298
- },
299
- // ═══════════════════════════════════════════════════════════════
300
- // FIXER - Error Resolution
301
- // ═══════════════════════════════════════════════════════════════
302
- fixer: {
303
- id: "fixer",
304
- description: "Error resolution - applies targeted fixes based on reviewer feedback",
305
- systemPrompt: `You are the Fixer - error resolution specialist.
250
+ canWrite: false,
251
+ canBash: true
252
+ };
253
+
254
+ // src/agents/fixer.ts
255
+ var fixer = {
256
+ id: "fixer",
257
+ description: "Error resolution - applies targeted fixes based on reviewer feedback",
258
+ systemPrompt: `You are the Fixer - error resolution specialist.
306
259
 
307
260
  ## Your Job
308
261
  Fix the SPECIFIC errors reported by reviewer.
@@ -349,16 +302,15 @@ You receive error reports like:
349
302
  - Ask for clarification
350
303
  - Show what you understand
351
304
  - Propose alternative fix`,
352
- canWrite: true,
353
- canBash: true
354
- },
355
- // ═══════════════════════════════════════════════════════════════
356
- // SEARCHER - Context Provider
357
- // ═══════════════════════════════════════════════════════════════
358
- searcher: {
359
- id: "searcher",
360
- description: "Context provider - finds documentation and codebase patterns",
361
- systemPrompt: `You are the Searcher - the context oracle.
305
+ canWrite: true,
306
+ canBash: true
307
+ };
308
+
309
+ // src/agents/searcher.ts
310
+ var searcher = {
311
+ id: "searcher",
312
+ description: "Context provider - finds documentation and codebase patterns",
313
+ systemPrompt: `You are the Searcher - the context oracle.
362
314
 
363
315
  ## Mission
364
316
  Your primary job is to find the **Truth** in the codebase.
@@ -384,64 +336,86 @@ OR
384
336
  ### 1. Architectural Boundaries (from docs)
385
337
  ### 2. Relevant Patterns (code snippets)
386
338
  ### 3. Recommendations`,
387
- canWrite: false,
388
- canBash: false
389
- }
339
+ canWrite: false,
340
+ canBash: false
390
341
  };
391
- function getBinaryPath() {
392
- const binDir = join(__dirname, "..", "bin");
393
- const os = platform();
394
- const cpu = arch();
395
- let binaryName;
396
- if (os === "win32") {
397
- binaryName = "orchestrator-windows-x64.exe";
398
- } else if (os === "darwin") {
399
- binaryName = cpu === "arm64" ? "orchestrator-macos-arm64" : "orchestrator-macos-x64";
400
- } else {
401
- binaryName = cpu === "arm64" ? "orchestrator-linux-arm64" : "orchestrator-linux-x64";
342
+
343
+ // src/agents/definitions.ts
344
+ var AGENTS = {
345
+ orchestrator,
346
+ planner,
347
+ coder,
348
+ reviewer,
349
+ fixer,
350
+ searcher
351
+ };
352
+
353
+ // src/core/tasks.ts
354
+ var TaskGraph = class _TaskGraph {
355
+ tasks = /* @__PURE__ */ new Map();
356
+ constructor(tasks) {
357
+ if (tasks) {
358
+ tasks.forEach((t) => this.addTask(t));
359
+ }
402
360
  }
403
- let binaryPath = join(binDir, binaryName);
404
- if (!existsSync(binaryPath)) {
405
- binaryPath = join(binDir, os === "win32" ? "orchestrator.exe" : "orchestrator");
361
+ addTask(task) {
362
+ this.tasks.set(task.id, { ...task, status: "pending", retryCount: 0 });
406
363
  }
407
- return binaryPath;
408
- }
409
- async function callRustTool(name, args) {
410
- const binary = getBinaryPath();
411
- if (!existsSync(binary)) {
412
- return JSON.stringify({ error: `Binary not found: ${binary}` });
364
+ getTask(id) {
365
+ return this.tasks.get(id);
413
366
  }
414
- return new Promise((resolve) => {
415
- const proc = spawn(binary, ["serve"], { stdio: ["pipe", "pipe", "pipe"] });
416
- let stdout = "";
417
- proc.stdout.on("data", (data) => {
418
- stdout += data.toString();
419
- });
420
- const request = JSON.stringify({
421
- jsonrpc: "2.0",
422
- id: 1,
423
- method: "tools/call",
424
- params: { name, arguments: args }
425
- });
426
- proc.stdin.write(request + "\n");
427
- proc.stdin.end();
428
- const timeout = setTimeout(() => {
429
- proc.kill();
430
- resolve(JSON.stringify({ error: "Timeout" }));
431
- }, 6e4);
432
- proc.on("close", () => {
433
- clearTimeout(timeout);
434
- try {
435
- const lines = stdout.trim().split("\n");
436
- const response = JSON.parse(lines[lines.length - 1]);
437
- const text = response?.result?.content?.[0]?.text;
438
- resolve(text || JSON.stringify(response.result));
439
- } catch {
440
- resolve(stdout || "No output");
441
- }
367
+ updateTask(id, updates) {
368
+ const task = this.tasks.get(id);
369
+ if (task) {
370
+ this.tasks.set(id, { ...task, ...updates });
371
+ }
372
+ }
373
+ getReadyTasks() {
374
+ return Array.from(this.tasks.values()).filter((task) => {
375
+ if (task.status !== "pending") return false;
376
+ return task.dependencies.every((depId) => {
377
+ const dep = this.tasks.get(depId);
378
+ return dep && dep.status === "completed";
379
+ });
442
380
  });
443
- });
444
- }
381
+ }
382
+ isCompleted() {
383
+ return Array.from(this.tasks.values()).every((t) => t.status === "completed");
384
+ }
385
+ hasFailed() {
386
+ return Array.from(this.tasks.values()).some((t) => t.status === "failed" && t.retryCount >= 3);
387
+ }
388
+ getTaskSummary() {
389
+ const tasks = Array.from(this.tasks.values());
390
+ const completed = tasks.filter((t) => t.status === "completed");
391
+ const notCompleted = tasks.filter((t) => t.status !== "completed");
392
+ let summary = "\u{1F4CB} **Mission Status**\n";
393
+ if (completed.length > 0) {
394
+ summary += `\u2705 Completed: ${completed.length} tasks (Hidden to save tokens)
395
+ `;
396
+ }
397
+ for (const task of notCompleted) {
398
+ const icon = task.status === "running" ? "\u23F3" : task.status === "failed" ? "\u274C" : "\u{1F4A4}";
399
+ summary += `${icon} [${task.id}] ${task.description}
400
+ `;
401
+ }
402
+ return summary;
403
+ }
404
+ toJSON() {
405
+ return JSON.stringify(Array.from(this.tasks.values()), null, 2);
406
+ }
407
+ static fromJSON(json) {
408
+ try {
409
+ const tasks = JSON.parse(json);
410
+ return new _TaskGraph(tasks);
411
+ } catch (e) {
412
+ console.error("Failed to parse TaskGraph JSON:", e);
413
+ return new _TaskGraph();
414
+ }
415
+ }
416
+ };
417
+
418
+ // src/core/state.ts
445
419
  var state = {
446
420
  missionActive: false,
447
421
  maxIterations: 1e3,
@@ -449,6 +423,9 @@ var state = {
449
423
  maxRetries: 3,
450
424
  sessions: /* @__PURE__ */ new Map()
451
425
  };
426
+
427
+ // src/tools/callAgent.ts
428
+ import { tool } from "@opencode-ai/plugin";
452
429
  var callAgentTool = tool({
453
430
  description: `Call a team member to perform specific work.
454
431
 
@@ -503,6 +480,9 @@ Execute according to your role. Be thorough and precise.
503
480
  return prompt;
504
481
  }
505
482
  });
483
+
484
+ // src/tools/slashCommand.ts
485
+ import { tool as tool2 } from "@opencode-ai/plugin";
506
486
  var COMMANDS = {
507
487
  "task": {
508
488
  description: "Execute a mission using Distributed Cognitive Architecture (PDCA Cycle)",
@@ -611,12 +591,12 @@ function createSlashcommandTool() {
611
591
  const hint = cmd.argumentHint ? ` ${cmd.argumentHint}` : "";
612
592
  return `- /${name}${hint}: ${cmd.description}`;
613
593
  }).join("\n");
614
- return tool({
594
+ return tool2({
615
595
  description: `Commands
616
596
 
617
597
  ${commandList}`,
618
598
  args: {
619
- command: tool.schema.string().describe("Command (without slash)")
599
+ command: tool2.schema.string().describe("Command (without slash)")
620
600
  },
621
601
  async execute(args) {
622
602
  const cmdName = (args.command || "").replace(/^\//, "").split(/\s+/)[0].toLowerCase();
@@ -631,11 +611,83 @@ ${commandList}`;
631
611
  }
632
612
  });
633
613
  }
634
- var grepSearchTool = (directory) => tool({
614
+
615
+ // src/tools/search.ts
616
+ import { tool as tool3 } from "@opencode-ai/plugin";
617
+
618
+ // src/tools/rust.ts
619
+ import { spawn } from "child_process";
620
+ import { existsSync as existsSync2 } from "fs";
621
+
622
+ // src/utils/binary.ts
623
+ import { join, dirname } from "path";
624
+ import { fileURLToPath } from "url";
625
+ import { platform, arch } from "os";
626
+ import { existsSync } from "fs";
627
+ var __dirname = dirname(fileURLToPath(import.meta.url));
628
+ function getBinaryPath() {
629
+ const binDir = join(__dirname, "..", "..", "bin");
630
+ const os = platform();
631
+ const cpu = arch();
632
+ let binaryName;
633
+ if (os === "win32") {
634
+ binaryName = "orchestrator-windows-x64.exe";
635
+ } else if (os === "darwin") {
636
+ binaryName = cpu === "arm64" ? "orchestrator-macos-arm64" : "orchestrator-macos-x64";
637
+ } else {
638
+ binaryName = cpu === "arm64" ? "orchestrator-linux-arm64" : "orchestrator-linux-x64";
639
+ }
640
+ let binaryPath = join(binDir, binaryName);
641
+ if (!existsSync(binaryPath)) {
642
+ binaryPath = join(binDir, os === "win32" ? "orchestrator.exe" : "orchestrator");
643
+ }
644
+ return binaryPath;
645
+ }
646
+
647
+ // src/tools/rust.ts
648
+ async function callRustTool(name, args) {
649
+ const binary = getBinaryPath();
650
+ if (!existsSync2(binary)) {
651
+ return JSON.stringify({ error: `Binary not found: ${binary}` });
652
+ }
653
+ return new Promise((resolve) => {
654
+ const proc = spawn(binary, ["serve"], { stdio: ["pipe", "pipe", "pipe"] });
655
+ let stdout = "";
656
+ proc.stdout.on("data", (data) => {
657
+ stdout += data.toString();
658
+ });
659
+ const request = JSON.stringify({
660
+ jsonrpc: "2.0",
661
+ id: 1,
662
+ method: "tools/call",
663
+ params: { name, arguments: args }
664
+ });
665
+ proc.stdin.write(request + "\n");
666
+ proc.stdin.end();
667
+ const timeout = setTimeout(() => {
668
+ proc.kill();
669
+ resolve(JSON.stringify({ error: "Timeout" }));
670
+ }, 6e4);
671
+ proc.on("close", () => {
672
+ clearTimeout(timeout);
673
+ try {
674
+ const lines = stdout.trim().split("\n");
675
+ const response = JSON.parse(lines[lines.length - 1]);
676
+ const text = response?.result?.content?.[0]?.text;
677
+ resolve(text || JSON.stringify(response.result));
678
+ } catch {
679
+ resolve(stdout || "No output");
680
+ }
681
+ });
682
+ });
683
+ }
684
+
685
+ // src/tools/search.ts
686
+ var grepSearchTool = (directory) => tool3({
635
687
  description: "Search code patterns",
636
688
  args: {
637
- pattern: tool.schema.string().describe("Regex pattern"),
638
- dir: tool.schema.string().optional().describe("Directory")
689
+ pattern: tool3.schema.string().describe("Regex pattern"),
690
+ dir: tool3.schema.string().optional().describe("Directory")
639
691
  },
640
692
  async execute(args) {
641
693
  return callRustTool("grep_search", {
@@ -644,11 +696,11 @@ var grepSearchTool = (directory) => tool({
644
696
  });
645
697
  }
646
698
  });
647
- var globSearchTool = (directory) => tool({
699
+ var globSearchTool = (directory) => tool3({
648
700
  description: "Find files by pattern",
649
701
  args: {
650
- pattern: tool.schema.string().describe("Glob pattern"),
651
- dir: tool.schema.string().optional().describe("Directory")
702
+ pattern: tool3.schema.string().describe("Glob pattern"),
703
+ dir: tool3.schema.string().optional().describe("Directory")
652
704
  },
653
705
  async execute(args) {
654
706
  return callRustTool("glob_search", {
@@ -657,11 +709,15 @@ var globSearchTool = (directory) => tool({
657
709
  });
658
710
  }
659
711
  });
712
+
713
+ // src/utils/common.ts
660
714
  function detectSlashCommand(text) {
661
715
  const match = text.trim().match(/^\/([a-zA-Z0-9_-]+)(?:\s+(.*))?$/);
662
716
  if (!match) return null;
663
717
  return { command: match[1], args: match[2] || "" };
664
718
  }
719
+
720
+ // src/index.ts
665
721
  var OrchestratorPlugin = async (input) => {
666
722
  const { directory } = input;
667
723
  return {
@@ -749,12 +805,8 @@ var OrchestratorPlugin = async (input) => {
749
805
  }
750
806
  }
751
807
  if (session.iterations >= state.maxIterations) {
808
+ state.missionActive = false;
752
809
  session.enabled = false;
753
- output.output += `
754
-
755
- \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
756
- \u26A0\uFE0F ITERATION LIMIT (${state.maxIterations})
757
- Review progress and continue manually.`;
758
810
  return;
759
811
  }
760
812
  if (output.output.includes("[") && output.output.includes("]") && output.output.includes("{") && input2.tool === "call_agent") {
@@ -0,0 +1,19 @@
1
+ export declare const callAgentTool: {
2
+ description: string;
3
+ args: {
4
+ agent: import("zod").ZodEnum<{
5
+ planner: "planner";
6
+ coder: "coder";
7
+ reviewer: "reviewer";
8
+ fixer: "fixer";
9
+ searcher: "searcher";
10
+ }>;
11
+ task: import("zod").ZodString;
12
+ context: import("zod").ZodOptional<import("zod").ZodString>;
13
+ };
14
+ execute(args: {
15
+ agent: "planner" | "coder" | "reviewer" | "fixer" | "searcher";
16
+ task: string;
17
+ context?: string | undefined;
18
+ }, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
19
+ };
@@ -0,0 +1 @@
1
+ export declare function callRustTool(name: string, args: Record<string, unknown>): Promise<string>;
@@ -0,0 +1,22 @@
1
+ export declare const grepSearchTool: (directory: string) => {
2
+ description: string;
3
+ args: {
4
+ pattern: import("zod").ZodString;
5
+ dir: import("zod").ZodOptional<import("zod").ZodString>;
6
+ };
7
+ execute(args: {
8
+ pattern: string;
9
+ dir?: string | undefined;
10
+ }, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
11
+ };
12
+ export declare const globSearchTool: (directory: string) => {
13
+ description: string;
14
+ args: {
15
+ pattern: import("zod").ZodString;
16
+ dir: import("zod").ZodOptional<import("zod").ZodString>;
17
+ };
18
+ execute(args: {
19
+ pattern: string;
20
+ dir?: string | undefined;
21
+ }, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
22
+ };
@@ -0,0 +1,14 @@
1
+ export declare const COMMANDS: Record<string, {
2
+ description: string;
3
+ template: string;
4
+ argumentHint?: string;
5
+ }>;
6
+ export declare function createSlashcommandTool(): {
7
+ description: string;
8
+ args: {
9
+ command: import("zod").ZodString;
10
+ };
11
+ execute(args: {
12
+ command: string;
13
+ }, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
14
+ };
@@ -0,0 +1 @@
1
+ export declare function getBinaryPath(): string;
@@ -0,0 +1,4 @@
1
+ export declare function detectSlashCommand(text: string): {
2
+ command: string;
3
+ args: string;
4
+ } | null;
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "opencode-orchestrator",
3
3
  "displayName": "OpenCode Orchestrator",
4
4
  "description": "Distributed Cognitive Architecture for OpenCode. Turns simple prompts into specialized multi-agent workflows (Planner, Coder, Reviewer).",
5
- "version": "0.1.56",
5
+ "version": "0.1.57",
6
6
  "author": "agnusdei1207",
7
7
  "license": "MIT",
8
8
  "repository": {