@naparnik/mcp 0.10.15 → 0.10.19

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/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # Изменения @naparnik/mcp
2
2
 
3
+ ## 0.10.19 — 2026-09-23. Шумодав голоса ставится сам
4
+
5
+ Вместе с движком расширение теперь ставит шумодав голоса — одну программу
6
+ на 27–39 МБ. Отдельно соглашаться не нужно: хватает «да» на сам движок. Если
7
+ шумодав не скачался, движок всё равно включится, а вы увидите одну строку,
8
+ как поставить его отдельно.
9
+
10
+ ## 0.10.18 — 2026-09-23. Для вас ничего не поменялось
11
+
12
+ В пояснениях расширения поправлено, откуда оно берёт шаги установки и место
13
+ портативного Python. Монтаж идёт как раньше.
14
+
15
+ ## 0.10.17 — 2026-09-23. Для вас ничего не поменялось
16
+
17
+ Внутри движка форма выбора, проверки, каталог умений, командная строка и
18
+ общий код монтажа разложены по своим папкам, и в пояснениях расширения
19
+ поправлены ссылки на них. Монтаж идёт как раньше, только первый после
20
+ обновления — дольше обычного, один раз.
21
+
22
+ ## 0.10.16 — 2026-09-23. Для вас ничего не поменялось
23
+
24
+ Внутри движка стиль, звук, герой, запись экрана и установка разложены по своим
25
+ папкам, и в пояснениях расширения поправлены ссылки на них. Монтаж идёт как
26
+ раньше, только первый после обновления — дольше обычного, один раз.
27
+
3
28
  ## 0.10.15 — 2026-09-23. Для вас ничего не поменялось
4
29
 
5
30
  Внутри движка файлы разложены по папкам, и в пояснениях расширения поправлены
package/README.md CHANGED
@@ -227,7 +227,7 @@ Desktop подставляет незаполненное поле настро
227
227
  портативная сборка в `<дом>/bin/python` → системный. Список мест внутри
228
228
  портативной сборки существует в двух копиях (иначе питон не найти, не имея
229
229
  питона) и сверяется тестом `src/engine.test.ts`, который читает
230
- `client/engine/env.py`.
230
+ `client/engine/media/ffmpeg.py`.
231
231
 
232
232
  ## Оболочка и начинка обновляются порознь
233
233
 
@@ -720,9 +720,9 @@ function parsePositiveInt(raw, fallback) {
720
720
  }
721
721
 
722
722
  // src/version.ts
723
- var VERSION = "0.10.15";
723
+ var VERSION = "0.10.19";
724
724
  var USER_AGENT = `naparnik-mcp/${VERSION}`;
725
- var MIN_ENGINE = "2026.09.19-355";
725
+ var MIN_ENGINE = "2026.09.23-406";
726
726
  var LAUNCHER_PROTOCOL = 1;
727
727
 
728
728
  // src/contracts/sdk-headers.ts
