@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.
- package/README.md +51 -0
- package/config-templates/README.md +2 -2
- package/config-templates/minimal.yaml +19 -8
- package/config-templates/typescript-library.yaml +19 -8
- package/config-templates/typescript-nodejs.yaml +19 -8
- package/config-templates/typescript-react.yaml +19 -8
- package/dist/bin/vibe-validate +54 -3
- package/dist/bin/vibe-validate.d.ts +5 -0
- package/dist/bin/vibe-validate.d.ts.map +1 -1
- package/dist/bin/vibe-validate.js +54 -3
- package/dist/bin/vibe-validate.js.map +1 -1
- package/dist/bin/vv +54 -3
- package/dist/bin.js +4 -0
- package/dist/bin.js.map +1 -1
- package/dist/commands/create-extractor.d.ts.map +1 -1
- package/dist/commands/create-extractor.js +41 -6
- package/dist/commands/create-extractor.js.map +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +172 -126
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/pre-commit.d.ts.map +1 -1
- package/dist/commands/pre-commit.js +177 -63
- package/dist/commands/pre-commit.js.map +1 -1
- package/dist/commands/run.d.ts.map +1 -1
- package/dist/commands/run.js +15 -14
- package/dist/commands/run.js.map +1 -1
- package/dist/schemas/watch-pr-schema.d.ts +2 -2
- package/dist/services/ci-providers/github-actions.d.ts.map +1 -1
- package/dist/services/ci-providers/github-actions.js +3 -2
- package/dist/services/ci-providers/github-actions.js.map +1 -1
- package/dist/utils/git-detection.d.ts.map +1 -1
- package/dist/utils/git-detection.js +18 -18
- package/dist/utils/git-detection.js.map +1 -1
- package/dist/utils/project-id.d.ts +1 -2
- package/dist/utils/project-id.d.ts.map +1 -1
- package/dist/utils/project-id.js +6 -11
- package/dist/utils/project-id.js.map +1 -1
- package/dist/utils/runner-adapter.d.ts.map +1 -1
- package/dist/utils/runner-adapter.js +1 -0
- package/dist/utils/runner-adapter.js.map +1 -1
- package/dist/utils/secret-scanning.d.ts +72 -0
- package/dist/utils/secret-scanning.d.ts.map +1 -0
- package/dist/utils/secret-scanning.js +205 -0
- package/dist/utils/secret-scanning.js.map +1 -0
- package/dist/utils/validate-workflow.d.ts.map +1 -1
- package/dist/utils/validate-workflow.js +9 -1
- package/dist/utils/validate-workflow.js.map +1 -1
- 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
|
-
#
|
|
32
|
-
#
|
|
33
|
-
|
|
34
|
-
#
|
|
35
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
32
|
-
#
|
|
33
|
-
|
|
34
|
-
#
|
|
35
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
33
|
-
#
|
|
34
|
-
|
|
35
|
-
#
|
|
36
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
33
|
-
#
|
|
34
|
-
|
|
35
|
-
#
|
|
36
|
-
#
|
|
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
|
-
#
|
|
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
|
package/dist/bin/vibe-validate
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
|
|
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
|
|
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
|
|
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":";AACA
|
|
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
|
|
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
|