@sylphx/flow 1.0.1 → 1.0.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/CHANGELOG.md +12 -0
- package/package.json +10 -9
- package/src/commands/codebase-command.ts +168 -0
- package/src/commands/flow-command.ts +1137 -0
- package/src/commands/flow-orchestrator.ts +296 -0
- package/src/commands/hook-command.ts +444 -0
- package/src/commands/init-command.ts +92 -0
- package/src/commands/init-core.ts +322 -0
- package/src/commands/knowledge-command.ts +161 -0
- package/src/commands/run-command.ts +120 -0
- package/src/components/benchmark-monitor.tsx +331 -0
- package/src/components/reindex-progress.tsx +261 -0
- package/src/composables/functional/index.ts +14 -0
- package/src/composables/functional/useEnvironment.ts +171 -0
- package/src/composables/functional/useFileSystem.ts +139 -0
- package/src/composables/index.ts +5 -0
- package/src/composables/useEnv.ts +13 -0
- package/src/composables/useRuntimeConfig.ts +27 -0
- package/src/composables/useTargetConfig.ts +45 -0
- package/src/config/ai-config.ts +376 -0
- package/src/config/constants.ts +35 -0
- package/src/config/index.ts +27 -0
- package/src/config/rules.ts +43 -0
- package/src/config/servers.ts +371 -0
- package/src/config/targets.ts +126 -0
- package/src/core/agent-loader.ts +141 -0
- package/src/core/agent-manager.ts +174 -0
- package/src/core/ai-sdk.ts +603 -0
- package/src/core/app-factory.ts +381 -0
- package/src/core/builtin-agents.ts +9 -0
- package/src/core/command-system.ts +550 -0
- package/src/core/config-system.ts +550 -0
- package/src/core/connection-pool.ts +390 -0
- package/src/core/di-container.ts +155 -0
- package/src/core/error-handling.ts +519 -0
- package/src/core/formatting/bytes.test.ts +115 -0
- package/src/core/formatting/bytes.ts +64 -0
- package/src/core/functional/async.ts +313 -0
- package/src/core/functional/either.ts +109 -0
- package/src/core/functional/error-handler.ts +135 -0
- package/src/core/functional/error-types.ts +311 -0
- package/src/core/functional/index.ts +19 -0
- package/src/core/functional/option.ts +142 -0
- package/src/core/functional/pipe.ts +189 -0
- package/src/core/functional/result.ts +204 -0
- package/src/core/functional/validation.ts +138 -0
- package/src/core/headless-display.ts +96 -0
- package/src/core/index.ts +6 -0
- package/src/core/installers/file-installer.ts +303 -0
- package/src/core/installers/mcp-installer.ts +213 -0
- package/src/core/interfaces/index.ts +22 -0
- package/src/core/interfaces/repository.interface.ts +91 -0
- package/src/core/interfaces/service.interface.ts +133 -0
- package/src/core/interfaces.ts +129 -0
- package/src/core/loop-controller.ts +200 -0
- package/src/core/result.ts +351 -0
- package/src/core/rule-loader.ts +147 -0
- package/src/core/rule-manager.ts +240 -0
- package/src/core/service-config.ts +252 -0
- package/src/core/session-service.ts +121 -0
- package/src/core/state-detector.ts +389 -0
- package/src/core/storage-factory.ts +115 -0
- package/src/core/stream-handler.ts +288 -0
- package/src/core/target-manager.ts +161 -0
- package/src/core/type-utils.ts +427 -0
- package/src/core/unified-storage.ts +456 -0
- package/src/core/upgrade-manager.ts +300 -0
- package/src/core/validation/limit.test.ts +155 -0
- package/src/core/validation/limit.ts +46 -0
- package/src/core/validation/query.test.ts +44 -0
- package/src/core/validation/query.ts +20 -0
- package/src/db/auto-migrate.ts +322 -0
- package/src/db/base-database-client.ts +144 -0
- package/src/db/cache-db.ts +218 -0
- package/src/db/cache-schema.ts +75 -0
- package/src/db/database.ts +70 -0
- package/src/db/index.ts +252 -0
- package/src/db/memory-db.ts +153 -0
- package/src/db/memory-schema.ts +29 -0
- package/src/db/schema.ts +289 -0
- package/src/db/session-repository.ts +733 -0
- package/src/domains/codebase/index.ts +5 -0
- package/src/domains/codebase/tools.ts +139 -0
- package/src/domains/index.ts +8 -0
- package/src/domains/knowledge/index.ts +10 -0
- package/src/domains/knowledge/resources.ts +537 -0
- package/src/domains/knowledge/tools.ts +174 -0
- package/src/domains/utilities/index.ts +6 -0
- package/src/domains/utilities/time/index.ts +5 -0
- package/src/domains/utilities/time/tools.ts +291 -0
- package/src/index.ts +211 -0
- package/src/services/agent-service.ts +273 -0
- package/src/services/claude-config-service.ts +252 -0
- package/src/services/config-service.ts +258 -0
- package/src/services/evaluation-service.ts +271 -0
- package/src/services/functional/evaluation-logic.ts +296 -0
- package/src/services/functional/file-processor.ts +273 -0
- package/src/services/functional/index.ts +12 -0
- package/src/services/index.ts +13 -0
- package/src/services/mcp-service.ts +432 -0
- package/src/services/memory.service.ts +476 -0
- package/src/services/search/base-indexer.ts +156 -0
- package/src/services/search/codebase-indexer-types.ts +38 -0
- package/src/services/search/codebase-indexer.ts +647 -0
- package/src/services/search/embeddings-provider.ts +455 -0
- package/src/services/search/embeddings.ts +316 -0
- package/src/services/search/functional-indexer.ts +323 -0
- package/src/services/search/index.ts +27 -0
- package/src/services/search/indexer.ts +380 -0
- package/src/services/search/knowledge-indexer.ts +422 -0
- package/src/services/search/semantic-search.ts +244 -0
- package/src/services/search/tfidf.ts +559 -0
- package/src/services/search/unified-search-service.ts +888 -0
- package/src/services/smart-config-service.ts +385 -0
- package/src/services/storage/cache-storage.ts +487 -0
- package/src/services/storage/drizzle-storage.ts +581 -0
- package/src/services/storage/index.ts +15 -0
- package/src/services/storage/lancedb-vector-storage.ts +494 -0
- package/src/services/storage/memory-storage.ts +268 -0
- package/src/services/storage/separated-storage.ts +467 -0
- package/src/services/storage/vector-storage.ts +13 -0
- package/src/shared/agents/index.ts +63 -0
- package/src/shared/files/index.ts +99 -0
- package/src/shared/index.ts +32 -0
- package/src/shared/logging/index.ts +24 -0
- package/src/shared/processing/index.ts +153 -0
- package/src/shared/types/index.ts +25 -0
- package/src/targets/claude-code.ts +574 -0
- package/src/targets/functional/claude-code-logic.ts +185 -0
- package/src/targets/functional/index.ts +6 -0
- package/src/targets/opencode.ts +529 -0
- package/src/types/agent.types.ts +32 -0
- package/src/types/api/batch.ts +108 -0
- package/src/types/api/errors.ts +118 -0
- package/src/types/api/index.ts +55 -0
- package/src/types/api/requests.ts +76 -0
- package/src/types/api/responses.ts +180 -0
- package/src/types/api/websockets.ts +85 -0
- package/src/types/api.types.ts +9 -0
- package/src/types/benchmark.ts +49 -0
- package/src/types/cli.types.ts +87 -0
- package/src/types/common.types.ts +35 -0
- package/src/types/database.types.ts +510 -0
- package/src/types/mcp-config.types.ts +448 -0
- package/src/types/mcp.types.ts +69 -0
- package/src/types/memory-types.ts +63 -0
- package/src/types/provider.types.ts +28 -0
- package/src/types/rule.types.ts +24 -0
- package/src/types/session.types.ts +214 -0
- package/src/types/target-config.types.ts +295 -0
- package/src/types/target.types.ts +140 -0
- package/src/types/todo.types.ts +25 -0
- package/src/types.ts +40 -0
- package/src/utils/advanced-tokenizer.ts +191 -0
- package/src/utils/agent-enhancer.ts +114 -0
- package/src/utils/ai-model-fetcher.ts +19 -0
- package/src/utils/async-file-operations.ts +516 -0
- package/src/utils/audio-player.ts +345 -0
- package/src/utils/cli-output.ts +266 -0
- package/src/utils/codebase-helpers.ts +211 -0
- package/src/utils/console-ui.ts +79 -0
- package/src/utils/database-errors.ts +140 -0
- package/src/utils/debug-logger.ts +49 -0
- package/src/utils/error-handler.ts +53 -0
- package/src/utils/file-operations.ts +310 -0
- package/src/utils/file-scanner.ts +259 -0
- package/src/utils/functional/array.ts +355 -0
- package/src/utils/functional/index.ts +15 -0
- package/src/utils/functional/object.ts +279 -0
- package/src/utils/functional/string.ts +281 -0
- package/src/utils/functional.ts +543 -0
- package/src/utils/help.ts +20 -0
- package/src/utils/immutable-cache.ts +106 -0
- package/src/utils/index.ts +78 -0
- package/src/utils/jsonc.ts +158 -0
- package/src/utils/logger.ts +396 -0
- package/src/utils/mcp-config.ts +249 -0
- package/src/utils/memory-tui.ts +414 -0
- package/src/utils/models-dev.ts +91 -0
- package/src/utils/notifications.ts +169 -0
- package/src/utils/object-utils.ts +51 -0
- package/src/utils/parallel-operations.ts +487 -0
- package/src/utils/paths.ts +143 -0
- package/src/utils/process-manager.ts +155 -0
- package/src/utils/prompts.ts +120 -0
- package/src/utils/search-tool-builder.ts +214 -0
- package/src/utils/secret-utils.ts +179 -0
- package/src/utils/security.ts +537 -0
- package/src/utils/session-manager.ts +168 -0
- package/src/utils/session-title.ts +87 -0
- package/src/utils/settings.ts +182 -0
- package/src/utils/simplified-errors.ts +410 -0
- package/src/utils/sync-utils.ts +159 -0
- package/src/utils/target-config.ts +570 -0
- package/src/utils/target-utils.ts +394 -0
- package/src/utils/template-engine.ts +94 -0
- package/src/utils/test-audio.ts +71 -0
- package/src/utils/todo-context.ts +46 -0
- package/src/utils/token-counter.ts +288 -0
- package/dist/index.d.ts +0 -10
- package/dist/index.js +0 -59554
- package/dist/lancedb.linux-x64-gnu-b7f0jgsz.node +0 -0
- package/dist/lancedb.linux-x64-musl-tgcv22rx.node +0 -0
- package/dist/shared/chunk-25dwp0dp.js +0 -89
- package/dist/shared/chunk-3pjb6063.js +0 -208
- package/dist/shared/chunk-4d6ydpw7.js +0 -2854
- package/dist/shared/chunk-4wjcadjk.js +0 -225
- package/dist/shared/chunk-5j4w74t6.js +0 -30
- package/dist/shared/chunk-5j8m3dh3.js +0 -58
- package/dist/shared/chunk-5thh3qem.js +0 -91
- package/dist/shared/chunk-6g9xy73m.js +0 -252
- package/dist/shared/chunk-7eq34c42.js +0 -23
- package/dist/shared/chunk-c2gwgx3r.js +0 -115
- package/dist/shared/chunk-cjd3mk4c.js +0 -1320
- package/dist/shared/chunk-g5cv6703.js +0 -368
- package/dist/shared/chunk-hpkhykhq.js +0 -574
- package/dist/shared/chunk-m2322pdk.js +0 -122
- package/dist/shared/chunk-nd5fdvaq.js +0 -26
- package/dist/shared/chunk-pgd3m6zf.js +0 -108
- package/dist/shared/chunk-qk8n91hw.js +0 -494
- package/dist/shared/chunk-rkkn8szp.js +0 -16855
- package/dist/shared/chunk-t16rfxh0.js +0 -61
- package/dist/shared/chunk-t4fbfa5v.js +0 -19
- package/dist/shared/chunk-t77h86w6.js +0 -276
- package/dist/shared/chunk-v0ez4aef.js +0 -71
- package/dist/shared/chunk-v29j2r3s.js +0 -32051
- package/dist/shared/chunk-vfbc6ew5.js +0 -765
- package/dist/shared/chunk-vmeqwm1c.js +0 -204
- package/dist/shared/chunk-x66eh37x.js +0 -137
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import inquirer from 'inquirer';
|
|
3
|
+
import ora from 'ora';
|
|
4
|
+
import { MCP_SERVER_REGISTRY, type MCPServerID } from '../config/servers.js';
|
|
5
|
+
import type { TargetConfigurationData } from '../types/target-config.types.js';
|
|
6
|
+
import type { Target } from '../types.js';
|
|
7
|
+
import { isCLICommandConfig, type Resolvable } from '../types.js';
|
|
8
|
+
|
|
9
|
+
export interface ValidationResult {
|
|
10
|
+
isValid: boolean;
|
|
11
|
+
missingRequired: string[];
|
|
12
|
+
invalidValues: string[];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface InstallOptions {
|
|
16
|
+
skipValidation?: boolean;
|
|
17
|
+
dryRun?: boolean;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* MCPService Interface
|
|
22
|
+
* Service for managing MCP server installation and configuration
|
|
23
|
+
*/
|
|
24
|
+
export interface MCPService {
|
|
25
|
+
readonly getAllServerIds: () => MCPServerID[];
|
|
26
|
+
readonly getAvailableServers: () => Promise<MCPServerID[]>;
|
|
27
|
+
readonly getInstalledServerIds: () => Promise<MCPServerID[]>;
|
|
28
|
+
readonly getRequiringConfiguration: (serverIds: MCPServerID[]) => MCPServerID[];
|
|
29
|
+
readonly validateServer: (
|
|
30
|
+
serverId: MCPServerID,
|
|
31
|
+
envValues: Record<string, string>
|
|
32
|
+
) => ValidationResult;
|
|
33
|
+
readonly configureServer: (
|
|
34
|
+
serverId: MCPServerID,
|
|
35
|
+
collectedEnv?: Record<string, string>
|
|
36
|
+
) => Promise<Record<string, string>>;
|
|
37
|
+
readonly installServers: (
|
|
38
|
+
serverIds: MCPServerID[],
|
|
39
|
+
serverConfigs?: Record<MCPServerID, Record<string, string>>
|
|
40
|
+
) => Promise<void>;
|
|
41
|
+
readonly readConfig: () => Promise<TargetConfigurationData>;
|
|
42
|
+
readonly writeConfig: (configData: TargetConfigurationData) => Promise<void>;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* MCPService Dependencies
|
|
47
|
+
*/
|
|
48
|
+
export interface MCPServiceDeps {
|
|
49
|
+
readonly target: Target;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Helper function to resolve static or dynamic configuration values
|
|
54
|
+
*/
|
|
55
|
+
function resolveConfig<T>(config: Resolvable<T>): Promise<T> {
|
|
56
|
+
if (typeof config === 'function') {
|
|
57
|
+
const result = (config as () => T | Promise<T>)();
|
|
58
|
+
return Promise.resolve(result);
|
|
59
|
+
}
|
|
60
|
+
return Promise.resolve(config);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Helper function to resolve static or dynamic configuration values with parameters
|
|
65
|
+
*/
|
|
66
|
+
export function resolveConfigWithParams<T, P>(
|
|
67
|
+
config: T | ((params: P) => Promise<T>) | ((params: P) => T),
|
|
68
|
+
params: P
|
|
69
|
+
): Promise<T> {
|
|
70
|
+
if (typeof config === 'function') {
|
|
71
|
+
const result = (config as (params: P) => T | Promise<T>)(params);
|
|
72
|
+
return Promise.resolve(result);
|
|
73
|
+
}
|
|
74
|
+
return Promise.resolve(config);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export { resolveConfig };
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Create MCP Service (Factory Function)
|
|
81
|
+
* Handles MCP server installation and configuration
|
|
82
|
+
*/
|
|
83
|
+
export const createMCPService = (deps: MCPServiceDeps): MCPService => {
|
|
84
|
+
/**
|
|
85
|
+
* Get all available server IDs from registry
|
|
86
|
+
*/
|
|
87
|
+
const getAllServerIds = (): MCPServerID[] => {
|
|
88
|
+
return Object.keys(MCP_SERVER_REGISTRY) as MCPServerID[];
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Get servers that are not yet installed
|
|
93
|
+
*/
|
|
94
|
+
const getAvailableServers = async (): Promise<MCPServerID[]> => {
|
|
95
|
+
const existingServerIds = await getInstalledServerIds();
|
|
96
|
+
return getAllServerIds().filter((id) => !existingServerIds.includes(id));
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Get currently installed server IDs
|
|
101
|
+
*/
|
|
102
|
+
const getInstalledServerIds = async (): Promise<MCPServerID[]> => {
|
|
103
|
+
try {
|
|
104
|
+
const configData = await deps.target.readConfig(process.cwd());
|
|
105
|
+
const mcpConfigPath = deps.target.config.mcpConfigPath;
|
|
106
|
+
const existingMcpSection = getNestedProperty(configData, mcpConfigPath) || {};
|
|
107
|
+
const existingServerNames = Object.keys(existingMcpSection);
|
|
108
|
+
|
|
109
|
+
return Object.values(MCP_SERVER_REGISTRY)
|
|
110
|
+
.filter((server) => existingServerNames.includes(server.name))
|
|
111
|
+
.map((server) => server.id);
|
|
112
|
+
} catch (_error) {
|
|
113
|
+
return [];
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Get servers that require configuration
|
|
119
|
+
*/
|
|
120
|
+
const getRequiringConfiguration = (serverIds: MCPServerID[]): MCPServerID[] => {
|
|
121
|
+
return serverIds.filter((id) => {
|
|
122
|
+
const server = MCP_SERVER_REGISTRY[id];
|
|
123
|
+
return !!server.envVars;
|
|
124
|
+
});
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Validate server configuration
|
|
129
|
+
*/
|
|
130
|
+
const validateServer = (
|
|
131
|
+
serverId: MCPServerID,
|
|
132
|
+
envValues: Record<string, string>
|
|
133
|
+
): ValidationResult => {
|
|
134
|
+
const server = MCP_SERVER_REGISTRY[serverId];
|
|
135
|
+
if (!server?.envVars) {
|
|
136
|
+
return { isValid: true, missingRequired: [], invalidValues: [] };
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const missingRequired: string[] = [];
|
|
140
|
+
const invalidValues: string[] = [];
|
|
141
|
+
|
|
142
|
+
for (const [key, config] of Object.entries(server.envVars)) {
|
|
143
|
+
const value = envValues[key] || process.env[key] || '';
|
|
144
|
+
|
|
145
|
+
if (config.required && (!value || value === '')) {
|
|
146
|
+
missingRequired.push(key);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Don't validate dependencies here - configureServer already handles them
|
|
150
|
+
// by skipping fields with missing dependencies
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return {
|
|
154
|
+
isValid: missingRequired.length === 0 && invalidValues.length === 0,
|
|
155
|
+
missingRequired,
|
|
156
|
+
invalidValues,
|
|
157
|
+
};
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Configure server through interactive prompts
|
|
162
|
+
*/
|
|
163
|
+
const configureServer = async (
|
|
164
|
+
serverId: MCPServerID,
|
|
165
|
+
collectedEnv: Record<string, string> = {}
|
|
166
|
+
): Promise<Record<string, string>> => {
|
|
167
|
+
const server = MCP_SERVER_REGISTRY[serverId];
|
|
168
|
+
const values: Record<string, string> = {};
|
|
169
|
+
|
|
170
|
+
if (!server.envVars) {
|
|
171
|
+
return values;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
console.log('');
|
|
175
|
+
console.log(chalk.cyan(`▸ ${server.name}`));
|
|
176
|
+
console.log(chalk.gray(` ${server.description}`));
|
|
177
|
+
console.log('');
|
|
178
|
+
|
|
179
|
+
for (const [key, config] of Object.entries(server.envVars)) {
|
|
180
|
+
if (config.dependsOn) {
|
|
181
|
+
const missingDeps = config.dependsOn.filter(
|
|
182
|
+
(dep) => !(collectedEnv[dep] || process.env[dep])
|
|
183
|
+
);
|
|
184
|
+
if (missingDeps.length > 0) {
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Check if value already exists in collectedEnv or process.env
|
|
190
|
+
const existingValue = collectedEnv[key] || process.env[key];
|
|
191
|
+
let value: string;
|
|
192
|
+
|
|
193
|
+
if (existingValue && existingValue.trim() !== '') {
|
|
194
|
+
value = existingValue;
|
|
195
|
+
} else if (config.fetchChoices) {
|
|
196
|
+
const spinner = ora('Fetching options...').start();
|
|
197
|
+
|
|
198
|
+
for (const [envKey, envValue] of Object.entries(collectedEnv)) {
|
|
199
|
+
if (envValue) {
|
|
200
|
+
process.env[envKey] = envValue;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
try {
|
|
205
|
+
const choices = await config.fetchChoices();
|
|
206
|
+
spinner.stop();
|
|
207
|
+
|
|
208
|
+
const answer = await inquirer.prompt({
|
|
209
|
+
type: 'list',
|
|
210
|
+
name: 'value',
|
|
211
|
+
message: `${key}${config.required ? ' *' : ''}`,
|
|
212
|
+
choices,
|
|
213
|
+
default: config.default || choices[0],
|
|
214
|
+
});
|
|
215
|
+
value = answer.value;
|
|
216
|
+
} catch (error) {
|
|
217
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
218
|
+
spinner.fail(chalk.red(`Failed to fetch options: ${errorMsg}`));
|
|
219
|
+
|
|
220
|
+
const answer = await inquirer.prompt({
|
|
221
|
+
type: 'input',
|
|
222
|
+
name: 'value',
|
|
223
|
+
message: `${key}${config.required ? ' *' : ''}`,
|
|
224
|
+
default: config.default,
|
|
225
|
+
});
|
|
226
|
+
value = answer.value;
|
|
227
|
+
}
|
|
228
|
+
} else if (key === 'GEMINI_MODEL') {
|
|
229
|
+
const answer = await inquirer.prompt({
|
|
230
|
+
type: 'list',
|
|
231
|
+
name: 'model',
|
|
232
|
+
message: `${key}${config.required ? ' *' : ''}`,
|
|
233
|
+
choices: ['gemini-2.5-flash', 'gemini-2.5-pro', 'gemini-1.5-flash', 'gemini-1.5-pro'],
|
|
234
|
+
default: config.default || 'gemini-2.5-flash',
|
|
235
|
+
});
|
|
236
|
+
value = answer.model;
|
|
237
|
+
} else {
|
|
238
|
+
const answer = await inquirer.prompt({
|
|
239
|
+
type: config.secret ? 'password' : 'input',
|
|
240
|
+
name: 'value',
|
|
241
|
+
message: `${key}${config.required ? ' *' : ''}`,
|
|
242
|
+
default: config.default,
|
|
243
|
+
mask: config.secret ? '•' : undefined,
|
|
244
|
+
});
|
|
245
|
+
value = answer.value;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (value) {
|
|
249
|
+
values[key] = value;
|
|
250
|
+
collectedEnv[key] = value;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
console.log(chalk.green('✓ Configured'));
|
|
255
|
+
console.log('');
|
|
256
|
+
|
|
257
|
+
return values;
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Install MCP servers to config file
|
|
262
|
+
* Note: Configuration should be done separately before calling this
|
|
263
|
+
*/
|
|
264
|
+
const installServers = async (
|
|
265
|
+
serverIds: MCPServerID[],
|
|
266
|
+
serverConfigs: Record<MCPServerID, Record<string, string>> = {}
|
|
267
|
+
): Promise<void> => {
|
|
268
|
+
if (serverIds.length === 0) {
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
try {
|
|
273
|
+
// Read current config
|
|
274
|
+
const configData = await deps.target.readConfig(process.cwd());
|
|
275
|
+
const mcpConfigPath = deps.target.config.mcpConfigPath;
|
|
276
|
+
const existingMcpSection = getNestedProperty(configData, mcpConfigPath) || {};
|
|
277
|
+
const mcpSection = { ...existingMcpSection };
|
|
278
|
+
|
|
279
|
+
// Add/update each server
|
|
280
|
+
for (const serverId of serverIds) {
|
|
281
|
+
const server = MCP_SERVER_REGISTRY[serverId];
|
|
282
|
+
const configuredValues = serverConfigs[serverId] || {};
|
|
283
|
+
|
|
284
|
+
// Prepare config with environment variables and dynamic command
|
|
285
|
+
let configToTransform = { ...server.config };
|
|
286
|
+
|
|
287
|
+
// Resolve potentially dynamic command and args (only for CLI servers)
|
|
288
|
+
let resolvedCommand: unknown;
|
|
289
|
+
let resolvedArgs: unknown;
|
|
290
|
+
|
|
291
|
+
if (isCLICommandConfig(server.config)) {
|
|
292
|
+
resolvedCommand = server.config.command
|
|
293
|
+
? await resolveConfig(server.config.command)
|
|
294
|
+
: undefined;
|
|
295
|
+
resolvedArgs = server.config.args ? await resolveConfig(server.config.args) : [];
|
|
296
|
+
|
|
297
|
+
// Apply target-specific flags for sylphx-flow server
|
|
298
|
+
if (serverId === 'sylphx-flow' && Array.isArray(resolvedArgs)) {
|
|
299
|
+
const targetConfig = deps.target.mcpServerConfig;
|
|
300
|
+
if (targetConfig) {
|
|
301
|
+
if (targetConfig.disableTime) {
|
|
302
|
+
resolvedArgs.push('--disable-time');
|
|
303
|
+
}
|
|
304
|
+
if (targetConfig.disableKnowledge) {
|
|
305
|
+
resolvedArgs.push('--disable-knowledge');
|
|
306
|
+
}
|
|
307
|
+
if (targetConfig.disableCodebase) {
|
|
308
|
+
resolvedArgs.push('--disable-codebase');
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Update the config with resolved values (only for CLI servers)
|
|
315
|
+
if (isCLICommandConfig(server.config)) {
|
|
316
|
+
configToTransform = {
|
|
317
|
+
...server.config,
|
|
318
|
+
command: resolvedCommand,
|
|
319
|
+
args: resolvedArgs,
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// If server has env vars and we have configured values, merge them
|
|
324
|
+
if (Object.keys(configuredValues).length > 0) {
|
|
325
|
+
const serverConfigEnv =
|
|
326
|
+
server.config.type === 'local'
|
|
327
|
+
? server.config.environment
|
|
328
|
+
: server.config.type === 'stdio'
|
|
329
|
+
? server.config.env
|
|
330
|
+
: {};
|
|
331
|
+
const updatedEnv = { ...serverConfigEnv };
|
|
332
|
+
|
|
333
|
+
for (const [key, value] of Object.entries(configuredValues)) {
|
|
334
|
+
if (value && value.trim() !== '') {
|
|
335
|
+
updatedEnv[key] = value;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
if (configToTransform.type === 'local') {
|
|
340
|
+
configToTransform.environment = updatedEnv;
|
|
341
|
+
} else if (configToTransform.type === 'stdio') {
|
|
342
|
+
configToTransform.env = updatedEnv;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// Transform config for target-specific format
|
|
347
|
+
const transformedConfig = deps.target.transformMCPConfig(configToTransform, serverId);
|
|
348
|
+
|
|
349
|
+
mcpSection[server.name] = transformedConfig;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// Write updated config
|
|
353
|
+
setNestedProperty(configData, mcpConfigPath, mcpSection);
|
|
354
|
+
await deps.target.writeConfig(process.cwd(), configData);
|
|
355
|
+
|
|
356
|
+
// Approve MCP servers if the target supports it
|
|
357
|
+
if (deps.target.approveMCPServers) {
|
|
358
|
+
const serverNames = serverIds.map((id) => MCP_SERVER_REGISTRY[id].name);
|
|
359
|
+
await deps.target.approveMCPServers(process.cwd(), serverNames);
|
|
360
|
+
}
|
|
361
|
+
} catch (error) {
|
|
362
|
+
throw new Error(
|
|
363
|
+
`Failed to install MCP servers: ${error instanceof Error ? error.message : String(error)}`
|
|
364
|
+
);
|
|
365
|
+
}
|
|
366
|
+
};
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Read target configuration
|
|
370
|
+
*/
|
|
371
|
+
const readConfig = async (): Promise<TargetConfigurationData> => {
|
|
372
|
+
try {
|
|
373
|
+
return (await deps.target.readConfig(process.cwd())) as TargetConfigurationData;
|
|
374
|
+
} catch (_error) {
|
|
375
|
+
return { settings: {} };
|
|
376
|
+
}
|
|
377
|
+
};
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Write target configuration
|
|
381
|
+
*/
|
|
382
|
+
const writeConfig = async (configData: TargetConfigurationData): Promise<void> => {
|
|
383
|
+
await deps.target.writeConfig(process.cwd(), configData);
|
|
384
|
+
};
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Get nested property from object using dot notation path
|
|
388
|
+
* Pure function - does not mutate input
|
|
389
|
+
*/
|
|
390
|
+
const getNestedProperty = (obj: TargetConfigurationData, path: string): unknown => {
|
|
391
|
+
return path.split('.').reduce((current: unknown, key: string) => {
|
|
392
|
+
if (typeof current === 'object' && current !== null) {
|
|
393
|
+
return (current as Record<string, unknown>)[key];
|
|
394
|
+
}
|
|
395
|
+
return undefined;
|
|
396
|
+
}, obj);
|
|
397
|
+
};
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Set nested property in object using dot notation path
|
|
401
|
+
* SIDE EFFECT: Mutates the input object
|
|
402
|
+
* NOTE: This is intentional for config file updates
|
|
403
|
+
*/
|
|
404
|
+
const setNestedProperty = (obj: TargetConfigurationData, path: string, value: unknown): void => {
|
|
405
|
+
const keys = path.split('.');
|
|
406
|
+
const lastKey = keys.pop();
|
|
407
|
+
if (!lastKey) {
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
const target = keys.reduce((current, key) => {
|
|
412
|
+
if (!current[key]) {
|
|
413
|
+
current[key] = {};
|
|
414
|
+
}
|
|
415
|
+
return current[key];
|
|
416
|
+
}, obj);
|
|
417
|
+
target[lastKey] = value;
|
|
418
|
+
};
|
|
419
|
+
|
|
420
|
+
// Return service interface
|
|
421
|
+
return {
|
|
422
|
+
getAllServerIds,
|
|
423
|
+
getAvailableServers,
|
|
424
|
+
getInstalledServerIds,
|
|
425
|
+
getRequiringConfiguration,
|
|
426
|
+
validateServer,
|
|
427
|
+
configureServer,
|
|
428
|
+
installServers,
|
|
429
|
+
readConfig,
|
|
430
|
+
writeConfig,
|
|
431
|
+
};
|
|
432
|
+
};
|