@vibe-validate/cli 0.18.3 → 0.18.4-rc.2

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.
Files changed (68) hide show
  1. package/dist/bin.js +5 -3
  2. package/dist/bin.js.map +1 -1
  3. package/dist/commands/doctor.d.ts.map +1 -1
  4. package/dist/commands/doctor.js +110 -89
  5. package/dist/commands/doctor.js.map +1 -1
  6. package/dist/commands/generate-workflow.d.ts.map +1 -1
  7. package/dist/commands/generate-workflow.js +42 -32
  8. package/dist/commands/generate-workflow.js.map +1 -1
  9. package/dist/commands/history.d.ts.map +1 -1
  10. package/dist/commands/history.js +15 -7
  11. package/dist/commands/history.js.map +1 -1
  12. package/dist/commands/init.d.ts.map +1 -1
  13. package/dist/commands/init.js +20 -11
  14. package/dist/commands/init.js.map +1 -1
  15. package/dist/commands/pre-commit.d.ts.map +1 -1
  16. package/dist/commands/pre-commit.js +46 -29
  17. package/dist/commands/pre-commit.js.map +1 -1
  18. package/dist/commands/run.js +3 -3
  19. package/dist/commands/run.js.map +1 -1
  20. package/dist/commands/snapshot.d.ts.map +1 -1
  21. package/dist/commands/snapshot.js +26 -17
  22. package/dist/commands/snapshot.js.map +1 -1
  23. package/dist/commands/state.d.ts.map +1 -1
  24. package/dist/commands/state.js +3 -1
  25. package/dist/commands/state.js.map +1 -1
  26. package/dist/commands/validate.d.ts.map +1 -1
  27. package/dist/commands/validate.js +17 -134
  28. package/dist/commands/validate.js.map +1 -1
  29. package/dist/services/ci-providers/github-actions.d.ts.map +1 -1
  30. package/dist/services/ci-providers/github-actions.js +2 -0
  31. package/dist/services/ci-providers/github-actions.js.map +1 -1
  32. package/dist/services/history-summary-builder.d.ts.map +1 -1
  33. package/dist/services/history-summary-builder.js +9 -19
  34. package/dist/services/history-summary-builder.js.map +1 -1
  35. package/dist/services/watch-pr-orchestrator.d.ts +8 -0
  36. package/dist/services/watch-pr-orchestrator.d.ts.map +1 -1
  37. package/dist/services/watch-pr-orchestrator.js +29 -18
  38. package/dist/services/watch-pr-orchestrator.js.map +1 -1
  39. package/dist/utils/check-validation.d.ts.map +1 -1
  40. package/dist/utils/check-validation.js +32 -14
  41. package/dist/utils/check-validation.js.map +1 -1
  42. package/dist/utils/command-name.d.ts.map +1 -1
  43. package/dist/utils/command-name.js +6 -4
  44. package/dist/utils/command-name.js.map +1 -1
  45. package/dist/utils/config-loader.d.ts.map +1 -1
  46. package/dist/utils/config-loader.js +5 -3
  47. package/dist/utils/config-loader.js.map +1 -1
  48. package/dist/utils/pid-lock.d.ts +27 -28
  49. package/dist/utils/pid-lock.d.ts.map +1 -1
  50. package/dist/utils/pid-lock.js +178 -92
  51. package/dist/utils/pid-lock.js.map +1 -1
  52. package/dist/utils/setup-checks/hooks-check.d.ts.map +1 -1
  53. package/dist/utils/setup-checks/hooks-check.js +14 -11
  54. package/dist/utils/setup-checks/hooks-check.js.map +1 -1
  55. package/dist/utils/setup-checks/workflow-check.d.ts.map +1 -1
  56. package/dist/utils/setup-checks/workflow-check.js +4 -3
  57. package/dist/utils/setup-checks/workflow-check.js.map +1 -1
  58. package/dist/utils/temp-files.d.ts +12 -12
  59. package/dist/utils/temp-files.d.ts.map +1 -1
  60. package/dist/utils/temp-files.js +67 -36
  61. package/dist/utils/temp-files.js.map +1 -1
  62. package/dist/utils/tree-hash-output.js +3 -3
  63. package/dist/utils/tree-hash-output.js.map +1 -1
  64. package/dist/utils/validation-lock-wrapper.d.ts +62 -0
  65. package/dist/utils/validation-lock-wrapper.d.ts.map +1 -0
  66. package/dist/utils/validation-lock-wrapper.js +186 -0
  67. package/dist/utils/validation-lock-wrapper.js.map +1 -0
  68. package/package.json +9 -7
@@ -28,6 +28,27 @@ import { formatTemplateList } from '../utils/template-discovery.js';
28
28
  import { checkSync, ciConfigToWorkflowOptions } from './generate-workflow.js';
29
29
  /** @deprecated State file deprecated in v0.12.0 - validation now uses git notes */
30
30
  const DEPRECATED_STATE_FILE = '.vibe-validate-state.yaml';
