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.
- package/LICENSE +21 -0
- package/README.md +466 -0
- package/bin/devbooks.js +987 -0
- package/package.json +43 -0
- package/skills/Skills/344/275/277/347/224/250/350/257/264/346/230/216.md +446 -0
- package/skills/Skill/345/274/200/345/217/221/346/214/207/345/215/227.md +248 -0
- package/skills/_shared/context-detection-template.md +315 -0
- package/skills/_shared/mcp-enhancement-template.md +144 -0
- 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
- package/skills/_template/config-discovery-template.md +126 -0
- package/skills/devbooks-brownfield-bootstrap/SKILL.md +167 -0
- 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
- 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
- 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
- package/skills/devbooks-brownfield-bootstrap/references//346/234/257/350/257/255/350/241/250/346/250/241/346/235/277.md +42 -0
- package/skills/devbooks-brownfield-bootstrap/scripts/cod-update.sh +357 -0
- package/skills/devbooks-brownfield-bootstrap/templates/project-profile-template.md +172 -0
- package/skills/devbooks-c4-map/SKILL.md +151 -0
- 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
- 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
- package/skills/devbooks-code-review/SKILL.md +175 -0
- 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
- 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
- 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
- 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
- package/skills/devbooks-coder/SKILL.md +219 -0
- 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
- 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
- package/skills/devbooks-coder/references//346/227/245/345/277/227/350/247/204/350/214/203.md +329 -0
- 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
- package/skills/devbooks-coder/references//351/224/231/350/257/257/347/240/201/350/247/204/350/214/203.md +463 -0
- package/skills/devbooks-delivery-workflow/SKILL.md +217 -0
- 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
- 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
- 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
- package/skills/devbooks-delivery-workflow/scripts/ac-trace-check.sh +330 -0
- package/skills/devbooks-delivery-workflow/scripts/audit-scope.sh +262 -0
- package/skills/devbooks-delivery-workflow/scripts/change-check.sh +1040 -0
- package/skills/devbooks-delivery-workflow/scripts/change-codemod-scaffold.sh +135 -0
- package/skills/devbooks-delivery-workflow/scripts/change-evidence.sh +152 -0
- package/skills/devbooks-delivery-workflow/scripts/change-scaffold.sh +442 -0
- package/skills/devbooks-delivery-workflow/scripts/change-spec-delta-scaffold.sh +136 -0
- package/skills/devbooks-delivery-workflow/scripts/constitution-check.sh +237 -0
- package/skills/devbooks-delivery-workflow/scripts/env-match-check.sh +128 -0
- package/skills/devbooks-delivery-workflow/scripts/fitness-check.sh +387 -0
- package/skills/devbooks-delivery-workflow/scripts/guardrail-check.sh +519 -0
- package/skills/devbooks-delivery-workflow/scripts/handoff-check.sh +141 -0
- package/skills/devbooks-delivery-workflow/scripts/hygiene-check.sh +340 -0
- package/skills/devbooks-delivery-workflow/scripts/migrate-from-openspec.sh +385 -0
- package/skills/devbooks-delivery-workflow/scripts/migrate-to-v2-gates.sh +202 -0
- package/skills/devbooks-delivery-workflow/scripts/progress-dashboard.sh +319 -0
- package/skills/devbooks-delivery-workflow/scripts/prototype-promote.sh +341 -0
- package/skills/devbooks-delivery-workflow/scripts/spec-preview.sh +203 -0
- package/skills/devbooks-delivery-workflow/scripts/spec-promote.sh +118 -0
- package/skills/devbooks-delivery-workflow/scripts/spec-rollback.sh +124 -0
- package/skills/devbooks-delivery-workflow/scripts/spec-stage.sh +117 -0
- package/skills/devbooks-delivery-workflow/scripts/verify-all.sh +78 -0
- package/skills/devbooks-delivery-workflow/scripts/verify-npm-package.sh +123 -0
- package/skills/devbooks-delivery-workflow/scripts/verify-openspec-free.sh +81 -0
- package/skills/devbooks-delivery-workflow/scripts/verify-slash-commands.sh +146 -0
- package/skills/devbooks-delivery-workflow/templates/handoff.md +50 -0
- package/skills/devbooks-design-backport/SKILL.md +73 -0
- 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
- package/skills/devbooks-design-doc/SKILL.md +121 -0
- 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
- 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
- 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
- package/skills/devbooks-entropy-monitor/SKILL.md +188 -0
- 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
- package/skills/devbooks-entropy-monitor/scripts/entropy-measure.sh +449 -0
- package/skills/devbooks-entropy-monitor/scripts/entropy-report.sh +303 -0
- package/skills/devbooks-entropy-monitor/templates/thresholds.json +99 -0
- package/skills/devbooks-federation/SKILL.md +264 -0
- package/skills/devbooks-federation/scripts/federation-check.sh +144 -0
- package/skills/devbooks-federation/templates/federation.yaml +89 -0
- package/skills/devbooks-impact-analysis/SKILL.md +135 -0
- 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
- package/skills/devbooks-impact-analysis/scripts/graph-cache.sh +214 -0
- package/skills/devbooks-implementation-plan/SKILL.md +83 -0
- 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
- package/skills/devbooks-index-bootstrap/SKILL.md +240 -0
- package/skills/devbooks-proposal-author/SKILL.md +83 -0
- 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
- package/skills/devbooks-proposal-challenger/SKILL.md +86 -0
- 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
- 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
- package/skills/devbooks-proposal-debate-workflow/SKILL.md +78 -0
- 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
- 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
- package/skills/devbooks-proposal-debate-workflow/scripts/proposal-debate-check.sh +102 -0
- package/skills/devbooks-proposal-judge/SKILL.md +78 -0
- 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
- package/skills/devbooks-router/SKILL.md +346 -0
- package/skills/devbooks-spec-contract/SKILL.md +191 -0
- package/skills/devbooks-spec-contract/references/API/350/256/276/350/256/241/346/214/207/345/215/227.md +349 -0
- 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
- 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
- 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
- package/skills/devbooks-spec-contract/scripts/implicit-change-detect.sh +378 -0
- package/skills/devbooks-spec-gardener/SKILL.md +72 -0
- 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
- package/skills/devbooks-test-owner/SKILL.md +172 -0
- 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
- 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
- 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
- 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
- package/skills/devbooks-test-owner/references//346/265/213/350/257/225/351/251/261/345/212/250.md +394 -0
- 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
- package/skills/devbooks-test-reviewer/SKILL.md +189 -0
- package/templates/.devbooks/config.yaml +88 -0
- package/templates/claude-commands/devbooks/apply.md +38 -0
- package/templates/claude-commands/devbooks/archive.md +33 -0
- package/templates/claude-commands/devbooks/backport.md +19 -0
- package/templates/claude-commands/devbooks/bootstrap.md +19 -0
- package/templates/claude-commands/devbooks/c4.md +19 -0
- package/templates/claude-commands/devbooks/challenger.md +19 -0
- package/templates/claude-commands/devbooks/code.md +19 -0
- package/templates/claude-commands/devbooks/debate.md +19 -0
- package/templates/claude-commands/devbooks/delivery.md +19 -0
- package/templates/claude-commands/devbooks/design.md +19 -0
- package/templates/claude-commands/devbooks/entropy.md +19 -0
- package/templates/claude-commands/devbooks/federation.md +19 -0
- package/templates/claude-commands/devbooks/gardener.md +19 -0
- package/templates/claude-commands/devbooks/impact.md +19 -0
- package/templates/claude-commands/devbooks/index.md +19 -0
- package/templates/claude-commands/devbooks/judge.md +19 -0
- package/templates/claude-commands/devbooks/plan.md +19 -0
- package/templates/claude-commands/devbooks/proposal.md +19 -0
- package/templates/claude-commands/devbooks/quick.md +42 -0
- package/templates/claude-commands/devbooks/review.md +19 -0
- package/templates/claude-commands/devbooks/router.md +19 -0
- package/templates/claude-commands/devbooks/spec.md +19 -0
- package/templates/claude-commands/devbooks/test-review.md +19 -0
- package/templates/claude-commands/devbooks/test.md +19 -0
- package/templates/dev-playbooks/README.md +458 -0
- package/templates/dev-playbooks/changes/.gitkeep +1 -0
- package/templates/dev-playbooks/constitution.md +116 -0
- package/templates/dev-playbooks/project.md +96 -0
- package/templates/dev-playbooks/scripts/.gitkeep +1 -0
- package/templates/dev-playbooks/specs/_meta/anti-patterns/.gitkeep +2 -0
- package/templates/dev-playbooks/specs/_meta/glossary.md +47 -0
- package/templates/dev-playbooks/specs/_meta/project-profile.md +79 -0
- package/templates/dev-playbooks/specs/architecture/fitness-rules.md +95 -0
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# skills/devbooks-delivery-workflow/scripts/ac-trace-check.sh
|
|
3
|
+
# AC-ID Traceability Coverage Check Script
|
|
4
|
+
#
|
|
5
|
+
# Checks the traceability coverage of AC-IDs from design to tests.
|
|
6
|
+
#
|
|
7
|
+
# Usage:
|
|
8
|
+
# ./ac-trace-check.sh <change-id> [options]
|
|
9
|
+
# ./ac-trace-check.sh --help
|
|
10
|
+
#
|
|
11
|
+
# Options:
|
|
12
|
+
# --threshold N Coverage threshold (default 80)
|
|
13
|
+
# --output FORMAT Output format (text|json, default text)
|
|
14
|
+
# --project-root DIR Project root directory
|
|
15
|
+
# --change-root DIR Change package directory
|
|
16
|
+
#
|
|
17
|
+
# Exit codes:
|
|
18
|
+
# 0 - Coverage meets threshold
|
|
19
|
+
# 1 - Coverage below threshold
|
|
20
|
+
# 2 - Usage error
|
|
21
|
+
|
|
22
|
+
set -euo pipefail
|
|
23
|
+
|
|
24
|
+
# Version
|
|
25
|
+
VERSION="1.0.0"
|
|
26
|
+
|
|
27
|
+
# Defaults
|
|
28
|
+
threshold=80
|
|
29
|
+
output_format="text"
|
|
30
|
+
project_root="."
|
|
31
|
+
change_root="changes"
|
|
32
|
+
|
|
33
|
+
# Color output
|
|
34
|
+
RED='\033[0;31m'
|
|
35
|
+
GREEN='\033[0;32m'
|
|
36
|
+
YELLOW='\033[0;33m'
|
|
37
|
+
BLUE='\033[0;34m'
|
|
38
|
+
NC='\033[0m'
|
|
39
|
+
|
|
40
|
+
# Show help
|
|
41
|
+
show_help() {
|
|
42
|
+
cat << 'EOF'
|
|
43
|
+
AC-ID Traceability Coverage Check Script (ac-trace-check.sh)
|
|
44
|
+
|
|
45
|
+
Usage:
|
|
46
|
+
./ac-trace-check.sh <change-id> [options]
|
|
47
|
+
|
|
48
|
+
Options:
|
|
49
|
+
--threshold N Coverage threshold, default 80 (percentage)
|
|
50
|
+
--output FORMAT Output format: text | json, default text
|
|
51
|
+
--project-root DIR Project root directory, default is current directory
|
|
52
|
+
--change-root DIR Change package directory, default is changes
|
|
53
|
+
--help, -h Show this help message
|
|
54
|
+
--version, -v Show version information
|
|
55
|
+
|
|
56
|
+
Algorithm:
|
|
57
|
+
1. Extract all AC-xxx from design.md
|
|
58
|
+
2. Extract AC-xxx referenced in tasks.md
|
|
59
|
+
3. Extract AC-xxx marked in tests/
|
|
60
|
+
4. Calculate: Coverage = (traced AC count) / (total AC count) x 100%
|
|
61
|
+
5. Compare against threshold, return exit code
|
|
62
|
+
|
|
63
|
+
Exit codes:
|
|
64
|
+
0 - Coverage meets threshold
|
|
65
|
+
1 - Coverage below threshold
|
|
66
|
+
2 - Usage error
|
|
67
|
+
|
|
68
|
+
Examples:
|
|
69
|
+
./ac-trace-check.sh my-feature # Default check
|
|
70
|
+
./ac-trace-check.sh my-feature --threshold 90 # 90% threshold
|
|
71
|
+
./ac-trace-check.sh my-feature --output json # JSON output
|
|
72
|
+
./ac-trace-check.sh my-feature --change-root dev-playbooks/changes
|
|
73
|
+
|
|
74
|
+
EOF
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
# Show version
|
|
78
|
+
show_version() {
|
|
79
|
+
echo "ac-trace-check.sh v${VERSION}"
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
# Log functions
|
|
83
|
+
log_info() {
|
|
84
|
+
[[ "$output_format" == "text" ]] && echo -e "${BLUE}[INFO]${NC} $*" >&2
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
log_pass() {
|
|
88
|
+
[[ "$output_format" == "text" ]] && echo -e "${GREEN}[PASS]${NC} $*"
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
log_fail() {
|
|
92
|
+
[[ "$output_format" == "text" ]] && echo -e "${RED}[FAIL]${NC} $*"
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
log_warn() {
|
|
96
|
+
[[ "$output_format" == "text" ]] && echo -e "${YELLOW}[WARN]${NC} $*"
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
# Extract AC-IDs
|
|
100
|
+
extract_ac_ids() {
|
|
101
|
+
local file="$1"
|
|
102
|
+
grep -oE "AC-[A-Z0-9]+" "$file" 2>/dev/null | sort -u || true
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
# Extract AC-IDs from directory
|
|
106
|
+
extract_ac_ids_from_dir() {
|
|
107
|
+
local dir="$1"
|
|
108
|
+
local pattern="${2:-*.test.*}"
|
|
109
|
+
find "$dir" -type f \( -name "*.test.ts" -o -name "*.test.js" -o -name "*.spec.ts" -o -name "*.spec.js" -o -name "*.bats" -o -name "*_test.py" -o -name "*_test.go" \) 2>/dev/null | while read -r file; do
|
|
110
|
+
grep -oE "AC-[A-Z0-9]+" "$file" 2>/dev/null || true
|
|
111
|
+
done | sort -u
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
# Calculate coverage
|
|
115
|
+
calculate_coverage() {
|
|
116
|
+
local design_acs="$1"
|
|
117
|
+
local tasks_acs="$2"
|
|
118
|
+
local test_acs="$3"
|
|
119
|
+
|
|
120
|
+
# Get AC lists
|
|
121
|
+
local design_list=()
|
|
122
|
+
local tasks_list=()
|
|
123
|
+
local test_list=()
|
|
124
|
+
local covered_list=()
|
|
125
|
+
local uncovered_list=()
|
|
126
|
+
|
|
127
|
+
while IFS= read -r ac; do
|
|
128
|
+
[[ -n "$ac" ]] && design_list+=("$ac")
|
|
129
|
+
done <<< "$design_acs"
|
|
130
|
+
|
|
131
|
+
while IFS= read -r ac; do
|
|
132
|
+
[[ -n "$ac" ]] && tasks_list+=("$ac")
|
|
133
|
+
done <<< "$tasks_acs"
|
|
134
|
+
|
|
135
|
+
while IFS= read -r ac; do
|
|
136
|
+
[[ -n "$ac" ]] && test_list+=("$ac")
|
|
137
|
+
done <<< "$test_acs"
|
|
138
|
+
|
|
139
|
+
local total=${#design_list[@]}
|
|
140
|
+
|
|
141
|
+
if [[ $total -eq 0 ]]; then
|
|
142
|
+
# No ACs, count as 100% coverage
|
|
143
|
+
echo "100 0 0"
|
|
144
|
+
return
|
|
145
|
+
fi
|
|
146
|
+
|
|
147
|
+
# Calculate covered ACs
|
|
148
|
+
local covered=0
|
|
149
|
+
for ac in "${design_list[@]}"; do
|
|
150
|
+
local in_test=false
|
|
151
|
+
for test_ac in "${test_list[@]}"; do
|
|
152
|
+
if [[ "$ac" == "$test_ac" ]]; then
|
|
153
|
+
in_test=true
|
|
154
|
+
covered_list+=("$ac")
|
|
155
|
+
break
|
|
156
|
+
fi
|
|
157
|
+
done
|
|
158
|
+
if [[ "$in_test" == false ]]; then
|
|
159
|
+
uncovered_list+=("$ac")
|
|
160
|
+
else
|
|
161
|
+
covered=$((covered + 1))
|
|
162
|
+
fi
|
|
163
|
+
done
|
|
164
|
+
|
|
165
|
+
local rate=0
|
|
166
|
+
if [[ $total -gt 0 ]]; then
|
|
167
|
+
rate=$((covered * 100 / total))
|
|
168
|
+
fi
|
|
169
|
+
|
|
170
|
+
echo "$rate $covered $total"
|
|
171
|
+
|
|
172
|
+
# Output uncovered list to stderr
|
|
173
|
+
if [[ ${#uncovered_list[@]} -gt 0 && "$output_format" == "text" ]]; then
|
|
174
|
+
echo "uncovered: ${uncovered_list[*]}" >&2
|
|
175
|
+
fi
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
# Main function
|
|
179
|
+
main() {
|
|
180
|
+
local change_id=""
|
|
181
|
+
|
|
182
|
+
# Parse arguments
|
|
183
|
+
while [[ $# -gt 0 ]]; do
|
|
184
|
+
case "$1" in
|
|
185
|
+
--help|-h)
|
|
186
|
+
show_help
|
|
187
|
+
exit 0
|
|
188
|
+
;;
|
|
189
|
+
--version|-v)
|
|
190
|
+
show_version
|
|
191
|
+
exit 0
|
|
192
|
+
;;
|
|
193
|
+
--threshold)
|
|
194
|
+
threshold="${2:-80}"
|
|
195
|
+
shift 2
|
|
196
|
+
;;
|
|
197
|
+
--output)
|
|
198
|
+
output_format="${2:-text}"
|
|
199
|
+
shift 2
|
|
200
|
+
;;
|
|
201
|
+
--project-root)
|
|
202
|
+
project_root="${2:-.}"
|
|
203
|
+
shift 2
|
|
204
|
+
;;
|
|
205
|
+
--change-root)
|
|
206
|
+
change_root="${2:-changes}"
|
|
207
|
+
shift 2
|
|
208
|
+
;;
|
|
209
|
+
-*)
|
|
210
|
+
echo "error: unknown option: $1" >&2
|
|
211
|
+
echo "Use --help for usage" >&2
|
|
212
|
+
exit 2
|
|
213
|
+
;;
|
|
214
|
+
*)
|
|
215
|
+
change_id="$1"
|
|
216
|
+
shift
|
|
217
|
+
;;
|
|
218
|
+
esac
|
|
219
|
+
done
|
|
220
|
+
|
|
221
|
+
# Validate arguments
|
|
222
|
+
if [[ -z "$change_id" ]]; then
|
|
223
|
+
echo "error: missing change-id" >&2
|
|
224
|
+
echo "Use --help for usage" >&2
|
|
225
|
+
exit 2
|
|
226
|
+
fi
|
|
227
|
+
|
|
228
|
+
# Build paths
|
|
229
|
+
local change_dir
|
|
230
|
+
if [[ "$change_root" = /* ]]; then
|
|
231
|
+
change_dir="${change_root}/${change_id}"
|
|
232
|
+
else
|
|
233
|
+
change_dir="${project_root}/${change_root}/${change_id}"
|
|
234
|
+
fi
|
|
235
|
+
|
|
236
|
+
local design_file="${change_dir}/design.md"
|
|
237
|
+
local tasks_file="${change_dir}/tasks.md"
|
|
238
|
+
local tests_dir="${project_root}/tests"
|
|
239
|
+
|
|
240
|
+
log_info "Checking change package: ${change_id}"
|
|
241
|
+
log_info "Design file: ${design_file}"
|
|
242
|
+
log_info "Tasks file: ${tasks_file}"
|
|
243
|
+
log_info "Tests directory: ${tests_dir}"
|
|
244
|
+
|
|
245
|
+
# Check file exists
|
|
246
|
+
if [[ ! -f "$design_file" ]]; then
|
|
247
|
+
if [[ "$output_format" == "json" ]]; then
|
|
248
|
+
echo '{"error": "design.md not found", "coverage": 0}'
|
|
249
|
+
else
|
|
250
|
+
log_fail "design.md does not exist: ${design_file}"
|
|
251
|
+
fi
|
|
252
|
+
exit 1
|
|
253
|
+
fi
|
|
254
|
+
|
|
255
|
+
# Extract AC-IDs
|
|
256
|
+
local design_acs tasks_acs test_acs
|
|
257
|
+
|
|
258
|
+
design_acs=$(extract_ac_ids "$design_file")
|
|
259
|
+
tasks_acs=""
|
|
260
|
+
if [[ -f "$tasks_file" ]]; then
|
|
261
|
+
tasks_acs=$(extract_ac_ids "$tasks_file")
|
|
262
|
+
fi
|
|
263
|
+
|
|
264
|
+
test_acs=""
|
|
265
|
+
if [[ -d "$tests_dir" ]]; then
|
|
266
|
+
test_acs=$(extract_ac_ids_from_dir "$tests_dir")
|
|
267
|
+
fi
|
|
268
|
+
|
|
269
|
+
# Calculate coverage
|
|
270
|
+
local result
|
|
271
|
+
result=$(calculate_coverage "$design_acs" "$tasks_acs" "$test_acs")
|
|
272
|
+
read -r rate covered total <<< "$result"
|
|
273
|
+
|
|
274
|
+
# Output results
|
|
275
|
+
if [[ "$output_format" == "json" ]]; then
|
|
276
|
+
local uncovered_json="[]"
|
|
277
|
+
# Recalculate uncovered list
|
|
278
|
+
local uncovered_acs=""
|
|
279
|
+
while IFS= read -r ac; do
|
|
280
|
+
[[ -z "$ac" ]] && continue
|
|
281
|
+
if ! echo "$test_acs" | grep -qx "$ac"; then
|
|
282
|
+
if [[ -z "$uncovered_acs" ]]; then
|
|
283
|
+
uncovered_acs="\"$ac\""
|
|
284
|
+
else
|
|
285
|
+
uncovered_acs="${uncovered_acs},\"$ac\""
|
|
286
|
+
fi
|
|
287
|
+
fi
|
|
288
|
+
done <<< "$design_acs"
|
|
289
|
+
|
|
290
|
+
cat << EOF
|
|
291
|
+
{
|
|
292
|
+
"change_id": "${change_id}",
|
|
293
|
+
"coverage": ${rate},
|
|
294
|
+
"threshold": ${threshold},
|
|
295
|
+
"covered": ${covered},
|
|
296
|
+
"total": ${total},
|
|
297
|
+
"uncovered": [${uncovered_acs}],
|
|
298
|
+
"pass": $([ "$rate" -ge "$threshold" ] && echo "true" || echo "false")
|
|
299
|
+
}
|
|
300
|
+
EOF
|
|
301
|
+
else
|
|
302
|
+
echo ""
|
|
303
|
+
echo "AC Traceability Coverage Report"
|
|
304
|
+
echo "================================"
|
|
305
|
+
echo "Change package: ${change_id}"
|
|
306
|
+
echo "Total ACs: ${total}"
|
|
307
|
+
echo "Covered: ${covered}"
|
|
308
|
+
echo "Coverage: ${rate}%"
|
|
309
|
+
echo "Threshold: ${threshold}%"
|
|
310
|
+
echo ""
|
|
311
|
+
|
|
312
|
+
if [[ $rate -ge $threshold ]]; then
|
|
313
|
+
log_pass "Coverage ${rate}% >= ${threshold}%, check passed"
|
|
314
|
+
exit 0
|
|
315
|
+
else
|
|
316
|
+
log_fail "Coverage ${rate}% < ${threshold}%, check failed"
|
|
317
|
+
exit 1
|
|
318
|
+
fi
|
|
319
|
+
fi
|
|
320
|
+
|
|
321
|
+
# Exit code for JSON mode
|
|
322
|
+
if [[ $rate -ge $threshold ]]; then
|
|
323
|
+
exit 0
|
|
324
|
+
else
|
|
325
|
+
exit 1
|
|
326
|
+
fi
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
# Run main function
|
|
330
|
+
main "$@"
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# audit-scope.sh - Provide full-scope audit scanning for precision improvement
|
|
3
|
+
#
|
|
4
|
+
# This script scans a directory and outputs metrics for audit purposes:
|
|
5
|
+
# - File count by type
|
|
6
|
+
# - Line count
|
|
7
|
+
# - Complexity metrics (if available)
|
|
8
|
+
# - Hotspot file list (high churn + high complexity)
|
|
9
|
+
#
|
|
10
|
+
# Reference: harden-devbooks-quality-gates design.md AC-011
|
|
11
|
+
|
|
12
|
+
set -euo pipefail
|
|
13
|
+
|
|
14
|
+
usage() {
|
|
15
|
+
cat <<'EOF' >&2
|
|
16
|
+
usage: audit-scope.sh <directory> [options]
|
|
17
|
+
|
|
18
|
+
Provide full-scope audit scanning for a directory:
|
|
19
|
+
- File count by type
|
|
20
|
+
- Total line count
|
|
21
|
+
- Complexity metrics (if tools available)
|
|
22
|
+
- Hotspot identification
|
|
23
|
+
|
|
24
|
+
Options:
|
|
25
|
+
--format <fmt> Output format: text (default), markdown, json
|
|
26
|
+
--exclude <pat> Exclude pattern (can be used multiple times)
|
|
27
|
+
-h, --help Show this help message
|
|
28
|
+
|
|
29
|
+
Exit Codes:
|
|
30
|
+
0 - Scan completed successfully
|
|
31
|
+
1 - Scan error or directory not found
|
|
32
|
+
2 - Usage error
|
|
33
|
+
|
|
34
|
+
Examples:
|
|
35
|
+
audit-scope.sh src/
|
|
36
|
+
audit-scope.sh src/ --format markdown
|
|
37
|
+
audit-scope.sh src/ --format json --exclude node_modules
|
|
38
|
+
EOF
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if [[ $# -eq 0 ]]; then
|
|
42
|
+
usage
|
|
43
|
+
exit 2
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
|
|
47
|
+
usage
|
|
48
|
+
exit 0
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
target_dir="$1"
|
|
52
|
+
shift
|
|
53
|
+
|
|
54
|
+
output_format="text"
|
|
55
|
+
declare -a exclude_patterns=()
|
|
56
|
+
|
|
57
|
+
while [[ $# -gt 0 ]]; do
|
|
58
|
+
case "$1" in
|
|
59
|
+
-h|--help)
|
|
60
|
+
usage
|
|
61
|
+
exit 0
|
|
62
|
+
;;
|
|
63
|
+
--format)
|
|
64
|
+
output_format="${2:-text}"
|
|
65
|
+
shift 2
|
|
66
|
+
;;
|
|
67
|
+
--exclude)
|
|
68
|
+
exclude_patterns+=("${2:-}")
|
|
69
|
+
shift 2
|
|
70
|
+
;;
|
|
71
|
+
*)
|
|
72
|
+
echo "error: unknown option: $1" >&2
|
|
73
|
+
usage
|
|
74
|
+
exit 2
|
|
75
|
+
;;
|
|
76
|
+
esac
|
|
77
|
+
done
|
|
78
|
+
|
|
79
|
+
# Validate format
|
|
80
|
+
case "$output_format" in
|
|
81
|
+
text|markdown|json) ;;
|
|
82
|
+
*)
|
|
83
|
+
echo "error: invalid --format: '$output_format' (use: text, markdown, json)" >&2
|
|
84
|
+
exit 2
|
|
85
|
+
;;
|
|
86
|
+
esac
|
|
87
|
+
|
|
88
|
+
# Check directory exists
|
|
89
|
+
if [[ ! -d "$target_dir" ]]; then
|
|
90
|
+
echo "error: directory not found: ${target_dir}" >&2
|
|
91
|
+
exit 1
|
|
92
|
+
fi
|
|
93
|
+
|
|
94
|
+
# Build find exclude arguments as array
|
|
95
|
+
declare -a find_exclude_args=()
|
|
96
|
+
if [[ ${#exclude_patterns[@]} -gt 0 ]]; then
|
|
97
|
+
for pat in "${exclude_patterns[@]}"; do
|
|
98
|
+
find_exclude_args+=(-not -path "*/${pat}/*")
|
|
99
|
+
done
|
|
100
|
+
fi
|
|
101
|
+
|
|
102
|
+
# =============================================================================
|
|
103
|
+
# Collect Metrics
|
|
104
|
+
# =============================================================================
|
|
105
|
+
|
|
106
|
+
# Count files by type
|
|
107
|
+
count_files() {
|
|
108
|
+
local ext="$1"
|
|
109
|
+
find "$target_dir" -type f -name "*.$ext" ${find_exclude_args[@]+"${find_exclude_args[@]}"} 2>/dev/null | wc -l | tr -d ' '
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
# Count total lines
|
|
113
|
+
count_lines() {
|
|
114
|
+
local ext="$1"
|
|
115
|
+
find "$target_dir" -type f -name "*.$ext" ${find_exclude_args[@]+"${find_exclude_args[@]}"} -exec cat {} \; 2>/dev/null | wc -l | tr -d ' '
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
# Total file count
|
|
119
|
+
total_files=$(find "$target_dir" -type f ${find_exclude_args[@]+"${find_exclude_args[@]}"} 2>/dev/null | wc -l | tr -d ' ')
|
|
120
|
+
|
|
121
|
+
# Count by common types
|
|
122
|
+
sh_count=$(count_files "sh")
|
|
123
|
+
ts_count=$(count_files "ts")
|
|
124
|
+
js_count=$(count_files "js")
|
|
125
|
+
md_count=$(count_files "md")
|
|
126
|
+
yml_count=$(count_files "yml")
|
|
127
|
+
yaml_count=$(count_files "yaml")
|
|
128
|
+
json_count=$(count_files "json")
|
|
129
|
+
py_count=$(count_files "py")
|
|
130
|
+
|
|
131
|
+
# Line counts
|
|
132
|
+
sh_lines=$(count_lines "sh")
|
|
133
|
+
ts_lines=$(count_lines "ts")
|
|
134
|
+
js_lines=$(count_lines "js")
|
|
135
|
+
|
|
136
|
+
# Total lines (for major code types)
|
|
137
|
+
total_lines=$((sh_lines + ts_lines + js_lines))
|
|
138
|
+
|
|
139
|
+
# Identify potential hotspots (largest files)
|
|
140
|
+
hotspots=""
|
|
141
|
+
if command -v wc >/dev/null 2>&1; then
|
|
142
|
+
hotspots=$(find "$target_dir" -type f \( -name "*.sh" -o -name "*.ts" -o -name "*.js" -o -name "*.py" \) ${find_exclude_args[@]+"${find_exclude_args[@]}"} -exec wc -l {} \; 2>/dev/null | sort -rn | head -10)
|
|
143
|
+
fi
|
|
144
|
+
|
|
145
|
+
# =============================================================================
|
|
146
|
+
# Output
|
|
147
|
+
# =============================================================================
|
|
148
|
+
|
|
149
|
+
case "$output_format" in
|
|
150
|
+
text)
|
|
151
|
+
echo "=================================================="
|
|
152
|
+
echo "Audit Scope: ${target_dir}"
|
|
153
|
+
echo "=================================================="
|
|
154
|
+
echo ""
|
|
155
|
+
echo "## File Count Summary"
|
|
156
|
+
echo " Total files: ${total_files}"
|
|
157
|
+
echo " Shell (.sh): ${sh_count}"
|
|
158
|
+
echo " TypeScript (.ts): ${ts_count}"
|
|
159
|
+
echo " JavaScript (.js): ${js_count}"
|
|
160
|
+
echo " Markdown (.md): ${md_count}"
|
|
161
|
+
echo " YAML (.yml/.yaml): $((yml_count + yaml_count))"
|
|
162
|
+
echo " JSON (.json): ${json_count}"
|
|
163
|
+
echo " Python (.py): ${py_count}"
|
|
164
|
+
echo ""
|
|
165
|
+
echo "## Line Count (Code)"
|
|
166
|
+
echo " Shell: ${sh_lines}"
|
|
167
|
+
echo " TypeScript: ${ts_lines}"
|
|
168
|
+
echo " JavaScript: ${js_lines}"
|
|
169
|
+
echo " Total: ${total_lines}"
|
|
170
|
+
echo ""
|
|
171
|
+
echo "## Potential Hotspots (Top 10 by line count)"
|
|
172
|
+
if [[ -n "$hotspots" ]]; then
|
|
173
|
+
echo "$hotspots" | while read -r line; do
|
|
174
|
+
echo " $line"
|
|
175
|
+
done
|
|
176
|
+
else
|
|
177
|
+
echo " (no code files found)"
|
|
178
|
+
fi
|
|
179
|
+
echo ""
|
|
180
|
+
;;
|
|
181
|
+
|
|
182
|
+
markdown)
|
|
183
|
+
echo "# Audit Scope: ${target_dir}"
|
|
184
|
+
echo ""
|
|
185
|
+
echo "## File Count Summary"
|
|
186
|
+
echo ""
|
|
187
|
+
echo "| Type | Count |"
|
|
188
|
+
echo "|------|-------|"
|
|
189
|
+
echo "| Total | ${total_files} |"
|
|
190
|
+
echo "| Shell (.sh) | ${sh_count} |"
|
|
191
|
+
echo "| TypeScript (.ts) | ${ts_count} |"
|
|
192
|
+
echo "| JavaScript (.js) | ${js_count} |"
|
|
193
|
+
echo "| Markdown (.md) | ${md_count} |"
|
|
194
|
+
echo "| YAML | $((yml_count + yaml_count)) |"
|
|
195
|
+
echo "| JSON | ${json_count} |"
|
|
196
|
+
echo "| Python (.py) | ${py_count} |"
|
|
197
|
+
echo ""
|
|
198
|
+
echo "## Line Count (Code)"
|
|
199
|
+
echo ""
|
|
200
|
+
echo "| Type | Lines |"
|
|
201
|
+
echo "|------|-------|"
|
|
202
|
+
echo "| Shell | ${sh_lines} |"
|
|
203
|
+
echo "| TypeScript | ${ts_lines} |"
|
|
204
|
+
echo "| JavaScript | ${js_lines} |"
|
|
205
|
+
echo "| **Total** | **${total_lines}** |"
|
|
206
|
+
echo ""
|
|
207
|
+
echo "## Potential Hotspots"
|
|
208
|
+
echo ""
|
|
209
|
+
if [[ -n "$hotspots" ]]; then
|
|
210
|
+
echo "| Lines | File |"
|
|
211
|
+
echo "|-------|------|"
|
|
212
|
+
echo "$hotspots" | while read -r lines file; do
|
|
213
|
+
echo "| ${lines} | ${file} |"
|
|
214
|
+
done
|
|
215
|
+
else
|
|
216
|
+
echo "(no code files found)"
|
|
217
|
+
fi
|
|
218
|
+
;;
|
|
219
|
+
|
|
220
|
+
json)
|
|
221
|
+
# Build hotspots JSON array
|
|
222
|
+
hotspots_json="[]"
|
|
223
|
+
if [[ -n "$hotspots" ]]; then
|
|
224
|
+
hotspots_json="["
|
|
225
|
+
first=true
|
|
226
|
+
while read -r lines file; do
|
|
227
|
+
if [[ "$first" == true ]]; then
|
|
228
|
+
first=false
|
|
229
|
+
else
|
|
230
|
+
hotspots_json+=","
|
|
231
|
+
fi
|
|
232
|
+
hotspots_json+="{\"lines\":${lines},\"file\":\"${file}\"}"
|
|
233
|
+
done <<< "$hotspots"
|
|
234
|
+
hotspots_json+="]"
|
|
235
|
+
fi
|
|
236
|
+
|
|
237
|
+
cat << EOF
|
|
238
|
+
{
|
|
239
|
+
"directory": "${target_dir}",
|
|
240
|
+
"fileCount": {
|
|
241
|
+
"total": ${total_files},
|
|
242
|
+
"shell": ${sh_count},
|
|
243
|
+
"typescript": ${ts_count},
|
|
244
|
+
"javascript": ${js_count},
|
|
245
|
+
"markdown": ${md_count},
|
|
246
|
+
"yaml": $((yml_count + yaml_count)),
|
|
247
|
+
"json": ${json_count},
|
|
248
|
+
"python": ${py_count}
|
|
249
|
+
},
|
|
250
|
+
"lineCount": {
|
|
251
|
+
"shell": ${sh_lines},
|
|
252
|
+
"typescript": ${ts_lines},
|
|
253
|
+
"javascript": ${js_lines},
|
|
254
|
+
"total": ${total_lines}
|
|
255
|
+
},
|
|
256
|
+
"hotspots": ${hotspots_json}
|
|
257
|
+
}
|
|
258
|
+
EOF
|
|
259
|
+
;;
|
|
260
|
+
esac
|
|
261
|
+
|
|
262
|
+
exit 0
|