@champpaba/claude-agent-kit 2.3.0 → 2.5.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/CLAUDE.md +255 -31
- package/.claude/commands/csetup.md +903 -184
- package/.claude/commands/pageplan.md +30 -244
- package/README.md +49 -21
- package/package.json +1 -1
|
@@ -249,228 +249,686 @@ Continue anyway? (yes/no)
|
|
|
249
249
|
|
|
250
250
|
---
|
|
251
251
|
|
|
252
|
-
### Step 2.6:
|
|
252
|
+
### Step 2.6: Adaptive Depth Research (v2.4.0)
|
|
253
253
|
|
|
254
|
-
> **NEW:**
|
|
255
|
-
> **
|
|
254
|
+
> **NEW:** Dynamic research layers based on change complexity - replaces hardcoded feature detection
|
|
255
|
+
> **WHY:** Different changes need different research depth. A typo fix needs 0 layers, a healthcare portal needs 10+.
|
|
256
|
+
> **Output:** `openspec/changes/{changeId}/research-checklist.md`
|
|
256
257
|
|
|
257
|
-
|
|
258
|
+
**Key Principles:**
|
|
259
|
+
- Layer 1 is ALWAYS "Best Practice" (คนอื่นทำกันยังไง? / How do others do it?)
|
|
260
|
+
- Layer 2+ determined dynamically based on change context
|
|
261
|
+
- No fixed minimum or maximum - truly adaptive (0 to 10+ layers)
|
|
262
|
+
- Visual design (from /designsetup) is STATIC - this only handles Strategy (WHAT/WHERE)
|
|
263
|
+
- Warns if industry practice conflicts with user's design choices
|
|
258
264
|
|
|
259
265
|
```typescript
|
|
260
|
-
output(`\n
|
|
261
|
-
|
|
262
|
-
// 1.
|
|
263
|
-
const
|
|
264
|
-
|
|
265
|
-
const
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
266
|
+
output(`\n🔬 Adaptive Depth Research Analysis...`)
|
|
267
|
+
|
|
268
|
+
// 1. Gather change context from all spec files
|
|
269
|
+
const proposalPath = `openspec/changes/${changeId}/proposal.md`
|
|
270
|
+
const tasksPath = `openspec/changes/${changeId}/tasks.md`
|
|
271
|
+
const designPath = `openspec/changes/${changeId}/design.md`
|
|
272
|
+
|
|
273
|
+
const proposal = fileExists(proposalPath) ? Read(proposalPath) : ''
|
|
274
|
+
const tasks = fileExists(tasksPath) ? Read(tasksPath) : ''
|
|
275
|
+
const design = fileExists(designPath) ? Read(designPath) : ''
|
|
276
|
+
const combined = (proposal + '\n' + tasks + '\n' + design).toLowerCase()
|
|
277
|
+
|
|
278
|
+
// 2. Analyze change characteristics using semantic understanding
|
|
279
|
+
const changeAnalysis = analyzeChangeCharacteristics(combined, proposal, tasks)
|
|
280
|
+
|
|
281
|
+
output(`\n📊 Change Analysis:`)
|
|
282
|
+
output(` Type: ${changeAnalysis.primaryType}`)
|
|
283
|
+
output(` Complexity: ${changeAnalysis.complexity}/10`)
|
|
284
|
+
output(` Risk Level: ${changeAnalysis.riskLevel}`)
|
|
285
|
+
output(` Target Audience: ${changeAnalysis.audience || 'Internal'}`)
|
|
286
|
+
|
|
287
|
+
// 3. Determine required research layers based on change characteristics
|
|
288
|
+
const requiredLayers = determineResearchLayers(changeAnalysis)
|
|
289
|
+
|
|
290
|
+
output(`\n📚 Research Layers Required: ${requiredLayers.length}`)
|
|
291
|
+
|
|
292
|
+
if (requiredLayers.length === 0) {
|
|
293
|
+
output(` ✅ No research needed - trivial change`)
|
|
294
|
+
output(` (Typo fix, debug log, simple badge, etc.)`)
|
|
295
|
+
} else {
|
|
296
|
+
requiredLayers.forEach((layer, idx) => {
|
|
297
|
+
output(` L${idx + 1}: ${layer.name}`)
|
|
298
|
+
output(` Focus: ${layer.focus}`)
|
|
299
|
+
output(` Questions: ${layer.questions.slice(0, 2).join(', ')}...`)
|
|
300
|
+
})
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// 4. Execute research for each layer using Context7 + semantic analysis
|
|
304
|
+
const researchResults = []
|
|
305
|
+
|
|
306
|
+
for (const layer of requiredLayers) {
|
|
307
|
+
output(`\n🔍 Researching L${layer.order}: ${layer.name}...`)
|
|
308
|
+
|
|
309
|
+
const layerResult = await executeLayerResearch(layer, changeAnalysis)
|
|
310
|
+
researchResults.push(layerResult)
|
|
311
|
+
|
|
312
|
+
output(` ✅ Found ${layerResult.findings.length} key findings`)
|
|
313
|
+
if (layerResult.warnings.length > 0) {
|
|
314
|
+
layerResult.warnings.forEach(w => output(` ⚠️ ${w}`))
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// 5. Check for conflicts with design system (if exists)
|
|
319
|
+
const tokensPath = 'design-system/tokens.json'
|
|
320
|
+
if (fileExists(tokensPath) && researchResults.length > 0) {
|
|
321
|
+
const tokens = JSON.parse(Read(tokensPath))
|
|
322
|
+
const conflicts = checkDesignConflicts(tokens, researchResults, changeAnalysis)
|
|
323
|
+
|
|
324
|
+
if (conflicts.length > 0) {
|
|
325
|
+
output(`\n⚠️ Design vs Industry Fit Conflicts:`)
|
|
326
|
+
conflicts.forEach(c => {
|
|
327
|
+
output(` - ${c.aspect}: Your design uses "${c.current}", but ${c.industry}`)
|
|
328
|
+
output(` Recommendation: ${c.recommendation}`)
|
|
329
|
+
})
|
|
330
|
+
output(`\n Note: User design choices take precedence. These are informational warnings.`)
|
|
304
331
|
}
|
|
305
332
|
}
|
|
306
333
|
|
|
307
|
-
//
|
|
308
|
-
const
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
334
|
+
// 6. Generate research-checklist.md
|
|
335
|
+
const checklistPath = `openspec/changes/${changeId}/research-checklist.md`
|
|
336
|
+
const checklistContent = generateResearchChecklist(changeAnalysis, requiredLayers, researchResults)
|
|
337
|
+
|
|
338
|
+
Write(checklistPath, checklistContent)
|
|
339
|
+
output(`\n✅ Generated: ${checklistPath}`)
|
|
340
|
+
|
|
341
|
+
// Store for use by agents
|
|
342
|
+
const adaptiveResearch = {
|
|
343
|
+
layerCount: requiredLayers.length,
|
|
344
|
+
layers: requiredLayers.map(l => l.name),
|
|
345
|
+
complexity: changeAnalysis.complexity,
|
|
346
|
+
checklistPath: checklistPath
|
|
347
|
+
}
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
#### Helper Functions
|
|
351
|
+
|
|
352
|
+
```typescript
|
|
353
|
+
// Analyze change characteristics using semantic understanding
|
|
354
|
+
function analyzeChangeCharacteristics(combined, proposal, tasks) {
|
|
355
|
+
const analysis = {
|
|
356
|
+
primaryType: 'general',
|
|
357
|
+
complexity: 1,
|
|
358
|
+
riskLevel: 'LOW',
|
|
359
|
+
audience: 'internal',
|
|
360
|
+
domains: [],
|
|
361
|
+
features: [],
|
|
362
|
+
hasUI: false,
|
|
363
|
+
hasAPI: false,
|
|
364
|
+
hasDatabase: false,
|
|
365
|
+
hasPayment: false,
|
|
366
|
+
hasAuth: false,
|
|
367
|
+
hasCompliance: false,
|
|
368
|
+
hasSensitiveData: false,
|
|
369
|
+
isExternalFacing: false,
|
|
370
|
+
industryContext: null
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// Detect primary type
|
|
374
|
+
if (/marketing|landing|hero|cta|conversion|sales/i.test(combined)) {
|
|
375
|
+
analysis.primaryType = 'marketing'
|
|
376
|
+
analysis.isExternalFacing = true
|
|
377
|
+
} else if (/dashboard|admin|management|analytics/i.test(combined)) {
|
|
378
|
+
analysis.primaryType = 'dashboard'
|
|
379
|
+
} else if (/api|endpoint|rest|graphql/i.test(combined)) {
|
|
380
|
+
analysis.primaryType = 'api'
|
|
381
|
+
} else if (/auth|login|register|password/i.test(combined)) {
|
|
382
|
+
analysis.primaryType = 'auth'
|
|
383
|
+
analysis.hasAuth = true
|
|
384
|
+
} else if (/database|schema|migration|model/i.test(combined)) {
|
|
385
|
+
analysis.primaryType = 'database'
|
|
386
|
+
analysis.hasDatabase = true
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// Detect features and domains
|
|
390
|
+
if (/payment|stripe|billing|checkout|subscription/i.test(combined)) {
|
|
391
|
+
analysis.hasPayment = true
|
|
392
|
+
analysis.features.push('payment')
|
|
393
|
+
analysis.riskLevel = 'HIGH'
|
|
394
|
+
}
|
|
395
|
+
if (/health|medical|patient|hipaa|phi/i.test(combined)) {
|
|
396
|
+
analysis.hasCompliance = true
|
|
397
|
+
analysis.hasSensitiveData = true
|
|
398
|
+
analysis.domains.push('healthcare')
|
|
399
|
+
analysis.industryContext = 'healthcare'
|
|
400
|
+
analysis.riskLevel = 'HIGH'
|
|
401
|
+
}
|
|
402
|
+
if (/fintech|banking|finance|pci|financial/i.test(combined)) {
|
|
403
|
+
analysis.hasCompliance = true
|
|
404
|
+
analysis.domains.push('fintech')
|
|
405
|
+
analysis.industryContext = 'fintech'
|
|
406
|
+
analysis.riskLevel = 'HIGH'
|
|
407
|
+
}
|
|
408
|
+
if (/saas|multi-tenant|tenant/i.test(combined)) {
|
|
409
|
+
analysis.domains.push('saas')
|
|
410
|
+
analysis.features.push('multi-tenancy')
|
|
312
411
|
}
|
|
412
|
+
if (/ecommerce|e-commerce|cart|product|shop/i.test(combined)) {
|
|
413
|
+
analysis.domains.push('ecommerce')
|
|
414
|
+
analysis.isExternalFacing = true
|
|
415
|
+
}
|
|
416
|
+
if (/realtime|real-time|websocket|collaboration/i.test(combined)) {
|
|
417
|
+
analysis.features.push('realtime')
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// Detect UI/API/Database
|
|
421
|
+
analysis.hasUI = /ui|page|component|form|button|modal/i.test(combined)
|
|
422
|
+
analysis.hasAPI = /api|endpoint|route|controller/i.test(combined)
|
|
423
|
+
analysis.hasDatabase = analysis.hasDatabase || /table|column|relation|index/i.test(combined)
|
|
424
|
+
|
|
425
|
+
// Detect audience
|
|
426
|
+
if (/b2c|consumer|user|customer/i.test(combined)) {
|
|
427
|
+
analysis.audience = 'consumer'
|
|
428
|
+
analysis.isExternalFacing = true
|
|
429
|
+
} else if (/b2b|enterprise|business/i.test(combined)) {
|
|
430
|
+
analysis.audience = 'business'
|
|
431
|
+
analysis.isExternalFacing = true
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// Calculate complexity (1-10)
|
|
435
|
+
let complexity = 1
|
|
436
|
+
if (analysis.features.length > 0) complexity += analysis.features.length
|
|
437
|
+
if (analysis.domains.length > 0) complexity += analysis.domains.length
|
|
438
|
+
if (analysis.hasCompliance) complexity += 2
|
|
439
|
+
if (analysis.hasPayment) complexity += 2
|
|
440
|
+
if (analysis.hasAuth) complexity += 1
|
|
441
|
+
if (analysis.isExternalFacing) complexity += 1
|
|
442
|
+
if (/integration|external api|third-party/i.test(combined)) complexity += 2
|
|
443
|
+
|
|
444
|
+
analysis.complexity = Math.min(complexity, 10)
|
|
445
|
+
|
|
446
|
+
// Adjust risk level
|
|
447
|
+
if (analysis.complexity >= 7 || analysis.hasCompliance || analysis.hasPayment) {
|
|
448
|
+
analysis.riskLevel = 'HIGH'
|
|
449
|
+
} else if (analysis.complexity >= 4 || analysis.hasAuth) {
|
|
450
|
+
analysis.riskLevel = 'MEDIUM'
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
return analysis
|
|
313
454
|
}
|
|
314
455
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
456
|
+
// Determine research layers dynamically based on change characteristics
|
|
457
|
+
function determineResearchLayers(analysis) {
|
|
458
|
+
const layers = []
|
|
459
|
+
let order = 1
|
|
460
|
+
|
|
461
|
+
// Check for trivial changes (0 layers)
|
|
462
|
+
if (analysis.complexity <= 1 &&
|
|
463
|
+
!analysis.hasUI && !analysis.hasAPI && !analysis.hasDatabase &&
|
|
464
|
+
analysis.riskLevel === 'LOW') {
|
|
465
|
+
return [] // No research needed
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
// L1: Best Practice (ALWAYS for non-trivial changes)
|
|
469
|
+
layers.push({
|
|
470
|
+
order: order++,
|
|
471
|
+
name: 'Best Practice / Industry Standard',
|
|
472
|
+
focus: `How do others implement ${analysis.primaryType}?`,
|
|
473
|
+
questions: [
|
|
474
|
+
`What is the industry standard for ${analysis.primaryType}?`,
|
|
475
|
+
'What are common patterns and anti-patterns?',
|
|
476
|
+
'What are the key success factors?',
|
|
477
|
+
'What are common failure modes?'
|
|
478
|
+
],
|
|
479
|
+
searchTopics: [`${analysis.primaryType} best practices`, `${analysis.primaryType} patterns`]
|
|
319
480
|
})
|
|
320
481
|
|
|
321
|
-
//
|
|
322
|
-
|
|
482
|
+
// L2+: Dynamic layers based on context
|
|
483
|
+
|
|
484
|
+
// Security layer (for auth, payment, sensitive data)
|
|
485
|
+
if (analysis.hasAuth || analysis.hasPayment || analysis.hasSensitiveData) {
|
|
486
|
+
layers.push({
|
|
487
|
+
order: order++,
|
|
488
|
+
name: 'Security Requirements',
|
|
489
|
+
focus: 'What security measures are required?',
|
|
490
|
+
questions: [
|
|
491
|
+
'What authentication/authorization is needed?',
|
|
492
|
+
'What data protection is required?',
|
|
493
|
+
'What are common security vulnerabilities?',
|
|
494
|
+
'What compliance requirements apply?'
|
|
495
|
+
],
|
|
496
|
+
searchTopics: ['security best practices', `${analysis.primaryType} security`]
|
|
497
|
+
})
|
|
498
|
+
}
|
|
323
499
|
|
|
324
|
-
|
|
325
|
-
|
|
500
|
+
// Compliance layer (for regulated industries)
|
|
501
|
+
if (analysis.hasCompliance || analysis.industryContext) {
|
|
502
|
+
layers.push({
|
|
503
|
+
order: order++,
|
|
504
|
+
name: `${analysis.industryContext || 'Industry'} Compliance`,
|
|
505
|
+
focus: `What ${analysis.industryContext || 'industry'} regulations apply?`,
|
|
506
|
+
questions: [
|
|
507
|
+
'What regulatory requirements must be met?',
|
|
508
|
+
'What audit trails are needed?',
|
|
509
|
+
'What data handling rules apply?',
|
|
510
|
+
'What documentation is required?'
|
|
511
|
+
],
|
|
512
|
+
searchTopics: [`${analysis.industryContext} compliance`, `${analysis.industryContext} regulations`]
|
|
513
|
+
})
|
|
514
|
+
}
|
|
326
515
|
|
|
327
|
-
|
|
328
|
-
|
|
516
|
+
// UX layer (for external-facing UI)
|
|
517
|
+
if (analysis.isExternalFacing && analysis.hasUI) {
|
|
518
|
+
layers.push({
|
|
519
|
+
order: order++,
|
|
520
|
+
name: 'User Experience Patterns',
|
|
521
|
+
focus: 'What UX patterns work for this audience?',
|
|
522
|
+
questions: [
|
|
523
|
+
'What user journey is expected?',
|
|
524
|
+
'What conversion patterns work?',
|
|
525
|
+
'What accessibility requirements apply?',
|
|
526
|
+
'What are user expectations?'
|
|
527
|
+
],
|
|
528
|
+
searchTopics: [`${analysis.primaryType} UX`, `${analysis.audience} UX patterns`]
|
|
529
|
+
})
|
|
530
|
+
}
|
|
329
531
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
532
|
+
// Psychology layer (for marketing/sales)
|
|
533
|
+
if (analysis.primaryType === 'marketing' || /conversion|sales|cta/i.test(analysis.primaryType)) {
|
|
534
|
+
layers.push({
|
|
535
|
+
order: order++,
|
|
536
|
+
name: 'Conversion Psychology',
|
|
537
|
+
focus: 'What psychological triggers work?',
|
|
538
|
+
questions: [
|
|
539
|
+
'What is the buyer awareness level?',
|
|
540
|
+
'What pain points to address?',
|
|
541
|
+
'What objections to overcome?',
|
|
542
|
+
'What social proof is needed?'
|
|
543
|
+
],
|
|
544
|
+
searchTopics: ['conversion psychology', 'landing page psychology']
|
|
545
|
+
})
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
// Content Strategy layer (for content-heavy pages)
|
|
549
|
+
if (analysis.primaryType === 'marketing' || /content|blog|documentation/i.test(analysis.primaryType)) {
|
|
550
|
+
layers.push({
|
|
551
|
+
order: order++,
|
|
552
|
+
name: 'Content Strategy',
|
|
553
|
+
focus: 'What content structure works?',
|
|
554
|
+
questions: [
|
|
555
|
+
'What content hierarchy is effective?',
|
|
556
|
+
'What tone and voice to use?',
|
|
557
|
+
'What call-to-actions work?',
|
|
558
|
+
'What content gaps exist?'
|
|
559
|
+
],
|
|
560
|
+
searchTopics: ['content strategy', 'copywriting best practices']
|
|
561
|
+
})
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
// Data Architecture layer (for database/data-intensive)
|
|
565
|
+
if (analysis.hasDatabase || /data|analytics|reporting/i.test(analysis.primaryType)) {
|
|
566
|
+
layers.push({
|
|
567
|
+
order: order++,
|
|
568
|
+
name: 'Data Architecture',
|
|
569
|
+
focus: 'What data patterns are appropriate?',
|
|
570
|
+
questions: [
|
|
571
|
+
'What normalization level is appropriate?',
|
|
572
|
+
'What indexing strategy is needed?',
|
|
573
|
+
'What scaling considerations apply?',
|
|
574
|
+
'What data integrity rules?'
|
|
575
|
+
],
|
|
576
|
+
searchTopics: ['database design patterns', 'data architecture']
|
|
577
|
+
})
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
// API Design layer (for API-focused changes)
|
|
581
|
+
if (analysis.hasAPI || analysis.primaryType === 'api') {
|
|
582
|
+
layers.push({
|
|
583
|
+
order: order++,
|
|
584
|
+
name: 'API Design',
|
|
585
|
+
focus: 'What API patterns are appropriate?',
|
|
586
|
+
questions: [
|
|
587
|
+
'What API style is appropriate (REST/GraphQL)?',
|
|
588
|
+
'What versioning strategy?',
|
|
589
|
+
'What error handling patterns?',
|
|
590
|
+
'What rate limiting/throttling?'
|
|
591
|
+
],
|
|
592
|
+
searchTopics: ['API design best practices', 'REST API patterns']
|
|
593
|
+
})
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
// Multi-tenancy layer (for SaaS)
|
|
597
|
+
if (analysis.features.includes('multi-tenancy')) {
|
|
598
|
+
layers.push({
|
|
599
|
+
order: order++,
|
|
600
|
+
name: 'Multi-tenancy Patterns',
|
|
601
|
+
focus: 'What isolation and scaling patterns?',
|
|
602
|
+
questions: [
|
|
603
|
+
'What data isolation model?',
|
|
604
|
+
'What authentication per tenant?',
|
|
605
|
+
'What resource limits?',
|
|
606
|
+
'What billing model integration?'
|
|
607
|
+
],
|
|
608
|
+
searchTopics: ['multi-tenant architecture', 'SaaS patterns']
|
|
609
|
+
})
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
// Real-time layer (for collaboration/live features)
|
|
613
|
+
if (analysis.features.includes('realtime')) {
|
|
614
|
+
layers.push({
|
|
615
|
+
order: order++,
|
|
616
|
+
name: 'Real-time Architecture',
|
|
617
|
+
focus: 'What real-time patterns are needed?',
|
|
618
|
+
questions: [
|
|
619
|
+
'WebSocket vs SSE vs polling?',
|
|
620
|
+
'What conflict resolution?',
|
|
621
|
+
'What offline support?',
|
|
622
|
+
'What scaling for connections?'
|
|
623
|
+
],
|
|
624
|
+
searchTopics: ['real-time architecture', 'WebSocket patterns']
|
|
625
|
+
})
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
// Performance layer (for high-traffic or data-intensive)
|
|
629
|
+
if (analysis.isExternalFacing || analysis.complexity >= 6 ||
|
|
630
|
+
/performance|speed|optimization|cache/i.test(analysis.primaryType)) {
|
|
631
|
+
layers.push({
|
|
632
|
+
order: order++,
|
|
633
|
+
name: 'Performance Optimization',
|
|
634
|
+
focus: 'What performance patterns are needed?',
|
|
635
|
+
questions: [
|
|
636
|
+
'What caching strategy?',
|
|
637
|
+
'What lazy loading patterns?',
|
|
638
|
+
'What CDN/edge considerations?',
|
|
639
|
+
'What database optimization?'
|
|
640
|
+
],
|
|
641
|
+
searchTopics: ['performance optimization', 'caching strategies']
|
|
642
|
+
})
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
// Integration layer (for external APIs/services)
|
|
646
|
+
if (/integration|external api|third-party|webhook/i.test(analysis.primaryType) ||
|
|
647
|
+
analysis.features.some(f => /payment|email|sms|notification/i.test(f))) {
|
|
648
|
+
layers.push({
|
|
649
|
+
order: order++,
|
|
650
|
+
name: 'Integration Patterns',
|
|
651
|
+
focus: 'What integration patterns are robust?',
|
|
652
|
+
questions: [
|
|
653
|
+
'What retry/circuit breaker patterns?',
|
|
654
|
+
'What error handling for external failures?',
|
|
655
|
+
'What monitoring/alerting?',
|
|
656
|
+
'What idempotency requirements?'
|
|
657
|
+
],
|
|
658
|
+
searchTopics: ['integration patterns', 'API integration best practices']
|
|
659
|
+
})
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
// Testing Strategy layer (for complex/high-risk)
|
|
663
|
+
if (analysis.riskLevel === 'HIGH' || analysis.complexity >= 7) {
|
|
664
|
+
layers.push({
|
|
665
|
+
order: order++,
|
|
666
|
+
name: 'Testing Strategy',
|
|
667
|
+
focus: 'What testing coverage is needed?',
|
|
668
|
+
questions: [
|
|
669
|
+
'What unit vs integration vs e2e balance?',
|
|
670
|
+
'What edge cases to cover?',
|
|
671
|
+
'What load/stress testing?',
|
|
672
|
+
'What security testing?'
|
|
673
|
+
],
|
|
674
|
+
searchTopics: ['testing strategy', `${analysis.primaryType} testing`]
|
|
675
|
+
})
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
return layers
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
// Execute research for a single layer using Claude's knowledge
|
|
682
|
+
// WHY: Domain knowledge (UX, DB design, security patterns) comes from Claude's training
|
|
683
|
+
// Stack knowledge (Prisma, React) comes from Context7 in Step 2.7
|
|
684
|
+
function executeLayerResearch(layer, changeAnalysis) {
|
|
685
|
+
const result = {
|
|
686
|
+
layer: layer.name,
|
|
687
|
+
findings: [],
|
|
688
|
+
recommendations: [],
|
|
689
|
+
warnings: [],
|
|
690
|
+
source: 'claude-knowledge'
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
// Claude generates best practices based on:
|
|
694
|
+
// - Layer context (what domain?)
|
|
695
|
+
// - Change analysis (what's being built?)
|
|
696
|
+
// - Questions to answer (what to research?)
|
|
697
|
+
//
|
|
698
|
+
// Claude's training includes:
|
|
699
|
+
// - UX: Nielsen Norman, Baymard Institute, Laws of UX
|
|
700
|
+
// - Database: Codd's normalization, indexing patterns
|
|
701
|
+
// - Security: OWASP, auth patterns, encryption
|
|
702
|
+
// - API: REST dissertation, versioning patterns
|
|
703
|
+
// - Architecture: distributed systems, caching, scaling
|
|
704
|
+
|
|
705
|
+
result.findings = generateDomainKnowledge(layer, changeAnalysis)
|
|
706
|
+
result.recommendations = generateRecommendations(layer, changeAnalysis)
|
|
707
|
+
result.warnings = checkForWarnings(layer, changeAnalysis)
|
|
708
|
+
|
|
709
|
+
return result
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
// Generate domain knowledge using Claude's reasoning
|
|
713
|
+
// This is where Claude applies its training to the specific change
|
|
714
|
+
function generateDomainKnowledge(layer, changeAnalysis) {
|
|
715
|
+
const findings = []
|
|
716
|
+
|
|
717
|
+
// Based on layer type, Claude will reason about best practices
|
|
718
|
+
// The actual content comes from Claude's response when /csetup runs
|
|
719
|
+
|
|
720
|
+
findings.push({
|
|
721
|
+
question: layer.questions[0],
|
|
722
|
+
// Claude fills this based on its knowledge when executing
|
|
723
|
+
analysis: `[Claude analyzes: ${layer.focus}]`,
|
|
724
|
+
bestPractices: [], // Claude lists industry standards
|
|
725
|
+
antiPatterns: [], // Claude lists what to avoid
|
|
726
|
+
tradeoffs: [] // Claude explains trade-offs
|
|
727
|
+
})
|
|
728
|
+
|
|
729
|
+
return findings
|
|
730
|
+
}
|
|
334
731
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
732
|
+
// Check for conflicts between design system and industry practices
|
|
733
|
+
function checkDesignConflicts(tokens, researchResults, changeAnalysis) {
|
|
734
|
+
const conflicts = []
|
|
735
|
+
|
|
736
|
+
// Only check for marketing/external-facing changes
|
|
737
|
+
if (!changeAnalysis.isExternalFacing) return conflicts
|
|
738
|
+
|
|
739
|
+
// Check color appropriateness for industry
|
|
740
|
+
if (tokens.colors && changeAnalysis.industryContext) {
|
|
741
|
+
const primaryColor = tokens.colors.primary
|
|
742
|
+
|
|
743
|
+
if (changeAnalysis.industryContext === 'healthcare') {
|
|
744
|
+
// Healthcare typically uses blue/green (trust, calm)
|
|
745
|
+
if (/red|orange|yellow/i.test(primaryColor)) {
|
|
746
|
+
conflicts.push({
|
|
747
|
+
aspect: 'Primary Color',
|
|
748
|
+
current: primaryColor,
|
|
749
|
+
industry: 'healthcare typically uses blue/green for trust and calm',
|
|
750
|
+
recommendation: 'Consider if bright colors are appropriate for healthcare context'
|
|
343
751
|
})
|
|
344
752
|
}
|
|
345
753
|
}
|
|
346
754
|
|
|
347
|
-
if (
|
|
348
|
-
|
|
755
|
+
if (changeAnalysis.industryContext === 'fintech') {
|
|
756
|
+
// Fintech typically uses blue/green (trust, money)
|
|
757
|
+
if (/pink|purple|orange/i.test(primaryColor)) {
|
|
758
|
+
conflicts.push({
|
|
759
|
+
aspect: 'Primary Color',
|
|
760
|
+
current: primaryColor,
|
|
761
|
+
industry: 'fintech typically uses blue/green for trust and stability',
|
|
762
|
+
recommendation: 'Consider if playful colors fit financial services context'
|
|
763
|
+
})
|
|
764
|
+
}
|
|
349
765
|
}
|
|
766
|
+
}
|
|
350
767
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
768
|
+
// Check animation appropriateness
|
|
769
|
+
if (tokens.animations && changeAnalysis.hasCompliance) {
|
|
770
|
+
if (tokens.animations.enableScrollAnimations) {
|
|
771
|
+
conflicts.push({
|
|
772
|
+
aspect: 'Scroll Animations',
|
|
773
|
+
current: 'enabled',
|
|
774
|
+
industry: 'compliance-heavy sites often minimize animations for accessibility',
|
|
775
|
+
recommendation: 'Ensure animations have reduced-motion alternatives'
|
|
776
|
+
})
|
|
354
777
|
}
|
|
355
778
|
}
|
|
356
779
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
const tier2Gaps = allGaps.filter(g => g.tier === 2)
|
|
780
|
+
return conflicts
|
|
781
|
+
}
|
|
360
782
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
783
|
+
// Generate research checklist markdown
|
|
784
|
+
function generateResearchChecklist(changeAnalysis, layers, results) {
|
|
785
|
+
let content = `# Research Checklist: ${changeAnalysis.primaryType}\n\n`
|
|
786
|
+
content += `> Generated by Adaptive Depth Research (v2.4.0)\n`
|
|
787
|
+
content += `> Complexity: ${changeAnalysis.complexity}/10 | Risk: ${changeAnalysis.riskLevel}\n\n`
|
|
788
|
+
|
|
789
|
+
if (layers.length === 0) {
|
|
790
|
+
content += `## ✅ No Research Required\n\n`
|
|
791
|
+
content += `This is a trivial change (complexity ${changeAnalysis.complexity}/10).\n`
|
|
792
|
+
content += `Proceed directly with implementation.\n`
|
|
793
|
+
return content
|
|
794
|
+
}
|
|
366
795
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
796
|
+
content += `## Summary\n\n`
|
|
797
|
+
content += `| Layer | Focus | Status |\n`
|
|
798
|
+
content += `|-------|-------|--------|\n`
|
|
799
|
+
layers.forEach((layer, idx) => {
|
|
800
|
+
content += `| L${idx + 1}: ${layer.name} | ${layer.focus} | ⏳ Pending |\n`
|
|
801
|
+
})
|
|
373
802
|
|
|
374
|
-
|
|
375
|
-
output(` ${feature}:`)
|
|
376
|
-
reqs.forEach(r => output(` - ${r}`))
|
|
377
|
-
}
|
|
803
|
+
content += `\n---\n\n`
|
|
378
804
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
question: 'How would you like to handle the security gaps?',
|
|
389
|
-
header: 'Spec Gaps',
|
|
390
|
-
options: [
|
|
391
|
-
{ label: 'A) Update spec', description: 'Add missing requirements to design.md (recommended)' },
|
|
392
|
-
{ label: 'B) Document skip', description: 'Record justification for skipping' },
|
|
393
|
-
{ label: 'C) Continue anyway', description: 'Proceed with gap (security risk)' }
|
|
394
|
-
],
|
|
395
|
-
multiSelect: false
|
|
396
|
-
}]
|
|
805
|
+
// Detail each layer
|
|
806
|
+
results.forEach((result, idx) => {
|
|
807
|
+
const layer = layers[idx]
|
|
808
|
+
content += `## L${idx + 1}: ${layer.name}\n\n`
|
|
809
|
+
content += `**Focus:** ${layer.focus}\n\n`
|
|
810
|
+
|
|
811
|
+
content += `### Key Questions\n\n`
|
|
812
|
+
layer.questions.forEach(q => {
|
|
813
|
+
content += `- [ ] ${q}\n`
|
|
397
814
|
})
|
|
398
815
|
|
|
399
|
-
if (
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
reqs.forEach(r => output(`- ${r}`))
|
|
410
|
-
}
|
|
411
|
-
output(``)
|
|
412
|
-
output(`**Source:** Feature Best Practice Validation`)
|
|
413
|
-
output(`**Added:** ${new Date().toISOString().split('T')[0]}`)
|
|
414
|
-
output(`\`\`\``)
|
|
415
|
-
output(``)
|
|
416
|
-
output(`Please update design.md and re-run /csetup.`)
|
|
417
|
-
return
|
|
418
|
-
} else if (decision.includes('B')) {
|
|
419
|
-
// Document conscious skip
|
|
420
|
-
output(`\n📝 Add this to design.md to document the skip:\n`)
|
|
421
|
-
output(`\`\`\`markdown`)
|
|
422
|
-
output(`### D{n}: Conscious Security Trade-offs`)
|
|
423
|
-
output(``)
|
|
424
|
-
output(`**Skipped requirements (with justification):**`)
|
|
425
|
-
output(``)
|
|
426
|
-
output(`| Requirement | Why Skipped | Risk Level | Mitigation |`)
|
|
427
|
-
output(`|-------------|-------------|------------|------------|`)
|
|
428
|
-
for (const gap of tier1Gaps) {
|
|
429
|
-
output(`| ${gap.requirement} | [YOUR REASON] | [LOW/MED/HIGH] | [YOUR MITIGATION] |`)
|
|
430
|
-
}
|
|
431
|
-
output(``)
|
|
432
|
-
output(`**Acknowledged by:** User decision in /csetup`)
|
|
433
|
-
output(`**Date:** ${new Date().toISOString().split('T')[0]}`)
|
|
434
|
-
output(`\`\`\``)
|
|
435
|
-
output(``)
|
|
436
|
-
|
|
437
|
-
const confirm = await askUserQuestion({
|
|
438
|
-
questions: [{
|
|
439
|
-
question: 'Confirm you will document this in design.md?',
|
|
440
|
-
header: 'Confirm',
|
|
441
|
-
options: [
|
|
442
|
-
{ label: 'Yes, continue', description: 'I will add documentation' },
|
|
443
|
-
{ label: 'Cancel', description: 'Go back and update spec' }
|
|
444
|
-
],
|
|
445
|
-
multiSelect: false
|
|
446
|
-
}]
|
|
816
|
+
if (result.findings.length > 0) {
|
|
817
|
+
content += `\n### Findings\n\n`
|
|
818
|
+
result.findings.forEach(f => {
|
|
819
|
+
content += `#### ${f.topic}\n\n`
|
|
820
|
+
if (Array.isArray(f.content)) {
|
|
821
|
+
f.content.forEach(point => content += `- ${point}\n`)
|
|
822
|
+
} else {
|
|
823
|
+
content += `${f.content}\n`
|
|
824
|
+
}
|
|
825
|
+
content += `\n*Source: ${f.source}*\n\n`
|
|
447
826
|
})
|
|
827
|
+
}
|
|
448
828
|
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
829
|
+
if (result.recommendations.length > 0) {
|
|
830
|
+
content += `### Recommendations\n\n`
|
|
831
|
+
result.recommendations.forEach(r => {
|
|
832
|
+
content += `- ${r}\n`
|
|
833
|
+
})
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
if (result.warnings.length > 0) {
|
|
837
|
+
content += `\n### ⚠️ Warnings\n\n`
|
|
838
|
+
result.warnings.forEach(w => {
|
|
839
|
+
content += `- ${w}\n`
|
|
840
|
+
})
|
|
453
841
|
}
|
|
454
|
-
|
|
842
|
+
|
|
843
|
+
content += `\n---\n\n`
|
|
844
|
+
})
|
|
845
|
+
|
|
846
|
+
// Add Content Guidelines section for marketing pages
|
|
847
|
+
if (changeAnalysis.primaryType === 'marketing' || changeAnalysis.isExternalFacing) {
|
|
848
|
+
content += `## 📝 Content Guidelines\n\n`
|
|
849
|
+
content += `> Claude generates these guidelines based on the change context.\n`
|
|
850
|
+
content += `> Use these as a starting point for content creation.\n\n`
|
|
851
|
+
|
|
852
|
+
content += `### Hero Section\n\n`
|
|
853
|
+
content += `**Headline Strategy:**\n`
|
|
854
|
+
content += `- Lead with primary pain point or aspiration\n`
|
|
855
|
+
content += `- 8-12 words, emotional trigger\n`
|
|
856
|
+
content += `- [Claude: Generate specific headline angle based on proposal]\n\n`
|
|
857
|
+
|
|
858
|
+
content += `**Subheadline:**\n`
|
|
859
|
+
content += `- Concrete benefit + emotional payoff\n`
|
|
860
|
+
content += `- 15-25 words\n`
|
|
861
|
+
content += `- [Claude: Generate based on value proposition]\n\n`
|
|
862
|
+
|
|
863
|
+
content += `**CTA:**\n`
|
|
864
|
+
content += `- Action verb + outcome\n`
|
|
865
|
+
content += `- [Claude: Generate based on user journey stage]\n\n`
|
|
866
|
+
|
|
867
|
+
content += `### Value Proposition\n\n`
|
|
868
|
+
content += `For each feature, translate to:\n`
|
|
869
|
+
content += `| Feature | Benefit | Emotional Payoff |\n`
|
|
870
|
+
content += `|---------|---------|------------------|\n`
|
|
871
|
+
content += `| [Technical] | [What user gets] | [How it makes them feel] |\n\n`
|
|
872
|
+
|
|
873
|
+
content += `### Social Proof\n\n`
|
|
874
|
+
content += `- Use specific results (numbers, timeframes)\n`
|
|
875
|
+
content += `- Match testimonials to target audience\n`
|
|
876
|
+
content += `- Include trust signals (logos, certifications)\n\n`
|
|
877
|
+
|
|
878
|
+
content += `---\n\n`
|
|
455
879
|
}
|
|
456
880
|
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
881
|
+
content += `## Agent Instructions\n\n`
|
|
882
|
+
content += `When implementing this change, agents should:\n\n`
|
|
883
|
+
content += `1. Review each layer's findings before starting\n`
|
|
884
|
+
content += `2. Check off questions as they are addressed\n`
|
|
885
|
+
content += `3. Follow recommendations where applicable\n`
|
|
886
|
+
content += `4. Address warnings or document exceptions\n`
|
|
887
|
+
|
|
888
|
+
if (changeAnalysis.primaryType === 'marketing' || changeAnalysis.isExternalFacing) {
|
|
889
|
+
content += `5. Use Content Guidelines section for copy direction\n`
|
|
463
890
|
}
|
|
464
|
-
|
|
465
|
-
|
|
891
|
+
|
|
892
|
+
return content
|
|
466
893
|
}
|
|
467
894
|
|
|
468
|
-
//
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
895
|
+
// Helper: Generate recommendations based on layer and context
|
|
896
|
+
// Claude fills in actual recommendations when executing /csetup
|
|
897
|
+
function generateRecommendations(layer, changeAnalysis) {
|
|
898
|
+
// These are prompts for Claude to expand with actual knowledge
|
|
899
|
+
// When /csetup runs, Claude will provide specific recommendations
|
|
900
|
+
|
|
901
|
+
return [
|
|
902
|
+
`[Claude: Based on ${layer.name} best practices for ${changeAnalysis.primaryType}]`,
|
|
903
|
+
`[Claude: Specific to this change's context and requirements]`
|
|
904
|
+
]
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
// Helper: Check for potential warnings based on layer and context
|
|
908
|
+
function checkForWarnings(layer, changeAnalysis) {
|
|
909
|
+
const warnings = []
|
|
910
|
+
|
|
911
|
+
// Risk-based warnings
|
|
912
|
+
if (changeAnalysis.riskLevel === 'HIGH') {
|
|
913
|
+
warnings.push(`HIGH risk change - review ${layer.name} carefully before deployment`)
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
// Compliance warnings
|
|
917
|
+
if (layer.name.includes('Compliance') && changeAnalysis.hasCompliance) {
|
|
918
|
+
warnings.push(`Regulatory compliance required - ensure all ${changeAnalysis.industryContext} requirements are met`)
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
// Payment warnings
|
|
922
|
+
if (changeAnalysis.hasPayment) {
|
|
923
|
+
warnings.push('Payment integration - ensure PCI compliance requirements are met')
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
// Security warnings
|
|
927
|
+
if (layer.name.includes('Security') && changeAnalysis.hasSensitiveData) {
|
|
928
|
+
warnings.push('Sensitive data handling - ensure proper encryption and access controls')
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
return warnings
|
|
474
932
|
}
|
|
475
933
|
```
|
|
476
934
|
|
|
@@ -587,6 +1045,7 @@ if (resolvedLibraries.length === 0) {
|
|
|
587
1045
|
}
|
|
588
1046
|
|
|
589
1047
|
// 5. Generate best-practices files for resolved libraries
|
|
1048
|
+
// v2.5.0: Smart Topic Query - include other library names for cross-library integration docs
|
|
590
1049
|
const bpDir = '.claude/contexts/domain/project/best-practices/'
|
|
591
1050
|
const existingBp = fileExists(bpDir) ? listFiles(bpDir) : []
|
|
592
1051
|
|
|
@@ -598,22 +1057,53 @@ const newLibraries = resolvedLibraries.filter(lib => {
|
|
|
598
1057
|
|
|
599
1058
|
if (newLibraries.length > 0) {
|
|
600
1059
|
output(`\n📚 Generating Best Practices from Context7...`)
|
|
1060
|
+
output(` 💡 Using Smart Topic Query for cross-library integration docs`)
|
|
601
1061
|
|
|
602
1062
|
// Create directory if needed
|
|
603
1063
|
if (!fileExists(bpDir)) {
|
|
604
1064
|
mkdir(bpDir)
|
|
605
1065
|
}
|
|
606
1066
|
|
|
1067
|
+
// Collect all integration risks for summary
|
|
1068
|
+
const integrationRisks = []
|
|
1069
|
+
|
|
607
1070
|
for (const lib of newLibraries) {
|
|
608
1071
|
output(` 📖 Fetching ${lib.title} best practices...`)
|
|
609
1072
|
|
|
610
1073
|
try {
|
|
1074
|
+
// v2.5.0: Smart Topic Query - include other library names in topic
|
|
1075
|
+
// WHY: This captures integration docs (e.g., "drizzle adapter" in auth.js docs)
|
|
1076
|
+
const otherLibNames = resolvedLibraries
|
|
1077
|
+
.filter(l => l.name !== lib.name)
|
|
1078
|
+
.map(l => l.name.toLowerCase())
|
|
1079
|
+
.slice(0, 5) // Limit to 5 to avoid topic overflow
|
|
1080
|
+
.join(', ')
|
|
1081
|
+
|
|
1082
|
+
const smartTopic = [
|
|
1083
|
+
'best practices',
|
|
1084
|
+
'patterns',
|
|
1085
|
+
'anti-patterns',
|
|
1086
|
+
'common mistakes',
|
|
1087
|
+
'adapter', // Key for ORM + Auth integrations
|
|
1088
|
+
'integration', // Key for multi-library setups
|
|
1089
|
+
'schema', // Key for database + auth column naming
|
|
1090
|
+
'configuration', // Key for setup requirements
|
|
1091
|
+
otherLibNames // Include other detected libraries
|
|
1092
|
+
].filter(Boolean).join(', ')
|
|
1093
|
+
|
|
611
1094
|
const docs = await mcp__context7__get_library_docs({
|
|
612
1095
|
context7CompatibleLibraryID: lib.context7Id,
|
|
613
|
-
topic:
|
|
1096
|
+
topic: smartTopic,
|
|
614
1097
|
mode: 'code'
|
|
615
1098
|
})
|
|
616
1099
|
|
|
1100
|
+
// v2.5.0: Detect integration risks from docs content
|
|
1101
|
+
const risks = detectIntegrationRisks(docs, lib.name, resolvedLibraries)
|
|
1102
|
+
if (risks.length > 0) {
|
|
1103
|
+
integrationRisks.push(...risks)
|
|
1104
|
+
output(` ⚠️ Found ${risks.length} integration pattern(s) to review`)
|
|
1105
|
+
}
|
|
1106
|
+
|
|
617
1107
|
const bpContent = generateBestPracticesFile(lib.title, docs, lib.context7Id)
|
|
618
1108
|
const safeName = lib.name.toLowerCase().replace(/[^a-z0-9]/g, '-')
|
|
619
1109
|
Write(`${bpDir}${safeName}.md`, bpContent)
|
|
@@ -624,6 +1114,13 @@ if (newLibraries.length > 0) {
|
|
|
624
1114
|
}
|
|
625
1115
|
}
|
|
626
1116
|
|
|
1117
|
+
// v2.5.0: Generate integration risk summary if any found
|
|
1118
|
+
if (integrationRisks.length > 0) {
|
|
1119
|
+
generateIntegrationRiskSummary(integrationRisks, bpDir, resolvedLibraries)
|
|
1120
|
+
output(`\n⚠️ Integration Risk Summary generated (${integrationRisks.length} items)`)
|
|
1121
|
+
output(` 📄 ${bpDir}INTEGRATION_RISKS.md`)
|
|
1122
|
+
}
|
|
1123
|
+
|
|
627
1124
|
// Generate/update index.md
|
|
628
1125
|
generateBestPracticesIndex(resolvedLibraries, changeId)
|
|
629
1126
|
output(` ✅ index.md updated`)
|
|
@@ -1313,6 +1810,228 @@ function extractChecklist(docs: string): string {
|
|
|
1313
1810
|
|
|
1314
1811
|
---
|
|
1315
1812
|
|
|
1813
|
+
### Helper: detectIntegrationRisks() - v2.5.0
|
|
1814
|
+
|
|
1815
|
+
> **Smart Risk Detection:** Scans Context7 docs for integration patterns that require attention.
|
|
1816
|
+
> **WHY:** Proactively catch integration requirements BEFORE implementation, not at runtime.
|
|
1817
|
+
|
|
1818
|
+
```typescript
|
|
1819
|
+
function detectIntegrationRisks(
|
|
1820
|
+
docs: string,
|
|
1821
|
+
currentLib: string,
|
|
1822
|
+
allLibs: Array<{ name: string; title: string }>
|
|
1823
|
+
): Array<{ library: string; risk: string; pattern: string; recommendation: string }> {
|
|
1824
|
+
const risks = []
|
|
1825
|
+
const docsLower = docs.toLowerCase()
|
|
1826
|
+
|
|
1827
|
+
// Integration risk patterns to detect
|
|
1828
|
+
const riskPatterns = [
|
|
1829
|
+
// Adapter patterns (ORM + Auth)
|
|
1830
|
+
{
|
|
1831
|
+
keywords: ['adapter', 'drizzleadapter', 'prismaadapter'],
|
|
1832
|
+
risk: 'Database adapter configuration required',
|
|
1833
|
+
pattern: 'adapter',
|
|
1834
|
+
recommendation: 'Verify adapter schema matches expected column names'
|
|
1835
|
+
},
|
|
1836
|
+
// Column naming patterns
|
|
1837
|
+
{
|
|
1838
|
+
keywords: ['column', 'columnname', 'snake_case', 'camelcase', 'mapping'],
|
|
1839
|
+
risk: 'Column naming convention mismatch possible',
|
|
1840
|
+
pattern: 'schema',
|
|
1841
|
+
recommendation: 'Check column naming between ORM schema and library expectations'
|
|
1842
|
+
},
|
|
1843
|
+
// Schema patterns
|
|
1844
|
+
{
|
|
1845
|
+
keywords: ['userstable', 'accountstable', 'sessionstable', 'schema'],
|
|
1846
|
+
risk: 'Custom table schema required',
|
|
1847
|
+
pattern: 'schema',
|
|
1848
|
+
recommendation: 'Ensure table schemas match library documentation exactly'
|
|
1849
|
+
},
|
|
1850
|
+
// Sync/Migration patterns
|
|
1851
|
+
{
|
|
1852
|
+
keywords: ['sync', 'migrate', 'migration', 'syncurl', 'embedded replica'],
|
|
1853
|
+
risk: 'Data synchronization setup required',
|
|
1854
|
+
pattern: 'sync',
|
|
1855
|
+
recommendation: 'Configure sync intervals and handle offline scenarios'
|
|
1856
|
+
},
|
|
1857
|
+
// Webhook patterns
|
|
1858
|
+
{
|
|
1859
|
+
keywords: ['webhook', 'webhookendpoint', 'webhooksecret'],
|
|
1860
|
+
risk: 'Webhook endpoint configuration required',
|
|
1861
|
+
pattern: 'webhook',
|
|
1862
|
+
recommendation: 'Set up webhook endpoints and verify signatures'
|
|
1863
|
+
},
|
|
1864
|
+
// API Key patterns
|
|
1865
|
+
{
|
|
1866
|
+
keywords: ['apikey', 'secretkey', 'authtoken', 'bearer'],
|
|
1867
|
+
risk: 'API credentials setup required',
|
|
1868
|
+
pattern: 'credentials',
|
|
1869
|
+
recommendation: 'Store credentials securely in environment variables'
|
|
1870
|
+
},
|
|
1871
|
+
// Lifecycle patterns
|
|
1872
|
+
{
|
|
1873
|
+
keywords: ['beforeall', 'afterall', 'beforeeach', 'aftereach', 'setup', 'teardown'],
|
|
1874
|
+
risk: 'Test lifecycle hooks required',
|
|
1875
|
+
pattern: 'lifecycle',
|
|
1876
|
+
recommendation: 'Implement proper setup/teardown in test configuration'
|
|
1877
|
+
}
|
|
1878
|
+
]
|
|
1879
|
+
|
|
1880
|
+
for (const rp of riskPatterns) {
|
|
1881
|
+
const found = rp.keywords.some(kw => docsLower.includes(kw.toLowerCase()))
|
|
1882
|
+
if (found) {
|
|
1883
|
+
// Check if this risk involves other detected libraries
|
|
1884
|
+
const involvedLibs = allLibs
|
|
1885
|
+
.filter(l => l.name !== currentLib)
|
|
1886
|
+
.filter(l => docsLower.includes(l.name.toLowerCase()))
|
|
1887
|
+
.map(l => l.name)
|
|
1888
|
+
|
|
1889
|
+
risks.push({
|
|
1890
|
+
library: currentLib,
|
|
1891
|
+
risk: rp.risk,
|
|
1892
|
+
pattern: rp.pattern,
|
|
1893
|
+
recommendation: rp.recommendation,
|
|
1894
|
+
involvedLibraries: involvedLibs
|
|
1895
|
+
})
|
|
1896
|
+
}
|
|
1897
|
+
}
|
|
1898
|
+
|
|
1899
|
+
return risks
|
|
1900
|
+
}
|
|
1901
|
+
```
|
|
1902
|
+
|
|
1903
|
+
---
|
|
1904
|
+
|
|
1905
|
+
### Helper: generateIntegrationRiskSummary() - v2.5.0
|
|
1906
|
+
|
|
1907
|
+
> **Risk Summary Output:** Creates INTEGRATION_RISKS.md with all detected cross-library concerns.
|
|
1908
|
+
> **WHY:** Agents can review this BEFORE implementation to avoid common integration mistakes.
|
|
1909
|
+
|
|
1910
|
+
```typescript
|
|
1911
|
+
function generateIntegrationRiskSummary(
|
|
1912
|
+
risks: Array<{
|
|
1913
|
+
library: string
|
|
1914
|
+
risk: string
|
|
1915
|
+
pattern: string
|
|
1916
|
+
recommendation: string
|
|
1917
|
+
involvedLibraries?: string[]
|
|
1918
|
+
}>,
|
|
1919
|
+
bpDir: string,
|
|
1920
|
+
allLibs: Array<{ name: string; title: string }>
|
|
1921
|
+
): void {
|
|
1922
|
+
// Group risks by pattern type
|
|
1923
|
+
const byPattern = {}
|
|
1924
|
+
for (const r of risks) {
|
|
1925
|
+
if (!byPattern[r.pattern]) byPattern[r.pattern] = []
|
|
1926
|
+
byPattern[r.pattern].push(r)
|
|
1927
|
+
}
|
|
1928
|
+
|
|
1929
|
+
const content = `# Integration Risk Summary
|
|
1930
|
+
|
|
1931
|
+
> **Generated:** ${new Date().toISOString().split('T')[0]}
|
|
1932
|
+
> **Template Version:** 2.5.0 - Smart Topic Query
|
|
1933
|
+
> **Detected Libraries:** ${allLibs.map(l => l.name).join(', ')}
|
|
1934
|
+
|
|
1935
|
+
---
|
|
1936
|
+
|
|
1937
|
+
## ⚠️ Review Before Implementation
|
|
1938
|
+
|
|
1939
|
+
The following integration patterns were detected from library documentation.
|
|
1940
|
+
**Agents should review these items in STEP 0 before writing code.**
|
|
1941
|
+
|
|
1942
|
+
---
|
|
1943
|
+
|
|
1944
|
+
${Object.entries(byPattern).map(([pattern, patternRisks]) => `
|
|
1945
|
+
### ${pattern.toUpperCase()} Patterns
|
|
1946
|
+
|
|
1947
|
+
| Library | Risk | Recommendation |
|
|
1948
|
+
|---------|------|----------------|
|
|
1949
|
+
${patternRisks.map(r => `| ${r.library} | ${r.risk} | ${r.recommendation} |`).join('\n')}
|
|
1950
|
+
${patternRisks.some(r => r.involvedLibraries?.length > 0) ? `
|
|
1951
|
+
**Cross-library concerns:**
|
|
1952
|
+
${patternRisks.filter(r => r.involvedLibraries?.length > 0).map(r => `- ${r.library} ↔ ${r.involvedLibraries.join(', ')}: ${r.risk}`).join('\n')}
|
|
1953
|
+
` : ''}
|
|
1954
|
+
`).join('\n')}
|
|
1955
|
+
|
|
1956
|
+
---
|
|
1957
|
+
|
|
1958
|
+
## Quick Checklist
|
|
1959
|
+
|
|
1960
|
+
Before implementing integrations:
|
|
1961
|
+
|
|
1962
|
+
${[...new Set(risks.map(r => r.recommendation))].map(rec => `- [ ] ${rec}`).join('\n')}
|
|
1963
|
+
|
|
1964
|
+
---
|
|
1965
|
+
|
|
1966
|
+
**This file is auto-generated by /csetup v2.5.0**
|
|
1967
|
+
**Agents read this in STEP 0 alongside best-practices files**
|
|
1968
|
+
`
|
|
1969
|
+
|
|
1970
|
+
Write(`${bpDir}INTEGRATION_RISKS.md`, content)
|
|
1971
|
+
}
|
|
1972
|
+
```
|
|
1973
|
+
|
|
1974
|
+
---
|
|
1975
|
+
|
|
1976
|
+
### Helper: generateBestPracticesIndex() - v2.5.0
|
|
1977
|
+
|
|
1978
|
+
> **Index File:** Creates index.md registry of all best practices files.
|
|
1979
|
+
> **v2.5.0:** Now includes INTEGRATION_RISKS.md if present.
|
|
1980
|
+
|
|
1981
|
+
```typescript
|
|
1982
|
+
function generateBestPracticesIndex(
|
|
1983
|
+
resolvedLibraries: Array<{ name: string; title: string; context7Id: string }>,
|
|
1984
|
+
changeId: string
|
|
1985
|
+
): void {
|
|
1986
|
+
const bpDir = '.claude/contexts/domain/project/best-practices/'
|
|
1987
|
+
const hasIntegrationRisks = fileExists(`${bpDir}INTEGRATION_RISKS.md`)
|
|
1988
|
+
|
|
1989
|
+
const content = `# Best Practices Index
|
|
1990
|
+
|
|
1991
|
+
> **Generated:** ${new Date().toISOString().split('T')[0]}
|
|
1992
|
+
> **Template Version:** 2.5.0 - Smart Topic Query
|
|
1993
|
+
> **Change:** ${changeId}
|
|
1994
|
+
|
|
1995
|
+
---
|
|
1996
|
+
|
|
1997
|
+
## 📚 Library Best Practices
|
|
1998
|
+
|
|
1999
|
+
| Library | File | Context7 ID |
|
|
2000
|
+
|---------|------|-------------|
|
|
2001
|
+
${resolvedLibraries.map(lib => {
|
|
2002
|
+
const safeName = lib.name.toLowerCase().replace(/[^a-z0-9]/g, '-')
|
|
2003
|
+
return `| ${lib.title} | [${safeName}.md](./${safeName}.md) | \`${lib.context7Id}\` |`
|
|
2004
|
+
}).join('\n')}
|
|
2005
|
+
|
|
2006
|
+
---
|
|
2007
|
+
|
|
2008
|
+
${hasIntegrationRisks ? `## ⚠️ Integration Risks
|
|
2009
|
+
|
|
2010
|
+
Cross-library integration concerns detected. **Review before implementation.**
|
|
2011
|
+
|
|
2012
|
+
→ [INTEGRATION_RISKS.md](./INTEGRATION_RISKS.md)
|
|
2013
|
+
|
|
2014
|
+
---
|
|
2015
|
+
|
|
2016
|
+
` : ''}## Usage
|
|
2017
|
+
|
|
2018
|
+
Agents read these files in **STEP 0** before implementation:
|
|
2019
|
+
|
|
2020
|
+
1. Read \`index.md\` (this file) for overview
|
|
2021
|
+
2. Read relevant \`{library}.md\` files for specific best practices
|
|
2022
|
+
${hasIntegrationRisks ? '3. Read `INTEGRATION_RISKS.md` for cross-library concerns' : ''}
|
|
2023
|
+
|
|
2024
|
+
---
|
|
2025
|
+
|
|
2026
|
+
**Auto-generated by /csetup v2.5.0**
|
|
2027
|
+
`
|
|
2028
|
+
|
|
2029
|
+
Write(`${bpDir}index.md`, content)
|
|
2030
|
+
}
|
|
2031
|
+
```
|
|
2032
|
+
|
|
2033
|
+
---
|
|
2034
|
+
|
|
1316
2035
|
### Step 3: Analyze Tasks
|
|
1317
2036
|
|
|
1318
2037
|
**Parse tasks.md content and detect keywords:**
|