@naparnik/mcp 0.10.18 → 0.10.21

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,28 @@
1
1
  # Изменения @naparnik/mcp
2
2
 
3
+ ## 0.10.21 — 2026-09-23. Первая установка отвечает быстрее
4
+
5
+ Движок встаёт, и монтировать можно сразу. Шумодав голоса и браузер для
6
+ графики докачиваются следом, пока вы работаете. Спросите, всё ли готово, —
7
+ ответ скажет, идёт ли ещё докачка.
8
+
9
+ ## 0.10.20 — 2026-09-23. «Поставь всё» ставит и браузер для графики
10
+
11
+ Установка теперь ставит браузер, которым рисуется графика. Ставится всем,
12
+ тем же заходом, что и остальное. Вес называется до установки, около 150 МБ.
13
+ Пока сборки для вашего компьютера нет, установка так и скажет и пойдёт
14
+ дальше.
15
+
16
+ Шумодав голоса тоже приезжает по «поставь всё». Раньше тот, у кого монтаж уже
17
+ стоял, слышал «ставить нечего» и оставался без него.
18
+
19
+ ## 0.10.19 — 2026-09-23. Шумодав голоса ставится сам
20
+
21
+ Вместе с движком расширение теперь ставит шумодав голоса — одну программу
22
+ на 27–39 МБ. Отдельно соглашаться не нужно: хватает «да» на сам движок. Если
23
+ шумодав не скачался, движок всё равно включится, а вы увидите одну строку,
24
+ как поставить его отдельно.
25
+
3
26
  ## 0.10.18 — 2026-09-23. Для вас ничего не поменялось
4
27
 
5
28
  В пояснениях расширения поправлено, откуда оно берёт шаги установки и место
@@ -720,9 +720,9 @@ function parsePositiveInt(raw, fallback) {
720
720
  }
721
721
 
722
722
  // src/version.ts
723
- var VERSION = "0.10.18";
723
+ var VERSION = "0.10.21";
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
@@ -1159,6 +1159,9 @@ var LONG_STEPS = /* @__PURE__ */ new Set([
1159
1159
  // а ждать по ним столько же, сколько раньше ждали модель речи.
1160
1160
  "cutout",
1161
1161
  "voice",
1162
+ // Браузер для графики — три архива, около 150 МБ сжатым (замер 1.7), и
1163
+ // ставится всем с «all» (решение владельца 2026-09-23).
1164
+ "browser",
1162
1165
  "all"
1163
1166
  ]);
