@deimoscloud/coreai 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 (216) hide show
  1. package/.prettierrc +9 -0
  2. package/AGENT_SPEC.md +347 -0
  3. package/ARCHITECTURE.md +547 -0
  4. package/DRAFT_PRD.md +1440 -0
  5. package/IMPLEMENTATION_PLAN.md +256 -0
  6. package/PRODUCT.md +473 -0
  7. package/README.md +303 -0
  8. package/WORKFLOWS.md +295 -0
  9. package/agents/_templates/ic-engineer.md +185 -0
  10. package/agents/_templates/reviewer.md +182 -0
  11. package/agents/backend-engineer.yaml +72 -0
  12. package/agents/devops-engineer.yaml +72 -0
  13. package/agents/engineering-manager.yaml +70 -0
  14. package/agents/examples/android-engineer.md +302 -0
  15. package/agents/examples/backend-engineer.md +320 -0
  16. package/agents/examples/devops-engineer.md +742 -0
  17. package/agents/examples/engineering-manager.md +469 -0
  18. package/agents/examples/frontend-engineer.md +58 -0
  19. package/agents/examples/product-manager.md +315 -0
  20. package/agents/examples/qa-engineer.md +371 -0
  21. package/agents/examples/security-engineer.md +525 -0
  22. package/agents/examples/solutions-architect.md +351 -0
  23. package/agents/examples/wearos-engineer.md +359 -0
  24. package/agents/frontend-engineer.yaml +72 -0
  25. package/commands/core/check-inbox.md +34 -0
  26. package/commands/core/delegate.md +30 -0
  27. package/commands/core/git-commit.md +144 -0
  28. package/commands/core/pr-create.md +193 -0
  29. package/commands/core/review.md +56 -0
  30. package/commands/core/sprint-status.md +65 -0
  31. package/commands/optional/docs-update.md +200 -0
  32. package/commands/optional/jira-create.md +200 -0
  33. package/commands/optional/jira-transition.md +184 -0
  34. package/commands/optional/worktree-cleanup.md +167 -0
  35. package/commands/optional/worktree-setup.md +110 -0
  36. package/dist/cli/index.js +4037 -0
  37. package/dist/cli/index.js.map +1 -0
  38. package/dist/index.d.ts +2978 -0
  39. package/dist/index.js +3867 -0
  40. package/dist/index.js.map +1 -0
  41. package/eslint.config.js +29 -0
  42. package/jest.config.js +22 -0
  43. package/knowledge-library/README.md +118 -0
  44. package/knowledge-library/android-engineer/context/current.txt +42 -0
  45. package/knowledge-library/android-engineer/control/decisions.txt +9 -0
  46. package/knowledge-library/android-engineer/control/dependencies.txt +19 -0
  47. package/knowledge-library/android-engineer/control/objectives.txt +26 -0
  48. package/knowledge-library/android-engineer/history/.gitkeep +0 -0
  49. package/knowledge-library/android-engineer/inbox/processed/.gitkeep +0 -0
  50. package/knowledge-library/android-engineer/outbox/.gitkeep +0 -0
  51. package/knowledge-library/android-engineer/tech/.gitkeep +0 -0
  52. package/knowledge-library/architecture.txt +61 -0
  53. package/knowledge-library/backend-engineer/context/current.txt +42 -0
  54. package/knowledge-library/backend-engineer/control/decisions.txt +9 -0
  55. package/knowledge-library/backend-engineer/control/dependencies.txt +19 -0
  56. package/knowledge-library/backend-engineer/control/objectives.txt +26 -0
  57. package/knowledge-library/backend-engineer/history/.gitkeep +0 -0
  58. package/knowledge-library/backend-engineer/inbox/processed/.gitkeep +0 -0
  59. package/knowledge-library/backend-engineer/outbox/.gitkeep +0 -0
  60. package/knowledge-library/backend-engineer/tech/.gitkeep +0 -0
  61. package/knowledge-library/context.txt +52 -0
  62. package/knowledge-library/devops-engineer/context/current.txt +42 -0
  63. package/knowledge-library/devops-engineer/control/decisions.txt +9 -0
  64. package/knowledge-library/devops-engineer/control/dependencies.txt +19 -0
  65. package/knowledge-library/devops-engineer/control/objectives.txt +26 -0
  66. package/knowledge-library/devops-engineer/history/.gitkeep +0 -0
  67. package/knowledge-library/devops-engineer/inbox/processed/.gitkeep +0 -0
  68. package/knowledge-library/devops-engineer/outbox/.gitkeep +0 -0
  69. package/knowledge-library/devops-engineer/tech/.gitkeep +0 -0
  70. package/knowledge-library/engineering-manager/context/current.txt +40 -0
  71. package/knowledge-library/engineering-manager/control/decisions.txt +9 -0
  72. package/knowledge-library/engineering-manager/control/objectives.txt +27 -0
  73. package/knowledge-library/engineering-manager/history/.gitkeep +0 -0
  74. package/knowledge-library/engineering-manager/inbox/processed/.gitkeep +0 -0
  75. package/knowledge-library/engineering-manager/outbox/.gitkeep +0 -0
  76. package/knowledge-library/engineering-manager/tech/.gitkeep +0 -0
  77. package/knowledge-library/prd.txt +81 -0
  78. package/knowledge-library/product-manager/context/current.txt +42 -0
  79. package/knowledge-library/product-manager/control/decisions.txt +9 -0
  80. package/knowledge-library/product-manager/control/dependencies.txt +19 -0
  81. package/knowledge-library/product-manager/control/objectives.txt +26 -0
  82. package/knowledge-library/product-manager/history/.gitkeep +0 -0
  83. package/knowledge-library/product-manager/inbox/processed/.gitkeep +0 -0
  84. package/knowledge-library/product-manager/outbox/.gitkeep +0 -0
  85. package/knowledge-library/product-manager/tech/.gitkeep +0 -0
  86. package/knowledge-library/qa-engineer/context/current.txt +42 -0
  87. package/knowledge-library/qa-engineer/control/decisions.txt +9 -0
  88. package/knowledge-library/qa-engineer/control/dependencies.txt +19 -0
  89. package/knowledge-library/qa-engineer/control/objectives.txt +26 -0
  90. package/knowledge-library/qa-engineer/history/.gitkeep +0 -0
  91. package/knowledge-library/qa-engineer/inbox/processed/.gitkeep +0 -0
  92. package/knowledge-library/qa-engineer/outbox/.gitkeep +0 -0
  93. package/knowledge-library/qa-engineer/tech/.gitkeep +0 -0
  94. package/knowledge-library/security-engineer/context/current.txt +42 -0
  95. package/knowledge-library/security-engineer/control/decisions.txt +9 -0
  96. package/knowledge-library/security-engineer/control/dependencies.txt +19 -0
  97. package/knowledge-library/security-engineer/control/objectives.txt +26 -0
  98. package/knowledge-library/security-engineer/history/.gitkeep +0 -0
  99. package/knowledge-library/security-engineer/inbox/processed/.gitkeep +0 -0
  100. package/knowledge-library/security-engineer/outbox/.gitkeep +0 -0
  101. package/knowledge-library/security-engineer/tech/.gitkeep +0 -0
  102. package/knowledge-library/solutions-architect/context/current.txt +42 -0
  103. package/knowledge-library/solutions-architect/control/decisions.txt +9 -0
  104. package/knowledge-library/solutions-architect/control/dependencies.txt +19 -0
  105. package/knowledge-library/solutions-architect/control/objectives.txt +26 -0
  106. package/knowledge-library/solutions-architect/history/.gitkeep +0 -0
  107. package/knowledge-library/solutions-architect/inbox/processed/.gitkeep +0 -0
  108. package/knowledge-library/solutions-architect/outbox/.gitkeep +0 -0
  109. package/knowledge-library/solutions-architect/tech/.gitkeep +0 -0
  110. package/knowledge-library/wearos-engineer/context/current.txt +42 -0
  111. package/knowledge-library/wearos-engineer/control/decisions.txt +9 -0
  112. package/knowledge-library/wearos-engineer/control/dependencies.txt +19 -0
  113. package/knowledge-library/wearos-engineer/control/objectives.txt +26 -0
  114. package/knowledge-library/wearos-engineer/history/.gitkeep +0 -0
  115. package/knowledge-library/wearos-engineer/inbox/processed/.gitkeep +0 -0
  116. package/knowledge-library/wearos-engineer/outbox/.gitkeep +0 -0
  117. package/knowledge-library/wearos-engineer/tech/.gitkeep +0 -0
  118. package/package.json +66 -0
  119. package/schemas/agent.schema.json +171 -0
  120. package/schemas/coreai.config.schema.json +257 -0
  121. package/scripts/add-agent.sh +323 -0
  122. package/scripts/install.sh +354 -0
  123. package/src/adapters/factory.test.ts +386 -0
  124. package/src/adapters/factory.ts +305 -0
  125. package/src/adapters/index.ts +113 -0
  126. package/src/adapters/interfaces.ts +268 -0
  127. package/src/adapters/mcp/client.test.ts +130 -0
  128. package/src/adapters/mcp/client.ts +451 -0
  129. package/src/adapters/mcp/discovery.test.ts +315 -0
  130. package/src/adapters/mcp/discovery.ts +340 -0
  131. package/src/adapters/mcp/index.ts +66 -0
  132. package/src/adapters/mcp/mapper.test.ts +218 -0
  133. package/src/adapters/mcp/mapper.ts +536 -0
  134. package/src/adapters/mcp/registry.test.ts +433 -0
  135. package/src/adapters/mcp/registry.ts +550 -0
  136. package/src/adapters/mcp/types.ts +258 -0
  137. package/src/adapters/native/filesystem.test.ts +350 -0
  138. package/src/adapters/native/filesystem.ts +393 -0
  139. package/src/adapters/native/github.test.ts +173 -0
  140. package/src/adapters/native/github.ts +627 -0
  141. package/src/adapters/native/index.ts +22 -0
  142. package/src/adapters/native/selector.test.ts +224 -0
  143. package/src/adapters/native/selector.ts +150 -0
  144. package/src/adapters/types.ts +270 -0
  145. package/src/agents/compiler.test.ts +399 -0
  146. package/src/agents/compiler.ts +359 -0
  147. package/src/agents/index.ts +36 -0
  148. package/src/agents/loader.test.ts +319 -0
  149. package/src/agents/loader.ts +143 -0
  150. package/src/agents/resolver.test.ts +282 -0
  151. package/src/agents/resolver.ts +262 -0
  152. package/src/agents/types.ts +87 -0
  153. package/src/cache/index.ts +38 -0
  154. package/src/cache/interfaces.ts +283 -0
  155. package/src/cache/manager.test.ts +266 -0
  156. package/src/cache/manager.ts +388 -0
  157. package/src/cache/provider.test.ts +485 -0
  158. package/src/cache/provider.ts +745 -0
  159. package/src/cache/types.test.ts +192 -0
  160. package/src/cache/types.ts +313 -0
  161. package/src/cli/commands/build.test.ts +248 -0
  162. package/src/cli/commands/build.ts +244 -0
  163. package/src/cli/commands/cache.test.ts +221 -0
  164. package/src/cli/commands/cache.ts +229 -0
  165. package/src/cli/commands/index.ts +63 -0
  166. package/src/cli/commands/init.test.ts +173 -0
  167. package/src/cli/commands/init.ts +296 -0
  168. package/src/cli/commands/skills.test.ts +272 -0
  169. package/src/cli/commands/skills.ts +348 -0
  170. package/src/cli/commands/status.test.ts +392 -0
  171. package/src/cli/commands/status.ts +332 -0
  172. package/src/cli/commands/sync.test.ts +213 -0
  173. package/src/cli/commands/sync.ts +251 -0
  174. package/src/cli/commands/validate.test.ts +216 -0
  175. package/src/cli/commands/validate.ts +340 -0
  176. package/src/cli/index.test.ts +190 -0
  177. package/src/cli/index.ts +493 -0
  178. package/src/commands/context.test.ts +163 -0
  179. package/src/commands/context.ts +111 -0
  180. package/src/commands/index.ts +56 -0
  181. package/src/commands/loader.test.ts +273 -0
  182. package/src/commands/loader.ts +355 -0
  183. package/src/commands/registry.test.ts +384 -0
  184. package/src/commands/registry.ts +248 -0
  185. package/src/commands/runner.test.ts +297 -0
  186. package/src/commands/runner.ts +222 -0
  187. package/src/commands/types.ts +361 -0
  188. package/src/config/index.ts +19 -0
  189. package/src/config/loader.test.ts +262 -0
  190. package/src/config/loader.ts +188 -0
  191. package/src/config/types.ts +154 -0
  192. package/src/context/index.ts +14 -0
  193. package/src/context/loader.test.ts +334 -0
  194. package/src/context/loader.ts +357 -0
  195. package/src/index.test.ts +13 -0
  196. package/src/index.ts +244 -0
  197. package/src/knowledge-library/index.ts +44 -0
  198. package/src/knowledge-library/manager.test.ts +536 -0
  199. package/src/knowledge-library/manager.ts +804 -0
  200. package/src/knowledge-library/types.ts +432 -0
  201. package/src/skills/generator.test.ts +602 -0
  202. package/src/skills/generator.ts +491 -0
  203. package/src/skills/index.ts +27 -0
  204. package/src/skills/templates.ts +520 -0
  205. package/src/skills/types.ts +251 -0
  206. package/templates/completion-report.md +72 -0
  207. package/templates/feedback.md +56 -0
  208. package/templates/project-files/CLAUDE.md.template +109 -0
  209. package/templates/project-files/coreai.json.example +47 -0
  210. package/templates/project-files/mcp.json.template +20 -0
  211. package/templates/review-complete.md +64 -0
  212. package/templates/review-request.md +67 -0
  213. package/templates/task-assignment.md +51 -0
  214. package/tsconfig.build.json +4 -0
  215. package/tsconfig.json +26 -0
  216. package/tsup.config.ts +23 -0
