@boshu2/vibe-check 2.2.1 → 2.4.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.
Files changed (77) hide show
  1. package/.agents/plans/2025-12-28-ai-safety-integration-plan.md +326 -0
  2. package/.agents/plans/2025-12-29-complexity-driver-plan.md +225 -0
  3. package/.agents/plans/2025-12-29-complexity-drivers-plan.md +253 -0
  4. package/.agents/research/2025-12-28-ai-platform-security-integration.md +295 -0
  5. package/.agents/research/2025-12-29-complexity-driver-architecture.md +392 -0
  6. package/.agents/research/2025-12-29-complexity-drivers.md +227 -0
  7. package/.beads/README.md +81 -0
  8. package/.beads/config.yaml +62 -0
  9. package/.beads/interactions.jsonl +0 -0
  10. package/.beads/issues.jsonl +21 -0
  11. package/.beads/metadata.json +4 -0
  12. package/.gitattributes +3 -0
  13. package/AGENTS.md +40 -0
  14. package/CHANGELOG.md +69 -0
  15. package/CLAUDE.md +75 -0
  16. package/README.md +71 -0
  17. package/dist/ai-safety/contract-drift.d.ts +14 -0
  18. package/dist/ai-safety/contract-drift.d.ts.map +1 -0
  19. package/dist/ai-safety/contract-drift.js +230 -0
  20. package/dist/ai-safety/contract-drift.js.map +1 -0
  21. package/dist/ai-safety/index.d.ts +43 -0
  22. package/dist/ai-safety/index.d.ts.map +1 -0
  23. package/dist/ai-safety/index.js +177 -0
  24. package/dist/ai-safety/index.js.map +1 -0
  25. package/dist/ai-safety/scope-violation.d.ts +18 -0
  26. package/dist/ai-safety/scope-violation.d.ts.map +1 -0
  27. package/dist/ai-safety/scope-violation.js +150 -0
  28. package/dist/ai-safety/scope-violation.js.map +1 -0
  29. package/dist/ai-safety/secret-leakage.d.ts +18 -0
  30. package/dist/ai-safety/secret-leakage.d.ts.map +1 -0
  31. package/dist/ai-safety/secret-leakage.js +188 -0
  32. package/dist/ai-safety/secret-leakage.js.map +1 -0
  33. package/dist/ai-safety/token-spiral.d.ts +17 -0
  34. package/dist/ai-safety/token-spiral.d.ts.map +1 -0
  35. package/dist/ai-safety/token-spiral.js +183 -0
  36. package/dist/ai-safety/token-spiral.js.map +1 -0
  37. package/dist/ai-safety/types.d.ts +122 -0
  38. package/dist/ai-safety/types.d.ts.map +1 -0
  39. package/dist/ai-safety/types.js +32 -0
  40. package/dist/ai-safety/types.js.map +1 -0
  41. package/dist/analyzers/complexity.d.ts +92 -0
  42. package/dist/analyzers/complexity.d.ts.map +1 -0
  43. package/dist/analyzers/complexity.js +79 -0
  44. package/dist/analyzers/complexity.js.map +1 -0
  45. package/dist/analyzers/modularity.d.ts +3 -1
  46. package/dist/analyzers/modularity.d.ts.map +1 -1
  47. package/dist/analyzers/modularity.js +32 -6
  48. package/dist/analyzers/modularity.js.map +1 -1
  49. package/dist/cli.js +2 -1
  50. package/dist/cli.js.map +1 -1
  51. package/dist/commands/driver.d.ts +18 -0
  52. package/dist/commands/driver.d.ts.map +1 -0
  53. package/dist/commands/driver.js +58 -0
  54. package/dist/commands/driver.js.map +1 -0
  55. package/dist/commands/index.d.ts +1 -0
  56. package/dist/commands/index.d.ts.map +1 -1
  57. package/dist/commands/index.js +1 -0
  58. package/dist/commands/index.js.map +1 -1
  59. package/dist/commands/modularity.d.ts +2 -0
  60. package/dist/commands/modularity.d.ts.map +1 -1
  61. package/dist/commands/modularity.js +86 -7
  62. package/dist/commands/modularity.js.map +1 -1
  63. package/dist/commands/session.d.ts +9 -0
  64. package/dist/commands/session.d.ts.map +1 -1
  65. package/dist/commands/session.js +42 -0
  66. package/dist/commands/session.js.map +1 -1
  67. package/dist/commands/watch.d.ts.map +1 -1
  68. package/dist/commands/watch.js +59 -0
  69. package/dist/commands/watch.js.map +1 -1
  70. package/drivers/README.md +327 -0
  71. package/drivers/go.sh +131 -0
  72. package/drivers/java.sh +137 -0
  73. package/drivers/javascript.sh +134 -0
  74. package/drivers/php.sh +132 -0
  75. package/drivers/python.sh +90 -0
  76. package/drivers/rust.sh +132 -0
  77. package/package.json +4 -1
