@iola_adm/iola-cli 0.1.41 → 0.1.43
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/package.json +1 -1
- package/src/cli.js +84 -4
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -120,6 +120,7 @@ const SKILL_BUNDLES = {
|
|
|
120
120
|
requirements: ["Ollama", "локальная модель"],
|
|
121
121
|
},
|
|
122
122
|
};
|
|
123
|
+
let onboardRanThisProcess = false;
|
|
123
124
|
const DEFAULT_AI_CONFIG = {
|
|
124
125
|
api: {
|
|
125
126
|
baseUrl: "https://apiiola.yasg.ru/api/v1",
|
|
@@ -622,6 +623,7 @@ async function runDefaultCli() {
|
|
|
622
623
|
|
|
623
624
|
async function startAgent() {
|
|
624
625
|
await showBanner();
|
|
626
|
+
await ensureAgentAiReady();
|
|
625
627
|
console.log("Интерактивный режим. Введите /help для списка команд, /exit для выхода.");
|
|
626
628
|
await runHooks("SessionStart", { mode: "agent" });
|
|
627
629
|
|
|
@@ -635,6 +637,73 @@ async function startAgent() {
|
|
|
635
637
|
await runHooks("SessionEnd", { mode: "agent" });
|
|
636
638
|
}
|
|
637
639
|
|
|
640
|
+
async function ensureAgentAiReady() {
|
|
641
|
+
const readiness = await getAiReadiness();
|
|
642
|
+
if (readiness.ready) return readiness;
|
|
643
|
+
|
|
644
|
+
if (!input.isTTY || !output.isTTY) {
|
|
645
|
+
console.log("AI-провайдер не настроен. Для настройки запустите: iola wizard");
|
|
646
|
+
return readiness;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
if (onboardRanThisProcess) {
|
|
650
|
+
console.log("AI-провайдер пока не настроен. Агент откроется, но AI-запросы потребуют настройки.");
|
|
651
|
+
console.log("Повторно открыть мастер можно командой: /wizard");
|
|
652
|
+
return readiness;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
console.log("AI-провайдер не настроен: нет локальной модели Ollama, API-ключей OpenAI/OpenRouter и авторизации Codex.");
|
|
656
|
+
console.log("Сейчас откроется мастер настройки. Уже существующие настройки не будут сброшены.");
|
|
657
|
+
console.log("");
|
|
658
|
+
await onboard([]);
|
|
659
|
+
|
|
660
|
+
const updated = await getAiReadiness();
|
|
661
|
+
if (!updated.ready) {
|
|
662
|
+
console.log("");
|
|
663
|
+
console.log("AI-провайдер пока не настроен. Агент откроется, но AI-запросы потребуют настройки.");
|
|
664
|
+
console.log("Повторно открыть мастер можно командой: /wizard");
|
|
665
|
+
}
|
|
666
|
+
return updated;
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
async function getAiReadiness() {
|
|
670
|
+
const [secrets, ollama, codex] = await Promise.all([
|
|
671
|
+
loadSecrets(),
|
|
672
|
+
hasUsableOllamaModel(),
|
|
673
|
+
hasUsableCodexAuth(),
|
|
674
|
+
]);
|
|
675
|
+
const openai = Boolean(process.env.OPENAI_API_KEY || secrets.openai?.apiKey);
|
|
676
|
+
const openrouter = Boolean(process.env.OPENROUTER_API_KEY || secrets.openrouter?.apiKey);
|
|
677
|
+
return {
|
|
678
|
+
ready: Boolean(ollama || openai || openrouter || codex),
|
|
679
|
+
ollama,
|
|
680
|
+
openai,
|
|
681
|
+
openrouter,
|
|
682
|
+
codex,
|
|
683
|
+
};
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
async function hasUsableOllamaModel() {
|
|
687
|
+
try {
|
|
688
|
+
const config = await loadConfig();
|
|
689
|
+
const baseUrl = config.ai.profiles?.local?.baseUrl || "http://127.0.0.1:11434";
|
|
690
|
+
const response = await fetch(`${baseUrl}/api/tags`, { signal: AbortSignal.timeout(1200) });
|
|
691
|
+
if (!response.ok) return false;
|
|
692
|
+
const payload = await response.json();
|
|
693
|
+
const models = Array.isArray(payload.models) ? payload.models : [];
|
|
694
|
+
return models.length > 0;
|
|
695
|
+
} catch {
|
|
696
|
+
return false;
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
async function hasUsableCodexAuth() {
|
|
701
|
+
const version = await getCommandVersion("codex", ["--version"]);
|
|
702
|
+
if (version === "не найден") return false;
|
|
703
|
+
if (process.env.OPENAI_API_KEY) return true;
|
|
704
|
+
return existsSync(path.join(os.homedir(), ".codex", "auth.json"));
|
|
705
|
+
}
|
|
706
|
+
|
|
638
707
|
async function startAgentReadline() {
|
|
639
708
|
const rl = readline.createInterface({ input, output, prompt: "iola> " });
|
|
640
709
|
const state = {
|
|
@@ -2163,16 +2232,26 @@ async function handleWiki(args) {
|
|
|
2163
2232
|
}
|
|
2164
2233
|
|
|
2165
2234
|
if (action === "links" || action === "list" || action === "ls") {
|
|
2166
|
-
|
|
2167
|
-
["title", "Раздел"],
|
|
2168
|
-
["url", "Ссылка"],
|
|
2169
|
-
]);
|
|
2235
|
+
printWikiLinks(links);
|
|
2170
2236
|
return;
|
|
2171
2237
|
}
|
|
2172
2238
|
|
|
2173
2239
|
throw new Error("Команды wiki: links, open.");
|
|
2174
2240
|
}
|
|
2175
2241
|
|
|
2242
|
+
function printWikiLinks(links) {
|
|
2243
|
+
if (links.length === 0) {
|
|
2244
|
+
console.log("Нет данных.");
|
|
2245
|
+
return;
|
|
2246
|
+
}
|
|
2247
|
+
const titleWidth = Math.max("Раздел".length, ...links.map((link) => visibleLength(link.title)));
|
|
2248
|
+
console.log(`${padCell("Раздел", titleWidth)} Ссылка`);
|
|
2249
|
+
console.log(`${"-".repeat(titleWidth)} ${"-".repeat(6)}`);
|
|
2250
|
+
for (const link of links) {
|
|
2251
|
+
console.log(`${padCell(link.title, titleWidth)} ${link.url}`);
|
|
2252
|
+
}
|
|
2253
|
+
}
|
|
2254
|
+
|
|
2176
2255
|
async function handleContext(args) {
|
|
2177
2256
|
const [action = "list"] = args;
|
|
2178
2257
|
const files = await listContextFiles();
|
|
@@ -6590,6 +6669,7 @@ async function setupClient(args) {
|
|
|
6590
6669
|
}
|
|
6591
6670
|
|
|
6592
6671
|
async function onboard(args = []) {
|
|
6672
|
+
onboardRanThisProcess = true;
|
|
6593
6673
|
const options = parseOptions(args);
|
|
6594
6674
|
await showBanner();
|
|
6595
6675
|
console.log("Мастер настройки iola-cli.");
|