@vibecodr/cli 1.0.1 → 1.0.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.
- package/CHANGELOG.md +17 -0
- package/dist/legacy/core/version.d.ts +2 -2
- package/dist/legacy/core/version.js +1 -1
- package/package.json +1 -1
- package/preinstall-check.mjs +181 -45
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
Pre-1.0.0 history for the `@vibecodr/cli@0.2.x` and `0.1.x` lines lives at [`docs/legacy/CHANGELOG-mcp-cli.md`](docs/legacy/CHANGELOG-mcp-cli.md). The `@vibecodr/vc-tools@0.1.x` line was the other half of the May 2026 merge; its source history is preserved in the archived [`BradenHartsell/vc-tools`](https://github.com/BradenHartsell/vc-tools) repository.
|
|
4
4
|
|
|
5
|
+
## 1.0.2
|
|
6
|
+
|
|
7
|
+
Hardens `preinstall-check.mjs` to also catch the **orphan-bin-shim** case that the 1.0.1 check missed.
|
|
8
|
+
|
|
9
|
+
When an earlier `npm install -g @vibecodr/cli` (or `@vibecodr/vc-tools`) was aborted mid-flight on Windows — typically because antivirus or an IDE held a file handle on the just-extracted tree during npm's cleanup — npm leaves the bin shim files (`vc-tools`, `vc-tools.cmd`, `vc-tools.ps1`, the `vibecodr` and `vibecodr-mcp` triples) at the global bin dir but the package itself isn't fully registered. The retry trips the same EEXIST because npm refuses to overwrite shim files it didn't write in the current install run.
|
|
10
|
+
|
|
11
|
+
The preinstall now:
|
|
12
|
+
|
|
13
|
+
- Inspects the global bin dir (`%APPDATA%\npm\` on Windows, `<prefix>/bin/` on POSIX) for any of the nine Windows shim names or three POSIX shim names.
|
|
14
|
+
- Cross-references against the global node_modules tree: if `<global-root>/@vibecodr/cli/package.json` doesn't exist or doesn't name `@vibecodr/cli`, the shim files are orphans.
|
|
15
|
+
- Prints an actionable cleanup recipe (`Remove-Item ... -Force` on Windows, `rm -f ...` on POSIX) listing the exact files to delete plus the half-installed package directory if present, then `npm install -g @vibecodr/cli`.
|
|
16
|
+
|
|
17
|
+
The check still bails for non-global installs, local dev installs from the source repo, and `VIBECDR_SKIP_PREINSTALL_CHECK=1` opt-outs, and false-positive-proofs itself: a clean re-install / upgrade of `@vibecodr/cli` (shims present + valid `@vibecodr/cli/package.json` present) passes through silently.
|
|
18
|
+
|
|
19
|
+
- `preinstall-check.mjs`: orphan-shim detection on top of the existing legacy-package check.
|
|
20
|
+
- `test/preinstall-check.test.ts`: 2 new cases (orphan-blocks, upgrade-passes-through) on top of the original 4.
|
|
21
|
+
|
|
5
22
|
## 1.0.1
|
|
6
23
|
|
|
7
24
|
Fixes the global-install collision for users who already had `@vibecodr/vc-tools@0.1.x` installed globally. Both packages register a `vc-tools` bin under the same path; npm refuses to overwrite a bin owned by a different package, so the install fails with `EEXIST: file already exists`.
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export declare const CLI_VERSION = "1.0.
|
|
2
|
-
export declare const VC_TOOLS_VERSION = "1.0.
|
|
1
|
+
export declare const CLI_VERSION = "1.0.2";
|
|
2
|
+
export declare const VC_TOOLS_VERSION = "1.0.2";
|
|
3
3
|
//# sourceMappingURL=version.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vibecodr/cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "The official Vibecodr CLI: hosted browser, hosted computer, capsule uploads, Pulse operations, and agent-client MCP setup under one command.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
package/preinstall-check.mjs
CHANGED
|
@@ -1,20 +1,29 @@
|
|
|
1
|
-
// Runs as the npm `preinstall` lifecycle script before file copy.
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
1
|
+
// Runs as the npm `preinstall` lifecycle script before file copy. Catches two
|
|
2
|
+
// install-blocking scenarios for `npm install -g @vibecodr/cli` and exits
|
|
3
|
+
// with an actionable message instead of leaving the user staring at npm's
|
|
4
|
+
// bare EEXIST:
|
|
5
|
+
//
|
|
6
|
+
// 1. Legacy install: @vibecodr/vc-tools@0.1.x is globally installed. That
|
|
7
|
+
// package and @vibecodr/cli@1.x both register a `vc-tools` bin under
|
|
8
|
+
// the same path; npm refuses to overwrite a bin owned by a different
|
|
9
|
+
// package.
|
|
10
|
+
// 2. Orphan shims from a prior aborted install: an earlier `npm install
|
|
11
|
+
// -g @vibecodr/cli` (or @vibecodr/vc-tools) wrote some of the
|
|
12
|
+
// `vc-tools` / `vibecodr` / `vibecodr-mcp` shim files at the global
|
|
13
|
+
// bin dir then died on Windows-handle-locked file cleanup. The
|
|
14
|
+
// orphan files block the retry with EEXIST even though no package
|
|
15
|
+
// currently claims them.
|
|
8
16
|
//
|
|
9
17
|
// Bail-outs (the check is a no-op in any of these cases):
|
|
10
18
|
// - VIBECDR_SKIP_PREINSTALL_CHECK=1 (operator opt-out)
|
|
11
19
|
// - not a global install (the conflict is global-bin-only)
|
|
12
20
|
// - running from inside this source repo (npm install / npm ci during
|
|
13
21
|
// local dev shouldn't trip the check)
|
|
14
|
-
// - npm ls
|
|
15
|
-
//
|
|
22
|
+
// - any inspection failure (`npm ls`, fs access) -- we never block a
|
|
23
|
+
// legitimate install on a transient diagnostic error
|
|
16
24
|
|
|
17
25
|
import { execSync } from "node:child_process";
|
|
26
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
18
27
|
import path from "node:path";
|
|
19
28
|
import { fileURLToPath } from "node:url";
|
|
20
29
|
|
|
@@ -23,9 +32,10 @@ const here = path.dirname(fileURLToPath(import.meta.url));
|
|
|
23
32
|
const repoRoot = here;
|
|
24
33
|
|
|
25
34
|
function isLocalDevInstall() {
|
|
26
|
-
// The npm lifecycle sets npm_config_local_prefix (or
|
|
27
|
-
// directory holding the package.json being installed FROM. For
|
|
28
|
-
// run inside this repo, that prefix equals our
|
|
35
|
+
// The npm lifecycle sets npm_config_local_prefix (or INIT_CWD) to the
|
|
36
|
+
// directory holding the package.json being installed FROM. For
|
|
37
|
+
// npm ci / npm install run inside this repo, that prefix equals our
|
|
38
|
+
// repo root.
|
|
29
39
|
const localPrefix = process.env["npm_config_local_prefix"] ?? process.env["INIT_CWD"];
|
|
30
40
|
if (!localPrefix) return false;
|
|
31
41
|
try {
|
|
@@ -49,6 +59,10 @@ if (isLocalDevInstall()) {
|
|
|
49
59
|
process.exit(0);
|
|
50
60
|
}
|
|
51
61
|
|
|
62
|
+
// ---------------------------------------------------------------------------
|
|
63
|
+
// Scenario 1: legacy @vibecodr/vc-tools@0.1.x globally installed
|
|
64
|
+
// ---------------------------------------------------------------------------
|
|
65
|
+
|
|
52
66
|
let collidingVersion;
|
|
53
67
|
try {
|
|
54
68
|
const output = execSync("npm ls -g --depth 0 --json @vibecodr/vc-tools", {
|
|
@@ -70,38 +84,160 @@ try {
|
|
|
70
84
|
// conflict.
|
|
71
85
|
}
|
|
72
86
|
|
|
73
|
-
if (
|
|
74
|
-
|
|
87
|
+
if (collidingVersion) {
|
|
88
|
+
printLegacyConflictMessage(collidingVersion);
|
|
89
|
+
process.exit(1);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// ---------------------------------------------------------------------------
|
|
93
|
+
// Scenario 2: orphan vc-tools / vibecodr / vibecodr-mcp shims at the global
|
|
94
|
+
// bin dir with no @vibecodr/cli package currently installed to own them
|
|
95
|
+
// ---------------------------------------------------------------------------
|
|
96
|
+
|
|
97
|
+
function npmGlobalBinDir() {
|
|
98
|
+
// Windows: <prefix>/. POSIX: <prefix>/bin.
|
|
99
|
+
const prefix = process.env["npm_config_prefix"];
|
|
100
|
+
if (!prefix) return undefined;
|
|
101
|
+
return process.platform === "win32" ? prefix : path.join(prefix, "bin");
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function npmGlobalRoot() {
|
|
105
|
+
const prefix = process.env["npm_config_prefix"];
|
|
106
|
+
if (!prefix) return undefined;
|
|
107
|
+
return process.platform === "win32"
|
|
108
|
+
? path.join(prefix, "node_modules")
|
|
109
|
+
: path.join(prefix, "lib", "node_modules");
|
|
75
110
|
}
|
|
76
111
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
112
|
+
function vibecodrCliInstalledAndValid() {
|
|
113
|
+
const root = npmGlobalRoot();
|
|
114
|
+
if (!root) return true; // can't determine -> don't block
|
|
115
|
+
const pkgPath = path.join(root, "@vibecodr", "cli", "package.json");
|
|
116
|
+
if (!existsSync(pkgPath)) return false;
|
|
117
|
+
try {
|
|
118
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
|
|
119
|
+
return pkg?.name === "@vibecodr/cli";
|
|
120
|
+
} catch {
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const SHIM_NAMES_WIN = ["vc-tools", "vc-tools.cmd", "vc-tools.ps1", "vibecodr", "vibecodr.cmd", "vibecodr.ps1", "vibecodr-mcp", "vibecodr-mcp.cmd", "vibecodr-mcp.ps1"];
|
|
126
|
+
const SHIM_NAMES_POSIX = ["vc-tools", "vibecodr", "vibecodr-mcp"];
|
|
127
|
+
|
|
128
|
+
function detectOrphanShims() {
|
|
129
|
+
const dir = npmGlobalBinDir();
|
|
130
|
+
if (!dir) return [];
|
|
131
|
+
const candidates = process.platform === "win32" ? SHIM_NAMES_WIN : SHIM_NAMES_POSIX;
|
|
132
|
+
return candidates.filter((name) => existsSync(path.join(dir, name)));
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const presentShims = detectOrphanShims();
|
|
136
|
+
if (presentShims.length > 0 && !vibecodrCliInstalledAndValid()) {
|
|
137
|
+
// Shim files exist at the global bin dir but no @vibecodr/cli package
|
|
138
|
+
// exists in global node_modules to own them. They're either from an
|
|
139
|
+
// earlier aborted install of @vibecodr/cli or a manually-deleted
|
|
140
|
+
// package that didn't clean its shims. Either way, the retry will
|
|
141
|
+
// EEXIST unless the user removes them first.
|
|
142
|
+
printOrphanShimMessage(npmGlobalBinDir(), npmGlobalRoot(), presentShims);
|
|
143
|
+
process.exit(1);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// No conflict detected; let npm proceed.
|
|
147
|
+
process.exit(0);
|
|
148
|
+
|
|
149
|
+
// ---------------------------------------------------------------------------
|
|
150
|
+
// Message helpers (separated so the test file can exercise the gate logic
|
|
151
|
+
// without diffing the multi-line console output)
|
|
152
|
+
// ---------------------------------------------------------------------------
|
|
153
|
+
|
|
154
|
+
function printLegacyConflictMessage(version) {
|
|
155
|
+
console.error("");
|
|
156
|
+
console.error("==========================================================================");
|
|
157
|
+
console.error(" @vibecodr/cli install blocked: legacy @vibecodr/vc-tools is in the way");
|
|
158
|
+
console.error("==========================================================================");
|
|
159
|
+
console.error("");
|
|
160
|
+
console.error(` You have @vibecodr/vc-tools@${version} installed globally. That`);
|
|
161
|
+
console.error(" package and @vibecodr/cli@1.x both claim the `vc-tools` bin name on");
|
|
162
|
+
console.error(" disk, and npm refuses to overwrite a bin owned by a different package");
|
|
163
|
+
console.error(" (you would otherwise see a cryptic EEXIST pointing at the global bin");
|
|
164
|
+
console.error(" dir).");
|
|
165
|
+
console.error("");
|
|
166
|
+
console.error(" The merged @vibecodr/cli replaces the legacy @vibecodr/vc-tools. The");
|
|
167
|
+
console.error(" legacy line is preserved on npm under explicit version pins; nothing");
|
|
168
|
+
console.error(" about your stored credentials, OS keychain entries, or config dirs is");
|
|
169
|
+
console.error(" removed by the uninstall below.");
|
|
170
|
+
console.error("");
|
|
171
|
+
console.error(" To unblock, in this order:");
|
|
172
|
+
console.error("");
|
|
173
|
+
console.error(" npm uninstall -g @vibecodr/vc-tools");
|
|
174
|
+
console.error(" npm install -g @vibecodr/cli");
|
|
175
|
+
console.error("");
|
|
176
|
+
console.error(" After install, all three bin names work and resolve to the same");
|
|
177
|
+
console.error(" dispatcher: vibecodr, vibecodr-mcp, vc-tools.");
|
|
178
|
+
console.error("");
|
|
179
|
+
console.error(" Advanced opt-out (not recommended): set VIBECDR_SKIP_PREINSTALL_CHECK=1");
|
|
180
|
+
console.error(" and retry. The collision still trips an EEXIST inside npm; the env var");
|
|
181
|
+
console.error(" only silences this preflight check.");
|
|
182
|
+
console.error("");
|
|
183
|
+
console.error("==========================================================================");
|
|
184
|
+
console.error("");
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function printOrphanShimMessage(binDir, root, shims) {
|
|
188
|
+
console.error("");
|
|
189
|
+
console.error("==========================================================================");
|
|
190
|
+
console.error(" @vibecodr/cli install blocked: orphan bin shims from a prior install");
|
|
191
|
+
console.error("==========================================================================");
|
|
192
|
+
console.error("");
|
|
193
|
+
console.error(" These bin shim files exist in your global npm bin directory but no");
|
|
194
|
+
console.error(" @vibecodr/cli package is currently installed to own them:");
|
|
195
|
+
console.error("");
|
|
196
|
+
for (const name of shims) {
|
|
197
|
+
console.error(` ${path.join(binDir, name)}`);
|
|
198
|
+
}
|
|
199
|
+
console.error("");
|
|
200
|
+
console.error(" They are typically left behind when an earlier global install of");
|
|
201
|
+
console.error(" @vibecodr/cli or @vibecodr/vc-tools was aborted mid-flight (Windows");
|
|
202
|
+
console.error(" file-handle locks during npm cleanup are the common cause). npm");
|
|
203
|
+
console.error(" refuses to overwrite shim files it didn't create in the current");
|
|
204
|
+
console.error(" install run, so the retry trips the same EEXIST every time.");
|
|
205
|
+
console.error("");
|
|
206
|
+
console.error(" To unblock on Windows (PowerShell):");
|
|
207
|
+
console.error("");
|
|
208
|
+
for (const name of shims) {
|
|
209
|
+
console.error(` Remove-Item "${path.join(binDir, name)}" -Force`);
|
|
210
|
+
}
|
|
211
|
+
if (root) {
|
|
212
|
+
const halfInstall = path.join(root, "@vibecodr", "cli");
|
|
213
|
+
if (existsSync(halfInstall)) {
|
|
214
|
+
console.error(` Remove-Item "${halfInstall}" -Recurse -Force`);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
console.error(" npm install -g @vibecodr/cli");
|
|
218
|
+
console.error("");
|
|
219
|
+
console.error(" On macOS / Linux (bash):");
|
|
220
|
+
console.error("");
|
|
221
|
+
for (const name of shims) {
|
|
222
|
+
console.error(` rm -f "${path.join(binDir, name)}"`);
|
|
223
|
+
}
|
|
224
|
+
if (root) {
|
|
225
|
+
const halfInstall = path.join(root, "@vibecodr", "cli");
|
|
226
|
+
if (existsSync(halfInstall)) {
|
|
227
|
+
console.error(` rm -rf "${halfInstall}"`);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
console.error(" npm install -g @vibecodr/cli");
|
|
231
|
+
console.error("");
|
|
232
|
+
console.error(" If the rm or Remove-Item fails with EPERM/locked-file errors, close");
|
|
233
|
+
console.error(" any IDE / terminal that has run vibecodr, vibecodr-mcp, or vc-tools");
|
|
234
|
+
console.error(" recently (the OS may still hold handles on the shim files), then");
|
|
235
|
+
console.error(" retry.");
|
|
236
|
+
console.error("");
|
|
237
|
+
console.error(" Advanced opt-out (not recommended): set VIBECDR_SKIP_PREINSTALL_CHECK=1");
|
|
238
|
+
console.error(" and retry. The shim collision still trips an EEXIST inside npm; the");
|
|
239
|
+
console.error(" env var only silences this preflight check.");
|
|
240
|
+
console.error("");
|
|
241
|
+
console.error("==========================================================================");
|
|
242
|
+
console.error("");
|
|
243
|
+
}
|