make-laten 1.2.0 → 1.2.2

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
@@ -1695,36 +1695,284 @@ var GitStatusCompressor = class {
1695
1695
  }
1696
1696
  };
1697
1697
 
1698
+ // src/route/tool-router.ts
1699
+ var ToolRouter = class {
1700
+ rules = [
1701
+ {
1702
+ matcher: (input) => input.type === "file",
1703
+ compressor: "file-read",
1704
+ confidence: 0.95,
1705
+ reason: "File read detected"
1706
+ },
1707
+ {
1708
+ matcher: (input) => input.type === "grep",
1709
+ compressor: "grep",
1710
+ confidence: 0.95,
1711
+ reason: "Grep results detected"
1712
+ },
1713
+ {
1714
+ matcher: (input) => input.type === "git-diff",
1715
+ compressor: "git-diff",
1716
+ confidence: 0.95,
1717
+ reason: "Git diff detected"
1718
+ }
1719
+ ];
1720
+ route(input) {
1721
+ for (const rule of this.rules) {
1722
+ if (rule.matcher(input)) {
1723
+ return {
1724
+ tool: "compress",
1725
+ compressor: rule.compressor,
1726
+ confidence: rule.confidence,
1727
+ reason: rule.reason
1728
+ };
1729
+ }
1730
+ }
1731
+ return {
1732
+ tool: "compress",
1733
+ confidence: 0.1,
1734
+ reason: "No matching route found"
1735
+ };
1736
+ }
1737
+ addRule(rule) {
1738
+ this.rules.push(rule);
1739
+ }
1740
+ };
1741
+
1742
+ // src/route/strategy-router.ts
1743
+ var StrategyRouter = class {
1744
+ thresholds = {
1745
+ small: 500,
1746
+ large: 5e3
1747
+ };
1748
+ select(context) {
1749
+ if (context.userPreference) {
1750
+ return {
1751
+ strategy: context.userPreference,
1752
+ reason: `User preference: ${context.userPreference}`,
1753
+ savings: this.estimateSavings(context.userPreference)
1754
+ };
1755
+ }
1756
+ const fileSize = context.fileSize || 0;
1757
+ if (fileSize >= this.thresholds.large) {
1758
+ return {
1759
+ strategy: "aggressive",
1760
+ reason: `large file (${fileSize} bytes)`,
1761
+ savings: 0.6
1762
+ };
1763
+ }
1764
+ if (fileSize <= this.thresholds.small) {
1765
+ return {
1766
+ strategy: "conservative",
1767
+ reason: `small file (${fileSize} bytes)`,
1768
+ savings: 0.2
1769
+ };
1770
+ }
1771
+ return {
1772
+ strategy: "balanced",
1773
+ reason: `Medium file (${fileSize} bytes)`,
1774
+ savings: 0.4
1775
+ };
1776
+ }
1777
+ estimateSavings(strategy) {
1778
+ switch (strategy) {
1779
+ case "aggressive":
1780
+ return 0.6;
1781
+ case "balanced":
1782
+ return 0.4;
1783
+ case "conservative":
1784
+ return 0.2;
1785
+ }
1786
+ }
1787
+ };
1788
+
1789
+ // src/learn/pattern-miner.ts
1790
+ var PatternMiner = class {
1791
+ operations = [];
1792
+ patterns = /* @__PURE__ */ new Map();
1793
+ record(operation) {
1794
+ this.operations.push(operation);
1795
+ if (operation.success) {
1796
+ this.updatePatterns(operation);
1797
+ }
1798
+ }
1799
+ getPatterns() {
1800
+ return Array.from(this.patterns.values());
1801
+ }
1802
+ getPatternsByType(type) {
1803
+ return this.getPatterns().filter((p) => p.type === type);
1804
+ }
1805
+ updatePatterns(operation) {
1806
+ const key = operation.type;
1807
+ const existing = this.patterns.get(key);
1808
+ if (existing) {
1809
+ existing.count++;
1810
+ existing.confidence = Math.min(0.99, existing.confidence + 0.05);
1811
+ } else {
1812
+ this.patterns.set(key, {
1813
+ id: `p${this.patterns.size + 1}`,
1814
+ type: operation.type,
1815
+ pattern: JSON.stringify(operation.input),
1816
+ confidence: 0.5,
1817
+ count: 1
1818
+ });
1819
+ }
1820
+ }
1821
+ };
1822
+
1823
+ // src/learn/failure-learner.ts
1824
+ var FailureLearner = class {
1825
+ failures = /* @__PURE__ */ new Map();
1826
+ record(failure) {
1827
+ const key = `${failure.type}:${failure.error}`;
1828
+ const existing = this.failures.get(key);
1829
+ if (existing) {
1830
+ existing.count++;
1831
+ } else {
1832
+ this.failures.set(key, {
1833
+ id: `f${this.failures.size + 1}`,
1834
+ ...failure,
1835
+ timestamp: Date.now(),
1836
+ count: 1
1837
+ });
1838
+ }
1839
+ }
1840
+ getFailures() {
1841
+ return Array.from(this.failures.values());
1842
+ }
1843
+ getFailuresByType(type) {
1844
+ return this.getFailures().filter((f) => f.type === type);
1845
+ }
1846
+ getSuggestions(type) {
1847
+ const failures = Array.from(this.failures.values()).filter((f) => f.type === type);
1848
+ const suggestions = [];
1849
+ for (const failure of failures) {
1850
+ if (failure.error.includes("not found")) {
1851
+ suggestions.push("check if file exists before processing");
1852
+ }
1853
+ if (failure.error.includes("permission")) {
1854
+ suggestions.push("verify file permissions");
1855
+ }
1856
+ if (failure.count > 2) {
1857
+ suggestions.push(`recurring issue: ${failure.error}`);
1858
+ }
1859
+ }
1860
+ return [...new Set(suggestions)];
1861
+ }
1862
+ };
1863
+
1864
+ // src/correct/auto-correct.ts
1865
+ var AutoCorrect = class {
1866
+ rules = [];
1867
+ corrections = [];
1868
+ appliedCount = 0;
1869
+ addRule(rule) {
1870
+ this.rules.push(rule);
1871
+ }
1872
+ getRules() {
1873
+ return this.rules;
1874
+ }
1875
+ correct(input) {
1876
+ let output = input;
1877
+ for (const rule of this.rules) {
1878
+ if (typeof rule.pattern === "string") {
1879
+ if (output.includes(rule.pattern)) {
1880
+ output = output.split(rule.pattern).join(rule.replacement);
1881
+ this.recordCorrection(input, output, rule.name);
1882
+ }
1883
+ } else {
1884
+ const matches = output.match(rule.pattern);
1885
+ if (matches) {
1886
+ output = output.replace(rule.pattern, rule.replacement);
1887
+ this.recordCorrection(input, output, rule.name);
1888
+ }
1889
+ }
1890
+ }
1891
+ return output;
1892
+ }
1893
+ getStats() {
1894
+ return {
1895
+ applied: this.appliedCount,
1896
+ corrections: this.corrections
1897
+ };
1898
+ }
1899
+ recordCorrection(original, corrected, ruleName) {
1900
+ this.appliedCount++;
1901
+ this.corrections.push({
1902
+ id: `c${this.corrections.length + 1}`,
1903
+ original,
1904
+ corrected,
1905
+ rule: ruleName,
1906
+ confidence: 0.9
1907
+ });
1908
+ }
1909
+ };
1910
+
1698
1911
  // src/cli/commands/benchmark.ts
