cognitive-core 0.0.2 → 0.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 (329) hide show
  1. package/README.md +302 -116
  2. package/SKILL.md +193 -0
  3. package/dist/agents/index.d.ts +3 -0
  4. package/dist/agents/index.d.ts.map +1 -0
  5. package/dist/agents/index.js +5 -0
  6. package/dist/agents/index.js.map +1 -0
  7. package/dist/agents/mock-provider.d.ts +23 -0
  8. package/dist/agents/mock-provider.d.ts.map +1 -0
  9. package/dist/agents/mock-provider.js +71 -0
  10. package/dist/agents/mock-provider.js.map +1 -0
  11. package/dist/agents/types.d.ts +98 -0
  12. package/dist/agents/types.d.ts.map +1 -0
  13. package/dist/agents/types.js +44 -0
  14. package/dist/agents/types.js.map +1 -0
  15. package/dist/atlas.d.ts +196 -0
  16. package/dist/atlas.d.ts.map +1 -0
  17. package/dist/atlas.js +373 -0
  18. package/dist/atlas.js.map +1 -0
  19. package/dist/bin/cognitive-core.d.ts +18 -0
  20. package/dist/bin/cognitive-core.d.ts.map +1 -0
  21. package/dist/bin/cognitive-core.js +419 -0
  22. package/dist/bin/cognitive-core.js.map +1 -0
  23. package/dist/embeddings/bm25.d.ts +104 -0
  24. package/dist/embeddings/bm25.d.ts.map +1 -0
  25. package/dist/embeddings/bm25.js +264 -0
  26. package/dist/embeddings/bm25.js.map +1 -0
  27. package/dist/embeddings/index.d.ts +12 -0
  28. package/dist/embeddings/index.d.ts.map +1 -0
  29. package/dist/embeddings/index.js +16 -0
  30. package/dist/embeddings/index.js.map +1 -0
  31. package/dist/embeddings/manager.d.ts +112 -0
  32. package/dist/embeddings/manager.d.ts.map +1 -0
  33. package/dist/embeddings/manager.js +215 -0
  34. package/dist/embeddings/manager.js.map +1 -0
  35. package/dist/embeddings/provider.d.ts +101 -0
  36. package/dist/embeddings/provider.d.ts.map +1 -0
  37. package/dist/embeddings/provider.js +232 -0
  38. package/dist/embeddings/provider.js.map +1 -0
  39. package/dist/embeddings/vector-store.d.ts +101 -0
  40. package/dist/embeddings/vector-store.d.ts.map +1 -0
  41. package/dist/embeddings/vector-store.js +256 -0
  42. package/dist/embeddings/vector-store.js.map +1 -0
  43. package/dist/factory.d.ts +193 -0
  44. package/dist/factory.d.ts.map +1 -0
  45. package/dist/factory.js +109 -0
  46. package/dist/factory.js.map +1 -0
  47. package/dist/index.d.ts +30 -453
  48. package/dist/index.d.ts.map +1 -0
  49. package/dist/index.js +84 -509
  50. package/dist/index.js.map +1 -0
  51. package/dist/learning/analyzer.d.ts +110 -0
  52. package/dist/learning/analyzer.d.ts.map +1 -0
  53. package/dist/learning/analyzer.js +213 -0
  54. package/dist/learning/analyzer.js.map +1 -0
  55. package/dist/learning/effectiveness.d.ts +158 -0
  56. package/dist/learning/effectiveness.d.ts.map +1 -0
  57. package/dist/learning/effectiveness.js +251 -0
  58. package/dist/learning/effectiveness.js.map +1 -0
  59. package/dist/learning/index.d.ts +8 -0
  60. package/dist/learning/index.d.ts.map +1 -0
  61. package/dist/learning/index.js +11 -0
  62. package/dist/learning/index.js.map +1 -0
  63. package/dist/learning/llm-extractor.d.ts +88 -0
  64. package/dist/learning/llm-extractor.d.ts.map +1 -0
  65. package/dist/learning/llm-extractor.js +372 -0
  66. package/dist/learning/llm-extractor.js.map +1 -0
  67. package/dist/learning/meta-learner.d.ts +80 -0
  68. package/dist/learning/meta-learner.d.ts.map +1 -0
  69. package/dist/learning/meta-learner.js +355 -0
  70. package/dist/learning/meta-learner.js.map +1 -0
  71. package/dist/learning/pipeline.d.ts +65 -0
  72. package/dist/learning/pipeline.d.ts.map +1 -0
  73. package/dist/learning/pipeline.js +170 -0
  74. package/dist/learning/pipeline.js.map +1 -0
  75. package/dist/learning/playbook-extractor.d.ts +113 -0
  76. package/dist/learning/playbook-extractor.d.ts.map +1 -0
  77. package/dist/learning/playbook-extractor.js +523 -0
  78. package/dist/learning/playbook-extractor.js.map +1 -0
  79. package/dist/learning/usage-inference.d.ts +82 -0
  80. package/dist/learning/usage-inference.d.ts.map +1 -0
  81. package/dist/learning/usage-inference.js +261 -0
  82. package/dist/learning/usage-inference.js.map +1 -0
  83. package/dist/mcp/index.d.ts +6 -0
  84. package/dist/mcp/index.d.ts.map +1 -0
  85. package/dist/mcp/index.js +6 -0
  86. package/dist/mcp/index.js.map +1 -0
  87. package/dist/mcp/playbook-server.d.ts +120 -0
  88. package/dist/mcp/playbook-server.d.ts.map +1 -0
  89. package/dist/mcp/playbook-server.js +427 -0
  90. package/dist/mcp/playbook-server.js.map +1 -0
  91. package/dist/memory/curated-loader.d.ts +62 -0
  92. package/dist/memory/curated-loader.d.ts.map +1 -0
  93. package/dist/memory/curated-loader.js +106 -0
  94. package/dist/memory/curated-loader.js.map +1 -0
  95. package/dist/memory/experience.d.ts +122 -0
  96. package/dist/memory/experience.d.ts.map +1 -0
  97. package/dist/memory/experience.js +392 -0
  98. package/dist/memory/experience.js.map +1 -0
  99. package/dist/memory/index.d.ts +6 -0
  100. package/dist/memory/index.d.ts.map +1 -0
  101. package/dist/memory/index.js +9 -0
  102. package/dist/memory/index.js.map +1 -0
  103. package/dist/memory/meta.d.ts +90 -0
  104. package/dist/memory/meta.d.ts.map +1 -0
  105. package/dist/memory/meta.js +362 -0
  106. package/dist/memory/meta.js.map +1 -0
  107. package/dist/memory/playbook.d.ts +133 -0
  108. package/dist/memory/playbook.d.ts.map +1 -0
  109. package/dist/memory/playbook.js +357 -0
  110. package/dist/memory/playbook.js.map +1 -0
  111. package/dist/memory/system.d.ts +167 -0
  112. package/dist/memory/system.d.ts.map +1 -0
  113. package/dist/memory/system.js +383 -0
  114. package/dist/memory/system.js.map +1 -0
  115. package/dist/runtime/backends/acp.d.ts +67 -0
  116. package/dist/runtime/backends/acp.d.ts.map +1 -0
  117. package/dist/runtime/backends/acp.js +290 -0
  118. package/dist/runtime/backends/acp.js.map +1 -0
  119. package/dist/runtime/backends/index.d.ts +5 -0
  120. package/dist/runtime/backends/index.d.ts.map +1 -0
  121. package/dist/runtime/backends/index.js +6 -0
  122. package/dist/runtime/backends/index.js.map +1 -0
  123. package/dist/runtime/backends/mock.d.ts +67 -0
  124. package/dist/runtime/backends/mock.d.ts.map +1 -0
  125. package/dist/runtime/backends/mock.js +153 -0
  126. package/dist/runtime/backends/mock.js.map +1 -0
  127. package/dist/runtime/backends/subprocess.d.ts +56 -0
  128. package/dist/runtime/backends/subprocess.d.ts.map +1 -0
  129. package/dist/runtime/backends/subprocess.js +260 -0
  130. package/dist/runtime/backends/subprocess.js.map +1 -0
  131. package/dist/runtime/flows/learning.d.ts +73 -0
  132. package/dist/runtime/flows/learning.d.ts.map +1 -0
  133. package/dist/runtime/flows/learning.js +116 -0
  134. package/dist/runtime/flows/learning.js.map +1 -0
  135. package/dist/runtime/flows/validation.d.ts +122 -0
  136. package/dist/runtime/flows/validation.d.ts.map +1 -0
  137. package/dist/runtime/flows/validation.js +223 -0
  138. package/dist/runtime/flows/validation.js.map +1 -0
  139. package/dist/runtime/index.d.ts +6 -0
  140. package/dist/runtime/index.d.ts.map +1 -0
  141. package/dist/runtime/index.js +8 -0
  142. package/dist/runtime/index.js.map +1 -0
  143. package/dist/runtime/manager.d.ts +116 -0
  144. package/dist/runtime/manager.d.ts.map +1 -0
  145. package/dist/runtime/manager.js +416 -0
  146. package/dist/runtime/manager.js.map +1 -0
  147. package/dist/runtime/types.d.ts +138 -0
  148. package/dist/runtime/types.d.ts.map +1 -0
  149. package/dist/runtime/types.js +2 -0
  150. package/dist/runtime/types.js.map +1 -0
  151. package/dist/search/evaluator.d.ts +102 -0
  152. package/dist/search/evaluator.d.ts.map +1 -0
  153. package/dist/search/evaluator.js +352 -0
  154. package/dist/search/evaluator.js.map +1 -0
  155. package/dist/search/index.d.ts +7 -0
  156. package/dist/search/index.d.ts.map +1 -0
  157. package/dist/search/index.js +11 -0
  158. package/dist/search/index.js.map +1 -0
  159. package/dist/search/refinement-loop.d.ts +73 -0
  160. package/dist/search/refinement-loop.d.ts.map +1 -0
  161. package/dist/search/refinement-loop.js +245 -0
  162. package/dist/search/refinement-loop.js.map +1 -0
  163. package/dist/search/refinement-types.d.ts +154 -0
  164. package/dist/search/refinement-types.d.ts.map +1 -0
  165. package/dist/search/refinement-types.js +99 -0
  166. package/dist/search/refinement-types.js.map +1 -0
  167. package/dist/search/router.d.ts +61 -0
  168. package/dist/search/router.d.ts.map +1 -0
  169. package/dist/search/router.js +197 -0
  170. package/dist/search/router.js.map +1 -0
  171. package/dist/search/solver.d.ts +75 -0
  172. package/dist/search/solver.d.ts.map +1 -0
  173. package/dist/search/solver.js +216 -0
  174. package/dist/search/solver.js.map +1 -0
  175. package/dist/search/verification-runner.d.ts +125 -0
  176. package/dist/search/verification-runner.d.ts.map +1 -0
  177. package/dist/search/verification-runner.js +440 -0
  178. package/dist/search/verification-runner.js.map +1 -0
  179. package/dist/surfacing/index.d.ts +2 -0
  180. package/dist/surfacing/index.d.ts.map +1 -0
  181. package/dist/surfacing/index.js +2 -0
  182. package/dist/surfacing/index.js.map +1 -0
  183. package/dist/surfacing/skill-library.d.ts +158 -0
  184. package/dist/surfacing/skill-library.d.ts.map +1 -0
  185. package/dist/surfacing/skill-library.js +429 -0
  186. package/dist/surfacing/skill-library.js.map +1 -0
  187. package/dist/types/config.d.ts +1113 -0
  188. package/dist/types/config.d.ts.map +1 -0
  189. package/dist/types/config.js +274 -0
  190. package/dist/types/config.js.map +1 -0
  191. package/dist/types/index.d.ts +9 -0
  192. package/dist/types/index.d.ts.map +1 -0
  193. package/dist/types/index.js +14 -0
  194. package/dist/types/index.js.map +1 -0
  195. package/dist/types/memory.d.ts +339 -0
  196. package/dist/types/memory.d.ts.map +1 -0
  197. package/dist/types/memory.js +207 -0
  198. package/dist/types/memory.js.map +1 -0
  199. package/dist/types/meta.d.ts +146 -0
  200. package/dist/types/meta.d.ts.map +1 -0
  201. package/dist/types/meta.js +51 -0
  202. package/dist/types/meta.js.map +1 -0
  203. package/dist/types/outcome.d.ts +42 -0
  204. package/dist/types/outcome.d.ts.map +1 -0
  205. package/dist/types/outcome.js +50 -0
  206. package/dist/types/outcome.js.map +1 -0
  207. package/dist/types/playbook.d.ts +119 -0
  208. package/dist/types/playbook.d.ts.map +1 -0
  209. package/dist/types/playbook.js +71 -0
  210. package/dist/types/playbook.js.map +1 -0
  211. package/dist/types/step.d.ts +44 -0
  212. package/dist/types/step.d.ts.map +1 -0
  213. package/dist/types/step.js +32 -0
  214. package/dist/types/step.js.map +1 -0
  215. package/dist/types/task.d.ts +91 -0
  216. package/dist/types/task.d.ts.map +1 -0
  217. package/dist/types/task.js +39 -0
  218. package/dist/types/task.js.map +1 -0
  219. package/dist/types/trajectory.d.ts +221 -0
  220. package/dist/types/trajectory.d.ts.map +1 -0
  221. package/dist/types/trajectory.js +60 -0
  222. package/dist/types/trajectory.js.map +1 -0
  223. package/dist/utils/index.d.ts +4 -0
  224. package/dist/utils/index.d.ts.map +1 -0
  225. package/dist/utils/index.js +4 -0
  226. package/dist/utils/index.js.map +1 -0
  227. package/dist/utils/similarity.d.ts +31 -0
  228. package/dist/utils/similarity.d.ts.map +1 -0
  229. package/dist/utils/similarity.js +107 -0
  230. package/dist/utils/similarity.js.map +1 -0
  231. package/dist/utils/storage.d.ts +106 -0
  232. package/dist/utils/storage.d.ts.map +1 -0
  233. package/dist/utils/storage.js +203 -0
  234. package/dist/utils/storage.js.map +1 -0
  235. package/dist/utils/validation.d.ts +129 -0
  236. package/dist/utils/validation.d.ts.map +1 -0
  237. package/dist/utils/validation.js +171 -0
  238. package/dist/utils/validation.js.map +1 -0
  239. package/package.json +50 -34
  240. package/scripts/migrate-to-playbooks.ts +307 -0
  241. package/src/agents/index.ts +14 -0
  242. package/src/agents/mock-provider.ts +93 -0
  243. package/src/agents/types.ts +137 -0
  244. package/src/atlas.ts +560 -0
  245. package/src/bin/cognitive-core.ts +470 -0
  246. package/src/embeddings/bm25.ts +337 -0
  247. package/src/embeddings/index.ts +39 -0
  248. package/src/embeddings/manager.ts +288 -0
  249. package/src/embeddings/provider.ts +311 -0
  250. package/src/embeddings/vector-store.ts +353 -0
  251. package/src/factory.ts +263 -0
  252. package/src/index.ts +246 -0
  253. package/src/learning/analyzer.ts +335 -0
  254. package/src/learning/effectiveness.ts +428 -0
  255. package/src/learning/index.ts +58 -0
  256. package/src/learning/llm-extractor.ts +542 -0
  257. package/src/learning/meta-learner.ts +516 -0
  258. package/src/learning/pipeline.ts +244 -0
  259. package/src/learning/playbook-extractor.ts +702 -0
  260. package/src/learning/usage-inference.ts +372 -0
  261. package/src/mcp/index.ts +12 -0
  262. package/src/mcp/playbook-server.ts +565 -0
  263. package/src/memory/curated-loader.ts +160 -0
  264. package/src/memory/experience.ts +515 -0
  265. package/src/memory/index.ts +27 -0
  266. package/src/memory/meta.ts +506 -0
  267. package/src/memory/playbook.ts +493 -0
  268. package/src/memory/system.ts +551 -0
  269. package/src/runtime/backends/acp.ts +378 -0
  270. package/src/runtime/backends/index.ts +24 -0
  271. package/src/runtime/backends/mock.ts +218 -0
  272. package/src/runtime/backends/subprocess.ts +356 -0
  273. package/src/runtime/flows/learning.ts +183 -0
  274. package/src/runtime/flows/validation.ts +381 -0
  275. package/src/runtime/index.ts +53 -0
  276. package/src/runtime/manager.ts +541 -0
  277. package/src/runtime/types.ts +157 -0
  278. package/src/search/evaluator.ts +474 -0
  279. package/src/search/index.ts +59 -0
  280. package/src/search/refinement-loop.ts +363 -0
  281. package/src/search/refinement-types.ts +159 -0
  282. package/src/search/router.ts +261 -0
  283. package/src/search/solver.ts +303 -0
  284. package/src/search/verification-runner.ts +570 -0
  285. package/src/surfacing/index.ts +6 -0
  286. package/src/surfacing/skill-library.ts +594 -0
  287. package/src/types/config.ts +333 -0
  288. package/src/types/index.ts +130 -0
  289. package/src/types/memory.ts +270 -0
  290. package/src/types/meta.ts +218 -0
  291. package/src/types/outcome.ts +66 -0
  292. package/src/types/playbook.ts +196 -0
  293. package/src/types/step.ts +40 -0
  294. package/src/types/task.ts +52 -0
  295. package/src/types/trajectory.ts +80 -0
  296. package/src/utils/index.ts +38 -0
  297. package/src/utils/similarity.ts +139 -0
  298. package/src/utils/storage.ts +249 -0
  299. package/src/utils/validation.ts +286 -0
  300. package/tests/embeddings/bm25.test.ts +130 -0
  301. package/tests/embeddings/manager.test.ts +205 -0
  302. package/tests/integration/atlas.test.ts +266 -0
  303. package/tests/integration/e2e.test.ts +929 -0
  304. package/tests/learning/analyzer.test.ts +426 -0
  305. package/tests/learning/effectiveness.test.ts +542 -0
  306. package/tests/learning/pipeline.test.ts +176 -0
  307. package/tests/learning/playbook-extractor-provenance.test.ts +114 -0
  308. package/tests/learning/usage-inference.test.ts +254 -0
  309. package/tests/mcp/playbook-server.test.ts +252 -0
  310. package/tests/memory/experience.test.ts +198 -0
  311. package/tests/memory/playbook.test.ts +338 -0
  312. package/tests/memory/provenance.test.ts +639 -0
  313. package/tests/memory/system.test.ts +325 -0
  314. package/tests/runtime/agent-manager.test.ts +512 -0
  315. package/tests/runtime/mock-backend.test.ts +248 -0
  316. package/tests/search/refinement-loop.test.ts +468 -0
  317. package/tests/search/refinement.test.ts +267 -0
  318. package/tests/search/router.test.ts +427 -0
  319. package/tests/surfacing/skill-library.test.ts +292 -0
  320. package/tests/types/outcome.test.ts +147 -0
  321. package/tests/types/step.test.ts +133 -0
  322. package/tests/types/task.test.ts +158 -0
  323. package/tests/types/trajectory.test.ts +253 -0
  324. package/tests/utils/similarity.test.ts +188 -0
  325. package/tests/utils/validation.test.ts +252 -0
  326. package/tsconfig.json +25 -0
  327. package/vitest.config.ts +22 -0
  328. package/dist/index.d.mts +0 -466
  329. package/dist/index.mjs +0 -478
