opencode-orchestrator 0.9.47 → 0.9.50

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.
@@ -12,3 +12,4 @@ export { COMMANDER_AGENTS } from "./agents.js";
12
12
  export { COMMANDER_TODO_FORMAT } from "./todo-format.js";
13
13
  export { COMMANDER_LOOP_CONTINUATION } from "./loop-continuation.js";
14
14
  export { COMMANDER_SYNC_HANDLING } from "./sync-handling.js";
15
+ export { COMMANDER_RECOVERY } from "./recovery.js";
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Commander Recovery Strategy
3
+ *
4
+ * How to handle agent failures, timeouts, and stuck situations.
5
+ */
6
+ export declare const COMMANDER_RECOVERY: string;
package/dist/index.js CHANGED
@@ -203,6 +203,17 @@ var HISTORY = {
203
203
  MAX_PROGRESS: 100
204
204
  };
205
205
 
206
+ // src/shared/recovery/constants/recovery-level.ts
207
+ var RECOVERY_LEVEL = {
208
+ /** Level 1: Split task into smaller units */
209
+ DECOMPOSE: "DECOMPOSE",
210
+ /** Level 2: Step back and create new strategy */
211
+ RE_PLAN: "RE-PLAN",
212
+ /** Level 3: Ask user for direction */
213
+ ASK_USER: "ASK USER"
214
+ };
215
+ var RECOVERY_PRINCIPLE = "DECOMPOSE \u2192 RE-PLAN \u2192 ASK. Never give up silently.";
216
+
206
217
  // src/shared/cache/constants/cache.ts
