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/README.ko.md +39 -46
- package/README.md +39 -46
- package/dist/agents.d.ts +3 -19
- package/dist/agents.js +45 -205
- package/dist/checkpoint.d.ts +22 -0
- package/dist/checkpoint.js +72 -0
- package/dist/config.d.ts +3 -1
- package/dist/config.js +30 -47
- package/dist/hooks/index.js +299 -118
- package/dist/index.d.ts +5 -1
- package/dist/index.js +4 -1
- package/dist/messages.d.ts +1 -1
- package/dist/messages.js +28 -56
- package/dist/state.d.ts +13 -0
- package/dist/state.js +9 -0
- package/dist/tools/index.d.ts +11 -2
- package/dist/tools/index.js +131 -21
- package/dist/types.d.ts +12 -5
- package/dist/utils.d.ts +11 -11
- package/dist/utils.js +55 -97
- package/opencode-resolve.example.json +0 -15
- package/opencode-resolve.reference.jsonc +94 -130
- package/package.json +1 -1
- package/scripts/cli.mjs +13 -9
- package/scripts/install-local.mjs +4 -18
- package/scripts/postinstall.mjs +132 -495
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
|
|
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
|
-
|
|
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
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
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
|
-
|
|
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
|
-
|
|
359
|
-
|
|
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
|
|
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
|
|
57
|
-
//
|
|
37
|
+
// Which resolve agents to inject. When omitted, the tier default is used.
|
|
38
|
+
// Explicit `enabled` wins over tier.
|
|
58
39
|
//
|
|
59
|
-
//
|
|
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
|
-
//
|
|
99
|
-
//
|
|
100
|
-
//
|
|
101
|
-
//
|
|
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
|
-
//
|
|
110
|
-
//
|
|
111
|
-
//
|
|
112
|
-
//
|
|
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":
|
|
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
|
-
//
|
|
139
|
-
//
|
|
140
|
-
//
|
|
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
|
|
154
|
-
//
|
|
162
|
+
// OpenCode default model. Pin models only when you want role-specific
|
|
163
|
+
// selection.
|
|
155
164
|
//
|
|
156
|
-
// When resolve.json is created
|
|
157
|
-
//
|
|
158
|
-
//
|
|
159
|
-
//
|
|
160
|
-
//
|
|
161
|
-
// - non-interactive install → no guessed model pinning;
|
|
162
|
-
//
|
|
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
|
|
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 (
|
|
184
|
-
//
|
|
185
|
-
//
|
|
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
|
-
// "
|
|
188
|
-
// "
|
|
189
|
-
// "
|
|
190
|
-
// "
|
|
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":
|
|
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":
|
|
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":
|
|
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":
|
|
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":
|
|
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.
|
|
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/",
|