prjct-cli 0.10.0 → 0.10.2

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 (43) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/core/__tests__/agentic/memory-system.test.js +263 -0
  3. package/core/__tests__/agentic/plan-mode.test.js +336 -0
  4. package/core/agentic/chain-of-thought.js +578 -0
  5. package/core/agentic/command-executor.js +238 -4
  6. package/core/agentic/context-builder.js +208 -8
  7. package/core/agentic/ground-truth.js +591 -0
  8. package/core/agentic/loop-detector.js +406 -0
  9. package/core/agentic/memory-system.js +850 -0
  10. package/core/agentic/parallel-tools.js +366 -0
  11. package/core/agentic/plan-mode.js +572 -0
  12. package/core/agentic/prompt-builder.js +76 -1
  13. package/core/agentic/response-templates.js +290 -0
  14. package/core/agentic/semantic-compression.js +517 -0
  15. package/core/agentic/think-blocks.js +657 -0
  16. package/core/agentic/tool-registry.js +32 -0
  17. package/core/agentic/validation-rules.js +380 -0
  18. package/core/command-registry.js +48 -0
  19. package/core/commands.js +43 -1
  20. package/core/context-sync.js +183 -0
  21. package/package.json +7 -15
  22. package/templates/commands/done.md +7 -0
  23. package/templates/commands/feature.md +8 -0
  24. package/templates/commands/ship.md +8 -0
  25. package/templates/commands/spec.md +128 -0
  26. package/templates/global/CLAUDE.md +17 -0
  27. package/core/__tests__/agentic/agent-router.test.js +0 -398
  28. package/core/__tests__/agentic/command-executor.test.js +0 -223
  29. package/core/__tests__/agentic/context-builder.test.js +0 -160
  30. package/core/__tests__/agentic/context-filter.test.js +0 -494
  31. package/core/__tests__/agentic/prompt-builder.test.js +0 -204
  32. package/core/__tests__/agentic/template-loader.test.js +0 -164
  33. package/core/__tests__/agentic/tool-registry.test.js +0 -243
  34. package/core/__tests__/domain/agent-generator.test.js +0 -289
  35. package/core/__tests__/domain/agent-loader.test.js +0 -179
  36. package/core/__tests__/domain/analyzer.test.js +0 -324
  37. package/core/__tests__/infrastructure/author-detector.test.js +0 -103
  38. package/core/__tests__/infrastructure/config-manager.test.js +0 -454
  39. package/core/__tests__/infrastructure/path-manager.test.js +0 -412
  40. package/core/__tests__/setup.test.js +0 -15
  41. package/core/__tests__/utils/date-helper.test.js +0 -169
  42. package/core/__tests__/utils/file-helper.test.js +0 -258
  43. package/core/__tests__/utils/jsonl-helper.test.js +0 -387
