@paths.design/caws-cli 3.1.1 → 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.
@@ -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,+BAuBhB;AAED;;;GAGG;AACH,8DA4EC;AAED;;;GAGG;AACH,4DAsDC;AAED;;;GAGG;AACH,8DA8CC"}
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
- console.log('ℹ️ No provenance data found');
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
  };
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
- .argument('<subcommand>', 'Command: update, show, verify, analyze-ai')
123
- .option('-c, --commit <hash>', 'Git commit hash')
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(provenanceCommand);
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) => {
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Scaffold git hooks for CAWS provenance tracking
3
+ * @param {string} projectDir - Project directory path
4
+ * @param {Object} options - Hook options
5
+ */
6
+ export function scaffoldGitHooks(projectDir: string, options?: any): Promise<{
7
+ added: number;
8
+ skipped: number;
9
+ }>;
10
+ /**
11
+ * Remove CAWS git hooks
12
+ * @param {string} projectDir - Project directory path
13
+ */
14
+ export function removeGitHooks(projectDir: string): Promise<void>;
15
+ /**
16
+ * Check git hooks status
17
+ * @param {string} projectDir - Project directory path
18
+ */
19
+ export function checkGitHooksStatus(projectDir: string): Promise<void>;
20
+ //# sourceMappingURL=git-hooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-hooks.d.ts","sourceRoot":"","sources":["../../src/scaffold/git-hooks.js"],"names":[],"mappings":"AASA;;;;GAIG;AACH,6CAHW,MAAM;;;GAuGhB;AAgND;;;GAGG;AACH,2CAFW,MAAM,iBAkChB;AAED;;;GAGG;AACH,gDAFW,MAAM,iBAgDhB"}