make-laten 1.1.0 → 1.2.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 +198 -51
- package/dist/cli/index.js +376 -175
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/index.mjs +376 -175
- package/dist/cli/index.mjs.map +1 -1
- package/dist/index.js +288 -68
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +274 -67
- package/dist/index.mjs.map +1 -1
- package/dist/mcp/server.js +250 -68
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/server.mjs +250 -68
- package/dist/mcp/server.mjs.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -58,29 +58,145 @@ function isKnownPattern(content) {
|
|
|
58
58
|
return patterns.some((p) => p.test(content));
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
// src/compress/strip.ts
|
|
62
|
+
function stripImports(content) {
|
|
63
|
+
return content.replace(/^import\s+[\s\S]*?from\s+['"][^'"]+['"]\s*;?\s*$/gm, "").replace(/^import\s+['"][^'"]+['"]\s*;?\s*$/gm, "").replace(/^import\s+\{[^}]*\}\s+from\s+['"][^'"]+['"]\s*;?\s*$/gm, "").split("\n").filter((l) => l.trim() !== "").join("\n");
|
|
64
|
+
}
|
|
65
|
+
function stripComments(content) {
|
|
66
|
+
let result = content.replace(/(?<!["'`])\/\/.*$/gm, "");
|
|
67
|
+
result = result.replace(/\/\*[\s\S]*?\*\//g, "");
|
|
68
|
+
return result.split("\n").filter((l) => l.trim() !== "").join("\n");
|
|
69
|
+
}
|
|
70
|
+
function stripBlankLines(content) {
|
|
71
|
+
return content.replace(/\n{3,}/g, "\n\n");
|
|
72
|
+
}
|
|
73
|
+
function stripWhitespace(content) {
|
|
74
|
+
return content.replace(/[ \t]+$/gm, "");
|
|
75
|
+
}
|
|
76
|
+
function stripAll(content) {
|
|
77
|
+
let result = content;
|
|
78
|
+
result = stripImports(result);
|
|
79
|
+
result = stripComments(result);
|
|
80
|
+
result = stripBlankLines(result);
|
|
81
|
+
result = stripWhitespace(result);
|
|
82
|
+
return result.trim();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// src/compress/structure.ts
|
|
86
|
+
function extractExports(content) {
|
|
87
|
+
const lines = content.split("\n");
|
|
88
|
+
const exports2 = [];
|
|
89
|
+
for (const line of lines) {
|
|
90
|
+
const trimmed = line.trim();
|
|
91
|
+
if (/^export\s+(default\s+)?/.test(trimmed)) {
|
|
92
|
+
if (trimmed.includes("{") && !trimmed.includes("}")) {
|
|
93
|
+
exports2.push(trimmed.replace(/\{[\s\S]*$/, "{ ... }"));
|
|
94
|
+
} else {
|
|
95
|
+
exports2.push(trimmed);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return exports2.join("\n");
|
|
100
|
+
}
|
|
101
|
+
function extractClassMethods(content) {
|
|
102
|
+
const classRegex = /class\s+\w+[^{]*\{([\s\S]*?)\n\}/g;
|
|
103
|
+
const methods = [];
|
|
104
|
+
let match;
|
|
105
|
+
while ((match = classRegex.exec(content)) !== null) {
|
|
106
|
+
const classBody = match[1];
|
|
107
|
+
const methodRegex = /(^\s*(?:public|private|protected|static|async|abstract|\s)*\w+\s*\([^)]*\)(?:\s*:\s*[^{]+)?)\s*\{/gm;
|
|
108
|
+
let methodMatch;
|
|
109
|
+
while ((methodMatch = methodRegex.exec(classBody)) !== null) {
|
|
110
|
+
methods.push(methodMatch[1].trim());
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return methods.join("\n");
|
|
114
|
+
}
|
|
115
|
+
function extractFunctionSignatures(content) {
|
|
116
|
+
const funcRegex = /(export\s+)?(async\s+)?function\s+\w+\s*\([^)]*\)(?:\s*:\s*[^{]+)?\s*\{/g;
|
|
117
|
+
const signatures = [];
|
|
118
|
+
let match;
|
|
119
|
+
while ((match = funcRegex.exec(content)) !== null) {
|
|
120
|
+
signatures.push(match[0].replace(/\{$/, ""));
|
|
121
|
+
}
|
|
122
|
+
return signatures.join("\n");
|
|
123
|
+
}
|
|
124
|
+
function extractTypeDefinitions(content) {
|
|
125
|
+
const typeRegex = /(export\s+)?(interface|type)\s+\w+[^{]*\{[^}]*\}|(export\s+)?type\s+\w+\s*=[^;]+;?/g;
|
|
126
|
+
const types = [];
|
|
127
|
+
let match;
|
|
128
|
+
while ((match = typeRegex.exec(content)) !== null) {
|
|
129
|
+
types.push(match[0].trim());
|
|
130
|
+
}
|
|
131
|
+
return types.join("\n");
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// src/compress/truncate.ts
|
|
135
|
+
function smartTruncate(content, maxTokens) {
|
|
136
|
+
const lines = content.split("\n");
|
|
137
|
+
const estimatedTokens = Math.ceil(content.length / 4);
|
|
138
|
+
if (estimatedTokens <= maxTokens) return content;
|
|
139
|
+
const targetLines = Math.round(maxTokens * 4 / (content.length / lines.length));
|
|
140
|
+
const headerLines = Math.floor(targetLines * 0.3);
|
|
141
|
+
const footerLines = Math.floor(targetLines * 0.3);
|
|
142
|
+
const omitted = lines.length - headerLines - footerLines;
|
|
143
|
+
const header = lines.slice(0, headerLines);
|
|
144
|
+
const footer = lines.slice(-footerLines);
|
|
145
|
+
return [...header, `
|
|
146
|
+
... [${omitted} lines omitted] ...
|
|
147
|
+
`, ...footer].join("\n");
|
|
148
|
+
}
|
|
149
|
+
|
|
61
150
|
// src/compress/file-read.ts
|
|
62
151
|
var FileReadCompressor = class {
|
|
63
152
|
async compress(input) {
|
|
64
153
|
const { content, filePath, language } = input;
|
|
65
|
-
const
|
|
66
|
-
const
|
|
67
|
-
|
|
154
|
+
const lines = content.split("\n").length;
|
|
155
|
+
const tokens = Math.ceil(content.length / 4);
|
|
156
|
+
if (tokens < 200) {
|
|
157
|
+
return {
|
|
158
|
+
content,
|
|
159
|
+
original: content,
|
|
160
|
+
confidence: 1,
|
|
161
|
+
metadata: {
|
|
162
|
+
strategy: "passthrough",
|
|
163
|
+
originalLines: lines,
|
|
164
|
+
compressedLines: lines,
|
|
165
|
+
savings: 0
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
const stripped = stripAll(content);
|
|
170
|
+
const exports2 = extractExports(stripped);
|
|
171
|
+
const classes = extractClassMethods(stripped);
|
|
172
|
+
const functions = extractFunctionSignatures(stripped);
|
|
173
|
+
const types = extractTypeDefinitions(stripped);
|
|
174
|
+
const sections = [
|
|
68
175
|
`// ${filePath} (${content.split("\n").length} lines)`,
|
|
69
176
|
"",
|
|
70
|
-
...signatures,
|
|
71
|
-
"",
|
|
72
177
|
"// Exports:",
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
178
|
+
exports2,
|
|
179
|
+
"",
|
|
180
|
+
"// Classes:",
|
|
181
|
+
classes,
|
|
182
|
+
"",
|
|
183
|
+
"// Functions:",
|
|
184
|
+
functions,
|
|
185
|
+
"",
|
|
186
|
+
"// Types:",
|
|
187
|
+
types
|
|
188
|
+
].filter((l) => l !== "" && !l.endsWith(":"));
|
|
189
|
+
let compressed = sections.join("\n");
|
|
190
|
+
const maxTokens = 2e3;
|
|
191
|
+
compressed = smartTruncate(compressed, maxTokens);
|
|
76
192
|
return {
|
|
77
193
|
content: compressed,
|
|
78
194
|
original: content,
|
|
79
195
|
confidence: calculateConfidence(content, compressed),
|
|
80
196
|
metadata: {
|
|
81
|
-
strategy: "
|
|
197
|
+
strategy: "hybrid",
|
|
82
198
|
originalLines: content.split("\n").length,
|
|
83
|
-
compressedLines:
|
|
199
|
+
compressedLines: compressed.split("\n").length,
|
|
84
200
|
savings: 1 - compressed.length / content.length
|
|
85
201
|
}
|
|
86
202
|
};
|
|
@@ -88,32 +204,6 @@ var FileReadCompressor = class {
|
|
|
88
204
|
async decompress(compressed) {
|
|
89
205
|
return compressed.original;
|
|
90
206
|
}
|
|
91
|
-
extractSignatures(content, language) {
|
|
92
|
-
const signatures = [];
|
|
93
|
-
const lines = content.split("\n");
|
|
94
|
-
for (const line of lines) {
|
|
95
|
-
const trimmed = line.trim();
|
|
96
|
-
if (/^(export\s+)?(async\s+)?function\s+\w+/.test(trimmed)) {
|
|
97
|
-
signatures.push(trimmed.replace(/\{[\s\S]*$/, "{ ... }"));
|
|
98
|
-
}
|
|
99
|
-
if (/^(export\s+)?class\s+\w+/.test(trimmed)) {
|
|
100
|
-
signatures.push(trimmed);
|
|
101
|
-
}
|
|
102
|
-
if (/^(export\s+)?(type|interface)\s+\w+/.test(trimmed)) {
|
|
103
|
-
signatures.push(trimmed);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
return signatures;
|
|
107
|
-
}
|
|
108
|
-
extractExports(content) {
|
|
109
|
-
const exports2 = [];
|
|
110
|
-
const exportRegex = /export\s+(default\s+)?(function|class|const|let|var|type|interface)\s+(\w+)/g;
|
|
111
|
-
let match;
|
|
112
|
-
while ((match = exportRegex.exec(content)) !== null) {
|
|
113
|
-
exports2.push(` - ${match[3]} (${match[2]})`);
|
|
114
|
-
}
|
|
115
|
-
return exports2;
|
|
116
|
-
}
|
|
117
207
|
};
|
|
118
208
|
|
|
119
209
|
// src/cli/commands/read.ts
|
|
@@ -272,18 +362,21 @@ var import_util2 = require("util");
|
|
|
272
362
|
var GitDiffCompressor = class {
|
|
273
363
|
async compress(input) {
|
|
274
364
|
const { diff } = input;
|
|
275
|
-
const
|
|
276
|
-
const condensed = hunks.map((hunk) => ({
|
|
277
|
-
file: hunk.file,
|
|
278
|
-
changes: this.condenseHunk(hunk),
|
|
279
|
-
stats: { additions: hunk.additions, deletions: hunk.deletions }
|
|
280
|
-
}));
|
|
365
|
+
const files = this.parseDiff(diff);
|
|
281
366
|
const lines = [];
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
367
|
+
const totalAdd = files.reduce((s, f) => s + f.additions, 0);
|
|
368
|
+
const totalDel = files.reduce((s, f) => s + f.deletions, 0);
|
|
369
|
+
lines.push(`# ${files.length} files changed: +${totalAdd} -${totalDel}`);
|
|
370
|
+
lines.push("");
|
|
371
|
+
for (const file of files) {
|
|
372
|
+
lines.push(`${file.path} (+${file.additions} -${file.deletions})`);
|
|
373
|
+
const changes = file.lines.filter((l) => l.type === "add" || l.type === "del").map((l) => `${l.type === "add" ? "+" : "-"}${l.content}`);
|
|
374
|
+
const limited = changes.slice(0, 20);
|
|
375
|
+
lines.push(...limited);
|
|
376
|
+
if (changes.length > 20) {
|
|
377
|
+
lines.push(`... [${changes.length - 20} more changes]`);
|
|
286
378
|
}
|
|
379
|
+
lines.push("");
|
|
287
380
|
}
|
|
288
381
|
const compressed = lines.join("\n");
|
|
289
382
|
return {
|
|
@@ -292,7 +385,7 @@ var GitDiffCompressor = class {
|
|
|
292
385
|
confidence: calculateConfidence(diff, compressed),
|
|
293
386
|
metadata: {
|
|
294
387
|
strategy: "condensed",
|
|
295
|
-
filesChanged:
|
|
388
|
+
filesChanged: files.length,
|
|
296
389
|
savings: 1 - compressed.length / diff.length
|
|
297
390
|
}
|
|
298
391
|
};
|
|
@@ -301,34 +394,31 @@ var GitDiffCompressor = class {
|
|
|
301
394
|
return compressed.original;
|
|
302
395
|
}
|
|
303
396
|
parseDiff(diff) {
|
|
304
|
-
const
|
|
397
|
+
const files = [];
|
|
305
398
|
const lines = diff.split("\n");
|
|
306
|
-
let
|
|
399
|
+
let current = null;
|
|
307
400
|
for (const line of lines) {
|
|
308
401
|
if (line.startsWith("diff --git")) {
|
|
309
|
-
if (
|
|
310
|
-
const
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
lines: [],
|
|
402
|
+
if (current) files.push(current);
|
|
403
|
+
const match = line.match(/b\/(.+)/);
|
|
404
|
+
current = {
|
|
405
|
+
path: match?.[1] || "unknown",
|
|
314
406
|
additions: 0,
|
|
315
|
-
deletions: 0
|
|
407
|
+
deletions: 0,
|
|
408
|
+
lines: []
|
|
316
409
|
};
|
|
317
|
-
} else if (
|
|
410
|
+
} else if (current) {
|
|
318
411
|
if (line.startsWith("+")) {
|
|
319
|
-
|
|
320
|
-
|
|
412
|
+
current.additions++;
|
|
413
|
+
current.lines.push({ type: "add", content: line.slice(1) });
|
|
321
414
|
} else if (line.startsWith("-")) {
|
|
322
|
-
|
|
323
|
-
|
|
415
|
+
current.deletions++;
|
|
416
|
+
current.lines.push({ type: "del", content: line.slice(1) });
|
|
324
417
|
}
|
|
325
418
|
}
|
|
326
419
|
}
|
|
327
|
-
if (
|
|
328
|
-
return
|
|
329
|
-
}
|
|
330
|
-
condenseHunk(hunk) {
|
|
331
|
-
return hunk.lines.filter((l) => l.type === "addition" || l.type === "deletion").map((l) => `${l.type === "addition" ? "+" : "-"} ${l.content}`);
|
|
420
|
+
if (current) files.push(current);
|
|
421
|
+
return files;
|
|
332
422
|
}
|
|
333
423
|
};
|
|
334
424
|
|
|
@@ -1349,125 +1439,102 @@ async function directoryExists(dirPath) {
|
|
|
1349
1439
|
return false;
|
|
1350
1440
|
}
|
|
1351
1441
|
}
|
|
1442
|
+
async function readJSON(filePath) {
|
|
1443
|
+
try {
|
|
1444
|
+
const raw = await import_promises3.default.readFile(filePath, "utf-8");
|
|
1445
|
+
return JSON.parse(raw);
|
|
1446
|
+
} catch {
|
|
1447
|
+
return {};
|
|
1448
|
+
}
|
|
1449
|
+
}
|
|
1450
|
+
async function writeJSON(filePath, data) {
|
|
1451
|
+
try {
|
|
1452
|
+
const dir = import_path2.default.dirname(filePath);
|
|
1453
|
+
await import_promises3.default.mkdir(dir, { recursive: true });
|
|
1454
|
+
await import_promises3.default.writeFile(filePath, JSON.stringify(data, null, 2));
|
|
1455
|
+
return true;
|
|
1456
|
+
} catch {
|
|
1457
|
+
return false;
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
var MCP_CMD = ["npx", "-y", "make-laten-mcp", "server"];
|
|
1352
1461
|
async function detectAllAgents() {
|
|
1353
1462
|
const home = getHome2();
|
|
1354
1463
|
const agents2 = [];
|
|
1355
|
-
const claudeConfig = import_path2.default.join(home, ".claude", "mcp.json");
|
|
1356
|
-
const claudeDir = import_path2.default.join(home, ".claude");
|
|
1357
1464
|
agents2.push({
|
|
1358
1465
|
name: "Claude Code",
|
|
1359
|
-
detected: await commandExists2("claude") || await directoryExists(
|
|
1360
|
-
configPath:
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
}
|
|
1365
|
-
|
|
1366
|
-
|
|
1466
|
+
detected: await commandExists2("claude") || await directoryExists(import_path2.default.join(home, ".claude")),
|
|
1467
|
+
configPath: import_path2.default.join(home, ".claude", "mcp.json"),
|
|
1468
|
+
version: await commandExists2("claude") ? await execAsync4("claude --version", { timeout: 3e3 }).then((r) => r.stdout.trim().split("\n")[0]).catch(() => "unknown") : void 0,
|
|
1469
|
+
writeConfig: async (p) => {
|
|
1470
|
+
const data = await readJSON(p);
|
|
1471
|
+
data.mcpServers = { ...data.mcpServers || {}, "make-laten": { command: "npx", args: ["-y", "make-laten-mcp", "server"] } };
|
|
1472
|
+
return writeJSON(p, data);
|
|
1473
|
+
}
|
|
1367
1474
|
});
|
|
1368
|
-
const cursorMcp = import_path2.default.join(home, ".cursor", "mcp.json");
|
|
1369
|
-
const cursorDir = import_path2.default.join(home, ".cursor");
|
|
1370
1475
|
agents2.push({
|
|
1371
1476
|
name: "Cursor",
|
|
1372
|
-
detected: await directoryExists(
|
|
1373
|
-
configPath:
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1477
|
+
detected: await directoryExists(import_path2.default.join(home, ".cursor")),
|
|
1478
|
+
configPath: import_path2.default.join(home, ".cursor", "mcp.json"),
|
|
1479
|
+
writeConfig: async (p) => {
|
|
1480
|
+
const data = await readJSON(p);
|
|
1481
|
+
data.mcpServers = { ...data.mcpServers || {}, "make-laten": { command: "npx", args: ["-y", "make-laten-mcp", "server"] } };
|
|
1482
|
+
return writeJSON(p, data);
|
|
1378
1483
|
}
|
|
1379
1484
|
});
|
|
1380
|
-
const codexMcp = import_path2.default.join(home, ".codex", "config.json");
|
|
1381
|
-
const codexDir = import_path2.default.join(home, ".codex");
|
|
1382
1485
|
agents2.push({
|
|
1383
1486
|
name: "Codex",
|
|
1384
|
-
detected: await commandExists2("codex") || await directoryExists(
|
|
1385
|
-
configPath:
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1487
|
+
detected: await commandExists2("codex") || await directoryExists(import_path2.default.join(home, ".codex")),
|
|
1488
|
+
configPath: import_path2.default.join(home, ".codex", "config.json"),
|
|
1489
|
+
writeConfig: async (p) => {
|
|
1490
|
+
const data = await readJSON(p);
|
|
1491
|
+
data.mcpServers = { ...data.mcpServers || {}, "make-laten": { command: "npx", args: ["-y", "make-laten-mcp", "server"] } };
|
|
1492
|
+
return writeJSON(p, data);
|
|
1390
1493
|
}
|
|
1391
1494
|
});
|
|
1392
|
-
const windsurfMcp = import_path2.default.join(home, ".codeium", "windsurf", "mcp_config.json");
|
|
1393
|
-
const windsurfDir = import_path2.default.join(home, ".codeium", "windsurf");
|
|
1394
1495
|
agents2.push({
|
|
1395
|
-
name: "
|
|
1396
|
-
detected: await directoryExists(
|
|
1397
|
-
configPath:
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1496
|
+
name: "OpenCode",
|
|
1497
|
+
detected: await directoryExists(import_path2.default.join(home, ".config", "opencode")),
|
|
1498
|
+
configPath: import_path2.default.join(home, ".config", "opencode", "opencode.json"),
|
|
1499
|
+
writeConfig: async (p) => {
|
|
1500
|
+
const data = await readJSON(p);
|
|
1501
|
+
data.mcp = { ...data.mcp || {}, "make-laten": { type: "local", command: MCP_CMD, enabled: true } };
|
|
1502
|
+
delete data.mcpServers;
|
|
1503
|
+
return writeJSON(p, data);
|
|
1402
1504
|
}
|
|
1403
1505
|
});
|
|
1404
|
-
const openCodeConfig = import_path2.default.join(home, ".config", "opencode", "opencode.json");
|
|
1405
|
-
const openCodeDir = import_path2.default.join(home, ".config", "opencode");
|
|
1406
1506
|
agents2.push({
|
|
1407
|
-
name: "
|
|
1408
|
-
detected: await directoryExists(
|
|
1409
|
-
configPath:
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1507
|
+
name: "Windsurf",
|
|
1508
|
+
detected: await directoryExists(import_path2.default.join(home, ".codeium", "windsurf")),
|
|
1509
|
+
configPath: import_path2.default.join(home, ".codeium", "windsurf", "mcp_config.json"),
|
|
1510
|
+
writeConfig: async (p) => {
|
|
1511
|
+
const data = await readJSON(p);
|
|
1512
|
+
data.mcpServers = { ...data.mcpServers || {}, "make-laten": { command: "npx", args: ["-y", "make-laten-mcp", "server"] } };
|
|
1513
|
+
return writeJSON(p, data);
|
|
1414
1514
|
}
|
|
1415
1515
|
});
|
|
1416
|
-
const clineDir = import_path2.default.join(home, ".cline");
|
|
1417
|
-
const clineMcp = import_path2.default.join(home, ".cline", "mcp_settings.json");
|
|
1418
1516
|
agents2.push({
|
|
1419
1517
|
name: "Cline",
|
|
1420
|
-
detected: await directoryExists(
|
|
1421
|
-
configPath:
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1518
|
+
detected: await directoryExists(import_path2.default.join(home, ".cline")),
|
|
1519
|
+
configPath: import_path2.default.join(home, ".cline", "mcp_settings.json"),
|
|
1520
|
+
writeConfig: async (p) => {
|
|
1521
|
+
const data = await readJSON(p);
|
|
1522
|
+
data.mcpServers = { ...data.mcpServers || {}, "make-laten": { command: "npx", args: ["-y", "make-laten-mcp", "server"] } };
|
|
1523
|
+
return writeJSON(p, data);
|
|
1426
1524
|
}
|
|
1427
1525
|
});
|
|
1428
|
-
const vscodeDir = import_path2.default.join(home, "Library", "Application Support", "Code", "User", "globalStorage");
|
|
1429
|
-
agents2.push({
|
|
1430
|
-
name: "GitHub Copilot (VS Code)",
|
|
1431
|
-
detected: await directoryExists(vscodeDir),
|
|
1432
|
-
configPath: "",
|
|
1433
|
-
mcpConfig: {}
|
|
1434
|
-
});
|
|
1435
|
-
const geminiDir = import_path2.default.join(home, ".gemini");
|
|
1436
1526
|
agents2.push({
|
|
1437
1527
|
name: "Gemini CLI",
|
|
1438
|
-
detected: await commandExists2("gemini") || await directoryExists(
|
|
1528
|
+
detected: await commandExists2("gemini") || await directoryExists(import_path2.default.join(home, ".gemini")),
|
|
1439
1529
|
configPath: import_path2.default.join(home, ".gemini", "settings.json"),
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1530
|
+
writeConfig: async (p) => {
|
|
1531
|
+
const data = await readJSON(p);
|
|
1532
|
+
data.mcpServers = { ...data.mcpServers || {}, "make-laten": { command: "npx", args: ["-y", "make-laten-mcp", "server"] } };
|
|
1533
|
+
return writeJSON(p, data);
|
|
1444
1534
|
}
|
|
1445
1535
|
});
|
|
1446
1536
|
return agents2;
|
|
1447
1537
|
}
|
|
1448
|
-
async function writeMCPConfig(agent) {
|
|
1449
|
-
try {
|
|
1450
|
-
const dir = import_path2.default.dirname(agent.configPath);
|
|
1451
|
-
await import_promises3.default.mkdir(dir, { recursive: true });
|
|
1452
|
-
let existing = {};
|
|
1453
|
-
try {
|
|
1454
|
-
const raw = await import_promises3.default.readFile(agent.configPath, "utf-8");
|
|
1455
|
-
existing = JSON.parse(raw);
|
|
1456
|
-
} catch {
|
|
1457
|
-
}
|
|
1458
|
-
const merged = {
|
|
1459
|
-
...existing,
|
|
1460
|
-
mcpServers: {
|
|
1461
|
-
...existing.mcpServers || {},
|
|
1462
|
-
...agent.mcpConfig.mcpServers
|
|
1463
|
-
}
|
|
1464
|
-
};
|
|
1465
|
-
await import_promises3.default.writeFile(agent.configPath, JSON.stringify(merged, null, 2));
|
|
1466
|
-
return true;
|
|
1467
|
-
} catch {
|
|
1468
|
-
return false;
|
|
1469
|
-
}
|
|
1470
|
-
}
|
|
1471
1538
|
function askQuestion(rl, question) {
|
|
1472
1539
|
return new Promise((resolve) => rl.question(question, resolve));
|
|
1473
1540
|
}
|
|
@@ -1494,42 +1561,25 @@ async function initCommand(options) {
|
|
|
1494
1561
|
console.log("");
|
|
1495
1562
|
if (options.all) {
|
|
1496
1563
|
for (const agent of detected) {
|
|
1497
|
-
const success = await
|
|
1564
|
+
const success = await agent.writeConfig(agent.configPath);
|
|
1498
1565
|
if (success) {
|
|
1499
1566
|
console.log(` \u2713 ${agent.name} \u2192 MCP configured`);
|
|
1500
1567
|
} else {
|
|
1501
|
-
console.log(` \u2717 ${agent.name} \u2192 failed`);
|
|
1568
|
+
console.log(` \u2717 ${agent.name} \u2192 failed to write config`);
|
|
1502
1569
|
}
|
|
1503
1570
|
}
|
|
1504
1571
|
} else if (options.project) {
|
|
1505
1572
|
const cwd = process.cwd();
|
|
1506
|
-
const mcpConfig = {
|
|
1507
|
-
mcpServers: {
|
|
1508
|
-
"make-laten": { command: "npx", args: ["-y", "make-laten-mcp", "server"] }
|
|
1509
|
-
}
|
|
1510
|
-
};
|
|
1511
1573
|
const configPath = import_path2.default.join(cwd, ".mcp.json");
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
const raw = await import_promises3.default.readFile(configPath, "utf-8");
|
|
1515
|
-
existing = JSON.parse(raw);
|
|
1516
|
-
} catch {
|
|
1517
|
-
}
|
|
1518
|
-
const merged = {
|
|
1519
|
-
...existing,
|
|
1520
|
-
mcpServers: {
|
|
1521
|
-
...existing.mcpServers || {},
|
|
1522
|
-
...mcpConfig.mcpServers
|
|
1523
|
-
}
|
|
1524
|
-
};
|
|
1525
|
-
await import_promises3.default.writeFile(configPath, JSON.stringify(merged, null, 2));
|
|
1574
|
+
const data = { mcpServers: { "make-laten": { command: "npx", args: ["-y", "make-laten-mcp", "server"] } } };
|
|
1575
|
+
await writeJSON(configPath, data);
|
|
1526
1576
|
console.log(` \u2713 .mcp.json created in ${cwd}`);
|
|
1527
1577
|
} else {
|
|
1528
1578
|
const rl = import_readline.default.createInterface({ input: process.stdin, output: process.stdout });
|
|
1529
1579
|
for (const agent of detected) {
|
|
1530
1580
|
const answer = await askQuestion(rl, ` Configure ${agent.name}? (Y/n) `);
|
|
1531
1581
|
if (answer.toLowerCase() !== "n") {
|
|
1532
|
-
const success = await
|
|
1582
|
+
const success = await agent.writeConfig(agent.configPath);
|
|
1533
1583
|
if (success) {
|
|
1534
1584
|
console.log(` \u2713 ${agent.name} \u2192 MCP configured`);
|
|
1535
1585
|
} else {
|
|
@@ -1553,6 +1603,156 @@ async function initCommand(options) {
|
|
|
1553
1603
|
console.log("");
|
|
1554
1604
|
}
|
|
1555
1605
|
|
|
1606
|
+
// src/compress/git-status.ts
|
|
1607
|
+
var GitStatusCompressor = class {
|
|
1608
|
+
async compress(input) {
|
|
1609
|
+
const { status } = input;
|
|
1610
|
+
const statusLines = status.split("\n").filter(Boolean).length;
|
|
1611
|
+
const tokens = Math.ceil(status.length / 4);
|
|
1612
|
+
if (tokens < 10) {
|
|
1613
|
+
return {
|
|
1614
|
+
content: status,
|
|
1615
|
+
original: status,
|
|
1616
|
+
confidence: 1,
|
|
1617
|
+
metadata: {
|
|
1618
|
+
strategy: "passthrough",
|
|
1619
|
+
totalFiles: statusLines,
|
|
1620
|
+
savings: 0
|
|
1621
|
+
}
|
|
1622
|
+
};
|
|
1623
|
+
}
|
|
1624
|
+
const files = this.parseStatus(status);
|
|
1625
|
+
const grouped = this.groupByStatus(files);
|
|
1626
|
+
const lines = [];
|
|
1627
|
+
for (const [statusType, statusFiles] of grouped) {
|
|
1628
|
+
const label = this.statusLabel(statusType);
|
|
1629
|
+
lines.push(`${label} (${statusFiles.length})`);
|
|
1630
|
+
const compressed2 = this.compressPaths(statusFiles.map((f) => f.path));
|
|
1631
|
+
lines.push(...compressed2);
|
|
1632
|
+
lines.push("");
|
|
1633
|
+
}
|
|
1634
|
+
const compressed = lines.join("\n");
|
|
1635
|
+
return {
|
|
1636
|
+
content: compressed,
|
|
1637
|
+
original: status,
|
|
1638
|
+
confidence: calculateConfidence(status, compressed),
|
|
1639
|
+
metadata: {
|
|
1640
|
+
strategy: "grouped",
|
|
1641
|
+
totalFiles: files.length,
|
|
1642
|
+
savings: 1 - compressed.length / status.length
|
|
1643
|
+
}
|
|
1644
|
+
};
|
|
1645
|
+
}
|
|
1646
|
+
async decompress(compressed) {
|
|
1647
|
+
return compressed.original;
|
|
1648
|
+
}
|
|
1649
|
+
parseStatus(status) {
|
|
1650
|
+
return status.split("\n").filter(Boolean).map((line) => {
|
|
1651
|
+
const match = line.match(/^(\?\?|[MADRC]+\s+)(.+)$/);
|
|
1652
|
+
if (match) {
|
|
1653
|
+
return { status: match[1].trim(), path: match[2] };
|
|
1654
|
+
}
|
|
1655
|
+
return { status: line[0], path: line.slice(3) };
|
|
1656
|
+
});
|
|
1657
|
+
}
|
|
1658
|
+
groupByStatus(files) {
|
|
1659
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
1660
|
+
for (const file of files) {
|
|
1661
|
+
const existing = grouped.get(file.status) || [];
|
|
1662
|
+
existing.push(file);
|
|
1663
|
+
grouped.set(file.status, existing);
|
|
1664
|
+
}
|
|
1665
|
+
return grouped;
|
|
1666
|
+
}
|
|
1667
|
+
statusLabel(status) {
|
|
1668
|
+
const labels = {
|
|
1669
|
+
"M": "Modified",
|
|
1670
|
+
"A": "Added",
|
|
1671
|
+
"D": "Deleted",
|
|
1672
|
+
"??": "Untracked",
|
|
1673
|
+
"R": "Renamed"
|
|
1674
|
+
};
|
|
1675
|
+
return labels[status] || `Status ${status}`;
|
|
1676
|
+
}
|
|
1677
|
+
compressPaths(paths) {
|
|
1678
|
+
if (paths.length <= 3) return paths.map((p) => ` ${p}`);
|
|
1679
|
+
const parts = paths.map((p) => p.split("/"));
|
|
1680
|
+
const minLength = Math.min(...parts.map((p) => p.length));
|
|
1681
|
+
let commonIndex = 0;
|
|
1682
|
+
for (let i = 0; i < minLength; i++) {
|
|
1683
|
+
if (parts.every((p) => p[i] === parts[0][i])) {
|
|
1684
|
+
commonIndex = i;
|
|
1685
|
+
} else {
|
|
1686
|
+
break;
|
|
1687
|
+
}
|
|
1688
|
+
}
|
|
1689
|
+
if (commonIndex > 0) {
|
|
1690
|
+
const prefix = parts[0].slice(0, commonIndex).join("/");
|
|
1691
|
+
const suffixes = paths.map((p) => p.slice(prefix.length + 1));
|
|
1692
|
+
return [` ${prefix}/`, ...suffixes.map((s) => ` ${s}`)];
|
|
1693
|
+
}
|
|
1694
|
+
return paths.map((p) => ` ${p}`);
|
|
1695
|
+
}
|
|
1696
|
+
};
|
|
1697
|
+
|
|
1698
|
+
// src/cli/commands/benchmark.ts
|
|
1699
|
+
var import_fs = __toESM(require("fs"));
|
|
1700
|
+
var import_path3 = __toESM(require("path"));
|
|
1701
|
+
var import_child_process5 = require("child_process");
|
|
1702
|
+
async function benchmark() {
|
|
1703
|
+
const fileCompressor = new FileReadCompressor();
|
|
1704
|
+
const diffCompressor = new GitDiffCompressor();
|
|
1705
|
+
const statusCompressor = new GitStatusCompressor();
|
|
1706
|
+
const projectPath = process.cwd();
|
|
1707
|
+
console.log("");
|
|
1708
|
+
console.log(" make-laten benchmark");
|
|
1709
|
+
console.log(" ===================");
|
|
1710
|
+
console.log("");
|
|
1711
|
+
const results = [];
|
|
1712
|
+
const testFiles = ["src/index.ts", "package.json", "README.md", "src/mcp/server.ts"];
|
|
1713
|
+
for (const file of testFiles) {
|
|
1714
|
+
const full = import_path3.default.join(projectPath, file);
|
|
1715
|
+
if (!import_fs.default.existsSync(full)) continue;
|
|
1716
|
+
const content = import_fs.default.readFileSync(full, "utf-8");
|
|
1717
|
+
const raw = Math.round(content.length / 4);
|
|
1718
|
+
const result = await fileCompressor.compress({ content, filePath: file });
|
|
1719
|
+
const compressed = Math.round(result.content.length / 4);
|
|
1720
|
+
results.push({ name: `read ${file}`, raw, compressed, savings: Math.round((1 - compressed / raw) * 100) });
|
|
1721
|
+
}
|
|
1722
|
+
try {
|
|
1723
|
+
const diff = (0, import_child_process5.execSync)('git diff HEAD~1 2>/dev/null || echo ""', { cwd: projectPath, encoding: "utf-8" }).trim();
|
|
1724
|
+
if (diff) {
|
|
1725
|
+
const raw = Math.round(diff.length / 4);
|
|
1726
|
+
const result = await diffCompressor.compress({ diff });
|
|
1727
|
+
const compressed = Math.round(result.content.length / 4);
|
|
1728
|
+
results.push({ name: "git-diff", raw, compressed, savings: Math.round((1 - compressed / raw) * 100) });
|
|
1729
|
+
}
|
|
1730
|
+
} catch {
|
|
1731
|
+
}
|
|
1732
|
+
try {
|
|
1733
|
+
const status = (0, import_child_process5.execSync)('git status --porcelain 2>/dev/null || echo ""', { cwd: projectPath, encoding: "utf-8" }).trim();
|
|
1734
|
+
if (status) {
|
|
1735
|
+
const raw = Math.round(status.length / 4);
|
|
1736
|
+
const result = await statusCompressor.compress({ status });
|
|
1737
|
+
const compressed = Math.round(result.content.length / 4);
|
|
1738
|
+
results.push({ name: "git-status", raw, compressed, savings: Math.round((1 - compressed / raw) * 100) });
|
|
1739
|
+
}
|
|
1740
|
+
} catch {
|
|
1741
|
+
}
|
|
1742
|
+
console.log(" Command".padEnd(28) + "Raw".padEnd(10) + "Compressed".padEnd(12) + "Savings");
|
|
1743
|
+
console.log(" " + "\u2500".repeat(60));
|
|
1744
|
+
for (const r of results) {
|
|
1745
|
+
console.log(` ${r.name}`.padEnd(28) + `${r.raw}`.padEnd(10) + `${r.compressed}`.padEnd(12) + `${r.savings}%`);
|
|
1746
|
+
}
|
|
1747
|
+
const totalRaw = results.reduce((s, r) => s + r.raw, 0);
|
|
1748
|
+
const totalCompressed = results.reduce((s, r) => s + r.compressed, 0);
|
|
1749
|
+
const savings = Math.round((1 - totalCompressed / totalRaw) * 100);
|
|
1750
|
+
console.log("");
|
|
1751
|
+
console.log(` Total: ${totalRaw} \u2192 ${totalCompressed} tokens (${savings}% saved)`);
|
|
1752
|
+
console.log("");
|
|
1753
|
+
}
|
|
1754
|
+
benchmark();
|
|
1755
|
+
|
|
1556
1756
|
// src/cli/index.ts
|
|
1557
1757
|
var program = new import_commander.Command();
|
|
1558
1758
|
program.name("make-laten").description("Universal efficiency toolkit for AI coding agents").version("1.0.3");
|
|
@@ -1568,5 +1768,6 @@ program.command("search").description("Search the web").argument("<query>", "Sea
|
|
|
1568
1768
|
program.command("fetch").description("Fetch and compress web content").argument("<url>", "URL to fetch").option("--no-compress", "Disable compression").option("--no-extract", "Disable semantic extraction").action(fetchCommand);
|
|
1569
1769
|
program.command("install").description("Install make-laten across all detected platforms").option("-u, --uninstall", "Remove adapters").option("-s, --status", "Show installation status").action(installCommand);
|
|
1570
1770
|
program.command("init").description("Interactive setup wizard \u2014 detect agents & configure MCP").option("-a, --all", "Configure all detected agents (no prompts)").option("-p, --project", "Create .mcp.json in current directory only").action(initCommand);
|
|
1771
|
+
program.command("benchmark").description("Compare raw vs compressed output").action(void 0);
|
|
1571
1772
|
program.parse();
|
|
1572
1773
|
//# sourceMappingURL=index.js.map
|