prjct-cli 0.6.0 → 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 (83) hide show
  1. package/CHANGELOG.md +67 -6
  2. package/CLAUDE.md +442 -36
  3. package/README.md +47 -54
  4. package/bin/prjct +170 -240
  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 +106 -62
  11. package/core/commands.js +2030 -2211
  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 +4 -12
  33. package/templates/agents/AGENTS.md +101 -27
  34. package/templates/analysis/analyze.md +84 -0
  35. package/templates/commands/analyze.md +9 -2
  36. package/templates/commands/bug.md +79 -0
  37. package/templates/commands/build.md +5 -2
  38. package/templates/commands/cleanup.md +5 -2
  39. package/templates/commands/design.md +5 -2
  40. package/templates/commands/done.md +4 -2
  41. package/templates/commands/feature.md +113 -0
  42. package/templates/commands/fix.md +41 -10
  43. package/templates/commands/git.md +7 -2
  44. package/templates/commands/help.md +2 -2
  45. package/templates/commands/idea.md +14 -5
  46. package/templates/commands/init.md +62 -7
  47. package/templates/commands/next.md +4 -2
  48. package/templates/commands/now.md +4 -2
  49. package/templates/commands/progress.md +27 -5
  50. package/templates/commands/recap.md +39 -10
  51. package/templates/commands/roadmap.md +19 -5
  52. package/templates/commands/ship.md +118 -16
  53. package/templates/commands/status.md +4 -2
  54. package/templates/commands/sync.md +19 -15
  55. package/templates/commands/task.md +4 -2
  56. package/templates/commands/test.md +5 -2
  57. package/templates/commands/workflow.md +4 -2
  58. package/core/agent-generator.js +0 -525
  59. package/core/analyzer.js +0 -600
  60. package/core/animations.js +0 -277
  61. package/core/ascii-graphics.js +0 -433
  62. package/core/git-integration.js +0 -401
  63. package/core/task-schema.js +0 -342
  64. package/core/workflow-engine.js +0 -213
  65. package/core/workflow-prompts.js +0 -192
  66. package/core/workflow-rules.js +0 -147
  67. package/scripts/post-install.js +0 -121
  68. package/scripts/preuninstall.js +0 -94
  69. package/scripts/verify-installation.sh +0 -158
  70. package/templates/agents/be.template.md +0 -27
  71. package/templates/agents/coordinator.template.md +0 -34
  72. package/templates/agents/data.template.md +0 -27
  73. package/templates/agents/devops.template.md +0 -27
  74. package/templates/agents/fe.template.md +0 -27
  75. package/templates/agents/mobile.template.md +0 -27
  76. package/templates/agents/qa.template.md +0 -27
  77. package/templates/agents/scribe.template.md +0 -29
  78. package/templates/agents/security.template.md +0 -27
  79. package/templates/agents/ux.template.md +0 -27
  80. package/templates/commands/context.md +0 -36
  81. package/templates/commands/stuck.md +0 -36
  82. package/templates/examples/natural-language-examples.md +0 -532
  83. /package/core/{agent-detector.js → infrastructure/agent-detector.js} +0 -0