@@ -1155,7 +1155,7 @@ var LONG_STEPS = /* @__PURE__ */ new Set([
1155
1155
  "model",
1156
1156
  // ⚠ Распознавание речи, вырез героя и чистка голоса весят вместе больше
1157
1157
  // двух гигабайт, и с 2026-09-10 НИ ОДИН из них не входит в `all` (решение
1158
- // владельца, `install.py`, `SEPARATE_JOBS`). Зовут их поимённо и по просьбе,
1158
+ // владельца, `setup/install.py`, `SEPARATE_JOBS`). Зовут их поимённо и по просьбе,
1159
1159
  // а ждать по ним столько же, сколько раньше ждали модель речи.
1160
1160
  "cutout",
1161
1161
  "voice",
@@ -14253,12 +14253,39 @@ ${describeFailure(trouble)}`
14253
14253
  "current \u0438\u0437\u043C\u0435\u043D\u0438\u043B\u0441\u044F \u043D\u0435\u043F\u043E\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043D\u043D\u043E \u043F\u0435\u0440\u0435\u0434 \u043F\u0435\u0440\u0435\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u0435\u043C \u2014 \u043D\u0438\u0447\u0435\u0433\u043E \u043D\u0435 \u0437\u0430\u0442\u0438\u0440\u0430\u043B. \u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C: \u043F\u043E\u0432\u0442\u043E\u0440\u0438\u0442\u0435 setup."
14254
14254
  );
14255
14255
  }
14256
+ const cleaner = await installVoiceCleaner(engine, dir, checked.version, python, finalPlace);
14256
14257
  return {
14257
14258
  ok: true,
14258
14259
  text: `\u041A\u0430\u043D\u0434\u0438\u0434\u0430\u0442 ${manifest.version}: prepared \u2192 ready \u2192 current.
14259
- \u041F\u0440\u0435\u0436\u043D\u044F\u044F \u0432\u0435\u0440\u0441\u0438\u044F: ${checked.baseCurrent ?? "\u043D\u0435\u0442"}; \u0435\u0451 \u0444\u0430\u0439\u043B\u044B \u0438 \u043E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u0435 \u0441\u043E\u0445\u0440\u0430\u043D\u0435\u043D\u044B.`
14260
+ \u041F\u0440\u0435\u0436\u043D\u044F\u044F \u0432\u0435\u0440\u0441\u0438\u044F: ${checked.baseCurrent ?? "\u043D\u0435\u0442"}; \u0435\u0451 \u0444\u0430\u0439\u043B\u044B \u0438 \u043E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u0435 \u0441\u043E\u0445\u0440\u0430\u043D\u0435\u043D\u044B.` + (cleaner === "" ? "" : `
14261
+ ${cleaner}`)
14260
14262
  };
14261
14263
  }
14264
+ var VOICE_CLEANER_SINCE = "2026.09.23-406";
14265
+ var VOICE_CLEANER_NOTE = "\u0412\u043C\u0435\u0441\u0442\u0435 \u0441 \u0434\u0432\u0438\u0436\u043A\u043E\u043C \u0432\u0441\u0442\u0430\u043D\u0435\u0442 \u0448\u0443\u043C\u043E\u0434\u0430\u0432 \u0433\u043E\u043B\u043E\u0441\u0430 \u2014 \u0435\u0449\u0451 \u043E\u043A\u043E\u043B\u043E 30 \u041C\u0411 \u0441 GitHub.";
14266
+ async function installVoiceCleaner(engine, dir, version2, python, place) {
14267
+ if (compare(version2, VOICE_CLEANER_SINCE) < 0) return "";
14268
+ try {
14269
+ await runCandidateWith(
14270
+ engine,
14271
+ dir,
14272
+ version2,
14273
+ python,
14274
+ place,
14275
+ ["env-install", "--pack", place.pack, "--step", "voice", "--consent"],
14276
+ { timeout: 30 * 6e4 }
14277
+ );
14278
+ return "";
14279
+ } catch (trouble) {
14280
+ return `\u0428\u0443\u043C\u043E\u0434\u0430\u0432 \u0433\u043E\u043B\u043E\u0441\u0430 \u043D\u0435 \u0432\u0441\u0442\u0430\u043B: ${voiceTrouble(trouble)}. \u0414\u0432\u0438\u0436\u043E\u043A \u0432\u043A\u043B\u044E\u0447\u0451\u043D \u0438 \u043C\u043E\u043D\u0442\u0438\u0440\u0443\u0435\u0442; \u043F\u043E\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u0448\u0443\u043C\u043E\u0434\u0430\u0432 \u043E\u0442\u0434\u0435\u043B\u044C\u043D\u043E \u2014 setup \u0441 what=voice.`;
14281
+ }
14282
+ }
14283
+ function voiceTrouble(trouble) {
14284
+ const said = trouble?.stdout;
14285
+ const line = typeof said === "string" ? said.split("\n").map((one) => one.trim()).find((one) => one.startsWith("\u0428\u0430\u0433 \xABvoice\xBB:")) : void 0;
14286
+ const why = (line ?? describeFailure(trouble)).replace(/^Шаг «voice»:\s*/, "");
14287
+ return why.split("\n")[0].slice(0, 300);
14288
+ }
14262
14289
  async function dryRun(engine, build, expected, trial) {
14263
14290
  const consolePy = join(build, "engine", "console.py");
14264
14291
  if (!existsSync(consolePy)) return `\u0432 \u0440\u0430\u0441\u043F\u0430\u043A\u043E\u0432\u0430\u043D\u043D\u043E\u043C \u0430\u0440\u0445\u0438\u0432\u0435 \u043D\u0435\u0442 ${consolePy}`;
@@ -15133,6 +15160,7 @@ async function installPayload(engine, opts, hooks = {}) {
15133
15160
  ok: false,
15134
15161
  text: `\u0414\u0432\u0438\u0436\u043A\u0430 \u043C\u043E\u043D\u0442\u0430\u0436\u0430 \u043D\u0430 \u044D\u0442\u043E\u0439 \u043C\u0430\u0448\u0438\u043D\u0435 \u043D\u0435\u0442 \u2014 \u043D\u0430\u0447\u0438\u043D\u043A\u0443 \u043D\u0430\u0434\u043E \u0441\u043A\u0430\u0447\u0430\u0442\u044C (${mb} \u041C\u0411, \u0432\u0435\u0440\u0441\u0438\u044F ${manifest.version}).
15135
15162
  \u041B\u044F\u0436\u0435\u0442 \u043E\u0434\u043D\u043E\u0439 \u043F\u0430\u043F\u043A\u043E\u0439 \u0432 ${engine.versionsDir()}; \u0432 \u0441\u0438\u0441\u0442\u0435\u043C\u0443 \u043D\u0438\u0447\u0435\u0433\u043E \u043D\u0435 \u0441\u0442\u0430\u0432\u0438\u0442\u0441\u044F.
15163
+ ${VOICE_CLEANER_NOTE}
15136
15164
  \u0421\u043F\u0440\u043E\u0441\u0438 \u0443 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043D\u0438\u0435 \u0438 \u043F\u043E\u0437\u043E\u0432\u0438 setup \u0435\u0449\u0451 \u0440\u0430\u0437 \u0441 consent=true.`
15137
15165
  };
15138
15166
  }
