claude-devkit-cli 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.
@@ -0,0 +1,214 @@
1
+ #!/usr/bin/env bash
2
+ # sensitive-guard.sh — PreToolUse hook for Claude Code
3
+ #
4
+ # Blocks access to sensitive files: .env, private keys, credentials, tokens.
5
+ # Supports .agentignore for project-specific patterns.
6
+ #
7
+ # Exit codes:
8
+ # 0 — access allowed
9
+ # 2 — access blocked (sensitive file)
10
+ #
11
+ # Environment:
12
+ # SENSITIVE_GUARD_EXTRA — additional pipe-separated filename patterns to block
13
+
14
+ set -euo pipefail
15
+
16
+ # ─── Read hook payload from stdin ───────────────────────────────────
17
+
18
+ INPUT=$(cat)
19
+ [[ -z "$INPUT" ]] && exit 0
20
+
21
+ # Check Node.js availability — security hook should warn loudly if disabled
22
+ if ! command -v node &>/dev/null; then
23
+ echo "WARNING: sensitive-guard disabled — Node.js not found. Sensitive files are NOT protected." >&2
24
+ exit 0
25
+ fi
26
+
27
+ # Extract file path and/or command using inline Node.js
28
+ PARSED=$(printf '%s' "$INPUT" | node -e "
29
+ try {
30
+ const d = JSON.parse(require('fs').readFileSync(0, 'utf-8'));
31
+ const fp = d.tool_input?.file_path || d.tool_input?.path || '';
32
+ const cmd = d.tool_input?.command || '';
33
+ const pat = d.tool_input?.pattern || '';
34
+ process.stdout.write(fp + '\n' + cmd + '\n' + pat);
35
+ } catch { process.exit(0); }
36
+ " 2>/dev/null) || exit 0
37
+
38
+ FILE_PATH=$(printf '%s' "$PARSED" | sed -n '1p')
39
+ COMMAND=$(printf '%s' "$PARSED" | sed -n '2p')
40
+ PATTERN=$(printf '%s' "$PARSED" | sed -n '3p')
41
+
42
+ # ─── Sensitive filename patterns ────────────────────────────────────
43
+
44
+ # Returns 0 (true) if the path matches a sensitive pattern
45
+ is_sensitive() {
46
+ local filepath="$1"
47
+ local basename
48
+ basename=$(basename "$filepath" 2>/dev/null) || return 1
49
+
50
+ # Exact filenames (basename match)
51
+ case "$basename" in
52
+ .env|.env.local|.env.development|.env.production|.env.staging|.env.test)
53
+ return 0 ;;
54
+ .npmrc|.pypirc|.netrc)
55
+ return 0 ;;
56
+ id_rsa|id_ecdsa|id_ed25519|id_dsa)
57
+ return 0 ;;
58
+ serviceAccountKey.json|service-account*.json)
59
+ return 0 ;;
60
+ .mcp.json|config.json)
61
+ # config.json only sensitive inside .docker/ — check full path
62
+ if [[ "$basename" == "config.json" ]]; then
63
+ [[ "$filepath" == *".docker/config.json"* ]] && return 0
64
+ else
65
+ return 0
66
+ fi
67
+ ;;
68
+ esac
69
+
70
+ # Extension patterns
71
+ case "$basename" in
72
+ *.pem|*.key|*.p12|*.pfx|*.jks|*.keystore|*.truststore)
73
+ return 0 ;;
74
+ *_rsa|*_ecdsa|*_ed25519|*_dsa)
75
+ return 0 ;;
76
+ esac
77
+
78
+ # Substring patterns (case-insensitive via bash)
79
+ local lower
80
+ lower=$(echo "$basename" | tr '[:upper:]' '[:lower:]')
81
+ case "$lower" in
82
+ *credential*|*secret*|*private_key*|*privatekey*)
83
+ return 0 ;;
84
+ firebase-adminsdk*)
85
+ return 0 ;;
86
+ esac
87
+
88
+ # .env.* but NOT .env.example or .env.sample or .env.template
89
+ if [[ "$basename" =~ ^\.env\. ]]; then
90
+ case "$basename" in
91
+ .env.example|.env.sample|.env.template) return 1 ;;
92
+ *) return 0 ;;
93
+ esac
94
+ fi
95
+
96
+ # Extra patterns from env var
97
+ if [[ -n "${SENSITIVE_GUARD_EXTRA:-}" ]]; then
98
+ if printf '%s\n' "$filepath" | grep -qE "$SENSITIVE_GUARD_EXTRA"; then
99
+ return 0
100
+ fi
101
+ fi
102
+
103
+ return 1
104
+ }
105
+
106
+ # ─── Check .agentignore ────────────────────────────────────────────
107
+
108
+ check_agentignore() {
109
+ local filepath="$1"
110
+ local ignorefile=""
111
+
112
+ # Look for ignore files in project root
113
+ for candidate in .agentignore .aiignore .cursorignore; do
114
+ if [[ -f "$candidate" ]]; then
115
+ ignorefile="$candidate"
116
+ break
117
+ fi
118
+ done
119
+
120
+ [[ -z "$ignorefile" ]] && return 1
121
+
122
+ # Simple line-by-line match (not full gitignore glob, but covers common cases)
123
+ local relpath
124
+ relpath=$(echo "$filepath" | sed "s|^$(pwd)/||") 2>/dev/null || relpath="$filepath"
125
+
126
+ while IFS= read -r pattern || [[ -n "$pattern" ]]; do
127
+ # Skip comments and empty lines
128
+ [[ -z "$pattern" || "$pattern" == \#* ]] && continue
129
+ # Simple glob match
130
+ if [[ "$relpath" == $pattern ]] || [[ "$(basename "$relpath")" == $pattern ]]; then
131
+ return 0
132
+ fi
133
+ done < "$ignorefile"
134
+
135
+ return 1
136
+ }
137
+
138
+ # ─── Check file path access ────────────────────────────────────────
139
+
140
+ block_with_message() {
141
+ local filepath="$1"
142
+ echo "Blocked: '$filepath' is a sensitive file (secrets, keys, or credentials). Access denied to protect sensitive data. Use .env.example for templates instead." >&2
143
+ exit 2
144
+ }
145
+
146
+ warn_with_message() {
147
+ local filepath="$1"
148
+ echo "Warning: '$filepath' is a sensitive file. If the user approved this access, proceed. Otherwise, ask the user for permission first via AskUserQuestion before reading sensitive files." >&2
149
+ # Warn only — exit 0 allows the command to proceed
150
+ # This enables the flow: Block Read → Claude asks user → User approves → Claude uses bash cat
151
+ exit 0
152
+ }
153
+
154
+ # ─── Check direct file access (Read/Write/Edit) → BLOCK ────────────
155
+
156
+ if [[ -n "$FILE_PATH" ]]; then
157
+ if is_sensitive "$FILE_PATH" || check_agentignore "$FILE_PATH"; then
158
+ block_with_message "$FILE_PATH"
159
+ fi
160
+ fi
161
+
162
+ # ─── Check bash commands → WARN only (allows approved access) ──────
163
+
164
+ if [[ -n "$COMMAND" ]]; then
165
+ # Extract .env file references from commands
166
+ SENSITIVE_IN_CMD=$(printf '%s\n' "$COMMAND" | grep -oE '[\./[:alnum:]_-]*\.env[\.[:alnum:]_-]*' | head -5) || true
167
+
168
+ if [[ -n "$SENSITIVE_IN_CMD" ]]; then
169
+ while IFS= read -r match; do
170
+ case "$match" in
171
+ *.example|*.sample|*.template) continue ;;
172
+ esac
173
+ if is_sensitive "$match"; then
174
+ warn_with_message "$match"
175
+ fi
176
+ done <<< "$SENSITIVE_IN_CMD"
177
+ fi
178
+
179
+ # Check for key/cert file references in commands → also warn only
180
+ KEY_IN_CMD=$(printf '%s\n' "$COMMAND" | grep -oE '[[:alnum:]_./-]*\.(pem|key|p12|pfx|jks|keystore)' | head -3) || true
181
+ if [[ -n "$KEY_IN_CMD" ]]; then
182
+ while IFS= read -r match; do
183
+ warn_with_message "$match"
184
+ done <<< "$KEY_IN_CMD"
185
+ fi
186
+
187
+ # Check for SSH keys, credentials, service accounts in commands
188
+ SENSITIVE_NAMES=$(printf '%s\n' "$COMMAND" | grep -oiE '(id_rsa|id_ecdsa|id_ed25519|id_dsa|serviceAccountKey\.json|service-account[[:alnum:]_-]*\.json|\.npmrc|\.pypirc|\.netrc)' | head -3) || true
189
+ if [[ -n "$SENSITIVE_NAMES" ]]; then
190
+ while IFS= read -r match; do
191
+ warn_with_message "$match"
192
+ done <<< "$SENSITIVE_NAMES"
193
+ fi
194
+
195
+ # Check for credential/secret keywords in file arguments
196
+ CRED_FILES=$(printf '%s\n' "$COMMAND" | grep -oiE '[[:alnum:]_./-]*(credential|secret|private_key|privatekey)[[:alnum:]_./-]*' | head -3) || true
197
+ if [[ -n "$CRED_FILES" ]]; then
198
+ while IFS= read -r match; do
199
+ warn_with_message "$match"
200
+ done <<< "$CRED_FILES"
201
+ fi
202
+ fi
203
+
204
+ # ─── Check Grep pattern for sensitive file paths ───────────────────
205
+
206
+ if [[ -n "$PATTERN" ]]; then
207
+ if is_sensitive "$PATTERN"; then
208
+ block_with_message "$PATTERN"
209
+ fi
210
+ fi
211
+
212
+ # ─── All checks passed ─────────────────────────────────────────────
213
+
214
+ exit 0
@@ -0,0 +1,68 @@
1
+ {
2
+ "hooks": {
3
+ "PreToolUse": [
4
+ {
5
+ "matcher": "Bash",
6
+ "hooks": [
7
+ {
8
+ "type": "command",
9
+ "command": "bash \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/path-guard.sh"
10
+ },
11
+ {
12
+ "type": "command",
13
+ "command": "bash \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/sensitive-guard.sh"
14
+ }
15
+ ]
16
+ },
17
+ {
18
+ "matcher": "Read|Write|Edit|MultiEdit|Grep",
19
+ "hooks": [
20
+ {
21
+ "type": "command",
22
+ "command": "bash \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/sensitive-guard.sh"
23
+ }
24
+ ]
25
+ },
26
+ {
27
+ "matcher": "Edit|MultiEdit",
28
+ "hooks": [
29
+ {
30
+ "type": "command",
31
+ "command": "node \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/comment-guard.js"
32
+ }
33
+ ]
34
+ },
35
+ {
36
+ "matcher": "Glob",
37
+ "hooks": [
38
+ {
39
+ "type": "command",
40
+ "command": "node \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/glob-guard.js"
41
+ }
42
+ ]
43
+ }
44
+ ],
45
+ "PostToolUse": [
46
+ {
47
+ "matcher": "Write|Edit|MultiEdit",
48
+ "hooks": [
49
+ {
50
+ "type": "command",
51
+ "command": "node \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/file-guard.js"
52
+ }
53
+ ]
54
+ }
55
+ ],
56
+ "Stop": [
57
+ {
58
+ "matcher": "",
59
+ "hooks": [
60
+ {
61
+ "type": "command",
62
+ "command": "bash \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/self-review.sh"
63
+ }
64
+ ]
65
+ }
66
+ ]
67
+ }
68
+ }
@@ -0,0 +1,231 @@
1
+ # Development Workflow Reference
2
+
3
+ > Spec-first development: every change follows SPEC → TEST PLAN → CODE + TESTS → BUILD PASS.
4
+
5
+ ---
6
+
7
+ ## 1. Four Workflow Types
8
+
9
+ ### New Feature
10
+
11
+ When: Building something that doesn't exist yet (no code, no spec).
12
+
13
+ ```
14
+ Step 1 → /plan "description of feature"
15
+ Generates: docs/specs/<feature>.md (spec)
16
+ docs/test-plans/<feature>.md (test plan)
17
+ Answers validation questions about assumptions.
18
+ Review both before proceeding.
19
+
20
+ Step 2 → (Optional) /challenge docs/test-plans/<feature>.md
21
+ Adversarial review: spawns hostile reviewers to find flaws.
22
+ Recommended for complex features, auth, data pipelines.
23
+ Skip for simple CRUD or small features.
24
+
25
+ Step 3 → Implement in chunks. After each chunk:
26
+ /test
27
+ Repeat until chunk is green.
28
+
29
+ Step 4 → /review (before merge)
30
+
31
+ Step 5 → /commit
32
+ ```
33
+
34
+ ### Update Existing Feature
35
+
36
+ When: Changing behavior, adding options, refactoring logic.
37
+
38
+ ```
39
+ Step 1 → Update spec FIRST: docs/specs/<feature>.md
40
+ Describe what's changing and why.
41
+
42
+ Step 2 → /plan docs/specs/<feature>.md
43
+ Updates the test plan with new/modified/removed test cases.
44
+
45
+ Step 3 → Implement code changes.
46
+ /test
47
+ Fix until green.
48
+
49
+ Step 4 → /review → /commit
50
+ ```
51
+
52
+ ### Bug Fix
53
+
54
+ When: Something is broken and needs fixing.
55
+
56
+ ```
57
+ Step 1 → /fix "description of the bug"
58
+ Writes failing test → fixes code → confirms green → runs full suite.
59
+
60
+ Step 2 → /commit
61
+
62
+ Optional → If the bug reveals an undocumented edge case, update the spec.
63
+ ```
64
+
65
+ ### Remove Feature
66
+
67
+ When: Deleting a feature, removing deprecated code.
68
+
69
+ ```
70
+ Step 1 → Mark spec sections as removed in docs/specs/<feature>.md
71
+ (Or archive the entire file if the feature is fully removed.)
72
+
73
+ Step 2 → Delete production code and related test code.
74
+
75
+ Step 3 → Run full test suite: bash scripts/build-test.sh
76
+ Fix any cascading breakage.
77
+
78
+ Step 4 → /commit
79
+ ```
80
+
81
+ ---
82
+
83
+ ## 2. Decision Tree
84
+
85
+ Use this to decide which workflow to follow:
86
+
87
+ ```
88
+ Is this a brand new feature (no existing spec or code)?
89
+ ├─ Yes → New Feature workflow. Start with /plan.
90
+ │ └─ Is the feature complex (auth, data pipeline, multi-service)?
91
+ │ ├─ Yes → Run /challenge after /plan, before coding.
92
+ │ └─ No → Skip /challenge, go straight to implementation.
93
+ └─ No
94
+ ├─ Is this a bug fix?
95
+ │ ├─ Yes → Bug Fix workflow. Start with /fix.
96
+ │ └─ No
97
+ │ ├─ Are you removing/deprecating code?
98
+ │ │ ├─ Yes → Remove Feature workflow.
99
+ │ │ └─ No → Update Feature workflow. Start by editing the spec.
100
+ │ │
101
+ │ └─ Is the change very small (< 5 lines, behavior unchanged)?
102
+ │ └─ Yes → Skip spec update. Just /test and /commit.
103
+ ```
104
+
105
+ ---
106
+
107
+ ## 3. Prompt Templates
108
+
109
+ Copy-paste these when working with Claude Code.
110
+
111
+ ### Template A — Implement + Test Together
112
+
113
+ ```
114
+ I just implemented [brief description].
115
+ Files changed: [list files]
116
+
117
+ Based on:
118
+ - Spec: docs/specs/<feature>.md (section §X)
119
+ - Test plan: docs/test-plans/<feature>.md
120
+
121
+ Write tests for the part I just implemented.
122
+ Only tests related to this change — not the entire feature.
123
+ Build and run until all pass.
124
+ If the spec seems incomplete, note what's missing but don't change it.
125
+ ```
126
+
127
+ ### Template B — Update Feature + Tests
128
+
129
+ ```
130
+ I'm about to change [description of change].
131
+ Affected files: [list]
132
+
133
+ 1. Update the spec: docs/specs/<feature>.md
134
+ 2. Update the test plan: docs/test-plans/<feature>.md (only affected test cases)
135
+ 3. Implement the code change
136
+ 4. Update tests to match
137
+ 5. Build and run → fix until green
138
+ ```
139
+
140
+ ### Template C — Test-First Bug Fix
141
+
142
+ ```
143
+ Bug: [description]
144
+ Steps to reproduce: [steps]
145
+ Expected: [correct behavior]
146
+ Actual: [broken behavior]
147
+
148
+ 1. Write a test that reproduces this bug (must fail currently)
149
+ 2. Fix the production code to make the test pass
150
+ 3. Run the full test suite — nothing else should break
151
+ 4. Update the spec if this is an undocumented edge case
152
+ ```
153
+
154
+ ### Template D — Remove Feature
155
+
156
+ ```
157
+ Removing: [feature name]
158
+ Files to delete: [list]
159
+
160
+ 1. Mark relevant spec sections as removed
161
+ 2. Mark related test plan entries as removed
162
+ 3. Delete production code
163
+ 4. Delete test code
164
+ 5. Run full test suite → fix cascading breaks
165
+ ```
166
+
167
+ ---
168
+
169
+ ## 4. Token Cost Guide
170
+
171
+ | Workflow | Estimated Tokens | When |
172
+ |----------|-----------------|------|
173
+ | `/test` (incremental) | 5–10k | Daily, after each code chunk |
174
+ | `/fix` (single bug) | 3–5k | As bugs arise |
175
+ | `/commit` | 2–4k | Each commit |
176
+ | `/review` (diff-based) | 10–20k | Before merge |
177
+ | `/plan` (new feature) | 20–40k | Start of new feature |
178
+ | `/challenge` (adversarial) | 15–30k | After /plan, for complex features |
179
+ | Full audit (manual) | 100k+ | Before release, quarterly |
180
+
181
+ **Rule of thumb:** Daily work uses templates + `/test` → low token cost.
182
+ Save `/plan` and full audits for significant milestones.
183
+
184
+ ---
185
+
186
+ ## 5. CI Integration Checklist
187
+
188
+ Use this as a PR review checklist (enforce manually or via CI):
189
+
190
+ - [ ] **Spec updated?** If production behavior changed, `docs/specs/` should have changes.
191
+ - [ ] **Test plan updated?** If spec changed, `docs/test-plans/` should have changes.
192
+ - [ ] **Tests pass?** `bash scripts/build-test.sh` exits 0.
193
+ - [ ] **No dead tests?** Removed production code → removed corresponding tests.
194
+ - [ ] **Coverage not decreased?** (Optional, per-team decision.)
195
+ - [ ] **No secrets in diff?** No API keys, tokens, passwords in committed code.
196
+ - [ ] **Commit messages conventional?** `type(scope): description` format.
197
+
198
+ ---
199
+
200
+ ## 6. Spec-Test-Code Sync Rules
201
+
202
+ | Change | Must Also Update |
203
+ |--------|-----------------|
204
+ | Production code behavior changed | Spec + test plan + tests |
205
+ | Spec updated | Test plan + tests (if behavior changed) |
206
+ | Test plan updated | Tests (implement new/modified test cases) |
207
+ | Code removed | Remove related tests. Mark spec as removed. |
208
+ | Bug fix | Add test. Update spec if edge case was undocumented. |
209
+
210
+ **Never acceptable:**
211
+ - Code changed, spec not updated (spec drift)
212
+ - Code changed, tests not updated (untested code)
213
+ - Spec changed, tests not updated (plan drift)
214
+ - Code removed, dead tests remain (orphaned tests)
215
+
216
+ **Acceptable shortcut** for changes under 5 lines with no behavior change:
217
+ - Code + tests together, skip spec update (same PR).
218
+
219
+ ---
220
+
221
+ ## 7. Common Pitfalls
222
+
223
+ | Pitfall | Symptom | Prevention |
224
+ |---------|---------|------------|
225
+ | **Spec drift** | Code does X, spec says Y | Always update spec before coding |
226
+ | **Dead tests** | Tests pass but test removed functionality | Delete tests when removing features |
227
+ | **Over-testing** | 50 tests for simple CRUD, slow suite | Focus on behavior, not implementation details |
228
+ | **Mock abuse** | Tests pass with mocks, fail in production | Use real implementations; mock only external services |
229
+ | **Big-bang testing** | All tests written after all code is done | Test incrementally after each chunk |
230
+ | **Ignoring flaky tests** | Tests pass sometimes, fail sometimes | Fix immediately — flaky tests erode trust |
231
+ | **Testing private methods** | Tests break on refactor | Test public API and behavior only |
File without changes
File without changes