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.
@@ -35,29 +35,145 @@ function isKnownPattern(content) {
35
35
  return patterns.some((p) => p.test(content));
36
36
  }
37
37
 
38
+ // src/compress/strip.ts
39
+ function stripImports(content) {
40
+ 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");
41
+ }
42
+ function stripComments(content) {
43
+ let result = content.replace(/(?<!["'`])\/\/.*$/gm, "");
44
+ result = result.replace(/\/\*[\s\S]*?\*\//g, "");
45
+ return result.split("\n").filter((l) => l.trim() !== "").join("\n");
46
+ }
47
+ function stripBlankLines(content) {
48
+ return content.replace(/\n{3,}/g, "\n\n");
49
+ }
50
+ function stripWhitespace(content) {
51
+ return content.replace(/[ \t]+$/gm, "");
52
+ }
53
+ function stripAll(content) {
54
+ let result = content;
55
+ result = stripImports(result);
56
+ result = stripComments(result);
57
+ result = stripBlankLines(result);
58
+ result = stripWhitespace(result);
59
+ return result.trim();
60
+ }
61
+
62
+ // src/compress/structure.ts
63
+ function extractExports(content) {
64
+ const lines = content.split("\n");
65
+ const exports = [];
66
+ for (const line of lines) {
67
+ const trimmed = line.trim();
68
+ if (/^export\s+(default\s+)?/.test(trimmed)) {
69
+ if (trimmed.includes("{") && !trimmed.includes("}")) {
70
+ exports.push(trimmed.replace(/\{[\s\S]*$/, "{ ... }"));
71
+ } else {
72
+ exports.push(trimmed);
73
+ }
74
+ }
75
+ }
76
+ return exports.join("\n");
77
+ }
78
+ function extractClassMethods(content) {
79
+ const classRegex = /class\s+\w+[^{]*\{([\s\S]*?)\n\}/g;
80
+ const methods = [];
81
+ let match;
82
+ while ((match = classRegex.exec(content)) !== null) {
83
+ const classBody = match[1];
84
+ const methodRegex = /(^\s*(?:public|private|protected|static|async|abstract|\s)*\w+\s*\([^)]*\)(?:\s*:\s*[^{]+)?)\s*\{/gm;
85
+ let methodMatch;
86
+ while ((methodMatch = methodRegex.exec(classBody)) !== null) {
87
+ methods.push(methodMatch[1].trim());
88
+ }
89
+ }
90
+ return methods.join("\n");
91
+ }
92
+ function extractFunctionSignatures(content) {
93
+ const funcRegex = /(export\s+)?(async\s+)?function\s+\w+\s*\([^)]*\)(?:\s*:\s*[^{]+)?\s*\{/g;
94
+ const signatures = [];
95
+ let match;
96
+ while ((match = funcRegex.exec(content)) !== null) {
97
+ signatures.push(match[0].replace(/\{$/, ""));
98
+ }
99
+ return signatures.join("\n");
100
+ }
101
+ function extractTypeDefinitions(content) {
102
+ const typeRegex = /(export\s+)?(interface|type)\s+\w+[^{]*\{[^}]*\}|(export\s+)?type\s+\w+\s*=[^;]+;?/g;
103
+ const types = [];
104
+ let match;
105
+ while ((match = typeRegex.exec(content)) !== null) {
106
+ types.push(match[0].trim());
107
+ }
108
+ return types.join("\n");
109
+ }
110
+
111
+ // src/compress/truncate.ts
112
+ function smartTruncate(content, maxTokens) {
113
+ const lines = content.split("\n");
114
+ const estimatedTokens = Math.ceil(content.length / 4);
115
+ if (estimatedTokens <= maxTokens) return content;
116
+ const targetLines = Math.round(maxTokens * 4 / (content.length / lines.length));
117
+ const headerLines = Math.floor(targetLines * 0.3);
118
+ const footerLines = Math.floor(targetLines * 0.3);
119
+ const omitted = lines.length - headerLines - footerLines;
120
+ const header = lines.slice(0, headerLines);
121
+ const footer = lines.slice(-footerLines);
122
+ return [...header, `
123
+ ... [${omitted} lines omitted] ...
124
+ `, ...footer].join("\n");
125
+ }
126
+
38
127
  // src/compress/file-read.ts
39
128
  var FileReadCompressor = class {
40
129
  async compress(input) {
41
130
  const { content, filePath, language } = input;
42
- const signatures = this.extractSignatures(content, language);
43
- const exports = this.extractExports(content);
44
- const lines = [
131
+ const lines = content.split("\n").length;
132
+ const tokens = Math.ceil(content.length / 4);
133
+ if (tokens < 200) {
134
+ return {
135
+ content,
136
+ original: content,
137
+ confidence: 1,
138
+ metadata: {
139
+ strategy: "passthrough",
140
+ originalLines: lines,
141
+ compressedLines: lines,
142
+ savings: 0
143
+ }
144
+ };
145
+ }
146
+ const stripped = stripAll(content);
147
+ const exports = extractExports(stripped);
148
+ const classes = extractClassMethods(stripped);
149
+ const functions = extractFunctionSignatures(stripped);
150
+ const types = extractTypeDefinitions(stripped);
151
+ const sections = [
45
152
  `// ${filePath} (${content.split("\n").length} lines)`,
46
153
  "",
47
- ...signatures,
48
- "",
49
154
  "// Exports:",
50
- ...exports
51
- ];
52
- const compressed = lines.join("\n");
155
+ exports,
156
+ "",
157
+ "// Classes:",
158
+ classes,
159
+ "",
160
+ "// Functions:",
161
+ functions,
162
+ "",
163
+ "// Types:",
164
+ types
165
+ ].filter((l) => l !== "" && !l.endsWith(":"));
166
+ let compressed = sections.join("\n");
167
+ const maxTokens = 2e3;
168
+ compressed = smartTruncate(compressed, maxTokens);
53
169
  return {
54
170
  content: compressed,
55
171
  original: content,
56
172
  confidence: calculateConfidence(content, compressed),
57
173
  metadata: {
58
- strategy: "signatures",
174
+ strategy: "hybrid",
59
175
  originalLines: content.split("\n").length,
60
- compressedLines: lines.length,
176
+ compressedLines: compressed.split("\n").length,
61
177
  savings: 1 - compressed.length / content.length
62
178
  }
63
179
  };
@@ -65,32 +181,6 @@ var FileReadCompressor = class {
65
181
  async decompress(compressed) {
66
182
  return compressed.original;
67
183
  }
68
- extractSignatures(content, language) {
69
- const signatures = [];
70
- const lines = content.split("\n");
71
- for (const line of lines) {
72
- const trimmed = line.trim();
73
- if (/^(export\s+)?(async\s+)?function\s+\w+/.test(trimmed)) {
74
- signatures.push(trimmed.replace(/\{[\s\S]*$/, "{ ... }"));
75
- }
76
- if (/^(export\s+)?class\s+\w+/.test(trimmed)) {
77
- signatures.push(trimmed);
78
- }
79
- if (/^(export\s+)?(type|interface)\s+\w+/.test(trimmed)) {
80
- signatures.push(trimmed);
81
- }
82
- }
83
- return signatures;
84
- }
85
- extractExports(content) {
86
- const exports = [];
87
- const exportRegex = /export\s+(default\s+)?(function|class|const|let|var|type|interface)\s+(\w+)/g;
88
- let match;
89
- while ((match = exportRegex.exec(content)) !== null) {
90
- exports.push(` - ${match[3]} (${match[2]})`);
91
- }
92
- return exports;
93
- }
94
184
  };
95
185
 
96
186
  // src/cli/commands/read.ts
@@ -249,18 +339,21 @@ import { promisify as promisify2 } from "util";
249
339
  var GitDiffCompressor = class {
250
340
  async compress(input) {
251
341
  const { diff } = input;
252
- const hunks = this.parseDiff(diff);
253
- const condensed = hunks.map((hunk) => ({
254
- file: hunk.file,
255
- changes: this.condenseHunk(hunk),
256
- stats: { additions: hunk.additions, deletions: hunk.deletions }
257
- }));
342
+ const files = this.parseDiff(diff);
258
343
  const lines = [];
259
- for (const hunk of condensed) {
260
- if (hunk.changes.length > 0) {
261
- lines.push(`${hunk.file} (+${hunk.stats.additions} -${hunk.stats.deletions})`);
262
- lines.push(...hunk.changes);
344
+ const totalAdd = files.reduce((s, f) => s + f.additions, 0);
345
+ const totalDel = files.reduce((s, f) => s + f.deletions, 0);
346
+ lines.push(`# ${files.length} files changed: +${totalAdd} -${totalDel}`);
347
+ lines.push("");
348
+ for (const file of files) {
349
+ lines.push(`${file.path} (+${file.additions} -${file.deletions})`);
350
+ const changes = file.lines.filter((l) => l.type === "add" || l.type === "del").map((l) => `${l.type === "add" ? "+" : "-"}${l.content}`);
351
+ const limited = changes.slice(0, 20);
352
+ lines.push(...limited);
353
+ if (changes.length > 20) {
354
+ lines.push(`... [${changes.length - 20} more changes]`);
263
355
  }
356
+ lines.push("");
264
357
  }
265
358
  const compressed = lines.join("\n");
266
359
  return {
@@ -269,7 +362,7 @@ var GitDiffCompressor = class {
269
362
  confidence: calculateConfidence(diff, compressed),
270
363
  metadata: {
271
364
  strategy: "condensed",
272
- filesChanged: condensed.length,
365
+ filesChanged: files.length,
273
366
  savings: 1 - compressed.length / diff.length
274
367
  }
275
368
  };
@@ -278,34 +371,31 @@ var GitDiffCompressor = class {
278
371
  return compressed.original;
279
372
  }
280
373
  parseDiff(diff) {
281
- const hunks = [];
374
+ const files = [];
282
375
  const lines = diff.split("\n");
283
- let currentHunk = null;
376
+ let current = null;
284
377
  for (const line of lines) {
285
378
  if (line.startsWith("diff --git")) {
286
- if (currentHunk) hunks.push(currentHunk);
287
- const fileMatch = line.match(/b\/(.+)/);
288
- currentHunk = {
289
- file: fileMatch?.[1] || "unknown",
290
- lines: [],
379
+ if (current) files.push(current);
380
+ const match = line.match(/b\/(.+)/);
381
+ current = {
382
+ path: match?.[1] || "unknown",
291
383
  additions: 0,
292
- deletions: 0
384
+ deletions: 0,
385
+ lines: []
293
386
  };
294
- } else if (currentHunk) {
387
+ } else if (current) {
295
388
  if (line.startsWith("+")) {
296
- currentHunk.additions++;
297
- currentHunk.lines.push({ type: "addition", content: line.slice(1) });
389
+ current.additions++;
390
+ current.lines.push({ type: "add", content: line.slice(1) });
298
391
  } else if (line.startsWith("-")) {
299
- currentHunk.deletions++;
300
- currentHunk.lines.push({ type: "deletion", content: line.slice(1) });
392
+ current.deletions++;
393
+ current.lines.push({ type: "del", content: line.slice(1) });
301
394
  }
302
395
  }
303
396
  }
304
- if (currentHunk) hunks.push(currentHunk);
305
- return hunks;
306
- }
307
- condenseHunk(hunk) {
308
- return hunk.lines.filter((l) => l.type === "addition" || l.type === "deletion").map((l) => `${l.type === "addition" ? "+" : "-"} ${l.content}`);
397
+ if (current) files.push(current);
398
+ return files;
309
399
  }
310
400
  };
311
401
 
@@ -1326,125 +1416,102 @@ async function directoryExists(dirPath) {
1326
1416
  return false;
1327
1417
  }
1328
1418
  }
1419
+ async function readJSON(filePath) {
1420
+ try {
1421
+ const raw = await fs3.readFile(filePath, "utf-8");
1422
+ return JSON.parse(raw);
1423
+ } catch {
1424
+ return {};
1425
+ }
1426
+ }
1427
+ async function writeJSON(filePath, data) {
1428
+ try {
1429
+ const dir = path2.dirname(filePath);
1430
+ await fs3.mkdir(dir, { recursive: true });
1431
+ await fs3.writeFile(filePath, JSON.stringify(data, null, 2));
1432
+ return true;
1433
+ } catch {
1434
+ return false;
1435
+ }
1436
+ }
1437
+ var MCP_CMD = ["npx", "-y", "make-laten-mcp", "server"];
1329
1438
  async function detectAllAgents() {
1330
1439
  const home = getHome2();
1331
1440
  const agents2 = [];
1332
- const claudeConfig = path2.join(home, ".claude", "mcp.json");
1333
- const claudeDir = path2.join(home, ".claude");
1334
1441
  agents2.push({
1335
1442
  name: "Claude Code",
1336
- detected: await commandExists2("claude") || await directoryExists(claudeDir),
1337
- configPath: claudeConfig,
1338
- mcpConfig: {
1339
- mcpServers: {
1340
- "make-laten": { command: "npx", args: ["-y", "make-laten-mcp", "server"] }
1341
- }
1342
- },
1343
- version: await commandExists2("claude") ? await execAsync4("claude --version", { timeout: 3e3 }).then((r) => r.stdout.trim().split("\n")[0]).catch(() => "unknown") : void 0
1443
+ detected: await commandExists2("claude") || await directoryExists(path2.join(home, ".claude")),
1444
+ configPath: path2.join(home, ".claude", "mcp.json"),
1445
+ version: await commandExists2("claude") ? await execAsync4("claude --version", { timeout: 3e3 }).then((r) => r.stdout.trim().split("\n")[0]).catch(() => "unknown") : void 0,
1446
+ writeConfig: async (p) => {
1447
+ const data = await readJSON(p);
1448
+ data.mcpServers = { ...data.mcpServers || {}, "make-laten": { command: "npx", args: ["-y", "make-laten-mcp", "server"] } };
1449
+ return writeJSON(p, data);
1450
+ }
1344
1451
  });
1345
- const cursorMcp = path2.join(home, ".cursor", "mcp.json");
1346
- const cursorDir = path2.join(home, ".cursor");
1347
1452
  agents2.push({
1348
1453
  name: "Cursor",
1349
- detected: await directoryExists(cursorDir),
1350
- configPath: cursorMcp,
1351
- mcpConfig: {
1352
- mcpServers: {
1353
- "make-laten": { command: "npx", args: ["-y", "make-laten-mcp", "server"] }
1354
- }
1454
+ detected: await directoryExists(path2.join(home, ".cursor")),
1455
+ configPath: path2.join(home, ".cursor", "mcp.json"),
1456
+ writeConfig: async (p) => {
1457
+ const data = await readJSON(p);
1458
+ data.mcpServers = { ...data.mcpServers || {}, "make-laten": { command: "npx", args: ["-y", "make-laten-mcp", "server"] } };
1459
+ return writeJSON(p, data);
1355
1460
  }
1356
1461
  });
1357
- const codexMcp = path2.join(home, ".codex", "config.json");
1358
- const codexDir = path2.join(home, ".codex");
1359
1462
  agents2.push({
1360
1463
  name: "Codex",
1361
- detected: await commandExists2("codex") || await directoryExists(codexDir),
1362
- configPath: codexMcp,
1363
- mcpConfig: {
1364
- mcpServers: {
1365
- "make-laten": { command: "npx", args: ["-y", "make-laten-mcp", "server"] }
1366
- }
1464
+ detected: await commandExists2("codex") || await directoryExists(path2.join(home, ".codex")),
1465
+ configPath: path2.join(home, ".codex", "config.json"),
1466
+ writeConfig: async (p) => {
1467
+ const data = await readJSON(p);
1468
+ data.mcpServers = { ...data.mcpServers || {}, "make-laten": { command: "npx", args: ["-y", "make-laten-mcp", "server"] } };
1469
+ return writeJSON(p, data);
1367
1470
  }
1368
1471
  });
1369
- const windsurfMcp = path2.join(home, ".codeium", "windsurf", "mcp_config.json");
1370
- const windsurfDir = path2.join(home, ".codeium", "windsurf");
1371
1472
  agents2.push({
1372
- name: "Windsurf",
1373
- detected: await directoryExists(windsurfDir),
1374
- configPath: windsurfMcp,
1375
- mcpConfig: {
1376
- mcpServers: {
1377
- "make-laten": { command: "npx", args: ["-y", "make-laten-mcp", "server"] }
1378
- }
1473
+ name: "OpenCode",
1474
+ detected: await directoryExists(path2.join(home, ".config", "opencode")),
1475
+ configPath: path2.join(home, ".config", "opencode", "opencode.json"),
1476
+ writeConfig: async (p) => {
1477
+ const data = await readJSON(p);
1478
+ data.mcp = { ...data.mcp || {}, "make-laten": { type: "local", command: MCP_CMD, enabled: true } };
1479
+ delete data.mcpServers;
1480
+ return writeJSON(p, data);
1379
1481
  }
1380
1482
  });
1381
- const openCodeConfig = path2.join(home, ".config", "opencode", "opencode.json");
1382
- const openCodeDir = path2.join(home, ".config", "opencode");
1383
1483
  agents2.push({
1384
- name: "OpenCode",
1385
- detected: await directoryExists(openCodeDir),
1386
- configPath: openCodeConfig,
1387
- mcpConfig: {
1388
- mcpServers: {
1389
- "make-laten": { command: "npx", args: ["-y", "make-laten-mcp", "server"] }
1390
- }
1484
+ name: "Windsurf",
1485
+ detected: await directoryExists(path2.join(home, ".codeium", "windsurf")),
1486
+ configPath: path2.join(home, ".codeium", "windsurf", "mcp_config.json"),
1487
+ writeConfig: async (p) => {
1488
+ const data = await readJSON(p);
1489
+ data.mcpServers = { ...data.mcpServers || {}, "make-laten": { command: "npx", args: ["-y", "make-laten-mcp", "server"] } };
1490
+ return writeJSON(p, data);
1391
1491
  }
1392
1492
  });
1393
- const clineDir = path2.join(home, ".cline");
1394
- const clineMcp = path2.join(home, ".cline", "mcp_settings.json");
1395
1493
  agents2.push({
1396
1494
  name: "Cline",
1397
- detected: await directoryExists(clineDir),
1398
- configPath: clineMcp,
1399
- mcpConfig: {
1400
- mcpServers: {
1401
- "make-laten": { command: "npx", args: ["-y", "make-laten-mcp", "server"] }
1402
- }
1495
+ detected: await directoryExists(path2.join(home, ".cline")),
1496
+ configPath: path2.join(home, ".cline", "mcp_settings.json"),
1497
+ writeConfig: async (p) => {
1498
+ const data = await readJSON(p);
1499
+ data.mcpServers = { ...data.mcpServers || {}, "make-laten": { command: "npx", args: ["-y", "make-laten-mcp", "server"] } };
1500
+ return writeJSON(p, data);
1403
1501
  }
1404
1502
  });
1405
- const vscodeDir = path2.join(home, "Library", "Application Support", "Code", "User", "globalStorage");
1406
- agents2.push({
1407
- name: "GitHub Copilot (VS Code)",
1408
- detected: await directoryExists(vscodeDir),
1409
- configPath: "",
1410
- mcpConfig: {}
1411
- });
1412
- const geminiDir = path2.join(home, ".gemini");
1413
1503
  agents2.push({
1414
1504
  name: "Gemini CLI",
1415
- detected: await commandExists2("gemini") || await directoryExists(geminiDir),
1505
+ detected: await commandExists2("gemini") || await directoryExists(path2.join(home, ".gemini")),
1416
1506
  configPath: path2.join(home, ".gemini", "settings.json"),
1417
- mcpConfig: {
1418
- mcpServers: {
1419
- "make-laten": { command: "npx", args: ["-y", "make-laten-mcp", "server"] }
1420
- }
1507
+ writeConfig: async (p) => {
1508
+ const data = await readJSON(p);
1509
+ data.mcpServers = { ...data.mcpServers || {}, "make-laten": { command: "npx", args: ["-y", "make-laten-mcp", "server"] } };
1510
+ return writeJSON(p, data);
1421
1511
  }
1422
1512
  });
1423
1513
  return agents2;
1424
1514
  }
1425
- async function writeMCPConfig(agent) {
1426
- try {
1427
- const dir = path2.dirname(agent.configPath);
1428
- await fs3.mkdir(dir, { recursive: true });
1429
- let existing = {};
1430
- try {
1431
- const raw = await fs3.readFile(agent.configPath, "utf-8");
1432
- existing = JSON.parse(raw);
1433
- } catch {
1434
- }
1435
- const merged = {
1436
- ...existing,
1437
- mcpServers: {
1438
- ...existing.mcpServers || {},
1439
- ...agent.mcpConfig.mcpServers
1440
- }
1441
- };
1442
- await fs3.writeFile(agent.configPath, JSON.stringify(merged, null, 2));
1443
- return true;
1444
- } catch {
1445
- return false;
1446
- }
1447
- }
1448
1515
  function askQuestion(rl, question) {
1449
1516
  return new Promise((resolve) => rl.question(question, resolve));
1450
1517
  }
@@ -1471,42 +1538,25 @@ async function initCommand(options) {
1471
1538
  console.log("");
1472
1539
  if (options.all) {
1473
1540
  for (const agent of detected) {
1474
- const success = await writeMCPConfig(agent);
1541
+ const success = await agent.writeConfig(agent.configPath);
1475
1542
  if (success) {
1476
1543
  console.log(` \u2713 ${agent.name} \u2192 MCP configured`);
1477
1544
  } else {
1478
- console.log(` \u2717 ${agent.name} \u2192 failed`);
1545
+ console.log(` \u2717 ${agent.name} \u2192 failed to write config`);
1479
1546
  }
1480
1547
  }
1481
1548
  } else if (options.project) {
1482
1549
  const cwd = process.cwd();
1483
- const mcpConfig = {
1484
- mcpServers: {
1485
- "make-laten": { command: "npx", args: ["-y", "make-laten-mcp", "server"] }
1486
- }
1487
- };
1488
1550
  const configPath = path2.join(cwd, ".mcp.json");
1489
- let existing = {};
1490
- try {
1491
- const raw = await fs3.readFile(configPath, "utf-8");
1492
- existing = JSON.parse(raw);
1493
- } catch {
1494
- }
1495
- const merged = {
1496
- ...existing,
1497
- mcpServers: {
1498
- ...existing.mcpServers || {},
1499
- ...mcpConfig.mcpServers
1500
- }
1501
- };
1502
- await fs3.writeFile(configPath, JSON.stringify(merged, null, 2));
1551
+ const data = { mcpServers: { "make-laten": { command: "npx", args: ["-y", "make-laten-mcp", "server"] } } };
1552
+ await writeJSON(configPath, data);
1503
1553
  console.log(` \u2713 .mcp.json created in ${cwd}`);
1504
1554
  } else {
1505
1555
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
1506
1556
  for (const agent of detected) {
1507
1557
  const answer = await askQuestion(rl, ` Configure ${agent.name}? (Y/n) `);
1508
1558
  if (answer.toLowerCase() !== "n") {
1509
- const success = await writeMCPConfig(agent);
1559
+ const success = await agent.writeConfig(agent.configPath);
1510
1560
  if (success) {
1511
1561
  console.log(` \u2713 ${agent.name} \u2192 MCP configured`);
1512
1562
  } else {
@@ -1530,6 +1580,156 @@ async function initCommand(options) {
1530
1580
  console.log("");
1531
1581
  }
1532
1582
 
1583
+ // src/compress/git-status.ts
1584
+ var GitStatusCompressor = class {
1585
+ async compress(input) {
1586
+ const { status } = input;
1587
+ const statusLines = status.split("\n").filter(Boolean).length;
1588
+ const tokens = Math.ceil(status.length / 4);
1589
+ if (tokens < 10) {
1590
+ return {
1591
+ content: status,
1592
+ original: status,
1593
+ confidence: 1,
1594
+ metadata: {
1595
+ strategy: "passthrough",
1596
+ totalFiles: statusLines,
1597
+ savings: 0
1598
+ }
1599
+ };
1600
+ }
1601
+ const files = this.parseStatus(status);
1602
+ const grouped = this.groupByStatus(files);
1603
+ const lines = [];
1604
+ for (const [statusType, statusFiles] of grouped) {
1605
+ const label = this.statusLabel(statusType);
1606
+ lines.push(`${label} (${statusFiles.length})`);
1607
+ const compressed2 = this.compressPaths(statusFiles.map((f) => f.path));
1608
+ lines.push(...compressed2);
1609
+ lines.push("");
1610
+ }
1611
+ const compressed = lines.join("\n");
1612
+ return {
1613
+ content: compressed,
1614
+ original: status,
1615
+ confidence: calculateConfidence(status, compressed),
1616
+ metadata: {
1617
+ strategy: "grouped",
1618
+ totalFiles: files.length,
1619
+ savings: 1 - compressed.length / status.length
1620
+ }
1621
+ };
1622
+ }
1623
+ async decompress(compressed) {
1624
+ return compressed.original;
1625
+ }
1626
+ parseStatus(status) {
1627
+ return status.split("\n").filter(Boolean).map((line) => {
1628
+ const match = line.match(/^(\?\?|[MADRC]+\s+)(.+)$/);
1629
+ if (match) {
1630
+ return { status: match[1].trim(), path: match[2] };
1631
+ }
1632
+ return { status: line[0], path: line.slice(3) };
1633
+ });
1634
+ }
1635
+ groupByStatus(files) {
1636
+ const grouped = /* @__PURE__ */ new Map();
1637
+ for (const file of files) {
1638
+ const existing = grouped.get(file.status) || [];
1639
+ existing.push(file);
1640
+ grouped.set(file.status, existing);
1641
+ }
1642
+ return grouped;
1643
+ }
1644
+ statusLabel(status) {
1645
+ const labels = {
1646
+ "M": "Modified",
1647
+ "A": "Added",
1648
+ "D": "Deleted",
1649
+ "??": "Untracked",
1650
+ "R": "Renamed"
1651
+ };
1652
+ return labels[status] || `Status ${status}`;
1653
+ }
1654
+ compressPaths(paths) {
1655
+ if (paths.length <= 3) return paths.map((p) => ` ${p}`);
1656
+ const parts = paths.map((p) => p.split("/"));
1657
+ const minLength = Math.min(...parts.map((p) => p.length));
1658
+ let commonIndex = 0;
1659
+ for (let i = 0; i < minLength; i++) {
1660
+ if (parts.every((p) => p[i] === parts[0][i])) {
1661
+ commonIndex = i;
1662
+ } else {
1663
+ break;
1664
+ }
1665
+ }
1666
+ if (commonIndex > 0) {
1667
+ const prefix = parts[0].slice(0, commonIndex).join("/");
1668
+ const suffixes = paths.map((p) => p.slice(prefix.length + 1));
1669
+ return [` ${prefix}/`, ...suffixes.map((s) => ` ${s}`)];
1670
+ }
1671
+ return paths.map((p) => ` ${p}`);
1672
+ }
1673
+ };
1674
+
1675
+ // src/cli/commands/benchmark.ts
1676
+ import fs4 from "fs";
1677
+ import path3 from "path";
1678
+ import { execSync } from "child_process";
1679
+ async function benchmark() {
1680
+ const fileCompressor = new FileReadCompressor();
1681
+ const diffCompressor = new GitDiffCompressor();
1682
+ const statusCompressor = new GitStatusCompressor();
1683
+ const projectPath = process.cwd();
1684
+ console.log("");
1685
+ console.log(" make-laten benchmark");
1686
+ console.log(" ===================");
1687
+ console.log("");
1688
+ const results = [];
1689
+ const testFiles = ["src/index.ts", "package.json", "README.md", "src/mcp/server.ts"];
1690
+ for (const file of testFiles) {
1691
+ const full = path3.join(projectPath, file);
1692
+ if (!fs4.existsSync(full)) continue;
1693
+ const content = fs4.readFileSync(full, "utf-8");
1694
+ const raw = Math.round(content.length / 4);
1695
+ const result = await fileCompressor.compress({ content, filePath: file });
1696
+ const compressed = Math.round(result.content.length / 4);
1697
+ results.push({ name: `read ${file}`, raw, compressed, savings: Math.round((1 - compressed / raw) * 100) });
1698
+ }
1699
+ try {
1700
+ const diff = execSync('git diff HEAD~1 2>/dev/null || echo ""', { cwd: projectPath, encoding: "utf-8" }).trim();
1701
+ if (diff) {
1702
+ const raw = Math.round(diff.length / 4);
1703
+ const result = await diffCompressor.compress({ diff });
1704
+ const compressed = Math.round(result.content.length / 4);
1705
+ results.push({ name: "git-diff", raw, compressed, savings: Math.round((1 - compressed / raw) * 100) });
1706
+ }
1707
+ } catch {
1708
+ }
1709
+ try {
1710
+ const status = execSync('git status --porcelain 2>/dev/null || echo ""', { cwd: projectPath, encoding: "utf-8" }).trim();
1711
+ if (status) {
1712
+ const raw = Math.round(status.length / 4);
1713
+ const result = await statusCompressor.compress({ status });
1714
+ const compressed = Math.round(result.content.length / 4);
1715
+ results.push({ name: "git-status", raw, compressed, savings: Math.round((1 - compressed / raw) * 100) });
1716
+ }
1717
+ } catch {
1718
+ }
1719
+ console.log(" Command".padEnd(28) + "Raw".padEnd(10) + "Compressed".padEnd(12) + "Savings");
1720
+ console.log(" " + "\u2500".repeat(60));
1721
+ for (const r of results) {
1722
+ console.log(` ${r.name}`.padEnd(28) + `${r.raw}`.padEnd(10) + `${r.compressed}`.padEnd(12) + `${r.savings}%`);
1723
+ }
1724
+ const totalRaw = results.reduce((s, r) => s + r.raw, 0);
1725
+ const totalCompressed = results.reduce((s, r) => s + r.compressed, 0);
1726
+ const savings = Math.round((1 - totalCompressed / totalRaw) * 100);
1727
+ console.log("");
1728
+ console.log(` Total: ${totalRaw} \u2192 ${totalCompressed} tokens (${savings}% saved)`);
1729
+ console.log("");
1730
+ }
1731
+ benchmark();
1732
+
1533
1733
  // src/cli/index.ts
1534
1734
  var program = new Command();
1535
1735
  program.name("make-laten").description("Universal efficiency toolkit for AI coding agents").version("1.0.3");
@@ -1545,5 +1745,6 @@ program.command("search").description("Search the web").argument("<query>", "Sea
1545
1745
  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);
1546
1746
  program.command("install").description("Install make-laten across all detected platforms").option("-u, --uninstall", "Remove adapters").option("-s, --status", "Show installation status").action(installCommand);
1547
1747
  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);
1748
+ program.command("benchmark").description("Compare raw vs compressed output").action(void 0);
1548
1749
  program.parse();
1549
1750
  //# sourceMappingURL=index.mjs.map