memory-pulse-mcp-server 0.1.13 → 0.1.15
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/dist/index.js +1136 -31
- package/dist/index.js.map +1 -1
- package/package.json +15 -14
- package/LICENSE +0 -26
package/dist/index.js
CHANGED
|
@@ -27,11 +27,11 @@ var MemoryType;
|
|
|
27
27
|
MemoryType2["SESSION"] = "session";
|
|
28
28
|
})(MemoryType || (MemoryType = {}));
|
|
29
29
|
var SearchStrategy;
|
|
30
|
-
(function(
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
(function(SearchStrategy3) {
|
|
31
|
+
SearchStrategy3["EXACT"] = "exact";
|
|
32
|
+
SearchStrategy3["FULLTEXT"] = "fulltext";
|
|
33
|
+
SearchStrategy3["SEMANTIC"] = "semantic";
|
|
34
|
+
SearchStrategy3["AUTO"] = "auto";
|
|
35
35
|
})(SearchStrategy || (SearchStrategy = {}));
|
|
36
36
|
|
|
37
37
|
// ../core/dist/features.js
|
|
@@ -270,6 +270,425 @@ function deserializeVector(s) {
|
|
|
270
270
|
return Array.from(buffer);
|
|
271
271
|
}
|
|
272
272
|
|
|
273
|
+
// ../core/dist/keywords.js
|
|
274
|
+
var CHINESE_STOP_WORDS = /* @__PURE__ */ new Set([
|
|
275
|
+
"\u7684",
|
|
276
|
+
"\u662F",
|
|
277
|
+
"\u5728",
|
|
278
|
+
"\u4E86",
|
|
279
|
+
"\u548C",
|
|
280
|
+
"\u4E0E",
|
|
281
|
+
"\u6216",
|
|
282
|
+
"\u6709",
|
|
283
|
+
"\u8FD9",
|
|
284
|
+
"\u90A3",
|
|
285
|
+
"\u6211",
|
|
286
|
+
"\u4F60",
|
|
287
|
+
"\u4ED6",
|
|
288
|
+
"\u5979",
|
|
289
|
+
"\u5B83",
|
|
290
|
+
"\u4EEC",
|
|
291
|
+
"\u4E0D",
|
|
292
|
+
"\u4E5F",
|
|
293
|
+
"\u5C31",
|
|
294
|
+
"\u90FD",
|
|
295
|
+
"\u4E3A",
|
|
296
|
+
"\u88AB",
|
|
297
|
+
"\u7740",
|
|
298
|
+
"\u8BA9",
|
|
299
|
+
"\u628A",
|
|
300
|
+
"\u7ED9",
|
|
301
|
+
"\u4ECE",
|
|
302
|
+
"\u5230",
|
|
303
|
+
"\u5BF9",
|
|
304
|
+
"\u4E8E",
|
|
305
|
+
"\u4F46",
|
|
306
|
+
"\u800C",
|
|
307
|
+
"\u53CA",
|
|
308
|
+
"\u8FD8",
|
|
309
|
+
"\u4EE5",
|
|
310
|
+
"\u6240",
|
|
311
|
+
"\u5982",
|
|
312
|
+
"\u5219",
|
|
313
|
+
"\u7B49",
|
|
314
|
+
"\u8BE5",
|
|
315
|
+
"\u8FD9\u4E2A",
|
|
316
|
+
"\u90A3\u4E2A",
|
|
317
|
+
"\u4E00\u4E2A",
|
|
318
|
+
"\u4EC0\u4E48",
|
|
319
|
+
"\u600E\u4E48",
|
|
320
|
+
"\u5982\u4F55",
|
|
321
|
+
"\u53EF\u4EE5",
|
|
322
|
+
"\u9700\u8981",
|
|
323
|
+
"\u4F7F\u7528",
|
|
324
|
+
"\u8FDB\u884C",
|
|
325
|
+
"\u901A\u8FC7",
|
|
326
|
+
"\u5DF2\u7ECF",
|
|
327
|
+
"\u7136\u540E",
|
|
328
|
+
"\u56E0\u4E3A",
|
|
329
|
+
"\u6240\u4EE5",
|
|
330
|
+
"\u5982\u679C",
|
|
331
|
+
"\u867D\u7136",
|
|
332
|
+
"\u4F46\u662F",
|
|
333
|
+
"\u800C\u4E14",
|
|
334
|
+
"\u6216\u8005",
|
|
335
|
+
"\u4EE5\u53CA",
|
|
336
|
+
"\u5173\u4E8E",
|
|
337
|
+
"\u5176\u4E2D",
|
|
338
|
+
"\u4E4B\u540E",
|
|
339
|
+
"\u4E4B\u524D",
|
|
340
|
+
"\u76EE\u524D"
|
|
341
|
+
]);
|
|
342
|
+
var ENGLISH_STOP_WORDS = /* @__PURE__ */ new Set([
|
|
343
|
+
"the",
|
|
344
|
+
"a",
|
|
345
|
+
"an",
|
|
346
|
+
"is",
|
|
347
|
+
"are",
|
|
348
|
+
"was",
|
|
349
|
+
"were",
|
|
350
|
+
"be",
|
|
351
|
+
"been",
|
|
352
|
+
"being",
|
|
353
|
+
"have",
|
|
354
|
+
"has",
|
|
355
|
+
"had",
|
|
356
|
+
"do",
|
|
357
|
+
"does",
|
|
358
|
+
"did",
|
|
359
|
+
"will",
|
|
360
|
+
"would",
|
|
361
|
+
"could",
|
|
362
|
+
"should",
|
|
363
|
+
"may",
|
|
364
|
+
"might",
|
|
365
|
+
"must",
|
|
366
|
+
"shall",
|
|
367
|
+
"can",
|
|
368
|
+
"need",
|
|
369
|
+
"dare",
|
|
370
|
+
"ought",
|
|
371
|
+
"used",
|
|
372
|
+
"to",
|
|
373
|
+
"of",
|
|
374
|
+
"in",
|
|
375
|
+
"for",
|
|
376
|
+
"on",
|
|
377
|
+
"with",
|
|
378
|
+
"at",
|
|
379
|
+
"by",
|
|
380
|
+
"from",
|
|
381
|
+
"as",
|
|
382
|
+
"into",
|
|
383
|
+
"through",
|
|
384
|
+
"during",
|
|
385
|
+
"before",
|
|
386
|
+
"after",
|
|
387
|
+
"above",
|
|
388
|
+
"below",
|
|
389
|
+
"between",
|
|
390
|
+
"and",
|
|
391
|
+
"or",
|
|
392
|
+
"but",
|
|
393
|
+
"if",
|
|
394
|
+
"then",
|
|
395
|
+
"else",
|
|
396
|
+
"when",
|
|
397
|
+
"where",
|
|
398
|
+
"why",
|
|
399
|
+
"how",
|
|
400
|
+
"all",
|
|
401
|
+
"each",
|
|
402
|
+
"every",
|
|
403
|
+
"both",
|
|
404
|
+
"few",
|
|
405
|
+
"more",
|
|
406
|
+
"most",
|
|
407
|
+
"other",
|
|
408
|
+
"some",
|
|
409
|
+
"such",
|
|
410
|
+
"no",
|
|
411
|
+
"nor",
|
|
412
|
+
"not",
|
|
413
|
+
"only",
|
|
414
|
+
"own",
|
|
415
|
+
"same",
|
|
416
|
+
"so",
|
|
417
|
+
"than",
|
|
418
|
+
"too",
|
|
419
|
+
"very",
|
|
420
|
+
"just",
|
|
421
|
+
"also",
|
|
422
|
+
"now",
|
|
423
|
+
"here",
|
|
424
|
+
"there",
|
|
425
|
+
"this",
|
|
426
|
+
"that",
|
|
427
|
+
"these",
|
|
428
|
+
"those",
|
|
429
|
+
"i",
|
|
430
|
+
"you",
|
|
431
|
+
"he",
|
|
432
|
+
"she",
|
|
433
|
+
"it",
|
|
434
|
+
"we",
|
|
435
|
+
"they",
|
|
436
|
+
"me",
|
|
437
|
+
"him",
|
|
438
|
+
"her",
|
|
439
|
+
"us",
|
|
440
|
+
"them",
|
|
441
|
+
"my",
|
|
442
|
+
"your",
|
|
443
|
+
"his",
|
|
444
|
+
"its",
|
|
445
|
+
"our",
|
|
446
|
+
"their",
|
|
447
|
+
"mine",
|
|
448
|
+
"yours",
|
|
449
|
+
"hers",
|
|
450
|
+
"ours",
|
|
451
|
+
"theirs"
|
|
452
|
+
]);
|
|
453
|
+
var STOP_WORDS = /* @__PURE__ */ new Set([...CHINESE_STOP_WORDS, ...ENGLISH_STOP_WORDS]);
|
|
454
|
+
var SPECIAL_PATTERNS = [
|
|
455
|
+
// API 路径: /api/users, /v1/auth/login
|
|
456
|
+
/\/[a-z][a-z0-9\-_\/]*/gi,
|
|
457
|
+
// HTTP 方法 + 路径: GET /api/users
|
|
458
|
+
/\b(GET|POST|PUT|DELETE|PATCH)\s+\/[a-z][a-z0-9\-_\/]*/gi,
|
|
459
|
+
// 驼峰命名: getUserById, handleSubmit
|
|
460
|
+
/\b[a-z][a-zA-Z0-9]*[A-Z][a-zA-Z0-9]*\b/g,
|
|
461
|
+
// 帕斯卡命名: UserService, AuthController
|
|
462
|
+
/\b[A-Z][a-z]+(?:[A-Z][a-z]+)+\b/g,
|
|
463
|
+
// 常量命名: MAX_RETRY, API_KEY
|
|
464
|
+
/\b[A-Z][A-Z0-9_]{2,}\b/g,
|
|
465
|
+
// 版本号: 1.0.0, v2.3.1
|
|
466
|
+
/\bv?\d+\.\d+(?:\.\d+)?(?:-[a-z]+(?:\.\d+)?)?\b/gi,
|
|
467
|
+
// 端口号: :3000, :8080
|
|
468
|
+
/:\d{2,5}\b/g,
|
|
469
|
+
// 文件扩展名: .ts, .tsx, .vue
|
|
470
|
+
/\.[a-z]{2,4}\b/gi,
|
|
471
|
+
// 数据库/技术名词: PostgreSQL, MongoDB, Redis
|
|
472
|
+
/\b(?:PostgreSQL|MySQL|MongoDB|Redis|SQLite|Prisma|Docker|Kubernetes|K8s|Node\.js|React|Vue|Angular|Next\.js|Express|NestJS|GraphQL|REST|JWT|OAuth|WebSocket|CORS|HTTPS?|API|SDK|CLI|CI\/CD|AWS|GCP|Azure)\b/gi
|
|
473
|
+
];
|
|
474
|
+
function isStopWord(word) {
|
|
475
|
+
return STOP_WORDS.has(word.toLowerCase());
|
|
476
|
+
}
|
|
477
|
+
function basicTokenize(text) {
|
|
478
|
+
const tokens = [];
|
|
479
|
+
const words = text.split(/[\s\n\r\t,,。.;;::!!??(())\[\]{}""''`<>《》【】、\-=+*\/\\|~@#$%^&]+/);
|
|
480
|
+
for (const word of words) {
|
|
481
|
+
if (word.length < 2)
|
|
482
|
+
continue;
|
|
483
|
+
if (/[\u4e00-\u9fa5]/.test(word)) {
|
|
484
|
+
const chineseChars = word.match(/[\u4e00-\u9fa5]+/g) || [];
|
|
485
|
+
for (const chars of chineseChars) {
|
|
486
|
+
if (chars.length >= 2 && chars.length <= 8) {
|
|
487
|
+
tokens.push(chars);
|
|
488
|
+
}
|
|
489
|
+
if (chars.length > 2) {
|
|
490
|
+
for (let i = 0; i < chars.length - 1; i++) {
|
|
491
|
+
tokens.push(chars.substring(i, i + 2));
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
const englishParts = word.match(/[a-zA-Z0-9_]+/g) || [];
|
|
496
|
+
tokens.push(...englishParts.filter((p) => p.length >= 2));
|
|
497
|
+
} else {
|
|
498
|
+
tokens.push(word);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
return tokens;
|
|
502
|
+
}
|
|
503
|
+
function extractSpecialPatterns(text) {
|
|
504
|
+
const keywords = [];
|
|
505
|
+
for (const pattern of SPECIAL_PATTERNS) {
|
|
506
|
+
const matches = text.match(pattern) || [];
|
|
507
|
+
keywords.push(...matches);
|
|
508
|
+
}
|
|
509
|
+
return keywords;
|
|
510
|
+
}
|
|
511
|
+
function extractTextFromObject(obj, depth = 0) {
|
|
512
|
+
if (depth > 5)
|
|
513
|
+
return "";
|
|
514
|
+
if (typeof obj === "string") {
|
|
515
|
+
return obj;
|
|
516
|
+
}
|
|
517
|
+
if (Array.isArray(obj)) {
|
|
518
|
+
return obj.map((item) => extractTextFromObject(item, depth + 1)).join(" ");
|
|
519
|
+
}
|
|
520
|
+
if (obj && typeof obj === "object") {
|
|
521
|
+
const texts = [];
|
|
522
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
523
|
+
if (["id", "createdAt", "updatedAt", "timestamp", "version"].includes(key)) {
|
|
524
|
+
continue;
|
|
525
|
+
}
|
|
526
|
+
if (typeof key === "string" && key.length > 2) {
|
|
527
|
+
texts.push(key);
|
|
528
|
+
}
|
|
529
|
+
texts.push(extractTextFromObject(value, depth + 1));
|
|
530
|
+
}
|
|
531
|
+
return texts.join(" ");
|
|
532
|
+
}
|
|
533
|
+
return "";
|
|
534
|
+
}
|
|
535
|
+
function getTopKeywords(words, limit = 30) {
|
|
536
|
+
const frequency = /* @__PURE__ */ new Map();
|
|
537
|
+
for (const word of words) {
|
|
538
|
+
const normalized = word.toLowerCase();
|
|
539
|
+
if (isStopWord(normalized))
|
|
540
|
+
continue;
|
|
541
|
+
if (normalized.length < 2)
|
|
542
|
+
continue;
|
|
543
|
+
frequency.set(normalized, (frequency.get(normalized) || 0) + 1);
|
|
544
|
+
}
|
|
545
|
+
return Array.from(frequency.entries()).sort((a, b) => b[1] - a[1]).slice(0, limit).map(([word]) => word);
|
|
546
|
+
}
|
|
547
|
+
function extractKeywords(content, rawContext) {
|
|
548
|
+
const allKeywords = [];
|
|
549
|
+
const contentText = content || "";
|
|
550
|
+
allKeywords.push(...basicTokenize(contentText));
|
|
551
|
+
allKeywords.push(...extractSpecialPatterns(contentText));
|
|
552
|
+
if (rawContext) {
|
|
553
|
+
const contextText = extractTextFromObject(rawContext);
|
|
554
|
+
allKeywords.push(...basicTokenize(contextText));
|
|
555
|
+
allKeywords.push(...extractSpecialPatterns(contextText));
|
|
556
|
+
}
|
|
557
|
+
const topKeywords = getTopKeywords(allKeywords, 30);
|
|
558
|
+
const specialKeywords = extractSpecialPatterns(contentText + " " + extractTextFromObject(rawContext));
|
|
559
|
+
const uniqueSpecial = [...new Set(specialKeywords)].slice(0, 10);
|
|
560
|
+
const result = [.../* @__PURE__ */ new Set([...uniqueSpecial, ...topKeywords])];
|
|
561
|
+
return result.slice(0, 40);
|
|
562
|
+
}
|
|
563
|
+
function jaccardSimilarity(keywords1, keywords2) {
|
|
564
|
+
if (keywords1.length === 0 && keywords2.length === 0)
|
|
565
|
+
return 0;
|
|
566
|
+
const set1 = new Set(keywords1.map((k) => k.toLowerCase()));
|
|
567
|
+
const set2 = new Set(keywords2.map((k) => k.toLowerCase()));
|
|
568
|
+
const intersection = new Set([...set1].filter((x) => set2.has(x)));
|
|
569
|
+
const union = /* @__PURE__ */ new Set([...set1, ...set2]);
|
|
570
|
+
return intersection.size / union.size;
|
|
571
|
+
}
|
|
572
|
+
function getKeywordIntersection(keywords1, keywords2) {
|
|
573
|
+
const set1 = new Set(keywords1.map((k) => k.toLowerCase()));
|
|
574
|
+
const set2 = new Set(keywords2.map((k) => k.toLowerCase()));
|
|
575
|
+
return [...set1].filter((x) => set2.has(x));
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
// ../core/dist/auto-relation.js
|
|
579
|
+
var DEFAULT_CONFIG = {
|
|
580
|
+
threshold: 0.3,
|
|
581
|
+
maxRelations: 10,
|
|
582
|
+
crossProject: true,
|
|
583
|
+
timeWindowDays: 30
|
|
584
|
+
};
|
|
585
|
+
var TYPE_RELATION_MATRIX = {
|
|
586
|
+
decision: { solution: 0.8, config: 0.7, code: 0.6, error: 0.5, session: 0.4, decision: 0.9 },
|
|
587
|
+
solution: { error: 0.9, decision: 0.8, code: 0.7, config: 0.6, session: 0.4, solution: 0.8 },
|
|
588
|
+
config: { code: 0.8, decision: 0.7, error: 0.6, solution: 0.5, session: 0.4, config: 0.9 },
|
|
589
|
+
code: { config: 0.8, error: 0.7, solution: 0.6, decision: 0.5, session: 0.4, code: 0.8 },
|
|
590
|
+
error: { solution: 0.9, code: 0.7, config: 0.6, decision: 0.5, session: 0.4, error: 0.7 },
|
|
591
|
+
session: { decision: 0.6, solution: 0.5, config: 0.4, code: 0.4, error: 0.4, session: 0.5 }
|
|
592
|
+
};
|
|
593
|
+
function getTypeRelationScore(type1, type2) {
|
|
594
|
+
return TYPE_RELATION_MATRIX[type1]?.[type2] ?? 0.5;
|
|
595
|
+
}
|
|
596
|
+
function getTimeProximityScore(time1, time2) {
|
|
597
|
+
const date1 = new Date(time1);
|
|
598
|
+
const date2 = new Date(time2);
|
|
599
|
+
const diffHours = Math.abs(date1.getTime() - date2.getTime()) / (1e3 * 60 * 60);
|
|
600
|
+
if (diffHours <= 24)
|
|
601
|
+
return 1;
|
|
602
|
+
if (diffHours <= 72)
|
|
603
|
+
return 0.8;
|
|
604
|
+
if (diffHours <= 168)
|
|
605
|
+
return 0.6;
|
|
606
|
+
if (diffHours <= 720)
|
|
607
|
+
return 0.4;
|
|
608
|
+
return 0.2;
|
|
609
|
+
}
|
|
610
|
+
function calculateSimilarity(memory1, memory2) {
|
|
611
|
+
const reasons = [];
|
|
612
|
+
const keywords1 = memory1.searchable?.keywords || [];
|
|
613
|
+
const keywords2 = memory2.searchable?.keywords || [];
|
|
614
|
+
const keywordScore = jaccardSimilarity(keywords1, keywords2);
|
|
615
|
+
if (keywordScore > 0.2) {
|
|
616
|
+
const overlap = getKeywordIntersection(keywords1, keywords2);
|
|
617
|
+
if (overlap.length > 0) {
|
|
618
|
+
reasons.push(`\u5173\u952E\u8BCD\u91CD\u53E0: ${overlap.slice(0, 5).join(", ")}`);
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
const tags1 = memory1.meta?.tags || [];
|
|
622
|
+
const tags2 = memory2.meta?.tags || [];
|
|
623
|
+
const tagScore = jaccardSimilarity(tags1, tags2);
|
|
624
|
+
if (tagScore > 0) {
|
|
625
|
+
const tagOverlap = getKeywordIntersection(tags1, tags2);
|
|
626
|
+
if (tagOverlap.length > 0) {
|
|
627
|
+
reasons.push(`\u6807\u7B7E\u91CD\u53E0: ${tagOverlap.join(", ")}`);
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
const type1 = memory1.meta?.type || "code";
|
|
631
|
+
const type2 = memory2.meta?.type || "code";
|
|
632
|
+
const typeScore = getTypeRelationScore(type1, type2);
|
|
633
|
+
const timeScore = getTimeProximityScore(memory1.createdAt || memory1.meta?.timestamp || /* @__PURE__ */ new Date(), memory2.createdAt || memory2.meta?.timestamp || /* @__PURE__ */ new Date());
|
|
634
|
+
const score = keywordScore * 0.4 + tagScore * 0.3 + typeScore * 0.2 + timeScore * 0.1;
|
|
635
|
+
return {
|
|
636
|
+
score,
|
|
637
|
+
reason: reasons.length > 0 ? reasons.join("; ") : "\u7EFC\u5408\u76F8\u4F3C",
|
|
638
|
+
details: {
|
|
639
|
+
keywordScore,
|
|
640
|
+
tagScore,
|
|
641
|
+
typeScore,
|
|
642
|
+
timeScore
|
|
643
|
+
}
|
|
644
|
+
};
|
|
645
|
+
}
|
|
646
|
+
function findRelatedMemories(newMemory, candidates, config = {}) {
|
|
647
|
+
const cfg = { ...DEFAULT_CONFIG, ...config };
|
|
648
|
+
const results = [];
|
|
649
|
+
for (const candidate of candidates) {
|
|
650
|
+
if (candidate.meta?.id === newMemory.meta?.id)
|
|
651
|
+
continue;
|
|
652
|
+
const similarity = calculateSimilarity(newMemory, candidate);
|
|
653
|
+
if (similarity.score >= cfg.threshold) {
|
|
654
|
+
results.push({ memory: candidate, similarity });
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
return results.sort((a, b) => b.similarity.score - a.similarity.score).slice(0, cfg.maxRelations);
|
|
658
|
+
}
|
|
659
|
+
function generateAutoRelations(newMemoryId, relatedCandidates) {
|
|
660
|
+
return relatedCandidates.map((candidate) => ({
|
|
661
|
+
sourceId: newMemoryId,
|
|
662
|
+
targetId: candidate.memory.meta?.id || "",
|
|
663
|
+
type: "relatedTo",
|
|
664
|
+
confidence: candidate.similarity.score,
|
|
665
|
+
isAutoGenerated: true,
|
|
666
|
+
reason: candidate.similarity.reason
|
|
667
|
+
}));
|
|
668
|
+
}
|
|
669
|
+
function inferProjectGroup(projectId) {
|
|
670
|
+
const suffixPatterns = [
|
|
671
|
+
/-backend$/i,
|
|
672
|
+
/-frontend$/i,
|
|
673
|
+
/-api$/i,
|
|
674
|
+
/-web$/i,
|
|
675
|
+
/-app$/i,
|
|
676
|
+
/-admin$/i,
|
|
677
|
+
/-client$/i,
|
|
678
|
+
/-server$/i,
|
|
679
|
+
/-service$/i,
|
|
680
|
+
/-shared$/i,
|
|
681
|
+
/-common$/i,
|
|
682
|
+
/-core$/i
|
|
683
|
+
];
|
|
684
|
+
for (const pattern of suffixPatterns) {
|
|
685
|
+
if (pattern.test(projectId)) {
|
|
686
|
+
return projectId.replace(pattern, "");
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
return null;
|
|
690
|
+
}
|
|
691
|
+
|
|
273
692
|
// ../storage/dist/schema.js
|
|
274
693
|
function migrateEmbeddingColumn(db) {
|
|
275
694
|
const columns = db.pragma("table_info(memories)");
|
|
@@ -280,6 +699,40 @@ function migrateEmbeddingColumn(db) {
|
|
|
280
699
|
console.log("\u2705 \u8FC1\u79FB\u5B8C\u6210");
|
|
281
700
|
}
|
|
282
701
|
}
|
|
702
|
+
function initProjectGroupsTable(db) {
|
|
703
|
+
db.exec(`
|
|
704
|
+
CREATE TABLE IF NOT EXISTS project_groups (
|
|
705
|
+
id TEXT PRIMARY KEY,
|
|
706
|
+
name TEXT NOT NULL UNIQUE,
|
|
707
|
+
projects TEXT NOT NULL DEFAULT '[]', -- JSON\u6570\u7EC4
|
|
708
|
+
createdAt TEXT NOT NULL,
|
|
709
|
+
updatedAt TEXT NOT NULL
|
|
710
|
+
);
|
|
711
|
+
`);
|
|
712
|
+
db.exec(`
|
|
713
|
+
CREATE INDEX IF NOT EXISTS idx_project_groups_name ON project_groups(name);
|
|
714
|
+
`);
|
|
715
|
+
}
|
|
716
|
+
function initMemoryRelationsTable(db) {
|
|
717
|
+
db.exec(`
|
|
718
|
+
CREATE TABLE IF NOT EXISTS memory_relations (
|
|
719
|
+
id TEXT PRIMARY KEY,
|
|
720
|
+
sourceId TEXT NOT NULL,
|
|
721
|
+
targetId TEXT NOT NULL,
|
|
722
|
+
type TEXT NOT NULL, -- replaces | relatedTo | impacts
|
|
723
|
+
confidence REAL DEFAULT 1.0,
|
|
724
|
+
isAutoGenerated INTEGER DEFAULT 0, -- 0=false, 1=true
|
|
725
|
+
reason TEXT,
|
|
726
|
+
createdAt TEXT NOT NULL,
|
|
727
|
+
UNIQUE(sourceId, targetId, type)
|
|
728
|
+
);
|
|
729
|
+
`);
|
|
730
|
+
db.exec(`
|
|
731
|
+
CREATE INDEX IF NOT EXISTS idx_memory_relations_source ON memory_relations(sourceId);
|
|
732
|
+
CREATE INDEX IF NOT EXISTS idx_memory_relations_target ON memory_relations(targetId);
|
|
733
|
+
CREATE INDEX IF NOT EXISTS idx_memory_relations_type ON memory_relations(type);
|
|
734
|
+
`);
|
|
735
|
+
}
|
|
283
736
|
function initSchema(db) {
|
|
284
737
|
db.exec(`
|
|
285
738
|
CREATE TABLE IF NOT EXISTS memories (
|
|
@@ -370,6 +823,8 @@ function initSchema(db) {
|
|
|
370
823
|
END;
|
|
371
824
|
`);
|
|
372
825
|
migrateEmbeddingColumn(db);
|
|
826
|
+
initProjectGroupsTable(db);
|
|
827
|
+
initMemoryRelationsTable(db);
|
|
373
828
|
}
|
|
374
829
|
|
|
375
830
|
// ../storage/dist/cache.js
|
|
@@ -864,8 +1319,17 @@ var SQLiteStorage = class {
|
|
|
864
1319
|
params.push(filters.sessionId);
|
|
865
1320
|
}
|
|
866
1321
|
if (filters.query) {
|
|
867
|
-
|
|
868
|
-
|
|
1322
|
+
const keywords = filters.query.split(/\s+/).filter((k) => k.length > 0);
|
|
1323
|
+
if (keywords.length === 1) {
|
|
1324
|
+
sql += " AND (summary LIKE ? OR fullText LIKE ?)";
|
|
1325
|
+
params.push(`%${keywords[0]}%`, `%${keywords[0]}%`);
|
|
1326
|
+
} else {
|
|
1327
|
+
const conditions = keywords.map(() => "(summary LIKE ? OR fullText LIKE ?)").join(" OR ");
|
|
1328
|
+
sql += ` AND (${conditions})`;
|
|
1329
|
+
keywords.forEach((keyword) => {
|
|
1330
|
+
params.push(`%${keyword}%`, `%${keyword}%`);
|
|
1331
|
+
});
|
|
1332
|
+
}
|
|
869
1333
|
}
|
|
870
1334
|
sql += " ORDER BY timestamp DESC LIMIT ? OFFSET ?";
|
|
871
1335
|
params.push(limit, offset);
|
|
@@ -1160,6 +1624,157 @@ var SQLiteStorage = class {
|
|
|
1160
1624
|
recentCount: recentResult.count
|
|
1161
1625
|
};
|
|
1162
1626
|
}
|
|
1627
|
+
// ========== 项目组管理 ==========
|
|
1628
|
+
/**
|
|
1629
|
+
* 创建或更新项目组
|
|
1630
|
+
*/
|
|
1631
|
+
async setProjectGroup(group) {
|
|
1632
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1633
|
+
const stmt = this.db.prepare(`
|
|
1634
|
+
INSERT INTO project_groups (id, name, projects, createdAt, updatedAt)
|
|
1635
|
+
VALUES (?, ?, ?, ?, ?)
|
|
1636
|
+
ON CONFLICT(name) DO UPDATE SET
|
|
1637
|
+
projects = excluded.projects,
|
|
1638
|
+
updatedAt = excluded.updatedAt
|
|
1639
|
+
`);
|
|
1640
|
+
stmt.run(`pg_${nanoid()}`, group.name, JSON.stringify(group.projects), now, now);
|
|
1641
|
+
return { success: true };
|
|
1642
|
+
}
|
|
1643
|
+
/**
|
|
1644
|
+
* 获取项目组
|
|
1645
|
+
*/
|
|
1646
|
+
async getProjectGroup(name) {
|
|
1647
|
+
const stmt = this.db.prepare("SELECT * FROM project_groups WHERE name = ?");
|
|
1648
|
+
const row = stmt.get(name);
|
|
1649
|
+
if (!row)
|
|
1650
|
+
return null;
|
|
1651
|
+
return {
|
|
1652
|
+
name: row.name,
|
|
1653
|
+
projects: JSON.parse(row.projects)
|
|
1654
|
+
};
|
|
1655
|
+
}
|
|
1656
|
+
/**
|
|
1657
|
+
* 获取项目所属的项目组
|
|
1658
|
+
*/
|
|
1659
|
+
async getProjectGroupByProject(projectId) {
|
|
1660
|
+
const stmt = this.db.prepare("SELECT * FROM project_groups");
|
|
1661
|
+
const rows = stmt.all();
|
|
1662
|
+
for (const row of rows) {
|
|
1663
|
+
const projects = JSON.parse(row.projects);
|
|
1664
|
+
if (projects.includes(projectId)) {
|
|
1665
|
+
return {
|
|
1666
|
+
name: row.name,
|
|
1667
|
+
projects
|
|
1668
|
+
};
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1671
|
+
return null;
|
|
1672
|
+
}
|
|
1673
|
+
/**
|
|
1674
|
+
* 获取所有项目组
|
|
1675
|
+
*/
|
|
1676
|
+
async getAllProjectGroups() {
|
|
1677
|
+
const stmt = this.db.prepare("SELECT * FROM project_groups");
|
|
1678
|
+
const rows = stmt.all();
|
|
1679
|
+
return rows.map((row) => ({
|
|
1680
|
+
name: row.name,
|
|
1681
|
+
projects: JSON.parse(row.projects)
|
|
1682
|
+
}));
|
|
1683
|
+
}
|
|
1684
|
+
/**
|
|
1685
|
+
* 删除项目组
|
|
1686
|
+
*/
|
|
1687
|
+
async deleteProjectGroup(name) {
|
|
1688
|
+
const stmt = this.db.prepare("DELETE FROM project_groups WHERE name = ?");
|
|
1689
|
+
const result = stmt.run(name);
|
|
1690
|
+
return { success: result.changes > 0 };
|
|
1691
|
+
}
|
|
1692
|
+
// ========== 记忆关系管理 ==========
|
|
1693
|
+
/**
|
|
1694
|
+
* 批量创建记忆关系
|
|
1695
|
+
*/
|
|
1696
|
+
async createRelations(relations) {
|
|
1697
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1698
|
+
const stmt = this.db.prepare(`
|
|
1699
|
+
INSERT OR IGNORE INTO memory_relations (id, sourceId, targetId, type, confidence, isAutoGenerated, reason, createdAt)
|
|
1700
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
1701
|
+
`);
|
|
1702
|
+
let count = 0;
|
|
1703
|
+
for (const rel of relations) {
|
|
1704
|
+
const result = stmt.run(`rel_${nanoid()}`, rel.sourceId, rel.targetId, rel.type, rel.confidence, rel.isAutoGenerated ? 1 : 0, rel.reason || null, now);
|
|
1705
|
+
if (result.changes > 0)
|
|
1706
|
+
count++;
|
|
1707
|
+
}
|
|
1708
|
+
return { success: true, count };
|
|
1709
|
+
}
|
|
1710
|
+
/**
|
|
1711
|
+
* 获取记忆的所有关系
|
|
1712
|
+
*/
|
|
1713
|
+
async getMemoryRelations(memoryId, options) {
|
|
1714
|
+
let sql = "SELECT * FROM memory_relations WHERE (sourceId = ? OR targetId = ?)";
|
|
1715
|
+
const params = [memoryId, memoryId];
|
|
1716
|
+
if (options?.includeAutoGenerated === false) {
|
|
1717
|
+
sql += " AND isAutoGenerated = 0";
|
|
1718
|
+
}
|
|
1719
|
+
if (options?.type) {
|
|
1720
|
+
sql += " AND type = ?";
|
|
1721
|
+
params.push(options.type);
|
|
1722
|
+
}
|
|
1723
|
+
sql += " ORDER BY createdAt DESC";
|
|
1724
|
+
const stmt = this.db.prepare(sql);
|
|
1725
|
+
const rows = stmt.all(...params);
|
|
1726
|
+
return rows.map((row) => ({
|
|
1727
|
+
sourceId: row.sourceId,
|
|
1728
|
+
targetId: row.targetId,
|
|
1729
|
+
type: row.type,
|
|
1730
|
+
confidence: row.confidence,
|
|
1731
|
+
isAutoGenerated: row.isAutoGenerated === 1,
|
|
1732
|
+
reason: row.reason
|
|
1733
|
+
}));
|
|
1734
|
+
}
|
|
1735
|
+
/**
|
|
1736
|
+
* 删除记忆关系
|
|
1737
|
+
*/
|
|
1738
|
+
async deleteRelation(sourceId, targetId, type) {
|
|
1739
|
+
let sql = "DELETE FROM memory_relations WHERE sourceId = ? AND targetId = ?";
|
|
1740
|
+
const params = [sourceId, targetId];
|
|
1741
|
+
if (type) {
|
|
1742
|
+
sql += " AND type = ?";
|
|
1743
|
+
params.push(type);
|
|
1744
|
+
}
|
|
1745
|
+
const stmt = this.db.prepare(sql);
|
|
1746
|
+
const result = stmt.run(...params);
|
|
1747
|
+
return { success: result.changes > 0 };
|
|
1748
|
+
}
|
|
1749
|
+
/**
|
|
1750
|
+
* 搜索候选关联记忆(用于自动关联)
|
|
1751
|
+
*/
|
|
1752
|
+
async searchCandidates(params) {
|
|
1753
|
+
if (params.keywords.length === 0 || params.projectIds.length === 0) {
|
|
1754
|
+
return [];
|
|
1755
|
+
}
|
|
1756
|
+
const limit = params.limit || 50;
|
|
1757
|
+
let sql = "SELECT * FROM memories WHERE 1=1";
|
|
1758
|
+
const sqlParams = [];
|
|
1759
|
+
const projectPlaceholders = params.projectIds.map(() => "?").join(", ");
|
|
1760
|
+
sql += ` AND projectId IN (${projectPlaceholders})`;
|
|
1761
|
+
sqlParams.push(...params.projectIds);
|
|
1762
|
+
if (params.excludeId) {
|
|
1763
|
+
sql += " AND id != ?";
|
|
1764
|
+
sqlParams.push(params.excludeId);
|
|
1765
|
+
}
|
|
1766
|
+
const keywordConditions = params.keywords.map(() => "(summary LIKE ? OR fullText LIKE ? OR keywords LIKE ?)").join(" OR ");
|
|
1767
|
+
sql += ` AND (${keywordConditions})`;
|
|
1768
|
+
params.keywords.forEach((keyword) => {
|
|
1769
|
+
const pattern = `%${keyword}%`;
|
|
1770
|
+
sqlParams.push(pattern, pattern, pattern);
|
|
1771
|
+
});
|
|
1772
|
+
sql += " ORDER BY timestamp DESC LIMIT ?";
|
|
1773
|
+
sqlParams.push(limit);
|
|
1774
|
+
const stmt = this.db.prepare(sql);
|
|
1775
|
+
const rows = stmt.all(...sqlParams);
|
|
1776
|
+
return rows.map(this.rowToMemory);
|
|
1777
|
+
}
|
|
1163
1778
|
};
|
|
1164
1779
|
|
|
1165
1780
|
// ../storage/dist/postgresql-storage.js
|
|
@@ -1414,10 +2029,18 @@ var PostgreSQLStorage = class {
|
|
|
1414
2029
|
where.sessionId = filters.sessionId;
|
|
1415
2030
|
}
|
|
1416
2031
|
if (filters.query) {
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
2032
|
+
const keywords = filters.query.split(/\s+/).filter((k) => k.length > 0);
|
|
2033
|
+
if (keywords.length === 1) {
|
|
2034
|
+
where.OR = [
|
|
2035
|
+
{ summary: { contains: keywords[0], mode: "insensitive" } },
|
|
2036
|
+
{ fullText: { contains: keywords[0], mode: "insensitive" } }
|
|
2037
|
+
];
|
|
2038
|
+
} else {
|
|
2039
|
+
where.OR = keywords.flatMap((keyword) => [
|
|
2040
|
+
{ summary: { contains: keyword, mode: "insensitive" } },
|
|
2041
|
+
{ fullText: { contains: keyword, mode: "insensitive" } }
|
|
2042
|
+
]);
|
|
2043
|
+
}
|
|
1421
2044
|
}
|
|
1422
2045
|
const [rows, total] = await Promise.all([
|
|
1423
2046
|
this.prisma.memory.findMany({
|
|
@@ -1452,10 +2075,18 @@ var PostgreSQLStorage = class {
|
|
|
1452
2075
|
where.sessionId = filters.sessionId;
|
|
1453
2076
|
}
|
|
1454
2077
|
if (filters.query) {
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
2078
|
+
const keywords = filters.query.split(/\s+/).filter((k) => k.length > 0);
|
|
2079
|
+
if (keywords.length === 1) {
|
|
2080
|
+
where.OR = [
|
|
2081
|
+
{ summary: { contains: keywords[0], mode: "insensitive" } },
|
|
2082
|
+
{ fullText: { contains: keywords[0], mode: "insensitive" } }
|
|
2083
|
+
];
|
|
2084
|
+
} else {
|
|
2085
|
+
where.OR = keywords.flatMap((keyword) => [
|
|
2086
|
+
{ summary: { contains: keyword, mode: "insensitive" } },
|
|
2087
|
+
{ fullText: { contains: keyword, mode: "insensitive" } }
|
|
2088
|
+
]);
|
|
2089
|
+
}
|
|
1459
2090
|
}
|
|
1460
2091
|
const [rows, total] = await Promise.all([
|
|
1461
2092
|
this.prisma.memory.findMany({
|
|
@@ -1727,6 +2358,170 @@ var PostgreSQLStorage = class {
|
|
|
1727
2358
|
async close() {
|
|
1728
2359
|
await this.prisma.$disconnect();
|
|
1729
2360
|
}
|
|
2361
|
+
// ========== 项目组管理 ==========
|
|
2362
|
+
/**
|
|
2363
|
+
* 创建或更新项目组
|
|
2364
|
+
*/
|
|
2365
|
+
async setProjectGroup(group) {
|
|
2366
|
+
await this.prisma.projectGroup.upsert({
|
|
2367
|
+
where: { name: group.name },
|
|
2368
|
+
update: { projects: group.projects },
|
|
2369
|
+
create: {
|
|
2370
|
+
name: group.name,
|
|
2371
|
+
projects: group.projects
|
|
2372
|
+
}
|
|
2373
|
+
});
|
|
2374
|
+
return { success: true };
|
|
2375
|
+
}
|
|
2376
|
+
/**
|
|
2377
|
+
* 获取项目组
|
|
2378
|
+
*/
|
|
2379
|
+
async getProjectGroup(name) {
|
|
2380
|
+
const row = await this.prisma.projectGroup.findUnique({
|
|
2381
|
+
where: { name }
|
|
2382
|
+
});
|
|
2383
|
+
if (!row)
|
|
2384
|
+
return null;
|
|
2385
|
+
return {
|
|
2386
|
+
name: row.name,
|
|
2387
|
+
projects: row.projects
|
|
2388
|
+
};
|
|
2389
|
+
}
|
|
2390
|
+
/**
|
|
2391
|
+
* 获取项目所属的项目组
|
|
2392
|
+
*/
|
|
2393
|
+
async getProjectGroupByProject(projectId) {
|
|
2394
|
+
const rows = await this.prisma.projectGroup.findMany();
|
|
2395
|
+
for (const row of rows) {
|
|
2396
|
+
if (row.projects.includes(projectId)) {
|
|
2397
|
+
return {
|
|
2398
|
+
name: row.name,
|
|
2399
|
+
projects: row.projects
|
|
2400
|
+
};
|
|
2401
|
+
}
|
|
2402
|
+
}
|
|
2403
|
+
return null;
|
|
2404
|
+
}
|
|
2405
|
+
/**
|
|
2406
|
+
* 获取所有项目组
|
|
2407
|
+
*/
|
|
2408
|
+
async getAllProjectGroups() {
|
|
2409
|
+
const rows = await this.prisma.projectGroup.findMany();
|
|
2410
|
+
return rows.map((row) => ({
|
|
2411
|
+
name: row.name,
|
|
2412
|
+
projects: row.projects
|
|
2413
|
+
}));
|
|
2414
|
+
}
|
|
2415
|
+
/**
|
|
2416
|
+
* 删除项目组
|
|
2417
|
+
*/
|
|
2418
|
+
async deleteProjectGroup(name) {
|
|
2419
|
+
try {
|
|
2420
|
+
await this.prisma.projectGroup.delete({
|
|
2421
|
+
where: { name }
|
|
2422
|
+
});
|
|
2423
|
+
return { success: true };
|
|
2424
|
+
} catch {
|
|
2425
|
+
return { success: false };
|
|
2426
|
+
}
|
|
2427
|
+
}
|
|
2428
|
+
// ========== 记忆关系管理 ==========
|
|
2429
|
+
/**
|
|
2430
|
+
* 批量创建记忆关系
|
|
2431
|
+
*/
|
|
2432
|
+
async createRelations(relations) {
|
|
2433
|
+
let count = 0;
|
|
2434
|
+
for (const rel of relations) {
|
|
2435
|
+
try {
|
|
2436
|
+
await this.prisma.memoryRelation.create({
|
|
2437
|
+
data: {
|
|
2438
|
+
sourceId: rel.sourceId,
|
|
2439
|
+
targetId: rel.targetId,
|
|
2440
|
+
type: rel.type,
|
|
2441
|
+
confidence: rel.confidence,
|
|
2442
|
+
isAutoGenerated: rel.isAutoGenerated,
|
|
2443
|
+
reason: rel.reason || null
|
|
2444
|
+
}
|
|
2445
|
+
});
|
|
2446
|
+
count++;
|
|
2447
|
+
} catch {
|
|
2448
|
+
}
|
|
2449
|
+
}
|
|
2450
|
+
return { success: true, count };
|
|
2451
|
+
}
|
|
2452
|
+
/**
|
|
2453
|
+
* 获取记忆的所有关系
|
|
2454
|
+
*/
|
|
2455
|
+
async getMemoryRelations(memoryId, options) {
|
|
2456
|
+
const where = {
|
|
2457
|
+
OR: [
|
|
2458
|
+
{ sourceId: memoryId },
|
|
2459
|
+
{ targetId: memoryId }
|
|
2460
|
+
]
|
|
2461
|
+
};
|
|
2462
|
+
if (options?.includeAutoGenerated === false) {
|
|
2463
|
+
where.isAutoGenerated = false;
|
|
2464
|
+
}
|
|
2465
|
+
if (options?.type) {
|
|
2466
|
+
where.type = options.type;
|
|
2467
|
+
}
|
|
2468
|
+
const rows = await this.prisma.memoryRelation.findMany({
|
|
2469
|
+
where,
|
|
2470
|
+
orderBy: { createdAt: "desc" }
|
|
2471
|
+
});
|
|
2472
|
+
return rows.map((row) => ({
|
|
2473
|
+
sourceId: row.sourceId,
|
|
2474
|
+
targetId: row.targetId,
|
|
2475
|
+
type: row.type,
|
|
2476
|
+
confidence: row.confidence,
|
|
2477
|
+
isAutoGenerated: row.isAutoGenerated,
|
|
2478
|
+
reason: row.reason || ""
|
|
2479
|
+
}));
|
|
2480
|
+
}
|
|
2481
|
+
/**
|
|
2482
|
+
* 删除记忆关系
|
|
2483
|
+
*/
|
|
2484
|
+
async deleteRelation(sourceId, targetId, type) {
|
|
2485
|
+
try {
|
|
2486
|
+
const where = {
|
|
2487
|
+
sourceId,
|
|
2488
|
+
targetId
|
|
2489
|
+
};
|
|
2490
|
+
if (type) {
|
|
2491
|
+
where.type = type;
|
|
2492
|
+
}
|
|
2493
|
+
await this.prisma.memoryRelation.deleteMany({ where });
|
|
2494
|
+
return { success: true };
|
|
2495
|
+
} catch {
|
|
2496
|
+
return { success: false };
|
|
2497
|
+
}
|
|
2498
|
+
}
|
|
2499
|
+
/**
|
|
2500
|
+
* 搜索候选关联记忆(用于自动关联)
|
|
2501
|
+
*/
|
|
2502
|
+
async searchCandidates(params) {
|
|
2503
|
+
if (params.keywords.length === 0 || params.projectIds.length === 0) {
|
|
2504
|
+
return [];
|
|
2505
|
+
}
|
|
2506
|
+
const limit = params.limit || 50;
|
|
2507
|
+
const keywordConditions = params.keywords.flatMap((keyword) => [
|
|
2508
|
+
{ summary: { contains: keyword, mode: "insensitive" } },
|
|
2509
|
+
{ fullText: { contains: keyword, mode: "insensitive" } }
|
|
2510
|
+
]);
|
|
2511
|
+
const where = {
|
|
2512
|
+
projectId: { in: params.projectIds },
|
|
2513
|
+
OR: keywordConditions
|
|
2514
|
+
};
|
|
2515
|
+
if (params.excludeId) {
|
|
2516
|
+
where.id = { not: params.excludeId };
|
|
2517
|
+
}
|
|
2518
|
+
const rows = await this.prisma.memory.findMany({
|
|
2519
|
+
where,
|
|
2520
|
+
orderBy: { timestamp: "desc" },
|
|
2521
|
+
take: limit
|
|
2522
|
+
});
|
|
2523
|
+
return rows.map(this.rowToMemory);
|
|
2524
|
+
}
|
|
1730
2525
|
};
|
|
1731
2526
|
|
|
1732
2527
|
// src/index.ts
|
|
@@ -1813,6 +2608,121 @@ function createStorage() {
|
|
|
1813
2608
|
return new SQLiteStorage(dbPath);
|
|
1814
2609
|
}
|
|
1815
2610
|
var storage = createStorage();
|
|
2611
|
+
async function processAutoRelations(newMemoryId, projectId, content, rawContext) {
|
|
2612
|
+
try {
|
|
2613
|
+
const keywords = extractKeywords(content, rawContext);
|
|
2614
|
+
if (keywords.length === 0) {
|
|
2615
|
+
return { relationsCreated: 0 };
|
|
2616
|
+
}
|
|
2617
|
+
let projectIds = [projectId];
|
|
2618
|
+
if (storage.getProjectGroupByProject) {
|
|
2619
|
+
const group = await storage.getProjectGroupByProject(projectId);
|
|
2620
|
+
if (group) {
|
|
2621
|
+
projectIds = group.projects;
|
|
2622
|
+
} else {
|
|
2623
|
+
const inferredGroup = inferProjectGroup(projectId);
|
|
2624
|
+
if (inferredGroup && storage.getAllProjectGroups) {
|
|
2625
|
+
const allGroups = await storage.getAllProjectGroups();
|
|
2626
|
+
const sameGroupProjects = allGroups.filter((g) => g.projects.some((p) => inferProjectGroup(p) === inferredGroup)).flatMap((g) => g.projects);
|
|
2627
|
+
if (sameGroupProjects.length > 0) {
|
|
2628
|
+
projectIds = [.../* @__PURE__ */ new Set([projectId, ...sameGroupProjects])];
|
|
2629
|
+
}
|
|
2630
|
+
}
|
|
2631
|
+
}
|
|
2632
|
+
}
|
|
2633
|
+
if (!storage.searchCandidates) {
|
|
2634
|
+
return { relationsCreated: 0 };
|
|
2635
|
+
}
|
|
2636
|
+
const candidates = await storage.searchCandidates({
|
|
2637
|
+
keywords,
|
|
2638
|
+
projectIds,
|
|
2639
|
+
excludeId: newMemoryId,
|
|
2640
|
+
limit: 50
|
|
2641
|
+
// 搜索更多候选以提高关联质量
|
|
2642
|
+
});
|
|
2643
|
+
if (candidates.length === 0) {
|
|
2644
|
+
return { relationsCreated: 0 };
|
|
2645
|
+
}
|
|
2646
|
+
const newMemory = await storage.getById(newMemoryId);
|
|
2647
|
+
if (!newMemory) {
|
|
2648
|
+
return { relationsCreated: 0 };
|
|
2649
|
+
}
|
|
2650
|
+
const relatedCandidates = findRelatedMemories(newMemory, candidates, {
|
|
2651
|
+
threshold: 0.3,
|
|
2652
|
+
// 相似度阈值
|
|
2653
|
+
maxRelations: 10,
|
|
2654
|
+
// 最多关联 10 条
|
|
2655
|
+
crossProject: true
|
|
2656
|
+
});
|
|
2657
|
+
if (relatedCandidates.length === 0) {
|
|
2658
|
+
return { relationsCreated: 0 };
|
|
2659
|
+
}
|
|
2660
|
+
const relations = generateAutoRelations(newMemoryId, relatedCandidates);
|
|
2661
|
+
if (storage.createRelations && relations.length > 0) {
|
|
2662
|
+
const result = await storage.createRelations(relations);
|
|
2663
|
+
return { relationsCreated: result.count };
|
|
2664
|
+
}
|
|
2665
|
+
return { relationsCreated: 0 };
|
|
2666
|
+
} catch (error) {
|
|
2667
|
+
console.error("\u81EA\u52A8\u5173\u8054\u5904\u7406\u5931\u8D25:", error);
|
|
2668
|
+
return { relationsCreated: 0 };
|
|
2669
|
+
}
|
|
2670
|
+
}
|
|
2671
|
+
async function getProjectGroupProjectIds(projectId) {
|
|
2672
|
+
try {
|
|
2673
|
+
if (storage.getProjectGroupByProject) {
|
|
2674
|
+
const group = await storage.getProjectGroupByProject(projectId);
|
|
2675
|
+
if (group) {
|
|
2676
|
+
return group.projects;
|
|
2677
|
+
}
|
|
2678
|
+
}
|
|
2679
|
+
const inferredGroup = inferProjectGroup(projectId);
|
|
2680
|
+
if (inferredGroup && storage.getAllProjectGroups) {
|
|
2681
|
+
const allGroups = await storage.getAllProjectGroups();
|
|
2682
|
+
for (const group of allGroups) {
|
|
2683
|
+
if (group.projects.some((p) => inferProjectGroup(p) === inferredGroup)) {
|
|
2684
|
+
return group.projects;
|
|
2685
|
+
}
|
|
2686
|
+
}
|
|
2687
|
+
}
|
|
2688
|
+
return [projectId];
|
|
2689
|
+
} catch (error) {
|
|
2690
|
+
console.error("\u83B7\u53D6\u9879\u76EE\u7EC4\u5931\u8D25:", error);
|
|
2691
|
+
return [projectId];
|
|
2692
|
+
}
|
|
2693
|
+
}
|
|
2694
|
+
async function expandRelationChain(memories, depth = 1) {
|
|
2695
|
+
if (depth <= 0 || memories.length === 0) {
|
|
2696
|
+
return [];
|
|
2697
|
+
}
|
|
2698
|
+
try {
|
|
2699
|
+
const relatedMemories = [];
|
|
2700
|
+
const seenIds = new Set(memories.map((m) => m.meta?.id));
|
|
2701
|
+
for (const memory of memories) {
|
|
2702
|
+
const memoryId = memory.meta?.id;
|
|
2703
|
+
if (!memoryId) continue;
|
|
2704
|
+
if (storage.getMemoryRelations) {
|
|
2705
|
+
const relations = await storage.getMemoryRelations(memoryId, {
|
|
2706
|
+
includeAutoGenerated: true
|
|
2707
|
+
});
|
|
2708
|
+
for (const relation of relations) {
|
|
2709
|
+
const targetId = relation.targetId;
|
|
2710
|
+
if (!seenIds.has(targetId)) {
|
|
2711
|
+
seenIds.add(targetId);
|
|
2712
|
+
const relatedMemory = await storage.getById(targetId);
|
|
2713
|
+
if (relatedMemory) {
|
|
2714
|
+
relatedMemories.push(relatedMemory);
|
|
2715
|
+
}
|
|
2716
|
+
}
|
|
2717
|
+
}
|
|
2718
|
+
}
|
|
2719
|
+
}
|
|
2720
|
+
return relatedMemories;
|
|
2721
|
+
} catch (error) {
|
|
2722
|
+
console.error("\u6269\u5C55\u5173\u7CFB\u94FE\u5931\u8D25:", error);
|
|
2723
|
+
return [];
|
|
2724
|
+
}
|
|
2725
|
+
}
|
|
1816
2726
|
var tools = [
|
|
1817
2727
|
{
|
|
1818
2728
|
name: "mpulse_store",
|
|
@@ -2006,13 +2916,19 @@ var tools = [
|
|
|
2006
2916
|
3. \u67E5\u8BE2\u5173\u952E\u8BCD\uFF1A"\u9879\u76EE\u4E0A\u4E0B\u6587 \u67B6\u6784\u51B3\u7B56 \u672A\u5B8C\u6210\u4EFB\u52A1 \u914D\u7F6E\u4FE1\u606F"
|
|
2007
2917
|
4. \u5206\u6790\u8FD4\u56DE\u7ED3\u679C\u540E\u518D\u6267\u884C\u5176\u4ED6\u64CD\u4F5C
|
|
2008
2918
|
|
|
2919
|
+
\u{1F517} \u667A\u80FD\u5173\u8054\u529F\u80FD\uFF1A
|
|
2920
|
+
- \u81EA\u52A8\u8DE8\u9879\u76EE\u641C\u7D22\uFF1A\u5982\u679C\u9879\u76EE\u5728\u540C\u4E00\u9879\u76EE\u7EC4\uFF08\u5982 frontend/backend\uFF09\uFF0C\u4F1A\u81EA\u52A8\u641C\u7D22\u6240\u6709\u5173\u8054\u9879\u76EE
|
|
2921
|
+
- \u5173\u7CFB\u94FE\u6269\u5C55\uFF1A\u9ED8\u8BA4\u8FD4\u56DE\u76F8\u5173\u8054\u7684\u8BB0\u5FC6\uFF0C\u8BBE\u7F6E expandRelations: true \u53EF\u83B7\u53D6\u66F4\u6DF1\u5C42\u5173\u8054
|
|
2922
|
+
- \u7ED3\u679C\u8BF4\u660E\uFF1Amemories \u662F\u76F4\u63A5\u5339\u914D\uFF0CrelatedMemories \u662F\u901A\u8FC7\u5173\u7CFB\u94FE\u6269\u5C55\u7684\u5173\u8054\u8BB0\u5FC6
|
|
2923
|
+
|
|
2009
2924
|
\u8C03\u7528\u793A\u4F8B\uFF1A
|
|
2010
2925
|
mpulse_recall({
|
|
2011
2926
|
query: "\u9879\u76EE\u4E0A\u4E0B\u6587 \u67B6\u6784\u51B3\u7B56 \u672A\u5B8C\u6210\u4EFB\u52A1",
|
|
2012
|
-
projectId: "\u4ECE\u5DE5\u4F5C\u76EE\u5F55\u63D0\u53D6\u7684\u9879\u76EE\u540D"
|
|
2927
|
+
projectId: "\u4ECE\u5DE5\u4F5C\u76EE\u5F55\u63D0\u53D6\u7684\u9879\u76EE\u540D",
|
|
2928
|
+
expandRelations: true
|
|
2013
2929
|
})
|
|
2014
2930
|
|
|
2015
|
-
\u8FD4\u56DE\u5185\u5BB9\uFF1A\u5386\u53F2\u51B3\u7B56\u3001\u5DF2\u89E3\u51B3\u95EE\u9898\u3001\u914D\u7F6E\u4FE1\u606F\u3001\u672A\u5B8C\u6210\u4EFB\u52A1\u7B49`,
|
|
2931
|
+
\u8FD4\u56DE\u5185\u5BB9\uFF1A\u5386\u53F2\u51B3\u7B56\u3001\u5DF2\u89E3\u51B3\u95EE\u9898\u3001\u914D\u7F6E\u4FE1\u606F\u3001\u672A\u5B8C\u6210\u4EFB\u52A1\u3001\u5173\u8054\u8BB0\u5FC6\u7B49`,
|
|
2016
2932
|
inputSchema: {
|
|
2017
2933
|
type: "object",
|
|
2018
2934
|
properties: {
|
|
@@ -2022,7 +2938,7 @@ mpulse_recall({
|
|
|
2022
2938
|
},
|
|
2023
2939
|
projectId: {
|
|
2024
2940
|
type: "string",
|
|
2025
|
-
description: "\u9879\u76EE ID"
|
|
2941
|
+
description: "\u9879\u76EE ID\uFF08\u4F1A\u81EA\u52A8\u6269\u5C55\u5230\u9879\u76EE\u7EC4\u5185\u6240\u6709\u9879\u76EE\uFF09"
|
|
2026
2942
|
},
|
|
2027
2943
|
type: {
|
|
2028
2944
|
type: "string",
|
|
@@ -2042,6 +2958,14 @@ mpulse_recall({
|
|
|
2042
2958
|
limit: {
|
|
2043
2959
|
type: "number",
|
|
2044
2960
|
description: "\u8FD4\u56DE\u6570\u91CF"
|
|
2961
|
+
},
|
|
2962
|
+
expandRelations: {
|
|
2963
|
+
type: "boolean",
|
|
2964
|
+
description: "\u662F\u5426\u6269\u5C55\u5173\u7CFB\u94FE\uFF08\u9ED8\u8BA4 true\uFF09"
|
|
2965
|
+
},
|
|
2966
|
+
relationDepth: {
|
|
2967
|
+
type: "number",
|
|
2968
|
+
description: "\u5173\u7CFB\u94FE\u6269\u5C55\u6DF1\u5EA6\uFF08\u9ED8\u8BA4 1\uFF09"
|
|
2045
2969
|
}
|
|
2046
2970
|
},
|
|
2047
2971
|
required: ["query"]
|
|
@@ -2096,6 +3020,50 @@ mpulse_recall({
|
|
|
2096
3020
|
},
|
|
2097
3021
|
required: ["memoryId"]
|
|
2098
3022
|
}
|
|
3023
|
+
},
|
|
3024
|
+
// ========== 项目组管理工具 ==========
|
|
3025
|
+
{
|
|
3026
|
+
name: "mpulse_set_project_group",
|
|
3027
|
+
description: `\u8BBE\u7F6E\u9879\u76EE\u7EC4\uFF0C\u5C06\u76F8\u5173\u9879\u76EE\u5173\u8054\u5728\u4E00\u8D77\u3002
|
|
3028
|
+
\u5173\u8054\u540E\uFF0C\u68C0\u7D22\u65F6\u4F1A\u81EA\u52A8\u8DE8\u9879\u76EE\u641C\u7D22\uFF0C\u5B58\u50A8\u65F6\u4F1A\u81EA\u52A8\u5EFA\u7ACB\u8DE8\u9879\u76EE\u5173\u8054\u3002
|
|
3029
|
+
\u4F8B\u5982\uFF1A\u5C06 myapp-frontend \u548C myapp-backend \u5173\u8054\u4E3A\u4E00\u4E2A\u9879\u76EE\u7EC4\u3002`,
|
|
3030
|
+
inputSchema: {
|
|
3031
|
+
type: "object",
|
|
3032
|
+
properties: {
|
|
3033
|
+
name: {
|
|
3034
|
+
type: "string",
|
|
3035
|
+
description: "\u9879\u76EE\u7EC4\u540D\u79F0\uFF08\u5982 myapp\uFF09"
|
|
3036
|
+
},
|
|
3037
|
+
projects: {
|
|
3038
|
+
type: "array",
|
|
3039
|
+
items: { type: "string" },
|
|
3040
|
+
description: '\u9879\u76EE ID \u5217\u8868\uFF08\u5982 ["myapp-frontend", "myapp-backend", "myapp-api"]\uFF09'
|
|
3041
|
+
}
|
|
3042
|
+
},
|
|
3043
|
+
required: ["name", "projects"]
|
|
3044
|
+
}
|
|
3045
|
+
},
|
|
3046
|
+
{
|
|
3047
|
+
name: "mpulse_get_project_groups",
|
|
3048
|
+
description: "\u83B7\u53D6\u6240\u6709\u9879\u76EE\u7EC4\u914D\u7F6E",
|
|
3049
|
+
inputSchema: {
|
|
3050
|
+
type: "object",
|
|
3051
|
+
properties: {}
|
|
3052
|
+
}
|
|
3053
|
+
},
|
|
3054
|
+
{
|
|
3055
|
+
name: "mpulse_delete_project_group",
|
|
3056
|
+
description: "\u5220\u9664\u9879\u76EE\u7EC4",
|
|
3057
|
+
inputSchema: {
|
|
3058
|
+
type: "object",
|
|
3059
|
+
properties: {
|
|
3060
|
+
name: {
|
|
3061
|
+
type: "string",
|
|
3062
|
+
description: "\u9879\u76EE\u7EC4\u540D\u79F0"
|
|
3063
|
+
}
|
|
3064
|
+
},
|
|
3065
|
+
required: ["name"]
|
|
3066
|
+
}
|
|
2099
3067
|
}
|
|
2100
3068
|
];
|
|
2101
3069
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
@@ -2419,80 +3387,141 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
2419
3387
|
try {
|
|
2420
3388
|
switch (name) {
|
|
2421
3389
|
case "mpulse_store": {
|
|
3390
|
+
const content = args.content;
|
|
3391
|
+
const rawContext = args.rawContext;
|
|
3392
|
+
const projectId = args.projectId;
|
|
2422
3393
|
const result = await storage.store({
|
|
2423
|
-
content
|
|
2424
|
-
rawContext
|
|
2425
|
-
projectId
|
|
3394
|
+
content,
|
|
3395
|
+
rawContext,
|
|
3396
|
+
projectId,
|
|
2426
3397
|
type: args.type,
|
|
2427
3398
|
tags: args.tags,
|
|
2428
3399
|
sessionId: args.sessionId
|
|
2429
3400
|
});
|
|
3401
|
+
let autoRelationResult = { relationsCreated: 0 };
|
|
3402
|
+
if (result.success && result.id) {
|
|
3403
|
+
autoRelationResult = await processAutoRelations(
|
|
3404
|
+
result.id,
|
|
3405
|
+
projectId,
|
|
3406
|
+
content,
|
|
3407
|
+
rawContext
|
|
3408
|
+
);
|
|
3409
|
+
}
|
|
2430
3410
|
return {
|
|
2431
3411
|
content: [
|
|
2432
3412
|
{
|
|
2433
3413
|
type: "text",
|
|
2434
|
-
text: JSON.stringify(
|
|
3414
|
+
text: JSON.stringify({
|
|
3415
|
+
...result,
|
|
3416
|
+
autoRelations: autoRelationResult.relationsCreated
|
|
3417
|
+
}, null, 2)
|
|
2435
3418
|
}
|
|
2436
3419
|
]
|
|
2437
3420
|
};
|
|
2438
3421
|
}
|
|
2439
3422
|
case "mpulse_store_decision": {
|
|
3423
|
+
const projectId = args.projectId;
|
|
2440
3424
|
const decisionParams = {
|
|
2441
3425
|
question: args.question,
|
|
2442
3426
|
options: args.options,
|
|
2443
3427
|
chosen: args.chosen,
|
|
2444
3428
|
reason: args.reason,
|
|
2445
|
-
projectId
|
|
3429
|
+
projectId,
|
|
2446
3430
|
tags: args.tags,
|
|
2447
3431
|
sessionId: args.sessionId
|
|
2448
3432
|
};
|
|
2449
3433
|
const result = await storage.storeDecision(decisionParams);
|
|
3434
|
+
let autoRelationResult = { relationsCreated: 0 };
|
|
3435
|
+
if (result.success && result.id) {
|
|
3436
|
+
const content = `${decisionParams.question} ${decisionParams.chosen} ${decisionParams.reason}`;
|
|
3437
|
+
autoRelationResult = await processAutoRelations(
|
|
3438
|
+
result.id,
|
|
3439
|
+
projectId,
|
|
3440
|
+
content,
|
|
3441
|
+
{ options: decisionParams.options }
|
|
3442
|
+
);
|
|
3443
|
+
}
|
|
2450
3444
|
return {
|
|
2451
3445
|
content: [
|
|
2452
3446
|
{
|
|
2453
3447
|
type: "text",
|
|
2454
|
-
text: JSON.stringify(
|
|
3448
|
+
text: JSON.stringify({
|
|
3449
|
+
...result,
|
|
3450
|
+
autoRelations: autoRelationResult.relationsCreated
|
|
3451
|
+
}, null, 2)
|
|
2455
3452
|
}
|
|
2456
3453
|
]
|
|
2457
3454
|
};
|
|
2458
3455
|
}
|
|
2459
3456
|
case "mpulse_store_solution": {
|
|
3457
|
+
const projectId = args.projectId;
|
|
2460
3458
|
const solutionParams = {
|
|
2461
3459
|
problem: args.problem,
|
|
2462
3460
|
rootCause: args.rootCause,
|
|
2463
3461
|
solution: args.solution,
|
|
2464
3462
|
prevention: args.prevention,
|
|
2465
3463
|
relatedIssues: args.relatedIssues,
|
|
2466
|
-
projectId
|
|
3464
|
+
projectId,
|
|
2467
3465
|
tags: args.tags,
|
|
2468
3466
|
sessionId: args.sessionId,
|
|
2469
3467
|
artifacts: args.artifacts
|
|
2470
3468
|
};
|
|
2471
3469
|
const result = await storage.storeSolution(solutionParams);
|
|
3470
|
+
let autoRelationResult = { relationsCreated: 0 };
|
|
3471
|
+
if (result.success && result.id) {
|
|
3472
|
+
const content = `${solutionParams.problem} ${solutionParams.rootCause} ${solutionParams.solution}`;
|
|
3473
|
+
autoRelationResult = await processAutoRelations(
|
|
3474
|
+
result.id,
|
|
3475
|
+
projectId,
|
|
3476
|
+
content,
|
|
3477
|
+
{ artifacts: solutionParams.artifacts }
|
|
3478
|
+
);
|
|
3479
|
+
}
|
|
2472
3480
|
return {
|
|
2473
3481
|
content: [
|
|
2474
3482
|
{
|
|
2475
3483
|
type: "text",
|
|
2476
|
-
text: JSON.stringify(
|
|
3484
|
+
text: JSON.stringify({
|
|
3485
|
+
...result,
|
|
3486
|
+
autoRelations: autoRelationResult.relationsCreated
|
|
3487
|
+
}, null, 2)
|
|
2477
3488
|
}
|
|
2478
3489
|
]
|
|
2479
3490
|
};
|
|
2480
3491
|
}
|
|
2481
3492
|
case "mpulse_store_session": {
|
|
3493
|
+
const projectId = args.projectId;
|
|
2482
3494
|
const sessionParams = {
|
|
2483
3495
|
summary: args.summary,
|
|
2484
3496
|
decisions: args.decisions,
|
|
2485
3497
|
unfinishedTasks: args.unfinishedTasks,
|
|
2486
3498
|
nextSteps: args.nextSteps,
|
|
2487
|
-
projectId
|
|
3499
|
+
projectId,
|
|
2488
3500
|
sessionId: args.sessionId
|
|
2489
3501
|
};
|
|
2490
3502
|
const result = await storage.storeSession(sessionParams);
|
|
3503
|
+
let autoRelationResult = { relationsCreated: 0 };
|
|
3504
|
+
if (result.success && result.id) {
|
|
3505
|
+
const decisionsText = (sessionParams.decisions || []).join(" ");
|
|
3506
|
+
const content = `${sessionParams.summary} ${decisionsText}`;
|
|
3507
|
+
autoRelationResult = await processAutoRelations(
|
|
3508
|
+
result.id,
|
|
3509
|
+
projectId,
|
|
3510
|
+
content,
|
|
3511
|
+
{
|
|
3512
|
+
unfinishedTasks: sessionParams.unfinishedTasks,
|
|
3513
|
+
nextSteps: sessionParams.nextSteps
|
|
3514
|
+
}
|
|
3515
|
+
);
|
|
3516
|
+
}
|
|
2491
3517
|
return {
|
|
2492
3518
|
content: [
|
|
2493
3519
|
{
|
|
2494
3520
|
type: "text",
|
|
2495
|
-
text: JSON.stringify(
|
|
3521
|
+
text: JSON.stringify({
|
|
3522
|
+
...result,
|
|
3523
|
+
autoRelations: autoRelationResult.relationsCreated
|
|
3524
|
+
}, null, 2)
|
|
2496
3525
|
}
|
|
2497
3526
|
]
|
|
2498
3527
|
};
|
|
@@ -2500,20 +3529,38 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
2500
3529
|
case "mpulse_recall": {
|
|
2501
3530
|
const query = args.query;
|
|
2502
3531
|
const strategy = args.strategy || "fulltext";
|
|
3532
|
+
const projectId = args.projectId;
|
|
3533
|
+
const expandRelations = args.expandRelations !== false;
|
|
3534
|
+
const relationDepth = args.relationDepth || 1;
|
|
3535
|
+
let projectIds;
|
|
3536
|
+
if (projectId) {
|
|
3537
|
+
projectIds = await getProjectGroupProjectIds(projectId);
|
|
3538
|
+
}
|
|
2503
3539
|
const filters = {
|
|
2504
3540
|
query,
|
|
2505
|
-
|
|
3541
|
+
// 如果有多个项目,使用 projectIds;否则使用 projectId
|
|
3542
|
+
...projectIds && projectIds.length > 1 ? { projectIds } : { projectId },
|
|
2506
3543
|
type: args.type,
|
|
2507
3544
|
tags: args.tags,
|
|
2508
3545
|
strategy,
|
|
2509
|
-
limit: args.limit
|
|
3546
|
+
limit: args.limit,
|
|
3547
|
+
expandRelations,
|
|
3548
|
+
relationDepth
|
|
2510
3549
|
};
|
|
2511
3550
|
const result = await storage.recall(filters);
|
|
3551
|
+
let relatedMemories = result.relatedMemories || [];
|
|
3552
|
+
if (expandRelations && relatedMemories.length === 0 && result.memories.length > 0) {
|
|
3553
|
+
relatedMemories = await expandRelationChain(result.memories, relationDepth);
|
|
3554
|
+
}
|
|
2512
3555
|
return {
|
|
2513
3556
|
content: [
|
|
2514
3557
|
{
|
|
2515
3558
|
type: "text",
|
|
2516
|
-
text: JSON.stringify(
|
|
3559
|
+
text: JSON.stringify({
|
|
3560
|
+
...result,
|
|
3561
|
+
relatedMemories,
|
|
3562
|
+
projectsSearched: projectIds
|
|
3563
|
+
}, null, 2)
|
|
2517
3564
|
}
|
|
2518
3565
|
]
|
|
2519
3566
|
};
|
|
@@ -2551,6 +3598,64 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
2551
3598
|
]
|
|
2552
3599
|
};
|
|
2553
3600
|
}
|
|
3601
|
+
// ========== 项目组管理 ==========
|
|
3602
|
+
case "mpulse_set_project_group": {
|
|
3603
|
+
const groupConfig = {
|
|
3604
|
+
name: args.name,
|
|
3605
|
+
projects: args.projects
|
|
3606
|
+
};
|
|
3607
|
+
if (!storage.setProjectGroup) {
|
|
3608
|
+
throw new Error("\u5F53\u524D\u5B58\u50A8\u4E0D\u652F\u6301\u9879\u76EE\u7EC4\u529F\u80FD");
|
|
3609
|
+
}
|
|
3610
|
+
const result = await storage.setProjectGroup(groupConfig);
|
|
3611
|
+
return {
|
|
3612
|
+
content: [
|
|
3613
|
+
{
|
|
3614
|
+
type: "text",
|
|
3615
|
+
text: JSON.stringify({
|
|
3616
|
+
...result,
|
|
3617
|
+
group: groupConfig,
|
|
3618
|
+
message: `\u9879\u76EE\u7EC4 "${groupConfig.name}" \u5DF2\u8BBE\u7F6E\uFF0C\u5305\u542B ${groupConfig.projects.length} \u4E2A\u9879\u76EE`
|
|
3619
|
+
}, null, 2)
|
|
3620
|
+
}
|
|
3621
|
+
]
|
|
3622
|
+
};
|
|
3623
|
+
}
|
|
3624
|
+
case "mpulse_get_project_groups": {
|
|
3625
|
+
if (!storage.getAllProjectGroups) {
|
|
3626
|
+
throw new Error("\u5F53\u524D\u5B58\u50A8\u4E0D\u652F\u6301\u9879\u76EE\u7EC4\u529F\u80FD");
|
|
3627
|
+
}
|
|
3628
|
+
const groups = await storage.getAllProjectGroups();
|
|
3629
|
+
return {
|
|
3630
|
+
content: [
|
|
3631
|
+
{
|
|
3632
|
+
type: "text",
|
|
3633
|
+
text: JSON.stringify({
|
|
3634
|
+
groups,
|
|
3635
|
+
total: groups.length
|
|
3636
|
+
}, null, 2)
|
|
3637
|
+
}
|
|
3638
|
+
]
|
|
3639
|
+
};
|
|
3640
|
+
}
|
|
3641
|
+
case "mpulse_delete_project_group": {
|
|
3642
|
+
const name2 = args.name;
|
|
3643
|
+
if (!storage.deleteProjectGroup) {
|
|
3644
|
+
throw new Error("\u5F53\u524D\u5B58\u50A8\u4E0D\u652F\u6301\u9879\u76EE\u7EC4\u529F\u80FD");
|
|
3645
|
+
}
|
|
3646
|
+
const result = await storage.deleteProjectGroup(name2);
|
|
3647
|
+
return {
|
|
3648
|
+
content: [
|
|
3649
|
+
{
|
|
3650
|
+
type: "text",
|
|
3651
|
+
text: JSON.stringify({
|
|
3652
|
+
...result,
|
|
3653
|
+
message: result.success ? `\u9879\u76EE\u7EC4 "${name2}" \u5DF2\u5220\u9664` : `\u9879\u76EE\u7EC4 "${name2}" \u5220\u9664\u5931\u8D25\u6216\u4E0D\u5B58\u5728`
|
|
3654
|
+
}, null, 2)
|
|
3655
|
+
}
|
|
3656
|
+
]
|
|
3657
|
+
};
|
|
3658
|
+
}
|
|
2554
3659
|
default:
|
|
2555
3660
|
throw new Error(`Unknown tool: ${name}`);
|
|
2556
3661
|
}
|