flowmind 1.0.1 → 1.1.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/core/index.js CHANGED
@@ -8,6 +8,7 @@ const LearningEngine = require('./learning-engine');
8
8
  const SceneMatcher = require('./scene-matcher');
9
9
  const ConfigManager = require('./config-manager');
10
10
  const ComponentRegistry = require('./component-registry');
11
+ const ModelManager = require('./ai/model-manager');
11
12
 
12
13
  class FlowMind {
13
14
  constructor(options = {}) {
@@ -16,6 +17,7 @@ class FlowMind {
16
17
  this.matcher = new SceneMatcher(this.config, this.learning);
17
18
  this.components = new ComponentRegistry(this.config);
18
19
  this.skills = new SkillLoader(this.config, this.learning, this.components);
20
+ this.ai = new ModelManager(options.ai || {});
19
21
  this.initialized = false;
20
22
  }
21
23
 
@@ -32,6 +34,13 @@ class FlowMind {
32
34
  await this.skills.loadAll();
33
35
  await this.matcher.loadScenes();
34
36
 
37
+ // Initialize AI model manager
38
+ try {
39
+ await this.ai.init();
40
+ } catch (error) {
41
+ console.warn(`AI model initialization failed: ${error.message}. Falling back to rule-based engine.`);
42
+ }
43
+
35
44
  this.initialized = true;
36
45
  return this;
37
46
  }
@@ -47,32 +56,70 @@ class FlowMind {
47
56
  const startTime = Date.now();
48
57
 
49
58
  try {
50
- // 1. Check for learning patterns (corrections, feedback)
51
- const learningResult = await this.learning.detectLearning(input, context);
59
+ // 1. AI Intent Understanding (if available)
60
+ const intent = await this.ai.understandIntent(input, context);
61
+
62
+ // 2. Check for learning patterns (corrections, feedback)
63
+ // Use AI to analyze learning feedback if available
64
+ const aiLearningResult = await this.ai.analyzeLearningFeedback(input, context);
65
+ const learningResult = aiLearningResult?.isLearning
66
+ ? aiLearningResult
67
+ : await this.learning.detectLearning(input, context);
52
68
  if (learningResult) {
53
69
  return this.formatLearningResponse(learningResult);
54
70
  }
55
71
 
56
- // 2. Check scene mappings
57
- const sceneMatch = await this.matcher.match(input);
72
+ // 3. Check scene mappings (with AI intent if available)
73
+ const sceneMatch = await this.matcher.match(input, intent);
58
74
  if (sceneMatch && sceneMatch.confidence >= 0.7) {
59
75
  return this.executeSceneWorkflow(sceneMatch, input, context);
60
76
  }
61
77
 
62
- // 3. Select and execute skill
63
- const skill = await this.skills.select(input, context);
78
+ // 4. Select skill (AI-assisted if available)
79
+ let skill = null;
80
+ const candidates = await this.skills.getCandidates(input, context);
81
+
82
+ if (candidates.length > 0) {
83
+ // Use AI to select skill if available
84
+ const aiSelection = await this.ai.selectSkill(input, candidates);
85
+ if (aiSelection && aiSelection.selectedSkill) {
86
+ skill = this.skills.get(aiSelection.selectedSkill);
87
+ }
88
+ }
89
+
90
+ // Fallback to rule-based selection
91
+ if (!skill) {
92
+ skill = await this.skills.select(input, context);
93
+ }
94
+
64
95
  if (!skill) {
65
96
  return this.formatError('No matching skill found', input);
66
97
  }
67
98
 
68
- // 4. Execute with learning applied
69
- const result = await this.executeWithLearning(skill, input, context);
99
+ // 5. Extract parameters using AI (if available)
100
+ const extractedParams = await this.ai.extractParameters(input, skill.name);
101
+
102
+ // 6. Execute with learning applied
103
+ const enhancedContext = {
104
+ ...context,
105
+ ...extractedParams,
106
+ intent: intent
107
+ };
108
+ const result = await this.executeWithLearning(skill, input, enhancedContext);
70
109
 
71
- // 5. Format and return
72
- return this.formatResult(result, {
110
+ // 7. Generate AI summary (if available)
111
+ const summary = await this.ai.summarizeResult(result, {
112
+ skill: skill.name,
113
+ intent: intent
114
+ });
115
+
116
+ // 8. Format and return
117
+ return this.formatResult(summary || result, {
73
118
  skill: skill.name,
74
119
  duration: Date.now() - startTime,
75
- sceneMatch: sceneMatch
120
+ sceneMatch: sceneMatch,
121
+ intent: intent,
122
+ aiEnhanced: !!summary
76
123
  });
77
124
 
78
125
  } catch (error) {
@@ -205,6 +252,22 @@ class FlowMind {
205
252
  return this.components.getStatus();
206
253
  }
207
254
 
255
+ /**
256
+ * Get AI model status
257
+ * @returns {object}
258
+ */
259
+ getAIStatus() {
260
+ return this.ai.getStatus();
261
+ }
262
+
263
+ /**
264
+ * Check if AI is available
265
+ * @returns {boolean}
266
+ */
267
+ hasAI() {
268
+ return this.ai.hasAvailableProvider();
269
+ }
270
+
208
271
  /**
209
272
  * Export learnings
210
273
  */
@@ -225,6 +225,23 @@ class SkillLoader {
225
225
  * Select best skill for input
226
226
  */
227
227
  async select(input, context = {}) {
228
+ const candidates = await this.getCandidates(input, context);
229
+
230
+ if (candidates.length === 0) {
231
+ return null;
232
+ }
233
+
234
+ // Sort by score (highest first)
235
+ candidates.sort((a, b) => b.score - a.score);
236
+
237
+ return candidates[0].skill;
238
+ }
239
+
240
+ /**
241
+ * Get candidate skills for input
242
+ * Returns skills that can handle the input with their scores
243
+ */
244
+ async getCandidates(input, context = {}) {
228
245
  const candidates = [];
229
246
 
230
247
  for (const [name, skill] of this.skills) {
@@ -232,7 +249,11 @@ class SkillLoader {
232
249
  const canHandle = await skill.canHandle(input, context);
233
250
  if (canHandle) {
234
251
  candidates.push({
252
+ name: skill.name,
235
253
  skill: skill,
254
+ description: skill.definition?.description || '',
255
+ triggers: skill.definition?.triggers || [],
256
+ category: skill.definition?.category || skill.definition?.metadata?.category || '',
236
257
  score: this.calculateSkillScore(skill, input, context)
237
258
  });
238
259
  }
@@ -241,14 +262,7 @@ class SkillLoader {
241
262
  }
242
263
  }
243
264
 
244
- if (candidates.length === 0) {
245
- return null;
246
- }
247
-
248
- // Sort by score (highest first)
249
- candidates.sort((a, b) => b.score - a.score);
250
-
251
- return candidates[0].skill;
265
+ return candidates;
252
266
  }
253
267
 
254
268
  /**
package/mcp/server.js ADDED
@@ -0,0 +1,313 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * FlowMind MCP Server
5
+ * 让 Claude/Codex 可以直接调用 FlowMind 内部流程
6
+ */
7
+
8
+ const FlowMind = require('../core');
9
+
10
+ // MCP Server 实现
11
+ class FlowMindMCPServer {
12
+ constructor() {
13
+ this.flowmind = null;
14
+ this.initialized = false;
15
+ }
16
+
17
+ async init() {
18
+ if (this.initialized) return;
19
+
20
+ this.flowmind = new FlowMind();
21
+ await this.flowmind.init();
22
+ this.initialized = true;
23
+ }
24
+
25
+ /**
26
+ * 获取所有可用工具
27
+ */
28
+ getTools() {
29
+ const skills = this.flowmind.skills.list();
30
+ const tools = [];
31
+
32
+ // 添加核心工具
33
+ tools.push({
34
+ name: 'flowmind_process',
35
+ description: 'Process a request using FlowMind AI agent. This is the main entry point for using FlowMind.',
36
+ inputSchema: {
37
+ type: 'object',
38
+ properties: {
39
+ input: {
40
+ type: 'string',
41
+ description: 'The request to process'
42
+ },
43
+ context: {
44
+ type: 'object',
45
+ description: 'Optional context for the request'
46
+ }
47
+ },
48
+ required: ['input']
49
+ }
50
+ });
51
+
52
+ tools.push({
53
+ name: 'flowmind_list_skills',
54
+ description: 'List all available FlowMind skills',
55
+ inputSchema: {
56
+ type: 'object',
57
+ properties: {}
58
+ }
59
+ });
60
+
61
+ tools.push({
62
+ name: 'flowmind_get_skill',
63
+ description: 'Get detailed information about a specific skill',
64
+ inputSchema: {
65
+ type: 'object',
66
+ properties: {
67
+ name: {
68
+ type: 'string',
69
+ description: 'Skill name'
70
+ }
71
+ },
72
+ required: ['name']
73
+ }
74
+ });
75
+
76
+ tools.push({
77
+ name: 'flowmind_ai_status',
78
+ description: 'Get AI model status and configuration',
79
+ inputSchema: {
80
+ type: 'object',
81
+ properties: {}
82
+ }
83
+ });
84
+
85
+ tools.push({
86
+ name: 'flowmind_learning_stats',
87
+ description: 'Get learning statistics',
88
+ inputSchema: {
89
+ type: 'object',
90
+ properties: {}
91
+ }
92
+ });
93
+
94
+ // 添加每个技能作为独立工具
95
+ for (const skill of skills) {
96
+ tools.push({
97
+ name: `flowmind_skill_${skill.name}`,
98
+ description: skill.description || `Execute ${skill.name} skill`,
99
+ inputSchema: {
100
+ type: 'object',
101
+ properties: {
102
+ input: {
103
+ type: 'string',
104
+ description: 'Input for the skill'
105
+ },
106
+ context: {
107
+ type: 'object',
108
+ description: 'Optional context'
109
+ }
110
+ },
111
+ required: ['input']
112
+ }
113
+ });
114
+ }
115
+
116
+ return tools;
117
+ }
118
+
119
+ /**
120
+ * 调用工具
121
+ */
122
+ async callTool(name, args) {
123
+ await this.init();
124
+
125
+ try {
126
+ // 核心工具
127
+ if (name === 'flowmind_process') {
128
+ const result = await this.flowmind.process(args.input, args.context || {});
129
+ return {
130
+ content: [{
131
+ type: 'text',
132
+ text: JSON.stringify(result, null, 2)
133
+ }]
134
+ };
135
+ }
136
+
137
+ if (name === 'flowmind_list_skills') {
138
+ const skills = this.flowmind.skills.list();
139
+ return {
140
+ content: [{
141
+ type: 'text',
142
+ text: JSON.stringify({ skills }, null, 2)
143
+ }]
144
+ };
145
+ }
146
+
147
+ if (name === 'flowmind_get_skill') {
148
+ const skill = this.flowmind.skills.get(args.name);
149
+ if (!skill) {
150
+ return {
151
+ content: [{
152
+ type: 'text',
153
+ text: JSON.stringify({ error: `Skill not found: ${args.name}` })
154
+ }],
155
+ isError: true
156
+ };
157
+ }
158
+ return {
159
+ content: [{
160
+ type: 'text',
161
+ text: JSON.stringify({
162
+ name: skill.name,
163
+ description: skill.definition?.description,
164
+ category: skill.definition?.category,
165
+ triggers: skill.definition?.triggers,
166
+ componentDependencies: skill.definition?.componentDependencies
167
+ }, null, 2)
168
+ }]
169
+ };
170
+ }
171
+
172
+ if (name === 'flowmind_ai_status') {
173
+ const status = this.flowmind.getAIStatus();
174
+ return {
175
+ content: [{
176
+ type: 'text',
177
+ text: JSON.stringify(status, null, 2)
178
+ }]
179
+ };
180
+ }
181
+
182
+ if (name === 'flowmind_learning_stats') {
183
+ const stats = await this.flowmind.getStats();
184
+ return {
185
+ content: [{
186
+ type: 'text',
187
+ text: JSON.stringify(stats, null, 2)
188
+ }]
189
+ };
190
+ }
191
+
192
+ // 技能工具
193
+ if (name.startsWith('flowmind_skill_')) {
194
+ const skillName = name.replace('flowmind_skill_', '');
195
+ const skill = this.flowmind.skills.get(skillName);
196
+
197
+ if (!skill) {
198
+ return {
199
+ content: [{
200
+ type: 'text',
201
+ text: JSON.stringify({ error: `Skill not found: ${skillName}` })
202
+ }],
203
+ isError: true
204
+ };
205
+ }
206
+
207
+ const result = await this.flowmind.executeWithLearning(skill, args.input, args.context || {});
208
+ return {
209
+ content: [{
210
+ type: 'text',
211
+ text: JSON.stringify(result, null, 2)
212
+ }]
213
+ };
214
+ }
215
+
216
+ return {
217
+ content: [{
218
+ type: 'text',
219
+ text: JSON.stringify({ error: `Unknown tool: ${name}` })
220
+ }],
221
+ isError: true
222
+ };
223
+
224
+ } catch (error) {
225
+ return {
226
+ content: [{
227
+ type: 'text',
228
+ text: JSON.stringify({ error: error.message })
229
+ }],
230
+ isError: true
231
+ };
232
+ }
233
+ }
234
+ }
235
+
236
+ // 启动 MCP Server
237
+ async function main() {
238
+ const server = new FlowMindMCPServer();
239
+
240
+ // 读取 stdin,写入 stdout
241
+ const readline = require('readline');
242
+ const rl = readline.createInterface({
243
+ input: process.stdin,
244
+ output: process.stdout,
245
+ terminal: false
246
+ });
247
+
248
+ rl.on('line', async (line) => {
249
+ try {
250
+ const request = JSON.parse(line);
251
+ let response;
252
+
253
+ if (request.method === 'initialize') {
254
+ response = {
255
+ jsonrpc: '2.0',
256
+ id: request.id,
257
+ result: {
258
+ protocolVersion: '2024-11-05',
259
+ capabilities: {
260
+ tools: {}
261
+ },
262
+ serverInfo: {
263
+ name: 'flowmind',
264
+ version: '1.0.1'
265
+ }
266
+ }
267
+ };
268
+ } else if (request.method === 'tools/list') {
269
+ await server.init();
270
+ const tools = server.getTools();
271
+ response = {
272
+ jsonrpc: '2.0',
273
+ id: request.id,
274
+ result: { tools }
275
+ };
276
+ } else if (request.method === 'tools/call') {
277
+ const result = await server.callTool(request.params.name, request.params.arguments || {});
278
+ response = {
279
+ jsonrpc: '2.0',
280
+ id: request.id,
281
+ result
282
+ };
283
+ } else {
284
+ response = {
285
+ jsonrpc: '2.0',
286
+ id: request.id,
287
+ error: {
288
+ code: -32601,
289
+ message: `Method not found: ${request.method}`
290
+ }
291
+ };
292
+ }
293
+
294
+ process.stdout.write(JSON.stringify(response) + '\n');
295
+ } catch (error) {
296
+ const response = {
297
+ jsonrpc: '2.0',
298
+ id: null,
299
+ error: {
300
+ code: -32700,
301
+ message: 'Parse error'
302
+ }
303
+ };
304
+ process.stdout.write(JSON.stringify(response) + '\n');
305
+ }
306
+ });
307
+
308
+ // 初始化
309
+ await server.init();
310
+ console.error('FlowMind MCP Server started');
311
+ }
312
+
313
+ main().catch(console.error);
package/package.json CHANGED
@@ -1,13 +1,15 @@
1
1
  {
2
2
  "name": "flowmind",
3
- "version": "1.0.1",
3
+ "version": "1.1.0",
4
4
  "description": "The AI Agent That Learns How You Work - Stop repeating yourself, FlowMind learns your workflows and applies them automatically.",
5
5
  "main": "core/index.js",
6
6
  "bin": {
7
- "flowmind": "./bin/flowmind.js"
7
+ "flowmind": "./bin/flowmind.js",
8
+ "flowmind-mcp": "./mcp/server.js"
8
9
  },
9
10
  "scripts": {
10
11
  "start": "node core/index.js",
12
+ "mcp": "node mcp/server.js",
11
13
  "test": "jest",
12
14
  "test:coverage": "jest --coverage",
13
15
  "lint": "eslint .",
@@ -21,7 +23,10 @@
21
23
  "learning-system",
22
24
  "code-review",
23
25
  "log-analysis",
24
- "devops"
26
+ "devops",
27
+ "mcp-server",
28
+ "claude-integration",
29
+ "codex-integration"
25
30
  ],
26
31
  "author": "FlowMind Technologies",
27
32
  "license": "MIT",
@@ -36,6 +41,7 @@
36
41
  "files": [
37
42
  "bin/",
38
43
  "core/",
44
+ "mcp/",
39
45
  "skills/",
40
46
  "scripts/",
41
47
  "templates/",