@@ -0,0 +1,134 @@
1
+ #!/bin/bash
2
+ # drivers/javascript.sh
3
+ # Wraps cyclomatic-complexity to produce standard complexity JSON
4
+ #
5
+ # Usage: ./drivers/javascript.sh [directory]
6
+ # directory: Path to JavaScript/TypeScript code to analyze (default: current directory)
7
+ #
8
+ # Output: JSON conforming to ComplexityReport schema
9
+ # Exit codes: 0 = success, 1 = error (npx not available or other failure)
10
+
11
+ set -euo pipefail
12
+
13
+ TARGET_DIR="${1:-.}"
14
+
15
+ # Check if npx is available
16
+ if ! command -v npx &> /dev/null; then
17
+ echo '{"error": "npx not found. Install Node.js and npm."}' >&2
18
+ exit 1
19
+ fi
20
+
21
+ # Check if target directory exists
22
+ if [ ! -d "$TARGET_DIR" ]; then
23
+ echo "{\"error\": \"Directory not found: $TARGET_DIR\"}" >&2
24
+ exit 1
25
+ fi
26
+
27
+ # Find all JS/TS files (excluding common build/dep directories)
28
+ FILES=$(find "$TARGET_DIR" -type f \( -name "*.js" -o -name "*.ts" -o -name "*.jsx" -o -name "*.tsx" \) \
29
+ ! -path "*/node_modules/*" \
30
+ ! -path "*/dist/*" \
31
+ ! -path "*/build/*" \
32
+ ! -path "*/.next/*" \
33
+ ! -path "*/coverage/*" 2>/dev/null)
34
+
35
+ # If no files found, output empty result
36
+ if [ -z "$FILES" ]; then
37
+ echo '{"tool":"cyclomatic-complexity","language":"javascript","generatedAt":"'$(date -u +"%Y-%m-%dT%H:%M:%SZ")'","files":{},"summary":{"totalFiles":0,"totalFunctions":0,"avgComplexity":0,"gradeDistribution":{"A":0,"B":0,"C":0,"D":0,"E":0,"F":0}}}'
38
+ exit 0
39
+ fi
40
+
41
+ # Build glob pattern for cyclomatic-complexity
42
+ # It expects quoted glob patterns like 'src/**/*.ts'
43
+ PATTERN="${TARGET_DIR}/**/*.{js,ts,jsx,tsx}"
44
+
45
+ # Run cyclomatic-complexity and transform output
46
+ # cyclomatic-complexity outputs JSON like:
47
+ # [
48
+ # {
49
+ # "file": "path/to/file.js",
50
+ # "functionComplexities": [
51
+ # {"name": "func", "complexity": 5, "line": 10}
52
+ # ],
53
+ # "complexitySum": 5,
54
+ # "complexityLevel": "ok"
55
+ # }
56
+ # ]
57
+
58
+ npx --yes cyclomatic-complexity "$PATTERN" --json 2>/dev/null | jq -c '
59
+ # Filter out empty files and global scope functions
60
+ map(
61
+ select(.functionComplexities | length > 0) |
62
+ . + {functionComplexities: [.functionComplexities[] | select(.name != "global")]}
63
+ ) |
64
+ map(select(.functionComplexities | length > 0)) |
65
+
66
+ # Transform to standard schema
67
+ (
68
+ map({
69
+ key: .file,
70
+ value: {
71
+ functions: (
72
+ .functionComplexities | map({
73
+ name: .name,
74
+ complexity: .complexity,
75
+ grade: (
76
+ if .complexity <= 5 then "A"
77
+ elif .complexity <= 10 then "B"
78
+ elif .complexity <= 20 then "C"
79
+ elif .complexity <= 30 then "D"
80
+ elif .complexity <= 40 then "E"
81
+ else "F"
82
+ end
83
+ ),
84
+ line: .line,
85
+ endLine: null
86
+ })
87
+ ),
88
+ avgComplexity: (
89
+ if (.functionComplexities | length) > 0 then
90
+ ((.functionComplexities | map(.complexity) | add) / (.functionComplexities | length))
91
+ else 0 end
92
+ ),
93
+ maxComplexity: (
94
+ if (.functionComplexities | length) > 0 then
95
+ (.functionComplexities | map(.complexity) | max)
96
+ else 0 end
97
+ ),
98
+ grade: (
99
+ if (.functionComplexities | length) > 0 then
100
+ ((.functionComplexities | map(.complexity) | add) / (.functionComplexities | length)) as $avg |
101
+ if $avg <= 5 then "A"
102
+ elif $avg <= 10 then "B"
103
+ elif $avg <= 20 then "C"
104
+ elif $avg <= 30 then "D"
105
+ elif $avg <= 40 then "E"
106
+ else "F"
107
+ end
108
+ else "A" end
109
+ )
110
+ }
111
+ }) | from_entries
112
+ ) as $files |
113
+ {
114
+ tool: "cyclomatic-complexity",
115
+ language: "javascript",
116
+ generatedAt: (now | todate),
117
+ files: $files,
118
+ summary: {
119
+ totalFiles: ($files | to_entries | length),
120
+ totalFunctions: ([$files | to_entries[].value.functions | length] | add // 0),
121
+ avgComplexity: (
122
+ [$files | to_entries[].value.avgComplexity] |
123
+ if length > 0 then (add / length) else 0 end
124
+ ),
125
+ gradeDistribution: (
126
+ [$files | to_entries[].value.grade] |
127
+ reduce .[] as $grade (
128
+ {A: 0, B: 0, C: 0, D: 0, E: 0, F: 0};
129
+ .[$grade] += 1
130
+ )
131
+ )
132
+ }
133
+ }
134
+ '
package/drivers/php.sh ADDED
@@ -0,0 +1,132 @@
1
+ #!/bin/bash
2
+ # drivers/php.sh
3
+ # Wraps PHPMD to produce standard complexity JSON
4
+ #
5
+ # Usage: ./drivers/php.sh [directory]
6
+ # directory: Path to PHP code to analyze (default: current directory)
7
+ #
8
+ # Output: JSON conforming to ComplexityReport schema
9
+ # Exit codes: 0 = success, 1 = error (phpmd not installed or other failure)
10
+
11
+ set -euo pipefail
12
+
13
+ TARGET_DIR="${1:-.}"
14
+
15
+ # Check phpmd is installed
16
+ if ! command -v phpmd &> /dev/null; then
17
+ echo '{"error": "phpmd not installed. Run: composer global require phpmd/phpmd"}' >&2
18
+ exit 1
19
+ fi
20
+
21
+ # Check if target directory exists
22
+ if [ ! -d "$TARGET_DIR" ]; then
23
+ echo "{\"error\": \"Directory not found: $TARGET_DIR\"}" >&2
24
+ exit 1
25
+ fi
26
+
27
+ # Check if there are any PHP files
28
+ if ! find "$TARGET_DIR" -name "*.php" ! -path "*/vendor/*" -print -quit 2>/dev/null | grep -q .; then
29
+ # No PHP files found, output empty result
30
+ echo '{"tool":"phpmd","language":"php","generatedAt":"'$(date -u +"%Y-%m-%dT%H:%M:%SZ")'","files":{},"summary":{"totalFiles":0,"totalFunctions":0,"avgComplexity":0,"gradeDistribution":{"A":0,"B":0,"C":0,"D":0,"E":0,"F":0}}}'
31
+ exit 0
32
+ fi
33
+
34
+ # Run PHPMD and transform output
35
+ # PHPMD outputs JSON violations, we need to extract cyclomatic complexity violations
36
+ # and transform them to our schema
37
+ # Using --ignore-violations-on-exit to ensure exit 0 even with violations
38
+
39
+ phpmd "$TARGET_DIR" json codesize --exclude vendor --ignore-violations-on-exit 2>/dev/null | jq -c '
40
+ # Helper function for complexity to grade conversion
41
+ def complexity_to_grade:
42
+ if . <= 5 then "A"
43
+ elif . <= 10 then "B"
44
+ elif . <= 20 then "C"
45
+ elif . <= 30 then "D"
46
+ elif . <= 40 then "E"
47
+ else "F"
48
+ end;
49
+
50
+ # Process PHPMD violations format
51
+ # Extract only CyclomaticComplexity violations
52
+ .files |
53
+ map(
54
+ select(.violations | length > 0) |
55
+ {
56
+ path: .file,
57
+ violations: [
58
+ .violations[] |
59
+ select(.rule == "CyclomaticComplexity") |
60
+ {
61
+ # Parse complexity from description like "The method foo() has a Cyclomatic Complexity of 12."
62
+ description: .description,
63
+ method: .method,
64
+ beginLine: .beginLine,
65
+ endLine: .endLine,
66
+ # Extract complexity number from description using regex
67
+ complexity: (
68
+ .description |
69
+ capture("Cyclomatic Complexity of (?<num>[0-9]+)") |
70
+ .num | tonumber
71
+ )
72
+ }
73
+ ]
74
+ } |
75
+ select(.violations | length > 0)
76
+ ) |
77
+
78
+ # Group by file and calculate metrics
79
+ map({
80
+ key: .path,
81
+ value: {
82
+ functions: (
83
+ .violations | map({
84
+ name: .method,
85
+ complexity: .complexity,
86
+ grade: (.complexity | complexity_to_grade),
87
+ line: .beginLine,
88
+ endLine: .endLine
89
+ })
90
+ ),
91
+ avgComplexity: (
92
+ if (.violations | length) > 0 then
93
+ ((.violations | map(.complexity) | add) / (.violations | length))
94
+ else 0 end
95
+ ),
96
+ maxComplexity: (
97
+ if (.violations | length) > 0 then
98
+ (.violations | map(.complexity) | max)
99
+ else 0 end
100
+ ),
101
+ grade: (
102
+ if (.violations | length) > 0 then
103
+ (((.violations | map(.complexity) | add) / (.violations | length)) | complexity_to_grade)
104
+ else "A" end
105
+ )
106
+ }
107
+ }) |
108
+ from_entries as $files |
109
+
110
+ # Build final output
111
+ {
112
+ tool: "phpmd",
113
+ language: "php",
114
+ generatedAt: (now | todate),
115
+ files: $files,
116
+ summary: {
117
+ totalFiles: ($files | to_entries | length),
118
+ totalFunctions: ([$files | to_entries[].value.functions | length] | add // 0),
119
+ avgComplexity: (
120
+ [$files | to_entries[].value.avgComplexity] |
121
+ if length > 0 then (add / length) else 0 end
122
+ ),
123
+ gradeDistribution: (
124
+ [$files | to_entries[].value.grade] |
125
+ reduce .[] as $grade (
126
+ {A: 0, B: 0, C: 0, D: 0, E: 0, F: 0};
127
+ .[$grade] += 1
128
+ )
129
+ )
130
+ }
131
+ }
132
+ '
@@ -0,0 +1,90 @@
1
+ #!/bin/bash
2
+ # drivers/python.sh
3
+ # Wraps radon to produce standard complexity JSON
4
+ #
5
+ # Usage: ./drivers/python.sh [directory]
6
+ # directory: Path to Python code to analyze (default: current directory)
7
+ #
8
+ # Output: JSON conforming to ComplexityReport schema
9
+ # Exit codes: 0 = success, 1 = error (radon not installed or other failure)
10
+
11
+ set -euo pipefail
12
+
13
+ TARGET_DIR="${1:-.}"
14
+
15
+ # Check radon is installed
16
+ if ! command -v radon &> /dev/null; then
17
+ echo '{"error": "radon not installed. Run: pip install radon"}' >&2
18
+ exit 1
19
+ fi
20
+
21
+ # Check if target directory exists
22
+ if [ ! -d "$TARGET_DIR" ]; then
23
+ echo "{\"error\": \"Directory not found: $TARGET_DIR\"}" >&2
24
+ exit 1
25
+ fi
26
+
27
+ # Run radon and transform output
28
+ # radon cc outputs JSON like:
29
+ # {
30
+ # "file.py": [
31
+ # {"name": "func", "complexity": 5, "rank": "A", "lineno": 10, ...}
32
+ # ]
33
+ # }
34
+ radon cc "$TARGET_DIR" -j --total-average 2>/dev/null | jq -c '
35
+ (to_entries | map({
36
+ key: .key,
37
+ value: {
38
+ functions: (.value | map({
39
+ name: .name,
40
+ complexity: .complexity,
41
+ grade: .rank,
42
+ line: .lineno,
43
+ endLine: .endline
44
+ })),
45
+ avgComplexity: (
46
+ if (.value | length) > 0 then
47
+ ((.value | map(.complexity) | add) / (.value | length))
48
+ else 0 end
49
+ ),
50
+ maxComplexity: (
51
+ if (.value | length) > 0 then
52
+ (.value | map(.complexity) | max)
53
+ else 0 end
54
+ ),
55
+ grade: (
56
+ if (.value | length) > 0 then
57
+ ((.value | map(.complexity) | add) / (.value | length)) as $avg |
58
+ if $avg <= 5 then "A"
59
+ elif $avg <= 10 then "B"
60
+ elif $avg <= 20 then "C"
61
+ elif $avg <= 30 then "D"
62
+ elif $avg <= 40 then "E"
63
+ else "F"
64
+ end
65
+ else "A" end
66
+ )
67
+ }
68
+ }) | from_entries) as $files |
69
+ {
70
+ tool: "radon",
71
+ language: "python",
72
+ generatedAt: (now | todate),
73
+ files: $files,
74
+ summary: {
75
+ totalFiles: ($files | to_entries | length),
76
+ totalFunctions: ([$files | to_entries[].value.functions | length] | add // 0),
77
+ avgComplexity: (
78
+ [$files | to_entries[].value.avgComplexity] |
79
+ if length > 0 then (add / length) else 0 end
80
+ ),
81
+ gradeDistribution: (
82
+ [$files | to_entries[].value.grade] |
83
+ reduce .[] as $grade (
84
+ {A: 0, B: 0, C: 0, D: 0, E: 0, F: 0};
85
+ .[$grade] += 1
86
+ )
87
+ )
88
+ }
89
+ }
90
+ '
@@ -0,0 +1,132 @@
1
+ #!/bin/bash
2
+ # drivers/rust.sh
3
+ # Wraps rust-code-analysis-cli to produce standard complexity JSON
4
+ #
5
+ # Usage: ./drivers/rust.sh [directory]
6
+ # directory: Path to Rust code to analyze (default: current directory)
7
+ #
8
+ # Output: JSON conforming to ComplexityReport schema
9
+ # Exit codes: 0 = success, 1 = error (rust-code-analysis-cli not installed or other failure)
10
+
11
+ set -euo pipefail
12
+
13
+ TARGET_DIR="${1:-.}"
14
+
15
+ # Check rust-code-analysis-cli is installed
16
+ if ! command -v rust-code-analysis-cli &> /dev/null; then
17
+ echo '{"error": "rust-code-analysis-cli not installed. Run: cargo install rust-code-analysis-cli"}' >&2
18
+ exit 1
19
+ fi
20
+
21
+ # Check if target directory exists
22
+ if [ ! -d "$TARGET_DIR" ]; then
23
+ echo "{\"error\": \"Directory not found: $TARGET_DIR\"}" >&2
24
+ exit 1
25
+ fi
26
+
27
+ # Check if there are any Rust files
28
+ if ! find "$TARGET_DIR" -name "*.rs" ! -path "*/target/*" -print -quit 2>/dev/null | grep -q .; then
29
+ # No Rust files found, output empty result
30
+ echo '{"tool":"rust-code-analysis","language":"rust","generatedAt":"'$(date -u +"%Y-%m-%dT%H:%M:%SZ")'","files":{},"summary":{"totalFiles":0,"totalFunctions":0,"avgComplexity":0,"gradeDistribution":{"A":0,"B":0,"C":0,"D":0,"E":0,"F":0}}}'
31
+ exit 0
32
+ fi
33
+
34
+ # Run rust-code-analysis-cli and transform output
35
+ # The tool outputs JSON with metrics for each file analyzed
36
+ # We need to transform this to match our ComplexityReport schema
37
+
38
+ # Create temp directory for JSON outputs
39
+ TEMP_DIR=$(mktemp -d)
40
+ trap "rm -rf $TEMP_DIR" EXIT
41
+
42
+ # Run rust-code-analysis-cli on the directory
43
+ # -m: enable metrics computation
44
+ # -O json: output format JSON
45
+ # -p: path to analyze
46
+ # Output goes to current directory with .json extension added to original filename
47
+ (cd "$TEMP_DIR" && rust-code-analysis-cli -m -p "$TARGET_DIR" -O json 2>/dev/null) || {
48
+ echo '{"error": "rust-code-analysis-cli failed to analyze code"}' >&2
49
+ exit 1
50
+ }
51
+
52
+ # Find all generated JSON files and merge them
53
+ # rust-code-analysis creates one JSON per source file
54
+ find "$TEMP_DIR" -name "*.json" -type f 2>/dev/null | jq -s -c '
55
+ # Helper function for complexity to grade conversion
56
+ def complexity_to_grade:
57
+ if . <= 5 then "A"
58
+ elif . <= 10 then "B"
59
+ elif . <= 20 then "C"
60
+ elif . <= 30 then "D"
61
+ elif . <= 40 then "E"
62
+ else "F"
63
+ end;
64
+
65
+ # Process each file'\''s metrics
66
+ map(
67
+ # Extract the original file path from name field
68
+ .name as $filepath |
69
+
70
+ # Get cyclomatic complexity for functions
71
+ (.spaces // []) |
72
+
73
+ # Find all functions and their complexity
74
+ [.. | select(.kind? == "function" or .kind? == "method") | {
75
+ name: .name.name,
76
+ complexity: (.metrics.cyclomatic.sum // 0),
77
+ line: .start_line,
78
+ endLine: .end_line
79
+ }] as $functions |
80
+
81
+ # Calculate file-level metrics
82
+ {
83
+ key: $filepath,
84
+ value: {
85
+ functions: ($functions | map(
86
+ . + {grade: (.complexity | complexity_to_grade)}
87
+ )),
88
+ avgComplexity: (
89
+ if ($functions | length) > 0 then
90
+ (($functions | map(.complexity) | add) / ($functions | length))
91
+ else 0 end
92
+ ),
93
+ maxComplexity: (
94
+ if ($functions | length) > 0 then
95
+ ($functions | map(.complexity) | max)
96
+ else 0 end
97
+ ),
98
+ grade: (
99
+ if ($functions | length) > 0 then
100
+ ((($functions | map(.complexity) | add) / ($functions | length)) | complexity_to_grade)
101
+ else "A" end
102
+ )
103
+ }
104
+ }
105
+ ) |
106
+
107
+ # Convert to object with file paths as keys
108
+ from_entries as $files |
109
+
110
+ # Build final output
111
+ {
112
+ tool: "rust-code-analysis",
113
+ language: "rust",
114
+ generatedAt: (now | todate),
115
+ files: $files,
116
+ summary: {
117
+ totalFiles: ($files | to_entries | length),
118
+ totalFunctions: ([$files | to_entries[].value.functions | length] | add // 0),
119
+ avgComplexity: (
120
+ [$files | to_entries[].value.avgComplexity] |
121
+ if length > 0 then (add / length) else 0 end
122
+ ),
123
+ gradeDistribution: (
124
+ [$files | to_entries[].value.grade] |
125
+ reduce .[] as $grade (
126
+ {A: 0, B: 0, C: 0, D: 0, E: 0, F: 0};
127
+ .[$grade] += 1
128
+ )
129
+ )
130
+ }
131
+ }
132
+ '
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@boshu2/vibe-check",
4
- "version": "2.2.1",
4
+ "version": "2.4.0",
5
5
  "description": "Track git commit patterns during AI-assisted coding (experimental)",
6
6
  "main": "dist/cli.js",
7
7
  "bin": {
@@ -33,9 +33,12 @@
33
33
  "commander": "^14.0.2",
34
34
  "date-fns": "^4.1.0",
35
35
  "enquirer": "^2.4.1",
36
+ "js-yaml": "^4.1.1",
37
+ "minimatch": "^10.1.1",
36
38
  "simple-git": "^3.30.0"
37
39
  },
38
40
  "devDependencies": {
41
+ "@types/js-yaml": "^4.0.9",
39
42
  "@types/node": "^25.0.2",
40
43
  "@vitest/coverage-v8": "^4.0.15",
41
44
  "ts-node": "^10.9.2",