@nxuss/lemma 1.11.0 → 1.14.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.
Files changed (80) hide show
  1. package/README.md +98 -821
  2. package/dist/cjs/cli/lemma-proxy.d.ts.map +1 -1
  3. package/dist/cjs/cli/lemma-proxy.js +14 -0
  4. package/dist/cjs/cli/lemma-proxy.js.map +1 -1
  5. package/dist/cjs/infra/mcp-tools.d.ts +7 -0
  6. package/dist/cjs/infra/mcp-tools.d.ts.map +1 -1
  7. package/dist/cjs/infra/mcp-tools.js +22 -0
  8. package/dist/cjs/infra/mcp-tools.js.map +1 -1
  9. package/dist/cjs/mcp/index.js +35 -7
  10. package/dist/cjs/mcp/index.js.map +1 -1
  11. package/dist/cjs/mcp/prompts.d.ts +1 -0
  12. package/dist/cjs/mcp/prompts.d.ts.map +1 -1
  13. package/dist/cjs/mcp/prompts.js +98 -0
  14. package/dist/cjs/mcp/prompts.js.map +1 -1
  15. package/dist/cjs/mcp/resources.d.ts +2 -0
  16. package/dist/cjs/mcp/resources.d.ts.map +1 -1
  17. package/dist/cjs/mcp/resources.js +26 -0
  18. package/dist/cjs/mcp/resources.js.map +1 -1
  19. package/dist/cjs/mcp/tasks.d.ts +20 -0
  20. package/dist/cjs/mcp/tasks.d.ts.map +1 -0
  21. package/dist/cjs/mcp/tasks.js +71 -0
  22. package/dist/cjs/mcp/tasks.js.map +1 -0
  23. package/dist/cjs/mcp/tool-profiles.d.ts.map +1 -1
  24. package/dist/cjs/mcp/tool-profiles.js +29 -50
  25. package/dist/cjs/mcp/tool-profiles.js.map +1 -1
  26. package/dist/cjs/mcp/tools.d.ts.map +1 -1
  27. package/dist/cjs/mcp/tools.js +575 -93
  28. package/dist/cjs/mcp/tools.js.map +1 -1
  29. package/dist/cjs/proxy/Gatekeeper.d.ts +29 -0
  30. package/dist/cjs/proxy/Gatekeeper.d.ts.map +1 -1
  31. package/dist/cjs/proxy/Gatekeeper.js +122 -1
  32. package/dist/cjs/proxy/Gatekeeper.js.map +1 -1
  33. package/dist/cjs/subconscious/TheBrainV2.d.ts +50 -1
  34. package/dist/cjs/subconscious/TheBrainV2.d.ts.map +1 -1
  35. package/dist/cjs/subconscious/TheBrainV2.js +149 -8
  36. package/dist/cjs/subconscious/TheBrainV2.js.map +1 -1
  37. package/dist/cjs/utils/PatchMatcher.d.ts +1 -0
  38. package/dist/cjs/utils/PatchMatcher.d.ts.map +1 -1
  39. package/dist/cjs/utils/PatchMatcher.js +4 -4
  40. package/dist/cjs/utils/PatchMatcher.js.map +1 -1
  41. package/dist/esm/cli/lemma-proxy.d.ts.map +1 -1
  42. package/dist/esm/cli/lemma-proxy.js +14 -0
  43. package/dist/esm/cli/lemma-proxy.js.map +1 -1
  44. package/dist/esm/infra/mcp-tools.d.ts +7 -0
  45. package/dist/esm/infra/mcp-tools.d.ts.map +1 -1
  46. package/dist/esm/infra/mcp-tools.js +22 -0
  47. package/dist/esm/infra/mcp-tools.js.map +1 -1
  48. package/dist/esm/mcp/index.js +37 -9
  49. package/dist/esm/mcp/index.js.map +1 -1
  50. package/dist/esm/mcp/prompts.d.ts +1 -0
  51. package/dist/esm/mcp/prompts.d.ts.map +1 -1
  52. package/dist/esm/mcp/prompts.js +95 -1
  53. package/dist/esm/mcp/prompts.js.map +1 -1
  54. package/dist/esm/mcp/resources.d.ts +2 -0
  55. package/dist/esm/mcp/resources.d.ts.map +1 -1
  56. package/dist/esm/mcp/resources.js +27 -2
  57. package/dist/esm/mcp/resources.js.map +1 -1
  58. package/dist/esm/mcp/tasks.d.ts +20 -0
  59. package/dist/esm/mcp/tasks.d.ts.map +1 -0
  60. package/dist/esm/mcp/tasks.js +66 -0
  61. package/dist/esm/mcp/tasks.js.map +1 -0
  62. package/dist/esm/mcp/tool-profiles.d.ts.map +1 -1
  63. package/dist/esm/mcp/tool-profiles.js +29 -50
  64. package/dist/esm/mcp/tool-profiles.js.map +1 -1
  65. package/dist/esm/mcp/tools.d.ts.map +1 -1
  66. package/dist/esm/mcp/tools.js +577 -95
  67. package/dist/esm/mcp/tools.js.map +1 -1
  68. package/dist/esm/proxy/Gatekeeper.d.ts +29 -0
  69. package/dist/esm/proxy/Gatekeeper.d.ts.map +1 -1
  70. package/dist/esm/proxy/Gatekeeper.js +120 -0
  71. package/dist/esm/proxy/Gatekeeper.js.map +1 -1
  72. package/dist/esm/subconscious/TheBrainV2.d.ts +50 -1
  73. package/dist/esm/subconscious/TheBrainV2.d.ts.map +1 -1
  74. package/dist/esm/subconscious/TheBrainV2.js +149 -8
  75. package/dist/esm/subconscious/TheBrainV2.js.map +1 -1
  76. package/dist/esm/utils/PatchMatcher.d.ts +1 -0
  77. package/dist/esm/utils/PatchMatcher.d.ts.map +1 -1
  78. package/dist/esm/utils/PatchMatcher.js +4 -4
  79. package/dist/esm/utils/PatchMatcher.js.map +1 -1
  80. package/package.json +2 -2
