milens 0.6.2 → 0.6.3

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.
Files changed (96) hide show
  1. package/README.md +157 -14
  2. package/dist/analyzer/engine.d.ts +1 -0
  3. package/dist/analyzer/engine.d.ts.map +1 -1
  4. package/dist/analyzer/engine.js +27 -8
  5. package/dist/analyzer/engine.js.map +1 -1
  6. package/dist/analyzer/review.d.ts +23 -0
  7. package/dist/analyzer/review.d.ts.map +1 -0
  8. package/dist/analyzer/review.js +143 -0
  9. package/dist/analyzer/review.js.map +1 -0
  10. package/dist/analyzer/testplan.d.ts +59 -0
  11. package/dist/analyzer/testplan.d.ts.map +1 -0
  12. package/dist/analyzer/testplan.js +218 -0
  13. package/dist/analyzer/testplan.js.map +1 -0
  14. package/dist/cli.js +2 -0
  15. package/dist/cli.js.map +1 -1
  16. package/dist/gateway/analyzer.d.ts +6 -0
  17. package/dist/gateway/analyzer.d.ts.map +1 -0
  18. package/dist/gateway/analyzer.js +218 -0
  19. package/dist/gateway/analyzer.js.map +1 -0
  20. package/dist/gateway/cache.d.ts +35 -0
  21. package/dist/gateway/cache.d.ts.map +1 -0
  22. package/dist/gateway/cache.js +175 -0
  23. package/dist/gateway/cache.js.map +1 -0
  24. package/dist/gateway/config.d.ts +10 -0
  25. package/dist/gateway/config.d.ts.map +1 -0
  26. package/dist/gateway/config.js +167 -0
  27. package/dist/gateway/config.js.map +1 -0
  28. package/dist/gateway/context-memory.d.ts +68 -0
  29. package/dist/gateway/context-memory.d.ts.map +1 -0
  30. package/dist/gateway/context-memory.js +157 -0
  31. package/dist/gateway/context-memory.js.map +1 -0
  32. package/dist/gateway/observability.d.ts +83 -0
  33. package/dist/gateway/observability.d.ts.map +1 -0
  34. package/dist/gateway/observability.js +152 -0
  35. package/dist/gateway/observability.js.map +1 -0
  36. package/dist/gateway/privacy.d.ts +27 -0
  37. package/dist/gateway/privacy.d.ts.map +1 -0
  38. package/dist/gateway/privacy.js +139 -0
  39. package/dist/gateway/privacy.js.map +1 -0
  40. package/dist/gateway/providers.d.ts +66 -0
  41. package/dist/gateway/providers.d.ts.map +1 -0
  42. package/dist/gateway/providers.js +377 -0
  43. package/dist/gateway/providers.js.map +1 -0
  44. package/dist/gateway/router.d.ts +18 -0
  45. package/dist/gateway/router.d.ts.map +1 -0
  46. package/dist/gateway/router.js +102 -0
  47. package/dist/gateway/router.js.map +1 -0
  48. package/dist/gateway/server.d.ts +20 -0
  49. package/dist/gateway/server.d.ts.map +1 -0
  50. package/dist/gateway/server.js +387 -0
  51. package/dist/gateway/server.js.map +1 -0
  52. package/dist/gateway/translator.d.ts +19 -0
  53. package/dist/gateway/translator.d.ts.map +1 -0
  54. package/dist/gateway/translator.js +340 -0
  55. package/dist/gateway/translator.js.map +1 -0
  56. package/dist/gateway/types.d.ts +215 -0
  57. package/dist/gateway/types.d.ts.map +1 -0
  58. package/dist/gateway/types.js +3 -0
  59. package/dist/gateway/types.js.map +1 -0
  60. package/dist/parser/extract.d.ts +1 -0
  61. package/dist/parser/extract.d.ts.map +1 -1
  62. package/dist/parser/extract.js +8 -0
  63. package/dist/parser/extract.js.map +1 -1
  64. package/dist/parser/lang-go.d.ts.map +1 -1
  65. package/dist/parser/lang-go.js +41 -5
  66. package/dist/parser/lang-go.js.map +1 -1
  67. package/dist/parser/lang-java.d.ts.map +1 -1
  68. package/dist/parser/lang-java.js +1 -0
  69. package/dist/parser/lang-java.js.map +1 -1
  70. package/dist/parser/lang-py.d.ts.map +1 -1
  71. package/dist/parser/lang-py.js +22 -0
  72. package/dist/parser/lang-py.js.map +1 -1
  73. package/dist/parser/lang-ruby.d.ts.map +1 -1
  74. package/dist/parser/lang-ruby.js +1 -0
  75. package/dist/parser/lang-ruby.js.map +1 -1
  76. package/dist/server/mcp.d.ts.map +1 -1
  77. package/dist/server/mcp.js +615 -106
  78. package/dist/server/mcp.js.map +1 -1
  79. package/dist/skills.js +32 -0
  80. package/dist/skills.js.map +1 -1
  81. package/dist/store/db.d.ts +44 -0
  82. package/dist/store/db.d.ts.map +1 -1
  83. package/dist/store/db.js +142 -25
  84. package/dist/store/db.js.map +1 -1
  85. package/dist/store/gateway-schema.sql +53 -0
  86. package/dist/store/schema.sql +33 -0
  87. package/dist/store/vectors.d.ts +65 -0
  88. package/dist/store/vectors.d.ts.map +1 -0
  89. package/dist/store/vectors.js +212 -0
  90. package/dist/store/vectors.js.map +1 -0
  91. package/dist/utils.d.ts +3 -0
  92. package/dist/utils.d.ts.map +1 -0
  93. package/dist/utils.js +9 -0
  94. package/dist/utils.js.map +1 -0
  95. package/docs/diagram2.svg +1 -1
  96. package/package.json +2 -1