@@ -16679,6 +16707,7 @@ async function updateEngine(engine, consent, key, baseUrl, timeoutMs = ASKED_POI
16679
16707
  const mb = (decision.manifest.bytes / 1024 / 1024).toFixed(1);
16680
16708
  return toolSuccess(
16681
16709
  `\u0415\u0441\u0442\u044C \u043D\u043E\u0432\u0430\u044F \u043D\u0430\u0447\u0438\u043D\u043A\u0430: ${engine.freshVersion() ?? "\u043D\u0435\u0442"} \u2192 ${decision.manifest.version}, ${mb} \u041C\u0411.
16710
+ ${VOICE_CLEANER_NOTE}
16682
16711
  \u0421\u043F\u0440\u043E\u0441\u0438 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430, \u043A\u0430\u0447\u0430\u0442\u044C \u043B\u0438 \u2014 \u044D\u0442\u043E \u0435\u0433\u043E \u0442\u0440\u0430\u0444\u0438\u043A \u0438 \u0435\u0433\u043E \u0434\u0438\u0441\u043A. \u0421\u043E\u0433\u043B\u0430\u0441\u0438\u043B\u0441\u044F \u2014 \u0437\u043E\u0432\u0438 setup \u0441 what=engine \u0438 consent=true.`
16683
16712
  );
16684
16713
  }
@@ -17195,7 +17224,7 @@ function planTool(engine, key) {
17195
17224
  "\u041F\u0430\u043F\u043A\u0430 \u043F\u0430\u043A\u0430 \u0444\u0438\u0440\u043C\u0435\u043D\u043D\u043E\u0433\u043E \u0441\u0442\u0438\u043B\u044F: \u0447\u0435\u0440\u043D\u043E\u0432\u0438\u043A \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044F \u0442\u0430\u043A, \u043A\u0430\u043A \u0435\u0433\u043E \u043F\u043E\u0442\u043E\u043C \u0441\u043E\u0431\u0435\u0440\u0443\u0442"
17196
17225
  ).optional(),
17197
17226
  // ⚠ ТАБЛИЦЫ ВКУСА НАЗВАНЫ ПРИМЕРОМ НАРОЧНО. Дверь к ним открыта движком