@@ -17,6 +17,18 @@ export interface GatekeeperStatus {
17
17
  isPro: boolean;
18
18
  licenseKey: string | null;
19
19
  }
20
+ export type InferenceMode = 'cloud' | 'hybrid' | 'airgapped';
21
+ export interface EgressDecision {
22
+ allowed: boolean;
23
+ mode: InferenceMode;
24
+ host: string;
25
+ reason: string;
26
+ }
27
+ export declare class EgressBlockedError extends Error {
28
+ readonly decision: EgressDecision;
29
+ code: "EGRESS_BLOCKED";
30
+ constructor(decision: EgressDecision);
31
+ }
20
32
  export interface CacheBackend {
21
33
  set(key: string, input: string, data: any, ttl: number): Promise<void>;
22
34
  findSimilar(input: string, threshold: number): Promise<{
@@ -32,7 +44,24 @@ export declare class Gatekeeper extends EventEmitter {
32
44
  private memBackend;
33
45
  private semBackend;
34
46
  private semInitialized;
47
+ private inferenceMode;
48
+ private allowedEndpoints;
35
49
  constructor(keyManager: KeyManager);
50
+ private loadInferencePolicy;
51
+ getInferenceStatus(): {
52
+ mode: InferenceMode;
53
+ allowedEndpoints: string[];
54
+ };
55
+ /**
56
+ * Central egress decision. Called once per outbound provider request from
57
+ * lemma-proxy.ts — no call site talks to a provider without going through this.
58
+ */
59
+ checkEgress(urlOrHost: string): EgressDecision;
60
+ /**
61
+ * Throws EgressBlockedError on denial, and emits 'egress-blocked' so callers
62
+ * (e.g. the audit/token_receipt log) can record the attempt for compliance.
63
+ */
64
+ assertEgressAllowed(urlOrHost: string): void;
36
65
  getBackend(): Promise<CacheBackend>;
37
66
  getMode(): CacheMode;
38
67
  getStatus(): GatekeeperStatus;
@@ -1 +1 @@
1
- {"version":3,"file":"Gatekeeper.d.ts","sourceRoot":"","sources":["../../../src/proxy/Gatekeeper.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,MAAM,MAAM,SAAS,GAAG,UAAU,GAAG,KAAK,CAAC;AAE3C,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,SAAS,CAAC;IAChB,eAAe,EAAE,OAAO,CAAC;IACzB,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvE,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,GAAG,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;IACjG,IAAI,IAAI,MAAM,CAAC;IACf,KAAK,IAAI,IAAI,CAAC;CACf;AAED,qBAAa,UAAW,SAAQ,YAAY;IAC1C,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,QAAQ,CAA0B;IAC1C,OAAO,CAAC,UAAU,CAA6B;IAC/C,OAAO,CAAC,UAAU,CAA6B;IAC/C,OAAO,CAAC,cAAc,CAAS;gBAEnB,UAAU,EAAE,UAAU;IAK5B,UAAU,IAAI,OAAO,CAAC,YAAY,CAAC;IAazC,OAAO,IAAI,SAAS;IAIpB,SAAS,IAAI,gBAAgB;IAK7B,MAAM,IAAI,IAAI;IAId,OAAO,CAAC,gBAAgB;YAKV,kBAAkB;CAejC"}
1
+ {"version":3,"file":"Gatekeeper.d.ts","sourceRoot":"","sources":["../../../src/proxy/Gatekeeper.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,MAAM,MAAM,SAAS,GAAG,UAAU,GAAG,KAAK,CAAC;AAE3C,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,SAAS,CAAC;IAChB,eAAe,EAAE,OAAO,CAAC;IACzB,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAmBD,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,QAAQ,GAAG,WAAW,CAAC;AAE7D,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,aAAa,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,kBAAmB,SAAQ,KAAK;aAEf,QAAQ,EAAE,cAAc;IADpD,IAAI,EAAG,gBAAgB,CAAU;gBACL,QAAQ,EAAE,cAAc;CAOrD;AA0CD,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvE,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,GAAG,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;IACjG,IAAI,IAAI,MAAM,CAAC;IACf,KAAK,IAAI,IAAI,CAAC;CACf;AAED,qBAAa,UAAW,SAAQ,YAAY;IAC1C,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,QAAQ,CAA0B;IAC1C,OAAO,CAAC,UAAU,CAA6B;IAC/C,OAAO,CAAC,UAAU,CAA6B;IAC/C,OAAO,CAAC,cAAc,CAAS;IAE/B,OAAO,CAAC,aAAa,CAA0B;IAC/C,OAAO,CAAC,gBAAgB,CAA0B;gBAEtC,UAAU,EAAE,UAAU;IAMlC,OAAO,CAAC,mBAAmB;IAsB3B,kBAAkB;;;;IAOlB;;;OAGG;IACH,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,cAAc;IAgC9C;;;OAGG;IACH,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAStC,UAAU,IAAI,OAAO,CAAC,YAAY,CAAC;IAazC,OAAO,IAAI,SAAS;IAIpB,SAAS,IAAI,gBAAgB;IAK7B,MAAM,IAAI,IAAI;IAKd,OAAO,CAAC,gBAAgB;YAKV,kBAAkB;CAejC"}
@@ -9,6 +9,57 @@
9
9
  * Emits 'mode-changed' when the effective tier switches.
10
10
  */
11
11
  import { EventEmitter } from 'events';
12
+ export class EgressBlockedError extends Error {
13
+ constructor(decision) {
14
+ super(`[Gatekeeper] Blocked outbound request to "${decision.host}" ` +
15
+ `(LEMMA_INFERENCE_MODE=${decision.mode}): ${decision.reason}`);
16
+ this.decision = decision;
17
+ this.code = 'EGRESS_BLOCKED';
18
+ this.name = 'EgressBlockedError';
19
+ }
20
+ }
21
+ // Public LLM provider hosts we recognize by default. Not exhaustive — enterprises
22
+ // extend this via LEMMA_ALLOWED_ENDPOINTS (allow) rather than us maintaining a
23
+ // perfect blocklist (deny-lists always miss something; this list only needs to
24
+ // cover the hosts Lemma itself dials directly, see lemma-proxy.ts callUpstream).
25
+ const KNOWN_PUBLIC_LLM_HOSTS = [
26
+ 'api.openai.com',
27
+ 'api.anthropic.com',
28
+ 'generativelanguage.googleapis.com',
29
+ 'api.mistral.ai',
30
+ 'api.cohere.ai',
31
+ ];
32
+ function parseAllowedEndpoints(raw) {
33
+ if (!raw)
34
+ return new Set();
35
+ return new Set(raw.split(',').map(h => h.trim().toLowerCase()).filter(Boolean));
36
+ }
37
+ function hostOf(urlOrHost) {
38
+ try {
39
+ return new URL(urlOrHost).hostname.toLowerCase();
40
+ }
41
+ catch {
42
+ // Already a bare hostname (e.g. from a config value, not a full URL)
43
+ return urlOrHost.toLowerCase().replace(/:\d+$/, '');
44
+ }
45
+ }
46
+ function isPrivateHost(host) {
47
+ if (host === 'localhost' || host === '127.0.0.1' || host === '::1')
48
+ return true;
49
+ if (host.endsWith('.local') || host.endsWith('.internal'))
50
+ return true;
51
+ const m = host.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/);
52
+ if (!m)
53
+ return false;
54
+ const [a, b] = [parseInt(m[1], 10), parseInt(m[2], 10)];
55
+ if (a === 10)
56
+ return true; // 10.0.0.0/8
57
+ if (a === 172 && b >= 16 && b <= 31)
58
+ return true; // 172.16.0.0/12
59
+ if (a === 192 && b === 168)
60
+ return true; // 192.168.0.0/16
61
+ return false;
62
+ }
12
63
  export class Gatekeeper extends EventEmitter {
13
64
  constructor(keyManager) {
14
65
  super();
@@ -16,7 +67,75 @@ export class Gatekeeper extends EventEmitter {
16
67
  this.memBackend = null;
17
68
  this.semBackend = null;
18
69
  this.semInitialized = false;
70
+ this.inferenceMode = 'cloud';
71
+ this.allowedEndpoints = new Set();
19
72
  this.keyManager = keyManager;
73
+ this.loadInferencePolicy();
74
+ }
75
+ loadInferencePolicy() {
76
+ const envValue = process.env.LEMMA_INFERENCE_MODE;
77
+ const raw = (envValue || 'cloud').toLowerCase();
78
+ this.allowedEndpoints = parseAllowedEndpoints(process.env.LEMMA_ALLOWED_ENDPOINTS);
79
+ if (raw === 'cloud' || raw === 'hybrid' || raw === 'airgapped') {
80
+ this.inferenceMode = raw;
81
+ return;
82
+ }
83
+ // LEMMA_INFERENCE_MODE was set to something we don't recognize (typo, stale
84
+ // value, etc). Unset defaults to "cloud" for backward compatibility, but a
85
+ // *garbled* value must not silently fall back to the unrestricted mode — that
86
+ // would let a typo quietly disable the one thing enterprises deploy this for.
87
+ // Fail closed to the strictest mode instead.
88
+ this.inferenceMode = 'airgapped';
89
+ console.error(`[Gatekeeper] Unknown LEMMA_INFERENCE_MODE="${envValue}". Failing closed to "airgapped" ` +
90
+ `(only private hosts + LEMMA_ALLOWED_ENDPOINTS) until this is fixed to one of: cloud, hybrid, airgapped.`);
91
+ }
92
+ getInferenceStatus() {
93
+ return {
94
+ mode: this.inferenceMode,
95
+ allowedEndpoints: Array.from(this.allowedEndpoints),
96
+ };
97
+ }
98
+ /**
99
+ * Central egress decision. Called once per outbound provider request from
100
+ * lemma-proxy.ts — no call site talks to a provider without going through this.
101
+ */
102
+ checkEgress(urlOrHost) {
103
+ const host = hostOf(urlOrHost);
104
+ const mode = this.inferenceMode;
105
+ if (mode === 'cloud') {
106
+ return { allowed: true, mode, host, reason: 'LEMMA_INFERENCE_MODE=cloud (unrestricted)' };
107
+ }
108
+ if (this.allowedEndpoints.has(host)) {
109
+ return { allowed: true, mode, host, reason: 'host is in LEMMA_ALLOWED_ENDPOINTS' };
110
+ }
111
+ if (isPrivateHost(host)) {
112
+ return { allowed: true, mode, host, reason: 'private/local host' };
113
+ }
114
+ if (mode === 'hybrid' && !KNOWN_PUBLIC_LLM_HOSTS.includes(host)) {
115
+ // hybrid only blocks recognized public LLM providers; unknown hosts (e.g. a
116
+ // customer's own SaaS endpoint) pass through unless they opt into airgapped.
117
+ return { allowed: true, mode, host, reason: 'not a recognized public LLM provider host' };
118
+ }
119
+ return {
120
+ allowed: false,
121
+ mode,
122
+ host,
123
+ reason: mode === 'airgapped'
124
+ ? 'airgapped mode blocks all non-private hosts not in LEMMA_ALLOWED_ENDPOINTS'
125
+ : 'hybrid mode blocks known public LLM provider hosts not in LEMMA_ALLOWED_ENDPOINTS',
126
+ };
127
+ }
128
+ /**
129
+ * Throws EgressBlockedError on denial, and emits 'egress-blocked' so callers
130
+ * (e.g. the audit/token_receipt log) can record the attempt for compliance.
131
+ */
132
+ assertEgressAllowed(urlOrHost) {
133
+ const decision = this.checkEgress(urlOrHost);
134
+ if (!decision.allowed) {
135
+ this.emit('egress-blocked', { ...decision, timestamp: Date.now() });
136
+ console.warn(`[Gatekeeper] BLOCKED egress to ${decision.host} (mode=${decision.mode}): ${decision.reason}`);
137
+ throw new EgressBlockedError(decision);
138
+ }
20
139
  }
21
140
  async getBackend() {
22
141
  const mode = this.getMode();
@@ -39,6 +158,7 @@ export class Gatekeeper extends EventEmitter {
39
158
  }
40
159
  reload() {
41
160
  this.keyManager.reload();
161
+ this.loadInferencePolicy();
42
162
  }
43
163
  getMemoryBackend() {
44
164
  if (!this.memBackend)
@@ -1 +1 @@
1
- {"version":3,"file":"Gatekeeper.js","sourceRoot":"","sources":["../../../src/proxy/Gatekeeper.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Gatekeeper.js","sourceRoot":"","sources":["../../../src/proxy/Gatekeeper.ts"],"names":[],"mappings":"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"}
@@ -38,6 +38,12 @@ export interface BrainEntry {
38
38
  * fix — the Brain can only ever suggest reuse, never warn "we already tried this."
39
39
  */
40
40
  outcome?: 'confirmed' | 'failed';
41
+ /**
42
+ * Free-text domain tag (e.g. "auth", "billing") lifted from cognitive_map's current
43
+ * context at store time. Absent means untagged — those entries stay visible to every
44
+ * domain-scoped search rather than disappearing, same rationale as projectId above.
45
+ */
46
+ domain?: string;
41
47
  /**
42
48
  * Absolute-path::symbolName -> sha256 of just that symbol's extracted source (via
43
49
  * SymbolSurgicalContext), not the whole file. When a file has an entry here, freshness
@@ -55,6 +61,12 @@ export interface BrainEntry {
55
61
  * still trustworthy instead of discarding (or blindly trusting) the whole thing.
56
62
  */
57
63
  claims?: Claim[];
64
+ /**
65
+ * Count of explicit "this memory led me astray" signals via downvote(). Distinct from
66
+ * hits: hits means "this surfaced and looked relevant enough to reuse," demerits means
67
+ * "reuse turned out to be wrong." Absent/0 means never downvoted.
68
+ */
69
+ demerits?: number;
58
70
  }
59
71
  export interface Claim {
60
72
  id: string;
@@ -89,6 +101,7 @@ export interface BrainSearchResult {
89
101
  staleFiles?: string[];
90
102
  outcome?: 'confirmed' | 'failed';
91
103
  claims?: ClaimFreshness[];
104
+ domain?: string;
92
105
  }
93
106
  export interface BrainSearchOptions {
94
107
  /**
@@ -99,6 +112,8 @@ export interface BrainSearchOptions {
99
112
  countStats?: boolean;
100
113
  /** Prefer memories from this project. See the scoping note in search(). */
101
114
  projectId?: string;
115
+ /** Prefer memories tagged with this domain. Same soft-fallback rule as projectId. */
116
+ domain?: string;
102
117
  }
103
118
  export interface BrainStats {
104
119
  totalEntries: number;
@@ -156,11 +171,33 @@ export declare class TheBrainV2 {
156
171
  * Store a query+response pair in the brain.
157
172
  * Returns false if detected as duplicate (>= dupThreshold similarity).
158
173
  */
159
- store(query: string, response: string, provider?: string, dupThreshold?: number, filePaths?: string[], projectId?: string, outcome?: 'confirmed' | 'failed', symbolRefs?: SymbolRef[], claimInputs?: ClaimInput[]): {
174
+ store(query: string, response: string, provider?: string, dupThreshold?: number, filePaths?: string[], projectId?: string, outcome?: 'confirmed' | 'failed', symbolRefs?: SymbolRef[], claimInputs?: ClaimInput[], domain?: string): {
160
175
  stored: boolean;
161
176
  reason: string;
162
177
  duplicate?: BrainSearchResult;
178
+ conflicts?: Array<{
179
+ id: string;
180
+ query: string;
181
+ outcome: 'confirmed' | 'failed';
182
+ }>;
163
183
  };
184
+ /**
185
+ * Hard cap on entry count. Past this, the inverted index keeps growing and old, unused
186
+ * entries dilute every future BM25 IDF calculation (more docs sharing a term → lower
187
+ * signal) without ever being asked for again. Evicting keeps ranking quality from
188
+ * degrading as the Brain accumulates months of memories.
189
+ */
190
+ private static readonly MAX_ENTRIES;
191
+ /** How many entries to evict per pass once over MAX_ENTRIES — batched, not one-at-a-time. */
192
+ private static readonly EVICT_BATCH;
193
+ /**
194
+ * Evict the lowest-value entries once the Brain is over capacity. Value = hits (proven
195
+ * usefulness) with a mild recency tiebreak — never based on similarity to any one query,
196
+ * since an entry unrelated to today's search may still be exactly what tomorrow's needs.
197
+ * Failed-outcome entries are cheap to keep (they're short, deliberate warnings) so they're
198
+ * evicted last among equally-unused entries rather than first.
199
+ */
200
+ private evictIfOverCapacity;
164
201
  /**
165
202
  * Search brain using BM25 + Jaccard re-ranking.
166
203
  * Returns results with similarity scores normalized to 0-1.
@@ -180,6 +217,18 @@ export declare class TheBrainV2 {
180
217
  similarity: number;
181
218
  existing?: BrainSearchResult;
182
219
  };
220
+ /**
221
+ * Record that a specific memory turned out NOT to help — the caller acted on it and it
222
+ * was wrong, misleading, or irrelevant despite ranking well. Unlike `outcome: 'failed'`
223
+ * (set at store time, about the underlying approach), this is set after the fact, about
224
+ * the memory's usefulness as a search result. Lowers future ranking and eviction priority
225
+ * without deleting the entry — a bad-fit-today memory may still be exactly right for a
226
+ * differently-phrased query tomorrow.
227
+ */
228
+ downvote(id: string): {
229
+ ok: boolean;
230
+ message: string;
231
+ };
183
232
  getStats(): BrainStats;
184
233
  clear(): void;
185
234
  }
@@ -1 +1 @@
1
- {"version":3,"file":"TheBrainV2.d.ts","sourceRoot":"","sources":["../../../src/subconscious/TheBrainV2.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAUH,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAInB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC;;;;;OAKG;IACH,OAAO,CAAC,EAAE,WAAW,GAAG,QAAQ,CAAC;IACjC;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,KAAK;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACvC;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,OAAO,CAAC,EAAE,SAAS,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,SAAS;IACxB,sFAAsF;IACtF,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,OAAO,CAAC,EAAE,WAAW,GAAG,QAAQ,CAAC;IACjC,MAAM,CAAC,EAAE,cAAc,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,kBAAkB;IACjC;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,2EAA2E;IAC3E,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB;AAqBD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,GAAG,GAAE,MAAsB,GAAG,MAAM,CAqCnE;AAID;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAuD/C;AA4BD;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAMvE;AAgBD,qBAAa,WAAW;IACtB,OAAO,CAAC,IAAI,CAAa;gBAEb,UAAU,CAAC,EAAE,MAAM;IAQ/B,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAOvB,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAQ1B,SAAS,IAAI,MAAM;CAGpB;AAID,wBAAgB,SAAS,CACvB,UAAU,EAAE,MAAM,EAAE,EACpB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACnC,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC1B,MAAM,CAWR;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,MAAM,CAO9E;AA8ID,qBAAa,UAAU;IACrB,OAAO,CAAC,OAAO,CAAsC;IACrD,OAAO,CAAC,aAAa,CAAuC;IAC5D,OAAO,CAAC,KAAK,CAAkC;IAC/C,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,UAAU,CAA8C;;IAShE,OAAO,CAAC,SAAS;IAMjB,OAAO,CAAC,IAAI;IA0CZ,OAAO,CAAC,kBAAkB;IAM1B,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,IAAI;IAiCZ;;;OAGG;IACH,KAAK,CACH,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,QAAQ,SAAY,EACpB,YAAY,SAAO,EACnB,SAAS,CAAC,EAAE,MAAM,EAAE,EACpB,SAAS,GAAE,MAA0B,EACrC,OAAO,CAAC,EAAE,WAAW,GAAG,QAAQ,EAChC,UAAU,CAAC,EAAE,SAAS,EAAE,EACxB,WAAW,CAAC,EAAE,UAAU,EAAE,GACzB;QAAE,MAAM,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,iBAAiB,CAAA;KAAE;IA6DrE;;;OAGG;IACH,MAAM,CACJ,KAAK,EAAE,MAAM,EACb,KAAK,SAAI,EACT,aAAa,SAAI,EACjB,OAAO,GAAE,kBAAuB,GAC/B,iBAAiB,EAAE;IAgItB;;;OAGG;IACH,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,UAAU,EAAE;IAQrD;;;OAGG;IACH,cAAc,CACZ,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,SAAS,SAAO,GACf;QAAE,WAAW,EAAE,OAAO,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,iBAAiB,CAAA;KAAE;IA6B7E,QAAQ,IAAI,UAAU;IAWtB,KAAK,IAAI,IAAI;CAad;AAMD,wBAAgB,QAAQ,IAAI,UAAU,CAGrC"}
1
+ {"version":3,"file":"TheBrainV2.d.ts","sourceRoot":"","sources":["../../../src/subconscious/TheBrainV2.ts"],"names":[],"mappings":"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"}
@@ -129,7 +129,37 @@ export function tokenize(text) {
129
129
  // the same index bucket. Purely additive: old entries that predate this still match on
130
130
  // their original terms exactly as before, they just don't get the extra recall.
131
131
  const stems = terms.map(stem).filter(s => s !== undefined);
132
- return [...new Set([...terms, ...bigrams, ...stems])];
132
+ // 7. Add a shared cluster tag for known dev-vocabulary synonyms (bilingual) so "jwt
133
+ // expiration" and "token timeout" land on a common term without needing embeddings.
134
+ // Purely additive, same rationale as stems — never replaces the surface form, so it
135
+ // can only add recall, never hide an existing exact match.
136
+ const synonymTags = terms
137
+ .map(t => SYNONYM_CLUSTERS.get(t))
138
+ .filter((c) => c !== undefined);
139
+ return [...new Set([...terms, ...bigrams, ...stems, ...synonymTags])];
140
+ }
141
+ // Groups of interchangeable dev-vocabulary terms (bilingual). Each member maps to a shared
142
+ // `syn_<canonical>` token so any two synonyms in the same group become a shared index bucket
143
+ // — a cheap substitute for embeddings when the gap is "different word, same concept" rather
144
+ // than true paraphrase. Keep groups small and unambiguous; a bad merge can only add a false
145
+ // candidate (never hide a real exact match), but it does dilute BM25 signal if overused.
146
+ const SYNONYM_GROUPS = [
147
+ ['jwt', 'token', 'session', 'auth', 'login', 'autenticacion', 'sesion', 'autenticar'],
148
+ ['timeout', 'expiration', 'expiry', 'vencimiento', 'caducidad', 'expirar', 'vencer'],
149
+ ['bug', 'error', 'fallo', 'falla', 'issue', 'defect', 'defecto'],
150
+ ['fix', 'patch', 'solucion', 'solucionar', 'arreglar', 'corregir', 'hotfix'],
151
+ ['delete', 'remove', 'eliminar', 'borrar', 'quitar'],
152
+ ['config', 'configuration', 'configuracion', 'settings', 'ajustes'],
153
+ ['deploy', 'deployment', 'despliegue', 'desplegar', 'release'],
154
+ ['crash', 'exception', 'excepcion', 'throw', 'falla'],
155
+ ['slow', 'lento', 'lentitud', 'latency', 'latencia', 'performance', 'rendimiento'],
156
+ ['test', 'tests', 'testing', 'prueba', 'pruebas', 'spec'],
157
+ ];
158
+ const SYNONYM_CLUSTERS = new Map();
159
+ for (const group of SYNONYM_GROUPS) {
160
+ const canonical = `syn_${group[0]}`;
161
+ for (const member of group)
162
+ SYNONYM_CLUSTERS.set(member, canonical);
133
163
  }
134
164
  // Suffix-stripping rules, longest/most-specific match first. Additive expansion only —
135
165
  // this is not a correctness-critical stemmer, so mild over-stemming (merging two distinct
@@ -470,7 +500,7 @@ export class TheBrainV2 {
470
500
  * Store a query+response pair in the brain.
471
501
  * Returns false if detected as duplicate (>= dupThreshold similarity).
472
502
  */
473
- store(query, response, provider = 'generic', dupThreshold = 0.92, filePaths, projectId = deriveProjectId(), outcome, symbolRefs, claimInputs) {
503
+ store(query, response, provider = 'generic', dupThreshold = 0.92, filePaths, projectId = deriveProjectId(), outcome, symbolRefs, claimInputs, domain) {
474
504
  // Quick bloom check
475
505
  const queryKey = query.trim().toLowerCase().substring(0, 200);
476
506
  if (this.bloom.has(queryKey)) {
@@ -484,6 +514,28 @@ export class TheBrainV2 {
484
514
  };
485
515
  }
486
516
  }
517
+ // Conflict check: another entry about the exact same symbol, with the opposite
518
+ // outcome, is worth flagging before this one is even written — two memories about one
519
+ // function disagreeing on whether an approach works is a trap for whoever searches next.
520
+ // Not a block, just a warning: the newer entry may legitimately supersede the older one.
521
+ let conflicts;
522
+ if (symbolRefs && symbolRefs.length > 0) {
523
+ const newKeys = new Set(symbolRefs.map((r) => `${path.resolve(r.filePath)}::${r.symbolName}`));
524
+ const newOutcome = outcome === 'failed' ? 'failed' : 'confirmed';
525
+ const found = [];
526
+ for (const existingEntry of this.entries.values()) {
527
+ if (!existingEntry.symbolHashes)
528
+ continue;
529
+ const existingOutcome = existingEntry.outcome === 'failed' ? 'failed' : 'confirmed';
530
+ if (existingOutcome === newOutcome)
531
+ continue;
532
+ const sharesSymbol = Object.keys(existingEntry.symbolHashes).some((k) => newKeys.has(k));
533
+ if (sharesSymbol)
534
+ found.push({ id: existingEntry.id, query: existingEntry.query, outcome: existingOutcome });
535
+ }
536
+ if (found.length > 0)
537
+ conflicts = found;
538
+ }
487
539
  const terms = tokenize(query + ' ' + response);
488
540
  const termFreq = termFrequencies(terms);
489
541
  const id = crypto
@@ -506,6 +558,7 @@ export class TheBrainV2 {
506
558
  outcome,
507
559
  symbolHashes: symbolRefs && symbolRefs.length > 0 ? hashSymbolsForFreshness(symbolRefs) : undefined,
508
560
  claims: claimInputs && claimInputs.length > 0 ? buildClaims(claimInputs) : undefined,
561
+ domain,
509
562
  };
510
563
  this.entries.set(id, entry);
511
564
  // Update inverted index
@@ -518,8 +571,46 @@ export class TheBrainV2 {
518
571
  // Update bloom
519
572
  this.bloom.add(queryKey);
520
573
  this.recalcAvgDocLength();
574
+ this.evictIfOverCapacity();
521
575
  this.scheduleSave();
522
- return { stored: true, reason: 'Stored successfully' };
576
+ return { stored: true, reason: 'Stored successfully', conflicts };
577
+ }
578
+ /**
579
+ * Evict the lowest-value entries once the Brain is over capacity. Value = hits (proven
580
+ * usefulness) with a mild recency tiebreak — never based on similarity to any one query,
581
+ * since an entry unrelated to today's search may still be exactly what tomorrow's needs.
582
+ * Failed-outcome entries are cheap to keep (they're short, deliberate warnings) so they're
583
+ * evicted last among equally-unused entries rather than first.
584
+ */
585
+ evictIfOverCapacity() {
586
+ if (this.entries.size <= TheBrainV2.MAX_ENTRIES)
587
+ return;
588
+ const ranked = Array.from(this.entries.values()).sort((a, b) => {
589
+ // Net value = hits minus twice the demerits — a downvoted entry is worse than a
590
+ // merely-unused one, so it should be first out even if it has a few stale hits.
591
+ const aValue = a.hits - (a.demerits || 0) * 2;
592
+ const bValue = b.hits - (b.demerits || 0) * 2;
593
+ const aFailed = a.outcome === 'failed' ? 1 : 0;
594
+ const bFailed = b.outcome === 'failed' ? 1 : 0;
595
+ if (aValue !== bValue)
596
+ return aValue - bValue; // lower net value evicted first
597
+ if (aFailed !== bFailed)
598
+ return bFailed - aFailed; // confirmed evicted before failed, when tied on value
599
+ return new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime(); // older evicted first
600
+ });
601
+ const toEvict = ranked.slice(0, TheBrainV2.EVICT_BATCH);
602
+ for (const entry of toEvict) {
603
+ this.entries.delete(entry.id);
604
+ for (const term of entry.terms) {
605
+ const ids = this.invertedIndex.get(term);
606
+ if (!ids)
607
+ continue;
608
+ ids.delete(entry.id);
609
+ if (ids.size === 0)
610
+ this.invertedIndex.delete(term);
611
+ }
612
+ }
613
+ this.recalcAvgDocLength();
523
614
  }
524
615
  // ─── Search ───────────────────────────────────────────────────────────────
525
616
  /**
@@ -594,11 +685,33 @@ export class TheBrainV2 {
594
685
  }
595
686
  // 4. Normalize BM25 to 0-1 range
596
687
  const maxBm25 = Math.max(...scored.map(s => s.bm25), 1);
597
- // 5. Combined score: 70% BM25 + 30% Jaccard
598
- const combined = scored.map(s => ({
599
- entry: s.entry,
600
- similarity: (s.bm25 / maxBm25) * 0.7 + s.jaccard * 0.3,
601
- }));
688
+ // 5. Combined score: 70% BM25 + 30% Jaccard, then adjust for signals BM25/Jaccard can't
689
+ // see on their own: a memory's own track record. Small and additive by design — none of
690
+ // these can turn an unrelated result into a top hit, they only reorder among already-
691
+ // relevant candidates.
692
+ const combined = scored.map(s => {
693
+ let similarity = (s.bm25 / maxBm25) * 0.7 + s.jaccard * 0.3;
694
+ // Popularity prior: entries other searches actually reused are more likely to be
695
+ // reused again. Log-scaled and capped at +0.08 so a handful of hits can't outrank a
696
+ // much better textual match.
697
+ similarity += Math.min(Math.log2(s.entry.hits + 1) * 0.02, 0.08);
698
+ // A documented dead end ranking above a working fix is actively harmful — it reads as
699
+ // a suggestion even with the "STALE"/"FAILED" label attached downstream. Demote, don't
700
+ // hide: the warning is still worth surfacing, just not first.
701
+ if (s.entry.outcome === 'failed')
702
+ similarity -= 0.15;
703
+ // Soft domain preference (see projectId scoping above for why this stays soft): an
704
+ // entry tagged with the requested domain is more likely relevant, but an untagged or
705
+ // cross-domain entry may still be the right answer.
706
+ if (options.domain && s.entry.domain === options.domain)
707
+ similarity += 0.05;
708
+ // Explicit negative feedback from downvote() — a caller saying "this was wrong" is a
709
+ // stronger, more deliberate signal than the absence of hits, so it outweighs the
710
+ // popularity prior above rather than just canceling it out.
711
+ if (s.entry.demerits)
712
+ similarity -= Math.min(s.entry.demerits * 0.06, 0.25);
713
+ return { entry: s.entry, similarity: Math.max(0, similarity) };
714
+ });
602
715
  // 6. Sort and filter
603
716
  combined.sort((a, b) => b.similarity - a.similarity);
604
717
  const results = combined
@@ -618,6 +731,7 @@ export class TheBrainV2 {
618
731
  ...(fresh ? {} : { staleFiles }),
619
732
  ...(r.entry.outcome ? { outcome: r.entry.outcome } : {}),
620
733
  ...(claims && claims.length > 0 ? { claims } : {}),
734
+ ...(r.entry.domain ? { domain: r.entry.domain } : {}),
621
735
  };
622
736
  });
623
737
  // 7. Update hit counters — only for searches a caller actually asked a question with.
@@ -671,6 +785,23 @@ export class TheBrainV2 {
671
785
  }
672
786
  return { isDuplicate: false, similarity: sim };
673
787
  }
788
+ // ─── Feedback ─────────────────────────────────────────────────────────────
789
+ /**
790
+ * Record that a specific memory turned out NOT to help — the caller acted on it and it
791
+ * was wrong, misleading, or irrelevant despite ranking well. Unlike `outcome: 'failed'`
792
+ * (set at store time, about the underlying approach), this is set after the fact, about
793
+ * the memory's usefulness as a search result. Lowers future ranking and eviction priority
794
+ * without deleting the entry — a bad-fit-today memory may still be exactly right for a
795
+ * differently-phrased query tomorrow.
796
+ */
797
+ downvote(id) {
798
+ const entry = this.entries.get(id);
799
+ if (!entry)
800
+ return { ok: false, message: `No entry with id "${id}" in the Brain.` };
801
+ entry.demerits = (entry.demerits || 0) + 1;
802
+ this.scheduleSave();
803
+ return { ok: true, message: `Recorded negative feedback on entry "${id}" (demerits: ${entry.demerits}). It will rank lower and be evicted sooner.` };
804
+ }
674
805
  // ─── Stats ────────────────────────────────────────────────────────────────
675
806
  getStats() {
676
807
  return {
@@ -700,6 +831,16 @@ export class TheBrainV2 {
700
831
  catch { /* ignore */ }
701
832
  }
702
833
  }
834
+ // ─── Capacity / Pruning ─────────────────────────────────────────────────────
835
+ /**
836
+ * Hard cap on entry count. Past this, the inverted index keeps growing and old, unused
837
+ * entries dilute every future BM25 IDF calculation (more docs sharing a term → lower
838
+ * signal) without ever being asked for again. Evicting keeps ranking quality from
839
+ * degrading as the Brain accumulates months of memories.
840
+ */
841
+ TheBrainV2.MAX_ENTRIES = 8000;
842
+ /** How many entries to evict per pass once over MAX_ENTRIES — batched, not one-at-a-time. */
843
+ TheBrainV2.EVICT_BATCH = 500;
703
844
  // ─── Global singleton ────────────────────────────────────────────────────────
704
845
  let _brain = null;
705
846
  export function getBrain() {