@@ -1,342 +0,0 @@
1
- /**
2
- * Task Metadata Schema and Agent Types
3
- *
4
- * Defines the structure for task tracking with agent assignment,
5
- * time estimation, and complexity scoring.
6
- *
7
- * @version 0.6.0
8
- */
9
-
10
- /**
11
- * Agent Types - Technical specialists for task assignment
12
- */
13
- const AGENT_TYPES = {
14
- 'backend-architect': {
15
- name: 'Backend Architect',
16
- specialization: 'Server-side architecture, APIs, databases',
17
- keywords: ['api', 'backend', 'server', 'database', 'endpoint', 'migration', 'schema'],
18
- icon: '🏗️',
19
- estimatedEfficiency: 1.0, // baseline
20
- },
21
- 'frontend-developer': {
22
- name: 'Frontend Developer',
23
- specialization: 'UI/UX, components, responsive design',
24
- keywords: ['ui', 'frontend', 'component', 'design', 'layout', 'responsive', 'css', 'style'],
25
- icon: '🎨',
26
- estimatedEfficiency: 1.0,
27
- },
28
- 'fullstack-engineer': {
29
- name: 'Fullstack Engineer',
30
- specialization: 'End-to-end feature development',
31
- keywords: ['fullstack', 'feature', 'integration', 'end-to-end', 'complete'],
32
- icon: '⚡',
33
- estimatedEfficiency: 0.9, // slightly slower due to context switching
34
- },
35
- 'devops-specialist': {
36
- name: 'DevOps Specialist',
37
- specialization: 'CI/CD, deployment, infrastructure',
38
- keywords: ['deploy', 'ci/cd', 'docker', 'kubernetes', 'infrastructure', 'pipeline', 'build'],
39
- icon: '🚀',
40
- estimatedEfficiency: 1.1, // faster at automation
41
- },
42
- 'security-engineer': {
43
- name: 'Security Engineer',
44
- specialization: 'Authentication, authorization, security',
45
- keywords: [
46
- 'auth',
47
- 'security',
48
- 'authentication',
49
- 'authorization',
50
- 'encryption',
51
- 'jwt',
52
- 'oauth',
53
- ],
54
- icon: '🔒',
55
- estimatedEfficiency: 0.8, // slower due to thorough security review
56
- },
57
- 'data-engineer': {
58
- name: 'Data Engineer',
59
- specialization: 'Data processing, analytics, ETL',
60
- keywords: ['data', 'analytics', 'etl', 'pipeline', 'processing', 'warehouse', 'query'],
61
- icon: '📊',
62
- estimatedEfficiency: 0.9,
63
- },
64
- 'qa-engineer': {
65
- name: 'QA Engineer',
66
- specialization: 'Testing, quality assurance, automation',
67
- keywords: ['test', 'testing', 'qa', 'quality', 'automation', 'e2e', 'integration'],
68
- icon: '🧪',
69
- estimatedEfficiency: 1.0,
70
- },
71
- 'performance-engineer': {
72
- name: 'Performance Engineer',
73
- specialization: 'Optimization, scaling, performance',
74
- keywords: ['performance', 'optimize', 'scaling', 'cache', 'speed', 'bottleneck'],
75
- icon: '⚡',
76
- estimatedEfficiency: 0.85, // slower due to profiling and measurement
77
- },
78
- 'general-developer': {
79
- name: 'General Developer',
80
- specialization: 'General-purpose development',
81
- keywords: ['fix', 'update', 'improve', 'refactor', 'cleanup'],
82
- icon: '👨‍💻',
83
- estimatedEfficiency: 1.0,
84
- },
85
- }
86
-
87
- /**
88
- * Complexity Levels
89
- */
90
- const COMPLEXITY = {
91
- trivial: {
92
- level: 1,
93
- name: 'Trivial',
94
- description: 'Simple changes, typos, configuration',
95
- estimatedHours: 0.5,
96
- multiplier: 0.5,
97
- examples: ['Fix typo', 'Update config value', 'Change color'],
98
- },
99
- simple: {
100
- level: 2,
101
- name: 'Simple',
102
- description: 'Straightforward implementation, single file',
103
- estimatedHours: 2,
104
- multiplier: 1.0,
105
- examples: ['Add validation', 'Create simple component', 'Update documentation'],
106
- },
107
- moderate: {
108
- level: 3,
109
- name: 'Moderate',
110
- description: 'Multiple files, some complexity',
111
- estimatedHours: 4,
112
- multiplier: 2.0,
113
- examples: ['Implement new feature', 'Refactor module', 'Add API endpoint'],
114
- },
115
- complex: {
116
- level: 4,
117
- name: 'Complex',
118
- description: 'System-wide changes, architecture',
119
- estimatedHours: 8,
120
- multiplier: 4.0,
121
- examples: ['Authentication system', 'Database migration', 'Performance optimization'],
122
- },
123
- epic: {
124
- level: 5,
125
- name: 'Epic',
126
- description: 'Major feature, multiple systems',
127
- estimatedHours: 16,
128
- multiplier: 8.0,
129
- examples: ['Payment integration', 'Real-time messaging', 'Admin dashboard'],
130
- },
131
- }
132
-
133
- /**
134
- * Task Status
135
- */
136
- const TASK_STATUS = {
137
- pending: 'Waiting to start',
138
- active: 'Currently working on',
139
- blocked: 'Blocked by dependency',
140
- completed: 'Successfully finished',
141
- cancelled: 'Cancelled/discarded',
142
- }
143
-
144
- /**
145
- * Task Schema
146
- */
147
- class TaskSchema {
148
- /**
149
- * Create a new task
150
- */
151
- static create(data) {
152
- const now = new Date().toISOString()
153
-
154
- return {
155
- id: data.id || this.generateId(),
156
- title: data.title,
157
- description: data.description || null,
158
-
159
- // Agent & Developer
160
- assignedAgent: data.assignedAgent || this.detectAgent(data.title),
161
- githubDev: data.githubDev || null, // Will be populated from git config
162
-
163
- // Complexity & Time
164
- complexity: data.complexity || this.estimateComplexity(data.title, data.description),
165
- estimatedTime: data.estimatedTime || this.estimateTime(data.complexity),
166
- actualTime: null,
167
-
168
- // Status & Tracking
169
- status: data.status || 'pending',
170
- priority: data.priority || 5,
171
- blocked: data.blocked || false,
172
- blockedBy: data.blockedBy || null,
173
-
174
- // Timestamps
175
- createdAt: data.createdAt || now,
176
- startedAt: data.startedAt || null,
177
- completedAt: data.completedAt || null,
178
-
179
- // Metadata
180
- tags: data.tags || [],
181
- notes: data.notes || null,
182
- }
183
- }
184
-
185
- /**
186
- * Generate unique task ID
187
- */
188
- static generateId() {
189
- return `task-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`
190
- }
191
-
192
- /**
193
- * Auto-detect appropriate agent based on task description
194
- */
195
- static detectAgent(title, description = '') {
196
- const text = `${title} ${description}`.toLowerCase()
197
- let bestMatch = 'general-developer'
198
- let highestScore = 0
199
-
200
- for (const [agentType, config] of Object.entries(AGENT_TYPES)) {
201
- const score = config.keywords.filter((keyword) => text.includes(keyword)).length
202
-
203
- if (score > highestScore) {
204
- highestScore = score
205
- bestMatch = agentType
206
- }
207
- }
208
-
209
- return bestMatch
210
- }
211
-
212
- /**
213
- * Estimate complexity based on keywords and description
214
- */
215
- static estimateComplexity(title, description = '') {
216
- const text = `${title} ${description}`.toLowerCase()
217
-
218
- // Epic indicators
219
- if (
220
- text.match(
221
- /system|payment|real-time|dashboard|integration|authentication|migration|architecture/i,
222
- )
223
- ) {
224
- return 'epic'
225
- }
226
-
227
- // Complex indicators
228
- if (text.match(/refactor|optimization|security|database|multiple|complex/i)) {
229
- return 'complex'
230
- }
231
-
232
- // Moderate indicators
233
- if (text.match(/feature|implement|api|endpoint|component|module/i)) {
234
- return 'moderate'
235
- }
236
-
237
- // Simple indicators
238
- if (text.match(/add|update|fix|change|simple|small/i)) {
239
- return 'simple'
240
- }
241
-
242
- // Trivial indicators
243
- if (text.match(/typo|config|color|text|minor|tiny/i)) {
244
- return 'trivial'
245
- }
246
-
247
- return 'simple' // default
248
- }
249
-
250
- /**
251
- * Estimate time based on complexity and agent efficiency
252
- */
253
- static estimateTime(complexity, agentType = 'general-developer') {
254
- const complexityData = COMPLEXITY[complexity]
255
- const agentData = AGENT_TYPES[agentType]
256
-
257
- if (!complexityData || !agentData) {
258
- return '2-4 hours'
259
- }
260
-
261
- const baseHours = complexityData.estimatedHours
262
- const adjustedHours = baseHours * agentData.estimatedEfficiency
263
-
264
- // Format as range
265
- const low = Math.floor(adjustedHours * 0.75)
266
- const high = Math.ceil(adjustedHours * 1.25)
267
-
268
- if (adjustedHours < 1) {
269
- return `${Math.round(adjustedHours * 60)} minutes`
270
- }
271
-
272
- return `${low}-${high} hours`
273
- }
274
-
275
- /**
276
- * Start a task (move to active)
277
- */
278
- static start(task) {
279
- return {
280
- ...task,
281
- status: 'active',
282
- startedAt: new Date().toISOString(),
283
- }
284
- }
285
-
286
- /**
287
- * Complete a task
288
- */
289
- static complete(task) {
290
- const completedAt = new Date().toISOString()
291
- const actualTime = this.calculateActualTime(task.startedAt, completedAt)
292
-
293
- return {
294
- ...task,
295
- status: 'completed',
296
- completedAt,
297
- actualTime,
298
- }
299
- }
300
-
301
- /**
302
- * Calculate actual time spent
303
- */
304
- static calculateActualTime(startedAt, completedAt) {
305
- if (!startedAt) return null
306
-
307
- const start = new Date(startedAt)
308
- const end = new Date(completedAt)
309
- const diffMs = end - start
310
- const hours = Math.floor(diffMs / (1000 * 60 * 60))
311
- const minutes = Math.floor((diffMs % (1000 * 60 * 60)) / (1000 * 60))
312
-
313
- if (hours === 0) {
314
- return `${minutes}m`
315
- }
316
- return `${hours}h ${minutes}m`
317
- }
318
-
319
- /**
320
- * Validate task schema
321
- */
322
- static validate(task) {
323
- const errors = []
324
-
325
- if (!task.title) errors.push('Task title is required')
326
- if (!AGENT_TYPES[task.assignedAgent]) errors.push('Invalid agent type')
327
- if (!COMPLEXITY[task.complexity]) errors.push('Invalid complexity level')
328
- if (!TASK_STATUS[task.status]) errors.push('Invalid task status')
329
-
330
- return {
331
- valid: errors.length === 0,
332
- errors,
333
- }
334
- }
335
- }
336
-
337
- module.exports = {
338
- TaskSchema,
339
- AGENT_TYPES,
340
- COMPLEXITY,
341
- TASK_STATUS,
342
- }
@@ -1,213 +0,0 @@
1
- /**
2
- * Workflow Engine
3
- * Orchestrates adaptive agent workflows based on project capabilities
4
- */
5
-
6
- const fs = require('fs').promises
7
- const path = require('path')
8
- const capabilities = require('./project-capabilities')
9
- const rules = require('./workflow-rules')
10
-
11
- class WorkflowEngine {
12
- /**
13
- * Initialize workflow for task
14
- * @param {string} task - Task description
15
- * @param {string} type - Workflow type (ui, api, bug, refactor, feature)
16
- * @param {string} dataPath - Project data path
17
- * @returns {Promise<Object>} Workflow object
18
- */
19
- async init(task, type, dataPath) {
20
- // Detect project capabilities
21
- const projectPath = path.dirname(path.dirname(dataPath))
22
- const caps = await capabilities.detect(projectPath)
23
-
24
- // Get base workflow
25
- const base = rules[type] || rules.ui
26
-
27
- // Map all steps - mark for prompting if capability missing
28
- const steps = base.map((s, index) => ({
29
- ...s,
30
- index,
31
- status: 'pending',
32
- skipped: false,
33
- needsPrompt: !s.required && s.prompt && !caps[s.needs],
34
- }))
35
-
36
- // Track which capabilities are missing
37
- const missingCapabilities = base
38
- .filter(s => !s.required && s.needs && !caps[s.needs])
39
- .map(s => s.needs)
40
-
41
- const workflow = {
42
- task,
43
- type,
44
- caps,
45
- steps,
46
- missingCapabilities,
47
- current: 0,
48
- active: true,
49
- createdAt: new Date().toISOString(),
50
- }
51
-
52
- await this.save(workflow, dataPath)
53
- return workflow
54
- }
55
-
56
- /**
57
- * Get current step info
58
- */
59
- async getCurrent(dataPath) {
60
- const wf = await this.load(dataPath)
61
- if (!wf || !wf.active) return null
62
-
63
- return wf.steps[wf.current]
64
- }
65
-
66
- /**
67
- * Advance to next step
68
- */
69
- async next(dataPath) {
70
- const wf = await this.load(dataPath)
71
- if (!wf) return null
72
-
73
- // Mark current step as completed
74
- wf.steps[wf.current].status = 'completed'
75
- wf.steps[wf.current].completedAt = new Date().toISOString()
76
-
77
- // Move to next
78
- wf.current++
79
-
80
- // Check if workflow complete
81
- if (wf.current >= wf.steps.length) {
82
- wf.active = false
83
- wf.completedAt = new Date().toISOString()
84
- await this.save(wf, dataPath)
85
- return null
86
- }
87
-
88
- // Mark next step as in progress
89
- wf.steps[wf.current].status = 'in_progress'
90
- wf.steps[wf.current].startedAt = new Date().toISOString()
91
-
92
- await this.save(wf, dataPath)
93
- return wf.steps[wf.current]
94
- }
95
-
96
- /**
97
- * Skip current step
98
- */
99
- async skip(dataPath, reason = 'User skipped') {
100
- const wf = await this.load(dataPath)
101
- if (!wf) return null
102
-
103
- wf.steps[wf.current].skipped = true
104
- wf.steps[wf.current].status = 'skipped'
105
- wf.steps[wf.current].skipReason = reason
106
- wf.steps[wf.current].skippedAt = new Date().toISOString()
107
-
108
- return await this.next(dataPath)
109
- }
110
-
111
- /**
112
- * Insert installation step before current step
113
- */
114
- async insertInstall(dataPath, installTask) {
115
- const wf = await this.load(dataPath)
116
- if (!wf) return null
117
-
118
- const currentIndex = wf.current
119
-
120
- // Insert install task at current position
121
- wf.steps.splice(currentIndex, 0, {
122
- ...installTask,
123
- index: currentIndex,
124
- status: 'in_progress',
125
- insertedAt: new Date().toISOString(),
126
- })
127
-
128
- // Reindex all subsequent steps
129
- for (let i = currentIndex + 1; i < wf.steps.length; i++) {
130
- wf.steps[i].index = i
131
- }
132
-
133
- await this.save(wf, dataPath)
134
- return wf.steps[currentIndex]
135
- }
136
-
137
- /**
138
- * Classify task type from description
139
- * @param {string} text - Task description
140
- * @returns {string} Workflow type
141
- */
142
- classify(text) {
143
- const t = text.toLowerCase()
144
-
145
- if (/button|form|modal|card|component|menu|nav|input/.test(t)) return 'ui'
146
- if (/endpoint|api|service|route|controller/.test(t)) return 'api'
147
- if (/bug|fix|error|issue|broken/.test(t)) return 'bug'
148
- if (/refactor|improve|optimize|clean/.test(t)) return 'refactor'
149
- if (/feature|functionality|module/.test(t)) return 'feature'
150
-
151
- return 'ui' // Default
152
- }
153
-
154
- /**
155
- * Get workflow status
156
- */
157
- async getStatus(dataPath) {
158
- const wf = await this.load(dataPath)
159
- if (!wf) return null
160
-
161
- return {
162
- task: wf.task,
163
- type: wf.type,
164
- active: wf.active,
165
- current: wf.current,
166
- total: wf.steps.length,
167
- steps: wf.steps.map(s => ({
168
- name: s.name,
169
- status: s.status,
170
- agent: s.agent,
171
- })),
172
- skipped: wf.skipped,
173
- }
174
- }
175
-
176
- /**
177
- * Load workflow from file
178
- */
179
- async load(dataPath) {
180
- try {
181
- const workflowPath = path.join(dataPath, 'workflow', 'state.json')
182
- const content = await fs.readFile(workflowPath, 'utf8')
183
- return JSON.parse(content)
184
- } catch {
185
- return null
186
- }
187
- }
188
-
189
- /**
190
- * Save workflow to file
191
- */
192
- async save(workflow, dataPath) {
193
- const workflowDir = path.join(dataPath, 'workflow')
194
- await fs.mkdir(workflowDir, { recursive: true })
195
-
196
- const workflowPath = path.join(workflowDir, 'state.json')
197
- await fs.writeFile(workflowPath, JSON.stringify(workflow, null, 2))
198
- }
199
-
200
- /**
201
- * Clear workflow
202
- */
203
- async clear(dataPath) {
204
- try {
205
- const workflowPath = path.join(dataPath, 'workflow', 'state.json')
206
- await fs.unlink(workflowPath)
207
- } catch {
208
- // Ignore if doesn't exist
209
- }
210
- }
211
- }
212
-
213
- module.exports = new WorkflowEngine()