@naparnik/mcp 0.10.25 → 0.10.40

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.
@@ -226,8 +226,8 @@ var StdioServerTransport = class {
226
226
  function toolSuccess(content, structured) {
227
227
  return { type: "success", content, ...structured !== void 0 ? { structured } : {} };
228
228
  }
229
- function toolMixed(blocks) {
230
- return { type: "success", content: blocks };
229
+ function toolMixed(blocks, structured) {
230
+ return { type: "success", content: blocks, ...structured !== void 0 ? { structured } : {} };
231
231
  }
232
232
  function toolError(error40, code) {
233
233
  return { type: "error", error: error40 };
@@ -727,9 +727,9 @@ function parsePositiveInt(raw, fallback) {
727
727
  }
728
728
 
729
729
  // src/version.ts
730
- var VERSION = "0.10.25";
730
+ var VERSION = "0.10.40";
731
731
  var USER_AGENT = `naparnik-mcp/${VERSION}`;
732
- var MIN_ENGINE = "2026.09.23-406";
732
+ var MIN_ENGINE = "2026.09.24-446";
733
733
  var LAUNCHER_PROTOCOL = 1;
734
734
 
735
735
  // src/contracts/sdk-headers.ts
@@ -1867,8 +1867,7 @@ function parseFailure(err, fallback) {
1867
1867
  return { ok: false, text: mine !== "" ? mine : e?.message ?? fallback };
1868
1868
  }
1869
1869
  function details(err) {
1870
- const e = err;
1871
- return [e?.stdout, e?.stderr, e?.message].filter(Boolean).join("\n").trim();
1870
+ return parseFailure(err, "").text.trim();
1872
1871
  }
1873
1872
  function lastLine(output) {
1874
1873
  const lines = output.trim().split("\n");
@@ -13779,7 +13778,7 @@ async function askPointer(opts) {
13779
13778
  ...key !== void 0 ? { headers: { authorization: `Bearer ${key}` } } : {}
13780
13779
  });
13781
13780
  if (!response.ok) {
13782
- return { ok: false, why: `\u0440\u0430\u0437\u0434\u0430\u0447\u0430 \u043E\u0442\u0432\u0435\u0442\u0438\u043B\u0430 ${response.status} \u2014 ${what} \u043D\u0435 \u043E\u0442\u0434\u0430\u043D` };
13781
+ return { ok: false, why: `\u0440\u0430\u0437\u0434\u0430\u0447\u0430 \u043E\u0442\u0432\u0435\u0442\u0438\u043B\u0430 ${response.status} \u2014 ${what} \u043D\u0435 \u043E\u0442\u0434\u0430\u043D`, status: response.status };
13783
13782
  }
13784
13783
  const type = (response.headers.get("content-type") ?? "").toLowerCase();
13785
13784
  if (!type.includes("json")) {
@@ -14108,12 +14107,20 @@ function blockCandidate(dir, candidate, text2) {
14108
14107
  };
14109
14108
  }
14110
14109
  writeCandidate(dir, { ...candidate, state: "blocked" });
14110
+ const lead = candidate.baseCurrent === null ? `\u0412\u0435\u0440\u0441\u0438\u044F ${candidate.version} \u043D\u0435 \u0432\u0441\u0442\u0430\u043B\u0430.` : `\u041D\u043E\u0432\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F ${candidate.version} \u043D\u0435 \u0432\u0441\u0442\u0430\u043B\u0430 \u2014 \u0440\u0430\u0431\u043E\u0442\u0430\u0435\u0442 \u043F\u0440\u0435\u0436\u043D\u044F\u044F ${candidate.baseCurrent}, \u043C\u043E\u043D\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u043C\u043E\u0436\u043D\u043E.`;
14111
14111
  return {
14112
14112
  ok: false,
14113
- text: text2.includes("\u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C:") ? text2 : `${text2}
14114
- \u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C: \u0438\u0441\u043F\u0440\u0430\u0432\u044C\u0442\u0435 \u0443\u043A\u0430\u0437\u0430\u043D\u043D\u0443\u044E \u043F\u0440\u0438\u0447\u0438\u043D\u0443 \u0438 \u043F\u043E\u0432\u0442\u043E\u0440\u0438\u0442\u0435 setup.`
14113
+ text: text2.includes("\u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C:") ? `${lead}
14114
+ ${text2}` : `${lead}
14115
+ ${text2}
14116
+ \u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C: \u043F\u043E\u0432\u0442\u043E\u0440\u0438 setup \u043F\u043E\u0437\u0436\u0435 \u2014 \u0441\u0432\u044F\u0437\u044C \u043C\u043E\u0433\u043B\u0430 \u043E\u0431\u043E\u0440\u0432\u0430\u0442\u044C\u0441\u044F. \u041E\u0442\u043A\u0430\u0436\u0435\u0442 \u0442\u0435\u043C \u0436\u0435 \u2014 \u044D\u0442\u0430 \u0432\u0435\u0440\u0441\u0438\u044F \u0441\u043B\u043E\u043C\u0430\u043D\u0430: \u043C\u043E\u043D\u0442\u0438\u0440\u0443\u0439 \u043D\u0430 \u043F\u0440\u0435\u0436\u043D\u0435\u0439 \u0438 \u0434\u043E\u0436\u0434\u0438\u0441\u044C \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0435\u0439.`
14115
14117
  };
14116
14118
  }
14119
+ function commandWords(trouble) {
14120
+ const text2 = parseFailure(trouble, describeFailure(trouble)).text;
14121
+ if (!text2.includes("Traceback (most recent call last):")) return text2;
14122
+ return lastLine(text2);
14123
+ }
14117
14124
  function sameCandidateState(actual, expected) {
14118
14125
  if (actual === null) return false;
14119
14126
  const samePayload = actual.payload === void 0 && expected.payload === void 0 || actual.payload !== void 0 && expected.payload !== void 0 && samePayloadProof(actual.payload, expected.payload);
@@ -14297,7 +14304,7 @@ async function activatePreparedCandidateLocked(engine, manifest, trial, extras =
14297
14304
  if (installedVenvTrouble !== null) throw new Error(installedVenvTrouble);
14298
14305
  } catch (trouble) {
14299
14306
  return blockCandidate(dir, candidate, `\u041E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u0435 \u043A\u0430\u043D\u0434\u0438\u0434\u0430\u0442\u0430 \u043D\u0435 \u0433\u043E\u0442\u043E\u0432\u043E \u2014 current \u043D\u0435 \u043C\u0435\u043D\u044F\u043B.
14300
- ${describeFailure(trouble)}`);
14307
+ ${commandWords(trouble)}`);
14301
14308
  }
14302
14309
  }
14303
14310
  const python = engine.candidatePython(place);
@@ -14341,7 +14348,7 @@ ${smoke}`);
14341
14348
  dir,
14342
14349
  candidate,
14343
14350
  `\u041E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u0430\u044F \u0441\u0440\u0435\u0434\u0430 \u043A\u0430\u043D\u0434\u0438\u0434\u0430\u0442\u0430 \u043D\u0435 \u0433\u043E\u0442\u043E\u0432\u0430 \u2014 current \u0438 \u043E\u0431\u0449\u0438\u0435 \u0440\u0430\u0431\u043E\u0447\u0438\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u044B \u043D\u0435 \u043C\u0435\u043D\u044F\u043B.
14344
- ${describeFailure(trouble)}`
14351
+ ${commandWords(trouble)}`
14345
14352
  );
14346
14353
  }
14347
14354
  const firstCompatibility = await compatibilityProof(engine, dir, candidate.version, python, place);
@@ -15616,38 +15623,6 @@ function retell(state, told, tell) {
15616
15623
  if (tell === void 0) return;
15617
15624
  for (const line of freshLines(state.text, told)) tell(line);
15618
15625
  }
15619
- var STAGE_WORDS = {
15620
- silence: "\u0443\u0431\u0435\u0440\u0443 \u043F\u0430\u0443\u0437\u044B",
15621
- voice: "\u0432\u044B\u0440\u043E\u0432\u043D\u044F\u044E \u0433\u043E\u043B\u043E\u0441",
15622
- speech: "\u0440\u0430\u0441\u043F\u043E\u0437\u043D\u0430\u044E \u0440\u0435\u0447\u044C",
15623
- phrases: "\u0440\u0430\u0437\u043B\u043E\u0436\u0443 \u0440\u0435\u0447\u044C \u043D\u0430 \u0444\u0440\u0430\u0437\u044B",
15624
- plan: "\u043F\u0440\u0438\u0434\u0443\u043C\u0430\u044E, \u0447\u0442\u043E \u043F\u043E\u043A\u0430\u0437\u0430\u0442\u044C \u0438 \u043A\u043E\u0433\u0434\u0430",
15625
- world: "\u043D\u0430\u0440\u0438\u0441\u0443\u044E \u0444\u043E\u043D \u0437\u0430 \u0433\u0435\u0440\u043E\u0435\u043C",
15626
- cutout: "\u043E\u0442\u0434\u0435\u043B\u044E \u0433\u0435\u0440\u043E\u044F \u043E\u0442 \u0444\u043E\u043D\u0430",
15627
- "hero-on-world": "\u043F\u043E\u0441\u0442\u0430\u0432\u043B\u044E \u0433\u0435\u0440\u043E\u044F \u043D\u0430 \u0444\u043E\u043D",
15628
- shots: "\u0440\u0430\u0441\u0441\u0442\u0430\u0432\u043B\u044E \u043A\u0440\u0443\u043F\u043D\u043E\u0441\u0442\u0438 \u043F\u043E \u043F\u043B\u0430\u043D\u0443",
15629
- screen: "\u0432\u0441\u0442\u0430\u0432\u043B\u044E \u0437\u0430\u043F\u0438\u0441\u044C \u044D\u043A\u0440\u0430\u043D\u0430",
15630
- inserts: "\u043D\u0430\u0440\u0438\u0441\u0443\u044E \u0433\u0440\u0430\u0444\u0438\u043A\u0443 \u043F\u043E \u043F\u043B\u0430\u043D\u0443",
15631
- subtitles: "\u043D\u0430\u0440\u0438\u0441\u0443\u044E \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u044B",
15632
- layers: "\u043F\u043E\u043B\u043E\u0436\u0443 \u043A\u0430\u0440\u0442\u0438\u043D\u043A\u0438 \u043F\u043E\u0432\u0435\u0440\u0445",
15633
- accents: "\u0440\u0430\u0441\u0441\u0442\u0430\u0432\u043B\u044E \u0437\u0432\u0443\u043A\u043E\u0432\u044B\u0435 \u0430\u043A\u0446\u0435\u043D\u0442\u044B",
15634
- mix: "\u0441\u0432\u0435\u0434\u0443 \u0437\u0432\u0443\u043A",
15635
- intro: "\u043F\u043E\u0441\u0442\u0430\u0432\u043B\u044E \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0443 \u0432 \u043D\u0430\u0447\u0430\u043B\u043E"
15636
- };
15637
- var NEAR_STEPS = 3;
15638
- function montageLadder(stages) {
15639
- const words = stages.map((stage) => STAGE_WORDS[stage]).filter((word) => word !== void 0);
15640
- if (words.length === 0) return [];
15641
- const near = words.slice(0, NEAR_STEPS);
15642
- const far = words.slice(NEAR_STEPS);
15643
- const lines = [`\u0421\u043D\u0430\u0447\u0430\u043B\u0430 ${near.join(", \u043F\u043E\u0442\u043E\u043C ")}.`];
15644
- if (far.length > 0) {
15645
- lines.push(
15646
- `\u0414\u0430\u043B\u044C\u0448\u0435: ${far.join(", ")}. \u0428\u0430\u0433\u043E\u0432 \u0432\u0441\u0435\u0433\u043E \u0434\u043E ${stages.length} \u2014 \u0447\u0442\u043E \u043D\u0435 \u043F\u043E\u043D\u0430\u0434\u043E\u0431\u0438\u0442\u0441\u044F, \u043F\u0440\u043E\u043F\u0443\u0449\u0443.`
15647
- );
15648
- }
15649
- return lines;
15650
- }
15651
15626
  var PAUSES_LADDER = [
15652
15627
  "\u0423\u0431\u0435\u0440\u0443 \u043C\u043E\u043B\u0447\u0430\u043D\u0438\u0435 \u0438 \u0437\u0430\u043F\u0438\u043D\u043A\u0438 \u2014 \u0431\u043E\u043B\u044C\u0448\u0435 \u043D\u0438\u0447\u0435\u0433\u043E \u043D\u0435 \u0442\u0440\u043E\u0433\u0430\u044E.",
15653
15628
  "\u0421\u0443\u0431\u0442\u0438\u0442\u0440\u044B, \u043A\u0430\u0440\u0442\u0438\u043D\u043A\u0438 \u043F\u043E\u0432\u0435\u0440\u0445 \u0438 \u0437\u0432\u0443\u043A \u2014 \u044D\u0442\u043E \u043E\u0442\u0434\u0435\u043B\u044C\u043D\u0430\u044F \u0440\u0430\u0431\u043E\u0442\u0430, \u0435\u0451 \u0437\u0434\u0435\u0441\u044C \u043D\u0435\u0442."
@@ -15848,6 +15823,10 @@ function empty() {
15848
15823
  behind: "",
15849
15824
  ahead: "",
15850
15825
  message: "",
15826
+ got: 0,
15827
+ of: 0,
15828
+ percent: 0,
15829
+ eta: "",
15851
15830
  file: "",
15852
15831
  outcome: "",
15853
15832
  trouble: "",
@@ -15874,6 +15853,7 @@ var RUNNING = /^Ещё считает, (\d+(?:[.,]\d+)?) с\.$/;
15874
15853
  var COMPLAINT = /^⚠ (.+)$/;
15875
15854
  var PLAN_HEAD = /^План:$/;
15876
15855
  var PLAN_ROW = /^· (.+)$/;
15856
+ var DOWNLOAD = /^Скачано (\d+) МБ(?: из (\d+) \((\d+)%\)(?:, (.+))?)?$/;
15877
15857
  var STYLE = /^Стиль: /;
15878
15858
  var LEFT_TAIL = /\.\s+(Осталось .+)$/;
15879
15859
  function readJob(text2) {
@@ -15980,6 +15960,13 @@ function readJob(text2) {
15980
15960
  }
15981
15961
  if (job.status === "running" || job.status === "waiting") job.message = line;
15982
15962
  }
15963
+ const download = job.status === "running" ? DOWNLOAD.exec(job.message) : null;
15964
+ if (download !== null) {
15965
+ job.got = Number(download[1]);
15966
+ job.of = Number(download[2] ?? 0);
15967
+ job.percent = Math.min(100, Number(download[3] ?? 0));
15968
+ job.eta = download[4] ?? "";
15969
+ }
15983
15970
  return job;
15984
15971
  }
15985
15972
  function seconds(text2) {
@@ -16357,7 +16344,7 @@ function pythonCrash(text2) {
16357
16344
  if (/(?:^|\.)(?:KeyboardInterrupt|SystemExit|Explained|Refusal)$/.test(errorType)) return null;
16358
16345
  const message = [m[2] ?? "", ...lines.slice(at + 1)].join("\n").trim();
16359
16346
  const innermost = frames[frames.length - 1];
16360
- const firstLine = message.split("\n")[0] ?? "";
16347
+ const firstLine2 = message.split("\n")[0] ?? "";
16361
16348
  return {
16362
16349
  errorType,
16363
16350
  message,
@@ -16365,7 +16352,7 @@ function pythonCrash(text2) {
16365
16352
  keep: "tail",
16366
16353
  frames: frames.slice(-3).map((f) => `${basename(f.file.replace(/\\/g, "/"))}:${f.func}`),
16367
16354
  python: pythonVersionIn(frames.map((f) => f.file)),
16368
- essence: `${errorType}${firstLine === "" ? "" : `: ${firstLine}`}` + (innermost ? ` \u2014 ${basename(innermost.file.replace(/\\/g, "/"))}:${innermost.line}` : "")
16355
+ essence: `${errorType}${firstLine2 === "" ? "" : `: ${firstLine2}`}` + (innermost ? ` \u2014 ${basename(innermost.file.replace(/\\/g, "/"))}:${innermost.line}` : "")
16369
16356
  };
16370
16357
  }
16371
16358
  function pythonVersionIn(files) {
@@ -16465,6 +16452,91 @@ function tail(text2, max) {
16465
16452
  function orNull(value, max) {
16466
16453
  return value === null || value === "" ? null : head(value, max);
16467
16454
  }
16455
+ var SETUP_CONTRACT = "naparnik-setup/1";
16456
+ var READINESS_CONTRACT = "naparnik-readiness/1";
16457
+ var JSON_CHECK = "--json";
16458
+ function knowsJsonCheck(engineDir) {
16459
+ try {
16460
+ const contract = JSON.parse(readFileSync(join(engineDir, "shell-contract.json"), "utf8"));
16461
+ const flags = contract.env_check_flags;
16462
+ return Array.isArray(flags) && flags.includes(JSON_CHECK);
16463
+ } catch {
16464
+ return false;
16465
+ }
16466
+ }
16467
+ function readReadiness(stdout) {
16468
+ const lines = stdout.trim().split("\n");
16469
+ let raw;
16470
+ try {
16471
+ raw = JSON.parse(lines[lines.length - 1] ?? "");
16472
+ } catch {
16473
+ return null;
16474
+ }
16475
+ const data = raw;
16476
+ if (data === null || typeof data !== "object" || data["contract"] !== READINESS_CONTRACT) return null;
16477
+ if (typeof data["words"] !== "string" || !Array.isArray(data["parts"])) return null;
16478
+ const parts = [];
16479
+ for (const item of data["parts"]) {
16480
+ const part = item;
16481
+ if (part === null || typeof part !== "object" || typeof part["name"] !== "string") continue;
16482
+ parts.push({
16483
+ name: part["name"],
16484
+ title: typeof part["title"] === "string" && part["title"] !== "" ? part["title"] : part["name"],
16485
+ ok: part["ok"] === true,
16486
+ mb: typeof part["mb"] === "number" && part["mb"] > 0 ? Math.round(part["mb"]) : 0,
16487
+ on_demand: part["on_demand"] === true,
16488
+ step: typeof part["step"] === "string" ? part["step"] : ""
16489
+ });
16490
+ }
16491
+ return { words: data["words"], ready: data["ready"] === true, parts };
16492
+ }
16493
+ var NOT_A_ROW = /* @__PURE__ */ new Set(["system"]);
16494
+ function weight(mb) {
16495
+ if (mb >= 1e3) return `${(mb / 1024).toFixed(1).replace(".", ",")} \u0413\u0411`;
16496
+ return `${mb} \u041C\u0411`;
16497
+ }
16498
+ function refusalWords(status) {
16499
+ if (status === 401) {
16500
+ return `\u041A\u043B\u044E\u0447 \u043F\u043E\u0434\u043F\u0438\u0441\u043A\u0438 \u043D\u0435 \u043F\u0440\u0438\u043D\u044F\u0442 \u2014 \u043D\u043E\u0432\u044B\u0435 \u0432\u0435\u0440\u0441\u0438\u0438 \u043D\u0435 \u043F\u0440\u043E\u0432\u0435\u0440\u0438\u0442\u044C. \u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C: \u043D\u0430\u043F\u0438\u0448\u0438\u0442\u0435 \u0431\u043E\u0442\u0443 ${KEY_SOURCE_BOT} \xAB\u041F\u043E\u043B\u0443\u0447\u0438\u0442\u044C \u043A\u043B\u044E\u0447\xBB.`;
16501
+ }
16502
+ if (status === 403) {
16503
+ return `\u041F\u043E\u0434\u043F\u0438\u0441\u043A\u0430 \u043A\u043E\u043D\u0447\u0438\u043B\u0430\u0441\u044C \u2014 \u043D\u043E\u0432\u044B\u0435 \u0432\u0435\u0440\u0441\u0438\u0438 \u043D\u0435 \u043F\u0440\u0438\u0445\u043E\u0434\u044F\u0442. \u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C: \u043F\u0440\u043E\u0434\u043B\u0438\u0442\u0435 \u0435\u0451 \u0443 \u0431\u043E\u0442\u0430 ${KEY_SOURCE_BOT}.`;
16504
+ }
16505
+ return "";
16506
+ }
16507
+ function setupCard(o) {
16508
+ const rows = (o.readiness?.parts ?? []).filter((part) => !NOT_A_ROW.has(part.name)).map((part) => ({
16509
+ title: part.title,
16510
+ state: part.ok ? "ok" : part.on_demand ? "later" : "missing",
16511
+ mb: part.ok ? 0 : part.mb
16512
+ }));
16513
+ const missingMb = rows.filter((row) => row.state === "missing").reduce((all, row) => all + row.mb, 0);
16514
+ const ready = o.readiness?.ready === true;
16515
+ const fresh = [];
16516
+ if (o.shell?.fresh) fresh.push(`\u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u0435 ${o.shell.fresh}${o.shell.mb ? ` (${weight(o.shell.mb)})` : ""}`);
16517
+ if (o.engine?.fresh) fresh.push(`\u0434\u0432\u0438\u0436\u043E\u043A ${o.engine.fresh}${o.engine.mb ? ` (${weight(o.engine.mb)})` : ""}`);
16518
+ const update = fresh.length ? `\u0412\u044B\u0448\u043B\u043E \u043D\u043E\u0432\u043E\u0435: ${fresh.join(", ")}.` : "";
16519
+ const trouble = refusalWords(o.shell?.status ?? 0) || refusalWords(o.engine?.status ?? 0);
16520
+ let next;
16521
+ if (o.noEngine) next = "\u0414\u0432\u0438\u0436\u043A\u0430 \u043C\u043E\u043D\u0442\u0430\u0436\u0430 \u0435\u0449\u0451 \u043D\u0435\u0442. \u0421\u043A\u0430\u0436\u0438\u0442\u0435 \xAB\u043F\u043E\u0441\u0442\u0430\u0432\u044C\xBB \u2014 \u043E\u043D \u0441\u043A\u0430\u0447\u0430\u0435\u0442\u0441\u044F \u043F\u043E\u0441\u043B\u0435 \u0432\u0430\u0448\u0435\u0433\u043E \xAB\u0434\u0430\xBB.";
16522
+ else if (o.noPython) next = "\u041D\u0443\u0436\u0435\u043D Python. \u0421\u043A\u0430\u0436\u0438\u0442\u0435 \xAB\u043F\u043E\u0441\u0442\u0430\u0432\u044C\xBB \u2014 \u043E\u043D \u0441\u043A\u0430\u0447\u0430\u0435\u0442\u0441\u044F \u043F\u043E\u0441\u043B\u0435 \u0432\u0430\u0448\u0435\u0433\u043E \xAB\u0434\u0430\xBB.";
16523
+ else if (o.readiness === null) next = o.note ?? "";
16524
+ else if (!ready) {
16525
+ next = `\u0414\u043B\u044F \u043C\u043E\u043D\u0442\u0430\u0436\u0430 \u043D\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442${missingMb ? ` ${weight(missingMb)}` : " \u0447\u0430\u0441\u0442\u0438"}. \u0421\u043A\u0430\u0436\u0438\u0442\u0435 \xAB\u043F\u043E\u0441\u0442\u0430\u0432\u044C\xBB \u2014 \u0434\u043E\u043A\u0430\u0447\u0430\u0435\u0442\u0441\u044F \u043F\u043E\u0441\u043B\u0435 \u0432\u0430\u0448\u0435\u0433\u043E \xAB\u0434\u0430\xBB.`;
16526
+ } else if (update !== "") next = "\u041C\u043E\u0436\u043D\u043E \u043C\u043E\u043D\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C. \u0421\u043A\u0430\u0436\u0438\u0442\u0435 \xAB\u043E\u0431\u043D\u043E\u0432\u0438\xBB \u2014 \u043D\u043E\u0432\u043E\u0435 \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.";
16527
+ else next = "\u0412\u0441\u0451 \u043D\u0430 \u043C\u0435\u0441\u0442\u0435 \u2014 \u043C\u043E\u0436\u043D\u043E \u043C\u043E\u043D\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C.";
16528
+ return {
16529
+ contract: SETUP_CONTRACT,
16530
+ engine: o.engine?.installed ?? "",
16531
+ shell: o.shellVersion,
16532
+ ready,
16533
+ rows,
16534
+ missingMb,
16535
+ update,
16536
+ trouble,
16537
+ next
16538
+ };
16539
+ }
16468
16540
  var WIDGET_MIME = "text/html;profile=mcp-app";
16469
16541
  function widgetStamp(html) {
16470
16542
  return createHash("sha256").update(html).digest("hex").slice(0, 8);
@@ -16675,6 +16747,108 @@ function runbarWidgetHtml() {
16675
16747
  .side[hidden] { display: none; }
16676
16748
  .side b { font-weight: 650; color: var(--ink); }
16677
16749
 
16750
+ /* \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 */
16751
+
16752
+ /* \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
16753
+ \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
16754
+ \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
16755
+ \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. */
16756
+ .meter {
16757
+ position: relative;
16758
+ height: 8px;
16759
+ margin-top: 12px;
16760
+ border-radius: 4px;
16761
+ background: var(--off);
16762
+ overflow: hidden;
16763
+ }
16764
+ .meter__fill {
16765
+ display: block;
16766
+ width: 0;
16767
+ height: 100%;
16768
+ border-radius: 4px;
16769
+ background: var(--yellow);
16770
+ transition: width .6s var(--ease);
16771
+ }
16772
+ .meter__cap {
16773
+ margin: 7px 0 0;
16774
+ color: var(--ink-soft);
16775
+ font-size: 13px;
16776
+ line-height: 1.4;
16777
+ font-variant-numeric: tabular-nums;
16778
+ }
16779
+ .meter__cap b { color: var(--ink); font-weight: 650; }
16780
+ .dl[hidden], .meter[hidden], .meter__cap[hidden] { display: none; }
16781
+
16782
+ /* \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 */
16783
+
16784
+ /* \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
16785
+ \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
16786
+ \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. */
16787
+ .card[hidden] { display: none; }
16788
+ .card__meta { margin: 4px 0 0; color: var(--ink-soft); font-size: 12.5px; font-variant-numeric: tabular-nums; }
16789
+ .card__meta[hidden] { display: none; }
16790
+ .parts { display: grid; gap: 2px 18px; margin: 14px 0 0; padding: 0; list-style: none; }
16791
+ .parts[hidden] { display: none; }
16792
+ .part {
16793
+ display: flex;
16794
+ align-items: center;
16795
+ gap: 10px;
16796
+ min-width: 0;
16797
+ padding: 6px 0;
16798
+ border-bottom: 1px solid var(--edge);
16799
+ font-size: 14px;
16800
+ line-height: 1.3;
16801
+ }
16802
+ /* \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,
16803
+ \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. */
16804
+ .part__m {
16805
+ position: relative;
16806
+ flex: none;
16807
+ width: 16px;
16808
+ height: 16px;
16809
+ border-radius: 50%;
16810
+ box-sizing: border-box;
16811
+ }
16812
+ .part.ok .part__m { background: var(--good); }
16813
+ .part.ok .part__m::before {
16814
+ content: "";
16815
+ position: absolute;
16816
+ top: 4px;
16817
+ left: 4px;
16818
+ width: 7px;
16819
+ height: 3.5px;
16820
+ border-left: 1.8px solid var(--good-ink);
16821
+ border-bottom: 1.8px solid var(--good-ink);
16822
+ transform: rotate(-45deg);
16823
+ }
16824
+ .part.missing .part__m { border: 2.5px solid var(--yellow); }
16825
+ .part.later .part__m { border: 2px dashed var(--note-dot); }
16826
+ .part__t { display: block; flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
16827
+ .part.ok .part__t { color: var(--ink-soft); }
16828
+ .part__w { flex: none; color: var(--ink-soft); font-size: 12.5px; font-variant-numeric: tabular-nums; }
16829
+ .part.missing .part__w { color: var(--ink); font-weight: 650; }
16830
+ /* \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. */
16831
+ .next {
16832
+ display: flex;
16833
+ align-items: flex-start;
16834
+ gap: 9px;
16835
+ margin: 14px 0 0;
16836
+ font-size: 15px;
16837
+ font-weight: 650;
16838
+ line-height: 1.35;
16839
+ letter-spacing: -0.01em;
16840
+ }
16841
+ .next[hidden] { display: none; }
16842
+ .next::before {
16843
+ content: "";
16844
+ flex: none;
16845
+ width: 8px;
16846
+ height: 8px;
16847
+ margin-top: 6px;
16848
+ border-radius: 2px;
16849
+ background: var(--yellow);
16850
+ }
16851
+
16678
16852
  /* \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 */
16679
16853
 
16680
16854
  /* \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:
@@ -16787,6 +16961,7 @@ function runbarWidgetHtml() {
16787
16961
  body { padding: 22px 20px 24px; }
16788
16962
  h2 { font-size: 21px; }
16789
16963
  .rail { gap: 5px; }
16964
+ .parts { grid-template-columns: 1fr 1fr; }
16790
16965
  }
16791
16966
  @media (min-width: 760px) {
16792
16967
  body { padding: 26px 24px 28px; }
@@ -16806,7 +16981,20 @@ function runbarWidgetHtml() {
16806
16981
  <span class="now__c" id="nowLeft" hidden></span>
16807
16982
  </span>
16808
16983
  </div>
16984
+ <div class="dl" id="dl" hidden>
16985
+ <div class="meter" id="dlMeter"><span class="meter__fill" id="dlFill"></span></div>
16986
+ <p class="meter__cap" id="dlCap"></p>
16987
+ </div>
16809
16988
  <div class="msg" id="msg" hidden></div>
16989
+ <section class="card" id="card" hidden>
16990
+ <p class="card__meta" id="cardMeta" hidden></p>
16991
+ <div class="meter" id="cardMeter" hidden><span class="meter__fill" id="cardFill"></span></div>
16992
+ <p class="meter__cap" id="cardCap" hidden></p>
16993
+ <ul class="parts" id="cardRows" hidden></ul>
16994
+ <div class="msg" id="cardUpdate" hidden></div>
16995
+ <div class="note" id="cardTrouble" hidden></div>
16996
+ <p class="next" id="cardNext" hidden></p>
16997
+ </section>
16810
16998
  <p class="side" id="behind" hidden></p>
16811
16999
  <p class="side" id="ahead" hidden></p>
16812
17000
  <div class="end" id="end" hidden>
@@ -16830,6 +17018,7 @@ function runbarWidgetHtml() {
16830
17018
  // \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).
16831
17019
  var GIVE_UP_AFTER = 5;
16832
17020
  var CONTRACT = '${JOB_CONTRACT}';
17021
+ var SETUP = '${SETUP_CONTRACT}';
16833
17022
 
16834
17023
  var nextId = 1;
16835
17024
  // 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
@@ -16961,6 +17150,7 @@ function runbarWidgetHtml() {
16961
17150
  job = data;
16962
17151
  // \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.
16963
17152
  document.body.classList.remove('gone');
17153
+ byId('card').hidden = true;
16964
17154
  var ended = !working(data.status);
16965
17155
 
16966
17156
  show('what', data.what || '\u0420\u0430\u0431\u043E\u0442\u0430\u044E');
@@ -16980,9 +17170,13 @@ function runbarWidgetHtml() {
16980
17170
  if (data.at && data.total) title = title + ' \xB7 \u044D\u0442\u0430\u043F ' + data.at + ' \u0438\u0437 ' + data.total;
16981
17171
  show('nowTitle', title);
16982
17172
  show('nowLeft', data.left || '');
16983
- show('msg', data.status === 'waiting' ? '' : (data.message || ''));
17173
+ var loading = download(data);
17174
+ // \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
17175
+ // \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.
17176
+ show('msg', data.status === 'waiting' || loading ? '' : (data.message || ''));
16984
17177
  } else {
16985
17178
  byId('msg').hidden = true;
17179
+ byId('dl').hidden = true;
16986
17180
  }
16987
17181
 
16988
17182
  // \xAB\u041F\u043E\u0437\u0430\u0434\u0438\xBB \u0438 \xAB\u0434\u0430\u043B\u044C\u0448\u0435\xBB \u043F\u0440\u0438\u0445\u043E\u0434\u044F\u0442 \u0441\u0442\u0440\u043E\u043A\u0430\u043C\u0438 \u0434\u0432\u0438\u0436\u043A\u0430 \u0446\u0435\u043B\u0438\u043A\u043E\u043C: \u0434\u0440\u043E\u0431\u0438\u0442\u044C \u0438\u0445 \u043F\u043E
@@ -16996,6 +17190,131 @@ function runbarWidgetHtml() {
16996
17190
  reportSize();
16997
17191
  }
16998
17192
 
17193
+ /**
17194
+ * \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.
17195
+ *
17196
+ * \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
17197
+ * \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
17198
+ * \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).
17199
+ */
17200
+ function capital(text) {
17201
+ var s = String(text || '');
17202
+ return /^[\u0430-\u044F\u0451]/.test(s) ? s.charAt(0).toUpperCase() + s.slice(1) : s;
17203
+ }
17204
+
17205
+ /** \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. */
17206
+ function weight(mb) {
17207
+ var n = Math.max(0, Math.round(Number(mb) || 0));
17208
+ if (n >= 1000) return (n / 1024).toFixed(1).replace('.', ',') + ' \u0413\u0411';
17209
+ return n + ' \u041C\u0411';
17210
+ }
17211
+
17212
+ function fill(id, percent) {
17213
+ var el = byId(id);
17214
+ if (el) el.style.width = Math.max(0, Math.min(100, Number(percent) || 0)) + '%';
17215
+ }
17216
+
17217
+ /**
17218
+ * \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.
17219
+ *
17220
+ * \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
17221
+ * \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.
17222
+ */
17223
+ function download(data) {
17224
+ var box = byId('dl');
17225
+ if (!box) return false;
17226
+ var got = Number(data.got) || 0;
17227
+ if (!got) { box.hidden = true; return false; }
17228
+ var of = Number(data.of) || 0;
17229
+ byId('dlMeter').hidden = !of;
17230
+ fill('dlFill', of ? data.percent : 0);
17231
+ var cap = byId('dlCap');
17232
+ cap.innerHTML = '';
17233
+ var b = document.createElement('b');
17234
+ b.textContent = of ? (got + ' \u0438\u0437 ' + weight(of)) : ('\u0441\u043A\u0430\u0447\u0430\u043D\u043E ' + weight(got));
17235
+ cap.appendChild(b);
17236
+ var tail = of ? ' \xB7 ' + (Number(data.percent) || 0) + '%' : '';
17237
+ if (data.eta) tail += ' \xB7 ' + data.eta;
17238
+ cap.appendChild(document.createTextNode(tail));
17239
+ cap.hidden = false;
17240
+ box.hidden = false;
17241
+ return true;
17242
+ }
17243
+
17244
+ // \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
17245
+
17246
+ /**
17247
+ * \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.
17248
+ *
17249
+ * \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
17250
+ * \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.
17251
+ */
17252
+ function renderCard(data) {
17253
+ if (closed) return;
17254
+ job = null;
17255
+ document.body.classList.remove('gone');
17256
+ document.body.classList.remove('bad');
17257
+ var hide = ['now', 'rail', 'msg', 'dl', 'behind', 'ahead', 'clock', 'end', 'note'];
17258
+ for (var i = 0; i < hide.length; i++) { var el = byId(hide[i]); if (el) el.hidden = true; }
17259
+
17260
+ var rows = data.rows || [];
17261
+ var ok = 0, need = 0;
17262
+ for (var j = 0; j < rows.length; j++) {
17263
+ if (rows[j].state === 'ok') { ok++; need++; }
17264
+ else if (rows[j].state === 'missing') need++;
17265
+ }
17266
+ show('what', data.ready ? '\u0412\u0441\u0451 \u0433\u043E\u0442\u043E\u0432\u043E \u043A \u043C\u043E\u043D\u0442\u0430\u0436\u0443' : (need > ok ? '\u0414\u043B\u044F \u043C\u043E\u043D\u0442\u0430\u0436\u0430 \u043D\u0435 \u0432\u0441\u0451 \u043D\u0430 \u043C\u0435\u0441\u0442\u0435' : '\u041C\u043E\u043D\u0442\u0430\u0436 \u043D\u0430 \u044D\u0442\u043E\u043C \u043A\u043E\u043C\u043F\u044C\u044E\u0442\u0435\u0440\u0435'));
17267
+
17268
+ var meta = [];
17269
+ if (data.engine) meta.push('\u0434\u0432\u0438\u0436\u043E\u043A ' + data.engine);
17270
+ if (data.shell) meta.push('\u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u0435 ' + data.shell);
17271
+ show('cardMeta', meta.join(' \xB7 '));
17272
+
17273
+ // \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
17274
+ // \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
17275
+ // \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.
17276
+ byId('cardMeter').hidden = !need;
17277
+ fill('cardFill', need ? ok * 100 / need : 0);
17278
+ var cap = byId('cardCap');
17279
+ cap.innerHTML = '';
17280
+ if (need) {
17281
+ var b = document.createElement('b');
17282
+ b.textContent = '\u0413\u043E\u0442\u043E\u0432\u043E ' + ok + ' \u0438\u0437 ' + need;
17283
+ cap.appendChild(b);
17284
+ if (data.missingMb) cap.appendChild(document.createTextNode(' \xB7 \u0434\u043E\u043A\u0430\u0447\u0430\u0442\u044C ' + weight(data.missingMb)));
17285
+ }
17286
+ cap.hidden = !need;
17287
+
17288
+ var list = byId('cardRows');
17289
+ list.innerHTML = '';
17290
+ for (var k = 0; k < rows.length; k++) {
17291
+ var row = rows[k];
17292
+ var li = document.createElement('li');
17293
+ li.className = 'part ' + row.state;
17294
+ var mark = document.createElement('span');
17295
+ mark.className = 'part__m';
17296
+ li.appendChild(mark);
17297
+ var title = document.createElement('span');
17298
+ title.className = 'part__t';
17299
+ title.textContent = capital(row.title);
17300
+ li.appendChild(title);
17301
+ var w = document.createElement('span');
17302
+ w.className = 'part__w';
17303
+ w.textContent = row.state === 'ok' ? '\u0441\u0442\u043E\u0438\u0442'
17304
+ : row.state === 'later' ? ('\u043F\u043E \u043F\u0440\u043E\u0441\u044C\u0431\u0435' + (row.mb ? ' \xB7 ' + weight(row.mb) : ''))
17305
+ : (row.mb ? weight(row.mb) : '\u043D\u0435\u0442');
17306
+ li.appendChild(w);
17307
+ list.appendChild(li);
17308
+ }
17309
+ list.hidden = !rows.length;
17310
+
17311
+ show('cardUpdate', data.update || '');
17312
+ show('cardTrouble', data.trouble || '');
17313
+ show('cardNext', data.next || '');
17314
+ byId('card').hidden = false;
17315
+ reportSize();
17316
+ }
17317
+
16999
17318
  function side(id, label, text) {
17000
17319
  var el = byId(id);
17001
17320
  if (!el) return;
@@ -17040,6 +17359,9 @@ function runbarWidgetHtml() {
17040
17359
  /** \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. */
17041
17360
  function finishWithWords(text) {
17042
17361
  job = null;
17362
+ document.body.classList.remove('gone');
17363
+ byId('card').hidden = true;
17364
+ byId('dl').hidden = true;
17043
17365
  byId('now').hidden = true;
17044
17366
  byId('rail').hidden = true;
17045
17367
  byId('msg').hidden = true;
@@ -17069,7 +17391,7 @@ function runbarWidgetHtml() {
17069
17391
  // \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
17070
17392
  // \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
17071
17393
  // \u043A\u0430\u0434\u0440 \u0438 \u0437\u0430\u043C\u0435\u0440\u043B\u0430.
17072
- var all = ['now', 'rail', 'msg', 'behind', 'ahead', 'clock', 'end', 'note', 'what'];
17394
+ var all = ['now', 'rail', 'msg', 'dl', 'card', 'behind', 'ahead', 'clock', 'end', 'note', 'what'];
17073
17395
  for (var i = 0; i < all.length; i++) { var el = byId(all[i]); if (el) el.hidden = true; }
17074
17396
  document.body.classList.add('gone');
17075
17397
  reportSize();
@@ -17110,8 +17432,16 @@ function runbarWidgetHtml() {
17110
17432
  }
17111
17433
  if (m.method === 'ui/notifications/tool-result') {
17112
17434
  if (m.params && m.params.isError) { finishWithWords(words(m.params)); return; }
17435
+ // \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
17436
+ // \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.
17437
+ var card = m.params && m.params.structuredContent;
17438
+ if (card && card.contract === SETUP) { renderCard(card); return; }
17113
17439
  var data = parse(m.params);
17114
- // \u26A0 \u041E\u0422\u0412\u0415\u0422 \u0411\u0415\u0417 \u0417\u0410\u0414\u0410\u0427\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 \u0417\u0410\u0413\u041B\u0423\u0428\u041A\u0415. \u041F\u043E\u043B\u043E\u0441\u0430
17440
+ // \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
17441
+ // \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
17442
+ // 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
17443
+ // \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,
17444
+ // \u0438\u0437\u0432\u0435\u0441\u0442\u043D\u044B\u0439 \u0431\u0440\u0430\u043A). \u041F\u043E\u043B\u043E\u0441\u0430
17115
17445
  // \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
17116
17446
  // \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,
17117
17447
  // \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
@@ -17171,31 +17501,6 @@ function aboutModels(passport) {
17171
17501
  function fromList(list, description) {
17172
17502
  return list !== void 0 && list.length > 0 ? external_exports.enum([...list]).describe(description) : external_exports.string().describe(description);
17173
17503
  }
17174
- function capabilitiesToSchema(passport, taken = /* @__PURE__ */ new Set()) {
17175
- const skills = passport?.["capabilities"];
17176
- if (skills === void 0) return {};
17177
- const schema = {};
17178
- for (const [name, o] of Object.entries(skills)) {
17179
- if (taken.has(name)) continue;
17180
- schema[name] = o["kind"] === "yes-no" ? external_exports.boolean().describe(o["about"]).optional() : external_exports.string().describe(o["about"]).optional();
17181
- }
17182
- return schema;
17183
- }
17184
- function readCapabilities(args, passport) {
17185
- const skills = passport?.["capabilities"];
17186
- if (skills === void 0) return [];
17187
- const line = [];
17188
- for (const [name, o] of Object.entries(skills)) {
17189
- const key = `--${name.split("_").join("-")}`;
17190
- if (o["kind"] === "yes-no") {
17191
- if (args[name] === true) line.push(key);
17192
- continue;
17193
- }
17194
- const value = args[name];
17195
- if (typeof value === "string") line.push(key, o["kind"] === "file" ? path(value) : value);
17196
- }
17197
- return line;
17198
- }
17199
17504
  function asToolResult(outcome) {
17200
17505
  return outcome.ok ? toolSuccess(outcome.text) : toolError(outcome.text);
17201
17506
  }
@@ -17217,7 +17522,6 @@ var KNOB_KIND = {
17217
17522
  "yes-no": "\u0434\u0430/\u043D\u0435\u0442"
17218
17523
  };
17219
17524
  var FROM_MINE = "mine";
17220
- var FROM_VENDOR = "vendor";
17221
17525
  function catalogInWords(data) {
17222
17526
  const lines = [];
17223
17527
  const version2 = data.engine?.version;
@@ -17276,12 +17580,10 @@ function catalogInWords(data) {
17276
17580
  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(", ");
17277
17581
  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}.`);
17278
17582
  }
17279
- const skills = data.skills ?? [];
17280
- if (skills.length > 0) {
17281
- const said = skills.map((s) => s.origin === FROM_VENDOR ? `${s.name} \u2014 ${s.about ?? ""} (\u0447\u0435\u0440\u0435\u0437 ${s.read ?? ""})` : `${s.read ?? s.name} \u2014 ${s.about ?? ""}`).join("; ");
17282
- lines.push(
17283
- `\u0421\u043A\u0438\u043B\u043B\u044B \u043D\u0430 \u0434\u0438\u0441\u043A\u0435, \u0447\u0438\u0442\u0430\u0442\u044C plan \u0441 read, \u0440\u043E\u043B\u0438\u043A \u0434\u043B\u044F \u044D\u0442\u043E\u0433\u043E \u043D\u0435 \u043D\u0443\u0436\u0435\u043D: ${said}. \u0413\u043E\u0434\u044F\u0442\u0441\u044F \u0438 \u043D\u0435 \u0434\u043B\u044F \u0440\u043E\u043B\u0438\u043A\u0430: \u043F\u0440\u0435\u0437\u0435\u043D\u0442\u0430\u0446\u0438\u044F, \u043A\u0430\u0440\u0442\u0438\u043D\u043A\u0430, \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u0430.`
17284
- );
17583
+ const index = data.handbook?.index;
17584
+ if (index !== void 0 && index.trim() !== "") {
17585
+ 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:
17586
+ ${index.trim()}`);
17285
17587
  }
17286
17588
  const style = data.style;
17287
17589
  if (style?.name !== void 0) {
@@ -17289,6 +17591,11 @@ function catalogInWords(data) {
17289
17591
  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.`
17290
17592
  );
17291
17593
  }
17594
+ const mine = data.mine?.summary ?? [];
17595
+ if (mine.length > 0) {
17596
+ 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):
17597
+ ${mine.map((line) => `\u2014 ${line}`).join("\n")}`);
17598
+ }
17292
17599
  for (const said of data.warnings ?? []) lines.push(said);
17293
17600
  return lines.join("\n");
17294
17601
  }
@@ -17314,60 +17621,6 @@ async function askCatalog(engine, pack, video) {
17314
17621
  }
17315
17622
  return catalogInWords(data);
17316
17623
  }
17317
- async function startMontage(engine, opts) {
17318
- const trouble = await engine.pythonTrouble();
17319
- if (trouble !== null) return toolError(trouble);
17320
- const python = engine.packPython();
17321
- if (python === null) {
17322
- return toolError(
17323
- "\u041E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u0435 \u043C\u043E\u043D\u0442\u0430\u0436\u0430 \u0435\u0449\u0451 \u043D\u0435 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u043E \u2014 \u043C\u043E\u043D\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u043D\u0435\u0447\u0435\u043C.\n\u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C: \u043F\u043E\u0437\u043E\u0432\u0438 setup, \u043E\u043D \u0441\u043A\u0430\u0436\u0435\u0442, \u0447\u0435\u0433\u043E \u043D\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442, \u0430 \u0441 what \u043E\u043D \u044D\u0442\u043E \u0438 \u043F\u043E\u0441\u0442\u0430\u0432\u0438\u0442."
17324
- );
17325
- }
17326
- const passport = await engine.passport();
17327
- if (passport === null) {
17328
- return toolError(
17329
- // ⚠ ВТОРАЯ ПРИЧИНА НАЗВАНА С 2026-09-09, И ОНА ТЕПЕРЬ ЧАСТАЯ. Пак
17330
- // переименован (`first-montage` → `montage`), а начинка живёт версионными
17331
- // папками: у того, чья начинка старее оболочки, пака по новому имени
17332
- // просто нет. `check_setup` про это не скажет ничего внятного — лечит
17333
- // обновление начинки, и назвать его надо здесь.
17334
- "\u041D\u0435 \u0441\u043C\u043E\u0433 \u043F\u0440\u043E\u0447\u0438\u0442\u0430\u0442\u044C \u043F\u0430\u0441\u043F\u043E\u0440\u0442 \u043F\u0430\u043A\u0430 \u043C\u043E\u043D\u0442\u0430\u0436\u0430 (pack.json).\n\u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C: \u043F\u043E\u0437\u043E\u0432\u0438 setup \u2014 \u043E\u043D \u0441\u043A\u0430\u0436\u0435\u0442, \u0447\u0442\u043E \u0441 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u043E\u0439 \u043D\u0435 \u0442\u0430\u043A. \u0415\u0441\u043B\u0438 \u043D\u0430\u0447\u0438\u043D\u043A\u0430 \u0441\u0442\u0430\u0432\u0438\u043B\u0430\u0441\u044C \u0434\u0430\u0432\u043D\u043E, \u0434\u0435\u043B\u043E \u043C\u043E\u0436\u0435\u0442 \u0431\u044B\u0442\u044C \u0432 \u043D\u0435\u0439: \u043F\u0430\u043A \u043F\u0435\u0440\u0435\u0435\u0445\u0430\u043B, \u0438 \u0441\u0442\u0430\u0440\u0430\u044F \u043D\u0430\u0447\u0438\u043D\u043A\u0430 \u0435\u0433\u043E \u043D\u0435 \u0441\u043E\u0434\u0435\u0440\u0436\u0438\u0442 \u2014 \u0442\u043E\u0433\u0434\u0430 \u043F\u043E\u043C\u043E\u0433\u0430\u0435\u0442 setup \u0441 what=engine."
17335
- );
17336
- }
17337
- if (opts.tell !== void 0) {
17338
- for (const line of opts.ladder ?? montageLadder(passport["stages"])) opts.tell(line);
17339
- opts.tell(opts.hint);
17340
- }
17341
- const launch = await engine.background({
17342
- place: opts.place,
17343
- executable: python,
17344
- key: opts.key,
17345
- startJob: [
17346
- "job-create",
17347
- "--video",
17348
- opts.video,
17349
- "--what",
17350
- opts.what,
17351
- "--command",
17352
- JSON.stringify(opts.command),
17353
- ...opts.style !== void 0 ? ["--style", opts.style] : []
17354
- ],
17355
- args: (id) => [passport["entry"], opts.video, "--job", id, ...opts.args],
17356
- advice: "\u043F\u043E\u0437\u043E\u0432\u0438 setup \u2014 \u0441\u043A\u043E\u0440\u0435\u0435 \u0432\u0441\u0435\u0433\u043E, \u043E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u0435 \u043D\u0435\u043F\u043E\u043B\u043D\u043E\u0435"
17357
- });
17358
- if ("refusal" in launch) return toolError(launch.refusal);
17359
- return toolSuccess(
17360
- `\u0417\u0430\u0434\u0430\u0447\u0430 ${launch.id}: ${opts.what}
17361
- \u0412\u0441\u0451 \u0434\u0435\u043B\u0430\u0435\u0442\u0441\u044F \u043D\u0430 \u043A\u043E\u043C\u043F\u044C\u044E\u0442\u0435\u0440\u0435 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F. ${opts.hint}
17362
- \u0420\u0430\u0431\u043E\u0442\u0430 \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: \u043D\u043E\u043C\u0435\u0440 \u0437\u0430\u0434\u0430\u0447\u0438 \u0437\u0430\u043F\u043E\u043C\u043D\u0438 \u0438 \u043F\u043E\u0437\u043E\u0432\u0438 wait \u0441 job "${launch.id}" \u2014 \u043E\u043D \u043F\u043E\u0434\u043E\u0436\u0434\u0451\u0442 \u0438 \u0440\u0430\u0441\u0441\u043A\u0430\u0436\u0435\u0442 \u0445\u043E\u0434 \u043F\u043E \u0448\u0430\u0433\u0430\u043C, \u043F\u0435\u0440\u0435\u0441\u043A\u0430\u0437\u044B\u0432\u0430\u0439 \u0435\u0433\u043E \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0443 \u0441\u0440\u0430\u0437\u0443. ${AWAY_NOTE}`,
17363
- startedJob({
17364
- id: launch.id,
17365
- what: opts.what,
17366
- ahead: (opts.ladder ?? montageLadder(passport["stages"])).join(" "),
17367
- message: opts.hint
17368
- })
17369
- );
17370
- }
17371
17624
  function fromWords(text2, contract) {
17372
17625
  let data;
17373
17626
  try {
@@ -17385,6 +17638,47 @@ function folderAnswer(text2) {
17385
17638
  const read = fromWords(text2);
17386
17639
  return "refusal" in read ? toolError(read.refusal) : toolSuccess(read.words, read.data);
17387
17640
  }
17641
+ var DRAFT_CONTRACT = "naparnik-draft/1";
17642
+ var VIEW_CONTRACT = "naparnik-view/1";
17643
+ var EDIT_CONTRACT = "naparnik-edit/1";
17644
+ function answerOrRefusal(text2, contract) {
17645
+ const read = fromWords(text2, contract);
17646
+ if ("refusal" in read) {
17647
+ const plain = text2.trim();
17648
+ return { refusal: plain.startsWith("{") || plain === "" ? read.refusal : plain };
17649
+ }
17650
+ return read.data["ok"] === false ? { refusal: read.words } : read;
17651
+ }
17652
+ async function draftDocument(engine, place, asked, key) {
17653
+ const answer = await engine.command([
17654
+ "document-draft",
17655
+ "--video",
17656
+ asked.video,
17657
+ "--pack",
17658
+ place.pack,
17659
+ ...asked.style !== void 0 ? ["--style", path(asked.style)] : [],
17660
+ ...(asked.also ?? []).flatMap((one) => ["--also", path(one)]),
17661
+ ...asked.ask !== void 0 ? ["--ask", JSON.stringify(asked.ask)] : [],
17662
+ "--json"
17663
+ ], key !== void 0 ? { key } : {});
17664
+ return answer.ok ? answerOrRefusal(answer.text, DRAFT_CONTRACT) : { refusal: answer.text };
17665
+ }
17666
+ async function editOperations(engine, place, asked, key) {
17667
+ const answer = await engine.command([
17668
+ "document-edit",
17669
+ "--project",
17670
+ path(asked.reel),
17671
+ "--ops",
17672
+ JSON.stringify(asked.ops),
17673
+ ...asked.stamps !== void 0 ? ["--stamps", JSON.stringify(asked.stamps)] : [],
17674
+ "--by",
17675
+ asked.by ?? "model",
17676
+ "--pack",
17677
+ place.pack,
17678
+ "--json"
17679
+ ], key !== void 0 ? { key } : {});
17680
+ return answer.ok ? answerOrRefusal(answer.text, EDIT_CONTRACT) : { refusal: answer.text };
17681
+ }
17388
17682
  function nameOrRefusal(candidate) {
17389
17683
  const looksLikePath2 = candidate.includes("/") || candidate.includes("\\") || candidate.startsWith("~") || candidate.startsWith(".") || candidate.length > 1 && candidate[1] === ":";
17390
17684
  if (!looksLikePath2) return { name: candidate };
@@ -17398,23 +17692,47 @@ function nameOrRefusal(candidate) {
17398
17692
  var ASKED_POINTER_MS = 15e3;
17399
17693
  var NEWS_POINTER_MS = 5e3;
17400
17694
  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.";
17401
- async function checkSetup(engine, asked) {
17695
+ async function inspectMachine(engine, asked) {
17402
17696
  const video = asked.video;
17403
17697
  const model = asked.model;
17404
17698
  const place = engine.place();
17405
- if (place === null) return toolError(engine.whyNoEngine());
17406
- const outcome = await engine.command([
17699
+ if (place === null) return { result: toolError(engine.whyNoEngine()), readiness: null };
17700
+ const args = [
17407
17701
  "env-check",
17408
17702
  "--pack",
17409
17703
  place.pack,
17410
17704
  ...video !== void 0 ? ["--video", path(video)] : [],
17411
17705
  ...model !== void 0 ? ["--model", model] : []
17412
- ]);
17413
- if (!outcome.ok) return toolError(outcome.text);
17706
+ ];
17707
+ let readiness = null;
17708
+ let words;
17709
+ if (knowsJsonCheck(place.engine)) {
17710
+ const answer = await askReadiness(engine, place, args);
17711
+ if ("ok" in answer && !answer.ok) return { result: toolError(answer.text), readiness: null };
17712
+ if ("parts" in answer) readiness = answer;
17713
+ words = "parts" in answer ? answer.words : answer.text;
17714
+ } else {
17715
+ const outcome = await engine.command(args);
17716
+ if (!outcome.ok) return { result: toolError(outcome.text), readiness: null };
17717
+ words = outcome.text;
17718
+ }
17414
17719
  const catalog = await askCatalog(engine, place.pack, video);
17415
- return toolSuccess(`${outcome.text}
17720
+ return { result: toolSuccess(`${words}
17416
17721
 
17417
- ${catalog}`);
17722
+ ${catalog}`), readiness };
17723
+ }
17724
+ async function askReadiness(engine, place, args) {
17725
+ const python = await engine.pythonTrouble();
17726
+ if (python !== null) return { ok: false, text: python };
17727
+ let stdout;
17728
+ try {
17729
+ stdout = (await engine.run(place, [...args, JSON_CHECK])).stdout;
17730
+ } catch (err) {
17731
+ const e = err;
17732
+ 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");
17733
+ stdout = e.stdout;
17734
+ }
17735
+ return readReadiness(stdout) ?? { ok: true, text: stdout.trim() };
17418
17736
  }
17419
17737
  async function installStep(engine, asked, key, baseUrl, tell) {
17420
17738
  const step = asked.step;
@@ -17523,7 +17841,8 @@ ${EXTRAS_LATER}`), later]);
17523
17841
  })
