@soleri/forge 3.0.0 → 4.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.
Files changed (110) hide show
  1. package/CHANGELOG.md +16 -1
  2. package/README.md +16 -1
  3. package/dist/domain-manager.d.ts +19 -0
  4. package/dist/domain-manager.js +139 -0
  5. package/dist/domain-manager.js.map +1 -0
  6. package/dist/facades/forge.facade.js +16 -0
  7. package/dist/facades/forge.facade.js.map +1 -1
  8. package/dist/knowledge-installer.d.ts +2 -18
  9. package/dist/knowledge-installer.js +2 -96
  10. package/dist/knowledge-installer.js.map +1 -1
  11. package/dist/lib.d.ts +12 -0
  12. package/dist/lib.js +12 -0
  13. package/dist/lib.js.map +1 -0
  14. package/dist/patching.d.ts +17 -0
  15. package/dist/patching.js +103 -0
  16. package/dist/patching.js.map +1 -0
  17. package/dist/scaffolder.js +1 -91
  18. package/dist/scaffolder.js.map +1 -1
  19. package/dist/templates/activate.js +1 -2
  20. package/dist/templates/activate.js.map +1 -1
  21. package/dist/templates/core-facade.js +1 -6
  22. package/dist/templates/core-facade.js.map +1 -1
  23. package/dist/templates/domain-facade.js +1 -3
  24. package/dist/templates/domain-facade.js.map +1 -1
  25. package/dist/templates/entry-point.js +2 -7
  26. package/dist/templates/entry-point.js.map +1 -1
  27. package/dist/templates/llm-client.js +3 -4
  28. package/dist/templates/llm-client.js.map +1 -1
  29. package/dist/templates/package-json.js +1 -2
  30. package/dist/templates/package-json.js.map +1 -1
  31. package/dist/templates/test-facades.js +2 -5
  32. package/dist/templates/test-facades.js.map +1 -1
  33. package/dist/types.d.ts +11 -0
  34. package/package.json +8 -1
  35. package/src/__tests__/knowledge-installer.test.ts +3 -7
  36. package/src/__tests__/scaffolder.test.ts +35 -47
  37. package/src/domain-manager.ts +168 -0
  38. package/src/facades/forge.facade.ts +18 -0
  39. package/src/knowledge-installer.ts +3 -118
  40. package/src/lib.ts +19 -0
  41. package/src/patching.ts +123 -0
  42. package/src/scaffolder.ts +1 -97
  43. package/src/templates/activate.ts +1 -2
  44. package/src/templates/core-facade.ts +1 -6
  45. package/src/templates/domain-facade.ts +1 -3
  46. package/src/templates/entry-point.ts +2 -7
  47. package/src/templates/llm-client.ts +3 -4
  48. package/src/templates/package-json.ts +1 -2
  49. package/src/templates/test-facades.ts +2 -5
  50. package/src/types.ts +12 -0
  51. package/dist/templates/brain.d.ts +0 -6
  52. package/dist/templates/brain.js +0 -478
  53. package/dist/templates/brain.js.map +0 -1
  54. package/dist/templates/facade-factory.d.ts +0 -1
  55. package/dist/templates/facade-factory.js +0 -63
  56. package/dist/templates/facade-factory.js.map +0 -1
  57. package/dist/templates/facade-types.d.ts +0 -1
  58. package/dist/templates/facade-types.js +0 -46
  59. package/dist/templates/facade-types.js.map +0 -1
  60. package/dist/templates/intelligence-loader.d.ts +0 -1
  61. package/dist/templates/intelligence-loader.js +0 -43
  62. package/dist/templates/intelligence-loader.js.map +0 -1
  63. package/dist/templates/intelligence-types.d.ts +0 -1
  64. package/dist/templates/intelligence-types.js +0 -24
  65. package/dist/templates/intelligence-types.js.map +0 -1
  66. package/dist/templates/llm-key-pool.d.ts +0 -7
  67. package/dist/templates/llm-key-pool.js +0 -211
  68. package/dist/templates/llm-key-pool.js.map +0 -1
  69. package/dist/templates/llm-types.d.ts +0 -5
  70. package/dist/templates/llm-types.js +0 -161
  71. package/dist/templates/llm-types.js.map +0 -1
  72. package/dist/templates/llm-utils.d.ts +0 -5
  73. package/dist/templates/llm-utils.js +0 -260
  74. package/dist/templates/llm-utils.js.map +0 -1
  75. package/dist/templates/planner.d.ts +0 -5
  76. package/dist/templates/planner.js +0 -150
  77. package/dist/templates/planner.js.map +0 -1
  78. package/dist/templates/test-brain.d.ts +0 -6
  79. package/dist/templates/test-brain.js +0 -474
  80. package/dist/templates/test-brain.js.map +0 -1
  81. package/dist/templates/test-llm.d.ts +0 -7
  82. package/dist/templates/test-llm.js +0 -574
  83. package/dist/templates/test-llm.js.map +0 -1
  84. package/dist/templates/test-loader.d.ts +0 -5
  85. package/dist/templates/test-loader.js +0 -146
  86. package/dist/templates/test-loader.js.map +0 -1
  87. package/dist/templates/test-planner.d.ts +0 -5
  88. package/dist/templates/test-planner.js +0 -271
  89. package/dist/templates/test-planner.js.map +0 -1
  90. package/dist/templates/test-vault.d.ts +0 -5
  91. package/dist/templates/test-vault.js +0 -380
  92. package/dist/templates/test-vault.js.map +0 -1
  93. package/dist/templates/vault.d.ts +0 -5
  94. package/dist/templates/vault.js +0 -263
  95. package/dist/templates/vault.js.map +0 -1
  96. package/src/templates/brain.ts +0 -478
  97. package/src/templates/facade-factory.ts +0 -62
  98. package/src/templates/facade-types.ts +0 -45
  99. package/src/templates/intelligence-loader.ts +0 -42
  100. package/src/templates/intelligence-types.ts +0 -23
  101. package/src/templates/llm-key-pool.ts +0 -212
  102. package/src/templates/llm-types.ts +0 -160
  103. package/src/templates/llm-utils.ts +0 -259
  104. package/src/templates/planner.ts +0 -150
  105. package/src/templates/test-brain.ts +0 -474
  106. package/src/templates/test-llm.ts +0 -575
  107. package/src/templates/test-loader.ts +0 -146
  108. package/src/templates/test-planner.ts +0 -271
  109. package/src/templates/test-vault.ts +0 -380
  110. package/src/templates/vault.ts +0 -263
