zaytsv-bot-graph-mcp 0.7.1 → 0.7.3

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zaytsv-bot-graph-mcp",
3
- "version": "0.7.1",
3
+ "version": "0.7.3",
4
4
  "description": "MCP server to build and publish Telegram, MAX and Instagram bot funnels/automations in the zaytsv /bots service. Zero dependencies.",
5
5
  "type": "module",
6
6
  "bin": { "zaytsv-bot-graph-mcp": "src/index.mjs" },
@@ -39,10 +39,12 @@
39
39
 
40
40
  #### Instagram (только для IG-ботов)
41
41
  IG-боты не поддерживают команды (`/start`). Вход — через взаимодействие с контентом или директ:
42
- - `TRIGGER_IG_DM` — `{ "isRoot": true }` — входящее сообщение в Instagram Direct. Это дефолтный триггер нового IG-графа (бэкенд сеет его при создании).
43
- - `TRIGGER_IG_COMMENT` — `{ "isRoot": true }` — комментарий к посту или Reel бота. Опционально: фильтрация по ключевому слову (поддерживается бэкендом, уточни у пользователя, если нужно).
44
- - `TRIGGER_IG_STORY_REPLY` — `{ "isRoot": true }` — ответ на историю бота.
45
- - `TRIGGER_IG_STORY_MENTION` — `{ "isRoot": true }` — упоминание бота в истории подписчика.
42
+ - `TRIGGER_IG_DM` — `{ "isRoot": true, "keywords": "хочу, каталог" }` — входящее сообщение в Instagram Direct. Это дефолтный триггер нового IG-графа (бэкенд сеет его при создании). `keywords` (опц.) — список через запятую или с новой строки; **регистронезависимо, совпадение по вхождению (contains)**; пусто = любое сообщение.
43
+ - `TRIGGER_IG_COMMENT` — `{ "isRoot": true, "keywords": "купить, цена" }` — комментарий к посту или Reel бота. `keywords` (опц.) список через запятую или с новой строки; регистронезависимый contains; пусто = любой комментарий.
44
+ - `TRIGGER_IG_STORY_REPLY` — `{ "isRoot": true, "keywords": "хочу, вопрос" }` — ответ на историю бота. `keywords` (опц.) — список через запятую или с новой строки; регистронезависимый contains; пусто = любой ответ.
45
+ - `TRIGGER_IG_STORY_MENTION` — `{ "isRoot": true }` — упоминание бота в истории подписчика. **Текста нет → фильтрация по ключевым словам не применяется**; срабатывает на каждое упоминание независимо от содержимого истории.
46
+
47
+ > **Разные слова — разные сценарии:** добавь **несколько триггеров одного типа** с разными `keywords`; бэкенд берёт **первый совпавший по порядку узлов**. Триггер-«ловушку» с пустыми `keywords` (ловит всё) ставь **последним** — иначе он заблокирует все нижестоящие ключевые слова.
46
48
 
47
49
  Для всех IG-триггеров реакция бота отправляется через Instagram Messaging API в течение **24-часового окна** после последнего входящего действия пользователя.
48
50
 
@@ -60,7 +62,8 @@ IG-боты не поддерживают команды (`/start`). Вход
60
62
  - **Кнопки-ссылки (`kind:"URL"`)**: `value` = URL. Могут иметь `"track": true` — клики считаются, и на такой шаг можно сослаться из условия `LINK_CLICKED` (см. ниже).
61
63
  - **`color`** (опционально, и у CALLBACK, и у URL) — только стили, которые рендерит Telegram (как в основном боте / pengrad `ButtonStyle`): `""`=по умолчанию, `"#2EA6FF"`=primary (синий), `"#34C759"`=success (зелёный), `"#FF3B30"`=danger (красный). Других цветов нет.
62
64
  - **Режим «Вопрос» (`awaitReply: true`)** — сообщение задаёт вопрос и ждёт ответ (паркуется как `ASK_QUESTION`). Доп. поля: `"saveTo":"name"` (обязателен, `[a-z_][a-z0-9_]{0,63}`), `"inputKind":"TEXT"|"PHOTO"|"DOCUMENT"|"CONTACT"|"LOCATION"`, `"validator":"ANY"|"PHONE"|"EMAIL"|"REGEX"`, `"regex":"..."`, `"retryText":"..."`, `"maxAttempts":3`. Выходы — `valid` / `invalid` (как у `ASK_QUESTION`), плюс `btn_N` для кнопок.
63
- - `SEND_PHOTO` — `{ "photoUrl": "https://...", "caption": "подпись (необязательно, ≤1024)" }`
65
+ - **Канал ответа Instagram (`igReplyChannel`, только для IG-ботов)** — `"comment"` (по умолчанию) — публичный ответ под комментарием; `"dm"` — личное сообщение автору комментария (Private Reply). `"dm"` срабатывает только в графе с `TRIGGER_IG_COMMENT` (нужен `comment_id`): Meta разрешает **1 ЛС на комментарий**, 24-часовое окно на private reply не распространяется. Чтобы ответить и публично, и в ЛС — поставь два шага: один с `"igReplyChannel":"comment"`, второй с `"igReplyChannel":"dm"`.
66
+ - `SEND_PHOTO` — `{ "photoUrl": "https://...", "caption": "подпись (необязательно, ≤1024)", "igReplyChannel": "comment"|"dm" }` (`igReplyChannel` — только IG, см. `SEND_MESSAGE`)
64
67
 
65
68
  ### Логика / ветвление
