@sylphx/flow 3.19.0 â 3.19.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/package.json +1 -3
- package/src/commands/flow/execute-v2.ts +126 -128
- package/src/commands/flow-command.ts +52 -42
- package/src/config/index.ts +0 -20
- package/src/core/agent-loader.ts +2 -2
- package/src/core/attach-manager.ts +5 -1
- package/src/core/cleanup-handler.ts +20 -16
- package/src/core/flow-executor.ts +93 -62
- package/src/core/functional/index.ts +0 -11
- package/src/core/index.ts +1 -1
- package/src/core/project-manager.ts +14 -29
- package/src/core/secrets-manager.ts +15 -18
- package/src/core/session-manager.ts +4 -8
- package/src/core/target-manager.ts +6 -3
- package/src/core/upgrade-manager.ts +1 -1
- package/src/index.ts +1 -1
- package/src/services/auto-upgrade.ts +6 -14
- package/src/services/config-service.ts +7 -23
- package/src/services/index.ts +1 -1
- package/src/targets/claude-code.ts +14 -8
- package/src/targets/opencode.ts +61 -39
- package/src/targets/shared/mcp-transforms.ts +20 -43
- package/src/types/agent.types.ts +5 -3
- package/src/types/mcp.types.ts +38 -1
- package/src/types.ts +4 -0
- package/src/utils/agent-enhancer.ts +1 -1
- package/src/utils/errors.ts +13 -0
- package/src/utils/files/file-operations.ts +16 -0
- package/src/utils/index.ts +1 -1
- package/src/core/error-handling.ts +0 -482
- package/src/core/functional/async.ts +0 -101
- package/src/core/functional/either.ts +0 -109
- package/src/core/functional/error-handler.ts +0 -135
- package/src/core/functional/pipe.ts +0 -189
- package/src/core/functional/validation.ts +0 -138
- package/src/types/mcp-config.types.ts +0 -448
- package/src/utils/error-handler.ts +0 -53
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
# @sylphx/flow
|
|
2
2
|
|
|
3
|
+
## 3.19.1 (2026-02-07)
|
|
4
|
+
|
|
5
|
+
### ð Bug Fixes
|
|
6
|
+
|
|
7
|
+
- add missing .js extensions to barrel exports ([54c4bb1](https://github.com/SylphxAI/flow/commit/54c4bb1bba79eb5b2e0d8ba06a7bf1486be5302c))
|
|
8
|
+
- replace silent catch blocks with debug logging ([fe5a646](https://github.com/SylphxAI/flow/commit/fe5a646c180e87242034228c2472d1a0a1bd8dda))
|
|
9
|
+
|
|
10
|
+
### â»ïž Refactoring
|
|
11
|
+
|
|
12
|
+
- rename AgentMetadata to AgentDefinition in agent.types.ts ([01c16c9](https://github.com/SylphxAI/flow/commit/01c16c984b3e7ec7d318016e018d7db957ea140a))
|
|
13
|
+
- extract readJsonFileSafe for repeated JSON-read-with-fallback pattern ([22088ed](https://github.com/SylphxAI/flow/commit/22088ed4d24cbfda2dc70f77dd2ae3e6f1ac111e))
|
|
14
|
+
- remove unused functional modules and fix config barrel exports ([2f9f5b2](https://github.com/SylphxAI/flow/commit/2f9f5b242b9d9149630f8d933db788f862a8cebb))
|
|
15
|
+
- extract convertServerSecrets from opencode writeConfig ([af7eac7](https://github.com/SylphxAI/flow/commit/af7eac7211d9067580a476683610da7f73c962e0))
|
|
16
|
+
- extract health check functions from doctorCommand ([7debe50](https://github.com/SylphxAI/flow/commit/7debe50559c25c4e2ee2486eb1bfc329c32b178c))
|
|
17
|
+
- extract tryJoinExistingSession and createNewSession from flow-executor ([5e25da8](https://github.com/SylphxAI/flow/commit/5e25da895e9bc216865f1e9810c21effd0878322))
|
|
18
|
+
- extract selectTarget and loadAgent from executeFlowV2 ([9735cf0](https://github.com/SylphxAI/flow/commit/9735cf04c1ef43f6842b5ac5deafc3b0e04aecbb))
|
|
19
|
+
|
|
20
|
+
### ð
Styles
|
|
21
|
+
|
|
22
|
+
- **flow:** format package.json with biome (tabs â spaces) ([7aeac4c](https://github.com/SylphxAI/flow/commit/7aeac4cf1d946ec3af82ae20b6215482d989a38f))
|
|
23
|
+
|
|
24
|
+
### ð§ Chores
|
|
25
|
+
|
|
26
|
+
- remove 35 unused dependencies ([55318b0](https://github.com/SylphxAI/flow/commit/55318b0f3215bf47d1875bd07b9fcdad094620c4))
|
|
27
|
+
|
|
3
28
|
## 3.19.0 (2026-02-07)
|
|
4
29
|
|
|
5
30
|
Performance, stability, and test coverage overhaul
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sylphx/flow",
|
|
3
|
-
"version": "3.19.
|
|
3
|
+
"version": "3.19.1",
|
|
4
4
|
"description": "One CLI to rule them all. Unified orchestration layer for AI coding assistants. Auto-detection, auto-installation, auto-upgrade.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -26,11 +26,9 @@
|
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
28
|
"@clack/prompts": "^0.9.0",
|
|
29
|
-
"boxen": "^8.0.1",
|
|
30
29
|
"chalk": "^5.6.2",
|
|
31
30
|
"commander": "^14.0.2",
|
|
32
31
|
"debug": "^4.4.3",
|
|
33
|
-
"gradient-string": "^3.0.0",
|
|
34
32
|
"gray-matter": "^4.0.3",
|
|
35
33
|
"pino": "^9.0.0",
|
|
36
34
|
"pino-pretty": "^11.0.0",
|
|
@@ -3,11 +3,15 @@
|
|
|
3
3
|
* Minimal, modern CLI output design
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import fs from 'node:fs/promises';
|
|
7
6
|
import path from 'node:path';
|
|
8
7
|
import { fileURLToPath } from 'node:url';
|
|
9
8
|
import chalk from 'chalk';
|
|
9
|
+
import createDebug from 'debug';
|
|
10
10
|
import { FlowExecutor } from '../../core/flow-executor.js';
|
|
11
|
+
import { readJsonFileSafe } from '../../utils/files/file-operations.js';
|
|
12
|
+
|
|
13
|
+
const debug = createDebug('flow:execute');
|
|
14
|
+
|
|
11
15
|
import { targetManager } from '../../core/target-manager.js';
|
|
12
16
|
import { AutoUpgrade } from '../../services/auto-upgrade.js';
|
|
13
17
|
import { GlobalConfigService } from '../../services/global-config.js';
|
|
@@ -15,8 +19,7 @@ import { TargetInstaller } from '../../services/target-installer.js';
|
|
|
15
19
|
import type { RunCommandOptions } from '../../types.js';
|
|
16
20
|
import { extractAgentInstructions, loadAgentContent } from '../../utils/agent-enhancer.js';
|
|
17
21
|
import { showAttachSummary, showHeader } from '../../utils/display/banner.js';
|
|
18
|
-
import { CLIError } from '../../utils/
|
|
19
|
-
import { UserCancelledError } from '../../utils/errors.js';
|
|
22
|
+
import { CLIError, UserCancelledError } from '../../utils/errors.js';
|
|
20
23
|
import { log, promptConfirm, promptSelect } from '../../utils/prompts/index.js';
|
|
21
24
|
import { ensureTargetInstalled, promptForTargetSelection } from '../../utils/target-selection.js';
|
|
22
25
|
import { resolvePrompt } from './prompt.js';
|
|
@@ -29,13 +32,9 @@ const __dirname = path.dirname(__filename);
|
|
|
29
32
|
* Get Flow version from package.json
|
|
30
33
|
*/
|
|
31
34
|
async function getFlowVersion(): Promise<string> {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
return packageJson.version;
|
|
36
|
-
} catch {
|
|
37
|
-
return 'unknown';
|
|
38
|
-
}
|
|
35
|
+
const packageJsonPath = path.join(__dirname, '..', '..', '..', 'package.json');
|
|
36
|
+
const pkg = await readJsonFileSafe<{ version?: string }>(packageJsonPath, {});
|
|
37
|
+
return pkg.version ?? 'unknown';
|
|
39
38
|
}
|
|
40
39
|
|
|
41
40
|
/**
|
|
@@ -138,6 +137,106 @@ function executeTargetCommand(
|
|
|
138
137
|
return target.executeCommand(systemPrompt, userPrompt, options);
|
|
139
138
|
}
|
|
140
139
|
|
|
140
|
+
/**
|
|
141
|
+
* Select target based on user settings, installed targets, and prompts
|
|
142
|
+
*/
|
|
143
|
+
async function selectTarget(
|
|
144
|
+
installedTargets: string[],
|
|
145
|
+
settings: import('../../services/global-config.js').GlobalSettings,
|
|
146
|
+
configService: GlobalConfigService,
|
|
147
|
+
targetInstaller: TargetInstaller
|
|
148
|
+
): Promise<string | null> {
|
|
149
|
+
if (settings.defaultTarget === 'ask-every-time') {
|
|
150
|
+
const targetId = await promptForTargetSelection(
|
|
151
|
+
installedTargets,
|
|
152
|
+
'Select AI CLI:',
|
|
153
|
+
'execution'
|
|
154
|
+
);
|
|
155
|
+
const installed = await ensureTargetInstalled(targetId, targetInstaller, installedTargets);
|
|
156
|
+
if (!installed) {
|
|
157
|
+
process.exit(1);
|
|
158
|
+
}
|
|
159
|
+
return targetId;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (!settings.defaultTarget) {
|
|
163
|
+
if (installedTargets.length === 1) {
|
|
164
|
+
const targetId = installedTargets[0];
|
|
165
|
+
settings.defaultTarget = targetId as 'claude-code' | 'opencode';
|
|
166
|
+
await configService.saveSettings(settings);
|
|
167
|
+
return targetId;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const targetId = await promptForTargetSelection(
|
|
171
|
+
installedTargets,
|
|
172
|
+
'Select AI CLI:',
|
|
173
|
+
'execution'
|
|
174
|
+
);
|
|
175
|
+
const installed = await ensureTargetInstalled(targetId, targetInstaller, installedTargets);
|
|
176
|
+
if (!installed) {
|
|
177
|
+
process.exit(1);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const rememberChoice = await promptConfirm({
|
|
181
|
+
message: 'Remember this choice?',
|
|
182
|
+
initialValue: true,
|
|
183
|
+
});
|
|
184
|
+
if (rememberChoice) {
|
|
185
|
+
settings.defaultTarget = targetId as 'claude-code' | 'opencode';
|
|
186
|
+
await configService.saveSettings(settings);
|
|
187
|
+
}
|
|
188
|
+
return targetId;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// User has a specific target preference
|
|
192
|
+
const targetId = settings.defaultTarget;
|
|
193
|
+
if (!installedTargets.includes(targetId)) {
|
|
194
|
+
const installation = targetInstaller.getInstallationInfo(targetId);
|
|
195
|
+
log.warn(`${installation?.name} not installed`);
|
|
196
|
+
const installed = await targetInstaller.install(targetId, true);
|
|
197
|
+
if (!installed) {
|
|
198
|
+
log.error('Cannot proceed: installation failed');
|
|
199
|
+
process.exit(1);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return targetId;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Load agent and build system prompt
|
|
207
|
+
*/
|
|
208
|
+
async function loadAgent(
|
|
209
|
+
options: FlowOptions,
|
|
210
|
+
settings: import('../../services/global-config.js').GlobalSettings,
|
|
211
|
+
configService: GlobalConfigService
|
|
212
|
+
): Promise<{ agent: string; systemPrompt: string }> {
|
|
213
|
+
const flowConfig = await configService.loadFlowConfig();
|
|
214
|
+
let agent = options.agent || settings.defaultAgent || 'builder';
|
|
215
|
+
|
|
216
|
+
if (!flowConfig.agents[agent]?.enabled) {
|
|
217
|
+
const enabledAgents = await configService.getEnabledAgents();
|
|
218
|
+
agent = enabledAgents.length > 0 ? enabledAgents[0] : 'builder';
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const [enabledRules, enabledOutputStyles] = await Promise.all([
|
|
222
|
+
configService.getEnabledRules(),
|
|
223
|
+
configService.getEnabledOutputStyles(),
|
|
224
|
+
]);
|
|
225
|
+
|
|
226
|
+
const agentContent = await loadAgentContent(
|
|
227
|
+
agent,
|
|
228
|
+
options.agentFile,
|
|
229
|
+
enabledRules,
|
|
230
|
+
enabledOutputStyles
|
|
231
|
+
);
|
|
232
|
+
const agentInstructions = extractAgentInstructions(agentContent);
|
|
233
|
+
|
|
234
|
+
return {
|
|
235
|
+
agent,
|
|
236
|
+
systemPrompt: `AGENT INSTRUCTIONS:\n${agentInstructions}`,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
|
|
141
240
|
/**
|
|
142
241
|
* Main flow execution with attach mode (V2) - Minimal output design
|
|
143
242
|
*/
|
|
@@ -158,79 +257,12 @@ export async function executeFlowV2(
|
|
|
158
257
|
getFlowVersion(),
|
|
159
258
|
]);
|
|
160
259
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
if (isAskEveryTime) {
|
|
168
|
-
// User explicitly wants to be asked every time
|
|
169
|
-
selectedTargetId = await promptForTargetSelection(
|
|
170
|
-
installedTargets,
|
|
171
|
-
'Select AI CLI:',
|
|
172
|
-
'execution'
|
|
173
|
-
);
|
|
174
|
-
|
|
175
|
-
const installed = await ensureTargetInstalled(
|
|
176
|
-
selectedTargetId,
|
|
177
|
-
targetInstaller,
|
|
178
|
-
installedTargets
|
|
179
|
-
);
|
|
180
|
-
|
|
181
|
-
if (!installed) {
|
|
182
|
-
process.exit(1);
|
|
183
|
-
}
|
|
184
|
-
} else if (hasNoSetting) {
|
|
185
|
-
// No setting - use auto-detection or prompt
|
|
186
|
-
if (installedTargets.length === 1) {
|
|
187
|
-
// Single target: auto-select and save silently
|
|
188
|
-
selectedTargetId = installedTargets[0];
|
|
189
|
-
settings.defaultTarget = selectedTargetId as 'claude-code' | 'opencode';
|
|
190
|
-
await configService.saveSettings(settings);
|
|
191
|
-
} else {
|
|
192
|
-
// Multiple targets: prompt and ask to remember
|
|
193
|
-
selectedTargetId = await promptForTargetSelection(
|
|
194
|
-
installedTargets,
|
|
195
|
-
'Select AI CLI:',
|
|
196
|
-
'execution'
|
|
197
|
-
);
|
|
198
|
-
|
|
199
|
-
const installed = await ensureTargetInstalled(
|
|
200
|
-
selectedTargetId,
|
|
201
|
-
targetInstaller,
|
|
202
|
-
installedTargets
|
|
203
|
-
);
|
|
204
|
-
|
|
205
|
-
if (!installed) {
|
|
206
|
-
process.exit(1);
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
const rememberChoice = await promptConfirm({
|
|
210
|
-
message: 'Remember this choice?',
|
|
211
|
-
initialValue: true,
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
if (rememberChoice) {
|
|
215
|
-
settings.defaultTarget = selectedTargetId as 'claude-code' | 'opencode';
|
|
216
|
-
await configService.saveSettings(settings);
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
} else if (hasSpecificTarget) {
|
|
220
|
-
// User has a specific target preference
|
|
221
|
-
selectedTargetId = settings.defaultTarget;
|
|
222
|
-
|
|
223
|
-
if (!installedTargets.includes(selectedTargetId)) {
|
|
224
|
-
const installation = targetInstaller.getInstallationInfo(selectedTargetId);
|
|
225
|
-
log.warn(`${installation?.name} not installed`);
|
|
226
|
-
const installed = await targetInstaller.install(selectedTargetId, true);
|
|
227
|
-
|
|
228
|
-
if (!installed) {
|
|
229
|
-
log.error('Cannot proceed: installation failed');
|
|
230
|
-
process.exit(1);
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
}
|
|
260
|
+
const selectedTargetId = await selectTarget(
|
|
261
|
+
installedTargets,
|
|
262
|
+
settings,
|
|
263
|
+
configService,
|
|
264
|
+
targetInstaller
|
|
265
|
+
);
|
|
234
266
|
|
|
235
267
|
// Get target name for header
|
|
236
268
|
const targetInstallation = targetInstaller.getInstallationInfo(selectedTargetId);
|
|
@@ -239,63 +271,34 @@ export async function executeFlowV2(
|
|
|
239
271
|
// Show minimal header
|
|
240
272
|
showHeader(version, targetName);
|
|
241
273
|
|
|
242
|
-
//
|
|
274
|
+
// Start background auto-upgrade (non-blocking)
|
|
243
275
|
new AutoUpgrade().start();
|
|
244
276
|
|
|
245
|
-
// Create executor
|
|
246
277
|
const executor = new FlowExecutor();
|
|
247
278
|
|
|
248
|
-
// Step 3: Execute attach mode lifecycle
|
|
249
279
|
try {
|
|
250
280
|
// Attach Flow environment (backup â attach â register cleanup)
|
|
251
281
|
const attachResult = await executor.execute(projectPath, {
|
|
252
282
|
verbose: options.verbose,
|
|
253
283
|
skipBackup: false,
|
|
254
284
|
skipSecrets: false,
|
|
255
|
-
skipProjectDocs: true,
|
|
285
|
+
skipProjectDocs: true,
|
|
256
286
|
merge: options.merge || false,
|
|
257
287
|
});
|
|
258
288
|
|
|
259
|
-
// Show attach summary
|
|
260
289
|
showAttachSummary(attachResult);
|
|
261
290
|
|
|
262
|
-
const targetId = selectedTargetId;
|
|
263
|
-
|
|
264
291
|
// Provider selection (Claude Code only, silent unless prompting)
|
|
265
|
-
if (
|
|
292
|
+
if (selectedTargetId === 'claude-code') {
|
|
266
293
|
await selectProvider(configService);
|
|
267
294
|
}
|
|
268
295
|
|
|
269
|
-
//
|
|
270
|
-
const
|
|
271
|
-
let agent = options.agent || settings.defaultAgent || 'builder';
|
|
272
|
-
|
|
273
|
-
// Check if agent is enabled (silent fallback)
|
|
274
|
-
if (!flowConfig.agents[agent]?.enabled) {
|
|
275
|
-
const enabledAgents = await configService.getEnabledAgents();
|
|
276
|
-
agent = enabledAgents.length > 0 ? enabledAgents[0] : 'builder';
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
// Load agent content (parallel fetch rules and styles)
|
|
280
|
-
const [enabledRules, enabledOutputStyles] = await Promise.all([
|
|
281
|
-
configService.getEnabledRules(),
|
|
282
|
-
configService.getEnabledOutputStyles(),
|
|
283
|
-
]);
|
|
284
|
-
|
|
285
|
-
const agentContent = await loadAgentContent(
|
|
286
|
-
agent,
|
|
287
|
-
options.agentFile,
|
|
288
|
-
enabledRules,
|
|
289
|
-
enabledOutputStyles
|
|
290
|
-
);
|
|
291
|
-
const agentInstructions = extractAgentInstructions(agentContent);
|
|
292
|
-
|
|
293
|
-
const systemPrompt = `AGENT INSTRUCTIONS:\n${agentInstructions}`;
|
|
296
|
+
// Load agent and build prompts
|
|
297
|
+
const { agent, systemPrompt } = await loadAgent(options, settings, configService);
|
|
294
298
|
const userPrompt = prompt?.trim() || '';
|
|
295
299
|
|
|
296
|
-
// Prepare run options
|
|
297
300
|
const runOptions: RunCommandOptions = {
|
|
298
|
-
target:
|
|
301
|
+
target: selectedTargetId,
|
|
299
302
|
verbose: options.verbose || false,
|
|
300
303
|
dryRun: options.dryRun || false,
|
|
301
304
|
agent,
|
|
@@ -305,30 +308,25 @@ export async function executeFlowV2(
|
|
|
305
308
|
continue: options.continue,
|
|
306
309
|
};
|
|
307
310
|
|
|
308
|
-
|
|
309
|
-
await executeTargetCommand(targetId, systemPrompt, userPrompt, runOptions);
|
|
310
|
-
|
|
311
|
-
// Step 5: Cleanup (silent)
|
|
311
|
+
await executeTargetCommand(selectedTargetId, systemPrompt, userPrompt, runOptions);
|
|
312
312
|
await executor.cleanup(projectPath);
|
|
313
313
|
} catch (error) {
|
|
314
|
-
// Handle user cancellation gracefully
|
|
315
314
|
if (error instanceof UserCancelledError) {
|
|
316
315
|
log.warn('Cancelled');
|
|
317
316
|
try {
|
|
318
317
|
await executor.cleanup(projectPath);
|
|
319
|
-
} catch {
|
|
320
|
-
|
|
318
|
+
} catch (cleanupError) {
|
|
319
|
+
debug('cleanup after cancel failed:', cleanupError);
|
|
321
320
|
}
|
|
322
321
|
process.exit(0);
|
|
323
322
|
}
|
|
324
323
|
|
|
325
324
|
console.error(chalk.red('\n Error:'), error);
|
|
326
325
|
|
|
327
|
-
// Ensure cleanup even on error
|
|
328
326
|
try {
|
|
329
327
|
await executor.cleanup(projectPath);
|
|
330
|
-
} catch {
|
|
331
|
-
|
|
328
|
+
} catch (cleanupError) {
|
|
329
|
+
debug('cleanup after error failed:', cleanupError);
|
|
332
330
|
}
|
|
333
331
|
|
|
334
332
|
throw error;
|
|
@@ -81,6 +81,53 @@ export const statusCommand = new Command('status')
|
|
|
81
81
|
}
|
|
82
82
|
});
|
|
83
83
|
|
|
84
|
+
async function checkClaudeCodeInstalled(): Promise<boolean> {
|
|
85
|
+
console.log('æ£æ¥ Claude Code å®è£
...');
|
|
86
|
+
try {
|
|
87
|
+
const { exec } = await import('node:child_process');
|
|
88
|
+
const { promisify } = await import('node:util');
|
|
89
|
+
const execAsync = promisify(exec);
|
|
90
|
+
await execAsync('which claude');
|
|
91
|
+
console.log(chalk.green(' â Claude Code å·²å®è£
'));
|
|
92
|
+
return true;
|
|
93
|
+
} catch {
|
|
94
|
+
console.log(chalk.red(' â Claude Code æªå®è£
'));
|
|
95
|
+
console.log(chalk.dim(' è¿è¡: npm install -g @anthropic-ai/claude-code'));
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async function checkConfiguration(
|
|
101
|
+
state: Awaited<ReturnType<StateDetector['detect']>>,
|
|
102
|
+
fix: boolean
|
|
103
|
+
): Promise<boolean> {
|
|
104
|
+
console.log('\næ£æ¥é
眮...');
|
|
105
|
+
if (state.corrupted) {
|
|
106
|
+
console.log(chalk.red(' â é
眮æå'));
|
|
107
|
+
if (fix) {
|
|
108
|
+
console.log(chalk.yellow(' ð æ£åšä¿®å€...'));
|
|
109
|
+
await executeFlow(undefined, { sync: true });
|
|
110
|
+
console.log(chalk.green(' â 已修å€'));
|
|
111
|
+
}
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
if (state.initialized) {
|
|
115
|
+
console.log(chalk.green(' â é
眮æ£åžž'));
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
console.log(chalk.yellow(' â é¡¹ç®æªåå§å'));
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function checkComponents(state: Awaited<ReturnType<StateDetector['detect']>>): void {
|
|
123
|
+
console.log('\næ£æ¥ç»ä»¶...');
|
|
124
|
+
for (const [name, component] of Object.entries(state.components)) {
|
|
125
|
+
const status = component.installed ? chalk.green('â') : chalk.red('â');
|
|
126
|
+
const count = 'count' in component && component.count ? ` (${component.count})` : '';
|
|
127
|
+
console.log(` ${status} ${name}${count}`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
84
131
|
/**
|
|
85
132
|
* Doctor command - diagnose and fix issues
|
|
86
133
|
*/
|
|
@@ -94,49 +141,12 @@ export const doctorCommand = new Command('doctor')
|
|
|
94
141
|
const detector = new StateDetector();
|
|
95
142
|
const state = await detector.detect();
|
|
96
143
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
console.log('æ£æ¥ Claude Code å®è£
...');
|
|
101
|
-
try {
|
|
102
|
-
const { exec } = await import('node:child_process');
|
|
103
|
-
const { promisify } = await import('node:util');
|
|
104
|
-
const execAsync = promisify(exec);
|
|
105
|
-
await execAsync('which claude');
|
|
106
|
-
console.log(chalk.green(' â Claude Code å·²å®è£
'));
|
|
107
|
-
} catch {
|
|
108
|
-
console.log(chalk.red(' â Claude Code æªå®è£
'));
|
|
109
|
-
console.log(chalk.dim(' è¿è¡: npm install -g @anthropic-ai/claude-code'));
|
|
110
|
-
issuesFound = true;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// Check 2: Configuration
|
|
114
|
-
console.log('\næ£æ¥é
眮...');
|
|
115
|
-
if (state.corrupted) {
|
|
116
|
-
console.log(chalk.red(' â é
眮æå'));
|
|
117
|
-
issuesFound = true;
|
|
118
|
-
|
|
119
|
-
if (options.fix) {
|
|
120
|
-
console.log(chalk.yellow(' ð æ£åšä¿®å€...'));
|
|
121
|
-
await executeFlow(undefined, { sync: true } as FlowOptions);
|
|
122
|
-
console.log(chalk.green(' â 已修å€'));
|
|
123
|
-
}
|
|
124
|
-
} else if (state.initialized) {
|
|
125
|
-
console.log(chalk.green(' â é
眮æ£åžž'));
|
|
126
|
-
} else {
|
|
127
|
-
console.log(chalk.yellow(' â é¡¹ç®æªåå§å'));
|
|
128
|
-
issuesFound = true;
|
|
129
|
-
}
|
|
144
|
+
const installOk = await checkClaudeCodeInstalled();
|
|
145
|
+
const configOk = await checkConfiguration(state, options.fix);
|
|
146
|
+
checkComponents(state);
|
|
130
147
|
|
|
131
|
-
|
|
132
|
-
console.log('\næ£æ¥ç»ä»¶...');
|
|
133
|
-
Object.entries(state.components).forEach(([name, component]) => {
|
|
134
|
-
const status = component.installed ? chalk.green('â') : chalk.red('â');
|
|
135
|
-
const count = 'count' in component && component.count ? ` (${component.count})` : '';
|
|
136
|
-
console.log(` ${status} ${name}${count}`);
|
|
137
|
-
});
|
|
148
|
+
const issuesFound = !installOk || !configOk;
|
|
138
149
|
|
|
139
|
-
// Summary
|
|
140
150
|
console.log(`\n${chalk.bold('ç»æ:')}`);
|
|
141
151
|
if (!issuesFound) {
|
|
142
152
|
console.log(chalk.green('â æææ£æ¥éè¿'));
|
|
@@ -241,7 +251,7 @@ export const quickstartCommand = new Command('quickstart')
|
|
|
241
251
|
|
|
242
252
|
if (tryNow) {
|
|
243
253
|
console.log(chalk.dim('\nLaunching Flow...\n'));
|
|
244
|
-
await executeFlow('describe this codebase briefly', { agent: 'builder' }
|
|
254
|
+
await executeFlow('describe this codebase briefly', { agent: 'builder' });
|
|
245
255
|
} else {
|
|
246
256
|
console.log(chalk.green("\nâš You're ready to go!\n"));
|
|
247
257
|
console.log(chalk.dim(' Run: sylphx-flow "your first task"\n'));
|
package/src/config/index.ts
CHANGED
|
@@ -1,27 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Configuration modules barrel export
|
|
3
|
-
* Centralized access to configuration-related functionality
|
|
4
3
|
*/
|
|
5
4
|
|
|
6
|
-
// Rules configuration
|
|
7
5
|
export * from './rules.js';
|
|
8
|
-
export {
|
|
9
|
-
getDefaultRules,
|
|
10
|
-
loadRuleConfiguration,
|
|
11
|
-
validateRuleConfiguration,
|
|
12
|
-
} from './rules.js';
|
|
13
|
-
// MCP server configurations
|
|
14
6
|
export * from './servers.js';
|
|
15
|
-
export {
|
|
16
|
-
configureServer,
|
|
17
|
-
getServerConfigurations,
|
|
18
|
-
validateServerConfiguration,
|
|
19
|
-
} from './servers.js';
|
|
20
|
-
// Target configurations
|
|
21
7
|
export * from './targets.js';
|
|
22
|
-
// Re-export commonly used configuration functions with better naming
|
|
23
|
-
export {
|
|
24
|
-
configureTargetDefaults,
|
|
25
|
-
getTargetDefaults,
|
|
26
|
-
validateTargetConfiguration,
|
|
27
|
-
} from './targets.js';
|
package/src/core/agent-loader.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { homedir } from 'node:os';
|
|
|
8
8
|
import { dirname, join, parse, relative } from 'node:path';
|
|
9
9
|
import { fileURLToPath } from 'node:url';
|
|
10
10
|
import matter from 'gray-matter';
|
|
11
|
-
import type { Agent,
|
|
11
|
+
import type { Agent, AgentDefinition } from '../types/agent.types.js';
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* Load a single agent from a markdown file
|
|
@@ -28,7 +28,7 @@ export async function loadAgentFromFile(
|
|
|
28
28
|
return null;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
const metadata:
|
|
31
|
+
const metadata: AgentDefinition = {
|
|
32
32
|
name: data.name,
|
|
33
33
|
description: data.description || '',
|
|
34
34
|
};
|
|
@@ -10,6 +10,7 @@ import fs from 'node:fs/promises';
|
|
|
10
10
|
import path from 'node:path';
|
|
11
11
|
import { MCP_SERVER_REGISTRY, type MCPServerID } from '../config/servers.js';
|
|
12
12
|
import { GlobalConfigService } from '../services/global-config.js';
|
|
13
|
+
import type { MCPServerConfigUnion } from '../types/mcp.types.js';
|
|
13
14
|
import type { Target } from '../types/target.types.js';
|
|
14
15
|
import { attachItemsToDir, attachRulesFile } from './attach/index.js';
|
|
15
16
|
import type { BackupManifest } from './backup-manager.js';
|
|
@@ -320,7 +321,10 @@ export class AttachManager {
|
|
|
320
321
|
// Add Flow MCP servers
|
|
321
322
|
for (const server of mcpServers) {
|
|
322
323
|
// Transform the server config for this target
|
|
323
|
-
const transformedConfig = target.transformMCPConfig(
|
|
324
|
+
const transformedConfig = target.transformMCPConfig(
|
|
325
|
+
server.config as MCPServerConfigUnion,
|
|
326
|
+
server.name
|
|
327
|
+
);
|
|
324
328
|
|
|
325
329
|
if (mcpContainer[server.name]) {
|
|
326
330
|
// Conflict: user has same MCP server
|