17524
17842
  );
17525
17843
  }
17526
- async function updateEngine(engine, consent, key, baseUrl, timeoutMs = ASKED_POINTER_MS) {
17844
+ async function updateEngine(engine, consent, key, baseUrl, timeoutMs = ASKED_POINTER_MS, seen = () => {
17845
+ }) {
17527
17846
  if (engine.pathSetByHand()) {
17528
17847
  return toolSuccess(
17529
17848
  "\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."
@@ -17536,6 +17855,12 @@ async function updateEngine(engine, consent, key, baseUrl, timeoutMs = ASKED_POI
17536
17855
  }
17537
17856
  const outcome = await fetchManifest(manifestUrl(engine, baseUrl), timeoutMs, key);
17538
17857
  const decision = decide(engine.freshVersion(), outcome.ok ? outcome.manifest : null);
17858
+ seen({
17859
+ installed: engine.freshVersion(),
17860
+ fresh: decision.what === "nothing" ? null : decision.manifest.version,
17861
+ mb: decision.what === "nothing" ? 0 : Math.round(decision.manifest.bytes / 1024 / 1024),
17862
+ status: outcome.ok ? 0 : outcome.status ?? 0
17863
+ });
17539
17864
  if (decision.what === "nothing") {
17540
17865
  const ownDir2 = engine.freshVersion();
17541
17866
  return toolSuccess(
@@ -17557,12 +17882,19 @@ ${VOICE_CLEANER_NOTE}
17557
17882
  }
17558
17883
  return asToolResult(await deploy(engine, decision.manifest, void 0, key));
17559
17884
  }
17560
- async function updateShell(engine, consent, key, baseUrl, timeoutMs = ASKED_POINTER_MS) {
17885
+ async function updateShell(engine, consent, key, baseUrl, timeoutMs = ASKED_POINTER_MS, seen = () => {
17886
+ }) {
17561
17887
  const home = engine.home();
17562
17888
  const url2 = engine.variable("NAPARNIK_BUNDLE_MANIFEST") ?? bundleUrlFor(baseUrl);
17563
17889
  const outcome = await fetchShellManifest(url2, timeoutMs, key);
17564
17890
  const installed = installedShell(home);
17565
17891
  const decision = decideShell(installed, outcome.ok ? outcome.manifest : null);
17892
+ seen({
17893
+ installed,
17894
+ fresh: decision.what === "nothing" ? null : decision.manifest.version,
17895
+ mb: decision.what === "nothing" ? 0 : Math.round((decision.manifest.body?.bytes ?? 0) / 1024 / 1024),
17896
+ status: outcome.ok ? 0 : outcome.status ?? 0
17897
+ });
17566
17898
  if (decision.what === "nothing") {
17567
17899
  if (!outcome.ok) {
17568
17900
  return toolSuccess(
@@ -17647,46 +17979,89 @@ function setupTool(engine, passport, key, baseUrl) {
17647
17979
  }
17648
17980
  }),
17649
17981
  async execute(args, ctx) {
17650
- if (args.rollback === "engine") return asToolResult(rollback(engine));
17651
- if (args.rollback === "shell") return asToolResult(rollbackShell(engine.home()));
17652
- const consent = args.consent === true;
17653
- const tell = ctx?.emitProgress;
17654
- const what = args.what;
17655
- if (what === void 0) return lookAround(engine, args.model, key, baseUrl);
17656
- if (what === "engine") return updateEngine(engine, consent, key, baseUrl);
17657
- if (what === "shell") return updateShell(engine, consent, key, baseUrl);
17658
- if (what === "all") {
17659
- return consent ? installEverything(engine, key, baseUrl, tell) : lookAround(engine, args.model, key, baseUrl);
17660
- }
17661
- const step = HEAVY_STEPS[what];
17662
- return consent ? installStep(engine, { step, model: args.model, consent: true }, key, baseUrl, tell) : askBeforeHeavy(engine, step, args.model, key, baseUrl);
17982
+ const news = { engine: null, shell: null };
17983
+ const said = await answer(args, ctx?.emitProgress, news);
17984
+ return withCard(said, () => setupCard({
17985
+ readiness: null,
17986
+ engine: news.engine ?? { installed: engine.freshVersion(), fresh: null, mb: 0, status: 0 },
17987
+ shell: news.shell,
17988
+ note: firstLine(said),
17989
+ shellVersion: VERSION
17990
+ }));
17663
17991
  }
17664
17992
  });
17993
+ async function answer(args, tell, news) {
17994
+ if (args.rollback === "engine") return asToolResult(rollback(engine));
17995
+ if (args.rollback === "shell") return asToolResult(rollbackShell(engine.home()));
17996
+ const consent = args.consent === true;
17997
+ const what = args.what;
17998
+ if (what === void 0) return lookAround(engine, args.model, key, baseUrl);
17999
+ if (what === "engine") {
18000
+ return updateEngine(engine, consent, key, baseUrl, ASKED_POINTER_MS, (seen) => {
18001
+ if (!consent) news.engine = seen;
18002
+ });
18003
+ }
18004
+ if (what === "shell") {
18005
+ return updateShell(engine, consent, key, baseUrl, ASKED_POINTER_MS, (seen) => {
18006
+ if (!consent) news.shell = seen;
18007
+ });
18008
+ }
18009
+ if (what === "all") {
18010
+ return consent ? installEverything(engine, key, baseUrl, tell) : lookAround(engine, args.model, key, baseUrl);
18011
+ }
18012
+ const step = HEAVY_STEPS[what];
18013
+ return consent ? installStep(engine, { step, model: args.model, consent: true }, key, baseUrl, tell) : askBeforeHeavy(engine, step, args.model, key, baseUrl);
18014
+ }
17665
18015
  }
17666
18016
  async function lookAround(engine, model, key, baseUrl) {
17667
- const shell = updateShell(engine, false, key, baseUrl, NEWS_POINTER_MS);
18017
+ let engineNews = null;
18018
+ let shellNews = null;
18019
+ const toEngine = (news2) => {
18020
+ engineNews = news2;
18021
+ };
18022
+ const toShell = (news2) => {
18023
+ shellNews = news2;
18024
+ };
18025
+ const card = (said, o) => withCard(said, () => setupCard({
18026
+ readiness: o.readiness ?? null,
18027
+ engine: engineNews ?? { installed: engine.freshVersion(), fresh: null, mb: 0, status: 0 },
18028
+ shell: shellNews,
18029
+ ...o.noEngine === true ? { noEngine: true } : {},
18030
+ ...o.noPython === true ? { noPython: true } : {},
18031
+ note: firstLine(said),
18032
+ shellVersion: VERSION
18033
+ }));
18034
+ const shell = updateShell(engine, false, key, baseUrl, NEWS_POINTER_MS, toShell);
17668
18035
  if (engine.place() === null) {
17669
18036
  const payload = await installPayload(engine, {
17670
18037
  consent: false,
17671
18038
  manifestUrl: manifestUrl(engine, baseUrl),
17672
18039
  ...key !== void 0 ? { key } : {}
17673
18040
  });
17674
- return together([toolSuccess(payload.text), await shell]);
18041
+ return card(together([toolSuccess(payload.text), await shell]), { noEngine: true });
17675
18042
  }
17676
18043
  if (await engine.pythonTrouble() !== null) {
17677
18044
  const python = await installPython(engine, { consent: false });
17678
- return together([
18045
+ return card(together([
17679
18046
  toolSuccess(python.text),
17680
- await updateEngine(engine, false, key, baseUrl, NEWS_POINTER_MS),
18047
+ await updateEngine(engine, false, key, baseUrl, NEWS_POINTER_MS, toEngine),
17681
18048
  await shell
17682
- ]);
18049
+ ]), { noPython: true });
17683
18050
  }
17684
18051
  const [machine, news, own] = await Promise.all([
17685
- checkSetup(engine, { model }),
17686
- updateEngine(engine, false, key, baseUrl, NEWS_POINTER_MS),
18052
+ inspectMachine(engine, { model }),
18053
+ updateEngine(engine, false, key, baseUrl, NEWS_POINTER_MS, toEngine),
17687
18054
  shell
17688
18055
  ]);
17689
- return together([machine, news, own]);
18056
+ return card(together([machine.result, news, own]), { readiness: machine.readiness });
18057
+ }
18058
+ function withCard(result, card) {
18059
+ if (result.type !== "success" || result.structured !== void 0) return result;
18060
+ return toolSuccess(wordsOf(result.content), card());
18061
+ }
18062
+ function firstLine(result) {
18063
+ const text2 = result.type === "success" ? wordsOf(result.content) : result.error;
18064
+ return text2.split("\n").map((line) => line.trim()).find((line) => line !== "") ?? "";
17690
18065
  }
17691
18066
  async function installEverything(engine, key, baseUrl, tell) {
17692
18067
  const said = [await updateShell(engine, true, key, baseUrl)];
@@ -17743,58 +18118,259 @@ function wordsOf(content) {
17743
18118
  if (typeof content === "string") return content;
17744
18119
  return content.map((block) => block.type === "text" ? block.text : "").join("\n");
17745
18120
  }
17746
- async function listReels(engine, workspace) {
18121
+ async function startRender(engine, asked, key, tell) {
17747
18122
  const place = engine.place();
17748
18123
  if (place === null) return toolError(engine.whyNoEngine());
17749
- const answer = await engine.command([
17750
- "reels",
17751
- "--json",
17752
- ...workspace !== void 0 ? ["--workspace", path(workspace)] : []
17753
- ]);
17754
- if (!answer.ok) return toolError(answer.text);
17755
- return folderAnswer(answer.text);
17756
- }
17757
- async function openReel(engine, asked) {
18124
+ const where = fileOrRefusal(asked.video);
18125
+ if ("refusal" in where) return toolError(where.refusal);
18126
+ if (asked.onlyPauses !== true) return startDocumentRender(engine, where.path, key, tell);
18127
+ if (tell !== void 0) for (const line of PAUSES_LADDER) tell(line);
18128
+ const ask2 = { pauses: {} };
18129
+ if (asked.tempo !== void 0 && asked.tempo !== 1) ask2["tempo"] = asked.tempo;
18130
+ const draft = await draftDocument(engine, place, { video: where.path, style: asked.style, ask: ask2 }, key);
18131
+ if ("refusal" in draft) return toolError(draft.refusal);
18132
+ const reel = String(draft.data["project"] ?? where.path);
18133
+ const agreement = await editOperations(engine, place, { reel, ops: [{ op: "agree" }] }, key);
18134
+ if ("refusal" in agreement) return toolError(agreement.refusal);
18135
+ return startDocumentRender(engine, reel, key, tell);
18136
+ }
18137
+ async function startDocumentRender(engine, reel, key, tell) {
17758
18138
  const place = engine.place();
17759
18139
  if (place === null) return toolError(engine.whyNoEngine());
17760
- if (asked.files.length === 0) {
17761
- return toolError(
17762
- "\u0417\u0430\u0432\u043E\u0434\u0438\u0442\u044C \u0440\u043E\u043B\u0438\u043A \u043D\u0435 \u0438\u0437 \u0447\u0435\u0433\u043E: \u043D\u0435 \u043D\u0430\u0437\u0432\u0430\u043D\u043E \u043D\u0438 \u043E\u0434\u043D\u043E\u0433\u043E \u0444\u0430\u0439\u043B\u0430.\n\u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C: \u0441\u043F\u0440\u043E\u0441\u0438 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430, \u043A\u0430\u043A\u043E\u0439 \u0444\u0430\u0439\u043B \u043C\u043E\u043D\u0442\u0438\u0440\u0443\u0435\u043C, \u0438\u043B\u0438 \u043F\u043E\u0437\u043E\u0432\u0438 plan \u2014 \u0442\u0430\u043C \u0432\u0438\u0434\u043D\u043E, \u0447\u0442\u043E \u0432 \u043F\u0430\u043F\u043A\u0435 \u043B\u0435\u0436\u0438\u0442."
17763
- );
17764
- }
17765
- const where = [];
17766
- for (const one of asked.files) {
17767
- const found = fileOrRefusal(one);
17768
- if ("refusal" in found) return toolError(found.refusal);
17769
- where.push(found.path);
17770
- }
17771
- const answer = await engine.command([
17772
- "reel-open",
17773
- ...where,
17774
- "--json",
17775
- ...asked.workspace !== void 0 ? ["--workspace", path(asked.workspace)] : [],
17776
- ...asked.together === true ? ["--together"] : []
17777
- ]);
17778
- if (!answer.ok) return toolError(answer.text);
17779
- return folderAnswer(answer.text);
17780
- }
17781
- var PLAN_DRAFT = "naparnik-plan-draft/1";
17782
- var COMPOSITION_VIEW = "naparnik-composition-view/1";
17783
- var SKILLS_READ = "naparnik-skills-read/1";
17784
- function answerOrRefusal(text2, contract) {
17785
- const read = fromWords(text2, contract);
17786
- if ("refusal" in read) {
17787
- const plain = text2.trim();
17788
- return { refusal: plain.startsWith("{") || plain === "" ? read.refusal : plain };
18140
+ const trouble = await engine.pythonTrouble();
18141
+ if (trouble !== null) return toolError(trouble);
18142
+ const python = engine.packPython();
18143
+ if (python === null) {
18144
+ return toolError("\u041E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u0435 \u043C\u043E\u043D\u0442\u0430\u0436\u0430 \u0435\u0449\u0451 \u043D\u0435 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u043E. \u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C: \u043F\u043E\u0437\u043E\u0432\u0438 setup.");
17789
18145
  }
17790
- const said = read.data;
17791
- return said.ok === false ? { refusal: read.words } : read;
17792
- }
17793
- async function readSkills(engine, asked) {
17794
- const place = engine.place();
17795
- if (place === null) return toolError(engine.whyNoEngine());
17796
- const answer = await engine.command([
17797
- "skills-read",
18146
+ if (tell !== void 0) for (const line of RENDER_LADDER) tell(line);
18147
+ const what = `\u043C\u043E\u043D\u0442\u0430\u0436 ${basename(reel)}`;
18148
+ const launch = await engine.background({
18149
+ place,
18150
+ executable: python,
18151
+ key,
18152
+ startJob: [
18153
+ "job-create",
18154
+ "--video",
18155
+ reel,
18156
+ "--what",
18157
+ what,
18158
+ "--command",
18159
+ JSON.stringify({ tool: "render", args: {} })
18160
+ ],
18161
+ args: (id) => [
18162
+ place.consolePy,
18163
+ "document-render",
18164
+ "--project",
18165
+ reel,
18166
+ "--pack",
18167
+ place.pack,
18168
+ "--job",
18169
+ id
18170
+ ],
18171
+ advice: "\u043F\u043E\u0437\u043E\u0432\u0438 setup \u2014 \u0441\u043A\u043E\u0440\u0435\u0435 \u0432\u0441\u0435\u0433\u043E, \u043E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u0435 \u043D\u0435\u043F\u043E\u043B\u043D\u043E\u0435"
18172
+ });
18173
+ if ("refusal" in launch) return toolError(launch.refusal);
18174
+ return toolSuccess(
18175
+ `\u0417\u0430\u0434\u0430\u0447\u0430 ${launch.id}: ${what}
18176
+ \u0414\u0430\u043B\u044C\u0448\u0435 \u043F\u043E\u0437\u043E\u0432\u0438 wait \u0441 \u044D\u0442\u0438\u043C \u043D\u043E\u043C\u0435\u0440\u043E\u043C. ${AWAY_NOTE}`,
18177
+ startedJob({
18178
+ id: launch.id,
18179
+ what,
18180
+ ahead: RENDER_LADDER.join(" "),
18181
+ message: "\u0420\u043E\u043B\u0438\u043A \u0441\u043E\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044F \u043D\u0430 \u043A\u043E\u043C\u043F\u044C\u044E\u0442\u0435\u0440\u0435 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F."
18182
+ })
18183
+ );
18184
+ }
18185
+ var RENDER_LADDER = [
18186
+ "\u041F\u0440\u043E\u0432\u0435\u0440\u044E, \u0447\u0442\u043E \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442 \u0441\u043E\u0433\u043B\u0430\u0441\u043E\u0432\u0430\u043D \u0438 \u043D\u0435 \u043F\u0440\u0430\u0432\u043B\u0435\u043D \u043C\u0438\u043C\u043E plan_edit.",
18187
+ "\u041F\u043E\u0441\u0447\u0438\u0442\u0430\u044E \u044D\u0444\u0444\u0435\u043A\u0442\u044B \u0438\u0441\u0445\u043E\u0434\u043D\u0438\u043A\u0430 (\u0432\u044B\u0440\u0435\u0437 \u0433\u0435\u0440\u043E\u044F, \u0448\u0443\u043C\u043E\u0434\u0430\u0432) \u0442\u0430\u043C, \u0433\u0434\u0435 \u0438\u0445 \u0432\u0438\u0434\u043D\u043E, \u2014 \u043F\u043E\u0442\u043E\u043C \u0441\u043E\u0431\u0435\u0440\u0443 \u043A\u0430\u0440\u0442\u0438\u043D\u043A\u0443 \u0438 \u0437\u0432\u0443\u043A."
18188
+ ];
18189
+ async function followWork(engine, asked, pace = realPace, tell) {
18190
+ const ask2 = () => engine.command(["job", asked.job]);
18191
+ const seconds2 = waitSeconds(asked.seconds ?? WAIT_LIMIT_SECONDS);
18192
+ if (seconds2 === 0) return asJobResult(await ask2());
18193
+ const state = await followJob({
18194
+ ask: ask2,
18195
+ seconds: seconds2,
18196
+ pace,
18197
+ // ⚠ Рассказ есть только если КЛИЕНТ его попросил (токен хода работы в
18198
+ // `_meta`). Нет — ждём молча и отвечаем итогом: ждать всё равно дешевле
18199
+ // пяти кругов переписки «спроси ещё раз».
18200
+ ...tell !== void 0 ? { tell } : {}
18201
+ });
18202
+ if (state.ok && stillWorking(state.text)) {
18203
+ const words = `${state.text}
18204
+ \u0416\u0434\u0430\u043B ${seconds2} \u0441, \u0440\u0430\u0431\u043E\u0442\u0430 \u0435\u0449\u0451 \u0438\u0434\u0451\u0442. \u0421\u043A\u0430\u0436\u0438 \u044D\u0442\u043E \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0443 \u0438 \u043F\u043E\u0437\u043E\u0432\u0438 wait \u0435\u0449\u0451 \u0440\u0430\u0437 \u2014 \u0442\u0430\u043A \u043E\u043D \u0443\u0441\u043B\u044B\u0448\u0438\u0442 \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0438\u0435 \u0448\u0430\u0433\u0438.`;
18205
+ const job = readJob(state.text);
18206
+ return job === null ? toolSuccess(words) : toolSuccess(words, job);
18207
+ }
18208
+ return asJobResult(state);
18209
+ }
18210
+ async function listJobs(engine, asked) {
18211
+ return asToolResult(
18212
+ await engine.command([
18213
+ "jobs",
18214
+ ...asked.video !== void 0 ? ["--video", path(asked.video)] : [],
18215
+ ...asked.limit !== void 0 ? ["--count", String(asked.limit)] : []
18216
+ ])
18217
+ );
18218
+ }
18219
+ function renderTool(engine, _passport, key) {
18220
+ return defineTool({
18221
+ name: "render",
18222
+ title: "\u0421\u043E\u0431\u0440\u0430\u0442\u044C \u0440\u043E\u043B\u0438\u043A",
18223
+ description: '\u0421\u043E\u0431\u0438\u0440\u0430\u0435\u0442 \u0441\u043E\u0433\u043B\u0430\u0441\u043E\u0432\u0430\u043D\u043D\u044B\u0439 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442 \u0440\u043E\u043B\u0438\u043A\u0430 \u043D\u0430 \u043A\u043E\u043C\u043F\u044C\u044E\u0442\u0435\u0440\u0435 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430: \u044D\u0444\u0444\u0435\u043A\u0442\u044B \u0438\u0441\u0445\u043E\u0434\u043D\u0438\u043A\u0430 (\u0432\u044B\u0440\u0435\u0437 \u0433\u0435\u0440\u043E\u044F, \u0448\u0443\u043C\u043E\u0434\u0430\u0432), \u043A\u0430\u0440\u0442\u0438\u043D\u043A\u0443, \u0437\u0432\u0443\u043A, \u0433\u043E\u0442\u043E\u0432\u044B\u0439 \u0444\u0430\u0439\u043B. \u0417\u043E\u0432\u0438 \u041F\u041E\u0421\u041B\u0415 \u0442\u043E\u0433\u043E, \u043A\u0430\u043A \u0447\u0435\u043B\u043E\u0432\u0435\u043A \u0441\u043A\u0430\u0437\u0430\u043B \xAB\u0434\u0430\xBB \u043D\u0430 \u0447\u0435\u0440\u043D\u043E\u0432\u0438\u043A \u0438\u0437 plan \u0438 \u0442\u044B \u0437\u0430\u043F\u0438\u0441\u0430\u043B \u044D\u0442\u043E plan_edit \u0441 {"op": "agree"}. \u0421\u043E\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044F \u0422\u041E\u041B\u042C\u041A\u041E \u0441\u043E\u0433\u043B\u0430\u0441\u043E\u0432\u0430\u043D\u043D\u044B\u0439 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442, \u0438 \u0442\u043E\u043B\u044C\u043A\u043E \u0437\u0430\u043F\u0438\u0441\u0430\u043D\u043D\u044B\u0439 \u0447\u0435\u0440\u0435\u0437 plan_edit: \u0444\u0430\u0439\u043B, \u043F\u043E\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u043D\u044B\u0439 \u043C\u0438\u043C\u043E \u043D\u0435\u0433\u043E, \u0434\u0432\u0438\u0436\u043E\u043A \u043D\u0435 \u0441\u043E\u0431\u0435\u0440\u0451\u0442 \u2014 \xAB\u043F\u0440\u0438\u0448\u043B\u0438 \u043F\u0440\u0430\u0432\u043A\u0443 \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u044F\u043C\u0438\xBB.\n\u041E\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u043D\u043E\u043C\u0435\u0440\u043E\u043C \u0437\u0430\u0434\u0430\u0447\u0438 \u2014 \u0434\u0430\u043B\u044C\u0448\u0435 wait, \u043E\u043D \u043F\u043E\u0434\u043E\u0436\u0434\u0451\u0442 \u0438 \u0440\u0430\u0441\u0441\u043A\u0430\u0436\u0435\u0442 \u0445\u043E\u0434. \u041F\u043E\u0432\u0442\u043E\u0440 \u0431\u0435\u0437 \u043F\u0440\u0430\u0432\u043E\u043A \u043E\u0442\u0434\u0430\u0451\u0442 \u0433\u043E\u0442\u043E\u0432\u043E\u0435 \u0441\u0440\u0430\u0437\u0443.\n\u041F\u0440\u043E\u0441\u044F\u0442 \xAB\u043F\u0440\u043E\u0441\u0442\u043E \u0443\u0431\u0435\u0440\u0438 \u043F\u0430\u0443\u0437\u044B\xBB \u2014 only_pauses=true \u0441 video: \u0447\u0435\u0440\u043D\u043E\u0432\u0438\u043A \u0441 \u043E\u0434\u043D\u0438\u043C\u0438 \u043F\u0430\u0443\u0437\u0430\u043C\u0438, \u0441\u043E\u0433\u043B\u0430\u0441\u0438\u0435 \u0438 \u0441\u0431\u043E\u0440\u043A\u0430 \u043E\u0434\u043D\u0438\u043C \u0432\u044B\u0437\u043E\u0432\u043E\u043C; tempo \u0440\u044F\u0434\u043E\u043C \u2014 \xAB\u0438 \u0443\u0441\u043A\u043E\u0440\u044C\xBB. \u041F\u0430\u0443\u0437\u044B \u0443\u0431\u0438\u0440\u0430\u044E\u0442\u0441\u044F \u043F\u043E \u0441\u043B\u043E\u0432\u0430\u043C, \u043F\u043E\u044D\u0442\u043E\u043C\u0443 \u043D\u0443\u0436\u043D\u0430 \u0440\u0430\u0441\u043F\u043E\u0437\u043D\u0430\u043D\u043D\u0430\u044F \u0440\u0435\u0447\u044C.\n\u0420\u0430\u0431\u043E\u0442\u0430 \u0438\u0434\u0451\u0442 \u043D\u0430 \u043A\u043E\u043C\u043F\u044C\u044E\u0442\u0435\u0440\u0435 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430, \u043A \u043D\u0430\u043C \u0432\u0438\u0434\u0435\u043E \u043D\u0435 \u0443\u0445\u043E\u0434\u0438\u0442 \u2014 \u043D\u0430\u0432\u0435\u0440\u0445 \u0438\u0434\u0451\u0442 \u0442\u043E\u043B\u044C\u043A\u043E \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0430 \u043F\u043E\u0434\u043F\u0438\u0441\u043A\u0438 \u043F\u043E \u043A\u043B\u044E\u0447\u0443.',
18224
+ // Полоса хода работы: монтаж идёт минутами, и всё это время в ленте не
18225
+ // происходило бы ничего. ⚠ Ожидание — у `wait`, и полосы там нет: иначе
18226
+ // каждая проверка рисовала бы новую поверх этой.
18227
+ ui: { resourceUri: RUNBAR_RESOURCE_URI },
18228
+ args: external_exports.object({
18229
+ video: external_exports.string().describe(
18230
+ "\u041F\u0443\u0442\u044C \u043A \u0432\u0438\u0434\u0435\u043E\u0444\u0430\u0439\u043B\u0443 \u0440\u043E\u043B\u0438\u043A\u0430. \u0417\u0430\u0432\u0435\u0434\u0451\u043D\u043D\u044B\u0439 \u0440\u043E\u043B\u0438\u043A \u043C\u043E\u0436\u043D\u043E \u043D\u0430\u0437\u0432\u0430\u0442\u044C \u0438 \u043F\u0430\u043F\u043A\u043E\u0439 \u2014 \u043A\u043B\u044E\u0447\u043E\u043C reel"
18231
+ ).optional(),
18232
+ reel: external_exports.string().describe(
18233
+ "\u041F\u0430\u043F\u043A\u0430 \u0440\u043E\u043B\u0438\u043A\u0430: \u0441\u043E\u0431\u0435\u0440\u0443 \u0435\u0433\u043E \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442 reel.json"
18234
+ ).optional(),
18235
+ only_pauses: external_exports.boolean().describe(
18236
+ "\u0422\u043E\u043B\u044C\u043A\u043E \u0443\u0431\u0440\u0430\u0442\u044C \u043F\u0430\u0443\u0437\u044B: \u0447\u0435\u0440\u043D\u043E\u0432\u0438\u043A \u0441 \u043E\u0434\u043D\u0438\u043C \u0440\u0430\u0437\u0434\u0435\u043B\u043E\u043C pauses, \u0441\u043E\u0433\u043B\u0430\u0441\u0438\u0435 \u0438 \u0441\u0431\u043E\u0440\u043A\u0430 \u0440\u0430\u0437\u043E\u043C"
18237
+ ).optional(),
18238
+ tempo: external_exports.number().describe(
18239
+ "\u0422\u043E\u043B\u044C\u043A\u043E \u0432\u043C\u0435\u0441\u0442\u0435 \u0441 only_pauses: \u0443\u0441\u043A\u043E\u0440\u0438\u0442\u044C \u0440\u0435\u0447\u044C, 1.0 \u2014 \u0431\u0435\u0437 \u0443\u0441\u043A\u043E\u0440\u0435\u043D\u0438\u044F"
18240
+ ).optional(),
18241
+ style: external_exports.string().describe(
18242
+ "\u0422\u043E\u043B\u044C\u043A\u043E \u0432\u043C\u0435\u0441\u0442\u0435 \u0441 only_pauses: \u043F\u0430\u043F\u043A\u0430 \u043F\u0430\u043A\u0430 \u0444\u0438\u0440\u043C\u0435\u043D\u043D\u043E\u0433\u043E \u0441\u0442\u0438\u043B\u044F"
18243
+ ).optional()
18244
+ }).check((ctx) => {
18245
+ const asked = ctx.value;
18246
+ const say = (message, where) => {
18247
+ ctx.issues.push({ code: "custom", message, input: asked, path: [where] });
18248
+ };
18249
+ if (asked.video === void 0 && asked.reel === void 0) {
18250
+ say(
18251
+ "\u041D\u0435 \u0441\u043A\u0430\u0437\u0430\u043D\u043E, \u0447\u0442\u043E \u0441\u043E\u0431\u0438\u0440\u0430\u0442\u044C: \u043D\u0430\u0437\u043E\u0432\u0438 video (\u0444\u0430\u0439\u043B) \u0438\u043B\u0438 reel (\u043F\u0430\u043F\u043A\u0443 \u0437\u0430\u0432\u0435\u0434\u0451\u043D\u043D\u043E\u0433\u043E \u0440\u043E\u043B\u0438\u043A\u0430). \u0427\u0442\u043E \u0443 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430 \u0435\u0441\u0442\u044C, \u043F\u043E\u043A\u0430\u0436\u0435\u0442 plan \u0431\u0435\u0437 \u0430\u0440\u0433\u0443\u043C\u0435\u043D\u0442\u043E\u0432",
18252
+ "video"
18253
+ );
18254
+ }
18255
+ if (asked.video !== void 0 && asked.reel !== void 0) {
18256
+ say("\xABvideo\xBB \u0438 \xABreel\xBB \u2014 \u044D\u0442\u043E \u043E\u0434\u043D\u043E \u0438 \u0442\u043E \u0436\u0435 \u043C\u0435\u0441\u0442\u043E, \u043D\u0430\u0437\u0432\u0430\u043D\u043D\u043E\u0435 \u0434\u0432\u0430\u0436\u0434\u044B. \u041E\u0441\u0442\u0430\u0432\u044C \u043E\u0434\u043D\u043E", "reel");
18257
+ }
18258
+ if (asked.only_pauses === true) return;
18259
+ const extra = ["tempo", "style"].filter((name) => asked[name] !== void 0);
18260
+ if (extra.length > 0) {
18261
+ say(
18262
+ `${extra.join(", ")} \u2014 \u0447\u0430\u0441\u0442\u044C \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0430, \u0430 \u043D\u0435 \u0441\u0431\u043E\u0440\u043A\u0438: \u0442\u0435\u043C\u043F \u2014 plan \u0441 ask {"tempo": \u2026} \u0438\u043B\u0438 plan_edit, \u0441\u0442\u0438\u043B\u044C \u2014 plan \u0441\u043E style. \u0417\u0434\u0435\u0441\u044C \u043E\u043D\u0438 \u0442\u043E\u043B\u044C\u043A\u043E \u0432\u043C\u0435\u0441\u0442\u0435 \u0441 only_pauses`,
18263
+ extra[0] ?? "tempo"
18264
+ );
18265
+ }
18266
+ }),
18267
+ async execute(args, ctx) {
18268
+ return startRender(
18269
+ engine,
18270
+ {
18271
+ video: args.video ?? args.reel ?? "",
18272
+ onlyPauses: args.only_pauses,
18273
+ tempo: args.tempo,
18274
+ style: args.style
18275
+ },
18276
+ key,
18277
+ ctx?.emitProgress
18278
+ );
18279
+ }
18280
+ });
18281
+ }
18282
+ function waitTool(engine, pace = realPace) {
18283
+ return defineTool({
18284
+ name: "wait",
18285
+ title: "\u0414\u043E\u0436\u0434\u0430\u0442\u044C\u0441\u044F \u0440\u0430\u0431\u043E\u0442\u044B",
18286
+ description: `\u0416\u0434\u0451\u0442 \u0437\u0430\u0434\u0430\u0447\u0443 \u0438 \u043F\u043E \u0445\u043E\u0434\u0443 \u0440\u0430\u0441\u0441\u043A\u0430\u0437\u044B\u0432\u0430\u0435\u0442, \u043A\u0430\u043A\u043E\u0439 \u0448\u0430\u0433 \u043F\u043E\u0448\u0451\u043B \u0438 \u043A\u0430\u043A\u043E\u0439 \u0437\u0430\u043A\u043E\u043D\u0447\u0438\u043B\u0441\u044F \u2014 \u043F\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, \u043D\u0435 \u0434\u043E\u0436\u0438\u0434\u0430\u044F\u0441\u044C \u043A\u043E\u043D\u0446\u0430. \u0422\u0430\u043A \u0438 \u0441\u043F\u0440\u0430\u0448\u0438\u0432\u0430\u0439: \u043E\u043F\u0440\u0430\u0448\u0438\u0432\u0430\u0442\u044C \u043F\u043E \u043A\u0440\u0443\u0433\u0443 \u043D\u0435 \u043D\u0430\u0434\u043E, \u0436\u0434\u0451\u0442 \u043E\u043D \u0434\u043E ${WAIT_LIMIT_SECONDS} \u0441\u0435\u043A\u0443\u043D\u0434 \u0438 \u0432\u0435\u0440\u043D\u0451\u0442\u0441\u044F \u0440\u0430\u043D\u044C\u0448\u0435, \u0435\u0441\u043B\u0438 \u0440\u0430\u0431\u043E\u0442\u0430 \u043A\u043E\u043D\u0447\u0438\u0442\u0441\u044F.
18287
+ \u0411\u0435\u0437 \u0430\u0440\u0433\u0443\u043C\u0435\u043D\u0442\u043E\u0432 \u043F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0435\u0442 \u043F\u043E\u0441\u043B\u0435\u0434\u043D\u0438\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 \u2014 \u043D\u043E\u043C\u0435\u0440, \u0440\u043E\u043B\u0438\u043A, \u0447\u0435\u043C \u043A\u043E\u043D\u0447\u0438\u043B\u043E\u0441\u044C. \u0417\u043E\u0432\u0438, \u043A\u043E\u0433\u0434\u0430 \u043D\u043E\u043C\u0435\u0440 \u043F\u043E\u0442\u0435\u0440\u044F\u043B\u0441\u044F: \u043D\u0430\u043F\u0440\u0438\u043C\u0435\u0440, \u043F\u043E\u0441\u043B\u0435 \u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u043A\u0430 \u043F\u0440\u043E\u0433\u0440\u0430\u043C\u043C\u044B \u0438\u043B\u0438 \u043A\u043E\u0433\u0434\u0430 \u0432\u044B\u0437\u043E\u0432 \u043E\u0431\u043E\u0440\u0432\u0430\u043B\u0441\u044F \u043F\u043E\u0441\u0440\u0435\u0434\u0438 \u0440\u0430\u0431\u043E\u0442\u044B. \u0421 video \u2014 \u0437\u0430\u0434\u0430\u0447\u0438 \u043E\u0434\u043D\u043E\u0433\u043E \u0440\u043E\u043B\u0438\u043A\u0430.
18288
+ \u0417\u0430\u0434\u0430\u0447\u0438 \u043B\u0435\u0436\u0430\u0442 \u043D\u0430 \u0434\u0438\u0441\u043A\u0435 \u0438 \u043F\u0435\u0440\u0435\u0436\u0438\u0432\u0430\u044E\u0442 \u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u043A \u043F\u0440\u043E\u0433\u0440\u0430\u043C\u043C\u044B. \u041F\u043E\u0434\u043F\u0438\u0441\u043A\u0430 \u043D\u0435 \u043D\u0443\u0436\u043D\u0430: \u0437\u0430\u0431\u0440\u0430\u0442\u044C \u0443\u0436\u0435 \u0441\u0434\u0435\u043B\u0430\u043D\u043D\u043E\u0435 \u043C\u043E\u0436\u043D\u043E \u0432\u0441\u0435\u0433\u0434\u0430.`,
18289
+ args: external_exports.object({
18290
+ job: external_exports.string().describe(
18291
+ "\u041D\u043E\u043C\u0435\u0440 \u0437\u0430\u0434\u0430\u0447\u0438, \u043D\u0430\u043F\u0440\u0438\u043C\u0435\u0440 2026-08-19T14-03-12Z-a3f1. \u0415\u0433\u043E \u043D\u0430\u0437\u0432\u0430\u043B \u0442\u043E\u0442 \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442, \u0447\u0442\u043E \u0437\u0430\u043F\u0443\u0441\u0442\u0438\u043B \u0440\u0430\u0431\u043E\u0442\u0443"
18292
+ ).optional(),
18293
+ seconds: external_exports.number().describe(
18294
+ `\u0421\u043A\u043E\u043B\u044C\u043A\u043E \u0441\u0435\u043A\u0443\u043D\u0434 \u0436\u0434\u0430\u0442\u044C. \u041F\u043E\u0442\u043E\u043B\u043E\u043A ${WAIT_LIMIT_SECONDS}: \u043F\u0440\u043E\u0441\u044C\u0431\u0430 \u0431\u043E\u043B\u044C\u0448\u0435 \u043C\u043E\u043B\u0447\u0430 \u043E\u0431\u0440\u0435\u0436\u0435\u0442\u0441\u044F. \u0411\u0435\u0437 \u043D\u0435\u0433\u043E \u0436\u0434\u0451\u0442 \u0441\u0442\u043E\u043B\u044C\u043A\u043E, \u0441\u043A\u043E\u043B\u044C\u043A\u043E \u043C\u043E\u0436\u043D\u043E`
18295
+ ).optional(),
18296
+ video: external_exports.string().describe("\u0422\u043E\u043B\u044C\u043A\u043E \u0437\u0430\u0434\u0430\u0447\u0438 \u044D\u0442\u043E\u0433\u043E \u0440\u043E\u043B\u0438\u043A\u0430 (\u0431\u0435\u0437 job)").optional(),
18297
+ limit: external_exports.number().describe("\u0421\u043A\u043E\u043B\u044C\u043A\u043E \u0437\u0430\u0434\u0430\u0447 \u043F\u043E\u043A\u0430\u0437\u0430\u0442\u044C, \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E 15").optional()
18298
+ }).check((ctx) => {
18299
+ const asked = ctx.value;
18300
+ if (asked.job === void 0) {
18301
+ if (asked.seconds !== void 0) {
18302
+ ctx.issues.push({
18303
+ code: "custom",
18304
+ message: "\xABseconds\xBB \u2014 \u044D\u0442\u043E \u0441\u043A\u043E\u043B\u044C\u043A\u043E \u0436\u0434\u0430\u0442\u044C \u041E\u0414\u041D\u0423 \u0437\u0430\u0434\u0430\u0447\u0443: \u043D\u0430\u0437\u043E\u0432\u0438 \u0435\u0451 \u043D\u043E\u043C\u0435\u0440 \u0432 \xABjob\xBB",
18305
+ input: asked,
18306
+ path: ["seconds"]
18307
+ });
18308
+ }
18309
+ return;
18310
+ }
18311
+ for (const key of ["video", "limit"]) {
18312
+ if (asked[key] !== void 0) {
18313
+ ctx.issues.push({
18314
+ code: "custom",
18315
+ message: `\xAB${key}\xBB \u043E\u0442\u043D\u043E\u0441\u0438\u0442\u0441\u044F \u043A \u0421\u041F\u0418\u0421\u041A\u0423 \u0437\u0430\u0434\u0430\u0447, \u0430 \u0441 \xABjob\xBB \u0436\u0434\u0443\u0442 \u043E\u0434\u043D\u0443. \u041F\u043E\u0437\u043E\u0432\u0438 \u0431\u0435\u0437 \xABjob\xBB, \u0447\u0442\u043E\u0431\u044B \u0443\u0432\u0438\u0434\u0435\u0442\u044C \u0441\u043F\u0438\u0441\u043E\u043A`,
18316
+ input: asked,
18317
+ path: [key]
18318
+ });
18319
+ }
18320
+ }
18321
+ }),
18322
+ readOnly: true,
18323
+ async execute(args, ctx) {
18324
+ const place = engine.place();
18325
+ if (place === null) return toolError(engine.whyNoEngine());
18326
+ if (args.job === void 0) {
18327
+ return listJobs(engine, { video: args.video, limit: args.limit });
18328
+ }
18329
+ return followWork(engine, { job: args.job, seconds: args.seconds }, pace, ctx?.emitProgress);
18330
+ }
18331
+ });
18332
+ }
18333
+ async function listReels(engine, workspace) {
18334
+ const place = engine.place();
18335
+ if (place === null) return toolError(engine.whyNoEngine());
18336
+ const answer = await engine.command([
18337
+ "reels",
18338
+ "--json",
18339
+ ...workspace !== void 0 ? ["--workspace", path(workspace)] : []
18340
+ ]);
18341
+ if (!answer.ok) return toolError(answer.text);
18342
+ return folderAnswer(answer.text);
18343
+ }
18344
+ async function openReel(engine, asked) {
18345
+ const place = engine.place();
18346
+ if (place === null) return toolError(engine.whyNoEngine());
18347
+ if (asked.files.length === 0) {
18348
+ return toolError(
18349
+ "\u0417\u0430\u0432\u043E\u0434\u0438\u0442\u044C \u0440\u043E\u043B\u0438\u043A \u043D\u0435 \u0438\u0437 \u0447\u0435\u0433\u043E: \u043D\u0435 \u043D\u0430\u0437\u0432\u0430\u043D\u043E \u043D\u0438 \u043E\u0434\u043D\u043E\u0433\u043E \u0444\u0430\u0439\u043B\u0430.\n\u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C: \u0441\u043F\u0440\u043E\u0441\u0438 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430, \u043A\u0430\u043A\u043E\u0439 \u0444\u0430\u0439\u043B \u043C\u043E\u043D\u0442\u0438\u0440\u0443\u0435\u043C, \u0438\u043B\u0438 \u043F\u043E\u0437\u043E\u0432\u0438 plan \u2014 \u0442\u0430\u043C \u0432\u0438\u0434\u043D\u043E, \u0447\u0442\u043E \u0432 \u043F\u0430\u043F\u043A\u0435 \u043B\u0435\u0436\u0438\u0442."
18350
+ );
18351
+ }
18352
+ const where = [];
18353
+ for (const one of asked.files) {
18354
+ const found = fileOrRefusal(one);
18355
+ if ("refusal" in found) return toolError(found.refusal);
18356
+ where.push(found.path);
18357
+ }
18358
+ const answer = await engine.command([
18359
+ "reel-open",
18360
+ ...where,
18361
+ "--json",
18362
+ ...asked.workspace !== void 0 ? ["--workspace", path(asked.workspace)] : [],
18363
+ ...asked.together === true ? ["--together"] : []
18364
+ ]);
18365
+ if (!answer.ok) return toolError(answer.text);
18366
+ return folderAnswer(answer.text);
18367
+ }
18368
+ var SKILLS_READ = "naparnik-skills-read/1";
18369
+ async function readSkills(engine, asked) {
18370
+ const place = engine.place();
18371
+ if (place === null) return toolError(engine.whyNoEngine());
18372
+ const answer = await engine.command([
18373
+ "skills-read",
17798
18374
  ...asked.files,
17799
18375
  "--pack",
17800
18376
  place.pack,
@@ -17805,19 +18381,21 @@ async function readSkills(engine, asked) {
17805
18381
  const read = answerOrRefusal(answer.text, SKILLS_READ);
17806
18382
  return "refusal" in read ? toolError(read.refusal) : toolSuccess(read.words, read.data);
17807
18383
  }
17808
- async function viewComposition(engine, reel) {
18384
+ async function viewDocument(engine, reel) {
17809
18385
  const place = engine.place();
17810
18386
  if (place === null) return toolError(engine.whyNoEngine());
17811
18387
  const where = fileOrRefusal(reel);
17812
18388
  if ("refusal" in where) return toolError(where.refusal);
17813
18389
  const answer = await engine.command([
17814
- "composition-view",
18390
+ "document-view",
17815
18391
  "--project",
17816
18392
  path(where.path),
18393
+ "--pack",
18394
+ place.pack,
17817
18395
  "--json"
17818
18396
  ]);
17819
18397
  if (!answer.ok) return toolError(answer.text);
17820
- const read = answerOrRefusal(answer.text, COMPOSITION_VIEW);
18398
+ const read = answerOrRefusal(answer.text, VIEW_CONTRACT);
17821
18399
  return "refusal" in read ? toolError(read.refusal) : toolSuccess(read.words, read.data);
17822
18400
  }
17823
18401
  async function whereToDraft(engine, video, also, workspace) {
@@ -17888,91 +18466,51 @@ async function planDraft(engine, asked, key, tell) {
17888
18466
 
17889
18467
  ` : "";
17890
18468
  const withHead = (text2) => `${head2}${text2}`;
17891
- const answer = await engine.command([
17892
- "plan-draft",
17893
- "--video",
17894
- plan.speech,
17895
- "--pack",
17896
- place.pack,
17897
- ...asked.style !== void 0 ? ["--style", path(asked.style)] : [],
17898
- "--json"
17899
- ], key !== void 0 ? { key } : {});
17900
- if (!answer.ok) return toolError(withHead(answer.text));
17901
- const read = answerOrRefusal(answer.text, PLAN_DRAFT);
18469
+ const also = plan.toOpen.length > 0 ? [] : asked.also ?? [];
18470
+ const read = await draftDocument(
18471
+ engine,
18472
+ place,
18473
+ { video: plan.speech, style: asked.style, ask: asked.ask, also },
18474
+ key
18475
+ );
17902
18476
  if ("refusal" in read) return toolError(withHead(read.refusal));
17903
- return toolSuccess(withHead(read.words), read.data);
18477
+ return withSheets(withHead(read.words), read.data);
18478
+ }
18479
+ async function withSheets(text2, data) {
18480
+ const material = data["material"];
18481
+ const images = Array.isArray(material?.images) ? material.images.filter((one) => typeof one === "string") : [];
18482
+ if (images.length === 0) return toolSuccess(text2, data);
18483
+ const pictures = [];
18484
+ const lost = [];
18485
+ for (const file2 of images) {
18486
+ try {
18487
+ pictures.push({ type: "image", base64: (await readFile(file2)).toString("base64"), mediaType: "image/jpeg" });
18488
+ } catch {
18489
+ lost.push(basename(file2));
18490
+ }
18491
+ }
18492
+ const told = lost.length === 0 ? text2 : `${text2}
18493
+ \u26A0 \u0421\u0435\u0442\u043A\u0430 \u0440\u0430\u0441\u043A\u0430\u0434\u0440\u043E\u0432\u043A\u0438 \u043D\u0435 \u043F\u0440\u043E\u0447\u0438\u0442\u0430\u043B\u0430\u0441\u044C: ${lost.join(", ")}. \u041A\u0430\u0434\u0440 \u0438\u0441\u0445\u043E\u0434\u043D\u0438\u043A\u0430 \u043F\u043E\u043A\u0430\u0436\u0435\u0442 preview \u0441 video, moment \u0438 from_where=source.`;
18494
+ return toolMixed([{ type: "text", text: told }, ...pictures], data);
17904
18495
  }
17905
18496
  var DRAFT_LADDER = [
17906
- "\u0421\u043D\u0430\u0447\u0430\u043B\u0430 \u0440\u0430\u0437\u0431\u0435\u0440\u0443 \u0440\u0435\u0447\u044C: \u0443\u0431\u0435\u0440\u0443 \u043F\u0430\u0443\u0437\u044B, \u0440\u0430\u0441\u043F\u043E\u0437\u043D\u0430\u044E \u0441\u043B\u043E\u0432\u0430, \u0440\u0430\u0437\u043B\u043E\u0436\u0443 \u0438\u0445 \u043D\u0430 \u0444\u0440\u0430\u0437\u044B.",
17907
- "\u041F\u043E\u0442\u043E\u043C \u043F\u0440\u0438\u0434\u0443\u043C\u0430\u044E, \u0447\u0442\u043E \u043F\u043E\u043A\u0430\u0437\u0430\u0442\u044C \u0438 \u043A\u043E\u0433\u0434\u0430, \u2014 \u0438 \u043F\u043E\u043A\u0430\u0436\u0443 \u044D\u0442\u043E \u0441\u043B\u043E\u0432\u0430\u043C\u0438, \u0434\u043E \u0441\u0431\u043E\u0440\u043A\u0438.",
17908
- "\u041F\u0435\u0440\u0432\u044B\u0439 \u0440\u0430\u0437 \u0438\u0434\u0451\u0442 \u043C\u0438\u043D\u0443\u0442\u0430\u043C\u0438: \u0440\u0430\u0441\u043F\u043E\u0437\u043D\u0430\u0432\u0430\u043D\u0438\u0435 \u0440\u0435\u0447\u0438 \u0441\u0430\u043C\u043E\u0435 \u0434\u043E\u043B\u0433\u043E\u0435. \u041E\u0431\u043E\u0440\u0432\u0451\u0442\u0441\u044F \u2014 \u043F\u043E\u0437\u043E\u0432\u0438 wait, \u0440\u0430\u0431\u043E\u0442\u0430 \u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0430\u0435\u0442\u0441\u044F, \u0430 \u043F\u043E\u0432\u0442\u043E\u0440\u043D\u044B\u0439 \u043F\u043B\u0430\u043D \u0441\u0442\u043E\u0438\u0442 \u0441\u0435\u043A\u0443\u043D\u0434."
18497
+ "\u0421\u043D\u0430\u0447\u0430\u043B\u0430 \u0440\u0430\u0441\u043F\u043E\u0437\u043D\u0430\u044E \u0440\u0435\u0447\u044C \u2014 \u0435\u0441\u043B\u0438 \u043F\u0440\u043E\u0441\u044C\u0431\u0435 \u043E\u043D\u0430 \u043D\u0443\u0436\u043D\u0430.",
18498
+ "\u041F\u043E\u0442\u043E\u043C \u0441\u043E\u0431\u0435\u0440\u0443 \u0447\u0435\u0440\u043D\u043E\u0432\u0438\u043A \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0430: \u043F\u0430\u0443\u0437\u044B, \u043F\u043E\u0434\u043F\u0438\u0441\u0438, \u043A\u0440\u0443\u043F\u043D\u043E\u0441\u0442\u0438, \u0437\u0432\u0443\u043A \u2014 \u0442\u043E\u043B\u044C\u043A\u043E \u0442\u043E, \u0447\u0442\u043E \u043F\u0440\u043E\u0441\u0438\u043B\u0438.",
18499
+ "\u041F\u0435\u0440\u0432\u044B\u0439 \u0440\u0430\u0437 \u0438\u0434\u0451\u0442 \u043C\u0438\u043D\u0443\u0442\u0430\u043C\u0438: \u0440\u0430\u0441\u043F\u043E\u0437\u043D\u0430\u0432\u0430\u043D\u0438\u0435 \u0440\u0435\u0447\u0438 \u0441\u0430\u043C\u043E\u0435 \u0434\u043E\u043B\u0433\u043E\u0435. \u041E\u0431\u043E\u0440\u0432\u0451\u0442\u0441\u044F \u2014 \u043F\u043E\u0437\u043E\u0432\u0438 wait, \u0440\u0430\u0431\u043E\u0442\u0430 \u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0430\u0435\u0442\u0441\u044F, \u0430 \u043F\u043E\u0432\u0442\u043E\u0440\u043D\u044B\u0439 \u0447\u0435\u0440\u043D\u043E\u0432\u0438\u043A \u0441\u0442\u043E\u0438\u0442 \u0441\u0435\u043A\u0443\u043D\u0434."
17909
18500
  ];
17910
- function aboutAgreement(said) {
17911
- const lines = [];
17912
- if (said.agreed === true) lines.push("\u041F\u043B\u0430\u043D \u0441\u043E\u0433\u043B\u0430\u0441\u043E\u0432\u0430\u043D \u2014 \u043C\u043E\u0436\u043D\u043E \u0441\u043E\u0431\u0438\u0440\u0430\u0442\u044C.");
17913
- if (said.agreed === false) {
17914
- lines.push(
17915
- "\u0421\u043E\u0433\u043B\u0430\u0441\u0438\u044F \u043D\u0435\u0442: \u044D\u0442\u043E\u0439 \u0440\u0435\u0434\u0430\u043A\u0446\u0438\u0438 \u0447\u0435\u043B\u043E\u0432\u0435\u043A \u0435\u0449\u0451 \u043D\u0435 \u0432\u0438\u0434\u0435\u043B. \u041F\u0435\u0440\u0435\u0441\u043A\u0430\u0436\u0438 \u0435\u043C\u0443, \u0447\u0442\u043E \u0432\u044B\u0448\u043B\u043E, \u0438 \u043D\u0430 \xAB\u0434\u0430\xBB \u043F\u043E\u0437\u043E\u0432\u0438 plan_edit \u0441 confirm \u2014 \u043C\u043E\u0436\u043D\u043E \u0442\u0435\u043C \u0436\u0435 \u0432\u044B\u0437\u043E\u0432\u043E\u043C, \u0447\u0442\u043E \u0438 \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0443\u044E \u043F\u0440\u0430\u0432\u043A\u0443."
17916
- );
17917
- }
17918
- if (said.plan_mine === true) {
17919
- lines.push(
17920
- "\u041F\u043B\u0430\u043D \u0440\u043E\u043B\u0438\u043A\u0430 \u0442\u0435\u043F\u0435\u0440\u044C \u0422\u0412\u041E\u0419: \u0441\u043E\u0431\u0438\u0440\u0430\u0442\u044C\u0441\u044F \u0431\u0443\u0434\u0435\u0442 \u043E\u043D, \u043D\u0430\u0448 \u0447\u0435\u0440\u043D\u043E\u0432\u0438\u043A \u0431\u043E\u043B\u044C\u0448\u0435 \u043D\u0435 \u043F\u0440\u0438\u043C\u0435\u043D\u044F\u0435\u0442\u0441\u044F. \u0412\u0435\u0440\u043D\u0443\u0442\u044C \u043D\u0430\u0448 \u2014 plan_edit \u0441 draft."
17921
- );
17922
- }
17923
- return lines;
17924
- }
17925
- async function editPlan(engine, asked, key, tell) {
18501
+ async function editDocument(engine, asked, key, tell) {
17926
18502
  const place = engine.place();
17927
18503
  if (place === null) return toolError(engine.whyNoEngine());
17928
- const asked_ = await engine.command([
17929
- "plan-edit",
17930
- "--project",
17931
- path(asked.reel),
17932
- ...asked.ops.length > 0 ? ["--ops", JSON.stringify(asked.ops)] : [],
17933
- ...asked.plan !== void 0 ? ["--plan", JSON.stringify(asked.plan)] : [],
17934
- ...asked.project !== void 0 ? ["--composition", JSON.stringify(asked.project)] : [],
17935
- ...asked.draft === true ? ["--draft"] : [],
17936
- ...asked.confirm === true ? ["--confirm"] : [],
17937
- "--by",
17938
- asked.by ?? "model",
17939
- "--json"
17940
- ], key !== void 0 ? { key } : {});
17941
- if (!asked_.ok) return toolError(asked_.text);
17942
- let said;
17943
- try {
17944
- said = JSON.parse(lastLine(asked_.text));
17945
- } catch {
17946
- return toolSuccess(asked_.text);
17947
- }
17948
- const many = (said.overrides ?? []).length;
17949
- const done = typeof said.words === "string" && said.words !== "" ? said.words : [
17950
- `\u041F\u0440\u0430\u0432\u043E\u043A \u0432 \u043F\u043B\u0430\u043D\u0435 \u0440\u043E\u043B\u0438\u043A\u0430: ${many}. \u0420\u043E\u043B\u0438\u043A: ${said.project ?? asked.reel}`,
17951
- ...aboutAgreement(said)
17952
- ].join("\n");
17953
- if (asked.rebuild !== true) {
17954
- return toolSuccess(
17955
- `${done}
17956
- \u0427\u0442\u043E\u0431\u044B \u0443\u0432\u0438\u0434\u0435\u0442\u044C \u0440\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442, \u043F\u043E\u0437\u043E\u0432\u0438 plan_edit \u0435\u0449\u0451 \u0440\u0430\u0437 \u0441 rebuild \u0438\u043B\u0438 \u0441\u043E\u0431\u0435\u0440\u0438 render \u2014 \u043F\u0435\u0440\u0435\u0441\u0431\u043E\u0440\u043A\u0430 \u0438\u0437 \u043A\u044D\u0448\u0430 \u0441\u0442\u043E\u0438\u0442 \u0441\u0435\u043A\u0443\u043D\u0434.`
17957
- );
17958
- }
17959
- if (said.video === null || said.video === void 0) {
17960
- return toolError(
17961
- `${done}
17962
- \u0410 \u043F\u0435\u0440\u0435\u0441\u043E\u0431\u0440\u0430\u0442\u044C \u043D\u0435\u0447\u0435\u043C: \u0432 \u0431\u0440\u0438\u0444\u0435 \u0440\u043E\u043B\u0438\u043A\u0430 \u043D\u0435 \u0437\u0430\u043F\u0438\u0441\u0430\u043D \u0444\u0430\u0439\u043B \u0441 \u0440\u0435\u0447\u044C\u044E.
17963
- \u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C: \u043F\u043E\u0437\u043E\u0432\u0438 render \u0441 \u043F\u0443\u0442\u0451\u043C \u043A \u0432\u0438\u0434\u0435\u043E \u2014 \u043E\u043D \u0438 \u0437\u0430\u043F\u0438\u0448\u0435\u0442 \u0444\u0430\u0439\u043B \u0432 \u0431\u0440\u0438\u0444.`
17964
- );
17965
- }
17966
- return startMontage(engine, {
17967
- key,
17968
- place,
17969
- ...tell !== void 0 ? { tell } : {},
17970
- video: said.video,
17971
- what: `\u043F\u0440\u0430\u0432\u043A\u0430 ${basename(said.video)}`,
17972
- command: { "tool": "montage", "args": {} },
17973
- args: [],
17974
- hint: "\u041F\u0440\u0430\u0432\u043A\u0430 \u043F\u043B\u0430\u043D\u0430: \u0437\u0430\u043D\u043E\u0432\u043E \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044F \u0442\u043E\u043B\u044C\u043A\u043E \u0442\u0440\u043E\u043D\u0443\u0442\u043E\u0435, \u043E\u0431\u044B\u0447\u043D\u043E \u0441\u0435\u043A\u0443\u043D\u0434\u044B."
17975
- });
18504
+ const read = await editOperations(engine, place, asked, key);
18505
+ if ("refusal" in read) return toolError(read.refusal);
18506
+ if (asked.rebuild !== true) return toolSuccess(read.words, read.data);
18507
+ const project = typeof read.data["project"] === "string" ? read.data["project"] : asked.reel;
18508
+ const started = await startDocumentRender(engine, project, key, tell);
18509
+ if (started.type === "error") return started;
18510
+ const text2 = typeof started.content === "string" ? started.content : "";
18511
+ return toolSuccess(`${read.words}
18512
+
18513
+ ${text2}`, started.structured);
17976
18514
  }
17977
18515
  var RECIPE_CONTRACT = "naparnik-recipe-view/1";
17978
18516
  var STEP_NEEDS = {
@@ -18042,7 +18580,11 @@ function planTool(engine, key) {
18042
18580
  return defineTool({
18043
18581
  name: "plan",
18044
18582
  title: "\u0427\u0442\u043E \u043F\u043E\u043A\u0430\u0436\u0435\u043C \u0432 \u0440\u043E\u043B\u0438\u043A\u0435",
18045
- description: "\u0427\u0435\u0440\u043D\u043E\u0432\u0438\u043A \u0440\u043E\u043B\u0438\u043A\u0430 \u0421\u041B\u041E\u0412\u0410\u041C\u0418 \u2014 \u0434\u043E \u0441\u0431\u043E\u0440\u043A\u0438. \u0411\u0435\u0437 \u0430\u0440\u0433\u0443\u043C\u0435\u043D\u0442\u043E\u0432 \u043F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0435\u0442, \u0447\u0442\u043E \u0443 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430 \u0432 \u043F\u0430\u043F\u043A\u0435: \u0440\u043E\u043B\u0438\u043A\u0438 \u0441 \u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u0435\u043C \u0438 \u0444\u0430\u0439\u043B\u044B, \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u0440\u043E\u043B\u0438\u043A\u043E\u043C \u0435\u0449\u0451 \u043D\u0435 \u0441\u0442\u0430\u043B\u0438. \u0417\u043E\u0432\u0438 \u043F\u0435\u0440\u0432\u044B\u043C, \u043A\u043E\u0433\u0434\u0430 \u043D\u0435 \u0437\u043D\u0430\u0435\u0448\u044C, \u043E \u043A\u0430\u043A\u043E\u043C \u0440\u043E\u043B\u0438\u043A\u0435 \u0440\u0435\u0447\u044C: \u0434\u043E\u0433\u0430\u0434\u043A\u0430 \u0442\u0443\u0442 \u0434\u043E\u0440\u043E\u0436\u0435 \u0432\u043E\u043F\u0440\u043E\u0441\u0430.\n\u0421 video \u0437\u0430\u0432\u043E\u0434\u0438\u0442 \u0440\u043E\u043B\u0438\u043A (\u0435\u0441\u043B\u0438 \u044D\u0442\u043E\u0442 \u0444\u0430\u0439\u043B \u0435\u0449\u0451 \u043D\u0435 \u0432 \u0440\u043E\u043B\u0438\u043A\u0435) \u0438 \u043F\u0440\u0438\u0434\u0443\u043C\u044B\u0432\u0430\u0435\u0442 \u0447\u0435\u0440\u043D\u043E\u0432\u0438\u043A: \u0447\u0442\u043E \u043F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0435\u043C \u0438 \u043A\u043E\u0433\u0434\u0430, \u043D\u043E\u043C\u0435\u0440\u0430 \u0441\u043B\u043E\u0432 \u043D\u0430 \u0433\u0440\u0430\u043D\u0438\u0446\u0430\u0445, \u0438\u043C\u044F \u043A\u0430\u0436\u0434\u043E\u0439 \u0432\u0441\u0442\u0430\u0432\u043A\u0438, \u0434\u0432\u0438\u0436\u0435\u043D\u0438\u0435 \u0441\u043B\u043E\u0432\u0430\u043C\u0438 \u0438 \u043F\u0443\u0441\u0442\u044B\u0435 \u043F\u043E\u0434\u043F\u0438\u0441\u0438, \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u043D\u0430\u0434\u043E \u043F\u0440\u0438\u0434\u0443\u043C\u0430\u0442\u044C. \u0422\u0435\u043C \u0436\u0435 \u043E\u0442\u0432\u0435\u0442\u043E\u043C \u043D\u0430\u0437\u044B\u0432\u0430\u0435\u0442, \u0427\u0422\u041E \u043F\u0440\u043E\u0447\u0438\u0442\u0430\u0442\u044C \u043F\u043E\u0434 \u044D\u0442\u043E\u0442 \u0440\u043E\u043B\u0438\u043A: \u043F\u0440\u043E\u0447\u0442\u0438 \u044D\u0442\u043E (plan \u0441 read), \u043E\u0431\u0441\u0443\u0434\u0438 \u0447\u0435\u0440\u043D\u043E\u0432\u0438\u043A \u0441 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u043E\u043C, \u043F\u043E\u043F\u0440\u0430\u0432\u044C plan_edit \u0438 \u0442\u043E\u043B\u044C\u043A\u043E \u043F\u043E\u0441\u043B\u0435 \u0435\u0433\u043E \xAB\u0434\u0430\xBB \u0437\u043E\u0432\u0438 render.\n\u041F\u0435\u0440\u0432\u044B\u0439 \u0447\u0435\u0440\u043D\u043E\u0432\u0438\u043A \u0438\u0434\u0451\u0442 \u043C\u0438\u043D\u0443\u0442\u0430\u043C\u0438: \u0440\u0430\u0441\u043F\u043E\u0437\u043D\u0430\u0451\u0442\u0441\u044F \u0440\u0435\u0447\u044C. \u041E\u0431\u043E\u0440\u0432\u0430\u043B\u0441\u044F \u0432\u044B\u0437\u043E\u0432 \u2014 \u0440\u0430\u0431\u043E\u0442\u0430 \u043D\u0435 \u043F\u0440\u043E\u043F\u0430\u043B\u0430: \u043F\u043E\u0437\u043E\u0432\u0438 wait, \u0430 \u043F\u043E\u0442\u043E\u043C plan \u043F\u043E \u0442\u043E\u043C\u0443 \u0436\u0435 \u0440\u043E\u043B\u0438\u043A\u0443 \u0435\u0449\u0451 \u0440\u0430\u0437, \u0432\u0442\u043E\u0440\u043E\u0439 \u0440\u0430\u0437 \u044D\u0442\u043E \u0441\u0435\u043A\u0443\u043D\u0434\u044B.\n\u0421 reel \u043F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0435\u0442 \u0441\u043E\u0445\u0440\u0430\u043D\u0451\u043D\u043D\u044B\u0439 \u043E\u0431\u0449\u0438\u0439 naparnik-project/1 \u0446\u0435\u043B\u0438\u043A\u043E\u043C \u0438 \u0433\u043E\u0432\u043E\u0440\u0438\u0442, \u0441\u043E\u0433\u043B\u0430\u0441\u043E\u0432\u0430\u043D\u0430 \u043B\u0438 \u0438\u043C\u0435\u043D\u043D\u043E \u044D\u0442\u0430 \u0440\u0435\u0434\u0430\u043A\u0446\u0438\u044F.\n\u0421 read \u043E\u0442\u0434\u0430\u0451\u0442 \u0442\u0435\u043A\u0441\u0442 \u043D\u0430\u0437\u0432\u0430\u043D\u043D\u044B\u0445 \u0444\u0430\u0439\u043B\u043E\u0432 \u0441\u043A\u0438\u043B\u043B\u043E\u0432 \u0438 \u0437\u043D\u0430\u043D\u0438\u0439 \u2014 \u0442\u0435\u0445, \u0447\u0442\u043E \u043D\u0430\u0437\u0432\u0430\u043B \u0447\u0435\u0440\u043D\u043E\u0432\u0438\u043A. \u0427\u0438\u0442\u0430\u0439 \u043F\u043E 3\u20134 \u0437\u0430 \u0432\u044B\u0437\u043E\u0432 \u0438 \u043D\u0435 \u0432\u044B\u0434\u0443\u043C\u044B\u0432\u0430\u0439 \u043F\u0443\u0442\u0435\u0439: \u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044F \u0442\u043E\u043B\u044C\u043A\u043E \u0442\u043E, \u0447\u0442\u043E \u043D\u0430\u0437\u0432\u0430\u043D\u043E.",
18583
+ description: `\u0427\u0435\u0440\u043D\u043E\u0432\u0438\u043A \u0440\u043E\u043B\u0438\u043A\u0430 \u2014 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442 \u043C\u043E\u043D\u0442\u0430\u0436\u0430 reel.json \u0438 \u0435\u0433\u043E \u043F\u0435\u0440\u0435\u0441\u043A\u0430\u0437 \u0441\u043B\u043E\u0432\u0430\u043C\u0438, \u0434\u043E \u0441\u0431\u043E\u0440\u043A\u0438. \u0411\u0435\u0437 \u0430\u0440\u0433\u0443\u043C\u0435\u043D\u0442\u043E\u0432 \u043F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0435\u0442, \u0447\u0442\u043E \u0443 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430 \u0432 \u043F\u0430\u043F\u043A\u0435: \u0440\u043E\u043B\u0438\u043A\u0438 \u0441 \u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u0435\u043C \u0438 \u0444\u0430\u0439\u043B\u044B, \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u0440\u043E\u043B\u0438\u043A\u043E\u043C \u0435\u0449\u0451 \u043D\u0435 \u0441\u0442\u0430\u043B\u0438. \u0417\u043E\u0432\u0438 \u043F\u0435\u0440\u0432\u044B\u043C, \u043A\u043E\u0433\u0434\u0430 \u043D\u0435 \u0437\u043D\u0430\u0435\u0448\u044C, \u043E \u043A\u0430\u043A\u043E\u043C \u0440\u043E\u043B\u0438\u043A\u0435 \u0440\u0435\u0447\u044C.
18584
+ \u0421 video \u0437\u0430\u0432\u043E\u0434\u0438\u0442 \u0440\u043E\u043B\u0438\u043A (\u0435\u0441\u043B\u0438 \u0444\u0430\u0439\u043B \u0435\u0449\u0451 \u043D\u0435 \u0432 \u0440\u043E\u043B\u0438\u043A\u0435) \u0438 \u0441\u043E\u0431\u0438\u0440\u0430\u0435\u0442 \u0447\u0435\u0440\u043D\u043E\u0432\u0438\u043A: \u043F\u043E\u0441\u0442\u0430\u0432\u0449\u0438\u043A\u0438 \u043A\u043B\u0430\u0434\u0443\u0442 \u043A\u043B\u0438\u043F\u044B \u043F\u043E \u0440\u0430\u0437\u0434\u0435\u043B\u0430\u043C \u043F\u0440\u043E\u0441\u044C\u0431\u044B. \u0423\u0437\u043A\u0430\u044F \u043F\u0440\u043E\u0441\u044C\u0431\u0430 \u2014 ask \u0441 \u0435\u0451 \u0440\u0430\u0437\u0434\u0435\u043B\u0430\u043C\u0438: {"tempo": 1.2} \u2014 \xAB\u0443\u0441\u043A\u043E\u0440\u044C \u0432 1,2 \u0440\u0430\u0437\u0430\xBB (\u0447\u0438\u0441\u043B\u043E \u043D\u0430\u0437\u044B\u0432\u0430\u0435\u0442 \u0447\u0435\u043B\u043E\u0432\u0435\u043A), {"loudness": {}, "voice": {}} \u2014 \xAB\u043F\u043E\u0434\u043D\u0438\u043C\u0438 \u0433\u0440\u043E\u043C\u043A\u043E\u0441\u0442\u044C \u0438 \u0443\u0431\u0435\u0440\u0438 \u0448\u0443\u043C\xBB; \u0440\u0430\u0437\u0434\u0435\u043B \u0441\u043E \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435\u043C true \u2014 \xAB\u043A\u0430\u043A \u0440\u0435\u0448\u0438\u0442 \u0447\u0435\u0440\u043D\u043E\u0432\u0438\u043A\xBB. ask \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u0435\u043D: \xAB\u0441\u043C\u043E\u043D\u0442\u0438\u0440\u0443\u0439\xBB \u0446\u0435\u043B\u0438\u043A\u043E\u043C \u2014 ${FULL_WORDS}. \u041F\u043E\u043B\u043D\u044B\u0439 \u0447\u0435\u0440\u043D\u043E\u0432\u0438\u043A \u0438 \u043F\u0440\u043E\u0441\u044C\u0431\u0430 \u043F\u0440\u043E \u043A\u0430\u0434\u0440 \u043F\u0440\u0438\u043D\u043E\u0441\u044F\u0442 \u043C\u0430\u0442\u0435\u0440\u0438\u0430\u043B: \u0444\u0430\u0439\u043B\u044B \u0441\u043B\u043E\u0432\u0430\u043C\u0438 \u0438 \u0440\u0430\u0441\u043A\u0430\u0434\u0440\u043E\u0432\u043A\u0443 \u043A\u0430\u0440\u0442\u0438\u043D\u043A\u0430\u043C\u0438 \u2014 \u043F\u043E\u0441\u043C\u043E\u0442\u0440\u0438 \u0434\u043E \u043F\u043B\u0430\u043D\u0430. \u041F\u043E\u0441\u043B\u0435\u0434\u043D\u0438\u043C \u0431\u043B\u043E\u043A\u043E\u043C \u0447\u0435\u0440\u043D\u043E\u0432\u0438\u043A \u043D\u0430\u0437\u044B\u0432\u0430\u0435\u0442 2\u20134 \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u044B \u0441\u043F\u0440\u0430\u0432\u043E\u0447\u043D\u0438\u043A\u0430: \u043F\u0440\u043E\u0447\u0442\u0438 \u0438\u0445 (plan \u0441 read), \u043F\u0435\u0440\u0435\u0441\u043A\u0430\u0436\u0438 \u0447\u0435\u0440\u043D\u043E\u0432\u0438\u043A \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0443 \u043F\u043E\u0441\u0442\u0440\u043E\u0447\u043D\u043E, \u043F\u043E\u043F\u0440\u0430\u0432\u044C plan_edit \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u044F\u043C\u0438 \u0438 \u0442\u043E\u043B\u044C\u043A\u043E \u043F\u043E\u0441\u043B\u0435 \u0435\u0433\u043E \xAB\u0434\u0430\xBB \u0437\u043E\u0432\u0438 render.
18585
+ \u041F\u0435\u0440\u0432\u044B\u0439 \u0447\u0435\u0440\u043D\u043E\u0432\u0438\u043A \u0441 \u0440\u0435\u0447\u044C\u044E \u0438\u0434\u0451\u0442 \u043C\u0438\u043D\u0443\u0442\u0430\u043C\u0438. \u041E\u0431\u043E\u0440\u0432\u0430\u043B\u0441\u044F \u0432\u044B\u0437\u043E\u0432 \u2014 \u0440\u0430\u0431\u043E\u0442\u0430 \u043D\u0435 \u043F\u0440\u043E\u043F\u0430\u043B\u0430: \u043F\u043E\u0437\u043E\u0432\u0438 wait, \u0430 \u043F\u043E\u0442\u043E\u043C plan \u043F\u043E \u0442\u043E\u043C\u0443 \u0436\u0435 \u0440\u043E\u043B\u0438\u043A\u0443 \u0435\u0449\u0451 \u0440\u0430\u0437, \u0432\u0442\u043E\u0440\u043E\u0439 \u0440\u0430\u0437 \u044D\u0442\u043E \u0441\u0435\u043A\u0443\u043D\u0434\u044B.
18586
+ \u0421 reel \u043F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0435\u0442 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442 \u0440\u043E\u043B\u0438\u043A\u0430: \u0434\u043E\u0440\u043E\u0436\u043A\u0438, \u043A\u043B\u0438\u043F\u044B \u043F\u043E id, \u0441\u043E\u0433\u043B\u0430\u0441\u043E\u0432\u0430\u043D \u043B\u0438 \u043E\u043D.
18587
+ \u0421 read \u043E\u0442\u0434\u0430\u0451\u0442 \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u044B \u0421\u043F\u0440\u0430\u0432\u043E\u0447\u043D\u0438\u043A\u0430 \u043C\u043E\u043D\u0442\u0430\u0436\u0451\u0440\u0430 (\u043F\u0435\u0447\u0430\u0442\u044C \u043F\u0435\u0440\u0432\u043E\u0439 \u0441\u0442\u0440\u043E\u043A\u043E\u0439), \u0442\u0430\u0431\u043B\u0438\u0446\u044B \u0432\u043A\u0443\u0441\u0430 \u0438 \u0447\u0443\u0436\u0438\u0435 \u0444\u0430\u0439\u043B\u044B \u2014 \u043F\u0443\u0442\u0438 \u0438\u0437 \u043E\u0433\u043B\u0430\u0432\u043B\u0435\u043D\u0438\u044F (\u0435\u0433\u043E \u0434\u0430\u0451\u0442 setup), \u0447\u0435\u0440\u043D\u043E\u0432\u0438\u043A\u0430 \u0438\u043B\u0438 \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u044B. \u0427\u0438\u0442\u0430\u0439 2\u20134 \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u044B \u043E\u0434\u043D\u0438\u043C \u0432\u044B\u0437\u043E\u0432\u043E\u043C \u0438 \u043D\u0435 \u0432\u044B\u0434\u0443\u043C\u044B\u0432\u0430\u0439 \u043F\u0443\u0442\u0435\u0439.`,
18046
18588
  // Полоса хода работы в ленте: черновик считается минутами, и всё это время
18047
18589
  // в ленте не происходило бы ничего. ⚠ Ожидание задачи — у `wait`, и полосы
18048
18590
  // у него нет: она объявлена на инструменте, и каждый вызов ожидания рисовал
@@ -18053,7 +18595,14 @@ function planTool(engine, key) {
18053
18595
  "\u041F\u0443\u0442\u044C \u043A \u0432\u0438\u0434\u0435\u043E\u0444\u0430\u0439\u043B\u0443 \u0441 \u0440\u0435\u0447\u044C\u044E \u2014 \u043F\u043E \u043D\u0435\u043C\u0443 \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044F \u0447\u0435\u0440\u043D\u043E\u0432\u0438\u043A. \u0424\u0430\u0439\u043B \u043B\u0435\u0436\u0438\u0442 \u0432 \u043F\u0430\u043F\u043A\u0435 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430 \u0438 \u0440\u043E\u043B\u0438\u043A\u043E\u043C \u0435\u0449\u0451 \u043D\u0435 \u0441\u0442\u0430\u043B \u2014 \u0437\u0430\u0432\u0435\u0434\u0443 \u0440\u043E\u043B\u0438\u043A \u0441\u0430\u043C"
18054
18596
  ).optional(),
18055
18597
  reel: external_exports.string().describe(
18056
- "\u041F\u0430\u043F\u043A\u0430 \u0437\u0430\u0432\u0435\u0434\u0451\u043D\u043D\u043E\u0433\u043E \u0440\u043E\u043B\u0438\u043A\u0430 \u0441 \u043E\u0431\u0449\u0438\u043C naparnik-project/1. \u041F\u043E\u043A\u0430\u0436\u0443 \u0442\u043E\u0447\u043D\u044B\u0439 JSON \u0438 \u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u0435 \u0441\u043E\u0433\u043B\u0430\u0441\u0438\u044F; \u043D\u0438\u0447\u0435\u0433\u043E \u043D\u0435 \u043F\u0435\u0440\u0435\u0441\u0447\u0438\u0442\u044B\u0432\u0430\u044E"
18598
+ "\u041F\u0430\u043F\u043A\u0430 \u0437\u0430\u0432\u0435\u0434\u0451\u043D\u043D\u043E\u0433\u043E \u0440\u043E\u043B\u0438\u043A\u0430: \u043F\u043E\u043A\u0430\u0436\u0443 \u0435\u0433\u043E \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442 reel.json \u2014 \u0434\u043E\u0440\u043E\u0436\u043A\u0438, \u043A\u043B\u0438\u043F\u044B \u043F\u043E id \u0438 \u0441\u043E\u0433\u043B\u0430\u0441\u043E\u0432\u0430\u043D \u043B\u0438 \u043E\u043D; \u043D\u0438\u0447\u0435\u0433\u043E \u043D\u0435 \u043F\u0435\u0440\u0435\u0441\u0447\u0438\u0442\u044B\u0432\u0430\u044E"
18599
+ ).optional(),
18600
+ // ⚠ ПОЛЯ РАЗДЕЛОВ СВОБОДНЫЕ, И ЭТО НЕ ЛЕНЬ: дом просьбы — поставщики пака
18601
+ // (`SECTIONS` шагов и их `supply`), судья — движок, и отказ приходит его
18602
+ // словами. Имена разделов описание повторяет, потому что его читает
18603
+ // модель; сторож копии — `plan-tools.test.ts`, сверка с `SECTIONS` пака.
18604
+ ask: external_exports.looseObject({}).describe(
18605
+ `\u0423\u0437\u043A\u0430\u044F \u043F\u0440\u043E\u0441\u044C\u0431\u0430 \u0440\u0430\u0437\u0434\u0435\u043B\u0430\u043C\u0438 \u2014 \u0442\u043E\u043B\u044C\u043A\u043E \u0432\u043C\u0435\u0441\u0442\u0435 \u0441 video: ${ASK_SECTIONS.join(", ")}; tempo \u2014 \u0432\u043E \u0441\u043A\u043E\u043B\u044C\u043A\u043E \u0440\u0430\u0437 \u0443\u0441\u043A\u043E\u0440\u0438\u0442\u044C, \u0447\u0438\u0441\u043B\u043E \u043E\u0442 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430. \u0417\u043D\u0430\u0447\u0435\u043D\u0438\u0435 true \u2014 \xAB\u043A\u0430\u043A \u0440\u0435\u0448\u0438\u0442 \u0447\u0435\u0440\u043D\u043E\u0432\u0438\u043A\xBB. {} \u2014 \u0438\u0441\u0445\u043E\u0434\u043D\u0438\u043A \u043A\u0430\u043A \u0441\u043D\u044F\u0442 (\u0446\u0432\u0435\u0442, \u0440\u0430\u0441\u043A\u043B\u0430\u0434\u043A\u0430); {"speech": {}} \u2014 \u0442\u043E\u043B\u044C\u043A\u043E \u0441\u043B\u043E\u0432\u0430 \u0441 \u043D\u043E\u043C\u0435\u0440\u0430\u043C\u0438 (fix_word, \u043A\u0443\u0441\u043E\u043A \u0441\u043E \u0441\u043B\u043E\u0432\u0430). ${FULL_WORDS} \u2014 \u043F\u043E\u043B\u043D\u044B\u0439 \u043C\u043E\u043D\u0442\u0430\u0436, \u0442\u043E\u043B\u044C\u043A\u043E \u043D\u0430 \xAB\u0441\u043C\u043E\u043D\u0442\u0438\u0440\u0443\u0439\xBB \u0446\u0435\u043B\u0438\u043A\u043E\u043C. \u0421 video \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u0435\u043D: \u0431\u0435\u0437 \u043D\u0435\u0433\u043E \u2014 \u043E\u0442\u043A\u0430\u0437`
18057
18606
  ).optional(),
18058
18607
  also: external_exports.array(external_exports.string()).describe(
18059
18608
  "\u0427\u0442\u043E \u0435\u0449\u0451 \u0438\u0434\u0451\u0442 \u0432 \u042D\u0422\u041E\u0422 \u0440\u043E\u043B\u0438\u043A: \u0437\u0430\u043F\u0438\u0441\u044C \u044D\u043A\u0440\u0430\u043D\u0430, \u043C\u0443\u0437\u044B\u043A\u0430, \u043A\u0430\u0440\u0442\u0438\u043D\u043A\u0438. \u0420\u043E\u043B\u0438 \u0440\u0435\u0448\u0430\u0435\u0442 \u0437\u0430\u043C\u0435\u0440, \u0430 \u043D\u0435 \u0438\u043C\u044F \u0444\u0430\u0439\u043B\u0430. \u0422\u043E\u043B\u044C\u043A\u043E \u0432\u043C\u0435\u0441\u0442\u0435 \u0441 video \u0438 \u0442\u043E\u043B\u044C\u043A\u043E \u043F\u0440\u0438 \u0437\u0430\u0432\u0435\u0434\u0435\u043D\u0438\u0438 \u0440\u043E\u043B\u0438\u043A\u0430"
@@ -18067,15 +18616,12 @@ function planTool(engine, key) {
18067
18616
  style: external_exports.string().describe(
18068
18617
  "\u041F\u0430\u043F\u043A\u0430 \u043F\u0430\u043A\u0430 \u0444\u0438\u0440\u043C\u0435\u043D\u043D\u043E\u0433\u043E \u0441\u0442\u0438\u043B\u044F: \u0447\u0435\u0440\u043D\u043E\u0432\u0438\u043A \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044F \u0442\u0430\u043A, \u043A\u0430\u043A \u0435\u0433\u043E \u043F\u043E\u0442\u043E\u043C \u0441\u043E\u0431\u0435\u0440\u0443\u0442"
18069
18618
  ).optional(),
18070
- // ⚠ ТАБЛИЦЫ ВКУСА НАЗВАНЫ ПРИМЕРОМ НАРОЧНО. Дверь к ним открыта движком
18071
- // (`engine/catalog/handbook.py`, корень `taste`), но модель о них не узнает ниоткуда:
18072
- // черновик называет их не всегда, а решение владельца 2026-09-18 разрешило
18073
- // ей писать план ролика целиком — и числа для него она обязана брать из
18074
- // наших замеров, а не из головы. Про «по одной-две за вызов» сказано тут
18075
- // же: таблицы тяжёлые, а ответ движка обрезан 48 КБ, и вызов на шесть
18076
- // таблиц вернулся бы частями, то есть лишними ходами.
18619
+ // ⚠ ПУТИ — КАК ИХ ПЕЧАТАЕТ ОГЛАВЛЕНИЕ СПРАВОЧНИКА (пакет Б1.14): без
18620
+ // приставки — страница `handbook/`, `taste/…` — таблица вкуса, `vendor/…` —
18621
+ // чужой файл. Заслоны чтения живут в движке (`engine/handbook/reader.py`).
18622
+ // Таблицы вкуса тяжёлые, а ответ движка обрезан 48 КБ: по одной-две.
18077
18623
  read: external_exports.array(external_exports.string()).describe(
18078
- `\u0424\u0430\u0439\u043B\u044B \u0441\u043A\u0438\u043B\u043B\u043E\u0432, \u0437\u043D\u0430\u043D\u0438\u0439 \u0438 \u0422\u0410\u0411\u041B\u0418\u0426 \u0412\u041A\u0423\u0421\u0410, \u043D\u0430\u0437\u0432\u0430\u043D\u043D\u044B\u0435 \u0447\u0435\u0440\u043D\u043E\u0432\u0438\u043A\u043E\u043C: \xABdirector/SKILL.md\xBB, \xABvendor/taste-skill/SKILL.md\xBB, \xABtaste/rhythm.json\xBB. \u0414\u043E ${FILES_PER_READ} \u0437\u0430 \u0432\u044B\u0437\u043E\u0432, \u043F\u0443\u0442\u0438 \u043E\u0442 \u043F\u0430\u043F\u043A\u0438 \u0441\u043A\u0438\u043B\u043B\u043E\u0432 \u043F\u0430\u043A\u0430 \u2014 \u043A\u0430\u043A \u0438\u0445 \u043D\u0430\u043F\u0435\u0447\u0430\u0442\u0430\u043B \u0447\u0435\u0440\u043D\u043E\u0432\u0438\u043A, \u0431\u0435\u0437 \xAB../\xBB \u0438 \u0431\u0435\u0437 \u0441\u0432\u043E\u0438\u0445 \u043F\u0443\u0442\u0435\u0439. \u0422\u0430\u0431\u043B\u0438\u0446\u044B \u0432\u043A\u0443\u0441\u0430 \u0442\u044F\u0436\u0451\u043B\u044B\u0435: \u0431\u0435\u0440\u0438 \u0438\u0445 \u043F\u043E \u043E\u0434\u043D\u043E\u0439-\u0434\u0432\u0435 \u0437\u0430 \u0432\u044B\u0437\u043E\u0432, \u0438\u043D\u0430\u0447\u0435 \u043E\u0442\u0432\u0435\u0442 \u043F\u0440\u0438\u0434\u0451\u0442 \u0447\u0430\u0441\u0442\u044F\u043C\u0438`
18624
+ `\u041F\u0443\u0442\u0438 \u043A\u0430\u043A \u0438\u0445 \u043D\u0430\u043F\u0435\u0447\u0430\u0442\u0430\u043B\u0438 \u043E\u0433\u043B\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u0441\u043F\u0440\u0430\u0432\u043E\u0447\u043D\u0438\u043A\u0430, \u0447\u0435\u0440\u043D\u043E\u0432\u0438\u043A \u0438\u043B\u0438 \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u0430: \xABdocument/clips.md\xBB, \xABtaste/rhythm.json\xBB, \xABvendor/taste-skill/SKILL.md\xBB. \u0414\u043E ${FILES_PER_READ} \u0437\u0430 \u0432\u044B\u0437\u043E\u0432, \u0431\u0435\u0437 \xAB../\xBB \u0438 \u0431\u0435\u0437 \u0441\u0432\u043E\u0438\u0445 \u043F\u0443\u0442\u0435\u0439. \u0422\u0430\u0431\u043B\u0438\u0446\u044B \u0432\u043A\u0443\u0441\u0430 \u0442\u044F\u0436\u0451\u043B\u044B\u0435: \u043F\u043E \u043E\u0434\u043D\u043E\u0439-\u0434\u0432\u0435 \u0437\u0430 \u0432\u044B\u0437\u043E\u0432, \u0438\u043D\u0430\u0447\u0435 \u043E\u0442\u0432\u0435\u0442 \u043F\u0440\u0438\u0434\u0451\u0442 \u0447\u0430\u0441\u0442\u044F\u043C\u0438`
18079
18625
  ).optional(),
18080
18626
  part: external_exports.number().describe(
18081
18627
  "\u041A\u0430\u043A\u0430\u044F \u0447\u0430\u0441\u0442\u044C \u043E\u0442\u0432\u0435\u0442\u0430 \u043D\u0443\u0436\u043D\u0430, \u0435\u0441\u043B\u0438 \u0444\u0430\u0439\u043B \u0434\u043B\u0438\u043D\u043D\u044B\u0439: \u0441\u0447\u0451\u0442 \u0441 \u0435\u0434\u0438\u043D\u0438\u0446\u044B. \u0421\u043A\u043E\u043B\u044C\u043A\u043E \u0438\u0445 \u0432\u0441\u0435\u0433\u043E, \u0441\u043A\u0430\u0436\u0435\u0442 \u0441\u0430\u043C \u043E\u0442\u0432\u0435\u0442"
@@ -18104,7 +18650,13 @@ function planTool(engine, key) {
18104
18650
  if (asked.part !== void 0 && asked.read === void 0) {
18105
18651
  say("\xABpart\xBB \u2014 \u044D\u0442\u043E \u0447\u0430\u0441\u0442\u044C \u043E\u0442\u0432\u0435\u0442\u0430 \u0447\u0442\u0435\u043D\u0438\u044F: \u043E\u043D \u0431\u044B\u0432\u0430\u0435\u0442 \u0442\u043E\u043B\u044C\u043A\u043E \u0432\u043C\u0435\u0441\u0442\u0435 \u0441 \xABread\xBB", "part");
18106
18652
  }
18107
- for (const key2 of ["also", "together"]) {
18653
+ if (asked.video !== void 0 && asked.ask === void 0) {
18654
+ say(
18655
+ `\u041D\u0430\u0437\u043E\u0432\u0438 \u043F\u0440\u043E\u0441\u044C\u0431\u0443: ask \u2014 \u0442\u043E\u043B\u044C\u043A\u043E \u0442\u043E, \u0447\u0442\u043E \u0447\u0435\u043B\u043E\u0432\u0435\u043A \u043F\u043E\u043F\u0440\u043E\u0441\u0438\u043B ({"tempo": <\u0432\u043E \u0441\u043A\u043E\u043B\u044C\u043A\u043E \u0440\u0430\u0437 \u043E\u043D \u0441\u043A\u0430\u0437\u0430\u043B>}, {"pauses": {}}, {"subtitles": {}}); \u0446\u0432\u0435\u0442, \u0440\u0430\u0441\u043A\u043B\u0430\u0434\u043A\u0430, split-screen \u2014 {}; \u0438\u0441\u043F\u0440\u0430\u0432\u0438\u0442\u044C \u0441\u043B\u043E\u0432\u043E \u2014 {"speech": {}}. \xAB\u0421\u043C\u043E\u043D\u0442\u0438\u0440\u0443\u0439\xBB \u0446\u0435\u043B\u0438\u043A\u043E\u043C \u2014 ${FULL_WORDS}`,
18656
+ "ask"
18657
+ );
18658
+ }
18659
+ for (const key2 of ["also", "together", "ask"]) {
18108
18660
  if (asked[key2] !== void 0 && asked.video === void 0) {
18109
18661
  say(`\xAB${key2}\xBB \u043E\u0442\u043D\u043E\u0441\u0438\u0442\u0441\u044F \u043A \u0437\u0430\u0432\u0435\u0434\u0435\u043D\u0438\u044E \u0440\u043E\u043B\u0438\u043A\u0430 \u0438 \u0431\u044B\u0432\u0430\u0435\u0442 \u0442\u043E\u043B\u044C\u043A\u043E \u0432\u043C\u0435\u0441\u0442\u0435 \u0441 \xABvideo\xBB`, key2);
18110
18662
  }
@@ -18114,7 +18666,7 @@ function planTool(engine, key) {
18114
18666
  if (args.read !== void 0) {
18115
18667
  return readSkills(engine, { files: args.read, part: args.part });
18116
18668
  }
18117
- if (args.reel !== void 0) return viewComposition(engine, args.reel);
18669
+ if (args.reel !== void 0) return viewDocument(engine, args.reel);
18118
18670
  if (args.video === void 0) return listReels(engine, args.workspace);
18119
18671
  return planDraft(
18120
18672
  engine,
@@ -18123,7 +18675,8 @@ function planTool(engine, key) {
18123
18675
  also: args.also,
18124
18676
  together: args.together,
18125
18677
  workspace: args.workspace,
18126
- style: args.style
18678
+ style: args.style,
18679
+ ask: args.ask
18127
18680
  },
18128
18681
  key,
18129
18682
  ctx?.emitProgress
@@ -18131,127 +18684,74 @@ function planTool(engine, key) {
18131
18684
  }
18132
18685
  });
18133
18686
  }
18134
- var MOVES = ["fade", "up", "down", "left", "right", "pop", "cut"];
18135
- var DRIFTS = ["none", "up", "down", "left", "right"];
18136
- var SPEEDS = ["slow", "normal", "fast"];
18137
- var SLOTS = ["top", "middle", "bottom"];
18687
+ var FULL_ASK = "all";
18688
+ var FULL_WORDS = `{"${FULL_ASK}": true}`;
18689
+ var ASK_SECTIONS = [
18690
+ "tempo",
18691
+ "pauses",
18692
+ "loudness",
18693
+ "voice",
18694
+ "music",
18695
+ "subtitles",
18696
+ "shots",
18697
+ "world",
18698
+ "inserts",
18699
+ "accents",
18700
+ "intro",
18701
+ "screen",
18702
+ "zoom",
18703
+ "webcam",
18704
+ "regions"
18705
+ ];
18706
+ var OPS = [
18707
+ "set",
18708
+ "unset",
18709
+ "add",
18710
+ "remove",
18711
+ "add_track",
18712
+ "add_group",
18713
+ "fix_word",
18714
+ "add_source",
18715
+ "add_package",
18716
+ "repin",
18717
+ "agree",
18718
+ "remember",
18719
+ "forget"
18720
+ ];
18138
18721
  function opSchema() {
18139
- return external_exports.object({
18140
- op: external_exports.string().describe(
18141
- "hero | remove | add | move | text | accent | word | world | motion | intro | part"
18142
- ),
18143
- from_word: external_exports.number().describe("hero: \u043F\u0435\u0440\u0432\u043E\u0435 \u0441\u043B\u043E\u0432\u043E \u043E\u0442\u0440\u0435\u0437\u043A\u0430").optional(),
18144
- // ⚠ ВТОРОЕ ЧИСЛО — СЛЕДУЮЩЕЕ ЗА ОТРЕЗКОМ, А НЕ ПОСЛЕДНЕЕ В НЁМ. Так их
18145
- // считает план (`lib/draft/build.py`: время конца берётся у слова `to_word - 1`),
18146
- // так же они печатаются в черновике словами, и так же их ждёт правка.
18147
- // До 2026-09-18 здесь стояло «последнее слово отрезка» — и модель, списав
18148
- // число из черновика, промахивалась на одно слово на каждой границе.
18149
- to_word: external_exports.number().describe(
18150
- "hero: \u0441\u043B\u043E\u0432\u043E \u0421\u041B\u0415\u0414\u0423\u042E\u0429\u0415\u0415 \u0437\u0430 \u043E\u0442\u0440\u0435\u0437\u043A\u043E\u043C \u2014 \u043E\u043D\u043E \u0441\u0430\u043C\u043E \u0432 \u043E\u0442\u0440\u0435\u0437\u043E\u043A \u043D\u0435 \u0432\u0445\u043E\u0434\u0438\u0442. \u0420\u043E\u0432\u043D\u043E \u0442\u043E \u0447\u0438\u0441\u043B\u043E, \u0447\u0442\u043E \u043D\u0430\u043F\u0435\u0447\u0430\u0442\u0430\u043D\u043E \u0432 \u0447\u0435\u0440\u043D\u043E\u0432\u0438\u043A\u0435"
18151
- ).optional(),
18152
- at_word: external_exports.number().describe("add, move: \u043D\u0430 \u043A\u0430\u043A\u043E\u043C \u0441\u043B\u043E\u0432\u0435").optional(),
18153
- until_word: external_exports.number().describe(
18154
- "add: \u0441\u043B\u043E\u0432\u043E \u0421\u041B\u0415\u0414\u0423\u042E\u0429\u0415\u0415 \u0437\u0430 \u043E\u0442\u0440\u0435\u0437\u043A\u043E\u043C \u2014 \u043E\u043D\u043E \u0441\u0430\u043C\u043E \u043D\u0435 \u0432\u0445\u043E\u0434\u0438\u0442"
18155
- ).optional(),
18156
- word: external_exports.number().describe("accent, word: \u043D\u043E\u043C\u0435\u0440 \u0441\u043B\u043E\u0432\u0430").optional(),
18157
- insert: external_exports.string().describe(
18158
- "remove, move, text, motion: \u0438\u043C\u044F \u0432\u0441\u0442\u0430\u0432\u043A\u0438 \u0438\u0437 \u0447\u0435\u0440\u043D\u043E\u0432\u0438\u043A\u0430, \u043D\u0430\u043F\u0440\u0438\u043C\u0435\u0440 chips-1"
18159
- ).optional(),
18160
- item: external_exports.number().describe("text: \u043D\u043E\u043C\u0435\u0440 \u043F\u0443\u043D\u043A\u0442\u0430 \u0441\u043F\u0438\u0441\u043A\u0430, \u0441 \u0435\u0434\u0438\u043D\u0438\u0446\u044B").optional(),
18161
- template: external_exports.string().describe("add: \u0448\u0430\u0431\u043B\u043E\u043D \u0432\u0441\u0442\u0430\u0432\u043A\u0438").optional(),
18162
- text: external_exports.string().describe(
18163
- "add: \u043F\u043E\u0434\u043F\u0438\u0441\u044C \u043D\u043E\u0432\u043E\u0439 \u0432\u0441\u0442\u0430\u0432\u043A\u0438; intro: \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0438 \u2014 \u0443 \u043D\u0435\u0451 \u044D\u0442\u043E \u043F\u043E\u043B\u0435 \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u043E"
18164
- ).optional(),
18165
- // ⚠ СЕКУНДА САМОЙ ЗАПИСИ, А НЕ СЕКУНДА РОЛИКА, И ПОЛЕ У НЕЁ СВОЁ. Окон
18166
- // записи экрана в плане бывает несколько, и каждое следующее продолжает
18167
- // предыдущее само (решение владельца 2026-09-18). Поле нужно там, где
18168
- // продолжение не годится: «а тут покажи с середины». Имя то же, что у
18169
- // слоя в плане наложений, — это одна и та же мысль, и второго имени для
18170
- // неё быть не должно.
18171
- file_start: external_exports.number().describe(
18172
- "add: \u0441 \u043A\u0430\u043A\u043E\u0439 \u0441\u0435\u043A\u0443\u043D\u0434\u044B \u0421\u0410\u041C\u041E\u0419 \u0437\u0430\u043F\u0438\u0441\u0438 \u044D\u043A\u0440\u0430\u043D\u0430 \u0438\u0433\u0440\u0430\u0442\u044C \u044D\u0442\u043E \u043E\u043A\u043D\u043E. \u041D\u0435 \u043F\u0438\u0448\u0435\u0448\u044C \u2014 \u043E\u043A\u043D\u043E \u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0430\u0435\u0442 \u043F\u0440\u0435\u0434\u044B\u0434\u0443\u0449\u0435\u0435 \u0441 \u0442\u043E\u0433\u043E \u043C\u0435\u0441\u0442\u0430, \u0433\u0434\u0435 \u043E\u043D\u043E \u043E\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u043B\u043E\u0441\u044C"
18173
- ).optional(),
18174
- value: external_exports.string().describe(
18175
- "hero: full|window|close-up|none; accent: accent|normal; text: \u043F\u043E\u0434\u043F\u0438\u0441\u044C; word: \u043A\u0430\u043A \u043F\u0440\u0430\u0432\u0438\u043B\u044C\u043D\u043E; world: grid|file|none; part: on|off"
18176
- ).optional(),
18177
- // ⚠ У ЭТИХ ДВУХ СТРОК ПЛАНА НЕТ ИМЕНИ ВСТАВКИ, ПОЭТОМУ И ПОЯВИЛОСЬ ОТДЕЛЬНОЕ
18178
- // ПОЛЕ. Вставку человек убирает по её имени (`remove`, `chips-1`), а
18179
- // субтитры и звуковые удары — это сами себе строка плана, целиком
18180
- // (`engine/brief.py`, `PARTS`).
18181
- what: external_exports.string().describe(
18182
- "part: \u043A\u0430\u043A\u0443\u044E \u0441\u0442\u0440\u043E\u043A\u0443 \u043F\u043B\u0430\u043D\u0430 \u0432\u044B\u0447\u0435\u0440\u043A\u043D\u0443\u0442\u044C \u0438\u043B\u0438 \u0432\u0435\u0440\u043D\u0443\u0442\u044C \u0446\u0435\u043B\u0438\u043A\u043E\u043C \u2014 subtitles | sfx"
18183
- ).optional(),
18184
- // Движение вставки словами: канвы модель не знает, а движок знает — в
18185
- // пиксели и секунды слова переводит шаг вставок по таблицам вкуса.
18186
- enter: external_exports.string().describe(
18187
- `motion, intro: \u043A\u0430\u043A \u0432\u0441\u0442\u0430\u0432\u043A\u0430 \u0438\u043B\u0438 \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0430 \u043F\u0440\u0438\u0445\u043E\u0434\u0438\u0442 \u2014 ${MOVES.join(" | ")}. fade \u2014 \u043F\u0440\u043E\u044F\u0432\u043B\u044F\u0435\u0442\u0441\u044F; up/down/left/right \u2014 \u0432\u044A\u0435\u0437\u0436\u0430\u0435\u0442 \u0441 \u044D\u0442\u043E\u0439 \u0441\u0442\u043E\u0440\u043E\u043D\u044B; pop \u2014 \u0432\u044B\u0441\u043A\u0430\u043A\u0438\u0432\u0430\u0435\u0442; cut \u2014 \u0440\u0435\u0437\u043E\u043C`
18188
- ).optional(),
18189
- exit: external_exports.string().describe(
18190
- `motion, intro: \u043A\u0430\u043A \u0443\u0445\u043E\u0434\u0438\u0442 \u2014 ${MOVES.join(" | ")}. \u0421\u0442\u043E\u0440\u043E\u043D\u0430 \u0442\u0443\u0442 \u0437\u043D\u0430\u0447\u0438\u0442, \u041A\u0423\u0414\u0410 \u0443\u0435\u0437\u0436\u0430\u0435\u0442: left \u2014 \u0432\u043B\u0435\u0432\u043E`
18191
- ).optional(),
18192
- drift: external_exports.string().describe(
18193
- `motion, intro: \u043C\u0435\u0434\u043B\u0435\u043D\u043D\u043E\u0435 \u0441\u043C\u0435\u0449\u0435\u043D\u0438\u0435 \u0437\u0430 \u0436\u0438\u0437\u043D\u044C \u0432\u0441\u0442\u0430\u0432\u043A\u0438 \u2014 ${DRIFTS.join(" | ")}; none \u2014 \u0441\u0442\u043E\u0438\u0442 \u043D\u0430 \u043C\u0435\u0441\u0442\u0435`
18194
- ).optional(),
18195
- speed: external_exports.string().describe(
18196
- `motion, intro: \u0441\u043A\u043E\u0440\u043E\u0441\u0442\u044C \u0432\u0445\u043E\u0434\u0430 \u0438 \u0443\u0445\u043E\u0434\u0430 \u2014 ${SPEEDS.join(" | ")}. normal \u2014 \u043A\u0430\u043A \u0437\u0430\u043C\u0435\u0440\u0435\u043D\u043E`
18197
- ).optional(),
18198
- slot: external_exports.string().describe(
18199
- `motion, intro: \u0433\u0434\u0435 \u0432\u0441\u0442\u0430\u0432\u043A\u0430 \u0441\u0442\u043E\u0438\u0442 \u043F\u043E \u0432\u0435\u0440\u0442\u0438\u043A\u0430\u043B\u0438 \u0432\u043D\u0443\u0442\u0440\u0438 \u0431\u0435\u0437\u043E\u043F\u0430\u0441\u043D\u043E\u0439 \u0440\u0430\u043C\u043A\u0438 \u2014 ${SLOTS.join(" | ")}`
18200
- ).optional(),
18201
- // Карточка в начале ролика: её вторая строка, длительность и снятие.
18202
- // ⚠ «text» СЛУЖИТ ДВУМ ОПЕРАЦИЯМ, и это не путаница: у `add` это подпись
18203
- // новой вставки, у `intro` — заголовок карточки. Развести их вторым именем
18204
- // значило бы завести модели два слова на одно и то же — «что написать».
18205
- note: external_exports.string().describe(
18206
- "intro: \u0432\u0442\u043E\u0440\u0430\u044F \u0441\u0442\u0440\u043E\u043A\u0430 \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0438, \u043F\u043E\u043C\u0435\u043B\u044C\u0447\u0435 \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043A\u0430"
18207
- ).optional(),
18208
- // ⚠ ЧИСЛО УМОЛЧАНИЯ ЗДЕСЬ НЕ НАЗЫВАЕТСЯ НАРОЧНО. Его дом один — «params»
18209
- // паспорта шага (`steps/intro/step.json`), и покупатель вправе поправить
18210
- // его в своей копии шага. Назови мы семёрку здесь — модель обещала бы её
18211
- // тому, у кого стоит другое число.
18212
- seconds: external_exports.number().describe(
18213
- "intro: \u0441\u043A\u043E\u043B\u044C\u043A\u043E \u0441\u0435\u043A\u0443\u043D\u0434 \u0434\u0435\u0440\u0436\u0438\u0442\u0441\u044F \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0430. \u041D\u0435 \u043D\u0430\u0437\u0432\u0430\u043B \u2014 \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u0435 \u0448\u0430\u0433\u0430"
18214
- ).optional(),
18215
- off: external_exports.boolean().describe("intro: \u0443\u0431\u0440\u0430\u0442\u044C \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0443 \u0438\u0437 \u043D\u0430\u0447\u0430\u043B\u0430 \u0440\u043E\u043B\u0438\u043A\u0430").optional()
18722
+ return external_exports.looseObject({
18723
+ op: external_exports.string().describe(OPS.join(" | "))
18216
18724
  });
18217
18725
  }
18218
18726
  function planEditTool(engine, key) {
18219
18727
  return defineTool({
18220
18728
  name: "plan_edit",
18221
- title: "\u041F\u043E\u043F\u0440\u0430\u0432\u0438\u0442\u044C \u043F\u043B\u0430\u043D \u0440\u043E\u043B\u0438\u043A\u0430",
18222
- description: "\u041F\u0440\u0430\u0432\u043A\u0430 \u0447\u0435\u0440\u043D\u043E\u0432\u0438\u043A\u0430 \u0438 \u0443\u0436\u0435 \u0441\u043E\u0431\u0440\u0430\u043D\u043D\u043E\u0433\u043E: \xAB\u043F\u043E\u043A\u0430\u0436\u0438 \u043C\u0435\u043D\u044F \u0446\u0435\u043B\u0438\u043A\u043E\u043C \u0432\u043E\u0442 \u0442\u0443\u0442\xBB, \xAB\u0443\u0431\u0435\u0440\u0438 \u0441\u043F\u0438\u0441\u043E\u043A\xBB, \xAB\u0432 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u0435 \u043D\u0435 \u0442\u043E \u0441\u043B\u043E\u0432\u043E\xBB, \xAB\u043F\u0443\u0441\u0442\u044C \u0432\u044B\u0435\u0437\u0436\u0430\u0435\u0442 \u0441\u043B\u0435\u0432\u0430\xBB, \xAB\u043F\u043E\u0434\u043F\u0438\u0448\u0438 \u0442\u0440\u0435\u0442\u0438\u0439 \u043F\u0443\u043D\u043A\u0442\xBB. \u041E\u0434\u043D\u0430 \u043F\u0440\u043E\u0441\u044C\u0431\u0430 \u2014 \u043E\u0434\u043D\u0430 \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u044F; \u0441 rebuild \u0441\u0440\u0430\u0437\u0443 \u043F\u0435\u0440\u0435\u0441\u043E\u0431\u0438\u0440\u0430\u0435\u0442, \u0438 \u044D\u0442\u043E \u0441\u0442\u043E\u0438\u0442 \u0441\u0435\u043A\u0443\u043D\u0434, \u0430 \u043D\u0435 \u043C\u0438\u043D\u0443\u0442: \u0437\u0430\u043D\u043E\u0432\u043E \u0434\u0435\u043B\u0430\u0435\u0442\u0441\u044F \u0442\u043E\u043B\u044C\u043A\u043E \u0442\u0440\u043E\u043D\u0443\u0442\u043E\u0435.\n\u041E\u043F\u0435\u0440\u0430\u0446\u0438\u0438: hero (\u043A\u0440\u0443\u043F\u043D\u043E\u0441\u0442\u044C \u043D\u0430 \u043E\u0442\u0440\u0435\u0437\u043A\u0435 \u0441\u043B\u043E\u0432), remove, add, move, text (\u043F\u043E\u0434\u043F\u0438\u0441\u044C \u0432\u0441\u0442\u0430\u0432\u043A\u0438 \u0438\u043B\u0438 \u0435\u0451 \u043F\u0443\u043D\u043A\u0442\u0430), accent (\u0441\u043B\u043E\u0432\u043E \u043A\u0440\u0443\u043F\u043D\u0435\u0435 \u0432 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u0430\u0445), word (\u0438\u0441\u043F\u0440\u0430\u0432\u0438\u0442\u044C \u0440\u0430\u0441\u043F\u043E\u0437\u043D\u0430\u043D\u043D\u043E\u0435 \u0441\u043B\u043E\u0432\u043E), world (\u0444\u043E\u043D \u0437\u0430 \u0433\u0435\u0440\u043E\u0435\u043C), motion (\u043A\u0430\u043A \u0432\u0441\u0442\u0430\u0432\u043A\u0430 \u043F\u0440\u0438\u0445\u043E\u0434\u0438\u0442, \u0443\u0445\u043E\u0434\u0438\u0442 \u0438 \u0433\u0434\u0435 \u0441\u0442\u043E\u0438\u0442), intro (\u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0430 \u0432 \u043D\u0430\u0447\u0430\u043B\u0435 \u0440\u043E\u043B\u0438\u043A\u0430: text, note, seconds; \u0443\u0431\u0440\u0430\u0442\u044C \u2014 off; \u0441\u043B\u043E\u0432\u0430 \u0434\u0432\u0438\u0436\u0435\u043D\u0438\u044F \u0443 \u043D\u0435\u0451 \u0442\u0435 \u0436\u0435 \u2014 enter, exit, drift, speed, slot), part (\u0432\u044B\u0447\u0435\u0440\u043A\u043D\u0443\u0442\u044C \u0446\u0435\u043B\u0438\u043A\u043E\u043C \u0441\u0442\u0440\u043E\u043A\u0443 \u043F\u043B\u0430\u043D\u0430, \u0443 \u043A\u043E\u0442\u043E\u0440\u043E\u0439 \u043D\u0435\u0442 \u0438\u043C\u0435\u043D\u0438 \u0432\u0441\u0442\u0430\u0432\u043A\u0438: what=subtitles|sfx, value=on|off \u2014 \xAB\u0431\u0435\u0437 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u043E\u0432\xBB, \xAB\u0431\u0435\u0437 \u0437\u0432\u0443\u043A\u043E\u0432\u044B\u0445 \u0443\u0434\u0430\u0440\u043E\u0432\xBB).\nintro \u2014 \u0435\u0434\u0438\u043D\u0441\u0442\u0432\u0435\u043D\u043D\u0430\u044F \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u044F, \u043A\u043E\u0442\u043E\u0440\u0430\u044F \u041C\u0415\u041D\u042F\u0415\u0422 \u0414\u041B\u0418\u041D\u0423 \u0440\u043E\u043B\u0438\u043A\u0430: \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0430 \u0432\u0441\u0442\u0430\u0451\u0442 \u041F\u0415\u0420\u0415\u0414 \u043D\u0438\u043C, \u0430 \u0441\u0430\u043C \u0440\u043E\u043B\u0438\u043A \u043E\u0441\u0442\u0430\u0451\u0442\u0441\u044F \u043A\u0430\u0434\u0440 \u0432 \u043A\u0430\u0434\u0440 \u043F\u0440\u0435\u0436\u043D\u0438\u043C. \u0420\u0430\u0431\u043E\u0442\u0430\u0435\u0442 \u0438 \u0432 \xAB\u0442\u043E\u043B\u044C\u043A\u043E \u043F\u0430\u0443\u0437\u044B\xBB.\n\u041D\u043E\u043C\u0435\u0440\u0430 \u0441\u043B\u043E\u0432 \u0438 \u0438\u043C\u0435\u043D\u0430 \u0432\u0441\u0442\u0430\u0432\u043E\u043A \u0431\u0435\u0440\u0438 \u0418\u0417 \u0427\u0415\u0420\u041D\u041E\u0412\u0418\u041A\u0410 (plan \u0441 video). \u041D\u0435 \u0432\u044B\u0434\u0443\u043C\u044B\u0432\u0430\u0439 \u0438\u0445: \u043F\u0440\u0430\u0432\u043A\u0430 \u043C\u0438\u043C\u043E \u0446\u0435\u043B\u0438 \u0431\u0443\u0434\u0435\u0442 \u043E\u0442\u043A\u043B\u043E\u043D\u0435\u043D\u0430 \u0441\u043B\u043E\u0432\u0430\u043C\u0438.\nconfirm \u2014 \u0447\u0435\u043B\u043E\u0432\u0435\u043A \u0441\u043A\u0430\u0437\u0430\u043B \xAB\u0434\u0430\xBB \u043D\u0430 \u043D\u044B\u043D\u0435\u0448\u043D\u044E\u044E \u0440\u0435\u0434\u0430\u043A\u0446\u0438\u044E; \u0431\u0435\u0437 \u044D\u0442\u043E\u0433\u043E \u0441\u0431\u043E\u0440\u043A\u0430 \u043F\u043B\u0430\u043D \u043D\u0435 \u0432\u043E\u0437\u044C\u043C\u0451\u0442. \u041B\u042E\u0411\u0410\u042F \u043F\u0440\u0430\u0432\u043A\u0430 \u0441\u043E\u0433\u043B\u0430\u0441\u0438\u0435 \u0441\u043D\u0438\u043C\u0430\u0435\u0442, \u043F\u043E\u044D\u0442\u043E\u043C\u0443 confirm \u0448\u043B\u0451\u0442\u0441\u044F \u0442\u0435\u043C \u0436\u0435 \u0432\u044B\u0437\u043E\u0432\u043E\u043C, \u0447\u0442\u043E \u0438 \u043F\u0440\u0430\u0432\u043A\u0430, \u2014 \u043F\u043E\u0441\u043B\u0435 \u0442\u043E\u0433\u043E \u043A\u0430\u043A \u0447\u0435\u043B\u043E\u0432\u0435\u043A \u0443\u0441\u043B\u044B\u0448\u0430\u043B, \u0447\u0442\u043E \u0438\u0437\u043C\u0435\u043D\u0438\u043B\u043E\u0441\u044C.\nplan \u2014 \u0432\u0435\u0441\u044C \u043F\u043B\u0430\u043D \u0440\u043E\u043B\u0438\u043A\u0430 \u0446\u0435\u043B\u0438\u043A\u043E\u043C, \u043D\u0430\u043F\u0438\u0441\u0430\u043D\u043D\u044B\u0439 \u0442\u043E\u0431\u043E\u0439: \u0434\u0432\u0438\u0436\u043E\u043A \u043F\u0440\u043E\u0432\u0435\u0440\u0438\u0442 \u0435\u0433\u043E \u043F\u043E \u0441\u0445\u0435\u043C\u0435 \u0438 \u043F\u043E \u043F\u043E\u0440\u043E\u0433\u0430\u043C \u0432\u043A\u0443\u0441\u0430 \u0438 \u043F\u0440\u0438 \u043D\u0430\u0440\u0443\u0448\u0435\u043D\u0438\u0438 \u043E\u0442\u043A\u0430\u0436\u0435\u0442 \u0441\u043B\u043E\u0432\u0430\u043C\u0438. \u0422\u0430\u043A \u0434\u0435\u043B\u0430\u044E\u0442, \u043A\u043E\u0433\u0434\u0430 \u043F\u0440\u0430\u0432\u043A\u0430\u043C\u0438 \u0443\u0436\u0435 \u043D\u0435 \u043E\u0431\u043E\u0439\u0442\u0438\u0441\u044C. draft \u2014 \u043E\u0431\u0440\u0430\u0442\u043D\u043E\u0435: \u0437\u0430\u0431\u044B\u0442\u044C \u0442\u0432\u043E\u0439 \u043F\u043B\u0430\u043D \u0438 \u0432\u0435\u0440\u043D\u0443\u0442\u044C\u0441\u044F \u043A \u043D\u0430\u0448\u0435\u043C\u0443 \u0447\u0435\u0440\u043D\u043E\u0432\u0438\u043A\u0443. \u041F\u0440\u043E\u0441\u044C\u0431\u0430 \u0443\u0437\u043A\u0430\u044F (\xAB\u043F\u0440\u043E\u0441\u0442\u043E \u0443\u0441\u043A\u043E\u0440\u044C\xBB) \u2014 \u043F\u043B\u0430\u043D\u0430 \u043D\u0435 \u043F\u0438\u0448\u0438 \u0432\u043E\u0432\u0441\u0435, \u0438\u043D\u0430\u0447\u0435 \u0432 \u0440\u043E\u043B\u0438\u043A\u0435 \u043F\u043E\u044F\u0432\u0438\u0442\u0441\u044F \u0442\u043E, \u043E \u0447\u0451\u043C \u043D\u0438\u043A\u0442\u043E \u043D\u0435 \u043F\u0440\u043E\u0441\u0438\u043B.\nproject \u2014 \u0432\u0435\u0441\u044C \u043E\u0431\u0449\u0438\u0439 naparnik-project/1 \u0446\u0435\u043B\u0438\u043A\u043E\u043C. \u0414\u0432\u0438\u0436\u043E\u043A \u0441\u0430\u043C \u0438\u0437\u043C\u0435\u0440\u044F\u0435\u0442 \u0438\u0441\u0445\u043E\u0434\u043D\u0438\u043A\u0438 \u0438 \u043F\u0440\u043E\u0432\u0435\u0440\u044F\u0435\u0442 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442; \u043F\u043E\u0441\u043B\u0435 \u043F\u043E\u043A\u0430\u0437\u0430 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0443 confirm \u043F\u0440\u0438\u0432\u044F\u0437\u044B\u0432\u0430\u0435\u0442 \u0441\u043E\u0433\u043B\u0430\u0441\u0438\u0435 \u043A \u0442\u043E\u0447\u043D\u043E\u0439 \u0440\u0435\u0434\u0430\u043A\u0446\u0438\u0438 \u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043C\u043E\u0441\u0442\u044F\u043C.\n\u0421\u043E step \u043F\u0440\u0430\u0432\u0438\u0442 \u043D\u0435 \u043F\u043B\u0430\u043D, \u0430 \u041F\u041E\u0420\u042F\u0414\u041E\u041A \u0428\u0410\u0413\u041E\u0412 \u043C\u043E\u043D\u0442\u0430\u0436\u0430: show \u2014 \u043F\u043E\u043A\u0430\u0437\u0430\u0442\u044C \u0434\u0435\u0439\u0441\u0442\u0432\u0443\u044E\u0449\u0438\u0439, mine \u2014 \u0437\u0430\u0432\u0435\u0441\u0442\u0438 \u0441\u0432\u043E\u044E \u043A\u043E\u043F\u0438\u044E \u043D\u0430\u0448\u0435\u0433\u043E, insert \u2014 \u043F\u043E\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u0441\u0432\u043E\u0439 \u0448\u0430\u0433 \u0434\u043E \u0438\u043B\u0438 \u043F\u043E\u0441\u043B\u0435 \u044D\u0442\u0430\u043F\u0430, replace \u2014 \u043F\u043E\u0434\u043C\u0435\u043D\u0438\u0442\u044C \u0448\u0430\u0433 \u0443 \u044D\u0442\u0430\u043F\u0430, remove \u2014 \u0443\u0431\u0440\u0430\u0442\u044C \u044D\u0442\u0430\u043F. \u041F\u0438\u0448\u0435\u0442 \u0442\u043E\u043B\u044C\u043A\u043E \u0432 \u043F\u0430\u043F\u043A\u0443 mine \u0434\u043E\u043C\u0430 \u041D\u0430\u043F\u0430\u0440\u043D\u0438\u043A\u0430: \u043D\u0430\u0448 \u043F\u043E\u0440\u044F\u0434\u043E\u043A \u043D\u0435 \u0442\u0440\u043E\u0433\u0430\u0435\u0442\u0441\u044F \u043D\u0438\u043A\u043E\u0433\u0434\u0430, \u0438 \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0435 \u0434\u0432\u0438\u0436\u043A\u0430 \u0442\u0432\u043E\u044E \u043A\u043E\u043F\u0438\u044E \u043D\u0435 \u0437\u0430\u043C\u0435\u043D\u044F\u0435\u0442. \u0421\u0432\u043E\u0439 \u0448\u0430\u0433 \u043F\u0440\u043E\u0432\u0435\u0440\u044F\u0435\u0442\u0441\u044F \u043F\u0440\u0438 \u0432\u0441\u0442\u0430\u0432\u043A\u0435 \u2014 \u0447\u0442\u043E \u0432 \u043D\u0451\u043C \u0447\u0438\u043D\u0438\u0442\u044C, \u0441\u043A\u0430\u0436\u0443\u0442 \u0441\u043B\u043E\u0432\u0430\u043C\u0438.",
18729
+ title: "\u041F\u043E\u043F\u0440\u0430\u0432\u0438\u0442\u044C \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442 \u0440\u043E\u043B\u0438\u043A\u0430",
18730
+ description: `\u041F\u0440\u0430\u0432\u043A\u0430 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0430 \u0440\u043E\u043B\u0438\u043A\u0430 reel.json \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u044F\u043C\u0438 \u043F\u043E id \u2014 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442 \u0446\u0435\u043B\u0438\u043A\u043E\u043C \u043D\u0435 \u043F\u0435\u0440\u0435\u043F\u0438\u0441\u044B\u0432\u0430\u0435\u0442\u0441\u044F. \u041E\u0434\u043D\u0430 \u043F\u0440\u043E\u0441\u044C\u0431\u0430 \u2014 \u043E\u0434\u043D\u0430 \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u044F: \xAB\u0437\u0432\u0443\u043A\u0438 \u0433\u0440\u043E\u043C\u0447\u0435\xBB \u2014 \u043E\u0434\u043D\u0430 \u0441\u0442\u0440\u043E\u043A\u0430 {"op": "set", "target": "defaults", "path": "sound.gain", "value": 7}. \u041F\u0430\u0447\u043A\u0430 \u043F\u0440\u0438\u043C\u0435\u043D\u044F\u0435\u0442\u0441\u044F \u0446\u0435\u043B\u0438\u043A\u043E\u043C \u0438\u043B\u0438 \u043D\u0438\u043A\u0430\u043A. \u041E\u043F\u0435\u0440\u0430\u0446\u0438\u0438 \u2014 document/edits.md \u0441\u043F\u0440\u0430\u0432\u043E\u0447\u043D\u0438\u043A\u0430: ${OPS.join(", ")}.
18731
+ stamps \u2014 \u043F\u0435\u0447\u0430\u0442\u0438 \u043F\u0440\u043E\u0447\u0438\u0442\u0430\u043D\u043D\u044B\u0445 \u0441\u0442\u0440\u0430\u043D\u0438\u0446 (\xABdocument/clips.md@1a2b3c4d\xBB \u2014 \u043F\u0435\u0440\u0432\u0430\u044F \u0441\u0442\u0440\u043E\u043A\u0430 \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u044B \u0432 \u043E\u0442\u0432\u0435\u0442\u0435 plan \u0441 read). \u041F\u0440\u0430\u0432\u043A\u0430 \u043A\u043B\u0438\u043F\u043E\u0432, \u043A\u043E\u0440\u043D\u044F, \u043E\u0431\u0449\u0435\u0433\u043E, \u0441\u0432\u043E\u0435\u0433\u043E \u043F\u0430\u043A\u0435\u0442\u0430 \u0438\u043B\u0438 \u0448\u0430\u0433\u0430 \u0431\u0435\u0437 \u043F\u0435\u0447\u0430\u0442\u0438 \u043E\u0442\u043A\u0430\u0437\u044B\u0432\u0430\u0435\u0442 \u0438 \u043F\u0440\u0438\u043D\u043E\u0441\u0438\u0442 \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u0443 \u0446\u0435\u043B\u0438\u043A\u043E\u043C: \u043F\u0440\u043E\u0447\u0442\u0438 \u0438 \u043F\u043E\u0432\u0442\u043E\u0440\u0438 \u0432\u044B\u0437\u043E\u0432.
18732
+ \xAB\u0417\u0430\u043F\u043E\u043C\u043D\u0438\xBB, \xAB\u0432\u0441\u0435\u0433\u0434\u0430 \u0442\u0430\u043A\xBB \u2014 remember (\u0441\u0432\u043E\u0451 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430, work/remember.md): \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442 \u043D\u0435 \u043C\u0435\u043D\u044F\u0435\u0442, \u043B\u043E\u0436\u0438\u0442\u0441\u044F \u0432 \u043A\u0430\u0436\u0434\u044B\u0439 \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0438\u0439 \u0447\u0435\u0440\u043D\u043E\u0432\u0438\u043A; \u043F\u0435\u0447\u0430\u0442\u0438 \u043D\u0435 \u043D\u0443\u0436\u043D\u043E.
18733
+ \xAB\u0414\u0430\xBB \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430 \u2014 \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u044F {"op": "agree"}: \u0442\u0435\u043C \u0436\u0435 \u0432\u044B\u0437\u043E\u0432\u043E\u043C, \u0447\u0442\u043E \u043F\u043E\u0441\u043B\u0435\u0434\u043D\u044F\u044F \u043F\u0440\u0430\u0432\u043A\u0430, \u0438\u043B\u0438 \u043E\u0442\u0434\u0435\u043B\u044C\u043D\u043E; \u043F\u0435\u0447\u0430\u0442\u0438 \u0435\u0439 \u043D\u0435 \u043D\u0443\u0436\u043D\u043E. \u041B\u044E\u0431\u0430\u044F \u043F\u0440\u0430\u0432\u043A\u0430 \u0441\u043E\u0433\u043B\u0430\u0441\u0438\u0435 \u0441\u043D\u0438\u043C\u0430\u0435\u0442. \u0414\u043E\u043A\u0443\u043C\u0435\u043D\u0442 \u043F\u0440\u0430\u0432\u0438\u0442\u0441\u044F \u0422\u041E\u041B\u042C\u041A\u041E \u0437\u0434\u0435\u0441\u044C: \u0444\u0430\u0439\u043B, \u043F\u043E\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u043D\u044B\u0439 \u043C\u0438\u043C\u043E plan_edit, \u043D\u0435 \u0441\u043E\u0433\u043B\u0430\u0441\u0443\u0435\u0442\u0441\u044F \u0438 \u043D\u0435 \u0441\u043E\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044F.
18734
+ rebuild \u2014 \u0441\u0440\u0430\u0437\u0443 \u0441\u043E\u0431\u0440\u0430\u0442\u044C \u0441\u043E\u0433\u043B\u0430\u0441\u043E\u0432\u0430\u043D\u043D\u044B\u0439 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442: \u043E\u0442\u0432\u0435\u0447\u0443 \u043D\u043E\u043C\u0435\u0440\u043E\u043C \u0437\u0430\u0434\u0430\u0447\u0438, \u0434\u0430\u043B\u044C\u0448\u0435 wait.
18735
+ \u0421\u043E step \u043F\u0440\u0430\u0432\u0438\u0442 \u043D\u0435 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442, \u0430 \u041F\u041E\u0420\u042F\u0414\u041E\u041A \u0428\u0410\u0413\u041E\u0412 \u0441\u0442\u0430\u0440\u043E\u0433\u043E \u043C\u043E\u043D\u0442\u0430\u0436\u0430: show, mine, insert, replace, remove. render \u043F\u043E \u044D\u0442\u043E\u043C\u0443 \u043F\u043E\u0440\u044F\u0434\u043A\u0443 \u041D\u0415 \u0441\u043E\u0431\u0438\u0440\u0430\u0435\u0442, \u0438 \u0440\u043E\u043B\u0438\u043A \u043E\u0442 step \u043D\u0435 \u043C\u0435\u043D\u044F\u0435\u0442\u0441\u044F. \u0421\u0432\u043E\u0439 \u044D\u0444\u0444\u0435\u043A\u0442 \u0432 \u0440\u043E\u043B\u0438\u043A\u0435 \u2014 \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0435\u0439 set \u0441 uses: "mine:<\u0438\u043C\u044F>".`,
18223
18736
  ui: { resourceUri: RUNBAR_RESOURCE_URI },
18224
18737
  args: external_exports.object({
18225
18738
  reel: external_exports.string().describe(
18226
18739
  "\u041F\u0430\u043F\u043A\u0430 \u0440\u043E\u043B\u0438\u043A\u0430 \u0438\u043B\u0438 \u043F\u0443\u0442\u044C \u043A \u0432\u0438\u0434\u0435\u043E\u0444\u0430\u0439\u043B\u0443 \u2014 \u0447\u0442\u043E \u0435\u0441\u0442\u044C \u043F\u043E\u0434 \u0440\u0443\u043A\u043E\u0439"
18227
18740
  ).optional(),
18228
- ops: external_exports.array(opSchema()).describe("\u0421\u043F\u0438\u0441\u043E\u043A \u043F\u0440\u0430\u0432\u043E\u043A; \u043F\u0440\u0438\u043C\u0435\u043D\u044F\u044E\u0442\u0441\u044F \u043F\u043E \u043F\u043E\u0440\u044F\u0434\u043A\u0443").optional(),
18229
- by: external_exports.enum(["model", "human"]).describe(
18230
- "\u041A\u0442\u043E \u0432\u043F\u0438\u0441\u0430\u043B \u043F\u0440\u0430\u0432\u043A\u0443. \xABmodel\xBB \u2014 \u0442\u044B \u0441\u0430\u043C \u0437\u0430\u043A\u0440\u044B\u043B \u043F\u0443\u0441\u0442\u043E\u0439 \u0441\u043B\u043E\u0442 \u043F\u043E\u0434\u043F\u0438\u0441\u0438; \xABhuman\xBB \u2014 \u0447\u0435\u043B\u043E\u0432\u0435\u043A \u043F\u043E\u043F\u0440\u043E\u0441\u0438\u043B \u0441\u043B\u043E\u0432\u0430\u043C\u0438. \u0423\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u0435 \u2014 model"
18231
- ).optional(),
18232
- rebuild: external_exports.boolean().describe(
18233
- "\u0421\u0440\u0430\u0437\u0443 \u043F\u0435\u0440\u0435\u0441\u043E\u0431\u0440\u0430\u0442\u044C \u0440\u043E\u043B\u0438\u043A. \u041E\u0442\u0432\u0435\u0447\u0443 \u043D\u043E\u043C\u0435\u0440\u043E\u043C \u0437\u0430\u0434\u0430\u0447\u0438, \u0434\u0430\u043B\u044C\u0448\u0435 wait"
18741
+ ops: external_exports.array(opSchema()).describe(
18742
+ '\u041E\u043F\u0435\u0440\u0430\u0446\u0438\u0438 \u043F\u043E \u043F\u043E\u0440\u044F\u0434\u043A\u0443; \u0441\u043E\u0433\u043B\u0430\u0441\u0438\u0435 \u2014 {"op": "agree"}'
18234
18743
  ).optional(),
18235
- confirm: external_exports.boolean().describe(
18236
- "\u0427\u0435\u043B\u043E\u0432\u0435\u043A \u0441\u043E\u0433\u043B\u0430\u0441\u043E\u0432\u0430\u043B \u043D\u044B\u043D\u0435\u0448\u043D\u044E\u044E \u0440\u0435\u0434\u0430\u043A\u0446\u0438\u044E \u043F\u043B\u0430\u043D\u0430. \u041B\u044E\u0431\u0430\u044F \u043F\u0440\u0430\u0432\u043A\u0430 \u0441\u043E\u0433\u043B\u0430\u0441\u0438\u0435 \u0441\u043D\u0438\u043C\u0430\u0435\u0442 \u2014 \u0448\u043B\u0438 \u044D\u0442\u0438\u043C \u0436\u0435 \u0432\u044B\u0437\u043E\u0432\u043E\u043C, \u0447\u0442\u043E \u0438 \u043F\u0440\u0430\u0432\u043A\u0443"
18744
+ stamps: external_exports.array(external_exports.string()).describe(
18745
+ "\u041F\u0435\u0447\u0430\u0442\u0438 \u0441\u0442\u0440\u0430\u043D\u0438\u0446 \u0441\u043F\u0440\u0430\u0432\u043E\u0447\u043D\u0438\u043A\u0430, \u043F\u0440\u043E\u0447\u0438\u0442\u0430\u043D\u043D\u044B\u0445 \u0432 \u044D\u0442\u043E\u043C \u0440\u0430\u0437\u0433\u043E\u0432\u043E\u0440\u0435: \xAB\u043F\u0443\u0442\u044C@\u043A\u043E\u0434\xBB"
18237
18746
  ).optional(),
18238
- // ⚠ СХЕМЫ ПЛАНА ЗДЕСЬ НЕТ НАРОЧНО, И ЭТО НЕ ЛЕНЬ. Дом договора
18239
- // `naparnik-plan/1` один — движок (`packs/montage/lib/draft/build.py`), и он же
18240
- // единственный судья: проверяет по схеме и по порогам брака таблиц вкуса.
18241
- // Перепиши мы состав плана сюда — у договора появилась бы вторая правда,
18242
- // которая расходится с первой молча, а узнаёт об этом человек собранным
18243
- // роликом. Поля свободные, а отказ приходит от того, кто план исполняет.
18244
- plan: external_exports.looseObject({}).describe(
18245
- "\u0412\u0415\u0421\u042C \u043F\u043B\u0430\u043D \u0440\u043E\u043B\u0438\u043A\u0430 \u0446\u0435\u043B\u0438\u043A\u043E\u043C, \u043D\u0430\u043F\u0438\u0441\u0430\u043D\u043D\u044B\u0439 \u0442\u043E\u0431\u043E\u0439, \u2014 \u0434\u043E\u0433\u043E\u0432\u043E\u0440 naparnik-plan/1. \u0427\u0438\u0441\u043B\u0430 \u0431\u0435\u0440\u0438 \u0438\u0437 \u0442\u0430\u0431\u043B\u0438\u0446 \u0432\u043A\u0443\u0441\u0430 (plan \u0441 read), \u0430 \u043D\u0435 \u0438\u0437 \u0433\u043E\u043B\u043E\u0432\u044B: \u0434\u0432\u0438\u0436\u043E\u043A \u043F\u0440\u043E\u0432\u0435\u0440\u0438\u0442 \u043F\u043B\u0430\u043D \u0438 \u043E\u0442\u043A\u0430\u0436\u0435\u0442 \u0441\u043B\u043E\u0432\u0430\u043C\u0438, \u043D\u0430\u0437\u0432\u0430\u0432, \u0447\u0442\u043E \u043D\u0430\u0440\u0443\u0448\u0435\u043D\u043E \u0438 \u043A\u0430\u043A\u0430\u044F \u043D\u043E\u0440\u043C\u0430"
18246
- ).optional(),
18247
- project: external_exports.looseObject({}).describe(
18248
- "\u0412\u0415\u0421\u042C \u043E\u0431\u0449\u0438\u0439 \u043F\u0440\u043E\u0435\u043A\u0442 \u043C\u043E\u043D\u0442\u0430\u0436\u0430 \u0446\u0435\u043B\u0438\u043A\u043E\u043C, \u0434\u043E\u0433\u043E\u0432\u043E\u0440 naparnik-project/1: \u0438\u0441\u0442\u043E\u0447\u043D\u0438\u043A\u0438, \u0434\u043E\u0440\u043E\u0436\u043A\u0438, \u043A\u043B\u0438\u043F\u044B, \u044D\u0444\u0444\u0435\u043A\u0442\u044B \u0438 \u0432\u044B\u0445\u043E\u0434. \u0414\u0432\u0438\u0436\u043E\u043A \u0438\u0437\u043C\u0435\u0440\u0438\u0442 \u0444\u0430\u0439\u043B\u044B \u0438 \u043F\u0440\u043E\u0432\u0435\u0440\u0438\u0442 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442 \u0434\u043E \u0437\u0430\u043F\u0438\u0441\u0438. \u041B\u044E\u0431\u0430\u044F \u043D\u043E\u0432\u0430\u044F \u0440\u0435\u0434\u0430\u043A\u0446\u0438\u044F \u0441\u043D\u0438\u043C\u0430\u0435\u0442 \u043F\u0440\u0435\u0436\u043D\u0435\u0435 \u0441\u043E\u0433\u043B\u0430\u0441\u0438\u0435"
18747
+ by: external_exports.enum(["model", "human"]).describe(
18748
+ "\u041A\u0442\u043E \u043F\u0440\u0430\u0432\u0438\u0442 \u0438 \u043A\u0442\u043E \u0441\u043A\u0430\u0437\u0430\u043B \xAB\u0434\u0430\xBB: model \u2014 \u0442\u044B \u0441 \u0435\u0433\u043E \u0441\u043B\u043E\u0432, human \u2014 \u043E\u043D \u0441\u0430\u043C. \u0423\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u0435 \u2014 model"
18249
18749
  ).optional(),
18250
- draft: external_exports.boolean().describe(
18251
- "\u0417\u0430\u0431\u044B\u0442\u044C \u043D\u0430\u043F\u0438\u0441\u0430\u043D\u043D\u044B\u0439 \u0442\u043E\u0431\u043E\u0439 \u043F\u043B\u0430\u043D \u0438 \u0432\u0435\u0440\u043D\u0443\u0442\u044C\u0441\u044F \u043A \u043D\u0430\u0448\u0435\u043C\u0443 \u0447\u0435\u0440\u043D\u043E\u0432\u0438\u043A\u0443"
18750
+ rebuild: external_exports.boolean().describe(
18751
+ "\u0421\u0440\u0430\u0437\u0443 \u0441\u043E\u0431\u0440\u0430\u0442\u044C \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442 \u043F\u043E\u0441\u043B\u0435 \u043F\u0440\u0430\u0432\u043A\u0438. \u041E\u0442\u0432\u0435\u0447\u0443 \u043D\u043E\u043C\u0435\u0440\u043E\u043C \u0437\u0430\u0434\u0430\u0447\u0438, \u0434\u0430\u043B\u044C\u0448\u0435 wait"
18252
18752
  ).optional(),
18253
18753
  step: external_exports.enum(["show", "mine", "insert", "remove", "replace"]).describe(
18254
- "\u0414\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0441 \u041F\u041E\u0420\u042F\u0414\u041A\u041E\u041C \u0428\u0410\u0413\u041E\u0412 \u043C\u043E\u043D\u0442\u0430\u0436\u0430, \u0430 \u043D\u0435 \u0441 \u043F\u043B\u0430\u043D\u043E\u043C \u0440\u043E\u043B\u0438\u043A\u0430"
18754
+ "\u0414\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0441 \u041F\u041E\u0420\u042F\u0414\u041A\u041E\u041C \u0428\u0410\u0413\u041E\u0412 \u043C\u043E\u043D\u0442\u0430\u0436\u0430, \u0430 \u043D\u0435 \u0441 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u043E\u043C \u0440\u043E\u043B\u0438\u043A\u0430"
18255
18755
  ).optional(),
18256
18756
  name: external_exports.string().describe(
18257
18757
  '\u0418\u043C\u044F \u0428\u0410\u0413\u0410, \u043A\u043E\u0442\u043E\u0440\u044B\u0439 \u0441\u0442\u0430\u0432\u0438\u043C (\u0434\u043B\u044F step="insert"). \u041E\u0434\u043D\u043E \u0441\u043B\u043E\u0432\u043E \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 \u0432 mine/steps'
@@ -18270,54 +18770,31 @@ function planEditTool(engine, key) {
18270
18770
  const say = (message, where) => {
18271
18771
  ctx.issues.push({ code: "custom", message, input: asked, path: [where] });
18272
18772
  };
18273
- const planKeys = ["reel", "ops", "by", "rebuild", "confirm", "plan", "project", "draft"].filter((key2) => asked[key2] !== void 0);
18274
- if (asked.step !== void 0 && planKeys.length > 0) {
18275
- say(
18276
- `\xABstep\xBB \u043F\u0440\u0430\u0432\u0438\u0442 \u043F\u043E\u0440\u044F\u0434\u043E\u043A \u0448\u0430\u0433\u043E\u0432 \u043C\u043E\u043D\u0442\u0430\u0436\u0430, \u0430 \u043D\u0435 \u043F\u043B\u0430\u043D \u0440\u043E\u043B\u0438\u043A\u0430 \u2014 \u043B\u0438\u0448\u043D\u0435\u0435: ${planKeys.join(", ")}. \u041F\u043E\u0437\u043E\u0432\u0438 \u043E\u0442\u0434\u0435\u043B\u044C\u043D\u043E`,
18277
- "step"
18278
- );
18279
- return;
18280
- }
18281
- if (asked.step === void 0) {
18282
- const stepKeys = STEP_KEYS.filter((key2) => asked[key2] !== void 0);
18283
- if (stepKeys.length > 0) {
18773
+ const editKeys = ["reel", "ops", "stamps", "by", "rebuild"].filter((key2) => asked[key2] !== void 0);
18774
+ if (asked.step !== void 0) {
18775
+ if (editKeys.length > 0) {
18284
18776
  say(
18285
- `\xAB${stepKeys.join(", ")}\xBB \u043E\u0442\u043D\u043E\u0441\u044F\u0442\u0441\u044F \u043A \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044E \u0441\u043E \u0441\u0432\u043E\u0438\u043C \u0448\u0430\u0433\u043E\u043C \u2014 \u043D\u0430\u0437\u043E\u0432\u0438 \xABstep\xBB`,
18777
+ `\xABstep\xBB \u043F\u0440\u0430\u0432\u0438\u0442 \u043F\u043E\u0440\u044F\u0434\u043E\u043A \u0448\u0430\u0433\u043E\u0432 \u043C\u043E\u043D\u0442\u0430\u0436\u0430, \u0430 \u043D\u0435 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442 \u0440\u043E\u043B\u0438\u043A\u0430 \u2014 \u043B\u0438\u0448\u043D\u0435\u0435: ${editKeys.join(", ")}. \u041F\u043E\u0437\u043E\u0432\u0438 \u043E\u0442\u0434\u0435\u043B\u044C\u043D\u043E`,
18286
18778
  "step"
18287
18779
  );
18288
18780
  }
18289
- if (asked.reel === void 0) {
18290
- say(
18291
- "\u041D\u0435 \u0437\u0430\u0434\u0430\u043D \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u044B\u0439 \u0430\u0440\u0433\u0443\u043C\u0435\u043D\u0442 \xABreel\xBB: \u043F\u0440\u0430\u0432\u043A\u0430 \u043F\u043B\u0430\u043D\u0430 \u2014 \u044D\u0442\u043E \u0440\u043E\u043B\u0438\u043A \u0438 \u0442\u043E, \u0447\u0442\u043E \u0441 \u043D\u0438\u043C \u0434\u0435\u043B\u0430\u0435\u043C. \u041F\u043E\u0440\u044F\u0434\u043E\u043A \u0448\u0430\u0433\u043E\u0432 \u043C\u043E\u043D\u0442\u0430\u0436\u0430 \u043F\u0440\u0430\u0432\u0438\u0442\u0441\u044F \u043A\u043B\u044E\u0447\u043E\u043C \xABstep\xBB",
18292
- "reel"
18293
- );
18294
- }
18295
- if (asked.plan !== void 0 && asked.draft === true) {
18296
- say(
18297
- "\xABplan\xBB \u043A\u043B\u0430\u0434\u0451\u0442 \u0442\u0432\u043E\u0439 \u043F\u043B\u0430\u043D \u0440\u043E\u043B\u0438\u043A\u0430, \xABdraft\xBB \u0435\u0433\u043E \u0441\u0442\u0438\u0440\u0430\u0435\u0442 \u2014 \u044D\u0442\u043E \u0434\u0432\u0435 \u043F\u0440\u043E\u0442\u0438\u0432\u043E\u043F\u043E\u043B\u043E\u0436\u043D\u044B\u0435 \u043F\u0440\u043E\u0441\u044C\u0431\u044B. \u041E\u0441\u0442\u0430\u0432\u044C \u043E\u0434\u043D\u0443",
18298
- "draft"
18299
- );
18300
- }
18301
- if (asked.project !== void 0 && (asked.ops !== void 0 || asked.plan !== void 0 || asked.draft === true)) {
18302
- say(
18303
- "\xABproject\xBB \u2014 \u0432\u0435\u0441\u044C \u043E\u0431\u0449\u0438\u0439 naparnik-project/1; ops/plan/draft \u043F\u0440\u0430\u0432\u044F\u0442 \u0441\u0442\u0430\u0440\u044B\u0439 \u0440\u0430\u0437\u0433\u043E\u0432\u043E\u0440\u043D\u044B\u0439 \u043F\u043B\u0430\u043D. \u041E\u0441\u0442\u0430\u0432\u044C \u043E\u0434\u043D\u0443 \u0432\u0435\u0442\u043A\u0443",
18304
- "project"
18305
- );
18306
- }
18307
- const asking = [
18308
- asked.ops !== void 0 ? "ops" : "",
18309
- asked.plan !== void 0 ? "plan" : "",
18310
- asked.project !== void 0 ? "project" : "",
18311
- asked.confirm === true ? "confirm" : "",
18312
- asked.draft === true ? "draft" : "",
18313
- asked.rebuild === true ? "rebuild" : ""
18314
- ].filter((one) => one !== "");
18315
- if (asking.length === 0) {
18316
- say(
18317
- "\u0414\u0435\u043B\u0430\u0442\u044C \u043D\u0435\u0447\u0435\u0433\u043E: \u043D\u0438 \u043F\u0440\u0430\u0432\u043E\u043A, \u043D\u0438 \u0441\u043E\u0433\u043B\u0430\u0441\u0438\u044F. \xABops\xBB \u2014 \u043F\u0440\u0430\u0432\u043A\u0438 \u043F\u043B\u0430\u043D\u0430, \xABplan\xBB \u2014 \u0432\u0435\u0441\u044C \u043F\u043B\u0430\u043D \u0440\u043E\u043B\u0438\u043A\u0430 \u0446\u0435\u043B\u0438\u043A\u043E\u043C, \xABconfirm\xBB \u2014 \u0447\u0435\u043B\u043E\u0432\u0435\u043A \u0441\u043A\u0430\u0437\u0430\u043B \xAB\u0434\u0430\xBB \u043D\u0430 \u043D\u044B\u043D\u0435\u0448\u043D\u044E\u044E \u0440\u0435\u0434\u0430\u043A\u0446\u0438\u044E, \xABdraft\xBB \u2014 \u0432\u0435\u0440\u043D\u0443\u0442\u044C \u043D\u0430\u0448 \u0447\u0435\u0440\u043D\u043E\u0432\u0438\u043A. \u041F\u043E\u0440\u044F\u0434\u043E\u043A \u0448\u0430\u0433\u043E\u0432 \u043C\u043E\u043D\u0442\u0430\u0436\u0430 \u043F\u0440\u0430\u0432\u0438\u0442\u0441\u044F \u043A\u043B\u044E\u0447\u043E\u043C \xABstep\xBB",
18318
- "ops"
18319
- );
18320
- }
18781
+ return;
18782
+ }
18783
+ const stepKeys = STEP_KEYS.filter((key2) => asked[key2] !== void 0);
18784
+ if (stepKeys.length > 0) {
18785
+ say(`\xAB${stepKeys.join(", ")}\xBB \u043E\u0442\u043D\u043E\u0441\u044F\u0442\u0441\u044F \u043A \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044E \u0441\u043E \u0441\u0432\u043E\u0438\u043C \u0448\u0430\u0433\u043E\u043C \u2014 \u043D\u0430\u0437\u043E\u0432\u0438 \xABstep\xBB`, "step");
18786
+ }
18787
+ if (asked.reel === void 0) {
18788
+ say(
18789
+ "\u041D\u0435 \u0437\u0430\u0434\u0430\u043D \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u044B\u0439 \u0430\u0440\u0433\u0443\u043C\u0435\u043D\u0442 \xABreel\xBB: \u043F\u0440\u0430\u0432\u043A\u0430 \u2014 \u044D\u0442\u043E \u0440\u043E\u043B\u0438\u043A \u0438 \u0442\u043E, \u0447\u0442\u043E \u0441 \u043D\u0438\u043C \u0434\u0435\u043B\u0430\u0435\u043C. \u041F\u043E\u0440\u044F\u0434\u043E\u043A \u0448\u0430\u0433\u043E\u0432 \u043C\u043E\u043D\u0442\u0430\u0436\u0430 \u043F\u0440\u0430\u0432\u0438\u0442\u0441\u044F \u043A\u043B\u044E\u0447\u043E\u043C \xABstep\xBB",
18790
+ "reel"
18791
+ );
18792
+ }
18793
+ if (asked.ops === void 0 || asked.ops.length === 0) {
18794
+ say(
18795
+ '\u0414\u0435\u043B\u0430\u0442\u044C \u043D\u0435\u0447\u0435\u0433\u043E: \u043D\u0435\u0442 \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0439. \u041F\u0440\u0430\u0432\u043A\u0430 \u2014 ops \u0441\u043E \u0441\u043F\u0438\u0441\u043A\u043E\u043C \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0439, \xAB\u0434\u0430\xBB \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430 \u2014 [{"op": "agree"}]. \u041F\u043E\u0440\u044F\u0434\u043E\u043A \u0448\u0430\u0433\u043E\u0432 \u043C\u043E\u043D\u0442\u0430\u0436\u0430 \u043F\u0440\u0430\u0432\u0438\u0442\u0441\u044F \u043A\u043B\u044E\u0447\u043E\u043C \xABstep\xBB',
18796
+ "ops"
18797
+ );
18321
18798
  }
18322
18799
  }),
18323
18800
  async execute(args, ctx) {
@@ -18330,352 +18807,21 @@ function planEditTool(engine, key) {
18330
18807
  with: args.with
18331
18808
  });
18332
18809
  }
18333
- return editPlan(
18810
+ return editDocument(
18334
18811
  engine,
18335
18812
  {
18336
18813
  reel: args.reel ?? "",
18337
18814
  ops: args.ops ?? [],
18815
+ stamps: args.stamps,
18338
18816
  by: args.by,
18339
- rebuild: args.rebuild,
18340
- confirm: args.confirm,
18341
- plan: args.plan,
18342
- project: args.project,
18343
- draft: args.draft
18344
- },
18345
- key,
18346
- ctx?.emitProgress
18347
- );
18348
- }
18349
- });
18350
- }
18351
- function universalOptions(asked) {
18352
- const found = /* @__PURE__ */ new Set();
18353
- const known = [
18354
- ["only_pauses", asked.onlyPauses],
18355
- ["style", asked.style],
18356
- ["preset", asked.preset],
18357
- ["model", asked.model],
18358
- ["tempo", asked.tempo],
18359
- ["keep_pauses", asked.keepPauses],
18360
- ["redo", asked.redo],
18361
- ["from_scratch", asked.fromScratch],
18362
- ["even_without_speech", asked.evenWithoutSpeech]
18363
- ];
18364
- for (const [name, value] of known) {
18365
- if (value !== void 0) found.add(name);
18366
- }
18367
- for (const [name, value] of Object.entries(asked.args ?? {})) {
18368
- if (name !== "reel" && value !== void 0) found.add(name);
18369
- }
18370
- return [...found].sort();
18371
- }
18372
- async function startRender(engine, asked, passport, key, tell) {
18373
- const place = engine.place();
18374
- if (place === null) return toolError(engine.whyNoEngine());
18375
- const where = fileOrRefusal(asked.video);
18376
- if ("refusal" in where) return toolError(where.refusal);
18377
- if (asked.reel === true) {
18378
- const viewed = await engine.command([
18379
- "composition-view",
18380
- "--project",
18381
- path(where.path),
18382
- "--json"
18383
- ]);
18384
- if (!viewed.ok) return toolError(viewed.text);
18385
- try {
18386
- const lines = viewed.text.trim().split("\n");
18387
- const answer = JSON.parse(lines[lines.length - 1] ?? "{}");
18388
- if (answer.universal === true) {
18389
- const extra = universalOptions(asked);
18390
- if (extra.length > 0) {
18391
- return toolError(
18392
- `\u041E\u0431\u0449\u0438\u0439 naparnik-project/1 \u0443\u0436\u0435 \u0445\u0440\u0430\u043D\u0438\u0442 \u043D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0438 \u043C\u043E\u043D\u0442\u0430\u0436\u0430 \u0432 \u0441\u0430\u043C\u043E\u043C project, \u043F\u043E\u044D\u0442\u043E\u043C\u0443 render \u043D\u0435 \u043F\u0440\u0438\u043C\u0435\u043D\u0438\u0442 \u043A \u043D\u0435\u043C\u0443 legacy-\u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u044B: ${extra.join(", ")}.
18393
- \u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C: \u0432\u043D\u0435\u0441\u0438 \u044D\u0442\u0438 \u0438\u0437\u043C\u0435\u043D\u0435\u043D\u0438\u044F \u0432 project \u0447\u0435\u0440\u0435\u0437 plan_edit \u0438 \u043F\u043E\u0437\u043E\u0432\u0438 render \u0442\u043E\u043B\u044C\u043A\u043E \u0441 reel.`
18394
- );
18395
- }
18396
- return startComposition(engine, where.path, key, tell);
18397
- }
18398
- } catch {
18399
- return toolError(
18400
- "\u0414\u0432\u0438\u0436\u043E\u043A \u043D\u0435 \u0441\u043C\u043E\u0433 \u043E\u043F\u0440\u0435\u0434\u0435\u043B\u0438\u0442\u044C \u0432\u0438\u0434 \u043F\u0440\u043E\u0435\u043A\u0442\u0430. \u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C: \u043E\u0431\u043D\u043E\u0432\u0438 \u043D\u0430\u0447\u0438\u043D\u043A\u0443 \u0447\u0435\u0440\u0435\u0437 setup."
18401
- );
18402
- }
18403
- }
18404
- const onlyPauses = asked.onlyPauses === true;
18405
- const line = onlyPauses ? ["--without-subs"] : [];
18406
- if (asked.style !== void 0) line.push("--style", path(asked.style));
18407
- if (asked.preset !== void 0) line.push("--preset", asked.preset);
18408
- if (asked.model !== void 0) line.push("--model", asked.model);
18409
- if (asked.tempo !== void 0 && asked.tempo !== 1) line.push("--tempo", String(asked.tempo));
18410
- if (asked.keepPauses === true) line.push("--keep-pauses");
18411
- if (asked.fromScratch === true) line.push("--afresh");
18412
- if (asked.evenWithoutSpeech === true) line.push("--anyway");
18413
- if (asked.redo !== void 0 && asked.redo.length > 0) line.push("--only", ...asked.redo);
18414
- line.push(...readCapabilities(asked.args ?? {}, passport));
18415
- const what = onlyPauses ? `\u043F\u0430\u0443\u0437\u044B ${basename(where.path)}` : `\u043C\u043E\u043D\u0442\u0430\u0436 ${basename(where.path)}`;
18416
- return startMontage(engine, {
18417
- key,
18418
- place,
18419
- ...onlyPauses ? { ladder: PAUSES_LADDER } : {},
18420
- ...tell !== void 0 ? { tell } : {},
18421
- video: where.path,
18422
- what,
18423
- // ⚠ КЛЮЧИ ЭТОГО СЛОВАРЯ — ДВИЖКОВЫЕ, И ПЕРЕИМЕНОВЫВАТЬ ИХ НЕЛЬЗЯ. По ним
18424
- // движок узнаёт повторный вызов с той же настройкой — то самое «повторный
18425
- // монтаж почти ничего не считает». Имя инструмента тут прежнее (`montage`,
18426
- // `cut_pauses`) нарочно: смени его — и каждое задание выглядело бы новым, а
18427
- // кэш перестал бы срабатывать молча.
18428
- command: onlyPauses ? { "tool": "cut_pauses", "args": { style: asked.style, tempo: asked.tempo } } : {
18429
- "tool": "montage",
18430
- "args": {
18431
- style: asked.style,
18432
- preset: asked.preset,
18433
- model: asked.model,
18434
- tempo: asked.tempo,
18435
- keep_pauses: asked.keepPauses === true
18436
- }
18437
- },
18438
- ...asked.style !== void 0 ? { style: path(asked.style) } : {},
18439
- args: line,
18440
- hint: onlyPauses ? "\u0411\u044B\u0441\u0442\u0440\u043E, \u043E\u0431\u044B\u0447\u043D\u043E \u043C\u0435\u043D\u044C\u0448\u0435 \u043C\u0438\u043D\u0443\u0442\u044B." : "\u041F\u0435\u0440\u0432\u044B\u0439 \u0440\u0430\u0437 \u2014 \u043C\u0438\u043D\u0443\u0442\u044B; \u043F\u043E\u0432\u0442\u043E\u0440\u043D\u044B\u0439 \u0441 \u0442\u043E\u0439 \u0436\u0435 \u043D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u043E\u0439 \u2014 \u0441\u0435\u043A\u0443\u043D\u0434\u044B."
18441
- });
18442
- }
18443
- async function startComposition(engine, reel, key, tell) {
18444
- const place = engine.place();
18445
- if (place === null) return toolError(engine.whyNoEngine());
18446
- const trouble = await engine.pythonTrouble();
18447
- if (trouble !== null) return toolError(trouble);
18448
- const python = engine.packPython();
18449
- if (python === null) {
18450
- return toolError("\u041E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u0435 \u043C\u043E\u043D\u0442\u0430\u0436\u0430 \u0435\u0449\u0451 \u043D\u0435 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u043E. \u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C: \u043F\u043E\u0437\u043E\u0432\u0438 setup.");
18451
- }
18452
- if (tell !== void 0) {
18453
- tell("\u041F\u0440\u043E\u0432\u0435\u0440\u044E \u0442\u043E\u0447\u043D\u0443\u044E \u0440\u0435\u0434\u0430\u043A\u0446\u0438\u044E \u043F\u0440\u043E\u0435\u043A\u0442\u0430 \u0438 \u0435\u0433\u043E \u0438\u0441\u0445\u043E\u0434\u043D\u0438\u043A\u0438.");
18454
- tell("\u0421\u043E\u0431\u0435\u0440\u0443 \u044D\u0444\u0444\u0435\u043A\u0442\u044B, \u0432\u0438\u0434\u0435\u043E \u0438 \u0437\u0432\u0443\u043A \u043F\u043E \u043E\u0431\u0449\u0435\u0439 \u043A\u043E\u043C\u043F\u043E\u0437\u0438\u0446\u0438\u0438.");
18455
- }
18456
- const launch = await engine.background({
18457
- place,
18458
- executable: python,
18459
- key,
18460
- startJob: [
18461
- "job-create",
18462
- "--video",
18463
- reel,
18464
- "--composition",
18465
- "--what",
18466
- `\u043C\u043E\u043D\u0442\u0430\u0436 ${basename(reel)}`,
18467
- "--command",
18468
- JSON.stringify({ tool: "composition", args: {} })
18469
- ],
18470
- args: (id) => [
18471
- place.consolePy,
18472
- "composition-render",
18473
- "--project",
18474
- reel,
18475
- "--job",
18476
- id
18477
- ],
18478
- advice: "\u043F\u043E\u0437\u043E\u0432\u0438 setup \u2014 \u0441\u043A\u043E\u0440\u0435\u0435 \u0432\u0441\u0435\u0433\u043E, \u043E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u0435 \u043D\u0435\u043F\u043E\u043B\u043D\u043E\u0435"
18479
- });
18480
- if ("refusal" in launch) return toolError(launch.refusal);
18481
- return toolSuccess(
18482
- `\u0417\u0430\u0434\u0430\u0447\u0430 ${launch.id}: \u043C\u043E\u043D\u0442\u0430\u0436 ${basename(reel)}
18483
- \u0414\u0430\u043B\u044C\u0448\u0435 \u043F\u043E\u0437\u043E\u0432\u0438 wait \u0441 \u044D\u0442\u0438\u043C \u043D\u043E\u043C\u0435\u0440\u043E\u043C. ${AWAY_NOTE}`,
18484
- startedJob({
18485
- id: launch.id,
18486
- what: `\u043C\u043E\u043D\u0442\u0430\u0436 ${basename(reel)}`,
18487
- ahead: "\u041F\u0440\u043E\u0432\u0435\u0440\u044E \u043F\u0440\u043E\u0435\u043A\u0442. \u0421\u043E\u0431\u0435\u0440\u0443 \u044D\u0444\u0444\u0435\u043A\u0442\u044B, \u0432\u0438\u0434\u0435\u043E \u0438 \u0437\u0432\u0443\u043A.",
18488
- message: "\u041E\u0431\u0449\u0438\u0439 \u043F\u0440\u043E\u0435\u043A\u0442 \u0441\u043E\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044F \u043D\u0430 \u043A\u043E\u043C\u043F\u044C\u044E\u0442\u0435\u0440\u0435 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F."
18489
- })
18490
- );
18491
- }
18492
- async function followWork(engine, asked, pace = realPace, tell) {
18493
- const ask2 = () => engine.command(["job", asked.job]);
18494
- const seconds2 = waitSeconds(asked.seconds ?? WAIT_LIMIT_SECONDS);
18495
- if (seconds2 === 0) return asJobResult(await ask2());
18496
- const state = await followJob({
18497
- ask: ask2,
18498
- seconds: seconds2,
18499
- pace,
18500
- // ⚠ Рассказ есть только если КЛИЕНТ его попросил (токен хода работы в
18501
- // `_meta`). Нет — ждём молча и отвечаем итогом: ждать всё равно дешевле
18502
- // пяти кругов переписки «спроси ещё раз».
18503
- ...tell !== void 0 ? { tell } : {}
18504
- });
18505
- if (state.ok && stillWorking(state.text)) {
18506
- const words = `${state.text}
18507
- \u0416\u0434\u0430\u043B ${seconds2} \u0441, \u0440\u0430\u0431\u043E\u0442\u0430 \u0435\u0449\u0451 \u0438\u0434\u0451\u0442. \u0421\u043A\u0430\u0436\u0438 \u044D\u0442\u043E \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0443 \u0438 \u043F\u043E\u0437\u043E\u0432\u0438 wait \u0435\u0449\u0451 \u0440\u0430\u0437 \u2014 \u0442\u0430\u043A \u043E\u043D \u0443\u0441\u043B\u044B\u0448\u0438\u0442 \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0438\u0435 \u0448\u0430\u0433\u0438.`;
18508
- const job = readJob(state.text);
18509
- return job === null ? toolSuccess(words) : toolSuccess(words, job);
18510
- }
18511
- return asJobResult(state);
18512
- }
18513
- async function listJobs(engine, asked) {
18514
- return asToolResult(
18515
- await engine.command([
18516
- "jobs",
18517
- ...asked.video !== void 0 ? ["--video", path(asked.video)] : [],
18518
- ...asked.limit !== void 0 ? ["--count", String(asked.limit)] : []
18519
- ])
18520
- );
18521
- }
18522
- function renderDeclared(passport) {
18523
- return external_exports.object({
18524
- video: external_exports.string().describe(
18525
- "\u041F\u0443\u0442\u044C \u043A \u0432\u0438\u0434\u0435\u043E\u0444\u0430\u0439\u043B\u0443 \u043D\u0430 \u043A\u043E\u043C\u043F\u044C\u044E\u0442\u0435\u0440\u0435 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430. \u0417\u0430\u0432\u0435\u0434\u0451\u043D\u043D\u044B\u0439 \u0440\u043E\u043B\u0438\u043A \u043C\u043E\u0436\u043D\u043E \u043D\u0430\u0437\u0432\u0430\u0442\u044C \u0438 \u043F\u0430\u043F\u043A\u043E\u0439 \u2014 \u043A\u043B\u044E\u0447\u043E\u043C reel"
18526
- ).optional(),
18527
- reel: external_exports.string().describe(
18528
- "\u041F\u0430\u043F\u043A\u0430 \u0437\u0430\u0432\u0435\u0434\u0451\u043D\u043D\u043E\u0433\u043E \u0440\u043E\u043B\u0438\u043A\u0430. \u0422\u043E \u0436\u0435, \u0447\u0442\u043E video, \u0442\u043E\u043B\u044C\u043A\u043E \u0434\u043B\u044F \u0440\u043E\u043B\u0438\u043A\u0430 \u0446\u0435\u043B\u0438\u043A\u043E\u043C: \u0438\u0441\u0445\u043E\u0434\u043D\u0438\u043A\u0438, \u0431\u0440\u0438\u0444 \u0438 \u043F\u0440\u0430\u0432\u043A\u0438 \u043F\u043B\u0430\u043D\u0430 \u0434\u0432\u0438\u0436\u043E\u043A \u0432\u043E\u0437\u044C\u043C\u0451\u0442 \u0438\u0437 \u043D\u0435\u0451 \u0441\u0430\u043C"
18529
- ).optional(),
18530
- only_pauses: external_exports.boolean().describe(
18531
- "\u0422\u043E\u043B\u044C\u043A\u043E \u0443\u0431\u0440\u0430\u0442\u044C \u043C\u043E\u043B\u0447\u0430\u043D\u0438\u0435 \u0438 \u0437\u0430\u043F\u0438\u043D\u043A\u0438. \u0420\u0435\u0447\u044C \u043F\u0440\u0438 \u044D\u0442\u043E\u043C \u041D\u0415 \u0440\u0430\u0441\u043F\u043E\u0437\u043D\u0430\u0451\u0442\u0441\u044F \u0438 \u0447\u0435\u0440\u043D\u043E\u0432\u0438\u043A\u0430 \u043D\u0435\u0442: \u0447\u0435\u043B\u043E\u0432\u0435\u043A, \u043F\u043E\u043F\u0440\u043E\u0441\u0438\u0432\u0448\u0438\u0439 \xAB\u043F\u0440\u043E\u0441\u0442\u043E \u0443\u0431\u0435\u0440\u0438 \u0442\u0438\u0448\u0438\u043D\u0443\xBB, \u043D\u0435 \u0436\u0434\u0451\u0442 \u043C\u0438\u043D\u0443\u0442\u044B \u0438 \u043D\u0435 \u043A\u0430\u0447\u0430\u0435\u0442 \u043F\u043E\u043B\u0442\u043E\u0440\u0430 \u0433\u0438\u0433\u0430\u0431\u0430\u0439\u0442\u0430. \u0421\u0443\u0431\u0442\u0438\u0442\u0440\u044B \u0438 \u0433\u0440\u0430\u0444\u0438\u043A\u0443 \u044D\u0442\u0438\u043C \u043D\u0435 \u0441\u043E\u0431\u0440\u0430\u0442\u044C"
18532
- ).optional(),
18533
- style: external_exports.string().describe(
18534
- "\u041F\u0430\u043F\u043A\u0430 \u043F\u0430\u043A\u0430 \u0444\u0438\u0440\u043C\u0435\u043D\u043D\u043E\u0433\u043E \u0441\u0442\u0438\u043B\u044F. \u041D\u0435 \u0443\u043A\u0430\u0437\u0430\u043D \u2014 \u0431\u0435\u0440\u0451\u0442\u0441\u044F \u0441\u0442\u0438\u043B\u044C \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430 \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E, \u0430 \u0435\u0441\u043B\u0438 \u0438 \u0435\u0433\u043E \u043D\u0435\u0442, \u0432\u0441\u0442\u0440\u043E\u0435\u043D\u043D\u044B\u0439 \u043D\u0435\u0439\u0442\u0440\u0430\u043B\u044C\u043D\u044B\u0439"
18535
- ).optional(),
18536
- preset: external_exports.string().describe(
18537
- "\u0418\u043C\u044F \u043F\u0440\u0435\u0441\u0435\u0442\u0430 \u0432\u0438\u0434\u0430 \u0418\u0417 \u041F\u0410\u041A\u0410 \u0421\u0422\u0418\u041B\u042F \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430. \u041D\u0435 \u0432\u044B\u0434\u0443\u043C\u044B\u0432\u0430\u0439 \u0438\u043C\u0435\u043D\u0430: \u0443 \u043D\u0435\u0433\u043E \u043C\u043E\u0436\u0435\u0442 \u0431\u044B\u0442\u044C \u043E\u0434\u0438\u043D \u043F\u0440\u0435\u0441\u0435\u0442 \u0438\u043B\u0438 \u0441\u0432\u043E\u0438"
18538
- ).optional(),
18539
- model: fromList(
18540
- passport?.["models"],
18541
- `\u041C\u043E\u0434\u0435\u043B\u044C \u0440\u0430\u0441\u043F\u043E\u0437\u043D\u0430\u0432\u0430\u043D\u0438\u044F \u0440\u0435\u0447\u0438. ${aboutModels(passport)}`
18542
- ).optional(),
18543
- tempo: external_exports.number().describe("\u0423\u0441\u043A\u043E\u0440\u0435\u043D\u0438\u0435 \u0440\u0435\u0447\u0438, 1.0 \u2014 \u0431\u0435\u0437 \u0443\u0441\u043A\u043E\u0440\u0435\u043D\u0438\u044F").optional(),
18544
- keep_pauses: external_exports.boolean().describe("\u041D\u0435 \u0442\u0440\u043E\u0433\u0430\u0442\u044C \u043F\u0430\u0443\u0437\u044B, \u0442\u043E\u043B\u044C\u043A\u043E \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u044B").optional(),
18545
- redo: external_exports.array(fromList(passport?.["stages"], "\u0418\u043C\u044F \u0448\u0430\u0433\u0430 \u043C\u043E\u043D\u0442\u0430\u0436\u0430")).describe(
18546
- "\u0421\u043E\u0431\u0440\u0430\u0442\u044C \u043D\u0430\u0437\u0432\u0430\u043D\u043D\u044B\u0435 \u0448\u0430\u0433\u0438 \u0437\u0430\u043D\u043E\u0432\u043E, \u0434\u0430\u0436\u0435 \u0435\u0441\u043B\u0438 \u0433\u043E\u0442\u043E\u0432\u043E\u0435 \u0443\u0436\u0435 \u043B\u0435\u0436\u0438\u0442. \u041D\u0443\u0436\u043D\u043E \u0440\u0435\u0434\u043A\u043E \u2014 \u043D\u0430\u043F\u0440\u0438\u043C\u0435\u0440, \u043A\u043E\u0433\u0434\u0430 \u043F\u043E\u0434\u043C\u0435\u043D\u0438\u043B\u0438 \u0438\u0441\u0445\u043E\u0434\u043D\u0438\u043A \u0442\u0435\u043C \u0436\u0435 \u0438\u043C\u0435\u043D\u0435\u043C" + (passport !== null ? `. \u0428\u0430\u0433\u0438: ${passport["stages"].join(", ")}` : "")
18547
- ).optional(),
18548
- from_scratch: external_exports.boolean().describe(
18549
- "\u0421\u0447\u0438\u0442\u0430\u0442\u044C \u0432\u0441\u0451 \u0437\u0430\u043D\u043E\u0432\u043E, \u043A\u044D\u0448 \u043D\u0435 \u0442\u0440\u043E\u0433\u0430\u0442\u044C. \u0414\u043E\u0440\u043E\u0433\u043E: \u0440\u0430\u0441\u043F\u043E\u0437\u043D\u0430\u0432\u0430\u043D\u0438\u0435 \u0440\u0435\u0447\u0438 \u044D\u0442\u043E \u043C\u0438\u043D\u0443\u0442\u044B. \u0421\u043D\u0430\u0447\u0430\u043B\u0430 \u043F\u043E\u043F\u0440\u043E\u0431\u0443\u0439 redo \u0441 \u043E\u0434\u043D\u0438\u043C \u0448\u0430\u0433\u043E\u043C"
18550
- ).optional(),
18551
- even_without_speech: external_exports.boolean().describe(
18552
- "\u0421\u043E\u0431\u0440\u0430\u0442\u044C, \u0434\u0430\u0436\u0435 \u0435\u0441\u043B\u0438 \u043C\u043E\u043D\u0442\u0430\u0436 \u0433\u043E\u0432\u043E\u0440\u0438\u0442 \xAB\u0440\u0435\u0447\u0438 \u0432 \u0444\u0430\u0439\u043B\u0435 \u043D\u0435\u0442\xBB. \u0421\u0442\u0430\u0432\u044C \u0422\u041E\u041B\u042C\u041A\u041E \u043F\u043E\u0441\u043B\u0435 \u0442\u043E\u0433\u043E, \u043A\u0430\u043A \u0441\u043F\u0440\u043E\u0441\u0438\u043B \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430 \u0438 \u043E\u043D \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u043B, \u0447\u0442\u043E \u0440\u0435\u0447\u044C \u0442\u0430\u043C \u0435\u0441\u0442\u044C: \u043D\u0430 \u043A\u043B\u0438\u043F\u0430\u0445 \u043F\u043E\u0434 \u043C\u0443\u0437\u044B\u043A\u0443 \u0434\u0432\u0438\u0436\u043E\u043A \u0440\u0430\u0441\u043F\u043E\u0437\u043D\u0430\u0432\u0430\u043D\u0438\u044F \u0432\u044B\u0434\u0443\u043C\u044B\u0432\u0430\u0435\u0442 \u0441\u043B\u043E\u0432\u0430, \u0438 \u043E\u043D\u0438 \u043F\u043E\u043F\u0430\u0434\u0443\u0442 \u0432 \u043A\u0430\u0434\u0440"
18553
- ).optional()
18554
- });
18555
- }
18556
- var NOT_FOR_PAUSES = ["preset", "model", "keep_pauses", "redo", "even_without_speech"];
18557
- function renderArgs(passport) {
18558
- const ours = renderDeclared(passport);
18559
- const packKeys = capabilitiesToSchema(passport, new Set(Object.keys(ours.shape)));
18560
- return ours.extend(packKeys);
18561
- }
18562
- function renderTool(engine, passport, key) {
18563
- return defineTool({
18564
- name: "render",
18565
- title: "\u0421\u043E\u0431\u0440\u0430\u0442\u044C \u0440\u043E\u043B\u0438\u043A",
18566
- description: "\u0421\u043E\u0431\u0438\u0440\u0430\u0435\u0442 \u0440\u043E\u043B\u0438\u043A \u043D\u0430 \u043A\u043E\u043C\u043F\u044C\u044E\u0442\u0435\u0440\u0435 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430: \u0443\u0431\u0438\u0440\u0430\u0435\u0442 \u043F\u0430\u0443\u0437\u044B, \u0441\u0442\u0430\u0432\u0438\u0442 \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u044B \u043F\u043E \u0441\u043B\u043E\u0432\u0430\u043C, \u0440\u0438\u0441\u0443\u0435\u0442 \u0433\u0440\u0430\u0444\u0438\u043A\u0443 \u043F\u043E \u043F\u043B\u0430\u043D\u0443, \u0441\u0432\u043E\u0434\u0438\u0442 \u0437\u0432\u0443\u043A. \u0417\u043E\u0432\u0438 \u041F\u041E\u0421\u041B\u0415 \u0442\u043E\u0433\u043E, \u043A\u0430\u043A \u0447\u0435\u043B\u043E\u0432\u0435\u043A \u0441\u043A\u0430\u0437\u0430\u043B \xAB\u0434\u0430\xBB \u043D\u0430 \u0447\u0435\u0440\u043D\u043E\u0432\u0438\u043A \u0438\u0437 plan: \u0441\u043E\u0431\u0440\u0430\u043D\u043D\u044B\u0439 \u043A\u0430\u0434\u0440 \u0441\u043F\u043E\u0440\u0438\u0442\u044C \u0434\u043E\u0440\u043E\u0436\u0435, \u0447\u0435\u043C \u0441\u0442\u0440\u043E\u0447\u043A\u0443 \u043F\u043B\u0430\u043D\u0430.\n\u0421\u043E\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044F \u0422\u041E\u041B\u042C\u041A\u041E \u0441\u043E\u0433\u043B\u0430\u0441\u043E\u0432\u0430\u043D\u043D\u044B\u0439 \u043F\u043B\u0430\u043D, \u0438 \xAB\u0434\u0430\xBB \u0432 \u0447\u0430\u0442\u0435 \u0441\u0430\u043C\u043E \u043F\u043E \u0441\u0435\u0431\u0435 \u043D\u0435 \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044F: \u0437\u0430\u043F\u0438\u0448\u0438 \u0435\u0433\u043E \u0432\u044B\u0437\u043E\u0432\u043E\u043C plan_edit \u0441 confirm \u2014 \u0442\u0435\u043C \u0436\u0435, \u043A\u043E\u0442\u043E\u0440\u044B\u043C \u0448\u043B\u0451\u0448\u044C \u043F\u043E\u0441\u043B\u0435\u0434\u043D\u044E\u044E \u043F\u0440\u0430\u0432\u043A\u0443. \u041B\u044E\u0431\u0430\u044F \u043F\u0440\u0430\u0432\u043A\u0430 \u0441\u043E\u0433\u043B\u0430\u0441\u0438\u0435 \u0441\u043D\u0438\u043C\u0430\u0435\u0442, \u043F\u043E\u044D\u0442\u043E\u043C\u0443 \u043F\u043E\u0440\u044F\u0434\u043E\u043A \u0442\u0430\u043A\u043E\u0439: \u043F\u043E\u043F\u0440\u0430\u0432\u0438\u043B, \u043F\u0435\u0440\u0435\u0441\u043A\u0430\u0437\u0430\u043B \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0443, \u0443\u0441\u043B\u044B\u0448\u0430\u043B \xAB\u0434\u0430\xBB, \u043F\u043E\u0437\u0432\u0430\u043B plan_edit \u0441 confirm, \u0438 \u0442\u043E\u043B\u044C\u043A\u043E \u0442\u0435\u043F\u0435\u0440\u044C render.\n\u0415\u0441\u043B\u0438 reel \u0441\u043E\u0434\u0435\u0440\u0436\u0438\u0442 \u043E\u0431\u0449\u0438\u0439 naparnik-project/1, render \u0441\u0430\u043C \u0432\u044B\u0431\u0438\u0440\u0430\u0435\u0442 \u0443\u043D\u0438\u0432\u0435\u0440\u0441\u0430\u043B\u044C\u043D\u0443\u044E \u0441\u0431\u043E\u0440\u043A\u0443; \u043E\u0442\u0434\u0435\u043B\u044C\u043D\u043E\u0433\u043E \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u0430 \u0434\u043B\u044F \u043D\u0435\u0451 \u043D\u0435\u0442. \u0412\u0441\u0435 \u043D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0438 \u0442\u0430\u043A\u043E\u0433\u043E \u043C\u043E\u043D\u0442\u0430\u0436\u0430 \u0443\u0436\u0435 \u043B\u0435\u0436\u0430\u0442 \u0432 project: \u0432\u043C\u0435\u0441\u0442\u0435 \u0441 reel \u043D\u0435 \u043F\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0439 style, preset, tempo \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u044B \u0441\u0442\u0430\u0440\u043E\u0433\u043E \u043C\u043E\u043D\u0442\u0430\u0436\u0430 \u2014 \u043D\u0443\u0436\u043D\u0443\u044E \u043F\u0440\u0430\u0432\u043A\u0443 \u0441\u043D\u0430\u0447\u0430\u043B\u0430 \u0437\u0430\u043F\u0438\u0448\u0438 \u0447\u0435\u0440\u0435\u0437 plan_edit.\n\u041E\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u043D\u043E\u043C\u0435\u0440\u043E\u043C \u0437\u0430\u0434\u0430\u0447\u0438 \u2014 \u0434\u0430\u043B\u044C\u0448\u0435 wait, \u043E\u043D \u043F\u043E\u0434\u043E\u0436\u0434\u0451\u0442 \u0438 \u0440\u0430\u0441\u0441\u043A\u0430\u0436\u0435\u0442 \u0445\u043E\u0434. \u041F\u043E\u0432\u0442\u043E\u0440\u043D\u044B\u0439 \u0432\u044B\u0437\u043E\u0432 \u0441 \u0442\u043E\u0439 \u0436\u0435 \u043D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u043E\u0439 \u043F\u043E\u0447\u0442\u0438 \u043D\u0438\u0447\u0435\u0433\u043E \u043D\u0435 \u0434\u0435\u043B\u0430\u0435\u0442 \u0437\u0430\u043D\u043E\u0432\u043E: \u0432\u0441\u0451 \u0431\u0435\u0440\u0451\u0442\u0441\u044F \u0438\u0437 \u043A\u044D\u0448\u0430.\n\u041F\u0440\u043E\u0441\u044F\u0442 \xAB\u043F\u0440\u043E\u0441\u0442\u043E \u0443\u0431\u0435\u0440\u0438 \u043F\u0430\u0443\u0437\u044B\xBB, \xAB\u0443\u0431\u0435\u0440\u0438 \u0442\u0438\u0448\u0438\u043D\u0443\xBB \u2014 only_pauses=true: \u0440\u0435\u0447\u044C \u043F\u0440\u0438 \u044D\u0442\u043E\u043C \u043D\u0435 \u0440\u0430\u0441\u043F\u043E\u0437\u043D\u0430\u0451\u0442\u0441\u044F, \u0447\u0435\u0440\u043D\u043E\u0432\u0438\u043A\u0430 \u043D\u0435\u0442 \u0438 \u0441\u043E\u0433\u043B\u0430\u0441\u043E\u0432\u044B\u0432\u0430\u0442\u044C \u043D\u0435\u0447\u0435\u0433\u043E. \u041A\u0430\u0440\u0442\u043E\u0447\u043A\u0430 \u0432 \u043D\u0430\u0447\u0430\u043B\u0435 (plan_edit, \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u044F intro) \u0440\u0430\u0431\u043E\u0442\u0430\u0435\u0442 \u0438 \u0437\u0434\u0435\u0441\u044C: \u043E\u043D\u0430 \u043D\u0435 \u043F\u0440\u043E \u0440\u0435\u0447\u044C, \u0430 \u043F\u0440\u043E \u0442\u043E, \u0447\u0442\u043E \u0432\u0441\u0442\u0430\u0451\u0442 \u041F\u0415\u0420\u0415\u0414 \u0440\u043E\u043B\u0438\u043A\u043E\u043C.\n\u0420\u0430\u0431\u043E\u0442\u0430 \u0438\u0434\u0451\u0442 \u043D\u0430 \u043A\u043E\u043C\u043F\u044C\u044E\u0442\u0435\u0440\u0435 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430, \u043A \u043D\u0430\u043C \u0432\u0438\u0434\u0435\u043E \u043D\u0435 \u0443\u0445\u043E\u0434\u0438\u0442 \u2014 \u043D\u0430\u0432\u0435\u0440\u0445 \u0438\u0434\u0451\u0442 \u0442\u043E\u043B\u044C\u043A\u043E \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0430 \u043F\u043E\u0434\u043F\u0438\u0441\u043A\u0438 \u043F\u043E \u043A\u043B\u044E\u0447\u0443.",
18567
- // Полоса хода работы: монтаж идёт минутами, и всё это время в ленте не
18568
- // происходило бы ничего. ⚠ Ожидание — у `wait`, и полосы там нет: иначе
18569
- // каждая проверка рисовала бы новую поверх этой.
18570
- ui: { resourceUri: RUNBAR_RESOURCE_URI },
18571
- // ⚠ КЛЮЧИ ПАКА ДОБАВЛЯЮТСЯ К СХЕМЕ ЧЕРЕЗ `extend`, А ТИП ОСТАЁТСЯ ОТ
18572
- // ОБЪЯВЛЕННОЙ ЧАСТИ. Их набор известен только в рантайме (паспорт пака), и
18573
- // выведенный из них тип превратился бы в словарь со свободными ключами —
18574
- // тогда `args.video` перестал бы быть строкой, а описка в имени поля
18575
- // перестала бы быть ошибкой компиляции. В объявление модели они при этом
18576
- // попадают полностью: схема-то настоящая.
18577
- args: renderArgs(passport).check((ctx) => {
18578
- const asked = ctx.value;
18579
- const say = (message, where) => {
18580
- ctx.issues.push({ code: "custom", message, input: asked, path: [where] });
18581
- };
18582
- const video = asked["video"];
18583
- const reel = asked["reel"];
18584
- if (video === void 0 && reel === void 0) {
18585
- say(
18586
- "\u041D\u0435 \u0441\u043A\u0430\u0437\u0430\u043D\u043E, \u0447\u0442\u043E \u0441\u043E\u0431\u0438\u0440\u0430\u0442\u044C: \u043D\u0430\u0437\u043E\u0432\u0438 video (\u0444\u0430\u0439\u043B) \u0438\u043B\u0438 reel (\u043F\u0430\u043F\u043A\u0443 \u0437\u0430\u0432\u0435\u0434\u0451\u043D\u043D\u043E\u0433\u043E \u0440\u043E\u043B\u0438\u043A\u0430). \u0427\u0442\u043E \u0443 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430 \u0435\u0441\u0442\u044C, \u043F\u043E\u043A\u0430\u0436\u0435\u0442 plan \u0431\u0435\u0437 \u0430\u0440\u0433\u0443\u043C\u0435\u043D\u0442\u043E\u0432",
18587
- "video"
18588
- );
18589
- }
18590
- if (video !== void 0 && reel !== void 0) {
18591
- say("\xABvideo\xBB \u0438 \xABreel\xBB \u2014 \u044D\u0442\u043E \u043E\u0434\u043D\u043E \u0438 \u0442\u043E \u0436\u0435 \u043C\u0435\u0441\u0442\u043E, \u043D\u0430\u0437\u0432\u0430\u043D\u043D\u043E\u0435 \u0434\u0432\u0430\u0436\u0434\u044B. \u041E\u0441\u0442\u0430\u0432\u044C \u043E\u0434\u043D\u043E", "reel");
18592
- }
18593
- if (asked["only_pauses"] !== true) return;
18594
- const extra = NOT_FOR_PAUSES.filter((name) => asked[name] !== void 0);
18595
- if (extra.length > 0) {
18596
- say(
18597
- `\xABonly_pauses\xBB \u0440\u0435\u0436\u0435\u0442 \u0442\u0438\u0448\u0438\u043D\u0443 \u0438 \u043D\u0430 \u044D\u0442\u043E\u043C \u043E\u0441\u0442\u0430\u043D\u0430\u0432\u043B\u0438\u0432\u0430\u0435\u0442\u0441\u044F \u2014 \u043B\u0438\u0448\u043D\u0435\u0435: ${extra.join(", ")}. \u041F\u043E\u0437\u043E\u0432\u0438 \u043B\u0438\u0431\u043E \u0441 only_pauses, \u043B\u0438\u0431\u043E \u0437\u0430 \u043F\u043E\u043B\u043D\u044B\u043C \u043C\u043E\u043D\u0442\u0430\u0436\u043E\u043C`,
18598
- "only_pauses"
18599
- );
18600
- }
18601
- }),
18602
- async execute(args, ctx) {
18603
- const all = args;
18604
- const video = args.video ?? args.reel ?? "";
18605
- return startRender(
18606
- engine,
18607
- {
18608
- video,
18609
- reel: args.reel !== void 0,
18610
- onlyPauses: args.only_pauses,
18611
- style: args.style,
18612
- preset: args.preset,
18613
- model: args.model,
18614
- tempo: args.tempo,
18615
- keepPauses: args.keep_pauses,
18616
- redo: args.redo,
18617
- fromScratch: args.from_scratch,
18618
- evenWithoutSpeech: args.even_without_speech,
18619
- args: all
18817
+ rebuild: args.rebuild
18620
18818
  },
18621
- passport,
18622
18819
  key,
18623
18820
  ctx?.emitProgress
18624
18821
  );
18625
18822
  }
18626
18823
  });
18627
18824
  }
18628
- function waitTool(engine, pace = realPace) {
18629
- return defineTool({
18630
- name: "wait",
18631
- title: "\u0414\u043E\u0436\u0434\u0430\u0442\u044C\u0441\u044F \u0440\u0430\u0431\u043E\u0442\u044B",
18632
- description: `\u0416\u0434\u0451\u0442 \u0437\u0430\u0434\u0430\u0447\u0443 \u0438 \u043F\u043E \u0445\u043E\u0434\u0443 \u0440\u0430\u0441\u0441\u043A\u0430\u0437\u044B\u0432\u0430\u0435\u0442, \u043A\u0430\u043A\u043E\u0439 \u0448\u0430\u0433 \u043F\u043E\u0448\u0451\u043B \u0438 \u043A\u0430\u043A\u043E\u0439 \u0437\u0430\u043A\u043E\u043D\u0447\u0438\u043B\u0441\u044F \u2014 \u043F\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, \u043D\u0435 \u0434\u043E\u0436\u0438\u0434\u0430\u044F\u0441\u044C \u043A\u043E\u043D\u0446\u0430. \u0422\u0430\u043A \u0438 \u0441\u043F\u0440\u0430\u0448\u0438\u0432\u0430\u0439: \u043E\u043F\u0440\u0430\u0448\u0438\u0432\u0430\u0442\u044C \u043F\u043E \u043A\u0440\u0443\u0433\u0443 \u043D\u0435 \u043D\u0430\u0434\u043E, \u0436\u0434\u0451\u0442 \u043E\u043D \u0434\u043E ${WAIT_LIMIT_SECONDS} \u0441\u0435\u043A\u0443\u043D\u0434 \u0438 \u0432\u0435\u0440\u043D\u0451\u0442\u0441\u044F \u0440\u0430\u043D\u044C\u0448\u0435, \u0435\u0441\u043B\u0438 \u0440\u0430\u0431\u043E\u0442\u0430 \u043A\u043E\u043D\u0447\u0438\u0442\u0441\u044F.
18633
- \u0411\u0435\u0437 \u0430\u0440\u0433\u0443\u043C\u0435\u043D\u0442\u043E\u0432 \u043F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0435\u0442 \u043F\u043E\u0441\u043B\u0435\u0434\u043D\u0438\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 \u2014 \u043D\u043E\u043C\u0435\u0440, \u0440\u043E\u043B\u0438\u043A, \u0447\u0435\u043C \u043A\u043E\u043D\u0447\u0438\u043B\u043E\u0441\u044C. \u0417\u043E\u0432\u0438, \u043A\u043E\u0433\u0434\u0430 \u043D\u043E\u043C\u0435\u0440 \u043F\u043E\u0442\u0435\u0440\u044F\u043B\u0441\u044F: \u043D\u0430\u043F\u0440\u0438\u043C\u0435\u0440, \u043F\u043E\u0441\u043B\u0435 \u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u043A\u0430 \u043F\u0440\u043E\u0433\u0440\u0430\u043C\u043C\u044B \u0438\u043B\u0438 \u043A\u043E\u0433\u0434\u0430 \u0432\u044B\u0437\u043E\u0432 \u043E\u0431\u043E\u0440\u0432\u0430\u043B\u0441\u044F \u043F\u043E\u0441\u0440\u0435\u0434\u0438 \u0440\u0430\u0431\u043E\u0442\u044B. \u0421 video \u2014 \u0437\u0430\u0434\u0430\u0447\u0438 \u043E\u0434\u043D\u043E\u0433\u043E \u0440\u043E\u043B\u0438\u043A\u0430.
18634
- \u0417\u0430\u0434\u0430\u0447\u0438 \u043B\u0435\u0436\u0430\u0442 \u043D\u0430 \u0434\u0438\u0441\u043A\u0435 \u0438 \u043F\u0435\u0440\u0435\u0436\u0438\u0432\u0430\u044E\u0442 \u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u043A \u043F\u0440\u043E\u0433\u0440\u0430\u043C\u043C\u044B. \u041F\u043E\u0434\u043F\u0438\u0441\u043A\u0430 \u043D\u0435 \u043D\u0443\u0436\u043D\u0430: \u0437\u0430\u0431\u0440\u0430\u0442\u044C \u0443\u0436\u0435 \u0441\u0434\u0435\u043B\u0430\u043D\u043D\u043E\u0435 \u043C\u043E\u0436\u043D\u043E \u0432\u0441\u0435\u0433\u0434\u0430.`,
18635
- args: external_exports.object({
18636
- job: external_exports.string().describe(
18637
- "\u041D\u043E\u043C\u0435\u0440 \u0437\u0430\u0434\u0430\u0447\u0438, \u043D\u0430\u043F\u0440\u0438\u043C\u0435\u0440 2026-08-19T14-03-12Z-a3f1. \u0415\u0433\u043E \u043D\u0430\u0437\u0432\u0430\u043B \u0442\u043E\u0442 \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442, \u0447\u0442\u043E \u0437\u0430\u043F\u0443\u0441\u0442\u0438\u043B \u0440\u0430\u0431\u043E\u0442\u0443"
18638
- ).optional(),
18639
- seconds: external_exports.number().describe(
18640
- `\u0421\u043A\u043E\u043B\u044C\u043A\u043E \u0441\u0435\u043A\u0443\u043D\u0434 \u0436\u0434\u0430\u0442\u044C. \u041F\u043E\u0442\u043E\u043B\u043E\u043A ${WAIT_LIMIT_SECONDS}: \u043F\u0440\u043E\u0441\u044C\u0431\u0430 \u0431\u043E\u043B\u044C\u0448\u0435 \u043C\u043E\u043B\u0447\u0430 \u043E\u0431\u0440\u0435\u0436\u0435\u0442\u0441\u044F. \u0411\u0435\u0437 \u043D\u0435\u0433\u043E \u0436\u0434\u0451\u0442 \u0441\u0442\u043E\u043B\u044C\u043A\u043E, \u0441\u043A\u043E\u043B\u044C\u043A\u043E \u043C\u043E\u0436\u043D\u043E`
18641
- ).optional(),
18642
- video: external_exports.string().describe("\u0422\u043E\u043B\u044C\u043A\u043E \u0437\u0430\u0434\u0430\u0447\u0438 \u044D\u0442\u043E\u0433\u043E \u0440\u043E\u043B\u0438\u043A\u0430 (\u0431\u0435\u0437 job)").optional(),
18643
- limit: external_exports.number().describe("\u0421\u043A\u043E\u043B\u044C\u043A\u043E \u0437\u0430\u0434\u0430\u0447 \u043F\u043E\u043A\u0430\u0437\u0430\u0442\u044C, \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E 15").optional()
18644
- }).check((ctx) => {
18645
- const asked = ctx.value;
18646
- if (asked.job === void 0) {
18647
- if (asked.seconds !== void 0) {
18648
- ctx.issues.push({
18649
- code: "custom",
18650
- message: "\xABseconds\xBB \u2014 \u044D\u0442\u043E \u0441\u043A\u043E\u043B\u044C\u043A\u043E \u0436\u0434\u0430\u0442\u044C \u041E\u0414\u041D\u0423 \u0437\u0430\u0434\u0430\u0447\u0443: \u043D\u0430\u0437\u043E\u0432\u0438 \u0435\u0451 \u043D\u043E\u043C\u0435\u0440 \u0432 \xABjob\xBB",
18651
- input: asked,
18652
- path: ["seconds"]
18653
- });
18654
- }
18655
- return;
18656
- }
18657
- for (const key of ["video", "limit"]) {
18658
- if (asked[key] !== void 0) {
18659
- ctx.issues.push({
18660
- code: "custom",
18661
- message: `\xAB${key}\xBB \u043E\u0442\u043D\u043E\u0441\u0438\u0442\u0441\u044F \u043A \u0421\u041F\u0418\u0421\u041A\u0423 \u0437\u0430\u0434\u0430\u0447, \u0430 \u0441 \xABjob\xBB \u0436\u0434\u0443\u0442 \u043E\u0434\u043D\u0443. \u041F\u043E\u0437\u043E\u0432\u0438 \u0431\u0435\u0437 \xABjob\xBB, \u0447\u0442\u043E\u0431\u044B \u0443\u0432\u0438\u0434\u0435\u0442\u044C \u0441\u043F\u0438\u0441\u043E\u043A`,
18662
- input: asked,
18663
- path: [key]
18664
- });
18665
- }
18666
- }
18667
- }),
18668
- readOnly: true,
18669
- async execute(args, ctx) {
18670
- const place = engine.place();
18671
- if (place === null) return toolError(engine.whyNoEngine());
18672
- if (args.job === void 0) {
18673
- return listJobs(engine, { video: args.video, limit: args.limit });
18674
- }
18675
- return followWork(engine, { job: args.job, seconds: args.seconds }, pace, ctx?.emitProgress);
18676
- }
18677
- });
18678
- }
18679
18825
  async function showFrame(engine, asked) {
18680
18826
  const video = asked.video;
18681
18827
  const moment = asked.moment;