prjct-cli 0.10.6 → 0.10.9
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.
- package/CHANGELOG.md +107 -0
- package/core/__tests__/agentic/prompt-builder.test.js +244 -0
- package/core/__tests__/utils/output.test.js +163 -0
- package/core/agentic/agent-router.js +45 -173
- package/core/agentic/context-builder.js +25 -15
- package/core/agentic/context-filter.js +118 -313
- package/core/agentic/prompt-builder.js +90 -46
- package/core/commands.js +121 -637
- package/core/domain/agent-generator.js +55 -4
- package/core/domain/analyzer.js +122 -0
- package/core/domain/context-estimator.js +32 -53
- package/core/domain/smart-cache.js +2 -1
- package/core/domain/task-analyzer.js +75 -146
- package/core/domain/task-stack.js +2 -1
- package/core/utils/logger.js +64 -0
- package/core/utils/output.js +54 -0
- package/package.json +1 -1
- package/templates/agentic/agent-routing.md +78 -0
- package/templates/agentic/context-filtering.md +77 -0
- package/templates/analysis/patterns.md +206 -0
- package/templates/analysis/project-analysis.md +78 -0
- package/templates/commands/sync.md +61 -7
- package/core/domain/tech-detector.js +0 -365
package/core/commands.js
CHANGED
|
@@ -32,6 +32,7 @@ const { VERSION } = require('./utils/version')
|
|
|
32
32
|
const dateHelper = require('./utils/date-helper')
|
|
33
33
|
const jsonlHelper = require('./utils/jsonl-helper')
|
|
34
34
|
const fileHelper = require('./utils/file-helper')
|
|
35
|
+
const out = require('./utils/output')
|
|
35
36
|
|
|
36
37
|
/**
|
|
37
38
|
* Agentic Commands - Template-driven execution
|
|
@@ -73,15 +74,11 @@ class PrjctCommands {
|
|
|
73
74
|
return { success: true }
|
|
74
75
|
}
|
|
75
76
|
|
|
76
|
-
|
|
77
|
-
console.log('🔧 Running prjct init...\n')
|
|
78
|
-
|
|
77
|
+
out.spin('initializing project...')
|
|
79
78
|
const initResult = await this.init(null, projectPath)
|
|
80
79
|
if (!initResult.success) {
|
|
81
80
|
return initResult
|
|
82
81
|
}
|
|
83
|
-
|
|
84
|
-
console.log('✅ Project initialized!\n')
|
|
85
82
|
return { success: true }
|
|
86
83
|
}
|
|
87
84
|
|
|
@@ -145,10 +142,7 @@ class PrjctCommands {
|
|
|
145
142
|
const nowContent = `# NOW\n\n**${task}**\n\nStarted: ${new Date().toLocaleString()}\n`
|
|
146
143
|
await toolRegistry.get('Write')(context.paths.now, nowContent)
|
|
147
144
|
|
|
148
|
-
|
|
149
|
-
console.log(`Started: ${new Date().toLocaleTimeString()}\n`)
|
|
150
|
-
console.log('Done? → /p:done')
|
|
151
|
-
console.log('Stuck? → /p:stuck')
|
|
145
|
+
out.done(`${task} (started)`)
|
|
152
146
|
|
|
153
147
|
await this.logToMemory(projectPath, 'task_started', {
|
|
154
148
|
task,
|
|
@@ -160,18 +154,18 @@ class PrjctCommands {
|
|
|
160
154
|
const nowContent = await toolRegistry.get('Read')(context.paths.now)
|
|
161
155
|
|
|
162
156
|
if (!nowContent || nowContent.includes('No current task')) {
|
|
163
|
-
|
|
164
|
-
console.log('\nStart something:')
|
|
165
|
-
console.log('• /p:now "task description"')
|
|
166
|
-
console.log('• /p:next (see queue)')
|
|
157
|
+
out.warn('no active task')
|
|
167
158
|
return { success: true, message: 'No active task' }
|
|
168
159
|
}
|
|
169
160
|
|
|
170
|
-
|
|
161
|
+
// Extract task name for minimal output
|
|
162
|
+
const taskMatch = nowContent.match(/\*\*(.+?)\*\*/)
|
|
163
|
+
const currentTask = taskMatch ? taskMatch[1] : 'unknown'
|
|
164
|
+
out.done(`working on: ${currentTask}`)
|
|
171
165
|
return { success: true, content: nowContent }
|
|
172
166
|
}
|
|
173
167
|
} catch (error) {
|
|
174
|
-
|
|
168
|
+
out.fail(error.message)
|
|
175
169
|
return { success: false, error: error.message }
|
|
176
170
|
}
|
|
177
171
|
}
|
|
@@ -190,11 +184,7 @@ class PrjctCommands {
|
|
|
190
184
|
|
|
191
185
|
// Validate: must have active task
|
|
192
186
|
if (!nowContent || nowContent.includes('No current task') || nowContent.trim() === '# NOW') {
|
|
193
|
-
|
|
194
|
-
console.log('\nStart something:')
|
|
195
|
-
console.log('• "start [task]" → begin working')
|
|
196
|
-
console.log('• /p:now "task" → set focus')
|
|
197
|
-
console.log('• /p:next → see queue')
|
|
187
|
+
out.warn('no active task')
|
|
198
188
|
return { success: true, message: 'No active task to complete' }
|
|
199
189
|
}
|
|
200
190
|
|
|
@@ -213,11 +203,7 @@ class PrjctCommands {
|
|
|
213
203
|
const emptyNow = '# NOW\n\nNo current task. Use `/p:now` to set focus.\n'
|
|
214
204
|
await toolRegistry.get('Write')(context.paths.now, emptyNow)
|
|
215
205
|
|
|
216
|
-
|
|
217
|
-
console.log("\nWhat's next?")
|
|
218
|
-
console.log('• "start next task" → Begin working')
|
|
219
|
-
console.log('• "ship this feature" → Track & celebrate')
|
|
220
|
-
console.log('• /p:now | /p:ship')
|
|
206
|
+
out.done(`${task}${duration ? ` (${duration})` : ''}`)
|
|
221
207
|
|
|
222
208
|
await this.logToMemory(projectPath, 'task_completed', {
|
|
223
209
|
task,
|
|
@@ -226,7 +212,7 @@ class PrjctCommands {
|
|
|
226
212
|
})
|
|
227
213
|
return { success: true, task, duration }
|
|
228
214
|
} catch (error) {
|
|
229
|
-
|
|
215
|
+
out.fail(error.message)
|
|
230
216
|
return { success: false, error: error.message }
|
|
231
217
|
}
|
|
232
218
|
}
|
|
@@ -244,27 +230,17 @@ class PrjctCommands {
|
|
|
244
230
|
const nextContent = await toolRegistry.get('Read')(context.paths.next)
|
|
245
231
|
|
|
246
232
|
if (!nextContent || nextContent.trim() === '# NEXT\n\n## Priority Queue') {
|
|
247
|
-
|
|
248
|
-
console.log('\nAdd tasks:')
|
|
249
|
-
console.log('• /p:feature "description" → Add feature with roadmap')
|
|
250
|
-
console.log('• /p:bug "description" → Report bug')
|
|
233
|
+
out.warn('queue empty')
|
|
251
234
|
return { success: true, message: 'Queue is empty' }
|
|
252
235
|
}
|
|
253
236
|
|
|
254
|
-
//
|
|
255
|
-
const
|
|
256
|
-
|
|
257
|
-
console.log('⚠️ You have an active task. Complete it with /p:done first.\n')
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
console.log(nextContent)
|
|
261
|
-
console.log('\nStart a task:')
|
|
262
|
-
console.log('• /p:build "task name" → Start task with tracking')
|
|
263
|
-
console.log('• /p:build 1 → Start first task')
|
|
237
|
+
// Count tasks for minimal output
|
|
238
|
+
const taskCount = (nextContent.match(/^- \[/gm) || []).length
|
|
239
|
+
out.done(`${taskCount} task${taskCount !== 1 ? 's' : ''} queued`)
|
|
264
240
|
|
|
265
241
|
return { success: true, content: nextContent }
|
|
266
242
|
} catch (error) {
|
|
267
|
-
|
|
243
|
+
out.fail(error.message)
|
|
268
244
|
return { success: false, error: error.message }
|
|
269
245
|
}
|
|
270
246
|
}
|
|
@@ -286,12 +262,11 @@ class PrjctCommands {
|
|
|
286
262
|
const isConfigured = await configManager.isConfigured(projectPath)
|
|
287
263
|
|
|
288
264
|
if (isConfigured) {
|
|
289
|
-
|
|
290
|
-
console.log('Use /p:sync to regenerate agents or /p:analyze to update analysis')
|
|
265
|
+
out.warn('already initialized')
|
|
291
266
|
return { success: false, message: 'Already initialized' }
|
|
292
267
|
}
|
|
293
268
|
|
|
294
|
-
|
|
269
|
+
out.spin('initializing...')
|
|
295
270
|
|
|
296
271
|
// Detect author from git
|
|
297
272
|
const author = await authorDetector.detect()
|
|
@@ -300,7 +275,7 @@ class PrjctCommands {
|
|
|
300
275
|
const config = await configManager.createConfig(projectPath, author)
|
|
301
276
|
const projectId = config.projectId
|
|
302
277
|
|
|
303
|
-
|
|
278
|
+
out.spin('creating structure...')
|
|
304
279
|
|
|
305
280
|
// Ensure global structure exists
|
|
306
281
|
await pathManager.ensureProjectStructure(projectId)
|
|
@@ -331,7 +306,6 @@ class PrjctCommands {
|
|
|
331
306
|
await toolRegistry.get('Write')(path.join(globalPath, filePath), content)
|
|
332
307
|
}
|
|
333
308
|
|
|
334
|
-
console.log(`✅ Global structure created: ${pathManager.getDisplayPath(globalPath)}`)
|
|
335
309
|
|
|
336
310
|
// Detect project state
|
|
337
311
|
const isEmpty = await this._detectEmptyDirectory(projectPath)
|
|
@@ -339,21 +313,13 @@ class PrjctCommands {
|
|
|
339
313
|
|
|
340
314
|
// MODE 1: Existing project
|
|
341
315
|
if (hasCode || !isEmpty) {
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
// Run analysis
|
|
316
|
+
out.spin('analyzing project...')
|
|
345
317
|
const analysisResult = await this.analyze({}, projectPath)
|
|
346
318
|
|
|
347
319
|
if (analysisResult.success) {
|
|
348
|
-
|
|
320
|
+
out.spin('generating agents...')
|
|
349
321
|
await this.sync(projectPath)
|
|
350
|
-
|
|
351
|
-
console.log('\n✅ prjct initialized!\n')
|
|
352
|
-
console.log('Ready to work! What feature shall we add?')
|
|
353
|
-
console.log('\nNext steps:')
|
|
354
|
-
console.log('• /p:feature → Add a feature')
|
|
355
|
-
console.log('• /p:now → Start working on something')
|
|
356
|
-
|
|
322
|
+
out.done('initialized')
|
|
357
323
|
return { success: true, mode: 'existing', projectId }
|
|
358
324
|
}
|
|
359
325
|
}
|
|
@@ -361,38 +327,20 @@ class PrjctCommands {
|
|
|
361
327
|
// MODE 2 & 3: Blank project
|
|
362
328
|
if (isEmpty && !hasCode) {
|
|
363
329
|
if (!idea) {
|
|
364
|
-
|
|
365
|
-
console.log('\n📐 Blank project - ARCHITECT MODE available\n')
|
|
366
|
-
console.log('Provide your project idea to activate architect mode:')
|
|
367
|
-
console.log('Example: /p:init "dynamic portfolio website"\n')
|
|
368
|
-
console.log('Or analyze an existing project by adding code first.')
|
|
369
|
-
|
|
330
|
+
out.done('blank project - provide idea for architect mode')
|
|
370
331
|
return { success: true, mode: 'blank_no_idea', projectId }
|
|
371
332
|
}
|
|
372
333
|
|
|
373
334
|
// MODE 2: ARCHITECT MODE
|
|
374
|
-
|
|
375
|
-
console.log(`Your idea: "${idea}"\n`)
|
|
376
|
-
|
|
377
|
-
// Save architect session
|
|
335
|
+
out.spin('architect mode...')
|
|
378
336
|
const sessionPath = path.join(globalPath, 'planning', 'architect-session.md')
|
|
379
337
|
const sessionContent = `# Architect Session\n\n## Idea\n${idea}\n\n## Status\nInitialized - awaiting stack recommendation\n\nGenerated: ${new Date().toLocaleString()}\n`
|
|
380
338
|
await toolRegistry.get('Write')(sessionPath, sessionContent)
|
|
381
339
|
|
|
382
|
-
console.log('🤖 Analyzing your idea and recommending tech stack...\n')
|
|
383
|
-
console.log('Recommended stacks:')
|
|
384
|
-
console.log(
|
|
385
|
-
' Option 1: Next.js + TypeScript + Tailwind (⭐ Recommended for modern web apps)'
|
|
386
|
-
)
|
|
387
|
-
console.log(' Option 2: React + Vite + shadcn/ui (Fast, minimal)')
|
|
388
|
-
console.log(' Option 3: Vue 3 + Nuxt (Great DX)')
|
|
389
|
-
console.log(' Custom: Describe your preferred stack\n')
|
|
390
|
-
console.log('Which option do you prefer? (Respond to continue setup)')
|
|
391
|
-
|
|
392
|
-
// Update global CLAUDE.md with latest instructions
|
|
393
340
|
const commandInstaller = require('./infrastructure/command-installer')
|
|
394
341
|
await commandInstaller.installGlobalConfig()
|
|
395
342
|
|
|
343
|
+
out.done('architect mode ready')
|
|
396
344
|
return { success: true, mode: 'architect', projectId, idea }
|
|
397
345
|
}
|
|
398
346
|
|
|
@@ -400,9 +348,10 @@ class PrjctCommands {
|
|
|
400
348
|
const commandInstaller = require('./infrastructure/command-installer')
|
|
401
349
|
await commandInstaller.installGlobalConfig()
|
|
402
350
|
|
|
351
|
+
out.done('initialized')
|
|
403
352
|
return { success: true, projectId }
|
|
404
353
|
} catch (error) {
|
|
405
|
-
|
|
354
|
+
out.fail(error.message)
|
|
406
355
|
return { success: false, error: error.message }
|
|
407
356
|
}
|
|
408
357
|
}
|
|
@@ -467,31 +416,17 @@ class PrjctCommands {
|
|
|
467
416
|
if (!initResult.success) return initResult
|
|
468
417
|
|
|
469
418
|
if (!description) {
|
|
470
|
-
|
|
471
|
-
console.log('Usage: /p:feature "description"')
|
|
419
|
+
out.fail('description required')
|
|
472
420
|
return { success: false, error: 'Description required' }
|
|
473
421
|
}
|
|
474
422
|
|
|
475
|
-
|
|
423
|
+
out.spin(`planning ${description}...`)
|
|
476
424
|
|
|
477
425
|
const context = await contextBuilder.build(projectPath, { description })
|
|
478
426
|
|
|
479
|
-
//
|
|
480
|
-
console.log('📊 Value Analysis:')
|
|
481
|
-
console.log(` • Feature: ${description}`)
|
|
482
|
-
console.log(' • Impact: Analyzing...')
|
|
483
|
-
console.log(' • Effort: Estimating...')
|
|
484
|
-
console.log(' • Timing: Evaluating...\n')
|
|
485
|
-
|
|
486
|
-
// Task breakdown (Claude would generate based on feature complexity)
|
|
427
|
+
// Task breakdown
|
|
487
428
|
const tasks = this._breakdownFeatureTasks(description)
|
|
488
429
|
|
|
489
|
-
console.log('📋 Task Breakdown:')
|
|
490
|
-
tasks.forEach((task, i) => {
|
|
491
|
-
console.log(` ${i + 1}. ${task}`)
|
|
492
|
-
})
|
|
493
|
-
console.log('')
|
|
494
|
-
|
|
495
430
|
// Write to next.md
|
|
496
431
|
const nextContent =
|
|
497
432
|
(await toolRegistry.get('Read')(context.paths.next)) || '# NEXT\n\n## Priority Queue\n\n'
|
|
@@ -509,14 +444,11 @@ class PrjctCommands {
|
|
|
509
444
|
timestamp: dateHelper.getTimestamp(),
|
|
510
445
|
})
|
|
511
446
|
|
|
512
|
-
|
|
513
|
-
console.log('Ready to start?')
|
|
514
|
-
console.log(`• /p:now "${tasks[0]}" → Start first task`)
|
|
515
|
-
console.log('• /p:next → See all tasks')
|
|
447
|
+
out.done(`${tasks.length} tasks created`)
|
|
516
448
|
|
|
517
449
|
return { success: true, feature: description, tasks }
|
|
518
450
|
} catch (error) {
|
|
519
|
-
|
|
451
|
+
out.fail(error.message)
|
|
520
452
|
return { success: false, error: error.message }
|
|
521
453
|
}
|
|
522
454
|
}
|
|
@@ -570,23 +502,15 @@ class PrjctCommands {
|
|
|
570
502
|
if (!initResult.success) return initResult
|
|
571
503
|
|
|
572
504
|
if (!description) {
|
|
573
|
-
|
|
574
|
-
console.log('Usage: /p:bug "description"')
|
|
505
|
+
out.fail('bug description required')
|
|
575
506
|
return { success: false, error: 'Description required' }
|
|
576
507
|
}
|
|
577
508
|
|
|
578
|
-
|
|
509
|
+
out.spin('tracking bug...')
|
|
579
510
|
|
|
580
511
|
const context = await contextBuilder.build(projectPath, { description })
|
|
581
|
-
|
|
582
|
-
// Auto-detect severity (simplified - Claude would do deeper analysis)
|
|
583
512
|
const severity = this._detectBugSeverity(description)
|
|
584
513
|
|
|
585
|
-
console.log(`📊 Severity: ${severity.toUpperCase()}`)
|
|
586
|
-
console.log(
|
|
587
|
-
` Priority: ${severity === 'critical' ? 'URGENT' : severity === 'high' ? 'High' : 'Normal'}\n`
|
|
588
|
-
)
|
|
589
|
-
|
|
590
514
|
// Add to next.md with priority
|
|
591
515
|
const nextContent =
|
|
592
516
|
(await toolRegistry.get('Read')(context.paths.next)) || '# NEXT\n\n## Priority Queue\n\n'
|
|
@@ -607,14 +531,11 @@ class PrjctCommands {
|
|
|
607
531
|
timestamp: dateHelper.getTimestamp(),
|
|
608
532
|
})
|
|
609
533
|
|
|
610
|
-
|
|
611
|
-
console.log('Next steps:')
|
|
612
|
-
console.log('• /p:now "fix bug" → Start fixing')
|
|
613
|
-
console.log('• /p:next → See all tasks')
|
|
534
|
+
out.done(`bug [${severity}] tracked`)
|
|
614
535
|
|
|
615
536
|
return { success: true, bug: description, severity }
|
|
616
537
|
} catch (error) {
|
|
617
|
-
|
|
538
|
+
out.fail(error.message)
|
|
618
539
|
return { success: false, error: error.message }
|
|
619
540
|
}
|
|
620
541
|
}
|
|
@@ -663,39 +584,27 @@ class PrjctCommands {
|
|
|
663
584
|
}
|
|
664
585
|
}
|
|
665
586
|
|
|
666
|
-
|
|
587
|
+
out.spin(`shipping ${feature}...`)
|
|
667
588
|
|
|
668
|
-
// Step 1: Lint
|
|
669
|
-
console.log('1️⃣ Running lint checks...')
|
|
589
|
+
// Step 1: Lint
|
|
670
590
|
const lintResult = await this._runLint(projectPath)
|
|
671
|
-
console.log(` ${lintResult.success ? '✅' : '⚠️'} Lint: ${lintResult.message}`)
|
|
672
591
|
|
|
673
|
-
// Step 2: Tests
|
|
674
|
-
|
|
592
|
+
// Step 2: Tests
|
|
593
|
+
out.spin('running tests...')
|
|
675
594
|
const testResult = await this._runTests(projectPath)
|
|
676
|
-
console.log(` ${testResult.success ? '✅' : '⚠️'} Tests: ${testResult.message}`)
|
|
677
|
-
|
|
678
|
-
// Step 3-5: Update docs, version, changelog
|
|
679
|
-
console.log('3️⃣ Updating documentation...')
|
|
680
|
-
console.log(' ✅ Docs updated')
|
|
681
595
|
|
|
682
|
-
|
|
596
|
+
// Step 3-5: Version + changelog
|
|
597
|
+
out.spin('updating version...')
|
|
683
598
|
const newVersion = await this._bumpVersion(projectPath)
|
|
684
|
-
console.log(` ✅ Version: ${newVersion}`)
|
|
685
|
-
|
|
686
|
-
console.log('5️⃣ Updating CHANGELOG...')
|
|
687
599
|
await this._updateChangelog(feature, newVersion, projectPath)
|
|
688
|
-
console.log(' ✅ CHANGELOG updated')
|
|
689
600
|
|
|
690
601
|
// Step 6-7: Git commit + push
|
|
691
|
-
|
|
602
|
+
out.spin('committing...')
|
|
692
603
|
const commitResult = await this._createShipCommit(feature, projectPath)
|
|
693
|
-
console.log(` ${commitResult.success ? '✅' : '⚠️'} ${commitResult.message}`)
|
|
694
604
|
|
|
695
605
|
if (commitResult.success) {
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
console.log(` ${pushResult.success ? '✅' : '⚠️'} ${pushResult.message}`)
|
|
606
|
+
out.spin('pushing...')
|
|
607
|
+
await this._gitPush(projectPath)
|
|
699
608
|
}
|
|
700
609
|
|
|
701
610
|
// Log to memory and shipped.md
|
|
@@ -732,16 +641,11 @@ class PrjctCommands {
|
|
|
732
641
|
})
|
|
733
642
|
}
|
|
734
643
|
|
|
735
|
-
|
|
736
|
-
console.log('💡 Recommendation: Compact conversation now')
|
|
737
|
-
console.log(' (Keeps context clean for next feature)\n')
|
|
738
|
-
console.log('Next:')
|
|
739
|
-
console.log('• /p:feature → Add new feature')
|
|
740
|
-
console.log('• /p:recap → See progress')
|
|
644
|
+
out.done(`v${newVersion} shipped`)
|
|
741
645
|
|
|
742
646
|
return { success: true, feature, version: newVersion }
|
|
743
647
|
} catch (error) {
|
|
744
|
-
|
|
648
|
+
out.fail(error.message)
|
|
745
649
|
return { success: false, error: error.message }
|
|
746
650
|
}
|
|
747
651
|
}
|
|
@@ -851,92 +755,28 @@ class PrjctCommands {
|
|
|
851
755
|
const initResult = await this.ensureProjectInit(projectPath)
|
|
852
756
|
if (!initResult.success) return initResult
|
|
853
757
|
|
|
854
|
-
|
|
855
|
-
|
|
758
|
+
out.spin('loading context...')
|
|
856
759
|
const context = await contextBuilder.build(projectPath)
|
|
857
760
|
|
|
858
|
-
// Read current state files
|
|
859
761
|
const nowContent = await toolRegistry.get('Read')(context.paths.now)
|
|
860
762
|
const nextContent = await toolRegistry.get('Read')(context.paths.next)
|
|
861
|
-
const analysisContent = await toolRegistry.get('Read')(context.paths.analysis)
|
|
862
|
-
|
|
863
|
-
// Read memory (last 10 entries)
|
|
864
|
-
const projectId = await configManager.getProjectId(projectPath)
|
|
865
|
-
const memoryPath = pathManager.getFilePath(projectId, 'memory', 'context.jsonl')
|
|
866
|
-
let recentActivity = []
|
|
867
|
-
|
|
868
|
-
try {
|
|
869
|
-
const entries = await jsonlHelper.readJsonLines(memoryPath)
|
|
870
|
-
recentActivity = entries.slice(-10).reverse()
|
|
871
|
-
} catch {
|
|
872
|
-
recentActivity = []
|
|
873
|
-
}
|
|
874
763
|
|
|
875
|
-
//
|
|
876
|
-
|
|
764
|
+
// Extract summary
|
|
765
|
+
let task = 'none'
|
|
877
766
|
if (nowContent && !nowContent.includes('No current task')) {
|
|
878
767
|
const taskMatch = nowContent.match(/\*\*(.+?)\*\*/)
|
|
879
|
-
|
|
880
|
-
console.log(`🎯 ${task}\n`)
|
|
881
|
-
} else {
|
|
882
|
-
console.log(' No active task\n')
|
|
883
|
-
}
|
|
884
|
-
|
|
885
|
-
// Show next queue summary
|
|
886
|
-
console.log('## Priority Queue')
|
|
887
|
-
const nextLines = nextContent
|
|
888
|
-
?.split('\n')
|
|
889
|
-
.filter((line) => line.trim() && !line.startsWith('#'))
|
|
890
|
-
if (nextLines && nextLines.length > 0) {
|
|
891
|
-
console.log(` ${nextLines.length} tasks in queue`)
|
|
892
|
-
nextLines.slice(0, 3).forEach((line) => console.log(` ${line}`))
|
|
893
|
-
if (nextLines.length > 3) console.log(` ... +${nextLines.length - 3} more`)
|
|
894
|
-
} else {
|
|
895
|
-
console.log(' Queue is empty')
|
|
768
|
+
task = taskMatch ? taskMatch[1] : 'active'
|
|
896
769
|
}
|
|
897
|
-
console.log('')
|
|
898
770
|
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
if (analysisContent) {
|
|
902
|
-
const stackMatch = analysisContent.match(/## Stack Detected\n([\s\S]*?)\n##/)
|
|
903
|
-
if (stackMatch) {
|
|
904
|
-
const stackLines = stackMatch[1]
|
|
905
|
-
.split('\n')
|
|
906
|
-
.filter((line) => line.includes('**'))
|
|
907
|
-
.slice(0, 5)
|
|
908
|
-
stackLines.forEach((line) => {
|
|
909
|
-
const cleaned = line.replace(/###/g, '').replace(/\*\*/g, '').trim()
|
|
910
|
-
if (cleaned) console.log(` ${cleaned}`)
|
|
911
|
-
})
|
|
912
|
-
}
|
|
913
|
-
} else {
|
|
914
|
-
console.log(' Run /p:analyze to detect stack')
|
|
915
|
-
}
|
|
916
|
-
console.log('')
|
|
917
|
-
|
|
918
|
-
// Show recent activity
|
|
919
|
-
console.log('## Recent Activity')
|
|
920
|
-
if (recentActivity.length > 0) {
|
|
921
|
-
recentActivity.slice(0, 5).forEach((entry) => {
|
|
922
|
-
const time = new Date(entry.timestamp).toLocaleString()
|
|
923
|
-
const action = entry.action.replace(/_/g, ' ')
|
|
924
|
-
console.log(` • ${action} - ${time}`)
|
|
925
|
-
})
|
|
926
|
-
} else {
|
|
927
|
-
console.log(' No recent activity')
|
|
928
|
-
}
|
|
929
|
-
|
|
930
|
-
console.log('\n💡 Next steps:')
|
|
931
|
-
console.log('• /p:recap → See full progress overview')
|
|
932
|
-
console.log('• /p:analyze → Update stack analysis')
|
|
933
|
-
console.log('• /p:feature → Add new feature')
|
|
771
|
+
const nextLines = nextContent?.split('\n').filter((line) => line.trim() && !line.startsWith('#')) || []
|
|
772
|
+
const queueCount = nextLines.length
|
|
934
773
|
|
|
935
774
|
await this.logToMemory(projectPath, 'context_viewed', { timestamp: dateHelper.getTimestamp() })
|
|
936
775
|
|
|
776
|
+
out.done(`task: ${task} | queue: ${queueCount}`)
|
|
937
777
|
return { success: true }
|
|
938
778
|
} catch (error) {
|
|
939
|
-
|
|
779
|
+
out.fail(error.message)
|
|
940
780
|
return { success: false, error: error.message }
|
|
941
781
|
}
|
|
942
782
|
}
|
|
@@ -950,94 +790,17 @@ class PrjctCommands {
|
|
|
950
790
|
const initResult = await this.ensureProjectInit(projectPath)
|
|
951
791
|
if (!initResult.success) return initResult
|
|
952
792
|
|
|
953
|
-
|
|
954
|
-
|
|
793
|
+
out.spin('loading recap...')
|
|
955
794
|
const context = await contextBuilder.build(projectPath)
|
|
956
795
|
|
|
957
|
-
// Read shipped features
|
|
958
796
|
const shippedContent = await toolRegistry.get('Read')(context.paths.shipped)
|
|
959
|
-
const shippedFeatures =
|
|
960
|
-
shippedContent
|
|
961
|
-
?.split('##')
|
|
962
|
-
.filter((section) => section.trim() && !section.includes('SHIPPED 🚀')) || []
|
|
797
|
+
const shippedFeatures = shippedContent?.split('##').filter((s) => s.trim() && !s.includes('SHIPPED')) || []
|
|
963
798
|
|
|
964
|
-
// Read current state
|
|
965
|
-
const nowContent = await toolRegistry.get('Read')(context.paths.now)
|
|
966
799
|
const nextContent = await toolRegistry.get('Read')(context.paths.next)
|
|
967
|
-
const
|
|
800
|
+
const nextTasks = nextContent?.split('\n').filter((l) => l.match(/^\d+\./) || l.includes('[ ]')).length || 0
|
|
968
801
|
|
|
969
|
-
|
|
970
|
-
const
|
|
971
|
-
nextContent
|
|
972
|
-
?.split('\n')
|
|
973
|
-
.filter((line) => line.trim().match(/^\d+\./) || line.includes('[ ]')).length || 0
|
|
974
|
-
|
|
975
|
-
const ideas =
|
|
976
|
-
ideasContent
|
|
977
|
-
?.split('##')
|
|
978
|
-
.filter(
|
|
979
|
-
(section) =>
|
|
980
|
-
section.trim() && !section.includes('IDEAS 💡') && !section.includes('Brain Dump')
|
|
981
|
-
).length || 0
|
|
982
|
-
|
|
983
|
-
// Display recap
|
|
984
|
-
console.log('═══════════════════════════════════════════════════')
|
|
985
|
-
console.log(` Shipped: ${shippedFeatures.length} features`)
|
|
986
|
-
console.log(` In Queue: ${nextTasks} tasks`)
|
|
987
|
-
console.log(` Ideas: ${ideas} captured`)
|
|
988
|
-
console.log('═══════════════════════════════════════════════════\n')
|
|
989
|
-
|
|
990
|
-
// Show shipped features
|
|
991
|
-
if (shippedFeatures.length > 0) {
|
|
992
|
-
console.log('## 🚀 Shipped Features\n')
|
|
993
|
-
shippedFeatures
|
|
994
|
-
.slice(-5)
|
|
995
|
-
.reverse()
|
|
996
|
-
.forEach((feature, i) => {
|
|
997
|
-
const lines = feature.trim().split('\n')
|
|
998
|
-
const title = lines[0].trim()
|
|
999
|
-
const shipped = lines
|
|
1000
|
-
.find((l) => l.includes('Shipped:'))
|
|
1001
|
-
?.replace('Shipped:', '')
|
|
1002
|
-
.trim()
|
|
1003
|
-
console.log(` ${i + 1}. ${title} ${shipped ? `(${shipped})` : ''}`)
|
|
1004
|
-
})
|
|
1005
|
-
if (shippedFeatures.length > 5) {
|
|
1006
|
-
console.log(`\n ... +${shippedFeatures.length - 5} more in progress/shipped.md`)
|
|
1007
|
-
}
|
|
1008
|
-
console.log('')
|
|
1009
|
-
} else {
|
|
1010
|
-
console.log('## 🚀 Shipped Features\n None yet - ship your first feature!\n')
|
|
1011
|
-
}
|
|
1012
|
-
|
|
1013
|
-
// Show current focus
|
|
1014
|
-
console.log('## 🎯 Current Focus\n')
|
|
1015
|
-
if (nowContent && !nowContent.includes('No current task')) {
|
|
1016
|
-
const taskMatch = nowContent.match(/\*\*(.+?)\*\*/)
|
|
1017
|
-
const task = taskMatch ? taskMatch[1] : 'Active task'
|
|
1018
|
-
console.log(` Working on: ${task}`)
|
|
1019
|
-
} else {
|
|
1020
|
-
console.log(' No active task')
|
|
1021
|
-
}
|
|
1022
|
-
console.log('')
|
|
1023
|
-
|
|
1024
|
-
// Show next priorities
|
|
1025
|
-
if (nextTasks > 0) {
|
|
1026
|
-
console.log('## 📋 Next Priorities\n')
|
|
1027
|
-
const taskLines = nextContent
|
|
1028
|
-
.split('\n')
|
|
1029
|
-
.filter((line) => line.trim().match(/^\d+\./) || line.includes('[ ]'))
|
|
1030
|
-
.slice(0, 3)
|
|
1031
|
-
|
|
1032
|
-
taskLines.forEach((line) => console.log(` ${line.trim()}`))
|
|
1033
|
-
if (nextTasks > 3) console.log(`\n ... +${nextTasks - 3} more tasks`)
|
|
1034
|
-
console.log('')
|
|
1035
|
-
}
|
|
1036
|
-
|
|
1037
|
-
console.log('💡 Next steps:')
|
|
1038
|
-
console.log('• /p:feature → Add new feature')
|
|
1039
|
-
console.log('• /p:now → Start working on something')
|
|
1040
|
-
console.log('• /p:ship → Ship completed work')
|
|
802
|
+
const ideasContent = await toolRegistry.get('Read')(context.paths.ideas)
|
|
803
|
+
const ideas = ideasContent?.split('##').filter((s) => s.trim() && !s.includes('IDEAS') && !s.includes('Brain')).length || 0
|
|
1041
804
|
|
|
1042
805
|
await this.logToMemory(projectPath, 'recap_viewed', {
|
|
1043
806
|
shipped: shippedFeatures.length,
|
|
@@ -1045,12 +808,10 @@ class PrjctCommands {
|
|
|
1045
808
|
timestamp: dateHelper.getTimestamp(),
|
|
1046
809
|
})
|
|
1047
810
|
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
stats: { shipped: shippedFeatures.length, tasks: nextTasks, ideas },
|
|
1051
|
-
}
|
|
811
|
+
out.done(`shipped: ${shippedFeatures.length} | queue: ${nextTasks} | ideas: ${ideas}`)
|
|
812
|
+
return { success: true, stats: { shipped: shippedFeatures.length, tasks: nextTasks, ideas } }
|
|
1052
813
|
} catch (error) {
|
|
1053
|
-
|
|
814
|
+
out.fail(error.message)
|
|
1054
815
|
return { success: false, error: error.message }
|
|
1055
816
|
}
|
|
1056
817
|
}
|
|
@@ -1065,98 +826,27 @@ class PrjctCommands {
|
|
|
1065
826
|
if (!initResult.success) return initResult
|
|
1066
827
|
|
|
1067
828
|
if (!issue) {
|
|
1068
|
-
|
|
1069
|
-
console.log('Usage: /p:stuck "description of problem"')
|
|
1070
|
-
console.log('\nExample: /p:stuck "CORS error in API calls"')
|
|
829
|
+
out.fail('issue description required')
|
|
1071
830
|
return { success: false, error: 'Issue description required' }
|
|
1072
831
|
}
|
|
1073
832
|
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
const context = await contextBuilder.build(projectPath, { issue })
|
|
1077
|
-
|
|
1078
|
-
// Read analysis to understand stack
|
|
1079
|
-
const analysisContent = await toolRegistry.get('Read')(context.paths.analysis)
|
|
1080
|
-
let detectedStack = 'your project'
|
|
1081
|
-
|
|
1082
|
-
if (analysisContent) {
|
|
1083
|
-
if (analysisContent.includes('Next.js')) detectedStack = 'Next.js'
|
|
1084
|
-
else if (analysisContent.includes('React')) detectedStack = 'React'
|
|
1085
|
-
else if (analysisContent.includes('Rust')) detectedStack = 'Rust'
|
|
1086
|
-
else if (analysisContent.includes('Go')) detectedStack = 'Go'
|
|
1087
|
-
else if (analysisContent.includes('Python')) detectedStack = 'Python'
|
|
1088
|
-
}
|
|
1089
|
-
|
|
1090
|
-
// Provide contextual help based on issue type
|
|
1091
|
-
console.log('💡 Contextual Help:\n')
|
|
1092
|
-
|
|
1093
|
-
const issueLower = issue.toLowerCase()
|
|
1094
|
-
|
|
1095
|
-
// Common issue patterns
|
|
1096
|
-
if (issueLower.includes('cors')) {
|
|
1097
|
-
console.log('## CORS Issue Detected\n')
|
|
1098
|
-
console.log('Common solutions for CORS errors:')
|
|
1099
|
-
console.log('1. Add CORS headers in your backend')
|
|
1100
|
-
if (detectedStack === 'Next.js') {
|
|
1101
|
-
console.log('2. Use Next.js API routes as proxy')
|
|
1102
|
-
console.log('3. Configure next.config.js rewrites')
|
|
1103
|
-
}
|
|
1104
|
-
console.log('4. Check if credentials are being sent')
|
|
1105
|
-
console.log('5. Verify allowed origins match exactly\n')
|
|
1106
|
-
} else if (issueLower.includes('test') || issueLower.includes('failing')) {
|
|
1107
|
-
console.log('## Test Issues\n')
|
|
1108
|
-
console.log('Debug steps:')
|
|
1109
|
-
console.log('1. Run tests in watch mode: npm test -- --watch')
|
|
1110
|
-
console.log('2. Check test environment setup')
|
|
1111
|
-
console.log('3. Verify mocks are correct')
|
|
1112
|
-
console.log('4. Check async handling\n')
|
|
1113
|
-
} else if (issueLower.includes('build') || issueLower.includes('compile')) {
|
|
1114
|
-
console.log('## Build/Compile Issues\n')
|
|
1115
|
-
console.log('Debug steps:')
|
|
1116
|
-
console.log('1. Clear cache and node_modules')
|
|
1117
|
-
console.log('2. Check TypeScript errors: npm run type-check')
|
|
1118
|
-
console.log('3. Verify all dependencies are installed')
|
|
1119
|
-
console.log('4. Check for circular dependencies\n')
|
|
1120
|
-
} else if (issueLower.includes('deploy') || issueLower.includes('production')) {
|
|
1121
|
-
console.log('## Deployment Issues\n')
|
|
1122
|
-
console.log('Debug steps:')
|
|
1123
|
-
console.log('1. Check environment variables')
|
|
1124
|
-
console.log('2. Verify build succeeds locally')
|
|
1125
|
-
console.log('3. Check logs in deployment platform')
|
|
1126
|
-
console.log('4. Verify node version matches\n')
|
|
1127
|
-
} else {
|
|
1128
|
-
console.log('## General Debugging Steps\n')
|
|
1129
|
-
console.log(`For ${detectedStack}:`)
|
|
1130
|
-
console.log('1. Check error logs and stack traces')
|
|
1131
|
-
console.log('2. Search error message in docs')
|
|
1132
|
-
console.log('3. Verify configuration files')
|
|
1133
|
-
console.log('4. Test in isolation (minimal reproduction)')
|
|
1134
|
-
console.log('5. Check recent changes (git diff)\n')
|
|
1135
|
-
}
|
|
833
|
+
out.spin('logging issue...')
|
|
1136
834
|
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
console.log(`• Official Docs: ${detectedStack} documentation`)
|
|
1142
|
-
}
|
|
1143
|
-
console.log('• Claude Code: Ask Claude for specific help with code\n')
|
|
1144
|
-
|
|
1145
|
-
console.log('💬 Still stuck?')
|
|
1146
|
-
console.log('• Share error logs with Claude')
|
|
1147
|
-
console.log('• Create minimal reproduction')
|
|
1148
|
-
console.log('• /p:context → Review project state')
|
|
835
|
+
const analyzer = require('./domain/analyzer')
|
|
836
|
+
analyzer.init(projectPath)
|
|
837
|
+
const packageJson = await analyzer.readPackageJson()
|
|
838
|
+
const detectedStack = packageJson?.name || 'project'
|
|
1149
839
|
|
|
1150
|
-
// Log to memory
|
|
1151
840
|
await this.logToMemory(projectPath, 'help_requested', {
|
|
1152
841
|
issue,
|
|
1153
842
|
stack: detectedStack,
|
|
1154
843
|
timestamp: dateHelper.getTimestamp(),
|
|
1155
844
|
})
|
|
1156
845
|
|
|
846
|
+
out.done(`issue logged: ${issue.slice(0, 40)}`)
|
|
1157
847
|
return { success: true, issue, stack: detectedStack }
|
|
1158
848
|
} catch (error) {
|
|
1159
|
-
|
|
849
|
+
out.fail(error.message)
|
|
1160
850
|
return { success: false, error: error.message }
|
|
1161
851
|
}
|
|
1162
852
|
}
|
|
@@ -1173,16 +863,7 @@ class PrjctCommands {
|
|
|
1173
863
|
async _cleanupMemory(projectPath) {
|
|
1174
864
|
const projectId = await configManager.getProjectId(projectPath)
|
|
1175
865
|
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
const results = {
|
|
1179
|
-
rotated: [],
|
|
1180
|
-
archived: [],
|
|
1181
|
-
totalSize: 0,
|
|
1182
|
-
freedSpace: 0,
|
|
1183
|
-
}
|
|
1184
|
-
|
|
1185
|
-
// 1. Check and rotate large JSONL files
|
|
866
|
+
const results = { rotated: [], totalSize: 0, freedSpace: 0 }
|
|
1186
867
|
const jsonlFiles = [
|
|
1187
868
|
pathManager.getFilePath(projectId, 'memory', 'context.jsonl'),
|
|
1188
869
|
pathManager.getFilePath(projectId, 'progress', 'shipped.md'),
|
|
@@ -1194,36 +875,17 @@ class PrjctCommands {
|
|
|
1194
875
|
const sizeMB = await jsonlHelper.getFileSizeMB(filePath)
|
|
1195
876
|
if (sizeMB > 0) {
|
|
1196
877
|
results.totalSize += sizeMB
|
|
1197
|
-
|
|
1198
878
|
const rotated = await jsonlHelper.rotateJsonLinesIfNeeded(filePath, 10)
|
|
1199
879
|
if (rotated) {
|
|
1200
880
|
results.rotated.push(path.basename(filePath))
|
|
1201
881
|
results.freedSpace += sizeMB
|
|
1202
882
|
}
|
|
1203
883
|
}
|
|
1204
|
-
} catch
|
|
1205
|
-
//
|
|
884
|
+
} catch {
|
|
885
|
+
// skip
|
|
1206
886
|
}
|
|
1207
887
|
}
|
|
1208
888
|
|
|
1209
|
-
// 2. Report disk usage
|
|
1210
|
-
console.log('💾 Disk Usage Report:\n')
|
|
1211
|
-
console.log(` Total size: ${results.totalSize.toFixed(2)}MB`)
|
|
1212
|
-
console.log(` Rotated files: ${results.rotated.length}`)
|
|
1213
|
-
|
|
1214
|
-
if (results.rotated.length > 0) {
|
|
1215
|
-
console.log(` Freed space: ${results.freedSpace.toFixed(2)}MB\n`)
|
|
1216
|
-
results.rotated.forEach((file) => console.log(` ✓ ${file}`))
|
|
1217
|
-
} else {
|
|
1218
|
-
console.log(' ✓ No rotation needed - all files under 10MB\n')
|
|
1219
|
-
}
|
|
1220
|
-
|
|
1221
|
-
// 3. Suggestions
|
|
1222
|
-
console.log('\n💡 Recommendations:\n')
|
|
1223
|
-
console.log(' 1. Claude Code: Compact conversation regularly')
|
|
1224
|
-
console.log(' 2. Exclude from Spotlight: System Settings → Privacy')
|
|
1225
|
-
console.log(' 3. Clear npm cache: npm cache clean --force\n')
|
|
1226
|
-
|
|
1227
889
|
return { success: true, results }
|
|
1228
890
|
}
|
|
1229
891
|
|
|
@@ -1248,14 +910,12 @@ class PrjctCommands {
|
|
|
1248
910
|
const validTypes = ['architecture', 'api', 'component', 'database', 'flow']
|
|
1249
911
|
|
|
1250
912
|
if (!validTypes.includes(designType)) {
|
|
1251
|
-
|
|
1252
|
-
console.log(`Valid types: ${validTypes.join(', ')}`)
|
|
913
|
+
out.fail(`invalid type: ${designType}`)
|
|
1253
914
|
return { success: false, error: 'Invalid design type' }
|
|
1254
915
|
}
|
|
1255
916
|
|
|
1256
917
|
const designTarget = target || 'system'
|
|
1257
|
-
|
|
1258
|
-
console.log(`🎨 Designing ${designType}: ${designTarget}\n`)
|
|
918
|
+
out.spin(`designing ${designType}...`)
|
|
1259
919
|
|
|
1260
920
|
// Create designs directory if it doesn't exist
|
|
1261
921
|
const projectId = await configManager.getProjectId(projectPath)
|
|
@@ -1292,27 +952,16 @@ class PrjctCommands {
|
|
|
1292
952
|
const designFilePath = path.join(designsPath, designFileName)
|
|
1293
953
|
await fileHelper.writeFile(designFilePath, designContent)
|
|
1294
954
|
|
|
1295
|
-
console.log('✅ Design document created!\n')
|
|
1296
|
-
console.log(`📄 Location: planning/designs/${designFileName}\n`)
|
|
1297
|
-
console.log('💡 Next steps:')
|
|
1298
|
-
console.log('• Review and refine the design')
|
|
1299
|
-
console.log('• /p:feature → Implement the design')
|
|
1300
|
-
console.log('• Share with team for feedback')
|
|
1301
|
-
|
|
1302
955
|
await this.logToMemory(projectPath, 'design_created', {
|
|
1303
956
|
type: designType,
|
|
1304
957
|
target: designTarget,
|
|
1305
958
|
timestamp: dateHelper.getTimestamp(),
|
|
1306
959
|
})
|
|
1307
960
|
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
designPath: designFilePath,
|
|
1311
|
-
type: designType,
|
|
1312
|
-
target: designTarget,
|
|
1313
|
-
}
|
|
961
|
+
out.done(`${designType} design created`)
|
|
962
|
+
return { success: true, designPath: designFilePath, type: designType, target: designTarget }
|
|
1314
963
|
} catch (error) {
|
|
1315
|
-
|
|
964
|
+
out.fail(error.message)
|
|
1316
965
|
return { success: false, error: error.message }
|
|
1317
966
|
}
|
|
1318
967
|
}
|
|
@@ -1691,11 +1340,13 @@ Process flow for ${target}.
|
|
|
1691
1340
|
const isMemoryMode = _options.memory === true || _options.type === 'memory'
|
|
1692
1341
|
|
|
1693
1342
|
if (isMemoryMode) {
|
|
1694
|
-
|
|
1695
|
-
|
|
1343
|
+
out.spin('cleaning memory...')
|
|
1344
|
+
const result = await this._cleanupMemory(projectPath)
|
|
1345
|
+
out.done('memory cleaned')
|
|
1346
|
+
return result
|
|
1696
1347
|
}
|
|
1697
1348
|
|
|
1698
|
-
|
|
1349
|
+
out.spin('cleaning up...')
|
|
1699
1350
|
|
|
1700
1351
|
const context = await contextBuilder.build(projectPath)
|
|
1701
1352
|
const projectId = await configManager.getProjectId(projectPath)
|
|
@@ -1766,9 +1417,6 @@ Process flow for ${target}.
|
|
|
1766
1417
|
cleaned.push('Queue: No file found')
|
|
1767
1418
|
}
|
|
1768
1419
|
|
|
1769
|
-
console.log('✅ Cleanup complete!\n')
|
|
1770
|
-
cleaned.forEach((item) => console.log(` • ${item}`))
|
|
1771
|
-
|
|
1772
1420
|
await this._cleanupMemoryInternal(projectPath)
|
|
1773
1421
|
|
|
1774
1422
|
await this.logToMemory(projectPath, 'cleanup_performed', {
|
|
@@ -1776,9 +1424,10 @@ Process flow for ${target}.
|
|
|
1776
1424
|
timestamp: dateHelper.getTimestamp(),
|
|
1777
1425
|
})
|
|
1778
1426
|
|
|
1427
|
+
out.done(`${cleaned.length} items cleaned`)
|
|
1779
1428
|
return { success: true, cleaned }
|
|
1780
1429
|
} catch (error) {
|
|
1781
|
-
|
|
1430
|
+
out.fail(error.message)
|
|
1782
1431
|
return { success: false, error: error.message }
|
|
1783
1432
|
}
|
|
1784
1433
|
}
|
|
@@ -1793,102 +1442,35 @@ Process flow for ${target}.
|
|
|
1793
1442
|
if (!initResult.success) return initResult
|
|
1794
1443
|
|
|
1795
1444
|
const validPeriods = ['day', 'week', 'month', 'all']
|
|
1796
|
-
if (!validPeriods.includes(period))
|
|
1797
|
-
period = 'week'
|
|
1798
|
-
}
|
|
1445
|
+
if (!validPeriods.includes(period)) period = 'week'
|
|
1799
1446
|
|
|
1800
|
-
|
|
1447
|
+
out.spin(`loading ${period} progress...`)
|
|
1801
1448
|
|
|
1802
1449
|
const projectId = await configManager.getProjectId(projectPath)
|
|
1803
1450
|
const memoryPath = pathManager.getFilePath(projectId, 'memory', 'context.jsonl')
|
|
1804
1451
|
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1452
|
+
const startDate = period === 'day' ? dateHelper.getDaysAgo(1) :
|
|
1453
|
+
period === 'week' ? dateHelper.getDaysAgo(7) :
|
|
1454
|
+
period === 'month' ? dateHelper.getDaysAgo(30) : new Date(0)
|
|
1808
1455
|
|
|
1809
|
-
switch (period) {
|
|
1810
|
-
case 'day':
|
|
1811
|
-
startDate = dateHelper.getDaysAgo(1)
|
|
1812
|
-
break
|
|
1813
|
-
case 'week':
|
|
1814
|
-
startDate = dateHelper.getDaysAgo(7)
|
|
1815
|
-
break
|
|
1816
|
-
case 'month':
|
|
1817
|
-
startDate = dateHelper.getDaysAgo(30)
|
|
1818
|
-
break
|
|
1819
|
-
case 'all':
|
|
1820
|
-
startDate = new Date(0) // Beginning of time
|
|
1821
|
-
break
|
|
1822
|
-
}
|
|
1823
|
-
|
|
1824
|
-
// Read memory and filter by period
|
|
1825
1456
|
let entries = []
|
|
1826
1457
|
try {
|
|
1827
1458
|
const allEntries = await jsonlHelper.readJsonLines(memoryPath)
|
|
1459
|
+
entries = allEntries.filter((e) => new Date(e.timestamp) >= startDate)
|
|
1460
|
+
} catch { entries = [] }
|
|
1828
1461
|
|
|
1829
|
-
entries = allEntries.filter((entry) => {
|
|
1830
|
-
const entryDate = new Date(entry.timestamp)
|
|
1831
|
-
return entryDate >= startDate
|
|
1832
|
-
})
|
|
1833
|
-
} catch {
|
|
1834
|
-
entries = []
|
|
1835
|
-
}
|
|
1836
|
-
|
|
1837
|
-
// Calculate metrics
|
|
1838
1462
|
const metrics = {
|
|
1839
|
-
tasksStarted: entries.filter((e) => e.action === 'task_started').length,
|
|
1840
1463
|
tasksCompleted: entries.filter((e) => e.action === 'task_completed').length,
|
|
1841
|
-
featuresPlanned: entries.filter((e) => e.action === 'feature_planned').length,
|
|
1842
1464
|
featuresShipped: entries.filter((e) => e.action === 'feature_shipped').length,
|
|
1843
|
-
bugsReported: entries.filter((e) => e.action === 'bug_reported').length,
|
|
1844
|
-
designsCreated: entries.filter((e) => e.action === 'design_created').length,
|
|
1845
|
-
helpRequested: entries.filter((e) => e.action === 'help_requested').length,
|
|
1846
1465
|
totalActions: entries.length,
|
|
1847
1466
|
}
|
|
1848
1467
|
|
|
1849
|
-
|
|
1850
|
-
console.log('═══════════════════════════════════════════════════')
|
|
1851
|
-
console.log(
|
|
1852
|
-
` Period: ${period} (${startDate.toLocaleDateString()} - ${now.toLocaleDateString()})`
|
|
1853
|
-
)
|
|
1854
|
-
console.log('═══════════════════════════════════════════════════\n')
|
|
1855
|
-
|
|
1856
|
-
console.log('## Activity Summary\n')
|
|
1857
|
-
console.log(` Total Actions: ${metrics.totalActions}`)
|
|
1858
|
-
console.log(` Tasks Started: ${metrics.tasksStarted}`)
|
|
1859
|
-
console.log(` Tasks Completed: ${metrics.tasksCompleted}`)
|
|
1860
|
-
console.log(` Features Planned: ${metrics.featuresPlanned}`)
|
|
1861
|
-
console.log(` Features Shipped: ${metrics.featuresShipped}`)
|
|
1862
|
-
console.log(` Bugs Reported: ${metrics.bugsReported}`)
|
|
1863
|
-
console.log(` Designs Created: ${metrics.designsCreated}`)
|
|
1864
|
-
console.log(` Help Requested: ${metrics.helpRequested}\n`)
|
|
1865
|
-
|
|
1866
|
-
// Completion rate
|
|
1867
|
-
if (metrics.tasksStarted > 0) {
|
|
1868
|
-
const completionRate = Math.round((metrics.tasksCompleted / metrics.tasksStarted) * 100)
|
|
1869
|
-
console.log(`## Completion Rate: ${completionRate}%\n`)
|
|
1870
|
-
}
|
|
1871
|
-
|
|
1872
|
-
// Velocity
|
|
1873
|
-
const daysInPeriod =
|
|
1874
|
-
period === 'day' ? 1 : period === 'week' ? 7 : period === 'month' ? 30 : 365
|
|
1875
|
-
const tasksPerDay = (metrics.tasksCompleted / daysInPeriod).toFixed(1)
|
|
1876
|
-
console.log(`## Velocity: ${tasksPerDay} tasks/day\n`)
|
|
1877
|
-
|
|
1878
|
-
console.log('💡 Actions:')
|
|
1879
|
-
console.log('• /p:recap → See shipped features')
|
|
1880
|
-
console.log('• /p:context → View current state')
|
|
1881
|
-
console.log('• /p:progress day|week|month|all → Change period')
|
|
1882
|
-
|
|
1883
|
-
await this.logToMemory(projectPath, 'progress_viewed', {
|
|
1884
|
-
period,
|
|
1885
|
-
metrics,
|
|
1886
|
-
timestamp: dateHelper.getTimestamp(),
|
|
1887
|
-
})
|
|
1468
|
+
await this.logToMemory(projectPath, 'progress_viewed', { period, metrics, timestamp: dateHelper.getTimestamp() })
|
|
1888
1469
|
|
|
1470
|
+
out.done(`${period}: ${metrics.tasksCompleted} tasks | ${metrics.featuresShipped} shipped`)
|
|
1889
1471
|
return { success: true, period, metrics }
|
|
1890
1472
|
} catch (error) {
|
|
1891
|
-
|
|
1473
|
+
out.fail(error.message)
|
|
1892
1474
|
return { success: false, error: error.message }
|
|
1893
1475
|
}
|
|
1894
1476
|
}
|
|
@@ -1902,36 +1484,24 @@ Process flow for ${target}.
|
|
|
1902
1484
|
const initResult = await this.ensureProjectInit(projectPath)
|
|
1903
1485
|
if (!initResult.success) return initResult
|
|
1904
1486
|
|
|
1905
|
-
|
|
1906
|
-
|
|
1487
|
+
out.spin('loading roadmap...')
|
|
1907
1488
|
const context = await contextBuilder.build(projectPath)
|
|
1908
|
-
|
|
1909
|
-
// Read roadmap content
|
|
1910
1489
|
const roadmapContent = await toolRegistry.get('Read')(context.paths.roadmap)
|
|
1911
1490
|
|
|
1912
1491
|
if (!roadmapContent || roadmapContent.trim() === '# ROADMAP') {
|
|
1913
|
-
|
|
1914
|
-
console.log('Example roadmap structure:')
|
|
1915
|
-
console.log(this._generateRoadmapTemplate())
|
|
1916
|
-
console.log('\n💡 Use /p:feature to add features')
|
|
1917
|
-
console.log(' Features are automatically added to roadmap')
|
|
1492
|
+
out.warn('no roadmap yet')
|
|
1918
1493
|
return { success: true, message: 'No roadmap' }
|
|
1919
1494
|
}
|
|
1920
1495
|
|
|
1921
|
-
//
|
|
1922
|
-
|
|
1496
|
+
// Count features in roadmap
|
|
1497
|
+
const features = (roadmapContent.match(/##/g) || []).length
|
|
1923
1498
|
|
|
1924
|
-
|
|
1925
|
-
console.log('• /p:feature → Add new feature to roadmap')
|
|
1926
|
-
console.log('• /p:status → See implementation status')
|
|
1927
|
-
|
|
1928
|
-
await this.logToMemory(projectPath, 'roadmap_viewed', {
|
|
1929
|
-
timestamp: dateHelper.getTimestamp(),
|
|
1930
|
-
})
|
|
1499
|
+
await this.logToMemory(projectPath, 'roadmap_viewed', { timestamp: dateHelper.getTimestamp() })
|
|
1931
1500
|
|
|
1501
|
+
out.done(`${features} features in roadmap`)
|
|
1932
1502
|
return { success: true, content: roadmapContent }
|
|
1933
1503
|
} catch (error) {
|
|
1934
|
-
|
|
1504
|
+
out.fail(error.message)
|
|
1935
1505
|
return { success: false, error: error.message }
|
|
1936
1506
|
}
|
|
1937
1507
|
}
|
|
@@ -2569,118 +2139,32 @@ Agent: ${agent}
|
|
|
2569
2139
|
|
|
2570
2140
|
/**
|
|
2571
2141
|
* Generate agents dynamically from analysis summary
|
|
2572
|
-
* 100%
|
|
2573
|
-
*
|
|
2142
|
+
* 100% AGENTIC - Uses analyzer for raw data, Claude decides
|
|
2143
|
+
* NO hardcoded categorization or framework lists
|
|
2574
2144
|
* @private
|
|
2575
2145
|
*/
|
|
2576
2146
|
async _generateAgentsFromAnalysis(summaryContent, generator, projectPath) {
|
|
2577
2147
|
const agents = []
|
|
2578
|
-
const TechDetector = require('./domain/tech-detector')
|
|
2579
|
-
const detector = new TechDetector(projectPath)
|
|
2580
|
-
const tech = await detector.detectAll()
|
|
2581
2148
|
|
|
2582
|
-
//
|
|
2583
|
-
|
|
2149
|
+
// 100% AGENTIC: Get raw project data, let Claude decide
|
|
2150
|
+
const analyzer = require('./domain/analyzer')
|
|
2151
|
+
analyzer.init(projectPath)
|
|
2584
2152
|
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
if (frontendFrameworks.length > 0 || frontendBuildTools.length > 0 || tech.languages.includes('JavaScript') || tech.languages.includes('TypeScript')) {
|
|
2594
|
-
const frameworkList = frontendFrameworks.length > 0
|
|
2595
|
-
? frontendFrameworks.join(', ')
|
|
2596
|
-
: (frontendBuildTools.length > 0 ? frontendBuildTools.join(', ') : 'JavaScript/TypeScript')
|
|
2597
|
-
|
|
2598
|
-
await generator.generateDynamicAgent('frontend-specialist', {
|
|
2599
|
-
role: 'Frontend Development Specialist',
|
|
2600
|
-
expertise: `${frameworkList}, ${tech.languages.filter(l => ['JavaScript', 'TypeScript'].includes(l)).join(' or ') || 'Modern JavaScript'}`,
|
|
2601
|
-
responsibilities: 'Handle UI components, state management, routing, and frontend architecture',
|
|
2602
|
-
projectContext: {
|
|
2603
|
-
detectedFrameworks: frontendFrameworks,
|
|
2604
|
-
buildTools: frontendBuildTools,
|
|
2605
|
-
languages: tech.languages.filter(l => ['JavaScript', 'TypeScript'].includes(l))
|
|
2606
|
-
},
|
|
2607
|
-
})
|
|
2608
|
-
agents.push('frontend-specialist')
|
|
2153
|
+
const projectData = {
|
|
2154
|
+
packageJson: await analyzer.readPackageJson(),
|
|
2155
|
+
extensions: await analyzer.getFileExtensions(),
|
|
2156
|
+
directories: await analyzer.listDirectories(),
|
|
2157
|
+
configFiles: await analyzer.listConfigFiles(),
|
|
2158
|
+
analysisSummary: summaryContent,
|
|
2159
|
+
projectPath
|
|
2609
2160
|
}
|
|
2610
2161
|
|
|
2611
|
-
//
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
)
|
|
2615
|
-
const backendLanguages = tech.languages.filter(l =>
|
|
2616
|
-
['Go', 'Rust', 'Python', 'Ruby', 'Elixir', 'Java', 'PHP'].includes(l)
|
|
2617
|
-
)
|
|
2162
|
+
// Let the generator decide what agents to create
|
|
2163
|
+
// It reads templates/agents/AGENTS.md and decides based on actual project
|
|
2164
|
+
const generatedAgents = await generator.generateAgentsFromTech(projectData)
|
|
2618
2165
|
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
? `${backendLanguages[0].toLowerCase()}-developer`
|
|
2622
|
-
: 'backend-specialist'
|
|
2623
|
-
|
|
2624
|
-
const expertise = backendFrameworks.length > 0
|
|
2625
|
-
? backendFrameworks.join(', ')
|
|
2626
|
-
: backendLanguages.join(', ')
|
|
2627
|
-
|
|
2628
|
-
await generator.generateDynamicAgent(agentName, {
|
|
2629
|
-
role: `${backendLanguages[0] || 'Backend'} Development Specialist`,
|
|
2630
|
-
expertise,
|
|
2631
|
-
responsibilities: 'Handle backend services, API development, server logic',
|
|
2632
|
-
projectContext: {
|
|
2633
|
-
detectedFrameworks: backendFrameworks,
|
|
2634
|
-
languages: backendLanguages
|
|
2635
|
-
},
|
|
2636
|
-
})
|
|
2637
|
-
agents.push(agentName)
|
|
2638
|
-
}
|
|
2639
|
-
|
|
2640
|
-
// Database specialist - if we have database tools
|
|
2641
|
-
if (tech.databases.length > 0) {
|
|
2642
|
-
await generator.generateDynamicAgent('database-specialist', {
|
|
2643
|
-
role: 'Database Specialist',
|
|
2644
|
-
expertise: tech.databases.join(', '),
|
|
2645
|
-
responsibilities: 'Handle database design, queries, migrations, data modeling',
|
|
2646
|
-
projectContext: {
|
|
2647
|
-
databases: tech.databases
|
|
2648
|
-
},
|
|
2649
|
-
})
|
|
2650
|
-
agents.push('database-specialist')
|
|
2651
|
-
}
|
|
2652
|
-
|
|
2653
|
-
// DevOps specialist - if we have DevOps tools
|
|
2654
|
-
if (tech.tools.some(t => ['Docker', 'Kubernetes', 'Terraform'].includes(t))) {
|
|
2655
|
-
await generator.generateDynamicAgent('devops-specialist', {
|
|
2656
|
-
role: 'DevOps & Infrastructure Specialist',
|
|
2657
|
-
expertise: tech.tools.filter(t => ['Docker', 'Kubernetes', 'Terraform'].includes(t)).join(', '),
|
|
2658
|
-
responsibilities: 'Handle containerization, deployment, infrastructure setup',
|
|
2659
|
-
projectContext: {
|
|
2660
|
-
tools: tech.tools
|
|
2661
|
-
},
|
|
2662
|
-
})
|
|
2663
|
-
agents.push('devops-specialist')
|
|
2664
|
-
}
|
|
2665
|
-
|
|
2666
|
-
// QA specialist - always generate if we have test frameworks or any code
|
|
2667
|
-
if (tech.testFrameworks.length > 0 || tech.languages.length > 0) {
|
|
2668
|
-
const testExpertise = tech.testFrameworks.length > 0
|
|
2669
|
-
? tech.testFrameworks.join(', ')
|
|
2670
|
-
: 'Testing frameworks, test automation'
|
|
2671
|
-
|
|
2672
|
-
await generator.generateDynamicAgent('qa-specialist', {
|
|
2673
|
-
role: 'Quality Assurance Specialist',
|
|
2674
|
-
expertise: testExpertise,
|
|
2675
|
-
responsibilities: 'Handle testing strategy, test creation, quality assurance',
|
|
2676
|
-
projectContext: {
|
|
2677
|
-
testFrameworks: tech.testFrameworks,
|
|
2678
|
-
languages: tech.languages,
|
|
2679
|
-
role: 'QA'
|
|
2680
|
-
},
|
|
2681
|
-
})
|
|
2682
|
-
agents.push('qa-specialist')
|
|
2683
|
-
}
|
|
2166
|
+
// Return agent names
|
|
2167
|
+
generatedAgents.forEach(agent => agents.push(agent.name || agent))
|
|
2684
2168
|
|
|
2685
2169
|
return agents
|
|
2686
2170
|
}
|