micro-models-agent 0.62.0 → 0.63.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/CHANGELOG.md CHANGED
@@ -4,6 +4,14 @@ All notable changes to Micro Models Agent (MMA) will be documented in this file.
4
4
 
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/), and this project adheres to [Semantic Versioning](https://semver.org/).
6
6
 
7
+ ## [0.63.0] - 2026-09-17
8
+
9
+ ### Added
10
+ - **REPL `/provider add`**: add a provider without leaving the agent. Mirrors `mma provider add` — `/provider add <name> [--url <url>] [--key <key>] [--priority <n>] [--context-window <n>] [--rpm <n>] [--parallel <n>]`. Seeds the legacy provider into `provider.entries` on first use, saves the config and hot-reloads the agent; switch with `/provider use <name>`. `/provider` autocompletion now includes `add`; i18n `repl.provider_add_missing_value`, `repl.provider_switch_hint` (en+ru).
11
+
12
+ ### Changed
13
+ - **Subcommand dispatch via handler maps** (new architecture rule #17): `/provider`, `/model` and `/skill` (`src/cli/repl-commands.ts`) and `SkillNameProvider.complete` (`src/cli/completer.ts`) now resolve subcommands through a `Record<string, handler>` map instead of `if (subcmd === …)` chains.
14
+
7
15
  ## [0.62.0] - 2026-09-17
8
16
 
9
17
  ### Added
package/dist/i18n/en.json CHANGED
@@ -494,7 +494,9 @@
494
494
  "repl.provider_list": "List configured providers or hot-swap the active one",
495
495
  "repl.provider_current": "Current provider",
496
496
  "repl.provider_set": "Provider set to: {name}",
497
- "repl.provider_usage": "/provider list - show entries (* = active, prio = fallback order) | /provider use <name> - switch without restart",
497
+ "repl.provider_usage": "/provider list - show entries (* = active, prio = fallback order) | /provider use <name> - switch without restart | /provider add <name> [--url <url>] [--key <key>] [--priority <n>] [--context-window <n>] [--rpm <n>] [--parallel <n>] - add to config",
498
+ "repl.provider_add_missing_value": "Missing value for {flag}",
499
+ "repl.provider_switch_hint": "Switch to it with: /provider use {name}",
498
500
  "repl.model_list": "List models of the active provider or switch the model",
499
501
  "repl.model_current": "Current model",
500
502
  "repl.model_set": "Model set to: {name}",
package/dist/i18n/ru.json CHANGED
@@ -488,7 +488,9 @@
488
488
  "repl.provider_list": "Список настроенных провайдеров или горячая смена активного",
489
489
  "repl.provider_current": "Текущий провайдер",
490
490
  "repl.provider_set": "Провайдер установлен: {name}",
491
- "repl.provider_usage": "/provider list — записи (* = активный, prio = порядок fallback) | /provider use <имя> — смена без перезапуска",
491
+ "repl.provider_usage": "/provider list — записи (* = активный, prio = порядок fallback) | /provider use <имя> — смена без перезапуска | /provider add <имя> [--url <url>] [--key <ключ>] [--priority <n>] [--context-window <n>] [--rpm <n>] [--parallel <n>] — добавить в конфиг",
492
+ "repl.provider_add_missing_value": "Нет значения для {flag}",
493
+ "repl.provider_switch_hint": "Переключитесь на него: /provider use {name}",
492
494
  "repl.model_list": "Список моделей активного провайдера или смена модели",
493
495
  "repl.model_current": "Текущая модель",
494
496
  "repl.model_set": "Модель установлена: {name}",
package/dist/main.js CHANGED
@@ -2945,7 +2945,9 @@ Excluded blocks: {count}`,
2945
2945
  "repl.provider_list": "List configured providers or hot-swap the active one",
2946
2946
  "repl.provider_current": "Current provider",
2947
2947
  "repl.provider_set": "Provider set to: {name}",
2948
- "repl.provider_usage": "/provider list - show entries (* = active, prio = fallback order) | /provider use <name> - switch without restart",
2948
+ "repl.provider_usage": "/provider list - show entries (* = active, prio = fallback order) | /provider use <name> - switch without restart | /provider add <name> [--url <url>] [--key <key>] [--priority <n>] [--context-window <n>] [--rpm <n>] [--parallel <n>] - add to config",
2949
+ "repl.provider_add_missing_value": "Missing value for {flag}",
2950
+ "repl.provider_switch_hint": "Switch to it with: /provider use {name}",
2949
2951
  "repl.model_list": "List models of the active provider or switch the model",
2950
2952
  "repl.model_current": "Current model",
2951
2953
  "repl.model_set": "Model set to: {name}",
@@ -3774,7 +3776,9 @@ var init_ru = __esm(() => {
3774
3776
  "repl.provider_list": "Список настроенных провайдеров или горячая смена активного",
3775
3777
  "repl.provider_current": "Текущий провайдер",
3776
3778
  "repl.provider_set": "Провайдер установлен: {name}",
3777
- "repl.provider_usage": "/provider list — записи (* = активный, prio = порядок fallback) | /provider use <имя> — смена без перезапуска",
3779
+ "repl.provider_usage": "/provider list — записи (* = активный, prio = порядок fallback) | /provider use <имя> — смена без перезапуска | /provider add <имя> [--url <url>] [--key <ключ>] [--priority <n>] [--context-window <n>] [--rpm <n>] [--parallel <n>] — добавить в конфиг",
3780
+ "repl.provider_add_missing_value": "Нет значения для {flag}",
3781
+ "repl.provider_switch_hint": "Переключитесь на него: /provider use {name}",
3778
3782
  "repl.model_list": "Список моделей активного провайдера или смена модели",
3779
3783
  "repl.model_current": "Текущая модель",
3780
3784
  "repl.model_set": "Модель установлена: {name}",
@@ -36705,100 +36709,172 @@ function registerConfigCommands(ctx) {
36705
36709
  });
36706
36710
  }
36707
36711
  function registerProviderCommands(ctx) {
36712
+ const list = () => {
36713
+ const providers = ctx.agent.listProviders();
36714
+ if (providers.length === 0) {
36715
+ console.log(`${t("repl.provider_current")} ${ctx.config.provider.type}`);
36716
+ console.log(` ${ctx.config.provider.baseUrl}`);
36717
+ return;
36718
+ }
36719
+ console.log(t("repl.provider_current"));
36720
+ for (const p of providers) {
36721
+ const marker = p.active ? pc2.green("* ") : " ";
36722
+ console.log(` ${marker}${p.label} (${pc2.dim(p.type)}) ${pc2.dim(p.baseUrl)}`);
36723
+ }
36724
+ };
36725
+ const use = async (args) => {
36726
+ const name = args[0];
36727
+ if (!name) {
36728
+ console.log(t("repl.provider_usage"));
36729
+ return;
36730
+ }
36731
+ try {
36732
+ await ctx.agent.setProvider(name);
36733
+ ctx.refreshModelCache();
36734
+ console.log(pc2.green(t("repl.provider_set", { name })));
36735
+ } catch (e) {
36736
+ console.log(pc2.red(e.message));
36737
+ }
36738
+ };
36739
+ const add = async (args) => {
36740
+ const flags = {};
36741
+ let name;
36742
+ for (let i = 0;i < args.length; i++) {
36743
+ const arg = args[i];
36744
+ if (arg.startsWith("--")) {
36745
+ const value = args[i + 1];
36746
+ if (value === undefined || value.startsWith("--")) {
36747
+ console.log(pc2.red(t("repl.provider_add_missing_value", { flag: arg })));
36748
+ return;
36749
+ }
36750
+ flags[arg.slice(2)] = value;
36751
+ i++;
36752
+ } else if (name === undefined) {
36753
+ name = arg;
36754
+ }
36755
+ }
36756
+ if (!name) {
36757
+ console.log(t("repl.provider_usage"));
36758
+ return;
36759
+ }
36760
+ const entries = Array.isArray(ctx.config.provider.entries) ? ctx.config.provider.entries : [];
36761
+ if (entries.length === 0) {
36762
+ entries.push({
36763
+ type: ctx.config.provider.type,
36764
+ label: ctx.config.provider.type,
36765
+ baseUrl: ctx.config.provider.baseUrl,
36766
+ apiKey: ctx.config.provider.apiKey
36767
+ });
36768
+ }
36769
+ const baseUrl = flags.url || HOSTED_BASE_URLS[name] || HOSTED_BASE_URLS[`opencode-${name}`] || "";
36770
+ if (!baseUrl) {
36771
+ console.log(pc2.red(t("cli.provider_no_url", { name })));
36772
+ return;
36773
+ }
36774
+ entries.push({
36775
+ type: name,
36776
+ label: name,
36777
+ baseUrl,
36778
+ apiKey: flags.key,
36779
+ ...flags.priority !== undefined ? { priority: Number(flags.priority) } : {},
36780
+ ...flags["context-window"] !== undefined ? { contextWindow: Number(flags["context-window"]) } : {},
36781
+ ...flags.rpm !== undefined || flags.parallel !== undefined ? {
36782
+ rateLimits: {
36783
+ maxRequestsPerMinute: Number(flags.rpm ?? 0) || 60,
36784
+ maxParallelTasks: Number(flags.parallel ?? 0) || 1
36785
+ }
36786
+ } : {}
36787
+ });
36788
+ ctx.config.provider.entries = entries;
36789
+ ctx.config.provider.active = ctx.config.provider.active || ctx.config.provider.type;
36790
+ const configPath = join54(ctx.configDir, "config.json");
36791
+ saveConfig(ctx.config, configPath, dirname24(configPath));
36792
+ await ctx.agent.reconfigure(ctx.config);
36793
+ console.log(pc2.green(t("cli.provider_added", { name })));
36794
+ console.log(t("repl.provider_switch_hint", { name }));
36795
+ };
36796
+ const handlers = {
36797
+ list,
36798
+ use,
36799
+ add
36800
+ };
36708
36801
  ctx.registerCommand({
36709
36802
  name: "provider",
36710
36803
  description: t("repl.provider_list"),
36711
36804
  usage: t("repl.provider_usage"),
36712
36805
  action: async (args) => {
36713
36806
  const subcmd = args[0];
36714
- if (!subcmd || subcmd === "list") {
36715
- const providers = ctx.agent.listProviders();
36716
- if (providers.length === 0) {
36717
- console.log(`${t("repl.provider_current")} ${ctx.config.provider.type}`);
36718
- console.log(` ${ctx.config.provider.baseUrl}`);
36719
- } else {
36720
- console.log(t("repl.provider_current"));
36721
- for (const p of providers) {
36722
- const marker = p.active ? pc2.green("* ") : " ";
36723
- console.log(` ${marker}${p.label} (${pc2.dim(p.type)}) ${pc2.dim(p.baseUrl)}`);
36724
- }
36725
- }
36807
+ const handler = subcmd ? handlers[subcmd] : handlers.list;
36808
+ if (!handler) {
36809
+ console.log(t("repl.provider_usage"));
36726
36810
  return;
36727
36811
  }
36728
- if (subcmd === "use") {
36729
- const name = args[1];
36730
- if (!name) {
36731
- console.log(t("repl.provider_usage"));
36732
- return;
36733
- }
36734
- try {
36735
- await ctx.agent.setProvider(name);
36736
- ctx.refreshModelCache();
36737
- console.log(pc2.green(t("repl.provider_set", { name })));
36738
- } catch (e) {
36739
- console.log(pc2.red(e.message));
36812
+ await handler(args.slice(1));
36813
+ }
36814
+ });
36815
+ const listModels = async () => {
36816
+ console.log(`${t("repl.model_current")} ${ctx.config.model}`);
36817
+ const { OpenAICompatProvider: OpenAICompatProvider2 } = await Promise.resolve().then(() => (init_openai_compat(), exports_openai_compat));
36818
+ const provider = new OpenAICompatProvider2({
36819
+ model: ctx.config.model,
36820
+ baseUrl: ctx.config.provider.baseUrl,
36821
+ apiKey: ctx.config.provider.apiKey,
36822
+ contextWindow: ctx.config.contextWindow
36823
+ });
36824
+ const { Spinner: Spinner2 } = await Promise.resolve().then(() => (init_spinner(), exports_spinner));
36825
+ const s = new Spinner2;
36826
+ s.start(t("cli.fetching_models"));
36827
+ try {
36828
+ const models = await provider.listModels();
36829
+ s.stop();
36830
+ if (models.length > 0) {
36831
+ ctx.refreshModelCache();
36832
+ console.log(t("cli.available_models"));
36833
+ const { getCertMark: getCertMark2 } = await Promise.resolve().then(() => (init_manifest(), exports_manifest));
36834
+ for (const m of models) {
36835
+ const marker = m === ctx.config.model ? pc2.green("* ") : " ";
36836
+ const mark = getCertMark2(m, ctx.config.provider.baseUrl, version2, process.cwd());
36837
+ const cert = mark === "certified" ? pc2.green("✔") : mark === "stale" ? pc2.yellow("○") : pc2.dim("·");
36838
+ const label = mark === "certified" ? ` ${pc2.green(t("cli.cert_label"))}` : mark === "stale" ? ` ${pc2.yellow(t("cli.cert_stale_label"))}` : "";
36839
+ console.log(` ${marker}${cert} ${m}${label}`);
36740
36840
  }
36741
- return;
36841
+ } else {
36842
+ console.log(t("cli.no_models_found"));
36742
36843
  }
36743
- console.log(t("repl.provider_usage"));
36844
+ } catch (err) {
36845
+ s.stop();
36846
+ console.log(t("cli.model_fetch_failed", { error: String(err) }));
36744
36847
  }
36745
- });
36848
+ console.log(t("cli.model_hint"));
36849
+ };
36850
+ const useModel = async (args) => {
36851
+ const name = args[0];
36852
+ if (!name) {
36853
+ console.log(t("repl.model_usage"));
36854
+ return;
36855
+ }
36856
+ ctx.config.model = name;
36857
+ const configPath = join54(ctx.configDir, "config.json");
36858
+ saveConfig(ctx.config, configPath, dirname24(configPath));
36859
+ await ctx.agent.reconfigure(ctx.config);
36860
+ console.log(pc2.green(t("repl.model_set", { name })));
36861
+ };
36862
+ const modelHandlers = {
36863
+ list: listModels,
36864
+ use: useModel
36865
+ };
36746
36866
  ctx.registerCommand({
36747
36867
  name: "model",
36748
36868
  description: t("repl.model_list"),
36749
36869
  usage: t("repl.model_usage"),
36750
36870
  action: async (args) => {
36751
36871
  const subcmd = args[0];
36752
- if (!subcmd || subcmd === "list") {
36753
- console.log(`${t("repl.model_current")} ${ctx.config.model}`);
36754
- const { OpenAICompatProvider: OpenAICompatProvider2 } = await Promise.resolve().then(() => (init_openai_compat(), exports_openai_compat));
36755
- const provider = new OpenAICompatProvider2({
36756
- model: ctx.config.model,
36757
- baseUrl: ctx.config.provider.baseUrl,
36758
- apiKey: ctx.config.provider.apiKey,
36759
- contextWindow: ctx.config.contextWindow
36760
- });
36761
- const { Spinner: Spinner2 } = await Promise.resolve().then(() => (init_spinner(), exports_spinner));
36762
- const s = new Spinner2;
36763
- s.start(t("cli.fetching_models"));
36764
- try {
36765
- const models = await provider.listModels();
36766
- s.stop();
36767
- if (models.length > 0) {
36768
- ctx.refreshModelCache();
36769
- console.log(t("cli.available_models"));
36770
- const { getCertMark: getCertMark2 } = await Promise.resolve().then(() => (init_manifest(), exports_manifest));
36771
- for (const m of models) {
36772
- const marker = m === ctx.config.model ? pc2.green("* ") : " ";
36773
- const mark = getCertMark2(m, ctx.config.provider.baseUrl, version2, process.cwd());
36774
- const cert = mark === "certified" ? pc2.green("✔") : mark === "stale" ? pc2.yellow("○") : pc2.dim("·");
36775
- const label = mark === "certified" ? ` ${pc2.green(t("cli.cert_label"))}` : mark === "stale" ? ` ${pc2.yellow(t("cli.cert_stale_label"))}` : "";
36776
- console.log(` ${marker}${cert} ${m}${label}`);
36777
- }
36778
- } else {
36779
- console.log(t("cli.no_models_found"));
36780
- }
36781
- } catch (err) {
36782
- s.stop();
36783
- console.log(t("cli.model_fetch_failed", { error: String(err) }));
36784
- }
36785
- console.log(t("cli.model_hint"));
36786
- return;
36787
- }
36788
- if (subcmd === "use") {
36789
- const name = args[1];
36790
- if (!name) {
36791
- console.log(t("repl.model_usage"));
36792
- return;
36793
- }
36794
- ctx.config.model = name;
36795
- const configPath = join54(ctx.configDir, "config.json");
36796
- saveConfig(ctx.config, configPath, dirname24(configPath));
36797
- await ctx.agent.reconfigure(ctx.config);
36798
- console.log(pc2.green(t("repl.model_set", { name })));
36872
+ const handler = subcmd ? modelHandlers[subcmd] : modelHandlers.list;
36873
+ if (!handler) {
36874
+ console.log(t("repl.model_usage"));
36799
36875
  return;
36800
36876
  }
36801
- console.log(t("repl.model_usage"));
36877
+ await handler(args.slice(1));
36802
36878
  }
36803
36879
  });
36804
36880
  ctx.registerCommand({
@@ -37107,88 +37183,97 @@ function registerSessionCommands(ctx) {
37107
37183
  function registerSkillCommands(ctx) {
37108
37184
  if (!ctx.skillsModule)
37109
37185
  return;
37186
+ const listSkills = () => {
37187
+ const available = ctx.skillsModule.getAvailable();
37188
+ if (available.length === 0) {
37189
+ console.log(t("repl.no_skills"));
37190
+ return;
37191
+ }
37192
+ console.log(pc2.bold(t("repl.available_skills")));
37193
+ for (const skill of available) {
37194
+ const tokens = estimateTokens(skill.content);
37195
+ const loaded = ctx.skillsModule.getLoaded().some((s) => s.name === skill.name);
37196
+ const marker = loaded ? pc2.green(" [loaded]") : "";
37197
+ console.log(` ${pc2.cyan(skill.name)}${marker} ${pc2.dim(`(${tokens} tokens)`)} ${skill.description.slice(0, 60)}`);
37198
+ }
37199
+ };
37200
+ const listLoaded = () => {
37201
+ const loaded = ctx.skillsModule.getLoaded();
37202
+ const budget = ctx.skillsModule.getBudget();
37203
+ if (loaded.length === 0) {
37204
+ console.log(t("repl.no_loaded"));
37205
+ return;
37206
+ }
37207
+ console.log(pc2.bold(t("repl.loaded_skills")));
37208
+ for (const skill of loaded) {
37209
+ const tokens = estimateTokens(skill.content);
37210
+ console.log(` ${pc2.cyan(skill.name)} ${pc2.dim(`(${tokens} tokens)`)} ${skill.description.slice(0, 60)}`);
37211
+ }
37212
+ console.log(pc2.dim(`
37213
+ ${t("repl.budget", { used: budget.used, total: budget.total, remaining: budget.remaining })}`));
37214
+ };
37215
+ const loadSkill = (args) => {
37216
+ const arg = args.join(" ");
37217
+ if (!arg) {
37218
+ console.log(t("repl.skill_load_usage"));
37219
+ return;
37220
+ }
37221
+ const result = ctx.skillsModule.loadByName(arg);
37222
+ if (result.success) {
37223
+ console.log(pc2.green(result.message));
37224
+ } else {
37225
+ console.log(pc2.red(result.message));
37226
+ }
37227
+ };
37228
+ const unloadSkill = (args) => {
37229
+ const arg = args.join(" ");
37230
+ if (!arg) {
37231
+ console.log(t("repl.skill_unload_usage"));
37232
+ return;
37233
+ }
37234
+ if (ctx.skillsModule.unload(arg)) {
37235
+ console.log(pc2.green(t("repl.skill_unloaded", { name: arg })));
37236
+ } else {
37237
+ console.log(pc2.red(t("repl.skill_not_loaded", { name: arg })));
37238
+ }
37239
+ };
37240
+ const searchSkills = (args) => {
37241
+ const arg = args.join(" ");
37242
+ if (!arg) {
37243
+ console.log(t("repl.skill_search_usage"));
37244
+ return;
37245
+ }
37246
+ const results = ctx.skillsModule.search(arg);
37247
+ if (results.length === 0) {
37248
+ console.log(t("repl.no_skill_match", { query: arg }));
37249
+ return;
37250
+ }
37251
+ console.log(pc2.bold(t("repl.skills_matching", { query: arg })));
37252
+ for (const skill of results) {
37253
+ const tokens = estimateTokens(skill.content);
37254
+ console.log(` ${pc2.cyan(skill.name)} ${pc2.dim(`(${tokens} tokens)`)} ${skill.description.slice(0, 60)}`);
37255
+ }
37256
+ };
37257
+ const skillHandlers = {
37258
+ list: listSkills,
37259
+ loaded: listLoaded,
37260
+ load: loadSkill,
37261
+ unload: unloadSkill,
37262
+ search: searchSkills
37263
+ };
37110
37264
  ctx.registerCommand({
37111
37265
  name: "skill",
37112
37266
  description: t("repl.skill"),
37113
37267
  usage: t("repl.skill_usage"),
37114
37268
  action: (args) => {
37115
37269
  const subcmd = args[0];
37116
- const arg = args.slice(1).join(" ");
37117
- if (!subcmd || subcmd === "list") {
37118
- const available = ctx.skillsModule.getAvailable();
37119
- if (available.length === 0) {
37120
- console.log(t("repl.no_skills"));
37121
- return;
37122
- }
37123
- console.log(pc2.bold(t("repl.available_skills")));
37124
- for (const skill of available) {
37125
- const tokens = estimateTokens(skill.content);
37126
- const loaded = ctx.skillsModule.getLoaded().some((s) => s.name === skill.name);
37127
- const marker = loaded ? pc2.green(" [loaded]") : "";
37128
- console.log(` ${pc2.cyan(skill.name)}${marker} ${pc2.dim(`(${tokens} tokens)`)} ${skill.description.slice(0, 60)}`);
37129
- }
37130
- return;
37131
- }
37132
- if (subcmd === "loaded") {
37133
- const loaded = ctx.skillsModule.getLoaded();
37134
- const budget = ctx.skillsModule.getBudget();
37135
- if (loaded.length === 0) {
37136
- console.log(t("repl.no_loaded"));
37137
- return;
37138
- }
37139
- console.log(pc2.bold(t("repl.loaded_skills")));
37140
- for (const skill of loaded) {
37141
- const tokens = estimateTokens(skill.content);
37142
- console.log(` ${pc2.cyan(skill.name)} ${pc2.dim(`(${tokens} tokens)`)} ${skill.description.slice(0, 60)}`);
37143
- }
37144
- console.log(pc2.dim(`
37145
- ${t("repl.budget", { used: budget.used, total: budget.total, remaining: budget.remaining })}`));
37146
- return;
37147
- }
37148
- if (subcmd === "load") {
37149
- if (!arg) {
37150
- console.log(t("repl.skill_load_usage"));
37151
- return;
37152
- }
37153
- const result = ctx.skillsModule.loadByName(arg);
37154
- if (result.success) {
37155
- console.log(pc2.green(result.message));
37156
- } else {
37157
- console.log(pc2.red(result.message));
37158
- }
37270
+ const handler = subcmd ? skillHandlers[subcmd] : skillHandlers.list;
37271
+ if (!handler) {
37272
+ console.log(pc2.red(t("repl.skill_unknown_sub", { subcmd })));
37273
+ console.log(t("repl.skill_usage"));
37159
37274
  return;
37160
37275
  }
37161
- if (subcmd === "unload") {
37162
- if (!arg) {
37163
- console.log(t("repl.skill_unload_usage"));
37164
- return;
37165
- }
37166
- if (ctx.skillsModule.unload(arg)) {
37167
- console.log(pc2.green(t("repl.skill_unloaded", { name: arg })));
37168
- } else {
37169
- console.log(pc2.red(t("repl.skill_not_loaded", { name: arg })));
37170
- }
37171
- return;
37172
- }
37173
- if (subcmd === "search") {
37174
- if (!arg) {
37175
- console.log(t("repl.skill_search_usage"));
37176
- return;
37177
- }
37178
- const results = ctx.skillsModule.search(arg);
37179
- if (results.length === 0) {
37180
- console.log(t("repl.no_skill_match", { query: arg }));
37181
- return;
37182
- }
37183
- console.log(pc2.bold(t("repl.skills_matching", { query: arg })));
37184
- for (const skill of results) {
37185
- const tokens = estimateTokens(skill.content);
37186
- console.log(` ${pc2.cyan(skill.name)} ${pc2.dim(`(${tokens} tokens)`)} ${skill.description.slice(0, 60)}`);
37187
- }
37188
- return;
37189
- }
37190
- console.log(pc2.red(t("repl.skill_unknown_sub", { subcmd })));
37191
- console.log(t("repl.skill_usage"));
37276
+ handler(args.slice(1));
37192
37277
  }
37193
37278
  });
37194
37279
  }
@@ -37221,6 +37306,7 @@ var init_repl_commands = __esm(() => {
37221
37306
  init_i18n();
37222
37307
  init_setup();
37223
37308
  init_config2();
37309
+ init_presets();
37224
37310
  init_budget();
37225
37311
  init_token_counter();
37226
37312
  init_map_command();
@@ -39549,22 +39635,17 @@ class SkillNameProvider {
39549
39635
  return ctx.tokenIndex >= 2 && ctx.tokens[0] === "/skill" && (ctx.tokens[1] === "load" || ctx.tokens[1] === "unload");
39550
39636
  }
39551
39637
  complete(ctx) {
39552
- const subcmd = ctx.tokens[1];
39553
- if (subcmd === "load") {
39554
- const available = this.skillsModule.getAvailable();
39555
- const names = available.map((s) => s.name);
39556
- if (!ctx.partial)
39557
- return names;
39558
- return names.filter((n) => n.toLowerCase().includes(ctx.partial.toLowerCase()));
39559
- }
39560
- if (subcmd === "unload") {
39561
- const loaded = this.skillsModule.getLoaded();
39562
- const names = loaded.map((s) => s.name);
39563
- if (!ctx.partial)
39564
- return names;
39565
- return names.filter((n) => n.toLowerCase().includes(ctx.partial.toLowerCase()));
39566
- }
39567
- return [];
39638
+ const sources = {
39639
+ load: () => this.skillsModule.getAvailable().map((s) => s.name),
39640
+ unload: () => this.skillsModule.getLoaded().map((s) => s.name)
39641
+ };
39642
+ const source = sources[ctx.tokens[1]];
39643
+ if (!source)
39644
+ return [];
39645
+ const names = source();
39646
+ if (!ctx.partial)
39647
+ return names;
39648
+ return names.filter((n) => n.toLowerCase().includes(ctx.partial.toLowerCase()));
39568
39649
  }
39569
39650
  }
39570
39651
 
@@ -40417,7 +40498,7 @@ class Repl {
40417
40498
  this.completer.registerProvider(new SubcommandProvider("skill", ["list", "loaded", "load", "unload", "search"]));
40418
40499
  this.completer.registerProvider(new SkillNameProvider(this.skillsModule));
40419
40500
  }
40420
- this.completer.registerProvider(new SubcommandProvider("provider", ["list", "use"]));
40501
+ this.completer.registerProvider(new SubcommandProvider("provider", ["list", "use", "add"]));
40421
40502
  this.completer.registerProvider(new SubcommandProvider("model", ["list", "use"]));
40422
40503
  const entryLabels = this.config.provider?.entries?.map((e) => e.label || e.type) ?? [];
40423
40504
  if (entryLabels.length > 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "micro-models-agent",
3
- "version": "0.62.0",
3
+ "version": "0.63.0",
4
4
  "description": "Micro Models Agent (MMA) — LLM agent harness for small models (Qwen3.5-9B, 32K-64K context)",
5
5
  "type": "module",
6
6
  "bin": {