@iola_adm/iola-cli 0.1.67 → 0.1.68

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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/cli.js +48 -7
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iola_adm/iola-cli",
3
- "version": "0.1.67",
3
+ "version": "0.1.68",
4
4
  "description": "CLI и AI-агент городского округа Йошкар-Ола.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/adm-iola/iola-cli#readme",
package/src/cli.js CHANGED
@@ -4077,18 +4077,14 @@ async function listAiModels(provider) {
4077
4077
  }
4078
4078
 
4079
4079
  const payload = await response.json();
4080
- return (payload.models || []).map((model) => ({
4080
+ const models = (payload.models || []).map((model) => ({
4081
4081
  id: model.name,
4082
4082
  provider: "ollama",
4083
4083
  note: model.modified_at ? `updated ${model.modified_at}` : "local",
4084
4084
  }));
4085
+ return models.length > 0 ? models : getRecommendedOllamaModels("not installed");
4085
4086
  } catch {
4086
- return [
4087
- { id: "llama3.2:1b", provider: "ollama", note: "recommended low RAM" },
4088
- { id: "llama3.2:3b", provider: "ollama", note: "recommended standard" },
4089
- { id: "qwen3:4b", provider: "ollama", note: "recommended balanced" },
4090
- { id: "qwen3:8b", provider: "ollama", note: "recommended good GPU" },
4091
- ];
4087
+ return getRecommendedOllamaModels("recommended");
4092
4088
  }
4093
4089
  }
4094
4090
 
@@ -4139,6 +4135,15 @@ async function listAiModels(provider) {
4139
4135
  ];
4140
4136
  }
4141
4137
 
4138
+ function getRecommendedOllamaModels(notePrefix = "recommended") {
4139
+ return [
4140
+ { id: "llama3.2:1b", provider: "ollama", note: `${notePrefix} low RAM` },
4141
+ { id: "llama3.2:3b", provider: "ollama", note: `${notePrefix} standard` },
4142
+ { id: "qwen3:4b", provider: "ollama", note: `${notePrefix} balanced` },
4143
+ { id: "qwen3:8b", provider: "ollama", note: `${notePrefix} good GPU` },
4144
+ ];
4145
+ }
4146
+
4142
4147
  async function printAiProfiles() {
4143
4148
  const config = await loadConfig();
4144
4149
  const active = getActiveProfileName(config);
@@ -4455,6 +4460,10 @@ async function chooseAiModel(provider) {
4455
4460
  async function switchModelTarget(target, model) {
4456
4461
  const config = await loadConfig();
4457
4462
  const provider = target === "local" ? "ollama" : target;
4463
+ if (provider === "ollama") {
4464
+ const ready = await ensureOllamaModelAvailable(model, config);
4465
+ if (!ready) return;
4466
+ }
4458
4467
  const profileName = provider === "ollama" ? "local" : provider;
4459
4468
  const currentProfile = config.ai.profiles?.[profileName] || buildProfileFromOptions(provider, { model });
4460
4469
  const profile = {
@@ -4480,6 +4489,38 @@ async function switchModelTarget(target, model) {
4480
4489
  console.log(`Активная модель: ${profileName} (${provider}, ${model})`);
4481
4490
  }
4482
4491
 
4492
+ async function ensureOllamaModelAvailable(model, config = null) {
4493
+ if (await isOllamaModelInstalled(model, config)) return true;
4494
+
4495
+ const command = await resolveOllamaCommand();
4496
+ if (!command) {
4497
+ console.log("Ollama CLI не найден в PATH, хотя локальный API может отвечать.");
4498
+ console.log("Откройте новый PowerShell или запустите мастер: iola ai setup ollama");
4499
+ return false;
4500
+ }
4501
+
4502
+ const shouldInstall = await confirm(`Локальная модель ${model} не скачана. Скачать через "ollama pull ${model}"? [Y/n] `);
4503
+ if (!shouldInstall) {
4504
+ console.log("Переключение на локальную модель отменено.");
4505
+ return false;
4506
+ }
4507
+
4508
+ await runCommand(command, ["pull", model], { inherit: true });
4509
+ return true;
4510
+ }
4511
+
4512
+ async function isOllamaModelInstalled(model, loadedConfig = null) {
4513
+ try {
4514
+ const config = loadedConfig || await loadConfig();
4515
+ const response = await fetch(`${config.ai.profiles?.local?.baseUrl || "http://127.0.0.1:11434"}/api/tags`);
4516
+ if (!response.ok) return false;
4517
+ const payload = await response.json();
4518
+ return (payload.models || []).some((entry) => entry.name === model);
4519
+ } catch {
4520
+ return false;
4521
+ }
4522
+ }
4523
+
4483
4524
  async function askText(question) {
4484
4525
  if (!process.stdin.isTTY) return "";
4485
4526
  const rl = readline.createInterface({ input, output });