claude-git-hooks 2.35.3 → 2.43.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/CHANGELOG.md +135 -0
- package/CLAUDE.md +24 -1389
- package/README.md +113 -0
- package/bin/claude-hooks +11 -7
- package/lib/cli-metadata.js +17 -3
- package/lib/commands/analyze-pr.js +270 -145
- package/lib/commands/analyze.js +151 -3
- package/lib/commands/create-pr.js +345 -134
- package/lib/commands/helpers.js +9 -4
- package/lib/commands/hooks.js +5 -5
- package/lib/commands/install.js +77 -28
- package/lib/commands/lint.js +120 -4
- package/lib/config.js +3 -0
- package/lib/hooks/pre-commit.js +26 -5
- package/lib/hooks/prepare-commit-msg.js +78 -4
- package/lib/utils/analysis-engine.js +12 -6
- package/lib/utils/claude-client.js +222 -12
- package/lib/utils/claude-diagnostics.js +5 -4
- package/lib/utils/cost-tracker.js +128 -0
- package/lib/utils/diff-analysis-orchestrator.js +2 -1
- package/lib/utils/git-operations.js +105 -2
- package/lib/utils/hooks-verified-marker.js +121 -0
- package/lib/utils/interactive-ui.js +4 -4
- package/lib/utils/judge.js +3 -2
- package/lib/utils/langfuse-tracer.js +156 -0
- package/lib/utils/logger.js +30 -5
- package/lib/utils/pr-metadata-engine.js +4 -2
- package/package.json +4 -2
package/CLAUDE.md
CHANGED
|
@@ -1,1400 +1,35 @@
|
|
|
1
1
|
# Repository Context
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
`claude-git-hooks` — intelligent Git hooks system integrating Claude CLI for code analysis, commit message generation, PR creation, and release workflow automation.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Context Acquisition
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
All project knowledge lives in [`.library/`](.library/). Start at [`.library/index.md`](.library/index.md).
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
2. **Pre-commit analysis**: Detects security issues, bugs, and code smells before each commit (blocks on CRITICAL/BLOCKER only)
|
|
11
|
-
3. **Interactive analysis**: `claude-hooks analyze` - review all issues (INFO to BLOCKER) interactively before committing
|
|
12
|
-
4. **Automatic messages**: Write `git commit -m "auto"` and Claude generates the message in Conventional Commits format with task-id extracted from branch
|
|
13
|
-
5. **PR analysis**: `claude-hooks analyze-diff [branch]` generates title, description, and test plan for PRs
|
|
14
|
-
6. **PR review**: `claude-hooks analyze-pr <url>` analyzes a GitHub PR with preset guidelines, Linear ticket enrichment, and posts review comments
|
|
15
|
-
7. **PR creation**: `claude-hooks create-pr [branch]` creates the PR on GitHub with automatic metadata (reviewers from CODEOWNERS, labels by preset, merge strategy auto-detected from branch naming)
|
|
16
|
-
8. **Linting**: `claude-hooks lint [paths...]` runs formatters and linters on staged files, directories, or specific files — supports Prettier, ESLint, Spotless, sqlfluff per preset (remote config priority with local fallback)
|
|
17
|
-
9. **Coupling detection**: `claude-hooks check-coupling` scans open PRs targeting a base branch, computes file overlap, and reports which features are coupled (share modified files) — helps TL make informed decisions before cutting a release
|
|
18
|
-
10. **Shadow management**: `claude-hooks shadow <analyze|reset|sync>` manages the shadow branch lifecycle — analyze divergence vs main and active RC, reset shadow to a clean copy of main, or sync shadow with a source branch (RC, develop, feature)
|
|
19
|
-
11. **Release creation**: `claude-hooks create-release <major|minor|patch>` creates a release-candidate branch from develop, bumps version files, commits, pushes, and deploys to shadow — replaces the 8 manual steps executed every Tuesday by the Tech Lead
|
|
20
|
-
12. **Feature revert**: `claude-hooks revert-feature <task-id>` finds a squash-merged feature commit by task ID in the current release-candidate, checks coupling with other RC features, reverts it, pushes, and optionally re-deploys shadow
|
|
21
|
-
13. **Release closure**: `claude-hooks close-release [description]` finalizes the active release-candidate — soft-resets onto main, creates a single clean commit, force-pushes, and creates a PR to main with the merge-commit strategy
|
|
9
|
+
Load context based on your current task:
|
|
22
10
|
|
|
23
|
-
|
|
11
|
+
| Task | Load |
|
|
12
|
+
|------|------|
|
|
13
|
+
| Writing or modifying code | [`.library/conventions.md`](.library/conventions.md) — coding standards, testing patterns |
|
|
14
|
+
| Understanding a source module | [`.library/by-code/`](.library/by-code/) — find the book for that file |
|
|
15
|
+
| Understanding a business workflow | [`.library/by-domain/`](.library/by-domain/) — commit pipeline, release management, PR analysis, GitHub integration |
|
|
16
|
+
| Adding a new CLI command | [`.library/by-task-type/add-new-command.md`](.library/by-task-type/add-new-command.md) — 7-book reading sequence |
|
|
17
|
+
| Updating the library after code changes | [`.library/README.md`](.library/README.md) — book schema, template, creation steps |
|
|
24
18
|
|
|
25
|
-
|
|
19
|
+
Books follow a standard template at `.library/templates/book-template.md`. After modifying a module, update its book and the relevant shelf index.
|
|
26
20
|
|
|
27
|
-
|
|
28
|
-
- **Module type**: ES6 modules (`"type": "module"` in package.json)
|
|
29
|
-
- **Main dependencies**:
|
|
30
|
-
- `@octokit/rest`: GitHub client for PR creation (v2.5.0+)
|
|
31
|
-
- **Dev dependencies**: Jest, ESLint, Prettier
|
|
32
|
-
- **Distribution**: NPM global package (`npm install -g claude-git-hooks`)
|
|
21
|
+
## Global Rules
|
|
33
22
|
|
|
34
|
-
|
|
23
|
+
These behavioral rules apply to all work in this repository:
|
|
35
24
|
|
|
36
|
-
**
|
|
25
|
+
1. **Do NOT perform git add, commit, or push unless explicitly asked** — git flow is handled by the human user
|
|
26
|
+
2. **Do NOT add dependencies without justification** — only 1 runtime dep (`@octokit/rest`); verify no built-in alternative exists
|
|
27
|
+
3. **Do NOT modify `.gitignore` without consultation** — `.claude/` is ignored by design
|
|
28
|
+
4. **Do NOT commit secrets** — tokens go in `.claude/settings.local.json` (gitignored) or env vars, never in tracked files
|
|
29
|
+
5. **Do NOT make breaking changes without MAJOR version bump** — config format, CLI arguments, template format changes require MAJOR
|
|
30
|
+
6. **Do NOT hardcode absolute paths** — use `getRepoRoot()` from `git-operations.js`; all paths relative to repo root
|
|
31
|
+
7. **Do NOT use `console.log`** — always use `logger.js`: `info()`, `warning()`, `error()`, `debug()`
|
|
32
|
+
8. **Platform-specific care** — use `path.join()` (no hardcoded `/`); test on Windows, Linux, macOS
|
|
33
|
+
9. **Input sanitization** — use `sanitize.js` for user inputs in shell commands; avoid `shell: true` in `spawn()`
|
|
37
34
|
|
|
38
|
-
|
|
39
|
-
- **lib/commands/**: Command modules - one file per CLI command, self-contained logic
|
|
40
|
-
- **lib/hooks/**: Git hook logic - Node.js implementations invoked by bash wrappers
|
|
41
|
-
- **lib/utils/**: Reusable utilities - shared across commands, no CLI dependencies
|
|
42
|
-
- **templates/**: Static assets - copied during installation, user-customizable
|
|
43
|
-
|
|
44
|
-
This separation enables:
|
|
45
|
-
|
|
46
|
-
- **Testability**: Each module can be unit tested independently
|
|
47
|
-
- **Maintainability**: Changes to one command don't risk breaking others
|
|
48
|
-
- **Discoverability**: Find code by filename matching command name
|
|
49
|
-
- **Extensibility**: Add new commands by creating new module files
|
|
50
|
-
|
|
51
|
-
### Directory Structure
|
|
52
|
-
|
|
53
|
-
```
|
|
54
|
-
claude-git-hooks/
|
|
55
|
-
├── bin/
|
|
56
|
-
│ └── claude-hooks # Thin CLI router - uses cli-metadata.js registry for dispatch
|
|
57
|
-
├── lib/
|
|
58
|
-
│ ├── cli-metadata.js # Command registry - single source of truth for CLI commands, flags, descriptions
|
|
59
|
-
│ ├── config.js # Config system - load/merge with priority
|
|
60
|
-
│ ├── commands/ # Command modules - one file per CLI command
|
|
61
|
-
│ │ ├── helpers.js # Shared CLI utilities - colors, output, platform
|
|
62
|
-
│ │ ├── install.js # Install command - dependencies, hooks, templates, linter check
|
|
63
|
-
│ │ ├── hooks.js # Hook management - enable, disable, status, uninstall
|
|
64
|
-
│ │ ├── analyze-diff.js # Diff analysis - generate PR metadata from git diff
|
|
65
|
-
│ │ ├── analyze-pr.js # PR analysis - analyze GitHub PR with team guidelines
|
|
66
|
-
│ │ ├── check-coupling.js # Coupling detection - detect coupled PRs before release (v2.23.0)
|
|
67
|
-
│ │ ├── shadow.js # Shadow management - analyze/reset/sync shadow branch lifecycle (v2.24.0)
|
|
68
|
-
│ │ ├── create-release.js # Release creation - RC branch from develop, version bump, shadow deploy (v2.27.0)
|
|
69
|
-
│ │ ├── revert-feature.js # Feature revert - find by task-id, coupling check, git revert, push, shadow (v2.28.0)
|
|
70
|
-
│ │ ├── close-release.js # Release closure - soft-reset, single commit, force-push, PR to main (v2.29.0)
|
|
71
|
-
│ │ ├── create-pr.js # PR creation - full Octokit workflow
|
|
72
|
-
│ │ ├── setup-github.js # Token setup - interactive GitHub configuration
|
|
73
|
-
│ │ ├── setup-linear.js # Token setup - interactive Linear configuration
|
|
74
|
-
│ │ ├── presets.js # Preset management - list, set, show current
|
|
75
|
-
│ │ ├── update.js # Self-update - check and install latest version
|
|
76
|
-
│ │ ├── migrate-config.js # Config migration - legacy to v2.8.0 format
|
|
77
|
-
│ │ ├── debug.js # Debug toggle - enable/disable verbose logging
|
|
78
|
-
│ │ ├── telemetry-cmd.js # Telemetry commands - show/clear statistics
|
|
79
|
-
│ │ ├── bump-version.js # Version management - bump with commit, CHANGELOG and tags
|
|
80
|
-
│ │ ├── generate-changelog.js # CHANGELOG generation - standalone command
|
|
81
|
-
│ │ ├── diff-batch-info.js # Batch info - orchestration config + speed telemetry (v2.20.0)
|
|
82
|
-
│ │ ├── lint.js # Lint command - run linters on staged files, dirs, or files
|
|
83
|
-
│ │ └── help.js # Help, AI help, and report-issue commands
|
|
84
|
-
│ ├── hooks/ # Git hooks - Node.js implementations
|
|
85
|
-
│ │ ├── pre-commit.js # Pre-commit analysis - code quality gate
|
|
86
|
-
│ │ └── prepare-commit-msg.js # Message generation - auto commit messages
|
|
87
|
-
│ └── utils/ # Reusable modules - shared logic
|
|
88
|
-
│ ├── tool-runner.js # Generic tool executor - resolve, spawn, parse, auto-fix (v2.34.0)
|
|
89
|
-
│ ├── linter-runner.js # Linter orchestration - preset mapping, Prettier/ESLint/Spotless/sqlfluff, remote config (v2.34.0)
|
|
90
|
-
│ ├── analysis-engine.js # Shared analysis logic - file data, 3-tier routing, results (v2.13.0+)
|
|
91
|
-
│ ├── diff-analysis-orchestrator.js # Intelligent batch orchestration via Opus (v2.20.0)
|
|
92
|
-
│ ├── claude-client.js # Claude CLI wrapper - spawn, retry, model override
|
|
93
|
-
│ ├── prompt-builder.js # Prompt construction - load templates, replace vars
|
|
94
|
-
│ ├── git-operations.js # Git abstractions - staged files, diff, repo root, push, commit, checkout, merge, reset, force-push, delete-remote-branch, divergence
|
|
95
|
-
│ ├── file-utils.js # File operations - repo-relative paths
|
|
96
|
-
│ ├── logger.js # Logging system - centralized output, debug mode
|
|
97
|
-
│ ├── preset-loader.js # Preset system - load tech-stack configurations
|
|
98
|
-
│ ├── pr-metadata-engine.js # PR metadata generation - branch context, diff reduction, metadata (v2.14.0)
|
|
99
|
-
│ ├── github-api.js # Octokit integration - PR creation, PR analysis, token validation, Teams API
|
|
100
|
-
│ ├── github-client.js # GitHub helpers - repo parsing, config-based reviewers (fallback)
|
|
101
|
-
│ ├── reviewer-selector.js # Team-based reviewer selection - resolve team members, exclude author (v2.32.0)
|
|
102
|
-
│ ├── authorization.js # Role-based authorization - PROTECTED_COMMANDS, authorizeCommand(), fail-closed (v2.23.0)
|
|
103
|
-
│ ├── remote-config.js # Remote config fetcher - cached JSON from git-hooks-config repo (v2.31.0)
|
|
104
|
-
│ ├── label-resolver.js # Label resolution - 5-rule engine with remote + local fallback (v2.31.0)
|
|
105
|
-
│ ├── token-store.js # Token persistence - centralized settings.local.json read/write
|
|
106
|
-
│ ├── linear-connector.js # Linear API - ticket context fetching with retry
|
|
107
|
-
│ ├── coupling-detector.js # Coupling algorithm - Union-Find transitive grouping (v2.23.0)
|
|
108
|
-
│ ├── pr-statistics.js # PR statistics - write-only JSONL analytics
|
|
109
|
-
│ ├── task-id.js # Task ID extraction - Jira, GitHub, Linear patterns
|
|
110
|
-
│ ├── interactive-ui.js # CLI UI components - previews, prompts, spinners
|
|
111
|
-
│ ├── judge.js # Auto-fix judge - LLM verdict + search/replace fixes (v2.20.0)
|
|
112
|
-
│ ├── resolution-prompt.js # Issue resolution - AI-friendly fix prompts
|
|
113
|
-
│ ├── installation-diagnostics.js # Installation diagnostics - error context
|
|
114
|
-
│ ├── claude-diagnostics.js # Claude errors - rate limit, auth, formatting
|
|
115
|
-
│ ├── which-command.js # Executable resolution - cross-platform paths
|
|
116
|
-
│ ├── sanitize.js # Input sanitization - shell safety
|
|
117
|
-
│ ├── telemetry.js # Local telemetry - track JSON parsing, retries
|
|
118
|
-
│ ├── version-manager.js # Version detection - parse, increment, validate, per-file targets (v2.12.0)
|
|
119
|
-
│ ├── git-tag-manager.js # Git tag operations - create, list, compare, push, isSemverTag (v2.12.0)
|
|
120
|
-
│ └── changelog-generator.js # CHANGELOG generation - Claude-powered analysis (v2.12.0)
|
|
121
|
-
├── templates/ # Static assets - copied during install
|
|
122
|
-
│ ├── pre-commit # Bash wrapper - invokes lib/hooks/pre-commit.js
|
|
123
|
-
│ ├── prepare-commit-msg # Bash wrapper - invokes lib/hooks/prepare-commit-msg.js
|
|
124
|
-
│ ├── check-version.sh # Version check - auto-update prompt
|
|
125
|
-
│ ├── CLAUDE_PRE_COMMIT.md # Analysis criteria - evaluation guidelines
|
|
126
|
-
│ ├── CLAUDE_ANALYSIS_PROMPT.md # Analysis prompt - code review template
|
|
127
|
-
│ ├── CLAUDE_RESOLUTION_PROMPT.md # Resolution prompt - structured JSON output for judge + manual use
|
|
128
|
-
│ ├── ANALYZE_DIFF.md # PR analysis - diff review template
|
|
129
|
-
│ ├── ANALYZE_PR.md # PR analysis - GitHub PR review template with category injection
|
|
130
|
-
│ ├── GENERATE_CHANGELOG.md # CHANGELOG generation - commit analysis template (v2.12.0)
|
|
131
|
-
│ ├── DIFF_ANALYSIS_ORCHESTRATION_PROMPT.md # Orchestration prompt - Opus batch grouping (v2.20.0)
|
|
132
|
-
│ ├── HELP_QUERY.md # AI help - question answering with NEED_MORE_CONTEXT protocol (v2.18.0)
|
|
133
|
-
│ ├── HELP_REPORT_ISSUE.md # Report issue - question generation from templates (v2.18.0)
|
|
134
|
-
│ ├── HELP_COMPOSE_ISSUE.md # Report issue - issue body composition from answers (v2.18.0)
|
|
135
|
-
│ ├── config.example.json # Config example - minimal setup
|
|
136
|
-
│ ├── config.advanced.example.json # Config advanced - all options documented
|
|
137
|
-
│ ├── settings.local.example.json # Local settings - token storage template
|
|
138
|
-
│ └── CUSTOMIZATION_GUIDE.md # Customization - preset creation guide
|
|
139
|
-
└── test/ # Tests - Jest with ES6 modules
|
|
140
|
-
└── unit/
|
|
141
|
-
└── *.test.js
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
### Execution Architecture
|
|
145
|
-
|
|
146
|
-
**1. Git Hooks (bash wrappers → Node.js)**
|
|
147
|
-
|
|
148
|
-
```
|
|
149
|
-
.git/hooks/pre-commit (bash)
|
|
150
|
-
↓
|
|
151
|
-
node lib/hooks/pre-commit.js
|
|
152
|
-
↓ (reads config + preset)
|
|
153
|
-
lib/config.js → merges: defaults < user config < preset config
|
|
154
|
-
↓ (gets staged files)
|
|
155
|
-
lib/utils/git-operations.js → getStagedFiles()
|
|
156
|
-
↓ (filters by preset extensions + size)
|
|
157
|
-
lib/utils/file-operations.js → filterFiles()
|
|
158
|
-
↓ (builds file data + runs analysis)
|
|
159
|
-
lib/utils/analysis-engine.js → buildFilesData(), runAnalysis()
|
|
160
|
-
↓ (2-tier routing: 1-2 files→sequential, 3+→Opus orchestration)
|
|
161
|
-
lib/utils/diff-analysis-orchestrator.js → orchestrateBatches() [if N ≥ 3]
|
|
162
|
-
lib/utils/claude-client.js → analyzeCode(prompt, { model }) per batch [parallel]
|
|
163
|
-
↓ (displays results)
|
|
164
|
-
lib/utils/analysis-engine.js → displayResults()
|
|
165
|
-
↓ (if blocking issues found)
|
|
166
|
-
lib/utils/resolution-prompt.js → generates claude_resolution_prompt.md
|
|
167
|
-
↓
|
|
168
|
-
exit 1 (blocks commit) or exit 0 (allows commit)
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
**2. Configuration System (priorities)**
|
|
172
|
-
|
|
173
|
-
```
|
|
174
|
-
defaults (lib/config.js)
|
|
175
|
-
↓ overridden by
|
|
176
|
-
user config (.claude/config.json)
|
|
177
|
-
↓ overridden by
|
|
178
|
-
preset config (.claude/presets/{name}/config.json) ← HIGHEST PRIORITY
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
**Rationale**: User configures general preferences, preset provides tech-stack-specific overrides.
|
|
182
|
-
|
|
183
|
-
**Team-wide remote config** ([`mscope-S-L/git-hooks-config`](https://github.com/mscope-S-L/git-hooks-config)):
|
|
184
|
-
|
|
185
|
-
- `labels.json` — PR label rules (fetched by `remote-config.js`, consumed by `label-resolver.js`)
|
|
186
|
-
- `formatters.json` — preset-to-tools mapping for linting/formatting (fetched by `remote-config.js`, consumed by `linter-runner.js`)
|
|
187
|
-
- `permissions.json` — role-based authorization (fetched directly by `authorization.js`, fail-closed)
|
|
188
|
-
- Changes take effect immediately across all governed repos — no tool update needed
|
|
189
|
-
|
|
190
|
-
**Config format (v2.8.0):**
|
|
191
|
-
|
|
192
|
-
```json
|
|
193
|
-
{
|
|
194
|
-
"version": "2.8.0",
|
|
195
|
-
"preset": "backend",
|
|
196
|
-
"overrides": {
|
|
197
|
-
"github": {
|
|
198
|
-
"pr": {
|
|
199
|
-
"defaultBase": "develop",
|
|
200
|
-
"reviewers": ["user"],
|
|
201
|
-
"autoPush": true, // Auto-push unpublished branches (v2.11.0)
|
|
202
|
-
"pushConfirm": true, // Prompt before push (v2.11.0)
|
|
203
|
-
"showCommits": true, // Show commit preview (v2.11.0)
|
|
204
|
-
"verifyRemote": true // Verify remote exists (v2.11.0)
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
**Hardcoded defaults (v2.8.0+):**
|
|
212
|
-
|
|
213
|
-
| Parameter | Value | Notes |
|
|
214
|
-
| ---------------------- | ------- | --------------------------------------------------- |
|
|
215
|
-
| Max file size | 1MB | Files larger are skipped |
|
|
216
|
-
| Max files per commit | 30 | Excess files trigger warning |
|
|
217
|
-
| Orchestrator threshold | 3 files | Commits with ≥3 files use Opus orchestration |
|
|
218
|
-
| Orchestrator model | opus | Internal constant — not user-configurable |
|
|
219
|
-
| Orchestrator timeout | 60s | Lightweight call (file overview only) |
|
|
220
|
-
| Analysis timeout | 360s | Per-batch timeout |
|
|
221
|
-
| Commit msg timeout | 300s | Message generation timeout |
|
|
222
|
-
| PR metadata timeout | 180s | Engine default (reads config) |
|
|
223
|
-
| Judge model | sonnet | Default, configurable via `config.judge.model` |
|
|
224
|
-
| Judge timeout | 360s | Per-judge call timeout |
|
|
225
|
-
| PR analysis model | sonnet | Default, configurable via `config.prAnalysis.model` |
|
|
226
|
-
| PR analysis timeout | 300s | Per-analysis Claude call |
|
|
227
|
-
| Linting enabled | true | Runs linters before Claude analysis |
|
|
228
|
-
| Linting auto-fix | true | Auto-fix and re-stage files |
|
|
229
|
-
| Linting fail on error | true | Block commit on linting errors |
|
|
230
|
-
| Linting fail on warn | false | Do not block on warnings |
|
|
231
|
-
| Linting timeout | 30s | Per-linter timeout (tool-specific overrides if higher) |
|
|
232
|
-
| Spotless timeout | 120s | Per-invocation; overrides config default |
|
|
233
|
-
|
|
234
|
-
**Judge behavior (v2.20.0):**
|
|
235
|
-
|
|
236
|
-
- Enabled by default (`config.judge?.enabled !== false`)
|
|
237
|
-
- Runs on **all issues** (any severity), not just blockers
|
|
238
|
-
- **Any unresolved issue blocks the commit** — no issue passes without judge approval
|
|
239
|
-
- Judge failure (timeout, JSON parse error, module load) → user warned → commit blocked
|
|
240
|
-
- No retries — failed fixes stay as unresolved issues
|
|
241
|
-
- When disabled (`config.judge.enabled: false`), falls back to original quality gate (blocks on CRITICAL/BLOCKER only)
|
|
242
|
-
- Resolution prompt file is only generated if issues remain after the judge
|
|
243
|
-
|
|
244
|
-
**3. Presets System**
|
|
245
|
-
|
|
246
|
-
| Preset | Extensions | Stack | Key Verifications |
|
|
247
|
-
| ----------- | -------------------------------------------------------------------------- | ------------------------ | --------------------------------------------------- |
|
|
248
|
-
| `backend` | `.java`, `.xml`, `.yml`, `.yaml` | Spring Boot + SQL Server | REST API, JPA, OWASP Top 10, SQL injection |
|
|
249
|
-
| `frontend` | `.js`, `.jsx`, `.ts`, `.tsx`, `.css`, `.scss`, `.html` | React + Material-UI | Hooks, XSS, a11y, performance |
|
|
250
|
-
| `fullstack` | backend + frontend | Spring Boot + React | **API contract consistency** (priority) |
|
|
251
|
-
| `database` | `.sql` | SQL Server | SQL injection, UPDATE/DELETE without WHERE, indexes |
|
|
252
|
-
| `ai` | `.js`, `.json`, `.md`, `.sh` | Node.js + Claude API | Prompts, API key security, cross-platform |
|
|
253
|
-
| `default` | `.js`, `.sh`, `.py`, `.rb`, `.pl`, `.sql`, `.yaml`, `.json`, `.xml`, `.md` | Multiple | Quality and security fundamentals |
|
|
254
|
-
|
|
255
|
-
**4. Analysis Routing (v2.20.0)**
|
|
256
|
-
|
|
257
|
-
Three-tier strategy based on file count:
|
|
258
|
-
|
|
259
|
-
| Files | Strategy |
|
|
260
|
-
| ------ | ----------------------------------------------------------------------------------------------------- |
|
|
261
|
-
| 1–2 | Sequential — single Claude call |
|
|
262
|
-
| **3+** | **Intelligent orchestration** — Opus orchestrator, semantic grouping, per-batch model, shared context |
|
|
263
|
-
|
|
264
|
-
**Orchestration flow (3+ files):**
|
|
265
|
-
|
|
266
|
-
```
|
|
267
|
-
staged files (N ≥ 3)
|
|
268
|
-
↓
|
|
269
|
-
[ORCHESTRATOR — Opus, 60s timeout]
|
|
270
|
-
Input: file overview table + detected cross-file deps (JS/TS/Java/Python regex)
|
|
271
|
-
Output: { batches: [{ filePaths, rationale, model }] }
|
|
272
|
-
↓
|
|
273
|
-
For each batch:
|
|
274
|
-
→ buildAnalysisPrompt(batchFiles + commonContext + batchRationale)
|
|
275
|
-
→ analyzeCode(prompt, { model: batch.model }) ← per-batch model
|
|
276
|
-
[all batches run in parallel via Promise.all]
|
|
277
|
-
↓
|
|
278
|
-
consolidateResults()
|
|
279
|
-
```
|
|
280
|
-
|
|
281
|
-
- **Orchestration model**: `opus` — hardcoded internal constant, not user-configurable
|
|
282
|
-
- **Threshold**: `ORCHESTRATOR_THRESHOLD = 3` — internal constant in `analysis-engine.js`
|
|
283
|
-
- **Fallback**: any orchestration failure → one-file-per-batch with haiku
|
|
284
|
-
- **Common context**: each batch prompt prefixed with commit overview, dep graph, and batch rationale
|
|
285
|
-
|
|
286
|
-
### Key Module Exports
|
|
287
|
-
|
|
288
|
-
**Command Modules (`lib/commands/`):**
|
|
289
|
-
|
|
290
|
-
| Module | Purpose | Key Exports |
|
|
291
|
-
| ----------------------- | --------------------------- | -------------------------------------------------------------------------------------------------- |
|
|
292
|
-
| `helpers.js` | Shared CLI utilities | `colors`, `error()`, `success()`, `info()`, `checkGitRepo()`, `getGitHooksPath()`, `Entertainment` |
|
|
293
|
-
| `install.js` | Installation logic | `runInstall()`, `extractLegacySettings()` |
|
|
294
|
-
| `hooks.js` | Hook management | `runEnable()`, `runDisable()`, `runStatus()`, `runUninstall()` |
|
|
295
|
-
| `analyze.js` | Interactive code analysis | `runAnalyze()` |
|
|
296
|
-
| `analyze-diff.js` | Diff analysis | `runAnalyzeDiff()` |
|
|
297
|
-
| `analyze-pr.js` | PR analysis from URL | `runAnalyzePr()`, `normalizeCategory()` |
|
|
298
|
-
| `check-coupling.js` | Coupling detection | `runCheckCoupling()` |
|
|
299
|
-
| `shadow.js` | Shadow branch management | `runShadow()` — routes to analyze/reset/sync subcommands (v2.24.0) |
|
|
300
|
-
| `create-release.js` | Release candidate creation | `runCreateRelease()` — RC branch from develop, version bump, push, shadow deploy (v2.27.0) |
|
|
301
|
-
| `revert-feature.js` | Feature revert in RC | `runRevertFeature()` — find by task-id, coupling check, revert, push, shadow sync (v2.28.0) |
|
|
302
|
-
| `close-release.js` | Release candidate closure | `runCloseRelease()` — soft-reset, single commit, force-push, PR to main (v2.29.0) |
|
|
303
|
-
| `create-pr.js` | PR creation | `runCreatePr()`, `detectMergeStrategy()` (private) |
|
|
304
|
-
| `bump-version.js` | Version management | `runBumpVersion()` |
|
|
305
|
-
| `generate-changelog.js` | CHANGELOG generation | `runGenerateChangelog()` |
|
|
306
|
-
| `setup-github.js` | Token setup (GitHub) | `runSetupGitHub()` |
|
|
307
|
-
| `setup-linear.js` | Token setup (Linear) | `runSetupLinear()` |
|
|
308
|
-
| `presets.js` | Preset management | `runShowPresets()`, `runSetPreset()`, `runCurrentPreset()` |
|
|
309
|
-
| `update.js` | Self-update | `runUpdate()` |
|
|
310
|
-
| `migrate-config.js` | Config migration | `runMigrateConfig()` |
|
|
311
|
-
| `debug.js` | Debug toggle | `runSetDebug()` |
|
|
312
|
-
| `telemetry-cmd.js` | Telemetry commands | `runShowTelemetry()`, `runClearTelemetry()` |
|
|
313
|
-
| `diff-batch-info.js` | Batch info display | `runDiffBatchInfo()` |
|
|
314
|
-
| `lint.js` | Lint command | `runLint()`, `resolvePaths()` |
|
|
315
|
-
| `help.js` | Help, AI help, report-issue | `runShowHelp()`, `showStaticHelp()`, `runShowVersion()` |
|
|
316
|
-
|
|
317
|
-
**Utility Modules (`lib/utils/`):**
|
|
318
|
-
|
|
319
|
-
| Module | Purpose | Key Exports |
|
|
320
|
-
| ------------------------------- | ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
321
|
-
| `lib/cli-metadata.js` | Command registry | `commands`, `buildCommandMap()`, `generateCompletionData()`, `PRESET_NAMES`, `HOOK_NAMES`, `BUMP_TYPES` |
|
|
322
|
-
| `lib/config.js` | Config system | `getConfig()` |
|
|
323
|
-
| `tool-runner.js` | Generic tool executor | `isToolAvailable()`, `filterFilesByTool()`, `runTool()`, `runToolFix()`, `runToolWithAutoFix()`, `displayToolResult()` (v2.34.0) |
|
|
324
|
-
| `linter-runner.js` | Linter orchestration | `runLinters()`, `displayLintResults()`, `checkLinterAvailability()`, `getLinterToolsForPreset()`, `LINTER_TOOLS`, `PRESET_LINTERS`, `parsePrettierOutput()`, `parseEslintOutput()`, `parseSpotlessOutput()`, `parseSqlfluffOutput()`, `filesToSpotlessRegex()` (v2.34.0) |
|
|
325
|
-
| `analysis-engine.js` | Shared analysis logic | `buildFileData()`, `buildFilesData()`, `runAnalysis()`, `consolidateResults()`, `hasBlockingIssues()`, `hasAnyIssues()`, `displayResults()`, `displayIssueSummary()` (v2.13.0+) |
|
|
326
|
-
| `diff-analysis-orchestrator.js` | Intelligent batch orchestration | `orchestrateBatches()`, `buildFileOverview()`, `detectDependencies()` (v2.20.0) |
|
|
327
|
-
| `claude-client.js` | Claude CLI wrapper | `analyzeCode()`, `executeClaudeWithRetry()`, `extractJSON()` — spawn, retry, model override |
|
|
328
|
-
| `prompt-builder.js` | Prompt construction | `buildAnalysisPrompt()`, `loadPrompt()` — accepts `commonContext`, `batchRationale` |
|
|
329
|
-
| `git-operations.js` | Git abstractions | `getStagedFiles()`, `getUnstagedFiles()`, `getAllTrackedFiles()`, `getDiff()`, `getRepoRoot()`, `getBranchPushStatus()`, `pushBranch()`, `createCommit()`, `fetchRemote()`, `branchExists()`, `getRemoteBranches()`, `resolveBaseBranch()`, `getChangedFilesBetweenRefs()`, `getDiffBetweenRefs()`, `getCommitsBetweenRefs()`, `checkoutBranch()`, `mergeBranch()`, `resetBranch()`, `forcePush()`, `deleteRemoteBranch()`, `getDivergence()`, `readFileFromRef()`, `getLatestTag()`, `isWorkingDirectoryClean()`, `getActiveBranch()`, `getCommitFiles()` |
|
|
330
|
-
| `file-utils.js` | File operations | `ensureDir()`, `ensureOutputDir()`, `writeOutputFile()`, `walkDirectoryTree()` |
|
|
331
|
-
| `pr-metadata-engine.js` | PR metadata generation | `getBranchContext()`, `buildDiffPayload()`, `generatePRMetadata()`, `analyzeBranchForPR()` (v2.14.0) |
|
|
332
|
-
| `git-tag-manager.js` | Git tag operations | `createTag()`, `pushTags()`, `getLocalTags()`, `getRemoteTags()`, `compareLocalAndRemoteTags()`, `tagExists()` (v2.12.0) |
|
|
333
|
-
| `version-manager.js` | Version management | `discoverVersionFiles()`, `getDiscoveryResult()`, `readVersionFromFile()`, `writeVersionToFile()`, `updateVersionFiles()`, `modifySuffix()`, `incrementVersion()`, `parseVersion()`, `validateVersionFormat()`, `compareVersions()`, `validateVersionAlignment()` (v2.15.5) |
|
|
334
|
-
| `changelog-generator.js` | CHANGELOG generation | `generateChangelogEntry()`, `updateChangelogFile()`, `getLastFinalVersionTag()`, `getCommitsSinceTag()`, `discoverChangelogFiles()`, `selectChangelogFile()` (v2.12.0) |
|
|
335
|
-
| `coupling-detector.js` | Coupling algorithm | `buildFileIndex()`, `getSharedFiles()`, `detectCouplingGroups()` — Union-Find transitive grouping (v2.23.0) |
|
|
336
|
-
| `github-api.js` | Octokit integration | `createPullRequest()`, `fetchPullRequest()`, `fetchPullRequestFiles()`, `createPullRequestReview()`, `parseGitHubPRUrl()`, `validateToken()`, `saveGitHubToken()`, `fetchFileContent()`, `fetchDirectoryListing()`, `createIssue()`, `listOpenPullRequests()`, `listRepoTeams()`, `listTeamMembers()`, `getAuthenticatedUser()`, `checkOrgMembership()`, `getCollaboratorPermission()` |
|
|
337
|
-
| `github-client.js` | GitHub helpers | `getReviewersForFiles()`, `parseGitHubRepo()` — config-based reviewer fallback |
|
|
338
|
-
| `reviewer-selector.js` | Team-based reviewer selection | `selectReviewers()` — resolve team members via GitHub Teams API, exclude PR author, config fallback (v2.32.0) |
|
|
339
|
-
| `authorization.js` | Role-based authorization | `authorizeCommand()`, `requiresAuthorization()`, `getRequiredRole()`, `AuthorizationError`, `PROTECTED_COMMANDS` — fail-closed guard for workflow commands (v2.23.0) |
|
|
340
|
-
| `remote-config.js` | Remote config fetcher | `fetchRemoteConfig(fileName)`, `CONFIG_REPO_OWNER`, `CONFIG_REPO_NAME`, `_clearCache()` — cached JSON from `git-hooks-config` repo, graceful degradation (v2.31.0) |
|
|
341
|
-
| `label-resolver.js` | Label resolution | `resolveLabels(context)` — 5-rule engine: preset, size, quality, strategy, defaults; remote config priority with local fallback (v2.31.0) |
|
|
342
|
-
| `token-store.js` | Token persistence | `loadToken()`, `saveToken()`, `hasToken()`, `loadLocalSettings()` |
|
|
343
|
-
| `linear-connector.js` | Linear integration | `loadLinearToken()`, `testConnection()`, `fetchTicket()`, `extractLinearTicketFromTitle()`, `parseLinearIdentifier()`, `LinearConnectorError` |
|
|
344
|
-
| `pr-statistics.js` | PR statistics | `recordPRAnalysis()` — write-only JSONL at `.claude/statistics/pr/stats.jsonl` |
|
|
345
|
-
| `preset-loader.js` | Preset system | `loadPreset()`, `listPresets()` |
|
|
346
|
-
| `task-id.js` | Task ID extraction | `getOrPromptTaskId()`, `formatWithTaskId()` |
|
|
347
|
-
| `logger.js` | Logging system | `info()`, `warning()`, `error()`, `debug()` |
|
|
348
|
-
| `judge.js` | Auto-fix judge | `judgeAndFix()`, `applyFix()` — LLM verdict + search/replace fixes (v2.20.0) |
|
|
349
|
-
| `resolution-prompt.js` | Issue resolution | `generateResolutionPrompt()` |
|
|
350
|
-
| `interactive-ui.js` | CLI UI components | `showPRPreview()`, `promptConfirmation()`, `promptMenu()`, `promptToggleList()`, `promptEditField()`, `promptUserConfirmation()` |
|
|
351
|
-
| `telemetry.js` | Local telemetry | `recordEvent()`, `displayStatistics()` |
|
|
352
|
-
|
|
353
|
-
### Design Patterns
|
|
354
|
-
|
|
355
|
-
1. **Command Registry**: `lib/cli-metadata.js` - single source of truth for CLI commands, flags, and descriptions. When adding CLI commands, add an entry to `lib/cli-metadata.js` — routing, completions, and help derive from it.
|
|
356
|
-
2. **Command Pattern**: `lib/commands/*.js` - each CLI command is a self-contained module
|
|
357
|
-
3. **Factory Pattern**: `preset-loader.js` loads configurations dynamically per tech-stack
|
|
358
|
-
4. **Template Method**: `prompt-builder.js` builds prompts from markdown templates
|
|
359
|
-
5. **Strategy Pattern**: `analysis-engine.js` selects between sequential (1–2 files) or orchestrated (3+ files) analysis based on file count threshold
|
|
360
|
-
6. **Orchestrator Pattern**: `diff-analysis-orchestrator.js` — Opus decides semantic grouping and model assignment; workers (analyzeCode per batch) execute in parallel
|
|
361
|
-
7. **Adapter Pattern**: `git-operations.js` abstracts git commands into JS functions
|
|
362
|
-
8. **Singleton Pattern**: `config.js` loads configuration once per execution
|
|
363
|
-
9. **Guard Pattern**: `authorization.js` — fail-closed gate in `bin/claude-hooks` before command dispatch; static `PROTECTED_COMMANDS` set avoids API calls for unprotected commands; permissions sourced from `mscope-S-L/git-hooks-config/permissions.json`
|
|
364
|
-
10. **Remote Config Pattern**: `remote-config.js` — fetches JSON from `mscope-S-L/git-hooks-config`, caches per-process (including nulls), graceful degradation (warn + return null); `label-resolver.js` and `linter-runner.js` — callers fetch remote config and decide fallback (`labels.json` for PR labels, `formatters.json` for preset-to-tools mapping)
|
|
365
|
-
11. **Pipeline Pattern**: `tool-runner.js` + `linter-runner.js` — generic tool execution infrastructure; formatters (Prettier) and linters (ESLint, Spotless, sqlfluff) share the same resolve → spawn → parse → fix → re-stage pipeline. Tool definitions are data objects, not classes. Preset-to-tools mapping fetched from `mscope-S-L/git-hooks-config/formatters.json` (remote config priority, local fallback).
|
|
366
|
-
|
|
367
|
-
### Key Data Flows
|
|
368
|
-
|
|
369
|
-
**Flow 0: Pre-commit linting (v2.34.0)**
|
|
370
|
-
|
|
371
|
-
```
|
|
372
|
-
git commit
|
|
373
|
-
→ hook reads staged files
|
|
374
|
-
→ filters by preset extensions + size
|
|
375
|
-
↓
|
|
376
|
-
→ LINTING STEP (fast, deterministic)
|
|
377
|
-
→ getLinterToolsForPreset(presetName):
|
|
378
|
-
1. fetchRemoteConfig('formatters.json') → remote presetTools mapping
|
|
379
|
-
2. fallback to local PRESET_LINTERS if remote unavailable
|
|
380
|
-
→ for each tool (formatters first, then linters):
|
|
381
|
-
isToolAvailable() → not found? warn + install hint → skip
|
|
382
|
-
filterFilesByTool() → matching files
|
|
383
|
-
→ timeout = max(config.linting.timeout, toolDef.timeout)
|
|
384
|
-
→ perFile tools (Spotless): resolve command path
|
|
385
|
-
.cmd/.bat → per-file mode (cmd.exe pipe safety)
|
|
386
|
-
otherwise → batch mode (single JVM startup)
|
|
387
|
-
runToolWithAutoFix() → check → auto-fix → re-stage → re-check
|
|
388
|
-
→ unfixable issues forwarded to judge
|
|
389
|
-
↓
|
|
390
|
-
→ continues to Claude analysis
|
|
391
|
-
```
|
|
392
|
-
|
|
393
|
-
**Flow 1: Pre-commit with blocking**
|
|
394
|
-
|
|
395
|
-
```
|
|
396
|
-
git commit
|
|
397
|
-
→ hook reads staged files
|
|
398
|
-
→ filters by preset extensions
|
|
399
|
-
→ [linting step — see Flow 0]
|
|
400
|
-
→ builds prompt with diff
|
|
401
|
-
→ Claude analyzes → detects issues
|
|
402
|
-
→ judge evaluates ALL issues (any severity):
|
|
403
|
-
→ TRUE_ISSUE: applies search/replace fix + git add
|
|
404
|
-
→ FALSE_POSITIVE: dismissed
|
|
405
|
-
→ if ALL resolved: exit 0 → COMMIT PROCEEDS
|
|
406
|
-
→ if ANY unresolved: generates resolution prompt → exit 1 → COMMIT BLOCKED
|
|
407
|
-
→ if judge fails (timeout, parse error): user warned → exit 1 → COMMIT BLOCKED
|
|
408
|
-
→ judge disabled (config.judge.enabled: false):
|
|
409
|
-
→ falls back to original quality gate (blocks on CRITICAL/BLOCKER only)
|
|
410
|
-
```
|
|
411
|
-
|
|
412
|
-
**Flow 1.5: Interactive analysis command (v2.13.0)**
|
|
413
|
-
|
|
414
|
-
```
|
|
415
|
-
claude-hooks analyze
|
|
416
|
-
→ runs outside git hook context (stdin works)
|
|
417
|
-
→ getStagedFiles() → buildFilesData() → runAnalysis()
|
|
418
|
-
→ displayIssueSummary() → shows all severity levels (or "No issues found")
|
|
419
|
-
→ promptUserConfirmation() → interactive menu:
|
|
420
|
-
→ [y] Continue - executes createCommit('auto', { noVerify: true })
|
|
421
|
-
→ [n] Abort - generates resolution prompt
|
|
422
|
-
→ [v] View - shows detailed issues → returns to menu
|
|
423
|
-
→ on continue: git commit -m "auto" --no-verify
|
|
424
|
-
→ prepare-commit-msg hook generates message via Claude
|
|
425
|
-
→ commit created with auto-generated message
|
|
426
|
-
```
|
|
427
|
-
|
|
428
|
-
**Flow 2: Commit with automatic message**
|
|
429
|
-
|
|
430
|
-
```
|
|
431
|
-
git commit -m "auto"
|
|
432
|
-
→ hook extracts task-id from branch (feature/IX-123-add-auth)
|
|
433
|
-
→ Claude generates message → "[IX-123] feat: add user authentication"
|
|
434
|
-
→ writes to .git/COMMIT_EDITMSG
|
|
435
|
-
→ commit proceeds with generated message
|
|
436
|
-
```
|
|
437
|
-
|
|
438
|
-
**Flow 3: Analyze diff (v2.14.0)**
|
|
439
|
-
|
|
440
|
-
```
|
|
441
|
-
claude-hooks analyze-diff develop
|
|
442
|
-
→ lib/commands/analyze-diff.js (thin wrapper)
|
|
443
|
-
→ analyzeBranchForPR() (pr-metadata-engine.js)
|
|
444
|
-
→ fetchRemote() → resolveBaseBranch() (suggests similar branches if not found)
|
|
445
|
-
→ getChangedFilesBetweenRefs() → getCommitsBetweenRefs()
|
|
446
|
-
→ buildDiffPayload() → tiered reduction (context → proportional → stat-only)
|
|
447
|
-
→ executeClaudeWithRetry() → parses PRMetadata
|
|
448
|
-
→ formats metadata to console
|
|
449
|
-
→ saves to .claude/out/pr-analysis.json
|
|
450
|
-
```
|
|
451
|
-
|
|
452
|
-
**Flow 3.5: Analyze PR from GitHub URL**
|
|
453
|
-
|
|
454
|
-
```
|
|
455
|
-
claude-hooks analyze-pr https://github.com/owner/repo/pull/123
|
|
456
|
-
→ parseGitHubPRUrl() → { owner, repo, number }
|
|
457
|
-
→ fetchPullRequest() + fetchPullRequestFiles() via Octokit
|
|
458
|
-
→ extractLinearTicketFromTitle() → fetchTicket() (optional enrichment)
|
|
459
|
-
→ resolvePreset(): CLI flag → PR labels → ticket labels → auto-detect from extensions → 'default'
|
|
460
|
-
→ loadPrompt('ANALYZE_PR.md') with preset guidelines + category injection
|
|
461
|
-
→ executeClaudeWithRetry() → extractJSON() → normalizeCategory() with fuzzy aliases
|
|
462
|
-
→ interactive comment workflow: post all / select / skip
|
|
463
|
-
→ createPullRequestReview() with inline comments + review body
|
|
464
|
-
→ recordPRAnalysis() → .claude/statistics/pr/stats.jsonl
|
|
465
|
-
```
|
|
466
|
-
|
|
467
|
-
**Flow 4: PR creation (with auto-push v2.11.0, engine v2.14.0, merge strategy v2.25.0, label resolver v2.31.0, team reviewers v2.32.0)**
|
|
468
|
-
|
|
469
|
-
```
|
|
470
|
-
claude-hooks create-pr develop
|
|
471
|
-
→ checks branch push status (unpublished/unpushed commits)
|
|
472
|
-
→ shows commit preview → prompts for confirmation
|
|
473
|
-
→ pushes branch to remote (if needed)
|
|
474
|
-
→ selectReviewers({ org, teamSlug, prAuthor, configReviewers }):
|
|
475
|
-
1. listTeamMembers(org, teamSlug) → resolve team (default: 'automation')
|
|
476
|
-
2. filter out prAuthor
|
|
477
|
-
3. if team empty or API fails → fall back to config.github.pr.reviewers
|
|
478
|
-
→ detectMergeStrategy(sourceBranch, targetBranch):
|
|
479
|
-
feature/* → squash | release-fix/* → squash
|
|
480
|
-
release-candidate/* → merge-commit | hotfix/* → merge-commit
|
|
481
|
-
any → main → merge-commit | unknown → user prompted to select
|
|
482
|
-
→ resolveLabels({ preset, fileCount, mergeStrategy, analysisResult, localLabelRules }):
|
|
483
|
-
1. preset labels (remote presetLabels or local fallback)
|
|
484
|
-
2. size labels: size:S (<10) | size:M (10-50) | size:L (50-100) | size:XL (>100)
|
|
485
|
-
3. quality labels: breaking-change, security, performance (from analysisResult)
|
|
486
|
-
4. strategy label: merge-strategy:squash or merge-strategy:merge-commit
|
|
487
|
-
5. default labels (from remote config only, e.g. needs-review)
|
|
488
|
-
→ prepends body reminder for merge-commit
|
|
489
|
-
→ analyzeBranchForPR() (pr-metadata-engine.js) → generates metadata
|
|
490
|
-
→ interactive preview + strategy info line → user confirms
|
|
491
|
-
→ Octokit creates PR on GitHub
|
|
492
|
-
```
|
|
493
|
-
|
|
494
|
-
**Flow 5: Version bump with per-file editing (v2.16.0)**
|
|
495
|
-
|
|
496
|
-
```
|
|
497
|
-
claude-hooks bump-version patch --interactive
|
|
498
|
-
→ validatePrerequisites() → clean working directory, valid branch, remote
|
|
499
|
-
→ discoverVersionFiles() → recursive scan (max 3 levels)
|
|
500
|
-
→ displayDiscoveryTable() → shows all discovered files with versions
|
|
501
|
-
→ promptFileSelection() → interactive menu:
|
|
502
|
-
→ [a] Update all files - all files get same newVersion
|
|
503
|
-
→ [s] Select files - toggle list to pick subset
|
|
504
|
-
→ [e] Edit per file - promptEditField() per file:
|
|
505
|
-
→ user enters custom version per file (Enter keeps calculated version)
|
|
506
|
-
→ validateVersionFormat() → rejects invalid entries
|
|
507
|
-
→ stores file.targetVersion on each descriptor
|
|
508
|
-
→ [c] Cancel
|
|
509
|
-
→ incrementVersion() / modifySuffix() → calculates newVersion (used for tag + commit)
|
|
510
|
-
→ updateVersionFiles() → uses file.targetVersion || newVersion per file
|
|
511
|
-
→ createTag(newVersion) → tag reflects primary release version
|
|
512
|
-
→ commit message uses newVersion
|
|
513
|
-
```
|
|
514
|
-
|
|
515
|
-
**Per-file version design**: `VersionFileDescriptor` gains an optional `targetVersion` property at runtime, set only by option 'e'. When present, `updateVersionFiles()` writes `targetVersion` instead of the global `newVersion`. The tag and commit message always use the calculated `newVersion`.
|
|
516
|
-
|
|
517
|
-
**Flow 6: Release candidate creation (v2.27.0)**
|
|
518
|
-
|
|
519
|
-
```
|
|
520
|
-
claude-hooks create-release minor
|
|
521
|
-
→ parseArguments() → bumpType, noShadow, dryRun, skipPush, updateChangelog
|
|
522
|
-
→ validatePreconditions():
|
|
523
|
-
checkGitRepo()
|
|
524
|
-
isWorkingDirectoryClean() → abort if dirty
|
|
525
|
-
getCurrentBranch() === 'develop' → abort if not on develop
|
|
526
|
-
fetchRemote() → warn on failure, continue
|
|
527
|
-
getDivergence('develop','origin/develop') → behind>0 → abort + git pull advice
|
|
528
|
-
getDivergence('origin/develop','origin/main') → behind>0 → abort + back-merge advice
|
|
529
|
-
getRemoteBranches().filter('release-candidate/*') → any found → abort + close-release advice
|
|
530
|
-
verifyRemoteExists()
|
|
531
|
-
→ discoverVersionFiles()
|
|
532
|
-
mismatch → abort with table + fix steps (non-interactive, cannot auto-resolve)
|
|
533
|
-
→ incrementVersion(currentVersion, bumpType) [no suffix in branch name]
|
|
534
|
-
→ rcBranch = 'release-candidate/V{nextVersion}'
|
|
535
|
-
→ [--dry-run] → preview table → return
|
|
536
|
-
→ promptConfirmation()
|
|
537
|
-
→ checkoutBranch(rcBranch, { create: true, startPoint: 'develop' })
|
|
538
|
-
→ updateVersionFiles()
|
|
539
|
-
→ [--update-changelog] → generateChangelogEntry() + updateChangelogFile()
|
|
540
|
-
→ stageFiles() + createCommit('chore(version): bump to {nextVersion}', { noVerify: true })
|
|
541
|
-
→ tagExists()? → warn + skip : createTag()
|
|
542
|
-
→ [unless --skip-push] pushBranch(rcBranch, { setUpstream: true })
|
|
543
|
-
→ [unless --no-shadow and not --skip-push] runShadow(['sync', rcBranch])
|
|
544
|
-
shadow error → warn, don't abort
|
|
545
|
-
→ checkoutBranch(rcBranch) [safety: ensure we land on RC after shadow sync]
|
|
546
|
-
→ display summary (branch, version, tag, push status, shadow status)
|
|
547
|
-
```
|
|
548
|
-
|
|
549
|
-
**create-release design decisions:**
|
|
550
|
-
|
|
551
|
-
- Mismatch aborts non-interactively (automation context — ambiguity must be fixed by human)
|
|
552
|
-
- Tag creation mirrors `bump-version`: created on RC branch; if tag already exists → warn + skip (no interactive prompt)
|
|
553
|
-
- Shadow sync delegates to `runShadow(['sync', rcBranch])` (public API, reuses conflict-resolution logic from #93)
|
|
554
|
-
- `--skip-push` implies no shadow (cannot sync unpushed branch)
|
|
555
|
-
- Branch naming: `release-candidate/V{semver}` — capital V per team convention, no suffix in branch name
|
|
556
|
-
|
|
557
|
-
**Flow 7: Feature revert in release-candidate (v2.28.0)**
|
|
558
|
-
|
|
559
|
-
```
|
|
560
|
-
claude-hooks revert-feature AUT-3179
|
|
561
|
-
→ parseArgs() → taskId, updateShadow, dryRun
|
|
562
|
-
→ getCurrentBranch() — must start with 'release-candidate/'
|
|
563
|
-
→ isWorkingDirectoryClean() → abort if dirty
|
|
564
|
-
→ git log --grep="AUT-3179" --fixed-strings -i origin/main..HEAD
|
|
565
|
-
0 matches → abort
|
|
566
|
-
1 match → show commit details (hash, message, author, date, files)
|
|
567
|
-
2+ matches → promptMenu() → user selects one
|
|
568
|
-
→ getCommitFiles(targetHash) → target file set
|
|
569
|
-
→ _checkCoupling(): for each other RC commit (skip target, skip Revert commits):
|
|
570
|
-
getCommitFiles(hash) → intersect with targetFiles → collect { taskId, sharedFiles }
|
|
571
|
-
→ [--dry-run] → preview table → return
|
|
572
|
-
→ _displayCommitDetails() + coupling warnings (informational, before single confirmation)
|
|
573
|
-
→ promptConfirmation('Proceed with revert?', false)
|
|
574
|
-
→ git revert --no-edit <hash> → stdio: inherit (shows git output)
|
|
575
|
-
→ git rev-parse HEAD → revertHash
|
|
576
|
-
→ pushBranch(rcBranch)
|
|
577
|
-
→ _appendRevertLog(): append { taskId, originalHash, revertHash, rcBranch, timestamp }
|
|
578
|
-
to .claude/revert-log.json (array, consumed by back-merge #96)
|
|
579
|
-
→ [--update-shadow] runShadow(['sync', rcBranch]) → warn on failure, don't abort
|
|
580
|
-
→ display summary + revert-the-revert reminder:
|
|
581
|
-
git revert <revertHash> # Restores AUT-3179 for next sprint
|
|
582
|
-
```
|
|
583
|
-
|
|
584
|
-
**revert-feature design decisions:**
|
|
585
|
-
|
|
586
|
-
- Coupling check is informational only — warnings shown before single confirmation (no second prompt)
|
|
587
|
-
- `Revert "..."` commits are skipped in coupling scan (they intentionally share files)
|
|
588
|
-
- `revert-log.json` schema: `[{ taskId, originalHash, revertHash, rcBranch, timestamp }]` — array to support multiple reverts; consumed by back-merge (#96)
|
|
589
|
-
- `git revert` uses `stdio: 'inherit'` so the user sees git output (including conflict messages)
|
|
590
|
-
- Push failure: revert commit is kept locally; user shown manual `git push` command
|
|
591
|
-
- Shadow sync error: warns but does not abort (non-fatal, same pattern as `create-release`)
|
|
592
|
-
|
|
593
|
-
**Flow 8: Release candidate closure (v2.29.0)**
|
|
594
|
-
|
|
595
|
-
```
|
|
596
|
-
claude-hooks close-release "cashflow + auth"
|
|
597
|
-
→ _parseArgs() → description, autoDescribe, dryRun, noPr
|
|
598
|
-
→ detect RC branch: current branch or getActiveBranch('release-candidate') → offer checkout
|
|
599
|
-
→ _extractVersion(rcBranch) → semver string
|
|
600
|
-
→ isWorkingDirectoryClean() → abort if dirty
|
|
601
|
-
→ fetchRemote() → warn on failure
|
|
602
|
-
→ getDivergence(rc, origin/rc) → behind>0 → abort + git pull advice
|
|
603
|
-
→ _collectFeatureList(): getCommitsBetweenRefs('origin/main', 'HEAD', { format: '%s' })
|
|
604
|
-
→ _resolveDescription():
|
|
605
|
-
CLI arg → use directly
|
|
606
|
-
--auto-describe → executeClaudeWithRetry(haiku, 60s) → 1-line phrase
|
|
607
|
-
default → show list + promptEditField() → TL accepts or overrides
|
|
608
|
-
→ [--dry-run] → preview table → return
|
|
609
|
-
→ promptConfirmation()
|
|
610
|
-
→ resetBranch('origin/main', { mode: 'soft' }) — all RC commits staged
|
|
611
|
-
→ execSync('git commit --no-verify -F -', { input: fullMessage }) — subject + body
|
|
612
|
-
→ forcePush(rcBranch, { lease: true })
|
|
613
|
-
→ [unless --no-pr] validateToken() + createPullRequest(head→main, label: merge-strategy:merge-commit)
|
|
614
|
-
→ display summary with PR URL + merge-commit reminder
|
|
615
|
-
```
|
|
616
|
-
|
|
617
|
-
**close-release design decisions:**
|
|
618
|
-
|
|
619
|
-
- `git commit --no-verify -F -` (stdin) is used instead of `createCommit()` to support multi-line body; `execSync` passes the full message via `input` option (no shell injection risk — fixed string)
|
|
620
|
-
- `process.exit()` calls are placed _outside_ try/catch blocks so that mock-based tests can observe them; the catch only handles git errors
|
|
621
|
-
- Description priority: CLI arg > `--auto-describe` (Claude haiku, 60s timeout) > `promptEditField` (shows list, TL edits)
|
|
622
|
-
- Auto-describe fallback: if Claude fails or feature list is empty, falls back to interactive prompt without aborting
|
|
623
|
-
- `close-release` was already in `PROTECTED_COMMANDS` — authorization.js unchanged
|
|
624
|
-
- Force-push failure: exits 1 and shows manual push command (no retry — destructive op)
|
|
625
|
-
- PR creation failure: warns + shows `gh pr create` alternative (non-fatal; commit and push already done)
|
|
626
|
-
- `_extractVersion`, `_collectFeatureList`, `_resolveDescription` are exported for unit testing
|
|
627
|
-
|
|
628
|
-
## Code Conventions
|
|
629
|
-
|
|
630
|
-
### General Style
|
|
631
|
-
|
|
632
|
-
- **Format**: Prettier (config in `.prettierrc.json`)
|
|
633
|
-
- **Linting**: ESLint 8.57.0 (config in `.eslintrc.json`)
|
|
634
|
-
- **Indentation**: 4 spaces
|
|
635
|
-
- **Quotes**: Single quotes (strings), double quotes (HTML/imports)
|
|
636
|
-
- **Semicolons**: Required
|
|
637
|
-
|
|
638
|
-
### Naming
|
|
639
|
-
|
|
640
|
-
- **Files**: `kebab-case.js` (e.g., `claude-client.js`, `git-operations.js`)
|
|
641
|
-
- **Functions**: `camelCase()` (e.g., `getStagedFiles()`, `buildAnalysisPrompt()`)
|
|
642
|
-
- **Constants**: `UPPER_SNAKE_CASE` (e.g., `MAX_FILE_SIZE`, `ALLOWED_EXTENSIONS`)
|
|
643
|
-
- **Classes**: Not applicable (no classes, only exported functions)
|
|
644
|
-
- **Private variables**: `_` prefix (e.g., `_internalHelper()`)
|
|
645
|
-
|
|
646
|
-
### Exports
|
|
647
|
-
|
|
648
|
-
**Preferred pattern - Named exports:**
|
|
649
|
-
|
|
650
|
-
```javascript
|
|
651
|
-
// lib/utils/example.js
|
|
652
|
-
export function doSomething() { ... }
|
|
653
|
-
export function doOtherThing() { ... }
|
|
654
|
-
|
|
655
|
-
// consumer
|
|
656
|
-
import { doSomething, doOtherThing } from './utils/example.js';
|
|
657
|
-
```
|
|
658
|
-
|
|
659
|
-
**Avoid default exports** (except in `bin/claude-hooks` per CLI convention).
|
|
660
|
-
|
|
661
|
-
### Error Handling
|
|
662
|
-
|
|
663
|
-
**Standard pattern:**
|
|
664
|
-
|
|
665
|
-
```javascript
|
|
666
|
-
import { error } from './utils/logger.js';
|
|
667
|
-
|
|
668
|
-
try {
|
|
669
|
-
const result = dangerousOperation();
|
|
670
|
-
return result;
|
|
671
|
-
} catch (err) {
|
|
672
|
-
error(`Failed to perform operation: ${err.message}`);
|
|
673
|
-
process.exit(1); // In hooks and CLI commands
|
|
674
|
-
// or throw err; // In library functions
|
|
675
|
-
}
|
|
676
|
-
```
|
|
677
|
-
|
|
678
|
-
**Specific errors:**
|
|
679
|
-
|
|
680
|
-
- Git operations → `execSync()` with try-catch, log and exit
|
|
681
|
-
- Claude CLI → retry logic in `claude-client.js`, configurable timeout
|
|
682
|
-
- GitHub API → catch `@octokit/request-error`, user-friendly formatting
|
|
683
|
-
|
|
684
|
-
### Logging
|
|
685
|
-
|
|
686
|
-
```javascript
|
|
687
|
-
import { info, warning, error, debug } from './utils/logger.js';
|
|
688
|
-
|
|
689
|
-
info('✅ Operation completed'); // User-facing messages
|
|
690
|
-
warning('⚠️ Non-blocking issue detected'); // Warnings
|
|
691
|
-
error('❌ Critical failure'); // Errors
|
|
692
|
-
debug('Detailed diagnostic info'); // Only shown when debug=true
|
|
693
|
-
```
|
|
694
|
-
|
|
695
|
-
**Debug mode**: Activate with `claude-hooks --debug true` or in `.claude/config.json`.
|
|
696
|
-
|
|
697
|
-
### Async/Await
|
|
698
|
-
|
|
699
|
-
**Prefer async/await over callbacks:**
|
|
700
|
-
|
|
701
|
-
```javascript
|
|
702
|
-
// ✅ GOOD
|
|
703
|
-
async function analyzeCode(prompt) {
|
|
704
|
-
const result = await spawnClaude(prompt);
|
|
705
|
-
return result;
|
|
706
|
-
}
|
|
707
|
-
|
|
708
|
-
// ❌ BAD
|
|
709
|
-
function analyzeCode(prompt, callback) {
|
|
710
|
-
spawnClaude(prompt, callback);
|
|
711
|
-
}
|
|
712
|
-
```
|
|
713
|
-
|
|
714
|
-
### Reusable Modules
|
|
715
|
-
|
|
716
|
-
All modules in `lib/utils/` must:
|
|
717
|
-
|
|
718
|
-
1. Export pure functions (no global side effects)
|
|
719
|
-
2. Include inline JSDoc documentation
|
|
720
|
-
3. Accept configuration via parameters (no globals)
|
|
721
|
-
4. Return structured results (objects or arrays)
|
|
722
|
-
5. Log with `logger.js` (no direct `console.log`)
|
|
723
|
-
|
|
724
|
-
## Workflow
|
|
725
|
-
|
|
726
|
-
### Branching Strategy
|
|
727
|
-
|
|
728
|
-
This repository follows **simplified GitHub Flow**:
|
|
729
|
-
|
|
730
|
-
- **Main branch**: `main` (protected)
|
|
731
|
-
- **Feature branches**: `feature/issue-description` or `feature/TASK-ID-description`
|
|
732
|
-
- **Fix branches**: `fix/issue-description`
|
|
733
|
-
- **Hotfix branches**: `hotfix/urgent-description`
|
|
734
|
-
|
|
735
|
-
**Rules:**
|
|
736
|
-
|
|
737
|
-
1. All changes require PR to `main`
|
|
738
|
-
2. No direct commits to `main`
|
|
739
|
-
3. PRs require review (auto-merge NOT allowed)
|
|
740
|
-
|
|
741
|
-
### Development Process
|
|
742
|
-
|
|
743
|
-
**1. Initial setup (first time)**
|
|
744
|
-
|
|
745
|
-
```bash
|
|
746
|
-
git clone https://github.com/mscope-S-L/git-hooks.git
|
|
747
|
-
cd git-hooks
|
|
748
|
-
npm install
|
|
749
|
-
npm link # Install globally as symlink for development
|
|
750
|
-
```
|
|
751
|
-
|
|
752
|
-
**2. Create feature branch**
|
|
753
|
-
|
|
754
|
-
```bash
|
|
755
|
-
git checkout -b feature/new-functionality
|
|
756
|
-
# or with task-id: feature/IX-123-new-functionality
|
|
757
|
-
```
|
|
758
|
-
|
|
759
|
-
**3. Iterative development**
|
|
760
|
-
|
|
761
|
-
```bash
|
|
762
|
-
# Make changes...
|
|
763
|
-
npm run lint # Check linting
|
|
764
|
-
npm run test # Run tests
|
|
765
|
-
git add .
|
|
766
|
-
git commit -m "feat: add new functionality"
|
|
767
|
-
# Hooks execute automatically
|
|
768
|
-
```
|
|
769
|
-
|
|
770
|
-
**4. Local testing**
|
|
771
|
-
|
|
772
|
-
Test changes in a test repository:
|
|
773
|
-
|
|
774
|
-
```bash
|
|
775
|
-
# In test repo
|
|
776
|
-
cd /path/to/test-repo
|
|
777
|
-
claude-hooks install --force --skip-auth # Reinstall from symlink
|
|
778
|
-
git commit -m "test" # Test hook
|
|
779
|
-
```
|
|
780
|
-
|
|
781
|
-
**5. Create PR**
|
|
782
|
-
|
|
783
|
-
```bash
|
|
784
|
-
git push -u origin feature/new-functionality
|
|
785
|
-
claude-hooks analyze-diff main # Generate PR metadata
|
|
786
|
-
# or directly:
|
|
787
|
-
claude-hooks create-pr main # Create PR on GitHub (if MCP configured)
|
|
788
|
-
```
|
|
789
|
-
|
|
790
|
-
### CI/CD
|
|
791
|
-
|
|
792
|
-
**Currently**: No automated CI/CD (GitHub Actions pending).
|
|
793
|
-
|
|
794
|
-
**Manual verifications before merge:**
|
|
795
|
-
|
|
796
|
-
1. `npm run lint` → passes
|
|
797
|
-
2. `npm run test` → all tests pass
|
|
798
|
-
3. Manual testing in test repo
|
|
799
|
-
4. Peer code review
|
|
800
|
-
5. CHANGELOG.md updated
|
|
801
|
-
|
|
802
|
-
### Versioning
|
|
803
|
-
|
|
804
|
-
We follow **Semantic Versioning** (MAJOR.MINOR.PATCH):
|
|
805
|
-
|
|
806
|
-
- **MAJOR**: Breaking changes (e.g., 1.x → 2.0 with ES6 migration)
|
|
807
|
-
- **MINOR**: New features without breaking changes (e.g., 2.2 → 2.3 with presets)
|
|
808
|
-
- **PATCH**: Bug fixes (e.g., 2.6.0 → 2.6.1 with spawn ENOENT fix)
|
|
809
|
-
|
|
810
|
-
**Update version:**
|
|
811
|
-
|
|
812
|
-
```bash
|
|
813
|
-
npm version patch # 2.6.1 → 2.6.2
|
|
814
|
-
npm version minor # 2.6.1 → 2.7.0
|
|
815
|
-
npm version major # 2.6.1 → 3.0.0
|
|
816
|
-
```
|
|
817
|
-
|
|
818
|
-
**Publish to NPM:**
|
|
819
|
-
|
|
820
|
-
```bash
|
|
821
|
-
npm publish
|
|
822
|
-
```
|
|
823
|
-
|
|
824
|
-
### Conventional Commits
|
|
825
|
-
|
|
826
|
-
Format: `<type>(<scope>): <subject>`
|
|
827
|
-
|
|
828
|
-
**Types:**
|
|
829
|
-
|
|
830
|
-
- `feat`: New functionality
|
|
831
|
-
- `fix`: Bug fix
|
|
832
|
-
- `docs`: Documentation only
|
|
833
|
-
- `style`: Formatting (no logic change)
|
|
834
|
-
- `refactor`: Refactoring without functional change
|
|
835
|
-
- `test`: Add or modify tests
|
|
836
|
-
- `chore`: Maintenance (deps, config)
|
|
837
|
-
- `perf`: Performance improvements
|
|
838
|
-
|
|
839
|
-
**Optional scopes:**
|
|
840
|
-
|
|
841
|
-
- `hooks`: Changes in pre-commit or prepare-commit-msg
|
|
842
|
-
- `presets`: Preset system
|
|
843
|
-
- `github`: GitHub integration
|
|
844
|
-
- `cli`: Main CLI commands
|
|
845
|
-
- `config`: Configuration system
|
|
846
|
-
- `windows`: Windows-specific fixes
|
|
847
|
-
|
|
848
|
-
**Examples:**
|
|
849
|
-
|
|
850
|
-
```
|
|
851
|
-
feat(presets): add database preset for SQL analysis
|
|
852
|
-
fix(windows): resolve spawn ENOENT with .cmd files
|
|
853
|
-
docs: update CLAUDE.md with architecture details
|
|
854
|
-
chore(deps): upgrade @octokit/rest to v21
|
|
855
|
-
```
|
|
856
|
-
|
|
857
|
-
## Release Workflow Guide
|
|
858
|
-
|
|
859
|
-
This section provides a practical guide for Tech Leads and Senior developers who use the workflow automation commands. These commands are **protected** — they require `senior` or `tech-lead` role (based on GitHub repo permissions).
|
|
860
|
-
|
|
861
|
-
### Quick Reference — Release Commands
|
|
862
|
-
|
|
863
|
-
| Command | When to use | What it does |
|
|
864
|
-
| ---------------- | --------------------------- | ------------------------------------------------------------------------ |
|
|
865
|
-
| `check-coupling` | Before cutting a release | Scans open PRs for shared files — reveals which features are coupled |
|
|
866
|
-
| `create-release` | Tuesday release prep | Creates RC branch from develop, bumps version, pushes, deploys to shadow |
|
|
867
|
-
| `shadow` | Throughout QA cycle | Manages the shadow (QA) branch — analyze status, reset, or sync with RC |
|
|
868
|
-
| `revert-feature` | During QA, feature fails | Finds and reverts a feature by task ID in the RC, with coupling warnings |
|
|
869
|
-
| `close-release` | QA passed, ready for deploy | Squashes RC into one commit, force-pushes, creates PR to main |
|
|
870
|
-
| `back-merge` | After production deploy | Tags release, resets shadow, merges main→develop, cleans up RC branch |
|
|
871
|
-
| `create-pr` | Any PR creation | Creates GitHub PR with auto-detected merge strategy and labels |
|
|
872
|
-
| `bump-version` | Manual version changes | Bumps version files, commits, tags — used outside the release cycle |
|
|
873
|
-
|
|
874
|
-
### Release Lifecycle — Step by Step
|
|
875
|
-
|
|
876
|
-
The typical weekly release cycle follows this sequence:
|
|
877
|
-
|
|
878
|
-
```
|
|
879
|
-
1. TUESDAY — Prepare release
|
|
880
|
-
claude-hooks check-coupling ← Are any open PRs coupled?
|
|
881
|
-
claude-hooks create-release minor ← Create RC from develop, bump version, shadow deploy
|
|
882
|
-
|
|
883
|
-
2. TUESDAY–THURSDAY — QA cycle
|
|
884
|
-
claude-hooks shadow sync release-candidate ← Re-sync shadow after fixes
|
|
885
|
-
claude-hooks revert-feature AUT-XXXX ← Revert a failing feature if needed
|
|
886
|
-
claude-hooks shadow analyze ← Check shadow divergence
|
|
887
|
-
|
|
888
|
-
3. THURSDAY 12:00 — Close release
|
|
889
|
-
claude-hooks close-release "description" ← Squash RC, create PR to main
|
|
890
|
-
|
|
891
|
-
4. THURSDAY 13:00 — After deploy
|
|
892
|
-
claude-hooks back-merge ← Tag, reset shadow, merge main→develop, cleanup
|
|
893
|
-
```
|
|
894
|
-
|
|
895
|
-
### Command Details
|
|
896
|
-
|
|
897
|
-
#### check-coupling
|
|
898
|
-
|
|
899
|
-
Scans open PRs targeting a base branch and detects which ones share modified files (are "coupled"). Coupled features must ship together or be pulled together — reverting one may break the other.
|
|
900
|
-
|
|
901
|
-
```bash
|
|
902
|
-
claude-hooks check-coupling # PRs targeting develop (default)
|
|
903
|
-
claude-hooks check-coupling --base main # PRs targeting main
|
|
904
|
-
claude-hooks check-coupling --json # Machine-readable output for CI
|
|
905
|
-
```
|
|
906
|
-
|
|
907
|
-
| Flag | Effect |
|
|
908
|
-
| ----------------- | ------------------------------------------------------------------------------- |
|
|
909
|
-
| `--base <branch>` | Base branch to scan PRs against (default: `develop`) |
|
|
910
|
-
| `--json` | Output structured JSON with `coupledGroups`, `independentPRNumbers`, `warnings` |
|
|
911
|
-
|
|
912
|
-
**Not protected** — any developer can run this. Uses GitHub API to fetch PR file lists. Transitive coupling is detected (if A shares files with B, and B with C, all three are grouped).
|
|
913
|
-
|
|
914
|
-
---
|
|
915
|
-
|
|
916
|
-
#### create-release
|
|
917
|
-
|
|
918
|
-
Creates a release-candidate branch from `develop`, bumps version files (package.json, pom.xml, etc.), commits, pushes, and deploys to shadow. Replaces 8 manual steps.
|
|
919
|
-
|
|
920
|
-
```bash
|
|
921
|
-
claude-hooks create-release minor # Standard release (most common)
|
|
922
|
-
claude-hooks create-release patch # Hotfix-style bump
|
|
923
|
-
claude-hooks create-release major # Breaking change release
|
|
924
|
-
```
|
|
925
|
-
|
|
926
|
-
| Flag | Effect |
|
|
927
|
-
| -------------------- | -------------------------------------------------- |
|
|
928
|
-
| `--dry-run` | Preview all planned actions without making changes |
|
|
929
|
-
| `--no-shadow` | Skip shadow deployment after push |
|
|
930
|
-
| `--skip-push` | Keep everything local (implies no shadow) |
|
|
931
|
-
| `--update-changelog` | Generate and include CHANGELOG entry |
|
|
932
|
-
|
|
933
|
-
**Preconditions** (all checked automatically):
|
|
934
|
-
|
|
935
|
-
- Must be on `develop` branch
|
|
936
|
-
- Working directory must be clean
|
|
937
|
-
- `develop` must be up-to-date with remote
|
|
938
|
-
- `develop` must not be behind `main` (run `back-merge` first if so)
|
|
939
|
-
- No existing `release-candidate/*` branch on remote (run `close-release` first)
|
|
940
|
-
|
|
941
|
-
**Branch naming**: `release-candidate/V{version}` (capital V, e.g., `release-candidate/V2.31.0`).
|
|
942
|
-
|
|
943
|
-
---
|
|
944
|
-
|
|
945
|
-
#### shadow
|
|
946
|
-
|
|
947
|
-
Manages the shadow branch — an ephemeral QA environment with its own pipeline. Three subcommands:
|
|
948
|
-
|
|
949
|
-
**shadow analyze** — Show divergence status:
|
|
950
|
-
|
|
951
|
-
```bash
|
|
952
|
-
claude-hooks shadow analyze
|
|
953
|
-
```
|
|
954
|
-
|
|
955
|
-
Shows how shadow compares to `main` and the active RC (commits ahead/behind). Use this to check if shadow needs a sync.
|
|
956
|
-
|
|
957
|
-
**shadow reset** — Recreate shadow from main:
|
|
958
|
-
|
|
959
|
-
```bash
|
|
960
|
-
claude-hooks shadow reset # Destroys and recreates from main
|
|
961
|
-
claude-hooks shadow reset --dry-run # Preview only
|
|
962
|
-
```
|
|
963
|
-
|
|
964
|
-
Used at the start/end of a release cycle. Destroys the current shadow branch and creates a fresh copy from main. Prompts for confirmation.
|
|
965
|
-
|
|
966
|
-
**shadow sync** — Merge a source branch into shadow:
|
|
967
|
-
|
|
968
|
-
```bash
|
|
969
|
-
claude-hooks shadow sync release-candidate # Auto-detect latest RC
|
|
970
|
-
claude-hooks shadow sync release-candidate/V2.31.0 # Explicit RC version
|
|
971
|
-
claude-hooks shadow sync develop # Test develop in shadow
|
|
972
|
-
claude-hooks shadow sync feature/AUT-XXXX # Test a specific feature
|
|
973
|
-
claude-hooks shadow sync <source> --dry-run # Preview only
|
|
974
|
-
```
|
|
975
|
-
|
|
976
|
-
| Flag | Effect |
|
|
977
|
-
| ----------- | ------------------------------ |
|
|
978
|
-
| `--dry-run` | Preview sync without executing |
|
|
979
|
-
|
|
980
|
-
**Conflict resolution during sync**: version files → accept source; CHANGELOG → keep both (warn TL); other conflicts → abort merge and advise manual resolution.
|
|
981
|
-
|
|
982
|
-
---
|
|
983
|
-
|
|
984
|
-
#### revert-feature
|
|
985
|
-
|
|
986
|
-
Finds a squash-merged feature commit by its task ID in the current release-candidate, checks for coupling with other RC features, and reverts it.
|
|
987
|
-
|
|
988
|
-
```bash
|
|
989
|
-
claude-hooks revert-feature AUT-3179 # Find and revert
|
|
990
|
-
claude-hooks revert-feature AUT-3179 --update-shadow # Also re-deploy shadow
|
|
991
|
-
claude-hooks revert-feature AUT-3179 --dry-run # Preview only
|
|
992
|
-
```
|
|
993
|
-
|
|
994
|
-
| Flag | Effect |
|
|
995
|
-
| ----------------- | -------------------------------------------------- |
|
|
996
|
-
| `--dry-run` | Show what would be reverted without making changes |
|
|
997
|
-
| `--update-shadow` | After reverting, sync shadow with the updated RC |
|
|
998
|
-
|
|
999
|
-
**Preconditions**: Must be on a `release-candidate/*` branch. Working directory must be clean.
|
|
1000
|
-
|
|
1001
|
-
**Search behavior**:
|
|
1002
|
-
|
|
1003
|
-
- 0 matches → abort with "No commits found"
|
|
1004
|
-
- 1 match → show details, confirm with user
|
|
1005
|
-
- 2+ matches → interactive menu to select which commit
|
|
1006
|
-
|
|
1007
|
-
**Coupling detection**: Before reverting, checks if other RC commits modify the same files. Shows warnings like `"⚠️ [AUT-3200] also modifies EmailService.java"`. This is informational — you decide whether to proceed.
|
|
1008
|
-
|
|
1009
|
-
**After revert**: Writes to `.claude/revert-log.json` for `back-merge` follow-up. Shows reminder to revert-the-revert in develop after the release deploys.
|
|
1010
|
-
|
|
1011
|
-
---
|
|
1012
|
-
|
|
1013
|
-
#### close-release
|
|
1014
|
-
|
|
1015
|
-
Finalizes the active release-candidate: squashes all RC commits into a single clean commit via `git reset --soft`, force-pushes, and creates a PR to main.
|
|
1016
|
-
|
|
1017
|
-
```bash
|
|
1018
|
-
claude-hooks close-release # Auto-detect RC, prompt for description
|
|
1019
|
-
claude-hooks close-release "cashflow + auth" # Explicit description
|
|
1020
|
-
claude-hooks close-release --auto-describe # Claude generates 1-line summary
|
|
1021
|
-
claude-hooks close-release --dry-run # Preview only
|
|
1022
|
-
claude-hooks close-release --no-pr # Skip PR creation
|
|
1023
|
-
```
|
|
1024
|
-
|
|
1025
|
-
| Flag | Effect |
|
|
1026
|
-
| ----------------- | --------------------------------------------------------------------------- |
|
|
1027
|
-
| `--dry-run` | Preview planned actions (reset, commit message, PR) without executing |
|
|
1028
|
-
| `--auto-describe` | Use Claude (haiku, 60s timeout) to generate a description from feature list |
|
|
1029
|
-
| `--no-pr` | Perform the reset + commit + force-push but skip GitHub PR creation |
|
|
1030
|
-
|
|
1031
|
-
**Description priority**: CLI argument → `--auto-describe` → interactive prompt (shows feature list, TL accepts or edits).
|
|
1032
|
-
|
|
1033
|
-
**Commit format**:
|
|
1034
|
-
|
|
1035
|
-
```
|
|
1036
|
-
Release v2.31.0: cashflow improvements + auth fixes
|
|
1037
|
-
|
|
1038
|
-
Includes:
|
|
1039
|
-
- [AUT-3179] feat(cashflow): use Mailjet templates
|
|
1040
|
-
- [AUT-3200] fix(cashflow): handle invalid template ID
|
|
1041
|
-
```
|
|
1042
|
-
|
|
1043
|
-
**PR creation**: Labels with `merge-strategy:merge-commit` and adds body reminder. This PR **must** be merged with merge-commit (not squash) to preserve history for back-merge.
|
|
1044
|
-
|
|
1045
|
-
---
|
|
1046
|
-
|
|
1047
|
-
#### back-merge
|
|
1048
|
-
|
|
1049
|
-
Post-deploy synchronization: tags the release on main, resets shadow, merges main into develop (with auto-conflict resolution), and cleans up the RC branch.
|
|
1050
|
-
|
|
1051
|
-
```bash
|
|
1052
|
-
claude-hooks back-merge # Full post-deploy (main → develop)
|
|
1053
|
-
claude-hooks back-merge --from main --into develop # Explicit source/destination
|
|
1054
|
-
claude-hooks back-merge --skip-tag # Already tagged manually
|
|
1055
|
-
claude-hooks back-merge --skip-shadow # Skip shadow reset
|
|
1056
|
-
claude-hooks back-merge --dry-run # Preview only
|
|
1057
|
-
```
|
|
1058
|
-
|
|
1059
|
-
| Flag | Effect |
|
|
1060
|
-
| ----------------- | --------------------------------------------- |
|
|
1061
|
-
| `--dry-run` | Preview all planned actions without executing |
|
|
1062
|
-
| `--from <branch>` | Source branch (default: `main`) |
|
|
1063
|
-
| `--into <branch>` | Destination branch (default: `develop`) |
|
|
1064
|
-
| `--skip-tag` | Skip tag creation (useful if already tagged) |
|
|
1065
|
-
| `--skip-shadow` | Skip shadow reset step |
|
|
1066
|
-
|
|
1067
|
-
**Auto-conflict resolution**:
|
|
1068
|
-
| Conflict type | Resolution |
|
|
1069
|
-
|---|---|
|
|
1070
|
-
| Version files (pom.xml, package.json) | Accept source (released version) |
|
|
1071
|
-
| CHANGELOG.md | Keep both — destination on top, source below |
|
|
1072
|
-
| Other | Abort — TL resolves manually |
|
|
1073
|
-
|
|
1074
|
-
**Revert follow-up**: If `.claude/revert-log.json` exists (from `revert-feature`), shows reverted features and offers to revert-the-revert in develop (restores them for next sprint).
|
|
1075
|
-
|
|
1076
|
-
**Branch protection note**: `back-merge` pushes directly to `develop`. If branch protection requires PRs, you must temporarily disable it or have bypass permissions.
|
|
1077
|
-
|
|
1078
|
-
---
|
|
1079
|
-
|
|
1080
|
-
#### create-pr (merge strategy awareness)
|
|
1081
|
-
|
|
1082
|
-
When creating a PR, the merge strategy is auto-detected from branch naming and displayed in the preview:
|
|
1083
|
-
|
|
1084
|
-
| PR direction | Strategy | Label |
|
|
1085
|
-
| --------------------------------------- | --------------------------------- | ----------------------------- |
|
|
1086
|
-
| `feature/*` → `develop` | Squash merge | `merge-strategy:squash` |
|
|
1087
|
-
| `release-fix/*` → `release-candidate/*` | Squash merge | `merge-strategy:squash` |
|
|
1088
|
-
| `release-candidate/*` → `main` | Merge commit | `merge-strategy:merge-commit` |
|
|
1089
|
-
| `hotfix/*` → `main` | Merge commit | `merge-strategy:merge-commit` |
|
|
1090
|
-
| Any branch → `main` | Merge commit | `merge-strategy:merge-commit` |
|
|
1091
|
-
| Unknown pattern | Warning — user prompted to select | — |
|
|
1092
|
-
|
|
1093
|
-
For merge-commit PRs, a reminder is added to the PR body: `"> ⚠️ This PR must be merged with **merge commit** (not squash)"`.
|
|
1094
|
-
|
|
1095
|
-
### Authorization
|
|
1096
|
-
|
|
1097
|
-
All workflow commands (except `check-coupling` and `create-pr`) are protected by role-based authorization:
|
|
1098
|
-
|
|
1099
|
-
- **Protected commands**: `create-release`, `close-release`, `back-merge`, `shadow`, `revert-feature`, `bump-version`
|
|
1100
|
-
- **Role hierarchy**: `developer` < `senior` < `tech-lead`
|
|
1101
|
-
- **Role mapping**: GitHub repo permission `push` → developer, `maintain` → senior, `admin` → tech-lead
|
|
1102
|
-
- **Permissions source**: `git-hooks-config/permissions.json` repo (controlled by TL/Senior)
|
|
1103
|
-
- **Fail-closed**: Any auth error (no token, invalid token, network failure, repo not governed) blocks the command
|
|
1104
|
-
|
|
1105
|
-
If blocked: `"⛔ Command 'create-release' requires role 'senior'. Your role: developer. Contact your Tech Lead."`
|
|
1106
|
-
|
|
1107
|
-
## Useful Commands
|
|
1108
|
-
|
|
1109
|
-
### Development
|
|
1110
|
-
|
|
1111
|
-
```bash
|
|
1112
|
-
# Installation and setup
|
|
1113
|
-
npm install # Install dependencies
|
|
1114
|
-
npm link # Install globally as symlink
|
|
1115
|
-
npm unlink # Uninstall global symlink
|
|
1116
|
-
|
|
1117
|
-
# Testing
|
|
1118
|
-
npm test # Run all tests (Jest)
|
|
1119
|
-
npm run test:watch # Tests in watch mode
|
|
1120
|
-
npm run test:coverage # Coverage report
|
|
1121
|
-
|
|
1122
|
-
# Linting and formatting
|
|
1123
|
-
npm run lint # Check ESLint
|
|
1124
|
-
npm run lint:fix # Auto-fix ESLint issues
|
|
1125
|
-
npm run format # Format with Prettier
|
|
1126
|
-
|
|
1127
|
-
# Versioning
|
|
1128
|
-
npm version patch|minor|major # Bump version
|
|
1129
|
-
npm publish # Publish to NPM
|
|
1130
|
-
```
|
|
1131
|
-
|
|
1132
|
-
### Package CLI
|
|
1133
|
-
|
|
1134
|
-
```bash
|
|
1135
|
-
# Hook installation in a repo
|
|
1136
|
-
claude-hooks install # Interactive installation
|
|
1137
|
-
claude-hooks install --force # Reinstall without confirmation
|
|
1138
|
-
claude-hooks install --skip-auth # Skip Claude verification
|
|
1139
|
-
|
|
1140
|
-
# Hook management
|
|
1141
|
-
claude-hooks status # View current status
|
|
1142
|
-
claude-hooks enable [hook] # Enable all or specific hook
|
|
1143
|
-
claude-hooks disable [hook] # Disable all or specific hook
|
|
1144
|
-
claude-hooks uninstall # Completely uninstall
|
|
1145
|
-
|
|
1146
|
-
# Presets
|
|
1147
|
-
claude-hooks presets # List available presets
|
|
1148
|
-
claude-hooks --set-preset backend # Change preset
|
|
1149
|
-
claude-hooks preset current # View current preset
|
|
1150
|
-
|
|
1151
|
-
# Linting
|
|
1152
|
-
claude-hooks lint # Lint staged files
|
|
1153
|
-
claude-hooks lint src/ # Lint all files in directory
|
|
1154
|
-
claude-hooks lint src/ lib/utils/ # Multiple directories
|
|
1155
|
-
claude-hooks lint file1.js file2.js # Specific files
|
|
1156
|
-
claude-hooks lint src/ file.js lib/ # Mix of dirs and files
|
|
1157
|
-
|
|
1158
|
-
# Analysis and PRs
|
|
1159
|
-
claude-hooks analyze-diff [branch] # Analyze diff for PR
|
|
1160
|
-
claude-hooks analyze-pr <pr-url> # Analyze GitHub PR with team guidelines
|
|
1161
|
-
claude-hooks analyze-pr <url> --dry-run # Analyze without posting comments
|
|
1162
|
-
claude-hooks check-coupling # Detect coupled PRs targeting develop
|
|
1163
|
-
claude-hooks check-coupling --base main # Explicit base branch
|
|
1164
|
-
claude-hooks check-coupling --json # Machine-readable JSON output
|
|
1165
|
-
claude-hooks shadow analyze # Show shadow divergence vs main + active RC
|
|
1166
|
-
claude-hooks shadow reset # Destroy shadow and recreate from main
|
|
1167
|
-
claude-hooks shadow reset --dry-run # Preview reset without executing
|
|
1168
|
-
claude-hooks shadow sync release-candidate # Merge latest RC into shadow (auto-detect)
|
|
1169
|
-
claude-hooks shadow sync release-candidate/V2.7.0 # Merge explicit RC into shadow
|
|
1170
|
-
claude-hooks shadow sync develop # Merge develop into shadow
|
|
1171
|
-
claude-hooks shadow sync release-candidate --dry-run # Preview sync without executing
|
|
1172
|
-
claude-hooks create-release minor # Create RC branch, bump, push, shadow
|
|
1173
|
-
claude-hooks create-release minor --no-shadow # Skip shadow deployment
|
|
1174
|
-
claude-hooks create-release minor --dry-run # Preview only
|
|
1175
|
-
claude-hooks create-release minor --skip-push # Local only (skips shadow too)
|
|
1176
|
-
claude-hooks create-release minor --update-changelog # Include CHANGELOG
|
|
1177
|
-
claude-hooks revert-feature AUT-3179 # Find and revert by task ID
|
|
1178
|
-
claude-hooks revert-feature AUT-3179 --update-shadow # Revert and re-deploy shadow
|
|
1179
|
-
claude-hooks revert-feature AUT-3179 --dry-run # Preview only
|
|
1180
|
-
claude-hooks close-release # Auto-detect RC, prompt for description
|
|
1181
|
-
claude-hooks close-release "cashflow + auth" # Explicit description
|
|
1182
|
-
claude-hooks close-release --auto-describe # Claude generates summary
|
|
1183
|
-
claude-hooks close-release --dry-run # Preview only
|
|
1184
|
-
claude-hooks close-release --no-pr # Skip PR creation
|
|
1185
|
-
claude-hooks create-pr [branch] # Create PR on GitHub
|
|
1186
|
-
claude-hooks setup-github # Configure GitHub token
|
|
1187
|
-
claude-hooks setup-linear # Configure Linear token
|
|
1188
|
-
|
|
1189
|
-
# Version management
|
|
1190
|
-
claude-hooks bump-version patch # Bump version (commits, tags locally)
|
|
1191
|
-
claude-hooks bump-version minor --suffix SNAPSHOT # With suffix
|
|
1192
|
-
claude-hooks bump-version major --update-changelog # With CHANGELOG
|
|
1193
|
-
claude-hooks bump-version patch --push # Push tag immediately
|
|
1194
|
-
claude-hooks bump-version patch --no-commit # Manual workflow
|
|
1195
|
-
claude-hooks bump-version patch --interactive # Force file selection menu
|
|
1196
|
-
claude-hooks generate-changelog # Generate CHANGELOG only
|
|
1197
|
-
|
|
1198
|
-
# Help and issue reporting
|
|
1199
|
-
claude-hooks help "how do presets work?" # AI-powered help (uses CLAUDE.md)
|
|
1200
|
-
claude-hooks help --report-issue # Interactive issue creation
|
|
1201
|
-
|
|
1202
|
-
# Orchestration diagnostics
|
|
1203
|
-
claude-hooks batch-info # Orchestration config + per-model speed telemetry
|
|
1204
|
-
|
|
1205
|
-
# Debugging
|
|
1206
|
-
claude-hooks --debug true # Enable debug mode
|
|
1207
|
-
claude-hooks --debug false # Disable debug mode
|
|
1208
|
-
claude-hooks --debug status # View debug status
|
|
1209
|
-
|
|
1210
|
-
# Auto-update
|
|
1211
|
-
claude-hooks update # Update to latest version
|
|
1212
|
-
```
|
|
1213
|
-
|
|
1214
|
-
### Git with Active Hooks
|
|
1215
|
-
|
|
1216
|
-
```bash
|
|
1217
|
-
# Normal commit with analysis
|
|
1218
|
-
git commit -m "feat: new functionality"
|
|
1219
|
-
|
|
1220
|
-
# Commit with automatic message
|
|
1221
|
-
git commit -m "auto" # Claude generates the message
|
|
1222
|
-
|
|
1223
|
-
# Skip analysis (emergencies)
|
|
1224
|
-
git commit --no-verify -m "hotfix: urgent"
|
|
1225
|
-
|
|
1226
|
-
# Amend last commit
|
|
1227
|
-
git commit --amend
|
|
1228
|
-
```
|
|
1229
|
-
|
|
1230
|
-
### Local Testing in Test Repo
|
|
1231
|
-
|
|
1232
|
-
```bash
|
|
1233
|
-
# Initial setup
|
|
1234
|
-
cd /path/to/test-repo
|
|
1235
|
-
claude-hooks install --force --skip-auth
|
|
1236
|
-
|
|
1237
|
-
# After changes in claude-hooks
|
|
1238
|
-
# (npm link is already active, no need to reinstall)
|
|
1239
|
-
cd /path/to/test-repo
|
|
1240
|
-
git add test.txt
|
|
1241
|
-
git commit -m "test: validate changes"
|
|
1242
|
-
# Hooks use local version automatically
|
|
1243
|
-
```
|
|
1244
|
-
|
|
1245
|
-
## Testing
|
|
1246
|
-
|
|
1247
|
-
### Test Framework
|
|
1248
|
-
|
|
1249
|
-
- **Framework**: Jest with ES6 modules (`--experimental-vm-modules`)
|
|
1250
|
-
- **Location**: `test/unit/*.test.js`
|
|
1251
|
-
- **Naming**: `{module-name}.test.js` matches `lib/utils/{module-name}.js`
|
|
1252
|
-
- **Run**: `npm test` (all), `npm run test:watch` (watch mode)
|
|
1253
|
-
|
|
1254
|
-
### Test Patterns
|
|
1255
|
-
|
|
1256
|
-
```javascript
|
|
1257
|
-
// test/unit/example.test.js
|
|
1258
|
-
import { functionToTest } from '../../lib/utils/example.js';
|
|
1259
|
-
|
|
1260
|
-
describe('functionToTest', () => {
|
|
1261
|
-
it('should handle normal input', () => {
|
|
1262
|
-
const result = functionToTest('input');
|
|
1263
|
-
expect(result).toBe('expected');
|
|
1264
|
-
});
|
|
1265
|
-
|
|
1266
|
-
it('should throw on invalid input', () => {
|
|
1267
|
-
expect(() => functionToTest(null)).toThrow('Invalid input');
|
|
1268
|
-
});
|
|
1269
|
-
});
|
|
1270
|
-
```
|
|
1271
|
-
|
|
1272
|
-
### Mocking
|
|
1273
|
-
|
|
1274
|
-
```javascript
|
|
1275
|
-
// Mock child_process for git/claude commands
|
|
1276
|
-
import { jest } from '@jest/globals';
|
|
1277
|
-
import { execSync } from 'child_process';
|
|
1278
|
-
|
|
1279
|
-
jest.mock('child_process');
|
|
1280
|
-
execSync.mockReturnValue('mocked output');
|
|
1281
|
-
```
|
|
1282
|
-
|
|
1283
|
-
### Coverage
|
|
1284
|
-
|
|
1285
|
-
No enforced threshold. Focus on critical paths:
|
|
1286
|
-
|
|
1287
|
-
- `claude-client.js` - Claude CLI interaction
|
|
1288
|
-
- `git-operations.js` - Git command abstraction
|
|
1289
|
-
- `config.js` - Configuration merging
|
|
1290
|
-
|
|
1291
|
-
## Proven Implementation Patterns
|
|
1292
|
-
|
|
1293
|
-
Recurring patterns validated across 15+ automation sessions. Apply these in new code to avoid known pitfalls.
|
|
1294
|
-
|
|
1295
|
-
### Testability
|
|
1296
|
-
|
|
1297
|
-
- **`process.exit()` outside try/catch**: Mocking `process.exit` to throw requires the throw to propagate. Any surrounding `catch (e)` silently swallows it. Pattern: capture fallible values inside try/catch, check them and exit *outside* the catch block.
|
|
1298
|
-
- **`jest.resetAllMocks()` over `clearAllMocks()`**: `clearAllMocks()` clears call history but does NOT drain `mockResolvedValueOnce` queues. Tests that leave unconsumed values silently corrupt subsequent tests. Use `resetAllMocks()` in `beforeEach` and re-apply all defaults explicitly.
|
|
1299
|
-
- **`_privateHelper` export for unit testing**: Private-by-convention functions (`_` prefix) can be exported for direct unit testing without invoking the full command flow. Used in `close-release.js`, `revert-feature.js`, `shadow.js`.
|
|
1300
|
-
|
|
1301
|
-
### Git Operations
|
|
1302
|
-
|
|
1303
|
-
- **`execSync` with `input` for multi-line commit messages**: `git commit -F -` with `execSync({ input: fullMessage })` avoids temp files, heredocs, and `\n` escaping. Used when `createCommit()` (which only supports `-m`) is insufficient.
|
|
1304
|
-
- **`git diff-tree --no-commit-id -r --name-only <hash>`**: Canonical command to list files changed in a single commit. Preferable to parsing `git show --stat` (fragile) or `getChangedFilesBetweenRefs('<hash>^', '<hash>')` (breaks on first commit).
|
|
1305
|
-
- **`git merge --no-verify --no-ff` via `execSync`**: `mergeBranch()` in `git-operations.js` does not support `--no-verify`. For hook-free merges (shadow sync, back-merge), use `execSync` directly with the full flags.
|
|
1306
|
-
|
|
1307
|
-
### Architecture
|
|
1308
|
-
|
|
1309
|
-
- **`PROTECTED_COMMANDS` fast-path**: Static Set check before any API call — non-protected commands short-circuit with zero network overhead. Pattern for any guard that only applies to a subset of commands.
|
|
1310
|
-
- **Graceful degradation for features, fail-closed for security**: Labels, shadow sync, CHANGELOG — warn and continue on failure. Authorization, permissions — block on any error. Two fetch patterns for the same config repo.
|
|
1311
|
-
- **Inline Set intersection over Union-Find for single-target checks**: `coupling-detector.js` Union-Find is for N-PR transitive grouping. For checking one commit against others (revert-feature), a simple `Set` intersection per item is sufficient.
|
|
1312
|
-
|
|
1313
|
-
## Restrictions
|
|
1314
|
-
|
|
1315
|
-
### What Claude should NOT do in this repository
|
|
1316
|
-
|
|
1317
|
-
1. **DO NOT add interactive prompts to git hooks**
|
|
1318
|
-
- Git hooks run with stdin redirected from `/dev/null`
|
|
1319
|
-
- Readline-based prompts cannot read user input in hook context
|
|
1320
|
-
- Works in IDE integrations (VSCode, IntelliJ) but breaks in terminal
|
|
1321
|
-
- **Solution**: Use `claude-hooks analyze` command instead (runs outside hook context)
|
|
1322
|
-
- **Rationale**: Discovered through manual testing in Issue #20
|
|
1323
|
-
|
|
1324
|
-
2. **DO NOT modify bash wrappers without corresponding Node.js changes**
|
|
1325
|
-
- `templates/pre-commit` and `templates/prepare-commit-msg` are wrappers
|
|
1326
|
-
- Real logic is in `lib/hooks/*.js`
|
|
1327
|
-
- Changes to bash should be minimal (only Node.js invocation)
|
|
1328
|
-
|
|
1329
|
-
3. **DO NOT use `shell: true` in `spawn()` calls**
|
|
1330
|
-
- Deprecated in Node.js 24 (DEP0190)
|
|
1331
|
-
- Use `which-command.js` to resolve executable paths
|
|
1332
|
-
- **Exception**: Windows with `.cmd`/`.bat` requires `cmd.exe /c` wrapper
|
|
1333
|
-
|
|
1334
|
-
4. **DO NOT modify config priority order**
|
|
1335
|
-
- Maintain: defaults < user config < preset config
|
|
1336
|
-
- Preset always wins (tech-stack specific has priority over user preferences)
|
|
1337
|
-
|
|
1338
|
-
5. **DO NOT create duplicate config files**
|
|
1339
|
-
- Single `.claude/config.json` per repo
|
|
1340
|
-
- Presets live in `.claude/presets/{name}/`
|
|
1341
|
-
- Do not create `.env` or similar files for configuration
|
|
1342
|
-
|
|
1343
|
-
6. **DO NOT make breaking changes without MAJOR version bump**
|
|
1344
|
-
- Changes in config.json structure → MAJOR
|
|
1345
|
-
- Changes in CLI arguments → MAJOR
|
|
1346
|
-
- Changes in template format → MINOR if backward compatible, otherwise MAJOR
|
|
1347
|
-
|
|
1348
|
-
7. **DO NOT hardcode absolute paths**
|
|
1349
|
-
- Use `getRepoRoot()` from `git-operations.js`
|
|
1350
|
-
- All paths relative to repo root
|
|
1351
|
-
- Exception: paths in `PATH` resolved with `which-command.js`
|
|
1352
|
-
|
|
1353
|
-
8. **DO NOT use `console.log` directly**
|
|
1354
|
-
- Always use `logger.js`: `info()`, `warning()`, `error()`, `debug()`
|
|
1355
|
-
- Enables centralized output control and debug mode
|
|
1356
|
-
|
|
1357
|
-
9. **DO NOT execute Claude CLI without timeout**
|
|
1358
|
-
- Always configure timeout (default: 360s analysis, 300s commit msg)
|
|
1359
|
-
- Timeout configurable in `.claude/config.json`
|
|
1360
|
-
|
|
1361
|
-
10. **DO NOT ignore platform-specific issues**
|
|
1362
|
-
- Test changes on Windows, Linux, and macOS
|
|
1363
|
-
- Path separators: use `path.join()` (no hardcoded `/`)
|
|
1364
|
-
- Line endings: templates use LF, convert on install if needed
|
|
1365
|
-
|
|
1366
|
-
11. **DO NOT commit secrets**
|
|
1367
|
-
- `.claude/settings.local.json` is in `.gitignore`
|
|
1368
|
-
- GitHub tokens should go in settings.local or env vars
|
|
1369
|
-
- Never in `.claude/config.json` (tracked)
|
|
1370
|
-
|
|
1371
|
-
12. **DO NOT modify project `.gitignore` without consultation**
|
|
1372
|
-
- `.claude/` is ignored by design (user-specific)
|
|
1373
|
-
- `node_modules/` obvious
|
|
1374
|
-
- New entries must be justified
|
|
1375
|
-
|
|
1376
|
-
13. **DO NOT add dependencies without validation**
|
|
1377
|
-
- Only 1 runtime dependency currently: `@octokit/rest`
|
|
1378
|
-
- New deps must be justified (no built-in alternative?)
|
|
1379
|
-
- Dev deps are OK if they improve DX (testing, linting)
|
|
1380
|
-
|
|
1381
|
-
14. **DO NOT perform git operations add, commit, push unless asked to**
|
|
1382
|
-
- Git flow associated with normal development must be left to human user
|
|
1383
|
-
|
|
1384
|
-
### Technical Limitations
|
|
1385
|
-
|
|
1386
|
-
1. **Node.js versions**: >=16.9.0 required (ES6 module features)
|
|
1387
|
-
2. **Claude CLI**: Must be installed and authenticated externally
|
|
1388
|
-
3. **Git**: Requires initialized repo (doesn't work outside git repos)
|
|
1389
|
-
4. **Parallel analysis**: Minimum 3 files to activate
|
|
1390
|
-
5. **File size**: Default max 1MB per file (configurable)
|
|
1391
|
-
6. **Max files**: Default 30 files per commit (configurable)
|
|
1392
|
-
7. **GitHub API**: Rate limits apply (5000 req/hour authenticated)
|
|
1393
|
-
|
|
1394
|
-
### Security Considerations
|
|
1395
|
-
|
|
1396
|
-
1. **Input sanitization**: Use `sanitize.js` for user inputs in shell commands
|
|
1397
|
-
2. **Token storage**: GitHub tokens in settings.local (gitignored) or env vars, NEVER tracked
|
|
1398
|
-
3. **Shell injection**: Avoid `shell: true`, use arrays in spawn()
|
|
1399
|
-
4. **Path traversal**: Validate relative paths before file operations
|
|
1400
|
-
5. **Secrets in diffs**: Hook should NOT prevent commits with secrets (user responsibility)
|
|
35
|
+
> See [`CLAUDE-MIGRATION.md`](CLAUDE-MIGRATION.md) for a mapping of where each original CLAUDE.md section moved.
|