@oneentry/mcp-platform-server 0.1.0 → 0.1.1
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/README.md +113 -71
- package/data/permissions.json +411 -0
- package/dist/api/build-catalog.d.ts +24 -0
- package/dist/api/build-catalog.d.ts.map +1 -0
- package/dist/api/build-catalog.js +257 -0
- package/dist/api/build-catalog.js.map +1 -0
- package/dist/api/catalog.d.ts +22 -3
- package/dist/api/catalog.d.ts.map +1 -1
- package/dist/api/catalog.js +69 -4
- package/dist/api/catalog.js.map +1 -1
- package/dist/api/normalize-schema.d.ts +14 -0
- package/dist/api/normalize-schema.d.ts.map +1 -0
- package/dist/api/normalize-schema.js +151 -0
- package/dist/api/normalize-schema.js.map +1 -0
- package/dist/api/swagger-source.d.ts +22 -0
- package/dist/api/swagger-source.d.ts.map +1 -0
- package/dist/api/swagger-source.js +76 -0
- package/dist/api/swagger-source.js.map +1 -0
- package/dist/api/types.d.ts +1 -1
- package/dist/api/types.d.ts.map +1 -1
- package/dist/bin/cli.js +11 -3
- package/dist/bin/cli.js.map +1 -1
- package/dist/config/config.d.ts +84 -10
- package/dist/config/config.d.ts.map +1 -1
- package/dist/config/config.js +69 -6
- package/dist/config/config.js.map +1 -1
- package/dist/index.d.ts +9 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/knowledge/github.d.ts +46 -0
- package/dist/knowledge/github.d.ts.map +1 -0
- package/dist/knowledge/github.js +214 -0
- package/dist/knowledge/github.js.map +1 -0
- package/dist/knowledge/loader.d.ts +46 -19
- package/dist/knowledge/loader.d.ts.map +1 -1
- package/dist/knowledge/loader.js +92 -105
- package/dist/knowledge/loader.js.map +1 -1
- package/dist/knowledge/search.d.ts +11 -0
- package/dist/knowledge/search.d.ts.map +1 -1
- package/dist/knowledge/search.js +36 -3
- package/dist/knowledge/search.js.map +1 -1
- package/dist/knowledge/tar.d.ts +22 -0
- package/dist/knowledge/tar.d.ts.map +1 -0
- package/dist/knowledge/tar.js +120 -0
- package/dist/knowledge/tar.js.map +1 -0
- package/dist/knowledge/types.d.ts +31 -10
- package/dist/knowledge/types.d.ts.map +1 -1
- package/dist/server.d.ts +3 -2
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +13 -6
- package/dist/server.js.map +1 -1
- package/dist/session.d.ts +6 -0
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +8 -0
- package/dist/session.js.map +1 -1
- package/dist/tools/guide.d.ts.map +1 -1
- package/dist/tools/guide.js +9 -2
- package/dist/tools/guide.js.map +1 -1
- package/dist/tools/whoami.d.ts.map +1 -1
- package/dist/tools/whoami.js +4 -0
- package/dist/tools/whoami.js.map +1 -1
- package/dist/transports/http.d.ts.map +1 -1
- package/dist/transports/http.js +26 -1
- package/dist/transports/http.js.map +1 -1
- package/dist/transports/stdio.js +1 -1
- package/dist/transports/stdio.js.map +1 -1
- package/knowledge/operating-rules.md +176 -0
- package/package.json +4 -4
- package/data/catalog.json +0 -1
- package/data/knowledge.json +0 -1
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { dirname, join, relative, resolve, sep } from 'node:path';
|
|
3
|
+
import { readTarGz } from './tar.js';
|
|
4
|
+
/** Каталог внутри репозитория, в котором лежит документация. */
|
|
5
|
+
const ROOT = 'knowledge';
|
|
6
|
+
const isRecord = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
7
|
+
/** Каталог кэша одного репозитория. Слэш в имени заменён, чтобы это был один уровень. */
|
|
8
|
+
const repoCacheDir = (source) => resolve(source.cacheDir, source.repo.replace('/', '--'));
|
|
9
|
+
const stateFile = (source) => join(repoCacheDir(source), 'current.json');
|
|
10
|
+
const readState = (source) => {
|
|
11
|
+
try {
|
|
12
|
+
const parsed = JSON.parse(readFileSync(stateFile(source), 'utf8'));
|
|
13
|
+
if (!isRecord(parsed) ||
|
|
14
|
+
typeof parsed['sha'] !== 'string' ||
|
|
15
|
+
typeof parsed['ref'] !== 'string' ||
|
|
16
|
+
typeof parsed['checkedAt'] !== 'number') {
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
return { ref: parsed['ref'], sha: parsed['sha'], checkedAt: parsed['checkedAt'] };
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
const writeState = (source, state) => {
|
|
26
|
+
mkdirSync(repoCacheDir(source), { recursive: true });
|
|
27
|
+
writeFileSync(stateFile(source), `${JSON.stringify(state)}\n`);
|
|
28
|
+
};
|
|
29
|
+
/** Рекурсивно собирает `*.md` каталога. Используется и кэшем, и локальным клоном. */
|
|
30
|
+
export const walkMarkdown = (root) => {
|
|
31
|
+
const out = [];
|
|
32
|
+
const visit = (dir) => {
|
|
33
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
34
|
+
const full = join(dir, entry.name);
|
|
35
|
+
if (entry.isDirectory()) {
|
|
36
|
+
visit(full);
|
|
37
|
+
}
|
|
38
|
+
else if (entry.isFile() && entry.name.endsWith('.md')) {
|
|
39
|
+
out.push(full);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
visit(root);
|
|
44
|
+
return out.sort();
|
|
45
|
+
};
|
|
46
|
+
const exists = (path) => {
|
|
47
|
+
try {
|
|
48
|
+
statSync(path);
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
/** Читает распакованное дерево из кэша. */
|
|
56
|
+
const readCached = (source, sha) => {
|
|
57
|
+
const dir = join(repoCacheDir(source), sha, ROOT);
|
|
58
|
+
if (!exists(dir)) {
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
return walkMarkdown(dir).map((file) => ({
|
|
62
|
+
path: relative(dir, file).split(sep).join('/'),
|
|
63
|
+
content: readFileSync(file, 'utf8'),
|
|
64
|
+
}));
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Записывает дерево в кэш и удаляет каталоги остальных sha.
|
|
68
|
+
* Кэш адресуется коммитом, поэтому старые версии не нужны никогда:
|
|
69
|
+
* запись неизменяема, и «протухнуть» она не может.
|
|
70
|
+
*/
|
|
71
|
+
const writeCache = (source, sha, files) => {
|
|
72
|
+
const base = repoCacheDir(source);
|
|
73
|
+
const target = join(base, sha, ROOT);
|
|
74
|
+
for (const file of files) {
|
|
75
|
+
const full = join(target, file.path);
|
|
76
|
+
mkdirSync(dirname(full), { recursive: true });
|
|
77
|
+
writeFileSync(full, file.content);
|
|
78
|
+
}
|
|
79
|
+
for (const entry of readdirSync(base, { withFileTypes: true })) {
|
|
80
|
+
if (entry.isDirectory() && entry.name !== sha) {
|
|
81
|
+
rmSync(join(base, entry.name), { recursive: true, force: true });
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
const headers = (source, accept) => ({
|
|
86
|
+
accept,
|
|
87
|
+
'user-agent': 'oneentry-mcp-platform',
|
|
88
|
+
...(source.token ? { authorization: `Bearer ${source.token}` } : {}),
|
|
89
|
+
});
|
|
90
|
+
/**
|
|
91
|
+
* Расшифровывает код ответа GitHub в причину, по которой ref не превратился в коммит.
|
|
92
|
+
* Голый статус здесь бесполезен: 404 и 409 — это разные ошибки настройки, и обе
|
|
93
|
+
* встречаются при первом подключении к новому репозиторию знаний.
|
|
94
|
+
*/
|
|
95
|
+
const shaFailureHint = (status) => {
|
|
96
|
+
switch (status) {
|
|
97
|
+
case 403: {
|
|
98
|
+
return ' (rate limit — set ONEENTRY_GITHUB_TOKEN)';
|
|
99
|
+
}
|
|
100
|
+
case 404: {
|
|
101
|
+
return ' (no such repository or ref — check ONEENTRY_MCP_KNOWLEDGE_REPO, and set ONEENTRY_GITHUB_TOKEN if it is private)';
|
|
102
|
+
}
|
|
103
|
+
case 409: {
|
|
104
|
+
return ' (the repository is empty — it has no commits yet)';
|
|
105
|
+
}
|
|
106
|
+
default: {
|
|
107
|
+
return '';
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
/**
|
|
112
|
+
* Превращает ref в конкретный коммит. Ответ — голый sha, поэтому запрос дешёвый:
|
|
113
|
+
* его можно делать при каждом запуске, не скачивая архив.
|
|
114
|
+
*/
|
|
115
|
+
const resolveSha = async (source) => {
|
|
116
|
+
const url = `https://api.github.com/repos/${source.repo}/commits/${encodeURIComponent(source.ref)}`;
|
|
117
|
+
const response = await fetch(url, {
|
|
118
|
+
headers: headers(source, 'application/vnd.github.sha'),
|
|
119
|
+
signal: AbortSignal.timeout(source.timeoutMs),
|
|
120
|
+
});
|
|
121
|
+
if (!response.ok) {
|
|
122
|
+
throw new Error(`GitHub answered ${String(response.status)} for ${source.repo}@${source.ref}` +
|
|
123
|
+
shaFailureHint(response.status));
|
|
124
|
+
}
|
|
125
|
+
const sha = (await response.text()).trim();
|
|
126
|
+
if (!/^[0-9a-f]{7,40}$/.test(sha)) {
|
|
127
|
+
throw new Error(`GitHub returned an unexpected commit id for ${source.repo}@${source.ref}`);
|
|
128
|
+
}
|
|
129
|
+
return sha;
|
|
130
|
+
};
|
|
131
|
+
/**
|
|
132
|
+
* Отбирает из архива только документацию.
|
|
133
|
+
* Всё, что вне `knowledge/`, и любой путь с `..` отбрасываются: архив приходит
|
|
134
|
+
* из сети, и он не должен решать, куда мы пишем.
|
|
135
|
+
*/
|
|
136
|
+
const selectDocs = (entries) => {
|
|
137
|
+
const prefix = `${ROOT}/`;
|
|
138
|
+
return entries
|
|
139
|
+
.filter((entry) => entry.path.startsWith(prefix) &&
|
|
140
|
+
entry.path.endsWith('.md') &&
|
|
141
|
+
!entry.path.split('/').includes('..'))
|
|
142
|
+
.map((entry) => ({ path: entry.path.slice(prefix.length), content: entry.content }));
|
|
143
|
+
};
|
|
144
|
+
/** Скачивает архив репозитория на конкретном коммите. Один запрос, лимитов API нет. */
|
|
145
|
+
const download = async (source, sha) => {
|
|
146
|
+
const url = `https://codeload.github.com/${source.repo}/tar.gz/${sha}`;
|
|
147
|
+
const response = await fetch(url, {
|
|
148
|
+
headers: headers(source, 'application/octet-stream'),
|
|
149
|
+
signal: AbortSignal.timeout(source.timeoutMs),
|
|
150
|
+
});
|
|
151
|
+
if (!response.ok) {
|
|
152
|
+
throw new Error(`GitHub answered ${String(response.status)} for the ${source.repo} archive`);
|
|
153
|
+
}
|
|
154
|
+
const files = selectDocs(readTarGz(Buffer.from(await response.arrayBuffer())));
|
|
155
|
+
if (files.length === 0) {
|
|
156
|
+
throw new Error(`${source.repo}@${sha} has no ${ROOT}/**/*.md — wrong repository or layout?`);
|
|
157
|
+
}
|
|
158
|
+
return files;
|
|
159
|
+
};
|
|
160
|
+
/**
|
|
161
|
+
* Отдаёт дерево знаний, предпочитая кэш.
|
|
162
|
+
* Порядок такой: свежий кэш -> сверка sha -> скачивание. Пока запись кэша моложе
|
|
163
|
+
* `refreshTtlMs`, сеть не трогается вообще — иначе цикл перезапусков сервера
|
|
164
|
+
* упирался бы в лимит анонимного API GitHub.
|
|
165
|
+
* Бросает исключение, если знания взять неоткуда; решение о запасном варианте
|
|
166
|
+
* принимает вызывающий.
|
|
167
|
+
*/
|
|
168
|
+
export const fetchKnowledgeTree = async (source) => {
|
|
169
|
+
const state = readState(source);
|
|
170
|
+
const files = state && state.ref === source.ref ? readCached(source, state.sha) : undefined;
|
|
171
|
+
/** Кэш годен только целиком: и запись о коммите, и распакованное дерево. */
|
|
172
|
+
const cache = state && files ? { state, files } : undefined;
|
|
173
|
+
if (cache && (source.offline || Date.now() - cache.state.checkedAt < source.refreshTtlMs)) {
|
|
174
|
+
return { files: cache.files, sha: cache.state.sha, source: 'cache' };
|
|
175
|
+
}
|
|
176
|
+
if (source.offline) {
|
|
177
|
+
throw new Error(`offline: no cached copy of ${source.repo}@${source.ref}`);
|
|
178
|
+
}
|
|
179
|
+
let sha;
|
|
180
|
+
try {
|
|
181
|
+
sha = await resolveSha(source);
|
|
182
|
+
}
|
|
183
|
+
catch (error) {
|
|
184
|
+
if (cache) {
|
|
185
|
+
/** Сеть недоступна, но кэш есть — работаем на нём, это не отказ. */
|
|
186
|
+
return { files: cache.files, sha: cache.state.sha, source: 'cache' };
|
|
187
|
+
}
|
|
188
|
+
throw error;
|
|
189
|
+
}
|
|
190
|
+
if (cache && cache.state.sha === sha) {
|
|
191
|
+
writeState(source, { ref: source.ref, sha, checkedAt: Date.now() });
|
|
192
|
+
return { files: cache.files, sha, source: 'cache' };
|
|
193
|
+
}
|
|
194
|
+
const downloaded = await download(source, sha);
|
|
195
|
+
writeCache(source, sha, downloaded);
|
|
196
|
+
writeState(source, { ref: source.ref, sha, checkedAt: Date.now() });
|
|
197
|
+
return { files: downloaded, sha, source: 'github' };
|
|
198
|
+
};
|
|
199
|
+
/**
|
|
200
|
+
* Читает знания из локального клона репозитория.
|
|
201
|
+
* Принимает и корень клона, и сам каталог `knowledge/` — путать их слишком легко,
|
|
202
|
+
* а разница видна по наличию подкаталога.
|
|
203
|
+
*/
|
|
204
|
+
export const readLocalTree = (path) => {
|
|
205
|
+
const root = exists(join(path, ROOT)) ? join(path, ROOT) : path;
|
|
206
|
+
if (!exists(root)) {
|
|
207
|
+
throw new Error(`Knowledge path "${path}" does not exist`);
|
|
208
|
+
}
|
|
209
|
+
return walkMarkdown(root).map((file) => ({
|
|
210
|
+
path: relative(root, file).split(sep).join('/'),
|
|
211
|
+
content: readFileSync(file, 'utf8'),
|
|
212
|
+
}));
|
|
213
|
+
};
|
|
214
|
+
//# sourceMappingURL=github.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github.js","sourceRoot":"","sources":["../../src/knowledge/github.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,27 +1,54 @@
|
|
|
1
|
-
import type
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { type KnowledgeFile } from './github.js';
|
|
2
|
+
import type { KnowledgeOrigin, KnowledgePack } from './types.js';
|
|
3
|
+
/** Настройки источника знаний, как их отдаёт конфигурация. */
|
|
4
|
+
export interface KnowledgeConfig {
|
|
5
|
+
repo: string;
|
|
6
|
+
ref: string;
|
|
7
|
+
/** Локальный клон репозитория знаний: приоритетнее сети. */
|
|
8
|
+
path?: string;
|
|
9
|
+
cacheDir: string;
|
|
10
|
+
refreshTtlMs: number;
|
|
11
|
+
offline: boolean;
|
|
12
|
+
token?: string;
|
|
13
|
+
timeoutMs: number;
|
|
14
|
+
}
|
|
15
|
+
/** Каталог с вшитым минимумом знаний (`operating-rules.md`). */
|
|
16
|
+
export declare const seedDir: () => string;
|
|
17
|
+
/** Каталог со сгенерированными данными пакета (`permissions.json`). */
|
|
5
18
|
export declare const dataDir: () => string;
|
|
6
19
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
20
|
+
* docId из пути внутри `knowledge/`.
|
|
21
|
+
* `<имя>/index.md` даёт docId `<имя>`: это позволяет разрезать большой документ
|
|
22
|
+
* на каталог из мелких файлов, не меняя идентификатор, на который уже ссылаются
|
|
23
|
+
* `docLinks` каталога операций и золотые запросы тестов.
|
|
9
24
|
*/
|
|
10
|
-
export declare const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
25
|
+
export declare const docIdFromPath: (path: string) => string;
|
|
26
|
+
/**
|
|
27
|
+
* Собирает пакет знаний из плоского списка файлов.
|
|
28
|
+
* Один вход для всех трёх источников — сети, кэша и локального клона, — поэтому
|
|
29
|
+
* поведение поиска не может разойтись между ними.
|
|
30
|
+
*/
|
|
31
|
+
export declare const packFromFiles: (params: {
|
|
32
|
+
files: readonly KnowledgeFile[];
|
|
33
|
+
source: KnowledgeOrigin;
|
|
14
34
|
builtAt: string;
|
|
35
|
+
repo?: string;
|
|
36
|
+
ref?: string;
|
|
37
|
+
sha?: string;
|
|
38
|
+
warning?: string;
|
|
15
39
|
}) => KnowledgePack;
|
|
16
|
-
/** Читает собранный снапшот из data/knowledge.json. */
|
|
17
|
-
export declare const loadSnapshot: () => KnowledgePack;
|
|
18
40
|
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
41
|
+
* Вшитый минимум: собственные правила эксплуатации пакета.
|
|
42
|
+
* Существует только затем, чтобы сервер без сети всё равно мог ответить на вопрос
|
|
43
|
+
* «как безопасно писать в эту CMS». Всё остальное живёт в репозитории знаний.
|
|
22
44
|
*/
|
|
23
|
-
export declare const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
45
|
+
export declare const seedPack: (warning?: string) => KnowledgePack;
|
|
46
|
+
/**
|
|
47
|
+
* Выбирает источник знаний: локальный клон -> GitHub (через кэш) -> вшитый минимум.
|
|
48
|
+
* Недоступный GitHub не мешает серверу подняться: пакет беднеет до вшитого минимума,
|
|
49
|
+
* а причина уезжает в `warning`, потому что сеть — не ошибка конфигурации.
|
|
50
|
+
* Единственное исключение бросается на нечитаемый локальный путь: его оператор указал
|
|
51
|
+
* явно, и молчаливое падение до вшитых правил выглядело бы как пустой корпус.
|
|
52
|
+
*/
|
|
53
|
+
export declare const resolveKnowledge: (config: KnowledgeConfig) => Promise<KnowledgePack>;
|
|
27
54
|
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/knowledge/loader.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAgC,aAAa,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/knowledge/loader.ts"],"names":[],"mappings":"AAIA,OAAO,EAAqC,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AACpF,OAAO,KAAK,EAAgC,eAAe,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE/F,8DAA8D;AAC9D,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,4DAA4D;IAC5D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AAKD,gEAAgE;AAChE,eAAO,MAAM,OAAO,QAAO,MAC+C,CAAC;AAE3E,uEAAuE;AACvE,eAAO,MAAM,OAAO,QAAO,MAC0C,CAAC;AAEtE;;;;;GAKG;AACH,eAAO,MAAM,aAAa,GAAI,MAAM,MAAM,KAAG,MACM,CAAC;AAEpD;;;;GAIG;AACH,eAAO,MAAM,aAAa,GAAI,QAAQ;IACpC,KAAK,EAAE,SAAS,aAAa,EAAE,CAAC;IAChC,MAAM,EAAE,eAAe,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,KAAG,aA2BH,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,QAAQ,GAAI,UAAU,MAAM,KAAG,aAWxC,CAAC;AAEL;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,GAAU,QAAQ,eAAe,KAAG,OAAO,CAAC,aAAa,CA2CrF,CAAC"}
|
package/dist/knowledge/loader.js
CHANGED
|
@@ -1,125 +1,112 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
3
|
import { fileURLToPath } from 'node:url';
|
|
4
4
|
import { chunkDocument } from './chunk.js';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
visit(full);
|
|
25
|
-
}
|
|
26
|
-
else if (entry.isFile() && entry.name.endsWith('.md')) {
|
|
27
|
-
out.push(full);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
};
|
|
31
|
-
visit(root);
|
|
32
|
-
return out.sort();
|
|
33
|
-
};
|
|
34
|
-
const exists = (path) => {
|
|
35
|
-
try {
|
|
36
|
-
statSync(path);
|
|
37
|
-
return true;
|
|
38
|
-
}
|
|
39
|
-
catch {
|
|
40
|
-
return false;
|
|
41
|
-
}
|
|
42
|
-
};
|
|
43
|
-
const collectSource = (repoRoot, spec) => {
|
|
44
|
-
const target = resolve(repoRoot, spec.subPath);
|
|
5
|
+
import { fetchKnowledgeTree, readLocalTree } from './github.js';
|
|
6
|
+
const messageOf = (error) => error instanceof Error ? error.message : String(error);
|
|
7
|
+
/** Каталог с вшитым минимумом знаний (`operating-rules.md`). */
|
|
8
|
+
export const seedDir = () => resolve(fileURLToPath(new URL('.', import.meta.url)), '../../knowledge');
|
|
9
|
+
/** Каталог со сгенерированными данными пакета (`permissions.json`). */
|
|
10
|
+
export const dataDir = () => resolve(fileURLToPath(new URL('.', import.meta.url)), '../../data');
|
|
11
|
+
/**
|
|
12
|
+
* docId из пути внутри `knowledge/`.
|
|
13
|
+
* `<имя>/index.md` даёт docId `<имя>`: это позволяет разрезать большой документ
|
|
14
|
+
* на каталог из мелких файлов, не меняя идентификатор, на который уже ссылаются
|
|
15
|
+
* `docLinks` каталога операций и золотые запросы тестов.
|
|
16
|
+
*/
|
|
17
|
+
export const docIdFromPath = (path) => path.replace(/\.md$/, '').replace(/\/index$/, '');
|
|
18
|
+
/**
|
|
19
|
+
* Собирает пакет знаний из плоского списка файлов.
|
|
20
|
+
* Один вход для всех трёх источников — сети, кэша и локального клона, — поэтому
|
|
21
|
+
* поведение поиска не может разойтись между ними.
|
|
22
|
+
*/
|
|
23
|
+
export const packFromFiles = (params) => {
|
|
45
24
|
const docs = [];
|
|
46
25
|
const chunks = [];
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
50
|
-
const files = spec.singleFile ? [target] : walkMarkdown(target);
|
|
51
|
-
for (const file of files) {
|
|
52
|
-
const rel = spec.singleFile
|
|
53
|
-
? file.split(sep).slice(-1).join('')
|
|
54
|
-
: relative(target, file);
|
|
55
|
-
const slug = rel.replace(/\.md$/, '').split(sep).join('/');
|
|
56
|
-
const docId = spec.docPrefix ? `${spec.docPrefix}/${slug}` : slug;
|
|
26
|
+
for (const file of [...params.files].sort((a, b) => a.path.localeCompare(b.path))) {
|
|
27
|
+
const docId = docIdFromPath(file.path);
|
|
57
28
|
const result = chunkDocument({
|
|
58
29
|
docId,
|
|
59
|
-
repo:
|
|
60
|
-
path:
|
|
61
|
-
markdown:
|
|
30
|
+
repo: docId.split('/')[0] ?? 'mcp',
|
|
31
|
+
path: `knowledge/${file.path}`,
|
|
32
|
+
markdown: file.content,
|
|
62
33
|
});
|
|
63
34
|
docs.push(result.doc);
|
|
64
35
|
chunks.push(...result.chunks);
|
|
65
36
|
}
|
|
66
|
-
return {
|
|
37
|
+
return {
|
|
38
|
+
version: 1,
|
|
39
|
+
builtAt: params.builtAt,
|
|
40
|
+
source: params.source,
|
|
41
|
+
...(params.repo ? { repo: params.repo } : {}),
|
|
42
|
+
...(params.ref ? { ref: params.ref } : {}),
|
|
43
|
+
...(params.sha ? { sha: params.sha } : {}),
|
|
44
|
+
...(params.warning ? { warning: params.warning } : {}),
|
|
45
|
+
docs,
|
|
46
|
+
chunks,
|
|
47
|
+
};
|
|
67
48
|
};
|
|
68
|
-
/** Каталог со собственными знаниями пакета (operating-rules.md и т.п.). */
|
|
69
|
-
export const ownKnowledgeDir = () => resolve(fileURLToPath(new URL('.', import.meta.url)), '../../knowledge');
|
|
70
|
-
/** Каталог со собранными данными пакета (knowledge.json, catalog.json). */
|
|
71
|
-
export const dataDir = () => resolve(fileURLToPath(new URL('.', import.meta.url)), '../../data');
|
|
72
49
|
/**
|
|
73
|
-
*
|
|
74
|
-
*
|
|
50
|
+
* Вшитый минимум: собственные правила эксплуатации пакета.
|
|
51
|
+
* Существует только затем, чтобы сервер без сети всё равно мог ответить на вопрос
|
|
52
|
+
* «как безопасно писать в эту CMS». Всё остальное живёт в репозитории знаний.
|
|
75
53
|
*/
|
|
76
|
-
export const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
54
|
+
export const seedPack = (warning) => packFromFiles({
|
|
55
|
+
files: [
|
|
56
|
+
{
|
|
57
|
+
path: 'mcp/operating-rules.md',
|
|
58
|
+
content: readFileSync(resolve(seedDir(), 'operating-rules.md'), 'utf8'),
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
source: 'seed',
|
|
62
|
+
builtAt: new Date().toISOString(),
|
|
63
|
+
...(warning ? { warning } : {}),
|
|
64
|
+
});
|
|
65
|
+
/**
|
|
66
|
+
* Выбирает источник знаний: локальный клон -> GitHub (через кэш) -> вшитый минимум.
|
|
67
|
+
* Недоступный GitHub не мешает серверу подняться: пакет беднеет до вшитого минимума,
|
|
68
|
+
* а причина уезжает в `warning`, потому что сеть — не ошибка конфигурации.
|
|
69
|
+
* Единственное исключение бросается на нечитаемый локальный путь: его оператор указал
|
|
70
|
+
* явно, и молчаливое падение до вшитых правил выглядело бы как пустой корпус.
|
|
71
|
+
*/
|
|
72
|
+
export const resolveKnowledge = async (config) => {
|
|
73
|
+
const builtAt = new Date().toISOString();
|
|
74
|
+
if (config.path) {
|
|
75
|
+
try {
|
|
76
|
+
return packFromFiles({
|
|
77
|
+
files: readLocalTree(config.path),
|
|
78
|
+
source: 'local',
|
|
79
|
+
builtAt,
|
|
80
|
+
repo: config.path,
|
|
81
|
+
});
|
|
89
82
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
chunks.push(...result.chunks);
|
|
83
|
+
catch (error) {
|
|
84
|
+
throw new Error(`Local knowledge path "${config.path}" could not be read (${messageOf(error)}). ` +
|
|
85
|
+
'Fix the path, or unset it to read the knowledge repository from GitHub.');
|
|
94
86
|
}
|
|
95
|
-
};
|
|
96
|
-
add(params.backPath, BACK_SOURCES);
|
|
97
|
-
add(params.frontPath, FRONT_SOURCES);
|
|
98
|
-
return { version: 1, builtAt: params.builtAt, source: params.source, docs, chunks };
|
|
99
|
-
};
|
|
100
|
-
/** Читает собранный снапшот из data/knowledge.json. */
|
|
101
|
-
export const loadSnapshot = () => {
|
|
102
|
-
const file = resolve(dataDir(), 'knowledge.json');
|
|
103
|
-
const parsed = JSON.parse(readFileSync(file, 'utf8'));
|
|
104
|
-
if (parsed.version !== 1) {
|
|
105
|
-
throw new Error(`Unsupported knowledge pack version ${String(parsed.version)}`);
|
|
106
87
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
source:
|
|
120
|
-
builtAt
|
|
88
|
+
try {
|
|
89
|
+
const tree = await fetchKnowledgeTree({
|
|
90
|
+
repo: config.repo,
|
|
91
|
+
ref: config.ref,
|
|
92
|
+
cacheDir: config.cacheDir,
|
|
93
|
+
refreshTtlMs: config.refreshTtlMs,
|
|
94
|
+
offline: config.offline,
|
|
95
|
+
...(config.token ? { token: config.token } : {}),
|
|
96
|
+
timeoutMs: config.timeoutMs,
|
|
97
|
+
});
|
|
98
|
+
return packFromFiles({
|
|
99
|
+
files: tree.files,
|
|
100
|
+
source: tree.source,
|
|
101
|
+
builtAt,
|
|
102
|
+
repo: config.repo,
|
|
103
|
+
ref: config.ref,
|
|
104
|
+
sha: tree.sha,
|
|
121
105
|
});
|
|
122
106
|
}
|
|
123
|
-
|
|
107
|
+
catch (error) {
|
|
108
|
+
return seedPack(`Knowledge repository ${config.repo}@${config.ref} is unavailable (${messageOf(error)}). ` +
|
|
109
|
+
'Only the bundled operating rules are available — module reference docs will not be found.');
|
|
110
|
+
}
|
|
124
111
|
};
|
|
125
112
|
//# sourceMappingURL=loader.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/knowledge/loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/knowledge/loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,6 +10,17 @@ export interface KnowledgeHit {
|
|
|
10
10
|
score: number;
|
|
11
11
|
snippet: string;
|
|
12
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* Выбрасывает из запроса слова короче трёх букв.
|
|
15
|
+
* Заголовок весит вчетверо больше текста, поэтому раздел «Не входит в scope»
|
|
16
|
+
* выигрывал у описания модуля на вопросе «почему атрибут не попал в индекс»:
|
|
17
|
+
* два служебных слова совпадали с заголовком, а значащие — с телом. Предлоги и
|
|
18
|
+
* частицы (`не`, `в`, `на`, `of`, `to`) не несут смысла ни в русском запросе,
|
|
19
|
+
* ни в английском, и участвовать в ранжировании не должны.
|
|
20
|
+
* Если после отбора не осталось ничего, запрос возвращается как есть —
|
|
21
|
+
* поиск по одному короткому слову лучше поиска ни по чему.
|
|
22
|
+
*/
|
|
23
|
+
export declare const meaningfulQuery: (query: string) => string;
|
|
13
24
|
/**
|
|
14
25
|
* Поисковый индекс по разделам документации.
|
|
15
26
|
* Хранит только идентификаторы в индексе, а тексты — в отдельной карте:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/knowledge/search.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE9E,+DAA+D;AAC/D,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAiCD;;;;GAIG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA6B;IAClD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA8B;IACnD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA4B;IACpD,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;gBAEjB,IAAI,EAAE,aAAa;IAkB/B,6EAA6E;IAC7E,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IAI5C,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAI7C,IAAI,IAAI,SAAS,YAAY,EAAE;IAI/B;;;OAGG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,SAAI,GAAG,YAAY,EAAE;CAwBjD"}
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/knowledge/search.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE9E,+DAA+D;AAC/D,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAiCD;;;;;;;;;GASG;AACH,eAAO,MAAM,eAAe,GAAI,OAAO,MAAM,KAAG,MAG/C,CAAC;AAqBF;;;;GAIG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA6B;IAClD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA8B;IACnD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA4B;IACpD,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;gBAEjB,IAAI,EAAE,aAAa;IAkB/B,6EAA6E;IAC7E,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IAI5C,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAI7C,IAAI,IAAI,SAAS,YAAY,EAAE;IAI/B;;;OAGG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,SAAI,GAAG,YAAY,EAAE;CAwBjD"}
|