opencode-resolve 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -3,28 +3,59 @@
3
3
  [![npm version](https://img.shields.io/npm/v/opencode-resolve.svg)](https://www.npmjs.com/package/opencode-resolve)
4
4
  [![license: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)
5
5
 
6
- Lightweight OpenCode plugin for focused task resolution with minimal agents and native `plan`/`build` preservation.
6
+ Small OpenCode plugin that turns a single instruction into a finished, verified change.
7
7
 
8
- `opencode-resolve` keeps native OpenCode `plan` and `build` behavior intact. It only injects a small set of optional agents so you can keep the useful early Oh My OpenCode-style persistence without a heavy multi-agent swarm.
8
+ `opencode-resolve` ships three roles by default **resolver** (orchestrator), **coder** (implementer), and **reviewer** (read-only auditor) and runs them with auto-approved permissions so a task drives to completion without prompting at every step. It defines roles, not model providers: agents inherit your OpenCode default model unless you pin them.
9
9
 
10
- ## Features
10
+ ---
11
11
 
12
- - Preserves native OpenCode `plan` and `build` behavior.
13
- - Injects only `coder` and `reviewer` by default.
14
- - Uses GLM-style defaults for coding and GPT-style defaults for review.
15
- - Adds a Context7 MCP preset only when one is not already configured.
16
- - Validates config strictly so typos fail fast.
17
- - Keeps Telegram notifications and remote control as companion-plugin concerns.
12
+ ## Table of Contents
18
13
 
19
- ## Install From npm
14
+ - [Roles at a glance](#roles-at-a-glance)
15
+ - [Quick Start](#quick-start)
16
+ - [Drop-in setup (give to an LLM)](#drop-in-setup-give-to-an-llm)
17
+ - [Default Behavior](#default-behavior)
18
+ - [Configuration](#configuration)
19
+ - [Configuration Reference](#configuration-reference)
20
+ - [Auto Approval](#auto-approval)
21
+ - [Parallel Subagent Limit](#parallel-subagent-limit)
22
+ - [Upgrade & Migration](#upgrade--migration)
23
+ - [Model Setup](#model-setup)
24
+ - [Agent Reference](#agent-reference)
25
+ - [Optional Commands](#optional-commands)
26
+ - [Local Development](#local-development)
27
+ - [Verification](#verification)
28
+ - [Release](#release)
29
+ - [Design Rules](#design-rules)
20
30
 
21
- Install this where OpenCode resolves plugins from. For most users, a global install is the simplest option:
31
+ ---
32
+
33
+ ## Roles at a glance
34
+
35
+ | Role | Default | Can edit? | Can run shell? | Purpose |
36
+ |---|:---:|:---:|:---:|---|
37
+ | `resolver` | Yes | Yes (auto) | Yes (auto) | Primary orchestrator. Plans, dispatches `coder` (one at a time), verifies, iterates. |
38
+ | `coder` | Yes | Yes (auto) | Yes (auto) | Focused implementer. Makes the smallest correct change and verifies. |
39
+ | `reviewer` | Yes | **Never** | **Never** | Read-only auditor. Inspects only — recommends fixes for `coder` or `resolver` to apply. |
40
+
41
+ Hard rule: **the reviewer cannot modify the project by any means.** Both `edit` and `bash` are denied for the reviewer regardless of `autoApprove`. Any required fix is routed back through `coder` or `resolver`.
42
+
43
+ ---
44
+
45
+ ## Quick Start
46
+
47
+ Install from npm:
22
48
 
23
49
  ```sh
24
50
  npm install -g opencode-resolve
25
51
  ```
26
52
 
27
- The package automatically registers itself in `~/.config/opencode/opencode.json` during `postinstall` and creates `~/.config/opencode/resolve.json` when missing.
53
+ The package `postinstall` step:
54
+
55
+ 1. Adds `opencode-resolve` to `~/.config/opencode/opencode.json` `plugin` array.
56
+ 2. Creates `~/.config/opencode/resolve.json` from [`opencode-resolve.example.json`](./opencode-resolve.example.json) when missing.
57
+
58
+ Restart OpenCode after installation.
28
59
 
29
60
  To skip automatic registration:
30
61
 
@@ -32,7 +63,7 @@ To skip automatic registration:
32
63
  OPENCODE_RESOLVE_SKIP_POSTINSTALL=1 npm install -g opencode-resolve
33
64
  ```
34
65
 
35
- Manual config fallback:
66
+ Manual fallback: add the plugin to `~/.config/opencode/opencode.json` yourself:
36
67
 
37
68
  ```json
38
69
  {
@@ -40,150 +71,433 @@ Manual config fallback:
40
71
  }
41
72
  ```
42
73
 
43
- The default model IDs assume your OpenCode provider configuration can access Z.AI/GLM and OpenAI/GPT models. Override `models` if your provider IDs differ.
74
+ ---
44
75
 
45
- ## Defaults
76
+ ## Drop-in setup (give to an LLM)
46
77
 
47
- Enabled by default:
78
+ Hand the block below to any reasonably capable LLM along with the instruction _"set up opencode-resolve on this machine"_ and it can finish the install end-to-end. Everything below is the entire required configuration — no other MCP servers, environment variables, or files are needed.
48
79
 
49
- - `coder`: GLM-based implementation agent for edits, tests, and iteration.
50
- - `reviewer`: GPT-based Oracle-style review agent for requirements fit, correctness, security, tests, and maintainability.
80
+ > **Important — OpenCode caches plugins itself.** OpenCode does NOT use globally-installed npm packages. It maintains its own cache at `~/.cache/opencode/packages/`. After the very first install (or any future upgrade), refresh the cache with `opencode plugin opencode-resolve --global --force` and restart OpenCode. `npm install -g` alone is not enough.
51
81
 
52
- Available but disabled unless configured:
82
+ **Step 1 install via OpenCode (also primes the cache):**
53
83
 
54
- - `architect`: GPT-based design and task decomposition.
55
- - `gpt-coder`: GPT-based difficult implementation fallback.
56
- - `debugger`: failure reproduction and root-cause analysis.
57
- - `researcher`: codebase and documentation research.
84
+ ```sh
85
+ opencode plugin opencode-resolve --global --force
86
+ ```
58
87
 
59
- The plugin also adds a `context7` MCP preset when one is not already configured.
88
+ **Step 2 `~/.config/opencode/opencode.json`** (merge into the existing file; do not replace it):
60
89
 
61
- ## Develop Locally
90
+ ```json
91
+ {
92
+ "$schema": "https://opencode.ai/config.json",
93
+ "model": "<your-default-model-id>",
94
+ "plugin": ["opencode-resolve"]
95
+ }
96
+ ```
62
97
 
63
- From this repository:
98
+ **Step 3 — `~/.config/opencode/resolve.json`** (auto-created by `postinstall`; the block below is the recommended canonical setup — copy it verbatim then edit `models` to match your provider):
64
99
 
65
- ```sh
66
- npm install
67
- npm test
68
- npm run install:local
100
+ ```json
101
+ {
102
+ "enabled": ["coder", "reviewer", "resolver"],
103
+ "preserveNative": true,
104
+ "context7": true,
105
+ "commands": false,
106
+ "autoApprove": true,
107
+ "maxParallelSubagents": 2,
108
+ "models": {
109
+ "glm": "zai-coding-plan/glm-5",
110
+ "gpt": "openai/gpt-5.5",
111
+ "coder": "glm",
112
+ "reviewer": "openai/gpt-4o-mini",
113
+ "resolver": "gpt"
114
+ },
115
+ "agents": {
116
+ "coder": { "mode": "all" },
117
+ "reviewer": { "mode": "all" },
118
+ "resolver": { "enabled": true },
119
+ "architect": { "enabled": false },
120
+ "gpt-coder": { "enabled": false },
121
+ "debugger": { "enabled": false },
122
+ "researcher": { "enabled": false }
123
+ }
124
+ }
69
125
  ```
70
126
 
71
- `install:local` builds the plugin, links it into the OpenCode global plugin directory, and creates `~/.config/opencode/resolve.json` if it does not exist.
127
+ **Step 4 restart OpenCode.**
72
128
 
73
- Manual equivalent:
129
+ ### Why this template
74
130
 
75
- ```sh
76
- npm run build
77
- mkdir -p ~/.config/opencode/plugins
78
- ln -sf "$PWD/dist/index.js" ~/.config/opencode/plugins/opencode-resolve.js
131
+ - **`enabled`** activates the three default roles: `coder` implements, `reviewer` audits read-only, `resolver` orchestrates.
132
+ - **`autoApprove: true`** lets `coder` and `resolver` work without per-action approval prompts. `reviewer` stays locked to deny — it cannot modify by any means.
133
+ - **`maxParallelSubagents: 2`** is a per-role cap: up to two coders and up to two reviewers may run concurrently when working on genuinely independent things. Drop to `1` for strict per-role serialization, raise above `2` for more aggressive fan-out.
134
+ - **`agents.coder.mode = "all"` and `agents.reviewer.mode = "all"`** make both visible in the primary agent picker, not just as subagents the resolver dispatches. You can still call them directly when you don't need orchestration.
135
+ - **`agents.resolver.enabled: true`** is explicit (default is also true); ships with `mode: "all"` so it appears as both a primary agent and a subagent.
136
+ - **`models`** uses two aliases (`glm` for fast/cheap implementation, `gpt` for stronger orchestration) and pins reviewer to `gpt-4o-mini` for cheap reads. Replace these with model IDs your provider actually exposes.
137
+ - **`context7`** is the only MCP this plugin auto-registers — no other MCP servers are required.
138
+ - All other resolve agents (`architect`, `gpt-coder`, `debugger`, `researcher`) ship disabled. Flip `enabled: true` only if you want to use them.
139
+
140
+ ### Resolver workflow (what happens when you call it)
141
+
142
+ 1. Resolver reads the request, inspects relevant files.
143
+ 2. Plans the smallest correct change.
144
+ 3. Dispatches `coder` to implement (one at a time).
145
+ 4. Verifies (tests, type checks, targeted checks).
146
+ 5. If issues remain, dispatches `coder` again with a focused fix.
147
+ 6. For risky changes, optionally consults `reviewer` for a read-only audit; routes any required fixes back through `coder`.
148
+ 7. Repeats until the task is resolved or clearly blocked, then returns a concise summary.
149
+
150
+ ---
151
+
152
+ ## Default Behavior
153
+
154
+ | Item | Default |
155
+ |---|---|
156
+ | Enabled agents | `coder`, `reviewer`, `resolver` |
157
+ | Primary agent for new tasks | `resolver` (`mode: "all"`) |
158
+ | Agent model | Inherits top-level OpenCode `model` |
159
+ | Native `plan` / `build` | Preserved untouched |
160
+ | Context7 MCP preset | Added if absent |
161
+ | Optional commands | Disabled |
162
+ | `autoApprove` | `true` (no per-action prompts on coder/resolver) |
163
+ | Reviewer modification | Denied (cannot be auto-approved) |
164
+
165
+ ---
166
+
167
+ ## Configuration
168
+
169
+ The plugin reads the first config file it finds:
170
+
171
+ | Priority | Path |
172
+ |---:|---|
173
+ | 1 | `.opencode/resolve.json` (project) |
174
+ | 2 | `opencode-resolve.json` (project) |
175
+ | 3 | `~/.config/opencode/resolve.json` |
176
+ | 4 | `~/.config/opencode/opencode-resolve.json` |
177
+
178
+ Inline plugin options in `opencode.json` override file config.
179
+
180
+ Config precedence:
181
+
182
+ ```text
183
+ built-in defaults -> first config file found -> inline plugin options
79
184
  ```
80
185
 
81
- Local plugin files are loaded automatically by OpenCode.
186
+ Minimal config (matches defaults):
187
+
188
+ ```json
189
+ {
190
+ "enabled": ["coder", "reviewer", "resolver"],
191
+ "autoApprove": true,
192
+ "context7": true,
193
+ "commands": false
194
+ }
195
+ ```
82
196
 
83
- After publishing/installing from npm, add the package to your OpenCode config:
197
+ Inline form inside `opencode.json`:
84
198
 
85
199
  ```json
86
200
  {
87
- "plugin": ["opencode-resolve"]
201
+ "plugin": [
202
+ [
203
+ "opencode-resolve",
204
+ {
205
+ "enabled": ["coder", "reviewer", "resolver"],
206
+ "autoApprove": true,
207
+ "context7": true,
208
+ "commands": false
209
+ }
210
+ ]
211
+ ]
88
212
  }
89
213
  ```
90
214
 
91
- ## Configuration
215
+ Strict validation rejects unknown agent names, misspelled keys, invalid modes, invalid permission values, and wrong value types — typos fail fast.
92
216
 
93
- The plugin reads the first config file it finds:
217
+ ---
218
+
219
+ ## Configuration Reference
220
+
221
+ Every accepted top-level option:
222
+
223
+ | Key | Type | Default | Purpose |
224
+ |---|---|---|---|
225
+ | `enabled` | `string[]` | `["coder", "reviewer", "resolver"]` | Which resolve agents to inject. Per-agent `agents.<name>.enabled` overrides this. |
226
+ | `preserveNative` | `boolean` | `true` | Native `plan`/`build` are always preserved. Accepted for readability. |
227
+ | `context7` | `boolean` | `true` | When true, registers the Context7 MCP server unless already configured. |
228
+ | `commands` | `boolean` | `false` | When true, adds `resolve`, `resolve-code`, `resolve-review` commands. |
229
+ | `autoApprove` | `boolean` | `true` | Flips default `"ask"` permissions to `"allow"` on enabled agents. Never touches `"deny"` or user-set keys. |
230
+ | `maxParallelSubagents` | `positive integer` | `1` | Cap on simultaneous subagents the resolver dispatches across coder, reviewer, etc. |
231
+ | `models` | `object` | `{}` | Alias map. Keys are agent names or `glm`/`gpt`. Values are model ids or other aliases. |
232
+ | `agents` | `object` | `{}` | Per-agent overrides (see below). |
233
+ | `config` | `string` | _none_ | Custom path to a config file (relative to the project or absolute). |
234
+
235
+ Per-agent options inside `agents.<name>`:
236
+
237
+ | Key | Type | Notes |
238
+ |---|---|---|
239
+ | `enabled` | `boolean` | Force-enable or force-disable this agent regardless of top-level `enabled`. |
240
+ | `model` | `string` | Model id or alias. Resolved against the top-level `models` map. |
241
+ | `mode` | `"subagent" \| "primary" \| "all"` | OpenCode agent mode. |
242
+ | `description` | `string` | Override the default description shown to other agents. |
243
+ | `prompt` | `string` | Override the default system prompt. (For `resolver`, this also disables the templated parallel-rule prompt.) |
244
+ | `color` | `string` | UI color. |
245
+ | `maxSteps` | `positive integer` | Per-invocation step budget. |
246
+ | `tools` | `Record<string, boolean>` | Toggle individual OpenCode tools. |
247
+ | `permission` | `object` | Permission overrides — see below. |
248
+
249
+ Permission keys (each takes `"ask"`, `"allow"`, or `"deny"`):
250
+
251
+ `edit`, `bash`, `webfetch`, `doom_loop`, `external_directory`.
252
+
253
+ `permission.bash` may also be a per-command map:
254
+
255
+ ```json
256
+ {
257
+ "permission": {
258
+ "bash": { "npm test": "allow", "rm -rf": "deny" }
259
+ }
260
+ }
261
+ ```
262
+
263
+ A fully-annotated reference config ships with the package as
264
+ [`opencode-resolve.reference.jsonc`](./opencode-resolve.reference.jsonc) — copy
265
+ the keys you need into your `resolve.json` (without the comments).
266
+
267
+ ---
94
268
 
95
- - `.opencode/resolve.json`
96
- - `opencode-resolve.json`
97
- - `~/.config/opencode/resolve.json`
98
- - `~/.config/opencode/opencode-resolve.json`
269
+ ## Auto Approval
99
270
 
100
- Example:
271
+ `autoApprove` (default `true`) flips every `"ask"` permission on the **enabled** agents to `"allow"`, so coder and resolver work continuously without per-action prompts. It never touches `"deny"` and never overrides a permission key the user explicitly set.
272
+
273
+ | Permission state | autoApprove: true | autoApprove: false |
274
+ |---|---|---|
275
+ | Default `"ask"` | becomes `"allow"` | stays `"ask"` |
276
+ | Default `"deny"` | stays `"deny"` | stays `"deny"` |
277
+ | User explicit `"ask"` | stays `"ask"` | stays `"ask"` |
278
+ | User explicit `"allow"` | stays `"allow"` | stays `"allow"` |
279
+ | User explicit `"deny"` | stays `"deny"` | stays `"deny"` |
280
+
281
+ Reviewer permissions for `edit` and `bash` are `"deny"` in the defaults, so `autoApprove` cannot grant the reviewer modification rights.
282
+
283
+ Turn it off when you want the conservative ask-every-time behavior:
101
284
 
102
285
  ```json
103
286
  {
104
- "enabled": ["coder", "reviewer"],
287
+ "autoApprove": false
288
+ }
289
+ ```
290
+
291
+ Trust note: `autoApprove: true` assumes you trust the workspace and the model you have configured. Use a sandbox or VM for untrusted code, and keep `autoApprove: false` if you want to inspect every action.
292
+
293
+ ---
294
+
295
+ ## Parallel Subagent Limit
296
+
297
+ `maxParallelSubagents` (default `2`) caps how many subagents the **resolver** may dispatch concurrently **per role**. The default of `2` lets up to two coders run in parallel AND up to two reviewers run in parallel — total up to four subagents in flight when both roles are active. Subagents of different roles may always run concurrently (e.g. coder implementing while reviewer audits the previous step).
298
+
299
+ | Value | Behavior |
300
+ |---|---|
301
+ | `1` | Strictly one of each role at a time. Coder may run while reviewer runs, but never two coders or two reviewers in parallel. |
302
+ | `2` (default) | Up to two of each role concurrently. Total in flight up to (per-role limit × number of active roles). |
303
+ | `N > 2` | Up to N of each role concurrently. Useful when fanning out genuinely independent work. |
304
+
305
+ Override per project or per user:
306
+
307
+ ```json
308
+ { "maxParallelSubagents": 1 } // strictest
309
+ { "maxParallelSubagents": 2 } // default
310
+ { "maxParallelSubagents": 4 } // aggressive parallelism
311
+ ```
312
+
313
+ > **Important — soft limit, not a hard cap.** The limit is woven into the resolver's system prompt only. There is no runtime interceptor that blocks excess dispatches. Modern models (GPT-5.x, GLM-5, Claude 4.x) generally respect the directive, but if a model misbehaves, dispatches above the limit will go through. Pair this with `maxSteps` to bound total iterations if you want a stricter ceiling.
314
+
315
+ The limit is templated into the prompt at config-load time, so restart OpenCode to pick up the new value. If you provide a custom `agents.resolver.prompt`, the templated rule is skipped and your prompt wins entirely.
316
+
317
+ ---
318
+
319
+ ## Upgrade & Migration
320
+
321
+ When you upgrade to a newer version of `opencode-resolve`, the `postinstall` script runs an **additive migration** on your existing `~/.config/opencode/resolve.json`:
322
+
323
+ - Adds new top-level keys (e.g. `autoApprove`, `maxParallelSubagents`) with their defaults if they are absent.
324
+ - **Never** modifies keys you have already set.
325
+ - **Never** rewrites your `enabled` list, `models` map, or `agents` overrides.
326
+ - If `enabled` is set and does not include `"resolver"`, prints a one-line tip suggesting you add it. Your file is left untouched.
327
+
328
+ Skip the migration entirely with:
329
+
330
+ ```sh
331
+ OPENCODE_RESOLVE_SKIP_POSTINSTALL=1 npm install -g opencode-resolve
332
+ ```
333
+
334
+ ---
335
+
336
+ ## Model Setup
337
+
338
+ `opencode-resolve` does not ship a provider-specific role default.
339
+
340
+ Model resolution order for each resolve agent:
341
+
342
+ 1. `agents.<name>.model`
343
+ 2. `models.<name>` alias mapping
344
+ 3. top-level OpenCode `model`
345
+ 4. OpenCode's own fallback when no model is configured
346
+
347
+ Use the default config when all resolve roles should follow your current OpenCode model.
348
+
349
+ Pin models only when you intentionally want fixed role behavior, such as fast coding on one model and deeper review on another.
350
+
351
+ Role-specific aliases:
352
+
353
+ ```json
354
+ {
355
+ "enabled": ["coder", "reviewer", "resolver"],
105
356
  "models": {
106
- "glm": "zai-coding-plan/glm-5",
107
- "gpt": "openai/gpt-5",
357
+ "glm": "zai-coding-plan/glm-5.1",
358
+ "gpt": "openai/gpt-5.5",
108
359
  "coder": "glm",
360
+ "resolver": "gpt",
109
361
  "reviewer": "gpt"
110
- },
111
- "preserveNative": true,
112
- "context7": true,
113
- "commands": false,
362
+ }
363
+ }
364
+ ```
365
+
366
+ Pin one role directly:
367
+
368
+ ```json
369
+ {
114
370
  "agents": {
115
- "architect": {
116
- "enabled": false
117
- },
118
- "gpt-coder": {
119
- "enabled": false,
120
- "model": "gpt"
371
+ "reviewer": {
372
+ "model": "openai/gpt-5.5"
121
373
  }
122
374
  }
123
375
  }
124
376
  ```
125
377
 
126
- You can also pass options directly from `opencode.json`:
378
+ Native OpenCode agents such as `plan` and `build` are configured through the top-level OpenCode `agent`, not through `opencode-resolve`.
379
+
380
+ Mixed setup example:
127
381
 
128
382
  ```json
129
383
  {
384
+ "model": "zai-coding-plan/glm-5.1",
385
+ "agent": {
386
+ "plan": {
387
+ "model": "openai/gpt-5.5"
388
+ }
389
+ },
130
390
  "plugin": [
131
391
  [
132
392
  "opencode-resolve",
133
393
  {
134
- "enabled": ["coder", "reviewer", "debugger"],
135
- "config": "~/.config/opencode/resolve.json"
394
+ "enabled": ["coder", "reviewer", "resolver"],
395
+ "models": {
396
+ "glm": "zai-coding-plan/glm-5.1",
397
+ "gpt": "openai/gpt-5.5",
398
+ "coder": "glm",
399
+ "resolver": "gpt",
400
+ "reviewer": "gpt"
401
+ }
136
402
  }
137
403
  ]
138
404
  ]
139
405
  }
140
406
  ```
141
407
 
142
- Options in `opencode.json` override file config.
408
+ In this setup, `plan`, `resolver`, and `reviewer` use `openai/gpt-5.5`; native `build` and resolve `coder` use `zai-coding-plan/glm-5.1`.
409
+
410
+ ---
411
+
412
+ ## Agent Reference
413
+
414
+ | Agent | Default | Mode | Edit | Bash | WebFetch | Purpose |
415
+ |---|:---:|---|---|---|---|---|
416
+ | `resolver` | Yes | `all` | ask → allow | ask → allow | ask → allow | Primary orchestrator. Plans, dispatches `coder` (one at a time), verifies, iterates to completion. |
417
+ | `coder` | Yes | `subagent` | ask → allow | ask → allow | ask → allow | Focused implementer. Smallest correct change. |
418
+ | `reviewer` | Yes | `subagent` | **deny** | **deny** | ask → allow | Read-only auditor. Cannot modify by any means. |
419
+ | `architect` | No | `subagent` | deny | ask → allow | ask → allow | Design and task decomposition. |
420
+ | `gpt-coder` | No | `subagent` | ask → allow | ask → allow | ask → allow | Stronger-reasoning implementation fallback. |
421
+ | `debugger` | No | `subagent` | ask → allow | ask → allow | ask → allow | Reproduction and root-cause analysis. |
422
+ | `researcher` | No | `subagent` | deny | ask → allow | ask → allow | Codebase and documentation research. |
423
+
424
+ `ask → allow` means the default is `"ask"` and `autoApprove` (default on) flips it to `"allow"`. Set `autoApprove: false` to keep them as `"ask"`.
425
+
426
+ Supported modes:
427
+
428
+ | Mode | Meaning |
429
+ |---|---|
430
+ | `subagent` | Available only as a subagent |
431
+ | `primary` | Available as a primary agent |
432
+ | `all` | Available as both primary and subagent |
433
+
434
+ Supported permission values: `ask`, `allow`, `deny`.
435
+
436
+ Supported model alias keys: `glm`, `gpt`, and every supported agent name. Aliases only resolve when defined in `models`.
437
+
438
+ `preserveNative` is accepted for readability, but native `plan` and `build` are always preserved. The plugin never rewrites built-in OpenCode agents.
143
439
 
144
- Config precedence is: built-in defaults, then the first config file found, then inline plugin options from `opencode.json`.
440
+ ### Resolver orchestration rules
145
441
 
146
- The config is validated on load. Unknown agent names, misspelled keys, invalid modes, invalid permission values, and wrong value types fail fast with a clear error instead of silently changing behavior.
442
+ The resolver's prompt enforces the following behavior:
147
443
 
148
- Supported agents:
444
+ - Plan the smallest correct change before dispatching.
445
+ - Dispatch **only one `coder` subagent at a time**. Never call coders in parallel.
446
+ - After each coder run, verify (tests, type checks, targeted checks) when practical.
447
+ - Optionally consult `reviewer` for an independent read-only audit on risky changes; route any required fixes back through `coder`.
448
+ - Iterate until the task is resolved or clearly blocked, then return a concise summary.
149
449
 
150
- - `coder`
151
- - `reviewer`
152
- - `architect`
153
- - `gpt-coder`
154
- - `debugger`
155
- - `researcher`
450
+ ---
156
451
 
157
- Supported model aliases:
452
+ ## Optional Commands
158
453
 
159
- - `glm`
160
- - `gpt`
161
- - every supported agent name
454
+ Set `commands: true` to add helper subtask commands:
162
455
 
163
- Supported agent modes are `subagent`, `primary`, and `all`. Supported permission values are `ask`, `allow`, and `deny`.
456
+ | Command | Description |
457
+ |---|---|
458
+ | `resolve` | Run the `resolver` agent end-to-end on the current task |
459
+ | `resolve-code` | Run the `coder` agent for focused implementation |
460
+ | `resolve-review` | Run the `reviewer` agent for a read-only audit |
164
461
 
165
- `preserveNative` is accepted for readability, but native `plan` and `build` are always preserved. The plugin never iterates or rewrites those built-in agents.
462
+ ---
463
+
464
+ ## Local Development
465
+
466
+ From this repository:
467
+
468
+ ```sh
469
+ npm install
470
+ npm test
471
+ npm run install:local
472
+ ```
473
+
474
+ `install:local` builds the plugin, links it into the OpenCode global plugin directory, and creates `~/.config/opencode/resolve.json` if it does not exist.
166
475
 
167
- `enabled` selects the default active agents. A per-agent `agents.<name>.enabled` value overrides that list.
476
+ Manual local install:
168
477
 
169
- Set `context7` to `false` to disable the Context7 MCP preset.
478
+ ```sh
479
+ npm run build
480
+ mkdir -p ~/.config/opencode/plugins
481
+ ln -sf "$PWD/dist/index.js" ~/.config/opencode/plugins/opencode-resolve.js
482
+ ```
170
483
 
171
- Set `commands` to `true` to add optional subtask commands:
484
+ Local plugin files are loaded automatically by OpenCode.
172
485
 
173
- - `resolve-code`: run the `coder` agent for focused implementation.
174
- - `resolve-review`: run the `reviewer` agent for requirement/risk review.
486
+ ---
175
487
 
176
488
  ## Verification
177
489
 
490
+ Run the normal checks:
491
+
178
492
  ```sh
179
493
  npm run typecheck
180
494
  npm test
181
495
  npm run build
182
496
  ```
183
497
 
184
- The test suite executes the built plugin and verifies default agent injection, model aliases, file config, plugin option overrides, optional commands, Context7 preservation, and native `plan`/`build` preservation.
498
+ The test suite executes the built plugin and verifies default agent injection, `autoApprove` behavior, model aliases, file config, plugin option overrides, optional commands, Context7 preservation, and native `plan`/`build` preservation.
185
499
 
186
- Before publishing, run:
500
+ Before publishing:
187
501
 
188
502
  ```sh
189
503
  npm run typecheck
@@ -194,13 +508,17 @@ npm publish --dry-run
194
508
 
195
509
  `npm pack` and `npm publish` run `npm test` first through the `prepack` script.
196
510
 
511
+ ---
512
+
197
513
  ## Release
198
514
 
199
515
  Releases are published by GitHub Actions when a version tag is pushed.
200
516
 
201
517
  Required repository secret:
202
518
 
203
- - `NPM_TOKEN`: npm automation token with publish access.
519
+ | Secret | Description |
520
+ |---|---|
521
+ | `NPM_TOKEN` | npm automation token with publish access |
204
522
 
205
523
  Tag release flow:
206
524
 
@@ -213,32 +531,12 @@ You can also run the `Publish to npm` workflow manually from GitHub Actions and
213
531
 
214
532
  The release workflow runs `npm ci`, `npm run typecheck`, `npm test`, and `npm publish --access public --provenance`.
215
533
 
534
+ ---
535
+
216
536
  ## Design Rules
217
537
 
218
538
  - Do not overwrite native `plan` or `build` agents.
219
- - Keep default subagent count small.
220
- - Search and inspect before editing.
221
- - Make the smallest correct change.
222
- - Verify when practical.
223
- - Use reviewer for final requirement/risk checks instead of running many agents by default.
224
-
225
- ## Companion Plugins
226
-
227
- `opencode-resolve` intentionally stays focused on agent injection and task resolution. Use notification or remote-control plugins alongside it instead of baking those concerns into this package.
228
-
229
- Recommended companion:
230
-
231
- - [`@jshsakura/opencode-telegram-bot-plugin`](https://github.com/jshsakura/opencode-telegram-bot-plugin): Telegram notifications and permission-response support for OpenCode sessions.
232
-
233
- Install and configure the Telegram plugin separately. It needs its own bot token/chat setup; see that plugin's README for details.
234
-
235
- Example:
236
-
237
- ```json
238
- {
239
- "plugin": [
240
- "opencode-resolve",
241
- "@jshsakura/opencode-telegram-bot-plugin"
242
- ]
243
- }
244
- ```
539
+ - Keep the default agent set small and role-clear: `resolver` orchestrates, `coder` modifies, `reviewer` only reads.
540
+ - The reviewer never modifies anything — fixes always go through `coder` or `resolver`.
541
+ - The resolver dispatches at most one coder at a time.
542
+ - Search and inspect before editing. Make the smallest correct change. Verify when practical.
package/dist/index.js CHANGED
@@ -1,18 +1,9 @@
1
1
  import { access, readFile } from "node:fs/promises";
2
2
  import { homedir } from "node:os";
3
3
  import { basename, isAbsolute, join, resolve } from "node:path";
4
- const DEFAULT_MODELS = {
5
- glm: "zai-coding-plan/glm-5",
6
- gpt: "openai/gpt-5",
7
- coder: "zai-coding-plan/glm-5",
8
- reviewer: "openai/gpt-5",
9
- architect: "openai/gpt-5",
10
- "gpt-coder": "openai/gpt-5",
11
- debugger: "zai-coding-plan/glm-5",
12
- researcher: "zai-coding-plan/glm-5",
13
- };
14
- const DEFAULT_ENABLED = ["coder", "reviewer"];
15
- const VALID_AGENT_NAMES = ["coder", "reviewer", "architect", "gpt-coder", "debugger", "researcher"];
4
+ const DEFAULT_MODELS = {};
5
+ const DEFAULT_ENABLED = ["coder", "reviewer", "resolver"];
6
+ const VALID_AGENT_NAMES = ["coder", "reviewer", "resolver", "architect", "gpt-coder", "debugger", "researcher"];
16
7
  const VALID_AGENT_NAME_SET = new Set(VALID_AGENT_NAMES);
17
8
  const VALID_MODEL_ALIASES = [...VALID_AGENT_NAMES, "glm", "gpt"];
18
9
  const VALID_MODEL_ALIAS_SET = new Set(VALID_MODEL_ALIASES);
@@ -25,8 +16,11 @@ const VALID_TOP_LEVEL_KEYS = new Set([
25
16
  "preserveNative",
26
17
  "context7",
27
18
  "commands",
19
+ "autoApprove",
20
+ "maxParallelSubagents",
28
21
  "config",
29
22
  ]);
23
+ const DEFAULT_MAX_PARALLEL_SUBAGENTS = 2;
30
24
  const VALID_AGENT_KEYS = new Set([
31
25
  "enabled",
32
26
  "model",
@@ -38,6 +32,27 @@ const VALID_AGENT_KEYS = new Set([
38
32
  "tools",
39
33
  "permission",
40
34
  ]);
35
+ function buildResolverPrompt(maxParallelSubagents) {
36
+ const limit = Math.max(1, Math.trunc(maxParallelSubagents));
37
+ const parallelRule = limit === 1
38
+ ? "CRITICAL: Dispatch at most ONE subagent of each role concurrently. Never run two coders in parallel, and never run two reviewers in parallel. A coder and a reviewer MAY run concurrently when they are doing genuinely independent work (e.g. coder is implementing the next change while reviewer audits the previous one). Wait for an in-flight subagent of a given role to finish before dispatching another of the same role."
39
+ : `CRITICAL: Dispatch at most ${limit} subagents of the same role concurrently. Never exceed ${limit} coders in parallel, and never exceed ${limit} reviewers in parallel. Subagents of different roles may run concurrently when they are doing genuinely independent work. Wait for in-flight subagents of a given role to finish before dispatching more of that role.`;
40
+ return [
41
+ "You are Resolver, the primary orchestrator agent for OpenCode Resolve.",
42
+ "Your job is to drive the user's task to a verified resolution end-to-end without unnecessary stops.",
43
+ "Workflow:",
44
+ "1. Understand the requirement. Inspect the relevant files briefly before planning.",
45
+ "2. Plan the smallest correct change.",
46
+ "3. Dispatch the coder subagent to implement the change. Pass a focused instruction with the exact files and behavior.",
47
+ `4. ${parallelRule}`,
48
+ "5. After implementation, verify when practical (run tests, type checks, or targeted checks).",
49
+ "6. If issues remain, dispatch the coder again with a focused fix, or apply a small direct edit yourself when it is clearly trivial.",
50
+ "7. Optionally consult the reviewer subagent for an independent read-only review on risky changes. The reviewer cannot modify anything; treat its output as advice and route any required fixes back through the coder. The same per-role parallel limit applies to the reviewer.",
51
+ "8. Repeat until the task is resolved or clearly blocked.",
52
+ "Return a concise summary of what changed, verification results, and any remaining blockers.",
53
+ "Note: this parallel rule is enforced via prompt only — there is no runtime cap on subagent dispatches. Honor it strictly to avoid file conflicts and wasted work.",
54
+ ].join("\n");
55
+ }
41
56
  const DEFAULT_AGENT_CONFIG = {
42
57
  coder: {
43
58
  mode: "subagent",
@@ -61,16 +76,29 @@ const DEFAULT_AGENT_CONFIG = {
61
76
  mode: "subagent",
62
77
  color: "#8A7CFF",
63
78
  maxSteps: 8,
64
- description: "Use for Oracle-style review of requirements fit, correctness, security, tests, and maintainability risks.",
79
+ description: "Read-only Oracle-style reviewer. Inspects code for requirements fit, correctness, security, tests, and maintainability risks. Never modifies anything.",
65
80
  prompt: [
66
- "You are Reviewer, an Oracle-style review subagent for OpenCode Resolve.",
67
- "Review the work against the user's actual requirements and the repository's existing patterns.",
81
+ "You are Reviewer, a strictly read-only review subagent for OpenCode Resolve.",
82
+ "You MUST NOT modify the project by any means: no file edits, no writes, no shell commands that change state, no git commits, no package installs.",
83
+ "Use read-only tools (read, grep, glob, list, web fetch for documentation) to inspect the work against the user's requirements and the repository's existing patterns.",
68
84
  "Prioritize concrete bugs, behavioral regressions, security risks, missing tests, and maintainability issues.",
69
- "Do not rewrite code unless explicitly asked; return findings ordered by severity with file and line references when available.",
70
- "If there are no findings, say so and mention residual risks or verification gaps.",
85
+ "Return findings ordered by severity with file and line references when available. If there are no findings, say so and mention residual risks or verification gaps.",
86
+ "If a fix is needed, describe it precisely and recommend dispatching the coder or resolver agent. Never apply fixes yourself.",
71
87
  ].join("\n"),
72
88
  permission: {
73
89
  edit: "deny",
90
+ bash: "deny",
91
+ webfetch: "ask",
92
+ },
93
+ },
94
+ resolver: {
95
+ mode: "all",
96
+ color: "#FF7AC6",
97
+ maxSteps: 30,
98
+ description: "Primary orchestrator. Drives a task to completion by planning, dispatching subagents (one at a time by default), and verifying results. Iterates until the task is resolved or clearly blocked.",
99
+ prompt: buildResolverPrompt(DEFAULT_MAX_PARALLEL_SUBAGENTS),
100
+ permission: {
101
+ edit: "ask",
74
102
  bash: "ask",
75
103
  webfetch: "ask",
76
104
  },
@@ -166,6 +194,9 @@ async function loadResolveConfig(directory, opencodeConfig, options) {
166
194
  function applyResolveConfig(config, resolveConfig) {
167
195
  const enabled = new Set(resolveConfig.enabled ?? DEFAULT_ENABLED);
168
196
  const models = { ...DEFAULT_MODELS, ...resolveConfig.models };
197
+ const defaultModel = typeof config.model === "string" ? config.model : undefined;
198
+ const autoApprove = resolveConfig.autoApprove !== false;
199
+ const maxParallelSubagents = resolveConfig.maxParallelSubagents ?? DEFAULT_MAX_PARALLEL_SUBAGENTS;
169
200
  config.agent ??= {};
170
201
  for (const name of Object.keys(DEFAULT_AGENT_CONFIG)) {
171
202
  const override = resolveConfig.agents?.[name];
@@ -173,13 +204,21 @@ function applyResolveConfig(config, resolveConfig) {
173
204
  if (!isEnabled)
174
205
  continue;
175
206
  const base = DEFAULT_AGENT_CONFIG[name];
176
- const { enabled: _enabled, ...agentOverride } = override ?? {};
177
- const model = resolveModel(agentOverride.model ?? models[name], models);
178
- config.agent[name] = {
207
+ const { enabled: _enabled, model: requestedModel, permission: userPermission, ...agentOverride } = override ?? {};
208
+ const model = resolveModel(requestedModel ?? models[name] ?? defaultModel, models);
209
+ const permission = buildPermission(base.permission, userPermission, autoApprove);
210
+ const agentConfig = {
179
211
  ...base,
180
212
  ...agentOverride,
181
- model,
182
213
  };
214
+ if (name === "resolver" && agentOverride.prompt === undefined) {
215
+ agentConfig.prompt = buildResolverPrompt(maxParallelSubagents);
216
+ }
217
+ if (permission)
218
+ agentConfig.permission = permission;
219
+ if (model)
220
+ agentConfig.model = model;
221
+ config.agent[name] = agentConfig;
183
222
  }
184
223
  if (resolveConfig.context7 !== false) {
185
224
  config.mcp ??= {};
@@ -190,9 +229,15 @@ function applyResolveConfig(config, resolveConfig) {
190
229
  }
191
230
  if (resolveConfig.commands) {
192
231
  config.command ??= {};
232
+ config.command["resolve"] ??= {
233
+ template: "Drive this task to a verified resolution end-to-end. Plan, dispatch one coder at a time, verify, and iterate. $ARGUMENTS",
234
+ description: "Run the OpenCode Resolve resolver agent end-to-end",
235
+ agent: "resolver",
236
+ subtask: true,
237
+ };
193
238
  config.command["resolve-review"] ??= {
194
- template: "Review the current implementation against the user's requirements. Focus on correctness, tests, security, and maintainability.",
195
- description: "Run the OpenCode Resolve reviewer agent",
239
+ template: "Review the current implementation against the user's requirements. Focus on correctness, tests, security, and maintainability. Do not modify anything.",
240
+ description: "Run the OpenCode Resolve reviewer agent (read-only)",
196
241
  agent: "reviewer",
197
242
  subtask: true,
198
243
  };
@@ -207,11 +252,13 @@ function applyResolveConfig(config, resolveConfig) {
207
252
  function defaultResolveConfig() {
208
253
  return {
209
254
  enabled: DEFAULT_ENABLED,
210
- models: DEFAULT_MODELS,
255
+ models: {},
211
256
  agents: {},
212
257
  preserveNative: true,
213
258
  context7: true,
214
259
  commands: false,
260
+ autoApprove: true,
261
+ maxParallelSubagents: DEFAULT_MAX_PARALLEL_SUBAGENTS,
215
262
  };
216
263
  }
217
264
  function mergeResolveConfig(...configs) {
@@ -223,6 +270,8 @@ function mergeResolveConfig(...configs) {
223
270
  result.preserveNative = config.preserveNative ?? result.preserveNative;
224
271
  result.context7 = config.context7 ?? result.context7;
225
272
  result.commands = config.commands ?? result.commands;
273
+ result.autoApprove = config.autoApprove ?? result.autoApprove;
274
+ result.maxParallelSubagents = config.maxParallelSubagents ?? result.maxParallelSubagents;
226
275
  result.models = { ...result.models, ...config.models };
227
276
  result.agents = mergeAgents(result.agents, config.agents);
228
277
  }
@@ -240,6 +289,27 @@ function resolveModel(model, models) {
240
289
  return undefined;
241
290
  return models[model] ?? model;
242
291
  }
292
+ function buildPermission(basePermission, userPermission, autoApprove) {
293
+ const merged = {
294
+ ...(basePermission ?? {}),
295
+ ...(userPermission ?? {}),
296
+ };
297
+ if (Object.keys(merged).length === 0)
298
+ return undefined;
299
+ if (!autoApprove)
300
+ return merged;
301
+ const userKeys = new Set(Object.keys(userPermission ?? {}));
302
+ const result = { ...merged };
303
+ for (const key of Object.keys(result)) {
304
+ if (userKeys.has(key))
305
+ continue;
306
+ const value = result[key];
307
+ if (value === "ask") {
308
+ result[key] = "allow";
309
+ }
310
+ }
311
+ return result;
312
+ }
243
313
  function getPluginOptions(config) {
244
314
  for (const entry of config.plugin ?? []) {
245
315
  if (Array.isArray(entry) && isResolvePluginEntry(entry[0])) {
@@ -310,6 +380,15 @@ function normalizeResolveConfig(value, source) {
310
380
  result.context7 = expectBoolean(config.context7, `${source}.context7`);
311
381
  if (config.commands !== undefined)
312
382
  result.commands = expectBoolean(config.commands, `${source}.commands`);
383
+ if (config.autoApprove !== undefined)
384
+ result.autoApprove = expectBoolean(config.autoApprove, `${source}.autoApprove`);
385
+ if (config.maxParallelSubagents !== undefined) {
386
+ const limit = expectNumber(config.maxParallelSubagents, `${source}.maxParallelSubagents`);
387
+ if (!Number.isInteger(limit) || limit < 1) {
388
+ throw new Error(`${source}.maxParallelSubagents must be a positive integer`);
389
+ }
390
+ result.maxParallelSubagents = limit;
391
+ }
313
392
  if (config.config !== undefined)
314
393
  result.config = expectString(config.config, `${source}.config`);
315
394
  return result;
@@ -1,19 +1,21 @@
1
1
  {
2
- "enabled": ["coder", "reviewer"],
3
- "models": {
4
- "glm": "zai-coding-plan/glm-5",
5
- "gpt": "openai/gpt-5",
6
- "coder": "glm",
7
- "reviewer": "gpt",
8
- "architect": "gpt",
9
- "gpt-coder": "gpt",
10
- "debugger": "glm",
11
- "researcher": "glm"
12
- },
2
+ "enabled": ["coder", "reviewer", "resolver"],
13
3
  "preserveNative": true,
14
4
  "context7": true,
15
5
  "commands": false,
6
+ "autoApprove": true,
7
+ "maxParallelSubagents": 2,
8
+ "models": {},
16
9
  "agents": {
10
+ "coder": {
11
+ "mode": "all"
12
+ },
13
+ "reviewer": {
14
+ "mode": "all"
15
+ },
16
+ "resolver": {
17
+ "enabled": true
18
+ },
17
19
  "architect": {
18
20
  "enabled": false
19
21
  },
@@ -28,3 +30,4 @@
28
30
  }
29
31
  }
30
32
  }
33
+
@@ -0,0 +1,169 @@
1
+ // opencode-resolve.reference.jsonc
2
+ //
3
+ // This file documents EVERY option opencode-resolve accepts. It is NOT loaded
4
+ // by the plugin (the plugin only reads .json). Copy what you need into
5
+ // `~/.config/opencode/resolve.json`, `.opencode/resolve.json`, or
6
+ // `opencode-resolve.json` (without the comments).
7
+ //
8
+ // Config file lookup order (first one found wins):
9
+ // 1. <project>/.opencode/resolve.json
10
+ // 2. <project>/opencode-resolve.json
11
+ // 3. ~/.config/opencode/resolve.json
12
+ // 4. ~/.config/opencode/opencode-resolve.json
13
+ //
14
+ // Inline plugin options inside opencode.json override the file config.
15
+ //
16
+ // Validation is strict: unknown keys, misspellings, invalid modes, invalid
17
+ // permission values, and wrong types throw an error at load time.
18
+
19
+ {
20
+ // -----------------------------------------------------------------------
21
+ // enabled (string[])
22
+ // Which resolve agents to inject. Default: ["coder", "reviewer", "resolver"].
23
+ // Native OpenCode agents (plan, build) are always preserved and never
24
+ // touched by this list. Per-agent `agents.<name>.enabled` overrides this.
25
+ // -----------------------------------------------------------------------
26
+ "enabled": ["coder", "reviewer", "resolver"],
27
+
28
+ // -----------------------------------------------------------------------
29
+ // preserveNative (boolean)
30
+ // Always true in practice — plan/build are never rewritten. Accepted for
31
+ // readability. Default: true.
32
+ // -----------------------------------------------------------------------
33
+ "preserveNative": true,
34
+
35
+ // -----------------------------------------------------------------------
36
+ // context7 (boolean)
37
+ // When true, registers the Context7 MCP server unless `mcp.context7` is
38
+ // already configured. Default: true.
39
+ // -----------------------------------------------------------------------
40
+ "context7": true,
41
+
42
+ // -----------------------------------------------------------------------
43
+ // commands (boolean)
44
+ // When true, adds three optional commands: `resolve`, `resolve-code`,
45
+ // `resolve-review`. Default: false.
46
+ // -----------------------------------------------------------------------
47
+ "commands": false,
48
+
49
+ // -----------------------------------------------------------------------
50
+ // autoApprove (boolean)
51
+ // When true, every default `"ask"` permission on enabled agents is flipped
52
+ // to `"allow"`. Never touches `"deny"`. Never overrides a permission key
53
+ // you set explicitly under `agents.<name>.permission`. Default: true.
54
+ //
55
+ // Set to false for the conservative ask-every-time behavior.
56
+ // -----------------------------------------------------------------------
57
+ "autoApprove": true,
58
+
59
+ // -----------------------------------------------------------------------
60
+ // maxParallelSubagents (positive integer)
61
+ // Maximum number of subagents of the SAME ROLE the resolver may dispatch
62
+ // concurrently. Default: 2 — at most two coders in parallel and at most
63
+ // two reviewers in parallel. Subagents of different roles may always run
64
+ // concurrently. This is a soft prompt-level limit, not a runtime cap —
65
+ // pair with `maxSteps` if you need a stricter ceiling.
66
+ // 1 = strict per-role serial (one of each role at a time)
67
+ // 2 = default
68
+ // N = up to N of each role
69
+ // -----------------------------------------------------------------------
70
+ "maxParallelSubagents": 2,
71
+
72
+ // -----------------------------------------------------------------------
73
+ // models (object)
74
+ // Alias map. Keys are either an agent name (coder, reviewer, resolver,
75
+ // architect, gpt-coder, debugger, researcher) OR one of the well-known
76
+ // aliases (`glm`, `gpt`). Values are model identifiers OR another alias.
77
+ //
78
+ // Resolution order for a given agent:
79
+ // 1. agents.<name>.model
80
+ // 2. models.<name> (resolved through the alias map)
81
+ // 3. top-level OpenCode `model`
82
+ // 4. OpenCode's own fallback
83
+ // -----------------------------------------------------------------------
84
+ "models": {
85
+ "glm": "zai-coding-plan/glm-5.1",
86
+ "gpt": "openai/gpt-5.5",
87
+ "coder": "glm",
88
+ "resolver": "gpt",
89
+ "reviewer": "gpt"
90
+ },
91
+
92
+ // -----------------------------------------------------------------------
93
+ // agents (object)
94
+ // Per-agent overrides. Each key MUST be a valid agent name. Each entry
95
+ // accepts: enabled, model, mode, description, prompt, color, maxSteps,
96
+ // tools, permission. Unknown keys throw.
97
+ //
98
+ // mode: "subagent" | "primary" | "all"
99
+ // permission.edit | bash | webfetch | doom_loop | external_directory:
100
+ // "ask" | "allow" | "deny"
101
+ // permission.bash may also be a per-command map:
102
+ // { "npm test": "allow", "rm -rf": "deny" }
103
+ // -----------------------------------------------------------------------
104
+ "agents": {
105
+ "coder": {
106
+ "enabled": true,
107
+ "model": "glm",
108
+ "mode": "subagent",
109
+ "maxSteps": 20,
110
+ "permission": {
111
+ "edit": "allow",
112
+ "bash": "allow",
113
+ "webfetch": "allow"
114
+ }
115
+ },
116
+
117
+ "reviewer": {
118
+ "enabled": true,
119
+ "model": "gpt",
120
+ "mode": "subagent",
121
+ "maxSteps": 8,
122
+ // Reviewer is read-only by design. edit and bash are denied even when
123
+ // autoApprove is true.
124
+ "permission": {
125
+ "edit": "deny",
126
+ "bash": "deny",
127
+ "webfetch": "allow"
128
+ }
129
+ },
130
+
131
+ "resolver": {
132
+ "enabled": true,
133
+ "model": "gpt",
134
+ "mode": "all",
135
+ "maxSteps": 30,
136
+ "permission": {
137
+ "edit": "allow",
138
+ "bash": "allow",
139
+ "webfetch": "allow"
140
+ }
141
+ },
142
+
143
+ // Optional agents — disabled by default. Flip enabled:true to use them.
144
+ "architect": {
145
+ "enabled": false,
146
+ "model": "gpt",
147
+ "mode": "subagent",
148
+ "maxSteps": 10
149
+ },
150
+ "gpt-coder": {
151
+ "enabled": false,
152
+ "model": "gpt",
153
+ "mode": "subagent",
154
+ "maxSteps": 20
155
+ },
156
+ "debugger": {
157
+ "enabled": false,
158
+ "model": "glm",
159
+ "mode": "subagent",
160
+ "maxSteps": 14
161
+ },
162
+ "researcher": {
163
+ "enabled": false,
164
+ "model": "glm",
165
+ "mode": "subagent",
166
+ "maxSteps": 8
167
+ }
168
+ }
169
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-resolve",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "OpenCode plugin that adds a small coder/reviewer agent set while preserving native plan/build behavior.",
5
5
  "type": "module",
6
6
  "homepage": "https://github.com/jshsakura/opencode-resolve#readme",
@@ -23,6 +23,7 @@
23
23
  "dist",
24
24
  "scripts",
25
25
  "opencode-resolve.example.json",
26
+ "opencode-resolve.reference.jsonc",
26
27
  "README.md",
27
28
  "LICENSE"
28
29
  ],
@@ -11,6 +11,11 @@ const opencodeConfigPath = join(configDir, "opencode.json")
11
11
  const resolveConfigPath = join(configDir, "resolve.json")
12
12
  const exampleConfigPath = join(root, "opencode-resolve.example.json")
13
13
 
14
+ const ADDITIVE_DEFAULTS = {
15
+ autoApprove: true,
16
+ maxParallelSubagents: 2,
17
+ }
18
+
14
19
  if (process.env.OPENCODE_RESOLVE_SKIP_POSTINSTALL === "1") {
15
20
  process.exit(0)
16
21
  }
@@ -39,6 +44,54 @@ async function registerPlugin() {
39
44
  await assertReadable(exampleConfigPath)
40
45
  await copyFile(exampleConfigPath, resolveConfigPath)
41
46
  console.log(`[${packageName}] created ${resolveConfigPath}`)
47
+ return
48
+ }
49
+
50
+ await migrateResolveConfig()
51
+ }
52
+
53
+ async function migrateResolveConfig() {
54
+ let raw
55
+ try {
56
+ raw = await readFile(resolveConfigPath, "utf8")
57
+ } catch (error) {
58
+ console.warn(`[${packageName}] could not read ${resolveConfigPath} for migration: ${formatError(error)}`)
59
+ return
60
+ }
61
+
62
+ let parsed
63
+ try {
64
+ parsed = JSON.parse(raw)
65
+ } catch (error) {
66
+ console.warn(`[${packageName}] ${resolveConfigPath} is not valid JSON; skipping migration: ${formatError(error)}`)
67
+ return
68
+ }
69
+
70
+ if (!isObject(parsed)) {
71
+ console.warn(`[${packageName}] ${resolveConfigPath} must contain a JSON object; skipping migration`)
72
+ return
73
+ }
74
+
75
+ const updated = { ...parsed }
76
+ const added = []
77
+ for (const [key, value] of Object.entries(ADDITIVE_DEFAULTS)) {
78
+ if (updated[key] === undefined) {
79
+ updated[key] = value
80
+ added.push(`${key}=${JSON.stringify(value)}`)
81
+ }
82
+ }
83
+
84
+ if (added.length > 0) {
85
+ await writeFile(resolveConfigPath, `${JSON.stringify(updated, null, 2)}\n`)
86
+ console.log(`[${packageName}] migrated ${resolveConfigPath}: added ${added.join(", ")}`)
87
+ } else {
88
+ console.log(`[${packageName}] ${resolveConfigPath} already up to date`)
89
+ }
90
+
91
+ if (Array.isArray(updated.enabled) && !updated.enabled.includes("resolver")) {
92
+ console.log(
93
+ `[${packageName}] tip: add "resolver" to "enabled" in ${resolveConfigPath} to use the new orchestrator agent.`,
94
+ )
42
95
  }
43
96
  }
44
97