17198
- // (`engine/skills.py`, корень `taste`), но модель о них не узнает ниоткуда:
17227
+ // (`engine/catalog/handbook.py`, корень `taste`), но модель о них не узнает ниоткуда:
17199
17228
  // черновик называет их не всегда, а решение владельца 2026-09-18 разрешило
17200
17229
  // ей писать план ролика целиком — и числа для него она обязана брать из
17201
17230
  // наших замеров, а не из головы. Про «по одной-две за вызов» сказано тут
@@ -18762,7 +18791,7 @@ function chooseWidgetHtml() {
18762
18791
  \u0412\u042B\u0421\u041E\u0422\u042B \u0421\u0410\u041C\u041E\u0419 \u0420\u0410\u041C\u041A\u0418, \u2014 \u0430 \u0440\u0430\u043C\u043A\u0430 \u043E\u0431\u044A\u044F\u0432\u043B\u0435\u043D\u0430 \u043C\u0435\u0440\u043D\u044B\u043C \u044F\u0449\u0438\u043A\u043E\u043C (container-type).
18763
18792
  \u041F\u0440\u043E\u0446\u0435\u043D\u0442\u044B \u043E\u0442 \u0448\u0438\u0440\u0438\u043D\u044B \u0442\u0443\u0442 \u043D\u0435 \u0433\u043E\u0434\u044F\u0442\u0441\u044F: \u043A\u0430\u0434\u0440 9:16, \u0438 \u043F\u043E \u0433\u043E\u0440\u0438\u0437\u043E\u043D\u0442\u0430\u043B\u0438 \u0441
18764
18793
  \u0432\u0435\u0440\u0442\u0438\u043A\u0430\u043B\u044C\u044E \u043E\u043D\u0438 \u0440\u0430\u0437\u043D\u044B\u0435.
18765
- \u26A0 \u0422\u0415\u041D\u042C, \u0410 \u041D\u0415 \u041E\u0411\u0412\u041E\u0414\u041A\u0410: \u0432 \u0440\u043E\u043B\u0438\u043A\u0435 \u043F\u043E\u0434 \u0441\u0442\u0440\u043E\u043A\u043E\u0439 \u043C\u044F\u0433\u043A\u0438\u0439 \u043E\u0440\u0435\u043E\u043B (engine/halo.py),
18794
+ \u26A0 \u0422\u0415\u041D\u042C, \u0410 \u041D\u0415 \u041E\u0411\u0412\u041E\u0414\u041A\u0410: \u0432 \u0440\u043E\u043B\u0438\u043A\u0435 \u043F\u043E\u0434 \u0441\u0442\u0440\u043E\u043A\u043E\u0439 \u043C\u044F\u0433\u043A\u0438\u0439 \u043E\u0440\u0435\u043E\u043B (engine/look/halo.py),
18766
18795
  \u0438 \u043F\u0440\u0435\u0432\u044C\u044E \u043E\u0431\u044F\u0437\u0430\u043D\u043E \u043F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0442\u044C \u0442\u043E \u0436\u0435 \u2014 \u043E\u0431\u0432\u043E\u0434\u043A\u0430 \u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044F \u043A\u0430\u043A \u0441\u0430\u043C\u043E\u0434\u0435\u043B\u043A\u0430. */
18767
18796
  .stage__frame { container-type: size; }
18768
18797
  /* \u26A0 \u0425\u041E\u041B\u0421\u0422 \u041B\u041E\u0416\u0418\u0422\u0421\u042F \u041F\u041E\u0412\u0415\u0420\u0425 \u041A\u0410\u0414\u0420\u0410, \u0410 \u041D\u0415 \u0412\u041C\u0415\u0421\u0422\u041E \u041D\u0415\u0413\u041E. \u041F\u043E\u043A\u0430 \u0444\u0438\u043B\u044C\u0442\u0440 \u043D\u0435 \u0432\u044B\u0431\u0440\u0430\u043D \u0438
@@ -18791,7 +18820,7 @@ function chooseWidgetHtml() {
18791
18820
  line-height: 1;
18792
18821
  /* \u26A0 \u0422\u0415\u041D\u042C \u041C\u042F\u0413\u041A\u0410\u042F \u0418 \u041F\u041E\u0427\u0422\u0418 \u041F\u0420\u041E\u0417\u0420\u0410\u0427\u041D\u0410\u042F, \u0410 \u041D\u0415 \u041E\u0411\u0412\u041E\u0414\u041A\u0410 \u041F\u041E\u0414 \u0412\u0418\u0414\u041E\u041C \u0422\u0415\u041D\u0418. \u041F\u043B\u043E\u0442\u043D\u044B\u0435
18793
18822
  \u0441\u043B\u043E\u0438 \u0447\u0438\u0442\u0430\u043B\u0438\u0441\u044C \u043A\u0430\u043A \u043A\u043E\u043D\u0442\u0443\u0440 \u0432\u043E\u043A\u0440\u0443\u0433 \u0431\u0443\u043A\u0432 \u2014 \u0440\u043E\u0432\u043D\u043E \u0442\u043E, \u0447\u0435\u0433\u043E \u0432 \u0440\u043E\u043B\u0438\u043A\u0435 \u043D\u0435\u0442:
18794
- \u0434\u0432\u0438\u0436\u043E\u043A \u043A\u043B\u0430\u0434\u0451\u0442 \u0447\u0435\u0442\u044B\u0440\u0435 \u0440\u0430\u0437\u043C\u044B\u0442\u044B\u0445 \u0441\u043B\u043E\u044F \u0441 \u043C\u0430\u043B\u043E\u0439 \u0441\u0438\u043B\u043E\u0439 (engine/halo.py).
18823
+ \u0434\u0432\u0438\u0436\u043E\u043A \u043A\u043B\u0430\u0434\u0451\u0442 \u0447\u0435\u0442\u044B\u0440\u0435 \u0440\u0430\u0437\u043C\u044B\u0442\u044B\u0445 \u0441\u043B\u043E\u044F \u0441 \u043C\u0430\u043B\u043E\u0439 \u0441\u0438\u043B\u043E\u0439 (engine/look/halo.py).
18795
18824
  \u041F\u0440\u0430\u0432\u043B\u0435\u043D\u043E \u0434\u0432\u0430\u0436\u0434\u044B \u043F\u043E \u043E\u0442\u0431\u0440\u0430\u043A\u043E\u0432\u043A\u0435 \u0432\u043B\u0430\u0434\u0435\u043B\u044C\u0446\u0430 (2026-09-13 \u0438 2026-09-15:
18796
18825
  \xAB\u0442\u0435\u043D\u0438 \u0441\u043B\u0438\u0448\u043A\u043E\u043C \u0437\u0430\u043C\u0435\u0442\u043D\u044B\u0435, \u043D\u0430\u0434\u043E \u0431\u043E\u043B\u044C\u0448\u0435 \u043F\u0440\u043E\u0437\u0440\u0430\u0447\u043D\u043E\u0441\u0442\u0438\xBB). */
18797
18826
  text-shadow:
@@ -19656,7 +19685,7 @@ function chooseWidgetHtml() {
19656
19685
  }
19657
19686
 
19658
19687
  // \u0421\u043B\u0443\u0436\u0435\u0431\u043D\u044B\u0435 \u0441\u043B\u043E\u0432\u0430 \u0433\u043B\u0430\u0432\u043D\u044B\u043C\u0438 \u043D\u0435 \u0431\u044B\u0432\u0430\u044E\u0442 \u2014 \u0442\u043E \u0436\u0435 \u043F\u0440\u0430\u0432\u0438\u043B\u043E, \u0447\u0442\u043E \u0432 \u0434\u0432\u0438\u0436\u043A\u0435
19659
- // (lib/layout.py \u0432 \u043F\u0430\u043A\u0435): \xAB\u0427\u0422\u041E\u0411\u042B\xBB \u0432\u043E \u0432\u0435\u0441\u044C \u043A\u0430\u0434\u0440 \u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044F \u043A\u0430\u043A \u043E\u0448\u0438\u0431\u043A\u0430 \u0432\u0451\u0440\u0441\u0442\u043A\u0438.
19688
+ // (lib/captions/layout.py \u0432 \u043F\u0430\u043A\u0435): \xAB\u0427\u0422\u041E\u0411\u042B\xBB \u0432\u043E \u0432\u0435\u0441\u044C \u043A\u0430\u0434\u0440 \u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044F \u043A\u0430\u043A \u043E\u0448\u0438\u0431\u043A\u0430 \u0432\u0451\u0440\u0441\u0442\u043A\u0438.
19660
19689
  var SMALL_WORDS = (' \u0430 \u043D\u043E \u0438 \u0438\u043B\u0438 \u0434\u0430 \u0436\u0435 \u043B\u0438 \u0431\u044B \u043D\u0435 \u043D\u0438 \u0432 \u0432\u043E \u043D\u0430 \u0437\u0430 \u043D\u0430\u0434 \u043F\u043E\u0434 \u043E\u0442 \u0434\u043E \u043F\u043E \u0438\u0437 \u0443 \u043A \u0441 \u0441\u043E \u043E \u043E\u0431 '
19661
19690
  + '\u043F\u0440\u043E \u0434\u043B\u044F \u043F\u0440\u0438 \u0431\u0435\u0437 \u0447\u0435\u0440\u0435\u0437 \u043C\u0435\u0436\u0434\u0443 \u0442\u043E \u0442\u043E\u0442 \u0442\u0430 \u0442\u0435 \u044D\u0442\u043E \u044D\u0442\u0438 \u044D\u0442\u043E\u0442 \u043A\u0430\u043A \u0447\u0442\u043E \u0447\u0435\u043C \u0447\u0442\u043E\u0431\u044B \u0435\u0441\u043B\u0438 \u043A\u043E\u0433\u0434\u0430 \u0433\u0434\u0435 '
19662
19691
  + '\u0442\u0430\u043C \u0442\u0443\u0442 \u0443\u0436\u0435 \u0435\u0449\u0451 \u0435\u0449\u0435 \u0432\u043E\u0442 \u0442\u0430\u043A \u0432\u044B \u0442\u044B \u043C\u044B \u043E\u043D \u043E\u043D\u0430 \u043E\u043D\u0438 \u044F \u043C\u043D\u0435 \u0442\u0435\u0431\u0435 ').split(' ');
package/dist/cli.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { Engine, chooseBody, handOverToBody, VERSION, rollback, rollbackShell, remove, fromNpxCache, install, keyFromBlock, readConfig, ForeignBlockError, currentMachineFingerprint, McpServer, buildAll, buildResources, StdioServerTransport, fromHost, WHERE_TO_GET_KEY, updateEngine, installStep, NaparnikApiClient, timeToCheck2, manifestUrlFor, fetchManifest, markChecked2, decide, shellDir, timeToCheck, bundleUrlFor, fetchShellManifest, markChecked, decideShell, installedShell, NaparnikConfigError } from './chunk-ZXASWNOE.js';
2
+ import { Engine, chooseBody, handOverToBody, VERSION, rollback, rollbackShell, remove, fromNpxCache, install, keyFromBlock, readConfig, ForeignBlockError, currentMachineFingerprint, McpServer, buildAll, buildResources, StdioServerTransport, fromHost, WHERE_TO_GET_KEY, updateEngine, installStep, NaparnikApiClient, timeToCheck2, manifestUrlFor, fetchManifest, markChecked2, decide, shellDir, timeToCheck, bundleUrlFor, fetchShellManifest, markChecked, decideShell, installedShell, NaparnikConfigError } from './chunk-4WX5APDI.js';
3
3
  import { fileURLToPath } from 'url';
4
4
  import { realpathSync, readFileSync } from 'fs';
5
5
 
package/dist/index.d.ts CHANGED
@@ -122,12 +122,13 @@ declare class NaparnikApiClient {
122
122
  /**
123
123
  * Где внутри распакованной портативной сборки лежит сам интерпретатор.
124
124
  *
125
- * ⚠ ТРИ ВАРИАНТА, А НЕ ДВА, И РОВНО ТЕ ЖЕ, ЧТО У ДВИЖКА
126
- * (`engine/env.py` → `_INSIDE_PYTHON`). Копия здесь неизбежна — питон мы
125
+ * ⚠ ТРИ ВАРИАНТА, А НЕ ДВА, И РОВНО ТЕ ЖЕ, ЧТО У ДВИЖКА. Источник правды —
126
+ * `engine/shell-contract.json` → `portable_python.inside`: оттуда их берёт и
127
+ * питон (`engine/setup/python_finder.py`). Копия здесь неизбежна — питон мы
127
128
  * ищем ДО того, как есть чем запустить питон, — но прошлая копия знала два
128
129
  * варианта из трёх: на сборке, где внутри лежит только `bin/python`, движок
129
- * питон видел, а сервер MCP нет. Обе стороны сверяет тест границы
130
- * (`engine.test.ts`), и он читает питоновский исходник, а не повторяет список.
130
+ * питон видел, а сервер MCP нет. Правится сначала JSON, потом сюда; расхождение
131
+ * ловит тест границы (`engine.test.ts`) сверкой с этим JSON.
131
132
  */
132
133
  declare const INSIDE_PYTHON: string[];
133
134
  /** Дом по умолчанию — ровно тот же литерал, что в `engine/kit/home.py`. */
@@ -146,12 +147,13 @@ declare const LONG_STEPS: Set<string>;
146
147
  /**
147
148
  * Все шаги установки, которые понимает движок.
148
149
  *
149
- * ⚠ ЭТО ЗЕРКАЛО `install.py` → `STEPS`, и оно уже один раз разошлось: движок печатал
150
+ * ⚠ ЭТО ЗЕРКАЛО `STEPS` движка, и оно уже один раз разошлось: движок печатал
150
151
  * «Шаг установки „вырез“», а здешний список о таком шаге не знал — клиент
151
152
  * оказывался в тупике, потому что инструмент не принимал значение, которое
152
- * движок сам же и назвал. Правится сверху вниз: сначала `install.py` → `STEPS`,
153
- * потом сюда. Расхождение сторожит `engine.test.ts` — он читает питоновский
154
- * исходник, а не повторяет список.
153
+ * движок сам же и назвал. Источник правды — `engine/shell-contract.json` →
154
+ * `install_steps`: оттуда `STEPS` берёт и `setup/install.py`. Правится сверху
155
+ * вниз: сначала JSON, потом сюда. Расхождение сторожит `engine.test.ts` сверкой
156
+ * с этим JSON.
155
157
  */
156
158
  declare const INSTALL_STEPS: string[];
157
159
  /**
@@ -162,12 +164,12 @@ declare const INSTALL_STEPS: string[];
162
164
  * прибита строкой "scripts/edit.py".
163
165
  */
164
166
  /**
165
- * ⚠ КЛЮЧИ РУССКИЕ, ПОТОМУ ЧТО ЭТО ОТВЕТ ПИТОНА, А НЕ НАШ ОБЪЕКТ. Паспорт
166
- * печатает движок монтажа (`pack.json` и команда паспорта), и имена полей — его.
167
- * Переименование здесь ничего не меняет на той стороне: оболочка просто
168
- * перестала бы находить поля и объявила бы «паспорт не прочитан» на каждом
169
- * запуске. Обе стороны сверяет тест границы (`engine.test.ts`), и он читает
170
- * питоновский исходник, а не повторяет список.
167
+ * ⚠ ИМЕНА ПОЛЕЙ — ОТВЕТ ПИТОНА, А НЕ НАШ ОБЪЕКТ. Паспорт печатает движок
168
+ * монтажа (`engine/passport.py` → `as_json`, команда `pack-description`), и
169
+ * имена полей — его. Переименование здесь ничего не меняет на той стороне:
170
+ * оболочка просто перестала бы находить поля и объявила бы «паспорт не
171
+ * прочитан» на каждом запуске. Поля, несущие имена, сверяет с настоящими
172
+ * `pack.json` и рецептом `tool-declaration.test.ts`.
171
173
  */
172
174
  interface PackPassport {
173
175
  'name': string;
@@ -1307,9 +1309,9 @@ declare class NaparnikConfigError extends NaparnikError {
1307
1309
  * годится ли она для новой начинки: разойдись она с пакетом, и в логах будет
1308
1310
  * стоять чужое число, а обновление начнёт считать оболочку не той.
1309
1311
  */
1310
- declare const VERSION = "0.10.15";
1312
+ declare const VERSION = "0.10.19";
1311
1313
  /** Как мы представляемся серверу Напарника. По нему в логах видно оболочку. */
1312
- declare const USER_AGENT = "naparnik-mcp/0.10.15";
1314
+ declare const USER_AGENT = "naparnik-mcp/0.10.19";
1313
1315
  /**
1314
1316
  * Самая старая начинка (движок монтажа), с которой эта оболочка работает.
1315
1317
  * Обновление начинки ниже этой версии не ставится, а выше — требует оболочки
@@ -1346,7 +1348,7 @@ declare const USER_AGENT = "naparnik-mcp/0.10.15";
1346
1348
  * словами «раздача ещё не обновилась». Номер берётся из УЖЕ СОБРАННОГО
1347
1349
  * артефакта этой волны, а не сочиняется по календарю.
1348
1350
  */
1349
- declare const MIN_ENGINE = "2026.09.19-355";
1351
+ declare const MIN_ENGINE = "2026.09.23-406";
1350
1352
 
1351
1353
  /**
1352
1354
  * Что вышло из установки или отката — одними словами у начинки и у тела.
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- export { DEFAULT_HOME, DeliveryError, Engine, ForeignBlockError, INSIDE_PYTHON, INSTALL_STEPS, KEEP_COPIES, KEEP_VERSIONS, LONG_STEPS, MANIFEST_TIMEOUT_MS, MANIFEST_URL, MARKER, MIN_ENGINE, NaparnikApiClient, NaparnikAuthError, NaparnikClientError, NaparnikConfigError, NaparnikError, NaparnikInsufficientBalanceError, NaparnikScopeError, NaparnikServerError, NaparnikTimeoutError, PAUSE_HOURS, SERVER_NAME, SOURCES_FILE, START_SEC, TOOL_SEC, USER_AGENT, VERSION, buildAll, buildBlock, buildResources, compare, configPath, decide, defineTool, deploy, downloadFile, fetchManifest, fileOrRefusal, findBlock, fromNpxCache, inside, install, installPayload, installPython, jsonSchemaOf, keyInTable, lastLine, loadConfig, markChecked2 as markChecked, markCurrent, parseEngineManifest, parseFailure, path, platformKey, previousVersion, probe, pythonSource, refusalFor, remove, rollback, tarEntries, tidyOld, timeToCheck2 as timeToCheck, unpackArchive, withArgs } from './chunk-ZXASWNOE.js';
1
+ export { DEFAULT_HOME, DeliveryError, Engine, ForeignBlockError, INSIDE_PYTHON, INSTALL_STEPS, KEEP_COPIES, KEEP_VERSIONS, LONG_STEPS, MANIFEST_TIMEOUT_MS, MANIFEST_URL, MARKER, MIN_ENGINE, NaparnikApiClient, NaparnikAuthError, NaparnikClientError, NaparnikConfigError, NaparnikError, NaparnikInsufficientBalanceError, NaparnikScopeError, NaparnikServerError, NaparnikTimeoutError, PAUSE_HOURS, SERVER_NAME, SOURCES_FILE, START_SEC, TOOL_SEC, USER_AGENT, VERSION, buildAll, buildBlock, buildResources, compare, configPath, decide, defineTool, deploy, downloadFile, fetchManifest, fileOrRefusal, findBlock, fromNpxCache, inside, install, installPayload, installPython, jsonSchemaOf, keyInTable, lastLine, loadConfig, markChecked2 as markChecked, markCurrent, parseEngineManifest, parseFailure, path, platformKey, previousVersion, probe, pythonSource, refusalFor, remove, rollback, tarEntries, tidyOld, timeToCheck2 as timeToCheck, unpackArchive, withArgs } from './chunk-4WX5APDI.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@naparnik/mcp",
3
- "version": "0.10.15",
3
+ "version": "0.10.19",
4
4
  "description": "MCP-сервер Напарника: монтаж вертикального видео на машине пользователя — паузы, субтитры, герой на новом фоне, звук. Видео никуда не уезжает.",
5
5
  "license": "SEE LICENSE IN LICENSE.md",
6
6
  "private": false,