flowmind 1.2.3 → 1.4.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.
Files changed (36) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/README.md +1 -1
  3. package/bin/flowmind.js +69 -16
  4. package/core/ai/base-model.js +47 -28
  5. package/core/ai/model-manager.js +100 -90
  6. package/core/ai/providers/anthropic.js +21 -14
  7. package/core/ai/providers/deepseek.js +12 -2
  8. package/core/ai/providers/ernie.js +2 -2
  9. package/core/ai/providers/glm.js +12 -2
  10. package/core/ai/providers/mimo.js +12 -2
  11. package/core/ai/providers/ollama.js +5 -4
  12. package/core/ai/providers/openai.js +8 -12
  13. package/core/ai/providers/qwen.js +12 -2
  14. package/core/config-manager.js +1 -0
  15. package/core/index.js +183 -6
  16. package/core/learning-engine.js +122 -30
  17. package/mcp/server.js +2 -1
  18. package/package.json +1 -1
  19. package/skills/api-sync/index.js +130 -0
  20. package/skills/archive-change/index.js +104 -0
  21. package/skills/auto-flow/index.js +124 -0
  22. package/skills/code-review/index.js +79 -0
  23. package/skills/code-review-audit/index.js +77 -0
  24. package/skills/data-logic-validation/index.js +108 -0
  25. package/skills/data-validation/index.js +72 -0
  26. package/skills/git-review/index.js +73 -0
  27. package/skills/learning-engine/index.js +50 -0
  28. package/skills/learning-feedback/index.js +83 -0
  29. package/skills/log-audit/index.js +88 -0
  30. package/skills/project-review/index.js +105 -0
  31. package/skills/requirement-analyst/index.js +88 -0
  32. package/skills/resource-bind/index.js +60 -0
  33. package/skills/sls-log-audit/index.js +120 -0
  34. package/skills/yapi-sync-interface/index.js +101 -0
  35. package/skills/yuque-sync-design/index.js +133 -0
  36. package/tui/app.jsx +1 -1