207
218
  var CACHE = {
208
219
  /** Default cache TTL (24 hours) */
@@ -297,6 +308,18 @@ var TOOL_NAMES = {
297
308
  GREP_SEARCH: "grep_search",
298
309
  GLOB_SEARCH: "glob_search",
299
310
  MGREP: "mgrep",
311
+ SED_REPLACE: "sed_replace",
312
+ // Diff & Compare tools
313
+ DIFF: "diff",
314
+ // JSON tools
315
+ JQ: "jq",
316
+ // HTTP tools
317
+ HTTP: "http",
318
+ // File tools
319
+ FILE_STATS: "file_stats",
320
+ // Git tools
321
+ GIT_DIFF: "git_diff",
322
+ GIT_STATUS: "git_status",
300
323
  // Web tools
301
324
  WEBFETCH: "webfetch",
302
325
  WEBSEARCH: "websearch",
@@ -412,6 +435,7 @@ var PROMPT_TAGS = {
412
435
  TODO_FORMAT: { open: "<todo_format>", close: "</todo_format>" },
413
436
  SYNC_ISSUE_HANDLING: { open: "<sync_issue_handling>", close: "</sync_issue_handling>" },
414
437
  LOOP_CONTINUATION: { open: "<loop_continuation>", close: "</loop_continuation>" },
438
+ RECOVERY: { open: "<recovery>", close: "</recovery>" },
415
439
  // === Planner ===
416
440
  FILE_LEVEL_PLANNING: { open: "<file_level_planning>", close: "</file_level_planning>" },
417
441
  TODO_SYNC: { open: "<todo_sync>", close: "</todo_sync>" },
@@ -13378,6 +13402,7 @@ var COMMANDER_FORBIDDEN = `${PROMPT_TAGS.FORBIDDEN_ACTIONS.open}
13378
13402
  - NEVER stop mid-mission to ask for permission
13379
13403
  - NEVER wait for user input during execution
13380
13404
  - NEVER output ${MISSION_SEAL.PATTERN} before ALL todos are [x]
13405
+ - If stuck \u2192 See ${PROMPT_TAGS.RECOVERY.open}: DECOMPOSE task smaller and retry
13381
13406
 
13382
13407
  ## Never Micromanage
13383
13408
  - NEVER execute tasks one-by-one when parallel is possible
@@ -13460,6 +13485,7 @@ var COMMANDER_EXECUTION = `${PROMPT_TAGS.EXECUTION_STRATEGY.open}
13460
13485
  - What are the HIGH-RISK parts of this mission?
13461
13486
  - What is my FALLBACK if a task fails?
13462
13487
  - How will I DETECT and RECOVER from issues?
13488
+ - If agent fails \u2192 See ${PROMPT_TAGS.RECOVERY.open} section: DECOMPOSE and retry
13463
13489
 
13464
13490
  \u274C ANTI-PATTERNS: Sequential execution when parallel is possible. Doing work yourself instead of delegating. Starting without clear decomposition.
13465
13491
 
@@ -13630,6 +13656,7 @@ ONLY THEN \u2192 output ${MISSION_SEAL.PATTERN}
13630
13656
  \u274C ${PATHS.SYNC_ISSUES} > 0 \u2192 LOOP
13631
13657
  \u274C Build fails \u2192 LOOP
13632
13658
  \u274C E2E = ${WORK_STATUS.E2E_STATUS.FAIL} \u2192 LOOP
13659
+ \u274C Agent timeout/stuck \u2192 DECOMPOSE per ${PROMPT_TAGS.RECOVERY.open} and LOOP
13633
13660
  \`\`\`
13634
13661
 
13635
13662
  ### \u26D4 NEVER SEAL IF:
@@ -13763,6 +13790,43 @@ ${AGENT_NAMES.REVIEWER}: (Integration test + sync check + clear ${PATHS.SYNC_ISS
13763
13790
  - Workers need: file path + issue ID + exact fix instructions
13764
13791
  ${PROMPT_TAGS.SYNC_ISSUE_HANDLING.close}`;
13765
13792
 
13793
+ // src/agents/prompts/commander/recovery.ts
13794
+ var COMMANDER_RECOVERY = `${PROMPT_TAGS.RECOVERY.open}
13795
+ ## RECOVERY: Agent Failure Handling
13796
+
13797
+ When any agent fails, times out, or gets stuck:
13798
+
13799
+ ### Level 1: ${RECOVERY_LEVEL.DECOMPOSE}
13800
+ - Task is too big \u2192 Split into smaller units (< 5 min each)
13801
+ - Delegate smaller pieces to fresh agents
13802
+ - For repetitive changes, use ${TOOL_NAMES.SED_REPLACE} or shell tools
13803
+
13804
+ ### Level 2: ${RECOVERY_LEVEL.RE_PLAN}
13805
+ If decomposition still fails:
13806
+ - Step back and re-analyze the problem
13807
+ - Write ${PATHS.OPENCODE}/escalation.md with analysis
13808
+ - Call ${AGENT_NAMES.PLANNER} to create new strategy
13809
+ - Try different approach
13810
+
13811
+ ### Level 3: ${RECOVERY_LEVEL.ASK_USER}
13812
+ If re-planning fails or requires human judgment:
13813
+ - Clearly explain the situation and what was tried
13814
+ - Present 2-3 options with pros/cons
13815
+ - Ask user for direction
13816
+ - Proceed based on user input
13817
+
13818
+ ### Decision Guide
13819
+ | Situation | Action |
13820
+ |-----------|--------|
13821
+ | Task too big | Level 1: ${RECOVERY_LEVEL.DECOMPOSE} |
13822
+ | Wrong approach | Level 2: ${RECOVERY_LEVEL.RE_PLAN} |
13823
+ | Ambiguous requirements | Level 3: ${RECOVERY_LEVEL.ASK_USER} |
13824
+ | Critical decision needed | Level 3: ${RECOVERY_LEVEL.ASK_USER} |
13825
+ | All attempts failed | Level 3: ${RECOVERY_LEVEL.ASK_USER} |
13826
+
13827
+ PRINCIPLE: ${RECOVERY_PRINCIPLE}
13828
+ ${PROMPT_TAGS.RECOVERY.close}`;
13829
+
13766
13830
  // src/agents/prompts/planner/role.ts
13767
13831
  var PLANNER_ROLE = `${PROMPT_TAGS.ROLE.open}
13768
13832
  You are ${AGENT_NAMES.PLANNER}. Strategic planner and researcher.
@@ -14842,6 +14906,7 @@ var systemPrompt = [
14842
14906
  // Loop, shared state, sync handling
14843
14907
  COMMANDER_LOOP_CONTINUATION,
14844
14908
  COMMANDER_SYNC_HANDLING,
14909
+ COMMANDER_RECOVERY,
14845
14910
  SHARED_WORKSPACE,
14846
14911
  ANTI_HALLUCINATION_CORE,
14847
14912
  MISSION_SEAL_RULES
@@ -15212,6 +15277,102 @@ var mgrepTool = (directory) => tool({
15212
15277
  return JSON.stringify(results, null, 2);
15213
15278
  }
15214
15279
  });
15280
+ var sedReplaceTool = (directory) => tool({
15281
+ description: `Find and replace patterns in files (sed-like). Supports regex. Use dry_run=true to preview changes.`,
15282
+ args: {
15283
+ pattern: tool.schema.string().describe("Regex pattern to find"),
15284
+ replacement: tool.schema.string().describe("Replacement string"),
15285
+ file: tool.schema.string().optional().describe("Single file to modify"),
15286
+ dir: tool.schema.string().optional().describe("Directory to search (modifies all matching files)"),
15287
+ dry_run: tool.schema.boolean().optional().describe("Preview changes without modifying files (default: false)"),
15288
+ backup: tool.schema.boolean().optional().describe("Create .bak backup before modifying (default: false)")
15289
+ },
15290
+ async execute(args) {
15291
+ return callRustTool("sed_replace", {
15292
+ pattern: args.pattern,
15293
+ replacement: args.replacement,
15294
+ file: args.file,
15295
+ directory: args.dir || (args.file ? void 0 : directory),
15296
+ dry_run: args.dry_run,
15297
+ backup: args.backup
15298
+ });
15299
+ }
15300
+ });
15301
+ var diffTool = () => tool({
15302
+ description: `Compare two files or strings and show differences.`,
15303
+ args: {
15304
+ file1: tool.schema.string().optional().describe("First file to compare"),
15305
+ file2: tool.schema.string().optional().describe("Second file to compare"),
15306
+ content1: tool.schema.string().optional().describe("First string to compare"),
15307
+ content2: tool.schema.string().optional().describe("Second string to compare"),
15308
+ ignore_whitespace: tool.schema.boolean().optional().describe("Ignore whitespace differences")
15309
+ },
15310
+ async execute(args) {
15311
+ return callRustTool("diff", args);
15312
+ }
15313
+ });
15314
+ var jqTool = () => tool({
15315
+ description: `Query and manipulate JSON using jq expressions.`,
15316
+ args: {
15317
+ json_input: tool.schema.string().optional().describe("JSON string to query"),
15318
+ file: tool.schema.string().optional().describe("JSON file to query"),
15319
+ expression: tool.schema.string().describe("jq expression (e.g., '.foo.bar', '.[] | select(.x > 1)')"),
15320
+ raw_output: tool.schema.boolean().optional().describe("Raw output (no JSON encoding for strings)")
15321
+ },
15322
+ async execute(args) {
15323
+ return callRustTool("jq", args);
15324
+ }
15325
+ });
15326
+ var httpTool = () => tool({
15327
+ description: `Make HTTP requests (GET, POST, PUT, DELETE, etc).`,
15328
+ args: {
15329
+ url: tool.schema.string().describe("URL to request"),
15330
+ method: tool.schema.string().optional().describe("HTTP method (GET, POST, PUT, DELETE, PATCH, HEAD)"),
15331
+ headers: tool.schema.object({}).optional().describe("Request headers as JSON object"),
15332
+ body: tool.schema.string().optional().describe("Request body"),
15333
+ timeout_ms: tool.schema.number().optional().describe("Request timeout in milliseconds")
15334
+ },
15335
+ async execute(args) {
15336
+ return callRustTool("http", args);
15337
+ }
15338
+ });
15339
+ var fileStatsTool = (directory) => tool({
15340
+ description: `Analyze file/directory statistics (file counts, sizes, line counts, etc).`,
15341
+ args: {
15342
+ dir: tool.schema.string().optional().describe("Directory to analyze (defaults to project root)"),
15343
+ max_depth: tool.schema.number().optional().describe("Maximum directory depth to analyze")
15344
+ },
15345
+ async execute(args) {
15346
+ return callRustTool("file_stats", {
15347
+ directory: args.dir || directory,
15348
+ max_depth: args.max_depth
15349
+ });
15350
+ }
15351
+ });
15352
+ var gitDiffTool = (directory) => tool({
15353
+ description: `Show git diff of uncommitted changes.`,
15354
+ args: {
15355
+ dir: tool.schema.string().optional().describe("Repository directory (defaults to project root)"),
15356
+ staged_only: tool.schema.boolean().optional().describe("Show only staged changes")
15357
+ },
15358
+ async execute(args) {
15359
+ return callRustTool("git_diff", {
15360
+ directory: args.dir || directory,
15361
+ staged_only: args.staged_only
15362
+ });
15363
+ }
15364
+ });
15365
+ var gitStatusTool = (directory) => tool({
15366
+ description: `Show git status (modified, added, deleted files).`,
15367
+ args: {
15368
+ dir: tool.schema.string().optional().describe("Repository directory (defaults to project root)")
15369
+ },
15370
+ async execute(args) {
15371
+ return callRustTool("git_status", {
15372
+ directory: args.dir || directory
15373
+ });
15374
+ }
15375
+ });
15215
15376
 
15216
15377
  // src/core/commands/manager.ts
15217
15378
  import { spawn as spawn2 } from "child_process";
@@ -19537,9 +19698,22 @@ var OrchestratorPlugin = async (input) => {
19537
19698
  tool: {
19538
19699
  [TOOL_NAMES.CALL_AGENT]: callAgentTool,
19539
19700
  [TOOL_NAMES.SLASHCOMMAND]: createSlashcommandTool(),
19701
+ // Search & Replace tools
19540
19702
  [TOOL_NAMES.GREP_SEARCH]: grepSearchTool(directory),
19541
19703
  [TOOL_NAMES.GLOB_SEARCH]: globSearchTool(directory),
19542
19704
  [TOOL_NAMES.MGREP]: mgrepTool(directory),
19705
+ [TOOL_NAMES.SED_REPLACE]: sedReplaceTool(directory),
19706
+ // Diff & Compare tools
19707
+ [TOOL_NAMES.DIFF]: diffTool(),
19708
+ // JSON tools
19709
+ [TOOL_NAMES.JQ]: jqTool(),
19710
+ // HTTP tools
19711
+ [TOOL_NAMES.HTTP]: httpTool(),
19712
+ // File tools
19713
+ [TOOL_NAMES.FILE_STATS]: fileStatsTool(directory),
19714
+ // Git tools
19715
+ [TOOL_NAMES.GIT_DIFF]: gitDiffTool(directory),
19716
+ [TOOL_NAMES.GIT_STATUS]: gitStatusTool(directory),
19543
19717
  // Background task tools
19544
19718
  [TOOL_NAMES.RUN_BACKGROUND]: runBackgroundTool,
19545
19719
  [TOOL_NAMES.CHECK_BACKGROUND]: checkBackgroundTool,
@@ -77,6 +77,10 @@ export declare const PROMPT_TAGS: {
77
77
  readonly open: "<loop_continuation>";
78
78
  readonly close: "</loop_continuation>";
79
79
  };
80
+ readonly RECOVERY: {
81
+ readonly open: "<recovery>";
82
+ readonly close: "</recovery>";
83
+ };
80
84
  readonly FILE_LEVEL_PLANNING: {
81
85
  readonly open: "<file_level_planning>";
82
86
  readonly close: "</file_level_planning>";
@@ -3,3 +3,4 @@
3
3
  */
4
4
  export { RECOVERY } from "./recovery.js";
5
5
  export { HISTORY } from "./history.js";
6
+ export { RECOVERY_LEVEL, RECOVERY_PRINCIPLE } from "./recovery-level.js";
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Recovery Level Constants
3
+ *
4
+ * Escalation levels for agent failure handling.
5
+ */
6
+ export declare const RECOVERY_LEVEL: {
7
+ /** Level 1: Split task into smaller units */
8
+ readonly DECOMPOSE: "DECOMPOSE";
9
+ /** Level 2: Step back and create new strategy */
10
+ readonly RE_PLAN: "RE-PLAN";
11
+ /** Level 3: Ask user for direction */
12
+ readonly ASK_USER: "ASK USER";
13
+ };
14
+ export declare const RECOVERY_PRINCIPLE = "DECOMPOSE \u2192 RE-PLAN \u2192 ASK. Never give up silently.";
15
+ export type RecoveryLevel = (typeof RECOVERY_LEVEL)[keyof typeof RECOVERY_LEVEL];
@@ -13,6 +13,13 @@ export declare const TOOL_NAMES: {
13
13
  readonly GREP_SEARCH: "grep_search";
14
14
  readonly GLOB_SEARCH: "glob_search";
15
15
  readonly MGREP: "mgrep";
16
+ readonly SED_REPLACE: "sed_replace";
17
+ readonly DIFF: "diff";
18
+ readonly JQ: "jq";
19
+ readonly HTTP: "http";
20
+ readonly FILE_STATS: "file_stats";
21
+ readonly GIT_DIFF: "git_diff";
22
+ readonly GIT_STATUS: "git_status";
16
23
  readonly WEBFETCH: "webfetch";
17
24
  readonly WEBSEARCH: "websearch";
18
25
  readonly CODESEARCH: "codesearch";
@@ -43,3 +43,124 @@ export declare const mgrepTool: (directory: string) => {
43
43
  dir?: string | undefined;
44
44
  }, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
45
45
  };
46
+ /**
47
+ * Sed replace tool - find and replace patterns in files
48
+ * Used for bulk code migrations and refactoring
49
+ */
50
+ export declare const sedReplaceTool: (directory: string) => {
51
+ description: string;
52
+ args: {
53
+ pattern: import("zod").ZodString;
54
+ replacement: import("zod").ZodString;
55
+ file: import("zod").ZodOptional<import("zod").ZodString>;
56
+ dir: import("zod").ZodOptional<import("zod").ZodString>;
57
+ dry_run: import("zod").ZodOptional<import("zod").ZodBoolean>;
58
+ backup: import("zod").ZodOptional<import("zod").ZodBoolean>;
59
+ };
60
+ execute(args: {
61
+ pattern: string;
62
+ replacement: string;
63
+ file?: string | undefined;
64
+ dir?: string | undefined;
65
+ dry_run?: boolean | undefined;
66
+ backup?: boolean | undefined;
67
+ }, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
68
+ };
69
+ /**
70
+ * Diff tool - compare files or strings
71
+ */
72
+ export declare const diffTool: () => {
73
+ description: string;
74
+ args: {
75
+ file1: import("zod").ZodOptional<import("zod").ZodString>;
76
+ file2: import("zod").ZodOptional<import("zod").ZodString>;
77
+ content1: import("zod").ZodOptional<import("zod").ZodString>;
78
+ content2: import("zod").ZodOptional<import("zod").ZodString>;
79
+ ignore_whitespace: import("zod").ZodOptional<import("zod").ZodBoolean>;
80
+ };
81
+ execute(args: {
82
+ file1?: string | undefined;
83
+ file2?: string | undefined;
84
+ content1?: string | undefined;
85
+ content2?: string | undefined;
86
+ ignore_whitespace?: boolean | undefined;
87
+ }, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
88
+ };
89
+ /**
90
+ * JQ tool - JSON query and manipulation
91
+ */
92
+ export declare const jqTool: () => {
93
+ description: string;
94
+ args: {
95
+ json_input: import("zod").ZodOptional<import("zod").ZodString>;
96
+ file: import("zod").ZodOptional<import("zod").ZodString>;
97
+ expression: import("zod").ZodString;
98
+ raw_output: import("zod").ZodOptional<import("zod").ZodBoolean>;
99
+ };
100
+ execute(args: {
101
+ expression: string;
102
+ json_input?: string | undefined;
103
+ file?: string | undefined;
104
+ raw_output?: boolean | undefined;
105
+ }, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
106
+ };
107
+ /**
108
+ * HTTP tool - make HTTP requests (curl-like)
109
+ */
110
+ export declare const httpTool: () => {
111
+ description: string;
112
+ args: {
113
+ url: import("zod").ZodString;
114
+ method: import("zod").ZodOptional<import("zod").ZodString>;
115
+ headers: import("zod").ZodOptional<import("zod").ZodObject<{}, import("zod/v4/core").$strip>>;
116
+ body: import("zod").ZodOptional<import("zod").ZodString>;
117
+ timeout_ms: import("zod").ZodOptional<import("zod").ZodNumber>;
118
+ };
119
+ execute(args: {
120
+ url: string;
121
+ method?: string | undefined;
122
+ headers?: Record<string, never> | undefined;
123
+ body?: string | undefined;
124
+ timeout_ms?: number | undefined;
125
+ }, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
126
+ };
127
+ /**
128
+ * File stats tool - analyze directory/file statistics
129
+ */
130
+ export declare const fileStatsTool: (directory: string) => {
131
+ description: string;
132
+ args: {
133
+ dir: import("zod").ZodOptional<import("zod").ZodString>;
134
+ max_depth: import("zod").ZodOptional<import("zod").ZodNumber>;
135
+ };
136
+ execute(args: {
137
+ dir?: string | undefined;
138
+ max_depth?: number | undefined;
139
+ }, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
140
+ };
141
+ /**
142
+ * Git diff tool - show uncommitted changes
143
+ */
144
+ export declare const gitDiffTool: (directory: string) => {
145
+ description: string;
146
+ args: {
147
+ dir: import("zod").ZodOptional<import("zod").ZodString>;
148
+ staged_only: import("zod").ZodOptional<import("zod").ZodBoolean>;
149
+ };
150
+ execute(args: {
151
+ dir?: string | undefined;
152
+ staged_only?: boolean | undefined;
153
+ }, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
154
+ };
155
+ /**
156
+ * Git status tool - show repository status
157
+ */
158
+ export declare const gitStatusTool: (directory: string) => {
159
+ description: string;
160
+ args: {
161
+ dir: import("zod").ZodOptional<import("zod").ZodString>;
162
+ };
163
+ execute(args: {
164
+ dir?: string | undefined;
165
+ }, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
166
+ };
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.47",
5
+ "version": "0.9.50",
6
6
  "author": "agnusdei1207",
7
7
  "license": "MIT",
8
8
  "repository": {