@paths.design/caws-cli 3.1.1 → 3.2.1
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/dist/commands/provenance.d.ts +10 -0
- package/dist/commands/provenance.d.ts.map +1 -1
- package/dist/commands/provenance.js +388 -3
- package/dist/generators/working-spec.js +21 -21
- package/dist/index.js +113 -7
- package/dist/scaffold/git-hooks.d.ts +20 -0
- package/dist/scaffold/git-hooks.d.ts.map +1 -0
- package/dist/scaffold/git-hooks.js +417 -0
- package/dist/scaffold/index.d.ts.map +1 -1
- package/dist/scaffold/index.js +19 -19
- package/package.json +1 -1
- package/dist/index-new.d.ts +0 -5
- package/dist/index-new.d.ts.map +0 -1
- package/dist/index-new.js +0 -317
- package/dist/index.js.backup +0 -4711
- package/templates/apps/tools/caws/prompt-lint.js.backup +0 -274
- package/templates/apps/tools/caws/provenance.js.backup +0 -73
|
@@ -19,4 +19,14 @@ export function showProvenance(options: any): Promise<void>;
|
|
|
19
19
|
* @param {Object} options - Command options
|
|
20
20
|
*/
|
|
21
21
|
export function verifyProvenance(options: any): Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* Initialize provenance tracking for the project
|
|
24
|
+
* @param {Object} options - Command options
|
|
25
|
+
*/
|
|
26
|
+
export function initProvenance(options: any): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* Install git hooks for automatic provenance updates
|
|
29
|
+
* @param {Object} options - Command options
|
|
30
|
+
*/
|
|
31
|
+
export function installHooks(options: any): Promise<void>;
|
|
22
32
|
//# sourceMappingURL=provenance.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provenance.d.ts","sourceRoot":"","sources":["../../src/commands/provenance.js"],"names":[],"mappings":"AAWA;;;;GAIG;AACH,8CAHW,MAAM,+
|
|
1
|
+
{"version":3,"file":"provenance.d.ts","sourceRoot":"","sources":["../../src/commands/provenance.js"],"names":[],"mappings":"AAWA;;;;GAIG;AACH,8CAHW,MAAM,+BA2BhB;AAED;;;GAGG;AACH,8DA4EC;AAED;;;GAGG;AACH,4DAyEC;AAED;;;GAGG;AACH,8DA8CC;AA6iBD;;;GAGG;AACH,4DAmEC;AAzcD;;;GAGG;AACH,0DAwEC"}
|
|
@@ -25,9 +25,13 @@ async function provenanceCommand(subcommand, options) {
|
|
|
25
25
|
return await verifyProvenance(options);
|
|
26
26
|
case 'analyze-ai':
|
|
27
27
|
return await analyzeAIProvenance(options);
|
|
28
|
+
case 'init':
|
|
29
|
+
return await initProvenance(options);
|
|
30
|
+
case 'install-hooks':
|
|
31
|
+
return await installHooks(options);
|
|
28
32
|
default:
|
|
29
33
|
console.error(`❌ Unknown provenance subcommand: ${subcommand}`);
|
|
30
|
-
console.log('Available commands: update, show, verify, analyze-ai');
|
|
34
|
+
console.log('Available commands: update, show, verify, analyze-ai, init, install-hooks');
|
|
31
35
|
process.exit(1);
|
|
32
36
|
}
|
|
33
37
|
} catch (error) {
|
|
@@ -123,12 +127,31 @@ async function updateProvenance(options) {
|
|
|
123
127
|
* @param {Object} options - Command options
|
|
124
128
|
*/
|
|
125
129
|
async function showProvenance(options) {
|
|
126
|
-
const { output = '.caws/provenance' } = options;
|
|
130
|
+
const { output = '.caws/provenance', format = 'text' } = options;
|
|
127
131
|
|
|
128
132
|
const chain = await loadProvenanceChain(output);
|
|
129
133
|
|
|
130
134
|
if (chain.length === 0) {
|
|
131
|
-
|
|
135
|
+
if (format === 'dashboard') {
|
|
136
|
+
console.log('┌─ CAWS Provenance Dashboard ──────────────────────┐');
|
|
137
|
+
console.log('│ ℹ️ No provenance data found │');
|
|
138
|
+
console.log('│ │');
|
|
139
|
+
console.log('│ 💡 Run "caws provenance init" to get started │');
|
|
140
|
+
console.log('└─────────────────────────────────────────────────┘');
|
|
141
|
+
} else {
|
|
142
|
+
console.log('ℹ️ No provenance data found');
|
|
143
|
+
console.log(`💡 Run "caws provenance init" to get started`);
|
|
144
|
+
}
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (format === 'json') {
|
|
149
|
+
console.log(JSON.stringify(chain, null, 2));
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (format === 'dashboard') {
|
|
154
|
+
await showDashboardFormat(chain, output);
|
|
132
155
|
return;
|
|
133
156
|
}
|
|
134
157
|
|
|
@@ -399,6 +422,293 @@ function analyzeCheckpointUsage(aiEntries) {
|
|
|
399
422
|
};
|
|
400
423
|
}
|
|
401
424
|
|
|
425
|
+
/**
|
|
426
|
+
* Install git hooks for automatic provenance updates
|
|
427
|
+
* @param {Object} options - Command options
|
|
428
|
+
*/
|
|
429
|
+
async function installHooks(options) {
|
|
430
|
+
const { output = '.caws/provenance', skipPreCommit = false, skipPostCommit = false } = options;
|
|
431
|
+
|
|
432
|
+
console.log('🔗 Installing CAWS Provenance Git Hooks');
|
|
433
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
434
|
+
|
|
435
|
+
// Check if we're in a git repository
|
|
436
|
+
if (!(await fs.pathExists('.git'))) {
|
|
437
|
+
console.log('❌ Not in a git repository');
|
|
438
|
+
console.log('💡 Initialize git first: git init');
|
|
439
|
+
process.exit(1);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
// Check if provenance is initialized
|
|
443
|
+
if (!(await fs.pathExists(path.join(output, 'chain.json')))) {
|
|
444
|
+
console.log('❌ Provenance not initialized');
|
|
445
|
+
console.log('💡 Run "caws provenance init" first');
|
|
446
|
+
process.exit(1);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
console.log('✅ Found git repository and provenance setup');
|
|
450
|
+
|
|
451
|
+
// Ensure hooks directory exists
|
|
452
|
+
const hooksDir = '.git/hooks';
|
|
453
|
+
await fs.ensureDir(hooksDir);
|
|
454
|
+
console.log('✅ Ensured hooks directory exists');
|
|
455
|
+
|
|
456
|
+
let hooksInstalled = 0;
|
|
457
|
+
|
|
458
|
+
// Install pre-commit hook for validation
|
|
459
|
+
if (!skipPreCommit) {
|
|
460
|
+
try {
|
|
461
|
+
const preCommitHook = await createPreCommitHook(output);
|
|
462
|
+
const preCommitPath = path.join(hooksDir, 'pre-commit');
|
|
463
|
+
|
|
464
|
+
await fs.writeFile(preCommitPath, preCommitHook);
|
|
465
|
+
await fs.chmod(preCommitPath, '755');
|
|
466
|
+
console.log('✅ Installed pre-commit hook for provenance validation');
|
|
467
|
+
hooksInstalled++;
|
|
468
|
+
} catch (error) {
|
|
469
|
+
console.warn('⚠️ Failed to install pre-commit hook:', error.message);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// Install post-commit hook for provenance updates
|
|
474
|
+
if (!skipPostCommit) {
|
|
475
|
+
try {
|
|
476
|
+
const postCommitHook = await createPostCommitHook(output);
|
|
477
|
+
const postCommitPath = path.join(hooksDir, 'post-commit');
|
|
478
|
+
|
|
479
|
+
await fs.writeFile(postCommitPath, postCommitHook);
|
|
480
|
+
await fs.chmod(postCommitPath, '755');
|
|
481
|
+
console.log('✅ Installed post-commit hook for provenance updates');
|
|
482
|
+
hooksInstalled++;
|
|
483
|
+
} catch (error) {
|
|
484
|
+
console.warn('⚠️ Failed to install post-commit hook:', error.message);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
console.log('');
|
|
489
|
+
console.log('🎉 Git hooks installation complete!');
|
|
490
|
+
console.log('');
|
|
491
|
+
console.log(`Installed ${hooksInstalled} hook(s):`);
|
|
492
|
+
if (!skipPreCommit) {
|
|
493
|
+
console.log(' • pre-commit: Validates provenance before commits');
|
|
494
|
+
}
|
|
495
|
+
if (!skipPostCommit) {
|
|
496
|
+
console.log(' • post-commit: Updates provenance after commits');
|
|
497
|
+
}
|
|
498
|
+
console.log('');
|
|
499
|
+
console.log('💡 Your commits will now automatically maintain provenance!');
|
|
500
|
+
console.log(' Run "caws provenance show" to view the updated chain');
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
/**
|
|
504
|
+
* Create pre-commit hook script for provenance validation
|
|
505
|
+
* @param {string} outputDir - Provenance output directory
|
|
506
|
+
* @returns {string} Hook script content
|
|
507
|
+
*/
|
|
508
|
+
async function createPreCommitHook(outputDir) {
|
|
509
|
+
const scriptPath = path.resolve('node_modules/.bin/caws');
|
|
510
|
+
const fallbackPath = path.resolve('packages/caws-cli/dist/index.js');
|
|
511
|
+
|
|
512
|
+
return `#!/bin/sh
|
|
513
|
+
# CAWS Provenance Pre-commit Hook
|
|
514
|
+
# Validates provenance integrity before allowing commits
|
|
515
|
+
|
|
516
|
+
echo "🔍 Validating CAWS provenance..."
|
|
517
|
+
|
|
518
|
+
# Find caws CLI
|
|
519
|
+
if command -v caws >/dev/null 2>&1; then
|
|
520
|
+
CAWS_CMD="caws"
|
|
521
|
+
elif [ -x "${scriptPath}" ]; then
|
|
522
|
+
CAWS_CMD="${scriptPath}"
|
|
523
|
+
elif [ -x "${fallbackPath}" ]; then
|
|
524
|
+
CAWS_CMD="node ${fallbackPath}"
|
|
525
|
+
else
|
|
526
|
+
echo "⚠️ CAWS CLI not found, skipping provenance validation"
|
|
527
|
+
exit 0
|
|
528
|
+
fi
|
|
529
|
+
|
|
530
|
+
# Run provenance verification
|
|
531
|
+
if $CAWS_CMD provenance verify --output "${outputDir}" >/dev/null 2>&1; then
|
|
532
|
+
echo "✅ Provenance validation passed"
|
|
533
|
+
exit 0
|
|
534
|
+
else
|
|
535
|
+
echo "❌ Provenance validation failed"
|
|
536
|
+
echo "💡 Run 'caws provenance show' to investigate"
|
|
537
|
+
exit 1
|
|
538
|
+
fi
|
|
539
|
+
`;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
/**
|
|
543
|
+
* Create post-commit hook script for provenance updates
|
|
544
|
+
* @param {string} outputDir - Provenance output directory
|
|
545
|
+
* @returns {string} Hook script content
|
|
546
|
+
*/
|
|
547
|
+
async function createPostCommitHook(outputDir) {
|
|
548
|
+
const scriptPath = path.resolve('node_modules/.bin/caws');
|
|
549
|
+
const fallbackPath = path.resolve('packages/caws-cli/dist/index.js');
|
|
550
|
+
|
|
551
|
+
return `#!/bin/sh
|
|
552
|
+
# CAWS Provenance Post-commit Hook
|
|
553
|
+
# Updates provenance chain after successful commits
|
|
554
|
+
|
|
555
|
+
echo "📝 Updating CAWS provenance..."
|
|
556
|
+
|
|
557
|
+
# Get the current commit hash
|
|
558
|
+
COMMIT_HASH=$(git rev-parse HEAD)
|
|
559
|
+
COMMIT_MSG=$(git log -1 --pretty=%B | head -n 1)
|
|
560
|
+
AUTHOR=$(git log -1 --pretty=%an)
|
|
561
|
+
|
|
562
|
+
# Find caws CLI
|
|
563
|
+
if command -v caws >/dev/null 2>&1; then
|
|
564
|
+
CAWS_CMD="caws"
|
|
565
|
+
elif [ -x "${scriptPath}" ]; then
|
|
566
|
+
CAWS_CMD="${scriptPath}"
|
|
567
|
+
elif [ -x "${fallbackPath}" ]; then
|
|
568
|
+
CAWS_CMD="node ${fallbackPath}"
|
|
569
|
+
else
|
|
570
|
+
echo "⚠️ CAWS CLI not found, skipping provenance update"
|
|
571
|
+
exit 0
|
|
572
|
+
fi
|
|
573
|
+
|
|
574
|
+
# Update provenance
|
|
575
|
+
if $CAWS_CMD provenance update --commit "$COMMIT_HASH" --message "$COMMIT_MSG" --author "$AUTHOR" --output "${outputDir}" --quiet; then
|
|
576
|
+
echo "✅ Provenance updated for commit \${COMMIT_HASH:0:8}"
|
|
577
|
+
else
|
|
578
|
+
echo "⚠️ Failed to update provenance (non-fatal)"
|
|
579
|
+
fi
|
|
580
|
+
|
|
581
|
+
exit 0
|
|
582
|
+
`;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
/**
|
|
586
|
+
* Show provenance data in dashboard format
|
|
587
|
+
* @param {Array} chain - Provenance chain entries
|
|
588
|
+
* @param {string} outputDir - Output directory path
|
|
589
|
+
*/
|
|
590
|
+
async function showDashboardFormat(chain, outputDir) {
|
|
591
|
+
// Calculate key metrics
|
|
592
|
+
const totalEntries = chain.length;
|
|
593
|
+
const aiEntries = chain.filter(
|
|
594
|
+
(entry) => entry.cursor_tracking?.available && entry.agent?.type !== 'human'
|
|
595
|
+
).length;
|
|
596
|
+
|
|
597
|
+
const avgQualityScore =
|
|
598
|
+
aiEntries > 0
|
|
599
|
+
? chain
|
|
600
|
+
.filter((entry) => entry.cursor_tracking?.quality_metrics?.ai_code_quality_score)
|
|
601
|
+
.reduce(
|
|
602
|
+
(sum, entry) => sum + entry.cursor_tracking.quality_metrics.ai_code_quality_score,
|
|
603
|
+
0
|
|
604
|
+
) /
|
|
605
|
+
chain.filter((entry) => entry.cursor_tracking?.quality_metrics?.ai_code_quality_score)
|
|
606
|
+
.length
|
|
607
|
+
: 0;
|
|
608
|
+
|
|
609
|
+
const avgAcceptanceRate =
|
|
610
|
+
aiEntries > 0
|
|
611
|
+
? chain
|
|
612
|
+
.filter((entry) => entry.cursor_tracking?.quality_metrics?.acceptance_rate)
|
|
613
|
+
.reduce((sum, entry) => sum + entry.cursor_tracking.quality_metrics.acceptance_rate, 0) /
|
|
614
|
+
chain.filter((entry) => entry.cursor_tracking?.quality_metrics?.acceptance_rate).length
|
|
615
|
+
: 0;
|
|
616
|
+
|
|
617
|
+
// Check config
|
|
618
|
+
let configStatus = '❌ Not configured';
|
|
619
|
+
try {
|
|
620
|
+
const configPath = path.join(outputDir, 'config.json');
|
|
621
|
+
if (await fs.pathExists(configPath)) {
|
|
622
|
+
const config = JSON.parse(await fs.readFile(configPath, 'utf8'));
|
|
623
|
+
const configured = [
|
|
624
|
+
config.cursor_tracking_api !== 'not_configured',
|
|
625
|
+
config.cursor_checkpoint_api !== 'not_configured',
|
|
626
|
+
config.cursor_project_id !== 'not_configured',
|
|
627
|
+
].filter(Boolean).length;
|
|
628
|
+
configStatus = configured === 3 ? '✅ Fully configured' : `⚠️ ${configured}/3 configured`;
|
|
629
|
+
}
|
|
630
|
+
} catch (error) {
|
|
631
|
+
// Ignore config read errors
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
// Display dashboard
|
|
635
|
+
console.log('┌─ CAWS Provenance Dashboard ──────────────────────┐');
|
|
636
|
+
console.log(`│ 📊 Total Entries: ${totalEntries.toString().padEnd(33)} │`);
|
|
637
|
+
console.log(`│ 🤖 AI-Assisted: ${aiEntries.toString().padEnd(35)} │`);
|
|
638
|
+
console.log(
|
|
639
|
+
`│ 🎯 Avg Quality: ${(avgQualityScore * 100).toFixed(0).padEnd(2)}%${' '.repeat(33)} │`
|
|
640
|
+
);
|
|
641
|
+
console.log(
|
|
642
|
+
`│ ✅ Avg Acceptance: ${(avgAcceptanceRate * 100).toFixed(0).padEnd(2)}%${' '.repeat(30)} │`
|
|
643
|
+
);
|
|
644
|
+
console.log(`│ ⚙️ Config Status: ${configStatus.padEnd(31)} │`);
|
|
645
|
+
console.log('├─────────────────────────────────────────────────┤');
|
|
646
|
+
|
|
647
|
+
if (totalEntries > 0) {
|
|
648
|
+
console.log('│ Recent Activity: │');
|
|
649
|
+
const recent = chain.slice(-3);
|
|
650
|
+
recent.forEach((entry, index) => {
|
|
651
|
+
const commit = entry.commit.hash.substring(0, 8);
|
|
652
|
+
const time = new Date(entry.timestamp).toLocaleDateString();
|
|
653
|
+
const msg = entry.commit.message.split('\n')[0].substring(0, 30);
|
|
654
|
+
const line = `${index + 1}. ${commit} ${time} ${msg}`;
|
|
655
|
+
console.log(`│ ${line.padEnd(47)} │`);
|
|
656
|
+
});
|
|
657
|
+
|
|
658
|
+
if (aiEntries > 0) {
|
|
659
|
+
console.log('├─────────────────────────────────────────────────┤');
|
|
660
|
+
console.log('│ AI Contribution Breakdown: │');
|
|
661
|
+
|
|
662
|
+
const contributions = chain
|
|
663
|
+
.filter((entry) => entry.cursor_tracking?.ai_code_breakdown)
|
|
664
|
+
.map((entry) => entry.cursor_tracking.ai_code_breakdown);
|
|
665
|
+
|
|
666
|
+
if (contributions.length > 0) {
|
|
667
|
+
const avgComposer =
|
|
668
|
+
contributions.reduce((sum, c) => sum + c.composer_chat.percentage, 0) /
|
|
669
|
+
contributions.length;
|
|
670
|
+
const avgTab =
|
|
671
|
+
contributions.reduce((sum, c) => sum + c.tab_completions.percentage, 0) /
|
|
672
|
+
contributions.length;
|
|
673
|
+
const avgManual =
|
|
674
|
+
contributions.reduce((sum, c) => sum + c.manual_human.percentage, 0) /
|
|
675
|
+
contributions.length;
|
|
676
|
+
|
|
677
|
+
const composerBar = '█'.repeat(Math.round(avgComposer / 5));
|
|
678
|
+
const tabBar = '█'.repeat(Math.round(avgTab / 5));
|
|
679
|
+
const manualBar = '█'.repeat(Math.round(avgManual / 5));
|
|
680
|
+
|
|
681
|
+
console.log(
|
|
682
|
+
`│ Composer/Chat: ${composerBar.padEnd(10)} ${Math.round(avgComposer).toString().padStart(2)}%${' '.repeat(18)} │`
|
|
683
|
+
);
|
|
684
|
+
console.log(
|
|
685
|
+
`│ Tab Complete: ${tabBar.padEnd(10)} ${Math.round(avgTab).toString().padStart(2)}%${' '.repeat(18)} │`
|
|
686
|
+
);
|
|
687
|
+
console.log(
|
|
688
|
+
`│ Manual: ${manualBar.padEnd(10)} ${Math.round(avgManual).toString().padStart(2)}%${' '.repeat(18)} │`
|
|
689
|
+
);
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
console.log('└─────────────────────────────────────────────────┘');
|
|
695
|
+
|
|
696
|
+
// Add insights
|
|
697
|
+
if (aiEntries > 0) {
|
|
698
|
+
console.log('');
|
|
699
|
+
console.log('💡 Insights:');
|
|
700
|
+
if (avgAcceptanceRate > 0.9) {
|
|
701
|
+
console.log(' ✅ High AI acceptance rate indicates effective collaboration');
|
|
702
|
+
} else if (avgAcceptanceRate < 0.7) {
|
|
703
|
+
console.log(' ⚠️ Lower acceptance rate may indicate AI refinement needed');
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
if (avgQualityScore > 0.8) {
|
|
707
|
+
console.log(' 🎯 Excellent AI code quality - great results!');
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
|
|
402
712
|
/**
|
|
403
713
|
* Provide insights and recommendations based on AI analysis
|
|
404
714
|
*/
|
|
@@ -498,6 +808,79 @@ async function getCursorTrackingData(commitHash) {
|
|
|
498
808
|
}
|
|
499
809
|
}
|
|
500
810
|
|
|
811
|
+
/**
|
|
812
|
+
* Initialize provenance tracking for the project
|
|
813
|
+
* @param {Object} options - Command options
|
|
814
|
+
*/
|
|
815
|
+
async function initProvenance(options) {
|
|
816
|
+
const { output = '.caws/provenance', cursorApi } = options;
|
|
817
|
+
|
|
818
|
+
console.log('🚀 Initializing CAWS Provenance Tracking');
|
|
819
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
820
|
+
|
|
821
|
+
// Check if already initialized
|
|
822
|
+
if (await fs.pathExists(path.join(output, 'chain.json'))) {
|
|
823
|
+
console.log('⚠️ Provenance already initialized');
|
|
824
|
+
console.log(` Chain exists at: ${output}/chain.json`);
|
|
825
|
+
console.log('');
|
|
826
|
+
console.log('💡 To reset, delete the provenance directory and run again');
|
|
827
|
+
return;
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
// Ensure output directory exists
|
|
831
|
+
await fs.ensureDir(output);
|
|
832
|
+
console.log(`✅ Created provenance directory: ${output}`);
|
|
833
|
+
|
|
834
|
+
// Load working spec to validate CAWS project
|
|
835
|
+
const specPath = '.caws/working-spec.yaml';
|
|
836
|
+
if (!(await fs.pathExists(specPath))) {
|
|
837
|
+
console.log('');
|
|
838
|
+
console.log('❌ Not in a CAWS project - missing working spec');
|
|
839
|
+
console.log('💡 Run "caws init" first to create a CAWS project');
|
|
840
|
+
process.exit(1);
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
console.log('✅ Found CAWS working spec');
|
|
844
|
+
|
|
845
|
+
// Initialize empty chain
|
|
846
|
+
const initialChain = [];
|
|
847
|
+
await saveProvenanceChain(initialChain, output);
|
|
848
|
+
console.log('✅ Initialized empty provenance chain');
|
|
849
|
+
|
|
850
|
+
// Create environment configuration hints
|
|
851
|
+
const envConfig = {
|
|
852
|
+
cursor_tracking_api: cursorApi || process.env.CURSOR_TRACKING_API || 'not_configured',
|
|
853
|
+
cursor_checkpoint_api: process.env.CURSOR_CHECKPOINT_API || 'not_configured',
|
|
854
|
+
cursor_project_id: process.env.CURSOR_PROJECT_ID || 'not_configured',
|
|
855
|
+
notes: [
|
|
856
|
+
'Configure CURSOR_TRACKING_API for AI code tracking',
|
|
857
|
+
'Configure CURSOR_CHECKPOINT_API for session recovery data',
|
|
858
|
+
'Configure CURSOR_PROJECT_ID to link with Cursor IDE',
|
|
859
|
+
],
|
|
860
|
+
};
|
|
861
|
+
|
|
862
|
+
await fs.writeFile(path.join(output, 'config.json'), JSON.stringify(envConfig, null, 2));
|
|
863
|
+
console.log('✅ Created configuration template');
|
|
864
|
+
|
|
865
|
+
console.log('');
|
|
866
|
+
console.log('🎉 Provenance tracking initialized!');
|
|
867
|
+
console.log('');
|
|
868
|
+
console.log('Next steps:');
|
|
869
|
+
console.log('1. Install git hooks for automatic provenance (recommended):');
|
|
870
|
+
console.log(' caws provenance install-hooks');
|
|
871
|
+
console.log('');
|
|
872
|
+
console.log('2. Configure environment variables (optional):');
|
|
873
|
+
console.log(' export CURSOR_TRACKING_API="your-api-endpoint"');
|
|
874
|
+
console.log(' export CURSOR_CHECKPOINT_API="your-checkpoint-endpoint"');
|
|
875
|
+
console.log(' export CURSOR_PROJECT_ID="your-project-id"');
|
|
876
|
+
console.log('');
|
|
877
|
+
console.log('3. Manual provenance updates (if not using hooks):');
|
|
878
|
+
console.log(' caws provenance update --commit <hash>');
|
|
879
|
+
console.log('');
|
|
880
|
+
console.log('4. View provenance history:');
|
|
881
|
+
console.log(' caws provenance show');
|
|
882
|
+
}
|
|
883
|
+
|
|
501
884
|
/**
|
|
502
885
|
* Get Cursor Composer/Chat checkpoint data
|
|
503
886
|
* @returns {Promise<Array>} Array of checkpoint data
|
|
@@ -591,4 +974,6 @@ module.exports = {
|
|
|
591
974
|
updateProvenance,
|
|
592
975
|
showProvenance,
|
|
593
976
|
verifyProvenance,
|
|
977
|
+
initProvenance,
|
|
978
|
+
installHooks,
|
|
594
979
|
};
|
|
@@ -17,41 +17,41 @@ const { validateWorkingSpec } = require('../validation/spec-validation');
|
|
|
17
17
|
*/
|
|
18
18
|
function generateWorkingSpec(answers) {
|
|
19
19
|
const template = {
|
|
20
|
-
id: answers.projectId,
|
|
21
|
-
title: answers.projectTitle,
|
|
22
|
-
risk_tier: answers.riskTier,
|
|
23
|
-
mode: answers.projectMode,
|
|
20
|
+
id: answers.projectId || 'PROJ-001',
|
|
21
|
+
title: answers.projectTitle || 'New CAWS Project',
|
|
22
|
+
risk_tier: answers.riskTier || 2,
|
|
23
|
+
mode: answers.projectMode || 'feature',
|
|
24
24
|
change_budget: {
|
|
25
|
-
max_files: answers.maxFiles,
|
|
26
|
-
max_loc: answers.maxLoc,
|
|
25
|
+
max_files: answers.maxFiles || 25,
|
|
26
|
+
max_loc: answers.maxLoc || 1000,
|
|
27
27
|
},
|
|
28
28
|
blast_radius: {
|
|
29
|
-
modules: answers.blastModules
|
|
29
|
+
modules: (answers.blastModules || 'src, tests')
|
|
30
30
|
.split(',')
|
|
31
31
|
.map((m) => m.trim())
|
|
32
32
|
.filter((m) => m),
|
|
33
|
-
data_migration: answers.dataMigration,
|
|
33
|
+
data_migration: answers.dataMigration ?? false,
|
|
34
34
|
},
|
|
35
|
-
operational_rollback_slo: answers.rollbackSlo,
|
|
35
|
+
operational_rollback_slo: answers.rollbackSlo || '5m',
|
|
36
36
|
threats: (answers.projectThreats || '')
|
|
37
37
|
.split('\n')
|
|
38
38
|
.map((t) => t.trim())
|
|
39
39
|
.filter((t) => t && !t.startsWith('-') === false), // Allow lines starting with -
|
|
40
40
|
scope: {
|
|
41
|
-
in: (answers.scopeIn || '')
|
|
41
|
+
in: (answers.scopeIn || 'src/, tests/')
|
|
42
42
|
.split(',')
|
|
43
43
|
.map((s) => s.trim())
|
|
44
44
|
.filter((s) => s),
|
|
45
|
-
out: (answers.scopeOut || '')
|
|
45
|
+
out: (answers.scopeOut || 'node_modules/, dist/')
|
|
46
46
|
.split(',')
|
|
47
47
|
.map((s) => s.trim())
|
|
48
48
|
.filter((s) => s),
|
|
49
49
|
},
|
|
50
|
-
invariants: (answers.projectInvariants || '')
|
|
50
|
+
invariants: (answers.projectInvariants || 'System maintains data consistency')
|
|
51
51
|
.split('\n')
|
|
52
52
|
.map((i) => i.trim())
|
|
53
53
|
.filter((i) => i),
|
|
54
|
-
acceptance: answers.acceptanceCriteria
|
|
54
|
+
acceptance: (answers.acceptanceCriteria || 'Given current state, when action occurs, then expected result')
|
|
55
55
|
.split('\n')
|
|
56
56
|
.filter((a) => a.trim())
|
|
57
57
|
.map((criteria, index) => {
|
|
@@ -87,32 +87,32 @@ function generateWorkingSpec(answers) {
|
|
|
87
87
|
};
|
|
88
88
|
}),
|
|
89
89
|
non_functional: {
|
|
90
|
-
a11y: answers.a11yRequirements
|
|
90
|
+
a11y: (answers.a11yRequirements || 'keyboard')
|
|
91
91
|
.split(',')
|
|
92
92
|
.map((a) => a.trim())
|
|
93
93
|
.filter((a) => a),
|
|
94
|
-
perf: { api_p95_ms: answers.perfBudget },
|
|
95
|
-
security: answers.securityRequirements
|
|
94
|
+
perf: { api_p95_ms: answers.perfBudget || 250 },
|
|
95
|
+
security: (answers.securityRequirements || 'validation')
|
|
96
96
|
.split(',')
|
|
97
97
|
.map((s) => s.trim())
|
|
98
98
|
.filter((s) => s),
|
|
99
99
|
},
|
|
100
100
|
contracts: [
|
|
101
101
|
{
|
|
102
|
-
type: answers.contractType,
|
|
103
|
-
path: answers.contractPath,
|
|
102
|
+
type: answers.contractType || '',
|
|
103
|
+
path: answers.contractPath || '',
|
|
104
104
|
},
|
|
105
105
|
],
|
|
106
106
|
observability: {
|
|
107
|
-
logs: answers.observabilityLogs
|
|
107
|
+
logs: (answers.observabilityLogs || '')
|
|
108
108
|
.split(',')
|
|
109
109
|
.map((l) => l.trim())
|
|
110
110
|
.filter((l) => l),
|
|
111
|
-
metrics: answers.observabilityMetrics
|
|
111
|
+
metrics: (answers.observabilityMetrics || '')
|
|
112
112
|
.split(',')
|
|
113
113
|
.map((m) => m.trim())
|
|
114
114
|
.filter((m) => m),
|
|
115
|
-
traces: answers.observabilityTraces
|
|
115
|
+
traces: (answers.observabilityTraces || '')
|
|
116
116
|
.split(',')
|
|
117
117
|
.map((t) => t.trim())
|
|
118
118
|
.filter((t) => t),
|
package/dist/index.js
CHANGED
|
@@ -34,6 +34,9 @@ const { executeTool } = require('./commands/tool');
|
|
|
34
34
|
// Import scaffold functionality
|
|
35
35
|
const { scaffoldProject, setScaffoldDependencies } = require('./scaffold');
|
|
36
36
|
|
|
37
|
+
// Import git hooks functionality
|
|
38
|
+
const { scaffoldGitHooks, removeGitHooks, checkGitHooksStatus } = require('./scaffold/git-hooks');
|
|
39
|
+
|
|
37
40
|
// Import validation functionality
|
|
38
41
|
// eslint-disable-next-line no-unused-vars
|
|
39
42
|
const { validateWorkingSpecWithSuggestions } = require('./validation/spec-validation');
|
|
@@ -115,17 +118,120 @@ program
|
|
|
115
118
|
.description('Statistical analysis for budget prediction and test optimization')
|
|
116
119
|
.action(testAnalysisCommand);
|
|
117
120
|
|
|
118
|
-
// Provenance command
|
|
119
|
-
program
|
|
121
|
+
// Provenance command group
|
|
122
|
+
const provenanceCmd = program
|
|
120
123
|
.command('provenance')
|
|
121
|
-
.description('Manage CAWS provenance tracking and audit trails')
|
|
122
|
-
|
|
123
|
-
|
|
124
|
+
.description('Manage CAWS provenance tracking and audit trails');
|
|
125
|
+
|
|
126
|
+
// Subcommands
|
|
127
|
+
provenanceCmd
|
|
128
|
+
.command('update')
|
|
129
|
+
.description('Add new commit to provenance chain')
|
|
130
|
+
.requiredOption('-c, --commit <hash>', 'Git commit hash')
|
|
124
131
|
.option('-m, --message <msg>', 'Commit message')
|
|
125
132
|
.option('-a, --author <info>', 'Author information')
|
|
126
133
|
.option('-q, --quiet', 'Suppress output')
|
|
127
|
-
.option('-o, --output <path>', 'Output path for provenance files')
|
|
128
|
-
.action(
|
|
134
|
+
.option('-o, --output <path>', 'Output path for provenance files', '.caws/provenance')
|
|
135
|
+
.action(async (options) => {
|
|
136
|
+
await provenanceCommand('update', options);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
provenanceCmd
|
|
140
|
+
.command('show')
|
|
141
|
+
.description('Display current provenance history')
|
|
142
|
+
.option('-o, --output <path>', 'Output path for provenance files', '.caws/provenance')
|
|
143
|
+
.option('--format <type>', 'Output format: text, json, dashboard', 'text')
|
|
144
|
+
.action(async (options) => {
|
|
145
|
+
await provenanceCommand('show', options);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
provenanceCmd
|
|
149
|
+
.command('verify')
|
|
150
|
+
.description('Validate provenance chain integrity')
|
|
151
|
+
.option('-o, --output <path>', 'Output path for provenance files', '.caws/provenance')
|
|
152
|
+
.action(async (options) => {
|
|
153
|
+
await provenanceCommand('verify', options);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
provenanceCmd
|
|
157
|
+
.command('analyze-ai')
|
|
158
|
+
.description('Analyze AI-assisted development patterns')
|
|
159
|
+
.option('-o, --output <path>', 'Output path for provenance files', '.caws/provenance')
|
|
160
|
+
.action(async (options) => {
|
|
161
|
+
await provenanceCommand('analyze-ai', options);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
provenanceCmd
|
|
165
|
+
.command('init')
|
|
166
|
+
.description('Initialize provenance tracking for the project')
|
|
167
|
+
.option('-o, --output <path>', 'Output path for provenance files', '.caws/provenance')
|
|
168
|
+
.option('--cursor-api <url>', 'Cursor tracking API endpoint')
|
|
169
|
+
.option('--cursor-key <key>', 'Cursor API key')
|
|
170
|
+
.action(async (options) => {
|
|
171
|
+
await provenanceCommand('init', options);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
// Git hooks command
|
|
175
|
+
const hooksCmd = program
|
|
176
|
+
.command('hooks')
|
|
177
|
+
.description('Manage CAWS git hooks for provenance tracking');
|
|
178
|
+
|
|
179
|
+
hooksCmd
|
|
180
|
+
.command('install')
|
|
181
|
+
.description('Install CAWS git hooks')
|
|
182
|
+
.option('--no-provenance', 'Skip provenance tracking hooks')
|
|
183
|
+
.option('--no-validation', 'Skip validation hooks')
|
|
184
|
+
.option('--no-quality-gates', 'Skip quality gate hooks')
|
|
185
|
+
.option('--force', 'Overwrite existing hooks')
|
|
186
|
+
.option('--backup', 'Backup existing hooks before replacing')
|
|
187
|
+
.action(async (options) => {
|
|
188
|
+
const hookOptions = {
|
|
189
|
+
provenance: options.provenance !== false,
|
|
190
|
+
validation: options.validation !== false,
|
|
191
|
+
qualityGates: options.qualityGates !== false,
|
|
192
|
+
force: options.force,
|
|
193
|
+
backup: options.backup,
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
try {
|
|
197
|
+
const result = await scaffoldGitHooks(process.cwd(), hookOptions);
|
|
198
|
+
if (result.added > 0) {
|
|
199
|
+
console.log(`✅ Successfully installed ${result.added} git hooks`);
|
|
200
|
+
if (result.skipped > 0) {
|
|
201
|
+
console.log(`⏭️ Skipped ${result.skipped} existing hooks`);
|
|
202
|
+
}
|
|
203
|
+
} else {
|
|
204
|
+
console.log('ℹ️ All hooks already configured');
|
|
205
|
+
}
|
|
206
|
+
} catch (error) {
|
|
207
|
+
console.error(`❌ Failed to install git hooks: ${error.message}`);
|
|
208
|
+
process.exit(1);
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
hooksCmd
|
|
213
|
+
.command('remove')
|
|
214
|
+
.description('Remove CAWS git hooks')
|
|
215
|
+
.action(async () => {
|
|
216
|
+
try {
|
|
217
|
+
await removeGitHooks(process.cwd());
|
|
218
|
+
} catch (error) {
|
|
219
|
+
console.error(`❌ Failed to remove git hooks: ${error.message}`);
|
|
220
|
+
process.exit(1);
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
hooksCmd
|
|
225
|
+
.command('status')
|
|
226
|
+
.description('Check git hooks status')
|
|
227
|
+
.action(async () => {
|
|
228
|
+
try {
|
|
229
|
+
await checkGitHooksStatus(process.cwd());
|
|
230
|
+
} catch (error) {
|
|
231
|
+
console.error(`❌ Failed to check git hooks status: ${error.message}`);
|
|
232
|
+
process.exit(1);
|
|
233
|
+
}
|
|
234
|
+
});
|
|
129
235
|
|
|
130
236
|
// Error handling
|
|
131
237
|
program.exitOverride((err) => {
|