@@ -0,0 +1,101 @@
1
+ /**
2
+ * YApi Sync Interface Skill
3
+ * Sync Controller interfaces to YApi, import/export Swagger
4
+ */
5
+
6
+ module.exports = {
7
+ canHandle(input, context) {
8
+ if (!input) return false;
9
+ return /yapi.*sync|同步.*yapi|yapi.*接口|接口.*yapi|swagger.*import|swagger.*export/i.test(input);
10
+ },
11
+
12
+ async execute(input, context) {
13
+ const apiDoc = context.componentRegistry?.getAdapter('apiDoc');
14
+
15
+ if (!apiDoc) {
16
+ return {
17
+ type: 'result',
18
+ skill: 'yapi-sync-interface',
19
+ message: 'YApi service not configured. Add yapi-mcp component first.',
20
+ data: { hint: 'Configure YApi MCP server in component registry' },
21
+ input,
22
+ timestamp: new Date().toISOString()
23
+ };
24
+ }
25
+
26
+ const params = parseYApiParams(input);
27
+
28
+ if (params.action === 'search') {
29
+ return {
30
+ type: 'result',
31
+ skill: 'yapi-sync-interface',
32
+ message: `Searching YApi for: ${params.keyword || 'all'}`,
33
+ data: {
34
+ mcpTool: 'yapi_search_apis',
35
+ args: { projectKeyword: params.project, nameKeyword: params.keyword, limit: 20 }
36
+ },
37
+ input,
38
+ timestamp: new Date().toISOString()
39
+ };
40
+ }
41
+
42
+ if (params.action === 'list') {
43
+ return {
44
+ type: 'result',
45
+ skill: 'yapi-sync-interface',
46
+ message: `Listing YApi categories for project: ${params.project || 'default'}`,
47
+ data: {
48
+ mcpTool: 'yapi_get_categories',
49
+ args: { projectId: params.project }
50
+ },
51
+ input,
52
+ timestamp: new Date().toISOString()
53
+ };
54
+ }
55
+
56
+ if (params.action === 'export') {
57
+ return {
58
+ type: 'result',
59
+ skill: 'yapi-sync-interface',
60
+ message: `Exporting YApi project: ${params.project}`,
61
+ data: {
62
+ mcpTool: 'yapi_export_project',
63
+ args: { projectId: params.project, type: params.format || 'swagger' }
64
+ },
65
+ input,
66
+ timestamp: new Date().toISOString()
67
+ };
68
+ }
69
+
70
+ return {
71
+ type: 'result',
72
+ skill: 'yapi-sync-interface',
73
+ message: 'YApi sync. Available actions: search, list, export, import',
74
+ data: {
75
+ actions: ['search - Search interfaces', 'list - List categories', 'export - Export project', 'import - Import Swagger'],
76
+ mcpTools: ['yapi_search_apis', 'yapi_get_categories', 'yapi_save_api', 'yapi_import_swagger', 'yapi_export_project']
77
+ },
78
+ input,
79
+ timestamp: new Date().toISOString()
80
+ };
81
+ }
82
+ };
83
+
84
+ function parseYApiParams(input) {
85
+ const params = {};
86
+ if (/搜索|search|查找|find/i.test(input)) params.action = 'search';
87
+ if (/列表|list|分类|categor/i.test(input)) params.action = 'list';
88
+ if (/导出|export/i.test(input)) params.action = 'export';
89
+ if (/导入|import|swagger/i.test(input)) params.action = 'import';
90
+
91
+ const projectMatch = input.match(/(?:项目|project)\s*[:=]?\s*(\S+)/i);
92
+ if (projectMatch) params.project = projectMatch[1];
93
+
94
+ const keywordMatch = input.match(/(?:关键词|keyword|搜索|名称|name)\s*[:=]?\s*(.+?)(?:\s*$)/i);
95
+ if (keywordMatch) params.keyword = keywordMatch[1].trim();
96
+
97
+ const formatMatch = input.match(/(?:格式|format)\s*[:=]?\s*(json|markdown|swagger)/i);
98
+ if (formatMatch) params.format = formatMatch[1].toLowerCase();
99
+
100
+ return params;
101
+ }
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Yuque Sync Design Skill
3
+ * Sync design documents to Yuque knowledge base
4
+ */
5
+
6
+ const fs = require('fs-extra');
7
+ const path = require('path');
8
+
9
+ module.exports = {
10
+ canHandle(input, context) {
11
+ if (!input) return false;
12
+ return /语雀.*同步|yuque.*sync|设计.*文档.*同步|同步.*设计|yuque.*design/i.test(input);
13
+ },
14
+
15
+ async execute(input, context) {
16
+ const knowledgeBase = context.componentRegistry?.getAdapter('knowledgeBase');
17
+
18
+ if (!knowledgeBase) {
19
+ return {
20
+ type: 'result',
21
+ skill: 'yuque-sync-design',
22
+ message: 'Yuque service not configured. Add yuque-mcp component first.',
23
+ data: { hint: 'Configure Yuque MCP server in component registry' },
24
+ input,
25
+ timestamp: new Date().toISOString()
26
+ };
27
+ }
28
+
29
+ const params = parseYuqueParams(input);
30
+
31
+ if (params.action === 'search') {
32
+ return {
33
+ type: 'result',
34
+ skill: 'yuque-sync-design',
35
+ message: `Searching Yuque for: ${params.keyword || 'all'}`,
36
+ data: {
37
+ mcpTool: 'search',
38
+ args: { q: params.keyword, type: 'doc' }
39
+ },
40
+ input,
41
+ timestamp: new Date().toISOString()
42
+ };
43
+ }
44
+
45
+ if (params.action === 'list') {
46
+ return {
47
+ type: 'result',
48
+ skill: 'yuque-sync-design',
49
+ message: 'Listing Yuque repositories',
50
+ data: {
51
+ mcpTool: 'get_user_repos',
52
+ args: {}
53
+ },
54
+ input,
55
+ timestamp: new Date().toISOString()
56
+ };
57
+ }
58
+
59
+ if (params.action === 'sync') {
60
+ return syncDesignDoc(params, input);
61
+ }
62
+
63
+ return {
64
+ type: 'result',
65
+ skill: 'yuque-sync-design',
66
+ message: 'Yuque design sync. Available actions: search, list, sync',
67
+ data: {
68
+ actions: ['search - Search documents', 'list - List repos', 'sync - Sync design doc'],
69
+ mcpTools: ['get_user_repos', 'get_repo_docs', 'get_doc', 'create_doc', 'update_doc', 'search']
70
+ },
71
+ input,
72
+ timestamp: new Date().toISOString()
73
+ };
74
+ }
75
+ };
76
+
77
+ function parseYuqueParams(input) {
78
+ const params = {};
79
+ if (/搜索|search|查找/i.test(input)) params.action = 'search';
80
+ if (/列表|list|仓库|repo/i.test(input)) params.action = 'list';
81
+ if (/同步|sync|上传|push/i.test(input)) params.action = 'sync';
82
+
83
+ const pathMatch = input.match(/(?:路径|path|文件|file)\s*[:=]?\s*(\S+)/i);
84
+ if (pathMatch) params.path = pathMatch[1];
85
+
86
+ const repoMatch = input.match(/(?:仓库|repo|namespace)\s*[:=]?\s*(\S+)/i);
87
+ if (repoMatch) params.repo = repoMatch[1];
88
+
89
+ const keywordMatch = input.match(/(?:关键词|keyword|搜索)\s*[:=]?\s*(.+?)(?:\s*$)/i);
90
+ if (keywordMatch) params.keyword = keywordMatch[1].trim();
91
+
92
+ return params;
93
+ }
94
+
95
+ async function syncDesignDoc(params, input) {
96
+ const filePath = params.path || 'DESIGN.md';
97
+
98
+ if (!(await fs.pathExists(filePath))) {
99
+ return {
100
+ type: 'error',
101
+ skill: 'yuque-sync-design',
102
+ message: `Design file not found: ${filePath}`,
103
+ input,
104
+ timestamp: new Date().toISOString()
105
+ };
106
+ }
107
+
108
+ const content = await fs.readFile(filePath, 'utf-8');
109
+ const title = extractTitle(content) || path.basename(filePath, '.md');
110
+
111
+ return {
112
+ type: 'result',
113
+ skill: 'yuque-sync-design',
114
+ message: `Ready to sync "${title}" to Yuque`,
115
+ data: {
116
+ mcpTool: 'create_doc',
117
+ args: {
118
+ namespace: params.repo,
119
+ slug: title.toLowerCase().replace(/\s+/g, '-'),
120
+ title,
121
+ body: content,
122
+ format: 'markdown'
123
+ }
124
+ },
125
+ input,
126
+ timestamp: new Date().toISOString()
127
+ };
128
+ }
129
+
130
+ function extractTitle(content) {
131
+ const match = content.match(/^#\s+(.+)$/m);
132
+ return match ? match[1].trim() : null;
133
+ }
package/tui/app.jsx CHANGED
@@ -26,7 +26,7 @@ function App({ flowmind }) {
26
26
  if (!mountedRef.current) return;
27
27
  if (result.type === 'result') {
28
28
  const text = typeof result.data === 'string' ? result.data : JSON.stringify(result.data, null, 2);
29
- addResponse(text.substring(0, 200) + (text.length > 200 ? '...' : ''));
29
+ addResponse(text);
30
30
  } else if (result.type === 'learning') {
31
31
  addResponse(result.message || 'Learning recorded');
32
32
  } else if (result.type === 'error') {