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,73 @@
1
+ /**
2
+ * Git Review Skill
3
+ * Reviews commit history, analyzes changes, ensures code quality
4
+ */
5
+
6
+ const { execSync } = require('child_process');
7
+
8
+ module.exports = {
9
+ canHandle(input, context) {
10
+ if (!input) return false;
11
+ return /git\s*review|commit.*review|代码提交|提交审查|review.*commit|检查提交/i.test(input);
12
+ },
13
+
14
+ async execute(input, context) {
15
+ const count = extractCount(input) || 5;
16
+
17
+ try {
18
+ const logRaw = execSync(
19
+ `git log --oneline -${count} --format="%H|%s|%an|%ai"`,
20
+ { encoding: 'utf-8', timeout: 10000 }
21
+ ).trim();
22
+
23
+ if (!logRaw) {
24
+ return { type: 'result', skill: 'git-review', message: 'No commits found', input, timestamp: new Date().toISOString() };
25
+ }
26
+
27
+ const commits = logRaw.split('\n').map(line => {
28
+ const [hash, subject, author, date] = line.split('|');
29
+ return { hash: hash?.slice(0, 8), subject, author, date };
30
+ });
31
+
32
+ const issues = [];
33
+ const good = [];
34
+
35
+ commits.forEach(c => {
36
+ // Check conventional commit format
37
+ const conventional = /^(feat|fix|docs|style|refactor|test|chore|perf|ci|build)(\(.+\))?: .+/;
38
+ if (!conventional.test(c.subject)) {
39
+ issues.push({ hash: c.hash, type: 'format', message: `Non-conventional commit message: "${c.subject}"` });
40
+ } else {
41
+ good.push({ hash: c.hash, message: c.subject });
42
+ }
43
+
44
+ // Check length
45
+ if (c.subject && c.subject.length > 72) {
46
+ issues.push({ hash: c.hash, type: 'length', message: `Subject too long (${c.subject.length} chars)` });
47
+ }
48
+ });
49
+
50
+ return {
51
+ type: 'result',
52
+ skill: 'git-review',
53
+ message: `Reviewed ${commits.length} commits: ${good.length} good, ${issues.length} issues`,
54
+ data: { commits, issues, good, summary: { total: commits.length, good: good.length, issues: issues.length } },
55
+ input,
56
+ timestamp: new Date().toISOString()
57
+ };
58
+ } catch (e) {
59
+ return {
60
+ type: 'error',
61
+ skill: 'git-review',
62
+ message: `Git review failed: ${e.message}`,
63
+ input,
64
+ timestamp: new Date().toISOString()
65
+ };
66
+ }
67
+ }
68
+ };
69
+
70
+ function extractCount(input) {
71
+ const match = input.match(/(\d+)\s*(?:个|条|commits?|次)/i) || input.match(/-(\d+)/);
72
+ return match ? parseInt(match[1]) : null;
73
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Learning Engine Skill
3
+ * Delegates to core LearningEngine for detecting and recording learning patterns
4
+ */
5
+
6
+ module.exports = {
7
+ canHandle(input, context) {
8
+ if (!input) return false;
9
+ const lower = input.toLowerCase();
10
+ const patterns = [
11
+ /不[对是]/, /错[了误]/, /应该[是用]/, /改[成为]/, /优化/, /改进/,
12
+ /记住/, /学习/, /纠正/, /prefer/, /learn/, /correct/, /remember/
13
+ ];
14
+ return patterns.some(p => p.test(lower));
15
+ },
16
+
17
+ async execute(input, context) {
18
+ const learning = context.flowmind?.learning;
19
+ if (!learning) {
20
+ return {
21
+ type: 'error',
22
+ skill: 'learning-engine',
23
+ message: 'Learning engine not available',
24
+ input
25
+ };
26
+ }
27
+
28
+ const result = await learning.detectLearning(input, context);
29
+
30
+ if (result) {
31
+ return {
32
+ type: 'learning',
33
+ skill: 'learning-engine',
34
+ learningType: result.type,
35
+ message: result.message || `Detected ${result.type} learning pattern`,
36
+ data: result,
37
+ input,
38
+ timestamp: new Date().toISOString()
39
+ };
40
+ }
41
+
42
+ return {
43
+ type: 'result',
44
+ skill: 'learning-engine',
45
+ message: 'No learning pattern detected in input',
46
+ input,
47
+ timestamp: new Date().toISOString()
48
+ };
49
+ }
50
+ };
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Learning Feedback Skill
3
+ * Captures user corrections, feedback, and refinement suggestions.
4
+ * Overlaps with learning-engine but focuses on feedback capture and binding.
5
+ */
6
+
7
+ module.exports = {
8
+ canHandle(input, context) {
9
+ if (!input) return false;
10
+ const lower = input.toLowerCase();
11
+ const feedbackPatterns = [
12
+ /不对/, /错了/, /应该是/, /不要/, /别这样/,
13
+ /下次/, /以后/, /记得/, /别再/, /改成/,
14
+ /wrong/, /should be/, /don't/, /next time/, /change to/
15
+ ];
16
+ return feedbackPatterns.some(p => p.test(lower));
17
+ },
18
+
19
+ async execute(input, context) {
20
+ const learning = context.flowmind?.learning;
21
+ if (!learning) {
22
+ return {
23
+ type: 'error',
24
+ skill: 'learning-feedback',
25
+ message: 'Learning engine not available',
26
+ input
27
+ };
28
+ }
29
+
30
+ // Detect correction patterns
31
+ const correction = learning.detectCorrection(input);
32
+ if (correction) {
33
+ const record = await learning.recordCorrection(correction, context);
34
+ return {
35
+ type: 'learning',
36
+ skill: 'learning-feedback',
37
+ learningType: 'correction',
38
+ message: `Recorded correction: ${correction.summary || 'user feedback captured'}`,
39
+ data: record,
40
+ input,
41
+ timestamp: new Date().toISOString()
42
+ };
43
+ }
44
+
45
+ // Detect preference patterns
46
+ const preference = learning.detectPreference(input);
47
+ if (preference) {
48
+ const record = await learning.recordPreference(preference, context);
49
+ return {
50
+ type: 'learning',
51
+ skill: 'learning-feedback',
52
+ learningType: 'preference',
53
+ message: `Recorded preference: ${preference.type} = ${preference.value}`,
54
+ data: record,
55
+ input,
56
+ timestamp: new Date().toISOString()
57
+ };
58
+ }
59
+
60
+ // Detect scene mapping
61
+ const scene = learning.detectSceneMapping(input);
62
+ if (scene) {
63
+ const record = await learning.recordSceneMapping(scene, context);
64
+ return {
65
+ type: 'learning',
66
+ skill: 'learning-feedback',
67
+ learningType: 'scene_mapping',
68
+ message: `Recorded scene mapping for skill: ${scene.skill}`,
69
+ data: record,
70
+ input,
71
+ timestamp: new Date().toISOString()
72
+ };
73
+ }
74
+
75
+ return {
76
+ type: 'result',
77
+ skill: 'learning-feedback',
78
+ message: 'No feedback pattern detected',
79
+ input,
80
+ timestamp: new Date().toISOString()
81
+ };
82
+ }
83
+ };
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Log Audit Skill
3
+ * Analyzes application logs, traces requests, debugs performance issues
4
+ */
5
+
6
+ module.exports = {
7
+ canHandle(input, context) {
8
+ if (!input) return false;
9
+ return /日志分析|log.*audit|日志查询|查日志|log.*analy|trace.*id|调用链/i.test(input);
10
+ },
11
+
12
+ async execute(input, context) {
13
+ const logService = context.componentRegistry?.getAdapter('logService');
14
+ const params = parseLogParams(input);
15
+
16
+ if (!logService && !params.mock) {
17
+ return {
18
+ type: 'result',
19
+ skill: 'log-audit',
20
+ message: 'Log service not configured. Connect an SLS/ELK log service first.',
21
+ data: { params, hint: 'Use `flowmind resource` to configure log service connections' },
22
+ input,
23
+ timestamp: new Date().toISOString()
24
+ };
25
+ }
26
+
27
+ // If we have a log service, format the query for MCP tools
28
+ if (params.traceId) {
29
+ return {
30
+ type: 'result',
31
+ skill: 'log-audit',
32
+ message: `Trace query for: ${params.traceId}`,
33
+ data: {
34
+ action: 'trace',
35
+ traceId: params.traceId,
36
+ query: `* and "${params.traceId}"`,
37
+ timeRange: params.timeRange || 'last 1 hour',
38
+ endpoint: params.endpoint || 'cn-shenzhen.log.aliyuncs.com'
39
+ },
40
+ input,
41
+ timestamp: new Date().toISOString()
42
+ };
43
+ }
44
+
45
+ return {
46
+ type: 'result',
47
+ skill: 'log-audit',
48
+ message: `Log query: ${params.service || 'all services'}, ${params.level || 'all levels'}, ${params.timeRange || 'last 1 hour'}`,
49
+ data: {
50
+ action: 'query',
51
+ query: buildSLSQuery(params),
52
+ timeRange: params.timeRange || 'last 1 hour',
53
+ endpoint: params.endpoint || 'cn-shenzhen.log.aliyuncs.com',
54
+ limit: params.limit || 100
55
+ },
56
+ input,
57
+ timestamp: new Date().toISOString()
58
+ };
59
+ }
60
+ };
61
+
62
+ function parseLogParams(input) {
63
+ const params = {};
64
+ const traceMatch = input.match(/(?:trace[_-]?id|调用链)\s*[:=]?\s*(\S+)/i);
65
+ if (traceMatch) params.traceId = traceMatch[1];
66
+
67
+ const serviceMatch = input.match(/(?:服务|service)\s*[:=]?\s*(\S+)/i);
68
+ if (serviceMatch) params.service = serviceMatch[1];
69
+
70
+ const levelMatch = input.match(/(?:级别|level)\s*[:=]?\s*(ERROR|WARN|INFO|DEBUG)/i);
71
+ if (levelMatch) params.level = levelMatch[1].toUpperCase();
72
+
73
+ const timeMatch = input.match(/(?:最近|last)\s*(\d+)\s*(分钟|小时|分钟|min|hour)/i);
74
+ if (timeMatch) params.timeRange = `last ${timeMatch[1]} ${timeMatch[2]}`;
75
+
76
+ const keywordMatch = input.match(/(?:关键词|keyword|搜索|search)\s*[:=]?\s*(.+?)(?:\s*$)/i);
77
+ if (keywordMatch) params.keyword = keywordMatch[1].trim();
78
+
79
+ return params;
80
+ }
81
+
82
+ function buildSLSQuery(params) {
83
+ const parts = [];
84
+ if (params.service) parts.push(`service: ${params.service}`);
85
+ if (params.level) parts.push(`level: ${params.level}`);
86
+ if (params.keyword) parts.push(`"${params.keyword}"`);
87
+ return parts.length > 0 ? parts.join(' and ') : '*';
88
+ }
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Project Review Skill
3
+ * Analyzes project health, dependencies, and overall quality
4
+ */
5
+
6
+ const fs = require('fs-extra');
7
+ const path = require('path');
8
+ const { execSync } = require('child_process');
9
+
10
+ module.exports = {
11
+ canHandle(input, context) {
12
+ if (!input) return false;
13
+ return /项目审查|project review|项目健康|health check|依赖检查|dependency/i.test(input);
14
+ },
15
+
16
+ async execute(input, context) {
17
+ const projectDir = extractProjectDir(input) || process.cwd();
18
+ const checks = [];
19
+ let score = 100;
20
+
21
+ // Check package.json
22
+ const pkgPath = path.join(projectDir, 'package.json');
23
+ if (await fs.pathExists(pkgPath)) {
24
+ const pkg = await fs.readJson(pkgPath);
25
+
26
+ // Check for missing description
27
+ if (!pkg.description) {
28
+ checks.push({ type: 'warning', name: 'Missing description', impact: -5 });
29
+ score -= 5;
30
+ }
31
+
32
+ // Check for missing license
33
+ if (!pkg.license) {
34
+ checks.push({ type: 'warning', name: 'Missing license', impact: -5 });
35
+ score -= 5;
36
+ }
37
+
38
+ // Check for missing test script
39
+ if (!pkg.scripts?.test || pkg.scripts.test === 'echo "Error: no test specified"') {
40
+ checks.push({ type: 'warning', name: 'No test script configured', impact: -10 });
41
+ score -= 10;
42
+ }
43
+
44
+ // Check for missing lint script
45
+ if (!pkg.scripts?.lint) {
46
+ checks.push({ type: 'info', name: 'No lint script configured', impact: -5 });
47
+ score -= 5;
48
+ }
49
+
50
+ // Check dependency count
51
+ const deps = Object.keys(pkg.dependencies || {});
52
+ const devDeps = Object.keys(pkg.devDependencies || {});
53
+ checks.push({ type: 'info', name: `Dependencies: ${deps.length} prod, ${devDeps.length} dev` });
54
+
55
+ // Check for outdated (if npm is available)
56
+ try {
57
+ const outdated = execSync('npm outdated --json 2>/dev/null || echo "{}"', {
58
+ encoding: 'utf-8', cwd: projectDir, timeout: 30000
59
+ });
60
+ const outdatedPkgs = JSON.parse(outdated);
61
+ const count = Object.keys(outdatedPkgs).length;
62
+ if (count > 0) {
63
+ checks.push({ type: 'warning', name: `${count} outdated package(s)`, impact: -5 });
64
+ score -= 5;
65
+ }
66
+ } catch {}
67
+ } else {
68
+ checks.push({ type: 'error', name: 'No package.json found', impact: -20 });
69
+ score -= 20;
70
+ }
71
+
72
+ // Check for README
73
+ if (!(await fs.pathExists(path.join(projectDir, 'README.md')))) {
74
+ checks.push({ type: 'warning', name: 'No README.md', impact: -10 });
75
+ score -= 10;
76
+ }
77
+
78
+ // Check for .git
79
+ if (!(await fs.pathExists(path.join(projectDir, '.git')))) {
80
+ checks.push({ type: 'info', name: 'Not a git repository' });
81
+ }
82
+
83
+ // Check for .gitignore
84
+ if (!(await fs.pathExists(path.join(projectDir, '.gitignore')))) {
85
+ checks.push({ type: 'warning', name: 'No .gitignore', impact: -5 });
86
+ score -= 5;
87
+ }
88
+
89
+ score = Math.max(0, score);
90
+
91
+ return {
92
+ type: 'result',
93
+ skill: 'project-review',
94
+ message: `Project health score: ${score}/100 (${checks.filter(c => c.type === 'warning' || c.type === 'error').length} issues)`,
95
+ data: { score, checks, summary: { score, issues: checks.filter(c => c.type !== 'info').length } },
96
+ input,
97
+ timestamp: new Date().toISOString()
98
+ };
99
+ }
100
+ };
101
+
102
+ function extractProjectDir(input) {
103
+ const match = input.match(/(?:项目|project|目录|dir)\s+(.+?)(?:\s|$)/i);
104
+ return match ? match[1].trim() : null;
105
+ }
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Requirement Analyst Skill
3
+ * Six-dimensional analysis of requirements, design, and code alignment
4
+ */
5
+
6
+ module.exports = {
7
+ canHandle(input, context) {
8
+ if (!input) return false;
9
+ return /需求分析|requirement.*analy|六维分析|需求.*审查|分析需求/i.test(input);
10
+ },
11
+
12
+ async execute(input, context) {
13
+ const dimensions = [
14
+ { name: '历史设计原则', weight: 0.15, description: '评估历史设计意图、依据、当前有效性' },
15
+ { name: '迭代合理性', weight: 0.15, description: '评估迭代驱动力、演进路径、迭代质量' },
16
+ { name: '可扩展性', weight: 0.20, description: '评估开发扩展性、需求升级扩展性、用户增长扩展性' },
17
+ { name: '市场路线图', weight: 0.15, description: '评估功能覆盖度、需求趋势、竞争定位' },
18
+ { name: '需求代码偏差', weight: 0.20, description: '评估功能缺失、过度实现、理解偏差' },
19
+ { name: '升级脆弱性', weight: 0.15, description: '评估数据模型脆弱性、API不兼容、硬编码陷阱' }
20
+ ];
21
+
22
+ const requirementText = extractRequirement(input);
23
+
24
+ if (!requirementText) {
25
+ return {
26
+ type: 'result',
27
+ skill: 'requirement-analyst',
28
+ message: 'Please provide requirement text or a requirement document path for analysis',
29
+ data: { dimensions: dimensions.map(d => ({ ...d, score: null })) },
30
+ input,
31
+ timestamp: new Date().toISOString()
32
+ };
33
+ }
34
+
35
+ // Basic analysis based on text content
36
+ const analysis = dimensions.map(dim => {
37
+ const keywords = getDimensionKeywords(dim.name);
38
+ const matches = keywords.filter(k => requirementText.toLowerCase().includes(k));
39
+ const coverage = Math.min(1, matches.length / Math.max(1, keywords.length * 0.3));
40
+ const score = Math.round(50 + coverage * 50);
41
+
42
+ return {
43
+ name: dim.name,
44
+ weight: dim.weight,
45
+ score,
46
+ description: dim.description,
47
+ findings: matches.length > 0 ? [`Found ${matches.length} relevant keywords`] : ['Insufficient data for analysis']
48
+ };
49
+ });
50
+
51
+ const overallScore = Math.round(
52
+ analysis.reduce((sum, d) => sum + d.score * d.weight, 0)
53
+ );
54
+
55
+ const priorityActions = [];
56
+ analysis.filter(d => d.score < 60).forEach(d => {
57
+ priorityActions.push({ priority: d.score < 40 ? 'P0' : 'P1', dimension: d.name, action: `Improve ${d.name}` });
58
+ });
59
+
60
+ return {
61
+ type: 'result',
62
+ skill: 'requirement-analyst',
63
+ message: `Six-dimensional analysis complete. Overall score: ${overallScore}/100`,
64
+ data: { overallScore, dimensions: analysis, priorityActions },
65
+ input,
66
+ timestamp: new Date().toISOString()
67
+ };
68
+ }
69
+ };
70
+
71
+ function extractRequirement(input) {
72
+ const jsonMatch = input.match(/\{[\s\S]*\}/);
73
+ if (jsonMatch) return jsonMatch[0];
74
+ const textMatch = input.replace(/需求分析|requirement.*analy|分析/gi, '').trim();
75
+ return textMatch.length > 10 ? textMatch : null;
76
+ }
77
+
78
+ function getDimensionKeywords(dimName) {
79
+ const map = {
80
+ '历史设计原则': ['设计', '架构', '历史', '原理', '依据', 'design', 'architecture'],
81
+ '迭代合理性': ['迭代', '版本', '功能', '需求', 'iteration', 'feature', 'release'],
82
+ '可扩展性': ['扩展', '模块', '接口', '性能', 'scalable', 'extensible', 'modular'],
83
+ '市场路线图': ['市场', '竞争', '路线', '规划', 'market', 'roadmap', 'competitive'],
84
+ '需求代码偏差': ['偏差', '缺失', '过度', '偏差', 'gap', 'deviation', 'mismatch'],
85
+ '升级脆弱性': ['脆弱', '兼容', '硬编码', '升级', 'fragile', 'breaking', 'migration']
86
+ };
87
+ return map[dimName] || [];
88
+ }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Resource Bind Skill
3
+ * Manage database, Redis, API, and other external resource connections
4
+ */
5
+
6
+ module.exports = {
7
+ canHandle(input, context) {
8
+ if (!input) return false;
9
+ return /资源绑定|resource.*bind|数据库.*连接|redis.*连接|连接.*管理|connection.*manage/i.test(input);
10
+ },
11
+
12
+ async execute(input, context) {
13
+ const registry = context.componentRegistry;
14
+ const params = parseResourceParams(input);
15
+
16
+ if (params.action === 'list') {
17
+ const components = registry ? registry.getAll() : [];
18
+ return {
19
+ type: 'result',
20
+ skill: 'resource-bind',
21
+ message: `Found ${components.length} configured component(s)`,
22
+ data: { components: components.map(c => ({ name: c.name, type: c.type, active: c.active })) },
23
+ input,
24
+ timestamp: new Date().toISOString()
25
+ };
26
+ }
27
+
28
+ if (params.action === 'status') {
29
+ const status = registry ? registry.getStatus() : {};
30
+ return {
31
+ type: 'result',
32
+ skill: 'resource-bind',
33
+ message: 'Resource connection status',
34
+ data: { status },
35
+ input,
36
+ timestamp: new Date().toISOString()
37
+ };
38
+ }
39
+
40
+ return {
41
+ type: 'result',
42
+ skill: 'resource-bind',
43
+ message: 'Resource binding. Available actions: list, status',
44
+ data: {
45
+ actions: ['list - List all resources', 'status - Show connection status'],
46
+ supportedTypes: ['MySQL', 'PostgreSQL', 'Redis', 'REST API']
47
+ },
48
+ input,
49
+ timestamp: new Date().toISOString()
50
+ };
51
+ }
52
+ };
53
+
54
+ function parseResourceParams(input) {
55
+ const params = {};
56
+ if (/列表|list|查看|show/i.test(input)) params.action = 'list';
57
+ if (/状态|status|连接/i.test(input)) params.action = 'status';
58
+ if (/绑定|bind|添加|add/i.test(input)) params.action = 'bind';
59
+ return params;
60
+ }
@@ -0,0 +1,120 @@
1
+ /**
2
+ * SLS Log Audit Skill
3
+ * Query Alibaba Cloud SLS logs, trace ID chain analysis, performance analysis
4
+ */
5
+
6
+ module.exports = {
7
+ canHandle(input, context) {
8
+ if (!input) return false;
9
+ return /sls.*日志|sls.*log|阿里云.*日志|trace.*分析|feign.*链|调用链.*分析/i.test(input);
10
+ },
11
+
12
+ async execute(input, context) {
13
+ const params = parseSLSParams(input);
14
+
15
+ // Determine default endpoint based on environment
16
+ const env = params.env || 'test';
17
+ const endpointMap = {
18
+ test: 'cn-shenzhen.log.aliyuncs.com',
19
+ uat: 'cn-shenzhen.log.aliyuncs.com',
20
+ gray: 'cn-hongkong.log.aliyuncs.com',
21
+ prod: 'cn-hongkong.log.aliyuncs.com'
22
+ };
23
+ const endpoint = endpointMap[env] || endpointMap.test;
24
+
25
+ if (params.traceId) {
26
+ return {
27
+ type: 'result',
28
+ skill: 'sls-log-audit',
29
+ message: `SLS TraceID chain analysis: ${params.traceId}`,
30
+ data: {
31
+ action: 'trace_chain',
32
+ traceId: params.traceId,
33
+ query: `* and "${params.traceId}"`,
34
+ endpoint,
35
+ project: params.project,
36
+ logstore: params.logstore,
37
+ timeRange: params.timeRange || 'last 1 hour'
38
+ },
39
+ input,
40
+ timestamp: new Date().toISOString()
41
+ };
42
+ }
43
+
44
+ if (params.keyword?.includes('feign') || /feign/i.test(input)) {
45
+ return {
46
+ type: 'result',
47
+ skill: 'sls-log-audit',
48
+ message: 'Feign call chain extraction',
49
+ data: {
50
+ action: 'feign_chain',
51
+ query: buildFeignQuery(params),
52
+ endpoint,
53
+ project: params.project,
54
+ logstore: params.logstore,
55
+ timeRange: params.timeRange || 'last 1 hour'
56
+ },
57
+ input,
58
+ timestamp: new Date().toISOString()
59
+ };
60
+ }
61
+
62
+ return {
63
+ type: 'result',
64
+ skill: 'sls-log-audit',
65
+ message: `SLS query: ${params.service || 'all'}, ${params.level || 'all'}, ${params.timeRange || 'last 1 hour'}`,
66
+ data: {
67
+ action: 'query',
68
+ query: buildSLSQuery(params),
69
+ endpoint,
70
+ project: params.project,
71
+ logstore: params.logstore,
72
+ timeRange: params.timeRange || 'last 1 hour',
73
+ limit: params.limit || 100
74
+ },
75
+ input,
76
+ timestamp: new Date().toISOString()
77
+ };
78
+ }
79
+ };
80
+
81
+ function parseSLSParams(input) {
82
+ const params = {};
83
+ const traceMatch = input.match(/trace[_-]?id\s*[:=]?\s*(\S+)/i);
84
+ if (traceMatch) params.traceId = traceMatch[1];
85
+
86
+ const serviceMatch = input.match(/(?:服务|service)\s*[:=]?\s*(\S+)/i);
87
+ if (serviceMatch) params.service = serviceMatch[1];
88
+
89
+ const levelMatch = input.match(/(?:级别|level)\s*[:=]?\s*(ERROR|WARN|INFO|DEBUG)/i);
90
+ if (levelMatch) params.level = levelMatch[1].toUpperCase();
91
+
92
+ const projectMatch = input.match(/(?:项目|project)\s*[:=]?\s*(\S+)/i);
93
+ if (projectMatch) params.project = projectMatch[1];
94
+
95
+ const logstoreMatch = input.match(/(?:logstore|日志库)\s*[:=]?\s*(\S+)/i);
96
+ if (logstoreMatch) params.logstore = logstoreMatch[1];
97
+
98
+ const envMatch = input.match(/(?:环境|env)\s*[:=]?\s*(test|uat|gray|prod)/i);
99
+ if (envMatch) params.env = envMatch[1].toLowerCase();
100
+
101
+ const timeMatch = input.match(/(?:最近|last)\s*(\d+)\s*(分钟|小时|min|hour)/i);
102
+ if (timeMatch) params.timeRange = `last ${timeMatch[1]} ${timeMatch[2]}`;
103
+
104
+ const keywordMatch = input.match(/(?:关键词|keyword|搜索)\s*[:=]?\s*(.+?)(?:\s*$)/i);
105
+ if (keywordMatch) params.keyword = keywordMatch[1].trim();
106
+
107
+ return params;
108
+ }
109
+
110
+ function buildSLSQuery(params) {
111
+ const parts = [];
112
+ if (params.service) parts.push(`service: ${params.service}`);
113
+ if (params.level) parts.push(`level: ${params.level}`);
114
+ if (params.keyword) parts.push(`"${params.keyword}"`);
115
+ return parts.length > 0 ? parts.join(' and ') : '*';
116
+ }
117
+
118
+ function buildFeignQuery(params) {
119
+ return `* and "feign" ${params.service ? `and service: ${params.service}` : ''}`;
120
+ }