mohdel 0.125.0 → 1.0.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.
Files changed (43) hide show
  1. package/README.md +154 -29
  2. package/config/curated.schema.json +32 -10
  3. package/js/client/gate-binary.js +5 -0
  4. package/js/client/index.js +1 -0
  5. package/js/core/envelope.js +5 -1
  6. package/js/factory/bridge.js +2 -2
  7. package/js/session/adapters/_chat_completions.js +3 -0
  8. package/js/session/adapters/_output_cap.js +30 -0
  9. package/js/session/adapters/_registry.js +44 -0
  10. package/js/session/adapters/anthropic.js +8 -5
  11. package/js/session/adapters/gemini.js +4 -0
  12. package/js/session/adapters/openai.js +2 -1
  13. package/js/session/run.js +14 -4
  14. package/js/session/run_image.js +12 -3
  15. package/package.json +49 -19
  16. package/src/cli/aliases.js +20 -0
  17. package/src/cli/ask.js +58 -12
  18. package/src/cli/backup.js +2 -1
  19. package/src/cli/check.js +15 -86
  20. package/src/cli/complete.js +130 -0
  21. package/src/cli/default.js +34 -13
  22. package/src/cli/doctor.js +33 -14
  23. package/src/cli/entry.js +173 -0
  24. package/src/cli/index.js +77 -66
  25. package/src/cli/instructions.js +349 -0
  26. package/src/cli/local.js +14 -0
  27. package/src/cli/model.js +184 -37
  28. package/src/cli/onboard.js +186 -121
  29. package/src/cli/rank.js +2 -1
  30. package/src/cli/ratelimit.js +3 -3
  31. package/src/cli/tag.js +2 -0
  32. package/src/lib/assistants.js +93 -0
  33. package/src/lib/catalog/openrouter.js +6 -1
  34. package/src/lib/catalog-review.js +195 -0
  35. package/src/lib/common.js +14 -1
  36. package/src/lib/creators.js +35 -0
  37. package/src/lib/index.js +17 -3
  38. package/src/lib/local-conventions.js +120 -0
  39. package/src/lib/provider-info.js +98 -0
  40. package/src/lib/providers.js +69 -14
  41. package/src/lib/schema.js +15 -3
  42. package/src/lib/select.js +125 -67
  43. package/js/session/adapters/image/index.js +0 -40
package/src/cli/doctor.js CHANGED
@@ -3,7 +3,7 @@ import { label, meta, ok, warn, err, inactive } from './colors.js'
3
3
  import providers from '../lib/providers.js'
4
4
  import { validate, isValidTag } from '../lib/schema.js'
5
5
  import {
6
- CONFIG_DIR, CURATED_PATH, CONFIG_PATH, ENV_PATH,
6
+ CONFIG_DIR, CURATED_PATH, CONFIG_PATH, ENV_PATH, tildePath,
7
7
  getCuratedModels, getConfig, loadDefaultEnv, getAPIKey, catalogEntries
8
8
  } from '../lib/common.js'
9
9
 
@@ -11,11 +11,15 @@ const row = (status, name, detail = '') =>
11
11
  ` ${status} ${name.padEnd(20)} ${meta(detail)}`
12
12
 
