@naparnik/mcp 0.10.50 → 0.10.53
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/dist/{chunk-DH5ID6CT.js → chunk-HNZNOPSB.js} +1794 -1898
- package/dist/cli.d.ts +41 -1
- package/dist/cli.js +258 -95
- package/dist/index.d.ts +34 -398
- package/dist/index.js +1 -1
- package/dist/tool-1kGke9dT.d.ts +374 -0
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createHash, randomUUID, randomBytes } from 'crypto';
|
|
2
|
-
import { existsSync, readFileSync, closeSync, mkdirSync, openSync, rmSync, renameSync, readdirSync, statSync, writeFileSync, symlinkSync, chmodSync, lstatSync, realpathSync, mkdtempSync, linkSync, readlinkSync, appendFileSync, fstatSync, readSync
|
|
2
|
+
import { existsSync, readFileSync, closeSync, mkdirSync, openSync, rmSync, renameSync, readdirSync, statSync, writeFileSync, symlinkSync, chmodSync, lstatSync, realpathSync, mkdtempSync, linkSync, readlinkSync, appendFileSync, fsyncSync, fstatSync, readSync } from 'fs';
|
|
3
3
|
import { win32, join, dirname, sep, resolve, basename, relative, isAbsolute, extname } from 'path';
|
|
4
4
|
import { gunzipSync } from 'zlib';
|
|
5
5
|
import { execFile, spawn, execFileSync } from 'child_process';
|
|
@@ -232,6 +232,9 @@ function toolMixed(blocks, structured) {
|
|
|
232
232
|
return { type: "success", content: blocks, ...structured !== void 0 ? { structured } : {} };
|
|
233
233
|
}
|
|
234
234
|
function toolError(error40, code) {
|
|
235
|
+
if (code !== void 0) {
|
|
236
|
+
return { type: "error", error: error40, code };
|
|
237
|
+
}
|
|
235
238
|
return { type: "error", error: error40 };
|
|
236
239
|
}
|
|
237
240
|
|
|
@@ -291,6 +294,27 @@ var McpServer = class {
|
|
|
291
294
|
void this.sendNotification("notifications/tools/list_changed");
|
|
292
295
|
}
|
|
293
296
|
}
|
|
297
|
+
/**
|
|
298
|
+
* Заменить весь набор инструментов разом — так новое тело оболочки встаёт
|
|
299
|
+
* без перезапуска (`body-swap.ts`).
|
|
300
|
+
*
|
|
301
|
+
* ⚠ УВЕДОМЛЕНИЕ ХОСТУ — ТОЛЬКО КОГДА ОБЪЯВЛЕНИЕ ИЗМЕНИЛОСЬ. Новое тело чаще
|
|
302
|
+
* всего несёт те же имена и схемы; `notifications/tools/list_changed` на
|
|
303
|
+
* каждую замену заставлял бы хост перечитывать список, а модель — заново
|
|
304
|
+
* смотреть на те же двери. Сравниваем то, что уезжает в `tools/list`.
|
|
305
|
+
*
|
|
306
|
+
* @returns изменилось ли объявление
|
|
307
|
+
*/
|
|
308
|
+
replaceTools(tools) {
|
|
309
|
+
const before = JSON.stringify(this.listMcpTools());
|
|
310
|
+
this.tools.clear();
|
|
311
|
+
for (const tool of tools) this.tools.set(tool.name, tool);
|
|
312
|
+
const changed = JSON.stringify(this.listMcpTools()) !== before;
|
|
313
|
+
if (changed && this.clientInitialized && this.transport !== null) {
|
|
314
|
+
void this.sendNotification("notifications/tools/list_changed");
|
|
315
|
+
}
|
|
316
|
+
return changed;
|
|
317
|
+
}
|
|
294
318
|
/**
|
|
295
319
|
* Удаляет инструмент из MCP-экспорта.
|
|
296
320
|
* @returns true если инструмент был найден и удалён
|
|
@@ -730,7 +754,7 @@ function parsePositiveInt(raw, fallback) {
|
|
|
730
754
|
}
|
|
731
755
|
|
|
732
756
|
// src/version.ts
|
|
733
|
-
var VERSION = "0.10.
|
|
757
|
+
var VERSION = "0.10.53";
|
|
734
758
|
var USER_AGENT = `naparnik-mcp/${VERSION}`;
|
|
735
759
|
var MIN_ENGINE = "2026.09.24-478";
|
|
736
760
|
var LAUNCHER_PROTOCOL = 1;
|
|
@@ -1621,7 +1645,9 @@ var Engine = class {
|
|
|
1621
1645
|
env;
|
|
1622
1646
|
awake;
|
|
1623
1647
|
passportCache;
|
|
1624
|
-
|
|
1648
|
+
pinned;
|
|
1649
|
+
/** Фоновые работы этого процесса, которые ещё идут: номер → версия, на которой заведены. */
|
|
1650
|
+
live = /* @__PURE__ */ new Map();
|
|
1625
1651
|
pythonChecked;
|
|
1626
1652
|
// ─── где что лежит ──────────────────────────────────────────────────────
|
|
1627
1653
|
/**
|
|
@@ -1659,26 +1685,46 @@ var Engine = class {
|
|
|
1659
1685
|
return join(this.home(), "engine");
|
|
1660
1686
|
}
|
|
1661
1687
|
/**
|
|
1662
|
-
* Какая версия движка
|
|
1688
|
+
* Какая версия движка рабочая ДЛЯ СЛЕДУЮЩЕЙ ЗАДАЧИ.
|
|
1663
1689
|
*
|
|
1664
1690
|
* Обычный ТЕКСТОВЫЙ файл, а не симлинк: создание симлинка на Windows требует
|
|
1665
1691
|
* режима разработчика или прав администратора, а строка в файле переносима и
|
|
1666
1692
|
* переименовывается атомарно.
|
|
1667
1693
|
*
|
|
1668
|
-
* ⚠
|
|
1669
|
-
*
|
|
1670
|
-
*
|
|
1671
|
-
*
|
|
1672
|
-
*
|
|
1673
|
-
* двух версий внутри одной задачи не упала бы, а тихо смешала результаты.
|
|
1694
|
+
* ⚠ ВЕРСИЯ ЧИТАЕТСЯ НА СТАРТЕ КАЖДОЙ ЗАДАЧИ, А НЕ ОДИН РАЗ НА ПРОЦЕСС (решение
|
|
1695
|
+
* владельца 2026-09-25: «зачем перезапускать Claude, если код просто
|
|
1696
|
+
* скачался»). Движок — отдельный питон на каждую команду, и новой версии не
|
|
1697
|
+
* нужен новый процесс оболочки. До 2026-09-25 версия запоминалась на всю жизнь
|
|
1698
|
+
* процесса, и каждое обновление кончалось «перезапусти Claude».
|
|
1674
1699
|
*
|
|
1675
|
-
*
|
|
1676
|
-
*
|
|
1677
|
-
*
|
|
1700
|
+
* ⚠ НО ИДУЩАЯ ЗАДАЧА ДОИГРЫВАЕТ НА СВОЕЙ ВЕРСИИ, И ЭТО НЕСУЩЕЕ. У движка кэш
|
|
1701
|
+
* по отпечаткам, и в отпечаток входит код шага: смесь двух версий внутри
|
|
1702
|
+
* одной задачи не упала бы, а тихо смешала результаты. Пока жива фоновая
|
|
1703
|
+
* работа, заведённая этим процессом (`background`), её опрос (`wait`) и её
|
|
1704
|
+
* отказ зовут ту же версию; сменилась — подхватывается после неё.
|
|
1705
|
+
*
|
|
1706
|
+
* `freshVersion()` даёт то, что лежит в файле прямо сейчас, мимо задачи: оно
|
|
1707
|
+
* нужно самому обновлению и новостям о версиях.
|
|
1678
1708
|
*/
|
|
1679
1709
|
currentVersion() {
|
|
1680
|
-
|
|
1681
|
-
|
|
1710
|
+
const fresh = this.freshVersion();
|
|
1711
|
+
if (this.pinned === void 0 || fresh !== this.pinned && this.live.size === 0) {
|
|
1712
|
+
if (this.pinned !== void 0 && fresh !== this.pinned) {
|
|
1713
|
+
this.passportCache = void 0;
|
|
1714
|
+
this.pythonChecked = void 0;
|
|
1715
|
+
}
|
|
1716
|
+
this.pinned = fresh;
|
|
1717
|
+
}
|
|
1718
|
+
return this.pinned;
|
|
1719
|
+
}
|
|
1720
|
+
/**
|
|
1721
|
+
* Идёт ли фоновая работа, заведённая этим процессом.
|
|
1722
|
+
*
|
|
1723
|
+
* Нужен двоим: версии движка (сменить её под живой задачей нельзя) и замене
|
|
1724
|
+
* тела оболочки (`body-swap.ts`): тело меняется, только когда ничего не идёт.
|
|
1725
|
+
*/
|
|
1726
|
+
busy() {
|
|
1727
|
+
return this.live.size > 0;
|
|
1682
1728
|
}
|
|
1683
1729
|
/** Что записано в файле `current` прямо сейчас, мимо памяти процесса. */
|
|
1684
1730
|
freshVersion() {
|
|
@@ -1742,20 +1788,6 @@ var Engine = class {
|
|
|
1742
1788
|
\u0418\u0441\u043A\u0430\u043B: ${join(this.versionsDir(), "<\u0432\u0435\u0440\u0441\u0438\u044F>", "engine", "console.py")}
|
|
1743
1789
|
\u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C: \u043F\u043E\u0437\u043E\u0432\u0438 setup \u2014 \u043E\u043D \u0441\u043A\u0430\u0447\u0430\u0435\u0442 \u043D\u0430\u0447\u0438\u043D\u043A\u0443 \u043C\u043E\u043D\u0442\u0430\u0436\u0430 (\u044D\u0442\u043E \u043E\u0442\u0434\u0435\u043B\u044C\u043D\u044B\u0439 \u0430\u0440\u0442\u0435\u0444\u0430\u043A\u0442: \u043F\u0438\u0442\u043E\u043D \u0438 \u043F\u0430\u043A \u0432\u0435\u0441\u044F\u0442 \u0434\u0435\u0441\u044F\u0442\u043A\u0438 \u043C\u0435\u0433\u0430\u0431\u0430\u0439\u0442, \u0432 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u0435 \u043E\u043D\u0438 \u043D\u0435 \u043A\u043B\u0430\u0434\u0443\u0442\u0441\u044F). \u0421\u043A\u0430\u0447\u0438\u0432\u0430\u043D\u0438\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0441\u043E\u0433\u043B\u0430\u0441\u0438\u044F \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430. \u0415\u0441\u043B\u0438 \u0434\u0432\u0438\u0436\u043E\u043A \u0443 \u043D\u0435\u0433\u043E \u0443\u0436\u0435 \u0435\u0441\u0442\u044C \u0441\u0432\u043E\u0435\u0439 \u043F\u0430\u043F\u043A\u043E\u0439 \u2014 \u043F\u0443\u0442\u044C \u043A \u043D\u0435\u0439 \u0443\u043A\u0430\u0437\u044B\u0432\u0430\u0435\u0442\u0441\u044F \u043F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u043E\u0439 NAPARNIK_ENGINE \u0432 \u043D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0430\u0445 \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u044F, \u043F\u043E\u0441\u043B\u0435 \u0447\u0435\u0433\u043E \u043F\u0440\u043E\u0433\u0440\u0430\u043C\u043C\u0443 \u043D\u0430\u0434\u043E \u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u0442\u0438\u0442\u044C.`;
|
|
1744
1790
|
}
|
|
1745
|
-
/**
|
|
1746
|
-
* Забыть, где движок, — после того как мы его только что поставили.
|
|
1747
|
-
*
|
|
1748
|
-
* ⚠ БЕЗ ЭТОГО ПЕРВАЯ УСТАНОВКА НЕ ВИДНА САМОЙ СЕБЕ. `currentVersion`
|
|
1749
|
-
* запоминается на всю жизнь процесса нарочно (подмена начинки — только на
|
|
1750
|
-
* старте), и сразу после доставки следующий же вызов получил бы
|
|
1751
|
-
* закэшированное «версии нет» про версию, которую мы сами и разложили.
|
|
1752
|
-
* Здесь это не нарушает обещания: смешивать две версии внутри задачи нечем,
|
|
1753
|
-
* до этого момента версии не было вовсе.
|
|
1754
|
-
*/
|
|
1755
|
-
forgetPlace() {
|
|
1756
|
-
this.versionAtStart = void 0;
|
|
1757
|
-
this.passportCache = void 0;
|
|
1758
|
-
}
|
|
1759
1791
|
/** Забыть ответ на вопрос «есть ли питон» — после того как мы его принесли. */
|
|
1760
1792
|
forgetPython() {
|
|
1761
1793
|
this.pythonChecked = void 0;
|
|
@@ -1861,7 +1893,7 @@ var Engine = class {
|
|
|
1861
1893
|
}
|
|
1862
1894
|
} catch {
|
|
1863
1895
|
}
|
|
1864
|
-
this.pythonChecked = "\u0421\u0432\u043E\u0435\u0433\u043E \u043F\u0438\u0442\u043E\u043D\u0430 \u043C\u043E\u043D\u0442\u0430\u0436\u0430 \u043D\u0430 \u044D\u0442\u043E\u043C \u043A\u043E\u043C\u043F\u044C\u044E\u0442\u0435\u0440\u0435 \u0435\u0449\u0451 \u043D\u0435\u0442 \u2014 \u043E\u043D \u0441\u0442\u0430\u0432\u0438\u0442\u0441\u044F \u0432\u043C\u0435\u0441\u0442\u0435 \u0441 \u0434\u0432\u0438\u0436\u043A\u043E\u043C, \u043E\u0434\u043D\u043E\u0439 \u043F\u0430\u043F\u043A\u043E\u0439, \u0432 \u0441\u0438\u0441\u0442\u0435\u043C\u0443 \u043D\u0438\u0447\u0435\u0433\u043E \u043D\u0435 \u0441\u0442\u0430\u0432\u0438\u0442\u0441\u044F.\n\u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C: \u043F\u043E\u0437\u043E\u0432\u0438
|
|
1896
|
+
this.pythonChecked = "\u0421\u0432\u043E\u0435\u0433\u043E \u043F\u0438\u0442\u043E\u043D\u0430 \u043C\u043E\u043D\u0442\u0430\u0436\u0430 \u043D\u0430 \u044D\u0442\u043E\u043C \u043A\u043E\u043C\u043F\u044C\u044E\u0442\u0435\u0440\u0435 \u0435\u0449\u0451 \u043D\u0435\u0442 \u2014 \u043E\u043D \u0441\u0442\u0430\u0432\u0438\u0442\u0441\u044F \u0432\u043C\u0435\u0441\u0442\u0435 \u0441 \u0434\u0432\u0438\u0436\u043A\u043E\u043C, \u043E\u0434\u043D\u043E\u0439 \u043F\u0430\u043F\u043A\u043E\u0439, \u0432 \u0441\u0438\u0441\u0442\u0435\u043C\u0443 \u043D\u0438\u0447\u0435\u0433\u043E \u043D\u0435 \u0441\u0442\u0430\u0432\u0438\u0442\u0441\u044F.\n\u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C: \u043F\u043E\u0437\u043E\u0432\u0438 install \u0441 what=all \u2014 \u043F\u043E\u0441\u0442\u0430\u0432\u043B\u044E \u0434\u0432\u0438\u0436\u043E\u043A \u0438 \u0432\u0441\u0451, \u0447\u0442\u043E \u0435\u043C\u0443 \u043D\u0443\u0436\u043D\u043E.";
|
|
1865
1897
|
return this.pythonChecked;
|
|
1866
1898
|
}
|
|
1867
1899
|
// ─── запуск ─────────────────────────────────────────────────────────────
|
|
@@ -1912,9 +1944,10 @@ var Engine = class {
|
|
|
1912
1944
|
async runWith(executable, place, args, {
|
|
1913
1945
|
maxBuffer = 8 << 20,
|
|
1914
1946
|
timeout = 3e5,
|
|
1915
|
-
key
|
|
1947
|
+
key,
|
|
1948
|
+
onLine
|
|
1916
1949
|
} = {}) {
|
|
1917
|
-
|
|
1950
|
+
const options = {
|
|
1918
1951
|
// ⚠ ПАПКА ПАКА МОЖЕТ НЕ СУЩЕСТВОВАТЬ, И ЭТО НЕ ГИПОТЕЗА. Так выглядит
|
|
1919
1952
|
// машина, где движок разложен, а пак ещё нет — например, сразу после
|
|
1920
1953
|
// обновления начинки урезанным архивом. `execFile` с несуществующим `cwd`
|
|
@@ -1933,6 +1966,20 @@ var Engine = class {
|
|
|
1933
1966
|
// обновление получает 403 и говорит человеку «каталог ещё не выложен».
|
|
1934
1967
|
// Поэтому не «вернуть ключ в среду», а передать его ровно на этот запуск.
|
|
1935
1968
|
env: montageEnv(this.pythonEnv(), key)
|
|
1969
|
+
};
|
|
1970
|
+
if (onLine === void 0) return execFileP(executable, [place.consolePy, ...args], options);
|
|
1971
|
+
return new Promise((done, fail) => {
|
|
1972
|
+
const child = execFile(executable, [place.consolePy, ...args], options, (err, out, errOut) => {
|
|
1973
|
+
if (err !== null) fail(Object.assign(err, { stdout: out, stderr: errOut }));
|
|
1974
|
+
else done({ stdout: out, stderr: errOut });
|
|
1975
|
+
});
|
|
1976
|
+
let rest = "";
|
|
1977
|
+
child.stdout?.on("data", (chunk) => {
|
|
1978
|
+
rest += String(chunk);
|
|
1979
|
+
const lines = rest.split(/\r?\n|\r/);
|
|
1980
|
+
rest = lines.pop() ?? "";
|
|
1981
|
+
for (const line of lines) if (line.trim() !== "") onLine(line.trim());
|
|
1982
|
+
});
|
|
1936
1983
|
});
|
|
1937
1984
|
}
|
|
1938
1985
|
/**
|
|
@@ -2053,6 +2100,15 @@ var Engine = class {
|
|
|
2053
2100
|
}
|
|
2054
2101
|
}
|
|
2055
2102
|
if (child.pid !== void 0) this.awake.follow(child.pid);
|
|
2103
|
+
const pid = child.pid;
|
|
2104
|
+
if (pid !== void 0) {
|
|
2105
|
+
this.live.set(pid, this.pinned ?? null);
|
|
2106
|
+
const done = () => {
|
|
2107
|
+
this.live.delete(pid);
|
|
2108
|
+
};
|
|
2109
|
+
child.once("close", done);
|
|
2110
|
+
child.once("error", done);
|
|
2111
|
+
}
|
|
2056
2112
|
this.watch(child, opts.place, id, opts.advice, log.file);
|
|
2057
2113
|
return { id };
|
|
2058
2114
|
}
|
|
@@ -2175,7 +2231,7 @@ function lastLine(output) {
|
|
|
2175
2231
|
function lastLines(text2, howMany) {
|
|
2176
2232
|
return text2.trim().split("\n").slice(-8).join("\n");
|
|
2177
2233
|
}
|
|
2178
|
-
var NOT_JSON = "\u0414\u0432\u0438\u0436\u043E\u043A \u043E\u0442\u0432\u0435\u0442\u0438\u043B \u043D\u0435 \u0442\u0435\u043C, \u0447\u0435\u0433\u043E \u0436\u0434\u0430\u043B\u0438. \u041E\u0431\u043D\u043E\u0432\u0438 \
|
|
2234
|
+
var NOT_JSON = "\u0414\u0432\u0438\u0436\u043E\u043A \u043E\u0442\u0432\u0435\u0442\u0438\u043B \u043D\u0435 \u0442\u0435\u043C, \u0447\u0435\u0433\u043E \u0436\u0434\u0430\u043B\u0438. \u041E\u0431\u043D\u043E\u0432\u0438 \u043C\u043E\u043D\u0442\u0430\u0436 \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u043E\u043C install \u0441 what=all \u0438 \u043F\u043E\u0432\u0442\u043E\u0440\u0438.";
|
|
2179
2235
|
|
|
2180
2236
|
// node_modules/zod/v4/classic/external.js
|
|
2181
2237
|
var external_exports = {};
|
|
@@ -13425,6 +13481,27 @@ function withArgs(tool) {
|
|
|
13425
13481
|
}
|
|
13426
13482
|
};
|
|
13427
13483
|
}
|
|
13484
|
+
var scope = new AsyncLocalStorage();
|
|
13485
|
+
function noteInstallFault(stage, trouble) {
|
|
13486
|
+
scope.getStore()?.push({ stage, trouble });
|
|
13487
|
+
}
|
|
13488
|
+
async function collectInstallFaults(work) {
|
|
13489
|
+
const faults = [];
|
|
13490
|
+
const value = await scope.run(faults, work);
|
|
13491
|
+
return { value, faults };
|
|
13492
|
+
}
|
|
13493
|
+
var JOBS_KEPT = 10;
|
|
13494
|
+
var byJob = /* @__PURE__ */ new Map();
|
|
13495
|
+
function collectJobInstallFaults(id, work) {
|
|
13496
|
+
const faults = [];
|
|
13497
|
+
byJob.delete(id);
|
|
13498
|
+
byJob.set(id, faults);
|
|
13499
|
+
while (byJob.size > JOBS_KEPT) byJob.delete(byJob.keys().next().value);
|
|
13500
|
+
return scope.run(faults, work);
|
|
13501
|
+
}
|
|
13502
|
+
function jobInstallFaults(id) {
|
|
13503
|
+
return byJob.get(id) ?? [];
|
|
13504
|
+
}
|
|
13428
13505
|
var KEEP_VERSIONS = 2;
|
|
13429
13506
|
var BROKEN_PREFIX = "broken-";
|
|
13430
13507
|
var WHY_FILE = "why.txt";
|
|
@@ -14096,29 +14173,6 @@ async function askPointer(opts) {
|
|
|
14096
14173
|
clearTimeout(timer);
|
|
14097
14174
|
}
|
|
14098
14175
|
}
|
|
14099
|
-
var scope = new AsyncLocalStorage();
|
|
14100
|
-
function noteInstallFault(stage, trouble) {
|
|
14101
|
-
scope.getStore()?.push({ stage, trouble });
|
|
14102
|
-
}
|
|
14103
|
-
async function collectInstallFaults(work) {
|
|
14104
|
-
const faults = [];
|
|
14105
|
-
const value = await scope.run(faults, work);
|
|
14106
|
-
return { value, faults };
|
|
14107
|
-
}
|
|
14108
|
-
var JOBS_KEPT = 10;
|
|
14109
|
-
var byJob = /* @__PURE__ */ new Map();
|
|
14110
|
-
function collectJobInstallFaults(id, work) {
|
|
14111
|
-
const faults = [];
|
|
14112
|
-
byJob.delete(id);
|
|
14113
|
-
byJob.set(id, faults);
|
|
14114
|
-
while (byJob.size > JOBS_KEPT) byJob.delete(byJob.keys().next().value);
|
|
14115
|
-
return scope.run(faults, work);
|
|
14116
|
-
}
|
|
14117
|
-
function jobInstallFaults(id) {
|
|
14118
|
-
return byJob.get(id) ?? [];
|
|
14119
|
-
}
|
|
14120
|
-
|
|
14121
|
-
// src/update.ts
|
|
14122
14176
|
var MANIFEST_PATH = "/download/engine/manifest.json";
|
|
14123
14177
|
function manifestUrlFor(baseUrl) {
|
|
14124
14178
|
return pointerUrl(baseUrl, MANIFEST_PATH);
|
|
@@ -14266,7 +14320,7 @@ ${delivery.text}` };
|
|
|
14266
14320
|
}
|
|
14267
14321
|
}
|
|
14268
14322
|
hooks.downloaded?.();
|
|
14269
|
-
if (candidateDeps(engine)) return activatePreparedCandidateLocked(engine, manifest, trial);
|
|
14323
|
+
if (candidateDeps(engine)) return activatePreparedCandidateLocked(engine, manifest, trial, "now", hooks.line);
|
|
14270
14324
|
const smoke = await dryRun(engine, dest, manifest.version, trial);
|
|
14271
14325
|
if (smoke !== null) {
|
|
14272
14326
|
const where = keepBroken(dir, manifest.version, smoke);
|
|
@@ -14295,7 +14349,7 @@ ${smoke}`
|
|
|
14295
14349
|
return {
|
|
14296
14350
|
ok: true,
|
|
14297
14351
|
text: `\u041D\u0430\u0447\u0438\u043D\u043A\u0430 \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0430: ${before ?? "\u043D\u0435\u0442"} \u2192 ${manifest.version}.
|
|
14298
|
-
\
|
|
14352
|
+
\u041D\u043E\u0432\u0430\u044F \u0440\u0430\u0431\u043E\u0442\u0430\u0435\u0442 \u0441\u043E \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0435\u0439 \u0437\u0430\u0434\u0430\u0447\u0438, \u0431\u0435\u0437 \u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u043A\u0430; \u0438\u0434\u0443\u0449\u0430\u044F \u0437\u0430\u0434\u0430\u0447\u0430 \u0434\u043E\u0438\u0433\u0440\u044B\u0432\u0430\u0435\u0442 \u043D\u0430 \u043F\u0440\u0435\u0436\u043D\u0435\u0439 \u2014 \u0443 \u0434\u0432\u0438\u0436\u043A\u0430 \u043A\u044D\u0448 \u043F\u043E \u043E\u0442\u043F\u0435\u0447\u0430\u0442\u043A\u0430\u043C, \u0438 \u0441\u043C\u0435\u0448\u0438\u0432\u0430\u0442\u044C \u0432\u0435\u0440\u0441\u0438\u0438 \u0432\u043D\u0443\u0442\u0440\u0438 \u0437\u0430\u0434\u0430\u0447\u0438 \u043D\u0435\u043B\u044C\u0437\u044F.
|
|
14299
14353
|
` + (wiped.length > 0 ? `\u0423\u0431\u0440\u0430\u043B \u0441\u0442\u0430\u0440\u044B\u0435 \u0432\u0435\u0440\u0441\u0438\u0438: ${wiped.join(", ")}.
|
|
14300
14354
|
` : "") + tidyFailed + `\u041E\u0442\u043A\u0430\u0442\u0438\u0442\u044C\u0441\u044F \u043D\u0430\u0437\u0430\u0434: setup \u0441 rollback=engine.`
|
|
14301
14355
|
};
|
|
@@ -14441,6 +14495,12 @@ function pollutedPayload(dest, candidate) {
|
|
|
14441
14495
|
function samePreparedCandidate(actual, expected) {
|
|
14442
14496
|
return actual !== null && actual.version === expected.version && actual.sha256 === expected.sha256 && actual.state === "prepared" && actual.baseCurrent === expected.baseCurrent && actual.environment === expected.environment && actual.mineDigest === expected.mineDigest && actual.payload !== void 0 && expected.payload !== void 0 && samePayloadProof(actual.payload, expected.payload);
|
|
14443
14497
|
}
|
|
14498
|
+
var STEP_ANSWER = /^(Шаг «|Дальше:|Спроси у человека:|Нужно скачать )/;
|
|
14499
|
+
function progressOnly(say) {
|
|
14500
|
+
return (line) => {
|
|
14501
|
+
if (!STEP_ANSWER.test(line)) say(line);
|
|
14502
|
+
};
|
|
14503
|
+
}
|
|
14444
14504
|
async function runCandidateWith(engine, dir, version2, executable, place, args, opts = {}, requireVenv = true) {
|
|
14445
14505
|
const venvTrouble = candidateVenvTrouble(dir, version2, place, requireVenv);
|
|
14446
14506
|
if (venvTrouble !== null) throw new Error(venvTrouble);
|
|
@@ -14488,7 +14548,7 @@ async function compatibilityProof(engine, dir, version2, python, place) {
|
|
|
14488
14548
|
return { ok: false, text: `\u0421\u043E\u0432\u043C\u0435\u0441\u0442\u0438\u043C\u043E\u0441\u0442\u044C \u043A\u0430\u043D\u0434\u0438\u0434\u0430\u0442\u0430 \u043D\u0435 \u043F\u0440\u043E\u0432\u0435\u0440\u0435\u043D\u0430 (unknown): ${describeFailure(trouble)}` };
|
|
14489
14549
|
}
|
|
14490
14550
|
}
|
|
14491
|
-
async function activatePreparedCandidateLocked(engine, manifest, trial, extras = "now") {
|
|
14551
|
+
async function activatePreparedCandidateLocked(engine, manifest, trial, extras = "now", say) {
|
|
14492
14552
|
const dir = engine.versionsDir();
|
|
14493
14553
|
const candidate = readCandidate(dir);
|
|
14494
14554
|
if (candidate?.version !== manifest.version || candidate.sha256 !== manifest.sha256) {
|
|
@@ -14536,7 +14596,7 @@ async function activatePreparedCandidateLocked(engine, manifest, trial, extras =
|
|
|
14536
14596
|
"--consent",
|
|
14537
14597
|
...extras === "later" ? requiredOnly(dir, candidate.version) : []
|
|
14538
14598
|
],
|
|
14539
|
-
{ timeout: 60 * 6e4 },
|
|
14599
|
+
{ timeout: 60 * 6e4, ...say === void 0 ? {} : { onLine: progressOnly(say) } },
|
|
14540
14600
|
false
|
|
14541
14601
|
);
|
|
14542
14602
|
const installedVenvTrouble = candidateVenvTrouble(dir, candidate.version, place, true);
|
|
@@ -14727,7 +14787,7 @@ async function installVoiceCleaner(engine, dir, version2, python, place) {
|
|
|
14727
14787
|
);
|
|
14728
14788
|
return "";
|
|
14729
14789
|
} catch (trouble) {
|
|
14730
|
-
return `\u0428\u0443\u043C\u043E\u0434\u0430\u0432 \u0433\u043E\u043B\u043E\u0441\u0430 \u043D\u0435 \u0432\u0441\u0442\u0430\u043B: ${voiceTrouble(trouble)}. \u0414\u0432\u0438\u0436\u043E\u043A \u0432\u043A\u043B\u044E\u0447\u0451\u043D \u0438 \u043C\u043E\u043D\u0442\u0438\u0440\u0443\u0435\u0442; \u043F\u043E\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u0448\u0443\u043C\u043E\u0434\u0430\u0432 \u043E\u0442\u0434\u0435\u043B\u044C\u043D\u043E \u2014
|
|
14790
|
+
return `\u0428\u0443\u043C\u043E\u0434\u0430\u0432 \u0433\u043E\u043B\u043E\u0441\u0430 \u043D\u0435 \u0432\u0441\u0442\u0430\u043B: ${voiceTrouble(trouble)}. \u0414\u0432\u0438\u0436\u043E\u043A \u0432\u043A\u043B\u044E\u0447\u0451\u043D \u0438 \u043C\u043E\u043D\u0442\u0438\u0440\u0443\u0435\u0442; \u043F\u043E\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u0448\u0443\u043C\u043E\u0434\u0430\u0432 \u043E\u0442\u0434\u0435\u043B\u044C\u043D\u043E \u2014 install \u0441 what=voice.`;
|
|
14731
14791
|
}
|
|
14732
14792
|
}
|
|
14733
14793
|
function voiceTrouble(trouble) {
|
|
@@ -14782,7 +14842,7 @@ function rollback(engine) {
|
|
|
14782
14842
|
return {
|
|
14783
14843
|
ok: true,
|
|
14784
14844
|
text: `\u041E\u0442\u043A\u0430\u0442\u0438\u043B \u043D\u0430\u0447\u0438\u043D\u043A\u0443: ${before ?? "\u043D\u0435\u0442"} \u2192 ${back}.
|
|
14785
|
-
\
|
|
14845
|
+
\u0420\u0430\u0431\u043E\u0442\u0430\u0435\u0442 \u0441\u043E \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0435\u0439 \u0437\u0430\u0434\u0430\u0447\u0438, \u0431\u0435\u0437 \u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u043A\u0430.`
|
|
14786
14846
|
};
|
|
14787
14847
|
});
|
|
14788
14848
|
} catch (trouble) {
|
|
@@ -15235,7 +15295,7 @@ ${smoke}`
|
|
|
15235
15295
|
return {
|
|
15236
15296
|
ok: true,
|
|
15237
15297
|
text: `\u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u0435 \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u043E: ${before} \u2192 ${manifest.version}.
|
|
15238
|
-
\
|
|
15298
|
+
\u0412\u0441\u0442\u0430\u043D\u0435\u0442 \u0441\u0430\u043C\u043E, \u043A\u0430\u043A \u0442\u043E\u043B\u044C\u043A\u043E \u043D\u0435 \u0438\u0434\u0451\u0442 \u043D\u0438 \u043E\u0434\u043D\u043E\u0439 \u0437\u0430\u0434\u0430\u0447\u0438, \u2014 \u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u043A\u0430\u0442\u044C \u041A\u043B\u043E\u0434\u0430 \u0438\u043B\u0438 Codex \u043D\u0435 \u043D\u0443\u0436\u043D\u043E.
|
|
15239
15299
|
` + (wiped.length > 0 ? `\u0423\u0431\u0440\u0430\u043B \u0441\u0442\u0430\u0440\u044B\u0435 \u0432\u0435\u0440\u0441\u0438\u0438: ${wiped.join(", ")}.
|
|
15240
15300
|
` : "") + tidyFailed + "\u041E\u0442\u043A\u0430\u0442\u0438\u0442\u044C\u0441\u044F \u043D\u0430\u0437\u0430\u0434: setup \u0441 rollback=shell."
|
|
15241
15301
|
};
|
|
@@ -15296,7 +15356,7 @@ function rollbackShell(home) {
|
|
|
15296
15356
|
return {
|
|
15297
15357
|
ok: true,
|
|
15298
15358
|
text: `\u041E\u0442\u043A\u0430\u0442\u0438\u043B \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u0435: ${before} \u2192 ${back}.
|
|
15299
|
-
\
|
|
15359
|
+
\u0412\u0441\u0442\u0430\u043D\u0435\u0442 \u0441\u0430\u043C\u043E, \u043A\u0430\u043A \u0442\u043E\u043B\u044C\u043A\u043E \u043D\u0435 \u0438\u0434\u0451\u0442 \u043D\u0438 \u043E\u0434\u043D\u043E\u0439 \u0437\u0430\u0434\u0430\u0447\u0438.`
|
|
15300
15360
|
};
|
|
15301
15361
|
});
|
|
15302
15362
|
} catch (trouble) {
|
|
@@ -15419,7 +15479,7 @@ async function installPayload(engine, opts, hooks = {}) {
|
|
|
15419
15479
|
text: `\u0414\u0432\u0438\u0436\u043A\u0430 \u043C\u043E\u043D\u0442\u0430\u0436\u0430 \u043D\u0430 \u044D\u0442\u043E\u0439 \u043C\u0430\u0448\u0438\u043D\u0435 \u043D\u0435\u0442 \u2014 \u043D\u0430\u0447\u0438\u043D\u043A\u0443 \u043D\u0430\u0434\u043E \u0441\u043A\u0430\u0447\u0430\u0442\u044C (${mb} \u041C\u0411, \u0432\u0435\u0440\u0441\u0438\u044F ${manifest.version}).
|
|
15420
15480
|
\u041B\u044F\u0436\u0435\u0442 \u043E\u0434\u043D\u043E\u0439 \u043F\u0430\u043F\u043A\u043E\u0439 \u0432 ${engine.versionsDir()}; \u0432 \u0441\u0438\u0441\u0442\u0435\u043C\u0443 \u043D\u0438\u0447\u0435\u0433\u043E \u043D\u0435 \u0441\u0442\u0430\u0432\u0438\u0442\u0441\u044F.
|
|
15421
15481
|
${VOICE_CLEANER_NOTE}
|
|
15422
|
-
\u0421\u043F\u0440\u043E\u0441\u0438 \u0443 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043D\u0438\u0435 \u0438 \u043F\u043E\u0437\u043E\u0432\u0438
|
|
15482
|
+
\u0421\u043F\u0440\u043E\u0441\u0438 \u0443 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043D\u0438\u0435 \u0438 \u043F\u043E\u0437\u043E\u0432\u0438 install \u0441 what=all.`
|
|
15423
15483
|
};
|
|
15424
15484
|
}
|
|
15425
15485
|
const dest = join(versionsDir, manifest.version);
|
|
@@ -15596,190 +15656,58 @@ function installLadder(step) {
|
|
|
15596
15656
|
"\u0418\u0434\u0451\u0442 \u043C\u0438\u043D\u0443\u0442\u0430\u043C\u0438. \u041E\u0431\u043E\u0440\u0432\u0451\u0442\u0441\u044F \u2014 \u043F\u043E\u0432\u0442\u043E\u0440\u0438 \u0442\u043E\u0442 \u0436\u0435 \u0448\u0430\u0433: \u0443\u0436\u0435 \u0441\u043A\u0430\u0447\u0430\u043D\u043D\u043E\u0435 \u043D\u0435 \u043F\u0440\u043E\u043F\u0430\u0434\u0451\u0442."
|
|
15597
15657
|
];
|
|
15598
15658
|
}
|
|
15599
|
-
var CALLS_FILE = "calls.jsonl";
|
|
15600
|
-
var CALLS_PREVIOUS = "calls.1.jsonl";
|
|
15601
|
-
var CALLS_CAP_BYTES = 1e6;
|
|
15602
|
-
function withCallLog(home, now = () => Date.now()) {
|
|
15603
|
-
return (tool) => {
|
|
15604
|
-
const original = tool.execute.bind(tool);
|
|
15605
|
-
return {
|
|
15606
|
-
...tool,
|
|
15607
|
-
async execute(input, ...rest) {
|
|
15608
|
-
const started = now();
|
|
15609
|
-
const result = await original(input, ...rest);
|
|
15610
|
-
write(home, {
|
|
15611
|
-
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
15612
|
-
tool: tool.name,
|
|
15613
|
-
ok: result.type === "success",
|
|
15614
|
-
ms: now() - started
|
|
15615
|
-
});
|
|
15616
|
-
return result;
|
|
15617
|
-
}
|
|
15618
|
-
};
|
|
15619
|
-
};
|
|
15620
|
-
}
|
|
15621
|
-
function write(home, line) {
|
|
15622
|
-
try {
|
|
15623
|
-
mkdirSync(home, { recursive: true });
|
|
15624
|
-
const file2 = join(home, CALLS_FILE);
|
|
15625
|
-
rotate(file2, join(home, CALLS_PREVIOUS));
|
|
15626
|
-
appendFileSync(file2, `${JSON.stringify(line)}
|
|
15627
|
-
`, { encoding: "utf8", mode: 384 });
|
|
15628
|
-
} catch {
|
|
15629
|
-
}
|
|
15630
|
-
}
|
|
15631
|
-
function rotate(file2, previous) {
|
|
15632
|
-
try {
|
|
15633
|
-
if (statSync(file2).size >= CALLS_CAP_BYTES) renameSync(file2, previous);
|
|
15634
|
-
} catch {
|
|
15635
|
-
}
|
|
15636
|
-
}
|
|
15637
15659
|
|
|
15638
|
-
// src/
|
|
15639
|
-
|
|
15640
|
-
|
|
15641
|
-
var CRASH_LIMITS = {
|
|
15642
|
-
bodyBytes: 65536,
|
|
15643
|
-
errorType: 120,
|
|
15644
|
-
message: 500,
|
|
15645
|
-
trace: 8e3,
|
|
15646
|
-
stage: 120,
|
|
15647
|
-
osPlatform: 32,
|
|
15648
|
-
osRelease: 64,
|
|
15649
|
-
osArch: 16,
|
|
15650
|
-
hostName: 64,
|
|
15651
|
-
hostVersion: 32,
|
|
15652
|
-
shellVersion: 32,
|
|
15653
|
-
engineVersion: 64,
|
|
15654
|
-
pythonVersion: 16,
|
|
15655
|
-
ffmpegVersion: 64,
|
|
15656
|
-
recentCalls: 10,
|
|
15657
|
-
repeats: 1e5
|
|
15658
|
-
};
|
|
15659
|
-
var CRASH_TOOL_NAME = /^[a-z_]{1,64}$/;
|
|
15660
|
-
var CRASH_FINGERPRINT = /^[0-9a-f]{16}$/;
|
|
15661
|
-
var text = (max) => external_exports.string().max(max);
|
|
15662
|
-
var CrashReportRequest = external_exports.object({
|
|
15663
|
-
contract: external_exports.literal(CRASH_CONTRACT),
|
|
15664
|
-
occurred_at: external_exports.string().datetime({ offset: true }),
|
|
15665
|
-
where: external_exports.enum(["tool", "job", "process"]),
|
|
15666
|
-
tool: external_exports.string().regex(CRASH_TOOL_NAME).nullable(),
|
|
15667
|
-
stage: text(CRASH_LIMITS.stage).nullable(),
|
|
15668
|
-
error_type: external_exports.string().min(1).max(CRASH_LIMITS.errorType),
|
|
15669
|
-
message: text(CRASH_LIMITS.message),
|
|
15670
|
-
trace: text(CRASH_LIMITS.trace),
|
|
15671
|
-
fingerprint: external_exports.string().regex(CRASH_FINGERPRINT),
|
|
15672
|
-
repeats: external_exports.number().int().min(0).max(CRASH_LIMITS.repeats),
|
|
15673
|
-
os: external_exports.object({
|
|
15674
|
-
platform: text(CRASH_LIMITS.osPlatform),
|
|
15675
|
-
release: text(CRASH_LIMITS.osRelease),
|
|
15676
|
-
arch: text(CRASH_LIMITS.osArch)
|
|
15677
|
-
}).strict(),
|
|
15678
|
-
host: external_exports.object({
|
|
15679
|
-
name: text(CRASH_LIMITS.hostName),
|
|
15680
|
-
version: text(CRASH_LIMITS.hostVersion)
|
|
15681
|
-
}).strict().nullable(),
|
|
15682
|
-
versions: external_exports.object({
|
|
15683
|
-
shell: text(CRASH_LIMITS.shellVersion),
|
|
15684
|
-
engine: text(CRASH_LIMITS.engineVersion).nullable(),
|
|
15685
|
-
python: text(CRASH_LIMITS.pythonVersion).nullable(),
|
|
15686
|
-
ffmpeg: text(CRASH_LIMITS.ffmpegVersion).nullable()
|
|
15687
|
-
}).strict(),
|
|
15688
|
-
recent_calls: external_exports.array(external_exports.string().regex(CRASH_TOOL_NAME)).max(CRASH_LIMITS.recentCalls)
|
|
15689
|
-
}).strict();
|
|
15690
|
-
var SECRET_MIN = 4;
|
|
15691
|
-
var HUMAN_FILE = /[^\s"'«»“”/\\<>()]{0,255}\.(?:mp4|mov|m4v|mkv|avi|webm|mts|wav|mp3|m4a|aac|flac|ogg|jpg|jpeg|png|heic|gif|srt|vtt)\b/gi;
|
|
15692
|
-
var PATH = /(?:<naparnik>|<shell>|~|[A-Za-z]:)?(?:[\\/][^\s"'«»“”<>|,;()[\]{}\\/]+)+[\\/]?/g;
|
|
15693
|
-
var QUOTED = /(["'])([^"'\n]*)\1|«([^»\n]*)»|“([^”\n]*)”/g;
|
|
15694
|
-
var KEY = /npk_[A-Za-z0-9_-]{6,}/g;
|
|
15695
|
-
function scrub(text2, context) {
|
|
15696
|
-
let out = text2.replace(KEY, "<key>");
|
|
15697
|
-
for (const secret of secretForms(context.secrets)) {
|
|
15698
|
-
out = replaceAll(out, secret, "<video>");
|
|
15699
|
-
}
|
|
15700
|
-
out = replaceAll(out, context.shellDir, "<shell>");
|
|
15701
|
-
out = replaceAll(out, context.naparnikHome, "<naparnik>");
|
|
15702
|
-
out = replaceAll(out, context.home, "~");
|
|
15703
|
-
out = out.replace(/(?:\/Users|\/home|[A-Za-z]:\\Users|[A-Za-z]:\/Users)[\\/][^\s"'«»“”\\/]+/g, "~");
|
|
15704
|
-
out = out.replace(QUOTED, (whole, _q, plain, fir, curly) => {
|
|
15705
|
-
const inside2 = plain ?? fir ?? curly ?? "";
|
|
15706
|
-
if (!looksHuman(inside2)) return whole;
|
|
15707
|
-
const [open, close] = plain !== void 0 ? [_q, _q] : fir !== void 0 ? ["\xAB", "\xBB"] : ["\u201C", "\u201D"];
|
|
15708
|
-
return `${open}${looksLikePath(inside2) ? pathOrMark(inside2) : "<text>"}${close}`;
|
|
15709
|
-
});
|
|
15710
|
-
out = out.replace(PATH, (found) => pathOrMark(found));
|
|
15711
|
-
out = out.replace(HUMAN_FILE, "<file>");
|
|
15712
|
-
out = swallowSpacedTails(out);
|
|
15713
|
-
if (context.user.length >= 3) out = replaceAll(out, context.user, "<user>");
|
|
15714
|
-
return out;
|
|
15715
|
-
}
|
|
15716
|
-
function swallowSpacedTails(text2) {
|
|
15717
|
-
return text2.replace(/<(?:path|file)>[^\n:<>"'«»“”]{0,512}<(?:path|file)>/g, "<path>").replace(/(<(?:path|file)>)([^\n:<>"'«»“”]{0,512})/g, (whole, mark, tail2) => /[^\x00-\x7F]/.test(tail2) ? mark : whole);
|
|
15718
|
-
}
|
|
15719
|
-
function secretForms(secrets) {
|
|
15720
|
-
const forms = /* @__PURE__ */ new Set();
|
|
15721
|
-
for (const raw of secrets) {
|
|
15722
|
-
const value = raw.trim();
|
|
15723
|
-
if (value.length < SECRET_MIN) continue;
|
|
15724
|
-
forms.add(value);
|
|
15725
|
-
if (!looksLikePath(value)) continue;
|
|
15726
|
-
if (isAbsolute(value)) forms.add(resolve(value));
|
|
15727
|
-
const name = basename(value);
|
|
15728
|
-
const stem = name.slice(0, name.length - extname(name).length);
|
|
15729
|
-
for (const one of [name, stem, `${stem}.montage`]) {
|
|
15730
|
-
if (one.length >= SECRET_MIN) forms.add(one);
|
|
15731
|
-
}
|
|
15732
|
-
}
|
|
15733
|
-
return [...forms].sort((a, b) => b.length - a.length);
|
|
15734
|
-
}
|
|
15735
|
-
function pathOrMark(found) {
|
|
15736
|
-
const flat = found.replace(/\\/g, "/");
|
|
15737
|
-
const ours = /^(?:<naparnik>|~\/\.naparnik)\/(?:engine|shell|bin)(?:\/|$)/.test(flat) || flat.startsWith("<shell>") || /\/(?:site-packages|dist-packages|node_modules)\//.test(flat) || /\/lib\/python\d/i.test(flat) || /\/Python\d+\/Lib\//i.test(flat);
|
|
15738
|
-
return ours ? found : "<path>";
|
|
15739
|
-
}
|
|
15740
|
-
var HUMAN_FILE_ONE = new RegExp(HUMAN_FILE.source, "i");
|
|
15741
|
-
function looksLikePath(value) {
|
|
15742
|
-
return /[\\/]/.test(value) || HUMAN_FILE_ONE.test(value);
|
|
15743
|
-
}
|
|
15744
|
-
function looksHuman(inside2) {
|
|
15745
|
-
return /[^\x00-\x7F]/.test(inside2) || /\s/.test(inside2) || looksLikePath(inside2);
|
|
15660
|
+
// src/words.ts
|
|
15661
|
+
function human(text2) {
|
|
15662
|
+
return text2;
|
|
15746
15663
|
}
|
|
15747
|
-
function
|
|
15748
|
-
|
|
15749
|
-
return text2.split(what).join(by);
|
|
15664
|
+
function forModel(text2) {
|
|
15665
|
+
return text2;
|
|
15750
15666
|
}
|
|
15667
|
+
var NO_HUMAN_TEXT = human("");
|
|
15751
15668
|
|
|
15752
15669
|
// src/job-report.ts
|
|
15753
15670
|
var JOB_CONTRACT = "naparnik-job/1";
|
|
15754
|
-
function
|
|
15671
|
+
function blankJob() {
|
|
15672
|
+
const none = NO_HUMAN_TEXT;
|
|
15755
15673
|
return {
|
|
15756
15674
|
contract: JOB_CONTRACT,
|
|
15757
15675
|
id: "",
|
|
15758
|
-
what:
|
|
15676
|
+
what: none,
|
|
15759
15677
|
status: "running",
|
|
15760
15678
|
sec: 0,
|
|
15761
15679
|
at: 0,
|
|
15762
15680
|
total: 0,
|
|
15763
|
-
now:
|
|
15764
|
-
left:
|
|
15765
|
-
behind:
|
|
15766
|
-
ahead:
|
|
15767
|
-
message:
|
|
15681
|
+
now: none,
|
|
15682
|
+
left: none,
|
|
15683
|
+
behind: none,
|
|
15684
|
+
ahead: none,
|
|
15685
|
+
message: none,
|
|
15768
15686
|
got: 0,
|
|
15769
15687
|
of: 0,
|
|
15770
15688
|
percent: 0,
|
|
15771
|
-
eta:
|
|
15689
|
+
eta: none,
|
|
15772
15690
|
file: "",
|
|
15773
|
-
outcome: "",
|
|
15774
|
-
say:
|
|
15775
|
-
trouble:
|
|
15776
|
-
advice:
|
|
15691
|
+
outcome: forModel(""),
|
|
15692
|
+
say: none,
|
|
15693
|
+
trouble: none,
|
|
15694
|
+
advice: none,
|
|
15777
15695
|
complaints: [],
|
|
15778
15696
|
plan: []
|
|
15779
15697
|
};
|
|
15780
15698
|
}
|
|
15699
|
+
function downloadOf(message) {
|
|
15700
|
+
const download = DOWNLOAD.exec(message);
|
|
15701
|
+
if (download === null) return null;
|
|
15702
|
+
return {
|
|
15703
|
+
got: Number(download[1]),
|
|
15704
|
+
of: Number(download[2] ?? 0),
|
|
15705
|
+
percent: Math.min(100, Number(download[3] ?? 0)),
|
|
15706
|
+
eta: human(download[4] ?? "")
|
|
15707
|
+
};
|
|
15708
|
+
}
|
|
15781
15709
|
function startedJob(o) {
|
|
15782
|
-
return { ...
|
|
15710
|
+
return { ...blankJob(), id: o.id, what: o.what, ahead: o.ahead, message: o.message };
|
|
15783
15711
|
}
|
|
15784
15712
|
var INSTALL_TITLES = {
|
|
15785
15713
|
all: "\u0423\u0441\u0442\u0430\u043D\u0430\u0432\u043B\u0438\u0432\u0430\u044E \u0431\u0438\u0431\u043B\u0438\u043E\u0442\u0435\u043A\u0438 \u0434\u043B\u044F \u043C\u043E\u043D\u0442\u0430\u0436\u0430",
|
|
@@ -15793,7 +15721,7 @@ var INSTALL_TITLES = {
|
|
|
15793
15721
|
voice: "\u0423\u0441\u0442\u0430\u043D\u0430\u0432\u043B\u0438\u0432\u0430\u044E \u0447\u0438\u0441\u0442\u043A\u0443 \u0433\u043E\u043B\u043E\u0441\u0430"
|
|
15794
15722
|
};
|
|
15795
15723
|
function installTitle(step) {
|
|
15796
|
-
return INSTALL_TITLES[step] ?? "\u0423\u0441\u0442\u0430\u043D\u0430\u0432\u043B\u0438\u0432\u0430\u044E \u0431\u0438\u0431\u043B\u0438\u043E\u0442\u0435\u043A\u0438 \u0434\u043B\u044F \u043C\u043E\u043D\u0442\u0430\u0436\u0430";
|
|
15724
|
+
return human(INSTALL_TITLES[step] ?? "\u0423\u0441\u0442\u0430\u043D\u0430\u0432\u043B\u0438\u0432\u0430\u044E \u0431\u0438\u0431\u043B\u0438\u043E\u0442\u0435\u043A\u0438 \u0434\u043B\u044F \u043C\u043E\u043D\u0442\u0430\u0436\u0430");
|
|
15797
15725
|
}
|
|
15798
15726
|
var INSTALL_HEAD = /^установка: (\S+)$/;
|
|
15799
15727
|
var HEAD = /^Задание (\S+): ?(.*)$/;
|
|
@@ -15819,9 +15747,9 @@ function readJob(text2) {
|
|
|
15819
15747
|
const lines = text2.split("\n").map((row) => row.trimEnd());
|
|
15820
15748
|
const head2 = HEAD.exec(lines[0]?.trim() ?? "");
|
|
15821
15749
|
if (head2 === null) return null;
|
|
15822
|
-
const job =
|
|
15750
|
+
const job = blankJob();
|
|
15823
15751
|
job.id = head2[1] ?? "";
|
|
15824
|
-
job.what = (head2[2] ?? "").trim();
|
|
15752
|
+
job.what = human((head2[2] ?? "").trim());
|
|
15825
15753
|
const install2 = INSTALL_HEAD.exec(job.what);
|
|
15826
15754
|
if (install2 !== null) job.what = installTitle(install2[1] ?? "");
|
|
15827
15755
|
let tail2 = null;
|
|
@@ -15831,7 +15759,7 @@ function readJob(text2) {
|
|
|
15831
15759
|
if (STYLE.test(line)) continue;
|
|
15832
15760
|
const complaint = COMPLAINT.exec(line);
|
|
15833
15761
|
if (complaint !== null) {
|
|
15834
|
-
job.complaints.push(complaint[1] ?? "");
|
|
15762
|
+
job.complaints.push(human(complaint[1] ?? ""));
|
|
15835
15763
|
tail2 = null;
|
|
15836
15764
|
continue;
|
|
15837
15765
|
}
|
|
@@ -15841,13 +15769,13 @@ function readJob(text2) {
|
|
|
15841
15769
|
}
|
|
15842
15770
|
const planRow = PLAN_ROW.exec(line);
|
|
15843
15771
|
if (planRow !== null) {
|
|
15844
|
-
job.plan.push(planRow[1] ?? "");
|
|
15772
|
+
job.plan.push(forModel(planRow[1] ?? ""));
|
|
15845
15773
|
tail2 = null;
|
|
15846
15774
|
continue;
|
|
15847
15775
|
}
|
|
15848
15776
|
const behind = BEHIND.exec(line);
|
|
15849
15777
|
if (behind !== null) {
|
|
15850
|
-
job.behind = behind[1] ?? "";
|
|
15778
|
+
job.behind = human(behind[1] ?? "");
|
|
15851
15779
|
continue;
|
|
15852
15780
|
}
|
|
15853
15781
|
const now = NOW.exec(line);
|
|
@@ -15857,16 +15785,16 @@ function readJob(text2) {
|
|
|
15857
15785
|
const title = now[3] ?? "";
|
|
15858
15786
|
const left = LEFT_TAIL.exec(title);
|
|
15859
15787
|
if (left !== null) {
|
|
15860
|
-
job.now = title.slice(0, left.index).trim();
|
|
15861
|
-
job.left = (left[1] ?? "").trim();
|
|
15788
|
+
job.now = human(title.slice(0, left.index).trim());
|
|
15789
|
+
job.left = human((left[1] ?? "").trim());
|
|
15862
15790
|
} else {
|
|
15863
|
-
job.now = title.trim();
|
|
15791
|
+
job.now = human(title.trim());
|
|
15864
15792
|
}
|
|
15865
15793
|
continue;
|
|
15866
15794
|
}
|
|
15867
15795
|
const ahead = AHEAD.exec(line);
|
|
15868
15796
|
if (ahead !== null) {
|
|
15869
|
-
job.ahead = ahead[1] ?? "";
|
|
15797
|
+
job.ahead = human(ahead[1] ?? "");
|
|
15870
15798
|
continue;
|
|
15871
15799
|
}
|
|
15872
15800
|
const done = DONE.exec(line);
|
|
@@ -15886,31 +15814,31 @@ function readJob(text2) {
|
|
|
15886
15814
|
if (failed !== null) {
|
|
15887
15815
|
job.status = "error";
|
|
15888
15816
|
job.sec = seconds(failed[1]);
|
|
15889
|
-
job.trouble = withoutPaths(failed[2] ?? "");
|
|
15817
|
+
job.trouble = human(withoutPaths(failed[2] ?? ""));
|
|
15890
15818
|
tail2 = null;
|
|
15891
15819
|
continue;
|
|
15892
15820
|
}
|
|
15893
15821
|
if (ABORTED.test(line)) {
|
|
15894
15822
|
job.status = "aborted";
|
|
15895
|
-
job.trouble = line;
|
|
15823
|
+
job.trouble = human(line);
|
|
15896
15824
|
job.sec = seconds(ABORTED_SEC.exec(line)?.[1]);
|
|
15897
15825
|
tail2 = null;
|
|
15898
15826
|
continue;
|
|
15899
15827
|
}
|
|
15900
15828
|
const advice = ADVICE.exec(line);
|
|
15901
15829
|
if (advice !== null) {
|
|
15902
|
-
job.advice = advice[1] ?? "";
|
|
15830
|
+
job.advice = human(advice[1] ?? "");
|
|
15903
15831
|
tail2 = null;
|
|
15904
15832
|
continue;
|
|
15905
15833
|
}
|
|
15906
15834
|
const say = SAY.exec(line);
|
|
15907
15835
|
if (say !== null) {
|
|
15908
|
-
job.say = say[1] ?? "";
|
|
15836
|
+
job.say = human(say[1] ?? "");
|
|
15909
15837
|
continue;
|
|
15910
15838
|
}
|
|
15911
15839
|
if (WAITING.test(line)) {
|
|
15912
15840
|
job.status = "waiting";
|
|
15913
|
-
job.message = line;
|
|
15841
|
+
job.message = human(line);
|
|
15914
15842
|
continue;
|
|
15915
15843
|
}
|
|
15916
15844
|
const running2 = RUNNING.exec(line);
|
|
@@ -15921,18 +15849,13 @@ function readJob(text2) {
|
|
|
15921
15849
|
}
|
|
15922
15850
|
if (tail2 !== null) {
|
|
15923
15851
|
tail2.push(line);
|
|
15924
|
-
job.outcome = tail2.join("\n");
|
|
15852
|
+
job.outcome = forModel(tail2.join("\n"));
|
|
15925
15853
|
continue;
|
|
15926
15854
|
}
|
|
15927
|
-
if (job.status === "running" || job.status === "waiting") job.message = line;
|
|
15928
|
-
}
|
|
15929
|
-
const download = job.status === "running" ? DOWNLOAD.exec(job.message) : null;
|
|
15930
|
-
if (download !== null) {
|
|
15931
|
-
job.got = Number(download[1]);
|
|
15932
|
-
job.of = Number(download[2] ?? 0);
|
|
15933
|
-
job.percent = Math.min(100, Number(download[3] ?? 0));
|
|
15934
|
-
job.eta = download[4] ?? "";
|
|
15855
|
+
if (job.status === "running" || job.status === "waiting") job.message = human(line);
|
|
15935
15856
|
}
|
|
15857
|
+
const download = job.status === "running" ? downloadOf(job.message) : null;
|
|
15858
|
+
if (download !== null) Object.assign(job, download);
|
|
15936
15859
|
return job;
|
|
15937
15860
|
}
|
|
15938
15861
|
function withoutPaths(text2) {
|
|
@@ -15944,781 +15867,643 @@ function seconds(text2) {
|
|
|
15944
15867
|
return Number.isFinite(value) ? value : 0;
|
|
15945
15868
|
}
|
|
15946
15869
|
|
|
15947
|
-
// src/
|
|
15948
|
-
|
|
15949
|
-
|
|
15950
|
-
|
|
15951
|
-
|
|
15952
|
-
|
|
15953
|
-
|
|
15954
|
-
|
|
15955
|
-
|
|
15956
|
-
|
|
15957
|
-
|
|
15958
|
-
|
|
15959
|
-
|
|
15960
|
-
|
|
15961
|
-
|
|
15962
|
-
|
|
15963
|
-
|
|
15964
|
-
|
|
15965
|
-
|
|
15966
|
-
|
|
15967
|
-
|
|
15968
|
-
|
|
15969
|
-
|
|
15970
|
-
|
|
15971
|
-
|
|
15972
|
-
|
|
15973
|
-
|
|
15974
|
-
|
|
15975
|
-
|
|
15976
|
-
|
|
15977
|
-
|
|
15978
|
-
|
|
15979
|
-
|
|
15980
|
-
|
|
15981
|
-
|
|
15982
|
-
|
|
15983
|
-
|
|
15984
|
-
|
|
15985
|
-
|
|
15986
|
-
|
|
15987
|
-
|
|
15988
|
-
|
|
15989
|
-
|
|
15990
|
-
|
|
15870
|
+
// src/tool-kit.ts
|
|
15871
|
+
function manifestUrl(engine, baseUrl) {
|
|
15872
|
+
return engine.variable("NAPARNIK_UPDATE_MANIFEST") ?? manifestUrlFor(baseUrl);
|
|
15873
|
+
}
|
|
15874
|
+
function aboutDefaults(map2) {
|
|
15875
|
+
if (map2 === void 0 || Object.keys(map2).length === 0) return "\u0441\u043C\u043E\u0442\u0440\u0438 setup";
|
|
15876
|
+
return Object.entries(map2).map(([engine, model]) => `${model} (${engine})`).join(", ");
|
|
15877
|
+
}
|
|
15878
|
+
function aboutModels(passport) {
|
|
15879
|
+
if (passport === null) return "\u0421\u043F\u0438\u0441\u043E\u043A \u043C\u043E\u0434\u0435\u043B\u0435\u0439 \u0441\u043C\u043E\u0442\u0440\u0438 \u0432 setup";
|
|
15880
|
+
return `\u041A\u0430\u043A\u0438\u0435 \u0435\u0441\u0442\u044C: ${passport["models"].join(", ")}; \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E \u2014 \u0441\u0432\u043E\u0451 \u043D\u0430 \u0434\u0432\u0438\u0436\u043E\u043A: ${aboutDefaults(passport["default_model"])}. \u041D\u0435 \u043D\u0430\u0437\u044B\u0432\u0430\u0439 \u043C\u043E\u0434\u0435\u043B\u044C \u0431\u0435\u0437 \u043D\u0443\u0436\u0434\u044B: \u043F\u0430\u043A \u0441\u0430\u043C \u0432\u043E\u0437\u044C\u043C\u0451\u0442 \u0442\u0443, \u0447\u0442\u043E \u0431\u044B\u0441\u0442\u0440\u0435\u0435 \u043D\u0430 \u044D\u0442\u043E\u043C \u043A\u043E\u043C\u043F\u044C\u044E\u0442\u0435\u0440\u0435`;
|
|
15881
|
+
}
|
|
15882
|
+
function fromList(list, description) {
|
|
15883
|
+
return list !== void 0 && list.length > 0 ? external_exports.enum([...list]).describe(description) : external_exports.string().describe(description);
|
|
15884
|
+
}
|
|
15885
|
+
function asToolResult(outcome) {
|
|
15886
|
+
return outcome.ok ? toolSuccess(outcome.text) : toolError(outcome.text);
|
|
15887
|
+
}
|
|
15888
|
+
function asJobResult(outcome) {
|
|
15889
|
+
if (!outcome.ok) return toolError(outcome.text);
|
|
15890
|
+
const job = readJob(outcome.text);
|
|
15891
|
+
return job === null ? toolSuccess(outcome.text) : toolSuccess(outcome.text, job);
|
|
15892
|
+
}
|
|
15893
|
+
var CAPABILITIES_CONTRACT = "naparnik-capabilities/1";
|
|
15894
|
+
var HEAVY_WORK = {
|
|
15895
|
+
model: "\u0440\u0430\u0441\u043F\u043E\u0437\u043D\u0430\u0432\u0430\u043D\u0438\u0435 \u0440\u0435\u0447\u0438",
|
|
15896
|
+
cutout: "\u0432\u044B\u0440\u0435\u0437 \u0433\u0435\u0440\u043E\u044F",
|
|
15897
|
+
voice: "\u0447\u0438\u0441\u0442\u043A\u0430 \u0433\u043E\u043B\u043E\u0441\u0430"
|
|
15898
|
+
};
|
|
15899
|
+
var KNOB_KIND = {
|
|
15900
|
+
file: "\u0444\u0430\u0439\u043B",
|
|
15901
|
+
string: "\u0441\u0442\u0440\u043E\u043A\u0430",
|
|
15902
|
+
number: "\u0447\u0438\u0441\u043B\u043E",
|
|
15903
|
+
"yes-no": "\u0434\u0430/\u043D\u0435\u0442"
|
|
15904
|
+
};
|
|
15905
|
+
var FROM_MINE = "mine";
|
|
15906
|
+
function catalogInWords(data) {
|
|
15907
|
+
const lines = [];
|
|
15908
|
+
const version2 = data.engine?.version;
|
|
15909
|
+
lines.push(`\u0427\u0442\u043E \u0443\u043C\u0435\u0435\u0442 \u043C\u043E\u043D\u0442\u0430\u0436 \u043D\u0430 \u044D\u0442\u043E\u043C \u043A\u043E\u043C\u043F\u044C\u044E\u0442\u0435\u0440\u0435${version2 !== void 0 ? `. \u0414\u0432\u0438\u0436\u043E\u043A ${version2}` : ""}.`);
|
|
15910
|
+
const steps = data.steps ?? [];
|
|
15911
|
+
const ready = steps.filter((s) => s.ready !== false);
|
|
15912
|
+
const later = steps.filter((s) => s.ready === false);
|
|
15913
|
+
if (ready.length > 0) {
|
|
15914
|
+
lines.push(`\u0423\u0436\u0435 \u0441\u0442\u043E\u0438\u0442: ${ready.map((s) => `${s.title} (${s.name})`).join(", ")}.`);
|
|
15991
15915
|
}
|
|
15992
|
-
|
|
15993
|
-
|
|
15916
|
+
if (later.length > 0) {
|
|
15917
|
+
const said = later.map((s) => {
|
|
15918
|
+
const work = (s.needs ?? []).map((n) => HEAVY_WORK[n] ?? n).join(" \u0438 ");
|
|
15919
|
+
const step = (s.needs ?? [])[0];
|
|
15920
|
+
return `${s.title} (${s.name}) \u2014 ${work}${step !== void 0 ? ` (install what="${step}")` : ""}`;
|
|
15921
|
+
}).join("; ");
|
|
15922
|
+
lines.push(
|
|
15923
|
+
`\u0414\u043E\u043A\u0430\u0447\u0430\u0435\u0442\u0441\u044F \u043F\u0435\u0440\u0435\u0434 \u043F\u0435\u0440\u0432\u044B\u043C \u043C\u043E\u043D\u0442\u0430\u0436\u043E\u043C, \u0441\u043F\u0440\u043E\u0441\u0438 \u0441\u043E\u0433\u043B\u0430\u0441\u0438\u0435 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430: ${said}.`
|
|
15924
|
+
);
|
|
15994
15925
|
}
|
|
15995
|
-
|
|
15996
|
-
|
|
15997
|
-
|
|
15998
|
-
*/
|
|
15999
|
-
submit(crash) {
|
|
16000
|
-
const delivery = this.#deliver(crash).catch(() => "none");
|
|
16001
|
-
this.#track(delivery.then(() => void 0));
|
|
16002
|
-
return delivery;
|
|
15926
|
+
const recipes = data.recipes ?? [];
|
|
15927
|
+
if (recipes.length > 0) {
|
|
15928
|
+
lines.push(`\u0413\u043E\u0442\u043E\u0432\u044B\u0435 \u043D\u0430\u0431\u043E\u0440\u044B \u0448\u0430\u0433\u043E\u0432: ${recipes.map((r) => `${r.title} (${r.name})`).join(", ")}.`);
|
|
16003
15929
|
}
|
|
16004
|
-
|
|
16005
|
-
|
|
16006
|
-
|
|
16007
|
-
|
|
16008
|
-
|
|
16009
|
-
async outcome(delivery) {
|
|
16010
|
-
let timer;
|
|
16011
|
-
const late = new Promise((done) => {
|
|
16012
|
-
timer = setTimeout(() => done("queued"), (this.#deps.timeoutMs ?? SEND_TIMEOUT_MS) + WORDS_GRACE_MS);
|
|
16013
|
-
timer.unref?.();
|
|
16014
|
-
});
|
|
16015
|
-
try {
|
|
16016
|
-
return await Promise.race([delivery, late]);
|
|
16017
|
-
} finally {
|
|
16018
|
-
clearTimeout(timer);
|
|
16019
|
-
}
|
|
15930
|
+
const inForce = data.recipe;
|
|
15931
|
+
if (inForce?.name !== void 0) {
|
|
15932
|
+
lines.push(
|
|
15933
|
+
inForce.origin === FROM_MINE ? `\u0420\u0435\u0446\u0435\u043F\u0442 \u0432 \u0434\u0435\u043B\u0435: \u0441\u0432\u043E\u0439 \xAB${inForce.name}\xBB \u2014 ${inForce.path ?? ""}.` : `\u0420\u0435\u0446\u0435\u043F\u0442 \u0432 \u0434\u0435\u043B\u0435: \u043D\u0430\u0448 \xAB${inForce.name}\xBB. \u0421\u0432\u043E\u0439 \u0437\u0430\u0432\u043E\u0434\u0438\u0442\u0441\u044F \u0447\u0435\u0440\u0435\u0437 plan_edit \u0441\u043E step.`
|
|
15934
|
+
);
|
|
16020
15935
|
}
|
|
16021
|
-
|
|
16022
|
-
|
|
16023
|
-
|
|
16024
|
-
|
|
16025
|
-
|
|
16026
|
-
|
|
16027
|
-
|
|
16028
|
-
|
|
16029
|
-
|
|
16030
|
-
|
|
15936
|
+
const questions = data.questions ?? [];
|
|
15937
|
+
if (questions.length > 0) {
|
|
15938
|
+
const sections = [...new Map(
|
|
15939
|
+
questions.filter((q) => q.section).map((q) => [q.section ?? "", q.group ?? ""])
|
|
15940
|
+
)].map(([id, tab]) => `${tab} (${id})`);
|
|
15941
|
+
lines.push(
|
|
15942
|
+
"\u0421\u043F\u0440\u043E\u0441\u0438\u0442\u044C \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0430\u043C\u0438 \u2014 choose_variant(questions=[\u2026]) \u0438\u043C\u0435\u043D\u0430\u043C\u0438 \u0432\u043E\u043F\u0440\u043E\u0441\u043E\u0432 \u0438\u043B\u0438 \u0440\u0430\u0437\u0434\u0435\u043B\u043E\u0432, \u0438 \u0442\u043E\u043B\u044C\u043A\u043E \u043F\u0440\u043E \u0442\u043E, \u0447\u0442\u043E \u0447\u0435\u043B\u043E\u0432\u0435\u043A \u0432\u044B\u0431\u0440\u0430\u043B \u0438\u043B\u0438 \u043F\u043E\u043F\u0440\u043E\u0441\u0438\u043B." + (sections.length > 0 ? ` \u0420\u0430\u0437\u0434\u0435\u043B\u044B: ${sections.join(", ")}.` : "")
|
|
15943
|
+
);
|
|
15944
|
+
for (const q of questions) {
|
|
15945
|
+
const tab = q.group ? `[${q.group}] ` : "";
|
|
15946
|
+
if (q.kind === "range") {
|
|
15947
|
+
const dials = (q.sliders ?? []).map((s) => `${s.title} (${s.name})`).join(", ");
|
|
15948
|
+
lines.push(`\u2014 ${tab}${q.title} (${q.name}), \u043F\u043E\u043B\u0437\u0443\u043D\u043A\u0430\u043C\u0438: ${dials}.`);
|
|
15949
|
+
continue;
|
|
15950
|
+
}
|
|
15951
|
+
const plain = q.kind === "plain" ? ", \u0431\u0435\u0437 \u043A\u0430\u0440\u0442\u0438\u043D\u043A\u0438" : "";
|
|
15952
|
+
const named = q.variants ?? [];
|
|
15953
|
+
const variants = named.length > 0 ? named.map((v) => `${v.title} (${v.name})`).join(", ") : "\u0432\u0430\u0440\u0438\u0430\u043D\u0442\u044B \u0441\u0447\u0438\u0442\u0430\u044E\u0442\u0441\u044F \u043F\u043E \u043A\u0430\u0434\u0440\u0443 \u0440\u043E\u043B\u0438\u043A\u0430";
|
|
15954
|
+
const total = typeof q.total === "number" ? q.total : named.length;
|
|
15955
|
+
const rest = total > named.length ? ` \u0438 \u0435\u0449\u0451 ${total - named.length}` : "";
|
|
15956
|
+
lines.push(`\u2014 ${tab}${q.title} (${q.name})${plain}: ${variants}${rest}.`);
|
|
16031
15957
|
}
|
|
16032
15958
|
}
|
|
16033
|
-
|
|
16034
|
-
|
|
16035
|
-
const
|
|
16036
|
-
|
|
16037
|
-
this.#lastFlush = now;
|
|
16038
|
-
this.#track(this.#flush());
|
|
15959
|
+
const knobs = data.knobs ?? [];
|
|
15960
|
+
if (knobs.length > 0) {
|
|
15961
|
+
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(", ");
|
|
15962
|
+
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}.`);
|
|
16039
15963
|
}
|
|
16040
|
-
|
|
16041
|
-
|
|
16042
|
-
|
|
15964
|
+
const index = data.handbook?.index;
|
|
15965
|
+
if (index !== void 0 && index.trim() !== "") {
|
|
15966
|
+
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:
|
|
15967
|
+
${index.trim()}`);
|
|
16043
15968
|
}
|
|
16044
|
-
|
|
16045
|
-
|
|
16046
|
-
|
|
15969
|
+
const style = data.style;
|
|
15970
|
+
if (style?.name !== void 0) {
|
|
15971
|
+
lines.push(
|
|
15972
|
+
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.`
|
|
15973
|
+
);
|
|
16047
15974
|
}
|
|
16048
|
-
|
|
16049
|
-
|
|
16050
|
-
|
|
16051
|
-
|
|
15975
|
+
const mine = data.mine?.summary ?? [];
|
|
15976
|
+
if (mine.length > 0) {
|
|
15977
|
+
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):
|
|
15978
|
+
${mine.map((line) => `\u2014 ${line}`).join("\n")}`);
|
|
16052
15979
|
}
|
|
16053
|
-
|
|
16054
|
-
|
|
16055
|
-
|
|
16056
|
-
|
|
16057
|
-
|
|
16058
|
-
|
|
16059
|
-
|
|
16060
|
-
|
|
15980
|
+
for (const said of data.warnings ?? []) lines.push(said);
|
|
15981
|
+
return lines.join("\n");
|
|
15982
|
+
}
|
|
15983
|
+
function otherContract(said, expected) {
|
|
15984
|
+
return `\u0414\u0432\u0438\u0436\u043E\u043A \u0433\u043E\u0432\u043E\u0440\u0438\u0442 \u043D\u0430 \u0434\u043E\u0433\u043E\u0432\u043E\u0440\u0435 \xAB${String(said)}\xBB, \u0430 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u0435 \u043F\u043E\u043D\u0438\u043C\u0430\u0435\u0442 \xAB${expected}\xBB. \u041E\u0431\u043D\u043E\u0432\u0438 \u043C\u043E\u043D\u0442\u0430\u0436: install \u0441 what=all \u2014 \u043F\u043E\u0441\u0442\u0430\u0432\u0438\u0442 \u043D\u043E\u0432\u044B\u0435 \u0432\u0435\u0440\u0441\u0438\u0438 \u0434\u0432\u0438\u0436\u043A\u0430 \u0438 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F.`;
|
|
15985
|
+
}
|
|
15986
|
+
async function askCatalog(engine, pack, video) {
|
|
15987
|
+
const answer = await engine.command([
|
|
15988
|
+
"capabilities",
|
|
15989
|
+
"--pack",
|
|
15990
|
+
pack,
|
|
15991
|
+
...video !== void 0 ? ["--video", path(video)] : []
|
|
15992
|
+
]);
|
|
15993
|
+
if (!answer.ok) return `\u0421\u043F\u0438\u0441\u043E\u043A \u0442\u043E\u0433\u043E, \u0447\u0442\u043E \u0443\u043C\u0435\u0435\u0442 \u043C\u043E\u043D\u0442\u0430\u0436, \u043D\u0435 \u043F\u0440\u0438\u0448\u0451\u043B: ${answer.text}`;
|
|
15994
|
+
let data;
|
|
15995
|
+
try {
|
|
15996
|
+
data = JSON.parse(answer.text);
|
|
15997
|
+
} catch {
|
|
15998
|
+
return `\u0421\u043F\u0438\u0441\u043E\u043A \u0442\u043E\u0433\u043E, \u0447\u0442\u043E \u0443\u043C\u0435\u0435\u0442 \u043C\u043E\u043D\u0442\u0430\u0436, \u043D\u0435 \u043F\u0440\u0438\u0448\u0451\u043B: ${NOT_JSON}`;
|
|
16061
15999
|
}
|
|
16062
|
-
|
|
16063
|
-
|
|
16064
|
-
this.#inflight.add(guarded);
|
|
16065
|
-
void guarded.finally(() => this.#inflight.delete(guarded));
|
|
16000
|
+
if (data.contract !== CAPABILITIES_CONTRACT) {
|
|
16001
|
+
return `\u0414\u0432\u0438\u0436\u043E\u043A \u0433\u043E\u0432\u043E\u0440\u0438\u0442 \u043D\u0430 \u0434\u043E\u0433\u043E\u0432\u043E\u0440\u0435 \xAB${String(data.contract)}\xBB, \u0430 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u0435 \u043F\u043E\u043D\u0438\u043C\u0430\u0435\u0442 \xAB${CAPABILITIES_CONTRACT}\xBB, \u0438 \u0441\u043F\u0438\u0441\u043E\u043A \u0442\u043E\u0433\u043E, \u0447\u0442\u043E \u0443\u043C\u0435\u0435\u0442 \u043C\u043E\u043D\u0442\u0430\u0436, \u043D\u0435 \u043F\u0440\u043E\u0447\u0438\u0442\u0430\u043D. \u041E\u0431\u043D\u043E\u0432\u0438 \u043C\u043E\u043D\u0442\u0430\u0436: install \u0441 what=all \u2014 \u043F\u043E\u0441\u0442\u0430\u0432\u0438\u0442 \u043D\u043E\u0432\u044B\u0435 \u0432\u0435\u0440\u0441\u0438\u0438 \u0434\u0432\u0438\u0436\u043A\u0430 \u0438 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F.`;
|
|
16066
16002
|
}
|
|
16067
|
-
|
|
16068
|
-
|
|
16069
|
-
|
|
16070
|
-
|
|
16071
|
-
|
|
16072
|
-
|
|
16073
|
-
|
|
16074
|
-
return
|
|
16003
|
+
return catalogInWords(data);
|
|
16004
|
+
}
|
|
16005
|
+
function fromWords(text2, contract) {
|
|
16006
|
+
let data;
|
|
16007
|
+
try {
|
|
16008
|
+
data = JSON.parse(text2);
|
|
16009
|
+
} catch {
|
|
16010
|
+
return { refusal: NOT_JSON };
|
|
16075
16011
|
}
|
|
16076
|
-
|
|
16077
|
-
|
|
16078
|
-
return readdirSync(this.#queueDir()).some((f) => f.endsWith(`-${fingerprint}.json`));
|
|
16079
|
-
} catch {
|
|
16080
|
-
return false;
|
|
16081
|
-
}
|
|
16012
|
+
if (contract !== void 0 && data.contract !== contract) {
|
|
16013
|
+
return { refusal: otherContract(data.contract, contract) };
|
|
16082
16014
|
}
|
|
16083
|
-
|
|
16084
|
-
|
|
16085
|
-
|
|
16086
|
-
|
|
16087
|
-
|
|
16088
|
-
|
|
16089
|
-
|
|
16090
|
-
|
|
16091
|
-
|
|
16092
|
-
|
|
16093
|
-
|
|
16094
|
-
|
|
16095
|
-
|
|
16096
|
-
|
|
16097
|
-
|
|
16098
|
-
continue;
|
|
16099
|
-
}
|
|
16100
|
-
const verdict = await this.#send(report);
|
|
16101
|
-
if (verdict === "retry") return;
|
|
16102
|
-
rmSync(path2, { force: true });
|
|
16103
|
-
}
|
|
16015
|
+
if (typeof data.words !== "string" || data.words === "") return { refusal: NOT_JSON };
|
|
16016
|
+
return { words: data.words, data };
|
|
16017
|
+
}
|
|
16018
|
+
function folderAnswer(text2) {
|
|
16019
|
+
const read = fromWords(text2);
|
|
16020
|
+
return "refusal" in read ? toolError(read.refusal) : toolSuccess(read.words, read.data);
|
|
16021
|
+
}
|
|
16022
|
+
var DRAFT_CONTRACT = "naparnik-draft/1";
|
|
16023
|
+
var VIEW_CONTRACT = "naparnik-view/1";
|
|
16024
|
+
var EDIT_CONTRACT = "naparnik-edit/1";
|
|
16025
|
+
function answerOrRefusal(text2, contract) {
|
|
16026
|
+
const read = fromWords(text2, contract);
|
|
16027
|
+
if ("refusal" in read) {
|
|
16028
|
+
const plain = text2.trim();
|
|
16029
|
+
return { refusal: plain.startsWith("{") || plain === "" ? read.refusal : plain };
|
|
16104
16030
|
}
|
|
16105
|
-
|
|
16106
|
-
* Отправить и решить, что делать с отчётом дальше.
|
|
16107
|
-
*
|
|
16108
|
-
* ⚠ В ОЧЕРЕДЬ ИДЁТ ТОЛЬКО ТО, ЧТО ПОВТОР ИСПРАВИТ: нет сети, таймаут, 5xx,
|
|
16109
|
-
* 429 и «ключа нет» (человек впишет его завтра). 400 и 413 — отчёт кривой,
|
|
16110
|
-
* 401 и 403 — ключ не наш: повтор даст тот же отказ, а очередь с потолком
|
|
16111
|
-
* вытесняла бы им живые отчёты.
|
|
16112
|
-
*/
|
|
16113
|
-
async #send(report) {
|
|
16114
|
-
if (!CrashReportRequest.safeParse(report).success) return "drop";
|
|
16115
|
-
try {
|
|
16116
|
-
await this.#deps.client.postMontage(CRASH_REPORT_PATH, report, {
|
|
16117
|
-
once: true,
|
|
16118
|
-
timeoutMs: this.#deps.timeoutMs ?? SEND_TIMEOUT_MS
|
|
16119
|
-
});
|
|
16120
|
-
return "sent";
|
|
16121
|
-
} catch (trouble) {
|
|
16122
|
-
if (trouble instanceof NaparnikAuthError || trouble instanceof NaparnikScopeError) return "drop";
|
|
16123
|
-
if (trouble instanceof NaparnikClientError) return trouble.status === 429 ? "retry" : "drop";
|
|
16124
|
-
return "retry";
|
|
16125
|
-
}
|
|
16126
|
-
}
|
|
16127
|
-
/**
|
|
16128
|
-
* Собрать отчёт: обезличить, обрезать, посчитать отпечаток и решить по
|
|
16129
|
-
* частоте. `null` — этот отпечаток уже уходил меньше получаса назад, и
|
|
16130
|
-
* повтор записан в счётчик.
|
|
16131
|
-
*/
|
|
16132
|
-
#build(crash) {
|
|
16133
|
-
const fingerprint = fingerprintOf2(crash.errorType, crash.frames);
|
|
16134
|
-
const state = this.#state();
|
|
16135
|
-
const now = this.#now();
|
|
16136
|
-
const seen = state.fingerprints[fingerprint];
|
|
16137
|
-
if (seen !== void 0 && now - seen.sentAt < RESEND_AFTER_MS) {
|
|
16138
|
-
seen.pending += 1;
|
|
16139
|
-
this.#save(state);
|
|
16140
|
-
return null;
|
|
16141
|
-
}
|
|
16142
|
-
const repeats = Math.min(seen?.pending ?? 0, CRASH_LIMITS.repeats);
|
|
16143
|
-
state.fingerprints[fingerprint] = { sentAt: now, pending: 0 };
|
|
16144
|
-
prune(state, now);
|
|
16145
|
-
this.#save(state);
|
|
16146
|
-
const context = this.scrubContext([...crash.secrets, ...this.#recentSecrets]);
|
|
16147
|
-
const clean = (text2) => scrub(text2, context);
|
|
16148
|
-
return {
|
|
16149
|
-
contract: CRASH_CONTRACT,
|
|
16150
|
-
occurred_at: new Date(now).toISOString(),
|
|
16151
|
-
where: crash.where,
|
|
16152
|
-
tool: crash.tool !== null && CRASH_TOOL_NAME.test(crash.tool) ? crash.tool : null,
|
|
16153
|
-
// ⚠ РЕЖЕМ ДО ОБЕЗЛИЧИВАНИЯ С ЗАПАСОМ И ЕЩЁ РАЗ ПОСЛЕ. Обезличивание идёт
|
|
16154
|
-
// синхронно, до ответа инструмента, а stderr движка бывает мегабайтами:
|
|
16155
|
-
// без первой резки длинный текст подвешивал бы ответ на секунды (ревью
|
|
16156
|
-
// безопасности 2026-09-24). Запас — вдвое: метки короче того, что заменяют.
|
|
16157
|
-
stage: crash.stage === null ? null : head(clean(head(crash.stage, 2 * CRASH_LIMITS.stage)), CRASH_LIMITS.stage),
|
|
16158
|
-
error_type: head(clean(head(crash.errorType, 2 * CRASH_LIMITS.errorType)), CRASH_LIMITS.errorType) || "Error",
|
|
16159
|
-
message: head(clean(head(crash.message, 2 * CRASH_LIMITS.message)), CRASH_LIMITS.message),
|
|
16160
|
-
trace: crash.keep === "tail" ? tail(clean(crash.trace.slice(-2 * CRASH_LIMITS.trace)), CRASH_LIMITS.trace) : head(clean(head(crash.trace, 2 * CRASH_LIMITS.trace)), CRASH_LIMITS.trace),
|
|
16161
|
-
fingerprint,
|
|
16162
|
-
repeats,
|
|
16163
|
-
os: {
|
|
16164
|
-
platform: head(platform(), CRASH_LIMITS.osPlatform),
|
|
16165
|
-
release: head(release(), CRASH_LIMITS.osRelease),
|
|
16166
|
-
arch: head(arch(), CRASH_LIMITS.osArch)
|
|
16167
|
-
},
|
|
16168
|
-
host: hostOf(crash.host ?? this.#host),
|
|
16169
|
-
versions: {
|
|
16170
|
-
shell: head(VERSION, CRASH_LIMITS.shellVersion),
|
|
16171
|
-
engine: orNull(this.#deps.engineVersion(), CRASH_LIMITS.engineVersion),
|
|
16172
|
-
python: orNull(crash.python, CRASH_LIMITS.pythonVersion),
|
|
16173
|
-
ffmpeg: null
|
|
16174
|
-
},
|
|
16175
|
-
recent_calls: recentCalls(this.#deps.home)
|
|
16176
|
-
};
|
|
16177
|
-
}
|
|
16178
|
-
/** Положить отчёт в очередь. `false` — диск не принял, отчёт пропал. */
|
|
16179
|
-
#enqueue(report) {
|
|
16180
|
-
try {
|
|
16181
|
-
const dir = this.#queueDir();
|
|
16182
|
-
mkdirSync(dir, { recursive: true });
|
|
16183
|
-
const name = `${String(this.#now()).padStart(15, "0")}-${report.fingerprint}.json`;
|
|
16184
|
-
const temporary = join(dir, `${name}.tmp`);
|
|
16185
|
-
writeFileSync(temporary, JSON.stringify(report), { mode: 384 });
|
|
16186
|
-
renameSync(temporary, join(dir, name));
|
|
16187
|
-
const files = readdirSync(dir).filter((f) => f.endsWith(".json")).sort();
|
|
16188
|
-
for (const old of files.slice(0, Math.max(0, files.length - QUEUE_CAP))) {
|
|
16189
|
-
rmSync(join(dir, old), { force: true });
|
|
16190
|
-
}
|
|
16191
|
-
return true;
|
|
16192
|
-
} catch {
|
|
16193
|
-
return false;
|
|
16194
|
-
}
|
|
16195
|
-
}
|
|
16196
|
-
#queueDir() {
|
|
16197
|
-
return join(this.#deps.home, "crash-reports", "queue");
|
|
16198
|
-
}
|
|
16199
|
-
#stateFile() {
|
|
16200
|
-
return join(this.#deps.home, "crash-reports", "seen.json");
|
|
16201
|
-
}
|
|
16202
|
-
#state() {
|
|
16203
|
-
try {
|
|
16204
|
-
const parsed = JSON.parse(readFileSync(this.#stateFile(), "utf8"));
|
|
16205
|
-
return {
|
|
16206
|
-
fingerprints: typeof parsed.fingerprints === "object" && parsed.fingerprints !== null ? parsed.fingerprints : {},
|
|
16207
|
-
jobs: Array.isArray(parsed.jobs) ? parsed.jobs.filter((j) => typeof j === "string") : []
|
|
16208
|
-
};
|
|
16209
|
-
} catch {
|
|
16210
|
-
return { fingerprints: {}, jobs: [] };
|
|
16211
|
-
}
|
|
16212
|
-
}
|
|
16213
|
-
#save(state) {
|
|
16214
|
-
try {
|
|
16215
|
-
mkdirSync(dirname(this.#stateFile()), { recursive: true });
|
|
16216
|
-
writeFileSync(this.#stateFile(), JSON.stringify(state), { mode: 384 });
|
|
16217
|
-
} catch {
|
|
16218
|
-
}
|
|
16219
|
-
}
|
|
16220
|
-
#ffmpegVersion() {
|
|
16221
|
-
this.#ffmpeg ??= (this.#deps.ffmpegVersion ?? (() => probeFfmpeg(this.#deps.home)))().catch(() => null);
|
|
16222
|
-
return this.#ffmpeg.then((v) => orNull(v, CRASH_LIMITS.ffmpegVersion));
|
|
16223
|
-
}
|
|
16224
|
-
};
|
|
16225
|
-
function prune(state, now) {
|
|
16226
|
-
for (const [key, value] of Object.entries(state.fingerprints)) {
|
|
16227
|
-
if (now - value.sentAt > 24 * 36e5 && value.pending === 0) delete state.fingerprints[key];
|
|
16228
|
-
}
|
|
16229
|
-
}
|
|
16230
|
-
function withCrashReport(crashes) {
|
|
16231
|
-
return (tool) => {
|
|
16232
|
-
if (crashes === null) return tool;
|
|
16233
|
-
const original = tool.execute.bind(tool);
|
|
16234
|
-
return {
|
|
16235
|
-
...tool,
|
|
16236
|
-
async execute(input, ...rest) {
|
|
16237
|
-
crashes.flushSoon();
|
|
16238
|
-
const host = hostFromContext(rest[0]);
|
|
16239
|
-
crashes.noteHost(host);
|
|
16240
|
-
crashes.noteSecrets(secretsOf(input));
|
|
16241
|
-
let result;
|
|
16242
|
-
let faults;
|
|
16243
|
-
try {
|
|
16244
|
-
({ value: result, faults } = await collectInstallFaults(() => original(input, ...rest)));
|
|
16245
|
-
} catch (trouble) {
|
|
16246
|
-
const crash = fromThrown(trouble, "tool", tool.name, input, host);
|
|
16247
|
-
return toolError(await brokenWords(crash, crashes, crashes.submit(crash)));
|
|
16248
|
-
}
|
|
16249
|
-
const install2 = firstInstallCrash(faults);
|
|
16250
|
-
if (install2 !== null) {
|
|
16251
|
-
const crash = { ...install2, where: "tool", tool: tool.name, secrets: secretsOf(input), host };
|
|
16252
|
-
return withNotice(result, await brokenWords(crash, crashes, crashes.submit(crash)));
|
|
16253
|
-
}
|
|
16254
|
-
return caught(result, tool.name, input, host, crashes);
|
|
16255
|
-
}
|
|
16256
|
-
};
|
|
16257
|
-
};
|
|
16031
|
+
return read.data["ok"] === false ? { refusal: read.words } : read;
|
|
16258
16032
|
}
|
|
16259
|
-
async function
|
|
16260
|
-
const
|
|
16261
|
-
|
|
16262
|
-
|
|
16263
|
-
|
|
16264
|
-
|
|
16265
|
-
|
|
16033
|
+
async function draftDocument(engine, place, asked, key) {
|
|
16034
|
+
const answer = await engine.command([
|
|
16035
|
+
"document-draft",
|
|
16036
|
+
"--video",
|
|
16037
|
+
asked.video,
|
|
16038
|
+
"--pack",
|
|
16039
|
+
place.pack,
|
|
16040
|
+
...asked.style !== void 0 ? ["--style", path(asked.style)] : [],
|
|
16041
|
+
...(asked.also ?? []).flatMap((one) => ["--also", path(one)]),
|
|
16042
|
+
...asked.ask !== void 0 ? ["--ask", JSON.stringify(asked.ask)] : [],
|
|
16043
|
+
"--json"
|
|
16044
|
+
], key !== void 0 ? { key } : {});
|
|
16045
|
+
return answer.ok ? answerOrRefusal(answer.text, DRAFT_CONTRACT) : { refusal: answer.text };
|
|
16266
16046
|
}
|
|
16267
|
-
function
|
|
16268
|
-
|
|
16269
|
-
|
|
16270
|
-
|
|
16271
|
-
|
|
16272
|
-
|
|
16047
|
+
async function editOperations(engine, place, asked, key) {
|
|
16048
|
+
const answer = await engine.command([
|
|
16049
|
+
"document-edit",
|
|
16050
|
+
"--project",
|
|
16051
|
+
path(asked.reel),
|
|
16052
|
+
"--ops",
|
|
16053
|
+
JSON.stringify(asked.ops),
|
|
16054
|
+
...asked.stamps !== void 0 ? ["--stamps", JSON.stringify(asked.stamps)] : [],
|
|
16055
|
+
"--by",
|
|
16056
|
+
asked.by ?? "model",
|
|
16057
|
+
"--pack",
|
|
16058
|
+
place.pack,
|
|
16059
|
+
"--json"
|
|
16060
|
+
], key !== void 0 ? { key } : {});
|
|
16061
|
+
return answer.ok ? answerOrRefusal(answer.text, EDIT_CONTRACT) : { refusal: answer.text };
|
|
16273
16062
|
}
|
|
16274
|
-
function
|
|
16275
|
-
|
|
16276
|
-
|
|
16277
|
-
|
|
16278
|
-
|
|
16279
|
-
|
|
16280
|
-
|
|
16063
|
+
function nameOrRefusal(candidate) {
|
|
16064
|
+
const looksLikePath2 = candidate.includes("/") || candidate.includes("\\") || candidate.startsWith("~") || candidate.startsWith(".") || candidate.length > 1 && candidate[1] === ":";
|
|
16065
|
+
if (!looksLikePath2) return { name: candidate };
|
|
16066
|
+
return {
|
|
16067
|
+
refusal: `\u0417\u0434\u0435\u0441\u044C \u0436\u0434\u0443\u0442 \u0418\u041C\u042F \u0448\u0430\u0433\u0430, \u0430 \u043F\u0440\u0438\u0448\u0451\u043B \u043F\u0443\u0442\u044C: ${candidate}
|
|
16068
|
+
\u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C: \u043D\u0430\u0437\u043E\u0432\u0438 \u0448\u0430\u0433 \u043E\u0434\u043D\u0438\u043C \u0441\u043B\u043E\u0432\u043E\u043C \u2014 \u0442\u0430\u043A, \u043A\u0430\u043A \u043D\u0430\u0437\u044B\u0432\u0430\u0435\u0442\u0441\u044F \u0435\u0433\u043E \u043F\u0430\u043F\u043A\u0430. \u0421\u0432\u043E\u0439 \u0448\u0430\u0433 \u043B\u0435\u0436\u0438\u0442 \u0432 \`mine/steps/<\u0438\u043C\u044F>\` \u0432 \u0434\u043E\u043C\u0435 \u041D\u0430\u043F\u0430\u0440\u043D\u0438\u043A\u0430, \u043D\u0430\u0448\u0438 \u043F\u0435\u0440\u0435\u0447\u0438\u0441\u043B\u044F\u0435\u0442 setup, \u0438\u043C\u044F \u0443 \u043A\u0430\u0436\u0434\u043E\u0433\u043E \u0441\u0442\u043E\u0438\u0442 \u0432 \u0441\u043A\u043E\u0431\u043A\u0430\u0445.`
|
|
16069
|
+
};
|
|
16281
16070
|
}
|
|
16282
|
-
|
|
16283
|
-
|
|
16284
|
-
|
|
16285
|
-
|
|
16286
|
-
|
|
16287
|
-
|
|
16071
|
+
var SETUP_CONTRACT = "naparnik-setup/1";
|
|
16072
|
+
var READINESS_CONTRACT = "naparnik-readiness/1";
|
|
16073
|
+
var JSON_CHECK = "--json";
|
|
16074
|
+
function knowsJsonCheck(engineDir) {
|
|
16075
|
+
try {
|
|
16076
|
+
const contract = JSON.parse(readFileSync(join(engineDir, "shell-contract.json"), "utf8"));
|
|
16077
|
+
const flags = contract.env_check_flags;
|
|
16078
|
+
return Array.isArray(flags) && flags.includes(JSON_CHECK);
|
|
16079
|
+
} catch {
|
|
16080
|
+
return false;
|
|
16288
16081
|
}
|
|
16289
|
-
const job = result.structured;
|
|
16290
|
-
if (job === void 0 || job["contract"] !== JOB_CONTRACT || job["status"] !== "error") return result;
|
|
16291
|
-
const id = typeof job["id"] === "string" ? job["id"] : "";
|
|
16292
|
-
if (!/^[\w.-]{1,80}$/.test(id) || crashes.jobSeen(id)) return result;
|
|
16293
|
-
const fromLog = pythonCrash(jobLogTail(crashes.home, id));
|
|
16294
|
-
const install2 = fromLog === null ? firstInstallCrash(jobInstallFaults(id)) : null;
|
|
16295
|
-
const parsed = fromLog ?? install2;
|
|
16296
|
-
if (parsed === null) return result;
|
|
16297
|
-
crashes.rememberJob(id);
|
|
16298
|
-
const stage = install2?.stage ?? (typeof job["now"] === "string" && job["now"] !== "" ? job["now"] : null);
|
|
16299
|
-
const crash = { ...parsed, where: "job", tool: name, stage, secrets: secretsOf(input), host };
|
|
16300
|
-
return withNotice(result, await brokenWords(crash, crashes, crashes.submit(crash)));
|
|
16301
16082
|
}
|
|
16302
|
-
|
|
16303
|
-
|
|
16304
|
-
|
|
16305
|
-
return [
|
|
16306
|
-
`\u0421\u043A\u0430\u0436\u0438 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0443 \u0442\u0430\u043A, \u0441\u0432\u043E\u0438\u043C\u0438 \u0441\u043B\u043E\u0432\u0430\u043C\u0438 \u043D\u0435 \u043C\u0435\u043D\u044F\u0439: \xAB${humanWords(fate)}\xBB`,
|
|
16307
|
-
`\u0421\u0443\u0442\u044C \u0434\u043B\u044F \u0442\u0435\u0431\u044F, \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0443 \u043D\u0435 \u0437\u0430\u0447\u0438\u0442\u044B\u0432\u0430\u0439: ${essence}`
|
|
16308
|
-
].join("\n");
|
|
16083
|
+
var STATES = /* @__PURE__ */ new Set(["ok", "missing", "later"]);
|
|
16084
|
+
function megabytes(value) {
|
|
16085
|
+
return typeof value === "number" && value > 0 ? Math.round(value) : 0;
|
|
16309
16086
|
}
|
|
16310
|
-
function
|
|
16311
|
-
|
|
16312
|
-
|
|
16087
|
+
function readReadiness(stdout) {
|
|
16088
|
+
const lines = stdout.trim().split("\n");
|
|
16089
|
+
let raw;
|
|
16090
|
+
try {
|
|
16091
|
+
raw = JSON.parse(lines[lines.length - 1] ?? "");
|
|
16092
|
+
} catch {
|
|
16093
|
+
return null;
|
|
16313
16094
|
}
|
|
16314
|
-
|
|
16315
|
-
|
|
16095
|
+
const data = raw;
|
|
16096
|
+
if (data === null || typeof data !== "object" || data["contract"] !== READINESS_CONTRACT) return null;
|
|
16097
|
+
if (typeof data["words"] !== "string" || !Array.isArray(data["parts"])) return null;
|
|
16098
|
+
const parts = [];
|
|
16099
|
+
for (const item of data["parts"]) {
|
|
16100
|
+
const part = item;
|
|
16101
|
+
if (part === null || typeof part !== "object" || typeof part["name"] !== "string") continue;
|
|
16102
|
+
parts.push({
|
|
16103
|
+
name: part["name"],
|
|
16104
|
+
title: typeof part["title"] === "string" && part["title"] !== "" ? part["title"] : part["name"],
|
|
16105
|
+
ok: part["ok"] === true,
|
|
16106
|
+
mb: megabytes(part["mb"]),
|
|
16107
|
+
on_demand: part["on_demand"] === true,
|
|
16108
|
+
step: typeof part["step"] === "string" ? part["step"] : ""
|
|
16109
|
+
});
|
|
16316
16110
|
}
|
|
16317
|
-
|
|
16318
|
-
|
|
16319
|
-
|
|
16320
|
-
|
|
16321
|
-
|
|
16322
|
-
|
|
16323
|
-
|
|
16324
|
-
|
|
16325
|
-
|
|
16111
|
+
let rows = null;
|
|
16112
|
+
if (Array.isArray(data["rows"])) {
|
|
16113
|
+
rows = [];
|
|
16114
|
+
for (const item of data["rows"]) {
|
|
16115
|
+
const row = item;
|
|
16116
|
+
if (row === null || typeof row !== "object" || typeof row["title"] !== "string") continue;
|
|
16117
|
+
const state = row["state"];
|
|
16118
|
+
if (typeof state !== "string" || !STATES.has(state)) continue;
|
|
16119
|
+
rows.push({ title: row["title"], state, mb: megabytes(row["mb"]) });
|
|
16326
16120
|
}
|
|
16327
|
-
exit(1);
|
|
16328
|
-
};
|
|
16329
|
-
proc.on("uncaughtException", fall);
|
|
16330
|
-
proc.on("unhandledRejection", fall);
|
|
16331
|
-
crashes.flushSoon();
|
|
16332
|
-
}
|
|
16333
|
-
function fromThrown(trouble, where, tool, input, host) {
|
|
16334
|
-
const error40 = trouble instanceof Error ? trouble : new Error(String(trouble));
|
|
16335
|
-
const errorType = error40.name || error40.constructor.name || "Error";
|
|
16336
|
-
const trace = error40.stack ?? `${errorType}: ${error40.message}`;
|
|
16337
|
-
const frames = jsFrames(trace);
|
|
16338
|
-
return {
|
|
16339
|
-
where,
|
|
16340
|
-
tool,
|
|
16341
|
-
stage: null,
|
|
16342
|
-
errorType,
|
|
16343
|
-
message: error40.message,
|
|
16344
|
-
trace,
|
|
16345
|
-
keep: "head",
|
|
16346
|
-
frames: frames.slice(0, 3).map((f) => `${f.file}:${f.func}`),
|
|
16347
|
-
python: null,
|
|
16348
|
-
secrets: secretsOf(input),
|
|
16349
|
-
host,
|
|
16350
|
-
essence: `${errorType}: ${error40.message}${frames[0] ? ` \u2014 ${frames[0].file}` : ""}`
|
|
16351
|
-
};
|
|
16352
|
-
}
|
|
16353
|
-
function installCrash(fault) {
|
|
16354
|
-
const { stage, trouble } = fault;
|
|
16355
|
-
if (machineCause(trouble)) return null;
|
|
16356
|
-
const said = commandOutput(trouble);
|
|
16357
|
-
if (said.includes(PYTHON_TRACEBACK)) {
|
|
16358
|
-
const parsed = pythonCrash(said);
|
|
16359
|
-
return parsed === null ? null : { ...parsed, stage };
|
|
16360
16121
|
}
|
|
16361
|
-
|
|
16362
|
-
const reason = lastMeaningfulLine(said) ?? lastMeaningfulLine(error40.message) ?? error40.name;
|
|
16363
|
-
const command = typeof trouble.cmd === "string" ? trouble.cmd : "";
|
|
16364
|
-
const trace = [
|
|
16365
|
-
command === "" ? "" : `\u043A\u043E\u043C\u0430\u043D\u0434\u0430: ${command}`,
|
|
16366
|
-
said.trim() === "" ? "" : `\u0432\u044B\u0432\u043E\u0434 \u043A\u043E\u043C\u0430\u043D\u0434\u044B:
|
|
16367
|
-
${said.trim().slice(-4e3)}`,
|
|
16368
|
-
error40.stack ?? `${error40.name}: ${error40.message}`
|
|
16369
|
-
].filter((part) => part !== "").join("\n\n");
|
|
16370
|
-
return {
|
|
16371
|
-
stage,
|
|
16372
|
-
errorType: "InstallError",
|
|
16373
|
-
message: `${stage}: ${reason}`,
|
|
16374
|
-
trace,
|
|
16375
|
-
keep: "head",
|
|
16376
|
-
// ⚠ ПРИЧИНА В ОТПЕЧАТКЕ — БЕЗ ПУТЕЙ И ЧИСЕЛ. Иначе все беды шага склеились
|
|
16377
|
-
// бы в один отпечаток, а сервер пишет в бот про отпечаток раз в час: вторая,
|
|
16378
|
-
// другая беда того же шага промолчала бы. А с путями и версиями одна и та
|
|
16379
|
-
// же беда у двух покупателей считалась бы двумя.
|
|
16380
|
-
frames: [`install:${stage}`, reason.replace(/(?:[A-Za-z]:)?[\\/][^\s'"]*/g, "<path>").replace(/\d+/g, "0").slice(0, 160)],
|
|
16381
|
-
python: /python@?(\d)\.(\d{1,2})\b/i.exec(command)?.slice(1, 3).join(".") ?? null,
|
|
16382
|
-
essence: `\u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0430, \u0448\u0430\u0433 ${stage}: ${reason}`
|
|
16383
|
-
};
|
|
16384
|
-
}
|
|
16385
|
-
function machineCause(trouble) {
|
|
16386
|
-
const t = trouble ?? {};
|
|
16387
|
-
if (typeof t.code === "string" && MACHINE_CODES.has(t.code)) return true;
|
|
16388
|
-
if (t.code === 2) return true;
|
|
16389
|
-
if (t.killed === true || typeof t.signal === "string" && t.signal !== "") return true;
|
|
16390
|
-
const text2 = `${typeof t.message === "string" ? t.message : String(trouble)}
|
|
16391
|
-
${commandOutput(trouble)}`;
|
|
16392
|
-
return MACHINE_WORDS.test(text2);
|
|
16393
|
-
}
|
|
16394
|
-
var MACHINE_CODES = /* @__PURE__ */ new Set([
|
|
16395
|
-
"ENOSPC",
|
|
16396
|
-
"EDQUOT",
|
|
16397
|
-
"EACCES",
|
|
16398
|
-
"EPERM",
|
|
16399
|
-
"EROFS",
|
|
16400
|
-
"EBUSY",
|
|
16401
|
-
"ENOTFOUND",
|
|
16402
|
-
"EAI_AGAIN",
|
|
16403
|
-
"ECONNRESET",
|
|
16404
|
-
"ECONNREFUSED",
|
|
16405
|
-
"ETIMEDOUT",
|
|
16406
|
-
"ENETUNREACH",
|
|
16407
|
-
"ENETDOWN",
|
|
16408
|
-
"EHOSTUNREACH"
|
|
16409
|
-
]);
|
|
16410
|
-
var MACHINE_WORDS = new RegExp([
|
|
16411
|
-
"No space left on device",
|
|
16412
|
-
"Disk quota exceeded",
|
|
16413
|
-
"Permission denied",
|
|
16414
|
-
"Operation not permitted",
|
|
16415
|
-
"Read-only file system",
|
|
16416
|
-
"Access is denied",
|
|
16417
|
-
"Temporary failure in name resolution",
|
|
16418
|
-
"Name or service not known",
|
|
16419
|
-
"nodename nor servname",
|
|
16420
|
-
"getaddrinfo",
|
|
16421
|
-
"Network is unreachable",
|
|
16422
|
-
"No route to host",
|
|
16423
|
-
"Connection refused",
|
|
16424
|
-
"Connection reset",
|
|
16425
|
-
"Connection aborted",
|
|
16426
|
-
"timed out",
|
|
16427
|
-
"Max retries exceeded",
|
|
16428
|
-
"NewConnectionError",
|
|
16429
|
-
"ConnectTimeoutError",
|
|
16430
|
-
"ReadTimeoutError",
|
|
16431
|
-
"ProxyError",
|
|
16432
|
-
"CERTIFICATE_VERIFY_FAILED"
|
|
16433
|
-
].map((one) => one.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|"), "i");
|
|
16434
|
-
function commandOutput(trouble) {
|
|
16435
|
-
const t = trouble ?? {};
|
|
16436
|
-
return [t.stderr, t.stdout].filter((one) => typeof one === "string" && one.trim() !== "").join("\n");
|
|
16437
|
-
}
|
|
16438
|
-
function lastMeaningfulLine(text2) {
|
|
16439
|
-
const lines = text2.split("\n").map((one) => one.trim()).filter((one) => one !== "" && !/^Command failed:/.test(one));
|
|
16440
|
-
return lines[lines.length - 1] ?? null;
|
|
16122
|
+
return { words: data["words"], ready: data["ready"] === true, parts, rows };
|
|
16441
16123
|
}
|
|
16442
|
-
function
|
|
16443
|
-
|
|
16444
|
-
|
|
16445
|
-
|
|
16446
|
-
if (m === null) continue;
|
|
16447
|
-
const file2 = basename(m[2] ?? "").replace(/-[A-Za-z0-9]{6,}(\.[cm]?js)$/, "$1");
|
|
16448
|
-
frames.push({ file: file2, func: m[1] ?? "<anonymous>" });
|
|
16449
|
-
}
|
|
16450
|
-
return frames;
|
|
16124
|
+
function refusalWords(status) {
|
|
16125
|
+
if (status === 401) return `\u041A\u043B\u044E\u0447 \u043D\u0435 \u043F\u043E\u0434\u0445\u043E\u0434\u0438\u0442. \u0412\u043E\u0437\u044C\u043C\u0438 \u043D\u043E\u0432\u044B\u0439 \u0444\u0430\u0439\u043B \u0432 \u0442\u0435\u043B\u0435\u0433\u0440\u0430\u043C-\u0431\u043E\u0442\u0435 ${KEY_SOURCE_HANDLE}.`;
|
|
16126
|
+
if (status === 403) return `\u041F\u043E\u0434\u043F\u0438\u0441\u043A\u0430 \u0437\u0430\u043A\u043E\u043D\u0447\u0438\u043B\u0430\u0441\u044C. \u041F\u0440\u043E\u0434\u043B\u0438 \u0435\u0451 \u0432 \u0442\u0435\u043B\u0435\u0433\u0440\u0430\u043C-\u0431\u043E\u0442\u0435 ${KEY_SOURCE_HANDLE}.`;
|
|
16127
|
+
return "";
|
|
16451
16128
|
}
|
|
16452
|
-
|
|
16453
|
-
|
|
16454
|
-
|
|
16455
|
-
|
|
16456
|
-
|
|
16457
|
-
const frames = [];
|
|
16458
|
-
let lastFrame = -1;
|
|
16459
|
-
lines.forEach((line, at2) => {
|
|
16460
|
-
const m2 = /^\s*File "(.+)", line (\d+), in (.+)$/.exec(line);
|
|
16461
|
-
if (m2 === null) return;
|
|
16462
|
-
frames.push({ file: m2[1] ?? "", line: m2[2] ?? "", func: (m2[3] ?? "").trim() });
|
|
16463
|
-
lastFrame = at2;
|
|
16464
|
-
});
|
|
16465
|
-
if (frames.length === 0) return null;
|
|
16466
|
-
if (frames.some((f) => /[\\/]mine[\\/]steps[\\/]/.test(f.file))) return null;
|
|
16467
|
-
const at = lines.findIndex((line, n) => n > lastFrame && line !== "" && !/^\s/.test(line));
|
|
16468
|
-
if (at < 0) return null;
|
|
16469
|
-
const m = /^([A-Za-z_][\w.]*)(?::\s?(.*))?$/.exec(lines[at] ?? "");
|
|
16470
|
-
if (m === null) return null;
|
|
16471
|
-
const errorType = m[1] ?? "Error";
|
|
16472
|
-
if (/(?:^|\.)(?:KeyboardInterrupt|SystemExit|Explained|Refusal)$/.test(errorType)) return null;
|
|
16473
|
-
const message = [m[2] ?? "", ...lines.slice(at + 1)].join("\n").trim();
|
|
16474
|
-
const innermost = frames[frames.length - 1];
|
|
16475
|
-
const firstLine2 = message.split("\n")[0] ?? "";
|
|
16476
|
-
return {
|
|
16477
|
-
errorType,
|
|
16478
|
-
message,
|
|
16479
|
-
trace: block,
|
|
16480
|
-
keep: "tail",
|
|
16481
|
-
frames: frames.slice(-3).map((f) => `${basename(f.file.replace(/\\/g, "/"))}:${f.func}`),
|
|
16482
|
-
python: pythonVersionIn(frames.map((f) => f.file)),
|
|
16483
|
-
essence: `${errorType}${firstLine2 === "" ? "" : `: ${firstLine2}`}` + (innermost ? ` \u2014 ${basename(innermost.file.replace(/\\/g, "/"))}:${innermost.line}` : "")
|
|
16484
|
-
};
|
|
16129
|
+
|
|
16130
|
+
// src/setup-job.ts
|
|
16131
|
+
var SETUP_JOB_MARK = "setup-";
|
|
16132
|
+
function isSetupJob(id) {
|
|
16133
|
+
return id.startsWith(SETUP_JOB_MARK);
|
|
16485
16134
|
}
|
|
16486
|
-
|
|
16487
|
-
|
|
16488
|
-
|
|
16489
|
-
|
|
16135
|
+
var TITLE_UPDATE = human("\u041E\u0431\u043D\u043E\u0432\u043B\u044F\u044E \u0431\u0438\u0431\u043B\u0438\u043E\u0442\u0435\u043A\u0438 \u0434\u043B\u044F \u043C\u043E\u043D\u0442\u0430\u0436\u0430");
|
|
16136
|
+
var TITLE_INSTALL = human("\u0423\u0441\u0442\u0430\u043D\u0430\u0432\u043B\u0438\u0432\u0430\u044E \u0431\u0438\u0431\u043B\u0438\u043E\u0442\u0435\u043A\u0438 \u0434\u043B\u044F \u043C\u043E\u043D\u0442\u0430\u0436\u0430");
|
|
16137
|
+
var SAY_UPDATED = human("\u0413\u043E\u0442\u043E\u0432\u043E \u2014 \u043D\u043E\u0432\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u0443\u0436\u0435 \u0440\u0430\u0431\u043E\u0442\u0430\u0435\u0442.");
|
|
16138
|
+
var SAY_NOTHING = human("\u0412\u0441\u0451 \u0443\u0436\u0435 \u0441\u0442\u043E\u0438\u0442 \u2014 \u043C\u043E\u0436\u043D\u043E \u043C\u043E\u043D\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C.");
|
|
16139
|
+
var SAY_INSTALLED = human("\u0413\u043E\u0442\u043E\u0432\u043E \u2014 \u043C\u043E\u0436\u043D\u043E \u043C\u043E\u043D\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C.");
|
|
16140
|
+
var ADVICE_ASK = human("\u041D\u0430\u043F\u0438\u0448\u0438 \u041A\u043B\u043E\u0434\u0443 \xAB\u0447\u0442\u043E \u0441\u043B\u0443\u0447\u0438\u043B\u043E\u0441\u044C\xBB \u2014 \u043E\u043D \u0440\u0430\u0441\u0441\u043A\u0430\u0436\u0435\u0442, \u0447\u0442\u043E \u043F\u043E\u0448\u043B\u043E \u043D\u0435 \u0442\u0430\u043A.");
|
|
16141
|
+
var CHECK = human("\u041F\u0440\u043E\u0432\u0435\u0440\u044F\u044E, \u0447\u0442\u043E \u043E\u0431\u043D\u043E\u0432\u0438\u0442\u044C");
|
|
16142
|
+
var INSTALL_NEW = human("\u0421\u0442\u0430\u0432\u043B\u044E \u043D\u043E\u0432\u0443\u044E \u0432\u0435\u0440\u0441\u0438\u044E");
|
|
16143
|
+
var MISSING = human("\u0421\u0442\u0430\u0432\u043B\u044E \u043D\u0435\u0434\u043E\u0441\u0442\u0430\u044E\u0449\u0435\u0435");
|
|
16144
|
+
var works = /* @__PURE__ */ new Map();
|
|
16145
|
+
var JOBS_DIR = "jobs";
|
|
16146
|
+
var JOBS_KEPT2 = 10;
|
|
16147
|
+
var BEAT_MS = 1e4;
|
|
16148
|
+
var STALE_MS = 6e4;
|
|
16149
|
+
var JOB_ID = /^setup-[\w-]{1,80}$/;
|
|
16150
|
+
function running(home, clock) {
|
|
16151
|
+
for (const work of works.values()) if (work.ended === null) return work.id;
|
|
16152
|
+
if (home === null) return null;
|
|
16153
|
+
for (const record2 of records(home)) {
|
|
16154
|
+
if (record2.ended === null && alive(record2, clock)) return record2.id;
|
|
16490
16155
|
}
|
|
16491
16156
|
return null;
|
|
16492
16157
|
}
|
|
16493
|
-
function
|
|
16494
|
-
|
|
16495
|
-
let fd = null;
|
|
16158
|
+
function records(home) {
|
|
16159
|
+
let names;
|
|
16496
16160
|
try {
|
|
16497
|
-
|
|
16498
|
-
const size = fstatSync(fd).size;
|
|
16499
|
-
const length = Math.min(size, JOB_LOG_TAIL);
|
|
16500
|
-
const buffer = Buffer.alloc(length);
|
|
16501
|
-
readSync(fd, buffer, 0, length, size - length);
|
|
16502
|
-
return buffer.toString("utf8");
|
|
16161
|
+
names = readdirSync(join(home, JOBS_DIR)).filter((name) => name.endsWith(".json"));
|
|
16503
16162
|
} catch {
|
|
16504
|
-
return
|
|
16505
|
-
} finally {
|
|
16506
|
-
if (fd !== null) try {
|
|
16507
|
-
closeSync(fd);
|
|
16508
|
-
} catch {
|
|
16509
|
-
}
|
|
16510
|
-
}
|
|
16511
|
-
}
|
|
16512
|
-
function fingerprintOf2(errorType, frames) {
|
|
16513
|
-
return createHash("sha256").update([errorType, ...frames].join("|")).digest("hex").slice(0, 16);
|
|
16514
|
-
}
|
|
16515
|
-
function secretsOf(input, depth = 0, out = []) {
|
|
16516
|
-
if (out.length >= 50 || depth > 4) return out;
|
|
16517
|
-
if (typeof input === "string") out.push(input);
|
|
16518
|
-
else if (Array.isArray(input)) for (const one of input) secretsOf(one, depth + 1, out);
|
|
16519
|
-
else if (typeof input === "object" && input !== null) {
|
|
16520
|
-
for (const one of Object.values(input)) secretsOf(one, depth + 1, out);
|
|
16163
|
+
return [];
|
|
16521
16164
|
}
|
|
16522
|
-
return
|
|
16165
|
+
return names.sort().reverse().map((name) => load(home, name.slice(0, -".json".length))).filter((record2) => record2 !== null);
|
|
16523
16166
|
}
|
|
16524
|
-
function
|
|
16167
|
+
function load(home, id) {
|
|
16168
|
+
if (!JOB_ID.test(id)) return null;
|
|
16525
16169
|
try {
|
|
16526
|
-
const
|
|
16527
|
-
|
|
16528
|
-
|
|
16529
|
-
|
|
16530
|
-
|
|
16531
|
-
|
|
16532
|
-
|
|
16533
|
-
|
|
16534
|
-
|
|
16535
|
-
|
|
16170
|
+
const value = JSON.parse(readFileSync(join(home, JOBS_DIR, `${id}.json`), "utf8"));
|
|
16171
|
+
if (value.id !== id || typeof value.what !== "string" || typeof value.started !== "number" || !Array.isArray(value.stages) || typeof value.at !== "number" || typeof value.pid !== "number" || typeof value.beat !== "number") return null;
|
|
16172
|
+
return {
|
|
16173
|
+
// Запись пишет только `save` этого файла, и слова в ней те же, что в
|
|
16174
|
+
// памяти ведущего процесса, — человеку.
|
|
16175
|
+
id,
|
|
16176
|
+
what: human(value.what),
|
|
16177
|
+
started: value.started,
|
|
16178
|
+
stages: value.stages.map((one) => human(String(one))),
|
|
16179
|
+
at: value.at,
|
|
16180
|
+
message: human(typeof value.message === "string" ? value.message : ""),
|
|
16181
|
+
ended: value.ended ?? null,
|
|
16182
|
+
pid: value.pid,
|
|
16183
|
+
beat: value.beat
|
|
16184
|
+
};
|
|
16536
16185
|
} catch {
|
|
16537
|
-
return
|
|
16186
|
+
return null;
|
|
16538
16187
|
}
|
|
16539
16188
|
}
|
|
16540
|
-
function
|
|
16541
|
-
|
|
16542
|
-
|
|
16543
|
-
|
|
16544
|
-
|
|
16545
|
-
|
|
16546
|
-
|
|
16547
|
-
|
|
16548
|
-
const own = join(home, "bin", platform() === "win32" ? "ffmpeg.exe" : "ffmpeg");
|
|
16549
|
-
const program = existsSync(own) ? own : "ffmpeg";
|
|
16550
|
-
return new Promise((done) => {
|
|
16551
|
-
execFile(program, ["-version"], { timeout: 3e3, encoding: "utf8" }, (trouble, stdout) => {
|
|
16552
|
-
if (trouble !== null) return done(null);
|
|
16553
|
-
const m = /^ffmpeg version (\S+)/.exec(stdout);
|
|
16554
|
-
done(m?.[1] ?? null);
|
|
16555
|
-
});
|
|
16556
|
-
});
|
|
16189
|
+
function alive(record2, clock) {
|
|
16190
|
+
if (clock() - record2.beat > STALE_MS) return false;
|
|
16191
|
+
try {
|
|
16192
|
+
process.kill(record2.pid, 0);
|
|
16193
|
+
return true;
|
|
16194
|
+
} catch (trouble) {
|
|
16195
|
+
return trouble.code === "EPERM";
|
|
16196
|
+
}
|
|
16557
16197
|
}
|
|
16558
|
-
function
|
|
16198
|
+
function save(work, clock) {
|
|
16199
|
+
if (work.home === null) return;
|
|
16559
16200
|
try {
|
|
16560
|
-
|
|
16201
|
+
const dir = join(work.home, JOBS_DIR);
|
|
16202
|
+
mkdirSync(dir, { recursive: true });
|
|
16203
|
+
const file2 = join(dir, `${work.id}.json`);
|
|
16204
|
+
const temp = `${file2}.${process.pid}.tmp`;
|
|
16205
|
+
const record2 = {
|
|
16206
|
+
id: work.id,
|
|
16207
|
+
what: work.what,
|
|
16208
|
+
started: work.started,
|
|
16209
|
+
stages: work.stages,
|
|
16210
|
+
at: work.at,
|
|
16211
|
+
message: work.message,
|
|
16212
|
+
ended: work.ended,
|
|
16213
|
+
pid: process.pid,
|
|
16214
|
+
beat: clock()
|
|
16215
|
+
};
|
|
16216
|
+
writeFileSync(temp, JSON.stringify(record2), "utf8");
|
|
16217
|
+
renameSync(temp, file2);
|
|
16561
16218
|
} catch {
|
|
16562
|
-
return "";
|
|
16563
16219
|
}
|
|
16564
16220
|
}
|
|
16565
|
-
function
|
|
16221
|
+
function prune(home) {
|
|
16566
16222
|
try {
|
|
16567
|
-
|
|
16223
|
+
const dir = join(home, JOBS_DIR);
|
|
16224
|
+
const names = readdirSync(dir).filter((name) => JOB_ID.test(name.replace(/\.json$/, ""))).sort();
|
|
16225
|
+
for (const name of names.slice(0, Math.max(0, names.length - JOBS_KEPT2))) rmSync(join(dir, name), { force: true });
|
|
16568
16226
|
} catch {
|
|
16569
|
-
return "";
|
|
16570
16227
|
}
|
|
16571
16228
|
}
|
|
16572
|
-
function
|
|
16573
|
-
|
|
16229
|
+
function fromDisk(home, id, clock) {
|
|
16230
|
+
const record2 = load(home, id);
|
|
16231
|
+
if (record2 === null) return null;
|
|
16232
|
+
if (record2.ended !== null || alive(record2, clock)) return record2;
|
|
16233
|
+
return {
|
|
16234
|
+
...record2,
|
|
16235
|
+
ended: {
|
|
16236
|
+
at: record2.beat,
|
|
16237
|
+
ending: {
|
|
16238
|
+
ok: false,
|
|
16239
|
+
trouble: human("\u041E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0435 \u043E\u0431\u043E\u0440\u0432\u0430\u043B\u043E\u0441\u044C: \u043F\u0440\u043E\u0433\u0440\u0430\u043C\u043C\u0430, \u043A\u043E\u0442\u043E\u0440\u0430\u044F \u0435\u0433\u043E \u0432\u0435\u043B\u0430, \u0437\u0430\u043A\u0440\u044B\u043B\u0430\u0441\u044C \u043F\u043E\u0441\u0440\u0435\u0434\u0438 \u0440\u0430\u0431\u043E\u0442\u044B. \u041F\u0440\u0435\u0436\u043D\u044F\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u043D\u0430 \u043C\u0435\u0441\u0442\u0435, \u043C\u043E\u043D\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u043C\u043E\u0436\u043D\u043E."),
|
|
16240
|
+
advice: human("\u041D\u0430\u043F\u0438\u0448\u0438 \xAB\u043E\u0431\u043D\u043E\u0432\u0438\xBB \u0435\u0449\u0451 \u0440\u0430\u0437 \u2014 \u043D\u0430\u0447\u043D\u0443 \u0437\u0430\u043D\u043E\u0432\u043E."),
|
|
16241
|
+
report: forModel(`\u041F\u0440\u043E\u0446\u0435\u0441\u0441 \u043E\u0431\u043E\u043B\u043E\u0447\u043A\u0438 ${record2.pid}, \u043A\u043E\u0442\u043E\u0440\u044B\u0439 \u0432\u0451\u043B \u0437\u0430\u0434\u0430\u0447\u0443, \u043F\u0440\u043E\u043F\u0430\u043B \u043D\u0430 \u044D\u0442\u0430\u043F\u0435 \xAB${record2.stages[record2.at - 1] ?? CHECK}\xBB.`)
|
|
16242
|
+
}
|
|
16243
|
+
}
|
|
16244
|
+
};
|
|
16574
16245
|
}
|
|
16575
|
-
function
|
|
16576
|
-
|
|
16577
|
-
|
|
16578
|
-
|
|
16246
|
+
function startSetupJob(what, run, clock = Date.now, home = null) {
|
|
16247
|
+
const already = running(home, clock);
|
|
16248
|
+
if (already !== null) return already;
|
|
16249
|
+
const started = clock();
|
|
16250
|
+
const id = `${SETUP_JOB_MARK}${new Date(started).toISOString().replace(/[:.]/g, "-")}`;
|
|
16251
|
+
const work = {
|
|
16252
|
+
id,
|
|
16253
|
+
what,
|
|
16254
|
+
started,
|
|
16255
|
+
stages: [CHECK],
|
|
16256
|
+
at: 1,
|
|
16257
|
+
message: human(""),
|
|
16258
|
+
ended: null,
|
|
16259
|
+
done: Promise.resolve(),
|
|
16260
|
+
home
|
|
16261
|
+
};
|
|
16262
|
+
const control = {
|
|
16263
|
+
plan(stages) {
|
|
16264
|
+
work.stages = stages;
|
|
16265
|
+
work.at = Math.min(work.at, stages.length);
|
|
16266
|
+
save(work, clock);
|
|
16267
|
+
},
|
|
16268
|
+
go(stage) {
|
|
16269
|
+
const index = work.stages.indexOf(stage);
|
|
16270
|
+
if (index >= 0) work.at = index + 1;
|
|
16271
|
+
work.message = human("");
|
|
16272
|
+
save(work, clock);
|
|
16273
|
+
},
|
|
16274
|
+
line(text2) {
|
|
16275
|
+
work.message = text2;
|
|
16276
|
+
save(work, clock);
|
|
16277
|
+
}
|
|
16278
|
+
};
|
|
16279
|
+
works.set(id, work);
|
|
16280
|
+
if (home !== null) prune(home);
|
|
16281
|
+
save(work, clock);
|
|
16282
|
+
const beat = home === null ? null : setInterval(() => save(work, clock), BEAT_MS);
|
|
16283
|
+
beat?.unref();
|
|
16284
|
+
work.done = collectJobInstallFaults(id, () => run(control).catch((trouble) => {
|
|
16285
|
+
noteInstallFault("update-job", trouble);
|
|
16286
|
+
return {
|
|
16287
|
+
ok: false,
|
|
16288
|
+
trouble: human("\u0427\u0442\u043E-\u0442\u043E \u0441\u043B\u043E\u043C\u0430\u043B\u043E\u0441\u044C \u043F\u043E\u0441\u0440\u0435\u0434\u0438 \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u044F \u2014 \u043F\u0440\u0435\u0436\u043D\u044F\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u043D\u0430 \u043C\u0435\u0441\u0442\u0435, \u043C\u043E\u043D\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u043C\u043E\u0436\u043D\u043E."),
|
|
16289
|
+
advice: ADVICE_ASK,
|
|
16290
|
+
report: forModel(String(trouble instanceof Error ? trouble.message : trouble))
|
|
16291
|
+
};
|
|
16292
|
+
})).then((ending) => {
|
|
16293
|
+
work.ended = { at: clock(), ending };
|
|
16294
|
+
if (beat !== null) clearInterval(beat);
|
|
16295
|
+
save(work, clock);
|
|
16296
|
+
});
|
|
16297
|
+
return id;
|
|
16579
16298
|
}
|
|
16580
|
-
function
|
|
16581
|
-
|
|
16299
|
+
async function setupJobDone(id) {
|
|
16300
|
+
await works.get(id)?.done;
|
|
16582
16301
|
}
|
|
16583
|
-
|
|
16584
|
-
|
|
16585
|
-
|
|
16586
|
-
function
|
|
16587
|
-
|
|
16588
|
-
|
|
16589
|
-
|
|
16590
|
-
|
|
16591
|
-
|
|
16592
|
-
|
|
16302
|
+
function setupJobEnding(id) {
|
|
16303
|
+
return works.get(id)?.ended?.ending ?? null;
|
|
16304
|
+
}
|
|
16305
|
+
function ownSetupJobRunning() {
|
|
16306
|
+
for (const work of works.values()) if (work.ended === null) return true;
|
|
16307
|
+
return false;
|
|
16308
|
+
}
|
|
16309
|
+
function quiet(line) {
|
|
16310
|
+
return line.replace(/^⚠\s*/, "").replace(/^Что делать:/, "\u0421\u043E\u0432\u0435\u0442:");
|
|
16311
|
+
}
|
|
16312
|
+
function setupJobText(id, clock = Date.now, home = null) {
|
|
16313
|
+
const work = works.get(id) ?? (home === null ? null : fromDisk(home, id, clock));
|
|
16314
|
+
if (work === null) return null;
|
|
16315
|
+
const head2 = `\u0417\u0430\u0434\u0430\u043D\u0438\u0435 ${work.id}: ${work.what}`;
|
|
16316
|
+
if (work.ended === null) {
|
|
16317
|
+
const sec2 = Math.max(0, Math.round((clock() - work.started) / 1e3));
|
|
16318
|
+
return [
|
|
16319
|
+
head2,
|
|
16320
|
+
`\u042D\u0442\u0430\u043F ${work.at} \u0438\u0437 ${work.stages.length}: ${work.stages[work.at - 1] ?? CHECK}`,
|
|
16321
|
+
...work.message === "" ? [] : [work.message],
|
|
16322
|
+
`\u0415\u0449\u0451 \u0441\u0447\u0438\u0442\u0430\u0435\u0442, ${sec2} \u0441.`
|
|
16323
|
+
].join("\n");
|
|
16324
|
+
}
|
|
16325
|
+
const sec = Math.max(0, Math.round((work.ended.at - work.started) / 1e3));
|
|
16326
|
+
const ending = work.ended.ending;
|
|
16327
|
+
const report = ending.report.split("\n").map((line) => line.trim()).filter((line) => line !== "").map(quiet);
|
|
16328
|
+
if (ending.ok) {
|
|
16329
|
+
return [head2, `\u0413\u043E\u0442\u043E\u0432\u043E \u0437\u0430 ${sec} \u0441.`, `\u0427\u0435\u043B\u043E\u0432\u0435\u043A\u0443: ${ending.say}`, ...report].join("\n");
|
|
16330
|
+
}
|
|
16331
|
+
return [
|
|
16332
|
+
head2,
|
|
16333
|
+
...report,
|
|
16334
|
+
`\u041D\u0435 \u043F\u043E\u043B\u0443\u0447\u0438\u043B\u043E\u0441\u044C \u0437\u0430 ${sec} \u0441: ${ending.trouble}`,
|
|
16335
|
+
`\u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C: ${ending.advice}`
|
|
16336
|
+
].join("\n");
|
|
16337
|
+
}
|
|
16338
|
+
function setupJobReport(id, home = null, clock = Date.now) {
|
|
16339
|
+
const work = works.get(id) ?? (home === null ? null : fromDisk(home, id, clock));
|
|
16340
|
+
if (work === null) return null;
|
|
16341
|
+
const job = blankJob();
|
|
16342
|
+
job.id = work.id;
|
|
16343
|
+
job.what = work.what;
|
|
16344
|
+
job.at = work.at;
|
|
16345
|
+
job.total = work.stages.length;
|
|
16346
|
+
job.now = work.stages[work.at - 1] ?? CHECK;
|
|
16347
|
+
if (work.ended === null) {
|
|
16348
|
+
job.sec = Math.max(0, Math.round((clock() - work.started) / 1e3));
|
|
16349
|
+
job.message = work.message;
|
|
16350
|
+
const download = downloadOf(work.message);
|
|
16351
|
+
if (download !== null) Object.assign(job, download);
|
|
16352
|
+
return job;
|
|
16353
|
+
}
|
|
16354
|
+
const ending = work.ended.ending;
|
|
16355
|
+
job.sec = Math.max(0, Math.round((work.ended.at - work.started) / 1e3));
|
|
16356
|
+
job.outcome = ending.report;
|
|
16357
|
+
if (ending.ok) {
|
|
16358
|
+
job.status = "done";
|
|
16359
|
+
job.say = ending.say;
|
|
16360
|
+
} else {
|
|
16361
|
+
job.status = "error";
|
|
16362
|
+
job.trouble = ending.trouble;
|
|
16363
|
+
job.advice = ending.advice;
|
|
16364
|
+
}
|
|
16365
|
+
return job;
|
|
16366
|
+
}
|
|
16367
|
+
function weightExact(bytes) {
|
|
16368
|
+
const mb = bytes / 1024 / 1024;
|
|
16369
|
+
if (mb >= 1e3) return `${(mb / 1024).toFixed(1).replace(".", ",")} \u0413\u0411`;
|
|
16370
|
+
return `${mb.toFixed(1).replace(".", ",")} \u041C\u0411`;
|
|
16371
|
+
}
|
|
16372
|
+
async function runUpdate(job, deps) {
|
|
16373
|
+
const { engine, key, baseUrl, what } = deps;
|
|
16374
|
+
const home = engine.home();
|
|
16375
|
+
const wantShell = what !== "engine";
|
|
16376
|
+
const hasEngine = engine.place() !== null;
|
|
16377
|
+
const wantEngine = what !== "shell" && hasEngine && !engine.pathSetByHand();
|
|
16378
|
+
const shellUrl = engine.variable("NAPARNIK_BUNDLE_MANIFEST") ?? bundleUrlFor(baseUrl);
|
|
16379
|
+
const [shellAsk, engineAsk] = await Promise.all([
|
|
16380
|
+
wantShell ? fetchShellManifest(shellUrl, deps.pointerMs, key) : Promise.resolve(null),
|
|
16381
|
+
wantEngine ? fetchManifest(manifestUrl(engine, baseUrl), deps.pointerMs, key) : Promise.resolve(null)
|
|
16382
|
+
]);
|
|
16383
|
+
const shellWas = installedShell(home);
|
|
16384
|
+
const shell = decideShell(shellWas, shellAsk?.ok === true ? shellAsk.manifest : null);
|
|
16385
|
+
const engineWas = engine.freshVersion();
|
|
16386
|
+
const fresh = decide(engineWas, engineAsk?.ok === true ? engineAsk.manifest : null);
|
|
16387
|
+
const shellStage = shell.what === "newer_available" ? human(`\u0421\u043A\u0430\u0447\u0438\u0432\u0430\u044E \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u0435 \xB7 ${weightExact(shell.manifest.body?.bytes ?? 0)}`) : null;
|
|
16388
|
+
const engineStage = fresh.what === "newer_available" ? human(`\u0421\u043A\u0430\u0447\u0438\u0432\u0430\u044E \u0434\u0432\u0438\u0436\u043E\u043A \xB7 ${weightExact(fresh.manifest.bytes)}`) : null;
|
|
16389
|
+
const missing = what === "all";
|
|
16390
|
+
job.plan([
|
|
16391
|
+
CHECK,
|
|
16392
|
+
...shellStage === null ? [] : [shellStage],
|
|
16393
|
+
...engineStage === null ? [] : [engineStage, INSTALL_NEW],
|
|
16394
|
+
...missing ? [MISSING] : []
|
|
16395
|
+
]);
|
|
16396
|
+
const steps = [];
|
|
16397
|
+
let updated = false;
|
|
16398
|
+
let installed = false;
|
|
16399
|
+
for (const [ask2, whose] of [[shellAsk, "\u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F"], [engineAsk, "\u0434\u0432\u0438\u0436\u043A\u0430"]]) {
|
|
16400
|
+
if (ask2 === null || ask2.ok) continue;
|
|
16401
|
+
const refusal = refusalWords(ask2.status ?? 0);
|
|
16402
|
+
steps.push({
|
|
16403
|
+
report: `\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0441\u043F\u0440\u043E\u0441\u0438\u0442\u044C, \u0435\u0441\u0442\u044C \u043B\u0438 \u043D\u043E\u0432\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F ${whose}: ${ask2.why}.`,
|
|
16404
|
+
trouble: human(refusal !== "" ? refusal : "\u041D\u0435 \u043F\u043E\u043B\u0443\u0447\u0438\u043B\u043E\u0441\u044C \u0441\u0432\u044F\u0437\u0430\u0442\u044C\u0441\u044F \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u043E\u043C \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0439.")
|
|
16405
|
+
});
|
|
16593
16406
|
}
|
|
16594
|
-
|
|
16595
|
-
|
|
16596
|
-
function megabytes(value) {
|
|
16597
|
-
return typeof value === "number" && value > 0 ? Math.round(value) : 0;
|
|
16598
|
-
}
|
|
16599
|
-
function readReadiness(stdout) {
|
|
16600
|
-
const lines = stdout.trim().split("\n");
|
|
16601
|
-
let raw;
|
|
16602
|
-
try {
|
|
16603
|
-
raw = JSON.parse(lines[lines.length - 1] ?? "");
|
|
16604
|
-
} catch {
|
|
16605
|
-
return null;
|
|
16407
|
+
if (shellAsk?.ok === true && shell.what === "nothing") {
|
|
16408
|
+
steps.push({ report: `\u0423 \u0432\u0430\u0441 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u0430 \u0441\u0430\u043C\u0430\u044F \u043F\u043E\u0441\u043B\u0435\u0434\u043D\u044F\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u2014 ${shellWas}.` });
|
|
16606
16409
|
}
|
|
16607
|
-
|
|
16608
|
-
|
|
16609
|
-
|
|
16610
|
-
|
|
16611
|
-
for (const item of data["parts"]) {
|
|
16612
|
-
const part = item;
|
|
16613
|
-
if (part === null || typeof part !== "object" || typeof part["name"] !== "string") continue;
|
|
16614
|
-
parts.push({
|
|
16615
|
-
name: part["name"],
|
|
16616
|
-
title: typeof part["title"] === "string" && part["title"] !== "" ? part["title"] : part["name"],
|
|
16617
|
-
ok: part["ok"] === true,
|
|
16618
|
-
mb: megabytes(part["mb"]),
|
|
16619
|
-
on_demand: part["on_demand"] === true,
|
|
16620
|
-
step: typeof part["step"] === "string" ? part["step"] : ""
|
|
16410
|
+
if (shell.what === "launcher_too_old") {
|
|
16411
|
+
steps.push({
|
|
16412
|
+
report: `\u041D\u043E\u0432\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F ${shell.manifest.version} \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043D\u043E\u0432\u043E\u0433\u043E \u0444\u0430\u0439\u043B\u0430 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F.`,
|
|
16413
|
+
trouble: human(`\u0414\u043B\u044F \u043D\u043E\u0432\u043E\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u043D\u0443\u0436\u0435\u043D \u043D\u043E\u0432\u044B\u0439 \u0444\u0430\u0439\u043B \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F. \u0412\u043E\u0437\u044C\u043C\u0438 \u0435\u0433\u043E \u0432 \u0442\u0435\u043B\u0435\u0433\u0440\u0430\u043C-\u0431\u043E\u0442\u0435 ${KEY_SOURCE_BOT}.`)
|
|
16621
16414
|
});
|
|
16622
16415
|
}
|
|
16623
|
-
|
|
16624
|
-
|
|
16625
|
-
|
|
16626
|
-
|
|
16627
|
-
|
|
16628
|
-
|
|
16629
|
-
|
|
16630
|
-
|
|
16631
|
-
|
|
16416
|
+
if (fresh.what === "shell_too_old") {
|
|
16417
|
+
steps.push({
|
|
16418
|
+
report: `\u041D\u043E\u0432\u0430\u044F \u043D\u0430\u0447\u0438\u043D\u043A\u0430 ${fresh.manifest.version} \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F \u043D\u0435 \u0441\u0442\u0430\u0440\u0448\u0435 ${fresh.manifest.minShellVersion}.`,
|
|
16419
|
+
trouble: human("\u041D\u043E\u0432\u043E\u043C\u0443 \u0434\u0432\u0438\u0436\u043A\u0443 \u043D\u0443\u0436\u043D\u043E \u043D\u043E\u0432\u043E\u0435 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u0435 \u2014 \u0435\u0433\u043E \u043F\u043E\u043A\u0430 \u043D\u0435\u0442 \u043D\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435.")
|
|
16420
|
+
});
|
|
16421
|
+
}
|
|
16422
|
+
if (shell.what === "newer_available" && shellStage !== null) {
|
|
16423
|
+
job.go(shellStage);
|
|
16424
|
+
const outcome = await installShell({ home, manifest: shell.manifest, key: key ?? null });
|
|
16425
|
+
if (outcome.ok) {
|
|
16426
|
+
updated = true;
|
|
16427
|
+
steps.push({ report: outcome.text });
|
|
16428
|
+
} else {
|
|
16429
|
+
steps.push({ report: outcome.text, trouble: human("\u041D\u043E\u0432\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F \u043D\u0435 \u0432\u0441\u0442\u0430\u043B\u0430 \u2014 \u0440\u0430\u0431\u043E\u0442\u0430\u0435\u0442 \u043F\u0440\u0435\u0436\u043D\u044F\u044F.") });
|
|
16632
16430
|
}
|
|
16633
16431
|
}
|
|
16634
|
-
|
|
16635
|
-
|
|
16636
|
-
|
|
16637
|
-
|
|
16638
|
-
|
|
16639
|
-
|
|
16640
|
-
|
|
16641
|
-
|
|
16642
|
-
}
|
|
16643
|
-
|
|
16644
|
-
|
|
16645
|
-
|
|
16646
|
-
|
|
16647
|
-
}
|
|
16648
|
-
|
|
16649
|
-
|
|
16650
|
-
|
|
16651
|
-
|
|
16652
|
-
|
|
16432
|
+
if (fresh.what === "newer_available" && engineStage !== null) {
|
|
16433
|
+
job.go(engineStage);
|
|
16434
|
+
const outcome = await deploy(engine, fresh.manifest, void 0, key, {
|
|
16435
|
+
// Строки хода скачивания и сборки печатает движок человеку: «Скачано …».
|
|
16436
|
+
line: (text2) => job.line(human(text2)),
|
|
16437
|
+
downloaded: () => {
|
|
16438
|
+
job.go(INSTALL_NEW);
|
|
16439
|
+
job.line(human("\u0421\u043E\u0431\u0438\u0440\u0430\u044E \u043E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u0435 \u043D\u043E\u0432\u043E\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u2014 \u044D\u0442\u043E \u0434\u043E \u043F\u0430\u0440\u044B \u043C\u0438\u043D\u0443\u0442."));
|
|
16440
|
+
}
|
|
16441
|
+
});
|
|
16442
|
+
if (outcome.ok) {
|
|
16443
|
+
updated = true;
|
|
16444
|
+
steps.push({ report: outcome.text });
|
|
16445
|
+
} else {
|
|
16446
|
+
const cause = causeOf(outcome.text);
|
|
16447
|
+
steps.push({
|
|
16448
|
+
report: outcome.text,
|
|
16449
|
+
trouble: human(`\u041D\u043E\u0432\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u0434\u0432\u0438\u0436\u043A\u0430 \u043D\u0435 \u0432\u0441\u0442\u0430\u043B\u0430${cause === "" ? "" : `: ${cause}`}. \u0420\u0430\u0431\u043E\u0442\u0430\u0435\u0442 \u043F\u0440\u0435\u0436\u043D\u044F\u044F${engineWas === null ? "" : ` ${engineWas}`}, \u043C\u043E\u043D\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u043C\u043E\u0436\u043D\u043E.`)
|
|
16450
|
+
});
|
|
16451
|
+
}
|
|
16452
|
+
}
|
|
16453
|
+
if (missing) {
|
|
16454
|
+
job.go(MISSING);
|
|
16455
|
+
const step = await followEngineJob(job, deps.engine, deps.pace, deps.installMissing);
|
|
16456
|
+
if (step.trouble === void 0 && step.installed) installed = true;
|
|
16457
|
+
steps.push(step);
|
|
16458
|
+
}
|
|
16459
|
+
const report = forModel(steps.map((step) => step.report).join("\n"));
|
|
16460
|
+
const trouble = steps.find((step) => step.trouble !== void 0)?.trouble;
|
|
16461
|
+
if (trouble !== void 0) return { ok: false, trouble, advice: ADVICE_ASK, report };
|
|
16462
|
+
if (updated) return { ok: true, say: SAY_UPDATED, report };
|
|
16463
|
+
return { ok: true, say: installed ? SAY_INSTALLED : SAY_NOTHING, report };
|
|
16653
16464
|
}
|
|
16654
|
-
function
|
|
16655
|
-
|
|
16656
|
-
|
|
16657
|
-
return "";
|
|
16465
|
+
function causeOf(text2) {
|
|
16466
|
+
const line = text2.split("\n").map((one) => one.trim()).find((one) => one !== "" && !/^(Новая версия|Версия) \S+ не встала/.test(one) && !/^Что делать:/.test(one)) ?? "";
|
|
16467
|
+
const phrase = (line.split(/\.\s|\s—\s|;\s/)[0] ?? "").replace(/\s*\([^)]*\)/g, "").replace(/\.$/, "").trim();
|
|
16468
|
+
return phrase === "" ? "" : phrase[0].toLowerCase() + phrase.slice(1);
|
|
16658
16469
|
}
|
|
16659
|
-
function
|
|
16660
|
-
|
|
16661
|
-
|
|
16470
|
+
async function runHeavy(job, deps) {
|
|
16471
|
+
job.plan([deps.title]);
|
|
16472
|
+
job.go(deps.title);
|
|
16473
|
+
const step = await followEngineJob(job, deps.engine, deps.pace, deps.start);
|
|
16474
|
+
const report = forModel(step.report);
|
|
16475
|
+
if (step.trouble !== void 0) return { ok: false, trouble: step.trouble, advice: ADVICE_ASK, report };
|
|
16476
|
+
return { ok: true, say: SAY_INSTALLED, report };
|
|
16662
16477
|
}
|
|
16663
|
-
function
|
|
16664
|
-
const
|
|
16665
|
-
|
|
16666
|
-
|
|
16667
|
-
parts.push(news.mb > 0 ? `${name} \xB7 ${exactWeight(news.mb)}` : name);
|
|
16478
|
+
async function followEngineJob(job, engine, pace, start) {
|
|
16479
|
+
const answer = await start();
|
|
16480
|
+
if (answer.type === "error") {
|
|
16481
|
+
return { report: answer.error, trouble: human("\u041D\u0435 \u043F\u043E\u043B\u0443\u0447\u0438\u043B\u043E\u0441\u044C \u043F\u043E\u0441\u0442\u0430\u0432\u0438\u0442\u044C."), installed: false };
|
|
16668
16482
|
}
|
|
16669
|
-
|
|
16670
|
-
|
|
16671
|
-
|
|
16672
|
-
|
|
16673
|
-
|
|
16674
|
-
|
|
16675
|
-
|
|
16676
|
-
"
|
|
16677
|
-
|
|
16678
|
-
|
|
16679
|
-
}
|
|
16680
|
-
function cardRows(readiness) {
|
|
16681
|
-
const rows = readiness?.rows ?? (readiness?.parts ?? []).filter((part) => !NOT_A_ROW.has(part.name)).map((part) => ({
|
|
16682
|
-
title: part.title,
|
|
16683
|
-
state: part.ok ? "ok" : part.on_demand ? "later" : "missing",
|
|
16684
|
-
mb: part.ok ? 0 : part.mb
|
|
16685
|
-
}));
|
|
16686
|
-
return rows.map((row) => ({ ...row, mb: row.state === "ok" ? 0 : row.mb, say: rowWords(row.state, row.mb) }));
|
|
16687
|
-
}
|
|
16688
|
-
var FOR_MODEL = /\bsetup\b|\bwait\b|what=|consent|\bjob\b|Скажи человеку|Спроси человека|скажи ему|перескажи/i;
|
|
16689
|
-
function forHuman(line) {
|
|
16690
|
-
return FOR_MODEL.test(line) ? "" : line;
|
|
16691
|
-
}
|
|
16692
|
-
function setupCard(o) {
|
|
16693
|
-
const rows = cardRows(o.readiness);
|
|
16694
|
-
const missingMb = rows.filter((row) => row.state === "missing").reduce((all, row) => all + row.mb, 0);
|
|
16695
|
-
const ready = o.readiness === null ? false : o.readiness.rows !== null ? rows.every((row) => row.state !== "missing") : o.readiness.ready;
|
|
16696
|
-
let title;
|
|
16697
|
-
let next;
|
|
16698
|
-
if (o.noEngine || o.noPython) {
|
|
16699
|
-
title = "\u041D\u0435\u043E\u0431\u0445\u043E\u0434\u0438\u043C\u043E \u0441\u043A\u0430\u0447\u0430\u0442\u044C \u043C\u043E\u043D\u0442\u0430\u0436 \u0434\u043B\u044F \u043F\u043E\u043B\u043D\u043E\u0446\u0435\u043D\u043D\u043E\u0439 \u0440\u0430\u0431\u043E\u0442\u044B";
|
|
16700
|
-
next = `\u041D\u0430\u043F\u0438\u0448\u0438 \xAB\u0441\u043A\u0430\u0447\u0430\u0439\xBB \u2014 \u0441\u043A\u0430\u0447\u0430\u044E ${o.noEngine ? "\u043C\u043E\u043D\u0442\u0430\u0436" : "Python"}.`;
|
|
16701
|
-
} else if (o.readiness === null) {
|
|
16702
|
-
title = o.title ?? TITLE_UNKNOWN;
|
|
16703
|
-
next = forHuman(o.note ?? "");
|
|
16704
|
-
} else if (!ready) {
|
|
16705
|
-
title = missingMb ? `\u041D\u0435\u043E\u0431\u0445\u043E\u0434\u0438\u043C\u043E \u0441\u043A\u0430\u0447\u0430\u0442\u044C ${weight(missingMb)} \u0434\u043B\u044F \u043F\u043E\u043B\u043D\u043E\u0446\u0435\u043D\u043D\u043E\u0439 \u0440\u0430\u0431\u043E\u0442\u044B` : "\u041D\u0435 \u0432\u0441\u0451 \u0433\u043E\u0442\u043E\u0432\u043E \u0434\u043B\u044F \u043F\u043E\u043B\u043D\u043E\u0446\u0435\u043D\u043D\u043E\u0439 \u0440\u0430\u0431\u043E\u0442\u044B";
|
|
16706
|
-
next = missingMb ? `\u041D\u0430\u043F\u0438\u0448\u0438 \xAB\u0441\u043A\u0430\u0447\u0430\u0439\xBB \u2014 \u0441\u043A\u0430\u0447\u0430\u044E ${weight(missingMb)}.` : "\u041D\u0430\u043F\u0438\u0448\u0438 \xAB\u0441\u043A\u0430\u0447\u0430\u0439\xBB \u2014 \u043F\u043E\u0441\u0442\u0430\u0432\u043B\u044E, \u0447\u0435\u0433\u043E \u043D\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442.";
|
|
16707
|
-
} else {
|
|
16708
|
-
title = TITLE_READY;
|
|
16709
|
-
next = "";
|
|
16483
|
+
const words = typeof answer.content === "string" ? answer.content : answer.content.map((block) => block.type === "text" ? block.text : "").join("\n");
|
|
16484
|
+
const id = typeof answer.structured?.["id"] === "string" ? answer.structured["id"] : "";
|
|
16485
|
+
if (id === "") return { report: words, installed: false };
|
|
16486
|
+
const rest = pace ?? realPace;
|
|
16487
|
+
let state = await engine.command(["job", id]);
|
|
16488
|
+
while (state.ok && stillWorking(state.text)) {
|
|
16489
|
+
const now = readJob(state.text);
|
|
16490
|
+
if (now !== null) job.line(now.message !== "" ? now.message : now.now);
|
|
16491
|
+
await rest.rest(POLL_EVERY_MS);
|
|
16492
|
+
state = await engine.command(["job", id]);
|
|
16710
16493
|
}
|
|
16711
|
-
|
|
16712
|
-
|
|
16713
|
-
|
|
16714
|
-
|
|
16715
|
-
|
|
16716
|
-
|
|
16717
|
-
|
|
16718
|
-
|
|
16719
|
-
|
|
16720
|
-
|
|
16721
|
-
}
|
|
16494
|
+
const end = state.ok ? readJob(state.text) : null;
|
|
16495
|
+
if (end === null || end.status !== "done") {
|
|
16496
|
+
return {
|
|
16497
|
+
report: `${words}
|
|
16498
|
+
${state.text}`,
|
|
16499
|
+
// Беда задачи движка — слова человеку от самого движка (строка «Не
|
|
16500
|
+
// получилось …» его задания), их и отдаём в окно.
|
|
16501
|
+
trouble: human(end?.trouble !== void 0 && end.trouble !== "" ? end.trouble : "\u041D\u0435 \u043F\u043E\u043B\u0443\u0447\u0438\u043B\u043E\u0441\u044C \u043F\u043E\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u043D\u0435\u0434\u043E\u0441\u0442\u0430\u044E\u0449\u0435\u0435."),
|
|
16502
|
+
installed: false
|
|
16503
|
+
};
|
|
16504
|
+
}
|
|
16505
|
+
return { report: `${words}
|
|
16506
|
+
${state.text}`, installed: true };
|
|
16722
16507
|
}
|
|
16723
16508
|
var WIDGET_MIME = "text/html;profile=mcp-app";
|
|
16724
16509
|
function widgetStamp(html) {
|
|
@@ -17403,8 +17188,10 @@ function runbarWidgetHtml() {
|
|
|
17403
17188
|
var box = byId('dl');
|
|
17404
17189
|
if (!box) return false;
|
|
17405
17190
|
var got = Number(data.got) || 0;
|
|
17406
|
-
if (!got) { box.hidden = true; return false; }
|
|
17407
17191
|
var of = Number(data.of) || 0;
|
|
17192
|
+
// \u041D\u043E\u043B\u044C \u0438\u0437 \u0438\u0437\u0432\u0435\u0441\u0442\u043D\u043E\u0433\u043E \u0446\u0435\u043B\u043E\u0433\u043E \u2014 \u0443\u0436\u0435 \u0448\u043A\u0430\u043B\u0430: \xAB0 \u0438\u0437 450 \u041C\u0411 \xB7 0%\xBB \u0433\u043E\u0432\u043E\u0440\u0438\u0442, \u0441\u043A\u043E\u043B\u044C\u043A\u043E
|
|
17193
|
+
// \u043F\u0440\u0435\u0434\u0441\u0442\u043E\u0438\u0442, \u0430 \u0441\u0442\u0440\u043E\u043A\u0430 \xAB\u0421\u043A\u0430\u0447\u0430\u043D\u043E 0 \u041C\u0411\xBB \u043F\u043B\u0430\u0448\u043A\u043E\u0439 \u0447\u0438\u0442\u0430\u043B\u0430\u0441\u044C \u0431\u044B \u043A\u0430\u043A \u043F\u043E\u043B\u043E\u043C\u043A\u0430.
|
|
17194
|
+
if (!got && !of) { box.hidden = true; return false; }
|
|
17408
17195
|
byId('dlMeter').hidden = !of;
|
|
17409
17196
|
fill('dlFill', of ? data.percent : 0);
|
|
17410
17197
|
var cap = byId('dlCap');
|
|
@@ -17655,985 +17442,1118 @@ function runbarWidgetHtml() {
|
|
|
17655
17442
|
</html>`;
|
|
17656
17443
|
}
|
|
17657
17444
|
|
|
17658
|
-
// src/tool
|
|
17659
|
-
|
|
17660
|
-
|
|
17661
|
-
|
|
17662
|
-
|
|
17663
|
-
|
|
17664
|
-
|
|
17665
|
-
}
|
|
17666
|
-
|
|
17667
|
-
|
|
17668
|
-
|
|
17669
|
-
|
|
17670
|
-
|
|
17671
|
-
|
|
17672
|
-
|
|
17673
|
-
|
|
17674
|
-
|
|
17675
|
-
|
|
17676
|
-
|
|
17677
|
-
|
|
17678
|
-
|
|
17679
|
-
|
|
17680
|
-
}
|
|
17681
|
-
|
|
17682
|
-
|
|
17683
|
-
|
|
17684
|
-
cutout: "\u0432\u044B\u0440\u0435\u0437 \u0433\u0435\u0440\u043E\u044F",
|
|
17685
|
-
voice: "\u0447\u0438\u0441\u0442\u043A\u0430 \u0433\u043E\u043B\u043E\u0441\u0430"
|
|
17686
|
-
};
|
|
17687
|
-
var KNOB_KIND = {
|
|
17688
|
-
file: "\u0444\u0430\u0439\u043B",
|
|
17689
|
-
string: "\u0441\u0442\u0440\u043E\u043A\u0430",
|
|
17690
|
-
number: "\u0447\u0438\u0441\u043B\u043E",
|
|
17691
|
-
"yes-no": "\u0434\u0430/\u043D\u0435\u0442"
|
|
17692
|
-
};
|
|
17693
|
-
var FROM_MINE = "mine";
|
|
17694
|
-
function catalogInWords(data) {
|
|
17695
|
-
const lines = [];
|
|
17696
|
-
const version2 = data.engine?.version;
|
|
17697
|
-
lines.push(`\u0427\u0442\u043E \u0443\u043C\u0435\u0435\u0442 \u043C\u043E\u043D\u0442\u0430\u0436 \u043D\u0430 \u044D\u0442\u043E\u043C \u043A\u043E\u043C\u043F\u044C\u044E\u0442\u0435\u0440\u0435${version2 !== void 0 ? `. \u0414\u0432\u0438\u0436\u043E\u043A ${version2}` : ""}.`);
|
|
17698
|
-
const steps = data.steps ?? [];
|
|
17699
|
-
const ready = steps.filter((s) => s.ready !== false);
|
|
17700
|
-
const later = steps.filter((s) => s.ready === false);
|
|
17701
|
-
if (ready.length > 0) {
|
|
17702
|
-
lines.push(`\u0423\u0436\u0435 \u0441\u0442\u043E\u0438\u0442: ${ready.map((s) => `${s.title} (${s.name})`).join(", ")}.`);
|
|
17703
|
-
}
|
|
17704
|
-
if (later.length > 0) {
|
|
17705
|
-
const said = later.map((s) => {
|
|
17706
|
-
const work = (s.needs ?? []).map((n) => HEAVY_WORK[n] ?? n).join(" \u0438 ");
|
|
17707
|
-
const step = (s.needs ?? [])[0];
|
|
17708
|
-
return `${s.title} (${s.name}) \u2014 ${work}${step !== void 0 ? ` (setup what="${step}")` : ""}`;
|
|
17709
|
-
}).join("; ");
|
|
17710
|
-
lines.push(
|
|
17711
|
-
`\u0414\u043E\u043A\u0430\u0447\u0430\u0435\u0442\u0441\u044F \u043F\u0435\u0440\u0435\u0434 \u043F\u0435\u0440\u0432\u044B\u043C \u043C\u043E\u043D\u0442\u0430\u0436\u043E\u043C, \u0441\u043F\u0440\u043E\u0441\u0438 \u0441\u043E\u0433\u043B\u0430\u0441\u0438\u0435 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430: ${said}.`
|
|
17712
|
-
);
|
|
17713
|
-
}
|
|
17714
|
-
const recipes = data.recipes ?? [];
|
|
17715
|
-
if (recipes.length > 0) {
|
|
17716
|
-
lines.push(`\u0413\u043E\u0442\u043E\u0432\u044B\u0435 \u043D\u0430\u0431\u043E\u0440\u044B \u0448\u0430\u0433\u043E\u0432: ${recipes.map((r) => `${r.title} (${r.name})`).join(", ")}.`);
|
|
17445
|
+
// src/setup-tool.ts
|
|
17446
|
+
var ASKED_POINTER_MS = 15e3;
|
|
17447
|
+
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.";
|
|
17448
|
+
async function inspectMachine(engine, asked) {
|
|
17449
|
+
const video = asked.video;
|
|
17450
|
+
const model = asked.model;
|
|
17451
|
+
const place = engine.place();
|
|
17452
|
+
if (place === null) return { result: toolError(engine.whyNoEngine()), readiness: null };
|
|
17453
|
+
const args = [
|
|
17454
|
+
"env-check",
|
|
17455
|
+
"--pack",
|
|
17456
|
+
place.pack,
|
|
17457
|
+
...video !== void 0 ? ["--video", path(video)] : [],
|
|
17458
|
+
...model !== void 0 ? ["--model", model] : []
|
|
17459
|
+
];
|
|
17460
|
+
let readiness = null;
|
|
17461
|
+
let words;
|
|
17462
|
+
if (knowsJsonCheck(place.engine)) {
|
|
17463
|
+
const answer = await askReadiness(engine, place, args);
|
|
17464
|
+
if ("ok" in answer && !answer.ok) return { result: toolError(answer.text), readiness: null };
|
|
17465
|
+
if ("parts" in answer) readiness = answer;
|
|
17466
|
+
words = "parts" in answer ? answer.words : answer.text;
|
|
17467
|
+
} else {
|
|
17468
|
+
const outcome = await engine.command(args);
|
|
17469
|
+
if (!outcome.ok) return { result: toolError(outcome.text), readiness: null };
|
|
17470
|
+
words = outcome.text;
|
|
17717
17471
|
}
|
|
17718
|
-
const
|
|
17719
|
-
|
|
17720
|
-
|
|
17721
|
-
|
|
17722
|
-
|
|
17472
|
+
const catalog = await askCatalog(engine, place.pack, video);
|
|
17473
|
+
return { result: toolSuccess(`${words}
|
|
17474
|
+
|
|
17475
|
+
${catalog}`), readiness };
|
|
17476
|
+
}
|
|
17477
|
+
async function askReadiness(engine, place, args) {
|
|
17478
|
+
const python = await engine.pythonTrouble();
|
|
17479
|
+
if (python !== null) return { ok: false, text: python };
|
|
17480
|
+
let stdout;
|
|
17481
|
+
try {
|
|
17482
|
+
stdout = (await engine.run(place, [...args, JSON_CHECK])).stdout;
|
|
17483
|
+
} catch (err) {
|
|
17484
|
+
const e = err;
|
|
17485
|
+
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");
|
|
17486
|
+
stdout = e.stdout;
|
|
17723
17487
|
}
|
|
17724
|
-
|
|
17725
|
-
|
|
17726
|
-
|
|
17727
|
-
|
|
17728
|
-
|
|
17729
|
-
|
|
17730
|
-
|
|
17731
|
-
);
|
|
17732
|
-
|
|
17733
|
-
|
|
17734
|
-
|
|
17735
|
-
|
|
17736
|
-
|
|
17737
|
-
|
|
17488
|
+
return readReadiness(stdout) ?? { ok: true, text: stdout.trim() };
|
|
17489
|
+
}
|
|
17490
|
+
async function installStep(engine, asked, key, baseUrl, tell) {
|
|
17491
|
+
const step = asked.step;
|
|
17492
|
+
const model = asked.model;
|
|
17493
|
+
const consent = asked.consent;
|
|
17494
|
+
if (engine.place() === null) {
|
|
17495
|
+
let candidate = readCandidate(engine.versionsDir());
|
|
17496
|
+
if (candidate === null) {
|
|
17497
|
+
if (tell !== void 0) for (const line of PAYLOAD_LADDER) tell(line);
|
|
17498
|
+
const result = await installPayload(engine, {
|
|
17499
|
+
consent,
|
|
17500
|
+
manifestUrl: manifestUrl(engine, baseUrl),
|
|
17501
|
+
...key !== void 0 ? { key } : {}
|
|
17502
|
+
});
|
|
17503
|
+
if (!result.ok) return toolError(result.text);
|
|
17504
|
+
candidate = readCandidate(engine.versionsDir());
|
|
17505
|
+
if (candidate === null) {
|
|
17506
|
+
return toolError("\u041D\u0430\u0447\u0438\u043D\u043A\u0430 \u0441\u043A\u0430\u0447\u0430\u043B\u0430\u0441\u044C \u0431\u0435\u0437 \u0443\u043A\u0430\u0437\u0430\u0442\u0435\u043B\u044F \u043A\u0430\u043D\u0434\u0438\u0434\u0430\u0442\u0430 \u2014 current \u043D\u0435 \u043C\u0435\u043D\u044F\u043B. \u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C: \u043F\u043E\u0432\u0442\u043E\u0440\u0438\u0442\u0435 setup.");
|
|
17738
17507
|
}
|
|
17739
|
-
|
|
17740
|
-
|
|
17741
|
-
|
|
17742
|
-
|
|
17743
|
-
|
|
17744
|
-
|
|
17508
|
+
}
|
|
17509
|
+
if (!consent) {
|
|
17510
|
+
return toolError(
|
|
17511
|
+
`\u041A\u0430\u043D\u0434\u0438\u0434\u0430\u0442 ${candidate.version} \u0443\u0436\u0435 \u043F\u043E\u0434\u0433\u043E\u0442\u043E\u0432\u043B\u0435\u043D, \u043D\u043E \u0435\u0449\u0451 \u043D\u0435 \u0440\u0430\u0431\u043E\u0447\u0438\u0439. \u0421\u043F\u0440\u043E\u0441\u0438 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043D\u0438\u0435 \u0441\u043E\u0431\u0440\u0430\u0442\u044C \u0435\u0433\u043E \u043E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u0435 \u0438 \u043F\u043E\u0437\u043E\u0432\u0438 install \u0441 what=all.`
|
|
17512
|
+
);
|
|
17513
|
+
}
|
|
17514
|
+
const extras = step === "all" ? "later" : "now";
|
|
17515
|
+
const activated = await continuePreparedCandidate(engine, candidate, void 0, extras);
|
|
17516
|
+
if (!activated.ok) return toolError(activated.text);
|
|
17517
|
+
engine.forgetPython();
|
|
17518
|
+
if (step === "python") return toolSuccess(activated.text);
|
|
17519
|
+
if (step === "all") {
|
|
17520
|
+
const ready = `${activated.text}
|
|
17521
|
+
\u041A\u0430\u043D\u0434\u0438\u0434\u0430\u0442 \u043F\u043E\u0441\u0442\u0430\u0432\u0438\u043B \u0431\u0438\u0431\u043B\u0438\u043E\u0442\u0435\u043A\u0438 \u043F\u043E \u0441\u0432\u043E\u0435\u043C\u0443 \u0437\u0430\u043C\u043A\u0443 \u0438 \u043F\u0440\u043E\u0448\u0451\u043B env-check. \u0412\u0441\u0451 \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u043E\u0435 \u0433\u043E\u0442\u043E\u0432\u043E.`;
|
|
17522
|
+
const later = await installStep(engine, asked, key, baseUrl, tell);
|
|
17523
|
+
if (later.type === "error") {
|
|
17524
|
+
return toolSuccess(
|
|
17525
|
+
`${ready}
|
|
17526
|
+
|
|
17527
|
+
\u041E\u0441\u0442\u0430\u043B\u044C\u043D\u043E\u0435 \u0444\u043E\u043D\u043E\u043C \u0437\u0430\u0432\u0435\u0441\u0442\u0438 \u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C: ${later.error}
|
|
17528
|
+
\u041C\u043E\u043D\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u044D\u0442\u043E \u043D\u0435 \u043C\u0435\u0448\u0430\u0435\u0442. \u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C: \u043F\u043E\u0437\u043E\u0432\u0438 install \u0441 what=all \u0435\u0449\u0451 \u0440\u0430\u0437.`
|
|
17529
|
+
);
|
|
17530
|
+
}
|
|
17531
|
+
return together([toolSuccess(`${ready}
|
|
17532
|
+
${EXTRAS_LATER}`), later]);
|
|
17745
17533
|
}
|
|
17746
17534
|
}
|
|
17747
|
-
const
|
|
17748
|
-
if (
|
|
17749
|
-
|
|
17750
|
-
|
|
17751
|
-
|
|
17752
|
-
|
|
17753
|
-
|
|
17754
|
-
|
|
17755
|
-
${index.trim()}`);
|
|
17756
|
-
}
|
|
17757
|
-
const style = data.style;
|
|
17758
|
-
if (style?.name !== void 0) {
|
|
17759
|
-
lines.push(
|
|
17760
|
-
style.own === true ? `\u0421\u0442\u0438\u043B\u044C: \u0441\u0432\u043E\u0439 \u043F\u0430\u043A \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430 \xAB${style.name}\xBB \u2014 \u0432\u044B\u0431\u0440\u0430\u043D\u043D\u043E\u0435 \u0437\u0430\u043F\u043E\u043C\u0438\u043D\u0430\u0435\u0442\u0441\u044F \u0432 \u043D\u0435\u0433\u043E.` : `\u0421\u0442\u0438\u043B\u044C: \u0432\u0441\u0442\u0440\u043E\u0435\u043D\u043D\u044B\u0439 \xAB${style.name}\xBB, \u0441\u0432\u043E\u0435\u0433\u043E \u043F\u0430\u043A\u0430 \u0443 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430 \u0435\u0449\u0451 \u043D\u0435\u0442.`
|
|
17761
|
-
);
|
|
17762
|
-
}
|
|
17763
|
-
const mine = data.mine?.summary ?? [];
|
|
17764
|
-
if (mine.length > 0) {
|
|
17765
|
-
lines.push(`\u0421\u0432\u043E\u0451 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430 (\u0437\u0430\u043F\u043E\u043C\u043D\u0435\u043D\u043E, \u0443\u0436\u0435 \u0432 \u043A\u0430\u0436\u0434\u043E\u043C \u0447\u0435\u0440\u043D\u043E\u0432\u0438\u043A\u0435; \xAB\u0437\u0430\u0431\u0443\u0434\u044C\xBB \u2014 plan_edit forget):
|
|
17766
|
-
${mine.map((line) => `\u2014 ${line}`).join("\n")}`);
|
|
17535
|
+
const place = engine.place();
|
|
17536
|
+
if (place === null) return toolError(engine.whyNoEngine());
|
|
17537
|
+
if (consent && await engine.pythonTrouble() !== null) {
|
|
17538
|
+
try {
|
|
17539
|
+
await engine.bringPython(place);
|
|
17540
|
+
} catch (trouble) {
|
|
17541
|
+
return toolError(`\u041F\u0438\u0442\u043E\u043D \u043C\u043E\u043D\u0442\u0430\u0436\u0430 \u043F\u043E\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C: ${describeFailure(trouble)}. \u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C: \u043F\u043E\u0432\u0442\u043E\u0440\u0438 setup.`);
|
|
17542
|
+
}
|
|
17767
17543
|
}
|
|
17768
|
-
|
|
17769
|
-
return lines.join("\n");
|
|
17770
|
-
}
|
|
17771
|
-
function otherContract(said, expected) {
|
|
17772
|
-
return `\u0414\u0432\u0438\u0436\u043E\u043A \u0433\u043E\u0432\u043E\u0440\u0438\u0442 \u043D\u0430 \u0434\u043E\u0433\u043E\u0432\u043E\u0440\u0435 \xAB${String(said)}\xBB, \u0430 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u0435 \u043F\u043E\u043D\u0438\u043C\u0430\u0435\u0442 \xAB${expected}\xBB. \u041E\u0431\u043D\u043E\u0432\u0438 \u0442\u043E, \u0447\u0442\u043E \u0441\u0442\u0430\u0440\u0435\u0435: setup \u0441 what=engine \u0434\u043B\u044F \u0434\u0432\u0438\u0436\u043A\u0430, what=shell \u0434\u043B\u044F \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F.`;
|
|
17773
|
-
}
|
|
17774
|
-
async function askCatalog(engine, pack, video) {
|
|
17775
|
-
const answer = await engine.command([
|
|
17776
|
-
"capabilities",
|
|
17544
|
+
const common = [
|
|
17777
17545
|
"--pack",
|
|
17778
|
-
pack,
|
|
17779
|
-
|
|
17780
|
-
|
|
17781
|
-
|
|
17782
|
-
|
|
17783
|
-
|
|
17784
|
-
|
|
17785
|
-
|
|
17786
|
-
|
|
17546
|
+
place.pack,
|
|
17547
|
+
"--step",
|
|
17548
|
+
step,
|
|
17549
|
+
...model !== void 0 ? ["--model", model] : [],
|
|
17550
|
+
...consent ? ["--consent"] : []
|
|
17551
|
+
];
|
|
17552
|
+
if (!LONG_STEPS.has(step)) return asToolResult(await engine.command(["env-install", ...common]));
|
|
17553
|
+
const python = await engine.pythonTrouble();
|
|
17554
|
+
if (python !== null) return toolError(python);
|
|
17555
|
+
if (tell !== void 0) for (const line of installLadder(step)) tell(line);
|
|
17556
|
+
const launch = await engine.background({
|
|
17557
|
+
place,
|
|
17558
|
+
executable: engine.enginePython(),
|
|
17559
|
+
// Установка берёт тот же слот тяжёлой работы, а на слоте стоит заслон
|
|
17560
|
+
// подписки в самом движке — без ключа она откажет платящему.
|
|
17561
|
+
key,
|
|
17562
|
+
startJob: [
|
|
17563
|
+
"install-create",
|
|
17564
|
+
"--pack",
|
|
17565
|
+
place.pack,
|
|
17566
|
+
"--step",
|
|
17567
|
+
step,
|
|
17568
|
+
...model !== void 0 ? ["--model", model] : []
|
|
17569
|
+
],
|
|
17570
|
+
args: (id) => [place.consolePy, "env-install", ...common, "--job", id],
|
|
17571
|
+
advice: "\u043F\u043E\u0437\u043E\u0432\u0438 setup \u2014 \u0441\u043A\u043E\u0440\u0435\u0435 \u0432\u0441\u0435\u0433\u043E, \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0430 \u043D\u0435\u043F\u043E\u043B\u043D\u0430\u044F"
|
|
17572
|
+
});
|
|
17573
|
+
if ("refusal" in launch) return toolError(launch.refusal);
|
|
17574
|
+
return toolSuccess(
|
|
17575
|
+
`\u0417\u0430\u0434\u0430\u0447\u0430 ${launch.id}: ${installTitle(step)} (\u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0430, \u0448\u0430\u0433 \xAB${step}\xBB).
|
|
17576
|
+
\u0418\u0434\u0451\u0442 \u043D\u0430 \u043A\u043E\u043C\u043F\u044C\u044E\u0442\u0435\u0440\u0435 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F \u0438 \u043F\u0435\u0440\u0435\u0436\u0438\u0432\u0430\u0435\u0442 \u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u043A \u043F\u0440\u043E\u0433\u0440\u0430\u043C\u043C\u044B. \u041F\u043E\u0437\u043E\u0432\u0438 wait \u0441 job "${launch.id}" \u2014 \u043E\u043D \u043F\u043E\u0434\u043E\u0436\u0434\u0451\u0442 \u0438 \u043F\u043E \u0445\u043E\u0434\u0443 \u0440\u0430\u0441\u0441\u043A\u0430\u0436\u0435\u0442, \u0441\u043A\u043E\u043B\u044C\u043A\u043E \u0441\u043A\u0430\u0447\u0430\u043D\u043E \u0438 \u043E \u0447\u0451\u043C \u043D\u0430\u0434\u043E \u0441\u043F\u0440\u043E\u0441\u0438\u0442\u044C \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430. \u041F\u0435\u0440\u0435\u0441\u043A\u0430\u0437\u044B\u0432\u0430\u0439 \u044D\u0442\u043E \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0443 \u0441\u0440\u0430\u0437\u0443, \u0430 \u043D\u0435 \u0432 \u043A\u043E\u043D\u0446\u0435. ${AWAY_NOTE}`,
|
|
17577
|
+
startedJob({
|
|
17578
|
+
id: launch.id,
|
|
17579
|
+
what: installTitle(step),
|
|
17580
|
+
ahead: human(installLadder(step).join(" ")),
|
|
17581
|
+
message: human("\u0418\u0434\u0451\u0442 \u043C\u0438\u043D\u0443\u0442\u0430\u043C\u0438: \u043A\u0430\u0447\u0430\u0435\u0442\u0441\u044F \u0438 \u0441\u043E\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044F \u0442\u043E, \u0447\u0435\u043C \u043C\u043E\u043D\u0442\u0438\u0440\u0443\u0435\u0442\u0441\u044F \u0432\u0438\u0434\u0435\u043E.")
|
|
17582
|
+
})
|
|
17583
|
+
);
|
|
17584
|
+
}
|
|
17585
|
+
async function updateEngine(engine, key, baseUrl, timeoutMs = ASKED_POINTER_MS) {
|
|
17586
|
+
if (engine.pathSetByHand()) {
|
|
17587
|
+
return toolSuccess(
|
|
17588
|
+
"\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."
|
|
17589
|
+
);
|
|
17787
17590
|
}
|
|
17788
|
-
if (
|
|
17789
|
-
return
|
|
17591
|
+
if (engine.place() === null) {
|
|
17592
|
+
return toolSuccess(
|
|
17593
|
+
"\u0414\u0432\u0438\u0436\u043A\u0430 \u043C\u043E\u043D\u0442\u0430\u0436\u0430 \u043D\u0430 \u044D\u0442\u043E\u043C \u043A\u043E\u043C\u043F\u044C\u044E\u0442\u0435\u0440\u0435 \u0435\u0449\u0451 \u043D\u0435\u0442 \u2014 \u043E\u0431\u043D\u043E\u0432\u043B\u044F\u0442\u044C \u043D\u0435\u0447\u0435\u0433\u043E.\n\u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C: \u043F\u043E\u0437\u043E\u0432\u0438 install \u0441 what=all, \u043E\u043D \u0441\u043A\u0430\u0447\u0430\u0435\u0442 \u043D\u0430\u0447\u0438\u043D\u043A\u0443 \u0441 \u043D\u0443\u043B\u044F (\u0441\u043A\u0430\u0447\u0438\u0432\u0430\u043D\u0438\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0441\u043E\u0433\u043B\u0430\u0441\u0438\u044F \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430)."
|
|
17594
|
+
);
|
|
17790
17595
|
}
|
|
17791
|
-
|
|
17792
|
-
|
|
17793
|
-
|
|
17794
|
-
|
|
17795
|
-
|
|
17796
|
-
|
|
17797
|
-
|
|
17798
|
-
return { refusal: NOT_JSON };
|
|
17596
|
+
const outcome = await fetchManifest(manifestUrl(engine, baseUrl), timeoutMs, key);
|
|
17597
|
+
const decision = decide(engine.freshVersion(), outcome.ok ? outcome.manifest : null);
|
|
17598
|
+
if (decision.what === "nothing") {
|
|
17599
|
+
const ownDir2 = engine.freshVersion();
|
|
17600
|
+
return toolSuccess(
|
|
17601
|
+
!outcome.ok ? `\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0441\u043F\u0440\u043E\u0441\u0438\u0442\u044C, \u0435\u0441\u0442\u044C \u043B\u0438 \u043D\u043E\u0432\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u043D\u0430\u0447\u0438\u043D\u043A\u0438: ${outcome.why}. \u042D\u0442\u043E \u043D\u0435 \u043F\u043E\u043B\u043E\u043C\u043A\u0430: \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u043D\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F (${ownDir2 ?? "\u043D\u0435 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u0430"}) \u0440\u0430\u0431\u043E\u0442\u0430\u0435\u0442 \u043A\u0430\u043A \u0440\u0430\u0431\u043E\u0442\u0430\u043B\u0430.` : `\u041D\u0430\u0447\u0438\u043D\u043A\u0430 \u0441\u0432\u0435\u0436\u0430\u044F: \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u0430 ${ownDir2 ?? "\u043D\u0435\u0442"}, \u043D\u043E\u0432\u0435\u0435 \u043D\u0435 \u0432\u044B\u0448\u043B\u043E.`
|
|
17602
|
+
);
|
|
17799
17603
|
}
|
|
17800
|
-
if (
|
|
17801
|
-
return
|
|
17604
|
+
if (decision.what === "shell_too_old") {
|
|
17605
|
+
return toolSuccess(
|
|
17606
|
+
`\u041D\u043E\u0432\u0430\u044F \u043D\u0430\u0447\u0438\u043D\u043A\u0430 ${decision.manifest.version} \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F \u043D\u0435 \u0441\u0442\u0430\u0440\u0448\u0435 ${decision.manifest.minShellVersion}, \u0430 \u0441\u0442\u043E\u0438\u0442 ${VERSION}. \u0421\u043A\u0430\u0436\u0438 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0443, \u0447\u0442\u043E \u0441\u043D\u0430\u0447\u0430\u043B\u0430 \u043D\u0430\u0434\u043E \u043E\u0431\u043D\u043E\u0432\u0438\u0442\u044C \u0441\u0430\u043C\u043E \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u0435 \u041D\u0430\u043F\u0430\u0440\u043D\u0438\u043A\u0430, \u0438 \u0442\u043E\u043B\u044C\u043A\u043E \u043F\u043E\u0442\u043E\u043C \u043D\u0430\u0447\u0438\u043D\u043A\u0443. \u0421\u0442\u0430\u0432\u0438\u0442\u044C \u043D\u0435 \u0441\u0442\u0430\u043B.`
|
|
17607
|
+
);
|
|
17802
17608
|
}
|
|
17803
|
-
|
|
17804
|
-
return { words: data.words, data };
|
|
17609
|
+
return asToolResult(await deploy(engine, decision.manifest, void 0, key));
|
|
17805
17610
|
}
|
|
17806
|
-
function
|
|
17807
|
-
|
|
17808
|
-
|
|
17611
|
+
function setupTool(engine, passport, key, baseUrl) {
|
|
17612
|
+
return defineTool({
|
|
17613
|
+
name: "setup",
|
|
17614
|
+
title: "\u041F\u0440\u043E\u0432\u0435\u0440\u0438\u0442\u044C, \u0432\u0441\u0451 \u043B\u0438 \u0433\u043E\u0442\u043E\u0432\u043E \u0434\u043B\u044F \u043C\u043E\u043D\u0442\u0430\u0436\u0430",
|
|
17615
|
+
description: "\u041F\u0440\u043E\u0432\u0435\u0440\u044F\u0435\u0442 \u0434\u0435\u043B\u043E\u043C, \u0447\u0442\u043E \u0441\u0442\u043E\u0438\u0442 \u0438 \u0447\u0435\u0433\u043E \u043D\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442, \u0447\u0442\u043E \u0434\u043E\u043A\u0430\u0447\u0430\u0435\u0442\u0441\u044F \u043F\u043E \u043F\u0440\u043E\u0441\u044C\u0431\u0435 \u0438 \u0441\u043A\u043E\u043B\u044C\u043A\u043E \u0432\u0435\u0441\u0438\u0442, \u0438 \u0447\u0442\u043E \u0443\u043C\u0435\u0435\u0442 \u043C\u043E\u043D\u0442\u0430\u0436 (\u0448\u0430\u0433\u0438, \u0432\u043E\u043F\u0440\u043E\u0441\u044B \u0434\u043B\u044F choose_variant, \u0447\u0435\u0439 \u0441\u0442\u0438\u043B\u044C). \u0417\u043E\u0432\u0438 \u041F\u0415\u0420\u0412\u042B\u041C, \u0434\u043E \u0440\u0430\u0431\u043E\u0442\u044B \u0441 \u0432\u0438\u0434\u0435\u043E. \u0421\u0442\u0430\u0432\u0438\u0442 install. \u0421\u043B\u043E\u043C\u0430\u043B\u043E\u0441\u044C \u043F\u043E\u0441\u043B\u0435 \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u044F \u2014 rollback.",
|
|
17616
|
+
args: external_exports.object({
|
|
17617
|
+
model: fromList(
|
|
17618
|
+
passport?.["models"],
|
|
17619
|
+
`\u041C\u043E\u0434\u0435\u043B\u044C \u0440\u0430\u0441\u043F\u043E\u0437\u043D\u0430\u0432\u0430\u043D\u0438\u044F \u0440\u0435\u0447\u0438, \u043A\u0430\u043A\u0443\u044E \u043F\u0440\u043E\u0432\u0435\u0440\u0438\u0442\u044C. ${aboutModels(passport)}`
|
|
17620
|
+
).optional(),
|
|
17621
|
+
rollback: external_exports.enum(["engine", "shell"]).describe(
|
|
17622
|
+
"\u0412\u0435\u0440\u043D\u0443\u0442\u044C \u043F\u0440\u0435\u0436\u043D\u044E\u044E \u0432\u0435\u0440\u0441\u0438\u044E: engine \u2014 \u0434\u0432\u0438\u0436\u043E\u043A, shell \u2014 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u0435"
|
|
17623
|
+
).optional()
|
|
17624
|
+
}),
|
|
17625
|
+
async execute(args) {
|
|
17626
|
+
if (args.rollback === "engine") return asToolResult(rollback(engine));
|
|
17627
|
+
if (args.rollback === "shell") return asToolResult(rollbackShell(engine.home()));
|
|
17628
|
+
return lookAround(engine, args.model, key, baseUrl);
|
|
17629
|
+
}
|
|
17630
|
+
});
|
|
17809
17631
|
}
|
|
17810
|
-
|
|
17811
|
-
|
|
17812
|
-
|
|
17813
|
-
|
|
17814
|
-
|
|
17815
|
-
|
|
17816
|
-
|
|
17817
|
-
return
|
|
17632
|
+
async function lookAround(engine, model, key, baseUrl) {
|
|
17633
|
+
if (engine.place() === null) {
|
|
17634
|
+
const payload = await installPayload(engine, {
|
|
17635
|
+
consent: false,
|
|
17636
|
+
manifestUrl: manifestUrl(engine, baseUrl),
|
|
17637
|
+
...key !== void 0 ? { key } : {}
|
|
17638
|
+
});
|
|
17639
|
+
return toolSuccess(`${payload.text}
|
|
17640
|
+
${INSTALL_HINT}`);
|
|
17818
17641
|
}
|
|
17819
|
-
|
|
17820
|
-
}
|
|
17821
|
-
|
|
17822
|
-
const
|
|
17823
|
-
|
|
17824
|
-
|
|
17825
|
-
|
|
17826
|
-
|
|
17827
|
-
place.pack,
|
|
17828
|
-
...asked.style !== void 0 ? ["--style", path(asked.style)] : [],
|
|
17829
|
-
...(asked.also ?? []).flatMap((one) => ["--also", path(one)]),
|
|
17830
|
-
...asked.ask !== void 0 ? ["--ask", JSON.stringify(asked.ask)] : [],
|
|
17831
|
-
"--json"
|
|
17832
|
-
], key !== void 0 ? { key } : {});
|
|
17833
|
-
return answer.ok ? answerOrRefusal(answer.text, DRAFT_CONTRACT) : { refusal: answer.text };
|
|
17834
|
-
}
|
|
17835
|
-
async function editOperations(engine, place, asked, key) {
|
|
17836
|
-
const answer = await engine.command([
|
|
17837
|
-
"document-edit",
|
|
17838
|
-
"--project",
|
|
17839
|
-
path(asked.reel),
|
|
17840
|
-
"--ops",
|
|
17841
|
-
JSON.stringify(asked.ops),
|
|
17842
|
-
...asked.stamps !== void 0 ? ["--stamps", JSON.stringify(asked.stamps)] : [],
|
|
17843
|
-
"--by",
|
|
17844
|
-
asked.by ?? "model",
|
|
17845
|
-
"--pack",
|
|
17846
|
-
place.pack,
|
|
17847
|
-
"--json"
|
|
17848
|
-
], key !== void 0 ? { key } : {});
|
|
17849
|
-
return answer.ok ? answerOrRefusal(answer.text, EDIT_CONTRACT) : { refusal: answer.text };
|
|
17850
|
-
}
|
|
17851
|
-
function nameOrRefusal(candidate) {
|
|
17852
|
-
const looksLikePath2 = candidate.includes("/") || candidate.includes("\\") || candidate.startsWith("~") || candidate.startsWith(".") || candidate.length > 1 && candidate[1] === ":";
|
|
17853
|
-
if (!looksLikePath2) return { name: candidate };
|
|
17854
|
-
return {
|
|
17855
|
-
refusal: `\u0417\u0434\u0435\u0441\u044C \u0436\u0434\u0443\u0442 \u0418\u041C\u042F \u0448\u0430\u0433\u0430, \u0430 \u043F\u0440\u0438\u0448\u0451\u043B \u043F\u0443\u0442\u044C: ${candidate}
|
|
17856
|
-
\u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C: \u043D\u0430\u0437\u043E\u0432\u0438 \u0448\u0430\u0433 \u043E\u0434\u043D\u0438\u043C \u0441\u043B\u043E\u0432\u043E\u043C \u2014 \u0442\u0430\u043A, \u043A\u0430\u043A \u043D\u0430\u0437\u044B\u0432\u0430\u0435\u0442\u0441\u044F \u0435\u0433\u043E \u043F\u0430\u043F\u043A\u0430. \u0421\u0432\u043E\u0439 \u0448\u0430\u0433 \u043B\u0435\u0436\u0438\u0442 \u0432 \`mine/steps/<\u0438\u043C\u044F>\` \u0432 \u0434\u043E\u043C\u0435 \u041D\u0430\u043F\u0430\u0440\u043D\u0438\u043A\u0430, \u043D\u0430\u0448\u0438 \u043F\u0435\u0440\u0435\u0447\u0438\u0441\u043B\u044F\u0435\u0442 setup, \u0438\u043C\u044F \u0443 \u043A\u0430\u0436\u0434\u043E\u0433\u043E \u0441\u0442\u043E\u0438\u0442 \u0432 \u0441\u043A\u043E\u0431\u043A\u0430\u0445.`
|
|
17857
|
-
};
|
|
17642
|
+
const noPython = await engine.pythonTrouble();
|
|
17643
|
+
if (noPython !== null) return toolSuccess(`${noPython}
|
|
17644
|
+
${INSTALL_HINT}`);
|
|
17645
|
+
const machine = await inspectMachine(engine, { model });
|
|
17646
|
+
if (machine.result.type === "error") return machine.result;
|
|
17647
|
+
return toolSuccess(`${wordsOf(machine.result.content)}
|
|
17648
|
+
|
|
17649
|
+
${INSTALL_HINT}`);
|
|
17858
17650
|
}
|
|
17859
|
-
var
|
|
17860
|
-
function
|
|
17861
|
-
return
|
|
17651
|
+
var INSTALL_HINT = "\u0421\u0442\u0430\u0432\u0438\u0442 install \u2014 \u0442\u043E\u043B\u044C\u043A\u043E \u043F\u043E\u0441\u043B\u0435 \xAB\u0434\u0430\xBB \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430 \u043D\u0430 \u043D\u0430\u0437\u0432\u0430\u043D\u043D\u043E\u0435 \u0441 \u0432\u0435\u0441\u043E\u043C: what=all \u2014 \u0432\u0441\u0451 \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u043E\u0435 \u0438 \u043D\u043E\u0432\u044B\u0435 \u0432\u0435\u0440\u0441\u0438\u0438; speech, cutout, voice \u2014 \u0442\u044F\u0436\u0451\u043B\u043E\u0435 \u043F\u043E \u043F\u0440\u043E\u0441\u044C\u0431\u0435. \u0413\u0434\u0435 \u043D\u0430\u043F\u0438\u0441\u0430\u043D\u043E \xABsetup \u0441 what=\u2026\xBB, \u0437\u043E\u0432\u0438 install \u0441 \u0442\u0435\u043C \u0436\u0435 what.";
|
|
17652
|
+
function installTool(engine, passport, key, baseUrl) {
|
|
17653
|
+
return defineTool({
|
|
17654
|
+
name: "install",
|
|
17655
|
+
title: "\u041F\u043E\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u0434\u043B\u044F \u043C\u043E\u043D\u0442\u0430\u0436\u0430",
|
|
17656
|
+
description: "\u0421\u0442\u0430\u0432\u0438\u0442 \u0438 \u043E\u0431\u043D\u043E\u0432\u043B\u044F\u0435\u0442 \u2014 \u0442\u043E\u043B\u044C\u043A\u043E \u043F\u043E\u0441\u043B\u0435 \xAB\u0434\u0430\xBB \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430 \u043D\u0430 \u0442\u043E, \u0447\u0442\u043E \u043D\u0430\u0437\u0432\u0430\u043B\u0430 \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0430 setup \u0441 \u0432\u0435\u0441\u043E\u043C. \u041E\u0442\u0432\u0435\u0442 \u2014 \u043D\u043E\u043C\u0435\u0440 \u0437\u0430\u0434\u0430\u0447\u0438: \u0436\u0434\u0438 wait. \u041F\u043E\u0432\u0442\u043E\u0440\u043D\u044B\u0439 \u0432\u044B\u0437\u043E\u0432 \u0432\u0435\u0440\u043D\u0451\u0442 \u0442\u0443 \u0436\u0435 \u0437\u0430\u0434\u0430\u0447\u0443.",
|
|
17657
|
+
ui: { resourceUri: RUNBAR_RESOURCE_URI },
|
|
17658
|
+
args: external_exports.object({
|
|
17659
|
+
what: external_exports.enum(["all", "speech", "cutout", "voice"]).describe(
|
|
17660
|
+
"all \u2014 \u0432\u0441\u0451 \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u043E\u0435 \u0438 \u043D\u043E\u0432\u044B\u0435 \u0432\u0435\u0440\u0441\u0438\u0438; speech \u2014 \u0440\u0430\u0441\u043F\u043E\u0437\u043D\u0430\u0432\u0430\u043D\u0438\u0435 \u0440\u0435\u0447\u0438 (\u0441\u0443\u0431\u0442\u0438\u0442\u0440\u044B); cutout \u2014 \u0432\u044B\u0440\u0435\u0437 \u0433\u0435\u0440\u043E\u044F (\u043D\u043E\u0432\u044B\u0439 \u0444\u043E\u043D); voice \u2014 \u0447\u0438\u0441\u0442\u043A\u0430 \u0433\u043E\u043B\u043E\u0441\u0430"
|
|
17661
|
+
),
|
|
17662
|
+
model: fromList(
|
|
17663
|
+
passport?.["models"],
|
|
17664
|
+
`\u041C\u043E\u0434\u0435\u043B\u044C \u0440\u0430\u0441\u043F\u043E\u0437\u043D\u0430\u0432\u0430\u043D\u0438\u044F \u0440\u0435\u0447\u0438 \u0434\u043B\u044F what=speech. ${aboutModels(passport)}`
|
|
17665
|
+
).optional()
|
|
17666
|
+
}),
|
|
17667
|
+
async execute(args) {
|
|
17668
|
+
return startInstall(engine, args.what, args.model, key, baseUrl);
|
|
17669
|
+
}
|
|
17670
|
+
});
|
|
17862
17671
|
}
|
|
17863
|
-
|
|
17864
|
-
|
|
17865
|
-
|
|
17866
|
-
|
|
17867
|
-
|
|
17868
|
-
|
|
17869
|
-
|
|
17870
|
-
|
|
17871
|
-
|
|
17872
|
-
|
|
17873
|
-
|
|
17874
|
-
|
|
17875
|
-
|
|
17876
|
-
|
|
17877
|
-
|
|
17878
|
-
|
|
17879
|
-
|
|
17880
|
-
|
|
17881
|
-
|
|
17882
|
-
|
|
17672
|
+
function startInstall(engine, what, model, key, baseUrl) {
|
|
17673
|
+
const id = what === "all" ? startSetupJob(engine.place() === null ? TITLE_INSTALL : TITLE_UPDATE, (job) => runUpdate(job, {
|
|
17674
|
+
engine,
|
|
17675
|
+
key,
|
|
17676
|
+
baseUrl,
|
|
17677
|
+
what: "all",
|
|
17678
|
+
pointerMs: ASKED_POINTER_MS,
|
|
17679
|
+
installMissing: () => installMissing(engine, key, baseUrl)
|
|
17680
|
+
}), Date.now, engine.home()) : startSetupJob(installTitle(HEAVY_STEPS[what]), (job) => runHeavy(job, {
|
|
17681
|
+
engine,
|
|
17682
|
+
title: installTitle(HEAVY_STEPS[what]),
|
|
17683
|
+
start: () => installStep(engine, { step: HEAVY_STEPS[what], model, consent: true }, key, baseUrl)
|
|
17684
|
+
}), Date.now, engine.home());
|
|
17685
|
+
const report = setupJobReport(id, engine.home());
|
|
17686
|
+
const ahead = what === "all" ? "" : `${installLadder(HEAVY_STEPS[what]).join(" ")}
|
|
17687
|
+
`;
|
|
17688
|
+
return toolSuccess(
|
|
17689
|
+
`\u0417\u0430\u0434\u0430\u0447\u0430 ${id}: ${report?.what ?? what}.
|
|
17690
|
+
${ahead}\u0418\u0434\u0451\u0442 \u043D\u0430 \u043A\u043E\u043C\u043F\u044C\u044E\u0442\u0435\u0440\u0435 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F, \u043F\u043E\u043B\u043E\u0441\u0430 \u0443 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430 \u043E\u0431\u043D\u043E\u0432\u043B\u044F\u0435\u0442\u0441\u044F \u0441\u0430\u043C\u0430. \u041F\u043E\u0437\u043E\u0432\u0438 wait \u0441 job "` + id + '" \u2014 \u0434\u043E\u0436\u0434\u0451\u0442\u0441\u044F \u0438 \u0441\u043A\u0430\u0436\u0435\u0442, \u0447\u0435\u043C \u043A\u043E\u043D\u0447\u0438\u043B\u043E\u0441\u044C; install \u043F\u043E\u0432\u0442\u043E\u0440\u043D\u043E \u043D\u0435 \u0437\u043E\u0432\u0438. \u0413\u043E\u0442\u043E\u0432\u043E \u2014 \u043F\u0435\u0440\u0435\u0441\u043A\u0430\u0436\u0438 \u0441\u0442\u0440\u043E\u043A\u0443 \xAB\u0427\u0435\u043B\u043E\u0432\u0435\u043A\u0443\xBB.',
|
|
17691
|
+
report ?? void 0
|
|
17692
|
+
);
|
|
17693
|
+
}
|
|
17694
|
+
var HEAVY_STEPS = {
|
|
17695
|
+
speech: "model",
|
|
17696
|
+
cutout: "cutout",
|
|
17697
|
+
voice: "voice"
|
|
17698
|
+
};
|
|
17699
|
+
async function installMissing(engine, key, baseUrl) {
|
|
17700
|
+
const place = engine.place();
|
|
17701
|
+
if (place !== null && await engine.pythonTrouble() === null && await nothingMissing(engine, place)) {
|
|
17702
|
+
return toolSuccess("\u0412\u0441\u0451 \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u043E\u0435 \u0434\u043B\u044F \u043C\u043E\u043D\u0442\u0430\u0436\u0430 \u043D\u0430 \u043C\u0435\u0441\u0442\u0435 \u2014 \u0441\u0442\u0430\u0432\u0438\u0442\u044C \u043D\u0435\u0447\u0435\u0433\u043E.");
|
|
17883
17703
|
}
|
|
17884
|
-
return
|
|
17704
|
+
return installStep(engine, { step: "all", consent: true }, key, baseUrl);
|
|
17885
17705
|
}
|
|
17886
|
-
function
|
|
17887
|
-
let names;
|
|
17706
|
+
async function nothingMissing(engine, place) {
|
|
17888
17707
|
try {
|
|
17889
|
-
|
|
17708
|
+
await engine.run(place, ["env-check", "--pack", place.pack, "--first-install"]);
|
|
17709
|
+
return true;
|
|
17890
17710
|
} catch {
|
|
17891
|
-
return
|
|
17711
|
+
return false;
|
|
17892
17712
|
}
|
|
17893
|
-
return names.sort().reverse().map((name) => load(home, name.slice(0, -".json".length))).filter((record2) => record2 !== null);
|
|
17894
17713
|
}
|
|
17895
|
-
function
|
|
17896
|
-
|
|
17897
|
-
|
|
17898
|
-
|
|
17899
|
-
|
|
17714
|
+
function together(results) {
|
|
17715
|
+
const text2 = results.map((one) => one.type === "success" ? wordsOf(one.content) : one.error).filter((words) => words !== "").join("\n\n");
|
|
17716
|
+
for (const one of results) {
|
|
17717
|
+
if (one.type === "success" && one.structured !== void 0) return toolSuccess(text2, one.structured);
|
|
17718
|
+
}
|
|
17719
|
+
return results.some((one) => one.type === "error") ? toolError(text2) : toolSuccess(text2);
|
|
17720
|
+
}
|
|
17721
|
+
function wordsOf(content) {
|
|
17722
|
+
if (typeof content === "string") return content;
|
|
17723
|
+
return content.map((block) => block.type === "text" ? block.text : "").join("\n");
|
|
17724
|
+
}
|
|
17725
|
+
var CALLS_FILE = "calls.jsonl";
|
|
17726
|
+
var CALLS_PREVIOUS = "calls.1.jsonl";
|
|
17727
|
+
var CALLS_CAP_BYTES = 1e6;
|
|
17728
|
+
function withCallLog(home, now = () => Date.now()) {
|
|
17729
|
+
return (tool) => {
|
|
17730
|
+
const original = tool.execute.bind(tool);
|
|
17900
17731
|
return {
|
|
17901
|
-
|
|
17902
|
-
|
|
17903
|
-
|
|
17904
|
-
|
|
17905
|
-
|
|
17906
|
-
|
|
17907
|
-
|
|
17908
|
-
|
|
17909
|
-
|
|
17732
|
+
...tool,
|
|
17733
|
+
async execute(input, ...rest) {
|
|
17734
|
+
const started = now();
|
|
17735
|
+
const result = await original(input, ...rest);
|
|
17736
|
+
write(home, {
|
|
17737
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
17738
|
+
tool: tool.name,
|
|
17739
|
+
ok: result.type === "success",
|
|
17740
|
+
ms: now() - started
|
|
17741
|
+
});
|
|
17742
|
+
return result;
|
|
17743
|
+
}
|
|
17910
17744
|
};
|
|
17911
|
-
}
|
|
17912
|
-
return null;
|
|
17913
|
-
}
|
|
17745
|
+
};
|
|
17914
17746
|
}
|
|
17915
|
-
function
|
|
17916
|
-
if (clock() - record2.beat > STALE_MS) return false;
|
|
17747
|
+
function write(home, line) {
|
|
17917
17748
|
try {
|
|
17918
|
-
|
|
17919
|
-
|
|
17920
|
-
|
|
17921
|
-
|
|
17749
|
+
mkdirSync(home, { recursive: true });
|
|
17750
|
+
const file2 = join(home, CALLS_FILE);
|
|
17751
|
+
rotate(file2, join(home, CALLS_PREVIOUS));
|
|
17752
|
+
appendFileSync(file2, `${JSON.stringify(line)}
|
|
17753
|
+
`, { encoding: "utf8", mode: 384 });
|
|
17754
|
+
} catch {
|
|
17922
17755
|
}
|
|
17923
17756
|
}
|
|
17924
|
-
function
|
|
17925
|
-
if (work.home === null) return;
|
|
17757
|
+
function rotate(file2, previous) {
|
|
17926
17758
|
try {
|
|
17927
|
-
|
|
17928
|
-
mkdirSync(dir, { recursive: true });
|
|
17929
|
-
const file2 = join(dir, `${work.id}.json`);
|
|
17930
|
-
const temp = `${file2}.${process.pid}.tmp`;
|
|
17931
|
-
const record2 = {
|
|
17932
|
-
id: work.id,
|
|
17933
|
-
what: work.what,
|
|
17934
|
-
started: work.started,
|
|
17935
|
-
stages: work.stages,
|
|
17936
|
-
at: work.at,
|
|
17937
|
-
message: work.message,
|
|
17938
|
-
ended: work.ended,
|
|
17939
|
-
pid: process.pid,
|
|
17940
|
-
beat: clock()
|
|
17941
|
-
};
|
|
17942
|
-
writeFileSync(temp, JSON.stringify(record2), "utf8");
|
|
17943
|
-
renameSync(temp, file2);
|
|
17759
|
+
if (statSync(file2).size >= CALLS_CAP_BYTES) renameSync(file2, previous);
|
|
17944
17760
|
} catch {
|
|
17945
17761
|
}
|
|
17946
|
-
}
|
|
17947
|
-
|
|
17948
|
-
|
|
17949
|
-
|
|
17950
|
-
|
|
17951
|
-
|
|
17952
|
-
|
|
17762
|
+
}
|
|
17763
|
+
|
|
17764
|
+
// src/contracts/crash-report.ts
|
|
17765
|
+
var CRASH_REPORT_PATH = "/crash-report";
|
|
17766
|
+
var CRASH_CONTRACT = "naparnik-crash/1";
|
|
17767
|
+
var CRASH_LIMITS = {
|
|
17768
|
+
bodyBytes: 65536,
|
|
17769
|
+
errorType: 120,
|
|
17770
|
+
message: 500,
|
|
17771
|
+
trace: 8e3,
|
|
17772
|
+
stage: 120,
|
|
17773
|
+
osPlatform: 32,
|
|
17774
|
+
osRelease: 64,
|
|
17775
|
+
osArch: 16,
|
|
17776
|
+
hostName: 64,
|
|
17777
|
+
hostVersion: 32,
|
|
17778
|
+
shellVersion: 32,
|
|
17779
|
+
engineVersion: 64,
|
|
17780
|
+
pythonVersion: 16,
|
|
17781
|
+
ffmpegVersion: 64,
|
|
17782
|
+
recentCalls: 10,
|
|
17783
|
+
repeats: 1e5
|
|
17784
|
+
};
|
|
17785
|
+
var CRASH_TOOL_NAME = /^[a-z_]{1,64}$/;
|
|
17786
|
+
var CRASH_FINGERPRINT = /^[0-9a-f]{16}$/;
|
|
17787
|
+
var text = (max) => external_exports.string().max(max);
|
|
17788
|
+
var CrashReportRequest = external_exports.object({
|
|
17789
|
+
contract: external_exports.literal(CRASH_CONTRACT),
|
|
17790
|
+
occurred_at: external_exports.string().datetime({ offset: true }),
|
|
17791
|
+
where: external_exports.enum(["tool", "job", "process"]),
|
|
17792
|
+
tool: external_exports.string().regex(CRASH_TOOL_NAME).nullable(),
|
|
17793
|
+
stage: text(CRASH_LIMITS.stage).nullable(),
|
|
17794
|
+
error_type: external_exports.string().min(1).max(CRASH_LIMITS.errorType),
|
|
17795
|
+
message: text(CRASH_LIMITS.message),
|
|
17796
|
+
trace: text(CRASH_LIMITS.trace),
|
|
17797
|
+
fingerprint: external_exports.string().regex(CRASH_FINGERPRINT),
|
|
17798
|
+
repeats: external_exports.number().int().min(0).max(CRASH_LIMITS.repeats),
|
|
17799
|
+
os: external_exports.object({
|
|
17800
|
+
platform: text(CRASH_LIMITS.osPlatform),
|
|
17801
|
+
release: text(CRASH_LIMITS.osRelease),
|
|
17802
|
+
arch: text(CRASH_LIMITS.osArch)
|
|
17803
|
+
}).strict(),
|
|
17804
|
+
host: external_exports.object({
|
|
17805
|
+
name: text(CRASH_LIMITS.hostName),
|
|
17806
|
+
version: text(CRASH_LIMITS.hostVersion)
|
|
17807
|
+
}).strict().nullable(),
|
|
17808
|
+
versions: external_exports.object({
|
|
17809
|
+
shell: text(CRASH_LIMITS.shellVersion),
|
|
17810
|
+
engine: text(CRASH_LIMITS.engineVersion).nullable(),
|
|
17811
|
+
python: text(CRASH_LIMITS.pythonVersion).nullable(),
|
|
17812
|
+
ffmpeg: text(CRASH_LIMITS.ffmpegVersion).nullable()
|
|
17813
|
+
}).strict(),
|
|
17814
|
+
recent_calls: external_exports.array(external_exports.string().regex(CRASH_TOOL_NAME)).max(CRASH_LIMITS.recentCalls)
|
|
17815
|
+
}).strict();
|
|
17816
|
+
var SECRET_MIN = 4;
|
|
17817
|
+
var HUMAN_FILE = /[^\s"'«»“”/\\<>()]{0,255}\.(?:mp4|mov|m4v|mkv|avi|webm|mts|wav|mp3|m4a|aac|flac|ogg|jpg|jpeg|png|heic|gif|srt|vtt)\b/gi;
|
|
17818
|
+
var PATH = /(?:<naparnik>|<shell>|~|[A-Za-z]:)?(?:[\\/][^\s"'«»“”<>|,;()[\]{}\\/]+)+[\\/]?/g;
|
|
17819
|
+
var QUOTED = /(["'])([^"'\n]*)\1|«([^»\n]*)»|“([^”\n]*)”/g;
|
|
17820
|
+
var KEY = /npk_[A-Za-z0-9_-]{6,}/g;
|
|
17821
|
+
function scrub(text2, context) {
|
|
17822
|
+
let out = text2.replace(KEY, "<key>");
|
|
17823
|
+
for (const secret of secretForms(context.secrets)) {
|
|
17824
|
+
out = replaceAll(out, secret, "<video>");
|
|
17825
|
+
}
|
|
17826
|
+
out = replaceAll(out, context.shellDir, "<shell>");
|
|
17827
|
+
out = replaceAll(out, context.naparnikHome, "<naparnik>");
|
|
17828
|
+
out = replaceAll(out, context.home, "~");
|
|
17829
|
+
out = out.replace(/(?:\/Users|\/home|[A-Za-z]:\\Users|[A-Za-z]:\/Users)[\\/][^\s"'«»“”\\/]+/g, "~");
|
|
17830
|
+
out = out.replace(QUOTED, (whole, _q, plain, fir, curly) => {
|
|
17831
|
+
const inside2 = plain ?? fir ?? curly ?? "";
|
|
17832
|
+
if (!looksHuman(inside2)) return whole;
|
|
17833
|
+
const [open, close] = plain !== void 0 ? [_q, _q] : fir !== void 0 ? ["\xAB", "\xBB"] : ["\u201C", "\u201D"];
|
|
17834
|
+
return `${open}${looksLikePath(inside2) ? pathOrMark(inside2) : "<text>"}${close}`;
|
|
17835
|
+
});
|
|
17836
|
+
out = out.replace(PATH, (found) => pathOrMark(found));
|
|
17837
|
+
out = out.replace(HUMAN_FILE, "<file>");
|
|
17838
|
+
out = swallowSpacedTails(out);
|
|
17839
|
+
if (context.user.length >= 3) out = replaceAll(out, context.user, "<user>");
|
|
17840
|
+
return out;
|
|
17841
|
+
}
|
|
17842
|
+
function swallowSpacedTails(text2) {
|
|
17843
|
+
return text2.replace(/<(?:path|file)>[^\n:<>"'«»“”]{0,512}<(?:path|file)>/g, "<path>").replace(/(<(?:path|file)>)([^\n:<>"'«»“”]{0,512})/g, (whole, mark, tail2) => /[^\x00-\x7F]/.test(tail2) ? mark : whole);
|
|
17844
|
+
}
|
|
17845
|
+
function secretForms(secrets) {
|
|
17846
|
+
const forms = /* @__PURE__ */ new Set();
|
|
17847
|
+
for (const raw of secrets) {
|
|
17848
|
+
const value = raw.trim();
|
|
17849
|
+
if (value.length < SECRET_MIN) continue;
|
|
17850
|
+
forms.add(value);
|
|
17851
|
+
if (!looksLikePath(value)) continue;
|
|
17852
|
+
if (isAbsolute(value)) forms.add(resolve(value));
|
|
17853
|
+
const name = basename(value);
|
|
17854
|
+
const stem = name.slice(0, name.length - extname(name).length);
|
|
17855
|
+
for (const one of [name, stem, `${stem}.montage`]) {
|
|
17856
|
+
if (one.length >= SECRET_MIN) forms.add(one);
|
|
17857
|
+
}
|
|
17858
|
+
}
|
|
17859
|
+
return [...forms].sort((a, b) => b.length - a.length);
|
|
17860
|
+
}
|
|
17861
|
+
function pathOrMark(found) {
|
|
17862
|
+
const flat = found.replace(/\\/g, "/");
|
|
17863
|
+
const ours = /^(?:<naparnik>|~\/\.naparnik)\/(?:engine|shell|bin)(?:\/|$)/.test(flat) || flat.startsWith("<shell>") || /\/(?:site-packages|dist-packages|node_modules)\//.test(flat) || /\/lib\/python\d/i.test(flat) || /\/Python\d+\/Lib\//i.test(flat);
|
|
17864
|
+
return ours ? found : "<path>";
|
|
17865
|
+
}
|
|
17866
|
+
var HUMAN_FILE_ONE = new RegExp(HUMAN_FILE.source, "i");
|
|
17867
|
+
function looksLikePath(value) {
|
|
17868
|
+
return /[\\/]/.test(value) || HUMAN_FILE_ONE.test(value);
|
|
17869
|
+
}
|
|
17870
|
+
function looksHuman(inside2) {
|
|
17871
|
+
return /[^\x00-\x7F]/.test(inside2) || /\s/.test(inside2) || looksLikePath(inside2);
|
|
17872
|
+
}
|
|
17873
|
+
function replaceAll(text2, what, by) {
|
|
17874
|
+
if (what === "") return text2;
|
|
17875
|
+
return text2.split(what).join(by);
|
|
17876
|
+
}
|
|
17877
|
+
|
|
17878
|
+
// src/crash-report.ts
|
|
17879
|
+
var RESEND_AFTER_MS = 30 * 6e4;
|
|
17880
|
+
var QUEUE_CAP = 20;
|
|
17881
|
+
var FLUSH_PER_PASS = 5;
|
|
17882
|
+
var FLUSH_EVERY_MS = 6e4;
|
|
17883
|
+
var SEND_TIMEOUT_MS = 3e3;
|
|
17884
|
+
var JOB_LOG_TAIL = 64 * 1024;
|
|
17885
|
+
var PYTHON_TRACEBACK = "Traceback (most recent call last):";
|
|
17886
|
+
var SUPPORT_TOPIC = "https://t.me/c/3763431875/10";
|
|
17887
|
+
var WORDS_GRACE_MS = 1e3;
|
|
17888
|
+
var CrashReporter = class {
|
|
17889
|
+
#deps;
|
|
17890
|
+
#now;
|
|
17891
|
+
#inflight = /* @__PURE__ */ new Set();
|
|
17892
|
+
#lastFlush = Number.NEGATIVE_INFINITY;
|
|
17893
|
+
#host = null;
|
|
17894
|
+
/**
|
|
17895
|
+
* Строки из аргументов недавних вызовов — только в памяти процесса.
|
|
17896
|
+
*
|
|
17897
|
+
* ⚠ ЗАЧЕМ. Задание упало — отчёт о нём приходит на `wait`, а в аргументах
|
|
17898
|
+
* `wait` лишь номер задания; путь к ролику был в аргументах `render`,
|
|
17899
|
+
* который задание запустил. Без этой памяти путь с пробелами из трейса ffmpeg
|
|
17900
|
+
* вычищался бы только общими правилами, а они его режут на куски (ревью
|
|
17901
|
+
* безопасности 2026-09-24). На диск не пишется: это ровно то, что мы
|
|
17902
|
+
* обещали не хранить.
|
|
17903
|
+
*/
|
|
17904
|
+
#recentSecrets = [];
|
|
17905
|
+
#ffmpeg = null;
|
|
17906
|
+
constructor(deps) {
|
|
17907
|
+
this.#deps = deps;
|
|
17908
|
+
this.#now = deps.now ?? (() => Date.now());
|
|
17909
|
+
}
|
|
17910
|
+
get canSend() {
|
|
17911
|
+
return this.#deps.canSend;
|
|
17912
|
+
}
|
|
17913
|
+
get home() {
|
|
17914
|
+
return this.#deps.home;
|
|
17915
|
+
}
|
|
17916
|
+
/** Запомнить программу-хост: при падении всего процесса контекста вызова нет. */
|
|
17917
|
+
/** Запомнить строки аргументов вызова — чтобы вычеркнуть их из будущих отчётов. */
|
|
17918
|
+
noteSecrets(secrets) {
|
|
17919
|
+
const fresh = secrets.filter((one) => one.length >= 4);
|
|
17920
|
+
if (fresh.length === 0) return;
|
|
17921
|
+
this.#recentSecrets = [...this.#recentSecrets.filter((one) => !fresh.includes(one)), ...fresh].slice(-50);
|
|
17922
|
+
}
|
|
17923
|
+
noteHost(host) {
|
|
17924
|
+
if (host !== null) this.#host = host;
|
|
17953
17925
|
}
|
|
17954
|
-
|
|
17955
|
-
|
|
17956
|
-
|
|
17957
|
-
|
|
17958
|
-
|
|
17959
|
-
|
|
17960
|
-
|
|
17961
|
-
|
|
17962
|
-
|
|
17963
|
-
|
|
17964
|
-
|
|
17965
|
-
|
|
17966
|
-
|
|
17967
|
-
|
|
17968
|
-
|
|
17926
|
+
/**
|
|
17927
|
+
* Отправить отчёт. Ответ инструмента ждёт итог через {@link wordsFor}, а
|
|
17928
|
+
* всё прочее — нет; для тестов и смоука — `settled()`.
|
|
17929
|
+
*/
|
|
17930
|
+
submit(crash) {
|
|
17931
|
+
const delivery = this.#deliver(crash).catch(() => "none");
|
|
17932
|
+
this.#track(delivery.then(() => void 0));
|
|
17933
|
+
return delivery;
|
|
17934
|
+
}
|
|
17935
|
+
/**
|
|
17936
|
+
* Итог отправки для слов человеку — не дольше таймаута отправки с запасом.
|
|
17937
|
+
* Не успела — отчёт ещё в пути и либо уйдёт, либо ляжет в очередь: «уйдёт»
|
|
17938
|
+
* правда в обоих случаях.
|
|
17939
|
+
*/
|
|
17940
|
+
async outcome(delivery) {
|
|
17941
|
+
let timer;
|
|
17942
|
+
const late = new Promise((done) => {
|
|
17943
|
+
timer = setTimeout(() => done("queued"), (this.#deps.timeoutMs ?? SEND_TIMEOUT_MS) + WORDS_GRACE_MS);
|
|
17944
|
+
timer.unref?.();
|
|
17945
|
+
});
|
|
17946
|
+
try {
|
|
17947
|
+
return await Promise.race([delivery, late]);
|
|
17948
|
+
} finally {
|
|
17949
|
+
clearTimeout(timer);
|
|
17969
17950
|
}
|
|
17970
|
-
}
|
|
17971
|
-
|
|
17972
|
-
|
|
17973
|
-
|
|
17974
|
-
|
|
17975
|
-
|
|
17976
|
-
|
|
17977
|
-
|
|
17978
|
-
|
|
17979
|
-
|
|
17980
|
-
|
|
17981
|
-
stages: [CHECK],
|
|
17982
|
-
at: 1,
|
|
17983
|
-
message: "",
|
|
17984
|
-
ended: null,
|
|
17985
|
-
done: Promise.resolve(),
|
|
17986
|
-
home
|
|
17987
|
-
};
|
|
17988
|
-
const control = {
|
|
17989
|
-
plan(stages) {
|
|
17990
|
-
work.stages = stages;
|
|
17991
|
-
work.at = Math.min(work.at, stages.length);
|
|
17992
|
-
save(work, clock);
|
|
17993
|
-
},
|
|
17994
|
-
go(stage) {
|
|
17995
|
-
const index = work.stages.indexOf(stage);
|
|
17996
|
-
if (index >= 0) work.at = index + 1;
|
|
17997
|
-
work.message = "";
|
|
17998
|
-
save(work, clock);
|
|
17999
|
-
},
|
|
18000
|
-
line(text2) {
|
|
18001
|
-
work.message = text2;
|
|
18002
|
-
save(work, clock);
|
|
17951
|
+
}
|
|
17952
|
+
/**
|
|
17953
|
+
* Процесс падает: отчёт кладётся на диск СИНХРОННО и уходит на следующем
|
|
17954
|
+
* запуске. Сеть здесь не трогаем — процессу осталось жить миллисекунды, и
|
|
17955
|
+
* недоставленный наполовину запрос хуже файла, который точно дойдёт.
|
|
17956
|
+
*/
|
|
17957
|
+
persist(crash) {
|
|
17958
|
+
try {
|
|
17959
|
+
const report = this.#build(crash);
|
|
17960
|
+
if (report !== null) this.#enqueue(report);
|
|
17961
|
+
} catch {
|
|
18003
17962
|
}
|
|
18004
|
-
}
|
|
18005
|
-
|
|
18006
|
-
|
|
18007
|
-
|
|
18008
|
-
|
|
18009
|
-
|
|
18010
|
-
|
|
18011
|
-
|
|
17963
|
+
}
|
|
17964
|
+
/** Досылка очереди — не чаще раза в минуту. */
|
|
17965
|
+
flushSoon() {
|
|
17966
|
+
const now = this.#now();
|
|
17967
|
+
if (now - this.#lastFlush < FLUSH_EVERY_MS) return;
|
|
17968
|
+
this.#lastFlush = now;
|
|
17969
|
+
this.#track(this.#flush());
|
|
17970
|
+
}
|
|
17971
|
+
/** Дождаться всего, что ушло мимо ответа. Боевому пути не нужно. */
|
|
17972
|
+
async settled() {
|
|
17973
|
+
while (this.#inflight.size > 0) await Promise.allSettled([...this.#inflight]);
|
|
17974
|
+
}
|
|
17975
|
+
/** Задание уже разобрано: отчёт о нём ушёл раньше, в этом или прошлом запуске. */
|
|
17976
|
+
jobSeen(id) {
|
|
17977
|
+
return this.#state().jobs.includes(id);
|
|
17978
|
+
}
|
|
17979
|
+
rememberJob(id) {
|
|
17980
|
+
const state = this.#state();
|
|
17981
|
+
state.jobs = [...state.jobs.filter((one) => one !== id), id].slice(-50);
|
|
17982
|
+
this.#save(state);
|
|
17983
|
+
}
|
|
17984
|
+
scrubContext(secrets) {
|
|
18012
17985
|
return {
|
|
18013
|
-
|
|
18014
|
-
|
|
18015
|
-
|
|
18016
|
-
|
|
17986
|
+
home: this.#deps.osHome ?? homedir(),
|
|
17987
|
+
user: this.#deps.osUser ?? safeUser(),
|
|
17988
|
+
naparnikHome: this.#deps.home,
|
|
17989
|
+
shellDir: this.#deps.shellDir ?? ownDir(),
|
|
17990
|
+
secrets
|
|
18017
17991
|
};
|
|
18018
|
-
})).then((ending) => {
|
|
18019
|
-
work.ended = { at: clock(), ending };
|
|
18020
|
-
if (beat !== null) clearInterval(beat);
|
|
18021
|
-
save(work, clock);
|
|
18022
|
-
});
|
|
18023
|
-
return id;
|
|
18024
|
-
}
|
|
18025
|
-
function quiet(line) {
|
|
18026
|
-
return line.replace(/^⚠\s*/, "").replace(/^Что делать:/, "\u0421\u043E\u0432\u0435\u0442:");
|
|
18027
|
-
}
|
|
18028
|
-
function setupJobText(id, clock = Date.now, home = null) {
|
|
18029
|
-
const work = works.get(id) ?? (home === null ? null : fromDisk(home, id, clock));
|
|
18030
|
-
if (work === null) return null;
|
|
18031
|
-
const head2 = `\u0417\u0430\u0434\u0430\u043D\u0438\u0435 ${work.id}: ${work.what}`;
|
|
18032
|
-
if (work.ended === null) {
|
|
18033
|
-
const sec2 = Math.max(0, Math.round((clock() - work.started) / 1e3));
|
|
18034
|
-
return [
|
|
18035
|
-
head2,
|
|
18036
|
-
`\u042D\u0442\u0430\u043F ${work.at} \u0438\u0437 ${work.stages.length}: ${work.stages[work.at - 1] ?? CHECK}`,
|
|
18037
|
-
...work.message === "" ? [] : [work.message],
|
|
18038
|
-
`\u0415\u0449\u0451 \u0441\u0447\u0438\u0442\u0430\u0435\u0442, ${sec2} \u0441.`
|
|
18039
|
-
].join("\n");
|
|
18040
17992
|
}
|
|
18041
|
-
|
|
18042
|
-
|
|
18043
|
-
|
|
18044
|
-
|
|
18045
|
-
return [head2, `\u0413\u043E\u0442\u043E\u0432\u043E \u0437\u0430 ${sec} \u0441.`, `\u0427\u0435\u043B\u043E\u0432\u0435\u043A\u0443: ${ending.say}`, ...report].join("\n");
|
|
17993
|
+
#track(work) {
|
|
17994
|
+
const guarded = work.catch(() => void 0);
|
|
17995
|
+
this.#inflight.add(guarded);
|
|
17996
|
+
void guarded.finally(() => this.#inflight.delete(guarded));
|
|
18046
17997
|
}
|
|
18047
|
-
|
|
18048
|
-
|
|
18049
|
-
|
|
18050
|
-
|
|
18051
|
-
|
|
18052
|
-
|
|
18053
|
-
|
|
18054
|
-
|
|
18055
|
-
const text2 = setupJobText(id, Date.now, home);
|
|
18056
|
-
return text2 === null ? null : readJob(text2);
|
|
18057
|
-
}
|
|
18058
|
-
function weightExact(bytes) {
|
|
18059
|
-
const mb = bytes / 1024 / 1024;
|
|
18060
|
-
if (mb >= 1e3) return `${(mb / 1024).toFixed(1).replace(".", ",")} \u0413\u0411`;
|
|
18061
|
-
return `${mb.toFixed(1).replace(".", ",")} \u041C\u0411`;
|
|
18062
|
-
}
|
|
18063
|
-
async function runUpdate(job, deps) {
|
|
18064
|
-
const { engine, key, baseUrl, what } = deps;
|
|
18065
|
-
const home = engine.home();
|
|
18066
|
-
const wantShell = what !== "engine";
|
|
18067
|
-
const hasEngine = engine.place() !== null;
|
|
18068
|
-
const wantEngine = what !== "shell" && hasEngine && !engine.pathSetByHand();
|
|
18069
|
-
const shellUrl = engine.variable("NAPARNIK_BUNDLE_MANIFEST") ?? bundleUrlFor(baseUrl);
|
|
18070
|
-
const [shellAsk, engineAsk] = await Promise.all([
|
|
18071
|
-
wantShell ? fetchShellManifest(shellUrl, deps.pointerMs, key) : Promise.resolve(null),
|
|
18072
|
-
wantEngine ? fetchManifest(manifestUrl(engine, baseUrl), deps.pointerMs, key) : Promise.resolve(null)
|
|
18073
|
-
]);
|
|
18074
|
-
const shellWas = installedShell(home);
|
|
18075
|
-
const shell = decideShell(shellWas, shellAsk?.ok === true ? shellAsk.manifest : null);
|
|
18076
|
-
const engineWas = engine.freshVersion();
|
|
18077
|
-
const fresh = decide(engineWas, engineAsk?.ok === true ? engineAsk.manifest : null);
|
|
18078
|
-
const shellStage = shell.what === "newer_available" ? `\u0421\u043A\u0430\u0447\u0438\u0432\u0430\u044E \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u0435 \xB7 ${weightExact(shell.manifest.body?.bytes ?? 0)}` : null;
|
|
18079
|
-
const engineStage = fresh.what === "newer_available" ? `\u0421\u043A\u0430\u0447\u0438\u0432\u0430\u044E \u0434\u0432\u0438\u0436\u043E\u043A \xB7 ${weightExact(fresh.manifest.bytes)}` : null;
|
|
18080
|
-
const missing = what === "all" && engineStage === null;
|
|
18081
|
-
job.plan([
|
|
18082
|
-
CHECK,
|
|
18083
|
-
...shellStage === null ? [] : [shellStage],
|
|
18084
|
-
...engineStage === null ? [] : [engineStage, INSTALL_NEW],
|
|
18085
|
-
...missing ? [MISSING] : []
|
|
18086
|
-
]);
|
|
18087
|
-
const steps = [];
|
|
18088
|
-
let updated = false;
|
|
18089
|
-
let installed = false;
|
|
18090
|
-
for (const [ask2, whose] of [[shellAsk, "\u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F"], [engineAsk, "\u0434\u0432\u0438\u0436\u043A\u0430"]]) {
|
|
18091
|
-
if (ask2 === null || ask2.ok) continue;
|
|
18092
|
-
const refusal = refusalWords(ask2.status ?? 0);
|
|
18093
|
-
steps.push({
|
|
18094
|
-
report: `\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0441\u043F\u0440\u043E\u0441\u0438\u0442\u044C, \u0435\u0441\u0442\u044C \u043B\u0438 \u043D\u043E\u0432\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F ${whose}: ${ask2.why}.`,
|
|
18095
|
-
trouble: refusal !== "" ? refusal : "\u041D\u0435 \u043F\u043E\u043B\u0443\u0447\u0438\u043B\u043E\u0441\u044C \u0441\u0432\u044F\u0437\u0430\u0442\u044C\u0441\u044F \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u043E\u043C \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0439."
|
|
18096
|
-
});
|
|
17998
|
+
async #deliver(crash) {
|
|
17999
|
+
const report = this.#build(crash);
|
|
18000
|
+
if (report === null) return this.#queuedAlready(fingerprintOf2(crash.errorType, crash.frames)) ? "queued" : "sent";
|
|
18001
|
+
report.versions.ffmpeg = await this.#ffmpegVersion();
|
|
18002
|
+
const verdict = await this.#send(report);
|
|
18003
|
+
if (verdict === "sent") return "sent";
|
|
18004
|
+
if (verdict === "drop") return "none";
|
|
18005
|
+
return this.#enqueue(report) ? "queued" : "none";
|
|
18097
18006
|
}
|
|
18098
|
-
|
|
18099
|
-
|
|
18007
|
+
#queuedAlready(fingerprint) {
|
|
18008
|
+
try {
|
|
18009
|
+
return readdirSync(this.#queueDir()).some((f) => f.endsWith(`-${fingerprint}.json`));
|
|
18010
|
+
} catch {
|
|
18011
|
+
return false;
|
|
18012
|
+
}
|
|
18100
18013
|
}
|
|
18101
|
-
|
|
18102
|
-
|
|
18103
|
-
|
|
18104
|
-
|
|
18105
|
-
|
|
18014
|
+
async #flush() {
|
|
18015
|
+
const dir = this.#queueDir();
|
|
18016
|
+
let files;
|
|
18017
|
+
try {
|
|
18018
|
+
files = readdirSync(dir).filter((f) => f.endsWith(".json")).sort();
|
|
18019
|
+
} catch {
|
|
18020
|
+
return;
|
|
18021
|
+
}
|
|
18022
|
+
for (const file2 of files.slice(0, FLUSH_PER_PASS)) {
|
|
18023
|
+
const path2 = join(dir, file2);
|
|
18024
|
+
let report;
|
|
18025
|
+
try {
|
|
18026
|
+
report = JSON.parse(readFileSync(path2, "utf8"));
|
|
18027
|
+
} catch {
|
|
18028
|
+
rmSync(path2, { force: true });
|
|
18029
|
+
continue;
|
|
18030
|
+
}
|
|
18031
|
+
const verdict = await this.#send(report);
|
|
18032
|
+
if (verdict === "retry") return;
|
|
18033
|
+
rmSync(path2, { force: true });
|
|
18034
|
+
}
|
|
18106
18035
|
}
|
|
18107
|
-
|
|
18108
|
-
|
|
18109
|
-
|
|
18110
|
-
|
|
18111
|
-
|
|
18036
|
+
/**
|
|
18037
|
+
* Отправить и решить, что делать с отчётом дальше.
|
|
18038
|
+
*
|
|
18039
|
+
* ⚠ В ОЧЕРЕДЬ ИДЁТ ТОЛЬКО ТО, ЧТО ПОВТОР ИСПРАВИТ: нет сети, таймаут, 5xx,
|
|
18040
|
+
* 429 и «ключа нет» (человек впишет его завтра). 400 и 413 — отчёт кривой,
|
|
18041
|
+
* 401 и 403 — ключ не наш: повтор даст тот же отказ, а очередь с потолком
|
|
18042
|
+
* вытесняла бы им живые отчёты.
|
|
18043
|
+
*/
|
|
18044
|
+
async #send(report) {
|
|
18045
|
+
if (!CrashReportRequest.safeParse(report).success) return "drop";
|
|
18046
|
+
try {
|
|
18047
|
+
await this.#deps.client.postMontage(CRASH_REPORT_PATH, report, {
|
|
18048
|
+
once: true,
|
|
18049
|
+
timeoutMs: this.#deps.timeoutMs ?? SEND_TIMEOUT_MS
|
|
18050
|
+
});
|
|
18051
|
+
return "sent";
|
|
18052
|
+
} catch (trouble) {
|
|
18053
|
+
if (trouble instanceof NaparnikAuthError || trouble instanceof NaparnikScopeError) return "drop";
|
|
18054
|
+
if (trouble instanceof NaparnikClientError) return trouble.status === 429 ? "retry" : "drop";
|
|
18055
|
+
return "retry";
|
|
18056
|
+
}
|
|
18112
18057
|
}
|
|
18113
|
-
|
|
18114
|
-
|
|
18115
|
-
|
|
18116
|
-
|
|
18117
|
-
|
|
18118
|
-
|
|
18119
|
-
|
|
18120
|
-
|
|
18058
|
+
/**
|
|
18059
|
+
* Собрать отчёт: обезличить, обрезать, посчитать отпечаток и решить по
|
|
18060
|
+
* частоте. `null` — этот отпечаток уже уходил меньше получаса назад, и
|
|
18061
|
+
* повтор записан в счётчик.
|
|
18062
|
+
*/
|
|
18063
|
+
#build(crash) {
|
|
18064
|
+
const fingerprint = fingerprintOf2(crash.errorType, crash.frames);
|
|
18065
|
+
const state = this.#state();
|
|
18066
|
+
const now = this.#now();
|
|
18067
|
+
const seen = state.fingerprints[fingerprint];
|
|
18068
|
+
if (seen !== void 0 && now - seen.sentAt < RESEND_AFTER_MS) {
|
|
18069
|
+
seen.pending += 1;
|
|
18070
|
+
this.#save(state);
|
|
18071
|
+
return null;
|
|
18121
18072
|
}
|
|
18073
|
+
const repeats = Math.min(seen?.pending ?? 0, CRASH_LIMITS.repeats);
|
|
18074
|
+
state.fingerprints[fingerprint] = { sentAt: now, pending: 0 };
|
|
18075
|
+
prune2(state, now);
|
|
18076
|
+
this.#save(state);
|
|
18077
|
+
const context = this.scrubContext([...crash.secrets, ...this.#recentSecrets]);
|
|
18078
|
+
const clean = (text2) => scrub(text2, context);
|
|
18079
|
+
return {
|
|
18080
|
+
contract: CRASH_CONTRACT,
|
|
18081
|
+
occurred_at: new Date(now).toISOString(),
|
|
18082
|
+
where: crash.where,
|
|
18083
|
+
tool: crash.tool !== null && CRASH_TOOL_NAME.test(crash.tool) ? crash.tool : null,
|
|
18084
|
+
// ⚠ РЕЖЕМ ДО ОБЕЗЛИЧИВАНИЯ С ЗАПАСОМ И ЕЩЁ РАЗ ПОСЛЕ. Обезличивание идёт
|
|
18085
|
+
// синхронно, до ответа инструмента, а stderr движка бывает мегабайтами:
|
|
18086
|
+
// без первой резки длинный текст подвешивал бы ответ на секунды (ревью
|
|
18087
|
+
// безопасности 2026-09-24). Запас — вдвое: метки короче того, что заменяют.
|
|
18088
|
+
stage: crash.stage === null ? null : head(clean(head(crash.stage, 2 * CRASH_LIMITS.stage)), CRASH_LIMITS.stage),
|
|
18089
|
+
error_type: head(clean(head(crash.errorType, 2 * CRASH_LIMITS.errorType)), CRASH_LIMITS.errorType) || "Error",
|
|
18090
|
+
message: head(clean(head(crash.message, 2 * CRASH_LIMITS.message)), CRASH_LIMITS.message),
|
|
18091
|
+
trace: crash.keep === "tail" ? tail(clean(crash.trace.slice(-2 * CRASH_LIMITS.trace)), CRASH_LIMITS.trace) : head(clean(head(crash.trace, 2 * CRASH_LIMITS.trace)), CRASH_LIMITS.trace),
|
|
18092
|
+
fingerprint,
|
|
18093
|
+
repeats,
|
|
18094
|
+
os: {
|
|
18095
|
+
platform: head(platform(), CRASH_LIMITS.osPlatform),
|
|
18096
|
+
release: head(release(), CRASH_LIMITS.osRelease),
|
|
18097
|
+
arch: head(arch(), CRASH_LIMITS.osArch)
|
|
18098
|
+
},
|
|
18099
|
+
host: hostOf(crash.host ?? this.#host),
|
|
18100
|
+
versions: {
|
|
18101
|
+
shell: head(VERSION, CRASH_LIMITS.shellVersion),
|
|
18102
|
+
engine: orNull(this.#deps.engineVersion(), CRASH_LIMITS.engineVersion),
|
|
18103
|
+
python: orNull(crash.python, CRASH_LIMITS.pythonVersion),
|
|
18104
|
+
ffmpeg: null
|
|
18105
|
+
},
|
|
18106
|
+
recent_calls: recentCalls(this.#deps.home)
|
|
18107
|
+
};
|
|
18122
18108
|
}
|
|
18123
|
-
|
|
18124
|
-
|
|
18125
|
-
|
|
18126
|
-
|
|
18127
|
-
|
|
18128
|
-
|
|
18129
|
-
|
|
18109
|
+
/** Положить отчёт в очередь. `false` — диск не принял, отчёт пропал. */
|
|
18110
|
+
#enqueue(report) {
|
|
18111
|
+
try {
|
|
18112
|
+
const dir = this.#queueDir();
|
|
18113
|
+
mkdirSync(dir, { recursive: true });
|
|
18114
|
+
const name = `${String(this.#now()).padStart(15, "0")}-${report.fingerprint}.json`;
|
|
18115
|
+
const temporary = join(dir, `${name}.tmp`);
|
|
18116
|
+
writeFileSync(temporary, JSON.stringify(report), { mode: 384 });
|
|
18117
|
+
renameSync(temporary, join(dir, name));
|
|
18118
|
+
const files = readdirSync(dir).filter((f) => f.endsWith(".json")).sort();
|
|
18119
|
+
for (const old of files.slice(0, Math.max(0, files.length - QUEUE_CAP))) {
|
|
18120
|
+
rmSync(join(dir, old), { force: true });
|
|
18130
18121
|
}
|
|
18131
|
-
|
|
18132
|
-
|
|
18133
|
-
|
|
18134
|
-
steps.push({ report: outcome.text });
|
|
18135
|
-
} else {
|
|
18136
|
-
const cause = causeOf(outcome.text);
|
|
18137
|
-
steps.push({
|
|
18138
|
-
report: outcome.text,
|
|
18139
|
-
trouble: `\u041D\u043E\u0432\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u0434\u0432\u0438\u0436\u043A\u0430 \u043D\u0435 \u0432\u0441\u0442\u0430\u043B\u0430${cause === "" ? "" : `: ${cause}`}. \u0420\u0430\u0431\u043E\u0442\u0430\u0435\u0442 \u043F\u0440\u0435\u0436\u043D\u044F\u044F${engineWas === null ? "" : ` ${engineWas}`}, \u043C\u043E\u043D\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u043C\u043E\u0436\u043D\u043E.`
|
|
18140
|
-
});
|
|
18122
|
+
return true;
|
|
18123
|
+
} catch {
|
|
18124
|
+
return false;
|
|
18141
18125
|
}
|
|
18142
18126
|
}
|
|
18143
|
-
|
|
18144
|
-
|
|
18145
|
-
const step = await deliverMissing(job, deps);
|
|
18146
|
-
if (step.trouble === void 0 && step.installed) installed = true;
|
|
18147
|
-
steps.push(step);
|
|
18127
|
+
#queueDir() {
|
|
18128
|
+
return join(this.#deps.home, "crash-reports", "queue");
|
|
18148
18129
|
}
|
|
18149
|
-
|
|
18150
|
-
|
|
18151
|
-
if (trouble !== void 0) return { ok: false, trouble, advice: ADVICE_ASK, report };
|
|
18152
|
-
if (updated) return { ok: true, say: SAY_RESTART, report };
|
|
18153
|
-
return { ok: true, say: installed ? SAY_INSTALLED : SAY_NOTHING, report };
|
|
18154
|
-
}
|
|
18155
|
-
function causeOf(text2) {
|
|
18156
|
-
const line = text2.split("\n").map((one) => one.trim()).find((one) => one !== "" && !/^(Новая версия|Версия) \S+ не встала/.test(one) && !/^Что делать:/.test(one)) ?? "";
|
|
18157
|
-
const phrase = (line.split(/\.\s|\s—\s|;\s/)[0] ?? "").replace(/\s*\([^)]*\)/g, "").replace(/\.$/, "").trim();
|
|
18158
|
-
return phrase === "" ? "" : phrase[0].toLowerCase() + phrase.slice(1);
|
|
18159
|
-
}
|
|
18160
|
-
async function deliverMissing(job, deps) {
|
|
18161
|
-
const answer = await deps.installMissing();
|
|
18162
|
-
if (answer.type === "error") {
|
|
18163
|
-
return { report: answer.error, trouble: "\u041D\u0435 \u043F\u043E\u043B\u0443\u0447\u0438\u043B\u043E\u0441\u044C \u043F\u043E\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u043D\u0435\u0434\u043E\u0441\u0442\u0430\u044E\u0449\u0435\u0435.", installed: false };
|
|
18130
|
+
#stateFile() {
|
|
18131
|
+
return join(this.#deps.home, "crash-reports", "seen.json");
|
|
18164
18132
|
}
|
|
18165
|
-
|
|
18166
|
-
|
|
18167
|
-
|
|
18168
|
-
|
|
18169
|
-
|
|
18170
|
-
|
|
18171
|
-
|
|
18172
|
-
|
|
18173
|
-
|
|
18174
|
-
|
|
18133
|
+
#state() {
|
|
18134
|
+
try {
|
|
18135
|
+
const parsed = JSON.parse(readFileSync(this.#stateFile(), "utf8"));
|
|
18136
|
+
return {
|
|
18137
|
+
fingerprints: typeof parsed.fingerprints === "object" && parsed.fingerprints !== null ? parsed.fingerprints : {},
|
|
18138
|
+
jobs: Array.isArray(parsed.jobs) ? parsed.jobs.filter((j) => typeof j === "string") : []
|
|
18139
|
+
};
|
|
18140
|
+
} catch {
|
|
18141
|
+
return { fingerprints: {}, jobs: [] };
|
|
18142
|
+
}
|
|
18175
18143
|
}
|
|
18176
|
-
|
|
18177
|
-
|
|
18178
|
-
|
|
18179
|
-
|
|
18180
|
-
|
|
18181
|
-
|
|
18182
|
-
installed: false
|
|
18183
|
-
};
|
|
18144
|
+
#save(state) {
|
|
18145
|
+
try {
|
|
18146
|
+
mkdirSync(dirname(this.#stateFile()), { recursive: true });
|
|
18147
|
+
writeFileSync(this.#stateFile(), JSON.stringify(state), { mode: 384 });
|
|
18148
|
+
} catch {
|
|
18149
|
+
}
|
|
18184
18150
|
}
|
|
18185
|
-
|
|
18186
|
-
|
|
18187
|
-
|
|
18188
|
-
|
|
18189
|
-
// src/setup-tool.ts
|
|
18190
|
-
var ASKED_POINTER_MS = 15e3;
|
|
18191
|
-
var NEWS_POINTER_MS = 5e3;
|
|
18192
|
-
var EXTRAS_LATER = "\u041C\u043E\u043D\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0443\u0436\u0435 \u043C\u043E\u0436\u043D\u043E. \u0424\u043E\u043D\u043E\u043C \u0434\u043E\u043A\u0430\u0447\u0438\u0432\u0430\u044E \u0442\u043E, \u0431\u0435\u0437 \u0447\u0435\u0433\u043E \u043C\u043E\u043D\u0442\u0430\u0436 \u0438 \u0442\u0430\u043A \u0438\u0434\u0451\u0442: \u0448\u0443\u043C\u043E\u0434\u0430\u0432 \u0433\u043E\u043B\u043E\u0441\u0430 \u2014 \u043E\u043A\u043E\u043B\u043E 30 \u041C\u0411, \u043A\u0430\u0440\u0442\u0443 \u0433\u0435\u0440\u043E\u044F \u0438 \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u0434\u043B\u044F \u0433\u0440\u0430\u0444\u0438\u043A\u0438 \u2014 \u0434\u043E 150 \u041C\u0411. \u0411\u0440\u0430\u0443\u0437\u0435\u0440 \u043A\u0430\u0447\u0430\u0435\u0442\u0441\u044F, \u0442\u043E\u043B\u044C\u043A\u043E \u0435\u0441\u043B\u0438 \u0435\u0433\u043E \u0441\u0431\u043E\u0440\u043A\u0430 \u0434\u043B\u044F \u044D\u0442\u043E\u0439 \u043C\u0430\u0448\u0438\u043D\u044B \u0443\u0436\u0435 \u0432\u044B\u043B\u043E\u0436\u0435\u043D\u0430: \u0433\u0440\u0430\u0444\u0438\u043A\u0430 \u0432 \u043C\u043E\u043D\u0442\u0430\u0436 \u0435\u0449\u0451 \u043D\u0435 \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D\u0430. \u041D\u0435 \u0434\u043E\u043A\u0430\u0447\u0430\u0435\u0442\u0441\u044F \u2014 \u043C\u043E\u043D\u0442\u0430\u0436 \u043D\u0435 \u0443\u043F\u0430\u0434\u0451\u0442, \u0430 setup \u0441\u043A\u0430\u0436\u0435\u0442 \u0441\u043B\u043E\u0432\u0430\u043C\u0438, \u0447\u0435\u0433\u043E \u043D\u0435\u0442.";
|
|
18193
|
-
async function inspectMachine(engine, asked) {
|
|
18194
|
-
const video = asked.video;
|
|
18195
|
-
const model = asked.model;
|
|
18196
|
-
const place = engine.place();
|
|
18197
|
-
if (place === null) return { result: toolError(engine.whyNoEngine()), readiness: null };
|
|
18198
|
-
const args = [
|
|
18199
|
-
"env-check",
|
|
18200
|
-
"--pack",
|
|
18201
|
-
place.pack,
|
|
18202
|
-
...video !== void 0 ? ["--video", path(video)] : [],
|
|
18203
|
-
...model !== void 0 ? ["--model", model] : []
|
|
18204
|
-
];
|
|
18205
|
-
let readiness = null;
|
|
18206
|
-
let words;
|
|
18207
|
-
if (knowsJsonCheck(place.engine)) {
|
|
18208
|
-
const answer = await askReadiness(engine, place, args);
|
|
18209
|
-
if ("ok" in answer && !answer.ok) return { result: toolError(answer.text), readiness: null };
|
|
18210
|
-
if ("parts" in answer) readiness = answer;
|
|
18211
|
-
words = "parts" in answer ? answer.words : answer.text;
|
|
18212
|
-
} else {
|
|
18213
|
-
const outcome = await engine.command(args);
|
|
18214
|
-
if (!outcome.ok) return { result: toolError(outcome.text), readiness: null };
|
|
18215
|
-
words = outcome.text;
|
|
18151
|
+
#ffmpegVersion() {
|
|
18152
|
+
this.#ffmpeg ??= (this.#deps.ffmpegVersion ?? (() => probeFfmpeg(this.#deps.home)))().catch(() => null);
|
|
18153
|
+
return this.#ffmpeg.then((v) => orNull(v, CRASH_LIMITS.ffmpegVersion));
|
|
18216
18154
|
}
|
|
18217
|
-
|
|
18218
|
-
|
|
18219
|
-
|
|
18220
|
-
|
|
18221
|
-
}
|
|
18222
|
-
async function askReadiness(engine, place, args) {
|
|
18223
|
-
const python = await engine.pythonTrouble();
|
|
18224
|
-
if (python !== null) return { ok: false, text: python };
|
|
18225
|
-
let stdout;
|
|
18226
|
-
try {
|
|
18227
|
-
stdout = (await engine.run(place, [...args, JSON_CHECK])).stdout;
|
|
18228
|
-
} catch (err) {
|
|
18229
|
-
const e = err;
|
|
18230
|
-
if (e.code !== 2 || typeof e.stdout !== "string") return parseFailure(err, "\u041F\u0440\u043E\u0432\u0435\u0440\u043A\u0430 \u043C\u0430\u0448\u0438\u043D\u044B \u043D\u0435 \u0432\u044B\u043F\u043E\u043B\u043D\u0438\u043B\u0430\u0441\u044C");
|
|
18231
|
-
stdout = e.stdout;
|
|
18155
|
+
};
|
|
18156
|
+
function prune2(state, now) {
|
|
18157
|
+
for (const [key, value] of Object.entries(state.fingerprints)) {
|
|
18158
|
+
if (now - value.sentAt > 24 * 36e5 && value.pending === 0) delete state.fingerprints[key];
|
|
18232
18159
|
}
|
|
18233
|
-
return readReadiness(stdout) ?? { ok: true, text: stdout.trim() };
|
|
18234
18160
|
}
|
|
18235
|
-
|
|
18236
|
-
|
|
18237
|
-
|
|
18238
|
-
|
|
18239
|
-
|
|
18240
|
-
|
|
18241
|
-
|
|
18242
|
-
|
|
18243
|
-
|
|
18244
|
-
|
|
18245
|
-
|
|
18246
|
-
|
|
18247
|
-
|
|
18248
|
-
|
|
18249
|
-
|
|
18250
|
-
|
|
18251
|
-
|
|
18252
|
-
|
|
18253
|
-
|
|
18254
|
-
|
|
18255
|
-
|
|
18256
|
-
|
|
18257
|
-
|
|
18258
|
-
|
|
18259
|
-
|
|
18260
|
-
const activated = await continuePreparedCandidate(engine, candidate, void 0, extras);
|
|
18261
|
-
if (!activated.ok) return toolError(activated.text);
|
|
18262
|
-
engine.forgetPlace();
|
|
18263
|
-
engine.forgetPython();
|
|
18264
|
-
if (step === "python") return toolSuccess(activated.text);
|
|
18265
|
-
if (step === "all") {
|
|
18266
|
-
const ready = `${activated.text}
|
|
18267
|
-
\u041A\u0430\u043D\u0434\u0438\u0434\u0430\u0442 \u043F\u043E\u0441\u0442\u0430\u0432\u0438\u043B \u0431\u0438\u0431\u043B\u0438\u043E\u0442\u0435\u043A\u0438 \u043F\u043E \u0441\u0432\u043E\u0435\u043C\u0443 \u0437\u0430\u043C\u043A\u0443 \u0438 \u043F\u0440\u043E\u0448\u0451\u043B env-check. \u0412\u0441\u0451 \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u043E\u0435 \u0433\u043E\u0442\u043E\u0432\u043E.`;
|
|
18268
|
-
const later = await installStep(engine, asked, key, baseUrl, tell);
|
|
18269
|
-
if (later.type === "error") {
|
|
18270
|
-
return toolSuccess(
|
|
18271
|
-
`${ready}
|
|
18272
|
-
|
|
18273
|
-
\u041E\u0441\u0442\u0430\u043B\u044C\u043D\u043E\u0435 \u0444\u043E\u043D\u043E\u043C \u0437\u0430\u0432\u0435\u0441\u0442\u0438 \u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C: ${later.error}
|
|
18274
|
-
\u041C\u043E\u043D\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u044D\u0442\u043E \u043D\u0435 \u043C\u0435\u0448\u0430\u0435\u0442. \u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C: \u043F\u043E\u0437\u043E\u0432\u0438 setup \u0441 what=all \u0435\u0449\u0451 \u0440\u0430\u0437.`
|
|
18275
|
-
);
|
|
18161
|
+
function withCrashReport(crashes) {
|
|
18162
|
+
return (tool) => {
|
|
18163
|
+
if (crashes === null) return tool;
|
|
18164
|
+
const original = tool.execute.bind(tool);
|
|
18165
|
+
return {
|
|
18166
|
+
...tool,
|
|
18167
|
+
async execute(input, ...rest) {
|
|
18168
|
+
crashes.flushSoon();
|
|
18169
|
+
const host = hostFromContext(rest[0]);
|
|
18170
|
+
crashes.noteHost(host);
|
|
18171
|
+
crashes.noteSecrets(secretsOf(input));
|
|
18172
|
+
let result;
|
|
18173
|
+
let faults;
|
|
18174
|
+
try {
|
|
18175
|
+
({ value: result, faults } = await collectInstallFaults(() => original(input, ...rest)));
|
|
18176
|
+
} catch (trouble) {
|
|
18177
|
+
const crash = fromThrown(trouble, "tool", tool.name, input, host);
|
|
18178
|
+
return toolError(await brokenWords(crash, crashes, crashes.submit(crash)));
|
|
18179
|
+
}
|
|
18180
|
+
const install2 = firstInstallCrash(faults);
|
|
18181
|
+
if (install2 !== null) {
|
|
18182
|
+
const crash = { ...install2, where: "tool", tool: tool.name, secrets: secretsOf(input), host };
|
|
18183
|
+
return withNotice(result, await brokenWords(crash, crashes, crashes.submit(crash)));
|
|
18184
|
+
}
|
|
18185
|
+
return caught(result, tool.name, input, host, crashes);
|
|
18276
18186
|
}
|
|
18277
|
-
|
|
18278
|
-
|
|
18279
|
-
|
|
18187
|
+
};
|
|
18188
|
+
};
|
|
18189
|
+
}
|
|
18190
|
+
async function reportInstallFaults(crashes, work) {
|
|
18191
|
+
const { value, faults } = await collectInstallFaults(work);
|
|
18192
|
+
const install2 = firstInstallCrash(faults);
|
|
18193
|
+
if (install2 !== null) {
|
|
18194
|
+
void crashes.submit({ ...install2, stage: `${install2.stage ?? ""} (\u0444\u043E\u043D\u043E\u043C \u043D\u0430 \u0441\u0442\u0430\u0440\u0442\u0435)`, where: "tool", tool: null, secrets: [], host: null });
|
|
18280
18195
|
}
|
|
18281
|
-
|
|
18282
|
-
|
|
18283
|
-
|
|
18284
|
-
|
|
18285
|
-
|
|
18286
|
-
}
|
|
18287
|
-
return toolError(`\u041F\u0438\u0442\u043E\u043D \u043C\u043E\u043D\u0442\u0430\u0436\u0430 \u043F\u043E\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C: ${describeFailure(trouble)}. \u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C: \u043F\u043E\u0432\u0442\u043E\u0440\u0438 setup.`);
|
|
18288
|
-
}
|
|
18196
|
+
return value;
|
|
18197
|
+
}
|
|
18198
|
+
function reportJobFaults(crashes, id, where) {
|
|
18199
|
+
const install2 = firstInstallCrash(jobInstallFaults(id));
|
|
18200
|
+
if (install2 !== null) {
|
|
18201
|
+
void crashes.submit({ ...install2, stage: `${install2.stage ?? ""} (${where})`, where: "job", tool: null, secrets: [], host: null });
|
|
18289
18202
|
}
|
|
18290
|
-
const common = [
|
|
18291
|
-
"--pack",
|
|
18292
|
-
place.pack,
|
|
18293
|
-
"--step",
|
|
18294
|
-
step,
|
|
18295
|
-
...model !== void 0 ? ["--model", model] : [],
|
|
18296
|
-
...consent ? ["--consent"] : []
|
|
18297
|
-
];
|
|
18298
|
-
if (!LONG_STEPS.has(step)) return asToolResult(await engine.command(["env-install", ...common]));
|
|
18299
|
-
const python = await engine.pythonTrouble();
|
|
18300
|
-
if (python !== null) return toolError(python);
|
|
18301
|
-
if (tell !== void 0) for (const line of installLadder(step)) tell(line);
|
|
18302
|
-
const launch = await engine.background({
|
|
18303
|
-
place,
|
|
18304
|
-
executable: engine.enginePython(),
|
|
18305
|
-
// Установка берёт тот же слот тяжёлой работы, а на слоте стоит заслон
|
|
18306
|
-
// подписки в самом движке — без ключа она откажет платящему.
|
|
18307
|
-
key,
|
|
18308
|
-
startJob: [
|
|
18309
|
-
"install-create",
|
|
18310
|
-
"--pack",
|
|
18311
|
-
place.pack,
|
|
18312
|
-
"--step",
|
|
18313
|
-
step,
|
|
18314
|
-
...model !== void 0 ? ["--model", model] : []
|
|
18315
|
-
],
|
|
18316
|
-
args: (id) => [place.consolePy, "env-install", ...common, "--job", id],
|
|
18317
|
-
advice: "\u043F\u043E\u0437\u043E\u0432\u0438 setup \u2014 \u0441\u043A\u043E\u0440\u0435\u0435 \u0432\u0441\u0435\u0433\u043E, \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0430 \u043D\u0435\u043F\u043E\u043B\u043D\u0430\u044F"
|
|
18318
|
-
});
|
|
18319
|
-
if ("refusal" in launch) return toolError(launch.refusal);
|
|
18320
|
-
return toolSuccess(
|
|
18321
|
-
`\u0417\u0430\u0434\u0430\u0447\u0430 ${launch.id}: ${installTitle(step)} (\u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0430, \u0448\u0430\u0433 \xAB${step}\xBB).
|
|
18322
|
-
\u0418\u0434\u0451\u0442 \u043D\u0430 \u043A\u043E\u043C\u043F\u044C\u044E\u0442\u0435\u0440\u0435 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F \u0438 \u043F\u0435\u0440\u0435\u0436\u0438\u0432\u0430\u0435\u0442 \u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u043A \u043F\u0440\u043E\u0433\u0440\u0430\u043C\u043C\u044B. \u041F\u043E\u0437\u043E\u0432\u0438 wait \u0441 job "${launch.id}" \u2014 \u043E\u043D \u043F\u043E\u0434\u043E\u0436\u0434\u0451\u0442 \u0438 \u043F\u043E \u0445\u043E\u0434\u0443 \u0440\u0430\u0441\u0441\u043A\u0430\u0436\u0435\u0442, \u0441\u043A\u043E\u043B\u044C\u043A\u043E \u0441\u043A\u0430\u0447\u0430\u043D\u043E \u0438 \u043E \u0447\u0451\u043C \u043D\u0430\u0434\u043E \u0441\u043F\u0440\u043E\u0441\u0438\u0442\u044C \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430. \u041F\u0435\u0440\u0435\u0441\u043A\u0430\u0437\u044B\u0432\u0430\u0439 \u044D\u0442\u043E \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0443 \u0441\u0440\u0430\u0437\u0443, \u0430 \u043D\u0435 \u0432 \u043A\u043E\u043D\u0446\u0435. ${AWAY_NOTE}`,
|
|
18323
|
-
startedJob({
|
|
18324
|
-
id: launch.id,
|
|
18325
|
-
what: installTitle(step),
|
|
18326
|
-
ahead: installLadder(step).join(" "),
|
|
18327
|
-
message: "\u0418\u0434\u0451\u0442 \u043C\u0438\u043D\u0443\u0442\u0430\u043C\u0438: \u043A\u0430\u0447\u0430\u0435\u0442\u0441\u044F \u0438 \u0441\u043E\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044F \u0442\u043E, \u0447\u0435\u043C \u043C\u043E\u043D\u0442\u0438\u0440\u0443\u0435\u0442\u0441\u044F \u0432\u0438\u0434\u0435\u043E."
|
|
18328
|
-
})
|
|
18329
|
-
);
|
|
18330
18203
|
}
|
|
18331
|
-
function
|
|
18332
|
-
|
|
18204
|
+
function firstInstallCrash(faults) {
|
|
18205
|
+
for (const fault of faults) {
|
|
18206
|
+
const parsed = installCrash(fault);
|
|
18207
|
+
if (parsed !== null) return parsed;
|
|
18208
|
+
}
|
|
18209
|
+
return null;
|
|
18210
|
+
}
|
|
18211
|
+
function withNotice(result, notice) {
|
|
18212
|
+
if (result.type === "error") return { ...result, error: `${result.error}
|
|
18213
|
+
|
|
18214
|
+
${notice}` };
|
|
18215
|
+
return typeof result.content === "string" ? { ...result, content: `${result.content}
|
|
18216
|
+
|
|
18217
|
+
${notice}` } : { ...result, content: [...result.content, { type: "text", text: notice }] };
|
|
18333
18218
|
}
|
|
18334
|
-
async function
|
|
18335
|
-
|
|
18336
|
-
|
|
18337
|
-
return
|
|
18338
|
-
|
|
18339
|
-
);
|
|
18219
|
+
async function caught(result, name, input, host, crashes) {
|
|
18220
|
+
if (result.type === "error") {
|
|
18221
|
+
const parsed2 = pythonCrash(result.error);
|
|
18222
|
+
if (parsed2 === null) return result;
|
|
18223
|
+
const crash2 = { ...parsed2, where: "tool", tool: name, stage: null, secrets: secretsOf(input), host };
|
|
18224
|
+
return toolError(await brokenWords(crash2, crashes, crashes.submit(crash2)));
|
|
18340
18225
|
}
|
|
18341
|
-
|
|
18342
|
-
|
|
18343
|
-
|
|
18344
|
-
|
|
18226
|
+
const job = result.structured;
|
|
18227
|
+
if (job === void 0 || job["contract"] !== JOB_CONTRACT || job["status"] !== "error") return result;
|
|
18228
|
+
const id = typeof job["id"] === "string" ? job["id"] : "";
|
|
18229
|
+
if (!/^[\w.-]{1,80}$/.test(id) || crashes.jobSeen(id)) return result;
|
|
18230
|
+
const fromLog = pythonCrash(jobLogTail(crashes.home, id));
|
|
18231
|
+
const install2 = fromLog === null ? firstInstallCrash(jobInstallFaults(id)) : null;
|
|
18232
|
+
const parsed = fromLog ?? install2;
|
|
18233
|
+
if (parsed === null) return result;
|
|
18234
|
+
crashes.rememberJob(id);
|
|
18235
|
+
const stage = install2?.stage ?? (typeof job["now"] === "string" && job["now"] !== "" ? job["now"] : null);
|
|
18236
|
+
const crash = { ...parsed, where: "job", tool: name, stage, secrets: secretsOf(input), host };
|
|
18237
|
+
return withNotice(result, await brokenWords(crash, crashes, crashes.submit(crash)));
|
|
18238
|
+
}
|
|
18239
|
+
async function brokenWords(crash, crashes, delivery) {
|
|
18240
|
+
const essence = head(scrub(head(crash.essence, 600), crashes.scrubContext(crash.secrets)), 300);
|
|
18241
|
+
const fate = crashes.canSend ? await crashes.outcome(delivery) : "none";
|
|
18242
|
+
return [
|
|
18243
|
+
`\u0421\u043A\u0430\u0436\u0438 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0443 \u0442\u0430\u043A, \u0441\u0432\u043E\u0438\u043C\u0438 \u0441\u043B\u043E\u0432\u0430\u043C\u0438 \u043D\u0435 \u043C\u0435\u043D\u044F\u0439: \xAB${humanWords(fate)}\xBB`,
|
|
18244
|
+
`\u0421\u0443\u0442\u044C \u0434\u043B\u044F \u0442\u0435\u0431\u044F, \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0443 \u043D\u0435 \u0437\u0430\u0447\u0438\u0442\u044B\u0432\u0430\u0439: ${essence}`
|
|
18245
|
+
].join("\n");
|
|
18246
|
+
}
|
|
18247
|
+
function humanWords(fate) {
|
|
18248
|
+
if (fate === "sent") {
|
|
18249
|
+
return `\u041F\u0440\u043E\u0438\u0437\u043E\u0448\u043B\u0430 \u043E\u0448\u0438\u0431\u043A\u0430. \u041E\u0442\u0447\u0451\u0442 \u0443\u0436\u0435 \u043E\u0442\u043F\u0440\u0430\u0432\u043B\u0435\u043D \u0440\u0430\u0437\u0440\u0430\u0431\u043E\u0442\u0447\u0438\u043A\u0430\u043C \u2014 \u043C\u044B \u0435\u0451 \u0438\u0441\u043F\u0440\u0430\u0432\u0438\u043C. \u0415\u0441\u043B\u0438 \u043D\u0443\u0436\u043D\u043E \u0441\u0440\u043E\u0447\u043D\u043E \u2014 \u043D\u0430\u043F\u0438\u0448\u0438 \u043D\u0430\u043C: ${SUPPORT_TOPIC}`;
|
|
18345
18250
|
}
|
|
18346
|
-
|
|
18347
|
-
|
|
18348
|
-
seen({
|
|
18349
|
-
installed: engine.freshVersion(),
|
|
18350
|
-
fresh: decision.what === "nothing" ? null : decision.manifest.version,
|
|
18351
|
-
mb: decision.what === "nothing" ? 0 : tenths(decision.manifest.bytes),
|
|
18352
|
-
status: outcome.ok ? 0 : outcome.status ?? 0,
|
|
18353
|
-
notes: ""
|
|
18354
|
-
});
|
|
18355
|
-
if (decision.what === "nothing") {
|
|
18356
|
-
const ownDir2 = engine.freshVersion();
|
|
18357
|
-
return toolSuccess(
|
|
18358
|
-
!outcome.ok ? `\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0441\u043F\u0440\u043E\u0441\u0438\u0442\u044C, \u0435\u0441\u0442\u044C \u043B\u0438 \u043D\u043E\u0432\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u043D\u0430\u0447\u0438\u043D\u043A\u0438: ${outcome.why}. \u042D\u0442\u043E \u043D\u0435 \u043F\u043E\u043B\u043E\u043C\u043A\u0430: \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u043D\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F (${ownDir2 ?? "\u043D\u0435 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u0430"}) \u0440\u0430\u0431\u043E\u0442\u0430\u0435\u0442 \u043A\u0430\u043A \u0440\u0430\u0431\u043E\u0442\u0430\u043B\u0430.` : `\u041D\u0430\u0447\u0438\u043D\u043A\u0430 \u0441\u0432\u0435\u0436\u0430\u044F: \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u0430 ${ownDir2 ?? "\u043D\u0435\u0442"}, \u043D\u043E\u0432\u0435\u0435 \u043D\u0435 \u0432\u044B\u0448\u043B\u043E.`
|
|
18359
|
-
);
|
|
18251
|
+
if (fate === "queued") {
|
|
18252
|
+
return `\u041F\u0440\u043E\u0438\u0437\u043E\u0448\u043B\u0430 \u043E\u0448\u0438\u0431\u043A\u0430. \u041E\u0442\u0447\u0451\u0442 \u0441\u043E\u0445\u0440\u0430\u043D\u0451\u043D \u0438 \u0443\u0439\u0434\u0451\u0442 \u0440\u0430\u0437\u0440\u0430\u0431\u043E\u0442\u0447\u0438\u043A\u0430\u043C, \u043A\u0430\u043A \u043F\u043E\u044F\u0432\u0438\u0442\u0441\u044F \u0441\u0432\u044F\u0437\u044C, \u2014 \u043C\u044B \u0435\u0451 \u0438\u0441\u043F\u0440\u0430\u0432\u0438\u043C. \u0415\u0441\u043B\u0438 \u043D\u0443\u0436\u043D\u043E \u0441\u0440\u043E\u0447\u043D\u043E \u2014 \u043D\u0430\u043F\u0438\u0448\u0438 \u043D\u0430\u043C: ${SUPPORT_TOPIC}`;
|
|
18360
18253
|
}
|
|
18361
|
-
|
|
18362
|
-
|
|
18363
|
-
|
|
18364
|
-
|
|
18254
|
+
return `\u041F\u0440\u043E\u0438\u0437\u043E\u0448\u043B\u0430 \u043E\u0448\u0438\u0431\u043A\u0430. \u041D\u0430\u043F\u0438\u0448\u0438 \u043D\u0430\u043C, \u043C\u044B \u0440\u0430\u0437\u0431\u0435\u0440\u0451\u043C\u0441\u044F: ${SUPPORT_TOPIC}`;
|
|
18255
|
+
}
|
|
18256
|
+
function watchProcessCrashes(crashes, proc = process, exit = (code) => process.exit(code)) {
|
|
18257
|
+
const fall = (trouble) => {
|
|
18258
|
+
crashes.persist(fromThrown(trouble, "process", null, {}, null));
|
|
18259
|
+
try {
|
|
18260
|
+
process.stderr.write(`naparnik-mcp: \u0443\u043F\u0430\u043B \u043F\u0440\u043E\u0446\u0435\u0441\u0441 \u2014 ${trouble instanceof Error ? trouble.stack ?? trouble.message : String(trouble)}
|
|
18261
|
+
`);
|
|
18262
|
+
} catch {
|
|
18263
|
+
}
|
|
18264
|
+
exit(1);
|
|
18265
|
+
};
|
|
18266
|
+
proc.on("uncaughtException", fall);
|
|
18267
|
+
proc.on("unhandledRejection", fall);
|
|
18268
|
+
crashes.flushSoon();
|
|
18269
|
+
}
|
|
18270
|
+
function fromThrown(trouble, where, tool, input, host) {
|
|
18271
|
+
const error40 = trouble instanceof Error ? trouble : new Error(String(trouble));
|
|
18272
|
+
const errorType = error40.name || error40.constructor.name || "Error";
|
|
18273
|
+
const trace = error40.stack ?? `${errorType}: ${error40.message}`;
|
|
18274
|
+
const frames = jsFrames(trace);
|
|
18275
|
+
return {
|
|
18276
|
+
where,
|
|
18277
|
+
tool,
|
|
18278
|
+
stage: null,
|
|
18279
|
+
errorType,
|
|
18280
|
+
message: error40.message,
|
|
18281
|
+
trace,
|
|
18282
|
+
keep: "head",
|
|
18283
|
+
frames: frames.slice(0, 3).map((f) => `${f.file}:${f.func}`),
|
|
18284
|
+
python: null,
|
|
18285
|
+
secrets: secretsOf(input),
|
|
18286
|
+
host,
|
|
18287
|
+
essence: `${errorType}: ${error40.message}${frames[0] ? ` \u2014 ${frames[0].file}` : ""}`
|
|
18288
|
+
};
|
|
18289
|
+
}
|
|
18290
|
+
function installCrash(fault) {
|
|
18291
|
+
const { stage, trouble } = fault;
|
|
18292
|
+
if (machineCause(trouble)) return null;
|
|
18293
|
+
const said = commandOutput(trouble);
|
|
18294
|
+
if (said.includes(PYTHON_TRACEBACK)) {
|
|
18295
|
+
const parsed = pythonCrash(said);
|
|
18296
|
+
return parsed === null ? null : { ...parsed, stage };
|
|
18365
18297
|
}
|
|
18366
|
-
|
|
18367
|
-
|
|
18368
|
-
|
|
18369
|
-
|
|
18370
|
-
${
|
|
18371
|
-
|
|
18372
|
-
|
|
18298
|
+
const error40 = trouble instanceof Error ? trouble : new Error(String(trouble));
|
|
18299
|
+
const reason = lastMeaningfulLine(said) ?? lastMeaningfulLine(error40.message) ?? error40.name;
|
|
18300
|
+
const command = typeof trouble.cmd === "string" ? trouble.cmd : "";
|
|
18301
|
+
const trace = [
|
|
18302
|
+
command === "" ? "" : `\u043A\u043E\u043C\u0430\u043D\u0434\u0430: ${command}`,
|
|
18303
|
+
said.trim() === "" ? "" : `\u0432\u044B\u0432\u043E\u0434 \u043A\u043E\u043C\u0430\u043D\u0434\u044B:
|
|
18304
|
+
${said.trim().slice(-4e3)}`,
|
|
18305
|
+
error40.stack ?? `${error40.name}: ${error40.message}`
|
|
18306
|
+
].filter((part) => part !== "").join("\n\n");
|
|
18307
|
+
return {
|
|
18308
|
+
stage,
|
|
18309
|
+
errorType: "InstallError",
|
|
18310
|
+
message: `${stage}: ${reason}`,
|
|
18311
|
+
trace,
|
|
18312
|
+
keep: "head",
|
|
18313
|
+
// ⚠ ПРИЧИНА В ОТПЕЧАТКЕ — БЕЗ ПУТЕЙ И ЧИСЕЛ. Иначе все беды шага склеились
|
|
18314
|
+
// бы в один отпечаток, а сервер пишет в бот про отпечаток раз в час: вторая,
|
|
18315
|
+
// другая беда того же шага промолчала бы. А с путями и версиями одна и та
|
|
18316
|
+
// же беда у двух покупателей считалась бы двумя.
|
|
18317
|
+
frames: [`install:${stage}`, reason.replace(/(?:[A-Za-z]:)?[\\/][^\s'"]*/g, "<path>").replace(/\d+/g, "0").slice(0, 160)],
|
|
18318
|
+
python: /python@?(\d)\.(\d{1,2})\b/i.exec(command)?.slice(1, 3).join(".") ?? null,
|
|
18319
|
+
essence: `\u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0430, \u0448\u0430\u0433 ${stage}: ${reason}`
|
|
18320
|
+
};
|
|
18321
|
+
}
|
|
18322
|
+
function machineCause(trouble) {
|
|
18323
|
+
const t = trouble ?? {};
|
|
18324
|
+
if (typeof t.code === "string" && MACHINE_CODES.has(t.code)) return true;
|
|
18325
|
+
if (t.code === 2) return true;
|
|
18326
|
+
if (t.killed === true || typeof t.signal === "string" && t.signal !== "") return true;
|
|
18327
|
+
const text2 = `${typeof t.message === "string" ? t.message : String(trouble)}
|
|
18328
|
+
${commandOutput(trouble)}`;
|
|
18329
|
+
return MACHINE_WORDS.test(text2);
|
|
18330
|
+
}
|
|
18331
|
+
var MACHINE_CODES = /* @__PURE__ */ new Set([
|
|
18332
|
+
"ENOSPC",
|
|
18333
|
+
"EDQUOT",
|
|
18334
|
+
"EACCES",
|
|
18335
|
+
"EPERM",
|
|
18336
|
+
"EROFS",
|
|
18337
|
+
"EBUSY",
|
|
18338
|
+
"ENOTFOUND",
|
|
18339
|
+
"EAI_AGAIN",
|
|
18340
|
+
"ECONNRESET",
|
|
18341
|
+
"ECONNREFUSED",
|
|
18342
|
+
"ETIMEDOUT",
|
|
18343
|
+
"ENETUNREACH",
|
|
18344
|
+
"ENETDOWN",
|
|
18345
|
+
"EHOSTUNREACH"
|
|
18346
|
+
]);
|
|
18347
|
+
var MACHINE_WORDS = new RegExp([
|
|
18348
|
+
"No space left on device",
|
|
18349
|
+
"Disk quota exceeded",
|
|
18350
|
+
"Permission denied",
|
|
18351
|
+
"Operation not permitted",
|
|
18352
|
+
"Read-only file system",
|
|
18353
|
+
"Access is denied",
|
|
18354
|
+
"Temporary failure in name resolution",
|
|
18355
|
+
"Name or service not known",
|
|
18356
|
+
"nodename nor servname",
|
|
18357
|
+
"getaddrinfo",
|
|
18358
|
+
"Network is unreachable",
|
|
18359
|
+
"No route to host",
|
|
18360
|
+
"Connection refused",
|
|
18361
|
+
"Connection reset",
|
|
18362
|
+
"Connection aborted",
|
|
18363
|
+
"timed out",
|
|
18364
|
+
"Max retries exceeded",
|
|
18365
|
+
"NewConnectionError",
|
|
18366
|
+
"ConnectTimeoutError",
|
|
18367
|
+
"ReadTimeoutError",
|
|
18368
|
+
"ProxyError",
|
|
18369
|
+
"CERTIFICATE_VERIFY_FAILED"
|
|
18370
|
+
].map((one) => one.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|"), "i");
|
|
18371
|
+
function commandOutput(trouble) {
|
|
18372
|
+
const t = trouble ?? {};
|
|
18373
|
+
return [t.stderr, t.stdout].filter((one) => typeof one === "string" && one.trim() !== "").join("\n");
|
|
18374
|
+
}
|
|
18375
|
+
function lastMeaningfulLine(text2) {
|
|
18376
|
+
const lines = text2.split("\n").map((one) => one.trim()).filter((one) => one !== "" && !/^Command failed:/.test(one));
|
|
18377
|
+
return lines[lines.length - 1] ?? null;
|
|
18378
|
+
}
|
|
18379
|
+
function jsFrames(stack) {
|
|
18380
|
+
const frames = [];
|
|
18381
|
+
for (const line of stack.split("\n")) {
|
|
18382
|
+
const m = /^\s*at (?:(.+?) \()?(.+?):\d+:\d+\)?\s*$/.exec(line);
|
|
18383
|
+
if (m === null) continue;
|
|
18384
|
+
const file2 = basename(m[2] ?? "").replace(/-[A-Za-z0-9]{6,}(\.[cm]?js)$/, "$1");
|
|
18385
|
+
frames.push({ file: file2, func: m[1] ?? "<anonymous>" });
|
|
18373
18386
|
}
|
|
18374
|
-
return
|
|
18387
|
+
return frames;
|
|
18375
18388
|
}
|
|
18376
|
-
|
|
18377
|
-
|
|
18378
|
-
|
|
18379
|
-
const
|
|
18380
|
-
const
|
|
18381
|
-
const
|
|
18382
|
-
|
|
18383
|
-
|
|
18384
|
-
|
|
18385
|
-
|
|
18386
|
-
|
|
18387
|
-
|
|
18388
|
-
notes: decision.what === "nothing" ? "" : decision.manifest.notes ?? ""
|
|
18389
|
+
function pythonCrash(text2) {
|
|
18390
|
+
const start = text2.lastIndexOf(PYTHON_TRACEBACK);
|
|
18391
|
+
if (start < 0) return null;
|
|
18392
|
+
const block = text2.slice(start).replace(/\s+$/, "");
|
|
18393
|
+
const lines = block.split("\n");
|
|
18394
|
+
const frames = [];
|
|
18395
|
+
let lastFrame = -1;
|
|
18396
|
+
lines.forEach((line, at2) => {
|
|
18397
|
+
const m2 = /^\s*File "(.+)", line (\d+), in (.+)$/.exec(line);
|
|
18398
|
+
if (m2 === null) return;
|
|
18399
|
+
frames.push({ file: m2[1] ?? "", line: m2[2] ?? "", func: (m2[3] ?? "").trim() });
|
|
18400
|
+
lastFrame = at2;
|
|
18389
18401
|
});
|
|
18390
|
-
if (
|
|
18391
|
-
|
|
18392
|
-
|
|
18393
|
-
|
|
18394
|
-
|
|
18395
|
-
|
|
18396
|
-
|
|
18397
|
-
|
|
18398
|
-
|
|
18399
|
-
|
|
18400
|
-
|
|
18401
|
-
|
|
18402
|
-
|
|
18403
|
-
|
|
18404
|
-
|
|
18405
|
-
|
|
18406
|
-
|
|
18407
|
-
|
|
18408
|
-
|
|
18409
|
-
|
|
18410
|
-
|
|
18411
|
-
|
|
18412
|
-
|
|
18402
|
+
if (frames.length === 0) return null;
|
|
18403
|
+
if (frames.some((f) => /[\\/]mine[\\/]steps[\\/]/.test(f.file))) return null;
|
|
18404
|
+
const at = lines.findIndex((line, n) => n > lastFrame && line !== "" && !/^\s/.test(line));
|
|
18405
|
+
if (at < 0) return null;
|
|
18406
|
+
const m = /^([A-Za-z_][\w.]*)(?::\s?(.*))?$/.exec(lines[at] ?? "");
|
|
18407
|
+
if (m === null) return null;
|
|
18408
|
+
const errorType = m[1] ?? "Error";
|
|
18409
|
+
if (/(?:^|\.)(?:KeyboardInterrupt|SystemExit|Explained|Refusal)$/.test(errorType)) return null;
|
|
18410
|
+
const message = [m[2] ?? "", ...lines.slice(at + 1)].join("\n").trim();
|
|
18411
|
+
const innermost = frames[frames.length - 1];
|
|
18412
|
+
const firstLine = message.split("\n")[0] ?? "";
|
|
18413
|
+
return {
|
|
18414
|
+
errorType,
|
|
18415
|
+
message,
|
|
18416
|
+
trace: block,
|
|
18417
|
+
keep: "tail",
|
|
18418
|
+
frames: frames.slice(-3).map((f) => `${basename(f.file.replace(/\\/g, "/"))}:${f.func}`),
|
|
18419
|
+
python: pythonVersionIn(frames.map((f) => f.file)),
|
|
18420
|
+
essence: `${errorType}${firstLine === "" ? "" : `: ${firstLine}`}` + (innermost ? ` \u2014 ${basename(innermost.file.replace(/\\/g, "/"))}:${innermost.line}` : "")
|
|
18421
|
+
};
|
|
18422
|
+
}
|
|
18423
|
+
function pythonVersionIn(files) {
|
|
18424
|
+
for (const file2 of files) {
|
|
18425
|
+
const m = /python(\d)\.?(\d{1,2})[\\/]/i.exec(file2);
|
|
18426
|
+
if (m !== null) return `${m[1]}.${m[2]}`;
|
|
18413
18427
|
}
|
|
18414
|
-
return
|
|
18415
|
-
home,
|
|
18416
|
-
manifest: decision.manifest,
|
|
18417
|
-
key: key ?? null
|
|
18418
|
-
}));
|
|
18428
|
+
return null;
|
|
18419
18429
|
}
|
|
18420
|
-
|
|
18421
|
-
|
|
18422
|
-
|
|
18423
|
-
|
|
18424
|
-
|
|
18425
|
-
|
|
18426
|
-
|
|
18427
|
-
|
|
18428
|
-
|
|
18429
|
-
|
|
18430
|
-
|
|
18431
|
-
|
|
18432
|
-
|
|
18433
|
-
|
|
18434
|
-
|
|
18435
|
-
|
|
18436
|
-
ui: { resourceUri: RUNBAR_RESOURCE_URI },
|
|
18437
|
-
args: external_exports.object({
|
|
18438
|
-
what: external_exports.enum(["all", "engine", "shell", "speech", "cutout", "voice"]).describe(
|
|
18439
|
-
"\u0427\u0442\u043E \u043F\u043E\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u0438\u043B\u0438 \u043E\u0431\u043D\u043E\u0432\u0438\u0442\u044C. all \u2014 \u0432\u0441\u0451 \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u043E\u0435, \u0447\u0435\u0433\u043E \u043D\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442, \u0438 \u043D\u043E\u0432\u044B\u0435 \u0432\u0435\u0440\u0441\u0438\u0438, \u043E \u043A\u043E\u0442\u043E\u0440\u044B\u0445 \u0441\u043A\u0430\u0437\u0430\u043B\u0430 \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0430; engine \u2014 \u0442\u043E\u043B\u044C\u043A\u043E \u043D\u043E\u0432\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u0434\u0432\u0438\u0436\u043A\u0430; shell \u2014 \u0442\u043E\u043B\u044C\u043A\u043E \u043D\u043E\u0432\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u0441\u0430\u043C\u043E\u0433\u043E \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F; speech \u2014 \u0440\u0430\u0441\u043F\u043E\u0437\u043D\u0430\u0432\u0430\u043D\u0438\u0435 \u0440\u0435\u0447\u0438 (\u0441\u0443\u0431\u0442\u0438\u0442\u0440\u044B); cutout \u2014 \u0432\u044B\u0440\u0435\u0437 \u0433\u0435\u0440\u043E\u044F (\u043D\u043E\u0432\u044B\u0439 \u0444\u043E\u043D); voice \u2014 \u0447\u0438\u0441\u0442\u043A\u0430 \u0433\u043E\u043B\u043E\u0441\u0430"
|
|
18440
|
-
).optional(),
|
|
18441
|
-
consent: external_exports.boolean().describe(
|
|
18442
|
-
"\u0427\u0435\u043B\u043E\u0432\u0435\u043A \u0420\u0410\u0417\u0420\u0415\u0428\u0418\u041B \u0441\u043A\u0430\u0447\u0430\u0442\u044C \u0442\u043E, \u0447\u0442\u043E \u043D\u0430\u0437\u0432\u0430\u043D\u043E \u0432 what. \u0421\u0442\u0430\u0432\u044C \u0442\u043E\u043B\u044C\u043A\u043E \u043F\u043E\u0441\u043B\u0435 \u0442\u043E\u0433\u043E, \u043A\u0430\u043A \u043D\u0430\u0437\u0432\u0430\u043B \u0435\u043C\u0443, \u0447\u0442\u043E \u0438 \u0441\u043A\u043E\u043B\u044C\u043A\u043E \u0432\u0435\u0441\u0438\u0442, \u0438 \u043E\u043D \u0441\u043E\u0433\u043B\u0430\u0441\u0438\u043B\u0441\u044F \u2014 \u044D\u0442\u043E \u0435\u0433\u043E \u0442\u0440\u0430\u0444\u0438\u043A \u0438 \u0435\u0433\u043E \u0434\u0438\u0441\u043A"
|
|
18443
|
-
).optional(),
|
|
18444
|
-
model: fromList(
|
|
18445
|
-
passport?.["models"],
|
|
18446
|
-
`\u041C\u043E\u0434\u0435\u043B\u044C \u0440\u0430\u0441\u043F\u043E\u0437\u043D\u0430\u0432\u0430\u043D\u0438\u044F \u0440\u0435\u0447\u0438: \u043A\u0430\u043A\u0443\u044E \u043F\u0440\u043E\u0432\u0435\u0440\u044F\u0442\u044C \u0438\u043B\u0438 \u0441\u0442\u0430\u0432\u0438\u0442\u044C \u0441 what="speech". ${aboutModels(passport)}`
|
|
18447
|
-
).optional(),
|
|
18448
|
-
rollback: external_exports.enum(["engine", "shell"]).describe(
|
|
18449
|
-
"\u0412\u0435\u0440\u043D\u0443\u0442\u044C \u043F\u0440\u0435\u0436\u043D\u044E\u044E \u0432\u0435\u0440\u0441\u0438\u044E: engine \u2014 \u0434\u0432\u0438\u0436\u043E\u043A, shell \u2014 \u0441\u0430\u043C\u043E \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u0435. \u0417\u043E\u0432\u0438, \u043A\u043E\u0433\u0434\u0430 \u043F\u043E\u0441\u043B\u0435 \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u044F \u0447\u0442\u043E-\u0442\u043E \u043F\u0435\u0440\u0435\u0441\u0442\u0430\u043B\u043E \u0440\u0430\u0431\u043E\u0442\u0430\u0442\u044C: \u043F\u0440\u0435\u0436\u043D\u044F\u044F \u043B\u0435\u0436\u0438\u0442 \u043D\u0430 \u0434\u0438\u0441\u043A\u0435 \u0440\u044F\u0434\u043E\u043C. \u0417\u0430\u0440\u0430\u0431\u043E\u0442\u0430\u0435\u0442 \u043F\u043E\u0441\u043B\u0435 \u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u043A\u0430"
|
|
18450
|
-
).optional()
|
|
18451
|
-
// ⚠ СОЧЕТАНИЯ СВЕРЯЮТСЯ В САМОЙ СХЕМЕ, А НЕ В ТЕЛЕ. Так правило видит
|
|
18452
|
-
// сверка аргументов на регистрации, и кривой вызов отбивается до всякой
|
|
18453
|
-
// сети (`tool-args.ts`); в теле оно стало бы правдой, о которой сверка не
|
|
18454
|
-
// знает.
|
|
18455
|
-
}).check((ctx) => {
|
|
18456
|
-
const asked = ctx.value;
|
|
18457
|
-
if (asked.rollback !== void 0 && asked.what !== void 0) {
|
|
18458
|
-
ctx.issues.push({
|
|
18459
|
-
code: "custom",
|
|
18460
|
-
message: "\xABrollback\xBB \u0438 \xABwhat\xBB \u2014 \u0440\u0430\u0437\u043D\u044B\u0435 \u043F\u0440\u043E\u0441\u044C\u0431\u044B: \u043E\u0442\u043A\u0430\u0442 \u0432\u043E\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043F\u0440\u0435\u0436\u043D\u044E\u044E \u0432\u0435\u0440\u0441\u0438\u044E, \u0430 what \u0441\u0442\u0430\u0432\u0438\u0442 \u043D\u043E\u0432\u043E\u0435. \u041F\u043E\u0437\u043E\u0432\u0438 \u0441 \u043E\u0434\u043D\u0438\u043C \u0438\u0437 \u043D\u0438\u0445",
|
|
18461
|
-
input: asked,
|
|
18462
|
-
path: ["rollback"]
|
|
18463
|
-
});
|
|
18464
|
-
}
|
|
18465
|
-
if (asked.consent === true && asked.what === void 0 && asked.rollback === void 0) {
|
|
18466
|
-
ctx.issues.push({
|
|
18467
|
-
code: "custom",
|
|
18468
|
-
message: "\xABconsent\xBB \u0431\u0435\u0437 \xABwhat\xBB: \u043D\u0435 \u0441\u043A\u0430\u0437\u0430\u043D\u043E, \u043D\u0430 \u0447\u0442\u043E \u0441\u043E\u0433\u043B\u0430\u0441\u0438\u043B\u0441\u044F \u0447\u0435\u043B\u043E\u0432\u0435\u043A. \u041D\u0430\u0437\u043E\u0432\u0438 what \u2014 \u0442\u043E, \u0447\u0442\u043E \u0442\u044B \u0435\u043C\u0443 \u043F\u0440\u0435\u0434\u043B\u0430\u0433\u0430\u043B",
|
|
18469
|
-
input: asked,
|
|
18470
|
-
path: ["consent"]
|
|
18471
|
-
});
|
|
18472
|
-
}
|
|
18473
|
-
}),
|
|
18474
|
-
async execute(args, ctx) {
|
|
18475
|
-
const news = { engine: null, shell: null };
|
|
18476
|
-
const said = await answer(args, ctx?.emitProgress, news);
|
|
18477
|
-
return withCard(said, () => setupCard({
|
|
18478
|
-
readiness: null,
|
|
18479
|
-
engine: news.engine ?? { installed: engine.freshVersion(), fresh: null, mb: 0, status: 0, notes: "" },
|
|
18480
|
-
shell: news.shell,
|
|
18481
|
-
note: firstLine(said),
|
|
18482
|
-
shellVersion: VERSION
|
|
18483
|
-
}));
|
|
18484
|
-
}
|
|
18485
|
-
});
|
|
18486
|
-
async function answer(args, tell, news) {
|
|
18487
|
-
if (args.rollback === "engine") return asToolResult(rollback(engine));
|
|
18488
|
-
if (args.rollback === "shell") return asToolResult(rollbackShell(engine.home()));
|
|
18489
|
-
const consent = args.consent === true;
|
|
18490
|
-
const what = args.what;
|
|
18491
|
-
if (what === void 0) return lookAround(engine, args.model, key, baseUrl);
|
|
18492
|
-
if (consent && UPDATES.has(what)) return startUpdate(engine, what, key, baseUrl);
|
|
18493
|
-
if (what === "engine") {
|
|
18494
|
-
return updateEngine(engine, consent, key, baseUrl, ASKED_POINTER_MS, (seen) => {
|
|
18495
|
-
if (!consent) news.engine = seen;
|
|
18496
|
-
});
|
|
18497
|
-
}
|
|
18498
|
-
if (what === "shell") {
|
|
18499
|
-
return updateShell(engine, consent, key, baseUrl, ASKED_POINTER_MS, (seen) => {
|
|
18500
|
-
if (!consent) news.shell = seen;
|
|
18501
|
-
});
|
|
18502
|
-
}
|
|
18503
|
-
if (what === "all") {
|
|
18504
|
-
return lookAround(engine, args.model, key, baseUrl);
|
|
18430
|
+
function jobLogTail(home, id) {
|
|
18431
|
+
const file2 = join(home, "logs", `${id}.log`);
|
|
18432
|
+
let fd = null;
|
|
18433
|
+
try {
|
|
18434
|
+
fd = openSync(file2, "r");
|
|
18435
|
+
const size = fstatSync(fd).size;
|
|
18436
|
+
const length = Math.min(size, JOB_LOG_TAIL);
|
|
18437
|
+
const buffer = Buffer.alloc(length);
|
|
18438
|
+
readSync(fd, buffer, 0, length, size - length);
|
|
18439
|
+
return buffer.toString("utf8");
|
|
18440
|
+
} catch {
|
|
18441
|
+
return "";
|
|
18442
|
+
} finally {
|
|
18443
|
+
if (fd !== null) try {
|
|
18444
|
+
closeSync(fd);
|
|
18445
|
+
} catch {
|
|
18505
18446
|
}
|
|
18506
|
-
const step = HEAVY_STEPS[what];
|
|
18507
|
-
return consent ? installStep(engine, { step, model: args.model, consent: true }, key, baseUrl, tell) : askBeforeHeavy(engine, step, args.model, key, baseUrl);
|
|
18508
18447
|
}
|
|
18509
18448
|
}
|
|
18510
|
-
|
|
18511
|
-
|
|
18512
|
-
|
|
18513
|
-
|
|
18514
|
-
|
|
18515
|
-
|
|
18516
|
-
const
|
|
18517
|
-
|
|
18518
|
-
|
|
18519
|
-
const card = (said, o) => withCard(said, () => setupCard({
|
|
18520
|
-
readiness: o.readiness ?? null,
|
|
18521
|
-
engine: engineNews ?? { installed: engine.freshVersion(), fresh: null, mb: 0, status: 0, notes: "" },
|
|
18522
|
-
shell: shellNews,
|
|
18523
|
-
...o.noEngine === true ? { noEngine: true } : {},
|
|
18524
|
-
...o.noPython === true ? { noPython: true } : {},
|
|
18525
|
-
note: o.note ?? firstLine(said),
|
|
18526
|
-
shellVersion: VERSION
|
|
18527
|
-
}));
|
|
18528
|
-
const shell = updateShell(engine, false, key, baseUrl, NEWS_POINTER_MS, toShell);
|
|
18529
|
-
if (engine.place() === null) {
|
|
18530
|
-
const payload = await installPayload(engine, {
|
|
18531
|
-
consent: false,
|
|
18532
|
-
manifestUrl: manifestUrl(engine, baseUrl),
|
|
18533
|
-
...key !== void 0 ? { key } : {}
|
|
18534
|
-
});
|
|
18535
|
-
return card(together([toolSuccess(payload.text), await shell]), { noEngine: true });
|
|
18449
|
+
function fingerprintOf2(errorType, frames) {
|
|
18450
|
+
return createHash("sha256").update([errorType, ...frames].join("|")).digest("hex").slice(0, 16);
|
|
18451
|
+
}
|
|
18452
|
+
function secretsOf(input, depth = 0, out = []) {
|
|
18453
|
+
if (out.length >= 50 || depth > 4) return out;
|
|
18454
|
+
if (typeof input === "string") out.push(input);
|
|
18455
|
+
else if (Array.isArray(input)) for (const one of input) secretsOf(one, depth + 1, out);
|
|
18456
|
+
else if (typeof input === "object" && input !== null) {
|
|
18457
|
+
for (const one of Object.values(input)) secretsOf(one, depth + 1, out);
|
|
18536
18458
|
}
|
|
18537
|
-
|
|
18538
|
-
if (noPython !== null) {
|
|
18539
|
-
return card(together([
|
|
18540
|
-
toolSuccess(noPython),
|
|
18541
|
-
await updateEngine(engine, false, key, baseUrl, NEWS_POINTER_MS, toEngine),
|
|
18542
|
-
await shell
|
|
18543
|
-
]), { noPython: true });
|
|
18544
|
-
}
|
|
18545
|
-
const [machine, news, own] = await Promise.all([
|
|
18546
|
-
inspectMachine(engine, { model }),
|
|
18547
|
-
updateEngine(engine, false, key, baseUrl, NEWS_POINTER_MS, toEngine),
|
|
18548
|
-
shell
|
|
18549
|
-
]);
|
|
18550
|
-
return card(
|
|
18551
|
-
together([newsForModel(shellNews, engineNews), machine.result, news, own]),
|
|
18552
|
-
{ readiness: machine.readiness, note: firstLine(together([machine.result, news, own])) }
|
|
18553
|
-
);
|
|
18459
|
+
return out;
|
|
18554
18460
|
}
|
|
18555
|
-
function
|
|
18556
|
-
|
|
18557
|
-
|
|
18558
|
-
|
|
18559
|
-
|
|
18560
|
-
|
|
18561
|
-
|
|
18562
|
-
|
|
18563
|
-
|
|
18461
|
+
function recentCalls(home) {
|
|
18462
|
+
try {
|
|
18463
|
+
const text2 = readFileSync(join(home, CALLS_FILE), "utf8").slice(-8192);
|
|
18464
|
+
const names = [];
|
|
18465
|
+
for (const line of text2.split("\n")) {
|
|
18466
|
+
try {
|
|
18467
|
+
const tool = JSON.parse(line).tool;
|
|
18468
|
+
if (typeof tool === "string" && CRASH_TOOL_NAME.test(tool)) names.push(tool);
|
|
18469
|
+
} catch {
|
|
18470
|
+
}
|
|
18471
|
+
}
|
|
18472
|
+
return names.slice(-CRASH_LIMITS.recentCalls);
|
|
18473
|
+
} catch {
|
|
18474
|
+
return [];
|
|
18475
|
+
}
|
|
18564
18476
|
}
|
|
18565
|
-
function
|
|
18566
|
-
|
|
18567
|
-
return
|
|
18477
|
+
function hostFromContext(context) {
|
|
18478
|
+
const host = context?.host;
|
|
18479
|
+
return host !== void 0 && typeof host.name === "string" && typeof host.version === "string" ? host : null;
|
|
18568
18480
|
}
|
|
18569
|
-
function
|
|
18570
|
-
|
|
18571
|
-
return text2.split("\n").map((line) => line.trim()).find((line) => line !== "") ?? "";
|
|
18481
|
+
function hostOf(host) {
|
|
18482
|
+
return host === null ? null : { name: head(host.name, CRASH_LIMITS.hostName), version: head(host.version, CRASH_LIMITS.hostVersion) };
|
|
18572
18483
|
}
|
|
18573
|
-
function
|
|
18574
|
-
const
|
|
18575
|
-
const
|
|
18576
|
-
|
|
18577
|
-
|
|
18578
|
-
|
|
18579
|
-
|
|
18580
|
-
|
|
18581
|
-
|
|
18582
|
-
})
|
|
18583
|
-
const report = setupJobReport(id, engine.home());
|
|
18584
|
-
return toolSuccess(
|
|
18585
|
-
`\u0417\u0430\u0434\u0430\u0447\u0430 ${id}: ${report?.what ?? title}.
|
|
18586
|
-
\u0418\u0434\u0451\u0442 \u043D\u0430 \u043A\u043E\u043C\u043F\u044C\u044E\u0442\u0435\u0440\u0435 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F: \u043F\u0440\u043E\u0432\u0435\u0440\u044E, \u0447\u0442\u043E \u0432\u044B\u0448\u043B\u043E, \u0441\u043A\u0430\u0447\u0430\u044E \u0438 \u043F\u043E\u0441\u0442\u0430\u0432\u043B\u044E. \u041F\u043E\u043B\u043E\u0441\u0430 \u0443 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430 \u043E\u0431\u043D\u043E\u0432\u043B\u044F\u0435\u0442\u0441\u044F \u0441\u0430\u043C\u0430. \u041F\u043E\u0437\u043E\u0432\u0438 wait \u0441 job "` + id + '" \u2014 \u0434\u043E\u0436\u0434\u0451\u0442\u0441\u044F \u0438 \u0441\u043A\u0430\u0436\u0435\u0442, \u0447\u0435\u043C \u043A\u043E\u043D\u0447\u0438\u043B\u043E\u0441\u044C; setup \u043F\u043E\u0432\u0442\u043E\u0440\u043D\u043E \u043D\u0435 \u0437\u043E\u0432\u0438. \u0413\u043E\u0442\u043E\u0432\u043E \u2014 \u043F\u0435\u0440\u0435\u0441\u043A\u0430\u0436\u0438 \u0441\u0442\u0440\u043E\u043A\u0443 \xAB\u0427\u0435\u043B\u043E\u0432\u0435\u043A\u0443\xBB.',
|
|
18587
|
-
report ?? void 0
|
|
18588
|
-
);
|
|
18484
|
+
function probeFfmpeg(home) {
|
|
18485
|
+
const own = join(home, "bin", platform() === "win32" ? "ffmpeg.exe" : "ffmpeg");
|
|
18486
|
+
const program = existsSync(own) ? own : "ffmpeg";
|
|
18487
|
+
return new Promise((done) => {
|
|
18488
|
+
execFile(program, ["-version"], { timeout: 3e3, encoding: "utf8" }, (trouble, stdout) => {
|
|
18489
|
+
if (trouble !== null) return done(null);
|
|
18490
|
+
const m = /^ffmpeg version (\S+)/.exec(stdout);
|
|
18491
|
+
done(m?.[1] ?? null);
|
|
18492
|
+
});
|
|
18493
|
+
});
|
|
18589
18494
|
}
|
|
18590
|
-
|
|
18591
|
-
|
|
18592
|
-
|
|
18593
|
-
|
|
18495
|
+
function ownDir() {
|
|
18496
|
+
try {
|
|
18497
|
+
return dirname(fileURLToPath(import.meta.url));
|
|
18498
|
+
} catch {
|
|
18499
|
+
return "";
|
|
18594
18500
|
}
|
|
18595
|
-
return installStep(engine, { step: "all", consent: true }, key, baseUrl, tell);
|
|
18596
18501
|
}
|
|
18597
|
-
|
|
18502
|
+
function safeUser() {
|
|
18598
18503
|
try {
|
|
18599
|
-
|
|
18600
|
-
return true;
|
|
18504
|
+
return userInfo().username;
|
|
18601
18505
|
} catch {
|
|
18602
|
-
return
|
|
18506
|
+
return "";
|
|
18603
18507
|
}
|
|
18604
18508
|
}
|
|
18605
|
-
|
|
18606
|
-
|
|
18607
|
-
if (place === null) {
|
|
18608
|
-
const payload = await installPayload(engine, {
|
|
18609
|
-
consent: false,
|
|
18610
|
-
manifestUrl: manifestUrl(engine, baseUrl),
|
|
18611
|
-
...key !== void 0 ? { key } : {}
|
|
18612
|
-
});
|
|
18613
|
-
return toolSuccess(payload.text);
|
|
18614
|
-
}
|
|
18615
|
-
const noPython = await engine.pythonTrouble();
|
|
18616
|
-
if (noPython !== null) return toolSuccess(noPython);
|
|
18617
|
-
return asToolResult(await engine.command([
|
|
18618
|
-
"env-install",
|
|
18619
|
-
"--pack",
|
|
18620
|
-
place.pack,
|
|
18621
|
-
"--step",
|
|
18622
|
-
step,
|
|
18623
|
-
...model !== void 0 ? ["--model", model] : []
|
|
18624
|
-
]));
|
|
18509
|
+
function head(text2, max) {
|
|
18510
|
+
return text2.length <= max ? text2 : text2.slice(0, max);
|
|
18625
18511
|
}
|
|
18626
|
-
function
|
|
18627
|
-
|
|
18628
|
-
|
|
18629
|
-
|
|
18630
|
-
}
|
|
18631
|
-
return results.some((one) => one.type === "error") ? toolError(text2) : toolSuccess(text2);
|
|
18512
|
+
function tail(text2, max) {
|
|
18513
|
+
if (text2.length <= max) return text2;
|
|
18514
|
+
const cut = "\u2026(\u043D\u0430\u0447\u0430\u043B\u043E \u043E\u0431\u0440\u0435\u0437\u0430\u043D\u043E)\n";
|
|
18515
|
+
return cut + text2.slice(text2.length - (max - cut.length));
|
|
18632
18516
|
}
|
|
18633
|
-
function
|
|
18634
|
-
|
|
18635
|
-
|
|
18517
|
+
function orNull(value, max) {
|
|
18518
|
+
return value === null || value === "" ? null : head(value, max);
|
|
18519
|
+
}
|
|
18520
|
+
|
|
18521
|
+
// src/update-nudge.ts
|
|
18522
|
+
function usable2(value) {
|
|
18523
|
+
return typeof value === "string" && value !== "";
|
|
18636
18524
|
}
|
|
18525
|
+
var processHook = null;
|
|
18526
|
+
function whenNewerReleased(hook) {
|
|
18527
|
+
processHook = hook;
|
|
18528
|
+
}
|
|
18529
|
+
function createUpdateNudge(parts = {}) {
|
|
18530
|
+
const shell = parts.shell ?? (() => installedShell(new Engine().home()));
|
|
18531
|
+
const installedEngine = parts.installedEngine ?? (() => new Engine().freshVersion());
|
|
18532
|
+
const update = parts.update ?? (() => {
|
|
18533
|
+
processHook?.();
|
|
18534
|
+
});
|
|
18535
|
+
const asked = /* @__PURE__ */ new Set();
|
|
18536
|
+
return (info) => {
|
|
18537
|
+
if (info === null || typeof info !== "object") return null;
|
|
18538
|
+
const safely = (read, fallback) => {
|
|
18539
|
+
try {
|
|
18540
|
+
return read();
|
|
18541
|
+
} catch {
|
|
18542
|
+
return fallback;
|
|
18543
|
+
}
|
|
18544
|
+
};
|
|
18545
|
+
const newShell = usable2(info.shell) && info.shell !== safely(shell, info.shell) ? info.shell : "";
|
|
18546
|
+
const engineNow = safely(installedEngine, null);
|
|
18547
|
+
const newEngine = usable2(info.engine) && engineNow !== null && info.engine !== engineNow ? info.engine : "";
|
|
18548
|
+
if (newShell === "" && newEngine === "") return null;
|
|
18549
|
+
const seen = `${newShell}|${newEngine}`;
|
|
18550
|
+
if (asked.has(seen)) return null;
|
|
18551
|
+
asked.add(seen);
|
|
18552
|
+
update();
|
|
18553
|
+
return null;
|
|
18554
|
+
};
|
|
18555
|
+
}
|
|
18556
|
+
var processUpdateNudge = createUpdateNudge();
|
|
18637
18557
|
var TRIAL_AXES = ["motion", "timing", "place", "camera", "color"];
|
|
18638
18558
|
var TRIALS_MAX = 10;
|
|
18639
18559
|
async function startRender(engine, asked, key, tell) {
|
|
@@ -18704,9 +18624,10 @@ async function startDocumentRender(engine, reel, key, tell, trials = {}) {
|
|
|
18704
18624
|
\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}`,
|
|
18705
18625
|
startedJob({
|
|
18706
18626
|
id: launch.id,
|
|
18707
|
-
|
|
18708
|
-
|
|
18709
|
-
|
|
18627
|
+
// Лестница и заголовок — слова человеку: полоса показывает их как есть.
|
|
18628
|
+
what: human(what),
|
|
18629
|
+
ahead: human(ladder.join(" ")),
|
|
18630
|
+
message: human("\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.")
|
|
18710
18631
|
})
|
|
18711
18632
|
);
|
|
18712
18633
|
}
|
|
@@ -18716,6 +18637,12 @@ var RENDER_LADDER = [
|
|
|
18716
18637
|
];
|
|
18717
18638
|
var TRIALS_STEP = "\u041F\u043E\u0442\u043E\u043C \u0441\u043E\u0431\u0435\u0440\u0443 \u0432\u0435\u0440\u0441\u0438\u0438 \u0434\u043B\u044F \u043F\u0440\u043E\u0431\u043D\u043E\u0433\u043E \u0440\u0435\u0436\u0438\u043C\u0430 \u043F\u043E \u043E\u0434\u043D\u043E\u0439: \u0440\u0435\u0447\u044C \u0438 \u0437\u0432\u0443\u043A \u0442\u0435 \u0436\u0435, \u0434\u0440\u0443\u0433\u043E\u0435 \u0434\u0432\u0438\u0436\u0435\u043D\u0438\u0435, \u043C\u0435\u0441\u0442\u0430 \u0438 \u043A\u0440\u0443\u043F\u043D\u043E\u0441\u0442\u044C.";
|
|
18718
18639
|
async function followWork(engine, asked, pace = realPace, tell) {
|
|
18640
|
+
const result = await followAny(engine, asked, pace, tell);
|
|
18641
|
+
if (!isSetupJob(asked.job) || result.type !== "success") return result;
|
|
18642
|
+
const report = setupJobReport(asked.job, engine.home());
|
|
18643
|
+
return report === null ? result : { ...result, structured: report };
|
|
18644
|
+
}
|
|
18645
|
+
async function followAny(engine, asked, pace, tell) {
|
|
18719
18646
|
const ask2 = async () => {
|
|
18720
18647
|
if (!isSetupJob(asked.job)) return engine.command(["job", asked.job]);
|
|
18721
18648
|
const text2 = setupJobText(asked.job, Date.now, engine.home());
|
|
@@ -19509,14 +19436,14 @@ var FONTS_CONTRACT = "naparnik-fonts/1";
|
|
|
19509
19436
|
var CAPABILITIES_CONTRACT2 = "naparnik-capabilities/1";
|
|
19510
19437
|
var OWN_STYLE_FOLDER = "style";
|
|
19511
19438
|
function contractRefusal(theirs) {
|
|
19512
|
-
return `\u0414\u0432\u0438\u0436\u043E\u043A \u0433\u043E\u0432\u043E\u0440\u0438\u0442 \u043D\u0430 \u0434\u043E\u0433\u043E\u0432\u043E\u0440\u0435 \xAB${theirs}\xBB, \u0430 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u0435 \u043F\u043E\u043D\u0438\u043C\u0430\u0435\u0442 \xAB${CHOICES_CONTRACT}\xBB. \u041E\u0431\u043D\u043E\u0432\u0438 \
|
|
19439
|
+
return `\u0414\u0432\u0438\u0436\u043E\u043A \u0433\u043E\u0432\u043E\u0440\u0438\u0442 \u043D\u0430 \u0434\u043E\u0433\u043E\u0432\u043E\u0440\u0435 \xAB${theirs}\xBB, \u0430 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u0435 \u043F\u043E\u043D\u0438\u043C\u0430\u0435\u0442 \xAB${CHOICES_CONTRACT}\xBB. \u041E\u0431\u043D\u043E\u0432\u0438 \u043C\u043E\u043D\u0442\u0430\u0436: install \u0441 what=all \u2014 \u043F\u043E\u0441\u0442\u0430\u0432\u0438\u0442 \u043D\u043E\u0432\u044B\u0435 \u0432\u0435\u0440\u0441\u0438\u0438 \u0434\u0432\u0438\u0436\u043A\u0430 \u0438 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F.`;
|
|
19513
19440
|
}
|
|
19514
19441
|
function notJson(text2) {
|
|
19515
19442
|
const head2 = text2.trim().slice(0, 160).replace(/\s+/g, " ");
|
|
19516
19443
|
return NOT_JSON2 + (head2 ? `
|
|
19517
19444
|
\u0427\u0442\u043E \u043F\u0440\u0438\u0448\u043B\u043E \u0432\u043C\u0435\u0441\u0442\u043E JSON: \xAB${head2}\u2026\xBB` : "");
|
|
19518
19445
|
}
|
|
19519
|
-
var NOT_JSON2 = "\u0414\u0432\u0438\u0436\u043E\u043A \u043E\u0442\u0432\u0435\u0442\u0438\u043B \u043D\u0435 \u0442\u0435\u043C, \u0447\u0435\u0433\u043E \u0436\u0434\u0430\u043B\u0438. \u041E\u0431\u043D\u043E\u0432\u0438 \
|
|
19446
|
+
var NOT_JSON2 = "\u0414\u0432\u0438\u0436\u043E\u043A \u043E\u0442\u0432\u0435\u0442\u0438\u043B \u043D\u0435 \u0442\u0435\u043C, \u0447\u0435\u0433\u043E \u0436\u0434\u0430\u043B\u0438. \u041E\u0431\u043D\u043E\u0432\u0438 \u043C\u043E\u043D\u0442\u0430\u0436 \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u043E\u043C install \u0441 what=all \u0438 \u043F\u043E\u0432\u0442\u043E\u0440\u0438.";
|
|
19520
19447
|
var FIRST_BATCH = 12;
|
|
19521
19448
|
var ALL_OF_THEM = 1e3;
|
|
19522
19449
|
var SAID_LIMIT = 6;
|
|
@@ -19669,7 +19596,7 @@ async function fontsBranch(engine, alphabet) {
|
|
|
19669
19596
|
);
|
|
19670
19597
|
}
|
|
19671
19598
|
return toolError(
|
|
19672
|
-
"\u0412 \u043D\u0430\u0431\u043E\u0440\u0435 \u043D\u0435 \u043D\u0430\u0448\u043B\u043E\u0441\u044C \u043D\u0438 \u043E\u0434\u043D\u043E\u0433\u043E \u0448\u0440\u0438\u0444\u0442\u0430. \u041E\u0431\u043D\u043E\u0432\u0438 \u043D\u0430\u0447\u0438\u043D\u043A\u0443 \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u043E\u043C
|
|
19599
|
+
"\u0412 \u043D\u0430\u0431\u043E\u0440\u0435 \u043D\u0435 \u043D\u0430\u0448\u043B\u043E\u0441\u044C \u043D\u0438 \u043E\u0434\u043D\u043E\u0433\u043E \u0448\u0440\u0438\u0444\u0442\u0430. \u041E\u0431\u043D\u043E\u0432\u0438 \u043D\u0430\u0447\u0438\u043D\u043A\u0443 \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u043E\u043C install \u0441 what=all: \u043F\u043E\u0445\u043E\u0436\u0435, \u043E\u043D\u0430 \u0440\u0430\u0441\u043F\u0430\u043A\u043E\u0432\u0430\u043D\u0430 \u0441\u0442\u0430\u0440\u043E\u0439 \u0432\u0435\u0440\u0441\u0438\u0435\u0439."
|
|
19673
19600
|
);
|
|
19674
19601
|
}
|
|
19675
19602
|
const short = listed.map((one) => ({
|
|
@@ -22629,40 +22556,6 @@ function chooseWidgetHtml() {
|
|
|
22629
22556
|
</html>`;
|
|
22630
22557
|
}
|
|
22631
22558
|
|
|
22632
|
-
// src/update-nudge.ts
|
|
22633
|
-
function usable2(value) {
|
|
22634
|
-
return typeof value === "string" && value !== "";
|
|
22635
|
-
}
|
|
22636
|
-
function createUpdateNudge(parts = {}) {
|
|
22637
|
-
const shell = parts.shell ?? VERSION;
|
|
22638
|
-
const installedEngine = parts.installedEngine ?? (() => new Engine().currentVersion());
|
|
22639
|
-
let said = false;
|
|
22640
|
-
return (info) => {
|
|
22641
|
-
if (said || info === null || typeof info !== "object") return null;
|
|
22642
|
-
const lines = [];
|
|
22643
|
-
if (usable2(info.shell) && info.shell !== shell) {
|
|
22644
|
-
lines.push(`\u0412\u044B\u0448\u043B\u043E \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0435 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F ${info.shell} \u2014 \u043E\u0431\u043D\u043E\u0432\u0438\u0442\u044C: setup \u0441 what=shell (\u0441\u043F\u0440\u043E\u0441\u0438 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430)`);
|
|
22645
|
-
}
|
|
22646
|
-
if (usable2(info.engine)) {
|
|
22647
|
-
let installed = null;
|
|
22648
|
-
try {
|
|
22649
|
-
installed = installedEngine();
|
|
22650
|
-
} catch {
|
|
22651
|
-
installed = null;
|
|
22652
|
-
}
|
|
22653
|
-
if (installed !== null && installed !== info.engine) {
|
|
22654
|
-
lines.push(
|
|
22655
|
-
`\u0412\u044B\u0448\u043B\u043E \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0435 \u0434\u0432\u0438\u0436\u043A\u0430 \u043C\u043E\u043D\u0442\u0430\u0436\u0430 ${info.engine} \u2014 \u043E\u0431\u043D\u043E\u0432\u0438\u0442\u044C: setup \u0441 what=engine (\u0441\u043F\u0440\u043E\u0441\u0438 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430)`
|
|
22656
|
-
);
|
|
22657
|
-
}
|
|
22658
|
-
}
|
|
22659
|
-
if (lines.length === 0) return null;
|
|
22660
|
-
said = true;
|
|
22661
|
-
return lines.join("\n");
|
|
22662
|
-
};
|
|
22663
|
-
}
|
|
22664
|
-
var processUpdateNudge = createUpdateNudge();
|
|
22665
|
-
|
|
22666
22559
|
// src/subscription.ts
|
|
22667
22560
|
var TOO_OFTEN = 429;
|
|
22668
22561
|
var STATUS_PATH = SDK_SUBSCRIPTION_STATUS_PATH;
|
|
@@ -22793,6 +22686,9 @@ function buildAll(client, engine, passport, key, baseUrl, pace = realPace, awake
|
|
|
22793
22686
|
// Порядок — это порядок работы, и модель читает список сверху вниз:
|
|
22794
22687
|
// проверить машину, придумать словами, поправить словами, собрать, дождаться.
|
|
22795
22688
|
setupTool(engine, passport, key, baseUrl),
|
|
22689
|
+
// Ставит — отдельной дверью с окном-полосой: у `setup` окна нет, и одно
|
|
22690
|
+
// «скачай» даёт одну задачу и одно окно (владелец 2026-09-25).
|
|
22691
|
+
installTool(engine, passport, key, baseUrl),
|
|
22796
22692
|
planTool(engine, key),
|
|
22797
22693
|
planEditTool(engine, key),
|
|
22798
22694
|
renderTool(engine, passport, key),
|
|
@@ -23026,4 +22922,4 @@ ${inTable}`, file2);
|
|
|
23026
22922
|
};
|
|
23027
22923
|
}
|
|
23028
22924
|
|
|
23029
|
-
export { CrashReporter, DEFAULT_HOME, DeliveryError, Engine, ForeignBlockError, INSTALL_STEPS, KEEP_COPIES, KEEP_VERSIONS, LOCK_FILE, LONG_STEPS, MANIFEST_TIMEOUT_MS, MANIFEST_URL, MARKER, MIN_ENGINE, McpServer, NaparnikApiClient, NaparnikAuthError, NaparnikClientError, NaparnikConfigError, NaparnikError, NaparnikInsufficientBalanceError, NaparnikScopeError, NaparnikServerError, NaparnikTimeoutError, PAUSE_HOURS, SERVER_NAME, START_SEC, StdioServerTransport, TOOL_SEC, USER_AGENT, VERSION, WHERE_TO_GET_KEY, Wakefulness, bringPython, buildAll, buildBlock, buildResources,
|
|
22925
|
+
export { CrashReporter, DEFAULT_HOME, DeliveryError, Engine, ForeignBlockError, INSTALL_STEPS, KEEP_COPIES, KEEP_VERSIONS, LOCK_FILE, LONG_STEPS, MANIFEST_TIMEOUT_MS, MANIFEST_URL, MARKER, MIN_ENGINE, McpServer, NaparnikApiClient, NaparnikAuthError, NaparnikClientError, NaparnikConfigError, NaparnikError, NaparnikInsufficientBalanceError, NaparnikScopeError, NaparnikServerError, NaparnikTimeoutError, PAUSE_HOURS, SERVER_NAME, START_SEC, StdioServerTransport, TITLE_UPDATE, TOOL_SEC, USER_AGENT, VERSION, WHERE_TO_GET_KEY, Wakefulness, bringPython, buildAll, buildBlock, buildResources, chooseBody, compare, configPath, currentMachineFingerprint, decide, defineTool, depFolderName, deploy, describeFailure, downloadFile, fetchManifest, fileOrRefusal, findBlock, forModel, fromHost, fromNpxCache, handOverToBody, inside, install, installMissing, installPayload, installStep, installedShell, jsonSchemaOf, keyFromBlock, keyInTable, lastLine, loadConfig, lockedPython, markChecked2 as markChecked, markCurrent2 as markCurrent, noteInstallFault, ownSetupJobRunning, parseEngineManifest, parseFailure, path, platformKey, previousVersion2 as previousVersion, probe, readConfig, realPace, refusalFor, remove, reportInstallFaults, reportJobFaults, rollback, rollbackShell, runUpdate, setupJobDone, setupJobEnding, shellDir, startSetupJob, systemBlocker, tarEntries, tidyOld2 as tidyOld, timeToCheck2 as timeToCheck, toolError, unpackArchive, updateEngine, watchProcessCrashes, whenNewerReleased, withArgs };
|