@champpaba/claude-agent-kit 3.0.3 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/CHANGELOG.md +180 -0
- package/.claude/CLAUDE.md +30 -27
- package/.claude/agents/_shared/pre-work-checklist.md +57 -9
- package/.claude/commands/cdev.md +36 -0
- package/.claude/commands/csetup.md +227 -1791
- package/.claude/contexts/patterns/tdd-classification.md +1 -1
- package/.claude/lib/README.md +3 -3
- package/.claude/lib/detailed-guides/taskmaster-analysis.md +1 -1
- package/.claude/lib/task-analyzer.md +144 -0
- package/.claude/lib/tdd-workflow.md +2 -1
- package/package.json +1 -1
- package/.claude/lib/tdd-classifier.md +0 -345
|
@@ -318,1531 +318,310 @@ Continue anyway? (yes/no)
|
|
|
318
318
|
|
|
319
319
|
---
|
|
320
320
|
|
|
321
|
-
### Step 2.6:
|
|
321
|
+
### Step 2.6: Generate Pre-Work Context (v3.2.0 - Consolidated)
|
|
322
322
|
|
|
323
|
-
> **
|
|
324
|
-
> **
|
|
325
|
-
> **
|
|
323
|
+
> **EXECUTE THESE STEPS** - Not pseudocode, actual instructions for Main Claude
|
|
324
|
+
> **Output:** `openspec/changes/{changeId}/pre-work-context.md`
|
|
325
|
+
> **Purpose:** Single file containing ALL context agents need before implementation
|
|
326
326
|
|
|
327
|
-
**
|
|
328
|
-
-
|
|
329
|
-
-
|
|
330
|
-
-
|
|
331
|
-
-
|
|
332
|
-
- Warns if industry practice conflicts with user's design choices
|
|
327
|
+
**This step consolidates:**
|
|
328
|
+
- Adaptive Depth Research (domain knowledge)
|
|
329
|
+
- Library Best Practices (from Context7)
|
|
330
|
+
- Integration Warnings (cross-library concerns)
|
|
331
|
+
- Critical Checklists (security/compliance requirements)
|
|
333
332
|
|
|
334
|
-
|
|
335
|
-
output(`\n🔬 Adaptive Depth Research Analysis...`)
|
|
336
|
-
|
|
337
|
-
// 1. Gather change context from all spec files
|
|
338
|
-
const proposalPath = `openspec/changes/${changeId}/proposal.md`
|
|
339
|
-
const tasksPath = `openspec/changes/${changeId}/tasks.md`
|
|
340
|
-
const designPath = `openspec/changes/${changeId}/design.md`
|
|
341
|
-
|
|
342
|
-
const proposal = fileExists(proposalPath) ? Read(proposalPath) : ''
|
|
343
|
-
const tasks = fileExists(tasksPath) ? Read(tasksPath) : ''
|
|
344
|
-
const design = fileExists(designPath) ? Read(designPath) : ''
|
|
345
|
-
const combined = (proposal + '\n' + tasks + '\n' + design).toLowerCase()
|
|
346
|
-
|
|
347
|
-
// 2. Analyze change characteristics using semantic understanding
|
|
348
|
-
const changeAnalysis = analyzeChangeCharacteristics(combined, proposal, tasks)
|
|
349
|
-
|
|
350
|
-
output(`\n📊 Change Analysis:`)
|
|
351
|
-
output(` Type: ${changeAnalysis.primaryType}`)
|
|
352
|
-
output(` Complexity: ${changeAnalysis.complexity}/10`)
|
|
353
|
-
output(` Risk Level: ${changeAnalysis.riskLevel}`)
|
|
354
|
-
output(` Target Audience: ${changeAnalysis.audience || 'Internal'}`)
|
|
355
|
-
|
|
356
|
-
// 3. Determine required research layers based on change characteristics
|
|
357
|
-
const requiredLayers = determineResearchLayers(changeAnalysis)
|
|
358
|
-
|
|
359
|
-
output(`\n📚 Research Layers Required: ${requiredLayers.length}`)
|
|
360
|
-
|
|
361
|
-
if (requiredLayers.length === 0) {
|
|
362
|
-
output(` ✅ No research needed - trivial change`)
|
|
363
|
-
output(` (Typo fix, debug log, simple badge, etc.)`)
|
|
364
|
-
} else {
|
|
365
|
-
requiredLayers.forEach((layer, idx) => {
|
|
366
|
-
output(` L${idx + 1}: ${layer.name}`)
|
|
367
|
-
output(` Focus: ${layer.focus}`)
|
|
368
|
-
output(` Questions: ${layer.questions.slice(0, 2).join(', ')}...`)
|
|
369
|
-
})
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
// 4. Execute research for each layer using Context7 + semantic analysis
|
|
373
|
-
const researchResults = []
|
|
374
|
-
|
|
375
|
-
for (const layer of requiredLayers) {
|
|
376
|
-
output(`\n🔍 Researching L${layer.order}: ${layer.name}...`)
|
|
377
|
-
|
|
378
|
-
const layerResult = await executeLayerResearch(layer, changeAnalysis)
|
|
379
|
-
researchResults.push(layerResult)
|
|
380
|
-
|
|
381
|
-
output(` ✅ Found ${layerResult.findings.length} key findings`)
|
|
382
|
-
if (layerResult.warnings.length > 0) {
|
|
383
|
-
layerResult.warnings.forEach(w => output(` ⚠️ ${w}`))
|
|
384
|
-
}
|
|
385
|
-
}
|
|
333
|
+
---
|
|
386
334
|
|
|
387
|
-
|
|
388
|
-
const tokensPath = 'design-system/data.yaml'
|
|
389
|
-
if (fileExists(tokensPath) && researchResults.length > 0) {
|
|
390
|
-
const tokens = parseYaml(Read(tokensPath))
|
|
391
|
-
const conflicts = checkDesignConflicts(tokens, researchResults, changeAnalysis)
|
|
392
|
-
|
|
393
|
-
if (conflicts.length > 0) {
|
|
394
|
-
output(`\n⚠️ Design vs Industry Fit Conflicts:`)
|
|
395
|
-
conflicts.forEach(c => {
|
|
396
|
-
output(` - ${c.aspect}: Your design uses "${c.current}", but ${c.industry}`)
|
|
397
|
-
output(` Recommendation: ${c.recommendation}`)
|
|
398
|
-
})
|
|
399
|
-
output(`\n Note: User design choices take precedence. These are informational warnings.`)
|
|
400
|
-
}
|
|
401
|
-
}
|
|
335
|
+
#### Step 2.6.1: Analyze Change Characteristics
|
|
402
336
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
337
|
+
**Read and analyze these files:**
|
|
338
|
+
- `openspec/changes/{changeId}/proposal.md`
|
|
339
|
+
- `openspec/changes/{changeId}/tasks.md`
|
|
340
|
+
- `openspec/changes/{changeId}/design.md` (if exists)
|
|
406
341
|
|
|
407
|
-
|
|
408
|
-
|
|
342
|
+
**Determine:**
|
|
343
|
+
1. **Primary Type:** marketing | dashboard | api | auth | database | general
|
|
344
|
+
2. **Complexity (1-10):** Based on features, integrations, external APIs
|
|
345
|
+
3. **Risk Level:** LOW | MEDIUM | HIGH
|
|
346
|
+
4. **Domains:** healthcare, fintech, ecommerce, saas (if applicable)
|
|
347
|
+
5. **Features:** payment, auth, multi-tenancy, realtime (if detected)
|
|
409
348
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
349
|
+
**Output:**
|
|
350
|
+
```
|
|
351
|
+
📊 Change Analysis:
|
|
352
|
+
Type: auth
|
|
353
|
+
Complexity: 6/10
|
|
354
|
+
Risk Level: HIGH
|
|
355
|
+
Domains: fintech
|
|
356
|
+
Features: payment, auth
|
|
417
357
|
```
|
|
418
358
|
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
```typescript
|
|
422
|
-
// Analyze change characteristics using semantic understanding
|
|
423
|
-
function analyzeChangeCharacteristics(combined, proposal, tasks) {
|
|
424
|
-
const analysis = {
|
|
425
|
-
primaryType: 'general',
|
|
426
|
-
complexity: 1,
|
|
427
|
-
riskLevel: 'LOW',
|
|
428
|
-
audience: 'internal',
|
|
429
|
-
domains: [],
|
|
430
|
-
features: [],
|
|
431
|
-
hasUI: false,
|
|
432
|
-
hasAPI: false,
|
|
433
|
-
hasDatabase: false,
|
|
434
|
-
hasPayment: false,
|
|
435
|
-
hasAuth: false,
|
|
436
|
-
hasCompliance: false,
|
|
437
|
-
hasSensitiveData: false,
|
|
438
|
-
isExternalFacing: false,
|
|
439
|
-
industryContext: null
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
// Detect primary type
|
|
443
|
-
if (/marketing|landing|hero|cta|conversion|sales/i.test(combined)) {
|
|
444
|
-
analysis.primaryType = 'marketing'
|
|
445
|
-
analysis.isExternalFacing = true
|
|
446
|
-
} else if (/dashboard|admin|management|analytics/i.test(combined)) {
|
|
447
|
-
analysis.primaryType = 'dashboard'
|
|
448
|
-
} else if (/api|endpoint|rest|graphql/i.test(combined)) {
|
|
449
|
-
analysis.primaryType = 'api'
|
|
450
|
-
} else if (/auth|login|register|password/i.test(combined)) {
|
|
451
|
-
analysis.primaryType = 'auth'
|
|
452
|
-
analysis.hasAuth = true
|
|
453
|
-
} else if (/database|schema|migration|model/i.test(combined)) {
|
|
454
|
-
analysis.primaryType = 'database'
|
|
455
|
-
analysis.hasDatabase = true
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
// Detect features and domains
|
|
459
|
-
if (/payment|stripe|billing|checkout|subscription/i.test(combined)) {
|
|
460
|
-
analysis.hasPayment = true
|
|
461
|
-
analysis.features.push('payment')
|
|
462
|
-
analysis.riskLevel = 'HIGH'
|
|
463
|
-
}
|
|
464
|
-
if (/health|medical|patient|hipaa|phi/i.test(combined)) {
|
|
465
|
-
analysis.hasCompliance = true
|
|
466
|
-
analysis.hasSensitiveData = true
|
|
467
|
-
analysis.domains.push('healthcare')
|
|
468
|
-
analysis.industryContext = 'healthcare'
|
|
469
|
-
analysis.riskLevel = 'HIGH'
|
|
470
|
-
}
|
|
471
|
-
if (/fintech|banking|finance|pci|financial/i.test(combined)) {
|
|
472
|
-
analysis.hasCompliance = true
|
|
473
|
-
analysis.domains.push('fintech')
|
|
474
|
-
analysis.industryContext = 'fintech'
|
|
475
|
-
analysis.riskLevel = 'HIGH'
|
|
476
|
-
}
|
|
477
|
-
if (/saas|multi-tenant|tenant/i.test(combined)) {
|
|
478
|
-
analysis.domains.push('saas')
|
|
479
|
-
analysis.features.push('multi-tenancy')
|
|
480
|
-
}
|
|
481
|
-
if (/ecommerce|e-commerce|cart|product|shop/i.test(combined)) {
|
|
482
|
-
analysis.domains.push('ecommerce')
|
|
483
|
-
analysis.isExternalFacing = true
|
|
484
|
-
}
|
|
485
|
-
if (/realtime|real-time|websocket|collaboration/i.test(combined)) {
|
|
486
|
-
analysis.features.push('realtime')
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
// Detect UI/API/Database
|
|
490
|
-
analysis.hasUI = /ui|page|component|form|button|modal/i.test(combined)
|
|
491
|
-
analysis.hasAPI = /api|endpoint|route|controller/i.test(combined)
|
|
492
|
-
analysis.hasDatabase = analysis.hasDatabase || /table|column|relation|index/i.test(combined)
|
|
493
|
-
|
|
494
|
-
// Detect audience
|
|
495
|
-
if (/b2c|consumer|user|customer/i.test(combined)) {
|
|
496
|
-
analysis.audience = 'consumer'
|
|
497
|
-
analysis.isExternalFacing = true
|
|
498
|
-
} else if (/b2b|enterprise|business/i.test(combined)) {
|
|
499
|
-
analysis.audience = 'business'
|
|
500
|
-
analysis.isExternalFacing = true
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
// Calculate complexity (1-10)
|
|
504
|
-
let complexity = 1
|
|
505
|
-
if (analysis.features.length > 0) complexity += analysis.features.length
|
|
506
|
-
if (analysis.domains.length > 0) complexity += analysis.domains.length
|
|
507
|
-
if (analysis.hasCompliance) complexity += 2
|
|
508
|
-
if (analysis.hasPayment) complexity += 2
|
|
509
|
-
if (analysis.hasAuth) complexity += 1
|
|
510
|
-
if (analysis.isExternalFacing) complexity += 1
|
|
511
|
-
if (/integration|external api|third-party/i.test(combined)) complexity += 2
|
|
512
|
-
|
|
513
|
-
analysis.complexity = Math.min(complexity, 10)
|
|
514
|
-
|
|
515
|
-
// Adjust risk level
|
|
516
|
-
if (analysis.complexity >= 7 || analysis.hasCompliance || analysis.hasPayment) {
|
|
517
|
-
analysis.riskLevel = 'HIGH'
|
|
518
|
-
} else if (analysis.complexity >= 4 || analysis.hasAuth) {
|
|
519
|
-
analysis.riskLevel = 'MEDIUM'
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
return analysis
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
// Determine research layers dynamically based on change characteristics
|
|
526
|
-
function determineResearchLayers(analysis) {
|
|
527
|
-
const layers = []
|
|
528
|
-
let order = 1
|
|
529
|
-
|
|
530
|
-
// Check for trivial changes (0 layers)
|
|
531
|
-
if (analysis.complexity <= 1 &&
|
|
532
|
-
!analysis.hasUI && !analysis.hasAPI && !analysis.hasDatabase &&
|
|
533
|
-
analysis.riskLevel === 'LOW') {
|
|
534
|
-
return [] // No research needed
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
// L1: Best Practice (ALWAYS for non-trivial changes)
|
|
538
|
-
layers.push({
|
|
539
|
-
order: order++,
|
|
540
|
-
name: 'Best Practice / Industry Standard',
|
|
541
|
-
focus: `How do others implement ${analysis.primaryType}?`,
|
|
542
|
-
questions: [
|
|
543
|
-
`What is the industry standard for ${analysis.primaryType}?`,
|
|
544
|
-
'What are common patterns and anti-patterns?',
|
|
545
|
-
'What are the key success factors?',
|
|
546
|
-
'What are common failure modes?'
|
|
547
|
-
],
|
|
548
|
-
searchTopics: [`${analysis.primaryType} best practices`, `${analysis.primaryType} patterns`]
|
|
549
|
-
})
|
|
550
|
-
|
|
551
|
-
// L2+: Dynamic layers based on context
|
|
552
|
-
|
|
553
|
-
// Security layer (for auth, payment, sensitive data)
|
|
554
|
-
if (analysis.hasAuth || analysis.hasPayment || analysis.hasSensitiveData) {
|
|
555
|
-
layers.push({
|
|
556
|
-
order: order++,
|
|
557
|
-
name: 'Security Requirements',
|
|
558
|
-
focus: 'What security measures are required?',
|
|
559
|
-
questions: [
|
|
560
|
-
'What authentication/authorization is needed?',
|
|
561
|
-
'What data protection is required?',
|
|
562
|
-
'What are common security vulnerabilities?',
|
|
563
|
-
'What compliance requirements apply?'
|
|
564
|
-
],
|
|
565
|
-
searchTopics: ['security best practices', `${analysis.primaryType} security`]
|
|
566
|
-
})
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
// Compliance layer (for regulated industries)
|
|
570
|
-
if (analysis.hasCompliance || analysis.industryContext) {
|
|
571
|
-
layers.push({
|
|
572
|
-
order: order++,
|
|
573
|
-
name: `${analysis.industryContext || 'Industry'} Compliance`,
|
|
574
|
-
focus: `What ${analysis.industryContext || 'industry'} regulations apply?`,
|
|
575
|
-
questions: [
|
|
576
|
-
'What regulatory requirements must be met?',
|
|
577
|
-
'What audit trails are needed?',
|
|
578
|
-
'What data handling rules apply?',
|
|
579
|
-
'What documentation is required?'
|
|
580
|
-
],
|
|
581
|
-
searchTopics: [`${analysis.industryContext} compliance`, `${analysis.industryContext} regulations`]
|
|
582
|
-
})
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
// UX layer (for external-facing UI)
|
|
586
|
-
if (analysis.isExternalFacing && analysis.hasUI) {
|
|
587
|
-
layers.push({
|
|
588
|
-
order: order++,
|
|
589
|
-
name: 'User Experience Patterns',
|
|
590
|
-
focus: 'What UX patterns work for this audience?',
|
|
591
|
-
questions: [
|
|
592
|
-
'What user journey is expected?',
|
|
593
|
-
'What conversion patterns work?',
|
|
594
|
-
'What accessibility requirements apply?',
|
|
595
|
-
'What are user expectations?'
|
|
596
|
-
],
|
|
597
|
-
searchTopics: [`${analysis.primaryType} UX`, `${analysis.audience} UX patterns`]
|
|
598
|
-
})
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
// Psychology layer (for marketing/sales)
|
|
602
|
-
if (analysis.primaryType === 'marketing' || /conversion|sales|cta/i.test(analysis.primaryType)) {
|
|
603
|
-
layers.push({
|
|
604
|
-
order: order++,
|
|
605
|
-
name: 'Conversion Psychology',
|
|
606
|
-
focus: 'What psychological triggers work?',
|
|
607
|
-
questions: [
|
|
608
|
-
'What is the buyer awareness level?',
|
|
609
|
-
'What pain points to address?',
|
|
610
|
-
'What objections to overcome?',
|
|
611
|
-
'What social proof is needed?'
|
|
612
|
-
],
|
|
613
|
-
searchTopics: ['conversion psychology', 'landing page psychology']
|
|
614
|
-
})
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
// Content Strategy layer (for content-heavy pages)
|
|
618
|
-
if (analysis.primaryType === 'marketing' || /content|blog|documentation/i.test(analysis.primaryType)) {
|
|
619
|
-
layers.push({
|
|
620
|
-
order: order++,
|
|
621
|
-
name: 'Content Strategy',
|
|
622
|
-
focus: 'What content structure works?',
|
|
623
|
-
questions: [
|
|
624
|
-
'What content hierarchy is effective?',
|
|
625
|
-
'What tone and voice to use?',
|
|
626
|
-
'What call-to-actions work?',
|
|
627
|
-
'What content gaps exist?'
|
|
628
|
-
],
|
|
629
|
-
searchTopics: ['content strategy', 'copywriting best practices']
|
|
630
|
-
})
|
|
631
|
-
}
|
|
632
|
-
|
|
633
|
-
// Data Architecture layer (for database/data-intensive)
|
|
634
|
-
if (analysis.hasDatabase || /data|analytics|reporting/i.test(analysis.primaryType)) {
|
|
635
|
-
layers.push({
|
|
636
|
-
order: order++,
|
|
637
|
-
name: 'Data Architecture',
|
|
638
|
-
focus: 'What data patterns are appropriate?',
|
|
639
|
-
questions: [
|
|
640
|
-
'What normalization level is appropriate?',
|
|
641
|
-
'What indexing strategy is needed?',
|
|
642
|
-
'What scaling considerations apply?',
|
|
643
|
-
'What data integrity rules?'
|
|
644
|
-
],
|
|
645
|
-
searchTopics: ['database design patterns', 'data architecture']
|
|
646
|
-
})
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
// API Design layer (for API-focused changes)
|
|
650
|
-
if (analysis.hasAPI || analysis.primaryType === 'api') {
|
|
651
|
-
layers.push({
|
|
652
|
-
order: order++,
|
|
653
|
-
name: 'API Design',
|
|
654
|
-
focus: 'What API patterns are appropriate?',
|
|
655
|
-
questions: [
|
|
656
|
-
'What API style is appropriate (REST/GraphQL)?',
|
|
657
|
-
'What versioning strategy?',
|
|
658
|
-
'What error handling patterns?',
|
|
659
|
-
'What rate limiting/throttling?'
|
|
660
|
-
],
|
|
661
|
-
searchTopics: ['API design best practices', 'REST API patterns']
|
|
662
|
-
})
|
|
663
|
-
}
|
|
664
|
-
|
|
665
|
-
// Multi-tenancy layer (for SaaS)
|
|
666
|
-
if (analysis.features.includes('multi-tenancy')) {
|
|
667
|
-
layers.push({
|
|
668
|
-
order: order++,
|
|
669
|
-
name: 'Multi-tenancy Patterns',
|
|
670
|
-
focus: 'What isolation and scaling patterns?',
|
|
671
|
-
questions: [
|
|
672
|
-
'What data isolation model?',
|
|
673
|
-
'What authentication per tenant?',
|
|
674
|
-
'What resource limits?',
|
|
675
|
-
'What billing model integration?'
|
|
676
|
-
],
|
|
677
|
-
searchTopics: ['multi-tenant architecture', 'SaaS patterns']
|
|
678
|
-
})
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
// Real-time layer (for collaboration/live features)
|
|
682
|
-
if (analysis.features.includes('realtime')) {
|
|
683
|
-
layers.push({
|
|
684
|
-
order: order++,
|
|
685
|
-
name: 'Real-time Architecture',
|
|
686
|
-
focus: 'What real-time patterns are needed?',
|
|
687
|
-
questions: [
|
|
688
|
-
'WebSocket vs SSE vs polling?',
|
|
689
|
-
'What conflict resolution?',
|
|
690
|
-
'What offline support?',
|
|
691
|
-
'What scaling for connections?'
|
|
692
|
-
],
|
|
693
|
-
searchTopics: ['real-time architecture', 'WebSocket patterns']
|
|
694
|
-
})
|
|
695
|
-
}
|
|
696
|
-
|
|
697
|
-
// Performance layer (for high-traffic or data-intensive)
|
|
698
|
-
if (analysis.isExternalFacing || analysis.complexity >= 6 ||
|
|
699
|
-
/performance|speed|optimization|cache/i.test(analysis.primaryType)) {
|
|
700
|
-
layers.push({
|
|
701
|
-
order: order++,
|
|
702
|
-
name: 'Performance Optimization',
|
|
703
|
-
focus: 'What performance patterns are needed?',
|
|
704
|
-
questions: [
|
|
705
|
-
'What caching strategy?',
|
|
706
|
-
'What lazy loading patterns?',
|
|
707
|
-
'What CDN/edge considerations?',
|
|
708
|
-
'What database optimization?'
|
|
709
|
-
],
|
|
710
|
-
searchTopics: ['performance optimization', 'caching strategies']
|
|
711
|
-
})
|
|
712
|
-
}
|
|
713
|
-
|
|
714
|
-
// Integration layer (for external APIs/services)
|
|
715
|
-
if (/integration|external api|third-party|webhook/i.test(analysis.primaryType) ||
|
|
716
|
-
analysis.features.some(f => /payment|email|sms|notification/i.test(f))) {
|
|
717
|
-
layers.push({
|
|
718
|
-
order: order++,
|
|
719
|
-
name: 'Integration Patterns',
|
|
720
|
-
focus: 'What integration patterns are robust?',
|
|
721
|
-
questions: [
|
|
722
|
-
'What retry/circuit breaker patterns?',
|
|
723
|
-
'What error handling for external failures?',
|
|
724
|
-
'What monitoring/alerting?',
|
|
725
|
-
'What idempotency requirements?'
|
|
726
|
-
],
|
|
727
|
-
searchTopics: ['integration patterns', 'API integration best practices']
|
|
728
|
-
})
|
|
729
|
-
}
|
|
730
|
-
|
|
731
|
-
// Testing Strategy layer (for complex/high-risk)
|
|
732
|
-
if (analysis.riskLevel === 'HIGH' || analysis.complexity >= 7) {
|
|
733
|
-
layers.push({
|
|
734
|
-
order: order++,
|
|
735
|
-
name: 'Testing Strategy',
|
|
736
|
-
focus: 'What testing coverage is needed?',
|
|
737
|
-
questions: [
|
|
738
|
-
'What unit vs integration vs e2e balance?',
|
|
739
|
-
'What edge cases to cover?',
|
|
740
|
-
'What load/stress testing?',
|
|
741
|
-
'What security testing?'
|
|
742
|
-
],
|
|
743
|
-
searchTopics: ['testing strategy', `${analysis.primaryType} testing`]
|
|
744
|
-
})
|
|
745
|
-
}
|
|
746
|
-
|
|
747
|
-
return layers
|
|
748
|
-
}
|
|
749
|
-
|
|
750
|
-
// Execute research for a single layer using Claude's knowledge
|
|
751
|
-
// WHY: Domain knowledge (UX, DB design, security patterns) comes from Claude's training
|
|
752
|
-
// Stack knowledge (Prisma, React) comes from Context7 in Step 2.7
|
|
753
|
-
function executeLayerResearch(layer, changeAnalysis) {
|
|
754
|
-
const result = {
|
|
755
|
-
layer: layer.name,
|
|
756
|
-
findings: [],
|
|
757
|
-
recommendations: [],
|
|
758
|
-
warnings: [],
|
|
759
|
-
requiredItems: [], // Critical checklist items that MUST be addressed
|
|
760
|
-
source: 'claude-knowledge'
|
|
761
|
-
}
|
|
762
|
-
|
|
763
|
-
// Claude generates best practices based on:
|
|
764
|
-
// - Layer context (what domain?)
|
|
765
|
-
// - Change analysis (what's being built?)
|
|
766
|
-
// - Questions to answer (what to research?)
|
|
767
|
-
//
|
|
768
|
-
// Claude's training includes:
|
|
769
|
-
// - UX: Nielsen Norman, Baymard Institute, Laws of UX
|
|
770
|
-
// - Database: Codd's normalization, indexing patterns
|
|
771
|
-
// - Security: OWASP, auth patterns, encryption
|
|
772
|
-
// - API: REST dissertation, versioning patterns
|
|
773
|
-
// - Architecture: distributed systems, caching, scaling
|
|
774
|
-
|
|
775
|
-
result.findings = generateDomainKnowledge(layer, changeAnalysis)
|
|
776
|
-
result.recommendations = generateRecommendations(layer, changeAnalysis)
|
|
777
|
-
result.warnings = checkForWarnings(layer, changeAnalysis)
|
|
778
|
-
|
|
779
|
-
// Inject critical required items based on layer and context
|
|
780
|
-
// WHY: These are non-negotiable security/compliance requirements
|
|
781
|
-
result.requiredItems = injectCriticalRequiredItems(layer, changeAnalysis)
|
|
782
|
-
|
|
783
|
-
return result
|
|
784
|
-
}
|
|
785
|
-
|
|
786
|
-
// ============================================================
|
|
787
|
-
// CRITICAL FLOW REQUIREMENTS (v2.8.0)
|
|
788
|
-
// ============================================================
|
|
789
|
-
// These are non-negotiable items that MUST be in the checklist
|
|
790
|
-
// WHY: Security/compliance failures have legal/financial consequences
|
|
791
|
-
|
|
792
|
-
/**
|
|
793
|
-
* Inject critical required items based on layer type and change context
|
|
794
|
-
* Returns checklist items that agents MUST verify are implemented
|
|
795
|
-
*/
|
|
796
|
-
function injectCriticalRequiredItems(layer, changeAnalysis) {
|
|
797
|
-
const items = []
|
|
798
|
-
|
|
799
|
-
// Security Requirements Layer
|
|
800
|
-
if (layer.name === 'Security Requirements') {
|
|
801
|
-
// Auth-related critical items
|
|
802
|
-
if (changeAnalysis.hasAuth) {
|
|
803
|
-
items.push(...CRITICAL_FLOWS.auth.security)
|
|
804
|
-
}
|
|
805
|
-
// Payment-related critical items
|
|
806
|
-
if (changeAnalysis.hasPayment) {
|
|
807
|
-
items.push(...CRITICAL_FLOWS.payment.security)
|
|
808
|
-
}
|
|
809
|
-
// Sensitive data handling
|
|
810
|
-
if (changeAnalysis.hasSensitiveData) {
|
|
811
|
-
items.push(...CRITICAL_FLOWS.sensitiveData.security)
|
|
812
|
-
}
|
|
813
|
-
}
|
|
814
|
-
|
|
815
|
-
// Compliance Layer
|
|
816
|
-
if (layer.name.includes('Compliance')) {
|
|
817
|
-
if (changeAnalysis.industryContext === 'healthcare') {
|
|
818
|
-
items.push(...CRITICAL_FLOWS.healthcare.compliance)
|
|
819
|
-
}
|
|
820
|
-
if (changeAnalysis.industryContext === 'fintech') {
|
|
821
|
-
items.push(...CRITICAL_FLOWS.fintech.compliance)
|
|
822
|
-
}
|
|
823
|
-
}
|
|
824
|
-
|
|
825
|
-
// Data Architecture Layer
|
|
826
|
-
if (layer.name === 'Data Architecture') {
|
|
827
|
-
if (changeAnalysis.hasSensitiveData) {
|
|
828
|
-
items.push(...CRITICAL_FLOWS.sensitiveData.dataArchitecture)
|
|
829
|
-
}
|
|
830
|
-
}
|
|
831
|
-
|
|
832
|
-
return items
|
|
833
|
-
}
|
|
834
|
-
|
|
835
|
-
/**
|
|
836
|
-
* Critical Flow Definitions
|
|
837
|
-
* Format: { category: { layer: [...items] } }
|
|
838
|
-
* Each item has: id, check, why, severity
|
|
839
|
-
*/
|
|
840
|
-
const CRITICAL_FLOWS = {
|
|
841
|
-
// ============================================================
|
|
842
|
-
// AUTH CRITICAL FLOWS
|
|
843
|
-
// ============================================================
|
|
844
|
-
auth: {
|
|
845
|
-
security: [
|
|
846
|
-
{
|
|
847
|
-
id: 'auth-password-hash',
|
|
848
|
-
check: '☐ Password hashing with bcrypt/argon2 (cost factor ≥ 10)',
|
|
849
|
-
why: 'Plain text or weak hashing = immediate breach if DB leaked',
|
|
850
|
-
severity: 'critical'
|
|
851
|
-
},
|
|
852
|
-
{
|
|
853
|
-
id: 'auth-rate-limit',
|
|
854
|
-
check: '☐ Rate limiting on login (max 5 attempts per 15 min)',
|
|
855
|
-
why: 'Prevents brute force attacks',
|
|
856
|
-
severity: 'critical'
|
|
857
|
-
},
|
|
858
|
-
{
|
|
859
|
-
id: 'auth-session-timeout',
|
|
860
|
-
check: '☐ Session timeout configured (≤ 24h, ≤ 15min for sensitive)',
|
|
861
|
-
why: 'Abandoned sessions are attack vectors',
|
|
862
|
-
severity: 'high'
|
|
863
|
-
},
|
|
864
|
-
{
|
|
865
|
-
id: 'auth-csrf',
|
|
866
|
-
check: '☐ CSRF protection on all state-changing endpoints',
|
|
867
|
-
why: 'OWASP Top 10 vulnerability',
|
|
868
|
-
severity: 'critical'
|
|
869
|
-
},
|
|
870
|
-
{
|
|
871
|
-
id: 'auth-secure-cookies',
|
|
872
|
-
check: '☐ Cookies: httpOnly, secure, sameSite=strict',
|
|
873
|
-
why: 'Prevents XSS token theft and CSRF',
|
|
874
|
-
severity: 'critical'
|
|
875
|
-
},
|
|
876
|
-
{
|
|
877
|
-
id: 'auth-password-policy',
|
|
878
|
-
check: '☐ Password policy enforced (min 8 chars, complexity optional)',
|
|
879
|
-
why: 'Weak passwords are #1 breach cause',
|
|
880
|
-
severity: 'high'
|
|
881
|
-
},
|
|
882
|
-
{
|
|
883
|
-
id: 'auth-account-lockout',
|
|
884
|
-
check: '☐ Account lockout after repeated failures (with unlock mechanism)',
|
|
885
|
-
why: 'Prevents brute force, but needs recovery path',
|
|
886
|
-
severity: 'medium'
|
|
887
|
-
}
|
|
888
|
-
],
|
|
889
|
-
flow: [
|
|
890
|
-
{
|
|
891
|
-
id: 'auth-flow-login',
|
|
892
|
-
check: '☐ Login flow: input → validate → session → redirect',
|
|
893
|
-
why: 'Standard secure login pattern',
|
|
894
|
-
severity: 'high'
|
|
895
|
-
},
|
|
896
|
-
{
|
|
897
|
-
id: 'auth-flow-logout',
|
|
898
|
-
check: '☐ Logout: invalidate session server-side (not just cookie)',
|
|
899
|
-
why: 'Client-side only logout leaves session valid',
|
|
900
|
-
severity: 'high'
|
|
901
|
-
},
|
|
902
|
-
{
|
|
903
|
-
id: 'auth-flow-forgot',
|
|
904
|
-
check: '☐ Forgot password: email → time-limited token → reset',
|
|
905
|
-
why: 'Token must expire (≤ 1 hour)',
|
|
906
|
-
severity: 'high'
|
|
907
|
-
}
|
|
908
|
-
]
|
|
909
|
-
},
|
|
910
|
-
|
|
911
|
-
// ============================================================
|
|
912
|
-
// PAYMENT CRITICAL FLOWS
|
|
913
|
-
// ============================================================
|
|
914
|
-
payment: {
|
|
915
|
-
security: [
|
|
916
|
-
{
|
|
917
|
-
id: 'payment-no-card-storage',
|
|
918
|
-
check: '☐ NO raw card numbers stored (use Stripe/payment provider tokens)',
|
|
919
|
-
why: 'PCI-DSS requirement, storing cards = massive liability',
|
|
920
|
-
severity: 'critical'
|
|
921
|
-
},
|
|
922
|
-
{
|
|
923
|
-
id: 'payment-https',
|
|
924
|
-
check: '☐ HTTPS enforced on all payment pages',
|
|
925
|
-
why: 'Payment data in transit must be encrypted',
|
|
926
|
-
severity: 'critical'
|
|
927
|
-
},
|
|
928
|
-
{
|
|
929
|
-
id: 'payment-webhook-verify',
|
|
930
|
-
check: '☐ Webhook signature verification (never trust unverified webhooks)',
|
|
931
|
-
why: 'Attackers can fake payment success webhooks',
|
|
932
|
-
severity: 'critical'
|
|
933
|
-
},
|
|
934
|
-
{
|
|
935
|
-
id: 'payment-idempotency',
|
|
936
|
-
check: '☐ Idempotency keys for payment creation',
|
|
937
|
-
why: 'Prevents double charges on retry',
|
|
938
|
-
severity: 'high'
|
|
939
|
-
},
|
|
940
|
-
{
|
|
941
|
-
id: 'payment-amount-verify',
|
|
942
|
-
check: '☐ Server-side price verification (never trust client price)',
|
|
943
|
-
why: 'Attackers modify client-side prices',
|
|
944
|
-
severity: 'critical'
|
|
945
|
-
}
|
|
946
|
-
],
|
|
947
|
-
flow: [
|
|
948
|
-
{
|
|
949
|
-
id: 'payment-flow-checkout',
|
|
950
|
-
check: '☐ Checkout flow: cart → address → payment → confirm → receipt',
|
|
951
|
-
why: 'Standard e-commerce pattern users expect',
|
|
952
|
-
severity: 'medium'
|
|
953
|
-
},
|
|
954
|
-
{
|
|
955
|
-
id: 'payment-flow-error',
|
|
956
|
-
check: '☐ Payment error handling with clear user message',
|
|
957
|
-
why: 'Failed payments need recovery path',
|
|
958
|
-
severity: 'high'
|
|
959
|
-
},
|
|
960
|
-
{
|
|
961
|
-
id: 'payment-flow-refund',
|
|
962
|
-
check: '☐ Refund flow documented (even if manual)',
|
|
963
|
-
why: 'Legal requirement in most jurisdictions',
|
|
964
|
-
severity: 'high'
|
|
965
|
-
}
|
|
966
|
-
]
|
|
967
|
-
},
|
|
968
|
-
|
|
969
|
-
// ============================================================
|
|
970
|
-
// SENSITIVE DATA CRITICAL FLOWS
|
|
971
|
-
// ============================================================
|
|
972
|
-
sensitiveData: {
|
|
973
|
-
security: [
|
|
974
|
-
{
|
|
975
|
-
id: 'data-encryption-rest',
|
|
976
|
-
check: '☐ Encryption at rest for PII/PHI (AES-256 or DB-level)',
|
|
977
|
-
why: 'Breached DB without encryption = full exposure',
|
|
978
|
-
severity: 'critical'
|
|
979
|
-
},
|
|
980
|
-
{
|
|
981
|
-
id: 'data-encryption-transit',
|
|
982
|
-
check: '☐ Encryption in transit (TLS 1.2+)',
|
|
983
|
-
why: 'Data interception prevention',
|
|
984
|
-
severity: 'critical'
|
|
985
|
-
},
|
|
986
|
-
{
|
|
987
|
-
id: 'data-access-logging',
|
|
988
|
-
check: '☐ Audit logging for sensitive data access',
|
|
989
|
-
why: 'Required for breach investigation and compliance',
|
|
990
|
-
severity: 'high'
|
|
991
|
-
},
|
|
992
|
-
{
|
|
993
|
-
id: 'data-minimization',
|
|
994
|
-
check: '☐ Data minimization (only collect what is needed)',
|
|
995
|
-
why: 'GDPR principle, reduces breach impact',
|
|
996
|
-
severity: 'medium'
|
|
997
|
-
}
|
|
998
|
-
],
|
|
999
|
-
dataArchitecture: [
|
|
1000
|
-
{
|
|
1001
|
-
id: 'data-arch-backup',
|
|
1002
|
-
check: '☐ Backup strategy with encryption',
|
|
1003
|
-
why: 'Backups are often unencrypted breach vector',
|
|
1004
|
-
severity: 'high'
|
|
1005
|
-
},
|
|
1006
|
-
{
|
|
1007
|
-
id: 'data-arch-retention',
|
|
1008
|
-
check: '☐ Data retention policy defined',
|
|
1009
|
-
why: 'Legal requirement (GDPR right to deletion)',
|
|
1010
|
-
severity: 'medium'
|
|
1011
|
-
}
|
|
1012
|
-
]
|
|
1013
|
-
},
|
|
1014
|
-
|
|
1015
|
-
// ============================================================
|
|
1016
|
-
// HEALTHCARE COMPLIANCE (HIPAA)
|
|
1017
|
-
// ============================================================
|
|
1018
|
-
healthcare: {
|
|
1019
|
-
compliance: [
|
|
1020
|
-
{
|
|
1021
|
-
id: 'hipaa-phi-encrypt',
|
|
1022
|
-
check: '☐ All PHI encrypted at rest and in transit',
|
|
1023
|
-
why: 'HIPAA Security Rule requirement',
|
|
1024
|
-
severity: 'critical'
|
|
1025
|
-
},
|
|
1026
|
-
{
|
|
1027
|
-
id: 'hipaa-access-control',
|
|
1028
|
-
check: '☐ Role-based access control for PHI',
|
|
1029
|
-
why: 'Minimum necessary standard',
|
|
1030
|
-
severity: 'critical'
|
|
1031
|
-
},
|
|
1032
|
-
{
|
|
1033
|
-
id: 'hipaa-audit-trail',
|
|
1034
|
-
check: '☐ Audit trail for all PHI access (who, what, when)',
|
|
1035
|
-
why: 'HIPAA requires 6-year audit log retention',
|
|
1036
|
-
severity: 'critical'
|
|
1037
|
-
},
|
|
1038
|
-
{
|
|
1039
|
-
id: 'hipaa-baa',
|
|
1040
|
-
check: '☐ BAA signed with all vendors handling PHI',
|
|
1041
|
-
why: 'Business Associate Agreement legally required',
|
|
1042
|
-
severity: 'critical'
|
|
1043
|
-
},
|
|
1044
|
-
{
|
|
1045
|
-
id: 'hipaa-breach-plan',
|
|
1046
|
-
check: '☐ Breach notification plan documented',
|
|
1047
|
-
why: '60-day notification requirement',
|
|
1048
|
-
severity: 'high'
|
|
1049
|
-
}
|
|
1050
|
-
]
|
|
1051
|
-
},
|
|
1052
|
-
|
|
1053
|
-
// ============================================================
|
|
1054
|
-
// FINTECH COMPLIANCE (PCI-DSS)
|
|
1055
|
-
// ============================================================
|
|
1056
|
-
fintech: {
|
|
1057
|
-
compliance: [
|
|
1058
|
-
{
|
|
1059
|
-
id: 'pci-no-pan',
|
|
1060
|
-
check: '☐ No PAN (card numbers) stored unless PCI certified',
|
|
1061
|
-
why: 'PCI-DSS Level 1 requirement',
|
|
1062
|
-
severity: 'critical'
|
|
1063
|
-
},
|
|
1064
|
-
{
|
|
1065
|
-
id: 'pci-tokenization',
|
|
1066
|
-
check: '☐ Tokenization for card data (Stripe, Braintree)',
|
|
1067
|
-
why: 'Removes PCI scope from your systems',
|
|
1068
|
-
severity: 'critical'
|
|
1069
|
-
},
|
|
1070
|
-
{
|
|
1071
|
-
id: 'pci-network-segment',
|
|
1072
|
-
check: '☐ Network segmentation for payment systems',
|
|
1073
|
-
why: 'Limits breach blast radius',
|
|
1074
|
-
severity: 'high'
|
|
1075
|
-
},
|
|
1076
|
-
{
|
|
1077
|
-
id: 'fintech-kyc',
|
|
1078
|
-
check: '☐ KYC verification flow for financial accounts',
|
|
1079
|
-
why: 'AML/KYC regulations',
|
|
1080
|
-
severity: 'high'
|
|
1081
|
-
},
|
|
1082
|
-
{
|
|
1083
|
-
id: 'fintech-transaction-limits',
|
|
1084
|
-
check: '☐ Transaction limits and velocity checks',
|
|
1085
|
-
why: 'Fraud prevention, regulatory requirement',
|
|
1086
|
-
severity: 'high'
|
|
1087
|
-
},
|
|
1088
|
-
{
|
|
1089
|
-
id: 'fintech-audit',
|
|
1090
|
-
check: '☐ Transaction audit trail (immutable)',
|
|
1091
|
-
why: 'Regulatory reporting requirement',
|
|
1092
|
-
severity: 'critical'
|
|
1093
|
-
}
|
|
1094
|
-
]
|
|
1095
|
-
}
|
|
1096
|
-
}
|
|
1097
|
-
|
|
1098
|
-
// Generate domain knowledge using Claude's reasoning
|
|
1099
|
-
// This is where Claude applies its training to the specific change
|
|
1100
|
-
function generateDomainKnowledge(layer, changeAnalysis) {
|
|
1101
|
-
const findings = []
|
|
1102
|
-
|
|
1103
|
-
// Based on layer type, Claude will reason about best practices
|
|
1104
|
-
// The actual content comes from Claude's response when /csetup runs
|
|
1105
|
-
|
|
1106
|
-
findings.push({
|
|
1107
|
-
question: layer.questions[0],
|
|
1108
|
-
// Claude fills this based on its knowledge when executing
|
|
1109
|
-
analysis: `[Claude analyzes: ${layer.focus}]`,
|
|
1110
|
-
bestPractices: [], // Claude lists industry standards
|
|
1111
|
-
antiPatterns: [], // Claude lists what to avoid
|
|
1112
|
-
tradeoffs: [] // Claude explains trade-offs
|
|
1113
|
-
})
|
|
359
|
+
---
|
|
1114
360
|
|
|
1115
|
-
|
|
1116
|
-
}
|
|
361
|
+
#### Step 2.6.2: Detect Libraries
|
|
1117
362
|
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
if (!changeAnalysis.isExternalFacing) return conflicts
|
|
1124
|
-
|
|
1125
|
-
// Check color appropriateness for industry
|
|
1126
|
-
if (tokens.colors && changeAnalysis.industryContext) {
|
|
1127
|
-
const primaryColor = tokens.colors.primary
|
|
1128
|
-
|
|
1129
|
-
if (changeAnalysis.industryContext === 'healthcare') {
|
|
1130
|
-
// Healthcare typically uses blue/green (trust, calm)
|
|
1131
|
-
if (/red|orange|yellow/i.test(primaryColor)) {
|
|
1132
|
-
conflicts.push({
|
|
1133
|
-
aspect: 'Primary Color',
|
|
1134
|
-
current: primaryColor,
|
|
1135
|
-
industry: 'healthcare typically uses blue/green for trust and calm',
|
|
1136
|
-
recommendation: 'Consider if bright colors are appropriate for healthcare context'
|
|
1137
|
-
})
|
|
1138
|
-
}
|
|
1139
|
-
}
|
|
363
|
+
**Read these files and identify library/framework names:**
|
|
364
|
+
- `package.json` (dependencies, devDependencies)
|
|
365
|
+
- `requirements.txt` or `pyproject.toml` (Python)
|
|
366
|
+
- `openspec/changes/{changeId}/proposal.md`
|
|
367
|
+
- `openspec/changes/{changeId}/design.md`
|
|
1140
368
|
|
|
1141
|
-
|
|
1142
|
-
// Fintech typically uses blue/green (trust, money)
|
|
1143
|
-
if (/pink|purple|orange/i.test(primaryColor)) {
|
|
1144
|
-
conflicts.push({
|
|
1145
|
-
aspect: 'Primary Color',
|
|
1146
|
-
current: primaryColor,
|
|
1147
|
-
industry: 'fintech typically uses blue/green for trust and stability',
|
|
1148
|
-
recommendation: 'Consider if playful colors fit financial services context'
|
|
1149
|
-
})
|
|
1150
|
-
}
|
|
1151
|
-
}
|
|
1152
|
-
}
|
|
369
|
+
**Look for:** React, Next.js, Vue, Angular, FastAPI, Express, Django, Prisma, Drizzle, SQLAlchemy, Vitest, Jest, Playwright, Stripe, better-auth, etc.
|
|
1153
370
|
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
recommendation: 'Ensure animations have reduced-motion alternatives'
|
|
1162
|
-
})
|
|
1163
|
-
}
|
|
1164
|
-
}
|
|
371
|
+
**Output:**
|
|
372
|
+
```
|
|
373
|
+
🔍 Libraries Detected:
|
|
374
|
+
- Next.js (from package.json)
|
|
375
|
+
- Prisma (from design.md)
|
|
376
|
+
- better-auth (from tasks.md)
|
|
377
|
+
```
|
|
1165
378
|
|
|
1166
|
-
|
|
1167
|
-
}
|
|
379
|
+
---
|
|
1168
380
|
|
|
1169
|
-
|
|
1170
|
-
function generateResearchChecklist(changeAnalysis, layers, results) {
|
|
1171
|
-
let content = `# Research Checklist: ${changeAnalysis.primaryType}\n\n`
|
|
1172
|
-
content += `> Generated by Adaptive Depth Research (v2.4.0)\n`
|
|
1173
|
-
content += `> Complexity: ${changeAnalysis.complexity}/10 | Risk: ${changeAnalysis.riskLevel}\n\n`
|
|
1174
|
-
|
|
1175
|
-
if (layers.length === 0) {
|
|
1176
|
-
content += `## ✅ No Research Required\n\n`
|
|
1177
|
-
content += `This is a trivial change (complexity ${changeAnalysis.complexity}/10).\n`
|
|
1178
|
-
content += `Proceed directly with implementation.\n`
|
|
1179
|
-
return content
|
|
1180
|
-
}
|
|
381
|
+
#### Step 2.6.3: Fetch Best Practices via Context7
|
|
1181
382
|
|
|
1182
|
-
|
|
1183
|
-
content += `| Layer | Focus | Status |\n`
|
|
1184
|
-
content += `|-------|-------|--------|\n`
|
|
1185
|
-
layers.forEach((layer, idx) => {
|
|
1186
|
-
content += `| L${idx + 1}: ${layer.name} | ${layer.focus} | ⏳ Pending |\n`
|
|
1187
|
-
})
|
|
383
|
+
**For EACH detected library, call these MCP tools:**
|
|
1188
384
|
|
|
1189
|
-
|
|
385
|
+
```
|
|
386
|
+
1. mcp__context7__resolve-library-id
|
|
387
|
+
Input: { libraryName: "Next.js" }
|
|
388
|
+
Output: Get the context7CompatibleLibraryID (e.g., "/vercel/next.js")
|
|
389
|
+
|
|
390
|
+
2. mcp__context7__get-library-docs
|
|
391
|
+
Input: {
|
|
392
|
+
context7CompatibleLibraryID: "/vercel/next.js",
|
|
393
|
+
topic: "best practices, patterns, common mistakes, [other-lib-names]",
|
|
394
|
+
mode: "code"
|
|
395
|
+
}
|
|
396
|
+
Output: Documentation with best practices
|
|
397
|
+
```
|
|
1190
398
|
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
const layer = layers[idx]
|
|
1194
|
-
content += `## L${idx + 1}: ${layer.name}\n\n`
|
|
1195
|
-
content += `**Focus:** ${layer.focus}\n\n`
|
|
399
|
+
**Smart Topic Query:** Include OTHER detected library names in the topic for cross-library integration docs.
|
|
400
|
+
Example: When fetching Prisma docs, include "Next.js, React" in topic.
|
|
1196
401
|
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
})
|
|
402
|
+
**Skip if:**
|
|
403
|
+
- Library not found in Context7 (note in warnings section instead)
|
|
404
|
+
- Library already has cached best practices from previous run
|
|
1201
405
|
|
|
1202
|
-
|
|
1203
|
-
content += `\n### Findings\n\n`
|
|
1204
|
-
result.findings.forEach(f => {
|
|
1205
|
-
content += `#### ${f.topic}\n\n`
|
|
1206
|
-
if (Array.isArray(f.content)) {
|
|
1207
|
-
f.content.forEach(point => content += `- ${point}\n`)
|
|
1208
|
-
} else {
|
|
1209
|
-
content += `${f.content}\n`
|
|
1210
|
-
}
|
|
1211
|
-
content += `\n*Source: ${f.source}*\n\n`
|
|
1212
|
-
})
|
|
1213
|
-
}
|
|
406
|
+
---
|
|
1214
407
|
|
|
1215
|
-
|
|
1216
|
-
content += `### Recommendations\n\n`
|
|
1217
|
-
result.recommendations.forEach(r => {
|
|
1218
|
-
content += `- ${r}\n`
|
|
1219
|
-
})
|
|
1220
|
-
}
|
|
408
|
+
#### Step 2.6.4: Determine Research Layers
|
|
1221
409
|
|
|
1222
|
-
|
|
1223
|
-
content += `\n### ⚠️ Warnings\n\n`
|
|
1224
|
-
result.warnings.forEach(w => {
|
|
1225
|
-
content += `- ${w}\n`
|
|
1226
|
-
})
|
|
1227
|
-
}
|
|
410
|
+
**Based on change analysis, select relevant research layers:**
|
|
1228
411
|
|
|
1229
|
-
|
|
1230
|
-
|
|
412
|
+
| Trigger | Layer | Focus |
|
|
413
|
+
|---------|-------|-------|
|
|
414
|
+
| Always (complexity > 1) | Best Practices | How do others do this? |
|
|
415
|
+
| hasAuth OR hasPayment | Security | Authentication, data protection |
|
|
416
|
+
| healthcare OR fintech | Compliance | HIPAA, PCI-DSS, regulations |
|
|
417
|
+
| isExternalFacing + hasUI | UX Patterns | User journey, accessibility |
|
|
418
|
+
| marketing type | Conversion Psychology | Triggers, objections, social proof |
|
|
419
|
+
| hasDatabase | Data Architecture | Normalization, indexing, scaling |
|
|
420
|
+
| hasAPI | API Design | REST/GraphQL, versioning, errors |
|
|
421
|
+
| payment feature | Payment Flows | PCI compliance, webhooks, idempotency |
|
|
1231
422
|
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
content += `> Use these as a starting point for content creation.\n\n`
|
|
1237
|
-
|
|
1238
|
-
content += `### Hero Section\n\n`
|
|
1239
|
-
content += `**Headline Strategy:**\n`
|
|
1240
|
-
content += `- Lead with primary pain point or aspiration\n`
|
|
1241
|
-
content += `- 8-12 words, emotional trigger\n`
|
|
1242
|
-
content += `- [Claude: Generate specific headline angle based on proposal]\n\n`
|
|
1243
|
-
|
|
1244
|
-
content += `**Subheadline:**\n`
|
|
1245
|
-
content += `- Concrete benefit + emotional payoff\n`
|
|
1246
|
-
content += `- 15-25 words\n`
|
|
1247
|
-
content += `- [Claude: Generate based on value proposition]\n\n`
|
|
1248
|
-
|
|
1249
|
-
content += `**CTA:**\n`
|
|
1250
|
-
content += `- Action verb + outcome\n`
|
|
1251
|
-
content += `- [Claude: Generate based on user journey stage]\n\n`
|
|
1252
|
-
|
|
1253
|
-
content += `### Value Proposition\n\n`
|
|
1254
|
-
content += `For each feature, translate to:\n`
|
|
1255
|
-
content += `| Feature | Benefit | Emotional Payoff |\n`
|
|
1256
|
-
content += `|---------|---------|------------------|\n`
|
|
1257
|
-
content += `| [Technical] | [What user gets] | [How it makes them feel] |\n\n`
|
|
1258
|
-
|
|
1259
|
-
content += `### Social Proof\n\n`
|
|
1260
|
-
content += `- Use specific results (numbers, timeframes)\n`
|
|
1261
|
-
content += `- Match testimonials to target audience\n`
|
|
1262
|
-
content += `- Include trust signals (logos, certifications)\n\n`
|
|
1263
|
-
|
|
1264
|
-
content += `---\n\n`
|
|
1265
|
-
}
|
|
423
|
+
**For each selected layer, generate:**
|
|
424
|
+
- 3-5 key questions to consider
|
|
425
|
+
- 2-3 recommendations from domain knowledge
|
|
426
|
+
- Warnings if applicable
|
|
1266
427
|
|
|
1267
|
-
|
|
1268
|
-
content += `When implementing this change, agents should:\n\n`
|
|
1269
|
-
content += `1. Review each layer's findings before starting\n`
|
|
1270
|
-
content += `2. Check off questions as they are addressed\n`
|
|
1271
|
-
content += `3. Follow recommendations where applicable\n`
|
|
1272
|
-
content += `4. Address warnings or document exceptions\n`
|
|
428
|
+
---
|
|
1273
429
|
|
|
1274
|
-
|
|
1275
|
-
content += `5. Use Content Guidelines section for copy direction\n`
|
|
1276
|
-
}
|
|
430
|
+
#### Step 2.6.5: Detect Integration Warnings
|
|
1277
431
|
|
|
1278
|
-
|
|
1279
|
-
}
|
|
432
|
+
**Cross-reference library combinations for known issues:**
|
|
1280
433
|
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
434
|
+
| Combination | Warning |
|
|
435
|
+
|-------------|---------|
|
|
436
|
+
| better-auth + custom JWT | better-auth handles JWT internally - don't duplicate |
|
|
437
|
+
| Prisma + serverless | Cold starts can timeout - use connection pooling |
|
|
438
|
+
| Next.js 14+ + pages router | App router is default - check which is intended |
|
|
439
|
+
| React 19 + old state libs | Check compatibility with new React features |
|
|
1286
440
|
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
]
|
|
1291
|
-
}
|
|
441
|
+
**Check Context7 docs for integration warnings:**
|
|
442
|
+
- Look for "migration", "breaking changes", "compatibility" in docs
|
|
443
|
+
- Note version-specific warnings
|
|
1292
444
|
|
|
1293
|
-
|
|
1294
|
-
function checkForWarnings(layer, changeAnalysis) {
|
|
1295
|
-
const warnings = []
|
|
445
|
+
---
|
|
1296
446
|
|
|
1297
|
-
|
|
1298
|
-
if (changeAnalysis.riskLevel === 'HIGH') {
|
|
1299
|
-
warnings.push(`HIGH risk change - review ${layer.name} carefully before deployment`)
|
|
1300
|
-
}
|
|
447
|
+
#### Step 2.6.6: Generate Critical Checklist Items
|
|
1301
448
|
|
|
1302
|
-
|
|
1303
|
-
if (layer.name.includes('Compliance') && changeAnalysis.hasCompliance) {
|
|
1304
|
-
warnings.push(`Regulatory compliance required - ensure all ${changeAnalysis.industryContext} requirements are met`)
|
|
1305
|
-
}
|
|
449
|
+
**Based on change characteristics, inject required items:**
|
|
1306
450
|
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
451
|
+
**If hasAuth:**
|
|
452
|
+
```
|
|
453
|
+
☐ Password hashing with bcrypt/argon2 (cost ≥ 10)
|
|
454
|
+
☐ Rate limiting on login (max 5 per 15 min)
|
|
455
|
+
☐ Session timeout configured
|
|
456
|
+
☐ CSRF protection on state-changing endpoints
|
|
457
|
+
☐ Cookies: httpOnly, secure, sameSite=strict
|
|
458
|
+
```
|
|
1311
459
|
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
460
|
+
**If hasPayment:**
|
|
461
|
+
```
|
|
462
|
+
☐ NO raw card storage (use Stripe tokens)
|
|
463
|
+
☐ HTTPS on all payment pages
|
|
464
|
+
☐ Webhook signature verification
|
|
465
|
+
☐ Idempotency keys for payments
|
|
466
|
+
☐ Server-side price verification
|
|
467
|
+
```
|
|
1316
468
|
|
|
1317
|
-
|
|
1318
|
-
|
|
469
|
+
**If healthcare/fintech:**
|
|
470
|
+
```
|
|
471
|
+
☐ Encryption at rest for PII/PHI
|
|
472
|
+
☐ Audit logging for sensitive data access
|
|
473
|
+
☐ Data minimization applied
|
|
474
|
+
☐ Compliance documentation prepared
|
|
1319
475
|
```
|
|
1320
476
|
|
|
1321
477
|
---
|
|
1322
478
|
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
> **Zero-Maintenance Design:** Automatically detects any library/framework from spec text and resolves via Context7.
|
|
1326
|
-
> **WHY:** Hardcoded mappings require constant maintenance and miss new libraries. Dynamic resolution works with any language (Python, Rust, Go, etc.) without code changes.
|
|
1327
|
-
|
|
1328
|
-
```typescript
|
|
1329
|
-
// ============================================================
|
|
1330
|
-
// STEP 2.7: Dynamic Tech Stack Detection & Best Practices
|
|
1331
|
-
// ============================================================
|
|
1332
|
-
|
|
1333
|
-
output(`\n🔍 Detecting Tech Stack (Dynamic Resolution)...`)
|
|
1334
|
-
|
|
1335
|
-
// 1. Gather text from ALL relevant sources
|
|
1336
|
-
const textSources = {
|
|
1337
|
-
proposal: Read(`openspec/changes/${changeId}/proposal.md`) || '',
|
|
1338
|
-
tasks: Read(`openspec/changes/${changeId}/tasks.md`) || '',
|
|
1339
|
-
design: fileExists(`openspec/changes/${changeId}/design.md`)
|
|
1340
|
-
? Read(`openspec/changes/${changeId}/design.md`) : '',
|
|
1341
|
-
packageJson: fileExists('package.json') ? Read('package.json') : '',
|
|
1342
|
-
requirementsTxt: fileExists('requirements.txt') ? Read('requirements.txt') : '',
|
|
1343
|
-
pyprojectToml: fileExists('pyproject.toml') ? Read('pyproject.toml') : '',
|
|
1344
|
-
cargoToml: fileExists('Cargo.toml') ? Read('Cargo.toml') : '',
|
|
1345
|
-
goMod: fileExists('go.mod') ? Read('go.mod') : '',
|
|
1346
|
-
composerJson: fileExists('composer.json') ? Read('composer.json') : '',
|
|
1347
|
-
gemfile: fileExists('Gemfile') ? Read('Gemfile') : ''
|
|
1348
|
-
}
|
|
1349
|
-
|
|
1350
|
-
const allText = Object.values(textSources).join('\n')
|
|
479
|
+
#### Step 2.6.7: Write pre-work-context.md
|
|
1351
480
|
|
|
1352
|
-
|
|
1353
|
-
// WHY: Pattern-based extraction still requires maintenance.
|
|
1354
|
-
// Instead, use Claude's understanding to identify libraries from context.
|
|
1355
|
-
output(` 🧠 Analyzing text semantically...`)
|
|
1356
|
-
|
|
1357
|
-
const potentialLibraries = await extractLibrariesSemantically(allText)
|
|
1358
|
-
|
|
1359
|
-
output(` 📝 Found ${potentialLibraries.length} potential libraries to verify`)
|
|
1360
|
-
|
|
1361
|
-
// 3. Resolve each potential library with Context7 (validate it's a real library)
|
|
1362
|
-
const resolvedLibraries = []
|
|
1363
|
-
const resolutionCache = new Map()
|
|
1364
|
-
|
|
1365
|
-
for (const candidate of potentialLibraries) {
|
|
1366
|
-
if (resolutionCache.has(candidate.toLowerCase())) continue
|
|
1367
|
-
|
|
1368
|
-
try {
|
|
1369
|
-
const result = await mcp__context7__resolve_library_id({
|
|
1370
|
-
libraryName: candidate
|
|
1371
|
-
})
|
|
1372
|
-
|
|
1373
|
-
const bestMatch = parseContext7Response(result, candidate)
|
|
1374
|
-
|
|
1375
|
-
if (bestMatch && bestMatch.score >= 60) {
|
|
1376
|
-
resolvedLibraries.push({
|
|
1377
|
-
name: candidate,
|
|
1378
|
-
context7Id: bestMatch.id,
|
|
1379
|
-
title: bestMatch.title,
|
|
1380
|
-
snippets: bestMatch.snippets,
|
|
1381
|
-
score: bestMatch.score
|
|
1382
|
-
})
|
|
1383
|
-
resolutionCache.set(candidate.toLowerCase(), bestMatch)
|
|
1384
|
-
output(` ✅ ${candidate} → ${bestMatch.id} (${bestMatch.snippets} snippets)`)
|
|
1385
|
-
}
|
|
1386
|
-
} catch (error) {
|
|
1387
|
-
resolutionCache.set(candidate.toLowerCase(), null)
|
|
1388
|
-
}
|
|
1389
|
-
}
|
|
481
|
+
**Create `openspec/changes/{changeId}/pre-work-context.md`:**
|
|
1390
482
|
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
output(` - ${lib.title} (${lib.context7Id})`)
|
|
1394
|
-
})
|
|
1395
|
-
|
|
1396
|
-
// 4. If no libraries detected, ask user for guidance
|
|
1397
|
-
if (resolvedLibraries.length === 0) {
|
|
1398
|
-
output(`\n⚠️ No libraries auto-detected from spec files`)
|
|
1399
|
-
|
|
1400
|
-
const answer = await askUserQuestion({
|
|
1401
|
-
questions: [{
|
|
1402
|
-
question: 'Enter the main libraries/frameworks for this project (comma-separated):',
|
|
1403
|
-
header: 'Libraries',
|
|
1404
|
-
options: [
|
|
1405
|
-
{ label: 'Skip', description: 'Continue without library-specific best practices' },
|
|
1406
|
-
{ label: 'React, Next.js', description: 'Common frontend stack' },
|
|
1407
|
-
{ label: 'FastAPI, SQLAlchemy, Pydantic', description: 'Python API stack' },
|
|
1408
|
-
{ label: 'Express, Prisma', description: 'Node.js backend stack' }
|
|
1409
|
-
],
|
|
1410
|
-
multiSelect: false
|
|
1411
|
-
}]
|
|
1412
|
-
})
|
|
1413
|
-
|
|
1414
|
-
if (!answer.includes('Skip')) {
|
|
1415
|
-
// Parse user input and resolve each
|
|
1416
|
-
const userLibraries = answer.split(',').map(s => s.trim()).filter(Boolean)
|
|
1417
|
-
for (const lib of userLibraries) {
|
|
1418
|
-
const result = await mcp__context7__resolve_library_id({ libraryName: lib })
|
|
1419
|
-
const bestMatch = parseContext7Response(result, lib)
|
|
1420
|
-
if (bestMatch) {
|
|
1421
|
-
resolvedLibraries.push({
|
|
1422
|
-
name: lib,
|
|
1423
|
-
context7Id: bestMatch.id,
|
|
1424
|
-
title: bestMatch.title,
|
|
1425
|
-
snippets: bestMatch.snippets,
|
|
1426
|
-
score: bestMatch.score
|
|
1427
|
-
})
|
|
1428
|
-
}
|
|
1429
|
-
}
|
|
1430
|
-
}
|
|
1431
|
-
}
|
|
483
|
+
```markdown
|
|
484
|
+
# Pre-Work Context: {changeId}
|
|
1432
485
|
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
const existingBp = fileExists(bpDir) ? listFiles(bpDir) : []
|
|
486
|
+
> **Generated:** {date}
|
|
487
|
+
> **Purpose:** All context agents need before implementation
|
|
488
|
+
> **Read by:** All agents in STEP 0
|
|
1437
489
|
|
|
1438
|
-
|
|
1439
|
-
const newLibraries = resolvedLibraries.filter(lib => {
|
|
1440
|
-
const safeName = lib.name.toLowerCase().replace(/[^a-z0-9]/g, '-')
|
|
1441
|
-
return !existingBp.some(f => f.toLowerCase().includes(safeName))
|
|
1442
|
-
})
|
|
490
|
+
---
|
|
1443
491
|
|
|
1444
|
-
|
|
1445
|
-
output(`\n📚 Generating Best Practices from Context7...`)
|
|
1446
|
-
output(` 💡 Using Smart Topic Query for cross-library integration docs`)
|
|
492
|
+
## 1. Change Analysis
|
|
1447
493
|
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
494
|
+
| Aspect | Value |
|
|
495
|
+
|--------|-------|
|
|
496
|
+
| Type | {primaryType} |
|
|
497
|
+
| Complexity | {complexity}/10 |
|
|
498
|
+
| Risk Level | {riskLevel} |
|
|
499
|
+
| Domains | {domains or "General"} |
|
|
500
|
+
| Features | {features or "None detected"} |
|
|
1452
501
|
|
|
1453
|
-
|
|
1454
|
-
const integrationRisks = []
|
|
1455
|
-
|
|
1456
|
-
for (const lib of newLibraries) {
|
|
1457
|
-
output(` 📖 Fetching ${lib.title} best practices...`)
|
|
1458
|
-
|
|
1459
|
-
try {
|
|
1460
|
-
// v2.5.0: Smart Topic Query - include other library names in topic
|
|
1461
|
-
// WHY: This captures integration docs (e.g., "drizzle adapter" in auth.js docs)
|
|
1462
|
-
const otherLibNames = resolvedLibraries
|
|
1463
|
-
.filter(l => l.name !== lib.name)
|
|
1464
|
-
.map(l => l.name.toLowerCase())
|
|
1465
|
-
.slice(0, 5) // Limit to 5 to avoid topic overflow
|
|
1466
|
-
.join(', ')
|
|
1467
|
-
|
|
1468
|
-
const smartTopic = [
|
|
1469
|
-
'best practices',
|
|
1470
|
-
'patterns',
|
|
1471
|
-
'anti-patterns',
|
|
1472
|
-
'common mistakes',
|
|
1473
|
-
'adapter', // Key for ORM + Auth integrations
|
|
1474
|
-
'integration', // Key for multi-library setups
|
|
1475
|
-
'schema', // Key for database + auth column naming
|
|
1476
|
-
'configuration', // Key for setup requirements
|
|
1477
|
-
otherLibNames // Include other detected libraries
|
|
1478
|
-
].filter(Boolean).join(', ')
|
|
1479
|
-
|
|
1480
|
-
const docs = await mcp__context7__get_library_docs({
|
|
1481
|
-
context7CompatibleLibraryID: lib.context7Id,
|
|
1482
|
-
topic: smartTopic,
|
|
1483
|
-
mode: 'code'
|
|
1484
|
-
})
|
|
1485
|
-
|
|
1486
|
-
// v2.5.0: Detect integration risks from docs content
|
|
1487
|
-
const risks = detectIntegrationRisks(docs, lib.name, resolvedLibraries)
|
|
1488
|
-
if (risks.length > 0) {
|
|
1489
|
-
integrationRisks.push(...risks)
|
|
1490
|
-
output(` ⚠️ Found ${risks.length} integration pattern(s) to review`)
|
|
1491
|
-
}
|
|
502
|
+
---
|
|
1492
503
|
|
|
1493
|
-
|
|
1494
|
-
const safeName = lib.name.toLowerCase().replace(/[^a-z0-9]/g, '-')
|
|
1495
|
-
Write(`${bpDir}${safeName}.md`, bpContent)
|
|
504
|
+
## 2. Library Best Practices
|
|
1496
505
|
|
|
1497
|
-
|
|
1498
|
-
} catch (error) {
|
|
1499
|
-
output(` ⚠️ ${lib.title} - failed to fetch docs, skipping`)
|
|
1500
|
-
}
|
|
1501
|
-
}
|
|
506
|
+
### {Library 1}
|
|
1502
507
|
|
|
1503
|
-
|
|
1504
|
-
if (integrationRisks.length > 0) {
|
|
1505
|
-
generateIntegrationRiskSummary(integrationRisks, bpDir, resolvedLibraries)
|
|
1506
|
-
output(`\n⚠️ Integration Risk Summary generated (${integrationRisks.length} items)`)
|
|
1507
|
-
output(` 📄 ${bpDir}INTEGRATION_RISKS.md`)
|
|
1508
|
-
}
|
|
508
|
+
**Source:** Context7 ({context7Id})
|
|
1509
509
|
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
510
|
+
**DO:**
|
|
511
|
+
- {best practice 1}
|
|
512
|
+
- {best practice 2}
|
|
1513
513
|
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
} else if (resolvedLibraries.length > 0) {
|
|
1518
|
-
output(`\n✅ Best Practices: Already configured for detected libraries`)
|
|
1519
|
-
} else {
|
|
1520
|
-
output(`\n✅ Best Practices: Skipped (no libraries to configure)`)
|
|
1521
|
-
}
|
|
514
|
+
**DON'T:**
|
|
515
|
+
- {anti-pattern 1}
|
|
516
|
+
- {anti-pattern 2}
|
|
1522
517
|
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
resolved: resolvedLibraries,
|
|
1527
|
-
bestPracticesPath: bpDir,
|
|
1528
|
-
files: existingBp.concat(newLibraries.map(l => `${l.name.toLowerCase().replace(/[^a-z0-9]/g, '-')}.md`))
|
|
1529
|
-
}
|
|
518
|
+
**Code Example:**
|
|
519
|
+
```{lang}
|
|
520
|
+
{example code from Context7}
|
|
1530
521
|
```
|
|
1531
522
|
|
|
523
|
+
### {Library 2}
|
|
524
|
+
{repeat structure}
|
|
525
|
+
|
|
1532
526
|
---
|
|
1533
527
|
|
|
1534
|
-
|
|
528
|
+
## 3. Research Findings
|
|
1535
529
|
|
|
1536
|
-
|
|
1537
|
-
> **WHY:** Pattern-based regex always has edge cases. Claude understands context and meaning.
|
|
530
|
+
### L1: {Layer Name}
|
|
1538
531
|
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
const truncatedText = text.length > 8000 ? text.slice(0, 8000) + '\n...[truncated]' : text
|
|
1543
|
-
|
|
1544
|
-
// Use Claude to semantically extract library/framework names
|
|
1545
|
-
// This is the MAIN Claude running /csetup, so we just analyze inline
|
|
1546
|
-
const prompt = `
|
|
1547
|
-
Analyze this text and extract ALL programming libraries, frameworks, and tools mentioned.
|
|
1548
|
-
|
|
1549
|
-
TEXT:
|
|
1550
|
-
${truncatedText}
|
|
1551
|
-
|
|
1552
|
-
INSTRUCTIONS:
|
|
1553
|
-
1. Look for any technology names (libraries, frameworks, ORMs, databases, tools)
|
|
1554
|
-
2. Include both explicit mentions ("using Mastra") and implicit ones ("PostgreSQL database")
|
|
1555
|
-
3. Return ONLY the library/framework names, one per line
|
|
1556
|
-
4. Do NOT include generic terms like "API", "REST", "database" (unless it's a specific product name)
|
|
1557
|
-
5. Do NOT include programming languages (Python, JavaScript, etc.) unless they're library names
|
|
1558
|
-
6. Include package names from any language (npm, pip, cargo, go, etc.)
|
|
1559
|
-
|
|
1560
|
-
OUTPUT FORMAT (one name per line, nothing else):
|
|
1561
|
-
`
|
|
532
|
+
**Key Questions:**
|
|
533
|
+
- {question 1}
|
|
534
|
+
- {question 2}
|
|
1562
535
|
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
// For now, return a simple extraction that Main Claude will process
|
|
536
|
+
**Recommendations:**
|
|
537
|
+
- {recommendation based on domain knowledge}
|
|
1566
538
|
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
const patternBased = extractPotentialLibraryNames(text)
|
|
539
|
+
**Warnings:**
|
|
540
|
+
- {warning if applicable}
|
|
1570
541
|
|
|
1571
|
-
|
|
1572
|
-
// and add any libraries you identify from context that patterns missed.
|
|
1573
|
-
// Example: "The system uses Mastra for orchestration" → add "Mastra"
|
|
542
|
+
{repeat for each layer}
|
|
1574
543
|
|
|
1575
|
-
|
|
1576
|
-
}
|
|
1577
|
-
```
|
|
544
|
+
---
|
|
1578
545
|
|
|
1579
|
-
|
|
546
|
+
## 4. Integration Warnings
|
|
1580
547
|
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
2. Identify any library/framework names the patterns might have missed
|
|
1584
|
-
3. Add them to the `potentialLibraries` array before Context7 validation
|
|
548
|
+
⚠️ **{Library A} + {Library B}:**
|
|
549
|
+
{warning description}
|
|
1585
550
|
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
- Claude's semantic understanding catches edge cases
|
|
1589
|
-
- Context7 validates everything (filters out false positives)
|
|
551
|
+
⚠️ **{Another combination}:**
|
|
552
|
+
{warning description}
|
|
1590
553
|
|
|
1591
554
|
---
|
|
1592
555
|
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
> **Pattern-based fallback:** Provides baseline extraction. Main Claude enhances with semantic analysis.
|
|
1596
|
-
|
|
1597
|
-
```typescript
|
|
1598
|
-
function extractPotentialLibraryNames(text: string): string[] {
|
|
1599
|
-
const candidates = new Set<string>()
|
|
1600
|
-
|
|
1601
|
-
// === Pattern 1: Package file dependencies ===
|
|
1602
|
-
// package.json: "react": "^18.0.0" → react
|
|
1603
|
-
const npmDeps = text.match(/"([a-z@][a-z0-9._/-]*)"\s*:\s*"[\^~]?\d/gi) || []
|
|
1604
|
-
npmDeps.forEach(m => {
|
|
1605
|
-
const match = m.match(/"([^"]+)"/)
|
|
1606
|
-
if (match) candidates.add(match[1].replace(/^@[^/]+\//, '')) // Strip scope
|
|
1607
|
-
})
|
|
556
|
+
## 5. Critical Checklist
|
|
1608
557
|
|
|
1609
|
-
|
|
1610
|
-
// Allow optional leading whitespace for indented requirements
|
|
1611
|
-
const pyDeps = text.match(/^\s*([a-zA-Z][a-zA-Z0-9_-]*)\s*[=<>~!]/gm) || []
|
|
1612
|
-
pyDeps.forEach(m => {
|
|
1613
|
-
const match = m.match(/([a-zA-Z][a-zA-Z0-9_-]*)\s*[=<>~!]/)
|
|
1614
|
-
if (match) candidates.add(match[1])
|
|
1615
|
-
})
|
|
558
|
+
> **MUST complete before marking phase done**
|
|
1616
559
|
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
const rustDeps = text.match(/^\s*([a-z][a-z0-9_-]*)\s*=/gm) || []
|
|
1620
|
-
rustDeps.forEach(m => {
|
|
1621
|
-
const match = m.match(/([a-z][a-z0-9_-]*)\s*=/)
|
|
1622
|
-
if (match) candidates.add(match[1])
|
|
1623
|
-
})
|
|
560
|
+
### Security
|
|
561
|
+
{security items if applicable}
|
|
1624
562
|
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
goDeps.forEach(m => {
|
|
1628
|
-
const match = m.match(/\/([a-z][a-z0-9_-]*)$/i)
|
|
1629
|
-
if (match) candidates.add(match[1])
|
|
1630
|
-
})
|
|
563
|
+
### Compliance
|
|
564
|
+
{compliance items if applicable}
|
|
1631
565
|
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
const pyImports = text.match(/(?:from|import)\s+([a-zA-Z][a-zA-Z0-9_]*)/g) || []
|
|
1635
|
-
pyImports.forEach(m => {
|
|
1636
|
-
const match = m.match(/(?:from|import)\s+([a-zA-Z][a-zA-Z0-9_]*)/)
|
|
1637
|
-
if (match) candidates.add(match[1])
|
|
1638
|
-
})
|
|
566
|
+
### Data Protection
|
|
567
|
+
{data items if applicable}
|
|
1639
568
|
|
|
1640
|
-
|
|
1641
|
-
const jsImports = text.match(/(?:from|require\s*\(\s*)['"]([a-zA-Z@][a-zA-Z0-9._/-]*)['"]/g) || []
|
|
1642
|
-
jsImports.forEach(m => {
|
|
1643
|
-
const match = m.match(/['"]([^'"]+)['"]/)
|
|
1644
|
-
if (match) {
|
|
1645
|
-
const pkg = match[1].replace(/^@[^/]+\//, '').split('/')[0]
|
|
1646
|
-
candidates.add(pkg)
|
|
1647
|
-
}
|
|
1648
|
-
})
|
|
569
|
+
---
|
|
1649
570
|
|
|
1650
|
-
|
|
1651
|
-
const rustImports = text.match(/(?:use|extern\s+crate)\s+([a-z][a-z0-9_]*)/g) || []
|
|
1652
|
-
rustImports.forEach(m => {
|
|
1653
|
-
const match = m.match(/(?:use|extern\s+crate)\s+([a-z][a-z0-9_]*)/)
|
|
1654
|
-
if (match) candidates.add(match[1])
|
|
1655
|
-
})
|
|
571
|
+
## 6. Quick Reference
|
|
1656
572
|
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
techMentions.forEach(m => {
|
|
1661
|
-
const match = m.match(/\s([A-Z][a-zA-Z0-9.]*)$/i)
|
|
1662
|
-
if (match) candidates.add(match[1])
|
|
1663
|
-
})
|
|
573
|
+
**Package Manager:** {from tech-stack.md or detected}
|
|
574
|
+
**Test Command:** {detected test script}
|
|
575
|
+
**Build Command:** {detected build script}
|
|
1664
576
|
|
|
1665
|
-
|
|
1666
|
-
const camelCase = text.match(/\b([A-Z][a-z]+(?:[A-Z][a-z]+)+)\b/g) || []
|
|
1667
|
-
camelCase.forEach(w => candidates.add(w))
|
|
1668
|
-
|
|
1669
|
-
// Mixed case words (SQLAlchemy, PostgreSQL, GraphQL - uppercase prefix + CamelCase)
|
|
1670
|
-
const mixedCase = text.match(/\b([A-Z]{2,}[a-z]+[A-Za-z]*)\b/g) || []
|
|
1671
|
-
mixedCase.forEach(w => candidates.add(w))
|
|
1672
|
-
|
|
1673
|
-
// === Pattern 3.5: PascalCase single words after tech keywords ===
|
|
1674
|
-
// "Framework: Mastra", "ORM: Prisma", "Database: PostgreSQL"
|
|
1675
|
-
// WHY: Many library names are single PascalCase words (Mastra, Prisma, Django, Flask)
|
|
1676
|
-
const techKeywordPatterns = [
|
|
1677
|
-
/(?:framework|library|orm|database|db|backend|frontend|ui|css|styling)[:\s]+([A-Z][a-z]+\w*)/gi,
|
|
1678
|
-
/(?:built\s+with|powered\s+by|using|via|with)\s+([A-Z][a-z]+\w*)/gi,
|
|
1679
|
-
/\*\*(?:framework|library|orm|database|backend|frontend)\*\*[:\s]+([A-Z][a-z]+\w*)/gi
|
|
1680
|
-
]
|
|
1681
|
-
techKeywordPatterns.forEach(pattern => {
|
|
1682
|
-
const matches = text.matchAll(pattern)
|
|
1683
|
-
for (const match of matches) {
|
|
1684
|
-
if (match[1]) candidates.add(match[1])
|
|
1685
|
-
}
|
|
1686
|
-
})
|
|
577
|
+
---
|
|
1687
578
|
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
const mdListItems = text.match(/^[\s]*[-*]\s+([A-Z][a-z]+\w*)(?:\s|$)/gm) || []
|
|
1691
|
-
mdListItems.forEach(m => {
|
|
1692
|
-
const match = m.match(/[-*]\s+([A-Z][a-z]+\w*)/)
|
|
1693
|
-
if (match) candidates.add(match[1])
|
|
1694
|
-
})
|
|
579
|
+
**Agents: Read this file in STEP 0 before implementation.**
|
|
580
|
+
```
|
|
1695
581
|
|
|
1696
|
-
|
|
1697
|
-
// "Mastra for AI orchestration", "Drizzle for database"
|
|
1698
|
-
const forPattern = text.match(/([A-Z][a-z]+\w*)\s+for\s+(?:ai|database|backend|frontend|api|web|mobile|server|client)/gi) || []
|
|
1699
|
-
forPattern.forEach(m => {
|
|
1700
|
-
const match = m.match(/^([A-Z][a-z]+\w*)/)
|
|
1701
|
-
if (match) candidates.add(match[1])
|
|
1702
|
-
})
|
|
582
|
+
---
|
|
1703
583
|
|
|
1704
|
-
|
|
1705
|
-
const dotJs = text.match(/\b([A-Z][a-z]+)\.js\b/gi) || []
|
|
1706
|
-
dotJs.forEach(m => {
|
|
1707
|
-
const match = m.match(/([A-Z][a-z]+)/i)
|
|
1708
|
-
if (match) candidates.add(match[1])
|
|
1709
|
-
})
|
|
584
|
+
#### Step 2.6.8: Output Summary
|
|
1710
585
|
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
const techSection = text.match(/(?:tech\s*stack|technologies|built\s*with|dependencies)[:\s]+([^\n]+)/gi) || []
|
|
1714
|
-
techSection.forEach(section => {
|
|
1715
|
-
const items = section.split(/[,\s]+/)
|
|
1716
|
-
items.forEach(item => {
|
|
1717
|
-
const cleaned = item.replace(/[^a-zA-Z0-9.-]/g, '')
|
|
1718
|
-
if (cleaned.length > 2) candidates.add(cleaned)
|
|
1719
|
-
})
|
|
1720
|
-
})
|
|
586
|
+
```
|
|
587
|
+
✅ Pre-Work Context Generated!
|
|
1721
588
|
|
|
1722
|
-
|
|
1723
|
-
// "**Mastra**", "`prisma`", "**Framework:** Mastra"
|
|
1724
|
-
const boldWords = text.match(/\*\*([A-Z][a-z]+\w*)\*\*/g) || []
|
|
1725
|
-
boldWords.forEach(m => {
|
|
1726
|
-
const match = m.match(/\*\*([A-Z][a-z]+\w*)\*\*/)
|
|
1727
|
-
if (match) candidates.add(match[1])
|
|
1728
|
-
})
|
|
589
|
+
📄 File: openspec/changes/{changeId}/pre-work-context.md
|
|
1729
590
|
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
591
|
+
Contents:
|
|
592
|
+
- Change Analysis: {type}, {complexity}/10, {risk}
|
|
593
|
+
- Libraries: {count} ({names})
|
|
594
|
+
- Research Layers: {count}
|
|
595
|
+
- Integration Warnings: {count}
|
|
596
|
+
- Critical Checklist Items: {count}
|
|
1735
597
|
|
|
1736
|
-
|
|
1737
|
-
// Use lowercase for case-insensitive comparison
|
|
1738
|
-
const stopWords = new Set([
|
|
1739
|
-
// Common English words (all lowercase for comparison)
|
|
1740
|
-
'the', 'this', 'that', 'with', 'from', 'using', 'for', 'and', 'but', 'not',
|
|
1741
|
-
'all', 'any', 'can', 'could', 'should', 'would', 'will', 'may', 'might',
|
|
1742
|
-
'each', 'every', 'some', 'many', 'most', 'other', 'such', 'only', 'just',
|
|
1743
|
-
'also', 'well', 'back', 'even', 'still', 'already', 'always', 'never',
|
|
1744
|
-
// Common programming terms that aren't libraries
|
|
1745
|
-
'api', 'rest', 'http', 'https', 'json', 'xml', 'html', 'css', 'sql',
|
|
1746
|
-
'get', 'post', 'put', 'delete', 'patch', 'url', 'uri', 'uuid', 'id',
|
|
1747
|
-
'true', 'false', 'none', 'null', 'undefined', 'error', 'exception',
|
|
1748
|
-
'class', 'function', 'method', 'object', 'array', 'string', 'number',
|
|
1749
|
-
'boolean', 'int', 'float', 'double', 'char', 'byte', 'long', 'short',
|
|
1750
|
-
'public', 'private', 'protected', 'static', 'final', 'const', 'let', 'var',
|
|
1751
|
-
'import', 'export', 'module', 'package', 'interface', 'type', 'enum',
|
|
1752
|
-
'test', 'tests', 'spec', 'specs', 'mock', 'stub', 'fake', 'spy',
|
|
1753
|
-
'config', 'configuration', 'settings', 'options', 'params', 'args',
|
|
1754
|
-
'user', 'users', 'admin', 'auth', 'login', 'logout', 'session', 'token',
|
|
1755
|
-
'data', 'database', 'table', 'column', 'row', 'index', 'key', 'value',
|
|
1756
|
-
'file', 'files', 'path', 'dir', 'directory', 'folder', 'name', 'size',
|
|
1757
|
-
'create', 'read', 'update', 'delete', 'list', 'get', 'set', 'add', 'remove',
|
|
1758
|
-
'start', 'stop', 'run', 'build', 'deploy', 'install', 'setup', 'init',
|
|
1759
|
-
// Version/date patterns
|
|
1760
|
-
'version', 'release', 'beta', 'alpha', 'stable', 'latest', 'current'
|
|
1761
|
-
])
|
|
1762
|
-
|
|
1763
|
-
return [...candidates]
|
|
1764
|
-
.filter(w => w.length > 2 && w.length < 30)
|
|
1765
|
-
.filter(w => !stopWords.has(w.toLowerCase())) // Case-insensitive comparison
|
|
1766
|
-
.filter(w => !/^\d+$/.test(w)) // Not pure numbers
|
|
1767
|
-
.filter(w => !/^v?\d+\.\d+/.test(w)) // Not version numbers
|
|
1768
|
-
.slice(0, 50) // Limit to avoid too many API calls
|
|
1769
|
-
}
|
|
598
|
+
📌 Agents will read this in STEP 0
|
|
1770
599
|
```
|
|
1771
600
|
|
|
1772
601
|
---
|
|
1773
602
|
|
|
1774
|
-
|
|
603
|
+
#### Step 2.6.9: Skip Conditions
|
|
1775
604
|
|
|
1776
|
-
|
|
605
|
+
**Skip this step entirely if:**
|
|
606
|
+
- Change is trivial (complexity = 1, risk = LOW, no special features)
|
|
607
|
+
- Output: `✅ Pre-Work Context: Skipped (trivial change)`
|
|
1777
608
|
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
title: string
|
|
1782
|
-
snippets: number
|
|
1783
|
-
score: number
|
|
1784
|
-
} | null {
|
|
1785
|
-
// Parse the Context7 response text to extract library info
|
|
1786
|
-
// Response format includes lines like:
|
|
1787
|
-
// - Title: SQLAlchemy
|
|
1788
|
-
// - Context7-compatible library ID: /sqlalchemy/sqlalchemy
|
|
1789
|
-
// - Code Snippets: 2830
|
|
1790
|
-
// - Benchmark Score: 84.4
|
|
1791
|
-
|
|
1792
|
-
const libraries = []
|
|
1793
|
-
const blocks = response.split('----------').filter(b => b.trim())
|
|
1794
|
-
|
|
1795
|
-
for (const block of blocks) {
|
|
1796
|
-
const titleMatch = block.match(/Title:\s*(.+)/i)
|
|
1797
|
-
const idMatch = block.match(/Context7-compatible library ID:\s*(\S+)/i)
|
|
1798
|
-
const snippetsMatch = block.match(/Code Snippets:\s*(\d+)/i)
|
|
1799
|
-
const scoreMatch = block.match(/Benchmark Score:\s*([\d.]+)/i)
|
|
1800
|
-
|
|
1801
|
-
if (titleMatch && idMatch) {
|
|
1802
|
-
libraries.push({
|
|
1803
|
-
title: titleMatch[1].trim(),
|
|
1804
|
-
id: idMatch[1].trim(),
|
|
1805
|
-
snippets: snippetsMatch ? parseInt(snippetsMatch[1]) : 0,
|
|
1806
|
-
score: scoreMatch ? parseFloat(scoreMatch[1]) : 50
|
|
1807
|
-
})
|
|
1808
|
-
}
|
|
1809
|
-
}
|
|
609
|
+
**Skip library lookup if:**
|
|
610
|
+
- No new libraries detected
|
|
611
|
+
- All libraries already have Context7 cache
|
|
1810
612
|
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
// Prefer exact title match, then highest score with good snippet count
|
|
1814
|
-
const searchLower = searchTerm.toLowerCase()
|
|
1815
|
-
|
|
1816
|
-
// First: exact match
|
|
1817
|
-
const exactMatch = libraries.find(l =>
|
|
1818
|
-
l.title.toLowerCase() === searchLower ||
|
|
1819
|
-
l.id.toLowerCase().includes(searchLower)
|
|
1820
|
-
)
|
|
1821
|
-
if (exactMatch) return exactMatch
|
|
1822
|
-
|
|
1823
|
-
// Second: partial match with good score
|
|
1824
|
-
const partialMatches = libraries.filter(l =>
|
|
1825
|
-
l.title.toLowerCase().includes(searchLower) ||
|
|
1826
|
-
searchLower.includes(l.title.toLowerCase())
|
|
1827
|
-
)
|
|
1828
|
-
if (partialMatches.length > 0) {
|
|
1829
|
-
return partialMatches.sort((a, b) => b.score - a.score)[0]
|
|
1830
|
-
}
|
|
613
|
+
---
|
|
1831
614
|
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
}
|
|
615
|
+
**⚠️ IMPORTANT:** This step requires YOU (Main Claude) to:
|
|
616
|
+
1. Actually read the spec files
|
|
617
|
+
2. Actually call Context7 MCP tools
|
|
618
|
+
3. Actually write the pre-work-context.md file
|
|
1837
619
|
|
|
1838
|
-
|
|
1839
|
-
return libraries[0]
|
|
1840
|
-
}
|
|
1841
|
-
```
|
|
620
|
+
Do NOT treat this as pseudocode. EXECUTE these instructions.
|
|
1842
621
|
|
|
1843
622
|
---
|
|
1844
623
|
|
|
1845
|
-
### Step 2.
|
|
624
|
+
### Step 2.7: Library Capability Validation (v2.2.0)
|
|
1846
625
|
|
|
1847
626
|
> **NEW:** Verify chosen libraries support ALL spec requirements before proceeding
|
|
1848
627
|
> **WHY:** Prevents spec drift - discovering during implementation that library doesn't support requirements
|
|
@@ -2079,351 +858,6 @@ const capabilityAnalysis = {
|
|
|
2079
858
|
}
|
|
2080
859
|
```
|
|
2081
860
|
|
|
2082
|
-
**Helper: generateBestPracticesFile()**
|
|
2083
|
-
|
|
2084
|
-
> **Updated v2.3.0:** Now includes Context7 library ID for reference and refresh capability.
|
|
2085
|
-
|
|
2086
|
-
```typescript
|
|
2087
|
-
function generateBestPracticesFile(
|
|
2088
|
-
tech: string,
|
|
2089
|
-
context7Docs: string,
|
|
2090
|
-
context7Id: string
|
|
2091
|
-
): string {
|
|
2092
|
-
return `# ${tech} Best Practices
|
|
2093
|
-
|
|
2094
|
-
> **Source:** Context7 MCP
|
|
2095
|
-
> **Library ID:** \`${context7Id}\`
|
|
2096
|
-
> **Generated:** ${new Date().toISOString().split('T')[0]}
|
|
2097
|
-
> **Refresh:** Query Context7 with the Library ID above to update this file
|
|
2098
|
-
|
|
2099
|
-
---
|
|
2100
|
-
|
|
2101
|
-
## Best Practices
|
|
2102
|
-
|
|
2103
|
-
${extractBestPractices(context7Docs)}
|
|
2104
|
-
|
|
2105
|
-
---
|
|
2106
|
-
|
|
2107
|
-
## Anti-Patterns to Avoid
|
|
2108
|
-
|
|
2109
|
-
${extractAntiPatterns(context7Docs)}
|
|
2110
|
-
|
|
2111
|
-
---
|
|
2112
|
-
|
|
2113
|
-
## Code Examples
|
|
2114
|
-
|
|
2115
|
-
${extractCodeExamples(context7Docs)}
|
|
2116
|
-
|
|
2117
|
-
---
|
|
2118
|
-
|
|
2119
|
-
## Quick Checklist
|
|
2120
|
-
|
|
2121
|
-
Before committing ${tech} code:
|
|
2122
|
-
${extractChecklist(context7Docs)}
|
|
2123
|
-
|
|
2124
|
-
---
|
|
2125
|
-
|
|
2126
|
-
**Agents read this file in STEP 0 before implementation.**
|
|
2127
|
-
`
|
|
2128
|
-
}
|
|
2129
|
-
|
|
2130
|
-
// Helper: Extract best practices from Context7 docs
|
|
2131
|
-
function extractBestPractices(docs: string): string {
|
|
2132
|
-
// Look for sections about best practices, recommendations, patterns
|
|
2133
|
-
const patterns = [
|
|
2134
|
-
/best\s*practices?[:\s]+([^#]+?)(?=##|$)/gi,
|
|
2135
|
-
/recommend(?:ed|ations)?[:\s]+([^#]+?)(?=##|$)/gi,
|
|
2136
|
-
/(?:do|should)[:\s]+([^#]+?)(?=##|$)/gi
|
|
2137
|
-
]
|
|
2138
|
-
|
|
2139
|
-
let extracted = ''
|
|
2140
|
-
for (const pattern of patterns) {
|
|
2141
|
-
const matches = docs.match(pattern)
|
|
2142
|
-
if (matches) {
|
|
2143
|
-
extracted += matches.join('\n\n')
|
|
2144
|
-
}
|
|
2145
|
-
}
|
|
2146
|
-
|
|
2147
|
-
return extracted || docs.slice(0, 2000) // Fallback to first 2000 chars
|
|
2148
|
-
}
|
|
2149
|
-
|
|
2150
|
-
// Helper: Extract anti-patterns from Context7 docs
|
|
2151
|
-
function extractAntiPatterns(docs: string): string {
|
|
2152
|
-
const patterns = [
|
|
2153
|
-
/anti-?patterns?[:\s]+([^#]+?)(?=##|$)/gi,
|
|
2154
|
-
/avoid[:\s]+([^#]+?)(?=##|$)/gi,
|
|
2155
|
-
/(?:don'?t|should\s*not)[:\s]+([^#]+?)(?=##|$)/gi,
|
|
2156
|
-
/common\s*mistakes?[:\s]+([^#]+?)(?=##|$)/gi
|
|
2157
|
-
]
|
|
2158
|
-
|
|
2159
|
-
let extracted = ''
|
|
2160
|
-
for (const pattern of patterns) {
|
|
2161
|
-
const matches = docs.match(pattern)
|
|
2162
|
-
if (matches) {
|
|
2163
|
-
extracted += matches.join('\n\n')
|
|
2164
|
-
}
|
|
2165
|
-
}
|
|
2166
|
-
|
|
2167
|
-
return extracted || 'Review Context7 documentation for anti-patterns specific to your use case.'
|
|
2168
|
-
}
|
|
2169
|
-
|
|
2170
|
-
// Helper: Extract code examples from Context7 docs
|
|
2171
|
-
function extractCodeExamples(docs: string): string {
|
|
2172
|
-
// Extract code blocks
|
|
2173
|
-
const codeBlocks = docs.match(/\`\`\`[\s\S]*?\`\`\`/g) || []
|
|
2174
|
-
return codeBlocks.slice(0, 5).join('\n\n') || 'See Context7 documentation for code examples.'
|
|
2175
|
-
}
|
|
2176
|
-
|
|
2177
|
-
// Helper: Generate checklist from docs
|
|
2178
|
-
function extractChecklist(docs: string): string {
|
|
2179
|
-
// Look for checklist items or generate from best practices
|
|
2180
|
-
const checklistPatterns = [
|
|
2181
|
-
/- \[[ x]\][^\n]+/gi,
|
|
2182
|
-
/\d+\.\s+[^\n]+/gi
|
|
2183
|
-
]
|
|
2184
|
-
|
|
2185
|
-
let items = []
|
|
2186
|
-
for (const pattern of checklistPatterns) {
|
|
2187
|
-
const matches = docs.match(pattern)
|
|
2188
|
-
if (matches) {
|
|
2189
|
-
items = items.concat(matches.slice(0, 10))
|
|
2190
|
-
}
|
|
2191
|
-
}
|
|
2192
|
-
|
|
2193
|
-
if (items.length > 0) {
|
|
2194
|
-
return items.map(item => `- [ ] ${item.replace(/^[\d.-\[\]x\s]+/i, '')}`).join('\n')
|
|
2195
|
-
}
|
|
2196
|
-
|
|
2197
|
-
// Fallback: generic checklist
|
|
2198
|
-
return `- [ ] Follow official documentation patterns
|
|
2199
|
-
- [ ] Handle errors appropriately
|
|
2200
|
-
- [ ] Add proper typing/validation
|
|
2201
|
-
- [ ] Write tests for new code
|
|
2202
|
-
- [ ] Review for security concerns`
|
|
2203
|
-
}
|
|
2204
|
-
```
|
|
2205
|
-
|
|
2206
|
-
---
|
|
2207
|
-
|
|
2208
|
-
### Helper: detectIntegrationRisks() - v2.5.0
|
|
2209
|
-
|
|
2210
|
-
> **Smart Risk Detection:** Scans Context7 docs for integration patterns that require attention.
|
|
2211
|
-
> **WHY:** Proactively catch integration requirements BEFORE implementation, not at runtime.
|
|
2212
|
-
|
|
2213
|
-
```typescript
|
|
2214
|
-
function detectIntegrationRisks(
|
|
2215
|
-
docs: string,
|
|
2216
|
-
currentLib: string,
|
|
2217
|
-
allLibs: Array<{ name: string; title: string }>
|
|
2218
|
-
): Array<{ library: string; risk: string; pattern: string; recommendation: string }> {
|
|
2219
|
-
const risks = []
|
|
2220
|
-
const docsLower = docs.toLowerCase()
|
|
2221
|
-
|
|
2222
|
-
// Integration risk patterns to detect
|
|
2223
|
-
const riskPatterns = [
|
|
2224
|
-
// Adapter patterns (ORM + Auth)
|
|
2225
|
-
{
|
|
2226
|
-
keywords: ['adapter', 'drizzleadapter', 'prismaadapter'],
|
|
2227
|
-
risk: 'Database adapter configuration required',
|
|
2228
|
-
pattern: 'adapter',
|
|
2229
|
-
recommendation: 'Verify adapter schema matches expected column names'
|
|
2230
|
-
},
|
|
2231
|
-
// Column naming patterns
|
|
2232
|
-
{
|
|
2233
|
-
keywords: ['column', 'columnname', 'snake_case', 'camelcase', 'mapping'],
|
|
2234
|
-
risk: 'Column naming convention mismatch possible',
|
|
2235
|
-
pattern: 'schema',
|
|
2236
|
-
recommendation: 'Check column naming between ORM schema and library expectations'
|
|
2237
|
-
},
|
|
2238
|
-
// Schema patterns
|
|
2239
|
-
{
|
|
2240
|
-
keywords: ['userstable', 'accountstable', 'sessionstable', 'schema'],
|
|
2241
|
-
risk: 'Custom table schema required',
|
|
2242
|
-
pattern: 'schema',
|
|
2243
|
-
recommendation: 'Ensure table schemas match library documentation exactly'
|
|
2244
|
-
},
|
|
2245
|
-
// Sync/Migration patterns
|
|
2246
|
-
{
|
|
2247
|
-
keywords: ['sync', 'migrate', 'migration', 'syncurl', 'embedded replica'],
|
|
2248
|
-
risk: 'Data synchronization setup required',
|
|
2249
|
-
pattern: 'sync',
|
|
2250
|
-
recommendation: 'Configure sync intervals and handle offline scenarios'
|
|
2251
|
-
},
|
|
2252
|
-
// Webhook patterns
|
|
2253
|
-
{
|
|
2254
|
-
keywords: ['webhook', 'webhookendpoint', 'webhooksecret'],
|
|
2255
|
-
risk: 'Webhook endpoint configuration required',
|
|
2256
|
-
pattern: 'webhook',
|
|
2257
|
-
recommendation: 'Set up webhook endpoints and verify signatures'
|
|
2258
|
-
},
|
|
2259
|
-
// API Key patterns
|
|
2260
|
-
{
|
|
2261
|
-
keywords: ['apikey', 'secretkey', 'authtoken', 'bearer'],
|
|
2262
|
-
risk: 'API credentials setup required',
|
|
2263
|
-
pattern: 'credentials',
|
|
2264
|
-
recommendation: 'Store credentials securely in environment variables'
|
|
2265
|
-
},
|
|
2266
|
-
// Lifecycle patterns
|
|
2267
|
-
{
|
|
2268
|
-
keywords: ['beforeall', 'afterall', 'beforeeach', 'aftereach', 'setup', 'teardown'],
|
|
2269
|
-
risk: 'Test lifecycle hooks required',
|
|
2270
|
-
pattern: 'lifecycle',
|
|
2271
|
-
recommendation: 'Implement proper setup/teardown in test configuration'
|
|
2272
|
-
}
|
|
2273
|
-
]
|
|
2274
|
-
|
|
2275
|
-
for (const rp of riskPatterns) {
|
|
2276
|
-
const found = rp.keywords.some(kw => docsLower.includes(kw.toLowerCase()))
|
|
2277
|
-
if (found) {
|
|
2278
|
-
// Check if this risk involves other detected libraries
|
|
2279
|
-
const involvedLibs = allLibs
|
|
2280
|
-
.filter(l => l.name !== currentLib)
|
|
2281
|
-
.filter(l => docsLower.includes(l.name.toLowerCase()))
|
|
2282
|
-
.map(l => l.name)
|
|
2283
|
-
|
|
2284
|
-
risks.push({
|
|
2285
|
-
library: currentLib,
|
|
2286
|
-
risk: rp.risk,
|
|
2287
|
-
pattern: rp.pattern,
|
|
2288
|
-
recommendation: rp.recommendation,
|
|
2289
|
-
involvedLibraries: involvedLibs
|
|
2290
|
-
})
|
|
2291
|
-
}
|
|
2292
|
-
}
|
|
2293
|
-
|
|
2294
|
-
return risks
|
|
2295
|
-
}
|
|
2296
|
-
```
|
|
2297
|
-
|
|
2298
|
-
---
|
|
2299
|
-
|
|
2300
|
-
### Helper: generateIntegrationRiskSummary() - v2.5.0
|
|
2301
|
-
|
|
2302
|
-
> **Risk Summary Output:** Creates INTEGRATION_RISKS.md with all detected cross-library concerns.
|
|
2303
|
-
> **WHY:** Agents can review this BEFORE implementation to avoid common integration mistakes.
|
|
2304
|
-
|
|
2305
|
-
```typescript
|
|
2306
|
-
function generateIntegrationRiskSummary(
|
|
2307
|
-
risks: Array<{
|
|
2308
|
-
library: string
|
|
2309
|
-
risk: string
|
|
2310
|
-
pattern: string
|
|
2311
|
-
recommendation: string
|
|
2312
|
-
involvedLibraries?: string[]
|
|
2313
|
-
}>,
|
|
2314
|
-
bpDir: string,
|
|
2315
|
-
allLibs: Array<{ name: string; title: string }>
|
|
2316
|
-
): void {
|
|
2317
|
-
// Group risks by pattern type
|
|
2318
|
-
const byPattern = {}
|
|
2319
|
-
for (const r of risks) {
|
|
2320
|
-
if (!byPattern[r.pattern]) byPattern[r.pattern] = []
|
|
2321
|
-
byPattern[r.pattern].push(r)
|
|
2322
|
-
}
|
|
2323
|
-
|
|
2324
|
-
const content = `# Integration Risk Summary
|
|
2325
|
-
|
|
2326
|
-
> **Generated:** ${new Date().toISOString().split('T')[0]}
|
|
2327
|
-
> **Template Version:** 2.5.0 - Smart Topic Query
|
|
2328
|
-
> **Detected Libraries:** ${allLibs.map(l => l.name).join(', ')}
|
|
2329
|
-
|
|
2330
|
-
---
|
|
2331
|
-
|
|
2332
|
-
## ⚠️ Review Before Implementation
|
|
2333
|
-
|
|
2334
|
-
The following integration patterns were detected from library documentation.
|
|
2335
|
-
**Agents should review these items in STEP 0 before writing code.**
|
|
2336
|
-
|
|
2337
|
-
---
|
|
2338
|
-
|
|
2339
|
-
${Object.entries(byPattern).map(([pattern, patternRisks]) => `
|
|
2340
|
-
### ${pattern.toUpperCase()} Patterns
|
|
2341
|
-
|
|
2342
|
-
| Library | Risk | Recommendation |
|
|
2343
|
-
|---------|------|----------------|
|
|
2344
|
-
${patternRisks.map(r => `| ${r.library} | ${r.risk} | ${r.recommendation} |`).join('\n')}
|
|
2345
|
-
${patternRisks.some(r => r.involvedLibraries?.length > 0) ? `
|
|
2346
|
-
**Cross-library concerns:**
|
|
2347
|
-
${patternRisks.filter(r => r.involvedLibraries?.length > 0).map(r => `- ${r.library} ↔ ${r.involvedLibraries.join(', ')}: ${r.risk}`).join('\n')}
|
|
2348
|
-
` : ''}
|
|
2349
|
-
`).join('\n')}
|
|
2350
|
-
|
|
2351
|
-
---
|
|
2352
|
-
|
|
2353
|
-
## Quick Checklist
|
|
2354
|
-
|
|
2355
|
-
Before implementing integrations:
|
|
2356
|
-
|
|
2357
|
-
${[...new Set(risks.map(r => r.recommendation))].map(rec => `- [ ] ${rec}`).join('\n')}
|
|
2358
|
-
|
|
2359
|
-
---
|
|
2360
|
-
|
|
2361
|
-
**This file is auto-generated by /csetup v2.5.0**
|
|
2362
|
-
**Agents read this in STEP 0 alongside best-practices files**
|
|
2363
|
-
`
|
|
2364
|
-
|
|
2365
|
-
Write(`${bpDir}INTEGRATION_RISKS.md`, content)
|
|
2366
|
-
}
|
|
2367
|
-
```
|
|
2368
|
-
|
|
2369
|
-
---
|
|
2370
|
-
|
|
2371
|
-
### Helper: generateBestPracticesIndex() - v2.5.0
|
|
2372
|
-
|
|
2373
|
-
> **Index File:** Creates index.md registry of all best practices files.
|
|
2374
|
-
> **v2.5.0:** Now includes INTEGRATION_RISKS.md if present.
|
|
2375
|
-
|
|
2376
|
-
```typescript
|
|
2377
|
-
function generateBestPracticesIndex(
|
|
2378
|
-
resolvedLibraries: Array<{ name: string; title: string; context7Id: string }>,
|
|
2379
|
-
changeId: string
|
|
2380
|
-
): void {
|
|
2381
|
-
const bpDir = '.claude/contexts/domain/project/best-practices/'
|
|
2382
|
-
const hasIntegrationRisks = fileExists(`${bpDir}INTEGRATION_RISKS.md`)
|
|
2383
|
-
|
|
2384
|
-
const content = `# Best Practices Index
|
|
2385
|
-
|
|
2386
|
-
> **Generated:** ${new Date().toISOString().split('T')[0]}
|
|
2387
|
-
> **Template Version:** 2.5.0 - Smart Topic Query
|
|
2388
|
-
> **Change:** ${changeId}
|
|
2389
|
-
|
|
2390
|
-
---
|
|
2391
|
-
|
|
2392
|
-
## 📚 Library Best Practices
|
|
2393
|
-
|
|
2394
|
-
| Library | File | Context7 ID |
|
|
2395
|
-
|---------|------|-------------|
|
|
2396
|
-
${resolvedLibraries.map(lib => {
|
|
2397
|
-
const safeName = lib.name.toLowerCase().replace(/[^a-z0-9]/g, '-')
|
|
2398
|
-
return `| ${lib.title} | [${safeName}.md](./${safeName}.md) | \`${lib.context7Id}\` |`
|
|
2399
|
-
}).join('\n')}
|
|
2400
|
-
|
|
2401
|
-
---
|
|
2402
|
-
|
|
2403
|
-
${hasIntegrationRisks ? `## ⚠️ Integration Risks
|
|
2404
|
-
|
|
2405
|
-
Cross-library integration concerns detected. **Review before implementation.**
|
|
2406
|
-
|
|
2407
|
-
→ [INTEGRATION_RISKS.md](./INTEGRATION_RISKS.md)
|
|
2408
|
-
|
|
2409
|
-
---
|
|
2410
|
-
|
|
2411
|
-
` : ''}## Usage
|
|
2412
|
-
|
|
2413
|
-
Agents read these files in **STEP 0** before implementation:
|
|
2414
|
-
|
|
2415
|
-
1. Read \`index.md\` (this file) for overview
|
|
2416
|
-
2. Read relevant \`{library}.md\` files for specific best practices
|
|
2417
|
-
${hasIntegrationRisks ? '3. Read `INTEGRATION_RISKS.md` for cross-library concerns' : ''}
|
|
2418
|
-
|
|
2419
|
-
---
|
|
2420
|
-
|
|
2421
|
-
**Auto-generated by /csetup v2.5.0**
|
|
2422
|
-
`
|
|
2423
|
-
|
|
2424
|
-
Write(`${bpDir}index.md`, content)
|
|
2425
|
-
}
|
|
2426
|
-
```
|
|
2427
861
|
|
|
2428
862
|
---
|
|
2429
863
|
|
|
@@ -2772,15 +1206,27 @@ function generatePhaseSection(phase, phaseTasks) {
|
|
|
2772
1206
|
const dominantAgent = getMostCommonAgent(phaseTasks)
|
|
2773
1207
|
const hasIncremental = phaseTasks.some(t => t.milestones)
|
|
2774
1208
|
const maxRisk = getMaxRisk(phaseTasks)
|
|
2775
|
-
|
|
1209
|
+
|
|
1210
|
+
// v3.1.0: Use TDD classification from task-analyzer.md (Step 2.6)
|
|
1211
|
+
// Each task now has task.tdd = { tdd_required, workflow, reason, confidence }
|
|
1212
|
+
const tddTasks = phaseTasks.filter(t => t.tdd?.tdd_required === true)
|
|
1213
|
+
const needsTDD = tddTasks.length > 0
|
|
1214
|
+
const tddReasons = [...new Set(tddTasks.map(t => t.tdd?.reason).filter(Boolean))]
|
|
2776
1215
|
|
|
2777
1216
|
let section = `## Phase ${phase.number}: ${phase.name}
|
|
2778
1217
|
|
|
2779
1218
|
**Agent:** ${dominantAgent}
|
|
2780
1219
|
**Strategy:** ${hasIncremental ? '🔄 INCREMENTAL' : 'Standard'}
|
|
2781
1220
|
**Risk:** ${maxRisk}
|
|
2782
|
-
${needsTDD ?
|
|
2783
|
-
|
|
1221
|
+
${needsTDD ? `**TDD Required:** ✅ YES
|
|
1222
|
+
**TDD Reason:** ${tddReasons.slice(0, 2).join('; ')}
|
|
1223
|
+
**TDD Workflow:** red-green-refactor
|
|
1224
|
+
|
|
1225
|
+
⚠️ **TDD WORKFLOW REQUIRED:**
|
|
1226
|
+
1. 🔴 RED: Write tests FIRST (they should fail)
|
|
1227
|
+
2. ✅ GREEN: Write minimal implementation to pass tests
|
|
1228
|
+
3. 🔧 REFACTOR: Improve code quality while keeping tests green
|
|
1229
|
+
` : ''}
|
|
2784
1230
|
`
|
|
2785
1231
|
|
|
2786
1232
|
// Group tasks: incremental tasks get milestone sections, others get simple list
|
|
@@ -3167,20 +1613,10 @@ function detectChangeType(tasks: AnalyzedTask[]): string {
|
|
|
3167
1613
|
}
|
|
3168
1614
|
```
|
|
3169
1615
|
|
|
3170
|
-
### detectAdditionalTech() -
|
|
3171
|
-
|
|
3172
|
-
> **Note:** This function is deprecated in v2.3.0. Use `extractPotentialLibraryNames()` + Context7 resolution instead.
|
|
3173
|
-
> The dynamic approach automatically detects any library without hardcoded patterns.
|
|
1616
|
+
### detectAdditionalTech() - REMOVED (v3.1.0)
|
|
3174
1617
|
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
// Use extractPotentialLibraryNames() for new implementations
|
|
3178
|
-
function detectAdditionalTech(proposal: string, tasks: string): string[] {
|
|
3179
|
-
// Now delegates to the dynamic detection system
|
|
3180
|
-
const combined = proposal + ' ' + tasks
|
|
3181
|
-
return extractPotentialLibraryNames(combined)
|
|
3182
|
-
}
|
|
3183
|
-
```
|
|
1618
|
+
> **Note:** This function was removed in v3.1.0. Use Step 2.7's direct Context7 instructions instead.
|
|
1619
|
+
> Main Claude now directly calls Context7 MCP tools to detect and resolve libraries.
|
|
3184
1620
|
|
|
3185
1621
|
---
|
|
3186
1622
|
|