@iola_adm/iola-cli 0.1.93 → 0.1.95
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 +71 -10
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -33,7 +33,7 @@ const LOCAL_CONFIG_FILE = path.join(PROJECT_IOLA_DIR, "local.json");
|
|
|
33
33
|
const BROWSER_RUNTIME_DIR = path.join(CONFIG_DIR, "browser-runtime");
|
|
34
34
|
const BROWSER_RUNTIME_PACKAGE = path.join(BROWSER_RUNTIME_DIR, "node_modules", "playwright", "package.json");
|
|
35
35
|
const INDEXABLE_EXTENSIONS = /\.(md|txt|csv|json|html|docx|xlsx|pptx|pdf)$/i;
|
|
36
|
-
const LOCAL_TOOLS = ["search_data", "search_entities", "resolve_entity_field", "get_card", "export_report", "file_read", "browser_open"];
|
|
36
|
+
const LOCAL_TOOLS = ["search_data", "search_entities", "resolve_entity_field", "get_card", "export_report", "file_read", "browser_open", "get_current_date"];
|
|
37
37
|
const LEGACY_LOCAL_TOOLS = ["search_local", "export_data", "run_report", "save_view"];
|
|
38
38
|
const FILE_TOOLS = ["files_tree", "files_read", "files_search", "files_write", "files_patch"];
|
|
39
39
|
const ALL_LOCAL_TOOLS = [...LOCAL_TOOLS, ...FILE_TOOLS];
|
|
@@ -628,13 +628,19 @@ async function runDefaultCli() {
|
|
|
628
628
|
|
|
629
629
|
initDatabase();
|
|
630
630
|
if (!isFirstRunCompleted()) {
|
|
631
|
-
await
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
631
|
+
const readiness = await getAiReadiness();
|
|
632
|
+
if (readiness.ready) {
|
|
633
|
+
markFirstRunCompleted();
|
|
634
|
+
} else {
|
|
635
|
+
await showBanner();
|
|
636
|
+
console.log("Первый запуск iola-cli. Сейчас откроется мастер настройки.");
|
|
637
|
+
console.log("После мастера запустится интерактивный агент.");
|
|
638
|
+
console.log("Введите 0, чтобы пропустить мастер и перейти в CLI.");
|
|
639
|
+
console.log("");
|
|
640
|
+
await onboard([]);
|
|
641
|
+
markFirstRunCompleted();
|
|
642
|
+
console.log("");
|
|
643
|
+
}
|
|
638
644
|
}
|
|
639
645
|
|
|
640
646
|
await startAgent([]);
|
|
@@ -6430,6 +6436,11 @@ async function localToolAsk(question, providerConfig, options) {
|
|
|
6430
6436
|
if (!options.quiet) console.log(guarded);
|
|
6431
6437
|
return guarded;
|
|
6432
6438
|
}
|
|
6439
|
+
const casualAnswer = buildCasualDirectAnswer(question);
|
|
6440
|
+
if (casualAnswer) {
|
|
6441
|
+
if (!options.quiet) console.log(casualAnswer);
|
|
6442
|
+
return casualAnswer;
|
|
6443
|
+
}
|
|
6433
6444
|
await ensureLocalData();
|
|
6434
6445
|
const plan = await buildLocalToolPlan(question, providerConfig, options);
|
|
6435
6446
|
if (plan.directAnswer) {
|
|
@@ -6483,6 +6494,20 @@ function guardNonPublicQuestion(question) {
|
|
|
6483
6494
|
return "";
|
|
6484
6495
|
}
|
|
6485
6496
|
|
|
6497
|
+
function buildCasualDirectAnswer(question) {
|
|
6498
|
+
const normalized = String(question || "").toLocaleLowerCase("ru-RU").trim();
|
|
6499
|
+
if (/^(привет|здравствуй|здравствуйте|добрый день|доброе утро|добрый вечер|hi|hello|hey)([!.?\s]+(как дела|как ты|что нового)[?.!\s]*)?$/iu.test(normalized)) {
|
|
6500
|
+
return "Привет. Работаю нормально. Могу помочь с открытыми данными Йошкар-Олы: школами, детскими садами, адресами, телефонами, сайтами и ИНН.";
|
|
6501
|
+
}
|
|
6502
|
+
if (/^(как дела|как ты|что нового|ты тут|ты здесь)[?.!\s]*$/iu.test(normalized)) {
|
|
6503
|
+
return "Я на месте. Могу искать и проверять открытые городские данные.";
|
|
6504
|
+
}
|
|
6505
|
+
if (/^(спасибо|благодарю)[!.?\s]*$/iu.test(normalized)) {
|
|
6506
|
+
return "Пожалуйста.";
|
|
6507
|
+
}
|
|
6508
|
+
return "";
|
|
6509
|
+
}
|
|
6510
|
+
|
|
6486
6511
|
function printToolPlan(plan) {
|
|
6487
6512
|
console.log("План выполнения:");
|
|
6488
6513
|
plan.steps.forEach((step, index) => {
|
|
@@ -6528,7 +6553,12 @@ async function buildLocalToolPlan(question, providerConfig, options) {
|
|
|
6528
6553
|
function normalizeIolaRouterPlan(raw, question, options = {}) {
|
|
6529
6554
|
const payload = typeof raw === "string" ? parseJsonObject(raw) : raw;
|
|
6530
6555
|
if (payload.action === "tool_call") {
|
|
6531
|
-
const tool = payload.tool
|
|
6556
|
+
const tool = normalizeIolaToolName(payload.tool);
|
|
6557
|
+
if (!availableToolNames(options).includes(tool)) {
|
|
6558
|
+
const casualAnswer = buildCasualDirectAnswer(question);
|
|
6559
|
+
if (casualAnswer) return { directAnswer: casualAnswer };
|
|
6560
|
+
return inferToolPlan(question, options);
|
|
6561
|
+
}
|
|
6532
6562
|
return { steps: [{ tool, args: payload.args || {} }] };
|
|
6533
6563
|
}
|
|
6534
6564
|
if (payload.action === "direct_answer") {
|
|
@@ -6546,6 +6576,12 @@ function normalizeIolaRouterPlan(raw, question, options = {}) {
|
|
|
6546
6576
|
throw new Error(`IOLA router вернул неподдерживаемое действие: ${payload.action || "unknown"}`);
|
|
6547
6577
|
}
|
|
6548
6578
|
|
|
6579
|
+
function normalizeIolaToolName(tool) {
|
|
6580
|
+
if (tool === "get_entity_field") return "resolve_entity_field";
|
|
6581
|
+
if (tool === "current_date" || tool === "date_now" || tool === "today") return "get_current_date";
|
|
6582
|
+
return tool;
|
|
6583
|
+
}
|
|
6584
|
+
|
|
6549
6585
|
function parseJsonObject(text) {
|
|
6550
6586
|
const match = String(text).match(/\{[\s\S]*\}/);
|
|
6551
6587
|
if (!match) throw new Error("JSON-план не найден.");
|
|
@@ -6698,6 +6734,9 @@ async function executeToolPlan(plan, options = {}) {
|
|
|
6698
6734
|
const text = await runBrowserAutomation("text", { url: step.args?.url, waitMs: Number(step.args?.waitMs || 0), timeout: Number(step.args?.timeout || 30000), viewport: step.args?.viewport || "1366x768" });
|
|
6699
6735
|
current = [{ url: step.args?.url, text }];
|
|
6700
6736
|
outputs.push({ tool: step.tool, rows: 1 });
|
|
6737
|
+
} else if (step.tool === "get_current_date") {
|
|
6738
|
+
current = [getCurrentDateInfo()];
|
|
6739
|
+
outputs.push({ tool: step.tool, rows: current.length });
|
|
6701
6740
|
} else if (String(step.tool || "").startsWith("mcp:")) {
|
|
6702
6741
|
const result = await callConfiguredMcpTool(step.tool, step.args || {});
|
|
6703
6742
|
current = Array.isArray(result) ? result : [result];
|
|
@@ -6736,6 +6775,16 @@ async function executeToolPlan(plan, options = {}) {
|
|
|
6736
6775
|
return { rows: current, outputs };
|
|
6737
6776
|
}
|
|
6738
6777
|
|
|
6778
|
+
function getCurrentDateInfo() {
|
|
6779
|
+
const now = new Date();
|
|
6780
|
+
return {
|
|
6781
|
+
name: "текущая дата",
|
|
6782
|
+
date: new Intl.DateTimeFormat("ru-RU", { dateStyle: "long" }).format(now),
|
|
6783
|
+
time: new Intl.DateTimeFormat("ru-RU", { timeStyle: "short" }).format(now),
|
|
6784
|
+
iso: now.toISOString(),
|
|
6785
|
+
};
|
|
6786
|
+
}
|
|
6787
|
+
|
|
6739
6788
|
function getLocalMcpToolNames() {
|
|
6740
6789
|
return mcpTools().map((tool) => `mcp:iola-local:${tool.name}`);
|
|
6741
6790
|
}
|
|
@@ -6818,6 +6867,7 @@ function formatToolResult(result, options) {
|
|
|
6818
6867
|
const name = row.entity.name || row.entity.inn || "организация";
|
|
6819
6868
|
return `${name}: ${row.field} = ${row.value ?? "не указано"}`;
|
|
6820
6869
|
}
|
|
6870
|
+
if (row.date && row.time) return `Сегодня ${row.date}, ${row.time}.`;
|
|
6821
6871
|
return `${row.name || row.check || row.inn || "строка"}: ${row.address || row.phone || row.email || row.website || row.count || ""}`;
|
|
6822
6872
|
}).join("\n");
|
|
6823
6873
|
}
|
|
@@ -7717,6 +7767,11 @@ async function onboard(args = []) {
|
|
|
7717
7767
|
|
|
7718
7768
|
const componentStatus = await getOnboardComponentStatus();
|
|
7719
7769
|
const components = options.yes ? defaultOnboardComponents(componentStatus) : await chooseOnboardComponents(componentStatus);
|
|
7770
|
+
if (components.length === 0) {
|
|
7771
|
+
markFirstRunCompleted();
|
|
7772
|
+
console.log("Мастер пропущен. Переход в CLI.");
|
|
7773
|
+
return;
|
|
7774
|
+
}
|
|
7720
7775
|
if (components.includes("workspace")) await handleWorkspace(["init"]);
|
|
7721
7776
|
if (components.includes("policy")) await handlePolicy(["use", "analyst"]);
|
|
7722
7777
|
if (components.includes("archive")) await ensureArchiveTool({ install: true });
|
|
@@ -7758,6 +7813,7 @@ async function chooseOnboardComponents(status = null) {
|
|
|
7758
7813
|
const componentStatus = status || await getOnboardComponentStatus();
|
|
7759
7814
|
console.log("");
|
|
7760
7815
|
console.log("Выберите компоненты через запятую:");
|
|
7816
|
+
console.log("0. выход в CLI [без настройки] - пропустить мастер");
|
|
7761
7817
|
for (const item of onboardComponentRows(componentStatus)) {
|
|
7762
7818
|
console.log(`${item.number}. ${item.title} [${item.status}] - ${item.hint}`);
|
|
7763
7819
|
}
|
|
@@ -7765,7 +7821,8 @@ async function chooseOnboardComponents(status = null) {
|
|
|
7765
7821
|
const rl = readline.createInterface({ input, output });
|
|
7766
7822
|
try {
|
|
7767
7823
|
const defaults = defaultOnboardSelection(componentStatus);
|
|
7768
|
-
const answer = (await rl.question(`Компоненты [${defaults.join(",")}]: `)).trim() || defaults.join(",");
|
|
7824
|
+
const answer = (await rl.question(`Компоненты [${defaults.join(",")}], 0 - выход в CLI: `)).trim() || defaults.join(",");
|
|
7825
|
+
if (isOnboardExitAnswer(answer)) return [];
|
|
7769
7826
|
const selected = new Set(answer.split(/[,\s]+/).filter(Boolean));
|
|
7770
7827
|
const map = {
|
|
7771
7828
|
1: "workspace",
|
|
@@ -7786,6 +7843,10 @@ async function chooseOnboardComponents(status = null) {
|
|
|
7786
7843
|
}
|
|
7787
7844
|
}
|
|
7788
7845
|
|
|
7846
|
+
function isOnboardExitAnswer(answer) {
|
|
7847
|
+
return /^(0|q|quit|exit|\/exit|skip|пропустить|выход)$/iu.test(String(answer || "").trim());
|
|
7848
|
+
}
|
|
7849
|
+
|
|
7789
7850
|
async function getOnboardComponentStatus() {
|
|
7790
7851
|
const [config, readiness, browser, archive, codexVersion, ollamaVersion] = await Promise.all([
|
|
7791
7852
|
loadConfig(),
|