dev-playbooks-cn 1.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.
Files changed (143) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +466 -0
  3. package/bin/devbooks.js +987 -0
  4. package/package.json +43 -0
  5. package/skills/Skills/344/275/277/347/224/250/350/257/264/346/230/216.md +446 -0
  6. package/skills/Skill/345/274/200/345/217/221/346/214/207/345/215/227.md +248 -0
  7. package/skills/_shared/context-detection-template.md +315 -0
  8. package/skills/_shared/mcp-enhancement-template.md +144 -0
  9. package/skills/_shared/references//351/200/232/347/224/250/345/256/210/351/227/250/345/215/217/350/256/256.md +114 -0
  10. package/skills/_template/config-discovery-template.md +126 -0
  11. package/skills/devbooks-brownfield-bootstrap/SKILL.md +167 -0
  12. package/skills/devbooks-brownfield-bootstrap/references//344/273/243/347/240/201/345/257/274/350/210/252/347/255/226/347/225/245.md +203 -0
  13. package/skills/devbooks-brownfield-bootstrap/references//345/255/230/351/207/217/351/241/271/347/233/256/345/210/235/345/247/213/345/214/226.md +96 -0
  14. package/skills/devbooks-brownfield-bootstrap/references//345/255/230/351/207/217/351/241/271/347/233/256/345/210/235/345/247/213/345/214/226/346/217/220/347/244/272/350/257/215.md +115 -0
  15. package/skills/devbooks-brownfield-bootstrap/references//346/234/257/350/257/255/350/241/250/346/250/241/346/235/277.md +42 -0
  16. package/skills/devbooks-brownfield-bootstrap/scripts/cod-update.sh +357 -0
  17. package/skills/devbooks-brownfield-bootstrap/templates/project-profile-template.md +172 -0
  18. package/skills/devbooks-c4-map/SKILL.md +151 -0
  19. package/skills/devbooks-c4-map/references/C4/346/236/266/346/236/204/345/234/260/345/233/276/346/217/220/347/244/272/350/257/215.md +33 -0
  20. package/skills/devbooks-c4-map/references//345/210/206/345/261/202/347/272/246/346/235/237/346/243/200/346/237/245/346/270/205/345/215/225.md +185 -0
  21. package/skills/devbooks-code-review/SKILL.md +175 -0
  22. package/skills/devbooks-code-review/references/PR/346/250/241/346/235/277/344/270/216/346/214/207/345/215/227.md +321 -0
  23. package/skills/devbooks-code-review/references//344/273/243/347/240/201/350/257/204/345/256/241/346/217/220/347/244/272/350/257/215.md +100 -0
  24. package/skills/devbooks-code-review/references//345/235/217/345/221/263/351/201/223/351/200/237/346/237/245/350/241/250.md +495 -0
  25. package/skills/devbooks-code-review/references//350/265/204/346/272/220/347/256/241/347/220/206/345/256/241/346/237/245/346/270/205/345/215/225.md +311 -0
  26. package/skills/devbooks-coder/SKILL.md +219 -0
  27. package/skills/devbooks-coder/references//344/273/243/347/240/201/345/256/236/347/216/260/346/217/220/347/244/272/350/257/215.md +70 -0
  28. package/skills/devbooks-coder/references//344/275/216/351/243/216/351/231/251/346/224/271/345/212/250/346/212/200/346/234/257.md +275 -0
  29. package/skills/devbooks-coder/references//346/227/245/345/277/227/350/247/204/350/214/203.md +329 -0
  30. package/skills/devbooks-coder/references//347/274/226/347/240/201/351/243/216/346/240/274/347/273/206/345/210/231.md +351 -0
  31. package/skills/devbooks-coder/references//351/224/231/350/257/257/347/240/201/350/247/204/350/214/203.md +463 -0
  32. package/skills/devbooks-delivery-workflow/SKILL.md +217 -0
  33. package/skills/devbooks-delivery-workflow/references//344/272/244/344/273/230/351/252/214/346/224/266/345/267/245/344/275/234/346/265/201.md +256 -0
  34. package/skills/devbooks-delivery-workflow/references//345/216/237/345/236/213-/347/224/237/344/272/247/345/217/214/350/275/250/346/250/241/345/274/217.md +168 -0
  35. package/skills/devbooks-delivery-workflow/references//345/217/230/346/233/264/351/252/214/350/257/201/344/270/216/350/277/275/346/272/257/346/250/241/346/235/277.md +133 -0
  36. package/skills/devbooks-delivery-workflow/scripts/ac-trace-check.sh +330 -0
  37. package/skills/devbooks-delivery-workflow/scripts/audit-scope.sh +262 -0
  38. package/skills/devbooks-delivery-workflow/scripts/change-check.sh +1040 -0
  39. package/skills/devbooks-delivery-workflow/scripts/change-codemod-scaffold.sh +135 -0
  40. package/skills/devbooks-delivery-workflow/scripts/change-evidence.sh +152 -0
  41. package/skills/devbooks-delivery-workflow/scripts/change-scaffold.sh +442 -0
  42. package/skills/devbooks-delivery-workflow/scripts/change-spec-delta-scaffold.sh +136 -0
  43. package/skills/devbooks-delivery-workflow/scripts/constitution-check.sh +237 -0
  44. package/skills/devbooks-delivery-workflow/scripts/env-match-check.sh +128 -0
  45. package/skills/devbooks-delivery-workflow/scripts/fitness-check.sh +387 -0
  46. package/skills/devbooks-delivery-workflow/scripts/guardrail-check.sh +519 -0
  47. package/skills/devbooks-delivery-workflow/scripts/handoff-check.sh +141 -0
  48. package/skills/devbooks-delivery-workflow/scripts/hygiene-check.sh +340 -0
  49. package/skills/devbooks-delivery-workflow/scripts/migrate-from-openspec.sh +385 -0
  50. package/skills/devbooks-delivery-workflow/scripts/migrate-to-v2-gates.sh +202 -0
  51. package/skills/devbooks-delivery-workflow/scripts/progress-dashboard.sh +319 -0
  52. package/skills/devbooks-delivery-workflow/scripts/prototype-promote.sh +341 -0
  53. package/skills/devbooks-delivery-workflow/scripts/spec-preview.sh +203 -0
  54. package/skills/devbooks-delivery-workflow/scripts/spec-promote.sh +118 -0
  55. package/skills/devbooks-delivery-workflow/scripts/spec-rollback.sh +124 -0
  56. package/skills/devbooks-delivery-workflow/scripts/spec-stage.sh +117 -0
  57. package/skills/devbooks-delivery-workflow/scripts/verify-all.sh +78 -0
  58. package/skills/devbooks-delivery-workflow/scripts/verify-npm-package.sh +123 -0
  59. package/skills/devbooks-delivery-workflow/scripts/verify-openspec-free.sh +81 -0
  60. package/skills/devbooks-delivery-workflow/scripts/verify-slash-commands.sh +146 -0
  61. package/skills/devbooks-delivery-workflow/templates/handoff.md +50 -0
  62. package/skills/devbooks-design-backport/SKILL.md +73 -0
  63. package/skills/devbooks-design-backport/references//345/233/236/345/206/231/350/256/276/350/256/241/346/226/207/346/241/243/346/217/220/347/244/272/350/257/215.md +196 -0
  64. package/skills/devbooks-design-doc/SKILL.md +121 -0
  65. package/skills/devbooks-design-doc/references//345/276/256/346/234/215/345/212/241/350/256/276/350/256/241/346/270/205/345/215/225.md +149 -0
  66. package/skills/devbooks-design-doc/references//350/256/276/350/256/241/346/226/207/346/241/243/346/217/220/347/244/272/350/257/215.md +189 -0
  67. package/skills/devbooks-design-doc/references//351/232/220/347/247/201/345/220/210/350/247/204/346/243/200/346/237/245/346/270/205/345/215/225.md +240 -0
  68. package/skills/devbooks-entropy-monitor/SKILL.md +188 -0
  69. package/skills/devbooks-entropy-monitor/references//347/206/265/345/272/246/351/207/217/346/226/271/346/263/225/350/256/272.md +223 -0
  70. package/skills/devbooks-entropy-monitor/scripts/entropy-measure.sh +449 -0
  71. package/skills/devbooks-entropy-monitor/scripts/entropy-report.sh +303 -0
  72. package/skills/devbooks-entropy-monitor/templates/thresholds.json +99 -0
  73. package/skills/devbooks-federation/SKILL.md +264 -0
  74. package/skills/devbooks-federation/scripts/federation-check.sh +144 -0
  75. package/skills/devbooks-federation/templates/federation.yaml +89 -0
  76. package/skills/devbooks-impact-analysis/SKILL.md +135 -0
  77. package/skills/devbooks-impact-analysis/references//345/275/261/345/223/215/345/210/206/346/236/220/346/217/220/347/244/272/350/257/215.md +82 -0
  78. package/skills/devbooks-impact-analysis/scripts/graph-cache.sh +214 -0
  79. package/skills/devbooks-implementation-plan/SKILL.md +83 -0
  80. package/skills/devbooks-implementation-plan/references//347/274/226/347/240/201/350/256/241/345/210/222/346/217/220/347/244/272/350/257/215.md +99 -0
  81. package/skills/devbooks-index-bootstrap/SKILL.md +240 -0
  82. package/skills/devbooks-proposal-author/SKILL.md +83 -0
  83. package/skills/devbooks-proposal-author/references//346/217/220/346/241/210/346/222/260/345/206/231/346/217/220/347/244/272/350/257/215.md +66 -0
  84. package/skills/devbooks-proposal-challenger/SKILL.md +86 -0
  85. package/skills/devbooks-proposal-challenger/references//344/274/246/347/220/206/344/270/216/345/220/210/350/247/204/346/243/200/346/237/245/346/270/205/345/215/225.md +176 -0
  86. package/skills/devbooks-proposal-challenger/references//346/217/220/346/241/210/350/264/250/347/226/221/346/217/220/347/244/272/350/257/215.md +57 -0
  87. package/skills/devbooks-proposal-debate-workflow/SKILL.md +78 -0
  88. package/skills/devbooks-proposal-debate-workflow/references//346/217/220/346/241/210/345/257/271/350/276/251/345/267/245/344/275/234/346/265/201.md +24 -0
  89. package/skills/devbooks-proposal-debate-workflow/references//346/217/220/346/241/210/345/257/271/350/276/251/346/250/241/346/235/277.md +35 -0
  90. package/skills/devbooks-proposal-debate-workflow/scripts/proposal-debate-check.sh +102 -0
  91. package/skills/devbooks-proposal-judge/SKILL.md +78 -0
  92. package/skills/devbooks-proposal-judge/references//346/217/220/346/241/210/350/243/201/345/206/263/346/217/220/347/244/272/350/257/215.md +37 -0
  93. package/skills/devbooks-router/SKILL.md +346 -0
  94. package/skills/devbooks-spec-contract/SKILL.md +191 -0
  95. package/skills/devbooks-spec-contract/references/API/350/256/276/350/256/241/346/214/207/345/215/227.md +349 -0
  96. package/skills/devbooks-spec-contract/references//345/245/221/347/272/246/344/270/216/346/225/260/346/215/256/345/256/232/344/271/211/346/217/220/347/244/272/350/257/215.md +85 -0
  97. package/skills/devbooks-spec-contract/references//350/247/204/346/240/274/345/217/230/346/233/264/346/217/220/347/244/272/350/257/215.md +63 -0
  98. package/skills/devbooks-spec-contract/references//351/232/220/345/274/217/345/217/230/346/233/264/346/243/200/346/265/213/346/217/220/347/244/272/350/257/215.md +183 -0
  99. package/skills/devbooks-spec-contract/scripts/implicit-change-detect.sh +378 -0
  100. package/skills/devbooks-spec-gardener/SKILL.md +72 -0
  101. package/skills/devbooks-spec-gardener/references//350/247/204/346/240/274/345/233/255/344/270/201/346/217/220/347/244/272/350/257/215.md +41 -0
  102. package/skills/devbooks-test-owner/SKILL.md +172 -0
  103. package/skills/devbooks-test-owner/references//345/217/230/346/233/264/351/252/214/350/257/201/344/270/216/350/277/275/346/272/257/346/250/241/346/235/277.md +228 -0
  104. package/skills/devbooks-test-owner/references//345/274/202/346/255/245/347/263/273/347/273/237/346/265/213/350/257/225/347/255/226/347/225/245.md +316 -0
  105. package/skills/devbooks-test-owner/references//346/265/213/350/257/225/344/273/243/347/240/201/346/217/220/347/244/272/350/257/215.md +208 -0
  106. package/skills/devbooks-test-owner/references//346/265/213/350/257/225/345/210/206/345/261/202/347/255/226/347/225/245.md +281 -0
  107. package/skills/devbooks-test-owner/references//346/265/213/350/257/225/351/251/261/345/212/250.md +394 -0
  108. package/skills/devbooks-test-owner/references//350/247/243/344/276/235/350/265/226/346/212/200/346/234/257/351/200/237/346/237/245/350/241/250.md +432 -0
  109. package/skills/devbooks-test-reviewer/SKILL.md +189 -0
  110. package/templates/.devbooks/config.yaml +88 -0
  111. package/templates/claude-commands/devbooks/apply.md +38 -0
  112. package/templates/claude-commands/devbooks/archive.md +33 -0
  113. package/templates/claude-commands/devbooks/backport.md +19 -0
  114. package/templates/claude-commands/devbooks/bootstrap.md +19 -0
  115. package/templates/claude-commands/devbooks/c4.md +19 -0
  116. package/templates/claude-commands/devbooks/challenger.md +19 -0
  117. package/templates/claude-commands/devbooks/code.md +19 -0
  118. package/templates/claude-commands/devbooks/debate.md +19 -0
  119. package/templates/claude-commands/devbooks/delivery.md +19 -0
  120. package/templates/claude-commands/devbooks/design.md +19 -0
  121. package/templates/claude-commands/devbooks/entropy.md +19 -0
  122. package/templates/claude-commands/devbooks/federation.md +19 -0
  123. package/templates/claude-commands/devbooks/gardener.md +19 -0
  124. package/templates/claude-commands/devbooks/impact.md +19 -0
  125. package/templates/claude-commands/devbooks/index.md +19 -0
  126. package/templates/claude-commands/devbooks/judge.md +19 -0
  127. package/templates/claude-commands/devbooks/plan.md +19 -0
  128. package/templates/claude-commands/devbooks/proposal.md +19 -0
  129. package/templates/claude-commands/devbooks/quick.md +42 -0
  130. package/templates/claude-commands/devbooks/review.md +19 -0
  131. package/templates/claude-commands/devbooks/router.md +19 -0
  132. package/templates/claude-commands/devbooks/spec.md +19 -0
  133. package/templates/claude-commands/devbooks/test-review.md +19 -0
  134. package/templates/claude-commands/devbooks/test.md +19 -0
  135. package/templates/dev-playbooks/README.md +458 -0
  136. package/templates/dev-playbooks/changes/.gitkeep +1 -0
  137. package/templates/dev-playbooks/constitution.md +116 -0
  138. package/templates/dev-playbooks/project.md +96 -0
  139. package/templates/dev-playbooks/scripts/.gitkeep +1 -0
  140. package/templates/dev-playbooks/specs/_meta/anti-patterns/.gitkeep +2 -0
  141. package/templates/dev-playbooks/specs/_meta/glossary.md +47 -0
  142. package/templates/dev-playbooks/specs/_meta/project-profile.md +79 -0
  143. package/templates/dev-playbooks/specs/architecture/fitness-rules.md +95 -0
