@nxuss/lemma 0.9.3 → 1.0.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 +35 -4
- package/bin/cli.js +97 -0
- package/bin/init.js +307 -0
- package/cache-proxy.js +191 -0
- package/dist/cjs/autopilot/AutopilotWatcher.d.ts +3 -2
- package/dist/cjs/autopilot/AutopilotWatcher.d.ts.map +1 -1
- package/dist/cjs/autopilot/AutopilotWatcher.js +48 -54
- package/dist/cjs/autopilot/AutopilotWatcher.js.map +1 -1
- package/dist/cjs/autopilot/Notifier.d.ts +5 -0
- package/dist/cjs/autopilot/Notifier.d.ts.map +1 -0
- package/dist/cjs/autopilot/Notifier.js +59 -0
- package/dist/cjs/autopilot/Notifier.js.map +1 -0
- package/dist/cjs/autopilot/PatchStore.d.ts +26 -0
- package/dist/cjs/autopilot/PatchStore.d.ts.map +1 -0
- package/dist/cjs/autopilot/PatchStore.js +88 -0
- package/dist/cjs/autopilot/PatchStore.js.map +1 -0
- package/dist/cjs/cli/lemma-proxy.d.ts.map +1 -1
- package/dist/cjs/cli/lemma-proxy.js +123 -4
- package/dist/cjs/cli/lemma-proxy.js.map +1 -1
- package/dist/cjs/mcp/index.js +1 -1
- package/dist/cjs/mcp/tools.d.ts.map +1 -1
- package/dist/cjs/mcp/tools.js +303 -77
- package/dist/cjs/mcp/tools.js.map +1 -1
- package/dist/cjs/subconscious/TheBrainV2.d.ts +102 -0
- package/dist/cjs/subconscious/TheBrainV2.d.ts.map +1 -0
- package/dist/cjs/subconscious/TheBrainV2.js +444 -0
- package/dist/cjs/subconscious/TheBrainV2.js.map +1 -0
- package/dist/cjs/utils/ContextCollapser.d.ts +21 -0
- package/dist/cjs/utils/ContextCollapser.d.ts.map +1 -0
- package/dist/cjs/utils/ContextCollapser.js +132 -0
- package/dist/cjs/utils/ContextCollapser.js.map +1 -0
- package/dist/cjs/utils/ExecutiveReport.d.ts +29 -0
- package/dist/cjs/utils/ExecutiveReport.d.ts.map +1 -0
- package/dist/cjs/utils/ExecutiveReport.js +111 -0
- package/dist/cjs/utils/ExecutiveReport.js.map +1 -0
- package/dist/cjs/utils/SurgicalASTInsert.d.ts +21 -0
- package/dist/cjs/utils/SurgicalASTInsert.d.ts.map +1 -0
- package/dist/cjs/utils/SurgicalASTInsert.js +173 -0
- package/dist/cjs/utils/SurgicalASTInsert.js.map +1 -0
- package/dist/cjs/utils/SymbolSurgicalContext.d.ts +25 -0
- package/dist/cjs/utils/SymbolSurgicalContext.d.ts.map +1 -0
- package/dist/cjs/utils/SymbolSurgicalContext.js +265 -0
- package/dist/cjs/utils/SymbolSurgicalContext.js.map +1 -0
- package/dist/cjs/utils/WormholeCompressor.d.ts +22 -0
- package/dist/cjs/utils/WormholeCompressor.d.ts.map +1 -0
- package/dist/cjs/utils/WormholeCompressor.js +152 -0
- package/dist/cjs/utils/WormholeCompressor.js.map +1 -0
- package/dist/esm/autopilot/AutopilotWatcher.d.ts +3 -2
- package/dist/esm/autopilot/AutopilotWatcher.d.ts.map +1 -1
- package/dist/esm/autopilot/AutopilotWatcher.js +48 -54
- package/dist/esm/autopilot/AutopilotWatcher.js.map +1 -1
- package/dist/esm/autopilot/Notifier.d.ts +5 -0
- package/dist/esm/autopilot/Notifier.d.ts.map +1 -0
- package/dist/esm/autopilot/Notifier.js +51 -0
- package/dist/esm/autopilot/Notifier.js.map +1 -0
- package/dist/esm/autopilot/PatchStore.d.ts +26 -0
- package/dist/esm/autopilot/PatchStore.d.ts.map +1 -0
- package/dist/esm/autopilot/PatchStore.js +77 -0
- package/dist/esm/autopilot/PatchStore.js.map +1 -0
- package/dist/esm/cli/lemma-proxy.d.ts.map +1 -1
- package/dist/esm/cli/lemma-proxy.js +123 -4
- package/dist/esm/cli/lemma-proxy.js.map +1 -1
- package/dist/esm/mcp/index.js +1 -1
- package/dist/esm/mcp/tools.d.ts.map +1 -1
- package/dist/esm/mcp/tools.js +303 -77
- package/dist/esm/mcp/tools.js.map +1 -1
- package/dist/esm/subconscious/TheBrainV2.d.ts +102 -0
- package/dist/esm/subconscious/TheBrainV2.d.ts.map +1 -0
- package/dist/esm/subconscious/TheBrainV2.js +431 -0
- package/dist/esm/subconscious/TheBrainV2.js.map +1 -0
- package/dist/esm/utils/ContextCollapser.d.ts +21 -0
- package/dist/esm/utils/ContextCollapser.d.ts.map +1 -0
- package/dist/esm/utils/ContextCollapser.js +128 -0
- package/dist/esm/utils/ContextCollapser.js.map +1 -0
- package/dist/esm/utils/ExecutiveReport.d.ts +29 -0
- package/dist/esm/utils/ExecutiveReport.d.ts.map +1 -0
- package/dist/esm/utils/ExecutiveReport.js +105 -0
- package/dist/esm/utils/ExecutiveReport.js.map +1 -0
- package/dist/esm/utils/SurgicalASTInsert.d.ts +21 -0
- package/dist/esm/utils/SurgicalASTInsert.d.ts.map +1 -0
- package/dist/esm/utils/SurgicalASTInsert.js +134 -0
- package/dist/esm/utils/SurgicalASTInsert.js.map +1 -0
- package/dist/esm/utils/SymbolSurgicalContext.d.ts +25 -0
- package/dist/esm/utils/SymbolSurgicalContext.d.ts.map +1 -0
- package/dist/esm/utils/SymbolSurgicalContext.js +226 -0
- package/dist/esm/utils/SymbolSurgicalContext.js.map +1 -0
- package/dist/esm/utils/WormholeCompressor.d.ts +22 -0
- package/dist/esm/utils/WormholeCompressor.d.ts.map +1 -0
- package/dist/esm/utils/WormholeCompressor.js +148 -0
- package/dist/esm/utils/WormholeCompressor.js.map +1 -0
- package/lemma-proxy.cjs +31 -14
- package/mcp-server.js +220 -0
- package/package.json +7 -2
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ContextCollapser — Zero-dependency extraction summarizer for technical logs & history.
|
|
3
|
+
*
|
|
4
|
+
* Replaces: Ollama for summarize_long_text and compress_context.
|
|
5
|
+
* Algorithm: Query-Focused TF-IDF Centroid sentence extraction + Jaccard dedup.
|
|
6
|
+
* Latency: <15ms for 100k characters.
|
|
7
|
+
*/
|
|
8
|
+
import { tokenize } from '../subconscious/TheBrainV2';
|
|
9
|
+
/**
|
|
10
|
+
* Split text into logical blocks (sentences or log chunks).
|
|
11
|
+
*/
|
|
12
|
+
export function splitIntoSentences(text) {
|
|
13
|
+
// Regex to split by sentence boundary (dot/exclamation/question followed by space or newline)
|
|
14
|
+
// Also preserves code lines/blocks reasonably
|
|
15
|
+
const lines = text.split(/\r?\n/);
|
|
16
|
+
const blocks = [];
|
|
17
|
+
for (const line of lines) {
|
|
18
|
+
const trimmed = line.trim();
|
|
19
|
+
if (!trimmed)
|
|
20
|
+
continue;
|
|
21
|
+
// If it's a long sentence with dots, split it
|
|
22
|
+
if (trimmed.length > 120 && trimmed.includes('. ')) {
|
|
23
|
+
const parts = trimmed.split(/(?<=[.!?])\s+/);
|
|
24
|
+
blocks.push(...parts.filter(p => p.trim().length > 0));
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
blocks.push(trimmed);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return blocks;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Jaccard similarity between two sentences.
|
|
34
|
+
*/
|
|
35
|
+
function Jaccard(setA, setB) {
|
|
36
|
+
if (setA.size === 0 && setB.size === 0)
|
|
37
|
+
return 0;
|
|
38
|
+
let inter = 0;
|
|
39
|
+
for (const item of setA) {
|
|
40
|
+
if (setB.has(item))
|
|
41
|
+
inter++;
|
|
42
|
+
}
|
|
43
|
+
return inter / (setA.size + setB.size - inter);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Summarize long text locally by selecting the most semantically dense sentences.
|
|
47
|
+
*/
|
|
48
|
+
export function collapseContext(text, options = {}) {
|
|
49
|
+
const maxLength = options.maxLength || 500;
|
|
50
|
+
const query = options.query || '';
|
|
51
|
+
if (!text || text.length <= maxLength) {
|
|
52
|
+
return text;
|
|
53
|
+
}
|
|
54
|
+
const sentences = splitIntoSentences(text);
|
|
55
|
+
if (sentences.length === 0)
|
|
56
|
+
return '';
|
|
57
|
+
// 1. Tokenize all sentences and build global vocabulary
|
|
58
|
+
const tokenizedSentences = sentences.map(s => new Set(tokenize(s)));
|
|
59
|
+
const globalFreq = {};
|
|
60
|
+
for (const tokens of tokenizedSentences) {
|
|
61
|
+
for (const token of tokens) {
|
|
62
|
+
globalFreq[token] = (globalFreq[token] || 0) + 1;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// 2. Tokenize query if present
|
|
66
|
+
const queryTokens = new Set(tokenize(query));
|
|
67
|
+
// 3. Score each sentence
|
|
68
|
+
const scoredSentences = sentences.map((sentence, index) => {
|
|
69
|
+
const tokens = tokenizedSentences[index];
|
|
70
|
+
if (tokens.size === 0)
|
|
71
|
+
return { sentence, score: 0, index, tokens };
|
|
72
|
+
let score = 0;
|
|
73
|
+
for (const token of tokens) {
|
|
74
|
+
// TF-IDF style weight: less common terms are worth more
|
|
75
|
+
const docFreq = globalFreq[token] || 1;
|
|
76
|
+
const idf = Math.log(sentences.length / docFreq + 1);
|
|
77
|
+
score += idf;
|
|
78
|
+
// Query boost
|
|
79
|
+
if (queryTokens.has(token)) {
|
|
80
|
+
score += idf * 2.5; // Boost keywords from query
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// Length normalization to avoid favoring super long sentences
|
|
84
|
+
// Sweet spot length is 40-120 chars
|
|
85
|
+
const len = sentence.length;
|
|
86
|
+
let lengthFactor = 1.0;
|
|
87
|
+
if (len < 20)
|
|
88
|
+
lengthFactor = 0.4;
|
|
89
|
+
else if (len > 150)
|
|
90
|
+
lengthFactor = 150 / len; // Penalty for overly verbose logs
|
|
91
|
+
return {
|
|
92
|
+
sentence,
|
|
93
|
+
score: score * lengthFactor,
|
|
94
|
+
index,
|
|
95
|
+
tokens
|
|
96
|
+
};
|
|
97
|
+
});
|
|
98
|
+
// 4. Sort sentences by score descending
|
|
99
|
+
const sorted = [...scoredSentences].sort((a, b) => b.score - a.score);
|
|
100
|
+
// 5. Select sentences while staying under length budget & avoiding redundant info
|
|
101
|
+
const selected = [];
|
|
102
|
+
let currentLength = 0;
|
|
103
|
+
for (const candidate of sorted) {
|
|
104
|
+
if (candidate.score <= 0)
|
|
105
|
+
continue;
|
|
106
|
+
if (currentLength + candidate.sentence.length > maxLength && selected.length >= 2) {
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
// Check redundancy (Jaccard similarity with already selected sentences)
|
|
110
|
+
let isRedundant = false;
|
|
111
|
+
for (const sel of selected) {
|
|
112
|
+
if (Jaccard(candidate.tokens, sel.tokens) > 0.45) {
|
|
113
|
+
isRedundant = true;
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
if (!isRedundant) {
|
|
118
|
+
selected.push(candidate);
|
|
119
|
+
currentLength += candidate.sentence.length + 1;
|
|
120
|
+
if (currentLength >= maxLength)
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
// 6. Re-sort selected sentences by their original chronological index to maintain flow
|
|
125
|
+
selected.sort((a, b) => a.index - b.index);
|
|
126
|
+
return selected.map(s => s.sentence).join('\n');
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=ContextCollapser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ContextCollapser.js","sourceRoot":"","sources":["../../../src/utils/ContextCollapser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ExecutiveReport — Generator for corporate ROI & productivity metrics.
|
|
3
|
+
*
|
|
4
|
+
* Compiles session and lifetime statistics from the savings ledger, estimating
|
|
5
|
+
* financial savings, developer hours reclaimed, security compliance events, and
|
|
6
|
+
* scaling projections for presenting to executive corporate sponsors.
|
|
7
|
+
*/
|
|
8
|
+
export interface ReportConfig {
|
|
9
|
+
teamSize?: number;
|
|
10
|
+
costPerDevHour?: number;
|
|
11
|
+
targetPath?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface ReportMetrics {
|
|
14
|
+
totalTokensSaved: number;
|
|
15
|
+
totalCostSaved: number;
|
|
16
|
+
devHoursSaved: number;
|
|
17
|
+
devHoursUSD: number;
|
|
18
|
+
totalBusinessValue: number;
|
|
19
|
+
securityEventsCount: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Calculates metrics and writes a highly structured Markdown corporate report.
|
|
23
|
+
*/
|
|
24
|
+
export declare function generateExecutiveReport(workspaceRoot: string, config?: ReportConfig): {
|
|
25
|
+
metrics: ReportMetrics;
|
|
26
|
+
markdown: string;
|
|
27
|
+
reportPath: string;
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=ExecutiveReport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExecutiveReport.d.ts","sourceRoot":"","sources":["../../../src/utils/ExecutiveReport.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,gBAAgB,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,mBAAmB,EAAE,MAAM,CAAC;CAC7B;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,aAAa,EAAE,MAAM,EACrB,MAAM,GAAE,YAAiB,GACxB;IAAE,OAAO,EAAE,aAAa,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CA2GlE"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ExecutiveReport — Generator for corporate ROI & productivity metrics.
|
|
3
|
+
*
|
|
4
|
+
* Compiles session and lifetime statistics from the savings ledger, estimating
|
|
5
|
+
* financial savings, developer hours reclaimed, security compliance events, and
|
|
6
|
+
* scaling projections for presenting to executive corporate sponsors.
|
|
7
|
+
*/
|
|
8
|
+
import fs from 'fs';
|
|
9
|
+
import path from 'path';
|
|
10
|
+
import { savingsLedger } from './SavingsLedger';
|
|
11
|
+
/**
|
|
12
|
+
* Calculates metrics and writes a highly structured Markdown corporate report.
|
|
13
|
+
*/
|
|
14
|
+
export function generateExecutiveReport(workspaceRoot, config = {}) {
|
|
15
|
+
const teamSize = config.teamSize || 10;
|
|
16
|
+
const costPerDevHour = config.costPerDevHour || 50;
|
|
17
|
+
const targetPath = config.targetPath || 'LEMMA_ROI_REPORT.md';
|
|
18
|
+
const reportPath = path.resolve(workspaceRoot, targetPath);
|
|
19
|
+
// 1. Gather ledger data
|
|
20
|
+
const snapshot = savingsLedger.getSnapshot();
|
|
21
|
+
// 2. Compute metrics
|
|
22
|
+
const totalTokensSaved = snapshot.total.tokensSaved;
|
|
23
|
+
const totalCostSaved = snapshot.total.costSaved;
|
|
24
|
+
// Estimate developer time saved:
|
|
25
|
+
// - 1 cache hit saves ~15 mins (0.25 hrs) of debug/reasoning.
|
|
26
|
+
// - 1 clipboard/context squeeze reduces prompt overhead & wait times, saving ~15 seconds (0.004 hrs) per event.
|
|
27
|
+
const cacheHits = snapshot.cache.events;
|
|
28
|
+
const squeezeEvents = snapshot.clipboard.events + snapshot.contextSqueeze.events + snapshot.historyPrune.events;
|
|
29
|
+
const devHoursSaved = Number((cacheHits * 0.25 + squeezeEvents * 0.004).toFixed(2));
|
|
30
|
+
const devHoursUSD = devHoursSaved * costPerDevHour;
|
|
31
|
+
const totalBusinessValue = totalCostSaved + devHoursUSD;
|
|
32
|
+
// Masked secrets count estimated from security events
|
|
33
|
+
const securityEventsCount = snapshot.clipboard.events; // Clipboard watcher scrubs automatically
|
|
34
|
+
// 3. Projections for scaling
|
|
35
|
+
const scaleTeams = [1, teamSize, teamSize * 5, teamSize * 10];
|
|
36
|
+
const projections = scaleTeams.map(size => {
|
|
37
|
+
// scale factor assuming other devs behave similarly
|
|
38
|
+
const scale = size;
|
|
39
|
+
return {
|
|
40
|
+
size,
|
|
41
|
+
monthlyTokens: Math.round(totalTokensSaved * scale * 22), // 22 working days
|
|
42
|
+
monthlyUSD: Number((totalCostSaved * scale * 22).toFixed(2)),
|
|
43
|
+
monthlyHours: Number((devHoursSaved * scale * 22).toFixed(1)),
|
|
44
|
+
monthlyROI: Number((totalBusinessValue * scale * 22).toFixed(2))
|
|
45
|
+
};
|
|
46
|
+
});
|
|
47
|
+
// 4. Build Markdown
|
|
48
|
+
const lines = [];
|
|
49
|
+
lines.push(`# 📊 Lemma Executive ROI & Cost Optimization Report`);
|
|
50
|
+
lines.push(`*Generated on: ${new Date().toLocaleDateString()} | Workspace: ${path.basename(workspaceRoot)}*`);
|
|
51
|
+
lines.push(``);
|
|
52
|
+
lines.push(`> [!IMPORTANT]`);
|
|
53
|
+
lines.push(`> **Executive Summary**: This report evaluates the direct business value, financial savings, and developer productivity hours reclaimed by implementing the **Lemma AI Gateway** in this workspace.`);
|
|
54
|
+
lines.push(``);
|
|
55
|
+
lines.push(`## 📈 Key Performance Indicators (KPIs)`);
|
|
56
|
+
lines.push(``);
|
|
57
|
+
lines.push(`| Metric | Value | Business Impact |`);
|
|
58
|
+
lines.push(`| :--- | :--- | :--- |`);
|
|
59
|
+
lines.push(`| **API Tokens Saved** | \`${totalTokensSaved.toLocaleString()}\` | Context optimization & deduplication |`);
|
|
60
|
+
lines.push(`| **Direct LLM Cost Saved** | \`$${totalCostSaved.toFixed(4)}\` | Real dollar savings on OpenAI / Anthropic billing |`);
|
|
61
|
+
lines.push(`| **Dev Time Reclaimed** | \`${devHoursSaved} Hours\` | Elimination of repetitive reasoning cycles |`);
|
|
62
|
+
lines.push(`| **Time Value Reclaimed** | \`$${devHoursUSD.toFixed(2)}\` | Productivity value based on $${costPerDevHour}/hr dev cost |`);
|
|
63
|
+
lines.push(`| **Total Business Value** | **$${totalBusinessValue.toFixed(2)}** | Combined Direct & Indirect Return on Investment |`);
|
|
64
|
+
lines.push(`| **Privacy Safeguards** | \`${securityEventsCount} Events\` | Auto-masked credentials/PII on clipboard |`);
|
|
65
|
+
lines.push(``);
|
|
66
|
+
lines.push(`## 🗜️ Savings Breakdown by Category`);
|
|
67
|
+
lines.push(``);
|
|
68
|
+
lines.push(`| Feature / Optimizer | Events | Est. Tokens Saved | Est. Cost Saved (USD) | Reclaimed Productivity |`);
|
|
69
|
+
lines.push(`| :--- | :---: | :---: | :---: | :---: |`);
|
|
70
|
+
lines.push(`| ⚡ **Semantic Cache (Brain)** | ${snapshot.cache.events} | ${snapshot.cache.tokensSaved.toLocaleString()} | $${snapshot.cache.costSaved.toFixed(4)} | ${(snapshot.cache.events * 0.25).toFixed(2)} hrs |`);
|
|
71
|
+
lines.push(`| 🗜️ **Context Squeezer & AST** | ${snapshot.contextSqueeze.events} | ${snapshot.contextSqueeze.tokensSaved.toLocaleString()} | $${snapshot.contextSqueeze.costSaved.toFixed(4)} | ${(snapshot.contextSqueeze.events * 0.004).toFixed(2)} hrs |`);
|
|
72
|
+
lines.push(`| 📜 **History Pruning (TextRank)** | ${snapshot.historyPrune.events} | ${snapshot.historyPrune.tokensSaved.toLocaleString()} | $${snapshot.historyPrune.costSaved.toFixed(4)} | ${(snapshot.historyPrune.events * 0.004).toFixed(2)} hrs |`);
|
|
73
|
+
lines.push(`| 📋 **Clipboard Compression** | ${snapshot.clipboard.events} | ${snapshot.clipboard.tokensSaved.toLocaleString()} | $${snapshot.clipboard.costSaved.toFixed(4)} | ${(snapshot.clipboard.events * 0.004).toFixed(2)} hrs |`);
|
|
74
|
+
lines.push(`| 🔀 **Complexity Routing** | ${snapshot.complexityRouting.events} | ${snapshot.complexityRouting.tokensSaved.toLocaleString()} | $${snapshot.complexityRouting.costSaved.toFixed(4)} | — |`);
|
|
75
|
+
lines.push(``);
|
|
76
|
+
lines.push(`## 🚀 Projections for Organization Scaling`);
|
|
77
|
+
lines.push(`Estimates for monthly and annual business value based on active usage across larger team scales:`);
|
|
78
|
+
lines.push(``);
|
|
79
|
+
lines.push(`| Team Size | Monthly Tokens Saved | Monthly API Savings (USD) | Monthly Dev Hours Saved | **Monthly Total Value (ROI)** |`);
|
|
80
|
+
lines.push(`| :---: | :---: | :---: | :---: | :--- |`);
|
|
81
|
+
for (const proj of projections) {
|
|
82
|
+
const boldPrefix = proj.size === teamSize ? '**' : '';
|
|
83
|
+
const boldSuffix = proj.size === teamSize ? '**' : '';
|
|
84
|
+
lines.push(`| ${boldPrefix}${proj.size} Devs${boldSuffix} | ${proj.monthlyTokens.toLocaleString()} | $${proj.monthlyUSD.toLocaleString()} | ${proj.monthlyHours} hrs | **$${proj.monthlyROI.toLocaleString()}** |`);
|
|
85
|
+
}
|
|
86
|
+
lines.push(``);
|
|
87
|
+
lines.push(`> [!TIP]`);
|
|
88
|
+
lines.push(`> **Security Compliance Note**: Lemma operates **entirely locally** using our zero-dependency AST parser and BM25 local indexing algorithms. No company code or intellectual property was transmitted to external servers for vector indexing, satisfying strict air-gapped corporate security compliance requirements.`);
|
|
89
|
+
const markdown = lines.join('\n');
|
|
90
|
+
// 5. Write to destination file
|
|
91
|
+
fs.writeFileSync(reportPath, markdown, 'utf8');
|
|
92
|
+
return {
|
|
93
|
+
metrics: {
|
|
94
|
+
totalTokensSaved,
|
|
95
|
+
totalCostSaved,
|
|
96
|
+
devHoursSaved,
|
|
97
|
+
devHoursUSD,
|
|
98
|
+
totalBusinessValue,
|
|
99
|
+
securityEventsCount
|
|
100
|
+
},
|
|
101
|
+
markdown,
|
|
102
|
+
reportPath
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=ExecutiveReport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExecutiveReport.js","sourceRoot":"","sources":["../../../src/utils/ExecutiveReport.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SurgicalASTInsert — AST-based surgical code insertion utility.
|
|
3
|
+
*
|
|
4
|
+
* Allows inserting methods, functions, or variable declarations inside a specific
|
|
5
|
+
* class, interface, or file scope, anchoring it relative to another symbol (e.g., "after method login").
|
|
6
|
+
*
|
|
7
|
+
* Prevents the LLM from outputting entire files or large search-replace blocks,
|
|
8
|
+
* reducing output token costs by up to 95%.
|
|
9
|
+
*/
|
|
10
|
+
export interface ASTInsertOptions {
|
|
11
|
+
filePath: string;
|
|
12
|
+
symbolName?: string;
|
|
13
|
+
anchorSymbol?: string;
|
|
14
|
+
insertPosition?: 'before' | 'after' | 'start' | 'end';
|
|
15
|
+
codeToInsert: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Core orchestrator for Surgical AST insertion.
|
|
19
|
+
*/
|
|
20
|
+
export declare function surgicalASTInsert(workspaceRoot: string, options: ASTInsertOptions): string;
|
|
21
|
+
//# sourceMappingURL=SurgicalASTInsert.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SurgicalASTInsert.d.ts","sourceRoot":"","sources":["../../../src/utils/SurgicalASTInsert.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAOH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,QAAQ,GAAG,OAAO,GAAG,OAAO,GAAG,KAAK,CAAC;IACtD,YAAY,EAAE,MAAM,CAAC;CACtB;AAuBD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,GAAG,MAAM,CAqG1F"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SurgicalASTInsert — AST-based surgical code insertion utility.
|
|
3
|
+
*
|
|
4
|
+
* Allows inserting methods, functions, or variable declarations inside a specific
|
|
5
|
+
* class, interface, or file scope, anchoring it relative to another symbol (e.g., "after method login").
|
|
6
|
+
*
|
|
7
|
+
* Prevents the LLM from outputting entire files or large search-replace blocks,
|
|
8
|
+
* reducing output token costs by up to 95%.
|
|
9
|
+
*/
|
|
10
|
+
import fs from 'fs';
|
|
11
|
+
import * as ts from 'typescript';
|
|
12
|
+
import { safeResolvePath } from '../mcp/utils';
|
|
13
|
+
/**
|
|
14
|
+
* Finds a class or interface node by name.
|
|
15
|
+
*/
|
|
16
|
+
function findTargetContainer(sourceFile, name) {
|
|
17
|
+
let result = null;
|
|
18
|
+
function walk(node) {
|
|
19
|
+
if (result)
|
|
20
|
+
return;
|
|
21
|
+
if (ts.isClassDeclaration(node) && node.name && node.name.text === name) {
|
|
22
|
+
result = node;
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
if (ts.isInterfaceDeclaration(node) && node.name && node.name.text === name) {
|
|
26
|
+
result = node;
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
ts.forEachChild(node, walk);
|
|
30
|
+
}
|
|
31
|
+
walk(sourceFile);
|
|
32
|
+
return result;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Core orchestrator for Surgical AST insertion.
|
|
36
|
+
*/
|
|
37
|
+
export function surgicalASTInsert(workspaceRoot, options) {
|
|
38
|
+
const { resolved } = safeResolvePath(workspaceRoot, options.filePath);
|
|
39
|
+
if (!fs.existsSync(resolved)) {
|
|
40
|
+
throw new Error(`File not found: ${options.filePath}`);
|
|
41
|
+
}
|
|
42
|
+
const src = fs.readFileSync(resolved, 'utf8');
|
|
43
|
+
const sf = ts.createSourceFile(resolved, src, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
|
|
44
|
+
const position = options.insertPosition || 'after';
|
|
45
|
+
let insertIndex = -1;
|
|
46
|
+
// Case A: Inserting inside a Class or Interface container
|
|
47
|
+
if (options.symbolName) {
|
|
48
|
+
const container = findTargetContainer(sf, options.symbolName);
|
|
49
|
+
if (!container) {
|
|
50
|
+
throw new Error(`Target container class/interface "${options.symbolName}" not found in file.`);
|
|
51
|
+
}
|
|
52
|
+
const members = container.members;
|
|
53
|
+
// Find anchor index among container members
|
|
54
|
+
let anchorIndex = -1;
|
|
55
|
+
if (options.anchorSymbol) {
|
|
56
|
+
anchorIndex = members.findIndex(m => {
|
|
57
|
+
if (ts.isMethodDeclaration(m) && m.name && ts.isIdentifier(m.name) && m.name.text === options.anchorSymbol)
|
|
58
|
+
return true;
|
|
59
|
+
if (ts.isPropertyDeclaration(m) && m.name && ts.isIdentifier(m.name) && m.name.text === options.anchorSymbol)
|
|
60
|
+
return true;
|
|
61
|
+
if (ts.isMethodSignature(m) && m.name && ts.isIdentifier(m.name) && m.name.text === options.anchorSymbol)
|
|
62
|
+
return true;
|
|
63
|
+
if (ts.isPropertySignature(m) && m.name && ts.isIdentifier(m.name) && m.name.text === options.anchorSymbol)
|
|
64
|
+
return true;
|
|
65
|
+
return false;
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
if (anchorIndex !== -1 && (position === 'after' || position === 'before')) {
|
|
69
|
+
const anchorNode = members[anchorIndex];
|
|
70
|
+
insertIndex = position === 'after' ? anchorNode.getEnd() : anchorNode.getStart();
|
|
71
|
+
}
|
|
72
|
+
else if (position === 'start' || members.length === 0) {
|
|
73
|
+
// Find open brace `{` index
|
|
74
|
+
const openBraceIndex = src.indexOf('{', container.getStart());
|
|
75
|
+
insertIndex = openBraceIndex + 1;
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
// default to end of container (right before closing brace `}`)
|
|
79
|
+
const closeBraceIndex = container.getEnd() - 1;
|
|
80
|
+
insertIndex = closeBraceIndex;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// Case B: Inserting at file/module scope
|
|
84
|
+
else {
|
|
85
|
+
let anchorNode = null;
|
|
86
|
+
if (options.anchorSymbol) {
|
|
87
|
+
// Find top-level function or variable declaration matching anchorSymbol
|
|
88
|
+
for (const statement of sf.statements) {
|
|
89
|
+
if (ts.isFunctionDeclaration(statement) && statement.name && statement.name.text === options.anchorSymbol) {
|
|
90
|
+
anchorNode = statement;
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
if (ts.isVariableStatement(statement)) {
|
|
94
|
+
for (const decl of statement.declarationList.declarations) {
|
|
95
|
+
if (ts.isIdentifier(decl.name) && decl.name.text === options.anchorSymbol) {
|
|
96
|
+
anchorNode = statement;
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (anchorNode && (position === 'after' || position === 'before')) {
|
|
104
|
+
insertIndex = position === 'after' ? anchorNode.getEnd() : anchorNode.getStart();
|
|
105
|
+
}
|
|
106
|
+
else if (position === 'start') {
|
|
107
|
+
insertIndex = 0;
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
// default: append to end of file
|
|
111
|
+
insertIndex = src.length;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (insertIndex === -1) {
|
|
115
|
+
throw new Error('Could not resolve suitable insertion index.');
|
|
116
|
+
}
|
|
117
|
+
// Formatting insert block with appropriate indentation
|
|
118
|
+
// Look at the line of insertIndex to guess base indentation
|
|
119
|
+
const linesBefore = src.substring(0, insertIndex).split('\n');
|
|
120
|
+
const lastLine = linesBefore[linesBefore.length - 1] || '';
|
|
121
|
+
const indentMatch = lastLine.match(/^\s*/);
|
|
122
|
+
const baseIndent = indentMatch ? indentMatch[0] : ' ';
|
|
123
|
+
// Apply indentation to code to insert
|
|
124
|
+
const indentedCode = options.codeToInsert
|
|
125
|
+
.split('\n')
|
|
126
|
+
.map((line, idx) => (idx === 0 ? line : baseIndent + line))
|
|
127
|
+
.join('\n');
|
|
128
|
+
// Splice string
|
|
129
|
+
const output = src.substring(0, insertIndex) + '\n' + baseIndent + indentedCode + '\n' + src.substring(insertIndex);
|
|
130
|
+
// Write file
|
|
131
|
+
fs.writeFileSync(resolved, output, 'utf8');
|
|
132
|
+
return resolved;
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=SurgicalASTInsert.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SurgicalASTInsert.js","sourceRoot":"","sources":["../../../src/utils/SurgicalASTInsert.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SymbolSurgicalContext — Surgical AST extraction tool.
|
|
3
|
+
*
|
|
4
|
+
* Scans a file for a specific symbol (class, function, variable, interface),
|
|
5
|
+
* extracts its implementation, parses its AST to find workspace dependencies,
|
|
6
|
+
* and extracts ONLY the signatures of those dependencies (not their entire files).
|
|
7
|
+
*
|
|
8
|
+
* Saves up to 90% of token context in LLM prompts.
|
|
9
|
+
*/
|
|
10
|
+
export interface SurgicalContextResult {
|
|
11
|
+
symbolName: string;
|
|
12
|
+
filePath: string;
|
|
13
|
+
implementation: string;
|
|
14
|
+
dependencies: Array<{
|
|
15
|
+
name: string;
|
|
16
|
+
filePath: string;
|
|
17
|
+
signature: string;
|
|
18
|
+
type: string;
|
|
19
|
+
}>;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Core orchestrator for Surgical Symbol Context Extraction.
|
|
23
|
+
*/
|
|
24
|
+
export declare function getSymbolSurgicalContext(workspaceRoot: string, relativeFilePath: string, symbolName: string): SurgicalContextResult;
|
|
25
|
+
//# sourceMappingURL=SymbolSurgicalContext.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SymbolSurgicalContext.d.ts","sourceRoot":"","sources":["../../../src/utils/SymbolSurgicalContext.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAOH,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,KAAK,CAAC;QAClB,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,MAAM,CAAC;QAClB,IAAI,EAAE,MAAM,CAAC;KACd,CAAC,CAAC;CACJ;AAmLD;;GAEG;AACH,wBAAgB,wBAAwB,CACtC,aAAa,EAAE,MAAM,EACrB,gBAAgB,EAAE,MAAM,EACxB,UAAU,EAAE,MAAM,GACjB,qBAAqB,CAmDvB"}
|