@naparnik/mcp 0.10.52 → 0.10.54
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 +12 -0
- package/dist/{chunk-CXFF4BPP.js → chunk-USWWD5M5.js} +2681 -2813
- package/dist/cli.d.ts +41 -1
- package/dist/cli.js +258 -95
- package/dist/index.d.ts +32 -397
- package/dist/index.js +1 -1
- package/dist/tool-1kGke9dT.d.ts +374 -0
- package/package.json +1 -1
package/dist/cli.d.ts
CHANGED
|
@@ -1,4 +1,33 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { T as Tool, M as McpResource, a as McpResourceItemContent } from './tool-1kGke9dT.js';
|
|
3
|
+
|
|
4
|
+
/** Номер договора `toolset()` между телами. */
|
|
5
|
+
declare const SWAP_PROTOCOL = 1;
|
|
6
|
+
/** Что самообновление поставило за проход; `null` — ничего. */
|
|
7
|
+
interface UpdatedVersions {
|
|
8
|
+
engine: string | null;
|
|
9
|
+
shell: string | null;
|
|
10
|
+
}
|
|
11
|
+
/** Набор тела: всё, что хозяину нужно от кода оболочки. */
|
|
12
|
+
interface Toolset {
|
|
13
|
+
/** Инструменты — те самые, что уезжают в `tools/list`. */
|
|
14
|
+
tools: Tool[];
|
|
15
|
+
/** Виджеты парой к инструментам. */
|
|
16
|
+
resources: Array<{
|
|
17
|
+
resource: McpResource;
|
|
18
|
+
contents: McpResourceItemContent[];
|
|
19
|
+
}>;
|
|
20
|
+
/** Идёт ли работа, которую нельзя рвать заменой: задача движка или установки. */
|
|
21
|
+
busy(): boolean;
|
|
22
|
+
/** Один проход самообновления (`self-update.ts`): что поставил. */
|
|
23
|
+
selfUpdate(): Promise<UpdatedVersions>;
|
|
24
|
+
}
|
|
25
|
+
/** Чем хозяин может попросить набор. Часть договора `SWAP_PROTOCOL`. */
|
|
26
|
+
interface ToolsetHooks {
|
|
27
|
+
/** Сервер сказал, что вышла новая версия: пройти самообновление сейчас. */
|
|
28
|
+
requestUpdate(): void;
|
|
29
|
+
}
|
|
30
|
+
|
|
2
31
|
/**
|
|
3
32
|
* Режим установщика. Возвращает true, если аргументы разобраны и сервер
|
|
4
33
|
* поднимать не надо.
|
|
@@ -11,6 +40,14 @@
|
|
|
11
40
|
* `main()` зовётся только при прямом запуске (`launchedDirectly`).
|
|
12
41
|
*/
|
|
13
42
|
declare function installer(args: string[]): Promise<boolean>;
|
|
43
|
+
/**
|
|
44
|
+
* Набор этого тела — для хозяина, который подхватывает новое тело на ходу.
|
|
45
|
+
*
|
|
46
|
+
* ⚠ ЭКСПОРТ — ЧАСТЬ ДОГОВОРА `SWAP_PROTOCOL` (`body-swap.ts`). Имя, форма
|
|
47
|
+
* `Toolset` и крючки хозяина меняются только вместе с номером.
|
|
48
|
+
*/
|
|
49
|
+
declare function toolset(hooks: ToolsetHooks): Promise<Toolset>;
|
|
50
|
+
|
|
14
51
|
/**
|
|
15
52
|
* Поднять сервер MCP.
|
|
16
53
|
*
|
|
@@ -20,7 +57,10 @@ declare function installer(args: string[]): Promise<boolean>;
|
|
|
20
57
|
* `catch → process.exit(1)` убил бы процесс мимо перехвата пускового файла, и
|
|
21
58
|
* обещанный откат на встроенную версию остался бы обещанием. Имя `start` —
|
|
22
59
|
* часть договора, за номером которого следит `LAUNCHER_PROTOCOL`.
|
|
60
|
+
*
|
|
61
|
+
* ⚠ ТОТ, КТО ПОДНЯЛ `start`, — ХОЗЯИН ПРОВОДА НА ВСЮ ЖИЗНЬ ПРОЦЕССА. Новое
|
|
62
|
+
* тело он подхватывает сам (`body-swap.ts`), без перезапуска Клода.
|
|
23
63
|
*/
|
|
24
64
|
declare function start(): Promise<void>;
|
|
25
65
|
|
|
26
|
-
export { installer, start };
|
|
66
|
+
export { SWAP_PROTOCOL, installer, start, toolset };
|
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { Engine, chooseBody, handOverToBody, VERSION, rollback, rollbackShell, remove, fromNpxCache, install, keyFromBlock, readConfig, ForeignBlockError,
|
|
3
|
-
import { fileURLToPath } from 'url';
|
|
2
|
+
import { Engine, chooseBody, handOverToBody, VERSION, rollback, rollbackShell, remove, fromNpxCache, install, keyFromBlock, readConfig, ForeignBlockError, McpServer, watchProcessCrashes, reportInstallFaults, noteInstallFault, StdioServerTransport, fromHost, WHERE_TO_GET_KEY, Wakefulness, systemBlocker, updateEngine, installStep, currentMachineFingerprint, CrashReporter, whenNewerReleased, buildAll, realPace, buildResources, shellDir, describeFailure, compare, toolError, NaparnikApiClient, ownSetupJobRunning, forModel, installedShell, startSetupJob, TITLE_UPDATE, runUpdate, setupJobDone, reportJobFaults, setupJobEnding, NaparnikConfigError, installMissing } from './chunk-USWWD5M5.js';
|
|
4
3
|
import { realpathSync, readFileSync } from 'fs';
|
|
4
|
+
import { join } from 'path';
|
|
5
|
+
import { fileURLToPath, pathToFileURL } from 'url';
|
|
5
6
|
|
|
6
7
|
// src/api-client.ts
|
|
7
8
|
function apiClientFor(state, machine = currentMachineFingerprint, engineVersion = () => null) {
|
|
@@ -43,7 +44,7 @@ var HOW_MONTAGE_WORKS = `
|
|
|
43
44
|
6. \u041F\u0440\u0430\u0432\u043A\u0430 \u0436\u0434\u0451\u0442 \u043F\u0435\u0447\u0430\u0442\u044C \u043F\u0440\u043E\u0447\u0438\u0442\u0430\u043D\u043D\u043E\u0439 \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u044B (stamps, document/edits.md):
|
|
44
45
|
\u0431\u0435\u0437 \u043D\u0435\u0451 plan_edit \u043E\u0442\u043A\u0430\u0436\u0435\u0442 \u0438 \u043F\u0440\u0438\u0448\u043B\u0451\u0442 \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u0443.
|
|
45
46
|
7. \u0422\u044F\u0436\u0451\u043B\u043E\u0435 (\u0432\u044B\u0440\u0435\u0437 \u0433\u0435\u0440\u043E\u044F, \u0440\u0430\u0441\u043F\u043E\u0437\u043D\u0430\u0432\u0430\u043D\u0438\u0435 \u0440\u0435\u0447\u0438) \u2014 \u041F\u041E \u041F\u0420\u041E\u0421\u042C\u0411\u0415, \u0432\u0435\u0441 \u0438\u0437 setup.
|
|
46
|
-
\xAB\u0414\u0430\xBB, \xAB\u043E\u0431\u043D\u043E\u0432\u0438\xBB \u2014 \u041E\u0414\u0418\u041D
|
|
47
|
+
\xAB\u0414\u0430\xBB, \xAB\u043E\u0431\u043D\u043E\u0432\u0438\xBB \u2014 \u041E\u0414\u0418\u041D install, \u0434\u0430\u043B\u044C\u0448\u0435 wait.
|
|
47
48
|
|
|
48
49
|
\u0421\u043F\u0440\u0430\u0432\u043E\u0447\u043D\u0438\u043A \u0433\u043E\u0434\u0438\u0442\u0441\u044F \u0438 \u0431\u0435\u0437 \u0440\u043E\u043B\u0438\u043A\u0430: \u043F\u0440\u0435\u0437\u0435\u043D\u0442\u0430\u0446\u0438\u044F.
|
|
49
50
|
\u041D\u0435 \u0432\u044B\u0434\u0443\u043C\u044B\u0432\u0430\u0439; \u0432\u0440\u0435\u043C\u044F \u2014 \u0442\u043E\u043B\u044C\u043A\u043E \u043E\u0442 \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u0430.
|
|
@@ -90,23 +91,6 @@ ${HOW_MONTAGE_WORKS}
|
|
|
90
91
|
\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.
|
|
91
92
|
`.trim();
|
|
92
93
|
}
|
|
93
|
-
var HOST_CUT = 2048;
|
|
94
|
-
var BASE_CHARS = 1500;
|
|
95
|
-
var NEWS_SEPARATOR = "\n\n";
|
|
96
|
-
var NEWS_LIMIT = Math.floor((HOST_CUT - BASE_CHARS - 2 * NEWS_SEPARATOR.length) / 2);
|
|
97
|
-
function aboutNewPayload(ownDir, fresh, megabytes) {
|
|
98
|
-
const now = ownDir === null ? "\u0434\u0432\u0438\u0436\u043E\u043A \u043D\u0435 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D" : `\u0441\u0442\u043E\u0438\u0442 ${ownDir}`;
|
|
99
|
-
return `\u0412\u042B\u0428\u041B\u0410 \u041D\u041E\u0412\u0410\u042F \u0412\u0415\u0420\u0421\u0418\u042F \u0414\u0412\u0418\u0416\u041A\u0410: ${now}, \u0435\u0441\u0442\u044C ${fresh} (${megabytes.toFixed(1)} \u041C\u0411). \u0421\u0430\u043C\u0430 \u043D\u0435 \u0441\u043A\u0430\u0447\u0430\u0435\u0442\u0441\u044F. \u0417\u0430\u0433\u043E\u0432\u043E\u0440\u0438\u0442 \u043E \u043C\u043E\u043D\u0442\u0430\u0436\u0435 \u2014 \u0441\u043A\u0430\u0436\u0438 \u043E\u0434\u043D\u043E\u0439 \u0444\u0440\u0430\u0437\u043E\u0439 \u0438 \u0441\u043F\u0440\u043E\u0441\u0438; \xAB\u0434\u0430\xBB \u2014 setup \u0441 what=engine \u0438 consent=true. \u041C\u043E\u043B\u0447\u0430 \u043D\u0435 \u043E\u0431\u043D\u043E\u0432\u043B\u044F\u0439 \u0438 \u0435\u0433\u043E \u0437\u0430\u0434\u0430\u0447\u0443 \u043D\u0435 \u0431\u0440\u043E\u0441\u0430\u0439.`;
|
|
100
|
-
}
|
|
101
|
-
function aboutNewShell(installed, fresh, notes) {
|
|
102
|
-
const head = `\u0412\u042B\u0428\u041B\u0410 \u041D\u041E\u0412\u0410\u042F \u0412\u0415\u0420\u0421\u0418\u042F \u0420\u0410\u0421\u0428\u0418\u0420\u0415\u041D\u0418\u042F: \u0441\u0442\u043E\u0438\u0442 ${installed}, \u0432\u044B\u0448\u043B\u0430 ${fresh}, \u0441\u0442\u0430\u0432\u0438\u0442\u0441\u044F \u043E\u0442\u0441\u044E\u0434\u0430.`;
|
|
103
|
-
const tail = "\u0417\u0430\u0433\u043E\u0432\u043E\u0440\u0438\u0442 \u043E \u043C\u043E\u043D\u0442\u0430\u0436\u0435 \u2014 \u0441\u043A\u0430\u0436\u0438 \u043E\u0434\u043D\u043E\u0439 \u0444\u0440\u0430\u0437\u043E\u0439 \u0438 \u0441\u043F\u0440\u043E\u0441\u0438; \xAB\u0434\u0430\xBB \u2014 setup \u0441 what=shell \u0438 consent=true. \u0412 \u0441\u0438\u043B\u0435 \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.";
|
|
104
|
-
if (notes === null || notes.trim() === "") return `${head} ${tail}`;
|
|
105
|
-
const room = NEWS_LIMIT - head.length - tail.length - " \u0427\u0442\u043E \u043D\u043E\u0432\u043E\u0433\u043E: . ".length;
|
|
106
|
-
const said = notes.replace(/\s+/g, " ").trim();
|
|
107
|
-
const cut = said.length <= room ? said : `${said.slice(0, Math.max(0, room - 1)).trimEnd()}\u2026`;
|
|
108
|
-
return `${head} \u0427\u0442\u043E \u043D\u043E\u0432\u043E\u0433\u043E: ${cut}. ${tail}`;
|
|
109
|
-
}
|
|
110
94
|
|
|
111
95
|
// src/auto-install.ts
|
|
112
96
|
var NO_AUTO = "NAPARNIK_NO_AUTOINSTALL";
|
|
@@ -126,7 +110,7 @@ async function prepareEngine(engine, opts) {
|
|
|
126
110
|
const plan = decideAuto({ off, hasKey, byHand, ready, refresh: opts.refresh === true });
|
|
127
111
|
if (plan === "nothing") return quiet;
|
|
128
112
|
if (plan === "refresh") {
|
|
129
|
-
const fresh = await updateEngine(engine,
|
|
113
|
+
const fresh = await updateEngine(engine, opts.key, opts.baseUrl);
|
|
130
114
|
const news = "error" in fresh ? fresh.error : typeof fresh.content === "string" ? fresh.content : "";
|
|
131
115
|
if (news !== "") say(news);
|
|
132
116
|
return { worked: true, ok: !("error" in fresh), lines: news === "" ? [] : [news] };
|
|
@@ -137,6 +121,186 @@ async function prepareEngine(engine, opts) {
|
|
|
137
121
|
if (text !== "") say(text);
|
|
138
122
|
return { worked: true, ok: !("error" in done), lines: text === "" ? [] : [text] };
|
|
139
123
|
}
|
|
124
|
+
var SWAP_PROTOCOL = 1;
|
|
125
|
+
function updatedWords(version) {
|
|
126
|
+
return forModel(`\u041E\u0431\u043D\u043E\u0432\u0438\u043B \u043C\u043E\u043D\u0442\u0430\u0436 \u0434\u043E ${version} \u2014 \u0443\u0436\u0435 \u0440\u0430\u0431\u043E\u0442\u0430\u0435\u0442.`);
|
|
127
|
+
}
|
|
128
|
+
function needsRestartWords(version) {
|
|
129
|
+
return forModel(
|
|
130
|
+
`\u041D\u043E\u0432\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F \u043C\u043E\u043D\u0442\u0430\u0436\u0430 ${version} \u0441\u043A\u0430\u0447\u0430\u043D\u0430, \u043D\u043E \u0432\u0441\u0442\u0430\u043D\u0435\u0442 \u0442\u043E\u043B\u044C\u043A\u043E \u043F\u043E\u0441\u043B\u0435 \u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u043A\u0430 Claude \u0438\u043B\u0438 Codex \u2014 \u0441\u043A\u0430\u0436\u0438 \u044D\u0442\u043E \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u0443 \u043E\u0434\u043D\u043E\u0439 \u0444\u0440\u0430\u0437\u043E\u0439, \u043A\u043E\u0433\u0434\u0430 \u043E\u043D \u0437\u0430\u043A\u043E\u043D\u0447\u0438\u0442 \u0442\u0435\u043A\u0443\u0449\u0435\u0435.`
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
var BodySwap = class {
|
|
134
|
+
constructor(o) {
|
|
135
|
+
this.o = o;
|
|
136
|
+
this.toolset = o.first;
|
|
137
|
+
this.version = o.version;
|
|
138
|
+
this.install(o.first);
|
|
139
|
+
}
|
|
140
|
+
o;
|
|
141
|
+
toolset;
|
|
142
|
+
/** Версия тела, которое сейчас отвечает; `null` — тело из `.mcpb` без папки версии. */
|
|
143
|
+
version;
|
|
144
|
+
inFlight = 0;
|
|
145
|
+
swapping = null;
|
|
146
|
+
/** Тела, которые не встали: второй раз не пробуем до смены `current`. */
|
|
147
|
+
refused = /* @__PURE__ */ new Set();
|
|
148
|
+
news = [];
|
|
149
|
+
/** Версия тела, которое отвечает сейчас. */
|
|
150
|
+
current() {
|
|
151
|
+
return this.version;
|
|
152
|
+
}
|
|
153
|
+
/** Самообновление сейчас: что встало — строкой модели в ближайший ответ. */
|
|
154
|
+
async selfUpdate() {
|
|
155
|
+
let updated;
|
|
156
|
+
try {
|
|
157
|
+
updated = await this.toolset.selfUpdate();
|
|
158
|
+
} catch (trouble) {
|
|
159
|
+
this.o.fault(trouble);
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
if (updated.engine !== null && updated.shell === null) this.news.push(updatedWords(updated.engine));
|
|
163
|
+
await this.refresh();
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Заменить набор, если вышло новое тело и ничего не идёт.
|
|
167
|
+
*
|
|
168
|
+
* ⚠ ОДНА ЗАМЕНА ЗА РАЗ. Два вызова, пришедшие вместе, ждут одну и ту же
|
|
169
|
+
* замену, а не заводят две: вторая импортировала бы то же тело второй раз.
|
|
170
|
+
*/
|
|
171
|
+
refresh() {
|
|
172
|
+
if (this.swapping !== null) return this.swapping;
|
|
173
|
+
if (this.o.off === true || this.inFlight > 0 || this.toolset.busy()) return Promise.resolve();
|
|
174
|
+
const next = this.pointed();
|
|
175
|
+
if (next === null || next === this.version || this.refused.has(next)) return Promise.resolve();
|
|
176
|
+
this.swapping = this.swapTo(next).finally(() => {
|
|
177
|
+
this.swapping = null;
|
|
178
|
+
});
|
|
179
|
+
return this.swapping;
|
|
180
|
+
}
|
|
181
|
+
/** Какую версию тела называет указатель — дёшево, без сверки сумм. */
|
|
182
|
+
pointed() {
|
|
183
|
+
try {
|
|
184
|
+
const name = readFileSync(join(shellDir(this.o.home), "current"), "utf8").trim();
|
|
185
|
+
return name === "" ? null : name;
|
|
186
|
+
} catch {
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
async swapTo(next) {
|
|
191
|
+
const choice = chooseBody({ home: this.o.home, ownFile: this.o.ownFile });
|
|
192
|
+
if (choice.what !== "body" || choice.version !== next) {
|
|
193
|
+
this.refused.add(next);
|
|
194
|
+
if (choice.what === "embedded" && choice.why !== null) this.o.log(`\u043D\u043E\u0432\u043E\u0435 \u0442\u0435\u043B\u043E \u043D\u0435 \u0433\u043E\u0434\u0438\u0442\u0441\u044F: ${choice.why}`);
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
let body;
|
|
198
|
+
let toolset2;
|
|
199
|
+
try {
|
|
200
|
+
body = await (this.o.load ?? importBody)(choice.entry);
|
|
201
|
+
if (body.SWAP_PROTOCOL !== SWAP_PROTOCOL || typeof body.toolset !== "function") {
|
|
202
|
+
this.refused.add(next);
|
|
203
|
+
this.news.push(needsRestartWords(next));
|
|
204
|
+
this.o.log(`\u0442\u0435\u043B\u043E ${next} \u0433\u043E\u0432\u043E\u0440\u0438\u0442 \u043F\u043E \u0434\u0440\u0443\u0433\u043E\u043C\u0443 \u0434\u043E\u0433\u043E\u0432\u043E\u0440\u0443 \u0437\u0430\u043C\u0435\u043D\u044B \u2014 \u0432\u0441\u0442\u0430\u043D\u0435\u0442 \u0441 \u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u043A\u043E\u043C`);
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
toolset2 = await body.toolset({ requestUpdate: () => {
|
|
208
|
+
void this.selfUpdate();
|
|
209
|
+
} });
|
|
210
|
+
} catch (trouble) {
|
|
211
|
+
this.refused.add(next);
|
|
212
|
+
this.o.fault(trouble);
|
|
213
|
+
this.o.log(`\u0442\u0435\u043B\u043E ${next} \u043D\u0435 \u043F\u043E\u0434\u043D\u044F\u043B\u043E\u0441\u044C (${describeFailure(trouble)}) \u2014 \u0440\u0430\u0431\u043E\u0442\u0430\u044E \u043F\u0440\u0435\u0436\u043D\u0438\u043C`);
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
if (this.inFlight > 0 || this.toolset.busy()) return;
|
|
217
|
+
const was = this.version;
|
|
218
|
+
this.toolset = toolset2;
|
|
219
|
+
this.version = next;
|
|
220
|
+
this.install(toolset2);
|
|
221
|
+
this.o.log(`\u043F\u043E\u0434\u0445\u0432\u0430\u0442\u0438\u043B \u0442\u0435\u043B\u043E ${next} \u0431\u0435\u0437 \u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u043A\u0430`);
|
|
222
|
+
if (was === null || compare(next, was) > 0) this.news.push(updatedWords(next));
|
|
223
|
+
}
|
|
224
|
+
install(toolset2) {
|
|
225
|
+
for (const one of toolset2.resources) this.o.shelf.addResource(one.resource, one.contents);
|
|
226
|
+
this.o.shelf.replaceTools(toolset2.tools.map((tool) => this.proxy(tool)));
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Инструмент, который зовёт ТЕКУЩИЙ набор, а не тот, что был при регистрации.
|
|
230
|
+
*
|
|
231
|
+
* ⚠ ЗАМЕНА ПРОВЕРЯЕТСЯ И ПЕРЕД ВЫЗОВОМ, А НЕ ТОЛЬКО ПОСЛЕ. Тело мог обновить
|
|
232
|
+
* соседний процесс (Codex рядом с Claude Desktop), и первый же вызов после
|
|
233
|
+
* этого шёл бы прежним кодом.
|
|
234
|
+
*/
|
|
235
|
+
proxy(tool) {
|
|
236
|
+
const name = tool.name;
|
|
237
|
+
return {
|
|
238
|
+
...tool,
|
|
239
|
+
execute: async (args, ctx) => {
|
|
240
|
+
await this.refresh();
|
|
241
|
+
const now = this.toolset.tools.find((one) => one.name === name);
|
|
242
|
+
if (now === void 0) {
|
|
243
|
+
return toolError(`\u0418\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u0430 ${name} \u0432 \u043D\u043E\u0432\u043E\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u043C\u043E\u043D\u0442\u0430\u0436\u0430 \u043D\u0435\u0442 \u2014 \u043F\u043E\u0441\u043C\u043E\u0442\u0440\u0438 \u0441\u043F\u0438\u0441\u043E\u043A \u0438\u043D\u0441\u0442\u0440\u0443\u043C\u0435\u043D\u0442\u043E\u0432 \u0437\u0430\u043D\u043E\u0432\u043E.`);
|
|
244
|
+
}
|
|
245
|
+
this.inFlight += 1;
|
|
246
|
+
try {
|
|
247
|
+
return this.withNews(await now.execute(args, ctx));
|
|
248
|
+
} finally {
|
|
249
|
+
this.inFlight -= 1;
|
|
250
|
+
if (this.inFlight === 0) void this.refresh();
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
/** Приложить новость модели к ответу — один раз. В данные окна не идёт. */
|
|
256
|
+
withNews(result) {
|
|
257
|
+
if (this.news.length === 0) return result;
|
|
258
|
+
const said = this.news.splice(0).join("\n");
|
|
259
|
+
if (result.type === "error") return { ...result, error: `${result.error}
|
|
260
|
+
|
|
261
|
+
${said}` };
|
|
262
|
+
return typeof result.content === "string" ? { ...result, content: `${result.content}
|
|
263
|
+
|
|
264
|
+
${said}` } : { ...result, content: [...result.content, { type: "text", text: said }] };
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
async function importBody(entry) {
|
|
268
|
+
return await import(pathToFileURL(entry).href);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// src/self-update.ts
|
|
272
|
+
var SELF_UPDATE_EVERY_MS = 6 * 60 * 60 * 1e3;
|
|
273
|
+
var NO_UPDATE = "NAPARNIK_NO_UPDATE";
|
|
274
|
+
var POINTER_MS = 15e3;
|
|
275
|
+
var NOTHING = { engine: null, shell: null };
|
|
276
|
+
async function selfUpdatePass(deps) {
|
|
277
|
+
const { engine, key, baseUrl } = deps;
|
|
278
|
+
if (engine.variable(NO_UPDATE) !== void 0) return NOTHING;
|
|
279
|
+
if (engine.variable(NO_AUTO) !== void 0) return NOTHING;
|
|
280
|
+
if (key === void 0 || key === "") return NOTHING;
|
|
281
|
+
if (engine.place() === null) return NOTHING;
|
|
282
|
+
const home = engine.home();
|
|
283
|
+
const engineWas = engine.freshVersion();
|
|
284
|
+
const shellWas = installedShell(home);
|
|
285
|
+
const id = startSetupJob(TITLE_UPDATE, (job) => runUpdate(job, {
|
|
286
|
+
engine,
|
|
287
|
+
key,
|
|
288
|
+
baseUrl,
|
|
289
|
+
what: "all",
|
|
290
|
+
pointerMs: POINTER_MS,
|
|
291
|
+
installMissing: deps.installMissing
|
|
292
|
+
}), Date.now, home);
|
|
293
|
+
await setupJobDone(id);
|
|
294
|
+
if (deps.crashes !== null) reportJobFaults(deps.crashes, id, "\u0441\u0430\u043C\u043E\u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0435");
|
|
295
|
+
const ending = setupJobEnding(id);
|
|
296
|
+
if (ending === null) return NOTHING;
|
|
297
|
+
const engineNow = engine.freshVersion();
|
|
298
|
+
const shellNow = installedShell(home);
|
|
299
|
+
return {
|
|
300
|
+
engine: engineNow !== null && engineNow !== engineWas ? engineNow : null,
|
|
301
|
+
shell: shellNow !== shellWas ? shellNow : null
|
|
302
|
+
};
|
|
303
|
+
}
|
|
140
304
|
|
|
141
305
|
// src/installer-args.ts
|
|
142
306
|
var KEY_ARG = "--key";
|
|
@@ -341,51 +505,9 @@ function wakefulEngine() {
|
|
|
341
505
|
function serverAddress(state) {
|
|
342
506
|
return state.ok ? state.config.baseUrl : state.baseUrl;
|
|
343
507
|
}
|
|
344
|
-
async function
|
|
345
|
-
if (engine.variable("NAPARNIK_NO_UPDATE") !== void 0) return null;
|
|
346
|
-
if (engine.place() === null) return null;
|
|
347
|
-
if (engine.pathSetByHand()) return null;
|
|
348
|
-
if (!timeToCheck2(engine)) return null;
|
|
349
|
-
try {
|
|
350
|
-
const url = engine.variable("NAPARNIK_UPDATE_MANIFEST") ?? manifestUrlFor(baseUrl);
|
|
351
|
-
const outcome = await fetchManifest(url, void 0, key);
|
|
352
|
-
markChecked2(engine);
|
|
353
|
-
const decision = decide(engine.freshVersion(), outcome.ok ? outcome.manifest : null);
|
|
354
|
-
if (decision.what !== "newer_available") return null;
|
|
355
|
-
return aboutNewPayload(
|
|
356
|
-
engine.freshVersion(),
|
|
357
|
-
decision.manifest.version,
|
|
358
|
-
decision.manifest.bytes / 1024 / 1024
|
|
359
|
-
);
|
|
360
|
-
} catch {
|
|
361
|
-
return null;
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
async function newShell(engine, baseUrl, key) {
|
|
365
|
-
if (engine.variable("NAPARNIK_NO_UPDATE") !== void 0) return null;
|
|
366
|
-
const home = engine.home();
|
|
367
|
-
const dir = shellDir(home);
|
|
368
|
-
if (!timeToCheck(dir)) return null;
|
|
369
|
-
try {
|
|
370
|
-
const url = engine.variable("NAPARNIK_BUNDLE_MANIFEST") ?? bundleUrlFor(baseUrl);
|
|
371
|
-
const outcome = await fetchShellManifest(url, void 0, key);
|
|
372
|
-
markChecked(dir);
|
|
373
|
-
const decision = decideShell(installedShell(home), outcome.ok ? outcome.manifest : null);
|
|
374
|
-
if (decision.what !== "newer_available") return null;
|
|
375
|
-
return aboutNewShell(
|
|
376
|
-
installedShell(home),
|
|
377
|
-
decision.manifest.version,
|
|
378
|
-
decision.manifest.notes
|
|
379
|
-
);
|
|
380
|
-
} catch {
|
|
381
|
-
return null;
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
async function start() {
|
|
385
|
-
const state = readConfig();
|
|
508
|
+
async function assemble(state, hooks) {
|
|
386
509
|
const engineForVersion = new Engine();
|
|
387
510
|
const client = apiClientFor(state, void 0, () => engineForVersion.currentVersion());
|
|
388
|
-
const basics = state.ok ? configuredInstructions(state.config.baseUrl) : notConfiguredInstructions(state.problem, state.message);
|
|
389
511
|
const { awake, engine } = wakefulEngine();
|
|
390
512
|
const crashes = new CrashReporter({
|
|
391
513
|
client,
|
|
@@ -393,33 +515,67 @@ async function start() {
|
|
|
393
515
|
engineVersion: () => engine.currentVersion(),
|
|
394
516
|
canSend: state.ok
|
|
395
517
|
});
|
|
396
|
-
|
|
397
|
-
const
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
const
|
|
518
|
+
const key = state.ok ? state.config.apiKey : void 0;
|
|
519
|
+
const baseUrl = serverAddress(state);
|
|
520
|
+
whenNewerReleased(() => {
|
|
521
|
+
hooks.requestUpdate();
|
|
522
|
+
});
|
|
523
|
+
const passport = await engine.passport();
|
|
524
|
+
const tools = buildAll(client, engine, passport, key, baseUrl, realPace, awake, crashes);
|
|
525
|
+
const toolset2 = {
|
|
526
|
+
tools,
|
|
527
|
+
resources: buildResources(),
|
|
528
|
+
busy: () => engine.busy() || ownSetupJobRunning(),
|
|
529
|
+
selfUpdate: () => selfUpdatePass({
|
|
530
|
+
engine,
|
|
531
|
+
key,
|
|
532
|
+
baseUrl,
|
|
533
|
+
crashes: state.ok ? crashes : null,
|
|
534
|
+
installMissing: () => installMissing(engine, key, baseUrl)
|
|
535
|
+
})
|
|
536
|
+
};
|
|
537
|
+
return { toolset: toolset2, engine, awake, crashes };
|
|
538
|
+
}
|
|
539
|
+
async function toolset(hooks) {
|
|
540
|
+
return (await assemble(readConfig(), hooks)).toolset;
|
|
541
|
+
}
|
|
542
|
+
function startedAs(home) {
|
|
543
|
+
const own = theFile();
|
|
544
|
+
const shells = shellDir(home);
|
|
545
|
+
return own.startsWith(`${shells}/`) || own.startsWith(`${shells}\\`) ? own.slice(shells.length + 1).split(/[\\/]/)[0] ?? VERSION : VERSION;
|
|
546
|
+
}
|
|
547
|
+
async function start() {
|
|
548
|
+
const state = readConfig();
|
|
549
|
+
const basics = state.ok ? configuredInstructions(state.config.baseUrl) : notConfiguredInstructions(state.problem, state.message);
|
|
403
550
|
const server = new McpServer(void 0, {
|
|
404
|
-
instructions:
|
|
405
|
-
// ⚠ ПРЕДСТАВЛЯЕМСЯ СВОИМ ИМЕНЕМ, А НЕ ИМЕНЕМ ЯДРА. В
|
|
406
|
-
//
|
|
407
|
-
// видит ровно это — и читал «@naparnik/super-agent-core 0.1.0» вместо
|
|
551
|
+
instructions: basics,
|
|
552
|
+
// ⚠ ПРЕДСТАВЛЯЕМСЯ СВОИМ ИМЕНЕМ, А НЕ ИМЕНЕМ ЯДРА. В Codex человек видит
|
|
553
|
+
// ровно это — и читал «@naparnik/super-agent-core 0.1.0» вместо
|
|
408
554
|
// названия расширения, которое сам поставил.
|
|
409
555
|
serverInfo: { name: "@naparnik/mcp", version: VERSION }
|
|
410
556
|
});
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
557
|
+
let swap = null;
|
|
558
|
+
const hooks = { requestUpdate: () => {
|
|
559
|
+
void swap?.selfUpdate();
|
|
560
|
+
} };
|
|
561
|
+
const { toolset: first, engine, awake, crashes } = await assemble(state, hooks);
|
|
562
|
+
watchProcessCrashes(crashes);
|
|
563
|
+
const home = engine.home();
|
|
564
|
+
swap = new BodySwap({
|
|
565
|
+
shelf: server,
|
|
566
|
+
first,
|
|
567
|
+
version: startedAs(home),
|
|
568
|
+
home,
|
|
569
|
+
ownFile: theFile(),
|
|
570
|
+
// Проба кандидата (`probeShell`) и разбор беды руками: тело не меняется.
|
|
571
|
+
off: engine.variable("NAPARNIK_NO_BODY") !== void 0 || engine.variable(NO_UPDATE) !== void 0,
|
|
572
|
+
log,
|
|
573
|
+
fault: (trouble) => {
|
|
574
|
+
void reportInstallFaults(crashes, async () => {
|
|
575
|
+
noteInstallFault("shell-swap", trouble);
|
|
576
|
+
});
|
|
577
|
+
}
|
|
578
|
+
});
|
|
423
579
|
const transport = new StdioServerTransport();
|
|
424
580
|
transport.onClose((error) => {
|
|
425
581
|
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}`);
|
|
@@ -429,20 +585,27 @@ async function start() {
|
|
|
429
585
|
await server.start(transport);
|
|
430
586
|
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";
|
|
431
587
|
if (state.ok) {
|
|
432
|
-
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}`);
|
|
588
|
+
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: ${first.tools.length}; ${aboutMontage}`);
|
|
433
589
|
} else {
|
|
434
590
|
log(
|
|
435
591
|
`${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}.`
|
|
436
592
|
);
|
|
437
593
|
}
|
|
438
594
|
if (state.ok) {
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
595
|
+
const background = async () => {
|
|
596
|
+
await awake.during(() => reportInstallFaults(crashes, () => prepareEngine(engine, {
|
|
597
|
+
key: state.config.apiKey,
|
|
598
|
+
baseUrl: state.config.baseUrl,
|
|
599
|
+
tell: log
|
|
600
|
+
})));
|
|
601
|
+
await swap?.selfUpdate();
|
|
602
|
+
};
|
|
603
|
+
void background().catch((trouble) => {
|
|
604
|
+
log(`\u0434\u0432\u0438\u0436\u043E\u043A \u0434\u043E\u043A\u0430\u0447\u0430\u0442\u044C \u0438\u043B\u0438 \u043E\u0431\u043D\u043E\u0432\u0438\u0442\u044C \u043D\u0435 \u0432\u044B\u0448\u043B\u043E: ${trouble instanceof Error ? trouble.message : String(trouble)}`);
|
|
445
605
|
});
|
|
606
|
+
setInterval(() => {
|
|
607
|
+
void swap?.selfUpdate();
|
|
608
|
+
}, SELF_UPDATE_EVERY_MS).unref();
|
|
446
609
|
}
|
|
447
610
|
for (const signal of ["SIGINT", "SIGTERM"]) {
|
|
448
611
|
process.on(signal, () => {
|
|
@@ -478,4 +641,4 @@ if (launchedDirectly()) {
|
|
|
478
641
|
});
|
|
479
642
|
}
|
|
480
643
|
|
|
481
|
-
export { installer, start };
|
|
644
|
+
export { SWAP_PROTOCOL, installer, start, toolset };
|