1699
1912
  var import_fs = __toESM(require("fs"));
1700
1913
  var import_path3 = __toESM(require("path"));
1701
1914
  var import_child_process5 = require("child_process");
1915
+ function countTokens(text) {
1916
+ return Math.ceil(text.length / 4);
1917
+ }
1702
1918
  async function benchmark() {
1703
- const fileCompressor = new FileReadCompressor();
1704
- const diffCompressor = new GitDiffCompressor();
1705
- const statusCompressor = new GitStatusCompressor();
1706
1919
  const projectPath = process.cwd();
1707
1920
  console.log("");
1708
- console.log(" make-laten benchmark");
1709
- console.log(" ===================");
1921
+ console.log(" make-laten benchmark (17 tools)");
1922
+ console.log(" ================================");
1710
1923
  console.log("");
1711
1924
  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) });
1925
+ console.log(" Compress Layer");
1926
+ console.log(" " + "\u2500".repeat(50));
1927
+ const smallFile = import_path3.default.join(projectPath, "src/index.ts");
1928
+ if (import_fs.default.existsSync(smallFile)) {
1929
+ const content = import_fs.default.readFileSync(smallFile, "utf-8");
1930
+ const raw = countTokens(content);
1931
+ const compressor = new FileReadCompressor();
1932
+ const result = await compressor.compress({ content, filePath: "src/index.ts" });
1933
+ const compressed = countTokens(result.content);
1934
+ results.push({ name: "read (small)", raw, compressed, savings: Math.round((1 - compressed / raw) * 100) });
1935
+ }
1936
+ const mediumFile = import_path3.default.join(projectPath, "src/mcp/server.ts");
1937
+ if (import_fs.default.existsSync(mediumFile)) {
1938
+ const content = import_fs.default.readFileSync(mediumFile, "utf-8");
1939
+ const raw = countTokens(content);
1940
+ const compressor = new FileReadCompressor();
1941
+ const result = await compressor.compress({ content, filePath: "src/mcp/server.ts" });
1942
+ const compressed = countTokens(result.content);
1943
+ results.push({ name: "read (medium)", raw, compressed, savings: Math.round((1 - compressed / raw) * 100) });
1944
+ }
1945
+ const largeFile = import_path3.default.join(projectPath, "README.md");
1946
+ if (import_fs.default.existsSync(largeFile)) {
1947
+ const content = import_fs.default.readFileSync(largeFile, "utf-8");
1948
+ const raw = countTokens(content);
1949
+ const compressor = new FileReadCompressor();
1950
+ const result = await compressor.compress({ content, filePath: "README.md" });
1951
+ const compressed = countTokens(result.content);
1952
+ results.push({ name: "read (large)", raw, compressed, savings: Math.round((1 - compressed / raw) * 100) });
1953
+ }
1954
+ try {
1955
+ const grepResult = (0, import_child_process5.execSync)('grep -rn "export" src/ 2>/dev/null | head -30', { cwd: projectPath, encoding: "utf-8" }).trim();
1956
+ if (grepResult) {
1957
+ const raw = countTokens(grepResult);
1958
+ const matches = grepResult.split("\n").filter(Boolean).map((line) => {
1959
+ const parts = line.split(":");
1960
+ return { file: parts[0], line: parseInt(parts[1], 10) || 0, content: parts.slice(2).join(":").trim() };
1961
+ });
1962
+ const compressor = new GrepCompressor();
1963
+ const result = await compressor.compress({ results: matches, pattern: "export", directory: "src/" });
1964
+ const compressed = countTokens(result.content);
1965
+ results.push({ name: "grep", raw, compressed, savings: Math.round((1 - compressed / raw) * 100) });
1966
+ }
1967
+ } catch {
1721
1968
  }
