@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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/cli.js +71 -10
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iola_adm/iola-cli",
3
- "version": "0.1.93",
3
+ "version": "0.1.95",
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
@@ -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 showBanner();
632
- console.log("Первый запуск iola-cli. Сейчас откроется мастер настройки.");
633
- console.log("После мастера запустится интерактивный агент.");
634
- console.log("");
635
- await onboard([]);
636
- markFirstRunCompleted();
637
- console.log("");
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 === "get_entity_field" ? "resolve_entity_field" : 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(),