@@ -1,398 +0,0 @@
1
- import { describe, it, expect, beforeEach, vi } from 'vitest'
2
- import { createRequire } from 'module'
3
- import path from 'path'
4
- import fs from 'fs/promises'
5
- import os from 'os'
6
-
7
- const require = createRequire(import.meta.url)
8
-
9
- describe('Mandatory Agent Router', () => {
10
- let MandatoryAgentRouter
11
- let AgentGenerator
12
- let router
13
- let mockAgentGenerator
14
-
15
- beforeEach(() => {
16
- MandatoryAgentRouter = require('../../agentic/agent-router.js')
17
- AgentGenerator = require('../../domain/agent-generator.js')
18
-
19
- // Mock agent generator
20
- mockAgentGenerator = {
21
- generateDynamicAgent: vi.fn().mockResolvedValue({
22
- name: 'test-agent',
23
- type: 'frontend-specialist',
24
- domain: 'frontend',
25
- confidence: 0.9
26
- })
27
- }
28
-
29
- router = new MandatoryAgentRouter()
30
- router.agentGenerator = mockAgentGenerator
31
- })
32
-
33
- describe('Constructor', () => {
34
- it('should initialize with agent generator', () => {
35
- expect(router.agentGenerator).toBeDefined()
36
- expect(router.agentCache).toBeInstanceOf(Map)
37
- expect(Array.isArray(router.usageLog)).toBe(true)
38
- })
39
- })
40
-
41
- describe('executeTask()', () => {
42
- it('should assign agent to task', async () => {
43
- const task = { description: 'create login component', type: 'ui' }
44
- const context = { projectPath: '/test', files: [] }
45
- const projectPath = '/test'
46
-
47
- const result = await router.executeTask(task, context, projectPath)
48
-
49
- expect(result).toBeDefined()
50
- expect(result.agent).toBeDefined()
51
- expect(result.agent.name).toBe('test-agent')
52
- expect(result.context).toBeDefined()
53
- expect(result.taskAnalysis).toBeDefined()
54
- expect(result.routing).toBeDefined()
55
- })
56
-
57
- it('should throw error if no agent can be assigned', async () => {
58
- router.agentGenerator.generateDynamicAgent = vi.fn().mockResolvedValue(null)
59
-
60
- const task = { description: 'unknown task' }
61
- const context = { projectPath: '/test' }
62
- const projectPath = '/test'
63
-
64
- await expect(router.executeTask(task, context, projectPath)).rejects.toThrow('CRITICAL: No agent assigned')
65
- })
66
-
67
- it('should cache agents for reuse', async () => {
68
- const task = { description: 'create component', type: 'ui' }
69
- const context = { projectPath: '/test' }
70
- const projectPath = '/test'
71
-
72
- await router.executeTask(task, context, projectPath)
73
- await router.executeTask(task, context, projectPath)
74
-
75
- // Should only generate once, second call uses cache
76
- expect(mockAgentGenerator.generateDynamicAgent).toHaveBeenCalledTimes(1)
77
- })
78
-
79
- it('should log agent usage', async () => {
80
- const task = { description: 'test task' }
81
- const context = { projectPath: '/test', files: ['file1.js', 'file2.js'] }
82
- const projectPath = '/test'
83
-
84
- await router.executeTask(task, context, projectPath)
85
-
86
- expect(router.usageLog.length).toBeGreaterThan(0)
87
- expect(router.usageLog[0].task).toBe('test task')
88
- expect(router.usageLog[0].agent).toBe('test-agent')
89
- })
90
- })
91
-
92
- describe('analyzeTask()', () => {
93
- it('should detect frontend tasks', () => {
94
- const task = { description: 'create react component with styles' }
95
- const analysis = router.analyzeTask(task)
96
-
97
- expect(analysis.domain).toBe('frontend')
98
- expect(analysis.confidence).toBeGreaterThan(0)
99
- expect(analysis.matchedKeywords.length).toBeGreaterThan(0)
100
- })
101
-
102
- it('should detect backend tasks', () => {
103
- const task = { description: 'create API endpoint with authentication' }
104
- const analysis = router.analyzeTask(task)
105
-
106
- expect(analysis.domain).toBe('backend')
107
- expect(analysis.matchedKeywords).toContain('api')
108
- })
109
-
110
- it('should detect database tasks', () => {
111
- const task = { description: 'create migration schema for postgres' }
112
- const analysis = router.analyzeTask(task)
113
-
114
- expect(analysis.domain).toBe('database')
115
- expect(analysis.matchedKeywords).toContain('migration')
116
- })
117
-
118
- it('should detect devops tasks', () => {
119
- const task = { description: 'deploy to docker kubernetes' }
120
- const analysis = router.analyzeTask(task)
121
-
122
- expect(analysis.domain).toBe('devops')
123
- })
124
-
125
- it('should detect qa tasks', () => {
126
- const task = { description: 'write unit tests and fix bugs' }
127
- const analysis = router.analyzeTask(task)
128
-
129
- expect(analysis.domain).toBe('qa')
130
- })
131
-
132
- it('should detect architecture tasks', () => {
133
- const task = { description: 'design architecture pattern and refactor' }
134
- const analysis = router.analyzeTask(task)
135
-
136
- expect(analysis.domain).toBe('architecture')
137
- })
138
-
139
- it('should return generalist for unknown tasks', () => {
140
- const task = { description: 'random task description' }
141
- const analysis = router.analyzeTask(task)
142
-
143
- expect(analysis.domain).toBe('generalist')
144
- expect(analysis.confidence).toBeLessThan(1)
145
- })
146
-
147
- it('should include technology stack in analysis', () => {
148
- const task = { description: 'create react component with typescript' }
149
- const analysis = router.analyzeTask(task)
150
-
151
- expect(analysis.techStack).toBeDefined()
152
- expect(analysis.techStack.languages).toContain('typescript')
153
- expect(analysis.techStack.frameworks).toContain('react')
154
- })
155
- })
156
-
157
- describe('detectTechnology()', () => {
158
- it('should detect languages', () => {
159
- const task = { description: 'write python script' }
160
- const tech = router.detectTechnology(task, task.description)
161
-
162
- expect(tech.languages).toContain('python')
163
- })
164
-
165
- it('should detect frameworks', () => {
166
- const task = { description: 'build express api' }
167
- const tech = router.detectTechnology(task, task.description)
168
-
169
- expect(tech.frameworks).toContain('express')
170
- })
171
-
172
- it('should detect databases', () => {
173
- const task = { description: 'query mongodb database' }
174
- const tech = router.detectTechnology(task, task.description)
175
-
176
- expect(tech.databases).toContain('mongodb')
177
- })
178
-
179
- it('should return empty arrays for unknown tech', () => {
180
- const task = { description: 'random task' }
181
- const tech = router.detectTechnology(task, task.description)
182
-
183
- expect(tech.languages).toEqual([])
184
- expect(tech.frameworks).toEqual([])
185
- expect(tech.databases).toEqual([])
186
- })
187
- })
188
-
189
- describe('assignAgent()', () => {
190
- it('should generate agent for task', async () => {
191
- const taskAnalysis = {
192
- domain: 'frontend',
193
- techStack: { languages: ['typescript'], frameworks: ['react'] }
194
- }
195
- const context = { projectPath: '/test' }
196
-
197
- const agent = await router.assignAgent(taskAnalysis, context)
198
-
199
- expect(agent).toBeDefined()
200
- expect(mockAgentGenerator.generateDynamicAgent).toHaveBeenCalled()
201
- })
202
-
203
- it('should use cached agent if available', async () => {
204
- const taskAnalysis = {
205
- domain: 'frontend',
206
- techStack: { languages: ['typescript'] }
207
- }
208
- const context = { projectPath: '/test' }
209
-
210
- const agent1 = await router.assignAgent(taskAnalysis, context)
211
- const agent2 = await router.assignAgent(taskAnalysis, context)
212
-
213
- expect(agent1).toBe(agent2) // Same instance from cache
214
- expect(mockAgentGenerator.generateDynamicAgent).toHaveBeenCalledTimes(1)
215
- })
216
- })
217
-
218
- describe('filterContextForAgent()', () => {
219
- it('should filter context for frontend agent', async () => {
220
- const agent = { name: 'frontend-agent', domain: 'frontend' }
221
- const fullContext = {
222
- files: [
223
- 'src/components/Button.jsx',
224
- 'src/api/users.js',
225
- 'src/styles/main.css',
226
- 'migrations/001_users.sql'
227
- ]
228
- }
229
- const taskAnalysis = { domain: 'frontend' }
230
-
231
- const filtered = await router.filterContextForAgent(agent, fullContext, taskAnalysis)
232
-
233
- expect(filtered.files).toContain('src/components/Button.jsx')
234
- expect(filtered.files).toContain('src/styles/main.css')
235
- expect(filtered.files).not.toContain('migrations/001_users.sql')
236
- expect(filtered.relevantOnly).toBe(true)
237
- })
238
-
239
- it('should filter context for backend agent', async () => {
240
- const agent = { name: 'backend-agent', domain: 'backend' }
241
- const fullContext = {
242
- files: [
243
- 'src/components/Button.jsx',
244
- 'src/api/users.js',
245
- 'src/routes/auth.js',
246
- 'src/styles/main.css'
247
- ]
248
- }
249
- const taskAnalysis = { domain: 'backend' }
250
-
251
- const filtered = await router.filterContextForAgent(agent, fullContext, taskAnalysis)
252
-
253
- expect(filtered.files).toContain('src/api/users.js')
254
- expect(filtered.files).toContain('src/routes/auth.js')
255
- expect(filtered.files).not.toContain('src/styles/main.css')
256
- })
257
-
258
- it('should filter context for database agent', async () => {
259
- const agent = { name: 'database-agent', domain: 'database' }
260
- const fullContext = {
261
- files: [
262
- 'src/models/User.js',
263
- 'migrations/001_users.sql',
264
- 'src/components/Button.jsx'
265
- ]
266
- }
267
- const taskAnalysis = { domain: 'database' }
268
-
269
- const filtered = await router.filterContextForAgent(agent, fullContext, taskAnalysis)
270
-
271
- expect(filtered.files).toContain('src/models/User.js')
272
- expect(filtered.files).toContain('migrations/001_users.sql')
273
- expect(filtered.files).not.toContain('src/components/Button.jsx')
274
- })
275
- })
276
-
277
- describe('filterFiles()', () => {
278
- it('should exclude files matching exclude patterns', () => {
279
- const files = ['src/app.js', 'node_modules/lib.js', 'dist/bundle.js']
280
- const pattern = {
281
- include: [],
282
- exclude: ['node_modules', 'dist'],
283
- extensions: []
284
- }
285
-
286
- const filtered = router.filterFiles(files, pattern)
287
-
288
- expect(filtered).not.toContain('node_modules/lib.js')
289
- expect(filtered).not.toContain('dist/bundle.js')
290
- expect(filtered).toContain('src/app.js')
291
- })
292
-
293
- it('should include only files matching include patterns', () => {
294
- const files = ['src/components/Button.jsx', 'src/api/users.js', 'tests/test.js']
295
- const pattern = {
296
- include: ['components'],
297
- exclude: [],
298
- extensions: []
299
- }
300
-
301
- const filtered = router.filterFiles(files, pattern)
302
-
303
- expect(filtered).toContain('src/components/Button.jsx')
304
- expect(filtered).not.toContain('src/api/users.js')
305
- })
306
-
307
- it('should filter by extensions', () => {
308
- const files = ['src/app.js', 'src/app.ts', 'src/app.py']
309
- const pattern = {
310
- include: [],
311
- exclude: [],
312
- extensions: ['.js', '.ts']
313
- }
314
-
315
- const filtered = router.filterFiles(files, pattern)
316
-
317
- expect(filtered).toContain('src/app.js')
318
- expect(filtered).toContain('src/app.ts')
319
- expect(filtered).not.toContain('src/app.py')
320
- })
321
- })
322
-
323
- describe('getBestPractices()', () => {
324
- it('should return domain-specific practices', async () => {
325
- const practices = await router.getBestPractices('frontend', { languages: [], frameworks: [] })
326
-
327
- expect(practices.length).toBeGreaterThan(0)
328
- expect(practices).toContain('Component composition over inheritance')
329
- })
330
-
331
- it('should include tech-specific practices', async () => {
332
- const practices = await router.getBestPractices('frontend', {
333
- languages: ['typescript'],
334
- frameworks: ['react']
335
- })
336
-
337
- expect(practices.some(p => p.includes('Hooks') || p.includes('TypeScript'))).toBe(true)
338
- })
339
- })
340
-
341
- describe('getSimilarDomains()', () => {
342
- it('should return similar domains for frontend', () => {
343
- const similar = router.getSimilarDomains('frontend')
344
- expect(similar).toContain('fullstack')
345
- })
346
-
347
- it('should return similar domains for backend', () => {
348
- const similar = router.getSimilarDomains('backend')
349
- expect(similar).toContain('fullstack')
350
- })
351
-
352
- it('should return default for unknown domain', () => {
353
- const similar = router.getSimilarDomains('unknown')
354
- expect(similar).toEqual(['generalist'])
355
- })
356
- })
357
-
358
- describe('getUsageStats()', () => {
359
- it('should return usage statistics', async () => {
360
- const task = { description: 'test task' }
361
- const context = { projectPath: '/test' }
362
- const projectPath = '/test'
363
-
364
- await router.executeTask(task, context, projectPath)
365
- await router.executeTask(task, context, projectPath)
366
-
367
- const stats = router.getUsageStats()
368
-
369
- expect(stats.totalTasks).toBe(2)
370
- expect(stats.byAgent).toBeDefined()
371
- expect(stats.mostUsedAgent).toBe('test-agent')
372
- })
373
-
374
- it('should handle empty usage log', () => {
375
- const stats = router.getUsageStats()
376
-
377
- expect(stats.totalTasks).toBe(0)
378
- expect(stats.mostUsedAgent).toBeNull()
379
- })
380
- })
381
-
382
- describe('calculateContextReduction()', () => {
383
- it('should calculate reduction for filtered context', () => {
384
- const filteredContext = { relevantOnly: true }
385
- const reduction = router.calculateContextReduction(filteredContext)
386
-
387
- expect(reduction).toBe('70-90%')
388
- })
389
-
390
- it('should return 0% for unfiltered context', () => {
391
- const context = { relevantOnly: false }
392
- const reduction = router.calculateContextReduction(context)
393
-
394
- expect(reduction).toBe('0%')
395
- })
396
- })
397
- })
398
-
@@ -1,223 +0,0 @@
1
- import { describe, it, expect } from 'vitest'
2
- import commandExecutor from '../../agentic/command-executor.js'
3
-
4
- describe('Command Executor', () => {
5
- const testProjectPath = process.cwd()
6
-
7
- describe('execute()', () => {
8
- it('should execute command successfully', async () => {
9
- const result = await commandExecutor.execute('now', {}, testProjectPath)
10
-
11
- expect(result).toBeDefined()
12
- expect(result.success).toBe(true)
13
- })
14
-
15
- it('should load template', async () => {
16
- const result = await commandExecutor.execute('now', {}, testProjectPath)
17
-
18
- expect(result.template).toBeDefined()
19
- expect(result.template).toHaveProperty('content')
20
- expect(result.template).toHaveProperty('frontmatter')
21
- })
22
-
23
- it('should build context', async () => {
24
- const result = await commandExecutor.execute('now', {}, testProjectPath)
25
-
26
- expect(result.context).toBeDefined()
27
- expect(result.context).toHaveProperty('projectId')
28
- expect(result.context).toHaveProperty('projectPath')
29
- expect(result.context).toHaveProperty('paths')
30
- })
31
-
32
- it('should load state', async () => {
33
- const result = await commandExecutor.execute('now', {}, testProjectPath)
34
-
35
- expect(result.state).toBeDefined()
36
- expect(typeof result.state).toBe('object')
37
- })
38
-
39
- it('should build prompt', async () => {
40
- const result = await commandExecutor.execute('now', {}, testProjectPath)
41
-
42
- expect(result.prompt).toBeDefined()
43
- expect(typeof result.prompt).toBe('string')
44
- expect(result.prompt.length).toBeGreaterThan(0)
45
- })
46
-
47
- it('should pass parameters to context', async () => {
48
- const params = { taskName: 'Test Task', feature: 'Test Feature' }
49
- const result = await commandExecutor.execute('now', params, testProjectPath)
50
-
51
- expect(result.context.params).toEqual(params)
52
- })
53
-
54
- it('should handle different commands', async () => {
55
- const commands = ['now', 'done', 'next', 'ship']
56
-
57
- for (const cmd of commands) {
58
- const result = await commandExecutor.execute(cmd, {}, testProjectPath)
59
- expect(result.success).toBe(true)
60
- }
61
- })
62
-
63
- it('should handle non-existent command', async () => {
64
- const result = await commandExecutor.execute('nonexistent', {}, testProjectPath)
65
-
66
- expect(result.success).toBe(false)
67
- expect(result.error).toBeDefined()
68
- expect(result.error).toContain('Template not found')
69
- })
70
-
71
- it('should include all execution data', async () => {
72
- const result = await commandExecutor.execute('now', {}, testProjectPath)
73
-
74
- expect(result).toHaveProperty('success')
75
- expect(result).toHaveProperty('template')
76
- expect(result).toHaveProperty('context')
77
- expect(result).toHaveProperty('state')
78
- expect(result).toHaveProperty('prompt')
79
- })
80
- })
81
-
82
- describe('executeTool()', () => {
83
- it('should execute allowed tool', async () => {
84
- const allowedTools = ['Read', 'Write', 'Bash']
85
- const result = await commandExecutor.executeTool('Read', [__filename], allowedTools)
86
-
87
- expect(result).toBeDefined()
88
- })
89
-
90
- it('should throw error for disallowed tool', async () => {
91
- const allowedTools = ['Read']
92
-
93
- await expect(commandExecutor.executeTool('Write', ['file.txt', 'content'], allowedTools)).rejects.toThrow(
94
- 'Tool Write not allowed for this command'
95
- )
96
- })
97
-
98
- it('should execute Read tool', async () => {
99
- const allowedTools = ['Read']
100
- const content = await commandExecutor.executeTool('Read', [__filename], allowedTools)
101
-
102
- expect(content).toBeDefined()
103
- expect(content).toContain('Command Executor')
104
- })
105
-
106
- it('should handle tool errors', async () => {
107
- const allowedTools = ['Read']
108
-
109
- await expect(commandExecutor.executeTool('UnknownTool', [], allowedTools)).rejects.toThrow()
110
- })
111
-
112
- it('should check permissions before execution', async () => {
113
- const allowedTools = ['Read']
114
-
115
- // Bash not allowed
116
- await expect(commandExecutor.executeTool('Bash', ['echo test'], allowedTools)).rejects.toThrow(
117
- 'not allowed'
118
- )
119
- })
120
- })
121
-
122
- describe('executeSimple()', () => {
123
- it('should execute simple command', async () => {
124
- const executionFn = async (_tools, _context) => {
125
- return { message: 'Executed successfully' }
126
- }
127
-
128
- const result = await commandExecutor.executeSimple('now', executionFn, testProjectPath)
129
-
130
- expect(result.success).toBe(true)
131
- expect(result.result).toEqual({ message: 'Executed successfully' })
132
- })
133
-
134
- it('should provide tools to execution function', async () => {
135
- const executionFn = async (_tools, _context) => {
136
- expect(_tools).toHaveProperty('read')
137
- expect(_tools).toHaveProperty('write')
138
- expect(_tools).toHaveProperty('bash')
139
- return { tools: 'available' }
140
- }
141
-
142
- const result = await commandExecutor.executeSimple('now', executionFn, testProjectPath)
143
-
144
- expect(result.success).toBe(true)
145
- })
146
-
147
- it('should provide context to execution function', async () => {
148
- const executionFn = async (_tools, _context) => {
149
- expect(_context).toBeDefined()
150
- expect(_context).toHaveProperty('projectId')
151
- expect(_context).toHaveProperty('projectPath')
152
- return { context: 'received' }
153
- }
154
-
155
- const result = await commandExecutor.executeSimple('now', executionFn, testProjectPath)
156
-
157
- expect(result.success).toBe(true)
158
- })
159
-
160
- it('should enforce tool permissions', async () => {
161
- const executionFn = async (_tools, _context) => {
162
- // Try to use a disallowed tool
163
- await _tools.write('/test/file.txt', 'content')
164
- }
165
-
166
- const result = await commandExecutor.executeSimple('now', executionFn, testProjectPath)
167
-
168
- // Should fail if Write is not in allowed tools for 'now'
169
- expect(result.success).toBe(false)
170
- })
171
-
172
- it('should handle execution errors', async () => {
173
- const executionFn = async (_tools, _context) => {
174
- throw new Error('Execution failed')
175
- }
176
-
177
- const result = await commandExecutor.executeSimple('now', executionFn, testProjectPath)
178
-
179
- expect(result.success).toBe(false)
180
- expect(result.error).toContain('Execution failed')
181
- })
182
-
183
- it('should work with allowed tools', async () => {
184
- const executionFn = async (_tools, _context) => {
185
- // Read is typically allowed
186
- const content = await _tools.read(__filename)
187
- return { readSuccess: content !== null }
188
- }
189
-
190
- const result = await commandExecutor.executeSimple('now', executionFn, testProjectPath)
191
-
192
- expect(result.success).toBe(true)
193
- expect(result.result.readSuccess).toBe(true)
194
- })
195
- })
196
-
197
- describe('Integration', () => {
198
- it('should execute full command flow', async () => {
199
- const result = await commandExecutor.execute('now', { task: 'Test Task' }, testProjectPath)
200
-
201
- expect(result.success).toBe(true)
202
- expect(result.template).toBeDefined()
203
- expect(result.context).toBeDefined()
204
- expect(result.state).toBeDefined()
205
- expect(result.prompt).toBeDefined()
206
-
207
- // Prompt should include the template content
208
- expect(result.prompt).toContain(result.template.content)
209
-
210
- // Context should include parameters
211
- expect(result.context.params.task).toBe('Test Task')
212
- })
213
-
214
- it('should build proper prompt structure', async () => {
215
- const result = await commandExecutor.execute('now', {}, testProjectPath)
216
-
217
- expect(result.prompt).toContain('# Command Instructions')
218
- expect(result.prompt).toContain('## Project Context')
219
- expect(result.prompt).toContain('## Current State')
220
- expect(result.prompt).toContain('## Execute')
221
- })
222
- })
223
- })