@oneentry/mcp-platform-server 0.1.0 → 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.
Files changed (113) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +135 -92
  3. package/data/permissions.json +411 -0
  4. package/dist/api/audit.d.ts +0 -11
  5. package/dist/api/audit.js +0 -10
  6. package/dist/api/auth.d.ts +0 -18
  7. package/dist/api/auth.js +0 -20
  8. package/dist/api/build-catalog.d.ts +10 -0
  9. package/dist/api/build-catalog.js +187 -0
  10. package/dist/api/catalog.d.ts +8 -15
  11. package/dist/api/catalog.js +54 -16
  12. package/dist/api/client.d.ts +0 -24
  13. package/dist/api/client.js +6 -28
  14. package/dist/api/normalize-schema.d.ts +3 -0
  15. package/dist/api/normalize-schema.js +133 -0
  16. package/dist/api/policy.d.ts +0 -23
  17. package/dist/api/policy.js +0 -0
  18. package/dist/api/shape.d.ts +0 -13
  19. package/dist/api/shape.js +0 -21
  20. package/dist/api/swagger-source.d.ts +11 -0
  21. package/dist/api/swagger-source.js +58 -0
  22. package/dist/api/types.d.ts +0 -34
  23. package/dist/api/types.js +0 -1
  24. package/dist/bin/cli.d.ts +0 -1
  25. package/dist/bin/cli.js +11 -7
  26. package/dist/config/config.d.ts +66 -46
  27. package/dist/config/config.js +47 -44
  28. package/dist/index.d.ts +9 -7
  29. package/dist/index.js +5 -6
  30. package/dist/knowledge/chunk.d.ts +0 -15
  31. package/dist/knowledge/chunk.js +0 -16
  32. package/dist/knowledge/github.d.ts +21 -0
  33. package/dist/knowledge/github.js +174 -0
  34. package/dist/knowledge/loader.d.ts +23 -24
  35. package/dist/knowledge/loader.js +69 -108
  36. package/dist/knowledge/search.d.ts +1 -12
  37. package/dist/knowledge/search.js +19 -20
  38. package/dist/knowledge/tar.d.ts +7 -0
  39. package/dist/knowledge/tar.js +87 -0
  40. package/dist/knowledge/types.d.ts +8 -22
  41. package/dist/knowledge/types.js +0 -1
  42. package/dist/server.d.ts +1 -12
  43. package/dist/server.js +21 -18
  44. package/dist/session.d.ts +1 -18
  45. package/dist/session.js +3 -13
  46. package/dist/tools/api-call.d.ts +0 -2
  47. package/dist/tools/api-call.js +0 -23
  48. package/dist/tools/api-discovery.d.ts +0 -2
  49. package/dist/tools/api-discovery.js +2 -5
  50. package/dist/tools/docs.d.ts +0 -2
  51. package/dist/tools/docs.js +1 -5
  52. package/dist/tools/guide.d.ts +0 -7
  53. package/dist/tools/guide.js +11 -11
  54. package/dist/tools/result.d.ts +0 -8
  55. package/dist/tools/result.js +0 -7
  56. package/dist/tools/whoami.d.ts +0 -2
  57. package/dist/tools/whoami.js +5 -3
  58. package/dist/transports/http.d.ts +0 -6
  59. package/dist/transports/http.js +17 -18
  60. package/dist/transports/stdio.d.ts +0 -6
  61. package/dist/transports/stdio.js +1 -7
  62. package/knowledge/operating-rules.md +121 -0
  63. package/package.json +20 -7
  64. package/data/catalog.json +0 -1
  65. package/data/knowledge.json +0 -1
  66. package/dist/api/audit.d.ts.map +0 -1
  67. package/dist/api/audit.js.map +0 -1
  68. package/dist/api/auth.d.ts.map +0 -1
  69. package/dist/api/auth.js.map +0 -1
  70. package/dist/api/catalog.d.ts.map +0 -1
  71. package/dist/api/catalog.js.map +0 -1
  72. package/dist/api/client.d.ts.map +0 -1
  73. package/dist/api/client.js.map +0 -1
  74. package/dist/api/policy.d.ts.map +0 -1
  75. package/dist/api/policy.js.map +0 -1
  76. package/dist/api/shape.d.ts.map +0 -1
  77. package/dist/api/shape.js.map +0 -1
  78. package/dist/api/types.d.ts.map +0 -1
  79. package/dist/api/types.js.map +0 -1
  80. package/dist/bin/cli.d.ts.map +0 -1
  81. package/dist/bin/cli.js.map +0 -1
  82. package/dist/config/config.d.ts.map +0 -1
  83. package/dist/config/config.js.map +0 -1
  84. package/dist/index.d.ts.map +0 -1
  85. package/dist/index.js.map +0 -1
  86. package/dist/knowledge/chunk.d.ts.map +0 -1
  87. package/dist/knowledge/chunk.js.map +0 -1
  88. package/dist/knowledge/loader.d.ts.map +0 -1
  89. package/dist/knowledge/loader.js.map +0 -1
  90. package/dist/knowledge/search.d.ts.map +0 -1
  91. package/dist/knowledge/search.js.map +0 -1
  92. package/dist/knowledge/types.d.ts.map +0 -1
  93. package/dist/knowledge/types.js.map +0 -1
  94. package/dist/server.d.ts.map +0 -1
  95. package/dist/server.js.map +0 -1
  96. package/dist/session.d.ts.map +0 -1
  97. package/dist/session.js.map +0 -1
  98. package/dist/tools/api-call.d.ts.map +0 -1
  99. package/dist/tools/api-call.js.map +0 -1
  100. package/dist/tools/api-discovery.d.ts.map +0 -1
  101. package/dist/tools/api-discovery.js.map +0 -1
  102. package/dist/tools/docs.d.ts.map +0 -1
  103. package/dist/tools/docs.js.map +0 -1
  104. package/dist/tools/guide.d.ts.map +0 -1
  105. package/dist/tools/guide.js.map +0 -1
  106. package/dist/tools/result.d.ts.map +0 -1
  107. package/dist/tools/result.js.map +0 -1
  108. package/dist/tools/whoami.d.ts.map +0 -1
  109. package/dist/tools/whoami.js.map +0 -1
  110. package/dist/transports/http.d.ts.map +0 -1
  111. package/dist/transports/http.js.map +0 -1
  112. package/dist/transports/stdio.d.ts.map +0 -1
  113. package/dist/transports/stdio.js.map +0 -1
