@ljwei-stak/dsh-model-router 0.17.0 → 0.18.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.
@@ -24,7 +24,7 @@
24
24
  export const DEFAULT_NPM_REGISTRY = 'https://registry.npmjs.org/'
25
25
 
26
26
  /** Shared shape of a "package manager" method: argv only, no script staging. */
27
- function packageManagerMethod(id, label, manager, spec, { registryFlag = '--registry=' } = {}) {
27
+ function packageManagerMethod(id, label, manager, spec, { registryFlag = '--registry=', command = 'install', extraArgs = [] } = {}) {
28
28
  return Object.freeze({
29
29
  id,
30
30
  label,
@@ -32,16 +32,21 @@ function packageManagerMethod(id, label, manager, spec, { registryFlag = '--regi
32
32
  manager,
33
33
  spec,
34
34
  registryFlag,
35
- installArgs: Object.freeze(['install', '-g', spec]),
35
+ installArgs: Object.freeze([command, '-g', spec, ...extraArgs]),
36
36
  uninstallArgs: Object.freeze(['uninstall', '-g', spec.replace(/@latest$/, '')]),
37
- /** npm/pnpm both accept --prefix to place a global install off the default. */
37
+ /** The resolver binds npm prefix or pnpm global-dir/global-bin-dir. */
38
38
  supportsInstallDir: true,
39
39
  supportsRegistry: true,
40
40
  })
41
41
  }
42
42
 
43
43
  /** Vendor installer script run from a verified local copy. */
44
- function scriptMethod(id, label, { shell, scriptUrl, verify, installArg = [], env = [], platforms, supportsInstallDir = false }) {
44
+ function scriptMethod(id, label, {
45
+ shell, scriptUrl, verify, installArg = [], env = [], platforms,
46
+ supportsInstallDir = false, installDirEnv = '', installDirSuffix = '',
47
+ defaultScriptInstallDir, defaultScriptInstallDirEnv, scriptBinaryNames,
48
+ registryEnv, installDirSubdir, uninstallUnsupportedReason, scriptFallbackUrls,
49
+ }) {
45
50
  return Object.freeze({
46
51
  id,
47
52
  label,
@@ -56,7 +61,16 @@ function scriptMethod(id, label, { shell, scriptUrl, verify, installArg = [], en
56
61
  platforms: Object.freeze(platforms),
57
62
  /** Whether the vendor script honours a caller-chosen directory at all. */
58
63
  supportsInstallDir,
59
- supportsRegistry: false,
64
+ installDirEnv,
65
+ installDirSuffix,
66
+ ...(installDirSubdir ? { installDirSubdir } : {}),
67
+ ...(uninstallUnsupportedReason ? { uninstallUnsupportedReason } : {}),
68
+ ...(defaultScriptInstallDir ? { defaultScriptInstallDir } : {}),
69
+ ...(defaultScriptInstallDirEnv ? { defaultScriptInstallDirEnv } : {}),
70
+ ...(scriptBinaryNames ? { scriptBinaryNames: Object.freeze(scriptBinaryNames) } : {}),
71
+ ...(scriptFallbackUrls ? { scriptFallbackUrls: Object.freeze(scriptFallbackUrls) } : {}),
72
+ ...(registryEnv ? { registryEnv } : {}),
73
+ supportsRegistry: Boolean(registryEnv),
60
74
  })
61
75
  }
62
76
 
@@ -73,9 +87,27 @@ export const OFFICIAL_TOOLS = Object.freeze([
73
87
  probeExecutables: ['kimi'],
74
88
  probeNote: 'kimi 与旧 Python 版 kimi-cli 同名;请核对可执行文件来源和版本。',
75
89
  providerHints: ['moonshot', 'kimi'],
90
+ scriptBinaryNames: Object.freeze(['kimi', 'kimi.exe']),
91
+ defaultScriptInstallDir: '.kimi-code/bin',
76
92
  installMethods: Object.freeze([
77
93
  packageManagerMethod('npm', 'npm', 'npm', '@moonshot-ai/kimi-code@latest'),
78
94
  packageManagerMethod('pnpm', 'pnpm', 'pnpm', '@moonshot-ai/kimi-code@latest'),
95
+ scriptMethod('script-bash', 'curl | bash', {
96
+ shell: 'bash', scriptUrl: 'https://code.kimi.com/kimi-code/install.sh',
97
+ platforms: ['linux', 'darwin'], supportsInstallDir: true,
98
+ installDirEnv: 'KIMI_INSTALL_DIR', installDirSuffix: 'bin',
99
+ env: ['KIMI_INSTALL_DIR'],
100
+ scriptBinaryNames: ['kimi'],
101
+ verify: Object.freeze({ mustInclude: ['kimi-code', 'code.kimi.com/kimi-code'] }),
102
+ }),
103
+ scriptMethod('script-powershell', 'irm | iex', {
104
+ shell: 'powershell', scriptUrl: 'https://code.kimi.com/kimi-code/install.ps1',
105
+ platforms: ['win32'], supportsInstallDir: true,
106
+ installDirEnv: 'KIMI_INSTALL_DIR', installDirSuffix: 'bin',
107
+ env: ['KIMI_INSTALL_DIR'],
108
+ scriptBinaryNames: ['kimi.exe'],
109
+ verify: Object.freeze({ mustInclude: ['kimi-code', 'code.kimi.com/kimi-code'] }),
110
+ }),
79
111
  ]),
80
112
  }),
81
113
  Object.freeze({
@@ -89,9 +121,29 @@ export const OFFICIAL_TOOLS = Object.freeze([
89
121
  uninstallArgs: ['uninstall', '-g', '@anthropic-ai/claude-code'],
90
122
  probeExecutables: ['claude'],
91
123
  providerHints: ['anthropic', 'claude'],
124
+ scriptBinaryNames: Object.freeze(['claude', 'claude.exe']),
125
+ defaultScriptInstallDir: '.local/bin',
92
126
  installMethods: Object.freeze([
93
127
  packageManagerMethod('npm', 'npm', 'npm', '@anthropic-ai/claude-code@latest'),
94
- packageManagerMethod('pnpm', 'pnpm', 'pnpm', '@anthropic-ai/claude-code@latest'),
128
+ packageManagerMethod('pnpm', 'pnpm', 'pnpm', '@anthropic-ai/claude-code@latest', {
129
+ command: 'add',
130
+ extraArgs: ['--ignore-scripts=false', '--allow-build=@anthropic-ai/claude-code'],
131
+ }),
132
+ // The native installer has no directory argument. npm/pnpm support a prefix.
133
+ scriptMethod('script-bash', 'curl | bash', {
134
+ shell: 'bash', scriptUrl: 'https://claude.ai/install.sh',
135
+ scriptFallbackUrls: ['https://downloads.claude.ai/claude-code-releases/bootstrap.sh'],
136
+ platforms: ['linux', 'darwin'],
137
+ scriptBinaryNames: ['claude'],
138
+ verify: Object.freeze({ mustInclude: ['downloads.claude.ai/claude-code-releases', 'manifest.json'] }),
139
+ }),
140
+ scriptMethod('script-powershell', 'irm | iex', {
141
+ shell: 'powershell', scriptUrl: 'https://claude.ai/install.ps1',
142
+ scriptFallbackUrls: ['https://downloads.claude.ai/claude-code-releases/bootstrap.ps1'],
143
+ platforms: ['win32'],
144
+ scriptBinaryNames: ['claude.exe'],
145
+ verify: Object.freeze({ mustInclude: ['downloads.claude.ai/claude-code-releases', 'manifest.json'] }),
146
+ }),
95
147
  ]),
96
148
  }),
97
149
  Object.freeze({
@@ -106,9 +158,30 @@ export const OFFICIAL_TOOLS = Object.freeze([
106
158
  probeExecutables: ['codex'],
107
159
  probeNote: 'Codex 版本横幅由适配层宽匹配;安装时取 npm 最新版。',
108
160
  providerHints: ['openai', 'gpt', 'codex'],
161
+ scriptBinaryNames: Object.freeze(['codex', 'codex.exe']),
162
+ defaultScriptInstallDir: '.local/bin',
109
163
  installMethods: Object.freeze([
110
164
  packageManagerMethod('npm', 'npm', 'npm', '@openai/codex@latest'),
111
165
  packageManagerMethod('pnpm', 'pnpm', 'pnpm', '@openai/codex@latest'),
166
+ scriptMethod('script-sh', 'curl | sh', {
167
+ shell: 'sh', scriptUrl: 'https://chatgpt.com/codex/install.sh',
168
+ platforms: ['linux', 'darwin'], supportsInstallDir: true,
169
+ installDirEnv: 'CODEX_INSTALL_DIR', env: ['CODEX_INSTALL_DIR'],
170
+ scriptBinaryNames: ['codex'],
171
+ verify: Object.freeze({ mustInclude: ['releases.openai.com/codex', 'CODEX_INSTALL_DIR'] }),
172
+ }),
173
+ scriptMethod('script-powershell', 'irm | iex', {
174
+ shell: 'powershell', scriptUrl: 'https://chatgpt.com/codex/install.ps1',
175
+ platforms: ['win32'], supportsInstallDir: true,
176
+ installDirEnv: 'CODEX_INSTALL_DIR', env: ['CODEX_INSTALL_DIR'],
177
+ defaultScriptInstallDirEnv: 'LOCALAPPDATA',
178
+ defaultScriptInstallDir: 'Programs/OpenAI/Codex/bin',
179
+ installDirSubdir: 'codex/bin',
180
+ uninstallUnsupportedReason: 'Codex 官方 Windows 脚本使用目录联接和版本化资源;请按官方卸载说明移除,插件不会删除联接目标。',
181
+ // The Windows bin directory is a junction to the versioned payload.
182
+ scriptBinaryNames: ['codex.exe'],
183
+ verify: Object.freeze({ mustInclude: ['releases.openai.com/codex', 'CODEX_INSTALL_DIR'] }),
184
+ }),
112
185
  ]),
113
186
  }),
114
187
  Object.freeze({
@@ -122,9 +195,33 @@ export const OFFICIAL_TOOLS = Object.freeze([
122
195
  uninstallArgs: ['uninstall', '-g', '@minimax-ai/code'],
123
196
  probeExecutables: ['mcode'],
124
197
  providerHints: ['minimax'],
198
+ defaultMethodsByPlatform: Object.freeze({ win32: 'script-powershell' }),
199
+ scriptBinaryNames: Object.freeze(['mcode', 'mcode-tools']),
200
+ defaultScriptInstallDir: '.minimax-code/bin',
125
201
  installMethods: Object.freeze([
126
- packageManagerMethod('npm', 'npm', 'npm', '@minimax-ai/code@latest'),
127
- packageManagerMethod('pnpm', 'pnpm', 'pnpm', '@minimax-ai/code@latest'),
202
+ packageManagerMethod('npm', 'npm', 'npm', '@minimax-ai/code@latest', {
203
+ extraArgs: ['--ignore-scripts=false', '--include=optional', '--allow-scripts=@minimax-ai/code,better-sqlite3'],
204
+ }),
205
+ packageManagerMethod('pnpm', 'pnpm', 'pnpm', '@minimax-ai/code@latest', {
206
+ command: 'add',
207
+ extraArgs: ['--ignore-scripts=false', '--allow-build=@minimax-ai/code', '--allow-build=better-sqlite3'],
208
+ }),
209
+ scriptMethod('script-bash', 'curl | bash', {
210
+ shell: 'bash', scriptUrl: 'https://filecdn.minimax.chat/public/install.sh',
211
+ platforms: ['linux', 'darwin'], supportsInstallDir: true,
212
+ installDirEnv: 'MCODE_INSTALL_DIR', installDirSuffix: 'bin',
213
+ registryEnv: 'MCODE_NPM_REGISTRY', env: ['MCODE_INSTALL_DIR', 'MCODE_NPM_REGISTRY'],
214
+ verify: Object.freeze({ mustInclude: ['MiniMax Code CLI', '@minimax-ai/code'] }),
215
+ }),
216
+ scriptMethod('script-powershell', 'irm | iex', {
217
+ shell: 'powershell', scriptUrl: 'https://filecdn.minimax.chat/public/install.ps1',
218
+ platforms: ['win32'], supportsInstallDir: true,
219
+ installDirEnv: 'MCODE_INSTALL_DIR',
220
+ registryEnv: 'MCODE_NPM_REGISTRY', env: ['MCODE_INSTALL_DIR', 'MCODE_NPM_REGISTRY'],
221
+ defaultScriptInstallDir: '.minimax-code',
222
+ scriptBinaryNames: ['mcode.cmd', 'mcode.ps1', 'mcode-tools.cmd', 'mcode-tools.ps1'],
223
+ verify: Object.freeze({ mustInclude: ['MiniMax Code CLI', '@minimax-ai/code'] }),
224
+ }),
128
225
  ]),
129
226
  }),
130
227
  Object.freeze({
@@ -138,9 +235,24 @@ export const OFFICIAL_TOOLS = Object.freeze([
138
235
  uninstallArgs: ['uninstall', '-g', '@mimo-ai/cli'],
139
236
  probeExecutables: ['mimo'],
140
237
  providerHints: ['mimo', 'xiaomi'],
238
+ scriptBinaryNames: Object.freeze(['mimo', 'mimo.exe']),
239
+ defaultScriptInstallDir: '.mimocode/bin',
141
240
  installMethods: Object.freeze([
142
241
  packageManagerMethod('npm', 'npm', 'npm', '@mimo-ai/cli@latest'),
143
242
  packageManagerMethod('pnpm', 'pnpm', 'pnpm', '@mimo-ai/cli@latest'),
243
+ scriptMethod('script-bash', 'curl | bash', {
244
+ shell: 'bash', scriptUrl: 'https://mimo.xiaomi.com/install',
245
+ platforms: ['linux', 'darwin'],
246
+ scriptBinaryNames: ['mimo'],
247
+ verify: Object.freeze({ mustInclude: ['mimo.xiaomi.com', '.mimocode'] }),
248
+ }),
249
+ scriptMethod('script-powershell', 'irm | iex', {
250
+ shell: 'powershell', scriptUrl: 'https://mimo.xiaomi.com/install.ps1',
251
+ platforms: ['win32'], supportsInstallDir: true,
252
+ installDirEnv: 'MIMOCODE_INSTALL_DIR', env: ['MIMOCODE_INSTALL_DIR'],
253
+ scriptBinaryNames: ['mimo.exe'],
254
+ verify: Object.freeze({ mustInclude: ['mimo.xiaomi.com', '.mimocode'] }),
255
+ }),
144
256
  ]),
145
257
  }),
146
258
  Object.freeze({
@@ -154,9 +266,26 @@ export const OFFICIAL_TOOLS = Object.freeze([
154
266
  uninstallArgs: ['uninstall', '-g', '@xai-official/grok'],
155
267
  probeExecutables: ['grok'],
156
268
  providerHints: ['xai', 'grok'],
269
+ scriptBinaryNames: Object.freeze(['grok', 'agent', 'grok.exe', 'agent.exe', 'grove.exe', 'grove-fsmonitor.exe', 'grove-credential.exe']),
270
+ defaultScriptInstallDir: '.grok/bin',
271
+ pathProfileMarkers: Object.freeze(['# >>> grok installer >>>', '# <<< grok installer <<<']),
157
272
  installMethods: Object.freeze([
158
273
  packageManagerMethod('npm', 'npm', 'npm', '@xai-official/grok@latest'),
159
274
  packageManagerMethod('pnpm', 'pnpm', 'pnpm', '@xai-official/grok@latest'),
275
+ scriptMethod('script-bash', 'curl | bash', {
276
+ shell: 'bash', scriptUrl: 'https://x.ai/cli/install.sh',
277
+ platforms: ['linux', 'darwin'], supportsInstallDir: true,
278
+ installDirEnv: 'GROK_BIN_DIR', env: ['GROK_BIN_DIR'],
279
+ scriptBinaryNames: ['grok', 'agent'],
280
+ verify: Object.freeze({ mustInclude: ['Grok CLI installer', 'x.ai/cli'] }),
281
+ }),
282
+ scriptMethod('script-powershell', 'irm | iex', {
283
+ shell: 'powershell', scriptUrl: 'https://x.ai/cli/install.ps1',
284
+ platforms: ['win32'], supportsInstallDir: true,
285
+ installDirEnv: 'GROK_BIN_DIR', env: ['GROK_BIN_DIR'],
286
+ scriptBinaryNames: ['grok.exe', 'agent.exe', 'grove.exe', 'grove-fsmonitor.exe', 'grove-credential.exe'],
287
+ verify: Object.freeze({ mustInclude: ['Grok CLI installer', 'x.ai/cli'] }),
288
+ }),
160
289
  ]),
161
290
  }),
162
291
  Object.freeze({
@@ -294,7 +423,10 @@ export function installMethodsFor(tool) {
294
423
  export function installMethodFor(tool, methodId) {
295
424
  const wanted = String(methodId ?? '').trim()
296
425
  if (!wanted) return null
297
- return installMethodsFor(tool).find(method => method.id === wanted) ?? null
426
+ // 0.17.1 saved Codex's POSIX installer as script-bash. The vendor uses sh;
427
+ // preserve that saved choice while returning the current declared method.
428
+ const canonical = tool?.id === 'codex' && wanted === 'script-bash' ? 'script-sh' : wanted
429
+ return installMethodsFor(tool).find(method => method.id === canonical) ?? null
298
430
  }
299
431
 
300
432
  /** The tool's default method, kept identical to `manager` / `installArgs`. */
@@ -310,7 +442,7 @@ export function installMethodBlockReason(method, platform = 'linux') {
310
442
 
311
443
  /**
312
444
  * A method able to place the tool in the user's chosen directory. npm and pnpm
313
- * take --prefix; the opencode script hardcodes its own path and cannot.
445
+ * bind their global directories; vendor scripts declare an argument or environment binding.
314
446
  */
315
447
  export function methodHonoursInstallDir(method) {
316
448
  return method?.supportsInstallDir === true
@@ -329,8 +461,8 @@ export function installCommandLineFor(tool, method) {
329
461
  if (!tool || tool.unsupported) return null
330
462
  if (!method) return null
331
463
  if (method.kind === 'script') {
332
- const piped = method.shell === 'powershell' ? `irm ${method.scriptUrl} | iex` : `curl -fsSL ${method.scriptUrl} | bash`
333
- return method.installArgs.length ? `${piped} ${method.installArgs[0]} <安装目录>` : piped
464
+ const piped = method.shell === 'powershell' ? `irm ${method.scriptUrl} | iex` : `curl -fsSL ${method.scriptUrl} | ${method.shell}`
465
+ return piped
334
466
  }
335
467
  return `${method.manager} ${method.installArgs.join(' ')}`
336
468
  }
@@ -339,6 +471,7 @@ export function installCommandLineFor(tool, method) {
339
471
  export function uninstallCommandLineFor(tool, method) {
340
472
  if (!tool || tool.unsupported || !method) return null
341
473
  if (tool.manager === 'signed-windows-installer') return null
474
+ if (method.uninstallUnsupportedReason) return method.uninstallUnsupportedReason
342
475
  if (method.kind === 'script') return '删除官方安装的可执行文件(保留配置与登录信息)'
343
476
  return `${method.manager} ${method.uninstallArgs.join(' ')}`
344
477
  }