@paths.design/caws-cli 7.0.3 → 8.0.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/dist/commands/quality-gates.js +147 -9
- package/dist/commands/specs.js +108 -13
- package/dist/commands/tool.js +0 -1
- package/dist/scaffold/git-hooks.js +159 -58
- package/dist/scaffold/index.js +1 -1
- package/dist/templates/.caws/tools/README.md +1 -0
- package/dist/utils/git-lock.js +1 -0
- package/dist/utils/project-analysis.js +176 -16
- package/dist/utils/quality-gates.js +7 -6
- package/dist/utils/spec-resolver.js +4 -0
- package/dist/utils/yaml-validation.js +1 -0
- package/package.json +1 -1
- package/templates/.caws/tools/README.md +1 -0
- package/dist/budget-derivation.d.ts +0 -74
- package/dist/budget-derivation.d.ts.map +0 -1
- package/dist/cicd-optimizer.d.ts +0 -142
- package/dist/cicd-optimizer.d.ts.map +0 -1
- package/dist/commands/archive.d.ts +0 -50
- package/dist/commands/archive.d.ts.map +0 -1
- package/dist/commands/burnup.d.ts +0 -6
- package/dist/commands/burnup.d.ts.map +0 -1
- package/dist/commands/diagnose.d.ts +0 -52
- package/dist/commands/diagnose.d.ts.map +0 -1
- package/dist/commands/evaluate.d.ts +0 -8
- package/dist/commands/evaluate.d.ts.map +0 -1
- package/dist/commands/init.d.ts +0 -5
- package/dist/commands/init.d.ts.map +0 -1
- package/dist/commands/iterate.d.ts +0 -8
- package/dist/commands/iterate.d.ts.map +0 -1
- package/dist/commands/mode.d.ts +0 -24
- package/dist/commands/mode.d.ts.map +0 -1
- package/dist/commands/plan.d.ts +0 -49
- package/dist/commands/plan.d.ts.map +0 -1
- package/dist/commands/provenance.d.ts +0 -32
- package/dist/commands/provenance.d.ts.map +0 -1
- package/dist/commands/quality-gates.d.ts +0 -52
- package/dist/commands/quality-gates.d.ts.map +0 -1
- package/dist/commands/quality-monitor.d.ts +0 -17
- package/dist/commands/quality-monitor.d.ts.map +0 -1
- package/dist/commands/specs.d.ts +0 -71
- package/dist/commands/specs.d.ts.map +0 -1
- package/dist/commands/status.d.ts +0 -44
- package/dist/commands/status.d.ts.map +0 -1
- package/dist/commands/templates.d.ts +0 -74
- package/dist/commands/templates.d.ts.map +0 -1
- package/dist/commands/tool.d.ts +0 -13
- package/dist/commands/tool.d.ts.map +0 -1
- package/dist/commands/troubleshoot.d.ts +0 -8
- package/dist/commands/troubleshoot.d.ts.map +0 -1
- package/dist/commands/tutorial.d.ts +0 -55
- package/dist/commands/tutorial.d.ts.map +0 -1
- package/dist/commands/validate.d.ts +0 -15
- package/dist/commands/validate.d.ts.map +0 -1
- package/dist/commands/waivers.d.ts +0 -8
- package/dist/commands/waivers.d.ts.map +0 -1
- package/dist/commands/workflow.d.ts +0 -85
- package/dist/commands/workflow.d.ts.map +0 -1
- package/dist/config/index.d.ts +0 -29
- package/dist/config/index.d.ts.map +0 -1
- package/dist/config/modes.d.ts +0 -225
- package/dist/config/modes.d.ts.map +0 -1
- package/dist/constants/spec-types.d.ts +0 -41
- package/dist/constants/spec-types.d.ts.map +0 -1
- package/dist/error-handler.d.ts +0 -164
- package/dist/error-handler.d.ts.map +0 -1
- package/dist/generators/jest-config.d.ts +0 -32
- package/dist/generators/jest-config.d.ts.map +0 -1
- package/dist/generators/working-spec.d.ts +0 -13
- package/dist/generators/working-spec.d.ts.map +0 -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.d.ts +0 -5
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.backup +0 -4711
- package/dist/minimal-cli.d.ts +0 -3
- package/dist/minimal-cli.d.ts.map +0 -1
- package/dist/policy/PolicyManager.d.ts +0 -104
- package/dist/policy/PolicyManager.d.ts.map +0 -1
- package/dist/scaffold/cursor-hooks.d.ts +0 -7
- package/dist/scaffold/cursor-hooks.d.ts.map +0 -1
- package/dist/scaffold/git-hooks.d.ts +0 -20
- package/dist/scaffold/git-hooks.d.ts.map +0 -1
- package/dist/scaffold/index.d.ts +0 -20
- package/dist/scaffold/index.d.ts.map +0 -1
- package/dist/spec/SpecFileManager.d.ts +0 -146
- package/dist/spec/SpecFileManager.d.ts.map +0 -1
- package/dist/test-analysis.d.ts +0 -182
- package/dist/test-analysis.d.ts.map +0 -1
- package/dist/tool-interface.d.ts +0 -236
- package/dist/tool-interface.d.ts.map +0 -1
- package/dist/tool-loader.d.ts +0 -77
- package/dist/tool-loader.d.ts.map +0 -1
- package/dist/tool-validator.d.ts +0 -72
- package/dist/tool-validator.d.ts.map +0 -1
- package/dist/utils/detection.d.ts +0 -7
- package/dist/utils/detection.d.ts.map +0 -1
- package/dist/utils/finalization.d.ts +0 -17
- package/dist/utils/finalization.d.ts.map +0 -1
- package/dist/utils/project-analysis.d.ts +0 -14
- package/dist/utils/project-analysis.d.ts.map +0 -1
- package/dist/utils/quality-gates.d.ts +0 -49
- package/dist/utils/quality-gates.d.ts.map +0 -1
- package/dist/utils/spec-resolver.d.ts +0 -88
- package/dist/utils/spec-resolver.d.ts.map +0 -1
- package/dist/utils/typescript-detector.d.ts +0 -63
- package/dist/utils/typescript-detector.d.ts.map +0 -1
- package/dist/validation/spec-validation.d.ts +0 -43
- package/dist/validation/spec-validation.d.ts.map +0 -1
- package/dist/waivers-manager.d.ts +0 -167
- package/dist/waivers-manager.d.ts.map +0 -1
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
const fs = require('fs-extra');
|
|
8
8
|
const path = require('path');
|
|
9
|
+
const { getTodoAnalyzerSuggestion } = require('../utils/project-analysis');
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Scaffold git hooks for CAWS provenance tracking
|
|
@@ -39,7 +40,7 @@ async function scaffoldGitHooks(projectDir, options = {}) {
|
|
|
39
40
|
name: 'pre-commit',
|
|
40
41
|
description: 'Pre-commit validation and quality checks',
|
|
41
42
|
enabled: validation || qualityGates,
|
|
42
|
-
content: generatePreCommitHook({ validation, qualityGates }),
|
|
43
|
+
content: generatePreCommitHook({ validation, qualityGates, projectDir }),
|
|
43
44
|
},
|
|
44
45
|
{
|
|
45
46
|
name: 'post-commit',
|
|
@@ -120,7 +121,10 @@ async function scaffoldGitHooks(projectDir, options = {}) {
|
|
|
120
121
|
* Implements fallback chain: Node script → CLI → Python scripts → Skip gracefully
|
|
121
122
|
*/
|
|
122
123
|
function generatePreCommitHook(options) {
|
|
123
|
-
const { qualityGates = true, stagedOnly = true } = options;
|
|
124
|
+
const { qualityGates = true, stagedOnly = true, projectDir = process.cwd() } = options;
|
|
125
|
+
|
|
126
|
+
// Get language-agnostic suggestions based on runtime availability
|
|
127
|
+
const todoSuggestion = getTodoAnalyzerSuggestion(projectDir);
|
|
124
128
|
|
|
125
129
|
return `#!/bin/bash
|
|
126
130
|
# CAWS Pre-commit Hook
|
|
@@ -144,13 +148,13 @@ if [ -f ".git/index.lock" ]; then
|
|
|
144
148
|
LOCK_AGE_MINUTES=$((LOCK_AGE / 60))
|
|
145
149
|
|
|
146
150
|
if [ $LOCK_AGE_MINUTES -gt 5 ]; then
|
|
147
|
-
echo "⚠️ Stale git lock detected (
|
|
151
|
+
echo "⚠️ Stale git lock detected (\${LOCK_AGE_MINUTES} minutes old)"
|
|
148
152
|
echo "💡 This may indicate a crashed git process"
|
|
149
153
|
echo "💡 Remove stale lock: rm .git/index.lock"
|
|
150
154
|
echo "⚠️ Warning: Check for running git/editor processes before removing"
|
|
151
155
|
exit 1
|
|
152
156
|
else
|
|
153
|
-
echo "⚠️ Git lock detected (
|
|
157
|
+
echo "⚠️ Git lock detected (\${LOCK_AGE_MINUTES} minutes old)"
|
|
154
158
|
echo "💡 Another git process may be running"
|
|
155
159
|
echo "💡 Wait for the other process to complete, or check for running processes"
|
|
156
160
|
exit 1
|
|
@@ -162,7 +166,7 @@ echo "🔍 Validating YAML syntax for CAWS spec files..."
|
|
|
162
166
|
YAML_VALIDATION_FAILED=false
|
|
163
167
|
|
|
164
168
|
# Find all staged .yaml/.yml files in .caws directory
|
|
165
|
-
STAGED_YAML_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep -E '
|
|
169
|
+
STAGED_YAML_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\\.caws/.*\\.(yaml|yml)$' || true)
|
|
166
170
|
|
|
167
171
|
if [ -n "$STAGED_YAML_FILES" ]; then
|
|
168
172
|
# Use Node.js to validate YAML if available
|
|
@@ -326,42 +330,49 @@ fi
|
|
|
326
330
|
if [ "$QUALITY_GATES_RAN" = true ]; then
|
|
327
331
|
echo "🔍 Checking for hidden TODOs in staged files..."
|
|
328
332
|
|
|
329
|
-
|
|
330
|
-
TODO_ANALYZER=""
|
|
333
|
+
TODO_CHECK_RAN=false
|
|
331
334
|
|
|
332
|
-
#
|
|
333
|
-
if [
|
|
334
|
-
TODO_ANALYZER="
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
335
|
+
# Option 1: Find TODO analyzer .mjs file (if installed locally)
|
|
336
|
+
if [ "$TODO_CHECK_RAN" = false ]; then
|
|
337
|
+
TODO_ANALYZER=""
|
|
338
|
+
|
|
339
|
+
# Try quality gates package TODO analyzer (published package)
|
|
340
|
+
if [ -f "node_modules/@paths.design/quality-gates/todo-analyzer.mjs" ]; then
|
|
341
|
+
TODO_ANALYZER="node_modules/@paths.design/quality-gates/todo-analyzer.mjs"
|
|
342
|
+
# Try quality gates package TODO analyzer (monorepo/local copy)
|
|
343
|
+
elif [ -f "node_modules/@caws/quality-gates/todo-analyzer.mjs" ]; then
|
|
344
|
+
TODO_ANALYZER="node_modules/@caws/quality-gates/todo-analyzer.mjs"
|
|
345
|
+
# Try monorepo structure (development)
|
|
346
|
+
elif [ -f "packages/quality-gates/todo-analyzer.mjs" ]; then
|
|
347
|
+
TODO_ANALYZER="packages/quality-gates/todo-analyzer.mjs"
|
|
348
|
+
# Try local copy in scripts directory (if scaffolded)
|
|
349
|
+
elif [ -f "scripts/todo-analyzer.mjs" ]; then
|
|
350
|
+
TODO_ANALYZER="scripts/todo-analyzer.mjs"
|
|
351
|
+
fi
|
|
352
|
+
|
|
353
|
+
# Run TODO analyzer if found
|
|
354
|
+
if [ -n "$TODO_ANALYZER" ] && command -v node >/dev/null 2>&1; then
|
|
355
|
+
if node "$TODO_ANALYZER" --staged-only --ci-mode --min-confidence 0.8 >/dev/null 2>&1; then
|
|
356
|
+
echo "✅ No critical hidden TODOs found in staged files"
|
|
357
|
+
TODO_CHECK_RAN=true
|
|
358
|
+
else
|
|
359
|
+
echo "❌ Critical hidden TODOs detected in staged files - commit blocked"
|
|
360
|
+
echo "💡 Fix stub implementations and placeholder code before committing"
|
|
361
|
+
echo "📖 See docs/PLACEHOLDER-DETECTION-GUIDE.md for classification"
|
|
362
|
+
echo ""
|
|
363
|
+
echo "🔍 Running detailed analysis on staged files..."
|
|
364
|
+
node "$TODO_ANALYZER" --staged-only --min-confidence 0.8
|
|
365
|
+
exit 1
|
|
366
|
+
fi
|
|
367
|
+
fi
|
|
344
368
|
fi
|
|
345
369
|
|
|
346
|
-
#
|
|
347
|
-
if [
|
|
348
|
-
if node "$TODO_ANALYZER" --staged-only --ci-mode --min-confidence 0.8 >/dev/null 2>&1; then
|
|
349
|
-
echo "✅ No critical hidden TODOs found in staged files"
|
|
350
|
-
else
|
|
351
|
-
echo "❌ Critical hidden TODOs detected in staged files - commit blocked"
|
|
352
|
-
echo "💡 Fix stub implementations and placeholder code before committing"
|
|
353
|
-
echo "📖 See docs/PLACEHOLDER-DETECTION-GUIDE.md for classification"
|
|
354
|
-
echo ""
|
|
355
|
-
echo "🔍 Running detailed analysis on staged files..."
|
|
356
|
-
node "$TODO_ANALYZER" --staged-only --min-confidence 0.8
|
|
357
|
-
exit 1
|
|
358
|
-
fi
|
|
359
|
-
# Fallback to legacy Python analyzer (deprecated - will be removed)
|
|
360
|
-
elif command -v python3 >/dev/null 2>&1 && [ -f "scripts/v3/analysis/todo_analyzer.py" ]; then
|
|
370
|
+
# Option 2: Fallback to legacy Python analyzer (deprecated - will be removed)
|
|
371
|
+
if [ "$TODO_CHECK_RAN" = false ] && command -v python3 >/dev/null 2>&1 && [ -f "scripts/v3/analysis/todo_analyzer.py" ]; then
|
|
361
372
|
echo "⚠️ Using legacy Python TODO analyzer (deprecated)"
|
|
362
|
-
echo "💡 Install @paths.design/quality-gates for Node.js version: npm install --save-dev @paths.design/quality-gates"
|
|
363
373
|
if python3 scripts/v3/analysis/todo_analyzer.py --staged-only --ci-mode --min-confidence 0.8 >/dev/null 2>&1; then
|
|
364
374
|
echo "✅ No critical hidden TODOs found in staged files"
|
|
375
|
+
TODO_CHECK_RAN=true
|
|
365
376
|
else
|
|
366
377
|
echo "❌ Critical hidden TODOs detected in staged files - commit blocked"
|
|
367
378
|
echo "💡 Fix stub implementations and placeholder code before committing"
|
|
@@ -371,9 +382,16 @@ if [ "$QUALITY_GATES_RAN" = true ]; then
|
|
|
371
382
|
python3 scripts/v3/analysis/todo_analyzer.py --staged-only --min-confidence 0.8
|
|
372
383
|
exit 1
|
|
373
384
|
fi
|
|
374
|
-
|
|
385
|
+
fi
|
|
386
|
+
|
|
387
|
+
# Option 3: No analyzer available - show language-aware suggestions
|
|
388
|
+
if [ "$TODO_CHECK_RAN" = false ]; then
|
|
375
389
|
echo "⚠️ TODO analyzer not available - skipping hidden TODO check"
|
|
376
|
-
echo "💡
|
|
390
|
+
echo "💡 Available options for TODO analysis:"
|
|
391
|
+
${todoSuggestion
|
|
392
|
+
.split('\n')
|
|
393
|
+
.map((line) => ` echo "${line.replace(/"/g, '\\"')}"`)
|
|
394
|
+
.join('\n')}
|
|
377
395
|
fi
|
|
378
396
|
fi
|
|
379
397
|
|
|
@@ -444,8 +462,8 @@ for arg in "$@"; do
|
|
|
444
462
|
echo "💡 To fix issues locally:"
|
|
445
463
|
echo " 1. Run: caws validate"
|
|
446
464
|
echo " 2. Fix reported issues"
|
|
447
|
-
echo " 3. Commit fixes: git commit --no-verify (allowed)"
|
|
448
|
-
echo " 4. Push again: git push (no --no-verify)"
|
|
465
|
+
echo " 3. Commit fixes: git commit --no-verify \\(allowed\\)"
|
|
466
|
+
echo " 4. Push again: git push \\(no --no-verify\\)"
|
|
449
467
|
exit 1
|
|
450
468
|
fi
|
|
451
469
|
done
|
|
@@ -508,13 +526,13 @@ if command -v caws >/dev/null 2>&1; then
|
|
|
508
526
|
echo " No active waivers found"
|
|
509
527
|
echo ""
|
|
510
528
|
echo "💡 If this is infrastructure/setup work, you can create a waiver:"
|
|
511
|
-
echo " caws waivers create
|
|
512
|
-
echo " --title='Initial CAWS setup'
|
|
513
|
-
echo " --reason=infrastructure_limitation
|
|
514
|
-
echo " --gates=contracts
|
|
515
|
-
echo " --expires-at='2024-12-31T23:59:59Z'
|
|
516
|
-
echo " --approved-by='@your-team'
|
|
517
|
-
echo " --impact-level=low
|
|
529
|
+
echo " caws waivers create \\\\"
|
|
530
|
+
echo " --title='Initial CAWS setup' \\\\"
|
|
531
|
+
echo " --reason=infrastructure_limitation \\\\"
|
|
532
|
+
echo " --gates=contracts \\\\"
|
|
533
|
+
echo " --expires-at='2024-12-31T23:59:59Z' \\\\"
|
|
534
|
+
echo " --approved-by='@your-team' \\\\"
|
|
535
|
+
echo " --impact-level=low \\\\"
|
|
518
536
|
echo " --mitigation-plan='Contracts will be added as features are developed'"
|
|
519
537
|
fi
|
|
520
538
|
|
|
@@ -523,43 +541,121 @@ if command -v caws >/dev/null 2>&1; then
|
|
|
523
541
|
echo "Next Steps:"
|
|
524
542
|
echo " 1. Review errors above"
|
|
525
543
|
echo " 2. Fix issues in .caws/working-spec.yaml"
|
|
526
|
-
echo " 3. Run: caws validate (to verify fixes)"
|
|
527
|
-
echo " 4. Commit fixes: git commit --no-verify (allowed)"
|
|
544
|
+
echo " 3. Run: caws validate \\(to verify fixes\\)"
|
|
545
|
+
echo " 4. Commit fixes: git commit --no-verify \\(allowed\\)"
|
|
528
546
|
echo " 5. Push again: git push"
|
|
529
547
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
530
548
|
exit 1
|
|
531
549
|
fi
|
|
532
550
|
fi
|
|
533
551
|
|
|
534
|
-
# Run
|
|
552
|
+
# Run full pre-push checks (full test suite required before push)
|
|
553
|
+
# Note: Pre-commit uses filtered tests for speed, but push requires full suite
|
|
554
|
+
echo ""
|
|
555
|
+
echo "⚡ Running full pre-push checks (full test suite required)..."
|
|
556
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
557
|
+
|
|
558
|
+
QUICK_CHECKS_FAILED=false
|
|
559
|
+
|
|
560
|
+
# 1. Linting (fast)
|
|
561
|
+
if [ -f "package.json" ]; then
|
|
562
|
+
if command -v npm >/dev/null 2>&1; then
|
|
563
|
+
if grep -q '"lint"' package.json; then
|
|
564
|
+
echo "🔍 Running linting..."
|
|
565
|
+
if npm run lint >/dev/null 2>&1; then
|
|
566
|
+
echo "✅ Linting passed"
|
|
567
|
+
else
|
|
568
|
+
echo "❌ Linting failed"
|
|
569
|
+
echo "💡 Fix lint errors: npm run lint"
|
|
570
|
+
QUICK_CHECKS_FAILED=true
|
|
571
|
+
fi
|
|
572
|
+
fi
|
|
573
|
+
fi
|
|
574
|
+
fi
|
|
575
|
+
|
|
576
|
+
# 2. Type checking (fast for TypeScript/JavaScript)
|
|
577
|
+
if [ -f "package.json" ]; then
|
|
578
|
+
if command -v npm >/dev/null 2>&1; then
|
|
579
|
+
if grep -q '"typecheck"' package.json; then
|
|
580
|
+
echo "🔍 Running type checking..."
|
|
581
|
+
if npm run typecheck >/dev/null 2>&1; then
|
|
582
|
+
echo "✅ Type checking passed"
|
|
583
|
+
else
|
|
584
|
+
echo "❌ Type checking failed"
|
|
585
|
+
echo "💡 Fix type errors: npm run typecheck"
|
|
586
|
+
QUICK_CHECKS_FAILED=true
|
|
587
|
+
fi
|
|
588
|
+
fi
|
|
589
|
+
fi
|
|
590
|
+
fi
|
|
591
|
+
|
|
592
|
+
# 3. Run FULL test suite (required for push) - no filtering
|
|
593
|
+
# Pre-commit uses filtered tests for speed, but push requires full suite
|
|
594
|
+
if [ -f "package.json" ]; then
|
|
595
|
+
if command -v npm >/dev/null 2>&1 && grep -q '"test"' package.json; then
|
|
596
|
+
echo "🧪 Running FULL test suite (required for push)..."
|
|
597
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
598
|
+
if npm test 2>&1 | tee /tmp/pre-push-test-full.log; then
|
|
599
|
+
echo "✅ Full test suite passed"
|
|
600
|
+
rm -f /tmp/pre-push-test-full.log
|
|
601
|
+
else
|
|
602
|
+
FULL_TEST_EXIT_CODE=\${PIPESTATUS[0]}
|
|
603
|
+
echo "❌ Full test suite failed (exit code: \${FULL_TEST_EXIT_CODE})"
|
|
604
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
605
|
+
echo "Test output (last 100 lines):"
|
|
606
|
+
tail -100 /tmp/pre-push-test-full.log 2>/dev/null || echo "No test output captured"
|
|
607
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
608
|
+
echo "💡 Fix test failures before pushing: npm test"
|
|
609
|
+
rm -f /tmp/pre-push-test-full.log
|
|
610
|
+
QUICK_CHECKS_FAILED=true
|
|
611
|
+
fi
|
|
612
|
+
fi
|
|
613
|
+
fi
|
|
614
|
+
|
|
615
|
+
# 4. Security checks (non-blocking warnings)
|
|
616
|
+
echo ""
|
|
535
617
|
echo "🔒 Running security checks..."
|
|
536
618
|
if [ -f "package.json" ]; then
|
|
537
|
-
# Check for vulnerabilities
|
|
538
619
|
if command -v npm >/dev/null 2>&1; then
|
|
539
620
|
echo "🔍 Checking for vulnerabilities..."
|
|
540
621
|
if npm audit --audit-level moderate >/dev/null 2>&1; then
|
|
541
622
|
echo "✅ Security audit passed"
|
|
542
623
|
else
|
|
543
|
-
echo "⚠️ Security vulnerabilities found"
|
|
624
|
+
echo "⚠️ Security vulnerabilities found (non-blocking)"
|
|
544
625
|
echo "💡 Review with: npm audit"
|
|
545
|
-
# Don't fail on warnings, just warn
|
|
546
626
|
fi
|
|
547
627
|
fi
|
|
548
628
|
elif [ -f "requirements.txt" ] || [ -f "pyproject.toml" ]; then
|
|
549
|
-
# Python project security checks
|
|
550
629
|
if command -v pip-audit >/dev/null 2>&1; then
|
|
551
630
|
echo "🔍 Checking Python vulnerabilities..."
|
|
552
|
-
pip-audit --desc 2>/dev/null || echo "⚠️ Install pip-audit
|
|
631
|
+
pip-audit --desc 2>/dev/null || echo "⚠️ Install pip-audit: pip install pip-audit"
|
|
553
632
|
fi
|
|
554
633
|
elif [ -f "Cargo.toml" ]; then
|
|
555
|
-
# Rust project security checks
|
|
556
634
|
if command -v cargo-audit >/dev/null 2>&1; then
|
|
557
635
|
echo "🔍 Checking Rust vulnerabilities..."
|
|
558
|
-
cargo audit 2>/dev/null || echo "⚠️ Install cargo-audit
|
|
636
|
+
cargo audit 2>/dev/null || echo "⚠️ Install cargo-audit: cargo install cargo-audit"
|
|
559
637
|
fi
|
|
560
638
|
fi
|
|
561
639
|
|
|
562
|
-
|
|
640
|
+
# Fail if any checks failed
|
|
641
|
+
if [ "$QUICK_CHECKS_FAILED" = true ]; then
|
|
642
|
+
echo ""
|
|
643
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
644
|
+
echo "❌ Pre-push checks failed"
|
|
645
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
646
|
+
echo "All checks (linting/type checking/full test suite) must pass before push."
|
|
647
|
+
echo ""
|
|
648
|
+
echo "💡 Fix failures before pushing:"
|
|
649
|
+
echo " - Linting: npm run lint"
|
|
650
|
+
echo " - Type checking: npm run typecheck"
|
|
651
|
+
echo " - Tests: npm test"
|
|
652
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
653
|
+
exit 1
|
|
654
|
+
fi
|
|
655
|
+
|
|
656
|
+
echo ""
|
|
657
|
+
echo "✅ Pre-push checks completed!"
|
|
658
|
+
echo "💡 All quality gates passed - ready to push"
|
|
563
659
|
`;
|
|
564
660
|
}
|
|
565
661
|
|
|
@@ -583,7 +679,7 @@ fi
|
|
|
583
679
|
|
|
584
680
|
# Basic commit message validation
|
|
585
681
|
if [ \${#COMMIT_MSG} -lt 10 ]; then
|
|
586
|
-
echo "❌ Commit message too short (minimum 10 characters)"
|
|
682
|
+
echo "❌ Commit message too short \\(minimum 10 characters\\)"
|
|
587
683
|
echo "💡 Write descriptive commit messages"
|
|
588
684
|
exit 1
|
|
589
685
|
fi
|
|
@@ -700,4 +796,9 @@ module.exports = {
|
|
|
700
796
|
scaffoldGitHooks,
|
|
701
797
|
removeGitHooks,
|
|
702
798
|
checkGitHooksStatus,
|
|
799
|
+
// Export generator functions for testing
|
|
800
|
+
generatePrePushHook,
|
|
801
|
+
generatePreCommitHook,
|
|
802
|
+
generatePostCommitHook,
|
|
803
|
+
generateCommitMsgHook,
|
|
703
804
|
};
|
package/dist/scaffold/index.js
CHANGED
|
@@ -735,7 +735,7 @@ async function scaffoldProject(options) {
|
|
|
735
735
|
}
|
|
736
736
|
|
|
737
737
|
// Update .gitignore to exclude CAWS local runtime files
|
|
738
|
-
const gitignoreUpdated = await updateGitignore(
|
|
738
|
+
const gitignoreUpdated = await updateGitignore(currentDir);
|
|
739
739
|
if (gitignoreUpdated) {
|
|
740
740
|
console.log(chalk.green('\n✅ Updated .gitignore to exclude CAWS local runtime files'));
|
|
741
741
|
console.log(
|
package/dist/utils/git-lock.js
CHANGED
|
@@ -111,9 +111,7 @@ function detectsPublishing(cwd = process.cwd()) {
|
|
|
111
111
|
// Check package.json for npm publishing
|
|
112
112
|
if (files.includes('package.json')) {
|
|
113
113
|
try {
|
|
114
|
-
const packageJson = JSON.parse(
|
|
115
|
-
fs.readFileSync(path.join(cwd, 'package.json'), 'utf8')
|
|
116
|
-
);
|
|
114
|
+
const packageJson = JSON.parse(fs.readFileSync(path.join(cwd, 'package.json'), 'utf8'));
|
|
117
115
|
|
|
118
116
|
// Indicators of publishing:
|
|
119
117
|
// - Has publishConfig
|
|
@@ -123,9 +121,7 @@ function detectsPublishing(cwd = process.cwd()) {
|
|
|
123
121
|
const hasPublishConfig = packageJson.publishConfig;
|
|
124
122
|
const hasPublishScript =
|
|
125
123
|
packageJson.scripts &&
|
|
126
|
-
Object.keys(packageJson.scripts).some((key) =>
|
|
127
|
-
key.toLowerCase().includes('publish')
|
|
128
|
-
);
|
|
124
|
+
Object.keys(packageJson.scripts).some((key) => key.toLowerCase().includes('publish'));
|
|
129
125
|
const hasScopedName = packageJson.name && packageJson.name.startsWith('@');
|
|
130
126
|
const hasRepository = packageJson.repository;
|
|
131
127
|
|
|
@@ -140,16 +136,13 @@ function detectsPublishing(cwd = process.cwd()) {
|
|
|
140
136
|
// Check pyproject.toml for PyPI publishing
|
|
141
137
|
if (files.includes('pyproject.toml')) {
|
|
142
138
|
try {
|
|
143
|
-
const pyprojectContent = fs.readFileSync(
|
|
144
|
-
path.join(cwd, 'pyproject.toml'),
|
|
145
|
-
'utf8'
|
|
146
|
-
);
|
|
139
|
+
const pyprojectContent = fs.readFileSync(path.join(cwd, 'pyproject.toml'), 'utf8');
|
|
147
140
|
|
|
148
141
|
// Check for build system and project metadata (indicates publishable package)
|
|
149
142
|
const hasBuildSystem = pyprojectContent.includes('[build-system]');
|
|
150
143
|
const hasProjectMetadata = pyprojectContent.includes('[project]');
|
|
151
|
-
const hasToolPublish =
|
|
152
|
-
|
|
144
|
+
const hasToolPublish =
|
|
145
|
+
pyprojectContent.includes('[tool.publish]') || pyprojectContent.includes('[tool.twine]');
|
|
153
146
|
|
|
154
147
|
if ((hasBuildSystem && hasProjectMetadata) || hasToolPublish) {
|
|
155
148
|
return true;
|
|
@@ -177,10 +170,7 @@ function detectsPublishing(cwd = process.cwd()) {
|
|
|
177
170
|
const workflowFiles = fs.readdirSync(workflowsPath);
|
|
178
171
|
for (const workflowFile of workflowFiles) {
|
|
179
172
|
if (workflowFile.endsWith('.yml') || workflowFile.endsWith('.yaml')) {
|
|
180
|
-
const workflowContent = fs.readFileSync(
|
|
181
|
-
path.join(workflowsPath, workflowFile),
|
|
182
|
-
'utf8'
|
|
183
|
-
);
|
|
173
|
+
const workflowContent = fs.readFileSync(path.join(workflowsPath, workflowFile), 'utf8');
|
|
184
174
|
// Check for common publishing actions/commands
|
|
185
175
|
if (
|
|
186
176
|
workflowContent.includes('npm publish') ||
|
|
@@ -201,8 +191,178 @@ function detectsPublishing(cwd = process.cwd()) {
|
|
|
201
191
|
return false;
|
|
202
192
|
}
|
|
203
193
|
|
|
194
|
+
/**
|
|
195
|
+
* Detect primary programming language(s) used in project
|
|
196
|
+
* @param {string} cwd - Current working directory
|
|
197
|
+
* @returns {Object} Language detection result with primary language and indicators
|
|
198
|
+
*/
|
|
199
|
+
function detectProjectLanguage(cwd = process.cwd()) {
|
|
200
|
+
const files = fs.readdirSync(cwd);
|
|
201
|
+
const indicators = {
|
|
202
|
+
javascript: false,
|
|
203
|
+
typescript: false,
|
|
204
|
+
python: false,
|
|
205
|
+
rust: false,
|
|
206
|
+
go: false,
|
|
207
|
+
java: false,
|
|
208
|
+
csharp: false,
|
|
209
|
+
php: false,
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
// JavaScript/TypeScript indicators
|
|
213
|
+
if (files.includes('package.json')) {
|
|
214
|
+
indicators.javascript = true;
|
|
215
|
+
try {
|
|
216
|
+
const packageJson = JSON.parse(fs.readFileSync(path.join(cwd, 'package.json'), 'utf8'));
|
|
217
|
+
const allDeps = {
|
|
218
|
+
...(packageJson.dependencies || {}),
|
|
219
|
+
...(packageJson.devDependencies || {}),
|
|
220
|
+
};
|
|
221
|
+
if ('typescript' in allDeps || files.includes('tsconfig.json')) {
|
|
222
|
+
indicators.typescript = true;
|
|
223
|
+
indicators.javascript = false; // TypeScript supersedes JavaScript
|
|
224
|
+
}
|
|
225
|
+
} catch (e) {
|
|
226
|
+
// Ignore parse errors
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Python indicators
|
|
231
|
+
if (
|
|
232
|
+
files.includes('requirements.txt') ||
|
|
233
|
+
files.includes('pyproject.toml') ||
|
|
234
|
+
files.includes('setup.py') ||
|
|
235
|
+
files.includes('Pipfile') ||
|
|
236
|
+
files.includes('poetry.lock') ||
|
|
237
|
+
files.some((f) => f.endsWith('.py'))
|
|
238
|
+
) {
|
|
239
|
+
indicators.python = true;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Rust indicators
|
|
243
|
+
if (files.includes('Cargo.toml') || files.some((f) => f.endsWith('.rs'))) {
|
|
244
|
+
indicators.rust = true;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Go indicators
|
|
248
|
+
if (
|
|
249
|
+
files.includes('go.mod') ||
|
|
250
|
+
files.includes('go.sum') ||
|
|
251
|
+
files.some((f) => f.endsWith('.go'))
|
|
252
|
+
) {
|
|
253
|
+
indicators.go = true;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Java indicators
|
|
257
|
+
if (
|
|
258
|
+
files.includes('pom.xml') ||
|
|
259
|
+
files.includes('build.gradle') ||
|
|
260
|
+
files.some((f) => f.endsWith('.java'))
|
|
261
|
+
) {
|
|
262
|
+
indicators.java = true;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// C# indicators
|
|
266
|
+
if (
|
|
267
|
+
files.some((f) => f.endsWith('.csproj')) ||
|
|
268
|
+
files.some((f) => f.endsWith('.sln')) ||
|
|
269
|
+
files.some((f) => f.endsWith('.cs'))
|
|
270
|
+
) {
|
|
271
|
+
indicators.csharp = true;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// PHP indicators
|
|
275
|
+
if (
|
|
276
|
+
files.includes('composer.json') ||
|
|
277
|
+
files.includes('composer.lock') ||
|
|
278
|
+
files.some((f) => f.endsWith('.php'))
|
|
279
|
+
) {
|
|
280
|
+
indicators.php = true;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Determine primary language (priority order)
|
|
284
|
+
let primaryLanguage = 'unknown';
|
|
285
|
+
if (indicators.typescript) {
|
|
286
|
+
primaryLanguage = 'typescript';
|
|
287
|
+
} else if (indicators.javascript) {
|
|
288
|
+
primaryLanguage = 'javascript';
|
|
289
|
+
} else if (indicators.python) {
|
|
290
|
+
primaryLanguage = 'python';
|
|
291
|
+
} else if (indicators.rust) {
|
|
292
|
+
primaryLanguage = 'rust';
|
|
293
|
+
} else if (indicators.go) {
|
|
294
|
+
primaryLanguage = 'go';
|
|
295
|
+
} else if (indicators.java) {
|
|
296
|
+
primaryLanguage = 'java';
|
|
297
|
+
} else if (indicators.csharp) {
|
|
298
|
+
primaryLanguage = 'csharp';
|
|
299
|
+
} else if (indicators.php) {
|
|
300
|
+
primaryLanguage = 'php';
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
return {
|
|
304
|
+
primary: primaryLanguage,
|
|
305
|
+
indicators,
|
|
306
|
+
hasNodeJs: indicators.javascript || indicators.typescript,
|
|
307
|
+
hasPython: indicators.python,
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Get language-agnostic suggestion for TODO analyzer installation
|
|
313
|
+
* Focuses on runtime availability (Node.js/npx) rather than project language
|
|
314
|
+
* @param {string} cwd - Current working directory
|
|
315
|
+
* @returns {string} Installation suggestion message
|
|
316
|
+
*/
|
|
317
|
+
function getTodoAnalyzerSuggestion(cwd = process.cwd()) {
|
|
318
|
+
// Check runtime availability (language-agnostic)
|
|
319
|
+
let hasNodeJs = false;
|
|
320
|
+
let hasNpx = false;
|
|
321
|
+
try {
|
|
322
|
+
const { execSync } = require('child_process');
|
|
323
|
+
execSync('command -v node', { encoding: 'utf8', stdio: 'ignore' });
|
|
324
|
+
hasNodeJs = true;
|
|
325
|
+
execSync('command -v npx', { encoding: 'utf8', stdio: 'ignore' });
|
|
326
|
+
hasNpx = true;
|
|
327
|
+
} catch (e) {
|
|
328
|
+
// Node.js/npx not available
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
const suggestions = [];
|
|
332
|
+
|
|
333
|
+
if (hasNpx) {
|
|
334
|
+
// npx available - works for any language, no installation needed
|
|
335
|
+
suggestions.push(
|
|
336
|
+
' • Use npx (no installation required): npx --yes @paths.design/quality-gates'
|
|
337
|
+
);
|
|
338
|
+
suggestions.push(' • Install package: npm install --save-dev @paths.design/quality-gates');
|
|
339
|
+
} else if (hasNodeJs) {
|
|
340
|
+
// Node.js available but npx not found (unusual)
|
|
341
|
+
suggestions.push(' • Install package: npm install --save-dev @paths.design/quality-gates');
|
|
342
|
+
suggestions.push(
|
|
343
|
+
' • Install npx: npm install -g npx (then use: npx --yes @paths.design/quality-gates)'
|
|
344
|
+
);
|
|
345
|
+
} else {
|
|
346
|
+
// Node.js not available - suggest installation
|
|
347
|
+
suggestions.push(
|
|
348
|
+
' • Install Node.js: https://nodejs.org/ (then use: npx --yes @paths.design/quality-gates)'
|
|
349
|
+
);
|
|
350
|
+
suggestions.push(' • Use CAWS MCP server: caws quality-gates (via MCP)');
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// Check for project-specific scripts (language-agnostic - if they exist, suggest them)
|
|
354
|
+
const pythonScript = path.join(cwd, 'scripts', 'v3', 'analysis', 'todo_analyzer.py');
|
|
355
|
+
if (fs.existsSync(pythonScript)) {
|
|
356
|
+
suggestions.push(` • Use project script: python3 ${pythonScript}`);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
return suggestions.join('\n');
|
|
360
|
+
}
|
|
361
|
+
|
|
204
362
|
module.exports = {
|
|
205
363
|
detectProjectType,
|
|
206
364
|
shouldInitInCurrentDirectory,
|
|
207
365
|
detectsPublishing,
|
|
366
|
+
detectProjectLanguage,
|
|
367
|
+
getTodoAnalyzerSuggestion,
|
|
208
368
|
};
|
|
@@ -11,6 +11,7 @@ const fs = require('fs');
|
|
|
11
11
|
const path = require('path');
|
|
12
12
|
const yaml = require('js-yaml');
|
|
13
13
|
const { execSync } = require('child_process');
|
|
14
|
+
const { getTodoAnalyzerSuggestion } = require('./project-analysis');
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* Quality Gate Configuration
|
|
@@ -229,17 +230,17 @@ function checkHiddenTodos(stagedFiles) {
|
|
|
229
230
|
|
|
230
231
|
if (!analyzerPath) {
|
|
231
232
|
console.warn('⚠️ TODO analyzer not found - skipping TODO analysis');
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
);
|
|
233
|
+
const suggestion = getTodoAnalyzerSuggestion(process.cwd());
|
|
234
|
+
console.warn('💡 Available options for TODO analysis:');
|
|
235
|
+
console.warn(suggestion);
|
|
235
236
|
return { todos: [], blocking: 0, total: 0 };
|
|
236
237
|
}
|
|
237
238
|
|
|
238
239
|
if (usePython) {
|
|
239
240
|
console.warn('⚠️ Using legacy Python TODO analyzer (deprecated)');
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
);
|
|
241
|
+
const suggestion = getTodoAnalyzerSuggestion(process.cwd());
|
|
242
|
+
console.warn('💡 Consider upgrading to Node.js version:');
|
|
243
|
+
console.warn(suggestion);
|
|
243
244
|
}
|
|
244
245
|
|
|
245
246
|
// Run the TODO analyzer with staged files
|
|
@@ -512,6 +512,10 @@ async function suggestMigration() {
|
|
|
512
512
|
function suggestFeatureBreakdown(legacySpec) {
|
|
513
513
|
const features = [];
|
|
514
514
|
|
|
515
|
+
if (!legacySpec) {
|
|
516
|
+
return features;
|
|
517
|
+
}
|
|
518
|
+
|
|
515
519
|
if (legacySpec.acceptance && legacySpec.acceptance.length > 0) {
|
|
516
520
|
// Group acceptance criteria by logical features
|
|
517
521
|
const criteriaByFeature = {};
|
package/package.json
CHANGED