@naparnik/mcp 0.10.50 → 0.10.52

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.
@@ -730,7 +730,7 @@ function parsePositiveInt(raw, fallback) {
730
730
  }
731
731
 
732
732
  // src/version.ts
733
- var VERSION = "0.10.50";
733
+ var VERSION = "0.10.52";
734
734
  var USER_AGENT = `naparnik-mcp/${VERSION}`;
735
735
  var MIN_ENGINE = "2026.09.24-478";
736
736
  var LAUNCHER_PROTOCOL = 1;
@@ -1912,9 +1912,10 @@ var Engine = class {
1912
1912
  async runWith(executable, place, args, {
1913
1913
  maxBuffer = 8 << 20,
1914
1914
  timeout = 3e5,
1915
- key
1915
+ key,
1916
+ onLine
1916
1917
  } = {}) {
1917
- return execFileP(executable, [place.consolePy, ...args], {
1918
+ const options = {
1918
1919
  // ⚠ ПАПКА ПАКА МОЖЕТ НЕ СУЩЕСТВОВАТЬ, И ЭТО НЕ ГИПОТЕЗА. Так выглядит
1919
1920
  // машина, где движок разложен, а пак ещё нет — например, сразу после
1920
1921
  // обновления начинки урезанным архивом. `execFile` с несуществующим `cwd`
@@ -1933,6 +1934,20 @@ var Engine = class {
1933
1934
  // обновление получает 403 и говорит человеку «каталог ещё не выложен».
1934
1935
  // Поэтому не «вернуть ключ в среду», а передать его ровно на этот запуск.
1935
1936
  env: montageEnv(this.pythonEnv(), key)
1937
+ };
1938
+ if (onLine === void 0) return execFileP(executable, [place.consolePy, ...args], options);
1939
+ return new Promise((done, fail) => {
1940
+ const child = execFile(executable, [place.consolePy, ...args], options, (err, out, errOut) => {
1941
+ if (err !== null) fail(Object.assign(err, { stdout: out, stderr: errOut }));
1942
+ else done({ stdout: out, stderr: errOut });
1943
+ });
1944
+ let rest = "";
1945
+ child.stdout?.on("data", (chunk) => {
1946
+ rest += String(chunk);
1947
+ const lines = rest.split(/\r?\n|\r/);
1948
+ rest = lines.pop() ?? "";
1949
+ for (const line of lines) if (line.trim() !== "") onLine(line.trim());
1950
+ });
1936
1951
  });
1937
1952
  }
1938
1953
  /**
@@ -14266,7 +14281,7 @@ ${delivery.text}` };
14266
14281
  }
14267
14282
  }
14268
14283
  hooks.downloaded?.();
14269
- if (candidateDeps(engine)) return activatePreparedCandidateLocked(engine, manifest, trial);
14284
+ if (candidateDeps(engine)) return activatePreparedCandidateLocked(engine, manifest, trial, "now", hooks.line);
14270
14285
  const smoke = await dryRun(engine, dest, manifest.version, trial);
14271
14286
  if (smoke !== null) {
14272
14287
  const where = keepBroken(dir, manifest.version, smoke);
@@ -14441,6 +14456,12 @@ function pollutedPayload(dest, candidate) {
14441
14456
  function samePreparedCandidate(actual, expected) {
14442
14457
  return actual !== null && actual.version === expected.version && actual.sha256 === expected.sha256 && actual.state === "prepared" && actual.baseCurrent === expected.baseCurrent && actual.environment === expected.environment && actual.mineDigest === expected.mineDigest && actual.payload !== void 0 && expected.payload !== void 0 && samePayloadProof(actual.payload, expected.payload);
14443
14458
  }
14459
+ var STEP_ANSWER = /^(Шаг «|Дальше:|Спроси у человека:|Нужно скачать )/;
14460
+ function progressOnly(say) {
14461
+ return (line) => {
14462
+ if (!STEP_ANSWER.test(line)) say(line);
14463
+ };
14464
+ }
14444
14465
  async function runCandidateWith(engine, dir, version2, executable, place, args, opts = {}, requireVenv = true) {
14445
14466
  const venvTrouble = candidateVenvTrouble(dir, version2, place, requireVenv);
14446
14467
  if (venvTrouble !== null) throw new Error(venvTrouble);
@@ -14488,7 +14509,7 @@ async function compatibilityProof(engine, dir, version2, python, place) {
14488
14509
  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)}` };
14489
14510
  }
14490
14511
  }
14491
- async function activatePreparedCandidateLocked(engine, manifest, trial, extras = "now") {
14512
+ async function activatePreparedCandidateLocked(engine, manifest, trial, extras = "now", say) {
14492
14513
  const dir = engine.versionsDir();
14493
14514
  const candidate = readCandidate(dir);
14494
14515
  if (candidate?.version !== manifest.version || candidate.sha256 !== manifest.sha256) {
@@ -14536,7 +14557,7 @@ async function activatePreparedCandidateLocked(engine, manifest, trial, extras =
14536
14557
  "--consent",
14537
14558
  ...extras === "later" ? requiredOnly(dir, candidate.version) : []
14538
14559
  ],
14539
- { timeout: 60 * 6e4 },
14560
+ { timeout: 60 * 6e4, ...say === void 0 ? {} : { onLine: progressOnly(say) } },
14540
14561
  false
14541
14562
  );
14542
14563
  const installedVenvTrouble = candidateVenvTrouble(dir, candidate.version, place, true);
@@ -16580,6 +16601,208 @@ function tail(text2, max) {
16580
16601
  function orNull(value, max) {
16581
16602
  return value === null || value === "" ? null : head(value, max);
16582
16603
  }
16604
+
16605
+ // src/tool-kit.ts
16606
+ function manifestUrl(engine, baseUrl) {
16607
+ return engine.variable("NAPARNIK_UPDATE_MANIFEST") ?? manifestUrlFor(baseUrl);
16608
+ }
16609
+ function aboutDefaults(map2) {
16610
+ if (map2 === void 0 || Object.keys(map2).length === 0) return "\u0441\u043C\u043E\u0442\u0440\u0438 setup";
16611
+ return Object.entries(map2).map(([engine, model]) => `${model} (${engine})`).join(", ");
16612
+ }
16613
+ function aboutModels(passport) {
16614
+ if (passport === null) return "\u0421\u043F\u0438\u0441\u043E\u043A \u043C\u043E\u0434\u0435\u043B\u0435\u0439 \u0441\u043C\u043E\u0442\u0440\u0438 \u0432 setup";
16615
+ return `\u041A\u0430\u043A\u0438\u0435 \u0435\u0441\u0442\u044C: ${passport["models"].join(", ")}; \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E \u2014 \u0441\u0432\u043E\u0451 \u043D\u0430 \u0434\u0432\u0438\u0436\u043E\u043A: ${aboutDefaults(passport["default_model"])}. \u041D\u0435 \u043D\u0430\u0437\u044B\u0432\u0430\u0439 \u043C\u043E\u0434\u0435\u043B\u044C \u0431\u0435\u0437 \u043D\u0443\u0436\u0434\u044B: \u043F\u0430\u043A \u0441\u0430\u043C \u0432\u043E\u0437\u044C\u043C\u0451\u0442 \u0442\u0443, \u0447\u0442\u043E \u0431\u044B\u0441\u0442\u0440\u0435\u0435 \u043D\u0430 \u044D\u0442\u043E\u043C \u043A\u043E\u043C\u043F\u044C\u044E\u0442\u0435\u0440\u0435`;
16616
+ }
16617
+ function fromList(list, description) {
16618
+ return list !== void 0 && list.length > 0 ? external_exports.enum([...list]).describe(description) : external_exports.string().describe(description);
16619
+ }
16620
+ function asToolResult(outcome) {
16621
+ return outcome.ok ? toolSuccess(outcome.text) : toolError(outcome.text);
16622
+ }
16623
+ function asJobResult(outcome) {
16624
+ if (!outcome.ok) return toolError(outcome.text);
16625
+ const job = readJob(outcome.text);
16626
+ return job === null ? toolSuccess(outcome.text) : toolSuccess(outcome.text, job);
16627
+ }
16628
+ var CAPABILITIES_CONTRACT = "naparnik-capabilities/1";
16629
+ var HEAVY_WORK = {
16630
+ model: "\u0440\u0430\u0441\u043F\u043E\u0437\u043D\u0430\u0432\u0430\u043D\u0438\u0435 \u0440\u0435\u0447\u0438",
16631
+ cutout: "\u0432\u044B\u0440\u0435\u0437 \u0433\u0435\u0440\u043E\u044F",
16632
+ voice: "\u0447\u0438\u0441\u0442\u043A\u0430 \u0433\u043E\u043B\u043E\u0441\u0430"
16633
+ };
16634
+ var KNOB_KIND = {
16635
+ file: "\u0444\u0430\u0439\u043B",
16636
+ string: "\u0441\u0442\u0440\u043E\u043A\u0430",
16637
+ number: "\u0447\u0438\u0441\u043B\u043E",
16638
+ "yes-no": "\u0434\u0430/\u043D\u0435\u0442"
16639
+ };
16640
+ var FROM_MINE = "mine";
16641
+ function catalogInWords(data) {
16642
+ const lines = [];
16643
+ const version2 = data.engine?.version;
16644
+ lines.push(`\u0427\u0442\u043E \u0443\u043C\u0435\u0435\u0442 \u043C\u043E\u043D\u0442\u0430\u0436 \u043D\u0430 \u044D\u0442\u043E\u043C \u043A\u043E\u043C\u043F\u044C\u044E\u0442\u0435\u0440\u0435${version2 !== void 0 ? `. \u0414\u0432\u0438\u0436\u043E\u043A ${version2}` : ""}.`);
16645
+ const steps = data.steps ?? [];
16646
+ const ready = steps.filter((s) => s.ready !== false);
16647
+ const later = steps.filter((s) => s.ready === false);
16648
+ if (ready.length > 0) {
16649
+ lines.push(`\u0423\u0436\u0435 \u0441\u0442\u043E\u0438\u0442: ${ready.map((s) => `${s.title} (${s.name})`).join(", ")}.`);
16650
+ }
16651
+ if (later.length > 0) {
16652
+ const said = later.map((s) => {
16653
+ const work = (s.needs ?? []).map((n) => HEAVY_WORK[n] ?? n).join(" \u0438 ");
16654
+ const step = (s.needs ?? [])[0];
16655
+ return `${s.title} (${s.name}) \u2014 ${work}${step !== void 0 ? ` (setup what="${step}")` : ""}`;
16656
+ }).join("; ");
16657
+ lines.push(
16658
+ `\u0414\u043E\u043A\u0430\u0447\u0430\u0435\u0442\u0441\u044F \u043F\u0435\u0440\u0435\u0434 \u043F\u0435\u0440\u0432\u044B\u043C \u043C\u043E\u043D\u0442\u0430\u0436\u043E\u043C, \u0441\u043F\u0440\u043E\u0441\u0438 \u0441\u043E\u0433\u043B\u0430\u0441\u0438\u0435 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430: ${said}.`
16659
+ );
16660
+ }
16661
+ const recipes = data.recipes ?? [];
16662
+ if (recipes.length > 0) {
16663
+ lines.push(`\u0413\u043E\u0442\u043E\u0432\u044B\u0435 \u043D\u0430\u0431\u043E\u0440\u044B \u0448\u0430\u0433\u043E\u0432: ${recipes.map((r) => `${r.title} (${r.name})`).join(", ")}.`);
16664
+ }
16665
+ const inForce = data.recipe;
16666
+ if (inForce?.name !== void 0) {
16667
+ lines.push(
16668
+ inForce.origin === FROM_MINE ? `\u0420\u0435\u0446\u0435\u043F\u0442 \u0432 \u0434\u0435\u043B\u0435: \u0441\u0432\u043E\u0439 \xAB${inForce.name}\xBB \u2014 ${inForce.path ?? ""}.` : `\u0420\u0435\u0446\u0435\u043F\u0442 \u0432 \u0434\u0435\u043B\u0435: \u043D\u0430\u0448 \xAB${inForce.name}\xBB. \u0421\u0432\u043E\u0439 \u0437\u0430\u0432\u043E\u0434\u0438\u0442\u0441\u044F \u0447\u0435\u0440\u0435\u0437 plan_edit \u0441\u043E step.`
16669
+ );
16670
+ }
16671
+ const questions = data.questions ?? [];
16672
+ if (questions.length > 0) {
16673
+ const sections = [...new Map(
16674
+ questions.filter((q) => q.section).map((q) => [q.section ?? "", q.group ?? ""])
16675
+ )].map(([id, tab]) => `${tab} (${id})`);
16676
+ lines.push(
16677
+ "\u0421\u043F\u0440\u043E\u0441\u0438\u0442\u044C \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0430\u043C\u0438 \u2014 choose_variant(questions=[\u2026]) \u0438\u043C\u0435\u043D\u0430\u043C\u0438 \u0432\u043E\u043F\u0440\u043E\u0441\u043E\u0432 \u0438\u043B\u0438 \u0440\u0430\u0437\u0434\u0435\u043B\u043E\u0432, \u0438 \u0442\u043E\u043B\u044C\u043A\u043E \u043F\u0440\u043E \u0442\u043E, \u0447\u0442\u043E \u0447\u0435\u043B\u043E\u0432\u0435\u043A \u0432\u044B\u0431\u0440\u0430\u043B \u0438\u043B\u0438 \u043F\u043E\u043F\u0440\u043E\u0441\u0438\u043B." + (sections.length > 0 ? ` \u0420\u0430\u0437\u0434\u0435\u043B\u044B: ${sections.join(", ")}.` : "")
16678
+ );
16679
+ for (const q of questions) {
16680
+ const tab = q.group ? `[${q.group}] ` : "";
16681
+ if (q.kind === "range") {
16682
+ const dials = (q.sliders ?? []).map((s) => `${s.title} (${s.name})`).join(", ");
16683
+ lines.push(`\u2014 ${tab}${q.title} (${q.name}), \u043F\u043E\u043B\u0437\u0443\u043D\u043A\u0430\u043C\u0438: ${dials}.`);
16684
+ continue;
16685
+ }
16686
+ const plain = q.kind === "plain" ? ", \u0431\u0435\u0437 \u043A\u0430\u0440\u0442\u0438\u043D\u043A\u0438" : "";
16687
+ const named = q.variants ?? [];
16688
+ const variants = named.length > 0 ? named.map((v) => `${v.title} (${v.name})`).join(", ") : "\u0432\u0430\u0440\u0438\u0430\u043D\u0442\u044B \u0441\u0447\u0438\u0442\u0430\u044E\u0442\u0441\u044F \u043F\u043E \u043A\u0430\u0434\u0440\u0443 \u0440\u043E\u043B\u0438\u043A\u0430";
16689
+ const total = typeof q.total === "number" ? q.total : named.length;
16690
+ const rest = total > named.length ? ` \u0438 \u0435\u0449\u0451 ${total - named.length}` : "";
16691
+ lines.push(`\u2014 ${tab}${q.title} (${q.name})${plain}: ${variants}${rest}.`);
16692
+ }
16693
+ }
16694
+ const knobs = data.knobs ?? [];
16695
+ if (knobs.length > 0) {
16696
+ const said = knobs.map((k) => `${k.name} (${k.kind !== void 0 ? KNOB_KIND[k.kind] ?? k.kind : "\u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435"})`).join(", ");
16697
+ lines.push(`\u0420\u0443\u0447\u043A\u0438 \u043C\u043E\u043D\u0442\u0430\u0436\u0430, \u0438\u0445 \u043F\u0435\u0440\u0435\u0434\u0430\u044E\u0442 \u0432 render: ${said}.`);
16698
+ }
16699
+ const index = data.handbook?.index;
16700
+ if (index !== void 0 && index.trim() !== "") {
16701
+ lines.push(`\u0421\u041F\u0420\u0410\u0412\u041E\u0427\u041D\u0418\u041A \u041C\u041E\u041D\u0422\u0410\u0416\u0401\u0420\u0410 \u2014 \u043E\u0433\u043B\u0430\u0432\u043B\u0435\u043D\u0438\u0435, \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u044B \u0447\u0438\u0442\u0430\u0439 plan \u0441 read:
16702
+ ${index.trim()}`);
16703
+ }
16704
+ const style = data.style;
16705
+ if (style?.name !== void 0) {
16706
+ lines.push(
16707
+ style.own === true ? `\u0421\u0442\u0438\u043B\u044C: \u0441\u0432\u043E\u0439 \u043F\u0430\u043A \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430 \xAB${style.name}\xBB \u2014 \u0432\u044B\u0431\u0440\u0430\u043D\u043D\u043E\u0435 \u0437\u0430\u043F\u043E\u043C\u0438\u043D\u0430\u0435\u0442\u0441\u044F \u0432 \u043D\u0435\u0433\u043E.` : `\u0421\u0442\u0438\u043B\u044C: \u0432\u0441\u0442\u0440\u043E\u0435\u043D\u043D\u044B\u0439 \xAB${style.name}\xBB, \u0441\u0432\u043E\u0435\u0433\u043E \u043F\u0430\u043A\u0430 \u0443 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430 \u0435\u0449\u0451 \u043D\u0435\u0442.`
16708
+ );
16709
+ }
16710
+ const mine = data.mine?.summary ?? [];
16711
+ if (mine.length > 0) {
16712
+ lines.push(`\u0421\u0432\u043E\u0451 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430 (\u0437\u0430\u043F\u043E\u043C\u043D\u0435\u043D\u043E, \u0443\u0436\u0435 \u0432 \u043A\u0430\u0436\u0434\u043E\u043C \u0447\u0435\u0440\u043D\u043E\u0432\u0438\u043A\u0435; \xAB\u0437\u0430\u0431\u0443\u0434\u044C\xBB \u2014 plan_edit forget):
16713
+ ${mine.map((line) => `\u2014 ${line}`).join("\n")}`);
16714
+ }
16715
+ for (const said of data.warnings ?? []) lines.push(said);
16716
+ return lines.join("\n");
16717
+ }
16718
+ function otherContract(said, expected) {
16719
+ return `\u0414\u0432\u0438\u0436\u043E\u043A \u0433\u043E\u0432\u043E\u0440\u0438\u0442 \u043D\u0430 \u0434\u043E\u0433\u043E\u0432\u043E\u0440\u0435 \xAB${String(said)}\xBB, \u0430 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u0435 \u043F\u043E\u043D\u0438\u043C\u0430\u0435\u0442 \xAB${expected}\xBB. \u041E\u0431\u043D\u043E\u0432\u0438 \u0442\u043E, \u0447\u0442\u043E \u0441\u0442\u0430\u0440\u0435\u0435: setup \u0441 what=engine \u0434\u043B\u044F \u0434\u0432\u0438\u0436\u043A\u0430, what=shell \u0434\u043B\u044F \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F.`;
16720
+ }
16721
+ async function askCatalog(engine, pack, video) {
16722
+ const answer = await engine.command([
16723
+ "capabilities",
16724
+ "--pack",
16725
+ pack,
16726
+ ...video !== void 0 ? ["--video", path(video)] : []
16727
+ ]);
16728
+ if (!answer.ok) return `\u0421\u043F\u0438\u0441\u043E\u043A \u0442\u043E\u0433\u043E, \u0447\u0442\u043E \u0443\u043C\u0435\u0435\u0442 \u043C\u043E\u043D\u0442\u0430\u0436, \u043D\u0435 \u043F\u0440\u0438\u0448\u0451\u043B: ${answer.text}`;
16729
+ let data;
16730
+ try {
16731
+ data = JSON.parse(answer.text);
16732
+ } catch {
16733
+ return `\u0421\u043F\u0438\u0441\u043E\u043A \u0442\u043E\u0433\u043E, \u0447\u0442\u043E \u0443\u043C\u0435\u0435\u0442 \u043C\u043E\u043D\u0442\u0430\u0436, \u043D\u0435 \u043F\u0440\u0438\u0448\u0451\u043B: ${NOT_JSON}`;
16734
+ }
16735
+ if (data.contract !== CAPABILITIES_CONTRACT) {
16736
+ return `\u0414\u0432\u0438\u0436\u043E\u043A \u0433\u043E\u0432\u043E\u0440\u0438\u0442 \u043D\u0430 \u0434\u043E\u0433\u043E\u0432\u043E\u0440\u0435 \xAB${String(data.contract)}\xBB, \u0430 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u0435 \u043F\u043E\u043D\u0438\u043C\u0430\u0435\u0442 \xAB${CAPABILITIES_CONTRACT}\xBB, \u0438 \u0441\u043F\u0438\u0441\u043E\u043A \u0442\u043E\u0433\u043E, \u0447\u0442\u043E \u0443\u043C\u0435\u0435\u0442 \u043C\u043E\u043D\u0442\u0430\u0436, \u043D\u0435 \u043F\u0440\u043E\u0447\u0438\u0442\u0430\u043D. \u041E\u0431\u043D\u043E\u0432\u0438 \u0442\u043E, \u0447\u0442\u043E \u0441\u0442\u0430\u0440\u0435\u0435: setup \u0441 what=engine \u0434\u043B\u044F \u0434\u0432\u0438\u0436\u043A\u0430, what=shell \u0434\u043B\u044F \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F.`;
16737
+ }
16738
+ return catalogInWords(data);
16739
+ }
16740
+ function fromWords(text2, contract) {
16741
+ let data;
16742
+ try {
16743
+ data = JSON.parse(text2);
16744
+ } catch {
16745
+ return { refusal: NOT_JSON };
16746
+ }
16747
+ if (contract !== void 0 && data.contract !== contract) {
16748
+ return { refusal: otherContract(data.contract, contract) };
16749
+ }
16750
+ if (typeof data.words !== "string" || data.words === "") return { refusal: NOT_JSON };
16751
+ return { words: data.words, data };
16752
+ }
16753
+ function folderAnswer(text2) {
16754
+ const read = fromWords(text2);
16755
+ return "refusal" in read ? toolError(read.refusal) : toolSuccess(read.words, read.data);
16756
+ }
16757
+ var DRAFT_CONTRACT = "naparnik-draft/1";
16758
+ var VIEW_CONTRACT = "naparnik-view/1";
16759
+ var EDIT_CONTRACT = "naparnik-edit/1";
16760
+ function answerOrRefusal(text2, contract) {
16761
+ const read = fromWords(text2, contract);
16762
+ if ("refusal" in read) {
16763
+ const plain = text2.trim();
16764
+ return { refusal: plain.startsWith("{") || plain === "" ? read.refusal : plain };
16765
+ }
16766
+ return read.data["ok"] === false ? { refusal: read.words } : read;
16767
+ }
16768
+ async function draftDocument(engine, place, asked, key) {
16769
+ const answer = await engine.command([
16770
+ "document-draft",
16771
+ "--video",
16772
+ asked.video,
16773
+ "--pack",
16774
+ place.pack,
16775
+ ...asked.style !== void 0 ? ["--style", path(asked.style)] : [],
16776
+ ...(asked.also ?? []).flatMap((one) => ["--also", path(one)]),
16777
+ ...asked.ask !== void 0 ? ["--ask", JSON.stringify(asked.ask)] : [],
16778
+ "--json"
16779
+ ], key !== void 0 ? { key } : {});
16780
+ return answer.ok ? answerOrRefusal(answer.text, DRAFT_CONTRACT) : { refusal: answer.text };
16781
+ }
16782
+ async function editOperations(engine, place, asked, key) {
16783
+ const answer = await engine.command([
16784
+ "document-edit",
16785
+ "--project",
16786
+ path(asked.reel),
16787
+ "--ops",
16788
+ JSON.stringify(asked.ops),
16789
+ ...asked.stamps !== void 0 ? ["--stamps", JSON.stringify(asked.stamps)] : [],
16790
+ "--by",
16791
+ asked.by ?? "model",
16792
+ "--pack",
16793
+ place.pack,
16794
+ "--json"
16795
+ ], key !== void 0 ? { key } : {});
16796
+ return answer.ok ? answerOrRefusal(answer.text, EDIT_CONTRACT) : { refusal: answer.text };
16797
+ }
16798
+ function nameOrRefusal(candidate) {
16799
+ const looksLikePath2 = candidate.includes("/") || candidate.includes("\\") || candidate.startsWith("~") || candidate.startsWith(".") || candidate.length > 1 && candidate[1] === ":";
16800
+ if (!looksLikePath2) return { name: candidate };
16801
+ return {
16802
+ refusal: `\u0417\u0434\u0435\u0441\u044C \u0436\u0434\u0443\u0442 \u0418\u041C\u042F \u0448\u0430\u0433\u0430, \u0430 \u043F\u0440\u0438\u0448\u0451\u043B \u043F\u0443\u0442\u044C: ${candidate}
16803
+ \u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C: \u043D\u0430\u0437\u043E\u0432\u0438 \u0448\u0430\u0433 \u043E\u0434\u043D\u0438\u043C \u0441\u043B\u043E\u0432\u043E\u043C \u2014 \u0442\u0430\u043A, \u043A\u0430\u043A \u043D\u0430\u0437\u044B\u0432\u0430\u0435\u0442\u0441\u044F \u0435\u0433\u043E \u043F\u0430\u043F\u043A\u0430. \u0421\u0432\u043E\u0439 \u0448\u0430\u0433 \u043B\u0435\u0436\u0438\u0442 \u0432 \`mine/steps/<\u0438\u043C\u044F>\` \u0432 \u0434\u043E\u043C\u0435 \u041D\u0430\u043F\u0430\u0440\u043D\u0438\u043A\u0430, \u043D\u0430\u0448\u0438 \u043F\u0435\u0440\u0435\u0447\u0438\u0441\u043B\u044F\u0435\u0442 setup, \u0438\u043C\u044F \u0443 \u043A\u0430\u0436\u0434\u043E\u0433\u043E \u0441\u0442\u043E\u0438\u0442 \u0432 \u0441\u043A\u043E\u0431\u043A\u0430\u0445.`
16804
+ };
16805
+ }
16583
16806
  var SETUP_CONTRACT = "naparnik-setup/1";
16584
16807
  var READINESS_CONTRACT = "naparnik-readiness/1";
16585
16808
  var JSON_CHECK = "--json";
@@ -16668,8 +16891,11 @@ function whatIsNew(shell, engine) {
16668
16891
  }
16669
16892
  return parts.join(" \u0438 ");
16670
16893
  }
16894
+ function updateOffered(shell, engine) {
16895
+ return Boolean(shell?.fresh) || Boolean(engine?.fresh);
16896
+ }
16671
16897
  function updateWords(shell, engine) {
16672
- if (!shell?.fresh && !engine?.fresh) return "";
16898
+ if (!updateOffered(shell, engine)) return "";
16673
16899
  const notes = shell?.fresh ? firstPhrase(shell.notes) : "";
16674
16900
  return [
16675
16901
  `\u0414\u043E\u0441\u0442\u0443\u043F\u043D\u0430 \u043D\u043E\u0432\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u043C\u043E\u043D\u0442\u0430\u0436\u0451\u0440\u0430: ${whatIsNew(shell, engine)}.${notes ? ` \u041F\u043E\u044F\u0432\u0438\u043B\u043E\u0441\u044C: ${notes}` : ""}`,
@@ -16720,1919 +16946,1720 @@ function setupCard(o) {
16720
16946
  next
16721
16947
  };
16722
16948
  }
16723
- var WIDGET_MIME = "text/html;profile=mcp-app";
16724
- function widgetStamp(html) {
16725
- return createHash("sha256").update(html).digest("hex").slice(0, 8);
16949
+ var SETUP_JOB_MARK = "setup-";
16950
+ function isSetupJob(id) {
16951
+ return id.startsWith(SETUP_JOB_MARK);
16726
16952
  }
16727
- var WIDGET_PLATE_CSS = `
16728
- :root { --plate: #ffffff; --plate-end: #f5f5f7; }
16729
- :root:has(> body.dark) { --plate: #1d1d1f; --plate-end: #000000; }
16730
- :root:has(> body.full) { min-height: 100%; }
16731
- html {
16732
- background: var(--plate-end) linear-gradient(var(--plate) calc(100% - 197px), var(--plate-end)) no-repeat;
16953
+ var TITLE_UPDATE = "\u041E\u0431\u043D\u043E\u0432\u043B\u044F\u044E \u0431\u0438\u0431\u043B\u0438\u043E\u0442\u0435\u043A\u0438 \u0434\u043B\u044F \u043C\u043E\u043D\u0442\u0430\u0436\u0430";
16954
+ var TITLE_INSTALL = "\u0423\u0441\u0442\u0430\u043D\u0430\u0432\u043B\u0438\u0432\u0430\u044E \u0431\u0438\u0431\u043B\u0438\u043E\u0442\u0435\u043A\u0438 \u0434\u043B\u044F \u043C\u043E\u043D\u0442\u0430\u0436\u0430";
16955
+ var SAY_RESTART = "\u0413\u043E\u0442\u043E\u0432\u043E. \u041F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u0442\u0438 Claude \u2014 \u043D\u043E\u0432\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u0437\u0430\u0440\u0430\u0431\u043E\u0442\u0430\u0435\u0442 \u043F\u043E\u0441\u043B\u0435 \u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u043A\u0430.";
16956
+ var SAY_NOTHING = "\u0412\u0441\u0451 \u0443\u0436\u0435 \u0441\u0442\u043E\u0438\u0442 \u2014 \u043C\u043E\u0436\u043D\u043E \u043C\u043E\u043D\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C.";
16957
+ var SAY_INSTALLED = "\u0413\u043E\u0442\u043E\u0432\u043E \u2014 \u043C\u043E\u0436\u043D\u043E \u043C\u043E\u043D\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C.";
16958
+ var ADVICE_ASK = "\u041D\u0430\u043F\u0438\u0448\u0438 \u041A\u043B\u043E\u0434\u0443 \xAB\u0447\u0442\u043E \u0441\u043B\u0443\u0447\u0438\u043B\u043E\u0441\u044C\xBB \u2014 \u043E\u043D \u0440\u0430\u0441\u0441\u043A\u0430\u0436\u0435\u0442, \u0447\u0442\u043E \u043F\u043E\u0448\u043B\u043E \u043D\u0435 \u0442\u0430\u043A.";
16959
+ var CHECK = "\u041F\u0440\u043E\u0432\u0435\u0440\u044F\u044E, \u0447\u0442\u043E \u043E\u0431\u043D\u043E\u0432\u0438\u0442\u044C";
16960
+ var INSTALL_NEW = "\u0421\u0442\u0430\u0432\u043B\u044E \u043D\u043E\u0432\u0443\u044E \u0432\u0435\u0440\u0441\u0438\u044E";
16961
+ var MISSING = "\u0421\u0442\u0430\u0432\u043B\u044E \u043D\u0435\u0434\u043E\u0441\u0442\u0430\u044E\u0449\u0435\u0435";
16962
+ var works = /* @__PURE__ */ new Map();
16963
+ var JOBS_DIR = "jobs";
16964
+ var JOBS_KEPT2 = 10;
16965
+ var BEAT_MS = 1e4;
16966
+ var STALE_MS = 6e4;
16967
+ var JOB_ID = /^setup-[\w-]{1,80}$/;
16968
+ function running(home, clock) {
16969
+ for (const work of works.values()) if (work.ended === null) return work.id;
16970
+ if (home === null) return null;
16971
+ for (const record2 of records(home)) {
16972
+ if (record2.ended === null && alive(record2, clock)) return record2.id;
16733
16973
  }
16734
- `;
16735
- var WIDGET_HEADING_CSS = `
16736
- :root {
16737
- --font-display: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Icons", "Helvetica Neue", Helvetica, Arial, sans-serif;
16974
+ return null;
16975
+ }
16976
+ function records(home) {
16977
+ let names;
16978
+ try {
16979
+ names = readdirSync(join(home, JOBS_DIR)).filter((name) => name.endsWith(".json"));
16980
+ } catch {
16981
+ return [];
16738
16982
  }
16739
- h2, .end__t { font-family: var(--font-display); }
16740
- `;
16741
-
16742
- // src/runbar.ts
16743
- var RUNBAR_RESOURCE_URI = `ui://naparnik/runbar-${widgetStamp(runbarWidgetHtml())}`;
16744
- var RUNBAR_MIME = WIDGET_MIME;
16745
- function runbarResource() {
16746
- return {
16747
- resource: {
16748
- uri: RUNBAR_RESOURCE_URI,
16749
- name: "\u0425\u043E\u0434 \u0440\u0430\u0431\u043E\u0442\u044B",
16750
- description: "\u041F\u043E\u043B\u043E\u0441\u0430 \u044D\u0442\u0430\u043F\u043E\u0432: \u0447\u0442\u043E \u0434\u0435\u043B\u0430\u0435\u0442\u0441\u044F \u0441\u0435\u0439\u0447\u0430\u0441 \u0438 \u0441\u043A\u043E\u043B\u044C\u043A\u043E \u0443\u0436\u0435 \u0438\u0434\u0451\u0442",
16751
- mimeType: RUNBAR_MIME
16752
- },
16753
- contents: [{
16754
- uri: RUNBAR_RESOURCE_URI,
16755
- mimeType: RUNBAR_MIME,
16756
- text: runbarWidgetHtml(),
16757
- _meta: { ui: { prefersBorder: true } }
16758
- }]
16759
- };
16760
- }
16761
- function runbarWidgetHtml() {
16762
- return `<!DOCTYPE html>
16763
- <html lang="ru">
16764
- <head>
16765
- <meta charset="utf-8">
16766
- <style>
16767
- /* \u2500\u2500\u2500 \u041C\u0438\u0440 \u043F\u043E\u043B\u043E\u0441\u044B \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
16768
- \u0426\u0432\u0435\u0442\u0430 \u0442\u0435 \u0436\u0435, \u0447\u0442\u043E \u0443 \u0444\u043E\u0440\u043C\u044B \u0432\u044B\u0431\u043E\u0440\u0430 \u0438 \u043D\u0430 \u043B\u0435\u043D\u0434\u0438\u043D\u0433\u0435: \u0436\u0451\u043B\u0442\u044B\u0439 \u0432\u0435\u0434\u0451\u0442 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u2014
16769
- \u0437\u0434\u0435\u0441\u044C \u044D\u0442\u043E \u0438\u0434\u0443\u0449\u0438\u0439 \u044D\u0442\u0430\u043F, \u0433\u043E\u043B\u0443\u0431\u043E\u0439 \u0432\u0435\u0434\u0451\u0442 \u0433\u043E\u043B\u043E\u0441 \u2014 \u0441\u0442\u0440\u043E\u043A\u0443 \u043E \u0442\u043E\u043C, \u0447\u0442\u043E \u043F\u0440\u043E\u0438\u0441\u0445\u043E\u0434\u0438\u0442.
16770
-
16771
- \u26A0 \u0421\u0412\u0415\u0422 \u2014 \u041E\u0421\u041D\u041E\u0412\u0410, \u0422\u0401\u041C\u041D\u0410\u042F \u0422\u0415\u041C\u0410 \u0422\u041E\u041B\u042C\u041A\u041E \u0414\u041E\u041F\u0418\u0421\u042B\u0412\u0410\u0415\u0422. \u041F\u0440\u0430\u0432\u0438\u043B\u043E \u043F\u0440\u043E\u0435\u043A\u0442\u0430: \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435
16772
- \u0443 \u0441\u0432\u043E\u0439\u0441\u0442\u0432\u0430 \u043E\u0434\u043D\u043E, \u0438 \u043F\u0440\u0430\u0432\u043A\u0430 \u0441\u0432\u0435\u0442\u043B\u043E\u0439 \u0442\u0435\u043C\u044B \u043D\u0435 \u043C\u043E\u0436\u0435\u0442 \u043C\u043E\u043B\u0447\u0430 \u043F\u0435\u0440\u0435\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u0442\u0451\u043C\u043D\u0443\u044E.
16773
-
16774
- \u26A0 \u041E \xABcolor-scheme\xBB: \u0435\u0433\u043E \u0437\u0434\u0435\u0441\u044C \u041D\u0415\u0422, \u0438 \u044D\u0442\u043E \u043D\u0435 \u0437\u0430\u0431\u044B\u0442\u043E. \u0421\u043E \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435\u043C
16775
- \xABlight dark\xBB \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u043F\u0435\u0440\u0435\u0441\u0442\u0430\u0451\u0442 \u043A\u043E\u043C\u043F\u043E\u0437\u0438\u0442\u0438\u0442\u044C iframe \u0441 \u043F\u043E\u0432\u0435\u0440\u0445\u043D\u043E\u0441\u0442\u044C\u044E \u0445\u043E\u0441\u0442\u0430 \u0438
16776
- \u0437\u0430\u043B\u0438\u0432\u0430\u0435\u0442 \u0435\u0433\u043E \u0441\u043E\u0431\u0441\u0442\u0432\u0435\u043D\u043D\u044B\u043C \u0445\u043E\u043B\u0441\u0442\u043E\u043C \u043F\u043E \u043D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0435 \u0421\u0418\u0421\u0422\u0415\u041C\u042B: \u043F\u0440\u0438 \u0441\u0432\u0435\u0442\u043B\u043E\u043C \u041A\u043B\u043E\u0434\u0435
16777
- \u043D\u0430 \u0442\u0451\u043C\u043D\u043E\u0439 macOS \u043F\u043E\u043B\u043E\u0441\u0430 \u043F\u043E\u043B\u0443\u0447\u0430\u043B\u0430 \u0431\u044B \u0447\u0451\u0440\u043D\u044B\u0439 \u0445\u043E\u043B\u0441\u0442 \u043F\u043E\u0434 \u0442\u0451\u043C\u043D\u044B\u043C\u0438 \u0447\u0435\u0440\u043D\u0438\u043B\u0430\u043C\u0438.
16778
- \u041E\u0448\u0438\u0431\u043A\u0430 \u043C\u043E\u043B\u0447\u0430\u043B\u0438\u0432\u0430\u044F, \u0432 \u043A\u043E\u043D\u0441\u043E\u043B\u0438 \u043F\u0443\u0441\u0442\u043E. \u041F\u0440\u043E\u0432\u0435\u0440\u0435\u043D\u043E \u043D\u0430 \u0444\u043E\u0440\u043C\u0435 \u0432\u044B\u0431\u043E\u0440\u0430 2026-09-10. */
16779
- /* \u041F\u043E\u0434\u043B\u043E\u0436\u043A\u0430 \u043E\u0431\u0449\u0430\u044F \u0441 \u0444\u043E\u0440\u043C\u043E\u0439 \u0432\u044B\u0431\u043E\u0440\u0430 \u0438 \u043B\u0435\u0436\u0438\u0442 \u0432 widget.ts. */
16780
- ${WIDGET_PLATE_CSS}
16781
- ${WIDGET_HEADING_CSS}
16782
- :root {
16783
- --ink: #1d1d1f;
16784
- --ink-soft: #5E5547;
16785
- --card: #F3EDDF;
16786
- --card-lift: #FBF7EC;
16787
- --edge: rgba(20, 17, 12, 0.10);
16788
- --edge-strong: rgba(20, 17, 12, 0.20);
16789
- --note-bg: rgba(29, 219, 208, 0.16);
16790
- --note-dot: #0c6f6a;
16791
- --off: rgba(20, 17, 12, 0.07);
16792
- --off-ink: #6E6455;
16793
- --good: #0E8B54;
16794
- --good-ink: #FFFFFF;
16795
- --bad: #B4341F;
16796
- --bad-bg: rgba(180, 52, 31, 0.10);
16797
- --lift: 0 2px 4px -2px rgba(21, 17, 9, 0.16), 0 16px 34px -20px rgba(21, 17, 9, 0.34);
16798
- --yellow: #f4c70f;
16799
- --ease: cubic-bezier(0.16, 1, 0.30, 1);
16800
- }
16801
- body.dark {
16802
- --ink: #f5f5f7;
16803
- --ink-soft: #ADA495;
16804
- --card: #211C15;
16805
- --card-lift: #2A2419;
16806
- --edge: rgba(244, 239, 230, 0.10);
16807
- --edge-strong: rgba(244, 239, 230, 0.22);
16808
- --note-bg: rgba(29, 219, 208, 0.10);
16809
- --note-dot: #1ddbd0;
16810
- --off: rgba(244, 239, 230, 0.07);
16811
- --off-ink: #9A9182;
16812
- --good: #2FBE7E;
16813
- --good-ink: #10231A;
16814
- --bad: #FF8B72;
16815
- --bad-bg: rgba(255, 139, 114, 0.12);
16816
- --lift: 0 2px 6px -3px rgba(0, 0, 0, 0.75), 0 20px 44px -28px rgba(0, 0, 0, 0.95);
16817
- }
16818
-
16819
- /* \u26A0 \u0421\u0412\u041E\u0418\u0425 \u0428\u0420\u0418\u0424\u0422\u041E\u0412 \u0417\u0414\u0415\u0421\u042C \u041D\u0415\u0422 \u0418 \u0411\u042B\u0422\u042C \u041D\u0415 \u0414\u041E\u041B\u0416\u041D\u041E: \u043F\u043E\u043A\u0443\u043F\u0430\u0442\u0435\u043B\u044E \u043E\u043D\u0438 \u043D\u0435 \u0443\u0435\u0437\u0436\u0430\u044E\u0442, \u0430
16820
- \u0432\u043D\u0435\u0448\u043D\u0438\u0435 \u0430\u0434\u0440\u0435\u0441\u0430 \u0440\u0435\u0436\u0435\u0442 CSP \u0445\u043E\u0441\u0442\u0430. \u0425\u0430\u0440\u0430\u043A\u0442\u0435\u0440 \u043D\u0430\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044F \u043A\u0435\u0433\u043B\u0435\u043C \u0438 \u0442\u0440\u0435\u043A\u0438\u043D\u0433\u043E\u043C. */
16821
- /* \u041F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0442\u044C \u043D\u0435\u0447\u0435\u0433\u043E \u2014 \u043F\u043E\u043B\u043E\u0441\u0430 \u043D\u0435 \u0437\u0430\u043D\u0438\u043C\u0430\u0435\u0442 \u0432 \u043B\u0435\u043D\u0442\u0435 \u043D\u0438 \u0441\u0442\u0440\u043E\u043A\u0438. \u041F\u0443\u0441\u0442\u0430\u044F \u043F\u043B\u0430\u0448\u043A\u0430
16822
- \u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044F \u043A\u0430\u043A \u043F\u043E\u043B\u043E\u043C\u043A\u0430 \u0440\u043E\u0432\u043D\u043E \u0442\u0430\u043A \u0436\u0435, \u043A\u0430\u043A \u0437\u0430\u0441\u0442\u044B\u0432\u0448\u0435\u0435 \xAB\u041D\u0430\u0447\u0438\u043D\u0430\u044E\u2026\xBB. */
16823
- body.gone { padding: 0; min-block-size: 0; }
16824
- body.gone > * { display: none; }
16825
-
16826
- body {
16827
- margin: 0;
16828
- padding: 18px 16px 20px;
16829
- max-inline-size: 880px;
16830
- font: 15px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", "Inter", "Helvetica Neue", Arial, sans-serif;
16831
- -webkit-font-smoothing: antialiased;
16832
- color: var(--ink);
16833
- background: transparent;
16834
- }
16835
- ::selection { background: rgba(244, 199, 15, 0.32); color: var(--ink); }
16836
-
16837
- /* \u2500\u2500\u2500 \u0428\u0430\u043F\u043A\u0430 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
16838
-
16839
- .head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
16840
- h2 {
16841
- margin: 0;
16842
- max-inline-size: 30ch;
16843
- font-size: 19px;
16844
- line-height: 1.15;
16845
- font-weight: 700;
16846
- letter-spacing: -0.03em;
16847
- text-wrap: balance;
16848
- }
16849
- /* \u0427\u0430\u0441\u044B \u043C\u043E\u043D\u043E\u0448\u0438\u0440\u0438\u043D\u043D\u044B\u0435 \u0438 \u0441 \u0444\u0438\u043A\u0441\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u044B\u043C\u0438 \u0446\u0438\u0444\u0440\u0430\u043C\u0438: \u043F\u0440\u043E\u043F\u043E\u0440\u0446\u0438\u043E\u043D\u0430\u043B\u044C\u043D\u044B\u0435 \u0446\u0438\u0444\u0440\u044B
16850
- \u0434\u0451\u0440\u0433\u0430\u044E\u0442 \u0432\u0441\u044E \u0441\u0442\u0440\u043E\u043A\u0443 \u043D\u0430 \u043A\u0430\u0436\u0434\u043E\u043C \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0438, \u0438 \u0433\u043B\u0430\u0437 \u0447\u0438\u0442\u0430\u0435\u0442 \u044D\u0442\u043E \u043A\u0430\u043A \u043C\u0438\u0433\u0430\u043D\u0438\u0435. */
16851
- .clock {
16852
- flex: none;
16853
- color: var(--ink-soft);
16854
- font-size: 13px;
16855
- font-variant-numeric: tabular-nums;
16856
- letter-spacing: -0.01em;
16857
- }
16858
- .clock[hidden] { display: none; }
16859
-
16860
- /* \u2500\u2500\u2500 \u041B\u0435\u0441\u0442\u043D\u0438\u0446\u0430 \u044D\u0442\u0430\u043F\u043E\u0432 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
16861
-
16862
- /* \u26A0 \u042D\u0422\u0410\u041F\u042B \u2014 \u042D\u0422\u041E \u041F\u041E\u041B\u041E\u0421\u042B, \u0410 \u041D\u0415 \u0422\u041E\u0427\u041A\u0418. \u0418\u0445 \u0431\u044B\u0432\u0430\u0435\u0442 \u043E\u0434\u0438\u043D\u043D\u0430\u0434\u0446\u0430\u0442\u044C, \u0438 \u043E\u0434\u0438\u043D\u043D\u0430\u0434\u0446\u0430\u0442\u044C
16863
- \u043A\u0440\u0443\u0436\u043A\u043E\u0432 \u0432 \u043B\u0435\u043D\u0442\u0435 \u0447\u0438\u0442\u0430\u044E\u0442\u0441\u044F \u043A\u0430\u043A \u0443\u0437\u043E\u0440; \u043F\u043E\u043B\u043E\u0441\u044B \u0436\u0435 \u0441\u043A\u043B\u0430\u0434\u044B\u0432\u0430\u044E\u0442\u0441\u044F \u0432 \u043E\u0434\u0438\u043D \u0448\u043E\u0432,
16864
- \u043F\u043E \u043A\u043E\u0442\u043E\u0440\u043E\u043C\u0443 \u0441\u0440\u0430\u0437\u0443 \u0432\u0438\u0434\u043D\u043E, \u043A\u0430\u043A\u0430\u044F \u0434\u043E\u043B\u044F \u0440\u0430\u0431\u043E\u0442\u044B \u043F\u043E\u0437\u0430\u0434\u0438. */
16865
- .rail { display: flex; gap: 4px; margin: 14px 0 0; padding: 0; list-style: none; }
16866
- .rail[hidden] { display: none; }
16867
- .rail li {
16868
- flex: 1 1 0;
16869
- height: 6px;
16870
- border-radius: 3px;
16871
- background: var(--off);
16872
- }
16873
- .rail li.was { background: var(--good); }
16874
- /* \u26A0 \u041A\u041B\u0410\u0421\u0421 \u0418\u0414\u0423\u0429\u0415\u0413\u041E \u042D\u0422\u0410\u041F\u0410 \u2014 \xABat\xBB, \u0410 \u041D\u0415 \xABnow\xBB, \u0418 \u042D\u0422\u041E \u041D\u0415 \u041F\u0420\u0418\u0414\u0418\u0420\u041A\u0410 \u041A \u0418\u041C\u0415\u041D\u0418. \u041F\u043E\u043A\u0430
16875
- \u043E\u043D \u0437\u0432\u0430\u043B\u0441\u044F \xABnow\xBB, \u0435\u0433\u043E \u043F\u043E\u0434\u0445\u0432\u0430\u0442\u044B\u0432\u0430\u043B \u0441\u0435\u043B\u0435\u043A\u0442\u043E\u0440 \xAB.now::before\xBB \u043D\u0438\u0436\u0435: \u043D\u0430 \u043F\u043E\u043B\u043E\u0441\u043A\u0435
16876
- \u0432\u044B\u0440\u0430\u0441\u0442\u0430\u043B \u0434\u044B\u0448\u0430\u0449\u0438\u0439 \u043E\u0433\u043E\u043D\u0451\u043A \u0440\u0430\u0437\u043C\u0435\u0440\u043E\u043C \u0431\u043E\u043B\u044C\u0448\u0435 \u0435\u0451 \u0441\u0430\u043C\u043E\u0439 \u2014 \u043E\u043D \u0432\u044B\u043B\u0435\u0437\u0430\u043B \u0442\u043E\u0447\u043A\u043E\u0439 \u0438
16877
- \u0441\u0434\u0432\u0438\u0433\u0430\u043B \u043F\u043E\u043B\u043E\u0441\u043A\u0443 \u0432\u043D\u0438\u0437 \u043E\u0442\u043D\u043E\u0441\u0438\u0442\u0435\u043B\u044C\u043D\u043E \u0441\u043E\u0441\u0435\u0434\u043D\u0438\u0445. \u0412\u0438\u0434\u043D\u043E \u0442\u043E\u043B\u044C\u043A\u043E \u0433\u043B\u0430\u0437\u0430\u043C\u0438, \u0432
16878
- \u043A\u043E\u043D\u0441\u043E\u043B\u0438 \u043F\u0443\u0441\u0442\u043E (\u0441\u043D\u0438\u043C\u043E\u043A 2026-09-10). */
16879
- .rail li.at {
16880
- background: var(--yellow);
16881
- animation: breathe 1.6s var(--ease) infinite;
16882
- }
16883
-
16884
- /* \u2500\u2500\u2500 \u0427\u0442\u043E \u0441\u0435\u0439\u0447\u0430\u0441 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
16885
-
16886
- .now { display: flex; align-items: flex-start; gap: 10px; margin-top: 14px; }
16887
- .now[hidden] { display: none; }
16888
- /* \u041E\u0433\u043E\u043D\u0451\u043A \u0441\u043B\u0435\u0432\u0430 \u2014 \u0435\u0434\u0438\u043D\u0441\u0442\u0432\u0435\u043D\u043D\u043E\u0435 \u0434\u0432\u0438\u0436\u0443\u0449\u0435\u0435\u0441\u044F \u043C\u0435\u0441\u0442\u043E: \u043F\u043E\u043A\u0430 \u043E\u043D \u0434\u044B\u0448\u0438\u0442, \u0440\u0430\u0431\u043E\u0442\u0430 \u0438\u0434\u0451\u0442.
16889
- \u041E\u043D \u0436\u0435 \u0433\u0430\u0441\u043D\u0435\u0442 \u0432 \u043A\u043E\u043D\u0446\u0435, \u0438 \u0433\u0430\u0441\u043D\u0435\u0442 \u043C\u043E\u043B\u0447\u0430 \u2014 \u043D\u0430 \u0435\u0433\u043E \u043C\u0435\u0441\u0442\u0435 \u043F\u043E\u044F\u0432\u043B\u044F\u0435\u0442\u0441\u044F \u0437\u043D\u0430\u043A. */
16890
- .now::before {
16891
- content: "";
16892
- flex: none;
16893
- width: 8px;
16894
- height: 8px;
16895
- margin-top: 7px;
16896
- border-radius: 50%;
16897
- background: var(--yellow);
16898
- animation: pulse 1.4s var(--ease) infinite;
16899
- }
16900
- .now__t { display: block; font-size: 17px; font-weight: 700; letter-spacing: -0.02em; line-height: 1.2; }
16901
- .now__c { display: block; margin-top: 3px; color: var(--ink-soft); font-size: 13px; line-height: 1.4; }
16902
- .now__c[hidden] { display: none; }
16903
-
16904
- /* \u0421\u0442\u0440\u043E\u043A\u0430 \u0434\u0432\u0438\u0436\u043A\u0430: \u0441\u043A\u043E\u043B\u044C\u043A\u043E \u0441\u043A\u0430\u0447\u0430\u043D\u043E, \u0441\u043A\u043E\u043B\u044C\u043A\u043E \u0440\u0430\u0441\u043F\u043E\u0437\u043D\u0430\u043D\u043E. \u0413\u043E\u043B\u0443\u0431\u0430\u044F \u043C\u0435\u0442\u043A\u0430, \u043F\u043E\u0442\u043E\u043C\u0443
16905
- \u0447\u0442\u043E \u044D\u0442\u043E \u0433\u043E\u043B\u043E\u0441 \u0440\u0430\u0431\u043E\u0442\u044B, \u0430 \u043D\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0438 \u043D\u0435 \u0431\u0435\u0434\u0430. */
16906
- .msg {
16907
- display: flex;
16908
- align-items: flex-start;
16909
- gap: 9px;
16910
- margin-top: 12px;
16911
- padding: 9px 13px;
16912
- border-radius: 12px;
16913
- background: var(--note-bg);
16914
- font-size: 13px;
16915
- line-height: 1.4;
16916
- }
16917
- .msg[hidden] { display: none; }
16918
- .msg::before {
16919
- content: "";
16920
- flex: none;
16921
- width: 7px;
16922
- height: 7px;
16923
- margin-top: 6px;
16924
- border-radius: 50%;
16925
- background: var(--note-dot);
16926
- }
16927
-
16928
-
16929
- /* \u2500\u2500\u2500 \u0428\u043A\u0430\u043B\u0430: \u0441\u043A\u043E\u043B\u044C\u043A\u043E \u0441\u043A\u0430\u0447\u0430\u043D\u043E, \u0441\u043A\u043E\u043B\u044C\u043A\u043E \u0433\u043E\u0442\u043E\u0432\u043E \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
16930
-
16931
- /* \u26A0 \u0428\u041A\u0410\u041B\u0410 \u2014 \u041E\u0414\u041D\u0410 \u041D\u0410 \u0421\u041A\u0410\u0427\u0418\u0412\u0410\u041D\u0418\u0415 \u0418 \u041D\u0410 \u041A\u0410\u0420\u0422\u041E\u0427\u041A\u0423. \u0412\u043B\u0430\u0434\u0435\u043B\u0435\u0446 2026-09-24: \xAB\u0447\u0442\u043E
16932
- \u0441\u0442\u0430\u0432\u043B\u044E, \u0447\u0442\u043E \u043E\u0441\u0442\u0430\u043B\u043E\u0441\u044C, \u043F\u0440\u043E\u0433\u0440\u0435\u0441\u0441-\u0431\u0430\u0440\xBB. \u0416\u0451\u043B\u0442\u0430\u044F \u0437\u0430\u043B\u0438\u0432\u043A\u0430 \u2014 \u044D\u0442\u043E \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435, \u0442\u0430 \u0436\u0435
16933
- \u0440\u043E\u043B\u044C, \u0447\u0442\u043E \u0443 \u0438\u0434\u0443\u0449\u0435\u0433\u043E \u044D\u0442\u0430\u043F\u0430; \u0448\u0438\u0440\u0438\u043D\u0443 \u0441\u0442\u0430\u0432\u0438\u0442 \u0441\u043A\u0440\u0438\u043F\u0442, \u0430 \u043F\u0435\u0440\u0435\u0445\u043E\u0434 \u043F\u043E \u0448\u0438\u0440\u0438\u043D\u0435
16934
- \u043F\u043B\u0430\u0432\u043D\u044B\u0439, \u0447\u0442\u043E\u0431\u044B \u043E\u043F\u0440\u043E\u0441 \u0440\u0430\u0437 \u0432 2,5 \u0441 \u043D\u0435 \u0434\u0451\u0440\u0433\u0430\u043B \u0435\u0451 \u0441\u043A\u0430\u0447\u043A\u0430\u043C\u0438. */
16935
- .meter {
16936
- position: relative;
16937
- height: 8px;
16938
- margin-top: 12px;
16939
- border-radius: 4px;
16940
- background: var(--off);
16941
- overflow: hidden;
16942
- }
16943
- .meter__fill {
16944
- display: block;
16945
- width: 0;
16946
- height: 100%;
16947
- border-radius: 4px;
16948
- background: var(--yellow);
16949
- transition: width .6s var(--ease);
16950
- }
16951
- .meter__cap {
16952
- margin: 7px 0 0;
16953
- color: var(--ink-soft);
16954
- font-size: 13px;
16955
- line-height: 1.4;
16956
- font-variant-numeric: tabular-nums;
16957
- }
16958
- .meter__cap b { color: var(--ink); font-weight: 650; }
16959
- .dl[hidden], .meter[hidden], .meter__cap[hidden] { display: none; }
16960
-
16961
- /* \u2500\u2500\u2500 \u041A\u0430\u0440\u0442\u043E\u0447\u043A\u0430 \u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u044F: \u043E\u0442\u0432\u0435\u0442 setup \u0431\u0435\u0437 \u0437\u0430\u0434\u0430\u0447\u0438 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
16962
-
16963
- /* \u26A0 \u041A\u0410\u0420\u0422\u041E\u0427\u041A\u0410 \u0412\u041C\u0415\u0421\u0422\u041E \u0421\u0412\u0401\u0420\u0422\u041A\u0418, \u0418 \u042D\u0422\u041E \u0416\u0418\u0412\u0410\u042F \u041F\u041E\u041B\u041E\u041C\u041A\u0410 2026-09-24. \u0420\u0430\u043C\u043A\u0443 \u0432\u0438\u0434\u0436\u0435\u0442\u0430
16964
- \u0445\u043E\u0441\u0442 \u0440\u0438\u0441\u0443\u0435\u0442 \u043D\u0430 \u043A\u0430\u0436\u0434\u043E\u043C \u0432\u044B\u0437\u043E\u0432\u0435 setup; \u0441\u0432\u0451\u0440\u043D\u0443\u0442\u0430\u044F \u043F\u043E\u043B\u043E\u0441\u0430 \u0432 Claude Desktop
16965
- \u043E\u0441\u0442\u0430\u0432\u043B\u044F\u043B\u0430 \u043F\u043E\u0434 \u043E\u0442\u0432\u0435\u0442\u043E\u043C \u043F\u0443\u0441\u0442\u0443\u044E \u0441\u0435\u0440\u0443\u044E \u043F\u043B\u0430\u0448\u043A\u0443. */
16966
- .card[hidden] { display: none; }
16967
- .card__meta { margin: 4px 0 0; color: var(--ink-soft); font-size: 12.5px; font-variant-numeric: tabular-nums; }
16968
- .card__meta[hidden] { display: none; }
16969
- /* \u041D\u043E\u0432\u043E\u0441\u0442\u044C \u043E \u0432\u0435\u0440\u0441\u0438\u0438 \u2014 \u0442\u0440\u0438 \u0441\u0442\u0440\u043E\u043A\u0438 \u0432\u043B\u0430\u0434\u0435\u043B\u044C\u0446\u0430: \u0447\u0442\u043E \u0432\u044B\u0448\u043B\u043E, \u0432\u043E\u043F\u0440\u043E\u0441, \u0447\u0442\u043E \u043D\u0430\u043F\u0438\u0441\u0430\u0442\u044C. */
16970
- #cardUpdate { white-space: pre-line; }
16971
- .parts { display: grid; gap: 2px 18px; margin: 14px 0 0; padding: 0; list-style: none; }
16972
- .parts[hidden] { display: none; }
16973
- .part {
16974
- display: flex;
16975
- align-items: center;
16976
- gap: 10px;
16977
- min-width: 0;
16978
- padding: 6px 0;
16979
- border-bottom: 1px solid var(--edge);
16980
- font-size: 14px;
16981
- line-height: 1.3;
16982
- }
16983
- /* \u0417\u043D\u0430\u043A \u0447\u0430\u0441\u0442\u0438 \u2014 \u0444\u043E\u0440\u043C\u0430, \u0430 \u043D\u0435 \u0442\u043E\u043B\u044C\u043A\u043E \u0446\u0432\u0435\u0442: \u0441\u0442\u043E\u0438\u0442 \u2014 \u0437\u0430\u043B\u0438\u0442\u044B\u0439 \u043A\u0440\u0443\u0436\u043E\u043A \u0441 \u0433\u0430\u043B\u043E\u0447\u043A\u043E\u0439,
16984
- \u043D\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442 \u2014 \u0436\u0451\u043B\u0442\u043E\u0435 \u043A\u043E\u043B\u044C\u0446\u043E, \u043F\u043E \u043F\u0440\u043E\u0441\u044C\u0431\u0435 \u2014 \u0433\u043E\u043B\u0443\u0431\u043E\u0435 \u043F\u0443\u043D\u043A\u0442\u0438\u0440\u043D\u043E\u0435. */
16985
- .part__m {
16986
- position: relative;
16987
- flex: none;
16988
- width: 16px;
16989
- height: 16px;
16990
- border-radius: 50%;
16991
- box-sizing: border-box;
16992
- }
16993
- .part.ok .part__m { background: var(--good); }
16994
- .part.ok .part__m::before {
16995
- content: "";
16996
- position: absolute;
16997
- top: 4px;
16998
- left: 4px;
16999
- width: 7px;
17000
- height: 3.5px;
17001
- border-left: 1.8px solid var(--good-ink);
17002
- border-bottom: 1.8px solid var(--good-ink);
17003
- transform: rotate(-45deg);
17004
- }
17005
- .part.missing .part__m { border: 2.5px solid var(--yellow); }
17006
- .part.later .part__m { border: 2px dashed var(--note-dot); }
17007
- .part__t { display: block; flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
17008
- .part.ok .part__t { color: var(--ink-soft); }
17009
- .part__w { flex: none; color: var(--ink-soft); font-size: 12.5px; font-variant-numeric: tabular-nums; }
17010
- .part.missing .part__w { color: var(--ink); font-weight: 650; }
17011
- /* \u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C \u0434\u0430\u043B\u044C\u0448\u0435 \u2014 \u043A\u0440\u0443\u043F\u043D\u0435\u0435 \u0441\u043F\u0438\u0441\u043A\u0430: \u044D\u0442\u043E \u043E\u0442\u0432\u0435\u0442 \u043D\u0430 \xAB\u0438 \u0447\u0442\u043E \u0442\u0435\u043F\u0435\u0440\u044C\xBB. */
17012
- .next {
17013
- display: flex;
17014
- align-items: flex-start;
17015
- gap: 9px;
17016
- margin: 14px 0 0;
17017
- font-size: 15px;
17018
- font-weight: 650;
17019
- line-height: 1.35;
17020
- letter-spacing: -0.01em;
17021
- }
17022
- .next[hidden] { display: none; }
17023
- .next::before {
17024
- content: "";
17025
- flex: none;
17026
- width: 8px;
17027
- height: 8px;
17028
- margin-top: 6px;
17029
- border-radius: 2px;
17030
- background: var(--yellow);
17031
- }
17032
-
17033
- /* \u2500\u2500\u2500 \u041A\u043E\u043D\u0435\u0446 \u0440\u0430\u0431\u043E\u0442\u044B \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
17034
-
17035
- /* \u26A0 \u041E\u0422\u0412\u0415\u0422 \u041A\u0420\u0423\u041F\u041D\u0415\u0415 \u0425\u041E\u0414\u0410. \u041E\u0442\u0431\u0440\u0430\u043A\u043E\u0432\u043A\u0430 \u0432\u043B\u0430\u0434\u0435\u043B\u044C\u0446\u0430 \u043D\u0430 \u0444\u043E\u0440\u043C\u0435 \u0432\u044B\u0431\u043E\u0440\u0430 2026-09-10:
17036
- \u0441\u0435\u0440\u0430\u044F \u0441\u0442\u0440\u043E\u0447\u043A\u0430 \u0432 \u0442\u043E\u043D \u043F\u043E\u0434\u0441\u043A\u0430\u0437\u043A\u0435 \u043D\u0435 \u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044F \u043A\u0430\u043A \u043E\u0442\u0432\u0435\u0442. \u0417\u0434\u0435\u0441\u044C \u0442\u043E \u0436\u0435: \u0447\u0435\u043B\u043E\u0432\u0435\u043A
17037
- \u0436\u0434\u0430\u043B \u043C\u0438\u043D\u0443\u0442\u044B \u0438 \u043E\u0431\u044F\u0437\u0430\u043D \u0443\u0432\u0438\u0434\u0435\u0442\u044C \u043A\u043E\u043D\u0435\u0446 \u0440\u0430\u0431\u043E\u0442\u044B \u0441 \u043F\u0435\u0440\u0432\u043E\u0433\u043E \u0432\u0437\u0433\u043B\u044F\u0434\u0430. */
17038
- .end { display: flex; align-items: flex-start; gap: 12px; margin-top: 18px; animation: drop .5s var(--ease); }
17039
- .end[hidden] { display: none; }
17040
- .end__m {
17041
- position: relative;
17042
- flex: none;
17043
- width: 34px;
17044
- height: 34px;
17045
- border-radius: 50%;
17046
- background: var(--good);
17047
- box-shadow: 0 6px 18px -8px var(--good);
17048
- /* \u26A0 \u0411\u0415\u0417 \u0417\u0410\u041B\u0418\u0412\u041A\u0418 \u041D\u0410\u0417\u0410\u0414: \u043D\u0430\u0440\u0438\u0441\u043E\u0432\u0430\u043D\u043D\u044B\u0439 \u0432 \u0441\u043A\u0440\u044B\u0442\u043E\u043C \u0431\u043B\u043E\u043A\u0435 \u0437\u043D\u0430\u043A \u0437\u0430\u043B\u0438\u043F\u0430\u043B \u0431\u044B
17049
- \u043F\u0440\u043E\u0437\u0440\u0430\u0447\u043D\u044B\u043C \u2014 \u0430\u043D\u0438\u043C\u0430\u0446\u0438\u044F \u0432 \u0441\u043A\u0440\u044B\u0442\u043E\u043C \u043E\u043A\u043D\u0435 \u043D\u0435 \u0441\u0442\u0430\u0440\u0442\u0443\u0435\u0442 (\u043D\u0430\u0448\u0451\u043B \u0441\u0442\u0435\u043D\u0434
17050
- 2026-09-12, \u0442\u0430 \u0436\u0435 \u0431\u0435\u0434\u0430 \u0431\u044B\u043B\u0430 \u0443 \u0441\u0442\u0440\u043E\u043A \u0444\u043E\u0440\u043C\u044B \u0432\u044B\u0431\u043E\u0440\u0430). */
17051
- animation: pop .55s var(--ease);
16983
+ return names.sort().reverse().map((name) => load(home, name.slice(0, -".json".length))).filter((record2) => record2 !== null);
16984
+ }
16985
+ function load(home, id) {
16986
+ if (!JOB_ID.test(id)) return null;
16987
+ try {
16988
+ const value = JSON.parse(readFileSync(join(home, JOBS_DIR, `${id}.json`), "utf8"));
16989
+ if (value.id !== id || typeof value.what !== "string" || typeof value.started !== "number" || !Array.isArray(value.stages) || typeof value.at !== "number" || typeof value.pid !== "number" || typeof value.beat !== "number") return null;
16990
+ return {
16991
+ id,
16992
+ what: value.what,
16993
+ started: value.started,
16994
+ stages: value.stages.map(String),
16995
+ at: value.at,
16996
+ message: typeof value.message === "string" ? value.message : "",
16997
+ ended: value.ended ?? null,
16998
+ pid: value.pid,
16999
+ beat: value.beat
17000
+ };
17001
+ } catch {
17002
+ return null;
17052
17003
  }
17053
- /* \u0413\u0430\u043B\u043E\u0447\u043A\u0430 \u043D\u0430\u0440\u0438\u0441\u043E\u0432\u0430\u043D\u0430 \u0434\u0432\u0443\u043C\u044F \u043A\u0440\u043E\u043C\u043A\u0430\u043C\u0438, \u0430 \u043D\u0435 \u043D\u0430\u0431\u0440\u0430\u043D\u0430 \u0441\u0438\u043C\u0432\u043E\u043B\u043E\u043C: \u044E\u043D\u0438\u043A\u043E\u0434\u043D\u0430\u044F \xAB\u2713\xBB \u0432
17054
- \u0441\u0438\u0441\u0442\u0435\u043C\u043D\u043E\u043C \u0448\u0440\u0438\u0444\u0442\u0435 \u043D\u0430 \u043A\u0430\u0436\u0434\u043E\u0439 \u043F\u043B\u0430\u0442\u0444\u043E\u0440\u043C\u0435 \u0441\u0432\u043E\u0435\u0439 \u0442\u043E\u043B\u0449\u0438\u043D\u044B \u0438 \u0432\u044B\u043B\u0435\u0437\u0430\u0435\u0442 \u0437\u0430 \u043A\u0440\u0443\u0436\u043E\u043A. */
17055
- .end__m::before {
17056
- content: "";
17057
- position: absolute;
17058
- top: 12px;
17059
- left: 10px;
17060
- width: 13px;
17061
- height: 7px;
17062
- border-left: 2.5px solid var(--good-ink);
17063
- border-bottom: 2.5px solid var(--good-ink);
17064
- transform: rotate(-45deg);
17004
+ }
17005
+ function alive(record2, clock) {
17006
+ if (clock() - record2.beat > STALE_MS) return false;
17007
+ try {
17008
+ process.kill(record2.pid, 0);
17009
+ return true;
17010
+ } catch (trouble) {
17011
+ return trouble.code === "EPERM";
17065
17012
  }
17066
- /* \u0423 \u0431\u0435\u0434\u044B \u0437\u043D\u0430\u043A \u0434\u0440\u0443\u0433\u043E\u0439 \u0444\u043E\u0440\u043C\u044B, \u0430 \u043D\u0435 \u0442\u043E\u0442 \u0436\u0435 \u043A\u0440\u0443\u0436\u043E\u043A \u0434\u0440\u0443\u0433\u043E\u0433\u043E \u0446\u0432\u0435\u0442\u0430: \u0446\u0432\u0435\u0442 \u043E\u0434\u0438\u043D
17067
- \u0447\u0438\u0442\u0430\u044E\u0442 \u043D\u0435 \u0432\u0441\u0435, \u0438 \u0432 \u0442\u0451\u043C\u043D\u043E\u0439 \u0442\u0435\u043C\u0435 \u0437\u0435\u043B\u0451\u043D\u043E\u0435 \u0441 \u043A\u0440\u0430\u0441\u043D\u044B\u043C \u0441\u0431\u043B\u0438\u0436\u0430\u044E\u0442\u0441\u044F. */
17068
- body.bad .end__m { background: var(--bad); box-shadow: 0 6px 18px -8px var(--bad); border-radius: 10px; }
17069
- body.bad .end__m::before {
17070
- top: 8px;
17071
- left: 16px;
17072
- width: 2.5px;
17073
- height: 12px;
17074
- border: 0;
17075
- border-radius: 2px;
17076
- background: var(--good-ink);
17077
- transform: none;
17013
+ }
17014
+ function save(work, clock) {
17015
+ if (work.home === null) return;
17016
+ try {
17017
+ const dir = join(work.home, JOBS_DIR);
17018
+ mkdirSync(dir, { recursive: true });
17019
+ const file2 = join(dir, `${work.id}.json`);
17020
+ const temp = `${file2}.${process.pid}.tmp`;
17021
+ const record2 = {
17022
+ id: work.id,
17023
+ what: work.what,
17024
+ started: work.started,
17025
+ stages: work.stages,
17026
+ at: work.at,
17027
+ message: work.message,
17028
+ ended: work.ended,
17029
+ pid: process.pid,
17030
+ beat: clock()
17031
+ };
17032
+ writeFileSync(temp, JSON.stringify(record2), "utf8");
17033
+ renameSync(temp, file2);
17034
+ } catch {
17078
17035
  }
17079
- /* \u0422\u043E\u0447\u043A\u0430 \u0432\u043E\u0441\u043A\u043B\u0438\u0446\u0430\u0442\u0435\u043B\u044C\u043D\u043E\u0433\u043E \u0437\u043D\u0430\u043A\u0430. \u0411\u0435\u0437 \u043D\u0435\u0451 \u043D\u0430 \u043A\u0440\u0443\u0436\u043A\u0435 \u0441\u0442\u043E\u0438\u0442 \u043F\u0440\u043E\u0441\u0442\u043E \u043F\u0430\u043B\u043A\u0430, \u0438
17080
- \u0437\u043D\u0430\u043A \u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044F \u043A\u0430\u043A \xAB\u0438\u0434\u0451\u0442 \u0437\u0430\u0433\u0440\u0443\u0437\u043A\u0430\xBB, \u0430 \u043D\u0435 \u043A\u0430\u043A \xAB\u0441\u0442\u043E\u0439, \u0442\u0443\u0442 \u0431\u0435\u0434\u0430\xBB. */
17081
- body.bad .end__m::after {
17082
- content: "";
17083
- position: absolute;
17084
- top: 23px;
17085
- left: 16px;
17086
- width: 2.5px;
17087
- height: 2.5px;
17088
- border-radius: 50%;
17089
- background: var(--good-ink);
17036
+ }
17037
+ function prune2(home) {
17038
+ try {
17039
+ const dir = join(home, JOBS_DIR);
17040
+ const names = readdirSync(dir).filter((name) => JOB_ID.test(name.replace(/\.json$/, ""))).sort();
17041
+ for (const name of names.slice(0, Math.max(0, names.length - JOBS_KEPT2))) rmSync(join(dir, name), { force: true });
17042
+ } catch {
17090
17043
  }
17091
- .end__x { display: block; padding-top: 2px; min-width: 0; }
17092
- .end__t { display: block; font-size: 17px; font-weight: 700; letter-spacing: -0.02em; line-height: 1.2; }
17093
- .end__h { display: block; margin-top: 4px; max-inline-size: 52ch; color: var(--ink-soft); font-size: 13px; line-height: 1.45; }
17094
- /* \u26A0 \u041F\u0423\u0422\u042C \u041A \u0424\u0410\u0419\u041B\u0423 \u041B\u041E\u041C\u0410\u0415\u0422\u0421\u042F \u041F\u041E \u041B\u042E\u0411\u041E\u041C\u0423 \u041C\u0415\u0421\u0422\u0423. \u0420\u0443\u0441\u0441\u043A\u0438\u0435 \u0438\u043C\u0435\u043D\u0430 \u043F\u0430\u043F\u043E\u043A \u0438 \u043F\u0440\u043E\u0431\u0435\u043B\u044B \u0432
17095
- \xAB\u041C\u043E\u0438 \u0432\u0438\u0434\u0435\u043E\xBB \u0438\u043D\u0430\u0447\u0435 \u0440\u0430\u0441\u043F\u0438\u0440\u0430\u044E\u0442 \u0431\u043B\u043E\u043A \u0438 \u0437\u0430\u0441\u0442\u0430\u0432\u043B\u044F\u044E\u0442 \u043B\u0435\u043D\u0442\u0443 \u0435\u0445\u0430\u0442\u044C \u0432\u0431\u043E\u043A. */
17096
- .path {
17097
- display: block;
17098
- margin-top: 6px;
17099
- padding: 7px 10px;
17100
- border-radius: 9px;
17101
- background: var(--card);
17102
- box-shadow: inset 0 0 0 1px var(--edge);
17103
- color: var(--ink);
17104
- font-size: 12.5px;
17105
- line-height: 1.4;
17106
- overflow-wrap: anywhere;
17044
+ }
17045
+ function fromDisk(home, id, clock) {
17046
+ const record2 = load(home, id);
17047
+ if (record2 === null) return null;
17048
+ if (record2.ended !== null || alive(record2, clock)) return record2;
17049
+ return {
17050
+ ...record2,
17051
+ ended: {
17052
+ at: record2.beat,
17053
+ ending: {
17054
+ ok: false,
17055
+ trouble: "\u041E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0435 \u043E\u0431\u043E\u0440\u0432\u0430\u043B\u043E\u0441\u044C: \u043F\u0440\u043E\u0433\u0440\u0430\u043C\u043C\u0430, \u043A\u043E\u0442\u043E\u0440\u0430\u044F \u0435\u0433\u043E \u0432\u0435\u043B\u0430, \u0437\u0430\u043A\u0440\u044B\u043B\u0430\u0441\u044C \u043F\u043E\u0441\u0440\u0435\u0434\u0438 \u0440\u0430\u0431\u043E\u0442\u044B. \u041F\u0440\u0435\u0436\u043D\u044F\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u043D\u0430 \u043C\u0435\u0441\u0442\u0435, \u043C\u043E\u043D\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u043C\u043E\u0436\u043D\u043E.",
17056
+ advice: "\u041D\u0430\u043F\u0438\u0448\u0438 \xAB\u043E\u0431\u043D\u043E\u0432\u0438\xBB \u0435\u0449\u0451 \u0440\u0430\u0437 \u2014 \u043D\u0430\u0447\u043D\u0443 \u0437\u0430\u043D\u043E\u0432\u043E.",
17057
+ report: `\u041F\u0440\u043E\u0446\u0435\u0441\u0441 \u043E\u0431\u043E\u043B\u043E\u0447\u043A\u0438 ${record2.pid}, \u043A\u043E\u0442\u043E\u0440\u044B\u0439 \u0432\u0451\u043B \u0437\u0430\u0434\u0430\u0447\u0443, \u043F\u0440\u043E\u043F\u0430\u043B \u043D\u0430 \u044D\u0442\u0430\u043F\u0435 \xAB${record2.stages[record2.at - 1] ?? CHECK}\xBB.`
17058
+ }
17059
+ }
17060
+ };
17061
+ }
17062
+ function startSetupJob(what, run, clock = Date.now, home = null) {
17063
+ const already = running(home, clock);
17064
+ if (already !== null) return already;
17065
+ const started = clock();
17066
+ const id = `${SETUP_JOB_MARK}${new Date(started).toISOString().replace(/[:.]/g, "-")}`;
17067
+ const work = {
17068
+ id,
17069
+ what,
17070
+ started,
17071
+ stages: [CHECK],
17072
+ at: 1,
17073
+ message: "",
17074
+ ended: null,
17075
+ done: Promise.resolve(),
17076
+ home
17077
+ };
17078
+ const control = {
17079
+ plan(stages) {
17080
+ work.stages = stages;
17081
+ work.at = Math.min(work.at, stages.length);
17082
+ save(work, clock);
17083
+ },
17084
+ go(stage) {
17085
+ const index = work.stages.indexOf(stage);
17086
+ if (index >= 0) work.at = index + 1;
17087
+ work.message = "";
17088
+ save(work, clock);
17089
+ },
17090
+ line(text2) {
17091
+ work.message = text2;
17092
+ save(work, clock);
17093
+ }
17094
+ };
17095
+ works.set(id, work);
17096
+ if (home !== null) prune2(home);
17097
+ save(work, clock);
17098
+ const beat = home === null ? null : setInterval(() => save(work, clock), BEAT_MS);
17099
+ beat?.unref();
17100
+ work.done = collectJobInstallFaults(id, () => run(control).catch((trouble) => {
17101
+ noteInstallFault("update-job", trouble);
17102
+ return {
17103
+ ok: false,
17104
+ trouble: "\u0427\u0442\u043E-\u0442\u043E \u0441\u043B\u043E\u043C\u0430\u043B\u043E\u0441\u044C \u043F\u043E\u0441\u0440\u0435\u0434\u0438 \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u044F \u2014 \u043F\u0440\u0435\u0436\u043D\u044F\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u043D\u0430 \u043C\u0435\u0441\u0442\u0435, \u043C\u043E\u043D\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u043C\u043E\u0436\u043D\u043E.",
17105
+ advice: ADVICE_ASK,
17106
+ report: String(trouble instanceof Error ? trouble.message : trouble)
17107
+ };
17108
+ })).then((ending) => {
17109
+ work.ended = { at: clock(), ending };
17110
+ if (beat !== null) clearInterval(beat);
17111
+ save(work, clock);
17112
+ });
17113
+ return id;
17114
+ }
17115
+ function quiet(line) {
17116
+ return line.replace(/^⚠\s*/, "").replace(/^Что делать:/, "\u0421\u043E\u0432\u0435\u0442:");
17117
+ }
17118
+ function setupJobText(id, clock = Date.now, home = null) {
17119
+ const work = works.get(id) ?? (home === null ? null : fromDisk(home, id, clock));
17120
+ if (work === null) return null;
17121
+ const head2 = `\u0417\u0430\u0434\u0430\u043D\u0438\u0435 ${work.id}: ${work.what}`;
17122
+ if (work.ended === null) {
17123
+ const sec2 = Math.max(0, Math.round((clock() - work.started) / 1e3));
17124
+ return [
17125
+ head2,
17126
+ `\u042D\u0442\u0430\u043F ${work.at} \u0438\u0437 ${work.stages.length}: ${work.stages[work.at - 1] ?? CHECK}`,
17127
+ ...work.message === "" ? [] : [work.message],
17128
+ `\u0415\u0449\u0451 \u0441\u0447\u0438\u0442\u0430\u0435\u0442, ${sec2} \u0441.`
17129
+ ].join("\n");
17107
17130
  }
17108
- .path[hidden] { display: none; }
17109
- /* pre-line, \u043F\u043E\u0442\u043E\u043C\u0443 \u0447\u0442\u043E \u0436\u0430\u043B\u043E\u0431 \u0431\u044B\u0432\u0430\u0435\u0442 \u043D\u0435\u0441\u043A\u043E\u043B\u044C\u043A\u043E, \u0438 \u043A\u0430\u0436\u0434\u0430\u044F \u0441\u0432\u043E\u044F \u0441\u0442\u0440\u043E\u043A\u0430: \u0441\u043B\u0438\u0442\u044B\u0435
17110
- \u0432 \u0430\u0431\u0437\u0430\u0446, \u043E\u043D\u0438 \u0447\u0438\u0442\u0430\u044E\u0442\u0441\u044F \u043A\u0430\u043A \u043E\u0434\u043D\u0430 \u0434\u043B\u0438\u043D\u043D\u0430\u044F \u0438 \u043F\u043E\u043B\u043E\u0432\u0438\u043D\u0430 \u0442\u0435\u0440\u044F\u0435\u0442\u0441\u044F. */
17111
- .warn { display: block; margin-top: 6px; white-space: pre-line; color: var(--ink-soft); font-size: 12.5px; line-height: 1.45; }
17112
- .warn[hidden] { display: none; }
17113
-
17114
- /* \u0421\u0442\u0440\u043E\u043A\u0430 \u0437\u0430\u043C\u0438\u043D\u043E\u043A: \xAB\u0441\u043F\u0440\u0430\u0448\u0438\u0432\u0430\u044E \u0435\u0449\u0451 \u0440\u0430\u0437\xBB, \xAB\u0445\u043E\u0441\u0442 \u043D\u0435 \u043E\u0442\u0432\u0435\u0442\u0438\u043B\xBB. \u041E\u0431\u044B\u0447\u043D\u044B\u043C\u0438
17115
- \u0447\u0435\u0440\u043D\u0438\u043B\u0430\u043C\u0438 \u2014 \u043F\u043E\u043A\u0440\u0430\u0441\u0438\u0442\u044C \u0437\u0430\u043C\u0438\u043D\u043A\u0443 \u0432 \u0444\u0438\u0440\u043C\u0435\u043D\u043D\u044B\u0439 \u0446\u0432\u0435\u0442 \u0437\u043D\u0430\u0447\u0438\u043B\u043E \u0431\u044B \u0441\u043E\u0432\u0440\u0430\u0442\u044C. */
17116
- .note {
17117
- margin-top: 12px;
17118
- padding: 9px 13px;
17119
- border-radius: 12px;
17120
- background: var(--bad-bg);
17121
- color: var(--ink);
17122
- font-size: 13px;
17123
- line-height: 1.4;
17131
+ const sec = Math.max(0, Math.round((work.ended.at - work.started) / 1e3));
17132
+ const ending = work.ended.ending;
17133
+ const report = ending.report.split("\n").map((line) => line.trim()).filter((line) => line !== "").map(quiet);
17134
+ if (ending.ok) {
17135
+ return [head2, `\u0413\u043E\u0442\u043E\u0432\u043E \u0437\u0430 ${sec} \u0441.`, `\u0427\u0435\u043B\u043E\u0432\u0435\u043A\u0443: ${ending.say}`, ...report].join("\n");
17124
17136
  }
17125
- .note[hidden] { display: none; }
17126
-
17127
- @keyframes drop { from { opacity: 0; transform: translateY(-14px); } to { opacity: 1; transform: none; } }
17128
- @keyframes pop { from { opacity: 0; transform: scale(.5); } to { opacity: 1; transform: none; } }
17129
- @keyframes pulse { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: .4; transform: scale(.75); } }
17130
- @keyframes breathe { 0%, 100% { opacity: 1; } 50% { opacity: .45; } }
17131
-
17132
- /* \u26A0 \u0414\u0412\u0418\u0416\u0415\u041D\u0418\u0415 \u041E\u0422\u041A\u041B\u042E\u0427\u0410\u0415\u0422\u0421\u042F \u0426\u0415\u041B\u0418\u041A\u041E\u041C, \u0410 \u041D\u0415 \u0423\u041A\u041E\u0420\u0410\u0427\u0418\u0412\u0410\u0415\u0422\u0421\u042F. \u041F\u043E\u043F\u0440\u043E\u0441\u0438\u0432\u0448\u0438\u0439 \u0441\u0438\u0441\u0442\u0435\u043C\u0443
17133
- \u043D\u0435 \u0434\u0432\u0438\u0433\u0430\u0442\u044C \u043A\u0430\u0440\u0442\u0438\u043D\u043A\u0443 \u043F\u0440\u043E\u0441\u0438\u043B \u043F\u0440\u043E \u0432\u0441\u0451 \u0441\u0440\u0430\u0437\u0443 \u2014 \u0438 \u043F\u0440\u043E \u043E\u0433\u043E\u043D\u0451\u043A, \u043A\u043E\u0442\u043E\u0440\u044B\u0439 \u0434\u044B\u0448\u0438\u0442
17134
- \u0437\u0434\u0435\u0441\u044C \u043C\u0438\u043D\u0443\u0442\u0430\u043C\u0438, \u0442\u0435\u043C \u0431\u043E\u043B\u0435\u0435. */
17135
- @media (prefers-reduced-motion: reduce) {
17136
- .now::before, .rail li.at, .end, .end__m { animation: none; }
17137
+ return [
17138
+ head2,
17139
+ ...report,
17140
+ `\u041D\u0435 \u043F\u043E\u043B\u0443\u0447\u0438\u043B\u043E\u0441\u044C \u0437\u0430 ${sec} \u0441: ${ending.trouble}`,
17141
+ `\u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C: ${ending.advice}`
17142
+ ].join("\n");
17143
+ }
17144
+ function setupJobReport(id, home = null) {
17145
+ const text2 = setupJobText(id, Date.now, home);
17146
+ return text2 === null ? null : readJob(text2);
17147
+ }
17148
+ function weightExact(bytes) {
17149
+ const mb = bytes / 1024 / 1024;
17150
+ if (mb >= 1e3) return `${(mb / 1024).toFixed(1).replace(".", ",")} \u0413\u0411`;
17151
+ return `${mb.toFixed(1).replace(".", ",")} \u041C\u0411`;
17152
+ }
17153
+ async function runUpdate(job, deps) {
17154
+ const { engine, key, baseUrl, what } = deps;
17155
+ const home = engine.home();
17156
+ const wantShell = what !== "engine";
17157
+ const hasEngine = engine.place() !== null;
17158
+ const wantEngine = what !== "shell" && hasEngine && !engine.pathSetByHand();
17159
+ const shellUrl = engine.variable("NAPARNIK_BUNDLE_MANIFEST") ?? bundleUrlFor(baseUrl);
17160
+ const [shellAsk, engineAsk] = await Promise.all([
17161
+ wantShell ? fetchShellManifest(shellUrl, deps.pointerMs, key) : Promise.resolve(null),
17162
+ wantEngine ? fetchManifest(manifestUrl(engine, baseUrl), deps.pointerMs, key) : Promise.resolve(null)
17163
+ ]);
17164
+ const shellWas = installedShell(home);
17165
+ const shell = decideShell(shellWas, shellAsk?.ok === true ? shellAsk.manifest : null);
17166
+ const engineWas = engine.freshVersion();
17167
+ const fresh = decide(engineWas, engineAsk?.ok === true ? engineAsk.manifest : null);
17168
+ const shellStage = shell.what === "newer_available" ? `\u0421\u043A\u0430\u0447\u0438\u0432\u0430\u044E \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u0435 \xB7 ${weightExact(shell.manifest.body?.bytes ?? 0)}` : null;
17169
+ const engineStage = fresh.what === "newer_available" ? `\u0421\u043A\u0430\u0447\u0438\u0432\u0430\u044E \u0434\u0432\u0438\u0436\u043E\u043A \xB7 ${weightExact(fresh.manifest.bytes)}` : null;
17170
+ const missing = what === "all" && engineStage === null;
17171
+ job.plan([
17172
+ CHECK,
17173
+ ...shellStage === null ? [] : [shellStage],
17174
+ ...engineStage === null ? [] : [engineStage, INSTALL_NEW],
17175
+ ...missing ? [MISSING] : []
17176
+ ]);
17177
+ const steps = [];
17178
+ let updated = false;
17179
+ let installed = false;
17180
+ for (const [ask2, whose] of [[shellAsk, "\u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F"], [engineAsk, "\u0434\u0432\u0438\u0436\u043A\u0430"]]) {
17181
+ if (ask2 === null || ask2.ok) continue;
17182
+ const refusal = refusalWords(ask2.status ?? 0);
17183
+ steps.push({
17184
+ report: `\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0441\u043F\u0440\u043E\u0441\u0438\u0442\u044C, \u0435\u0441\u0442\u044C \u043B\u0438 \u043D\u043E\u0432\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F ${whose}: ${ask2.why}.`,
17185
+ trouble: refusal !== "" ? refusal : "\u041D\u0435 \u043F\u043E\u043B\u0443\u0447\u0438\u043B\u043E\u0441\u044C \u0441\u0432\u044F\u0437\u0430\u0442\u044C\u0441\u044F \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u043E\u043C \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0439."
17186
+ });
17137
17187
  }
17138
-
17139
- /* \u2500\u2500\u2500 \u0428\u0438\u0440\u043E\u043A\u0438\u0439 \u044D\u043A\u0440\u0430\u043D \u0442\u043E\u043B\u044C\u043A\u043E \u0434\u043E\u043F\u0438\u0441\u044B\u0432\u0430\u0435\u0442 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
17140
-
17141
- @media (min-width: 560px) {
17142
- body { padding: 22px 20px 24px; }
17143
- h2 { font-size: 21px; }
17144
- .rail { gap: 5px; }
17145
- .parts { grid-template-columns: 1fr 1fr; }
17188
+ if (shellAsk?.ok === true && shell.what === "nothing") {
17189
+ steps.push({ report: `\u0423 \u0432\u0430\u0441 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u0430 \u0441\u0430\u043C\u0430\u044F \u043F\u043E\u0441\u043B\u0435\u0434\u043D\u044F\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u2014 ${shellWas}.` });
17146
17190
  }
17147
- @media (min-width: 760px) {
17148
- body { padding: 26px 24px 28px; }
17149
- h2 { font-size: 22px; }
17191
+ if (shell.what === "launcher_too_old") {
17192
+ steps.push({
17193
+ report: `\u041D\u043E\u0432\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F ${shell.manifest.version} \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043D\u043E\u0432\u043E\u0433\u043E \u0444\u0430\u0439\u043B\u0430 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F.`,
17194
+ trouble: `\u0414\u043B\u044F \u043D\u043E\u0432\u043E\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u043D\u0443\u0436\u0435\u043D \u043D\u043E\u0432\u044B\u0439 \u0444\u0430\u0439\u043B \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F. \u0412\u043E\u0437\u044C\u043C\u0438 \u0435\u0433\u043E \u0432 \u0442\u0435\u043B\u0435\u0433\u0440\u0430\u043C-\u0431\u043E\u0442\u0435 ${KEY_SOURCE_BOT}.`
17195
+ });
17150
17196
  }
17151
- </style>
17152
- </head>
17153
- <body>
17154
- <div class="head">
17155
- <h2 id="what" hidden></h2>
17156
- <span class="clock" id="clock" hidden></span>
17157
- </div>
17158
- <ol class="rail" id="rail" hidden></ol>
17159
- <div class="now" id="now">
17160
- <span>
17161
- <strong class="now__t" id="nowTitle">\u041D\u0430\u0447\u0438\u043D\u0430\u044E</strong>
17162
- <span class="now__c" id="nowLeft" hidden></span>
17163
- </span>
17164
- </div>
17165
- <div class="dl" id="dl" hidden>
17166
- <div class="meter" id="dlMeter"><span class="meter__fill" id="dlFill"></span></div>
17167
- <p class="meter__cap" id="dlCap"></p>
17168
- </div>
17169
- <div class="msg" id="msg" hidden></div>
17170
- <section class="card" id="card" hidden>
17171
- <p class="card__meta" id="cardMeta" hidden></p>
17172
- <div class="meter" id="cardMeter" hidden><span class="meter__fill" id="cardFill"></span></div>
17173
- <p class="meter__cap" id="cardCap" hidden></p>
17174
- <ul class="parts" id="cardRows" hidden></ul>
17175
- <div class="msg" id="cardUpdate" hidden></div>
17176
- <div class="note" id="cardTrouble" hidden></div>
17177
- <p class="next" id="cardNext" hidden></p>
17178
- </section>
17179
- <div class="end" id="end" hidden>
17180
- <span class="end__m" aria-hidden="true"></span>
17181
- <span class="end__x">
17182
- <strong class="end__t" id="endTitle"></strong>
17183
- <span class="end__h" id="endHint"></span>
17184
- <span class="path" id="path" hidden></span>
17185
- <span class="warn" id="warn" hidden></span>
17186
- </span>
17187
- </div>
17188
- <div class="note" id="note" hidden></div>
17189
- <script>
17190
- (function () {
17191
- // \u26A0 \u041A\u0410\u041A \u0427\u0410\u0421\u0422\u041E \u0421\u041F\u0420\u0410\u0428\u0418\u0412\u0410\u0422\u042C. \u041A\u0430\u0436\u0434\u044B\u0439 \u043E\u043F\u0440\u043E\u0441 \u2014 \u0437\u0430\u043F\u0443\u0441\u043A \u043F\u0438\u0442\u043E\u043D\u0430 \u043D\u0430 \u043C\u0430\u0448\u0438\u043D\u0435 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430,
17192
- // \u0438 \u0447\u0430\u0449\u0435 \u0434\u0432\u0443\u0445 \u0441\u0435\u043A\u0443\u043D\u0434 \u044D\u0442\u043E \u043E\u0442\u043D\u0438\u043C\u0430\u043B\u043E \u0431\u044B \u044F\u0434\u0440\u043E \u0443 \u0441\u0430\u043C\u043E\u0433\u043E \u043C\u043E\u043D\u0442\u0430\u0436\u0430. \u0420\u0435\u0436\u0435 \u043F\u044F\u0442\u0438 \u2014
17193
- // \u0438 \u043F\u043E\u043B\u043E\u0441\u0430 \u043E\u0442\u0441\u0442\u0430\u0451\u0442 \u043E\u0442 \u0440\u0430\u0431\u043E\u0442\u044B \u043D\u0430\u0441\u0442\u043E\u043B\u044C\u043A\u043E, \u0447\u0442\u043E \u0447\u0435\u043B\u043E\u0432\u0435\u043A \u0441\u043D\u043E\u0432\u0430 \u0441\u043C\u043E\u0442\u0440\u0438\u0442 \u0432 \u0442\u0438\u0448\u0438\u043D\u0443.
17194
- var POLL_MS = 2500;
17195
- // \u0421\u043A\u043E\u043B\u044C\u043A\u043E \u043F\u043E\u0434\u0440\u044F\u0434 \u043D\u0435\u0443\u0434\u0430\u0447 \u0442\u0435\u0440\u043F\u0438\u043C, \u043F\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043C \u0441\u043A\u0430\u0437\u0430\u0442\u044C \u0441\u043B\u043E\u0432\u0430\u043C\u0438. \u041E\u0434\u043D\u0430 \u043D\u0435\u0443\u0434\u0430\u0447\u0430 \u2014
17196
- // \u044D\u0442\u043E \u043D\u043E\u0440\u043C\u0430: \u043E\u043F\u0440\u043E\u0441 \u0437\u0430\u043F\u0443\u0441\u043A\u0430\u0435\u0442 \u043F\u043E\u0434\u043F\u0440\u043E\u0446\u0435\u0441\u0441, \u0438 \u043E\u043D \u043C\u043E\u0436\u0435\u0442 \u043D\u0435 \u0443\u0434\u0430\u0442\u044C\u0441\u044F \u043F\u043E \u0441\u043B\u0443\u0447\u0430\u0439\u043D\u043E\u0439
17197
- // \u043F\u0440\u0438\u0447\u0438\u043D\u0435 (\u0430\u043D\u0442\u0438\u0432\u0438\u0440\u0443\u0441, \u043D\u0435\u0445\u0432\u0430\u0442\u043A\u0430 \u043F\u0430\u043C\u044F\u0442\u0438, \u0433\u043E\u043D\u043A\u0430 \u0437\u0430 \u0444\u0430\u0439\u043B\u043E\u043C \u0437\u0430\u0434\u0430\u043D\u0438\u044F).
17198
- var GIVE_UP_AFTER = 5;
17199
- var CONTRACT = '${JOB_CONTRACT}';
17200
- var SETUP = '${SETUP_CONTRACT}';
17201
-
17202
- var nextId = 1;
17203
- // Object.create(null), \u0430 \u043D\u0435 {}: \u0438\u043D\u0430\u0447\u0435 id \u0432\u0438\u0434\u0430 \xABtoString\xBB \u0434\u043E\u0441\u0442\u0430\u0451\u0442 \u0444\u0443\u043D\u043A\u0446\u0438\u044E \u0441
17204
- // \u043F\u0440\u043E\u0442\u043E\u0442\u0438\u043F\u0430, \u0438 \u043E\u0442\u0432\u0435\u0442 \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044F \u043E\u0436\u0438\u0434\u0430\u0435\u043C\u044B\u043C \u043D\u0430 \u043F\u0443\u0441\u0442\u043E\u043C \u043C\u0435\u0441\u0442\u0435.
17205
- var waiting = Object.create(null);
17206
- function send(method, params, onReply) {
17207
- var id = nextId++;
17208
- if (onReply) waiting[id] = onReply;
17209
- window.parent.postMessage({ jsonrpc: '2.0', id: id, method: method, params: params }, '*');
17210
- return id;
17197
+ if (fresh.what === "shell_too_old") {
17198
+ steps.push({
17199
+ report: `\u041D\u043E\u0432\u0430\u044F \u043D\u0430\u0447\u0438\u043D\u043A\u0430 ${fresh.manifest.version} \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F \u043D\u0435 \u0441\u0442\u0430\u0440\u0448\u0435 ${fresh.manifest.minShellVersion}.`,
17200
+ trouble: "\u041D\u043E\u0432\u043E\u043C\u0443 \u0434\u0432\u0438\u0436\u043A\u0443 \u043D\u0443\u0436\u043D\u043E \u043D\u043E\u0432\u043E\u0435 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u0435 \u2014 \u0435\u0433\u043E \u043F\u043E\u043A\u0430 \u043D\u0435\u0442 \u043D\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435."
17201
+ });
17211
17202
  }
17212
- function notify(method, params) {
17213
- window.parent.postMessage({ jsonrpc: '2.0', method: method, params: params }, '*');
17203
+ if (shell.what === "newer_available" && shellStage !== null) {
17204
+ job.go(shellStage);
17205
+ const outcome = await installShell({ home, manifest: shell.manifest, key: key ?? null });
17206
+ if (outcome.ok) {
17207
+ updated = true;
17208
+ steps.push({ report: outcome.text });
17209
+ } else {
17210
+ steps.push({ report: outcome.text, trouble: "\u041D\u043E\u0432\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F \u043D\u0435 \u0432\u0441\u0442\u0430\u043B\u0430 \u2014 \u0440\u0430\u0431\u043E\u0442\u0430\u0435\u0442 \u043F\u0440\u0435\u0436\u043D\u044F\u044F." });
17211
+ }
17214
17212
  }
17215
- function byId(id) { return document.getElementById(id); }
17216
- function reportSize() {
17217
- notify('ui/notifications/size-changed', { height: document.documentElement.scrollHeight });
17213
+ if (fresh.what === "newer_available" && engineStage !== null) {
17214
+ job.go(engineStage);
17215
+ const outcome = await deploy(engine, fresh.manifest, void 0, key, {
17216
+ line: (text2) => job.line(text2),
17217
+ downloaded: () => {
17218
+ job.go(INSTALL_NEW);
17219
+ job.line("\u0421\u043E\u0431\u0438\u0440\u0430\u044E \u043E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u0435 \u043D\u043E\u0432\u043E\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u2014 \u044D\u0442\u043E \u0434\u043E \u043F\u0430\u0440\u044B \u043C\u0438\u043D\u0443\u0442.");
17220
+ }
17221
+ });
17222
+ if (outcome.ok) {
17223
+ updated = true;
17224
+ steps.push({ report: outcome.text });
17225
+ } else {
17226
+ const cause = causeOf(outcome.text);
17227
+ steps.push({
17228
+ report: outcome.text,
17229
+ trouble: `\u041D\u043E\u0432\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u0434\u0432\u0438\u0436\u043A\u0430 \u043D\u0435 \u0432\u0441\u0442\u0430\u043B\u0430${cause === "" ? "" : `: ${cause}`}. \u0420\u0430\u0431\u043E\u0442\u0430\u0435\u0442 \u043F\u0440\u0435\u0436\u043D\u044F\u044F${engineWas === null ? "" : ` ${engineWas}`}, \u043C\u043E\u043D\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u043C\u043E\u0436\u043D\u043E.`
17230
+ });
17231
+ }
17218
17232
  }
17219
- function show(id, text) {
17220
- var el = byId(id);
17221
- if (!el) return;
17222
- el.textContent = text || '';
17223
- el.hidden = !text;
17233
+ if (missing) {
17234
+ job.go(MISSING);
17235
+ const step = await deliverMissing(job, deps);
17236
+ if (step.trouble === void 0 && step.installed) installed = true;
17237
+ steps.push(step);
17224
17238
  }
17225
-
17226
- // \u2500\u2500\u2500 \u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u0435 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
17227
- var job = null;
17228
- // \u26A0 \u0422\u0420\u0418 \u0420\u0410\u0417\u041D\u042B\u0425 \xAB\u0421\u0422\u041E\u041F\xBB, \u0418 \u041F\u0423\u0422\u0410\u0422\u042C \u0418\u0425 \u041D\u0415\u041B\u042C\u0417\u042F. closed \u2014 \u0432\u0438\u0434\u0436\u0435\u0442 \u0437\u0430\u043A\u0440\u044B\u043B\u0438, \u0431\u043E\u043B\u044C\u0448\u0435
17229
- // \u043D\u0435 \u0440\u0438\u0441\u0443\u0435\u043C \u0432\u043E\u0432\u0441\u0435. done \u2014 \u0440\u0430\u0431\u043E\u0442\u0430 \u043A\u043E\u043D\u0447\u0438\u043B\u0430\u0441\u044C, \u0441\u043F\u0440\u0430\u0448\u0438\u0432\u0430\u0442\u044C \u043D\u0435 \u043E \u0447\u0435\u043C. fails \u2014
17230
- // \u0441\u0447\u0451\u0442\u0447\u0438\u043A \u043F\u043E\u0434\u0440\u044F\u0434 \u0438\u0434\u0443\u0449\u0438\u0445 \u043D\u0435\u0443\u0434\u0430\u0447 \u043E\u043F\u0440\u043E\u0441\u0430.
17231
- var closed = false;
17232
- var fails = 0;
17233
- function working(s) { return s === 'running' || s === 'waiting'; }
17234
-
17235
- function later() {
17236
- if (closed) return;
17237
- if (!job || !job.id || !working(job.status)) return;
17238
- setTimeout(poll, POLL_MS);
17239
+ const report = steps.map((step) => step.report).join("\n");
17240
+ const trouble = steps.find((step) => step.trouble !== void 0)?.trouble;
17241
+ if (trouble !== void 0) return { ok: false, trouble, advice: ADVICE_ASK, report };
17242
+ if (updated) return { ok: true, say: SAY_RESTART, report };
17243
+ return { ok: true, say: installed ? SAY_INSTALLED : SAY_NOTHING, report };
17244
+ }
17245
+ function causeOf(text2) {
17246
+ const line = text2.split("\n").map((one) => one.trim()).find((one) => one !== "" && !/^(Новая версия|Версия) \S+ не встала/.test(one) && !/^Что делать:/.test(one)) ?? "";
17247
+ const phrase = (line.split(/\.\s|\s—\s|;\s/)[0] ?? "").replace(/\s*\([^)]*\)/g, "").replace(/\.$/, "").trim();
17248
+ return phrase === "" ? "" : phrase[0].toLowerCase() + phrase.slice(1);
17249
+ }
17250
+ async function deliverMissing(job, deps) {
17251
+ const answer = await deps.installMissing();
17252
+ if (answer.type === "error") {
17253
+ return { report: answer.error, trouble: "\u041D\u0435 \u043F\u043E\u043B\u0443\u0447\u0438\u043B\u043E\u0441\u044C \u043F\u043E\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u043D\u0435\u0434\u043E\u0441\u0442\u0430\u044E\u0449\u0435\u0435.", installed: false };
17239
17254
  }
17240
-
17241
- // \u26A0 \u041F\u041E\u041B\u041E\u0421\u0410 \u0421\u041F\u0420\u0410\u0428\u0418\u0412\u0410\u0415\u0422 \u0421\u0410\u041C\u0410, \u0418 \u042D\u0422\u041E \u0413\u041B\u0410\u0412\u041D\u041E\u0415 \u0412 \u041D\u0415\u0419. \u0418\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442 \u043E\u0442\u0432\u0435\u0442\u0438\u043B \u043D\u043E\u043C\u0435\u0440\u043E\u043C
17242
- // \u0437\u0430\u0434\u0430\u0447\u0438 \u0438 \u0443\u043C\u043E\u043B\u043A \u2014 \u0434\u0435\u0440\u0436\u0430\u0442\u044C \u0432\u044B\u0437\u043E\u0432 \u043E\u0442\u043A\u0440\u044B\u0442\u044B\u043C \u043C\u0438\u043D\u0443\u0442\u0430\u043C\u0438 MCP \u043D\u0435 \u0434\u0430\u0451\u0442. \u041C\u043E\u0434\u0435\u043B\u044C \u043F\u0440\u0438
17243
- // \u044D\u0442\u043E\u043C \u043D\u0435 \u0442\u0440\u0430\u0442\u0438\u0442 \u0445\u043E\u0434: \u043E\u0442\u0432\u0435\u0442 \u043D\u0430 tools/call \u0443\u0445\u043E\u0434\u0438\u0442 \u0412\u0418\u0414\u0416\u0415\u0422\u0423, \u0430 \u043D\u0435 \u0432 \u0440\u0430\u0437\u0433\u043E\u0432\u043E\u0440.
17244
- function poll() {
17245
- if (closed || !job || !job.id) return;
17246
- // \u26A0 seconds: 0 \u2014 \xAB\u041E\u0422\u0412\u0415\u0422\u042C \u041A\u0410\u041A \u0415\u0421\u0422\u042C\xBB, \u0418 \u0411\u0415\u0417 \u041D\u0415\u0413\u041E \u041F\u041E\u041B\u041E\u0421\u0410 \u0412\u0421\u0422\u0410\u0401\u0422. \u0423 wait \u0431\u0435\u0437
17247
- // \u044D\u0442\u043E\u0433\u043E \u043A\u043B\u044E\u0447\u0430 \u043E\u0436\u0438\u0434\u0430\u043D\u0438\u0435 \u0434\u043B\u0438\u0442\u0441\u044F \u0434\u043E 55 \u0441\u0435\u043A\u0443\u043D\u0434: \u0442\u0430\u043A \u043E\u043D \u0438 \u0434\u043E\u043B\u0436\u0435\u043D \u0440\u0430\u0431\u043E\u0442\u0430\u0442\u044C,
17248
- // \u043A\u043E\u0433\u0434\u0430 \u0435\u0433\u043E \u0437\u043E\u0432\u0451\u0442 \u043C\u043E\u0434\u0435\u043B\u044C \u2014 \xAB\u0441\u043F\u0440\u043E\u0441\u0438 \u0435\u0449\u0451 \u0440\u0430\u0437\xBB \u0441\u0442\u043E\u0438\u0442 \u0435\u0439 \u0446\u0435\u043B\u043E\u0433\u043E \u0445\u043E\u0434\u0430. \u0410
17249
- // \u043F\u043E\u043B\u043E\u0441\u0430 \u0441\u043F\u0440\u0430\u0448\u0438\u0432\u0430\u0435\u0442 \u0421\u0410\u041C\u0410 \u043A\u0430\u0436\u0434\u044B\u0435 2,5 \u0441\u0435\u043A\u0443\u043D\u0434\u044B, \u0438 \u0431\u043B\u043E\u043A\u0438\u0440\u0443\u044E\u0449\u0438\u0439 \u0432\u044B\u0437\u043E\u0432 \u043E\u0437\u043D\u0430\u0447\u0430\u043B
17250
- // \u0431\u044B \u043E\u0434\u043D\u0443 \u043F\u0435\u0440\u0435\u0440\u0438\u0441\u043E\u0432\u043A\u0443 \u0432 \u043C\u0438\u043D\u0443\u0442\u0443 \u0432\u043C\u0435\u0441\u0442\u043E \u0434\u0432\u0430\u0434\u0446\u0430\u0442\u0438 \u0447\u0435\u0442\u044B\u0440\u0451\u0445.
17251
- send('tools/call', { name: 'wait', arguments: { job: job.id, seconds: 0 } }, function (m) {
17252
- if (closed) return;
17253
- if (m.error) return stumble('\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0441\u043F\u0440\u043E\u0441\u0438\u0442\u044C \u043E \u0440\u0430\u0431\u043E\u0442\u0435: ' + ((m.error && m.error.message) || '\u0445\u043E\u0441\u0442 \u043F\u0440\u043E\u043C\u043E\u043B\u0447\u0430\u043B'));
17254
- var answer = m.result || {};
17255
- // \u041E\u0442\u043A\u0430\u0437 \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u0430 \u2014 \u044D\u0442\u043E \u043E\u0442\u0432\u0435\u0442, \u0430 \u043D\u0435 \u0441\u0431\u043E\u0439: \u0434\u0432\u0438\u0436\u043E\u043A \u043E\u0431\u044A\u044F\u0441\u043D\u044F\u0435\u0442 \u0441\u043B\u043E\u0432\u0430\u043C\u0438,
17256
- // \u0438 \u0447\u0435\u043B\u043E\u0432\u0435\u043A \u043E\u0431\u044F\u0437\u0430\u043D \u0438\u0445 \u043F\u0440\u043E\u0447\u0438\u0442\u0430\u0442\u044C, \u0430 \u043D\u0435 \u0441\u043C\u043E\u0442\u0440\u0435\u0442\u044C \u0432 \u043F\u0443\u0441\u0442\u0443\u044E \u043F\u043E\u043B\u043E\u0441\u0443.
17257
- if (answer.isError) return finishWithWords(words(answer));
17258
- var data = answer.structuredContent;
17259
- if (!data || data.contract !== CONTRACT) return stumble('\u041E\u0442\u0432\u0435\u0442 \u043E \u0440\u0430\u0431\u043E\u0442\u0435 \u043F\u0440\u0438\u0448\u0451\u043B \u043D\u0435 \u0442\u043E\u0442. \u0421\u043F\u0440\u043E\u0441\u0438\u0442\u0435 \u041A\u043B\u043E\u0434\u0430, \u0447\u0442\u043E \u0441 \u0437\u0430\u0434\u0430\u0447\u0435\u0439.');
17260
- fails = 0;
17261
- byId('note').hidden = true;
17262
- render(data);
17263
- later();
17264
- });
17265
- // \u0425\u043E\u0441\u0442 \u043C\u043E\u0436\u0435\u0442 \u043D\u0435 \u043E\u0442\u0432\u0435\u0442\u0438\u0442\u044C \u0432\u043E\u0432\u0441\u0435. \u0416\u0434\u0451\u043C \u0432\u0434\u0432\u043E\u0435 \u0434\u043E\u043B\u044C\u0448\u0435 \u043E\u043F\u0440\u043E\u0441\u0430 \u0438 \u043F\u0440\u043E\u0431\u0443\u0435\u043C \u0441\u043D\u043E\u0432\u0430:
17266
- // \u043C\u043E\u043B\u0447\u0430\u043D\u0438\u0435 \u043E\u0434\u043D\u043E\u0433\u043E \u043A\u0440\u0443\u0433\u0430 \u2014 \u043D\u0435 \u043F\u043E\u0432\u043E\u0434 \u0431\u0440\u043E\u0441\u0430\u0442\u044C \u0440\u0430\u0431\u043E\u0442\u0443, \u043A\u043E\u0442\u043E\u0440\u0430\u044F \u0438\u0434\u0451\u0442.
17267
- var mine = nextId - 1;
17268
- setTimeout(function () {
17269
- if (closed || !waiting[mine]) return;
17270
- delete waiting[mine];
17271
- stumble('\u041E\u0442\u0432\u0435\u0442\u0430 \u043E \u0440\u0430\u0431\u043E\u0442\u0435 \u043D\u0435\u0442. \u0421\u043F\u0440\u0430\u0448\u0438\u0432\u0430\u044E \u0435\u0449\u0451 \u0440\u0430\u0437.');
17272
- }, POLL_MS * 2);
17255
+ const words = typeof answer.content === "string" ? answer.content : answer.content.map((block) => block.type === "text" ? block.text : "").join("\n");
17256
+ const id = typeof answer.structured?.["id"] === "string" ? answer.structured["id"] : "";
17257
+ if (id === "") return { report: words, installed: false };
17258
+ const pace = deps.pace ?? realPace;
17259
+ let state = await deps.engine.command(["job", id]);
17260
+ while (state.ok && stillWorking(state.text)) {
17261
+ const now = readJob(state.text);
17262
+ if (now !== null) job.line(now.message !== "" ? now.message : now.now);
17263
+ await pace.rest(POLL_EVERY_MS);
17264
+ state = await deps.engine.command(["job", id]);
17273
17265
  }
17274
-
17275
- /** \u0417\u0430\u043C\u0438\u043D\u043A\u0430: \u0433\u043E\u0432\u043E\u0440\u0438\u043C \u0441\u043B\u043E\u0432\u0430\u043C\u0438 \u0438 \u043F\u0440\u043E\u0431\u0443\u0435\u043C \u0441\u043D\u043E\u0432\u0430, \u043F\u043E\u043A\u0430 \u043D\u0435 \u043A\u043E\u043D\u0447\u0438\u0442\u0441\u044F \u0442\u0435\u0440\u043F\u0435\u043D\u0438\u0435. */
17276
- function stumble(text) {
17277
- fails++;
17278
- if (fails >= GIVE_UP_AFTER) {
17279
- show('note', '\u041D\u0435 \u043F\u043E\u043B\u0443\u0447\u0430\u0435\u0442\u0441\u044F \u0443\u0437\u043D\u0430\u0442\u044C, \u0447\u0442\u043E \u0441 \u0440\u0430\u0431\u043E\u0442\u043E\u0439. \u041E\u043D\u0430 \u0438\u0434\u0451\u0442 \u0441\u0430\u043C\u0430 \u0438 \u043D\u0438\u043A\u0443\u0434\u0430 \u043D\u0435 \u0434\u0435\u043D\u0435\u0442\u0441\u044F \u2014 \u0441\u043F\u0440\u043E\u0441\u0438\u0442\u0435 \u041A\u043B\u043E\u0434\u0430: \xAB\u0447\u0442\u043E \u0441 \u0437\u0430\u0434\u0430\u0447\u0435\u0439 ' + (job && job.id ? job.id : '') + '\xBB.');
17280
- reportSize();
17281
- return;
17282
- }
17283
- show('note', text);
17284
- reportSize();
17285
- later();
17266
+ const end = state.ok ? readJob(state.text) : null;
17267
+ if (end === null || end.status !== "done") {
17268
+ return {
17269
+ report: `${words}
17270
+ ${state.text}`,
17271
+ trouble: end?.trouble !== void 0 && end.trouble !== "" ? end.trouble : "\u041D\u0435 \u043F\u043E\u043B\u0443\u0447\u0438\u043B\u043E\u0441\u044C \u043F\u043E\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u043D\u0435\u0434\u043E\u0441\u0442\u0430\u044E\u0449\u0435\u0435.",
17272
+ installed: false
17273
+ };
17286
17274
  }
17275
+ return { report: `${words}
17276
+ ${state.text}`, installed: true };
17277
+ }
17287
17278
 
17288
- /** \u0422\u0435\u043A\u0441\u0442 \u043E\u0442\u0432\u0435\u0442\u0430 \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u0430 \u2014 \u0442\u043E, \u0447\u0442\u043E \u043F\u0440\u0435\u0434\u043D\u0430\u0437\u043D\u0430\u0447\u0435\u043D\u043E \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0443 \u0438 \u043C\u043E\u0434\u0435\u043B\u0438. */
17289
- function words(answer) {
17290
- var blocks = (answer && answer.content) || [];
17291
- var text = '';
17292
- for (var i = 0; i < blocks.length; i++) {
17293
- if (blocks[i].type === 'text') text += (text ? ' ' : '') + blocks[i].text;
17294
- }
17295
- return text;
17279
+ // src/setup-tool.ts
17280
+ var ASKED_POINTER_MS = 15e3;
17281
+ var NEWS_POINTER_MS = 5e3;
17282
+ 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.";
17283
+ async function inspectMachine(engine, asked) {
17284
+ const video = asked.video;
17285
+ const model = asked.model;
17286
+ const place = engine.place();
17287
+ if (place === null) return { result: toolError(engine.whyNoEngine()), readiness: null };
17288
+ const args = [
17289
+ "env-check",
17290
+ "--pack",
17291
+ place.pack,
17292
+ ...video !== void 0 ? ["--video", path(video)] : [],
17293
+ ...model !== void 0 ? ["--model", model] : []
17294
+ ];
17295
+ let readiness = null;
17296
+ let words;
17297
+ if (knowsJsonCheck(place.engine)) {
17298
+ const answer = await askReadiness(engine, place, args);
17299
+ if ("ok" in answer && !answer.ok) return { result: toolError(answer.text), readiness: null };
17300
+ if ("parts" in answer) readiness = answer;
17301
+ words = "parts" in answer ? answer.words : answer.text;
17302
+ } else {
17303
+ const outcome = await engine.command(args);
17304
+ if (!outcome.ok) return { result: toolError(outcome.text), readiness: null };
17305
+ words = outcome.text;
17296
17306
  }
17307
+ const catalog = await askCatalog(engine, place.pack, video);
17308
+ return { result: toolSuccess(`${words}
17297
17309
 
17298
- // \u2500\u2500\u2500 \u0440\u0438\u0441\u043E\u0432\u0430\u043D\u0438\u0435 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
17299
-
17300
- /** \xAB3 \u043C\u0438\u043D 20 \u0441\xBB, \xAB45 \u0441\xBB \u2014 \u0432\u0440\u0435\u043C\u044F \u0441\u043B\u043E\u0432\u0430\u043C\u0438, \u0430 \u043D\u0435 \u0433\u043E\u043B\u044B\u043C \u0447\u0438\u0441\u043B\u043E\u043C \u0441\u0435\u043A\u0443\u043D\u0434. */
17301
- function howLong(sec) {
17302
- var s = Math.max(0, Math.round(Number(sec) || 0));
17303
- if (s < 60) return s + ' \u0441';
17304
- var m = Math.floor(s / 60);
17305
- var rest = s % 60;
17306
- return m + ' \u043C\u0438\u043D' + (rest ? ' ' + rest + ' \u0441' : '');
17310
+ ${catalog}`), readiness };
17311
+ }
17312
+ async function askReadiness(engine, place, args) {
17313
+ const python = await engine.pythonTrouble();
17314
+ if (python !== null) return { ok: false, text: python };
17315
+ let stdout;
17316
+ try {
17317
+ stdout = (await engine.run(place, [...args, JSON_CHECK])).stdout;
17318
+ } catch (err) {
17319
+ const e = err;
17320
+ if (e.code !== 2 || typeof e.stdout !== "string") return parseFailure(err, "\u041F\u0440\u043E\u0432\u0435\u0440\u043A\u0430 \u043C\u0430\u0448\u0438\u043D\u044B \u043D\u0435 \u0432\u044B\u043F\u043E\u043B\u043D\u0438\u043B\u0430\u0441\u044C");
17321
+ stdout = e.stdout;
17307
17322
  }
17308
-
17309
- // \u26A0 \u041B\u0415\u0421\u0422\u041D\u0418\u0426\u0410 \u0420\u0418\u0421\u0423\u0415\u0422\u0421\u042F \u041F\u041E \u041E\u0422\u0412\u0415\u0422\u0423 \u0414\u0412\u0418\u0416\u041A\u0410, \u0410 \u041D\u0415 \u041F\u0420\u0418\u0411\u0418\u0422\u0410 \u0417\u0414\u0415\u0421\u042C. \u042D\u0442\u0430\u043F\u043E\u0432 \u0431\u044B\u0432\u0430\u0435\u0442
17310
- // \u0440\u0430\u0437\u043D\u043E\u0435 \u0447\u0438\u0441\u043B\u043E: \u0443 \u043C\u043E\u043D\u0442\u0430\u0436\u0430 \u0438\u0445 \u0434\u043E \u043E\u0434\u0438\u043D\u043D\u0430\u0434\u0446\u0430\u0442\u0438, \u0443 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0438 \u0442\u0440\u0438, \u0443 \xAB\u0442\u043E\u043B\u044C\u043A\u043E
17311
- // \u043F\u0430\u0443\u0437\u044B\xBB \u043E\u0434\u0438\u043D. \u0421\u0432\u043E\u0439 \u0441\u043F\u0438\u0441\u043E\u043A \u0440\u0430\u0437\u043E\u0448\u0451\u043B\u0441\u044F \u0431\u044B \u0441 \u043D\u0430\u0441\u0442\u043E\u044F\u0449\u0438\u043C \u043D\u0430 \u043F\u0435\u0440\u0432\u043E\u043C \u043D\u043E\u0432\u043E\u043C \u0448\u0430\u0433\u0435.
17312
- function rail(at, total, ended) {
17313
- var root = byId('rail');
17314
- if (!root) return;
17315
- root.innerHTML = '';
17316
- if (!total || total < 1) { root.hidden = true; return; }
17317
- for (var i = 1; i <= total; i++) {
17318
- var li = document.createElement('li');
17319
- // \u041A\u043E\u043D\u0447\u0438\u0432\u0448\u0430\u044F\u0441\u044F \u0440\u0430\u0431\u043E\u0442\u0430 \u043D\u0435 \u0434\u0435\u0440\u0436\u0438\u0442 \xAB\u0438\u0434\u0443\u0449\u0435\u0433\u043E\xBB \u044D\u0442\u0430\u043F\u0430: \u0436\u0451\u043B\u0442\u0430\u044F \u043F\u043E\u043B\u043E\u0441\u043A\u0430 \u0440\u044F\u0434\u043E\u043C \u0441\u043E
17320
- // \u0441\u043B\u043E\u0432\u043E\u043C \xAB\u0413\u043E\u0442\u043E\u0432\u043E\xBB \u0447\u0438\u0442\u0430\u043B\u0430\u0441\u044C \u0431\u044B \u043A\u0430\u043A \xAB\u0435\u0449\u0451 \u0447\u0442\u043E-\u0442\u043E \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044F\xBB.
17321
- li.className = ended ? 'was' : (i < at ? 'was' : (i === at ? 'at' : ''));
17322
- root.appendChild(li);
17323
+ return readReadiness(stdout) ?? { ok: true, text: stdout.trim() };
17324
+ }
17325
+ async function installStep(engine, asked, key, baseUrl, tell) {
17326
+ const step = asked.step;
17327
+ const model = asked.model;
17328
+ const consent = asked.consent;
17329
+ if (engine.place() === null) {
17330
+ let candidate = readCandidate(engine.versionsDir());
17331
+ if (candidate === null) {
17332
+ if (tell !== void 0) for (const line of PAYLOAD_LADDER) tell(line);
17333
+ const result = await installPayload(engine, {
17334
+ consent,
17335
+ manifestUrl: manifestUrl(engine, baseUrl),
17336
+ ...key !== void 0 ? { key } : {}
17337
+ });
17338
+ if (!result.ok) return toolError(result.text);
17339
+ candidate = readCandidate(engine.versionsDir());
17340
+ if (candidate === null) {
17341
+ return toolError("\u041D\u0430\u0447\u0438\u043D\u043A\u0430 \u0441\u043A\u0430\u0447\u0430\u043B\u0430\u0441\u044C \u0431\u0435\u0437 \u0443\u043A\u0430\u0437\u0430\u0442\u0435\u043B\u044F \u043A\u0430\u043D\u0434\u0438\u0434\u0430\u0442\u0430 \u2014 current \u043D\u0435 \u043C\u0435\u043D\u044F\u043B. \u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C: \u043F\u043E\u0432\u0442\u043E\u0440\u0438\u0442\u0435 setup.");
17342
+ }
17323
17343
  }
17324
- root.hidden = false;
17325
- }
17326
-
17327
- function render(data) {
17328
- if (closed) return;
17329
- job = data;
17330
- // \u0414\u0430\u043D\u043D\u044B\u0435 \u043F\u0440\u0438\u0448\u043B\u0438 \u043F\u043E\u0441\u043B\u0435 \u0441\u0432\u0451\u0440\u0442\u043A\u0438 \u2014 \u0432\u043E\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043C\u0441\u044F \u0432 \u043B\u0435\u043D\u0442\u0443.
17331
- document.body.classList.remove('gone');
17332
- byId('card').hidden = true;
17333
- var ended = !working(data.status);
17334
-
17335
- // \u26A0 \u041E\u0411\u0429\u0415\u0419 \u0417\u0410\u0413\u041B\u0423\u0428\u041A\u0418 \xAB\u0420\u0410\u0411\u041E\u0422\u0410\u042E\xBB \u041D\u0415\u0422 (\u0432\u043B\u0430\u0434\u0435\u043B\u0435\u0446 2026-09-24): \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A \u2014 \u0441\u0440\u0430\u0437\u0443
17336
- // \u043D\u0430\u0437\u0432\u0430\u043D\u0438\u0435 \u0440\u0430\u0431\u043E\u0442\u044B, \u0430 \u043D\u0435 \u0441\u043B\u043E\u0432\u043E, \u043A\u043E\u0442\u043E\u0440\u043E\u0435 \u043D\u0438\u0447\u0435\u0433\u043E \u043D\u0435 \u0433\u043E\u0432\u043E\u0440\u0438\u0442.
17337
- show('what', data.what || '');
17338
- var clock = byId('clock');
17339
- if (clock) {
17340
- clock.textContent = (ended ? '' : '\u0438\u0434\u0451\u0442 ') + howLong(data.sec);
17341
- // \u26A0 \u041D\u0410 \u041D\u0423\u041B\u0415 \u0427\u0410\u0421\u042B \u041C\u041E\u041B\u0427\u0410\u0422. \xAB\u0438\u0434\u0451\u0442 0 \u0441\xBB \u2014 \u044D\u0442\u043E \u043D\u0435 \u043E\u0442\u0432\u0435\u0442 \u043D\u0430 \xAB\u0441\u043A\u043E\u043B\u044C\u043A\u043E \u0443\u0436\u0435
17342
- // \u0440\u0430\u0431\u043E\u0442\u0430\u0435\u0442\xBB, \u0430 \u043C\u0443\u0441\u043E\u0440 \u0432 \u0448\u0430\u043F\u043A\u0435: \u0434\u0432\u0438\u0436\u043E\u043A \u0435\u0449\u0451 \u043D\u0435 \u043E\u0442\u043C\u0435\u0442\u0438\u043B \u043D\u0430\u0447\u0430\u043B\u0430.
17343
- clock.hidden = !data.sec;
17344
+ if (!consent) {
17345
+ return toolError(
17346
+ `\u041A\u0430\u043D\u0434\u0438\u0434\u0430\u0442 ${candidate.version} \u0443\u0436\u0435 \u043F\u043E\u0434\u0433\u043E\u0442\u043E\u0432\u043B\u0435\u043D, \u043D\u043E \u0435\u0449\u0451 \u043D\u0435 \u0440\u0430\u0431\u043E\u0447\u0438\u0439. \u0421\u043F\u0440\u043E\u0441\u0438 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043D\u0438\u0435 \u0441\u043E\u0431\u0440\u0430\u0442\u044C \u0435\u0433\u043E \u043E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u0435 \u0438 \u043F\u043E\u0437\u043E\u0432\u0438 setup \u0441 consent=true.`
17347
+ );
17344
17348
  }
17345
- rail(Number(data.at) || 0, Number(data.total) || 0, ended);
17349
+ const extras = step === "all" ? "later" : "now";
17350
+ const activated = await continuePreparedCandidate(engine, candidate, void 0, extras);
17351
+ if (!activated.ok) return toolError(activated.text);
17352
+ engine.forgetPlace();
17353
+ engine.forgetPython();
17354
+ if (step === "python") return toolSuccess(activated.text);
17355
+ if (step === "all") {
17356
+ const ready = `${activated.text}
17357
+ \u041A\u0430\u043D\u0434\u0438\u0434\u0430\u0442 \u043F\u043E\u0441\u0442\u0430\u0432\u0438\u043B \u0431\u0438\u0431\u043B\u0438\u043E\u0442\u0435\u043A\u0438 \u043F\u043E \u0441\u0432\u043E\u0435\u043C\u0443 \u0437\u0430\u043C\u043A\u0443 \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.`;
17358
+ const later = await installStep(engine, asked, key, baseUrl, tell);
17359
+ if (later.type === "error") {
17360
+ return toolSuccess(
17361
+ `${ready}
17346
17362
 
17347
- var now = byId('now');
17348
- if (now) now.hidden = ended;
17349
- if (!ended) {
17350
- var title = data.now || (data.status === 'waiting' ? '\u0416\u0434\u0443, \u043F\u043E\u043A\u0430 \u0437\u0430\u043A\u043E\u043D\u0447\u0438\u0442\u0441\u044F \u0434\u0440\u0443\u0433\u0430\u044F \u0440\u0430\u0431\u043E\u0442\u0430' : '\u041D\u0430\u0447\u0438\u043D\u0430\u044E');
17351
- if (data.at && data.total) title = title + ' \xB7 ' + data.at + ' \u0438\u0437 ' + data.total;
17352
- show('nowTitle', title);
17353
- show('nowLeft', data.left || '');
17354
- var loading = download(data);
17355
- // \u0421\u043A\u0430\u0447\u0438\u0432\u0430\u043D\u0438\u0435 \u0443\u0436\u0435 \u0441\u043A\u0430\u0437\u0430\u043D\u043E \u0448\u043A\u0430\u043B\u043E\u0439 \u0438 \u043F\u043E\u0434\u043F\u0438\u0441\u044C\u044E \u043F\u043E\u0434 \u043D\u0435\u0439 \u2014 \u0442\u0430 \u0436\u0435 \u0441\u0442\u0440\u043E\u043A\u0430
17356
- // \u0433\u043E\u043B\u0443\u0431\u043E\u0439 \u043F\u043B\u0430\u0448\u043A\u043E\u0439 \u0440\u044F\u0434\u043E\u043C \u0431\u044B\u043B\u0430 \u0431\u044B \u0432\u0442\u043E\u0440\u044B\u043C \u044D\u043A\u0437\u0435\u043C\u043F\u043B\u044F\u0440\u043E\u043C \u043E\u0434\u043D\u0438\u0445 \u0438 \u0442\u0435\u0445 \u0436\u0435 \u0447\u0438\u0441\u0435\u043B.
17357
- show('msg', data.status === 'waiting' || loading ? '' : (data.message || ''));
17358
- } else {
17359
- byId('msg').hidden = true;
17360
- byId('dl').hidden = true;
17363
+ \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}
17364
+ \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.`
17365
+ );
17366
+ }
17367
+ return together([toolSuccess(`${ready}
17368
+ ${EXTRAS_LATER}`), later]);
17361
17369
  }
17362
-
17363
- // \u26A0 \xAB\u041F\u041E\u0417\u0410\u0414\u0418\xBB \u0418 \xAB\u0414\u0410\u041B\u042C\u0428\u0415\xBB \u041D\u0415 \u0420\u0418\u0421\u0423\u042E\u0422\u0421\u042F (\u0432\u043B\u0430\u0434\u0435\u043B\u0435\u0446 2026-09-24): \u043F\u043E\u0434 \u043D\u0430\u0437\u0432\u0430\u043D\u0438\u0435\u043C
17364
- // \u044D\u0442\u0430\u043F\u0430 \u0438 \u0448\u043A\u0430\u043B\u043E\u0439 \u043E\u043D\u0438 \u0431\u044B\u043B\u0438 \u0442\u0440\u0435\u0442\u044C\u0438\u043C \u0438 \u0447\u0435\u0442\u0432\u0451\u0440\u0442\u044B\u043C \u0440\u0430\u0441\u0441\u043A\u0430\u0437\u043E\u043C \u043E\u0431 \u043E\u0434\u043D\u043E\u043C \u0438 \u0442\u043E\u043C \u0436\u0435.
17365
- // \u041E\u0442\u0447\u0451\u0442 \u0438\u0445 \u043F\u043E-\u043F\u0440\u0435\u0436\u043D\u0435\u043C\u0443 \u043D\u0435\u0441\u0451\u0442 \u2014 \u0441\u0442\u0440\u043E\u043A\u0438 \u043D\u0443\u0436\u043D\u044B \u043C\u043E\u0434\u0435\u043B\u0438, \u0430 \u043D\u0435 \u044D\u043A\u0440\u0430\u043D\u0443.
17366
-
17367
- if (ended) finish(data);
17368
- else { byId('end').hidden = true; document.body.classList.remove('bad'); }
17369
- reportSize();
17370
17370
  }
17371
-
17372
- /**
17373
- * \u0417\u0430\u0433\u043B\u0430\u0432\u043D\u0430\u044F \u0443 \u0440\u0443\u0441\u0441\u043A\u043E\u0433\u043E \u043D\u0430\u0437\u0432\u0430\u043D\u0438\u044F \u0447\u0430\u0441\u0442\u0438, \u0430 \u0438\u043C\u044F \u043F\u0440\u043E\u0433\u0440\u0430\u043C\u043C\u044B \u2014 \u043A\u0430\u043A \u0435\u0441\u0442\u044C.
17374
- *
17375
- * \u26A0 \u041D\u0415 CSS \xABfirst-letter\xBB. \u041D\u0430\u0437\u0432\u0430\u043D\u0438\u044F \u0447\u0430\u0441\u0442\u0435\u0439 \u043F\u0438\u0448\u0435\u0442 \u0434\u0432\u0438\u0436\u043E\u043A \u0441\u0442\u0440\u043E\u0447\u043D\u044B\u043C\u0438: \u043E\u043D\u0438 \u0436\u0435
17376
- * \u0438\u0434\u0443\u0442 \u0432 \u0435\u0433\u043E \u043E\u0442\u0432\u0435\u0442 \u043C\u043E\u0434\u0435\u043B\u0438 \u0441\u0435\u0440\u0435\u0434\u0438\u043D\u043E\u0439 \u0444\u0440\u0430\u0437\u044B. \u041D\u043E \xABffmpeg\xBB \u2014 \u0438\u043C\u044F \u043F\u0440\u043E\u0433\u0440\u0430\u043C\u043C\u044B, \u0438
17377
- * \u043F\u0440\u0430\u0432\u0438\u043B\u043E \u0434\u043B\u044F \u0432\u0441\u0435\u0445 \u043F\u0435\u0440\u0432\u044B\u0445 \u0431\u0443\u043A\u0432 \u0434\u0435\u043B\u0430\u043B\u043E \u0438\u0437 \u043D\u0435\u0433\u043E \xABFfmpeg\xBB (\u0441\u043D\u0438\u043C\u043E\u043A 2026-09-24).
17378
- */
17379
- function capital(text) {
17380
- var s = String(text || '');
17381
- return /^[\u0430-\u044F\u0451]/.test(s) ? s.charAt(0).toUpperCase() + s.slice(1) : s;
17371
+ const place = engine.place();
17372
+ if (place === null) return toolError(engine.whyNoEngine());
17373
+ if (consent && await engine.pythonTrouble() !== null) {
17374
+ try {
17375
+ await engine.bringPython(place);
17376
+ } catch (trouble) {
17377
+ return toolError(`\u041F\u0438\u0442\u043E\u043D \u043C\u043E\u043D\u0442\u0430\u0436\u0430 \u043F\u043E\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C: ${describeFailure(trouble)}. \u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C: \u043F\u043E\u0432\u0442\u043E\u0440\u0438 setup.`);
17378
+ }
17382
17379
  }
17383
-
17384
- /** \xAB245 \u041C\u0411\xBB, \xAB1,6 \u0413\u0411\xBB \u2014 \u043A\u0430\u043A \u0432 \u0441\u043B\u043E\u0432\u0430\u0445 setup, \u0430 \u043D\u0435 \u0433\u043E\u043B\u044B\u043C \u0447\u0438\u0441\u043B\u043E\u043C \u043C\u0435\u0433\u0430\u0431\u0430\u0439\u0442. */
17385
- function weight(mb) {
17386
- var n = Math.max(0, Math.round(Number(mb) || 0));
17387
- if (n >= 1000) return (n / 1024).toFixed(1).replace('.', ',') + ' \u0413\u0411';
17388
- return n + ' \u041C\u0411';
17380
+ const common = [
17381
+ "--pack",
17382
+ place.pack,
17383
+ "--step",
17384
+ step,
17385
+ ...model !== void 0 ? ["--model", model] : [],
17386
+ ...consent ? ["--consent"] : []
17387
+ ];
17388
+ if (!LONG_STEPS.has(step)) return asToolResult(await engine.command(["env-install", ...common]));
17389
+ const python = await engine.pythonTrouble();
17390
+ if (python !== null) return toolError(python);
17391
+ if (tell !== void 0) for (const line of installLadder(step)) tell(line);
17392
+ const launch = await engine.background({
17393
+ place,
17394
+ executable: engine.enginePython(),
17395
+ // Установка берёт тот же слот тяжёлой работы, а на слоте стоит заслон
17396
+ // подписки в самом движке — без ключа она откажет платящему.
17397
+ key,
17398
+ startJob: [
17399
+ "install-create",
17400
+ "--pack",
17401
+ place.pack,
17402
+ "--step",
17403
+ step,
17404
+ ...model !== void 0 ? ["--model", model] : []
17405
+ ],
17406
+ args: (id) => [place.consolePy, "env-install", ...common, "--job", id],
17407
+ advice: "\u043F\u043E\u0437\u043E\u0432\u0438 setup \u2014 \u0441\u043A\u043E\u0440\u0435\u0435 \u0432\u0441\u0435\u0433\u043E, \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0430 \u043D\u0435\u043F\u043E\u043B\u043D\u0430\u044F"
17408
+ });
17409
+ if ("refusal" in launch) return toolError(launch.refusal);
17410
+ return toolSuccess(
17411
+ `\u0417\u0430\u0434\u0430\u0447\u0430 ${launch.id}: ${installTitle(step)} (\u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0430, \u0448\u0430\u0433 \xAB${step}\xBB).
17412
+ \u0418\u0434\u0451\u0442 \u043D\u0430 \u043A\u043E\u043C\u043F\u044C\u044E\u0442\u0435\u0440\u0435 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F \u0438 \u043F\u0435\u0440\u0435\u0436\u0438\u0432\u0430\u0435\u0442 \u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u043A \u043F\u0440\u043E\u0433\u0440\u0430\u043C\u043C\u044B. \u041F\u043E\u0437\u043E\u0432\u0438 wait \u0441 job "${launch.id}" \u2014 \u043E\u043D \u043F\u043E\u0434\u043E\u0436\u0434\u0451\u0442 \u0438 \u043F\u043E \u0445\u043E\u0434\u0443 \u0440\u0430\u0441\u0441\u043A\u0430\u0436\u0435\u0442, \u0441\u043A\u043E\u043B\u044C\u043A\u043E \u0441\u043A\u0430\u0447\u0430\u043D\u043E \u0438 \u043E \u0447\u0451\u043C \u043D\u0430\u0434\u043E \u0441\u043F\u0440\u043E\u0441\u0438\u0442\u044C \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430. \u041F\u0435\u0440\u0435\u0441\u043A\u0430\u0437\u044B\u0432\u0430\u0439 \u044D\u0442\u043E \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0443 \u0441\u0440\u0430\u0437\u0443, \u0430 \u043D\u0435 \u0432 \u043A\u043E\u043D\u0446\u0435. ${AWAY_NOTE}`,
17413
+ startedJob({
17414
+ id: launch.id,
17415
+ what: installTitle(step),
17416
+ ahead: installLadder(step).join(" "),
17417
+ message: "\u0418\u0434\u0451\u0442 \u043C\u0438\u043D\u0443\u0442\u0430\u043C\u0438: \u043A\u0430\u0447\u0430\u0435\u0442\u0441\u044F \u0438 \u0441\u043E\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044F \u0442\u043E, \u0447\u0435\u043C \u043C\u043E\u043D\u0442\u0438\u0440\u0443\u0435\u0442\u0441\u044F \u0432\u0438\u0434\u0435\u043E."
17418
+ })
17419
+ );
17420
+ }
17421
+ function tenths(bytes) {
17422
+ return Math.round(bytes / 1024 / 1024 * 10) / 10;
17423
+ }
17424
+ async function updateEngine(engine, consent, key, baseUrl, timeoutMs = ASKED_POINTER_MS, seen = () => {
17425
+ }) {
17426
+ if (engine.pathSetByHand()) {
17427
+ return toolSuccess(
17428
+ "\u041F\u0430\u043F\u043A\u0430 \u0434\u0432\u0438\u0436\u043A\u0430 \u0437\u0430\u0434\u0430\u043D\u0430 \u0432\u0440\u0443\u0447\u043D\u0443\u044E \u043F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u043E\u0439 NAPARNIK_ENGINE \u2014 \u043E\u0431\u043D\u043E\u0432\u043B\u044F\u0442\u044C \u043D\u0435\u0447\u0435\u0433\u043E: \u0441\u0430\u043C\u043E\u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0435 \u0440\u0430\u0431\u043E\u0442\u0430\u0435\u0442 \u0441 \u0432\u0435\u0440\u0441\u0438\u043E\u043D\u043D\u043E\u0439 \u0440\u0430\u0441\u043A\u043B\u0430\u0434\u043A\u043E\u0439 \u0432 ~/.naparnik/engine, \u0430 \u044D\u0442\u0430 \u043F\u0430\u043F\u043A\u0430 \u043C\u0438\u043C\u043E \u043D\u0435\u0451. \u0421\u043A\u0430\u0436\u0438 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0443, \u0447\u0442\u043E \u0434\u0432\u0438\u0436\u043E\u043A \u0437\u0434\u0435\u0441\u044C \u043E\u0431\u043D\u043E\u0432\u043B\u044F\u0435\u0442\u0441\u044F \u0442\u0435\u043C \u0436\u0435 \u0441\u043F\u043E\u0441\u043E\u0431\u043E\u043C, \u043A\u0430\u043A\u0438\u043C \u0431\u044B\u043B \u043F\u043E\u043B\u043E\u0436\u0435\u043D."
17429
+ );
17430
+ }
17431
+ if (engine.place() === null) {
17432
+ return toolSuccess(
17433
+ "\u0414\u0432\u0438\u0436\u043A\u0430 \u043C\u043E\u043D\u0442\u0430\u0436\u0430 \u043D\u0430 \u044D\u0442\u043E\u043C \u043A\u043E\u043C\u043F\u044C\u044E\u0442\u0435\u0440\u0435 \u0435\u0449\u0451 \u043D\u0435\u0442 \u2014 \u043E\u0431\u043D\u043E\u0432\u043B\u044F\u0442\u044C \u043D\u0435\u0447\u0435\u0433\u043E.\n\u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C: \u043F\u043E\u0437\u043E\u0432\u0438 setup \u0441 what=all, \u043E\u043D \u0441\u043A\u0430\u0447\u0430\u0435\u0442 \u043D\u0430\u0447\u0438\u043D\u043A\u0443 \u0441 \u043D\u0443\u043B\u044F (\u0441\u043A\u0430\u0447\u0438\u0432\u0430\u043D\u0438\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0441\u043E\u0433\u043B\u0430\u0441\u0438\u044F \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430)."
17434
+ );
17435
+ }
17436
+ const outcome = await fetchManifest(manifestUrl(engine, baseUrl), timeoutMs, key);
17437
+ const decision = decide(engine.freshVersion(), outcome.ok ? outcome.manifest : null);
17438
+ seen({
17439
+ installed: engine.freshVersion(),
17440
+ fresh: decision.what === "nothing" ? null : decision.manifest.version,
17441
+ mb: decision.what === "nothing" ? 0 : tenths(decision.manifest.bytes),
17442
+ status: outcome.ok ? 0 : outcome.status ?? 0,
17443
+ notes: ""
17444
+ });
17445
+ if (decision.what === "nothing") {
17446
+ const ownDir2 = engine.freshVersion();
17447
+ return toolSuccess(
17448
+ !outcome.ok ? `\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0441\u043F\u0440\u043E\u0441\u0438\u0442\u044C, \u0435\u0441\u0442\u044C \u043B\u0438 \u043D\u043E\u0432\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u043D\u0430\u0447\u0438\u043D\u043A\u0438: ${outcome.why}. \u042D\u0442\u043E \u043D\u0435 \u043F\u043E\u043B\u043E\u043C\u043A\u0430: \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u043D\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F (${ownDir2 ?? "\u043D\u0435 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u0430"}) \u0440\u0430\u0431\u043E\u0442\u0430\u0435\u0442 \u043A\u0430\u043A \u0440\u0430\u0431\u043E\u0442\u0430\u043B\u0430.` : `\u041D\u0430\u0447\u0438\u043D\u043A\u0430 \u0441\u0432\u0435\u0436\u0430\u044F: \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u0430 ${ownDir2 ?? "\u043D\u0435\u0442"}, \u043D\u043E\u0432\u0435\u0435 \u043D\u0435 \u0432\u044B\u0448\u043B\u043E.`
17449
+ );
17389
17450
  }
17390
-
17391
- function fill(id, percent) {
17392
- var el = byId(id);
17393
- if (el) el.style.width = Math.max(0, Math.min(100, Number(percent) || 0)) + '%';
17451
+ if (decision.what === "shell_too_old") {
17452
+ return toolSuccess(
17453
+ `\u041D\u043E\u0432\u0430\u044F \u043D\u0430\u0447\u0438\u043D\u043A\u0430 ${decision.manifest.version} \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F \u043D\u0435 \u0441\u0442\u0430\u0440\u0448\u0435 ${decision.manifest.minShellVersion}, \u0430 \u0441\u0442\u043E\u0438\u0442 ${VERSION}. \u0421\u043A\u0430\u0436\u0438 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0443, \u0447\u0442\u043E \u0441\u043D\u0430\u0447\u0430\u043B\u0430 \u043D\u0430\u0434\u043E \u043E\u0431\u043D\u043E\u0432\u0438\u0442\u044C \u0441\u0430\u043C\u043E \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u0435 \u041D\u0430\u043F\u0430\u0440\u043D\u0438\u043A\u0430, \u0438 \u0442\u043E\u043B\u044C\u043A\u043E \u043F\u043E\u0442\u043E\u043C \u043D\u0430\u0447\u0438\u043D\u043A\u0443. \u0421\u0442\u0430\u0432\u0438\u0442\u044C \u043D\u0435 \u0441\u0442\u0430\u043B.`
17454
+ );
17394
17455
  }
17395
-
17396
- /**
17397
- * \u0428\u043A\u0430\u043B\u0430 \u0441\u043A\u0430\u0447\u0438\u0432\u0430\u043D\u0438\u044F \u043F\u043E \u0447\u0438\u0441\u043B\u0430\u043C \u0437\u0430\u0434\u0430\u0447\u0438. \u0412\u0435\u0440\u043D\u0451\u0442, \u043D\u0430\u0440\u0438\u0441\u043E\u0432\u0430\u043D\u0430 \u043B\u0438 \u043E\u043D\u0430.
17398
- *
17399
- * \u26A0 \u0411\u0415\u0417 \xAB\u0418\u0417 \u0421\u041A\u041E\u041B\u042C\u041A\u0418\u0425\xBB \u0417\u0410\u041B\u0418\u0412\u041A\u0418 \u041D\u0415\u0422, \u0410 \u041F\u041E\u0414\u041F\u0418\u0421\u042C \u0415\u0421\u0422\u042C. \u0412\u0441\u0435\u0433\u043E \u0434\u0432\u0438\u0436\u043E\u043A \u0437\u043D\u0430\u0435\u0442 \u043D\u0435
17400
- * \u0432\u0441\u0435\u0433\u0434\u0430; \u0437\u0430\u043B\u0438\u0442\u044C \u043D\u0430\u0443\u0433\u0430\u0434 \u2014 \u0441\u043E\u0432\u0440\u0430\u0442\u044C \u043E \u0434\u043E\u043B\u0435, \u0430 \u043C\u0435\u0433\u0430\u0431\u0430\u0439\u0442\u044B \u043F\u0440\u0430\u0432\u0434\u0438\u0432\u044B.
17401
- */
17402
- function download(data) {
17403
- var box = byId('dl');
17404
- if (!box) return false;
17405
- var got = Number(data.got) || 0;
17406
- if (!got) { box.hidden = true; return false; }
17407
- var of = Number(data.of) || 0;
17408
- byId('dlMeter').hidden = !of;
17409
- fill('dlFill', of ? data.percent : 0);
17410
- var cap = byId('dlCap');
17411
- cap.innerHTML = '';
17412
- var b = document.createElement('b');
17413
- b.textContent = of ? (got + ' \u0438\u0437 ' + weight(of)) : ('\u0441\u043A\u0430\u0447\u0430\u043D\u043E ' + weight(got));
17414
- cap.appendChild(b);
17415
- var tail = of ? ' \xB7 ' + (Number(data.percent) || 0) + '%' : '';
17416
- if (data.eta) tail += ' \xB7 ' + data.eta;
17417
- cap.appendChild(document.createTextNode(tail));
17418
- cap.hidden = false;
17419
- box.hidden = false;
17420
- return true;
17456
+ if (!consent) {
17457
+ const mb = (decision.manifest.bytes / 1024 / 1024).toFixed(1);
17458
+ return toolSuccess(
17459
+ `\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.
17460
+ ${VOICE_CLEANER_NOTE}
17461
+ \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.`
17462
+ );
17421
17463
  }
17422
-
17423
- // \u2500\u2500\u2500 \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0430 \u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u044F \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
17424
-
17425
- /**
17426
- * \u041E\u0442\u0432\u0435\u0442 setup \u0431\u0435\u0437 \u0437\u0430\u0434\u0430\u0447\u0438: \u0447\u0442\u043E \u0441\u0442\u043E\u0438\u0442, \u0447\u0435\u0433\u043E \u043D\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442, \u0447\u0442\u043E \u0432\u044B\u0448\u043B\u043E, \u0447\u0442\u043E \u0434\u0430\u043B\u044C\u0448\u0435.
17427
- *
17428
- * \u26A0 \u041E\u041F\u0420\u041E\u0421 \u041D\u0415 \u0417\u0410\u0412\u041E\u0414\u0418\u0422\u0421\u042F: \u0440\u0430\u0431\u043E\u0442\u044B \u043D\u0435\u0442, \u0441\u043F\u0440\u0430\u0448\u0438\u0432\u0430\u0442\u044C \u043D\u0435 \u043E \u0447\u0435\u043C. \u041A\u0430\u0440\u0442\u043E\u0447\u043A\u0430 \u2014 \u0441\u043D\u0438\u043C\u043E\u043A
17429
- * \u043D\u0430 \u043C\u043E\u043C\u0435\u043D\u0442 \u043E\u0442\u0432\u0435\u0442\u0430; \u043D\u043E\u0432\u044B\u0439 \u0432\u044B\u0437\u043E\u0432 setup \u043F\u0440\u0438\u043D\u0435\u0441\u0451\u0442 \u043D\u043E\u0432\u0443\u044E.
17430
- */
17431
- function renderCard(data) {
17432
- if (closed) return;
17433
- job = null;
17434
- document.body.classList.remove('gone');
17435
- document.body.classList.remove('bad');
17436
- var hide = ['now', 'rail', 'msg', 'dl', 'clock', 'end', 'note'];
17437
- for (var i = 0; i < hide.length; i++) { var el = byId(hide[i]); if (el) el.hidden = true; }
17438
-
17439
- var rows = data.rows || [];
17440
- var ok = 0, need = 0;
17441
- for (var j = 0; j < rows.length; j++) {
17442
- if (rows[j].state === 'ok') { ok++; need++; }
17443
- else if (rows[j].state === 'missing') need++;
17464
+ return asToolResult(await deploy(engine, decision.manifest, void 0, key));
17465
+ }
17466
+ async function updateShell(engine, consent, key, baseUrl, timeoutMs = ASKED_POINTER_MS, seen = () => {
17467
+ }) {
17468
+ const home = engine.home();
17469
+ const url2 = engine.variable("NAPARNIK_BUNDLE_MANIFEST") ?? bundleUrlFor(baseUrl);
17470
+ const outcome = await fetchShellManifest(url2, timeoutMs, key);
17471
+ const installed = installedShell(home);
17472
+ const decision = decideShell(installed, outcome.ok ? outcome.manifest : null);
17473
+ seen({
17474
+ installed,
17475
+ fresh: decision.what === "nothing" ? null : decision.manifest.version,
17476
+ mb: decision.what === "nothing" ? 0 : tenths(decision.manifest.body?.bytes ?? 0),
17477
+ status: outcome.ok ? 0 : outcome.status ?? 0,
17478
+ notes: decision.what === "nothing" ? "" : decision.manifest.notes ?? ""
17479
+ });
17480
+ if (decision.what === "nothing") {
17481
+ if (!outcome.ok) {
17482
+ return toolSuccess(
17483
+ `\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0441\u043F\u0440\u043E\u0441\u0438\u0442\u044C, \u0435\u0441\u0442\u044C \u043B\u0438 \u043D\u043E\u0432\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F: ${outcome.why}. \u042D\u0442\u043E \u043D\u0435 \u043F\u043E\u043B\u043E\u043C\u043A\u0430: \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u043D\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F (${installed}) \u0440\u0430\u0431\u043E\u0442\u0430\u0435\u0442 \u043A\u0430\u043A \u0440\u0430\u0431\u043E\u0442\u0430\u043B\u0430.`
17484
+ );
17444
17485
  }
17445
- // \u0421\u043B\u043E\u0432\u0430 \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0438 \u043F\u0438\u0448\u0435\u0442 \u043E\u0431\u043E\u043B\u043E\u0447\u043A\u0430 (setup-card.ts), \u0437\u0434\u0435\u0441\u044C \u0438\u0445 \u0442\u043E\u043B\u044C\u043A\u043E \u0441\u0442\u0430\u0432\u044F\u0442
17446
- // \u043D\u0430 \u043C\u0435\u0441\u0442\u043E: \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A, \u0432\u0435\u0440\u0441\u0438\u044F, \u0441\u0442\u0440\u043E\u043A\u0438, \u043D\u043E\u0432\u043E\u0441\u0442\u044C, \u0447\u0442\u043E \u0434\u0430\u043B\u044C\u0448\u0435.
17447
- show('what', data.title || '');
17448
- show('cardMeta', data.meta || '');
17449
-
17450
- // \u0428\u043A\u0430\u043B\u0430 \u0433\u043E\u0442\u043E\u0432\u043D\u043E\u0441\u0442\u0438 \u2014 \u043F\u043E \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u043E\u043C\u0443: \u0442\u043E, \u0447\u0442\u043E \u0432\u0441\u0442\u0430\u043D\u0435\u0442 \u043F\u043E \u043F\u0440\u043E\u0441\u044C\u0431\u0435, \u0434\u043E\u043B\u0435\u0439
17451
- // \xAB\u043D\u0435 \u0433\u043E\u0442\u043E\u0432\u043E\xBB \u043D\u0435 \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044F, \u0438\u043D\u0430\u0447\u0435 \u0447\u0435\u043B\u043E\u0432\u0435\u043A \u0431\u0435\u0437 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u043E\u0432 \u043D\u0430\u0432\u0441\u0435\u0433\u0434\u0430 \u0432\u0438\u0434\u0435\u043B \u0431\u044B
17452
- // \u043D\u0435\u0434\u043E\u043B\u0438\u0442\u0443\u044E \u043F\u043E\u043B\u043E\u0441\u0443 \u043D\u0430 \u0438\u0441\u043F\u0440\u0430\u0432\u043D\u043E\u0439 \u043C\u0430\u0448\u0438\u043D\u0435.
17453
- byId('cardMeter').hidden = !need;
17454
- fill('cardFill', need ? ok * 100 / need : 0);
17455
- var cap = byId('cardCap');
17456
- cap.innerHTML = '';
17457
- if (need) {
17458
- var b = document.createElement('b');
17459
- b.textContent = '\u0413\u043E\u0442\u043E\u0432\u043E ' + ok + ' \u0438\u0437 ' + need;
17460
- cap.appendChild(b);
17486
+ return toolSuccess(
17487
+ outcome.manifest.body === null ? `\u0423\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u043E ${installed}; \u043D\u0430 \u0440\u0430\u0437\u0434\u0430\u0447\u0435 ${outcome.manifest.version}, \u043D\u043E \u0444\u0430\u0439\u043B\u0430 \u0434\u043B\u044F \u0441\u0430\u043C\u043E\u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u044F \u0442\u0430\u043C \u043F\u043E\u043A\u0430 \u043D\u0435\u0442. \u041D\u0438\u0447\u0435\u0433\u043E \u0434\u0435\u043B\u0430\u0442\u044C \u043D\u0435 \u043D\u0443\u0436\u043D\u043E, \u043E\u043D \u043F\u043E\u044F\u0432\u0438\u0442\u0441\u044F \u0441 \u0431\u043B\u0438\u0436\u0430\u0439\u0448\u0438\u043C \u0432\u044B\u043A\u0430\u0442\u043E\u043C.` : `\u0423 \u0432\u0430\u0441 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u0430 \u0441\u0430\u043C\u0430\u044F \u043F\u043E\u0441\u043B\u0435\u0434\u043D\u044F\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u2014 ${installed}.`
17488
+ );
17489
+ }
17490
+ if (decision.what === "launcher_too_old") {
17491
+ return toolSuccess(
17492
+ `\u041D\u043E\u0432\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F ${decision.manifest.version} \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043D\u043E\u0432\u043E\u0433\u043E \u0444\u0430\u0439\u043B\u0430 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F \u2014 \u0442\u043E\u0433\u043E, \u0447\u0442\u043E \u0441\u0442\u0430\u0432\u0438\u0442\u0441\u044F \u043F\u0435\u0440\u0435\u0442\u0430\u0441\u043A\u0438\u0432\u0430\u043D\u0438\u0435\u043C. \u0421\u043A\u0430\u0436\u0438 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0443: \u043D\u0430\u043F\u0438\u0448\u0438\u0442\u0435 \u0431\u043E\u0442\u0443 ${KEY_SOURCE_BOT}, \u043E\u043D \u043F\u0440\u0438\u0448\u043B\u0451\u0442 \u0441\u0432\u0435\u0436\u0438\u0439 \u0444\u0430\u0439\u043B; \u0432\u0441\u0451 \u043E\u0441\u0442\u0430\u043B\u044C\u043D\u043E\u0435 \u2014 \u043A\u043B\u044E\u0447, \u0434\u0432\u0438\u0436\u043E\u043A, \u0441\u0442\u0438\u043B\u044C, \u0437\u0430\u0434\u0430\u0447\u0438 \u2014 \u043E\u0441\u0442\u0430\u043D\u0435\u0442\u0441\u044F \u043D\u0430 \u043C\u0435\u0441\u0442\u0435. \u0421\u0442\u0430\u0432\u0438\u0442\u044C \u043D\u0435 \u0441\u0442\u0430\u043B.`
17493
+ );
17494
+ }
17495
+ if (!consent) {
17496
+ const mb = ((decision.manifest.body?.bytes ?? 0) / 1024 / 1024).toFixed(1);
17497
+ return toolSuccess(
17498
+ `\u0415\u0441\u0442\u044C \u043D\u043E\u0432\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F: ${installed} \u2192 ${decision.manifest.version}, ${mb} \u041C\u0411.
17499
+ ` + (decision.manifest.notes === null ? "" : `\u0427\u0442\u043E \u043D\u043E\u0432\u043E\u0433\u043E:
17500
+ ${decision.manifest.notes}
17501
+ `) + "\u0421\u043A\u0430\u0436\u0438 \u044D\u0442\u043E \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0443 \u0438 \u0441\u043F\u0440\u043E\u0441\u0438, \u0441\u0442\u0430\u0432\u0438\u0442\u044C \u043B\u0438. \u0421\u043E\u0433\u043B\u0430\u0441\u0438\u043B\u0441\u044F \u2014 \u0437\u043E\u0432\u0438 setup \u0441 what=shell \u0441 consent=true. \u0417\u0430\u0440\u0430\u0431\u043E\u0442\u0430\u0435\u0442 \u043F\u043E\u0441\u043B\u0435 \u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u043A\u0430 \u041A\u043B\u043E\u0434\u0430 \u0438\u043B\u0438 Codex."
17502
+ );
17503
+ }
17504
+ return asToolResult(await installShell({
17505
+ home,
17506
+ manifest: decision.manifest,
17507
+ key: key ?? null
17508
+ }));
17509
+ }
17510
+ var UPDATES = /* @__PURE__ */ new Set(["all", "engine", "shell"]);
17511
+ var HEAVY_STEPS = {
17512
+ speech: "model",
17513
+ cutout: "cutout",
17514
+ voice: "voice"
17515
+ };
17516
+ function setupTool(engine, passport, key, baseUrl) {
17517
+ return defineTool({
17518
+ name: "setup",
17519
+ title: "\u041F\u0440\u043E\u0432\u0435\u0440\u0438\u0442\u044C \u0438 \u043F\u043E\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u0432\u0441\u0451 \u0434\u043B\u044F \u043C\u043E\u043D\u0442\u0430\u0436\u0430",
17520
+ description: "\u0412\u0441\u0451, \u0447\u0435\u043C \u043C\u043E\u043D\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u043D\u0430 \u044D\u0442\u043E\u043C \u043A\u043E\u043C\u043F\u044C\u044E\u0442\u0435\u0440\u0435, \u2014 \u043E\u0434\u043D\u0438\u043C \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u043E\u043C. \u0411\u0435\u0437 \u0430\u0440\u0433\u0443\u043C\u0435\u043D\u0442\u043E\u0432 \u041F\u0420\u041E\u0412\u0415\u0420\u042F\u0415\u0422 \u0434\u0435\u043B\u043E\u043C: \u0447\u0442\u043E \u0441\u0442\u043E\u0438\u0442 \u0438 \u0447\u0435\u0433\u043E \u043D\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442, \u0447\u0442\u043E \u0434\u043E\u043A\u0430\u0447\u0430\u0435\u0442\u0441\u044F \u043F\u043E \u043F\u0440\u043E\u0441\u044C\u0431\u0435 \u0438 \u0441\u043A\u043E\u043B\u044C\u043A\u043E \u0432\u0435\u0441\u0438\u0442, \u0447\u0442\u043E \u0443\u043C\u0435\u0435\u0442 \u043C\u043E\u043D\u0442\u0430\u0436 (\u0448\u0430\u0433\u0438, \u0432\u043E\u043F\u0440\u043E\u0441\u044B \u0434\u043B\u044F \u043A\u0430\u0440\u0442\u043E\u0447\u0435\u043A choose_variant, \u0447\u0435\u0439 \u0440\u0435\u0446\u0435\u043F\u0442 \u0438 \u0447\u0435\u0439 \u0441\u0442\u0438\u043B\u044C) \u0438 \u0432\u044B\u0448\u043B\u0430 \u043B\u0438 \u043D\u043E\u0432\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u0434\u0432\u0438\u0436\u043A\u0430 \u0438\u043B\u0438 \u0441\u0430\u043C\u043E\u0433\u043E \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F. \u0417\u043E\u0432\u0438 \u041F\u0415\u0420\u0412\u042B\u041C, \u0434\u043E \u043B\u044E\u0431\u043E\u0439 \u0440\u0430\u0431\u043E\u0442\u044B \u0441 \u0432\u0438\u0434\u0435\u043E, \u0438 \u0438\u0437 \u0441\u0432\u043E\u0435\u0439 \u043F\u0430\u043C\u044F\u0442\u0438 \u043E\u0431 \u044D\u0442\u043E\u043C \u043D\u0435 \u0440\u0430\u0441\u0441\u043A\u0430\u0437\u044B\u0432\u0430\u0439.\n\u0421\u0442\u0430\u0432\u0438\u0442 \u0438 \u043E\u0431\u043D\u043E\u0432\u043B\u044F\u0435\u0442 \u0441 what, \u043D\u043E \u0442\u043E\u043B\u044C\u043A\u043E \u043F\u043E\u0441\u043B\u0435 \xAB\u0434\u0430\xBB \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430: \u0441\u043D\u0430\u0447\u0430\u043B\u0430 \u0441\u043A\u0430\u0436\u0438 \u0435\u043C\u0443 \u0441\u043B\u043E\u0432\u0430\u043C\u0438, \u0447\u0442\u043E \u043F\u043E\u0441\u0442\u0430\u0432\u0438\u0448\u044C \u0438 \u0441\u043A\u043E\u043B\u044C\u043A\u043E \u044D\u0442\u043E \u0432\u0435\u0441\u0438\u0442, \u043F\u043E\u0442\u043E\u043C \u0437\u043E\u0432\u0438 \u0441 \u0442\u0435\u043C \u0436\u0435 what \u0438 consent=true. \xAB\u0421\u043A\u0430\u0447\u0430\u0439\xBB \u0438 \xAB\u043E\u0431\u043D\u043E\u0432\u0438\xBB \u2014 \u0442\u043E \u0436\u0435 \xAB\u0434\u0430\xBB \u043D\u0430 \u0442\u043E, \u0447\u0442\u043E \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0430 \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438 \u0443\u0436\u0435 \u043D\u0430\u0437\u0432\u0430\u043B\u0430 \u0441 \u0432\u0435\u0441\u043E\u043C: \u0437\u043E\u0432\u0438 what=all \u0441 consent=true \u041E\u0414\u0418\u041D \u0440\u0430\u0437 \u2014 \u043E\u0442\u0432\u0435\u0442 \u043D\u043E\u043C\u0435\u0440\u043E\u043C \u0437\u0430\u0434\u0430\u0447\u0438, \u0434\u0430\u043B\u044C\u0448\u0435 wait, setup \u043F\u043E\u0432\u0442\u043E\u0440\u043D\u043E \u043D\u0435 \u0437\u043E\u0432\u0438. \u0411\u0435\u0437 consent \u043D\u0438\u0447\u0435\u0433\u043E \u043D\u0435 \u043A\u0430\u0447\u0430\u0435\u0442\u0441\u044F \u2014 \u043F\u0440\u0438\u0434\u0443\u0442 \u0432\u0435\u0441 \u0438 \u0432\u043E\u043F\u0440\u043E\u0441. \u0422\u044F\u0436\u0451\u043B\u043E\u0435 \u0441\u0442\u0430\u0432\u0438\u0442\u0441\u044F \u0442\u043E\u043B\u044C\u043A\u043E \u043F\u043E\u0434 \u043F\u0440\u043E\u0441\u044C\u0431\u0443: \u043D\u0435 \u043F\u0440\u043E\u0441\u0438\u043B\u0438 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u044B \u2014 \u043D\u0435 \u0441\u0442\u0430\u0432\u044C speech, \u043D\u0435 \u043F\u0440\u043E\u0441\u0438\u043B\u0438 \u043D\u043E\u0432\u044B\u0439 \u0444\u043E\u043D \u2014 \u043D\u0435 \u0441\u0442\u0430\u0432\u044C cutout.\n\u0414\u043E\u043B\u0433\u0430\u044F \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0430 \u043E\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u043D\u043E\u043C\u0435\u0440\u043E\u043C \u0437\u0430\u0434\u0430\u0447\u0438 \u2014 \u0434\u043E\u0436\u0434\u0438\u0441\u044C \u0435\u0451 \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u043E\u043C wait. \u041D\u043E\u0432\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u0434\u0432\u0438\u0436\u043A\u0430 \u0438\u043B\u0438 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F \u0437\u0430\u0440\u0430\u0431\u043E\u0442\u0430\u0435\u0442 \u043F\u043E\u0441\u043B\u0435 \u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u043A\u0430 \u041A\u043B\u043E\u0434\u0430 \u0438\u043B\u0438 Codex, \u0441\u043A\u0430\u0436\u0438 \u044D\u0442\u043E \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0443. \u0421\u043B\u043E\u043C\u0430\u043B\u043E\u0441\u044C \u043F\u043E\u0441\u043B\u0435 \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u044F \u2014 rollback. \u041F\u043E\u0434\u043F\u0438\u0441\u043A\u0430 \u043D\u0435 \u043D\u0443\u0436\u043D\u0430: \u0443\u0437\u043D\u0430\u0442\u044C, \u0437\u0430 \u0447\u0442\u043E \u043F\u043B\u0430\u0442\u044F\u0442, \u043C\u043E\u0436\u043D\u043E \u0434\u043E \u043E\u043F\u043B\u0430\u0442\u044B, \u0430 \u0441\u043A\u0430\u0447\u0438\u0432\u0430\u043D\u0438\u0435 \u0441\u0430\u043C\u043E \u0443\u043F\u0438\u0440\u0430\u0435\u0442\u0441\u044F \u0432 \u043A\u043B\u044E\u0447 \u043D\u0430 \u0440\u0430\u0437\u0434\u0430\u0447\u0435.",
17521
+ // ⚠ ОКНА У `setup` НЕТ, И ЭТО РЕШЕНИЕ ВЛАДЕЛЬЦА 2026-09-25. Окно в Claude
17522
+ // Desktop привязано к инструменту целиком: на одно «скачай» модель звала
17523
+ // setup четыре раза (проверка, cutout, voice, all) — четыре окна, в двух
17524
+ // сырой текст движка. «Или уж убрать, если не можем нормально сделать».
17525
+ // Полоса вернётся у отдельного инструмента установки тяжёлого (план
17526
+ // «как у взрослых», decisions.md 2026-09-25): один вызов — одно окно.
17527
+ args: external_exports.object({
17528
+ what: external_exports.enum(["all", "engine", "shell", "speech", "cutout", "voice"]).describe(
17529
+ "\u0427\u0442\u043E \u043F\u043E\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u0438\u043B\u0438 \u043E\u0431\u043D\u043E\u0432\u0438\u0442\u044C. all \u2014 \u0432\u0441\u0451 \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u043E\u0435, \u0447\u0435\u0433\u043E \u043D\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442, \u0438 \u043D\u043E\u0432\u044B\u0435 \u0432\u0435\u0440\u0441\u0438\u0438, \u043E \u043A\u043E\u0442\u043E\u0440\u044B\u0445 \u0441\u043A\u0430\u0437\u0430\u043B\u0430 \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0430; engine \u2014 \u0442\u043E\u043B\u044C\u043A\u043E \u043D\u043E\u0432\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u0434\u0432\u0438\u0436\u043A\u0430; shell \u2014 \u0442\u043E\u043B\u044C\u043A\u043E \u043D\u043E\u0432\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u0441\u0430\u043C\u043E\u0433\u043E \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F; speech \u2014 \u0440\u0430\u0441\u043F\u043E\u0437\u043D\u0430\u0432\u0430\u043D\u0438\u0435 \u0440\u0435\u0447\u0438 (\u0441\u0443\u0431\u0442\u0438\u0442\u0440\u044B); cutout \u2014 \u0432\u044B\u0440\u0435\u0437 \u0433\u0435\u0440\u043E\u044F (\u043D\u043E\u0432\u044B\u0439 \u0444\u043E\u043D); voice \u2014 \u0447\u0438\u0441\u0442\u043A\u0430 \u0433\u043E\u043B\u043E\u0441\u0430"
17530
+ ).optional(),
17531
+ consent: external_exports.boolean().describe(
17532
+ "\u0427\u0435\u043B\u043E\u0432\u0435\u043A \u0420\u0410\u0417\u0420\u0415\u0428\u0418\u041B \u0441\u043A\u0430\u0447\u0430\u0442\u044C \u0442\u043E, \u0447\u0442\u043E \u043D\u0430\u0437\u0432\u0430\u043D\u043E \u0432 what. \u0421\u0442\u0430\u0432\u044C \u0442\u043E\u043B\u044C\u043A\u043E \u043F\u043E\u0441\u043B\u0435 \u0442\u043E\u0433\u043E, \u043A\u0430\u043A \u043D\u0430\u0437\u0432\u0430\u043B \u0435\u043C\u0443, \u0447\u0442\u043E \u0438 \u0441\u043A\u043E\u043B\u044C\u043A\u043E \u0432\u0435\u0441\u0438\u0442, \u0438 \u043E\u043D \u0441\u043E\u0433\u043B\u0430\u0441\u0438\u043B\u0441\u044F \u2014 \u044D\u0442\u043E \u0435\u0433\u043E \u0442\u0440\u0430\u0444\u0438\u043A \u0438 \u0435\u0433\u043E \u0434\u0438\u0441\u043A"
17533
+ ).optional(),
17534
+ model: fromList(
17535
+ passport?.["models"],
17536
+ `\u041C\u043E\u0434\u0435\u043B\u044C \u0440\u0430\u0441\u043F\u043E\u0437\u043D\u0430\u0432\u0430\u043D\u0438\u044F \u0440\u0435\u0447\u0438: \u043A\u0430\u043A\u0443\u044E \u043F\u0440\u043E\u0432\u0435\u0440\u044F\u0442\u044C \u0438\u043B\u0438 \u0441\u0442\u0430\u0432\u0438\u0442\u044C \u0441 what="speech". ${aboutModels(passport)}`
17537
+ ).optional(),
17538
+ rollback: external_exports.enum(["engine", "shell"]).describe(
17539
+ "\u0412\u0435\u0440\u043D\u0443\u0442\u044C \u043F\u0440\u0435\u0436\u043D\u044E\u044E \u0432\u0435\u0440\u0441\u0438\u044E: engine \u2014 \u0434\u0432\u0438\u0436\u043E\u043A, shell \u2014 \u0441\u0430\u043C\u043E \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u0435. \u0417\u043E\u0432\u0438, \u043A\u043E\u0433\u0434\u0430 \u043F\u043E\u0441\u043B\u0435 \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u044F \u0447\u0442\u043E-\u0442\u043E \u043F\u0435\u0440\u0435\u0441\u0442\u0430\u043B\u043E \u0440\u0430\u0431\u043E\u0442\u0430\u0442\u044C: \u043F\u0440\u0435\u0436\u043D\u044F\u044F \u043B\u0435\u0436\u0438\u0442 \u043D\u0430 \u0434\u0438\u0441\u043A\u0435 \u0440\u044F\u0434\u043E\u043C. \u0417\u0430\u0440\u0430\u0431\u043E\u0442\u0430\u0435\u0442 \u043F\u043E\u0441\u043B\u0435 \u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u043A\u0430"
17540
+ ).optional()
17541
+ // ⚠ СОЧЕТАНИЯ СВЕРЯЮТСЯ В САМОЙ СХЕМЕ, А НЕ В ТЕЛЕ. Так правило видит
17542
+ // сверка аргументов на регистрации, и кривой вызов отбивается до всякой
17543
+ // сети (`tool-args.ts`); в теле оно стало бы правдой, о которой сверка не
17544
+ // знает.
17545
+ }).check((ctx) => {
17546
+ const asked = ctx.value;
17547
+ if (asked.rollback !== void 0 && asked.what !== void 0) {
17548
+ ctx.issues.push({
17549
+ code: "custom",
17550
+ message: "\xABrollback\xBB \u0438 \xABwhat\xBB \u2014 \u0440\u0430\u0437\u043D\u044B\u0435 \u043F\u0440\u043E\u0441\u044C\u0431\u044B: \u043E\u0442\u043A\u0430\u0442 \u0432\u043E\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043F\u0440\u0435\u0436\u043D\u044E\u044E \u0432\u0435\u0440\u0441\u0438\u044E, \u0430 what \u0441\u0442\u0430\u0432\u0438\u0442 \u043D\u043E\u0432\u043E\u0435. \u041F\u043E\u0437\u043E\u0432\u0438 \u0441 \u043E\u0434\u043D\u0438\u043C \u0438\u0437 \u043D\u0438\u0445",
17551
+ input: asked,
17552
+ path: ["rollback"]
17553
+ });
17554
+ }
17555
+ if (asked.consent === true && asked.what === void 0 && asked.rollback === void 0) {
17556
+ ctx.issues.push({
17557
+ code: "custom",
17558
+ message: "\xABconsent\xBB \u0431\u0435\u0437 \xABwhat\xBB: \u043D\u0435 \u0441\u043A\u0430\u0437\u0430\u043D\u043E, \u043D\u0430 \u0447\u0442\u043E \u0441\u043E\u0433\u043B\u0430\u0441\u0438\u043B\u0441\u044F \u0447\u0435\u043B\u043E\u0432\u0435\u043A. \u041D\u0430\u0437\u043E\u0432\u0438 what \u2014 \u0442\u043E, \u0447\u0442\u043E \u0442\u044B \u0435\u043C\u0443 \u043F\u0440\u0435\u0434\u043B\u0430\u0433\u0430\u043B",
17559
+ input: asked,
17560
+ path: ["consent"]
17561
+ });
17562
+ }
17563
+ }),
17564
+ async execute(args, ctx) {
17565
+ const news = { engine: null, shell: null };
17566
+ const said = await answer(args, ctx?.emitProgress, news);
17567
+ return withCard(said, () => setupCard({
17568
+ readiness: null,
17569
+ engine: news.engine ?? { installed: engine.freshVersion(), fresh: null, mb: 0, status: 0, notes: "" },
17570
+ shell: news.shell,
17571
+ note: firstLine(said),
17572
+ shellVersion: VERSION
17573
+ }));
17461
17574
  }
17462
- cap.hidden = !need;
17463
-
17464
- var list = byId('cardRows');
17465
- list.innerHTML = '';
17466
- for (var k = 0; k < rows.length; k++) {
17467
- var row = rows[k];
17468
- var li = document.createElement('li');
17469
- li.className = 'part ' + row.state;
17470
- var mark = document.createElement('span');
17471
- mark.className = 'part__m';
17472
- li.appendChild(mark);
17473
- var title = document.createElement('span');
17474
- title.className = 'part__t';
17475
- title.textContent = capital(row.title);
17476
- li.appendChild(title);
17477
- var w = document.createElement('span');
17478
- w.className = 'part__w';
17479
- w.textContent = row.say || '';
17480
- li.appendChild(w);
17481
- list.appendChild(li);
17575
+ });
17576
+ async function answer(args, tell, news) {
17577
+ if (args.rollback === "engine") return asToolResult(rollback(engine));
17578
+ if (args.rollback === "shell") return asToolResult(rollbackShell(engine.home()));
17579
+ const consent = args.consent === true;
17580
+ const what = args.what;
17581
+ if (what === void 0) return lookAround(engine, args.model, key, baseUrl);
17582
+ if (consent && UPDATES.has(what)) return startUpdate(engine, what, key, baseUrl);
17583
+ if (what === "engine") {
17584
+ return updateEngine(engine, consent, key, baseUrl, ASKED_POINTER_MS, (seen) => {
17585
+ if (!consent) news.engine = seen;
17586
+ });
17482
17587
  }
17483
- list.hidden = !rows.length;
17484
-
17485
- show('cardUpdate', data.update || '');
17486
- show('cardTrouble', data.trouble || '');
17487
- show('cardNext', data.next || '');
17488
- byId('card').hidden = false;
17489
- reportSize();
17490
- }
17491
-
17492
- /** \u041A\u043E\u043D\u0435\u0446 \u0440\u0430\u0431\u043E\u0442\u044B: \u0443\u0441\u043F\u0435\u0445 \u0441 \u043F\u0443\u0442\u0451\u043C \u043A \u0444\u0430\u0439\u043B\u0443 \u0438\u043B\u0438 \u043E\u0442\u043A\u0430\u0437 \u0441\u043B\u043E\u0432\u0430\u043C\u0438. */
17493
- function finish(data) {
17494
- var good = data.status === 'done';
17495
- document.body.classList.remove('bad');
17496
- if (!good) document.body.classList.add('bad');
17497
-
17498
- if (good && data.file) {
17499
- show('endTitle', '\u0413\u043E\u0442\u043E\u0432\u043E \u0437\u0430 ' + howLong(data.sec));
17500
- show('endHint', '\u0420\u043E\u043B\u0438\u043A \u0433\u043E\u0442\u043E\u0432:');
17501
- show('path', data.file);
17502
- } else if (good) {
17503
- // \u26A0 \u0423 \u0420\u0410\u0411\u041E\u0422\u042B \u0411\u0415\u0417 \u0424\u0410\u0419\u041B\u0410 \u2014 \u0424\u0420\u0410\u0417\u0410, \u0410 \u041D\u0415 \u041E\u0422\u0427\u0401\u0422 (\u0432\u043B\u0430\u0434\u0435\u043B\u0435\u0446 2026-09-24). \u041E\u0442\u0447\u0451\u0442
17504
- // \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0438 \u2014 \u0441\u0442\u0440\u043E\u043A\u0438 \u0434\u0432\u0438\u0436\u043A\u0430 \u0441 \u043F\u0443\u0442\u044F\u043C\u0438 \u0438 \u0438\u043C\u0435\u043D\u0430\u043C\u0438 \u0448\u0430\u0433\u043E\u0432, \u043E\u043D \u0434\u043B\u044F \u043C\u043E\u0434\u0435\u043B\u0438.
17505
- // \xAB\u0413\u043E\u0442\u043E\u0432\u043E. \u041F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u0442\u0438 Claude \u2014 \u2026\xBB \u0434\u0435\u043B\u0438\u0442\u0441\u044F \u043D\u0430 \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A \u0438 \u043F\u043E\u0434\u0441\u043A\u0430\u0437\u043A\u0443.
17506
- var say = data.say || '\u0413\u043E\u0442\u043E\u0432\u043E \u2014 \u043C\u043E\u0436\u043D\u043E \u043C\u043E\u043D\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C.';
17507
- var cut = /^(.+?)[.!]\\s+(.+)$/.exec(say);
17508
- show('endTitle', cut ? cut[1] : say.replace(/[.]$/, ''));
17509
- show('endHint', cut ? cut[2] : '');
17510
- show('path', '');
17511
- } else {
17512
- show('endTitle', data.status === 'aborted' ? '\u0420\u0430\u0431\u043E\u0442\u0430 \u043F\u0440\u0435\u0440\u0432\u0430\u043B\u0430\u0441\u044C' : '\u041D\u0435 \u043F\u043E\u043B\u0443\u0447\u0438\u043B\u043E\u0441\u044C');
17513
- show('endHint', data.trouble || '\u0427\u0442\u043E-\u0442\u043E \u0441\u043B\u043E\u043C\u0430\u043B\u043E\u0441\u044C. \u041D\u0430\u043F\u0438\u0448\u0438 \u041A\u043B\u043E\u0434\u0443 \xAB\u0447\u0442\u043E \u0441\u043B\u0443\u0447\u0438\u043B\u043E\u0441\u044C\xBB.');
17514
- show('path', '');
17588
+ if (what === "shell") {
17589
+ return updateShell(engine, consent, key, baseUrl, ASKED_POINTER_MS, (seen) => {
17590
+ if (!consent) news.shell = seen;
17591
+ });
17515
17592
  }
17516
- var warn = [];
17517
- if (good && data.outcome && data.file) warn.push(data.outcome);
17518
- // \u26A0 \u0416\u0410\u041B\u041E\u0411\u0410 \u041F\u041E\u041C\u0415\u0427\u0415\u041D\u0410 \u0417\u041D\u0410\u041A\u041E\u041C, \u0410 \u041D\u0415 \u0421\u041B\u0418\u0422\u0410 \u0421 \u041E\u0421\u0422\u0410\u041B\u042C\u041D\u042B\u041C. \xAB\u0413\u043E\u0442\u043E\u0432\u043E\xBB \u0441 \u0438\u0437\u0432\u0435\u0441\u0442\u043D\u044B\u043C
17519
- // \u0431\u0440\u0430\u043A\u043E\u043C \u2014 \u044D\u0442\u043E \u043D\u0435 \xAB\u0433\u043E\u0442\u043E\u0432\u043E\xBB: \u0442\u0435\u043C \u0436\u0435 \u0441\u0435\u0440\u044B\u043C \u043A\u0435\u0433\u043B\u0435\u043C, \u0447\u0442\u043E \u0438 \u043F\u043E\u0434\u0441\u043A\u0430\u0437\u043A\u0430, \u0431\u0440\u0430\u043A
17520
- // \u043F\u0440\u043E\u0447\u0438\u0442\u0430\u044E\u0442 \u043D\u0435 \u0432\u0441\u0435, \u0430 \u0438\u043C\u0435\u043D\u043D\u043E \u0435\u0433\u043E \u0447\u0435\u043B\u043E\u0432\u0435\u043A \u0438 \u0434\u043E\u043B\u0436\u0435\u043D \u0443\u0432\u0438\u0434\u0435\u0442\u044C.
17521
- var list = data.complaints || [];
17522
- for (var i = 0; i < list.length; i++) warn.push('\u26A0 ' + list[i]);
17523
- if (!good && data.advice) warn.push(data.advice);
17524
- show('warn', warn.join('\\n'));
17525
-
17526
- byId('end').hidden = false;
17527
- byId('note').hidden = true;
17528
- }
17529
-
17530
- /** \u041E\u0442\u043A\u0430\u0437 \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u0430: \u0441\u043B\u043E\u0432\u0430 \u0432\u043C\u0435\u0441\u0442\u043E \u043F\u043E\u043B\u043E\u0441\u044B. \u041F\u0443\u0441\u0442\u0430\u044F \u0440\u0430\u043C\u043A\u0430 \u0442\u0443\u0442 \u0441\u0442\u0440\u0430\u0448\u043D\u0435\u0435 \u0431\u0435\u0434\u044B. */
17531
- function finishWithWords(text) {
17532
- job = null;
17533
- document.body.classList.remove('gone');
17534
- byId('card').hidden = true;
17535
- byId('dl').hidden = true;
17536
- byId('now').hidden = true;
17537
- byId('rail').hidden = true;
17538
- byId('msg').hidden = true;
17539
- byId('clock').hidden = true;
17540
- document.body.classList.add('bad');
17541
- show('endTitle', '\u041D\u0435 \u043F\u043E\u043B\u0443\u0447\u0438\u043B\u043E\u0441\u044C');
17542
- show('endHint', text || '\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0443\u0437\u043D\u0430\u0442\u044C, \u0447\u0442\u043E \u0441 \u0440\u0430\u0431\u043E\u0442\u043E\u0439. \u0421\u043F\u0440\u043E\u0441\u0438\u0442\u0435 \u041A\u043B\u043E\u0434\u0430 \u0441\u043B\u043E\u0432\u0430\u043C\u0438.');
17543
- byId('path').hidden = true;
17544
- byId('warn').hidden = true;
17545
- byId('end').hidden = false;
17546
- byId('note').hidden = true;
17547
- reportSize();
17548
- }
17549
-
17550
- /**
17551
- * \u041F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0442\u044C \u043D\u0435\u0447\u0435\u0433\u043E: \u0443\u0431\u0440\u0430\u0442\u044C \u043F\u043E\u043B\u043E\u0441\u0443 \u0441\u043E\u0432\u0441\u0435\u043C \u0438 \u043E\u0442\u0434\u0430\u0442\u044C \u043B\u0435\u043D\u0442\u0435 \u0435\u0451 \u043C\u0435\u0441\u0442\u043E.
17552
- *
17553
- * \u26A0 \u041D\u0415 \xAB\u0421\u041A\u0420\u042B\u0422\u042C \u0421\u041E\u0414\u0415\u0420\u0416\u0418\u041C\u041E\u0415\xBB, \u0410 \u0421\u0412\u0415\u0420\u041D\u0423\u0422\u042C \u041E\u041A\u041D\u041E. \u0421\u043F\u0440\u044F\u0442\u0430\u043D\u043D\u044B\u0435 \u0431\u043B\u043E\u043A\u0438 \u0432\u043D\u0443\u0442\u0440\u0438 \u0440\u0430\u043C\u043A\u0438
17554
- * \u043E\u0441\u0442\u0430\u0432\u043B\u044F\u044E\u0442 \u0432 \u043B\u0435\u043D\u0442\u0435 \u043F\u0443\u0441\u0442\u0443\u044E \u043F\u043B\u0430\u0448\u043A\u0443 \u2014 \u043E\u043D\u0430 \u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044F \u043A\u0430\u043A \u043F\u043E\u043B\u043E\u043C\u043A\u0430 \u043D\u0438\u0447\u0443\u0442\u044C \u043D\u0435
17555
- * \u043C\u0435\u043D\u044C\u0448\u0435, \u0447\u0435\u043C \u0437\u0430\u0441\u0442\u044B\u0432\u0448\u0435\u0435 \xAB\u041D\u0430\u0447\u0438\u043D\u0430\u044E\u2026\xBB.
17556
- */
17557
- function collapse() {
17558
- job = null;
17559
- // \u26A0 \u041D\u0415 \u0425\u041E\u0420\u041E\u041D\u0418\u041C \u0412\u0418\u0414\u0416\u0415\u0422, \u0410 \u0422\u041E\u041B\u042C\u041A\u041E \u0423\u0411\u0418\u0420\u0410\u0415\u041C \u0415\u0413\u041E \u0421 \u0413\u041B\u0410\u0417. \u0421\u0442\u0430\u0432\u044C \u043C\u044B \u0437\u0434\u0435\u0441\u044C
17560
- // \xAB\u0437\u0430\u043A\u0440\u044B\u0442\u043E\xBB, \u043F\u0440\u0438\u0448\u0435\u0434\u0448\u0430\u044F \u0441\u043B\u0435\u0434\u043E\u043C \u043D\u0430\u0441\u0442\u043E\u044F\u0449\u0430\u044F \u0437\u0430\u0434\u0430\u0447\u0430 (\u0445\u043E\u0441\u0442 \u0432\u043F\u0440\u0430\u0432\u0435 \u043F\u0440\u0438\u0441\u043B\u0430\u0442\u044C \u0434\u0432\u0430
17561
- // \u0443\u0432\u0435\u0434\u043E\u043C\u043B\u0435\u043D\u0438\u044F \u043F\u043E\u0434\u0440\u044F\u0434) \u043E\u0441\u0442\u0430\u043B\u0430\u0441\u044C \u0431\u044B \u0431\u0435\u0437 \u043E\u043F\u0440\u043E\u0441\u0430 \u2014 \u043F\u043E\u043B\u043E\u0441\u0430 \u043F\u043E\u043A\u0430\u0437\u0430\u043B\u0430 \u0431\u044B \u043F\u0435\u0440\u0432\u044B\u0439
17562
- // \u043A\u0430\u0434\u0440 \u0438 \u0437\u0430\u043C\u0435\u0440\u043B\u0430.
17563
- var all = ['now', 'rail', 'msg', 'dl', 'card', 'clock', 'end', 'note', 'what'];
17564
- for (var i = 0; i < all.length; i++) { var el = byId(all[i]); if (el) el.hidden = true; }
17565
- document.body.classList.add('gone');
17566
- reportSize();
17593
+ if (what === "all") {
17594
+ return lookAround(engine, args.model, key, baseUrl);
17595
+ }
17596
+ const step = HEAVY_STEPS[what];
17597
+ return consent ? installStep(engine, { step, model: args.model, consent: true }, key, baseUrl, tell) : askBeforeHeavy(engine, step, args.model, key, baseUrl);
17567
17598
  }
17568
-
17569
- // \u2500\u2500\u2500 \u043C\u0438\u0440 \u0445\u043E\u0441\u0442\u0430 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
17570
-
17571
- function applyContext(ctx) {
17572
- if (!ctx) return;
17573
- if (ctx.theme === 'dark') document.body.classList.add('dark');
17574
- else if (ctx.theme === 'light') document.body.classList.remove('dark');
17599
+ }
17600
+ async function lookAround(engine, model, key, baseUrl) {
17601
+ let engineNews = null;
17602
+ let shellNews = null;
17603
+ const toEngine = (news2) => {
17604
+ engineNews = news2;
17605
+ };
17606
+ const toShell = (news2) => {
17607
+ shellNews = news2;
17608
+ };
17609
+ const card = (said, o) => withCard(said, () => setupCard({
17610
+ readiness: o.readiness ?? null,
17611
+ engine: engineNews ?? { installed: engine.freshVersion(), fresh: null, mb: 0, status: 0, notes: "" },
17612
+ shell: shellNews,
17613
+ ...o.noEngine === true ? { noEngine: true } : {},
17614
+ ...o.noPython === true ? { noPython: true } : {},
17615
+ note: o.note ?? firstLine(said),
17616
+ shellVersion: VERSION
17617
+ }));
17618
+ const shell = updateShell(engine, false, key, baseUrl, NEWS_POINTER_MS, toShell);
17619
+ if (engine.place() === null) {
17620
+ const payload = await installPayload(engine, {
17621
+ consent: false,
17622
+ manifestUrl: manifestUrl(engine, baseUrl),
17623
+ ...key !== void 0 ? { key } : {}
17624
+ });
17625
+ return card(together([toolSuccess(payload.text), await shell]), { noEngine: true });
17575
17626
  }
17576
-
17577
- // \u26A0 \u0414\u0410\u041D\u041D\u042B\u0415 \u041F\u0420\u0418\u0425\u041E\u0414\u042F\u0422 \u0422\u041E\u041B\u042C\u041A\u041E \u0418\u0417 structuredContent. \u0412 content \u0445\u043E\u0441\u0442 \u043A\u043B\u0430\u0434\u0451\u0442 \u0444\u0440\u0430\u0437\u0443
17578
- // \u0434\u043B\u044F \u043C\u043E\u0434\u0435\u043B\u0438 (\xAB\u0417\u0430\u0434\u0430\u0447\u0430 2026-\u2026: \u043C\u043E\u043D\u0442\u0430\u0436\xBB), \u0438 \u0440\u0430\u0437\u0431\u043E\u0440 \u0435\u0451 \u043A\u0430\u043A JSON \u043F\u0430\u0434\u0430\u043B \u0431\u044B \u043C\u043E\u043B\u0447\u0430,
17579
- // \u043E\u0441\u0442\u0430\u0432\u043B\u044F\u044F \u043F\u043E\u043B\u043E\u0441\u0443 \u043D\u0430 \u0432\u0435\u0447\u043D\u043E\u043C \xAB\u041D\u0430\u0447\u0438\u043D\u0430\u044E\u2026\xBB. \u0422\u0430\u043A \u0443\u0436\u0435 \u0431\u044B\u043B\u043E \u0443 \u0444\u043E\u0440\u043C\u044B \u0432\u044B\u0431\u043E\u0440\u0430.
17580
- function parse(params) {
17581
- var data = params && params.structuredContent;
17582
- if (data && data.contract === CONTRACT) return data;
17583
- return null;
17627
+ const noPython = await engine.pythonTrouble();
17628
+ if (noPython !== null) {
17629
+ return card(together([
17630
+ toolSuccess(noPython),
17631
+ await updateEngine(engine, false, key, baseUrl, NEWS_POINTER_MS, toEngine),
17632
+ await shell
17633
+ ]), { noPython: true });
17584
17634
  }
17585
-
17586
- window.addEventListener('message', function (e) {
17587
- // \u26A0 \u041B\u042E\u0411\u041E\u0419 \u041F\u0420\u0415\u0414\u041E\u041A, \u0410 \u041D\u0415 \u0421\u0422\u0420\u041E\u0413\u041E window.parent: \u0445\u043E\u0441\u0442 \u043F\u043E \u0441\u043F\u0435\u043A\u0435 \u0441\u0442\u0430\u0432\u0438\u0442 \u043C\u0435\u0436\u0434\u0443
17588
- // \u0441\u043E\u0431\u043E\u0439 \u0438 \u043D\u0430\u043C\u0438 \u043F\u0435\u0441\u043E\u0447\u043D\u0438\u0446\u0443 \u2014 \u043F\u0435\u0440\u0432\u044B\u0439 iframe \u0437\u0430\u0432\u043E\u0434\u0438\u0442 \u0432\u0442\u043E\u0440\u043E\u0439, \u043D\u0430\u0448. \u0421\u043E\u0441\u0435\u0434\u043D\u0435\u0435
17589
- // \u043E\u043A\u043D\u043E \u0432 \u0442\u043E\u0439 \u0436\u0435 \u043B\u0435\u043D\u0442\u0435 \u043F\u0440\u0438 \u044D\u0442\u043E\u043C \u043E\u0442\u0441\u0435\u0447\u0435\u043D\u043E: \u043E\u043D\u043E \u0440\u043E\u0432\u043D\u044F, \u0430 \u043D\u0435 \u043F\u0440\u0435\u0434\u043E\u043A.
17590
- if (e.source !== window.parent && e.source !== window.top) return;
17591
- var m = e.data;
17592
- if (!m || m.jsonrpc !== '2.0') return;
17593
- // \u26A0 \u042D\u0422\u041E \u041E\u0422\u0412\u0415\u0422, \u0410 \u041D\u0415 \u0417\u0410\u041F\u0420\u041E\u0421. \u041D\u0443\u043C\u0435\u0440\u0430\u0446\u0438\u044F \u0443 \u0445\u043E\u0441\u0442\u0430 \u0441\u0432\u043E\u044F, \u0442\u043E\u0436\u0435 \u0441 \u0435\u0434\u0438\u043D\u0438\u0446\u044B: \u0435\u0433\u043E
17594
- // \u0437\u0430\u043F\u0440\u043E\u0441 \u0441 id 1 \u0441\u044A\u0435\u043B \u0431\u044B \u043A\u043E\u043B\u0431\u044D\u043A \u043D\u0430\u0448\u0435\u0433\u043E \u0440\u0443\u043A\u043E\u043F\u043E\u0436\u0430\u0442\u0438\u044F.
17595
- var answer = m.method === undefined && (m.result !== undefined || m.error !== undefined);
17596
- if (answer && m.id !== undefined && waiting[m.id]) {
17597
- var reply = waiting[m.id];
17598
- delete waiting[m.id];
17599
- reply(m);
17600
- return;
17601
- }
17602
- if (m.method === 'ui/notifications/tool-result') {
17603
- if (m.params && m.params.isError) { finishWithWords(words(m.params)); return; }
17604
- // \u041E\u0442\u0432\u0435\u0442 setup \u0431\u0435\u0437 \u0437\u0430\u0434\u0430\u0447\u0438 \u2014 \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0430 \u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u044F, \u0430 \u043D\u0435 \u0441\u0432\u0451\u0440\u0442\u043A\u0430: \u0440\u0430\u043C\u043A\u0443 \u0445\u043E\u0441\u0442
17605
- // \u0440\u0438\u0441\u0443\u0435\u0442 \u0432\u0441\u0451 \u0440\u0430\u0432\u043D\u043E, \u0438 \u0441\u0432\u0451\u0440\u043D\u0443\u0442\u0430\u044F \u043F\u043E\u043B\u043E\u0441\u0430 \u043E\u0441\u0442\u0430\u0432\u043B\u044F\u043B\u0430 \u0431\u044B \u043F\u0443\u0441\u0442\u0443\u044E \u043F\u043B\u0430\u0448\u043A\u0443.
17606
- var card = m.params && m.params.structuredContent;
17607
- if (card && card.contract === SETUP) { renderCard(card); return; }
17608
- var data = parse(m.params);
17609
- // \u26A0 \u041E\u0422\u0412\u0415\u0422 \u0411\u0415\u0417 \u0417\u0410\u0414\u0410\u0427\u0418 \u0418 \u0411\u0415\u0417 \u041A\u0410\u0420\u0422\u041E\u0427\u041A\u0418 \u2014 \u0421\u0412\u041E\u0420\u0410\u0427\u0418\u0412\u0410\u0415\u041C\u0421\u042F, \u0410 \u041D\u0415 \u0412\u0418\u0421\u0418\u041C \u041D\u0410
17610
- // \u0417\u0410\u0413\u041B\u0423\u0428\u041A\u0415. \u0423 setup \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0430 \u0435\u0441\u0442\u044C \u0432\u0441\u0435\u0433\u0434\u0430 (\u0432\u044B\u0448\u0435, 2026-09-24): \u0441\u0432\u0451\u0440\u0442\u043A\u0443
17611
- // Claude Desktop \u043D\u0435 \u0443\u0431\u0438\u0440\u0430\u0435\u0442, \u0438 \u0442\u0430\u043C \u043E\u0441\u0442\u0430\u0432\u0430\u043B\u0430\u0441\u044C \u043F\u0443\u0441\u0442\u0430\u044F \u0440\u0430\u043C\u043A\u0430. \u0417\u0434\u0435\u0441\u044C
17612
- // \u043E\u0441\u0442\u0430\u043B\u0438\u0441\u044C \u0447\u0443\u0436\u0438\u0435 \u043E\u0442\u0432\u0435\u0442\u044B \u0431\u0435\u0437 \u0440\u0430\u0431\u043E\u0442\u044B \u2014 plan \u0431\u0435\u0437 \u0432\u0438\u0434\u0435\u043E (docs/plan/README.md,
17613
- // \u0438\u0437\u0432\u0435\u0441\u0442\u043D\u044B\u0439 \u0431\u0440\u0430\u043A). \u041F\u043E\u043B\u043E\u0441\u0430
17614
- // \u043E\u0431\u044A\u044F\u0432\u043B\u0435\u043D\u0430 \u0443 \u0412\u0421\u0415\u0413\u041E \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u0430, \u0430 \u043D\u0435 \u0443 \u043E\u0442\u0434\u0435\u043B\u044C\u043D\u043E\u0433\u043E \u043E\u0442\u0432\u0435\u0442\u0430, \u0438 \u0445\u043E\u0441\u0442 \u0440\u0438\u0441\u0443\u0435\u0442
17615
- // \u0435\u0451 \u043D\u0430 \u043A\u0430\u0436\u0434\u043E\u043C \u0432\u044B\u0437\u043E\u0432\u0435 \u2014 \u0432 \u0442\u043E\u043C \u0447\u0438\u0441\u043B\u0435 \u043D\u0430 \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0435 setup \u0431\u0435\u0437 \u0430\u0440\u0433\u0443\u043C\u0435\u043D\u0442\u043E\u0432,
17616
- // \u0433\u0434\u0435 \u043D\u0438\u043A\u0430\u043A\u043E\u0439 \u0440\u0430\u0431\u043E\u0442\u044B \u043D\u0435\u0442 \u0438 \u043D\u043E\u043C\u0435\u0440\u0430 \u0437\u0430\u0434\u0430\u0447\u0438 \u0432 \u043E\u0442\u0432\u0435\u0442\u0435 \u0442\u043E\u0436\u0435. \u0420\u0430\u043D\u044C\u0448\u0435 \u0437\u0434\u0435\u0441\u044C
17617
- // \u0441\u0442\u043E\u044F\u043B \u043F\u0443\u0441\u0442\u043E\u0439 \u0432\u044B\u0445\u043E\u0434, \u0438
17618
- // \u0447\u0435\u043B\u043E\u0432\u0435\u043A \u043F\u043E\u043B\u0443\u0447\u0430\u043B \u0432\u0435\u0447\u043D\u043E\u0435 \xAB\u0420\u0430\u0431\u043E\u0442\u0430\u044E \u2014 \u041D\u0430\u0447\u0438\u043D\u0430\u044E\u2026\xBB \u043F\u043E\u0434 \u043E\u0442\u0432\u0435\u0442\u043E\u043C \xAB\u0432\u0441\u0451 \u043D\u0430 \u043C\u0435\u0441\u0442\u0435\xBB.
17619
- // \u0412\u043B\u0430\u0434\u0435\u043B\u0435\u0446 2026-09-20: \xAB\u043F\u043E\u0447\u0435\u043C\u0443 \u0442\u0443\u0442 \u0442\u043E\u043B\u044C\u043A\u043E \u0440\u0430\u0431\u043E\u0442\u0430\u044E \u2014 \u043D\u0430\u0447\u0438\u043D\u0430\u044E?\xBB \u0421\u043B\u043E\u0432\u0430
17620
- // \u043E\u0442\u0432\u0435\u0442\u0430 \u0445\u043E\u0441\u0442 \u043F\u0435\u0447\u0430\u0442\u0430\u0435\u0442 \u0440\u044F\u0434\u043E\u043C \u0441\u0430\u043C, \u043F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0442\u044C \u043D\u0430\u043C \u043D\u0435\u0447\u0435\u0433\u043E \u2014 \u0443\u0445\u043E\u0434\u0438\u043C \u0441 \u0433\u043B\u0430\u0437.
17621
- if (!data) { collapse(); return; }
17622
- render(data);
17623
- later();
17624
- return;
17625
- }
17626
- if (m.method === 'ui/notifications/host-context-changed') { applyContext(m.params); return; }
17627
- // \u26A0 \u0412\u0418\u0414\u0416\u0415\u0422 \u0417\u0410\u041A\u0420\u042B\u041B\u0418 \u2014 \u0422\u0410\u0419\u041C\u0415\u0420 \u041E\u0411\u042F\u0417\u0410\u041D \u0423\u041C\u0415\u0420\u0415\u0422\u042C. \u0418\u043D\u0430\u0447\u0435 \u043E\u043D \u0437\u0430\u043F\u0443\u0441\u043A\u0430\u0435\u0442 \u043F\u0438\u0442\u043E\u043D \u043D\u0430
17628
- // \u043C\u0430\u0448\u0438\u043D\u0435 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430 \u043A\u0430\u0436\u0434\u044B\u0435 \u0434\u0432\u0435 \u0441 \u043F\u043E\u043B\u043E\u0432\u0438\u043D\u043E\u0439 \u0441\u0435\u043A\u0443\u043D\u0434\u044B \u0434\u043E \u043A\u043E\u043D\u0446\u0430 \u0434\u043D\u044F, \u0430 \u043F\u043E\u043A\u0430\u0437\u0430\u0442\u044C
17629
- // \u0440\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442 \u0443\u0436\u0435 \u043D\u0435\u043A\u0443\u0434\u0430: \u043E\u043A\u043D\u0430 \u043D\u0435\u0442.
17630
- if (m.method === 'ui/resource-teardown') { closed = true; job = null; return; }
17631
- });
17632
-
17633
- // \u26A0 \u0412\u042B\u0421\u041E\u0422\u0423 \u0421\u041E\u041E\u0411\u0429\u0410\u0415\u041C \u0421\u0420\u0410\u0417\u0423, \u0414\u041E \u0412\u0421\u042F\u041A\u0418\u0425 \u0414\u0410\u041D\u041D\u042B\u0425. \u041F\u043E\u043A\u0430 \u044D\u0442\u043E \u0434\u0435\u043B\u0430\u043B\u043E\u0441\u044C \u0442\u043E\u043B\u044C\u043A\u043E \u043F\u0440\u0438
17634
- // \u043E\u0442\u0440\u0438\u0441\u043E\u0432\u043A\u0435, \u0437\u0430\u043C\u0438\u043D\u043A\u0430 \u0441 \u0434\u0430\u043D\u043D\u044B\u043C\u0438 \u0432\u044B\u0433\u043B\u044F\u0434\u0435\u043B\u0430 \u043A\u0430\u043A \u043F\u0443\u0441\u0442\u043E\u0439 \u0431\u043B\u043E\u043A \u0432 \u043B\u0435\u043D\u0442\u0435: \u0440\u0430\u0437\u043C\u0435\u0442\u043A\u0430
17635
- // \u0435\u0441\u0442\u044C, \u0430 \u043F\u043E\u043A\u0430\u0437\u0430\u0442\u044C \u0435\u0451 \u043D\u0435\u0433\u0434\u0435 \u2014 \u0443 \u043E\u043A\u043D\u0430 \u043D\u0443\u043B\u0435\u0432\u0430\u044F \u0432\u044B\u0441\u043E\u0442\u0430.
17636
- reportSize();
17637
- // \u26A0 \u041E\u0411\u0410 \u0418\u041C\u0415\u041D\u0418 \u0421\u0420\u0410\u0417\u0423, \u0418 \u042D\u0422\u041E \u041D\u0415 \u041F\u0415\u0420\u0415\u0421\u0422\u0420\u0410\u0425\u041E\u0412\u041A\u0410. \u0416\u0438\u0432\u043E\u0439 Claude Desktop \u043E\u0442\u043A\u0430\u0437\u044B\u0432\u0430\u0435\u0442
17638
- // \u0432 \u0440\u0443\u043A\u043E\u043F\u043E\u0436\u0430\u0442\u0438\u0438 \u0431\u0435\u0437 appInfo (\xABexpected object, received undefined\xBB \u043F\u043E \u043F\u0443\u0442\u0438
17639
- // params.appInfo), \u0430 \u0441\u043F\u0435\u043A\u0430 2026-01-26 \u043D\u0430\u0437\u044B\u0432\u0430\u0435\u0442 \u044D\u0442\u043E \u043F\u043E\u043B\u0435 clientInfo. \u0423\u0431\u0435\u0440\u0438
17640
- // \u043B\u044E\u0431\u043E\u0435 \u2014 \u0432\u0438\u0434\u0436\u0435\u0442 \u043F\u0435\u0440\u0435\u0441\u0442\u0430\u043D\u0435\u0442 \u0440\u0430\u0431\u043E\u0442\u0430\u0442\u044C \u043B\u0438\u0431\u043E \u0441\u0435\u0433\u043E\u0434\u043D\u044F, \u043B\u0438\u0431\u043E \u043D\u0430 \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0435\u043C \u0445\u043E\u0441\u0442\u0435.
17641
- send('ui/initialize', {
17642
- protocolVersion: '2026-01-26',
17643
- capabilities: {},
17644
- appInfo: { name: 'naparnik-runbar', version: '${VERSION}' },
17645
- clientInfo: { name: 'naparnik-runbar', version: '${VERSION}' },
17646
- appCapabilities: { availableDisplayModes: ['inline'] }
17647
- }, function (m) {
17648
- if (m.error) { show('note', '\u0425\u043E\u0441\u0442 \u043E\u0442\u043A\u0430\u0437\u0430\u043B \u0432 \u0440\u0443\u043A\u043E\u043F\u043E\u0436\u0430\u0442\u0438\u0438: ' + ((m.error && m.error.message) || '')); reportSize(); return; }
17649
- applyContext(m.result && m.result.hostContext);
17650
- notify('ui/notifications/initialized', {});
17651
- });
17652
- })();
17653
- </script>
17654
- </body>
17655
- </html>`;
17635
+ const [machine, news, own] = await Promise.all([
17636
+ inspectMachine(engine, { model }),
17637
+ updateEngine(engine, false, key, baseUrl, NEWS_POINTER_MS, toEngine),
17638
+ shell
17639
+ ]);
17640
+ const offered = updateOffered(shellNews, engineNews);
17641
+ return card(
17642
+ together([newsForModel(shellNews, engineNews), machine.result, news, own]),
17643
+ { readiness: machine.readiness, note: offered ? "" : firstLine(together([machine.result, news, own])) }
17644
+ );
17656
17645
  }
17657
-
17658
- // src/tool-kit.ts
17659
- function manifestUrl(engine, baseUrl) {
17660
- return engine.variable("NAPARNIK_UPDATE_MANIFEST") ?? manifestUrlFor(baseUrl);
17646
+ function newsForModel(shell, engine) {
17647
+ if (!shell?.fresh && !engine?.fresh) return toolSuccess("");
17648
+ const numbers = [
17649
+ engine?.fresh ? `\u0434\u0432\u0438\u0436\u043E\u043A ${engine.installed ?? "\u043D\u0435\u0442"} \u2192 ${engine.fresh}` : "",
17650
+ shell?.fresh ? `\u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u0435 ${shell.installed ?? VERSION} \u2192 ${shell.fresh}` : ""
17651
+ ].filter((one) => one !== "").join(", ");
17652
+ return toolSuccess(
17653
+ `\u0414\u043E\u0441\u0442\u0443\u043F\u043D\u0430 \u043D\u043E\u0432\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u043C\u043E\u043D\u0442\u0430\u0436\u0451\u0440\u0430: ${whatIsNew(shell, engine)} (${numbers}). \u0421\u043A\u0430\u0436\u0438 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0443, \u0447\u0442\u043E \u0438\u043C\u0435\u043D\u043D\u043E \u043E\u0431\u043D\u043E\u0432\u0438\u0442\u0441\u044F \u0438 \u0441\u043A\u043E\u043B\u044C\u043A\u043E \u0432\u0435\u0441\u0438\u0442. \xAB\u041E\u0431\u043D\u043E\u0432\u0438\xBB \u2014 \u044D\u0442\u043E \xAB\u0434\u0430\xBB: \u043E\u0434\u0438\u043D \u0432\u044B\u0437\u043E\u0432 setup \u0441 what=all \u0438 consent=true, \u0434\u0430\u043B\u044C\u0448\u0435 wait \u043F\u043E \u043D\u043E\u043C\u0435\u0440\u0443 \u0437\u0430\u0434\u0430\u0447\u0438.`
17654
+ );
17661
17655
  }
17662
- function aboutDefaults(map2) {
17663
- if (map2 === void 0 || Object.keys(map2).length === 0) return "\u0441\u043C\u043E\u0442\u0440\u0438 setup";
17664
- return Object.entries(map2).map(([engine, model]) => `${model} (${engine})`).join(", ");
17656
+ function withCard(result, card) {
17657
+ if (result.type !== "success" || result.structured !== void 0) return result;
17658
+ return toolSuccess(wordsOf(result.content), card());
17665
17659
  }
17666
- function aboutModels(passport) {
17667
- if (passport === null) return "\u0421\u043F\u0438\u0441\u043E\u043A \u043C\u043E\u0434\u0435\u043B\u0435\u0439 \u0441\u043C\u043E\u0442\u0440\u0438 \u0432 setup";
17668
- return `\u041A\u0430\u043A\u0438\u0435 \u0435\u0441\u0442\u044C: ${passport["models"].join(", ")}; \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E \u2014 \u0441\u0432\u043E\u0451 \u043D\u0430 \u0434\u0432\u0438\u0436\u043E\u043A: ${aboutDefaults(passport["default_model"])}. \u041D\u0435 \u043D\u0430\u0437\u044B\u0432\u0430\u0439 \u043C\u043E\u0434\u0435\u043B\u044C \u0431\u0435\u0437 \u043D\u0443\u0436\u0434\u044B: \u043F\u0430\u043A \u0441\u0430\u043C \u0432\u043E\u0437\u044C\u043C\u0451\u0442 \u0442\u0443, \u0447\u0442\u043E \u0431\u044B\u0441\u0442\u0440\u0435\u0435 \u043D\u0430 \u044D\u0442\u043E\u043C \u043A\u043E\u043C\u043F\u044C\u044E\u0442\u0435\u0440\u0435`;
17660
+ function firstLine(result) {
17661
+ const text2 = result.type === "success" ? wordsOf(result.content) : result.error;
17662
+ return text2.split("\n").map((line) => line.trim()).find((line) => line !== "") ?? "";
17663
+ }
17664
+ function startUpdate(engine, what, key, baseUrl) {
17665
+ const title = engine.place() === null ? TITLE_INSTALL : TITLE_UPDATE;
17666
+ const id = startSetupJob(title, (job) => runUpdate(job, {
17667
+ engine,
17668
+ key,
17669
+ baseUrl,
17670
+ what,
17671
+ pointerMs: ASKED_POINTER_MS,
17672
+ installMissing: () => installMissing(engine, key, baseUrl, void 0)
17673
+ }), Date.now, engine.home());
17674
+ const report = setupJobReport(id, engine.home());
17675
+ return toolSuccess(
17676
+ `\u0417\u0430\u0434\u0430\u0447\u0430 ${id}: ${report?.what ?? title}.
17677
+ \u0418\u0434\u0451\u0442 \u043D\u0430 \u043A\u043E\u043C\u043F\u044C\u044E\u0442\u0435\u0440\u0435 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F: \u043F\u0440\u043E\u0432\u0435\u0440\u044E, \u0447\u0442\u043E \u0432\u044B\u0448\u043B\u043E, \u0441\u043A\u0430\u0447\u0430\u044E \u0438 \u043F\u043E\u0441\u0442\u0430\u0432\u043B\u044E. \u041F\u043E\u043B\u043E\u0441\u0430 \u0443 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430 \u043E\u0431\u043D\u043E\u0432\u043B\u044F\u0435\u0442\u0441\u044F \u0441\u0430\u043C\u0430. \u041F\u043E\u0437\u043E\u0432\u0438 wait \u0441 job "` + id + '" \u2014 \u0434\u043E\u0436\u0434\u0451\u0442\u0441\u044F \u0438 \u0441\u043A\u0430\u0436\u0435\u0442, \u0447\u0435\u043C \u043A\u043E\u043D\u0447\u0438\u043B\u043E\u0441\u044C; setup \u043F\u043E\u0432\u0442\u043E\u0440\u043D\u043E \u043D\u0435 \u0437\u043E\u0432\u0438. \u0413\u043E\u0442\u043E\u0432\u043E \u2014 \u043F\u0435\u0440\u0435\u0441\u043A\u0430\u0436\u0438 \u0441\u0442\u0440\u043E\u043A\u0443 \xAB\u0427\u0435\u043B\u043E\u0432\u0435\u043A\u0443\xBB.',
17678
+ report ?? void 0
17679
+ );
17680
+ }
17681
+ async function installMissing(engine, key, baseUrl, tell) {
17682
+ const place = engine.place();
17683
+ if (place !== null && await engine.pythonTrouble() === null && await nothingMissing(engine, place)) {
17684
+ return toolSuccess("\u0412\u0441\u0451 \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u043E\u0435 \u0434\u043B\u044F \u043C\u043E\u043D\u0442\u0430\u0436\u0430 \u043D\u0430 \u043C\u0435\u0441\u0442\u0435 \u2014 \u0441\u0442\u0430\u0432\u0438\u0442\u044C \u043D\u0435\u0447\u0435\u0433\u043E.");
17685
+ }
17686
+ return installStep(engine, { step: "all", consent: true }, key, baseUrl, tell);
17687
+ }
17688
+ async function nothingMissing(engine, place) {
17689
+ try {
17690
+ await engine.run(place, ["env-check", "--pack", place.pack, "--first-install"]);
17691
+ return true;
17692
+ } catch {
17693
+ return false;
17694
+ }
17695
+ }
17696
+ async function askBeforeHeavy(engine, step, model, key, baseUrl) {
17697
+ const place = engine.place();
17698
+ if (place === null) {
17699
+ const payload = await installPayload(engine, {
17700
+ consent: false,
17701
+ manifestUrl: manifestUrl(engine, baseUrl),
17702
+ ...key !== void 0 ? { key } : {}
17703
+ });
17704
+ return toolSuccess(payload.text);
17705
+ }
17706
+ const noPython = await engine.pythonTrouble();
17707
+ if (noPython !== null) return toolSuccess(noPython);
17708
+ return asToolResult(await engine.command([
17709
+ "env-install",
17710
+ "--pack",
17711
+ place.pack,
17712
+ "--step",
17713
+ step,
17714
+ ...model !== void 0 ? ["--model", model] : []
17715
+ ]));
17669
17716
  }
17670
- function fromList(list, description) {
17671
- return list !== void 0 && list.length > 0 ? external_exports.enum([...list]).describe(description) : external_exports.string().describe(description);
17717
+ function together(results) {
17718
+ const text2 = results.map((one) => one.type === "success" ? wordsOf(one.content) : one.error).filter((words) => words !== "").join("\n\n");
17719
+ for (const one of results) {
17720
+ if (one.type === "success" && one.structured !== void 0) return toolSuccess(text2, one.structured);
17721
+ }
17722
+ return results.some((one) => one.type === "error") ? toolError(text2) : toolSuccess(text2);
17672
17723
  }
17673
- function asToolResult(outcome) {
17674
- return outcome.ok ? toolSuccess(outcome.text) : toolError(outcome.text);
17724
+ function wordsOf(content) {
17725
+ if (typeof content === "string") return content;
17726
+ return content.map((block) => block.type === "text" ? block.text : "").join("\n");
17675
17727
  }
17676
- function asJobResult(outcome) {
17677
- if (!outcome.ok) return toolError(outcome.text);
17678
- const job = readJob(outcome.text);
17679
- return job === null ? toolSuccess(outcome.text) : toolSuccess(outcome.text, job);
17728
+ var WIDGET_MIME = "text/html;profile=mcp-app";
17729
+ function widgetStamp(html) {
17730
+ return createHash("sha256").update(html).digest("hex").slice(0, 8);
17680
17731
  }
17681
- var CAPABILITIES_CONTRACT = "naparnik-capabilities/1";
17682
- var HEAVY_WORK = {
17683
- model: "\u0440\u0430\u0441\u043F\u043E\u0437\u043D\u0430\u0432\u0430\u043D\u0438\u0435 \u0440\u0435\u0447\u0438",
17684
- cutout: "\u0432\u044B\u0440\u0435\u0437 \u0433\u0435\u0440\u043E\u044F",
17685
- voice: "\u0447\u0438\u0441\u0442\u043A\u0430 \u0433\u043E\u043B\u043E\u0441\u0430"
17686
- };
17687
- var KNOB_KIND = {
17688
- file: "\u0444\u0430\u0439\u043B",
17689
- string: "\u0441\u0442\u0440\u043E\u043A\u0430",
17690
- number: "\u0447\u0438\u0441\u043B\u043E",
17691
- "yes-no": "\u0434\u0430/\u043D\u0435\u0442"
17692
- };
17693
- var FROM_MINE = "mine";
17694
- function catalogInWords(data) {
17695
- const lines = [];
17696
- const version2 = data.engine?.version;
17697
- lines.push(`\u0427\u0442\u043E \u0443\u043C\u0435\u0435\u0442 \u043C\u043E\u043D\u0442\u0430\u0436 \u043D\u0430 \u044D\u0442\u043E\u043C \u043A\u043E\u043C\u043F\u044C\u044E\u0442\u0435\u0440\u0435${version2 !== void 0 ? `. \u0414\u0432\u0438\u0436\u043E\u043A ${version2}` : ""}.`);
17698
- const steps = data.steps ?? [];
17699
- const ready = steps.filter((s) => s.ready !== false);
17700
- const later = steps.filter((s) => s.ready === false);
17701
- if (ready.length > 0) {
17702
- lines.push(`\u0423\u0436\u0435 \u0441\u0442\u043E\u0438\u0442: ${ready.map((s) => `${s.title} (${s.name})`).join(", ")}.`);
17732
+ var WIDGET_PLATE_CSS = `
17733
+ :root { --plate: #ffffff; --plate-end: #f5f5f7; }
17734
+ :root:has(> body.dark) { --plate: #1d1d1f; --plate-end: #000000; }
17735
+ :root:has(> body.full) { min-height: 100%; }
17736
+ html {
17737
+ background: var(--plate-end) linear-gradient(var(--plate) calc(100% - 197px), var(--plate-end)) no-repeat;
17703
17738
  }
17704
- if (later.length > 0) {
17705
- const said = later.map((s) => {
17706
- const work = (s.needs ?? []).map((n) => HEAVY_WORK[n] ?? n).join(" \u0438 ");
17707
- const step = (s.needs ?? [])[0];
17708
- return `${s.title} (${s.name}) \u2014 ${work}${step !== void 0 ? ` (setup what="${step}")` : ""}`;
17709
- }).join("; ");
17710
- lines.push(
17711
- `\u0414\u043E\u043A\u0430\u0447\u0430\u0435\u0442\u0441\u044F \u043F\u0435\u0440\u0435\u0434 \u043F\u0435\u0440\u0432\u044B\u043C \u043C\u043E\u043D\u0442\u0430\u0436\u043E\u043C, \u0441\u043F\u0440\u043E\u0441\u0438 \u0441\u043E\u0433\u043B\u0430\u0441\u0438\u0435 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430: ${said}.`
17712
- );
17739
+ `;
17740
+ var WIDGET_HEADING_CSS = `
17741
+ :root {
17742
+ --font-display: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Icons", "Helvetica Neue", Helvetica, Arial, sans-serif;
17713
17743
  }
17714
- const recipes = data.recipes ?? [];
17715
- if (recipes.length > 0) {
17716
- lines.push(`\u0413\u043E\u0442\u043E\u0432\u044B\u0435 \u043D\u0430\u0431\u043E\u0440\u044B \u0448\u0430\u0433\u043E\u0432: ${recipes.map((r) => `${r.title} (${r.name})`).join(", ")}.`);
17744
+ h2, .end__t { font-family: var(--font-display); }
17745
+ `;
17746
+
17747
+ // src/runbar.ts
17748
+ var RUNBAR_RESOURCE_URI = `ui://naparnik/runbar-${widgetStamp(runbarWidgetHtml())}`;
17749
+ var RUNBAR_MIME = WIDGET_MIME;
17750
+ function runbarResource() {
17751
+ return {
17752
+ resource: {
17753
+ uri: RUNBAR_RESOURCE_URI,
17754
+ name: "\u0425\u043E\u0434 \u0440\u0430\u0431\u043E\u0442\u044B",
17755
+ description: "\u041F\u043E\u043B\u043E\u0441\u0430 \u044D\u0442\u0430\u043F\u043E\u0432: \u0447\u0442\u043E \u0434\u0435\u043B\u0430\u0435\u0442\u0441\u044F \u0441\u0435\u0439\u0447\u0430\u0441 \u0438 \u0441\u043A\u043E\u043B\u044C\u043A\u043E \u0443\u0436\u0435 \u0438\u0434\u0451\u0442",
17756
+ mimeType: RUNBAR_MIME
17757
+ },
17758
+ contents: [{
17759
+ uri: RUNBAR_RESOURCE_URI,
17760
+ mimeType: RUNBAR_MIME,
17761
+ text: runbarWidgetHtml(),
17762
+ _meta: { ui: { prefersBorder: true } }
17763
+ }]
17764
+ };
17765
+ }
17766
+ function runbarWidgetHtml() {
17767
+ return `<!DOCTYPE html>
17768
+ <html lang="ru">
17769
+ <head>
17770
+ <meta charset="utf-8">
17771
+ <style>
17772
+ /* \u2500\u2500\u2500 \u041C\u0438\u0440 \u043F\u043E\u043B\u043E\u0441\u044B \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
17773
+ \u0426\u0432\u0435\u0442\u0430 \u0442\u0435 \u0436\u0435, \u0447\u0442\u043E \u0443 \u0444\u043E\u0440\u043C\u044B \u0432\u044B\u0431\u043E\u0440\u0430 \u0438 \u043D\u0430 \u043B\u0435\u043D\u0434\u0438\u043D\u0433\u0435: \u0436\u0451\u043B\u0442\u044B\u0439 \u0432\u0435\u0434\u0451\u0442 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u2014
17774
+ \u0437\u0434\u0435\u0441\u044C \u044D\u0442\u043E \u0438\u0434\u0443\u0449\u0438\u0439 \u044D\u0442\u0430\u043F, \u0433\u043E\u043B\u0443\u0431\u043E\u0439 \u0432\u0435\u0434\u0451\u0442 \u0433\u043E\u043B\u043E\u0441 \u2014 \u0441\u0442\u0440\u043E\u043A\u0443 \u043E \u0442\u043E\u043C, \u0447\u0442\u043E \u043F\u0440\u043E\u0438\u0441\u0445\u043E\u0434\u0438\u0442.
17775
+
17776
+ \u26A0 \u0421\u0412\u0415\u0422 \u2014 \u041E\u0421\u041D\u041E\u0412\u0410, \u0422\u0401\u041C\u041D\u0410\u042F \u0422\u0415\u041C\u0410 \u0422\u041E\u041B\u042C\u041A\u041E \u0414\u041E\u041F\u0418\u0421\u042B\u0412\u0410\u0415\u0422. \u041F\u0440\u0430\u0432\u0438\u043B\u043E \u043F\u0440\u043E\u0435\u043A\u0442\u0430: \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435
17777
+ \u0443 \u0441\u0432\u043E\u0439\u0441\u0442\u0432\u0430 \u043E\u0434\u043D\u043E, \u0438 \u043F\u0440\u0430\u0432\u043A\u0430 \u0441\u0432\u0435\u0442\u043B\u043E\u0439 \u0442\u0435\u043C\u044B \u043D\u0435 \u043C\u043E\u0436\u0435\u0442 \u043C\u043E\u043B\u0447\u0430 \u043F\u0435\u0440\u0435\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u0442\u0451\u043C\u043D\u0443\u044E.
17778
+
17779
+ \u26A0 \u041E \xABcolor-scheme\xBB: \u0435\u0433\u043E \u0437\u0434\u0435\u0441\u044C \u041D\u0415\u0422, \u0438 \u044D\u0442\u043E \u043D\u0435 \u0437\u0430\u0431\u044B\u0442\u043E. \u0421\u043E \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435\u043C
17780
+ \xABlight dark\xBB \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u043F\u0435\u0440\u0435\u0441\u0442\u0430\u0451\u0442 \u043A\u043E\u043C\u043F\u043E\u0437\u0438\u0442\u0438\u0442\u044C iframe \u0441 \u043F\u043E\u0432\u0435\u0440\u0445\u043D\u043E\u0441\u0442\u044C\u044E \u0445\u043E\u0441\u0442\u0430 \u0438
17781
+ \u0437\u0430\u043B\u0438\u0432\u0430\u0435\u0442 \u0435\u0433\u043E \u0441\u043E\u0431\u0441\u0442\u0432\u0435\u043D\u043D\u044B\u043C \u0445\u043E\u043B\u0441\u0442\u043E\u043C \u043F\u043E \u043D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0435 \u0421\u0418\u0421\u0422\u0415\u041C\u042B: \u043F\u0440\u0438 \u0441\u0432\u0435\u0442\u043B\u043E\u043C \u041A\u043B\u043E\u0434\u0435
17782
+ \u043D\u0430 \u0442\u0451\u043C\u043D\u043E\u0439 macOS \u043F\u043E\u043B\u043E\u0441\u0430 \u043F\u043E\u043B\u0443\u0447\u0430\u043B\u0430 \u0431\u044B \u0447\u0451\u0440\u043D\u044B\u0439 \u0445\u043E\u043B\u0441\u0442 \u043F\u043E\u0434 \u0442\u0451\u043C\u043D\u044B\u043C\u0438 \u0447\u0435\u0440\u043D\u0438\u043B\u0430\u043C\u0438.
17783
+ \u041E\u0448\u0438\u0431\u043A\u0430 \u043C\u043E\u043B\u0447\u0430\u043B\u0438\u0432\u0430\u044F, \u0432 \u043A\u043E\u043D\u0441\u043E\u043B\u0438 \u043F\u0443\u0441\u0442\u043E. \u041F\u0440\u043E\u0432\u0435\u0440\u0435\u043D\u043E \u043D\u0430 \u0444\u043E\u0440\u043C\u0435 \u0432\u044B\u0431\u043E\u0440\u0430 2026-09-10. */
17784
+ /* \u041F\u043E\u0434\u043B\u043E\u0436\u043A\u0430 \u043E\u0431\u0449\u0430\u044F \u0441 \u0444\u043E\u0440\u043C\u043E\u0439 \u0432\u044B\u0431\u043E\u0440\u0430 \u0438 \u043B\u0435\u0436\u0438\u0442 \u0432 widget.ts. */
17785
+ ${WIDGET_PLATE_CSS}
17786
+ ${WIDGET_HEADING_CSS}
17787
+ :root {
17788
+ --ink: #1d1d1f;
17789
+ --ink-soft: #5E5547;
17790
+ --card: #F3EDDF;
17791
+ --card-lift: #FBF7EC;
17792
+ --edge: rgba(20, 17, 12, 0.10);
17793
+ --edge-strong: rgba(20, 17, 12, 0.20);
17794
+ --note-bg: rgba(29, 219, 208, 0.16);
17795
+ --note-dot: #0c6f6a;
17796
+ --off: rgba(20, 17, 12, 0.07);
17797
+ --off-ink: #6E6455;
17798
+ --good: #0E8B54;
17799
+ --good-ink: #FFFFFF;
17800
+ --bad: #B4341F;
17801
+ --bad-bg: rgba(180, 52, 31, 0.10);
17802
+ --lift: 0 2px 4px -2px rgba(21, 17, 9, 0.16), 0 16px 34px -20px rgba(21, 17, 9, 0.34);
17803
+ --yellow: #f4c70f;
17804
+ --ease: cubic-bezier(0.16, 1, 0.30, 1);
17717
17805
  }
17718
- const inForce = data.recipe;
17719
- if (inForce?.name !== void 0) {
17720
- lines.push(
17721
- inForce.origin === FROM_MINE ? `\u0420\u0435\u0446\u0435\u043F\u0442 \u0432 \u0434\u0435\u043B\u0435: \u0441\u0432\u043E\u0439 \xAB${inForce.name}\xBB \u2014 ${inForce.path ?? ""}.` : `\u0420\u0435\u0446\u0435\u043F\u0442 \u0432 \u0434\u0435\u043B\u0435: \u043D\u0430\u0448 \xAB${inForce.name}\xBB. \u0421\u0432\u043E\u0439 \u0437\u0430\u0432\u043E\u0434\u0438\u0442\u0441\u044F \u0447\u0435\u0440\u0435\u0437 plan_edit \u0441\u043E step.`
17722
- );
17806
+ body.dark {
17807
+ --ink: #f5f5f7;
17808
+ --ink-soft: #ADA495;
17809
+ --card: #211C15;
17810
+ --card-lift: #2A2419;
17811
+ --edge: rgba(244, 239, 230, 0.10);
17812
+ --edge-strong: rgba(244, 239, 230, 0.22);
17813
+ --note-bg: rgba(29, 219, 208, 0.10);
17814
+ --note-dot: #1ddbd0;
17815
+ --off: rgba(244, 239, 230, 0.07);
17816
+ --off-ink: #9A9182;
17817
+ --good: #2FBE7E;
17818
+ --good-ink: #10231A;
17819
+ --bad: #FF8B72;
17820
+ --bad-bg: rgba(255, 139, 114, 0.12);
17821
+ --lift: 0 2px 6px -3px rgba(0, 0, 0, 0.75), 0 20px 44px -28px rgba(0, 0, 0, 0.95);
17723
17822
  }
17724
- const questions = data.questions ?? [];
17725
- if (questions.length > 0) {
17726
- const sections = [...new Map(
17727
- questions.filter((q) => q.section).map((q) => [q.section ?? "", q.group ?? ""])
17728
- )].map(([id, tab]) => `${tab} (${id})`);
17729
- lines.push(
17730
- "\u0421\u043F\u0440\u043E\u0441\u0438\u0442\u044C \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0430\u043C\u0438 \u2014 choose_variant(questions=[\u2026]) \u0438\u043C\u0435\u043D\u0430\u043C\u0438 \u0432\u043E\u043F\u0440\u043E\u0441\u043E\u0432 \u0438\u043B\u0438 \u0440\u0430\u0437\u0434\u0435\u043B\u043E\u0432, \u0438 \u0442\u043E\u043B\u044C\u043A\u043E \u043F\u0440\u043E \u0442\u043E, \u0447\u0442\u043E \u0447\u0435\u043B\u043E\u0432\u0435\u043A \u0432\u044B\u0431\u0440\u0430\u043B \u0438\u043B\u0438 \u043F\u043E\u043F\u0440\u043E\u0441\u0438\u043B." + (sections.length > 0 ? ` \u0420\u0430\u0437\u0434\u0435\u043B\u044B: ${sections.join(", ")}.` : "")
17731
- );
17732
- for (const q of questions) {
17733
- const tab = q.group ? `[${q.group}] ` : "";
17734
- if (q.kind === "range") {
17735
- const dials = (q.sliders ?? []).map((s) => `${s.title} (${s.name})`).join(", ");
17736
- lines.push(`\u2014 ${tab}${q.title} (${q.name}), \u043F\u043E\u043B\u0437\u0443\u043D\u043A\u0430\u043C\u0438: ${dials}.`);
17737
- continue;
17738
- }
17739
- const plain = q.kind === "plain" ? ", \u0431\u0435\u0437 \u043A\u0430\u0440\u0442\u0438\u043D\u043A\u0438" : "";
17740
- const named = q.variants ?? [];
17741
- const variants = named.length > 0 ? named.map((v) => `${v.title} (${v.name})`).join(", ") : "\u0432\u0430\u0440\u0438\u0430\u043D\u0442\u044B \u0441\u0447\u0438\u0442\u0430\u044E\u0442\u0441\u044F \u043F\u043E \u043A\u0430\u0434\u0440\u0443 \u0440\u043E\u043B\u0438\u043A\u0430";
17742
- const total = typeof q.total === "number" ? q.total : named.length;
17743
- const rest = total > named.length ? ` \u0438 \u0435\u0449\u0451 ${total - named.length}` : "";
17744
- lines.push(`\u2014 ${tab}${q.title} (${q.name})${plain}: ${variants}${rest}.`);
17745
- }
17823
+
17824
+ /* \u26A0 \u0421\u0412\u041E\u0418\u0425 \u0428\u0420\u0418\u0424\u0422\u041E\u0412 \u0417\u0414\u0415\u0421\u042C \u041D\u0415\u0422 \u0418 \u0411\u042B\u0422\u042C \u041D\u0415 \u0414\u041E\u041B\u0416\u041D\u041E: \u043F\u043E\u043A\u0443\u043F\u0430\u0442\u0435\u043B\u044E \u043E\u043D\u0438 \u043D\u0435 \u0443\u0435\u0437\u0436\u0430\u044E\u0442, \u0430
17825
+ \u0432\u043D\u0435\u0448\u043D\u0438\u0435 \u0430\u0434\u0440\u0435\u0441\u0430 \u0440\u0435\u0436\u0435\u0442 CSP \u0445\u043E\u0441\u0442\u0430. \u0425\u0430\u0440\u0430\u043A\u0442\u0435\u0440 \u043D\u0430\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044F \u043A\u0435\u0433\u043B\u0435\u043C \u0438 \u0442\u0440\u0435\u043A\u0438\u043D\u0433\u043E\u043C. */
17826
+ /* \u041F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0442\u044C \u043D\u0435\u0447\u0435\u0433\u043E \u2014 \u043F\u043E\u043B\u043E\u0441\u0430 \u043D\u0435 \u0437\u0430\u043D\u0438\u043C\u0430\u0435\u0442 \u0432 \u043B\u0435\u043D\u0442\u0435 \u043D\u0438 \u0441\u0442\u0440\u043E\u043A\u0438. \u041F\u0443\u0441\u0442\u0430\u044F \u043F\u043B\u0430\u0448\u043A\u0430
17827
+ \u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044F \u043A\u0430\u043A \u043F\u043E\u043B\u043E\u043C\u043A\u0430 \u0440\u043E\u0432\u043D\u043E \u0442\u0430\u043A \u0436\u0435, \u043A\u0430\u043A \u0437\u0430\u0441\u0442\u044B\u0432\u0448\u0435\u0435 \xAB\u041D\u0430\u0447\u0438\u043D\u0430\u044E\u2026\xBB. */
17828
+ body.gone { padding: 0; min-block-size: 0; }
17829
+ body.gone > * { display: none; }
17830
+
17831
+ body {
17832
+ margin: 0;
17833
+ padding: 18px 16px 20px;
17834
+ max-inline-size: 880px;
17835
+ font: 15px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", "Inter", "Helvetica Neue", Arial, sans-serif;
17836
+ -webkit-font-smoothing: antialiased;
17837
+ color: var(--ink);
17838
+ background: transparent;
17746
17839
  }
17747
- const knobs = data.knobs ?? [];
17748
- if (knobs.length > 0) {
17749
- const said = knobs.map((k) => `${k.name} (${k.kind !== void 0 ? KNOB_KIND[k.kind] ?? k.kind : "\u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435"})`).join(", ");
17750
- lines.push(`\u0420\u0443\u0447\u043A\u0438 \u043C\u043E\u043D\u0442\u0430\u0436\u0430, \u0438\u0445 \u043F\u0435\u0440\u0435\u0434\u0430\u044E\u0442 \u0432 render: ${said}.`);
17840
+ ::selection { background: rgba(244, 199, 15, 0.32); color: var(--ink); }
17841
+
17842
+ /* \u2500\u2500\u2500 \u0428\u0430\u043F\u043A\u0430 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
17843
+
17844
+ .head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
17845
+ h2 {
17846
+ margin: 0;
17847
+ max-inline-size: 30ch;
17848
+ font-size: 19px;
17849
+ line-height: 1.15;
17850
+ font-weight: 700;
17851
+ letter-spacing: -0.03em;
17852
+ text-wrap: balance;
17751
17853
  }
17752
- const index = data.handbook?.index;
17753
- if (index !== void 0 && index.trim() !== "") {
17754
- lines.push(`\u0421\u041F\u0420\u0410\u0412\u041E\u0427\u041D\u0418\u041A \u041C\u041E\u041D\u0422\u0410\u0416\u0401\u0420\u0410 \u2014 \u043E\u0433\u043B\u0430\u0432\u043B\u0435\u043D\u0438\u0435, \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u044B \u0447\u0438\u0442\u0430\u0439 plan \u0441 read:
17755
- ${index.trim()}`);
17854
+ /* \u0427\u0430\u0441\u044B \u043C\u043E\u043D\u043E\u0448\u0438\u0440\u0438\u043D\u043D\u044B\u0435 \u0438 \u0441 \u0444\u0438\u043A\u0441\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u044B\u043C\u0438 \u0446\u0438\u0444\u0440\u0430\u043C\u0438: \u043F\u0440\u043E\u043F\u043E\u0440\u0446\u0438\u043E\u043D\u0430\u043B\u044C\u043D\u044B\u0435 \u0446\u0438\u0444\u0440\u044B
17855
+ \u0434\u0451\u0440\u0433\u0430\u044E\u0442 \u0432\u0441\u044E \u0441\u0442\u0440\u043E\u043A\u0443 \u043D\u0430 \u043A\u0430\u0436\u0434\u043E\u043C \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0438, \u0438 \u0433\u043B\u0430\u0437 \u0447\u0438\u0442\u0430\u0435\u0442 \u044D\u0442\u043E \u043A\u0430\u043A \u043C\u0438\u0433\u0430\u043D\u0438\u0435. */
17856
+ .clock {
17857
+ flex: none;
17858
+ color: var(--ink-soft);
17859
+ font-size: 13px;
17860
+ font-variant-numeric: tabular-nums;
17861
+ letter-spacing: -0.01em;
17756
17862
  }
17757
- const style = data.style;
17758
- if (style?.name !== void 0) {
17759
- lines.push(
17760
- style.own === true ? `\u0421\u0442\u0438\u043B\u044C: \u0441\u0432\u043E\u0439 \u043F\u0430\u043A \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430 \xAB${style.name}\xBB \u2014 \u0432\u044B\u0431\u0440\u0430\u043D\u043D\u043E\u0435 \u0437\u0430\u043F\u043E\u043C\u0438\u043D\u0430\u0435\u0442\u0441\u044F \u0432 \u043D\u0435\u0433\u043E.` : `\u0421\u0442\u0438\u043B\u044C: \u0432\u0441\u0442\u0440\u043E\u0435\u043D\u043D\u044B\u0439 \xAB${style.name}\xBB, \u0441\u0432\u043E\u0435\u0433\u043E \u043F\u0430\u043A\u0430 \u0443 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430 \u0435\u0449\u0451 \u043D\u0435\u0442.`
17761
- );
17863
+ .clock[hidden] { display: none; }
17864
+
17865
+ /* \u2500\u2500\u2500 \u041B\u0435\u0441\u0442\u043D\u0438\u0446\u0430 \u044D\u0442\u0430\u043F\u043E\u0432 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
17866
+
17867
+ /* \u26A0 \u042D\u0422\u0410\u041F\u042B \u2014 \u042D\u0422\u041E \u041F\u041E\u041B\u041E\u0421\u042B, \u0410 \u041D\u0415 \u0422\u041E\u0427\u041A\u0418. \u0418\u0445 \u0431\u044B\u0432\u0430\u0435\u0442 \u043E\u0434\u0438\u043D\u043D\u0430\u0434\u0446\u0430\u0442\u044C, \u0438 \u043E\u0434\u0438\u043D\u043D\u0430\u0434\u0446\u0430\u0442\u044C
17868
+ \u043A\u0440\u0443\u0436\u043A\u043E\u0432 \u0432 \u043B\u0435\u043D\u0442\u0435 \u0447\u0438\u0442\u0430\u044E\u0442\u0441\u044F \u043A\u0430\u043A \u0443\u0437\u043E\u0440; \u043F\u043E\u043B\u043E\u0441\u044B \u0436\u0435 \u0441\u043A\u043B\u0430\u0434\u044B\u0432\u0430\u044E\u0442\u0441\u044F \u0432 \u043E\u0434\u0438\u043D \u0448\u043E\u0432,
17869
+ \u043F\u043E \u043A\u043E\u0442\u043E\u0440\u043E\u043C\u0443 \u0441\u0440\u0430\u0437\u0443 \u0432\u0438\u0434\u043D\u043E, \u043A\u0430\u043A\u0430\u044F \u0434\u043E\u043B\u044F \u0440\u0430\u0431\u043E\u0442\u044B \u043F\u043E\u0437\u0430\u0434\u0438. */
17870
+ .rail { display: flex; gap: 4px; margin: 14px 0 0; padding: 0; list-style: none; }
17871
+ .rail[hidden] { display: none; }
17872
+ .rail li {
17873
+ flex: 1 1 0;
17874
+ height: 6px;
17875
+ border-radius: 3px;
17876
+ background: var(--off);
17762
17877
  }
17763
- const mine = data.mine?.summary ?? [];
17764
- if (mine.length > 0) {
17765
- lines.push(`\u0421\u0432\u043E\u0451 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430 (\u0437\u0430\u043F\u043E\u043C\u043D\u0435\u043D\u043E, \u0443\u0436\u0435 \u0432 \u043A\u0430\u0436\u0434\u043E\u043C \u0447\u0435\u0440\u043D\u043E\u0432\u0438\u043A\u0435; \xAB\u0437\u0430\u0431\u0443\u0434\u044C\xBB \u2014 plan_edit forget):
17766
- ${mine.map((line) => `\u2014 ${line}`).join("\n")}`);
17878
+ .rail li.was { background: var(--good); }
17879
+ /* \u26A0 \u041A\u041B\u0410\u0421\u0421 \u0418\u0414\u0423\u0429\u0415\u0413\u041E \u042D\u0422\u0410\u041F\u0410 \u2014 \xABat\xBB, \u0410 \u041D\u0415 \xABnow\xBB, \u0418 \u042D\u0422\u041E \u041D\u0415 \u041F\u0420\u0418\u0414\u0418\u0420\u041A\u0410 \u041A \u0418\u041C\u0415\u041D\u0418. \u041F\u043E\u043A\u0430
17880
+ \u043E\u043D \u0437\u0432\u0430\u043B\u0441\u044F \xABnow\xBB, \u0435\u0433\u043E \u043F\u043E\u0434\u0445\u0432\u0430\u0442\u044B\u0432\u0430\u043B \u0441\u0435\u043B\u0435\u043A\u0442\u043E\u0440 \xAB.now::before\xBB \u043D\u0438\u0436\u0435: \u043D\u0430 \u043F\u043E\u043B\u043E\u0441\u043A\u0435
17881
+ \u0432\u044B\u0440\u0430\u0441\u0442\u0430\u043B \u0434\u044B\u0448\u0430\u0449\u0438\u0439 \u043E\u0433\u043E\u043D\u0451\u043A \u0440\u0430\u0437\u043C\u0435\u0440\u043E\u043C \u0431\u043E\u043B\u044C\u0448\u0435 \u0435\u0451 \u0441\u0430\u043C\u043E\u0439 \u2014 \u043E\u043D \u0432\u044B\u043B\u0435\u0437\u0430\u043B \u0442\u043E\u0447\u043A\u043E\u0439 \u0438
17882
+ \u0441\u0434\u0432\u0438\u0433\u0430\u043B \u043F\u043E\u043B\u043E\u0441\u043A\u0443 \u0432\u043D\u0438\u0437 \u043E\u0442\u043D\u043E\u0441\u0438\u0442\u0435\u043B\u044C\u043D\u043E \u0441\u043E\u0441\u0435\u0434\u043D\u0438\u0445. \u0412\u0438\u0434\u043D\u043E \u0442\u043E\u043B\u044C\u043A\u043E \u0433\u043B\u0430\u0437\u0430\u043C\u0438, \u0432
17883
+ \u043A\u043E\u043D\u0441\u043E\u043B\u0438 \u043F\u0443\u0441\u0442\u043E (\u0441\u043D\u0438\u043C\u043E\u043A 2026-09-10). */
17884
+ .rail li.at {
17885
+ background: var(--yellow);
17886
+ animation: breathe 1.6s var(--ease) infinite;
17887
+ }
17888
+
17889
+ /* \u2500\u2500\u2500 \u0427\u0442\u043E \u0441\u0435\u0439\u0447\u0430\u0441 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
17890
+
17891
+ .now { display: flex; align-items: flex-start; gap: 10px; margin-top: 14px; }
17892
+ .now[hidden] { display: none; }
17893
+ /* \u041E\u0433\u043E\u043D\u0451\u043A \u0441\u043B\u0435\u0432\u0430 \u2014 \u0435\u0434\u0438\u043D\u0441\u0442\u0432\u0435\u043D\u043D\u043E\u0435 \u0434\u0432\u0438\u0436\u0443\u0449\u0435\u0435\u0441\u044F \u043C\u0435\u0441\u0442\u043E: \u043F\u043E\u043A\u0430 \u043E\u043D \u0434\u044B\u0448\u0438\u0442, \u0440\u0430\u0431\u043E\u0442\u0430 \u0438\u0434\u0451\u0442.
17894
+ \u041E\u043D \u0436\u0435 \u0433\u0430\u0441\u043D\u0435\u0442 \u0432 \u043A\u043E\u043D\u0446\u0435, \u0438 \u0433\u0430\u0441\u043D\u0435\u0442 \u043C\u043E\u043B\u0447\u0430 \u2014 \u043D\u0430 \u0435\u0433\u043E \u043C\u0435\u0441\u0442\u0435 \u043F\u043E\u044F\u0432\u043B\u044F\u0435\u0442\u0441\u044F \u0437\u043D\u0430\u043A. */
17895
+ .now::before {
17896
+ content: "";
17897
+ flex: none;
17898
+ width: 8px;
17899
+ height: 8px;
17900
+ margin-top: 7px;
17901
+ border-radius: 50%;
17902
+ background: var(--yellow);
17903
+ animation: pulse 1.4s var(--ease) infinite;
17767
17904
  }
17768
- for (const said of data.warnings ?? []) lines.push(said);
17769
- return lines.join("\n");
17770
- }
17771
- function otherContract(said, expected) {
17772
- return `\u0414\u0432\u0438\u0436\u043E\u043A \u0433\u043E\u0432\u043E\u0440\u0438\u0442 \u043D\u0430 \u0434\u043E\u0433\u043E\u0432\u043E\u0440\u0435 \xAB${String(said)}\xBB, \u0430 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u0435 \u043F\u043E\u043D\u0438\u043C\u0430\u0435\u0442 \xAB${expected}\xBB. \u041E\u0431\u043D\u043E\u0432\u0438 \u0442\u043E, \u0447\u0442\u043E \u0441\u0442\u0430\u0440\u0435\u0435: setup \u0441 what=engine \u0434\u043B\u044F \u0434\u0432\u0438\u0436\u043A\u0430, what=shell \u0434\u043B\u044F \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F.`;
17773
- }
17774
- async function askCatalog(engine, pack, video) {
17775
- const answer = await engine.command([
17776
- "capabilities",
17777
- "--pack",
17778
- pack,
17779
- ...video !== void 0 ? ["--video", path(video)] : []
17780
- ]);
17781
- if (!answer.ok) return `\u0421\u043F\u0438\u0441\u043E\u043A \u0442\u043E\u0433\u043E, \u0447\u0442\u043E \u0443\u043C\u0435\u0435\u0442 \u043C\u043E\u043D\u0442\u0430\u0436, \u043D\u0435 \u043F\u0440\u0438\u0448\u0451\u043B: ${answer.text}`;
17782
- let data;
17783
- try {
17784
- data = JSON.parse(answer.text);
17785
- } catch {
17786
- return `\u0421\u043F\u0438\u0441\u043E\u043A \u0442\u043E\u0433\u043E, \u0447\u0442\u043E \u0443\u043C\u0435\u0435\u0442 \u043C\u043E\u043D\u0442\u0430\u0436, \u043D\u0435 \u043F\u0440\u0438\u0448\u0451\u043B: ${NOT_JSON}`;
17905
+ .now__t { display: block; font-size: 17px; font-weight: 700; letter-spacing: -0.02em; line-height: 1.2; }
17906
+ .now__c { display: block; margin-top: 3px; color: var(--ink-soft); font-size: 13px; line-height: 1.4; }
17907
+ .now__c[hidden] { display: none; }
17908
+
17909
+ /* \u0421\u0442\u0440\u043E\u043A\u0430 \u0434\u0432\u0438\u0436\u043A\u0430: \u0441\u043A\u043E\u043B\u044C\u043A\u043E \u0441\u043A\u0430\u0447\u0430\u043D\u043E, \u0441\u043A\u043E\u043B\u044C\u043A\u043E \u0440\u0430\u0441\u043F\u043E\u0437\u043D\u0430\u043D\u043E. \u0413\u043E\u043B\u0443\u0431\u0430\u044F \u043C\u0435\u0442\u043A\u0430, \u043F\u043E\u0442\u043E\u043C\u0443
17910
+ \u0447\u0442\u043E \u044D\u0442\u043E \u0433\u043E\u043B\u043E\u0441 \u0440\u0430\u0431\u043E\u0442\u044B, \u0430 \u043D\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0438 \u043D\u0435 \u0431\u0435\u0434\u0430. */
17911
+ .msg {
17912
+ display: flex;
17913
+ align-items: flex-start;
17914
+ gap: 9px;
17915
+ margin-top: 12px;
17916
+ padding: 9px 13px;
17917
+ border-radius: 12px;
17918
+ background: var(--note-bg);
17919
+ font-size: 13px;
17920
+ line-height: 1.4;
17787
17921
  }
17788
- if (data.contract !== CAPABILITIES_CONTRACT) {
17789
- return `\u0414\u0432\u0438\u0436\u043E\u043A \u0433\u043E\u0432\u043E\u0440\u0438\u0442 \u043D\u0430 \u0434\u043E\u0433\u043E\u0432\u043E\u0440\u0435 \xAB${String(data.contract)}\xBB, \u0430 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u0435 \u043F\u043E\u043D\u0438\u043C\u0430\u0435\u0442 \xAB${CAPABILITIES_CONTRACT}\xBB, \u0438 \u0441\u043F\u0438\u0441\u043E\u043A \u0442\u043E\u0433\u043E, \u0447\u0442\u043E \u0443\u043C\u0435\u0435\u0442 \u043C\u043E\u043D\u0442\u0430\u0436, \u043D\u0435 \u043F\u0440\u043E\u0447\u0438\u0442\u0430\u043D. \u041E\u0431\u043D\u043E\u0432\u0438 \u0442\u043E, \u0447\u0442\u043E \u0441\u0442\u0430\u0440\u0435\u0435: setup \u0441 what=engine \u0434\u043B\u044F \u0434\u0432\u0438\u0436\u043A\u0430, what=shell \u0434\u043B\u044F \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F.`;
17922
+ .msg[hidden] { display: none; }
17923
+ .msg::before {
17924
+ content: "";
17925
+ flex: none;
17926
+ width: 7px;
17927
+ height: 7px;
17928
+ margin-top: 6px;
17929
+ border-radius: 50%;
17930
+ background: var(--note-dot);
17790
17931
  }
17791
- return catalogInWords(data);
17792
- }
17793
- function fromWords(text2, contract) {
17794
- let data;
17795
- try {
17796
- data = JSON.parse(text2);
17797
- } catch {
17798
- return { refusal: NOT_JSON };
17932
+
17933
+
17934
+ /* \u2500\u2500\u2500 \u0428\u043A\u0430\u043B\u0430: \u0441\u043A\u043E\u043B\u044C\u043A\u043E \u0441\u043A\u0430\u0447\u0430\u043D\u043E, \u0441\u043A\u043E\u043B\u044C\u043A\u043E \u0433\u043E\u0442\u043E\u0432\u043E \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
17935
+
17936
+ /* \u26A0 \u0428\u041A\u0410\u041B\u0410 \u2014 \u041E\u0414\u041D\u0410 \u041D\u0410 \u0421\u041A\u0410\u0427\u0418\u0412\u0410\u041D\u0418\u0415 \u0418 \u041D\u0410 \u041A\u0410\u0420\u0422\u041E\u0427\u041A\u0423. \u0412\u043B\u0430\u0434\u0435\u043B\u0435\u0446 2026-09-24: \xAB\u0447\u0442\u043E
17937
+ \u0441\u0442\u0430\u0432\u043B\u044E, \u0447\u0442\u043E \u043E\u0441\u0442\u0430\u043B\u043E\u0441\u044C, \u043F\u0440\u043E\u0433\u0440\u0435\u0441\u0441-\u0431\u0430\u0440\xBB. \u0416\u0451\u043B\u0442\u0430\u044F \u0437\u0430\u043B\u0438\u0432\u043A\u0430 \u2014 \u044D\u0442\u043E \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435, \u0442\u0430 \u0436\u0435
17938
+ \u0440\u043E\u043B\u044C, \u0447\u0442\u043E \u0443 \u0438\u0434\u0443\u0449\u0435\u0433\u043E \u044D\u0442\u0430\u043F\u0430; \u0448\u0438\u0440\u0438\u043D\u0443 \u0441\u0442\u0430\u0432\u0438\u0442 \u0441\u043A\u0440\u0438\u043F\u0442, \u0430 \u043F\u0435\u0440\u0435\u0445\u043E\u0434 \u043F\u043E \u0448\u0438\u0440\u0438\u043D\u0435
17939
+ \u043F\u043B\u0430\u0432\u043D\u044B\u0439, \u0447\u0442\u043E\u0431\u044B \u043E\u043F\u0440\u043E\u0441 \u0440\u0430\u0437 \u0432 2,5 \u0441 \u043D\u0435 \u0434\u0451\u0440\u0433\u0430\u043B \u0435\u0451 \u0441\u043A\u0430\u0447\u043A\u0430\u043C\u0438. */
17940
+ .meter {
17941
+ position: relative;
17942
+ height: 8px;
17943
+ margin-top: 12px;
17944
+ border-radius: 4px;
17945
+ background: var(--off);
17946
+ overflow: hidden;
17799
17947
  }
17800
- if (contract !== void 0 && data.contract !== contract) {
17801
- return { refusal: otherContract(data.contract, contract) };
17948
+ .meter__fill {
17949
+ display: block;
17950
+ width: 0;
17951
+ height: 100%;
17952
+ border-radius: 4px;
17953
+ background: var(--yellow);
17954
+ transition: width .6s var(--ease);
17802
17955
  }
17803
- if (typeof data.words !== "string" || data.words === "") return { refusal: NOT_JSON };
17804
- return { words: data.words, data };
17805
- }
17806
- function folderAnswer(text2) {
17807
- const read = fromWords(text2);
17808
- return "refusal" in read ? toolError(read.refusal) : toolSuccess(read.words, read.data);
17809
- }
17810
- var DRAFT_CONTRACT = "naparnik-draft/1";
17811
- var VIEW_CONTRACT = "naparnik-view/1";
17812
- var EDIT_CONTRACT = "naparnik-edit/1";
17813
- function answerOrRefusal(text2, contract) {
17814
- const read = fromWords(text2, contract);
17815
- if ("refusal" in read) {
17816
- const plain = text2.trim();
17817
- return { refusal: plain.startsWith("{") || plain === "" ? read.refusal : plain };
17956
+ .meter__cap {
17957
+ margin: 7px 0 0;
17958
+ color: var(--ink-soft);
17959
+ font-size: 13px;
17960
+ line-height: 1.4;
17961
+ font-variant-numeric: tabular-nums;
17818
17962
  }
17819
- return read.data["ok"] === false ? { refusal: read.words } : read;
17820
- }
17821
- async function draftDocument(engine, place, asked, key) {
17822
- const answer = await engine.command([
17823
- "document-draft",
17824
- "--video",
17825
- asked.video,
17826
- "--pack",
17827
- place.pack,
17828
- ...asked.style !== void 0 ? ["--style", path(asked.style)] : [],
17829
- ...(asked.also ?? []).flatMap((one) => ["--also", path(one)]),
17830
- ...asked.ask !== void 0 ? ["--ask", JSON.stringify(asked.ask)] : [],
17831
- "--json"
17832
- ], key !== void 0 ? { key } : {});
17833
- return answer.ok ? answerOrRefusal(answer.text, DRAFT_CONTRACT) : { refusal: answer.text };
17834
- }
17835
- async function editOperations(engine, place, asked, key) {
17836
- const answer = await engine.command([
17837
- "document-edit",
17838
- "--project",
17839
- path(asked.reel),
17840
- "--ops",
17841
- JSON.stringify(asked.ops),
17842
- ...asked.stamps !== void 0 ? ["--stamps", JSON.stringify(asked.stamps)] : [],
17843
- "--by",
17844
- asked.by ?? "model",
17845
- "--pack",
17846
- place.pack,
17847
- "--json"
17848
- ], key !== void 0 ? { key } : {});
17849
- return answer.ok ? answerOrRefusal(answer.text, EDIT_CONTRACT) : { refusal: answer.text };
17850
- }
17851
- function nameOrRefusal(candidate) {
17852
- const looksLikePath2 = candidate.includes("/") || candidate.includes("\\") || candidate.startsWith("~") || candidate.startsWith(".") || candidate.length > 1 && candidate[1] === ":";
17853
- if (!looksLikePath2) return { name: candidate };
17854
- return {
17855
- refusal: `\u0417\u0434\u0435\u0441\u044C \u0436\u0434\u0443\u0442 \u0418\u041C\u042F \u0448\u0430\u0433\u0430, \u0430 \u043F\u0440\u0438\u0448\u0451\u043B \u043F\u0443\u0442\u044C: ${candidate}
17856
- \u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C: \u043D\u0430\u0437\u043E\u0432\u0438 \u0448\u0430\u0433 \u043E\u0434\u043D\u0438\u043C \u0441\u043B\u043E\u0432\u043E\u043C \u2014 \u0442\u0430\u043A, \u043A\u0430\u043A \u043D\u0430\u0437\u044B\u0432\u0430\u0435\u0442\u0441\u044F \u0435\u0433\u043E \u043F\u0430\u043F\u043A\u0430. \u0421\u0432\u043E\u0439 \u0448\u0430\u0433 \u043B\u0435\u0436\u0438\u0442 \u0432 \`mine/steps/<\u0438\u043C\u044F>\` \u0432 \u0434\u043E\u043C\u0435 \u041D\u0430\u043F\u0430\u0440\u043D\u0438\u043A\u0430, \u043D\u0430\u0448\u0438 \u043F\u0435\u0440\u0435\u0447\u0438\u0441\u043B\u044F\u0435\u0442 setup, \u0438\u043C\u044F \u0443 \u043A\u0430\u0436\u0434\u043E\u0433\u043E \u0441\u0442\u043E\u0438\u0442 \u0432 \u0441\u043A\u043E\u0431\u043A\u0430\u0445.`
17857
- };
17858
- }
17859
- var SETUP_JOB_MARK = "setup-";
17860
- function isSetupJob(id) {
17861
- return id.startsWith(SETUP_JOB_MARK);
17862
- }
17863
- var TITLE_UPDATE = "\u041E\u0431\u043D\u043E\u0432\u043B\u044F\u044E \u0431\u0438\u0431\u043B\u0438\u043E\u0442\u0435\u043A\u0438 \u0434\u043B\u044F \u043C\u043E\u043D\u0442\u0430\u0436\u0430";
17864
- var TITLE_INSTALL = "\u0423\u0441\u0442\u0430\u043D\u0430\u0432\u043B\u0438\u0432\u0430\u044E \u0431\u0438\u0431\u043B\u0438\u043E\u0442\u0435\u043A\u0438 \u0434\u043B\u044F \u043C\u043E\u043D\u0442\u0430\u0436\u0430";
17865
- var SAY_RESTART = "\u0413\u043E\u0442\u043E\u0432\u043E. \u041F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u0442\u0438 Claude \u2014 \u043D\u043E\u0432\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u0437\u0430\u0440\u0430\u0431\u043E\u0442\u0430\u0435\u0442 \u043F\u043E\u0441\u043B\u0435 \u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u043A\u0430.";
17866
- var SAY_NOTHING = "\u0412\u0441\u0451 \u0443\u0436\u0435 \u0441\u0442\u043E\u0438\u0442 \u2014 \u043C\u043E\u0436\u043D\u043E \u043C\u043E\u043D\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C.";
17867
- var SAY_INSTALLED = "\u0413\u043E\u0442\u043E\u0432\u043E \u2014 \u043C\u043E\u0436\u043D\u043E \u043C\u043E\u043D\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C.";
17868
- var ADVICE_ASK = "\u041D\u0430\u043F\u0438\u0448\u0438 \u041A\u043B\u043E\u0434\u0443 \xAB\u0447\u0442\u043E \u0441\u043B\u0443\u0447\u0438\u043B\u043E\u0441\u044C\xBB \u2014 \u043E\u043D \u0440\u0430\u0441\u0441\u043A\u0430\u0436\u0435\u0442, \u0447\u0442\u043E \u043F\u043E\u0448\u043B\u043E \u043D\u0435 \u0442\u0430\u043A.";
17869
- var CHECK = "\u041F\u0440\u043E\u0432\u0435\u0440\u044F\u044E, \u0447\u0442\u043E \u043E\u0431\u043D\u043E\u0432\u0438\u0442\u044C";
17870
- var INSTALL_NEW = "\u0421\u0442\u0430\u0432\u043B\u044E \u043D\u043E\u0432\u0443\u044E \u0432\u0435\u0440\u0441\u0438\u044E";
17871
- var MISSING = "\u0421\u0442\u0430\u0432\u043B\u044E \u043D\u0435\u0434\u043E\u0441\u0442\u0430\u044E\u0449\u0435\u0435";
17872
- var works = /* @__PURE__ */ new Map();
17873
- var JOBS_DIR = "jobs";
17874
- var JOBS_KEPT2 = 10;
17875
- var BEAT_MS = 1e4;
17876
- var STALE_MS = 6e4;
17877
- var JOB_ID = /^setup-[\w-]{1,80}$/;
17878
- function running(home, clock) {
17879
- for (const work of works.values()) if (work.ended === null) return work.id;
17880
- if (home === null) return null;
17881
- for (const record2 of records(home)) {
17882
- if (record2.ended === null && alive(record2, clock)) return record2.id;
17963
+ .meter__cap b { color: var(--ink); font-weight: 650; }
17964
+ .dl[hidden], .meter[hidden], .meter__cap[hidden] { display: none; }
17965
+
17966
+ /* \u2500\u2500\u2500 \u041A\u0430\u0440\u0442\u043E\u0447\u043A\u0430 \u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u044F: \u043E\u0442\u0432\u0435\u0442 setup \u0431\u0435\u0437 \u0437\u0430\u0434\u0430\u0447\u0438 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
17967
+
17968
+ /* \u26A0 \u041A\u0410\u0420\u0422\u041E\u0427\u041A\u0410 \u0412\u041C\u0415\u0421\u0422\u041E \u0421\u0412\u0401\u0420\u0422\u041A\u0418, \u0418 \u042D\u0422\u041E \u0416\u0418\u0412\u0410\u042F \u041F\u041E\u041B\u041E\u041C\u041A\u0410 2026-09-24. \u0420\u0430\u043C\u043A\u0443 \u0432\u0438\u0434\u0436\u0435\u0442\u0430
17969
+ \u0445\u043E\u0441\u0442 \u0440\u0438\u0441\u0443\u0435\u0442 \u043D\u0430 \u043A\u0430\u0436\u0434\u043E\u043C \u0432\u044B\u0437\u043E\u0432\u0435 setup; \u0441\u0432\u0451\u0440\u043D\u0443\u0442\u0430\u044F \u043F\u043E\u043B\u043E\u0441\u0430 \u0432 Claude Desktop
17970
+ \u043E\u0441\u0442\u0430\u0432\u043B\u044F\u043B\u0430 \u043F\u043E\u0434 \u043E\u0442\u0432\u0435\u0442\u043E\u043C \u043F\u0443\u0441\u0442\u0443\u044E \u0441\u0435\u0440\u0443\u044E \u043F\u043B\u0430\u0448\u043A\u0443. */
17971
+ .card[hidden] { display: none; }
17972
+ .card__meta { margin: 4px 0 0; color: var(--ink-soft); font-size: 12.5px; font-variant-numeric: tabular-nums; }
17973
+ .card__meta[hidden] { display: none; }
17974
+ /* \u041D\u043E\u0432\u043E\u0441\u0442\u044C \u043E \u0432\u0435\u0440\u0441\u0438\u0438 \u2014 \u0442\u0440\u0438 \u0441\u0442\u0440\u043E\u043A\u0438 \u0432\u043B\u0430\u0434\u0435\u043B\u044C\u0446\u0430: \u0447\u0442\u043E \u0432\u044B\u0448\u043B\u043E, \u0432\u043E\u043F\u0440\u043E\u0441, \u0447\u0442\u043E \u043D\u0430\u043F\u0438\u0441\u0430\u0442\u044C. */
17975
+ #cardUpdate { white-space: pre-line; }
17976
+ .parts { display: grid; gap: 2px 18px; margin: 14px 0 0; padding: 0; list-style: none; }
17977
+ .parts[hidden] { display: none; }
17978
+ .part {
17979
+ display: flex;
17980
+ align-items: center;
17981
+ gap: 10px;
17982
+ min-width: 0;
17983
+ padding: 6px 0;
17984
+ border-bottom: 1px solid var(--edge);
17985
+ font-size: 14px;
17986
+ line-height: 1.3;
17883
17987
  }
17884
- return null;
17885
- }
17886
- function records(home) {
17887
- let names;
17888
- try {
17889
- names = readdirSync(join(home, JOBS_DIR)).filter((name) => name.endsWith(".json"));
17890
- } catch {
17891
- return [];
17988
+ /* \u0417\u043D\u0430\u043A \u0447\u0430\u0441\u0442\u0438 \u2014 \u0444\u043E\u0440\u043C\u0430, \u0430 \u043D\u0435 \u0442\u043E\u043B\u044C\u043A\u043E \u0446\u0432\u0435\u0442: \u0441\u0442\u043E\u0438\u0442 \u2014 \u0437\u0430\u043B\u0438\u0442\u044B\u0439 \u043A\u0440\u0443\u0436\u043E\u043A \u0441 \u0433\u0430\u043B\u043E\u0447\u043A\u043E\u0439,
17989
+ \u043D\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442 \u2014 \u0436\u0451\u043B\u0442\u043E\u0435 \u043A\u043E\u043B\u044C\u0446\u043E, \u043F\u043E \u043F\u0440\u043E\u0441\u044C\u0431\u0435 \u2014 \u0433\u043E\u043B\u0443\u0431\u043E\u0435 \u043F\u0443\u043D\u043A\u0442\u0438\u0440\u043D\u043E\u0435. */
17990
+ .part__m {
17991
+ position: relative;
17992
+ flex: none;
17993
+ width: 16px;
17994
+ height: 16px;
17995
+ border-radius: 50%;
17996
+ box-sizing: border-box;
17892
17997
  }
17893
- return names.sort().reverse().map((name) => load(home, name.slice(0, -".json".length))).filter((record2) => record2 !== null);
17894
- }
17895
- function load(home, id) {
17896
- if (!JOB_ID.test(id)) return null;
17897
- try {
17898
- const value = JSON.parse(readFileSync(join(home, JOBS_DIR, `${id}.json`), "utf8"));
17899
- if (value.id !== id || typeof value.what !== "string" || typeof value.started !== "number" || !Array.isArray(value.stages) || typeof value.at !== "number" || typeof value.pid !== "number" || typeof value.beat !== "number") return null;
17900
- return {
17901
- id,
17902
- what: value.what,
17903
- started: value.started,
17904
- stages: value.stages.map(String),
17905
- at: value.at,
17906
- message: typeof value.message === "string" ? value.message : "",
17907
- ended: value.ended ?? null,
17908
- pid: value.pid,
17909
- beat: value.beat
17910
- };
17911
- } catch {
17912
- return null;
17998
+ .part.ok .part__m { background: var(--good); }
17999
+ .part.ok .part__m::before {
18000
+ content: "";
18001
+ position: absolute;
18002
+ top: 4px;
18003
+ left: 4px;
18004
+ width: 7px;
18005
+ height: 3.5px;
18006
+ border-left: 1.8px solid var(--good-ink);
18007
+ border-bottom: 1.8px solid var(--good-ink);
18008
+ transform: rotate(-45deg);
17913
18009
  }
17914
- }
17915
- function alive(record2, clock) {
17916
- if (clock() - record2.beat > STALE_MS) return false;
17917
- try {
17918
- process.kill(record2.pid, 0);
17919
- return true;
17920
- } catch (trouble) {
17921
- return trouble.code === "EPERM";
18010
+ .part.missing .part__m { border: 2.5px solid var(--yellow); }
18011
+ .part.later .part__m { border: 2px dashed var(--note-dot); }
18012
+ .part__t { display: block; flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
18013
+ .part.ok .part__t { color: var(--ink-soft); }
18014
+ .part__w { flex: none; color: var(--ink-soft); font-size: 12.5px; font-variant-numeric: tabular-nums; }
18015
+ .part.missing .part__w { color: var(--ink); font-weight: 650; }
18016
+ /* \u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C \u0434\u0430\u043B\u044C\u0448\u0435 \u2014 \u043A\u0440\u0443\u043F\u043D\u0435\u0435 \u0441\u043F\u0438\u0441\u043A\u0430: \u044D\u0442\u043E \u043E\u0442\u0432\u0435\u0442 \u043D\u0430 \xAB\u0438 \u0447\u0442\u043E \u0442\u0435\u043F\u0435\u0440\u044C\xBB. */
18017
+ .next {
18018
+ display: flex;
18019
+ align-items: flex-start;
18020
+ gap: 9px;
18021
+ margin: 14px 0 0;
18022
+ font-size: 15px;
18023
+ font-weight: 650;
18024
+ line-height: 1.35;
18025
+ letter-spacing: -0.01em;
17922
18026
  }
17923
- }
17924
- function save(work, clock) {
17925
- if (work.home === null) return;
17926
- try {
17927
- const dir = join(work.home, JOBS_DIR);
17928
- mkdirSync(dir, { recursive: true });
17929
- const file2 = join(dir, `${work.id}.json`);
17930
- const temp = `${file2}.${process.pid}.tmp`;
17931
- const record2 = {
17932
- id: work.id,
17933
- what: work.what,
17934
- started: work.started,
17935
- stages: work.stages,
17936
- at: work.at,
17937
- message: work.message,
17938
- ended: work.ended,
17939
- pid: process.pid,
17940
- beat: clock()
17941
- };
17942
- writeFileSync(temp, JSON.stringify(record2), "utf8");
17943
- renameSync(temp, file2);
17944
- } catch {
18027
+ .next[hidden] { display: none; }
18028
+ .next::before {
18029
+ content: "";
18030
+ flex: none;
18031
+ width: 8px;
18032
+ height: 8px;
18033
+ margin-top: 6px;
18034
+ border-radius: 2px;
18035
+ background: var(--yellow);
17945
18036
  }
17946
- }
17947
- function prune2(home) {
17948
- try {
17949
- const dir = join(home, JOBS_DIR);
17950
- const names = readdirSync(dir).filter((name) => JOB_ID.test(name.replace(/\.json$/, ""))).sort();
17951
- for (const name of names.slice(0, Math.max(0, names.length - JOBS_KEPT2))) rmSync(join(dir, name), { force: true });
17952
- } catch {
18037
+
18038
+ /* \u2500\u2500\u2500 \u041A\u043E\u043D\u0435\u0446 \u0440\u0430\u0431\u043E\u0442\u044B \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
18039
+
18040
+ /* \u26A0 \u041E\u0422\u0412\u0415\u0422 \u041A\u0420\u0423\u041F\u041D\u0415\u0415 \u0425\u041E\u0414\u0410. \u041E\u0442\u0431\u0440\u0430\u043A\u043E\u0432\u043A\u0430 \u0432\u043B\u0430\u0434\u0435\u043B\u044C\u0446\u0430 \u043D\u0430 \u0444\u043E\u0440\u043C\u0435 \u0432\u044B\u0431\u043E\u0440\u0430 2026-09-10:
18041
+ \u0441\u0435\u0440\u0430\u044F \u0441\u0442\u0440\u043E\u0447\u043A\u0430 \u0432 \u0442\u043E\u043D \u043F\u043E\u0434\u0441\u043A\u0430\u0437\u043A\u0435 \u043D\u0435 \u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044F \u043A\u0430\u043A \u043E\u0442\u0432\u0435\u0442. \u0417\u0434\u0435\u0441\u044C \u0442\u043E \u0436\u0435: \u0447\u0435\u043B\u043E\u0432\u0435\u043A
18042
+ \u0436\u0434\u0430\u043B \u043C\u0438\u043D\u0443\u0442\u044B \u0438 \u043E\u0431\u044F\u0437\u0430\u043D \u0443\u0432\u0438\u0434\u0435\u0442\u044C \u043A\u043E\u043D\u0435\u0446 \u0440\u0430\u0431\u043E\u0442\u044B \u0441 \u043F\u0435\u0440\u0432\u043E\u0433\u043E \u0432\u0437\u0433\u043B\u044F\u0434\u0430. */
18043
+ .end { display: flex; align-items: flex-start; gap: 12px; margin-top: 18px; animation: drop .5s var(--ease); }
18044
+ .end[hidden] { display: none; }
18045
+ .end__m {
18046
+ position: relative;
18047
+ flex: none;
18048
+ width: 34px;
18049
+ height: 34px;
18050
+ border-radius: 50%;
18051
+ background: var(--good);
18052
+ box-shadow: 0 6px 18px -8px var(--good);
18053
+ /* \u26A0 \u0411\u0415\u0417 \u0417\u0410\u041B\u0418\u0412\u041A\u0418 \u041D\u0410\u0417\u0410\u0414: \u043D\u0430\u0440\u0438\u0441\u043E\u0432\u0430\u043D\u043D\u044B\u0439 \u0432 \u0441\u043A\u0440\u044B\u0442\u043E\u043C \u0431\u043B\u043E\u043A\u0435 \u0437\u043D\u0430\u043A \u0437\u0430\u043B\u0438\u043F\u0430\u043B \u0431\u044B
18054
+ \u043F\u0440\u043E\u0437\u0440\u0430\u0447\u043D\u044B\u043C \u2014 \u0430\u043D\u0438\u043C\u0430\u0446\u0438\u044F \u0432 \u0441\u043A\u0440\u044B\u0442\u043E\u043C \u043E\u043A\u043D\u0435 \u043D\u0435 \u0441\u0442\u0430\u0440\u0442\u0443\u0435\u0442 (\u043D\u0430\u0448\u0451\u043B \u0441\u0442\u0435\u043D\u0434
18055
+ 2026-09-12, \u0442\u0430 \u0436\u0435 \u0431\u0435\u0434\u0430 \u0431\u044B\u043B\u0430 \u0443 \u0441\u0442\u0440\u043E\u043A \u0444\u043E\u0440\u043C\u044B \u0432\u044B\u0431\u043E\u0440\u0430). */
18056
+ animation: pop .55s var(--ease);
17953
18057
  }
17954
- }
17955
- function fromDisk(home, id, clock) {
17956
- const record2 = load(home, id);
17957
- if (record2 === null) return null;
17958
- if (record2.ended !== null || alive(record2, clock)) return record2;
17959
- return {
17960
- ...record2,
17961
- ended: {
17962
- at: record2.beat,
17963
- ending: {
17964
- ok: false,
17965
- trouble: "\u041E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0435 \u043E\u0431\u043E\u0440\u0432\u0430\u043B\u043E\u0441\u044C: \u043F\u0440\u043E\u0433\u0440\u0430\u043C\u043C\u0430, \u043A\u043E\u0442\u043E\u0440\u0430\u044F \u0435\u0433\u043E \u0432\u0435\u043B\u0430, \u0437\u0430\u043A\u0440\u044B\u043B\u0430\u0441\u044C \u043F\u043E\u0441\u0440\u0435\u0434\u0438 \u0440\u0430\u0431\u043E\u0442\u044B. \u041F\u0440\u0435\u0436\u043D\u044F\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u043D\u0430 \u043C\u0435\u0441\u0442\u0435, \u043C\u043E\u043D\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u043C\u043E\u0436\u043D\u043E.",
17966
- advice: "\u041D\u0430\u043F\u0438\u0448\u0438 \xAB\u043E\u0431\u043D\u043E\u0432\u0438\xBB \u0435\u0449\u0451 \u0440\u0430\u0437 \u2014 \u043D\u0430\u0447\u043D\u0443 \u0437\u0430\u043D\u043E\u0432\u043E.",
17967
- report: `\u041F\u0440\u043E\u0446\u0435\u0441\u0441 \u043E\u0431\u043E\u043B\u043E\u0447\u043A\u0438 ${record2.pid}, \u043A\u043E\u0442\u043E\u0440\u044B\u0439 \u0432\u0451\u043B \u0437\u0430\u0434\u0430\u0447\u0443, \u043F\u0440\u043E\u043F\u0430\u043B \u043D\u0430 \u044D\u0442\u0430\u043F\u0435 \xAB${record2.stages[record2.at - 1] ?? CHECK}\xBB.`
17968
- }
17969
- }
17970
- };
17971
- }
17972
- function startSetupJob(what, run, clock = Date.now, home = null) {
17973
- const already = running(home, clock);
17974
- if (already !== null) return already;
17975
- const started = clock();
17976
- const id = `${SETUP_JOB_MARK}${new Date(started).toISOString().replace(/[:.]/g, "-")}`;
17977
- const work = {
17978
- id,
17979
- what,
17980
- started,
17981
- stages: [CHECK],
17982
- at: 1,
17983
- message: "",
17984
- ended: null,
17985
- done: Promise.resolve(),
17986
- home
17987
- };
17988
- const control = {
17989
- plan(stages) {
17990
- work.stages = stages;
17991
- work.at = Math.min(work.at, stages.length);
17992
- save(work, clock);
17993
- },
17994
- go(stage) {
17995
- const index = work.stages.indexOf(stage);
17996
- if (index >= 0) work.at = index + 1;
17997
- work.message = "";
17998
- save(work, clock);
17999
- },
18000
- line(text2) {
18001
- work.message = text2;
18002
- save(work, clock);
18003
- }
18004
- };
18005
- works.set(id, work);
18006
- if (home !== null) prune2(home);
18007
- save(work, clock);
18008
- const beat = home === null ? null : setInterval(() => save(work, clock), BEAT_MS);
18009
- beat?.unref();
18010
- work.done = collectJobInstallFaults(id, () => run(control).catch((trouble) => {
18011
- noteInstallFault("update-job", trouble);
18012
- return {
18013
- ok: false,
18014
- trouble: "\u0427\u0442\u043E-\u0442\u043E \u0441\u043B\u043E\u043C\u0430\u043B\u043E\u0441\u044C \u043F\u043E\u0441\u0440\u0435\u0434\u0438 \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u044F \u2014 \u043F\u0440\u0435\u0436\u043D\u044F\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u043D\u0430 \u043C\u0435\u0441\u0442\u0435, \u043C\u043E\u043D\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u043C\u043E\u0436\u043D\u043E.",
18015
- advice: ADVICE_ASK,
18016
- report: String(trouble instanceof Error ? trouble.message : trouble)
18017
- };
18018
- })).then((ending) => {
18019
- work.ended = { at: clock(), ending };
18020
- if (beat !== null) clearInterval(beat);
18021
- save(work, clock);
18022
- });
18023
- return id;
18024
- }
18025
- function quiet(line) {
18026
- return line.replace(/^⚠\s*/, "").replace(/^Что делать:/, "\u0421\u043E\u0432\u0435\u0442:");
18027
- }
18028
- function setupJobText(id, clock = Date.now, home = null) {
18029
- const work = works.get(id) ?? (home === null ? null : fromDisk(home, id, clock));
18030
- if (work === null) return null;
18031
- const head2 = `\u0417\u0430\u0434\u0430\u043D\u0438\u0435 ${work.id}: ${work.what}`;
18032
- if (work.ended === null) {
18033
- const sec2 = Math.max(0, Math.round((clock() - work.started) / 1e3));
18034
- return [
18035
- head2,
18036
- `\u042D\u0442\u0430\u043F ${work.at} \u0438\u0437 ${work.stages.length}: ${work.stages[work.at - 1] ?? CHECK}`,
18037
- ...work.message === "" ? [] : [work.message],
18038
- `\u0415\u0449\u0451 \u0441\u0447\u0438\u0442\u0430\u0435\u0442, ${sec2} \u0441.`
18039
- ].join("\n");
18058
+ /* \u0413\u0430\u043B\u043E\u0447\u043A\u0430 \u043D\u0430\u0440\u0438\u0441\u043E\u0432\u0430\u043D\u0430 \u0434\u0432\u0443\u043C\u044F \u043A\u0440\u043E\u043C\u043A\u0430\u043C\u0438, \u0430 \u043D\u0435 \u043D\u0430\u0431\u0440\u0430\u043D\u0430 \u0441\u0438\u043C\u0432\u043E\u043B\u043E\u043C: \u044E\u043D\u0438\u043A\u043E\u0434\u043D\u0430\u044F \xAB\u2713\xBB \u0432
18059
+ \u0441\u0438\u0441\u0442\u0435\u043C\u043D\u043E\u043C \u0448\u0440\u0438\u0444\u0442\u0435 \u043D\u0430 \u043A\u0430\u0436\u0434\u043E\u0439 \u043F\u043B\u0430\u0442\u0444\u043E\u0440\u043C\u0435 \u0441\u0432\u043E\u0435\u0439 \u0442\u043E\u043B\u0449\u0438\u043D\u044B \u0438 \u0432\u044B\u043B\u0435\u0437\u0430\u0435\u0442 \u0437\u0430 \u043A\u0440\u0443\u0436\u043E\u043A. */
18060
+ .end__m::before {
18061
+ content: "";
18062
+ position: absolute;
18063
+ top: 12px;
18064
+ left: 10px;
18065
+ width: 13px;
18066
+ height: 7px;
18067
+ border-left: 2.5px solid var(--good-ink);
18068
+ border-bottom: 2.5px solid var(--good-ink);
18069
+ transform: rotate(-45deg);
18040
18070
  }
18041
- const sec = Math.max(0, Math.round((work.ended.at - work.started) / 1e3));
18042
- const ending = work.ended.ending;
18043
- const report = ending.report.split("\n").map((line) => line.trim()).filter((line) => line !== "").map(quiet);
18044
- if (ending.ok) {
18045
- return [head2, `\u0413\u043E\u0442\u043E\u0432\u043E \u0437\u0430 ${sec} \u0441.`, `\u0427\u0435\u043B\u043E\u0432\u0435\u043A\u0443: ${ending.say}`, ...report].join("\n");
18071
+ /* \u0423 \u0431\u0435\u0434\u044B \u0437\u043D\u0430\u043A \u0434\u0440\u0443\u0433\u043E\u0439 \u0444\u043E\u0440\u043C\u044B, \u0430 \u043D\u0435 \u0442\u043E\u0442 \u0436\u0435 \u043A\u0440\u0443\u0436\u043E\u043A \u0434\u0440\u0443\u0433\u043E\u0433\u043E \u0446\u0432\u0435\u0442\u0430: \u0446\u0432\u0435\u0442 \u043E\u0434\u0438\u043D
18072
+ \u0447\u0438\u0442\u0430\u044E\u0442 \u043D\u0435 \u0432\u0441\u0435, \u0438 \u0432 \u0442\u0451\u043C\u043D\u043E\u0439 \u0442\u0435\u043C\u0435 \u0437\u0435\u043B\u0451\u043D\u043E\u0435 \u0441 \u043A\u0440\u0430\u0441\u043D\u044B\u043C \u0441\u0431\u043B\u0438\u0436\u0430\u044E\u0442\u0441\u044F. */
18073
+ body.bad .end__m { background: var(--bad); box-shadow: 0 6px 18px -8px var(--bad); border-radius: 10px; }
18074
+ body.bad .end__m::before {
18075
+ top: 8px;
18076
+ left: 16px;
18077
+ width: 2.5px;
18078
+ height: 12px;
18079
+ border: 0;
18080
+ border-radius: 2px;
18081
+ background: var(--good-ink);
18082
+ transform: none;
18046
18083
  }
18047
- return [
18048
- head2,
18049
- ...report,
18050
- `\u041D\u0435 \u043F\u043E\u043B\u0443\u0447\u0438\u043B\u043E\u0441\u044C \u0437\u0430 ${sec} \u0441: ${ending.trouble}`,
18051
- `\u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C: ${ending.advice}`
18052
- ].join("\n");
18053
- }
18054
- function setupJobReport(id, home = null) {
18055
- const text2 = setupJobText(id, Date.now, home);
18056
- return text2 === null ? null : readJob(text2);
18057
- }
18058
- function weightExact(bytes) {
18059
- const mb = bytes / 1024 / 1024;
18060
- if (mb >= 1e3) return `${(mb / 1024).toFixed(1).replace(".", ",")} \u0413\u0411`;
18061
- return `${mb.toFixed(1).replace(".", ",")} \u041C\u0411`;
18062
- }
18063
- async function runUpdate(job, deps) {
18064
- const { engine, key, baseUrl, what } = deps;
18065
- const home = engine.home();
18066
- const wantShell = what !== "engine";
18067
- const hasEngine = engine.place() !== null;
18068
- const wantEngine = what !== "shell" && hasEngine && !engine.pathSetByHand();
18069
- const shellUrl = engine.variable("NAPARNIK_BUNDLE_MANIFEST") ?? bundleUrlFor(baseUrl);
18070
- const [shellAsk, engineAsk] = await Promise.all([
18071
- wantShell ? fetchShellManifest(shellUrl, deps.pointerMs, key) : Promise.resolve(null),
18072
- wantEngine ? fetchManifest(manifestUrl(engine, baseUrl), deps.pointerMs, key) : Promise.resolve(null)
18073
- ]);
18074
- const shellWas = installedShell(home);
18075
- const shell = decideShell(shellWas, shellAsk?.ok === true ? shellAsk.manifest : null);
18076
- const engineWas = engine.freshVersion();
18077
- const fresh = decide(engineWas, engineAsk?.ok === true ? engineAsk.manifest : null);
18078
- const shellStage = shell.what === "newer_available" ? `\u0421\u043A\u0430\u0447\u0438\u0432\u0430\u044E \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u0435 \xB7 ${weightExact(shell.manifest.body?.bytes ?? 0)}` : null;
18079
- const engineStage = fresh.what === "newer_available" ? `\u0421\u043A\u0430\u0447\u0438\u0432\u0430\u044E \u0434\u0432\u0438\u0436\u043E\u043A \xB7 ${weightExact(fresh.manifest.bytes)}` : null;
18080
- const missing = what === "all" && engineStage === null;
18081
- job.plan([
18082
- CHECK,
18083
- ...shellStage === null ? [] : [shellStage],
18084
- ...engineStage === null ? [] : [engineStage, INSTALL_NEW],
18085
- ...missing ? [MISSING] : []
18086
- ]);
18087
- const steps = [];
18088
- let updated = false;
18089
- let installed = false;
18090
- for (const [ask2, whose] of [[shellAsk, "\u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F"], [engineAsk, "\u0434\u0432\u0438\u0436\u043A\u0430"]]) {
18091
- if (ask2 === null || ask2.ok) continue;
18092
- const refusal = refusalWords(ask2.status ?? 0);
18093
- steps.push({
18094
- report: `\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0441\u043F\u0440\u043E\u0441\u0438\u0442\u044C, \u0435\u0441\u0442\u044C \u043B\u0438 \u043D\u043E\u0432\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F ${whose}: ${ask2.why}.`,
18095
- trouble: refusal !== "" ? refusal : "\u041D\u0435 \u043F\u043E\u043B\u0443\u0447\u0438\u043B\u043E\u0441\u044C \u0441\u0432\u044F\u0437\u0430\u0442\u044C\u0441\u044F \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u043E\u043C \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0439."
18096
- });
18084
+ /* \u0422\u043E\u0447\u043A\u0430 \u0432\u043E\u0441\u043A\u043B\u0438\u0446\u0430\u0442\u0435\u043B\u044C\u043D\u043E\u0433\u043E \u0437\u043D\u0430\u043A\u0430. \u0411\u0435\u0437 \u043D\u0435\u0451 \u043D\u0430 \u043A\u0440\u0443\u0436\u043A\u0435 \u0441\u0442\u043E\u0438\u0442 \u043F\u0440\u043E\u0441\u0442\u043E \u043F\u0430\u043B\u043A\u0430, \u0438
18085
+ \u0437\u043D\u0430\u043A \u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044F \u043A\u0430\u043A \xAB\u0438\u0434\u0451\u0442 \u0437\u0430\u0433\u0440\u0443\u0437\u043A\u0430\xBB, \u0430 \u043D\u0435 \u043A\u0430\u043A \xAB\u0441\u0442\u043E\u0439, \u0442\u0443\u0442 \u0431\u0435\u0434\u0430\xBB. */
18086
+ body.bad .end__m::after {
18087
+ content: "";
18088
+ position: absolute;
18089
+ top: 23px;
18090
+ left: 16px;
18091
+ width: 2.5px;
18092
+ height: 2.5px;
18093
+ border-radius: 50%;
18094
+ background: var(--good-ink);
18097
18095
  }
18098
- if (shellAsk?.ok === true && shell.what === "nothing") {
18099
- steps.push({ report: `\u0423 \u0432\u0430\u0441 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u0430 \u0441\u0430\u043C\u0430\u044F \u043F\u043E\u0441\u043B\u0435\u0434\u043D\u044F\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u2014 ${shellWas}.` });
18096
+ .end__x { display: block; padding-top: 2px; min-width: 0; }
18097
+ .end__t { display: block; font-size: 17px; font-weight: 700; letter-spacing: -0.02em; line-height: 1.2; }
18098
+ .end__h { display: block; margin-top: 4px; max-inline-size: 52ch; color: var(--ink-soft); font-size: 13px; line-height: 1.45; }
18099
+ /* \u26A0 \u041F\u0423\u0422\u042C \u041A \u0424\u0410\u0419\u041B\u0423 \u041B\u041E\u041C\u0410\u0415\u0422\u0421\u042F \u041F\u041E \u041B\u042E\u0411\u041E\u041C\u0423 \u041C\u0415\u0421\u0422\u0423. \u0420\u0443\u0441\u0441\u043A\u0438\u0435 \u0438\u043C\u0435\u043D\u0430 \u043F\u0430\u043F\u043E\u043A \u0438 \u043F\u0440\u043E\u0431\u0435\u043B\u044B \u0432
18100
+ \xAB\u041C\u043E\u0438 \u0432\u0438\u0434\u0435\u043E\xBB \u0438\u043D\u0430\u0447\u0435 \u0440\u0430\u0441\u043F\u0438\u0440\u0430\u044E\u0442 \u0431\u043B\u043E\u043A \u0438 \u0437\u0430\u0441\u0442\u0430\u0432\u043B\u044F\u044E\u0442 \u043B\u0435\u043D\u0442\u0443 \u0435\u0445\u0430\u0442\u044C \u0432\u0431\u043E\u043A. */
18101
+ .path {
18102
+ display: block;
18103
+ margin-top: 6px;
18104
+ padding: 7px 10px;
18105
+ border-radius: 9px;
18106
+ background: var(--card);
18107
+ box-shadow: inset 0 0 0 1px var(--edge);
18108
+ color: var(--ink);
18109
+ font-size: 12.5px;
18110
+ line-height: 1.4;
18111
+ overflow-wrap: anywhere;
18100
18112
  }
18101
- if (shell.what === "launcher_too_old") {
18102
- steps.push({
18103
- report: `\u041D\u043E\u0432\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F ${shell.manifest.version} \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043D\u043E\u0432\u043E\u0433\u043E \u0444\u0430\u0439\u043B\u0430 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F.`,
18104
- trouble: `\u0414\u043B\u044F \u043D\u043E\u0432\u043E\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u043D\u0443\u0436\u0435\u043D \u043D\u043E\u0432\u044B\u0439 \u0444\u0430\u0439\u043B \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F. \u0412\u043E\u0437\u044C\u043C\u0438 \u0435\u0433\u043E \u0432 \u0442\u0435\u043B\u0435\u0433\u0440\u0430\u043C-\u0431\u043E\u0442\u0435 ${KEY_SOURCE_BOT}.`
18105
- });
18113
+ .path[hidden] { display: none; }
18114
+ /* pre-line, \u043F\u043E\u0442\u043E\u043C\u0443 \u0447\u0442\u043E \u0436\u0430\u043B\u043E\u0431 \u0431\u044B\u0432\u0430\u0435\u0442 \u043D\u0435\u0441\u043A\u043E\u043B\u044C\u043A\u043E, \u0438 \u043A\u0430\u0436\u0434\u0430\u044F \u0441\u0432\u043E\u044F \u0441\u0442\u0440\u043E\u043A\u0430: \u0441\u043B\u0438\u0442\u044B\u0435
18115
+ \u0432 \u0430\u0431\u0437\u0430\u0446, \u043E\u043D\u0438 \u0447\u0438\u0442\u0430\u044E\u0442\u0441\u044F \u043A\u0430\u043A \u043E\u0434\u043D\u0430 \u0434\u043B\u0438\u043D\u043D\u0430\u044F \u0438 \u043F\u043E\u043B\u043E\u0432\u0438\u043D\u0430 \u0442\u0435\u0440\u044F\u0435\u0442\u0441\u044F. */
18116
+ .warn { display: block; margin-top: 6px; white-space: pre-line; color: var(--ink-soft); font-size: 12.5px; line-height: 1.45; }
18117
+ .warn[hidden] { display: none; }
18118
+
18119
+ /* \u0421\u0442\u0440\u043E\u043A\u0430 \u0437\u0430\u043C\u0438\u043D\u043E\u043A: \xAB\u0441\u043F\u0440\u0430\u0448\u0438\u0432\u0430\u044E \u0435\u0449\u0451 \u0440\u0430\u0437\xBB, \xAB\u0445\u043E\u0441\u0442 \u043D\u0435 \u043E\u0442\u0432\u0435\u0442\u0438\u043B\xBB. \u041E\u0431\u044B\u0447\u043D\u044B\u043C\u0438
18120
+ \u0447\u0435\u0440\u043D\u0438\u043B\u0430\u043C\u0438 \u2014 \u043F\u043E\u043A\u0440\u0430\u0441\u0438\u0442\u044C \u0437\u0430\u043C\u0438\u043D\u043A\u0443 \u0432 \u0444\u0438\u0440\u043C\u0435\u043D\u043D\u044B\u0439 \u0446\u0432\u0435\u0442 \u0437\u043D\u0430\u0447\u0438\u043B\u043E \u0431\u044B \u0441\u043E\u0432\u0440\u0430\u0442\u044C. */
18121
+ .note {
18122
+ margin-top: 12px;
18123
+ padding: 9px 13px;
18124
+ border-radius: 12px;
18125
+ background: var(--bad-bg);
18126
+ color: var(--ink);
18127
+ font-size: 13px;
18128
+ line-height: 1.4;
18106
18129
  }
18107
- if (fresh.what === "shell_too_old") {
18108
- steps.push({
18109
- report: `\u041D\u043E\u0432\u0430\u044F \u043D\u0430\u0447\u0438\u043D\u043A\u0430 ${fresh.manifest.version} \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F \u043D\u0435 \u0441\u0442\u0430\u0440\u0448\u0435 ${fresh.manifest.minShellVersion}.`,
18110
- trouble: "\u041D\u043E\u0432\u043E\u043C\u0443 \u0434\u0432\u0438\u0436\u043A\u0443 \u043D\u0443\u0436\u043D\u043E \u043D\u043E\u0432\u043E\u0435 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u0435 \u2014 \u0435\u0433\u043E \u043F\u043E\u043A\u0430 \u043D\u0435\u0442 \u043D\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435."
18111
- });
18130
+ .note[hidden] { display: none; }
18131
+
18132
+ @keyframes drop { from { opacity: 0; transform: translateY(-14px); } to { opacity: 1; transform: none; } }
18133
+ @keyframes pop { from { opacity: 0; transform: scale(.5); } to { opacity: 1; transform: none; } }
18134
+ @keyframes pulse { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: .4; transform: scale(.75); } }
18135
+ @keyframes breathe { 0%, 100% { opacity: 1; } 50% { opacity: .45; } }
18136
+
18137
+ /* \u26A0 \u0414\u0412\u0418\u0416\u0415\u041D\u0418\u0415 \u041E\u0422\u041A\u041B\u042E\u0427\u0410\u0415\u0422\u0421\u042F \u0426\u0415\u041B\u0418\u041A\u041E\u041C, \u0410 \u041D\u0415 \u0423\u041A\u041E\u0420\u0410\u0427\u0418\u0412\u0410\u0415\u0422\u0421\u042F. \u041F\u043E\u043F\u0440\u043E\u0441\u0438\u0432\u0448\u0438\u0439 \u0441\u0438\u0441\u0442\u0435\u043C\u0443
18138
+ \u043D\u0435 \u0434\u0432\u0438\u0433\u0430\u0442\u044C \u043A\u0430\u0440\u0442\u0438\u043D\u043A\u0443 \u043F\u0440\u043E\u0441\u0438\u043B \u043F\u0440\u043E \u0432\u0441\u0451 \u0441\u0440\u0430\u0437\u0443 \u2014 \u0438 \u043F\u0440\u043E \u043E\u0433\u043E\u043D\u0451\u043A, \u043A\u043E\u0442\u043E\u0440\u044B\u0439 \u0434\u044B\u0448\u0438\u0442
18139
+ \u0437\u0434\u0435\u0441\u044C \u043C\u0438\u043D\u0443\u0442\u0430\u043C\u0438, \u0442\u0435\u043C \u0431\u043E\u043B\u0435\u0435. */
18140
+ @media (prefers-reduced-motion: reduce) {
18141
+ .now::before, .rail li.at, .end, .end__m { animation: none; }
18112
18142
  }
18113
- if (shell.what === "newer_available" && shellStage !== null) {
18114
- job.go(shellStage);
18115
- const outcome = await installShell({ home, manifest: shell.manifest, key: key ?? null });
18116
- if (outcome.ok) {
18117
- updated = true;
18118
- steps.push({ report: outcome.text });
18119
- } else {
18120
- steps.push({ report: outcome.text, trouble: "\u041D\u043E\u0432\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F \u043D\u0435 \u0432\u0441\u0442\u0430\u043B\u0430 \u2014 \u0440\u0430\u0431\u043E\u0442\u0430\u0435\u0442 \u043F\u0440\u0435\u0436\u043D\u044F\u044F." });
18121
- }
18143
+
18144
+ /* \u2500\u2500\u2500 \u0428\u0438\u0440\u043E\u043A\u0438\u0439 \u044D\u043A\u0440\u0430\u043D \u0442\u043E\u043B\u044C\u043A\u043E \u0434\u043E\u043F\u0438\u0441\u044B\u0432\u0430\u0435\u0442 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
18145
+
18146
+ @media (min-width: 560px) {
18147
+ body { padding: 22px 20px 24px; }
18148
+ h2 { font-size: 21px; }
18149
+ .rail { gap: 5px; }
18150
+ .parts { grid-template-columns: 1fr 1fr; }
18122
18151
  }
18123
- if (fresh.what === "newer_available" && engineStage !== null) {
18124
- job.go(engineStage);
18125
- const outcome = await deploy(engine, fresh.manifest, void 0, key, {
18126
- line: (text2) => job.line(text2),
18127
- downloaded: () => {
18128
- job.go(INSTALL_NEW);
18129
- job.line("\u0421\u043E\u0431\u0438\u0440\u0430\u044E \u043E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u0435 \u043D\u043E\u0432\u043E\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u2014 \u044D\u0442\u043E \u0434\u043E \u043F\u0430\u0440\u044B \u043C\u0438\u043D\u0443\u0442.");
18130
- }
18131
- });
18132
- if (outcome.ok) {
18133
- updated = true;
18134
- steps.push({ report: outcome.text });
18135
- } else {
18136
- const cause = causeOf(outcome.text);
18137
- steps.push({
18138
- report: outcome.text,
18139
- trouble: `\u041D\u043E\u0432\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u0434\u0432\u0438\u0436\u043A\u0430 \u043D\u0435 \u0432\u0441\u0442\u0430\u043B\u0430${cause === "" ? "" : `: ${cause}`}. \u0420\u0430\u0431\u043E\u0442\u0430\u0435\u0442 \u043F\u0440\u0435\u0436\u043D\u044F\u044F${engineWas === null ? "" : ` ${engineWas}`}, \u043C\u043E\u043D\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u043C\u043E\u0436\u043D\u043E.`
18140
- });
18141
- }
18152
+ @media (min-width: 760px) {
18153
+ body { padding: 26px 24px 28px; }
18154
+ h2 { font-size: 22px; }
18142
18155
  }
18143
- if (missing) {
18144
- job.go(MISSING);
18145
- const step = await deliverMissing(job, deps);
18146
- if (step.trouble === void 0 && step.installed) installed = true;
18147
- steps.push(step);
18156
+ </style>
18157
+ </head>
18158
+ <body>
18159
+ <div class="head">
18160
+ <h2 id="what" hidden></h2>
18161
+ <span class="clock" id="clock" hidden></span>
18162
+ </div>
18163
+ <ol class="rail" id="rail" hidden></ol>
18164
+ <div class="now" id="now">
18165
+ <span>
18166
+ <strong class="now__t" id="nowTitle">\u041D\u0430\u0447\u0438\u043D\u0430\u044E</strong>
18167
+ <span class="now__c" id="nowLeft" hidden></span>
18168
+ </span>
18169
+ </div>
18170
+ <div class="dl" id="dl" hidden>
18171
+ <div class="meter" id="dlMeter"><span class="meter__fill" id="dlFill"></span></div>
18172
+ <p class="meter__cap" id="dlCap"></p>
18173
+ </div>
18174
+ <div class="msg" id="msg" hidden></div>
18175
+ <section class="card" id="card" hidden>
18176
+ <p class="card__meta" id="cardMeta" hidden></p>
18177
+ <div class="meter" id="cardMeter" hidden><span class="meter__fill" id="cardFill"></span></div>
18178
+ <p class="meter__cap" id="cardCap" hidden></p>
18179
+ <ul class="parts" id="cardRows" hidden></ul>
18180
+ <div class="msg" id="cardUpdate" hidden></div>
18181
+ <div class="note" id="cardTrouble" hidden></div>
18182
+ <p class="next" id="cardNext" hidden></p>
18183
+ </section>
18184
+ <div class="end" id="end" hidden>
18185
+ <span class="end__m" aria-hidden="true"></span>
18186
+ <span class="end__x">
18187
+ <strong class="end__t" id="endTitle"></strong>
18188
+ <span class="end__h" id="endHint"></span>
18189
+ <span class="path" id="path" hidden></span>
18190
+ <span class="warn" id="warn" hidden></span>
18191
+ </span>
18192
+ </div>
18193
+ <div class="note" id="note" hidden></div>
18194
+ <script>
18195
+ (function () {
18196
+ // \u26A0 \u041A\u0410\u041A \u0427\u0410\u0421\u0422\u041E \u0421\u041F\u0420\u0410\u0428\u0418\u0412\u0410\u0422\u042C. \u041A\u0430\u0436\u0434\u044B\u0439 \u043E\u043F\u0440\u043E\u0441 \u2014 \u0437\u0430\u043F\u0443\u0441\u043A \u043F\u0438\u0442\u043E\u043D\u0430 \u043D\u0430 \u043C\u0430\u0448\u0438\u043D\u0435 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430,
18197
+ // \u0438 \u0447\u0430\u0449\u0435 \u0434\u0432\u0443\u0445 \u0441\u0435\u043A\u0443\u043D\u0434 \u044D\u0442\u043E \u043E\u0442\u043D\u0438\u043C\u0430\u043B\u043E \u0431\u044B \u044F\u0434\u0440\u043E \u0443 \u0441\u0430\u043C\u043E\u0433\u043E \u043C\u043E\u043D\u0442\u0430\u0436\u0430. \u0420\u0435\u0436\u0435 \u043F\u044F\u0442\u0438 \u2014
18198
+ // \u0438 \u043F\u043E\u043B\u043E\u0441\u0430 \u043E\u0442\u0441\u0442\u0430\u0451\u0442 \u043E\u0442 \u0440\u0430\u0431\u043E\u0442\u044B \u043D\u0430\u0441\u0442\u043E\u043B\u044C\u043A\u043E, \u0447\u0442\u043E \u0447\u0435\u043B\u043E\u0432\u0435\u043A \u0441\u043D\u043E\u0432\u0430 \u0441\u043C\u043E\u0442\u0440\u0438\u0442 \u0432 \u0442\u0438\u0448\u0438\u043D\u0443.
18199
+ var POLL_MS = 2500;
18200
+ // \u0421\u043A\u043E\u043B\u044C\u043A\u043E \u043F\u043E\u0434\u0440\u044F\u0434 \u043D\u0435\u0443\u0434\u0430\u0447 \u0442\u0435\u0440\u043F\u0438\u043C, \u043F\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043C \u0441\u043A\u0430\u0437\u0430\u0442\u044C \u0441\u043B\u043E\u0432\u0430\u043C\u0438. \u041E\u0434\u043D\u0430 \u043D\u0435\u0443\u0434\u0430\u0447\u0430 \u2014
18201
+ // \u044D\u0442\u043E \u043D\u043E\u0440\u043C\u0430: \u043E\u043F\u0440\u043E\u0441 \u0437\u0430\u043F\u0443\u0441\u043A\u0430\u0435\u0442 \u043F\u043E\u0434\u043F\u0440\u043E\u0446\u0435\u0441\u0441, \u0438 \u043E\u043D \u043C\u043E\u0436\u0435\u0442 \u043D\u0435 \u0443\u0434\u0430\u0442\u044C\u0441\u044F \u043F\u043E \u0441\u043B\u0443\u0447\u0430\u0439\u043D\u043E\u0439
18202
+ // \u043F\u0440\u0438\u0447\u0438\u043D\u0435 (\u0430\u043D\u0442\u0438\u0432\u0438\u0440\u0443\u0441, \u043D\u0435\u0445\u0432\u0430\u0442\u043A\u0430 \u043F\u0430\u043C\u044F\u0442\u0438, \u0433\u043E\u043D\u043A\u0430 \u0437\u0430 \u0444\u0430\u0439\u043B\u043E\u043C \u0437\u0430\u0434\u0430\u043D\u0438\u044F).
18203
+ var GIVE_UP_AFTER = 5;
18204
+ var CONTRACT = '${JOB_CONTRACT}';
18205
+ var SETUP = '${SETUP_CONTRACT}';
18206
+
18207
+ var nextId = 1;
18208
+ // Object.create(null), \u0430 \u043D\u0435 {}: \u0438\u043D\u0430\u0447\u0435 id \u0432\u0438\u0434\u0430 \xABtoString\xBB \u0434\u043E\u0441\u0442\u0430\u0451\u0442 \u0444\u0443\u043D\u043A\u0446\u0438\u044E \u0441
18209
+ // \u043F\u0440\u043E\u0442\u043E\u0442\u0438\u043F\u0430, \u0438 \u043E\u0442\u0432\u0435\u0442 \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044F \u043E\u0436\u0438\u0434\u0430\u0435\u043C\u044B\u043C \u043D\u0430 \u043F\u0443\u0441\u0442\u043E\u043C \u043C\u0435\u0441\u0442\u0435.
18210
+ var waiting = Object.create(null);
18211
+ function send(method, params, onReply) {
18212
+ var id = nextId++;
18213
+ if (onReply) waiting[id] = onReply;
18214
+ window.parent.postMessage({ jsonrpc: '2.0', id: id, method: method, params: params }, '*');
18215
+ return id;
18148
18216
  }
18149
- const report = steps.map((step) => step.report).join("\n");
18150
- const trouble = steps.find((step) => step.trouble !== void 0)?.trouble;
18151
- if (trouble !== void 0) return { ok: false, trouble, advice: ADVICE_ASK, report };
18152
- if (updated) return { ok: true, say: SAY_RESTART, report };
18153
- return { ok: true, say: installed ? SAY_INSTALLED : SAY_NOTHING, report };
18154
- }
18155
- function causeOf(text2) {
18156
- const line = text2.split("\n").map((one) => one.trim()).find((one) => one !== "" && !/^(Новая версия|Версия) \S+ не встала/.test(one) && !/^Что делать:/.test(one)) ?? "";
18157
- const phrase = (line.split(/\.\s|\s—\s|;\s/)[0] ?? "").replace(/\s*\([^)]*\)/g, "").replace(/\.$/, "").trim();
18158
- return phrase === "" ? "" : phrase[0].toLowerCase() + phrase.slice(1);
18159
- }
18160
- async function deliverMissing(job, deps) {
18161
- const answer = await deps.installMissing();
18162
- if (answer.type === "error") {
18163
- return { report: answer.error, trouble: "\u041D\u0435 \u043F\u043E\u043B\u0443\u0447\u0438\u043B\u043E\u0441\u044C \u043F\u043E\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u043D\u0435\u0434\u043E\u0441\u0442\u0430\u044E\u0449\u0435\u0435.", installed: false };
18217
+ function notify(method, params) {
18218
+ window.parent.postMessage({ jsonrpc: '2.0', method: method, params: params }, '*');
18164
18219
  }
18165
- const words = typeof answer.content === "string" ? answer.content : answer.content.map((block) => block.type === "text" ? block.text : "").join("\n");
18166
- const id = typeof answer.structured?.["id"] === "string" ? answer.structured["id"] : "";
18167
- if (id === "") return { report: words, installed: false };
18168
- const pace = deps.pace ?? realPace;
18169
- let state = await deps.engine.command(["job", id]);
18170
- while (state.ok && stillWorking(state.text)) {
18171
- const now = readJob(state.text);
18172
- if (now !== null) job.line(now.message !== "" ? now.message : now.now);
18173
- await pace.rest(POLL_EVERY_MS);
18174
- state = await deps.engine.command(["job", id]);
18220
+ function byId(id) { return document.getElementById(id); }
18221
+ function reportSize() {
18222
+ notify('ui/notifications/size-changed', { height: document.documentElement.scrollHeight });
18175
18223
  }
18176
- const end = state.ok ? readJob(state.text) : null;
18177
- if (end === null || end.status !== "done") {
18178
- return {
18179
- report: `${words}
18180
- ${state.text}`,
18181
- trouble: end?.trouble !== void 0 && end.trouble !== "" ? end.trouble : "\u041D\u0435 \u043F\u043E\u043B\u0443\u0447\u0438\u043B\u043E\u0441\u044C \u043F\u043E\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u043D\u0435\u0434\u043E\u0441\u0442\u0430\u044E\u0449\u0435\u0435.",
18182
- installed: false
18183
- };
18224
+ function show(id, text) {
18225
+ var el = byId(id);
18226
+ if (!el) return;
18227
+ el.textContent = text || '';
18228
+ el.hidden = !text;
18184
18229
  }
18185
- return { report: `${words}
18186
- ${state.text}`, installed: true };
18187
- }
18188
18230
 
18189
- // src/setup-tool.ts
18190
- var ASKED_POINTER_MS = 15e3;
18191
- var NEWS_POINTER_MS = 5e3;
18192
- 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.";
18193
- async function inspectMachine(engine, asked) {
18194
- const video = asked.video;
18195
- const model = asked.model;
18196
- const place = engine.place();
18197
- if (place === null) return { result: toolError(engine.whyNoEngine()), readiness: null };
18198
- const args = [
18199
- "env-check",
18200
- "--pack",
18201
- place.pack,
18202
- ...video !== void 0 ? ["--video", path(video)] : [],
18203
- ...model !== void 0 ? ["--model", model] : []
18204
- ];
18205
- let readiness = null;
18206
- let words;
18207
- if (knowsJsonCheck(place.engine)) {
18208
- const answer = await askReadiness(engine, place, args);
18209
- if ("ok" in answer && !answer.ok) return { result: toolError(answer.text), readiness: null };
18210
- if ("parts" in answer) readiness = answer;
18211
- words = "parts" in answer ? answer.words : answer.text;
18212
- } else {
18213
- const outcome = await engine.command(args);
18214
- if (!outcome.ok) return { result: toolError(outcome.text), readiness: null };
18215
- words = outcome.text;
18231
+ // \u2500\u2500\u2500 \u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u0435 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
18232
+ var job = null;
18233
+ // \u26A0 \u0422\u0420\u0418 \u0420\u0410\u0417\u041D\u042B\u0425 \xAB\u0421\u0422\u041E\u041F\xBB, \u0418 \u041F\u0423\u0422\u0410\u0422\u042C \u0418\u0425 \u041D\u0415\u041B\u042C\u0417\u042F. closed \u2014 \u0432\u0438\u0434\u0436\u0435\u0442 \u0437\u0430\u043A\u0440\u044B\u043B\u0438, \u0431\u043E\u043B\u044C\u0448\u0435
18234
+ // \u043D\u0435 \u0440\u0438\u0441\u0443\u0435\u043C \u0432\u043E\u0432\u0441\u0435. done \u2014 \u0440\u0430\u0431\u043E\u0442\u0430 \u043A\u043E\u043D\u0447\u0438\u043B\u0430\u0441\u044C, \u0441\u043F\u0440\u0430\u0448\u0438\u0432\u0430\u0442\u044C \u043D\u0435 \u043E \u0447\u0435\u043C. fails \u2014
18235
+ // \u0441\u0447\u0451\u0442\u0447\u0438\u043A \u043F\u043E\u0434\u0440\u044F\u0434 \u0438\u0434\u0443\u0449\u0438\u0445 \u043D\u0435\u0443\u0434\u0430\u0447 \u043E\u043F\u0440\u043E\u0441\u0430.
18236
+ var closed = false;
18237
+ var fails = 0;
18238
+ function working(s) { return s === 'running' || s === 'waiting'; }
18239
+
18240
+ function later() {
18241
+ if (closed) return;
18242
+ if (!job || !job.id || !working(job.status)) return;
18243
+ setTimeout(poll, POLL_MS);
18216
18244
  }
18217
- const catalog = await askCatalog(engine, place.pack, video);
18218
- return { result: toolSuccess(`${words}
18219
18245
 
18220
- ${catalog}`), readiness };
18221
- }
18222
- async function askReadiness(engine, place, args) {
18223
- const python = await engine.pythonTrouble();
18224
- if (python !== null) return { ok: false, text: python };
18225
- let stdout;
18226
- try {
18227
- stdout = (await engine.run(place, [...args, JSON_CHECK])).stdout;
18228
- } catch (err) {
18229
- const e = err;
18230
- if (e.code !== 2 || typeof e.stdout !== "string") return parseFailure(err, "\u041F\u0440\u043E\u0432\u0435\u0440\u043A\u0430 \u043C\u0430\u0448\u0438\u043D\u044B \u043D\u0435 \u0432\u044B\u043F\u043E\u043B\u043D\u0438\u043B\u0430\u0441\u044C");
18231
- stdout = e.stdout;
18246
+ // \u26A0 \u041F\u041E\u041B\u041E\u0421\u0410 \u0421\u041F\u0420\u0410\u0428\u0418\u0412\u0410\u0415\u0422 \u0421\u0410\u041C\u0410, \u0418 \u042D\u0422\u041E \u0413\u041B\u0410\u0412\u041D\u041E\u0415 \u0412 \u041D\u0415\u0419. \u0418\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442 \u043E\u0442\u0432\u0435\u0442\u0438\u043B \u043D\u043E\u043C\u0435\u0440\u043E\u043C
18247
+ // \u0437\u0430\u0434\u0430\u0447\u0438 \u0438 \u0443\u043C\u043E\u043B\u043A \u2014 \u0434\u0435\u0440\u0436\u0430\u0442\u044C \u0432\u044B\u0437\u043E\u0432 \u043E\u0442\u043A\u0440\u044B\u0442\u044B\u043C \u043C\u0438\u043D\u0443\u0442\u0430\u043C\u0438 MCP \u043D\u0435 \u0434\u0430\u0451\u0442. \u041C\u043E\u0434\u0435\u043B\u044C \u043F\u0440\u0438
18248
+ // \u044D\u0442\u043E\u043C \u043D\u0435 \u0442\u0440\u0430\u0442\u0438\u0442 \u0445\u043E\u0434: \u043E\u0442\u0432\u0435\u0442 \u043D\u0430 tools/call \u0443\u0445\u043E\u0434\u0438\u0442 \u0412\u0418\u0414\u0416\u0415\u0422\u0423, \u0430 \u043D\u0435 \u0432 \u0440\u0430\u0437\u0433\u043E\u0432\u043E\u0440.
18249
+ function poll() {
18250
+ if (closed || !job || !job.id) return;
18251
+ // \u26A0 seconds: 0 \u2014 \xAB\u041E\u0422\u0412\u0415\u0422\u042C \u041A\u0410\u041A \u0415\u0421\u0422\u042C\xBB, \u0418 \u0411\u0415\u0417 \u041D\u0415\u0413\u041E \u041F\u041E\u041B\u041E\u0421\u0410 \u0412\u0421\u0422\u0410\u0401\u0422. \u0423 wait \u0431\u0435\u0437
18252
+ // \u044D\u0442\u043E\u0433\u043E \u043A\u043B\u044E\u0447\u0430 \u043E\u0436\u0438\u0434\u0430\u043D\u0438\u0435 \u0434\u043B\u0438\u0442\u0441\u044F \u0434\u043E 55 \u0441\u0435\u043A\u0443\u043D\u0434: \u0442\u0430\u043A \u043E\u043D \u0438 \u0434\u043E\u043B\u0436\u0435\u043D \u0440\u0430\u0431\u043E\u0442\u0430\u0442\u044C,
18253
+ // \u043A\u043E\u0433\u0434\u0430 \u0435\u0433\u043E \u0437\u043E\u0432\u0451\u0442 \u043C\u043E\u0434\u0435\u043B\u044C \u2014 \xAB\u0441\u043F\u0440\u043E\u0441\u0438 \u0435\u0449\u0451 \u0440\u0430\u0437\xBB \u0441\u0442\u043E\u0438\u0442 \u0435\u0439 \u0446\u0435\u043B\u043E\u0433\u043E \u0445\u043E\u0434\u0430. \u0410
18254
+ // \u043F\u043E\u043B\u043E\u0441\u0430 \u0441\u043F\u0440\u0430\u0448\u0438\u0432\u0430\u0435\u0442 \u0421\u0410\u041C\u0410 \u043A\u0430\u0436\u0434\u044B\u0435 2,5 \u0441\u0435\u043A\u0443\u043D\u0434\u044B, \u0438 \u0431\u043B\u043E\u043A\u0438\u0440\u0443\u044E\u0449\u0438\u0439 \u0432\u044B\u0437\u043E\u0432 \u043E\u0437\u043D\u0430\u0447\u0430\u043B
18255
+ // \u0431\u044B \u043E\u0434\u043D\u0443 \u043F\u0435\u0440\u0435\u0440\u0438\u0441\u043E\u0432\u043A\u0443 \u0432 \u043C\u0438\u043D\u0443\u0442\u0443 \u0432\u043C\u0435\u0441\u0442\u043E \u0434\u0432\u0430\u0434\u0446\u0430\u0442\u0438 \u0447\u0435\u0442\u044B\u0440\u0451\u0445.
18256
+ send('tools/call', { name: 'wait', arguments: { job: job.id, seconds: 0 } }, function (m) {
18257
+ if (closed) return;
18258
+ if (m.error) return stumble('\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0441\u043F\u0440\u043E\u0441\u0438\u0442\u044C \u043E \u0440\u0430\u0431\u043E\u0442\u0435: ' + ((m.error && m.error.message) || '\u0445\u043E\u0441\u0442 \u043F\u0440\u043E\u043C\u043E\u043B\u0447\u0430\u043B'));
18259
+ var answer = m.result || {};
18260
+ // \u041E\u0442\u043A\u0430\u0437 \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u0430 \u2014 \u044D\u0442\u043E \u043E\u0442\u0432\u0435\u0442, \u0430 \u043D\u0435 \u0441\u0431\u043E\u0439: \u0434\u0432\u0438\u0436\u043E\u043A \u043E\u0431\u044A\u044F\u0441\u043D\u044F\u0435\u0442 \u0441\u043B\u043E\u0432\u0430\u043C\u0438,
18261
+ // \u0438 \u0447\u0435\u043B\u043E\u0432\u0435\u043A \u043E\u0431\u044F\u0437\u0430\u043D \u0438\u0445 \u043F\u0440\u043E\u0447\u0438\u0442\u0430\u0442\u044C, \u0430 \u043D\u0435 \u0441\u043C\u043E\u0442\u0440\u0435\u0442\u044C \u0432 \u043F\u0443\u0441\u0442\u0443\u044E \u043F\u043E\u043B\u043E\u0441\u0443.
18262
+ if (answer.isError) return finishWithWords(words(answer));
18263
+ var data = answer.structuredContent;
18264
+ if (!data || data.contract !== CONTRACT) return stumble('\u041E\u0442\u0432\u0435\u0442 \u043E \u0440\u0430\u0431\u043E\u0442\u0435 \u043F\u0440\u0438\u0448\u0451\u043B \u043D\u0435 \u0442\u043E\u0442. \u0421\u043F\u0440\u043E\u0441\u0438\u0442\u0435 \u041A\u043B\u043E\u0434\u0430, \u0447\u0442\u043E \u0441 \u0437\u0430\u0434\u0430\u0447\u0435\u0439.');
18265
+ fails = 0;
18266
+ byId('note').hidden = true;
18267
+ render(data);
18268
+ later();
18269
+ });
18270
+ // \u0425\u043E\u0441\u0442 \u043C\u043E\u0436\u0435\u0442 \u043D\u0435 \u043E\u0442\u0432\u0435\u0442\u0438\u0442\u044C \u0432\u043E\u0432\u0441\u0435. \u0416\u0434\u0451\u043C \u0432\u0434\u0432\u043E\u0435 \u0434\u043E\u043B\u044C\u0448\u0435 \u043E\u043F\u0440\u043E\u0441\u0430 \u0438 \u043F\u0440\u043E\u0431\u0443\u0435\u043C \u0441\u043D\u043E\u0432\u0430:
18271
+ // \u043C\u043E\u043B\u0447\u0430\u043D\u0438\u0435 \u043E\u0434\u043D\u043E\u0433\u043E \u043A\u0440\u0443\u0433\u0430 \u2014 \u043D\u0435 \u043F\u043E\u0432\u043E\u0434 \u0431\u0440\u043E\u0441\u0430\u0442\u044C \u0440\u0430\u0431\u043E\u0442\u0443, \u043A\u043E\u0442\u043E\u0440\u0430\u044F \u0438\u0434\u0451\u0442.
18272
+ var mine = nextId - 1;
18273
+ setTimeout(function () {
18274
+ if (closed || !waiting[mine]) return;
18275
+ delete waiting[mine];
18276
+ stumble('\u041E\u0442\u0432\u0435\u0442\u0430 \u043E \u0440\u0430\u0431\u043E\u0442\u0435 \u043D\u0435\u0442. \u0421\u043F\u0440\u0430\u0448\u0438\u0432\u0430\u044E \u0435\u0449\u0451 \u0440\u0430\u0437.');
18277
+ }, POLL_MS * 2);
18232
18278
  }
18233
- return readReadiness(stdout) ?? { ok: true, text: stdout.trim() };
18234
- }
18235
- async function installStep(engine, asked, key, baseUrl, tell) {
18236
- const step = asked.step;
18237
- const model = asked.model;
18238
- const consent = asked.consent;
18239
- if (engine.place() === null) {
18240
- let candidate = readCandidate(engine.versionsDir());
18241
- if (candidate === null) {
18242
- if (tell !== void 0) for (const line of PAYLOAD_LADDER) tell(line);
18243
- const result = await installPayload(engine, {
18244
- consent,
18245
- manifestUrl: manifestUrl(engine, baseUrl),
18246
- ...key !== void 0 ? { key } : {}
18247
- });
18248
- if (!result.ok) return toolError(result.text);
18249
- candidate = readCandidate(engine.versionsDir());
18250
- if (candidate === null) {
18251
- return toolError("\u041D\u0430\u0447\u0438\u043D\u043A\u0430 \u0441\u043A\u0430\u0447\u0430\u043B\u0430\u0441\u044C \u0431\u0435\u0437 \u0443\u043A\u0430\u0437\u0430\u0442\u0435\u043B\u044F \u043A\u0430\u043D\u0434\u0438\u0434\u0430\u0442\u0430 \u2014 current \u043D\u0435 \u043C\u0435\u043D\u044F\u043B. \u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C: \u043F\u043E\u0432\u0442\u043E\u0440\u0438\u0442\u0435 setup.");
18252
- }
18253
- }
18254
- if (!consent) {
18255
- return toolError(
18256
- `\u041A\u0430\u043D\u0434\u0438\u0434\u0430\u0442 ${candidate.version} \u0443\u0436\u0435 \u043F\u043E\u0434\u0433\u043E\u0442\u043E\u0432\u043B\u0435\u043D, \u043D\u043E \u0435\u0449\u0451 \u043D\u0435 \u0440\u0430\u0431\u043E\u0447\u0438\u0439. \u0421\u043F\u0440\u043E\u0441\u0438 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043D\u0438\u0435 \u0441\u043E\u0431\u0440\u0430\u0442\u044C \u0435\u0433\u043E \u043E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u0435 \u0438 \u043F\u043E\u0437\u043E\u0432\u0438 setup \u0441 consent=true.`
18257
- );
18258
- }
18259
- const extras = step === "all" ? "later" : "now";
18260
- const activated = await continuePreparedCandidate(engine, candidate, void 0, extras);
18261
- if (!activated.ok) return toolError(activated.text);
18262
- engine.forgetPlace();
18263
- engine.forgetPython();
18264
- if (step === "python") return toolSuccess(activated.text);
18265
- if (step === "all") {
18266
- const ready = `${activated.text}
18267
- \u041A\u0430\u043D\u0434\u0438\u0434\u0430\u0442 \u043F\u043E\u0441\u0442\u0430\u0432\u0438\u043B \u0431\u0438\u0431\u043B\u0438\u043E\u0442\u0435\u043A\u0438 \u043F\u043E \u0441\u0432\u043E\u0435\u043C\u0443 \u0437\u0430\u043C\u043A\u0443 \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.`;
18268
- const later = await installStep(engine, asked, key, baseUrl, tell);
18269
- if (later.type === "error") {
18270
- return toolSuccess(
18271
- `${ready}
18272
18279
 
18273
- \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}
18274
- \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.`
18275
- );
18276
- }
18277
- return together([toolSuccess(`${ready}
18278
- ${EXTRAS_LATER}`), later]);
18280
+ /** \u0417\u0430\u043C\u0438\u043D\u043A\u0430: \u0433\u043E\u0432\u043E\u0440\u0438\u043C \u0441\u043B\u043E\u0432\u0430\u043C\u0438 \u0438 \u043F\u0440\u043E\u0431\u0443\u0435\u043C \u0441\u043D\u043E\u0432\u0430, \u043F\u043E\u043A\u0430 \u043D\u0435 \u043A\u043E\u043D\u0447\u0438\u0442\u0441\u044F \u0442\u0435\u0440\u043F\u0435\u043D\u0438\u0435. */
18281
+ function stumble(text) {
18282
+ fails++;
18283
+ if (fails >= GIVE_UP_AFTER) {
18284
+ show('note', '\u041D\u0435 \u043F\u043E\u043B\u0443\u0447\u0430\u0435\u0442\u0441\u044F \u0443\u0437\u043D\u0430\u0442\u044C, \u0447\u0442\u043E \u0441 \u0440\u0430\u0431\u043E\u0442\u043E\u0439. \u041E\u043D\u0430 \u0438\u0434\u0451\u0442 \u0441\u0430\u043C\u0430 \u0438 \u043D\u0438\u043A\u0443\u0434\u0430 \u043D\u0435 \u0434\u0435\u043D\u0435\u0442\u0441\u044F \u2014 \u0441\u043F\u0440\u043E\u0441\u0438\u0442\u0435 \u041A\u043B\u043E\u0434\u0430: \xAB\u0447\u0442\u043E \u0441 \u0437\u0430\u0434\u0430\u0447\u0435\u0439 ' + (job && job.id ? job.id : '') + '\xBB.');
18285
+ reportSize();
18286
+ return;
18279
18287
  }
18288
+ show('note', text);
18289
+ reportSize();
18290
+ later();
18280
18291
  }
18281
- const place = engine.place();
18282
- if (place === null) return toolError(engine.whyNoEngine());
18283
- if (consent && await engine.pythonTrouble() !== null) {
18284
- try {
18285
- await engine.bringPython(place);
18286
- } catch (trouble) {
18287
- return toolError(`\u041F\u0438\u0442\u043E\u043D \u043C\u043E\u043D\u0442\u0430\u0436\u0430 \u043F\u043E\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C: ${describeFailure(trouble)}. \u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C: \u043F\u043E\u0432\u0442\u043E\u0440\u0438 setup.`);
18292
+
18293
+ /** \u0422\u0435\u043A\u0441\u0442 \u043E\u0442\u0432\u0435\u0442\u0430 \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u0430 \u2014 \u0442\u043E, \u0447\u0442\u043E \u043F\u0440\u0435\u0434\u043D\u0430\u0437\u043D\u0430\u0447\u0435\u043D\u043E \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0443 \u0438 \u043C\u043E\u0434\u0435\u043B\u0438. */
18294
+ function words(answer) {
18295
+ var blocks = (answer && answer.content) || [];
18296
+ var text = '';
18297
+ for (var i = 0; i < blocks.length; i++) {
18298
+ if (blocks[i].type === 'text') text += (text ? ' ' : '') + blocks[i].text;
18288
18299
  }
18300
+ return text;
18289
18301
  }
18290
- const common = [
18291
- "--pack",
18292
- place.pack,
18293
- "--step",
18294
- step,
18295
- ...model !== void 0 ? ["--model", model] : [],
18296
- ...consent ? ["--consent"] : []
18297
- ];
18298
- if (!LONG_STEPS.has(step)) return asToolResult(await engine.command(["env-install", ...common]));
18299
- const python = await engine.pythonTrouble();
18300
- if (python !== null) return toolError(python);
18301
- if (tell !== void 0) for (const line of installLadder(step)) tell(line);
18302
- const launch = await engine.background({
18303
- place,
18304
- executable: engine.enginePython(),
18305
- // Установка берёт тот же слот тяжёлой работы, а на слоте стоит заслон
18306
- // подписки в самом движке — без ключа она откажет платящему.
18307
- key,
18308
- startJob: [
18309
- "install-create",
18310
- "--pack",
18311
- place.pack,
18312
- "--step",
18313
- step,
18314
- ...model !== void 0 ? ["--model", model] : []
18315
- ],
18316
- args: (id) => [place.consolePy, "env-install", ...common, "--job", id],
18317
- advice: "\u043F\u043E\u0437\u043E\u0432\u0438 setup \u2014 \u0441\u043A\u043E\u0440\u0435\u0435 \u0432\u0441\u0435\u0433\u043E, \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0430 \u043D\u0435\u043F\u043E\u043B\u043D\u0430\u044F"
18318
- });
18319
- if ("refusal" in launch) return toolError(launch.refusal);
18320
- return toolSuccess(
18321
- `\u0417\u0430\u0434\u0430\u0447\u0430 ${launch.id}: ${installTitle(step)} (\u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0430, \u0448\u0430\u0433 \xAB${step}\xBB).
18322
- \u0418\u0434\u0451\u0442 \u043D\u0430 \u043A\u043E\u043C\u043F\u044C\u044E\u0442\u0435\u0440\u0435 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F \u0438 \u043F\u0435\u0440\u0435\u0436\u0438\u0432\u0430\u0435\u0442 \u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u043A \u043F\u0440\u043E\u0433\u0440\u0430\u043C\u043C\u044B. \u041F\u043E\u0437\u043E\u0432\u0438 wait \u0441 job "${launch.id}" \u2014 \u043E\u043D \u043F\u043E\u0434\u043E\u0436\u0434\u0451\u0442 \u0438 \u043F\u043E \u0445\u043E\u0434\u0443 \u0440\u0430\u0441\u0441\u043A\u0430\u0436\u0435\u0442, \u0441\u043A\u043E\u043B\u044C\u043A\u043E \u0441\u043A\u0430\u0447\u0430\u043D\u043E \u0438 \u043E \u0447\u0451\u043C \u043D\u0430\u0434\u043E \u0441\u043F\u0440\u043E\u0441\u0438\u0442\u044C \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430. \u041F\u0435\u0440\u0435\u0441\u043A\u0430\u0437\u044B\u0432\u0430\u0439 \u044D\u0442\u043E \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0443 \u0441\u0440\u0430\u0437\u0443, \u0430 \u043D\u0435 \u0432 \u043A\u043E\u043D\u0446\u0435. ${AWAY_NOTE}`,
18323
- startedJob({
18324
- id: launch.id,
18325
- what: installTitle(step),
18326
- ahead: installLadder(step).join(" "),
18327
- message: "\u0418\u0434\u0451\u0442 \u043C\u0438\u043D\u0443\u0442\u0430\u043C\u0438: \u043A\u0430\u0447\u0430\u0435\u0442\u0441\u044F \u0438 \u0441\u043E\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044F \u0442\u043E, \u0447\u0435\u043C \u043C\u043E\u043D\u0442\u0438\u0440\u0443\u0435\u0442\u0441\u044F \u0432\u0438\u0434\u0435\u043E."
18328
- })
18329
- );
18330
- }
18331
- function tenths(bytes) {
18332
- return Math.round(bytes / 1024 / 1024 * 10) / 10;
18333
- }
18334
- async function updateEngine(engine, consent, key, baseUrl, timeoutMs = ASKED_POINTER_MS, seen = () => {
18335
- }) {
18336
- if (engine.pathSetByHand()) {
18337
- return toolSuccess(
18338
- "\u041F\u0430\u043F\u043A\u0430 \u0434\u0432\u0438\u0436\u043A\u0430 \u0437\u0430\u0434\u0430\u043D\u0430 \u0432\u0440\u0443\u0447\u043D\u0443\u044E \u043F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u043E\u0439 NAPARNIK_ENGINE \u2014 \u043E\u0431\u043D\u043E\u0432\u043B\u044F\u0442\u044C \u043D\u0435\u0447\u0435\u0433\u043E: \u0441\u0430\u043C\u043E\u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0435 \u0440\u0430\u0431\u043E\u0442\u0430\u0435\u0442 \u0441 \u0432\u0435\u0440\u0441\u0438\u043E\u043D\u043D\u043E\u0439 \u0440\u0430\u0441\u043A\u043B\u0430\u0434\u043A\u043E\u0439 \u0432 ~/.naparnik/engine, \u0430 \u044D\u0442\u0430 \u043F\u0430\u043F\u043A\u0430 \u043C\u0438\u043C\u043E \u043D\u0435\u0451. \u0421\u043A\u0430\u0436\u0438 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0443, \u0447\u0442\u043E \u0434\u0432\u0438\u0436\u043E\u043A \u0437\u0434\u0435\u0441\u044C \u043E\u0431\u043D\u043E\u0432\u043B\u044F\u0435\u0442\u0441\u044F \u0442\u0435\u043C \u0436\u0435 \u0441\u043F\u043E\u0441\u043E\u0431\u043E\u043C, \u043A\u0430\u043A\u0438\u043C \u0431\u044B\u043B \u043F\u043E\u043B\u043E\u0436\u0435\u043D."
18339
- );
18340
- }
18341
- if (engine.place() === null) {
18342
- return toolSuccess(
18343
- "\u0414\u0432\u0438\u0436\u043A\u0430 \u043C\u043E\u043D\u0442\u0430\u0436\u0430 \u043D\u0430 \u044D\u0442\u043E\u043C \u043A\u043E\u043C\u043F\u044C\u044E\u0442\u0435\u0440\u0435 \u0435\u0449\u0451 \u043D\u0435\u0442 \u2014 \u043E\u0431\u043D\u043E\u0432\u043B\u044F\u0442\u044C \u043D\u0435\u0447\u0435\u0433\u043E.\n\u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C: \u043F\u043E\u0437\u043E\u0432\u0438 setup \u0441 what=all, \u043E\u043D \u0441\u043A\u0430\u0447\u0430\u0435\u0442 \u043D\u0430\u0447\u0438\u043D\u043A\u0443 \u0441 \u043D\u0443\u043B\u044F (\u0441\u043A\u0430\u0447\u0438\u0432\u0430\u043D\u0438\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0441\u043E\u0433\u043B\u0430\u0441\u0438\u044F \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430)."
18344
- );
18345
- }
18346
- const outcome = await fetchManifest(manifestUrl(engine, baseUrl), timeoutMs, key);
18347
- const decision = decide(engine.freshVersion(), outcome.ok ? outcome.manifest : null);
18348
- seen({
18349
- installed: engine.freshVersion(),
18350
- fresh: decision.what === "nothing" ? null : decision.manifest.version,
18351
- mb: decision.what === "nothing" ? 0 : tenths(decision.manifest.bytes),
18352
- status: outcome.ok ? 0 : outcome.status ?? 0,
18353
- notes: ""
18354
- });
18355
- if (decision.what === "nothing") {
18356
- const ownDir2 = engine.freshVersion();
18357
- return toolSuccess(
18358
- !outcome.ok ? `\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0441\u043F\u0440\u043E\u0441\u0438\u0442\u044C, \u0435\u0441\u0442\u044C \u043B\u0438 \u043D\u043E\u0432\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u043D\u0430\u0447\u0438\u043D\u043A\u0438: ${outcome.why}. \u042D\u0442\u043E \u043D\u0435 \u043F\u043E\u043B\u043E\u043C\u043A\u0430: \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u043D\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F (${ownDir2 ?? "\u043D\u0435 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u0430"}) \u0440\u0430\u0431\u043E\u0442\u0430\u0435\u0442 \u043A\u0430\u043A \u0440\u0430\u0431\u043E\u0442\u0430\u043B\u0430.` : `\u041D\u0430\u0447\u0438\u043D\u043A\u0430 \u0441\u0432\u0435\u0436\u0430\u044F: \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u0430 ${ownDir2 ?? "\u043D\u0435\u0442"}, \u043D\u043E\u0432\u0435\u0435 \u043D\u0435 \u0432\u044B\u0448\u043B\u043E.`
18359
- );
18360
- }
18361
- if (decision.what === "shell_too_old") {
18362
- return toolSuccess(
18363
- `\u041D\u043E\u0432\u0430\u044F \u043D\u0430\u0447\u0438\u043D\u043A\u0430 ${decision.manifest.version} \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F \u043D\u0435 \u0441\u0442\u0430\u0440\u0448\u0435 ${decision.manifest.minShellVersion}, \u0430 \u0441\u0442\u043E\u0438\u0442 ${VERSION}. \u0421\u043A\u0430\u0436\u0438 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0443, \u0447\u0442\u043E \u0441\u043D\u0430\u0447\u0430\u043B\u0430 \u043D\u0430\u0434\u043E \u043E\u0431\u043D\u043E\u0432\u0438\u0442\u044C \u0441\u0430\u043C\u043E \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u0435 \u041D\u0430\u043F\u0430\u0440\u043D\u0438\u043A\u0430, \u0438 \u0442\u043E\u043B\u044C\u043A\u043E \u043F\u043E\u0442\u043E\u043C \u043D\u0430\u0447\u0438\u043D\u043A\u0443. \u0421\u0442\u0430\u0432\u0438\u0442\u044C \u043D\u0435 \u0441\u0442\u0430\u043B.`
18364
- );
18302
+
18303
+ // \u2500\u2500\u2500 \u0440\u0438\u0441\u043E\u0432\u0430\u043D\u0438\u0435 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
18304
+
18305
+ /** \xAB3 \u043C\u0438\u043D 20 \u0441\xBB, \xAB45 \u0441\xBB \u2014 \u0432\u0440\u0435\u043C\u044F \u0441\u043B\u043E\u0432\u0430\u043C\u0438, \u0430 \u043D\u0435 \u0433\u043E\u043B\u044B\u043C \u0447\u0438\u0441\u043B\u043E\u043C \u0441\u0435\u043A\u0443\u043D\u0434. */
18306
+ function howLong(sec) {
18307
+ var s = Math.max(0, Math.round(Number(sec) || 0));
18308
+ if (s < 60) return s + ' \u0441';
18309
+ var m = Math.floor(s / 60);
18310
+ var rest = s % 60;
18311
+ return m + ' \u043C\u0438\u043D' + (rest ? ' ' + rest + ' \u0441' : '');
18365
18312
  }
18366
- if (!consent) {
18367
- const mb = (decision.manifest.bytes / 1024 / 1024).toFixed(1);
18368
- return toolSuccess(
18369
- `\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.
18370
- ${VOICE_CLEANER_NOTE}
18371
- \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.`
18372
- );
18313
+
18314
+ // \u26A0 \u041B\u0415\u0421\u0422\u041D\u0418\u0426\u0410 \u0420\u0418\u0421\u0423\u0415\u0422\u0421\u042F \u041F\u041E \u041E\u0422\u0412\u0415\u0422\u0423 \u0414\u0412\u0418\u0416\u041A\u0410, \u0410 \u041D\u0415 \u041F\u0420\u0418\u0411\u0418\u0422\u0410 \u0417\u0414\u0415\u0421\u042C. \u042D\u0442\u0430\u043F\u043E\u0432 \u0431\u044B\u0432\u0430\u0435\u0442
18315
+ // \u0440\u0430\u0437\u043D\u043E\u0435 \u0447\u0438\u0441\u043B\u043E: \u0443 \u043C\u043E\u043D\u0442\u0430\u0436\u0430 \u0438\u0445 \u0434\u043E \u043E\u0434\u0438\u043D\u043D\u0430\u0434\u0446\u0430\u0442\u0438, \u0443 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0438 \u0442\u0440\u0438, \u0443 \xAB\u0442\u043E\u043B\u044C\u043A\u043E
18316
+ // \u043F\u0430\u0443\u0437\u044B\xBB \u043E\u0434\u0438\u043D. \u0421\u0432\u043E\u0439 \u0441\u043F\u0438\u0441\u043E\u043A \u0440\u0430\u0437\u043E\u0448\u0451\u043B\u0441\u044F \u0431\u044B \u0441 \u043D\u0430\u0441\u0442\u043E\u044F\u0449\u0438\u043C \u043D\u0430 \u043F\u0435\u0440\u0432\u043E\u043C \u043D\u043E\u0432\u043E\u043C \u0448\u0430\u0433\u0435.
18317
+ function rail(at, total, ended) {
18318
+ var root = byId('rail');
18319
+ if (!root) return;
18320
+ root.innerHTML = '';
18321
+ if (!total || total < 1) { root.hidden = true; return; }
18322
+ for (var i = 1; i <= total; i++) {
18323
+ var li = document.createElement('li');
18324
+ // \u041A\u043E\u043D\u0447\u0438\u0432\u0448\u0430\u044F\u0441\u044F \u0440\u0430\u0431\u043E\u0442\u0430 \u043D\u0435 \u0434\u0435\u0440\u0436\u0438\u0442 \xAB\u0438\u0434\u0443\u0449\u0435\u0433\u043E\xBB \u044D\u0442\u0430\u043F\u0430: \u0436\u0451\u043B\u0442\u0430\u044F \u043F\u043E\u043B\u043E\u0441\u043A\u0430 \u0440\u044F\u0434\u043E\u043C \u0441\u043E
18325
+ // \u0441\u043B\u043E\u0432\u043E\u043C \xAB\u0413\u043E\u0442\u043E\u0432\u043E\xBB \u0447\u0438\u0442\u0430\u043B\u0430\u0441\u044C \u0431\u044B \u043A\u0430\u043A \xAB\u0435\u0449\u0451 \u0447\u0442\u043E-\u0442\u043E \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044F\xBB.
18326
+ li.className = ended ? 'was' : (i < at ? 'was' : (i === at ? 'at' : ''));
18327
+ root.appendChild(li);
18328
+ }
18329
+ root.hidden = false;
18373
18330
  }
18374
- return asToolResult(await deploy(engine, decision.manifest, void 0, key));
18375
- }
18376
- async function updateShell(engine, consent, key, baseUrl, timeoutMs = ASKED_POINTER_MS, seen = () => {
18377
- }) {
18378
- const home = engine.home();
18379
- const url2 = engine.variable("NAPARNIK_BUNDLE_MANIFEST") ?? bundleUrlFor(baseUrl);
18380
- const outcome = await fetchShellManifest(url2, timeoutMs, key);
18381
- const installed = installedShell(home);
18382
- const decision = decideShell(installed, outcome.ok ? outcome.manifest : null);
18383
- seen({
18384
- installed,
18385
- fresh: decision.what === "nothing" ? null : decision.manifest.version,
18386
- mb: decision.what === "nothing" ? 0 : tenths(decision.manifest.body?.bytes ?? 0),
18387
- status: outcome.ok ? 0 : outcome.status ?? 0,
18388
- notes: decision.what === "nothing" ? "" : decision.manifest.notes ?? ""
18389
- });
18390
- if (decision.what === "nothing") {
18391
- if (!outcome.ok) {
18392
- return toolSuccess(
18393
- `\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0441\u043F\u0440\u043E\u0441\u0438\u0442\u044C, \u0435\u0441\u0442\u044C \u043B\u0438 \u043D\u043E\u0432\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F: ${outcome.why}. \u042D\u0442\u043E \u043D\u0435 \u043F\u043E\u043B\u043E\u043C\u043A\u0430: \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u043D\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F (${installed}) \u0440\u0430\u0431\u043E\u0442\u0430\u0435\u0442 \u043A\u0430\u043A \u0440\u0430\u0431\u043E\u0442\u0430\u043B\u0430.`
18394
- );
18331
+
18332
+ function render(data) {
18333
+ if (closed) return;
18334
+ job = data;
18335
+ // \u0414\u0430\u043D\u043D\u044B\u0435 \u043F\u0440\u0438\u0448\u043B\u0438 \u043F\u043E\u0441\u043B\u0435 \u0441\u0432\u0451\u0440\u0442\u043A\u0438 \u2014 \u0432\u043E\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043C\u0441\u044F \u0432 \u043B\u0435\u043D\u0442\u0443.
18336
+ document.body.classList.remove('gone');
18337
+ byId('card').hidden = true;
18338
+ var ended = !working(data.status);
18339
+
18340
+ // \u26A0 \u041E\u0411\u0429\u0415\u0419 \u0417\u0410\u0413\u041B\u0423\u0428\u041A\u0418 \xAB\u0420\u0410\u0411\u041E\u0422\u0410\u042E\xBB \u041D\u0415\u0422 (\u0432\u043B\u0430\u0434\u0435\u043B\u0435\u0446 2026-09-24): \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A \u2014 \u0441\u0440\u0430\u0437\u0443
18341
+ // \u043D\u0430\u0437\u0432\u0430\u043D\u0438\u0435 \u0440\u0430\u0431\u043E\u0442\u044B, \u0430 \u043D\u0435 \u0441\u043B\u043E\u0432\u043E, \u043A\u043E\u0442\u043E\u0440\u043E\u0435 \u043D\u0438\u0447\u0435\u0433\u043E \u043D\u0435 \u0433\u043E\u0432\u043E\u0440\u0438\u0442.
18342
+ show('what', data.what || '');
18343
+ var clock = byId('clock');
18344
+ if (clock) {
18345
+ clock.textContent = (ended ? '' : '\u0438\u0434\u0451\u0442 ') + howLong(data.sec);
18346
+ // \u26A0 \u041D\u0410 \u041D\u0423\u041B\u0415 \u0427\u0410\u0421\u042B \u041C\u041E\u041B\u0427\u0410\u0422. \xAB\u0438\u0434\u0451\u0442 0 \u0441\xBB \u2014 \u044D\u0442\u043E \u043D\u0435 \u043E\u0442\u0432\u0435\u0442 \u043D\u0430 \xAB\u0441\u043A\u043E\u043B\u044C\u043A\u043E \u0443\u0436\u0435
18347
+ // \u0440\u0430\u0431\u043E\u0442\u0430\u0435\u0442\xBB, \u0430 \u043C\u0443\u0441\u043E\u0440 \u0432 \u0448\u0430\u043F\u043A\u0435: \u0434\u0432\u0438\u0436\u043E\u043A \u0435\u0449\u0451 \u043D\u0435 \u043E\u0442\u043C\u0435\u0442\u0438\u043B \u043D\u0430\u0447\u0430\u043B\u0430.
18348
+ clock.hidden = !data.sec;
18349
+ }
18350
+ rail(Number(data.at) || 0, Number(data.total) || 0, ended);
18351
+
18352
+ var now = byId('now');
18353
+ if (now) now.hidden = ended;
18354
+ if (!ended) {
18355
+ var title = data.now || (data.status === 'waiting' ? '\u0416\u0434\u0443, \u043F\u043E\u043A\u0430 \u0437\u0430\u043A\u043E\u043D\u0447\u0438\u0442\u0441\u044F \u0434\u0440\u0443\u0433\u0430\u044F \u0440\u0430\u0431\u043E\u0442\u0430' : '\u041D\u0430\u0447\u0438\u043D\u0430\u044E');
18356
+ if (data.at && data.total) title = title + ' \xB7 ' + data.at + ' \u0438\u0437 ' + data.total;
18357
+ show('nowTitle', title);
18358
+ show('nowLeft', data.left || '');
18359
+ var loading = download(data);
18360
+ // \u0421\u043A\u0430\u0447\u0438\u0432\u0430\u043D\u0438\u0435 \u0443\u0436\u0435 \u0441\u043A\u0430\u0437\u0430\u043D\u043E \u0448\u043A\u0430\u043B\u043E\u0439 \u0438 \u043F\u043E\u0434\u043F\u0438\u0441\u044C\u044E \u043F\u043E\u0434 \u043D\u0435\u0439 \u2014 \u0442\u0430 \u0436\u0435 \u0441\u0442\u0440\u043E\u043A\u0430
18361
+ // \u0433\u043E\u043B\u0443\u0431\u043E\u0439 \u043F\u043B\u0430\u0448\u043A\u043E\u0439 \u0440\u044F\u0434\u043E\u043C \u0431\u044B\u043B\u0430 \u0431\u044B \u0432\u0442\u043E\u0440\u044B\u043C \u044D\u043A\u0437\u0435\u043C\u043F\u043B\u044F\u0440\u043E\u043C \u043E\u0434\u043D\u0438\u0445 \u0438 \u0442\u0435\u0445 \u0436\u0435 \u0447\u0438\u0441\u0435\u043B.
18362
+ show('msg', data.status === 'waiting' || loading ? '' : (data.message || ''));
18363
+ } else {
18364
+ byId('msg').hidden = true;
18365
+ byId('dl').hidden = true;
18395
18366
  }
18396
- return toolSuccess(
18397
- outcome.manifest.body === null ? `\u0423\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u043E ${installed}; \u043D\u0430 \u0440\u0430\u0437\u0434\u0430\u0447\u0435 ${outcome.manifest.version}, \u043D\u043E \u0444\u0430\u0439\u043B\u0430 \u0434\u043B\u044F \u0441\u0430\u043C\u043E\u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u044F \u0442\u0430\u043C \u043F\u043E\u043A\u0430 \u043D\u0435\u0442. \u041D\u0438\u0447\u0435\u0433\u043E \u0434\u0435\u043B\u0430\u0442\u044C \u043D\u0435 \u043D\u0443\u0436\u043D\u043E, \u043E\u043D \u043F\u043E\u044F\u0432\u0438\u0442\u0441\u044F \u0441 \u0431\u043B\u0438\u0436\u0430\u0439\u0448\u0438\u043C \u0432\u044B\u043A\u0430\u0442\u043E\u043C.` : `\u0423 \u0432\u0430\u0441 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u0430 \u0441\u0430\u043C\u0430\u044F \u043F\u043E\u0441\u043B\u0435\u0434\u043D\u044F\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u2014 ${installed}.`
18398
- );
18367
+
18368
+ // \u26A0 \xAB\u041F\u041E\u0417\u0410\u0414\u0418\xBB \u0418 \xAB\u0414\u0410\u041B\u042C\u0428\u0415\xBB \u041D\u0415 \u0420\u0418\u0421\u0423\u042E\u0422\u0421\u042F (\u0432\u043B\u0430\u0434\u0435\u043B\u0435\u0446 2026-09-24): \u043F\u043E\u0434 \u043D\u0430\u0437\u0432\u0430\u043D\u0438\u0435\u043C
18369
+ // \u044D\u0442\u0430\u043F\u0430 \u0438 \u0448\u043A\u0430\u043B\u043E\u0439 \u043E\u043D\u0438 \u0431\u044B\u043B\u0438 \u0442\u0440\u0435\u0442\u044C\u0438\u043C \u0438 \u0447\u0435\u0442\u0432\u0451\u0440\u0442\u044B\u043C \u0440\u0430\u0441\u0441\u043A\u0430\u0437\u043E\u043C \u043E\u0431 \u043E\u0434\u043D\u043E\u043C \u0438 \u0442\u043E\u043C \u0436\u0435.
18370
+ // \u041E\u0442\u0447\u0451\u0442 \u0438\u0445 \u043F\u043E-\u043F\u0440\u0435\u0436\u043D\u0435\u043C\u0443 \u043D\u0435\u0441\u0451\u0442 \u2014 \u0441\u0442\u0440\u043E\u043A\u0438 \u043D\u0443\u0436\u043D\u044B \u043C\u043E\u0434\u0435\u043B\u0438, \u0430 \u043D\u0435 \u044D\u043A\u0440\u0430\u043D\u0443.
18371
+
18372
+ if (ended) finish(data);
18373
+ else { byId('end').hidden = true; document.body.classList.remove('bad'); }
18374
+ reportSize();
18399
18375
  }
18400
- if (decision.what === "launcher_too_old") {
18401
- return toolSuccess(
18402
- `\u041D\u043E\u0432\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F ${decision.manifest.version} \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043D\u043E\u0432\u043E\u0433\u043E \u0444\u0430\u0439\u043B\u0430 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F \u2014 \u0442\u043E\u0433\u043E, \u0447\u0442\u043E \u0441\u0442\u0430\u0432\u0438\u0442\u0441\u044F \u043F\u0435\u0440\u0435\u0442\u0430\u0441\u043A\u0438\u0432\u0430\u043D\u0438\u0435\u043C. \u0421\u043A\u0430\u0436\u0438 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0443: \u043D\u0430\u043F\u0438\u0448\u0438\u0442\u0435 \u0431\u043E\u0442\u0443 ${KEY_SOURCE_BOT}, \u043E\u043D \u043F\u0440\u0438\u0448\u043B\u0451\u0442 \u0441\u0432\u0435\u0436\u0438\u0439 \u0444\u0430\u0439\u043B; \u0432\u0441\u0451 \u043E\u0441\u0442\u0430\u043B\u044C\u043D\u043E\u0435 \u2014 \u043A\u043B\u044E\u0447, \u0434\u0432\u0438\u0436\u043E\u043A, \u0441\u0442\u0438\u043B\u044C, \u0437\u0430\u0434\u0430\u0447\u0438 \u2014 \u043E\u0441\u0442\u0430\u043D\u0435\u0442\u0441\u044F \u043D\u0430 \u043C\u0435\u0441\u0442\u0435. \u0421\u0442\u0430\u0432\u0438\u0442\u044C \u043D\u0435 \u0441\u0442\u0430\u043B.`
18403
- );
18376
+
18377
+ /**
18378
+ * \u0417\u0430\u0433\u043B\u0430\u0432\u043D\u0430\u044F \u0443 \u0440\u0443\u0441\u0441\u043A\u043E\u0433\u043E \u043D\u0430\u0437\u0432\u0430\u043D\u0438\u044F \u0447\u0430\u0441\u0442\u0438, \u0430 \u0438\u043C\u044F \u043F\u0440\u043E\u0433\u0440\u0430\u043C\u043C\u044B \u2014 \u043A\u0430\u043A \u0435\u0441\u0442\u044C.
18379
+ *
18380
+ * \u26A0 \u041D\u0415 CSS \xABfirst-letter\xBB. \u041D\u0430\u0437\u0432\u0430\u043D\u0438\u044F \u0447\u0430\u0441\u0442\u0435\u0439 \u043F\u0438\u0448\u0435\u0442 \u0434\u0432\u0438\u0436\u043E\u043A \u0441\u0442\u0440\u043E\u0447\u043D\u044B\u043C\u0438: \u043E\u043D\u0438 \u0436\u0435
18381
+ * \u0438\u0434\u0443\u0442 \u0432 \u0435\u0433\u043E \u043E\u0442\u0432\u0435\u0442 \u043C\u043E\u0434\u0435\u043B\u0438 \u0441\u0435\u0440\u0435\u0434\u0438\u043D\u043E\u0439 \u0444\u0440\u0430\u0437\u044B. \u041D\u043E \xABffmpeg\xBB \u2014 \u0438\u043C\u044F \u043F\u0440\u043E\u0433\u0440\u0430\u043C\u043C\u044B, \u0438
18382
+ * \u043F\u0440\u0430\u0432\u0438\u043B\u043E \u0434\u043B\u044F \u0432\u0441\u0435\u0445 \u043F\u0435\u0440\u0432\u044B\u0445 \u0431\u0443\u043A\u0432 \u0434\u0435\u043B\u0430\u043B\u043E \u0438\u0437 \u043D\u0435\u0433\u043E \xABFfmpeg\xBB (\u0441\u043D\u0438\u043C\u043E\u043A 2026-09-24).
18383
+ */
18384
+ function capital(text) {
18385
+ var s = String(text || '');
18386
+ return /^[\u0430-\u044F\u0451]/.test(s) ? s.charAt(0).toUpperCase() + s.slice(1) : s;
18404
18387
  }
18405
- if (!consent) {
18406
- const mb = ((decision.manifest.body?.bytes ?? 0) / 1024 / 1024).toFixed(1);
18407
- return toolSuccess(
18408
- `\u0415\u0441\u0442\u044C \u043D\u043E\u0432\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F: ${installed} \u2192 ${decision.manifest.version}, ${mb} \u041C\u0411.
18409
- ` + (decision.manifest.notes === null ? "" : `\u0427\u0442\u043E \u043D\u043E\u0432\u043E\u0433\u043E:
18410
- ${decision.manifest.notes}
18411
- `) + "\u0421\u043A\u0430\u0436\u0438 \u044D\u0442\u043E \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0443 \u0438 \u0441\u043F\u0440\u043E\u0441\u0438, \u0441\u0442\u0430\u0432\u0438\u0442\u044C \u043B\u0438. \u0421\u043E\u0433\u043B\u0430\u0441\u0438\u043B\u0441\u044F \u2014 \u0437\u043E\u0432\u0438 setup \u0441 what=shell \u0441 consent=true. \u0417\u0430\u0440\u0430\u0431\u043E\u0442\u0430\u0435\u0442 \u043F\u043E\u0441\u043B\u0435 \u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u043A\u0430 \u041A\u043B\u043E\u0434\u0430 \u0438\u043B\u0438 Codex."
18412
- );
18388
+
18389
+ /** \xAB245 \u041C\u0411\xBB, \xAB1,6 \u0413\u0411\xBB \u2014 \u043A\u0430\u043A \u0432 \u0441\u043B\u043E\u0432\u0430\u0445 setup, \u0430 \u043D\u0435 \u0433\u043E\u043B\u044B\u043C \u0447\u0438\u0441\u043B\u043E\u043C \u043C\u0435\u0433\u0430\u0431\u0430\u0439\u0442. */
18390
+ function weight(mb) {
18391
+ var n = Math.max(0, Math.round(Number(mb) || 0));
18392
+ if (n >= 1000) return (n / 1024).toFixed(1).replace('.', ',') + ' \u0413\u0411';
18393
+ return n + ' \u041C\u0411';
18413
18394
  }
18414
- return asToolResult(await installShell({
18415
- home,
18416
- manifest: decision.manifest,
18417
- key: key ?? null
18418
- }));
18419
- }
18420
- var UPDATES = /* @__PURE__ */ new Set(["all", "engine", "shell"]);
18421
- var HEAVY_STEPS = {
18422
- speech: "model",
18423
- cutout: "cutout",
18424
- voice: "voice"
18425
- };
18426
- function setupTool(engine, passport, key, baseUrl) {
18427
- return defineTool({
18428
- name: "setup",
18429
- title: "\u041F\u0440\u043E\u0432\u0435\u0440\u0438\u0442\u044C \u0438 \u043F\u043E\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u0432\u0441\u0451 \u0434\u043B\u044F \u043C\u043E\u043D\u0442\u0430\u0436\u0430",
18430
- description: "\u0412\u0441\u0451, \u0447\u0435\u043C \u043C\u043E\u043D\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u043D\u0430 \u044D\u0442\u043E\u043C \u043A\u043E\u043C\u043F\u044C\u044E\u0442\u0435\u0440\u0435, \u2014 \u043E\u0434\u043D\u0438\u043C \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u043E\u043C. \u0411\u0435\u0437 \u0430\u0440\u0433\u0443\u043C\u0435\u043D\u0442\u043E\u0432 \u041F\u0420\u041E\u0412\u0415\u0420\u042F\u0415\u0422 \u0434\u0435\u043B\u043E\u043C: \u0447\u0442\u043E \u0441\u0442\u043E\u0438\u0442 \u0438 \u0447\u0435\u0433\u043E \u043D\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442, \u0447\u0442\u043E \u0434\u043E\u043A\u0430\u0447\u0430\u0435\u0442\u0441\u044F \u043F\u043E \u043F\u0440\u043E\u0441\u044C\u0431\u0435 \u0438 \u0441\u043A\u043E\u043B\u044C\u043A\u043E \u0432\u0435\u0441\u0438\u0442, \u0447\u0442\u043E \u0443\u043C\u0435\u0435\u0442 \u043C\u043E\u043D\u0442\u0430\u0436 (\u0448\u0430\u0433\u0438, \u0432\u043E\u043F\u0440\u043E\u0441\u044B \u0434\u043B\u044F \u043A\u0430\u0440\u0442\u043E\u0447\u0435\u043A choose_variant, \u0447\u0435\u0439 \u0440\u0435\u0446\u0435\u043F\u0442 \u0438 \u0447\u0435\u0439 \u0441\u0442\u0438\u043B\u044C) \u0438 \u0432\u044B\u0448\u043B\u0430 \u043B\u0438 \u043D\u043E\u0432\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u0434\u0432\u0438\u0436\u043A\u0430 \u0438\u043B\u0438 \u0441\u0430\u043C\u043E\u0433\u043E \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F. \u0417\u043E\u0432\u0438 \u041F\u0415\u0420\u0412\u042B\u041C, \u0434\u043E \u043B\u044E\u0431\u043E\u0439 \u0440\u0430\u0431\u043E\u0442\u044B \u0441 \u0432\u0438\u0434\u0435\u043E, \u0438 \u0438\u0437 \u0441\u0432\u043E\u0435\u0439 \u043F\u0430\u043C\u044F\u0442\u0438 \u043E\u0431 \u044D\u0442\u043E\u043C \u043D\u0435 \u0440\u0430\u0441\u0441\u043A\u0430\u0437\u044B\u0432\u0430\u0439.\n\u0421\u0442\u0430\u0432\u0438\u0442 \u0438 \u043E\u0431\u043D\u043E\u0432\u043B\u044F\u0435\u0442 \u0441 what, \u043D\u043E \u0442\u043E\u043B\u044C\u043A\u043E \u043F\u043E\u0441\u043B\u0435 \xAB\u0434\u0430\xBB \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430: \u0441\u043D\u0430\u0447\u0430\u043B\u0430 \u0441\u043A\u0430\u0436\u0438 \u0435\u043C\u0443 \u0441\u043B\u043E\u0432\u0430\u043C\u0438, \u0447\u0442\u043E \u043F\u043E\u0441\u0442\u0430\u0432\u0438\u0448\u044C \u0438 \u0441\u043A\u043E\u043B\u044C\u043A\u043E \u044D\u0442\u043E \u0432\u0435\u0441\u0438\u0442, \u043F\u043E\u0442\u043E\u043C \u0437\u043E\u0432\u0438 \u0441 \u0442\u0435\u043C \u0436\u0435 what \u0438 consent=true. \xAB\u0421\u043A\u0430\u0447\u0430\u0439\xBB \u0438 \xAB\u043E\u0431\u043D\u043E\u0432\u0438\xBB \u2014 \u0442\u043E \u0436\u0435 \xAB\u0434\u0430\xBB \u043D\u0430 \u0442\u043E, \u0447\u0442\u043E \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0430 \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438 \u0443\u0436\u0435 \u043D\u0430\u0437\u0432\u0430\u043B\u0430 \u0441 \u0432\u0435\u0441\u043E\u043C: \u0437\u043E\u0432\u0438 what=all \u0441 consent=true \u041E\u0414\u0418\u041D \u0440\u0430\u0437 \u2014 \u043E\u0442\u0432\u0435\u0442 \u043D\u043E\u043C\u0435\u0440\u043E\u043C \u0437\u0430\u0434\u0430\u0447\u0438, \u0434\u0430\u043B\u044C\u0448\u0435 wait, setup \u043F\u043E\u0432\u0442\u043E\u0440\u043D\u043E \u043D\u0435 \u0437\u043E\u0432\u0438. \u0411\u0435\u0437 consent \u043D\u0438\u0447\u0435\u0433\u043E \u043D\u0435 \u043A\u0430\u0447\u0430\u0435\u0442\u0441\u044F \u2014 \u043F\u0440\u0438\u0434\u0443\u0442 \u0432\u0435\u0441 \u0438 \u0432\u043E\u043F\u0440\u043E\u0441. \u0422\u044F\u0436\u0451\u043B\u043E\u0435 \u0441\u0442\u0430\u0432\u0438\u0442\u0441\u044F \u0442\u043E\u043B\u044C\u043A\u043E \u043F\u043E\u0434 \u043F\u0440\u043E\u0441\u044C\u0431\u0443: \u043D\u0435 \u043F\u0440\u043E\u0441\u0438\u043B\u0438 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u044B \u2014 \u043D\u0435 \u0441\u0442\u0430\u0432\u044C speech, \u043D\u0435 \u043F\u0440\u043E\u0441\u0438\u043B\u0438 \u043D\u043E\u0432\u044B\u0439 \u0444\u043E\u043D \u2014 \u043D\u0435 \u0441\u0442\u0430\u0432\u044C cutout.\n\u0414\u043E\u043B\u0433\u0430\u044F \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0430 \u043E\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u043D\u043E\u043C\u0435\u0440\u043E\u043C \u0437\u0430\u0434\u0430\u0447\u0438 \u2014 \u0434\u043E\u0436\u0434\u0438\u0441\u044C \u0435\u0451 \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u043E\u043C wait. \u041D\u043E\u0432\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u0434\u0432\u0438\u0436\u043A\u0430 \u0438\u043B\u0438 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F \u0437\u0430\u0440\u0430\u0431\u043E\u0442\u0430\u0435\u0442 \u043F\u043E\u0441\u043B\u0435 \u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u043A\u0430 \u041A\u043B\u043E\u0434\u0430 \u0438\u043B\u0438 Codex, \u0441\u043A\u0430\u0436\u0438 \u044D\u0442\u043E \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0443. \u0421\u043B\u043E\u043C\u0430\u043B\u043E\u0441\u044C \u043F\u043E\u0441\u043B\u0435 \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u044F \u2014 rollback. \u041F\u043E\u0434\u043F\u0438\u0441\u043A\u0430 \u043D\u0435 \u043D\u0443\u0436\u043D\u0430: \u0443\u0437\u043D\u0430\u0442\u044C, \u0437\u0430 \u0447\u0442\u043E \u043F\u043B\u0430\u0442\u044F\u0442, \u043C\u043E\u0436\u043D\u043E \u0434\u043E \u043E\u043F\u043B\u0430\u0442\u044B, \u0430 \u0441\u043A\u0430\u0447\u0438\u0432\u0430\u043D\u0438\u0435 \u0441\u0430\u043C\u043E \u0443\u043F\u0438\u0440\u0430\u0435\u0442\u0441\u044F \u0432 \u043A\u043B\u044E\u0447 \u043D\u0430 \u0440\u0430\u0437\u0434\u0430\u0447\u0435.",
18431
- // Полоса хода работы в ленте: установка качает десятки минут, и человек
18432
- // видит, что качается и сколько уже скачано. ⚠ Ожидание задачи — у
18433
- // отдельного инструмента `wait`, без полосы: полоса объявлена на
18434
- // инструменте, и ждать тем же инструментом значило бы рисовать новую
18435
- // полосу на каждый вызов.
18436
- ui: { resourceUri: RUNBAR_RESOURCE_URI },
18437
- args: external_exports.object({
18438
- what: external_exports.enum(["all", "engine", "shell", "speech", "cutout", "voice"]).describe(
18439
- "\u0427\u0442\u043E \u043F\u043E\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u0438\u043B\u0438 \u043E\u0431\u043D\u043E\u0432\u0438\u0442\u044C. all \u2014 \u0432\u0441\u0451 \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u043E\u0435, \u0447\u0435\u0433\u043E \u043D\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442, \u0438 \u043D\u043E\u0432\u044B\u0435 \u0432\u0435\u0440\u0441\u0438\u0438, \u043E \u043A\u043E\u0442\u043E\u0440\u044B\u0445 \u0441\u043A\u0430\u0437\u0430\u043B\u0430 \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0430; engine \u2014 \u0442\u043E\u043B\u044C\u043A\u043E \u043D\u043E\u0432\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u0434\u0432\u0438\u0436\u043A\u0430; shell \u2014 \u0442\u043E\u043B\u044C\u043A\u043E \u043D\u043E\u0432\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u0441\u0430\u043C\u043E\u0433\u043E \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F; speech \u2014 \u0440\u0430\u0441\u043F\u043E\u0437\u043D\u0430\u0432\u0430\u043D\u0438\u0435 \u0440\u0435\u0447\u0438 (\u0441\u0443\u0431\u0442\u0438\u0442\u0440\u044B); cutout \u2014 \u0432\u044B\u0440\u0435\u0437 \u0433\u0435\u0440\u043E\u044F (\u043D\u043E\u0432\u044B\u0439 \u0444\u043E\u043D); voice \u2014 \u0447\u0438\u0441\u0442\u043A\u0430 \u0433\u043E\u043B\u043E\u0441\u0430"
18440
- ).optional(),
18441
- consent: external_exports.boolean().describe(
18442
- "\u0427\u0435\u043B\u043E\u0432\u0435\u043A \u0420\u0410\u0417\u0420\u0415\u0428\u0418\u041B \u0441\u043A\u0430\u0447\u0430\u0442\u044C \u0442\u043E, \u0447\u0442\u043E \u043D\u0430\u0437\u0432\u0430\u043D\u043E \u0432 what. \u0421\u0442\u0430\u0432\u044C \u0442\u043E\u043B\u044C\u043A\u043E \u043F\u043E\u0441\u043B\u0435 \u0442\u043E\u0433\u043E, \u043A\u0430\u043A \u043D\u0430\u0437\u0432\u0430\u043B \u0435\u043C\u0443, \u0447\u0442\u043E \u0438 \u0441\u043A\u043E\u043B\u044C\u043A\u043E \u0432\u0435\u0441\u0438\u0442, \u0438 \u043E\u043D \u0441\u043E\u0433\u043B\u0430\u0441\u0438\u043B\u0441\u044F \u2014 \u044D\u0442\u043E \u0435\u0433\u043E \u0442\u0440\u0430\u0444\u0438\u043A \u0438 \u0435\u0433\u043E \u0434\u0438\u0441\u043A"
18443
- ).optional(),
18444
- model: fromList(
18445
- passport?.["models"],
18446
- `\u041C\u043E\u0434\u0435\u043B\u044C \u0440\u0430\u0441\u043F\u043E\u0437\u043D\u0430\u0432\u0430\u043D\u0438\u044F \u0440\u0435\u0447\u0438: \u043A\u0430\u043A\u0443\u044E \u043F\u0440\u043E\u0432\u0435\u0440\u044F\u0442\u044C \u0438\u043B\u0438 \u0441\u0442\u0430\u0432\u0438\u0442\u044C \u0441 what="speech". ${aboutModels(passport)}`
18447
- ).optional(),
18448
- rollback: external_exports.enum(["engine", "shell"]).describe(
18449
- "\u0412\u0435\u0440\u043D\u0443\u0442\u044C \u043F\u0440\u0435\u0436\u043D\u044E\u044E \u0432\u0435\u0440\u0441\u0438\u044E: engine \u2014 \u0434\u0432\u0438\u0436\u043E\u043A, shell \u2014 \u0441\u0430\u043C\u043E \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u0435. \u0417\u043E\u0432\u0438, \u043A\u043E\u0433\u0434\u0430 \u043F\u043E\u0441\u043B\u0435 \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u044F \u0447\u0442\u043E-\u0442\u043E \u043F\u0435\u0440\u0435\u0441\u0442\u0430\u043B\u043E \u0440\u0430\u0431\u043E\u0442\u0430\u0442\u044C: \u043F\u0440\u0435\u0436\u043D\u044F\u044F \u043B\u0435\u0436\u0438\u0442 \u043D\u0430 \u0434\u0438\u0441\u043A\u0435 \u0440\u044F\u0434\u043E\u043C. \u0417\u0430\u0440\u0430\u0431\u043E\u0442\u0430\u0435\u0442 \u043F\u043E\u0441\u043B\u0435 \u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u043A\u0430"
18450
- ).optional()
18451
- // ⚠ СОЧЕТАНИЯ СВЕРЯЮТСЯ В САМОЙ СХЕМЕ, А НЕ В ТЕЛЕ. Так правило видит
18452
- // сверка аргументов на регистрации, и кривой вызов отбивается до всякой
18453
- // сети (`tool-args.ts`); в теле оно стало бы правдой, о которой сверка не
18454
- // знает.
18455
- }).check((ctx) => {
18456
- const asked = ctx.value;
18457
- if (asked.rollback !== void 0 && asked.what !== void 0) {
18458
- ctx.issues.push({
18459
- code: "custom",
18460
- message: "\xABrollback\xBB \u0438 \xABwhat\xBB \u2014 \u0440\u0430\u0437\u043D\u044B\u0435 \u043F\u0440\u043E\u0441\u044C\u0431\u044B: \u043E\u0442\u043A\u0430\u0442 \u0432\u043E\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043F\u0440\u0435\u0436\u043D\u044E\u044E \u0432\u0435\u0440\u0441\u0438\u044E, \u0430 what \u0441\u0442\u0430\u0432\u0438\u0442 \u043D\u043E\u0432\u043E\u0435. \u041F\u043E\u0437\u043E\u0432\u0438 \u0441 \u043E\u0434\u043D\u0438\u043C \u0438\u0437 \u043D\u0438\u0445",
18461
- input: asked,
18462
- path: ["rollback"]
18463
- });
18464
- }
18465
- if (asked.consent === true && asked.what === void 0 && asked.rollback === void 0) {
18466
- ctx.issues.push({
18467
- code: "custom",
18468
- message: "\xABconsent\xBB \u0431\u0435\u0437 \xABwhat\xBB: \u043D\u0435 \u0441\u043A\u0430\u0437\u0430\u043D\u043E, \u043D\u0430 \u0447\u0442\u043E \u0441\u043E\u0433\u043B\u0430\u0441\u0438\u043B\u0441\u044F \u0447\u0435\u043B\u043E\u0432\u0435\u043A. \u041D\u0430\u0437\u043E\u0432\u0438 what \u2014 \u0442\u043E, \u0447\u0442\u043E \u0442\u044B \u0435\u043C\u0443 \u043F\u0440\u0435\u0434\u043B\u0430\u0433\u0430\u043B",
18469
- input: asked,
18470
- path: ["consent"]
18471
- });
18472
- }
18473
- }),
18474
- async execute(args, ctx) {
18475
- const news = { engine: null, shell: null };
18476
- const said = await answer(args, ctx?.emitProgress, news);
18477
- return withCard(said, () => setupCard({
18478
- readiness: null,
18479
- engine: news.engine ?? { installed: engine.freshVersion(), fresh: null, mb: 0, status: 0, notes: "" },
18480
- shell: news.shell,
18481
- note: firstLine(said),
18482
- shellVersion: VERSION
18483
- }));
18484
- }
18485
- });
18486
- async function answer(args, tell, news) {
18487
- if (args.rollback === "engine") return asToolResult(rollback(engine));
18488
- if (args.rollback === "shell") return asToolResult(rollbackShell(engine.home()));
18489
- const consent = args.consent === true;
18490
- const what = args.what;
18491
- if (what === void 0) return lookAround(engine, args.model, key, baseUrl);
18492
- if (consent && UPDATES.has(what)) return startUpdate(engine, what, key, baseUrl);
18493
- if (what === "engine") {
18494
- return updateEngine(engine, consent, key, baseUrl, ASKED_POINTER_MS, (seen) => {
18495
- if (!consent) news.engine = seen;
18496
- });
18395
+
18396
+ function fill(id, percent) {
18397
+ var el = byId(id);
18398
+ if (el) el.style.width = Math.max(0, Math.min(100, Number(percent) || 0)) + '%';
18399
+ }
18400
+
18401
+ /**
18402
+ * \u0428\u043A\u0430\u043B\u0430 \u0441\u043A\u0430\u0447\u0438\u0432\u0430\u043D\u0438\u044F \u043F\u043E \u0447\u0438\u0441\u043B\u0430\u043C \u0437\u0430\u0434\u0430\u0447\u0438. \u0412\u0435\u0440\u043D\u0451\u0442, \u043D\u0430\u0440\u0438\u0441\u043E\u0432\u0430\u043D\u0430 \u043B\u0438 \u043E\u043D\u0430.
18403
+ *
18404
+ * \u26A0 \u0411\u0415\u0417 \xAB\u0418\u0417 \u0421\u041A\u041E\u041B\u042C\u041A\u0418\u0425\xBB \u0417\u0410\u041B\u0418\u0412\u041A\u0418 \u041D\u0415\u0422, \u0410 \u041F\u041E\u0414\u041F\u0418\u0421\u042C \u0415\u0421\u0422\u042C. \u0412\u0441\u0435\u0433\u043E \u0434\u0432\u0438\u0436\u043E\u043A \u0437\u043D\u0430\u0435\u0442 \u043D\u0435
18405
+ * \u0432\u0441\u0435\u0433\u0434\u0430; \u0437\u0430\u043B\u0438\u0442\u044C \u043D\u0430\u0443\u0433\u0430\u0434 \u2014 \u0441\u043E\u0432\u0440\u0430\u0442\u044C \u043E \u0434\u043E\u043B\u0435, \u0430 \u043C\u0435\u0433\u0430\u0431\u0430\u0439\u0442\u044B \u043F\u0440\u0430\u0432\u0434\u0438\u0432\u044B.
18406
+ */
18407
+ function download(data) {
18408
+ var box = byId('dl');
18409
+ if (!box) return false;
18410
+ var got = Number(data.got) || 0;
18411
+ var of = Number(data.of) || 0;
18412
+ // \u041D\u043E\u043B\u044C \u0438\u0437 \u0438\u0437\u0432\u0435\u0441\u0442\u043D\u043E\u0433\u043E \u0446\u0435\u043B\u043E\u0433\u043E \u2014 \u0443\u0436\u0435 \u0448\u043A\u0430\u043B\u0430: \xAB0 \u0438\u0437 450 \u041C\u0411 \xB7 0%\xBB \u0433\u043E\u0432\u043E\u0440\u0438\u0442, \u0441\u043A\u043E\u043B\u044C\u043A\u043E
18413
+ // \u043F\u0440\u0435\u0434\u0441\u0442\u043E\u0438\u0442, \u0430 \u0441\u0442\u0440\u043E\u043A\u0430 \xAB\u0421\u043A\u0430\u0447\u0430\u043D\u043E 0 \u041C\u0411\xBB \u043F\u043B\u0430\u0448\u043A\u043E\u0439 \u0447\u0438\u0442\u0430\u043B\u0430\u0441\u044C \u0431\u044B \u043A\u0430\u043A \u043F\u043E\u043B\u043E\u043C\u043A\u0430.
18414
+ if (!got && !of) { box.hidden = true; return false; }
18415
+ byId('dlMeter').hidden = !of;
18416
+ fill('dlFill', of ? data.percent : 0);
18417
+ var cap = byId('dlCap');
18418
+ cap.innerHTML = '';
18419
+ var b = document.createElement('b');
18420
+ b.textContent = of ? (got + ' \u0438\u0437 ' + weight(of)) : ('\u0441\u043A\u0430\u0447\u0430\u043D\u043E ' + weight(got));
18421
+ cap.appendChild(b);
18422
+ var tail = of ? ' \xB7 ' + (Number(data.percent) || 0) + '%' : '';
18423
+ if (data.eta) tail += ' \xB7 ' + data.eta;
18424
+ cap.appendChild(document.createTextNode(tail));
18425
+ cap.hidden = false;
18426
+ box.hidden = false;
18427
+ return true;
18428
+ }
18429
+
18430
+ // \u2500\u2500\u2500 \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0430 \u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u044F \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
18431
+
18432
+ /**
18433
+ * \u041E\u0442\u0432\u0435\u0442 setup \u0431\u0435\u0437 \u0437\u0430\u0434\u0430\u0447\u0438: \u0447\u0442\u043E \u0441\u0442\u043E\u0438\u0442, \u0447\u0435\u0433\u043E \u043D\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442, \u0447\u0442\u043E \u0432\u044B\u0448\u043B\u043E, \u0447\u0442\u043E \u0434\u0430\u043B\u044C\u0448\u0435.
18434
+ *
18435
+ * \u26A0 \u041E\u041F\u0420\u041E\u0421 \u041D\u0415 \u0417\u0410\u0412\u041E\u0414\u0418\u0422\u0421\u042F: \u0440\u0430\u0431\u043E\u0442\u044B \u043D\u0435\u0442, \u0441\u043F\u0440\u0430\u0448\u0438\u0432\u0430\u0442\u044C \u043D\u0435 \u043E \u0447\u0435\u043C. \u041A\u0430\u0440\u0442\u043E\u0447\u043A\u0430 \u2014 \u0441\u043D\u0438\u043C\u043E\u043A
18436
+ * \u043D\u0430 \u043C\u043E\u043C\u0435\u043D\u0442 \u043E\u0442\u0432\u0435\u0442\u0430; \u043D\u043E\u0432\u044B\u0439 \u0432\u044B\u0437\u043E\u0432 setup \u043F\u0440\u0438\u043D\u0435\u0441\u0451\u0442 \u043D\u043E\u0432\u0443\u044E.
18437
+ */
18438
+ function renderCard(data) {
18439
+ if (closed) return;
18440
+ job = null;
18441
+ document.body.classList.remove('gone');
18442
+ document.body.classList.remove('bad');
18443
+ var hide = ['now', 'rail', 'msg', 'dl', 'clock', 'end', 'note'];
18444
+ for (var i = 0; i < hide.length; i++) { var el = byId(hide[i]); if (el) el.hidden = true; }
18445
+
18446
+ var rows = data.rows || [];
18447
+ var ok = 0, need = 0;
18448
+ for (var j = 0; j < rows.length; j++) {
18449
+ if (rows[j].state === 'ok') { ok++; need++; }
18450
+ else if (rows[j].state === 'missing') need++;
18497
18451
  }
18498
- if (what === "shell") {
18499
- return updateShell(engine, consent, key, baseUrl, ASKED_POINTER_MS, (seen) => {
18500
- if (!consent) news.shell = seen;
18501
- });
18452
+ // \u0421\u043B\u043E\u0432\u0430 \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0438 \u043F\u0438\u0448\u0435\u0442 \u043E\u0431\u043E\u043B\u043E\u0447\u043A\u0430 (setup-card.ts), \u0437\u0434\u0435\u0441\u044C \u0438\u0445 \u0442\u043E\u043B\u044C\u043A\u043E \u0441\u0442\u0430\u0432\u044F\u0442
18453
+ // \u043D\u0430 \u043C\u0435\u0441\u0442\u043E: \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A, \u0432\u0435\u0440\u0441\u0438\u044F, \u0441\u0442\u0440\u043E\u043A\u0438, \u043D\u043E\u0432\u043E\u0441\u0442\u044C, \u0447\u0442\u043E \u0434\u0430\u043B\u044C\u0448\u0435.
18454
+ show('what', data.title || '');
18455
+ show('cardMeta', data.meta || '');
18456
+
18457
+ // \u0428\u043A\u0430\u043B\u0430 \u0433\u043E\u0442\u043E\u0432\u043D\u043E\u0441\u0442\u0438 \u2014 \u043F\u043E \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u043E\u043C\u0443: \u0442\u043E, \u0447\u0442\u043E \u0432\u0441\u0442\u0430\u043D\u0435\u0442 \u043F\u043E \u043F\u0440\u043E\u0441\u044C\u0431\u0435, \u0434\u043E\u043B\u0435\u0439
18458
+ // \xAB\u043D\u0435 \u0433\u043E\u0442\u043E\u0432\u043E\xBB \u043D\u0435 \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044F, \u0438\u043D\u0430\u0447\u0435 \u0447\u0435\u043B\u043E\u0432\u0435\u043A \u0431\u0435\u0437 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u043E\u0432 \u043D\u0430\u0432\u0441\u0435\u0433\u0434\u0430 \u0432\u0438\u0434\u0435\u043B \u0431\u044B
18459
+ // \u043D\u0435\u0434\u043E\u043B\u0438\u0442\u0443\u044E \u043F\u043E\u043B\u043E\u0441\u0443 \u043D\u0430 \u0438\u0441\u043F\u0440\u0430\u0432\u043D\u043E\u0439 \u043C\u0430\u0448\u0438\u043D\u0435.
18460
+ byId('cardMeter').hidden = !need;
18461
+ fill('cardFill', need ? ok * 100 / need : 0);
18462
+ var cap = byId('cardCap');
18463
+ cap.innerHTML = '';
18464
+ if (need) {
18465
+ var b = document.createElement('b');
18466
+ b.textContent = '\u0413\u043E\u0442\u043E\u0432\u043E ' + ok + ' \u0438\u0437 ' + need;
18467
+ cap.appendChild(b);
18502
18468
  }
18503
- if (what === "all") {
18504
- return lookAround(engine, args.model, key, baseUrl);
18469
+ cap.hidden = !need;
18470
+
18471
+ var list = byId('cardRows');
18472
+ list.innerHTML = '';
18473
+ for (var k = 0; k < rows.length; k++) {
18474
+ var row = rows[k];
18475
+ var li = document.createElement('li');
18476
+ li.className = 'part ' + row.state;
18477
+ var mark = document.createElement('span');
18478
+ mark.className = 'part__m';
18479
+ li.appendChild(mark);
18480
+ var title = document.createElement('span');
18481
+ title.className = 'part__t';
18482
+ title.textContent = capital(row.title);
18483
+ li.appendChild(title);
18484
+ var w = document.createElement('span');
18485
+ w.className = 'part__w';
18486
+ w.textContent = row.say || '';
18487
+ li.appendChild(w);
18488
+ list.appendChild(li);
18505
18489
  }
18506
- const step = HEAVY_STEPS[what];
18507
- return consent ? installStep(engine, { step, model: args.model, consent: true }, key, baseUrl, tell) : askBeforeHeavy(engine, step, args.model, key, baseUrl);
18508
- }
18509
- }
18510
- async function lookAround(engine, model, key, baseUrl) {
18511
- let engineNews = null;
18512
- let shellNews = null;
18513
- const toEngine = (news2) => {
18514
- engineNews = news2;
18515
- };
18516
- const toShell = (news2) => {
18517
- shellNews = news2;
18518
- };
18519
- const card = (said, o) => withCard(said, () => setupCard({
18520
- readiness: o.readiness ?? null,
18521
- engine: engineNews ?? { installed: engine.freshVersion(), fresh: null, mb: 0, status: 0, notes: "" },
18522
- shell: shellNews,
18523
- ...o.noEngine === true ? { noEngine: true } : {},
18524
- ...o.noPython === true ? { noPython: true } : {},
18525
- note: o.note ?? firstLine(said),
18526
- shellVersion: VERSION
18527
- }));
18528
- const shell = updateShell(engine, false, key, baseUrl, NEWS_POINTER_MS, toShell);
18529
- if (engine.place() === null) {
18530
- const payload = await installPayload(engine, {
18531
- consent: false,
18532
- manifestUrl: manifestUrl(engine, baseUrl),
18533
- ...key !== void 0 ? { key } : {}
18534
- });
18535
- return card(together([toolSuccess(payload.text), await shell]), { noEngine: true });
18490
+ list.hidden = !rows.length;
18491
+
18492
+ show('cardUpdate', data.update || '');
18493
+ show('cardTrouble', data.trouble || '');
18494
+ show('cardNext', data.next || '');
18495
+ byId('card').hidden = false;
18496
+ reportSize();
18536
18497
  }
18537
- const noPython = await engine.pythonTrouble();
18538
- if (noPython !== null) {
18539
- return card(together([
18540
- toolSuccess(noPython),
18541
- await updateEngine(engine, false, key, baseUrl, NEWS_POINTER_MS, toEngine),
18542
- await shell
18543
- ]), { noPython: true });
18498
+
18499
+ /** \u041A\u043E\u043D\u0435\u0446 \u0440\u0430\u0431\u043E\u0442\u044B: \u0443\u0441\u043F\u0435\u0445 \u0441 \u043F\u0443\u0442\u0451\u043C \u043A \u0444\u0430\u0439\u043B\u0443 \u0438\u043B\u0438 \u043E\u0442\u043A\u0430\u0437 \u0441\u043B\u043E\u0432\u0430\u043C\u0438. */
18500
+ function finish(data) {
18501
+ var good = data.status === 'done';
18502
+ document.body.classList.remove('bad');
18503
+ if (!good) document.body.classList.add('bad');
18504
+
18505
+ if (good && data.file) {
18506
+ show('endTitle', '\u0413\u043E\u0442\u043E\u0432\u043E \u0437\u0430 ' + howLong(data.sec));
18507
+ show('endHint', '\u0420\u043E\u043B\u0438\u043A \u0433\u043E\u0442\u043E\u0432:');
18508
+ show('path', data.file);
18509
+ } else if (good) {
18510
+ // \u26A0 \u0423 \u0420\u0410\u0411\u041E\u0422\u042B \u0411\u0415\u0417 \u0424\u0410\u0419\u041B\u0410 \u2014 \u0424\u0420\u0410\u0417\u0410, \u0410 \u041D\u0415 \u041E\u0422\u0427\u0401\u0422 (\u0432\u043B\u0430\u0434\u0435\u043B\u0435\u0446 2026-09-24). \u041E\u0442\u0447\u0451\u0442
18511
+ // \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0438 \u2014 \u0441\u0442\u0440\u043E\u043A\u0438 \u0434\u0432\u0438\u0436\u043A\u0430 \u0441 \u043F\u0443\u0442\u044F\u043C\u0438 \u0438 \u0438\u043C\u0435\u043D\u0430\u043C\u0438 \u0448\u0430\u0433\u043E\u0432, \u043E\u043D \u0434\u043B\u044F \u043C\u043E\u0434\u0435\u043B\u0438.
18512
+ // \xAB\u0413\u043E\u0442\u043E\u0432\u043E. \u041F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u0442\u0438 Claude \u2014 \u2026\xBB \u0434\u0435\u043B\u0438\u0442\u0441\u044F \u043D\u0430 \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A \u0438 \u043F\u043E\u0434\u0441\u043A\u0430\u0437\u043A\u0443.
18513
+ var say = data.say || '\u0413\u043E\u0442\u043E\u0432\u043E \u2014 \u043C\u043E\u0436\u043D\u043E \u043C\u043E\u043D\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C.';
18514
+ var cut = /^(.+?)[.!]\\s+(.+)$/.exec(say);
18515
+ show('endTitle', cut ? cut[1] : say.replace(/[.]$/, ''));
18516
+ show('endHint', cut ? cut[2] : '');
18517
+ show('path', '');
18518
+ } else {
18519
+ show('endTitle', data.status === 'aborted' ? '\u0420\u0430\u0431\u043E\u0442\u0430 \u043F\u0440\u0435\u0440\u0432\u0430\u043B\u0430\u0441\u044C' : '\u041D\u0435 \u043F\u043E\u043B\u0443\u0447\u0438\u043B\u043E\u0441\u044C');
18520
+ show('endHint', data.trouble || '\u0427\u0442\u043E-\u0442\u043E \u0441\u043B\u043E\u043C\u0430\u043B\u043E\u0441\u044C. \u041D\u0430\u043F\u0438\u0448\u0438 \u041A\u043B\u043E\u0434\u0443 \xAB\u0447\u0442\u043E \u0441\u043B\u0443\u0447\u0438\u043B\u043E\u0441\u044C\xBB.');
18521
+ show('path', '');
18522
+ }
18523
+ var warn = [];
18524
+ if (good && data.outcome && data.file) warn.push(data.outcome);
18525
+ // \u26A0 \u0416\u0410\u041B\u041E\u0411\u0410 \u041F\u041E\u041C\u0415\u0427\u0415\u041D\u0410 \u0417\u041D\u0410\u041A\u041E\u041C, \u0410 \u041D\u0415 \u0421\u041B\u0418\u0422\u0410 \u0421 \u041E\u0421\u0422\u0410\u041B\u042C\u041D\u042B\u041C. \xAB\u0413\u043E\u0442\u043E\u0432\u043E\xBB \u0441 \u0438\u0437\u0432\u0435\u0441\u0442\u043D\u044B\u043C
18526
+ // \u0431\u0440\u0430\u043A\u043E\u043C \u2014 \u044D\u0442\u043E \u043D\u0435 \xAB\u0433\u043E\u0442\u043E\u0432\u043E\xBB: \u0442\u0435\u043C \u0436\u0435 \u0441\u0435\u0440\u044B\u043C \u043A\u0435\u0433\u043B\u0435\u043C, \u0447\u0442\u043E \u0438 \u043F\u043E\u0434\u0441\u043A\u0430\u0437\u043A\u0430, \u0431\u0440\u0430\u043A
18527
+ // \u043F\u0440\u043E\u0447\u0438\u0442\u0430\u044E\u0442 \u043D\u0435 \u0432\u0441\u0435, \u0430 \u0438\u043C\u0435\u043D\u043D\u043E \u0435\u0433\u043E \u0447\u0435\u043B\u043E\u0432\u0435\u043A \u0438 \u0434\u043E\u043B\u0436\u0435\u043D \u0443\u0432\u0438\u0434\u0435\u0442\u044C.
18528
+ var list = data.complaints || [];
18529
+ for (var i = 0; i < list.length; i++) warn.push('\u26A0 ' + list[i]);
18530
+ if (!good && data.advice) warn.push(data.advice);
18531
+ show('warn', warn.join('\\n'));
18532
+
18533
+ byId('end').hidden = false;
18534
+ byId('note').hidden = true;
18544
18535
  }
18545
- const [machine, news, own] = await Promise.all([
18546
- inspectMachine(engine, { model }),
18547
- updateEngine(engine, false, key, baseUrl, NEWS_POINTER_MS, toEngine),
18548
- shell
18549
- ]);
18550
- return card(
18551
- together([newsForModel(shellNews, engineNews), machine.result, news, own]),
18552
- { readiness: machine.readiness, note: firstLine(together([machine.result, news, own])) }
18553
- );
18554
- }
18555
- function newsForModel(shell, engine) {
18556
- if (!shell?.fresh && !engine?.fresh) return toolSuccess("");
18557
- const numbers = [
18558
- engine?.fresh ? `\u0434\u0432\u0438\u0436\u043E\u043A ${engine.installed ?? "\u043D\u0435\u0442"} \u2192 ${engine.fresh}` : "",
18559
- shell?.fresh ? `\u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u0435 ${shell.installed ?? VERSION} \u2192 ${shell.fresh}` : ""
18560
- ].filter((one) => one !== "").join(", ");
18561
- return toolSuccess(
18562
- `\u0414\u043E\u0441\u0442\u0443\u043F\u043D\u0430 \u043D\u043E\u0432\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u043C\u043E\u043D\u0442\u0430\u0436\u0451\u0440\u0430: ${whatIsNew(shell, engine)} (${numbers}). \u0421\u043A\u0430\u0436\u0438 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0443, \u0447\u0442\u043E \u0438\u043C\u0435\u043D\u043D\u043E \u043E\u0431\u043D\u043E\u0432\u0438\u0442\u0441\u044F \u0438 \u0441\u043A\u043E\u043B\u044C\u043A\u043E \u0432\u0435\u0441\u0438\u0442. \xAB\u041E\u0431\u043D\u043E\u0432\u0438\xBB \u2014 \u044D\u0442\u043E \xAB\u0434\u0430\xBB: \u043E\u0434\u0438\u043D \u0432\u044B\u0437\u043E\u0432 setup \u0441 what=all \u0438 consent=true, \u0434\u0430\u043B\u044C\u0448\u0435 wait \u043F\u043E \u043D\u043E\u043C\u0435\u0440\u0443 \u0437\u0430\u0434\u0430\u0447\u0438.`
18563
- );
18564
- }
18565
- function withCard(result, card) {
18566
- if (result.type !== "success" || result.structured !== void 0) return result;
18567
- return toolSuccess(wordsOf(result.content), card());
18568
- }
18569
- function firstLine(result) {
18570
- const text2 = result.type === "success" ? wordsOf(result.content) : result.error;
18571
- return text2.split("\n").map((line) => line.trim()).find((line) => line !== "") ?? "";
18572
- }
18573
- function startUpdate(engine, what, key, baseUrl) {
18574
- const title = engine.place() === null ? TITLE_INSTALL : TITLE_UPDATE;
18575
- const id = startSetupJob(title, (job) => runUpdate(job, {
18576
- engine,
18577
- key,
18578
- baseUrl,
18579
- what,
18580
- pointerMs: ASKED_POINTER_MS,
18581
- installMissing: () => installMissing(engine, key, baseUrl, void 0)
18582
- }), Date.now, engine.home());
18583
- const report = setupJobReport(id, engine.home());
18584
- return toolSuccess(
18585
- `\u0417\u0430\u0434\u0430\u0447\u0430 ${id}: ${report?.what ?? title}.
18586
- \u0418\u0434\u0451\u0442 \u043D\u0430 \u043A\u043E\u043C\u043F\u044C\u044E\u0442\u0435\u0440\u0435 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F: \u043F\u0440\u043E\u0432\u0435\u0440\u044E, \u0447\u0442\u043E \u0432\u044B\u0448\u043B\u043E, \u0441\u043A\u0430\u0447\u0430\u044E \u0438 \u043F\u043E\u0441\u0442\u0430\u0432\u043B\u044E. \u041F\u043E\u043B\u043E\u0441\u0430 \u0443 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430 \u043E\u0431\u043D\u043E\u0432\u043B\u044F\u0435\u0442\u0441\u044F \u0441\u0430\u043C\u0430. \u041F\u043E\u0437\u043E\u0432\u0438 wait \u0441 job "` + id + '" \u2014 \u0434\u043E\u0436\u0434\u0451\u0442\u0441\u044F \u0438 \u0441\u043A\u0430\u0436\u0435\u0442, \u0447\u0435\u043C \u043A\u043E\u043D\u0447\u0438\u043B\u043E\u0441\u044C; setup \u043F\u043E\u0432\u0442\u043E\u0440\u043D\u043E \u043D\u0435 \u0437\u043E\u0432\u0438. \u0413\u043E\u0442\u043E\u0432\u043E \u2014 \u043F\u0435\u0440\u0435\u0441\u043A\u0430\u0436\u0438 \u0441\u0442\u0440\u043E\u043A\u0443 \xAB\u0427\u0435\u043B\u043E\u0432\u0435\u043A\u0443\xBB.',
18587
- report ?? void 0
18588
- );
18589
- }
18590
- async function installMissing(engine, key, baseUrl, tell) {
18591
- const place = engine.place();
18592
- if (place !== null && await engine.pythonTrouble() === null && await nothingMissing(engine, place)) {
18593
- return toolSuccess("\u0412\u0441\u0451 \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u043E\u0435 \u0434\u043B\u044F \u043C\u043E\u043D\u0442\u0430\u0436\u0430 \u043D\u0430 \u043C\u0435\u0441\u0442\u0435 \u2014 \u0441\u0442\u0430\u0432\u0438\u0442\u044C \u043D\u0435\u0447\u0435\u0433\u043E.");
18536
+
18537
+ /** \u041E\u0442\u043A\u0430\u0437 \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u0430: \u0441\u043B\u043E\u0432\u0430 \u0432\u043C\u0435\u0441\u0442\u043E \u043F\u043E\u043B\u043E\u0441\u044B. \u041F\u0443\u0441\u0442\u0430\u044F \u0440\u0430\u043C\u043A\u0430 \u0442\u0443\u0442 \u0441\u0442\u0440\u0430\u0448\u043D\u0435\u0435 \u0431\u0435\u0434\u044B. */
18538
+ function finishWithWords(text) {
18539
+ job = null;
18540
+ document.body.classList.remove('gone');
18541
+ byId('card').hidden = true;
18542
+ byId('dl').hidden = true;
18543
+ byId('now').hidden = true;
18544
+ byId('rail').hidden = true;
18545
+ byId('msg').hidden = true;
18546
+ byId('clock').hidden = true;
18547
+ document.body.classList.add('bad');
18548
+ show('endTitle', '\u041D\u0435 \u043F\u043E\u043B\u0443\u0447\u0438\u043B\u043E\u0441\u044C');
18549
+ show('endHint', text || '\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0443\u0437\u043D\u0430\u0442\u044C, \u0447\u0442\u043E \u0441 \u0440\u0430\u0431\u043E\u0442\u043E\u0439. \u0421\u043F\u0440\u043E\u0441\u0438\u0442\u0435 \u041A\u043B\u043E\u0434\u0430 \u0441\u043B\u043E\u0432\u0430\u043C\u0438.');
18550
+ byId('path').hidden = true;
18551
+ byId('warn').hidden = true;
18552
+ byId('end').hidden = false;
18553
+ byId('note').hidden = true;
18554
+ reportSize();
18594
18555
  }
18595
- return installStep(engine, { step: "all", consent: true }, key, baseUrl, tell);
18596
- }
18597
- async function nothingMissing(engine, place) {
18598
- try {
18599
- await engine.run(place, ["env-check", "--pack", place.pack, "--first-install"]);
18600
- return true;
18601
- } catch {
18602
- return false;
18556
+
18557
+ /**
18558
+ * \u041F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0442\u044C \u043D\u0435\u0447\u0435\u0433\u043E: \u0443\u0431\u0440\u0430\u0442\u044C \u043F\u043E\u043B\u043E\u0441\u0443 \u0441\u043E\u0432\u0441\u0435\u043C \u0438 \u043E\u0442\u0434\u0430\u0442\u044C \u043B\u0435\u043D\u0442\u0435 \u0435\u0451 \u043C\u0435\u0441\u0442\u043E.
18559
+ *
18560
+ * \u26A0 \u041D\u0415 \xAB\u0421\u041A\u0420\u042B\u0422\u042C \u0421\u041E\u0414\u0415\u0420\u0416\u0418\u041C\u041E\u0415\xBB, \u0410 \u0421\u0412\u0415\u0420\u041D\u0423\u0422\u042C \u041E\u041A\u041D\u041E. \u0421\u043F\u0440\u044F\u0442\u0430\u043D\u043D\u044B\u0435 \u0431\u043B\u043E\u043A\u0438 \u0432\u043D\u0443\u0442\u0440\u0438 \u0440\u0430\u043C\u043A\u0438
18561
+ * \u043E\u0441\u0442\u0430\u0432\u043B\u044F\u044E\u0442 \u0432 \u043B\u0435\u043D\u0442\u0435 \u043F\u0443\u0441\u0442\u0443\u044E \u043F\u043B\u0430\u0448\u043A\u0443 \u2014 \u043E\u043D\u0430 \u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044F \u043A\u0430\u043A \u043F\u043E\u043B\u043E\u043C\u043A\u0430 \u043D\u0438\u0447\u0443\u0442\u044C \u043D\u0435
18562
+ * \u043C\u0435\u043D\u044C\u0448\u0435, \u0447\u0435\u043C \u0437\u0430\u0441\u0442\u044B\u0432\u0448\u0435\u0435 \xAB\u041D\u0430\u0447\u0438\u043D\u0430\u044E\u2026\xBB.
18563
+ */
18564
+ function collapse() {
18565
+ job = null;
18566
+ // \u26A0 \u041D\u0415 \u0425\u041E\u0420\u041E\u041D\u0418\u041C \u0412\u0418\u0414\u0416\u0415\u0422, \u0410 \u0422\u041E\u041B\u042C\u041A\u041E \u0423\u0411\u0418\u0420\u0410\u0415\u041C \u0415\u0413\u041E \u0421 \u0413\u041B\u0410\u0417. \u0421\u0442\u0430\u0432\u044C \u043C\u044B \u0437\u0434\u0435\u0441\u044C
18567
+ // \xAB\u0437\u0430\u043A\u0440\u044B\u0442\u043E\xBB, \u043F\u0440\u0438\u0448\u0435\u0434\u0448\u0430\u044F \u0441\u043B\u0435\u0434\u043E\u043C \u043D\u0430\u0441\u0442\u043E\u044F\u0449\u0430\u044F \u0437\u0430\u0434\u0430\u0447\u0430 (\u0445\u043E\u0441\u0442 \u0432\u043F\u0440\u0430\u0432\u0435 \u043F\u0440\u0438\u0441\u043B\u0430\u0442\u044C \u0434\u0432\u0430
18568
+ // \u0443\u0432\u0435\u0434\u043E\u043C\u043B\u0435\u043D\u0438\u044F \u043F\u043E\u0434\u0440\u044F\u0434) \u043E\u0441\u0442\u0430\u043B\u0430\u0441\u044C \u0431\u044B \u0431\u0435\u0437 \u043E\u043F\u0440\u043E\u0441\u0430 \u2014 \u043F\u043E\u043B\u043E\u0441\u0430 \u043F\u043E\u043A\u0430\u0437\u0430\u043B\u0430 \u0431\u044B \u043F\u0435\u0440\u0432\u044B\u0439
18569
+ // \u043A\u0430\u0434\u0440 \u0438 \u0437\u0430\u043C\u0435\u0440\u043B\u0430.
18570
+ var all = ['now', 'rail', 'msg', 'dl', 'card', 'clock', 'end', 'note', 'what'];
18571
+ for (var i = 0; i < all.length; i++) { var el = byId(all[i]); if (el) el.hidden = true; }
18572
+ document.body.classList.add('gone');
18573
+ reportSize();
18603
18574
  }
18604
- }
18605
- async function askBeforeHeavy(engine, step, model, key, baseUrl) {
18606
- const place = engine.place();
18607
- if (place === null) {
18608
- const payload = await installPayload(engine, {
18609
- consent: false,
18610
- manifestUrl: manifestUrl(engine, baseUrl),
18611
- ...key !== void 0 ? { key } : {}
18612
- });
18613
- return toolSuccess(payload.text);
18575
+
18576
+ // \u2500\u2500\u2500 \u043C\u0438\u0440 \u0445\u043E\u0441\u0442\u0430 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
18577
+
18578
+ function applyContext(ctx) {
18579
+ if (!ctx) return;
18580
+ if (ctx.theme === 'dark') document.body.classList.add('dark');
18581
+ else if (ctx.theme === 'light') document.body.classList.remove('dark');
18614
18582
  }
18615
- const noPython = await engine.pythonTrouble();
18616
- if (noPython !== null) return toolSuccess(noPython);
18617
- return asToolResult(await engine.command([
18618
- "env-install",
18619
- "--pack",
18620
- place.pack,
18621
- "--step",
18622
- step,
18623
- ...model !== void 0 ? ["--model", model] : []
18624
- ]));
18625
- }
18626
- function together(results) {
18627
- const text2 = results.map((one) => one.type === "success" ? wordsOf(one.content) : one.error).filter((words) => words !== "").join("\n\n");
18628
- for (const one of results) {
18629
- if (one.type === "success" && one.structured !== void 0) return toolSuccess(text2, one.structured);
18583
+
18584
+ // \u26A0 \u0414\u0410\u041D\u041D\u042B\u0415 \u041F\u0420\u0418\u0425\u041E\u0414\u042F\u0422 \u0422\u041E\u041B\u042C\u041A\u041E \u0418\u0417 structuredContent. \u0412 content \u0445\u043E\u0441\u0442 \u043A\u043B\u0430\u0434\u0451\u0442 \u0444\u0440\u0430\u0437\u0443
18585
+ // \u0434\u043B\u044F \u043C\u043E\u0434\u0435\u043B\u0438 (\xAB\u0417\u0430\u0434\u0430\u0447\u0430 2026-\u2026: \u043C\u043E\u043D\u0442\u0430\u0436\xBB), \u0438 \u0440\u0430\u0437\u0431\u043E\u0440 \u0435\u0451 \u043A\u0430\u043A JSON \u043F\u0430\u0434\u0430\u043B \u0431\u044B \u043C\u043E\u043B\u0447\u0430,
18586
+ // \u043E\u0441\u0442\u0430\u0432\u043B\u044F\u044F \u043F\u043E\u043B\u043E\u0441\u0443 \u043D\u0430 \u0432\u0435\u0447\u043D\u043E\u043C \xAB\u041D\u0430\u0447\u0438\u043D\u0430\u044E\u2026\xBB. \u0422\u0430\u043A \u0443\u0436\u0435 \u0431\u044B\u043B\u043E \u0443 \u0444\u043E\u0440\u043C\u044B \u0432\u044B\u0431\u043E\u0440\u0430.
18587
+ function parse(params) {
18588
+ var data = params && params.structuredContent;
18589
+ if (data && data.contract === CONTRACT) return data;
18590
+ return null;
18630
18591
  }
18631
- return results.some((one) => one.type === "error") ? toolError(text2) : toolSuccess(text2);
18632
- }
18633
- function wordsOf(content) {
18634
- if (typeof content === "string") return content;
18635
- return content.map((block) => block.type === "text" ? block.text : "").join("\n");
18592
+
18593
+ window.addEventListener('message', function (e) {
18594
+ // \u26A0 \u041B\u042E\u0411\u041E\u0419 \u041F\u0420\u0415\u0414\u041E\u041A, \u0410 \u041D\u0415 \u0421\u0422\u0420\u041E\u0413\u041E window.parent: \u0445\u043E\u0441\u0442 \u043F\u043E \u0441\u043F\u0435\u043A\u0435 \u0441\u0442\u0430\u0432\u0438\u0442 \u043C\u0435\u0436\u0434\u0443
18595
+ // \u0441\u043E\u0431\u043E\u0439 \u0438 \u043D\u0430\u043C\u0438 \u043F\u0435\u0441\u043E\u0447\u043D\u0438\u0446\u0443 \u2014 \u043F\u0435\u0440\u0432\u044B\u0439 iframe \u0437\u0430\u0432\u043E\u0434\u0438\u0442 \u0432\u0442\u043E\u0440\u043E\u0439, \u043D\u0430\u0448. \u0421\u043E\u0441\u0435\u0434\u043D\u0435\u0435
18596
+ // \u043E\u043A\u043D\u043E \u0432 \u0442\u043E\u0439 \u0436\u0435 \u043B\u0435\u043D\u0442\u0435 \u043F\u0440\u0438 \u044D\u0442\u043E\u043C \u043E\u0442\u0441\u0435\u0447\u0435\u043D\u043E: \u043E\u043D\u043E \u0440\u043E\u0432\u043D\u044F, \u0430 \u043D\u0435 \u043F\u0440\u0435\u0434\u043E\u043A.
18597
+ if (e.source !== window.parent && e.source !== window.top) return;
18598
+ var m = e.data;
18599
+ if (!m || m.jsonrpc !== '2.0') return;
18600
+ // \u26A0 \u042D\u0422\u041E \u041E\u0422\u0412\u0415\u0422, \u0410 \u041D\u0415 \u0417\u0410\u041F\u0420\u041E\u0421. \u041D\u0443\u043C\u0435\u0440\u0430\u0446\u0438\u044F \u0443 \u0445\u043E\u0441\u0442\u0430 \u0441\u0432\u043E\u044F, \u0442\u043E\u0436\u0435 \u0441 \u0435\u0434\u0438\u043D\u0438\u0446\u044B: \u0435\u0433\u043E
18601
+ // \u0437\u0430\u043F\u0440\u043E\u0441 \u0441 id 1 \u0441\u044A\u0435\u043B \u0431\u044B \u043A\u043E\u043B\u0431\u044D\u043A \u043D\u0430\u0448\u0435\u0433\u043E \u0440\u0443\u043A\u043E\u043F\u043E\u0436\u0430\u0442\u0438\u044F.
18602
+ var answer = m.method === undefined && (m.result !== undefined || m.error !== undefined);
18603
+ if (answer && m.id !== undefined && waiting[m.id]) {
18604
+ var reply = waiting[m.id];
18605
+ delete waiting[m.id];
18606
+ reply(m);
18607
+ return;
18608
+ }
18609
+ if (m.method === 'ui/notifications/tool-result') {
18610
+ if (m.params && m.params.isError) { finishWithWords(words(m.params)); return; }
18611
+ // \u041E\u0442\u0432\u0435\u0442 setup \u0431\u0435\u0437 \u0437\u0430\u0434\u0430\u0447\u0438 \u2014 \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0430 \u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u044F, \u0430 \u043D\u0435 \u0441\u0432\u0451\u0440\u0442\u043A\u0430: \u0440\u0430\u043C\u043A\u0443 \u0445\u043E\u0441\u0442
18612
+ // \u0440\u0438\u0441\u0443\u0435\u0442 \u0432\u0441\u0451 \u0440\u0430\u0432\u043D\u043E, \u0438 \u0441\u0432\u0451\u0440\u043D\u0443\u0442\u0430\u044F \u043F\u043E\u043B\u043E\u0441\u0430 \u043E\u0441\u0442\u0430\u0432\u043B\u044F\u043B\u0430 \u0431\u044B \u043F\u0443\u0441\u0442\u0443\u044E \u043F\u043B\u0430\u0448\u043A\u0443.
18613
+ var card = m.params && m.params.structuredContent;
18614
+ if (card && card.contract === SETUP) { renderCard(card); return; }
18615
+ var data = parse(m.params);
18616
+ // \u26A0 \u041E\u0422\u0412\u0415\u0422 \u0411\u0415\u0417 \u0417\u0410\u0414\u0410\u0427\u0418 \u0418 \u0411\u0415\u0417 \u041A\u0410\u0420\u0422\u041E\u0427\u041A\u0418 \u2014 \u0421\u0412\u041E\u0420\u0410\u0427\u0418\u0412\u0410\u0415\u041C\u0421\u042F, \u0410 \u041D\u0415 \u0412\u0418\u0421\u0418\u041C \u041D\u0410
18617
+ // \u0417\u0410\u0413\u041B\u0423\u0428\u041A\u0415. \u0423 setup \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0430 \u0435\u0441\u0442\u044C \u0432\u0441\u0435\u0433\u0434\u0430 (\u0432\u044B\u0448\u0435, 2026-09-24): \u0441\u0432\u0451\u0440\u0442\u043A\u0443
18618
+ // Claude Desktop \u043D\u0435 \u0443\u0431\u0438\u0440\u0430\u0435\u0442, \u0438 \u0442\u0430\u043C \u043E\u0441\u0442\u0430\u0432\u0430\u043B\u0430\u0441\u044C \u043F\u0443\u0441\u0442\u0430\u044F \u0440\u0430\u043C\u043A\u0430. \u0417\u0434\u0435\u0441\u044C
18619
+ // \u043E\u0441\u0442\u0430\u043B\u0438\u0441\u044C \u0447\u0443\u0436\u0438\u0435 \u043E\u0442\u0432\u0435\u0442\u044B \u0431\u0435\u0437 \u0440\u0430\u0431\u043E\u0442\u044B \u2014 plan \u0431\u0435\u0437 \u0432\u0438\u0434\u0435\u043E (docs/plan/README.md,
18620
+ // \u0438\u0437\u0432\u0435\u0441\u0442\u043D\u044B\u0439 \u0431\u0440\u0430\u043A). \u041F\u043E\u043B\u043E\u0441\u0430
18621
+ // \u043E\u0431\u044A\u044F\u0432\u043B\u0435\u043D\u0430 \u0443 \u0412\u0421\u0415\u0413\u041E \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u0430, \u0430 \u043D\u0435 \u0443 \u043E\u0442\u0434\u0435\u043B\u044C\u043D\u043E\u0433\u043E \u043E\u0442\u0432\u0435\u0442\u0430, \u0438 \u0445\u043E\u0441\u0442 \u0440\u0438\u0441\u0443\u0435\u0442
18622
+ // \u0435\u0451 \u043D\u0430 \u043A\u0430\u0436\u0434\u043E\u043C \u0432\u044B\u0437\u043E\u0432\u0435 \u2014 \u0432 \u0442\u043E\u043C \u0447\u0438\u0441\u043B\u0435 \u043D\u0430 \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0435 setup \u0431\u0435\u0437 \u0430\u0440\u0433\u0443\u043C\u0435\u043D\u0442\u043E\u0432,
18623
+ // \u0433\u0434\u0435 \u043D\u0438\u043A\u0430\u043A\u043E\u0439 \u0440\u0430\u0431\u043E\u0442\u044B \u043D\u0435\u0442 \u0438 \u043D\u043E\u043C\u0435\u0440\u0430 \u0437\u0430\u0434\u0430\u0447\u0438 \u0432 \u043E\u0442\u0432\u0435\u0442\u0435 \u0442\u043E\u0436\u0435. \u0420\u0430\u043D\u044C\u0448\u0435 \u0437\u0434\u0435\u0441\u044C
18624
+ // \u0441\u0442\u043E\u044F\u043B \u043F\u0443\u0441\u0442\u043E\u0439 \u0432\u044B\u0445\u043E\u0434, \u0438
18625
+ // \u0447\u0435\u043B\u043E\u0432\u0435\u043A \u043F\u043E\u043B\u0443\u0447\u0430\u043B \u0432\u0435\u0447\u043D\u043E\u0435 \xAB\u0420\u0430\u0431\u043E\u0442\u0430\u044E \u2014 \u041D\u0430\u0447\u0438\u043D\u0430\u044E\u2026\xBB \u043F\u043E\u0434 \u043E\u0442\u0432\u0435\u0442\u043E\u043C \xAB\u0432\u0441\u0451 \u043D\u0430 \u043C\u0435\u0441\u0442\u0435\xBB.
18626
+ // \u0412\u043B\u0430\u0434\u0435\u043B\u0435\u0446 2026-09-20: \xAB\u043F\u043E\u0447\u0435\u043C\u0443 \u0442\u0443\u0442 \u0442\u043E\u043B\u044C\u043A\u043E \u0440\u0430\u0431\u043E\u0442\u0430\u044E \u2014 \u043D\u0430\u0447\u0438\u043D\u0430\u044E?\xBB \u0421\u043B\u043E\u0432\u0430
18627
+ // \u043E\u0442\u0432\u0435\u0442\u0430 \u0445\u043E\u0441\u0442 \u043F\u0435\u0447\u0430\u0442\u0430\u0435\u0442 \u0440\u044F\u0434\u043E\u043C \u0441\u0430\u043C, \u043F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0442\u044C \u043D\u0430\u043C \u043D\u0435\u0447\u0435\u0433\u043E \u2014 \u0443\u0445\u043E\u0434\u0438\u043C \u0441 \u0433\u043B\u0430\u0437.
18628
+ if (!data) { collapse(); return; }
18629
+ render(data);
18630
+ later();
18631
+ return;
18632
+ }
18633
+ if (m.method === 'ui/notifications/host-context-changed') { applyContext(m.params); return; }
18634
+ // \u26A0 \u0412\u0418\u0414\u0416\u0415\u0422 \u0417\u0410\u041A\u0420\u042B\u041B\u0418 \u2014 \u0422\u0410\u0419\u041C\u0415\u0420 \u041E\u0411\u042F\u0417\u0410\u041D \u0423\u041C\u0415\u0420\u0415\u0422\u042C. \u0418\u043D\u0430\u0447\u0435 \u043E\u043D \u0437\u0430\u043F\u0443\u0441\u043A\u0430\u0435\u0442 \u043F\u0438\u0442\u043E\u043D \u043D\u0430
18635
+ // \u043C\u0430\u0448\u0438\u043D\u0435 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430 \u043A\u0430\u0436\u0434\u044B\u0435 \u0434\u0432\u0435 \u0441 \u043F\u043E\u043B\u043E\u0432\u0438\u043D\u043E\u0439 \u0441\u0435\u043A\u0443\u043D\u0434\u044B \u0434\u043E \u043A\u043E\u043D\u0446\u0430 \u0434\u043D\u044F, \u0430 \u043F\u043E\u043A\u0430\u0437\u0430\u0442\u044C
18636
+ // \u0440\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442 \u0443\u0436\u0435 \u043D\u0435\u043A\u0443\u0434\u0430: \u043E\u043A\u043D\u0430 \u043D\u0435\u0442.
18637
+ if (m.method === 'ui/resource-teardown') { closed = true; job = null; return; }
18638
+ });
18639
+
18640
+ // \u26A0 \u0412\u042B\u0421\u041E\u0422\u0423 \u0421\u041E\u041E\u0411\u0429\u0410\u0415\u041C \u0421\u0420\u0410\u0417\u0423, \u0414\u041E \u0412\u0421\u042F\u041A\u0418\u0425 \u0414\u0410\u041D\u041D\u042B\u0425. \u041F\u043E\u043A\u0430 \u044D\u0442\u043E \u0434\u0435\u043B\u0430\u043B\u043E\u0441\u044C \u0442\u043E\u043B\u044C\u043A\u043E \u043F\u0440\u0438
18641
+ // \u043E\u0442\u0440\u0438\u0441\u043E\u0432\u043A\u0435, \u0437\u0430\u043C\u0438\u043D\u043A\u0430 \u0441 \u0434\u0430\u043D\u043D\u044B\u043C\u0438 \u0432\u044B\u0433\u043B\u044F\u0434\u0435\u043B\u0430 \u043A\u0430\u043A \u043F\u0443\u0441\u0442\u043E\u0439 \u0431\u043B\u043E\u043A \u0432 \u043B\u0435\u043D\u0442\u0435: \u0440\u0430\u0437\u043C\u0435\u0442\u043A\u0430
18642
+ // \u0435\u0441\u0442\u044C, \u0430 \u043F\u043E\u043A\u0430\u0437\u0430\u0442\u044C \u0435\u0451 \u043D\u0435\u0433\u0434\u0435 \u2014 \u0443 \u043E\u043A\u043D\u0430 \u043D\u0443\u043B\u0435\u0432\u0430\u044F \u0432\u044B\u0441\u043E\u0442\u0430.
18643
+ reportSize();
18644
+ // \u26A0 \u041E\u0411\u0410 \u0418\u041C\u0415\u041D\u0418 \u0421\u0420\u0410\u0417\u0423, \u0418 \u042D\u0422\u041E \u041D\u0415 \u041F\u0415\u0420\u0415\u0421\u0422\u0420\u0410\u0425\u041E\u0412\u041A\u0410. \u0416\u0438\u0432\u043E\u0439 Claude Desktop \u043E\u0442\u043A\u0430\u0437\u044B\u0432\u0430\u0435\u0442
18645
+ // \u0432 \u0440\u0443\u043A\u043E\u043F\u043E\u0436\u0430\u0442\u0438\u0438 \u0431\u0435\u0437 appInfo (\xABexpected object, received undefined\xBB \u043F\u043E \u043F\u0443\u0442\u0438
18646
+ // params.appInfo), \u0430 \u0441\u043F\u0435\u043A\u0430 2026-01-26 \u043D\u0430\u0437\u044B\u0432\u0430\u0435\u0442 \u044D\u0442\u043E \u043F\u043E\u043B\u0435 clientInfo. \u0423\u0431\u0435\u0440\u0438
18647
+ // \u043B\u044E\u0431\u043E\u0435 \u2014 \u0432\u0438\u0434\u0436\u0435\u0442 \u043F\u0435\u0440\u0435\u0441\u0442\u0430\u043D\u0435\u0442 \u0440\u0430\u0431\u043E\u0442\u0430\u0442\u044C \u043B\u0438\u0431\u043E \u0441\u0435\u0433\u043E\u0434\u043D\u044F, \u043B\u0438\u0431\u043E \u043D\u0430 \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0435\u043C \u0445\u043E\u0441\u0442\u0435.
18648
+ send('ui/initialize', {
18649
+ protocolVersion: '2026-01-26',
18650
+ capabilities: {},
18651
+ appInfo: { name: 'naparnik-runbar', version: '${VERSION}' },
18652
+ clientInfo: { name: 'naparnik-runbar', version: '${VERSION}' },
18653
+ appCapabilities: { availableDisplayModes: ['inline'] }
18654
+ }, function (m) {
18655
+ if (m.error) { show('note', '\u0425\u043E\u0441\u0442 \u043E\u0442\u043A\u0430\u0437\u0430\u043B \u0432 \u0440\u0443\u043A\u043E\u043F\u043E\u0436\u0430\u0442\u0438\u0438: ' + ((m.error && m.error.message) || '')); reportSize(); return; }
18656
+ applyContext(m.result && m.result.hostContext);
18657
+ notify('ui/notifications/initialized', {});
18658
+ });
18659
+ })();
18660
+ </script>
18661
+ </body>
18662
+ </html>`;
18636
18663
  }
18637
18664
  var TRIAL_AXES = ["motion", "timing", "place", "camera", "color"];
18638
18665
  var TRIALS_MAX = 10;