@oneentry/mcp-platform-server 0.1.1 → 0.1.3
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/LICENSE +21 -0
- package/README.md +62 -61
- package/dist/api/audit.d.ts +0 -11
- package/dist/api/audit.js +0 -10
- package/dist/api/auth.d.ts +0 -18
- package/dist/api/auth.js +0 -20
- package/dist/api/build-catalog.d.ts +0 -14
- package/dist/api/build-catalog.js +7 -77
- package/dist/api/catalog.d.ts +0 -26
- package/dist/api/catalog.js +3 -30
- package/dist/api/client.d.ts +0 -24
- package/dist/api/client.js +6 -28
- package/dist/api/normalize-schema.d.ts +0 -11
- package/dist/api/normalize-schema.js +0 -18
- package/dist/api/policy.d.ts +0 -23
- package/dist/api/policy.js +0 -0
- package/dist/api/shape.d.ts +0 -13
- package/dist/api/shape.js +0 -21
- package/dist/api/swagger-source.d.ts +1 -12
- package/dist/api/swagger-source.js +2 -20
- package/dist/api/types.d.ts +0 -34
- package/dist/api/types.js +0 -1
- package/dist/bin/cli.d.ts +0 -1
- package/dist/bin/cli.js +1 -5
- package/dist/config/config.d.ts +0 -54
- package/dist/config/config.js +0 -60
- package/dist/index.d.ts +0 -5
- package/dist/index.js +0 -5
- package/dist/knowledge/chunk.d.ts +0 -15
- package/dist/knowledge/chunk.js +0 -16
- package/dist/knowledge/github.d.ts +0 -25
- package/dist/knowledge/github.js +0 -40
- package/dist/knowledge/loader.d.ts +0 -28
- package/dist/knowledge/loader.js +0 -26
- package/dist/knowledge/search.d.ts +0 -22
- package/dist/knowledge/search.js +0 -34
- package/dist/knowledge/tar.d.ts +0 -15
- package/dist/knowledge/tar.js +0 -33
- package/dist/knowledge/types.d.ts +0 -35
- package/dist/knowledge/types.js +0 -1
- package/dist/server.d.ts +0 -12
- package/dist/server.js +10 -14
- package/dist/session.d.ts +0 -23
- package/dist/session.js +0 -18
- package/dist/tools/api-call.d.ts +0 -2
- package/dist/tools/api-call.js +0 -23
- package/dist/tools/api-discovery.d.ts +0 -2
- package/dist/tools/api-discovery.js +2 -5
- package/dist/tools/docs.d.ts +0 -2
- package/dist/tools/docs.js +1 -5
- package/dist/tools/guide.d.ts +0 -7
- package/dist/tools/guide.js +2 -9
- package/dist/tools/result.d.ts +0 -8
- package/dist/tools/result.js +0 -7
- package/dist/tools/whoami.d.ts +0 -2
- package/dist/tools/whoami.js +1 -3
- package/dist/transports/http.d.ts +0 -6
- package/dist/transports/http.js +0 -26
- package/dist/transports/stdio.d.ts +0 -6
- package/dist/transports/stdio.js +0 -6
- package/knowledge/operating-rules.md +70 -125
- package/package.json +18 -5
- package/dist/api/audit.d.ts.map +0 -1
- package/dist/api/audit.js.map +0 -1
- package/dist/api/auth.d.ts.map +0 -1
- package/dist/api/auth.js.map +0 -1
- package/dist/api/build-catalog.d.ts.map +0 -1
- package/dist/api/build-catalog.js.map +0 -1
- package/dist/api/catalog.d.ts.map +0 -1
- package/dist/api/catalog.js.map +0 -1
- package/dist/api/client.d.ts.map +0 -1
- package/dist/api/client.js.map +0 -1
- package/dist/api/normalize-schema.d.ts.map +0 -1
- package/dist/api/normalize-schema.js.map +0 -1
- package/dist/api/policy.d.ts.map +0 -1
- package/dist/api/policy.js.map +0 -1
- package/dist/api/shape.d.ts.map +0 -1
- package/dist/api/shape.js.map +0 -1
- package/dist/api/swagger-source.d.ts.map +0 -1
- package/dist/api/swagger-source.js.map +0 -1
- package/dist/api/types.d.ts.map +0 -1
- package/dist/api/types.js.map +0 -1
- package/dist/bin/cli.d.ts.map +0 -1
- package/dist/bin/cli.js.map +0 -1
- package/dist/config/config.d.ts.map +0 -1
- package/dist/config/config.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/knowledge/chunk.d.ts.map +0 -1
- package/dist/knowledge/chunk.js.map +0 -1
- package/dist/knowledge/github.d.ts.map +0 -1
- package/dist/knowledge/github.js.map +0 -1
- package/dist/knowledge/loader.d.ts.map +0 -1
- package/dist/knowledge/loader.js.map +0 -1
- package/dist/knowledge/search.d.ts.map +0 -1
- package/dist/knowledge/search.js.map +0 -1
- package/dist/knowledge/tar.d.ts.map +0 -1
- package/dist/knowledge/tar.js.map +0 -1
- package/dist/knowledge/types.d.ts.map +0 -1
- package/dist/knowledge/types.js.map +0 -1
- package/dist/server.d.ts.map +0 -1
- package/dist/server.js.map +0 -1
- package/dist/session.d.ts.map +0 -1
- package/dist/session.js.map +0 -1
- package/dist/tools/api-call.d.ts.map +0 -1
- package/dist/tools/api-call.js.map +0 -1
- package/dist/tools/api-discovery.d.ts.map +0 -1
- package/dist/tools/api-discovery.js.map +0 -1
- package/dist/tools/docs.d.ts.map +0 -1
- package/dist/tools/docs.js.map +0 -1
- package/dist/tools/guide.d.ts.map +0 -1
- package/dist/tools/guide.js.map +0 -1
- package/dist/tools/result.d.ts.map +0 -1
- package/dist/tools/result.js.map +0 -1
- package/dist/tools/whoami.d.ts.map +0 -1
- package/dist/tools/whoami.js.map +0 -1
- package/dist/transports/http.d.ts.map +0 -1
- package/dist/transports/http.js.map +0 -1
- package/dist/transports/stdio.d.ts.map +0 -1
- package/dist/transports/stdio.js.map +0 -1
package/dist/api/types.d.ts
CHANGED
|
@@ -1,25 +1,13 @@
|
|
|
1
|
-
/** HTTP-методы, встречающиеся в Admin API. */
|
|
2
1
|
export type HttpMethod = 'get' | 'post' | 'put' | 'patch' | 'delete';
|
|
3
|
-
/**
|
|
4
|
-
* Класс риска операции. Определяется на сборке каталога, а не в рантайме,
|
|
5
|
-
* чтобы политику доступа нельзя было обойти хитрым аргументом.
|
|
6
|
-
*/
|
|
7
2
|
export type RiskLevel = 'read' | 'write' | 'destructive';
|
|
8
|
-
/** Параметр операции (path / query / header). */
|
|
9
3
|
export interface OperationParam {
|
|
10
4
|
name: string;
|
|
11
5
|
location: 'path' | 'query' | 'header';
|
|
12
6
|
required: boolean;
|
|
13
7
|
description?: string;
|
|
14
|
-
/** Нормализованная JSON-схема параметра. */
|
|
15
8
|
schema: JsonSchema;
|
|
16
9
|
example?: unknown;
|
|
17
10
|
}
|
|
18
|
-
/**
|
|
19
|
-
* Нормализованная JSON-схема. Swagger проекта содержит 311 TypeScript-подобных
|
|
20
|
-
* значений `type` (`Record<string, any>`, `CommonLocalizeInfos`, `image`…),
|
|
21
|
-
* поэтому «схема» здесь — результат приведения, а не исходник.
|
|
22
|
-
*/
|
|
23
11
|
export interface JsonSchema {
|
|
24
12
|
type?: string;
|
|
25
13
|
format?: string;
|
|
@@ -29,28 +17,19 @@ export interface JsonSchema {
|
|
|
29
17
|
items?: JsonSchema;
|
|
30
18
|
properties?: Record<string, JsonSchema>;
|
|
31
19
|
required?: string[];
|
|
32
|
-
/** Тип не удалось привести к JSON Schema: доверять следует `example`. */
|
|
33
20
|
'x-loose'?: boolean;
|
|
34
|
-
/** Исходный TypeScript-подобный тип из swagger — сохранён как подсказка. */
|
|
35
21
|
'x-source-type'?: string;
|
|
36
|
-
/** Схема была урезана по размеру. */
|
|
37
22
|
'x-truncated'?: boolean;
|
|
38
23
|
}
|
|
39
|
-
/** Одна операция Admin API в каталоге. */
|
|
40
24
|
export interface Operation {
|
|
41
|
-
/** `operationId` из swagger, например `AdminPagesController_findAllRoot`. */
|
|
42
25
|
opId: string;
|
|
43
26
|
method: HttpMethod;
|
|
44
|
-
/** Путь без префикса API, например `/pages/{id}`. */
|
|
45
27
|
path: string;
|
|
46
|
-
/** Полный путь как в swagger, например `/api/admin/pages/{id}`. */
|
|
47
28
|
fullPath: string;
|
|
48
29
|
tag: string;
|
|
49
30
|
summary: string;
|
|
50
|
-
/** Требуемое право из `AdminPermissionsEnum`, если объявлено в контроллере. */
|
|
51
31
|
permission?: string;
|
|
52
32
|
risk: RiskLevel;
|
|
53
|
-
/** Операция навсегда остаётся за подтверждением, независимо от уровня allow. */
|
|
54
33
|
alwaysConfirm: boolean;
|
|
55
34
|
params: OperationParam[];
|
|
56
35
|
body?: {
|
|
@@ -59,27 +38,14 @@ export interface Operation {
|
|
|
59
38
|
required: boolean;
|
|
60
39
|
};
|
|
61
40
|
responseSummary?: string;
|
|
62
|
-
/** Идентификаторы разделов документации (`<docId>#<anchor>`), объясняющих операцию. */
|
|
63
|
-
docLinks: string[];
|
|
64
|
-
/** Склеенный текст для поиска по каталогу. */
|
|
65
41
|
searchText: string;
|
|
66
42
|
}
|
|
67
|
-
/** Собранный каталог: результат `buildCatalog` — swagger стенда плюс карта прав. */
|
|
68
43
|
export interface Catalog {
|
|
69
44
|
version: 1;
|
|
70
45
|
builtAt: string;
|
|
71
|
-
/** Префикс путей из swagger (`/api/admin`) — проверяется при сборке. */
|
|
72
46
|
apiPrefix: string;
|
|
73
|
-
/** Хэш исходного swagger.json — виден в cms_whoami, ловит рассинхрон. */
|
|
74
47
|
swaggerHash: string;
|
|
75
|
-
/** Полный список значений `AdminPermissionsEnum`. */
|
|
76
48
|
permissions: string[];
|
|
77
|
-
/**
|
|
78
|
-
* Замечания сборки — прежде всего признаки устаревшего swagger.json.
|
|
79
|
-
* Показываются в `cms_whoami`: рассинхрон каталога и реального API должен быть
|
|
80
|
-
* виден агенту, а не выясняться по 404.
|
|
81
|
-
*/
|
|
82
49
|
warnings: string[];
|
|
83
50
|
operations: Operation[];
|
|
84
51
|
}
|
|
85
|
-
//# sourceMappingURL=types.d.ts.map
|
package/dist/api/types.js
CHANGED
package/dist/bin/cli.d.ts
CHANGED
package/dist/bin/cli.js
CHANGED
|
@@ -24,7 +24,7 @@ Knowledge (documentation is fetched from GitHub, not bundled)
|
|
|
24
24
|
--knowledge-ref <ref> branch, tag or commit, default main
|
|
25
25
|
--knowledge-path <dir> read a local clone instead of GitHub (fast edit loop)
|
|
26
26
|
--knowledge-ttl <ms> how long a cached commit stays fresh, default 3600000
|
|
27
|
-
--cache-dir <path> where the knowledge tree and the
|
|
27
|
+
--cache-dir <path> where the knowledge tree and the API document are cached
|
|
28
28
|
--offline never touch the network: cache and bundled rules only
|
|
29
29
|
|
|
30
30
|
Environment
|
|
@@ -47,10 +47,6 @@ const main = async () => {
|
|
|
47
47
|
await runStdio(config);
|
|
48
48
|
};
|
|
49
49
|
main().catch((error) => {
|
|
50
|
-
/**
|
|
51
|
-
* В stdio-режиме stdout занят протоколом, поэтому любая диагностика идёт в stderr.
|
|
52
|
-
*/
|
|
53
50
|
process.stderr.write(`oneentry-mcp-platform: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
54
51
|
process.exitCode = 1;
|
|
55
52
|
});
|
|
56
|
-
//# sourceMappingURL=cli.js.map
|
package/dist/config/config.d.ts
CHANGED
|
@@ -1,33 +1,14 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
/**
|
|
3
|
-
* Уровень разрешённых операций.
|
|
4
|
-
* Читаем по умолчанию: агент не может ничего испортить, пока человек явно не разрешил.
|
|
5
|
-
*/
|
|
6
2
|
export declare const AllowLevelSchema: z.ZodEnum<["read", "write", "destructive"]>;
|
|
7
3
|
export type AllowLevel = z.infer<typeof AllowLevelSchema>;
|
|
8
|
-
/**
|
|
9
|
-
* Режим работы сервера. Определяется транспортом, а не отдельным флагом:
|
|
10
|
-
* stdio -> local (агент и CMS на одной машине), streamable HTTP -> remote (сервис).
|
|
11
|
-
*/
|
|
12
4
|
export declare const ServerModeSchema: z.ZodEnum<["local", "remote"]>;
|
|
13
5
|
export type ServerMode = z.infer<typeof ServerModeSchema>;
|
|
14
|
-
/**
|
|
15
|
-
* Откуда брать документацию. Знания живут в отдельном публичном репозитории GitHub
|
|
16
|
-
* и скачиваются в рантайме, а не вшиваются в пакет: иначе правка одной строки
|
|
17
|
-
* документации требовала бы перевыпуска npm-пакета.
|
|
18
|
-
*/
|
|
19
6
|
export declare const KnowledgeConfigSchema: z.ZodObject<{
|
|
20
|
-
/** `owner/name` репозитория знаний. */
|
|
21
7
|
repo: z.ZodString;
|
|
22
|
-
/** Ветка, тег или коммит. Пин на тег — способ зафиксировать знания для стенда. */
|
|
23
8
|
ref: z.ZodString;
|
|
24
|
-
/** Локальный клон репозитория знаний: читать его вместо сети. */
|
|
25
9
|
path: z.ZodOptional<z.ZodString>;
|
|
26
|
-
/** Сколько считать закэшированный коммит свежим, не спрашивая GitHub. */
|
|
27
10
|
refreshTtlMs: z.ZodNumber;
|
|
28
|
-
/** Не ходить в сеть: только кэш и вшитые правила. */
|
|
29
11
|
offline: z.ZodBoolean;
|
|
30
|
-
/** Токен GitHub — только чтобы поднять лимит API. Репозиторий публичный. */
|
|
31
12
|
token: z.ZodOptional<z.ZodString>;
|
|
32
13
|
}, "strip", z.ZodTypeAny, {
|
|
33
14
|
repo: string;
|
|
@@ -45,33 +26,19 @@ export declare const KnowledgeConfigSchema: z.ZodObject<{
|
|
|
45
26
|
token?: string | undefined;
|
|
46
27
|
}>;
|
|
47
28
|
export type KnowledgeSettings = z.infer<typeof KnowledgeConfigSchema>;
|
|
48
|
-
/**
|
|
49
|
-
* Полная конфигурация сервера после слияния источников.
|
|
50
|
-
* Все дальнейшие слои получают её как зависимость и не читают process.env сами —
|
|
51
|
-
* это то, что позволяет держать один и тот же код для local и remote.
|
|
52
|
-
*/
|
|
53
29
|
export declare const ConfigSchema: z.ZodObject<{
|
|
54
30
|
mode: z.ZodEnum<["local", "remote"]>;
|
|
55
|
-
/** Базовый URL Admin API, всегда с префиксом /api/admin и без завершающего слэша. */
|
|
56
31
|
baseUrl: z.ZodString;
|
|
57
32
|
allow: z.ZodEnum<["read", "write", "destructive"]>;
|
|
58
|
-
/** Логин/пароль админа. В remote-режиме могут отсутствовать — тогда их даёт сессия. */
|
|
59
33
|
login: z.ZodOptional<z.ZodString>;
|
|
60
34
|
password: z.ZodOptional<z.ZodString>;
|
|
61
|
-
/** Готовый access-токен вместо логина/пароля. */
|
|
62
35
|
token: z.ZodOptional<z.ZodString>;
|
|
63
36
|
knowledge: z.ZodObject<{
|
|
64
|
-
/** `owner/name` репозитория знаний. */
|
|
65
37
|
repo: z.ZodString;
|
|
66
|
-
/** Ветка, тег или коммит. Пин на тег — способ зафиксировать знания для стенда. */
|
|
67
38
|
ref: z.ZodString;
|
|
68
|
-
/** Локальный клон репозитория знаний: читать его вместо сети. */
|
|
69
39
|
path: z.ZodOptional<z.ZodString>;
|
|
70
|
-
/** Сколько считать закэшированный коммит свежим, не спрашивая GitHub. */
|
|
71
40
|
refreshTtlMs: z.ZodNumber;
|
|
72
|
-
/** Не ходить в сеть: только кэш и вшитые правила. */
|
|
73
41
|
offline: z.ZodBoolean;
|
|
74
|
-
/** Токен GitHub — только чтобы поднять лимит API. Репозиторий публичный. */
|
|
75
42
|
token: z.ZodOptional<z.ZodString>;
|
|
76
43
|
}, "strip", z.ZodTypeAny, {
|
|
77
44
|
repo: string;
|
|
@@ -88,18 +55,13 @@ export declare const ConfigSchema: z.ZodObject<{
|
|
|
88
55
|
path?: string | undefined;
|
|
89
56
|
token?: string | undefined;
|
|
90
57
|
}>;
|
|
91
|
-
/** Каталог кэша: распакованный репозиторий знаний и снимок swagger стенда. */
|
|
92
58
|
cacheDir: z.ZodString;
|
|
93
|
-
/** Файл JSONL-аудита. В remote-режиме обязателен. */
|
|
94
59
|
auditPath: z.ZodOptional<z.ZodString>;
|
|
95
|
-
/** Таймаут одного запроса к Admin API, мс. */
|
|
96
60
|
requestTimeoutMs: z.ZodNumber;
|
|
97
|
-
/** Максимальный размер сериализованного ответа, отдаваемого модели, в байтах. */
|
|
98
61
|
maxResponseBytes: z.ZodNumber;
|
|
99
62
|
http: z.ZodObject<{
|
|
100
63
|
port: z.ZodNumber;
|
|
101
64
|
host: z.ZodString;
|
|
102
|
-
/** Разрешённые Origin для remote-режима. Пустой список = принимать только запросы без Origin. */
|
|
103
65
|
allowedOrigins: z.ZodArray<z.ZodString, "many">;
|
|
104
66
|
}, "strip", z.ZodTypeAny, {
|
|
105
67
|
port: number;
|
|
@@ -160,23 +122,7 @@ export declare const ConfigSchema: z.ZodObject<{
|
|
|
160
122
|
auditPath?: string | undefined;
|
|
161
123
|
}>;
|
|
162
124
|
export type Config = z.infer<typeof ConfigSchema>;
|
|
163
|
-
/** Разобранные аргументы командной строки. */
|
|
164
125
|
export type CliFlags = Record<string, string | boolean>;
|
|
165
|
-
/**
|
|
166
|
-
* Минимальный разбор argv: поддерживаются `--flag`, `--key=value` и `--key value`.
|
|
167
|
-
* Своя реализация вместо зависимости — набор флагов маленький и стабильный.
|
|
168
|
-
*/
|
|
169
126
|
export declare const parseFlags: (argv: readonly string[]) => CliFlags;
|
|
170
|
-
/**
|
|
171
|
-
* Нормализует базовый URL: убирает завершающий слэш и требует префикс Admin API.
|
|
172
|
-
* Сервер работает только с админским API — это гарантия, а не соглашение,
|
|
173
|
-
* поэтому проверка живёт здесь, а не в клиенте.
|
|
174
|
-
*/
|
|
175
127
|
export declare const normalizeBaseUrl: (raw: string) => string;
|
|
176
|
-
/**
|
|
177
|
-
* Собирает конфигурацию по приоритету: флаги > переменные окружения > ./oneentry-mcp-platform.json > дефолты.
|
|
178
|
-
* Валидация одна и та же для обоих режимов; отличается только то, что в remote-режиме
|
|
179
|
-
* обязателен путь аудита, а документация всегда берётся из снапшота.
|
|
180
|
-
*/
|
|
181
128
|
export declare const loadConfig: (argv: readonly string[], env?: NodeJS.ProcessEnv, cwd?: string) => Config;
|
|
182
|
-
//# sourceMappingURL=config.d.ts.map
|
package/dist/config/config.js
CHANGED
|
@@ -2,63 +2,31 @@ import { readFileSync } from 'node:fs';
|
|
|
2
2
|
import { homedir } from 'node:os';
|
|
3
3
|
import { resolve } from 'node:path';
|
|
4
4
|
import { z } from 'zod';
|
|
5
|
-
/**
|
|
6
|
-
* Уровень разрешённых операций.
|
|
7
|
-
* Читаем по умолчанию: агент не может ничего испортить, пока человек явно не разрешил.
|
|
8
|
-
*/
|
|
9
5
|
export const AllowLevelSchema = z.enum(['read', 'write', 'destructive']);
|
|
10
|
-
/**
|
|
11
|
-
* Режим работы сервера. Определяется транспортом, а не отдельным флагом:
|
|
12
|
-
* stdio -> local (агент и CMS на одной машине), streamable HTTP -> remote (сервис).
|
|
13
|
-
*/
|
|
14
6
|
export const ServerModeSchema = z.enum(['local', 'remote']);
|
|
15
|
-
/**
|
|
16
|
-
* Откуда брать документацию. Знания живут в отдельном публичном репозитории GitHub
|
|
17
|
-
* и скачиваются в рантайме, а не вшиваются в пакет: иначе правка одной строки
|
|
18
|
-
* документации требовала бы перевыпуска npm-пакета.
|
|
19
|
-
*/
|
|
20
7
|
export const KnowledgeConfigSchema = z.object({
|
|
21
|
-
/** `owner/name` репозитория знаний. */
|
|
22
8
|
repo: z.string().regex(/^[\w.-]+\/[\w.-]+$/, 'knowledge repo must look like "owner/name"'),
|
|
23
|
-
/** Ветка, тег или коммит. Пин на тег — способ зафиксировать знания для стенда. */
|
|
24
9
|
ref: z.string().min(1),
|
|
25
|
-
/** Локальный клон репозитория знаний: читать его вместо сети. */
|
|
26
10
|
path: z.string().optional(),
|
|
27
|
-
/** Сколько считать закэшированный коммит свежим, не спрашивая GitHub. */
|
|
28
11
|
refreshTtlMs: z.number().int().nonnegative(),
|
|
29
|
-
/** Не ходить в сеть: только кэш и вшитые правила. */
|
|
30
12
|
offline: z.boolean(),
|
|
31
|
-
/** Токен GitHub — только чтобы поднять лимит API. Репозиторий публичный. */
|
|
32
13
|
token: z.string().min(1).optional(),
|
|
33
14
|
});
|
|
34
|
-
/**
|
|
35
|
-
* Полная конфигурация сервера после слияния источников.
|
|
36
|
-
* Все дальнейшие слои получают её как зависимость и не читают process.env сами —
|
|
37
|
-
* это то, что позволяет держать один и тот же код для local и remote.
|
|
38
|
-
*/
|
|
39
15
|
export const ConfigSchema = z.object({
|
|
40
16
|
mode: ServerModeSchema,
|
|
41
|
-
/** Базовый URL Admin API, всегда с префиксом /api/admin и без завершающего слэша. */
|
|
42
17
|
baseUrl: z.string().url(),
|
|
43
18
|
allow: AllowLevelSchema,
|
|
44
|
-
/** Логин/пароль админа. В remote-режиме могут отсутствовать — тогда их даёт сессия. */
|
|
45
19
|
login: z.string().min(1).optional(),
|
|
46
20
|
password: z.string().min(1).optional(),
|
|
47
|
-
/** Готовый access-токен вместо логина/пароля. */
|
|
48
21
|
token: z.string().min(1).optional(),
|
|
49
22
|
knowledge: KnowledgeConfigSchema,
|
|
50
|
-
/** Каталог кэша: распакованный репозиторий знаний и снимок swagger стенда. */
|
|
51
23
|
cacheDir: z.string().min(1),
|
|
52
|
-
/** Файл JSONL-аудита. В remote-режиме обязателен. */
|
|
53
24
|
auditPath: z.string().optional(),
|
|
54
|
-
/** Таймаут одного запроса к Admin API, мс. */
|
|
55
25
|
requestTimeoutMs: z.number().int().positive(),
|
|
56
|
-
/** Максимальный размер сериализованного ответа, отдаваемого модели, в байтах. */
|
|
57
26
|
maxResponseBytes: z.number().int().positive(),
|
|
58
27
|
http: z.object({
|
|
59
28
|
port: z.number().int().min(1).max(65535),
|
|
60
29
|
host: z.string().min(1),
|
|
61
|
-
/** Разрешённые Origin для remote-режима. Пустой список = принимать только запросы без Origin. */
|
|
62
30
|
allowedOrigins: z.array(z.string()),
|
|
63
31
|
}),
|
|
64
32
|
});
|
|
@@ -71,13 +39,8 @@ const DEFAULTS = {
|
|
|
71
39
|
httpHost: '127.0.0.1',
|
|
72
40
|
knowledgeRepo: 'ONEENTRY-PLATFORM/oneentry-platform-rules',
|
|
73
41
|
knowledgeRef: 'main',
|
|
74
|
-
/** Час: достаточно редко, чтобы цикл перезапусков не упирался в лимит API GitHub. */
|
|
75
42
|
knowledgeTtlMs: 3_600_000,
|
|
76
43
|
};
|
|
77
|
-
/**
|
|
78
|
-
* Минимальный разбор argv: поддерживаются `--flag`, `--key=value` и `--key value`.
|
|
79
|
-
* Своя реализация вместо зависимости — набор флагов маленький и стабильный.
|
|
80
|
-
*/
|
|
81
44
|
export const parseFlags = (argv) => {
|
|
82
45
|
const flags = {};
|
|
83
46
|
for (let i = 0; i < argv.length; i++) {
|
|
@@ -103,10 +66,6 @@ export const parseFlags = (argv) => {
|
|
|
103
66
|
return flags;
|
|
104
67
|
};
|
|
105
68
|
const asString = (value) => typeof value === 'string' && value.length > 0 ? value : undefined;
|
|
106
|
-
/**
|
|
107
|
-
* Булев флаг из трёх источников. Голый `--offline` — это `true`, поэтому
|
|
108
|
-
* значение флага может быть и строкой, и признаком присутствия.
|
|
109
|
-
*/
|
|
110
69
|
const asBoolean = (value, fallback) => {
|
|
111
70
|
if (value === undefined) {
|
|
112
71
|
return fallback;
|
|
@@ -116,10 +75,6 @@ const asBoolean = (value, fallback) => {
|
|
|
116
75
|
}
|
|
117
76
|
return ['1', 'true', 'yes', 'on'].includes(value.trim().toLowerCase());
|
|
118
77
|
};
|
|
119
|
-
/**
|
|
120
|
-
* Каталог кэша по умолчанию: XDG, с откатом на `~/.cache`.
|
|
121
|
-
* Кэш обязан пережить перезапуск процесса, поэтому временный каталог не годится.
|
|
122
|
-
*/
|
|
123
78
|
const defaultCacheDir = (env) => {
|
|
124
79
|
const xdg = asString(env['XDG_CACHE_HOME']);
|
|
125
80
|
return resolve(xdg ?? resolve(homedir(), '.cache'), 'oneentry-mcp-platform');
|
|
@@ -134,11 +89,6 @@ const asNumber = (value, fallback) => {
|
|
|
134
89
|
}
|
|
135
90
|
return parsed;
|
|
136
91
|
};
|
|
137
|
-
/**
|
|
138
|
-
* Нормализует базовый URL: убирает завершающий слэш и требует префикс Admin API.
|
|
139
|
-
* Сервер работает только с админским API — это гарантия, а не соглашение,
|
|
140
|
-
* поэтому проверка живёт здесь, а не в клиенте.
|
|
141
|
-
*/
|
|
142
92
|
export const normalizeBaseUrl = (raw) => {
|
|
143
93
|
const trimmed = raw.replace(/\/+$/, '');
|
|
144
94
|
if (!trimmed.includes('/api/admin')) {
|
|
@@ -163,11 +113,6 @@ const readConfigFile = (cwd) => {
|
|
|
163
113
|
throw error;
|
|
164
114
|
}
|
|
165
115
|
};
|
|
166
|
-
/**
|
|
167
|
-
* Собирает конфигурацию по приоритету: флаги > переменные окружения > ./oneentry-mcp-platform.json > дефолты.
|
|
168
|
-
* Валидация одна и та же для обоих режимов; отличается только то, что в remote-режиме
|
|
169
|
-
* обязателен путь аудита, а документация всегда берётся из снапшота.
|
|
170
|
-
*/
|
|
171
116
|
export const loadConfig = (argv, env = process.env, cwd = process.cwd()) => {
|
|
172
117
|
const flags = parseFlags(argv);
|
|
173
118
|
const file = readConfigFile(cwd);
|
|
@@ -202,7 +147,6 @@ export const loadConfig = (argv, env = process.env, cwd = process.cwd()) => {
|
|
|
202
147
|
path: pickKnowledge('knowledge-path', 'ONEENTRY_MCP_KNOWLEDGE_PATH', 'path'),
|
|
203
148
|
refreshTtlMs: asNumber(pickKnowledge('knowledge-ttl', 'ONEENTRY_MCP_KNOWLEDGE_TTL_MS', 'refreshTtlMs'), DEFAULTS.knowledgeTtlMs),
|
|
204
149
|
offline: asBoolean(flags['offline'] ?? env['ONEENTRY_MCP_OFFLINE'], false),
|
|
205
|
-
/** Только из окружения: секрет не должен попадать ни в argv, ни в файл конфигурации. */
|
|
206
150
|
token: asString(env['ONEENTRY_GITHUB_TOKEN']),
|
|
207
151
|
},
|
|
208
152
|
cacheDir: pick('cache-dir', 'ONEENTRY_MCP_CACHE_DIR', 'cacheDir') ?? defaultCacheDir(env),
|
|
@@ -216,9 +160,6 @@ export const loadConfig = (argv, env = process.env, cwd = process.cwd()) => {
|
|
|
216
160
|
},
|
|
217
161
|
};
|
|
218
162
|
const config = ConfigSchema.parse(candidate);
|
|
219
|
-
/**
|
|
220
|
-
* Пароль через флаг не принимаем ни в каком режиме: argv видно в списке процессов.
|
|
221
|
-
*/
|
|
222
163
|
if (asString(flags['password'])) {
|
|
223
164
|
throw new Error('Refusing --password: pass ONEENTRY_CMS_PASSWORD via the environment instead.');
|
|
224
165
|
}
|
|
@@ -227,4 +168,3 @@ export const loadConfig = (argv, env = process.env, cwd = process.cwd()) => {
|
|
|
227
168
|
}
|
|
228
169
|
return config;
|
|
229
170
|
};
|
|
230
|
-
//# sourceMappingURL=config.js.map
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Публичный API пакета: всё, что нужно, чтобы встроить сервер в свой процесс
|
|
3
|
-
* или собрать его иначе, чем это делает CLI.
|
|
4
|
-
*/
|
|
5
1
|
export { loadConfig, parseFlags, normalizeBaseUrl, ConfigSchema } from './config/config.js';
|
|
6
2
|
export type { Config, AllowLevel, ServerMode } from './config/config.js';
|
|
7
3
|
export { createServer, createSharedDeps } from './server.js';
|
|
@@ -27,4 +23,3 @@ export { runStdio } from './transports/stdio.js';
|
|
|
27
23
|
export { runHttp } from './transports/http.js';
|
|
28
24
|
export type { Catalog, Operation, JsonSchema, RiskLevel } from './api/types.js';
|
|
29
25
|
export type { KnowledgeChunk, KnowledgeDoc, KnowledgeOrigin, KnowledgePack, } from './knowledge/types.js';
|
|
30
|
-
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Публичный API пакета: всё, что нужно, чтобы встроить сервер в свой процесс
|
|
3
|
-
* или собрать его иначе, чем это делает CLI.
|
|
4
|
-
*/
|
|
5
1
|
export { loadConfig, parseFlags, normalizeBaseUrl, ConfigSchema } from './config/config.js';
|
|
6
2
|
export { createServer, createSharedDeps } from './server.js';
|
|
7
3
|
export { Session } from './session.js';
|
|
@@ -19,4 +15,3 @@ export { buildCatalog } from './api/build-catalog.js';
|
|
|
19
15
|
export { fetchSwagger } from './api/swagger-source.js';
|
|
20
16
|
export { runStdio } from './transports/stdio.js';
|
|
21
17
|
export { runHttp } from './transports/http.js';
|
|
22
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1,27 +1,13 @@
|
|
|
1
1
|
import type { KnowledgeChunk, KnowledgeDoc } from './types.js';
|
|
2
|
-
/**
|
|
3
|
-
* Слаг заголовка в стиле GitHub: нижний регистр, пробелы в дефисы,
|
|
4
|
-
* пунктуация выброшена. Кириллица сохраняется — документация в проекте русскоязычная.
|
|
5
|
-
*/
|
|
6
2
|
export declare const slugify: (heading: string) => string;
|
|
7
3
|
interface Section {
|
|
8
4
|
title: string;
|
|
9
5
|
lines: string[];
|
|
10
6
|
}
|
|
11
|
-
/**
|
|
12
|
-
* Режет markdown по заголовкам `##` и `###`.
|
|
13
|
-
* Преамбула до первого `##` становится разделом с пустым anchor — в ней обычно
|
|
14
|
-
* лежит самое важное описание модуля, терять его нельзя.
|
|
15
|
-
*/
|
|
16
7
|
export declare const splitSections: (markdown: string) => {
|
|
17
8
|
docTitle: string;
|
|
18
9
|
sections: Section[];
|
|
19
10
|
};
|
|
20
|
-
/**
|
|
21
|
-
* Превращает один markdown-файл в документ + его разделы.
|
|
22
|
-
* Anchor'ы дедуплицируются суффиксом, иначе два одинаковых `## Схема`
|
|
23
|
-
* в одном файле стали бы неразличимы для cms_docs_read.
|
|
24
|
-
*/
|
|
25
11
|
export declare const chunkDocument: (params: {
|
|
26
12
|
docId: string;
|
|
27
13
|
repo: KnowledgeChunk["repo"];
|
|
@@ -32,4 +18,3 @@ export declare const chunkDocument: (params: {
|
|
|
32
18
|
chunks: KnowledgeChunk[];
|
|
33
19
|
};
|
|
34
20
|
export {};
|
|
35
|
-
//# sourceMappingURL=chunk.d.ts.map
|
package/dist/knowledge/chunk.js
CHANGED
|
@@ -1,20 +1,10 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Слаг заголовка в стиле GitHub: нижний регистр, пробелы в дефисы,
|
|
3
|
-
* пунктуация выброшена. Кириллица сохраняется — документация в проекте русскоязычная.
|
|
4
|
-
*/
|
|
5
1
|
export const slugify = (heading) => heading
|
|
6
2
|
.toLowerCase()
|
|
7
3
|
.replace(/`|\*|_|\[|\]|\(|\)|:|,|\.|\/|\\|«|»|"|'|\?|!|;/g, '')
|
|
8
4
|
.trim()
|
|
9
5
|
.replace(/\s+/g, '-')
|
|
10
6
|
.slice(0, 80);
|
|
11
|
-
/** Строки внутри огороженных блоков кода не считаются заголовками. */
|
|
12
7
|
const isFence = (line) => line.startsWith('```') || line.startsWith('~~~');
|
|
13
|
-
/**
|
|
14
|
-
* Режет markdown по заголовкам `##` и `###`.
|
|
15
|
-
* Преамбула до первого `##` становится разделом с пустым anchor — в ней обычно
|
|
16
|
-
* лежит самое важное описание модуля, терять его нельзя.
|
|
17
|
-
*/
|
|
18
8
|
export const splitSections = (markdown) => {
|
|
19
9
|
const lines = markdown.split('\n');
|
|
20
10
|
let docTitle = '';
|
|
@@ -43,11 +33,6 @@ export const splitSections = (markdown) => {
|
|
|
43
33
|
sections: sections.filter((s) => s.title !== '' || s.lines.join('').trim() !== ''),
|
|
44
34
|
};
|
|
45
35
|
};
|
|
46
|
-
/**
|
|
47
|
-
* Превращает один markdown-файл в документ + его разделы.
|
|
48
|
-
* Anchor'ы дедуплицируются суффиксом, иначе два одинаковых `## Схема`
|
|
49
|
-
* в одном файле стали бы неразличимы для cms_docs_read.
|
|
50
|
-
*/
|
|
51
36
|
export const chunkDocument = (params) => {
|
|
52
37
|
const { docTitle, sections } = splitSections(params.markdown);
|
|
53
38
|
const seen = new Map();
|
|
@@ -84,4 +69,3 @@ export const chunkDocument = (params) => {
|
|
|
84
69
|
chunks,
|
|
85
70
|
};
|
|
86
71
|
};
|
|
87
|
-
//# sourceMappingURL=chunk.js.map
|
|
@@ -1,46 +1,21 @@
|
|
|
1
|
-
/** Откуда и как забирать репозиторий знаний. */
|
|
2
1
|
export interface KnowledgeSource {
|
|
3
|
-
/** `owner/name` публичного репозитория GitHub. */
|
|
4
2
|
repo: string;
|
|
5
|
-
/** Ветка, тег или sha. */
|
|
6
3
|
ref: string;
|
|
7
4
|
cacheDir: string;
|
|
8
|
-
/** Как долго считать закэшированный sha свежим, не спрашивая GitHub. */
|
|
9
5
|
refreshTtlMs: number;
|
|
10
|
-
/** Не ходить в сеть вовсе: только кэш. */
|
|
11
6
|
offline: boolean;
|
|
12
|
-
/** Токен GitHub — только чтобы поднять лимит API; репозиторий публичный. */
|
|
13
7
|
token?: string;
|
|
14
8
|
timeoutMs: number;
|
|
15
9
|
}
|
|
16
|
-
/** Файл документации, вынутый из репозитория. */
|
|
17
10
|
export interface KnowledgeFile {
|
|
18
|
-
/** Путь относительно каталога `knowledge/`, например `back/docs/menus-module.md`. */
|
|
19
11
|
path: string;
|
|
20
12
|
content: string;
|
|
21
13
|
}
|
|
22
|
-
/** Результат получения дерева знаний. */
|
|
23
14
|
export interface KnowledgeTree {
|
|
24
15
|
files: KnowledgeFile[];
|
|
25
16
|
sha: string;
|
|
26
|
-
/** `github` — только что скачано, `cache` — взято с диска. */
|
|
27
17
|
source: 'github' | 'cache';
|
|
28
18
|
}
|
|
29
|
-
/** Рекурсивно собирает `*.md` каталога. Используется и кэшем, и локальным клоном. */
|
|
30
19
|
export declare const walkMarkdown: (root: string) => string[];
|
|
31
|
-
/**
|
|
32
|
-
* Отдаёт дерево знаний, предпочитая кэш.
|
|
33
|
-
* Порядок такой: свежий кэш -> сверка sha -> скачивание. Пока запись кэша моложе
|
|
34
|
-
* `refreshTtlMs`, сеть не трогается вообще — иначе цикл перезапусков сервера
|
|
35
|
-
* упирался бы в лимит анонимного API GitHub.
|
|
36
|
-
* Бросает исключение, если знания взять неоткуда; решение о запасном варианте
|
|
37
|
-
* принимает вызывающий.
|
|
38
|
-
*/
|
|
39
20
|
export declare const fetchKnowledgeTree: (source: KnowledgeSource) => Promise<KnowledgeTree>;
|
|
40
|
-
/**
|
|
41
|
-
* Читает знания из локального клона репозитория.
|
|
42
|
-
* Принимает и корень клона, и сам каталог `knowledge/` — путать их слишком легко,
|
|
43
|
-
* а разница видна по наличию подкаталога.
|
|
44
|
-
*/
|
|
45
21
|
export declare const readLocalTree: (path: string) => KnowledgeFile[];
|
|
46
|
-
//# sourceMappingURL=github.d.ts.map
|
package/dist/knowledge/github.js
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import { dirname, join, relative, resolve, sep } from 'node:path';
|
|
3
3
|
import { readTarGz } from './tar.js';
|
|
4
|
-
/** Каталог внутри репозитория, в котором лежит документация. */
|
|
5
4
|
const ROOT = 'knowledge';
|
|
6
5
|
const isRecord = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
7
|
-
/** Каталог кэша одного репозитория. Слэш в имени заменён, чтобы это был один уровень. */
|
|
8
6
|
const repoCacheDir = (source) => resolve(source.cacheDir, source.repo.replace('/', '--'));
|
|
9
7
|
const stateFile = (source) => join(repoCacheDir(source), 'current.json');
|
|
10
8
|
const readState = (source) => {
|
|
@@ -26,7 +24,6 @@ const writeState = (source, state) => {
|
|
|
26
24
|
mkdirSync(repoCacheDir(source), { recursive: true });
|
|
27
25
|
writeFileSync(stateFile(source), `${JSON.stringify(state)}\n`);
|
|
28
26
|
};
|
|
29
|
-
/** Рекурсивно собирает `*.md` каталога. Используется и кэшем, и локальным клоном. */
|
|
30
27
|
export const walkMarkdown = (root) => {
|
|
31
28
|
const out = [];
|
|
32
29
|
const visit = (dir) => {
|
|
@@ -52,7 +49,6 @@ const exists = (path) => {
|
|
|
52
49
|
return false;
|
|
53
50
|
}
|
|
54
51
|
};
|
|
55
|
-
/** Читает распакованное дерево из кэша. */
|
|
56
52
|
const readCached = (source, sha) => {
|
|
57
53
|
const dir = join(repoCacheDir(source), sha, ROOT);
|
|
58
54
|
if (!exists(dir)) {
|
|
@@ -63,11 +59,6 @@ const readCached = (source, sha) => {
|
|
|
63
59
|
content: readFileSync(file, 'utf8'),
|
|
64
60
|
}));
|
|
65
61
|
};
|
|
66
|
-
/**
|
|
67
|
-
* Записывает дерево в кэш и удаляет каталоги остальных sha.
|
|
68
|
-
* Кэш адресуется коммитом, поэтому старые версии не нужны никогда:
|
|
69
|
-
* запись неизменяема, и «протухнуть» она не может.
|
|
70
|
-
*/
|
|
71
62
|
const writeCache = (source, sha, files) => {
|
|
72
63
|
const base = repoCacheDir(source);
|
|
73
64
|
const target = join(base, sha, ROOT);
|
|
@@ -87,11 +78,6 @@ const headers = (source, accept) => ({
|
|
|
87
78
|
'user-agent': 'oneentry-mcp-platform',
|
|
88
79
|
...(source.token ? { authorization: `Bearer ${source.token}` } : {}),
|
|
89
80
|
});
|
|
90
|
-
/**
|
|
91
|
-
* Расшифровывает код ответа GitHub в причину, по которой ref не превратился в коммит.
|
|
92
|
-
* Голый статус здесь бесполезен: 404 и 409 — это разные ошибки настройки, и обе
|
|
93
|
-
* встречаются при первом подключении к новому репозиторию знаний.
|
|
94
|
-
*/
|
|
95
81
|
const shaFailureHint = (status) => {
|
|
96
82
|
switch (status) {
|
|
97
83
|
case 403: {
|
|
@@ -108,10 +94,6 @@ const shaFailureHint = (status) => {
|
|
|
108
94
|
}
|
|
109
95
|
}
|
|
110
96
|
};
|
|
111
|
-
/**
|
|
112
|
-
* Превращает ref в конкретный коммит. Ответ — голый sha, поэтому запрос дешёвый:
|
|
113
|
-
* его можно делать при каждом запуске, не скачивая архив.
|
|
114
|
-
*/
|
|
115
97
|
const resolveSha = async (source) => {
|
|
116
98
|
const url = `https://api.github.com/repos/${source.repo}/commits/${encodeURIComponent(source.ref)}`;
|
|
117
99
|
const response = await fetch(url, {
|
|
@@ -128,11 +110,6 @@ const resolveSha = async (source) => {
|
|
|
128
110
|
}
|
|
129
111
|
return sha;
|
|
130
112
|
};
|
|
131
|
-
/**
|
|
132
|
-
* Отбирает из архива только документацию.
|
|
133
|
-
* Всё, что вне `knowledge/`, и любой путь с `..` отбрасываются: архив приходит
|
|
134
|
-
* из сети, и он не должен решать, куда мы пишем.
|
|
135
|
-
*/
|
|
136
113
|
const selectDocs = (entries) => {
|
|
137
114
|
const prefix = `${ROOT}/`;
|
|
138
115
|
return entries
|
|
@@ -141,7 +118,6 @@ const selectDocs = (entries) => {
|
|
|
141
118
|
!entry.path.split('/').includes('..'))
|
|
142
119
|
.map((entry) => ({ path: entry.path.slice(prefix.length), content: entry.content }));
|
|
143
120
|
};
|
|
144
|
-
/** Скачивает архив репозитория на конкретном коммите. Один запрос, лимитов API нет. */
|
|
145
121
|
const download = async (source, sha) => {
|
|
146
122
|
const url = `https://codeload.github.com/${source.repo}/tar.gz/${sha}`;
|
|
147
123
|
const response = await fetch(url, {
|
|
@@ -157,18 +133,9 @@ const download = async (source, sha) => {
|
|
|
157
133
|
}
|
|
158
134
|
return files;
|
|
159
135
|
};
|
|
160
|
-
/**
|
|
161
|
-
* Отдаёт дерево знаний, предпочитая кэш.
|
|
162
|
-
* Порядок такой: свежий кэш -> сверка sha -> скачивание. Пока запись кэша моложе
|
|
163
|
-
* `refreshTtlMs`, сеть не трогается вообще — иначе цикл перезапусков сервера
|
|
164
|
-
* упирался бы в лимит анонимного API GitHub.
|
|
165
|
-
* Бросает исключение, если знания взять неоткуда; решение о запасном варианте
|
|
166
|
-
* принимает вызывающий.
|
|
167
|
-
*/
|
|
168
136
|
export const fetchKnowledgeTree = async (source) => {
|
|
169
137
|
const state = readState(source);
|
|
170
138
|
const files = state && state.ref === source.ref ? readCached(source, state.sha) : undefined;
|
|
171
|
-
/** Кэш годен только целиком: и запись о коммите, и распакованное дерево. */
|
|
172
139
|
const cache = state && files ? { state, files } : undefined;
|
|
173
140
|
if (cache && (source.offline || Date.now() - cache.state.checkedAt < source.refreshTtlMs)) {
|
|
174
141
|
return { files: cache.files, sha: cache.state.sha, source: 'cache' };
|
|
@@ -182,7 +149,6 @@ export const fetchKnowledgeTree = async (source) => {
|
|
|
182
149
|
}
|
|
183
150
|
catch (error) {
|
|
184
151
|
if (cache) {
|
|
185
|
-
/** Сеть недоступна, но кэш есть — работаем на нём, это не отказ. */
|
|
186
152
|
return { files: cache.files, sha: cache.state.sha, source: 'cache' };
|
|
187
153
|
}
|
|
188
154
|
throw error;
|
|
@@ -196,11 +162,6 @@ export const fetchKnowledgeTree = async (source) => {
|
|
|
196
162
|
writeState(source, { ref: source.ref, sha, checkedAt: Date.now() });
|
|
197
163
|
return { files: downloaded, sha, source: 'github' };
|
|
198
164
|
};
|
|
199
|
-
/**
|
|
200
|
-
* Читает знания из локального клона репозитория.
|
|
201
|
-
* Принимает и корень клона, и сам каталог `knowledge/` — путать их слишком легко,
|
|
202
|
-
* а разница видна по наличию подкаталога.
|
|
203
|
-
*/
|
|
204
165
|
export const readLocalTree = (path) => {
|
|
205
166
|
const root = exists(join(path, ROOT)) ? join(path, ROOT) : path;
|
|
206
167
|
if (!exists(root)) {
|
|
@@ -211,4 +172,3 @@ export const readLocalTree = (path) => {
|
|
|
211
172
|
content: readFileSync(file, 'utf8'),
|
|
212
173
|
}));
|
|
213
174
|
};
|
|
214
|
-
//# sourceMappingURL=github.js.map
|