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 +8 -0
- package/dist/i18n/en.json +3 -1
- package/dist/i18n/ru.json +3 -1
- package/dist/main.js +249 -168
- package/package.json +1 -1
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
|
-
|
|
36715
|
-
|
|
36716
|
-
|
|
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
|
-
|
|
36729
|
-
|
|
36730
|
-
|
|
36731
|
-
|
|
36732
|
-
|
|
36733
|
-
|
|
36734
|
-
|
|
36735
|
-
|
|
36736
|
-
|
|
36737
|
-
|
|
36738
|
-
|
|
36739
|
-
|
|
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
|
-
|
|
36841
|
+
} else {
|
|
36842
|
+
console.log(t("cli.no_models_found"));
|
|
36742
36843
|
}
|
|
36743
|
-
|
|
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
|
-
|
|
36753
|
-
|
|
36754
|
-
|
|
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
|
-
|
|
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
|
|
37117
|
-
if (!
|
|
37118
|
-
|
|
37119
|
-
|
|
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
|
-
|
|
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
|
|
39553
|
-
|
|
39554
|
-
|
|
39555
|
-
|
|
39556
|
-
|
|
39557
|
-
|
|
39558
|
-
return
|
|
39559
|
-
|
|
39560
|
-
if (
|
|
39561
|
-
|
|
39562
|
-
|
|
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) {
|