1722
1969
  try {
1723
1970
  const diff = (0, import_child_process5.execSync)('git diff HEAD~1 2>/dev/null || echo ""', { cwd: projectPath, encoding: "utf-8" }).trim();
1724
1971
  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);
1972
+ const raw = countTokens(diff);
1973
+ const compressor = new GitDiffCompressor();
1974
+ const result = await compressor.compress({ diff });
1975
+ const compressed = countTokens(result.content);
1728
1976
  results.push({ name: "git-diff", raw, compressed, savings: Math.round((1 - compressed / raw) * 100) });
1729
1977
  }
1730
1978
  } catch {
@@ -1732,23 +1980,108 @@ async function benchmark() {
1732
1980
  try {
1733
1981
  const status = (0, import_child_process5.execSync)('git status --porcelain 2>/dev/null || echo ""', { cwd: projectPath, encoding: "utf-8" }).trim();
1734
1982
  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);
1983
+ const raw = countTokens(status);
1984
+ const compressor = new GitStatusCompressor();
1985
+ const result = await compressor.compress({ status });
1986
+ const compressed = countTokens(result.content);
1738
1987
  results.push({ name: "git-status", raw, compressed, savings: Math.round((1 - compressed / raw) * 100) });
1739
1988
  }
1740
1989
  } catch {
1741
1990
  }
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}%`);
1991
+ console.log("");
1992
+ console.log(" Route Layer");
1993
+ console.log(" " + "\u2500".repeat(50));
1994
+ const router = new ToolRouter();
1995
+ const strategyRouter = new StrategyRouter();
1996
+ const routeTests = [
1997
+ { type: "file", content: "test" },
1998
+ { type: "grep", content: "test" },
1999
+ { type: "git-diff", content: "test" }
2000
+ ];
2001
+ for (const test of routeTests) {
2002
+ const route = router.route(test);
2003
+ console.log(` route(${test.type}) \u2192 ${route.compressor || "none"} (${Math.round(route.confidence * 100)}%)`);
2004
+ }
2005
+ const strategies = [
2006
+ { fileSize: 100, pref: void 0 },
2007
+ { fileSize: 1e3, pref: void 0 },
2008
+ { fileSize: 1e4, pref: void 0 },
2009
+ { fileSize: 0, pref: "aggressive" }
2010
+ ];
2011
+ for (const s of strategies) {
2012
+ const strategy = strategyRouter.select({ fileSize: s.fileSize, userPreference: s.pref });
2013
+ console.log(` strategy(${s.fileSize || s.pref}) \u2192 ${strategy.strategy} (savings: ${Math.round(strategy.savings * 100)}%)`);
2014
+ }
2015
+ console.log("");
2016
+ console.log(" Cache Layer");
2017
+ console.log(" " + "\u2500".repeat(50));
2018
+ const cache = new SessionCache();
2019
+ cache.set("test:key1", { content: "value1", metadata: {} });
2020
+ cache.set("test:key2", { content: "value2", metadata: {} });
2021
+ cache.get("test:key1");
2022
+ cache.get("test:key1");
2023
+ cache.get("test:key2");
2024
+ cache.get("test:miss");
2025
+ const cacheStats = cache.stats();
2026
+ console.log(` L1 Session: ${cacheStats.size} entries, ${cacheStats.hits} hits, ${cacheStats.misses} misses, ${Math.round(cacheStats.hitRate * 100)}% hit rate`);
2027
+ console.log("");
2028
+ console.log(" Learn Layer");
2029
+ console.log(" " + "\u2500".repeat(50));
2030
+ const miner = new PatternMiner();
2031
+ miner.record({ type: "file-read", input: { file: "a.ts" }, success: true });
2032
+ miner.record({ type: "file-read", input: { file: "b.ts" }, success: true });
2033
+ miner.record({ type: "grep", input: { pattern: "test" }, success: true });
2034
+ miner.record({ type: "git-diff", input: {}, success: true });
2035
+ const learner = new FailureLearner();
2036
+ learner.record({ type: "file-read", error: "File not found", success: false });
2037
+ learner.record({ type: "grep", error: "Permission denied", success: false });
2038
+ const patterns = miner.getPatterns();
2039
+ const failures = learner.getFailures();
2040
+ console.log(` Patterns: ${patterns.length} learned`);
2041
+ for (const p of patterns.slice(0, 3)) {
2042
+ console.log(` - ${p.type}: confidence ${Math.round(p.confidence * 100)}%, count ${p.count}`);
2043
+ }
2044
+ console.log(` Failures: ${failures.length} recorded`);
2045
+ for (const f of failures.slice(0, 3)) {
2046
+ const suggestions = learner.getSuggestions(f.type);
2047
+ console.log(` - ${f.type}: ${f.error} \u2192 ${suggestions[0] || "none"}`);
1746
2048
  }
2049
+ console.log("");
2050
+ console.log(" Correct Layer");
2051
+ console.log(" " + "\u2500".repeat(50));
2052
+ const correct = new AutoCorrect();
2053
+ correct.addRule({ name: "typo", description: "Fix common typo", pattern: "teh", replacement: "the" });
2054
+ correct.addRule({ name: "typo2", description: "Fix common typo", pattern: "adn", replacement: "and" });
2055
+ const testText = "teh quick brown fox adn teh cat";
2056
+ const corrected = correct.correct(testText);
2057
+ const correctStats = correct.getStats();
2058
+ console.log(` Input: "${testText}"`);
2059
+ console.log(` Output: "${corrected}"`);
2060
+ console.log(` Corrections applied: ${correctStats.applied}`);
2061
+ console.log("");
2062
+ console.log(" Web Layer");
2063
+ console.log(" " + "\u2500".repeat(50));
2064
+ const webRouter = new WebRouter();
2065
+ const webStats = webRouter.getCacheStats();
2066
+ console.log(` Cache: ${webStats.fetchSize} fetch, ${webStats.searchSize} search`);
2067
+ console.log(` Backends: duckduckgo (default)`);
2068
+ console.log(` Features: semantic extraction, compression, caching`);
2069
+ console.log("");
2070
+ console.log(" Summary");
2071
+ console.log(" " + "\u2500".repeat(50));
1747
2072
  const totalRaw = results.reduce((s, r) => s + r.raw, 0);
1748
2073
  const totalCompressed = results.reduce((s, r) => s + r.compressed, 0);
1749
2074
  const savings = Math.round((1 - totalCompressed / totalRaw) * 100);
2075
+ console.log(" Command".padEnd(20) + "Raw".padEnd(10) + "Compressed".padEnd(12) + "Savings");
2076
+ console.log(" " + "\u2500".repeat(50));
2077
+ for (const r of results) {
2078
+ console.log(` ${r.name}`.padEnd(20) + `${r.raw}`.padEnd(10) + `${r.compressed}`.padEnd(12) + `${r.savings}%`);
2079
+ }
2080
+ console.log(" " + "\u2500".repeat(50));
2081
+ console.log(` ${"Total".padEnd(20)}${totalRaw}`.padEnd(10) + `${totalCompressed}`.padEnd(12) + `${savings}%`);
1750
2082
  console.log("");
1751
- console.log(` Total: ${totalRaw} \u2192 ${totalCompressed} tokens (${savings}% saved)`);
2083
+ console.log(` 17 tools exposed via MCP`);
2084
+ console.log(` 4 layers: compress, route, cache, learn`);
1752
2085
  console.log("");
1753
2086
  }
1754
2087
  benchmark();