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/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 signatures = this.extractSignatures(content, language);
66
- const exports2 = this.extractExports(content);
67
- const lines = [
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
- ...exports2
74
- ];
75
- const compressed = lines.join("\n");
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: "signatures",
197
+ strategy: "hybrid",
82
198
  originalLines: content.split("\n").length,
83
- compressedLines: lines.length,
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 hunks = this.parseDiff(diff);
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
- for (const hunk of condensed) {
283
- if (hunk.changes.length > 0) {
284
- lines.push(`${hunk.file} (+${hunk.stats.additions} -${hunk.stats.deletions})`);
285
- lines.push(...hunk.changes);
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: condensed.length,
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 hunks = [];
397
+ const files = [];
305
398
  const lines = diff.split("\n");
306
- let currentHunk = null;
399
+ let current = null;
307
400
  for (const line of lines) {
308
401
  if (line.startsWith("diff --git")) {
309
- if (currentHunk) hunks.push(currentHunk);
310
- const fileMatch = line.match(/b\/(.+)/);
311
- currentHunk = {
312
- file: fileMatch?.[1] || "unknown",
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 (currentHunk) {
410
+ } else if (current) {
318
411
  if (line.startsWith("+")) {
319
- currentHunk.additions++;
320
- currentHunk.lines.push({ type: "addition", content: line.slice(1) });
412
+ current.additions++;
413
+ current.lines.push({ type: "add", content: line.slice(1) });
321
414
  } else if (line.startsWith("-")) {
322
- currentHunk.deletions++;
323
- currentHunk.lines.push({ type: "deletion", content: line.slice(1) });
415
+ current.deletions++;
416
+ current.lines.push({ type: "del", content: line.slice(1) });
324
417
  }
325
418
  }
326
419
  }
327
- if (currentHunk) hunks.push(currentHunk);
328
- return hunks;
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(claudeDir),
1360
- configPath: claudeConfig,
1361
- mcpConfig: {
1362
- mcpServers: {
1363
- "make-laten": { command: "npx", args: ["-y", "make-laten-mcp", "server"] }
1364
- }
1365
- },
1366
- version: await commandExists2("claude") ? await execAsync4("claude --version", { timeout: 3e3 }).then((r) => r.stdout.trim().split("\n")[0]).catch(() => "unknown") : void 0
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(cursorDir),
1373
- configPath: cursorMcp,
1374
- mcpConfig: {
1375
- mcpServers: {
1376
- "make-laten": { command: "npx", args: ["-y", "make-laten-mcp", "server"] }
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(codexDir),
1385
- configPath: codexMcp,
1386
- mcpConfig: {
1387
- mcpServers: {
1388
- "make-laten": { command: "npx", args: ["-y", "make-laten-mcp", "server"] }
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: "Windsurf",
1396
- detected: await directoryExists(windsurfDir),
1397
- configPath: windsurfMcp,
1398
- mcpConfig: {
1399
- mcpServers: {
1400
- "make-laten": { command: "npx", args: ["-y", "make-laten-mcp", "server"] }
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: "OpenCode",
1408
- detected: await directoryExists(openCodeDir),
1409
- configPath: openCodeConfig,
1410
- mcpConfig: {
1411
- mcpServers: {
1412
- "make-laten": { command: "npx", args: ["-y", "make-laten-mcp", "server"] }
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(clineDir),
1421
- configPath: clineMcp,
1422
- mcpConfig: {
1423
- mcpServers: {
1424
- "make-laten": { command: "npx", args: ["-y", "make-laten-mcp", "server"] }
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(geminiDir),
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
- mcpConfig: {
1441
- mcpServers: {
1442
- "make-laten": { command: "npx", args: ["-y", "make-laten-mcp", "server"] }
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 writeMCPConfig(agent);
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
- let existing = {};
1513
- try {
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 writeMCPConfig(agent);
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