@@ -1,19 +1,6 @@
1
- /** Результат подготовки ответа к отдаче модели. */
2
1
  export interface ShapedResponse {
3
2
  body: unknown;
4
3
  truncated: boolean;
5
4
  }
6
- /**
7
- * Приводит ответ Admin API к размеру, пригодному для контекста модели.
8
- * Массивы урезаются по элементам (а не обрывом JSON), поэтому результат
9
- * остаётся валидным и самоописанным: агент видит `_truncated` и сужает запрос.
10
- */
11
5
  export declare const shapeResponse: (raw: unknown, maxBytes: number) => ShapedResponse;
12
- /**
13
- * Сжимает текущее состояние цели до размера, который не топит ответ dry-run.
14
- * Целиком отдаётся только небольшая цель: для создания в коллекции «цель» — это весь
15
- * список существующих объектов, а он бывает в сотни килобайт и вытесняет собой
16
- * единственно нужные части плана — политику и собранный запрос.
17
- */
18
6
  export declare const summarizeTarget: (target: unknown) => unknown;
19
- //# sourceMappingURL=shape.d.ts.map
package/dist/api/shape.js CHANGED
@@ -1,12 +1,9 @@
1
- /** Поля, значения которых бесполезны модели и раздувают ответ. */
2
1
  const BLOB_KEYS = new Set(['base64', 'buffer', 'content', 'fileContent', 'data64', 'blob']);
3
2
  const BLOB_VALUE_LIMIT = 512;
4
3
  const isRecord = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
5
- /** Похоже ли строковое значение на base64-блоб, который незачем показывать. */
6
4
  const looksLikeBlob = (key, value) => typeof value === 'string' &&
7
5
  value.length > BLOB_VALUE_LIMIT &&
8
6
  (BLOB_KEYS.has(key) || /^data:|^[A-Za-z0-9+/=]{512,}$/.test(value));
