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/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
- console.log('⚠️ Project not initialized')
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
- console.log(`🎯 Working on: ${task}`)
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
- console.log(' Not working on anything')
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
- console.log(nowContent)
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
- console.error('❌ Error:', error.message)
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
- console.log(' Not working on anything right now!')
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
- console.log(`✅ Task complete: ${task}${duration ? ` (${duration})` : ''}`)
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
- console.error('❌ Error:', error.message)
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
- console.log('📋 Queue is empty!')
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
- // Check if there's an active task
255
- const nowContent = await toolRegistry.get('Read')(context.paths.now)
256
- if (nowContent && !nowContent.includes('No current task')) {
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
- console.error('❌ Error:', error.message)
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
- console.log('⚠️ Project already initialized')
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
- console.log(`✨ Initializing prjct v${VERSION}...\n`)
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
- console.log(`📁 Project ID: ${projectId}`)
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
- console.log('\n📊 Existing project detected - analyzing...\n')
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
- // Run sync to generate agents
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
- // MODE 3: No idea provided
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
- console.log('\n📐 ARCHITECT MODE ACTIVATED\n')
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
- console.error('❌ Error:', error.message)
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
- console.log('❌ Feature description required')
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
- console.log(`✨ Creating feature roadmap: ${description}\n`)
423
+ out.spin(`planning ${description}...`)
476
424
 
477
425
  const context = await contextBuilder.build(projectPath, { description })
478
426
 
479
- // Value analysis (simplified - Claude would do deeper analysis)
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
- console.log('✅ Feature roadmap created!\n')
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
- console.error('❌ Error:', error.message)
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
- console.log(' Bug description required')
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
- console.log(`🐛 Reporting bug: ${description}\n`)
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
- console.log('✅ Bug tracked!\n')
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
- console.error('❌ Error:', error.message)
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
- console.log(`🚀 Shipping: ${feature}\n`)
587
+ out.spin(`shipping ${feature}...`)
667
588
 
668
- // Step 1: Lint (non-blocking)
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 (non-blocking)
674
- console.log('2️⃣ Running tests...')
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
- console.log('4️⃣ Bumping version...')
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
- console.log('6️⃣ Creating git commit...')
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
- console.log('7️⃣ Pushing to remote...')
697
- const pushResult = await this._gitPush(projectPath)
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
- console.log('\n🎉 Feature shipped successfully!\n')
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
- console.error('❌ Error:', error.message)
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
- console.log('📋 Project Context\n')
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
- // Display context
876
- console.log('## Current Focus')
764
+ // Extract summary
765
+ let task = 'none'
877
766
  if (nowContent && !nowContent.includes('No current task')) {
878
767
  const taskMatch = nowContent.match(/\*\*(.+?)\*\*/)
879
- const task = taskMatch ? taskMatch[1] : 'Active task'
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
- // Show stack summary
900
- console.log('## Tech Stack')
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
- console.error('❌ Error:', error.message)
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
- console.log('📊 Project Recap\n')
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 ideasContent = await toolRegistry.get('Read')(context.paths.ideas)
800
+ const nextTasks = nextContent?.split('\n').filter((l) => l.match(/^\d+\./) || l.includes('[ ]')).length || 0
968
801
 
969
- // Count tasks
970
- const nextTasks =
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
- return {
1049
- success: true,
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
- console.error('❌ Error:', error.message)
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
- console.log(' Issue description required')
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
- console.log(`🆘 Getting help: ${issue}\n`)
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
- console.log('📚 Resources:')
1138
- console.log(`• Stack Overflow: Search "${issue}"`)
1139
- console.log(`• GitHub Issues: Search in ${detectedStack} repo`)
1140
- if (detectedStack !== 'your project') {
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
- console.error('❌ Error:', error.message)
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
- console.log('📊 Analyzing disk usage...\n')
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 (error) {
1205
- // File doesn't exist, skip
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
- console.log(`❌ Invalid design type: ${designType}`)
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
- return {
1309
- success: true,
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
- console.error('❌ Error:', error.message)
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
- console.log('🧹 Memory cleanup...\n')
1695
- return await this._cleanupMemory(projectPath)
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
- console.log('🧹 Cleaning up project...\n')
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
- console.error('❌ Error:', error.message)
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
- console.log(`📈 Progress Report (${period})\n`)
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
- // Calculate time range
1806
- const now = new Date()
1807
- let startDate
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
- // Display metrics
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
- console.error('❌ Error:', error.message)
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
- console.log('🗺️ Project Roadmap\n')
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
- console.log('📝 No roadmap yet. Add features to build roadmap:\n')
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
- // Display roadmap
1922
- console.log(roadmapContent)
1496
+ // Count features in roadmap
1497
+ const features = (roadmapContent.match(/##/g) || []).length
1923
1498
 
1924
- console.log('\n💡 Actions:')
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
- console.error('❌ Error:', error.message)
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% DYNAMIC - Uses TechDetector, NO HARDCODING
2573
- * Claude decides based on actual detected technologies
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
- // Generate agents based on ACTUAL detected technologies
2583
- // No assumptions, no hardcoding - just what we found
2149
+ // 100% AGENTIC: Get raw project data, let Claude decide
2150
+ const analyzer = require('./domain/analyzer')
2151
+ analyzer.init(projectPath)
2584
2152
 
2585
- // Frontend agents - if we have frontend frameworks
2586
- const frontendFrameworks = tech.frameworks.filter(f =>
2587
- ['react', 'vue', 'angular', 'svelte', 'next', 'nuxt', 'sveltekit', 'remix'].includes(f.toLowerCase())
2588
- )
2589
- const frontendBuildTools = tech.buildTools.filter(t =>
2590
- ['vite', 'webpack', 'rollup', 'esbuild'].includes(t.toLowerCase())
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
- // Backend agents - if we have backend frameworks or languages
2612
- const backendFrameworks = tech.frameworks.filter(f =>
2613
- ['express', 'fastify', 'koa', 'hapi', 'nest', 'django', 'flask', 'fastapi', 'rails', 'phoenix', 'laravel'].includes(f.toLowerCase())
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
- if (backendFrameworks.length > 0 || backendLanguages.length > 0) {
2620
- const agentName = backendLanguages.length > 0
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
  }