@jussmor/commit-memory-mcp 0.4.3 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/db/client.d.ts +31 -0
- package/dist/db/client.js +206 -20
- package/dist/mcp/server.js +163 -1
- package/package.json +1 -1
package/dist/db/client.d.ts
CHANGED
|
@@ -37,3 +37,34 @@ export declare function archiveFeatureContext(db: RagDatabase, options: {
|
|
|
37
37
|
domain: string;
|
|
38
38
|
feature: string;
|
|
39
39
|
}): number;
|
|
40
|
+
export interface FeatureResumeOptions {
|
|
41
|
+
feature: string;
|
|
42
|
+
domain?: string;
|
|
43
|
+
limit?: number;
|
|
44
|
+
}
|
|
45
|
+
export declare function getFeatureResume(db: RagDatabase, options: FeatureResumeOptions): string;
|
|
46
|
+
export declare function listLearnedFeatures(db: RagDatabase, options?: {
|
|
47
|
+
domain?: string;
|
|
48
|
+
status?: string;
|
|
49
|
+
}): Array<{
|
|
50
|
+
feature: string;
|
|
51
|
+
domain: string;
|
|
52
|
+
branch: string;
|
|
53
|
+
confidence: number;
|
|
54
|
+
status: string;
|
|
55
|
+
createdAt: string;
|
|
56
|
+
updatedAt: string;
|
|
57
|
+
title: string;
|
|
58
|
+
contentLength: number;
|
|
59
|
+
}>;
|
|
60
|
+
export declare function listAvailableBranches(db: RagDatabase, options?: {
|
|
61
|
+
domain?: string;
|
|
62
|
+
feature?: string;
|
|
63
|
+
}): Array<{
|
|
64
|
+
branch: string;
|
|
65
|
+
feature: string;
|
|
66
|
+
domain: string;
|
|
67
|
+
factCount: number;
|
|
68
|
+
lastUpdated: string;
|
|
69
|
+
topConfidence: number;
|
|
70
|
+
}>;
|
package/dist/db/client.js
CHANGED
|
@@ -477,9 +477,35 @@ export function buildContextPack(db, options) {
|
|
|
477
477
|
};
|
|
478
478
|
// PRIORITY 0) Learned feature knowledge is always included first when available.
|
|
479
479
|
// This ensures feature knowledge isn't lost behind PR metadata.
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
480
|
+
// Always include learned features regardless of parameter filters.
|
|
481
|
+
let learnedFacts = [];
|
|
482
|
+
if (options.feature) {
|
|
483
|
+
// Search for learned knowledge about the specific feature
|
|
484
|
+
learnedFacts = db.prepare(`
|
|
485
|
+
SELECT
|
|
486
|
+
id,
|
|
487
|
+
source_type,
|
|
488
|
+
source_ref,
|
|
489
|
+
title,
|
|
490
|
+
content,
|
|
491
|
+
scope_domain,
|
|
492
|
+
scope_feature,
|
|
493
|
+
scope_branch,
|
|
494
|
+
scope_task_type,
|
|
495
|
+
priority,
|
|
496
|
+
confidence,
|
|
497
|
+
status,
|
|
498
|
+
updated_at,
|
|
499
|
+
((priority * 0.40) + (confidence * 0.30) + 0.25) AS score
|
|
500
|
+
FROM context_facts
|
|
501
|
+
WHERE source_type = 'feature-agent' AND scope_feature = ? AND status = 'promoted'
|
|
502
|
+
ORDER BY updated_at DESC, priority DESC
|
|
503
|
+
LIMIT ?
|
|
504
|
+
`).all(options.feature, Math.max(3, Math.floor(options.limit * 0.2)));
|
|
505
|
+
}
|
|
506
|
+
else {
|
|
507
|
+
// Auto-discover recently learned features when no specific feature is requested
|
|
508
|
+
learnedFacts = db.prepare(`
|
|
483
509
|
SELECT
|
|
484
510
|
id,
|
|
485
511
|
source_type,
|
|
@@ -500,24 +526,24 @@ export function buildContextPack(db, options) {
|
|
|
500
526
|
ORDER BY updated_at DESC, priority DESC
|
|
501
527
|
LIMIT ?
|
|
502
528
|
`).all(Math.max(3, Math.floor(options.limit * 0.2)));
|
|
503
|
-
const learnedRows = learnedFacts.map((row) => ({
|
|
504
|
-
id: String(row.id ?? ""),
|
|
505
|
-
sourceType: String(row.source_type ?? ""),
|
|
506
|
-
sourceRef: String(row.source_ref ?? ""),
|
|
507
|
-
title: String(row.title ?? ""),
|
|
508
|
-
content: String(row.content ?? ""),
|
|
509
|
-
domain: String(row.scope_domain ?? ""),
|
|
510
|
-
feature: String(row.scope_feature ?? ""),
|
|
511
|
-
branch: String(row.scope_branch ?? ""),
|
|
512
|
-
taskType: String(row.scope_task_type ?? ""),
|
|
513
|
-
priority: Number(row.priority ?? 0),
|
|
514
|
-
confidence: Number(row.confidence ?? 0),
|
|
515
|
-
score: Number(row.score ?? 0),
|
|
516
|
-
status: String(row.status ?? "promoted"),
|
|
517
|
-
updatedAt: String(row.updated_at ?? ""),
|
|
518
|
-
}));
|
|
519
|
-
addRows(learnedRows);
|
|
520
529
|
}
|
|
530
|
+
const learnedRows = learnedFacts.map((row) => ({
|
|
531
|
+
id: String(row.id ?? ""),
|
|
532
|
+
sourceType: String(row.source_type ?? ""),
|
|
533
|
+
sourceRef: String(row.source_ref ?? ""),
|
|
534
|
+
title: String(row.title ?? ""),
|
|
535
|
+
content: String(row.content ?? ""),
|
|
536
|
+
domain: String(row.scope_domain ?? ""),
|
|
537
|
+
feature: String(row.scope_feature ?? ""),
|
|
538
|
+
branch: String(row.scope_branch ?? ""),
|
|
539
|
+
taskType: String(row.scope_task_type ?? ""),
|
|
540
|
+
priority: Number(row.priority ?? 0),
|
|
541
|
+
confidence: Number(row.confidence ?? 0),
|
|
542
|
+
score: Number(row.score ?? 0),
|
|
543
|
+
status: String(row.status ?? "promoted"),
|
|
544
|
+
updatedAt: String(row.updated_at ?? ""),
|
|
545
|
+
}));
|
|
546
|
+
addRows(learnedRows);
|
|
521
547
|
// 1) Main branch domain context is the durable source-of-truth baseline.
|
|
522
548
|
if (pack.length < options.limit) {
|
|
523
549
|
addRows(runQuery({
|
|
@@ -650,3 +676,163 @@ export function archiveFeatureContext(db, options) {
|
|
|
650
676
|
const result = tx();
|
|
651
677
|
return Number(result.changes ?? 0);
|
|
652
678
|
}
|
|
679
|
+
export function getFeatureResume(db, options) {
|
|
680
|
+
const feature = String(options.feature ?? "").trim();
|
|
681
|
+
const domain = String(options.domain ?? "").trim();
|
|
682
|
+
const limit = Number(options.limit ?? 20);
|
|
683
|
+
if (!feature) {
|
|
684
|
+
return "# Feature Resume\n\nError: feature parameter is required.";
|
|
685
|
+
}
|
|
686
|
+
// Query learned feature facts
|
|
687
|
+
const learnedFacts = db
|
|
688
|
+
.prepare(`
|
|
689
|
+
SELECT
|
|
690
|
+
title,
|
|
691
|
+
content,
|
|
692
|
+
confidence,
|
|
693
|
+
updated_at
|
|
694
|
+
FROM context_facts
|
|
695
|
+
WHERE source_type = 'feature-agent'
|
|
696
|
+
AND scope_feature = ?
|
|
697
|
+
AND status = 'promoted'
|
|
698
|
+
ORDER BY updated_at DESC
|
|
699
|
+
LIMIT 1
|
|
700
|
+
`)
|
|
701
|
+
.all(feature);
|
|
702
|
+
// Query PR metadata related to the feature
|
|
703
|
+
const prFacts = db
|
|
704
|
+
.prepare(`
|
|
705
|
+
SELECT
|
|
706
|
+
title,
|
|
707
|
+
content,
|
|
708
|
+
source_ref,
|
|
709
|
+
confidence,
|
|
710
|
+
updated_at
|
|
711
|
+
FROM context_facts
|
|
712
|
+
WHERE source_type LIKE 'pr_%'
|
|
713
|
+
AND (scope_feature = ? OR scope_branch LIKE ?)
|
|
714
|
+
AND status = 'promoted'
|
|
715
|
+
ORDER BY updated_at DESC
|
|
716
|
+
LIMIT ?
|
|
717
|
+
`)
|
|
718
|
+
.all(feature, `%${feature}%`, limit);
|
|
719
|
+
// Build markdown document
|
|
720
|
+
const markdown = [];
|
|
721
|
+
markdown.push(`# Feature Resume: ${feature}`);
|
|
722
|
+
markdown.push("");
|
|
723
|
+
// Add learned knowledge section
|
|
724
|
+
if (learnedFacts.length > 0) {
|
|
725
|
+
const learned = learnedFacts[0];
|
|
726
|
+
markdown.push("## 📚 Feature Knowledge");
|
|
727
|
+
markdown.push(`**Confidence:** ${(learned.confidence * 100).toFixed(0)}%`);
|
|
728
|
+
markdown.push(`**Last Updated:** ${new Date(learned.updated_at).toLocaleString()}`);
|
|
729
|
+
markdown.push("");
|
|
730
|
+
markdown.push(learned.content);
|
|
731
|
+
markdown.push("");
|
|
732
|
+
}
|
|
733
|
+
else {
|
|
734
|
+
markdown.push("## 📚 Feature Knowledge");
|
|
735
|
+
markdown.push("*(No learned knowledge yet. Run `learn_feature` to seed context.)*");
|
|
736
|
+
markdown.push("");
|
|
737
|
+
}
|
|
738
|
+
// Add PR metadata section
|
|
739
|
+
if (prFacts.length > 0) {
|
|
740
|
+
markdown.push("## 🔗 Related Pull Requests");
|
|
741
|
+
markdown.push("");
|
|
742
|
+
for (const pr of prFacts) {
|
|
743
|
+
const confidence = (pr.confidence * 100).toFixed(0);
|
|
744
|
+
const ref = pr.source_ref || "unknown";
|
|
745
|
+
markdown.push(`- **${pr.title}** (${ref}) — ${confidence}% confidence`);
|
|
746
|
+
if (pr.content && pr.content.length < 200) {
|
|
747
|
+
markdown.push(` > ${pr.content}`);
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
markdown.push("");
|
|
751
|
+
}
|
|
752
|
+
// Add recommendations
|
|
753
|
+
markdown.push("## 💡 Recommendations");
|
|
754
|
+
if (learnedFacts.length === 0) {
|
|
755
|
+
markdown.push('- Run `learn_feature({ featureBranch: "${feature}", agentContent: "..." })` to seed knowledge');
|
|
756
|
+
}
|
|
757
|
+
if (prFacts.length === 0) {
|
|
758
|
+
markdown.push("- Sync PR context with `pre_plan_sync_brief` to see related PRs");
|
|
759
|
+
}
|
|
760
|
+
markdown.push("- Use this resume alongside your active worktree for complete context");
|
|
761
|
+
return markdown.join("\n");
|
|
762
|
+
}
|
|
763
|
+
export function listLearnedFeatures(db, options) {
|
|
764
|
+
const clauses = ["source_type = 'feature-agent'"];
|
|
765
|
+
const values = [];
|
|
766
|
+
if (options?.domain) {
|
|
767
|
+
clauses.push("scope_domain = ?");
|
|
768
|
+
values.push(options.domain);
|
|
769
|
+
}
|
|
770
|
+
if (options?.status) {
|
|
771
|
+
clauses.push("status = ?");
|
|
772
|
+
values.push(options.status);
|
|
773
|
+
}
|
|
774
|
+
else {
|
|
775
|
+
clauses.push("status = 'promoted'");
|
|
776
|
+
}
|
|
777
|
+
const where = clauses.length > 0 ? `WHERE ${clauses.join(" AND ")}` : "";
|
|
778
|
+
const rows = db.prepare(`
|
|
779
|
+
SELECT DISTINCT
|
|
780
|
+
scope_feature as feature,
|
|
781
|
+
scope_domain as domain,
|
|
782
|
+
scope_branch as branch,
|
|
783
|
+
confidence,
|
|
784
|
+
status,
|
|
785
|
+
created_at,
|
|
786
|
+
updated_at,
|
|
787
|
+
title,
|
|
788
|
+
LENGTH(content) as contentLength
|
|
789
|
+
FROM context_facts
|
|
790
|
+
${where}
|
|
791
|
+
ORDER BY updated_at DESC
|
|
792
|
+
`).all(...values);
|
|
793
|
+
return rows.map((row) => ({
|
|
794
|
+
feature: String(row.feature ?? ""),
|
|
795
|
+
domain: String(row.domain ?? ""),
|
|
796
|
+
branch: String(row.branch ?? ""),
|
|
797
|
+
confidence: Number(row.confidence ?? 0),
|
|
798
|
+
status: String(row.status ?? ""),
|
|
799
|
+
createdAt: String(row.created_at ?? ""),
|
|
800
|
+
updatedAt: String(row.updated_at ?? ""),
|
|
801
|
+
title: String(row.title ?? ""),
|
|
802
|
+
contentLength: Number(row.contentLength ?? 0),
|
|
803
|
+
}));
|
|
804
|
+
}
|
|
805
|
+
export function listAvailableBranches(db, options) {
|
|
806
|
+
const clauses = ["status = 'promoted'"];
|
|
807
|
+
const values = [];
|
|
808
|
+
if (options?.domain) {
|
|
809
|
+
clauses.push("scope_domain = ?");
|
|
810
|
+
values.push(options.domain);
|
|
811
|
+
}
|
|
812
|
+
if (options?.feature) {
|
|
813
|
+
clauses.push("scope_feature = ?");
|
|
814
|
+
values.push(options.feature);
|
|
815
|
+
}
|
|
816
|
+
const where = clauses.length > 0 ? `WHERE ${clauses.join(" AND ")}` : "";
|
|
817
|
+
const rows = db.prepare(`
|
|
818
|
+
SELECT
|
|
819
|
+
scope_branch as branch,
|
|
820
|
+
scope_feature as feature,
|
|
821
|
+
scope_domain as domain,
|
|
822
|
+
COUNT(*) as factCount,
|
|
823
|
+
MAX(updated_at) as lastUpdated,
|
|
824
|
+
MAX(confidence) as topConfidence
|
|
825
|
+
FROM context_facts
|
|
826
|
+
${where}
|
|
827
|
+
GROUP BY scope_branch, scope_feature, scope_domain
|
|
828
|
+
ORDER BY updated_at DESC
|
|
829
|
+
`).all(...values);
|
|
830
|
+
return rows.map((row) => ({
|
|
831
|
+
branch: String(row.branch ?? ""),
|
|
832
|
+
feature: String(row.feature ?? ""),
|
|
833
|
+
domain: String(row.domain ?? ""),
|
|
834
|
+
factCount: Number(row.factCount ?? 0),
|
|
835
|
+
lastUpdated: String(row.lastUpdated ?? ""),
|
|
836
|
+
topConfidence: Number(row.topConfidence ?? 0),
|
|
837
|
+
}));
|
|
838
|
+
}
|
package/dist/mcp/server.js
CHANGED
|
@@ -6,7 +6,7 @@ import { execFileSync } from "node:child_process";
|
|
|
6
6
|
import fs from "node:fs";
|
|
7
7
|
import path from "node:path";
|
|
8
8
|
import { pathToFileURL } from "node:url";
|
|
9
|
-
import { archiveFeatureContext, buildContextPack, openDatabase, promoteContextFacts, upsertContextFact, upsertWorktreeSession, } from "../db/client.js";
|
|
9
|
+
import { archiveFeatureContext, buildContextPack, getFeatureResume, listLearnedFeatures, listAvailableBranches, openDatabase, promoteContextFacts, upsertContextFact, upsertWorktreeSession, } from "../db/client.js";
|
|
10
10
|
import { commitDetails, explainPathActivity, extractFeatureBranchCommits, latestCommitForFile, mainBranchOvernightBrief, resumeFeatureSessionBrief, whoChangedFile, } from "../git/insights.js";
|
|
11
11
|
import { listActiveWorktrees } from "../git/worktree.js";
|
|
12
12
|
import { syncPullRequestContext } from "../pr/sync.js";
|
|
@@ -334,6 +334,49 @@ export async function startMcpServer() {
|
|
|
334
334
|
required: ["featureBranch"],
|
|
335
335
|
},
|
|
336
336
|
},
|
|
337
|
+
{
|
|
338
|
+
name: "get_feature_resume",
|
|
339
|
+
description: "Combine learned feature knowledge with PR metadata and return as markdown. Does NOT require a git worktree. Use this to review a feature's complete context: what we learned about it + related PR activity.",
|
|
340
|
+
inputSchema: {
|
|
341
|
+
type: "object",
|
|
342
|
+
properties: {
|
|
343
|
+
feature: {
|
|
344
|
+
type: "string",
|
|
345
|
+
description: "e.g. messaging",
|
|
346
|
+
},
|
|
347
|
+
domain: { type: "string" },
|
|
348
|
+
limit: { type: "number" },
|
|
349
|
+
},
|
|
350
|
+
required: ["feature"],
|
|
351
|
+
},
|
|
352
|
+
},
|
|
353
|
+
{
|
|
354
|
+
name: "list_learned_features",
|
|
355
|
+
description: "List all learned features stored in the knowledge database with confidence levels and timestamps.",
|
|
356
|
+
inputSchema: {
|
|
357
|
+
type: "object",
|
|
358
|
+
properties: {
|
|
359
|
+
domain: { type: "string" },
|
|
360
|
+
status: {
|
|
361
|
+
type: "string",
|
|
362
|
+
description: "Filter by status (promoted, draft, etc). Defaults to promoted.",
|
|
363
|
+
},
|
|
364
|
+
},
|
|
365
|
+
required: [],
|
|
366
|
+
},
|
|
367
|
+
},
|
|
368
|
+
{
|
|
369
|
+
name: "list_available_branches",
|
|
370
|
+
description: "List all available branches and features with knowledge context available for each.",
|
|
371
|
+
inputSchema: {
|
|
372
|
+
type: "object",
|
|
373
|
+
properties: {
|
|
374
|
+
domain: { type: "string" },
|
|
375
|
+
feature: { type: "string" },
|
|
376
|
+
},
|
|
377
|
+
required: [],
|
|
378
|
+
},
|
|
379
|
+
},
|
|
337
380
|
{
|
|
338
381
|
name: "pre_plan_sync_brief",
|
|
339
382
|
description: "Run sync + overnight + feature resume analysis before planning work.",
|
|
@@ -638,6 +681,125 @@ export async function startMcpServer() {
|
|
|
638
681
|
content: [{ type: "text", text: JSON.stringify(brief, null, 2) }],
|
|
639
682
|
};
|
|
640
683
|
}
|
|
684
|
+
if (request.params.name === "get_feature_resume") {
|
|
685
|
+
const feature = String(request.params.arguments?.feature ?? "").trim();
|
|
686
|
+
const domain = String(request.params.arguments?.domain ?? "").trim();
|
|
687
|
+
const limit = Number(request.params.arguments?.limit ?? 20);
|
|
688
|
+
if (!feature) {
|
|
689
|
+
return {
|
|
690
|
+
content: [{ type: "text", text: "feature parameter is required" }],
|
|
691
|
+
isError: true,
|
|
692
|
+
};
|
|
693
|
+
}
|
|
694
|
+
const db = openDatabase(dbPath);
|
|
695
|
+
try {
|
|
696
|
+
const resume = getFeatureResume(db, {
|
|
697
|
+
feature,
|
|
698
|
+
domain: domain || undefined,
|
|
699
|
+
limit: Number.isFinite(limit) && limit > 0 ? limit : 20,
|
|
700
|
+
});
|
|
701
|
+
return {
|
|
702
|
+
content: [{ type: "text", text: resume }],
|
|
703
|
+
};
|
|
704
|
+
}
|
|
705
|
+
finally {
|
|
706
|
+
db.close();
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
if (request.params.name === "list_learned_features") {
|
|
710
|
+
const domain = String(request.params.arguments?.domain ?? "").trim();
|
|
711
|
+
const status = String(request.params.arguments?.status ?? "").trim();
|
|
712
|
+
const db = openDatabase(dbPath);
|
|
713
|
+
try {
|
|
714
|
+
const features = listLearnedFeatures(db, {
|
|
715
|
+
domain: domain || undefined,
|
|
716
|
+
status: status || undefined,
|
|
717
|
+
});
|
|
718
|
+
const markdown = [
|
|
719
|
+
"# Learned Features",
|
|
720
|
+
"",
|
|
721
|
+
features.length === 0
|
|
722
|
+
? "*(No learned features yet)*"
|
|
723
|
+
: `${features.length} feature(s) available:`,
|
|
724
|
+
"",
|
|
725
|
+
];
|
|
726
|
+
if (features.length > 0) {
|
|
727
|
+
markdown.push("| Feature | Domain | Branch | Confidence | Status | Last Updated |");
|
|
728
|
+
markdown.push("|---------|--------|--------|------------|--------|--------------|");
|
|
729
|
+
for (const feat of features) {
|
|
730
|
+
const confidence = (feat.confidence * 100).toFixed(0);
|
|
731
|
+
const lastUpdated = new Date(feat.updatedAt).toLocaleDateString();
|
|
732
|
+
markdown.push(`| **${feat.feature}** | ${feat.domain} | ${feat.branch} | ${confidence}% | ${feat.status} | ${lastUpdated} |`);
|
|
733
|
+
}
|
|
734
|
+
markdown.push("");
|
|
735
|
+
markdown.push("## Feature Details");
|
|
736
|
+
markdown.push("");
|
|
737
|
+
for (const feat of features) {
|
|
738
|
+
markdown.push(`### ${feat.feature}`);
|
|
739
|
+
markdown.push(`- **Confidence:** ${(feat.confidence * 100).toFixed(0)}%`);
|
|
740
|
+
markdown.push(`- **Domain:** ${feat.domain}`);
|
|
741
|
+
markdown.push(`- **Branch:** ${feat.branch}`);
|
|
742
|
+
markdown.push(`- **Status:** ${feat.status}`);
|
|
743
|
+
markdown.push(`- **Created:** ${new Date(feat.createdAt).toLocaleString()}`);
|
|
744
|
+
markdown.push(`- **Updated:** ${new Date(feat.updatedAt).toLocaleString()}`);
|
|
745
|
+
markdown.push(`- **Title:** ${feat.title}`);
|
|
746
|
+
markdown.push(`- **Content size:** ${feat.contentLength} bytes`);
|
|
747
|
+
markdown.push("");
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
return {
|
|
751
|
+
content: [{ type: "text", text: markdown.join("\n") }],
|
|
752
|
+
};
|
|
753
|
+
}
|
|
754
|
+
finally {
|
|
755
|
+
db.close();
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
if (request.params.name === "list_available_branches") {
|
|
759
|
+
const domain = String(request.params.arguments?.domain ?? "").trim();
|
|
760
|
+
const feature = String(request.params.arguments?.feature ?? "").trim();
|
|
761
|
+
const db = openDatabase(dbPath);
|
|
762
|
+
try {
|
|
763
|
+
const branches = listAvailableBranches(db, {
|
|
764
|
+
domain: domain || undefined,
|
|
765
|
+
feature: feature || undefined,
|
|
766
|
+
});
|
|
767
|
+
const markdown = [
|
|
768
|
+
"# Available Branches and Features",
|
|
769
|
+
"",
|
|
770
|
+
branches.length === 0
|
|
771
|
+
? "*(No branches with knowledge available)*"
|
|
772
|
+
: `${branches.length} branch/feature combination(s):`,
|
|
773
|
+
"",
|
|
774
|
+
];
|
|
775
|
+
if (branches.length > 0) {
|
|
776
|
+
markdown.push("| Branch | Feature | Domain | Facts | Confidence | Last Updated |");
|
|
777
|
+
markdown.push("|--------|---------|--------|-------|------------|--------------|");
|
|
778
|
+
for (const branch of branches) {
|
|
779
|
+
const confidence = (branch.topConfidence * 100).toFixed(0);
|
|
780
|
+
const lastUpdated = new Date(branch.lastUpdated).toLocaleDateString();
|
|
781
|
+
markdown.push(`| **${branch.branch}** | ${branch.feature} | ${branch.domain} | ${branch.factCount} | ${confidence}% | ${lastUpdated} |`);
|
|
782
|
+
}
|
|
783
|
+
markdown.push("");
|
|
784
|
+
markdown.push("## Branch Details");
|
|
785
|
+
markdown.push("");
|
|
786
|
+
for (const branch of branches) {
|
|
787
|
+
markdown.push(`### ${branch.branch} (${branch.feature})`);
|
|
788
|
+
markdown.push(`- **Domain:** ${branch.domain}`);
|
|
789
|
+
markdown.push(`- **Facts stored:** ${branch.factCount}`);
|
|
790
|
+
markdown.push(`- **Top confidence:** ${(branch.topConfidence * 100).toFixed(0)}%`);
|
|
791
|
+
markdown.push(`- **Last updated:** ${new Date(branch.lastUpdated).toLocaleString()}`);
|
|
792
|
+
markdown.push("");
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
return {
|
|
796
|
+
content: [{ type: "text", text: markdown.join("\n") }],
|
|
797
|
+
};
|
|
798
|
+
}
|
|
799
|
+
finally {
|
|
800
|
+
db.close();
|
|
801
|
+
}
|
|
802
|
+
}
|
|
641
803
|
if (request.params.name === "pre_plan_sync_brief") {
|
|
642
804
|
const owner = String(request.params.arguments?.owner ?? "").trim();
|
|
643
805
|
const repo = String(request.params.arguments?.repo ?? "").trim();
|
package/package.json
CHANGED