66
69
  - `CONDITION` — проверка условий, выходы `yes` / `no`. `{ "match":"ALL"|"ANY", "conditions":[ { "kind":"...", "op":"...", "key":"...", "value":"..." } ] }`. `match:"ALL"` — все условия истинны; `"ANY"` — хотя бы одно. Полный список `kind`/`op`/полей — в разделе [«Условия CONDITION»](#условия-condition).
@@ -146,6 +149,7 @@ IG-боты подключаются через OAuth в разделе **«Ин
146
149
  - **`ASK_QUESTION`** — `inputKind` ограничен: только `TEXT`, `EMAIL`, `PHONE`, `NUMBER` (`IG_INPUT_UNSUPPORTED`). Нельзя запрашивать `CONTACT` (кнопка «Поделиться номером» недоступна в IG), `LOCATION`, `PHOTO`, `DOCUMENT`.
147
150
  - **Нет reply-клавиатур** — кнопки IG работают как inline (URL или Deep Link); стиль кнопок ограничен возможностями IG Messaging API.
148
151
  - **Нет SUBSCRIBED** — условие «подписан на канал» недоступно.
152
+ - **Коммент → ЛС (Private Reply)** — на `SEND_MESSAGE`/`SEND_PHOTO` в графе с `TRIGGER_IG_COMMENT` укажи `"igReplyChannel": "dm"`, чтобы ответить автору комментария в Direct (а не публично под постом). По умолчанию (`"comment"`) — публичный ответ. Подробнее — `igReplyChannel` в разделе «Сообщения».
149
153
 
150
154
  ### Оффлайн-проверка IG-графа
151
155
 
@@ -89,6 +89,12 @@ Instagram доставляет сообщения только в течение
89
89
 
90
90
  `inputKind == null` (не задан) — допустимо (дефолт = текст).
91
91
 
92
+ ### Фильтрация по ключевым словам (`keywords`) — только информация, не ошибка
93
+
94
+ `TRIGGER_IG_COMMENT`, `TRIGGER_IG_DM`, `TRIGGER_IG_STORY_REPLY` поддерживают опциональное поле `keywords` в config. Значение — произвольная строка (список через запятую или с новой строки). Бэкенд делает **регистронезависимый contains** (вхождение): срабатывает, если входящий текст содержит хотя бы одно из ключевых слов/фраз (по вхождению, без границ слова). Пустое или отсутствующее `keywords` = совпадение с любым событием. Никаких жёстких кодов ошибок для `keywords` нет — любая строка валидна.
95
+
96
+ `TRIGGER_IG_STORY_MENTION` фильтрацию по ключевым словам **не поддерживает**: Instagram не передаёт текст упоминания боту, поэтому `keywords` игнорируется (валидатор выдаёт предупреждение, не ошибку).
97
+
92
98
  ---
93
99
 
94
100
  ## Локальная проверка
@@ -98,4 +104,4 @@ Instagram доставляет сообщения только в течение
98
104
  ```bash
99
105
  node validate.mjs <import.json> --platform=INSTAGRAM
100
106
  ```
101
- Добавляет проверки `IG_NODE_UNSUPPORTED`, `IG_DELAY_OVER_24H`, `IG_INPUT_UNSUPPORTED` поверх всех обычных.
107
+ Добавляет проверки `IG_NODE_UNSUPPORTED`, `IG_DELAY_OVER_24H`, `IG_INPUT_UNSUPPORTED` поверх всех обычных, а также предупреждение (WARNING) для `TRIGGER_IG_STORY_MENTION` с заполненным `keywords` (поле игнорируется).
@@ -108,6 +108,12 @@ if (broadcast.length && triggers.length > broadcast.length) errors.push("BROADCA
108
108
  for (const n of nodes) {
109
109
  const c = n.config || {};
110
110
  const who = `«${c._title || n.id}» (${n.type})`;
111
+ if (c.igReplyChannel != null && !["comment", "dm"].includes(String(c.igReplyChannel))) {
112
+ warns.push(`${who}: igReplyChannel должен быть "comment" или "dm" (получено "${c.igReplyChannel}")`);
113
+ }
114
+ if (String(c.igReplyChannel) === "dm" && platform !== "INSTAGRAM") {
115
+ warns.push(`${who}: igReplyChannel="dm" учитывается только у Instagram-ботов`);
116
+ }
111
117
  switch (n.type) {
112
118
  case "SEND_MESSAGE": {
113
119
  const flat = !blank(c.text) || !blank(c.photoUrl);
@@ -353,6 +359,11 @@ if (platform === "INSTAGRAM") {
353
359
  errors.push(`IG_DELAY_OVER_24H: ${who} — задержка больше 24ч недопустима для Instagram (24-часовое окно доставки)`);
354
360
  }
355
361
  }
362
+
363
+ // 4) TRIGGER_IG_STORY_MENTION: keywords игнорируется — текста упоминания нет
364
+ if (type === "TRIGGER_IG_STORY_MENTION" && !blank(c.keywords)) {
365
+ warns.push(`${who}: TRIGGER_IG_STORY_MENTION не фильтруется по ключевым словам (у упоминания нет текста) — keywords игнорируется`);
366
+ }
356
367
  }
357
368
  }
358
369
 
package/src/index.mjs CHANGED
@@ -22,7 +22,7 @@ import os from "node:os";
22
22
  import fs from "node:fs";
23
23
  import path from "node:path";
24
24
 
25
- const VERSION = "0.7.1";
25
+ const VERSION = "0.7.3";
26
26
  const BASE = (process.env.ZAYTSV_BASE_URL || "https://zaytsv.ru").replace(/\/+$/, "");
27
27
  const CONFIG_DIR = path.join(os.homedir(), ".zaytsv-bot-graph");
28
28
  const TOKEN_FILE = path.join(CONFIG_DIR, "token");