@nxuss/lemma 0.9.3 → 1.0.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/README.md +18 -3
- package/bin/cli.js +97 -0
- package/bin/init.js +307 -0
- package/cache-proxy.js +191 -0
- package/dist/cjs/cli/lemma-proxy.d.ts.map +1 -1
- package/dist/cjs/cli/lemma-proxy.js +2 -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 +292 -71
- 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/cli/lemma-proxy.d.ts.map +1 -1
- package/dist/esm/cli/lemma-proxy.js +2 -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 +292 -71
- 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 +5 -1
package/dist/cjs/mcp/tools.js
CHANGED
|
@@ -52,6 +52,12 @@ const utils_1 = require("./utils");
|
|
|
52
52
|
const PRReviewEngine_1 = require("../pr-review/PRReviewEngine");
|
|
53
53
|
const ReviewStore_1 = require("../pr-review/ReviewStore");
|
|
54
54
|
const reviewRunner_1 = require("../pr-review/reviewRunner");
|
|
55
|
+
const TheBrainV2_1 = require("../subconscious/TheBrainV2");
|
|
56
|
+
const ContextCollapser_1 = require("../utils/ContextCollapser");
|
|
57
|
+
const SymbolSurgicalContext_1 = require("../utils/SymbolSurgicalContext");
|
|
58
|
+
const WormholeCompressor_1 = require("../utils/WormholeCompressor");
|
|
59
|
+
const ExecutiveReport_1 = require("../utils/ExecutiveReport");
|
|
60
|
+
const SurgicalASTInsert_1 = require("../utils/SurgicalASTInsert");
|
|
55
61
|
// ── Pro License Gate ──────────────────────────────────────────────────────────
|
|
56
62
|
const LICENSE_FILE = path_1.default.join(os_1.default.homedir(), '.lemma-cache', 'license.json');
|
|
57
63
|
let _proStatusCache = null;
|
|
@@ -359,6 +365,67 @@ const toolDefinitions = [
|
|
|
359
365
|
required: ["text"],
|
|
360
366
|
},
|
|
361
367
|
},
|
|
368
|
+
{
|
|
369
|
+
name: "get_symbol_surgical_context",
|
|
370
|
+
description: "Extrae quirúrgicamente la implementación de un símbolo específico (clase, función, interfaz) y las firmas (pero no la implementación completa) de todas sus dependencias locales del workspace. Ahorra hasta 90% de tokens.",
|
|
371
|
+
inputSchema: {
|
|
372
|
+
type: "object",
|
|
373
|
+
properties: {
|
|
374
|
+
filePath: { type: "string", description: "Ruta relativa del archivo que contiene el símbolo" },
|
|
375
|
+
symbolName: { type: "string", description: "Nombre de la función, clase, tipo o interfaz a extraer" },
|
|
376
|
+
},
|
|
377
|
+
required: ["filePath", "symbolName"],
|
|
378
|
+
},
|
|
379
|
+
},
|
|
380
|
+
{
|
|
381
|
+
name: "wormhole_squeeze",
|
|
382
|
+
description: "Comprime código a formato WORMHOLE súper denso usando tokens de palabra clave y abreviación de variables reversible. Ideal para alimentar contextos de lectura al LLM.",
|
|
383
|
+
inputSchema: {
|
|
384
|
+
type: "object",
|
|
385
|
+
properties: {
|
|
386
|
+
text: { type: "string", description: "El código fuente a comprimir" },
|
|
387
|
+
},
|
|
388
|
+
required: ["text"],
|
|
389
|
+
},
|
|
390
|
+
},
|
|
391
|
+
{
|
|
392
|
+
name: "generate_executive_roi_report",
|
|
393
|
+
description: "Genera un reporte ejecutivo en formato Markdown de Retorno de Inversión (ROI), dinero ahorrado en API, horas de desarrollo recuperadas y proyecciones de escala para la gerencia.",
|
|
394
|
+
inputSchema: {
|
|
395
|
+
type: "object",
|
|
396
|
+
properties: {
|
|
397
|
+
teamSize: { type: "number", description: "Número de ingenieros en el equipo (default: 10)", default: 10 },
|
|
398
|
+
costPerDevHour: { type: "number", description: "Costo estimado en USD por hora de desarrollador (default: 50)", default: 50 },
|
|
399
|
+
targetPath: { type: "string", description: "Nombre de archivo del reporte generado (default: LEMMA_ROI_REPORT.md)", default: "LEMMA_ROI_REPORT.md" },
|
|
400
|
+
},
|
|
401
|
+
},
|
|
402
|
+
},
|
|
403
|
+
{
|
|
404
|
+
name: "surgical_ast_insert",
|
|
405
|
+
description: "Inserta quirúrgicamente código (métodos, propiedades, funciones) en una clase, interfaz o ámbito de archivo de TypeScript utilizando el AST Compiler. Evita escribir diffs de búsqueda y reemplazo grandes o reescribir todo el archivo. Ahorra 95% de tokens de salida.",
|
|
406
|
+
inputSchema: {
|
|
407
|
+
type: "object",
|
|
408
|
+
properties: {
|
|
409
|
+
filePath: { type: "string", description: "Ruta del archivo TypeScript (relativo al root)" },
|
|
410
|
+
symbolName: { type: "string", description: "Nombre de la clase o interfaz donde insertar (opcional)" },
|
|
411
|
+
anchorSymbol: { type: "string", description: "Nombre del método o propiedad como anclaje (ej. 'login')" },
|
|
412
|
+
insertPosition: { type: "string", enum: ["before", "after", "start", "end"], description: "Posición relativa al anclaje (default: 'after')", default: "after" },
|
|
413
|
+
codeToInsert: { type: "string", description: "El código fuente exacto a insertar" },
|
|
414
|
+
},
|
|
415
|
+
required: ["filePath", "codeToInsert"],
|
|
416
|
+
},
|
|
417
|
+
},
|
|
418
|
+
{
|
|
419
|
+
name: "local_semantic_autofix",
|
|
420
|
+
description: "Intenta resolver errores de compilación o ejecución localmente consultando The Brain por tracebacks/mensajes similares. Si hay coincidencia, devuelve la solución/parche instantáneamente sin gastar tokens de LLM.",
|
|
421
|
+
inputSchema: {
|
|
422
|
+
type: "object",
|
|
423
|
+
properties: {
|
|
424
|
+
errorMessage: { type: "string", description: "El traceback del error o mensaje de error a resolver" },
|
|
425
|
+
},
|
|
426
|
+
required: ["errorMessage"],
|
|
427
|
+
},
|
|
428
|
+
},
|
|
362
429
|
{
|
|
363
430
|
name: "compress_context",
|
|
364
431
|
description: "Comprime el historial de conversación: resume turns antiguos vía Ollama, mantiene solo los últimos N intactos. Reduce contexto 70-80%. USAR antes de cada turno extendido.",
|
|
@@ -587,6 +654,11 @@ const toolHandlers = {
|
|
|
587
654
|
diff_only: handleDiffOnly,
|
|
588
655
|
batch_tool_calls: handleBatchToolCalls,
|
|
589
656
|
turbosqueeze: handleTurboSqueeze,
|
|
657
|
+
get_symbol_surgical_context: handleGetSymbolSurgicalContext,
|
|
658
|
+
wormhole_squeeze: handleWormholeSqueeze,
|
|
659
|
+
generate_executive_roi_report: handleGenerateExecutiveRoiReport,
|
|
660
|
+
surgical_ast_insert: handleSurgicalAstInsert,
|
|
661
|
+
local_semantic_autofix: handleLocalSemanticAutofix,
|
|
590
662
|
compress_context: handleCompressContext,
|
|
591
663
|
smarter_cache: handleSmarterCache,
|
|
592
664
|
token_budget: handleTokenBudget,
|
|
@@ -675,22 +747,21 @@ async function handleSearchMemory(args) {
|
|
|
675
747
|
if (!query)
|
|
676
748
|
throw new Error("Query is required");
|
|
677
749
|
try {
|
|
678
|
-
const
|
|
679
|
-
const
|
|
680
|
-
const results = response.data.results || [];
|
|
750
|
+
const brain = (0, TheBrainV2_1.getBrain)();
|
|
751
|
+
const results = brain.search(query, limit);
|
|
681
752
|
if (results.length === 0) {
|
|
682
753
|
return { content: [{ type: "text", text: "No relevant memories found in Lemma's Brain." }] };
|
|
683
754
|
}
|
|
684
755
|
const formatted = results
|
|
685
756
|
.map((r, i) => {
|
|
686
|
-
return `Result ${i + 1} (Similarity: ${(r.similarity * 100).toFixed(1)}%)\nPrompt: ${r.
|
|
757
|
+
return `Result ${i + 1} (Similarity: ${(r.similarity * 100).toFixed(1)}%)\nPrompt: ${r.query.substring(0, 300)}...\nResponse: ${typeof r.response === "string" ? r.response : JSON.stringify(r.response, null, 2)}`;
|
|
687
758
|
})
|
|
688
759
|
.join("\n\n---\n\n");
|
|
689
760
|
return { content: [{ type: "text", text: `Lemma found ${results.length} memories:\n\n${formatted}` }] };
|
|
690
761
|
}
|
|
691
762
|
catch (e) {
|
|
692
763
|
(0, utils_1.logError)("search_memory", e);
|
|
693
|
-
return { content: [{ type: "text", text: `
|
|
764
|
+
return { content: [{ type: "text", text: `Local Search failed: ${e.message}` }] };
|
|
694
765
|
}
|
|
695
766
|
}
|
|
696
767
|
async function handleStoreMemory(args) {
|
|
@@ -700,12 +771,8 @@ async function handleStoreMemory(args) {
|
|
|
700
771
|
if (!query || !responseText)
|
|
701
772
|
throw new Error("Query and response are required");
|
|
702
773
|
try {
|
|
703
|
-
const
|
|
704
|
-
const
|
|
705
|
-
query,
|
|
706
|
-
response: responseText,
|
|
707
|
-
provider,
|
|
708
|
-
});
|
|
774
|
+
const brain = (0, TheBrainV2_1.getBrain)();
|
|
775
|
+
const storeRes = brain.store(query, responseText, provider);
|
|
709
776
|
const tokensSaved = Math.max(100, Math.floor(responseText.length / 4));
|
|
710
777
|
(0, reportSavings_1.reportSavings)({
|
|
711
778
|
source: "cache",
|
|
@@ -713,11 +780,11 @@ async function handleStoreMemory(args) {
|
|
|
713
780
|
toolName: "store_memory",
|
|
714
781
|
query: query.substring(0, 100),
|
|
715
782
|
});
|
|
716
|
-
return { content: [{ type: "text", text: `Success: ${
|
|
783
|
+
return { content: [{ type: "text", text: `Success: Memory stored. ${storeRes.reason}` }] };
|
|
717
784
|
}
|
|
718
785
|
catch (e) {
|
|
719
786
|
(0, utils_1.logError)("store_memory", e);
|
|
720
|
-
return { content: [{ type: "text", text: `Failed to store memory in
|
|
787
|
+
return { content: [{ type: "text", text: `Failed to store memory in local Brain: ${e.message}` }] };
|
|
721
788
|
}
|
|
722
789
|
}
|
|
723
790
|
async function handleGetRoutingAdvice(args) {
|
|
@@ -1285,24 +1352,20 @@ async function handleQueryHybridConsensus(args) {
|
|
|
1285
1352
|
const threshold = typeof args?.threshold === "number" ? args.threshold : 0.8;
|
|
1286
1353
|
if (!query)
|
|
1287
1354
|
throw new Error("query is required");
|
|
1288
|
-
const port = (0, utils_1.getProxyPort)();
|
|
1289
1355
|
const fullQuery = context ? `${query}\n\nContext: ${context}` : query;
|
|
1290
1356
|
try {
|
|
1291
|
-
const
|
|
1292
|
-
const results =
|
|
1357
|
+
const brain = (0, TheBrainV2_1.getBrain)();
|
|
1358
|
+
const results = brain.search(fullQuery, 3);
|
|
1293
1359
|
const topHit = results[0];
|
|
1294
1360
|
if (topHit && topHit.similarity >= threshold) {
|
|
1295
|
-
const savedTokens = Math.floor((topHit.response?.
|
|
1361
|
+
const savedTokens = Math.floor((topHit.response?.length || 500) / 4);
|
|
1296
1362
|
(0, reportSavings_1.reportSavings)({
|
|
1297
1363
|
source: "cache",
|
|
1298
1364
|
tokens: savedTokens,
|
|
1299
1365
|
toolName: "query_hybrid_consensus",
|
|
1300
1366
|
query: query.substring(0, 100),
|
|
1301
1367
|
});
|
|
1302
|
-
const responseText =
|
|
1303
|
-
? topHit.response
|
|
1304
|
-
: topHit.response?.choices?.[0]?.message?.content ||
|
|
1305
|
-
JSON.stringify(topHit.response, null, 2);
|
|
1368
|
+
const responseText = topHit.response;
|
|
1306
1369
|
return {
|
|
1307
1370
|
content: [
|
|
1308
1371
|
{
|
|
@@ -1328,7 +1391,7 @@ async function handleQueryHybridConsensus(args) {
|
|
|
1328
1391
|
(0, utils_1.logError)("query_hybrid_consensus", e);
|
|
1329
1392
|
return {
|
|
1330
1393
|
content: [
|
|
1331
|
-
{ type: "text", text: `Hybrid Consensus failed: ${e.message}
|
|
1394
|
+
{ type: "text", text: `Hybrid Consensus failed: ${e.message}` },
|
|
1332
1395
|
],
|
|
1333
1396
|
};
|
|
1334
1397
|
}
|
|
@@ -1339,7 +1402,6 @@ async function handleGetTelepathicHints(args) {
|
|
|
1339
1402
|
const limit = typeof args?.limit === "number" ? args.limit : 5;
|
|
1340
1403
|
if (!activeFile)
|
|
1341
1404
|
throw new Error("activeFile is required");
|
|
1342
|
-
const port = (0, utils_1.getProxyPort)();
|
|
1343
1405
|
const basename = path_1.default.basename(activeFile, path_1.default.extname(activeFile));
|
|
1344
1406
|
const dirContext = path_1.default
|
|
1345
1407
|
.dirname(activeFile)
|
|
@@ -1350,8 +1412,8 @@ async function handleGetTelepathicHints(args) {
|
|
|
1350
1412
|
const ext = path_1.default.extname(activeFile).replace(".", "");
|
|
1351
1413
|
const telepathicQuery = `${basename} ${dirContext} ${ext} patterns solutions architecture`;
|
|
1352
1414
|
try {
|
|
1353
|
-
const
|
|
1354
|
-
const results =
|
|
1415
|
+
const brain = (0, TheBrainV2_1.getBrain)();
|
|
1416
|
+
const results = brain.search(telepathicQuery, limit);
|
|
1355
1417
|
if (results.length === 0) {
|
|
1356
1418
|
return {
|
|
1357
1419
|
content: [
|
|
@@ -1365,11 +1427,8 @@ async function handleGetTelepathicHints(args) {
|
|
|
1365
1427
|
let hintsText = `Telepathic Hints for \`${activeFile}\`\n*(${results.length} relevant memories surfaced from The Brain)*\n\n`;
|
|
1366
1428
|
results.forEach((r, i) => {
|
|
1367
1429
|
const similarity = (r.similarity * 100).toFixed(1);
|
|
1368
|
-
const prompt =
|
|
1369
|
-
const responseContent =
|
|
1370
|
-
? r.response
|
|
1371
|
-
: r.response?.choices?.[0]?.message?.content ||
|
|
1372
|
-
JSON.stringify(r.response).substring(0, 300);
|
|
1430
|
+
const prompt = r.query || "Unknown";
|
|
1431
|
+
const responseContent = r.response || "";
|
|
1373
1432
|
hintsText += `### Hint ${i + 1} (${similarity}% match)\n`;
|
|
1374
1433
|
hintsText += `**Memory:** ${prompt}\n\n`;
|
|
1375
1434
|
hintsText += `${responseContent.substring(0, 400)}${responseContent.length > 400 ? "..." : ""}\n\n---\n\n`;
|
|
@@ -1389,7 +1448,7 @@ async function handleGetTelepathicHints(args) {
|
|
|
1389
1448
|
content: [
|
|
1390
1449
|
{
|
|
1391
1450
|
type: "text",
|
|
1392
|
-
text: `Telepathic Hints failed: ${e.message}
|
|
1451
|
+
text: `Telepathic Hints failed: ${e.message}`,
|
|
1393
1452
|
},
|
|
1394
1453
|
],
|
|
1395
1454
|
};
|
|
@@ -1401,17 +1460,8 @@ async function handleSummarizeLongText(args) {
|
|
|
1401
1460
|
const maxLength = args?.maxLength || 500;
|
|
1402
1461
|
if (!text)
|
|
1403
1462
|
throw new Error("text is required");
|
|
1404
|
-
const host = process.env.OLLAMA_HOST || 'http://localhost:11434';
|
|
1405
|
-
const model = process.env.OLLAMA_GEN_MODEL || 'llama3';
|
|
1406
1463
|
try {
|
|
1407
|
-
const
|
|
1408
|
-
const resp = await axios_1.default.post(`${host}/api/generate`, {
|
|
1409
|
-
model,
|
|
1410
|
-
prompt,
|
|
1411
|
-
stream: false,
|
|
1412
|
-
options: { temperature: 0.1, num_predict: maxLength * 2 },
|
|
1413
|
-
});
|
|
1414
|
-
const summary = resp.data.response.trim();
|
|
1464
|
+
const summary = (0, ContextCollapser_1.collapseContext)(text, { maxLength });
|
|
1415
1465
|
(0, reportSavings_1.reportSavings)({
|
|
1416
1466
|
source: "contextSqueeze",
|
|
1417
1467
|
charsBefore: text.length,
|
|
@@ -1422,7 +1472,7 @@ async function handleSummarizeLongText(args) {
|
|
|
1422
1472
|
}
|
|
1423
1473
|
catch (e) {
|
|
1424
1474
|
(0, utils_1.logError)("summarize_long_text", e);
|
|
1425
|
-
return { content: [{ type: "text", text: `Summarization failed: ${e.message}
|
|
1475
|
+
return { content: [{ type: "text", text: `Summarization failed: ${e.message}` }] };
|
|
1426
1476
|
}
|
|
1427
1477
|
}
|
|
1428
1478
|
// ── Prune Conversation History ──────────────────────────────────────
|
|
@@ -1571,21 +1621,14 @@ async function handleCompressContext(args) {
|
|
|
1571
1621
|
const recent = messages.slice(-keepRecent);
|
|
1572
1622
|
const old = messages.slice(0, -keepRecent);
|
|
1573
1623
|
let summary = "";
|
|
1574
|
-
let summaryMethod = "
|
|
1624
|
+
let summaryMethod = "local-collapser";
|
|
1575
1625
|
try {
|
|
1576
|
-
const
|
|
1577
|
-
|
|
1578
|
-
const summaryPrompt = `Summarize the following conversation history into 2-3 concise sentences. Capture ONLY: key decisions made, code patterns established, unresolved issues. Be extremely brief.\n\n${JSON.stringify(old.map((m) => ({ role: m.role, content: typeof m.content === 'string' ? m.content.substring(0, 400) : '...' })))}`;
|
|
1579
|
-
const resp = await axios_1.default.post(`${host}/api/generate`, {
|
|
1580
|
-
model, prompt: summaryPrompt, stream: false,
|
|
1581
|
-
options: { temperature: 0.1, num_predict: 300 },
|
|
1582
|
-
});
|
|
1583
|
-
summary = resp.data.response.trim();
|
|
1584
|
-
summaryMethod = "ollama";
|
|
1626
|
+
const oldText = old.map((m, i) => `[Turn ${i + 1} / ${m.role}]: ${typeof m.content === 'string' ? m.content : '...'}`).join('\n');
|
|
1627
|
+
summary = (0, ContextCollapser_1.collapseContext)(oldText, { maxLength: 800 });
|
|
1585
1628
|
}
|
|
1586
|
-
catch {
|
|
1629
|
+
catch (err) {
|
|
1587
1630
|
summary = old.map((m, i) => `[Turn ${i + 1} / ${m.role}]: ${typeof m.content === 'string' ? m.content.substring(0, 150).replace(/\n/g, ' ') : '...'}`).join('\n').substring(0, 2000);
|
|
1588
|
-
summaryMethod = "truncate";
|
|
1631
|
+
summaryMethod = "truncate-fallback";
|
|
1589
1632
|
}
|
|
1590
1633
|
const oldLength = JSON.stringify(old).length;
|
|
1591
1634
|
const summaryLength = summary.length;
|
|
@@ -1613,16 +1656,13 @@ async function handleSmarterCache(args) {
|
|
|
1613
1656
|
const threshold = typeof args?.threshold === "number" ? args.threshold : 0.75;
|
|
1614
1657
|
if (!query)
|
|
1615
1658
|
throw new Error("query is required");
|
|
1616
|
-
const port = (0, utils_1.getProxyPort)();
|
|
1617
1659
|
const fullQuery = context ? `${query}\n\nContext: ${context}` : query;
|
|
1618
1660
|
try {
|
|
1619
|
-
const
|
|
1620
|
-
const results =
|
|
1661
|
+
const brain = (0, TheBrainV2_1.getBrain)();
|
|
1662
|
+
const results = brain.search(fullQuery, 5);
|
|
1621
1663
|
const topHit = results[0];
|
|
1622
1664
|
if (topHit && topHit.similarity >= threshold) {
|
|
1623
|
-
const responseText =
|
|
1624
|
-
? topHit.response
|
|
1625
|
-
: topHit.response?.choices?.[0]?.message?.content || JSON.stringify(topHit.response, null, 2);
|
|
1665
|
+
const responseText = topHit.response;
|
|
1626
1666
|
const tokensSaved = Math.floor(responseText.length / 4);
|
|
1627
1667
|
try {
|
|
1628
1668
|
const { reportSavings } = await Promise.resolve().then(() => __importStar(require("../utils/reportSavings")));
|
|
@@ -1667,7 +1707,7 @@ async function handleSmarterCache(args) {
|
|
|
1667
1707
|
hit: false,
|
|
1668
1708
|
error: e.message,
|
|
1669
1709
|
source: "cache-unavailable",
|
|
1670
|
-
hint: "
|
|
1710
|
+
hint: "El cache local del brain falló. El LLM funcionará normalmente sin cache.",
|
|
1671
1711
|
}, null, 2),
|
|
1672
1712
|
}],
|
|
1673
1713
|
};
|
|
@@ -2320,10 +2360,9 @@ async function handleSemanticDedupGuard(args) {
|
|
|
2320
2360
|
const threshold = typeof args?.threshold === "number" ? args.threshold : 0.92;
|
|
2321
2361
|
if (!query || !response)
|
|
2322
2362
|
throw new Error("query and response are required");
|
|
2323
|
-
const port = (0, utils_1.getProxyPort)();
|
|
2324
2363
|
try {
|
|
2325
|
-
const
|
|
2326
|
-
const results =
|
|
2364
|
+
const brain = (0, TheBrainV2_1.getBrain)();
|
|
2365
|
+
const results = brain.search(query, 3);
|
|
2327
2366
|
const topHit = results[0];
|
|
2328
2367
|
if (!topHit) {
|
|
2329
2368
|
return {
|
|
@@ -2334,17 +2373,18 @@ async function handleSemanticDedupGuard(args) {
|
|
|
2334
2373
|
}, null, 2) }],
|
|
2335
2374
|
};
|
|
2336
2375
|
}
|
|
2337
|
-
|
|
2376
|
+
let sim = topHit.similarity || 0;
|
|
2377
|
+
if (topHit.query.trim().toLowerCase() === query.trim().toLowerCase()) {
|
|
2378
|
+
sim = 1.0;
|
|
2379
|
+
}
|
|
2338
2380
|
if (sim >= threshold) {
|
|
2339
2381
|
return {
|
|
2340
2382
|
content: [{ type: "text", text: JSON.stringify({
|
|
2341
2383
|
verdict: "DUPLICATE_REJECTED",
|
|
2342
2384
|
reason: `Duplicado exacto detectado (${(sim * 100).toFixed(1)}% ≥ ${(threshold * 100).toFixed(0)}%). NO hagas store_memory — ya existe.`,
|
|
2343
2385
|
similarity: sim,
|
|
2344
|
-
existingQuery: typeof topHit.
|
|
2345
|
-
existingResponse: (
|
|
2346
|
-
? topHit.response
|
|
2347
|
-
: topHit.response?.choices?.[0]?.message?.content || "").substring(0, 300),
|
|
2386
|
+
existingQuery: typeof topHit.query === "string" ? topHit.query.substring(0, 200) : "N/A",
|
|
2387
|
+
existingResponse: (topHit.response || "").substring(0, 300),
|
|
2348
2388
|
tokensSaved: Math.floor(response.length / 4),
|
|
2349
2389
|
}, null, 2) }],
|
|
2350
2390
|
};
|
|
@@ -2355,7 +2395,7 @@ async function handleSemanticDedupGuard(args) {
|
|
|
2355
2395
|
verdict: "SIMILAR_WARNING",
|
|
2356
2396
|
reason: `Contenido similar detectado (${(sim * 100).toFixed(1)}%). Decide si es distinto suficiente para guardar.`,
|
|
2357
2397
|
similarity: sim,
|
|
2358
|
-
existingQuery: typeof topHit.
|
|
2398
|
+
existingQuery: typeof topHit.query === "string" ? topHit.query.substring(0, 200) : "N/A",
|
|
2359
2399
|
recommendation: "Si aporta info nueva → procede con store_memory. Si es redundante → descarta.",
|
|
2360
2400
|
}, null, 2) }],
|
|
2361
2401
|
};
|
|
@@ -2373,7 +2413,7 @@ async function handleSemanticDedupGuard(args) {
|
|
|
2373
2413
|
return {
|
|
2374
2414
|
content: [{ type: "text", text: JSON.stringify({
|
|
2375
2415
|
verdict: "STORE_ALLOWED",
|
|
2376
|
-
reason: "
|
|
2416
|
+
reason: "El cache local del brain falló. Procediendo con store.",
|
|
2377
2417
|
error: e.message,
|
|
2378
2418
|
}, null, 2) }],
|
|
2379
2419
|
};
|
|
@@ -3279,4 +3319,185 @@ async function handleRefactor(args) {
|
|
|
3279
3319
|
return { content: [{ type: "text", text: `refactor failed: ${err.message}` }] };
|
|
3280
3320
|
}
|
|
3281
3321
|
}
|
|
3322
|
+
// ── Surgical Symbol Context ──────────────────────────────────────────
|
|
3323
|
+
async function handleGetSymbolSurgicalContext(args) {
|
|
3324
|
+
const filePath = args?.filePath;
|
|
3325
|
+
const symbolName = args?.symbolName;
|
|
3326
|
+
if (!filePath || !symbolName)
|
|
3327
|
+
throw new Error("filePath and symbolName are required");
|
|
3328
|
+
const workspaceRoot = process.cwd();
|
|
3329
|
+
try {
|
|
3330
|
+
const res = (0, SymbolSurgicalContext_1.getSymbolSurgicalContext)(workspaceRoot, filePath, symbolName);
|
|
3331
|
+
const lines = [];
|
|
3332
|
+
lines.push(`# 🧬 Surgical Context: Symbol \`${symbolName}\` in \`${filePath}\``);
|
|
3333
|
+
lines.push(`## Implementation`);
|
|
3334
|
+
lines.push(`\`\`\`typescript\n${res.implementation}\n\`\`\``);
|
|
3335
|
+
if (res.dependencies.length > 0) {
|
|
3336
|
+
lines.push(`## Workspace Dependencies (Signatures ONLY)`);
|
|
3337
|
+
for (const dep of res.dependencies) {
|
|
3338
|
+
lines.push(`### \`${dep.name}\` (${dep.type}) declared in \`${dep.filePath}\``);
|
|
3339
|
+
lines.push(`\`\`\`typescript\n${dep.signature}\n\`\`\``);
|
|
3340
|
+
}
|
|
3341
|
+
}
|
|
3342
|
+
else {
|
|
3343
|
+
lines.push(`*No local workspace dependencies detected for this symbol.*`);
|
|
3344
|
+
}
|
|
3345
|
+
const output = lines.join("\n\n");
|
|
3346
|
+
const originalSize = fs_1.default.readFileSync(path_1.default.resolve(workspaceRoot, filePath), "utf8").length;
|
|
3347
|
+
const totalRawSize = originalSize + res.dependencies.reduce((sum, dep) => {
|
|
3348
|
+
try {
|
|
3349
|
+
return sum + fs_1.default.readFileSync(path_1.default.resolve(workspaceRoot, dep.filePath), "utf8").length;
|
|
3350
|
+
}
|
|
3351
|
+
catch {
|
|
3352
|
+
return sum;
|
|
3353
|
+
}
|
|
3354
|
+
}, 0);
|
|
3355
|
+
(0, reportSavings_1.reportSavings)({
|
|
3356
|
+
source: "contextSqueeze",
|
|
3357
|
+
charsBefore: totalRawSize,
|
|
3358
|
+
charsAfter: output.length,
|
|
3359
|
+
toolName: "get_symbol_surgical_context",
|
|
3360
|
+
filePath
|
|
3361
|
+
});
|
|
3362
|
+
return {
|
|
3363
|
+
content: [{ type: "text", text: output }]
|
|
3364
|
+
};
|
|
3365
|
+
}
|
|
3366
|
+
catch (err) {
|
|
3367
|
+
(0, utils_1.logError)("get_symbol_surgical_context", err);
|
|
3368
|
+
return {
|
|
3369
|
+
content: [{ type: "text", text: `Surgical context extraction failed: ${err.message}` }]
|
|
3370
|
+
};
|
|
3371
|
+
}
|
|
3372
|
+
}
|
|
3373
|
+
// ── Wormhole Squeeze ────────────────────────────────────────────────
|
|
3374
|
+
async function handleWormholeSqueeze(args) {
|
|
3375
|
+
const text = args?.text;
|
|
3376
|
+
if (!text)
|
|
3377
|
+
throw new Error("text is required");
|
|
3378
|
+
try {
|
|
3379
|
+
const compressed = (0, WormholeCompressor_1.compressWormhole)(text);
|
|
3380
|
+
(0, reportSavings_1.reportSavings)({
|
|
3381
|
+
source: "contextSqueeze",
|
|
3382
|
+
charsBefore: text.length,
|
|
3383
|
+
charsAfter: compressed.length,
|
|
3384
|
+
toolName: "wormhole_squeeze"
|
|
3385
|
+
});
|
|
3386
|
+
return {
|
|
3387
|
+
content: [{ type: "text", text: compressed }]
|
|
3388
|
+
};
|
|
3389
|
+
}
|
|
3390
|
+
catch (err) {
|
|
3391
|
+
(0, utils_1.logError)("wormhole_squeeze", err);
|
|
3392
|
+
return {
|
|
3393
|
+
content: [{ type: "text", text: `Wormhole compression failed: ${err.message}` }]
|
|
3394
|
+
};
|
|
3395
|
+
}
|
|
3396
|
+
}
|
|
3397
|
+
// ── Executive ROI Report ──────────────────────────────────────────────
|
|
3398
|
+
async function handleGenerateExecutiveRoiReport(args) {
|
|
3399
|
+
const teamSize = typeof args?.teamSize === "number" ? args.teamSize : 10;
|
|
3400
|
+
const costPerDevHour = typeof args?.costPerDevHour === "number" ? args.costPerDevHour : 50;
|
|
3401
|
+
const targetPath = args?.targetPath || "LEMMA_ROI_REPORT.md";
|
|
3402
|
+
const workspaceRoot = process.cwd();
|
|
3403
|
+
try {
|
|
3404
|
+
const res = (0, ExecutiveReport_1.generateExecutiveReport)(workspaceRoot, {
|
|
3405
|
+
teamSize,
|
|
3406
|
+
costPerDevHour,
|
|
3407
|
+
targetPath
|
|
3408
|
+
});
|
|
3409
|
+
return {
|
|
3410
|
+
content: [{
|
|
3411
|
+
type: "text",
|
|
3412
|
+
text: `Success: ROI Report generated at ${targetPath}.\n\nTotal Business Value Saved: $${res.metrics.totalBusinessValue.toFixed(2)} USD\nEstimated Dev Time Saved: ${res.metrics.devHoursSaved} Hours\nDirect API Cost Saved: $${res.metrics.totalCostSaved.toFixed(4)} USD`
|
|
3413
|
+
}]
|
|
3414
|
+
};
|
|
3415
|
+
}
|
|
3416
|
+
catch (err) {
|
|
3417
|
+
(0, utils_1.logError)("generate_executive_roi_report", err);
|
|
3418
|
+
return {
|
|
3419
|
+
content: [{ type: "text", text: `ROI Report generation failed: ${err.message}` }]
|
|
3420
|
+
};
|
|
3421
|
+
}
|
|
3422
|
+
}
|
|
3423
|
+
// ── Surgical AST Insert ──────────────────────────────────────────────
|
|
3424
|
+
async function handleSurgicalAstInsert(args) {
|
|
3425
|
+
const filePath = args?.filePath;
|
|
3426
|
+
const symbolName = args?.symbolName;
|
|
3427
|
+
const anchorSymbol = args?.anchorSymbol;
|
|
3428
|
+
const insertPosition = args?.insertPosition;
|
|
3429
|
+
const codeToInsert = args?.codeToInsert;
|
|
3430
|
+
if (!filePath || !codeToInsert)
|
|
3431
|
+
throw new Error("filePath and codeToInsert are required");
|
|
3432
|
+
const workspaceRoot = process.cwd();
|
|
3433
|
+
try {
|
|
3434
|
+
const resolvedPath = (0, SurgicalASTInsert_1.surgicalASTInsert)(workspaceRoot, {
|
|
3435
|
+
filePath,
|
|
3436
|
+
symbolName,
|
|
3437
|
+
anchorSymbol,
|
|
3438
|
+
insertPosition,
|
|
3439
|
+
codeToInsert
|
|
3440
|
+
});
|
|
3441
|
+
const newTextSize = fs_1.default.readFileSync(resolvedPath, "utf8").length;
|
|
3442
|
+
const outputCharsSaved = Math.max(0, newTextSize - codeToInsert.length);
|
|
3443
|
+
const tokensSaved = Math.floor(outputCharsSaved / 4);
|
|
3444
|
+
(0, reportSavings_1.reportSavings)({
|
|
3445
|
+
source: "contextSqueeze",
|
|
3446
|
+
tokens: tokensSaved,
|
|
3447
|
+
toolName: "surgical_ast_insert",
|
|
3448
|
+
filePath
|
|
3449
|
+
});
|
|
3450
|
+
return {
|
|
3451
|
+
content: [{
|
|
3452
|
+
type: "text",
|
|
3453
|
+
text: `Success: Surgically inserted code into ${filePath} using AST compiler.`
|
|
3454
|
+
}]
|
|
3455
|
+
};
|
|
3456
|
+
}
|
|
3457
|
+
catch (err) {
|
|
3458
|
+
(0, utils_1.logError)("surgical_ast_insert", err);
|
|
3459
|
+
return {
|
|
3460
|
+
content: [{ type: "text", text: `Surgical AST insertion failed: ${err.message}` }]
|
|
3461
|
+
};
|
|
3462
|
+
}
|
|
3463
|
+
}
|
|
3464
|
+
// ── Local Semantic Autofix ────────────────────────────────────────────
|
|
3465
|
+
async function handleLocalSemanticAutofix(args) {
|
|
3466
|
+
const errorMessage = args?.errorMessage;
|
|
3467
|
+
if (!errorMessage)
|
|
3468
|
+
throw new Error("errorMessage is required");
|
|
3469
|
+
try {
|
|
3470
|
+
const brain = (0, TheBrainV2_1.getBrain)();
|
|
3471
|
+
const results = brain.search(errorMessage, 3, 0.70);
|
|
3472
|
+
const topHit = results[0];
|
|
3473
|
+
if (topHit) {
|
|
3474
|
+
const responseText = topHit.response;
|
|
3475
|
+
const tokensSaved = Math.max(100, Math.floor(responseText.length / 4));
|
|
3476
|
+
(0, reportSavings_1.reportSavings)({
|
|
3477
|
+
source: "cache",
|
|
3478
|
+
tokens: tokensSaved,
|
|
3479
|
+
toolName: "local_semantic_autofix",
|
|
3480
|
+
query: errorMessage.substring(0, 100)
|
|
3481
|
+
});
|
|
3482
|
+
return {
|
|
3483
|
+
content: [{
|
|
3484
|
+
type: "text",
|
|
3485
|
+
text: `🎯 Local Auto-Fix HIT (similarity: ${(topHit.similarity * 100).toFixed(1)}%)\n\nFound matching resolution in global memory. Cost: 0 tokens.\n\n---\n\n${responseText}`
|
|
3486
|
+
}]
|
|
3487
|
+
};
|
|
3488
|
+
}
|
|
3489
|
+
return {
|
|
3490
|
+
content: [{
|
|
3491
|
+
type: "text",
|
|
3492
|
+
text: `Brain MISS (No matching resolutions for this error in local memory).\n\nPlease proceed to ask the LLM for guidance. Once resolved, make sure to call store_memory with:\n- query: "[Error description/traceback]"\n- response: "[Exact code patch or steps used to fix]"\n\nThis will allow resolving this error instantly with 0 tokens next time!`
|
|
3493
|
+
}]
|
|
3494
|
+
};
|
|
3495
|
+
}
|
|
3496
|
+
catch (err) {
|
|
3497
|
+
(0, utils_1.logError)("local_semantic_autofix", err);
|
|
3498
|
+
return {
|
|
3499
|
+
content: [{ type: "text", text: `Local auto-fix failed: ${err.message}` }]
|
|
3500
|
+
};
|
|
3501
|
+
}
|
|
3502
|
+
}
|
|
3282
3503
|
//# sourceMappingURL=tools.js.map
|