flowmind 1.4.8 → 1.5.1
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 +31 -0
- package/bin/flowmind.js +219 -55
- package/core/adapters/workflow-adapter.js +9 -0
- package/core/config-manager.js +8 -1
- package/core/index.js +33 -17
- package/core/learning-engine.js +406 -0
- package/core/providers/friday/flow-adapter.js +8 -0
- package/core/scene-matcher.js +5 -1
- package/core/sdd-agent-sync.js +467 -0
- package/core/skill-loader.js +51 -10
- package/core/utils.js +55 -1
- package/dashboard/app.jsx +5 -5
- package/dashboard/components/ActivityFeed.jsx +7 -6
- package/dashboard/components/DragonPanel.jsx +4 -16
- package/dashboard/components/McpStatusBar.jsx +3 -2
- package/dashboard/components/StatsRow.jsx +6 -8
- package/package.json +2 -2
- package/skills/auto-flow/index.js +320 -45
- package/skills/data-logic-validation/index.js +9 -5
- package/skills/resource-bind/SKILL.md +21 -1
- package/skills/resource-bind/index.js +206 -14
- package/skills/yapi-sync-interface/index.js +14 -7
- package/skills/yuque-sync-design/index.js +15 -8
- package/tui/app.jsx +44 -28
- package/tui/components/ChatPanel.jsx +55 -43
- package/tui/components/DragonTotem.jsx +4 -73
- package/tui/components/Sidebar.jsx +7 -7
- package/tui/components/StatusBar.jsx +5 -6
- package/tui/format-result.js +164 -0
- package/tui/ui.js +186 -0
package/core/learning-engine.js
CHANGED
|
@@ -36,6 +36,7 @@ class LearningEngine {
|
|
|
36
36
|
this.writeQueue = new WriteQueue();
|
|
37
37
|
this.records = {};
|
|
38
38
|
this.skillBindings = {};
|
|
39
|
+
this.resourceBindings = {};
|
|
39
40
|
this.stats = {};
|
|
40
41
|
this.initialized = false;
|
|
41
42
|
}
|
|
@@ -55,6 +56,7 @@ class LearningEngine {
|
|
|
55
56
|
|
|
56
57
|
// Load existing data
|
|
57
58
|
await this.loadSkillBindings();
|
|
59
|
+
await this.loadResourceBindings();
|
|
58
60
|
await this.loadStats();
|
|
59
61
|
|
|
60
62
|
this.initialized = true;
|
|
@@ -309,6 +311,172 @@ class LearningEngine {
|
|
|
309
311
|
return {};
|
|
310
312
|
}
|
|
311
313
|
|
|
314
|
+
/**
|
|
315
|
+
* Save a business/resource binding for later reuse.
|
|
316
|
+
*/
|
|
317
|
+
async saveResourceBinding(binding, context = {}) {
|
|
318
|
+
const normalized = {
|
|
319
|
+
id: binding.id || `bind-${Date.now()}-${uuidv4().slice(0, 8)}`,
|
|
320
|
+
timestamp: binding.timestamp || new Date().toISOString(),
|
|
321
|
+
business: binding.business || 'default',
|
|
322
|
+
aliases: [...new Set([binding.business, ...(binding.aliases || [])].filter(Boolean))],
|
|
323
|
+
componentType: binding.componentType || null,
|
|
324
|
+
provider: binding.provider || null,
|
|
325
|
+
mcpServer: binding.mcpServer || null,
|
|
326
|
+
skill: binding.skill || context.currentSkill || 'resource-bind',
|
|
327
|
+
source: binding.source || 'manual',
|
|
328
|
+
keywords: [...new Set(binding.keywords || this.extractKeywords(binding.business || ''))],
|
|
329
|
+
connection: { ...(binding.connection || {}) },
|
|
330
|
+
metadata: { ...(binding.metadata || {}) },
|
|
331
|
+
stats: {
|
|
332
|
+
useCount: binding.stats?.useCount || 0,
|
|
333
|
+
lastUsed: binding.stats?.lastUsed || null
|
|
334
|
+
}
|
|
335
|
+
};
|
|
336
|
+
|
|
337
|
+
await this.writeQueue.run('resource-bindings', async () => {
|
|
338
|
+
this.resourceBindings.bindings = this.resourceBindings.bindings || [];
|
|
339
|
+
const index = this.resourceBindings.bindings.findIndex((item) => item.id === normalized.id
|
|
340
|
+
|| (item.business === normalized.business
|
|
341
|
+
&& item.componentType === normalized.componentType
|
|
342
|
+
&& item.provider === normalized.provider));
|
|
343
|
+
|
|
344
|
+
if (index >= 0) {
|
|
345
|
+
const previous = this.resourceBindings.bindings[index];
|
|
346
|
+
this.resourceBindings.bindings[index] = {
|
|
347
|
+
...previous,
|
|
348
|
+
...normalized,
|
|
349
|
+
aliases: [...new Set([...(previous.aliases || []), ...normalized.aliases])],
|
|
350
|
+
keywords: [...new Set([...(previous.keywords || []), ...normalized.keywords])],
|
|
351
|
+
connection: { ...(previous.connection || {}), ...(normalized.connection || {}) },
|
|
352
|
+
metadata: { ...(previous.metadata || {}), ...(normalized.metadata || {}) },
|
|
353
|
+
timestamp: normalized.timestamp
|
|
354
|
+
};
|
|
355
|
+
normalized.id = this.resourceBindings.bindings[index].id;
|
|
356
|
+
} else {
|
|
357
|
+
this.resourceBindings.bindings.push(normalized);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
this.resourceBindings.lastUpdated = new Date().toISOString();
|
|
361
|
+
await this.saveResourceBindings();
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
await this.updateStats('resource_binding', normalized.skill);
|
|
365
|
+
|
|
366
|
+
eventBus.emit('learning:recorded', {
|
|
367
|
+
type: 'resource_binding',
|
|
368
|
+
skill: normalized.skill,
|
|
369
|
+
recordId: normalized.id,
|
|
370
|
+
business: normalized.business,
|
|
371
|
+
componentType: normalized.componentType,
|
|
372
|
+
provider: normalized.provider
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
return normalized;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* Return all stored resource bindings.
|
|
380
|
+
*/
|
|
381
|
+
async listResourceBindings() {
|
|
382
|
+
return this.resourceBindings.bindings || [];
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* Find the best-matching binding for an input and skill context.
|
|
387
|
+
*/
|
|
388
|
+
async matchResourceBinding(input, skillName = null) {
|
|
389
|
+
const bindings = this.resourceBindings.bindings || [];
|
|
390
|
+
if (!bindings.length) return null;
|
|
391
|
+
|
|
392
|
+
const componentType = this.inferComponentType(input, skillName);
|
|
393
|
+
const normalized = String(input || '').toLowerCase();
|
|
394
|
+
const preferredBindingId = componentType
|
|
395
|
+
? this.skillBindings.bindings?.[skillName]?.preferredResourceBindings?.[componentType] || null
|
|
396
|
+
: null;
|
|
397
|
+
|
|
398
|
+
let best = null;
|
|
399
|
+
let bestScore = 0;
|
|
400
|
+
|
|
401
|
+
for (const binding of bindings) {
|
|
402
|
+
let score = 0;
|
|
403
|
+
|
|
404
|
+
if (componentType && binding.componentType === componentType) {
|
|
405
|
+
score += 4;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
if (binding.provider && normalized.includes(String(binding.provider).toLowerCase())) {
|
|
409
|
+
score += 3;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
if (binding.mcpServer && normalized.includes(String(binding.mcpServer).toLowerCase())) {
|
|
413
|
+
score += 3;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
if (preferredBindingId && binding.id === preferredBindingId) {
|
|
417
|
+
score += 8;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
for (const alias of binding.aliases || []) {
|
|
421
|
+
if (alias && normalized.includes(String(alias).toLowerCase())) {
|
|
422
|
+
score += 6;
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
for (const keyword of binding.keywords || []) {
|
|
427
|
+
if (keyword && normalized.includes(String(keyword).toLowerCase())) {
|
|
428
|
+
score += 1;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
if (!best || score > bestScore) {
|
|
433
|
+
best = binding;
|
|
434
|
+
bestScore = score;
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
if (!best) return null;
|
|
439
|
+
|
|
440
|
+
if (bestScore === 0) {
|
|
441
|
+
const sameComponent = componentType
|
|
442
|
+
? bindings.filter((binding) => binding.componentType === componentType)
|
|
443
|
+
: [];
|
|
444
|
+
return sameComponent.length === 1 ? sameComponent[0] : null;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
return best;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* Mark a binding as used.
|
|
452
|
+
*/
|
|
453
|
+
async markResourceBindingUsed(bindingId, context = {}) {
|
|
454
|
+
if (!bindingId) return;
|
|
455
|
+
|
|
456
|
+
let updatedBinding = null;
|
|
457
|
+
await this.writeQueue.run('resource-bindings', async () => {
|
|
458
|
+
const bindings = this.resourceBindings.bindings || [];
|
|
459
|
+
const index = bindings.findIndex((binding) => binding.id === bindingId);
|
|
460
|
+
if (index < 0) return;
|
|
461
|
+
|
|
462
|
+
const current = bindings[index];
|
|
463
|
+
updatedBinding = {
|
|
464
|
+
...current,
|
|
465
|
+
stats: {
|
|
466
|
+
useCount: (current.stats?.useCount || 0) + 1,
|
|
467
|
+
lastUsed: new Date().toISOString()
|
|
468
|
+
}
|
|
469
|
+
};
|
|
470
|
+
bindings[index] = updatedBinding;
|
|
471
|
+
this.resourceBindings.lastUpdated = new Date().toISOString();
|
|
472
|
+
await this.saveResourceBindings();
|
|
473
|
+
});
|
|
474
|
+
|
|
475
|
+
if (updatedBinding) {
|
|
476
|
+
await this.promoteResourceBindingPreference(updatedBinding, context);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
312
480
|
/**
|
|
313
481
|
* Save learning record
|
|
314
482
|
*/
|
|
@@ -373,6 +541,191 @@ class LearningEngine {
|
|
|
373
541
|
});
|
|
374
542
|
}
|
|
375
543
|
|
|
544
|
+
async saveAutoGeneratedRecord(record, skill = record.skill || '_global') {
|
|
545
|
+
const recordPath = path.join(
|
|
546
|
+
this.expandPath(this.learningPath),
|
|
547
|
+
'records',
|
|
548
|
+
skill,
|
|
549
|
+
`${record.id}.json`
|
|
550
|
+
);
|
|
551
|
+
|
|
552
|
+
const existed = await fs.pathExists(recordPath);
|
|
553
|
+
await fs.ensureDir(path.dirname(recordPath));
|
|
554
|
+
await fs.writeJson(recordPath, record, { spaces: 2 });
|
|
555
|
+
|
|
556
|
+
if (!this.records[skill]) {
|
|
557
|
+
this.records[skill] = [];
|
|
558
|
+
}
|
|
559
|
+
const index = this.records[skill].findIndex((item) => item.id === record.id);
|
|
560
|
+
if (index >= 0) {
|
|
561
|
+
this.records[skill][index] = record;
|
|
562
|
+
} else {
|
|
563
|
+
this.records[skill].push(record);
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
return { created: !existed, path: recordPath };
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
async savePassivePreferences(skillName, updates) {
|
|
570
|
+
const prefsPath = path.join(
|
|
571
|
+
this.expandPath(this.learningPath),
|
|
572
|
+
'records',
|
|
573
|
+
skillName,
|
|
574
|
+
'preferences.json'
|
|
575
|
+
);
|
|
576
|
+
const queueKey = `prefs:${skillName}`;
|
|
577
|
+
await this.writeQueue.run(queueKey, async () => {
|
|
578
|
+
let prefs = {};
|
|
579
|
+
if (await fs.pathExists(prefsPath)) {
|
|
580
|
+
prefs = await fs.readJson(prefsPath);
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
const next = typeof updates === 'function' ? updates(prefs) : { ...prefs, ...updates };
|
|
584
|
+
next.lastUpdated = new Date().toISOString();
|
|
585
|
+
|
|
586
|
+
await fs.ensureDir(path.dirname(prefsPath));
|
|
587
|
+
await fs.writeJson(prefsPath, next, { spaces: 2 });
|
|
588
|
+
});
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
getAutoPromoteConfig() {
|
|
592
|
+
return this.config.get('learning.autoPromote', {
|
|
593
|
+
enabled: true,
|
|
594
|
+
resourceBindingMinUses: 3,
|
|
595
|
+
sceneMinUses: 2
|
|
596
|
+
});
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
async promoteResourceBindingPreference(binding, context = {}) {
|
|
600
|
+
const config = this.getAutoPromoteConfig();
|
|
601
|
+
const skillName = context.skillName || context.currentSkill || binding.skill || null;
|
|
602
|
+
if (!config.enabled || !skillName || !binding.componentType) {
|
|
603
|
+
return false;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
if ((binding.stats?.useCount || 0) < config.resourceBindingMinUses) {
|
|
607
|
+
return false;
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
this.skillBindings.bindings = this.skillBindings.bindings || {};
|
|
611
|
+
const skillBinding = this.skillBindings.bindings[skillName] || {
|
|
612
|
+
learningCount: 0,
|
|
613
|
+
records: [],
|
|
614
|
+
rules: [],
|
|
615
|
+
preferredResourceBindings: {}
|
|
616
|
+
};
|
|
617
|
+
skillBinding.preferredResourceBindings = skillBinding.preferredResourceBindings || {};
|
|
618
|
+
|
|
619
|
+
const existingPreferred = skillBinding.preferredResourceBindings[binding.componentType];
|
|
620
|
+
const changed = existingPreferred !== binding.id;
|
|
621
|
+
if (changed) {
|
|
622
|
+
skillBinding.preferredResourceBindings[binding.componentType] = binding.id;
|
|
623
|
+
skillBinding.lastLearning = new Date().toISOString();
|
|
624
|
+
this.skillBindings.bindings[skillName] = skillBinding;
|
|
625
|
+
await this.saveSkillBindings();
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
await this.savePassivePreferences(skillName, (prefs) => ({
|
|
629
|
+
...prefs,
|
|
630
|
+
preferredResourceBindings: {
|
|
631
|
+
...(prefs.preferredResourceBindings || {}),
|
|
632
|
+
[binding.componentType]: {
|
|
633
|
+
bindingId: binding.id,
|
|
634
|
+
business: binding.business,
|
|
635
|
+
provider: binding.provider,
|
|
636
|
+
componentType: binding.componentType,
|
|
637
|
+
useCount: binding.stats?.useCount || 0,
|
|
638
|
+
lastUsed: binding.stats?.lastUsed || null
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
}));
|
|
642
|
+
|
|
643
|
+
const record = {
|
|
644
|
+
id: `auto-resource-${skillName}-${binding.componentType}`,
|
|
645
|
+
timestamp: new Date().toISOString(),
|
|
646
|
+
type: 'resource_preference',
|
|
647
|
+
source: 'passive',
|
|
648
|
+
autoGenerated: true,
|
|
649
|
+
input: context.input || binding.metadata?.input || binding.business,
|
|
650
|
+
skill: skillName,
|
|
651
|
+
componentType: binding.componentType,
|
|
652
|
+
business: binding.business,
|
|
653
|
+
provider: binding.provider,
|
|
654
|
+
bindingId: binding.id,
|
|
655
|
+
useCount: binding.stats?.useCount || 0,
|
|
656
|
+
lastUsed: binding.stats?.lastUsed || null,
|
|
657
|
+
application: {
|
|
658
|
+
condition: `When ${skillName} resolves ${binding.componentType}`,
|
|
659
|
+
action: `Prefer resource binding ${binding.business}`,
|
|
660
|
+
priority: 'medium'
|
|
661
|
+
}
|
|
662
|
+
};
|
|
663
|
+
const saved = await this.saveAutoGeneratedRecord(record, skillName);
|
|
664
|
+
if (saved.created) {
|
|
665
|
+
await this.updateStats('resource_preference', skillName);
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
return changed || saved.created;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
async promoteSceneUsage(scene, context = {}) {
|
|
672
|
+
const config = this.getAutoPromoteConfig();
|
|
673
|
+
if (!config.enabled || !scene?.id) {
|
|
674
|
+
return false;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
if ((scene.stats?.useCount || 0) < config.sceneMinUses) {
|
|
678
|
+
return false;
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
const primarySkill = scene.workflow?.skills?.[0]?.skill || 'global';
|
|
682
|
+
const record = {
|
|
683
|
+
id: `auto-scene-${scene.id}`,
|
|
684
|
+
timestamp: new Date().toISOString(),
|
|
685
|
+
type: 'scene_preference',
|
|
686
|
+
source: 'passive',
|
|
687
|
+
autoGenerated: true,
|
|
688
|
+
input: context.input || scene.name,
|
|
689
|
+
skill: '_global',
|
|
690
|
+
sceneId: scene.id,
|
|
691
|
+
sceneName: scene.name,
|
|
692
|
+
primarySkill,
|
|
693
|
+
keywords: scene.keywords || [],
|
|
694
|
+
workflow: scene.workflow || {},
|
|
695
|
+
preferences: scene.preferences || {},
|
|
696
|
+
stats: {
|
|
697
|
+
useCount: scene.stats?.useCount || 0,
|
|
698
|
+
lastUsed: scene.stats?.lastUsed || null,
|
|
699
|
+
successRate: scene.stats?.successRate || 1.0
|
|
700
|
+
},
|
|
701
|
+
application: {
|
|
702
|
+
condition: `When request matches scene ${scene.name}`,
|
|
703
|
+
action: `Apply workflow starting with ${primarySkill}`,
|
|
704
|
+
priority: 'medium'
|
|
705
|
+
}
|
|
706
|
+
};
|
|
707
|
+
|
|
708
|
+
const saved = await this.saveAutoGeneratedRecord(record, '_global');
|
|
709
|
+
if (saved.created) {
|
|
710
|
+
await this.updateStats('scene_preference', 'global');
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
await this.savePassivePreferences('_global', (prefs) => ({
|
|
714
|
+
...prefs,
|
|
715
|
+
preferredScenes: {
|
|
716
|
+
...(prefs.preferredScenes || {}),
|
|
717
|
+
[scene.id]: {
|
|
718
|
+
name: scene.name,
|
|
719
|
+
primarySkill,
|
|
720
|
+
useCount: scene.stats?.useCount || 0,
|
|
721
|
+
successRate: scene.stats?.successRate || 1.0
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
}));
|
|
725
|
+
|
|
726
|
+
return saved.created;
|
|
727
|
+
}
|
|
728
|
+
|
|
376
729
|
/**
|
|
377
730
|
* Update skill bindings
|
|
378
731
|
*/
|
|
@@ -415,6 +768,20 @@ class LearningEngine {
|
|
|
415
768
|
}
|
|
416
769
|
}
|
|
417
770
|
|
|
771
|
+
/**
|
|
772
|
+
* Load resource bindings
|
|
773
|
+
*/
|
|
774
|
+
async loadResourceBindings() {
|
|
775
|
+
const bindingsPath = path.join(this.expandPath(this.learningPath), 'resource-bindings.json');
|
|
776
|
+
|
|
777
|
+
if (await fs.pathExists(bindingsPath)) {
|
|
778
|
+
this.resourceBindings = await fs.readJson(bindingsPath);
|
|
779
|
+
this.resourceBindings.bindings = this.resourceBindings.bindings || [];
|
|
780
|
+
} else {
|
|
781
|
+
this.resourceBindings = { version: '1.0', bindings: [] };
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
|
|
418
785
|
/**
|
|
419
786
|
* Save skill bindings
|
|
420
787
|
*/
|
|
@@ -426,6 +793,15 @@ class LearningEngine {
|
|
|
426
793
|
});
|
|
427
794
|
}
|
|
428
795
|
|
|
796
|
+
/**
|
|
797
|
+
* Save resource bindings
|
|
798
|
+
*/
|
|
799
|
+
async saveResourceBindings() {
|
|
800
|
+
const bindingsPath = path.join(this.expandPath(this.learningPath), 'resource-bindings.json');
|
|
801
|
+
this.resourceBindings.lastUpdated = new Date().toISOString();
|
|
802
|
+
await fs.writeJson(bindingsPath, this.resourceBindings, { spaces: 2 });
|
|
803
|
+
}
|
|
804
|
+
|
|
429
805
|
/**
|
|
430
806
|
* Load stats
|
|
431
807
|
*/
|
|
@@ -480,6 +856,7 @@ class LearningEngine {
|
|
|
480
856
|
exportedAt: new Date().toISOString(),
|
|
481
857
|
stats: this.stats,
|
|
482
858
|
skillBindings: this.skillBindings,
|
|
859
|
+
resourceBindings: this.resourceBindings,
|
|
483
860
|
records: this.records
|
|
484
861
|
};
|
|
485
862
|
|
|
@@ -513,8 +890,23 @@ class LearningEngine {
|
|
|
513
890
|
}
|
|
514
891
|
}
|
|
515
892
|
|
|
893
|
+
// Merge resource bindings
|
|
894
|
+
const existing = this.resourceBindings.bindings || [];
|
|
895
|
+
const incoming = data.resourceBindings?.bindings || [];
|
|
896
|
+
for (const binding of incoming) {
|
|
897
|
+
const match = existing.find((item) => item.id === binding.id
|
|
898
|
+
|| (item.business === binding.business
|
|
899
|
+
&& item.componentType === binding.componentType
|
|
900
|
+
&& item.provider === binding.provider));
|
|
901
|
+
if (!match) {
|
|
902
|
+
existing.push(binding);
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
this.resourceBindings.bindings = existing;
|
|
906
|
+
|
|
516
907
|
// Save
|
|
517
908
|
await this.saveSkillBindings();
|
|
909
|
+
await this.saveResourceBindings();
|
|
518
910
|
await this.saveStats();
|
|
519
911
|
|
|
520
912
|
return { success: true, imported: data.stats.totalRecords };
|
|
@@ -619,6 +1011,20 @@ class LearningEngine {
|
|
|
619
1011
|
return [...new Set(words)].slice(0, 10);
|
|
620
1012
|
}
|
|
621
1013
|
|
|
1014
|
+
inferComponentType(input, skillName = null) {
|
|
1015
|
+
const normalized = `${skillName || ''} ${input || ''}`.toLowerCase();
|
|
1016
|
+
|
|
1017
|
+
if (/yapi|api 文档|api doc|swagger|接口/.test(normalized)) return 'apiDoc';
|
|
1018
|
+
if (/yuque|语雀|knowledge base|知识库|design/.test(normalized)) return 'knowledgeBase';
|
|
1019
|
+
if (/redis|缓存|cache/.test(normalized)) return 'redisMonitor';
|
|
1020
|
+
if (/sql|数据库|database|rds|dms/.test(normalized)) return 'databaseQuery';
|
|
1021
|
+
if (/log|日志|trace|sls/.test(normalized)) return 'logService';
|
|
1022
|
+
if (/pipeline|workflow|部署|流水线/.test(normalized)) return 'workflow';
|
|
1023
|
+
if (/report|coverage|报告/.test(normalized)) return 'report';
|
|
1024
|
+
|
|
1025
|
+
return null;
|
|
1026
|
+
}
|
|
1027
|
+
|
|
622
1028
|
extractWorkflow(input) {
|
|
623
1029
|
// Extract workflow steps
|
|
624
1030
|
return {
|
|
@@ -65,6 +65,14 @@ class FridayFlowAdapter extends WorkflowAdapter {
|
|
|
65
65
|
};
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
async startBatchPipelineRun(params) {
|
|
69
|
+
return {
|
|
70
|
+
mcpServer: this.mcpServer,
|
|
71
|
+
tool: this.resolveTool('startBatchPipelineRun'),
|
|
72
|
+
params: params || {}
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
68
76
|
async getPipelineRun(pipelineId, runId) {
|
|
69
77
|
return {
|
|
70
78
|
mcpServer: this.mcpServer,
|
package/core/scene-matcher.js
CHANGED
|
@@ -239,7 +239,7 @@ class SceneMatcher {
|
|
|
239
239
|
/**
|
|
240
240
|
* Update scene usage stats
|
|
241
241
|
*/
|
|
242
|
-
async updateSceneStats(sceneId, success) {
|
|
242
|
+
async updateSceneStats(sceneId, success, context = {}) {
|
|
243
243
|
const scene = this.scenes.find(s => s.id === sceneId);
|
|
244
244
|
if (!scene) return;
|
|
245
245
|
|
|
@@ -254,6 +254,10 @@ class SceneMatcher {
|
|
|
254
254
|
|
|
255
255
|
// Save updated scenes
|
|
256
256
|
await this.saveScenes();
|
|
257
|
+
|
|
258
|
+
if (success && this.learning?.promoteSceneUsage) {
|
|
259
|
+
await this.learning.promoteSceneUsage(scene, context);
|
|
260
|
+
}
|
|
257
261
|
}
|
|
258
262
|
|
|
259
263
|
/**
|