flowmind 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/LICENSE +21 -0
- package/README.md +855 -0
- package/README_CN.md +854 -0
- package/bin/flowmind.js +464 -0
- package/core/adapters/api-doc-adapter.js +71 -0
- package/core/adapters/base-adapter.js +80 -0
- package/core/adapters/database-manager-adapter.js +60 -0
- package/core/adapters/database-query-adapter.js +51 -0
- package/core/adapters/knowledge-base-adapter.js +75 -0
- package/core/adapters/log-service-adapter.js +41 -0
- package/core/adapters/mcp-adapter.js +65 -0
- package/core/adapters/report-adapter.js +60 -0
- package/core/adapters/workflow-adapter.js +62 -0
- package/core/component-registry.js +281 -0
- package/core/component-types.js +63 -0
- package/core/config-manager.js +360 -0
- package/core/index.js +223 -0
- package/core/learning-engine.js +588 -0
- package/core/mcp-compatibility.js +150 -0
- package/core/providers/aliyun/dms-adapter.js +98 -0
- package/core/providers/aliyun/redis-adapter.js +88 -0
- package/core/providers/aliyun/sls-adapter.js +86 -0
- package/core/providers/friday/flow-adapter.js +85 -0
- package/core/providers/friday/report-adapter.js +83 -0
- package/core/providers/yapi/yapi-adapter.js +79 -0
- package/core/providers/yuque/yuque-adapter.js +90 -0
- package/core/scene-matcher.js +326 -0
- package/core/skill-loader.js +291 -0
- package/package.json +67 -0
- package/scripts/migrate-config.js +153 -0
- package/skills/api-sync/SKILL.md +203 -0
- package/skills/archive-change/SKILL.md +172 -0
- package/skills/auto-flow/SKILL.md +277 -0
- package/skills/code-review/SKILL.md +206 -0
- package/skills/code-review-audit/SKILL.md +150 -0
- package/skills/data-logic-validation/SKILL.md +162 -0
- package/skills/data-validation/SKILL.md +210 -0
- package/skills/git-review/SKILL.md +190 -0
- package/skills/learning-engine/SKILL.md +352 -0
- package/skills/learning-feedback/SKILL.md +174 -0
- package/skills/log-audit/SKILL.md +226 -0
- package/skills/project-review/SKILL.md +196 -0
- package/skills/requirement-analyst/SKILL.md +275 -0
- package/skills/resource-bind/SKILL.md +222 -0
- package/skills/sls-log-audit/SKILL.md +223 -0
- package/skills/yapi-sync-interface/SKILL.md +145 -0
- package/skills/yuque-sync-design/SKILL.md +157 -0
package/bin/flowmind.js
ADDED
|
@@ -0,0 +1,464 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* FlowMind CLI
|
|
5
|
+
* The AI Agent That Learns How You Work
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { program } = require('commander');
|
|
9
|
+
const chalk = require('chalk');
|
|
10
|
+
const ora = require('ora');
|
|
11
|
+
const inquirer = require('inquirer');
|
|
12
|
+
const fs = require('fs-extra');
|
|
13
|
+
const path = require('path');
|
|
14
|
+
const FlowMind = require('../core');
|
|
15
|
+
|
|
16
|
+
// Package info
|
|
17
|
+
const packageJson = require('../package.json');
|
|
18
|
+
|
|
19
|
+
// Create FlowMind instance
|
|
20
|
+
let flowmind;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Initialize FlowMind
|
|
24
|
+
*/
|
|
25
|
+
async function initFlowMind(options = {}) {
|
|
26
|
+
flowmind = new FlowMind(options);
|
|
27
|
+
await flowmind.init();
|
|
28
|
+
return flowmind;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Display banner
|
|
33
|
+
*/
|
|
34
|
+
function showBanner() {
|
|
35
|
+
console.log(chalk.cyan(`
|
|
36
|
+
╔══════════════════════════════════════════════════╗
|
|
37
|
+
║ ║
|
|
38
|
+
║ 🧠 FlowMind ║
|
|
39
|
+
║ The AI Agent That Learns How You Work ║
|
|
40
|
+
║ ║
|
|
41
|
+
╚══════════════════════════════════════════════════╝
|
|
42
|
+
`));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// CLI Commands
|
|
46
|
+
program
|
|
47
|
+
.name('flowmind')
|
|
48
|
+
.description('The AI Agent That Learns How You Work')
|
|
49
|
+
.version(packageJson.version);
|
|
50
|
+
|
|
51
|
+
// Init command
|
|
52
|
+
program
|
|
53
|
+
.command('init')
|
|
54
|
+
.description('Initialize FlowMind in current directory')
|
|
55
|
+
.action(async () => {
|
|
56
|
+
showBanner();
|
|
57
|
+
|
|
58
|
+
const spinner = ora('Initializing FlowMind...').start();
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
// Create config directory
|
|
62
|
+
const configDir = path.join(process.env.HOME || process.env.USERPROFILE, '.flowmind');
|
|
63
|
+
await fs.ensureDir(configDir);
|
|
64
|
+
await fs.ensureDir(path.join(configDir, 'learning'));
|
|
65
|
+
await fs.ensureDir(path.join(configDir, 'learning', 'records'));
|
|
66
|
+
|
|
67
|
+
// Create default config
|
|
68
|
+
const configPath = path.join(configDir, 'config.json');
|
|
69
|
+
if (!await fs.pathExists(configPath)) {
|
|
70
|
+
const defaultConfig = {
|
|
71
|
+
version: '1.0.0',
|
|
72
|
+
learning: {
|
|
73
|
+
enabled: true,
|
|
74
|
+
autoApply: true,
|
|
75
|
+
confidenceThreshold: 0.7,
|
|
76
|
+
storagePath: path.join(configDir, 'learning')
|
|
77
|
+
},
|
|
78
|
+
sceneMapping: {
|
|
79
|
+
enabled: true,
|
|
80
|
+
weights: {
|
|
81
|
+
keywordMatch: 0.4,
|
|
82
|
+
patternMatch: 0.3,
|
|
83
|
+
historyScore: 0.2,
|
|
84
|
+
confidence: 0.1
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
await fs.writeJson(configPath, defaultConfig, { spaces: 2 });
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
spinner.succeed('FlowMind initialized successfully!');
|
|
93
|
+
|
|
94
|
+
console.log(chalk.green('\n✓ Configuration created at:'), configDir);
|
|
95
|
+
console.log(chalk.green('✓ Learning system ready'));
|
|
96
|
+
console.log(chalk.green('✓ Scene mapping ready'));
|
|
97
|
+
|
|
98
|
+
console.log(chalk.cyan('\nNext steps:'));
|
|
99
|
+
console.log(' 1. Run', chalk.yellow('flowmind'), 'to start interactive mode');
|
|
100
|
+
console.log(' 2. Or use', chalk.yellow('flowmind "your request"'), 'for single commands');
|
|
101
|
+
console.log(' 3. FlowMind will learn from your corrections automatically');
|
|
102
|
+
|
|
103
|
+
} catch (error) {
|
|
104
|
+
spinner.fail('Failed to initialize FlowMind');
|
|
105
|
+
console.error(chalk.red(error.message));
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// Process command (default)
|
|
110
|
+
program
|
|
111
|
+
.command('process')
|
|
112
|
+
.alias('p')
|
|
113
|
+
.description('Process a request')
|
|
114
|
+
.argument('[input]', 'Input to process')
|
|
115
|
+
.option('-s, --skill <skill>', 'Use specific skill')
|
|
116
|
+
.option('-v, --verbose', 'Verbose output')
|
|
117
|
+
.action(async (input, options) => {
|
|
118
|
+
try {
|
|
119
|
+
const fm = await initFlowMind();
|
|
120
|
+
|
|
121
|
+
if (!input) {
|
|
122
|
+
// Interactive mode
|
|
123
|
+
await runInteractiveMode(fm);
|
|
124
|
+
} else {
|
|
125
|
+
// Single command mode
|
|
126
|
+
const spinner = ora('Processing...').start();
|
|
127
|
+
|
|
128
|
+
const result = await fm.process(input, {
|
|
129
|
+
skill: options.skill,
|
|
130
|
+
verbose: options.verbose
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
spinner.stop();
|
|
134
|
+
displayResult(result);
|
|
135
|
+
}
|
|
136
|
+
} catch (error) {
|
|
137
|
+
console.error(chalk.red('Error:'), error.message);
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
// Learn command
|
|
142
|
+
program
|
|
143
|
+
.command('learn')
|
|
144
|
+
.description('Manage learning records')
|
|
145
|
+
.option('-l, --list', 'List learning records')
|
|
146
|
+
.option('-s, --skill <skill>', 'Filter by skill')
|
|
147
|
+
.option('-t, --type <type>', 'Filter by type')
|
|
148
|
+
.option('-e, --export [file]', 'Export learnings')
|
|
149
|
+
.option('-i, --import <file>', 'Import learnings')
|
|
150
|
+
.option('-r, --reset <skill>', 'Reset skill learnings')
|
|
151
|
+
.option('-d, --delete <id>', 'Delete learning record')
|
|
152
|
+
.action(async (options) => {
|
|
153
|
+
try {
|
|
154
|
+
const fm = await initFlowMind();
|
|
155
|
+
|
|
156
|
+
if (options.list) {
|
|
157
|
+
const stats = await fm.getStats();
|
|
158
|
+
displayStats(stats);
|
|
159
|
+
} else if (options.export) {
|
|
160
|
+
const exportPath = options.export || 'flowmind-learnings.json';
|
|
161
|
+
await fm.exportLearnings({ output: exportPath });
|
|
162
|
+
console.log(chalk.green('✓ Learnings exported to:'), exportPath);
|
|
163
|
+
} else if (options.import) {
|
|
164
|
+
const data = await fs.readJson(options.import);
|
|
165
|
+
await fm.importLearnings(data);
|
|
166
|
+
console.log(chalk.green('✓ Learnings imported successfully'));
|
|
167
|
+
} else if (options.reset) {
|
|
168
|
+
console.log(chalk.yellow('Resetting learnings for:'), options.reset);
|
|
169
|
+
// Implementation would go here
|
|
170
|
+
} else if (options.delete) {
|
|
171
|
+
console.log(chalk.yellow('Deleting learning:'), options.delete);
|
|
172
|
+
// Implementation would go here
|
|
173
|
+
} else {
|
|
174
|
+
// Default to list
|
|
175
|
+
const stats = await fm.getStats();
|
|
176
|
+
displayStats(stats);
|
|
177
|
+
}
|
|
178
|
+
} catch (error) {
|
|
179
|
+
console.error(chalk.red('Error:'), error.message);
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
// Scenes command
|
|
184
|
+
program
|
|
185
|
+
.command('scenes')
|
|
186
|
+
.description('Manage scene mappings')
|
|
187
|
+
.option('-l, --list', 'List scenes')
|
|
188
|
+
.option('-a, --add', 'Add new scene')
|
|
189
|
+
.option('-r, --remove <id>', 'Remove scene')
|
|
190
|
+
.option('-e, --export [file]', 'Export scenes')
|
|
191
|
+
.action(async (options) => {
|
|
192
|
+
try {
|
|
193
|
+
const fm = await initFlowMind();
|
|
194
|
+
|
|
195
|
+
if (options.list) {
|
|
196
|
+
const scenes = fm.matcher.listScenes();
|
|
197
|
+
displayScenes(scenes);
|
|
198
|
+
} else if (options.add) {
|
|
199
|
+
await addSceneInteractive(fm);
|
|
200
|
+
} else if (options.remove) {
|
|
201
|
+
await fm.matcher.removeScene(options.remove);
|
|
202
|
+
console.log(chalk.green('✓ Scene removed'));
|
|
203
|
+
} else if (options.export) {
|
|
204
|
+
const exportPath = options.export || 'flowmind-scenes.json';
|
|
205
|
+
const scenes = fm.matcher.listScenes();
|
|
206
|
+
await fs.writeJson(exportPath, scenes, { spaces: 2 });
|
|
207
|
+
console.log(chalk.green('✓ Scenes exported to:'), exportPath);
|
|
208
|
+
} else {
|
|
209
|
+
// Default to list
|
|
210
|
+
const scenes = fm.matcher.listScenes();
|
|
211
|
+
displayScenes(scenes);
|
|
212
|
+
}
|
|
213
|
+
} catch (error) {
|
|
214
|
+
console.error(chalk.red('Error:'), error.message);
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
// Skills command
|
|
219
|
+
program
|
|
220
|
+
.command('skills')
|
|
221
|
+
.description('List available skills')
|
|
222
|
+
.action(async () => {
|
|
223
|
+
try {
|
|
224
|
+
const fm = await initFlowMind();
|
|
225
|
+
const skills = fm.skills.list();
|
|
226
|
+
displaySkills(skills);
|
|
227
|
+
} catch (error) {
|
|
228
|
+
console.error(chalk.red('Error:'), error.message);
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
// Stats command
|
|
233
|
+
program
|
|
234
|
+
.command('stats')
|
|
235
|
+
.description('Show FlowMind statistics')
|
|
236
|
+
.action(async () => {
|
|
237
|
+
try {
|
|
238
|
+
const fm = await initFlowMind();
|
|
239
|
+
const stats = await fm.getStats();
|
|
240
|
+
displayStats(stats);
|
|
241
|
+
} catch (error) {
|
|
242
|
+
console.error(chalk.red('Error:'), error.message);
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
// Config command
|
|
247
|
+
program
|
|
248
|
+
.command('config')
|
|
249
|
+
.description('Manage configuration')
|
|
250
|
+
.option('-l, --list', 'List configuration')
|
|
251
|
+
.option('-s, --set <key> <value>', 'Set configuration value')
|
|
252
|
+
.option('-g, --get <key>', 'Get configuration value')
|
|
253
|
+
.action(async (options) => {
|
|
254
|
+
try {
|
|
255
|
+
const fm = await initFlowMind();
|
|
256
|
+
|
|
257
|
+
if (options.list) {
|
|
258
|
+
const config = fm.config.getAll();
|
|
259
|
+
console.log(chalk.cyan('\nFlowMind Configuration:'));
|
|
260
|
+
console.log(JSON.stringify(config, null, 2));
|
|
261
|
+
} else if (options.set && options.value) {
|
|
262
|
+
fm.config.set(options.set, options.value);
|
|
263
|
+
await fm.config.save();
|
|
264
|
+
console.log(chalk.green('✓ Configuration updated'));
|
|
265
|
+
} else if (options.get) {
|
|
266
|
+
const value = fm.config.get(options.get);
|
|
267
|
+
console.log(value);
|
|
268
|
+
} else {
|
|
269
|
+
const config = fm.config.getAll();
|
|
270
|
+
console.log(JSON.stringify(config, null, 2));
|
|
271
|
+
}
|
|
272
|
+
} catch (error) {
|
|
273
|
+
console.error(chalk.red('Error:'), error.message);
|
|
274
|
+
}
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
// Interactive mode
|
|
278
|
+
async function runInteractiveMode(fm) {
|
|
279
|
+
showBanner();
|
|
280
|
+
console.log(chalk.cyan('Interactive mode started. Type "exit" to quit.\n'));
|
|
281
|
+
|
|
282
|
+
while (true) {
|
|
283
|
+
const { input } = await inquirer.prompt([
|
|
284
|
+
{
|
|
285
|
+
type: 'input',
|
|
286
|
+
name: 'input',
|
|
287
|
+
message: chalk.green('You:'),
|
|
288
|
+
prefix: ''
|
|
289
|
+
}
|
|
290
|
+
]);
|
|
291
|
+
|
|
292
|
+
if (input.toLowerCase() === 'exit' || input.toLowerCase() === 'quit') {
|
|
293
|
+
console.log(chalk.cyan('\nGoodbye! FlowMind will remember your preferences. 👋\n'));
|
|
294
|
+
break;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
if (!input.trim()) continue;
|
|
298
|
+
|
|
299
|
+
const spinner = ora('Thinking...').start();
|
|
300
|
+
|
|
301
|
+
try {
|
|
302
|
+
const result = await fm.process(input);
|
|
303
|
+
spinner.stop();
|
|
304
|
+
displayResult(result);
|
|
305
|
+
} catch (error) {
|
|
306
|
+
spinner.stop();
|
|
307
|
+
console.error(chalk.red('Error:'), error.message);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
console.log(''); // Empty line for spacing
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Add scene interactive
|
|
315
|
+
async function addSceneInteractive(fm) {
|
|
316
|
+
const answers = await inquirer.prompt([
|
|
317
|
+
{
|
|
318
|
+
type: 'input',
|
|
319
|
+
name: 'name',
|
|
320
|
+
message: 'Scene name:',
|
|
321
|
+
},
|
|
322
|
+
{
|
|
323
|
+
type: 'input',
|
|
324
|
+
name: 'keywords',
|
|
325
|
+
message: 'Keywords (comma separated):',
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
type: 'input',
|
|
329
|
+
name: 'patterns',
|
|
330
|
+
message: 'Trigger patterns (comma separated):',
|
|
331
|
+
},
|
|
332
|
+
{
|
|
333
|
+
type: 'input',
|
|
334
|
+
name: 'skills',
|
|
335
|
+
message: 'Skills to execute (comma separated):',
|
|
336
|
+
}
|
|
337
|
+
]);
|
|
338
|
+
|
|
339
|
+
const scene = {
|
|
340
|
+
name: answers.name,
|
|
341
|
+
keywords: answers.keywords.split(',').map(k => k.trim()),
|
|
342
|
+
patterns: answers.patterns.split(',').map(p => p.trim()),
|
|
343
|
+
workflow: {
|
|
344
|
+
skills: answers.skills.split(',').map(s => ({
|
|
345
|
+
skill: s.trim(),
|
|
346
|
+
params: {}
|
|
347
|
+
}))
|
|
348
|
+
}
|
|
349
|
+
};
|
|
350
|
+
|
|
351
|
+
await fm.matcher.addScene(scene);
|
|
352
|
+
console.log(chalk.green('✓ Scene added successfully'));
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// Display functions
|
|
356
|
+
function displayResult(result) {
|
|
357
|
+
if (result.type === 'learning') {
|
|
358
|
+
console.log(chalk.cyan(result.message));
|
|
359
|
+
} else if (result.type === 'result') {
|
|
360
|
+
console.log(chalk.white('\n┌─────────────────────────────────────────────────────┐'));
|
|
361
|
+
console.log(chalk.white('│ Result │'));
|
|
362
|
+
console.log(chalk.white('├─────────────────────────────────────────────────────┤'));
|
|
363
|
+
|
|
364
|
+
if (result.metadata?.skill) {
|
|
365
|
+
console.log(chalk.white(`│ Skill: ${result.metadata.skill}`));
|
|
366
|
+
}
|
|
367
|
+
if (result.metadata?.duration) {
|
|
368
|
+
console.log(chalk.white(`│ Duration: ${result.metadata.duration}ms`));
|
|
369
|
+
}
|
|
370
|
+
if (result.metadata?.sceneMatch) {
|
|
371
|
+
console.log(chalk.white(`│ Scene: ${result.metadata.sceneMatch.scene.name}`));
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
console.log(chalk.white('├─────────────────────────────────────────────────────┤'));
|
|
375
|
+
console.log(chalk.white('│'));
|
|
376
|
+
|
|
377
|
+
if (typeof result.data === 'string') {
|
|
378
|
+
console.log(chalk.white(result.data));
|
|
379
|
+
} else {
|
|
380
|
+
console.log(chalk.white(JSON.stringify(result.data, null, 2)));
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
console.log(chalk.white('│'));
|
|
384
|
+
console.log(chalk.white('└─────────────────────────────────────────────────────┘'));
|
|
385
|
+
} else if (result.type === 'error') {
|
|
386
|
+
console.log(chalk.red('\n✗ Error:'), result.message);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
function displayStats(stats) {
|
|
391
|
+
console.log(chalk.cyan('\n┌─────────────────────────────────────────────────────┐'));
|
|
392
|
+
console.log(chalk.cyan('│ FlowMind Statistics │'));
|
|
393
|
+
console.log(chalk.cyan('├─────────────────────────────────────────────────────┤'));
|
|
394
|
+
console.log(chalk.cyan(`│ Total Learning Records: ${stats.totalRecords || 0}`));
|
|
395
|
+
console.log(chalk.cyan(`│ Last Learning: ${stats.lastLearning || 'Never'}`));
|
|
396
|
+
console.log(chalk.cyan('├─────────────────────────────────────────────────────┤'));
|
|
397
|
+
|
|
398
|
+
if (stats.byType && Object.keys(stats.byType).length > 0) {
|
|
399
|
+
console.log(chalk.cyan('│ By Type:'));
|
|
400
|
+
for (const [type, count] of Object.entries(stats.byType)) {
|
|
401
|
+
console.log(chalk.cyan(`│ ${type}: ${count}`));
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
if (stats.bySkill && Object.keys(stats.bySkill).length > 0) {
|
|
406
|
+
console.log(chalk.cyan('├─────────────────────────────────────────────────────┤'));
|
|
407
|
+
console.log(chalk.cyan('│ By Skill:'));
|
|
408
|
+
for (const [skill, count] of Object.entries(stats.bySkill)) {
|
|
409
|
+
console.log(chalk.cyan(`│ ${skill}: ${count}`));
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
console.log(chalk.cyan('└─────────────────────────────────────────────────────┘'));
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
function displayScenes(scenes) {
|
|
417
|
+
console.log(chalk.cyan('\n┌─────────────────────────────────────────────────────┐'));
|
|
418
|
+
console.log(chalk.cyan('│ Scene Mappings │'));
|
|
419
|
+
console.log(chalk.cyan('├─────────────────────────────────────────────────────┤'));
|
|
420
|
+
|
|
421
|
+
if (scenes.length === 0) {
|
|
422
|
+
console.log(chalk.cyan('│ No scenes defined yet. │'));
|
|
423
|
+
} else {
|
|
424
|
+
for (const scene of scenes) {
|
|
425
|
+
console.log(chalk.cyan(`│ ${scene.name}`));
|
|
426
|
+
console.log(chalk.cyan(`│ Keywords: ${scene.keywords?.join(', ') || 'N/A'}`));
|
|
427
|
+
console.log(chalk.cyan(`│ Used: ${scene.useCount || 0} times`));
|
|
428
|
+
console.log(chalk.cyan('├─────────────────────────────────────────────────────┤'));
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
console.log(chalk.cyan('└─────────────────────────────────────────────────────┘'));
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
function displaySkills(skills) {
|
|
436
|
+
console.log(chalk.cyan('\n┌─────────────────────────────────────────────────────┐'));
|
|
437
|
+
console.log(chalk.cyan('│ Available Skills │'));
|
|
438
|
+
console.log(chalk.cyan('├─────────────────────────────────────────────────────┤'));
|
|
439
|
+
|
|
440
|
+
for (const skill of skills) {
|
|
441
|
+
console.log(chalk.cyan(`│ ${skill.name}`));
|
|
442
|
+
if (skill.description) {
|
|
443
|
+
console.log(chalk.cyan(`│ ${skill.description.substring(0, 50)}...`));
|
|
444
|
+
}
|
|
445
|
+
console.log(chalk.cyan('├─────────────────────────────────────────────────────┤'));
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
console.log(chalk.cyan('└─────────────────────────────────────────────────────┘'));
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// Parse arguments
|
|
452
|
+
program.parse(process.argv);
|
|
453
|
+
|
|
454
|
+
// Default to interactive mode if no command specified
|
|
455
|
+
if (!process.argv.slice(2).length) {
|
|
456
|
+
(async () => {
|
|
457
|
+
try {
|
|
458
|
+
const fm = await initFlowMind();
|
|
459
|
+
await runInteractiveMode(fm);
|
|
460
|
+
} catch (error) {
|
|
461
|
+
console.error(chalk.red('Error:'), error.message);
|
|
462
|
+
}
|
|
463
|
+
})();
|
|
464
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FlowMind API Doc Adapter Interface
|
|
3
|
+
* Abstract interface for API documentation services (YApi, Swagger Hub, etc.)
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const McpAdapter = require('./mcp-adapter');
|
|
7
|
+
const { ComponentType } = require('../component-types');
|
|
8
|
+
|
|
9
|
+
class ApiDocAdapter extends McpAdapter {
|
|
10
|
+
get componentType() {
|
|
11
|
+
return ComponentType.API_DOC;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Search APIs by keyword.
|
|
16
|
+
* @param {object} params - { nameKeyword, pathKeyword, projectKeyword }
|
|
17
|
+
* @returns {Promise<object>}
|
|
18
|
+
*/
|
|
19
|
+
async searchApis(params) {
|
|
20
|
+
throw new Error('Subclasses must implement searchApis()');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Get categories for a project.
|
|
25
|
+
* @param {string} projectId
|
|
26
|
+
* @returns {Promise<object>}
|
|
27
|
+
*/
|
|
28
|
+
async getCategories(projectId) {
|
|
29
|
+
throw new Error('Subclasses must implement getCategories()');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Save (create/update) an API interface.
|
|
34
|
+
* @param {object} apiData
|
|
35
|
+
* @returns {Promise<object>}
|
|
36
|
+
*/
|
|
37
|
+
async saveApi(apiData) {
|
|
38
|
+
throw new Error('Subclasses must implement saveApi()');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Import Swagger/OpenAPI data.
|
|
43
|
+
* @param {string} projectId
|
|
44
|
+
* @param {string} catId
|
|
45
|
+
* @param {string} swaggerData
|
|
46
|
+
* @returns {Promise<object>}
|
|
47
|
+
*/
|
|
48
|
+
async importSwagger(projectId, catId, swaggerData) {
|
|
49
|
+
throw new Error('Subclasses must implement importSwagger()');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Export project data.
|
|
54
|
+
* @param {string} projectId
|
|
55
|
+
* @param {string} type - 'json', 'markdown', 'swagger'
|
|
56
|
+
* @returns {Promise<object>}
|
|
57
|
+
*/
|
|
58
|
+
async exportProject(projectId, type) {
|
|
59
|
+
throw new Error('Subclasses must implement exportProject()');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* List projects.
|
|
64
|
+
* @returns {Promise<object>}
|
|
65
|
+
*/
|
|
66
|
+
async listProjects() {
|
|
67
|
+
throw new Error('Subclasses must implement listProjects()');
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
module.exports = ApiDocAdapter;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FlowMind Base Adapter
|
|
3
|
+
* Abstract base class for all component adapters
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
class BaseAdapter {
|
|
7
|
+
constructor(providerName, config = {}) {
|
|
8
|
+
this.providerName = providerName;
|
|
9
|
+
this.config = config;
|
|
10
|
+
this.enabled = config.enabled !== false;
|
|
11
|
+
this._initialized = false;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Get the component type this adapter implements.
|
|
16
|
+
* Subclasses must override this.
|
|
17
|
+
* @returns {string} ComponentType value
|
|
18
|
+
*/
|
|
19
|
+
get componentType() {
|
|
20
|
+
throw new Error('Subclasses must implement componentType getter');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Get the MCP server name associated with this adapter, if any.
|
|
25
|
+
* @returns {string|null}
|
|
26
|
+
*/
|
|
27
|
+
get mcpServer() {
|
|
28
|
+
return this.config.mcpServer || null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Initialize the adapter. Called once before first use.
|
|
33
|
+
* @returns {Promise<void>}
|
|
34
|
+
*/
|
|
35
|
+
async init() {
|
|
36
|
+
this._initialized = true;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Check if the adapter is ready to serve requests.
|
|
41
|
+
* @returns {boolean}
|
|
42
|
+
*/
|
|
43
|
+
isReady() {
|
|
44
|
+
return this.enabled && this._initialized;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Get adapter status information.
|
|
49
|
+
* @returns {object}
|
|
50
|
+
*/
|
|
51
|
+
getStatus() {
|
|
52
|
+
return {
|
|
53
|
+
provider: this.providerName,
|
|
54
|
+
type: this.componentType,
|
|
55
|
+
enabled: this.enabled,
|
|
56
|
+
initialized: this._initialized,
|
|
57
|
+
mcpServer: this.mcpServer
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Get the list of MCP tool names this adapter provides.
|
|
63
|
+
* Subclasses should override to declare their tools.
|
|
64
|
+
* @returns {string[]}
|
|
65
|
+
*/
|
|
66
|
+
getProvidedTools() {
|
|
67
|
+
return [];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Check if a specific MCP tool is provided by this adapter.
|
|
72
|
+
* @param {string} toolName
|
|
73
|
+
* @returns {boolean}
|
|
74
|
+
*/
|
|
75
|
+
hasTool(toolName) {
|
|
76
|
+
return this.getProvidedTools().includes(toolName);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
module.exports = BaseAdapter;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FlowMind Database Manager Adapter Interface
|
|
3
|
+
* Abstract interface for database management services (DMS, etc.)
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const McpAdapter = require('./mcp-adapter');
|
|
7
|
+
const { ComponentType } = require('../component-types');
|
|
8
|
+
|
|
9
|
+
class DatabaseManagerAdapter extends McpAdapter {
|
|
10
|
+
get componentType() {
|
|
11
|
+
return ComponentType.DATABASE_MANAGER;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* List database instances.
|
|
16
|
+
* @param {object} params - Optional filter params
|
|
17
|
+
* @returns {Promise<object>}
|
|
18
|
+
*/
|
|
19
|
+
async listInstances(params) {
|
|
20
|
+
throw new Error('Subclasses must implement listInstances()');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Execute a SQL script against a database.
|
|
25
|
+
* @param {object} params - { database_id, script }
|
|
26
|
+
* @returns {Promise<object>}
|
|
27
|
+
*/
|
|
28
|
+
async executeScript(params) {
|
|
29
|
+
throw new Error('Subclasses must implement executeScript()');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Search for databases by name.
|
|
34
|
+
* @param {string} searchKey
|
|
35
|
+
* @returns {Promise<object>}
|
|
36
|
+
*/
|
|
37
|
+
async searchDatabase(searchKey) {
|
|
38
|
+
throw new Error('Subclasses must implement searchDatabase()');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* List tables in a database.
|
|
43
|
+
* @param {string} databaseId
|
|
44
|
+
* @returns {Promise<object>}
|
|
45
|
+
*/
|
|
46
|
+
async listTables(databaseId) {
|
|
47
|
+
throw new Error('Subclasses must implement listTables()');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Get table detail information.
|
|
52
|
+
* @param {string} tableGuid
|
|
53
|
+
* @returns {Promise<object>}
|
|
54
|
+
*/
|
|
55
|
+
async getTableDetail(tableGuid) {
|
|
56
|
+
throw new Error('Subclasses must implement getTableDetail()');
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
module.exports = DatabaseManagerAdapter;
|