make-laten 1.2.0 → 1.2.1

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.
@@ -406,15 +406,596 @@ var GitStatusCompressor = class {
406
406
  }
407
407
  };
408
408
 
409
+ // src/route/tool-router.ts
410
+ var ToolRouter = class {
411
+ rules = [
412
+ {
413
+ matcher: (input) => input.type === "file",
414
+ compressor: "file-read",
415
+ confidence: 0.95,
416
+ reason: "File read detected"
417
+ },
418
+ {
419
+ matcher: (input) => input.type === "grep",
420
+ compressor: "grep",
421
+ confidence: 0.95,
422
+ reason: "Grep results detected"
423
+ },
424
+ {
425
+ matcher: (input) => input.type === "git-diff",
426
+ compressor: "git-diff",
427
+ confidence: 0.95,
428
+ reason: "Git diff detected"
429
+ }
430
+ ];
431
+ route(input) {
432
+ for (const rule of this.rules) {
433
+ if (rule.matcher(input)) {
434
+ return {
435
+ tool: "compress",
436
+ compressor: rule.compressor,
437
+ confidence: rule.confidence,
438
+ reason: rule.reason
439
+ };
440
+ }
441
+ }
442
+ return {
443
+ tool: "compress",
444
+ confidence: 0.1,
445
+ reason: "No matching route found"
446
+ };
447
+ }
448
+ addRule(rule) {
449
+ this.rules.push(rule);
450
+ }
451
+ };
452
+
453
+ // src/route/strategy-router.ts
454
+ var StrategyRouter = class {
455
+ thresholds = {
456
+ small: 500,
457
+ large: 5e3
458
+ };
459
+ select(context) {
460
+ if (context.userPreference) {
461
+ return {
462
+ strategy: context.userPreference,
463
+ reason: `User preference: ${context.userPreference}`,
464
+ savings: this.estimateSavings(context.userPreference)
465
+ };
466
+ }
467
+ const fileSize = context.fileSize || 0;
468
+ if (fileSize >= this.thresholds.large) {
469
+ return {
470
+ strategy: "aggressive",
471
+ reason: `large file (${fileSize} bytes)`,
472
+ savings: 0.6
473
+ };
474
+ }
475
+ if (fileSize <= this.thresholds.small) {
476
+ return {
477
+ strategy: "conservative",
478
+ reason: `small file (${fileSize} bytes)`,
479
+ savings: 0.2
480
+ };
481
+ }
482
+ return {
483
+ strategy: "balanced",
484
+ reason: `Medium file (${fileSize} bytes)`,
485
+ savings: 0.4
486
+ };
487
+ }
488
+ estimateSavings(strategy) {
489
+ switch (strategy) {
490
+ case "aggressive":
491
+ return 0.6;
492
+ case "balanced":
493
+ return 0.4;
494
+ case "conservative":
495
+ return 0.2;
496
+ }
497
+ }
498
+ };
499
+
500
+ // src/learn/pattern-miner.ts
501
+ var PatternMiner = class {
502
+ operations = [];
503
+ patterns = /* @__PURE__ */ new Map();
504
+ record(operation) {
505
+ this.operations.push(operation);
506
+ if (operation.success) {
507
+ this.updatePatterns(operation);
508
+ }
509
+ }
510
+ getPatterns() {
511
+ return Array.from(this.patterns.values());
512
+ }
513
+ getPatternsByType(type) {
514
+ return this.getPatterns().filter((p) => p.type === type);
515
+ }
516
+ updatePatterns(operation) {
517
+ const key = operation.type;
518
+ const existing = this.patterns.get(key);
519
+ if (existing) {
520
+ existing.count++;
521
+ existing.confidence = Math.min(0.99, existing.confidence + 0.05);
522
+ } else {
523
+ this.patterns.set(key, {
524
+ id: `p${this.patterns.size + 1}`,
525
+ type: operation.type,
526
+ pattern: JSON.stringify(operation.input),
527
+ confidence: 0.5,
528
+ count: 1
529
+ });
530
+ }
531
+ }
532
+ };
533
+
534
+ // src/learn/failure-learner.ts
535
+ var FailureLearner = class {
536
+ failures = /* @__PURE__ */ new Map();
537
+ record(failure) {
538
+ const key = `${failure.type}:${failure.error}`;
539
+ const existing = this.failures.get(key);
540
+ if (existing) {
541
+ existing.count++;
542
+ } else {
543
+ this.failures.set(key, {
544
+ id: `f${this.failures.size + 1}`,
545
+ ...failure,
546
+ timestamp: Date.now(),
547
+ count: 1
548
+ });
549
+ }
550
+ }
551
+ getFailures() {
552
+ return Array.from(this.failures.values());
553
+ }
554
+ getFailuresByType(type) {
555
+ return this.getFailures().filter((f) => f.type === type);
556
+ }
557
+ getSuggestions(type) {
558
+ const failures = Array.from(this.failures.values()).filter((f) => f.type === type);
559
+ const suggestions = [];
560
+ for (const failure of failures) {
561
+ if (failure.error.includes("not found")) {
562
+ suggestions.push("check if file exists before processing");
563
+ }
564
+ if (failure.error.includes("permission")) {
565
+ suggestions.push("verify file permissions");
566
+ }
567
+ if (failure.count > 2) {
568
+ suggestions.push(`recurring issue: ${failure.error}`);
569
+ }
570
+ }
571
+ return [...new Set(suggestions)];
572
+ }
573
+ };
574
+
575
+ // src/correct/auto-correct.ts
576
+ var AutoCorrect = class {
577
+ rules = [];
578
+ corrections = [];
579
+ appliedCount = 0;
580
+ addRule(rule) {
581
+ this.rules.push(rule);
582
+ }
583
+ getRules() {
584
+ return this.rules;
585
+ }
586
+ correct(input) {
587
+ let output = input;
588
+ for (const rule of this.rules) {
589
+ if (typeof rule.pattern === "string") {
590
+ if (output.includes(rule.pattern)) {
591
+ output = output.split(rule.pattern).join(rule.replacement);
592
+ this.recordCorrection(input, output, rule.name);
593
+ }
594
+ } else {
595
+ const matches = output.match(rule.pattern);
596
+ if (matches) {
597
+ output = output.replace(rule.pattern, rule.replacement);
598
+ this.recordCorrection(input, output, rule.name);
599
+ }
600
+ }
601
+ }
602
+ return output;
603
+ }
604
+ getStats() {
605
+ return {
606
+ applied: this.appliedCount,
607
+ corrections: this.corrections
608
+ };
609
+ }
610
+ recordCorrection(original, corrected, ruleName) {
611
+ this.appliedCount++;
612
+ this.corrections.push({
613
+ id: `c${this.corrections.length + 1}`,
614
+ original,
615
+ corrected,
616
+ rule: ruleName,
617
+ confidence: 0.9
618
+ });
619
+ }
620
+ };
621
+
622
+ // src/cache/l1-session.ts
623
+ var SessionCache = class {
624
+ store = /* @__PURE__ */ new Map();
625
+ hits = 0;
626
+ misses = 0;
627
+ get(key) {
628
+ const entry = this.store.get(key);
629
+ if (entry) {
630
+ this.hits++;
631
+ return entry;
632
+ }
633
+ this.misses++;
634
+ return null;
635
+ }
636
+ set(key, value) {
637
+ this.store.set(key, value);
638
+ }
639
+ clear() {
640
+ this.store.clear();
641
+ this.hits = 0;
642
+ this.misses = 0;
643
+ }
644
+ stats() {
645
+ const total = this.hits + this.misses;
646
+ return {
647
+ hits: this.hits,
648
+ misses: this.misses,
649
+ size: this.store.size,
650
+ hitRate: total > 0 ? this.hits / total : 0
651
+ };
652
+ }
653
+ };
654
+
655
+ // src/web/backends/duckduckgo.ts
656
+ var DuckDuckGoBackend = class {
657
+ name = "duckduckgo";
658
+ isAvailable() {
659
+ return true;
660
+ }
661
+ async search(query, options) {
662
+ const maxResults = options?.maxResults || 5;
663
+ const url = `https://html.duckduckgo.com/html/?q=${encodeURIComponent(query)}`;
664
+ const response = await fetch(url, {
665
+ headers: {
666
+ "User-Agent": "Mozilla/5.0 (compatible; make-laten/0.1.0)"
667
+ }
668
+ });
669
+ const html = await response.text();
670
+ return this.parseResults(html, maxResults);
671
+ }
672
+ parseResults(html, maxResults) {
673
+ const results = [];
674
+ const resultRegex = /<a[^>]*class="result__a"[^>]*href="([^"]*)"[^>]*>([\s\S]*?)<\/a>/gi;
675
+ const snippetRegex = /<a[^>]*class="result__snippet"[^>]*>([\s\S]*?)<\/a>/gi;
676
+ let match;
677
+ const urls = [];
678
+ const titles = [];
679
+ while ((match = resultRegex.exec(html)) !== null && urls.length < maxResults) {
680
+ const rawUrl = match[1];
681
+ const urlMatch = rawUrl.match(/uddg=([^&]+)/);
682
+ const url = urlMatch ? decodeURIComponent(urlMatch[1]) : rawUrl;
683
+ const title = this.stripTags(match[2]).trim();
684
+ if (url && title) {
685
+ urls.push(url);
686
+ titles.push(title);
687
+ }
688
+ }
689
+ const snippets = [];
690
+ while ((match = snippetRegex.exec(html)) !== null && snippets.length < maxResults) {
691
+ snippets.push(this.stripTags(match[1]).trim());
692
+ }
693
+ for (let i = 0; i < urls.length; i++) {
694
+ results.push({
695
+ title: titles[i],
696
+ url: urls[i],
697
+ snippet: snippets[i] || "",
698
+ score: 1 - i * 0.1
699
+ });
700
+ }
701
+ return results;
702
+ }
703
+ stripTags(html) {
704
+ return html.replace(/<[^>]+>/g, "").replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&#x27;/g, "'").replace(/&quot;/g, '"');
705
+ }
706
+ };
707
+
708
+ // src/web/backends/index.ts
709
+ function selectBackend(preferred) {
710
+ const backends = [
711
+ new DuckDuckGoBackend()
712
+ ];
713
+ if (preferred) {
714
+ const found = backends.find((b) => b.name === preferred);
715
+ if (found) return found;
716
+ }
717
+ return backends.find((b) => b.isAvailable()) || backends[0];
718
+ }
719
+
720
+ // src/web/extractor.ts
721
+ function stripTags(html) {
722
+ return html.replace(/<[^>]+>/g, "").replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'");
723
+ }
724
+ function extractTitle(html) {
725
+ const titleMatch = html.match(/<title[^>]*>([\s\S]*?)<\/title>/i);
726
+ if (titleMatch) return stripTags(titleMatch[1]).trim();
727
+ const h1Match = html.match(/<h1[^>]*>([\s\S]*?)<\/h1>/i);
728
+ if (h1Match) return stripTags(h1Match[1]).trim();
729
+ return "Untitled";
730
+ }
731
+ function extractSections(html) {
732
+ const sections = [];
733
+ const headingRegex = /<h([1-6])[^>]*>([\s\S]*?)<\/h\1>/gi;
734
+ let match;
735
+ while ((match = headingRegex.exec(html)) !== null) {
736
+ const level = parseInt(match[1]);
737
+ const heading = stripTags(match[2]).trim();
738
+ const startPos = match.index + match[0].length;
739
+ const nextHeading = html.substring(startPos).match(/<h[1-6]/i);
740
+ const endPos = nextHeading ? startPos + nextHeading.index : html.length;
741
+ const content = stripTags(html.substring(startPos, endPos)).trim();
742
+ if (!content) continue;
743
+ const importance = level <= 2 ? "primary" : level <= 4 ? "secondary" : "tertiary";
744
+ sections.push({ heading, level, content, importance });
745
+ }
746
+ return sections;
747
+ }
748
+ function extractCodeExamples(html) {
749
+ const examples = [];
750
+ const codeRegex = /<(?:pre|code)[^>]*>[\s\S]*?<(?:code|\/pre)[^>]*>/gi;
751
+ const blockRegex = /<pre[^>]*><code[^>]*class="[^"]*language-(\w+)[^"]*"[^>]*>([\s\S]*?)<\/code><\/pre>/gi;
752
+ let match;
753
+ while ((match = blockRegex.exec(html)) !== null) {
754
+ const language = match[1];
755
+ const code = stripTags(match[2]).trim();
756
+ if (code.length > 10) {
757
+ examples.push({ language, code });
758
+ }
759
+ }
760
+ const inlineRegex = /<code[^>]*class="[^"]*language-(\w+)[^"]*"[^>]*>([\s\S]*?)<\/code>/gi;
761
+ while ((match = inlineRegex.exec(html)) !== null) {
762
+ const language = match[1];
763
+ const code = stripTags(match[2]).trim();
764
+ if (code.length > 20 && !examples.some((e) => e.code === code)) {
765
+ examples.push({ language, code });
766
+ }
767
+ }
768
+ return examples.slice(0, 10);
769
+ }
770
+ function extractKeyPoints(sections) {
771
+ const keyPoints = [];
772
+ for (const section of sections.filter((s) => s.importance === "primary")) {
773
+ const sentences = section.content.split(/[.!?\n]+/).filter((s) => s.trim().length > 10);
774
+ if (sentences.length > 0) {
775
+ keyPoints.push(sentences[0].trim());
776
+ }
777
+ }
778
+ return keyPoints.slice(0, 5);
779
+ }
780
+ function classifyPurpose(html, sections) {
781
+ const text = (html + " " + sections.map((s) => s.heading).join(" ")).toLowerCase();
782
+ if (text.includes("api reference") || text.includes("endpoint") || text.includes("parameters")) return "reference";
783
+ if (text.includes("tutorial") || text.includes("step by step") || text.includes("getting started")) return "tutorial";
784
+ if (text.includes("blog") || text.includes("published") || text.includes("author")) return "blog";
785
+ if (text.includes("install") || text.includes("quickstart") || text.includes("overview")) return "documentation";
786
+ return "documentation";
787
+ }
788
+ function extractSemantic(html, url) {
789
+ const title = extractTitle(html);
790
+ const sections = extractSections(html);
791
+ const codeExamples = extractCodeExamples(html);
792
+ const keyPoints = extractKeyPoints(sections);
793
+ const purpose = classifyPurpose(html, sections);
794
+ return {
795
+ type: "webpage",
796
+ url,
797
+ title,
798
+ purpose,
799
+ sections,
800
+ keyPoints,
801
+ codeExamples,
802
+ metadata: {
803
+ language: html.match(/lang="(\w+)"/)?.[1] || "en",
804
+ author: html.match(/<meta[^>]*name="author"[^>]*content="([^"]+)"/i)?.[1],
805
+ tags: html.match(/<meta[^>]*name="keywords"[^>]*content="([^"]+)"/i)?.[1]?.split(",").map((t) => t.trim())
806
+ }
807
+ };
808
+ }
809
+
810
+ // src/web/compressor.ts
811
+ function compressWebContent(semantic, options = {}) {
812
+ const { maxTokens = 1e3, includeCode = true, includeSections = "all" } = options;
813
+ const lines = [];
814
+ lines.push(`# ${semantic.title}`);
815
+ lines.push(`URL: ${semantic.url}`);
816
+ lines.push(`Purpose: ${semantic.purpose}`);
817
+ lines.push("");
818
+ if (semantic.keyPoints.length > 0) {
819
+ lines.push("## Key Points");
820
+ for (const point of semantic.keyPoints) {
821
+ lines.push(`- ${point}`);
822
+ }
823
+ lines.push("");
824
+ }
825
+ const filteredSections = filterSections(semantic.sections, includeSections);
826
+ for (const section of filteredSections) {
827
+ const content = truncateContent(section.content, 500);
828
+ lines.push(`## ${section.heading}`);
829
+ lines.push(content);
830
+ lines.push("");
831
+ }
832
+ if (includeCode && semantic.codeExamples.length > 0) {
833
+ const topExamples = semantic.codeExamples.slice(0, 3);
834
+ lines.push("## Code Examples");
835
+ for (const example of topExamples) {
836
+ lines.push(`\`\`\`${example.language}`);
837
+ lines.push(truncateContent(example.code, 300));
838
+ lines.push("```");
839
+ lines.push("");
840
+ }
841
+ }
842
+ let result = lines.join("\n");
843
+ const estimatedTokens = estimateTokens(result);
844
+ if (estimatedTokens > maxTokens) {
845
+ result = truncateByTokens(result, maxTokens);
846
+ }
847
+ return result;
848
+ }
849
+ function filterSections(sections, mode) {
850
+ if (mode === "none") return [];
851
+ if (mode === "primary") return sections.filter((s) => s.importance === "primary");
852
+ return sections;
853
+ }
854
+ function truncateContent(content, maxLength) {
855
+ if (content.length <= maxLength) return content;
856
+ return content.slice(0, maxLength) + "...";
857
+ }
858
+ function estimateTokens(text) {
859
+ return Math.ceil(text.length / 4);
860
+ }
861
+ function truncateByTokens(text, maxTokens) {
862
+ const maxChars = maxTokens * 4;
863
+ if (text.length <= maxChars) return text;
864
+ const truncated = text.slice(0, maxChars);
865
+ const lastNewline = truncated.lastIndexOf("\n");
866
+ return truncated.slice(0, lastNewline > 0 ? lastNewline : maxChars) + "\n\n... (truncated)";
867
+ }
868
+
869
+ // src/web/router.ts
870
+ var WebRouter = class {
871
+ fetchCache = /* @__PURE__ */ new Map();
872
+ searchCache = /* @__PURE__ */ new Map();
873
+ cacheTtl;
874
+ constructor(options) {
875
+ this.cacheTtl = options?.cacheTtlMs || 60 * 60 * 1e3;
876
+ }
877
+ async search(query, options) {
878
+ const cacheKey = `search:${query}:${JSON.stringify(options || {})}`;
879
+ const cached = this.searchCache.get(cacheKey);
880
+ if (cached && this.isFresh(cacheKey)) {
881
+ return cached;
882
+ }
883
+ const backend = selectBackend(options?.backend);
884
+ const results = await backend.search(query, options);
885
+ this.searchCache.set(cacheKey, results);
886
+ this.storeFreshness(cacheKey);
887
+ return results;
888
+ }
889
+ async fetch(url, options) {
890
+ const cacheKey = `fetch:${url}:${options?.format || "text"}`;
891
+ if (options?.cache !== false) {
892
+ const cached = this.fetchCache.get(cacheKey);
893
+ if (cached && this.isFresh(cacheKey)) {
894
+ return cached;
895
+ }
896
+ }
897
+ const startTime = Date.now();
898
+ const response = await fetch(url);
899
+ const html = await response.text();
900
+ const originalSize = html.length;
901
+ let content;
902
+ let semantic = void 0;
903
+ if (options?.extract !== false) {
904
+ semantic = extractSemantic(html, url);
905
+ content = compressWebContent(semantic, {
906
+ includeCode: true,
907
+ includeSections: options?.format === "html" ? "all" : "primary"
908
+ });
909
+ } else {
910
+ content = html;
911
+ }
912
+ const compressedSize = content.length;
913
+ const result = {
914
+ url,
915
+ title: semantic?.title || extractSimpleTitle(html),
916
+ content,
917
+ semantic,
918
+ metadata: {
919
+ fetchTime: Date.now() - startTime,
920
+ originalSize,
921
+ compressedSize,
922
+ savings: 1 - compressedSize / originalSize
923
+ }
924
+ };
925
+ if (options?.cache !== false) {
926
+ this.fetchCache.set(cacheKey, result);
927
+ this.storeFreshness(cacheKey);
928
+ }
929
+ return result;
930
+ }
931
+ async extract(url) {
932
+ return this.fetch(url, { extract: true, compress: true });
933
+ }
934
+ async summarize(content, options) {
935
+ const lines = content.split("\n");
936
+ const summaryLines = [];
937
+ let tokenCount = 0;
938
+ const maxTokens = options?.maxTokens || 200;
939
+ for (const line of lines) {
940
+ const lineTokens = Math.ceil(line.length / 4);
941
+ if (tokenCount + lineTokens > maxTokens) break;
942
+ if (line.startsWith("#") || line.startsWith("-") || line.startsWith("*")) {
943
+ summaryLines.push(line);
944
+ tokenCount += lineTokens;
945
+ }
946
+ }
947
+ if (summaryLines.length === 0 && lines.length > 0) {
948
+ for (const line of lines.slice(0, 5)) {
949
+ const lineTokens = Math.ceil(line.length / 4);
950
+ if (tokenCount + lineTokens > maxTokens) break;
951
+ summaryLines.push(line);
952
+ tokenCount += lineTokens;
953
+ }
954
+ }
955
+ return summaryLines.join("\n");
956
+ }
957
+ clearCache() {
958
+ this.fetchCache.clear();
959
+ this.searchCache.clear();
960
+ }
961
+ getCacheStats() {
962
+ return {
963
+ fetchSize: this.fetchCache.size,
964
+ searchSize: this.searchCache.size
965
+ };
966
+ }
967
+ isFresh(key) {
968
+ const timestamp = this.freshness.get(key);
969
+ if (!timestamp) return false;
970
+ return Date.now() - timestamp < this.cacheTtl;
971
+ }
972
+ storeFreshness(key) {
973
+ this.freshness.set(key, Date.now());
974
+ }
975
+ freshness = /* @__PURE__ */ new Map();
976
+ };
977
+ function extractSimpleTitle(html) {
978
+ const titleMatch = html.match(/<title[^>]*>([\s\S]*?)<\/title>/i);
979
+ return titleMatch ? titleMatch[1].replace(/<[^>]+>/g, "").trim() : "Untitled";
980
+ }
981
+
409
982
  // src/mcp/server.ts