13
13
  export async function runDoctor (args) {
14
+ const all = args.includes('--all')
14
15
  if (args.includes('-h') || args.includes('--help')) {
15
16
  console.log(`mohdel doctor — check that your install is wired up
16
17
 
17
18
  Usage:
18
- mo doctor [--json]
19
+ mo doctor [--all] [--json]
20
+
21
+ Options:
22
+ --all List every provider's API key variable, set or not
19
23
 
20
24
  What it checks:
21
25
  - Config directory and environment file exist
@@ -45,9 +49,10 @@ Exit code:
45
49
 
46
50
  // 1. Config dir + env file
47
51
  report.configDir.ok = existsSync(CONFIG_DIR)
52
+ report.assistant = (await getConfig()).assistant || null
48
53
  report.envFile.ok = existsSync(ENV_PATH)
49
54
  if (!report.configDir.ok) report.warnings.push('config directory does not exist (will be created on first save)')
50
- if (!report.envFile.ok) report.warnings.push(`no ${ENV_PATH} — set API keys there or via shell env`)
55
+ if (!report.envFile.ok) report.warnings.push(`no ${tildePath(ENV_PATH)} — set API keys there or via shell env`)
51
56
 
52
57
  // 2. API keys per provider
53
58
  for (const [name, def] of Object.entries(providers)) {
@@ -70,6 +75,9 @@ Exit code:
70
75
  const entries = catalogEntries(curated)
71
76
  report.curatedFile.active = entries.filter(([, s]) => !s.deprecated).length
72
77
  report.curatedFile.deprecated = entries.length - report.curatedFile.active
78
+ if (report.curatedFile.active === 0) {
79
+ report.warnings.push('catalog is empty — "mo curate <provider>" adds a provider\'s models, then "mo model instructions <provider>" fills in the prices')
80
+ }
73
81
 
74
82
  // Schema validation (same logic as 'mo check', condensed)
75
83
  const knownProviders = new Set(Object.keys(providers))
@@ -126,13 +134,15 @@ Exit code:
126
134
  }
127
135
 
128
136
  // Pretty output
129
- console.log(label('Mohdel doctor\n'))
137
+ console.log(label('mohdel doctor\n'))
130
138
 
131
139
  console.log(label('Configuration'))
132
- console.log(row(report.configDir.ok ? ok('✓') : warn('!'), 'Config dir', report.configDir.path))
133
- console.log(row(report.envFile.ok ? ok('✓') : warn('!'), 'Env file', report.envFile.ok ? report.envFile.path : `${report.envFile.path} (missing)`))
140
+ console.log(row(report.configDir.ok ? ok('✓') : warn('!'), 'Config dir', tildePath(report.configDir.path)))
141
+ if (report.assistant) console.log(row(ok('✓'), 'Coding agent', report.assistant))
142
+ console.log(row(report.envFile.ok ? ok('✓') : warn('!'), 'Env file', report.envFile.ok ? tildePath(report.envFile.path) : `${tildePath(report.envFile.path)} (missing)`))
134
143
  if (report.curatedFile.ok) {
135
- console.log(row(ok('✓'), 'curated.json', `${report.curatedFile.active} active, ${report.curatedFile.deprecated} deprecated`))
144
+ const mark = report.curatedFile.active === 0 ? warn('!') : ok('✓')
145
+ console.log(row(mark, 'curated.json', `${report.curatedFile.active} active, ${report.curatedFile.deprecated} deprecated`))
136
146
  } else {
137
147
  console.log(row(err('✗'), 'curated.json', 'failed to load'))
138
148
  }
@@ -142,13 +152,22 @@ Exit code:
142
152
  for (const k of report.keys.configured) {
143
153
  console.log(row(ok('✓'), k.provider, k.envVar))
144
154
  }
145
- for (const k of report.keys.missing) {
146
- console.log(row(inactive('○'), k.provider, `${k.envVar} (unset)`))
155
+ // A row per unset provider is a dozen lines of nothing on a fresh install,
156
+ // but the variable names are what you came for when a key isn't picked up.
157
+ if (all) {
158
+ for (const k of report.keys.missing) {
159
+ console.log(row(inactive('○'), k.provider, `${k.envVar} (unset)`))
160
+ }
161
+ } else if (report.keys.missing.length) {
162
+ console.log(row(inactive('○'), `${report.keys.missing.length} unset`,
163
+ meta('"mo providers" lists them, "mo doctor --all" their variables')))
147
164
  }
148
165
 
149
166
  console.log()
150
167
  console.log(label('Catalog validation'))
151
- if (report.schema.errors.length) {
168
+ if (report.curatedFile.ok && report.curatedFile.active === 0 && report.curatedFile.deprecated === 0) {
169
+ console.log(` ${inactive('○')} nothing to validate`)
170
+ } else if (report.schema.errors.length) {
152
171
  console.log(` ${err('✗')} ${report.schema.errors.length} error(s) ${meta('— run "mo check" for details')}`)
153
172
  } else {
154
173
  console.log(` ${ok('✓')} no errors`)
@@ -171,11 +190,11 @@ Exit code:
171
190
  if (report.errors.length) {
172
191
  console.log(`${err('✗')} ${report.errors.length} error(s):`)
173
192
  for (const e of report.errors) console.log(` ${err('✗')} ${e}`)
174
- process.exit(1)
175
- } else if (report.warnings.length) {
193
+ }
194
+ if (report.warnings.length) {
176
195
  console.log(`${warn('!')} ${report.warnings.length} warning(s) — install is usable but not fully configured`)
177
196
  for (const w of report.warnings) console.log(` ${warn('!')} ${w}`)
178
- } else {
179
- console.log(`${ok('✓')} ready`)
180
197
  }
198
+ if (report.errors.length) process.exit(1)
199
+ if (!report.warnings.length) console.log(`${ok('✓')} ready`)
181
200
  }
@@ -0,0 +1,173 @@
1
+ import { readFile, rm } from 'node:fs/promises'
2
+ import { CURATED_PATH, getCuratedModels, saveCuratedModels, tildePath } from '../lib/common.js'
3
+ import { parseCandidates, reviewCandidates } from '../lib/catalog-review.js'
4
+ import { localConventionsOrExit } from './local.js'
5
+ import { id, label, meta, err, warn, ok } from './colors.js'
6
+
7
+ const readStdin = async () => {
8
+ const chunks = []
9
+ for await (const chunk of process.stdin) chunks.push(chunk)
10
+ return Buffer.concat(chunks).toString('utf8')
11
+ }
12
+
13
+ const readCandidateFile = async (path) => {
14
+ if (path === '-') return readStdin()
15
+ return readFile(path, 'utf8')
16
+ }
17
+
18
+ const show = (value) => JSON.stringify(value)
19
+
20
+ const renderChange = ({ field, from, to }) => {
21
+ const name = field.padEnd(22)
22
+ if (from === undefined) return ` ${ok('+')} ${name} ${show(to)}`
23
+ if (to === undefined) return ` ${err('-')} ${name} ${show(from)} ${meta('→ (removed)')}`
24
+ return ` ${warn('~')} ${name} ${show(from)} ${meta('→')} ${show(to)}`
25
+ }
26
+
27
+ export const printReview = (reviews, ignored) => {
28
+ for (const key of ignored) {
29
+ console.log(meta(`skipping meta key ${key}`))
30
+ }
31
+ for (const review of reviews) {
32
+ console.log(`\n${id(review.key)} ${label(review.status)}`)
33
+ for (const change of review.changes) console.log(renderChange(change))
34
+ for (const e of review.errors) console.log(` ${err('✗')} ${e}`)
35
+ for (const w of review.warnings) console.log(` ${warn('!')} ${w}`)
36
+ }
37
+ }
38
+
39
+ export const summarize = (reviews) => ({
40
+ candidates: reviews.length,
41
+ new: reviews.filter(r => r.status === 'new').length,
42
+ changed: reviews.filter(r => r.status === 'changed').length,
43
+ unchanged: reviews.filter(r => r.status === 'unchanged').length,
44
+ errors: reviews.reduce((n, r) => n + r.errors.length, 0),
45
+ warnings: reviews.reduce((n, r) => n + r.warnings.length, 0)
46
+ })
47
+
48
+ const printSummary = (counts) => {
49
+ const parts = [`${counts.new} new`, `${counts.changed} changed`, `${counts.unchanged} unchanged`]
50
+ console.log(`\n${label(`${counts.candidates} candidate(s):`)} ${parts.join(', ')} ${meta('│')} ` +
51
+ `${counts.errors ? err(`${counts.errors} error(s)`) : ok('0 errors')}, ${counts.warnings} warning(s)`)
52
+ }
53
+
54
+ const loadReview = async (path) => {
55
+ const { entries, ignored } = parseCandidates(await readCandidateFile(path))
56
+ const curated = await getCuratedModels()
57
+ const local = await localConventionsOrExit()
58
+ return { curated, entries, ignored, reviews: reviewCandidates(curated, entries, { local }) }
59
+ }
60
+
61
+ export async function runCheckEntry (args) {
62
+ const path = args[args.indexOf('--entry') + 1]
63
+ if (!path) {
64
+ console.error('Usage: mo model check --entry <file|->')
65
+ process.exit(1)
66
+ }
67
+ const json = args.includes('--json')
68
+
69
+ let review
70
+ try {
71
+ review = await loadReview(path)
72
+ } catch (e) {
73
+ if (json) console.log(JSON.stringify({ error: e.message }, null, 2))
74
+ else console.error(err(e.message))
75
+ process.exit(1)
76
+ }
77
+
78
+ const counts = summarize(review.reviews)
79
+ if (json) {
80
+ console.log(JSON.stringify({ counts, ignored: review.ignored, candidates: review.reviews }, null, 2))
81
+ } else {
82
+ printReview(review.reviews, review.ignored)
83
+ printSummary(counts)
84
+ if (!counts.errors) {
85
+ console.log(`${meta('Next:')} mo model apply ${path === '-' ? '<file>' : path}`)
86
+ }
87
+ }
88
+ if (counts.errors) process.exit(1)
89
+ }
90
+
91
+ export async function runApply (args) {
92
+ if (args.includes('-h') || args.includes('--help')) {
93
+ console.log(`mohdel model apply — write reviewed catalog entries
94
+
95
+ Usage:
96
+ model apply <file|-> [--yes] [--rm]
97
+
98
+ Reads entries in curated.json shape, validates them, prints the diff
99
+ against ${tildePath(CURATED_PATH)}, and writes after confirmation. Nothing is
100
+ written when validation reports an error.
101
+
102
+ The candidate file is left alone unless you say otherwise — at a terminal
103
+ it asks, and --rm removes it without asking. Undo uses the catalog's own
104
+ backups, not the candidate.
105
+
106
+ Options:
107
+ --yes Skip the confirmation prompt
108
+ --rm Delete the candidate file once it has been applied
109
+
110
+ Write an entry with your coding agent: mo model instructions <provider>`)
111
+ process.exit(0)
112
+ }
113
+
114
+ const path = args.find(a => !a.startsWith('--'))
115
+ if (!path) {
116
+ console.error('Usage: mo model apply <file|-> [--yes] [--rm]')
117
+ process.exit(1)
118
+ }
119
+
120
+ let review
121
+ try {
122
+ review = await loadReview(path)
123
+ } catch (e) {
124
+ console.error(err(e.message))
125
+ process.exit(1)
126
+ }
127
+
128
+ const counts = summarize(review.reviews)
129
+ printReview(review.reviews, review.ignored)
130
+ printSummary(counts)
131
+
132
+ if (counts.errors) {
133
+ console.error(`\n${err('Not written')} — fix the errors above and run again.`)
134
+ process.exit(1)
135
+ }
136
+ const nothingToDo = !counts.new && !counts.changed
137
+ if (nothingToDo) console.log(`\n${ok('Nothing to write')} — the catalog already matches.`)
138
+
139
+ if (!nothingToDo && !args.includes('--yes')) {
140
+ if (!process.stdout.isTTY || path === '-') {
141
+ console.error(`\n${err('Not written')} — no terminal to confirm on. Re-run in a terminal, or pass --yes.`)
142
+ process.exit(1)
143
+ }
144
+ const { confirm, isCancel } = await import('@clack/prompts')
145
+ const go = await confirm({ message: `Write ${counts.new + counts.changed} entry(ies) to ${tildePath(CURATED_PATH)}?` })
146
+ if (isCancel(go) || !go) {
147
+ console.log(meta('Not written.'))
148
+ return
149
+ }
150
+ }
151
+
152
+ if (!nothingToDo) {
153
+ await saveCuratedModels({ ...review.curated, ...review.entries })
154
+ console.log(`${ok('✓')} ${counts.new + counts.changed} entry(ies) written to ${tildePath(CURATED_PATH)}`)
155
+ console.log(`${meta('Undo:')} mo model backup diff prev ${meta('│')} mo model backup restore prev`)
156
+ }
157
+
158
+ // The candidate was written by the agent, not by mohdel, so it is never
159
+ // removed unasked. It has served its purpose though, and the catalog's own
160
+ // backups are what an undo uses — not this file.
161
+ if (path === '-') return
162
+ if (args.includes('--rm')) {
163
+ await rm(path, { force: true })
164
+ console.log(`${ok('✓')} removed ${path}`)
165
+ return
166
+ }
167
+ if (!process.stdout.isTTY) return
168
+ const { confirm, isCancel } = await import('@clack/prompts')
169
+ const drop = await confirm({ message: `Delete ${path}?`, initialValue: false })
170
+ if (isCancel(drop) || !drop) return
171
+ await rm(path, { force: true })
172
+ console.log(`${ok('✓')} removed ${path}`)
173
+ }
package/src/cli/index.js CHANGED
@@ -9,6 +9,10 @@
9
9
  * Aliases: ls → model list, rl → ratelimit
10
10
  */
11
11
 
12
+ import { detectAssistants, launchLines } from '../lib/assistants.js'
13
+ import { getConfig } from '../lib/common.js'
14
+ import { ALIASES } from './aliases.js'
15
+
12
16
  const [command, ...args] = process.argv.slice(2)
13
17
 
14
18
  if (!command) {
@@ -17,38 +21,65 @@ if (!command) {
17
21
  process.exit(0)
18
22
  }
19
23
 
24
+ // Before anything else: a tab press must not pay for the factory import.
25
+ if (command === '__complete') {
26
+ const { runComplete } = await import('./complete.js')
27
+ await runComplete(args)
28
+ process.exit(0)
29
+ }
30
+
31
+ if (command === 'completion') {
32
+ const { runCompletionScript } = await import('./complete.js')
33
+ runCompletionScript(args)
34
+ process.exit(0)
35
+ }
36
+
20
37
  if (command === '-h' || command === '--help') {
21
- console.log(`mohdel — model catalog management
38
+ const assistant = (await getConfig()).assistant || null
39
+ const { default: PROVIDER_INFO } = await import('../lib/provider-info.js')
40
+ const { default: providerDefs } = await import('../lib/providers.js')
41
+ const keyRows = Object.keys(PROVIDER_INFO)
42
+ .map(name => [providerDefs[name].apiKeyEnv, `${PROVIDER_INFO[name].label} API key`])
43
+ .concat([['MOHDEL_LOCAL_API_SK', 'Bearer token for a local server, if it wants one']])
44
+ const keyWidth = Math.max(...keyRows.map(([k]) => k.length))
45
+ const keys = keyRows.map(([k, d]) => ` ${k.padEnd(keyWidth + 2)}${d}`).join('\n')
46
+ console.log(`mohdel — self-hosted LLM gateway and SDK for Node
47
+
48
+ Run a model, see what the call cost, and curate the catalog those prices
49
+ come from. Your keys, your infra, no SaaS in the path.
22
50
 
23
51
  Commands:
24
- model list [--sort price|context|name] List all curated models
25
- model search <term> Filter models by name/label
26
- model stats Catalog summary
27
- model show <model> Show model details
52
+ model list [--sort price|context|name] List all curated models (mo ls, mo models)
53
+ model search <term> Filter models by name/label (mo search)
54
+ model stats Catalog summary (mo stats)
55
+ model show <model> Show model details (mo show)
28
56
  model get <model> <key> Get a field value
29
57
  model set <model> <key> <value> Set a field
30
58
  model rm <model> <key> Remove a field
31
59
  model add <provider>/<model-id> Add a model manually
32
- model check [--local] Validate catalog
33
- model rank [--use-case <name>] Rank models by benchmarks
34
- model bench <model> Benchmark with live inference
35
- model curate [provider] Add upstream models to catalog
36
-
37
- provider list List all providers
38
- provider list <provider> List models from a provider
39
- provider setup <provider> Configure API key (interactive)
60
+ model instructions [provider] Brief for your coding agent (mo instructions)
61
+ model check [--entry <file|->] Validate catalog, or candidate entries (mo check)
62
+ model apply <file|-> Write reviewed entries to the catalog (mo apply)
63
+ model rank [--use-case <name>] Rank models by benchmarks (mo rank)
64
+ model bench <model> Benchmark with live inference (mo bench)
65
+ model curate [provider] Add upstream models to catalog (mo curate)
66
+
67
+ provider list List all providers (mo providers)
68
+ provider list <provider> List curated models for a provider
69
+ provider models <provider> List models the key can reach upstream
70
+ provider setup <provider> Configure API key (interactive) (mo setup)
40
71
  provider rm <provider> Remove API key
41
72
 
42
- creator list List all creators
73
+ creator list List all creators (mo creators)
43
74
  creator list <creator> List models by a creator
44
75
 
45
- tag list List all unique tags
76
+ tag list List all unique tags (mo tags)
46
77
  tag list <model> Show tags on a model
47
78
  tag show <tag> List models with a tag
48
79
  tag add <model> <tag> Add a tag
49
80
  tag rm <model> <tag> Remove a tag
50
81
 
51
- ratelimit show <model|provider> Show effective limits
82
+ ratelimit show <model|provider> Show effective limits (mo rl show)
52
83
  ratelimit set <model> [rpm] [tpm] Set model-level limits
53
84
  ratelimit rm <model> Remove model-level limits
54
85
  ratelimit provider set <p> [rpm] [tpm] Set provider-level limits
@@ -57,24 +88,30 @@ Commands:
57
88
  ask <provider/model> [prompt] One-shot inference (pipeable)
58
89
  transcribe <provider/model> <file> Speech → text from an audio file
59
90
 
60
- default Set default model (interactive)
91
+ default [model] Set the model "mo ask" uses by default
61
92
  doctor Check that your install is wired up
93
+ completion bash Shell completion — source <(mo completion bash)
94
+
95
+ Catalog work with a coding agent:
96
+ Prices, context limits and cache rates are in no provider API — they live on
97
+ docs pages. Put the brief in front of the coding agent you already use:
62
98
 
63
- Aliases:
64
- models model list
65
- providers provider list
66
- creators creator list
67
- tags tag list
68
- ls model list
69
- show <model> model show <model>
70
- search <term> model search <term>
71
- stats model stats
72
- check model check
73
- setup <provider> provider setup <provider>
74
- rank model rank
75
- bench <model> model bench <model>
76
- curate [provider] model curate [provider]
77
- rl ratelimit
99
+ mo model instructions openai > mohdel-brief.md
100
+
101
+ then start it on <prompt>:
102
+
103
+ read mohdel-brief.md, then add gpt-5.6 to my mohdel catalog
104
+
105
+ ${launchLines(detectAssistants(), assistant).join('\n')}
106
+
107
+ The agent needs to be able to fetch a web page — that is where the prices
108
+ are. It drafts mohdel-candidate.json and checks it; you apply it:
109
+
110
+ mo model check --entry mohdel-candidate.json
111
+ mo model apply mohdel-candidate.json ← prints the diff first
112
+
113
+ Aliases appear in brackets above. "mo rl" stands in for "mo ratelimit" on
114
+ every subcommand, not only its list form.
78
115
 
79
116
  Global flags:
80
117
  --json [fields] Output as JSON (omit fields to list available)
@@ -83,51 +120,25 @@ Environment:
83
120
  API keys are loaded from ~/.config/mohdel/environment (KEY=value format).
84
121
  Run "mo" with no arguments to configure interactively.
85
122
 
86
- ANTHROPIC_API_SK Anthropic API key
87
- OPENAI_API_SK OpenAI API key
88
- GEMINI_API_SK Google Gemini API key
89
- GROQ_API_SK Groq API key
90
- CEREBRAS_API_SK Cerebras API key
91
- XAI_API_SK xAI API key
92
- MISTRAL_API_SK Mistral API key
93
- DEEPSEEK_API_SK DeepSeek API key
94
- FIREWORKS_API_SK Fireworks API key
95
- OPENROUTER_API_SK OpenRouter API key
96
- NOVITA_API_SK Novita API key
123
+ ${keys}
97
124
 
98
125
  Configuration:
99
- ~/.config/mohdel/environment API keys (loaded automatically)
100
- ~/.config/mohdel/curated.json Model catalog
101
- ~/.config/mohdel/providers.json Provider-level rate limits
102
- ~/.config/mohdel/default.json Default model selection`)
126
+ ~/.config/mohdel/environment API keys (loaded automatically)
127
+ ~/.config/mohdel/curated.json Model catalog
128
+ ~/.config/mohdel/catalog.local.json This installation's own fields and tags
129
+ ~/.config/mohdel/providers.json Provider-level rate limits
130
+ ~/.config/mohdel/excluded.json Models to hide from list and curate
131
+ ~/.config/mohdel/default.json Default model, and your coding agent`)
103
132
  process.exit(0)
104
133
  }
105
134
 
106
- // Alias resolution: short commands → noun + verb
107
- const ALIASES = {
108
- models: { noun: 'model', inject: ['list'] },
109
- providers: { noun: 'provider', inject: ['list'] },
110
- creators: { noun: 'creator', inject: ['list'] },
111
- tags: { noun: 'tag', inject: ['list'] },
112
- ls: { noun: 'model', inject: ['list'] },
113
- show: { noun: 'model', inject: ['show'] },
114
- search: { noun: 'model', inject: ['search'] },
115
- stats: { noun: 'model', inject: ['stats'] },
116
- check: { noun: 'model', inject: ['check'] },
117
- setup: { noun: 'provider', inject: ['setup'] },
118
- rank: { noun: 'model', inject: ['rank'] },
119
- bench: { noun: 'model', inject: ['bench'] },
120
- curate: { noun: 'model', inject: ['curate'] },
121
- rl: { noun: 'ratelimit', inject: [] }
122
- }
123
-
124
135
  const alias = ALIASES[command]
125
136
  const resolved = alias ? alias.noun : command
126
137
  const resolvedArgs = alias ? [...alias.inject, ...args] : args
127
138
 
128
139
  if (resolved === 'default') {
129
140
  const { runDefault } = await import('./default.js')
130
- await runDefault()
141
+ await runDefault(resolvedArgs)
131
142
  } else if (resolved === 'doctor') {
132
143
  const { runDoctor } = await import('./doctor.js')
133
144
  await runDoctor(resolvedArgs)