opencode-resolve 0.1.13 → 0.1.16
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 +216 -850
- package/README.md +215 -849
- package/dist/agents.js +14 -14
- package/dist/config.d.ts +1 -0
- package/dist/config.js +10 -0
- package/dist/hooks/index.js +131 -40
- package/dist/messages.d.ts +34 -0
- package/dist/messages.js +867 -0
- package/dist/state.d.ts +3 -0
- package/dist/state.js +2 -1
- package/dist/types.d.ts +2 -0
- package/dist/utils.js +20 -3
- package/opencode-resolve.example.json +1 -0
- package/opencode-resolve.reference.jsonc +20 -3
- package/package.json +5 -2
- package/scripts/cli.mjs +75 -0
- package/scripts/install-local.mjs +33 -7
- package/scripts/postinstall.mjs +215 -22
package/dist/state.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ProjectContext, ResolveConfig } from "./types.js";
|
|
2
|
+
import type { Locale } from "./messages.js";
|
|
2
3
|
export declare const DIAGNOSTICS_TTL_MS = 30000;
|
|
3
4
|
export declare const FAILURE_PATTERN_TTL_MS = 120000;
|
|
4
5
|
export declare const FAILURE_THRESHOLD = 10;
|
|
@@ -29,5 +30,7 @@ export interface SessionState {
|
|
|
29
30
|
sessionStartTime: number;
|
|
30
31
|
loopWarnings: string[];
|
|
31
32
|
lastStrategyHint: string;
|
|
33
|
+
currentAgent?: string;
|
|
34
|
+
locale: Locale;
|
|
32
35
|
}
|
|
33
36
|
export declare function createSessionState(): SessionState;
|
package/dist/state.js
CHANGED
package/dist/types.d.ts
CHANGED
|
@@ -21,6 +21,7 @@ export type ResolveAgentConfig = {
|
|
|
21
21
|
};
|
|
22
22
|
export type ProfileName = "mix" | "glm" | "gpt";
|
|
23
23
|
export type TierName = "bronze" | "silver" | "gold";
|
|
24
|
+
export type LanguageSetting = "auto" | "en" | "ko";
|
|
24
25
|
export type ResolveConfig = {
|
|
25
26
|
profile?: ProfileName;
|
|
26
27
|
tier?: TierName;
|
|
@@ -33,6 +34,7 @@ export type ResolveConfig = {
|
|
|
33
34
|
autoApprove?: boolean;
|
|
34
35
|
maxParallelSubagents?: number;
|
|
35
36
|
autoUpdate?: boolean;
|
|
37
|
+
language?: LanguageSetting;
|
|
36
38
|
};
|
|
37
39
|
export type ResolvePluginOptions = ResolveConfig & {
|
|
38
40
|
config?: string;
|
package/dist/utils.js
CHANGED
|
@@ -246,9 +246,12 @@ export function isNewerVersion(candidate, baseline) {
|
|
|
246
246
|
return false;
|
|
247
247
|
}
|
|
248
248
|
export async function maybeAutoUpdate() {
|
|
249
|
+
const previous = readUpdateCheckCache();
|
|
249
250
|
try {
|
|
250
|
-
const previous = readUpdateCheckCache();
|
|
251
251
|
if (previous && Date.now() - previous.checkedAt < UPDATE_CHECK_INTERVAL_MS) {
|
|
252
|
+
if (isNewerVersion(previous.latest, PLUGIN_VERSION)) {
|
|
253
|
+
refreshPluginCacheInBackground(previous.latest, "cached");
|
|
254
|
+
}
|
|
252
255
|
return;
|
|
253
256
|
}
|
|
254
257
|
}
|
|
@@ -280,9 +283,22 @@ export async function maybeAutoUpdate() {
|
|
|
280
283
|
}
|
|
281
284
|
if (!isNewerVersion(latest, PLUGIN_VERSION))
|
|
282
285
|
return;
|
|
283
|
-
|
|
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.`);
|
|
284
291
|
try {
|
|
285
|
-
spawn("sh", ["-c", `rm -rf "${PLUGIN_CACHE_DIR}" && opencode plugin opencode-resolve --global --force`], {
|
|
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();
|
|
286
302
|
}
|
|
287
303
|
catch {
|
|
288
304
|
// If spawn fails, the user already saw the notice and can run the command manually.
|
|
@@ -311,6 +327,7 @@ export const BANNED_COMMANDS = [
|
|
|
311
327
|
/\b(irb|ghci|scala|jshell)\b(\s*$)/, // other REPLs
|
|
312
328
|
/\b(bash|zsh|fish|sh)\s+-i\b/, // interactive shells
|
|
313
329
|
/\bgit\s+add\s+-p\b/, // interactive git add
|
|
330
|
+
/\bgit\s+add\s+(\.|-A|--all)(\s|$)/, // broad staging can capture unrelated files
|
|
314
331
|
/\bgit\s+rebase\s+-i\b/, // interactive rebase
|
|
315
332
|
/\bgit\s+commit\b(?!\s+-m)/, // commit without -m
|
|
316
333
|
/\bscreen\b/, // screen multiplexer
|
|
@@ -116,6 +116,22 @@
|
|
|
116
116
|
// -----------------------------------------------------------------------
|
|
117
117
|
"maxParallelSubagents": 2,
|
|
118
118
|
|
|
119
|
+
// -----------------------------------------------------------------------
|
|
120
|
+
// language ("auto" | "en" | "ko")
|
|
121
|
+
// Locale for hook-generated reminders, role-play narration, and system
|
|
122
|
+
// nudges. Does NOT change agent prompts or model output — only the
|
|
123
|
+
// plugin's own messages.
|
|
124
|
+
//
|
|
125
|
+
// "auto" — detect from $LANG (defaults to en if not Korean). Default.
|
|
126
|
+
// "en" — force English.
|
|
127
|
+
// "ko" — force Korean.
|
|
128
|
+
//
|
|
129
|
+
// Examples of what this affects:
|
|
130
|
+
// en: "[resolver] Reminder: verify your changes ..."
|
|
131
|
+
// ko: "[리졸버] 리마인더: 완료 보고 전에 변경사항을 검증하세요 ..."
|
|
132
|
+
// -----------------------------------------------------------------------
|
|
133
|
+
"language": "auto",
|
|
134
|
+
|
|
119
135
|
// -----------------------------------------------------------------------
|
|
120
136
|
// models (object)
|
|
121
137
|
// Alias map. Keys are either an agent name (coder, reviewer, resolver,
|
|
@@ -145,7 +161,8 @@
|
|
|
145
161
|
// - non-interactive install → no guessed model pinning; profile mix,
|
|
146
162
|
// models {}, and resolver/codex/glm primary routes enabled
|
|
147
163
|
// - OPENCODE_RESOLVE_AUTO_PRESET=1 → legacy non-interactive
|
|
148
|
-
// provider-adapted presets
|
|
164
|
+
// provider-adapted presets. GLM presets prefer high-concurrency models
|
|
165
|
+
// such as GLM-5.1 / GLM-4.5 over low-concurrency Flash tiers.
|
|
149
166
|
// Existing resolve.json files are never overwritten without consent.
|
|
150
167
|
// Interactive reinstall asks whether to update or back up and run fresh
|
|
151
168
|
// setup. Non-interactive automation can set:
|
|
@@ -168,8 +185,8 @@
|
|
|
168
185
|
// third-party providers never blocks agent execution.
|
|
169
186
|
// "models": {
|
|
170
187
|
// "glm": "zai-coding-plan/glm-5.1",
|
|
171
|
-
// "bronze": "zai-coding-plan/glm-4.
|
|
172
|
-
// "silver": "zai-coding-plan/glm-5",
|
|
188
|
+
// "bronze": "zai-coding-plan/glm-4.5",
|
|
189
|
+
// "silver": "zai-coding-plan/glm-5.1",
|
|
173
190
|
// "gold": "zai-coding-plan/glm-5.1",
|
|
174
191
|
// "fast": "bronze",
|
|
175
192
|
// "strong": "gold",
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-resolve",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.16",
|
|
4
4
|
"description": "OpenCode plugin that adds a lightweight resolver/coder harness for continuous agentic coding.",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"homepage": "https://github.
|
|
6
|
+
"homepage": "https://jshsakura.github.io/opencode-resolve/",
|
|
7
7
|
"bugs": {
|
|
8
8
|
"url": "https://github.com/jshsakura/opencode-resolve/issues"
|
|
9
9
|
},
|
|
@@ -19,6 +19,9 @@
|
|
|
19
19
|
"types": "./dist/index.d.ts"
|
|
20
20
|
}
|
|
21
21
|
},
|
|
22
|
+
"bin": {
|
|
23
|
+
"opencode-resolve": "./scripts/cli.mjs"
|
|
24
|
+
},
|
|
22
25
|
"files": [
|
|
23
26
|
"dist",
|
|
24
27
|
"scripts",
|
package/scripts/cli.mjs
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawn } from "node:child_process"
|
|
3
|
+
import { dirname, join, resolve } from "node:path"
|
|
4
|
+
import { fileURLToPath } from "node:url"
|
|
5
|
+
|
|
6
|
+
const root = resolve(dirname(fileURLToPath(import.meta.url)), "..")
|
|
7
|
+
const postinstall = join(root, "scripts", "postinstall.mjs")
|
|
8
|
+
const args = process.argv.slice(2)
|
|
9
|
+
const command = args[0] && !args[0].startsWith("-") ? args.shift() : "setup"
|
|
10
|
+
|
|
11
|
+
if (command === "help" || args.includes("--help") || args.includes("-h")) {
|
|
12
|
+
printHelp()
|
|
13
|
+
process.exit(0)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (command !== "setup") {
|
|
17
|
+
console.error(`Unknown command: ${command}`)
|
|
18
|
+
printHelp()
|
|
19
|
+
process.exit(1)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const env = { ...process.env }
|
|
23
|
+
if (args.includes("--fresh")) env.OPENCODE_RESOLVE_REINSTALL = "fresh"
|
|
24
|
+
if (args.includes("--reset-config")) {
|
|
25
|
+
env.OPENCODE_RESOLVE_REINSTALL = "fresh"
|
|
26
|
+
env.OPENCODE_RESOLVE_RESET_MODELS = "1"
|
|
27
|
+
}
|
|
28
|
+
if (args.includes("--update")) env.OPENCODE_RESOLVE_REINSTALL = "update"
|
|
29
|
+
if (args.includes("--models") || args.includes("--configure-models")) env.OPENCODE_RESOLVE_CONFIGURE_MODELS = "1"
|
|
30
|
+
if (args.includes("--auto-preset")) env.OPENCODE_RESOLVE_AUTO_PRESET = "1"
|
|
31
|
+
if (args.includes("--no-companions")) env.OPENCODE_RESOLVE_SKIP_COMPANIONS = "1"
|
|
32
|
+
if (args.includes("--force-cache") || args.includes("--refresh-cache")) env.OPENCODE_RESOLVE_FORCE_CACHE_REFRESH = "1"
|
|
33
|
+
|
|
34
|
+
const child = spawn(process.execPath, [postinstall], {
|
|
35
|
+
stdio: "inherit",
|
|
36
|
+
env,
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
child.on("exit", (code, signal) => {
|
|
40
|
+
if (signal) {
|
|
41
|
+
process.kill(process.pid, signal)
|
|
42
|
+
return
|
|
43
|
+
}
|
|
44
|
+
process.exit(code ?? 1)
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
child.on("error", (error) => {
|
|
48
|
+
console.error(error.message)
|
|
49
|
+
process.exit(1)
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
function printHelp() {
|
|
53
|
+
console.log(`opencode-resolve
|
|
54
|
+
|
|
55
|
+
Usage:
|
|
56
|
+
opencode-resolve setup [--fresh|--update|--reset-config] [--models] [--auto-preset] [--force-cache] [--no-companions]
|
|
57
|
+
|
|
58
|
+
Commands:
|
|
59
|
+
setup Register the OpenCode plugin, create or migrate resolve.json, and refresh stale plugin cache.
|
|
60
|
+
|
|
61
|
+
Options:
|
|
62
|
+
--fresh Back up existing resolve.json and run setup again, preserving existing model pins.
|
|
63
|
+
--update Preserve existing resolve.json and add missing defaults.
|
|
64
|
+
--reset-config Back up existing resolve.json and regenerate it, including model pins.
|
|
65
|
+
--models Reconfigure model pins without replacing the rest of resolve.json.
|
|
66
|
+
--auto-preset Non-interactive provider-based model preset.
|
|
67
|
+
--force-cache Force OpenCode plugin cache refresh without deleting resolve.json.
|
|
68
|
+
--no-companions Skip companion plugin suggestions.
|
|
69
|
+
|
|
70
|
+
Examples:
|
|
71
|
+
opencode-resolve setup --fresh
|
|
72
|
+
opencode-resolve setup --update
|
|
73
|
+
opencode-resolve setup --force-cache
|
|
74
|
+
`)
|
|
75
|
+
}
|
|
@@ -40,20 +40,23 @@ async function handleExistingResolveConfig() {
|
|
|
40
40
|
return
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
const existing = await readExistingResolveConfig()
|
|
43
44
|
await backupResolveConfig()
|
|
44
|
-
await createAdaptiveResolveConfig(
|
|
45
|
+
await createAdaptiveResolveConfig({
|
|
46
|
+
preservedModels: process.env.OPENCODE_RESOLVE_RESET_MODELS === "1" ? undefined : existing?.models,
|
|
47
|
+
})
|
|
45
48
|
}
|
|
46
49
|
|
|
47
50
|
async function chooseExistingResolveConfigAction() {
|
|
48
|
-
const requested = (
|
|
51
|
+
const requested = readInstallerOption("reinstall").trim().toLowerCase()
|
|
49
52
|
if (["fresh", "reset", "recreate", "new"].includes(requested)) return "fresh"
|
|
50
53
|
if (["update", "keep", "migrate", "preserve"].includes(requested)) return "update"
|
|
51
54
|
if (requested) {
|
|
52
|
-
console.warn(`Ignoring unknown
|
|
55
|
+
console.warn(`Ignoring unknown reinstall mode ${JSON.stringify(requested)}; use "fresh" or "update".`)
|
|
53
56
|
}
|
|
54
57
|
|
|
55
58
|
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
56
|
-
console.log(
|
|
59
|
+
console.log("Existing resolve config found; preserving it. Run `opencode-resolve setup --models` for model setup or `opencode-resolve setup --fresh` to regenerate without dropping model pins.")
|
|
57
60
|
return "update"
|
|
58
61
|
}
|
|
59
62
|
|
|
@@ -62,7 +65,7 @@ async function chooseExistingResolveConfigAction() {
|
|
|
62
65
|
console.log("")
|
|
63
66
|
console.log(`Existing resolve config found: ${resolveConfigPath}`)
|
|
64
67
|
console.log(" 1. update existing config — preserve your settings")
|
|
65
|
-
console.log(" 2. fresh reinstall — back up resolve.json and create a new config")
|
|
68
|
+
console.log(" 2. fresh reinstall — back up resolve.json and create a new config, preserving model pins")
|
|
66
69
|
const raw = await rl.question("Existing config [1=update, 2=fresh reinstall, default 1]: ")
|
|
67
70
|
return raw.trim() === "2" ? "fresh" : "update"
|
|
68
71
|
} finally {
|
|
@@ -78,9 +81,20 @@ async function backupResolveConfig() {
|
|
|
78
81
|
console.log(`Backed up existing resolve config to ${backupPath}`)
|
|
79
82
|
}
|
|
80
83
|
|
|
81
|
-
async function
|
|
84
|
+
async function readExistingResolveConfig() {
|
|
85
|
+
try {
|
|
86
|
+
const raw = await readFile(resolveConfigPath, "utf8")
|
|
87
|
+
const parsed = JSON.parse(raw)
|
|
88
|
+
return isObject(parsed) ? parsed : undefined
|
|
89
|
+
} catch {
|
|
90
|
+
return undefined
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async function createAdaptiveResolveConfig(options = {}) {
|
|
82
95
|
const raw = await readFile(exampleConfig, "utf8")
|
|
83
96
|
const example = JSON.parse(raw)
|
|
97
|
+
const preservedModels = isObject(options.preservedModels) ? options.preservedModels : undefined
|
|
84
98
|
|
|
85
99
|
let opencodeConfig = {}
|
|
86
100
|
try {
|
|
@@ -105,7 +119,9 @@ async function createAdaptiveResolveConfig() {
|
|
|
105
119
|
}
|
|
106
120
|
}
|
|
107
121
|
if (preset && Object.keys(preset).length > 0) {
|
|
108
|
-
resolveConfig.models = preset
|
|
122
|
+
resolveConfig.models = preservedModels ? { ...preset, ...preservedModels } : preset
|
|
123
|
+
} else if (preservedModels) {
|
|
124
|
+
resolveConfig.models = { ...preservedModels }
|
|
109
125
|
}
|
|
110
126
|
|
|
111
127
|
await mkdir(configDir, { recursive: true })
|
|
@@ -198,3 +214,13 @@ function isMissingFileError(error) {
|
|
|
198
214
|
function isObject(value) {
|
|
199
215
|
return typeof value === "object" && value !== null && !Array.isArray(value)
|
|
200
216
|
}
|
|
217
|
+
|
|
218
|
+
function readInstallerOption(name) {
|
|
219
|
+
const normalized = name.toUpperCase().replace(/-/g, "_")
|
|
220
|
+
const npmName = name.toLowerCase().replace(/-/g, "_")
|
|
221
|
+
return (
|
|
222
|
+
process.env[`OPENCODE_RESOLVE_${normalized}`] ??
|
|
223
|
+
process.env[`npm_config_opencode_resolve_${npmName}`] ??
|
|
224
|
+
""
|
|
225
|
+
)
|
|
226
|
+
}
|