prjct-cli 0.5.1 → 0.7.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 (81) hide show
  1. package/CHANGELOG.md +220 -7
  2. package/CLAUDE.md +476 -55
  3. package/README.md +48 -55
  4. package/bin/prjct +170 -225
  5. package/core/agentic/command-executor.js +113 -0
  6. package/core/agentic/context-builder.js +85 -0
  7. package/core/agentic/prompt-builder.js +86 -0
  8. package/core/agentic/template-loader.js +104 -0
  9. package/core/agentic/tool-registry.js +117 -0
  10. package/core/command-registry.js +597 -0
  11. package/core/commands.js +2046 -2028
  12. package/core/domain/agent-generator.js +118 -0
  13. package/core/domain/analyzer.js +211 -0
  14. package/core/domain/architect-session.js +300 -0
  15. package/core/{agents → infrastructure/agents}/claude-agent.js +16 -13
  16. package/core/{author-detector.js → infrastructure/author-detector.js} +3 -1
  17. package/core/{capability-installer.js → infrastructure/capability-installer.js} +3 -6
  18. package/core/{command-installer.js → infrastructure/command-installer.js} +4 -2
  19. package/core/{config-manager.js → infrastructure/config-manager.js} +4 -4
  20. package/core/{editors-config.js → infrastructure/editors-config.js} +2 -10
  21. package/core/{migrator.js → infrastructure/migrator.js} +34 -19
  22. package/core/{path-manager.js → infrastructure/path-manager.js} +20 -44
  23. package/core/{session-manager.js → infrastructure/session-manager.js} +45 -105
  24. package/core/{update-checker.js → infrastructure/update-checker.js} +67 -67
  25. package/core/{animations-simple.js → utils/animations.js} +3 -23
  26. package/core/utils/date-helper.js +238 -0
  27. package/core/utils/file-helper.js +327 -0
  28. package/core/utils/jsonl-helper.js +206 -0
  29. package/core/{project-capabilities.js → utils/project-capabilities.js} +21 -22
  30. package/core/utils/session-helper.js +277 -0
  31. package/core/{version.js → utils/version.js} +1 -1
  32. package/package.json +5 -12
  33. package/templates/agents/AGENTS.md +151 -99
  34. package/templates/analysis/analyze.md +84 -0
  35. package/templates/commands/analyze.md +37 -233
  36. package/templates/commands/bug.md +79 -0
  37. package/templates/commands/build.md +44 -0
  38. package/templates/commands/cleanup.md +24 -84
  39. package/templates/commands/design.md +20 -95
  40. package/templates/commands/done.md +17 -180
  41. package/templates/commands/feature.md +113 -0
  42. package/templates/commands/fix.md +58 -66
  43. package/templates/commands/git.md +35 -57
  44. package/templates/commands/help.md +18 -52
  45. package/templates/commands/idea.md +18 -34
  46. package/templates/commands/init.md +65 -257
  47. package/templates/commands/next.md +20 -60
  48. package/templates/commands/now.md +21 -23
  49. package/templates/commands/progress.md +40 -73
  50. package/templates/commands/recap.md +52 -75
  51. package/templates/commands/roadmap.md +30 -85
  52. package/templates/commands/ship.md +93 -126
  53. package/templates/commands/status.md +42 -0
  54. package/templates/commands/sync.md +19 -205
  55. package/templates/commands/task.md +19 -79
  56. package/templates/commands/test.md +25 -71
  57. package/templates/commands/workflow.md +20 -210
  58. package/core/agent-generator.js +0 -516
  59. package/core/analyzer.js +0 -600
  60. package/core/animations.js +0 -277
  61. package/core/git-integration.js +0 -401
  62. package/core/workflow-engine.js +0 -213
  63. package/core/workflow-prompts.js +0 -192
  64. package/core/workflow-rules.js +0 -147
  65. package/scripts/post-install.js +0 -121
  66. package/scripts/preuninstall.js +0 -94
  67. package/scripts/verify-installation.sh +0 -158
  68. package/templates/agents/be.template.md +0 -42
  69. package/templates/agents/data.template.md +0 -41
  70. package/templates/agents/devops.template.md +0 -41
  71. package/templates/agents/fe.template.md +0 -42
  72. package/templates/agents/mobile.template.md +0 -41
  73. package/templates/agents/pm.template.md +0 -84
  74. package/templates/agents/qa.template.md +0 -54
  75. package/templates/agents/scribe.template.md +0 -95
  76. package/templates/agents/security.template.md +0 -41
  77. package/templates/agents/ux.template.md +0 -49
  78. package/templates/commands/context.md +0 -105
  79. package/templates/commands/stuck.md +0 -48
  80. package/templates/examples/natural-language-examples.md +0 -532
  81. /package/core/{agent-detector.js → infrastructure/agent-detector.js} +0 -0