@@ -0,0 +1,449 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ # ============================================================================
5
+ # entropy-measure.sh
6
+ # ============================================================================
7
+ # Collects system entropy metrics across four dimensions:
8
+ # - Structural entropy (cyclomatic complexity, file/function sizes)
9
+ # - Change entropy (hotspots, coupling, churn)
10
+ # - Test entropy (flaky tests, coverage, test/code ratio)
11
+ # - Dependency entropy (outdated deps, vulnerabilities)
12
+ #
13
+ # Reference: "The Mythical Man-Month" Chapter 16 "No Silver Bullet" - Controlling complexity is key to software development
14
+ # ============================================================================
15
+
16
+ usage() {
17
+ cat <<'EOF' >&2
18
+ usage: entropy-measure.sh [--project-root <dir>] [--truth-root <dir>] [--output <file>] [--days <n>]
19
+
20
+ Collects system entropy metrics for a codebase.
21
+
22
+ Options:
23
+ --project-root Project root directory (default: pwd)
24
+ --truth-root Truth root for storing reports (default: specs)
25
+ --output Output JSON file (default: <truth-root>/_meta/entropy/metrics-YYYY-MM-DD.json)
26
+ --days Days of git history to analyze for change entropy (default: 30)
27
+
28
+ Output:
29
+ JSON file with metrics across four dimensions:
30
+ - structural: complexity, file sizes, function sizes
31
+ - change: hotspots, coupling, churn
32
+ - test: flaky ratio, coverage, test/code ratio
33
+ - dependency: outdated ratio, vulnerabilities
34
+
35
+ Examples:
36
+ entropy-measure.sh
37
+ entropy-measure.sh --project-root /path/to/repo --days 60
38
+ entropy-measure.sh --output ./entropy-report.json
39
+ EOF
40
+ }
41
+
42
+ # Color output helpers
43
+ red() { printf '\033[0;31m%s\033[0m\n' "$*" >&2; }
44
+ green() { printf '\033[0;32m%s\033[0m\n' "$*" >&2; }
45
+ yellow() { printf '\033[0;33m%s\033[0m\n' "$*" >&2; }
46
+
47
+ err() { red "error: $*"; }
48
+ warn() { yellow "warn: $*"; }
49
+ ok() { green "ok: $*"; }
50
+
51
+ if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
52
+ usage
53
+ exit 0
54
+ fi
55
+
56
+ project_root="${DEVBOOKS_PROJECT_ROOT:-$(pwd)}"
57
+ truth_root="${DEVBOOKS_TRUTH_ROOT:-specs}"
58
+ output_file=""
59
+ days=30
60
+
61
+ while [[ $# -gt 0 ]]; do
62
+ case "$1" in
63
+ -h|--help)
64
+ usage
65
+ exit 0
66
+ ;;
67
+ --project-root)
68
+ project_root="${2:-}"
69
+ shift 2
70
+ ;;
71
+ --truth-root)
72
+ truth_root="${2:-}"
73
+ shift 2
74
+ ;;
75
+ --output)
76
+ output_file="${2:-}"
77
+ shift 2
78
+ ;;
79
+ --days)
80
+ days="${2:-30}"
81
+ shift 2
82
+ ;;
83
+ *)
84
+ usage
85
+ exit 2
86
+ ;;
87
+ esac
88
+ done
89
+
90
+ # Normalize paths
91
+ project_root="${project_root%/}"
92
+ truth_root="${truth_root%/}"
93
+
94
+ if [[ "$truth_root" = /* ]]; then
95
+ truth_dir="$truth_root"
96
+ else
97
+ truth_dir="${project_root}/${truth_root}"
98
+ fi
99
+
100
+ # Set default output file
101
+ if [[ -z "$output_file" ]]; then
102
+ entropy_dir="${truth_dir}/_meta/entropy"
103
+ mkdir -p "$entropy_dir"
104
+ output_file="${entropy_dir}/metrics-$(date +%Y-%m-%d).json"
105
+ fi
106
+
107
+ # Ensure output directory exists
108
+ mkdir -p "$(dirname "$output_file")"
109
+
110
+ echo "=== Entropy Measurement ==="
111
+ echo "project: ${project_root}"
112
+ echo "output: ${output_file}"
113
+ echo ""
114
+
115
+ # ============================================================================
116
+ # Metric collection functions
117
+ # ============================================================================
118
+
119
+ # Count lines in files matching pattern, excluding common non-source dirs
120
+ count_lines() {
121
+ local pattern="$1"
122
+ find "$project_root" -type f -name "$pattern" \
123
+ ! -path "*/node_modules/*" \
124
+ ! -path "*/.git/*" \
125
+ ! -path "*/vendor/*" \
126
+ ! -path "*/dist/*" \
127
+ ! -path "*/build/*" \
128
+ ! -path "*/__pycache__/*" \
129
+ 2>/dev/null | while read -r f; do
130
+ wc -l < "$f" 2>/dev/null || echo 0
131
+ done | awk '{ sum += $1 } END { print sum+0 }'
132
+ }
133
+
134
+ # Get file line counts as JSON array
135
+ get_file_sizes() {
136
+ local sizes='[]'
137
+ while IFS= read -r f; do
138
+ [[ -n "$f" ]] || continue
139
+ local lines
140
+ lines=$(wc -l < "$f" 2>/dev/null || echo 0)
141
+ sizes=$(echo "$sizes" | jq --arg f "$f" --argjson l "$lines" '. + [$l]')
142
+ done < <(find "$project_root" -type f \( -name "*.js" -o -name "*.ts" -o -name "*.py" -o -name "*.go" -o -name "*.java" -o -name "*.rb" \) \
143
+ ! -path "*/node_modules/*" \
144
+ ! -path "*/.git/*" \
145
+ ! -path "*/vendor/*" \
146
+ ! -path "*/dist/*" \
147
+ ! -path "*/build/*" \
148
+ 2>/dev/null | head -500)
149
+ echo "$sizes"
150
+ }
151
+
152
+ # Calculate percentile from JSON array
153
+ percentile() {
154
+ local arr="$1"
155
+ local p="$2"
156
+ echo "$arr" | jq --argjson p "$p" '
157
+ sort |
158
+ if length == 0 then 0
159
+ else
160
+ (length - 1) * $p / 100 | floor | . as $idx |
161
+ if $idx >= length then .[-1]
162
+ else .[$idx]
163
+ end
164
+ end
165
+ '
166
+ }
167
+
168
+ # Count git hotspots (files changed frequently)
169
+ count_hotspots() {
170
+ if ! git -C "$project_root" rev-parse --git-dir >/dev/null 2>&1; then
171
+ echo '{"hotspot_count": 0, "total_files": 0, "hotspot_ratio": 0}'
172
+ return
173
+ fi
174
+
175
+ local total_files hotspot_files
176
+ total_files=$(git -C "$project_root" ls-files 2>/dev/null | wc -l | tr -d ' ')
177
+
178
+ # Files changed more than 5 times in the period
179
+ hotspot_files=$(git -C "$project_root" log --since="${days} days ago" --name-only --pretty=format: 2>/dev/null \
180
+ | grep -v '^$' \
181
+ | sort \
182
+ | uniq -c \
183
+ | awk '$1 > 5 { count++ } END { print count+0 }')
184
+
185
+ local ratio
186
+ if [[ "$total_files" -gt 0 ]]; then
187
+ ratio=$(echo "scale=4; $hotspot_files / $total_files" | bc 2>/dev/null || echo "0")
188
+ else
189
+ ratio="0"
190
+ fi
191
+
192
+ jq -n \
193
+ --argjson hc "$hotspot_files" \
194
+ --argjson tf "$total_files" \
195
+ --argjson r "$ratio" \
196
+ '{"hotspot_count": $hc, "total_files": $tf, "hotspot_ratio": $r}'
197
+ }
198
+
199
+ # Analyze dependency status
200
+ analyze_dependencies() {
201
+ local result='{"outdated": 0, "total": 0, "outdated_ratio": 0, "vulnerabilities": 0}'
202
+
203
+ # npm/yarn
204
+ if [[ -f "$project_root/package.json" ]]; then
205
+ local total_deps outdated_deps
206
+ total_deps=$(jq -r '(.dependencies // {}) + (.devDependencies // {}) | keys | length' "$project_root/package.json" 2>/dev/null || echo "0")
207
+
208
+ # Try npm outdated (if npm available)
209
+ if command -v npm >/dev/null 2>&1; then
210
+ outdated_deps=$(cd "$project_root" && npm outdated --json 2>/dev/null | jq 'keys | length' 2>/dev/null || echo "0")
211
+ else
212
+ outdated_deps="0"
213
+ fi
214
+
215
+ local ratio
216
+ if [[ "$total_deps" -gt 0 ]]; then
217
+ ratio=$(echo "scale=4; $outdated_deps / $total_deps" | bc 2>/dev/null || echo "0")
218
+ else
219
+ ratio="0"
220
+ fi
221
+
222
+ result=$(jq -n \
223
+ --argjson od "$outdated_deps" \
224
+ --argjson td "$total_deps" \
225
+ --argjson r "$ratio" \
226
+ --argjson v 0 \
227
+ '{"outdated": $od, "total": $td, "outdated_ratio": $r, "vulnerabilities": $v}')
228
+ fi
229
+
230
+ # pip/requirements.txt
231
+ if [[ -f "$project_root/requirements.txt" ]]; then
232
+ local total_deps
233
+ total_deps=$(grep -c -v '^#' "$project_root/requirements.txt" 2>/dev/null | grep -v '^$' | wc -l || echo "0")
234
+ # Note: pip-audit would be needed for proper outdated detection
235
+ result=$(echo "$result" | jq --argjson td "$total_deps" '.total = $td')
236
+ fi
237
+
238
+ echo "$result"
239
+ }
240
+
241
+ # Count test files and calculate test/code ratio
242
+ analyze_tests() {
243
+ local test_lines=0
244
+ local code_lines=0
245
+
246
+ # Count test file lines
247
+ test_lines=$(find "$project_root" -type f \( -name "*.test.js" -o -name "*.test.ts" -o -name "*.spec.js" -o -name "*.spec.ts" -o -name "test_*.py" -o -name "*_test.py" -o -name "*_test.go" \) \
248
+ ! -path "*/node_modules/*" \
249
+ ! -path "*/.git/*" \
250
+ 2>/dev/null | while read -r f; do
251
+ wc -l < "$f" 2>/dev/null || echo 0
252
+ done | awk '{ sum += $1 } END { print sum+0 }')
253
+
254
+ # Count source file lines (excluding tests)
255
+ code_lines=$(find "$project_root" -type f \( -name "*.js" -o -name "*.ts" -o -name "*.py" -o -name "*.go" \) \
256
+ ! -name "*.test.*" \
257
+ ! -name "*.spec.*" \
258
+ ! -name "test_*" \
259
+ ! -name "*_test.*" \
260
+ ! -path "*/node_modules/*" \
261
+ ! -path "*/.git/*" \
262
+ ! -path "*/tests/*" \
263
+ ! -path "*/__tests__/*" \
264
+ 2>/dev/null | while read -r f; do
265
+ wc -l < "$f" 2>/dev/null || echo 0
266
+ done | awk '{ sum += $1 } END { print sum+0 }')
267
+
268
+ local ratio
269
+ if [[ "$code_lines" -gt 0 ]]; then
270
+ ratio=$(echo "scale=4; $test_lines / $code_lines" | bc 2>/dev/null || echo "0")
271
+ else
272
+ ratio="0"
273
+ fi
274
+
275
+ jq -n \
276
+ --argjson tl "$test_lines" \
277
+ --argjson cl "$code_lines" \
278
+ --argjson r "$ratio" \
279
+ '{"test_lines": $tl, "code_lines": $cl, "test_code_ratio": $r, "flaky_ratio": 0, "coverage": null}'
280
+ }
281
+
282
+ # ============================================================================
283
+ # Main measurement
284
+ # ============================================================================
285
+
286
+ echo "measuring: structural entropy..."
287
+ file_sizes=$(get_file_sizes)
288
+ file_p95=$(percentile "$file_sizes" 95)
289
+ file_mean=$(echo "$file_sizes" | jq 'if length == 0 then 0 else (add / length) end')
290
+ echo " file_lines_p95: ${file_p95}"
291
+ echo " file_lines_mean: ${file_mean}"
292
+
293
+ echo "measuring: change entropy..."
294
+ hotspots=$(count_hotspots)
295
+ hotspot_ratio=$(echo "$hotspots" | jq -r '.hotspot_ratio')
296
+ echo " hotspot_ratio: ${hotspot_ratio}"
297
+
298
+ echo "measuring: test entropy..."
299
+ test_metrics=$(analyze_tests)
300
+ test_code_ratio=$(echo "$test_metrics" | jq -r '.test_code_ratio')
301
+ echo " test_code_ratio: ${test_code_ratio}"
302
+
303
+ echo "measuring: dependency entropy..."
304
+ dep_metrics=$(analyze_dependencies)
305
+ outdated_ratio=$(echo "$dep_metrics" | jq -r '.outdated_ratio')
306
+ echo " outdated_ratio: ${outdated_ratio}"
307
+
308
+ # ============================================================================
309
+ # Load thresholds
310
+ # ============================================================================
311
+
312
+ thresholds_file="${truth_dir}/_meta/entropy/thresholds.json"
313
+ if [[ -f "$thresholds_file" ]]; then
314
+ thresholds=$(cat "$thresholds_file")
315
+ else
316
+ # Default thresholds
317
+ thresholds='{
318
+ "structural": {
319
+ "complexity_mean": 10,
320
+ "complexity_p95": 20,
321
+ "file_lines_p95": 500,
322
+ "function_lines_p95": 50
323
+ },
324
+ "change": {
325
+ "hotspot_ratio": 0.1,
326
+ "coupling_ratio": 0.3,
327
+ "churn_ratio": 0.5
328
+ },
329
+ "test": {
330
+ "flaky_ratio": 0.01,
331
+ "coverage_min": 0.7,
332
+ "test_code_ratio_min": 0.5
333
+ },
334
+ "dependency": {
335
+ "outdated_ratio": 0.2,
336
+ "vulnerabilities": 0
337
+ }
338
+ }'
339
+ fi
340
+
341
+ # ============================================================================
342
+ # Generate alerts
343
+ # ============================================================================
344
+
345
+ alerts='[]'
346
+
347
+ # Check file size threshold
348
+ file_threshold=$(echo "$thresholds" | jq -r '.structural.file_lines_p95 // 500')
349
+ if (( $(echo "$file_p95 > $file_threshold" | bc -l 2>/dev/null || echo 0) )); then
350
+ alerts=$(echo "$alerts" | jq --arg m "file_lines_p95 ($file_p95) exceeds threshold ($file_threshold)" '. + [{level: "warning", dimension: "structural", message: $m}]')
351
+ fi
352
+
353
+ # Check hotspot threshold
354
+ hotspot_threshold=$(echo "$thresholds" | jq -r '.change.hotspot_ratio // 0.1')
355
+ if (( $(echo "$hotspot_ratio > $hotspot_threshold" | bc -l 2>/dev/null || echo 0) )); then
356
+ alerts=$(echo "$alerts" | jq --arg m "hotspot_ratio ($hotspot_ratio) exceeds threshold ($hotspot_threshold)" '. + [{level: "warning", dimension: "change", message: $m}]')
357
+ fi
358
+
359
+ # Check test/code ratio threshold
360
+ test_threshold=$(echo "$thresholds" | jq -r '.test.test_code_ratio_min // 0.5')
361
+ if (( $(echo "$test_code_ratio < $test_threshold" | bc -l 2>/dev/null || echo 0) )); then
362
+ alerts=$(echo "$alerts" | jq --arg m "test_code_ratio ($test_code_ratio) below threshold ($test_threshold)" '. + [{level: "warning", dimension: "test", message: $m}]')
363
+ fi
364
+
365
+ # Check outdated deps threshold
366
+ outdated_threshold=$(echo "$thresholds" | jq -r '.dependency.outdated_ratio // 0.2')
367
+ if (( $(echo "$outdated_ratio > $outdated_threshold" | bc -l 2>/dev/null || echo 0) )); then
368
+ alerts=$(echo "$alerts" | jq --arg m "outdated_ratio ($outdated_ratio) exceeds threshold ($outdated_threshold)" '. + [{level: "warning", dimension: "dependency", message: $m}]')
369
+ fi
370
+
371
+ # ============================================================================
372
+ # Generate output
373
+ # ============================================================================
374
+
375
+ jq -n \
376
+ --arg ts "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
377
+ --arg project "$project_root" \
378
+ --argjson days "$days" \
379
+ --argjson file_p95 "$file_p95" \
380
+ --argjson file_mean "$file_mean" \
381
+ --argjson hotspots "$hotspots" \
382
+ --argjson tests "$test_metrics" \
383
+ --argjson deps "$dep_metrics" \
384
+ --argjson thresholds "$thresholds" \
385
+ --argjson alerts "$alerts" \
386
+ '{
387
+ timestamp: $ts,
388
+ project_root: $project,
389
+ analysis_period_days: $days,
390
+ metrics: {
391
+ structural: {
392
+ file_lines_p95: $file_p95,
393
+ file_lines_mean: $file_mean,
394
+ complexity_mean: null,
395
+ complexity_p95: null,
396
+ function_lines_p95: null
397
+ },
398
+ change: $hotspots,
399
+ test: $tests,
400
+ dependency: $deps
401
+ },
402
+ thresholds: $thresholds,
403
+ alerts: $alerts,
404
+ summary: {
405
+ total_alerts: ($alerts | length),
406
+ dimensions_healthy: (4 - (
407
+ (if ($alerts | map(select(.dimension == "structural")) | length) > 0 then 1 else 0 end) +
408
+ (if ($alerts | map(select(.dimension == "change")) | length) > 0 then 1 else 0 end) +
409
+ (if ($alerts | map(select(.dimension == "test")) | length) > 0 then 1 else 0 end) +
410
+ (if ($alerts | map(select(.dimension == "dependency")) | length) > 0 then 1 else 0 end)
411
+ )),
412
+ dimensions_total: 4
413
+ }
414
+ }' > "$output_file"
415
+
416
+ # ============================================================================
417
+ # Append to history
418
+ # ============================================================================
419
+
420
+ history_file="${truth_dir}/_meta/entropy/history.json"
421
+ if [[ -f "$history_file" ]]; then
422
+ # Append new entry
423
+ tmp_file=$(mktemp)
424
+ jq --slurpfile new "$output_file" '. + $new' "$history_file" > "$tmp_file"
425
+ mv "$tmp_file" "$history_file"
426
+ else
427
+ # Create new history file
428
+ jq -s '.' "$output_file" > "$history_file"
429
+ fi
430
+
431
+ # ============================================================================
432
+ # Output summary
433
+ # ============================================================================
434
+
435
+ echo ""
436
+ echo "=== Entropy Summary ==="
437
+ alert_count=$(echo "$alerts" | jq 'length')
438
+ healthy=$(jq -r '.summary.dimensions_healthy' "$output_file")
439
+
440
+ if [[ "$alert_count" -eq 0 ]]; then
441
+ ok "all ${healthy}/4 dimensions healthy"
442
+ else
443
+ warn "${alert_count} alert(s) detected"
444
+ echo "$alerts" | jq -r '.[] | " [\(.level)] \(.dimension): \(.message)"'
445
+ fi
446
+
447
+ echo ""
448
+ ok "report: ${output_file}"
449
+ ok "history: ${history_file}"