opencode-orchestrator 0.1.56 → 0.1.59
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 +1 -1
- package/bin/orchestrator-linux-arm64 +0 -0
- package/bin/orchestrator-linux-x64 +0 -0
- package/dist/agents/coder.d.ts +2 -0
- package/dist/agents/definitions.d.ts +2 -0
- package/dist/agents/fixer.d.ts +2 -0
- package/dist/agents/orchestrator.d.ts +2 -0
- package/dist/agents/planner.d.ts +2 -0
- package/dist/agents/reviewer.d.ts +2 -0
- package/dist/agents/searcher.d.ts +2 -0
- package/dist/agents/types.d.ts +7 -0
- package/dist/cli.js +9 -3
- package/dist/core/state.d.ts +14 -0
- package/dist/core/tasks.d.ts +29 -0
- package/dist/index.js +294 -245
- package/dist/tools/callAgent.d.ts +19 -0
- package/dist/tools/rust.d.ts +1 -0
- package/dist/tools/search.d.ts +22 -0
- package/dist/tools/slashCommand.d.ts +14 -0
- package/dist/utils/binary.d.ts +1 -0
- package/dist/utils/common.d.ts +4 -0
- package/package.json +1 -1
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
|
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 (!
|
|
31
|
-
console.error(`Error: Orchestrator binary not found for your platform (${
|
|
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/
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
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,68 +10,99 @@ 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
|
-
|
|
92
|
-
|
|
93
|
-
- **
|
|
94
|
-
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
-
|
|
109
|
-
-
|
|
110
|
-
-
|
|
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, find patterns, and search external references.
|
|
30
|
+
- **Tool Selection**:
|
|
31
|
+
- \`grep\`, \`glob\`, \`lsp_*\`: Standard search.
|
|
32
|
+
- \`searcher\` agent: Contextual search & External Docs.
|
|
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): **STOP**. Ask user for confirmation or specific design specs before calling Coder.
|
|
41
|
+
- **WORKS** (Logic): Call **coder** for atomic implementation.
|
|
42
|
+
|
|
43
|
+
### Delegation Prompt Structure (MANDATORY)
|
|
44
|
+
When calling subagents (Coder, Searcher, Planner, Reviewer, Fixer), 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**: "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
|
+
- **NO HALLUCINATED AGENTS**: Only use [Orchestrator, Planner, Coder, Reviewer, Fixer, Searcher].
|
|
76
|
+
|
|
77
|
+
## Communication Style
|
|
78
|
+
- **Concise**: Start work immediately. No "I'm on it".
|
|
79
|
+
- **Direct**: Answer directly without preamble.
|
|
80
|
+
- **No Flattery**: No "Great question!".
|
|
81
|
+
- **Status Not Updates**: Use "Mission Status" block instead of chatty updates.
|
|
82
|
+
|
|
83
|
+
|
|
111
84
|
|
|
112
85
|
## Global Consistency Rules (Mandatory)
|
|
113
86
|
- **State Persistence**: Independent nodes MUST communicate via files, not memory.
|
|
114
87
|
- **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
88
|
- **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.
|
|
89
|
+
- **Trust No One**: Subagents can hallucinate. Verify their outputs with tools.
|
|
136
90
|
|
|
137
91
|
## Progress Status
|
|
138
92
|
Always show the Mission status at the end of your turns:
|
|
139
|
-
|
|
140
|
-
[TASK-001]
|
|
141
|
-
[TASK-002]
|
|
142
|
-
[TASK-003]
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
systemPrompt: `You are the Planner - the master architect.
|
|
93
|
+
Mission Status:
|
|
94
|
+
[TASK-001] Completed
|
|
95
|
+
[TASK-002] Running
|
|
96
|
+
[TASK-003] Pending`,
|
|
97
|
+
canWrite: false,
|
|
98
|
+
canBash: false
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
// src/agents/planner.ts
|
|
102
|
+
var planner = {
|
|
103
|
+
id: "planner",
|
|
104
|
+
description: "Architect - decomposes work into a JSON Mission",
|
|
105
|
+
systemPrompt: `You are the Planner - the master architect.
|
|
153
106
|
|
|
154
107
|
## Your Mission
|
|
155
108
|
1. **Understand & Filter**: Read documentation, but **FILTER** out irrelevant parts. determine what is truly important.
|
|
@@ -197,16 +150,15 @@ Produce a JSON array of tasks:
|
|
|
197
150
|
- Break circular dependencies.
|
|
198
151
|
- Ensure all files are identified by absolute or relative path from project root.
|
|
199
152
|
- Keep complexity < 7. If higher, split the task.`,
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
systemPrompt: `You are the Coder - implementation specialist.
|
|
153
|
+
canWrite: false,
|
|
154
|
+
canBash: false
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
// src/agents/coder.ts
|
|
158
|
+
var coder = {
|
|
159
|
+
id: "coder",
|
|
160
|
+
description: "Implementation - executes one atomic task with complete, working code",
|
|
161
|
+
systemPrompt: `You are the Coder - implementation specialist.
|
|
210
162
|
|
|
211
163
|
## Your Job
|
|
212
164
|
Execute the ONE atomic task you're given. Produce complete, working code.
|
|
@@ -253,16 +205,15 @@ Provide COMPLETE code that:
|
|
|
253
205
|
\`\`\`
|
|
254
206
|
|
|
255
207
|
Brief explanation if needed.`,
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
systemPrompt: `You are the Reviewer - the Style Guardian and Sync Sentinel.
|
|
208
|
+
canWrite: true,
|
|
209
|
+
canBash: true
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
// src/agents/reviewer.ts
|
|
213
|
+
var reviewer = {
|
|
214
|
+
id: "reviewer",
|
|
215
|
+
description: "Style Guardian & Sync Sentinel - ensures total code consistency",
|
|
216
|
+
systemPrompt: `You are the Reviewer - the Style Guardian and Sync Sentinel.
|
|
266
217
|
|
|
267
218
|
## Your Job
|
|
268
219
|
1. **Task Review**: Verify individual code changes (Syntax, Style, Logic).
|
|
@@ -282,27 +233,26 @@ Brief explanation if needed.`,
|
|
|
282
233
|
## Review Results (MANDATORY Format)
|
|
283
234
|
### If PASS:
|
|
284
235
|
\`\`\`
|
|
285
|
-
|
|
236
|
+
PASS (Confidence: 100%)
|
|
286
237
|
- All individual checks passed.
|
|
287
238
|
- Global Sync Check: NO drift detected.
|
|
288
239
|
\`\`\`
|
|
289
240
|
|
|
290
241
|
### If FAIL:
|
|
291
242
|
\`\`\`
|
|
292
|
-
|
|
243
|
+
FAIL [SYNC-ERROR | STYLE | LOGIC]
|
|
293
244
|
...
|
|
294
245
|
\`\`\`
|
|
295
246
|
`,
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
systemPrompt: `You are the Fixer - error resolution specialist.
|
|
247
|
+
canWrite: false,
|
|
248
|
+
canBash: true
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
// src/agents/fixer.ts
|
|
252
|
+
var fixer = {
|
|
253
|
+
id: "fixer",
|
|
254
|
+
description: "Error resolution - applies targeted fixes based on reviewer feedback",
|
|
255
|
+
systemPrompt: `You are the Fixer - error resolution specialist.
|
|
306
256
|
|
|
307
257
|
## Your Job
|
|
308
258
|
Fix the SPECIFIC errors reported by reviewer.
|
|
@@ -349,16 +299,15 @@ You receive error reports like:
|
|
|
349
299
|
- Ask for clarification
|
|
350
300
|
- Show what you understand
|
|
351
301
|
- Propose alternative fix`,
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
systemPrompt: `You are the Searcher - the context oracle.
|
|
302
|
+
canWrite: true,
|
|
303
|
+
canBash: true
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
// src/agents/searcher.ts
|
|
307
|
+
var searcher = {
|
|
308
|
+
id: "searcher",
|
|
309
|
+
description: "Context provider - finds documentation and codebase patterns",
|
|
310
|
+
systemPrompt: `You are the Searcher - the context oracle.
|
|
362
311
|
|
|
363
312
|
## Mission
|
|
364
313
|
Your primary job is to find the **Truth** in the codebase.
|
|
@@ -384,64 +333,86 @@ OR
|
|
|
384
333
|
### 1. Architectural Boundaries (from docs)
|
|
385
334
|
### 2. Relevant Patterns (code snippets)
|
|
386
335
|
### 3. Recommendations`,
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
}
|
|
336
|
+
canWrite: false,
|
|
337
|
+
canBash: false
|
|
390
338
|
};
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
339
|
+
|
|
340
|
+
// src/agents/definitions.ts
|
|
341
|
+
var AGENTS = {
|
|
342
|
+
orchestrator,
|
|
343
|
+
planner,
|
|
344
|
+
coder,
|
|
345
|
+
reviewer,
|
|
346
|
+
fixer,
|
|
347
|
+
searcher
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
// src/core/tasks.ts
|
|
351
|
+
var TaskGraph = class _TaskGraph {
|
|
352
|
+
tasks = /* @__PURE__ */ new Map();
|
|
353
|
+
constructor(tasks) {
|
|
354
|
+
if (tasks) {
|
|
355
|
+
tasks.forEach((t) => this.addTask(t));
|
|
356
|
+
}
|
|
402
357
|
}
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
binaryPath = join(binDir, os === "win32" ? "orchestrator.exe" : "orchestrator");
|
|
358
|
+
addTask(task) {
|
|
359
|
+
this.tasks.set(task.id, { ...task, status: "pending", retryCount: 0 });
|
|
406
360
|
}
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
async function callRustTool(name, args) {
|
|
410
|
-
const binary = getBinaryPath();
|
|
411
|
-
if (!existsSync(binary)) {
|
|
412
|
-
return JSON.stringify({ error: `Binary not found: ${binary}` });
|
|
361
|
+
getTask(id) {
|
|
362
|
+
return this.tasks.get(id);
|
|
413
363
|
}
|
|
414
|
-
|
|
415
|
-
const
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
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
|
-
}
|
|
364
|
+
updateTask(id, updates) {
|
|
365
|
+
const task = this.tasks.get(id);
|
|
366
|
+
if (task) {
|
|
367
|
+
this.tasks.set(id, { ...task, ...updates });
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
getReadyTasks() {
|
|
371
|
+
return Array.from(this.tasks.values()).filter((task) => {
|
|
372
|
+
if (task.status !== "pending") return false;
|
|
373
|
+
return task.dependencies.every((depId) => {
|
|
374
|
+
const dep = this.tasks.get(depId);
|
|
375
|
+
return dep && dep.status === "completed";
|
|
376
|
+
});
|
|
442
377
|
});
|
|
443
|
-
}
|
|
444
|
-
|
|
378
|
+
}
|
|
379
|
+
isCompleted() {
|
|
380
|
+
return Array.from(this.tasks.values()).every((t) => t.status === "completed");
|
|
381
|
+
}
|
|
382
|
+
hasFailed() {
|
|
383
|
+
return Array.from(this.tasks.values()).some((t) => t.status === "failed" && t.retryCount >= 3);
|
|
384
|
+
}
|
|
385
|
+
getTaskSummary() {
|
|
386
|
+
const tasks = Array.from(this.tasks.values());
|
|
387
|
+
const completed = tasks.filter((t) => t.status === "completed");
|
|
388
|
+
const notCompleted = tasks.filter((t) => t.status !== "completed");
|
|
389
|
+
let summary = "\u{1F4CB} **Mission Status**\n";
|
|
390
|
+
if (completed.length > 0) {
|
|
391
|
+
summary += `\u2705 Completed: ${completed.length} tasks (Hidden to save tokens)
|
|
392
|
+
`;
|
|
393
|
+
}
|
|
394
|
+
for (const task of notCompleted) {
|
|
395
|
+
const icon = task.status === "running" ? "\u23F3" : task.status === "failed" ? "\u274C" : "\u{1F4A4}";
|
|
396
|
+
summary += `${icon} [${task.id}] ${task.description}
|
|
397
|
+
`;
|
|
398
|
+
}
|
|
399
|
+
return summary;
|
|
400
|
+
}
|
|
401
|
+
toJSON() {
|
|
402
|
+
return JSON.stringify(Array.from(this.tasks.values()), null, 2);
|
|
403
|
+
}
|
|
404
|
+
static fromJSON(json) {
|
|
405
|
+
try {
|
|
406
|
+
const tasks = JSON.parse(json);
|
|
407
|
+
return new _TaskGraph(tasks);
|
|
408
|
+
} catch (e) {
|
|
409
|
+
console.error("Failed to parse TaskGraph JSON:", e);
|
|
410
|
+
return new _TaskGraph();
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
};
|
|
414
|
+
|
|
415
|
+
// src/core/state.ts
|
|
445
416
|
var state = {
|
|
446
417
|
missionActive: false,
|
|
447
418
|
maxIterations: 1e3,
|
|
@@ -449,6 +420,9 @@ var state = {
|
|
|
449
420
|
maxRetries: 3,
|
|
450
421
|
sessions: /* @__PURE__ */ new Map()
|
|
451
422
|
};
|
|
423
|
+
|
|
424
|
+
// src/tools/callAgent.ts
|
|
425
|
+
import { tool } from "@opencode-ai/plugin";
|
|
452
426
|
var callAgentTool = tool({
|
|
453
427
|
description: `Call a team member to perform specific work.
|
|
454
428
|
|
|
@@ -503,6 +477,9 @@ Execute according to your role. Be thorough and precise.
|
|
|
503
477
|
return prompt;
|
|
504
478
|
}
|
|
505
479
|
});
|
|
480
|
+
|
|
481
|
+
// src/tools/slashCommand.ts
|
|
482
|
+
import { tool as tool2 } from "@opencode-ai/plugin";
|
|
506
483
|
var COMMANDS = {
|
|
507
484
|
"task": {
|
|
508
485
|
description: "Execute a mission using Distributed Cognitive Architecture (PDCA Cycle)",
|
|
@@ -611,12 +588,12 @@ function createSlashcommandTool() {
|
|
|
611
588
|
const hint = cmd.argumentHint ? ` ${cmd.argumentHint}` : "";
|
|
612
589
|
return `- /${name}${hint}: ${cmd.description}`;
|
|
613
590
|
}).join("\n");
|
|
614
|
-
return
|
|
591
|
+
return tool2({
|
|
615
592
|
description: `Commands
|
|
616
593
|
|
|
617
594
|
${commandList}`,
|
|
618
595
|
args: {
|
|
619
|
-
command:
|
|
596
|
+
command: tool2.schema.string().describe("Command (without slash)")
|
|
620
597
|
},
|
|
621
598
|
async execute(args) {
|
|
622
599
|
const cmdName = (args.command || "").replace(/^\//, "").split(/\s+/)[0].toLowerCase();
|
|
@@ -631,11 +608,83 @@ ${commandList}`;
|
|
|
631
608
|
}
|
|
632
609
|
});
|
|
633
610
|
}
|
|
634
|
-
|
|
611
|
+
|
|
612
|
+
// src/tools/search.ts
|
|
613
|
+
import { tool as tool3 } from "@opencode-ai/plugin";
|
|
614
|
+
|
|
615
|
+
// src/tools/rust.ts
|
|
616
|
+
import { spawn } from "child_process";
|
|
617
|
+
import { existsSync as existsSync2 } from "fs";
|
|
618
|
+
|
|
619
|
+
// src/utils/binary.ts
|
|
620
|
+
import { join, dirname } from "path";
|
|
621
|
+
import { fileURLToPath } from "url";
|
|
622
|
+
import { platform, arch } from "os";
|
|
623
|
+
import { existsSync } from "fs";
|
|
624
|
+
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
625
|
+
function getBinaryPath() {
|
|
626
|
+
const binDir = join(__dirname, "..", "..", "bin");
|
|
627
|
+
const os = platform();
|
|
628
|
+
const cpu = arch();
|
|
629
|
+
let binaryName;
|
|
630
|
+
if (os === "win32") {
|
|
631
|
+
binaryName = "orchestrator-windows-x64.exe";
|
|
632
|
+
} else if (os === "darwin") {
|
|
633
|
+
binaryName = cpu === "arm64" ? "orchestrator-macos-arm64" : "orchestrator-macos-x64";
|
|
634
|
+
} else {
|
|
635
|
+
binaryName = cpu === "arm64" ? "orchestrator-linux-arm64" : "orchestrator-linux-x64";
|
|
636
|
+
}
|
|
637
|
+
let binaryPath = join(binDir, binaryName);
|
|
638
|
+
if (!existsSync(binaryPath)) {
|
|
639
|
+
binaryPath = join(binDir, os === "win32" ? "orchestrator.exe" : "orchestrator");
|
|
640
|
+
}
|
|
641
|
+
return binaryPath;
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
// src/tools/rust.ts
|
|
645
|
+
async function callRustTool(name, args) {
|
|
646
|
+
const binary = getBinaryPath();
|
|
647
|
+
if (!existsSync2(binary)) {
|
|
648
|
+
return JSON.stringify({ error: `Binary not found: ${binary}` });
|
|
649
|
+
}
|
|
650
|
+
return new Promise((resolve) => {
|
|
651
|
+
const proc = spawn(binary, ["serve"], { stdio: ["pipe", "pipe", "pipe"] });
|
|
652
|
+
let stdout = "";
|
|
653
|
+
proc.stdout.on("data", (data) => {
|
|
654
|
+
stdout += data.toString();
|
|
655
|
+
});
|
|
656
|
+
const request = JSON.stringify({
|
|
657
|
+
jsonrpc: "2.0",
|
|
658
|
+
id: 1,
|
|
659
|
+
method: "tools/call",
|
|
660
|
+
params: { name, arguments: args }
|
|
661
|
+
});
|
|
662
|
+
proc.stdin.write(request + "\n");
|
|
663
|
+
proc.stdin.end();
|
|
664
|
+
const timeout = setTimeout(() => {
|
|
665
|
+
proc.kill();
|
|
666
|
+
resolve(JSON.stringify({ error: "Timeout" }));
|
|
667
|
+
}, 6e4);
|
|
668
|
+
proc.on("close", () => {
|
|
669
|
+
clearTimeout(timeout);
|
|
670
|
+
try {
|
|
671
|
+
const lines = stdout.trim().split("\n");
|
|
672
|
+
const response = JSON.parse(lines[lines.length - 1]);
|
|
673
|
+
const text = response?.result?.content?.[0]?.text;
|
|
674
|
+
resolve(text || JSON.stringify(response.result));
|
|
675
|
+
} catch {
|
|
676
|
+
resolve(stdout || "No output");
|
|
677
|
+
}
|
|
678
|
+
});
|
|
679
|
+
});
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
// src/tools/search.ts
|
|
683
|
+
var grepSearchTool = (directory) => tool3({
|
|
635
684
|
description: "Search code patterns",
|
|
636
685
|
args: {
|
|
637
|
-
pattern:
|
|
638
|
-
dir:
|
|
686
|
+
pattern: tool3.schema.string().describe("Regex pattern"),
|
|
687
|
+
dir: tool3.schema.string().optional().describe("Directory")
|
|
639
688
|
},
|
|
640
689
|
async execute(args) {
|
|
641
690
|
return callRustTool("grep_search", {
|
|
@@ -644,11 +693,11 @@ var grepSearchTool = (directory) => tool({
|
|
|
644
693
|
});
|
|
645
694
|
}
|
|
646
695
|
});
|
|
647
|
-
var globSearchTool = (directory) =>
|
|
696
|
+
var globSearchTool = (directory) => tool3({
|
|
648
697
|
description: "Find files by pattern",
|
|
649
698
|
args: {
|
|
650
|
-
pattern:
|
|
651
|
-
dir:
|
|
699
|
+
pattern: tool3.schema.string().describe("Glob pattern"),
|
|
700
|
+
dir: tool3.schema.string().optional().describe("Directory")
|
|
652
701
|
},
|
|
653
702
|
async execute(args) {
|
|
654
703
|
return callRustTool("glob_search", {
|
|
@@ -657,11 +706,15 @@ var globSearchTool = (directory) => tool({
|
|
|
657
706
|
});
|
|
658
707
|
}
|
|
659
708
|
});
|
|
709
|
+
|
|
710
|
+
// src/utils/common.ts
|
|
660
711
|
function detectSlashCommand(text) {
|
|
661
712
|
const match = text.trim().match(/^\/([a-zA-Z0-9_-]+)(?:\s+(.*))?$/);
|
|
662
713
|
if (!match) return null;
|
|
663
714
|
return { command: match[1], args: match[2] || "" };
|
|
664
715
|
}
|
|
716
|
+
|
|
717
|
+
// src/index.ts
|
|
665
718
|
var OrchestratorPlugin = async (input) => {
|
|
666
719
|
const { directory } = input;
|
|
667
720
|
return {
|
|
@@ -749,12 +802,8 @@ var OrchestratorPlugin = async (input) => {
|
|
|
749
802
|
}
|
|
750
803
|
}
|
|
751
804
|
if (session.iterations >= state.maxIterations) {
|
|
805
|
+
state.missionActive = false;
|
|
752
806
|
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
807
|
return;
|
|
759
808
|
}
|
|
760
809
|
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;
|
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.
|
|
5
|
+
"version": "0.1.59",
|
|
6
6
|
"author": "agnusdei1207",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"repository": {
|