1164
1167
  var INSTALL_STEPS = [
@@ -1169,6 +1172,7 @@ var INSTALL_STEPS = [
1169
1172
  "model",
1170
1173
  "cutout",
1171
1174
  "voice",
1175
+ "browser",
1172
1176
  "all"
1173
1177
  ];
1174
1178
  function montageEnv(base, key) {
@@ -13819,7 +13823,7 @@ function recoverPublicationLocked(dir) {
13819
13823
  }
13820
13824
  clearPublication(dir, publication.operationId);
13821
13825
  }
13822
- async function continuePreparedCandidate(engine, expected, bootstrap, trial = probe) {
13826
+ async function continuePreparedCandidate(engine, expected, bootstrap, trial = probe, extras = "now") {
13823
13827
  try {
13824
13828
  return await withVersionLock(engine.versionsDir(), async () => {
13825
13829
  const checked = preparedCandidateBeforeBootstrap(engine, expected);
@@ -13828,7 +13832,7 @@ async function continuePreparedCandidate(engine, expected, bootstrap, trial = pr
13828
13832
  const after = preparedCandidateAfterBootstrap(engine, checked.candidate);
13829
13833
  if (!after.ok) return after.outcome;
13830
13834
  if (!bootstrapped.ok) return bootstrapped;
13831
- return activatePreparedCandidateLocked(engine, after.candidate, trial);
13835
+ return activatePreparedCandidateLocked(engine, after.candidate, trial, extras);
13832
13836
  });
13833
13837
  } catch (trouble) {
13834
13838
  if (trouble instanceof VersionLockError) return { ok: false, text: trouble.message };
@@ -14048,7 +14052,7 @@ async function compatibilityProof(engine, dir, version2, python, place) {
14048
14052
  return { ok: false, text: `\u0421\u043E\u0432\u043C\u0435\u0441\u0442\u0438\u043C\u043E\u0441\u0442\u044C \u043A\u0430\u043D\u0434\u0438\u0434\u0430\u0442\u0430 \u043D\u0435 \u043F\u0440\u043E\u0432\u0435\u0440\u0435\u043D\u0430 (unknown): ${describeFailure(trouble)}` };
14049
14053
  }
14050
14054
  }
14051
- async function activatePreparedCandidateLocked(engine, manifest, trial) {
14055
+ async function activatePreparedCandidateLocked(engine, manifest, trial, extras = "now") {
14052
14056
  const dir = engine.versionsDir();
14053
14057
  const candidate = readCandidate(dir);
14054
14058
  if (candidate?.version !== manifest.version || candidate.sha256 !== manifest.sha256) {
@@ -14099,7 +14103,15 @@ async function activatePreparedCandidateLocked(engine, manifest, trial) {
14099
14103
  candidate.version,
14100
14104
  engine.bootstrapPython(),
14101
14105
  place,
14102
- ["env-install", "--pack", place.pack, "--step", "env", "--consent"],
14106
+ [
14107
+ "env-install",
14108
+ "--pack",
14109
+ place.pack,
14110
+ "--step",
14111
+ "env",
14112
+ "--consent",
14113
+ ...extras === "later" ? requiredOnly(dir, candidate.version) : []
14114
+ ],
14103
14115
  { timeout: 60 * 6e4 },
14104
14116
  true
14105
14117
  );
@@ -14253,12 +14265,51 @@ ${describeFailure(trouble)}`
14253
14265
  "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
14266
  );
14255
14267
  }
14268
+ const cleaner = extras === "now" ? await installVoiceCleaner(engine, dir, checked.version, python, finalPlace) : "";
14256
14269
  return {
14257
14270
  ok: true,
14258
14271
  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.`
14272
+ \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 === "" ? "" : `
14273
+ ${cleaner}`)
14260
14274
  };
14261
14275
  }
14276
+ var REQUIRED_ONLY = "--required-only";
14277
+ function requiredOnly(dir, version2) {
14278
+ try {
14279
+ const contract = JSON.parse(
14280
+ readFileSync(join(dir, version2, "engine", "shell-contract.json"), "utf8")
14281
+ );
14282
+ const flags = contract.env_install_flags;
14283
+ return Array.isArray(flags) && flags.includes(REQUIRED_ONLY) ? [REQUIRED_ONLY] : [];
14284
+ } catch {
14285
+ return [];
14286
+ }
14287
+ }
14288
+ var VOICE_CLEANER_SINCE = "2026.09.23-406";
14289
+ 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.";
14290
+ async function installVoiceCleaner(engine, dir, version2, python, place) {
14291
+ if (compare(version2, VOICE_CLEANER_SINCE) < 0) return "";
14292
+ try {
14293
+ await runCandidateWith(
14294
+ engine,
14295
+ dir,
14296
+ version2,
14297
+ python,
14298
+ place,
14299
+ ["env-install", "--pack", place.pack, "--step", "voice", "--consent"],
14300
+ { timeout: 30 * 6e4 }
14301
+ );
14302
+ return "";
14303
+ } catch (trouble) {
14304
+ 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.`;
14305
+ }
14306
+ }
14307
+ function voiceTrouble(trouble) {
14308
+ const said = trouble?.stdout;
14309
+ const line = typeof said === "string" ? said.split("\n").map((one) => one.trim()).find((one) => one.startsWith("\u0428\u0430\u0433 \xABvoice\xBB:")) : void 0;
14310
+ const why = (line ?? describeFailure(trouble)).replace(/^Шаг «voice»:\s*/, "");
14311
+ return why.split("\n")[0].slice(0, 300);
14312
+ }
14262
14313
  async function dryRun(engine, build, expected, trial) {
14263
14314
  const consolePy = join(build, "engine", "console.py");
14264
14315
  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 +15184,7 @@ async function installPayload(engine, opts, hooks = {}) {
15133
15184
  ok: false,
15134
15185
  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
15186
  \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.
15187
+ ${VOICE_CLEANER_NOTE}
15136
15188
  \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
15189
  };
15138
15190
  }
@@ -16278,13 +16330,14 @@ var INSTALL_WORDS = {
16278
16330
  env: "\u0441\u043E\u0431\u0435\u0440\u0443 \u043E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u0435 \u043C\u043E\u043D\u0442\u0430\u0436\u0430",
16279
16331
  model: "\u0441\u043A\u0430\u0447\u0430\u044E \u043C\u043E\u0434\u0435\u043B\u044C \u0440\u0430\u0441\u043F\u043E\u0437\u043D\u0430\u0432\u0430\u043D\u0438\u044F \u0440\u0435\u0447\u0438 \u2014 \u043E\u043D\u0430 \u0438\u0437 \u0432\u0441\u0435\u0433\u043E \u0441\u0430\u043C\u0430\u044F \u0442\u044F\u0436\u0451\u043B\u0430\u044F",
16280
16332
  cutout: "\u0441\u043A\u0430\u0447\u0430\u044E \u0442\u043E, \u0447\u0435\u043C \u043E\u0442\u0434\u0435\u043B\u044F\u044E \u0433\u0435\u0440\u043E\u044F \u043E\u0442 \u0444\u043E\u043D\u0430",
16281
- voice: "\u0441\u043A\u0430\u0447\u0430\u044E \u0442\u043E, \u0447\u0435\u043C \u0447\u0438\u0449\u0443 \u0433\u043E\u043B\u043E\u0441"
16333
+ voice: "\u0441\u043A\u0430\u0447\u0430\u044E \u0442\u043E, \u0447\u0435\u043C \u0447\u0438\u0449\u0443 \u0433\u043E\u043B\u043E\u0441",
16334
+ browser: "\u043F\u043E\u0441\u0442\u0430\u0432\u043B\u044E \u0431\u0440\u0430\u0443\u0437\u0435\u0440, \u043A\u043E\u0442\u043E\u0440\u044B\u043C \u0440\u0438\u0441\u0443\u044E \u0433\u0440\u0430\u0444\u0438\u043A\u0443"
16282
16335
  };
16283
16336
  function installLadder(step) {
16284
16337
  if (step === "all") {
16285
16338
  return [
16286
16339
  "\u041F\u0440\u043E\u0432\u0435\u0440\u044E, \u0447\u0435\u0433\u043E \u043D\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442, \u0438 \u0434\u043E\u0441\u0442\u0430\u0432\u043B\u044E \u043F\u043E \u043E\u0447\u0435\u0440\u0435\u0434\u0438.",
16287
- "\u0422\u044F\u0436\u0451\u043B\u043E\u0435 \u0441\u044E\u0434\u0430 \u043D\u0435 \u0432\u0445\u043E\u0434\u0438\u0442: \u0440\u0430\u0441\u043F\u043E\u0437\u043D\u0430\u0432\u0430\u043D\u0438\u0435 \u0440\u0435\u0447\u0438, \u0432\u044B\u0440\u0435\u0437 \u0433\u0435\u0440\u043E\u044F \u0438 \u0447\u0438\u0441\u0442\u043A\u0430 \u0433\u043E\u043B\u043E\u0441\u0430 \u0441\u0442\u0430\u0432\u044F\u0442\u0441\u044F \u043E\u0442\u0434\u0435\u043B\u044C\u043D\u043E \u0438 \u0442\u043E\u043B\u044C\u043A\u043E \u043F\u043E\u0441\u043B\u0435 \xAB\u0434\u0430\xBB \u043E\u0442 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430."
16340
+ "\u0422\u044F\u0436\u0451\u043B\u043E\u0435 \u0441\u044E\u0434\u0430 \u043D\u0435 \u0432\u0445\u043E\u0434\u0438\u0442: \u0440\u0430\u0441\u043F\u043E\u0437\u043D\u0430\u0432\u0430\u043D\u0438\u0435 \u0440\u0435\u0447\u0438 \u0438 \u0432\u044B\u0440\u0435\u0437 \u0433\u0435\u0440\u043E\u044F \u0441\u0442\u0430\u0432\u044F\u0442\u0441\u044F \u043E\u0442\u0434\u0435\u043B\u044C\u043D\u043E \u0438 \u0442\u043E\u043B\u044C\u043A\u043E \u043F\u043E\u0441\u043B\u0435 \xAB\u0434\u0430\xBB \u043E\u0442 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430."
16288
16341
  ];
16289
16342
  }
16290
16343
  const word = INSTALL_WORDS[step];
@@ -16536,6 +16589,7 @@ function nameOrRefusal(candidate) {
16536
16589
  // src/setup-tool.ts
16537
16590
  var ASKED_POINTER_MS = 15e3;
16538
16591
  var NEWS_POINTER_MS = 5e3;
16592
+ var EXTRAS_LATER = "\u041C\u043E\u043D\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0443\u0436\u0435 \u043C\u043E\u0436\u043D\u043E. \u0424\u043E\u043D\u043E\u043C \u0434\u043E\u043A\u0430\u0447\u0438\u0432\u0430\u044E \u0442\u043E, \u0431\u0435\u0437 \u0447\u0435\u0433\u043E \u043C\u043E\u043D\u0442\u0430\u0436 \u0438 \u0442\u0430\u043A \u0438\u0434\u0451\u0442: \u0448\u0443\u043C\u043E\u0434\u0430\u0432 \u0433\u043E\u043B\u043E\u0441\u0430 \u2014 \u043E\u043A\u043E\u043B\u043E 30 \u041C\u0411, \u043A\u0430\u0440\u0442\u0443 \u0433\u0435\u0440\u043E\u044F \u0438 \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u0434\u043B\u044F \u0433\u0440\u0430\u0444\u0438\u043A\u0438 \u2014 \u0434\u043E 150 \u041C\u0411. \u0411\u0440\u0430\u0443\u0437\u0435\u0440 \u043A\u0430\u0447\u0430\u0435\u0442\u0441\u044F, \u0442\u043E\u043B\u044C\u043A\u043E \u0435\u0441\u043B\u0438 \u0435\u0433\u043E \u0441\u0431\u043E\u0440\u043A\u0430 \u0434\u043B\u044F \u044D\u0442\u043E\u0439 \u043C\u0430\u0448\u0438\u043D\u044B \u0443\u0436\u0435 \u0432\u044B\u043B\u043E\u0436\u0435\u043D\u0430: \u0433\u0440\u0430\u0444\u0438\u043A\u0430 \u0432 \u043C\u043E\u043D\u0442\u0430\u0436 \u0435\u0449\u0451 \u043D\u0435 \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D\u0430. \u041D\u0435 \u0434\u043E\u043A\u0430\u0447\u0430\u0435\u0442\u0441\u044F \u2014 \u043C\u043E\u043D\u0442\u0430\u0436 \u043D\u0435 \u0443\u043F\u0430\u0434\u0451\u0442, \u0430 setup \u0441\u043A\u0430\u0436\u0435\u0442 \u0441\u043B\u043E\u0432\u0430\u043C\u0438, \u0447\u0435\u0433\u043E \u043D\u0435\u0442.";
16539
16593
  async function checkSetup(engine, asked) {
16540
16594
  const video = asked.video;
16541
16595
  const model = asked.model;
@@ -16579,6 +16633,7 @@ async function installStep(engine, asked, key, baseUrl, tell) {
16579
16633
  );
16580
16634
  }
16581
16635
  let bootstrapText = "";
16636
+ const extras = step === "all" ? "later" : "now";
16582
16637
  const activated = await continuePreparedCandidate(engine, candidate, async ({ candidate: locked }) => {
16583
16638
  if (await engine.pythonTrouble() === null) {
16584
16639
  return { ok: true, text: "Python \u0443\u0436\u0435 \u0434\u043E\u0441\u0442\u0443\u043F\u0435\u043D; \u043F\u043E\u0432\u0442\u043E\u0440\u043D\u043E \u043D\u0438\u0447\u0435\u0433\u043E \u043D\u0435 \u0441\u043A\u0430\u0447\u0438\u0432\u0430\u043B." };
@@ -16586,7 +16641,7 @@ async function installStep(engine, asked, key, baseUrl, tell) {
16586
16641
  const python2 = await installPythonUnderLock(engine, { consent, version: locked.version });
16587
16642
  bootstrapText = python2.text;
16588
16643
  return python2;
16589
- });
16644
+ }, void 0, extras);
16590
16645
  if (!activated.ok) return toolError(activated.text);
16591
16646
  engine.forgetPlace();
16592
16647
  if (step === "python") {
@@ -16594,10 +16649,19 @@ async function installStep(engine, asked, key, baseUrl, tell) {
16594
16649
  ${activated.text}`.trim());
16595
16650
  }
16596
16651
  if (step === "all") {
16597
- return toolSuccess(
16598
- `${activated.text}
16599
- \u041A\u0430\u043D\u0434\u0438\u0434\u0430\u0442 \u043F\u043E\u0441\u0442\u0430\u0432\u0438\u043B ffmpeg, \u0441\u043E\u0431\u0440\u0430\u043B \u0441\u0432\u043E\u0451 \u043E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u0435 \u0438 \u043F\u0440\u043E\u0448\u0451\u043B env-check. \u0412\u0441\u0451 \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u043E\u0435 \u0433\u043E\u0442\u043E\u0432\u043E.`
16600
- );
16652
+ const ready = `${activated.text}
16653
+ \u041A\u0430\u043D\u0434\u0438\u0434\u0430\u0442 \u043F\u043E\u0441\u0442\u0430\u0432\u0438\u043B ffmpeg, \u0441\u043E\u0431\u0440\u0430\u043B \u0441\u0432\u043E\u0451 \u043E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u0435 \u0438 \u043F\u0440\u043E\u0448\u0451\u043B env-check. \u0412\u0441\u0451 \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u043E\u0435 \u0433\u043E\u0442\u043E\u0432\u043E.`;
16654
+ const later = await installStep(engine, asked, key, baseUrl, tell);
16655
+ if (later.type === "error") {
16656
+ return toolSuccess(
16657
+ `${ready}
16658
+
16659
+ \u041E\u0441\u0442\u0430\u043B\u044C\u043D\u043E\u0435 \u0444\u043E\u043D\u043E\u043C \u0437\u0430\u0432\u0435\u0441\u0442\u0438 \u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C: ${later.error}
16660
+ \u041C\u043E\u043D\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u044D\u0442\u043E \u043D\u0435 \u043C\u0435\u0448\u0430\u0435\u0442. \u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C: \u043F\u043E\u0437\u043E\u0432\u0438 setup \u0441 what=all \u0435\u0449\u0451 \u0440\u0430\u0437.`
16661
+ );
16662
+ }
16663
+ return together([toolSuccess(`${ready}
16664
+ ${EXTRAS_LATER}`), later]);
16601
16665
  }
16602
16666
  }
16603
16667
  if (step === "python" || step === "all") {
@@ -16679,6 +16743,7 @@ async function updateEngine(engine, consent, key, baseUrl, timeoutMs = ASKED_POI
16679
16743
  const mb = (decision.manifest.bytes / 1024 / 1024).toFixed(1);
16680
16744
  return toolSuccess(
16681
16745
  `\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.
16746
+ ${VOICE_CLEANER_NOTE}
16682
16747
  \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
16748
  );
16684
16749
  }
@@ -16830,7 +16895,7 @@ async function installMissing(engine, key, baseUrl, tell) {
16830
16895
  }
16831
16896
  async function nothingMissing(engine, place) {
16832
16897
  try {
16833
- await engine.run(place, ["env-check", "--pack", place.pack]);
16898
+ await engine.run(place, ["env-check", "--pack", place.pack, "--first-install"]);
16834
16899
  return true;
16835
16900
  } catch {
16836
16901
  return false;
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-O7XB7YJ5.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-5DKUJSAN.js';
3
3
  import { fileURLToPath } from 'url';
4
4
  import { realpathSync, readFileSync } from 'fs';
5
5
 
package/dist/index.d.ts CHANGED
@@ -1309,9 +1309,9 @@ declare class NaparnikConfigError extends NaparnikError {
1309
1309
  * годится ли она для новой начинки: разойдись она с пакетом, и в логах будет
1310
1310
  * стоять чужое число, а обновление начнёт считать оболочку не той.
1311
1311
  */
1312
- declare const VERSION = "0.10.18";
1312
+ declare const VERSION = "0.10.21";
1313
1313
  /** Как мы представляемся серверу Напарника. По нему в логах видно оболочку. */
1314
- declare const USER_AGENT = "naparnik-mcp/0.10.18";
1314
+ declare const USER_AGENT = "naparnik-mcp/0.10.21";
1315
1315
  /**
1316
1316
  * Самая старая начинка (движок монтажа), с которой эта оболочка работает.
1317
1317
  * Обновление начинки ниже этой версии не ставится, а выше — требует оболочки
@@ -1348,7 +1348,7 @@ declare const USER_AGENT = "naparnik-mcp/0.10.18";
1348
1348
  * словами «раздача ещё не обновилась». Номер берётся из УЖЕ СОБРАННОГО
1349
1349
  * артефакта этой волны, а не сочиняется по календарю.
1350
1350
  */
1351
- declare const MIN_ENGINE = "2026.09.19-355";
1351
+ declare const MIN_ENGINE = "2026.09.23-406";
1352
1352
 
1353
1353
  /**
1354
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-O7XB7YJ5.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-5DKUJSAN.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@naparnik/mcp",
3
- "version": "0.10.18",
3
+ "version": "0.10.21",
4
4
  "description": "MCP-сервер Напарника: монтаж вертикального видео на машине пользователя — паузы, субтитры, герой на новом фоне, звук. Видео никуда не уезжает.",
5
5
  "license": "SEE LICENSE IN LICENSE.md",
6
6
  "private": false,