31
+ // Check name constants (extracted to avoid duplication warnings)
32
+ const CHECK_CLI_BUILD_STATUS = 'CLI build status';
33
+ const CHECK_NODE_VERSION = 'Node.js version';
34
+ const CHECK_PACKAGE_MANAGER = 'Package manager';
35
+ const CHECK_GIT_REPOSITORY = 'Git repository';
36
+ const CHECK_GIT_MAIN_BRANCH = 'Git main branch';
37
+ const CHECK_GIT_REMOTE_ORIGIN = 'Git remote origin';
38
+ const CHECK_GIT_REMOTE_MAIN_BRANCH = 'Git remote main branch';
39
+ const CHECK_CONFIG_VALID = 'Configuration valid';
40
+ const CHECK_GITIGNORE_STATE_FILE = 'Gitignore state file';
41
+ const CHECK_VALIDATION_HISTORY = 'Validation history';
42
+ const CHECK_VALIDATION_HISTORY_MIGRATION = 'Validation history migration';
43
+ const CHECK_PRE_COMMIT_HOOK = 'Pre-commit hook';
44
+ const CHECK_GITHUB_ACTIONS_WORKFLOW = 'GitHub Actions workflow';
45
+ const CHECK_PRE_COMMIT_SECRET_SCANNING = 'Pre-commit secret scanning';
46
+ const CHECK_VIBE_VALIDATE_VERSION = 'vibe-validate version';
47
+ // Common message constants
48
+ const MSG_SKIPPED_NOT_IN_GIT = 'Skipped (not in git repository)';
49
+ const MSG_SKIPPED_NO_CONFIG = 'Skipped (no config)';
50
+ const SUGGESTION_INSTALL_NODE_JS = 'Install Node.js: https://nodejs.org/';
51
+ const GIT_REF_DEPRECATED_RUNS = 'refs/notes/vibe-validate/runs';
31
52
  /**
32
53
  * Check if CLI build is in sync with source code (development mode only)
33
54
  *
@@ -42,16 +63,16 @@ function checkCliBuildSync() {
42
63
  const gitRoot = findGitRoot();
43
64
  if (!gitRoot) {
44
65
  return {
45
- name: 'CLI build status',
66
+ name: CHECK_CLI_BUILD_STATUS,
46
67
  passed: true,
47
- message: 'Skipped (not in git repository)',
68
+ message: MSG_SKIPPED_NOT_IN_GIT,
48
69
  };
49
70
  }
50
71
  const sourcePackageJsonPath = join(gitRoot, 'packages/cli/package.json');
51
72
  // Not in vibe-validate source tree
52
73
  if (!existsSync(sourcePackageJsonPath)) {
53
74
  return {
54
- name: 'CLI build status',
75
+ name: CHECK_CLI_BUILD_STATUS,
55
76
  passed: true,
56
77
  message: 'Skipped (not in vibe-validate source tree)',
57
78
  };
@@ -66,14 +87,14 @@ function checkCliBuildSync() {
66
87
  // Compare versions - this is the confusing scenario that needs detection
67
88
  if (runningVersion !== sourceVersion) {
68
89
  return {
69
- name: 'CLI build status',
90
+ name: CHECK_CLI_BUILD_STATUS,
70
91
  passed: false,
71
92
  message: `Build is stale: running v${runningVersion}, source v${sourceVersion}`,
72
93
  suggestion: 'Rebuild packages: pnpm -r build',
73
94
  };
74
95
  }
75
96
  return {
76
- name: 'CLI build status',
97
+ name: CHECK_CLI_BUILD_STATUS,
77
98
  passed: true,
78
99
  message: `Build is up to date (v${runningVersion})`,
79
100
  };
@@ -82,7 +103,7 @@ function checkCliBuildSync() {
82
103
  catch (_error) {
83
104
  // Any errors are non-critical - this is a development-only check
84
105
  return {
85
- name: 'CLI build status',
106
+ name: CHECK_CLI_BUILD_STATUS,
86
107
  passed: true,
87
108
  message: 'Skipped (could not determine build status)',
88
109
  };
@@ -97,27 +118,27 @@ function checkNodeVersion() {
97
118
  // Validate that we got a valid version number
98
119
  if (!version) {
99
120
  return {
100
- name: 'Node.js version',
121
+ name: CHECK_NODE_VERSION,
101
122
  passed: false,
102
123
  message: 'Failed to detect Node.js version',
103
- suggestion: 'Install Node.js: https://nodejs.org/',
124
+ suggestion: SUGGESTION_INSTALL_NODE_JS,
104
125
  };
105
126
  }
106
127
  const majorVersion = Number.parseInt(version.replace('v', '').split('.')[0]);
107
128
  if (Number.isNaN(majorVersion) || majorVersion === 0) {
108
129
  return {
109
- name: 'Node.js version',
130
+ name: CHECK_NODE_VERSION,
110
131
  passed: false,
111
132
  message: `Failed to parse Node.js version from output: "${version}"`,
112
- suggestion: 'Install Node.js: https://nodejs.org/',
133
+ suggestion: SUGGESTION_INSTALL_NODE_JS,
113
134
  };
114
135
  }
115
136
  return majorVersion >= 20 ? {
116
- name: 'Node.js version',
137
+ name: CHECK_NODE_VERSION,
117
138
  passed: true,
118
139
  message: `${version} (meets requirement: >=20.0.0)`,
119
140
  } : {
120
- name: 'Node.js version',
141
+ name: CHECK_NODE_VERSION,
121
142
  passed: false,
122
143
  message: `${version} is too old. Node.js 20+ required.`,
123
144
  suggestion: 'Upgrade Node.js: https://nodejs.org/ or use nvm',
@@ -126,7 +147,7 @@ function checkNodeVersion() {
126
147
  catch (error) {
127
148
  const errorMessage = error instanceof Error ? error.message : String(error);
128
149
  return {
129
- name: 'Node.js version',
150
+ name: CHECK_NODE_VERSION,
130
151
  passed: false,
131
152
  message: `Failed to detect Node.js version: ${errorMessage}`,
132
153
  suggestion: 'Install Node.js: https://nodejs.org/',
@@ -164,14 +185,14 @@ function checkGitRepository() {
164
185
  const isGitRepo = isGitRepository();
165
186
  if (isGitRepo) {
166
187
  return {
167
- name: 'Git repository',
188
+ name: CHECK_GIT_REPOSITORY,
168
189
  passed: true,
169
190
  message: 'Current directory is a git repository',
170
191
  };
171
192
  }
172
193
  else {
173
194
  return {
174
- name: 'Git repository',
195
+ name: CHECK_GIT_REPOSITORY,
175
196
  passed: false,
176
197
  message: 'Current directory is not a git repository',
177
198
  suggestion: 'Run: git init',
@@ -181,7 +202,7 @@ function checkGitRepository() {
181
202
  catch (error) {
182
203
  const errorMessage = error instanceof Error ? error.message : String(error);
183
204
  return {
184
- name: 'Git repository',
205
+ name: CHECK_GIT_REPOSITORY,
185
206
  passed: false,
186
207
  message: `Error checking git repository: ${errorMessage}`,
187
208
  suggestion: 'Run: git init',
@@ -231,7 +252,7 @@ async function checkConfigValid(config, configWithErrors) {
231
252
  errors: configWithErrors.errors
232
253
  });
233
254
  return {
234
- name: 'Configuration valid',
255
+ name: CHECK_CONFIG_VALID,
235
256
  passed: false,
236
257
  message,
237
258
  suggestion,
@@ -243,7 +264,7 @@ async function checkConfigValid(config, configWithErrors) {
243
264
  // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- Need to filter empty strings, not just null/undefined
244
265
  const fileName = configPath.split('/').pop() || 'vibe-validate.config.yaml';
245
266
  return {
246
- name: 'Configuration valid',
267
+ name: CHECK_CONFIG_VALID,
247
268
  passed: false,
248
269
  message: `Found ${fileName} but it contains validation errors`,
249
270
  suggestion: [
@@ -258,7 +279,7 @@ async function checkConfigValid(config, configWithErrors) {
258
279
  // No config file found
259
280
  const templateList = formatTemplateList();
260
281
  return {
261
- name: 'Configuration valid',
282
+ name: CHECK_CONFIG_VALID,
262
283
  passed: false,
263
284
  message: 'No configuration file found',
264
285
  suggestion: [
@@ -279,14 +300,14 @@ async function checkConfigValid(config, configWithErrors) {
279
300
  }
280
301
  }
281
302
  return {
282
- name: 'Configuration valid',
303
+ name: CHECK_CONFIG_VALID,
283
304
  passed: true,
284
305
  message: `Loaded successfully (${config.validation.phases.length} phases)`,
285
306
  };
286
307
  }
287
308
  catch (error) {
288
309
  return {
289
- name: 'Configuration valid',
310
+ name: CHECK_CONFIG_VALID,
290
311
  passed: false,
291
312
  message: `Invalid configuration: ${error instanceof Error ? error.message : String(error)}`,
292
313
  suggestion: 'Check syntax in vibe-validate.config.yaml',
@@ -301,9 +322,9 @@ async function checkPackageManager(config) {
301
322
  if (!config) {
302
323
  // Config check will catch this
303
324
  return {
304
- name: 'Package manager',
325
+ name: CHECK_PACKAGE_MANAGER,
305
326
  passed: true,
306
- message: 'Skipped (no config)',
327
+ message: MSG_SKIPPED_NO_CONFIG,
307
328
  };
308
329
  }
309
330
  // Detect package manager from config commands
@@ -312,7 +333,7 @@ async function checkPackageManager(config) {
312
333
  const version = getToolVersion(pm);
313
334
  if (version) {
314
335
  return {
315
- name: 'Package manager',
336
+ name: CHECK_PACKAGE_MANAGER,
316
337
  passed: true,
317
338
  message: `${pm} ${version} is available`,
318
339
  };
@@ -321,7 +342,7 @@ async function checkPackageManager(config) {
321
342
  const currentPm = detectPackageManager(process.cwd());
322
343
  const installCmd = getGlobalInstallCommand(currentPm, pm);
323
344
  return {
324
- name: 'Package manager',
345
+ name: CHECK_PACKAGE_MANAGER,
325
346
  passed: false,
326
347
  message: `${pm} not found (required by config commands)`,
327
348
  suggestion: pm === 'npm'
@@ -332,7 +353,7 @@ async function checkPackageManager(config) {
332
353
  catch (error) {
333
354
  const errorMessage = error instanceof Error ? error.message : String(error);
334
355
  return {
335
- name: 'Package manager',
356
+ name: CHECK_PACKAGE_MANAGER,
336
357
  passed: true,
337
358
  message: `Skipped (config check failed): ${errorMessage}`,
338
359
  };
@@ -349,15 +370,15 @@ async function checkWorkflowSync(config) {
349
370
  const gitRoot = findGitRoot();
350
371
  if (!gitRoot) {
351
372
  return {
352
- name: 'GitHub Actions workflow',
373
+ name: CHECK_GITHUB_ACTIONS_WORKFLOW,
353
374
  passed: true,
354
- message: 'Skipped (not in git repository)',
375
+ message: MSG_SKIPPED_NOT_IN_GIT,
355
376
  };
356
377
  }
357
378
  const workflowPath = join(gitRoot, '.github/workflows/validate.yml');
358
379
  if (!existsSync(workflowPath)) {
359
380
  return {
360
- name: 'GitHub Actions workflow',
381
+ name: CHECK_GITHUB_ACTIONS_WORKFLOW,
361
382
  passed: true,
362
383
  message: 'No workflow file (optional)',
363
384
  };
@@ -365,15 +386,15 @@ async function checkWorkflowSync(config) {
365
386
  try {
366
387
  if (!config) {
367
388
  return {
368
- name: 'GitHub Actions workflow',
389
+ name: CHECK_GITHUB_ACTIONS_WORKFLOW,
369
390
  passed: true,
370
- message: 'Skipped (no config)',
391
+ message: MSG_SKIPPED_NO_CONFIG,
371
392
  };
372
393
  }
373
394
  // Check if workflow check is disabled in config
374
395
  if (config.ci?.disableWorkflowCheck === true) {
375
396
  return {
376
- name: 'GitHub Actions workflow',
397
+ name: CHECK_GITHUB_ACTIONS_WORKFLOW,
377
398
  passed: true,
378
399
  message: 'Workflow sync check disabled (ci.disableWorkflowCheck: true)',
379
400
  };
@@ -385,11 +406,11 @@ async function checkWorkflowSync(config) {
385
406
  };
386
407
  const { inSync, diff } = checkSync(config, generateOptions, workflowPath);
387
408
  return inSync ? {
388
- name: 'GitHub Actions workflow',
409
+ name: CHECK_GITHUB_ACTIONS_WORKFLOW,
389
410
  passed: true,
390
411
  message: 'Workflow is in sync with config',
391
412
  } : {
392
- name: 'GitHub Actions workflow',
413
+ name: CHECK_GITHUB_ACTIONS_WORKFLOW,
393
414
  passed: false,
394
415
  message: `Workflow is out of sync: ${diff ?? 'differs from config'}`,
395
416
  suggestion: [
@@ -404,7 +425,7 @@ async function checkWorkflowSync(config) {
404
425
  }
405
426
  catch (error) {
406
427
  return {
407
- name: 'GitHub Actions workflow',
428
+ name: CHECK_GITHUB_ACTIONS_WORKFLOW,
408
429
  passed: false,
409
430
  message: `Failed to check workflow sync: ${error instanceof Error ? error.message : String(error)}`,
410
431
  suggestion: 'Verify workflow file syntax',
@@ -423,7 +444,7 @@ async function checkPreCommitHook(config) {
423
444
  // If user explicitly disabled, acknowledge their choice
424
445
  if (!preCommitEnabled) {
425
446
  return {
426
- name: 'Pre-commit hook',
447
+ name: CHECK_PRE_COMMIT_HOOK,
427
448
  passed: true,
428
449
  message: 'Pre-commit hook disabled in config (user preference)',
429
450
  };
@@ -432,9 +453,9 @@ async function checkPreCommitHook(config) {
432
453
  const gitRoot = findGitRoot();
433
454
  if (!gitRoot) {
434
455
  return {
435
- name: 'Pre-commit hook',
456
+ name: CHECK_PRE_COMMIT_HOOK,
436
457
  passed: true,
437
- message: 'Skipped (not in git repository)',
458
+ message: MSG_SKIPPED_NOT_IN_GIT,
438
459
  };
439
460
  }
440
461
  const huskyPath = join(gitRoot, '.husky/pre-commit');
@@ -442,7 +463,7 @@ async function checkPreCommitHook(config) {
442
463
  if (!existsSync(huskyPath)) {
443
464
  const cmd = getCommandName();
444
465
  return {
445
- name: 'Pre-commit hook',
466
+ name: CHECK_PRE_COMMIT_HOOK,
446
467
  passed: false,
447
468
  message: 'Pre-commit hook not installed',
448
469
  suggestion: `Manual: npx husky init && echo "${cmd} pre-commit" > .husky/pre-commit\n 💡 Or run: ${cmd} init --setup-hooks\n 💡 Or disable: set hooks.preCommit.enabled=false in config`,
@@ -457,7 +478,7 @@ async function checkPreCommitHook(config) {
457
478
  hookContent.includes('npx vibe-validate validate');
458
479
  if (hasVibeValidate) {
459
480
  return {
460
- name: 'Pre-commit hook',
481
+ name: CHECK_PRE_COMMIT_HOOK,
461
482
  passed: true,
462
483
  message: 'Pre-commit hook installed and runs vibe-validate',
463
484
  };
@@ -467,7 +488,7 @@ async function checkPreCommitHook(config) {
467
488
  const cmd = getCommandName();
468
489
  const hookPreview = hookContent.split('\n').slice(0, 3).join('; ').trim();
469
490
  return {
470
- name: 'Pre-commit hook',
491
+ name: CHECK_PRE_COMMIT_HOOK,
471
492
  passed: false,
472
493
  message: `Custom pre-commit hook detected: "${hookPreview}..."`,
473
494
  suggestion: `Manual: Verify that .husky/pre-commit runs "${expectedCommand}"\n 💡 Or run: ${cmd} init --setup-hooks\n 💡 Or disable: set hooks.preCommit.enabled=false in config`,
@@ -477,7 +498,7 @@ async function checkPreCommitHook(config) {
477
498
  catch (error) {
478
499
  const errorMessage = error instanceof Error ? error.message : String(error);
479
500
  return {
480
- name: 'Pre-commit hook',
501
+ name: CHECK_PRE_COMMIT_HOOK,
481
502
  passed: false,
482
503
  message: `Pre-commit hook exists but unreadable: ${errorMessage}`,
483
504
  suggestion: 'Fix file permissions or set hooks.preCommit.enabled=false',
@@ -536,7 +557,7 @@ async function checkVersion(versionChecker = defaultVersionChecker) {
536
557
  const contextLabel = getContextLabel(context);
537
558
  if (currentVersion === latestVersion) {
538
559
  return {
539
- name: 'vibe-validate version',
560
+ name: CHECK_VIBE_VALIDATE_VERSION,
540
561
  passed: true,
541
562
  message: `Current: ${currentVersion}${contextLabel} — up to date with npm`,
542
563
  };
@@ -545,7 +566,7 @@ async function checkVersion(versionChecker = defaultVersionChecker) {
545
566
  // Only show suggestion if current version is behind npm
546
567
  const cmd = getCommandName();
547
568
  return {
548
- name: 'vibe-validate version',
569
+ name: CHECK_VIBE_VALIDATE_VERSION,
549
570
  passed: true, // Warning only, not a failure
550
571
  message: `Current: ${currentVersion}${contextLabel}, Latest: ${latestVersion} available`,
551
572
  suggestion: `Upgrade: ${getUpgradeCommand(context)}\n 💡 After upgrade: Run '${cmd} doctor' to verify setup`,
@@ -554,7 +575,7 @@ async function checkVersion(versionChecker = defaultVersionChecker) {
554
575
  else {
555
576
  // Current version is ahead of npm (pre-release or unpublished)
556
577
  return {
557
- name: 'vibe-validate version',
578
+ name: CHECK_VIBE_VALIDATE_VERSION,
558
579
  passed: true,
559
580
  message: `Current: ${currentVersion}${contextLabel} (ahead of npm: ${latestVersion})`,
560
581
  };
@@ -564,7 +585,7 @@ async function checkVersion(versionChecker = defaultVersionChecker) {
564
585
  // npm registry unavailable - not a critical error
565
586
  const errorMessage = npmError instanceof Error ? npmError.message : String(npmError);
566
587
  return {
567
- name: 'vibe-validate version',
588
+ name: CHECK_VIBE_VALIDATE_VERSION,
568
589
  passed: true,
569
590
  message: `Current version: ${currentVersion} (unable to check for updates: ${errorMessage})`,
570
591
  };
@@ -573,7 +594,7 @@ async function checkVersion(versionChecker = defaultVersionChecker) {
573
594
  catch (error) {
574
595
  const errorMessage = error instanceof Error ? error.message : String(error);
575
596
  return {
576
- name: 'vibe-validate version',
597
+ name: CHECK_VIBE_VALIDATE_VERSION,
577
598
  passed: true,
578
599
  message: `Unable to determine version: ${errorMessage}`,
579
600
  };
@@ -592,16 +613,16 @@ function checkGitignoreStateFile() {
592
613
  const gitRoot = findGitRoot();
593
614
  if (!gitRoot) {
594
615
  return {
595
- name: 'Gitignore state file',
616
+ name: CHECK_GITIGNORE_STATE_FILE,
596
617
  passed: true,
597
- message: 'Skipped (not in git repository)',
618
+ message: MSG_SKIPPED_NOT_IN_GIT,
598
619
  };
599
620
  }
600
621
  const gitignorePath = join(gitRoot, '.gitignore');
601
622
  // Check if .gitignore exists
602
623
  if (!existsSync(gitignorePath)) {
603
624
  return {
604
- name: 'Gitignore state file',
625
+ name: CHECK_GITIGNORE_STATE_FILE,
605
626
  passed: true,
606
627
  message: '.gitignore file not found (state file deprecated - using git notes)',
607
628
  };
@@ -621,7 +642,7 @@ function checkGitignoreStateFile() {
621
642
  }
622
643
  else {
623
644
  return {
624
- name: 'Gitignore state file',
645
+ name: CHECK_GITIGNORE_STATE_FILE,
625
646
  passed: true,
626
647
  message: 'No deprecated state file entries in .gitignore',
627
648
  };
@@ -630,7 +651,7 @@ function checkGitignoreStateFile() {
630
651
  catch (error) {
631
652
  const errorMessage = error instanceof Error ? error.message : String(error);
632
653
  return {
633
- name: 'Gitignore state file',
654
+ name: CHECK_GITIGNORE_STATE_FILE,
634
655
  passed: false,
635
656
  message: `.gitignore exists but is unreadable: ${errorMessage}`,
636
657
  suggestion: 'Fix file permissions: chmod 644 .gitignore',
@@ -676,13 +697,13 @@ function checkCacheMigration() {
676
697
  try {
677
698
  // Check if the EXACT old validation history ref exists (singular "runs", not "run/")
678
699
  // Using git for-each-ref with exact ref name to avoid matching "run/" subdirectories
679
- const result = executeGitCommand(['for-each-ref', '--format=%(refname)', 'refs/notes/vibe-validate/runs'], { ignoreErrors: true, suppressStderr: true });
680
- if (result.success && result.stdout.trim() === 'refs/notes/vibe-validate/runs') {
700
+ const result = executeGitCommand(['for-each-ref', '--format=%(refname)', GIT_REF_DEPRECATED_RUNS], { ignoreErrors: true, suppressStderr: true });
701
+ if (result.success && result.stdout.trim() === GIT_REF_DEPRECATED_RUNS) {
681
702
  // Old validation history namespace exists - automatically clean it up
682
703
  try {
683
- executeGitCommand(['update-ref', '-d', 'refs/notes/vibe-validate/runs']);
704
+ executeGitCommand(['update-ref', '-d', GIT_REF_DEPRECATED_RUNS]);
684
705
  return {
685
- name: 'Validation history migration',
706
+ name: CHECK_VALIDATION_HISTORY_MIGRATION,
686
707
  passed: true,
687
708
  message: 'Automatically removed old validation history format (pre-v0.15.0)',
688
709
  };
@@ -691,7 +712,7 @@ function checkCacheMigration() {
691
712
  catch (_error) {
692
713
  // Fallback to manual suggestion if auto-cleanup fails
693
714
  return {
694
- name: 'Validation history migration',
715
+ name: CHECK_VALIDATION_HISTORY_MIGRATION,
695
716
  passed: true, // Not a failure, just informational
696
717
  message: 'Old validation history format detected (pre-v0.15.0)',
697
718
  suggestion: `Manual cleanup:\n git update-ref -d refs/notes/vibe-validate/runs\n ℹ️ This removes the deprecated "runs" namespace`,
@@ -699,7 +720,7 @@ function checkCacheMigration() {
699
720
  }
700
721
  }
701
722
  return {
702
- name: 'Validation history migration',
723
+ name: CHECK_VALIDATION_HISTORY_MIGRATION,
703
724
  passed: true,
704
725
  message: 'Using current validation history format',
705
726
  };
@@ -708,7 +729,7 @@ function checkCacheMigration() {
708
729
  catch (_error) {
709
730
  // Git command failed or no git notes - that's fine
710
731
  return {
711
- name: 'Validation history migration',
732
+ name: CHECK_VALIDATION_HISTORY_MIGRATION,
712
733
  passed: true,
713
734
  message: 'No validation history to migrate',
714
735
  };
@@ -722,7 +743,7 @@ async function checkHistoryHealth() {
722
743
  const health = await checkValidationHistoryHealth();
723
744
  if (!health.shouldWarn) {
724
745
  return {
725
- name: 'Validation history',
746
+ name: CHECK_VALIDATION_HISTORY,
726
747
  passed: true,
727
748
  message: `${health.totalNotes} tree hashes tracked, history is healthy`,
728
749
  };
@@ -730,7 +751,7 @@ async function checkHistoryHealth() {
730
751
  // Has warnings - advisory only, not a critical failure
731
752
  const cmd = getCommandName();
732
753
  return {
733
- name: 'Validation history',
754
+ name: CHECK_VALIDATION_HISTORY,
734
755
  passed: true, // Advisory: large history is a warning, not a failure
735
756
  message: `${health.totalNotes} tree hashes tracked (${health.oldNotesCount} older than 90 days)`,
736
757
  suggestion: `Prune old history: ${cmd} history prune --older-than "90 days"`,
@@ -740,7 +761,7 @@ async function checkHistoryHealth() {
740
761
  // Git notes not available or other error - not critical
741
762
  const errorMessage = error instanceof Error ? error.message : String(error);
742
763
  return {
743
- name: 'Validation history',
764
+ name: CHECK_VALIDATION_HISTORY,
744
765
  passed: true,
745
766
  message: `History unavailable (not in git repo or no validation runs yet): ${errorMessage}`,
746
767
  };
@@ -753,9 +774,9 @@ async function checkMainBranch(config) {
753
774
  try {
754
775
  if (!config) {
755
776
  return {
756
- name: 'Git main branch',
777
+ name: CHECK_GIT_MAIN_BRANCH,
757
778
  passed: true,
758
- message: 'Skipped (no config)',
779
+ message: MSG_SKIPPED_NO_CONFIG,
759
780
  };
760
781
  }
761
782
  const mainBranch = getMainBranch(config.git);
@@ -764,7 +785,7 @@ async function checkMainBranch(config) {
764
785
  const localResult = verifyRef(mainBranch);
765
786
  if (localResult) {
766
787
  return {
767
- name: 'Git main branch',
788
+ name: CHECK_GIT_MAIN_BRANCH,
768
789
  passed: true,
769
790
  message: `Branch '${mainBranch}' exists locally`,
770
791
  };
@@ -773,13 +794,13 @@ async function checkMainBranch(config) {
773
794
  const remoteResult = verifyRef(`${remoteOrigin}/${mainBranch}`);
774
795
  if (remoteResult) {
775
796
  return {
776
- name: 'Git main branch',
797
+ name: CHECK_GIT_MAIN_BRANCH,
777
798
  passed: true,
778
799
  message: `Branch '${mainBranch}' exists on remote '${remoteOrigin}' (fetch-depth: 0 required in CI)`,
779
800
  };
780
801
  }
781
802
  return {
782
- name: 'Git main branch',
803
+ name: CHECK_GIT_MAIN_BRANCH,
783
804
  passed: false,
784
805
  message: `Configured main branch '${mainBranch}' does not exist locally or on remote '${remoteOrigin}'`,
785
806
  suggestion: `Create branch: git checkout -b ${mainBranch} OR update config to use existing branch (e.g., 'master', 'develop')`,
@@ -788,7 +809,7 @@ async function checkMainBranch(config) {
788
809
  catch (error) {
789
810
  const errorMessage = error instanceof Error ? error.message : String(error);
790
811
  return {
791
- name: 'Git main branch',
812
+ name: CHECK_GIT_MAIN_BRANCH,
792
813
  passed: true,
793
814
  message: `Skipped (config or git error): ${errorMessage}`,
794
815
  };
@@ -801,9 +822,9 @@ async function checkRemoteOrigin(config) {
801
822
  try {
802
823
  if (!config) {
803
824
  return {
804
- name: 'Git remote origin',
825
+ name: CHECK_GIT_REMOTE_ORIGIN,
805
826
  passed: true,
806
- message: 'Skipped (no config)',
827
+ message: MSG_SKIPPED_NO_CONFIG,
807
828
  };
808
829
  }
809
830
  const remoteOrigin = getRemoteOrigin(config.git);
@@ -814,7 +835,7 @@ async function checkRemoteOrigin(config) {
814
835
  : [];
815
836
  if (remotes.includes(remoteOrigin)) {
816
837
  return {
817
- name: 'Git remote origin',
838
+ name: CHECK_GIT_REMOTE_ORIGIN,
818
839
  passed: true,
819
840
  message: `Remote '${remoteOrigin}' exists`,
820
841
  };
@@ -822,7 +843,7 @@ async function checkRemoteOrigin(config) {
822
843
  else {
823
844
  const availableRemotes = remotes.join(', ') || '(none)';
824
845
  return {
825
- name: 'Git remote origin',
846
+ name: CHECK_GIT_REMOTE_ORIGIN,
826
847
  passed: false,
827
848
  message: `Configured remote '${remoteOrigin}' does not exist. Available: ${availableRemotes}`,
828
849
  suggestion: `Add remote: git remote add ${remoteOrigin} <url> OR update config to use existing remote (e.g., 'origin')`,
@@ -832,7 +853,7 @@ async function checkRemoteOrigin(config) {
832
853
  catch (error) {
833
854
  const errorMessage = error instanceof Error ? error.message : String(error);
834
855
  return {
835
- name: 'Git remote origin',
856
+ name: CHECK_GIT_REMOTE_ORIGIN,
836
857
  passed: false,
837
858
  message: `Failed to list git remotes: ${errorMessage}`,
838
859
  suggestion: 'Verify git repository is initialized',
@@ -842,7 +863,7 @@ async function checkRemoteOrigin(config) {
842
863
  catch (error) {
843
864
  const errorMessage = error instanceof Error ? error.message : String(error);
844
865
  return {
845
- name: 'Git remote origin',
866
+ name: CHECK_GIT_REMOTE_ORIGIN,
846
867
  passed: true,
847
868
  message: `Skipped (config or git error): ${errorMessage}`,
848
869
  };
@@ -855,9 +876,9 @@ async function checkRemoteMainBranch(config) {
855
876
  try {
856
877
  if (!config) {
857
878
  return {
858
- name: 'Git remote main branch',
879
+ name: CHECK_GIT_REMOTE_MAIN_BRANCH,
859
880
  passed: true,
860
- message: 'Skipped (no config)',
881
+ message: MSG_SKIPPED_NO_CONFIG,
861
882
  };
862
883
  }
863
884
  const mainBranch = getMainBranch(config.git);
@@ -870,7 +891,7 @@ async function checkRemoteMainBranch(config) {
870
891
  : [];
871
892
  if (!remotes.includes(remoteOrigin)) {
872
893
  return {
873
- name: 'Git remote main branch',
894
+ name: CHECK_GIT_REMOTE_MAIN_BRANCH,
874
895
  passed: true,
875
896
  message: `Skipped (remote '${remoteOrigin}' not configured)`,
876
897
  };
@@ -881,7 +902,7 @@ async function checkRemoteMainBranch(config) {
881
902
  throw new Error(`Failed to check remote branch: ${lsRemoteResult.stderr}`);
882
903
  }
883
904
  return {
884
- name: 'Git remote main branch',
905
+ name: CHECK_GIT_REMOTE_MAIN_BRANCH,
885
906
  passed: true,
886
907
  message: `Branch '${mainBranch}' exists on remote '${remoteOrigin}'`,
887
908
  };
@@ -889,7 +910,7 @@ async function checkRemoteMainBranch(config) {
889
910
  catch (error) {
890
911
  const errorMessage = error instanceof Error ? error.message : String(error);
891
912
  return {
892
- name: 'Git remote main branch',
913
+ name: CHECK_GIT_REMOTE_MAIN_BRANCH,
893
914
  passed: false,
894
915
  message: `Branch '${mainBranch}' does not exist on remote '${remoteOrigin}': ${errorMessage}`,
895
916
  suggestion: `Push branch: git push ${remoteOrigin} ${mainBranch} OR update config to match remote branch name`,
@@ -899,7 +920,7 @@ async function checkRemoteMainBranch(config) {
899
920
  catch (error) {
900
921
  const errorMessage = error instanceof Error ? error.message : String(error);
901
922
  return {
902
- name: 'Git remote main branch',
923
+ name: CHECK_GIT_REMOTE_MAIN_BRANCH,
903
924
  passed: true,
904
925
  message: `Skipped (config or git error): ${errorMessage}`,
905
926
  };
@@ -912,15 +933,15 @@ async function checkSecretScanning(config) {
912
933
  try {
913
934
  if (!config) {
914
935
  return {
915
- name: 'Pre-commit secret scanning',
936
+ name: CHECK_PRE_COMMIT_SECRET_SCANNING,
916
937
  passed: true,
917
- message: 'Skipped (no config)',
938
+ message: MSG_SKIPPED_NO_CONFIG,
918
939
  };
919
940
  }
920
941
  const secretScanning = config.hooks?.preCommit?.secretScanning;
921
942
  if (!secretScanning) {
922
943
  return {
923
- name: 'Pre-commit secret scanning',
944
+ name: CHECK_PRE_COMMIT_SECRET_SCANNING,
924
945
  passed: true,
925
946
  message: 'Secret scanning not configured',
926
947
  suggestion: 'Recommended: Enable secret scanning to prevent credential leaks\n • Add to config: hooks.preCommit.secretScanning.enabled=true\n • Install gitleaks: brew install gitleaks\n • Or add .secretlintrc.json for npm-based scanning',
@@ -928,7 +949,7 @@ async function checkSecretScanning(config) {
928
949
  }
929
950
  if (secretScanning.enabled === false) {
930
951
  return {
931
- name: 'Pre-commit secret scanning',
952
+ name: CHECK_PRE_COMMIT_SECRET_SCANNING,
932
953
  passed: true,
933
954
  message: 'Secret scanning disabled in config (user preference)',
934
955
  };
@@ -940,7 +961,7 @@ async function checkSecretScanning(config) {
940
961
  const pm = detectPackageManager(process.cwd());
941
962
  const secretlintInstall = getDevInstallCommand(pm, '@secretlint/secretlint-rule-preset-recommend secretlint');
942
963
  return {
943
- name: 'Pre-commit secret scanning',
964
+ name: CHECK_PRE_COMMIT_SECRET_SCANNING,
944
965
  passed: true,
945
966
  message: 'Secret scanning enabled but no tools available',
946
967
  suggestion: `Install a secret scanning tool:\n • gitleaks: brew install gitleaks\n • secretlint: ${secretlintInstall}\n • Or add config files: .gitleaks.toml or .secretlintrc.json`,
@@ -974,7 +995,7 @@ async function checkSecretScanning(config) {
974
995
  const gitleaks = availableTools.find(t => t.tool === 'gitleaks');
975
996
  if (gitleaks?.hasConfig && !gitleaks.available) {
976
997
  return {
977
- name: 'Pre-commit secret scanning',
998
+ name: CHECK_PRE_COMMIT_SECRET_SCANNING,
978
999
  passed: true,
979
1000
  message,
980
1001
  suggestion: 'Install gitleaks for better performance: brew install gitleaks',
@@ -984,14 +1005,14 @@ async function checkSecretScanning(config) {
984
1005
  const hasGitleaksAvailable = availableTools.some(t => t.tool === 'gitleaks' && t.available);
985
1006
  if (!hasGitleaksAvailable && toolsToRun.some(t => t.tool === 'secretlint')) {
986
1007
  return {
987
- name: 'Pre-commit secret scanning',
1008
+ name: CHECK_PRE_COMMIT_SECRET_SCANNING,
988
1009
  passed: true,
989
1010
  message,
990
1011
  suggestion: 'Consider installing gitleaks for faster scanning: brew install gitleaks',
991
1012
  };
992
1013
  }
993
1014
  return {
994
- name: 'Pre-commit secret scanning',
1015
+ name: CHECK_PRE_COMMIT_SECRET_SCANNING,
995
1016
  passed: true,
996
1017
  message,
997
1018
  };
@@ -999,7 +1020,7 @@ async function checkSecretScanning(config) {
999
1020
  catch (error) {
1000
1021
  const errorMessage = error instanceof Error ? error.message : String(error);
1001
1022
  return {
1002
- name: 'Pre-commit secret scanning',
1023
+ name: CHECK_PRE_COMMIT_SECRET_SCANNING,
1003
1024
  passed: true,
1004
1025
  message: `Skipped (config or execution error): ${errorMessage}`,
1005
1026
  };