9
- /** Рекурсивно заменяет блобы заглушкой с указанием исходного размера. */
10
7
  const stripBlobs = (value, key = '') => {
11
8
  if (looksLikeBlob(key, value)) {
12
9
  return `[stripped ${String(value.length)} chars]`;
@@ -23,18 +20,12 @@ const stripBlobs = (value, key = '') => {
23
20
  }
24
21
  return value;
25
22
  };
26
- /**
27
- * Приводит ответ Admin API к размеру, пригодному для контекста модели.
28
- * Массивы урезаются по элементам (а не обрывом JSON), поэтому результат
29
- * остаётся валидным и самоописанным: агент видит `_truncated` и сужает запрос.
30
- */
31
23
  export const shapeResponse = (raw, maxBytes) => {
32
24
  const cleaned = stripBlobs(raw);
33
25
  const size = (value) => Buffer.byteLength(JSON.stringify(value) ?? '', 'utf8');
34
26
  if (size(cleaned) <= maxBytes) {
35
27
  return { body: cleaned, truncated: false };
36
28
  }
37
- /** Массив верхнего уровня: оставляем префикс элементов. */
38
29
  if (Array.isArray(cleaned)) {
39
30
  const kept = takePrefix(cleaned, maxBytes);
40
31
  return {
@@ -49,7 +40,6 @@ export const shapeResponse = (raw, maxBytes) => {
49
40
  truncated: true,
50
41
  };
51
42
  }
52
- /** Пагинированный объект: урезаем самый большой массив внутри него. */
53
43
  if (isRecord(cleaned)) {
54
44
  const arrayKey = Object.entries(cleaned)
55
45
  .filter(([, value]) => Array.isArray(value))
@@ -83,11 +73,8 @@ export const shapeResponse = (raw, maxBytes) => {
83
73
  truncated: true,
84
74
  };
85
75
  };
86
- /** Бюджет на показ текущего состояния цели в плане dry-run и в запросе подтверждения. */
87
76
  const TARGET_LIMIT = 4_000;
88
- /** Сколько идентификаторов списка показывать в сводке. */
89
77
  const TARGET_ID_SAMPLE = 20;
90
- /** Собирает опознавательные значения элементов списка: id, если он есть, иначе сам элемент. */
91
78
  const identify = (items) => items.slice(0, TARGET_ID_SAMPLE).map((item) => {
92
79
  if (!isRecord(item)) {
93
80
  return item;
@@ -95,12 +82,6 @@ const identify = (items) => items.slice(0, TARGET_ID_SAMPLE).map((item) => {
95
82
  const id = item['id'] ?? item['identifier'] ?? item['marker'];
96
83
  return id ?? Object.keys(item).slice(0, 3);
97
84
  });
98
- /**
99
- * Сжимает текущее состояние цели до размера, который не топит ответ dry-run.
100
- * Целиком отдаётся только небольшая цель: для создания в коллекции «цель» — это весь
101
- * список существующих объектов, а он бывает в сотни килобайт и вытесняет собой
102
- * единственно нужные части плана — политику и собранный запрос.
103
- */
104
85
  export const summarizeTarget = (target) => {
105
86
  if (target === undefined || target === null) {
106
87
  return null;
@@ -134,7 +115,6 @@ export const summarizeTarget = (target) => {
134
115
  }
135
116
  return { _summary: { kind: 'value', preview: String(target).slice(0, 200), hint } };
136
117
  };
137
- /** Берёт максимальный префикс массива, укладывающийся в бюджет байтов. */
138
118
  const takePrefix = (items, maxBytes) => {
139
119
  const kept = [];
140
120
  let used = 2;
@@ -148,4 +128,3 @@ const takePrefix = (items, maxBytes) => {
148
128
  }
149
129
  return kept;
150
130
  };
151
- //# sourceMappingURL=shape.js.map
@@ -0,0 +1,11 @@
1
+ export interface SwaggerSource {
2
+ baseUrl: string;
3
+ cacheDir: string;
4
+ timeoutMs: number;
5
+ bearer?: string;
6
+ }
7
+ export interface FetchedSwagger {
8
+ raw: string;
9
+ origin: 'instance' | 'cache';
10
+ }
11
+ export declare const fetchSwagger: (source: SwaggerSource) => Promise<FetchedSwagger>;
@@ -0,0 +1,58 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ const SWAGGER_PATH = '/workflows/nodes/admin-api/swagger.json';
5
+ const LANG_CODE = 'en_US';
6
+ const cacheFile = (source) => join(source.cacheDir, 'swagger', `${createHash('sha256').update(source.baseUrl).digest('hex').slice(0, 16)}.json`);
7
+ const readCache = (source) => {
8
+ try {
9
+ return readFileSync(cacheFile(source), 'utf8');
10
+ }
11
+ catch {
12
+ return undefined;
13
+ }
14
+ };
15
+ const writeCache = (source, raw) => {
16
+ const file = cacheFile(source);
17
+ mkdirSync(join(source.cacheDir, 'swagger'), { recursive: true });
18
+ writeFileSync(file, raw);
19
+ };
20
+ export const fetchSwagger = async (source) => {
21
+ const url = `${source.baseUrl}${SWAGGER_PATH}?langCode=${LANG_CODE}`;
22
+ const request = async (bearer) => fetch(url, {
23
+ headers: {
24
+ accept: 'application/json',
25
+ ...(bearer ? { authorization: `Bearer ${bearer}` } : {}),
26
+ },
27
+ signal: AbortSignal.timeout(source.timeoutMs),
28
+ });
29
+ try {
30
+ let response = await request();
31
+ if ((response.status === 401 || response.status === 403) && source.bearer) {
32
+ response = await request(source.bearer);
33
+ }
34
+ if (!response.ok) {
35
+ throw new Error(`${source.baseUrl} answered ${String(response.status)} for ${SWAGGER_PATH}` +
36
+ (response.status === 401 || response.status === 403
37
+ ? ' — the instance requires credentials to read its API document'
38
+ : ''));
39
+ }
40
+ const raw = await response.text();
41
+ const parsed = JSON.parse(raw);
42
+ if (typeof parsed !== 'object' ||
43
+ parsed === null ||
44
+ !('paths' in parsed) ||
45
+ typeof parsed.paths !== 'object') {
46
+ throw new Error(`${source.baseUrl}${SWAGGER_PATH} did not answer with an OpenAPI document`);
47
+ }
48
+ writeCache(source, raw);
49
+ return { raw, origin: 'instance' };
50
+ }
51
+ catch (error) {
52
+ const cached = readCache(source);
53
+ if (cached) {
54
+ return { raw: cached, origin: 'cache' };
55
+ }
56
+ throw error instanceof Error ? error : new Error(String(error));
57
+ }
58
+ };
@@ -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
- /** Собранный каталог: то, что build-catalog.ts пишет в data/catalog.json. */
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
@@ -1,2 +1 @@
1
1
  export {};
2
- //# sourceMappingURL=types.js.map
package/dist/bin/cli.d.ts CHANGED
@@ -1,3 +1,2 @@
1
1
  #!/usr/bin/env node
2
2
  export {};
3
- //# sourceMappingURL=cli.d.ts.map
package/dist/bin/cli.js CHANGED
@@ -11,8 +11,6 @@ Options
11
11
  --base-url <url> Admin API base URL (must contain /api/admin)
12
12
  --allow <level> read (default) | write | destructive
13
13
  --login <login> admin login; the password comes from ONEENTRY_CMS_PASSWORD
14
- --back <path> backend-app checkout: read knowledge live instead of the bundled snapshot
15
- --front <path> frontend-app checkout
16
14
  --audit <path> JSONL audit log (required in remote mode)
17
15
  --http serve Streamable HTTP instead of stdio
18
16
  --port <n> HTTP port, default 8931
@@ -21,9 +19,19 @@ Options
21
19
  --request-timeout <ms> per-request timeout, default 30000
22
20
  --max-response-bytes <n> response cap handed to the model, default 24576
23
21
 
22
+ Knowledge (documentation is fetched from GitHub, not bundled)
23
+ --knowledge-repo <o/n> knowledge repository, default ONEENTRY-PLATFORM/oneentry-platform-rules
24
+ --knowledge-ref <ref> branch, tag or commit, default main
25
+ --knowledge-path <dir> read a local clone instead of GitHub (fast edit loop)
26
+ --knowledge-ttl <ms> how long a cached commit stays fresh, default 3600000
27
+ --cache-dir <path> where the knowledge tree and the API document are cached
28
+ --offline never touch the network: cache and bundled rules only
29
+
24
30
  Environment
25
31
  ONEENTRY_CMS_LOGIN, ONEENTRY_CMS_PASSWORD, ONEENTRY_CMS_TOKEN, ONEENTRY_CMS_BASE_URL, ONEENTRY_MCP_ALLOW,
26
- ONEENTRY_MCP_BACK_PATH, ONEENTRY_MCP_FRONT_PATH, ONEENTRY_MCP_AUDIT_PATH, ONEENTRY_MCP_PORT, ONEENTRY_MCP_HOST
32
+ ONEENTRY_MCP_AUDIT_PATH, ONEENTRY_MCP_PORT, ONEENTRY_MCP_HOST, ONEENTRY_MCP_CACHE_DIR,
33
+ ONEENTRY_MCP_KNOWLEDGE_REPO, ONEENTRY_MCP_KNOWLEDGE_REF, ONEENTRY_MCP_KNOWLEDGE_PATH,
34
+ ONEENTRY_MCP_KNOWLEDGE_TTL_MS, ONEENTRY_MCP_OFFLINE, ONEENTRY_GITHUB_TOKEN
27
35
  `;
28
36
  const main = async () => {
29
37
  const argv = process.argv.slice(2);
@@ -39,10 +47,6 @@ const main = async () => {
39
47
  await runStdio(config);
40
48
  };
41
49
  main().catch((error) => {
42
- /**
43
- * В stdio-режиме stdout занят протоколом, поэтому любая диагностика идёт в stderr.
44
- */
45
50
  process.stderr.write(`oneentry-mcp-platform: ${error instanceof Error ? error.message : String(error)}\n`);
46
51
  process.exitCode = 1;
47
52
  });
48
- //# sourceMappingURL=cli.js.map
@@ -1,45 +1,67 @@
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
- * Полная конфигурация сервера после слияния источников.
16
- * Все дальнейшие слои получают её как зависимость и не читают process.env сами —
17
- * это то, что позволяет держать один и тот же код для local и remote.
18
- */
6
+ export declare const KnowledgeConfigSchema: z.ZodObject<{
7
+ repo: z.ZodString;
8
+ ref: z.ZodString;
9
+ path: z.ZodOptional<z.ZodString>;
10
+ refreshTtlMs: z.ZodNumber;
11
+ offline: z.ZodBoolean;
12
+ token: z.ZodOptional<z.ZodString>;
13
+ }, "strip", z.ZodTypeAny, {
14
+ repo: string;
15
+ ref: string;
16
+ refreshTtlMs: number;
17
+ offline: boolean;
18
+ path?: string | undefined;
19
+ token?: string | undefined;
20
+ }, {
21
+ repo: string;
22
+ ref: string;
23
+ refreshTtlMs: number;
24
+ offline: boolean;
25
+ path?: string | undefined;
26
+ token?: string | undefined;
27
+ }>;
28
+ export type KnowledgeSettings = z.infer<typeof KnowledgeConfigSchema>;
19
29
  export declare const ConfigSchema: z.ZodObject<{
20
30
  mode: z.ZodEnum<["local", "remote"]>;
21
- /** Базовый URL Admin API, всегда с префиксом /api/admin и без завершающего слэша. */
22
31
  baseUrl: z.ZodString;
23
32
  allow: z.ZodEnum<["read", "write", "destructive"]>;
24
- /** Логин/пароль админа. В remote-режиме могут отсутствовать — тогда их даёт сессия. */
25
33
  login: z.ZodOptional<z.ZodString>;
26
34
  password: z.ZodOptional<z.ZodString>;
27
- /** Готовый access-токен вместо логина/пароля. */
28
35
  token: z.ZodOptional<z.ZodString>;
29
- /** Путь к чекауту dnk-back: включает чтение документации «живьём» вместо снапшота. */
30
- backPath: z.ZodOptional<z.ZodString>;
31
- /** Путь к чекауту dnk-front. */
32
- frontPath: z.ZodOptional<z.ZodString>;
33
- /** Файл JSONL-аудита. В remote-режиме обязателен. */
36
+ knowledge: z.ZodObject<{
37
+ repo: z.ZodString;
38
+ ref: z.ZodString;
39
+ path: z.ZodOptional<z.ZodString>;
40
+ refreshTtlMs: z.ZodNumber;
41
+ offline: z.ZodBoolean;
42
+ token: z.ZodOptional<z.ZodString>;
43
+ }, "strip", z.ZodTypeAny, {
44
+ repo: string;
45
+ ref: string;
46
+ refreshTtlMs: number;
47
+ offline: boolean;
48
+ path?: string | undefined;
49
+ token?: string | undefined;
50
+ }, {
51
+ repo: string;
52
+ ref: string;
53
+ refreshTtlMs: number;
54
+ offline: boolean;
55
+ path?: string | undefined;
56
+ token?: string | undefined;
57
+ }>;
58
+ cacheDir: z.ZodString;
34
59
  auditPath: z.ZodOptional<z.ZodString>;
35
- /** Таймаут одного запроса к Admin API, мс. */
36
60
  requestTimeoutMs: z.ZodNumber;
37
- /** Максимальный размер сериализованного ответа, отдаваемого модели, в байтах. */
38
61
  maxResponseBytes: z.ZodNumber;
39
62
  http: z.ZodObject<{
40
63
  port: z.ZodNumber;
41
64
  host: z.ZodString;
42
- /** Разрешённые Origin для remote-режима. Пустой список = принимать только запросы без Origin. */
43
65
  allowedOrigins: z.ZodArray<z.ZodString, "many">;
44
66
  }, "strip", z.ZodTypeAny, {
45
67
  port: number;
@@ -54,6 +76,15 @@ export declare const ConfigSchema: z.ZodObject<{
54
76
  mode: "local" | "remote";
55
77
  baseUrl: string;
56
78
  allow: "read" | "write" | "destructive";
79
+ knowledge: {
80
+ repo: string;
81
+ ref: string;
82
+ refreshTtlMs: number;
83
+ offline: boolean;
84
+ path?: string | undefined;
85
+ token?: string | undefined;
86
+ };
87
+ cacheDir: string;
57
88
  requestTimeoutMs: number;
58
89
  maxResponseBytes: number;
59
90
  http: {
@@ -61,16 +92,23 @@ export declare const ConfigSchema: z.ZodObject<{
61
92
  host: string;
62
93
  allowedOrigins: string[];
63
94
  };
95
+ token?: string | undefined;
64
96
  login?: string | undefined;
65
97
  password?: string | undefined;
66
- token?: string | undefined;
67
- backPath?: string | undefined;
68
- frontPath?: string | undefined;
69
98
  auditPath?: string | undefined;
70
99
  }, {
71
100
  mode: "local" | "remote";
72
101
  baseUrl: string;
73
102
  allow: "read" | "write" | "destructive";
103
+ knowledge: {
104
+ repo: string;
105
+ ref: string;
106
+ refreshTtlMs: number;
107
+ offline: boolean;
108
+ path?: string | undefined;
109
+ token?: string | undefined;
110
+ };
111
+ cacheDir: string;
74
112
  requestTimeoutMs: number;
75
113
  maxResponseBytes: number;
76
114
  http: {
@@ -78,31 +116,13 @@ export declare const ConfigSchema: z.ZodObject<{
78
116
  host: string;
79
117
  allowedOrigins: string[];
80
118
  };
119
+ token?: string | undefined;
81
120
  login?: string | undefined;
82
121
  password?: string | undefined;
83
- token?: string | undefined;
84
- backPath?: string | undefined;
85
- frontPath?: string | undefined;
86
122
  auditPath?: string | undefined;
87
123
  }>;
88
124
  export type Config = z.infer<typeof ConfigSchema>;
89
- /** Разобранные аргументы командной строки. */
90
125
  export type CliFlags = Record<string, string | boolean>;
91
- /**
92
- * Минимальный разбор argv: поддерживаются `--flag`, `--key=value` и `--key value`.
93
- * Своя реализация вместо зависимости — набор флагов маленький и стабильный.
94
- */
95
126
  export declare const parseFlags: (argv: readonly string[]) => CliFlags;
96
- /**
97
- * Нормализует базовый URL: убирает завершающий слэш и требует префикс Admin API.
98
- * Сервер работает только с админским API — это гарантия, а не соглашение,
99
- * поэтому проверка живёт здесь, а не в клиенте.
100
- */
101
127
  export declare const normalizeBaseUrl: (raw: string) => string;
102
- /**
103
- * Собирает конфигурацию по приоритету: флаги > переменные окружения > ./oneentry-mcp-platform.json > дефолты.
104
- * Валидация одна и та же для обоих режимов; отличается только то, что в remote-режиме
105
- * обязателен путь аудита, а документация всегда берётся из снапшота.
106
- */
107
128
  export declare const loadConfig: (argv: readonly string[], env?: NodeJS.ProcessEnv, cwd?: string) => Config;
108
- //# sourceMappingURL=config.d.ts.map
@@ -1,45 +1,32 @@
1
1
  import { readFileSync } from 'node:fs';
2
+ import { homedir } from 'node:os';
2
3
  import { resolve } from 'node:path';
3
4
  import { z } from 'zod';
4
- /**
5
- * Уровень разрешённых операций.
6
- * Читаем по умолчанию: агент не может ничего испортить, пока человек явно не разрешил.
7
- */
8
5
  export const AllowLevelSchema = z.enum(['read', 'write', 'destructive']);
9
- /**
10
- * Режим работы сервера. Определяется транспортом, а не отдельным флагом:
11
- * stdio -> local (агент и CMS на одной машине), streamable HTTP -> remote (сервис).
12
- */
13
6
  export const ServerModeSchema = z.enum(['local', 'remote']);
14
- /**
15
- * Полная конфигурация сервера после слияния источников.
16
- * Все дальнейшие слои получают её как зависимость и не читают process.env сами —
17
- * это то, что позволяет держать один и тот же код для local и remote.
18
- */
7
+ export const KnowledgeConfigSchema = z.object({
8
+ repo: z.string().regex(/^[\w.-]+\/[\w.-]+$/, 'knowledge repo must look like "owner/name"'),
9
+ ref: z.string().min(1),
10
+ path: z.string().optional(),
11
+ refreshTtlMs: z.number().int().nonnegative(),
12
+ offline: z.boolean(),
13
+ token: z.string().min(1).optional(),
14
+ });
19
15
  export const ConfigSchema = z.object({
20
16
  mode: ServerModeSchema,
21
- /** Базовый URL Admin API, всегда с префиксом /api/admin и без завершающего слэша. */
22
17
  baseUrl: z.string().url(),
23
18
  allow: AllowLevelSchema,
24
- /** Логин/пароль админа. В remote-режиме могут отсутствовать — тогда их даёт сессия. */
25
19
  login: z.string().min(1).optional(),
26
20
  password: z.string().min(1).optional(),
27
- /** Готовый access-токен вместо логина/пароля. */
28
21
  token: z.string().min(1).optional(),
29
- /** Путь к чекауту dnk-back: включает чтение документации «живьём» вместо снапшота. */
30
- backPath: z.string().optional(),
31
- /** Путь к чекауту dnk-front. */
32
- frontPath: z.string().optional(),
33
- /** Файл JSONL-аудита. В remote-режиме обязателен. */
22
+ knowledge: KnowledgeConfigSchema,
23
+ cacheDir: z.string().min(1),
34
24
  auditPath: z.string().optional(),
35
- /** Таймаут одного запроса к Admin API, мс. */
36
25
  requestTimeoutMs: z.number().int().positive(),
37
- /** Максимальный размер сериализованного ответа, отдаваемого модели, в байтах. */
38
26
  maxResponseBytes: z.number().int().positive(),
39
27
  http: z.object({
40
28
  port: z.number().int().min(1).max(65535),
41
29
  host: z.string().min(1),
42
- /** Разрешённые Origin для remote-режима. Пустой список = принимать только запросы без Origin. */
43
30
  allowedOrigins: z.array(z.string()),
44
31
  }),
45
32
  });
@@ -50,11 +37,10 @@ const DEFAULTS = {
50
37
  maxResponseBytes: 24_576,
51
38
  httpPort: 8931,
52
39
  httpHost: '127.0.0.1',
40
+ knowledgeRepo: 'ONEENTRY-PLATFORM/oneentry-platform-rules',
41
+ knowledgeRef: 'main',
42
+ knowledgeTtlMs: 3_600_000,
53
43
  };
54
- /**
55
- * Минимальный разбор argv: поддерживаются `--flag`, `--key=value` и `--key value`.
56
- * Своя реализация вместо зависимости — набор флагов маленький и стабильный.
57
- */
58
44
  export const parseFlags = (argv) => {
59
45
  const flags = {};
60
46
  for (let i = 0; i < argv.length; i++) {
@@ -80,6 +66,19 @@ export const parseFlags = (argv) => {
80
66
  return flags;
81
67
  };
82
68
  const asString = (value) => typeof value === 'string' && value.length > 0 ? value : undefined;
69
+ const asBoolean = (value, fallback) => {
70
+ if (value === undefined) {
71
+ return fallback;
72
+ }
73
+ if (typeof value === 'boolean') {
74
+ return value;
75
+ }
76
+ return ['1', 'true', 'yes', 'on'].includes(value.trim().toLowerCase());
77
+ };
78
+ const defaultCacheDir = (env) => {
79
+ const xdg = asString(env['XDG_CACHE_HOME']);
80
+ return resolve(xdg ?? resolve(homedir(), '.cache'), 'oneentry-mcp-platform');
81
+ };
83
82
  const asNumber = (value, fallback) => {
84
83
  if (value === undefined) {
85
84
  return fallback;
@@ -90,11 +89,6 @@ const asNumber = (value, fallback) => {
90
89
  }
91
90
  return parsed;
92
91
  };
93
- /**
94
- * Нормализует базовый URL: убирает завершающий слэш и требует префикс Admin API.
95
- * Сервер работает только с админским API — это гарантия, а не соглашение,
96
- * поэтому проверка живёт здесь, а не в клиенте.
97
- */
98
92
  export const normalizeBaseUrl = (raw) => {
99
93
  const trimmed = raw.replace(/\/+$/, '');
100
94
  if (!trimmed.includes('/api/admin')) {
@@ -119,11 +113,6 @@ const readConfigFile = (cwd) => {
119
113
  throw error;
120
114
  }
121
115
  };
122
- /**
123
- * Собирает конфигурацию по приоритету: флаги > переменные окружения > ./oneentry-mcp-platform.json > дефолты.
124
- * Валидация одна и та же для обоих режимов; отличается только то, что в remote-режиме
125
- * обязателен путь аудита, а документация всегда берётся из снапшота.
126
- */
127
116
  export const loadConfig = (argv, env = process.env, cwd = process.cwd()) => {
128
117
  const flags = parseFlags(argv);
129
118
  const file = readConfigFile(cwd);
@@ -132,6 +121,15 @@ export const loadConfig = (argv, env = process.env, cwd = process.cwd()) => {
132
121
  return typeof value === 'string' && value.length > 0 ? value : undefined;
133
122
  };
134
123
  const pick = (flagKey, envKey, fileKey) => asString(flags[flagKey]) ?? asString(env[envKey]) ?? fileString(fileKey);
124
+ const fileKnowledge = file['knowledge'];
125
+ const knowledgeFile = (key) => {
126
+ if (typeof fileKnowledge !== 'object' || fileKnowledge === null || Array.isArray(fileKnowledge)) {
127
+ return undefined;
128
+ }
129
+ const value = fileKnowledge[key];
130
+ return typeof value === 'string' && value.length > 0 ? value : undefined;
131
+ };
132
+ const pickKnowledge = (flagKey, envKey, fileKey) => asString(flags[flagKey]) ?? asString(env[envKey]) ?? knowledgeFile(fileKey);
135
133
  const mode = flags['http'] === true || asString(flags['http']) ? 'remote' : 'local';
136
134
  const originsRaw = pick('allowed-origins', 'ONEENTRY_MCP_ALLOWED_ORIGINS', 'allowedOrigins');
137
135
  const candidate = {
@@ -141,8 +139,17 @@ export const loadConfig = (argv, env = process.env, cwd = process.cwd()) => {
141
139
  login: pick('login', 'ONEENTRY_CMS_LOGIN', 'login'),
142
140
  password: asString(env['ONEENTRY_CMS_PASSWORD']) ?? fileString('password'),
143
141
  token: asString(env['ONEENTRY_CMS_TOKEN']) ?? fileString('token'),
144
- backPath: pick('back', 'ONEENTRY_MCP_BACK_PATH', 'backPath'),
145
- frontPath: pick('front', 'ONEENTRY_MCP_FRONT_PATH', 'frontPath'),
142
+ knowledge: {
143
+ repo: pickKnowledge('knowledge-repo', 'ONEENTRY_MCP_KNOWLEDGE_REPO', 'repo') ??
144
+ DEFAULTS.knowledgeRepo,
145
+ ref: pickKnowledge('knowledge-ref', 'ONEENTRY_MCP_KNOWLEDGE_REF', 'ref') ??
146
+ DEFAULTS.knowledgeRef,
147
+ path: pickKnowledge('knowledge-path', 'ONEENTRY_MCP_KNOWLEDGE_PATH', 'path'),
148
+ refreshTtlMs: asNumber(pickKnowledge('knowledge-ttl', 'ONEENTRY_MCP_KNOWLEDGE_TTL_MS', 'refreshTtlMs'), DEFAULTS.knowledgeTtlMs),
149
+ offline: asBoolean(flags['offline'] ?? env['ONEENTRY_MCP_OFFLINE'], false),
150
+ token: asString(env['ONEENTRY_GITHUB_TOKEN']),
151
+ },
152
+ cacheDir: pick('cache-dir', 'ONEENTRY_MCP_CACHE_DIR', 'cacheDir') ?? defaultCacheDir(env),
146
153
  auditPath: pick('audit', 'ONEENTRY_MCP_AUDIT_PATH', 'auditPath'),
147
154
  requestTimeoutMs: asNumber(pick('request-timeout', 'ONEENTRY_MCP_REQUEST_TIMEOUT_MS', 'requestTimeoutMs'), DEFAULTS.requestTimeoutMs),
148
155
  maxResponseBytes: asNumber(pick('max-response-bytes', 'ONEENTRY_MCP_MAX_RESPONSE_BYTES', 'maxResponseBytes'), DEFAULTS.maxResponseBytes),
@@ -153,9 +160,6 @@ export const loadConfig = (argv, env = process.env, cwd = process.cwd()) => {
153
160
  },
154
161
  };
155
162
  const config = ConfigSchema.parse(candidate);
156
- /**
157
- * Пароль через флаг не принимаем ни в каком режиме: argv видно в списке процессов.
158
- */
159
163
  if (asString(flags['password'])) {
160
164
  throw new Error('Refusing --password: pass ONEENTRY_CMS_PASSWORD via the environment instead.');
161
165
  }
@@ -164,4 +168,3 @@ export const loadConfig = (argv, env = process.env, cwd = process.cwd()) => {
164
168
  }
165
169
  return config;
166
170
  };
167
- //# 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';
@@ -15,9 +11,15 @@ export { shapeResponse } from './api/shape.js';
15
11
  export { AuditLog } from './api/audit.js';
16
12
  export { TokenStore, AuthError } from './api/auth.js';
17
13
  export { KnowledgeIndex } from './knowledge/search.js';
18
- export { buildPack, loadSnapshot, resolveKnowledge } from './knowledge/loader.js';
14
+ export { packFromFiles, resolveKnowledge, seedPack } from './knowledge/loader.js';
15
+ export type { KnowledgeConfig } from './knowledge/loader.js';
16
+ export { fetchKnowledgeTree, readLocalTree } from './knowledge/github.js';
17
+ export type { KnowledgeFile, KnowledgeSource, KnowledgeTree } from './knowledge/github.js';
18
+ export { readTar, readTarGz } from './knowledge/tar.js';
19
+ export { buildCatalog } from './api/build-catalog.js';
20
+ export type { PermissionMap } from './api/build-catalog.js';
21
+ export { fetchSwagger } from './api/swagger-source.js';
19
22
  export { runStdio } from './transports/stdio.js';
20
23
  export { runHttp } from './transports/http.js';
21
24
  export type { Catalog, Operation, JsonSchema, RiskLevel } from './api/types.js';
22
- export type { KnowledgeChunk, KnowledgeDoc, KnowledgePack } from './knowledge/types.js';
23
- //# sourceMappingURL=index.d.ts.map
25
+ export type { KnowledgeChunk, KnowledgeDoc, KnowledgeOrigin, KnowledgePack, } from './knowledge/types.js';