opencode-orchestrator 0.9.6 → 0.9.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +98 -97
- package/dist/index.js +41 -20
- package/dist/shared/message/constants/index.d.ts +2 -0
- package/dist/shared/message/constants/message-roles.d.ts +23 -0
- package/dist/shared/message/constants/part-types.d.ts +4 -0
- package/dist/shared/message/constants/plugin-hooks.d.ts +15 -0
- package/dist/shared/session/constants/index.d.ts +2 -2
- package/dist/shared/session/constants/session-events.d.ts +7 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
# OpenCode Orchestrator
|
|
6
6
|
|
|
7
|
-
>
|
|
7
|
+
> **🚀 Multi-Agent Orchestration Plugin for [OpenCode](https://opencode.ai)**
|
|
8
8
|
|
|
9
9
|
[](LICENSE)
|
|
10
10
|
[](https://www.npmjs.com/package/opencode-orchestrator)
|
|
@@ -12,112 +12,120 @@
|
|
|
12
12
|
|
|
13
13
|
---
|
|
14
14
|
|
|
15
|
+
## 🔥 Why This Plugin?
|
|
16
|
+
|
|
17
|
+
**Budget models have limits. Orchestration breaks them.**
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
15
21
|
## ⚡ Quick Start
|
|
16
22
|
|
|
17
23
|
```bash
|
|
18
24
|
npm install -g opencode-orchestrator
|
|
19
25
|
```
|
|
20
26
|
|
|
21
|
-
|
|
27
|
+
Then in OpenCode:
|
|
22
28
|
|
|
23
29
|
```bash
|
|
24
30
|
/task "Build a REST API with authentication"
|
|
25
31
|
```
|
|
26
32
|
|
|
27
|
-
|
|
33
|
+
**Done.** You just deployed an army of AI agents. They plan, build, test, fix — and don't stop until it's sealed. ✨
|
|
28
34
|
|
|
29
35
|
---
|
|
30
36
|
|
|
31
|
-
##
|
|
32
|
-
|
|
33
|
-
Budget models have limits. Orchestration breaks them.
|
|
34
|
-
|
|
35
|
-
---
|
|
37
|
+
## 🎯 What Makes This Different?
|
|
36
38
|
|
|
37
|
-
|
|
39
|
+
### 🚀 Core Capabilities
|
|
38
40
|
|
|
39
|
-
|
|
41
|
+
| | Feature | What It Means |
|
|
42
|
+
|:---:|:---|:---|
|
|
43
|
+
| ⚡ | **Multi-Session Parallel** | 50 isolated sessions running simultaneously. True multi-threading. |
|
|
44
|
+
| 🔥 | **Parallel Execution** | Workers build different files at once. 10x faster. |
|
|
45
|
+
| � | **Non-Blocking Async** | Fire-and-forget. Commander never waits. Results collected automatically. |
|
|
46
|
+
| 🧩 | **Smart Distribution** | One file = one worker. No conflicts. No stepping on each other. |
|
|
47
|
+
| 🔗 | **Real-Time Sync** | Shared `.opencode/` state. All agents see updates instantly. |
|
|
48
|
+
| 🛡️ | **Auto Verify & Test** | E2E tests, import checks, integration validation. Bugs get caught. |
|
|
49
|
+
| 🩹 | **Self-Healing** | Auto-recovery from crashes, rate limits, context overflow. 3 retries. |
|
|
50
|
+
| � | **Live Monitoring** | Track sessions, progress, queues. Toast notifications in real-time. |
|
|
40
51
|
|
|
41
52
|
---
|
|
42
53
|
|
|
43
|
-
## ✨ v0.9.4 Highlights
|
|
44
54
|
|
|
45
|
-
|
|
55
|
+
## 🏛️ How It Works
|
|
46
56
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
57
|
+
```
|
|
58
|
+
YOU
|
|
59
|
+
│
|
|
60
|
+
│ /task "Build REST API"
|
|
61
|
+
▼
|
|
62
|
+
╔══════════════════════════════════════════════════════════╗
|
|
63
|
+
║ 🎯 COMMANDER ║
|
|
64
|
+
║ "I orchestrate. I never sleep." ║
|
|
65
|
+
╚══════════════════════════════════════════════════════════╝
|
|
66
|
+
│
|
|
67
|
+
┌────────────────┼────────────────┐
|
|
68
|
+
│ │ │
|
|
69
|
+
▼ ▼ ▼
|
|
70
|
+
┌──────────┐ ┌──────────┐ ┌──────────┐
|
|
71
|
+
│📋 PLANNER│ │🔨 WORKER │ │🔨 WORKER │ x50 PARALLEL
|
|
72
|
+
│ Plan & │ │ auth.ts │ │ api.ts │ SESSIONS
|
|
73
|
+
│ Research │ │ (TDD) │ │ (TDD) │
|
|
74
|
+
└──────────┘ └──────────┘ └──────────┘
|
|
75
|
+
│ │ │
|
|
76
|
+
└────────────────┼────────────────┘
|
|
77
|
+
▼
|
|
78
|
+
╔══════════════════════════════════════════════════════════╗
|
|
79
|
+
║ ✅ REVIEWER ║
|
|
80
|
+
║ E2E Tests • Sync Check • Validate ║
|
|
81
|
+
╚══════════════════════════════════════════════════════════╝
|
|
82
|
+
│
|
|
83
|
+
┌──────┴──────┐
|
|
84
|
+
│ Complete? │
|
|
85
|
+
└──────┬──────┘
|
|
86
|
+
No ↙ ↘ Yes
|
|
87
|
+
♻️ 🎖️
|
|
88
|
+
LOOP SEALED
|
|
89
|
+
(auto-fix) (mission done)
|
|
90
|
+
```
|
|
55
91
|
|
|
56
92
|
---
|
|
57
93
|
|
|
58
|
-
##
|
|
94
|
+
## 🤖 The 4 Agents
|
|
59
95
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
│ Read state → Delegate → Loop │
|
|
67
|
-
└────────────────────────────────┘
|
|
68
|
-
│
|
|
69
|
-
┌───────────────────────┼───────────────────────┐
|
|
70
|
-
▼ ▼ ▼
|
|
71
|
-
┌─────────┐ ┌─────────┐ ┌─────────┐
|
|
72
|
-
│ PLANNER │ │ WORKER │ │ WORKER │ ⚡ PARALLEL
|
|
73
|
-
│ Plan it │ │ Build A │ │ Build B │ EXECUTION
|
|
74
|
-
└─────────┘ └─────────┘ └─────────┘
|
|
75
|
-
│ │ │
|
|
76
|
-
└───────────────────────┼───────────────────────┘
|
|
77
|
-
▼
|
|
78
|
-
┌────────────────────────────────┐
|
|
79
|
-
│ ✅ REVIEWER │
|
|
80
|
-
│ Verify → Sync │
|
|
81
|
-
└────────────────────────────────┘
|
|
82
|
-
│
|
|
83
|
-
┌──────────┴──────────┐
|
|
84
|
-
│ TODO incomplete? │
|
|
85
|
-
│ Sync issues? │
|
|
86
|
-
└──────────┬──────────┘
|
|
87
|
-
Yes ↓ ↓ No
|
|
88
|
-
♻️ LOOP 🎖️ SEALED
|
|
89
|
-
```
|
|
96
|
+
| Agent | Role | Superpower |
|
|
97
|
+
|-------|------|------------|
|
|
98
|
+
| **🎯 Commander** | Orchestrator | Sees everything, delegates intelligently, never stops |
|
|
99
|
+
| **📋 Planner** | Strategist | Web search, doc caching, file-level task breakdown |
|
|
100
|
+
| **🔨 Worker** | Builder | TDD isolation, 1 file = 1 session, parallel execution |
|
|
101
|
+
| **✅ Reviewer** | Quality Gate | E2E tests, sync checks, integration validation |
|
|
90
102
|
|
|
91
|
-
|
|
103
|
+
---
|
|
92
104
|
|
|
93
|
-
|
|
94
|
-
┌─────────────────────────────────────────────────────────────┐
|
|
95
|
-
│ 🔒 ISOLATION │ 🔄 SYNC │ ✅ STABILITY │
|
|
96
|
-
├─────────────────────────────────────────────────────────────┤
|
|
97
|
-
│ Each worker │ Shared state │ TODO 100% complete │
|
|
98
|
-
│ owns 1 file │ via .opencode │ + Zero sync issues │
|
|
99
|
-
│ No conflicts │ Real-time │ = Mission SEALED │
|
|
100
|
-
└─────────────────────────────────────────────────────────────┘
|
|
101
|
-
```
|
|
105
|
+
## 📊 System Specs
|
|
102
106
|
|
|
107
|
+
| Capability | Value |
|
|
108
|
+
|------------|-------|
|
|
109
|
+
| **Parallel Sessions** | 50 simultaneous |
|
|
110
|
+
| **Concurrency per Agent** | 10 default |
|
|
111
|
+
| **Poll Interval** | 1 second |
|
|
112
|
+
| **Session TTL** | 60 minutes |
|
|
113
|
+
| **Auto-Recovery** | 3 attempts per session |
|
|
114
|
+
| **Max Iterations** | 20 per mission |
|
|
115
|
+
| **Memory Limit** | 1,000 tasks (auto GC) |
|
|
103
116
|
|
|
104
117
|
---
|
|
105
118
|
|
|
106
|
-
## 🎮
|
|
107
|
-
|
|
108
|
-
| Mode | Trigger | What Happens |
|
|
109
|
-
|------|---------|--------------|
|
|
110
|
-
| **Commander Mode** 🎯 | `/task "mission"` | Full autonomous execution |
|
|
111
|
-
| **Chat Mode** 💬 | Just type normally | Simple Q&A, no automation |
|
|
119
|
+
## 🎮 What Happens When You Run `/task`
|
|
112
120
|
|
|
113
|
-
**
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
121
|
+
1. **🎯 Commander** reads state, creates TODO
|
|
122
|
+
2. **📋 Planner** breaks down into file-level tasks
|
|
123
|
+
3. **🔨 Workers** build in parallel (50 simultaneous sessions!)
|
|
124
|
+
4. **✅ Reviewer** validates, runs E2E tests
|
|
125
|
+
5. **♻️ Loop** until all TODOs checked + zero issues
|
|
126
|
+
6. **🎖️ SEALED** — mission complete
|
|
119
127
|
|
|
120
|
-
**Stop anytime
|
|
128
|
+
> **Tip:** Stop anytime with `/stop`
|
|
121
129
|
|
|
122
130
|
<div align="center">
|
|
123
131
|
<p><strong>TUI</strong></p>
|
|
@@ -130,37 +138,29 @@ A multi-agent system that **autonomously executes complex tasks** from start to
|
|
|
130
138
|
<p><strong>Window</strong></p>
|
|
131
139
|
<img src="assets/window_image.png" alt="Commander Window" width="600" />
|
|
132
140
|
</div>
|
|
133
|
-
---
|
|
134
|
-
|
|
135
|
-
## 🤖 The 4 Agents
|
|
136
|
-
|
|
137
|
-
| Agent | Role | Key Actions |
|
|
138
|
-
|-------|------|-------------|
|
|
139
|
-
| **Commander** 🎯 | Orchestrator | Delegates tasks, monitors progress, seals mission |
|
|
140
|
-
| **Planner** 📋 | Research + Plan | Web search, doc caching, TODO creation |
|
|
141
|
-
| **Worker** 🔨 | Implementation | Code writing, file ops, background commands |
|
|
142
|
-
| **Reviewer** ✅ | Quality Control | Verification, TODO updates, context management |
|
|
143
141
|
|
|
144
142
|
---
|
|
145
143
|
|
|
146
|
-
##
|
|
144
|
+
## 🔧 Self-Healing Features
|
|
147
145
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
146
|
+
```
|
|
147
|
+
┌────────────────────────────────────────────────────────────┐
|
|
148
|
+
│ ERROR TYPE │ AUTO-RECOVERY ACTION │
|
|
149
|
+
├────────────────────────────────────────────────────────────┤
|
|
150
|
+
│ Tool crash │ Inject recovery prompt │
|
|
151
|
+
│ Rate limit │ Exponential backoff + retry │
|
|
152
|
+
│ Context overflow │ Smart compaction │
|
|
153
|
+
│ Thinking block error │ Auto-restructure │
|
|
154
|
+
│ Session timeout │ Resume from checkpoint │
|
|
155
|
+
│ Build failure │ Loop back, fix, retry │
|
|
156
|
+
└────────────────────────────────────────────────────────────┘
|
|
157
|
+
```
|
|
155
158
|
|
|
156
159
|
---
|
|
157
160
|
|
|
158
161
|
## 📚 Documentation
|
|
159
162
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
- **[System Architecture](docs/SYSTEM_ARCHITECTURE.md)** — Complete technical documentation
|
|
163
|
-
- [Release Notes](docs/releases/) — Version history
|
|
163
|
+
- **[System Architecture](docs/SYSTEM_ARCHITECTURE.md)** — Full technical deep-dive
|
|
164
164
|
|
|
165
165
|
---
|
|
166
166
|
|
|
@@ -179,5 +179,6 @@ MIT License. [LICENSE](LICENSE)
|
|
|
179
179
|
---
|
|
180
180
|
|
|
181
181
|
<div align="center">
|
|
182
|
-
<
|
|
182
|
+
<h3>🚀 v0.9.7 — "Relentless execution until absolute success."</h3>
|
|
183
|
+
<p><i>Multi-agent. Parallel. Non-blocking. Self-healing. Enterprise-grade.</i></p>
|
|
183
184
|
</div>
|
package/dist/index.js
CHANGED
|
@@ -232,6 +232,9 @@ var SESSION_EVENTS = {
|
|
|
232
232
|
CREATED: "session.created",
|
|
233
233
|
ERROR: "session.error"
|
|
234
234
|
};
|
|
235
|
+
var MESSAGE_EVENTS = {
|
|
236
|
+
UPDATED: "message.updated"
|
|
237
|
+
};
|
|
235
238
|
|
|
236
239
|
// src/shared/session/constants/event-types.ts
|
|
237
240
|
var TASK_EVENTS = {
|
|
@@ -311,7 +314,11 @@ var PART_TYPES = {
|
|
|
311
314
|
TEXT: "text",
|
|
312
315
|
REASONING: "reasoning",
|
|
313
316
|
TOOL_CALL: "tool_call",
|
|
314
|
-
TOOL_RESULT: "tool_result"
|
|
317
|
+
TOOL_RESULT: "tool_result",
|
|
318
|
+
/** Anthropic-style tool reference */
|
|
319
|
+
TOOL: "tool",
|
|
320
|
+
/** Anthropic-style tool invocation */
|
|
321
|
+
TOOL_USE: "tool_use"
|
|
315
322
|
};
|
|
316
323
|
|
|
317
324
|
// src/shared/message/constants/prompts.ts
|
|
@@ -321,6 +328,20 @@ var PROMPTS = {
|
|
|
321
328
|
CONTINUE_DEFAULT: "continue from where we left off"
|
|
322
329
|
};
|
|
323
330
|
|
|
331
|
+
// src/shared/message/constants/message-roles.ts
|
|
332
|
+
var MESSAGE_ROLES = {
|
|
333
|
+
/** AI assistant message */
|
|
334
|
+
ASSISTANT: "assistant",
|
|
335
|
+
/** User message */
|
|
336
|
+
USER: "user",
|
|
337
|
+
/** System message */
|
|
338
|
+
SYSTEM: "system"
|
|
339
|
+
};
|
|
340
|
+
var SESSION_STATUS = {
|
|
341
|
+
IDLE: "idle",
|
|
342
|
+
BUSY: "busy"
|
|
343
|
+
};
|
|
344
|
+
|
|
324
345
|
// src/shared/errors/patterns.ts
|
|
325
346
|
var ERROR_PATTERNS = {
|
|
326
347
|
TOOL_RESULT_MISSING: /tool_result_missing|tool result.*missing/i,
|
|
@@ -15957,7 +15978,7 @@ var TaskPoller = class {
|
|
|
15957
15978
|
for (const task of running) {
|
|
15958
15979
|
try {
|
|
15959
15980
|
const sessionStatus = allStatuses[task.sessionID];
|
|
15960
|
-
if (sessionStatus?.type ===
|
|
15981
|
+
if (sessionStatus?.type === SESSION_STATUS.IDLE) {
|
|
15961
15982
|
const elapsed2 = Date.now() - task.startedAt.getTime();
|
|
15962
15983
|
if (elapsed2 < CONFIG.MIN_STABILITY_MS) continue;
|
|
15963
15984
|
if (!await this.validateSessionHasOutput(task.sessionID)) continue;
|
|
@@ -15984,7 +16005,7 @@ var TaskPoller = class {
|
|
|
15984
16005
|
try {
|
|
15985
16006
|
const response = await this.client.session.messages({ path: { id: sessionID } });
|
|
15986
16007
|
const messages = response.data ?? [];
|
|
15987
|
-
return messages.some((m) => m.info?.role ===
|
|
16008
|
+
return messages.some((m) => m.info?.role === MESSAGE_ROLES.ASSISTANT && m.parts?.some((p) => p.type === PART_TYPES.TEXT && p.text?.trim() || p.type === PART_TYPES.TOOL));
|
|
15988
16009
|
} catch {
|
|
15989
16010
|
return true;
|
|
15990
16011
|
}
|
|
@@ -16010,13 +16031,13 @@ var TaskPoller = class {
|
|
|
16010
16031
|
const result = await this.client.session.messages({ path: { id: task.sessionID } });
|
|
16011
16032
|
if (result.error) return;
|
|
16012
16033
|
const messages = result.data ?? [];
|
|
16013
|
-
const assistantMsgs = messages.filter((m) => m.info?.role ===
|
|
16034
|
+
const assistantMsgs = messages.filter((m) => m.info?.role === MESSAGE_ROLES.ASSISTANT);
|
|
16014
16035
|
let toolCalls = 0;
|
|
16015
16036
|
let lastTool;
|
|
16016
16037
|
let lastMessage;
|
|
16017
16038
|
for (const msg of assistantMsgs) {
|
|
16018
16039
|
for (const part of msg.parts ?? []) {
|
|
16019
|
-
if (part.type ===
|
|
16040
|
+
if (part.type === PART_TYPES.TOOL_USE || part.tool) {
|
|
16020
16041
|
toolCalls++;
|
|
16021
16042
|
lastTool = part.tool || part.name;
|
|
16022
16043
|
}
|
|
@@ -16332,7 +16353,7 @@ var ParallelAgentManager = class _ParallelAgentManager {
|
|
|
16332
16353
|
const result = await this.client.session.messages({ path: { id: task.sessionID } });
|
|
16333
16354
|
if (result.error) return `Error: ${result.error}`;
|
|
16334
16355
|
const messages = result.data ?? [];
|
|
16335
|
-
const lastMsg = messages.filter((m) => m.info?.role ===
|
|
16356
|
+
const lastMsg = messages.filter((m) => m.info?.role === MESSAGE_ROLES.ASSISTANT).reverse()[0];
|
|
16336
16357
|
if (!lastMsg) return "(No response)";
|
|
16337
16358
|
const text = lastMsg.parts?.filter((p) => p.type === PART_TYPES.TEXT || p.type === PART_TYPES.REASONING).map((p) => p.text ?? "").filter(Boolean).join("\n") ?? "";
|
|
16338
16359
|
task.result = text;
|
|
@@ -16370,7 +16391,7 @@ var ParallelAgentManager = class _ParallelAgentManager {
|
|
|
16370
16391
|
handleTaskError(taskId, error45) {
|
|
16371
16392
|
const task = this.store.get(taskId);
|
|
16372
16393
|
if (!task) return;
|
|
16373
|
-
task.status =
|
|
16394
|
+
task.status = TASK_STATUS.ERROR;
|
|
16374
16395
|
task.error = error45 instanceof Error ? error45.message : String(error45);
|
|
16375
16396
|
task.completedAt = /* @__PURE__ */ new Date();
|
|
16376
16397
|
if (task.concurrencyKey) this.concurrency.release(task.concurrencyKey);
|
|
@@ -16395,20 +16416,20 @@ async function validateSessionHasOutput(session, sessionID) {
|
|
|
16395
16416
|
const response = await session.messages({ path: { id: sessionID } });
|
|
16396
16417
|
const messages = response.data ?? [];
|
|
16397
16418
|
const hasAssistantMessage = messages.some(
|
|
16398
|
-
(m) => m.info?.role ===
|
|
16419
|
+
(m) => m.info?.role === MESSAGE_ROLES.ASSISTANT
|
|
16399
16420
|
);
|
|
16400
16421
|
if (!hasAssistantMessage) {
|
|
16401
16422
|
return false;
|
|
16402
16423
|
}
|
|
16403
16424
|
const hasContent = messages.some((m) => {
|
|
16404
|
-
if (m.info?.role !==
|
|
16425
|
+
if (m.info?.role !== MESSAGE_ROLES.ASSISTANT) return false;
|
|
16405
16426
|
const parts = m.parts ?? [];
|
|
16406
16427
|
return parts.some(
|
|
16407
16428
|
(p) => (
|
|
16408
16429
|
// Text content
|
|
16409
16430
|
p.type === PART_TYPES.TEXT && p.text && p.text.trim().length > 0 || // Reasoning content
|
|
16410
16431
|
p.type === PART_TYPES.REASONING && p.text && p.text.trim().length > 0 || // Tool calls (indicates work was done)
|
|
16411
|
-
p.type ===
|
|
16432
|
+
p.type === PART_TYPES.TOOL || p.type === PART_TYPES.TOOL_USE || p.tool
|
|
16412
16433
|
)
|
|
16413
16434
|
);
|
|
16414
16435
|
});
|
|
@@ -16448,7 +16469,7 @@ async function pollWithSafetyLimits(session, sessionID, startTime) {
|
|
|
16448
16469
|
stablePolls = 0;
|
|
16449
16470
|
continue;
|
|
16450
16471
|
}
|
|
16451
|
-
if (sessionStatus.type !==
|
|
16472
|
+
if (sessionStatus.type !== SESSION_STATUS.IDLE) {
|
|
16452
16473
|
stablePolls = 0;
|
|
16453
16474
|
continue;
|
|
16454
16475
|
}
|
|
@@ -16491,7 +16512,7 @@ async function extractSessionResult(session, sessionID) {
|
|
|
16491
16512
|
try {
|
|
16492
16513
|
const msgs = await session.messages({ path: { id: sessionID } });
|
|
16493
16514
|
const messages = msgs.data ?? [];
|
|
16494
|
-
const lastMsg = messages.filter((m) => m.info?.role ===
|
|
16515
|
+
const lastMsg = messages.filter((m) => m.info?.role === MESSAGE_ROLES.ASSISTANT).reverse()[0];
|
|
16495
16516
|
const text = lastMsg?.parts?.filter((p) => p.type === PART_TYPES.TEXT || p.type === PART_TYPES.REASONING).map((p) => p.text ?? "").join("\n") || "";
|
|
16496
16517
|
return text;
|
|
16497
16518
|
} catch (error45) {
|
|
@@ -18159,7 +18180,7 @@ async function detectSealInSession(client, sessionID) {
|
|
|
18159
18180
|
try {
|
|
18160
18181
|
const response = await client.session.messages({ path: { id: sessionID } });
|
|
18161
18182
|
const messages = response.data ?? [];
|
|
18162
|
-
const assistantMessages = messages.filter((m) => m.info?.role ===
|
|
18183
|
+
const assistantMessages = messages.filter((m) => m.info?.role === MESSAGE_ROLES.ASSISTANT);
|
|
18163
18184
|
const recentMessages = assistantMessages.slice(-3);
|
|
18164
18185
|
for (const msg of recentMessages) {
|
|
18165
18186
|
if (!msg.parts) continue;
|
|
@@ -18450,12 +18471,12 @@ function createEventHandler(ctx) {
|
|
|
18450
18471
|
manager.handleEvent(event);
|
|
18451
18472
|
} catch {
|
|
18452
18473
|
}
|
|
18453
|
-
if (event.type ===
|
|
18474
|
+
if (event.type === SESSION_EVENTS.CREATED) {
|
|
18454
18475
|
const sessionID = event.properties?.id || "";
|
|
18455
18476
|
log2("[event-handler] session.created", { sessionID });
|
|
18456
18477
|
presets.missionStarted(`Session ${sessionID.slice(0, 12)}...`);
|
|
18457
18478
|
}
|
|
18458
|
-
if (event.type ===
|
|
18479
|
+
if (event.type === SESSION_EVENTS.DELETED) {
|
|
18459
18480
|
const sessionID = event.properties?.id || event.properties?.info?.id || "";
|
|
18460
18481
|
const session = sessions.get(sessionID);
|
|
18461
18482
|
if (session) {
|
|
@@ -18471,7 +18492,7 @@ function createEventHandler(ctx) {
|
|
|
18471
18492
|
presets.sessionCompleted(sessionID, duration3);
|
|
18472
18493
|
}
|
|
18473
18494
|
}
|
|
18474
|
-
if (event.type ===
|
|
18495
|
+
if (event.type === SESSION_EVENTS.ERROR) {
|
|
18475
18496
|
const sessionID = event.properties?.sessionId || event.properties?.sessionID || "";
|
|
18476
18497
|
const error45 = event.properties?.error;
|
|
18477
18498
|
log2("[event-handler] session.error", { sessionID, error: error45 });
|
|
@@ -18493,19 +18514,19 @@ function createEventHandler(ctx) {
|
|
|
18493
18514
|
}
|
|
18494
18515
|
presets.taskFailed("session", String(error45).slice(0, 50));
|
|
18495
18516
|
}
|
|
18496
|
-
if (event.type ===
|
|
18517
|
+
if (event.type === MESSAGE_EVENTS.UPDATED) {
|
|
18497
18518
|
const messageInfo = event.properties?.info;
|
|
18498
18519
|
const sessionID = messageInfo?.sessionID;
|
|
18499
18520
|
const role = messageInfo?.role;
|
|
18500
|
-
if (sessionID && role ===
|
|
18521
|
+
if (sessionID && role === MESSAGE_ROLES.ASSISTANT) {
|
|
18501
18522
|
markRecoveryComplete(sessionID);
|
|
18502
18523
|
}
|
|
18503
|
-
if (sessionID && role ===
|
|
18524
|
+
if (sessionID && role === MESSAGE_ROLES.USER) {
|
|
18504
18525
|
handleUserMessage(sessionID);
|
|
18505
18526
|
handleUserMessage2(sessionID);
|
|
18506
18527
|
}
|
|
18507
18528
|
}
|
|
18508
|
-
if (event.type ===
|
|
18529
|
+
if (event.type === SESSION_EVENTS.IDLE) {
|
|
18509
18530
|
const sessionID = event.properties?.sessionID || "";
|
|
18510
18531
|
if (sessionID) {
|
|
18511
18532
|
const isMainSession = sessions.has(sessionID);
|
|
@@ -4,3 +4,5 @@
|
|
|
4
4
|
export { PART_TYPES } from "./part-types.js";
|
|
5
5
|
export { PROMPTS } from "./prompts.js";
|
|
6
6
|
export { SLASH_COMMANDS } from "./slash-commands.js";
|
|
7
|
+
export { PLUGIN_HOOKS, type PluginHookName } from "./plugin-hooks.js";
|
|
8
|
+
export { MESSAGE_ROLES, SESSION_STATUS, type MessageRole, type SessionStatus } from "./message-roles.js";
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Message Role Constants
|
|
3
|
+
*
|
|
4
|
+
* OpenCode message roles
|
|
5
|
+
* Use these instead of hardcoded strings
|
|
6
|
+
*/
|
|
7
|
+
export declare const MESSAGE_ROLES: {
|
|
8
|
+
/** AI assistant message */
|
|
9
|
+
readonly ASSISTANT: "assistant";
|
|
10
|
+
/** User message */
|
|
11
|
+
readonly USER: "user";
|
|
12
|
+
/** System message */
|
|
13
|
+
readonly SYSTEM: "system";
|
|
14
|
+
};
|
|
15
|
+
export type MessageRole = typeof MESSAGE_ROLES[keyof typeof MESSAGE_ROLES];
|
|
16
|
+
/**
|
|
17
|
+
* Session Status Types
|
|
18
|
+
*/
|
|
19
|
+
export declare const SESSION_STATUS: {
|
|
20
|
+
readonly IDLE: "idle";
|
|
21
|
+
readonly BUSY: "busy";
|
|
22
|
+
};
|
|
23
|
+
export type SessionStatus = typeof SESSION_STATUS[keyof typeof SESSION_STATUS];
|
|
@@ -6,4 +6,8 @@ export declare const PART_TYPES: {
|
|
|
6
6
|
readonly REASONING: "reasoning";
|
|
7
7
|
readonly TOOL_CALL: "tool_call";
|
|
8
8
|
readonly TOOL_RESULT: "tool_result";
|
|
9
|
+
/** Anthropic-style tool reference */
|
|
10
|
+
readonly TOOL: "tool";
|
|
11
|
+
/** Anthropic-style tool invocation */
|
|
12
|
+
readonly TOOL_USE: "tool_use";
|
|
9
13
|
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin Hook Constants
|
|
3
|
+
*
|
|
4
|
+
* OpenCode plugin hook names (from @opencode-ai/plugin)
|
|
5
|
+
* Use these instead of hardcoded strings
|
|
6
|
+
*/
|
|
7
|
+
export declare const PLUGIN_HOOKS: {
|
|
8
|
+
/** Intercepts user messages before sending to LLM */
|
|
9
|
+
readonly CHAT_MESSAGE: "chat.message";
|
|
10
|
+
/** Runs after LLM finishes responding */
|
|
11
|
+
readonly ASSISTANT_DONE: "assistant.done";
|
|
12
|
+
/** Runs after any tool call completes */
|
|
13
|
+
readonly TOOL_EXECUTE_AFTER: "tool.execute.after";
|
|
14
|
+
};
|
|
15
|
+
export type PluginHookName = typeof PLUGIN_HOOKS[keyof typeof PLUGIN_HOOKS];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Session constants
|
|
3
3
|
*/
|
|
4
|
-
export { SESSION_EVENTS } from "./session-events.js";
|
|
5
|
-
export type { SessionEventType } from "./session-events.js";
|
|
4
|
+
export { SESSION_EVENTS, MESSAGE_EVENTS } from "./session-events.js";
|
|
5
|
+
export type { SessionEventType, MessageEventType } from "./session-events.js";
|
|
6
6
|
export { TASK_EVENTS, TODO_EVENTS, SESSION_EVENTS as SESSION_STATE_EVENTS, DOCUMENT_EVENTS, MISSION_EVENTS, SPECIAL_EVENTS, EVENT_TYPES, } from "./event-types.js";
|
|
7
7
|
export type { EventTypeValue } from "./event-types.js";
|
|
@@ -8,3 +8,10 @@ export declare const SESSION_EVENTS: {
|
|
|
8
8
|
readonly ERROR: "session.error";
|
|
9
9
|
};
|
|
10
10
|
export type SessionEventType = (typeof SESSION_EVENTS)[keyof typeof SESSION_EVENTS];
|
|
11
|
+
/**
|
|
12
|
+
* Message Event Types
|
|
13
|
+
*/
|
|
14
|
+
export declare const MESSAGE_EVENTS: {
|
|
15
|
+
readonly UPDATED: "message.updated";
|
|
16
|
+
};
|
|
17
|
+
export type MessageEventType = (typeof MESSAGE_EVENTS)[keyof typeof MESSAGE_EVENTS];
|
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.9.
|
|
5
|
+
"version": "0.9.8",
|
|
6
6
|
"author": "agnusdei1207",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"repository": {
|