@vibecodr/cli 1.0.0 → 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 +75 -115
- package/MIGRATION.md +31 -2
- package/dist/auth/credential-broker.d.ts +28 -0
- package/dist/auth/credential-broker.d.ts.map +1 -0
- package/dist/auth/credential-broker.js +80 -0
- package/dist/auth/credential-broker.js.map +1 -0
- package/dist/bin/vc-tools.js +4 -0
- package/dist/bin/vc-tools.js.map +1 -1
- package/dist/bin/vibecodr-mcp.js +4 -0
- package/dist/bin/vibecodr-mcp.js.map +1 -1
- package/dist/clients/claude-code.d.ts.map +1 -1
- package/dist/clients/claude-code.js +5 -1
- package/dist/clients/claude-code.js.map +1 -1
- package/dist/core/env.d.ts +13 -0
- package/dist/core/env.d.ts.map +1 -0
- package/dist/core/env.js +62 -0
- package/dist/core/env.js.map +1 -0
- package/dist/legacy/config/store.d.ts.map +1 -1
- package/dist/legacy/config/store.js +19 -5
- package/dist/legacy/config/store.js.map +1 -1
- package/dist/legacy/core/version.d.ts +2 -2
- package/dist/legacy/core/version.js +1 -1
- package/dist/platform/paths.d.ts.map +1 -1
- package/dist/platform/paths.js +11 -1
- package/dist/platform/paths.js.map +1 -1
- package/dist/storage/config-store.d.ts.map +1 -1
- package/dist/storage/config-store.js +15 -3
- package/dist/storage/config-store.js.map +1 -1
- package/dist/storage/install-manifest.d.ts.map +1 -1
- package/dist/storage/install-manifest.js +14 -3
- package/dist/storage/install-manifest.js.map +1 -1
- package/dist/storage/migrate.d.ts +15 -0
- package/dist/storage/migrate.d.ts.map +1 -0
- package/dist/storage/migrate.js +93 -0
- package/dist/storage/migrate.js.map +1 -0
- package/dist/types/install.d.ts +4 -0
- package/dist/types/install.d.ts.map +1 -1
- package/docs/commands.md +171 -119
- package/docs/legacy/CHANGELOG-mcp-cli.md +85 -0
- package/package.json +74 -69
- package/preinstall-check.mjs +243 -0
|
@@ -0,0 +1,243 @@
|
|
|
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.
|
|
16
|
+
//
|
|
17
|
+
// Bail-outs (the check is a no-op in any of these cases):
|
|
18
|
+
// - VIBECDR_SKIP_PREINSTALL_CHECK=1 (operator opt-out)
|
|
19
|
+
// - not a global install (the conflict is global-bin-only)
|
|
20
|
+
// - running from inside this source repo (npm install / npm ci during
|
|
21
|
+
// local dev shouldn't trip the check)
|
|
22
|
+
// - any inspection failure (`npm ls`, fs access) -- we never block a
|
|
23
|
+
// legitimate install on a transient diagnostic error
|
|
24
|
+
|
|
25
|
+
import { execSync } from "node:child_process";
|
|
26
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
27
|
+
import path from "node:path";
|
|
28
|
+
import { fileURLToPath } from "node:url";
|
|
29
|
+
|
|
30
|
+
const SKIP_ENV = "VIBECDR_SKIP_PREINSTALL_CHECK";
|
|
31
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
32
|
+
const repoRoot = here;
|
|
33
|
+
|
|
34
|
+
function isLocalDevInstall() {
|
|
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.
|
|
39
|
+
const localPrefix = process.env["npm_config_local_prefix"] ?? process.env["INIT_CWD"];
|
|
40
|
+
if (!localPrefix) return false;
|
|
41
|
+
try {
|
|
42
|
+
return path.resolve(localPrefix) === repoRoot;
|
|
43
|
+
} catch {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function isGlobalInstall() {
|
|
49
|
+
return process.env["npm_config_global"] === "true";
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (process.env[SKIP_ENV] === "1") {
|
|
53
|
+
process.exit(0);
|
|
54
|
+
}
|
|
55
|
+
if (!isGlobalInstall()) {
|
|
56
|
+
process.exit(0);
|
|
57
|
+
}
|
|
58
|
+
if (isLocalDevInstall()) {
|
|
59
|
+
process.exit(0);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// ---------------------------------------------------------------------------
|
|
63
|
+
// Scenario 1: legacy @vibecodr/vc-tools@0.1.x globally installed
|
|
64
|
+
// ---------------------------------------------------------------------------
|
|
65
|
+
|
|
66
|
+
let collidingVersion;
|
|
67
|
+
try {
|
|
68
|
+
const output = execSync("npm ls -g --depth 0 --json @vibecodr/vc-tools", {
|
|
69
|
+
encoding: "utf8",
|
|
70
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
71
|
+
});
|
|
72
|
+
const parsed = JSON.parse(output);
|
|
73
|
+
const entry = parsed?.dependencies?.["@vibecodr/vc-tools"];
|
|
74
|
+
if (entry && typeof entry.version === "string") {
|
|
75
|
+
// 0.2.x is the tombstone forwarder package; it depends on @vibecodr/cli
|
|
76
|
+
// and is the intended migration path. Only block on the legacy 0.1.x line
|
|
77
|
+
// (and a defensive guard against any pre-0.2 versions we never published).
|
|
78
|
+
if (entry.version.startsWith("0.1.")) {
|
|
79
|
+
collidingVersion = entry.version;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
} catch {
|
|
83
|
+
// npm ls exits non-zero when the package isn't installed; treat as no
|
|
84
|
+
// conflict.
|
|
85
|
+
}
|
|
86
|
+
|
|
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");
|
|
110
|
+
}
|
|
111
|
+
|
|
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
|
+
}
|