cognitive-core 0.0.1 → 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 +363 -2
  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 +43 -0
  48. package/dist/index.d.ts.map +1 -0
  49. package/dist/index.js +84 -0
  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 +61 -9
  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/index.d.ts +0 -4
  329. package/index.js +0 -4
@@ -0,0 +1,378 @@
1
+ /**
2
+ * ACP Backend using acp-factory
3
+ *
4
+ * This backend uses the acp-factory package to spawn and manage ACP-compatible
5
+ * agents like Claude Code, providing a clean interface for Atlas integration.
6
+ */
7
+ import {
8
+ AgentFactory,
9
+ AgentHandle,
10
+ Session,
11
+ type AgentConfig,
12
+ type SpawnOptions,
13
+ type ExtendedSessionUpdate,
14
+ } from 'acp-factory';
15
+ import type {
16
+ AgentBackend,
17
+ AgentSpawnConfig,
18
+ AgentSession,
19
+ AgentMessage,
20
+ ToolCall,
21
+ } from '../types.js';
22
+
23
+ /**
24
+ * ACP agent configuration
25
+ */
26
+ export interface ACPAgentConfig extends AgentConfig {
27
+ /** Display name for the agent */
28
+ displayName?: string;
29
+ }
30
+
31
+ /**
32
+ * Active ACP session state
33
+ */
34
+ interface ACPSessionState {
35
+ atlasSession: AgentSession;
36
+ agentHandle: AgentHandle;
37
+ acpSession: Session;
38
+ }
39
+
40
+ /**
41
+ * ACP Backend
42
+ * Uses acp-factory to spawn and manage ACP-compatible agents
43
+ */
44
+ export class ACPBackend implements AgentBackend {
45
+ readonly name = 'acp';
46
+ readonly supportedTypes: string[];
47
+
48
+ private sessions: Map<string, ACPSessionState> = new Map();
49
+ private handles: Map<string, AgentHandle> = new Map();
50
+
51
+ constructor(configs: Record<string, ACPAgentConfig>) {
52
+ this.supportedTypes = Object.keys(configs);
53
+
54
+ // Register all agent configs with AgentFactory
55
+ for (const [name, config] of Object.entries(configs)) {
56
+ AgentFactory.register(name, {
57
+ command: config.command,
58
+ args: config.args,
59
+ env: config.env,
60
+ });
61
+ }
62
+ }
63
+
64
+ async isAvailable(): Promise<boolean> {
65
+ return this.supportedTypes.length > 0;
66
+ }
67
+
68
+ async spawn(config: AgentSpawnConfig): Promise<AgentSession> {
69
+ const atlasSessionId = crypto.randomUUID();
70
+
71
+ // Create Atlas session tracking
72
+ const atlasSession: AgentSession = {
73
+ id: atlasSessionId,
74
+ agentType: config.agentType,
75
+ task: config.task,
76
+ state: 'running',
77
+ messages: [],
78
+ toolCalls: [],
79
+ startTime: new Date(),
80
+ metadata: {
81
+ injectedKnowledge: !!config.injectedKnowledge,
82
+ },
83
+ };
84
+
85
+ try {
86
+ // Spawn the agent
87
+ const spawnOptions: SpawnOptions = {
88
+ permissionMode: 'auto-approve', // Auto-approve for automated learning
89
+ env: config.env,
90
+ };
91
+
92
+ const agentHandle = await AgentFactory.spawn(config.agentType, spawnOptions);
93
+ this.handles.set(atlasSessionId, agentHandle);
94
+
95
+ // Store capabilities
96
+ atlasSession.metadata.capabilities = agentHandle.capabilities;
97
+
98
+ // Create a session with the agent
99
+ const cwd = config.cwd ?? process.cwd();
100
+ const acpSession = await agentHandle.createSession(cwd);
101
+
102
+ // Store session state
103
+ const state: ACPSessionState = {
104
+ atlasSession,
105
+ agentHandle,
106
+ acpSession,
107
+ };
108
+ this.sessions.set(atlasSessionId, state);
109
+
110
+ // Build prompt content with knowledge injection
111
+ let promptContent = config.task.description;
112
+ if (config.systemPromptAdditions) {
113
+ promptContent = `## Context from Atlas Memory\n\n${config.systemPromptAdditions}\n\n---\n\n${promptContent}`;
114
+ }
115
+ if (Object.keys(config.task.context).length > 0) {
116
+ promptContent += `\n\n## Additional Context\n\`\`\`json\n${JSON.stringify(config.task.context, null, 2)}\n\`\`\``;
117
+ }
118
+
119
+ // Send prompt and collect updates
120
+ await this.runPrompt(state, promptContent, config);
121
+
122
+ return atlasSession;
123
+ } catch (error) {
124
+ atlasSession.state = 'failed';
125
+ atlasSession.error = error instanceof Error ? error.message : 'Unknown error';
126
+ atlasSession.endTime = new Date();
127
+ console.error(
128
+ `[ACPBackend] Session ${atlasSessionId} spawn failed:`,
129
+ error instanceof Error ? error.message : String(error)
130
+ );
131
+ return atlasSession;
132
+ }
133
+ }
134
+
135
+ /**
136
+ * Run a prompt and collect all updates
137
+ */
138
+ private async runPrompt(
139
+ state: ACPSessionState,
140
+ promptContent: string,
141
+ config: AgentSpawnConfig
142
+ ): Promise<void> {
143
+ const { atlasSession, acpSession } = state;
144
+
145
+ try {
146
+ // Stream updates from the agent
147
+ for await (const update of acpSession.prompt(promptContent)) {
148
+ this.processUpdate(atlasSession, update, config);
149
+ }
150
+
151
+ // Mark as completed
152
+ atlasSession.state = 'completed';
153
+ atlasSession.endTime = new Date();
154
+ } catch (error) {
155
+ atlasSession.state = 'failed';
156
+ atlasSession.error = error instanceof Error ? error.message : 'Unknown error';
157
+ atlasSession.endTime = new Date();
158
+ console.error(
159
+ `[ACPBackend] Session ${atlasSession.id} prompt execution failed:`,
160
+ error instanceof Error ? error.message : String(error)
161
+ );
162
+ }
163
+ }
164
+
165
+ /**
166
+ * Process a session update from the agent
167
+ * Uses defensive typing since ACP types can vary
168
+ */
169
+ private processUpdate(
170
+ session: AgentSession,
171
+ update: ExtendedSessionUpdate,
172
+ config: AgentSpawnConfig
173
+ ): void {
174
+ // Cast to any for flexible property access since ACP types are complex unions
175
+ const u = update as Record<string, unknown>;
176
+ const updateType = u.sessionUpdate as string;
177
+
178
+ switch (updateType) {
179
+ case 'agent_message_chunk':
180
+ case 'user_message_chunk':
181
+ case 'agent_thought_chunk': {
182
+ // ContentChunk has a single 'content' field (ContentBlock)
183
+ const content = u.content as Record<string, unknown> | undefined;
184
+ if (content && content.type === 'text' && typeof content.text === 'string') {
185
+ const message: AgentMessage = {
186
+ role: updateType === 'user_message_chunk' ? 'user' : 'assistant',
187
+ content: content.text,
188
+ timestamp: new Date(),
189
+ };
190
+ session.messages.push(message);
191
+ config.onMessage?.(message);
192
+ }
193
+ break;
194
+ }
195
+
196
+ case 'tool_call': {
197
+ // ToolCall has toolCallId, title, rawInput, status, content, etc.
198
+ const toolCallId = (u.toolCallId as string) ?? crypto.randomUUID();
199
+ const title = (u.title as string) ?? 'unknown';
200
+ const rawInput = u.rawInput;
201
+
202
+ const toolCall: ToolCall = {
203
+ id: toolCallId,
204
+ name: title,
205
+ input: rawInput,
206
+ startTime: new Date(),
207
+ };
208
+ session.toolCalls.push(toolCall);
209
+ config.onToolCall?.(toolCall);
210
+ break;
211
+ }
212
+
213
+ case 'tool_call_update': {
214
+ // ToolCallUpdate has toolCallId, status, content, etc.
215
+ const toolCallId = u.toolCallId as string;
216
+ const status = u.status as string | undefined;
217
+ const content = u.content as Array<Record<string, unknown>> | undefined;
218
+
219
+ const existingTc = session.toolCalls.find((t) => t.id === toolCallId);
220
+ if (existingTc) {
221
+ if (status === 'completed' || status === 'failed') {
222
+ existingTc.endTime = new Date();
223
+ }
224
+ if (content && Array.isArray(content)) {
225
+ // Extract text from content blocks
226
+ const outputs: string[] = [];
227
+ for (const block of content) {
228
+ if (block.type === 'text' && typeof block.text === 'string') {
229
+ outputs.push(block.text);
230
+ } else if (block.type === 'diff' && typeof block.diff === 'string') {
231
+ outputs.push(block.diff);
232
+ }
233
+ }
234
+ if (outputs.length > 0) {
235
+ existingTc.output = outputs.join('\n');
236
+ }
237
+ }
238
+ if (status === 'failed') {
239
+ existingTc.error = 'Tool call failed';
240
+ }
241
+ }
242
+ break;
243
+ }
244
+
245
+ case 'permission_request': {
246
+ // In auto-approve mode, this shouldn't happen, but log it
247
+ session.messages.push({
248
+ role: 'system',
249
+ content: `Permission requested: ${JSON.stringify(update)}`,
250
+ timestamp: new Date(),
251
+ });
252
+ break;
253
+ }
254
+
255
+ case 'plan': {
256
+ // Agent shared its plan
257
+ const plan = u.plan;
258
+ session.messages.push({
259
+ role: 'assistant',
260
+ content: `[Plan] ${JSON.stringify(plan)}`,
261
+ timestamp: new Date(),
262
+ });
263
+ break;
264
+ }
265
+
266
+ default:
267
+ // Log other updates for debugging
268
+ session.metadata.lastUpdate = update;
269
+ }
270
+ }
271
+
272
+ async getSession(sessionId: string): Promise<AgentSession | undefined> {
273
+ return this.sessions.get(sessionId)?.atlasSession;
274
+ }
275
+
276
+ async sendMessage(sessionId: string, message: string): Promise<void> {
277
+ const state = this.sessions.get(sessionId);
278
+ if (!state) {
279
+ throw new Error('Session not found');
280
+ }
281
+
282
+ // Send additional prompt
283
+ for await (const update of state.acpSession.prompt(message)) {
284
+ this.processUpdate(state.atlasSession, update, {
285
+ agentType: state.atlasSession.agentType,
286
+ task: state.atlasSession.task,
287
+ });
288
+ }
289
+ }
290
+
291
+ async terminate(sessionId: string): Promise<void> {
292
+ const state = this.sessions.get(sessionId);
293
+ if (!state) return;
294
+
295
+ try {
296
+ // Cancel any running prompt
297
+ await state.acpSession.cancel();
298
+ } catch (error) {
299
+ // Log cancellation errors but don't throw
300
+ console.error(
301
+ `[ACPBackend] Session ${sessionId} cancel error:`,
302
+ error instanceof Error ? error.message : String(error)
303
+ );
304
+ }
305
+
306
+ try {
307
+ // Close the agent handle
308
+ await state.agentHandle.close();
309
+ } catch (error) {
310
+ // Log close errors but don't throw
311
+ console.error(
312
+ `[ACPBackend] Session ${sessionId} close error:`,
313
+ error instanceof Error ? error.message : String(error)
314
+ );
315
+ }
316
+
317
+ state.atlasSession.state = 'failed';
318
+ state.atlasSession.error = 'Terminated';
319
+ state.atlasSession.endTime = new Date();
320
+
321
+ this.sessions.delete(sessionId);
322
+ this.handles.delete(sessionId);
323
+ }
324
+
325
+ async listSessions(): Promise<AgentSession[]> {
326
+ return Array.from(this.sessions.values()).map((s) => s.atlasSession);
327
+ }
328
+
329
+ /**
330
+ * Get a raw ACP session for advanced usage
331
+ */
332
+ getACPSession(sessionId: string): Session | undefined {
333
+ return this.sessions.get(sessionId)?.acpSession;
334
+ }
335
+
336
+ /**
337
+ * Get a raw agent handle for advanced usage
338
+ */
339
+ getAgentHandle(sessionId: string): AgentHandle | undefined {
340
+ return this.sessions.get(sessionId)?.agentHandle;
341
+ }
342
+ }
343
+
344
+ /**
345
+ * Create an ACP backend with agent configurations
346
+ */
347
+ export function createACPBackend(
348
+ configs: Record<string, ACPAgentConfig>
349
+ ): ACPBackend {
350
+ return new ACPBackend(configs);
351
+ }
352
+
353
+ /**
354
+ * Pre-configured Claude Code agent via claude-code-acp
355
+ */
356
+ export const claudeCodeACPConfig: ACPAgentConfig = {
357
+ command: 'npx',
358
+ args: ['claude-code-acp'],
359
+ displayName: 'Claude Code (ACP)',
360
+ };
361
+
362
+ /**
363
+ * Pre-configured Claude direct (requires --print mode)
364
+ * Note: This may not support full ACP protocol
365
+ */
366
+ export const claudeCodeDirectConfig: ACPAgentConfig = {
367
+ command: 'claude',
368
+ args: ['--print'],
369
+ displayName: 'Claude (Direct)',
370
+ };
371
+
372
+ /**
373
+ * Helper to register common agents
374
+ */
375
+ export function registerCommonAgents(): void {
376
+ AgentFactory.register('claude-code', claudeCodeACPConfig);
377
+ AgentFactory.register('claude-code-acp', claudeCodeACPConfig);
378
+ }
@@ -0,0 +1,24 @@
1
+ export {
2
+ SubprocessBackend,
3
+ createSubprocessBackend,
4
+ claudeCodeConfig,
5
+ type SubprocessAgentConfig,
6
+ } from './subprocess.js';
7
+
8
+ export {
9
+ MockBackend,
10
+ createMockBackend,
11
+ type MockAgentBehavior,
12
+ } from './mock.js';
13
+
14
+ export {
15
+ ACPBackend,
16
+ createACPBackend,
17
+ claudeCodeACPConfig,
18
+ claudeCodeDirectConfig,
19
+ registerCommonAgents,
20
+ type ACPAgentConfig,
21
+ } from './acp.js';
22
+
23
+ // Re-export useful types from acp-factory
24
+ export { AgentFactory } from 'acp-factory';
@@ -0,0 +1,218 @@
1
+ import type {
2
+ AgentBackend,
3
+ AgentSpawnConfig,
4
+ AgentSession,
5
+ AgentMessage,
6
+ ToolCall,
7
+ } from '../types.js';
8
+
9
+ /**
10
+ * Mock agent behavior definition
11
+ */
12
+ export interface MockAgentBehavior {
13
+ /** Simulated tool calls */
14
+ toolCalls?: Array<{
15
+ name: string;
16
+ input: unknown;
17
+ output: unknown;
18
+ delayMs?: number;
19
+ }>;
20
+ /** Messages to emit */
21
+ messages?: Array<{
22
+ role: 'assistant' | 'user';
23
+ content: string;
24
+ delayMs?: number;
25
+ }>;
26
+ /** Final result */
27
+ result?: unknown;
28
+ /** Should the agent succeed? */
29
+ success?: boolean;
30
+ /** Error message if failing */
31
+ error?: string;
32
+ /** Total duration in ms */
33
+ durationMs?: number;
34
+ }
35
+
36
+ /**
37
+ * Mock backend for testing
38
+ */
39
+ export class MockBackend implements AgentBackend {
40
+ readonly name = 'mock';
41
+ readonly supportedTypes = ['mock', 'test'];
42
+
43
+ private sessions: Map<string, AgentSession> = new Map();
44
+ private behaviors: Map<string, MockAgentBehavior> = new Map();
45
+ private defaultBehavior: MockAgentBehavior;
46
+
47
+ constructor(defaultBehavior?: MockAgentBehavior) {
48
+ this.defaultBehavior = defaultBehavior ?? {
49
+ success: true,
50
+ result: 'Mock result',
51
+ durationMs: 100,
52
+ };
53
+ }
54
+
55
+ /**
56
+ * Set behavior for a specific task description
57
+ */
58
+ setBehavior(taskDescription: string, behavior: MockAgentBehavior): void {
59
+ this.behaviors.set(taskDescription, behavior);
60
+ }
61
+
62
+ /**
63
+ * Set default behavior for all tasks
64
+ */
65
+ setDefaultBehavior(behavior: MockAgentBehavior): void {
66
+ this.defaultBehavior = behavior;
67
+ }
68
+
69
+ async isAvailable(): Promise<boolean> {
70
+ return true;
71
+ }
72
+
73
+ async spawn(config: AgentSpawnConfig): Promise<AgentSession> {
74
+ const sessionId = crypto.randomUUID();
75
+ const behavior =
76
+ this.behaviors.get(config.task.description) ?? this.defaultBehavior;
77
+
78
+ const session: AgentSession = {
79
+ id: sessionId,
80
+ agentType: config.agentType,
81
+ task: config.task,
82
+ state: 'running',
83
+ messages: [],
84
+ toolCalls: [],
85
+ startTime: new Date(),
86
+ metadata: {
87
+ injectedKnowledge: !!config.injectedKnowledge,
88
+ hasSystemPromptAdditions: !!config.systemPromptAdditions,
89
+ },
90
+ };
91
+
92
+ this.sessions.set(sessionId, session);
93
+
94
+ // Simulate execution asynchronously
95
+ this.simulateExecution(session, behavior, config).catch((error) => {
96
+ session.state = 'failed';
97
+ session.error = error.message;
98
+ session.endTime = new Date();
99
+ });
100
+
101
+ return session;
102
+ }
103
+
104
+ private async simulateExecution(
105
+ session: AgentSession,
106
+ behavior: MockAgentBehavior,
107
+ config: AgentSpawnConfig
108
+ ): Promise<void> {
109
+ const startTime = Date.now();
110
+
111
+ // Emit messages
112
+ if (behavior.messages) {
113
+ for (const msg of behavior.messages) {
114
+ if (msg.delayMs) {
115
+ await this.delay(msg.delayMs);
116
+ }
117
+
118
+ const message: AgentMessage = {
119
+ role: msg.role,
120
+ content: msg.content,
121
+ timestamp: new Date(),
122
+ };
123
+ session.messages.push(message);
124
+ config.onMessage?.(message);
125
+ }
126
+ }
127
+
128
+ // Emit tool calls
129
+ if (behavior.toolCalls) {
130
+ for (const tc of behavior.toolCalls) {
131
+ if (tc.delayMs) {
132
+ await this.delay(tc.delayMs);
133
+ }
134
+
135
+ const toolCall: ToolCall = {
136
+ id: crypto.randomUUID(),
137
+ name: tc.name,
138
+ input: tc.input,
139
+ output: tc.output,
140
+ startTime: new Date(),
141
+ endTime: new Date(),
142
+ };
143
+ session.toolCalls.push(toolCall);
144
+ config.onToolCall?.(toolCall);
145
+ }
146
+ }
147
+
148
+ // Wait for remaining duration
149
+ const elapsed = Date.now() - startTime;
150
+ const remaining = (behavior.durationMs ?? 100) - elapsed;
151
+ if (remaining > 0) {
152
+ await this.delay(remaining);
153
+ }
154
+
155
+ // Complete
156
+ session.endTime = new Date();
157
+ if (behavior.success ?? true) {
158
+ session.state = 'completed';
159
+ session.result = behavior.result;
160
+ } else {
161
+ session.state = 'failed';
162
+ session.error = behavior.error ?? 'Mock failure';
163
+ }
164
+ }
165
+
166
+ private delay(ms: number): Promise<void> {
167
+ return new Promise((resolve) => setTimeout(resolve, ms));
168
+ }
169
+
170
+ async getSession(sessionId: string): Promise<AgentSession | undefined> {
171
+ return this.sessions.get(sessionId);
172
+ }
173
+
174
+ async sendMessage(sessionId: string, _message: string): Promise<void> {
175
+ const session = this.sessions.get(sessionId);
176
+ if (!session) {
177
+ throw new Error('Session not found');
178
+ }
179
+ // Mock doesn't process additional messages
180
+ }
181
+
182
+ async terminate(sessionId: string): Promise<void> {
183
+ const session = this.sessions.get(sessionId);
184
+ if (!session) return;
185
+
186
+ session.state = 'failed';
187
+ session.error = 'Terminated';
188
+ session.endTime = new Date();
189
+ }
190
+
191
+ async listSessions(): Promise<AgentSession[]> {
192
+ return Array.from(this.sessions.values());
193
+ }
194
+
195
+ /**
196
+ * Get all sessions (for testing assertions)
197
+ */
198
+ getAllSessions(): AgentSession[] {
199
+ return Array.from(this.sessions.values());
200
+ }
201
+
202
+ /**
203
+ * Clear all sessions
204
+ */
205
+ clear(): void {
206
+ this.sessions.clear();
207
+ this.behaviors.clear();
208
+ }
209
+ }
210
+
211
+ /**
212
+ * Create a mock backend
213
+ */
214
+ export function createMockBackend(
215
+ defaultBehavior?: MockAgentBehavior
216
+ ): MockBackend {
217
+ return new MockBackend(defaultBehavior);
218
+ }