@@ -1,150 +0,0 @@
1
- /**
2
- * Generates src/planning/planner.ts for a new agent.
3
- * The Planner provides JSON-file-backed plan management with state machine transitions.
4
- */
5
- export function generatePlanner() {
6
- return PLANNER_TEMPLATE;
7
- }
8
- const PLANNER_TEMPLATE = [
9
- "import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';",
10
- "import { dirname } from 'node:path';",
11
- '',
12
- "export type PlanStatus = 'draft' | 'approved' | 'executing' | 'completed';",
13
- "export type TaskStatus = 'pending' | 'in_progress' | 'completed' | 'skipped' | 'failed';",
14
- '',
15
- 'export interface PlanTask {',
16
- ' id: string;',
17
- ' title: string;',
18
- ' description: string;',
19
- ' status: TaskStatus;',
20
- ' updatedAt: number;',
21
- '}',
22
- '',
23
- 'export interface Plan {',
24
- ' id: string;',
25
- ' objective: string;',
26
- ' scope: string;',
27
- ' status: PlanStatus;',
28
- ' decisions: string[];',
29
- ' tasks: PlanTask[];',
30
- ' createdAt: number;',
31
- ' updatedAt: number;',
32
- '}',
33
- '',
34
- 'export interface PlanStore {',
35
- ' version: string;',
36
- ' plans: Plan[];',
37
- '}',
38
- '',
39
- 'export class Planner {',
40
- ' private filePath: string;',
41
- ' private store: PlanStore;',
42
- '',
43
- ' constructor(filePath: string) {',
44
- ' this.filePath = filePath;',
45
- ' this.store = this.load();',
46
- ' }',
47
- '',
48
- ' private load(): PlanStore {',
49
- ' if (!existsSync(this.filePath)) {',
50
- " return { version: '1.0', plans: [] };",
51
- ' }',
52
- ' try {',
53
- " const data = readFileSync(this.filePath, 'utf-8');",
54
- ' return JSON.parse(data) as PlanStore;',
55
- ' } catch {',
56
- " return { version: '1.0', plans: [] };",
57
- ' }',
58
- ' }',
59
- '',
60
- ' private save(): void {',
61
- ' mkdirSync(dirname(this.filePath), { recursive: true });',
62
- " writeFileSync(this.filePath, JSON.stringify(this.store, null, 2), 'utf-8');",
63
- ' }',
64
- '',
65
- ' create(params: { objective: string; scope: string; decisions?: string[]; tasks?: Array<{ title: string; description: string }> }): Plan {',
66
- ' const now = Date.now();',
67
- ' const plan: Plan = {',
68
- ' id: `plan-${now}-${Math.random().toString(36).slice(2, 8)}`,',
69
- ' objective: params.objective,',
70
- ' scope: params.scope,',
71
- " status: 'draft',",
72
- ' decisions: params.decisions ?? [],',
73
- ' tasks: (params.tasks ?? []).map((t, i) => ({',
74
- ' id: `task-${i + 1}`,',
75
- ' title: t.title,',
76
- ' description: t.description,',
77
- " status: 'pending' as TaskStatus,",
78
- ' updatedAt: now,',
79
- ' })),',
80
- ' createdAt: now,',
81
- ' updatedAt: now,',
82
- ' };',
83
- ' this.store.plans.push(plan);',
84
- ' this.save();',
85
- ' return plan;',
86
- ' }',
87
- '',
88
- ' get(planId: string): Plan | null {',
89
- ' return this.store.plans.find((p) => p.id === planId) ?? null;',
90
- ' }',
91
- '',
92
- ' list(): Plan[] {',
93
- ' return [...this.store.plans];',
94
- ' }',
95
- '',
96
- ' approve(planId: string): Plan {',
97
- ' const plan = this.get(planId);',
98
- ' if (!plan) throw new Error(`Plan not found: ${planId}`);',
99
- " if (plan.status !== 'draft') throw new Error(`Cannot approve plan in '${plan.status}' status — must be 'draft'`);",
100
- " plan.status = 'approved';",
101
- ' plan.updatedAt = Date.now();',
102
- ' this.save();',
103
- ' return plan;',
104
- ' }',
105
- '',
106
- ' startExecution(planId: string): Plan {',
107
- ' const plan = this.get(planId);',
108
- ' if (!plan) throw new Error(`Plan not found: ${planId}`);',
109
- " if (plan.status !== 'approved') throw new Error(`Cannot execute plan in '${plan.status}' status — must be 'approved'`);",
110
- " plan.status = 'executing';",
111
- ' plan.updatedAt = Date.now();',
112
- ' this.save();',
113
- ' return plan;',
114
- ' }',
115
- '',
116
- ' updateTask(planId: string, taskId: string, status: TaskStatus): Plan {',
117
- ' const plan = this.get(planId);',
118
- ' if (!plan) throw new Error(`Plan not found: ${planId}`);',
119
- " if (plan.status !== 'executing') throw new Error(`Cannot update tasks on plan in '${plan.status}' status — must be 'executing'`);",
120
- ' const task = plan.tasks.find((t) => t.id === taskId);',
121
- ' if (!task) throw new Error(`Task not found: ${taskId}`);',
122
- ' task.status = status;',
123
- ' task.updatedAt = Date.now();',
124
- ' plan.updatedAt = Date.now();',
125
- " // Auto-transition: if plan is executing and first task starts, that's fine",
126
- ' // Auto-start execution when approving and updating first task',
127
- ' this.save();',
128
- ' return plan;',
129
- ' }',
130
- '',
131
- ' complete(planId: string): Plan {',
132
- ' const plan = this.get(planId);',
133
- ' if (!plan) throw new Error(`Plan not found: ${planId}`);',
134
- " if (plan.status !== 'executing') throw new Error(`Cannot complete plan in '${plan.status}' status — must be 'executing'`);",
135
- " plan.status = 'completed';",
136
- ' plan.updatedAt = Date.now();',
137
- ' this.save();',
138
- ' return plan;',
139
- ' }',
140
- '',
141
- ' getExecuting(): Plan[] {',
142
- " return this.store.plans.filter((p) => p.status === 'executing');",
143
- ' }',
144
- '',
145
- ' getActive(): Plan[] {',
146
- " return this.store.plans.filter((p) => p.status === 'draft' || p.status === 'approved' || p.status === 'executing');",
147
- ' }',
148
- '}',
149
- ].join('\n');
150
- //# sourceMappingURL=planner.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"planner.js","sourceRoot":"","sources":["../../src/templates/planner.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,UAAU,eAAe;IAC7B,OAAO,gBAAgB,CAAC;AAC1B,CAAC;AAED,MAAM,gBAAgB,GAAG;IACvB,+EAA+E;IAC/E,sCAAsC;IACtC,EAAE;IACF,4EAA4E;IAC5E,0FAA0F;IAC1F,EAAE;IACF,6BAA6B;IAC7B,eAAe;IACf,kBAAkB;IAClB,wBAAwB;IACxB,uBAAuB;IACvB,sBAAsB;IACtB,GAAG;IACH,EAAE;IACF,yBAAyB;IACzB,eAAe;IACf,sBAAsB;IACtB,kBAAkB;IAClB,uBAAuB;IACvB,wBAAwB;IACxB,sBAAsB;IACtB,sBAAsB;IACtB,sBAAsB;IACtB,GAAG;IACH,EAAE;IACF,8BAA8B;IAC9B,oBAAoB;IACpB,kBAAkB;IAClB,GAAG;IACH,EAAE;IACF,wBAAwB;IACxB,6BAA6B;IAC7B,6BAA6B;IAC7B,EAAE;IACF,mCAAmC;IACnC,+BAA+B;IAC/B,+BAA+B;IAC/B,KAAK;IACL,EAAE;IACF,+BAA+B;IAC/B,uCAAuC;IACvC,6CAA6C;IAC7C,OAAO;IACP,WAAW;IACX,0DAA0D;IAC1D,6CAA6C;IAC7C,eAAe;IACf,6CAA6C;IAC7C,OAAO;IACP,KAAK;IACL,EAAE;IACF,0BAA0B;IAC1B,6DAA6D;IAC7D,iFAAiF;IACjF,KAAK;IACL,EAAE;IACF,6IAA6I;IAC7I,6BAA6B;IAC7B,0BAA0B;IAC1B,oEAAoE;IACpE,oCAAoC;IACpC,4BAA4B;IAC5B,wBAAwB;IACxB,0CAA0C;IAC1C,oDAAoD;IACpD,8BAA8B;IAC9B,yBAAyB;IACzB,qCAAqC;IACrC,0CAA0C;IAC1C,yBAAyB;IACzB,YAAY;IACZ,uBAAuB;IACvB,uBAAuB;IACvB,QAAQ;IACR,kCAAkC;IAClC,kBAAkB;IAClB,kBAAkB;IAClB,KAAK;IACL,EAAE;IACF,sCAAsC;IACtC,mEAAmE;IACnE,KAAK;IACL,EAAE;IACF,oBAAoB;IACpB,mCAAmC;IACnC,KAAK;IACL,EAAE;IACF,mCAAmC;IACnC,oCAAoC;IACpC,8DAA8D;IAC9D,uHAAuH;IACvH,+BAA+B;IAC/B,kCAAkC;IAClC,kBAAkB;IAClB,kBAAkB;IAClB,KAAK;IACL,EAAE;IACF,0CAA0C;IAC1C,oCAAoC;IACpC,8DAA8D;IAC9D,6HAA6H;IAC7H,gCAAgC;IAChC,kCAAkC;IAClC,kBAAkB;IAClB,kBAAkB;IAClB,KAAK;IACL,EAAE;IACF,0EAA0E;IAC1E,oCAAoC;IACpC,8DAA8D;IAC9D,uIAAuI;IACvI,2DAA2D;IAC3D,8DAA8D;IAC9D,2BAA2B;IAC3B,kCAAkC;IAClC,kCAAkC;IAClC,iFAAiF;IACjF,oEAAoE;IACpE,kBAAkB;IAClB,kBAAkB;IAClB,KAAK;IACL,EAAE;IACF,oCAAoC;IACpC,oCAAoC;IACpC,8DAA8D;IAC9D,gIAAgI;IAChI,gCAAgC;IAChC,kCAAkC;IAClC,kBAAkB;IAClB,kBAAkB;IAClB,KAAK;IACL,EAAE;IACF,4BAA4B;IAC5B,sEAAsE;IACtE,KAAK;IACL,EAAE;IACF,yBAAyB;IACzB,yHAAyH;IACzH,KAAK;IACL,GAAG;CACJ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC"}
@@ -1,6 +0,0 @@
1
- /**
2
- * Generates brain test file for a new agent.
3
- * Tests cover: TF-IDF scoring, intelligent search, auto-tagging,
4
- * duplicate detection, feedback, adaptive weights, vocabulary.
5
- */
6
- export declare function generateBrainTest(): string;
@@ -1,474 +0,0 @@
1
- /**
2
- * Generates brain test file for a new agent.
3
- * Tests cover: TF-IDF scoring, intelligent search, auto-tagging,
4
- * duplicate detection, feedback, adaptive weights, vocabulary.
5
- */
6
- export function generateBrainTest() {
7
- return BRAIN_TEST_TEMPLATE;
8
- }
9
- const BRAIN_TEST_TEMPLATE = [
10
- "import { describe, it, expect, beforeEach, afterEach } from 'vitest';",
11
- "import { Vault } from '../vault/vault.js';",
12
- "import { Brain } from '../brain/brain.js';",
13
- "import type { IntelligenceEntry } from '../intelligence/types.js';",
14
- '',
15
- 'function makeEntry(overrides: Partial<IntelligenceEntry> = {}): IntelligenceEntry {',
16
- ' return {',
17
- " id: overrides.id ?? 'test-1',",
18
- " type: overrides.type ?? 'pattern',",
19
- " domain: overrides.domain ?? 'testing',",
20
- " title: overrides.title ?? 'Test Pattern',",
21
- " severity: overrides.severity ?? 'warning',",
22
- " description: overrides.description ?? 'A test pattern for unit tests.',",
23
- " tags: overrides.tags ?? ['testing', 'assertions'],",
24
- ' };',
25
- '}',
26
- '',
27
- "describe('Brain', () => {",
28
- ' let vault: Vault;',
29
- ' let brain: Brain;',
30
- '',
31
- ' beforeEach(() => {',
32
- " vault = new Vault(':memory:');",
33
- ' brain = new Brain(vault);',
34
- ' });',
35
- '',
36
- ' afterEach(() => {',
37
- ' vault.close();',
38
- ' });',
39
- '',
40
- ' // ─── Constructor ──────────────────────────────────────────────',
41
- '',
42
- " describe('constructor', () => {",
43
- " it('should create brain with empty vocabulary on empty vault', () => {",
44
- ' expect(brain.getVocabularySize()).toBe(0);',
45
- ' });',
46
- '',
47
- " it('should build vocabulary from existing entries', () => {",
48
- ' vault.seed([',
49
- " makeEntry({ id: 'v1', title: 'Input validation pattern', description: 'Always validate user input at boundaries.', tags: ['validation', 'security'] }),",
50
- " makeEntry({ id: 'v2', title: 'Caching strategy', description: 'Use cache-aside for read-heavy workloads.', tags: ['caching', 'performance'] }),",
51
- ' ]);',
52
- ' const brain2 = new Brain(vault);',
53
- ' expect(brain2.getVocabularySize()).toBeGreaterThan(0);',
54
- ' });',
55
- ' });',
56
- '',
57
- ' // ─── Intelligent Search ──────────────────────────────────────',
58
- '',
59
- " describe('intelligentSearch', () => {",
60
- ' beforeEach(() => {',
61
- ' vault.seed([',
62
- " makeEntry({ id: 'is-1', title: 'Input validation pattern', description: 'Always validate user input at system boundaries to prevent injection attacks.', domain: 'security', severity: 'critical', tags: ['validation', 'security', 'input'] }),",
63
- " makeEntry({ id: 'is-2', title: 'Caching strategy for APIs', description: 'Use cache-aside pattern for read-heavy API workloads.', domain: 'performance', severity: 'warning', tags: ['caching', 'api', 'performance'] }),",
64
- " makeEntry({ id: 'is-3', title: 'Error handling best practices', description: 'Use typed errors with context for better debugging experience.', domain: 'clean-code', severity: 'suggestion', tags: ['errors', 'debugging'] }),",
65
- ' ]);',
66
- ' brain = new Brain(vault);',
67
- ' });',
68
- '',
69
- " it('should return ranked results', () => {",
70
- " const results = brain.intelligentSearch('validation input');",
71
- ' expect(results.length).toBeGreaterThan(0);',
72
- " expect(results[0].entry.id).toBe('is-1');",
73
- ' });',
74
- '',
75
- " it('should include score breakdown', () => {",
76
- " const results = brain.intelligentSearch('validation');",
77
- ' expect(results.length).toBeGreaterThan(0);',
78
- ' const breakdown = results[0].breakdown;',
79
- " expect(breakdown).toHaveProperty('semantic');",
80
- " expect(breakdown).toHaveProperty('severity');",
81
- " expect(breakdown).toHaveProperty('recency');",
82
- " expect(breakdown).toHaveProperty('tagOverlap');",
83
- " expect(breakdown).toHaveProperty('domainMatch');",
84
- " expect(breakdown).toHaveProperty('total');",
85
- ' expect(breakdown.total).toBe(results[0].score);',
86
- ' });',
87
- '',
88
- " it('should return empty array for no matches', () => {",
89
- " const results = brain.intelligentSearch('xyznonexistent');",
90
- ' expect(results).toEqual([]);',
91
- ' });',
92
- '',
93
- " it('should respect limit', () => {",
94
- " const results = brain.intelligentSearch('pattern', { limit: 1 });",
95
- ' expect(results.length).toBeLessThanOrEqual(1);',
96
- ' });',
97
- '',
98
- " it('should filter by domain', () => {",
99
- " const results = brain.intelligentSearch('pattern', { domain: 'security' });",
100
- " expect(results.every((r) => r.entry.domain === 'security')).toBe(true);",
101
- ' });',
102
- '',
103
- " it('should boost domain matches when domain is specified', () => {",
104
- " const withDomain = brain.intelligentSearch('pattern', { domain: 'security' });",
105
- ' if (withDomain.length > 0) {',
106
- ' expect(withDomain[0].breakdown.domainMatch).toBe(1.0);',
107
- ' }',
108
- ' });',
109
- '',
110
- " it('should boost severity in scoring', () => {",
111
- " const results = brain.intelligentSearch('pattern');",
112
- ' if (results.length >= 2) {',
113
- ' // Critical entry should have higher severity score',
114
- " const critical = results.find((r) => r.entry.severity === 'critical');",
115
- " const suggestion = results.find((r) => r.entry.severity === 'suggestion');",
116
- ' if (critical && suggestion) {',
117
- ' expect(critical.breakdown.severity).toBeGreaterThan(suggestion.breakdown.severity);',
118
- ' }',
119
- ' }',
120
- ' });',
121
- '',
122
- " it('should boost tag overlap when tags provided', () => {",
123
- " const results = brain.intelligentSearch('pattern', { tags: ['validation', 'security'] });",
124
- ' if (results.length > 0) {',
125
- ' // The security entry with matching tags should have tag overlap > 0',
126
- " const secEntry = results.find((r) => r.entry.id === 'is-1');",
127
- ' if (secEntry) {',
128
- ' expect(secEntry.breakdown.tagOverlap).toBeGreaterThan(0);',
129
- ' }',
130
- ' }',
131
- ' });',
132
- '',
133
- " it('should handle search on empty vault gracefully', () => {",
134
- " const emptyVault = new Vault(':memory:');",
135
- ' const emptyBrain = new Brain(emptyVault);',
136
- " const results = emptyBrain.intelligentSearch('anything');",
137
- ' expect(results).toEqual([]);',
138
- ' emptyVault.close();',
139
- ' });',
140
- ' });',
141
- '',
142
- ' // ─── Enrich and Capture ─────────────────────────────────────',
143
- '',
144
- " describe('enrichAndCapture', () => {",
145
- " it('should capture entry and return auto-tags', () => {",
146
- ' const result = brain.enrichAndCapture({',
147
- " id: 'cap-1',",
148
- " type: 'pattern',",
149
- " domain: 'security',",
150
- " title: 'SQL injection prevention',",
151
- " severity: 'critical',",
152
- " description: 'Always use parameterized queries to prevent SQL injection attacks on database.',",
153
- ' tags: [],',
154
- ' });',
155
- ' expect(result.captured).toBe(true);',
156
- " expect(result.id).toBe('cap-1');",
157
- ' expect(result.autoTags.length).toBeGreaterThan(0);',
158
- ' });',
159
- '',
160
- " it('should merge auto-tags with user-provided tags', () => {",
161
- ' const result = brain.enrichAndCapture({',
162
- " id: 'cap-2',",
163
- " type: 'pattern',",
164
- " domain: 'security',",
165
- " title: 'XSS prevention methods',",
166
- " severity: 'critical',",
167
- " description: 'Sanitize all user input before rendering in the browser to prevent cross-site scripting.',",
168
- " tags: ['user-tag'],",
169
- ' });',
170
- ' expect(result.captured).toBe(true);',
171
- ' // Verify the entry in vault has merged tags',
172
- " const entry = vault.get('cap-2');",
173
- ' expect(entry).not.toBeNull();',
174
- " expect(entry!.tags).toContain('user-tag');",
175
- ' expect(entry!.tags.length).toBeGreaterThan(1);',
176
- ' });',
177
- '',
178
- " it('should store entry in vault', () => {",
179
- ' brain.enrichAndCapture({',
180
- " id: 'cap-3',",
181
- " type: 'rule',",
182
- " domain: 'testing',",
183
- " title: 'Always test edge cases',",
184
- " severity: 'warning',",
185
- " description: 'Write tests for boundary values, null inputs, and error conditions.',",
186
- " tags: ['testing'],",
187
- ' });',
188
- " const entry = vault.get('cap-3');",
189
- ' expect(entry).not.toBeNull();',
190
- " expect(entry!.title).toBe('Always test edge cases');",
191
- ' });',
192
- '',
193
- " it('should update vocabulary incrementally after capture', () => {",
194
- ' const sizeBefore = brain.getVocabularySize();',
195
- ' brain.enrichAndCapture({',
196
- " id: 'cap-4',",
197
- " type: 'pattern',",
198
- " domain: 'performance',",
199
- " title: 'Connection pooling optimization',",
200
- " severity: 'warning',",
201
- " description: 'Use connection pooling for database connections to reduce overhead and improve throughput.',",
202
- " tags: ['database', 'performance'],",
203
- ' });',
204
- ' expect(brain.getVocabularySize()).toBeGreaterThan(sizeBefore);',
205
- ' });',
206
- '',
207
- " it('should capture entry without tags and auto-generate them', () => {",
208
- ' const result = brain.enrichAndCapture({',
209
- " id: 'cap-5',",
210
- " type: 'anti-pattern',",
211
- " domain: 'clean-code',",
212
- " title: 'Deeply nested conditionals',",
213
- " severity: 'warning',",
214
- " description: 'Avoid deeply nested if-else blocks. Use early returns and guard clauses instead.',",
215
- ' tags: [],',
216
- ' });',
217
- ' expect(result.captured).toBe(true);',
218
- ' expect(result.autoTags.length).toBeGreaterThan(0);',
219
- " const entry = vault.get('cap-5');",
220
- ' expect(entry!.tags.length).toBeGreaterThan(0);',
221
- ' });',
222
- ' });',
223
- '',
224
- ' // ─── Duplicate Detection ────────────────────────────────────',
225
- '',
226
- " describe('duplicate detection', () => {",
227
- ' beforeEach(() => {',
228
- ' vault.seed([',
229
- ' makeEntry({',
230
- " id: 'dup-existing',",
231
- " domain: 'security',",
232
- " title: 'Input validation pattern for user forms',",
233
- " description: 'Always validate user input at system boundaries to prevent injection attacks.',",
234
- " tags: ['validation', 'security'],",
235
- ' }),',
236
- ' ]);',
237
- ' brain = new Brain(vault);',
238
- ' });',
239
- '',
240
- " it('should warn on similar entry', () => {",
241
- ' const result = brain.enrichAndCapture({',
242
- " id: 'dup-new-1',",
243
- " type: 'pattern',",
244
- " domain: 'security',",
245
- " title: 'Input validation pattern for user forms and APIs',",
246
- " severity: 'warning',",
247
- " description: 'Validate all user input at boundaries to block injection vectors.',",
248
- " tags: ['validation'],",
249
- ' });',
250
- ' // Should still capture (warn threshold, not block)',
251
- ' expect(result.captured).toBe(true);',
252
- ' // May have a duplicate warning if similarity >= 0.6',
253
- ' if (result.duplicate) {',
254
- " expect(result.duplicate.id).toBe('dup-existing');",
255
- ' expect(result.duplicate.similarity).toBeGreaterThanOrEqual(0.6);',
256
- ' }',
257
- ' });',
258
- '',
259
- " it('should allow dissimilar entries without duplicate warning', () => {",
260
- ' const result = brain.enrichAndCapture({',
261
- " id: 'dup-different',",
262
- " type: 'pattern',",
263
- " domain: 'security',",
264
- " title: 'Rate limiting configuration',",
265
- " severity: 'warning',",
266
- " description: 'Configure rate limits on API endpoints to prevent abuse.',",
267
- " tags: ['rate-limiting'],",
268
- ' });',
269
- ' expect(result.captured).toBe(true);',
270
- ' });',
271
- ' });',
272
- '',
273
- ' // ─── Record Feedback ────────────────────────────────────────',
274
- '',
275
- " describe('recordFeedback', () => {",
276
- " it('should record feedback in database', () => {",
277
- " brain.recordFeedback('test query', 'entry-1', 'accepted');",
278
- ' const stats = brain.getStats();',
279
- ' expect(stats.feedbackCount).toBe(1);',
280
- ' });',
281
- '',
282
- " it('should record multiple feedback entries', () => {",
283
- " brain.recordFeedback('query-1', 'entry-1', 'accepted');",
284
- " brain.recordFeedback('query-2', 'entry-2', 'dismissed');",
285
- " brain.recordFeedback('query-3', 'entry-3', 'accepted');",
286
- ' const stats = brain.getStats();',
287
- ' expect(stats.feedbackCount).toBe(3);',
288
- ' });',
289
- '',
290
- " it('should keep default weights below feedback threshold', () => {",
291
- ' for (let i = 0; i < 10; i++) {',
292
- " brain.recordFeedback('q' + i, 'e' + i, 'accepted');",
293
- ' }',
294
- ' const stats = brain.getStats();',
295
- ' expect(stats.weights.semantic).toBeCloseTo(0.40, 2);',
296
- ' });',
297
- ' });',
298
- '',
299
- ' // ─── Adaptive Weights ───────────────────────────────────────',
300
- '',
301
- " describe('adaptive weights', () => {",
302
- " it('should adjust weights after reaching feedback threshold', () => {",
303
- ' // Record 30+ feedback entries with high accept rate',
304
- ' for (let i = 0; i < 35; i++) {',
305
- " brain.recordFeedback('query-' + i, 'entry-' + i, 'accepted');",
306
- ' }',
307
- ' const stats = brain.getStats();',
308
- ' // Semantic weight should increase with high accept rate',
309
- ' expect(stats.weights.semantic).toBeGreaterThan(0.40);',
310
- ' });',
311
- '',
312
- " it('should decrease semantic weight with high dismiss rate', () => {",
313
- ' for (let i = 0; i < 35; i++) {',
314
- " brain.recordFeedback('query-' + i, 'entry-' + i, 'dismissed');",
315
- ' }',
316
- ' const stats = brain.getStats();',
317
- ' expect(stats.weights.semantic).toBeLessThan(0.40);',
318
- ' });',
319
- '',
320
- " it('should keep weights bounded within ±0.15 of defaults', () => {",
321
- ' for (let i = 0; i < 50; i++) {',
322
- " brain.recordFeedback('query-' + i, 'entry-' + i, 'accepted');",
323
- ' }',
324
- ' const stats = brain.getStats();',
325
- ' expect(stats.weights.semantic).toBeLessThanOrEqual(0.55);',
326
- ' expect(stats.weights.semantic).toBeGreaterThanOrEqual(0.25);',
327
- ' });',
328
- '',
329
- " it('should normalize weights to sum to 1.0', () => {",
330
- ' for (let i = 0; i < 35; i++) {',
331
- " brain.recordFeedback('query-' + i, 'entry-' + i, 'accepted');",
332
- ' }',
333
- ' const stats = brain.getStats();',
334
- ' const sum = stats.weights.semantic + stats.weights.severity + stats.weights.recency + stats.weights.tagOverlap + stats.weights.domainMatch;',
335
- ' expect(sum).toBeCloseTo(1.0, 5);',
336
- ' });',
337
- '',
338
- " it('should keep default weights with balanced feedback', () => {",
339
- ' // 50/50 accept/dismiss rate',
340
- ' for (let i = 0; i < 20; i++) {',
341
- " brain.recordFeedback('qa-' + i, 'ea-' + i, 'accepted');",
342
- ' }',
343
- ' for (let i = 0; i < 20; i++) {',
344
- " brain.recordFeedback('qd-' + i, 'ed-' + i, 'dismissed');",
345
- ' }',
346
- ' const stats = brain.getStats();',
347
- ' // With balanced feedback, semantic weight should stay near default',
348
- ' expect(stats.weights.semantic).toBeCloseTo(0.40, 1);',
349
- ' });',
350
- ' });',
351
- '',
352
- ' // ─── Vocabulary ─────────────────────────────────────────────',
353
- '',
354
- " describe('vocabulary', () => {",
355
- " it('should rebuild vocabulary from vault entries', () => {",
356
- ' vault.seed([',
357
- " makeEntry({ id: 'voc-1', title: 'Authentication pattern', description: 'JWT tokens for API auth.', tags: ['auth', 'jwt'] }),",
358
- " makeEntry({ id: 'voc-2', title: 'Authorization rules', description: 'Role-based access control.', tags: ['rbac', 'auth'] }),",
359
- ' ]);',
360
- ' brain.rebuildVocabulary();',
361
- ' expect(brain.getVocabularySize()).toBeGreaterThan(0);',
362
- ' });',
363
- '',
364
- " it('should clear vocabulary when vault is empty', () => {",
365
- " vault.seed([makeEntry({ id: 'voc-3', title: 'Temp entry', description: 'Will be removed.', tags: ['temp'] })]);",
366
- ' brain.rebuildVocabulary();',
367
- ' expect(brain.getVocabularySize()).toBeGreaterThan(0);',
368
- " vault.remove('voc-3');",
369
- ' brain.rebuildVocabulary();',
370
- ' expect(brain.getVocabularySize()).toBe(0);',
371
- ' });',
372
- '',
373
- " it('should persist vocabulary to database', () => {",
374
- ' vault.seed([',
375
- " makeEntry({ id: 'voc-4', title: 'Persistent vocabulary test', description: 'Testing database persistence.', tags: ['persistence'] }),",
376
- ' ]);',
377
- ' brain.rebuildVocabulary();',
378
- ' const db = vault.getDb();',
379
- " const count = (db.prepare('SELECT COUNT(*) as count FROM brain_vocabulary').get() as { count: number }).count;",
380
- ' expect(count).toBeGreaterThan(0);',
381
- ' });',
382
- '',
383
- " it('should handle rebuild on empty vault gracefully', () => {",
384
- ' brain.rebuildVocabulary();',
385
- ' expect(brain.getVocabularySize()).toBe(0);',
386
- ' });',
387
- ' });',
388
- '',
389
- ' // ─── Stats ──────────────────────────────────────────────────',
390
- '',
391
- " describe('getStats', () => {",
392
- " it('should return stats with zero counts for new brain', () => {",
393
- ' const stats = brain.getStats();',
394
- ' expect(stats.vocabularySize).toBe(0);',
395
- ' expect(stats.feedbackCount).toBe(0);',
396
- ' expect(stats.weights.semantic).toBeCloseTo(0.40, 2);',
397
- ' });',
398
- '',
399
- " it('should return correct vocabulary size after seeding', () => {",
400
- ' vault.seed([',
401
- " makeEntry({ id: 'st-1', title: 'Pattern one', description: 'Description one.', tags: ['a'] }),",
402
- " makeEntry({ id: 'st-2', title: 'Pattern two', description: 'Description two.', tags: ['b'] }),",
403
- ' ]);',
404
- ' brain.rebuildVocabulary();',
405
- ' const stats = brain.getStats();',
406
- ' expect(stats.vocabularySize).toBeGreaterThan(0);',
407
- ' });',
408
- '',
409
- " it('should return correct feedback count', () => {",
410
- " brain.recordFeedback('q1', 'e1', 'accepted');",
411
- " brain.recordFeedback('q2', 'e2', 'dismissed');",
412
- ' const stats = brain.getStats();',
413
- ' expect(stats.feedbackCount).toBe(2);',
414
- ' });',
415
- ' });',
416
- '',
417
- ' // ─── Get Relevant Patterns ──────────────────────────────────',
418
- '',
419
- " describe('getRelevantPatterns', () => {",
420
- " it('should return ranked results for query context', () => {",
421
- ' vault.seed([',
422
- " makeEntry({ id: 'rel-1', title: 'Authentication pattern', description: 'JWT for API auth.', domain: 'security', tags: ['auth'] }),",
423
- " makeEntry({ id: 'rel-2', title: 'Database indexing', description: 'Index frequently queried columns.', domain: 'performance', tags: ['indexing'] }),",
424
- ' ]);',
425
- ' brain = new Brain(vault);',
426
- " const results = brain.getRelevantPatterns({ query: 'authentication', domain: 'security' });",
427
- ' expect(results.length).toBeGreaterThan(0);',
428
- ' });',
429
- '',
430
- " it('should return empty for no context matches', () => {",
431
- " const results = brain.getRelevantPatterns({ query: 'nonexistent' });",
432
- ' expect(results).toEqual([]);',
433
- ' });',
434
- ' });',
435
- '',
436
- ' // ─── Graceful Degradation ───────────────────────────────────',
437
- '',
438
- " describe('graceful degradation', () => {",
439
- " it('should work without vocabulary (empty vault)', () => {",
440
- ' expect(brain.getVocabularySize()).toBe(0);',
441
- " const results = brain.intelligentSearch('anything');",
442
- ' expect(results).toEqual([]);',
443
- ' });',
444
- '',
445
- " it('should fall back to severity + recency scoring when vocabulary is empty', () => {",
446
- ' // Seed entries but create brain before vocabulary can build',
447
- ' vault.seed([',
448
- " makeEntry({ id: 'gd-1', title: 'Fallback test pattern', description: 'Testing graceful degradation.', severity: 'critical', tags: ['fallback'] }),",
449
- ' ]);',
450
- ' // Rebuild brain to pick up vocabulary',
451
- ' brain = new Brain(vault);',
452
- " const results = brain.intelligentSearch('fallback test');",
453
- ' expect(results.length).toBeGreaterThan(0);',
454
- ' // Should have a score even with vocabulary',
455
- ' expect(results[0].score).toBeGreaterThan(0);',
456
- ' });',
457
- '',
458
- " it('should handle capture on empty vault without errors', () => {",
459
- ' const result = brain.enrichAndCapture({',
460
- " id: 'gd-cap-1',",
461
- " type: 'pattern',",
462
- " domain: 'testing',",
463
- " title: 'First pattern ever',",
464
- " severity: 'warning',",
465
- " description: 'The very first pattern captured in an empty vault.',",
466
- ' tags: [],',
467
- ' });',
468
- ' expect(result.captured).toBe(true);',
469
- ' expect(result.autoTags.length).toBeGreaterThan(0);',
470
- ' });',
471
- ' });',
472
- '});',
473
- ].join('\n');
474
- //# sourceMappingURL=test-brain.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"test-brain.js","sourceRoot":"","sources":["../../src/templates/test-brain.ts"],"names":[],"mappings":"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"}