@@ -0,0 +1,252 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import { PlaybookMCPServer, createPlaybookMCPServer } from '../../src/mcp/playbook-server.js';
3
+ import { PlaybookLibrary } from '../../src/memory/playbook.js';
4
+ import { createPlaybook } from '../../src/types/playbook.js';
5
+ import * as fs from 'node:fs/promises';
6
+ import * as path from 'node:path';
7
+
8
+ describe('PlaybookMCPServer', () => {
9
+ let server: PlaybookMCPServer;
10
+ let playbooks: PlaybookLibrary;
11
+ let testDir: string;
12
+
13
+ beforeEach(async () => {
14
+ testDir = path.join(process.cwd(), '.test-mcp-' + Date.now());
15
+ await fs.mkdir(testDir, { recursive: true });
16
+ playbooks = new PlaybookLibrary(testDir);
17
+ await playbooks.init();
18
+ server = createPlaybookMCPServer(playbooks, undefined, {
19
+ maxResults: 5,
20
+ minConfidence: 0.3,
21
+ });
22
+
23
+ // Add test playbooks
24
+ await playbooks.add(createPlaybook({
25
+ name: 'Debug TypeScript Errors',
26
+ applicability: {
27
+ situations: ['When encountering TypeScript compilation errors'],
28
+ triggers: ['type error', 'typescript', 'TS2'],
29
+ antiPatterns: [],
30
+ domains: ['code', 'typescript'],
31
+ },
32
+ guidance: {
33
+ strategy: 'Systematically identify and fix type mismatches',
34
+ tactics: ['Check type definitions', 'Use type assertions carefully'],
35
+ steps: ['Read error message', 'Find source file', 'Fix type'],
36
+ },
37
+ verification: {
38
+ successIndicators: ['tsc compiles successfully'],
39
+ failureIndicators: ['errors persist'],
40
+ commands: [],
41
+ },
42
+ confidence: 0.8,
43
+ }));
44
+
45
+ await playbooks.add(createPlaybook({
46
+ name: 'Write Unit Tests',
47
+ applicability: {
48
+ situations: ['When adding test coverage'],
49
+ triggers: ['test', 'unit test', 'vitest'],
50
+ antiPatterns: [],
51
+ domains: ['testing'],
52
+ },
53
+ guidance: {
54
+ strategy: 'Write focused tests for individual functions',
55
+ tactics: ['Use describe/it blocks', 'Test edge cases'],
56
+ },
57
+ verification: {
58
+ successIndicators: ['tests pass'],
59
+ failureIndicators: ['tests fail'],
60
+ commands: [],
61
+ },
62
+ confidence: 0.9,
63
+ }));
64
+ });
65
+
66
+ afterEach(async () => {
67
+ await playbooks.close();
68
+ await fs.rm(testDir, { recursive: true, force: true });
69
+ });
70
+
71
+ describe('getTools', () => {
72
+ it('should return available MCP tools', () => {
73
+ const tools = server.getTools();
74
+
75
+ expect(tools).toHaveLength(4);
76
+ expect(tools.map(t => t.name)).toContain('search_playbooks');
77
+ expect(tools.map(t => t.name)).toContain('get_playbook_details');
78
+ expect(tools.map(t => t.name)).toContain('list_domains');
79
+ expect(tools.map(t => t.name)).toContain('get_playbooks_by_domain');
80
+ });
81
+
82
+ it('should have proper input schemas', () => {
83
+ const tools = server.getTools();
84
+ const searchTool = tools.find(t => t.name === 'search_playbooks');
85
+
86
+ expect(searchTool?.inputSchema.type).toBe('object');
87
+ expect(searchTool?.inputSchema.required).toContain('query');
88
+ expect(searchTool?.inputSchema.properties).toHaveProperty('query');
89
+ });
90
+ });
91
+
92
+ describe('handleToolCall - search_playbooks', () => {
93
+ it('should search playbooks by query', async () => {
94
+ const result = await server.handleToolCall({
95
+ name: 'search_playbooks',
96
+ arguments: { query: 'typescript error' },
97
+ });
98
+
99
+ expect(result.isError).toBeFalsy();
100
+ expect(result.content[0].text).toContain('Debug TypeScript Errors');
101
+ });
102
+
103
+ it('should filter by domain', async () => {
104
+ const result = await server.handleToolCall({
105
+ name: 'search_playbooks',
106
+ arguments: { query: 'test coverage', domain: 'testing' },
107
+ });
108
+
109
+ expect(result.isError).toBeFalsy();
110
+ expect(result.content[0].text).toContain('Write Unit Tests');
111
+ expect(result.content[0].text).not.toContain('Debug TypeScript Errors');
112
+ });
113
+
114
+ it('should return message when no results found', async () => {
115
+ const result = await server.handleToolCall({
116
+ name: 'search_playbooks',
117
+ arguments: { query: 'nonexistent query xyz123' },
118
+ });
119
+
120
+ expect(result.isError).toBeFalsy();
121
+ expect(result.content[0].text).toContain('No playbooks found');
122
+ });
123
+
124
+ it('should validate required arguments', async () => {
125
+ const result = await server.handleToolCall({
126
+ name: 'search_playbooks',
127
+ arguments: {}, // Missing query
128
+ });
129
+
130
+ expect(result.isError).toBe(true);
131
+ expect(result.content[0].text).toContain('Error');
132
+ });
133
+
134
+ it('should respect maxResults limit', async () => {
135
+ const result = await server.handleToolCall({
136
+ name: 'search_playbooks',
137
+ arguments: { query: 'typescript error', maxResults: 1 },
138
+ });
139
+
140
+ expect(result.isError).toBeFalsy();
141
+ // Should only return at most 1 result (could be 0 if no match)
142
+ const text = result.content[0].text;
143
+ if (!text.includes('No playbooks found')) {
144
+ const matches = text.match(/## /g);
145
+ expect(matches?.length ?? 0).toBeLessThanOrEqual(1);
146
+ }
147
+ });
148
+ });
149
+
150
+ describe('handleToolCall - get_playbook_details', () => {
151
+ it('should get playbook details by ID', async () => {
152
+ const allPlaybooks = await playbooks.getAll();
153
+ const playbookId = allPlaybooks[0].id;
154
+
155
+ const result = await server.handleToolCall({
156
+ name: 'get_playbook_details',
157
+ arguments: { playbookId },
158
+ });
159
+
160
+ expect(result.isError).toBeFalsy();
161
+ expect(result.content[0].text).toContain(allPlaybooks[0].name);
162
+ expect(result.content[0].text).toContain('Strategy');
163
+ expect(result.content[0].text).toContain('Tactics');
164
+ });
165
+
166
+ it('should return error for non-existent playbook', async () => {
167
+ const result = await server.handleToolCall({
168
+ name: 'get_playbook_details',
169
+ arguments: { playbookId: 'non-existent-id' },
170
+ });
171
+
172
+ expect(result.isError).toBe(true);
173
+ expect(result.content[0].text).toContain('not found');
174
+ });
175
+
176
+ it('should validate required arguments', async () => {
177
+ const result = await server.handleToolCall({
178
+ name: 'get_playbook_details',
179
+ arguments: {}, // Missing playbookId
180
+ });
181
+
182
+ expect(result.isError).toBe(true);
183
+ });
184
+ });
185
+
186
+ describe('handleToolCall - list_domains', () => {
187
+ it('should list all domains', async () => {
188
+ const result = await server.handleToolCall({
189
+ name: 'list_domains',
190
+ arguments: {},
191
+ });
192
+
193
+ expect(result.isError).toBeFalsy();
194
+ expect(result.content[0].text).toContain('code');
195
+ expect(result.content[0].text).toContain('typescript');
196
+ expect(result.content[0].text).toContain('testing');
197
+ });
198
+ });
199
+
200
+ describe('handleToolCall - get_playbooks_by_domain', () => {
201
+ it('should get playbooks for a specific domain', async () => {
202
+ const result = await server.handleToolCall({
203
+ name: 'get_playbooks_by_domain',
204
+ arguments: { domain: 'testing' },
205
+ });
206
+
207
+ expect(result.isError).toBeFalsy();
208
+ expect(result.content[0].text).toContain('Write Unit Tests');
209
+ });
210
+
211
+ it('should return message when no playbooks in domain', async () => {
212
+ const result = await server.handleToolCall({
213
+ name: 'get_playbooks_by_domain',
214
+ arguments: { domain: 'nonexistent-domain' },
215
+ });
216
+
217
+ expect(result.isError).toBeFalsy();
218
+ expect(result.content[0].text).toContain('No playbooks found');
219
+ });
220
+
221
+ it('should validate required arguments', async () => {
222
+ const result = await server.handleToolCall({
223
+ name: 'get_playbooks_by_domain',
224
+ arguments: {}, // Missing domain
225
+ });
226
+
227
+ expect(result.isError).toBe(true);
228
+ });
229
+ });
230
+
231
+ describe('handleToolCall - unknown tool', () => {
232
+ it('should return error for unknown tool', async () => {
233
+ const result = await server.handleToolCall({
234
+ name: 'unknown_tool',
235
+ arguments: {},
236
+ });
237
+
238
+ expect(result.isError).toBe(true);
239
+ expect(result.content[0].text).toContain('Unknown tool');
240
+ });
241
+ });
242
+
243
+ describe('getServerInfo', () => {
244
+ it('should return server information', () => {
245
+ const info = server.getServerInfo();
246
+
247
+ expect(info.name).toBe('atlas-playbook-server');
248
+ expect(info.version).toBeDefined();
249
+ expect(info.description).toBeDefined();
250
+ });
251
+ });
252
+ });
@@ -0,0 +1,198 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import { ExperienceMemory } from '../../src/memory/experience.js';
3
+ import { createExperience, type Experience } from '../../src/types/memory.js';
4
+ import { mkdtemp, rm } from 'node:fs/promises';
5
+ import { join } from 'node:path';
6
+ import { tmpdir } from 'node:os';
7
+
8
+ describe('ExperienceMemory', () => {
9
+ let tempDir: string;
10
+ let memory: ExperienceMemory;
11
+
12
+ beforeEach(async () => {
13
+ tempDir = await mkdtemp(join(tmpdir(), 'atlas-test-'));
14
+ memory = new ExperienceMemory(tempDir);
15
+ await memory.init();
16
+ });
17
+
18
+ afterEach(async () => {
19
+ await memory.close();
20
+ await rm(tempDir, { recursive: true, force: true });
21
+ });
22
+
23
+ function createSampleExperience(overrides?: Partial<Experience>): Experience {
24
+ return createExperience({
25
+ taskInput: 'Write a function to add two numbers',
26
+ solutionOutput: 'function add(a, b) { return a + b; }',
27
+ feedback: 'Correct implementation',
28
+ success: true,
29
+ domain: 'code',
30
+ trajectoryId: 'traj-1',
31
+ ...overrides,
32
+ });
33
+ }
34
+
35
+ describe('add and get', () => {
36
+ it('should store and retrieve an experience', async () => {
37
+ const exp = createSampleExperience();
38
+ await memory.add(exp);
39
+
40
+ const retrieved = await memory.get(exp.id);
41
+ expect(retrieved).toBeDefined();
42
+ expect(retrieved?.taskInput).toBe(exp.taskInput);
43
+ expect(retrieved?.success).toBe(true);
44
+ });
45
+
46
+ it('should return undefined for non-existent id', async () => {
47
+ const result = await memory.get('non-existent-id');
48
+ expect(result).toBeUndefined();
49
+ });
50
+ });
51
+
52
+ describe('findSimilar', () => {
53
+ it('should find similar experiences by text', async () => {
54
+ await memory.add(createSampleExperience({
55
+ taskInput: 'Write a function to add two numbers',
56
+ }));
57
+ await memory.add(createSampleExperience({
58
+ taskInput: 'Write a function to multiply two numbers',
59
+ }));
60
+ await memory.add(createSampleExperience({
61
+ taskInput: 'Create a database schema',
62
+ }));
63
+
64
+ const results = await memory.findSimilar('function to add numbers', { k: 2 });
65
+ expect(results.length).toBeGreaterThanOrEqual(1);
66
+ expect(results[0].experience.taskInput).toContain('add');
67
+ });
68
+
69
+ it('should filter by domain', async () => {
70
+ await memory.add(createSampleExperience({ domain: 'code' }));
71
+ await memory.add(createSampleExperience({ domain: 'reasoning' }));
72
+
73
+ const results = await memory.findSimilar('test', { domain: 'code' });
74
+ expect(results.every(r => r.experience.domain === 'code')).toBe(true);
75
+ });
76
+
77
+ it('should filter by success', async () => {
78
+ await memory.add(createSampleExperience({ success: true }));
79
+ await memory.add(createSampleExperience({ success: false }));
80
+
81
+ const results = await memory.findSimilar('test', { successOnly: true });
82
+ expect(results.every(r => r.experience.success)).toBe(true);
83
+ });
84
+
85
+ it('should filter by minimum score', async () => {
86
+ await memory.add(createSampleExperience({
87
+ taskInput: 'exact match query here',
88
+ }));
89
+ await memory.add(createSampleExperience({
90
+ taskInput: 'something completely unrelated',
91
+ }));
92
+
93
+ const results = await memory.findSimilar('exact match query here', {
94
+ minScore: 0.9,
95
+ });
96
+ // Only high-scoring results should be returned
97
+ expect(results.every(r => r.score >= 0.9)).toBe(true);
98
+ });
99
+ });
100
+
101
+ describe('update', () => {
102
+ it('should update an experience', async () => {
103
+ const exp = createSampleExperience();
104
+ await memory.add(exp);
105
+
106
+ const updated = await memory.update(exp.id, {
107
+ feedback: 'Updated feedback',
108
+ });
109
+
110
+ expect(updated?.feedback).toBe('Updated feedback');
111
+ expect(updated?.id).toBe(exp.id); // ID preserved
112
+ });
113
+
114
+ it('should return undefined for non-existent id', async () => {
115
+ const result = await memory.update('non-existent', { feedback: 'new' });
116
+ expect(result).toBeUndefined();
117
+ });
118
+ });
119
+
120
+ describe('recordUsage', () => {
121
+ it('should increment usage count', async () => {
122
+ const exp = createSampleExperience();
123
+ await memory.add(exp);
124
+
125
+ await memory.recordUsage(exp.id);
126
+ await memory.recordUsage(exp.id);
127
+
128
+ const updated = await memory.get(exp.id);
129
+ expect(updated?.usageCount).toBe(2);
130
+ expect(updated?.lastAccessedAt).toBeDefined();
131
+ });
132
+ });
133
+
134
+ describe('getAll and getByTrajectory', () => {
135
+ it('should get all experiences', async () => {
136
+ await memory.add(createSampleExperience());
137
+ await memory.add(createSampleExperience());
138
+ await memory.add(createSampleExperience());
139
+
140
+ const all = await memory.getAll();
141
+ expect(all).toHaveLength(3);
142
+ });
143
+
144
+ it('should get experiences by trajectory', async () => {
145
+ await memory.add(createSampleExperience({ trajectoryId: 'traj-a' }));
146
+ await memory.add(createSampleExperience({ trajectoryId: 'traj-a' }));
147
+ await memory.add(createSampleExperience({ trajectoryId: 'traj-b' }));
148
+
149
+ const results = await memory.getByTrajectory('traj-a');
150
+ expect(results).toHaveLength(2);
151
+ });
152
+ });
153
+
154
+ describe('prune', () => {
155
+ it('should prune experiences by count', async () => {
156
+ for (let i = 0; i < 5; i++) {
157
+ await memory.add(createSampleExperience());
158
+ }
159
+
160
+ const pruned = await memory.prune({ maxCount: 3 });
161
+ expect(pruned.totalPruned).toBe(2);
162
+ expect(pruned.prunedByReason.capacity).toHaveLength(2);
163
+
164
+ const remaining = await memory.count();
165
+ expect(remaining).toBe(3);
166
+ });
167
+ });
168
+
169
+ describe('count', () => {
170
+ it('should return correct count', async () => {
171
+ expect(await memory.count()).toBe(0);
172
+
173
+ await memory.add(createSampleExperience());
174
+ expect(await memory.count()).toBe(1);
175
+
176
+ await memory.add(createSampleExperience());
177
+ expect(await memory.count()).toBe(2);
178
+ });
179
+ });
180
+
181
+ describe('persistence', () => {
182
+ it('should persist data across reloads', async () => {
183
+ const exp = createSampleExperience();
184
+ await memory.add(exp);
185
+ await memory.close();
186
+
187
+ // Create new memory instance
188
+ const memory2 = new ExperienceMemory(tempDir);
189
+ await memory2.init();
190
+
191
+ const retrieved = await memory2.get(exp.id);
192
+ expect(retrieved).toBeDefined();
193
+ expect(retrieved?.taskInput).toBe(exp.taskInput);
194
+
195
+ await memory2.close();
196
+ });
197
+ });
198
+ });