@naparnik/mcp 0.1.0 → 0.10.11

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/dist/cli.d.ts CHANGED
@@ -1 +1,26 @@
1
1
  #!/usr/bin/env node
2
+ /**
3
+ * Режим установщика. Возвращает true, если аргументы разобраны и сервер
4
+ * поднимать не надо.
5
+ *
6
+ * ⚠ ЭКСПОРТИРУЕТСЯ РАДИ ОДНОГО СТОРОЖА, И СТОРОЖ ЭТОГО СТОИТ. Отказ на ключ в
7
+ * аргументе — единственное место, где утечка либо есть, либо её нет; проверять
8
+ * его по копии разбора в `installer-args.test.ts` бесполезно: сними здесь
9
+ * вызов `keyRefusal` — и копия останется зелёной, а ключ снова уедет в историю
10
+ * оболочки (проверено мутацией). Импорт модуля при этом ничего не поднимает:
11
+ * `main()` зовётся только при прямом запуске (`launchedDirectly`).
12
+ */
13
+ declare function installer(args: string[]): Promise<boolean>;
14
+ /**
15
+ * Поднять сервер MCP.
16
+ *
17
+ * ⚠ ЭТО ЭКСПОРТ, И ЭКСПОРТ ОБЯЗАТЕЛЬНЫЙ. Так пусковой файл из `.mcpb` зовёт
18
+ * ТЕЛО, скачанное с раздачи (`launcher.ts`): он импортирует этот модуль и
19
+ * вызывает `start`. Запускайся тело само при импорте, его собственный
20
+ * `catch → process.exit(1)` убил бы процесс мимо перехвата пускового файла, и
21
+ * обещанный откат на встроенную версию остался бы обещанием. Имя `start` —
22
+ * часть договора, за номером которого следит `LAUNCHER_PROTOCOL`.
23
+ */
24
+ declare function start(): Promise<void>;
25
+
26
+ export { installer, start };
package/dist/cli.js CHANGED
@@ -1,17 +1,431 @@
1
1
  #!/usr/bin/env node
2
- import { NaparnikConfigError, loadConfig, NaparnikApiClient, McpServer, createNaparnikTools, StdioServerTransport } from './chunk-T6UWKM37.js';
2
+ import { Engine, chooseBody, handOverToBody, VERSION, rollback, rollbackShell, remove, fromNpxCache, install, keyFromBlock, readConfig, ForeignBlockError, currentMachineFingerprint, McpServer, buildAll, buildResources, StdioServerTransport, fromHost, WHERE_TO_GET_KEY, updateEngine, installStep, NaparnikApiClient, timeToCheck2, manifestUrlFor, fetchManifest, markChecked2, decide, shellDir, timeToCheck, bundleUrlFor, fetchShellManifest, markChecked, decideShell, installedShell, NaparnikConfigError } from './chunk-MBUPRPJQ.js';
3
+ import { fileURLToPath } from 'url';
4
+ import { realpathSync, readFileSync } from 'fs';
3
5
 
