claude-git-hooks 2.30.2 → 2.32.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/README.md CHANGED
@@ -36,16 +36,30 @@ claude-hooks create-pr develop
36
36
  ```
37
37
 
38
38
  **Auto-push feature (v2.11.0):**
39
+
39
40
  - Detects unpublished branches or unpushed commits
40
41
  - Shows commit preview before pushing
41
42
  - Prompts for confirmation (configurable)
42
43
  - Handles diverged branches gracefully
43
44
 
44
45
  **Merge strategy awareness (v2.25.0):**
46
+
45
47
  - Auto-detects required strategy from branch naming: `feature/*`/`release-fix/*` → squash, `release-candidate/*`/`hotfix/*`/`→ main` → merge commit
46
48
  - Displays strategy in PR preview; adds `merge-strategy:squash` or `merge-strategy:merge-commit` label
47
49
  - Prepends body reminder for merge-commit PRs; unknown patterns prompt user to select manually
48
50
 
51
+ **Automatic label resolution (v2.31.0):**
52
+
53
+ - Resolves labels from 5 rule types: preset, size, quality, strategy, and defaults
54
+ - Remote config priority (`mscope-S-L/git-hooks-config/labels.json`) with local fallback
55
+ - Size labels: `size:S` (<10 files), `size:M` (10-50), `size:L` (50-100), `size:XL` (>100) — thresholds configurable remotely
56
+ - Quality labels: `breaking-change`, `security`, `performance` from analysis result
57
+ - Each rule type independently enabled/disabled via remote config
58
+
59
+ ### Team Configuration
60
+
61
+ Label rules, PR categories, and role-based permissions are managed centrally in [`mscope-S-L/git-hooks-config`](https://github.com/mscope-S-L/git-hooks-config). Changes there take effect immediately across all governed repositories — no tool update or deploy required.
62
+
49
63
  ### Token Setup
50
64
 
51
65
  ```bash
@@ -54,12 +68,14 @@ claude-hooks setup-linear # Configure Linear token for ticket enrichment
54
68
  ```
55
69
 
56
70
  **Option 1 - Settings file (recommended):**
71
+
57
72
  ```json
58
73
  // .claude/settings.local.json (gitignored)
59
74
  { "githubToken": "ghp_..." }
60
75
  ```
61
76
 
62
77
  **Option 2 - Environment variable:**
78
+
63
79
  ```bash
64
80
  export GITHUB_TOKEN="ghp_..."
65
81
  ```
@@ -82,12 +98,13 @@ claude-hooks analyze --all
82
98
  ```
83
99
 
84
100
  **What it does:**
101
+
85
102
  - Analyzes selected file scope (staged, unstaged, or all)
86
103
  - Shows all issues (INFO, MINOR, MAJOR, CRITICAL, BLOCKER)
87
104
  - Interactive prompt with options:
88
- - **Continue**: Creates commit automatically with auto-generated message
89
- - **Abort**: Generate resolution prompt and fix issues
90
- - **View**: Show detailed issue list
105
+ - **Continue**: Creates commit automatically with auto-generated message
106
+ - **Abort**: Generate resolution prompt and fix issues
107
+ - **View**: Show detailed issue list
91
108
  - Executes `git commit -m "auto" --no-verify` on confirmation
92
109
  - Works outside git hooks (no stdin limitations)
93
110
 
@@ -143,6 +160,7 @@ claude-hooks bump-version patch --no-commit
143
160
  ```
144
161
 
145
162
  **What it does:**
163
+
146
164
  - Detects project type (Node.js, Maven, or monorepo with both)
147
165
  - Updates `package.json` and/or `pom.xml`
148
166
  - Generates CHANGELOG entry with Claude (analyzes commits)
@@ -151,6 +169,7 @@ claude-hooks bump-version patch --no-commit
151
169
  - Tags stay local by default (use `--push` to push immediately, or let `create-pr` handle it)
152
170
 
153
171
  **Version workflow:**
172
+
154
173
  ```
155
174
  2.7.0 → 2.8.0-SNAPSHOT # Start development
156
175
  2.8.0-SNAPSHOT → 2.8.0-RC # Release candidate
@@ -158,6 +177,7 @@ claude-hooks bump-version patch --no-commit
158
177
  ```
159
178
 
160
179
  **Integration with create-pr:**
180
+
161
181
  - Validates version alignment (package.json, pom.xml, CHANGELOG, tags)
162
182
  - Detects and prompts to push unpushed tags
163
183
  - Warns if local version ≤ remote version
@@ -178,6 +198,7 @@ claude-hooks generate-changelog --base-branch develop
178
198
  ```
179
199
 
180
200
  **What it does:**
201
+
181
202
  - Analyzes commits since last tag using Claude
182
203
  - Categorizes by Conventional Commits types (feat, fix, refactor, etc.)
183
204
  - Generates Keep a Changelog format entries
@@ -206,14 +227,14 @@ claude-hooks --set-preset backend # Set preset
206
227
  claude-hooks preset current # Show current
207
228
  ```
208
229
 
209
- | Preset | Extensions | Focus |
210
- |--------|------------|-------|
211
- | backend | .java, .xml, .yml, .yaml | Spring Boot, JPA, OWASP |
212
- | frontend | .js, .jsx, .ts, .tsx, .css, .scss, .html | React, XSS, a11y |
213
- | fullstack | all above | API contract consistency |
214
- | database | .sql | SQL injection, indexes |
215
- | ai | .js, .json, .md, .sh | Node.js, Claude API |
216
- | default | multiple | General quality |
230
+ | Preset | Extensions | Focus |
231
+ | --------- | ---------------------------------------- | ------------------------ |
232
+ | backend | .java, .xml, .yml, .yaml | Spring Boot, JPA, OWASP |
233
+ | frontend | .js, .jsx, .ts, .tsx, .css, .scss, .html | React, XSS, a11y |
234
+ | fullstack | all above | API contract consistency |
235
+ | database | .sql | SQL injection, indexes |
236
+ | ai | .js, .json, .md, .sh | Node.js, Claude API |
237
+ | default | multiple | General quality |
217
238
 
218
239
  ### Skip Analysis
219
240
 
@@ -267,60 +288,61 @@ claude-hooks update # Update to latest version
267
288
 
268
289
  ### Directory Map
269
290
 
270
- | Path | Purpose | Key Exports |
271
- |------|---------|-------------|
272
- | `bin/claude-hooks` | **Thin CLI router** - argument parsing, command dispatch | - |
273
- | `lib/commands/` | **Command modules** - one file per CLI command | See table below |
274
- | `lib/config.js` | **Config system** - load/merge configuration | `getConfig()` |
275
- | `lib/hooks/` | **Git hook logic** - Node.js implementations | `pre-commit.js`, `prepare-commit-msg.js` |
276
- | `lib/utils/` | **Reusable utilities** - shared across commands | See table below |
277
- | `templates/` | **Static assets** - bash wrappers, prompts, presets | Copied during install |
291
+ | Path | Purpose | Key Exports |
292
+ | ------------------ | -------------------------------------------------------- | ---------------------------------------- |
293
+ | `bin/claude-hooks` | **Thin CLI router** - argument parsing, command dispatch | - |
294
+ | `lib/commands/` | **Command modules** - one file per CLI command | See table below |
295
+ | `lib/config.js` | **Config system** - load/merge configuration | `getConfig()` |
296
+ | `lib/hooks/` | **Git hook logic** - Node.js implementations | `pre-commit.js`, `prepare-commit-msg.js` |
297
+ | `lib/utils/` | **Reusable utilities** - shared across commands | See table below |
298
+ | `templates/` | **Static assets** - bash wrappers, prompts, presets | Copied during install |
278
299
 
279
300
  ### Command Modules (`lib/commands/`)
280
301
 
281
- | Module | Purpose | Key Exports |
282
- |--------|---------|-------------|
283
- | `helpers.js` | **Shared CLI utilities** - colors, output, platform detection | `colors`, `error()`, `success()`, `info()`, `checkGitRepo()`, `Entertainment` |
284
- | `install.js` | **Installation logic** - dependencies, hooks, templates | `runInstall()`, `extractLegacySettings()` |
285
- | `hooks.js` | **Hook management** - enable, disable, status, uninstall | `runEnable()`, `runDisable()`, `runStatus()`, `runUninstall()` |
286
- | `analyze.js` | **Interactive code analysis** - analyze before committing | `runAnalyze()` |
287
- | `analyze-diff.js` | **Diff analysis** - generate PR metadata from git diff | `runAnalyzeDiff()` |
288
- | `analyze-pr.js` | **PR analysis** - analyze GitHub PR with team guidelines | `runAnalyzePr()` |
289
- | `create-pr.js` | **PR creation** - full workflow via Octokit | `runCreatePr()` |
290
- | `bump-version.js` | **Version management** - bump with CHANGELOG and Git tag | `runBumpVersion()` |
291
- | `generate-changelog.js` | **CHANGELOG generation** - standalone command | `runGenerateChangelog()` |
292
- | `setup-github.js` | **Token setup** - interactive GitHub configuration | `runSetupGitHub()` |
293
- | `setup-linear.js` | **Token setup** - interactive Linear configuration | `runSetupLinear()` |
294
- | `presets.js` | **Preset management** - list, set, show current | `runShowPresets()`, `runSetPreset()`, `runCurrentPreset()` |
295
- | `update.js` | **Self-update** - check and install latest version | `runUpdate()` |
296
- | `migrate-config.js` | **Config migration** - legacy to v2.8.0 format | `runMigrateConfig()` |
297
- | `debug.js` | **Debug toggle** - enable/disable verbose logging | `runSetDebug()` |
298
- | `telemetry-cmd.js` | **Telemetry commands** - show/clear statistics | `runShowTelemetry()`, `runClearTelemetry()` |
299
- | `diff-batch-info.js` | **Batch info** - orchestration config + per-model speed telemetry | `runDiffBatchInfo()` |
300
- | `help.js` | **Help, AI help, report-issue** | `runShowHelp()`, `showStaticHelp()`, `runShowVersion()` |
302
+ | Module | Purpose | Key Exports |
303
+ | ----------------------- | ----------------------------------------------------------------- | ----------------------------------------------------------------------------- |
304
+ | `helpers.js` | **Shared CLI utilities** - colors, output, platform detection | `colors`, `error()`, `success()`, `info()`, `checkGitRepo()`, `Entertainment` |
305
+ | `install.js` | **Installation logic** - dependencies, hooks, templates | `runInstall()`, `extractLegacySettings()` |
306
+ | `hooks.js` | **Hook management** - enable, disable, status, uninstall | `runEnable()`, `runDisable()`, `runStatus()`, `runUninstall()` |
307
+ | `analyze.js` | **Interactive code analysis** - analyze before committing | `runAnalyze()` |
308
+ | `analyze-diff.js` | **Diff analysis** - generate PR metadata from git diff | `runAnalyzeDiff()` |
309
+ | `analyze-pr.js` | **PR analysis** - analyze GitHub PR with team guidelines | `runAnalyzePr()` |
310
+ | `create-pr.js` | **PR creation** - full workflow via Octokit | `runCreatePr()` |
311
+ | `bump-version.js` | **Version management** - bump with CHANGELOG and Git tag | `runBumpVersion()` |
312
+ | `generate-changelog.js` | **CHANGELOG generation** - standalone command | `runGenerateChangelog()` |
313
+ | `setup-github.js` | **Token setup** - interactive GitHub configuration | `runSetupGitHub()` |
314
+ | `setup-linear.js` | **Token setup** - interactive Linear configuration | `runSetupLinear()` |
315
+ | `presets.js` | **Preset management** - list, set, show current | `runShowPresets()`, `runSetPreset()`, `runCurrentPreset()` |
316
+ | `update.js` | **Self-update** - check and install latest version | `runUpdate()` |
317
+ | `migrate-config.js` | **Config migration** - legacy to v2.8.0 format | `runMigrateConfig()` |
318
+ | `debug.js` | **Debug toggle** - enable/disable verbose logging | `runSetDebug()` |
319
+ | `telemetry-cmd.js` | **Telemetry commands** - show/clear statistics | `runShowTelemetry()`, `runClearTelemetry()` |
320
+ | `diff-batch-info.js` | **Batch info** - orchestration config + per-model speed telemetry | `runDiffBatchInfo()` |
321
+ | `help.js` | **Help, AI help, report-issue** | `runShowHelp()`, `showStaticHelp()`, `runShowVersion()` |
301
322
 
302
323
  ### Utility Modules (`lib/utils/`)
303
324
 
304
- | Module | Purpose | Key Exports |
305
- |--------|---------|-------------|
306
- | `analysis-engine.js` | **Shared analysis logic** - file data, orchestration, results (v2.13.0) | `buildFilesData()`, `runAnalysis()`, `consolidateResults()`, `displayResults()` |
307
- | `diff-analysis-orchestrator.js` | **Intelligent orchestration** - semantic batch grouping via Opus (v2.20.0) | `orchestrateBatches()`, `buildFileOverview()`, `detectDependencies()` |
308
- | `claude-client.js` | **Claude CLI wrapper** - spawn, retry, model override | `analyzeCode()`, `executeClaudeWithRetry()`, `extractJSON()` |
309
- | `prompt-builder.js` | **Prompt construction** - load templates, replace variables, inject commit context | `buildAnalysisPrompt()`, `loadPrompt()` |
310
- | `git-operations.js` | **Git abstractions** - staged files, diff, branch comparison | `getStagedFiles()`, `getDiff()`, `getRepoRoot()`, `resolveBaseBranch()`, `getDiffBetweenRefs()` |
311
- | `pr-metadata-engine.js` | **PR metadata generation** - branch context, diff reduction (v2.14.0) | `getBranchContext()`, `buildDiffPayload()`, `generatePRMetadata()`, `analyzeBranchForPR()` |
312
- | `github-api.js` | **Octokit integration** - PR creation, PR analysis, token validation, content fetching | `createPullRequest()`, `fetchPullRequest()`, `fetchPullRequestFiles()`, `createPullRequestReview()`, `parseGitHubPRUrl()`, `validateToken()`, `saveGitHubToken()`, `fetchFileContent()`, `fetchDirectoryListing()`, `createIssue()` |
313
- | `token-store.js` | **Token persistence** - centralized settings.local.json read/write | `loadToken()`, `saveToken()`, `hasToken()`, `loadLocalSettings()` |
314
- | `linear-connector.js` | **Linear integration** - ticket context fetching with retry | `fetchTicket()`, `extractLinearTicketFromTitle()`, `testConnection()`, `loadLinearToken()` |
315
- | `pr-statistics.js` | **PR statistics** - write-only JSONL analytics | `recordPRAnalysis()` |
316
- | `github-client.js` | **GitHub helpers** - CODEOWNERS parsing, reviewers | `getReviewersForFiles()`, `parseGitHubRepo()` |
317
- | `preset-loader.js` | **Preset system** - load tech-stack configurations | `loadPreset()`, `listPresets()` |
318
- | `task-id.js` | **Task ID extraction** - Jira, GitHub, Linear patterns | `getOrPromptTaskId()`, `formatWithTaskId()` |
319
- | `judge.js` | **Auto-fix judge** - LLM verdict + search/replace fixes (v2.20.0) | `judgeAndFix()`, `applyFix()` |
320
- | `resolution-prompt.js` | **Issue resolution** - AI-friendly fix prompts | `generateResolutionPrompt()` |
321
- | `logger.js` | **Logging system** - centralized output with debug mode | `info()`, `warning()`, `error()`, `debug()` |
322
- | `interactive-ui.js` | **CLI UI components** - previews, prompts, spinners | `showPRPreview()`, `promptConfirmation()`, `promptMenu()` |
323
- | `telemetry.js` | **Local telemetry** - track JSON parsing, retries | `recordEvent()`, `displayStatistics()` |
325
+ | Module | Purpose | Key Exports |
326
+ | ------------------------------- | -------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
327
+ | `analysis-engine.js` | **Shared analysis logic** - file data, orchestration, results (v2.13.0) | `buildFilesData()`, `runAnalysis()`, `consolidateResults()`, `displayResults()` |
328
+ | `diff-analysis-orchestrator.js` | **Intelligent orchestration** - semantic batch grouping via Opus (v2.20.0) | `orchestrateBatches()`, `buildFileOverview()`, `detectDependencies()` |
329
+ | `claude-client.js` | **Claude CLI wrapper** - spawn, retry, model override | `analyzeCode()`, `executeClaudeWithRetry()`, `extractJSON()` |
330
+ | `prompt-builder.js` | **Prompt construction** - load templates, replace variables, inject commit context | `buildAnalysisPrompt()`, `loadPrompt()` |
331
+ | `git-operations.js` | **Git abstractions** - staged files, diff, branch comparison | `getStagedFiles()`, `getDiff()`, `getRepoRoot()`, `resolveBaseBranch()`, `getDiffBetweenRefs()` |
332
+ | `pr-metadata-engine.js` | **PR metadata generation** - branch context, diff reduction (v2.14.0) | `getBranchContext()`, `buildDiffPayload()`, `generatePRMetadata()`, `analyzeBranchForPR()` |
333
+ | `github-api.js` | **Octokit integration** - PR creation, PR analysis, token validation, content fetching | `createPullRequest()`, `fetchPullRequest()`, `fetchPullRequestFiles()`, `createPullRequestReview()`, `parseGitHubPRUrl()`, `validateToken()`, `saveGitHubToken()`, `fetchFileContent()`, `fetchDirectoryListing()`, `createIssue()` |
334
+ | `token-store.js` | **Token persistence** - centralized settings.local.json read/write | `loadToken()`, `saveToken()`, `hasToken()`, `loadLocalSettings()` |
335
+ | `linear-connector.js` | **Linear integration** - ticket context fetching with retry | `fetchTicket()`, `extractLinearTicketFromTitle()`, `testConnection()`, `loadLinearToken()` |
336
+ | `pr-statistics.js` | **PR statistics** - write-only JSONL analytics | `recordPRAnalysis()` |
337
+ | `github-client.js` | **GitHub helpers** - repo parsing, config-based reviewers | `getReviewersForFiles()`, `parseGitHubRepo()` |
338
+ | `reviewer-selector.js` | **Team-based reviewer selection** - GitHub Teams API resolution (v2.32.0) | `selectReviewers()` |
339
+ | `preset-loader.js` | **Preset system** - load tech-stack configurations | `loadPreset()`, `listPresets()` |
340
+ | `task-id.js` | **Task ID extraction** - Jira, GitHub, Linear patterns | `getOrPromptTaskId()`, `formatWithTaskId()` |
341
+ | `judge.js` | **Auto-fix judge** - LLM verdict + search/replace fixes (v2.20.0) | `judgeAndFix()`, `applyFix()` |
342
+ | `resolution-prompt.js` | **Issue resolution** - AI-friendly fix prompts | `generateResolutionPrompt()` |
343
+ | `logger.js` | **Logging system** - centralized output with debug mode | `info()`, `warning()`, `error()`, `debug()` |
344
+ | `interactive-ui.js` | **CLI UI components** - previews, prompts, spinners | `showPRPreview()`, `promptConfirmation()`, `promptMenu()` |
345
+ | `telemetry.js` | **Local telemetry** - track JSON parsing, retries | `recordEvent()`, `displayStatistics()` |
324
346
 
325
347
  ### Execution Flow
326
348
 
@@ -396,20 +418,20 @@ Preset always wins - tech-stack specific has priority over user preferences.
396
418
 
397
419
  ```json
398
420
  {
399
- "version": "2.8.0",
400
- "preset": "backend",
401
- "overrides": {
402
- "github": {
403
- "pr": {
404
- "defaultBase": "develop",
405
- "reviewers": ["user"],
406
- "autoPush": true, // Auto-push unpublished branches (v2.11.0)
407
- "pushConfirm": true, // Prompt before push (v2.11.0)
408
- "showCommits": true, // Show commit preview (v2.11.0)
409
- "verifyRemote": true // Verify remote exists (v2.11.0)
410
- }
411
- },
412
- }
421
+ "version": "2.8.0",
422
+ "preset": "backend",
423
+ "overrides": {
424
+ "github": {
425
+ "pr": {
426
+ "defaultBase": "develop",
427
+ "reviewers": ["user"],
428
+ "autoPush": true, // Auto-push unpublished branches (v2.11.0)
429
+ "pushConfirm": true, // Prompt before push (v2.11.0)
430
+ "showCommits": true, // Show commit preview (v2.11.0)
431
+ "verifyRemote": true // Verify remote exists (v2.11.0)
432
+ }
433
+ }
434
+ }
413
435
  }
414
436
  ```
415
437
 
@@ -423,22 +445,22 @@ Preset always wins - tech-stack specific has priority over user preferences.
423
445
 
424
446
  ### Modification Guide
425
447
 
426
- | To change... | Edit... |
427
- |--------------|---------|
428
- | CLI argument parsing | `bin/claude-hooks` |
429
- | Install workflow | `lib/commands/install.js` |
430
- | PR creation flow | `lib/commands/create-pr.js` |
431
- | PR analysis from URL | `lib/commands/analyze-pr.js` |
432
- | Analysis logic | `lib/hooks/pre-commit.js` |
433
- | Message generation | `lib/hooks/prepare-commit-msg.js` |
434
- | Prompt templates | `templates/*.md` or `.claude/prompts/*.md` |
435
- | Preset definitions | `templates/presets/{name}/` |
436
- | Config defaults | `lib/config.js` |
437
- | GitHub integration | `lib/utils/github-api.js` |
438
- | Claude CLI calls | `lib/utils/claude-client.js` |
439
- | Batch orchestration logic | `lib/utils/diff-analysis-orchestrator.js` |
440
- | Orchestration prompt | `templates/DIFF_ANALYSIS_ORCHESTRATION_PROMPT.md` |
441
- | Auto-fix judge logic | `lib/utils/judge.js` |
448
+ | To change... | Edit... |
449
+ | ------------------------- | ------------------------------------------------- |
450
+ | CLI argument parsing | `bin/claude-hooks` |
451
+ | Install workflow | `lib/commands/install.js` |
452
+ | PR creation flow | `lib/commands/create-pr.js` |
453
+ | PR analysis from URL | `lib/commands/analyze-pr.js` |
454
+ | Analysis logic | `lib/hooks/pre-commit.js` |
455
+ | Message generation | `lib/hooks/prepare-commit-msg.js` |
456
+ | Prompt templates | `templates/*.md` or `.claude/prompts/*.md` |
457
+ | Preset definitions | `templates/presets/{name}/` |
458
+ | Config defaults | `lib/config.js` |
459
+ | GitHub integration | `lib/utils/github-api.js` |
460
+ | Claude CLI calls | `lib/utils/claude-client.js` |
461
+ | Batch orchestration logic | `lib/utils/diff-analysis-orchestrator.js` |
462
+ | Orchestration prompt | `templates/DIFF_ANALYSIS_ORCHESTRATION_PROMPT.md` |
463
+ | Auto-fix judge logic | `lib/utils/judge.js` |
442
464
 
443
465
  ### File Structure
444
466
 
@@ -483,12 +505,13 @@ claude-git-hooks/
483
505
 
484
506
  Two-tier strategy based on file count:
485
507
 
486
- | Files | Strategy | Details |
487
- |-------|----------|---------|
488
- | 1–2 | Sequential | Single Claude call, full context |
489
- | 3+ | **Intelligent orchestration** | Opus groups files semantically, assigns model per batch, shared commit context |
508
+ | Files | Strategy | Details |
509
+ | ----- | ----------------------------- | ------------------------------------------------------------------------------ |
510
+ | 1–2 | Sequential | Single Claude call, full context |
511
+ | 3+ | **Intelligent orchestration** | Opus groups files semantically, assigns model per batch, shared commit context |
490
512
 
491
513
  **Orchestration flow (3+ files):**
514
+
492
515
  1. Opus reads a lightweight file overview + detected cross-file dependencies
493
516
  2. Groups related files into semantically coherent batches
494
517
  3. Assigns model per batch: `haiku` (config/docs), `sonnet` (business logic), `opus` (security-critical)
@@ -496,6 +519,7 @@ Two-tier strategy based on file count:
496
519
  5. Falls back to one-file-per-batch if orchestration fails
497
520
 
498
521
  **Inspect orchestration settings:**
522
+
499
523
  ```bash
500
524
  claude-hooks batch-info # Shows config + per-model avg speed from telemetry
501
525
  ```
@@ -35,6 +35,7 @@ import {
35
35
  promptEditField
36
36
  } from '../utils/interactive-ui.js';
37
37
  import logger from '../utils/logger.js';
38
+ import { resolveLabels } from '../utils/label-resolver.js';
38
39
  import { colors, error, checkGitRepo } from './helpers.js';
39
40
 
40
41
  /** Prefix for release-candidate branches */
