@soleri/core 2.0.2 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/brain/brain.d.ts +12 -50
- package/dist/brain/brain.d.ts.map +1 -1
- package/dist/brain/brain.js +147 -12
- package/dist/brain/brain.js.map +1 -1
- package/dist/brain/intelligence.d.ts +51 -0
- package/dist/brain/intelligence.d.ts.map +1 -0
- package/dist/brain/intelligence.js +666 -0
- package/dist/brain/intelligence.js.map +1 -0
- package/dist/brain/types.d.ts +165 -0
- package/dist/brain/types.d.ts.map +1 -0
- package/dist/brain/types.js +2 -0
- package/dist/brain/types.js.map +1 -0
- package/dist/cognee/client.d.ts +35 -0
- package/dist/cognee/client.d.ts.map +1 -0
- package/dist/cognee/client.js +291 -0
- package/dist/cognee/client.js.map +1 -0
- package/dist/cognee/types.d.ts +46 -0
- package/dist/cognee/types.d.ts.map +1 -0
- package/dist/cognee/types.js +3 -0
- package/dist/cognee/types.js.map +1 -0
- package/dist/curator/curator.d.ts.map +1 -1
- package/dist/curator/curator.js +7 -5
- package/dist/curator/curator.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/llm/llm-client.d.ts.map +1 -1
- package/dist/llm/llm-client.js +9 -2
- package/dist/llm/llm-client.js.map +1 -1
- package/dist/runtime/core-ops.d.ts +3 -3
- package/dist/runtime/core-ops.d.ts.map +1 -1
- package/dist/runtime/core-ops.js +180 -15
- package/dist/runtime/core-ops.js.map +1 -1
- package/dist/runtime/runtime.d.ts.map +1 -1
- package/dist/runtime/runtime.js +4 -0
- package/dist/runtime/runtime.js.map +1 -1
- package/dist/runtime/types.d.ts +2 -0
- package/dist/runtime/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/brain-intelligence.test.ts +623 -0
- package/src/__tests__/brain.test.ts +265 -27
- package/src/__tests__/cognee-client.test.ts +524 -0
- package/src/__tests__/core-ops.test.ts +77 -49
- package/src/__tests__/curator.test.ts +126 -31
- package/src/__tests__/domain-ops.test.ts +45 -9
- package/src/__tests__/runtime.test.ts +13 -11
- package/src/brain/brain.ts +194 -65
- package/src/brain/intelligence.ts +1061 -0
- package/src/brain/types.ts +176 -0
- package/src/cognee/client.ts +352 -0
- package/src/cognee/types.ts +62 -0
- package/src/curator/curator.ts +52 -15
- package/src/index.ts +26 -1
- package/src/llm/llm-client.ts +18 -24
- package/src/runtime/core-ops.ts +219 -26
- package/src/runtime/runtime.ts +5 -0
- package/src/runtime/types.ts +2 -0
|
@@ -34,8 +34,8 @@ describe('createCoreOps', () => {
|
|
|
34
34
|
return op;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
it('should return
|
|
38
|
-
expect(ops.length).toBe(
|
|
37
|
+
it('should return 37 ops', () => {
|
|
38
|
+
expect(ops.length).toBe(37);
|
|
39
39
|
});
|
|
40
40
|
|
|
41
41
|
it('should have all expected op names', () => {
|
|
@@ -63,6 +63,18 @@ describe('createCoreOps', () => {
|
|
|
63
63
|
expect(names).toContain('rebuild_vocabulary');
|
|
64
64
|
expect(names).toContain('brain_stats');
|
|
65
65
|
expect(names).toContain('llm_status');
|
|
66
|
+
// Brain Intelligence
|
|
67
|
+
expect(names).toContain('brain_session_context');
|
|
68
|
+
expect(names).toContain('brain_strengths');
|
|
69
|
+
expect(names).toContain('brain_global_patterns');
|
|
70
|
+
expect(names).toContain('brain_recommend');
|
|
71
|
+
expect(names).toContain('brain_build_intelligence');
|
|
72
|
+
expect(names).toContain('brain_export');
|
|
73
|
+
expect(names).toContain('brain_import');
|
|
74
|
+
expect(names).toContain('brain_extract_knowledge');
|
|
75
|
+
expect(names).toContain('brain_archive_sessions');
|
|
76
|
+
expect(names).toContain('brain_promote_proposals');
|
|
77
|
+
expect(names).toContain('brain_lifecycle');
|
|
66
78
|
// Curator
|
|
67
79
|
expect(names).toContain('curator_status');
|
|
68
80
|
expect(names).toContain('curator_detect_duplicates');
|
|
@@ -75,58 +87,65 @@ describe('createCoreOps', () => {
|
|
|
75
87
|
});
|
|
76
88
|
|
|
77
89
|
it('search should query vault via brain', async () => {
|
|
78
|
-
runtime.vault.seed([
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
90
|
+
runtime.vault.seed([
|
|
91
|
+
{
|
|
92
|
+
id: 'co-1',
|
|
93
|
+
type: 'pattern',
|
|
94
|
+
domain: 'testing',
|
|
95
|
+
title: 'Test pattern for core ops',
|
|
96
|
+
severity: 'warning',
|
|
97
|
+
description: 'Core ops test.',
|
|
98
|
+
tags: ['test'],
|
|
99
|
+
},
|
|
100
|
+
]);
|
|
87
101
|
runtime.brain.rebuildVocabulary();
|
|
88
102
|
|
|
89
103
|
// Re-create ops since brain state changed
|
|
90
104
|
ops = createCoreOps(runtime);
|
|
91
|
-
const results = await findOp('search').handler({ query: 'core ops test' }) as unknown[];
|
|
105
|
+
const results = (await findOp('search').handler({ query: 'core ops test' })) as unknown[];
|
|
92
106
|
expect(results.length).toBeGreaterThan(0);
|
|
93
107
|
});
|
|
94
108
|
|
|
95
109
|
it('vault_stats should return counts', async () => {
|
|
96
|
-
runtime.vault.seed([
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
110
|
+
runtime.vault.seed([
|
|
111
|
+
{
|
|
112
|
+
id: 'vs-1',
|
|
113
|
+
type: 'pattern',
|
|
114
|
+
domain: 'd1',
|
|
115
|
+
title: 'T',
|
|
116
|
+
severity: 'warning',
|
|
117
|
+
description: 'D',
|
|
118
|
+
tags: ['t'],
|
|
119
|
+
},
|
|
120
|
+
]);
|
|
121
|
+
const stats = (await findOp('vault_stats').handler({})) as { totalEntries: number };
|
|
106
122
|
expect(stats.totalEntries).toBe(1);
|
|
107
123
|
});
|
|
108
124
|
|
|
109
125
|
it('create_plan + get_plan should work', async () => {
|
|
110
|
-
const created = await findOp('create_plan').handler({
|
|
126
|
+
const created = (await findOp('create_plan').handler({
|
|
111
127
|
objective: 'Test plan',
|
|
112
128
|
scope: 'core-ops test',
|
|
113
129
|
tasks: [{ title: 'Task 1', description: 'Do something' }],
|
|
114
|
-
}) as { created: boolean; plan: { id: string; status: string } };
|
|
130
|
+
})) as { created: boolean; plan: { id: string; status: string } };
|
|
115
131
|
expect(created.created).toBe(true);
|
|
116
132
|
expect(created.plan.status).toBe('draft');
|
|
117
133
|
|
|
118
|
-
const plan = await findOp('get_plan').handler({ planId: created.plan.id }) as { id: string };
|
|
134
|
+
const plan = (await findOp('get_plan').handler({ planId: created.plan.id })) as { id: string };
|
|
119
135
|
expect(plan.id).toBe(created.plan.id);
|
|
120
136
|
});
|
|
121
137
|
|
|
122
138
|
it('brain_stats should return stats', async () => {
|
|
123
|
-
const stats = await findOp('brain_stats').handler({}) as {
|
|
139
|
+
const stats = (await findOp('brain_stats').handler({})) as {
|
|
140
|
+
vocabularySize: number;
|
|
141
|
+
feedbackCount: number;
|
|
142
|
+
};
|
|
124
143
|
expect(stats.vocabularySize).toBe(0);
|
|
125
144
|
expect(stats.feedbackCount).toBe(0);
|
|
126
145
|
});
|
|
127
146
|
|
|
128
147
|
it('llm_status should return provider info', async () => {
|
|
129
|
-
const status = await findOp('llm_status').handler({}) as {
|
|
148
|
+
const status = (await findOp('llm_status').handler({})) as {
|
|
130
149
|
providers: {
|
|
131
150
|
openai: { available: boolean };
|
|
132
151
|
anthropic: { available: boolean };
|
|
@@ -139,22 +158,24 @@ describe('createCoreOps', () => {
|
|
|
139
158
|
});
|
|
140
159
|
|
|
141
160
|
it('curator_status should return initialized', async () => {
|
|
142
|
-
const status = await findOp('curator_status').handler({}) as { initialized: boolean };
|
|
161
|
+
const status = (await findOp('curator_status').handler({})) as { initialized: boolean };
|
|
143
162
|
expect(status.initialized).toBe(true);
|
|
144
163
|
});
|
|
145
164
|
|
|
146
165
|
it('curator_health_audit should return score', async () => {
|
|
147
|
-
runtime.vault.seed([
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
166
|
+
runtime.vault.seed([
|
|
167
|
+
{
|
|
168
|
+
id: 'ha-1',
|
|
169
|
+
type: 'pattern',
|
|
170
|
+
domain: 'testing',
|
|
171
|
+
title: 'Health pattern',
|
|
172
|
+
severity: 'warning',
|
|
173
|
+
description: 'Testing health.',
|
|
174
|
+
tags: ['health'],
|
|
175
|
+
},
|
|
176
|
+
]);
|
|
156
177
|
runtime.curator.groomAll();
|
|
157
|
-
const result = await findOp('curator_health_audit').handler({}) as { score: number };
|
|
178
|
+
const result = (await findOp('curator_health_audit').handler({})) as { score: number };
|
|
158
179
|
expect(result.score).toBeGreaterThan(0);
|
|
159
180
|
});
|
|
160
181
|
|
|
@@ -169,21 +190,28 @@ describe('createCoreOps', () => {
|
|
|
169
190
|
toolsUsed: [],
|
|
170
191
|
});
|
|
171
192
|
|
|
172
|
-
const results = await findOp('memory_search').handler({
|
|
193
|
+
const results = (await findOp('memory_search').handler({
|
|
194
|
+
query: 'core ops memory',
|
|
195
|
+
})) as unknown[];
|
|
173
196
|
expect(results.length).toBeGreaterThan(0);
|
|
174
197
|
});
|
|
175
198
|
|
|
176
199
|
it('export should return bundles', async () => {
|
|
177
|
-
runtime.vault.seed([
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
200
|
+
runtime.vault.seed([
|
|
201
|
+
{
|
|
202
|
+
id: 'exp-1',
|
|
203
|
+
type: 'pattern',
|
|
204
|
+
domain: 'security',
|
|
205
|
+
title: 'Export test',
|
|
206
|
+
severity: 'warning',
|
|
207
|
+
description: 'Testing export.',
|
|
208
|
+
tags: ['export'],
|
|
209
|
+
},
|
|
210
|
+
]);
|
|
211
|
+
const result = (await findOp('export').handler({})) as {
|
|
212
|
+
exported: boolean;
|
|
213
|
+
totalEntries: number;
|
|
214
|
+
};
|
|
187
215
|
expect(result.exported).toBe(true);
|
|
188
216
|
expect(result.totalEntries).toBe(1);
|
|
189
217
|
});
|
|
@@ -121,8 +121,16 @@ describe('Curator', () => {
|
|
|
121
121
|
describe('Duplicate Detection', () => {
|
|
122
122
|
it('should detect duplicates above threshold', () => {
|
|
123
123
|
vault.seed([
|
|
124
|
-
makeEntry({
|
|
125
|
-
|
|
124
|
+
makeEntry({
|
|
125
|
+
id: 'dup-1',
|
|
126
|
+
title: 'Use semantic tokens for colors',
|
|
127
|
+
description: 'Always use semantic tokens instead of raw hex values for color styling.',
|
|
128
|
+
}),
|
|
129
|
+
makeEntry({
|
|
130
|
+
id: 'dup-2',
|
|
131
|
+
title: 'Use semantic tokens for color values',
|
|
132
|
+
description: 'Prefer semantic color tokens over raw hex or rgb values in styling.',
|
|
133
|
+
}),
|
|
126
134
|
]);
|
|
127
135
|
const results = curator.detectDuplicates(undefined, 0.3);
|
|
128
136
|
expect(results.length).toBeGreaterThan(0);
|
|
@@ -134,8 +142,16 @@ describe('Curator', () => {
|
|
|
134
142
|
|
|
135
143
|
it('should not detect duplicates below threshold', () => {
|
|
136
144
|
vault.seed([
|
|
137
|
-
makeEntry({
|
|
138
|
-
|
|
145
|
+
makeEntry({
|
|
146
|
+
id: 'uniq-1',
|
|
147
|
+
title: 'Database indexing strategies',
|
|
148
|
+
description: 'Create indices on frequently queried columns.',
|
|
149
|
+
}),
|
|
150
|
+
makeEntry({
|
|
151
|
+
id: 'uniq-2',
|
|
152
|
+
title: 'React component lifecycle',
|
|
153
|
+
description: 'Use useEffect for side effects in functional components.',
|
|
154
|
+
}),
|
|
139
155
|
]);
|
|
140
156
|
const results = curator.detectDuplicates(undefined, 0.8);
|
|
141
157
|
expect(results.length).toBe(0);
|
|
@@ -143,9 +159,21 @@ describe('Curator', () => {
|
|
|
143
159
|
|
|
144
160
|
it('should detect duplicates for a specific entry', () => {
|
|
145
161
|
vault.seed([
|
|
146
|
-
makeEntry({
|
|
147
|
-
|
|
148
|
-
|
|
162
|
+
makeEntry({
|
|
163
|
+
id: 'spec-1',
|
|
164
|
+
title: 'Authentication with JWT tokens',
|
|
165
|
+
description: 'Use JSON Web Tokens for stateless authentication.',
|
|
166
|
+
}),
|
|
167
|
+
makeEntry({
|
|
168
|
+
id: 'spec-2',
|
|
169
|
+
title: 'JWT token authentication pattern',
|
|
170
|
+
description: 'Implement JWT-based authentication for API endpoints.',
|
|
171
|
+
}),
|
|
172
|
+
makeEntry({
|
|
173
|
+
id: 'spec-3',
|
|
174
|
+
title: 'Database connection pooling',
|
|
175
|
+
description: 'Use connection pools for efficient database access.',
|
|
176
|
+
}),
|
|
149
177
|
]);
|
|
150
178
|
const results = curator.detectDuplicates('spec-1', 0.3);
|
|
151
179
|
expect(results.length).toBe(1);
|
|
@@ -154,8 +182,16 @@ describe('Curator', () => {
|
|
|
154
182
|
|
|
155
183
|
it('should suggest merge for high similarity', () => {
|
|
156
184
|
vault.seed([
|
|
157
|
-
makeEntry({
|
|
158
|
-
|
|
185
|
+
makeEntry({
|
|
186
|
+
id: 'merge-1',
|
|
187
|
+
title: 'Validate user input',
|
|
188
|
+
description: 'Always validate and sanitize user input before processing.',
|
|
189
|
+
}),
|
|
190
|
+
makeEntry({
|
|
191
|
+
id: 'merge-2',
|
|
192
|
+
title: 'Validate user input',
|
|
193
|
+
description: 'Always validate and sanitize user input before processing.',
|
|
194
|
+
}),
|
|
159
195
|
]);
|
|
160
196
|
const results = curator.detectDuplicates(undefined, 0.3);
|
|
161
197
|
if (results.length > 0 && results[0].matches.length > 0) {
|
|
@@ -185,7 +221,8 @@ describe('Curator', () => {
|
|
|
185
221
|
id: 'ap-inline',
|
|
186
222
|
type: 'anti-pattern',
|
|
187
223
|
title: 'Avoid inline styles for styling',
|
|
188
|
-
description:
|
|
224
|
+
description:
|
|
225
|
+
'Never use inline styles — prefer CSS classes or Tailwind utilities for styling.',
|
|
189
226
|
tags: ['styling'],
|
|
190
227
|
}),
|
|
191
228
|
]);
|
|
@@ -219,8 +256,18 @@ describe('Curator', () => {
|
|
|
219
256
|
|
|
220
257
|
it('should respect UNIQUE constraint — no duplicate contradictions', () => {
|
|
221
258
|
vault.seed([
|
|
222
|
-
makeEntry({
|
|
223
|
-
|
|
259
|
+
makeEntry({
|
|
260
|
+
id: 'p-dup',
|
|
261
|
+
type: 'pattern',
|
|
262
|
+
title: 'Use inline styles',
|
|
263
|
+
description: 'Apply inline styles for dynamic values.',
|
|
264
|
+
}),
|
|
265
|
+
makeEntry({
|
|
266
|
+
id: 'ap-dup',
|
|
267
|
+
type: 'anti-pattern',
|
|
268
|
+
title: 'Avoid inline styles',
|
|
269
|
+
description: 'Do not use inline styles.',
|
|
270
|
+
}),
|
|
224
271
|
]);
|
|
225
272
|
curator.detectContradictions(0.2);
|
|
226
273
|
const first = curator.getContradictions();
|
|
@@ -231,8 +278,18 @@ describe('Curator', () => {
|
|
|
231
278
|
|
|
232
279
|
it('should resolve a contradiction', () => {
|
|
233
280
|
vault.seed([
|
|
234
|
-
makeEntry({
|
|
235
|
-
|
|
281
|
+
makeEntry({
|
|
282
|
+
id: 'p-res',
|
|
283
|
+
type: 'pattern',
|
|
284
|
+
title: 'Use inline styles',
|
|
285
|
+
description: 'Apply inline styles.',
|
|
286
|
+
}),
|
|
287
|
+
makeEntry({
|
|
288
|
+
id: 'ap-res',
|
|
289
|
+
type: 'anti-pattern',
|
|
290
|
+
title: 'Avoid inline styles',
|
|
291
|
+
description: 'Do not use inline styles.',
|
|
292
|
+
}),
|
|
236
293
|
]);
|
|
237
294
|
curator.detectContradictions(0.2);
|
|
238
295
|
const all = curator.getContradictions();
|
|
@@ -245,8 +302,18 @@ describe('Curator', () => {
|
|
|
245
302
|
|
|
246
303
|
it('should dismiss a contradiction', () => {
|
|
247
304
|
vault.seed([
|
|
248
|
-
makeEntry({
|
|
249
|
-
|
|
305
|
+
makeEntry({
|
|
306
|
+
id: 'p-dis',
|
|
307
|
+
type: 'pattern',
|
|
308
|
+
title: 'Use inline styles',
|
|
309
|
+
description: 'Apply inline styles.',
|
|
310
|
+
}),
|
|
311
|
+
makeEntry({
|
|
312
|
+
id: 'ap-dis',
|
|
313
|
+
type: 'anti-pattern',
|
|
314
|
+
title: 'Avoid inline styles',
|
|
315
|
+
description: 'Do not use inline styles.',
|
|
316
|
+
}),
|
|
250
317
|
]);
|
|
251
318
|
curator.detectContradictions(0.2);
|
|
252
319
|
const all = curator.getContradictions();
|
|
@@ -256,8 +323,18 @@ describe('Curator', () => {
|
|
|
256
323
|
|
|
257
324
|
it('should list by status', () => {
|
|
258
325
|
vault.seed([
|
|
259
|
-
makeEntry({
|
|
260
|
-
|
|
326
|
+
makeEntry({
|
|
327
|
+
id: 'p-ls',
|
|
328
|
+
type: 'pattern',
|
|
329
|
+
title: 'Use inline styles',
|
|
330
|
+
description: 'Apply inline styles.',
|
|
331
|
+
}),
|
|
332
|
+
makeEntry({
|
|
333
|
+
id: 'ap-ls',
|
|
334
|
+
type: 'anti-pattern',
|
|
335
|
+
title: 'Avoid inline styles',
|
|
336
|
+
description: 'Do not use inline styles.',
|
|
337
|
+
}),
|
|
261
338
|
]);
|
|
262
339
|
curator.detectContradictions(0.2);
|
|
263
340
|
const open = curator.getContradictions('open');
|
|
@@ -295,7 +372,9 @@ describe('Curator', () => {
|
|
|
295
372
|
curator.groomEntry('groom-state');
|
|
296
373
|
|
|
297
374
|
const db = vault.getDb();
|
|
298
|
-
const row = db
|
|
375
|
+
const row = db
|
|
376
|
+
.prepare('SELECT * FROM curator_entry_state WHERE entry_id = ?')
|
|
377
|
+
.get('groom-state') as Record<string, unknown>;
|
|
299
378
|
expect(row).toBeDefined();
|
|
300
379
|
expect(row.status).toBe('active');
|
|
301
380
|
expect(row.last_groomed_at).not.toBeNull();
|
|
@@ -336,8 +415,16 @@ describe('Curator', () => {
|
|
|
336
415
|
|
|
337
416
|
it('should find issues in dry-run', () => {
|
|
338
417
|
vault.seed([
|
|
339
|
-
makeEntry({
|
|
340
|
-
|
|
418
|
+
makeEntry({
|
|
419
|
+
id: 'con-1',
|
|
420
|
+
title: 'Validate user input thoroughly',
|
|
421
|
+
description: 'Always validate and sanitize all user input before processing.',
|
|
422
|
+
}),
|
|
423
|
+
makeEntry({
|
|
424
|
+
id: 'con-2',
|
|
425
|
+
title: 'Validate user input thoroughly',
|
|
426
|
+
description: 'Always validate and sanitize all user input before processing.',
|
|
427
|
+
}),
|
|
341
428
|
]);
|
|
342
429
|
const result = curator.consolidate({ dryRun: true, duplicateThreshold: 0.3 });
|
|
343
430
|
expect(result.dryRun).toBe(true);
|
|
@@ -369,14 +456,24 @@ describe('Curator', () => {
|
|
|
369
456
|
expect(result.mutations).toBeGreaterThan(0);
|
|
370
457
|
|
|
371
458
|
// Check that entry state was archived
|
|
372
|
-
const row = db
|
|
459
|
+
const row = db
|
|
460
|
+
.prepare('SELECT status FROM curator_entry_state WHERE entry_id = ?')
|
|
461
|
+
.get('stale-con') as { status: string };
|
|
373
462
|
expect(row.status).toBe('archived');
|
|
374
463
|
});
|
|
375
464
|
|
|
376
465
|
it('should remove duplicates when not dry-run', () => {
|
|
377
466
|
vault.seed([
|
|
378
|
-
makeEntry({
|
|
379
|
-
|
|
467
|
+
makeEntry({
|
|
468
|
+
id: 'rem-1',
|
|
469
|
+
title: 'Duplicate pattern for removal',
|
|
470
|
+
description: 'This is a duplicate pattern that should be removed during consolidation.',
|
|
471
|
+
}),
|
|
472
|
+
makeEntry({
|
|
473
|
+
id: 'rem-2',
|
|
474
|
+
title: 'Duplicate pattern for removal',
|
|
475
|
+
description: 'This is a duplicate pattern that should be removed during consolidation.',
|
|
476
|
+
}),
|
|
380
477
|
]);
|
|
381
478
|
const result = curator.consolidate({ dryRun: false, duplicateThreshold: 0.3 });
|
|
382
479
|
expect(result.mutations).toBeGreaterThan(0);
|
|
@@ -440,9 +537,7 @@ describe('Curator', () => {
|
|
|
440
537
|
});
|
|
441
538
|
|
|
442
539
|
it('should penalize for missing entry types', () => {
|
|
443
|
-
vault.seed([
|
|
444
|
-
makeEntry({ id: 'h-p1', type: 'pattern', tags: ['x'] }),
|
|
445
|
-
]);
|
|
540
|
+
vault.seed([makeEntry({ id: 'h-p1', type: 'pattern', tags: ['x'] })]);
|
|
446
541
|
curator.groomAll();
|
|
447
542
|
const result = curator.healthAudit();
|
|
448
543
|
expect(result.score).toBeLessThan(100);
|
|
@@ -451,9 +546,7 @@ describe('Curator', () => {
|
|
|
451
546
|
});
|
|
452
547
|
|
|
453
548
|
it('should recommend actions for issues', () => {
|
|
454
|
-
vault.seed([
|
|
455
|
-
makeEntry({ id: 'h-rec', type: 'pattern', tags: [] }),
|
|
456
|
-
]);
|
|
549
|
+
vault.seed([makeEntry({ id: 'h-rec', type: 'pattern', tags: [] })]);
|
|
457
550
|
const result = curator.healthAudit();
|
|
458
551
|
expect(result.recommendations.length).toBeGreaterThan(0);
|
|
459
552
|
});
|
|
@@ -461,7 +554,9 @@ describe('Curator', () => {
|
|
|
461
554
|
it('should handle empty vault gracefully', () => {
|
|
462
555
|
const result = curator.healthAudit();
|
|
463
556
|
expect(result.score).toBe(100);
|
|
464
|
-
expect(result.recommendations).toContain(
|
|
557
|
+
expect(result.recommendations).toContain(
|
|
558
|
+
'Vault is empty — add knowledge entries to get started.',
|
|
559
|
+
);
|
|
465
560
|
});
|
|
466
561
|
|
|
467
562
|
it('should include tag health metrics', () => {
|
|
@@ -41,12 +41,28 @@ describe('createDomainFacade', () => {
|
|
|
41
41
|
|
|
42
42
|
it('get_patterns should scope to domain', async () => {
|
|
43
43
|
runtime.vault.seed([
|
|
44
|
-
{
|
|
45
|
-
|
|
44
|
+
{
|
|
45
|
+
id: 'sec-1',
|
|
46
|
+
type: 'pattern',
|
|
47
|
+
domain: 'security',
|
|
48
|
+
title: 'Auth',
|
|
49
|
+
severity: 'warning',
|
|
50
|
+
description: 'Auth.',
|
|
51
|
+
tags: ['auth'],
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: 'api-1',
|
|
55
|
+
type: 'pattern',
|
|
56
|
+
domain: 'api-design',
|
|
57
|
+
title: 'REST',
|
|
58
|
+
severity: 'warning',
|
|
59
|
+
description: 'REST.',
|
|
60
|
+
tags: ['rest'],
|
|
61
|
+
},
|
|
46
62
|
]);
|
|
47
63
|
const facade = createDomainFacade(runtime, 'test-domain', 'security');
|
|
48
64
|
const op = facade.ops.find((o) => o.name === 'get_patterns')!;
|
|
49
|
-
const results = await op.handler({}) as IntelligenceEntry[];
|
|
65
|
+
const results = (await op.handler({})) as IntelligenceEntry[];
|
|
50
66
|
expect(results.every((e) => e.domain === 'security')).toBe(true);
|
|
51
67
|
});
|
|
52
68
|
|
|
@@ -68,29 +84,45 @@ describe('createDomainFacade', () => {
|
|
|
68
84
|
|
|
69
85
|
it('remove should delete entry', async () => {
|
|
70
86
|
runtime.vault.seed([
|
|
71
|
-
{
|
|
87
|
+
{
|
|
88
|
+
id: 'rm-1',
|
|
89
|
+
type: 'pattern',
|
|
90
|
+
domain: 'security',
|
|
91
|
+
title: 'Remove me',
|
|
92
|
+
severity: 'warning',
|
|
93
|
+
description: 'Remove.',
|
|
94
|
+
tags: ['test'],
|
|
95
|
+
},
|
|
72
96
|
]);
|
|
73
97
|
const facade = createDomainFacade(runtime, 'test-domain', 'security');
|
|
74
98
|
const removeOp = facade.ops.find((o) => o.name === 'remove')!;
|
|
75
|
-
const result = await removeOp.handler({ id: 'rm-1' }) as { removed: boolean };
|
|
99
|
+
const result = (await removeOp.handler({ id: 'rm-1' })) as { removed: boolean };
|
|
76
100
|
expect(result.removed).toBe(true);
|
|
77
101
|
expect(runtime.vault.get('rm-1')).toBeNull();
|
|
78
102
|
});
|
|
79
103
|
|
|
80
104
|
it('get_entry should return specific entry', async () => {
|
|
81
105
|
runtime.vault.seed([
|
|
82
|
-
{
|
|
106
|
+
{
|
|
107
|
+
id: 'ge-1',
|
|
108
|
+
type: 'pattern',
|
|
109
|
+
domain: 'security',
|
|
110
|
+
title: 'Get me',
|
|
111
|
+
severity: 'warning',
|
|
112
|
+
description: 'Get.',
|
|
113
|
+
tags: ['test'],
|
|
114
|
+
},
|
|
83
115
|
]);
|
|
84
116
|
const facade = createDomainFacade(runtime, 'test-domain', 'security');
|
|
85
117
|
const getOp = facade.ops.find((o) => o.name === 'get_entry')!;
|
|
86
|
-
const result = await getOp.handler({ id: 'ge-1' }) as IntelligenceEntry;
|
|
118
|
+
const result = (await getOp.handler({ id: 'ge-1' })) as IntelligenceEntry;
|
|
87
119
|
expect(result.id).toBe('ge-1');
|
|
88
120
|
});
|
|
89
121
|
|
|
90
122
|
it('get_entry should return error for missing entry', async () => {
|
|
91
123
|
const facade = createDomainFacade(runtime, 'test-domain', 'security');
|
|
92
124
|
const getOp = facade.ops.find((o) => o.name === 'get_entry')!;
|
|
93
|
-
const result = await getOp.handler({ id: 'nope' }) as { error: string };
|
|
125
|
+
const result = (await getOp.handler({ id: 'nope' })) as { error: string };
|
|
94
126
|
expect(result.error).toBeDefined();
|
|
95
127
|
});
|
|
96
128
|
});
|
|
@@ -110,7 +142,11 @@ describe('createDomainFacades', () => {
|
|
|
110
142
|
});
|
|
111
143
|
|
|
112
144
|
it('should create one facade per domain', () => {
|
|
113
|
-
const facades = createDomainFacades(runtime, 'test-multi', [
|
|
145
|
+
const facades = createDomainFacades(runtime, 'test-multi', [
|
|
146
|
+
'security',
|
|
147
|
+
'api-design',
|
|
148
|
+
'testing',
|
|
149
|
+
]);
|
|
114
150
|
expect(facades.length).toBe(3);
|
|
115
151
|
expect(facades[0].name).toBe('test-multi_security');
|
|
116
152
|
expect(facades[1].name).toBe('test-multi_api_design');
|
|
@@ -58,26 +58,28 @@ describe('createAgentRuntime', () => {
|
|
|
58
58
|
runtime = null; // already closed
|
|
59
59
|
});
|
|
60
60
|
|
|
61
|
-
it('brain should be wired to vault', () => {
|
|
61
|
+
it('brain should be wired to vault', async () => {
|
|
62
62
|
runtime = createAgentRuntime({
|
|
63
63
|
agentId: 'test-brain-wire',
|
|
64
64
|
vaultPath: ':memory:',
|
|
65
65
|
});
|
|
66
66
|
|
|
67
67
|
// Seed some data through vault
|
|
68
|
-
runtime.vault.seed([
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
68
|
+
runtime.vault.seed([
|
|
69
|
+
{
|
|
70
|
+
id: 'rt-1',
|
|
71
|
+
type: 'pattern',
|
|
72
|
+
domain: 'testing',
|
|
73
|
+
title: 'Runtime test pattern',
|
|
74
|
+
severity: 'warning',
|
|
75
|
+
description: 'A test.',
|
|
76
|
+
tags: ['test'],
|
|
77
|
+
},
|
|
78
|
+
]);
|
|
77
79
|
|
|
78
80
|
// Brain should find it
|
|
79
81
|
runtime.brain.rebuildVocabulary();
|
|
80
|
-
const results = runtime.brain.intelligentSearch('runtime test', { limit: 5 });
|
|
82
|
+
const results = await runtime.brain.intelligentSearch('runtime test', { limit: 5 });
|
|
81
83
|
expect(results.length).toBeGreaterThan(0);
|
|
82
84
|
});
|
|
83
85
|
|