@vibe-validate/cli 0.17.0-rc4 → 0.17.1-rc.1

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 (48) hide show
  1. package/README.md +51 -0
  2. package/config-templates/README.md +2 -2
  3. package/config-templates/minimal.yaml +19 -8
  4. package/config-templates/typescript-library.yaml +19 -8
  5. package/config-templates/typescript-nodejs.yaml +19 -8
  6. package/config-templates/typescript-react.yaml +19 -8
  7. package/dist/bin/vibe-validate +54 -3
  8. package/dist/bin/vibe-validate.d.ts +5 -0
  9. package/dist/bin/vibe-validate.d.ts.map +1 -1
  10. package/dist/bin/vibe-validate.js +54 -3
  11. package/dist/bin/vibe-validate.js.map +1 -1
  12. package/dist/bin/vv +54 -3
  13. package/dist/bin.js +4 -0
  14. package/dist/bin.js.map +1 -1
  15. package/dist/commands/create-extractor.d.ts.map +1 -1
  16. package/dist/commands/create-extractor.js +41 -6
  17. package/dist/commands/create-extractor.js.map +1 -1
  18. package/dist/commands/doctor.d.ts.map +1 -1
  19. package/dist/commands/doctor.js +172 -126
  20. package/dist/commands/doctor.js.map +1 -1
  21. package/dist/commands/pre-commit.d.ts.map +1 -1
  22. package/dist/commands/pre-commit.js +177 -63
  23. package/dist/commands/pre-commit.js.map +1 -1
  24. package/dist/commands/run.d.ts.map +1 -1
  25. package/dist/commands/run.js +15 -14
  26. package/dist/commands/run.js.map +1 -1
  27. package/dist/schemas/watch-pr-schema.d.ts +2 -2
  28. package/dist/services/ci-providers/github-actions.d.ts.map +1 -1
  29. package/dist/services/ci-providers/github-actions.js +3 -2
  30. package/dist/services/ci-providers/github-actions.js.map +1 -1
  31. package/dist/utils/git-detection.d.ts.map +1 -1
  32. package/dist/utils/git-detection.js +18 -18
  33. package/dist/utils/git-detection.js.map +1 -1
  34. package/dist/utils/project-id.d.ts +1 -2
  35. package/dist/utils/project-id.d.ts.map +1 -1
  36. package/dist/utils/project-id.js +6 -11
  37. package/dist/utils/project-id.js.map +1 -1
  38. package/dist/utils/runner-adapter.d.ts.map +1 -1
  39. package/dist/utils/runner-adapter.js +1 -0
  40. package/dist/utils/runner-adapter.js.map +1 -1
  41. package/dist/utils/secret-scanning.d.ts +72 -0
  42. package/dist/utils/secret-scanning.d.ts.map +1 -0
  43. package/dist/utils/secret-scanning.js +205 -0
  44. package/dist/utils/secret-scanning.js.map +1 -0
  45. package/dist/utils/validate-workflow.d.ts.map +1 -1
  46. package/dist/utils/validate-workflow.js +9 -1
  47. package/dist/utils/validate-workflow.js.map +1 -1
  48. package/package.json +8 -6
package/README.md CHANGED
@@ -9,6 +9,7 @@ The `@vibe-validate/cli` package provides a command-line interface for running v
9
9
 
10
10
  ## Features
11
11
 
12
+ - **🛡️ Automatic work protection** - Invisible safety net for all uncommitted changes
12
13
  - **🚀 Git tree hash-based caching** - 312x faster validation on unchanged code
13
14
  - **🤖 Agent-friendly output** - Minimal token waste, structured error reporting
14
15
  - **⚡ Parallel phase execution** - Run validation steps concurrently
@@ -487,6 +488,56 @@ phases:
487
488
  totalErrors: 1