@@ -0,0 +1,35 @@
1
+ import type { ChatRequest, MessageAnalysis, CacheEntry, CacheConfig } from './types.js';
2
+ import type { CodeSymbol } from '../types.js';
3
+ import type BetterSqlite3 from 'better-sqlite3';
4
+ export declare class SemanticCache {
5
+ private rawDb;
6
+ private config;
7
+ private stmts;
8
+ constructor(rawDb: BetterSqlite3.Database, config: CacheConfig);
9
+ private prepareStatements;
10
+ /** Look up a cached response by AST hash + request hash */
11
+ lookup(req: ChatRequest, analysis?: MessageAnalysis): CacheEntry | null;
12
+ /** Store a response in the cache */
13
+ store(req: ChatRequest, analysis: MessageAnalysis, response: string, meta: {
14
+ model: string;
15
+ provider: string;
16
+ tokensIn: number;
17
+ tokensOut: number;
18
+ }): void;
19
+ /** Compute AST hash — captures code structure, survives renames/reformats */
20
+ computeASTHash(symbols: CodeSymbol[]): string;
21
+ /** Compute request hash — normalized version of the prompt */
22
+ private computeRequestHash;
23
+ /** Evict expired entries + enforce max capacity */
24
+ private ensureCapacity;
25
+ /** Invalidate cache entries related to changed files */
26
+ invalidateForFiles(filePaths: string[]): number;
27
+ /** Get cache statistics */
28
+ getStats(): {
29
+ totalEntries: number;
30
+ totalHits: number;
31
+ totalTokensCached: number;
32
+ totalCostSaved: number;
33
+ };
34
+ }
35
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/gateway/cache.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACxF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,aAAa,MAAM,gBAAgB,CAAC;AAEhD,qBAAa,aAAa;IAItB,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,MAAM;IAJhB,OAAO,CAAC,KAAK,CAAiD;gBAGpD,KAAK,EAAE,aAAa,CAAC,QAAQ,EAC7B,MAAM,EAAE,WAAW;IAK7B,OAAO,CAAC,iBAAiB;IAoDzB,2DAA2D;IAC3D,MAAM,CAAC,GAAG,EAAE,WAAW,EAAE,QAAQ,CAAC,EAAE,eAAe,GAAG,UAAU,GAAG,IAAI;IA2BvE,oCAAoC;IACpC,KAAK,CACH,GAAG,EAAE,WAAW,EAChB,QAAQ,EAAE,eAAe,EACzB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,GAC7E,IAAI;IAmBP,6EAA6E;IAC7E,cAAc,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,MAAM;IAe7C,8DAA8D;IAC9D,OAAO,CAAC,kBAAkB;IAgB1B,mDAAmD;IACnD,OAAO,CAAC,cAAc;IAStB,wDAAwD;IACxD,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,MAAM;IAU/C,2BAA2B;IAC3B,QAAQ,IAAI;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,iBAAiB,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAA;KAAE;CAS3G"}
@@ -0,0 +1,175 @@
1
+ // ── Semantic cache — AST-structure-aware caching for LLM responses ──
2
+ import { createHash } from 'node:crypto';
3
+ export class SemanticCache {
4
+ rawDb;
5
+ config;
6
+ stmts;
7
+ constructor(rawDb, config) {
8
+ this.rawDb = rawDb;
9
+ this.config = config;
10
+ this.stmts = this.prepareStatements();
11
+ }
12
+ prepareStatements() {
13
+ return {
14
+ lookup: this.rawDb.prepare(`SELECT * FROM gateway_cache
15
+ WHERE ast_hash = ? AND request_hash = ?
16
+ AND datetime(created_at, '+' || ttl_hours || ' hours') > datetime('now')
17
+ LIMIT 1`),
18
+ lookupByAst: this.rawDb.prepare(`SELECT * FROM gateway_cache
19
+ WHERE ast_hash = ?
20
+ AND datetime(created_at, '+' || ttl_hours || ' hours') > datetime('now')
21
+ ORDER BY hit_count DESC LIMIT 1`),
22
+ insert: this.rawDb.prepare(`INSERT OR REPLACE INTO gateway_cache
23
+ (id, ast_hash, request_hash, response, model, provider, tokens_in, tokens_out, cost_estimate, ttl_hours)
24
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`),
25
+ recordHit: this.rawDb.prepare(`UPDATE gateway_cache SET hit_count = hit_count + 1, last_hit_at = datetime('now') WHERE id = ?`),
26
+ evictExpired: this.rawDb.prepare(`DELETE FROM gateway_cache WHERE datetime(created_at, '+' || ttl_hours || ' hours') <= datetime('now')`),
27
+ evictOldest: this.rawDb.prepare(`DELETE FROM gateway_cache WHERE id IN (
28
+ SELECT id FROM gateway_cache ORDER BY last_hit_at ASC NULLS FIRST, created_at ASC
29
+ LIMIT ?
30
+ )`),
31
+ count: this.rawDb.prepare('SELECT COUNT(*) as c FROM gateway_cache'),
32
+ invalidateByFile: this.rawDb.prepare(`DELETE FROM gateway_cache WHERE ast_hash IN (
33
+ SELECT DISTINCT gc.ast_hash FROM gateway_cache gc
34
+ WHERE gc.id IN (
35
+ SELECT gc2.id FROM gateway_cache gc2
36
+ JOIN json_each(gc2.response) -- Response contains symbol info referencing the file
37
+ )
38
+ )`),
39
+ stats: this.rawDb.prepare(`SELECT
40
+ COUNT(*) as total_entries,
41
+ SUM(hit_count) as total_hits,
42
+ SUM(tokens_in + tokens_out) as total_tokens_cached,
43
+ SUM(cost_estimate * hit_count) as total_cost_saved
44
+ FROM gateway_cache`),
45
+ };
46
+ }
47
+ /** Look up a cached response by AST hash + request hash */
48
+ lookup(req, analysis) {
49
+ if (!this.config.enabled)
50
+ return null;
51
+ const astHash = analysis?.symbols.length
52
+ ? this.computeASTHash(analysis.symbols)
53
+ : null;
54
+ const requestHash = this.computeRequestHash(req);
55
+ // Try exact match (ast + request)
56
+ if (astHash) {
57
+ const row = this.stmts.lookup.get(astHash, requestHash);
58
+ if (row) {
59
+ this.stmts.recordHit.run(row.id);
60
+ return rowToCacheEntry(row);
61
+ }
62
+ // Try AST-only match (structural cache hit — same code structure, different prompt wording)
63
+ const astRow = this.stmts.lookupByAst.get(astHash);
64
+ if (astRow) {
65
+ this.stmts.recordHit.run(astRow.id);
66
+ return rowToCacheEntry(astRow);
67
+ }
68
+ }
69
+ return null;
70
+ }
71
+ /** Store a response in the cache */
72
+ store(req, analysis, response, meta) {
73
+ if (!this.config.enabled || !analysis.symbols.length)
74
+ return;
75
+ // Evict if over capacity
76
+ this.ensureCapacity();
77
+ const astHash = this.computeASTHash(analysis.symbols);
78
+ const requestHash = this.computeRequestHash(req);
79
+ const id = createHash('sha256').update(astHash + requestHash).digest('hex').slice(0, 16);
80
+ const costEstimate = estimateCost(meta.tokensIn, meta.tokensOut, meta.model);
81
+ this.stmts.insert.run(id, astHash, requestHash, response, meta.model, meta.provider, meta.tokensIn, meta.tokensOut, costEstimate, this.config.ttlHours);
82
+ }
83
+ /** Compute AST hash — captures code structure, survives renames/reformats */
84
+ computeASTHash(symbols) {
85
+ // Hash based on structural properties, NOT code text or names
86
+ const structure = symbols
87
+ .sort((a, b) => a.filePath.localeCompare(b.filePath) || a.startLine - b.startLine)
88
+ .map(s => {
89
+ // Include: kind, export status, parent relationship, line span size
90
+ const span = s.endLine - s.startLine;
91
+ const parent = s.parentId ? '1' : '0';
92
+ return `${s.kind}:${s.exported ? 'E' : 'I'}:${parent}:${span}`;
93
+ })
94
+ .join('|');
95
+ return createHash('sha256').update(structure).digest('hex').slice(0, 16);
96
+ }
97
+ /** Compute request hash — normalized version of the prompt */
98
+ computeRequestHash(req) {
99
+ // Normalize: lowercase, collapse whitespace, remove timestamps
100
+ const normalized = req.messages
101
+ .filter(m => m.role === 'user')
102
+ .map(m => {
103
+ const text = typeof m.content === 'string' ? m.content
104
+ : Array.isArray(m.content)
105
+ ? m.content.filter(p => p.type === 'text').map(p => p.text ?? '').join(' ')
106
+ : '';
107
+ return text.toLowerCase().replace(/\s+/g, ' ').trim();
108
+ })
109
+ .join('\n');
110
+ return createHash('sha256').update(normalized).digest('hex').slice(0, 16);
111
+ }
112
+ /** Evict expired entries + enforce max capacity */
113
+ ensureCapacity() {
114
+ this.stmts.evictExpired.run();
115
+ const count = this.stmts.count.get()?.c ?? 0;
116
+ if (count >= this.config.maxEntries) {
117
+ const toDelete = Math.ceil(this.config.maxEntries * 0.1); // Remove 10%
118
+ this.stmts.evictOldest.run(toDelete);
119
+ }
120
+ }
121
+ /** Invalidate cache entries related to changed files */
122
+ invalidateForFiles(filePaths) {
123
+ // Simple approach: clear all cache when files change
124
+ // (More granular: match ast_hash to symbols in changed files)
125
+ if (filePaths.length > 0) {
126
+ const result = this.rawDb.prepare('DELETE FROM gateway_cache').run();
127
+ return result.changes;
128
+ }
129
+ return 0;
130
+ }
131
+ /** Get cache statistics */
132
+ getStats() {
133
+ const row = this.stmts.stats.get();
134
+ return {
135
+ totalEntries: row?.total_entries ?? 0,
136
+ totalHits: row?.total_hits ?? 0,
137
+ totalTokensCached: row?.total_tokens_cached ?? 0,
138
+ totalCostSaved: row?.total_cost_saved ?? 0,
139
+ };
140
+ }
141
+ }
142
+ function rowToCacheEntry(row) {
143
+ return {
144
+ id: row.id,
145
+ astHash: row.ast_hash,
146
+ requestHash: row.request_hash,
147
+ response: row.response,
148
+ model: row.model,
149
+ provider: row.provider,
150
+ tokensIn: row.tokens_in,
151
+ tokensOut: row.tokens_out,
152
+ costEstimate: row.cost_estimate,
153
+ createdAt: row.created_at,
154
+ hitCount: row.hit_count,
155
+ lastHitAt: row.last_hit_at,
156
+ ttlHours: row.ttl_hours,
157
+ };
158
+ }
159
+ // Rough cost estimation per 1M tokens (USD)
160
+ const MODEL_COSTS = {
161
+ 'gpt-4o': { input: 2.5, output: 10 },
162
+ 'gpt-4o-mini': { input: 0.15, output: 0.6 },
163
+ 'claude-3-5-sonnet': { input: 3, output: 15 },
164
+ 'claude-3-5-haiku': { input: 0.8, output: 4 },
165
+ 'gemini-1.5-pro': { input: 1.25, output: 5 },
166
+ 'gemini-1.5-flash': { input: 0.075, output: 0.3 },
167
+ };
168
+ function estimateCost(tokensIn, tokensOut, model) {
169
+ // Try exact match then prefix match
170
+ const costs = MODEL_COSTS[model]
171
+ ?? Object.entries(MODEL_COSTS).find(([k]) => model.includes(k))?.[1]
172
+ ?? { input: 1, output: 3 }; // Default fallback
173
+ return (tokensIn * costs.input + tokensOut * costs.output) / 1_000_000;
174
+ }
175
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/gateway/cache.ts"],"names":[],"mappings":"AAAA,uEAAuE;AAEvE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAKzC,MAAM,OAAO,aAAa;IAId;IACA;IAJF,KAAK,CAAiD;IAE9D,YACU,KAA6B,EAC7B,MAAmB;QADnB,UAAK,GAAL,KAAK,CAAwB;QAC7B,WAAM,GAAN,MAAM,CAAa;QAE3B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,iBAAiB,EAAE,CAAC;IACxC,CAAC;IAEO,iBAAiB;QACvB,OAAO;YACL,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CACxB;;;iBAGS,CACV;YACD,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAC7B;;;yCAGiC,CAClC;YACD,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CACxB;;+CAEuC,CACxC;YACD,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAC3B,gGAAgG,CACjG;YACD,YAAY,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAC9B,uGAAuG,CACxG;YACD,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAC7B;;;WAGG,CACJ;YACD,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,yCAAyC,CAAC;YACpE,gBAAgB,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAClC;;;;;;WAMG,CACJ;YACD,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CACvB;;;;;4BAKoB,CACrB;SACF,CAAC;IACJ,CAAC;IAED,2DAA2D;IAC3D,MAAM,CAAC,GAAgB,EAAE,QAA0B;QACjD,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC;QAEtC,MAAM,OAAO,GAAG,QAAQ,EAAE,OAAO,CAAC,MAAM;YACtC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,OAAO,CAAC;YACvC,CAAC,CAAC,IAAI,CAAC;QACT,MAAM,WAAW,GAAG,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC;QAEjD,kCAAkC;QAClC,IAAI,OAAO,EAAE,CAAC;YACZ,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,WAAW,CAAQ,CAAC;YAC/D,IAAI,GAAG,EAAE,CAAC;gBACR,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBACjC,OAAO,eAAe,CAAC,GAAG,CAAC,CAAC;YAC9B,CAAC;YAED,4FAA4F;YAC5F,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,OAAO,CAAQ,CAAC;YAC1D,IAAI,MAAM,EAAE,CAAC;gBACX,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;gBACpC,OAAO,eAAe,CAAC,MAAM,CAAC,CAAC;YACjC,CAAC;QACH,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED,oCAAoC;IACpC,KAAK,CACH,GAAgB,EAChB,QAAyB,EACzB,QAAgB,EAChB,IAA8E;QAE9E,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM;YAAE,OAAO;QAE7D,yBAAyB;QACzB,IAAI,CAAC,cAAc,EAAE,CAAC;QAEtB,MAAM,OAAO,GAAG,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QACtD,MAAM,WAAW,GAAG,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC;QACjD,MAAM,EAAE,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,GAAG,WAAW,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACzF,MAAM,YAAY,GAAG,YAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QAE7E,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CACnB,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAClC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,QAAQ,EACzB,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,EAAE,YAAY,EAC3C,IAAI,CAAC,MAAM,CAAC,QAAQ,CACrB,CAAC;IACJ,CAAC;IAED,6EAA6E;IAC7E,cAAc,CAAC,OAAqB;QAClC,8DAA8D;QAC9D,MAAM,SAAS,GAAG,OAAO;aACtB,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS,CAAC;aACjF,GAAG,CAAC,CAAC,CAAC,EAAE;YACP,oEAAoE;YACpE,MAAM,IAAI,GAAG,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,SAAS,CAAC;YACrC,MAAM,MAAM,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;YACtC,OAAO,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;QACjE,CAAC,CAAC;aACD,IAAI,CAAC,GAAG,CAAC,CAAC;QAEb,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC3E,CAAC;IAED,8DAA8D;IACtD,kBAAkB,CAAC,GAAgB;QACzC,+DAA+D;QAC/D,MAAM,UAAU,GAAG,GAAG,CAAC,QAAQ;aAC5B,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC;aAC9B,GAAG,CAAC,CAAC,CAAC,EAAE;YACP,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO;gBACpD,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;oBACxB,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;oBAC3E,CAAC,CAAC,EAAE,CAAC;YACT,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;QACxD,CAAC,CAAC;aACD,IAAI,CAAC,IAAI,CAAC,CAAC;QAEd,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC5E,CAAC;IAED,mDAAmD;IAC3C,cAAc;QACpB,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,EAAE,CAAC;QAC9B,MAAM,KAAK,GAAI,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,EAAU,EAAE,CAAC,IAAI,CAAC,CAAC;QACtD,IAAI,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;YACpC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,GAAG,GAAG,CAAC,CAAC,CAAC,aAAa;YACvE,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACvC,CAAC;IACH,CAAC;IAED,wDAAwD;IACxD,kBAAkB,CAAC,SAAmB;QACpC,qDAAqD;QACrD,8DAA8D;QAC9D,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACzB,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,2BAA2B,CAAC,CAAC,GAAG,EAAE,CAAC;YACrE,OAAO,MAAM,CAAC,OAAO,CAAC;QACxB,CAAC;QACD,OAAO,CAAC,CAAC;IACX,CAAC;IAED,2BAA2B;IAC3B,QAAQ;QACN,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,EAAS,CAAC;QAC1C,OAAO;YACL,YAAY,EAAE,GAAG,EAAE,aAAa,IAAI,CAAC;YACrC,SAAS,EAAE,GAAG,EAAE,UAAU,IAAI,CAAC;YAC/B,iBAAiB,EAAE,GAAG,EAAE,mBAAmB,IAAI,CAAC;YAChD,cAAc,EAAE,GAAG,EAAE,gBAAgB,IAAI,CAAC;SAC3C,CAAC;IACJ,CAAC;CACF;AAED,SAAS,eAAe,CAAC,GAAQ;IAC/B,OAAO;QACL,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,OAAO,EAAE,GAAG,CAAC,QAAQ;QACrB,WAAW,EAAE,GAAG,CAAC,YAAY;QAC7B,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,QAAQ,EAAE,GAAG,CAAC,QAAQ;QACtB,QAAQ,EAAE,GAAG,CAAC,SAAS;QACvB,SAAS,EAAE,GAAG,CAAC,UAAU;QACzB,YAAY,EAAE,GAAG,CAAC,aAAa;QAC/B,SAAS,EAAE,GAAG,CAAC,UAAU;QACzB,QAAQ,EAAE,GAAG,CAAC,SAAS;QACvB,SAAS,EAAE,GAAG,CAAC,WAAW;QAC1B,QAAQ,EAAE,GAAG,CAAC,SAAS;KACxB,CAAC;AACJ,CAAC;AAED,4CAA4C;AAC5C,MAAM,WAAW,GAAsD;IACrE,QAAQ,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE;IACpC,aAAa,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE;IAC3C,mBAAmB,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE;IAC7C,kBAAkB,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,EAAE;IAC7C,gBAAgB,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE;IAC5C,kBAAkB,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE;CAClD,CAAC;AAEF,SAAS,YAAY,CAAC,QAAgB,EAAE,SAAiB,EAAE,KAAa;IACtE,oCAAoC;IACpC,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC;WAC3B,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;WACjE,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,mBAAmB;IACjD,OAAO,CAAC,QAAQ,GAAG,KAAK,CAAC,KAAK,GAAG,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC;AACzE,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { GatewayConfig } from './types.js';
2
+ /** Load gateway config from gateway.json, applying defaults for missing fields */
3
+ export declare function loadConfig(projectDir: string): GatewayConfig;
4
+ /** Create a default gateway.json if none exists */
5
+ export declare function initConfig(projectDir: string): string;
6
+ /** Validate config, returning errors */
7
+ export declare function validateConfig(config: GatewayConfig): string[];
8
+ /** Resolve env var references in api keys (${VAR_NAME} → process.env.VAR_NAME) */
9
+ export declare function resolveEnvVars(config: GatewayConfig): GatewayConfig;
10
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/gateway/config.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAyF,MAAM,YAAY,CAAC;AA0CvI,kFAAkF;AAClF,wBAAgB,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,aAAa,CAgB5D;AAED,mDAAmD;AACnD,wBAAgB,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAqCrD;AAED,wCAAwC;AACxC,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,EAAE,CA4B9D;AAED,kFAAkF;AAClF,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,GAAG,aAAa,CAQnE"}
@@ -0,0 +1,167 @@
1
+ // ── Config — gateway.json loader and validator ──
2
+ import { readFileSync, existsSync, writeFileSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ const DEFAULT_ROUTING = {
5
+ thresholds: { economy: 5, standard: 20 },
6
+ intentMultipliers: {
7
+ generate: 1.0,
8
+ refactor: 1.5,
9
+ review: 0.8,
10
+ test: 0.7,
11
+ debug: 1.2,
12
+ explain: 0.5,
13
+ docstring: 0.3,
14
+ unknown: 1.0,
15
+ },
16
+ defaultTier: 'standard',
17
+ };
18
+ const DEFAULT_CACHE = {
19
+ enabled: true,
20
+ maxEntries: 1000,
21
+ ttlHours: 24,
22
+ };
23
+ const DEFAULT_CONTEXT_INJECTION = {
24
+ enabled: true,
25
+ maxTokens: 500,
26
+ includeCallers: true,
27
+ includeDependencies: true,
28
+ includeBlastRadius: true,
29
+ };
30
+ const DEFAULT_CONFIG = {
31
+ port: 4141,
32
+ host: '127.0.0.1',
33
+ providers: [],
34
+ routing: DEFAULT_ROUTING,
35
+ cache: DEFAULT_CACHE,
36
+ contextInjection: DEFAULT_CONTEXT_INJECTION,
37
+ privacy: { rules: [], defaultAction: 'allow' },
38
+ rateLimit: { windowMs: 60000, maxRequests: 60 },
39
+ };
40
+ /** Load gateway config from gateway.json, applying defaults for missing fields */
41
+ export function loadConfig(projectDir) {
42
+ const configPath = join(projectDir, 'gateway.json');
43
+ if (!existsSync(configPath)) {
44
+ return { ...DEFAULT_CONFIG };
45
+ }
46
+ const raw = readFileSync(configPath, 'utf-8');
47
+ let parsed;
48
+ try {
49
+ parsed = JSON.parse(raw);
50
+ }
51
+ catch {
52
+ throw new Error(`Invalid JSON in ${configPath}`);
53
+ }
54
+ return mergeConfig(parsed);
55
+ }
56
+ /** Create a default gateway.json if none exists */
57
+ export function initConfig(projectDir) {
58
+ const configPath = join(projectDir, 'gateway.json');
59
+ if (existsSync(configPath)) {
60
+ return configPath;
61
+ }
62
+ const template = {
63
+ $schema: './node_modules/milens/gateway-schema.json',
64
+ port: 4141,
65
+ host: '127.0.0.1',
66
+ providers: [
67
+ {
68
+ id: 'openai-main',
69
+ name: 'OpenAI',
70
+ tier: 'premium',
71
+ format: 'openai',
72
+ endpoint: 'https://api.openai.com/v1',
73
+ apiKey: '${OPENAI_API_KEY}',
74
+ models: ['gpt-4o', 'gpt-4o-mini'],
75
+ },
76
+ ],
77
+ routing: DEFAULT_ROUTING,
78
+ cache: DEFAULT_CACHE,
79
+ contextInjection: DEFAULT_CONTEXT_INJECTION,
80
+ privacy: {
81
+ rules: [
82
+ { pathPattern: '**/.env*', action: 'block', reason: 'Environment files contain secrets' },
83
+ { pathPattern: '**/secrets/**', action: 'block', reason: 'Secret files' },
84
+ ],
85
+ defaultAction: 'allow',
86
+ },
87
+ rateLimit: { windowMs: 60000, maxRequests: 60 },
88
+ };
89
+ writeFileSync(configPath, JSON.stringify(template, null, 2) + '\n', 'utf-8');
90
+ return configPath;
91
+ }
92
+ /** Validate config, returning errors */
93
+ export function validateConfig(config) {
94
+ const errors = [];
95
+ if (config.port < 1 || config.port > 65535) {
96
+ errors.push(`Invalid port: ${config.port}`);
97
+ }
98
+ if (!config.providers.length) {
99
+ errors.push('No providers configured — at least one provider is required');
100
+ }
101
+ for (const p of config.providers) {
102
+ if (!p.id)
103
+ errors.push('Provider missing "id"');
104
+ if (!p.format)
105
+ errors.push(`Provider "${p.id}": missing "format"`);
106
+ if (!p.endpoint)
107
+ errors.push(`Provider "${p.id}": missing "endpoint"`);
108
+ if (!p.apiKey)
109
+ errors.push(`Provider "${p.id}": missing "apiKey"`);
110
+ if (!p.models?.length)
111
+ errors.push(`Provider "${p.id}": missing "models"`);
112
+ // Check for env var references
113
+ if (p.apiKey.startsWith('${') && p.apiKey.endsWith('}')) {
114
+ const envVar = p.apiKey.slice(2, -1);
115
+ if (!process.env[envVar]) {
116
+ errors.push(`Provider "${p.id}": env var ${envVar} is not set`);
117
+ }
118
+ }
119
+ }
120
+ return errors;
121
+ }
122
+ /** Resolve env var references in api keys (${VAR_NAME} → process.env.VAR_NAME) */
123
+ export function resolveEnvVars(config) {
124
+ return {
125
+ ...config,
126
+ providers: config.providers.map(p => ({
127
+ ...p,
128
+ apiKey: resolveEnvValue(p.apiKey),
129
+ })),
130
+ };
131
+ }
132
+ function resolveEnvValue(value) {
133
+ if (value.startsWith('${') && value.endsWith('}')) {
134
+ const envVar = value.slice(2, -1);
135
+ return process.env[envVar] ?? value;
136
+ }
137
+ return value;
138
+ }
139
+ function mergeConfig(raw) {
140
+ return {
141
+ port: typeof raw.port === 'number' ? raw.port : DEFAULT_CONFIG.port,
142
+ host: typeof raw.host === 'string' ? raw.host : DEFAULT_CONFIG.host,
143
+ providers: Array.isArray(raw.providers) ? raw.providers : [],
144
+ routing: {
145
+ ...DEFAULT_ROUTING,
146
+ ...(typeof raw.routing === 'object' && raw.routing ? raw.routing : {}),
147
+ },
148
+ cache: {
149
+ ...DEFAULT_CACHE,
150
+ ...(typeof raw.cache === 'object' && raw.cache ? raw.cache : {}),
151
+ },
152
+ contextInjection: {
153
+ ...DEFAULT_CONTEXT_INJECTION,
154
+ ...(typeof raw.contextInjection === 'object' && raw.contextInjection
155
+ ? raw.contextInjection : {}),
156
+ },
157
+ privacy: {
158
+ rules: Array.isArray(raw.privacy?.rules) ? raw.privacy.rules : [],
159
+ defaultAction: raw.privacy?.defaultAction ?? 'allow',
160
+ },
161
+ rateLimit: {
162
+ windowMs: raw.rateLimit?.windowMs ?? 60000,
163
+ maxRequests: raw.rateLimit?.maxRequests ?? 60,
164
+ },
165
+ };
166
+ }
167
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/gateway/config.ts"],"names":[],"mappings":"AAAA,mDAAmD;AAEnD,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAClE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC,MAAM,eAAe,GAAkB;IACrC,UAAU,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE;IACxC,iBAAiB,EAAE;QACjB,QAAQ,EAAE,GAAG;QACb,QAAQ,EAAE,GAAG;QACb,MAAM,EAAE,GAAG;QACX,IAAI,EAAE,GAAG;QACT,KAAK,EAAE,GAAG;QACV,OAAO,EAAE,GAAG;QACZ,SAAS,EAAE,GAAG;QACd,OAAO,EAAE,GAAG;KACb;IACD,WAAW,EAAE,UAAU;CACxB,CAAC;AAEF,MAAM,aAAa,GAAgB;IACjC,OAAO,EAAE,IAAI;IACb,UAAU,EAAE,IAAI;IAChB,QAAQ,EAAE,EAAE;CACb,CAAC;AAEF,MAAM,yBAAyB,GAA2B;IACxD,OAAO,EAAE,IAAI;IACb,SAAS,EAAE,GAAG;IACd,cAAc,EAAE,IAAI;IACpB,mBAAmB,EAAE,IAAI;IACzB,kBAAkB,EAAE,IAAI;CACzB,CAAC;AAEF,MAAM,cAAc,GAAkB;IACpC,IAAI,EAAE,IAAI;IACV,IAAI,EAAE,WAAW;IACjB,SAAS,EAAE,EAAE;IACb,OAAO,EAAE,eAAe;IACxB,KAAK,EAAE,aAAa;IACpB,gBAAgB,EAAE,yBAAyB;IAC3C,OAAO,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,aAAa,EAAE,OAAO,EAAE;IAC9C,SAAS,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,EAAE;CAChD,CAAC;AAEF,kFAAkF;AAClF,MAAM,UAAU,UAAU,CAAC,UAAkB;IAC3C,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;IAEpD,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,OAAO,EAAE,GAAG,cAAc,EAAE,CAAC;IAC/B,CAAC;IAED,MAAM,GAAG,GAAG,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IAC9C,IAAI,MAA+B,CAAC;IACpC,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,mBAAmB,UAAU,EAAE,CAAC,CAAC;IACnD,CAAC;IAED,OAAO,WAAW,CAAC,MAAM,CAAC,CAAC;AAC7B,CAAC;AAED,mDAAmD;AACnD,MAAM,UAAU,UAAU,CAAC,UAAkB;IAC3C,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;IAEpD,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC3B,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,MAAM,QAAQ,GAA4B;QACxC,OAAO,EAAE,2CAA2C;QACpD,IAAI,EAAE,IAAI;QACV,IAAI,EAAE,WAAW;QACjB,SAAS,EAAE;YACT;gBACE,EAAE,EAAE,aAAa;gBACjB,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,SAAS;gBACf,MAAM,EAAE,QAAQ;gBAChB,QAAQ,EAAE,2BAA2B;gBACrC,MAAM,EAAE,mBAAmB;gBAC3B,MAAM,EAAE,CAAC,QAAQ,EAAE,aAAa,CAAC;aAClC;SACF;QACD,OAAO,EAAE,eAAe;QACxB,KAAK,EAAE,aAAa;QACpB,gBAAgB,EAAE,yBAAyB;QAC3C,OAAO,EAAE;YACP,KAAK,EAAE;gBACL,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,mCAAmC,EAAE;gBACzF,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE;aAC1E;YACD,aAAa,EAAE,OAAO;SACvB;QACD,SAAS,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,EAAE;KAChD,CAAC;IAEF,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;IAC7E,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,wCAAwC;AACxC,MAAM,UAAU,cAAc,CAAC,MAAqB;IAClD,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,IAAI,MAAM,CAAC,IAAI,GAAG,CAAC,IAAI,MAAM,CAAC,IAAI,GAAG,KAAK,EAAE,CAAC;QAC3C,MAAM,CAAC,IAAI,CAAC,iBAAiB,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;IAC9C,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC;QAC7B,MAAM,CAAC,IAAI,CAAC,6DAA6D,CAAC,CAAC;IAC7E,CAAC;IAED,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;QACjC,IAAI,CAAC,CAAC,CAAC,EAAE;YAAE,MAAM,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;QAChD,IAAI,CAAC,CAAC,CAAC,MAAM;YAAE,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,EAAE,qBAAqB,CAAC,CAAC;QACnE,IAAI,CAAC,CAAC,CAAC,QAAQ;YAAE,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,EAAE,uBAAuB,CAAC,CAAC;QACvE,IAAI,CAAC,CAAC,CAAC,MAAM;YAAE,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,EAAE,qBAAqB,CAAC,CAAC;QACnE,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,MAAM;YAAE,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,EAAE,qBAAqB,CAAC,CAAC;QAE3E,+BAA+B;QAC/B,IAAI,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACxD,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YACrC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;gBACzB,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,EAAE,cAAc,MAAM,aAAa,CAAC,CAAC;YAClE,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,cAAc,CAAC,MAAqB;IAClD,OAAO;QACL,GAAG,MAAM;QACT,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YACpC,GAAG,CAAC;YACJ,MAAM,EAAE,eAAe,CAAC,CAAC,CAAC,MAAM,CAAC;SAClC,CAAC,CAAC;KACJ,CAAC;AACJ,CAAC;AAED,SAAS,eAAe,CAAC,KAAa;IACpC,IAAI,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAClD,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAClC,OAAO,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC;IACtC,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,WAAW,CAAC,GAA4B;IAC/C,OAAO;QACL,IAAI,EAAE,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,cAAc,CAAC,IAAI;QACnE,IAAI,EAAE,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,cAAc,CAAC,IAAI;QACnE,SAAS,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,SAA6B,CAAC,CAAC,CAAC,EAAE;QAChF,OAAO,EAAE;YACP,GAAG,eAAe;YAClB,GAAG,CAAC,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,OAAiC,CAAC,CAAC,CAAC,EAAE,CAAC;SACjG;QACD,KAAK,EAAE;YACL,GAAG,aAAa;YAChB,GAAG,CAAC,OAAO,GAAG,CAAC,KAAK,KAAK,QAAQ,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,KAA6B,CAAC,CAAC,CAAC,EAAE,CAAC;SACzF;QACD,gBAAgB,EAAE;YAChB,GAAG,yBAAyB;YAC5B,GAAG,CAAC,OAAO,GAAG,CAAC,gBAAgB,KAAK,QAAQ,IAAI,GAAG,CAAC,gBAAgB;gBAClE,CAAC,CAAC,GAAG,CAAC,gBAAmD,CAAC,CAAC,CAAC,EAAE,CAAC;SAClE;QACD,OAAO,EAAE;YACP,KAAK,EAAE,KAAK,CAAC,OAAO,CAAE,GAAG,CAAC,OAAe,EAAE,KAAK,CAAC,CAAC,CAAC,CAAE,GAAG,CAAC,OAAe,CAAC,KAAsB,CAAC,CAAC,CAAC,EAAE;YACpG,aAAa,EAAG,GAAG,CAAC,OAAe,EAAE,aAAa,IAAI,OAAO;SAC9D;QACD,SAAS,EAAE;YACT,QAAQ,EAAG,GAAG,CAAC,SAAiB,EAAE,QAAQ,IAAI,KAAK;YACnD,WAAW,EAAG,GAAG,CAAC,SAAiB,EAAE,WAAW,IAAI,EAAE;SACvD;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,68 @@
1
+ /** A shared context entry */
2
+ interface ContextEntry {
3
+ key: string;
4
+ value: string;
5
+ source: string;
6
+ addedAt: number;
7
+ hash: string;
8
+ tags: string[];
9
+ }
10
+ /** Change notification */
11
+ interface ContextChange {
12
+ type: 'add' | 'update' | 'remove';
13
+ key: string;
14
+ value?: string;
15
+ source: string;
16
+ timestamp: number;
17
+ }
18
+ type ChangeListener = (change: ContextChange) => void;
19
+ export declare class ContextMemory {
20
+ private agents;
21
+ private entries;
22
+ private listeners;
23
+ private changeLog;
24
+ private maxEntries;
25
+ private maxChangeLog;
26
+ constructor(opts?: {
27
+ maxEntries?: number;
28
+ maxChangeLog?: number;
29
+ });
30
+ /** Register a new agent session */
31
+ registerAgent(name: string, role: string): string;
32
+ /** Remove an agent session */
33
+ removeAgent(agentId: string): void;
34
+ /** Add or update a context entry (dedup by content hash) */
35
+ set(agentId: string, key: string, value: string, tags?: string[]): boolean;
36
+ /** Get a context entry */
37
+ get(key: string): string | undefined;
38
+ /** Remove a context entry */
39
+ remove(agentId: string, key: string): boolean;
40
+ /** Get all context entries matching tags */
41
+ getByTags(tags: string[]): ContextEntry[];
42
+ /** Get all context contributed by a specific agent */
43
+ getByAgent(agentId: string): ContextEntry[];
44
+ /** Subscribe to context changes */
45
+ subscribe(agentId: string, listener: ChangeListener): void;
46
+ /** Get changes since a timestamp */
47
+ getChangesSince(since: number): ContextChange[];
48
+ /** Build a summary string of shared context (for injection into prompts) */
49
+ buildContextSummary(maxTokens?: number): string;
50
+ /** List active agents */
51
+ listAgents(): {
52
+ id: string;
53
+ name: string;
54
+ role: string;
55
+ contextCount: number;
56
+ lastActive: number;
57
+ }[];
58
+ /** Get stats */
59
+ getStats(): {
60
+ agents: number;
61
+ entries: number;
62
+ changeLogSize: number;
63
+ };
64
+ private recordChange;
65
+ private evictOldest;
66
+ }
67
+ export {};
68
+ //# sourceMappingURL=context-memory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-memory.d.ts","sourceRoot":"","sources":["../../src/gateway/context-memory.ts"],"names":[],"mappings":"AAcA,6BAA6B;AAC7B,UAAU,YAAY;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,0BAA0B;AAC1B,UAAU,aAAa;IACrB,IAAI,EAAE,KAAK,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,KAAK,cAAc,GAAG,CAAC,MAAM,EAAE,aAAa,KAAK,IAAI,CAAC;AAEtD,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAmC;IACjD,OAAO,CAAC,OAAO,CAAmC;IAClD,OAAO,CAAC,SAAS,CAAqC;IACtD,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,YAAY,CAAS;gBAEjB,IAAI,GAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAO;IAKrE,mCAAmC;IACnC,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM;IAWjD,8BAA8B;IAC9B,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAKlC,4DAA4D;IAC5D,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,GAAE,MAAM,EAAO,GAAG,OAAO;IAgC9E,0BAA0B;IAC1B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAIpC,6BAA6B;IAC7B,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO;IAY7C,4CAA4C;IAC5C,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,YAAY,EAAE;IAOzC,sDAAsD;IACtD,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,EAAE;IAQ3C,mCAAmC;IACnC,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,GAAG,IAAI;IAI1D,oCAAoC;IACpC,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,EAAE;IAI/C,4EAA4E;IAC5E,mBAAmB,CAAC,SAAS,SAAO,GAAG,MAAM;IAoB7C,yBAAyB;IACzB,UAAU,IAAI;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,EAAE;IAUpG,gBAAgB;IAChB,QAAQ;;;;;IAQR,OAAO,CAAC,YAAY;IAcpB,OAAO,CAAC,WAAW;CASpB"}
@@ -0,0 +1,157 @@
1
+ // ── Context Memory — shared context across multi-agent sessions ──
2
+ import { createHash, randomUUID } from 'node:crypto';
3
+ export class ContextMemory {
4
+ agents = new Map();
5
+ entries = new Map();
6
+ listeners = new Map();
7
+ changeLog = [];
8
+ maxEntries;
9
+ maxChangeLog;
10
+ constructor(opts = {}) {
11
+ this.maxEntries = opts.maxEntries ?? 500;
12
+ this.maxChangeLog = opts.maxChangeLog ?? 1000;
13
+ }
14
+ /** Register a new agent session */
15
+ registerAgent(name, role) {
16
+ const id = randomUUID().slice(0, 8);
17
+ this.agents.set(id, {
18
+ id, name, role,
19
+ joinedAt: Date.now(),
20
+ lastActive: Date.now(),
21
+ contextKeys: new Set(),
22
+ });
23
+ return id;
24
+ }
25
+ /** Remove an agent session */
26
+ removeAgent(agentId) {
27
+ this.agents.delete(agentId);
28
+ this.listeners.delete(agentId);
29
+ }
30
+ /** Add or update a context entry (dedup by content hash) */
31
+ set(agentId, key, value, tags = []) {
32
+ const agent = this.agents.get(agentId);
33
+ if (!agent)
34
+ return false;
35
+ const hash = createHash('sha256').update(value).digest('hex').slice(0, 12);
36
+ // Check for duplicate content under a different key
37
+ const existing = this.entries.get(key);
38
+ if (existing && existing.hash === hash) {
39
+ return false; // No change
40
+ }
41
+ // Enforce capacity
42
+ if (!existing && this.entries.size >= this.maxEntries) {
43
+ this.evictOldest();
44
+ }
45
+ const changeType = existing ? 'update' : 'add';
46
+ this.entries.set(key, {
47
+ key, value,
48
+ source: agentId,
49
+ addedAt: Date.now(),
50
+ hash,
51
+ tags,
52
+ });
53
+ agent.contextKeys.add(key);
54
+ agent.lastActive = Date.now();
55
+ this.recordChange({ type: changeType, key, value, source: agentId, timestamp: Date.now() });
56
+ return true;
57
+ }
58
+ /** Get a context entry */
59
+ get(key) {
60
+ return this.entries.get(key)?.value;
61
+ }
62
+ /** Remove a context entry */
63
+ remove(agentId, key) {
64
+ const entry = this.entries.get(key);
65
+ if (!entry)
66
+ return false;
67
+ this.entries.delete(key);
68
+ const agent = this.agents.get(agentId);
69
+ agent?.contextKeys.delete(key);
70
+ this.recordChange({ type: 'remove', key, source: agentId, timestamp: Date.now() });
71
+ return true;
72
+ }
73
+ /** Get all context entries matching tags */
74
+ getByTags(tags) {
75
+ const tagSet = new Set(tags);
76
+ return [...this.entries.values()].filter(e => e.tags.some(t => tagSet.has(t)));
77
+ }
78
+ /** Get all context contributed by a specific agent */
79
+ getByAgent(agentId) {
80
+ const agent = this.agents.get(agentId);
81
+ if (!agent)
82
+ return [];
83
+ return [...agent.contextKeys]
84
+ .map(k => this.entries.get(k))
85
+ .filter((e) => e !== undefined);
86
+ }
87
+ /** Subscribe to context changes */
88
+ subscribe(agentId, listener) {
89
+ this.listeners.set(agentId, listener);
90
+ }
91
+ /** Get changes since a timestamp */
92
+ getChangesSince(since) {
93
+ return this.changeLog.filter(c => c.timestamp > since);
94
+ }
95
+ /** Build a summary string of shared context (for injection into prompts) */
96
+ buildContextSummary(maxTokens = 2000) {
97
+ const entries = [...this.entries.values()]
98
+ .sort((a, b) => b.addedAt - a.addedAt);
99
+ const lines = [];
100
+ let approxTokens = 0;
101
+ for (const entry of entries) {
102
+ const line = `[${entry.tags.join(',')}] ${entry.key}: ${entry.value}`;
103
+ const lineTokens = Math.ceil(line.length / 4);
104
+ if (approxTokens + lineTokens > maxTokens)
105
+ break;
106
+ lines.push(line);
107
+ approxTokens += lineTokens;
108
+ }
109
+ return lines.length
110
+ ? `--- Shared Context (${this.agents.size} agents) ---\n${lines.join('\n')}`
111
+ : '';
112
+ }
113
+ /** List active agents */
114
+ listAgents() {
115
+ return [...this.agents.values()].map(a => ({
116
+ id: a.id,
117
+ name: a.name,
118
+ role: a.role,
119
+ contextCount: a.contextKeys.size,
120
+ lastActive: a.lastActive,
121
+ }));
122
+ }
123
+ /** Get stats */
124
+ getStats() {
125
+ return {
126
+ agents: this.agents.size,
127
+ entries: this.entries.size,
128
+ changeLogSize: this.changeLog.length,
129
+ };
130
+ }
131
+ recordChange(change) {
132
+ this.changeLog.push(change);
133
+ if (this.changeLog.length > this.maxChangeLog) {
134
+ this.changeLog = this.changeLog.slice(-Math.floor(this.maxChangeLog * 0.8));
135
+ }
136
+ // Notify other agents
137
+ for (const [agentId, listener] of this.listeners) {
138
+ if (agentId !== change.source) {
139
+ try {
140
+ listener(change);
141
+ }
142
+ catch { /* ignore listener errors */ }
143
+ }
144
+ }
145
+ }
146
+ evictOldest() {
147
+ let oldest = null;
148
+ for (const entry of this.entries.values()) {
149
+ if (!oldest || entry.addedAt < oldest.addedAt)
150
+ oldest = entry;
151
+ }
152
+ if (oldest) {
153
+ this.entries.delete(oldest.key);
154
+ }
155
+ }
156
+ }
157
+ //# sourceMappingURL=context-memory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-memory.js","sourceRoot":"","sources":["../../src/gateway/context-memory.ts"],"names":[],"mappings":"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"}