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,565 @@
1
+ /**
2
+ * MCP Playbook Server
3
+ * Exposes playbook retrieval via Model Context Protocol
4
+ *
5
+ * @deprecated This module is deprecated in favor of the CLI interface and SKILL.md approach.
6
+ * See /SKILL.md for instructions on how agents should interact with cognitive-core.
7
+ * Use the CLI at bin/cognitive-core instead of this MCP server.
8
+ *
9
+ * This server provides on-demand access to the full playbook library,
10
+ * allowing agents to search for specific guidance beyond what's in their
11
+ * system prompt.
12
+ */
13
+
14
+ import type { Playbook } from '../types/index.js';
15
+ import type { PlaybookLibrary, PlaybookMatch } from '../memory/playbook.js';
16
+ import type { SkillLibrary } from '../surfacing/skill-library.js';
17
+ import type { MCPServerConfig } from '../types/config.js';
18
+ import {
19
+ validateMCPArgs,
20
+ MCPSearchPlaybooksSchema,
21
+ MCPGetPlaybookDetailsSchema,
22
+ MCPGetPlaybooksByDomainSchema,
23
+ } from '../utils/validation.js';
24
+
25
+ /**
26
+ * MCP Tool definition
27
+ */
28
+ export interface MCPTool {
29
+ name: string;
30
+ description: string;
31
+ inputSchema: {
32
+ type: 'object';
33
+ properties: Record<string, unknown>;
34
+ required?: string[];
35
+ };
36
+ }
37
+
38
+ /**
39
+ * MCP Tool call request
40
+ */
41
+ export interface MCPToolCall {
42
+ name: string;
43
+ arguments: Record<string, unknown>;
44
+ }
45
+
46
+ /**
47
+ * MCP Tool call result
48
+ */
49
+ export interface MCPToolResult {
50
+ content: Array<{
51
+ type: 'text';
52
+ text: string;
53
+ }>;
54
+ isError?: boolean;
55
+ }
56
+
57
+ /**
58
+ * Search result for MCP
59
+ */
60
+ export interface PlaybookSearchResult {
61
+ id: string;
62
+ name: string;
63
+ confidence: number;
64
+ matchScore: number;
65
+ matchType: string;
66
+ strategy: string;
67
+ tactics: string[];
68
+ successRate: number;
69
+ domains: string[];
70
+ }
71
+
72
+ /**
73
+ * Default configuration
74
+ */
75
+ const DEFAULT_CONFIG: MCPServerConfig = {
76
+ enabled: true,
77
+ exposeResources: true,
78
+ exposeTools: true,
79
+ maxResults: 5,
80
+ minConfidence: 0.3,
81
+ includeRefinements: true,
82
+ enableDomainFiltering: true,
83
+ };
84
+
85
+ /**
86
+ * MCP Playbook Server
87
+ * Provides playbook search tools for agents
88
+ */
89
+ export class PlaybookMCPServer {
90
+ private playbooks: PlaybookLibrary;
91
+ private config: MCPServerConfig;
92
+
93
+ constructor(
94
+ playbooks: PlaybookLibrary,
95
+ _skillLibrary?: SkillLibrary,
96
+ config?: Partial<MCPServerConfig>
97
+ ) {
98
+ this.playbooks = playbooks;
99
+ this.config = { ...DEFAULT_CONFIG, ...config };
100
+ }
101
+
102
+ /**
103
+ * Get available MCP tools
104
+ */
105
+ getTools(): MCPTool[] {
106
+ return [
107
+ {
108
+ name: 'search_playbooks',
109
+ description:
110
+ 'Search for playbooks that provide guidance for solving a problem. ' +
111
+ 'Returns strategies, tactics, and success indicators for matching playbooks.',
112
+ inputSchema: {
113
+ type: 'object',
114
+ properties: {
115
+ query: {
116
+ type: 'string',
117
+ description: 'Description of the problem or task to find playbooks for',
118
+ },
119
+ domain: {
120
+ type: 'string',
121
+ description: 'Optional domain to filter results (e.g., "code", "testing", "refactoring")',
122
+ },
123
+ maxResults: {
124
+ type: 'number',
125
+ description: 'Maximum number of playbooks to return (default: 5)',
126
+ },
127
+ },
128
+ required: ['query'],
129
+ },
130
+ },
131
+ {
132
+ name: 'get_playbook_details',
133
+ description:
134
+ 'Get detailed information about a specific playbook by ID, ' +
135
+ 'including full tactics, steps, refinements, and usage statistics.',
136
+ inputSchema: {
137
+ type: 'object',
138
+ properties: {
139
+ playbookId: {
140
+ type: 'string',
141
+ description: 'The ID of the playbook to retrieve',
142
+ },
143
+ },
144
+ required: ['playbookId'],
145
+ },
146
+ },
147
+ {
148
+ name: 'list_domains',
149
+ description: 'List all domains that have playbooks available.',
150
+ inputSchema: {
151
+ type: 'object',
152
+ properties: {},
153
+ },
154
+ },
155
+ {
156
+ name: 'get_playbooks_by_domain',
157
+ description: 'Get all playbooks for a specific domain.',
158
+ inputSchema: {
159
+ type: 'object',
160
+ properties: {
161
+ domain: {
162
+ type: 'string',
163
+ description: 'The domain to get playbooks for',
164
+ },
165
+ maxResults: {
166
+ type: 'number',
167
+ description: 'Maximum number of playbooks to return (default: 10)',
168
+ },
169
+ },
170
+ required: ['domain'],
171
+ },
172
+ },
173
+ ];
174
+ }
175
+
176
+ /**
177
+ * Handle an MCP tool call
178
+ */
179
+ async handleToolCall(call: MCPToolCall): Promise<MCPToolResult> {
180
+ try {
181
+ switch (call.name) {
182
+ case 'search_playbooks':
183
+ return await this.handleSearchPlaybooks(call.arguments);
184
+ case 'get_playbook_details':
185
+ return await this.handleGetPlaybookDetails(call.arguments);
186
+ case 'list_domains':
187
+ return await this.handleListDomains();
188
+ case 'get_playbooks_by_domain':
189
+ return await this.handleGetPlaybooksByDomain(call.arguments);
190
+ default:
191
+ return {
192
+ content: [{ type: 'text', text: `Unknown tool: ${call.name}` }],
193
+ isError: true,
194
+ };
195
+ }
196
+ } catch (error) {
197
+ return {
198
+ content: [
199
+ {
200
+ type: 'text',
201
+ text: `Error: ${error instanceof Error ? error.message : String(error)}`,
202
+ },
203
+ ],
204
+ isError: true,
205
+ };
206
+ }
207
+ }
208
+
209
+ /**
210
+ * Handle search_playbooks tool call
211
+ */
212
+ private async handleSearchPlaybooks(
213
+ args: Record<string, unknown>
214
+ ): Promise<MCPToolResult> {
215
+ // Validate arguments
216
+ const validated = validateMCPArgs(
217
+ MCPSearchPlaybooksSchema,
218
+ args,
219
+ 'search_playbooks'
220
+ );
221
+ const { query, domain } = validated;
222
+ const maxResults = validated.maxResults ?? this.config.maxResults;
223
+
224
+ const matches = await this.playbooks.findMatching(query, {
225
+ k: maxResults,
226
+ domains: domain ? [domain] : undefined,
227
+ minConfidence: this.config.minConfidence,
228
+ excludeAntiPatterns: true,
229
+ });
230
+
231
+ if (matches.length === 0) {
232
+ return {
233
+ content: [
234
+ {
235
+ type: 'text',
236
+ text: 'No playbooks found matching your query. Try a different description or broader search terms.',
237
+ },
238
+ ],
239
+ };
240
+ }
241
+
242
+ const results: PlaybookSearchResult[] = matches.map((m) =>
243
+ this.formatPlaybookForSearch(m)
244
+ );
245
+
246
+ const formattedResults = results
247
+ .map((r) => this.formatSearchResultAsText(r))
248
+ .join('\n\n---\n\n');
249
+
250
+ return {
251
+ content: [{ type: 'text', text: formattedResults }],
252
+ };
253
+ }
254
+
255
+ /**
256
+ * Handle get_playbook_details tool call
257
+ */
258
+ private async handleGetPlaybookDetails(
259
+ args: Record<string, unknown>
260
+ ): Promise<MCPToolResult> {
261
+ // Validate arguments
262
+ const validated = validateMCPArgs(
263
+ MCPGetPlaybookDetailsSchema,
264
+ args,
265
+ 'get_playbook_details'
266
+ );
267
+ const playbook = await this.playbooks.get(validated.playbookId);
268
+
269
+ if (!playbook) {
270
+ return {
271
+ content: [
272
+ {
273
+ type: 'text',
274
+ text: `Playbook not found: ${validated.playbookId}`,
275
+ },
276
+ ],
277
+ isError: true,
278
+ };
279
+ }
280
+
281
+ const details = this.formatPlaybookDetails(playbook);
282
+ return {
283
+ content: [{ type: 'text', text: details }],
284
+ };
285
+ }
286
+
287
+ /**
288
+ * Handle list_domains tool call
289
+ */
290
+ private async handleListDomains(): Promise<MCPToolResult> {
291
+ const allPlaybooks = await this.playbooks.getAll();
292
+ const domains = new Set<string>();
293
+
294
+ for (const playbook of allPlaybooks) {
295
+ for (const domain of playbook.applicability.domains) {
296
+ domains.add(domain);
297
+ }
298
+ }
299
+
300
+ const domainList = Array.from(domains).sort();
301
+
302
+ if (domainList.length === 0) {
303
+ return {
304
+ content: [
305
+ {
306
+ type: 'text',
307
+ text: 'No domains found. Playbooks may not have domain assignments yet.',
308
+ },
309
+ ],
310
+ };
311
+ }
312
+
313
+ const text = `Available domains:\n${domainList.map((d) => ` - ${d}`).join('\n')}`;
314
+ return {
315
+ content: [{ type: 'text', text }],
316
+ };
317
+ }
318
+
319
+ /**
320
+ * Handle get_playbooks_by_domain tool call
321
+ */
322
+ private async handleGetPlaybooksByDomain(
323
+ args: Record<string, unknown>
324
+ ): Promise<MCPToolResult> {
325
+ // Validate arguments
326
+ const validated = validateMCPArgs(
327
+ MCPGetPlaybooksByDomainSchema,
328
+ args,
329
+ 'get_playbooks_by_domain'
330
+ );
331
+ const { domain } = validated;
332
+ const maxResults = validated.maxResults ?? 10;
333
+
334
+ const allPlaybooks = await this.playbooks.getAll();
335
+ const domainPlaybooks = allPlaybooks
336
+ .filter((p) => p.applicability.domains.includes(domain))
337
+ .sort((a, b) => b.confidence - a.confidence)
338
+ .slice(0, maxResults);
339
+
340
+ if (domainPlaybooks.length === 0) {
341
+ return {
342
+ content: [
343
+ {
344
+ type: 'text',
345
+ text: `No playbooks found for domain: ${domain}`,
346
+ },
347
+ ],
348
+ };
349
+ }
350
+
351
+ const formatted = domainPlaybooks
352
+ .map((p) => this.formatPlaybookSummary(p))
353
+ .join('\n\n');
354
+
355
+ return {
356
+ content: [{ type: 'text', text: formatted }],
357
+ };
358
+ }
359
+
360
+ /**
361
+ * Format playbook match for search results
362
+ */
363
+ private formatPlaybookForSearch(match: PlaybookMatch): PlaybookSearchResult {
364
+ const { playbook, score, matchType } = match;
365
+ const { successCount, failureCount } = playbook.evolution;
366
+ const totalUses = successCount + failureCount;
367
+
368
+ return {
369
+ id: playbook.id,
370
+ name: playbook.name,
371
+ confidence: playbook.confidence,
372
+ matchScore: score,
373
+ matchType,
374
+ strategy: playbook.guidance.strategy,
375
+ tactics: playbook.guidance.tactics,
376
+ successRate: totalUses > 0 ? successCount / totalUses : 0,
377
+ domains: playbook.applicability.domains,
378
+ };
379
+ }
380
+
381
+ /**
382
+ * Format search result as text
383
+ */
384
+ private formatSearchResultAsText(result: PlaybookSearchResult): string {
385
+ const lines: string[] = [];
386
+
387
+ lines.push(`## ${result.name}`);
388
+ lines.push(`ID: ${result.id}`);
389
+ lines.push(`Match: ${Math.round(result.matchScore * 100)}% (${result.matchType})`);
390
+ lines.push(`Confidence: ${Math.round(result.confidence * 100)}%`);
391
+ lines.push(`Success Rate: ${Math.round(result.successRate * 100)}%`);
392
+
393
+ if (result.domains.length > 0) {
394
+ lines.push(`Domains: ${result.domains.join(', ')}`);
395
+ }
396
+
397
+ lines.push('');
398
+ lines.push(`**Strategy**: ${result.strategy}`);
399
+
400
+ if (result.tactics.length > 0) {
401
+ lines.push('**Tactics**:');
402
+ for (const tactic of result.tactics.slice(0, 5)) {
403
+ lines.push(` - ${tactic}`);
404
+ }
405
+ if (result.tactics.length > 5) {
406
+ lines.push(` ... and ${result.tactics.length - 5} more`);
407
+ }
408
+ }
409
+
410
+ return lines.join('\n');
411
+ }
412
+
413
+ /**
414
+ * Format playbook summary
415
+ */
416
+ private formatPlaybookSummary(playbook: Playbook): string {
417
+ const lines: string[] = [];
418
+ const { successCount, failureCount } = playbook.evolution;
419
+ const totalUses = successCount + failureCount;
420
+ const successRate = totalUses > 0 ? successCount / totalUses : 0;
421
+
422
+ lines.push(`## ${playbook.name}`);
423
+ lines.push(`ID: ${playbook.id}`);
424
+ lines.push(`Confidence: ${Math.round(playbook.confidence * 100)}%`);
425
+ lines.push(`Uses: ${totalUses} (${Math.round(successRate * 100)}% success)`);
426
+ lines.push('');
427
+ lines.push(`**Strategy**: ${playbook.guidance.strategy}`);
428
+
429
+ return lines.join('\n');
430
+ }
431
+
432
+ /**
433
+ * Format full playbook details
434
+ */
435
+ private formatPlaybookDetails(playbook: Playbook): string {
436
+ const lines: string[] = [];
437
+ const { successCount, failureCount } = playbook.evolution;
438
+ const totalUses = successCount + failureCount;
439
+ const successRate = totalUses > 0 ? successCount / totalUses : 0;
440
+
441
+ lines.push(`# ${playbook.name}`);
442
+ lines.push(`ID: ${playbook.id}`);
443
+ lines.push(`Version: ${playbook.evolution.version}`);
444
+ lines.push(`Confidence: ${Math.round(playbook.confidence * 100)}%`);
445
+ lines.push(`Complexity: ${playbook.complexity}`);
446
+ lines.push(`Estimated Effort: ${playbook.estimatedEffort} steps`);
447
+ lines.push('');
448
+
449
+ // Applicability
450
+ lines.push('## Applicability');
451
+ if (playbook.applicability.situations.length > 0) {
452
+ lines.push('**When to use**:');
453
+ for (const sit of playbook.applicability.situations) {
454
+ lines.push(` - ${sit}`);
455
+ }
456
+ }
457
+ if (playbook.applicability.triggers.length > 0) {
458
+ lines.push('**Triggers**:');
459
+ for (const trigger of playbook.applicability.triggers) {
460
+ lines.push(` - ${trigger}`);
461
+ }
462
+ }
463
+ if (playbook.applicability.antiPatterns.length > 0) {
464
+ lines.push('**Avoid when**:');
465
+ for (const anti of playbook.applicability.antiPatterns) {
466
+ lines.push(` - ${anti}`);
467
+ }
468
+ }
469
+ if (playbook.applicability.domains.length > 0) {
470
+ lines.push(`**Domains**: ${playbook.applicability.domains.join(', ')}`);
471
+ }
472
+ lines.push('');
473
+
474
+ // Guidance
475
+ lines.push('## Guidance');
476
+ lines.push(`**Strategy**: ${playbook.guidance.strategy}`);
477
+ if (playbook.guidance.tactics.length > 0) {
478
+ lines.push('**Tactics**:');
479
+ for (const tactic of playbook.guidance.tactics) {
480
+ lines.push(` - ${tactic}`);
481
+ }
482
+ }
483
+ if (playbook.guidance.steps && playbook.guidance.steps.length > 0) {
484
+ lines.push('**Steps**:');
485
+ for (let i = 0; i < playbook.guidance.steps.length; i++) {
486
+ lines.push(` ${i + 1}. ${playbook.guidance.steps[i]}`);
487
+ }
488
+ }
489
+ lines.push('');
490
+
491
+ // Verification
492
+ lines.push('## Verification');
493
+ if (playbook.verification.successIndicators.length > 0) {
494
+ lines.push('**Success indicators**:');
495
+ for (const ind of playbook.verification.successIndicators) {
496
+ lines.push(` - ${ind}`);
497
+ }
498
+ }
499
+ if (playbook.verification.failureIndicators.length > 0) {
500
+ lines.push('**Failure indicators**:');
501
+ for (const ind of playbook.verification.failureIndicators) {
502
+ lines.push(` - ${ind}`);
503
+ }
504
+ }
505
+ lines.push('');
506
+
507
+ // Statistics
508
+ lines.push('## Statistics');
509
+ lines.push(`- Total uses: ${totalUses}`);
510
+ lines.push(`- Success rate: ${Math.round(successRate * 100)}%`);
511
+ lines.push(`- Successes: ${successCount}`);
512
+ lines.push(`- Failures: ${failureCount}`);
513
+ lines.push('');
514
+
515
+ // Refinements (if enabled)
516
+ if (
517
+ this.config.includeRefinements &&
518
+ playbook.evolution.refinements.length > 0
519
+ ) {
520
+ lines.push('## Context-Specific Refinements');
521
+ for (const ref of playbook.evolution.refinements) {
522
+ lines.push(`- **${ref.context}**: ${ref.addition}`);
523
+ }
524
+ lines.push('');
525
+ }
526
+
527
+ // Failure modes
528
+ if (playbook.evolution.failures.length > 0) {
529
+ lines.push('## Known Failure Modes');
530
+ for (const failure of playbook.evolution.failures.slice(0, 5)) {
531
+ lines.push(`- ${failure.context}: ${failure.failureMode}`);
532
+ }
533
+ lines.push('');
534
+ }
535
+
536
+ return lines.join('\n');
537
+ }
538
+
539
+ /**
540
+ * Get server info for MCP protocol
541
+ */
542
+ getServerInfo(): {
543
+ name: string;
544
+ version: string;
545
+ description: string;
546
+ } {
547
+ return {
548
+ name: 'atlas-playbook-server',
549
+ version: '1.0.0',
550
+ description:
551
+ 'MCP server providing access to the Atlas playbook library for on-demand guidance retrieval',
552
+ };
553
+ }
554
+ }
555
+
556
+ /**
557
+ * Create an MCP playbook server
558
+ */
559
+ export function createPlaybookMCPServer(
560
+ playbooks: PlaybookLibrary,
561
+ skillLibrary?: SkillLibrary,
562
+ config?: Partial<MCPServerConfig>
563
+ ): PlaybookMCPServer {
564
+ return new PlaybookMCPServer(playbooks, skillLibrary, config);
565
+ }
@@ -0,0 +1,160 @@
1
+ /**
2
+ * Curated Playbook Loader
3
+ *
4
+ * Loads playbooks from JSON files on disk and manages them separately
5
+ * from runtime-extracted playbooks. Supports a --recreate workflow:
6
+ * drop all curated playbooks and reload from source files without
7
+ * losing extracted or imported playbooks.
8
+ *
9
+ * Inspired by Dash's separation of curated knowledge (file-loaded)
10
+ * vs learnings (runtime-discovered).
11
+ */
12
+
13
+ import { readFile, readdir, stat } from 'node:fs/promises';
14
+ import { join, relative } from 'node:path';
15
+ import { existsSync } from 'node:fs';
16
+ import type { PlaybookProvenance } from '../types/index.js';
17
+ import { createPlaybook } from '../types/index.js';
18
+ import type { PlaybookLibrary } from './playbook.js';
19
+
20
+ /**
21
+ * Schema for a curated playbook JSON file
22
+ */
23
+ export interface CuratedPlaybookFile {
24
+ name: string;
25
+ applicability: {
26
+ situations: string[];
27
+ triggers?: string[];
28
+ antiPatterns?: string[];
29
+ domains: string[];
30
+ };
31
+ guidance: {
32
+ strategy: string;
33
+ tactics: string[];
34
+ steps?: string[];
35
+ codeExample?: string;
36
+ };
37
+ verification?: {
38
+ successIndicators?: string[];
39
+ failureIndicators?: string[];
40
+ rollbackStrategy?: string;
41
+ };
42
+ confidence?: number;
43
+ complexity?: 'simple' | 'moderate' | 'complex';
44
+ estimatedEffort?: number;
45
+ curatedBy?: string;
46
+ }
47
+
48
+ /**
49
+ * Result of a curated playbook load operation
50
+ */
51
+ export interface CuratedLoadResult {
52
+ loaded: number;
53
+ skipped: number;
54
+ errors: Array<{ file: string; error: string }>;
55
+ recreated: boolean;
56
+ }
57
+
58
+ /**
59
+ * Load curated playbooks from a directory of JSON files into the library.
60
+ *
61
+ * @param curatedDir - Directory containing curated playbook JSON files
62
+ * @param library - PlaybookLibrary to load into
63
+ * @param options.recreate - If true, delete existing curated playbooks before loading
64
+ */
65
+ export async function loadCuratedPlaybooks(
66
+ curatedDir: string,
67
+ library: PlaybookLibrary,
68
+ options?: { recreate?: boolean }
69
+ ): Promise<CuratedLoadResult> {
70
+ const result: CuratedLoadResult = {
71
+ loaded: 0,
72
+ skipped: 0,
73
+ errors: [],
74
+ recreated: false,
75
+ };
76
+
77
+ if (!existsSync(curatedDir)) {
78
+ return result;
79
+ }
80
+
81
+ // Recreate: drop all curated playbooks first
82
+ if (options?.recreate) {
83
+ await library.deleteByOrigin('curated');
84
+ result.recreated = true;
85
+ }
86
+
87
+ // Find all JSON files in the directory (non-recursive)
88
+ const files = await readdir(curatedDir);
89
+ const jsonFiles = files.filter((f) => f.endsWith('.json'));
90
+
91
+ for (const file of jsonFiles) {
92
+ const filePath = join(curatedDir, file);
93
+ const fileStat = await stat(filePath);
94
+ if (!fileStat.isFile()) continue;
95
+
96
+ try {
97
+ const content = await readFile(filePath, 'utf-8');
98
+ const parsed = JSON.parse(content) as CuratedPlaybookFile;
99
+
100
+ // Validate required fields
101
+ if (!parsed.name || !parsed.applicability || !parsed.guidance) {
102
+ result.errors.push({
103
+ file,
104
+ error: 'Missing required fields: name, applicability, guidance',
105
+ });
106
+ continue;
107
+ }
108
+
109
+ // Check if this curated playbook already exists (by name)
110
+ const existing = await library.getByName(parsed.name);
111
+ if (existing && !options?.recreate) {
112
+ result.skipped++;
113
+ continue;
114
+ }
115
+
116
+ const relativePath = relative(process.cwd(), filePath);
117
+ const provenance: PlaybookProvenance = {
118
+ origin: 'curated',
119
+ sourceFile: relativePath,
120
+ curatedBy: parsed.curatedBy,
121
+ recordedAt: new Date(),
122
+ };
123
+
124
+ const playbook = createPlaybook({
125
+ name: parsed.name,
126
+ applicability: {
127
+ situations: parsed.applicability.situations,
128
+ triggers: parsed.applicability.triggers ?? [],
129
+ antiPatterns: parsed.applicability.antiPatterns ?? [],
130
+ domains: parsed.applicability.domains,
131
+ },
132
+ guidance: {
133
+ strategy: parsed.guidance.strategy,
134
+ tactics: parsed.guidance.tactics,
135
+ steps: parsed.guidance.steps,
136
+ codeExample: parsed.guidance.codeExample,
137
+ },
138
+ verification: {
139
+ successIndicators: parsed.verification?.successIndicators ?? [],
140
+ failureIndicators: parsed.verification?.failureIndicators ?? [],
141
+ rollbackStrategy: parsed.verification?.rollbackStrategy,
142
+ },
143
+ provenance,
144
+ confidence: parsed.confidence ?? 0.7, // Curated starts higher than extracted (0.3)
145
+ complexity: parsed.complexity ?? 'moderate',
146
+ estimatedEffort: parsed.estimatedEffort ?? 3,
147
+ });
148
+
149
+ await library.add(playbook);
150
+ result.loaded++;
151
+ } catch (error) {
152
+ result.errors.push({
153
+ file,
154
+ error: error instanceof Error ? error.message : String(error),
155
+ });
156
+ }
157
+ }
158
+
159
+ return result;
160
+ }