4
- // src/cli.ts
6
+ // src/api-client.ts
7
+ function apiClientFor(state, machine = currentMachineFingerprint, engineVersion = () => null) {
8
+ return state.ok ? new NaparnikApiClient(state.config, machine, engineVersion) : notConfiguredClient(state.message);
9
+ }
10
+ function notConfiguredClient(reason) {
11
+ const stub = {
12
+ postMontage: async () => {
13
+ throw new NaparnikConfigError(
14
+ `${reason} \u0412\u043F\u0438\u0448\u0438\u0442\u0435 \u043A\u043B\u044E\u0447 \u0432 \u0441\u0435\u043A\u0446\u0438\u044E env \u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 MCP-\u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0438 \u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u0442\u0438\u0442\u0435 Claude \u2014 \u043F\u043E\u0441\u043B\u0435 \u044D\u0442\u043E\u0433\u043E \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u044B \u0437\u0430\u0440\u0430\u0431\u043E\u0442\u0430\u044E\u0442.`
15
+ );
16
+ }
17
+ };
18
+ return stub;
19
+ }
20
+
21
+ // src/instructions.ts
22
+ var WHAT_IS_IT = `
23
+ \u041D\u0430\u043F\u0430\u0440\u043D\u0438\u043A \u043C\u043E\u043D\u0442\u0438\u0440\u0443\u0435\u0442 \u0432\u0438\u0434\u0435\u043E \u043D\u0430 \u043A\u043E\u043C\u043F\u044C\u044E\u0442\u0435\u0440\u0435 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430. \u041D\u0438 \u0432\u0438\u0434\u0435\u043E, \u043D\u0438 \u0437\u0432\u0443\u043A, \u043D\u0438 \u0440\u0435\u0447\u044C
24
+ \u043D\u0438\u043A\u0443\u0434\u0430 \u043D\u0435 \u0443\u0435\u0437\u0436\u0430\u044E\u0442 \u2014 \u043D\u0430\u0432\u0435\u0440\u0445 \u0443\u0445\u043E\u0434\u0438\u0442 \u0442\u043E\u043B\u044C\u043A\u043E \u043A\u043B\u044E\u0447 \u043F\u043E\u0434\u043F\u0438\u0441\u043A\u0438.
25
+ `.trim();
26
+ var HOW_MONTAGE_WORKS = `
27
+ \u041A\u0410\u041A \u041C\u041E\u041D\u0422\u0418\u0420\u041E\u0412\u0410\u0422\u042C
28
+
29
+ 1. setup \u043F\u0435\u0440\u0432\u044B\u043C, \u0434\u043E \u0432\u0438\u0434\u0435\u043E: \u0447\u0442\u043E \u0441\u0442\u043E\u0438\u0442, \u0447\u0442\u043E \u0443\u043C\u0435\u0435\u0442, \u0447\u0435\u0439 \u0441\u0442\u0438\u043B\u044C \u0438
30
+ \u043F\u043E\u0440\u044F\u0434\u043E\u043A. \u0418\u0437 \u043F\u0430\u043C\u044F\u0442\u0438 \u043D\u0435 \u0440\u0430\u0441\u0441\u043A\u0430\u0437\u044B\u0432\u0430\u0439.
31
+ 2. plan \u0431\u0435\u0437 \u0430\u0440\u0433\u0443\u043C\u0435\u043D\u0442\u043E\u0432 \u2014 \u0447\u0442\u043E \u0443 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0430 \u0441\u043D\u044F\u0442\u043E; plan \u0441 video \u2014 \u0427\u0415\u0420\u041D\u041E\u0412\u0418\u041A
32
+ \u0421\u041B\u041E\u0412\u0410\u041C\u0418, \u0434\u043E \u0441\u0431\u043E\u0440\u043A\u0438. \u041D\u0430\u0437\u043E\u0432\u0451\u0442 \u0444\u0430\u0439\u043B\u044B \u0441\u043A\u0438\u043B\u043B\u043E\u0432 \u2014 \u043F\u0440\u043E\u0447\u0442\u0438 \u0438\u0445 plan \u0441 read.
33
+ 3. \u041F\u0435\u0440\u0435\u0441\u043A\u0430\u0436\u0438 \u0447\u0435\u0440\u043D\u043E\u0432\u0438\u043A \u041F\u041E\u0421\u0422\u0420\u041E\u0427\u041D\u041E \u0438 \u043E\u0431\u0441\u0443\u0434\u0438. \u041F\u0440\u0430\u0432\u043A\u0438 \u2014 plan_edit. \u041F\u043E\u043A\u0430 \u043D\u0435 \u0441\u043A\u0430\u0437\u0430\u043B
34
+ \xAB\u0434\u0430\xBB, \u043D\u0435 \u0441\u043E\u0431\u0438\u0440\u0430\u0439; \u0441\u043A\u0430\u0437\u0430\u043B \u2014 plan_edit \u0441 confirm.
35
+ \u0423\u0437\u043A\u0430\u044F \u043F\u0440\u043E\u0441\u044C\u0431\u0430 (\xAB\u043F\u0440\u043E\u0441\u0442\u043E \u0443\u0441\u043A\u043E\u0440\u044C\xBB) \u2014 \u043F\u043B\u0430\u043D \u043F\u0443\u0441\u0442\u043E\u0439, \u043B\u0438\u0448\u043D\u0435\u0433\u043E \u043D\u0435 \u0431\u0443\u0434\u0435\u0442.
36
+ 4. \u0421\u0442\u0438\u043B\u044C \u0432\u0441\u0442\u0440\u043E\u0435\u043D\u043D\u044B\u0439 \u2014 \u0441\u043F\u0440\u043E\u0441\u0438 \u041E\u0414\u0418\u041D \u0440\u0430\u0437, \u0432\u0430\u0440\u0438\u0430\u043D\u0442\u0430\u043C\u0438 \u043F\u043E \u0440\u0430\u0437\u0434\u0435\u043B\u0430\u043C \u043A\u0430\u0442\u0430\u043B\u043E\u0433\u0430
37
+ (\u0441\u0443\u0431\u0442\u0438\u0442\u0440\u044B, \u0446\u0432\u0435\u0442, \u043F\u0430\u0443\u0437\u044B, \u0441\u0432\u043E\u0439 \u0441\u0442\u0438\u043B\u044C): AskUserQuestion, \u0431\u0435\u0437 \u043D\u0435\u0433\u043E \u2014 \u0441\u043B\u043E\u0432\u0430\u043C\u0438 \u0441
38
+ \u043D\u043E\u043C\u0435\u0440\u0430\u043C\u0438. \u0412\u044B\u0431\u0440\u0430\u043D\u043D\u043E\u0435 \u2014 choose_variant(questions=[\u0440\u0430\u0437\u0434\u0435\u043B\u044B]), \xAB\u0413\u043E\u0442\u043E\u0432\u043E\xBB
39
+ \u0437\u0430\u043F\u0438\u0448\u0435\u0442. \u041D\u0438\u0447\u0435\u0433\u043E \u043D\u0435 \u0432\u044B\u0431\u0440\u0430\u043B \u2014 variant_chosen \u0441 keep=true.
40
+ \u0421\u0442\u0438\u043B\u044C \u0443\u0436\u0435 \u0441\u0432\u043E\u0439 \u2014 \u043D\u0435 \u0441\u043F\u0440\u0430\u0448\u0438\u0432\u0430\u0439.
41
+ 5. \u0414\u0430\u043B\u044C\u0448\u0435 render: \u0432\u0435\u0440\u043D\u0451\u0442 \u041D\u041E\u041C\u0415\u0420 \u0417\u0410\u0414\u0410\u0427\u0418, \u0436\u0434\u0451\u0442 \u0435\u0433\u043E wait. \u041F\u0435\u0440\u0435\u0441\u043A\u0430\u0437\u044B\u0432\u0430\u0439 \u0448\u0430\u0433\u0438,
42
+ \u043C\u043E\u043B\u0447\u0430\u043D\u0438\u0435 \u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044F \xAB\u0437\u0430\u0432\u0438\u0441\u043B\u043E\xBB; \u0447\u0435\u043A-\u043B\u0438\u0441\u0442 (TaskUpdate) \u2014 \u0432\u0435\u0434\u0438 \u0432 \u043D\u0451\u043C. \u0413\u043E\u0442\u043E\u0432\u043E \u2014
43
+ preview.
44
+ 6. \xAB\u0425\u043E\u0447\u0443 \u0438\u043D\u0430\u0447\u0435\xBB: \u0441\u0442\u0438\u043B\u044C \u0438 \u0432\u0430\u0440\u0438\u0430\u043D\u0442 \u2014 choose_variant; \u043D\u0435\u0441\u043A\u043E\u043B\u044C\u043A\u043E \u0438\u0441\u0445\u043E\u0434\u043D\u0438\u043A\u043E\u0432,
45
+ split-screen, PiP, \u0442\u043E\u0447\u043D\u044B\u0435 in/out \u2014 \u0441\u043A\u0438\u043B\u043B composer (plan \u0441 read), project \u2014
46
+ plan_edit, \u0441\u0431\u043E\u0440\u043A\u0430 \u2014 render \u0441 reel; \u0441\u0432\u043E\u0451 \u2014 \u0441\u0432\u043E\u0439 \u0448\u0430\u0433 \u0432 mine/steps (\u043F\u0430\u043F\u043A\u0443
47
+ \u0432\u0435\u0440\u0441\u0438\u0438 \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0435 \u0437\u0430\u043C\u0435\u043D\u044F\u0435\u0442), \u0434\u0430\u043B\u044C\u0448\u0435 plan_edit \u0441\u043E step; \u043A\u0430\u043A \u2014 \u0432 \u0441\u043A\u0438\u043B\u043B\u0435 builder.
48
+ \u0422\u043E\u043B\u044C\u043A\u043E \u043F\u0430\u0443\u0437\u044B \u2014 render \u0441 only_pauses.
49
+ 7. \u0422\u044F\u0436\u0451\u043B\u043E\u0435 (\u0432\u044B\u0440\u0435\u0437 \u0433\u0435\u0440\u043E\u044F, \u0447\u0438\u0441\u0442\u043A\u0430 \u0433\u043E\u043B\u043E\u0441\u0430, \u0440\u0430\u0441\u043F\u043E\u0437\u043D\u0430\u0432\u0430\u043D\u0438\u0435 \u0440\u0435\u0447\u0438 \u2014 1,5 \u0413\u0411) \u2014 \u041F\u041E
50
+ \u041F\u0420\u041E\u0421\u042C\u0411\u0415: \u043D\u0430\u0437\u043E\u0432\u0438 \u0432\u0435\u0441, \u043F\u043E\u0441\u043B\u0435 \xAB\u0434\u0430\xBB setup \u0441 consent=true. \u0422\u0430\u043A \u0436\u0435 \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u044F,
51
+ \u0432 \u0441\u0438\u043B\u0435 \u043F\u043E\u0441\u043B\u0435 \u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u043A\u0430.
52
+
53
+ \u0421\u043A\u0438\u043B\u043B\u044B (\u0432\u0438\u0437\u0443\u0430\u043B, \u0434\u0432\u0438\u0436\u0435\u043D\u0438\u0435, \u0432\u043A\u0443\u0441) \u0447\u0438\u0442\u0430\u0435\u0442 plan \u0441 read \u0438 \u0411\u0415\u0417 \u0440\u043E\u043B\u0438\u043A\u0430: \u0433\u043E\u0434\u044F\u0442\u0441\u044F \u0438
54
+ \u0434\u043B\u044F \u043F\u0440\u0435\u0437\u0435\u043D\u0442\u0430\u0446\u0438\u0438. \u041F\u0435\u0440\u0435\u0447\u0435\u043D\u044C \u0432 setup.
55
+
56
+ \u041D\u0435 \u0432\u044B\u0434\u0443\u043C\u044B\u0432\u0430\u0439, \u0447\u0442\u043E \u0443\u043C\u0435\u0435\u0442 \u043C\u043E\u043D\u0442\u0430\u0436, \u0432\u0440\u0435\u043C\u044F \u043D\u0430\u0437\u044B\u0432\u0430\u0439 \u0442\u043E\u043B\u044C\u043A\u043E \u043E\u0442 \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u0430.
57
+ \u041A\u0430\u043A \u0443\u0441\u0442\u0440\u043E\u0435\u043D\u043E \u0432\u043D\u0443\u0442\u0440\u0438, \u043D\u0435 \u0440\u0430\u0441\u0441\u043A\u0430\u0437\u044B\u0432\u0430\u0439. \u041B\u0435\u043D\u0442\u0430 \u0438 \u043F\u043E\u043C\u043E\u0449\u043D\u0438\u043A\u0438 \u0443\u0431\u0440\u0430\u043D\u044B.
58
+ `.trim();
59
+ function notConfiguredInstructions(problem, detail) {
60
+ const diagnosis = problem === "missing_key" ? "\u041A\u043B\u044E\u0447 \u0434\u043E\u0441\u0442\u0443\u043F\u0430 \u043D\u0435 \u0437\u0430\u0434\u0430\u043D." : `\u041A\u043B\u044E\u0447 \u0437\u0430\u0434\u0430\u043D, \u043D\u043E \u0432\u044B\u0433\u043B\u044F\u0434\u0438\u0442 \u043D\u0435\u043F\u0440\u0430\u0432\u0438\u043B\u044C\u043D\u043E. ${detail}`;
61
+ const hint = problem === "malformed_key" ? "\u0427\u0430\u0441\u0442\u044B\u0435 \u043F\u0440\u0438\u0447\u0438\u043D\u044B: \u0441\u043A\u043E\u043F\u0438\u0440\u043E\u0432\u0430\u043D\u0430 \u0447\u0430\u0441\u0442\u044C \u043A\u043B\u044E\u0447\u0430, \u043F\u043E\u043F\u0430\u043B\u0438 \u043A\u0430\u0432\u044B\u0447\u043A\u0438 \u0438\u043B\u0438 \u043F\u0440\u043E\u0431\u0435\u043B\u044B." : "";
62
+ return `
63
+ ${WHAT_IS_IT}
64
+
65
+ \u26A0\uFE0F \u0418\u041D\u0422\u0415\u0413\u0420\u0410\u0426\u0418\u042F \u041D\u0415 \u041D\u0410\u0421\u0422\u0420\u041E\u0415\u041D\u0410. ${diagnosis}
66
+
67
+ \u0411\u0435\u0437 \u043A\u043B\u044E\u0447\u0430 \u0440\u0430\u0431\u043E\u0442\u0430\u044E\u0442 setup (\u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0430), plan \u0431\u0435\u0437 \u0432\u0438\u0434\u0435\u043E, wait, preview \u0438
68
+ choose_variant: \u043E\u043D\u0438 \u0441\u0447\u0438\u0442\u0430\u044E\u0442 \u043D\u0430 \u0435\u0433\u043E \u043C\u0430\u0448\u0438\u043D\u0435. render \u0438 plan \u0441 \u0432\u0438\u0434\u0435\u043E \u043D\u0435 \u0437\u0430\u043F\u0443\u0441\u0442\u044F\u0442\u0441\u044F \u2014
69
+ \u043F\u043E \u043A\u043B\u044E\u0447\u0443 \u043F\u0440\u043E\u0432\u0435\u0440\u044F\u0435\u0442\u0441\u044F \u043F\u043E\u0434\u043F\u0438\u0441\u043A\u0430, \u2014 \u0438 \u0434\u0432\u0438\u0436\u043E\u043A \u043D\u0435 \u0441\u043A\u0430\u0447\u0430\u0435\u0442\u0441\u044F: \u0440\u0430\u0437\u0434\u0430\u0447\u0430 \u0437\u0430\u043A\u0440\u044B\u0442\u0430. \u041D\u0435
70
+ \u0433\u043E\u0432\u043E\u0440\u0438 \xAB\u043D\u0438\u0447\u0435\u0433\u043E \u043D\u0435 \u0440\u0430\u0431\u043E\u0442\u0430\u0435\u0442\xBB: \u043E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u0435 \u043F\u0440\u043E\u0432\u0435\u0440\u0438\u0442\u044C \u043C\u043E\u0436\u043D\u043E, \u0434\u043B\u044F \u043C\u043E\u043D\u0442\u0430\u0436\u0430 \u043D\u0443\u0436\u0435\u043D \u043A\u043B\u044E\u0447.
71
+
72
+ \u041A\u0410\u041A \u041F\u041E\u041B\u0423\u0427\u0418\u0422\u042C \u041A\u041B\u042E\u0427. ${WHERE_TO_GET_KEY} \u041E\u043F\u043B\u0430\u0442\u0438\u0432\u0448\u0435\u043C\u0443 \u0431\u043E\u0442 \u043F\u0440\u0438\u0448\u043B\u0451\u0442 \u0444\u0430\u0439\u043B \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F
73
+ \u0441 \u0443\u0436\u0435 \u0432\u0448\u0438\u0442\u044B\u043C \u043A\u043B\u044E\u0447\u043E\u043C \u2014 \u0435\u0433\u043E \u0434\u043E\u0441\u0442\u0430\u0442\u043E\u0447\u043D\u043E \u043E\u0442\u043A\u0440\u044B\u0442\u044C. \u0421\u0442\u0430\u0432\u0438\u043B\u0438 \u0447\u0435\u0440\u0435\u0437 npx \u0438\u043B\u0438 Codex \u2014
74
+ \u043F\u0440\u0438\u0448\u043B\u0451\u0442 \u0433\u043E\u0442\u043E\u0432\u0443\u044E \u0441\u0442\u0440\u043E\u043A\u0443.
75
+
76
+ \u041A\u043B\u044E\u0447 \u0432\u044B\u0433\u043B\u044F\u0434\u0438\u0442 \u0442\u0430\u043A: npk_ \u0438 \u0434\u0430\u043B\u044C\u0448\u0435 64 \u0441\u0438\u043C\u0432\u043E\u043B\u0430 \u0438\u0437 \u0446\u0438\u0444\u0440 \u0438 \u043B\u0430\u0442\u0438\u043D\u0441\u043A\u0438\u0445 \u0431\u0443\u043A\u0432 a-f.
77
+ \u0412\u0440\u0443\u0447\u043D\u0443\u044E \u0435\u0433\u043E \u0432\u043F\u0438\u0441\u044B\u0432\u0430\u044E\u0442 \u0432 \u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044E \u044D\u0442\u043E\u0433\u043E MCP-\u0441\u0435\u0440\u0432\u0435\u0440\u0430, \u0432 \u0441\u0435\u043A\u0446\u0438\u044E env:
78
+
79
+ { "mcpServers": { "naparnik": { "command": "npx", "args": ["-y", "@naparnik/mcp"],
80
+ "env": { "NAPARNIK_API_KEY": "npk_\u0441\u044E\u0434\u0430_\u043A\u043B\u044E\u0447" } } } }
81
+
82
+ \u041F\u043E\u0441\u043B\u0435 \u044D\u0442\u043E\u0433\u043E \u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u0442\u0438\u0442\u044C \u041A\u043B\u043E\u0434\u0430 \u0438\u043B\u0438 Codex. ${hint}
83
+
84
+ \u26A0\uFE0F \u041A\u041B\u042E\u0427 \u0416\u0418\u0412\u0401\u0422 \u041D\u0410 \u041E\u0414\u041D\u041E\u041C \u041A\u041E\u041C\u041F\u042C\u042E\u0422\u0415\u0420\u0415: \u043D\u043E\u0432\u044B\u0439 \u0432\u044B\u043F\u0443\u0441\u043A \u043E\u0442\u0437\u044B\u0432\u0430\u0435\u0442 \u043F\u0440\u0435\u0436\u043D\u0438\u0439. \xAB\u041F\u0440\u0438\u0448\u043B\u0438\u0442\u0435 \u043C\u043E\u0439
85
+ \u043A\u043B\u044E\u0447\xBB \u043E\u0437\u043D\u0430\u0447\u0430\u0435\u0442 \xAB\u0432\u044B\u0434\u0430\u0439\u0442\u0435 \u043D\u043E\u0432\u044B\u0439, \u0441\u0442\u0430\u0440\u044B\u0439 \u043E\u0442\u043A\u043B\u044E\u0447\u0438\u0442\u0435\xBB \u2014 \u0441\u043A\u0430\u0437\u0430\u0442\u044C \u044D\u0442\u043E \u043D\u0430\u0434\u043E \u0414\u041E, \u0430 \u043D\u0435
86
+ \u043F\u043E\u0441\u043B\u0435. \u0421\u043C\u0435\u043D\u0438\u0442\u044C \u043A\u043E\u043C\u043F\u044C\u044E\u0442\u0435\u0440 \u043C\u043E\u0436\u043D\u043E \u043A\u043D\u043E\u043F\u043A\u043E\u0439 \u0432 \u0431\u043E\u0442\u0435.
87
+ `.trim();
88
+ }
89
+ function configuredInstructions(baseUrl) {
90
+ return `
91
+ ${WHAT_IS_IT}
92
+
93
+ \u041F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D\u043E \u043A: ${baseUrl}
94
+
95
+ ${HOW_MONTAGE_WORKS}
96
+
97
+ \u041C\u043E\u043D\u0442\u0430\u0436 \u041D\u0415 \u0442\u0440\u0430\u0442\u0438\u0442 \u043D\u0438 \u0431\u0430\u043B\u0430\u043D\u0441, \u043D\u0438 \u0442\u043E\u043A\u0435\u043D\u044B.
98
+ `.trim();
99
+ }
100
+ function aboutNewPayload(ownDir, fresh, megabytes) {
101
+ return `
102
+ \u0412\u042B\u0428\u041B\u0410 \u041D\u041E\u0412\u0410\u042F \u0412\u0415\u0420\u0421\u0418\u042F \u0414\u0412\u0418\u0416\u041A\u0410 \u041C\u041E\u041D\u0422\u0410\u0416\u0410
103
+
104
+ ${ownDir === null ? "\u0414\u0432\u0438\u0436\u043E\u043A \u0435\u0449\u0451 \u043D\u0435 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D" : `\u0423\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u0430 ${ownDir}`}, \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u0430 ${fresh} (${megabytes.toFixed(1)} \u041C\u0411).
105
+ \u0421\u0430\u043C\u0430 \u043E\u043D\u0430 \u043D\u0435 \u0441\u043A\u0430\u0447\u0430\u0435\u0442\u0441\u044F. \u041A\u043E\u0433\u0434\u0430 \u0447\u0435\u043B\u043E\u0432\u0435\u043A \u0432 \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0438\u0439 \u0440\u0430\u0437 \u0437\u0430\u0433\u043E\u0432\u043E\u0440\u0438\u0442 \u043E \u043C\u043E\u043D\u0442\u0430\u0436\u0435,
106
+ \u0441\u043A\u0430\u0436\u0438 \u043E\u0431 \u044D\u0442\u043E\u043C \u043E\u0434\u043D\u043E\u0439 \u0444\u0440\u0430\u0437\u043E\u0439 \u0438 \u0441\u043F\u0440\u043E\u0441\u0438, \u043E\u0431\u043D\u043E\u0432\u043B\u044F\u0442\u044C \u043B\u0438; \u0441\u043E\u0433\u043B\u0430\u0441\u0438\u0442\u0441\u044F \u2014 \u0437\u043E\u0432\u0438
107
+ setup \u0441 what=engine \u0438 consent=true. \u041D\u0435 \u043E\u0431\u043D\u043E\u0432\u043B\u044F\u0439 \u043C\u043E\u043B\u0447\u0430 \u0438 \u043D\u0435 \u0431\u0440\u043E\u0441\u0430\u0439 \u0440\u0430\u0434\u0438 \u044D\u0442\u043E\u0433\u043E \u0435\u0433\u043E
108
+ \u0442\u0435\u043A\u0443\u0449\u0443\u044E \u0437\u0430\u0434\u0430\u0447\u0443: \u0441\u0442\u0430\u0440\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u0440\u0430\u0431\u043E\u0442\u0430\u0435\u0442 \u043A\u0430\u043A \u0440\u0430\u0431\u043E\u0442\u0430\u043B\u0430.
109
+ `.trim();
110
+ }
111
+ function aboutNewShell(installed, fresh, notes) {
112
+ return `
113
+ \u0412\u042B\u0428\u041B\u0410 \u041D\u041E\u0412\u0410\u042F \u0412\u0415\u0420\u0421\u0418\u042F \u0421\u0410\u041C\u041E\u0413\u041E \u0420\u0410\u0421\u0428\u0418\u0420\u0415\u041D\u0418\u042F
114
+
115
+ \u0421\u0442\u043E\u0438\u0442 ${installed}, \u0432\u044B\u0448\u043B\u0430 ${fresh}. \u0425\u043E\u0434\u0438\u0442\u044C \u043A \u0431\u043E\u0442\u0443 \u0437\u0430 \u0444\u0430\u0439\u043B\u043E\u043C \u0431\u043E\u043B\u044C\u0448\u0435 \u043D\u0435 \u043D\u0443\u0436\u043D\u043E \u2014
116
+ \u0441\u0442\u0430\u0432\u0438\u0442\u0441\u044F \u043E\u0442\u0441\u044E\u0434\u0430.
117
+ ${notes === null ? "" : `
118
+ \u0427\u0422\u041E \u041D\u041E\u0412\u041E\u0413\u041E (\u043F\u0435\u0440\u0435\u0441\u043A\u0430\u0436\u0438 \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0443 \u0441\u0432\u043E\u0438\u043C\u0438 \u0441\u043B\u043E\u0432\u0430\u043C\u0438, \u043D\u0435 \u0437\u0430\u0447\u0438\u0442\u044B\u0432\u0430\u0439 \u0446\u0435\u043B\u0438\u043A\u043E\u043C):
119
+ ${notes}
120
+ `}
121
+ \u0421\u0430\u043C\u0430 \u043E\u043D\u0430 \u043D\u0435 \u043F\u043E\u0441\u0442\u0430\u0432\u0438\u0442\u0441\u044F. \u041A\u043E\u0433\u0434\u0430 \u0447\u0435\u043B\u043E\u0432\u0435\u043A \u0432 \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0438\u0439 \u0440\u0430\u0437 \u0437\u0430\u0433\u043E\u0432\u043E\u0440\u0438\u0442 \u043E \u043C\u043E\u043D\u0442\u0430\u0436\u0435, \u0441\u043A\u0430\u0436\u0438
122
+ \u043E\u0431 \u044D\u0442\u043E\u043C \u043E\u0434\u043D\u043E\u0439 \u0444\u0440\u0430\u0437\u043E\u0439 \u0438 \u0441\u043F\u0440\u043E\u0441\u0438, \u043E\u0431\u043D\u043E\u0432\u043B\u044F\u0442\u044C \u043B\u0438; \u0441\u043E\u0433\u043B\u0430\u0441\u0438\u0442\u0441\u044F \u2014 \u0437\u043E\u0432\u0438 setup \u0441
123
+ what=shell \u0438 consent=true. \u041D\u0435 \u043E\u0431\u043D\u043E\u0432\u043B\u044F\u0439 \u043C\u043E\u043B\u0447\u0430 \u0438 \u043D\u0435 \u0431\u0440\u043E\u0441\u0430\u0439 \u0440\u0430\u0434\u0438 \u044D\u0442\u043E\u0433\u043E \u0435\u0433\u043E \u0442\u0435\u043A\u0443\u0449\u0443\u044E \u0437\u0430\u0434\u0430\u0447\u0443.
124
+ \u041E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0435 \u0432\u0441\u0442\u0443\u043F\u0438\u0442 \u0432 \u0441\u0438\u043B\u0443 \u043F\u043E\u0441\u043B\u0435 \u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u043A\u0430 \u041A\u043B\u043E\u0434\u0430 \u0438\u043B\u0438 Codex \u2014 \u0441\u043A\u0430\u0436\u0438 \u0438 \u044D\u0442\u043E, \u0438\u043D\u0430\u0447\u0435
125
+ \u0447\u0435\u043B\u043E\u0432\u0435\u043A \u0440\u0435\u0448\u0438\u0442, \u0447\u0442\u043E \u043D\u0438\u0447\u0435\u0433\u043E \u043D\u0435 \u043F\u0440\u043E\u0438\u0437\u043E\u0448\u043B\u043E.
126
+ `.trim();
127
+ }
128
+
129
+ // src/auto-install.ts
130
+ var NO_AUTO = "NAPARNIK_NO_AUTOINSTALL";
131
+ function decideAuto(state) {
132
+ if (state.off || !state.hasKey || state.byHand) return "nothing";
133
+ if (!state.ready) return "install";
134
+ return state.refresh ? "refresh" : "nothing";
135
+ }
136
+ async function prepareEngine(engine, opts) {
137
+ const say = opts.tell ?? (() => {
138
+ });
139
+ const quiet = { worked: false, ok: true, lines: [] };
140
+ const off = engine.variable(NO_AUTO) !== void 0;
141
+ const hasKey = opts.key !== void 0 && opts.key !== "";
142
+ const byHand = engine.pathSetByHand();
143
+ const ready = off || !hasKey || byHand ? false : engine.place() !== null && await engine.pythonTrouble() === null;
144
+ const plan = decideAuto({ off, hasKey, byHand, ready, refresh: opts.refresh === true });
145
+ if (plan === "nothing") return quiet;
146
+ if (plan === "refresh") {
147
+ const fresh = await updateEngine(engine, true, opts.key, opts.baseUrl);
148
+ const news = "error" in fresh ? fresh.error : typeof fresh.content === "string" ? fresh.content : "";
149
+ if (news !== "") say(news);
150
+ return { worked: true, ok: !("error" in fresh), lines: news === "" ? [] : [news] };
151
+ }
152
+ say("\u041A\u0430\u0447\u0430\u044E \u0434\u0432\u0438\u0436\u043E\u043A \u043C\u043E\u043D\u0442\u0430\u0436\u0430 \u2014 \u044D\u0442\u043E \u0440\u0430\u0437\u043E\u0432\u0430\u044F \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0430, \u0434\u0430\u043B\u044C\u0448\u0435 \u043E\u043D \u043E\u0441\u0442\u0430\u0451\u0442\u0441\u044F \u043D\u0430 \u043C\u0430\u0448\u0438\u043D\u0435.");
153
+ const done = await installStep(engine, { step: "all", consent: true }, opts.key, opts.baseUrl, say);
154
+ const text = typeof done === "object" && "error" in done ? done.error : typeof done.content === "string" ? done.content : "";
155
+ if (text !== "") say(text);
156
+ return { worked: true, ok: !("error" in done), lines: text === "" ? [] : [text] };
157
+ }
158
+
159
+ // src/installer-args.ts
160
+ var KEY_ARG = "--key";
161
+ var INSTALLER_ARGS = {
162
+ install: {
163
+ arg: "--install",
164
+ after: " codex",
165
+ what: "\u043F\u0440\u043E\u043F\u0438\u0441\u0430\u0442\u044C \u0441\u0435\u0440\u0432\u0435\u0440 \u0432 ~/.codex/config.toml"
166
+ },
167
+ remove: {
168
+ arg: "--remove",
169
+ after: " codex",
170
+ what: "\u0443\u0431\u0440\u0430\u0442\u044C \u043E\u0442\u0442\u0443\u0434\u0430 \u043D\u0430\u0448 \u0431\u043B\u043E\u043A"
171
+ },
172
+ version: {
173
+ arg: "--version",
174
+ after: "",
175
+ what: "\u0432\u0435\u0440\u0441\u0438\u044F \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F"
176
+ },
177
+ rollback: {
178
+ arg: "--rollback",
179
+ after: "",
180
+ what: "\u0432\u0435\u0440\u043D\u0443\u0442\u044C \u0434\u0432\u0438\u0436\u043E\u043A \u043C\u043E\u043D\u0442\u0430\u0436\u0430 \u043D\u0430 \u043F\u0440\u043E\u0448\u043B\u0443\u044E \u0432\u0435\u0440\u0441\u0438\u044E"
181
+ },
182
+ /**
183
+ * ⚠ ЭТО ЕДИНСТВЕННЫЙ ВЫХОД ИЗ ОДНОГО ПОЛОЖЕНИЯ, И ПОТОМУ ОН ЗДЕСЬ, А НЕ ТОЛЬКО
184
+ * ИНСТРУМЕНТОМ. Тело оболочки, которое прошло дымовой прогон (`--version`
185
+ * печатается до `start()`), но падает уже внутри `start()`, оставляет человека
186
+ * без MCP-сессии вовсе — а значит и без инструмента `shell_rollback`. Этот
187
+ * флаг отрабатывает в ПУСКОВОМ файле, до передачи управления телу, то есть
188
+ * работает и тогда, когда тело не поднимается.
189
+ */
190
+ shellRollback: {
191
+ arg: "--shell-rollback",
192
+ after: "",
193
+ what: "\u0432\u0435\u0440\u043D\u0443\u0442\u044C \u0441\u0430\u043C\u043E \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u0435 \u043D\u0430 \u043F\u0440\u043E\u0448\u043B\u0443\u044E \u0432\u0435\u0440\u0441\u0438\u044E"
194
+ }
195
+ };
196
+ function askedFor(args) {
197
+ const order = ["version", "shellRollback", "rollback", "install", "remove"];
198
+ for (const ask of order) {
199
+ if (args.includes(INSTALLER_ARGS[ask].arg)) return ask;
200
+ }
201
+ return null;
202
+ }
203
+ function keyRefusal(args) {
204
+ if (!args.includes(KEY_ARG)) return null;
205
+ return `\u041A\u043B\u044E\u0447 \u0430\u0440\u0433\u0443\u043C\u0435\u043D\u0442\u043E\u043C ${KEY_ARG} \u043D\u0435 \u043F\u0440\u0438\u043D\u0438\u043C\u0430\u0435\u0442\u0441\u044F: \u043E\u043D \u0432\u0438\u0434\u0435\u043D \u0432 \u0438\u0441\u0442\u043E\u0440\u0438\u0438 \u043E\u0431\u043E\u043B\u043E\u0447\u043A\u0438 \u0438 \u0432
206
+ \u0441\u043F\u0438\u0441\u043A\u0435 \u043F\u0440\u043E\u0446\u0435\u0441\u0441\u043E\u0432, \u0430 \u043D\u0430 \u0437\u0430\u043F\u0438\u0441\u0438 \u044D\u043A\u0440\u0430\u043D\u0430 \u2014 \u0446\u0435\u043B\u0438\u043A\u043E\u043C.
207
+ \u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C: \u0437\u0430\u0434\u0430\u0439 \u043A\u043B\u044E\u0447 \u043F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u043E\u0439 \u0441\u0440\u0435\u0434\u044B NAPARNIK_API_KEY \u2014 \u0438\u043B\u0438 \u043F\u043E\u0432\u0442\u043E\u0440\u0438
208
+ \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0443 \u0431\u0435\u0437 \u044D\u0442\u043E\u0433\u043E \u0430\u0440\u0433\u0443\u043C\u0435\u043D\u0442\u0430 \u0438 \u043E\u0442\u0432\u0435\u0442\u044C \u043D\u0430 \u0432\u043E\u043F\u0440\u043E\u0441 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u0449\u0438\u043A\u0430: \u0432\u0432\u043E\u0434 \u043D\u0435
209
+ \u043F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0435\u0442\u0441\u044F.
210
+ `;
211
+ }
212
+ async function keyForInstall(env, ask) {
213
+ const given = fromHost(env["NAPARNIK_API_KEY"]);
214
+ return given !== "" ? given : await ask();
215
+ }
216
+ function helpText() {
217
+ const width = Math.max(
218
+ ...Object.values(INSTALLER_ARGS).map((one) => `${one.arg}${one.after}`.length)
219
+ );
220
+ const lines = Object.values(INSTALLER_ARGS).map((one) => {
221
+ const left = `${one.arg}${one.after}`;
222
+ return ` ${left.padEnd(width)} ${one.what}`;
223
+ });
224
+ return `\u041D\u0435 \u043F\u043E\u043D\u044F\u043B \u0430\u0440\u0433\u0443\u043C\u0435\u043D\u0442\u044B. \u0423\u043C\u0435\u044E:
225
+ ${lines.join("\n")}
226
+ \u0411\u0435\u0437 \u0430\u0440\u0433\u0443\u043C\u0435\u043D\u0442\u043E\u0432 \u2014 \u044D\u0442\u043E MCP-\u0441\u0435\u0440\u0432\u0435\u0440, \u0435\u0433\u043E \u0437\u0430\u043F\u0443\u0441\u043A\u0430\u0435\u0442 \u043F\u0440\u043E\u0433\u0440\u0430\u043C\u043C\u0430, \u0430 \u043D\u0435 \u0447\u0435\u043B\u043E\u0432\u0435\u043A.
227
+ `;
228
+ }
5
229
  function log(message) {
6
230
  process.stderr.write(`[naparnik-mcp] ${message}
7
231
  `);
8
232
  }