@@ -0,0 +1,399 @@
1
+ import { mkdtempSync, mkdirSync, writeFileSync, rmSync, readFileSync, existsSync } from 'fs';
2
+ import { join, dirname } from 'path';
3
+ import { tmpdir } from 'os';
4
+ import { fileURLToPath } from 'url';
5
+ import {
6
+ generateAgentMarkdown,
7
+ compileAgent,
8
+ loadAllAgents,
9
+ filterAgentsByTeam,
10
+ compileAgents,
11
+ } from './compiler.js';
12
+ import type { AgentDefinition, AgentMetadata } from './types.js';
13
+ import type { CoreAIConfig } from '../config/types.js';
14
+
15
+ const __filename = fileURLToPath(import.meta.url);
16
+ const __dirname = dirname(__filename);
17
+
18
+ describe('Agent Compiler', () => {
19
+ let tempDir: string;
20
+
21
+ beforeEach(() => {
22
+ tempDir = mkdtempSync(join(tmpdir(), 'coreai-compiler-test-'));
23
+ });
24
+
25
+ afterEach(() => {
26
+ rmSync(tempDir, { recursive: true, force: true });
27
+ });
28
+
29
+ const minimalAgent: AgentDefinition = {
30
+ role: 'test-agent',
31
+ type: 'ic-engineer',
32
+ display_name: 'Test Agent',
33
+ description: 'A test agent for unit testing.',
34
+ };
35
+
36
+ const fullAgent: AgentDefinition = {
37
+ role: 'backend-engineer',
38
+ type: 'ic-engineer',
39
+ display_name: 'Backend Engineer',
40
+ description: 'Senior backend engineer specializing in API design.',
41
+ responsibilities: ['Design APIs', 'Write tests', 'Review code'],
42
+ expertise: {
43
+ primary: ['API design', 'Database design'],
44
+ tech_stack: 'TypeScript, Node.js',
45
+ },
46
+ skills: ['Code review', 'Debugging'],
47
+ principles: {
48
+ code_quality: ['Write clean code', 'Follow SOLID'],
49
+ testing: ['Test first', 'High coverage'],
50
+ },
51
+ behaviors: {
52
+ workflow: 'ticket-implementation',
53
+ quality_gates: 'lint, test, build',
54
+ },
55
+ context_sources: {
56
+ shared: ['docs/architecture'],
57
+ personal: ['KnowledgeLibrary/backend-engineer/context'],
58
+ },
59
+ communication: {
60
+ inbox: 'KnowledgeLibrary/backend-engineer/inbox',
61
+ outbox: 'KnowledgeLibrary/backend-engineer/outbox',
62
+ },
63
+ };
64
+
65
+ describe('generateAgentMarkdown', () => {
66
+ it('should generate markdown for minimal agent', () => {
67
+ const markdown = generateAgentMarkdown(minimalAgent);
68
+
69
+ expect(markdown).toContain('# Test Agent');
70
+ expect(markdown).toContain('**Role:** test-agent');
71
+ expect(markdown).toContain('**Type:** ic-engineer');
72
+ expect(markdown).toContain('## Description');
73
+ expect(markdown).toContain('A test agent for unit testing.');
74
+ expect(markdown).toContain('*Generated by CoreAI*');
75
+ });
76
+
77
+ it('should generate markdown for full agent', () => {
78
+ const markdown = generateAgentMarkdown(fullAgent);
79
+
80
+ // Header
81
+ expect(markdown).toContain('# Backend Engineer');
82
+ expect(markdown).toContain('**Role:** backend-engineer');
83
+
84
+ // Responsibilities
85
+ expect(markdown).toContain('## Responsibilities');
86
+ expect(markdown).toContain('- Design APIs');
87
+ expect(markdown).toContain('- Write tests');
88
+
89
+ // Expertise
90
+ expect(markdown).toContain('## Expertise');
91
+ expect(markdown).toContain('### Primary Areas');
92
+ expect(markdown).toContain('- API design');
93
+ expect(markdown).toContain('### Tech Stack');
94
+ expect(markdown).toContain('TypeScript, Node.js');
95
+
96
+ // Skills
97
+ expect(markdown).toContain('## Skills');
98
+ expect(markdown).toContain('- Code review');
99
+
100
+ // Principles
101
+ expect(markdown).toContain('## Principles');
102
+ expect(markdown).toContain('### Code Quality');
103
+ expect(markdown).toContain('- Write clean code');
104
+ expect(markdown).toContain('### Testing');
105
+ expect(markdown).toContain('- Test first');
106
+
107
+ // Behaviors
108
+ expect(markdown).toContain('## Behaviors');
109
+ expect(markdown).toContain('**Workflow:** ticket-implementation');
110
+
111
+ // Context Sources
112
+ expect(markdown).toContain('## Context Sources');
113
+ expect(markdown).toContain('### Shared');
114
+ expect(markdown).toContain('- docs/architecture');
115
+ expect(markdown).toContain('### Personal');
116
+
117
+ // Communication
118
+ expect(markdown).toContain('## Communication');
119
+ expect(markdown).toContain('**Inbox:**');
120
+ expect(markdown).toContain('**Outbox:**');
121
+ });
122
+
123
+ it('should format snake_case titles correctly', () => {
124
+ const markdown = generateAgentMarkdown(fullAgent);
125
+ expect(markdown).toContain('### Code Quality');
126
+ });
127
+ });
128
+
129
+ describe('compileAgent', () => {
130
+ it('should compile agent with variable resolution', () => {
131
+ const agent: AgentDefinition = {
132
+ role: 'test-agent',
133
+ type: 'ic-engineer',
134
+ display_name: 'Test Agent',
135
+ description: 'Agent for ${config.project.name}',
136
+ };
137
+
138
+ const config: CoreAIConfig = {
139
+ version: '1.0',
140
+ project: { name: 'my-project' },
141
+ };
142
+
143
+ const markdown = compileAgent(agent, config);
144
+
145
+ expect(markdown).toContain('Agent for my-project');
146
+ });
147
+
148
+ it('should compile agent without config', () => {
149
+ const markdown = compileAgent(minimalAgent);
150
+ expect(markdown).toContain('# Test Agent');
151
+ });
152
+ });
153
+
154
+ describe('loadAllAgents', () => {
155
+ it('should load agents from core directory', () => {
156
+ // Create core agents
157
+ const coreDir = join(tempDir, 'core');
158
+ mkdirSync(coreDir);
159
+ writeFileSync(
160
+ join(coreDir, 'agent-one.yaml'),
161
+ `
162
+ role: agent-one
163
+ type: ic-engineer
164
+ display_name: Agent One
165
+ description: First agent
166
+ `
167
+ );
168
+
169
+ const agents = loadAllAgents({ coreAgentsDir: coreDir });
170
+
171
+ expect(agents.size).toBe(1);
172
+ expect(agents.get('agent-one')?.source).toBe('core');
173
+ });
174
+
175
+ it('should load agents from custom directory', () => {
176
+ const customDir = join(tempDir, 'custom');
177
+ mkdirSync(customDir);
178
+ writeFileSync(
179
+ join(customDir, 'custom-agent.yaml'),
180
+ `
181
+ role: custom-agent
182
+ type: specialist
183
+ display_name: Custom Agent
184
+ description: A custom agent
185
+ `
186
+ );
187
+
188
+ const agents = loadAllAgents({ customAgentsDir: customDir });
189
+
190
+ expect(agents.size).toBe(1);
191
+ expect(agents.get('custom-agent')?.source).toBe('custom');
192
+ });
193
+
194
+ it('should mark overridden agents correctly', () => {
195
+ const coreDir = join(tempDir, 'core');
196
+ const customDir = join(tempDir, 'custom');
197
+ mkdirSync(coreDir);
198
+ mkdirSync(customDir);
199
+
200
+ // Core agent
201
+ writeFileSync(
202
+ join(coreDir, 'shared-agent.yaml'),
203
+ `
204
+ role: shared-agent
205
+ type: ic-engineer
206
+ display_name: Core Version
207
+ description: Core version of agent
208
+ `
209
+ );
210
+
211
+ // Custom override
212
+ writeFileSync(
213
+ join(customDir, 'shared-agent.yaml'),
214
+ `
215
+ role: shared-agent
216
+ type: ic-engineer
217
+ display_name: Custom Version
218
+ description: Custom version of agent
219
+ `
220
+ );
221
+
222
+ const agents = loadAllAgents({
223
+ coreAgentsDir: coreDir,
224
+ customAgentsDir: customDir,
225
+ });
226
+
227
+ expect(agents.size).toBe(1);
228
+ expect(agents.get('shared-agent')?.source).toBe('override');
229
+ expect(agents.get('shared-agent')?.definition.display_name).toBe('Custom Version');
230
+ });
231
+ });
232
+
233
+ describe('filterAgentsByTeam', () => {
234
+ it('should return all agents when no team config', () => {
235
+ const agents = new Map<string, AgentMetadata>([
236
+ ['agent-one', { definition: minimalAgent, source: 'core', filePath: '' }],
237
+ ['agent-two', { definition: fullAgent, source: 'core', filePath: '' }],
238
+ ]);
239
+
240
+ const filtered = filterAgentsByTeam(agents);
241
+ expect(filtered.size).toBe(2);
242
+ });
243
+
244
+ it('should filter agents by team config', () => {
245
+ const agents = new Map<string, AgentMetadata>([
246
+ ['agent-one', { definition: minimalAgent, source: 'core', filePath: '' }],
247
+ ['agent-two', { definition: fullAgent, source: 'core', filePath: '' }],
248
+ ]);
249
+
250
+ const config: CoreAIConfig = {
251
+ version: '1.0',
252
+ project: { name: 'test' },
253
+ team: { agents: ['agent-one'] },
254
+ };
255
+
256
+ const filtered = filterAgentsByTeam(agents, config);
257
+ expect(filtered.size).toBe(1);
258
+ expect(filtered.has('agent-one')).toBe(true);
259
+ expect(filtered.has('agent-two')).toBe(false);
260
+ });
261
+
262
+ it('should handle empty team agents array', () => {
263
+ const agents = new Map<string, AgentMetadata>([
264
+ ['agent-one', { definition: minimalAgent, source: 'core', filePath: '' }],
265
+ ]);
266
+
267
+ const config: CoreAIConfig = {
268
+ version: '1.0',
269
+ project: { name: 'test' },
270
+ team: { agents: [] },
271
+ };
272
+
273
+ const filtered = filterAgentsByTeam(agents, config);
274
+ expect(filtered.size).toBe(1);
275
+ });
276
+ });
277
+
278
+ describe('compileAgents', () => {
279
+ it('should compile agents to output directory', () => {
280
+ const coreDir = join(tempDir, 'core');
281
+ const outputDir = join(tempDir, 'output');
282
+ mkdirSync(coreDir);
283
+
284
+ writeFileSync(
285
+ join(coreDir, 'test-agent.yaml'),
286
+ `
287
+ role: test-agent
288
+ type: ic-engineer
289
+ display_name: Test Agent
290
+ description: A test agent
291
+ `
292
+ );
293
+
294
+ const result = compileAgents(undefined, {
295
+ coreAgentsDir: coreDir,
296
+ outputDir,
297
+ projectRoot: tempDir,
298
+ });
299
+
300
+ expect(result.compiled.length).toBe(1);
301
+ expect(result.errors.length).toBe(0);
302
+ expect(result.compiled[0].role).toBe('test-agent');
303
+
304
+ // Verify file was created
305
+ const outputPath = join(outputDir, 'test-agent.md');
306
+ expect(existsSync(outputPath)).toBe(true);
307
+
308
+ const content = readFileSync(outputPath, 'utf-8');
309
+ expect(content).toContain('# Test Agent');
310
+ });
311
+
312
+ it('should resolve variables during compilation', () => {
313
+ const coreDir = join(tempDir, 'core');
314
+ const outputDir = join(tempDir, 'output');
315
+ mkdirSync(coreDir);
316
+
317
+ writeFileSync(
318
+ join(coreDir, 'test-agent.yaml'),
319
+ `
320
+ role: test-agent
321
+ type: ic-engineer
322
+ display_name: Test Agent
323
+ description: Agent for \${config.project.name}
324
+ `
325
+ );
326
+
327
+ const config: CoreAIConfig = {
328
+ version: '1.0',
329
+ project: { name: 'my-awesome-project' },
330
+ };
331
+
332
+ compileAgents(config, {
333
+ coreAgentsDir: coreDir,
334
+ outputDir,
335
+ projectRoot: tempDir,
336
+ });
337
+
338
+ const content = readFileSync(join(outputDir, 'test-agent.md'), 'utf-8');
339
+ expect(content).toContain('Agent for my-awesome-project');
340
+ });
341
+
342
+ it('should create output directory if it does not exist', () => {
343
+ const coreDir = join(tempDir, 'core');
344
+ const outputDir = join(tempDir, 'nested', 'output', 'dir');
345
+ mkdirSync(coreDir);
346
+
347
+ writeFileSync(
348
+ join(coreDir, 'test-agent.yaml'),
349
+ `
350
+ role: test-agent
351
+ type: ic-engineer
352
+ display_name: Test Agent
353
+ description: A test agent
354
+ `
355
+ );
356
+
357
+ compileAgents(undefined, {
358
+ coreAgentsDir: coreDir,
359
+ outputDir,
360
+ projectRoot: tempDir,
361
+ });
362
+
363
+ expect(existsSync(outputDir)).toBe(true);
364
+ });
365
+ });
366
+
367
+ describe('Core Agents Compilation', () => {
368
+ it('should compile all core agents successfully', () => {
369
+ const coreAgentsDir = join(__dirname, '../../agents');
370
+ const outputDir = join(tempDir, 'compiled');
371
+
372
+ const result = compileAgents(undefined, {
373
+ coreAgentsDir,
374
+ outputDir,
375
+ projectRoot: tempDir,
376
+ });
377
+
378
+ expect(result.errors.length).toBe(0);
379
+ expect(result.compiled.length).toBe(4);
380
+
381
+ // Verify each agent was compiled
382
+ const roles = result.compiled.map((c) => c.role).sort();
383
+ expect(roles).toEqual([
384
+ 'backend-engineer',
385
+ 'devops-engineer',
386
+ 'engineering-manager',
387
+ 'frontend-engineer',
388
+ ]);
389
+
390
+ // Verify files exist and have content
391
+ for (const compiled of result.compiled) {
392
+ const content = readFileSync(compiled.outputPath, 'utf-8');
393
+ expect(content.length).toBeGreaterThan(0);
394
+ expect(content).toContain('# ');
395
+ expect(content).toContain('*Generated by CoreAI*');
396
+ }
397
+ });
398
+ });
399
+ });