claude-git-hooks 2.20.0 → 2.21.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 CHANGED
@@ -5,6 +5,24 @@ Todos los cambios notables en este proyecto se documentarán en este archivo.
5
5
  El formato está basado en [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  y este proyecto adhiere a [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [2.21.0] - 2026-03-10
9
+
10
+ ### ✨ Added
11
+ - New `analyze-pr` command to analyze GitHub PRs with team guidelines and post review comments (#86)
12
+ - Linear ticket enrichment for PR analysis - automatically fetches ticket context when `[AUT-1234]` pattern found in PR title
13
+ - New `setup-linear` command for interactive Linear token configuration
14
+ - Centralized token persistence via `token-store.js` utility for managing settings.local.json
15
+ - PR statistics tracking with write-only JSONL analytics at `.claude/statistics/pr/stats.jsonl`
16
+ - Interactive comment workflow for PR analysis - confirm, select, or skip findings before posting
17
+ - Auto-detection of preset from PR labels, Linear ticket labels, or file extensions
18
+ - New `ANALYZE_PR.md` prompt template for GitHub PR review with category injection
19
+ - Category normalization with fuzzy alias mapping for analysis results
20
+
21
+ ### 🔧 Changed
22
+ - Extended `github-api.js` with PR fetch, review creation, and URL parsing capabilities
23
+ - Updated documentation (README, README-NPM, CLAUDE.md) with analyze-pr usage and architecture
24
+
25
+
8
26
  ## [2.20.0] - 2026-03-09
9
27
 
10
28
  ### ✨ Added
package/CLAUDE.md CHANGED
@@ -10,7 +10,8 @@
10
10
  2. **Interactive analysis**: `claude-hooks analyze` - review all issues (INFO to BLOCKER) interactively before committing
11
11
  3. **Automatic messages**: Write `git commit -m "auto"` and Claude generates the message in Conventional Commits format with task-id extracted from branch
12
12
  4. **PR analysis**: `claude-hooks analyze-diff [branch]` generates title, description, and test plan for PRs
13
- 5. **PR creation**: `claude-hooks create-pr [branch]` creates the PR on GitHub with automatic metadata (reviewers from CODEOWNERS, labels by preset)
13
+ 5. **PR review**: `claude-hooks analyze-pr <url>` analyzes a GitHub PR with preset guidelines, Linear ticket enrichment, and posts review comments
14
+ 6. **PR creation**: `claude-hooks create-pr [branch]` creates the PR on GitHub with automatic metadata (reviewers from CODEOWNERS, labels by preset)
14
15
 
15
16
  ## Architecture
16
17
 
@@ -54,8 +55,10 @@ claude-git-hooks/
54
55
  │ │ ├── install.js # Install command - dependencies, hooks, templates
55
56
  │ │ ├── hooks.js # Hook management - enable, disable, status, uninstall
56
57
  │ │ ├── analyze-diff.js # Diff analysis - generate PR metadata from git diff
58
+ │ │ ├── analyze-pr.js # PR analysis - analyze GitHub PR with team guidelines
57
59
  │ │ ├── create-pr.js # PR creation - full Octokit workflow
58
60
  │ │ ├── setup-github.js # Token setup - interactive GitHub configuration
61
+ │ │ ├── setup-linear.js # Token setup - interactive Linear configuration
59
62
  │ │ ├── presets.js # Preset management - list, set, show current
60
63
  │ │ ├── update.js # Self-update - check and install latest version
61
64
  │ │ ├── migrate-config.js # Config migration - legacy to v2.8.0 format
@@ -78,8 +81,11 @@ claude-git-hooks/
78
81
  │ ├── logger.js # Logging system - centralized output, debug mode
79
82
  │ ├── preset-loader.js # Preset system - load tech-stack configurations
80
83
  │ ├── pr-metadata-engine.js # PR metadata generation - branch context, diff reduction, metadata (v2.14.0)
81
- │ ├── github-api.js # Octokit integration - PR creation, token validation
84
+ │ ├── github-api.js # Octokit integration - PR creation, PR analysis, token validation
82
85
  │ ├── github-client.js # GitHub helpers - CODEOWNERS parsing, reviewers
86
+ │ ├── token-store.js # Token persistence - centralized settings.local.json read/write
87
+ │ ├── linear-connector.js # Linear API - ticket context fetching with retry
88
+ │ ├── pr-statistics.js # PR statistics - write-only JSONL analytics
83
89
  │ ├── task-id.js # Task ID extraction - Jira, GitHub, Linear patterns
84
90
  │ ├── interactive-ui.js # CLI UI components - previews, prompts, spinners
85
91
  │ ├── judge.js # Auto-fix judge - LLM verdict + search/replace fixes (v2.20.0)
@@ -100,6 +106,7 @@ claude-git-hooks/
100
106
  │ ├── CLAUDE_ANALYSIS_PROMPT.md # Analysis prompt - code review template
101
107
  │ ├── CLAUDE_RESOLUTION_PROMPT.md # Resolution prompt - structured JSON output for judge + manual use
102
108
  │ ├── ANALYZE_DIFF.md # PR analysis - diff review template
109
+ │ ├── ANALYZE_PR.md # PR analysis - GitHub PR review template with category injection
103
110
  │ ├── GENERATE_CHANGELOG.md # CHANGELOG generation - commit analysis template (v2.12.0)
104
111
  │ ├── DIFF_ANALYSIS_ORCHESTRATION_PROMPT.md # Orchestration prompt - Opus batch grouping (v2.20.0)
105
112
  │ ├── HELP_QUERY.md # AI help - question answering with NEED_MORE_CONTEXT protocol (v2.18.0)
@@ -186,8 +193,10 @@ preset config (.claude/presets/{name}/config.json) ← HIGHEST PRIORITY
186
193
  | Analysis timeout | 300s | Per-batch timeout |
187
194
  | Commit msg timeout | 300s | Message generation timeout |
188
195
  | PR metadata timeout | 180s | Engine default (reads config) |
189
- | Judge model | opus | Default, configurable via `config.judge.model` |
196
+ | Judge model | sonnet | Default, configurable via `config.judge.model` |
190
197
  | Judge timeout | 120s | Per-judge call timeout |
198
+ | PR analysis model | sonnet | Default, configurable via `config.prAnalysis.model` |
199
+ | PR analysis timeout | 300s | Per-analysis Claude call |
191
200
 
192
201
  **Judge behavior (v2.20.0):**
193
202
 
@@ -252,10 +261,12 @@ consolidateResults()
252
261
  | `hooks.js` | Hook management | `runEnable()`, `runDisable()`, `runStatus()`, `runUninstall()` |
253
262
  | `analyze.js` | Interactive code analysis | `runAnalyze()` |
254
263
  | `analyze-diff.js` | Diff analysis | `runAnalyzeDiff()` |
264
+ | `analyze-pr.js` | PR analysis from URL | `runAnalyzePr()`, `normalizeCategory()` |
255
265
  | `create-pr.js` | PR creation | `runCreatePr()` |
256
266
  | `bump-version.js` | Version management | `runBumpVersion()` |
257
267
  | `generate-changelog.js` | CHANGELOG generation | `runGenerateChangelog()` |
258
- | `setup-github.js` | Token setup | `runSetupGitHub()` |
268
+ | `setup-github.js` | Token setup (GitHub) | `runSetupGitHub()` |
269
+ | `setup-linear.js` | Token setup (Linear) | `runSetupLinear()` |
259
270
  | `presets.js` | Preset management | `runShowPresets()`, `runSetPreset()`, `runCurrentPreset()` |
260
271
  | `update.js` | Self-update | `runUpdate()` |
261
272
  | `migrate-config.js` | Config migration | `runMigrateConfig()` |
@@ -280,8 +291,11 @@ consolidateResults()
280
291
  | `git-tag-manager.js` | Git tag operations | `createTag()`, `pushTags()`, `getLocalTags()`, `getRemoteTags()`, `compareLocalAndRemoteTags()`, `tagExists()` (v2.12.0) |
281
292
  | `version-manager.js` | Version management | `discoverVersionFiles()`, `getDiscoveryResult()`, `readVersionFromFile()`, `writeVersionToFile()`, `updateVersionFiles()`, `modifySuffix()`, `incrementVersion()`, `parseVersion()`, `validateVersionFormat()`, `compareVersions()`, `validateVersionAlignment()` (v2.15.5) |
282
293
  | `changelog-generator.js` | CHANGELOG generation | `generateChangelogEntry()`, `updateChangelogFile()`, `getLastFinalVersionTag()`, `getCommitsSinceTag()`, `discoverChangelogFiles()`, `selectChangelogFile()` (v2.12.0) |
283
- | `github-api.js` | Octokit integration | `createPullRequest()`, `validateToken()`, `saveGitHubToken()`, `fetchFileContent()`, `fetchDirectoryListing()`, `createIssue()` |
294
+ | `github-api.js` | Octokit integration | `createPullRequest()`, `fetchPullRequest()`, `fetchPullRequestFiles()`, `createPullRequestReview()`, `parseGitHubPRUrl()`, `validateToken()`, `saveGitHubToken()`, `fetchFileContent()`, `fetchDirectoryListing()`, `createIssue()` |
284
295
  | `github-client.js` | GitHub helpers | `getReviewersForFiles()`, `parseGitHubRepo()` |
296
+ | `token-store.js` | Token persistence | `loadToken()`, `saveToken()`, `hasToken()`, `loadLocalSettings()` |
297
+ | `linear-connector.js` | Linear integration | `loadLinearToken()`, `testConnection()`, `fetchTicket()`, `extractLinearTicketFromTitle()`, `parseLinearIdentifier()`, `LinearConnectorError` |
298
+ | `pr-statistics.js` | PR statistics | `recordPRAnalysis()` — write-only JSONL at `.claude/statistics/pr/stats.jsonl` |
285
299
  | `preset-loader.js` | Preset system | `loadPreset()`, `listPresets()` |
286
300
  | `task-id.js` | Task ID extraction | `getOrPromptTaskId()`, `formatWithTaskId()` |
287
301
  | `logger.js` | Logging system | `info()`, `warning()`, `error()`, `debug()` |
@@ -361,6 +375,21 @@ claude-hooks analyze-diff develop
361
375
  → saves to .claude/out/pr-analysis.json
362
376
  ```
363
377
 
378
+ **Flow 3.5: Analyze PR from GitHub URL**
379
+
380
+ ```
381
+ claude-hooks analyze-pr https://github.com/owner/repo/pull/123
382
+ → parseGitHubPRUrl() → { owner, repo, number }
383
+ → fetchPullRequest() + fetchPullRequestFiles() via Octokit
384
+ → extractLinearTicketFromTitle() → fetchTicket() (optional enrichment)
385
+ → resolvePreset(): CLI flag → PR labels → ticket labels → auto-detect from extensions → 'default'
386
+ → loadPrompt('ANALYZE_PR.md') with preset guidelines + category injection
387
+ → executeClaudeWithRetry() → extractJSON() → normalizeCategory() with fuzzy aliases
388
+ → interactive comment workflow: post all / select / skip
389
+ → createPullRequestReview() with inline comments + review body
390
+ → recordPRAnalysis() → .claude/statistics/pr/stats.jsonl
391
+ ```
392
+
364
393
  **Flow 4: PR creation (with auto-push v2.11.0, engine v2.14.0)**
365
394
 
366
395
  ```
@@ -673,8 +702,11 @@ claude-hooks preset current # View current preset
673
702
 
674
703
  # Analysis and PRs
675
704
  claude-hooks analyze-diff [branch] # Analyze diff for PR
705
+ claude-hooks analyze-pr <pr-url> # Analyze GitHub PR with team guidelines
706
+ claude-hooks analyze-pr <url> --dry-run # Analyze without posting comments
676
707
  claude-hooks create-pr [branch] # Create PR on GitHub
677
708
  claude-hooks setup-github # Configure GitHub token
709
+ claude-hooks setup-linear # Configure Linear token
678
710
 
679
711
  # Version management
680
712
  claude-hooks bump-version patch # Bump version (commits, tags locally)
package/README.md CHANGED
@@ -41,10 +41,11 @@ claude-hooks create-pr develop
41
41
  - Prompts for confirmation (configurable)
42
42
  - Handles diverged branches gracefully
43
43
 
44
- ### GitHub Token Setup
44
+ ### Token Setup
45
45
 
46
46
  ```bash
47
- claude-hooks setup-github # Shows status and configuration options
47
+ claude-hooks setup-github # Configure GitHub token for PR creation
48
+ claude-hooks setup-linear # Configure Linear token for ticket enrichment
48
49
  ```
49
50
 
50
51
  **Option 1 - Settings file (recommended):**
@@ -94,6 +95,24 @@ claude-hooks analyze-diff develop
94
95
  # Generates PR metadata without creating
95
96
  ```
96
97
 
98
+ ### Analyze PR from GitHub URL
99
+
100
+ ```bash
101
+ claude-hooks analyze-pr https://github.com/owner/repo/pull/123
102
+ # Fetches PR, applies preset guidelines, posts review comments
103
+
104
+ claude-hooks analyze-pr https://github.com/owner/repo/pull/123 --dry-run
105
+ # Analyze without posting comments
106
+
107
+ claude-hooks analyze-pr https://github.com/owner/repo/pull/123 --preset backend --model opus
108
+ # Override preset and model
109
+ ```
110
+
111
+ - Auto-detects preset from PR labels, Linear ticket labels, or file extensions
112
+ - Enriches with Linear ticket context when `[AUT-1234]` found in PR title
113
+ - Interactive comment workflow: confirm/skip each finding before posting
114
+ - Classifies into inline (file:line) and general (review-level) categories
115
+
97
116
  ### Bump Version
98
117
 
99
118
  Automatic version management with CHANGELOG generation and Git tagging:
@@ -261,10 +280,12 @@ claude-hooks update # Update to latest version
261
280
  | `hooks.js` | **Hook management** - enable, disable, status, uninstall | `runEnable()`, `runDisable()`, `runStatus()`, `runUninstall()` |
262
281
  | `analyze.js` | **Interactive code analysis** - analyze before committing | `runAnalyze()` |
263
282
  | `analyze-diff.js` | **Diff analysis** - generate PR metadata from git diff | `runAnalyzeDiff()` |
283
+ | `analyze-pr.js` | **PR analysis** - analyze GitHub PR with team guidelines | `runAnalyzePr()` |
264
284
  | `create-pr.js` | **PR creation** - full workflow via Octokit | `runCreatePr()` |
265
285
  | `bump-version.js` | **Version management** - bump with CHANGELOG and Git tag | `runBumpVersion()` |
266
286
  | `generate-changelog.js` | **CHANGELOG generation** - standalone command | `runGenerateChangelog()` |
267
287
  | `setup-github.js` | **Token setup** - interactive GitHub configuration | `runSetupGitHub()` |
288
+ | `setup-linear.js` | **Token setup** - interactive Linear configuration | `runSetupLinear()` |
268
289
  | `presets.js` | **Preset management** - list, set, show current | `runShowPresets()`, `runSetPreset()`, `runCurrentPreset()` |
269
290
  | `update.js` | **Self-update** - check and install latest version | `runUpdate()` |
270
291
  | `migrate-config.js` | **Config migration** - legacy to v2.8.0 format | `runMigrateConfig()` |
@@ -283,7 +304,10 @@ claude-hooks update # Update to latest version
283
304
  | `prompt-builder.js` | **Prompt construction** - load templates, replace variables, inject commit context | `buildAnalysisPrompt()`, `loadPrompt()` |
284
305
  | `git-operations.js` | **Git abstractions** - staged files, diff, branch comparison | `getStagedFiles()`, `getDiff()`, `getRepoRoot()`, `resolveBaseBranch()`, `getDiffBetweenRefs()` |
285
306
  | `pr-metadata-engine.js` | **PR metadata generation** - branch context, diff reduction (v2.14.0) | `getBranchContext()`, `buildDiffPayload()`, `generatePRMetadata()`, `analyzeBranchForPR()` |
286
- | `github-api.js` | **Octokit integration** - PR creation, token validation, content fetching | `createPullRequest()`, `validateToken()`, `saveGitHubToken()`, `fetchFileContent()`, `fetchDirectoryListing()`, `createIssue()` |
307
+ | `github-api.js` | **Octokit integration** - PR creation, PR analysis, token validation, content fetching | `createPullRequest()`, `fetchPullRequest()`, `fetchPullRequestFiles()`, `createPullRequestReview()`, `parseGitHubPRUrl()`, `validateToken()`, `saveGitHubToken()`, `fetchFileContent()`, `fetchDirectoryListing()`, `createIssue()` |
308
+ | `token-store.js` | **Token persistence** - centralized settings.local.json read/write | `loadToken()`, `saveToken()`, `hasToken()`, `loadLocalSettings()` |
309
+ | `linear-connector.js` | **Linear integration** - ticket context fetching with retry | `fetchTicket()`, `extractLinearTicketFromTitle()`, `testConnection()`, `loadLinearToken()` |
310
+ | `pr-statistics.js` | **PR statistics** - write-only JSONL analytics | `recordPRAnalysis()` |
287
311
  | `github-client.js` | **GitHub helpers** - CODEOWNERS parsing, reviewers | `getReviewersForFiles()`, `parseGitHubRepo()` |
288
312
  | `preset-loader.js` | **Preset system** - load tech-stack configurations | `loadPreset()`, `listPresets()` |
289
313
  | `task-id.js` | **Task ID extraction** - Jira, GitHub, Linear patterns | `getOrPromptTaskId()`, `formatWithTaskId()` |
@@ -338,6 +362,21 @@ claude-hooks analyze-diff|create-pr → bin/claude-hooks (router)
338
362
  → create-pr: additionally creates PR via Octokit API
339
363
  ```
340
364
 
365
+ #### PR Analysis (analyze-pr)
366
+
367
+ ```
368
+ claude-hooks analyze-pr <url> → bin/claude-hooks (router)
369
+ → lib/commands/analyze-pr.js
370
+ → parseGitHubPRUrl() → fetchPullRequest() + fetchPullRequestFiles()
371
+ → extractLinearTicketFromTitle() → fetchTicket() (optional enrichment)
372
+ → resolvePreset() (labels → ticket → auto-detect → default)
373
+ → loadPrompt('ANALYZE_PR.md') with preset guidelines + categories
374
+ → executeClaudeWithRetry() → extractJSON() → normalizeCategory()
375
+ → interactive comment workflow (confirm/skip)
376
+ → createPullRequestReview() → inline + general comments
377
+ → recordPRAnalysis() (JSONL statistics)
378
+ ```
379
+
341
380
  ### Config Priority
342
381
 
343
382
  ```
@@ -384,6 +423,7 @@ Preset always wins - tech-stack specific has priority over user preferences.
384
423
  | CLI argument parsing | `bin/claude-hooks` |
385
424
  | Install workflow | `lib/commands/install.js` |
386
425
  | PR creation flow | `lib/commands/create-pr.js` |
426
+ | PR analysis from URL | `lib/commands/analyze-pr.js` |
387
427
  | Analysis logic | `lib/hooks/pre-commit.js` |
388
428
  | Message generation | `lib/hooks/prepare-commit-msg.js` |
389
429
  | Prompt templates | `templates/*.md` or `.claude/prompts/*.md` |
@@ -407,8 +447,10 @@ claude-git-hooks/
407
447
  │ │ ├── install.js # Install command - hooks, templates
408
448
  │ │ ├── hooks.js # Hook management - enable/disable
409
449
  │ │ ├── analyze-diff.js # Diff analysis - PR metadata
450
+ │ │ ├── analyze-pr.js # PR analysis - GitHub PR review
410
451
  │ │ ├── create-pr.js # PR creation - Octokit workflow
411
- │ │ ├── setup-github.js # Token setup - interactive config
452
+ │ │ ├── setup-github.js # Token setup - interactive GitHub config
453
+ │ │ ├── setup-linear.js # Token setup - interactive Linear config
412
454
  │ │ ├── presets.js # Preset commands - list/set
413
455
  │ │ ├── update.js # Self-update - npm latest
414
456
  │ │ ├── migrate-config.js # Migration - legacy to v2.8.0
@@ -421,7 +463,8 @@ claude-git-hooks/
421
463
  │ │ └── prepare-commit-msg.js # Message generation
422
464
  │ └── utils/ # Reusable modules - shared logic
423
465
  │ ├── diff-analysis-orchestrator.js # Intelligent batch orchestration
424
- └── judge.js # Auto-fix judge (v2.20.0)
466
+ ├── judge.js # Auto-fix judge (v2.20.0)
467
+ │ └── token-store.js # Token persistence - settings.local.json
425
468
  ├── templates/
426
469
  │ ├── pre-commit # Bash wrapper - invokes Node.js
427
470
  │ ├── prepare-commit-msg # Bash wrapper - invokes Node.js
package/bin/claude-hooks CHANGED
@@ -93,6 +93,7 @@ async function main() {
93
93
  [
94
94
  'install',
95
95
  'analyze-diff',
96
+ 'analyze-pr',
96
97
  'create-pr',
97
98
  'bump-version',
98
99
  'generate-changelog',
@@ -5,7 +5,7 @@
5
5
  * Three consumers read from this registry:
6
6
  * 1. bin/claude-hooks — routing (replaces switch/case)
7
7
  * 2. installCompletions() — generates shell completion scripts at install time
8
- * 3. showStaticHelp() — can derive help text from metadata
8
+ * 3. showStaticHelp() — generates help text from this registry
9
9
  *
10
10
  * Adding a new command = adding one entry here.
11
11
  * Completions auto-update for every user at next install.
@@ -115,6 +115,21 @@ export const commands = [
115
115
  completion: "git branch --format='%(refname:short)'"
116
116
  }
117
117
  },
118
+ {
119
+ name: 'analyze-pr',
120
+ description: 'Analyze a GitHub PR with team guidelines',
121
+ handler: async () => (await import('./commands/analyze-pr.js')).runAnalyzePr,
122
+ args: { name: 'pr-url' },
123
+ flags: {
124
+ '--preset': {
125
+ description: 'Override preset selection',
126
+ takesValue: true,
127
+ values: PRESET_NAMES
128
+ },
129
+ '--model': { description: 'Claude model override', takesValue: true },
130
+ '--dry-run': { description: 'Analyze without posting comments' }
131
+ }
132
+ },
118
133
  {
119
134
  name: 'create-pr',
120
135
  description: 'Create PR with auto-generated metadata',
@@ -129,6 +144,11 @@ export const commands = [
129
144
  description: 'Configure GitHub token for PR creation',
130
145
  handler: async () => (await import('./commands/setup-github.js')).runSetupGitHub
131
146
  },
147
+ {
148
+ name: 'setup-linear',
149
+ description: 'Configure Linear token for ticket enrichment',
150
+ handler: async () => (await import('./commands/setup-linear.js')).runSetupLinear
151
+ },
132
152
  {
133
153
  name: 'presets',
134
154
  description: 'List all available presets',