@fractalizer/mcp-cli 0.3.18 → 1.0.0
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 +158 -266
- package/dist/commands/connect.command.d.ts +18 -15
- package/dist/commands/connect.command.d.ts.map +1 -1
- package/dist/commands/connect.command.js +66 -40
- package/dist/commands/connect.command.js.map +1 -1
- package/dist/commands/disconnect.command.d.ts +5 -17
- package/dist/commands/disconnect.command.d.ts.map +1 -1
- package/dist/commands/disconnect.command.js +4 -15
- package/dist/commands/disconnect.command.js.map +1 -1
- package/dist/commands/doctor.command.d.ts +34 -0
- package/dist/commands/doctor.command.d.ts.map +1 -0
- package/dist/commands/doctor.command.js +321 -0
- package/dist/commands/doctor.command.js.map +1 -0
- package/dist/commands/index.d.ts +1 -0
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +2 -0
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/list.command.d.ts +4 -9
- package/dist/commands/list.command.d.ts.map +1 -1
- package/dist/commands/list.command.js +1 -5
- package/dist/commands/list.command.js.map +1 -1
- package/dist/commands/status.command.d.ts +6 -13
- package/dist/commands/status.command.d.ts.map +1 -1
- package/dist/commands/status.command.js +15 -12
- package/dist/commands/status.command.js.map +1 -1
- package/dist/commands/validate.command.d.ts +6 -11
- package/dist/commands/validate.command.d.ts.map +1 -1
- package/dist/commands/validate.command.js +15 -19
- package/dist/commands/validate.command.js.map +1 -1
- package/dist/connectors/base/base-connector.d.ts +31 -55
- package/dist/connectors/base/base-connector.d.ts.map +1 -1
- package/dist/connectors/base/base-connector.js +71 -57
- package/dist/connectors/base/base-connector.js.map +1 -1
- package/dist/connectors/base/configurable-connector.d.ts +89 -24
- package/dist/connectors/base/configurable-connector.d.ts.map +1 -1
- package/dist/connectors/base/configurable-connector.js +266 -23
- package/dist/connectors/base/configurable-connector.js.map +1 -1
- package/dist/connectors/base/connector.interface.d.ts +29 -20
- package/dist/connectors/base/connector.interface.d.ts.map +1 -1
- package/dist/connectors/base/index.d.ts +0 -1
- package/dist/connectors/base/index.d.ts.map +1 -1
- package/dist/connectors/base/index.js +0 -1
- package/dist/connectors/base/index.js.map +1 -1
- package/dist/connectors/claude-code/claude-code.connector.d.ts +100 -21
- package/dist/connectors/claude-code/claude-code.connector.d.ts.map +1 -1
- package/dist/connectors/claude-code/claude-code.connector.js +221 -40
- package/dist/connectors/claude-code/claude-code.connector.js.map +1 -1
- package/dist/connectors/connector-factory.d.ts +15 -15
- package/dist/connectors/connector-factory.d.ts.map +1 -1
- package/dist/connectors/connector-factory.js +61 -18
- package/dist/connectors/connector-factory.js.map +1 -1
- package/dist/connectors/index.d.ts +0 -4
- package/dist/connectors/index.d.ts.map +1 -1
- package/dist/connectors/index.js +2 -8
- package/dist/connectors/index.js.map +1 -1
- package/dist/connectors/registry.d.ts +20 -27
- package/dist/connectors/registry.d.ts.map +1 -1
- package/dist/connectors/registry.js +34 -34
- package/dist/connectors/registry.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/{base.types.d.ts → client.types.d.ts} +30 -30
- package/dist/types/client.types.d.ts.map +1 -0
- package/dist/types/client.types.js +6 -0
- package/dist/types/client.types.js.map +1 -0
- package/dist/types/doctor.types.d.ts +91 -0
- package/dist/types/doctor.types.d.ts.map +1 -0
- package/dist/types/doctor.types.js +12 -0
- package/dist/types/doctor.types.js.map +1 -0
- package/dist/types/launch.types.d.ts +59 -0
- package/dist/types/launch.types.d.ts.map +1 -0
- package/dist/types/launch.types.js +6 -0
- package/dist/types/launch.types.js.map +1 -0
- package/dist/types.d.ts +23 -14
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +9 -2
- package/dist/types.js.map +1 -1
- package/dist/utils/command-executor.d.ts +39 -3
- package/dist/utils/command-executor.d.ts.map +1 -1
- package/dist/utils/command-executor.js +95 -8
- package/dist/utils/command-executor.js.map +1 -1
- package/dist/utils/config-manager.d.ts +25 -42
- package/dist/utils/config-manager.d.ts.map +1 -1
- package/dist/utils/config-manager.js +21 -49
- package/dist/utils/config-manager.js.map +1 -1
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/interactive-prompter.d.ts +16 -64
- package/dist/utils/interactive-prompter.d.ts.map +1 -1
- package/dist/utils/interactive-prompter.js +12 -65
- package/dist/utils/interactive-prompter.js.map +1 -1
- package/dist/utils/launch-spec-helpers.d.ts +38 -0
- package/dist/utils/launch-spec-helpers.d.ts.map +1 -0
- package/dist/utils/launch-spec-helpers.js +131 -0
- package/dist/utils/launch-spec-helpers.js.map +1 -0
- package/package.json +2 -2
- package/dist/connectors/base/file-based-connector.d.ts +0 -97
- package/dist/connectors/base/file-based-connector.d.ts.map +0 -1
- package/dist/connectors/base/file-based-connector.js +0 -185
- package/dist/connectors/base/file-based-connector.js.map +0 -1
- package/dist/connectors/claude-desktop/claude-desktop.connector.d.ts +0 -38
- package/dist/connectors/claude-desktop/claude-desktop.connector.d.ts.map +0 -1
- package/dist/connectors/claude-desktop/claude-desktop.connector.js +0 -68
- package/dist/connectors/claude-desktop/claude-desktop.connector.js.map +0 -1
- package/dist/connectors/codex/codex.connector.d.ts +0 -51
- package/dist/connectors/codex/codex.connector.d.ts.map +0 -1
- package/dist/connectors/codex/codex.connector.js +0 -76
- package/dist/connectors/codex/codex.connector.js.map +0 -1
- package/dist/connectors/gemini/gemini.connector.d.ts +0 -41
- package/dist/connectors/gemini/gemini.connector.d.ts.map +0 -1
- package/dist/connectors/gemini/gemini.connector.js +0 -61
- package/dist/connectors/gemini/gemini.connector.js.map +0 -1
- package/dist/connectors/qwen/qwen.connector.d.ts +0 -41
- package/dist/connectors/qwen/qwen.connector.d.ts.map +0 -1
- package/dist/connectors/qwen/qwen.connector.js +0 -61
- package/dist/connectors/qwen/qwen.connector.js.map +0 -1
- package/dist/types/base.types.d.ts.map +0 -1
- package/dist/types/base.types.js +0 -6
- package/dist/types/base.types.js.map +0 -1
|
@@ -1,19 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Client-related types for MCP CLI Framework (framework-agnostic)
|
|
3
3
|
* @packageDocumentation
|
|
4
4
|
*/
|
|
5
|
-
/**
|
|
6
|
-
* Базовая конфигурация для любого MCP сервера
|
|
7
|
-
* Все MCP серверы должны расширять этот интерфейс
|
|
8
|
-
*/
|
|
9
|
-
export interface BaseMCPServerConfig {
|
|
10
|
-
/** Абсолютный путь к директории проекта */
|
|
11
|
-
projectPath: string;
|
|
12
|
-
/** Уровень логирования */
|
|
13
|
-
logLevel?: 'debug' | 'info' | 'warn' | 'error';
|
|
14
|
-
/** Дополнительные переменные окружения для MCP сервера */
|
|
15
|
-
env?: Record<string, string>;
|
|
16
|
-
}
|
|
17
5
|
/**
|
|
18
6
|
* Информация о MCP клиенте (Claude Desktop, Claude Code и т.д.)
|
|
19
7
|
*/
|
|
@@ -51,6 +39,9 @@ export interface ConnectionStatus {
|
|
|
51
39
|
}
|
|
52
40
|
/**
|
|
53
41
|
* Конфигурация MCP сервера для записи в файл клиента (JSON/TOML)
|
|
42
|
+
*
|
|
43
|
+
* @internal Используется только реализациями коннекторов. Публичный API
|
|
44
|
+
* принимает {@link ServerLaunchSpec}.
|
|
54
45
|
*/
|
|
55
46
|
export interface MCPClientServerConfig {
|
|
56
47
|
command: string;
|
|
@@ -60,6 +51,8 @@ export interface MCPClientServerConfig {
|
|
|
60
51
|
/**
|
|
61
52
|
* Базовая структура конфигурационного файла MCP клиента
|
|
62
53
|
* Generic тип для разных форматов (mcpServers, mcp_servers и т.д.)
|
|
54
|
+
*
|
|
55
|
+
* @internal Используется только реализациями коннекторов.
|
|
63
56
|
*/
|
|
64
57
|
export type MCPClientConfig<TKey extends string = 'mcpServers'> = {
|
|
65
58
|
[K in TKey]?: Record<string, MCPClientServerConfig>;
|
|
@@ -70,9 +63,11 @@ export type MCPClientConfig<TKey extends string = 'mcpServers'> = {
|
|
|
70
63
|
export type PromptType = 'input' | 'password' | 'select' | 'confirm' | 'number';
|
|
71
64
|
/**
|
|
72
65
|
* Определение промпта для сбора конфигурации
|
|
73
|
-
*
|
|
66
|
+
*
|
|
67
|
+
* @template TDomainConfig - Тип доменной конфигурации MCP сервера (произвольный объект)
|
|
68
|
+
* @template K - Ключ поля в конфигурации
|
|
74
69
|
*/
|
|
75
|
-
export interface ConfigPromptDefinition<
|
|
70
|
+
export interface ConfigPromptDefinition<TDomainConfig extends object, K extends keyof TDomainConfig = keyof TDomainConfig> {
|
|
76
71
|
/** Имя поля в конфигурации */
|
|
77
72
|
name: K;
|
|
78
73
|
/** Тип промпта */
|
|
@@ -80,37 +75,42 @@ export interface ConfigPromptDefinition<TConfig extends BaseMCPServerConfig, K e
|
|
|
80
75
|
/** Сообщение для пользователя */
|
|
81
76
|
message: string;
|
|
82
77
|
/** Значение по умолчанию (может быть функцией от сохраненной конфигурации) */
|
|
83
|
-
default?:
|
|
78
|
+
default?: TDomainConfig[K] | ((savedConfig?: Partial<TDomainConfig>) => TDomainConfig[K] | undefined);
|
|
84
79
|
/** Функция валидации */
|
|
85
|
-
validate?: (value:
|
|
80
|
+
validate?: (value: TDomainConfig[K]) => string | true;
|
|
86
81
|
/** Варианты выбора (для type: 'select') */
|
|
87
82
|
choices?: Array<{
|
|
88
83
|
name: string;
|
|
89
|
-
value:
|
|
84
|
+
value: TDomainConfig[K];
|
|
90
85
|
}>;
|
|
91
86
|
/** Условное отображение промпта */
|
|
92
|
-
when?: (answers: Partial<
|
|
87
|
+
when?: (answers: Partial<TDomainConfig>) => boolean;
|
|
93
88
|
/** Маска для ввода (для type: 'password') */
|
|
94
89
|
mask?: string;
|
|
95
90
|
}
|
|
96
91
|
/**
|
|
97
92
|
* Опции для ConfigManager
|
|
93
|
+
*
|
|
94
|
+
* @template TDomainConfig - Тип доменной конфигурации MCP сервера (произвольный объект)
|
|
98
95
|
*/
|
|
99
|
-
export interface ConfigManagerOptions<
|
|
96
|
+
export interface ConfigManagerOptions<TDomainConfig extends object> {
|
|
100
97
|
/** Название проекта (для ~/.{projectName}/config.json) */
|
|
101
98
|
projectName: string;
|
|
102
99
|
/**
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
*
|
|
100
|
+
* Кастомная сериализация перед записью в файл.
|
|
101
|
+
*
|
|
102
|
+
* Обязательное поле — гарантия защиты от случайного сохранения секретов:
|
|
103
|
+
* адаптер сервера обязан явно решить, какие поля попадают в config.json
|
|
104
|
+
* (например, исключить token и сохранить только orgId/apiBase).
|
|
105
|
+
*
|
|
106
|
+
* Если в твоём адаптере хочется писать «весь объект как есть» — передай
|
|
107
|
+
* `serialize: (cfg) => ({ ...cfg })`. Это явное согласие на сохранение
|
|
108
|
+
* всех полей.
|
|
109
109
|
*/
|
|
110
|
-
serialize
|
|
110
|
+
serialize: (config: TDomainConfig) => Record<string, unknown>;
|
|
111
111
|
/**
|
|
112
|
-
* Опционально: кастомная десериализация после чтения из
|
|
112
|
+
* Опционально: кастомная десериализация после чтения из файла.
|
|
113
113
|
*/
|
|
114
|
-
deserialize?: (data: Record<string, unknown>) => Partial<
|
|
114
|
+
deserialize?: (data: Record<string, unknown>) => Partial<TDomainConfig>;
|
|
115
115
|
}
|
|
116
|
-
//# sourceMappingURL=
|
|
116
|
+
//# sourceMappingURL=client.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.types.d.ts","sourceRoot":"","sources":["../../src/types/client.types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.types.js","sourceRoot":"","sources":["../../src/types/client.types.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Типы для команды самодиагностики `doctor`.
|
|
3
|
+
*
|
|
4
|
+
* Команда `doctor` запускает набор проверок (client-level + доменные) и
|
|
5
|
+
* возвращает агрегированный {@link DoctorReport}. Доменные проверки
|
|
6
|
+
* передаются вызывающим кодом через `extraChecks` — framework к доменной
|
|
7
|
+
* модели агностичен.
|
|
8
|
+
*
|
|
9
|
+
* @packageDocumentation
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Статус результата одной проверки.
|
|
13
|
+
*
|
|
14
|
+
* - `ok` — проверка пройдена.
|
|
15
|
+
* - `warn` — есть подозрение/неполные данные, но не блокер
|
|
16
|
+
* (например, путь выглядит относительным, файл конфига отсутствует).
|
|
17
|
+
* - `fail` — проблема, из-за которой сервер точно не заработает.
|
|
18
|
+
* - `skip` — проверка пропущена по объективным причинам (например, сервер не
|
|
19
|
+
* подключен к этому клиенту, нет данных для проверки).
|
|
20
|
+
* `skip` не учитывается в `summary.fail/warn/ok`.
|
|
21
|
+
*/
|
|
22
|
+
export type DoctorCheckStatus = 'ok' | 'warn' | 'fail' | 'skip';
|
|
23
|
+
/**
|
|
24
|
+
* Результат выполнения одной проверки.
|
|
25
|
+
*/
|
|
26
|
+
export interface DoctorCheckResult {
|
|
27
|
+
/** Итоговый статус. */
|
|
28
|
+
status: DoctorCheckStatus;
|
|
29
|
+
/** Человекочитаемое сообщение о результате. */
|
|
30
|
+
message: string;
|
|
31
|
+
/** Многострочные детали (например, путь к файлу, версия). Опционально. */
|
|
32
|
+
details?: string[];
|
|
33
|
+
/** Рекомендация по исправлению. Для `warn`/`fail`. Опционально. */
|
|
34
|
+
hint?: string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Описание одной проверки.
|
|
38
|
+
*
|
|
39
|
+
* `run` — асинхронная функция, выполняющая проверку. Не должна выбрасывать
|
|
40
|
+
* исключений (любое исключение перехватывается `doctorCommand` и трактуется
|
|
41
|
+
* как `fail`).
|
|
42
|
+
*/
|
|
43
|
+
export interface DoctorCheck {
|
|
44
|
+
/** Короткое имя проверки для вывода (например, `bundle-accessible`). */
|
|
45
|
+
name: string;
|
|
46
|
+
/** Развёрнутое описание того, что проверяется. */
|
|
47
|
+
description: string;
|
|
48
|
+
/**
|
|
49
|
+
* Опциональная группа для визуальной группировки в выводе
|
|
50
|
+
* (например, имя клиента `Claude Code` или домен `Yandex Tracker`).
|
|
51
|
+
*/
|
|
52
|
+
group?: string;
|
|
53
|
+
/** Функция выполнения проверки. */
|
|
54
|
+
run: () => Promise<DoctorCheckResult>;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Агрегированный отчёт о всех проверках.
|
|
58
|
+
*/
|
|
59
|
+
export interface DoctorReport {
|
|
60
|
+
/**
|
|
61
|
+
* Результаты проверок в детерминированном порядке (соответствует порядку,
|
|
62
|
+
* в котором проверки были собраны: client-level → extraChecks).
|
|
63
|
+
*/
|
|
64
|
+
checks: Array<{
|
|
65
|
+
check: DoctorCheck;
|
|
66
|
+
result: DoctorCheckResult;
|
|
67
|
+
}>;
|
|
68
|
+
/**
|
|
69
|
+
* Сводка по статусам (без учёта `skip`).
|
|
70
|
+
*/
|
|
71
|
+
summary: {
|
|
72
|
+
ok: number;
|
|
73
|
+
warn: number;
|
|
74
|
+
fail: number;
|
|
75
|
+
skip: number;
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
import type { IConnectorRegistry } from '../types.js';
|
|
79
|
+
/**
|
|
80
|
+
* Опции для команды `doctor`.
|
|
81
|
+
*/
|
|
82
|
+
export interface DoctorCommandOptions {
|
|
83
|
+
/** Реестр коннекторов MCP клиентов. */
|
|
84
|
+
registry: IConnectorRegistry;
|
|
85
|
+
/**
|
|
86
|
+
* Дополнительные доменные проверки (например, валидация бандла сервера,
|
|
87
|
+
* проверка локальной конфигурации). Выполняются параллельно с client-level.
|
|
88
|
+
*/
|
|
89
|
+
extraChecks?: DoctorCheck[];
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=doctor.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.types.d.ts","sourceRoot":"","sources":["../../src/types/doctor.types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH;;;;;;;;;;GAUG;AACH,MAAM,MAAM,iBAAiB,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAEhE;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,uBAAuB;IACvB,MAAM,EAAE,iBAAiB,CAAC;IAE1B,+CAA+C;IAC/C,OAAO,EAAE,MAAM,CAAC;IAEhB,0EAA0E;IAC1E,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IAEnB,mEAAmE;IACnE,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;GAMG;AACH,MAAM,WAAW,WAAW;IAC1B,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAC;IAEb,kDAAkD;IAClD,WAAW,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,mCAAmC;IACnC,GAAG,EAAE,MAAM,OAAO,CAAC,iBAAiB,CAAC,CAAC;CACvC;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B;;;OAGG;IACH,MAAM,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,WAAW,CAAC;QAAC,MAAM,EAAE,iBAAiB,CAAA;KAAE,CAAC,CAAC;IAEjE;;OAEG;IACH,OAAO,EAAE;QACP,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;CACH;AAID,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEtD;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,uCAAuC;IACvC,QAAQ,EAAE,kBAAkB,CAAC;IAE7B;;;OAGG;IACH,WAAW,CAAC,EAAE,WAAW,EAAE,CAAC;CAC7B"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Типы для команды самодиагностики `doctor`.
|
|
3
|
+
*
|
|
4
|
+
* Команда `doctor` запускает набор проверок (client-level + доменные) и
|
|
5
|
+
* возвращает агрегированный {@link DoctorReport}. Доменные проверки
|
|
6
|
+
* передаются вызывающим кодом через `extraChecks` — framework к доменной
|
|
7
|
+
* модели агностичен.
|
|
8
|
+
*
|
|
9
|
+
* @packageDocumentation
|
|
10
|
+
*/
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=doctor.types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.types.js","sourceRoot":"","sources":["../../src/types/doctor.types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Launch specification types for MCP servers (framework-agnostic)
|
|
3
|
+
* @packageDocumentation
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Спецификация запуска MCP сервера
|
|
7
|
+
*
|
|
8
|
+
* Готовая «команда + аргументы + переменные окружения» для записи в конфиг клиента.
|
|
9
|
+
* Публичный контракт между вызывающим кодом (адаптером домена) и framework: framework
|
|
10
|
+
* ничего не знает о доменных полях, оперируя только `ServerLaunchSpec`.
|
|
11
|
+
*
|
|
12
|
+
* Структурно совпадает с `MCPClientServerConfig` (internal), но логически выполняет
|
|
13
|
+
* другую роль: spec — это вход в `connector.connect()`, а `MCPClientServerConfig` — формат
|
|
14
|
+
* записи в JSON/TOML файлах клиентов.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* const spec: ServerLaunchSpec = {
|
|
19
|
+
* command: 'node',
|
|
20
|
+
* args: ['/abs/path/dist/server.bundle.cjs'],
|
|
21
|
+
* env: { API_TOKEN: 'xxx', ORG_ID: 'my-org' },
|
|
22
|
+
* };
|
|
23
|
+
*
|
|
24
|
+
* await connector.connect(spec);
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export interface ServerLaunchSpec {
|
|
28
|
+
/** Команда для запуска (обычно `node` или абсолютный путь к исполняемому файлу) */
|
|
29
|
+
command: string;
|
|
30
|
+
/**
|
|
31
|
+
* Аргументы команды (включая путь к скрипту и Node-флаги при необходимости).
|
|
32
|
+
*
|
|
33
|
+
* `readonly` — гарантия неизменяемости. Если коннектору нужно изменить
|
|
34
|
+
* массив, он должен сделать локальную копию.
|
|
35
|
+
*/
|
|
36
|
+
args: readonly string[];
|
|
37
|
+
/** Переменные окружения, передаваемые серверу */
|
|
38
|
+
env: Record<string, string>;
|
|
39
|
+
/**
|
|
40
|
+
* Рабочая директория для процесса сервера (опционально).
|
|
41
|
+
*
|
|
42
|
+
* Если задано — должно быть абсолютным путём. Поддержка зависит от конкретного
|
|
43
|
+
* клиента: для file-based клиентов (Claude Desktop, Gemini, Qwen, Codex)
|
|
44
|
+
* сохраняется в конфиге и читается обратно; для Claude Code не поддерживается
|
|
45
|
+
* (выводится warning).
|
|
46
|
+
*
|
|
47
|
+
* Если `undefined` — поле не пишется в конфиг, наследуется текущий cwd процесса.
|
|
48
|
+
*/
|
|
49
|
+
cwd?: string;
|
|
50
|
+
/**
|
|
51
|
+
* Метка «сервер выключен» (опционально). Если `true`, клиент НЕ должен
|
|
52
|
+
* запускать процесс сервера. Поддержка зависит от клиента: file-based клиенты
|
|
53
|
+
* пишут поле в JSON/TOML; Claude Code эту опцию не поддерживает (warning).
|
|
54
|
+
*
|
|
55
|
+
* Если `undefined` — поле не пишется в конфиг (по умолчанию активный).
|
|
56
|
+
*/
|
|
57
|
+
disabled?: boolean;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=launch.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"launch.types.d.ts","sourceRoot":"","sources":["../../src/types/launch.types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,WAAW,gBAAgB;IAC/B,mFAAmF;IACnF,OAAO,EAAE,MAAM,CAAC;IAEhB;;;;;OAKG;IACH,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IAExB,iDAAiD;IACjD,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAE5B;;;;;;;;;OASG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"launch.types.js","sourceRoot":"","sources":["../../src/types/launch.types.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
package/dist/types.d.ts
CHANGED
|
@@ -2,36 +2,45 @@
|
|
|
2
2
|
* Core types for MCP CLI Framework
|
|
3
3
|
* @packageDocumentation
|
|
4
4
|
*/
|
|
5
|
-
export { type
|
|
6
|
-
|
|
5
|
+
export { type MCPClientInfo, type ConnectionStatus, type PromptType, type ConfigPromptDefinition, type ConfigManagerOptions, } from './types/client.types.js';
|
|
6
|
+
export { type ServerLaunchSpec } from './types/launch.types.js';
|
|
7
|
+
export { type DoctorCheck, type DoctorCheckResult, type DoctorCheckStatus, type DoctorReport, type DoctorCommandOptions, } from './types/doctor.types.js';
|
|
8
|
+
import type { ConnectionStatus, ConfigPromptDefinition } from './types/client.types.js';
|
|
9
|
+
import type { ServerLaunchSpec } from './types/launch.types.js';
|
|
7
10
|
import type { MCPConnector } from './connectors/base/connector.interface.js';
|
|
8
11
|
import type { ConfigManager } from './utils/config-manager.js';
|
|
9
12
|
/**
|
|
10
13
|
* Опции для команды connect
|
|
14
|
+
*
|
|
15
|
+
* @template TDomainConfig - Тип доменной конфигурации MCP сервера (произвольный объект)
|
|
11
16
|
*/
|
|
12
|
-
export interface ConnectCommandOptions<
|
|
17
|
+
export interface ConnectCommandOptions<TDomainConfig extends object> {
|
|
13
18
|
/** Реестр коннекторов */
|
|
14
|
-
registry: IConnectorRegistry
|
|
19
|
+
registry: IConnectorRegistry;
|
|
15
20
|
/** Менеджер конфигурации */
|
|
16
|
-
configManager: ConfigManager<
|
|
17
|
-
/** Промпты для сбора конфигурации */
|
|
18
|
-
configPrompts: ConfigPromptDefinition<
|
|
21
|
+
configManager: ConfigManager<TDomainConfig>;
|
|
22
|
+
/** Промпты для сбора доменной конфигурации */
|
|
23
|
+
configPrompts: ConfigPromptDefinition<TDomainConfig>[];
|
|
24
|
+
/**
|
|
25
|
+
* Адаптер: доменная конфигурация → спецификация запуска MCP сервера.
|
|
26
|
+
* Framework не знает структуру `TDomainConfig`, эта функция превращает её в
|
|
27
|
+
* `{ command, args, env }` для записи в конфиг клиента.
|
|
28
|
+
*/
|
|
29
|
+
buildServerLaunch: (config: TDomainConfig) => ServerLaunchSpec;
|
|
19
30
|
/** CLI опции (из commander) */
|
|
20
31
|
cliOptions?: {
|
|
21
32
|
client?: string;
|
|
22
33
|
};
|
|
23
|
-
/** Опционально: функция для добавления projectPath к конфигу */
|
|
24
|
-
buildConfig?: (serverConfig: Omit<TConfig, 'projectPath'>) => TConfig;
|
|
25
34
|
}
|
|
26
35
|
/**
|
|
27
36
|
* Интерфейс для реестра MCP коннекторов
|
|
28
37
|
* @internal - используется только для типизации command options
|
|
29
38
|
*/
|
|
30
|
-
export interface IConnectorRegistry
|
|
31
|
-
register(connector: MCPConnector
|
|
32
|
-
get(name: string): MCPConnector
|
|
33
|
-
getAll(): MCPConnector
|
|
34
|
-
findInstalled(): Promise<MCPConnector
|
|
39
|
+
export interface IConnectorRegistry {
|
|
40
|
+
register(connector: MCPConnector): void;
|
|
41
|
+
get(name: string): MCPConnector | undefined;
|
|
42
|
+
getAll(): MCPConnector[];
|
|
43
|
+
findInstalled(): Promise<MCPConnector[]>;
|
|
35
44
|
checkAllStatuses(): Promise<Map<string, ConnectionStatus>>;
|
|
36
45
|
}
|
|
37
46
|
export type { MCPConnector };
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,KAAK,UAAU,EACf,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,GAC1B,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAGhE,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,KAAK,YAAY,EACjB,KAAK,oBAAoB,GAC1B,MAAM,yBAAyB,CAAC;AAGjC,OAAO,KAAK,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACxF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0CAA0C,CAAC;AAC7E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAE/D;;;;GAIG;AACH,MAAM,WAAW,qBAAqB,CAAC,aAAa,SAAS,MAAM;IACjE,yBAAyB;IACzB,QAAQ,EAAE,kBAAkB,CAAC;IAE7B,4BAA4B;IAC5B,aAAa,EAAE,aAAa,CAAC,aAAa,CAAC,CAAC;IAE5C,8CAA8C;IAC9C,aAAa,EAAE,sBAAsB,CAAC,aAAa,CAAC,EAAE,CAAC;IAEvD;;;;OAIG;IACH,iBAAiB,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,gBAAgB,CAAC;IAE/D,+BAA+B;IAC/B,UAAU,CAAC,EAAE;QACX,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;CACH;AAED;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,SAAS,EAAE,YAAY,GAAG,IAAI,CAAC;IACxC,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAAC;IAC5C,MAAM,IAAI,YAAY,EAAE,CAAC;IACzB,aAAa,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;IACzC,gBAAgB,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC;CAC5D;AAGD,YAAY,EAAE,YAAY,EAAE,CAAC"}
|
package/dist/types.js
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
* Core types for MCP CLI Framework
|
|
3
3
|
* @packageDocumentation
|
|
4
4
|
*/
|
|
5
|
-
// Re-export
|
|
6
|
-
|
|
5
|
+
// Re-export client-related types.
|
|
6
|
+
// Note: MCPClientServerConfig / MCPClientConfig — internal-only (используются
|
|
7
|
+
// внутри ConfigurableConnector для типизации raw-JSON/TOML структур). НЕ
|
|
8
|
+
// re-export.
|
|
9
|
+
export {} from './types/client.types.js';
|
|
10
|
+
// Re-export launch spec
|
|
11
|
+
export {} from './types/launch.types.js';
|
|
12
|
+
// Re-export doctor types (Stage 1.3)
|
|
13
|
+
export {} from './types/doctor.types.js';
|
|
7
14
|
//# sourceMappingURL=types.js.map
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,kCAAkC;AAClC,8EAA8E;AAC9E,yEAAyE;AACzE,aAAa;AACb,OAAO,EAMN,MAAM,yBAAyB,CAAC;AAEjC,wBAAwB;AACxB,OAAO,EAAyB,MAAM,yBAAyB,CAAC;AAEhE,qCAAqC;AACrC,OAAO,EAMN,MAAM,yBAAyB,CAAC"}
|
|
@@ -4,6 +4,16 @@
|
|
|
4
4
|
* @module CommandExecutor
|
|
5
5
|
* @description Утилита для выполнения shell команд с различными режимами вывода
|
|
6
6
|
*/
|
|
7
|
+
/**
|
|
8
|
+
* Опции для {@link CommandExecutor.exec}.
|
|
9
|
+
*/
|
|
10
|
+
export interface ExecOptions {
|
|
11
|
+
/**
|
|
12
|
+
* Таймаут выполнения в миллисекундах. При превышении — процесс убивается
|
|
13
|
+
* `SIGKILL`, выбрасывается `Error('Timeout: <command> exceeded <ms>ms')`.
|
|
14
|
+
*/
|
|
15
|
+
timeout?: number;
|
|
16
|
+
}
|
|
7
17
|
/**
|
|
8
18
|
* Класс для выполнения shell команд
|
|
9
19
|
*
|
|
@@ -12,6 +22,12 @@
|
|
|
12
22
|
* // Выполнить команду и получить вывод
|
|
13
23
|
* const output = CommandExecutor.exec('echo "test"');
|
|
14
24
|
*
|
|
25
|
+
* // С таймаутом
|
|
26
|
+
* const output = CommandExecutor.exec('claude mcp list', { timeout: 5000 });
|
|
27
|
+
*
|
|
28
|
+
* // Безопасное выполнение без shell-интерпретации
|
|
29
|
+
* const out = CommandExecutor.execFile('claude', ['mcp', 'list'], { timeout: 5000 });
|
|
30
|
+
*
|
|
15
31
|
* // Проверить наличие команды
|
|
16
32
|
* if (CommandExecutor.isCommandAvailable('node')) {
|
|
17
33
|
* console.log('Node.js установлен');
|
|
@@ -20,11 +36,12 @@
|
|
|
20
36
|
*/
|
|
21
37
|
export declare class CommandExecutor {
|
|
22
38
|
/**
|
|
23
|
-
* Выполнить команду и вернуть stdout
|
|
39
|
+
* Выполнить команду и вернуть stdout.
|
|
24
40
|
*
|
|
25
41
|
* @param command - Команда для выполнения
|
|
42
|
+
* @param options - Опции выполнения (включая `timeout`)
|
|
26
43
|
* @returns Вывод команды
|
|
27
|
-
* @throws {Error} Если команда завершилась с ошибкой
|
|
44
|
+
* @throws {Error} Если команда завершилась с ошибкой или превысила таймаут
|
|
28
45
|
*
|
|
29
46
|
* @example
|
|
30
47
|
* ```typescript
|
|
@@ -32,7 +49,26 @@ export declare class CommandExecutor {
|
|
|
32
49
|
* console.log(nodeVersion); // v22.21.1
|
|
33
50
|
* ```
|
|
34
51
|
*/
|
|
35
|
-
static exec(command: string): string;
|
|
52
|
+
static exec(command: string, options?: ExecOptions): string;
|
|
53
|
+
/**
|
|
54
|
+
* Выполнить команду через `execFileSync` без shell-интерпретации.
|
|
55
|
+
*
|
|
56
|
+
* Этот метод предпочтительнее {@link exec} в случаях, когда команда и её
|
|
57
|
+
* аргументы фиксированы и НЕ должны интерпретироваться шеллом
|
|
58
|
+
* (избегаем риска инъекции, кросс-платформенных проблем с кавычками и т.п.).
|
|
59
|
+
*
|
|
60
|
+
* @param command - Имя исполняемого файла (резолвится через PATH) или абсолютный путь
|
|
61
|
+
* @param args - Аргументы команды (каждый — отдельный элемент массива)
|
|
62
|
+
* @param options - Опции (включая `timeout` в мс)
|
|
63
|
+
* @returns stdout команды
|
|
64
|
+
* @throws {Error} Если команда завершилась с ненулевым кодом или превысила таймаут
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```typescript
|
|
68
|
+
* const out = CommandExecutor.execFile('claude', ['mcp', 'list'], { timeout: 5000 });
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
static execFile(command: string, args: string[], options?: ExecOptions): string;
|
|
36
72
|
/**
|
|
37
73
|
* Выполнить команду тихо (подавить вывод)
|
|
38
74
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command-executor.d.ts","sourceRoot":"","sources":["../../src/utils/command-executor.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH
|
|
1
|
+
{"version":3,"file":"command-executor.d.ts","sourceRoot":"","sources":["../../src/utils/command-executor.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAyBD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,eAAe;IAC1B;;;;;;;;;;;;;OAaG;IACH,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM;IA4B/D;;;;;;;;;;;;;;;;;OAiBG;IACH,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM;IA6BnF;;;;;;;;;;OAUG;IACH,MAAM,CAAC,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAQxC;;;;;;;;;;;;;OAaG;WACU,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAgB5E;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;CAQpD"}
|
|
@@ -4,7 +4,31 @@
|
|
|
4
4
|
* @module CommandExecutor
|
|
5
5
|
* @description Утилита для выполнения shell команд с различными режимами вывода
|
|
6
6
|
*/
|
|
7
|
-
import { execSync, spawn } from 'node:child_process';
|
|
7
|
+
import { execFileSync, execSync, spawn } from 'node:child_process';
|
|
8
|
+
/**
|
|
9
|
+
* Максимальная длина stderr в сообщении об ошибке.
|
|
10
|
+
*
|
|
11
|
+
* Цель — не раздувать message длинными выводами CLI (некоторые программы
|
|
12
|
+
* пишут многостраничный traceback). 200 символов достаточно для диагностики.
|
|
13
|
+
*/
|
|
14
|
+
const STDERR_PREVIEW_LIMIT = 200;
|
|
15
|
+
/**
|
|
16
|
+
* Извлечь и обрезать stderr из объекта ошибки `execSync`/`execFileSync`.
|
|
17
|
+
*/
|
|
18
|
+
function extractStderr(err) {
|
|
19
|
+
if (typeof err !== 'object' || err === null)
|
|
20
|
+
return undefined;
|
|
21
|
+
const stderr = err.stderr;
|
|
22
|
+
if (stderr === undefined || stderr === null)
|
|
23
|
+
return undefined;
|
|
24
|
+
const text = typeof stderr === 'string' ? stderr : String(stderr);
|
|
25
|
+
const trimmed = text.trim();
|
|
26
|
+
if (trimmed.length === 0)
|
|
27
|
+
return undefined;
|
|
28
|
+
return trimmed.length > STDERR_PREVIEW_LIMIT
|
|
29
|
+
? `${trimmed.slice(0, STDERR_PREVIEW_LIMIT)}…`
|
|
30
|
+
: trimmed;
|
|
31
|
+
}
|
|
8
32
|
/**
|
|
9
33
|
* Класс для выполнения shell команд
|
|
10
34
|
*
|
|
@@ -13,6 +37,12 @@ import { execSync, spawn } from 'node:child_process';
|
|
|
13
37
|
* // Выполнить команду и получить вывод
|
|
14
38
|
* const output = CommandExecutor.exec('echo "test"');
|
|
15
39
|
*
|
|
40
|
+
* // С таймаутом
|
|
41
|
+
* const output = CommandExecutor.exec('claude mcp list', { timeout: 5000 });
|
|
42
|
+
*
|
|
43
|
+
* // Безопасное выполнение без shell-интерпретации
|
|
44
|
+
* const out = CommandExecutor.execFile('claude', ['mcp', 'list'], { timeout: 5000 });
|
|
45
|
+
*
|
|
16
46
|
* // Проверить наличие команды
|
|
17
47
|
* if (CommandExecutor.isCommandAvailable('node')) {
|
|
18
48
|
* console.log('Node.js установлен');
|
|
@@ -21,11 +51,12 @@ import { execSync, spawn } from 'node:child_process';
|
|
|
21
51
|
*/
|
|
22
52
|
export class CommandExecutor {
|
|
23
53
|
/**
|
|
24
|
-
* Выполнить команду и вернуть stdout
|
|
54
|
+
* Выполнить команду и вернуть stdout.
|
|
25
55
|
*
|
|
26
56
|
* @param command - Команда для выполнения
|
|
57
|
+
* @param options - Опции выполнения (включая `timeout`)
|
|
27
58
|
* @returns Вывод команды
|
|
28
|
-
* @throws {Error} Если команда завершилась с ошибкой
|
|
59
|
+
* @throws {Error} Если команда завершилась с ошибкой или превысила таймаут
|
|
29
60
|
*
|
|
30
61
|
* @example
|
|
31
62
|
* ```typescript
|
|
@@ -33,12 +64,68 @@ export class CommandExecutor {
|
|
|
33
64
|
* console.log(nodeVersion); // v22.21.1
|
|
34
65
|
* ```
|
|
35
66
|
*/
|
|
36
|
-
static exec(command) {
|
|
67
|
+
static exec(command, options = {}) {
|
|
68
|
+
const execOptions = {
|
|
69
|
+
encoding: 'utf-8',
|
|
70
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
71
|
+
};
|
|
72
|
+
if (options.timeout !== undefined) {
|
|
73
|
+
execOptions.timeout = options.timeout;
|
|
74
|
+
execOptions.killSignal = 'SIGKILL';
|
|
75
|
+
}
|
|
37
76
|
try {
|
|
38
|
-
return execSync(command,
|
|
77
|
+
return execSync(command, execOptions);
|
|
39
78
|
}
|
|
40
|
-
catch {
|
|
41
|
-
|
|
79
|
+
catch (err) {
|
|
80
|
+
// `execSync` бросает ошибку с `signal === 'SIGKILL'` при таймауте.
|
|
81
|
+
const errorObj = err;
|
|
82
|
+
if (options.timeout !== undefined &&
|
|
83
|
+
(errorObj?.signal === 'SIGKILL' || errorObj?.code === 'ETIMEDOUT')) {
|
|
84
|
+
throw new Error(`Timeout: ${command} exceeded ${String(options.timeout)}ms`);
|
|
85
|
+
}
|
|
86
|
+
const stderr = extractStderr(err);
|
|
87
|
+
throw new Error(stderr ? `Command failed: ${command} (${stderr})` : `Command failed: ${command}`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Выполнить команду через `execFileSync` без shell-интерпретации.
|
|
92
|
+
*
|
|
93
|
+
* Этот метод предпочтительнее {@link exec} в случаях, когда команда и её
|
|
94
|
+
* аргументы фиксированы и НЕ должны интерпретироваться шеллом
|
|
95
|
+
* (избегаем риска инъекции, кросс-платформенных проблем с кавычками и т.п.).
|
|
96
|
+
*
|
|
97
|
+
* @param command - Имя исполняемого файла (резолвится через PATH) или абсолютный путь
|
|
98
|
+
* @param args - Аргументы команды (каждый — отдельный элемент массива)
|
|
99
|
+
* @param options - Опции (включая `timeout` в мс)
|
|
100
|
+
* @returns stdout команды
|
|
101
|
+
* @throws {Error} Если команда завершилась с ненулевым кодом или превысила таймаут
|
|
102
|
+
*
|
|
103
|
+
* @example
|
|
104
|
+
* ```typescript
|
|
105
|
+
* const out = CommandExecutor.execFile('claude', ['mcp', 'list'], { timeout: 5000 });
|
|
106
|
+
* ```
|
|
107
|
+
*/
|
|
108
|
+
static execFile(command, args, options = {}) {
|
|
109
|
+
const execOptions = {
|
|
110
|
+
encoding: 'utf-8',
|
|
111
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
112
|
+
};
|
|
113
|
+
if (options.timeout !== undefined) {
|
|
114
|
+
execOptions.timeout = options.timeout;
|
|
115
|
+
execOptions.killSignal = 'SIGKILL';
|
|
116
|
+
}
|
|
117
|
+
const displayCmd = `${command} ${args.join(' ')}`.trim();
|
|
118
|
+
try {
|
|
119
|
+
return execFileSync(command, args, execOptions);
|
|
120
|
+
}
|
|
121
|
+
catch (err) {
|
|
122
|
+
const errorObj = err;
|
|
123
|
+
if (options.timeout !== undefined &&
|
|
124
|
+
(errorObj?.signal === 'SIGKILL' || errorObj?.code === 'ETIMEDOUT')) {
|
|
125
|
+
throw new Error(`Timeout: ${displayCmd} exceeded ${String(options.timeout)}ms`);
|
|
126
|
+
}
|
|
127
|
+
const stderr = extractStderr(err);
|
|
128
|
+
throw new Error(stderr ? `Command failed: ${displayCmd} (${stderr})` : `Command failed: ${displayCmd}`);
|
|
42
129
|
}
|
|
43
130
|
}
|
|
44
131
|
/**
|
|
@@ -82,7 +169,7 @@ export class CommandExecutor {
|
|
|
82
169
|
resolve();
|
|
83
170
|
}
|
|
84
171
|
else {
|
|
85
|
-
reject(new Error(`Command exited with code ${code}`));
|
|
172
|
+
reject(new Error(`Command exited with code ${String(code)}`));
|
|
86
173
|
}
|
|
87
174
|
});
|
|
88
175
|
child.on('error', reject);
|