@naparnik/mcp 0.10.22 → 0.10.25
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 +23 -0
- package/dist/{chunk-KWTLR6D2.js → chunk-F5B2GHZW.js} +1072 -293
- package/dist/cli.js +26 -12
- package/dist/index.d.ts +842 -633
- package/dist/index.js +1 -1
- package/package.json +1 -1
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { createHash, randomBytes, randomUUID } from 'crypto';
|
|
2
1
|
import { execFile, spawn, execFileSync } from 'child_process';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
2
|
+
import { createHash, randomBytes, randomUUID } from 'crypto';
|
|
3
|
+
import { existsSync, readFileSync, closeSync, mkdirSync, openSync, readdirSync, statSync, rmSync, writeFileSync, renameSync, symlinkSync, chmodSync, lstatSync, realpathSync, mkdtempSync, linkSync, readlinkSync, appendFileSync, fstatSync, readSync, fsyncSync } from 'fs';
|
|
4
|
+
import { platform, homedir, arch, release, userInfo, tmpdir } from 'os';
|
|
5
|
+
import { win32, join, dirname, sep, resolve, relative, isAbsolute, basename, extname } from 'path';
|
|
6
6
|
import { promisify } from 'util';
|
|
7
7
|
import { gunzipSync } from 'zlib';
|
|
8
|
-
import { pathToFileURL } from 'url';
|
|
8
|
+
import { pathToFileURL, fileURLToPath } from 'url';
|
|
9
9
|
import { readFile } from 'fs/promises';
|
|
10
10
|
|
|
11
11
|
var __defProp = Object.defineProperty;
|
|
@@ -176,12 +176,12 @@ var StdioServerTransport = class {
|
|
|
176
176
|
throw new McpError(McpErrorCode.InternalError, "Stdio-\u0442\u0440\u0430\u043D\u0441\u043F\u043E\u0440\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u043D\u0435 \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0451\u043D");
|
|
177
177
|
}
|
|
178
178
|
const line = encodeNdjsonLine(message);
|
|
179
|
-
await new Promise((
|
|
179
|
+
await new Promise((resolve5, reject) => {
|
|
180
180
|
let settled = false;
|
|
181
181
|
const done = () => {
|
|
182
182
|
if (settled) return;
|
|
183
183
|
settled = true;
|
|
184
|
-
|
|
184
|
+
resolve5();
|
|
185
185
|
};
|
|
186
186
|
const flushed = process.stdout.write(line, "utf8", (err) => {
|
|
187
187
|
if (err !== null && err !== void 0) {
|
|
@@ -412,6 +412,13 @@ var McpServer = class {
|
|
|
412
412
|
* Обрабатывает запрос инициализации.
|
|
413
413
|
*/
|
|
414
414
|
handleInitialize(params) {
|
|
415
|
+
const client = params?.["clientInfo"];
|
|
416
|
+
if (typeof client?.name === "string") {
|
|
417
|
+
this.toolContext = {
|
|
418
|
+
...this.toolContext,
|
|
419
|
+
host: { name: client.name, version: typeof client.version === "string" ? client.version : "" }
|
|
420
|
+
};
|
|
421
|
+
}
|
|
415
422
|
const clientVersion = params?.["protocolVersion"];
|
|
416
423
|
const negotiatedVersion = typeof clientVersion === "string" && clientVersion.length > 0 ? clientVersion : MCP_PROTOCOL_VERSION;
|
|
417
424
|
return {
|
|
@@ -658,8 +665,8 @@ function describeFailure(err) {
|
|
|
658
665
|
const bottom = err.cause;
|
|
659
666
|
if (bottom instanceof Error) {
|
|
660
667
|
const code = bottom.code;
|
|
661
|
-
const
|
|
662
|
-
return err.message ===
|
|
668
|
+
const tail2 = typeof code === "string" ? `${code}: ${bottom.message}` : bottom.message;
|
|
669
|
+
return err.message === tail2 || tail2 === "" ? err.message : `${err.message} (${tail2})`;
|
|
663
670
|
}
|
|
664
671
|
return err.message;
|
|
665
672
|
}
|
|
@@ -679,8 +686,8 @@ function loadConfig(env = process.env) {
|
|
|
679
686
|
throw new NaparnikConfigError(state.message);
|
|
680
687
|
}
|
|
681
688
|
function fromHost(value) {
|
|
682
|
-
const
|
|
683
|
-
return /^\$\{[^}]*\}$/.test(
|
|
689
|
+
const text2 = (value ?? "").trim();
|
|
690
|
+
return /^\$\{[^}]*\}$/.test(text2) ? "" : text2;
|
|
684
691
|
}
|
|
685
692
|
function readConfig(env = process.env) {
|
|
686
693
|
const apiKey = fromHost(env["NAPARNIK_API_KEY"]);
|
|
@@ -720,7 +727,7 @@ function parsePositiveInt(raw, fallback) {
|
|
|
720
727
|
}
|
|
721
728
|
|
|
722
729
|
// src/version.ts
|
|
723
|
-
var VERSION = "0.10.
|
|
730
|
+
var VERSION = "0.10.25";
|
|
724
731
|
var USER_AGENT = `naparnik-mcp/${VERSION}`;
|
|
725
732
|
var MIN_ENGINE = "2026.09.23-406";
|
|
726
733
|
var LAUNCHER_PROTOCOL = 1;
|
|
@@ -890,9 +897,9 @@ var NaparnikApiClient = class {
|
|
|
890
897
|
return headers;
|
|
891
898
|
}
|
|
892
899
|
async parse(response, shape = {}) {
|
|
893
|
-
let
|
|
900
|
+
let text2;
|
|
894
901
|
try {
|
|
895
|
-
|
|
902
|
+
text2 = await response.text();
|
|
896
903
|
} catch (err) {
|
|
897
904
|
throw new NaparnikServerError(
|
|
898
905
|
`\u0421\u043E\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u0435 \u043E\u0431\u043E\u0440\u0432\u0430\u043B\u043E\u0441\u044C \u043F\u0440\u0438 \u0447\u0442\u0435\u043D\u0438\u0438 \u043E\u0442\u0432\u0435\u0442\u0430 \u041D\u0430\u043F\u0430\u0440\u043D\u0438\u043A\u0430: ${describe(err)}`,
|
|
@@ -900,15 +907,15 @@ var NaparnikApiClient = class {
|
|
|
900
907
|
);
|
|
901
908
|
}
|
|
902
909
|
if (response.ok) {
|
|
903
|
-
if (shape.wantText === true) return
|
|
904
|
-
if (
|
|
910
|
+
if (shape.wantText === true) return text2;
|
|
911
|
+
if (text2 === "") return {};
|
|
905
912
|
try {
|
|
906
|
-
return JSON.parse(
|
|
913
|
+
return JSON.parse(text2);
|
|
907
914
|
} catch {
|
|
908
|
-
throw new NaparnikServerError("\u041D\u0430\u043F\u0430\u0440\u043D\u0438\u043A \u0432\u0435\u0440\u043D\u0443\u043B \u043D\u0435\u043A\u043E\u0440\u0440\u0435\u043A\u0442\u043D\u044B\u0439 JSON", response.status, truncate(
|
|
915
|
+
throw new NaparnikServerError("\u041D\u0430\u043F\u0430\u0440\u043D\u0438\u043A \u0432\u0435\u0440\u043D\u0443\u043B \u043D\u0435\u043A\u043E\u0440\u0440\u0435\u043A\u0442\u043D\u044B\u0439 JSON", response.status, truncate(text2));
|
|
909
916
|
}
|
|
910
917
|
}
|
|
911
|
-
const payload = safeJson(
|
|
918
|
+
const payload = safeJson(text2);
|
|
912
919
|
switch (response.status) {
|
|
913
920
|
// ⚠ ЗАПАСНЫЕ ТЕКСТЫ ЗДЕСЬ ВЕЛИ В ПАНЕЛЬ, КОТОРОЙ НЕТ, и молча: обычно
|
|
914
921
|
// сервер присылает свой текст, и эти строки видны только когда 401
|
|
@@ -940,20 +947,20 @@ var NaparnikApiClient = class {
|
|
|
940
947
|
throw new NaparnikServerError(
|
|
941
948
|
`\u041D\u0430\u043F\u0430\u0440\u043D\u0438\u043A \u043E\u0442\u0432\u0435\u0442\u0438\u043B \u043E\u0448\u0438\u0431\u043A\u043E\u0439 ${response.status}. \u042D\u0442\u043E \u0432\u0440\u0435\u043C\u0435\u043D\u043D\u044B\u0439 \u0441\u0431\u043E\u0439 \u043D\u0430 \u043D\u0430\u0448\u0435\u0439 \u0441\u0442\u043E\u0440\u043E\u043D\u0435.`,
|
|
942
949
|
response.status,
|
|
943
|
-
truncate(
|
|
950
|
+
truncate(text2)
|
|
944
951
|
);
|
|
945
952
|
}
|
|
946
953
|
throw new NaparnikClientError(
|
|
947
954
|
messageFrom(payload) ?? `\u0417\u0430\u043F\u0440\u043E\u0441 \u043E\u0442\u043A\u043B\u043E\u043D\u0451\u043D (${response.status}).`,
|
|
948
955
|
response.status,
|
|
949
|
-
truncate(
|
|
956
|
+
truncate(text2)
|
|
950
957
|
);
|
|
951
958
|
}
|
|
952
959
|
}
|
|
953
960
|
};
|
|
954
|
-
function safeJson(
|
|
961
|
+
function safeJson(text2) {
|
|
955
962
|
try {
|
|
956
|
-
return JSON.parse(
|
|
963
|
+
return JSON.parse(text2);
|
|
957
964
|
} catch {
|
|
958
965
|
return null;
|
|
959
966
|
}
|
|
@@ -970,17 +977,17 @@ function messageFrom(payload) {
|
|
|
970
977
|
function numberOr(value, fallback) {
|
|
971
978
|
return typeof value === "number" && Number.isFinite(value) ? value : fallback;
|
|
972
979
|
}
|
|
973
|
-
function truncate(
|
|
974
|
-
return
|
|
980
|
+
function truncate(text2, limit = 500) {
|
|
981
|
+
return text2.length > limit ? `${text2.slice(0, limit)}\u2026` : text2;
|
|
975
982
|
}
|
|
976
983
|
function networkHint(err) {
|
|
977
|
-
const
|
|
984
|
+
const text2 = describeFailure(err);
|
|
978
985
|
const proxy = ["HTTPS_PROXY", "https_proxy", "HTTP_PROXY", "http_proxy"].find((i) => (process.env[i] ?? "").trim() !== "");
|
|
979
986
|
if (proxy !== void 0) {
|
|
980
987
|
return `
|
|
981
988
|
\u041D\u0430 \u044D\u0442\u043E\u0439 \u043C\u0430\u0448\u0438\u043D\u0435 \u0437\u0430\u0434\u0430\u043D ${proxy}, \u043D\u043E Node \u043D\u0435 \u0445\u043E\u0434\u0438\u0442 \u0447\u0435\u0440\u0435\u0437 \u043F\u0440\u043E\u043A\u0441\u0438 \u0441\u0430\u043C \u2014 \u0437\u0430\u043F\u0440\u043E\u0441 \u0443\u0448\u0451\u043B \u043D\u0430\u043F\u0440\u044F\u043C\u0443\u044E. \u0415\u0441\u043B\u0438 \u0432\u044B\u0445\u043E\u0434 \u0432 \u0438\u043D\u0442\u0435\u0440\u043D\u0435\u0442 \u0442\u043E\u043B\u044C\u043A\u043E \u0447\u0435\u0440\u0435\u0437 \u043F\u0440\u043E\u043A\u0441\u0438, \u043D\u0443\u0436\u0435\u043D Node 24 \u0438\u043B\u0438 \u043D\u043E\u0432\u0435\u0435 \u0441 NODE_USE_ENV_PROXY=1.`;
|
|
982
989
|
}
|
|
983
|
-
if (/CERT|SELF_SIGNED|UNABLE_TO_VERIFY/i.test(
|
|
990
|
+
if (/CERT|SELF_SIGNED|UNABLE_TO_VERIFY/i.test(text2)) {
|
|
984
991
|
return "\n\u041F\u043E\u0445\u043E\u0436\u0435 \u043D\u0430 \u043F\u0435\u0440\u0435\u0445\u0432\u0430\u0442 TLS (\u043A\u043E\u0440\u043F\u043E\u0440\u0430\u0442\u0438\u0432\u043D\u044B\u0439 \u0430\u043D\u0442\u0438\u0432\u0438\u0440\u0443\u0441 \u0438\u043B\u0438 \u043F\u0440\u043E\u043A\u0441\u0438). \u041F\u0443\u0442\u044C \u043A \u043A\u043E\u0440\u043D\u0435\u0432\u043E\u043C\u0443 \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u0443 \u043E\u0440\u0433\u0430\u043D\u0438\u0437\u0430\u0446\u0438\u0438 \u0437\u0430\u0434\u0430\u0451\u0442\u0441\u044F \u043F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u043E\u0439 NODE_EXTRA_CA_CERTS.";
|
|
985
992
|
}
|
|
986
993
|
return "";
|
|
@@ -989,7 +996,175 @@ function describe(err) {
|
|
|
989
996
|
return describeFailure(err);
|
|
990
997
|
}
|
|
991
998
|
function sleep(ms) {
|
|
992
|
-
return new Promise((
|
|
999
|
+
return new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
1000
|
+
}
|
|
1001
|
+
var TAIL_MS = 10 * 6e4;
|
|
1002
|
+
var AWAY_NOTE = "\u0421\u043A\u0430\u0436\u0438 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0443: \u043C\u043E\u0436\u043D\u043E \u043E\u0442\u043E\u0439\u0442\u0438, \u043A\u043E\u043C\u043F\u044C\u044E\u0442\u0435\u0440 \u043D\u0435 \u0443\u0441\u043D\u0451\u0442, \u043F\u043E\u043A\u0430 \u0438\u0434\u0451\u0442 \u0440\u0430\u0431\u043E\u0442\u0430. \u0422\u043E\u043B\u044C\u043A\u043E \u043A\u0440\u044B\u0448\u043A\u0443 \u043D\u043E\u0443\u0442\u0431\u0443\u043A\u0430 \u043D\u0435 \u0437\u0430\u043A\u0440\u044B\u0432\u0430\u0442\u044C.";
|
|
1003
|
+
var realClock = {
|
|
1004
|
+
now: () => Date.now(),
|
|
1005
|
+
later(ms, fire) {
|
|
1006
|
+
const timer = setTimeout(fire, ms);
|
|
1007
|
+
timer.unref();
|
|
1008
|
+
return () => clearTimeout(timer);
|
|
1009
|
+
}
|
|
1010
|
+
};
|
|
1011
|
+
var Wakefulness = class {
|
|
1012
|
+
constructor(blocker, opts = {}) {
|
|
1013
|
+
this.blocker = blocker;
|
|
1014
|
+
this.clock = opts.clock ?? realClock;
|
|
1015
|
+
this.pid = opts.pid ?? process.pid;
|
|
1016
|
+
this.tailMs = opts.tailMs ?? TAIL_MS;
|
|
1017
|
+
}
|
|
1018
|
+
blocker;
|
|
1019
|
+
holders = /* @__PURE__ */ new Set();
|
|
1020
|
+
until = 0;
|
|
1021
|
+
lamp = null;
|
|
1022
|
+
/**
|
|
1023
|
+
* Система однажды лампу не дала — больше не просим. Иначе каждый вызов
|
|
1024
|
+
* пытался бы заново запустить то, чего нет, а работа человека важнее.
|
|
1025
|
+
*/
|
|
1026
|
+
refused = false;
|
|
1027
|
+
cancelTail = null;
|
|
1028
|
+
clock;
|
|
1029
|
+
pid;
|
|
1030
|
+
tailMs;
|
|
1031
|
+
/** Держать компьютер бодрым; вернуть снятие. Снять второй раз — ничего не делает. */
|
|
1032
|
+
hold() {
|
|
1033
|
+
const token = /* @__PURE__ */ Symbol("hold");
|
|
1034
|
+
this.holders.add(token);
|
|
1035
|
+
this.sync();
|
|
1036
|
+
return () => {
|
|
1037
|
+
if (!this.holders.delete(token)) return;
|
|
1038
|
+
this.until = Math.max(this.until, this.clock.now() + this.tailMs);
|
|
1039
|
+
this.sync();
|
|
1040
|
+
};
|
|
1041
|
+
}
|
|
1042
|
+
/**
|
|
1043
|
+
* Держать, пока идёт работа, — и когда она кончилась успехом, и когда упала.
|
|
1044
|
+
*
|
|
1045
|
+
* ⚠ Работа — функцией, а не готовым обещанием. Обещание уже запущено: тело
|
|
1046
|
+
* async-функции до первого await идёт при вычислении аргумента, и начало
|
|
1047
|
+
* работы оставалось без лампы (тест обёртки поймал ровно это).
|
|
1048
|
+
*/
|
|
1049
|
+
async during(work) {
|
|
1050
|
+
const release2 = this.hold();
|
|
1051
|
+
try {
|
|
1052
|
+
return await work();
|
|
1053
|
+
} finally {
|
|
1054
|
+
release2();
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
/**
|
|
1058
|
+
* Своя лампа для фоновой работы, привязанная к её процессу. Гаснет сама, когда
|
|
1059
|
+
* работа кончилась, — даже если нас к тому времени уже закрыли.
|
|
1060
|
+
*/
|
|
1061
|
+
follow(pid) {
|
|
1062
|
+
if (this.refused) return;
|
|
1063
|
+
try {
|
|
1064
|
+
if (this.blocker(pid) === null) this.refused = true;
|
|
1065
|
+
} catch {
|
|
1066
|
+
this.refused = true;
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
sync() {
|
|
1070
|
+
const want = this.holders.size > 0 || this.clock.now() < this.until;
|
|
1071
|
+
if (want && this.lamp === null && !this.refused) this.light();
|
|
1072
|
+
if (!want && this.lamp !== null) {
|
|
1073
|
+
this.lamp.stop();
|
|
1074
|
+
this.lamp = null;
|
|
1075
|
+
}
|
|
1076
|
+
this.cancelTail?.();
|
|
1077
|
+
this.cancelTail = null;
|
|
1078
|
+
if (this.holders.size === 0 && want) {
|
|
1079
|
+
this.cancelTail = this.clock.later(this.until - this.clock.now(), () => this.sync());
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
light() {
|
|
1083
|
+
let lamp;
|
|
1084
|
+
try {
|
|
1085
|
+
lamp = this.blocker(this.pid);
|
|
1086
|
+
} catch {
|
|
1087
|
+
lamp = null;
|
|
1088
|
+
}
|
|
1089
|
+
if (lamp === null) {
|
|
1090
|
+
this.refused = true;
|
|
1091
|
+
return;
|
|
1092
|
+
}
|
|
1093
|
+
this.lamp = lamp;
|
|
1094
|
+
lamp.onExit(() => {
|
|
1095
|
+
if (this.lamp === lamp) this.lamp = null;
|
|
1096
|
+
});
|
|
1097
|
+
}
|
|
1098
|
+
};
|
|
1099
|
+
var ASLEEP = new Wakefulness(() => null);
|
|
1100
|
+
function systemBlocker(platform4 = process.platform, run = spawn, env = process.env) {
|
|
1101
|
+
return (pid) => {
|
|
1102
|
+
let command;
|
|
1103
|
+
let args;
|
|
1104
|
+
if (platform4 === "darwin") {
|
|
1105
|
+
command = "/usr/bin/caffeinate";
|
|
1106
|
+
args = ["-i", "-w", String(pid)];
|
|
1107
|
+
} else if (platform4 === "win32") {
|
|
1108
|
+
command = `${env["SystemRoot"] ?? "C:\\Windows"}\\System32\\WindowsPowerShell\\v1.0\\powershell.exe`;
|
|
1109
|
+
args = [
|
|
1110
|
+
"-NoProfile",
|
|
1111
|
+
"-NonInteractive",
|
|
1112
|
+
"-WindowStyle",
|
|
1113
|
+
"Hidden",
|
|
1114
|
+
// Закодированным, а не строкой: в тексте кавычки из C#, и Windows
|
|
1115
|
+
// склеивает их с кавычками командной строки непредсказуемо.
|
|
1116
|
+
"-EncodedCommand",
|
|
1117
|
+
Buffer.from(windowsScript(pid), "utf16le").toString("base64")
|
|
1118
|
+
];
|
|
1119
|
+
} else {
|
|
1120
|
+
return null;
|
|
1121
|
+
}
|
|
1122
|
+
const child = run(command, args, {
|
|
1123
|
+
stdio: "ignore",
|
|
1124
|
+
windowsHide: true,
|
|
1125
|
+
detached: false
|
|
1126
|
+
});
|
|
1127
|
+
child.unref();
|
|
1128
|
+
let exited = false;
|
|
1129
|
+
const listeners = [];
|
|
1130
|
+
const gone = () => {
|
|
1131
|
+
if (exited) return;
|
|
1132
|
+
exited = true;
|
|
1133
|
+
for (const cb of listeners) cb();
|
|
1134
|
+
};
|
|
1135
|
+
child.on("error", gone);
|
|
1136
|
+
child.on("exit", gone);
|
|
1137
|
+
return {
|
|
1138
|
+
stop() {
|
|
1139
|
+
try {
|
|
1140
|
+
child.kill();
|
|
1141
|
+
} catch {
|
|
1142
|
+
}
|
|
1143
|
+
},
|
|
1144
|
+
onExit(cb) {
|
|
1145
|
+
if (exited) cb();
|
|
1146
|
+
else listeners.push(cb);
|
|
1147
|
+
}
|
|
1148
|
+
};
|
|
1149
|
+
};
|
|
1150
|
+
}
|
|
1151
|
+
function windowsScript(pid) {
|
|
1152
|
+
return [
|
|
1153
|
+
`$t = Add-Type -Name Power -Namespace Naparnik -PassThru -MemberDefinition '[DllImport("kernel32.dll")] public static extern uint SetThreadExecutionState(uint f);'`,
|
|
1154
|
+
"[void]$t::SetThreadExecutionState([uint32]2147483649)",
|
|
1155
|
+
`Wait-Process -Id ${pid} -ErrorAction SilentlyContinue`
|
|
1156
|
+
].join("\n");
|
|
1157
|
+
}
|
|
1158
|
+
function withWakefulness(awake) {
|
|
1159
|
+
return (tool) => {
|
|
1160
|
+
const original = tool.execute.bind(tool);
|
|
1161
|
+
return {
|
|
1162
|
+
...tool,
|
|
1163
|
+
async execute(input, ...rest) {
|
|
1164
|
+
return awake.during(() => original(input, ...rest));
|
|
1165
|
+
}
|
|
1166
|
+
};
|
|
1167
|
+
};
|
|
993
1168
|
}
|
|
994
1169
|
var FINGERPRINT_VERSION = "mid1";
|
|
995
1170
|
var MIN_ID_LENGTH = 8;
|
|
@@ -1185,10 +1360,12 @@ function montageEnv(base, key) {
|
|
|
1185
1360
|
};
|
|
1186
1361
|
}
|
|
1187
1362
|
var Engine = class {
|
|
1188
|
-
constructor(env = process.env) {
|
|
1363
|
+
constructor(env = process.env, awake = ASLEEP) {
|
|
1189
1364
|
this.env = env;
|
|
1365
|
+
this.awake = awake;
|
|
1190
1366
|
}
|
|
1191
1367
|
env;
|
|
1368
|
+
awake;
|
|
1192
1369
|
passportCache;
|
|
1193
1370
|
versionAtStart;
|
|
1194
1371
|
pythonChecked;
|
|
@@ -1576,6 +1753,7 @@ var Engine = class {
|
|
|
1576
1753
|
} catch {
|
|
1577
1754
|
}
|
|
1578
1755
|
}
|
|
1756
|
+
if (child.pid !== void 0) this.awake.follow(child.pid);
|
|
1579
1757
|
this.watch(child, opts.place, id, opts.advice, log.file);
|
|
1580
1758
|
return { id };
|
|
1581
1759
|
}
|
|
@@ -1627,7 +1805,7 @@ var Engine = class {
|
|
|
1627
1805
|
});
|
|
1628
1806
|
});
|
|
1629
1807
|
child.on("close", (code, signal) => {
|
|
1630
|
-
const
|
|
1808
|
+
const tail2 = logTail();
|
|
1631
1809
|
if (signal) {
|
|
1632
1810
|
void this.run(place, [
|
|
1633
1811
|
"job-abort",
|
|
@@ -1635,17 +1813,17 @@ var Engine = class {
|
|
|
1635
1813
|
"--signal",
|
|
1636
1814
|
String(signal),
|
|
1637
1815
|
"--tail",
|
|
1638
|
-
lastLines(
|
|
1816
|
+
lastLines(tail2)
|
|
1639
1817
|
]).catch(() => {
|
|
1640
1818
|
});
|
|
1641
1819
|
return;
|
|
1642
1820
|
}
|
|
1643
|
-
if (code === 0 || code === 2 || code === 3 ||
|
|
1821
|
+
if (code === 0 || code === 2 || code === 3 || tail2.trim() === "") return;
|
|
1644
1822
|
void this.run(place, [
|
|
1645
1823
|
"job-fail",
|
|
1646
1824
|
id,
|
|
1647
1825
|
"--what",
|
|
1648
|
-
lastLines(
|
|
1826
|
+
lastLines(tail2),
|
|
1649
1827
|
"--what-to-do",
|
|
1650
1828
|
"\u043F\u043E\u043A\u0430\u0436\u0438 \u044D\u0442\u043E \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0443 \u0446\u0435\u043B\u0438\u043A\u043E\u043C"
|
|
1651
1829
|
]).catch(() => {
|
|
@@ -1696,8 +1874,8 @@ function lastLine(output) {
|
|
|
1696
1874
|
const lines = output.trim().split("\n");
|
|
1697
1875
|
return (lines[lines.length - 1] ?? "").trim();
|
|
1698
1876
|
}
|
|
1699
|
-
function lastLines(
|
|
1700
|
-
return
|
|
1877
|
+
function lastLines(text2, howMany) {
|
|
1878
|
+
return text2.trim().split("\n").slice(-8).join("\n");
|
|
1701
1879
|
}
|
|
1702
1880
|
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 \u0434\u0432\u0438\u0436\u043E\u043A \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u043E\u043C setup \u0441 what=engine \u0438 \u043F\u043E\u0432\u0442\u043E\u0440\u0438.";
|
|
1703
1881
|
|
|
@@ -13301,19 +13479,19 @@ function acquireVersionLock(dir, hooks = {}) {
|
|
|
13301
13479
|
};
|
|
13302
13480
|
}
|
|
13303
13481
|
async function withVersionLock(dir, work, hooks = {}) {
|
|
13304
|
-
const
|
|
13482
|
+
const release2 = acquireVersionLock(dir, hooks);
|
|
13305
13483
|
try {
|
|
13306
13484
|
return await work();
|
|
13307
13485
|
} finally {
|
|
13308
|
-
|
|
13486
|
+
release2();
|
|
13309
13487
|
}
|
|
13310
13488
|
}
|
|
13311
13489
|
function withVersionLockSync(dir, work) {
|
|
13312
|
-
const
|
|
13490
|
+
const release2 = acquireVersionLock(dir);
|
|
13313
13491
|
try {
|
|
13314
13492
|
return work();
|
|
13315
13493
|
} finally {
|
|
13316
|
-
|
|
13494
|
+
release2();
|
|
13317
13495
|
}
|
|
13318
13496
|
}
|
|
13319
13497
|
var PUBLICATION_FILE = ".publication.json";
|
|
@@ -13922,7 +14100,7 @@ function preparedCandidateAfterBootstrap(engine, before) {
|
|
|
13922
14100
|
}
|
|
13923
14101
|
return { ok: true, candidate, place };
|
|
13924
14102
|
}
|
|
13925
|
-
function blockCandidate(dir, candidate,
|
|
14103
|
+
function blockCandidate(dir, candidate, text2) {
|
|
13926
14104
|
if (!sameCandidateState(readCandidate(dir), candidate)) {
|
|
13927
14105
|
return {
|
|
13928
14106
|
ok: false,
|
|
@@ -13932,7 +14110,7 @@ function blockCandidate(dir, candidate, text) {
|
|
|
13932
14110
|
writeCandidate(dir, { ...candidate, state: "blocked" });
|
|
13933
14111
|
return {
|
|
13934
14112
|
ok: false,
|
|
13935
|
-
text:
|
|
14113
|
+
text: text2.includes("\u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C:") ? text2 : `${text2}
|
|
13936
14114
|
\u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C: \u0438\u0441\u043F\u0440\u0430\u0432\u044C\u0442\u0435 \u0443\u043A\u0430\u0437\u0430\u043D\u043D\u0443\u044E \u043F\u0440\u0438\u0447\u0438\u043D\u0443 \u0438 \u043F\u043E\u0432\u0442\u043E\u0440\u0438\u0442\u0435 setup.`
|
|
13937
14115
|
};
|
|
13938
14116
|
}
|
|
@@ -13986,9 +14164,9 @@ async function prepareCopiedCandidateVenv(engine, dir, version2, place) {
|
|
|
13986
14164
|
if (engine.prepareCandidateVenv !== void 0) {
|
|
13987
14165
|
await engine.prepareCandidateVenv(place);
|
|
13988
14166
|
} else {
|
|
13989
|
-
const { execFile:
|
|
14167
|
+
const { execFile: execFile4 } = await import('child_process');
|
|
13990
14168
|
const { promisify: promisify3 } = await import('util');
|
|
13991
|
-
await promisify3(
|
|
14169
|
+
await promisify3(execFile4)(engine.bootstrapPython(), ["-m", "venv", "--copies", venv], {
|
|
13992
14170
|
timeout: 10 * 6e4,
|
|
13993
14171
|
encoding: "utf8",
|
|
13994
14172
|
env: { ...engine.pythonEnv(), PYTHONDONTWRITEBYTECODE: "1" }
|
|
@@ -14004,7 +14182,7 @@ async function prepareCopiedCandidateVenv(engine, dir, version2, place) {
|
|
|
14004
14182
|
}
|
|
14005
14183
|
async function candidatePipReady(engine, python) {
|
|
14006
14184
|
if (engine.candidatePipReady !== void 0) return engine.candidatePipReady(python);
|
|
14007
|
-
const { execFile:
|
|
14185
|
+
const { execFile: execFile4 } = await import('child_process');
|
|
14008
14186
|
const { promisify: promisify3 } = await import('util');
|
|
14009
14187
|
const env = { ...engine.pythonEnv(), PYTHONDONTWRITEBYTECODE: "1" };
|
|
14010
14188
|
delete env["PYTHONHOME"];
|
|
@@ -14012,7 +14190,7 @@ async function candidatePipReady(engine, python) {
|
|
|
14012
14190
|
delete env["VIRTUAL_ENV"];
|
|
14013
14191
|
delete env["__PYVENV_LAUNCHER__"];
|
|
14014
14192
|
try {
|
|
14015
|
-
await promisify3(
|
|
14193
|
+
await promisify3(execFile4)(python, ["-B", "-m", "pip", "--version"], {
|
|
14016
14194
|
timeout: 6e4,
|
|
14017
14195
|
encoding: "utf8",
|
|
14018
14196
|
env
|
|
@@ -14324,9 +14502,9 @@ async function dryRun(engine, build, expected, trial) {
|
|
|
14324
14502
|
}
|
|
14325
14503
|
}
|
|
14326
14504
|
async function probe(engine, consolePy) {
|
|
14327
|
-
const { execFile:
|
|
14505
|
+
const { execFile: execFile4 } = await import('child_process');
|
|
14328
14506
|
const { promisify: promisify3 } = await import('util');
|
|
14329
|
-
return promisify3(
|
|
14507
|
+
return promisify3(execFile4)(engine.enginePython(), [consolePy, "version"], {
|
|
14330
14508
|
timeout: 6e4,
|
|
14331
14509
|
encoding: "utf8",
|
|
14332
14510
|
env: engine.pythonEnv()
|
|
@@ -14508,8 +14686,8 @@ function fieldLine(header, start, length) {
|
|
|
14508
14686
|
return chunk.subarray(0, end === -1 ? chunk.length : end).toString("utf8");
|
|
14509
14687
|
}
|
|
14510
14688
|
function octal(header, start, length) {
|
|
14511
|
-
const
|
|
14512
|
-
const ch = Number.parseInt(
|
|
14689
|
+
const text2 = fieldLine(header, start, length).trim();
|
|
14690
|
+
const ch = Number.parseInt(text2, 8);
|
|
14513
14691
|
return Number.isFinite(ch) ? ch : 0;
|
|
14514
14692
|
}
|
|
14515
14693
|
function fieldSize(header, start, length) {
|
|
@@ -14769,7 +14947,7 @@ var probeShell = async (entry) => {
|
|
|
14769
14947
|
encoding: "utf8",
|
|
14770
14948
|
env
|
|
14771
14949
|
});
|
|
14772
|
-
await new Promise((
|
|
14950
|
+
await new Promise((resolve5, reject) => {
|
|
14773
14951
|
const child = spawn(process.execPath, [entry], { stdio: ["pipe", "pipe", "pipe"], env });
|
|
14774
14952
|
let output = "";
|
|
14775
14953
|
let errors = "";
|
|
@@ -14780,7 +14958,7 @@ var probeShell = async (entry) => {
|
|
|
14780
14958
|
finished = true;
|
|
14781
14959
|
clearTimeout(timer);
|
|
14782
14960
|
child.kill();
|
|
14783
|
-
if (trouble === void 0)
|
|
14961
|
+
if (trouble === void 0) resolve5();
|
|
14784
14962
|
else reject(trouble);
|
|
14785
14963
|
};
|
|
14786
14964
|
const send = (message) => {
|
|
@@ -15116,10 +15294,10 @@ function recoverInterruptedPublication(dir) {
|
|
|
15116
15294
|
\u041E\u043D\u0430 \u0435\u0449\u0451 \u043D\u0435 \u0440\u0430\u0431\u043E\u0447\u0430\u044F: setup \u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0438\u0442 \u044D\u0442\u043E\u0442 \u043A\u0430\u043D\u0434\u0438\u0434\u0430\u0442 \u0438 \u0441\u043D\u0430\u0447\u0430\u043B\u0430 \u0441\u043E\u0431\u0435\u0440\u0451\u0442 \u0435\u0433\u043E \u043E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u0435.`
|
|
15117
15295
|
};
|
|
15118
15296
|
}
|
|
15119
|
-
function platformKey(os = process.platform,
|
|
15120
|
-
if (os === "darwin") return
|
|
15121
|
-
if (os === "win32") return
|
|
15122
|
-
if (os === "linux") return
|
|
15297
|
+
function platformKey(os = process.platform, arch2 = process.arch) {
|
|
15298
|
+
if (os === "darwin") return arch2 === "arm64" ? "Darwin-arm64" : arch2 === "x64" ? "Darwin-x86_64" : null;
|
|
15299
|
+
if (os === "win32") return arch2 === "x64" ? "Windows-AMD64" : null;
|
|
15300
|
+
if (os === "linux") return arch2 === "x64" ? "Linux-x86_64" : arch2 === "arm64" ? "Linux-aarch64" : null;
|
|
15123
15301
|
return null;
|
|
15124
15302
|
}
|
|
15125
15303
|
function pythonSource(engineDir, key = platformKey()) {
|
|
@@ -15382,9 +15560,276 @@ function safePythonDirectory(home, pythonDir) {
|
|
|
15382
15560
|
}
|
|
15383
15561
|
}
|
|
15384
15562
|
function troubleText(what, trouble) {
|
|
15385
|
-
const
|
|
15563
|
+
const tail2 = trouble instanceof DeliveryError ? trouble.message : trouble instanceof Error ? trouble.message : String(trouble);
|
|
15386
15564
|
return `${what}, \u043D\u0438\u0447\u0435\u0433\u043E \u043D\u0435 \u043C\u0435\u043D\u044F\u043B.
|
|
15387
|
-
${
|
|
15565
|
+
${tail2}` + (tail2.includes("\u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C:") ? "" : "\n\u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C: \u0438\u0441\u043F\u0440\u0430\u0432\u044C\u0442\u0435 \u0443\u043A\u0430\u0437\u0430\u043D\u043D\u0443\u044E \u043F\u0440\u0438\u0447\u0438\u043D\u0443 \u0438 \u043F\u043E\u0432\u0442\u043E\u0440\u0438\u0442\u0435 setup.");
|
|
15566
|
+
}
|
|
15567
|
+
|
|
15568
|
+
// src/progress.ts
|
|
15569
|
+
var realPace = {
|
|
15570
|
+
now: () => Date.now(),
|
|
15571
|
+
rest: (ms) => new Promise((done) => {
|
|
15572
|
+
setTimeout(done, ms);
|
|
15573
|
+
})
|
|
15574
|
+
};
|
|
15575
|
+
var WAIT_LIMIT_SECONDS = 55;
|
|
15576
|
+
var POLL_EVERY_MS = 2e3;
|
|
15577
|
+
var JOB_STILL_COMPUTING = "\u0415\u0449\u0451 \u0441\u0447\u0438\u0442\u0430\u0435\u0442";
|
|
15578
|
+
var JOB_IN_QUEUE = "\u0416\u0434\u0451\u0442 \u043E\u0447\u0435\u0440\u0435\u0434\u0438";
|
|
15579
|
+
function stillWorking(text2) {
|
|
15580
|
+
return text2.includes(JOB_STILL_COMPUTING) || text2.includes(JOB_IN_QUEUE);
|
|
15581
|
+
}
|
|
15582
|
+
function waitSeconds(asked) {
|
|
15583
|
+
if (asked === void 0 || !Number.isFinite(asked) || asked <= 0) return 0;
|
|
15584
|
+
return Math.min(Math.round(asked), WAIT_LIMIT_SECONDS);
|
|
15585
|
+
}
|
|
15586
|
+
function freshLines(text2, told) {
|
|
15587
|
+
const news = [];
|
|
15588
|
+
for (const row of text2.split("\n").slice(1)) {
|
|
15589
|
+
const line = row.trim();
|
|
15590
|
+
if (line.length === 0) continue;
|
|
15591
|
+
if (line.startsWith(JOB_STILL_COMPUTING)) continue;
|
|
15592
|
+
if (told.has(line)) continue;
|
|
15593
|
+
told.add(line);
|
|
15594
|
+
news.push(line);
|
|
15595
|
+
}
|
|
15596
|
+
return news;
|
|
15597
|
+
}
|
|
15598
|
+
async function followJob(opts) {
|
|
15599
|
+
const pace = opts.pace ?? realPace;
|
|
15600
|
+
const until = pace.now() + opts.seconds * 1e3;
|
|
15601
|
+
const told = /* @__PURE__ */ new Set();
|
|
15602
|
+
let state = await opts.ask();
|
|
15603
|
+
retell(state, told, opts.tell);
|
|
15604
|
+
while (state.ok && stillWorking(state.text) && pace.now() < until) {
|
|
15605
|
+
await pace.rest(POLL_EVERY_MS);
|
|
15606
|
+
try {
|
|
15607
|
+
state = await opts.ask();
|
|
15608
|
+
} catch {
|
|
15609
|
+
continue;
|
|
15610
|
+
}
|
|
15611
|
+
retell(state, told, opts.tell);
|
|
15612
|
+
}
|
|
15613
|
+
return state;
|
|
15614
|
+
}
|
|
15615
|
+
function retell(state, told, tell) {
|
|
15616
|
+
if (tell === void 0) return;
|
|
15617
|
+
for (const line of freshLines(state.text, told)) tell(line);
|
|
15618
|
+
}
|
|
15619
|
+
var STAGE_WORDS = {
|
|
15620
|
+
silence: "\u0443\u0431\u0435\u0440\u0443 \u043F\u0430\u0443\u0437\u044B",
|
|
15621
|
+
voice: "\u0432\u044B\u0440\u043E\u0432\u043D\u044F\u044E \u0433\u043E\u043B\u043E\u0441",
|
|
15622
|
+
speech: "\u0440\u0430\u0441\u043F\u043E\u0437\u043D\u0430\u044E \u0440\u0435\u0447\u044C",
|
|
15623
|
+
phrases: "\u0440\u0430\u0437\u043B\u043E\u0436\u0443 \u0440\u0435\u0447\u044C \u043D\u0430 \u0444\u0440\u0430\u0437\u044B",
|
|
15624
|
+
plan: "\u043F\u0440\u0438\u0434\u0443\u043C\u0430\u044E, \u0447\u0442\u043E \u043F\u043E\u043A\u0430\u0437\u0430\u0442\u044C \u0438 \u043A\u043E\u0433\u0434\u0430",
|
|
15625
|
+
world: "\u043D\u0430\u0440\u0438\u0441\u0443\u044E \u0444\u043E\u043D \u0437\u0430 \u0433\u0435\u0440\u043E\u0435\u043C",
|
|
15626
|
+
cutout: "\u043E\u0442\u0434\u0435\u043B\u044E \u0433\u0435\u0440\u043E\u044F \u043E\u0442 \u0444\u043E\u043D\u0430",
|
|
15627
|
+
"hero-on-world": "\u043F\u043E\u0441\u0442\u0430\u0432\u043B\u044E \u0433\u0435\u0440\u043E\u044F \u043D\u0430 \u0444\u043E\u043D",
|
|
15628
|
+
shots: "\u0440\u0430\u0441\u0441\u0442\u0430\u0432\u043B\u044E \u043A\u0440\u0443\u043F\u043D\u043E\u0441\u0442\u0438 \u043F\u043E \u043F\u043B\u0430\u043D\u0443",
|
|
15629
|
+
screen: "\u0432\u0441\u0442\u0430\u0432\u043B\u044E \u0437\u0430\u043F\u0438\u0441\u044C \u044D\u043A\u0440\u0430\u043D\u0430",
|
|
15630
|
+
inserts: "\u043D\u0430\u0440\u0438\u0441\u0443\u044E \u0433\u0440\u0430\u0444\u0438\u043A\u0443 \u043F\u043E \u043F\u043B\u0430\u043D\u0443",
|
|
15631
|
+
subtitles: "\u043D\u0430\u0440\u0438\u0441\u0443\u044E \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u044B",
|
|
15632
|
+
layers: "\u043F\u043E\u043B\u043E\u0436\u0443 \u043A\u0430\u0440\u0442\u0438\u043D\u043A\u0438 \u043F\u043E\u0432\u0435\u0440\u0445",
|
|
15633
|
+
accents: "\u0440\u0430\u0441\u0441\u0442\u0430\u0432\u043B\u044E \u0437\u0432\u0443\u043A\u043E\u0432\u044B\u0435 \u0430\u043A\u0446\u0435\u043D\u0442\u044B",
|
|
15634
|
+
mix: "\u0441\u0432\u0435\u0434\u0443 \u0437\u0432\u0443\u043A",
|
|
15635
|
+
intro: "\u043F\u043E\u0441\u0442\u0430\u0432\u043B\u044E \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0443 \u0432 \u043D\u0430\u0447\u0430\u043B\u043E"
|
|
15636
|
+
};
|
|
15637
|
+
var NEAR_STEPS = 3;
|
|
15638
|
+
function montageLadder(stages) {
|
|
15639
|
+
const words = stages.map((stage) => STAGE_WORDS[stage]).filter((word) => word !== void 0);
|
|
15640
|
+
if (words.length === 0) return [];
|
|
15641
|
+
const near = words.slice(0, NEAR_STEPS);
|
|
15642
|
+
const far = words.slice(NEAR_STEPS);
|
|
15643
|
+
const lines = [`\u0421\u043D\u0430\u0447\u0430\u043B\u0430 ${near.join(", \u043F\u043E\u0442\u043E\u043C ")}.`];
|
|
15644
|
+
if (far.length > 0) {
|
|
15645
|
+
lines.push(
|
|
15646
|
+
`\u0414\u0430\u043B\u044C\u0448\u0435: ${far.join(", ")}. \u0428\u0430\u0433\u043E\u0432 \u0432\u0441\u0435\u0433\u043E \u0434\u043E ${stages.length} \u2014 \u0447\u0442\u043E \u043D\u0435 \u043F\u043E\u043D\u0430\u0434\u043E\u0431\u0438\u0442\u0441\u044F, \u043F\u0440\u043E\u043F\u0443\u0449\u0443.`
|
|
15647
|
+
);
|
|
15648
|
+
}
|
|
15649
|
+
return lines;
|
|
15650
|
+
}
|
|
15651
|
+
var PAUSES_LADDER = [
|
|
15652
|
+
"\u0423\u0431\u0435\u0440\u0443 \u043C\u043E\u043B\u0447\u0430\u043D\u0438\u0435 \u0438 \u0437\u0430\u043F\u0438\u043D\u043A\u0438 \u2014 \u0431\u043E\u043B\u044C\u0448\u0435 \u043D\u0438\u0447\u0435\u0433\u043E \u043D\u0435 \u0442\u0440\u043E\u0433\u0430\u044E.",
|
|
15653
|
+
"\u0421\u0443\u0431\u0442\u0438\u0442\u0440\u044B, \u043A\u0430\u0440\u0442\u0438\u043D\u043A\u0438 \u043F\u043E\u0432\u0435\u0440\u0445 \u0438 \u0437\u0432\u0443\u043A \u2014 \u044D\u0442\u043E \u043E\u0442\u0434\u0435\u043B\u044C\u043D\u0430\u044F \u0440\u0430\u0431\u043E\u0442\u0430, \u0435\u0451 \u0437\u0434\u0435\u0441\u044C \u043D\u0435\u0442."
|
|
15654
|
+
];
|
|
15655
|
+
var PAYLOAD_LADDER = [
|
|
15656
|
+
"\u0421\u043D\u0430\u0447\u0430\u043B\u0430 \u043F\u043E\u043B\u043E\u0436\u0443 \u0434\u0432\u0438\u0436\u043E\u043A \u043C\u043E\u043D\u0442\u0430\u0436\u0430 \u043E\u0434\u043D\u043E\u0439 \u043F\u0430\u043F\u043A\u043E\u0439 \u2014 \u0432 \u0441\u0438\u0441\u0442\u0435\u043C\u0443 \u043D\u0438\u0447\u0435\u0433\u043E \u043D\u0435 \u0441\u0442\u0430\u0432\u0438\u0442\u0441\u044F.",
|
|
15657
|
+
"\u041F\u043E\u0442\u043E\u043C ffmpeg, python \u0438 \u043E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u0435 \u043C\u043E\u043D\u0442\u0430\u0436\u0430. \u0422\u044F\u0436\u0451\u043B\u043E\u0435 \u2014 \u0440\u0430\u0441\u043F\u043E\u0437\u043D\u0430\u0432\u0430\u043D\u0438\u0435 \u0440\u0435\u0447\u0438, \u0432\u044B\u0440\u0435\u0437 \u0433\u0435\u0440\u043E\u044F, \u0447\u0438\u0441\u0442\u043A\u0430 \u0433\u043E\u043B\u043E\u0441\u0430 \u2014 \u0441\u0442\u0430\u0432\u0438\u0442\u0441\u044F \u043E\u0442\u0434\u0435\u043B\u044C\u043D\u043E \u0438 \u0442\u043E\u043B\u044C\u043A\u043E \u043F\u043E \u043F\u0440\u043E\u0441\u044C\u0431\u0435."
|
|
15658
|
+
];
|
|
15659
|
+
var INSTALL_WORDS = {
|
|
15660
|
+
ffmpeg: "\u043F\u043E\u0441\u0442\u0430\u0432\u043B\u044E ffmpeg \u2014 \u0438\u043C \u0441\u043E\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044F \u0432\u0438\u0434\u0435\u043E",
|
|
15661
|
+
python: "\u043F\u043E\u0441\u0442\u0430\u0432\u043B\u044E python",
|
|
15662
|
+
env: "\u0441\u043E\u0431\u0435\u0440\u0443 \u043E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u0435 \u043C\u043E\u043D\u0442\u0430\u0436\u0430",
|
|
15663
|
+
model: "\u0441\u043A\u0430\u0447\u0430\u044E \u043C\u043E\u0434\u0435\u043B\u044C \u0440\u0430\u0441\u043F\u043E\u0437\u043D\u0430\u0432\u0430\u043D\u0438\u044F \u0440\u0435\u0447\u0438 \u2014 \u043E\u043D\u0430 \u0438\u0437 \u0432\u0441\u0435\u0433\u043E \u0441\u0430\u043C\u0430\u044F \u0442\u044F\u0436\u0451\u043B\u0430\u044F",
|
|
15664
|
+
cutout: "\u0441\u043A\u0430\u0447\u0430\u044E \u0442\u043E, \u0447\u0435\u043C \u043E\u0442\u0434\u0435\u043B\u044F\u044E \u0433\u0435\u0440\u043E\u044F \u043E\u0442 \u0444\u043E\u043D\u0430",
|
|
15665
|
+
voice: "\u0441\u043A\u0430\u0447\u0430\u044E \u0442\u043E, \u0447\u0435\u043C \u0447\u0438\u0449\u0443 \u0433\u043E\u043B\u043E\u0441",
|
|
15666
|
+
browser: "\u043F\u043E\u0441\u0442\u0430\u0432\u043B\u044E \u0431\u0440\u0430\u0443\u0437\u0435\u0440, \u043A\u043E\u0442\u043E\u0440\u044B\u043C \u0440\u0438\u0441\u0443\u044E \u0433\u0440\u0430\u0444\u0438\u043A\u0443"
|
|
15667
|
+
};
|
|
15668
|
+
function installLadder(step) {
|
|
15669
|
+
if (step === "all") {
|
|
15670
|
+
return [
|
|
15671
|
+
"\u041F\u0440\u043E\u0432\u0435\u0440\u044E, \u0447\u0435\u0433\u043E \u043D\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442, \u0438 \u0434\u043E\u0441\u0442\u0430\u0432\u043B\u044E \u043F\u043E \u043E\u0447\u0435\u0440\u0435\u0434\u0438.",
|
|
15672
|
+
"\u0422\u044F\u0436\u0451\u043B\u043E\u0435 \u0441\u044E\u0434\u0430 \u043D\u0435 \u0432\u0445\u043E\u0434\u0438\u0442: \u0440\u0430\u0441\u043F\u043E\u0437\u043D\u0430\u0432\u0430\u043D\u0438\u0435 \u0440\u0435\u0447\u0438 \u0438 \u0432\u044B\u0440\u0435\u0437 \u0433\u0435\u0440\u043E\u044F \u0441\u0442\u0430\u0432\u044F\u0442\u0441\u044F \u043E\u0442\u0434\u0435\u043B\u044C\u043D\u043E \u0438 \u0442\u043E\u043B\u044C\u043A\u043E \u043F\u043E\u0441\u043B\u0435 \xAB\u0434\u0430\xBB \u043E\u0442 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430."
|
|
15673
|
+
];
|
|
15674
|
+
}
|
|
15675
|
+
const word = INSTALL_WORDS[step];
|
|
15676
|
+
if (word === void 0) return [];
|
|
15677
|
+
return [
|
|
15678
|
+
`\u0421\u0435\u0439\u0447\u0430\u0441 ${word}.`,
|
|
15679
|
+
"\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."
|
|
15680
|
+
];
|
|
15681
|
+
}
|
|
15682
|
+
var CALLS_FILE = "calls.jsonl";
|
|
15683
|
+
var CALLS_PREVIOUS = "calls.1.jsonl";
|
|
15684
|
+
var CALLS_CAP_BYTES = 1e6;
|
|
15685
|
+
function withCallLog(home, now = () => Date.now()) {
|
|
15686
|
+
return (tool) => {
|
|
15687
|
+
const original = tool.execute.bind(tool);
|
|
15688
|
+
return {
|
|
15689
|
+
...tool,
|
|
15690
|
+
async execute(input, ...rest) {
|
|
15691
|
+
const started = now();
|
|
15692
|
+
const result = await original(input, ...rest);
|
|
15693
|
+
write(home, {
|
|
15694
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
15695
|
+
tool: tool.name,
|
|
15696
|
+
ok: result.type === "success",
|
|
15697
|
+
ms: now() - started
|
|
15698
|
+
});
|
|
15699
|
+
return result;
|
|
15700
|
+
}
|
|
15701
|
+
};
|
|
15702
|
+
};
|
|
15703
|
+
}
|
|
15704
|
+
function write(home, line) {
|
|
15705
|
+
try {
|
|
15706
|
+
mkdirSync(home, { recursive: true });
|
|
15707
|
+
const file2 = join(home, CALLS_FILE);
|
|
15708
|
+
rotate(file2, join(home, CALLS_PREVIOUS));
|
|
15709
|
+
appendFileSync(file2, `${JSON.stringify(line)}
|
|
15710
|
+
`, { encoding: "utf8", mode: 384 });
|
|
15711
|
+
} catch {
|
|
15712
|
+
}
|
|
15713
|
+
}
|
|
15714
|
+
function rotate(file2, previous) {
|
|
15715
|
+
try {
|
|
15716
|
+
if (statSync(file2).size >= CALLS_CAP_BYTES) renameSync(file2, previous);
|
|
15717
|
+
} catch {
|
|
15718
|
+
}
|
|
15719
|
+
}
|
|
15720
|
+
|
|
15721
|
+
// src/contracts/crash-report.ts
|
|
15722
|
+
var CRASH_REPORT_PATH = "/crash-report";
|
|
15723
|
+
var CRASH_CONTRACT = "naparnik-crash/1";
|
|
15724
|
+
var CRASH_LIMITS = {
|
|
15725
|
+
bodyBytes: 65536,
|
|
15726
|
+
errorType: 120,
|
|
15727
|
+
message: 500,
|
|
15728
|
+
trace: 8e3,
|
|
15729
|
+
stage: 120,
|
|
15730
|
+
osPlatform: 32,
|
|
15731
|
+
osRelease: 64,
|
|
15732
|
+
osArch: 16,
|
|
15733
|
+
hostName: 64,
|
|
15734
|
+
hostVersion: 32,
|
|
15735
|
+
shellVersion: 32,
|
|
15736
|
+
engineVersion: 64,
|
|
15737
|
+
pythonVersion: 16,
|
|
15738
|
+
ffmpegVersion: 64,
|
|
15739
|
+
recentCalls: 10,
|
|
15740
|
+
repeats: 1e5
|
|
15741
|
+
};
|
|
15742
|
+
var CRASH_TOOL_NAME = /^[a-z_]{1,64}$/;
|
|
15743
|
+
var CRASH_FINGERPRINT = /^[0-9a-f]{16}$/;
|
|
15744
|
+
var text = (max) => external_exports.string().max(max);
|
|
15745
|
+
var CrashReportRequest = external_exports.object({
|
|
15746
|
+
contract: external_exports.literal(CRASH_CONTRACT),
|
|
15747
|
+
occurred_at: external_exports.string().datetime({ offset: true }),
|
|
15748
|
+
where: external_exports.enum(["tool", "job", "process"]),
|
|
15749
|
+
tool: external_exports.string().regex(CRASH_TOOL_NAME).nullable(),
|
|
15750
|
+
stage: text(CRASH_LIMITS.stage).nullable(),
|
|
15751
|
+
error_type: external_exports.string().min(1).max(CRASH_LIMITS.errorType),
|
|
15752
|
+
message: text(CRASH_LIMITS.message),
|
|
15753
|
+
trace: text(CRASH_LIMITS.trace),
|
|
15754
|
+
fingerprint: external_exports.string().regex(CRASH_FINGERPRINT),
|
|
15755
|
+
repeats: external_exports.number().int().min(0).max(CRASH_LIMITS.repeats),
|
|
15756
|
+
os: external_exports.object({
|
|
15757
|
+
platform: text(CRASH_LIMITS.osPlatform),
|
|
15758
|
+
release: text(CRASH_LIMITS.osRelease),
|
|
15759
|
+
arch: text(CRASH_LIMITS.osArch)
|
|
15760
|
+
}).strict(),
|
|
15761
|
+
host: external_exports.object({
|
|
15762
|
+
name: text(CRASH_LIMITS.hostName),
|
|
15763
|
+
version: text(CRASH_LIMITS.hostVersion)
|
|
15764
|
+
}).strict().nullable(),
|
|
15765
|
+
versions: external_exports.object({
|
|
15766
|
+
shell: text(CRASH_LIMITS.shellVersion),
|
|
15767
|
+
engine: text(CRASH_LIMITS.engineVersion).nullable(),
|
|
15768
|
+
python: text(CRASH_LIMITS.pythonVersion).nullable(),
|
|
15769
|
+
ffmpeg: text(CRASH_LIMITS.ffmpegVersion).nullable()
|
|
15770
|
+
}).strict(),
|
|
15771
|
+
recent_calls: external_exports.array(external_exports.string().regex(CRASH_TOOL_NAME)).max(CRASH_LIMITS.recentCalls)
|
|
15772
|
+
}).strict();
|
|
15773
|
+
var SECRET_MIN = 4;
|
|
15774
|
+
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;
|
|
15775
|
+
var PATH = /(?:<naparnik>|<shell>|~|[A-Za-z]:)?(?:[\\/][^\s"'«»“”<>|,;()[\]{}\\/]+)+[\\/]?/g;
|
|
15776
|
+
var QUOTED = /(["'])([^"'\n]*)\1|«([^»\n]*)»|“([^”\n]*)”/g;
|
|
15777
|
+
var KEY = /npk_[A-Za-z0-9_-]{6,}/g;
|
|
15778
|
+
function scrub(text2, context) {
|
|
15779
|
+
let out = text2.replace(KEY, "<key>");
|
|
15780
|
+
for (const secret of secretForms(context.secrets)) {
|
|
15781
|
+
out = replaceAll(out, secret, "<video>");
|
|
15782
|
+
}
|
|
15783
|
+
out = replaceAll(out, context.shellDir, "<shell>");
|
|
15784
|
+
out = replaceAll(out, context.naparnikHome, "<naparnik>");
|
|
15785
|
+
out = replaceAll(out, context.home, "~");
|
|
15786
|
+
out = out.replace(/(?:\/Users|\/home|[A-Za-z]:\\Users|[A-Za-z]:\/Users)[\\/][^\s"'«»“”\\/]+/g, "~");
|
|
15787
|
+
out = out.replace(QUOTED, (whole, _q, plain, fir, curly) => {
|
|
15788
|
+
const inside2 = plain ?? fir ?? curly ?? "";
|
|
15789
|
+
if (!looksHuman(inside2)) return whole;
|
|
15790
|
+
const [open, close] = plain !== void 0 ? [_q, _q] : fir !== void 0 ? ["\xAB", "\xBB"] : ["\u201C", "\u201D"];
|
|
15791
|
+
return `${open}${looksLikePath(inside2) ? pathOrMark(inside2) : "<text>"}${close}`;
|
|
15792
|
+
});
|
|
15793
|
+
out = out.replace(PATH, (found) => pathOrMark(found));
|
|
15794
|
+
out = out.replace(HUMAN_FILE, "<file>");
|
|
15795
|
+
out = swallowSpacedTails(out);
|
|
15796
|
+
if (context.user.length >= 3) out = replaceAll(out, context.user, "<user>");
|
|
15797
|
+
return out;
|
|
15798
|
+
}
|
|
15799
|
+
function swallowSpacedTails(text2) {
|
|
15800
|
+
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);
|
|
15801
|
+
}
|
|
15802
|
+
function secretForms(secrets) {
|
|
15803
|
+
const forms = /* @__PURE__ */ new Set();
|
|
15804
|
+
for (const raw of secrets) {
|
|
15805
|
+
const value = raw.trim();
|
|
15806
|
+
if (value.length < SECRET_MIN) continue;
|
|
15807
|
+
forms.add(value);
|
|
15808
|
+
if (!looksLikePath(value)) continue;
|
|
15809
|
+
if (isAbsolute(value)) forms.add(resolve(value));
|
|
15810
|
+
const name = basename(value);
|
|
15811
|
+
const stem = name.slice(0, name.length - extname(name).length);
|
|
15812
|
+
for (const one of [name, stem, `${stem}.montage`]) {
|
|
15813
|
+
if (one.length >= SECRET_MIN) forms.add(one);
|
|
15814
|
+
}
|
|
15815
|
+
}
|
|
15816
|
+
return [...forms].sort((a, b) => b.length - a.length);
|
|
15817
|
+
}
|
|
15818
|
+
function pathOrMark(found) {
|
|
15819
|
+
const flat = found.replace(/\\/g, "/");
|
|
15820
|
+
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);
|
|
15821
|
+
return ours ? found : "<path>";
|
|
15822
|
+
}
|
|
15823
|
+
var HUMAN_FILE_ONE = new RegExp(HUMAN_FILE.source, "i");
|
|
15824
|
+
function looksLikePath(value) {
|
|
15825
|
+
return /[\\/]/.test(value) || HUMAN_FILE_ONE.test(value);
|
|
15826
|
+
}
|
|
15827
|
+
function looksHuman(inside2) {
|
|
15828
|
+
return /[^\x00-\x7F]/.test(inside2) || /\s/.test(inside2) || looksLikePath(inside2);
|
|
15829
|
+
}
|
|
15830
|
+
function replaceAll(text2, what, by) {
|
|
15831
|
+
if (what === "") return text2;
|
|
15832
|
+
return text2.split(what).join(by);
|
|
15388
15833
|
}
|
|
15389
15834
|
|
|
15390
15835
|
// src/job-report.ts
|
|
@@ -15431,14 +15876,14 @@ var PLAN_HEAD = /^План:$/;
|
|
|
15431
15876
|
var PLAN_ROW = /^· (.+)$/;
|
|
15432
15877
|
var STYLE = /^Стиль: /;
|
|
15433
15878
|
var LEFT_TAIL = /\.\s+(Осталось .+)$/;
|
|
15434
|
-
function readJob(
|
|
15435
|
-
const lines =
|
|
15436
|
-
const
|
|
15437
|
-
if (
|
|
15879
|
+
function readJob(text2) {
|
|
15880
|
+
const lines = text2.split("\n").map((row) => row.trimEnd());
|
|
15881
|
+
const head2 = HEAD.exec(lines[0]?.trim() ?? "");
|
|
15882
|
+
if (head2 === null) return null;
|
|
15438
15883
|
const job = empty();
|
|
15439
|
-
job.id =
|
|
15440
|
-
job.what = (
|
|
15441
|
-
let
|
|
15884
|
+
job.id = head2[1] ?? "";
|
|
15885
|
+
job.what = (head2[2] ?? "").trim();
|
|
15886
|
+
let tail2 = null;
|
|
15442
15887
|
for (const row of lines.slice(1)) {
|
|
15443
15888
|
const line = row.trim();
|
|
15444
15889
|
if (line === "") continue;
|
|
@@ -15446,17 +15891,17 @@ function readJob(text) {
|
|
|
15446
15891
|
const complaint = COMPLAINT.exec(line);
|
|
15447
15892
|
if (complaint !== null) {
|
|
15448
15893
|
job.complaints.push(complaint[1] ?? "");
|
|
15449
|
-
|
|
15894
|
+
tail2 = null;
|
|
15450
15895
|
continue;
|
|
15451
15896
|
}
|
|
15452
15897
|
if (PLAN_HEAD.test(line)) {
|
|
15453
|
-
|
|
15898
|
+
tail2 = null;
|
|
15454
15899
|
continue;
|
|
15455
15900
|
}
|
|
15456
15901
|
const planRow = PLAN_ROW.exec(line);
|
|
15457
15902
|
if (planRow !== null) {
|
|
15458
15903
|
job.plan.push(planRow[1] ?? "");
|
|
15459
|
-
|
|
15904
|
+
tail2 = null;
|
|
15460
15905
|
continue;
|
|
15461
15906
|
}
|
|
15462
15907
|
const behind = BEHIND.exec(line);
|
|
@@ -15487,13 +15932,13 @@ function readJob(text) {
|
|
|
15487
15932
|
if (done !== null) {
|
|
15488
15933
|
job.status = "done";
|
|
15489
15934
|
job.sec = seconds(done[1]);
|
|
15490
|
-
|
|
15935
|
+
tail2 = [];
|
|
15491
15936
|
continue;
|
|
15492
15937
|
}
|
|
15493
15938
|
const file2 = FILE.exec(line);
|
|
15494
15939
|
if (file2 !== null && job.status === "done") {
|
|
15495
15940
|
job.file = file2[1] ?? "";
|
|
15496
|
-
|
|
15941
|
+
tail2 = null;
|
|
15497
15942
|
continue;
|
|
15498
15943
|
}
|
|
15499
15944
|
const failed = FAILED.exec(line);
|
|
@@ -15501,20 +15946,20 @@ function readJob(text) {
|
|
|
15501
15946
|
job.status = "error";
|
|
15502
15947
|
job.sec = seconds(failed[1]);
|
|
15503
15948
|
job.trouble = failed[2] ?? "";
|
|
15504
|
-
|
|
15949
|
+
tail2 = null;
|
|
15505
15950
|
continue;
|
|
15506
15951
|
}
|
|
15507
15952
|
if (ABORTED.test(line)) {
|
|
15508
15953
|
job.status = "aborted";
|
|
15509
15954
|
job.trouble = line;
|
|
15510
15955
|
job.sec = seconds(ABORTED_SEC.exec(line)?.[1]);
|
|
15511
|
-
|
|
15956
|
+
tail2 = null;
|
|
15512
15957
|
continue;
|
|
15513
15958
|
}
|
|
15514
15959
|
const advice = ADVICE.exec(line);
|
|
15515
15960
|
if (advice !== null) {
|
|
15516
15961
|
job.advice = advice[1] ?? "";
|
|
15517
|
-
|
|
15962
|
+
tail2 = null;
|
|
15518
15963
|
continue;
|
|
15519
15964
|
}
|
|
15520
15965
|
if (WAITING.test(line)) {
|
|
@@ -15528,52 +15973,530 @@ function readJob(text) {
|
|
|
15528
15973
|
job.sec = seconds(running[1]);
|
|
15529
15974
|
continue;
|
|
15530
15975
|
}
|
|
15531
|
-
if (
|
|
15532
|
-
|
|
15533
|
-
job.outcome =
|
|
15976
|
+
if (tail2 !== null) {
|
|
15977
|
+
tail2.push(line);
|
|
15978
|
+
job.outcome = tail2.join("\n");
|
|
15534
15979
|
continue;
|
|
15535
15980
|
}
|
|
15536
15981
|
if (job.status === "running" || job.status === "waiting") job.message = line;
|
|
15537
15982
|
}
|
|
15538
15983
|
return job;
|
|
15539
15984
|
}
|
|
15540
|
-
function seconds(
|
|
15541
|
-
if (
|
|
15542
|
-
const value = Number(
|
|
15985
|
+
function seconds(text2) {
|
|
15986
|
+
if (text2 === void 0) return 0;
|
|
15987
|
+
const value = Number(text2.replace(",", "."));
|
|
15543
15988
|
return Number.isFinite(value) ? value : 0;
|
|
15544
15989
|
}
|
|
15545
|
-
|
|
15546
|
-
|
|
15547
|
-
|
|
15548
|
-
|
|
15549
|
-
var
|
|
15550
|
-
|
|
15551
|
-
|
|
15552
|
-
|
|
15553
|
-
|
|
15554
|
-
|
|
15990
|
+
|
|
15991
|
+
// src/crash-report.ts
|
|
15992
|
+
var RESEND_AFTER_MS = 30 * 6e4;
|
|
15993
|
+
var QUEUE_CAP = 20;
|
|
15994
|
+
var FLUSH_PER_PASS = 5;
|
|
15995
|
+
var FLUSH_EVERY_MS = 6e4;
|
|
15996
|
+
var SEND_TIMEOUT_MS = 3e3;
|
|
15997
|
+
var JOB_LOG_TAIL = 64 * 1024;
|
|
15998
|
+
var PYTHON_TRACEBACK = "Traceback (most recent call last):";
|
|
15999
|
+
var CrashReporter = class {
|
|
16000
|
+
#deps;
|
|
16001
|
+
#now;
|
|
16002
|
+
#inflight = /* @__PURE__ */ new Set();
|
|
16003
|
+
#lastFlush = Number.NEGATIVE_INFINITY;
|
|
16004
|
+
#host = null;
|
|
16005
|
+
/**
|
|
16006
|
+
* Строки из аргументов недавних вызовов — только в памяти процесса.
|
|
16007
|
+
*
|
|
16008
|
+
* ⚠ ЗАЧЕМ. Задание упало — отчёт о нём приходит на `wait`, а в аргументах
|
|
16009
|
+
* `wait` лишь номер задания; путь к ролику был в аргументах `render`,
|
|
16010
|
+
* который задание запустил. Без этой памяти путь с пробелами из трейса ffmpeg
|
|
16011
|
+
* вычищался бы только общими правилами, а они его режут на куски (ревью
|
|
16012
|
+
* безопасности 2026-09-24). На диск не пишется: это ровно то, что мы
|
|
16013
|
+
* обещали не хранить.
|
|
16014
|
+
*/
|
|
16015
|
+
#recentSecrets = [];
|
|
16016
|
+
#ffmpeg = null;
|
|
16017
|
+
constructor(deps) {
|
|
16018
|
+
this.#deps = deps;
|
|
16019
|
+
this.#now = deps.now ?? (() => Date.now());
|
|
15555
16020
|
}
|
|
15556
|
-
|
|
15557
|
-
|
|
15558
|
-
:root {
|
|
15559
|
-
--font-display: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Icons", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
|
16021
|
+
get canSend() {
|
|
16022
|
+
return this.#deps.canSend;
|
|
15560
16023
|
}
|
|
15561
|
-
|
|
15562
|
-
|
|
15563
|
-
|
|
15564
|
-
|
|
15565
|
-
|
|
15566
|
-
|
|
15567
|
-
|
|
15568
|
-
|
|
15569
|
-
|
|
15570
|
-
|
|
15571
|
-
|
|
15572
|
-
|
|
15573
|
-
|
|
15574
|
-
|
|
15575
|
-
|
|
15576
|
-
|
|
16024
|
+
get home() {
|
|
16025
|
+
return this.#deps.home;
|
|
16026
|
+
}
|
|
16027
|
+
/** Запомнить программу-хост: при падении всего процесса контекста вызова нет. */
|
|
16028
|
+
/** Запомнить строки аргументов вызова — чтобы вычеркнуть их из будущих отчётов. */
|
|
16029
|
+
noteSecrets(secrets) {
|
|
16030
|
+
const fresh = secrets.filter((one) => one.length >= 4);
|
|
16031
|
+
if (fresh.length === 0) return;
|
|
16032
|
+
this.#recentSecrets = [...this.#recentSecrets.filter((one) => !fresh.includes(one)), ...fresh].slice(-50);
|
|
16033
|
+
}
|
|
16034
|
+
noteHost(host) {
|
|
16035
|
+
if (host !== null) this.#host = host;
|
|
16036
|
+
}
|
|
16037
|
+
/** Отправить отчёт мимо ответа. Для тестов и смоука — `settled()`. */
|
|
16038
|
+
submit(crash) {
|
|
16039
|
+
this.#track(this.#deliver(crash));
|
|
16040
|
+
}
|
|
16041
|
+
/**
|
|
16042
|
+
* Процесс падает: отчёт кладётся на диск СИНХРОННО и уходит на следующем
|
|
16043
|
+
* запуске. Сеть здесь не трогаем — процессу осталось жить миллисекунды, и
|
|
16044
|
+
* недоставленный наполовину запрос хуже файла, который точно дойдёт.
|
|
16045
|
+
*/
|
|
16046
|
+
persist(crash) {
|
|
16047
|
+
try {
|
|
16048
|
+
const report = this.#build(crash);
|
|
16049
|
+
if (report !== null) this.#enqueue(report);
|
|
16050
|
+
} catch {
|
|
16051
|
+
}
|
|
16052
|
+
}
|
|
16053
|
+
/** Досылка очереди — не чаще раза в минуту. */
|
|
16054
|
+
flushSoon() {
|
|
16055
|
+
const now = this.#now();
|
|
16056
|
+
if (now - this.#lastFlush < FLUSH_EVERY_MS) return;
|
|
16057
|
+
this.#lastFlush = now;
|
|
16058
|
+
this.#track(this.#flush());
|
|
16059
|
+
}
|
|
16060
|
+
/** Дождаться всего, что ушло мимо ответа. Боевому пути не нужно. */
|
|
16061
|
+
async settled() {
|
|
16062
|
+
while (this.#inflight.size > 0) await Promise.allSettled([...this.#inflight]);
|
|
16063
|
+
}
|
|
16064
|
+
/** Задание уже разобрано: отчёт о нём ушёл раньше, в этом или прошлом запуске. */
|
|
16065
|
+
jobSeen(id) {
|
|
16066
|
+
return this.#state().jobs.includes(id);
|
|
16067
|
+
}
|
|
16068
|
+
rememberJob(id) {
|
|
16069
|
+
const state = this.#state();
|
|
16070
|
+
state.jobs = [...state.jobs.filter((one) => one !== id), id].slice(-50);
|
|
16071
|
+
this.#save(state);
|
|
16072
|
+
}
|
|
16073
|
+
scrubContext(secrets) {
|
|
16074
|
+
return {
|
|
16075
|
+
home: this.#deps.osHome ?? homedir(),
|
|
16076
|
+
user: this.#deps.osUser ?? safeUser(),
|
|
16077
|
+
naparnikHome: this.#deps.home,
|
|
16078
|
+
shellDir: this.#deps.shellDir ?? ownDir(),
|
|
16079
|
+
secrets
|
|
16080
|
+
};
|
|
16081
|
+
}
|
|
16082
|
+
#track(work) {
|
|
16083
|
+
const guarded = work.catch(() => void 0);
|
|
16084
|
+
this.#inflight.add(guarded);
|
|
16085
|
+
void guarded.finally(() => this.#inflight.delete(guarded));
|
|
16086
|
+
}
|
|
16087
|
+
async #deliver(crash) {
|
|
16088
|
+
const report = this.#build(crash);
|
|
16089
|
+
if (report === null) return;
|
|
16090
|
+
report.versions.ffmpeg = await this.#ffmpegVersion();
|
|
16091
|
+
const verdict = await this.#send(report);
|
|
16092
|
+
if (verdict === "retry") this.#enqueue(report);
|
|
16093
|
+
}
|
|
16094
|
+
async #flush() {
|
|
16095
|
+
const dir = this.#queueDir();
|
|
16096
|
+
let files;
|
|
16097
|
+
try {
|
|
16098
|
+
files = readdirSync(dir).filter((f) => f.endsWith(".json")).sort();
|
|
16099
|
+
} catch {
|
|
16100
|
+
return;
|
|
16101
|
+
}
|
|
16102
|
+
for (const file2 of files.slice(0, FLUSH_PER_PASS)) {
|
|
16103
|
+
const path2 = join(dir, file2);
|
|
16104
|
+
let report;
|
|
16105
|
+
try {
|
|
16106
|
+
report = JSON.parse(readFileSync(path2, "utf8"));
|
|
16107
|
+
} catch {
|
|
16108
|
+
rmSync(path2, { force: true });
|
|
16109
|
+
continue;
|
|
16110
|
+
}
|
|
16111
|
+
const verdict = await this.#send(report);
|
|
16112
|
+
if (verdict === "retry") return;
|
|
16113
|
+
rmSync(path2, { force: true });
|
|
16114
|
+
}
|
|
16115
|
+
}
|
|
16116
|
+
/**
|
|
16117
|
+
* Отправить и решить, что делать с отчётом дальше.
|
|
16118
|
+
*
|
|
16119
|
+
* ⚠ В ОЧЕРЕДЬ ИДЁТ ТОЛЬКО ТО, ЧТО ПОВТОР ИСПРАВИТ: нет сети, таймаут, 5xx,
|
|
16120
|
+
* 429 и «ключа нет» (человек впишет его завтра). 400 и 413 — отчёт кривой,
|
|
16121
|
+
* 401 и 403 — ключ не наш: повтор даст тот же отказ, а очередь с потолком
|
|
16122
|
+
* вытесняла бы им живые отчёты.
|
|
16123
|
+
*/
|
|
16124
|
+
async #send(report) {
|
|
16125
|
+
if (!CrashReportRequest.safeParse(report).success) return "drop";
|
|
16126
|
+
try {
|
|
16127
|
+
await this.#deps.client.postMontage(CRASH_REPORT_PATH, report, {
|
|
16128
|
+
once: true,
|
|
16129
|
+
timeoutMs: this.#deps.timeoutMs ?? SEND_TIMEOUT_MS
|
|
16130
|
+
});
|
|
16131
|
+
return "sent";
|
|
16132
|
+
} catch (trouble) {
|
|
16133
|
+
if (trouble instanceof NaparnikAuthError || trouble instanceof NaparnikScopeError) return "drop";
|
|
16134
|
+
if (trouble instanceof NaparnikClientError) return trouble.status === 429 ? "retry" : "drop";
|
|
16135
|
+
return "retry";
|
|
16136
|
+
}
|
|
16137
|
+
}
|
|
16138
|
+
/**
|
|
16139
|
+
* Собрать отчёт: обезличить, обрезать, посчитать отпечаток и решить по
|
|
16140
|
+
* частоте. `null` — этот отпечаток уже уходил меньше получаса назад, и
|
|
16141
|
+
* повтор записан в счётчик.
|
|
16142
|
+
*/
|
|
16143
|
+
#build(crash) {
|
|
16144
|
+
const fingerprint = fingerprintOf2(crash.errorType, crash.frames);
|
|
16145
|
+
const state = this.#state();
|
|
16146
|
+
const now = this.#now();
|
|
16147
|
+
const seen = state.fingerprints[fingerprint];
|
|
16148
|
+
if (seen !== void 0 && now - seen.sentAt < RESEND_AFTER_MS) {
|
|
16149
|
+
seen.pending += 1;
|
|
16150
|
+
this.#save(state);
|
|
16151
|
+
return null;
|
|
16152
|
+
}
|
|
16153
|
+
const repeats = Math.min(seen?.pending ?? 0, CRASH_LIMITS.repeats);
|
|
16154
|
+
state.fingerprints[fingerprint] = { sentAt: now, pending: 0 };
|
|
16155
|
+
prune(state, now);
|
|
16156
|
+
this.#save(state);
|
|
16157
|
+
const context = this.scrubContext([...crash.secrets, ...this.#recentSecrets]);
|
|
16158
|
+
const clean = (text2) => scrub(text2, context);
|
|
16159
|
+
return {
|
|
16160
|
+
contract: CRASH_CONTRACT,
|
|
16161
|
+
occurred_at: new Date(now).toISOString(),
|
|
16162
|
+
where: crash.where,
|
|
16163
|
+
tool: crash.tool !== null && CRASH_TOOL_NAME.test(crash.tool) ? crash.tool : null,
|
|
16164
|
+
// ⚠ РЕЖЕМ ДО ОБЕЗЛИЧИВАНИЯ С ЗАПАСОМ И ЕЩЁ РАЗ ПОСЛЕ. Обезличивание идёт
|
|
16165
|
+
// синхронно, до ответа инструмента, а stderr движка бывает мегабайтами:
|
|
16166
|
+
// без первой резки длинный текст подвешивал бы ответ на секунды (ревью
|
|
16167
|
+
// безопасности 2026-09-24). Запас — вдвое: метки короче того, что заменяют.
|
|
16168
|
+
stage: crash.stage === null ? null : head(clean(head(crash.stage, 2 * CRASH_LIMITS.stage)), CRASH_LIMITS.stage),
|
|
16169
|
+
error_type: head(clean(head(crash.errorType, 2 * CRASH_LIMITS.errorType)), CRASH_LIMITS.errorType) || "Error",
|
|
16170
|
+
message: head(clean(head(crash.message, 2 * CRASH_LIMITS.message)), CRASH_LIMITS.message),
|
|
16171
|
+
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),
|
|
16172
|
+
fingerprint,
|
|
16173
|
+
repeats,
|
|
16174
|
+
os: {
|
|
16175
|
+
platform: head(platform(), CRASH_LIMITS.osPlatform),
|
|
16176
|
+
release: head(release(), CRASH_LIMITS.osRelease),
|
|
16177
|
+
arch: head(arch(), CRASH_LIMITS.osArch)
|
|
16178
|
+
},
|
|
16179
|
+
host: hostOf(crash.host ?? this.#host),
|
|
16180
|
+
versions: {
|
|
16181
|
+
shell: head(VERSION, CRASH_LIMITS.shellVersion),
|
|
16182
|
+
engine: orNull(this.#deps.engineVersion(), CRASH_LIMITS.engineVersion),
|
|
16183
|
+
python: orNull(crash.python, CRASH_LIMITS.pythonVersion),
|
|
16184
|
+
ffmpeg: null
|
|
16185
|
+
},
|
|
16186
|
+
recent_calls: recentCalls(this.#deps.home)
|
|
16187
|
+
};
|
|
16188
|
+
}
|
|
16189
|
+
#enqueue(report) {
|
|
16190
|
+
try {
|
|
16191
|
+
const dir = this.#queueDir();
|
|
16192
|
+
mkdirSync(dir, { recursive: true });
|
|
16193
|
+
const name = `${String(this.#now()).padStart(15, "0")}-${report.fingerprint}.json`;
|
|
16194
|
+
const temporary = join(dir, `${name}.tmp`);
|
|
16195
|
+
writeFileSync(temporary, JSON.stringify(report), { mode: 384 });
|
|
16196
|
+
renameSync(temporary, join(dir, name));
|
|
16197
|
+
const files = readdirSync(dir).filter((f) => f.endsWith(".json")).sort();
|
|
16198
|
+
for (const old of files.slice(0, Math.max(0, files.length - QUEUE_CAP))) {
|
|
16199
|
+
rmSync(join(dir, old), { force: true });
|
|
16200
|
+
}
|
|
16201
|
+
} catch {
|
|
16202
|
+
}
|
|
16203
|
+
}
|
|
16204
|
+
#queueDir() {
|
|
16205
|
+
return join(this.#deps.home, "crash-reports", "queue");
|
|
16206
|
+
}
|
|
16207
|
+
#stateFile() {
|
|
16208
|
+
return join(this.#deps.home, "crash-reports", "seen.json");
|
|
16209
|
+
}
|
|
16210
|
+
#state() {
|
|
16211
|
+
try {
|
|
16212
|
+
const parsed = JSON.parse(readFileSync(this.#stateFile(), "utf8"));
|
|
16213
|
+
return {
|
|
16214
|
+
fingerprints: typeof parsed.fingerprints === "object" && parsed.fingerprints !== null ? parsed.fingerprints : {},
|
|
16215
|
+
jobs: Array.isArray(parsed.jobs) ? parsed.jobs.filter((j) => typeof j === "string") : []
|
|
16216
|
+
};
|
|
16217
|
+
} catch {
|
|
16218
|
+
return { fingerprints: {}, jobs: [] };
|
|
16219
|
+
}
|
|
16220
|
+
}
|
|
16221
|
+
#save(state) {
|
|
16222
|
+
try {
|
|
16223
|
+
mkdirSync(dirname(this.#stateFile()), { recursive: true });
|
|
16224
|
+
writeFileSync(this.#stateFile(), JSON.stringify(state), { mode: 384 });
|
|
16225
|
+
} catch {
|
|
16226
|
+
}
|
|
16227
|
+
}
|
|
16228
|
+
#ffmpegVersion() {
|
|
16229
|
+
this.#ffmpeg ??= (this.#deps.ffmpegVersion ?? (() => probeFfmpeg(this.#deps.home)))().catch(() => null);
|
|
16230
|
+
return this.#ffmpeg.then((v) => orNull(v, CRASH_LIMITS.ffmpegVersion));
|
|
16231
|
+
}
|
|
16232
|
+
};
|
|
16233
|
+
function prune(state, now) {
|
|
16234
|
+
for (const [key, value] of Object.entries(state.fingerprints)) {
|
|
16235
|
+
if (now - value.sentAt > 24 * 36e5 && value.pending === 0) delete state.fingerprints[key];
|
|
16236
|
+
}
|
|
16237
|
+
}
|
|
16238
|
+
function withCrashReport(crashes) {
|
|
16239
|
+
return (tool) => {
|
|
16240
|
+
if (crashes === null) return tool;
|
|
16241
|
+
const original = tool.execute.bind(tool);
|
|
16242
|
+
return {
|
|
16243
|
+
...tool,
|
|
16244
|
+
async execute(input, ...rest) {
|
|
16245
|
+
crashes.flushSoon();
|
|
16246
|
+
const host = hostFromContext(rest[0]);
|
|
16247
|
+
crashes.noteHost(host);
|
|
16248
|
+
crashes.noteSecrets(secretsOf(input));
|
|
16249
|
+
let result;
|
|
16250
|
+
try {
|
|
16251
|
+
result = await original(input, ...rest);
|
|
16252
|
+
} catch (trouble) {
|
|
16253
|
+
const crash = fromThrown(trouble, "tool", tool.name, input, host);
|
|
16254
|
+
crashes.submit(crash);
|
|
16255
|
+
return toolError(brokenWords(crash, crashes));
|
|
16256
|
+
}
|
|
16257
|
+
return caught(result, tool.name, input, host, crashes);
|
|
16258
|
+
}
|
|
16259
|
+
};
|
|
16260
|
+
};
|
|
16261
|
+
}
|
|
16262
|
+
function caught(result, name, input, host, crashes) {
|
|
16263
|
+
if (result.type === "error") {
|
|
16264
|
+
const parsed2 = pythonCrash(result.error);
|
|
16265
|
+
if (parsed2 === null) return result;
|
|
16266
|
+
const crash2 = { ...parsed2, where: "tool", tool: name, stage: null, secrets: secretsOf(input), host };
|
|
16267
|
+
crashes.submit(crash2);
|
|
16268
|
+
return toolError(brokenWords(crash2, crashes));
|
|
16269
|
+
}
|
|
16270
|
+
const job = result.structured;
|
|
16271
|
+
if (job === void 0 || job["contract"] !== JOB_CONTRACT || job["status"] !== "error") return result;
|
|
16272
|
+
const id = typeof job["id"] === "string" ? job["id"] : "";
|
|
16273
|
+
if (!/^[\w.-]{1,80}$/.test(id) || crashes.jobSeen(id)) return result;
|
|
16274
|
+
const parsed = pythonCrash(jobLogTail(crashes.home, id));
|
|
16275
|
+
if (parsed === null) return result;
|
|
16276
|
+
crashes.rememberJob(id);
|
|
16277
|
+
const stage = typeof job["now"] === "string" && job["now"] !== "" ? job["now"] : null;
|
|
16278
|
+
const crash = { ...parsed, where: "job", tool: name, stage, secrets: secretsOf(input), host };
|
|
16279
|
+
crashes.submit(crash);
|
|
16280
|
+
const notice = `
|
|
16281
|
+
|
|
16282
|
+
${brokenWords(crash, crashes)}`;
|
|
16283
|
+
return typeof result.content === "string" ? { ...result, content: result.content + notice } : { ...result, content: [...result.content, { type: "text", text: notice.trim() }] };
|
|
16284
|
+
}
|
|
16285
|
+
function brokenWords(crash, crashes) {
|
|
16286
|
+
const essence = head(scrub(head(crash.essence, 600), crashes.scrubContext(crash.secrets)), 300);
|
|
16287
|
+
return [
|
|
16288
|
+
"\u0421\u043B\u043E\u043C\u0430\u043B\u043E\u0441\u044C \u043D\u0430 \u043D\u0430\u0448\u0435\u0439 \u0441\u0442\u043E\u0440\u043E\u043D\u0435, \u043D\u0435 \u0443 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430.",
|
|
16289
|
+
crashes.canSend ? `\u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C: \u0441\u043A\u0430\u0436\u0438, \u0447\u0442\u043E \u0442\u0435\u0445\u043D\u0438\u0447\u0435\u0441\u043A\u0438\u0439 \u043E\u0442\u0447\u0451\u0442 \u0443\u0445\u043E\u0434\u0438\u0442 \u043D\u0430\u043C \u0441\u0430\u043C \u0438 \u0440\u0430\u0441\u0441\u043A\u0430\u0437\u044B\u0432\u0430\u0442\u044C \u043D\u0438\u0447\u0435\u0433\u043E \u043D\u0435 \u043D\u0443\u0436\u043D\u043E, \u0438 \u043F\u043E\u043F\u0440\u043E\u0431\u0443\u0439 \u0435\u0449\u0451 \u0440\u0430\u0437. \u041F\u043E\u0432\u0442\u043E\u0440\u0438\u0442\u0441\u044F \u2014 \u043F\u0443\u0441\u0442\u044C \u043D\u0430\u043F\u0438\u0448\u0435\u0442 \u043D\u0430\u043C \u0432 \u0431\u043E\u0442 ${KEY_SOURCE_BOT}.` : `\u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C: \u043F\u043E\u043F\u0440\u043E\u0431\u0443\u0439 \u0435\u0449\u0451 \u0440\u0430\u0437. \u041F\u043E\u0432\u0442\u043E\u0440\u0438\u0442\u0441\u044F \u2014 \u043F\u0443\u0441\u0442\u044C \u043D\u0430\u043F\u0438\u0448\u0435\u0442 \u043D\u0430\u043C \u0432 \u0431\u043E\u0442 ${KEY_SOURCE_BOT}.`,
|
|
16290
|
+
`\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}`
|
|
16291
|
+
].join("\n");
|
|
16292
|
+
}
|
|
16293
|
+
function watchProcessCrashes(crashes, proc = process, exit = (code) => process.exit(code)) {
|
|
16294
|
+
const fall = (trouble) => {
|
|
16295
|
+
crashes.persist(fromThrown(trouble, "process", null, {}, null));
|
|
16296
|
+
try {
|
|
16297
|
+
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)}
|
|
16298
|
+
`);
|
|
16299
|
+
} catch {
|
|
16300
|
+
}
|
|
16301
|
+
exit(1);
|
|
16302
|
+
};
|
|
16303
|
+
proc.on("uncaughtException", fall);
|
|
16304
|
+
proc.on("unhandledRejection", fall);
|
|
16305
|
+
crashes.flushSoon();
|
|
16306
|
+
}
|
|
16307
|
+
function fromThrown(trouble, where, tool, input, host) {
|
|
16308
|
+
const error40 = trouble instanceof Error ? trouble : new Error(String(trouble));
|
|
16309
|
+
const errorType = error40.name || error40.constructor.name || "Error";
|
|
16310
|
+
const trace = error40.stack ?? `${errorType}: ${error40.message}`;
|
|
16311
|
+
const frames = jsFrames(trace);
|
|
16312
|
+
return {
|
|
16313
|
+
where,
|
|
16314
|
+
tool,
|
|
16315
|
+
stage: null,
|
|
16316
|
+
errorType,
|
|
16317
|
+
message: error40.message,
|
|
16318
|
+
trace,
|
|
16319
|
+
keep: "head",
|
|
16320
|
+
frames: frames.slice(0, 3).map((f) => `${f.file}:${f.func}`),
|
|
16321
|
+
python: null,
|
|
16322
|
+
secrets: secretsOf(input),
|
|
16323
|
+
host,
|
|
16324
|
+
essence: `${errorType}: ${error40.message}${frames[0] ? ` \u2014 ${frames[0].file}` : ""}`
|
|
16325
|
+
};
|
|
16326
|
+
}
|
|
16327
|
+
function jsFrames(stack) {
|
|
16328
|
+
const frames = [];
|
|
16329
|
+
for (const line of stack.split("\n")) {
|
|
16330
|
+
const m = /^\s*at (?:(.+?) \()?(.+?):\d+:\d+\)?\s*$/.exec(line);
|
|
16331
|
+
if (m === null) continue;
|
|
16332
|
+
const file2 = basename(m[2] ?? "").replace(/-[A-Za-z0-9]{6,}(\.[cm]?js)$/, "$1");
|
|
16333
|
+
frames.push({ file: file2, func: m[1] ?? "<anonymous>" });
|
|
16334
|
+
}
|
|
16335
|
+
return frames;
|
|
16336
|
+
}
|
|
16337
|
+
function pythonCrash(text2) {
|
|
16338
|
+
const start = text2.lastIndexOf(PYTHON_TRACEBACK);
|
|
16339
|
+
if (start < 0) return null;
|
|
16340
|
+
const block = text2.slice(start).replace(/\s+$/, "");
|
|
16341
|
+
const lines = block.split("\n");
|
|
16342
|
+
const frames = [];
|
|
16343
|
+
let lastFrame = -1;
|
|
16344
|
+
lines.forEach((line, at2) => {
|
|
16345
|
+
const m2 = /^\s*File "(.+)", line (\d+), in (.+)$/.exec(line);
|
|
16346
|
+
if (m2 === null) return;
|
|
16347
|
+
frames.push({ file: m2[1] ?? "", line: m2[2] ?? "", func: (m2[3] ?? "").trim() });
|
|
16348
|
+
lastFrame = at2;
|
|
16349
|
+
});
|
|
16350
|
+
if (frames.length === 0) return null;
|
|
16351
|
+
if (frames.some((f) => /[\\/]mine[\\/]steps[\\/]/.test(f.file))) return null;
|
|
16352
|
+
const at = lines.findIndex((line, n) => n > lastFrame && line !== "" && !/^\s/.test(line));
|
|
16353
|
+
if (at < 0) return null;
|
|
16354
|
+
const m = /^([A-Za-z_][\w.]*)(?::\s?(.*))?$/.exec(lines[at] ?? "");
|
|
16355
|
+
if (m === null) return null;
|
|
16356
|
+
const errorType = m[1] ?? "Error";
|
|
16357
|
+
if (/(?:^|\.)(?:KeyboardInterrupt|SystemExit|Explained|Refusal)$/.test(errorType)) return null;
|
|
16358
|
+
const message = [m[2] ?? "", ...lines.slice(at + 1)].join("\n").trim();
|
|
16359
|
+
const innermost = frames[frames.length - 1];
|
|
16360
|
+
const firstLine = message.split("\n")[0] ?? "";
|
|
16361
|
+
return {
|
|
16362
|
+
errorType,
|
|
16363
|
+
message,
|
|
16364
|
+
trace: block,
|
|
16365
|
+
keep: "tail",
|
|
16366
|
+
frames: frames.slice(-3).map((f) => `${basename(f.file.replace(/\\/g, "/"))}:${f.func}`),
|
|
16367
|
+
python: pythonVersionIn(frames.map((f) => f.file)),
|
|
16368
|
+
essence: `${errorType}${firstLine === "" ? "" : `: ${firstLine}`}` + (innermost ? ` \u2014 ${basename(innermost.file.replace(/\\/g, "/"))}:${innermost.line}` : "")
|
|
16369
|
+
};
|
|
16370
|
+
}
|
|
16371
|
+
function pythonVersionIn(files) {
|
|
16372
|
+
for (const file2 of files) {
|
|
16373
|
+
const m = /python(\d)\.?(\d{1,2})[\\/]/i.exec(file2);
|
|
16374
|
+
if (m !== null) return `${m[1]}.${m[2]}`;
|
|
16375
|
+
}
|
|
16376
|
+
return null;
|
|
16377
|
+
}
|
|
16378
|
+
function jobLogTail(home, id) {
|
|
16379
|
+
const file2 = join(home, "logs", `${id}.log`);
|
|
16380
|
+
let fd = null;
|
|
16381
|
+
try {
|
|
16382
|
+
fd = openSync(file2, "r");
|
|
16383
|
+
const size = fstatSync(fd).size;
|
|
16384
|
+
const length = Math.min(size, JOB_LOG_TAIL);
|
|
16385
|
+
const buffer = Buffer.alloc(length);
|
|
16386
|
+
readSync(fd, buffer, 0, length, size - length);
|
|
16387
|
+
return buffer.toString("utf8");
|
|
16388
|
+
} catch {
|
|
16389
|
+
return "";
|
|
16390
|
+
} finally {
|
|
16391
|
+
if (fd !== null) try {
|
|
16392
|
+
closeSync(fd);
|
|
16393
|
+
} catch {
|
|
16394
|
+
}
|
|
16395
|
+
}
|
|
16396
|
+
}
|
|
16397
|
+
function fingerprintOf2(errorType, frames) {
|
|
16398
|
+
return createHash("sha256").update([errorType, ...frames].join("|")).digest("hex").slice(0, 16);
|
|
16399
|
+
}
|
|
16400
|
+
function secretsOf(input, depth = 0, out = []) {
|
|
16401
|
+
if (out.length >= 50 || depth > 4) return out;
|
|
16402
|
+
if (typeof input === "string") out.push(input);
|
|
16403
|
+
else if (Array.isArray(input)) for (const one of input) secretsOf(one, depth + 1, out);
|
|
16404
|
+
else if (typeof input === "object" && input !== null) {
|
|
16405
|
+
for (const one of Object.values(input)) secretsOf(one, depth + 1, out);
|
|
16406
|
+
}
|
|
16407
|
+
return out;
|
|
16408
|
+
}
|
|
16409
|
+
function recentCalls(home) {
|
|
16410
|
+
try {
|
|
16411
|
+
const text2 = readFileSync(join(home, CALLS_FILE), "utf8").slice(-8192);
|
|
16412
|
+
const names = [];
|
|
16413
|
+
for (const line of text2.split("\n")) {
|
|
16414
|
+
try {
|
|
16415
|
+
const tool = JSON.parse(line).tool;
|
|
16416
|
+
if (typeof tool === "string" && CRASH_TOOL_NAME.test(tool)) names.push(tool);
|
|
16417
|
+
} catch {
|
|
16418
|
+
}
|
|
16419
|
+
}
|
|
16420
|
+
return names.slice(-CRASH_LIMITS.recentCalls);
|
|
16421
|
+
} catch {
|
|
16422
|
+
return [];
|
|
16423
|
+
}
|
|
16424
|
+
}
|
|
16425
|
+
function hostFromContext(context) {
|
|
16426
|
+
const host = context?.host;
|
|
16427
|
+
return host !== void 0 && typeof host.name === "string" && typeof host.version === "string" ? host : null;
|
|
16428
|
+
}
|
|
16429
|
+
function hostOf(host) {
|
|
16430
|
+
return host === null ? null : { name: head(host.name, CRASH_LIMITS.hostName), version: head(host.version, CRASH_LIMITS.hostVersion) };
|
|
16431
|
+
}
|
|
16432
|
+
function probeFfmpeg(home) {
|
|
16433
|
+
const own = join(home, "bin", platform() === "win32" ? "ffmpeg.exe" : "ffmpeg");
|
|
16434
|
+
const program = existsSync(own) ? own : "ffmpeg";
|
|
16435
|
+
return new Promise((done) => {
|
|
16436
|
+
execFile(program, ["-version"], { timeout: 3e3, encoding: "utf8" }, (trouble, stdout) => {
|
|
16437
|
+
if (trouble !== null) return done(null);
|
|
16438
|
+
const m = /^ffmpeg version (\S+)/.exec(stdout);
|
|
16439
|
+
done(m?.[1] ?? null);
|
|
16440
|
+
});
|
|
16441
|
+
});
|
|
16442
|
+
}
|
|
16443
|
+
function ownDir() {
|
|
16444
|
+
try {
|
|
16445
|
+
return dirname(fileURLToPath(import.meta.url));
|
|
16446
|
+
} catch {
|
|
16447
|
+
return "";
|
|
16448
|
+
}
|
|
16449
|
+
}
|
|
16450
|
+
function safeUser() {
|
|
16451
|
+
try {
|
|
16452
|
+
return userInfo().username;
|
|
16453
|
+
} catch {
|
|
16454
|
+
return "";
|
|
16455
|
+
}
|
|
16456
|
+
}
|
|
16457
|
+
function head(text2, max) {
|
|
16458
|
+
return text2.length <= max ? text2 : text2.slice(0, max);
|
|
16459
|
+
}
|
|
16460
|
+
function tail(text2, max) {
|
|
16461
|
+
if (text2.length <= max) return text2;
|
|
16462
|
+
const cut = "\u2026(\u043D\u0430\u0447\u0430\u043B\u043E \u043E\u0431\u0440\u0435\u0437\u0430\u043D\u043E)\n";
|
|
16463
|
+
return cut + text2.slice(text2.length - (max - cut.length));
|
|
16464
|
+
}
|
|
16465
|
+
function orNull(value, max) {
|
|
16466
|
+
return value === null || value === "" ? null : head(value, max);
|
|
16467
|
+
}
|
|
16468
|
+
var WIDGET_MIME = "text/html;profile=mcp-app";
|
|
16469
|
+
function widgetStamp(html) {
|
|
16470
|
+
return createHash("sha256").update(html).digest("hex").slice(0, 8);
|
|
16471
|
+
}
|
|
16472
|
+
var WIDGET_PLATE_CSS = `
|
|
16473
|
+
:root { --plate: #ffffff; --plate-end: #f5f5f7; }
|
|
16474
|
+
:root:has(> body.dark) { --plate: #1d1d1f; --plate-end: #000000; }
|
|
16475
|
+
:root:has(> body.full) { min-height: 100%; }
|
|
16476
|
+
html {
|
|
16477
|
+
background: var(--plate-end) linear-gradient(var(--plate) calc(100% - 197px), var(--plate-end)) no-repeat;
|
|
16478
|
+
}
|
|
16479
|
+
`;
|
|
16480
|
+
var WIDGET_HEADING_CSS = `
|
|
16481
|
+
:root {
|
|
16482
|
+
--font-display: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Icons", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
|
16483
|
+
}
|
|
16484
|
+
h2, .end__t { font-family: var(--font-display); }
|
|
16485
|
+
`;
|
|
16486
|
+
|
|
16487
|
+
// src/runbar.ts
|
|
16488
|
+
var RUNBAR_RESOURCE_URI = `ui://naparnik/runbar-${widgetStamp(runbarWidgetHtml())}`;
|
|
16489
|
+
var RUNBAR_MIME = WIDGET_MIME;
|
|
16490
|
+
function runbarResource() {
|
|
16491
|
+
return {
|
|
16492
|
+
resource: {
|
|
16493
|
+
uri: RUNBAR_RESOURCE_URI,
|
|
16494
|
+
name: "\u0425\u043E\u0434 \u0440\u0430\u0431\u043E\u0442\u044B",
|
|
16495
|
+
description: "\u041F\u043E\u043B\u043E\u0441\u0430 \u044D\u0442\u0430\u043F\u043E\u0432: \u0447\u0442\u043E \u0434\u0435\u043B\u0430\u0435\u0442\u0441\u044F \u0441\u0435\u0439\u0447\u0430\u0441 \u0438 \u0441\u043A\u043E\u043B\u044C\u043A\u043E \u0443\u0436\u0435 \u0438\u0434\u0451\u0442",
|
|
16496
|
+
mimeType: RUNBAR_MIME
|
|
16497
|
+
},
|
|
16498
|
+
contents: [{
|
|
16499
|
+
uri: RUNBAR_RESOURCE_URI,
|
|
15577
16500
|
mimeType: RUNBAR_MIME,
|
|
15578
16501
|
text: runbarWidgetHtml(),
|
|
15579
16502
|
_meta: { ui: { prefersBorder: true } }
|
|
@@ -16233,121 +17156,6 @@ function runbarWidgetHtml() {
|
|
|
16233
17156
|
</html>`;
|
|
16234
17157
|
}
|
|
16235
17158
|
|
|
16236
|
-
// src/progress.ts
|
|
16237
|
-
var realPace = {
|
|
16238
|
-
now: () => Date.now(),
|
|
16239
|
-
rest: (ms) => new Promise((done) => {
|
|
16240
|
-
setTimeout(done, ms);
|
|
16241
|
-
})
|
|
16242
|
-
};
|
|
16243
|
-
var WAIT_LIMIT_SECONDS = 55;
|
|
16244
|
-
var POLL_EVERY_MS = 2e3;
|
|
16245
|
-
var JOB_STILL_COMPUTING = "\u0415\u0449\u0451 \u0441\u0447\u0438\u0442\u0430\u0435\u0442";
|
|
16246
|
-
var JOB_IN_QUEUE = "\u0416\u0434\u0451\u0442 \u043E\u0447\u0435\u0440\u0435\u0434\u0438";
|
|
16247
|
-
function stillWorking(text) {
|
|
16248
|
-
return text.includes(JOB_STILL_COMPUTING) || text.includes(JOB_IN_QUEUE);
|
|
16249
|
-
}
|
|
16250
|
-
function waitSeconds(asked) {
|
|
16251
|
-
if (asked === void 0 || !Number.isFinite(asked) || asked <= 0) return 0;
|
|
16252
|
-
return Math.min(Math.round(asked), WAIT_LIMIT_SECONDS);
|
|
16253
|
-
}
|
|
16254
|
-
function freshLines(text, told) {
|
|
16255
|
-
const news = [];
|
|
16256
|
-
for (const row of text.split("\n").slice(1)) {
|
|
16257
|
-
const line = row.trim();
|
|
16258
|
-
if (line.length === 0) continue;
|
|
16259
|
-
if (line.startsWith(JOB_STILL_COMPUTING)) continue;
|
|
16260
|
-
if (told.has(line)) continue;
|
|
16261
|
-
told.add(line);
|
|
16262
|
-
news.push(line);
|
|
16263
|
-
}
|
|
16264
|
-
return news;
|
|
16265
|
-
}
|
|
16266
|
-
async function followJob(opts) {
|
|
16267
|
-
const pace = opts.pace ?? realPace;
|
|
16268
|
-
const until = pace.now() + opts.seconds * 1e3;
|
|
16269
|
-
const told = /* @__PURE__ */ new Set();
|
|
16270
|
-
let state = await opts.ask();
|
|
16271
|
-
retell(state, told, opts.tell);
|
|
16272
|
-
while (state.ok && stillWorking(state.text) && pace.now() < until) {
|
|
16273
|
-
await pace.rest(POLL_EVERY_MS);
|
|
16274
|
-
try {
|
|
16275
|
-
state = await opts.ask();
|
|
16276
|
-
} catch {
|
|
16277
|
-
continue;
|
|
16278
|
-
}
|
|
16279
|
-
retell(state, told, opts.tell);
|
|
16280
|
-
}
|
|
16281
|
-
return state;
|
|
16282
|
-
}
|
|
16283
|
-
function retell(state, told, tell) {
|
|
16284
|
-
if (tell === void 0) return;
|
|
16285
|
-
for (const line of freshLines(state.text, told)) tell(line);
|
|
16286
|
-
}
|
|
16287
|
-
var STAGE_WORDS = {
|
|
16288
|
-
silence: "\u0443\u0431\u0435\u0440\u0443 \u043F\u0430\u0443\u0437\u044B",
|
|
16289
|
-
voice: "\u0432\u044B\u0440\u043E\u0432\u043D\u044F\u044E \u0433\u043E\u043B\u043E\u0441",
|
|
16290
|
-
speech: "\u0440\u0430\u0441\u043F\u043E\u0437\u043D\u0430\u044E \u0440\u0435\u0447\u044C",
|
|
16291
|
-
phrases: "\u0440\u0430\u0437\u043B\u043E\u0436\u0443 \u0440\u0435\u0447\u044C \u043D\u0430 \u0444\u0440\u0430\u0437\u044B",
|
|
16292
|
-
plan: "\u043F\u0440\u0438\u0434\u0443\u043C\u0430\u044E, \u0447\u0442\u043E \u043F\u043E\u043A\u0430\u0437\u0430\u0442\u044C \u0438 \u043A\u043E\u0433\u0434\u0430",
|
|
16293
|
-
world: "\u043D\u0430\u0440\u0438\u0441\u0443\u044E \u0444\u043E\u043D \u0437\u0430 \u0433\u0435\u0440\u043E\u0435\u043C",
|
|
16294
|
-
cutout: "\u043E\u0442\u0434\u0435\u043B\u044E \u0433\u0435\u0440\u043E\u044F \u043E\u0442 \u0444\u043E\u043D\u0430",
|
|
16295
|
-
"hero-on-world": "\u043F\u043E\u0441\u0442\u0430\u0432\u043B\u044E \u0433\u0435\u0440\u043E\u044F \u043D\u0430 \u0444\u043E\u043D",
|
|
16296
|
-
shots: "\u0440\u0430\u0441\u0441\u0442\u0430\u0432\u043B\u044E \u043A\u0440\u0443\u043F\u043D\u043E\u0441\u0442\u0438 \u043F\u043E \u043F\u043B\u0430\u043D\u0443",
|
|
16297
|
-
screen: "\u0432\u0441\u0442\u0430\u0432\u043B\u044E \u0437\u0430\u043F\u0438\u0441\u044C \u044D\u043A\u0440\u0430\u043D\u0430",
|
|
16298
|
-
inserts: "\u043D\u0430\u0440\u0438\u0441\u0443\u044E \u0433\u0440\u0430\u0444\u0438\u043A\u0443 \u043F\u043E \u043F\u043B\u0430\u043D\u0443",
|
|
16299
|
-
subtitles: "\u043D\u0430\u0440\u0438\u0441\u0443\u044E \u0441\u0443\u0431\u0442\u0438\u0442\u0440\u044B",
|
|
16300
|
-
layers: "\u043F\u043E\u043B\u043E\u0436\u0443 \u043A\u0430\u0440\u0442\u0438\u043D\u043A\u0438 \u043F\u043E\u0432\u0435\u0440\u0445",
|
|
16301
|
-
accents: "\u0440\u0430\u0441\u0441\u0442\u0430\u0432\u043B\u044E \u0437\u0432\u0443\u043A\u043E\u0432\u044B\u0435 \u0430\u043A\u0446\u0435\u043D\u0442\u044B",
|
|
16302
|
-
mix: "\u0441\u0432\u0435\u0434\u0443 \u0437\u0432\u0443\u043A",
|
|
16303
|
-
intro: "\u043F\u043E\u0441\u0442\u0430\u0432\u043B\u044E \u043A\u0430\u0440\u0442\u043E\u0447\u043A\u0443 \u0432 \u043D\u0430\u0447\u0430\u043B\u043E"
|
|
16304
|
-
};
|
|
16305
|
-
var NEAR_STEPS = 3;
|
|
16306
|
-
function montageLadder(stages) {
|
|
16307
|
-
const words = stages.map((stage) => STAGE_WORDS[stage]).filter((word) => word !== void 0);
|
|
16308
|
-
if (words.length === 0) return [];
|
|
16309
|
-
const near = words.slice(0, NEAR_STEPS);
|
|
16310
|
-
const far = words.slice(NEAR_STEPS);
|
|
16311
|
-
const lines = [`\u0421\u043D\u0430\u0447\u0430\u043B\u0430 ${near.join(", \u043F\u043E\u0442\u043E\u043C ")}.`];
|
|
16312
|
-
if (far.length > 0) {
|
|
16313
|
-
lines.push(
|
|
16314
|
-
`\u0414\u0430\u043B\u044C\u0448\u0435: ${far.join(", ")}. \u0428\u0430\u0433\u043E\u0432 \u0432\u0441\u0435\u0433\u043E \u0434\u043E ${stages.length} \u2014 \u0447\u0442\u043E \u043D\u0435 \u043F\u043E\u043D\u0430\u0434\u043E\u0431\u0438\u0442\u0441\u044F, \u043F\u0440\u043E\u043F\u0443\u0449\u0443.`
|
|
16315
|
-
);
|
|
16316
|
-
}
|
|
16317
|
-
return lines;
|
|
16318
|
-
}
|
|
16319
|
-
var PAUSES_LADDER = [
|
|
16320
|
-
"\u0423\u0431\u0435\u0440\u0443 \u043C\u043E\u043B\u0447\u0430\u043D\u0438\u0435 \u0438 \u0437\u0430\u043F\u0438\u043D\u043A\u0438 \u2014 \u0431\u043E\u043B\u044C\u0448\u0435 \u043D\u0438\u0447\u0435\u0433\u043E \u043D\u0435 \u0442\u0440\u043E\u0433\u0430\u044E.",
|
|
16321
|
-
"\u0421\u0443\u0431\u0442\u0438\u0442\u0440\u044B, \u043A\u0430\u0440\u0442\u0438\u043D\u043A\u0438 \u043F\u043E\u0432\u0435\u0440\u0445 \u0438 \u0437\u0432\u0443\u043A \u2014 \u044D\u0442\u043E \u043E\u0442\u0434\u0435\u043B\u044C\u043D\u0430\u044F \u0440\u0430\u0431\u043E\u0442\u0430, \u0435\u0451 \u0437\u0434\u0435\u0441\u044C \u043D\u0435\u0442."
|
|
16322
|
-
];
|
|
16323
|
-
var PAYLOAD_LADDER = [
|
|
16324
|
-
"\u0421\u043D\u0430\u0447\u0430\u043B\u0430 \u043F\u043E\u043B\u043E\u0436\u0443 \u0434\u0432\u0438\u0436\u043E\u043A \u043C\u043E\u043D\u0442\u0430\u0436\u0430 \u043E\u0434\u043D\u043E\u0439 \u043F\u0430\u043F\u043A\u043E\u0439 \u2014 \u0432 \u0441\u0438\u0441\u0442\u0435\u043C\u0443 \u043D\u0438\u0447\u0435\u0433\u043E \u043D\u0435 \u0441\u0442\u0430\u0432\u0438\u0442\u0441\u044F.",
|
|
16325
|
-
"\u041F\u043E\u0442\u043E\u043C ffmpeg, python \u0438 \u043E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u0435 \u043C\u043E\u043D\u0442\u0430\u0436\u0430. \u0422\u044F\u0436\u0451\u043B\u043E\u0435 \u2014 \u0440\u0430\u0441\u043F\u043E\u0437\u043D\u0430\u0432\u0430\u043D\u0438\u0435 \u0440\u0435\u0447\u0438, \u0432\u044B\u0440\u0435\u0437 \u0433\u0435\u0440\u043E\u044F, \u0447\u0438\u0441\u0442\u043A\u0430 \u0433\u043E\u043B\u043E\u0441\u0430 \u2014 \u0441\u0442\u0430\u0432\u0438\u0442\u0441\u044F \u043E\u0442\u0434\u0435\u043B\u044C\u043D\u043E \u0438 \u0442\u043E\u043B\u044C\u043A\u043E \u043F\u043E \u043F\u0440\u043E\u0441\u044C\u0431\u0435."
|
|
16326
|
-
];
|
|
16327
|
-
var INSTALL_WORDS = {
|
|
16328
|
-
ffmpeg: "\u043F\u043E\u0441\u0442\u0430\u0432\u043B\u044E ffmpeg \u2014 \u0438\u043C \u0441\u043E\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044F \u0432\u0438\u0434\u0435\u043E",
|
|
16329
|
-
python: "\u043F\u043E\u0441\u0442\u0430\u0432\u043B\u044E python",
|
|
16330
|
-
env: "\u0441\u043E\u0431\u0435\u0440\u0443 \u043E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u0435 \u043C\u043E\u043D\u0442\u0430\u0436\u0430",
|
|
16331
|
-
model: "\u0441\u043A\u0430\u0447\u0430\u044E \u043C\u043E\u0434\u0435\u043B\u044C \u0440\u0430\u0441\u043F\u043E\u0437\u043D\u0430\u0432\u0430\u043D\u0438\u044F \u0440\u0435\u0447\u0438 \u2014 \u043E\u043D\u0430 \u0438\u0437 \u0432\u0441\u0435\u0433\u043E \u0441\u0430\u043C\u0430\u044F \u0442\u044F\u0436\u0451\u043B\u0430\u044F",
|
|
16332
|
-
cutout: "\u0441\u043A\u0430\u0447\u0430\u044E \u0442\u043E, \u0447\u0435\u043C \u043E\u0442\u0434\u0435\u043B\u044F\u044E \u0433\u0435\u0440\u043E\u044F \u043E\u0442 \u0444\u043E\u043D\u0430",
|
|
16333
|
-
voice: "\u0441\u043A\u0430\u0447\u0430\u044E \u0442\u043E, \u0447\u0435\u043C \u0447\u0438\u0449\u0443 \u0433\u043E\u043B\u043E\u0441",
|
|
16334
|
-
browser: "\u043F\u043E\u0441\u0442\u0430\u0432\u043B\u044E \u0431\u0440\u0430\u0443\u0437\u0435\u0440, \u043A\u043E\u0442\u043E\u0440\u044B\u043C \u0440\u0438\u0441\u0443\u044E \u0433\u0440\u0430\u0444\u0438\u043A\u0443"
|
|
16335
|
-
};
|
|
16336
|
-
function installLadder(step) {
|
|
16337
|
-
if (step === "all") {
|
|
16338
|
-
return [
|
|
16339
|
-
"\u041F\u0440\u043E\u0432\u0435\u0440\u044E, \u0447\u0435\u0433\u043E \u043D\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442, \u0438 \u0434\u043E\u0441\u0442\u0430\u0432\u043B\u044E \u043F\u043E \u043E\u0447\u0435\u0440\u0435\u0434\u0438.",
|
|
16340
|
-
"\u0422\u044F\u0436\u0451\u043B\u043E\u0435 \u0441\u044E\u0434\u0430 \u043D\u0435 \u0432\u0445\u043E\u0434\u0438\u0442: \u0440\u0430\u0441\u043F\u043E\u0437\u043D\u0430\u0432\u0430\u043D\u0438\u0435 \u0440\u0435\u0447\u0438 \u0438 \u0432\u044B\u0440\u0435\u0437 \u0433\u0435\u0440\u043E\u044F \u0441\u0442\u0430\u0432\u044F\u0442\u0441\u044F \u043E\u0442\u0434\u0435\u043B\u044C\u043D\u043E \u0438 \u0442\u043E\u043B\u044C\u043A\u043E \u043F\u043E\u0441\u043B\u0435 \xAB\u0434\u0430\xBB \u043E\u0442 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430."
|
|
16341
|
-
];
|
|
16342
|
-
}
|
|
16343
|
-
const word = INSTALL_WORDS[step];
|
|
16344
|
-
if (word === void 0) return [];
|
|
16345
|
-
return [
|
|
16346
|
-
`\u0421\u0435\u0439\u0447\u0430\u0441 ${word}.`,
|
|
16347
|
-
"\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."
|
|
16348
|
-
];
|
|
16349
|
-
}
|
|
16350
|
-
|
|
16351
17159
|
// src/tool-kit.ts
|
|
16352
17160
|
function manifestUrl(engine, baseUrl) {
|
|
16353
17161
|
return engine.variable("NAPARNIK_UPDATE_MANIFEST") ?? manifestUrlFor(baseUrl);
|
|
@@ -16551,7 +17359,7 @@ async function startMontage(engine, opts) {
|
|
|
16551
17359
|
return toolSuccess(
|
|
16552
17360
|
`\u0417\u0430\u0434\u0430\u0447\u0430 ${launch.id}: ${opts.what}
|
|
16553
17361
|
\u0412\u0441\u0451 \u0434\u0435\u043B\u0430\u0435\u0442\u0441\u044F \u043D\u0430 \u043A\u043E\u043C\u043F\u044C\u044E\u0442\u0435\u0440\u0435 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044F. ${opts.hint}
|
|
16554
|
-
\u0420\u0430\u0431\u043E\u0442\u0430 \u043F\u0435\u0440\u0435\u0436\u0438\u0432\u0430\u0435\u0442 \u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u043A \u043F\u0440\u043E\u0433\u0440\u0430\u043C\u043C\u044B: \u043D\u043E\u043C\u0435\u0440 \u0437\u0430\u0434\u0430\u0447\u0438 \u0437\u0430\u043F\u043E\u043C\u043D\u0438 \u0438 \u043F\u043E\u0437\u043E\u0432\u0438 wait \u0441 job "${launch.id}" \u2014 \u043E\u043D \u043F\u043E\u0434\u043E\u0436\u0434\u0451\u0442 \u0438 \u0440\u0430\u0441\u0441\u043A\u0430\u0436\u0435\u0442 \u0445\u043E\u0434 \u043F\u043E \u0448\u0430\u0433\u0430\u043C, \u043F\u0435\u0440\u0435\u0441\u043A\u0430\u0437\u044B\u0432\u0430\u0439 \u0435\u0433\u043E \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0443 \u0441\u0440\u0430\u0437\u0443
|
|
17362
|
+
\u0420\u0430\u0431\u043E\u0442\u0430 \u043F\u0435\u0440\u0435\u0436\u0438\u0432\u0430\u0435\u0442 \u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u043A \u043F\u0440\u043E\u0433\u0440\u0430\u043C\u043C\u044B: \u043D\u043E\u043C\u0435\u0440 \u0437\u0430\u0434\u0430\u0447\u0438 \u0437\u0430\u043F\u043E\u043C\u043D\u0438 \u0438 \u043F\u043E\u0437\u043E\u0432\u0438 wait \u0441 job "${launch.id}" \u2014 \u043E\u043D \u043F\u043E\u0434\u043E\u0436\u0434\u0451\u0442 \u0438 \u0440\u0430\u0441\u0441\u043A\u0430\u0436\u0435\u0442 \u0445\u043E\u0434 \u043F\u043E \u0448\u0430\u0433\u0430\u043C, \u043F\u0435\u0440\u0435\u0441\u043A\u0430\u0437\u044B\u0432\u0430\u0439 \u0435\u0433\u043E \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0443 \u0441\u0440\u0430\u0437\u0443. ${AWAY_NOTE}`,
|
|
16555
17363
|
startedJob({
|
|
16556
17364
|
id: launch.id,
|
|
16557
17365
|
what: opts.what,
|
|
@@ -16560,10 +17368,10 @@ async function startMontage(engine, opts) {
|
|
|
16560
17368
|
})
|
|
16561
17369
|
);
|
|
16562
17370
|
}
|
|
16563
|
-
function fromWords(
|
|
17371
|
+
function fromWords(text2, contract) {
|
|
16564
17372
|
let data;
|
|
16565
17373
|
try {
|
|
16566
|
-
data = JSON.parse(
|
|
17374
|
+
data = JSON.parse(text2);
|
|
16567
17375
|
} catch {
|
|
16568
17376
|
return { refusal: NOT_JSON };
|
|
16569
17377
|
}
|
|
@@ -16573,13 +17381,13 @@ function fromWords(text, contract) {
|
|
|
16573
17381
|
if (typeof data.words !== "string" || data.words === "") return { refusal: NOT_JSON };
|
|
16574
17382
|
return { words: data.words, data };
|
|
16575
17383
|
}
|
|
16576
|
-
function folderAnswer(
|
|
16577
|
-
const read = fromWords(
|
|
17384
|
+
function folderAnswer(text2) {
|
|
17385
|
+
const read = fromWords(text2);
|
|
16578
17386
|
return "refusal" in read ? toolError(read.refusal) : toolSuccess(read.words, read.data);
|
|
16579
17387
|
}
|
|
16580
17388
|
function nameOrRefusal(candidate) {
|
|
16581
|
-
const
|
|
16582
|
-
if (!
|
|
17389
|
+
const looksLikePath2 = candidate.includes("/") || candidate.includes("\\") || candidate.startsWith("~") || candidate.startsWith(".") || candidate.length > 1 && candidate[1] === ":";
|
|
17390
|
+
if (!looksLikePath2) return { name: candidate };
|
|
16583
17391
|
return {
|
|
16584
17392
|
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}
|
|
16585
17393
|
\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.`
|
|
@@ -16706,7 +17514,7 @@ ${EXTRAS_LATER}`), later]);
|
|
|
16706
17514
|
if ("refusal" in launch) return toolError(launch.refusal);
|
|
16707
17515
|
return toolSuccess(
|
|
16708
17516
|
`\u0417\u0430\u0434\u0430\u0447\u0430 ${launch.id}: \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0430, \u0448\u0430\u0433 \xAB${step}\xBB.
|
|
16709
|
-
\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
|
|
17517
|
+
\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}`,
|
|
16710
17518
|
startedJob({
|
|
16711
17519
|
id: launch.id,
|
|
16712
17520
|
what: `\u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0430, \u0448\u0430\u0433 \xAB${step}\xBB`,
|
|
@@ -16729,9 +17537,9 @@ async function updateEngine(engine, consent, key, baseUrl, timeoutMs = ASKED_POI
|
|
|
16729
17537
|
const outcome = await fetchManifest(manifestUrl(engine, baseUrl), timeoutMs, key);
|
|
16730
17538
|
const decision = decide(engine.freshVersion(), outcome.ok ? outcome.manifest : null);
|
|
16731
17539
|
if (decision.what === "nothing") {
|
|
16732
|
-
const
|
|
17540
|
+
const ownDir2 = engine.freshVersion();
|
|
16733
17541
|
return toolSuccess(
|
|
16734
|
-
!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 (${
|
|
17542
|
+
!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.`
|
|
16735
17543
|
);
|
|
16736
17544
|
}
|
|
16737
17545
|
if (decision.what === "shell_too_old") {
|
|
@@ -16925,11 +17733,11 @@ async function askBeforeHeavy(engine, step, model, key, baseUrl) {
|
|
|
16925
17733
|
]));
|
|
16926
17734
|
}
|
|
16927
17735
|
function together(results) {
|
|
16928
|
-
const
|
|
17736
|
+
const text2 = results.map((one) => one.type === "success" ? wordsOf(one.content) : one.error).filter((words) => words !== "").join("\n\n");
|
|
16929
17737
|
for (const one of results) {
|
|
16930
|
-
if (one.type === "success" && one.structured !== void 0) return toolSuccess(
|
|
17738
|
+
if (one.type === "success" && one.structured !== void 0) return toolSuccess(text2, one.structured);
|
|
16931
17739
|
}
|
|
16932
|
-
return results.some((one) => one.type === "error") ? toolError(
|
|
17740
|
+
return results.some((one) => one.type === "error") ? toolError(text2) : toolSuccess(text2);
|
|
16933
17741
|
}
|
|
16934
17742
|
function wordsOf(content) {
|
|
16935
17743
|
if (typeof content === "string") return content;
|
|
@@ -16973,10 +17781,10 @@ async function openReel(engine, asked) {
|
|
|
16973
17781
|
var PLAN_DRAFT = "naparnik-plan-draft/1";
|
|
16974
17782
|
var COMPOSITION_VIEW = "naparnik-composition-view/1";
|
|
16975
17783
|
var SKILLS_READ = "naparnik-skills-read/1";
|
|
16976
|
-
function answerOrRefusal(
|
|
16977
|
-
const read = fromWords(
|
|
17784
|
+
function answerOrRefusal(text2, contract) {
|
|
17785
|
+
const read = fromWords(text2, contract);
|
|
16978
17786
|
if ("refusal" in read) {
|
|
16979
|
-
const plain =
|
|
17787
|
+
const plain = text2.trim();
|
|
16980
17788
|
return { refusal: plain.startsWith("{") || plain === "" ? read.refusal : plain };
|
|
16981
17789
|
}
|
|
16982
17790
|
const said = read.data;
|
|
@@ -17076,10 +17884,10 @@ async function planDraft(engine, asked, key, tell) {
|
|
|
17076
17884
|
}
|
|
17077
17885
|
}
|
|
17078
17886
|
if (tell !== void 0) for (const line of DRAFT_LADDER) tell(line);
|
|
17079
|
-
const
|
|
17887
|
+
const head2 = opened !== null && opened.type === "success" && typeof opened.content === "string" ? `${opened.content}
|
|
17080
17888
|
|
|
17081
17889
|
` : "";
|
|
17082
|
-
const withHead = (
|
|
17890
|
+
const withHead = (text2) => `${head2}${text2}`;
|
|
17083
17891
|
const answer = await engine.command([
|
|
17084
17892
|
"plan-draft",
|
|
17085
17893
|
"--video",
|
|
@@ -17672,7 +18480,7 @@ async function startComposition(engine, reel, key, tell) {
|
|
|
17672
18480
|
if ("refusal" in launch) return toolError(launch.refusal);
|
|
17673
18481
|
return toolSuccess(
|
|
17674
18482
|
`\u0417\u0430\u0434\u0430\u0447\u0430 ${launch.id}: \u043C\u043E\u043D\u0442\u0430\u0436 ${basename(reel)}
|
|
17675
|
-
\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
|
|
18483
|
+
\u0414\u0430\u043B\u044C\u0448\u0435 \u043F\u043E\u0437\u043E\u0432\u0438 wait \u0441 \u044D\u0442\u0438\u043C \u043D\u043E\u043C\u0435\u0440\u043E\u043C. ${AWAY_NOTE}`,
|
|
17676
18484
|
startedJob({
|
|
17677
18485
|
id: launch.id,
|
|
17678
18486
|
what: `\u043C\u043E\u043D\u0442\u0430\u0436 ${basename(reel)}`,
|
|
@@ -18002,10 +18810,10 @@ var OWN_STYLE_FOLDER = "style";
|
|
|
18002
18810
|
function contractRefusal(theirs) {
|
|
18003
18811
|
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 \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.`;
|
|
18004
18812
|
}
|
|
18005
|
-
function notJson(
|
|
18006
|
-
const
|
|
18007
|
-
return NOT_JSON2 + (
|
|
18008
|
-
\u0427\u0442\u043E \u043F\u0440\u0438\u0448\u043B\u043E \u0432\u043C\u0435\u0441\u0442\u043E JSON: \xAB${
|
|
18813
|
+
function notJson(text2) {
|
|
18814
|
+
const head2 = text2.trim().slice(0, 160).replace(/\s+/g, " ");
|
|
18815
|
+
return NOT_JSON2 + (head2 ? `
|
|
18816
|
+
\u0427\u0442\u043E \u043F\u0440\u0438\u0448\u043B\u043E \u0432\u043C\u0435\u0441\u0442\u043E JSON: \xAB${head2}\u2026\xBB` : "");
|
|
18009
18817
|
}
|
|
18010
18818
|
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 \u0434\u0432\u0438\u0436\u043E\u043A \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u043E\u043C setup \u0441 what=engine \u0438 \u043F\u043E\u0432\u0442\u043E\u0440\u0438.";
|
|
18011
18819
|
var FIRST_BATCH = 12;
|
|
@@ -18353,7 +19161,7 @@ async function showCards(engine, input) {
|
|
|
18353
19161
|
// «Готово» требовало ответить и там. Нашло ревью устройства
|
|
18354
19162
|
// 2026-09-18.
|
|
18355
19163
|
only: wanted2,
|
|
18356
|
-
clip:
|
|
19164
|
+
clip: basename5(where.path),
|
|
18357
19165
|
video: where.path,
|
|
18358
19166
|
// ⚠ СЫРЬЁ ПРЕВЬЮ ЕДЕТ ФОРМЕ ЦЕЛИКОМ: чистый кадр, числа вида и
|
|
18359
19167
|
// умолчания движка. Картинку она складывает сама (решение владельца
|
|
@@ -18432,7 +19240,7 @@ function questionInWords(q) {
|
|
|
18432
19240
|
return `${q.title} ${shown}${rest}`;
|
|
18433
19241
|
}
|
|
18434
19242
|
var LATIN_NAME = /^[a-z][a-z0-9_-]{0,31}$/;
|
|
18435
|
-
function
|
|
19243
|
+
function basename5(path2) {
|
|
18436
19244
|
const parts = path2.split(/[\\/]/);
|
|
18437
19245
|
return parts[parts.length - 1] ?? path2;
|
|
18438
19246
|
}
|
|
@@ -21119,44 +21927,6 @@ function chooseWidgetHtml() {
|
|
|
21119
21927
|
</body>
|
|
21120
21928
|
</html>`;
|
|
21121
21929
|
}
|
|
21122
|
-
var CALLS_FILE = "calls.jsonl";
|
|
21123
|
-
var CALLS_PREVIOUS = "calls.1.jsonl";
|
|
21124
|
-
var CALLS_CAP_BYTES = 1e6;
|
|
21125
|
-
function withCallLog(home, now = () => Date.now()) {
|
|
21126
|
-
return (tool) => {
|
|
21127
|
-
const original = tool.execute.bind(tool);
|
|
21128
|
-
return {
|
|
21129
|
-
...tool,
|
|
21130
|
-
async execute(input, ...rest) {
|
|
21131
|
-
const started = now();
|
|
21132
|
-
const result = await original(input, ...rest);
|
|
21133
|
-
write(home, {
|
|
21134
|
-
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
21135
|
-
tool: tool.name,
|
|
21136
|
-
ok: result.type === "success",
|
|
21137
|
-
ms: now() - started
|
|
21138
|
-
});
|
|
21139
|
-
return result;
|
|
21140
|
-
}
|
|
21141
|
-
};
|
|
21142
|
-
};
|
|
21143
|
-
}
|
|
21144
|
-
function write(home, line) {
|
|
21145
|
-
try {
|
|
21146
|
-
mkdirSync(home, { recursive: true });
|
|
21147
|
-
const file2 = join(home, CALLS_FILE);
|
|
21148
|
-
rotate(file2, join(home, CALLS_PREVIOUS));
|
|
21149
|
-
appendFileSync(file2, `${JSON.stringify(line)}
|
|
21150
|
-
`, { encoding: "utf8", mode: 384 });
|
|
21151
|
-
} catch {
|
|
21152
|
-
}
|
|
21153
|
-
}
|
|
21154
|
-
function rotate(file2, previous) {
|
|
21155
|
-
try {
|
|
21156
|
-
if (statSync(file2).size >= CALLS_CAP_BYTES) renameSync(file2, previous);
|
|
21157
|
-
} catch {
|
|
21158
|
-
}
|
|
21159
|
-
}
|
|
21160
21930
|
|
|
21161
21931
|
// src/update-nudge.ts
|
|
21162
21932
|
function usable2(value) {
|
|
@@ -21317,7 +22087,7 @@ ${result.content}` : [{ type: "text", text: header }, ...result.content]
|
|
|
21317
22087
|
}
|
|
21318
22088
|
|
|
21319
22089
|
// src/tool-registry.ts
|
|
21320
|
-
function buildAll(client, engine, passport, key, baseUrl, pace = realPace) {
|
|
22090
|
+
function buildAll(client, engine, passport, key, baseUrl, pace = realPace, awake = ASLEEP, crashes = null) {
|
|
21321
22091
|
return [
|
|
21322
22092
|
// Порядок — это порядок работы, и модель читает список сверху вниз:
|
|
21323
22093
|
// проверить машину, придумать словами, поправить словами, собрать, дождаться.
|
|
@@ -21349,7 +22119,16 @@ function buildAll(client, engine, passport, key, baseUrl, pace = realPace) {
|
|
|
21349
22119
|
// ходы МОДЕЛИ, а ход, отбитый опиской или мёртвой подпиской, стоил тех же
|
|
21350
22120
|
// секунд. Встань счётчик внутрь — из замера выпали бы именно неудачные
|
|
21351
22121
|
// ходы, то есть самые дорогие (`call-log.ts`).
|
|
21352
|
-
|
|
22122
|
+
//
|
|
22123
|
+
// ⚠ «НЕ СПИ» — СНАРУЖИ СВЕРКИ И ЗАСЛОНА, ПОД СЧЁТЧИКОМ. Держит любой ход
|
|
22124
|
+
// модели, в том числе отбитый: раз модель зовёт — она работает, и хвост
|
|
22125
|
+
// бодрости после него нужен так же (`keep-awake.ts`). Счётчик остаётся
|
|
22126
|
+
// самым внешним по доводу выше.
|
|
22127
|
+
//
|
|
22128
|
+
// ⚠ ЛОВУШКА ПОЛОМОК — СНАРУЖИ СВЕРКИ И ЗАСЛОНА: падение в самом заслоне
|
|
22129
|
+
// подписки — тоже наш баг, и его надо поймать. Под счётчиком — чтобы
|
|
22130
|
+
// пойманный вызов лёг в журнал отказом, а не пропал из замера.
|
|
22131
|
+
].map(withSubscription(client)).map(withArgs).map(withCrashReport(crashes)).map(withWakefulness(awake)).map(withCallLog(engine.home()));
|
|
21353
22132
|
}
|
|
21354
22133
|
function buildResources() {
|
|
21355
22134
|
return [chooseResource(), runbarResource()];
|
|
@@ -21402,8 +22181,8 @@ function buildBlock(entryFile, key) {
|
|
|
21402
22181
|
function withoutBom(string5) {
|
|
21403
22182
|
return string5.charCodeAt(0) === 65279 ? string5.slice(1) : string5;
|
|
21404
22183
|
}
|
|
21405
|
-
function findBlock(
|
|
21406
|
-
const lines =
|
|
22184
|
+
function findBlock(text2) {
|
|
22185
|
+
const lines = text2.split("\n");
|
|
21407
22186
|
const heading = new RegExp(`^\\[mcp_servers\\.(?:${SERVER_NAME}|"${SERVER_NAME}")\\]\\s*$`);
|
|
21408
22187
|
const child = new RegExp(`^\\[mcp_servers\\.(?:${SERVER_NAME}|"${SERVER_NAME}")\\.`);
|
|
21409
22188
|
const i = lines.findIndex((s) => heading.test(s));
|
|
@@ -21428,8 +22207,8 @@ function keyFromBlock(blockText) {
|
|
|
21428
22207
|
}
|
|
21429
22208
|
return void 0;
|
|
21430
22209
|
}
|
|
21431
|
-
function keyInTable(
|
|
21432
|
-
const lines =
|
|
22210
|
+
function keyInTable(text2) {
|
|
22211
|
+
const lines = text2.split("\n");
|
|
21433
22212
|
let inTable = false;
|
|
21434
22213
|
for (const raw of lines) {
|
|
21435
22214
|
const s = withoutBom(raw);
|
|
@@ -21546,4 +22325,4 @@ ${inTable}`, file2);
|
|
|
21546
22325
|
};
|
|
21547
22326
|
}
|
|
21548
22327
|
|
|
21549
|
-
export { DEFAULT_HOME, DeliveryError, Engine, ForeignBlockError, INSIDE_PYTHON, INSTALL_STEPS, KEEP_COPIES, KEEP_VERSIONS, LONG_STEPS, MANIFEST_TIMEOUT_MS, MANIFEST_URL, MARKER, MIN_ENGINE, McpServer, NaparnikApiClient, NaparnikAuthError, NaparnikClientError, NaparnikConfigError, NaparnikError, NaparnikInsufficientBalanceError, NaparnikScopeError, NaparnikServerError, NaparnikTimeoutError, PAUSE_HOURS, SERVER_NAME, SOURCES_FILE, START_SEC, StdioServerTransport, TOOL_SEC, USER_AGENT, VERSION, WHERE_TO_GET_KEY, buildAll, buildBlock, buildResources, bundleUrlFor, chooseBody, compare, configPath, currentMachineFingerprint, decide, decideShell, defineTool, deploy, downloadFile, fetchManifest, fetchShellManifest, fileOrRefusal, findBlock, fromHost, fromNpxCache, handOverToBody, inside, install, installPayload, installPython, installStep, installedShell, jsonSchemaOf, keyFromBlock, keyInTable, lastLine, loadConfig, manifestUrlFor, markChecked, markChecked2, markCurrent2 as markCurrent, parseEngineManifest, parseFailure, path, platformKey, previousVersion2 as previousVersion, probe, pythonSource, readConfig, refusalFor, remove, rollback, rollbackShell, shellDir, tarEntries, tidyOld2 as tidyOld, timeToCheck, timeToCheck2, unpackArchive, updateEngine, withArgs };
|
|
22328
|
+
export { CrashReporter, DEFAULT_HOME, DeliveryError, Engine, ForeignBlockError, INSIDE_PYTHON, INSTALL_STEPS, KEEP_COPIES, KEEP_VERSIONS, LONG_STEPS, MANIFEST_TIMEOUT_MS, MANIFEST_URL, MARKER, MIN_ENGINE, McpServer, NaparnikApiClient, NaparnikAuthError, NaparnikClientError, NaparnikConfigError, NaparnikError, NaparnikInsufficientBalanceError, NaparnikScopeError, NaparnikServerError, NaparnikTimeoutError, PAUSE_HOURS, SERVER_NAME, SOURCES_FILE, START_SEC, StdioServerTransport, TOOL_SEC, USER_AGENT, VERSION, WHERE_TO_GET_KEY, Wakefulness, buildAll, buildBlock, buildResources, bundleUrlFor, chooseBody, compare, configPath, currentMachineFingerprint, decide, decideShell, defineTool, deploy, downloadFile, fetchManifest, fetchShellManifest, fileOrRefusal, findBlock, fromHost, fromNpxCache, handOverToBody, inside, install, installPayload, installPython, installStep, installedShell, jsonSchemaOf, keyFromBlock, keyInTable, lastLine, loadConfig, manifestUrlFor, markChecked, markChecked2, markCurrent2 as markCurrent, parseEngineManifest, parseFailure, path, platformKey, previousVersion2 as previousVersion, probe, pythonSource, readConfig, realPace, refusalFor, remove, rollback, rollbackShell, shellDir, systemBlocker, tarEntries, tidyOld2 as tidyOld, timeToCheck, timeToCheck2, unpackArchive, updateEngine, watchProcessCrashes, withArgs };
|