@nxuss/lemma 1.0.5 → 1.1.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/README.md +203 -95
- package/dist/cjs/mcp/prompts.d.ts +1 -1
- package/dist/cjs/mcp/prompts.d.ts.map +1 -1
- package/dist/cjs/mcp/prompts.js +24 -0
- package/dist/cjs/mcp/prompts.js.map +1 -1
- package/dist/cjs/mcp/tools.d.ts.map +1 -1
- package/dist/cjs/mcp/tools.js +497 -0
- package/dist/cjs/mcp/tools.js.map +1 -1
- package/dist/cjs/utils/AutoContextBundle.d.ts +17 -0
- package/dist/cjs/utils/AutoContextBundle.d.ts.map +1 -0
- package/dist/cjs/utils/AutoContextBundle.js +125 -0
- package/dist/cjs/utils/AutoContextBundle.js.map +1 -0
- package/dist/cjs/utils/BulkFileDigest.d.ts +13 -0
- package/dist/cjs/utils/BulkFileDigest.d.ts.map +1 -0
- package/dist/cjs/utils/BulkFileDigest.js +64 -0
- package/dist/cjs/utils/BulkFileDigest.js.map +1 -0
- package/dist/cjs/utils/ConversationCheckpoint.d.ts +14 -0
- package/dist/cjs/utils/ConversationCheckpoint.d.ts.map +1 -0
- package/dist/cjs/utils/ConversationCheckpoint.js +77 -0
- package/dist/cjs/utils/ConversationCheckpoint.js.map +1 -0
- package/dist/cjs/utils/FileFingerprint.d.ts +11 -0
- package/dist/cjs/utils/FileFingerprint.d.ts.map +1 -0
- package/dist/cjs/utils/FileFingerprint.js +64 -0
- package/dist/cjs/utils/FileFingerprint.js.map +1 -0
- package/dist/cjs/utils/GitBlameHeat.d.ts +20 -0
- package/dist/cjs/utils/GitBlameHeat.d.ts.map +1 -0
- package/dist/cjs/utils/GitBlameHeat.js +91 -0
- package/dist/cjs/utils/GitBlameHeat.js.map +1 -0
- package/dist/cjs/utils/ImportTreeContext.d.ts +17 -0
- package/dist/cjs/utils/ImportTreeContext.d.ts.map +1 -0
- package/dist/cjs/utils/ImportTreeContext.js +159 -0
- package/dist/cjs/utils/ImportTreeContext.js.map +1 -0
- package/dist/cjs/utils/PromptPatternCache.d.ts +14 -0
- package/dist/cjs/utils/PromptPatternCache.d.ts.map +1 -0
- package/dist/cjs/utils/PromptPatternCache.js +104 -0
- package/dist/cjs/utils/PromptPatternCache.js.map +1 -0
- package/dist/cjs/utils/RepeatGuard.d.ts +9 -0
- package/dist/cjs/utils/RepeatGuard.d.ts.map +1 -0
- package/dist/cjs/utils/RepeatGuard.js +90 -0
- package/dist/cjs/utils/RepeatGuard.js.map +1 -0
- package/dist/cjs/utils/TestAutofixInterceptor.d.ts +17 -0
- package/dist/cjs/utils/TestAutofixInterceptor.d.ts.map +1 -0
- package/dist/cjs/utils/TestAutofixInterceptor.js +125 -0
- package/dist/cjs/utils/TestAutofixInterceptor.js.map +1 -0
- package/dist/cjs/utils/TokenBudgetedReader.d.ts +14 -0
- package/dist/cjs/utils/TokenBudgetedReader.d.ts.map +1 -0
- package/dist/cjs/utils/TokenBudgetedReader.js +157 -0
- package/dist/cjs/utils/TokenBudgetedReader.js.map +1 -0
- package/dist/cjs/utils/TypeCoverage.d.ts +15 -0
- package/dist/cjs/utils/TypeCoverage.d.ts.map +1 -0
- package/dist/cjs/utils/TypeCoverage.js +141 -0
- package/dist/cjs/utils/TypeCoverage.js.map +1 -0
- package/dist/esm/mcp/prompts.d.ts +1 -1
- package/dist/esm/mcp/prompts.d.ts.map +1 -1
- package/dist/esm/mcp/prompts.js +24 -0
- package/dist/esm/mcp/prompts.js.map +1 -1
- package/dist/esm/mcp/tools.d.ts.map +1 -1
- package/dist/esm/mcp/tools.js +497 -0
- package/dist/esm/mcp/tools.js.map +1 -1
- package/dist/esm/utils/AutoContextBundle.d.ts +17 -0
- package/dist/esm/utils/AutoContextBundle.d.ts.map +1 -0
- package/dist/esm/utils/AutoContextBundle.js +86 -0
- package/dist/esm/utils/AutoContextBundle.js.map +1 -0
- package/dist/esm/utils/BulkFileDigest.d.ts +13 -0
- package/dist/esm/utils/BulkFileDigest.d.ts.map +1 -0
- package/dist/esm/utils/BulkFileDigest.js +58 -0
- package/dist/esm/utils/BulkFileDigest.js.map +1 -0
- package/dist/esm/utils/ConversationCheckpoint.d.ts +14 -0
- package/dist/esm/utils/ConversationCheckpoint.d.ts.map +1 -0
- package/dist/esm/utils/ConversationCheckpoint.js +69 -0
- package/dist/esm/utils/ConversationCheckpoint.js.map +1 -0
- package/dist/esm/utils/FileFingerprint.d.ts +11 -0
- package/dist/esm/utils/FileFingerprint.d.ts.map +1 -0
- package/dist/esm/utils/FileFingerprint.js +56 -0
- package/dist/esm/utils/FileFingerprint.js.map +1 -0
- package/dist/esm/utils/GitBlameHeat.d.ts +20 -0
- package/dist/esm/utils/GitBlameHeat.d.ts.map +1 -0
- package/dist/esm/utils/GitBlameHeat.js +85 -0
- package/dist/esm/utils/GitBlameHeat.js.map +1 -0
- package/dist/esm/utils/ImportTreeContext.d.ts +17 -0
- package/dist/esm/utils/ImportTreeContext.d.ts.map +1 -0
- package/dist/esm/utils/ImportTreeContext.js +153 -0
- package/dist/esm/utils/ImportTreeContext.js.map +1 -0
- package/dist/esm/utils/PromptPatternCache.d.ts +14 -0
- package/dist/esm/utils/PromptPatternCache.d.ts.map +1 -0
- package/dist/esm/utils/PromptPatternCache.js +96 -0
- package/dist/esm/utils/PromptPatternCache.js.map +1 -0
- package/dist/esm/utils/RepeatGuard.d.ts +9 -0
- package/dist/esm/utils/RepeatGuard.d.ts.map +1 -0
- package/dist/esm/utils/RepeatGuard.js +83 -0
- package/dist/esm/utils/RepeatGuard.js.map +1 -0
- package/dist/esm/utils/TestAutofixInterceptor.d.ts +17 -0
- package/dist/esm/utils/TestAutofixInterceptor.d.ts.map +1 -0
- package/dist/esm/utils/TestAutofixInterceptor.js +122 -0
- package/dist/esm/utils/TestAutofixInterceptor.js.map +1 -0
- package/dist/esm/utils/TokenBudgetedReader.d.ts +14 -0
- package/dist/esm/utils/TokenBudgetedReader.d.ts.map +1 -0
- package/dist/esm/utils/TokenBudgetedReader.js +118 -0
- package/dist/esm/utils/TokenBudgetedReader.js.map +1 -0
- package/dist/esm/utils/TypeCoverage.d.ts +15 -0
- package/dist/esm/utils/TypeCoverage.d.ts.map +1 -0
- package/dist/esm/utils/TypeCoverage.js +102 -0
- package/dist/esm/utils/TypeCoverage.js.map +1 -0
- package/package.json +1 -1
package/dist/cjs/mcp/tools.js
CHANGED
|
@@ -49,6 +49,17 @@ const ComplexityRouter_1 = require("../proxy/ComplexityRouter");
|
|
|
49
49
|
const ContextSqueezer_1 = require("../utils/ContextSqueezer");
|
|
50
50
|
const reportSavings_1 = require("../utils/reportSavings");
|
|
51
51
|
const utils_1 = require("./utils");
|
|
52
|
+
const FileFingerprint_1 = require("../utils/FileFingerprint");
|
|
53
|
+
const GitBlameHeat_1 = require("../utils/GitBlameHeat");
|
|
54
|
+
const TypeCoverage_1 = require("../utils/TypeCoverage");
|
|
55
|
+
const ImportTreeContext_1 = require("../utils/ImportTreeContext");
|
|
56
|
+
const TokenBudgetedReader_1 = require("../utils/TokenBudgetedReader");
|
|
57
|
+
const BulkFileDigest_1 = require("../utils/BulkFileDigest");
|
|
58
|
+
const AutoContextBundle_1 = require("../utils/AutoContextBundle");
|
|
59
|
+
const RepeatGuard_1 = require("../utils/RepeatGuard");
|
|
60
|
+
const ConversationCheckpoint_1 = require("../utils/ConversationCheckpoint");
|
|
61
|
+
const TestAutofixInterceptor_1 = require("../utils/TestAutofixInterceptor");
|
|
62
|
+
const PromptPatternCache_1 = require("../utils/PromptPatternCache");
|
|
52
63
|
const PRReviewEngine_1 = require("../pr-review/PRReviewEngine");
|
|
53
64
|
const ReviewStore_1 = require("../pr-review/ReviewStore");
|
|
54
65
|
const reviewRunner_1 = require("../pr-review/reviewRunner");
|
|
@@ -82,6 +93,12 @@ const FREE_TOOLS = new Set([
|
|
|
82
93
|
"token_budget", "squeeze_prompt", "turbosqueeze",
|
|
83
94
|
// Utility — just enough to function
|
|
84
95
|
"read_workspace_file", "scrub_privacy", "summarize_long_text",
|
|
96
|
+
// Phase 1 zero-cost analysis tools
|
|
97
|
+
"file_fingerprint", "git_blame_heat", "type_coverage_report", "import_tree_context",
|
|
98
|
+
// Phase 2 smart reading & dedup tools
|
|
99
|
+
"read_token_budgeted", "bulk_file_digest", "auto_context_bundle", "repeat_guard",
|
|
100
|
+
// Phase 3 session & automation tools
|
|
101
|
+
"conversation_checkpoint", "test_autofix_interceptor", "prompt_pattern_cache",
|
|
85
102
|
]);
|
|
86
103
|
const PRO_GATE_MESSAGE = [
|
|
87
104
|
"🔒 This tool requires Lemma Pro.",
|
|
@@ -812,6 +829,144 @@ const toolDefinitions = [
|
|
|
812
829
|
},
|
|
813
830
|
required: ["filePath", "functionName"]
|
|
814
831
|
}
|
|
832
|
+
},
|
|
833
|
+
{
|
|
834
|
+
name: "file_fingerprint",
|
|
835
|
+
description: "Compute SHA256 fingerprint of a file. Returns 'unchanged' if hash matches cache, avoiding full re-reads. Saves 60-70% tokens on repeated file access.",
|
|
836
|
+
inputSchema: {
|
|
837
|
+
type: "object",
|
|
838
|
+
properties: {
|
|
839
|
+
filePath: { type: "string", description: "Path relative to the project root" },
|
|
840
|
+
forceRefresh: { type: "boolean", description: "Force re-read even if hash matches", default: false }
|
|
841
|
+
},
|
|
842
|
+
required: ["filePath"]
|
|
843
|
+
}
|
|
844
|
+
},
|
|
845
|
+
{
|
|
846
|
+
name: "git_blame_heat",
|
|
847
|
+
description: "Analyze git blame history to identify high-risk lines and authors. Zero LLM cost. Returns risk scores per line, hotspots, and top contributors by risk.",
|
|
848
|
+
inputSchema: {
|
|
849
|
+
type: "object",
|
|
850
|
+
properties: {
|
|
851
|
+
filePath: { type: "string", description: "Path relative to the project root" }
|
|
852
|
+
},
|
|
853
|
+
required: ["filePath"]
|
|
854
|
+
}
|
|
855
|
+
},
|
|
856
|
+
{
|
|
857
|
+
name: "type_coverage_report",
|
|
858
|
+
description: "Analyze TypeScript type coverage of a file using AST. Returns declaration count, typed vs untyped ratio, any-usage count, and a safety score 0-100. Zero LLM cost.",
|
|
859
|
+
inputSchema: {
|
|
860
|
+
type: "object",
|
|
861
|
+
properties: {
|
|
862
|
+
filePath: { type: "string", description: "Path relative to the project root" }
|
|
863
|
+
},
|
|
864
|
+
required: ["filePath"]
|
|
865
|
+
}
|
|
866
|
+
},
|
|
867
|
+
{
|
|
868
|
+
name: "import_tree_context",
|
|
869
|
+
description: "Build a bidirectional import graph for a file. Shows what it imports, what imports it, and external dependencies. Zero LLM cost. Essential before refactors.",
|
|
870
|
+
inputSchema: {
|
|
871
|
+
type: "tool",
|
|
872
|
+
properties: {
|
|
873
|
+
filePath: { type: "string", description: "Path relative to the project root" },
|
|
874
|
+
depth: { type: "number", description: "Traversal depth (default: 2)", default: 2 }
|
|
875
|
+
},
|
|
876
|
+
required: ["filePath"]
|
|
877
|
+
}
|
|
878
|
+
},
|
|
879
|
+
{
|
|
880
|
+
name: "read_token_budgeted",
|
|
881
|
+
description: "Read a file with a hard token budget. Returns only the most relevant sections up to maxTokens. Saves 70-90% vs full reads.",
|
|
882
|
+
inputSchema: {
|
|
883
|
+
type: "object",
|
|
884
|
+
properties: {
|
|
885
|
+
filePath: { type: "string", description: "Path relative to the project root" },
|
|
886
|
+
query: { type: "string", description: "Search query to determine relevance", default: "" },
|
|
887
|
+
maxTokens: { type: "number", description: "Maximum tokens to return (default: 2000)", default: 2000 }
|
|
888
|
+
},
|
|
889
|
+
required: ["filePath"]
|
|
890
|
+
}
|
|
891
|
+
},
|
|
892
|
+
{
|
|
893
|
+
name: "bulk_file_digest",
|
|
894
|
+
description: "Read multiple files in one call and return a compressed digest. Saves 80% round-trips vs reading files individually.",
|
|
895
|
+
inputSchema: {
|
|
896
|
+
type: "object",
|
|
897
|
+
properties: {
|
|
898
|
+
filePaths: {
|
|
899
|
+
type: "array",
|
|
900
|
+
items: { type: "string" },
|
|
901
|
+
description: "Array of file paths relative to the project root"
|
|
902
|
+
},
|
|
903
|
+
query: { type: "string", description: "Search query for relevance ranking", default: "" },
|
|
904
|
+
maxTotalTokens: { type: "number", description: "Total token budget for all files (default: 4000)", default: 4000 }
|
|
905
|
+
},
|
|
906
|
+
required: ["filePaths"]
|
|
907
|
+
}
|
|
908
|
+
},
|
|
909
|
+
{
|
|
910
|
+
name: "auto_context_bundle",
|
|
911
|
+
description: "Get everything about a file in one call: compressed content, import graph, schema types, and telepathic hints from The Brain. Replaces 4-5 separate tool calls.",
|
|
912
|
+
inputSchema: {
|
|
913
|
+
type: "object",
|
|
914
|
+
properties: {
|
|
915
|
+
filePath: { type: "string", description: "Path relative to the project root" }
|
|
916
|
+
},
|
|
917
|
+
required: ["filePath"]
|
|
918
|
+
}
|
|
919
|
+
},
|
|
920
|
+
{
|
|
921
|
+
name: "repeat_guard",
|
|
922
|
+
description: "Check if a draft output is repetitive compared to recent responses. Returns similarity score and suggestion. Prevents duplicate explanations.",
|
|
923
|
+
inputSchema: {
|
|
924
|
+
type: "object",
|
|
925
|
+
properties: {
|
|
926
|
+
draftOutput: { type: "string", description: "The draft output to check for repetition" },
|
|
927
|
+
threshold: { type: "number", description: "Similarity threshold 0-1 (default: 0.75)", default: 0.75 }
|
|
928
|
+
},
|
|
929
|
+
required: ["draftOutput"]
|
|
930
|
+
}
|
|
931
|
+
},
|
|
932
|
+
{
|
|
933
|
+
name: "conversation_checkpoint",
|
|
934
|
+
description: "Save or load session state. Prevents re-explaining context across turns. Save current progress or load last checkpoint.",
|
|
935
|
+
inputSchema: {
|
|
936
|
+
type: "object",
|
|
937
|
+
properties: {
|
|
938
|
+
action: { type: "string", enum: ["save", "load", "summary"], description: "Action to perform", default: "load" },
|
|
939
|
+
filesModified: { type: "array", items: { type: "string" }, description: "Files modified in this session" },
|
|
940
|
+
decisionsMade: { type: "array", items: { type: "string" }, description: "Decisions made" },
|
|
941
|
+
bugsResolved: { type: "array", items: { type: "string" }, description: "Bugs resolved" },
|
|
942
|
+
tasksPending: { type: "array", items: { type: "string" }, description: "Pending tasks" }
|
|
943
|
+
},
|
|
944
|
+
required: ["action"]
|
|
945
|
+
}
|
|
946
|
+
},
|
|
947
|
+
{
|
|
948
|
+
name: "test_autofix_interceptor",
|
|
949
|
+
description: "Run tests and auto-search The Brain for fixes to failures. Returns failure list with suggested fixes from past sessions. Saves 4-5 turns of debugging.",
|
|
950
|
+
inputSchema: {
|
|
951
|
+
type: "object",
|
|
952
|
+
properties: {
|
|
953
|
+
command: { type: "string", description: "Test command (default: 'npm test')", default: "npm test" }
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
},
|
|
957
|
+
{
|
|
958
|
+
name: "prompt_pattern_cache",
|
|
959
|
+
description: "Find or store optimized prompt templates. Reuses past prompt patterns to save 20-30% tokens on repetitive operations.",
|
|
960
|
+
inputSchema: {
|
|
961
|
+
type: "object",
|
|
962
|
+
properties: {
|
|
963
|
+
action: { type: "string", enum: ["find", "store", "stats"], description: "Action to perform", default: "find" },
|
|
964
|
+
query: { type: "string", description: "The prompt/query to search or store" },
|
|
965
|
+
template: { type: "string", description: "The optimized template to store (for 'store' action)" },
|
|
966
|
+
tokensSaved: { type: "number", description: "Estimated tokens saved by this template", default: 0 }
|
|
967
|
+
},
|
|
968
|
+
required: ["action"]
|
|
969
|
+
}
|
|
815
970
|
}
|
|
816
971
|
];
|
|
817
972
|
const toolHandlers = {
|
|
@@ -872,6 +1027,17 @@ const toolHandlers = {
|
|
|
872
1027
|
semantic_grep: handleSemanticGrep,
|
|
873
1028
|
imports_skeleton_resolver: handleImportsSkeletonResolver,
|
|
874
1029
|
ast_flow_visualizer: handleAstFlowVisualizer,
|
|
1030
|
+
file_fingerprint: handleFileFingerprint,
|
|
1031
|
+
git_blame_heat: handleGitBlameHeat,
|
|
1032
|
+
type_coverage_report: handleTypeCoverageReport,
|
|
1033
|
+
import_tree_context: handleImportTreeContext,
|
|
1034
|
+
read_token_budgeted: handleReadTokenBudgeted,
|
|
1035
|
+
bulk_file_digest: handleBulkFileDigest,
|
|
1036
|
+
auto_context_bundle: handleAutoContextBundle,
|
|
1037
|
+
repeat_guard: handleRepeatGuard,
|
|
1038
|
+
conversation_checkpoint: handleConversationCheckpoint,
|
|
1039
|
+
test_autofix_interceptor: handleTestAutofixInterceptor,
|
|
1040
|
+
prompt_pattern_cache: handlePromptPatternCache,
|
|
875
1041
|
};
|
|
876
1042
|
function setupToolsHandlers(server, onToolCall) {
|
|
877
1043
|
server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => ({
|
|
@@ -4480,4 +4646,335 @@ async function handleAstFlowVisualizer(args) {
|
|
|
4480
4646
|
return { content: [{ type: "text", text: `AST flow visualization failed: ${e.message}` }] };
|
|
4481
4647
|
}
|
|
4482
4648
|
}
|
|
4649
|
+
// ── File Fingerprint ──────────────────────────────────────────────────
|
|
4650
|
+
async function handleFileFingerprint(args) {
|
|
4651
|
+
const filePath = args.filePath;
|
|
4652
|
+
const forceRefresh = !!args.forceRefresh;
|
|
4653
|
+
if (!filePath)
|
|
4654
|
+
throw new Error("filePath is required");
|
|
4655
|
+
const workspaceRoot = process.cwd();
|
|
4656
|
+
try {
|
|
4657
|
+
const result = (0, FileFingerprint_1.computeFingerprint)(filePath, workspaceRoot, forceRefresh);
|
|
4658
|
+
if (result.status === "unchanged") {
|
|
4659
|
+
return { content: [{ type: "text", text: `UNCHANGED: ${filePath} (hash: ${result.hash}, ${result.lines} lines)` }] };
|
|
4660
|
+
}
|
|
4661
|
+
if (result.status === "new") {
|
|
4662
|
+
return { content: [{ type: "text", text: `NEW: ${filePath} (hash: ${result.hash}, ${result.lines} lines)` }] };
|
|
4663
|
+
}
|
|
4664
|
+
(0, reportSavings_1.reportSavings)({ source: "cache", charsBefore: (result.content || "").length, charsAfter: 0, toolName: "file_fingerprint", filePath });
|
|
4665
|
+
return { content: [{ type: "text", text: `CHANGED: ${filePath} (hash: ${result.hash}, ${result.lines} lines)\n\n${result.content}` }] };
|
|
4666
|
+
}
|
|
4667
|
+
catch (e) {
|
|
4668
|
+
(0, utils_1.logError)("file_fingerprint", e);
|
|
4669
|
+
return { content: [{ type: "text", text: `Fingerprint failed: ${e.message}` }] };
|
|
4670
|
+
}
|
|
4671
|
+
}
|
|
4672
|
+
// ── Git Blame Heat ────────────────────────────────────────────────────
|
|
4673
|
+
async function handleGitBlameHeat(args) {
|
|
4674
|
+
const filePath = args.filePath;
|
|
4675
|
+
if (!filePath)
|
|
4676
|
+
throw new Error("filePath is required");
|
|
4677
|
+
const workspaceRoot = process.cwd();
|
|
4678
|
+
try {
|
|
4679
|
+
const result = (0, GitBlameHeat_1.analyzeBlameHeat)(filePath, workspaceRoot);
|
|
4680
|
+
const lines = [
|
|
4681
|
+
`# Git Blame Heat: ${result.file}`,
|
|
4682
|
+
`**Total lines:** ${result.totalLines} | **Risk Score:** ${result.riskScore}/100`,
|
|
4683
|
+
"",
|
|
4684
|
+
];
|
|
4685
|
+
if (result.topAuthors.length > 0) {
|
|
4686
|
+
lines.push("## Top Authors by Risk");
|
|
4687
|
+
for (const a of result.topAuthors) {
|
|
4688
|
+
lines.push(`- **${a.author}**: ${a.lines} lines, risk ${a.risk}`);
|
|
4689
|
+
}
|
|
4690
|
+
lines.push("");
|
|
4691
|
+
}
|
|
4692
|
+
if (result.hotspots.length > 0) {
|
|
4693
|
+
lines.push("## Hotspots (risk > 50)");
|
|
4694
|
+
for (const h of result.hotspots.slice(0, 10)) {
|
|
4695
|
+
lines.push(`- L${h.line}: risk=${h.riskScore.toFixed(1)}, author=${h.author}, age=${h.age}d, changes=${h.changeCount}`);
|
|
4696
|
+
}
|
|
4697
|
+
}
|
|
4698
|
+
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
4699
|
+
}
|
|
4700
|
+
catch (e) {
|
|
4701
|
+
(0, utils_1.logError)("git_blame_heat", e);
|
|
4702
|
+
return { content: [{ type: "text", text: `Git blame heat failed: ${e.message}` }] };
|
|
4703
|
+
}
|
|
4704
|
+
}
|
|
4705
|
+
// ── Type Coverage Report ──────────────────────────────────────────────
|
|
4706
|
+
async function handleTypeCoverageReport(args) {
|
|
4707
|
+
const filePath = args.filePath;
|
|
4708
|
+
if (!filePath)
|
|
4709
|
+
throw new Error("filePath is required");
|
|
4710
|
+
const workspaceRoot = process.cwd();
|
|
4711
|
+
try {
|
|
4712
|
+
const result = (0, TypeCoverage_1.analyzeTypeCoverage)(filePath, workspaceRoot);
|
|
4713
|
+
const lines = [
|
|
4714
|
+
`# Type Coverage: ${result.file}`,
|
|
4715
|
+
`**Score:** ${result.score}/100 | **Coverage:** ${result.coveragePercent}%`,
|
|
4716
|
+
`**Declarations:** ${result.typedDeclarations}/${result.totalDeclarations} typed | **any count:** ${result.anyCount}`,
|
|
4717
|
+
"",
|
|
4718
|
+
];
|
|
4719
|
+
if (result.missingTypes.length > 0) {
|
|
4720
|
+
lines.push("## Missing Types (first 10)");
|
|
4721
|
+
for (const m of result.missingTypes.slice(0, 10)) {
|
|
4722
|
+
lines.push(`- L${m.line}: \`${m.code}\``);
|
|
4723
|
+
}
|
|
4724
|
+
}
|
|
4725
|
+
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
4726
|
+
}
|
|
4727
|
+
catch (e) {
|
|
4728
|
+
(0, utils_1.logError)("type_coverage_report", e);
|
|
4729
|
+
return { content: [{ type: "text", text: `Type coverage analysis failed: ${e.message}` }] };
|
|
4730
|
+
}
|
|
4731
|
+
}
|
|
4732
|
+
// ── Import Tree Context ───────────────────────────────────────────────
|
|
4733
|
+
async function handleImportTreeContext(args) {
|
|
4734
|
+
const filePath = args.filePath;
|
|
4735
|
+
const depth = args.depth || 2;
|
|
4736
|
+
if (!filePath)
|
|
4737
|
+
throw new Error("filePath is required");
|
|
4738
|
+
const workspaceRoot = process.cwd();
|
|
4739
|
+
try {
|
|
4740
|
+
const result = (0, ImportTreeContext_1.buildImportTree)(filePath, workspaceRoot, depth);
|
|
4741
|
+
return { content: [{ type: "text", text: result.summary }] };
|
|
4742
|
+
}
|
|
4743
|
+
catch (e) {
|
|
4744
|
+
(0, utils_1.logError)("import_tree_context", e);
|
|
4745
|
+
return { content: [{ type: "text", text: `Import tree failed: ${e.message}` }] };
|
|
4746
|
+
}
|
|
4747
|
+
}
|
|
4748
|
+
// ── Token Budgeted Reader ─────────────────────────────────────────────
|
|
4749
|
+
async function handleReadTokenBudgeted(args) {
|
|
4750
|
+
const filePath = args.filePath;
|
|
4751
|
+
const query = args.query || '';
|
|
4752
|
+
const maxTokens = args.maxTokens || 2000;
|
|
4753
|
+
if (!filePath)
|
|
4754
|
+
throw new Error("filePath is required");
|
|
4755
|
+
const workspaceRoot = process.cwd();
|
|
4756
|
+
try {
|
|
4757
|
+
const result = (0, TokenBudgetedReader_1.readTokenBudgeted)(filePath, workspaceRoot, query, maxTokens);
|
|
4758
|
+
if (!result.truncated) {
|
|
4759
|
+
return { content: [{ type: "text", text: `FULL READ: ${result.filePath} (${result.tokensUsed} tokens)\n\n${result.content}` }] };
|
|
4760
|
+
}
|
|
4761
|
+
const sections = result.relevantSections.map(s => `L${s.start}-L${s.end} (${s.reason})`).join(', ');
|
|
4762
|
+
return { content: [{ type: "text", text: `BUDGETED READ: ${result.filePath} (${result.tokensUsed}/${result.tokensBudget} tokens, ${result.relevantSections.length} sections)\nSections: ${sections}\n\n${result.content}` }] };
|
|
4763
|
+
}
|
|
4764
|
+
catch (e) {
|
|
4765
|
+
(0, utils_1.logError)("read_token_budgeted", e);
|
|
4766
|
+
return { content: [{ type: "text", text: `Token budgeted read failed: ${e.message}` }] };
|
|
4767
|
+
}
|
|
4768
|
+
}
|
|
4769
|
+
// ── Bulk File Digest ──────────────────────────────────────────────────
|
|
4770
|
+
async function handleBulkFileDigest(args) {
|
|
4771
|
+
const filePaths = args.filePaths;
|
|
4772
|
+
const query = args.query || '';
|
|
4773
|
+
const maxTotalTokens = args.maxTotalTokens || 4000;
|
|
4774
|
+
if (!filePaths || filePaths.length === 0)
|
|
4775
|
+
throw new Error("filePaths array is required");
|
|
4776
|
+
const workspaceRoot = process.cwd();
|
|
4777
|
+
try {
|
|
4778
|
+
const result = (0, BulkFileDigest_1.bulkFileDigest)(filePaths, workspaceRoot, query, maxTotalTokens);
|
|
4779
|
+
const lines = [`# Bulk Digest: ${result.files.length} files (${result.totalTokens} tokens)\n`];
|
|
4780
|
+
for (const f of result.files) {
|
|
4781
|
+
const flag = f.truncated ? ' [TRUNCATED]' : '';
|
|
4782
|
+
lines.push(`## ${f.path} (${f.tokenCount} tokens)${flag}\n${f.summary}\n`);
|
|
4783
|
+
}
|
|
4784
|
+
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
4785
|
+
}
|
|
4786
|
+
catch (e) {
|
|
4787
|
+
(0, utils_1.logError)("bulk_file_digest", e);
|
|
4788
|
+
return { content: [{ type: "text", text: `Bulk digest failed: ${e.message}` }] };
|
|
4789
|
+
}
|
|
4790
|
+
}
|
|
4791
|
+
// ── Auto Context Bundle ───────────────────────────────────────────────
|
|
4792
|
+
async function handleAutoContextBundle(args) {
|
|
4793
|
+
const filePath = args.filePath;
|
|
4794
|
+
if (!filePath)
|
|
4795
|
+
throw new Error("filePath is required");
|
|
4796
|
+
const workspaceRoot = process.cwd();
|
|
4797
|
+
try {
|
|
4798
|
+
const result = (0, AutoContextBundle_1.autoContextBundle)(filePath, workspaceRoot);
|
|
4799
|
+
const lines = [
|
|
4800
|
+
`# Auto Context: ${result.filePath}`,
|
|
4801
|
+
`**Hash:** ${result.fingerprint} | **Tokens:** ~${result.tokenEstimate}`,
|
|
4802
|
+
"",
|
|
4803
|
+
];
|
|
4804
|
+
if (result.imports.length > 0) {
|
|
4805
|
+
const localImps = result.imports.filter(i => i.isLocal);
|
|
4806
|
+
const extImps = result.imports.filter(i => !i.isLocal);
|
|
4807
|
+
if (localImps.length > 0)
|
|
4808
|
+
lines.push(`**Local imports:** ${localImps.map(i => `${i.symbols.join(', ')} from ${i.source}`).join('; ')}`);
|
|
4809
|
+
if (extImps.length > 0)
|
|
4810
|
+
lines.push(`**External:** ${extImps.map(i => i.source.split('/')[0]).join(', ')}`);
|
|
4811
|
+
lines.push("");
|
|
4812
|
+
}
|
|
4813
|
+
if (result.importedBy.length > 0) {
|
|
4814
|
+
lines.push(`**Imported by:** ${result.importedBy.join(', ')}`);
|
|
4815
|
+
lines.push("");
|
|
4816
|
+
}
|
|
4817
|
+
if (result.schemaTypes) {
|
|
4818
|
+
lines.push(`## Types\n\`\`\`typescript\n${result.schemaTypes}\n\`\`\`\n`);
|
|
4819
|
+
}
|
|
4820
|
+
if (result.telepathicHints.length > 0) {
|
|
4821
|
+
lines.push("## Relevant Brain Memories");
|
|
4822
|
+
for (const h of result.telepathicHints) {
|
|
4823
|
+
lines.push(`- **${h.query}:** ${h.response.slice(0, 200)}`);
|
|
4824
|
+
}
|
|
4825
|
+
lines.push("");
|
|
4826
|
+
}
|
|
4827
|
+
lines.push(`## Content\n${result.content}`);
|
|
4828
|
+
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
4829
|
+
}
|
|
4830
|
+
catch (e) {
|
|
4831
|
+
(0, utils_1.logError)("auto_context_bundle", e);
|
|
4832
|
+
return { content: [{ type: "text", text: `Auto context bundle failed: ${e.message}` }] };
|
|
4833
|
+
}
|
|
4834
|
+
}
|
|
4835
|
+
// ── Repeat Guard ──────────────────────────────────────────────────────
|
|
4836
|
+
async function handleRepeatGuard(args) {
|
|
4837
|
+
const draftOutput = args.draftOutput;
|
|
4838
|
+
const threshold = args.threshold || 0.75;
|
|
4839
|
+
if (!draftOutput)
|
|
4840
|
+
throw new Error("draftOutput is required");
|
|
4841
|
+
const workspaceRoot = process.cwd();
|
|
4842
|
+
try {
|
|
4843
|
+
const result = (0, RepeatGuard_1.checkRepeat)(draftOutput, workspaceRoot, threshold);
|
|
4844
|
+
(0, RepeatGuard_1.recordOutput)(draftOutput, workspaceRoot);
|
|
4845
|
+
const icon = result.isRepeat ? '⚠️' : '✅';
|
|
4846
|
+
const lines = [
|
|
4847
|
+
`${icon} Repeat Guard`,
|
|
4848
|
+
`**Similarity:** ${Math.round(result.similarity * 100)}% | **Threshold:** ${Math.round(threshold * 100)}%`,
|
|
4849
|
+
`**Verdict:** ${result.isRepeat ? 'REPETITIVE' : 'OK'}`,
|
|
4850
|
+
`**Note:** ${result.suggestion}`,
|
|
4851
|
+
];
|
|
4852
|
+
if (result.previousOutput) {
|
|
4853
|
+
lines.push(`\n**Previous output preview:** ${result.previousOutput}`);
|
|
4854
|
+
}
|
|
4855
|
+
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
4856
|
+
}
|
|
4857
|
+
catch (e) {
|
|
4858
|
+
(0, utils_1.logError)("repeat_guard", e);
|
|
4859
|
+
return { content: [{ type: "text", text: `Repeat guard failed: ${e.message}` }] };
|
|
4860
|
+
}
|
|
4861
|
+
}
|
|
4862
|
+
// ── Conversation Checkpoint ───────────────────────────────────────────
|
|
4863
|
+
async function handleConversationCheckpoint(args) {
|
|
4864
|
+
const action = args.action || 'load';
|
|
4865
|
+
const workspaceRoot = process.cwd();
|
|
4866
|
+
try {
|
|
4867
|
+
if (action === 'load') {
|
|
4868
|
+
const cp = (0, ConversationCheckpoint_1.loadLatestCheckpoint)(workspaceRoot);
|
|
4869
|
+
if (!cp) {
|
|
4870
|
+
return { content: [{ type: "text", text: 'No checkpoint found. Starting fresh session.' }] };
|
|
4871
|
+
}
|
|
4872
|
+
const age = Math.floor((Date.now() - cp.timestamp) / 60000);
|
|
4873
|
+
const lines = [
|
|
4874
|
+
`# Session Checkpoint (${age}min ago)`,
|
|
4875
|
+
`**Summary:** ${cp.summary}`,
|
|
4876
|
+
`**Files modified:** ${cp.filesModified.length}`,
|
|
4877
|
+
`**Decisions:** ${cp.decisionsMade.length}`,
|
|
4878
|
+
`**Bugs resolved:** ${cp.bugsResolved.length}`,
|
|
4879
|
+
`**Pending tasks:** ${cp.tasksPending.length}`,
|
|
4880
|
+
`**Token estimate:** ~${cp.tokenEstimate}`,
|
|
4881
|
+
];
|
|
4882
|
+
if (cp.tasksPending.length > 0) {
|
|
4883
|
+
lines.push('\n## Pending Tasks');
|
|
4884
|
+
for (const t of cp.tasksPending)
|
|
4885
|
+
lines.push(`- ${t}`);
|
|
4886
|
+
}
|
|
4887
|
+
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
4888
|
+
}
|
|
4889
|
+
if (action === 'save') {
|
|
4890
|
+
const filesModified = args.filesModified || [];
|
|
4891
|
+
const decisionsMade = args.decisionsMade || [];
|
|
4892
|
+
const bugsResolved = args.bugsResolved || [];
|
|
4893
|
+
const tasksPending = args.tasksPending || [];
|
|
4894
|
+
const summary = (0, ConversationCheckpoint_1.buildCheckpointSummary)(filesModified, decisionsMade, bugsResolved, tasksPending);
|
|
4895
|
+
const cp = (0, ConversationCheckpoint_1.saveCheckpoint)({ projectPath: workspaceRoot, filesModified, decisionsMade, bugsResolved, tasksPending, summary }, workspaceRoot);
|
|
4896
|
+
return { content: [{ type: "text", text: `Checkpoint saved (${cp.tokenEstimate} tokens estimated).` }] };
|
|
4897
|
+
}
|
|
4898
|
+
if (action === 'summary') {
|
|
4899
|
+
const cp = (0, ConversationCheckpoint_1.loadLatestCheckpoint)(workspaceRoot);
|
|
4900
|
+
return { content: [{ type: "text", text: cp ? cp.summary : 'No checkpoint available.' }] };
|
|
4901
|
+
}
|
|
4902
|
+
return { content: [{ type: "text", text: `Unknown action: ${action}. Use 'save', 'load', or 'summary'.` }] };
|
|
4903
|
+
}
|
|
4904
|
+
catch (e) {
|
|
4905
|
+
(0, utils_1.logError)("conversation_checkpoint", e);
|
|
4906
|
+
return { content: [{ type: "text", text: `Checkpoint failed: ${e.message}` }] };
|
|
4907
|
+
}
|
|
4908
|
+
}
|
|
4909
|
+
// ── Test Autofix Interceptor ──────────────────────────────────────────
|
|
4910
|
+
async function handleTestAutofixInterceptor(args) {
|
|
4911
|
+
const command = args.command || 'npm test';
|
|
4912
|
+
const workspaceRoot = process.cwd();
|
|
4913
|
+
try {
|
|
4914
|
+
const result = (0, TestAutofixInterceptor_1.runTestAutofix)(command, workspaceRoot);
|
|
4915
|
+
const lines = [
|
|
4916
|
+
`# Test Results: ${result.passed}/${result.totalTests} passed, ${result.failed} failed`,
|
|
4917
|
+
];
|
|
4918
|
+
if (result.failures.length > 0) {
|
|
4919
|
+
lines.push(`\n## ${result.failures.length} Failure(s) (${result.autoFixAvailable} with brain fix)\n`);
|
|
4920
|
+
for (const f of result.failures) {
|
|
4921
|
+
lines.push(`### ${f.testName}${f.file ? ` (${f.file})` : ''}`);
|
|
4922
|
+
lines.push(`\`\`\`\n${f.error.slice(0, 300)}\n\`\`\``);
|
|
4923
|
+
if (f.brainHit && f.suggestedFix) {
|
|
4924
|
+
lines.push(`**Suggested fix (from Brain):** ${f.suggestedFix.slice(0, 400)}`);
|
|
4925
|
+
}
|
|
4926
|
+
else {
|
|
4927
|
+
lines.push('**Brain:** No matching fix found.');
|
|
4928
|
+
}
|
|
4929
|
+
lines.push('');
|
|
4930
|
+
}
|
|
4931
|
+
}
|
|
4932
|
+
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
4933
|
+
}
|
|
4934
|
+
catch (e) {
|
|
4935
|
+
(0, utils_1.logError)("test_autofix_interceptor", e);
|
|
4936
|
+
return { content: [{ type: "text", text: `Test autofix failed: ${e.message}` }] };
|
|
4937
|
+
}
|
|
4938
|
+
}
|
|
4939
|
+
// ── Prompt Pattern Cache ──────────────────────────────────────────────
|
|
4940
|
+
async function handlePromptPatternCache(args) {
|
|
4941
|
+
const action = args.action || 'find';
|
|
4942
|
+
const query = args.query || '';
|
|
4943
|
+
const template = args.template || '';
|
|
4944
|
+
const tokensSaved = args.tokensSaved || 0;
|
|
4945
|
+
const workspaceRoot = process.cwd();
|
|
4946
|
+
try {
|
|
4947
|
+
if (action === 'find') {
|
|
4948
|
+
if (!query)
|
|
4949
|
+
throw new Error("query is required for 'find'");
|
|
4950
|
+
const pattern = (0, PromptPatternCache_1.findPattern)(query, workspaceRoot);
|
|
4951
|
+
if (pattern) {
|
|
4952
|
+
return { content: [{ type: "text", text: `Pattern found (hit #${pattern.hitCount}):\n\n**Keywords:** ${pattern.keywords.join(', ')}\n**Template:**\n${pattern.template}\n\n**Avg tokens saved:** ${pattern.avgTokensSaved}` }] };
|
|
4953
|
+
}
|
|
4954
|
+
return { content: [{ type: "text", text: 'No matching pattern found. Consider storing one with action "store".' }] };
|
|
4955
|
+
}
|
|
4956
|
+
if (action === 'store') {
|
|
4957
|
+
if (!query || !template)
|
|
4958
|
+
throw new Error("query and template are required for 'store'");
|
|
4959
|
+
const pattern = (0, PromptPatternCache_1.storePattern)(query, template, tokensSaved, workspaceRoot);
|
|
4960
|
+
return { content: [{ type: "text", text: `Pattern stored (id: ${pattern.id}). Keywords: ${pattern.keywords.join(', ')}` }] };
|
|
4961
|
+
}
|
|
4962
|
+
if (action === 'stats') {
|
|
4963
|
+
const stats = (0, PromptPatternCache_1.getPatternStats)(workspaceRoot);
|
|
4964
|
+
const lines = [`# Prompt Pattern Cache: ${stats.totalPatterns} patterns\n`];
|
|
4965
|
+
if (stats.topPatterns.length > 0) {
|
|
4966
|
+
lines.push('## Top Patterns');
|
|
4967
|
+
for (const p of stats.topPatterns) {
|
|
4968
|
+
lines.push(`- **${p.id}**: hits=${p.hitCount}, saved=${p.avgTokensSaved}tok, kw=[${p.keywords.slice(0, 5).join(', ')}]`);
|
|
4969
|
+
}
|
|
4970
|
+
}
|
|
4971
|
+
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
4972
|
+
}
|
|
4973
|
+
return { content: [{ type: "text", text: `Unknown action: ${action}. Use 'find', 'store', or 'stats'.` }] };
|
|
4974
|
+
}
|
|
4975
|
+
catch (e) {
|
|
4976
|
+
(0, utils_1.logError)("prompt_pattern_cache", e);
|
|
4977
|
+
return { content: [{ type: "text", text: `Prompt pattern cache failed: ${e.message}` }] };
|
|
4978
|
+
}
|
|
4979
|
+
}
|
|
4483
4980
|
//# sourceMappingURL=tools.js.map
|