@@ -43,9 +44,6 @@ const RC_PREFIX = 'release-candidate';
43
44
  /** Target branch for the release PR */
44
45
  const TARGET_BRANCH = 'main';
45
46
 
46
- /** Label added to the created PR to signal merge-commit strategy */
47
- const MERGE_COMMIT_LABEL = 'merge-strategy:merge-commit';
48
-
49
47
  /** Body reminder prepended to PR description */
50
48
  const MERGE_COMMIT_REMINDER =
51
49
  '> ⚠️ This PR must be merged with **merge commit** (not squash)\n\n';
@@ -201,7 +199,7 @@ function _showDryRunPreview({ rcBranch, version, description, featureList, optio
201
199
  console.log(` 3. git push --force-with-lease origin ${rcBranch}`);
202
200
  if (!options.noPr) {
203
201
  console.log(` 4. Create PR: ${rcBranch} → ${TARGET_BRANCH}`);
204
- console.log(` Label: ${MERGE_COMMIT_LABEL}`);
202
+ console.log(' Label: merge-strategy:merge-commit');
205
203
  } else {
206
204
  console.log(' 4. PR creation skipped (--no-pr)');
207
205
  }
@@ -411,13 +409,15 @@ export async function runCloseRelease(args) {
411
409
  const { createPullRequest, validateToken } = await import('../utils/github-api.js');
412
410
  const { parseGitHubRepo } = await import('../utils/github-client.js');
413
411
 
412
+ const prLabels = await resolveLabels({ mergeStrategy: 'merge-commit' });
413
+
414
414
  const tokenValidation = await validateToken();
415
415
  if (!tokenValidation.valid) {
416
416
  showWarning(`GitHub token invalid — PR not created: ${tokenValidation.error}`);
417
417
  console.log('');
418
418
  console.log('Create the PR manually:');
419
419
  console.log(
420
- ` gh pr create --base ${TARGET_BRANCH} --head ${rcBranch} --label "${MERGE_COMMIT_LABEL}"`
420
+ ` gh pr create --base ${TARGET_BRANCH} --head ${rcBranch} --label "merge-strategy:merge-commit"`
421
421
  );
422
422
  } else {
423
423
  const repoInfo = parseGitHubRepo();
@@ -435,7 +435,7 @@ export async function runCloseRelease(args) {
435
435
  body: prBody,
436
436
  head: rcBranch,
437
437
  base: TARGET_BRANCH,
438
- labels: [MERGE_COMMIT_LABEL]
438
+ labels: prLabels
439
439
  });
440
440
  prUrl = pr.html_url;
441
441
  showSuccess(`✓ PR created: ${prUrl}`);
@@ -444,7 +444,7 @@ export async function runCloseRelease(args) {
444
444
  console.log('');
445
445
  console.log('Create the PR manually:');
446
446
  console.log(
447
- ` gh pr create --base ${TARGET_BRANCH} --head ${rcBranch} --label "${MERGE_COMMIT_LABEL}"`
447
+ ` gh pr create --base ${TARGET_BRANCH} --head ${rcBranch} --label "merge-strategy:merge-commit"`
448
448
  );
449
449
  }
450
450
  }
@@ -9,7 +9,7 @@ import path from 'path';
9
9
  import { analyzeBranchForPR } from '../utils/pr-metadata-engine.js';
10
10
  import { getConfig } from '../config.js';
11
11
  import { getOrPromptTaskId, formatWithTaskId } from '../utils/task-id.js';
12
- import { getReviewersForFiles } from '../utils/github-client.js';
12
+ import { selectReviewers } from '../utils/reviewer-selector.js';
13
13
  import {
14
14
  showPRPreview,
15
15
  promptMenu,
@@ -21,6 +21,7 @@ import {
21
21
  } from '../utils/interactive-ui.js';
22
22
  import { getBranchPushStatus, pushBranch } from '../utils/git-operations.js';
23
23
  import logger from '../utils/logger.js';
24
+ import { resolveLabels } from '../utils/label-resolver.js';
24
25
  import { error, checkGitRepo } from './helpers.js';
25
26
 
26
27
  /**
@@ -557,19 +558,8 @@ export async function runCreatePr(args) {
557
558
  bodyLength: prBody.length
558
559
  });
559
560
 
560
- // Step 9: Get labels from preset
561
- logger.debug('create-pr', 'Step 9: Getting labels from preset');
562
- let labels = [];
563
- if (config.preset && config.github?.pr?.labelRules) {
564
- labels = config.github.pr.labelRules[config.preset] || [];
565
- }
566
- if (analysisResult.breakingChanges) {
567
- labels.push('breaking-change');
568
- }
569
- logger.debug('create-pr', 'Labels determined', { labels, preset: config.preset });
570
-
571
- // Step 9.5: Detect merge strategy
572
- logger.debug('create-pr', 'Step 9.5: Detecting merge strategy', {
561
+ // Step 9: Detect merge strategy (needed before label resolution)
562
+ logger.debug('create-pr', 'Step 9: Detecting merge strategy', {
573
563
  sourceBranch: currentBranch,
574
564
  targetBranch: baseBranch
575
565
  });
@@ -591,9 +581,25 @@ export async function runCreatePr(args) {
591
581
  else if (strategyChoice === 'm') mergeStrategy = 'merge-commit';
592
582
  }
593
583
 
594
- if (mergeStrategy !== 'unknown') {
595
- labels.push(`merge-strategy:${mergeStrategy}`);
596
- logger.debug('create-pr', 'Merge strategy label added', { mergeStrategy });
584
+ // Step 9.5: Resolve labels
585
+ logger.debug('create-pr', 'Step 9.5: Resolving labels');
586
+ let labels = [];
587
+ try {
588
+ labels = await resolveLabels({
589
+ preset: config.preset,
590
+ fileCount: filesArray.length,
591
+ mergeStrategy,
592
+ analysisResult: {
593
+ breakingChanges: analysisResult.breakingChanges || false,
594
+ hasSecurityIssues: analysisResult.hasSecurityIssues || false,
595
+ hasPerformanceIssues: analysisResult.hasPerformanceIssues || false
596
+ },
597
+ localLabelRules: config.github?.pr?.labelRules
598
+ });
599
+ logger.debug('create-pr', 'Labels resolved', { labels, preset: config.preset });
600
+ } catch (labelError) {
601
+ logger.warning('create-pr', 'Label resolution failed, continuing without labels', { error: labelError.message });
602
+ showWarning('Failed to resolve labels - continuing with PR creation');
597
603
  }
598
604
 
599
605
  let finalBody = prBody;
@@ -601,12 +607,19 @@ export async function runCreatePr(args) {
601
607
  finalBody = `> ⚠️ This PR must be merged with **merge commit** (not squash)\n\n${prBody}`;
602
608
  }
603
609
 
604
- // Step 10: Get reviewers from CODEOWNERS and config
605
- logger.debug('create-pr', 'Step 10: Getting reviewers from CODEOWNERS and config');
606
- const reviewers = await getReviewersForFiles(filesArray, config.github?.pr);
610
+ // Step 10: Get reviewers from team + config fallback
611
+ logger.debug('create-pr', 'Step 10: Selecting reviewers via team resolution');
612
+ const reviewers = await selectReviewers({
613
+ org: repoInfo.owner,
614
+ repoFullName: repoInfo.fullName,
615
+ teamSlug: config.github?.pr?.teamSlug || 'automation',
616
+ prAuthor: tokenValidation.user,
617
+ configReviewers: config.github?.pr?.reviewers || [],
618
+ excludeReviewers: config.github?.pr?.excludeReviewers || []
619
+ });
607
620
  logger.debug('create-pr', 'Reviewers determined', {
608
621
  reviewers,
609
- sources: 'CODEOWNERS + config'
622
+ sources: 'team + config fallback'
610
623
  });
611
624
 
612
625
  // Step 11: Show PR preview
@@ -3,7 +3,7 @@
3
3
  * Purpose: Role-based authorization for protected workflow commands
4
4
  *
5
5
  * Design:
6
- * - Permissions are sourced from a centralized GitHub repo (mscope-S-L/claude-hooks-permissions)
6
+ * - Permissions are sourced from a centralized GitHub repo (mscope-S-L/git-hooks-config)
7
7
  * - Role hierarchy is defined in permissions.json (ordered lowest → highest)
8
8
  * - Commands not in commandPermissions are open to all
9
9
  * - All failure scenarios are fail-closed (block on any error)
@@ -31,14 +31,13 @@ import {
31
31
  } from './github-api.js';
32
32
 
33
33
  /**
34
- * Constants for the centralized permissions repository
34
+ * Constants for the centralized config repository
35
35
  *
36
- * PERMISSIONS_REPO_OWNER/NAME: where the permissions file lives (currently personal profile,
37
- * update to 'mscope-S-L' when repos are migrated to the org).
38
- * PERMISSIONS_ORG: the GitHub org used for membership checks — stable regardless of repo location.
36
+ * PERMISSIONS_REPO_OWNER/NAME: where the permissions file lives (mscope-S-L org).
37
+ * PERMISSIONS_ORG: the GitHub org used for membership checks.
39
38
  */
40
- const PERMISSIONS_REPO_OWNER = 'pablo-rovito-mscope';
41
- const PERMISSIONS_REPO_NAME = 'claude-hooks-permissions';
39
+ const PERMISSIONS_REPO_OWNER = 'mscope-S-L';
40
+ const PERMISSIONS_REPO_NAME = 'git-hooks-config';
42
41
  const PERMISSIONS_FILE_PATH = 'permissions.json';
43
42
  const PERMISSIONS_ORG = 'mscope-S-L';
44
43