9
- async function main() {
10
- const config = loadConfig();
11
- const client = new NaparnikApiClient(config);
12
- const server = new McpServer();
13
- const tools = createNaparnikTools(client);
233
+ function theFile() {
234
+ return fileURLToPath(import.meta.url);
235
+ }
236
+ async function askKey() {
237
+ if (process.stdin.isTTY !== true) return void 0;
238
+ const { createInterface } = await import('readline/promises');
239
+ const lines = createInterface({ input: process.stdin, output: process.stdout, terminal: true });
240
+ lines._writeToOutput = () => {
241
+ };
242
+ try {
243
+ process.stdout.write(
244
+ // ⚠ ЗДЕСЬ ОБЕЩАЛИСЬ ЛЕНТА РИЛСОВ, РАСПАКОВКА БРЕНДА И ГЕНЕРАЦИЯ. Этих
245
+ // инструментов нет с 2026-09-02: полка данных убрана вместе с гашением
246
+ // монолита. Человек вводил ключ за то, чего в расширении не будет.
247
+ `${WHERE_TO_GET_KEY}
248
+ \u041F\u043E \u043D\u0435\u043C\u0443 \u043F\u0440\u043E\u0432\u0435\u0440\u044F\u0435\u0442\u0441\u044F \u043F\u043E\u0434\u043F\u0438\u0441\u043A\u0430 \u0438 \u043A\u0430\u0447\u0430\u0435\u0442\u0441\u044F \u0434\u0432\u0438\u0436\u043E\u043A \u043C\u043E\u043D\u0442\u0430\u0436\u0430. \u0411\u0435\u0437 \u043A\u043B\u044E\u0447\u0430
249
+ \u043F\u043E\u043B\u0443\u0447\u0438\u0442\u0441\u044F \u0442\u043E\u043B\u044C\u043A\u043E \u043F\u0440\u043E\u0432\u0435\u0440\u0438\u0442\u044C \u043E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u0435 \u0438 \u0437\u0430\u0431\u0440\u0430\u0442\u044C \u0443\u0436\u0435 \u0433\u043E\u0442\u043E\u0432\u043E\u0435.
250
+ \u041A\u043B\u044E\u0447: `
251
+ );
252
+ const response = (await lines.question("")).trim();
253
+ process.stdout.write("\n");
254
+ return response === "" ? void 0 : response;
255
+ } finally {
256
+ lines.close();
257
+ }
258
+ }
259
+ async function installer(args) {
260
+ if (args.length === 0) return false;
261
+ const leak = keyRefusal(args);
262
+ if (leak !== null) {
263
+ process.stderr.write(leak);
264
+ process.exitCode = 2;
265
+ return true;
266
+ }
267
+ const ask = askedFor(args);
268
+ if (ask === "version") {
269
+ process.stdout.write(`${VERSION}
270
+ `);
271
+ return true;
272
+ }
273
+ if (ask === "rollback") {
274
+ const result = rollback(new Engine());
275
+ process.stdout.write(`${result.text}
276
+ `);
277
+ if (!result.ok) process.exitCode = 1;
278
+ return true;
279
+ }
280
+ if (ask === "shellRollback") {
281
+ const result = rollbackShell(new Engine().home());
282
+ process.stdout.write(`${result.text}
283
+ `);
284
+ if (!result.ok) process.exitCode = 1;
285
+ return true;
286
+ }
287
+ const where = args.indexOf(INSTALLER_ARGS.install.arg);
288
+ const strip = args.indexOf(INSTALLER_ARGS.remove.arg);
289
+ const target = where !== -1 ? args[where + 1] : strip !== -1 ? args[strip + 1] : void 0;
290
+ if (ask === null) {
291
+ process.stderr.write(helpText());
292
+ process.exitCode = 2;
293
+ return true;
294
+ }
295
+ if (target !== "codex") {
296
+ process.stderr.write(
297
+ `\u0423\u043C\u0435\u044E \u0441\u0442\u0430\u0432\u0438\u0442\u044C \u0442\u043E\u043B\u044C\u043A\u043E \u0432 codex, \u0430 \u043F\u0440\u043E\u0441\u044F\u0442 \xAB${target ?? ""}\xBB.
298
+ Claude Desktop \u0441\u0442\u0430\u0432\u0438\u0442\u0441\u044F \u043F\u0435\u0440\u0435\u0442\u0430\u0441\u043A\u0438\u0432\u0430\u043D\u0438\u0435\u043C \u0444\u0430\u0439\u043B\u0430 .mcpb, Claude Code \u2014 \u043A\u043E\u043C\u0430\u043D\u0434\u043E\u0439
299
+ \`claude mcp add\`. \u0420\u0443\u043A\u0430\u043C\u0438 \u043A\u043E\u043D\u0444\u0438\u0433 \u0442\u0430\u043C \u043F\u0440\u0430\u0432\u0438\u0442\u044C \u043D\u0435 \u043D\u0443\u0436\u043D\u043E.
300
+ `
301
+ );
302
+ process.exitCode = 2;
303
+ return true;
304
+ }
305
+ try {
306
+ if (strip !== -1) {
307
+ process.stdout.write(`${remove().words}
308
+ `);
309
+ return true;
310
+ }
311
+ const file = theFile();
312
+ if (fromNpxCache(file)) {
313
+ process.stderr.write(
314
+ `\u0417\u0430\u043F\u0443\u0449\u0435\u043D\u043E \u0447\u0435\u0440\u0435\u0437 npx \u2014 \u043F\u0440\u043E\u043F\u0438\u0441\u044B\u0432\u0430\u0442\u044C \u0432 \u043A\u043E\u043D\u0444\u0438\u0433 \u043D\u0435\u0447\u0435\u0433\u043E.
315
+ \u042D\u0442\u043E\u0442 \u0444\u0430\u0439\u043B \u043B\u0435\u0436\u0438\u0442 \u0432\u043E \u0432\u0440\u0435\u043C\u0435\u043D\u043D\u043E\u043C \u043A\u044D\u0448\u0435 npx (${file}), \u043A\u043E\u0442\u043E\u0440\u044B\u0439 \u0441\u043D\u043E\u0441\u044F\u0442 \u0447\u0438\u0441\u0442\u043A\u0430 npm,
316
+ \u0443\u0431\u043E\u0440\u0449\u0438\u043A\u0438 \u0434\u0438\u0441\u043A\u0430 \u0438 \u043A\u043E\u0440\u043F\u043E\u0440\u0430\u0442\u0438\u0432\u043D\u044B\u0435 \u043F\u043E\u043B\u0438\u0442\u0438\u043A\u0438. Codex \u043F\u043E\u0441\u043B\u0435 \u044D\u0442\u043E\u0433\u043E \u0431\u0443\u0434\u0435\u0442 \u0432\u0435\u0447\u043D\u043E
317
+ \u0441\u043E\u043E\u0431\u0449\u0430\u0442\u044C, \u0447\u0442\u043E \u0441\u0435\u0440\u0432\u0435\u0440 \u043D\u0435 \u0437\u0430\u043F\u0443\u0441\u0442\u0438\u043B\u0441\u044F.
318
+
319
+ \u0427\u0442\u043E \u0434\u0435\u043B\u0430\u0442\u044C: \u043F\u043E\u0441\u0442\u0430\u0432\u044C\u0442\u0435 \u043F\u0430\u043A\u0435\u0442 \u043F\u043E\u0441\u0442\u043E\u044F\u043D\u043D\u043E \u0438 \u043F\u043E\u0432\u0442\u043E\u0440\u0438\u0442\u0435
320
+ npm i -g @naparnik/mcp
321
+ naparnik-mcp --install codex
322
+ `
323
+ );
324
+ process.exitCode = 2;
325
+ return true;
326
+ }
327
+ const key = await keyForInstall(process.env, askKey);
328
+ const result = install({ entryFile: file, ...key !== void 0 ? { key } : {} });
329
+ process.stdout.write(`${result.words}
330
+ `);
331
+ const forEngine = key ?? keyFromBlock(readFileSync(result.file, "utf8"));
332
+ const engine = new Engine();
333
+ const outcome = await prepareEngine(engine, {
334
+ key: forEngine,
335
+ baseUrl: serverAddress(readConfig()),
336
+ tell: (line) => process.stdout.write(`${line}
337
+ `),
338
+ // Установка руками — значит человек пришёл за новым: если движок стоит,
339
+ // но вышла свежая начинка, тянем и её. Молчаливое «у тебя всё есть» —
340
+ // это то, из-за чего покупатель остаётся на прошлой версии.
341
+ refresh: true
342
+ });
343
+ if (outcome.worked && !outcome.ok) {
344
+ process.stdout.write(
345
+ "\u0414\u0432\u0438\u0436\u043E\u043A \u0441\u043A\u0430\u0447\u0430\u0442\u044C \u0441\u0435\u0439\u0447\u0430\u0441 \u043D\u0435 \u0432\u044B\u0448\u043B\u043E. \u041F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u0442\u0438\u0442\u0435 Codex \u0438 \u0441\u043A\u0430\u0436\u0438\u0442\u0435\n\xAB\u043F\u0440\u043E\u0432\u0435\u0440\u044C, \u0432\u0441\u0451 \u043B\u0438 \u0433\u043E\u0442\u043E\u0432\u043E \u0434\u043B\u044F \u043C\u043E\u043D\u0442\u0430\u0436\u0430\xBB \u2014 \u0434\u043E\u043A\u0430\u0447\u0430\u044E \u043E\u0442\u0442\u0443\u0434\u0430.\n"
346
+ );
347
+ }
348
+ } catch (trouble) {
349
+ process.stderr.write(`${trouble instanceof ForeignBlockError ? trouble.message : String(trouble)}
350
+ `);
351
+ process.exitCode = 1;
352
+ }
353
+ return true;
354
+ }
355
+ function serverAddress(state) {
356
+ return state.ok ? state.config.baseUrl : state.baseUrl;
357
+ }
358
+ async function newPayload(engine, baseUrl, key) {
359
+ if (engine.variable("NAPARNIK_NO_UPDATE") !== void 0) return null;
360
+ if (engine.place() === null) return null;
361
+ if (engine.pathSetByHand()) return null;
362
+ if (!timeToCheck2(engine)) return null;
363
+ try {
364
+ const url = engine.variable("NAPARNIK_UPDATE_MANIFEST") ?? manifestUrlFor(baseUrl);
365
+ const outcome = await fetchManifest(url, void 0, key);
366
+ markChecked2(engine);
367
+ const decision = decide(engine.freshVersion(), outcome.ok ? outcome.manifest : null);
368
+ if (decision.what !== "newer_available") return null;
369
+ return aboutNewPayload(
370
+ engine.freshVersion(),
371
+ decision.manifest.version,
372
+ decision.manifest.bytes / 1024 / 1024
373
+ );
374
+ } catch {
375
+ return null;
376
+ }
377
+ }
378
+ async function newShell(engine, baseUrl, key) {
379
+ if (engine.variable("NAPARNIK_NO_UPDATE") !== void 0) return null;
380
+ const home = engine.home();
381
+ const dir = shellDir(home);
382
+ if (!timeToCheck(dir)) return null;
383
+ try {
384
+ const url = engine.variable("NAPARNIK_BUNDLE_MANIFEST") ?? bundleUrlFor(baseUrl);
385
+ const outcome = await fetchShellManifest(url, void 0, key);
386
+ markChecked(dir);
387
+ const decision = decideShell(installedShell(home), outcome.ok ? outcome.manifest : null);
388
+ if (decision.what !== "newer_available") return null;
389
+ return aboutNewShell(
390
+ installedShell(home),
391
+ decision.manifest.version,
392
+ decision.manifest.notes
393
+ );
394
+ } catch {
395
+ return null;
396
+ }
397
+ }
398
+ async function start() {
399
+ const state = readConfig();
400
+ const engineForVersion = new Engine();
401
+ const client = apiClientFor(state, void 0, () => engineForVersion.currentVersion());
402
+ const basics = state.ok ? configuredInstructions(state.config.baseUrl) : notConfiguredInstructions(state.problem, state.message);
403
+ const engine = new Engine();
404
+ const [passport, aboutUpdate, aboutShell] = await Promise.all([
405
+ engine.passport(),
406
+ newPayload(engine, serverAddress(state), state.ok ? state.config.apiKey : void 0),
407
+ newShell(engine, serverAddress(state), state.ok ? state.config.apiKey : void 0)
408
+ ]);
409
+ const news = [aboutUpdate, aboutShell].filter((one) => one !== null);
410
+ const server = new McpServer(void 0, {
411
+ instructions: news.length === 0 ? basics : `${basics}
412
+
413
+ ${news.join("\n\n")}`,
414
+ // ⚠ ПРЕДСТАВЛЯЕМСЯ СВОИМ ИМЕНЕМ, А НЕ ИМЕНЕМ ЯДРА. В Claude Desktop имя
415
+ // берётся из манифеста расширения и подмена незаметна, а в Codex человек
416
+ // видит ровно это — и читал «@naparnik/super-agent-core 0.1.0» вместо
417
+ // названия расширения, которое сам поставил.
418
+ serverInfo: { name: "@naparnik/mcp", version: VERSION }
419
+ });
420
+ const tools = buildAll(
421
+ client,
422
+ engine,
423
+ passport,
424
+ state.ok ? state.config.apiKey : void 0,
425
+ serverAddress(state)
426
+ );
14
427
  for (const tool of tools) server.addTool(tool);
428
+ for (const r of buildResources()) server.addResource(r.resource, r.contents);
15
429
  const transport = new StdioServerTransport();
16
430
  transport.onClose((error) => {
17
431
  if (error !== void 0) log(`\u0441\u043E\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u0435 \u0437\u0430\u043A\u0440\u044B\u0442\u043E \u0441 \u043E\u0448\u0438\u0431\u043A\u043E\u0439: ${error.message}`);
@@ -19,18 +433,55 @@ async function main() {
19
433
  });
20
434
  await transport.connect();
21
435
  await server.start(transport);
22
- log(`\u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0451\u043D \u043A ${config.baseUrl}, \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u043E\u0432: ${tools.length}`);
436
+ const aboutMontage = engine.place() !== null ? `\u0434\u0432\u0438\u0436\u043E\u043A \u043C\u043E\u043D\u0442\u0430\u0436\u0430 \u043D\u0430\u0439\u0434\u0435\u043D: ${engine.place()?.engine}` : "\u0434\u0432\u0438\u0436\u043E\u043A \u043C\u043E\u043D\u0442\u0430\u0436\u0430 \u043D\u0435 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D \u2014 \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u044B \u043C\u043E\u043D\u0442\u0430\u0436\u0430 \u043E\u0431\u044A\u044F\u0441\u043D\u044F\u0442 \u044D\u0442\u043E \u0441\u043B\u043E\u0432\u0430\u043C\u0438";
437
+ if (state.ok) {
438
+ log(`\u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0451\u043D \u043A ${state.config.baseUrl}, \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u043E\u0432: ${tools.length}; ${aboutMontage}`);
439
+ } else {
440
+ log(
441
+ `${state.message} \u0418\u043D\u0441\u0442\u0440\u0443\u043A\u0446\u0438\u044F \u043F\u043E \u043D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0435 \u043F\u0435\u0440\u0435\u0434\u0430\u043D\u0430 \u043A\u043B\u0438\u0435\u043D\u0442\u0443. \u041C\u043E\u043D\u0442\u0430\u0436 \u0431\u0435\u0437 \u043A\u043B\u044E\u0447\u0430 \u043D\u0435 \u0437\u0430\u043F\u0443\u0441\u0442\u0438\u0442\u0441\u044F, \u043D\u043E \u043E\u043A\u0440\u0443\u0436\u0435\u043D\u0438\u0435 \u043F\u0440\u043E\u0432\u0435\u0440\u0438\u0442\u044C \u043C\u043E\u0436\u043D\u043E: ${aboutMontage}.`
442
+ );
443
+ }
444
+ if (state.ok) {
445
+ void prepareEngine(engine, {
446
+ key: state.config.apiKey,
447
+ baseUrl: state.config.baseUrl,
448
+ tell: log
449
+ }).catch((trouble) => {
450
+ log(`\u0434\u0432\u0438\u0436\u043E\u043A \u0434\u043E\u043A\u0430\u0447\u0430\u0442\u044C \u043D\u0435 \u0432\u044B\u0448\u043B\u043E: ${trouble instanceof Error ? trouble.message : String(trouble)}`);
451
+ });
452
+ }
23
453
  for (const signal of ["SIGINT", "SIGTERM"]) {
24
454
  process.on(signal, () => {
25
455
  void server.stop().finally(() => process.exit(0));
26
456
  });
27
457
  }
28
458
  }
29
- main().catch((err) => {
30
- if (err instanceof NaparnikConfigError) {
31
- log(err.message);
32
- process.exit(1);
459
+ async function run() {
460
+ const args = process.argv.slice(2);
461
+ if (args.length === 0) {
462
+ const engine = new Engine();
463
+ if (engine.variable("NAPARNIK_NO_BODY") === void 0) {
464
+ const choice = chooseBody({ home: engine.home(), ownFile: theFile() });
465
+ if (await handOverToBody(choice, log)) return;
466
+ }
33
467
  }
34
- log(`\u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0437\u0430\u043F\u0443\u0441\u0442\u0438\u0442\u044C\u0441\u044F: ${err instanceof Error ? err.message : String(err)}`);
35
- process.exit(1);
36
- });
468
+ if (await installer(args)) return;
469
+ await start();
470
+ }
471
+ function launchedDirectly() {
472
+ const started = process.argv[1];
473
+ if (started === void 0) return false;
474
+ try {
475
+ return realpathSync(started) === realpathSync(theFile());
476
+ } catch {
477
+ return started === theFile();
478
+ }
479
+ }
480
+ if (launchedDirectly()) {
481
+ run().catch((err) => {
482
+ log(`\u043D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0437\u0430\u043F\u0443\u0441\u0442\u0438\u0442\u044C\u0441\u044F: ${err instanceof Error ? err.message : String(err)}`);
483
+ process.exit(1);
484
+ });
485
+ }
486
+
487
+ export { installer, start };