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