opencode-orchestrator 1.3.11 → 1.5.0
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 +33 -3
- package/bin/orchestrator-linux-arm64 +0 -0
- package/bin/orchestrator-linux-x64 +0 -0
- package/dist/agents/prompts/02_discovery/discovery_core.d.ts +1 -1
- package/dist/agents/prompts/03_planning/planning_core.d.ts +1 -1
- package/dist/agents/prompts/04_execution/execution_core.d.ts +1 -1
- package/dist/agents/prompts/05_verification/verification_core.d.ts +1 -1
- package/dist/agents/prompts/06_mission/mission_core.d.ts +1 -1
- package/dist/agents/prompts/08_tools/tools_core.d.ts +1 -1
- package/dist/core/knowledge/context-provider.d.ts +1 -0
- package/dist/core/knowledge/mission-memory.d.ts +2 -0
- package/dist/index.js +169 -40
- package/dist/shared/constants/system-messages.d.ts +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
[](LICENSE)
|
|
7
7
|
[](https://www.npmjs.com/package/opencode-orchestrator)
|
|
8
8
|
<!-- VERSION:START -->
|
|
9
|
-
**Version:** `1.
|
|
9
|
+
**Version:** `1.5.0`
|
|
10
10
|
<!-- VERSION:END -->
|
|
11
11
|
</div>
|
|
12
12
|
|
|
@@ -34,8 +34,8 @@ Manual fallback: remove `"opencode-orchestrator"` or `["opencode-orchestrator",
|
|
|
34
34
|
Tested compatibility:
|
|
35
35
|
|
|
36
36
|
1. Node.js `24+`
|
|
37
|
-
2. `@opencode-ai/plugin` `1.17.
|
|
38
|
-
3. `@opencode-ai/sdk` `1.17.
|
|
37
|
+
2. `@opencode-ai/plugin` `1.17.4`
|
|
38
|
+
3. `@opencode-ai/sdk` `1.17.4`
|
|
39
39
|
|
|
40
40
|
OpenCode plugin options belong inside the `plugin` array as `["plugin-name", {...}]` tuples. Configure `agentConcurrency` and `missionLoop` there:
|
|
41
41
|
|
|
@@ -99,6 +99,35 @@ Mission controls:
|
|
|
99
99
|
3. `/cancel` and `/stop` deactivate the current mission loop.
|
|
100
100
|
4. The default mission iteration ceiling is `1,000,000,000`.
|
|
101
101
|
|
|
102
|
+
### Authorized Shell Listener TUI
|
|
103
|
+
|
|
104
|
+
For owned lab machines or explicitly authorized test environments, the bundled Rust CLI can run a multi-session TCP shell listener:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
orchestrator shell-listener --bind 127.0.0.1 --port 4444
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
The listener is intentionally outside the OpenCode JSON-RPC tool surface. It is an operator-driven terminal workflow, not an LLM-callable tool.
|
|
111
|
+
|
|
112
|
+
Safety defaults:
|
|
113
|
+
|
|
114
|
+
1. Loopback-only bind by default.
|
|
115
|
+
2. Non-loopback bind addresses require `--allow-remote`.
|
|
116
|
+
3. Raw stream logs are stored under `.opencode-orchestrator/shell-listener/`.
|
|
117
|
+
4. The CLI does not generate payloads, exploit targets, or bypass authentication.
|
|
118
|
+
|
|
119
|
+
TUI commands:
|
|
120
|
+
|
|
121
|
+
| Command | Purpose |
|
|
122
|
+
| --- | --- |
|
|
123
|
+
| `sessions` | Show connected sessions, peer addresses, status, and raw log paths. |
|
|
124
|
+
| `use <id>` | Select the active session. |
|
|
125
|
+
| `send <text>` | Send one input line to the active session. Use this for login, registry, CDK, or reverse-proxy prompts that need human input. |
|
|
126
|
+
| `run <cmd>` | Send a command followed by a unique sentinel marker so completion can be recognized in output. |
|
|
127
|
+
| `pty` | Send a manual PTY helper to the active session when the remote environment supports Python. |
|
|
128
|
+
| `close [id]` | Close a session. |
|
|
129
|
+
| `quit` | Stop the listener UI. |
|
|
130
|
+
|
|
102
131
|
## 4. How It Works
|
|
103
132
|
|
|
104
133
|
```mermaid
|
|
@@ -128,6 +157,7 @@ Runtime evidence is written only when enabled:
|
|
|
128
157
|
| `.opencode/mission-ledger.jsonl` | Bounded event trail for mission decisions. |
|
|
129
158
|
| `.opencode/docs/brain/scratchpad.md` | Generated Markdown memory surface for active missions. |
|
|
130
159
|
| `.opencode/docs/brain/knowledge-map.canvas` | Obsidian-compatible visual map of objective, evidence, and verification nodes. |
|
|
160
|
+
| `.opencode/docs/brain/memories/*.md` | Generated mission-relevant memory notes indexed by the knowledge retriever. |
|
|
131
161
|
|
|
132
162
|
## 5. Developer Notes
|
|
133
163
|
|
|
Binary file
|
|
Binary file
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* ╔════════════════════════════════════════════════════════════╗
|
|
3
3
|
* ║ DISCOVERY CORE PHILOSOPHY ║
|
|
4
4
|
* ╠════════════════════════════════════════════════════════════╣
|
|
5
|
-
* ║
|
|
5
|
+
* ║ Core Philosophy of Discovery: Thorough Exploration Before Execution ║
|
|
6
6
|
* ╚════════════════════════════════════════════════════════════╝
|
|
7
7
|
*/
|
|
8
8
|
export declare const DISCOVERY_CORE = "\n# Discovery Phase Philosophy\n\nBefore any execution, thoroughly explore:\n1. Workspace structure\n2. Environment capabilities\n3. Available skills and tools\n4. Project patterns and conventions\n\nThe discovery phase sets the foundation for all subsequent actions.\n";
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* ╔════════════════════════════════════════════════════════════╗
|
|
3
3
|
* ║ PLANNING CORE PHILOSOPHY ║
|
|
4
4
|
* ╠════════════════════════════════════════════════════════════╣
|
|
5
|
-
* ║
|
|
5
|
+
* ║ Core Philosophy of Planning: Establishing Clear, Actionable Plans ║
|
|
6
6
|
* ╚════════════════════════════════════════════════════════════╝
|
|
7
7
|
*/
|
|
8
8
|
export declare const PLANNING_CORE = "\n# Planning Phase Philosophy\n\nCreate actionable, granular plans:\n1. Break down complex tasks into atomic units\n2. Identify dependencies and execution order\n3. Plan for parallel execution where possible\n4. Define clear success criteria\n\nGood planning makes execution straightforward.\n";
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* ╔════════════════════════════════════════════════════════════╗
|
|
3
3
|
* ║ EXECUTION CORE PHILOSOPHY ║
|
|
4
4
|
* ╠════════════════════════════════════════════════════════════╣
|
|
5
|
-
* ║
|
|
5
|
+
* ║ Core Philosophy of Execution: Executing Plans with Precision ║
|
|
6
6
|
* ╚════════════════════════════════════════════════════════════╝
|
|
7
7
|
*/
|
|
8
8
|
export declare const EXECUTION_CORE = "\n# Execution Phase Philosophy\n\nExecute with precision and quality:\n1. Follow the plan systematically\n2. Handle errors gracefully\n3. Provide clear progress updates\n4. Maintain code quality standards\n\nExecution transforms plans into reality.\n";
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* ╔════════════════════════════════════════════════════════════╗
|
|
3
3
|
* ║ VERIFICATION CORE PHILOSOPHY ║
|
|
4
4
|
* ╠════════════════════════════════════════════════════════════╣
|
|
5
|
-
* ║
|
|
5
|
+
* ║ Core Philosophy of Verification: Execution-Based Quality Assurance ║
|
|
6
6
|
* ╚════════════════════════════════════════════════════════════╝
|
|
7
7
|
*/
|
|
8
8
|
export declare const VERIFICATION_CORE = "\n# Verification Phase Philosophy\n\nVerify through actual execution:\n1. Build the project\n2. Run tests\n3. Check linting and type errors\n4. Validate runtime behavior\n\nReal execution is the ultimate verification.\n";
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* ╔════════════════════════════════════════════════════════════╗
|
|
3
3
|
* ║ MISSION CORE PHILOSOPHY ║
|
|
4
4
|
* ╠════════════════════════════════════════════════════════════╣
|
|
5
|
-
* ║
|
|
5
|
+
* ║ Core Philosophy of Mission Control: Managing Full Lifecycle ║
|
|
6
6
|
* ╚════════════════════════════════════════════════════════════╝
|
|
7
7
|
*/
|
|
8
8
|
export declare const MISSION_CORE = "\n# Mission Management Philosophy\n\nManage the entire mission lifecycle:\n1. Track mission status throughout execution\n2. Handle recovery from failures\n3. Determine completion conditions\n4. Ensure clean mission closure\n\nA mission succeeds when all objectives are met.\n";
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* ╔════════════════════════════════════════════════════════════╗
|
|
3
3
|
* ║ TOOLS CORE PHILOSOPHY ║
|
|
4
4
|
* ╠════════════════════════════════════════════════════════════╣
|
|
5
|
-
* ║
|
|
5
|
+
* ║ Core Philosophy of Tools: Using the Right Tools Correctly ║
|
|
6
6
|
* ╚════════════════════════════════════════════════════════════╝
|
|
7
7
|
*/
|
|
8
8
|
export declare const TOOLS_CORE = "\n# Tools Usage Philosophy\n\nUse the right tool for the right job:\n1. Understand each tool's capabilities and limitations\n2. Choose the most appropriate tool for each task\n3. Use tools efficiently and correctly\n4. Validate tool outputs\n\nProper tool usage amplifies effectiveness.\n";
|
|
@@ -2,3 +2,5 @@ import type { MissionLoopState } from "../../shared/loop/interfaces/mission-loop
|
|
|
2
2
|
export declare function syncMissionMemory(directory: string, state: MissionLoopState): boolean;
|
|
3
3
|
export declare function getMissionScratchpadPath(directory: string): string;
|
|
4
4
|
export declare function getMissionCanvasPath(directory: string): string;
|
|
5
|
+
export declare function getMissionMemoryNotesDirPath(directory: string): string;
|
|
6
|
+
export declare function readMissionScratchpadSnapshot(directory: string, maxChars?: number): string | null;
|
package/dist/index.js
CHANGED
|
@@ -36437,7 +36437,7 @@ init_logger();
|
|
|
36437
36437
|
// src/core/loop/mission-loop.ts
|
|
36438
36438
|
init_logger();
|
|
36439
36439
|
init_shared();
|
|
36440
|
-
import { existsSync as
|
|
36440
|
+
import { existsSync as existsSync4, readFileSync as readFileSync3, writeFileSync as writeFileSync2, unlinkSync as unlinkSync2, mkdirSync as mkdirSync4 } from "node:fs";
|
|
36441
36441
|
import { join as join6 } from "node:path";
|
|
36442
36442
|
|
|
36443
36443
|
// src/shared/constants/system-messages.ts
|
|
@@ -36515,15 +36515,15 @@ var CONTINUE_INSTRUCTION = `<auto_continue>
|
|
|
36515
36515
|
</auto_continue>`;
|
|
36516
36516
|
var STAGNATION_INTERVENTION = `
|
|
36517
36517
|
<system_intervention type="stagnation_detected">
|
|
36518
|
-
\u26A0\uFE0F
|
|
36519
|
-
|
|
36518
|
+
\u26A0\uFE0F **WARNING: STAGNATION DETECTED**
|
|
36519
|
+
No substantive progress has been detected for the past several turns. Repeating the same action or merely "monitoring" is prohibited.
|
|
36520
36520
|
|
|
36521
|
-
|
|
36522
|
-
1.
|
|
36523
|
-
2.
|
|
36524
|
-
3.
|
|
36521
|
+
**Guidelines for Autonomous Diagnosis and Resolution:**
|
|
36522
|
+
1. **Check Real-time Logs**: Use \`check_background_task\` or \`read_file\` to directly check the output logs of the running task.
|
|
36523
|
+
2. **Process Liveness Diagnosis**: If the task appears to be in a zombie state or hung, proactively \`kill\` it, break down the steps, and run it again.
|
|
36524
|
+
3. **Strategy Pivot**: If the same approach keeps failing, use alternative tools or methods to reach the goal.
|
|
36525
36525
|
|
|
36526
|
-
|
|
36526
|
+
**Intervene proactively right now. Do not wait.**
|
|
36527
36527
|
</system_intervention>`;
|
|
36528
36528
|
var CLEANUP_INSTRUCTION = `
|
|
36529
36529
|
<system_maintenance type="continuous_hygiene">
|
|
@@ -36548,7 +36548,7 @@ You must maintain a pristine workspace. **As part of your move**, perform these
|
|
|
36548
36548
|
|
|
36549
36549
|
// src/core/knowledge/mission-memory.ts
|
|
36550
36550
|
init_shared();
|
|
36551
|
-
import { mkdirSync as mkdirSync3, renameSync, writeFileSync } from "node:fs";
|
|
36551
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync2, readdirSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
|
|
36552
36552
|
import { dirname as dirname2, join as join5 } from "node:path";
|
|
36553
36553
|
|
|
36554
36554
|
// src/core/loop/mission-ledger.ts
|
|
@@ -36625,8 +36625,17 @@ function parseLedgerLine(line) {
|
|
|
36625
36625
|
var BRAIN_DIR = join5(PATHS.DOCS, "brain");
|
|
36626
36626
|
var SCRATCHPAD_FILE = "scratchpad.md";
|
|
36627
36627
|
var CANVAS_FILE = "knowledge-map.canvas";
|
|
36628
|
+
var MEMORY_NOTES_DIR = "memories";
|
|
36628
36629
|
var MAX_CANVAS_EVENTS = 3;
|
|
36629
36630
|
var MAX_SCRATCHPAD_EVENTS = 6;
|
|
36631
|
+
var MAX_MEMORY_NOTES = 8;
|
|
36632
|
+
var MAX_MEMORY_BODY_CHARS = 900;
|
|
36633
|
+
var SCRATCHPAD_SNAPSHOT_CHARS = 1600;
|
|
36634
|
+
var MISSION_MEMORY_LEVELS = [
|
|
36635
|
+
"project" /* PROJECT */,
|
|
36636
|
+
"mission" /* MISSION */,
|
|
36637
|
+
"task" /* TASK */
|
|
36638
|
+
];
|
|
36630
36639
|
function syncMissionMemory(directory, state2) {
|
|
36631
36640
|
const options = getMissionRuntimeOptions();
|
|
36632
36641
|
if (!options.markdownMemory) return false;
|
|
@@ -36637,6 +36646,7 @@ function syncMissionMemory(directory, state2) {
|
|
|
36637
36646
|
try {
|
|
36638
36647
|
writeScratchpad(directory, state2, events);
|
|
36639
36648
|
writeCanvas(directory, state2, events);
|
|
36649
|
+
syncMissionMemoryNotes(directory, state2);
|
|
36640
36650
|
return true;
|
|
36641
36651
|
} catch {
|
|
36642
36652
|
return false;
|
|
@@ -36648,6 +36658,17 @@ function getMissionScratchpadPath(directory) {
|
|
|
36648
36658
|
function getMissionCanvasPath(directory) {
|
|
36649
36659
|
return join5(directory, BRAIN_DIR, CANVAS_FILE);
|
|
36650
36660
|
}
|
|
36661
|
+
function getMissionMemoryNotesDirPath(directory) {
|
|
36662
|
+
return join5(directory, BRAIN_DIR, MEMORY_NOTES_DIR);
|
|
36663
|
+
}
|
|
36664
|
+
function readMissionScratchpadSnapshot(directory, maxChars = SCRATCHPAD_SNAPSHOT_CHARS) {
|
|
36665
|
+
const path11 = getMissionScratchpadPath(directory);
|
|
36666
|
+
if (!existsSync3(path11)) return null;
|
|
36667
|
+
const content = stripFrontmatter(readFileSync2(path11, "utf8")).trim();
|
|
36668
|
+
if (!content) return null;
|
|
36669
|
+
if (content.length <= maxChars) return content;
|
|
36670
|
+
return `${content.slice(0, maxChars)}...`;
|
|
36671
|
+
}
|
|
36651
36672
|
function writeScratchpad(directory, state2, events) {
|
|
36652
36673
|
const content = [
|
|
36653
36674
|
"---",
|
|
@@ -36682,6 +36703,22 @@ function writeCanvas(directory, state2, events) {
|
|
|
36682
36703
|
const edges = buildCanvasEdges(nodes);
|
|
36683
36704
|
atomicWrite(getMissionCanvasPath(directory), JSON.stringify({ nodes, edges }, null, 2));
|
|
36684
36705
|
}
|
|
36706
|
+
function syncMissionMemoryNotes(directory, state2) {
|
|
36707
|
+
const notesDir = getMissionMemoryNotesDirPath(directory);
|
|
36708
|
+
const expectedFiles = /* @__PURE__ */ new Set();
|
|
36709
|
+
for (const entry of selectMissionMemoryEntries(state2)) {
|
|
36710
|
+
const fileName = buildMemoryNoteFileName(entry);
|
|
36711
|
+
expectedFiles.add(fileName);
|
|
36712
|
+
atomicWrite(join5(notesDir, fileName), buildMemoryNoteContent(state2, entry));
|
|
36713
|
+
}
|
|
36714
|
+
if (!existsSync3(notesDir)) return;
|
|
36715
|
+
for (const entry of readdirSync(notesDir, { withFileTypes: true })) {
|
|
36716
|
+
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
36717
|
+
if (!expectedFiles.has(entry.name)) {
|
|
36718
|
+
unlinkSync(join5(notesDir, entry.name));
|
|
36719
|
+
}
|
|
36720
|
+
}
|
|
36721
|
+
}
|
|
36685
36722
|
function buildCanvasNodes(state2, events) {
|
|
36686
36723
|
const nodes = [
|
|
36687
36724
|
textNode("objective", `Objective
|
|
@@ -36711,6 +36748,67 @@ function buildCanvasEdges(nodes) {
|
|
|
36711
36748
|
function textNode(id, text, x, y) {
|
|
36712
36749
|
return { id, type: "text", text, x, y, width: 360, height: 180 };
|
|
36713
36750
|
}
|
|
36751
|
+
function selectMissionMemoryEntries(state2) {
|
|
36752
|
+
const snapshot = MemoryManager.getInstance().export();
|
|
36753
|
+
const query = `${state2.objective ?? ""} ${state2.prompt}`.trim();
|
|
36754
|
+
const selected = [];
|
|
36755
|
+
for (const level of MISSION_MEMORY_LEVELS) {
|
|
36756
|
+
const entries = snapshot[level] ?? [];
|
|
36757
|
+
for (const entry of entries) {
|
|
36758
|
+
if (shouldPersistMissionEntry(entry, level, query)) {
|
|
36759
|
+
selected.push(entry);
|
|
36760
|
+
}
|
|
36761
|
+
}
|
|
36762
|
+
}
|
|
36763
|
+
return selected.sort((left, right) => right.importance - left.importance || right.timestamp - left.timestamp).slice(0, MAX_MEMORY_NOTES);
|
|
36764
|
+
}
|
|
36765
|
+
function shouldPersistMissionEntry(entry, level, query) {
|
|
36766
|
+
const matchesQuery = query ? isRelevantToQuery(entry.content, query) : false;
|
|
36767
|
+
switch (level) {
|
|
36768
|
+
case "project" /* PROJECT */:
|
|
36769
|
+
return entry.importance >= 0.7 || matchesQuery;
|
|
36770
|
+
case "mission" /* MISSION */:
|
|
36771
|
+
return entry.importance >= 0.5 || matchesQuery;
|
|
36772
|
+
case "task" /* TASK */:
|
|
36773
|
+
return entry.importance >= 0.7 || matchesQuery;
|
|
36774
|
+
default:
|
|
36775
|
+
return false;
|
|
36776
|
+
}
|
|
36777
|
+
}
|
|
36778
|
+
function isRelevantToQuery(content, query) {
|
|
36779
|
+
const normalizedContent = content.toLowerCase();
|
|
36780
|
+
const keywords = query.toLowerCase().split(/\s+/).map((token) => token.trim()).filter((token) => token.length > 3);
|
|
36781
|
+
if (keywords.length === 0) return false;
|
|
36782
|
+
return keywords.some((keyword) => normalizedContent.includes(keyword));
|
|
36783
|
+
}
|
|
36784
|
+
function buildMemoryNoteFileName(entry) {
|
|
36785
|
+
return `${entry.level}-${sanitizeFilePart(entry.id)}.md`;
|
|
36786
|
+
}
|
|
36787
|
+
function buildMemoryNoteContent(state2, entry) {
|
|
36788
|
+
const recordedAt = new Date(entry.timestamp).toISOString();
|
|
36789
|
+
const body = entry.content.length > MAX_MEMORY_BODY_CHARS ? `${entry.content.slice(0, MAX_MEMORY_BODY_CHARS)}...` : entry.content;
|
|
36790
|
+
return [
|
|
36791
|
+
"---",
|
|
36792
|
+
`tags: [mission-memory, orchestrator, ${entry.level}]`,
|
|
36793
|
+
`title: "${escapeYaml(`${entry.level} memory ${entry.id}`)}"`,
|
|
36794
|
+
"keep: true",
|
|
36795
|
+
`level: "${entry.level}"`,
|
|
36796
|
+
`importance: ${entry.importance.toFixed(3)}`,
|
|
36797
|
+
`session: "${escapeYaml(state2.sessionID)}"`,
|
|
36798
|
+
`recorded_at: "${recordedAt}"`,
|
|
36799
|
+
`objective: "${escapeYaml(state2.objective ?? state2.prompt)}"`,
|
|
36800
|
+
"---",
|
|
36801
|
+
`# ${capitalize(entry.level)} Memory`,
|
|
36802
|
+
"",
|
|
36803
|
+
`- Session: ${state2.sessionID}`,
|
|
36804
|
+
`- Recorded at: ${recordedAt}`,
|
|
36805
|
+
`- Importance: ${entry.importance.toFixed(3)}`,
|
|
36806
|
+
"",
|
|
36807
|
+
"## Content",
|
|
36808
|
+
body,
|
|
36809
|
+
""
|
|
36810
|
+
].join("\n");
|
|
36811
|
+
}
|
|
36714
36812
|
function formatEventLines(events) {
|
|
36715
36813
|
if (events.length === 0) return ["- No runtime evidence recorded yet."];
|
|
36716
36814
|
return events.map((event) => `- ${event.timestamp} ${event.type}: ${event.summary ?? event.reason ?? "recorded"}`);
|
|
@@ -36724,6 +36822,15 @@ function atomicWrite(path11, content) {
|
|
|
36724
36822
|
function escapeYaml(value) {
|
|
36725
36823
|
return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
36726
36824
|
}
|
|
36825
|
+
function stripFrontmatter(content) {
|
|
36826
|
+
return content.replace(/^---\n[\s\S]*?\n---\n?/u, "");
|
|
36827
|
+
}
|
|
36828
|
+
function sanitizeFilePart(value) {
|
|
36829
|
+
return value.replace(/[^a-zA-Z0-9_-]+/g, "-");
|
|
36830
|
+
}
|
|
36831
|
+
function capitalize(value) {
|
|
36832
|
+
return value.charAt(0).toUpperCase() + value.slice(1);
|
|
36833
|
+
}
|
|
36727
36834
|
|
|
36728
36835
|
// src/core/loop/mission-loop.ts
|
|
36729
36836
|
var STATE_FILE = MISSION_CONTROL.STATE_FILE;
|
|
@@ -36734,11 +36841,11 @@ function getStateFilePath(directory) {
|
|
|
36734
36841
|
}
|
|
36735
36842
|
function readLoopState(directory) {
|
|
36736
36843
|
const filePath = getStateFilePath(directory);
|
|
36737
|
-
if (!
|
|
36844
|
+
if (!existsSync4(filePath)) {
|
|
36738
36845
|
return null;
|
|
36739
36846
|
}
|
|
36740
36847
|
try {
|
|
36741
|
-
const content =
|
|
36848
|
+
const content = readFileSync3(filePath, "utf-8");
|
|
36742
36849
|
return JSON.parse(content);
|
|
36743
36850
|
} catch (error95) {
|
|
36744
36851
|
log(`[${MISSION_CONTROL.LOG_SOURCE}] Failed to read state: ${error95}`);
|
|
@@ -36749,7 +36856,7 @@ function writeLoopState(directory, state2) {
|
|
|
36749
36856
|
const filePath = getStateFilePath(directory);
|
|
36750
36857
|
const dirPath = join6(directory, PATHS.OPENCODE);
|
|
36751
36858
|
try {
|
|
36752
|
-
if (!
|
|
36859
|
+
if (!existsSync4(dirPath)) {
|
|
36753
36860
|
mkdirSync4(dirPath, { recursive: true });
|
|
36754
36861
|
}
|
|
36755
36862
|
writeFileSync2(filePath, JSON.stringify(state2, null, 2), "utf-8");
|
|
@@ -36761,11 +36868,11 @@ function writeLoopState(directory, state2) {
|
|
|
36761
36868
|
}
|
|
36762
36869
|
function clearLoopState(directory) {
|
|
36763
36870
|
const filePath = getStateFilePath(directory);
|
|
36764
|
-
if (!
|
|
36871
|
+
if (!existsSync4(filePath)) {
|
|
36765
36872
|
return false;
|
|
36766
36873
|
}
|
|
36767
36874
|
try {
|
|
36768
|
-
|
|
36875
|
+
unlinkSync2(filePath);
|
|
36769
36876
|
return true;
|
|
36770
36877
|
} catch (error95) {
|
|
36771
36878
|
log(`[${MISSION_CONTROL.LOG_SOURCE}] Failed to clear state: ${error95}`);
|
|
@@ -37251,7 +37358,7 @@ ${commandList}`;
|
|
|
37251
37358
|
// src/core/loop/verification.ts
|
|
37252
37359
|
init_shared();
|
|
37253
37360
|
init_logger();
|
|
37254
|
-
import { existsSync as
|
|
37361
|
+
import { existsSync as existsSync5, readFileSync as readFileSync4 } from "node:fs";
|
|
37255
37362
|
import { join as join7 } from "node:path";
|
|
37256
37363
|
var CHECKLIST_FILE = CHECKLIST.FILE;
|
|
37257
37364
|
function parseChecklistLine(line, currentCategory) {
|
|
@@ -37318,11 +37425,11 @@ function parseChecklist(content) {
|
|
|
37318
37425
|
}
|
|
37319
37426
|
function readChecklist(directory) {
|
|
37320
37427
|
const filePath = join7(directory, CHECKLIST_FILE);
|
|
37321
|
-
if (!
|
|
37428
|
+
if (!existsSync5(filePath)) {
|
|
37322
37429
|
return [];
|
|
37323
37430
|
}
|
|
37324
37431
|
try {
|
|
37325
|
-
const content =
|
|
37432
|
+
const content = readFileSync4(filePath, "utf-8");
|
|
37326
37433
|
return parseChecklist(content);
|
|
37327
37434
|
} catch (error95) {
|
|
37328
37435
|
log(`[checklist] Failed to read checklist: ${error95}`);
|
|
@@ -37340,7 +37447,7 @@ function verifyChecklist(directory) {
|
|
|
37340
37447
|
errors: []
|
|
37341
37448
|
};
|
|
37342
37449
|
const filePath = join7(directory, CHECKLIST_FILE);
|
|
37343
|
-
if (!
|
|
37450
|
+
if (!existsSync5(filePath)) {
|
|
37344
37451
|
result.errors.push(`Verification checklist not found at ${CHECKLIST_FILE}`);
|
|
37345
37452
|
result.errors.push("Create checklist with at least: build, tests, and any environment-specific checks");
|
|
37346
37453
|
return result;
|
|
@@ -37417,9 +37524,9 @@ function verifyMissionCompletion(directory) {
|
|
|
37417
37524
|
}
|
|
37418
37525
|
}
|
|
37419
37526
|
const todoPath = join7(directory, PATHS.TODO);
|
|
37420
|
-
if (
|
|
37527
|
+
if (existsSync5(todoPath)) {
|
|
37421
37528
|
try {
|
|
37422
|
-
const content =
|
|
37529
|
+
const content = readFileSync4(todoPath, "utf-8");
|
|
37423
37530
|
const incompleteCount = countMatches(content, TODO_INCOMPLETE_PATTERN);
|
|
37424
37531
|
const completeCount = countMatches(content, TODO_COMPLETE_PATTERN);
|
|
37425
37532
|
const total = incompleteCount + completeCount;
|
|
@@ -37442,9 +37549,9 @@ function verifyMissionCompletion(directory) {
|
|
|
37442
37549
|
result.errors.push(`TODO file not found at ${PATHS.TODO}`);
|
|
37443
37550
|
}
|
|
37444
37551
|
const syncPath = join7(directory, PATHS.SYNC_ISSUES);
|
|
37445
|
-
if (
|
|
37552
|
+
if (existsSync5(syncPath)) {
|
|
37446
37553
|
try {
|
|
37447
|
-
const content =
|
|
37554
|
+
const content = readFileSync4(syncPath, "utf-8");
|
|
37448
37555
|
result.syncIssuesEmpty = !hasRealSyncIssues(content);
|
|
37449
37556
|
if (!result.syncIssuesEmpty) {
|
|
37450
37557
|
const issueLines = content.split("\n").filter(
|
|
@@ -37532,7 +37639,7 @@ function buildVerificationSummary(result) {
|
|
|
37532
37639
|
init_logger();
|
|
37533
37640
|
import { exec as exec2 } from "node:child_process";
|
|
37534
37641
|
import { promisify as promisify2 } from "node:util";
|
|
37535
|
-
import { readFileSync as
|
|
37642
|
+
import { readFileSync as readFileSync5 } from "node:fs";
|
|
37536
37643
|
|
|
37537
37644
|
// src/shared/notification/os-notify/constants/notification-commands.ts
|
|
37538
37645
|
var NOTIFICATION_COMMANDS = {
|
|
@@ -37610,7 +37717,7 @@ async function notifyDarwin(title, message) {
|
|
|
37610
37717
|
function isWSL() {
|
|
37611
37718
|
try {
|
|
37612
37719
|
if (process.env.WSL_DISTRO_NAME || process.env.WSLENV) return true;
|
|
37613
|
-
const procVersion =
|
|
37720
|
+
const procVersion = readFileSync5("/proc/version", "utf-8");
|
|
37614
37721
|
return /microsoft|WSL/i.test(procVersion);
|
|
37615
37722
|
} catch {
|
|
37616
37723
|
return false;
|
|
@@ -39131,9 +39238,9 @@ import * as path6 from "node:path";
|
|
|
39131
39238
|
|
|
39132
39239
|
// src/core/cache/utils.ts
|
|
39133
39240
|
import * as fs6 from "node:fs/promises";
|
|
39134
|
-
import { existsSync as
|
|
39241
|
+
import { existsSync as existsSync7 } from "node:fs";
|
|
39135
39242
|
async function ensureCacheDir() {
|
|
39136
|
-
if (!
|
|
39243
|
+
if (!existsSync7(CACHE_DIR)) {
|
|
39137
39244
|
await fs6.mkdir(CACHE_DIR, { recursive: true });
|
|
39138
39245
|
}
|
|
39139
39246
|
}
|
|
@@ -39635,14 +39742,14 @@ var backgroundTaskManager = BackgroundTaskManager.instance;
|
|
|
39635
39742
|
|
|
39636
39743
|
// src/tools/rust-pool.ts
|
|
39637
39744
|
import { spawn as spawn2 } from "child_process";
|
|
39638
|
-
import { existsSync as
|
|
39745
|
+
import { existsSync as existsSync10 } from "fs";
|
|
39639
39746
|
|
|
39640
39747
|
// src/utils/binary.ts
|
|
39641
39748
|
init_shared();
|
|
39642
39749
|
import { join as join12, dirname as dirname5 } from "path";
|
|
39643
39750
|
import { fileURLToPath } from "url";
|
|
39644
39751
|
import { platform, arch } from "os";
|
|
39645
|
-
import { existsSync as
|
|
39752
|
+
import { existsSync as existsSync9 } from "fs";
|
|
39646
39753
|
var __dirname = dirname5(fileURLToPath(import.meta.url));
|
|
39647
39754
|
function getPlatformBinaryName(os = platform(), cpu = arch()) {
|
|
39648
39755
|
if (os === PLATFORM.WIN32) {
|
|
@@ -39663,7 +39770,7 @@ function resolveBinaryPath(options = {}) {
|
|
|
39663
39770
|
const moduleDir = options.moduleDir ?? __dirname;
|
|
39664
39771
|
const os = options.os ?? platform();
|
|
39665
39772
|
const cpu = options.cpu ?? arch();
|
|
39666
|
-
const exists = options.exists ??
|
|
39773
|
+
const exists = options.exists ?? existsSync9;
|
|
39667
39774
|
const binaryName = getPlatformBinaryName(os, cpu);
|
|
39668
39775
|
for (const binDir of getCandidateBinDirs(moduleDir)) {
|
|
39669
39776
|
const binaryPath = join12(binDir, binaryName);
|
|
@@ -39702,7 +39809,7 @@ var RustToolPool = class {
|
|
|
39702
39809
|
constructor(maxSize = 4, options = {}) {
|
|
39703
39810
|
this.maxSize = maxSize;
|
|
39704
39811
|
this.binaryPath = options.binaryPath ?? getBinaryPath;
|
|
39705
|
-
this.exists = options.exists ??
|
|
39812
|
+
this.exists = options.exists ?? existsSync10;
|
|
39706
39813
|
this.idleTimeout = options.idleTimeoutMs ?? this.idleTimeout;
|
|
39707
39814
|
this.processReadyDelay = options.processReadyDelayMs ?? this.processReadyDelay;
|
|
39708
39815
|
this.requestTimeout = options.requestTimeoutMs ?? this.requestTimeout;
|
|
@@ -42478,7 +42585,7 @@ Wait for these tasks to complete before concluding the mission.
|
|
|
42478
42585
|
init_shared();
|
|
42479
42586
|
|
|
42480
42587
|
// src/core/knowledge/context-provider.ts
|
|
42481
|
-
import { existsSync as
|
|
42588
|
+
import { existsSync as existsSync11, readFileSync as readFileSync7, readdirSync as readdirSync2 } from "node:fs";
|
|
42482
42589
|
import path10 from "node:path";
|
|
42483
42590
|
|
|
42484
42591
|
// src/core/knowledge/graph-parser.ts
|
|
@@ -42772,7 +42879,7 @@ var HybridSearch = class {
|
|
|
42772
42879
|
};
|
|
42773
42880
|
|
|
42774
42881
|
// src/core/knowledge/tag-indexer.ts
|
|
42775
|
-
import { readFileSync as
|
|
42882
|
+
import { readFileSync as readFileSync6 } from "node:fs";
|
|
42776
42883
|
var TagIndexer = class {
|
|
42777
42884
|
tagMap = /* @__PURE__ */ new Map();
|
|
42778
42885
|
fileCache = /* @__PURE__ */ new Map();
|
|
@@ -42846,7 +42953,7 @@ var TagIndexer = class {
|
|
|
42846
42953
|
*/
|
|
42847
42954
|
indexFileFromDisk(filePath) {
|
|
42848
42955
|
try {
|
|
42849
|
-
const content =
|
|
42956
|
+
const content = readFileSync6(filePath, "utf8");
|
|
42850
42957
|
this.indexFile(filePath, content);
|
|
42851
42958
|
} catch {
|
|
42852
42959
|
this.clearIndexForFile(filePath);
|
|
@@ -42946,6 +43053,7 @@ var MAX_RESULTS = 3;
|
|
|
42946
43053
|
var MAX_SNIPPET_CHARS = 220;
|
|
42947
43054
|
var KNOWLEDGE_ROOTS = ["docs", path10.join(".opencode", "docs")];
|
|
42948
43055
|
var SKIP_SEGMENTS = /* @__PURE__ */ new Set(["node_modules", "dist", "bin", ".git", "archive"]);
|
|
43056
|
+
var GENERATED_SCRATCHPAD_PATH = path10.join(".opencode", "docs", "brain", "scratchpad.md");
|
|
42949
43057
|
var KnowledgeContextProvider = class {
|
|
42950
43058
|
buildPrompt(directory, query) {
|
|
42951
43059
|
const normalizedQuery = query.trim();
|
|
@@ -42961,14 +43069,14 @@ var KnowledgeContextProvider = class {
|
|
|
42961
43069
|
const files = [];
|
|
42962
43070
|
for (const root of KNOWLEDGE_ROOTS) {
|
|
42963
43071
|
const fullRoot = path10.join(directory, root);
|
|
42964
|
-
if (!
|
|
43072
|
+
if (!existsSync11(fullRoot)) continue;
|
|
42965
43073
|
files.push(...this.walkDirectory(fullRoot));
|
|
42966
43074
|
}
|
|
42967
|
-
return files.sort();
|
|
43075
|
+
return files.filter((filePath) => !this.isDirectInjectedScratchpad(directory, filePath)).sort();
|
|
42968
43076
|
}
|
|
42969
43077
|
walkDirectory(directory) {
|
|
42970
43078
|
const files = [];
|
|
42971
|
-
for (const entry of
|
|
43079
|
+
for (const entry of readdirSync2(directory, { withFileTypes: true })) {
|
|
42972
43080
|
const fullPath = path10.join(directory, entry.name);
|
|
42973
43081
|
if (entry.isDirectory()) {
|
|
42974
43082
|
if (SKIP_SEGMENTS.has(entry.name)) continue;
|
|
@@ -42989,7 +43097,7 @@ var KnowledgeContextProvider = class {
|
|
|
42989
43097
|
const noteToSnippet = /* @__PURE__ */ new Map();
|
|
42990
43098
|
for (const filePath of files) {
|
|
42991
43099
|
try {
|
|
42992
|
-
const content =
|
|
43100
|
+
const content = readFileSync7(filePath, "utf8");
|
|
42993
43101
|
const noteName = graphParser.getNoteName(filePath);
|
|
42994
43102
|
const { body } = tagIndexer.parseFrontmatter(content);
|
|
42995
43103
|
const normalizedBody = body.trim();
|
|
@@ -43009,6 +43117,9 @@ var KnowledgeContextProvider = class {
|
|
|
43009
43117
|
if (normalized.length <= MAX_SNIPPET_CHARS) return normalized;
|
|
43010
43118
|
return `${normalized.slice(0, MAX_SNIPPET_CHARS)}...`;
|
|
43011
43119
|
}
|
|
43120
|
+
isDirectInjectedScratchpad(directory, filePath) {
|
|
43121
|
+
return path10.relative(directory, filePath) === GENERATED_SCRATCHPAD_PATH;
|
|
43122
|
+
}
|
|
43012
43123
|
formatPrompt(query, results, indexed) {
|
|
43013
43124
|
const lines = [
|
|
43014
43125
|
"<knowledge_rag_context>",
|
|
@@ -43050,13 +43161,17 @@ function createSystemTransformHandler(ctx) {
|
|
|
43050
43161
|
const { commander: commander2 } = await Promise.resolve().then(() => (init_commander(), commander_exports));
|
|
43051
43162
|
systemAdditions.push(commander2.systemPrompt);
|
|
43052
43163
|
systemAdditions.push(buildMissionLoopSystemPrompt(loopState));
|
|
43164
|
+
const scratchpadPrompt = buildMissionScratchpadPrompt(directory);
|
|
43165
|
+
if (scratchpadPrompt) {
|
|
43166
|
+
systemAdditions.push(scratchpadPrompt);
|
|
43167
|
+
}
|
|
43053
43168
|
}
|
|
43054
43169
|
if (session?.active) {
|
|
43055
43170
|
systemAdditions.push(buildActiveSessionPrompt(session.step));
|
|
43056
43171
|
}
|
|
43057
43172
|
const knowledgePrompt = buildKnowledgeContextPrompt(
|
|
43058
43173
|
directory,
|
|
43059
|
-
loopState
|
|
43174
|
+
loopState,
|
|
43060
43175
|
state2.sessions.get(sessionID)?.currentTask
|
|
43061
43176
|
);
|
|
43062
43177
|
if (knowledgePrompt) {
|
|
@@ -43077,10 +43192,24 @@ function createSystemTransformHandler(ctx) {
|
|
|
43077
43192
|
}
|
|
43078
43193
|
};
|
|
43079
43194
|
}
|
|
43080
|
-
function buildKnowledgeContextPrompt(directory,
|
|
43081
|
-
const queryParts = [
|
|
43195
|
+
function buildKnowledgeContextPrompt(directory, loopState, currentTask) {
|
|
43196
|
+
const queryParts = [
|
|
43197
|
+
loopState?.objective ?? "",
|
|
43198
|
+
loopState?.prompt ?? "",
|
|
43199
|
+
currentTask ?? "",
|
|
43200
|
+
loopState?.lastProgress ?? "",
|
|
43201
|
+
loopState?.lastVerificationSummary ?? "",
|
|
43202
|
+
loopState?.lastContinuationReason ?? ""
|
|
43203
|
+
].filter(Boolean);
|
|
43082
43204
|
return knowledgeContextProvider.buildPrompt(directory, queryParts.join(" ").trim());
|
|
43083
43205
|
}
|
|
43206
|
+
function buildMissionScratchpadPrompt(directory) {
|
|
43207
|
+
const snapshot = readMissionScratchpadSnapshot(directory);
|
|
43208
|
+
if (!snapshot) return null;
|
|
43209
|
+
return `<mission_scratchpad path="${PATHS.DOCS}/brain/scratchpad.md">
|
|
43210
|
+
${snapshot}
|
|
43211
|
+
</mission_scratchpad>`;
|
|
43212
|
+
}
|
|
43084
43213
|
function buildMissionLoopSystemPrompt(loopState) {
|
|
43085
43214
|
return `<orchestrator_mission_loop>
|
|
43086
43215
|
\u{1F3AF} MISSION LOOP ACTIVE: Iteration ${loopState.iteration}/${loopState.maxIterations}
|
|
@@ -21,5 +21,5 @@ export declare const MISSION_MESSAGES: {
|
|
|
21
21
|
};
|
|
22
22
|
export declare const COMPACTION_PROMPT: string;
|
|
23
23
|
export declare const CONTINUE_INSTRUCTION: string;
|
|
24
|
-
export declare const STAGNATION_INTERVENTION = "\n<system_intervention type=\"stagnation_detected\">\n\u26A0\uFE0F
|
|
24
|
+
export declare const STAGNATION_INTERVENTION = "\n<system_intervention type=\"stagnation_detected\">\n\u26A0\uFE0F **WARNING: STAGNATION DETECTED**\nNo substantive progress has been detected for the past several turns. Repeating the same action or merely \"monitoring\" is prohibited.\n\n**Guidelines for Autonomous Diagnosis and Resolution:**\n1. **Check Real-time Logs**: Use `check_background_task` or `read_file` to directly check the output logs of the running task.\n2. **Process Liveness Diagnosis**: If the task appears to be in a zombie state or hung, proactively `kill` it, break down the steps, and run it again.\n3. **Strategy Pivot**: If the same approach keeps failing, use alternative tools or methods to reach the goal.\n\n**Intervene proactively right now. Do not wait.**\n</system_intervention>";
|
|
25
25
|
export declare const CLEANUP_INSTRUCTION = "\n<system_maintenance type=\"continuous_hygiene\">\n\uD83E\uDDF9 **DOCUMENTATION & STATE HYGIENE (Iteration %ITER%)**\nYou must maintain a pristine workspace. **As part of your move**, perform these checks:\n\n1. **Relevance Assessment**:\n - Review active documents (`.opencode/*.md`). Are they needed for the *current* objective?\n - If a file represents a solved problem or obsolete context, **Archive it** to `.opencode/archive/` or delete it.\n\n2. **Synchronization**:\n - Verify `TODO.md` matches the actual code state. Mark completed items immediately.\n - Check `sync-issues.md`. If issues are resolved, remove them.\n\n3. **Context Optimization**:\n - If `work-log.md` is getting noisy, summarize key decisions into `summary.md` and truncate the log.\n - Keep context lightweight.\n\n**Rule**: A cluttered workspace leads to hallucinations. Clean as you go.\n</system_maintenance>\n";
|
package/package.json
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
"name": "opencode-orchestrator",
|
|
3
3
|
"displayName": "OpenCode Orchestrator",
|
|
4
4
|
"description": "Multi-agent mission control for OpenCode with Commander, Planner, Worker, and Reviewer workflows.",
|
|
5
|
-
"version": "1.
|
|
5
|
+
"version": "1.5.0",
|
|
6
6
|
"author": "agnusdei1207",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
10
10
|
"url": "git+https://github.com/agnusdei1207/opencode-orchestrator.git"
|
|
11
11
|
},
|
|
12
|
-
"homepage": "https://github.
|
|
12
|
+
"homepage": "https://agnusdei1207.github.io/opencode-orchestrator/",
|
|
13
13
|
"bugs": {
|
|
14
14
|
"url": "https://github.com/agnusdei1207/opencode-orchestrator/issues"
|
|
15
15
|
},
|
|
@@ -74,8 +74,8 @@
|
|
|
74
74
|
"node": ">=24"
|
|
75
75
|
},
|
|
76
76
|
"dependencies": {
|
|
77
|
-
"@opencode-ai/plugin": "1.17.
|
|
78
|
-
"@opencode-ai/sdk": "1.17.
|
|
77
|
+
"@opencode-ai/plugin": "1.17.4",
|
|
78
|
+
"@opencode-ai/sdk": "1.17.4",
|
|
79
79
|
"jsonc-parser": "^3.3.1",
|
|
80
80
|
"zod": "^4.3.6"
|
|
81
81
|
},
|