410
983
  var import_child_process = require("child_process");
411
984
  var import_util = require("util");
412
985
  var import_promises = __toESM(require("fs/promises"));
413
986
  var execAsync = (0, import_util.promisify)(import_child_process.exec);
987
+ var sessionCache = new SessionCache();
988
+ var toolRouter = new ToolRouter();
989
+ var strategyRouter = new StrategyRouter();
990
+ var patternMiner = new PatternMiner();
991
+ var failureLearner = new FailureLearner();
992
+ var autoCorrect = new AutoCorrect();
993
+ var webRouter = new WebRouter();
414
994
  var TOOLS = [
995
+ // Compress Layer
415
996
  {
416
997
  name: "make-laten-read",
417
- description: "Read and compress a file (65-90% token savings)",
998
+ description: "Read and compress a file (65-92% token savings)",
418
999
  inputSchema: {
419
1000
  type: "object",
420
1001
  properties: {
@@ -450,10 +1031,127 @@ var TOOLS = [
450
1031
  description: "Compressed git status",
451
1032
  inputSchema: { type: "object", properties: {} }
452
1033
  },
1034
+ // Route Layer
1035
+ {
1036
+ name: "make-laten-route",
1037
+ description: "Route input to correct compressor",
1038
+ inputSchema: {
1039
+ type: "object",
1040
+ properties: {
1041
+ type: { type: "string", enum: ["file", "grep", "git-diff", "unknown"], description: "Input type" },
1042
+ content: { type: "string", description: "Input content" }
1043
+ },
1044
+ required: ["type", "content"]
1045
+ }
1046
+ },
1047
+ {
1048
+ name: "make-laten-strategy",
1049
+ description: "Select compression strategy based on context",
1050
+ inputSchema: {
1051
+ type: "object",
1052
+ properties: {
1053
+ file_size: { type: "number", description: "File size in bytes" },
1054
+ preference: { type: "string", enum: ["aggressive", "balanced", "conservative"], description: "Strategy preference" }
1055
+ }
1056
+ }
1057
+ },
1058
+ // Cache Layer
453
1059
  {
454
1060
  name: "make-laten-cache-stats",
455
1061
  description: "Show cache performance stats",
456
1062
  inputSchema: { type: "object", properties: {} }
1063
+ },
1064
+ {
1065
+ name: "make-laten-cache-get",
1066
+ description: "Get value from session cache",
1067
+ inputSchema: {
1068
+ type: "object",
1069
+ properties: {
1070
+ key: { type: "string", description: "Cache key" }
1071
+ },
1072
+ required: ["key"]
1073
+ }
1074
+ },
1075
+ {
1076
+ name: "make-laten-cache-set",
1077
+ description: "Set value in session cache",
1078
+ inputSchema: {
1079
+ type: "object",
1080
+ properties: {
1081
+ key: { type: "string", description: "Cache key" },
1082
+ value: { type: "string", description: "Value to cache" }
1083
+ },
1084
+ required: ["key", "value"]
1085
+ }
1086
+ },
1087
+ {
1088
+ name: "make-laten-cache-clear",
1089
+ description: "Clear session cache",
1090
+ inputSchema: { type: "object", properties: {} }
1091
+ },
1092
+ // Learn Layer
1093
+ {
1094
+ name: "make-laten-patterns",
1095
+ description: "Get learned patterns from usage",
1096
+ inputSchema: { type: "object", properties: {} }
1097
+ },
1098
+ {
1099
+ name: "make-laten-failures",
1100
+ description: "Get failure records and suggestions",
1101
+ inputSchema: { type: "object", properties: {} }
1102
+ },
1103
+ {
1104
+ name: "make-laten-suggestions",
1105
+ description: "Get suggestions based on learned patterns",
1106
+ inputSchema: {
1107
+ type: "object",
1108
+ properties: {
1109
+ context: { type: "string", description: "Context for suggestions" }
1110
+ }
1111
+ }
1112
+ },
1113
+ // Correct Layer
1114
+ {
1115
+ name: "make-laten-correct",
1116
+ description: "Apply auto-corrections to text",
1117
+ inputSchema: {
1118
+ type: "object",
1119
+ properties: {
1120
+ text: { type: "string", description: "Text to correct" }
1121
+ },
1122
+ required: ["text"]
1123
+ }
1124
+ },
1125
+ // Web Layer
1126
+ {
1127
+ name: "make-laten-search",
1128
+ description: "Search the web with semantic understanding",
1129
+ inputSchema: {
1130
+ type: "object",
1131
+ properties: {
1132
+ query: { type: "string", description: "Search query" },
1133
+ backend: { type: "string", description: "Search backend (duckduckgo, exa, tavily)" }
1134
+ },
1135
+ required: ["query"]
1136
+ }
1137
+ },
1138
+ {
1139
+ name: "make-laten-fetch",
1140
+ description: "Fetch and compress web content",
1141
+ inputSchema: {
1142
+ type: "object",
1143
+ properties: {
1144
+ url: { type: "string", description: "URL to fetch" },
1145
+ extract: { type: "boolean", description: "Extract semantic content", default: true }
1146
+ },
1147
+ required: ["url"]
1148
+ }
1149
+ },
1150
+ // Tool Layer
1151
+ {
1152
+ name: "make-laten-tools",
1153
+ description: "List available make-laten tools",
1154
+ inputSchema: { type: "object", properties: {} }
457
1155
  }
458
1156
  ];
459
1157
  function detectLanguage(filePath) {
@@ -483,9 +1181,9 @@ async function handleRead(params) {
483
1181
  filePath: params.file_path,
484
1182
  language: detectLanguage(params.file_path)
485
1183
  });
486
- return {
487
- content: [{ type: "text", text: JSON.stringify({ compressed: result.content, savings: result.metadata.savings, confidence: result.confidence }) }]
488
- };
1184
+ patternMiner.record({ type: "file-read", input: { file: params.file_path }, success: true });
1185
+ sessionCache.set(`file:${params.file_path}`, { content: result.content, metadata: result.metadata });
1186
+ return { content: [{ type: "text", text: JSON.stringify({ compressed: result.content, savings: result.metadata.savings, confidence: result.confidence }) }] };
489
1187
  }
490
1188
  async function handleGrep(params) {
491
1189
  const dir = params.path || ".";
@@ -499,6 +1197,7 @@ async function handleGrep(params) {
499
1197
  });
500
1198
  const compressor = new GrepCompressor();
501
1199
  const result = await compressor.compress({ results: matches, pattern: params.pattern, directory: dir });
1200
+ patternMiner.record({ type: "grep", input: { pattern: params.pattern, dir }, success: true });
502
1201
  return { content: [{ type: "text", text: JSON.stringify({ compressed: result.content, total: matches.length, savings: result.metadata.savings }) }] };
503
1202
  }
504
1203
  async function handleGitDiff(params) {
@@ -509,6 +1208,7 @@ async function handleGitDiff(params) {
509
1208
  }
510
1209
  const compressor = new GitDiffCompressor();
511
1210
  const result = await compressor.compress({ diff: stdout });
1211
+ patternMiner.record({ type: "git-diff", input: { staged: params.staged }, success: true });
512
1212
  return { content: [{ type: "text", text: JSON.stringify({ compressed: result.content, savings: result.metadata.savings }) }] };
513
1213
  }
514
1214
  async function handleGitStatus() {
@@ -517,15 +1217,89 @@ async function handleGitStatus() {
517
1217
  const result = await compressor.compress({ status: stdout });
518
1218
  return { content: [{ type: "text", text: JSON.stringify({ compressed: result.content, savings: result.metadata.savings }) }] };
519
1219
  }
1220
+ async function handleRoute(params) {
1221
+ const route = toolRouter.route({ type: params.type, content: params.content });
1222
+ return { content: [{ type: "text", text: JSON.stringify(route) }] };
1223
+ }
1224
+ async function handleStrategy(params) {
1225
+ const strategy = strategyRouter.select({
1226
+ fileSize: params.file_size,
1227
+ userPreference: params.preference
1228
+ });
1229
+ return { content: [{ type: "text", text: JSON.stringify(strategy) }] };
1230
+ }
520
1231
  async function handleCacheStats() {
521
- return { content: [{ type: "text", text: JSON.stringify({ message: "Cache stats \u2014 use CLI: make-laten cache stats" }) }] };
1232
+ const stats = sessionCache.stats();
1233
+ return { content: [{ type: "text", text: JSON.stringify(stats) }] };
1234
+ }
1235
+ async function handleCacheGet(params) {
1236
+ const entry = sessionCache.get(params.key);
1237
+ return { content: [{ type: "text", text: JSON.stringify({ found: !!entry, entry }) }] };
1238
+ }
1239
+ async function handleCacheSet(params) {
1240
+ sessionCache.set(params.key, { content: params.value, metadata: { setAt: Date.now() } });
1241
+ return { content: [{ type: "text", text: JSON.stringify({ success: true }) }] };
1242
+ }
1243
+ async function handleCacheClear() {
1244
+ sessionCache.clear();
1245
+ return { content: [{ type: "text", text: JSON.stringify({ success: true }) }] };
1246
+ }
1247
+ async function handlePatterns() {
1248
+ const patterns = patternMiner.getPatterns();
1249
+ return { content: [{ type: "text", text: JSON.stringify({ patterns, total: patterns.length }) }] };
1250
+ }
1251
+ async function handleFailures() {
1252
+ const failures = failureLearner.getFailures();
1253
+ return { content: [{ type: "text", text: JSON.stringify({ failures, total: failures.length }) }] };
1254
+ }
1255
+ async function handleSuggestions(params) {
1256
+ const patterns = patternMiner.getPatterns();
1257
+ const failures = failureLearner.getFailures();
1258
+ const suggestions = [];
1259
+ for (const pattern of patterns.slice(0, 5)) {
1260
+ suggestions.push(`Pattern: ${pattern.type} (confidence: ${pattern.confidence})`);
1261
+ }
1262
+ for (const failure of failures.slice(0, 5)) {
1263
+ const failureSuggestions = failureLearner.getSuggestions(failure.type);
1264
+ suggestions.push(...failureSuggestions);
1265
+ }
1266
+ return { content: [{ type: "text", text: JSON.stringify({ suggestions: [...new Set(suggestions)] }) }] };
1267
+ }
1268
+ async function handleCorrect(params) {
1269
+ const corrected = autoCorrect.correct(params.text);
1270
+ const stats = autoCorrect.getStats();
1271
+ return { content: [{ type: "text", text: JSON.stringify({ original: params.text, corrected, corrections: stats.applied }) }] };
1272
+ }
1273
+ async function handleSearch(params) {
1274
+ const results = await webRouter.search(params.query, { backend: params.backend });
1275
+ return { content: [{ type: "text", text: JSON.stringify({ results, total: results.length }) }] };
1276
+ }
1277
+ async function handleFetch(params) {
1278
+ const result = await webRouter.fetch(params.url, { extract: params.extract !== false });
1279
+ return { content: [{ type: "text", text: JSON.stringify({ url: result.url, title: result.title, content: result.content, savings: result.metadata.savings }) }] };
1280
+ }
1281
+ async function handleTools() {
1282
+ const tools = TOOLS.map((t) => ({ name: t.name, description: t.description }));
1283
+ return { content: [{ type: "text", text: JSON.stringify({ tools, total: tools.length }) }] };
522
1284
  }
523
1285
  var handlers = {
524
1286
  "make-laten-read": handleRead,
525
1287
  "make-laten-grep": handleGrep,
526
1288
  "make-laten-git-diff": handleGitDiff,
527
1289
  "make-laten-git-status": handleGitStatus,
528
- "make-laten-cache-stats": handleCacheStats
1290
+ "make-laten-route": handleRoute,
1291
+ "make-laten-strategy": handleStrategy,
1292
+ "make-laten-cache-stats": handleCacheStats,
1293
+ "make-laten-cache-get": handleCacheGet,
1294
+ "make-laten-cache-set": handleCacheSet,
1295
+ "make-laten-cache-clear": handleCacheClear,
1296
+ "make-laten-patterns": handlePatterns,
1297
+ "make-laten-failures": handleFailures,
1298
+ "make-laten-suggestions": handleSuggestions,
1299
+ "make-laten-correct": handleCorrect,
1300
+ "make-laten-search": handleSearch,
1301
+ "make-laten-fetch": handleFetch,
1302
+ "make-laten-tools": handleTools
529
1303
  };
530
1304
  function sendResponse(id, result) {
531
1305
  const response = { jsonrpc: "2.0", id, result };
@@ -542,7 +1316,7 @@ async function handleLine(line) {
542
1316
  sendResponse(request.id, {
543
1317
  protocolVersion: "2024-11-05",
544
1318
  capabilities: { tools: {} },
545
- serverInfo: { name: "make-laten", version: "1.0.0" }
1319
+ serverInfo: { name: "make-laten", version: "1.2.0" }
546
1320
  });
547
1321
  } else if (request.method === "notifications/initialized") {
548
1322
  } else if (request.method === "tools/list") {
@@ -558,6 +1332,7 @@ async function handleLine(line) {
558
1332
  const result = await handler(params || {});
559
1333
  sendResponse(request.id, result);
560
1334
  } catch (error) {
1335
+ failureLearner.record({ type: name, error: error.message, success: false });
561
1336
  sendError(request.id, -32e3, error.message);
562
1337
  }
563
1338
  } else {
@@ -580,5 +1355,5 @@ process.stdin.on("data", async (chunk) => {
580
1355
  }
581
1356
  }
582
1357
  });
583
- process.stderr.write("make-laten MCP server started\n");
1358
+ process.stderr.write("make-laten MCP server started (17 tools)\n");
584
1359
  //# sourceMappingURL=server.js.map