@@ -1,516 +0,0 @@
1
- const fs = require('fs').promises
2
- const path = require('path')
3
- const os = require('os')
4
-
5
- /**
6
- * AgentGenerator - Dynamic agent generation for prjct-cli
7
- *
8
- * Generates specialized AI agents based on project analysis,
9
- * customizing them with project-specific context and requirements.
10
- *
11
- * @version 0.5.0
12
- */
13
- class AgentGenerator {
14
- constructor() {
15
- this.templatesDir = path.join(__dirname, '..', 'templates', 'agents')
16
- this.outputDir = path.join(os.homedir(), '.claude', 'agents')
17
-
18
- // Base agents (always generated)
19
- this.baseAgents = ['pm', 'ux', 'fe', 'be', 'qa', 'scribe']
20
-
21
- // Agent colors for visual distinction
22
- this.agentColors = {
23
- pm: 'cyan',
24
- ux: 'purple',
25
- fe: 'orange',
26
- be: 'yellow',
27
- qa: 'green',
28
- scribe: 'blue',
29
- devops: 'red',
30
- security: 'magenta',
31
- mobile: 'pink',
32
- data: 'teal',
33
- }
34
- }
35
-
36
- /**
37
- * Generate all agents for a project
38
- * @param {Object} projectAnalysis - Analysis result from /p:analyze
39
- * @returns {Promise<Array>} List of generated agent types
40
- */
41
- async generateAll(projectAnalysis) {
42
- console.log('\n🤖 Generating AI agents...\n')
43
-
44
- // Ensure output directory exists
45
- await fs.mkdir(this.outputDir, { recursive: true })
46
-
47
- // Detect which agents to generate
48
- const conditionalAgents = this.detectConditionalAgents(projectAnalysis)
49
- const allAgents = [...this.baseAgents, ...conditionalAgents]
50
-
51
- // Generate each agent
52
- const generated = []
53
- for (const agentType of allAgents) {
54
- try {
55
- await this.generateAgent(agentType, projectAnalysis)
56
- generated.push(agentType)
57
- console.log(` ✅ ${agentType.toUpperCase()} agent created`)
58
- } catch (error) {
59
- console.error(` ❌ Failed to create ${agentType} agent:`, error.message)
60
- }
61
- }
62
-
63
- console.log(`\n✨ Generated ${generated.length} agents\n`)
64
-
65
- return generated
66
- }
67
-
68
- /**
69
- * Detect which conditional agents should be generated
70
- * @param {Object} analysis - Project analysis
71
- * @returns {Array<string>} List of conditional agent types
72
- */
73
- detectConditionalAgents(analysis) {
74
- const agents = []
75
-
76
- // Security agent for web apps or apps with auth
77
- if (
78
- analysis.type === 'web' ||
79
- analysis.isWebApp ||
80
- analysis.hasAuth ||
81
- analysis.hasAPI
82
- ) {
83
- agents.push('security')
84
- }
85
-
86
- // DevOps agent for projects with Docker/K8s/CI
87
- if (
88
- analysis.hasDocker ||
89
- analysis.hasKubernetes ||
90
- analysis.hasCI ||
91
- analysis.hasDeployment
92
- ) {
93
- agents.push('devops')
94
- }
95
-
96
- // Mobile agent for React Native/Flutter/mobile frameworks
97
- if (
98
- analysis.isMobile ||
99
- analysis.frameworks?.some(f =>
100
- ['react-native', 'flutter', 'ionic', 'expo'].includes(
101
- f.toLowerCase(),
102
- ),
103
- )
104
- ) {
105
- agents.push('mobile')
106
- }
107
-
108
- // Data Science agent for ML/data projects
109
- if (
110
- analysis.hasML ||
111
- analysis.hasDataScience ||
112
- analysis.dependencies?.some(d =>
113
- [
114
- 'tensorflow',
115
- 'pytorch',
116
- 'scikit-learn',
117
- 'pandas',
118
- 'numpy',
119
- 'jupyter',
120
- ].includes(d.toLowerCase()),
121
- )
122
- ) {
123
- agents.push('data')
124
- }
125
-
126
- return agents
127
- }
128
-
129
- /**
130
- * Generate a single agent file
131
- * @param {string} type - Agent type (pm, fe, be, etc.)
132
- * @param {Object} analysis - Project analysis
133
- * @returns {Promise<void>}
134
- */
135
- async generateAgent(type, analysis) {
136
- // Load template
137
- const templatePath = path.join(this.templatesDir, `${type}.template.md`)
138
- let template
139
-
140
- try {
141
- template = await fs.readFile(templatePath, 'utf-8')
142
- } catch (error) {
143
- throw new Error(`Template not found for ${type} agent`)
144
- }
145
-
146
- // Replace placeholders
147
- let content = this.replacePlaceholders(template, analysis)
148
-
149
- // Add project-specific context
150
- content += this.generateProjectContext(type, analysis)
151
-
152
- // Write agent file
153
- const outputPath = path.join(this.outputDir, `p_agent_${type}.md`)
154
- await fs.writeFile(outputPath, content, 'utf-8')
155
- }
156
-
157
- /**
158
- * Replace template placeholders with actual values
159
- * @param {string} template - Template content
160
- * @param {Object} analysis - Project analysis
161
- * @returns {string} Processed template
162
- */
163
- replacePlaceholders(template, analysis) {
164
- const replacements = {
165
- PROJECT_NAME: analysis.name || 'Unknown Project',
166
- DETECTED_STACK: this.formatStack(analysis),
167
- DETECTED_PATTERN: analysis.architecture || 'Not detected',
168
- DETECTED_ENTRY: analysis.entryPoint || 'Not detected',
169
- PROJECT_TYPE: analysis.type || 'application',
170
- PRIMARY_LANGUAGE: analysis.primaryLanguage || 'JavaScript',
171
- FRAMEWORK: this.formatFrameworks(analysis.frameworks),
172
- }
173
-
174
- let content = template
175
-
176
- for (const [key, value] of Object.entries(replacements)) {
177
- const regex = new RegExp(`\\[${key}\\]`, 'g')
178
- content = content.replace(regex, value)
179
- }
180
-
181
- return content
182
- }
183
-
184
- /**
185
- * Format stack information for display
186
- * @param {Object} analysis - Project analysis
187
- * @returns {string} Formatted stack string
188
- */
189
- formatStack(analysis) {
190
- const parts = []
191
-
192
- if (analysis.primaryLanguage) {
193
- parts.push(analysis.primaryLanguage)
194
- }
195
-
196
- if (analysis.frameworks && analysis.frameworks.length > 0) {
197
- parts.push(...analysis.frameworks.slice(0, 3))
198
- }
199
-
200
- if (analysis.tools && analysis.tools.length > 0) {
201
- parts.push(...analysis.tools.slice(0, 2))
202
- }
203
-
204
- return parts.length > 0 ? parts.join(' + ') : 'Not detected'
205
- }
206
-
207
- /**
208
- * Format frameworks list
209
- * @param {Array} frameworks - List of frameworks
210
- * @returns {string} Formatted string
211
- */
212
- formatFrameworks(frameworks) {
213
- if (!frameworks || frameworks.length === 0) {
214
- return 'None detected'
215
- }
216
- return frameworks.join(', ')
217
- }
218
-
219
- /**
220
- * Generate project-specific context section
221
- * @param {string} type - Agent type
222
- * @param {Object} analysis - Project analysis
223
- * @returns {string} Context markdown
224
- */
225
- generateProjectContext(type, analysis) {
226
- let context = '\n\n## Project-Specific Context\n\n'
227
-
228
- switch (type) {
229
- case 'fe':
230
- context += this.generateFrontendContext(analysis)
231
- break
232
- case 'be':
233
- context += this.generateBackendContext(analysis)
234
- break
235
- case 'ux':
236
- context += this.generateUXContext(analysis)
237
- break
238
- case 'qa':
239
- context += this.generateQAContext(analysis)
240
- break
241
- case 'devops':
242
- context += this.generateDevOpsContext(analysis)
243
- break
244
- case 'security':
245
- context += this.generateSecurityContext(analysis)
246
- break
247
- default:
248
- context += this.generateGenericContext(analysis)
249
- }
250
-
251
- return context
252
- }
253
-
254
- /**
255
- * Generate frontend-specific context
256
- */
257
- generateFrontendContext(analysis) {
258
- const context = []
259
-
260
- if (analysis.frontend) {
261
- const fe = analysis.frontend
262
-
263
- if (fe.framework) {
264
- context.push(`- **Framework**: ${fe.framework}${fe.version ? ` ${fe.version}` : ''}`)
265
- }
266
-
267
- if (fe.stateManagement) {
268
- context.push(`- **State Management**: ${fe.stateManagement}`)
269
- }
270
-
271
- if (fe.routing) {
272
- context.push(`- **Routing**: ${fe.routing}`)
273
- }
274
-
275
- if (fe.styling) {
276
- context.push(`- **Styling**: ${fe.styling}`)
277
- }
278
-
279
- if (fe.buildTool) {
280
- context.push(`- **Build Tool**: ${fe.buildTool}`)
281
- }
282
-
283
- if (fe.componentPattern) {
284
- context.push(`- **Component Pattern**: ${fe.componentPattern}`)
285
- }
286
- }
287
-
288
- if (analysis.directories?.components) {
289
- context.push(`- **Components Location**: ${analysis.directories.components}`)
290
- }
291
-
292
- return context.length > 0 ? context.join('\n') : '- No specific frontend context detected'
293
- }
294
-
295
- /**
296
- * Generate backend-specific context
297
- */
298
- generateBackendContext(analysis) {
299
- const context = []
300
-
301
- if (analysis.backend) {
302
- const be = analysis.backend
303
-
304
- if (be.framework) {
305
- context.push(`- **Framework**: ${be.framework}${be.version ? ` ${be.version}` : ''}`)
306
- }
307
-
308
- if (be.database) {
309
- context.push(`- **Database**: ${be.database}`)
310
- }
311
-
312
- if (be.orm) {
313
- context.push(`- **ORM/ODM**: ${be.orm}`)
314
- }
315
-
316
- if (be.auth) {
317
- context.push(`- **Authentication**: ${be.auth}`)
318
- }
319
-
320
- if (be.apiStyle) {
321
- context.push(`- **API Style**: ${be.apiStyle}`)
322
- }
323
- }
324
-
325
- if (analysis.hasAPI) {
326
- context.push(`- **API Detected**: Yes`)
327
- }
328
-
329
- return context.length > 0 ? context.join('\n') : '- No specific backend context detected'
330
- }
331
-
332
- /**
333
- * Generate UX-specific context
334
- */
335
- generateUXContext(analysis) {
336
- const context = []
337
-
338
- if (analysis.frontend?.styling) {
339
- context.push(`- **Design System**: ${analysis.frontend.styling}`)
340
- }
341
-
342
- if (analysis.hasDesignSystem) {
343
- context.push(`- **Design System Files**: Detected`)
344
- }
345
-
346
- if (analysis.accessibility) {
347
- context.push(`- **Accessibility**: ${analysis.accessibility}`)
348
- }
349
-
350
- context.push(`- **Focus**: User experience, visual design, interaction patterns`)
351
-
352
- return context.join('\n')
353
- }
354
-
355
- /**
356
- * Generate QA-specific context
357
- */
358
- generateQAContext(analysis) {
359
- const context = []
360
-
361
- if (analysis.testing) {
362
- if (analysis.testing.framework) {
363
- context.push(`- **Test Framework**: ${analysis.testing.framework}`)
364
- }
365
-
366
- if (analysis.testing.coverage) {
367
- context.push(`- **Coverage Tool**: ${analysis.testing.coverage}`)
368
- }
369
-
370
- if (analysis.testing.e2e) {
371
- context.push(`- **E2E Testing**: ${analysis.testing.e2e}`)
372
- }
373
- }
374
-
375
- if (analysis.hasTests) {
376
- context.push(`- **Tests Detected**: Yes`)
377
- }
378
-
379
- return context.length > 0 ? context.join('\n') : '- No specific testing context detected'
380
- }
381
-
382
- /**
383
- * Generate DevOps-specific context
384
- */
385
- generateDevOpsContext(analysis) {
386
- const context = []
387
-
388
- if (analysis.hasDocker) {
389
- context.push(`- **Docker**: Detected (Dockerfile, docker-compose)`)
390
- }
391
-
392
- if (analysis.hasKubernetes) {
393
- context.push(`- **Kubernetes**: Detected`)
394
- }
395
-
396
- if (analysis.hasCI) {
397
- context.push(`- **CI/CD**: ${analysis.ciProvider || 'Detected'}`)
398
- }
399
-
400
- if (analysis.deployment) {
401
- context.push(`- **Deployment**: ${analysis.deployment}`)
402
- }
403
-
404
- return context.length > 0 ? context.join('\n') : '- Infrastructure and deployment files detected'
405
- }
406
-
407
- /**
408
- * Generate security-specific context
409
- */
410
- generateSecurityContext(analysis) {
411
- const context = []
412
-
413
- if (analysis.hasAuth) {
414
- context.push(`- **Authentication**: Detected`)
415
- }
416
-
417
- if (analysis.hasAPI) {
418
- context.push(`- **API Security**: Focus on endpoint security`)
419
- }
420
-
421
- if (analysis.type === 'web' || analysis.isWebApp) {
422
- context.push(`- **Web Security**: OWASP Top 10 compliance`)
423
- }
424
-
425
- context.push(`- **Focus**: Security audits, vulnerability assessment, secure coding practices`)
426
-
427
- return context.join('\n')
428
- }
429
-
430
- /**
431
- * Generate generic project context
432
- */
433
- generateGenericContext(analysis) {
434
- const context = []
435
-
436
- if (analysis.description) {
437
- context.push(`- **Description**: ${analysis.description}`)
438
- }
439
-
440
- if (analysis.mainDirectories && analysis.mainDirectories.length > 0) {
441
- context.push(`- **Main Directories**: ${analysis.mainDirectories.join(', ')}`)
442
- }
443
-
444
- if (analysis.totalFiles) {
445
- context.push(`- **Total Files**: ${analysis.totalFiles}`)
446
- }
447
-
448
- return context.length > 0 ? context.join('\n') : '- Standard project setup'
449
- }
450
-
451
- /**
452
- * Update existing agents with new project context
453
- * @param {Object} analysis - Updated project analysis
454
- * @returns {Promise<Array>} List of updated agents
455
- */
456
- async updateExistingAgents(analysis) {
457
- console.log('\n🔄 Updating existing agents...\n')
458
-
459
- const updated = []
460
-
461
- // Check which agents currently exist
462
- try {
463
- const files = await fs.readdir(this.outputDir)
464
- const agentFiles = files.filter(f => f.startsWith('p_agent_') && f.endsWith('.md'))
465
-
466
- for (const file of agentFiles) {
467
- const type = file.replace('p_agent_', '').replace('.md', '')
468
-
469
- try {
470
- await this.generateAgent(type, analysis)
471
- updated.push(type)
472
- console.log(` ↻ ${type.toUpperCase()} agent updated`)
473
- } catch (error) {
474
- console.error(` ❌ Failed to update ${type} agent:`, error.message)
475
- }
476
- }
477
- } catch (error) {
478
- console.error('Error reading agents directory:', error.message)
479
- }
480
-
481
- console.log(`\n✨ Updated ${updated.length} agents\n`)
482
-
483
- return updated
484
- }
485
-
486
- /**
487
- * Remove agents that are no longer needed
488
- * @param {Array} requiredAgents - List of agents that should exist
489
- * @returns {Promise<Array>} List of removed agents
490
- */
491
- async cleanupObsoleteAgents(requiredAgents) {
492
- const removed = []
493
-
494
- try {
495
- const files = await fs.readdir(this.outputDir)
496
- const agentFiles = files.filter(f => f.startsWith('p_agent_') && f.endsWith('.md'))
497
-
498
- for (const file of agentFiles) {
499
- const type = file.replace('p_agent_', '').replace('.md', '')
500
-
501
- if (!requiredAgents.includes(type)) {
502
- const filePath = path.join(this.outputDir, file)
503
- await fs.unlink(filePath)
504
- removed.push(type)
505
- console.log(` 🗑️ ${type.toUpperCase()} agent removed (no longer needed)`)
506
- }
507
- }
508
- } catch (error) {
509
- console.error('Error during cleanup:', error.message)
510
- }
511
-
512
- return removed
513
- }
514
- }
515
-
516
- module.exports = new AgentGenerator()