opencode-resolve 0.1.7 → 0.1.8
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 +98 -53
- package/README.md +98 -53
- package/dist/agents.d.ts +26 -0
- package/dist/agents.js +355 -0
- package/dist/config.d.ts +29 -0
- package/dist/config.js +398 -0
- package/dist/hooks/index.d.ts +18 -0
- package/dist/hooks/index.js +493 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +11 -702
- package/dist/state.d.ts +33 -0
- package/dist/state.js +20 -0
- package/dist/tools/index.d.ts +252 -0
- package/dist/tools/index.js +1209 -0
- package/dist/types.d.ts +56 -0
- package/dist/types.js +1 -0
- package/dist/utils.d.ts +33 -0
- package/dist/utils.js +371 -0
- package/opencode-resolve.example.json +5 -2
- package/opencode-resolve.reference.jsonc +78 -19
- package/package.json +6 -2
- package/scripts/postinstall.mjs +193 -31
package/scripts/postinstall.mjs
CHANGED
|
@@ -17,6 +17,19 @@ const ADDITIVE_DEFAULTS = {
|
|
|
17
17
|
autoApprove: true,
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
// ZAI local MCP server bootstrap for GLM users.
|
|
21
|
+
// Do not copy provider secrets from OpenCode's auth store into opencode.json.
|
|
22
|
+
// The MCP process should receive credentials from the user's runtime environment.
|
|
23
|
+
const ZAI_MCP_SERVERS = {
|
|
24
|
+
"zai-mcp-server": {
|
|
25
|
+
type: "local",
|
|
26
|
+
command: ["npx", "-y", "@z_ai/mcp-server"],
|
|
27
|
+
environment: {
|
|
28
|
+
Z_AI_MODE: "ZAI",
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
}
|
|
32
|
+
|
|
20
33
|
const COMPANION_PLUGINS = [
|
|
21
34
|
{
|
|
22
35
|
pkg: "@tarquinen/opencode-dcp",
|
|
@@ -58,11 +71,19 @@ async function registerPlugin() {
|
|
|
58
71
|
await mkdir(configDir, { recursive: true })
|
|
59
72
|
|
|
60
73
|
const config = await readOpenCodeConfig()
|
|
61
|
-
|
|
74
|
+
let configChanged = addPlugin(config)
|
|
75
|
+
|
|
76
|
+
// Inject ZAI MCP servers when GLM is detected
|
|
77
|
+
const allModels = detectAllModels(config)
|
|
78
|
+
const hasGLM = allModels.some((m) => isGLMModel(m))
|
|
79
|
+
if (hasGLM) {
|
|
80
|
+
const mcpChanged = await injectZAIMCPs(config)
|
|
81
|
+
configChanged = configChanged || mcpChanged
|
|
82
|
+
}
|
|
62
83
|
|
|
63
|
-
if (
|
|
84
|
+
if (configChanged) {
|
|
64
85
|
await writeFile(opencodeConfigPath, `${JSON.stringify(config, null, 2)}\n`)
|
|
65
|
-
console.log(`[${packageName}]
|
|
86
|
+
console.log(`[${packageName}] updated ${opencodeConfigPath}`)
|
|
66
87
|
} else {
|
|
67
88
|
console.log(`[${packageName}] already registered in ${opencodeConfigPath}`)
|
|
68
89
|
}
|
|
@@ -81,9 +102,27 @@ async function createAdaptiveResolveConfig(opencodeConfig) {
|
|
|
81
102
|
const example = JSON.parse(raw)
|
|
82
103
|
|
|
83
104
|
const currentModel = detectOpenCodeModel(opencodeConfig)
|
|
84
|
-
const
|
|
85
|
-
|
|
105
|
+
const allModels = detectAllModels(opencodeConfig)
|
|
86
106
|
const resolveConfig = { ...example }
|
|
107
|
+
|
|
108
|
+
// Profile selection based on detected providers
|
|
109
|
+
const hasGLM = allModels.some((m) => isGLMModel(m))
|
|
110
|
+
const hasGPT = allModels.some((m) => isGPTModel(m))
|
|
111
|
+
const preset = buildModelPreset(currentModel, allModels)
|
|
112
|
+
|
|
113
|
+
if (hasGLM && !hasGPT) {
|
|
114
|
+
// GLM only → GLM profile, silver tier (token-efficient, no deep-reviewer)
|
|
115
|
+
resolveConfig.profile = "glm"
|
|
116
|
+
resolveConfig.tier = "silver"
|
|
117
|
+
} else if (hasGPT && !hasGLM) {
|
|
118
|
+
// GPT only → GPT profile, gold tier (full power)
|
|
119
|
+
resolveConfig.profile = "gpt"
|
|
120
|
+
resolveConfig.tier = "gold"
|
|
121
|
+
} else {
|
|
122
|
+
// Mixed or unknown provider → explicit mix profile. No tier: use DEFAULT_ENABLED.
|
|
123
|
+
resolveConfig.profile = "mix"
|
|
124
|
+
}
|
|
125
|
+
|
|
87
126
|
if (preset && Object.keys(preset).length > 0) {
|
|
88
127
|
resolveConfig.models = preset
|
|
89
128
|
}
|
|
@@ -121,54 +160,155 @@ function detectOpenCodeModel(config) {
|
|
|
121
160
|
return null
|
|
122
161
|
}
|
|
123
162
|
|
|
124
|
-
function buildModelPreset(currentModel) {
|
|
125
|
-
|
|
163
|
+
function buildModelPreset(currentModel, allModels = []) {
|
|
164
|
+
const glmModel = allModels.find((m) => isGLMModel(m))
|
|
165
|
+
const gptModel = allModels.find((m) => isGPTModel(m))
|
|
126
166
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
// GLM / ZAI mixed preset
|
|
130
|
-
if (lower.includes("glm") || lower.includes("zai")) {
|
|
167
|
+
if (glmModel && gptModel) {
|
|
131
168
|
return {
|
|
132
|
-
|
|
133
|
-
|
|
169
|
+
mix: "gpt",
|
|
170
|
+
glm: glmModel,
|
|
171
|
+
gpt: gptModel,
|
|
172
|
+
bronze: "glm",
|
|
173
|
+
silver: "glm",
|
|
174
|
+
gold: "gpt",
|
|
134
175
|
fast: "glm",
|
|
135
176
|
strong: "gpt",
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
177
|
+
mini: "glm",
|
|
178
|
+
codex: "gpt",
|
|
179
|
+
explorer: "bronze",
|
|
180
|
+
coder: "silver",
|
|
181
|
+
resolver: "gold",
|
|
182
|
+
reviewer: "gold",
|
|
183
|
+
"deep-reviewer": "gold",
|
|
184
|
+
planner: "gold",
|
|
141
185
|
}
|
|
142
186
|
}
|
|
143
187
|
|
|
188
|
+
if (!currentModel) {
|
|
189
|
+
if (glmModel) return buildGLMOnlyPreset(glmModel)
|
|
190
|
+
if (gptModel) return buildGPTOnlyPreset(gptModel)
|
|
191
|
+
return {}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const lower = currentModel.toLowerCase()
|
|
195
|
+
|
|
196
|
+
// GLM / ZAI — GLM-only preset (no GPT dependency, avoids token-exhaustion errors)
|
|
197
|
+
if (lower.includes("glm") || lower.includes("zai")) {
|
|
198
|
+
return buildGLMOnlyPreset(currentModel)
|
|
199
|
+
}
|
|
200
|
+
|
|
144
201
|
// OpenAI / GPT single-provider preset
|
|
145
202
|
if (lower.includes("openai/") || lower.includes("gpt")) {
|
|
146
|
-
return
|
|
147
|
-
gpt: currentModel,
|
|
148
|
-
fast: "gpt",
|
|
149
|
-
strong: "gpt",
|
|
150
|
-
mini: "gpt",
|
|
151
|
-
codex: "gpt",
|
|
152
|
-
coder: "gpt",
|
|
153
|
-
resolver: "gpt",
|
|
154
|
-
explorer: "gpt",
|
|
155
|
-
reviewer: "gpt",
|
|
156
|
-
"deep-reviewer": "gpt",
|
|
157
|
-
}
|
|
203
|
+
return buildGPTOnlyPreset(currentModel)
|
|
158
204
|
}
|
|
159
205
|
|
|
160
206
|
// Unknown provider — keep model-neutral
|
|
161
207
|
return {}
|
|
162
208
|
}
|
|
163
209
|
|
|
210
|
+
function buildGLMOnlyPreset(model) {
|
|
211
|
+
return {
|
|
212
|
+
glm: model,
|
|
213
|
+
fast: "glm",
|
|
214
|
+
strong: "glm",
|
|
215
|
+
coder: "glm",
|
|
216
|
+
resolver: "glm",
|
|
217
|
+
reviewer: "glm",
|
|
218
|
+
"deep-reviewer": "glm",
|
|
219
|
+
explorer: "fast",
|
|
220
|
+
planner: "glm",
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function buildGPTOnlyPreset(model) {
|
|
225
|
+
return {
|
|
226
|
+
gpt: model,
|
|
227
|
+
fast: "gpt",
|
|
228
|
+
strong: "gpt",
|
|
229
|
+
mini: "gpt",
|
|
230
|
+
codex: "gpt",
|
|
231
|
+
coder: "gpt",
|
|
232
|
+
resolver: "gpt",
|
|
233
|
+
explorer: "gpt",
|
|
234
|
+
reviewer: "gpt",
|
|
235
|
+
"deep-reviewer": "gpt",
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
164
239
|
function getPresetLabel(currentModel) {
|
|
165
240
|
if (!currentModel) return "inherited"
|
|
166
241
|
const lower = currentModel.toLowerCase()
|
|
167
|
-
if (lower.includes("glm") || lower.includes("zai")) return "glm
|
|
242
|
+
if (lower.includes("glm") || lower.includes("zai")) return "glm-only"
|
|
168
243
|
if (lower.includes("openai/") || lower.includes("gpt")) return "gpt-only"
|
|
169
244
|
return "inherited"
|
|
170
245
|
}
|
|
171
246
|
|
|
247
|
+
function isGLMModel(currentModel) {
|
|
248
|
+
if (!currentModel) return false
|
|
249
|
+
const lower = currentModel.toLowerCase()
|
|
250
|
+
return lower.includes("glm") || lower.includes("zai")
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
function isGPTModel(currentModel) {
|
|
254
|
+
if (!currentModel) return false
|
|
255
|
+
const lower = currentModel.toLowerCase()
|
|
256
|
+
return lower.includes("openai/") || lower.includes("gpt")
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function detectAllModels(config) {
|
|
260
|
+
const models = new Set()
|
|
261
|
+
|
|
262
|
+
// Top-level model
|
|
263
|
+
if (typeof config.model === "string" && config.model.length > 0) {
|
|
264
|
+
models.add(config.model)
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Top-level models object values
|
|
268
|
+
if (isObject(config.models)) {
|
|
269
|
+
for (const value of Object.values(config.models)) {
|
|
270
|
+
if (typeof value === "string" && value.length > 0) {
|
|
271
|
+
models.add(value)
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Provider model lists
|
|
277
|
+
if (isObject(config.provider)) {
|
|
278
|
+
for (const [providerId, providerConfig] of Object.entries(config.provider)) {
|
|
279
|
+
if (isObject(providerConfig) && isObject(providerConfig.models)) {
|
|
280
|
+
for (const [modelKey, modelEntry] of Object.entries(providerConfig.models)) {
|
|
281
|
+
if (typeof modelKey === "string" && modelKey.length > 0) {
|
|
282
|
+
models.add(qualifyModelId(providerId, modelKey))
|
|
283
|
+
}
|
|
284
|
+
if (typeof modelEntry === "string") {
|
|
285
|
+
models.add(qualifyModelId(providerId, modelEntry))
|
|
286
|
+
} else if (isObject(modelEntry) && typeof modelEntry.id === "string") {
|
|
287
|
+
models.add(qualifyModelId(providerId, modelEntry.id))
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Agent model values
|
|
295
|
+
if (isObject(config.agent)) {
|
|
296
|
+
for (const agentConfig of Object.values(config.agent)) {
|
|
297
|
+
if (isObject(agentConfig) && typeof agentConfig.model === "string" && agentConfig.model.length > 0) {
|
|
298
|
+
models.add(agentConfig.model)
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
return [...models]
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function qualifyModelId(providerId, modelId) {
|
|
307
|
+
if (typeof modelId !== "string" || modelId.length === 0) return modelId
|
|
308
|
+
if (modelId.includes("/")) return modelId
|
|
309
|
+
return `${providerId}/${modelId}`
|
|
310
|
+
}
|
|
311
|
+
|
|
172
312
|
async function migrateResolveConfig() {
|
|
173
313
|
let raw
|
|
174
314
|
try {
|
|
@@ -239,6 +379,28 @@ function addPlugin(config) {
|
|
|
239
379
|
return true
|
|
240
380
|
}
|
|
241
381
|
|
|
382
|
+
async function injectZAIMCPs(config) {
|
|
383
|
+
config.mcp ??= {}
|
|
384
|
+
if (!isObject(config.mcp)) return false
|
|
385
|
+
|
|
386
|
+
const added = []
|
|
387
|
+
for (const [name, mcpConfig] of Object.entries(ZAI_MCP_SERVERS)) {
|
|
388
|
+
if (config.mcp[name] === undefined) {
|
|
389
|
+
config.mcp[name] = mcpConfig
|
|
390
|
+
added.push(name)
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
if (added.length > 0) {
|
|
395
|
+
console.log(`[${packageName}] injected ZAI MCP server config: ${added.join(", ")}`)
|
|
396
|
+
console.log(`[${packageName}] note: API keys are not copied into opencode.json; export Z_AI_API_KEY if the MCP server requires it.`)
|
|
397
|
+
return true
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
console.log(`[${packageName}] ZAI MCP server already present — skipping`)
|
|
401
|
+
return false
|
|
402
|
+
}
|
|
403
|
+
|
|
242
404
|
function isRegisteredPluginEntry(entry) {
|
|
243
405
|
if (typeof entry === "string") return isResolvePluginName(entry)
|
|
244
406
|
if (Array.isArray(entry) && typeof entry[0] === "string") return isResolvePluginName(entry[0])
|