make-laten 1.0.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/index.mjs ADDED
@@ -0,0 +1,1946 @@
1
+ // src/graph/database.ts
2
+ import Database from "better-sqlite3";
3
+ var SCHEMA = `
4
+ CREATE TABLE IF NOT EXISTS nodes (
5
+ id TEXT PRIMARY KEY,
6
+ type TEXT NOT NULL,
7
+ content TEXT NOT NULL,
8
+ original TEXT,
9
+ embedding BLOB,
10
+ metadata TEXT NOT NULL DEFAULT '{}',
11
+ created_at INTEGER NOT NULL DEFAULT (unixepoch()),
12
+ accessed_at INTEGER NOT NULL DEFAULT (unixepoch()),
13
+ access_count INTEGER DEFAULT 0
14
+ );
15
+
16
+ CREATE TABLE IF NOT EXISTS edges (
17
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
18
+ source TEXT NOT NULL,
19
+ target TEXT NOT NULL,
20
+ type TEXT NOT NULL,
21
+ weight REAL DEFAULT 1.0,
22
+ metadata TEXT,
23
+ created_at INTEGER NOT NULL DEFAULT (unixepoch()),
24
+ FOREIGN KEY (source) REFERENCES nodes(id),
25
+ FOREIGN KEY (target) REFERENCES nodes(id)
26
+ );
27
+
28
+ CREATE INDEX IF NOT EXISTS idx_nodes_type ON nodes(type);
29
+ CREATE INDEX IF NOT EXISTS idx_nodes_created ON nodes(created_at);
30
+ CREATE INDEX IF NOT EXISTS idx_nodes_accessed ON nodes(accessed_at);
31
+ CREATE INDEX IF NOT EXISTS idx_edges_source ON edges(source);
32
+ CREATE INDEX IF NOT EXISTS idx_edges_target ON edges(target);
33
+ CREATE INDEX IF NOT EXISTS idx_edges_type ON edges(type);
34
+ `;
35
+ async function createDatabase(dbPath) {
36
+ const db = new Database(dbPath);
37
+ db.pragma("journal_mode = WAL");
38
+ db.pragma("foreign_keys = ON");
39
+ db.exec(SCHEMA);
40
+ return db;
41
+ }
42
+
43
+ // src/graph/edges.ts
44
+ var EdgeStore = class {
45
+ constructor(db) {
46
+ this.db = db;
47
+ }
48
+ db;
49
+ async add(edge) {
50
+ this.db.prepare(`
51
+ INSERT INTO edges (source, target, type, weight, metadata)
52
+ VALUES (?, ?, ?, ?, ?)
53
+ `).run(
54
+ edge.source,
55
+ edge.target,
56
+ edge.type,
57
+ edge.weight,
58
+ edge.metadata ? JSON.stringify(edge.metadata) : null
59
+ );
60
+ }
61
+ async getFrom(source, type) {
62
+ let query = "SELECT * FROM edges WHERE source = ?";
63
+ const params = [source];
64
+ if (type) {
65
+ query += " AND type = ?";
66
+ params.push(type);
67
+ }
68
+ const rows = this.db.prepare(query).all(...params);
69
+ return rows.map((row) => this.hydrate(row));
70
+ }
71
+ async getTo(target, type) {
72
+ let query = "SELECT * FROM edges WHERE target = ?";
73
+ const params = [target];
74
+ if (type) {
75
+ query += " AND type = ?";
76
+ params.push(type);
77
+ }
78
+ const rows = this.db.prepare(query).all(...params);
79
+ return rows.map((row) => this.hydrate(row));
80
+ }
81
+ async delete(source, target) {
82
+ this.db.prepare("DELETE FROM edges WHERE source = ? AND target = ?").run(source, target);
83
+ }
84
+ hydrate(row) {
85
+ return {
86
+ id: row.id,
87
+ source: row.source,
88
+ target: row.target,
89
+ type: row.type,
90
+ weight: row.weight,
91
+ metadata: row.metadata ? JSON.parse(row.metadata) : void 0,
92
+ createdAt: row.created_at
93
+ };
94
+ }
95
+ };
96
+
97
+ // src/graph/nodes.ts
98
+ var NodeStore = class {
99
+ constructor(db) {
100
+ this.db = db;
101
+ }
102
+ db;
103
+ async upsert(node) {
104
+ const stmt = this.db.prepare(`
105
+ INSERT INTO nodes (id, type, content, original, metadata, created_at, accessed_at, access_count)
106
+ VALUES (?, ?, ?, ?, ?, unixepoch(), unixepoch(), 1)
107
+ ON CONFLICT(id) DO UPDATE SET
108
+ content = excluded.content,
109
+ original = excluded.original,
110
+ metadata = excluded.metadata,
111
+ accessed_at = unixepoch(),
112
+ access_count = access_count + 1
113
+ `);
114
+ stmt.run(
115
+ node.id,
116
+ node.type,
117
+ node.content,
118
+ node.original || null,
119
+ JSON.stringify(node.metadata || {})
120
+ );
121
+ }
122
+ async get(id) {
123
+ this.db.prepare(`
124
+ UPDATE nodes SET accessed_at = unixepoch(), access_count = access_count + 1
125
+ WHERE id = ?
126
+ `).run(id);
127
+ const row = this.db.prepare("SELECT * FROM nodes WHERE id = ?").get(id);
128
+ if (!row) return null;
129
+ return this.hydrate(row);
130
+ }
131
+ async delete(id) {
132
+ this.db.prepare("DELETE FROM edges WHERE source = ? OR target = ?").run(id, id);
133
+ this.db.prepare("DELETE FROM nodes WHERE id = ?").run(id);
134
+ }
135
+ async listByType(type) {
136
+ const rows = this.db.prepare("SELECT * FROM nodes WHERE type = ?").all(type);
137
+ return rows.map((row) => this.hydrate(row));
138
+ }
139
+ hydrate(row) {
140
+ return {
141
+ id: row.id,
142
+ type: row.type,
143
+ content: row.content,
144
+ original: row.original || void 0,
145
+ embedding: row.embedding || void 0,
146
+ metadata: JSON.parse(row.metadata),
147
+ createdAt: row.created_at,
148
+ accessedAt: row.accessed_at,
149
+ accessCount: row.access_count
150
+ };
151
+ }
152
+ };
153
+
154
+ // src/compress/confidence.ts
155
+ function calculateConfidence(original, compressed) {
156
+ if (!original.length) return 0;
157
+ let score = 1;
158
+ const ratio = compressed.length / original.length;
159
+ if (ratio < 0.01) score -= 0.5;
160
+ else if (ratio < 0.05) score -= 0.3;
161
+ if (codeBlocksModified(original, compressed)) score -= 0.4;
162
+ if (isKnownPattern(original)) score += 0.1;
163
+ return Math.max(0, Math.min(1, score));
164
+ }
165
+ function codeBlocksModified(original, compressed) {
166
+ const codeBlockRegex = /```[\s\S]*?```/g;
167
+ const originalBlocks = original.match(codeBlockRegex) || [];
168
+ const compressedBlocks = compressed.match(codeBlockRegex) || [];
169
+ if (originalBlocks.length !== compressedBlocks.length) return true;
170
+ for (let i = 0; i < originalBlocks.length; i++) {
171
+ if (originalBlocks[i] !== compressedBlocks[i]) return true;
172
+ }
173
+ return false;
174
+ }
175
+ function isKnownPattern(content) {
176
+ const patterns = [
177
+ /export\s+(default\s+)?(function|class|const|let|var)/,
178
+ /import\s+.*from\s+['"]/
179
+ ];
180
+ return patterns.some((p) => p.test(content));
181
+ }
182
+
183
+ // src/compress/file-read.ts
184
+ var FileReadCompressor = class {
185
+ async compress(input) {
186
+ const { content, filePath, language } = input;
187
+ const signatures = this.extractSignatures(content, language);
188
+ const exports = this.extractExports(content);
189
+ const lines = [
190
+ `// ${filePath} (${content.split("\n").length} lines)`,
191
+ "",
192
+ ...signatures,
193
+ "",
194
+ "// Exports:",
195
+ ...exports
196
+ ];
197
+ const compressed = lines.join("\n");
198
+ return {
199
+ content: compressed,
200
+ original: content,
201
+ confidence: calculateConfidence(content, compressed),
202
+ metadata: {
203
+ strategy: "signatures",
204
+ originalLines: content.split("\n").length,
205
+ compressedLines: lines.length,
206
+ savings: 1 - compressed.length / content.length
207
+ }
208
+ };
209
+ }
210
+ async decompress(compressed) {
211
+ return compressed.original;
212
+ }
213
+ extractSignatures(content, language) {
214
+ const signatures = [];
215
+ const lines = content.split("\n");
216
+ for (const line of lines) {
217
+ const trimmed = line.trim();
218
+ if (/^(export\s+)?(async\s+)?function\s+\w+/.test(trimmed)) {
219
+ signatures.push(trimmed.replace(/\{[\s\S]*$/, "{ ... }"));
220
+ }
221
+ if (/^(export\s+)?class\s+\w+/.test(trimmed)) {
222
+ signatures.push(trimmed);
223
+ }
224
+ if (/^(export\s+)?(type|interface)\s+\w+/.test(trimmed)) {
225
+ signatures.push(trimmed);
226
+ }
227
+ }
228
+ return signatures;
229
+ }
230
+ extractExports(content) {
231
+ const exports = [];
232
+ const exportRegex = /export\s+(default\s+)?(function|class|const|let|var|type|interface)\s+(\w+)/g;
233
+ let match;
234
+ while ((match = exportRegex.exec(content)) !== null) {
235
+ exports.push(` - ${match[3]} (${match[2]})`);
236
+ }
237
+ return exports;
238
+ }
239
+ };
240
+
241
+ // src/compress/git-diff.ts
242
+ var GitDiffCompressor = class {
243
+ async compress(input) {
244
+ const { diff } = input;
245
+ const hunks = this.parseDiff(diff);
246
+ const condensed = hunks.map((hunk) => ({
247
+ file: hunk.file,
248
+ changes: this.condenseHunk(hunk),
249
+ stats: { additions: hunk.additions, deletions: hunk.deletions }
250
+ }));
251
+ const lines = [];
252
+ for (const hunk of condensed) {
253
+ if (hunk.changes.length > 0) {
254
+ lines.push(`${hunk.file} (+${hunk.stats.additions} -${hunk.stats.deletions})`);
255
+ lines.push(...hunk.changes);
256
+ }
257
+ }
258
+ const compressed = lines.join("\n");
259
+ return {
260
+ content: compressed,
261
+ original: diff,
262
+ confidence: calculateConfidence(diff, compressed),
263
+ metadata: {
264
+ strategy: "condensed",
265
+ filesChanged: condensed.length,
266
+ savings: 1 - compressed.length / diff.length
267
+ }
268
+ };
269
+ }
270
+ async decompress(compressed) {
271
+ return compressed.original;
272
+ }
273
+ parseDiff(diff) {
274
+ const hunks = [];
275
+ const lines = diff.split("\n");
276
+ let currentHunk = null;
277
+ for (const line of lines) {
278
+ if (line.startsWith("diff --git")) {
279
+ if (currentHunk) hunks.push(currentHunk);
280
+ const fileMatch = line.match(/b\/(.+)/);
281
+ currentHunk = {
282
+ file: fileMatch?.[1] || "unknown",
283
+ lines: [],
284
+ additions: 0,
285
+ deletions: 0
286
+ };
287
+ } else if (currentHunk) {
288
+ if (line.startsWith("+")) {
289
+ currentHunk.additions++;
290
+ currentHunk.lines.push({ type: "addition", content: line.slice(1) });
291
+ } else if (line.startsWith("-")) {
292
+ currentHunk.deletions++;
293
+ currentHunk.lines.push({ type: "deletion", content: line.slice(1) });
294
+ }
295
+ }
296
+ }
297
+ if (currentHunk) hunks.push(currentHunk);
298
+ return hunks;
299
+ }
300
+ condenseHunk(hunk) {
301
+ return hunk.lines.filter((l) => l.type === "addition" || l.type === "deletion").map((l) => `${l.type === "addition" ? "+" : "-"} ${l.content}`);
302
+ }
303
+ };
304
+
305
+ // src/compress/grep.ts
306
+ var GrepCompressor = class {
307
+ async compress(input) {
308
+ const { results } = input;
309
+ const grouped = this.groupByFile(results);
310
+ const lines = [];
311
+ for (const [file, matches] of grouped) {
312
+ lines.push(`${file} (${matches.length} matches)`);
313
+ const unique = this.deduplicate(matches);
314
+ for (const match of unique) {
315
+ lines.push(` L${match.line}: ${match.content}`);
316
+ }
317
+ }
318
+ const compressed = lines.join("\n");
319
+ const original = results.map((r) => `${r.file}:${r.line}: ${r.content}`).join("\n");
320
+ return {
321
+ content: compressed,
322
+ original,
323
+ confidence: calculateConfidence(original, compressed),
324
+ metadata: {
325
+ strategy: "grouped",
326
+ totalMatches: results.length,
327
+ uniqueFiles: grouped.size,
328
+ savings: 1 - compressed.length / original.length
329
+ }
330
+ };
331
+ }
332
+ async decompress(compressed) {
333
+ return compressed.original;
334
+ }
335
+ groupByFile(results) {
336
+ const grouped = /* @__PURE__ */ new Map();
337
+ for (const result of results) {
338
+ const existing = grouped.get(result.file) || [];
339
+ existing.push(result);
340
+ grouped.set(result.file, existing);
341
+ }
342
+ return grouped;
343
+ }
344
+ deduplicate(matches) {
345
+ const seen = /* @__PURE__ */ new Set();
346
+ return matches.filter((match) => {
347
+ const key = match.content.trim();
348
+ if (seen.has(key)) return false;
349
+ seen.add(key);
350
+ return true;
351
+ });
352
+ }
353
+ };
354
+
355
+ // src/compress/output.ts
356
+ var OutputCompressor = class {
357
+ static compress(input, options = {}) {
358
+ const { maxLength = 1e3, removeWhitespace = false, prettyPrint = false } = options;
359
+ let output = input;
360
+ if (removeWhitespace) {
361
+ output = output.replace(/\s+/g, " ").trim();
362
+ }
363
+ try {
364
+ const parsed = JSON.parse(output);
365
+ if (prettyPrint) {
366
+ output = JSON.stringify(parsed, null, 2);
367
+ } else {
368
+ output = JSON.stringify(parsed);
369
+ }
370
+ } catch {
371
+ }
372
+ if (output.length > maxLength) {
373
+ const suffix = "...[truncated]";
374
+ output = output.substring(0, maxLength - suffix.length) + suffix;
375
+ }
376
+ return output;
377
+ }
378
+ };
379
+
380
+ // src/cache/l1-session.ts
381
+ var SessionCache = class {
382
+ store = /* @__PURE__ */ new Map();
383
+ hits = 0;
384
+ misses = 0;
385
+ get(key) {
386
+ const entry = this.store.get(key);
387
+ if (entry) {
388
+ this.hits++;
389
+ return entry;
390
+ }
391
+ this.misses++;
392
+ return null;
393
+ }
394
+ set(key, value) {
395
+ this.store.set(key, value);
396
+ }
397
+ clear() {
398
+ this.store.clear();
399
+ this.hits = 0;
400
+ this.misses = 0;
401
+ }
402
+ stats() {
403
+ const total = this.hits + this.misses;
404
+ return {
405
+ hits: this.hits,
406
+ misses: this.misses,
407
+ size: this.store.size,
408
+ hitRate: total > 0 ? this.hits / total : 0
409
+ };
410
+ }
411
+ };
412
+
413
+ // src/cache/l2-cross.ts
414
+ var CrossSessionCache = class {
415
+ constructor(db) {
416
+ this.db = db;
417
+ }
418
+ db;
419
+ async get(key) {
420
+ const row = this.db.prepare(`
421
+ SELECT content, metadata, created_at
422
+ FROM nodes
423
+ WHERE id = ? AND type = 'cache'
424
+ `).get(key);
425
+ if (!row) return null;
426
+ const metadata = JSON.parse(row.metadata);
427
+ if (metadata.ttl) {
428
+ const age = Date.now() / 1e3 - row.created_at;
429
+ if (age > metadata.ttl) {
430
+ this.db.prepare("DELETE FROM nodes WHERE id = ?").run(key);
431
+ return null;
432
+ }
433
+ }
434
+ this.db.prepare(`
435
+ UPDATE nodes SET accessed_at = unixepoch(), access_count = access_count + 1
436
+ WHERE id = ?
437
+ `).run(key);
438
+ return {
439
+ content: row.content,
440
+ metadata: JSON.parse(row.metadata)
441
+ };
442
+ }
443
+ async set(key, value, options) {
444
+ this.db.prepare(`
445
+ INSERT INTO nodes (id, type, content, metadata, created_at, accessed_at, access_count)
446
+ VALUES (?, 'cache', ?, ?, unixepoch(), unixepoch(), 1)
447
+ ON CONFLICT(id) DO UPDATE SET
448
+ content = excluded.content,
449
+ metadata = excluded.metadata,
450
+ accessed_at = unixepoch(),
451
+ access_count = access_count + 1
452
+ `).run(key, value.content, JSON.stringify({ ...value.metadata, ttl: options?.ttl }));
453
+ }
454
+ async delete(key) {
455
+ this.db.prepare("DELETE FROM nodes WHERE id = ?").run(key);
456
+ }
457
+ async clear() {
458
+ this.db.prepare("DELETE FROM nodes WHERE type = 'cache'").run();
459
+ }
460
+ };
461
+
462
+ // src/cache/semantic.ts
463
+ var SemanticCache = class {
464
+ entries = [];
465
+ store(content, embedding, metadata = {}) {
466
+ const entry = {
467
+ id: `sc${this.entries.length + 1}`,
468
+ content,
469
+ embedding,
470
+ metadata,
471
+ createdAt: Date.now()
472
+ };
473
+ this.entries.push(entry);
474
+ return entry;
475
+ }
476
+ search(query, minSimilarity = 0.8) {
477
+ const results = [];
478
+ for (const entry of this.entries) {
479
+ const similarity = this.cosineSimilarity(query, entry.embedding);
480
+ if (similarity >= minSimilarity) {
481
+ results.push({ entry, similarity });
482
+ }
483
+ }
484
+ return results.sort((a, b) => b.similarity - a.similarity);
485
+ }
486
+ getAll() {
487
+ return this.entries;
488
+ }
489
+ cosineSimilarity(a, b) {
490
+ if (a.length !== b.length) return 0;
491
+ let dotProduct = 0;
492
+ let normA = 0;
493
+ let normB = 0;
494
+ for (let i = 0; i < a.length; i++) {
495
+ dotProduct += a[i] * b[i];
496
+ normA += a[i] * a[i];
497
+ normB += b[i] * b[i];
498
+ }
499
+ return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
500
+ }
501
+ };
502
+
503
+ // src/cache/index.ts
504
+ function createCacheManager(db) {
505
+ const session = new SessionCache();
506
+ const crossSession = db ? new CrossSessionCache(db) : null;
507
+ const semantic = new SemanticCache();
508
+ return {
509
+ session,
510
+ crossSession,
511
+ semantic
512
+ };
513
+ }
514
+ function makeLatenCache(db) {
515
+ const l1 = new SessionCache();
516
+ const l2 = new CrossSessionCache(db);
517
+ return {
518
+ l1,
519
+ l2,
520
+ async get(key) {
521
+ const l1Result = l1.get(key);
522
+ if (l1Result) return l1Result;
523
+ const l2Result = await l2.get(key);
524
+ if (l2Result) {
525
+ l1.set(key, l2Result);
526
+ return l2Result;
527
+ }
528
+ return null;
529
+ },
530
+ async set(key, value, options) {
531
+ l1.set(key, value);
532
+ await l2.set(key, value, options);
533
+ },
534
+ async invalidate(pattern) {
535
+ l1.clear();
536
+ await l2.clear();
537
+ },
538
+ stats() {
539
+ return {
540
+ l1: l1.stats(),
541
+ l2: { size: 0 }
542
+ };
543
+ }
544
+ };
545
+ }
546
+
547
+ // src/route/tool-router.ts
548
+ var ToolRouter = class {
549
+ rules = [
550
+ {
551
+ matcher: (input) => input.type === "file",
552
+ compressor: "file-read",
553
+ confidence: 0.95,
554
+ reason: "File read detected"
555
+ },
556
+ {
557
+ matcher: (input) => input.type === "grep",
558
+ compressor: "grep",
559
+ confidence: 0.95,
560
+ reason: "Grep results detected"
561
+ },
562
+ {
563
+ matcher: (input) => input.type === "git-diff",
564
+ compressor: "git-diff",
565
+ confidence: 0.95,
566
+ reason: "Git diff detected"
567
+ }
568
+ ];
569
+ route(input) {
570
+ for (const rule of this.rules) {
571
+ if (rule.matcher(input)) {
572
+ return {
573
+ tool: "compress",
574
+ compressor: rule.compressor,
575
+ confidence: rule.confidence,
576
+ reason: rule.reason
577
+ };
578
+ }
579
+ }
580
+ return {
581
+ tool: "compress",
582
+ confidence: 0.1,
583
+ reason: "No matching route found"
584
+ };
585
+ }
586
+ addRule(rule) {
587
+ this.rules.push(rule);
588
+ }
589
+ };
590
+
591
+ // src/route/strategy-router.ts
592
+ var StrategyRouter = class {
593
+ thresholds = {
594
+ small: 500,
595
+ large: 5e3
596
+ };
597
+ select(context) {
598
+ if (context.userPreference) {
599
+ return {
600
+ strategy: context.userPreference,
601
+ reason: `User preference: ${context.userPreference}`,
602
+ savings: this.estimateSavings(context.userPreference)
603
+ };
604
+ }
605
+ const fileSize = context.fileSize || 0;
606
+ if (fileSize >= this.thresholds.large) {
607
+ return {
608
+ strategy: "aggressive",
609
+ reason: `large file (${fileSize} bytes)`,
610
+ savings: 0.6
611
+ };
612
+ }
613
+ if (fileSize <= this.thresholds.small) {
614
+ return {
615
+ strategy: "conservative",
616
+ reason: `small file (${fileSize} bytes)`,
617
+ savings: 0.2
618
+ };
619
+ }
620
+ return {
621
+ strategy: "balanced",
622
+ reason: `Medium file (${fileSize} bytes)`,
623
+ savings: 0.4
624
+ };
625
+ }
626
+ estimateSavings(strategy) {
627
+ switch (strategy) {
628
+ case "aggressive":
629
+ return 0.6;
630
+ case "balanced":
631
+ return 0.4;
632
+ case "conservative":
633
+ return 0.2;
634
+ }
635
+ }
636
+ };
637
+
638
+ // src/route/index.ts
639
+ function createRouter() {
640
+ const tool = new ToolRouter();
641
+ const strategy = new StrategyRouter();
642
+ return {
643
+ tool,
644
+ strategy,
645
+ route: (input) => tool.route(input),
646
+ selectStrategy: (context) => strategy.select(context)
647
+ };
648
+ }
649
+
650
+ // src/tool/registry.ts
651
+ var ToolRegistry = class {
652
+ tools = /* @__PURE__ */ new Map();
653
+ register(name, tool) {
654
+ this.tools.set(name, tool);
655
+ }
656
+ get(name) {
657
+ return this.tools.get(name);
658
+ }
659
+ list() {
660
+ return Array.from(this.tools.values());
661
+ }
662
+ has(name) {
663
+ return this.tools.has(name);
664
+ }
665
+ unregister(name) {
666
+ return this.tools.delete(name);
667
+ }
668
+ };
669
+
670
+ // src/tool/semantic-tool.ts
671
+ var SemanticTool = class {
672
+ name;
673
+ intent;
674
+ inputTypes;
675
+ outputType;
676
+ constructor(name, config) {
677
+ this.name = name;
678
+ this.intent = config.intent;
679
+ this.inputTypes = new Set(config.inputTypes);
680
+ this.outputType = config.outputType;
681
+ }
682
+ supportsInput(inputType) {
683
+ return this.inputTypes.has(inputType);
684
+ }
685
+ describe() {
686
+ return `${this.name}: ${this.intent} (${Array.from(this.inputTypes).join(", ")} \u2192 ${this.outputType})`;
687
+ }
688
+ };
689
+
690
+ // src/tool/index.ts
691
+ function createToolRegistry() {
692
+ const registry = new ToolRegistry();
693
+ registry.register("compress", {
694
+ name: "compress",
695
+ description: "Compress content to reduce tokens",
696
+ execute: async (input) => ({ content: "compressed", confidence: 0.9 })
697
+ });
698
+ registry.register("cache", {
699
+ name: "cache",
700
+ description: "Cache content for reuse",
701
+ execute: async (input) => ({ content: "cached", confidence: 1 })
702
+ });
703
+ registry.register("graph", {
704
+ name: "graph",
705
+ description: "Store in knowledge graph",
706
+ execute: async (input) => ({ stored: true })
707
+ });
708
+ return registry;
709
+ }
710
+ function getSemanticTools() {
711
+ return [
712
+ new SemanticTool("compress", {
713
+ intent: "Reduce token usage",
714
+ inputTypes: ["file", "grep", "git-diff"],
715
+ outputType: "compressed"
716
+ }),
717
+ new SemanticTool("cache", {
718
+ intent: "Store for reuse",
719
+ inputTypes: ["compressed", "original"],
720
+ outputType: "cached"
721
+ }),
722
+ new SemanticTool("graph", {
723
+ intent: "Build knowledge base",
724
+ inputTypes: ["any"],
725
+ outputType: "stored"
726
+ })
727
+ ];
728
+ }
729
+
730
+ // src/adapter/claude-code.ts
731
+ var ClaudeCodeAdapter = class {
732
+ name = "claude-code";
733
+ version = "1.0.0";
734
+ type = "hook";
735
+ format(input) {
736
+ const { content, context } = input;
737
+ const formatted = this.formatForClaude(content, context);
738
+ return {
739
+ output: formatted,
740
+ format: "claude",
741
+ metadata: {
742
+ filePath: context?.filePath,
743
+ timestamp: Date.now()
744
+ }
745
+ };
746
+ }
747
+ parse(output) {
748
+ return { content: output, parsed: true };
749
+ }
750
+ formatForClaude(content, context) {
751
+ const parts = [];
752
+ if (context?.filePath) {
753
+ parts.push(`**File:** \`${context.filePath}\``);
754
+ }
755
+ parts.push(content);
756
+ return parts.join("\n\n");
757
+ }
758
+ };
759
+
760
+ // src/adapter/codex.ts
761
+ var CodexAdapter = class {
762
+ name = "codex";
763
+ version = "1.0.0";
764
+ type = "hook";
765
+ format(input) {
766
+ const { content, context } = input;
767
+ const formatted = this.formatForCodex(content, context);
768
+ return {
769
+ output: formatted,
770
+ format: "codex",
771
+ metadata: {
772
+ timestamp: Date.now()
773
+ }
774
+ };
775
+ }
776
+ parse(output) {
777
+ try {
778
+ return JSON.parse(output);
779
+ } catch {
780
+ return { content: output };
781
+ }
782
+ }
783
+ formatForCodex(content, context) {
784
+ if (context?.expectJson) {
785
+ return JSON.stringify({ content, timestamp: Date.now() });
786
+ }
787
+ return content;
788
+ }
789
+ };
790
+
791
+ // src/adapter/gemini-cli.ts
792
+ var GeminiCliAdapter = class {
793
+ name = "gemini-cli";
794
+ version = "1.0.0";
795
+ type = "hook";
796
+ format(input) {
797
+ const { content, context } = input;
798
+ const formatted = this.formatForGemini(content, context);
799
+ const multimodal = context?.includeImage || false;
800
+ return {
801
+ output: formatted,
802
+ format: "gemini",
803
+ metadata: {
804
+ multimodal,
805
+ imagePath: context?.imagePath,
806
+ timestamp: Date.now()
807
+ }
808
+ };
809
+ }
810
+ parse(output) {
811
+ return { content: output, parsed: true };
812
+ }
813
+ formatForGemini(content, context) {
814
+ const parts = [content];
815
+ if (context?.includeImage && context?.imagePath) {
816
+ parts.push(`[Image: ${context.imagePath}]`);
817
+ }
818
+ return parts.join("\n");
819
+ }
820
+ };
821
+
822
+ // src/adapter/hook.ts
823
+ import fs from "fs/promises";
824
+ import path from "path";
825
+ var HookAdapter = class {
826
+ name;
827
+ version = "1.0.0";
828
+ type = "hook";
829
+ hooks = {};
830
+ constructor(name) {
831
+ this.name = name;
832
+ }
833
+ format(input) {
834
+ const { content, context } = input;
835
+ const parts = [];
836
+ if (context?.filePath) {
837
+ parts.push(`**File:** \`${context.filePath}\``);
838
+ }
839
+ parts.push(content);
840
+ return {
841
+ output: parts.join("\n\n"),
842
+ format: this.name,
843
+ metadata: { filePath: context?.filePath, timestamp: Date.now() }
844
+ };
845
+ }
846
+ parse(output) {
847
+ return { content: output, parsed: true };
848
+ }
849
+ setHooks(hooks) {
850
+ this.hooks = hooks;
851
+ }
852
+ async intercept(toolCall) {
853
+ if (this.hooks.preToolUse) {
854
+ return this.hooks.preToolUse(toolCall);
855
+ }
856
+ return toolCall;
857
+ }
858
+ async postProcess(result) {
859
+ if (this.hooks.postToolUse) {
860
+ return this.hooks.postToolUse(result);
861
+ }
862
+ return result;
863
+ }
864
+ async install(agentPath) {
865
+ const hooksDir = path.join(agentPath, "hooks");
866
+ await fs.mkdir(hooksDir, { recursive: true });
867
+ const preToolHook = `#!/usr/bin/env node
868
+ const { readFileSync } = require('fs');
869
+ const input = JSON.parse(readFileSync('/dev/stdin', 'utf-8'));
870
+
871
+ if (input.tool === 'Read' || input.tool === 'Bash') {
872
+ process.env.MAKE_LATEN_INTERCEPT = '1';
873
+ }
874
+
875
+ process.stdout.write(JSON.stringify(input));
876
+ `;
877
+ const postToolHook = `#!/usr/bin/env node
878
+ const { readFileSync } = require('fs');
879
+ const input = JSON.parse(readFileSync('/dev/stdin', 'utf-8'));
880
+
881
+ if (input.output && input.output.length > 10000) {
882
+ input.output = input.output.slice(0, 10000) + '\\n... (truncated by make-laten)';
883
+ }
884
+
885
+ process.stdout.write(JSON.stringify(input));
886
+ `;
887
+ await fs.writeFile(path.join(hooksDir, "pre-tool-use.js"), preToolHook);
888
+ await fs.writeFile(path.join(hooksDir, "post-tool-use.js"), postToolHook);
889
+ }
890
+ async uninstall(agentPath) {
891
+ const hooksDir = path.join(agentPath, "hooks");
892
+ try {
893
+ await fs.rm(path.join(hooksDir, "pre-tool-use.js"), { force: true });
894
+ await fs.rm(path.join(hooksDir, "post-tool-use.js"), { force: true });
895
+ } catch {
896
+ }
897
+ }
898
+ async isInstalled(agentPath) {
899
+ try {
900
+ await fs.access(path.join(agentPath, "hooks", "pre-tool-use.js"));
901
+ return true;
902
+ } catch {
903
+ return false;
904
+ }
905
+ }
906
+ };
907
+
908
+ // src/adapter/rules.ts
909
+ import fs2 from "fs/promises";
910
+ import path2 from "path";
911
+
912
+ // src/adapter/types.ts
913
+ var AGENT_CONFIGS = {
914
+ "claude-code": { type: "hook" },
915
+ "codex": { type: "hook" },
916
+ "gemini-cli": { type: "hook" },
917
+ "cursor": { type: "rules", rulesFile: ".cursorrules" },
918
+ "windsurf": { type: "rules", rulesFile: ".windsurfrules" },
919
+ "cline": { type: "rules", rulesFile: ".clinerules" },
920
+ "copilot": { type: "rules", rulesFile: ".github/copilot-instructions.md" }
921
+ };
922
+
923
+ // src/adapter/rules.ts
924
+ var RULES_TEMPLATE = `
925
+ # make-laten efficiency rules
926
+
927
+ ## Token Optimization
928
+ - When reading files, prefer using \`make-laten read <file>\` for compressed output
929
+ - When searching code, prefer using \`make-laten grep <pattern>\` for grouped results
930
+ - When checking git status, prefer using \`make-laten git diff\` for condensed output
931
+
932
+ ## Caching
933
+ - make-laten automatically caches frequently accessed files
934
+ - Use \`make-laten cache stats\` to see cache performance
935
+ - Use \`make-laten cache clear\` to reset cache if needed
936
+
937
+ ## Web Search
938
+ - Use \`make-laten search <query>\` for optimized web search
939
+ - Use \`make-laten fetch <url>\` for compressed web fetch
940
+ `;
941
+ var RulesAdapter = class {
942
+ name;
943
+ version = "1.0.0";
944
+ type = "rules";
945
+ constructor(agentName) {
946
+ this.name = agentName;
947
+ }
948
+ format(input) {
949
+ return {
950
+ output: input.content,
951
+ format: "markdown",
952
+ metadata: { agent: this.name, timestamp: Date.now() }
953
+ };
954
+ }
955
+ parse(output) {
956
+ return { content: output };
957
+ }
958
+ async install(agentPath) {
959
+ const config = AGENT_CONFIGS[this.name];
960
+ if (!config?.rulesFile) {
961
+ throw new Error(`No rules file configured for ${this.name}`);
962
+ }
963
+ const rulesPath = path2.join(agentPath, config.rulesFile);
964
+ const existing = await fs2.readFile(rulesPath, "utf-8").catch(() => "");
965
+ if (existing.includes("make-laten")) {
966
+ return;
967
+ }
968
+ await fs2.mkdir(path2.dirname(rulesPath), { recursive: true });
969
+ await fs2.writeFile(rulesPath, existing + "\n\n" + RULES_TEMPLATE);
970
+ }
971
+ async uninstall(agentPath) {
972
+ const config = AGENT_CONFIGS[this.name];
973
+ if (!config?.rulesFile) return;
974
+ const rulesPath = path2.join(agentPath, config.rulesFile);
975
+ try {
976
+ let content = await fs2.readFile(rulesPath, "utf-8");
977
+ const marker = "# make-laten efficiency rules";
978
+ const idx = content.indexOf(marker);
979
+ if (idx !== -1) {
980
+ const endIdx = content.indexOf("\n#", idx + marker.length);
981
+ content = content.slice(0, idx).trim() + "\n" + (endIdx !== -1 ? content.slice(endIdx) : "");
982
+ await fs2.writeFile(rulesPath, content.trim() + "\n");
983
+ }
984
+ } catch {
985
+ }
986
+ }
987
+ async isInstalled(agentPath) {
988
+ const config = AGENT_CONFIGS[this.name];
989
+ if (!config?.rulesFile) return false;
990
+ try {
991
+ const content = await fs2.readFile(path2.join(agentPath, config.rulesFile), "utf-8");
992
+ return content.includes("make-laten");
993
+ } catch {
994
+ return false;
995
+ }
996
+ }
997
+ };
998
+
999
+ // src/adapter/detector.ts
1000
+ import { exec } from "child_process";
1001
+ import { promisify } from "util";
1002
+ import fs3 from "fs/promises";
1003
+ import path3 from "path";
1004
+ var execAsync = promisify(exec);
1005
+ var AgentDetector = class {
1006
+ async detectAgents() {
1007
+ const agents = [];
1008
+ for (const [name, config] of Object.entries(AGENT_CONFIGS)) {
1009
+ const detected = await this.detectAgent(name, config.type);
1010
+ if (detected) {
1011
+ agents.push(detected);
1012
+ }
1013
+ }
1014
+ return agents;
1015
+ }
1016
+ async detectAgent(name, type) {
1017
+ const commands = {
1018
+ "claude-code": "claude --version",
1019
+ "codex": "codex --version",
1020
+ "gemini-cli": "gemini --version"
1021
+ };
1022
+ if (commands[name]) {
1023
+ try {
1024
+ const { stdout } = await execAsync(commands[name], { timeout: 5e3 });
1025
+ const version = stdout.trim().split("\n")[0];
1026
+ const agentPath = await this.getAgentPath(name);
1027
+ return { name, type, path: agentPath, version, detected: true };
1028
+ } catch {
1029
+ return null;
1030
+ }
1031
+ }
1032
+ if (type === "rules") {
1033
+ const rulesPath = AGENT_CONFIGS[name]?.rulesFile;
1034
+ if (rulesPath) {
1035
+ try {
1036
+ await fs3.access(path3.join(process.cwd(), rulesPath));
1037
+ return { name, type, path: process.cwd(), version: null, detected: true };
1038
+ } catch {
1039
+ return null;
1040
+ }
1041
+ }
1042
+ }
1043
+ return null;
1044
+ }
1045
+ async getAgentPath(name) {
1046
+ const home = process.env.HOME || process.env.USERPROFILE || "";
1047
+ const paths = {
1048
+ "claude-code": path3.join(home, ".claude"),
1049
+ "codex": path3.join(home, ".codex"),
1050
+ "gemini-cli": path3.join(home, ".gemini")
1051
+ };
1052
+ return paths[name] || path3.join(home, `.${name}`);
1053
+ }
1054
+ async hasCommand(cmd) {
1055
+ try {
1056
+ await execAsync(`which ${cmd}`, { timeout: 3e3 });
1057
+ return true;
1058
+ } catch {
1059
+ return false;
1060
+ }
1061
+ }
1062
+ };
1063
+
1064
+ // src/adapter/installer.ts
1065
+ var Installer = class {
1066
+ detector = new AgentDetector();
1067
+ async install() {
1068
+ const agents = await this.detector.detectAgents();
1069
+ const installed = [];
1070
+ const skipped = [];
1071
+ for (const agent of agents) {
1072
+ try {
1073
+ const adapter = this.createAdapter(agent);
1074
+ if (adapter.install) {
1075
+ await adapter.install(agent.path);
1076
+ installed.push(agent.name);
1077
+ } else {
1078
+ skipped.push(agent.name);
1079
+ }
1080
+ } catch {
1081
+ skipped.push(agent.name);
1082
+ }
1083
+ }
1084
+ return { installed, skipped };
1085
+ }
1086
+ async uninstall() {
1087
+ const agents = await this.detector.detectAgents();
1088
+ const removed = [];
1089
+ for (const agent of agents) {
1090
+ try {
1091
+ const adapter = this.createAdapter(agent);
1092
+ if (adapter.uninstall) {
1093
+ await adapter.uninstall(agent.path);
1094
+ removed.push(agent.name);
1095
+ }
1096
+ } catch {
1097
+ }
1098
+ }
1099
+ return { removed };
1100
+ }
1101
+ async status() {
1102
+ const agents = await this.detector.detectAgents();
1103
+ for (const agent of agents) {
1104
+ const adapter = this.createAdapter(agent);
1105
+ if (adapter.isInstalled) {
1106
+ agent.detected = await adapter.isInstalled(agent.path);
1107
+ }
1108
+ }
1109
+ return agents;
1110
+ }
1111
+ createAdapter(agent) {
1112
+ const config = AGENT_CONFIGS[agent.name];
1113
+ if (config?.type === "rules") {
1114
+ return new RulesAdapter(agent.name);
1115
+ }
1116
+ return new HookAdapter(agent.name);
1117
+ }
1118
+ };
1119
+
1120
+ // src/adapter/index.ts
1121
+ var adapters = /* @__PURE__ */ new Map();
1122
+ adapters.set("claude-code", new ClaudeCodeAdapter());
1123
+ adapters.set("codex", new CodexAdapter());
1124
+ adapters.set("gemini-cli", new GeminiCliAdapter());
1125
+ function getAdapter(name) {
1126
+ return adapters.get(name);
1127
+ }
1128
+ function getAdapters() {
1129
+ return Array.from(adapters.values());
1130
+ }
1131
+ function createAdapter(config) {
1132
+ return config;
1133
+ }
1134
+ function registerAdapter(name, adapter) {
1135
+ adapters.set(name, adapter);
1136
+ }
1137
+ function createHookAdapter(name) {
1138
+ return new HookAdapter(name);
1139
+ }
1140
+ function createRulesAdapter(name) {
1141
+ return new RulesAdapter(name);
1142
+ }
1143
+ function createInstaller() {
1144
+ return new Installer();
1145
+ }
1146
+ function createDetector() {
1147
+ return new AgentDetector();
1148
+ }
1149
+
1150
+ // src/learn/pattern-miner.ts
1151
+ var PatternMiner = class {
1152
+ operations = [];
1153
+ patterns = /* @__PURE__ */ new Map();
1154
+ record(operation) {
1155
+ this.operations.push(operation);
1156
+ if (operation.success) {
1157
+ this.updatePatterns(operation);
1158
+ }
1159
+ }
1160
+ getPatterns() {
1161
+ return Array.from(this.patterns.values());
1162
+ }
1163
+ getPatternsByType(type) {
1164
+ return this.getPatterns().filter((p) => p.type === type);
1165
+ }
1166
+ updatePatterns(operation) {
1167
+ const key = operation.type;
1168
+ const existing = this.patterns.get(key);
1169
+ if (existing) {
1170
+ existing.count++;
1171
+ existing.confidence = Math.min(0.99, existing.confidence + 0.05);
1172
+ } else {
1173
+ this.patterns.set(key, {
1174
+ id: `p${this.patterns.size + 1}`,
1175
+ type: operation.type,
1176
+ pattern: JSON.stringify(operation.input),
1177
+ confidence: 0.5,
1178
+ count: 1
1179
+ });
1180
+ }
1181
+ }
1182
+ };
1183
+
1184
+ // src/learn/failure-learner.ts
1185
+ var FailureLearner = class {
1186
+ failures = /* @__PURE__ */ new Map();
1187
+ record(failure) {
1188
+ const key = `${failure.type}:${failure.error}`;
1189
+ const existing = this.failures.get(key);
1190
+ if (existing) {
1191
+ existing.count++;
1192
+ } else {
1193
+ this.failures.set(key, {
1194
+ id: `f${this.failures.size + 1}`,
1195
+ ...failure,
1196
+ timestamp: Date.now(),
1197
+ count: 1
1198
+ });
1199
+ }
1200
+ }
1201
+ getFailures() {
1202
+ return Array.from(this.failures.values());
1203
+ }
1204
+ getFailuresByType(type) {
1205
+ return this.getFailures().filter((f) => f.type === type);
1206
+ }
1207
+ getSuggestions(type) {
1208
+ const failures = Array.from(this.failures.values()).filter((f) => f.type === type);
1209
+ const suggestions = [];
1210
+ for (const failure of failures) {
1211
+ if (failure.error.includes("not found")) {
1212
+ suggestions.push("check if file exists before processing");
1213
+ }
1214
+ if (failure.error.includes("permission")) {
1215
+ suggestions.push("verify file permissions");
1216
+ }
1217
+ if (failure.count > 2) {
1218
+ suggestions.push(`recurring issue: ${failure.error}`);
1219
+ }
1220
+ }
1221
+ return [...new Set(suggestions)];
1222
+ }
1223
+ };
1224
+
1225
+ // src/learn/index.ts
1226
+ function createLearner() {
1227
+ const patterns = new PatternMiner();
1228
+ const failures = new FailureLearner();
1229
+ return {
1230
+ patterns,
1231
+ failures,
1232
+ record: (op) => {
1233
+ patterns.record(op);
1234
+ if (!op.success) {
1235
+ failures.record({
1236
+ type: op.type,
1237
+ error: op.error || "Unknown error",
1238
+ context: op.input
1239
+ });
1240
+ }
1241
+ }
1242
+ };
1243
+ }
1244
+
1245
+ // src/correct/auto-correct.ts
1246
+ var AutoCorrect = class {
1247
+ rules = [];
1248
+ corrections = [];
1249
+ appliedCount = 0;
1250
+ addRule(rule) {
1251
+ this.rules.push(rule);
1252
+ }
1253
+ getRules() {
1254
+ return this.rules;
1255
+ }
1256
+ correct(input) {
1257
+ let output = input;
1258
+ for (const rule of this.rules) {
1259
+ if (typeof rule.pattern === "string") {
1260
+ if (output.includes(rule.pattern)) {
1261
+ output = output.split(rule.pattern).join(rule.replacement);
1262
+ this.recordCorrection(input, output, rule.name);
1263
+ }
1264
+ } else {
1265
+ const matches = output.match(rule.pattern);
1266
+ if (matches) {
1267
+ output = output.replace(rule.pattern, rule.replacement);
1268
+ this.recordCorrection(input, output, rule.name);
1269
+ }
1270
+ }
1271
+ }
1272
+ return output;
1273
+ }
1274
+ getStats() {
1275
+ return {
1276
+ applied: this.appliedCount,
1277
+ corrections: this.corrections
1278
+ };
1279
+ }
1280
+ recordCorrection(original, corrected, ruleName) {
1281
+ this.appliedCount++;
1282
+ this.corrections.push({
1283
+ id: `c${this.corrections.length + 1}`,
1284
+ original,
1285
+ corrected,
1286
+ rule: ruleName,
1287
+ confidence: 0.9
1288
+ });
1289
+ }
1290
+ };
1291
+
1292
+ // src/correct/index.ts
1293
+ var defaultRules = [
1294
+ {
1295
+ name: "fix-typo-teh",
1296
+ description: 'Fix "teh" typo',
1297
+ pattern: "teh",
1298
+ replacement: "the"
1299
+ },
1300
+ {
1301
+ name: "fix-typo-recieve",
1302
+ description: 'Fix "recieve" typo',
1303
+ pattern: "recieve",
1304
+ replacement: "receive"
1305
+ }
1306
+ ];
1307
+ function createCorrector(rules = defaultRules) {
1308
+ const engine = new AutoCorrect();
1309
+ for (const rule of rules) {
1310
+ engine.addRule(rule);
1311
+ }
1312
+ return {
1313
+ engine,
1314
+ rules: engine.getRules(),
1315
+ correct: (input) => engine.correct(input)
1316
+ };
1317
+ }
1318
+
1319
+ // src/middleware/pipeline.ts
1320
+ var Pipeline = class {
1321
+ middlewares = [];
1322
+ use(middleware) {
1323
+ this.middlewares.push(middleware);
1324
+ return this;
1325
+ }
1326
+ size() {
1327
+ return this.middlewares.length;
1328
+ }
1329
+ async execute(ctx) {
1330
+ let index = 0;
1331
+ const next = async (ctx2) => {
1332
+ if (index >= this.middlewares.length) {
1333
+ return { output: ctx2.input, metadata: ctx2.metadata };
1334
+ }
1335
+ const middleware = this.middlewares[index++];
1336
+ return middleware(ctx2, next);
1337
+ };
1338
+ return next(ctx);
1339
+ }
1340
+ };
1341
+
1342
+ // src/plugin/loader.ts
1343
+ var PluginLoader = class {
1344
+ plugins = /* @__PURE__ */ new Map();
1345
+ register(plugin) {
1346
+ this.plugins.set(plugin.name, plugin);
1347
+ }
1348
+ get(name) {
1349
+ return this.plugins.get(name);
1350
+ }
1351
+ has(name) {
1352
+ return this.plugins.has(name);
1353
+ }
1354
+ getAll() {
1355
+ return Array.from(this.plugins.values());
1356
+ }
1357
+ async initializeAll(ctx) {
1358
+ for (const plugin of this.plugins.values()) {
1359
+ await plugin.initialize(ctx);
1360
+ }
1361
+ }
1362
+ async destroyAll() {
1363
+ for (const plugin of this.plugins.values()) {
1364
+ if (plugin.destroy) {
1365
+ await plugin.destroy();
1366
+ }
1367
+ }
1368
+ }
1369
+ };
1370
+
1371
+ // src/security/rate-limiter.ts
1372
+ var RateLimiter = class {
1373
+ config;
1374
+ records = /* @__PURE__ */ new Map();
1375
+ constructor(config) {
1376
+ this.config = config;
1377
+ }
1378
+ allow(key) {
1379
+ const now = Date.now();
1380
+ const record = this.records.get(key);
1381
+ if (!record || now > record.resetAt) {
1382
+ this.records.set(key, { count: 1, resetAt: now + this.config.windowMs });
1383
+ return true;
1384
+ }
1385
+ if (record.count >= this.config.maxRequests) {
1386
+ return false;
1387
+ }
1388
+ record.count++;
1389
+ return true;
1390
+ }
1391
+ getUsage(key) {
1392
+ const record = this.records.get(key);
1393
+ if (!record || Date.now() > record.resetAt) {
1394
+ return 0;
1395
+ }
1396
+ return record.count;
1397
+ }
1398
+ reset(key) {
1399
+ this.records.delete(key);
1400
+ }
1401
+ };
1402
+
1403
+ // src/logging/logger.ts
1404
+ var LOG_LEVELS = {
1405
+ debug: 0,
1406
+ info: 1,
1407
+ warn: 2,
1408
+ error: 3
1409
+ };
1410
+ var Logger = class {
1411
+ config;
1412
+ constructor(config) {
1413
+ this.config = config;
1414
+ }
1415
+ debug(message, metadata) {
1416
+ this.log("debug", message, metadata);
1417
+ }
1418
+ info(message, metadata) {
1419
+ this.log("info", message, metadata);
1420
+ }
1421
+ warn(message, metadata) {
1422
+ this.log("warn", message, metadata);
1423
+ }
1424
+ error(message, metadata) {
1425
+ this.log("error", message, metadata);
1426
+ }
1427
+ log(level, message, metadata) {
1428
+ if (LOG_LEVELS[level] >= LOG_LEVELS[this.config.level]) {
1429
+ this.config.handler({
1430
+ level,
1431
+ message,
1432
+ metadata,
1433
+ timestamp: Date.now()
1434
+ });
1435
+ }
1436
+ }
1437
+ };
1438
+
1439
+ // src/error/handler.ts
1440
+ var ErrorHandler = class {
1441
+ errors = [];
1442
+ handle(error) {
1443
+ this.errors.push(error);
1444
+ const category = this.categorize(error);
1445
+ const suggestions = this.getSuggestions(error);
1446
+ return {
1447
+ handled: true,
1448
+ category,
1449
+ suggestions
1450
+ };
1451
+ }
1452
+ getStats() {
1453
+ const byCategory = {};
1454
+ for (const error of this.errors) {
1455
+ const cat = this.categorize(error);
1456
+ byCategory[cat] = (byCategory[cat] || 0) + 1;
1457
+ }
1458
+ return { total: this.errors.length, byCategory };
1459
+ }
1460
+ categorize(error) {
1461
+ if (error.message.includes("not found")) return "not-found";
1462
+ if (error.message.includes("permission")) return "permission";
1463
+ if (error.message.includes("timeout")) return "timeout";
1464
+ return "unknown";
1465
+ }
1466
+ getSuggestions(error) {
1467
+ const suggestions = [];
1468
+ if (error.message.includes("not found")) {
1469
+ suggestions.push("check if file or resource exists");
1470
+ }
1471
+ if (error.message.includes("permission")) {
1472
+ suggestions.push("verify access permissions");
1473
+ }
1474
+ if (error.message.includes("timeout")) {
1475
+ suggestions.push("increase timeout or retry");
1476
+ }
1477
+ return suggestions;
1478
+ }
1479
+ };
1480
+
1481
+ // src/metrics/collector.ts
1482
+ var MetricsCollector = class {
1483
+ counters = /* @__PURE__ */ new Map();
1484
+ gauges = /* @__PURE__ */ new Map();
1485
+ histograms = /* @__PURE__ */ new Map();
1486
+ increment(name, value = 1) {
1487
+ this.counters.set(name, (this.counters.get(name) || 0) + value);
1488
+ }
1489
+ getCounter(name) {
1490
+ return this.counters.get(name) || 0;
1491
+ }
1492
+ setGauge(name, value) {
1493
+ this.gauges.set(name, value);
1494
+ }
1495
+ getGauge(name) {
1496
+ return this.gauges.get(name) || 0;
1497
+ }
1498
+ record(name, value) {
1499
+ const values = this.histograms.get(name) || [];
1500
+ values.push(value);
1501
+ this.histograms.set(name, values);
1502
+ }
1503
+ getHistogram(name) {
1504
+ const values = this.histograms.get(name) || [];
1505
+ if (values.length === 0) {
1506
+ return { avg: 0, min: 0, max: 0, count: 0 };
1507
+ }
1508
+ return {
1509
+ avg: values.reduce((a, b) => a + b, 0) / values.length,
1510
+ min: Math.min(...values),
1511
+ max: Math.max(...values),
1512
+ count: values.length
1513
+ };
1514
+ }
1515
+ reset() {
1516
+ this.counters.clear();
1517
+ this.gauges.clear();
1518
+ this.histograms.clear();
1519
+ }
1520
+ };
1521
+
1522
+ // src/session/manager.ts
1523
+ var SessionManager = class {
1524
+ config;
1525
+ sessions = /* @__PURE__ */ new Map();
1526
+ constructor(config) {
1527
+ this.config = config;
1528
+ }
1529
+ create(userId) {
1530
+ const session = {
1531
+ id: `s${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
1532
+ userId,
1533
+ createdAt: Date.now(),
1534
+ lastAccessedAt: Date.now()
1535
+ };
1536
+ this.sessions.set(session.id, session);
1537
+ return session;
1538
+ }
1539
+ get(id) {
1540
+ const session = this.sessions.get(id);
1541
+ if (session && Date.now() - session.lastAccessedAt > this.config.timeoutMs) {
1542
+ this.sessions.delete(id);
1543
+ return void 0;
1544
+ }
1545
+ if (session) {
1546
+ session.lastAccessedAt = Date.now();
1547
+ }
1548
+ return session;
1549
+ }
1550
+ destroy(id) {
1551
+ this.sessions.delete(id);
1552
+ }
1553
+ getActive() {
1554
+ const now = Date.now();
1555
+ return Array.from(this.sessions.values()).filter(
1556
+ (s) => now - s.lastAccessedAt <= this.config.timeoutMs
1557
+ );
1558
+ }
1559
+ };
1560
+
1561
+ // src/web/backends/duckduckgo.ts
1562
+ var DuckDuckGoBackend = class {
1563
+ name = "duckduckgo";
1564
+ isAvailable() {
1565
+ return true;
1566
+ }
1567
+ async search(query, options) {
1568
+ const maxResults = options?.maxResults || 5;
1569
+ const url = `https://html.duckduckgo.com/html/?q=${encodeURIComponent(query)}`;
1570
+ const response = await fetch(url, {
1571
+ headers: {
1572
+ "User-Agent": "Mozilla/5.0 (compatible; make-laten/0.1.0)"
1573
+ }
1574
+ });
1575
+ const html = await response.text();
1576
+ return this.parseResults(html, maxResults);
1577
+ }
1578
+ parseResults(html, maxResults) {
1579
+ const results = [];
1580
+ const resultRegex = /<a[^>]*class="result__a"[^>]*href="([^"]*)"[^>]*>([\s\S]*?)<\/a>/gi;
1581
+ const snippetRegex = /<a[^>]*class="result__snippet"[^>]*>([\s\S]*?)<\/a>/gi;
1582
+ let match;
1583
+ const urls = [];
1584
+ const titles = [];
1585
+ while ((match = resultRegex.exec(html)) !== null && urls.length < maxResults) {
1586
+ const rawUrl = match[1];
1587
+ const urlMatch = rawUrl.match(/uddg=([^&]+)/);
1588
+ const url = urlMatch ? decodeURIComponent(urlMatch[1]) : rawUrl;
1589
+ const title = this.stripTags(match[2]).trim();
1590
+ if (url && title) {
1591
+ urls.push(url);
1592
+ titles.push(title);
1593
+ }
1594
+ }
1595
+ const snippets = [];
1596
+ while ((match = snippetRegex.exec(html)) !== null && snippets.length < maxResults) {
1597
+ snippets.push(this.stripTags(match[1]).trim());
1598
+ }
1599
+ for (let i = 0; i < urls.length; i++) {
1600
+ results.push({
1601
+ title: titles[i],
1602
+ url: urls[i],
1603
+ snippet: snippets[i] || "",
1604
+ score: 1 - i * 0.1
1605
+ });
1606
+ }
1607
+ return results;
1608
+ }
1609
+ stripTags(html) {
1610
+ return html.replace(/<[^>]+>/g, "").replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&#x27;/g, "'").replace(/&quot;/g, '"');
1611
+ }
1612
+ };
1613
+
1614
+ // src/web/backends/index.ts
1615
+ function selectBackend(preferred) {
1616
+ const backends = [
1617
+ new DuckDuckGoBackend()
1618
+ ];
1619
+ if (preferred) {
1620
+ const found = backends.find((b) => b.name === preferred);
1621
+ if (found) return found;
1622
+ }
1623
+ return backends.find((b) => b.isAvailable()) || backends[0];
1624
+ }
1625
+
1626
+ // src/web/extractor.ts
1627
+ function stripTags(html) {
1628
+ return html.replace(/<[^>]+>/g, "").replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'");
1629
+ }
1630
+ function extractTitle(html) {
1631
+ const titleMatch = html.match(/<title[^>]*>([\s\S]*?)<\/title>/i);
1632
+ if (titleMatch) return stripTags(titleMatch[1]).trim();
1633
+ const h1Match = html.match(/<h1[^>]*>([\s\S]*?)<\/h1>/i);
1634
+ if (h1Match) return stripTags(h1Match[1]).trim();
1635
+ return "Untitled";
1636
+ }
1637
+ function extractSections(html) {
1638
+ const sections = [];
1639
+ const headingRegex = /<h([1-6])[^>]*>([\s\S]*?)<\/h\1>/gi;
1640
+ let match;
1641
+ while ((match = headingRegex.exec(html)) !== null) {
1642
+ const level = parseInt(match[1]);
1643
+ const heading = stripTags(match[2]).trim();
1644
+ const startPos = match.index + match[0].length;
1645
+ const nextHeading = html.substring(startPos).match(/<h[1-6]/i);
1646
+ const endPos = nextHeading ? startPos + nextHeading.index : html.length;
1647
+ const content = stripTags(html.substring(startPos, endPos)).trim();
1648
+ if (!content) continue;
1649
+ const importance = level <= 2 ? "primary" : level <= 4 ? "secondary" : "tertiary";
1650
+ sections.push({ heading, level, content, importance });
1651
+ }
1652
+ return sections;
1653
+ }
1654
+ function extractCodeExamples(html) {
1655
+ const examples = [];
1656
+ const codeRegex = /<(?:pre|code)[^>]*>[\s\S]*?<(?:code|\/pre)[^>]*>/gi;
1657
+ const blockRegex = /<pre[^>]*><code[^>]*class="[^"]*language-(\w+)[^"]*"[^>]*>([\s\S]*?)<\/code><\/pre>/gi;
1658
+ let match;
1659
+ while ((match = blockRegex.exec(html)) !== null) {
1660
+ const language = match[1];
1661
+ const code = stripTags(match[2]).trim();
1662
+ if (code.length > 10) {
1663
+ examples.push({ language, code });
1664
+ }
1665
+ }
1666
+ const inlineRegex = /<code[^>]*class="[^"]*language-(\w+)[^"]*"[^>]*>([\s\S]*?)<\/code>/gi;
1667
+ while ((match = inlineRegex.exec(html)) !== null) {
1668
+ const language = match[1];
1669
+ const code = stripTags(match[2]).trim();
1670
+ if (code.length > 20 && !examples.some((e) => e.code === code)) {
1671
+ examples.push({ language, code });
1672
+ }
1673
+ }
1674
+ return examples.slice(0, 10);
1675
+ }
1676
+ function extractKeyPoints(sections) {
1677
+ const keyPoints = [];
1678
+ for (const section of sections.filter((s) => s.importance === "primary")) {
1679
+ const sentences = section.content.split(/[.!?\n]+/).filter((s) => s.trim().length > 10);
1680
+ if (sentences.length > 0) {
1681
+ keyPoints.push(sentences[0].trim());
1682
+ }
1683
+ }
1684
+ return keyPoints.slice(0, 5);
1685
+ }
1686
+ function classifyPurpose(html, sections) {
1687
+ const text = (html + " " + sections.map((s) => s.heading).join(" ")).toLowerCase();
1688
+ if (text.includes("api reference") || text.includes("endpoint") || text.includes("parameters")) return "reference";
1689
+ if (text.includes("tutorial") || text.includes("step by step") || text.includes("getting started")) return "tutorial";
1690
+ if (text.includes("blog") || text.includes("published") || text.includes("author")) return "blog";
1691
+ if (text.includes("install") || text.includes("quickstart") || text.includes("overview")) return "documentation";
1692
+ return "documentation";
1693
+ }
1694
+ function extractSemantic(html, url) {
1695
+ const title = extractTitle(html);
1696
+ const sections = extractSections(html);
1697
+ const codeExamples = extractCodeExamples(html);
1698
+ const keyPoints = extractKeyPoints(sections);
1699
+ const purpose = classifyPurpose(html, sections);
1700
+ return {
1701
+ type: "webpage",
1702
+ url,
1703
+ title,
1704
+ purpose,
1705
+ sections,
1706
+ keyPoints,
1707
+ codeExamples,
1708
+ metadata: {
1709
+ language: html.match(/lang="(\w+)"/)?.[1] || "en",
1710
+ author: html.match(/<meta[^>]*name="author"[^>]*content="([^"]+)"/i)?.[1],
1711
+ tags: html.match(/<meta[^>]*name="keywords"[^>]*content="([^"]+)"/i)?.[1]?.split(",").map((t) => t.trim())
1712
+ }
1713
+ };
1714
+ }
1715
+
1716
+ // src/web/compressor.ts
1717
+ function compressWebContent(semantic, options = {}) {
1718
+ const { maxTokens = 1e3, includeCode = true, includeSections = "all" } = options;
1719
+ const lines = [];
1720
+ lines.push(`# ${semantic.title}`);
1721
+ lines.push(`URL: ${semantic.url}`);
1722
+ lines.push(`Purpose: ${semantic.purpose}`);
1723
+ lines.push("");
1724
+ if (semantic.keyPoints.length > 0) {
1725
+ lines.push("## Key Points");
1726
+ for (const point of semantic.keyPoints) {
1727
+ lines.push(`- ${point}`);
1728
+ }
1729
+ lines.push("");
1730
+ }
1731
+ const filteredSections = filterSections(semantic.sections, includeSections);
1732
+ for (const section of filteredSections) {
1733
+ const content = truncateContent(section.content, 500);
1734
+ lines.push(`## ${section.heading}`);
1735
+ lines.push(content);
1736
+ lines.push("");
1737
+ }
1738
+ if (includeCode && semantic.codeExamples.length > 0) {
1739
+ const topExamples = semantic.codeExamples.slice(0, 3);
1740
+ lines.push("## Code Examples");
1741
+ for (const example of topExamples) {
1742
+ lines.push(`\`\`\`${example.language}`);
1743
+ lines.push(truncateContent(example.code, 300));
1744
+ lines.push("```");
1745
+ lines.push("");
1746
+ }
1747
+ }
1748
+ let result = lines.join("\n");
1749
+ const estimatedTokens = estimateTokens(result);
1750
+ if (estimatedTokens > maxTokens) {
1751
+ result = truncateByTokens(result, maxTokens);
1752
+ }
1753
+ return result;
1754
+ }
1755
+ function filterSections(sections, mode) {
1756
+ if (mode === "none") return [];
1757
+ if (mode === "primary") return sections.filter((s) => s.importance === "primary");
1758
+ return sections;
1759
+ }
1760
+ function truncateContent(content, maxLength) {
1761
+ if (content.length <= maxLength) return content;
1762
+ return content.slice(0, maxLength) + "...";
1763
+ }
1764
+ function estimateTokens(text) {
1765
+ return Math.ceil(text.length / 4);
1766
+ }
1767
+ function truncateByTokens(text, maxTokens) {
1768
+ const maxChars = maxTokens * 4;
1769
+ if (text.length <= maxChars) return text;
1770
+ const truncated = text.slice(0, maxChars);
1771
+ const lastNewline = truncated.lastIndexOf("\n");
1772
+ return truncated.slice(0, lastNewline > 0 ? lastNewline : maxChars) + "\n\n... (truncated)";
1773
+ }
1774
+
1775
+ // src/web/router.ts
1776
+ var WebRouter = class {
1777
+ fetchCache = /* @__PURE__ */ new Map();
1778
+ searchCache = /* @__PURE__ */ new Map();
1779
+ cacheTtl;
1780
+ constructor(options) {
1781
+ this.cacheTtl = options?.cacheTtlMs || 60 * 60 * 1e3;
1782
+ }
1783
+ async search(query, options) {
1784
+ const cacheKey = `search:${query}:${JSON.stringify(options || {})}`;
1785
+ const cached = this.searchCache.get(cacheKey);
1786
+ if (cached && this.isFresh(cacheKey)) {
1787
+ return cached;
1788
+ }
1789
+ const backend = selectBackend(options?.backend);
1790
+ const results = await backend.search(query, options);
1791
+ this.searchCache.set(cacheKey, results);
1792
+ this.storeFreshness(cacheKey);
1793
+ return results;
1794
+ }
1795
+ async fetch(url, options) {
1796
+ const cacheKey = `fetch:${url}:${options?.format || "text"}`;
1797
+ if (options?.cache !== false) {
1798
+ const cached = this.fetchCache.get(cacheKey);
1799
+ if (cached && this.isFresh(cacheKey)) {
1800
+ return cached;
1801
+ }
1802
+ }
1803
+ const startTime = Date.now();
1804
+ const response = await fetch(url);
1805
+ const html = await response.text();
1806
+ const originalSize = html.length;
1807
+ let content;
1808
+ let semantic = void 0;
1809
+ if (options?.extract !== false) {
1810
+ semantic = extractSemantic(html, url);
1811
+ content = compressWebContent(semantic, {
1812
+ includeCode: true,
1813
+ includeSections: options?.format === "html" ? "all" : "primary"
1814
+ });
1815
+ } else {
1816
+ content = html;
1817
+ }
1818
+ const compressedSize = content.length;
1819
+ const result = {
1820
+ url,
1821
+ title: semantic?.title || extractSimpleTitle(html),
1822
+ content,
1823
+ semantic,
1824
+ metadata: {
1825
+ fetchTime: Date.now() - startTime,
1826
+ originalSize,
1827
+ compressedSize,
1828
+ savings: 1 - compressedSize / originalSize
1829
+ }
1830
+ };
1831
+ if (options?.cache !== false) {
1832
+ this.fetchCache.set(cacheKey, result);
1833
+ this.storeFreshness(cacheKey);
1834
+ }
1835
+ return result;
1836
+ }
1837
+ async extract(url) {
1838
+ return this.fetch(url, { extract: true, compress: true });
1839
+ }
1840
+ async summarize(content, options) {
1841
+ const lines = content.split("\n");
1842
+ const summaryLines = [];
1843
+ let tokenCount = 0;
1844
+ const maxTokens = options?.maxTokens || 200;
1845
+ for (const line of lines) {
1846
+ const lineTokens = Math.ceil(line.length / 4);
1847
+ if (tokenCount + lineTokens > maxTokens) break;
1848
+ if (line.startsWith("#") || line.startsWith("-") || line.startsWith("*")) {
1849
+ summaryLines.push(line);
1850
+ tokenCount += lineTokens;
1851
+ }
1852
+ }
1853
+ if (summaryLines.length === 0 && lines.length > 0) {
1854
+ for (const line of lines.slice(0, 5)) {
1855
+ const lineTokens = Math.ceil(line.length / 4);
1856
+ if (tokenCount + lineTokens > maxTokens) break;
1857
+ summaryLines.push(line);
1858
+ tokenCount += lineTokens;
1859
+ }
1860
+ }
1861
+ return summaryLines.join("\n");
1862
+ }
1863
+ clearCache() {
1864
+ this.fetchCache.clear();
1865
+ this.searchCache.clear();
1866
+ }
1867
+ getCacheStats() {
1868
+ return {
1869
+ fetchSize: this.fetchCache.size,
1870
+ searchSize: this.searchCache.size
1871
+ };
1872
+ }
1873
+ isFresh(key) {
1874
+ const timestamp = this.freshness.get(key);
1875
+ if (!timestamp) return false;
1876
+ return Date.now() - timestamp < this.cacheTtl;
1877
+ }
1878
+ storeFreshness(key) {
1879
+ this.freshness.set(key, Date.now());
1880
+ }
1881
+ freshness = /* @__PURE__ */ new Map();
1882
+ };
1883
+ function extractSimpleTitle(html) {
1884
+ const titleMatch = html.match(/<title[^>]*>([\s\S]*?)<\/title>/i);
1885
+ return titleMatch ? titleMatch[1].replace(/<[^>]+>/g, "").trim() : "Untitled";
1886
+ }
1887
+
1888
+ // src/index.ts
1889
+ var VERSION = "0.1.0";
1890
+ export {
1891
+ AGENT_CONFIGS,
1892
+ AgentDetector,
1893
+ AutoCorrect,
1894
+ ClaudeCodeAdapter,
1895
+ CodexAdapter,
1896
+ CrossSessionCache,
1897
+ DuckDuckGoBackend,
1898
+ EdgeStore,
1899
+ ErrorHandler,
1900
+ FailureLearner,
1901
+ FileReadCompressor,
1902
+ GeminiCliAdapter,
1903
+ GitDiffCompressor,
1904
+ GrepCompressor,
1905
+ HookAdapter,
1906
+ Installer,
1907
+ Logger,
1908
+ MetricsCollector,
1909
+ NodeStore,
1910
+ OutputCompressor,
1911
+ PatternMiner,
1912
+ Pipeline,
1913
+ PluginLoader,
1914
+ RateLimiter,
1915
+ RulesAdapter,
1916
+ SemanticCache,
1917
+ SemanticTool,
1918
+ SessionCache,
1919
+ SessionManager,
1920
+ StrategyRouter,
1921
+ ToolRegistry,
1922
+ ToolRouter,
1923
+ VERSION,
1924
+ WebRouter,
1925
+ calculateConfidence,
1926
+ compressWebContent,
1927
+ createAdapter,
1928
+ createCacheManager,
1929
+ createCorrector,
1930
+ createDatabase,
1931
+ createDetector,
1932
+ createHookAdapter,
1933
+ createInstaller,
1934
+ createLearner,
1935
+ createRouter,
1936
+ createRulesAdapter,
1937
+ createToolRegistry,
1938
+ extractSemantic,
1939
+ getAdapter,
1940
+ getAdapters,
1941
+ getSemanticTools,
1942
+ makeLatenCache,
1943
+ registerAdapter,
1944
+ selectBackend
1945
+ };
1946
+ //# sourceMappingURL=index.mjs.map