@sylphx/flow 1.2.0 → 1.3.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/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # @sylphx/flow
2
2
 
3
+ ## 1.3.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Enhanced --sync with MCP registry checking:
8
+ - Detect servers not in Flow registry (removed or custom)
9
+ - Interactive selection for removal
10
+ - Clean removal from .mcp.json
11
+ - Flow: sync templates → check MCP → remove selected
12
+
13
+ ## 1.2.1
14
+
15
+ ### Patch Changes
16
+
17
+ - Apply MEP principles to workspace documentation rule:
18
+ - Condensed from verbose instructions to condition→action format
19
+ - Removed step-by-step teaching and command examples
20
+ - Embedded verification in directives
21
+ - 31% reduction while maintaining clarity
22
+
3
23
  ## 1.2.0
4
24
 
5
25
  ### Minor Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sylphx/flow",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "AI-powered development workflow automation with autonomous loop mode and smart configuration",
5
5
  "type": "module",
6
6
  "bin": {
@@ -405,6 +405,20 @@ async function executeSetupPhase(prompt: string | undefined, options: FlowOption
405
405
 
406
406
  const deletedCount = await executeSyncDelete(manifest);
407
407
  console.log(chalk.green(`\n✓ Deleted ${deletedCount} files\n`));
408
+
409
+ // Check MCP servers
410
+ const { checkMCPServers, showNonRegistryServers, selectServersToRemove, removeMCPServers } = await import('../utils/sync-utils.js');
411
+ const nonRegistryServers = await checkMCPServers(process.cwd());
412
+
413
+ if (nonRegistryServers.length > 0) {
414
+ showNonRegistryServers(nonRegistryServers);
415
+ const serversToRemove = await selectServersToRemove(nonRegistryServers);
416
+
417
+ if (serversToRemove.length > 0) {
418
+ const removedCount = await removeMCPServers(process.cwd(), serversToRemove);
419
+ console.log(chalk.green(`\n✓ Removed ${removedCount} MCP server(s)\n`));
420
+ }
421
+ }
408
422
  } else if (!options.sync) {
409
423
  const targetId = await selectAndValidateTarget(initOptions);
410
424
  selectedTarget = targetId;
@@ -720,6 +734,20 @@ async function executeFlowOnce(prompt: string | undefined, options: FlowOptions)
720
734
 
721
735
  const deletedCount = await executeSyncDelete(manifest);
722
736
  console.log(chalk.green(`\n✓ Deleted ${deletedCount} files\n`));
737
+
738
+ // Check MCP servers
739
+ const { checkMCPServers, showNonRegistryServers, selectServersToRemove, removeMCPServers } = await import('../utils/sync-utils.js');
740
+ const nonRegistryServers = await checkMCPServers(process.cwd());
741
+
742
+ if (nonRegistryServers.length > 0) {
743
+ showNonRegistryServers(nonRegistryServers);
744
+ const serversToRemove = await selectServersToRemove(nonRegistryServers);
745
+
746
+ if (serversToRemove.length > 0) {
747
+ const removedCount = await removeMCPServers(process.cwd(), serversToRemove);
748
+ console.log(chalk.green(`\n✓ Removed ${removedCount} MCP server(s)\n`));
749
+ }
750
+ }
723
751
  } else {
724
752
  // Select and validate target (will use existing in repair mode, or prompt if needed)
725
753
  const targetId = await selectAndValidateTarget(initOptions);
@@ -2,6 +2,7 @@ import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import chalk from 'chalk';
4
4
  import type { Target } from '../types.js';
5
+ import { MCP_SERVER_REGISTRY } from '../config/servers.js';
5
6
 
6
7
  /**
7
8
  * Files to delete during sync for each target
@@ -157,3 +158,108 @@ export async function confirmSync(): Promise<boolean> {
157
158
  ]);
158
159
  return confirm;
159
160
  }
161
+
162
+ /**
163
+ * Check MCP servers - find servers not in Flow registry
164
+ */
165
+ export async function checkMCPServers(cwd: string): Promise<string[]> {
166
+ const mcpPath = path.join(cwd, '.mcp.json');
167
+
168
+ if (!fs.existsSync(mcpPath)) {
169
+ return [];
170
+ }
171
+
172
+ try {
173
+ const content = await fs.promises.readFile(mcpPath, 'utf-8');
174
+ const mcpConfig = JSON.parse(content);
175
+
176
+ if (!mcpConfig.mcpServers) {
177
+ return [];
178
+ }
179
+
180
+ const installedServers = Object.keys(mcpConfig.mcpServers);
181
+ const registryServers = Object.keys(MCP_SERVER_REGISTRY);
182
+
183
+ // Find servers not in registry
184
+ return installedServers.filter(id => !registryServers.includes(id));
185
+ } catch (error) {
186
+ console.warn(chalk.yellow('⚠ Failed to read .mcp.json'));
187
+ return [];
188
+ }
189
+ }
190
+
191
+ /**
192
+ * Show non-registry servers
193
+ */
194
+ export function showNonRegistryServers(servers: string[]): void {
195
+ if (servers.length === 0) {
196
+ return;
197
+ }
198
+
199
+ console.log(chalk.cyan.bold('\n📋 MCP Registry Check\n'));
200
+ console.log(chalk.yellow('⚠️ 以下 MCP servers 唔係 Flow registry 入面:\n'));
201
+
202
+ servers.forEach(server => {
203
+ console.log(chalk.dim(` - ${server}`));
204
+ });
205
+
206
+ console.log(chalk.dim('\n可能原因:'));
207
+ console.log(chalk.dim(' 1. Flow registry 已移除'));
208
+ console.log(chalk.dim(' 2. 你自己手動安裝\n'));
209
+ }
210
+
211
+ /**
212
+ * Select servers to remove
213
+ */
214
+ export async function selectServersToRemove(servers: string[]): Promise<string[]> {
215
+ const { default: inquirer } = await import('inquirer');
216
+ const { selected } = await inquirer.prompt([
217
+ {
218
+ type: 'checkbox',
219
+ name: 'selected',
220
+ message: '選擇要刪除既 servers:',
221
+ choices: servers.map(s => ({ name: s, value: s })),
222
+ },
223
+ ]);
224
+ return selected;
225
+ }
226
+
227
+ /**
228
+ * Remove MCP servers from .mcp.json
229
+ */
230
+ export async function removeMCPServers(cwd: string, serversToRemove: string[]): Promise<number> {
231
+ if (serversToRemove.length === 0) {
232
+ return 0;
233
+ }
234
+
235
+ const mcpPath = path.join(cwd, '.mcp.json');
236
+
237
+ try {
238
+ const content = await fs.promises.readFile(mcpPath, 'utf-8');
239
+ const mcpConfig = JSON.parse(content);
240
+
241
+ if (!mcpConfig.mcpServers) {
242
+ return 0;
243
+ }
244
+
245
+ let removedCount = 0;
246
+ for (const server of serversToRemove) {
247
+ if (mcpConfig.mcpServers[server]) {
248
+ delete mcpConfig.mcpServers[server];
249
+ removedCount++;
250
+ }
251
+ }
252
+
253
+ // Write back
254
+ await fs.promises.writeFile(
255
+ mcpPath,
256
+ JSON.stringify(mcpConfig, null, 2) + '\n',
257
+ 'utf-8'
258
+ );
259
+
260
+ return removedCount;
261
+ } catch (error) {
262
+ console.warn(chalk.yellow('⚠ Failed to update .mcp.json'));
263
+ return 0;
264
+ }
265
+ }