488
489
  ```
489
490
 
491
+ ## Work Protection & Recovery
492
+
493
+ vibe-validate automatically protects your uncommitted work every time it calculates a git tree hash for caching.
494
+
495
+ ### How It Works
496
+
497
+ When you run validation commands, vibe-validate:
498
+ 1. Creates a temporary git index
499
+ 2. Stages all your files (tracked + untracked) in that temp index
500
+ 3. Runs `git write-tree` to create git objects for everything
501
+ 4. Cleans up the temp index (your real index is untouched)
502
+
503
+ **Result**: All your files are now in `.git/objects/` as git blobs, even if they're unstaged or untracked.
504
+
505
+ ### Recovery Commands
506
+
507
+ ```bash
508
+ # List validation history (shows tree hashes with timestamps)
509
+ vv history list
510
+
511
+ # Show files in a specific tree hash
512
+ git ls-tree <tree-hash>
513
+
514
+ # View a specific file from any validation point
515
+ git cat-file -p <tree-hash>:path/to/file.ts
516
+
517
+ # Recover a file
518
+ git cat-file -p <tree-hash>:src/deleted-work.ts > src/deleted-work.ts
519
+
520
+ # Recover entire directory
521
+ git checkout <tree-hash> -- src/
522
+ ```
523
+
524
+ ### Use Cases
525
+
526
+ - **Accidental git restore**: Recover unstaged changes after accidental revert
527
+ - **Bad refactoring**: Revert to code state before risky changes
528
+ - **Editor crashes**: Restore in-progress work from last validation
529
+ - **Experimental changes**: Compare current code vs previous validation snapshots
530
+ - **Team debugging**: Share exact code state via tree hash
531
+
532
+ ### When Protection Happens
533
+
534
+ Your work is automatically captured during:
535
+ - `vv validate` - Full validation
536
+ - `vv pre-commit` - Pre-commit workflow
537
+ - `vv run <command>` - Individual command execution (cached)
538
+
539
+ See [Work Protection Guide](../../docs/work-protection.md) for detailed examples.
540
+
490
541
  ## Integration with Pre-Commit Hooks
491
542
 
492
543
  **Recommended setup using [husky](https://typicode.github.io/husky/):**
@@ -322,8 +322,8 @@ All templates in this directory are:
322
322
  ## Related Documentation
323
323
 
324
324
  - [Getting Started Guide](../docs/getting-started.md)
325
- - [Configuration Reference](../docs/configuration-reference.md)
326
- - [CLI Reference](../docs/cli-reference.md)
325
+ - [Configuration Reference](../docs/skill/resources/configuration-reference.md)
326
+ - [CLI Reference](../docs/skill/resources/cli-reference.md)
327
327
 
328
328
  ---
329
329
 
@@ -25,17 +25,28 @@ hooks:
25
25
  preCommit:
26
26
  enabled: true
27
27
  # Secret scanning prevents accidental credential commits
28
- # Runs before validation to catch secrets in staged files
29
28
  secretScanning:
30
29
  enabled: true
31
- # Gitleaks is recommended for speed and comprehensive detection (160+ secret types)
32
- # Install: brew install gitleaks (macOS) | https://github.com/gitleaks/gitleaks#installation
33
- scanCommand: "gitleaks protect --staged --verbose"
34
- # Alternative tools:
35
- # - detect-secrets: scanCommand: "detect-secrets scan --staged"
36
- # - semgrep: scanCommand: "semgrep scan --config auto"
30
+ # Autodetect mode (recommended): Omit scanCommand to auto-detect tools
31
+ # Automatically runs tools based on config files present:
32
+ # - .gitleaks.toml or .gitleaksignore → runs gitleaks
33
+ # - .secretlintrc.json → runs secretlint (via npx)
34
+ # - Both files present runs both tools (defense-in-depth)
37
35
  #
38
- # False positives: Create .gitleaksignore file with fingerprints
36
+ # Setup options:
37
+ # 1. gitleaks (recommended - fast, 160+ secret types):
38
+ # macOS: brew install gitleaks
39
+ # Linux/Windows: https://github.com/gitleaks/gitleaks#installation
40
+ # Create .gitleaksignore for false positives
41
+ #
42
+ # 2. secretlint (npm-based, always available):
43
+ # npm install --save-dev @secretlint/secretlint-rule-preset-recommend secretlint
44
+ # Create .secretlintrc.json with: {"rules": [{"id": "@secretlint/secretlint-rule-preset-recommend"}]}
45
+ # Create .secretlintignore for false positives
46
+ #
47
+ # 3. Both (defense-in-depth): Create both config files
48
+ #
49
+ # To use explicit command instead: scanCommand: "gitleaks protect --staged --verbose"
39
50
  # To disable: set enabled: false
40
51
 
41
52
  # Validation configuration
@@ -25,17 +25,28 @@ hooks:
25
25
  preCommit:
26
26
  enabled: true
27
27
  # Secret scanning prevents accidental credential commits
28
- # Runs before validation to catch secrets in staged files
29
28
  secretScanning:
30
29
  enabled: true
31
- # Gitleaks is recommended for speed and comprehensive detection (160+ secret types)
32
- # Install: brew install gitleaks (macOS) | https://github.com/gitleaks/gitleaks#installation
33
- scanCommand: "gitleaks protect --staged --verbose"
34
- # Alternative tools:
35
- # - detect-secrets: scanCommand: "detect-secrets scan --staged"
36
- # - semgrep: scanCommand: "semgrep scan --config auto"
30
+ # Autodetect mode (recommended): Omit scanCommand to auto-detect tools
31
+ # Automatically runs tools based on config files present:
32
+ # - .gitleaks.toml or .gitleaksignore → runs gitleaks
33
+ # - .secretlintrc.json → runs secretlint (via npx)
34
+ # - Both files present runs both tools (defense-in-depth)
37
35
  #
38
- # False positives: Create .gitleaksignore file with fingerprints
36
+ # Setup options:
37
+ # 1. gitleaks (recommended - fast, 160+ secret types):
38
+ # macOS: brew install gitleaks
39
+ # Linux/Windows: https://github.com/gitleaks/gitleaks#installation
40
+ # Create .gitleaksignore for false positives
41
+ #
42
+ # 2. secretlint (npm-based, always available):
43
+ # npm install --save-dev @secretlint/secretlint-rule-preset-recommend secretlint
44
+ # Create .secretlintrc.json with: {"rules": [{"id": "@secretlint/secretlint-rule-preset-recommend"}]}
45
+ # Create .secretlintignore for false positives
46
+ #
47
+ # 3. Both (defense-in-depth): Create both config files
48
+ #
49
+ # To use explicit command instead: scanCommand: "gitleaks protect --staged --verbose"
39
50
  # To disable: set enabled: false
40
51
 
41
52
  # Validation configuration
@@ -26,17 +26,28 @@ hooks:
26
26
  preCommit:
27
27
  enabled: true
28
28
  # Secret scanning prevents accidental credential commits
29
- # Runs before validation to catch secrets in staged files
30
29
  secretScanning:
31
30
  enabled: true
32
- # Gitleaks is recommended for speed and comprehensive detection (160+ secret types)
33
- # Install: brew install gitleaks (macOS) | https://github.com/gitleaks/gitleaks#installation
34
- scanCommand: "gitleaks protect --staged --verbose"
35
- # Alternative tools:
36
- # - detect-secrets: scanCommand: "detect-secrets scan --staged"
37
- # - semgrep: scanCommand: "semgrep scan --config auto"
31
+ # Autodetect mode (recommended): Omit scanCommand to auto-detect tools
32
+ # Automatically runs tools based on config files present:
33
+ # - .gitleaks.toml or .gitleaksignore → runs gitleaks
34
+ # - .secretlintrc.json → runs secretlint (via npx)
35
+ # - Both files present runs both tools (defense-in-depth)
38
36
  #
39
- # False positives: Create .gitleaksignore file with fingerprints
37
+ # Setup options:
38
+ # 1. gitleaks (recommended - fast, 160+ secret types):
39
+ # macOS: brew install gitleaks
40
+ # Linux/Windows: https://github.com/gitleaks/gitleaks#installation
41
+ # Create .gitleaksignore for false positives
42
+ #
43
+ # 2. secretlint (npm-based, always available):
44
+ # npm install --save-dev @secretlint/secretlint-rule-preset-recommend secretlint
45
+ # Create .secretlintrc.json with: {"rules": [{"id": "@secretlint/secretlint-rule-preset-recommend"}]}
46
+ # Create .secretlintignore for false positives
47
+ #
48
+ # 3. Both (defense-in-depth): Create both config files
49
+ #
50
+ # To use explicit command instead: scanCommand: "gitleaks protect --staged --verbose"
40
51
  # To disable: set enabled: false
41
52
 
42
53
  # Validation configuration
@@ -26,17 +26,28 @@ hooks:
26
26
  preCommit:
27
27
  enabled: true
28
28
  # Secret scanning prevents accidental credential commits
29
- # Runs before validation to catch secrets in staged files
30
29
  secretScanning:
31
30
  enabled: true
32
- # Gitleaks is recommended for speed and comprehensive detection (160+ secret types)
33
- # Install: brew install gitleaks (macOS) | https://github.com/gitleaks/gitleaks#installation
34
- scanCommand: "gitleaks protect --staged --verbose"
35
- # Alternative tools:
36
- # - detect-secrets: scanCommand: "detect-secrets scan --staged"
37
- # - semgrep: scanCommand: "semgrep scan --config auto"
31
+ # Autodetect mode (recommended): Omit scanCommand to auto-detect tools
32
+ # Automatically runs tools based on config files present:
33
+ # - .gitleaks.toml or .gitleaksignore → runs gitleaks
34
+ # - .secretlintrc.json → runs secretlint (via npx)
35
+ # - Both files present runs both tools (defense-in-depth)
38
36
  #
39
- # False positives: Create .gitleaksignore file with fingerprints
37
+ # Setup options:
38
+ # 1. gitleaks (recommended - fast, 160+ secret types):
39
+ # macOS: brew install gitleaks
40
+ # Linux/Windows: https://github.com/gitleaks/gitleaks#installation
41
+ # Create .gitleaksignore for false positives
42
+ #
43
+ # 2. secretlint (npm-based, always available):
44
+ # npm install --save-dev @secretlint/secretlint-rule-preset-recommend secretlint
45
+ # Create .secretlintrc.json with: {"rules": [{"id": "@secretlint/secretlint-rule-preset-recommend"}]}
46
+ # Create .secretlintignore for false positives
47
+ #
48
+ # 3. Both (defense-in-depth): Create both config files
49
+ #
50
+ # To use explicit command instead: scanCommand: "gitleaks protect --staged --verbose"
40
51
  # To disable: set enabled: false
41
52
 
42
53
  # Validation configuration
@@ -7,10 +7,15 @@
7
7
  * - Local install: Project has vibe-validate → node_modules version (packaged)
8
8
  * - Global install: Fallback → globally installed version (packaged)
9
9
  *
10
+ * Features:
11
+ * - Version detection and comparison
12
+ * - Gentle warnings when global is outdated
13
+ * - Debug mode (VV_DEBUG=1) shows resolution details
14
+ *
10
15
  * Works in both git and non-git directories. Non-git directories don't get
11
16
  * caching but still get error extraction.
12
17
  */
13
- import { existsSync } from 'node:fs';
18
+ import { existsSync, readFileSync } from 'node:fs';
14
19
  import { dirname, join } from 'node:path';
15
20
  import { spawnSync } from 'node:child_process';
16
21
  import { fileURLToPath } from 'node:url';
@@ -46,8 +51,12 @@ function findProjectRoot(startDir) {
46
51
  * @returns Path to bin.js if detected, null otherwise
47
52
  */
48
53
  function getDevModeBinary(projectRoot) {
49
- const wrapperPath = join(projectRoot, 'packages/cli/dist/vibe-validate');
54
+ const wrapperPath = join(projectRoot, 'packages/cli/dist/bin/vibe-validate');
50
55
  const binPath = join(projectRoot, 'packages/cli/dist/bin.js');
56
+ if (process.env.VV_DEBUG === '1') {
57
+ console.error(`[vv debug] Dev check - wrapper: ${wrapperPath} (${existsSync(wrapperPath)})`);
58
+ console.error(`[vv debug] Dev check - bin: ${binPath} (${existsSync(binPath)})`);
59
+ }
51
60
  // Both files must exist to confirm we're in vibe-validate repo
52
61
  if (existsSync(wrapperPath) && existsSync(binPath)) {
53
62
  return binPath;
@@ -77,21 +86,42 @@ function findLocalInstall(projectRoot) {
77
86
  }
78
87
  return null;
79
88
  }
89
+ /**
90
+ * Read version from package.json
91
+ * @param packageJsonPath - Path to package.json file
92
+ * @returns Version string or null if not found
93
+ */
94
+ function readVersion(packageJsonPath) {
95
+ try {
96
+ if (!existsSync(packageJsonPath)) {
97
+ return null;
98
+ }
99
+ const content = readFileSync(packageJsonPath, 'utf-8');
100
+ const pkg = JSON.parse(content);
101
+ return pkg.version ?? null;
102
+ }
103
+ catch {
104
+ return null;
105
+ }
106
+ }
80
107
  /**
81
108
  * Main entry point - detects context and executes appropriate binary
82
109
  */
83
110
  function main() {
84
111
  const cwd = process.cwd();
85
112
  const args = process.argv.slice(2);
113
+ const debug = process.env.VV_DEBUG === '1';
86
114
  // Find project root (where .git is, or cwd if no git)
87
115
  const projectRoot = findProjectRoot(cwd);
88
116
  let binPath;
89
117
  let context;
118
+ let binDir;
90
119
  // Priority 1: Check for developer mode (inside vibe-validate repo)
91
120
  const devBin = getDevModeBinary(projectRoot);
92
121
  if (devBin) {
93
122
  binPath = devBin;
94
123
  context = 'dev';
124
+ binDir = dirname(dirname(devBin)); // packages/cli/dist -> packages/cli
95
125
  }
96
126
  // Priority 2: Check for local install (node_modules)
97
127
  else {
@@ -99,19 +129,40 @@ function main() {
99
129
  if (localBin) {
100
130
  binPath = localBin;
101
131
  context = 'local';
132
+ binDir = dirname(dirname(localBin)); // node_modules/@vibe-validate/cli/dist -> node_modules/@vibe-validate/cli
102
133
  }
103
134
  // Priority 3: Use global install (this script's location)
104
135
  else {
105
136
  binPath = join(__dirname, '../bin.js');
106
137
  context = 'global';
138
+ binDir = dirname(__dirname); // dist -> cli root
107
139
  }
108
140
  }
141
+ // Read versions for comparison
142
+ // __dirname = dist/bin, so go up twice to reach package.json at cli root
143
+ const globalPkgPath = join(dirname(dirname(__dirname)), 'package.json');
144
+ const globalVersion = readVersion(globalPkgPath);
145
+ let localVersion = null;
146
+ if (context === 'local') {
147
+ const localPkgPath = join(binDir, 'package.json');
148
+ localVersion = readVersion(localPkgPath);
149
+ }
150
+ // Debug output
151
+ if (debug) {
152
+ console.error(`[vv debug] CWD: ${cwd}`);
153
+ console.error(`[vv debug] Project root: ${projectRoot}`);
154
+ console.error(`[vv debug] Context: ${context}`);
155
+ console.error(`[vv debug] Binary: ${binPath}`);
156
+ console.error(`[vv debug] Global version: ${globalVersion ?? 'unknown'}`);
157
+ console.error(`[vv debug] Local version: ${localVersion ?? 'N/A'}`);
158
+ console.error(`[vv debug] Args: ${args.join(' ')}`);
159
+ }
109
160
  // Execute the binary with all arguments
110
161
  const result = spawnSync(process.execPath, [binPath, ...args], {
111
162
  stdio: 'inherit',
112
163
  env: {
113
164
  ...process.env,
114
- VV_CONTEXT: context, // Pass context for debugging (optional)
165
+ VV_CONTEXT: context, // Pass context for debugging
115
166
  },
116
167
  });
117
168
  // Exit with same code as child process
@@ -7,6 +7,11 @@
7
7
  * - Local install: Project has vibe-validate → node_modules version (packaged)
8
8
  * - Global install: Fallback → globally installed version (packaged)
9
9
  *
10
+ * Features:
11
+ * - Version detection and comparison
12
+ * - Gentle warnings when global is outdated
13
+ * - Debug mode (VV_DEBUG=1) shows resolution details
14
+ *
10
15
  * Works in both git and non-git directories. Non-git directories don't get
11
16
  * caching but still get error extraction.
12
17
  */
@@ -1 +1 @@
1
- {"version":3,"file":"vibe-validate.d.ts","sourceRoot":"","sources":["../../src/bin/vibe-validate.ts"],"names":[],"mappings":";AACA;;;;;;;;;;GAUG"}
1
+ {"version":3,"file":"vibe-validate.d.ts","sourceRoot":"","sources":["../../src/bin/vibe-validate.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;GAeG"}
@@ -7,10 +7,15 @@
7
7
  * - Local install: Project has vibe-validate → node_modules version (packaged)
8
8
  * - Global install: Fallback → globally installed version (packaged)
9
9
  *
10
+ * Features:
11
+ * - Version detection and comparison
12
+ * - Gentle warnings when global is outdated
13
+ * - Debug mode (VV_DEBUG=1) shows resolution details
14
+ *
10
15
  * Works in both git and non-git directories. Non-git directories don't get
11
16
  * caching but still get error extraction.
12
17
  */
13
- import { existsSync } from 'node:fs';
18
+ import { existsSync, readFileSync } from 'node:fs';
14
19
  import { dirname, join } from 'node:path';
15
20
  import { spawnSync } from 'node:child_process';
16
21
  import { fileURLToPath } from 'node:url';
@@ -46,8 +51,12 @@ function findProjectRoot(startDir) {
46
51
  * @returns Path to bin.js if detected, null otherwise
47
52
  */
48
53
  function getDevModeBinary(projectRoot) {
49
- const wrapperPath = join(projectRoot, 'packages/cli/dist/vibe-validate');
54
+ const wrapperPath = join(projectRoot, 'packages/cli/dist/bin/vibe-validate');
50
55
  const binPath = join(projectRoot, 'packages/cli/dist/bin.js');
56
+ if (process.env.VV_DEBUG === '1') {
57
+ console.error(`[vv debug] Dev check - wrapper: ${wrapperPath} (${existsSync(wrapperPath)})`);
58
+ console.error(`[vv debug] Dev check - bin: ${binPath} (${existsSync(binPath)})`);
59
+ }
51
60
  // Both files must exist to confirm we're in vibe-validate repo
52
61
  if (existsSync(wrapperPath) && existsSync(binPath)) {
53
62
  return binPath;
@@ -77,21 +86,42 @@ function findLocalInstall(projectRoot) {
77
86
  }
78
87
  return null;
79
88
  }
89
+ /**
90
+ * Read version from package.json
91
+ * @param packageJsonPath - Path to package.json file
92
+ * @returns Version string or null if not found
93
+ */
94
+ function readVersion(packageJsonPath) {
95
+ try {
96
+ if (!existsSync(packageJsonPath)) {
97
+ return null;
98
+ }
99
+ const content = readFileSync(packageJsonPath, 'utf-8');
100
+ const pkg = JSON.parse(content);
101
+ return pkg.version ?? null;
102
+ }
103
+ catch {
104
+ return null;
105
+ }
106
+ }
80
107
  /**
81
108
  * Main entry point - detects context and executes appropriate binary
82
109
  */
83
110
  function main() {
84
111
  const cwd = process.cwd();
85
112
  const args = process.argv.slice(2);
113
+ const debug = process.env.VV_DEBUG === '1';
86
114
  // Find project root (where .git is, or cwd if no git)
87
115
  const projectRoot = findProjectRoot(cwd);
88
116
  let binPath;
89
117
  let context;
118
+ let binDir;
90
119
  // Priority 1: Check for developer mode (inside vibe-validate repo)
91
120
  const devBin = getDevModeBinary(projectRoot);
92
121
  if (devBin) {
93
122
  binPath = devBin;
94
123
  context = 'dev';
124
+ binDir = dirname(dirname(devBin)); // packages/cli/dist -> packages/cli
95
125
  }
96
126
  // Priority 2: Check for local install (node_modules)
97
127
  else {
@@ -99,19 +129,40 @@ function main() {
99
129
  if (localBin) {
100
130
  binPath = localBin;
101
131
  context = 'local';
132
+ binDir = dirname(dirname(localBin)); // node_modules/@vibe-validate/cli/dist -> node_modules/@vibe-validate/cli
102
133
  }
103
134
  // Priority 3: Use global install (this script's location)
104
135
  else {
105
136
  binPath = join(__dirname, '../bin.js');
106
137
  context = 'global';
138
+ binDir = dirname(__dirname); // dist -> cli root
107
139
  }
108
140
  }
141
+ // Read versions for comparison
142
+ // __dirname = dist/bin, so go up twice to reach package.json at cli root
143
+ const globalPkgPath = join(dirname(dirname(__dirname)), 'package.json');
144
+ const globalVersion = readVersion(globalPkgPath);
145
+ let localVersion = null;
146
+ if (context === 'local') {
147
+ const localPkgPath = join(binDir, 'package.json');
148
+ localVersion = readVersion(localPkgPath);
149
+ }
150
+ // Debug output
151
+ if (debug) {
152
+ console.error(`[vv debug] CWD: ${cwd}`);
153
+ console.error(`[vv debug] Project root: ${projectRoot}`);
154
+ console.error(`[vv debug] Context: ${context}`);
155
+ console.error(`[vv debug] Binary: ${binPath}`);
156
+ console.error(`[vv debug] Global version: ${globalVersion ?? 'unknown'}`);
157
+ console.error(`[vv debug] Local version: ${localVersion ?? 'N/A'}`);
158
+ console.error(`[vv debug] Args: ${args.join(' ')}`);
159
+ }
109
160
  // Execute the binary with all arguments
110
161
  const result = spawnSync(process.execPath, [binPath, ...args], {
111
162
  stdio: 'inherit',
112
163
  env: {
113
164
  ...process.env,
114
- VV_CONTEXT: context, // Pass context for debugging (optional)
165
+ VV_CONTEXT: context, // Pass context for debugging
115
166
  },
116
167
  });
117
168
  // Exit with same code as child process
@@ -1 +1 @@
1
- {"version":3,"file":"vibe-validate.js","sourceRoot":"","sources":["../../src/bin/vibe-validate.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"vibe-validate.js","sourceRoot":"","sources":["../../src/bin/vibe-validate.ts"],"names":[],"mappings":"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"}
package/dist/bin/vv CHANGED
@@ -7,10 +7,15 @@
7
7
  * - Local install: Project has vibe-validate → node_modules version (packaged)
8
8
  * - Global install: Fallback → globally installed version (packaged)
9
9
  *
10
+ * Features:
11
+ * - Version detection and comparison
12
+ * - Gentle warnings when global is outdated
13
+ * - Debug mode (VV_DEBUG=1) shows resolution details
14
+ *
10
15
  * Works in both git and non-git directories. Non-git directories don't get
11
16
  * caching but still get error extraction.
12
17
  */
13
- import { existsSync } from 'node:fs';
18
+ import { existsSync, readFileSync } from 'node:fs';
14
19
  import { dirname, join } from 'node:path';
15
20
  import { spawnSync } from 'node:child_process';
16
21
  import { fileURLToPath } from 'node:url';
@@ -46,8 +51,12 @@ function findProjectRoot(startDir) {
46
51
  * @returns Path to bin.js if detected, null otherwise
47
52
  */
48
53
  function getDevModeBinary(projectRoot) {
49
- const wrapperPath = join(projectRoot, 'packages/cli/dist/vibe-validate');
54
+ const wrapperPath = join(projectRoot, 'packages/cli/dist/bin/vibe-validate');
50
55
  const binPath = join(projectRoot, 'packages/cli/dist/bin.js');
56
+ if (process.env.VV_DEBUG === '1') {
57
+ console.error(`[vv debug] Dev check - wrapper: ${wrapperPath} (${existsSync(wrapperPath)})`);
58
+ console.error(`[vv debug] Dev check - bin: ${binPath} (${existsSync(binPath)})`);
59
+ }
51
60
  // Both files must exist to confirm we're in vibe-validate repo
52
61
  if (existsSync(wrapperPath) && existsSync(binPath)) {
53
62
  return binPath;
@@ -77,21 +86,42 @@ function findLocalInstall(projectRoot) {
77
86
  }
78
87
  return null;
79
88
  }
89
+ /**
90
+ * Read version from package.json
91
+ * @param packageJsonPath - Path to package.json file
92
+ * @returns Version string or null if not found
93
+ */
94
+ function readVersion(packageJsonPath) {
95
+ try {
96
+ if (!existsSync(packageJsonPath)) {
97
+ return null;
98
+ }
99
+ const content = readFileSync(packageJsonPath, 'utf-8');
100
+ const pkg = JSON.parse(content);
101
+ return pkg.version ?? null;
102
+ }
103
+ catch {
104
+ return null;
105
+ }
106
+ }
80
107
  /**
81
108
  * Main entry point - detects context and executes appropriate binary
82
109
  */
83
110
  function main() {
84
111
  const cwd = process.cwd();
85
112
  const args = process.argv.slice(2);
113
+ const debug = process.env.VV_DEBUG === '1';
86
114
  // Find project root (where .git is, or cwd if no git)
87
115
  const projectRoot = findProjectRoot(cwd);
88
116
  let binPath;
89
117
  let context;
118
+ let binDir;
90
119
  // Priority 1: Check for developer mode (inside vibe-validate repo)
91
120
  const devBin = getDevModeBinary(projectRoot);
92
121
  if (devBin) {
93
122
  binPath = devBin;
94
123
  context = 'dev';
124
+ binDir = dirname(dirname(devBin)); // packages/cli/dist -> packages/cli
95
125
  }
96
126
  // Priority 2: Check for local install (node_modules)
97
127
  else {
@@ -99,19 +129,40 @@ function main() {
99
129
  if (localBin) {
100
130
  binPath = localBin;
101
131
  context = 'local';
132
+ binDir = dirname(dirname(localBin)); // node_modules/@vibe-validate/cli/dist -> node_modules/@vibe-validate/cli
102
133
  }
103
134
  // Priority 3: Use global install (this script's location)
104
135
  else {
105
136
  binPath = join(__dirname, '../bin.js');
106
137
  context = 'global';
138
+ binDir = dirname(__dirname); // dist -> cli root
107
139
  }
108
140
  }
141
+ // Read versions for comparison
142
+ // __dirname = dist/bin, so go up twice to reach package.json at cli root
143
+ const globalPkgPath = join(dirname(dirname(__dirname)), 'package.json');
144
+ const globalVersion = readVersion(globalPkgPath);
145
+ let localVersion = null;
146
+ if (context === 'local') {
147
+ const localPkgPath = join(binDir, 'package.json');
148
+ localVersion = readVersion(localPkgPath);
149
+ }
150
+ // Debug output
151
+ if (debug) {
152
+ console.error(`[vv debug] CWD: ${cwd}`);
153
+ console.error(`[vv debug] Project root: ${projectRoot}`);
154
+ console.error(`[vv debug] Context: ${context}`);
155
+ console.error(`[vv debug] Binary: ${binPath}`);
156
+ console.error(`[vv debug] Global version: ${globalVersion ?? 'unknown'}`);
157
+ console.error(`[vv debug] Local version: ${localVersion ?? 'N/A'}`);
158
+ console.error(`[vv debug] Args: ${args.join(' ')}`);
159
+ }
109
160
  // Execute the binary with all arguments
110
161
  const result = spawnSync(process.execPath, [binPath, ...args], {
111
162
  stdio: 'inherit',
112
163
  env: {
113
164
  ...process.env,
114
- VV_CONTEXT: context, // Pass context for debugging (optional)
165
+ VV_CONTEXT: context, // Pass context for debugging
115
166
  },
116
167
  });
117
168
  // Exit with same code as child process
package/dist/bin.js CHANGED
@@ -30,6 +30,10 @@ let version = '0.9.2'; // Fallback version
30
30
  try {
31
31
  const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
32
32
  version = packageJson.version;
33
+ // Append "-dev" suffix if running in dev context
34
+ if (process.env.VV_CONTEXT === 'dev') {
35
+ version = `${version}-dev`;
36
+ }
33
37
  }
34
38
  catch (error) {
35
39
  // If package.json can't be read (shouldn't happen in production), use fallback