agentic-sdlc-wizard 1.37.0 → 1.37.1
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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +6 -0
- package/CLAUDE_CODE_SDLC_WIZARD.md +2 -2
- package/hooks/_find-sdlc-root.sh +59 -0
- package/hooks/instructions-loaded-check.sh +3 -0
- package/hooks/model-effort-check.sh +7 -0
- package/hooks/precompact-seam-check.sh +9 -0
- package/hooks/sdlc-prompt-check.sh +6 -0
- package/hooks/tdd-pretool-check.sh +9 -0
- package/package.json +1 -1
- package/skills/update/SKILL.md +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,12 @@ All notable changes to the SDLC Wizard.
|
|
|
4
4
|
|
|
5
5
|
> **Note:** This changelog is for humans to read. Don't manually apply these changes - just run the wizard ("Check for SDLC wizard updates") and it handles everything automatically.
|
|
6
6
|
|
|
7
|
+
## [1.37.1] - 2026-04-24
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **Dual-channel hook 2× print** (token-bloat audit, ROADMAP item 8, PR #241). When both the project's `.claude/settings.json` AND a locally-installed wizard plugin (`~/.claude/plugins-local/` or `~/.claude/plugins/cache/`) registered the same hook, both fired per event — `SDLC BASELINE` block printed twice per `UserPromptSubmit`, ~300 tokens doubled per prompt. Fix: `dedupe_plugin_or_project()` helper in `hooks/_find-sdlc-root.sh`. Plugin invocation yields if project also registers the same hook by name (project always wins). Wired into all 5 hooks (sdlc-prompt-check, instructions-loaded-check, tdd-pretool-check, model-effort-check, precompact-seam-check). Consumer plugin-only installs still fire normally. Codex 2-round: 100/100 CERTIFIED. 9 new dedupe tests + 1 stale-fixture fix (test_instructions_hook_cwd_walkup now reads current version dynamically from package.json so it doesn't drift past the staleness-nudge threshold on each release).
|
|
12
|
+
|
|
7
13
|
## [1.37.0] - 2026-04-24
|
|
8
14
|
|
|
9
15
|
### Changed
|
|
@@ -2715,7 +2715,7 @@ If deployment fails or post-deploy verification catches issues:
|
|
|
2715
2715
|
|
|
2716
2716
|
**SDLC.md:**
|
|
2717
2717
|
```markdown
|
|
2718
|
-
<!-- SDLC Wizard Version: 1.37.
|
|
2718
|
+
<!-- SDLC Wizard Version: 1.37.1 -->
|
|
2719
2719
|
<!-- Setup Date: [DATE] -->
|
|
2720
2720
|
<!-- Completed Steps: step-0.1, step-0.2, step-0.4, step-1, step-2, step-3, step-4, step-5, step-6, step-7, step-8, step-9 -->
|
|
2721
2721
|
<!-- Git Workflow: [PRs or Solo] -->
|
|
@@ -3777,7 +3777,7 @@ Walk through updates? (y/n)
|
|
|
3777
3777
|
Store wizard state in `SDLC.md` as metadata comments (invisible to readers, parseable by Claude):
|
|
3778
3778
|
|
|
3779
3779
|
```markdown
|
|
3780
|
-
<!-- SDLC Wizard Version: 1.37.
|
|
3780
|
+
<!-- SDLC Wizard Version: 1.37.1 -->
|
|
3781
3781
|
<!-- Setup Date: 2026-01-24 -->
|
|
3782
3782
|
<!-- Completed Steps: step-0.1, step-0.2, step-1, step-2, step-3, step-4, step-5, step-6, step-7, step-8, step-9 -->
|
|
3783
3783
|
<!-- Git Workflow: PRs -->
|
package/hooks/_find-sdlc-root.sh
CHANGED
|
@@ -34,3 +34,62 @@ find_partial_sdlc_root() {
|
|
|
34
34
|
done
|
|
35
35
|
return 1
|
|
36
36
|
}
|
|
37
|
+
|
|
38
|
+
# dedupe_plugin_or_project — token-bloat fix.
|
|
39
|
+
# When a hook is registered via BOTH the project's `.claude/settings.json` AND
|
|
40
|
+
# a locally-installed wizard plugin (e.g., maintainer dogfooding the wizard
|
|
41
|
+
# while also having `~/.claude/plugins-local/sdlc-wizard-wrap/`), the same
|
|
42
|
+
# script fires twice per event = 2× tokens per prompt, 2× hook output noise.
|
|
43
|
+
#
|
|
44
|
+
# Resolution: plugin invocation yields if the project also registers the
|
|
45
|
+
# same hook by name. Project registration always wins (user-explicit).
|
|
46
|
+
# Consumer plugin-only installs (no project settings.json) still fire normally.
|
|
47
|
+
#
|
|
48
|
+
# Plugin path heuristic: $0 contains "/plugins-local/" or "/plugins/cache/".
|
|
49
|
+
#
|
|
50
|
+
# Usage:
|
|
51
|
+
# source _find-sdlc-root.sh
|
|
52
|
+
# dedupe_plugin_or_project || exit 0 # plugin yields when project registered
|
|
53
|
+
#
|
|
54
|
+
# Args (optional, for tests): $1 script_path, $2 project_dir
|
|
55
|
+
# Returns: 0 = proceed, 1 = yield (caller should exit 0).
|
|
56
|
+
#
|
|
57
|
+
# Codex review hardening (DEDUPE-001/002):
|
|
58
|
+
# - Uses parameter expansion (${path##*/}) instead of `basename` — survives
|
|
59
|
+
# PATH-restricted environments. Falsely emitting `basename: command not found`
|
|
60
|
+
# would corrupt the rc=1 (yield) signal.
|
|
61
|
+
# - Matches the script name only inside a `"command"` JSON field, not anywhere
|
|
62
|
+
# in the settings file. Otherwise a basename mentioned in `permissions.allow`
|
|
63
|
+
# or a comment would falsely trigger yield (plugin would skip when project
|
|
64
|
+
# never actually registers the hook).
|
|
65
|
+
dedupe_plugin_or_project() {
|
|
66
|
+
local script_path="${1:-${BASH_SOURCE[1]:-$0}}"
|
|
67
|
+
local project_dir="${2:-${CLAUDE_PROJECT_DIR:-.}}"
|
|
68
|
+
|
|
69
|
+
case "$script_path" in
|
|
70
|
+
*/plugins-local/*|*/plugins/cache/*)
|
|
71
|
+
local proj_settings="$project_dir/.claude/settings.json"
|
|
72
|
+
[ -f "$proj_settings" ] || return 0
|
|
73
|
+
|
|
74
|
+
# Parameter-expansion basename: ${path##*/} strips up to last /.
|
|
75
|
+
# If no / in path, returns path itself (defensive — caller passed
|
|
76
|
+
# bare filename).
|
|
77
|
+
local script_name="${script_path##*/}"
|
|
78
|
+
[ -n "$script_name" ] || return 0
|
|
79
|
+
|
|
80
|
+
# Match only inside a "command" JSON registration so a basename
|
|
81
|
+
# appearing in permissions.allow / comments / unrelated sections
|
|
82
|
+
# doesn't falsely yield. Pattern: `"command"` followed by colon,
|
|
83
|
+
# any whitespace, optional quotes, anything, then the basename.
|
|
84
|
+
# Example matches:
|
|
85
|
+
# "command": "$CLAUDE_PROJECT_DIR/hooks/sdlc-prompt-check.sh"
|
|
86
|
+
# "command":"hooks/sdlc-prompt-check.sh"
|
|
87
|
+
# Does NOT match:
|
|
88
|
+
# "Bash(./hooks/sdlc-prompt-check.sh *)" (in permissions.allow)
|
|
89
|
+
if grep -qE '"command"[[:space:]]*:[[:space:]]*"[^"]*'"$script_name"'"' "$proj_settings" 2>/dev/null; then
|
|
90
|
+
return 1 # yield — project will fire its own copy
|
|
91
|
+
fi
|
|
92
|
+
;;
|
|
93
|
+
esac
|
|
94
|
+
return 0 # proceed
|
|
95
|
+
}
|
|
@@ -8,6 +8,9 @@
|
|
|
8
8
|
HOOK_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
9
9
|
source "$HOOK_DIR/_find-sdlc-root.sh"
|
|
10
10
|
|
|
11
|
+
# Token-bloat fix: when both project + plugin register this hook, plugin yields.
|
|
12
|
+
dedupe_plugin_or_project "${BASH_SOURCE[0]}" || exit 0
|
|
13
|
+
|
|
11
14
|
# CWD walk-up finds nearest SDLC project (#173: silent exit for non-SDLC dirs)
|
|
12
15
|
if find_sdlc_root; then
|
|
13
16
|
PROJECT_DIR="$SDLC_ROOT"
|
|
@@ -15,6 +15,13 @@
|
|
|
15
15
|
|
|
16
16
|
RECOMMENDED_MODEL="opus[1m]"
|
|
17
17
|
|
|
18
|
+
# Token-bloat fix: when both project + plugin register this hook, plugin yields.
|
|
19
|
+
HOOK_DIR="${BASH_SOURCE[0]%/*}"
|
|
20
|
+
[ "$HOOK_DIR" = "${BASH_SOURCE[0]}" ] && HOOK_DIR="."
|
|
21
|
+
# shellcheck disable=SC1091
|
|
22
|
+
source "$HOOK_DIR/_find-sdlc-root.sh"
|
|
23
|
+
dedupe_plugin_or_project "${BASH_SOURCE[0]}" || { cat > /dev/null; exit 0; }
|
|
24
|
+
|
|
18
25
|
# Drain stdin (SessionStart sends JSON but model field isn't in it)
|
|
19
26
|
cat > /dev/null
|
|
20
27
|
|
|
@@ -14,6 +14,15 @@
|
|
|
14
14
|
# → finish in-progress git operation first
|
|
15
15
|
# Allow otherwise.
|
|
16
16
|
|
|
17
|
+
# Token-bloat fix: when both project + plugin register this hook, plugin yields.
|
|
18
|
+
# Use parameter expansion (not `dirname`) so the PATH-restricted gh-missing test
|
|
19
|
+
# still works — bash builtin `${var%/*}` is always available.
|
|
20
|
+
HOOK_DIR="${BASH_SOURCE[0]%/*}"
|
|
21
|
+
[ "$HOOK_DIR" = "${BASH_SOURCE[0]}" ] && HOOK_DIR="."
|
|
22
|
+
# shellcheck disable=SC1091
|
|
23
|
+
source "$HOOK_DIR/_find-sdlc-root.sh"
|
|
24
|
+
dedupe_plugin_or_project "${BASH_SOURCE[0]}" || { [ ! -t 0 ] && cat > /dev/null; exit 0; }
|
|
25
|
+
|
|
17
26
|
[ ! -t 0 ] && INPUT=$(cat) || INPUT=""
|
|
18
27
|
|
|
19
28
|
# Determine project root: prefer $CLAUDE_PROJECT_DIR, fall back to cwd
|
|
@@ -6,6 +6,12 @@
|
|
|
6
6
|
HOOK_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
7
7
|
source "$HOOK_DIR/_find-sdlc-root.sh"
|
|
8
8
|
|
|
9
|
+
# Token-bloat fix: when both project + plugin register this hook, plugin yields.
|
|
10
|
+
# Prevents 2× SDLC BASELINE print per UserPromptSubmit (~300 tokens doubled).
|
|
11
|
+
# Pass real script path explicitly (not $0) so the dedupe heuristic recognizes
|
|
12
|
+
# plugin paths even when the script is sourced or invoked via aliases.
|
|
13
|
+
dedupe_plugin_or_project "${BASH_SOURCE[0]}" || exit 0
|
|
14
|
+
|
|
9
15
|
# CWD walk-up finds nearest SDLC project (#173: silent exit for non-SDLC dirs)
|
|
10
16
|
if find_sdlc_root; then
|
|
11
17
|
PROJECT_DIR="$SDLC_ROOT"
|
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
# PreToolUse hook - TDD enforcement before editing source files
|
|
3
3
|
# Fires before Write/Edit/MultiEdit tools
|
|
4
4
|
|
|
5
|
+
# Token-bloat fix: when both project + plugin register this hook, plugin yields.
|
|
6
|
+
# Parameter-expansion-safe (no `dirname` dep): `%/*` strips trailing `/file`.
|
|
7
|
+
# Fallback `.` when BASH_SOURCE has no slash (direct invocation `bash hook.sh`).
|
|
8
|
+
HOOK_DIR="${BASH_SOURCE[0]%/*}"
|
|
9
|
+
[ "$HOOK_DIR" = "${BASH_SOURCE[0]}" ] && HOOK_DIR="."
|
|
10
|
+
# shellcheck disable=SC1091
|
|
11
|
+
source "$HOOK_DIR/_find-sdlc-root.sh"
|
|
12
|
+
dedupe_plugin_or_project "${BASH_SOURCE[0]}" || exit 0
|
|
13
|
+
|
|
5
14
|
# Read the tool input (JSON with file_path, content, etc.)
|
|
6
15
|
TOOL_INPUT=$(cat)
|
|
7
16
|
|
package/package.json
CHANGED
package/skills/update/SKILL.md
CHANGED
|
@@ -46,9 +46,10 @@ Parse all CHANGELOG entries between the user's installed version and the latest.
|
|
|
46
46
|
|
|
47
47
|
```
|
|
48
48
|
Installed: 1.24.0
|
|
49
|
-
Latest: 1.37.
|
|
49
|
+
Latest: 1.37.1
|
|
50
50
|
|
|
51
51
|
What changed:
|
|
52
|
+
- [1.37.1] Token-bloat fix: dedupe 2× SDLC BASELINE print when both project + plugin register the same hook (~300 tokens doubled per prompt). 5 hooks gain `dedupe_plugin_or_project()` helper. Codex 2-round 100/100.
|
|
52
53
|
- [1.37.0] `monthly-research.yml` workflow deleted (ROADMAP #231 Phase 1) — 0 merged artifacts in 30d while burning $11-23/month; research happens inline now. `model-effort-check.sh` loud WARNING below xhigh (#217) — max preferred, xhigh floor; duplicate effort nudge in `instructions-loaded-check.sh` removed; single source of truth. Both changes Codex-certified.
|
|
53
54
|
- [1.36.1] Repo renamed `agentic-ai-sdlc-wizard` → `claude-sdlc-wizard` (matches sibling pattern; npm package unchanged); `npm pkg fix` metadata cleanup; slug migration across docs/tests/configs
|
|
54
55
|
- [1.36.0] CC 2.1.118 `/usage` canonical + aliases, Tier 2 dead-gate fix (#215), score-history max_score correctness (#211), setup-bun regression guard (#210), post-mortem learnings (#220-222), GPT-5.5 adoption plan (#223), MCP-tool hooks + #198 re-verify in backlog (#218/#219)
|