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,83 @@
1
+ import type { CostRecord, Intent, Tier } from './types.js';
2
+ import type BetterSqlite3 from 'better-sqlite3';
3
+ export declare class CostTracker {
4
+ private rawDb;
5
+ private stmts;
6
+ constructor(rawDb: BetterSqlite3.Database);
7
+ private prepareStatements;
8
+ /** Record a completed request */
9
+ record(data: {
10
+ provider: string;
11
+ model: string;
12
+ tokensIn: number;
13
+ tokensOut: number;
14
+ costEstimate: number;
15
+ durationMs: number;
16
+ symbolIds: string[];
17
+ filePaths: string[];
18
+ intent: Intent;
19
+ complexityScore: number;
20
+ tier: Tier;
21
+ cacheHit: boolean;
22
+ }): string;
23
+ /** Cost breakdown by provider + model */
24
+ getCostByProvider(windowSql?: string): {
25
+ provider: string;
26
+ model: string;
27
+ request_count: number;
28
+ total_tokens_in: number;
29
+ total_tokens_out: number;
30
+ total_cost: number;
31
+ avg_duration: number;
32
+ }[];
33
+ /** Cost breakdown by file path */
34
+ getCostByFile(limit?: number, windowSql?: string): {
35
+ file_path: string;
36
+ request_count: number;
37
+ total_tokens: number;
38
+ total_cost: number;
39
+ }[];
40
+ /** Cost breakdown by intent */
41
+ getCostByIntent(windowSql?: string): {
42
+ intent: string;
43
+ request_count: number;
44
+ total_tokens: number;
45
+ total_cost: number;
46
+ avg_complexity: number;
47
+ }[];
48
+ /** Cost breakdown by tier */
49
+ getCostByTier(windowSql?: string): {
50
+ tier: string;
51
+ request_count: number;
52
+ total_cost: number;
53
+ avg_duration: number;
54
+ }[];
55
+ /** Cache hit/miss stats and savings */
56
+ getCacheSavings(windowSql?: string): {
57
+ cacheHits: any;
58
+ cacheMisses: any;
59
+ costSaved: any;
60
+ tokensSaved: any;
61
+ hitRate: number;
62
+ };
63
+ /** Most expensive symbols */
64
+ getTopExpensiveSymbols(limit?: number, windowSql?: string): {
65
+ symbol_id: string;
66
+ request_count: number;
67
+ total_cost: number;
68
+ total_tokens: number;
69
+ }[];
70
+ /** Overall summary */
71
+ getSummary(windowSql?: string): {
72
+ totalRequests: any;
73
+ totalTokensIn: any;
74
+ totalTokensOut: any;
75
+ totalCost: any;
76
+ avgDuration: any;
77
+ firstRequest: any;
78
+ lastRequest: any;
79
+ };
80
+ /** Get recent requests for debugging */
81
+ getRecentRequests(limit?: number): CostRecord[];
82
+ }
83
+ //# sourceMappingURL=observability.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"observability.d.ts","sourceRoot":"","sources":["../../src/gateway/observability.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAC3D,OAAO,KAAK,aAAa,MAAM,gBAAgB,CAAC;AAEhD,qBAAa,WAAW;IAGV,OAAO,CAAC,KAAK;IAFzB,OAAO,CAAC,KAAK,CAA+C;gBAExC,KAAK,EAAE,aAAa,CAAC,QAAQ;IAIjD,OAAO,CAAC,iBAAiB;IAyFzB,iCAAiC;IACjC,MAAM,CAAC,IAAI,EAAE;QACX,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,MAAM,CAAC;QAClB,YAAY,EAAE,MAAM,CAAC;QACrB,UAAU,EAAE,MAAM,CAAC;QACnB,SAAS,EAAE,MAAM,EAAE,CAAC;QACpB,SAAS,EAAE,MAAM,EAAE,CAAC;QACpB,MAAM,EAAE,MAAM,CAAC;QACf,eAAe,EAAE,MAAM,CAAC;QACxB,IAAI,EAAE,IAAI,CAAC;QACX,QAAQ,EAAE,OAAO,CAAC;KACnB,GAAG,MAAM;IAiBV,yCAAyC;IACzC,iBAAiB,CAAC,SAAS,SAAa,GACS;QAC7C,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAChC,aAAa,EAAE,MAAM,CAAC;QAAC,eAAe,EAAE,MAAM,CAAC;QAAC,gBAAgB,EAAE,MAAM,CAAC;QACzE,UAAU,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;KAC1C,EAAE;IAGL,kCAAkC;IAClC,aAAa,CAAC,KAAK,SAAK,EAAE,SAAS,SAAa,GACI;QAChD,SAAS,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;KACpF,EAAE;IAGL,+BAA+B;IAC/B,eAAe,CAAC,SAAS,SAAa,GACS;QAC3C,MAAM,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAC;KACzG,EAAE;IAGL,6BAA6B;IAC7B,aAAa,CAAC,SAAS,SAAa,GACS;QACzC,IAAI,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;KAC/E,EAAE;IAGL,uCAAuC;IACvC,eAAe,CAAC,SAAS,SAAa;;;;;;;IAatC,6BAA6B;IAC7B,sBAAsB,CAAC,KAAK,SAAK,EAAE,SAAS,SAAa,GACD;QACpD,SAAS,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;KACpF,EAAE;IAGL,sBAAsB;IACtB,UAAU,CAAC,SAAS,SAAa;;;;;;;;;IAajC,wCAAwC;IACxC,iBAAiB,CAAC,KAAK,SAAK,GAAG,UAAU,EAAE;CAkB5C"}
@@ -0,0 +1,152 @@
1
+ // ── Observability — per-function / per-file cost tracking ──
2
+ import { randomUUID } from 'node:crypto';
3
+ export class CostTracker {
4
+ rawDb;
5
+ stmts;
6
+ constructor(rawDb) {
7
+ this.rawDb = rawDb;
8
+ this.stmts = this.prepareStatements();
9
+ }
10
+ prepareStatements() {
11
+ return {
12
+ insert: this.rawDb.prepare(`INSERT INTO gateway_cost_log
13
+ (request_id, provider, model, tokens_in, tokens_out, cost_estimate, duration_ms,
14
+ symbol_ids, file_paths, intent, complexity_score, tier, cache_hit)
15
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`),
16
+ byProvider: this.rawDb.prepare(`SELECT provider, model,
17
+ COUNT(*) as request_count,
18
+ SUM(tokens_in) as total_tokens_in,
19
+ SUM(tokens_out) as total_tokens_out,
20
+ SUM(cost_estimate) as total_cost,
21
+ AVG(duration_ms) as avg_duration
22
+ FROM gateway_cost_log
23
+ WHERE timestamp >= datetime('now', ?)
24
+ GROUP BY provider, model
25
+ ORDER BY total_cost DESC`),
26
+ byFile: this.rawDb.prepare(`SELECT jf.value as file_path,
27
+ COUNT(*) as request_count,
28
+ SUM(cl.tokens_in + cl.tokens_out) as total_tokens,
29
+ SUM(cl.cost_estimate) as total_cost
30
+ FROM gateway_cost_log cl, json_each(cl.file_paths) jf
31
+ WHERE cl.timestamp >= datetime('now', ?)
32
+ GROUP BY jf.value
33
+ ORDER BY total_cost DESC
34
+ LIMIT ?`),
35
+ byIntent: this.rawDb.prepare(`SELECT intent,
36
+ COUNT(*) as request_count,
37
+ SUM(tokens_in + tokens_out) as total_tokens,
38
+ SUM(cost_estimate) as total_cost,
39
+ AVG(complexity_score) as avg_complexity
40
+ FROM gateway_cost_log
41
+ WHERE timestamp >= datetime('now', ?)
42
+ GROUP BY intent
43
+ ORDER BY total_cost DESC`),
44
+ byTier: this.rawDb.prepare(`SELECT tier,
45
+ COUNT(*) as request_count,
46
+ SUM(cost_estimate) as total_cost,
47
+ AVG(duration_ms) as avg_duration
48
+ FROM gateway_cost_log
49
+ WHERE timestamp >= datetime('now', ?)
50
+ GROUP BY tier`),
51
+ cacheSavings: this.rawDb.prepare(`SELECT
52
+ SUM(CASE WHEN cache_hit = 1 THEN 1 ELSE 0 END) as cache_hits,
53
+ SUM(CASE WHEN cache_hit = 0 THEN 1 ELSE 0 END) as cache_misses,
54
+ SUM(CASE WHEN cache_hit = 1 THEN cost_estimate ELSE 0 END) as cost_saved,
55
+ SUM(CASE WHEN cache_hit = 1 THEN tokens_in + tokens_out ELSE 0 END) as tokens_saved
56
+ FROM gateway_cost_log
57
+ WHERE timestamp >= datetime('now', ?)`),
58
+ topSymbols: this.rawDb.prepare(`SELECT js.value as symbol_id,
59
+ COUNT(*) as request_count,
60
+ SUM(cl.cost_estimate) as total_cost,
61
+ SUM(cl.tokens_in + cl.tokens_out) as total_tokens
62
+ FROM gateway_cost_log cl, json_each(cl.symbol_ids) js
63
+ WHERE cl.timestamp >= datetime('now', ?)
64
+ GROUP BY js.value
65
+ ORDER BY total_cost DESC
66
+ LIMIT ?`),
67
+ summary: this.rawDb.prepare(`SELECT
68
+ COUNT(*) as total_requests,
69
+ SUM(tokens_in) as total_tokens_in,
70
+ SUM(tokens_out) as total_tokens_out,
71
+ SUM(cost_estimate) as total_cost,
72
+ AVG(duration_ms) as avg_duration,
73
+ MIN(timestamp) as first_request,
74
+ MAX(timestamp) as last_request
75
+ FROM gateway_cost_log
76
+ WHERE timestamp >= datetime('now', ?)`),
77
+ recentRequests: this.rawDb.prepare(`SELECT * FROM gateway_cost_log ORDER BY timestamp DESC LIMIT ?`),
78
+ };
79
+ }
80
+ /** Record a completed request */
81
+ record(data) {
82
+ const requestId = randomUUID();
83
+ this.stmts.insert.run(requestId, data.provider, data.model, data.tokensIn, data.tokensOut, data.costEstimate, data.durationMs, JSON.stringify(data.symbolIds), JSON.stringify(data.filePaths), data.intent, data.complexityScore, data.tier, data.cacheHit ? 1 : 0);
84
+ return requestId;
85
+ }
86
+ /** Cost breakdown by provider + model */
87
+ getCostByProvider(windowSql = '-30 days') {
88
+ return this.stmts.byProvider.all(windowSql);
89
+ }
90
+ /** Cost breakdown by file path */
91
+ getCostByFile(limit = 20, windowSql = '-30 days') {
92
+ return this.stmts.byFile.all(windowSql, limit);
93
+ }
94
+ /** Cost breakdown by intent */
95
+ getCostByIntent(windowSql = '-30 days') {
96
+ return this.stmts.byIntent.all(windowSql);
97
+ }
98
+ /** Cost breakdown by tier */
99
+ getCostByTier(windowSql = '-30 days') {
100
+ return this.stmts.byTier.all(windowSql);
101
+ }
102
+ /** Cache hit/miss stats and savings */
103
+ getCacheSavings(windowSql = '-30 days') {
104
+ const row = this.stmts.cacheSavings.get(windowSql);
105
+ return {
106
+ cacheHits: row?.cache_hits ?? 0,
107
+ cacheMisses: row?.cache_misses ?? 0,
108
+ costSaved: row?.cost_saved ?? 0,
109
+ tokensSaved: row?.tokens_saved ?? 0,
110
+ hitRate: row?.cache_hits
111
+ ? row.cache_hits / (row.cache_hits + row.cache_misses)
112
+ : 0,
113
+ };
114
+ }
115
+ /** Most expensive symbols */
116
+ getTopExpensiveSymbols(limit = 10, windowSql = '-30 days') {
117
+ return this.stmts.topSymbols.all(windowSql, limit);
118
+ }
119
+ /** Overall summary */
120
+ getSummary(windowSql = '-30 days') {
121
+ const row = this.stmts.summary.get(windowSql);
122
+ return {
123
+ totalRequests: row?.total_requests ?? 0,
124
+ totalTokensIn: row?.total_tokens_in ?? 0,
125
+ totalTokensOut: row?.total_tokens_out ?? 0,
126
+ totalCost: row?.total_cost ?? 0,
127
+ avgDuration: row?.avg_duration ?? 0,
128
+ firstRequest: row?.first_request ?? null,
129
+ lastRequest: row?.last_request ?? null,
130
+ };
131
+ }
132
+ /** Get recent requests for debugging */
133
+ getRecentRequests(limit = 10) {
134
+ return this.stmts.recentRequests.all(limit).map(r => ({
135
+ requestId: r.request_id,
136
+ timestamp: r.timestamp,
137
+ provider: r.provider,
138
+ model: r.model,
139
+ tokensIn: r.tokens_in,
140
+ tokensOut: r.tokens_out,
141
+ costEstimate: r.cost_estimate,
142
+ durationMs: r.duration_ms,
143
+ symbolIds: JSON.parse(r.symbol_ids || '[]'),
144
+ filePaths: JSON.parse(r.file_paths || '[]'),
145
+ intent: r.intent,
146
+ complexityScore: r.complexity_score,
147
+ tier: r.tier,
148
+ cacheHit: !!r.cache_hit,
149
+ }));
150
+ }
151
+ }
152
+ //# sourceMappingURL=observability.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"observability.js","sourceRoot":"","sources":["../../src/gateway/observability.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import type { ChatMessage, PrivacyRule, PrivacyDecision, MessageAnalysis } from './types.js';
2
+ import type BetterSqlite3 from 'better-sqlite3';
3
+ export declare class PrivacyFilter {
4
+ private rawDb;
5
+ private defaultRules;
6
+ private rulesCache;
7
+ private stmts;
8
+ constructor(rawDb: BetterSqlite3.Database, defaultRules?: PrivacyRule[]);
9
+ private prepareStatements;
10
+ /** Evaluate privacy decision for a request based on referenced files */
11
+ evaluate(analysis: MessageAnalysis): PrivacyDecision;
12
+ /** Mask sensitive content in messages — returns masked messages + unmask map */
13
+ maskMessages(messages: ChatMessage[], rules: PrivacyRule[]): {
14
+ masked: ChatMessage[];
15
+ unmaskMap: Map<string, string>;
16
+ };
17
+ /** Restore original content from masked tokens */
18
+ unmask(text: string, unmaskMap: Map<string, string>): string;
19
+ /** Add a privacy rule (persisted to DB) */
20
+ addRule(rule: PrivacyRule): void;
21
+ /** Remove a privacy rule */
22
+ removeRule(pathPattern: string): boolean;
23
+ /** List all rules */
24
+ listRules(): PrivacyRule[];
25
+ private loadRules;
26
+ }
27
+ //# sourceMappingURL=privacy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"privacy.d.ts","sourceRoot":"","sources":["../../src/gateway/privacy.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAiB,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC5G,OAAO,KAAK,aAAa,MAAM,gBAAgB,CAAC;AAEhD,qBAAa,aAAa;IAKtB,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,YAAY;IALtB,OAAO,CAAC,UAAU,CAA8B;IAChD,OAAO,CAAC,KAAK,CAAiD;gBAGpD,KAAK,EAAE,aAAa,CAAC,QAAQ,EAC7B,YAAY,GAAE,WAAW,EAAO;IAK1C,OAAO,CAAC,iBAAiB;IAUzB,wEAAwE;IACxE,QAAQ,CAAC,QAAQ,EAAE,eAAe,GAAG,eAAe;IA6BpD,gFAAgF;IAChF,YAAY,CAAC,QAAQ,EAAE,WAAW,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG;QAAE,MAAM,EAAE,WAAW,EAAE,CAAC;QAAC,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE;IAsBtH,kDAAkD;IAClD,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM;IAQ5D,2CAA2C;IAC3C,OAAO,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI;IAKhC,4BAA4B;IAC5B,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO;IAMxC,qBAAqB;IACrB,SAAS,IAAI,WAAW,EAAE;IAI1B,OAAO,CAAC,SAAS;CAUlB"}
@@ -0,0 +1,139 @@
1
+ // ── Privacy filter — path-based sensitivity rules with masking ──
2
+ import { randomBytes } from 'node:crypto';
3
+ export class PrivacyFilter {
4
+ rawDb;
5
+ defaultRules;
6
+ rulesCache = null;
7
+ stmts;
8
+ constructor(rawDb, defaultRules = []) {
9
+ this.rawDb = rawDb;
10
+ this.defaultRules = defaultRules;
11
+ this.stmts = this.prepareStatements();
12
+ }
13
+ prepareStatements() {
14
+ return {
15
+ listRules: this.rawDb.prepare('SELECT * FROM gateway_privacy_rules ORDER BY path_pattern'),
16
+ addRule: this.rawDb.prepare(`INSERT OR REPLACE INTO gateway_privacy_rules (path_pattern, action, reason) VALUES (?, ?, ?)`),
17
+ removeRule: this.rawDb.prepare('DELETE FROM gateway_privacy_rules WHERE path_pattern = ?'),
18
+ };
19
+ }
20
+ /** Evaluate privacy decision for a request based on referenced files */
21
+ evaluate(analysis) {
22
+ const rules = this.loadRules();
23
+ const matched = [];
24
+ let highestAction = 'allow';
25
+ for (const file of analysis.files) {
26
+ for (const rule of rules) {
27
+ if (matchGlob(file, rule.pathPattern)) {
28
+ matched.push(rule);
29
+ highestAction = promoteAction(highestAction, rule.action);
30
+ }
31
+ }
32
+ }
33
+ // Also check symbol file paths
34
+ for (const sym of analysis.symbols) {
35
+ for (const rule of rules) {
36
+ if (matchGlob(sym.filePath, rule.pathPattern)) {
37
+ if (!matched.some(m => m.pathPattern === rule.pathPattern)) {
38
+ matched.push(rule);
39
+ highestAction = promoteAction(highestAction, rule.action);
40
+ }
41
+ }
42
+ }
43
+ }
44
+ return { action: highestAction, matchedRules: matched };
45
+ }
46
+ /** Mask sensitive content in messages — returns masked messages + unmask map */
47
+ maskMessages(messages, rules) {
48
+ const unmaskMap = new Map();
49
+ const masked = messages.map(msg => {
50
+ const content = typeof msg.content === 'string' ? msg.content : '';
51
+ if (!content)
52
+ return msg;
53
+ let result = content;
54
+ for (const rule of rules) {
55
+ if (rule.action !== 'mask')
56
+ continue;
57
+ result = maskPatternOccurrences(result, rule.pathPattern, unmaskMap);
58
+ }
59
+ // Mask inline @sensitive annotations
60
+ result = maskSensitiveAnnotations(result, unmaskMap);
61
+ return { ...msg, content: result };
62
+ });
63
+ return { masked, unmaskMap };
64
+ }
65
+ /** Restore original content from masked tokens */
66
+ unmask(text, unmaskMap) {
67
+ let result = text;
68
+ for (const [token, original] of unmaskMap) {
69
+ result = result.replaceAll(token, original);
70
+ }
71
+ return result;
72
+ }
73
+ /** Add a privacy rule (persisted to DB) */
74
+ addRule(rule) {
75
+ this.stmts.addRule.run(rule.pathPattern, rule.action, rule.reason ?? null);
76
+ this.rulesCache = null;
77
+ }
78
+ /** Remove a privacy rule */
79
+ removeRule(pathPattern) {
80
+ const r = this.stmts.removeRule.run(pathPattern);
81
+ this.rulesCache = null;
82
+ return r.changes > 0;
83
+ }
84
+ /** List all rules */
85
+ listRules() {
86
+ return this.loadRules();
87
+ }
88
+ loadRules() {
89
+ if (this.rulesCache)
90
+ return this.rulesCache;
91
+ const dbRules = this.stmts.listRules.all().map(r => ({
92
+ pathPattern: r.path_pattern,
93
+ action: r.action,
94
+ reason: r.reason ?? undefined,
95
+ }));
96
+ this.rulesCache = [...this.defaultRules, ...dbRules];
97
+ return this.rulesCache;
98
+ }
99
+ }
100
+ // ── Helpers ──
101
+ /** Simple glob matching: supports * and ** */
102
+ function matchGlob(filePath, pattern) {
103
+ const regex = pattern
104
+ .replace(/[.+^${}()|[\]\\]/g, '\\$&') // Escape special regex chars
105
+ .replace(/\*\*/g, '{{GLOBSTAR}}') // Temp placeholder
106
+ .replace(/\*/g, '[^/]*') // Single glob
107
+ .replace(/{{GLOBSTAR}}/g, '.*'); // Double glob
108
+ return new RegExp(`^${regex}$`).test(filePath);
109
+ }
110
+ /** Promote to higher severity: block > local-only > mask > allow */
111
+ function promoteAction(current, incoming) {
112
+ const priority = { allow: 0, mask: 1, 'local-only': 2, block: 3 };
113
+ return (priority[incoming] ?? 0) > (priority[current] ?? 0) ? incoming : current;
114
+ }
115
+ /** Replace occurrences matching a glob pattern in text with masked tokens */
116
+ function maskPatternOccurrences(text, pathPattern, unmaskMap) {
117
+ // Extract a searchable pattern from the glob (e.g., "secrets/**" → "secrets/")
118
+ const literalPrefix = pathPattern.replace(/\*.*$/, '');
119
+ if (!literalPrefix || !text.includes(literalPrefix))
120
+ return text;
121
+ // Find all file-path-like substrings starting with the literal prefix
122
+ const filePathRe = new RegExp(literalPrefix.replace(/[.+^${}()|[\]\\]/g, '\\$&') + '[\\w/._-]*', 'g');
123
+ return text.replace(filePathRe, match => {
124
+ if (!matchGlob(match, pathPattern))
125
+ return match;
126
+ const token = `[REDACTED_${randomBytes(4).toString('hex')}]`;
127
+ unmaskMap.set(token, match);
128
+ return token;
129
+ });
130
+ }
131
+ /** Mask content wrapped in @sensitive{...} annotations */
132
+ function maskSensitiveAnnotations(text, unmaskMap) {
133
+ return text.replace(/@sensitive\{([^}]+)\}/g, (_match, inner) => {
134
+ const token = `[REDACTED_${randomBytes(4).toString('hex')}]`;
135
+ unmaskMap.set(token, inner);
136
+ return token;
137
+ });
138
+ }
139
+ //# sourceMappingURL=privacy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"privacy.js","sourceRoot":"","sources":["../../src/gateway/privacy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,66 @@
1
+ import type { ProviderConfig, ProviderState, ProviderStatus, Tier, ChatRequest, SSEChunk, SSEChoiceDelta, ChatResponse } from './types.js';
2
+ export interface ChatResult {
3
+ response: ChatResponse;
4
+ durationMs: number;
5
+ }
6
+ export interface StreamChunk {
7
+ chunk: SSEChunk;
8
+ raw?: string;
9
+ }
10
+ export declare abstract class BaseAdapter {
11
+ protected config: ProviderConfig;
12
+ constructor(config: ProviderConfig);
13
+ abstract chat(req: ChatRequest): Promise<ChatResult>;
14
+ abstract chatStream(req: ChatRequest): AsyncGenerator<StreamChunk>;
15
+ protected fetchWithTimeout(url: string, init: RequestInit): Promise<Response>;
16
+ protected makeSSEChunk(delta: SSEChoiceDelta, model: string): SSEChunk;
17
+ }
18
+ export declare class OpenAIAdapter extends BaseAdapter {
19
+ chat(req: ChatRequest): Promise<ChatResult>;
20
+ chatStream(req: ChatRequest): AsyncGenerator<StreamChunk>;
21
+ private headers;
22
+ private parseSSEStream;
23
+ }
24
+ export declare class AnthropicAdapter extends BaseAdapter {
25
+ chat(req: ChatRequest): Promise<ChatResult>;
26
+ chatStream(req: ChatRequest): AsyncGenerator<StreamChunk>;
27
+ private headers;
28
+ }
29
+ export declare class GeminiAdapter extends BaseAdapter {
30
+ chat(req: ChatRequest): Promise<ChatResult>;
31
+ chatStream(req: ChatRequest): AsyncGenerator<StreamChunk>;
32
+ private buildUrl;
33
+ }
34
+ export declare class ProviderRegistry {
35
+ private providers;
36
+ private adapters;
37
+ private roundRobinIndex;
38
+ addProvider(config: ProviderConfig): void;
39
+ removeProvider(id: string): void;
40
+ getAdapter(id: string): BaseAdapter | undefined;
41
+ getState(id: string): ProviderState | undefined;
42
+ /** Get all providers for a tier, ordered by round-robin */
43
+ getByTier(tier: Tier): ProviderConfig[];
44
+ /** Build a fallback chain: requested tier → lower tiers */
45
+ buildFallbackChain(startTier: Tier): ProviderConfig[];
46
+ /** Mark a provider as used, update stats */
47
+ recordUse(id: string, tokens: number): void;
48
+ /** Mark a provider failure */
49
+ recordFailure(id: string, error: string): void;
50
+ /** List all model IDs across all providers */
51
+ listModels(): Array<{
52
+ id: string;
53
+ provider: string;
54
+ tier: Tier;
55
+ }>;
56
+ /** Find which provider has a specific model */
57
+ findByModel(model: string): ProviderConfig | undefined;
58
+ /** Get health status for all providers */
59
+ getHealthStatus(): Array<{
60
+ id: string;
61
+ status: ProviderStatus;
62
+ tier: Tier;
63
+ requests: number;
64
+ }>;
65
+ }
66
+ //# sourceMappingURL=providers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"providers.d.ts","sourceRoot":"","sources":["../../src/gateway/providers.ts"],"names":[],"mappings":"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"}