opencode-resolve 0.1.20 → 0.3.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/dist/utils.js CHANGED
@@ -1,14 +1,10 @@
1
1
  import { spawn } from "node:child_process";
2
2
  import { stat, readFile, access, readdir } from "node:fs/promises";
3
3
  import { join, dirname, extname, relative } from "node:path";
4
- import { readFileSync, writeFileSync, mkdirSync } from "node:fs";
5
- import { homedir } from "node:os";
4
+ import { readFileSync } from "node:fs";
6
5
  import { fileURLToPath } from "node:url";
7
6
  import { normalizeResolveConfig } from "./config.js";
8
7
  export const PLUGIN_VERSION = readPluginVersion();
9
- export const UPDATE_CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;
10
- export const UPDATE_CHECK_FILE = join(homedir(), ".cache", "opencode-resolve", "update-check.json");
11
- export const PLUGIN_CACHE_DIR = join(homedir(), ".cache", "opencode", "packages", "opencode-resolve@latest");
12
8
  export function runCommand(command, cwd, timeoutMs) {
13
9
  return new Promise((resolve) => {
14
10
  const proc = spawn("sh", ["-c", command], {
@@ -49,16 +45,45 @@ export function isMissingFileError(error) {
49
45
  export function formatError(error) {
50
46
  return error instanceof Error ? error.message : String(error);
51
47
  }
52
- export function classifyBashCommand(pattern) {
48
+ /**
49
+ * Which rollback command, if any, this bash line runs. Both are destructive and
50
+ * denied by default; `permissions.allowGitReset` / `allowGitClean` un-gate them,
51
+ * and the caller writes a checkpoint ref before execution.
52
+ */
53
+ export function detectRollbackCommand(pattern) {
53
54
  const cmd = pattern.trim();
55
+ if (GIT_HARD_RESET_PATTERN.test(cmd))
56
+ return "reset";
57
+ if (GIT_FORCE_CLEAN_PATTERN.test(cmd))
58
+ return "clean";
59
+ return undefined;
60
+ }
61
+ function isRollbackPermitted(kind, permissions) {
62
+ if (kind === "reset")
63
+ return permissions?.allowGitReset === true;
64
+ return permissions?.allowGitClean === true;
65
+ }
66
+ export function classifyBashCommand(pattern, permissions) {
67
+ const cmd = pattern.trim();
68
+ // A permitted rollback stops being a deny-pattern, but every *other* deny
69
+ // pattern in the same command line still applies — `git reset --hard && rm -rf /`
70
+ // must not slip through on the strength of the exemption.
71
+ const exempt = new Set();
72
+ if (permissions?.allowGitReset)
73
+ exempt.add(GIT_HARD_RESET_PATTERN);
74
+ if (permissions?.allowGitClean)
75
+ exempt.add(GIT_FORCE_CLEAN_PATTERN);
54
76
  for (const re of BANNED_COMMANDS) {
55
- if (re.test(cmd))
77
+ if (!exempt.has(re) && re.test(cmd))
56
78
  return "deny";
57
79
  }
58
80
  for (const re of DANGEROUS_BASH_PATTERNS) {
59
- if (re.test(cmd))
81
+ if (!exempt.has(re) && re.test(cmd))
60
82
  return "deny";
61
83
  }
84
+ const rollback = detectRollbackCommand(cmd);
85
+ if (rollback && isRollbackPermitted(rollback, permissions))
86
+ return "allow";
62
87
  const firstToken = cmd.split(/\s+/)[0];
63
88
  if (ALWAYS_SAFE_COMMANDS.includes(firstToken))
64
89
  return "allow";
@@ -218,92 +243,13 @@ export function readPluginVersion() {
218
243
  return "unknown";
219
244
  }
220
245
  }
221
- export function readUpdateCheckCache() {
222
- try {
223
- const raw = readFileSync(UPDATE_CHECK_FILE, "utf8");
224
- const parsed = JSON.parse(raw);
225
- if (typeof parsed?.checkedAt === "number" &&
226
- typeof parsed?.latest === "string") {
227
- return { checkedAt: parsed.checkedAt, latest: parsed.latest };
228
- }
229
- }
230
- catch {
231
- // file missing or unparseable
232
- }
233
- return undefined;
234
- }
235
- export function isNewerVersion(candidate, baseline) {
236
- const a = candidate.split(".").map((n) => Number.parseInt(n, 10));
237
- const b = baseline.split(".").map((n) => Number.parseInt(n, 10));
238
- for (let i = 0; i < Math.max(a.length, b.length); i++) {
239
- const av = Number.isFinite(a[i]) ? a[i] : 0;
240
- const bv = Number.isFinite(b[i]) ? b[i] : 0;
241
- if (av > bv)
242
- return true;
243
- if (av < bv)
244
- return false;
245
- }
246
- return false;
247
- }
248
- export async function maybeAutoUpdate() {
249
- const previous = readUpdateCheckCache();
250
- try {
251
- if (previous && Date.now() - previous.checkedAt < UPDATE_CHECK_INTERVAL_MS) {
252
- if (isNewerVersion(previous.latest, PLUGIN_VERSION)) {
253
- refreshPluginCacheInBackground(previous.latest, "cached");
254
- }
255
- return;
256
- }
257
- }
258
- catch {
259
- // ignore corrupt cache and re-check
260
- }
261
- let latest;
262
- try {
263
- const response = await fetch("https://registry.npmjs.org/opencode-resolve/latest", {
264
- headers: { Accept: "application/json" },
265
- signal: AbortSignal.timeout(5000),
266
- });
267
- if (!response.ok)
268
- return;
269
- const data = (await response.json());
270
- if (typeof data?.version !== "string")
271
- return;
272
- latest = data.version;
273
- }
274
- catch {
275
- return;
276
- }
277
- try {
278
- mkdirSync(dirname(UPDATE_CHECK_FILE), { recursive: true });
279
- writeFileSync(UPDATE_CHECK_FILE, JSON.stringify({ checkedAt: Date.now(), latest }));
280
- }
281
- catch {
282
- // best-effort; don't block on cache write failure
283
- }
284
- if (!isNewerVersion(latest, PLUGIN_VERSION))
285
- return;
286
- refreshPluginCacheInBackground(latest, "registry");
287
- }
288
- function refreshPluginCacheInBackground(latest, source) {
289
- const sourceLabel = source === "cached" ? "cached latest" : "registry latest";
290
- console.log(`[opencode-resolve] new version v${latest} available (${sourceLabel}, current: v${PLUGIN_VERSION}) — refreshing OpenCode plugin cache in background. Restart OpenCode to activate it.`);
291
- try {
292
- spawn("sh", ["-c", `rm -rf "${PLUGIN_CACHE_DIR}" && opencode plugin opencode-resolve@latest --global --force`], {
293
- detached: true,
294
- stdio: "ignore",
295
- env: {
296
- ...process.env,
297
- OPENCODE_RESOLVE_REFRESHING_CACHE: "1",
298
- OPENCODE_RESOLVE_SKIP_POSTINSTALL: "1",
299
- OPENCODE_RESOLVE_SKIP_COMPANIONS: "1",
300
- },
301
- }).unref();
302
- }
303
- catch {
304
- // If spawn fails, the user already saw the notice and can run the command manually.
305
- }
306
- }
246
+ // Auto-update was removed: it spawned `opencode plugin opencode-resolve@latest
247
+ // --global --force` per `hooks.config()` call, which created hundreds of parallel
248
+ // OpenCode sessions whenever multiple instances loaded the plugin at once (and
249
+ // once flattened the user's server with 177 sessions during a test run).
250
+ // Users update manually: `npm i -g opencode-resolve` or via the install script.
251
+ // The `autoUpdate` config field is still accepted by the schema for backward
252
+ // compatibility, but it is now a no-op.
307
253
  export async function readFirstJson(paths) {
308
254
  for (const path of paths) {
309
255
  try {
@@ -318,6 +264,17 @@ export async function readFirstJson(paths) {
318
264
  }
319
265
  return undefined;
320
266
  }
267
+ // The two destructive-but-recoverable rollback commands. Shared regex identities
268
+ // so `classifyBashCommand` can exempt them from the deny lists by reference when
269
+ // the matching `permissions.allow*` flag is set.
270
+ export const GIT_HARD_RESET_PATTERN = /\bgit\s+reset\s+--hard/;
271
+ export const GIT_FORCE_CLEAN_PATTERN = /\bgit\s+clean\s+-[a-zA-Z]*f/;
272
+ // `git clean -x` also deletes gitignored files. Checkpoints snapshot via
273
+ // `git add -A`, which honours .gitignore — so a `-x` clean destroys files
274
+ // (.env, local secrets) the checkpoint cannot restore. Never exempted.
275
+ // Matches `-x` in any flag position (`-xdf`, `-f -x`, `-Xf`), but does not
276
+ // reach past a command separator into the next command.
277
+ export const GIT_CLEAN_IGNORED_PATTERN = /\bgit\s+clean\b[^;&|]*\s-[a-zA-Z]*[xX]/;
321
278
  export const BANNED_COMMANDS = [
322
279
  /\b(vim?|nano|emacs|pico|ed)\b/, // interactive editors
323
280
  /\b(less|more|most|pg)\b/, // pagers
@@ -347,7 +304,7 @@ export const BANNED_COMMANDS = [
347
304
  /\bchown\s+-R\s+/, // recursive chown
348
305
  /\bsudo\s+(rm|chmod|chown|dd|mkfs)/, // sudo + destructive
349
306
  /\bgit\s+push\s+--force/, // force push
350
- /\bgit\s+reset\s+--hard/, // hard reset
307
+ GIT_HARD_RESET_PATTERN, // hard reset (gated by permissions.allowGitReset)
351
308
  /\brm\s+(-rf?|-fr?)\s+[^.]/, // rm -rf (not dotfiles)
352
309
  /\bdd\s+if=/, // dd can destroy disks
353
310
  /\b(mkfs|format)\b/, // filesystem format
@@ -355,8 +312,9 @@ export const BANNED_COMMANDS = [
355
312
  export const DANGEROUS_BASH_PATTERNS = [
356
313
  /\brm\s+.*-[rR].*[fF].*\s+\//, // rm -rf /... (absolute path)
357
314
  /\bgit\s+push\s+.*(--force|-f\b)/, // force push
358
- /\bgit\s+reset\s+--hard/, // hard reset
359
- /\bgit\s+clean\s+-fd/, // clean untracked files
315
+ GIT_HARD_RESET_PATTERN, // hard reset (gated by permissions.allowGitReset)
316
+ GIT_FORCE_CLEAN_PATTERN, // clean untracked files (gated by permissions.allowGitClean)
317
+ GIT_CLEAN_IGNORED_PATTERN, // clean gitignored files — unrecoverable, never exempted
360
318
  /\bsudo\s+rm\b/, // sudo rm
361
319
  /\bdd\s+.*of=\/dev\//, // dd to device
362
320
  /\bchmod\s+-R\s+777\s+\//, // chmod everything
@@ -1,10 +1,7 @@
1
1
  {
2
- "profile": "mix",
3
2
  "preserveNative": true,
4
- "context7": true,
5
3
  "commands": false,
6
4
  "autoApprove": true,
7
- "autoUpdate": true,
8
5
  "language": "auto",
9
6
  "models": {},
10
7
  "agents": {
@@ -15,12 +12,6 @@
15
12
  "resolver": {
16
13
  "enabled": true
17
14
  },
18
- "codex": {
19
- "enabled": false
20
- },
21
- "gpt": {
22
- "enabled": false
23
- },
24
15
  "explorer": {
25
16
  "enabled": true,
26
17
  "mode": "subagent"
@@ -40,17 +31,11 @@
40
31
  "architect": {
41
32
  "enabled": false
42
33
  },
43
- "gpt-coder": {
44
- "enabled": false
45
- },
46
34
  "debugger": {
47
35
  "enabled": false
48
36
  },
49
37
  "researcher": {
50
38
  "enabled": false
51
- },
52
- "glm": {
53
- "enabled": false
54
39
  }
55
40
  }
56
41
  }
@@ -17,23 +17,6 @@
17
17
  // permission values, and wrong types throw an error at load time.
18
18
 
19
19
  {
20
- // -----------------------------------------------------------------------
21
- // profile ("mix" | "glm" | "gpt")
22
- // Activates provider-specific agent configurations.
23
- // Set automatically by postinstall based on detected providers.
24
- //
25
- // "mix" — explicit mixed/default profile. Uses standard resolver prompts,
26
- // DEFAULT_ENABLED, and whatever model aliases you configure.
27
- // "glm" — GLM-only, optimized for ZAI coding-plan: reduced maxSteps,
28
- // token-efficient prompts, no hard concurrency cap by default.
29
- // No deep-reviewer by default.
30
- // "gpt" — GPT-only, high-performance: parallel coder dispatch, full agent
31
- // roster, higher maxSteps.
32
- //
33
- // When omitted, the plugin defaults to "mix".
34
- // -----------------------------------------------------------------------
35
- "profile": "mix",
36
-
37
20
  // -----------------------------------------------------------------------
38
21
  // tier ("bronze" | "silver" | "gold")
39
22
  // Agent roster preset. Overrides the default enabled list when set.
@@ -41,27 +24,22 @@
41
24
  // "bronze" — Minimum agents: coder + resolver only. Maximum token savings.
42
25
  // "silver" — Standard: coder, resolver, explorer, reviewer, planner.
43
26
  // No deep-reviewer. Best balance for most projects.
44
- // "gold" — Full power: all 8 agents including debugger and researcher.
45
- // Maximum capability for complex tasks.
46
- //
47
- // Postinstall sets this automatically:
48
- // GLM → silver, GPT → gold, Mix/unknown → no tier (DEFAULT_ENABLED applies).
27
+ // "gold" — Full power: all 9 agents including deep-reviewer, debugger,
28
+ // architect and researcher. Maximum capability for complex tasks.
49
29
  //
30
+ // When omitted, the default enabled list applies (see `enabled` below).
50
31
  // Explicit `enabled` array always wins over tier.
51
32
  // -----------------------------------------------------------------------
52
33
  // "tier": "silver",
53
34
 
54
35
  // -----------------------------------------------------------------------
55
36
  // enabled (string[])
56
- // Which resolve agents to inject. When omitted, the tier or profile default
57
- // is used. Explicit `enabled` wins over both tier and profile defaults.
37
+ // Which resolve agents to inject. When omitted, the tier default is used.
38
+ // Explicit `enabled` wins over tier.
58
39
  //
59
- // Mix/default (no tier): ["coder", "resolver", "explorer", "reviewer",
40
+ // Default (no tier): ["coder", "resolver", "explorer", "reviewer",
60
41
  // "deep-reviewer", "planner"].
61
42
  //
62
- // GLM profile default: ["coder", "resolver", "explorer", "reviewer",
63
- // "planner"] — deep-reviewer omitted to save tokens.
64
- //
65
43
  // Core path: resolver + coder form the fixed-role verified resolve loop.
66
44
  // Internal specialists: explorer, reviewer, deep-reviewer are injected as
67
45
  // subagents by default (OpenCode-native composition), but are NOT the
@@ -79,13 +57,6 @@
79
57
  // -----------------------------------------------------------------------
80
58
  "preserveNative": true,
81
59
 
82
- // -----------------------------------------------------------------------
83
- // context7 (boolean)
84
- // When true, registers the Context7 MCP server unless `mcp.context7` is
85
- // already configured. Default: true.
86
- // -----------------------------------------------------------------------
87
- "context7": true,
88
-
89
60
  // -----------------------------------------------------------------------
90
61
  // commands (boolean)
91
62
  // When true, adds three optional commands: `resolve`, `resolve-code`,
@@ -95,26 +66,23 @@
95
66
 
96
67
  // -----------------------------------------------------------------------
97
68
  // autoApprove (boolean)
98
- // Documentary flag. The plugin's permission.ask hook automatically
99
- // classifies bash commands as safe (allow) / dangerous (deny) / unknown (ask).
100
- // Base agent permissions are already set to the correct defaults (allow for
101
- // edit/webfetch, ask for bash on write agents, deny for read-only agents).
102
- // Changing this flag has no effect on behavior — it exists for config
103
- // readability and future compatibility. Default: true.
69
+ // When true, the plugin's permission.ask hook auto-approves safe bash
70
+ // commands on resolve agents (read-only probes, verify commands) and
71
+ // denies dangerous ones. Native OpenCode sessions are untouched this
72
+ // only applies while a resolve agent is active. Default: true.
104
73
  // -----------------------------------------------------------------------
105
74
  "autoApprove": true,
106
75
 
107
76
  // -----------------------------------------------------------------------
108
77
  // maxParallelSubagents (positive integer)
109
- // Optional prompt-level cap for how many subagents of the SAME ROLE the
110
- // resolver may dispatch concurrently. When omitted, the resolver uses soft
111
- // fan-out guidance and backs off on rate-limit errors. GLM profile does not
112
- // impose a hard cap unless you set one.
113
- // 1 = strict per-role serial
78
+ // Prompt-level cap for how many subagents of the SAME ROLE the resolver
79
+ // may dispatch concurrently.
80
+ // 1 = strict per-role serial (default when omitted token-efficient,
81
+ // avoids rate-limit thrash on quota-bound plans like ZAI coding-plan)
114
82
  // 2 = up to two coders in parallel
115
83
  // N = up to N of each role
116
84
  // -----------------------------------------------------------------------
117
- "maxParallelSubagents": 2,
85
+ // "maxParallelSubagents": 1,
118
86
 
119
87
  // -----------------------------------------------------------------------
120
88
  // language ("auto" | "en" | "ko")
@@ -125,22 +93,63 @@
125
93
  // "auto" — detect from $LANG (defaults to en if not Korean). Default.
126
94
  // "en" — force English.
127
95
  // "ko" — force Korean.
128
- //
129
- // Examples of what this affects:
130
- // en: "[resolver] Reminder: verify your changes ..."
131
- // ko: "[리졸버] 리마인더: 완료 보고 전에 변경사항을 검증하세요 ..."
132
96
  // -----------------------------------------------------------------------
133
97
  "language": "auto",
134
98
 
99
+ // -----------------------------------------------------------------------
100
+ // singleAgentMode (boolean)
101
+ // When true, the resolver makes ALL edits itself with edit/write tools and
102
+ // does NOT dispatch a coder subagent for implementation. Subagents may still
103
+ // be used to gather information or diagnose (explorer/debugger), but never
104
+ // to write code. Trades isolation for lower latency and token cost on
105
+ // simple tasks. Default: false (resolver dispatches a coder subagent).
106
+ // -----------------------------------------------------------------------
107
+ // "singleAgentMode": false,
108
+
109
+ // -----------------------------------------------------------------------
110
+ // permissions (object)
111
+ // Opt-in relaxations of the universal bash safety policy. Both default to
112
+ // false, and both apply ONLY to opencode-resolve's own agents — native
113
+ // opencode agents (build/plan/chat) keep the unconditional deny.
114
+ //
115
+ // allowGitReset — permits `git reset --hard`
116
+ // allowGitClean — permits `git clean -f` (and -fd, -df, ...)
117
+ //
118
+ // `git clean -x` / `-X` stays denied no matter what: it deletes gitignored
119
+ // files, and the checkpoint below snapshots via `git add -A`, which honours
120
+ // .gitignore. A `-x` clean would destroy files (.env, local secrets) the
121
+ // checkpoint cannot bring back.
122
+ //
123
+ // Without these, an agent that tangles the worktree mid-debug has no way to
124
+ // return to a clean state and stalls. With them, the agent can recover.
125
+ //
126
+ // Before either command runs, the plugin snapshots the ENTIRE worktree —
127
+ // tracked edits and untracked files — into a git ref:
128
+ //
129
+ // refs/resolve-checkpoint/<timestamp>-<reset|clean>
130
+ //
131
+ // The snapshot uses a throwaway index, so your real index, working tree,
132
+ // branches and HEAD are never touched. Nothing is staged or committed.
133
+ // If the snapshot cannot be written, the destructive command is blocked.
134
+ //
135
+ // To recover after a rollback you regret:
136
+ // git for-each-ref refs/resolve-checkpoint # list checkpoints
137
+ // git restore --source=<ref> -- . # bring everything back
138
+ //
139
+ // Checkpoints are also taken when you approve one of these commands at the
140
+ // permission prompt, even with both flags left false.
141
+ // -----------------------------------------------------------------------
142
+ // "permissions": {
143
+ // "allowGitReset": true,
144
+ // "allowGitClean": true
145
+ // },
146
+
135
147
  // -----------------------------------------------------------------------
136
148
  // models (object)
137
- // Alias map. Keys are either an agent name (coder, reviewer, resolver,
138
- // codex, gpt, glm, architect, gpt-coder, debugger, researcher, explorer,
139
- // deep-reviewer, planner)
140
- // OR one of the well-known aliases (`glm`, `gpt`, `quick`, `deep`,
141
- // `fast`, `strong`, `mini`, `codex`, `bronze`, `silver`, `gold`,
142
- // `gpt-bronze`, `gpt-silver`, `gpt-gold`, `glm-bronze`, `glm-silver`,
143
- // `glm-gold`).
149
+ // Alias map. Keys are either an agent name (coder, reviewer, resolver,
150
+ // architect, debugger, researcher, explorer, deep-reviewer, planner)
151
+ // OR one of the well-known aliases (`quick`, `deep`, `fast`, `strong`,
152
+ // `mini`, `bronze`, `silver`, `gold`).
144
153
  // Values are model identifiers OR another alias.
145
154
  //
146
155
  // Resolution order for a given agent:
@@ -150,26 +159,23 @@
150
159
  // 4. OpenCode's own fallback
151
160
  //
152
161
  // By default the models map is empty — all agents inherit the top-level
153
- // OpenCode default model. Pin models only when you have measured a
154
- // benefit from role-specific model selection.
162
+ // OpenCode default model. Pin models only when you want role-specific
163
+ // selection.
155
164
  //
156
- // When resolve.json is created for the first time by postinstall, the
157
- // plugin inspects your OpenCode model config and writes an adaptive
158
- // preset:
159
- // - interactive terminal always prompts for mix/gpt/glm, three-tier models,
160
- // and optional dedicated codex/glm primary agents
161
- // - non-interactive install → no guessed model pinning; profile mix,
162
- // models {}, and resolver/codex/glm primary routes enabled
163
- // - OPENCODE_RESOLVE_AUTO_PRESET=1 → legacy non-interactive
164
- // provider-adapted presets. GLM presets prefer high-concurrency models
165
- // such as GLM-5.1 / GLM-4.5 over low-concurrency Flash tiers.
165
+ // When resolve.json is created by postinstall, the plugin inspects your
166
+ // OpenCode model config and offers to pin a provider/model:
167
+ // - interactive terminal → detects providers, asks which one + which
168
+ // model(s), pins them. One model for everything is the recommended
169
+ // default.
170
+ // - non-interactive install → no guessed model pinning; all agents
171
+ // inherit the top-level OpenCode model.
166
172
  // Existing resolve.json files are never overwritten without consent.
167
173
  // Interactive reinstall asks whether to update or back up and run fresh
168
174
  // setup. Non-interactive automation can set:
169
175
  // OPENCODE_RESOLVE_REINSTALL=fresh
170
176
  // OPENCODE_RESOLVE_REINSTALL=update
171
177
  //
172
- // Example — one efficient model for everything (recommended default):
178
+ // Example — one model for everything (recommended default):
173
179
  // "models": {}
174
180
  //
175
181
  // Example — pin roles to specific models when needed:
@@ -180,26 +186,22 @@
180
186
  // "resolver": "strong"
181
187
  // }
182
188
  //
183
- // Example — GLM-only three-tier preset (auto-generated for GLM/ZAI users):
184
- // GLM fills all tiers — no GPT dependency, so token exhaustion on
185
- // third-party providers never blocks agent execution.
189
+ // Example — GLM-only three-tier preset (GLM fills all tiers, no GPT
190
+ // dependency, so quota exhaustion on third-party providers never blocks
191
+ // agent execution):
186
192
  // "models": {
187
- // "glm": "zai-coding-plan/glm-5.1",
188
- // "bronze": "zai-coding-plan/glm-4.5",
189
- // "silver": "zai-coding-plan/glm-5.1",
190
- // "gold": "zai-coding-plan/glm-5.1",
191
- // "fast": "bronze",
193
+ // "bronze": "zai-coding-plan/glm-5.2",
194
+ // "silver": "zai-coding-plan/glm-5.2",
195
+ // "gold": "zai-coding-plan/glm-5.2",
196
+ // "fast": "bronze",
192
197
  // "strong": "gold",
193
- // "coder": "gold",
198
+ // "coder": "gold",
194
199
  // "resolver": "gold",
195
200
  // "reviewer": "gold",
196
201
  // "deep-reviewer": "gold",
197
202
  // "explorer": "bronze",
198
203
  // "planner": "gold"
199
204
  // }
200
- //
201
- // Legacy aliases (glm, gpt, quick, deep) remain supported for backward
202
- // compatibility. New configs should prefer provider-neutral aliases.
203
205
  // -----------------------------------------------------------------------
204
206
  "models": {},
205
207
 
@@ -219,7 +221,7 @@
219
221
  "coder": {
220
222
  "enabled": true,
221
223
  "mode": "subagent",
222
- "maxSteps": 20,
224
+ "maxSteps": 15,
223
225
  "permission": {
224
226
  "edit": "allow",
225
227
  "bash": "allow",
@@ -230,7 +232,7 @@
230
232
  "resolver": {
231
233
  "enabled": true,
232
234
  "mode": "all",
233
- "maxSteps": 30,
235
+ "maxSteps": 25,
234
236
  "permission": {
235
237
  "edit": "allow",
236
238
  "bash": "allow",
@@ -238,28 +240,6 @@
238
240
  }
239
241
  },
240
242
 
241
- // codex — Codex-optimized primary resolver (selectable in agent picker)
242
- // Same verified resolve-loop style as resolver, with a Codex-specific
243
- // system prompt. Legacy — kept for backward compatibility. New GPT
244
- // installs should prefer the "gpt" agent instead.
245
- "codex": {
246
- "enabled": false,
247
- "mode": "all",
248
- "maxSteps": 35
249
- },
250
-
251
- // -----------------------------------------------------------------
252
- // gpt — GPT-optimized primary resolver (selectable in agent picker)
253
- // GPT-specific verified resolve-loop with parallel coder dispatch,
254
- // full agent roster, and higher maxSteps. Enabled automatically when
255
- // GPT profile is selected during install. Uses buildGPTResolverPrompt().
256
- // -----------------------------------------------------------------
257
- "gpt": {
258
- "enabled": false,
259
- "mode": "all",
260
- "maxSteps": 35
261
- },
262
-
263
243
  // Internal specialist subagents — enabled by default as subagents only.
264
244
  // Core path is resolver→coder. These are dispatched only when justified.
265
245
 
@@ -268,7 +248,7 @@
268
248
  // dispatches explorer only when scope is genuinely unknown.
269
249
  "explorer": {
270
250
  "mode": "subagent",
271
- "maxSteps": 6,
251
+ "maxSteps": 5,
272
252
  "permission": {
273
253
  "edit": "deny",
274
254
  "bash": "allow",
@@ -281,9 +261,7 @@
281
261
  // non-trivial changes.
282
262
  "reviewer": {
283
263
  "mode": "subagent",
284
- "maxSteps": 8,
285
- // Reviewer is read-only by design. edit and bash are denied even when
286
- // autoApprove is true.
264
+ "maxSteps": 6,
287
265
  "permission": {
288
266
  "edit": "deny",
289
267
  "bash": "deny",
@@ -304,6 +282,11 @@
304
282
  }
305
283
  },
306
284
 
285
+ "planner": {
286
+ "mode": "subagent",
287
+ "maxSteps": 8
288
+ },
289
+
307
290
  // Disabled by default — enable explicitly when needed.
308
291
 
309
292
  "architect": {
@@ -311,11 +294,6 @@
311
294
  "mode": "subagent",
312
295
  "maxSteps": 10
313
296
  },
314
- "gpt-coder": {
315
- "enabled": false,
316
- "mode": "subagent",
317
- "maxSteps": 20
318
- },
319
297
  "debugger": {
320
298
  "enabled": false,
321
299
  "mode": "subagent",
@@ -325,20 +303,6 @@
325
303
  "enabled": false,
326
304
  "mode": "subagent",
327
305
  "maxSteps": 8
328
- },
329
-
330
- // -----------------------------------------------------------------
331
- // glm — GLM-optimized orchestrator (selectable in agent picker)
332
- // Disabled by default. Enable to get a standalone GLM agent with
333
- // coding-plan optimized prompts: session limit handling,
334
- // token-efficient execution, no hard concurrency cap unless configured.
335
- // Users pick this from OpenCode's agent picker as an alternative
336
- // to the default resolver.
337
- // -----------------------------------------------------------------
338
- "glm": {
339
- "enabled": false,
340
- "mode": "all",
341
- "maxSteps": 30
342
306
  }
343
307
  }
344
308
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-resolve",
3
- "version": "0.1.20",
3
+ "version": "0.3.0",
4
4
  "description": "OpenCode plugin that adds a lightweight resolver/coder harness for continuous agentic coding.",
5
5
  "type": "module",
6
6
  "homepage": "https://jshsakura.github.io/opencode-resolve/",