@vibesdotdev/bin 1.0.2 → 1.0.3-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/checkout.mjs +17 -0
- package/package.json +107 -33
- package/vibes.mjs +22 -0
- package/README.md +0 -37
- package/bin/vibes +0 -149
- package/scripts/postinstall.js +0 -310
package/checkout.mjs
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
import { captureCheckoutCliLaunch } from '@vibesdotdev/host-bun/cli-checkout';
|
|
3
|
+
import { startHost } from '@vibesdotdev/plugins/host-start.mjs';
|
|
4
|
+
// The checkout command is the same public CLI rooted at the declared checkout:
|
|
5
|
+
// it declares the published package's version, `vibes.plugins` selection and
|
|
6
|
+
// `vibes.config` block, resolved in the checkout's own graph.
|
|
7
|
+
import manifest from './package.json' with { type: 'json' };
|
|
8
|
+
|
|
9
|
+
const launch = captureCheckoutCliLaunch(import.meta.url);
|
|
10
|
+
await startHost({
|
|
11
|
+
...launch,
|
|
12
|
+
host: { ...launch.host, version: manifest.version },
|
|
13
|
+
hostPluginSpecifiers: manifest.vibes.plugins,
|
|
14
|
+
hostConfig: manifest.vibes.config,
|
|
15
|
+
attestHostGraph: true,
|
|
16
|
+
globalPackagePlugins: false
|
|
17
|
+
});
|
package/package.json
CHANGED
|
@@ -1,42 +1,116 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vibesdotdev/bin",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
"
|
|
3
|
+
"version": "1.0.3-rc.1",
|
|
4
|
+
"dependencies": {
|
|
5
|
+
"@vibesdotdev/account": "^1.0.0-rc.2",
|
|
6
|
+
"@vibesdotdev/agent-execution": "^1.0.0-rc.1",
|
|
7
|
+
"@vibesdotdev/ai": "^1.0.0-rc.3",
|
|
8
|
+
"@vibesdotdev/ai-schemas": "^1.0.0-rc.3",
|
|
9
|
+
"@vibesdotdev/applets": "^1.0.0-rc.2",
|
|
10
|
+
"@vibesdotdev/auth": "^1.0.0-rc.3",
|
|
11
|
+
"@vibesdotdev/bridge": "^1.0.0-rc.0",
|
|
12
|
+
"@vibesdotdev/chat": "^1.0.0-rc.0",
|
|
13
|
+
"@vibesdotdev/cli": "^1.0.0-rc.2",
|
|
14
|
+
"@vibesdotdev/code-sessions": "^1.0.0-rc.0",
|
|
15
|
+
"@vibesdotdev/command-palette": "^1.0.0-rc.3",
|
|
16
|
+
"@vibesdotdev/control": "^1.0.0-rc.2",
|
|
17
|
+
"@vibesdotdev/execution-local": "^1.0.0-rc.3",
|
|
18
|
+
"@vibesdotdev/filesystem": "^1.0.0-rc.2",
|
|
19
|
+
"@vibesdotdev/git-operations": "^1.0.0-rc.2",
|
|
20
|
+
"@vibesdotdev/host-bun": "^1.0.0-rc.2",
|
|
21
|
+
"@vibesdotdev/hq": "^1.0.0-rc.1",
|
|
22
|
+
"@vibesdotdev/infra-core": "^1.0.0-rc.4",
|
|
23
|
+
"@vibesdotdev/infra-deploy": "^1.0.0-rc.4",
|
|
24
|
+
"@vibesdotdev/integrations": "^1.0.0-rc.2",
|
|
25
|
+
"@vibesdotdev/integrations-vibes": "^1.0.0-rc.1",
|
|
26
|
+
"@vibesdotdev/kernel": "^1.0.0-rc.6",
|
|
27
|
+
"@vibesdotdev/kernel-rpc": "^1.0.0-rc.2",
|
|
28
|
+
"@vibesdotdev/kit": "^1.0.0-rc.3",
|
|
29
|
+
"@vibesdotdev/knowledge": "^1.0.0-rc.1",
|
|
30
|
+
"@vibesdotdev/mcp": "^1.0.0-rc.0",
|
|
31
|
+
"@vibesdotdev/notifications": "^1.0.0-rc.2",
|
|
32
|
+
"@vibesdotdev/platform": "^1.0.0-rc.1",
|
|
33
|
+
"@vibesdotdev/plugins": "^1.0.0-rc.0",
|
|
34
|
+
"@vibesdotdev/pm": "^1.0.0-rc.2",
|
|
35
|
+
"@vibesdotdev/projects": "^1.0.0-rc.0",
|
|
36
|
+
"@vibesdotdev/prompts": "^1.0.0-rc.0",
|
|
37
|
+
"@vibesdotdev/registry": "^1.0.0-rc.3",
|
|
38
|
+
"@vibesdotdev/scope": "^1.0.0-rc.2",
|
|
39
|
+
"@vibesdotdev/secrets": "^1.0.0-rc.3",
|
|
40
|
+
"@vibesdotdev/session": "^1.0.0-rc.1",
|
|
41
|
+
"@vibesdotdev/storage": "^1.0.0-rc.3",
|
|
42
|
+
"@vibesdotdev/studio": "^1.0.0-rc.0",
|
|
43
|
+
"@vibesdotdev/surface-sveltekit": "^1.0.0-rc.3",
|
|
44
|
+
"@vibesdotdev/sync": "^1.0.0-rc.2",
|
|
45
|
+
"@vibesdotdev/terminal-client": "^1.0.0-rc.2",
|
|
46
|
+
"@vibesdotdev/testing": "^1.0.0-rc.2",
|
|
47
|
+
"@vibesdotdev/tui": "^1.0.0-rc.2",
|
|
48
|
+
"@vibesdotdev/vessel": "^1.0.0-rc.2",
|
|
49
|
+
"@vibesdotdev/workboard": "^1.0.0-rc.0",
|
|
50
|
+
"@vibesdotdev/workspace": "^1.0.0-rc.1"
|
|
14
51
|
},
|
|
15
52
|
"files": [
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"README.md"
|
|
53
|
+
"vibes.mjs",
|
|
54
|
+
"checkout.mjs"
|
|
19
55
|
],
|
|
20
|
-
"scripts": {
|
|
21
|
-
"postinstall": "node scripts/postinstall.js",
|
|
22
|
-
"pack:dry-run": "npm pack --dry-run --json --ignore-scripts",
|
|
23
|
-
"publish:npm": "npm publish --access public --registry=https://registry.npmjs.org",
|
|
24
|
-
"check": "bun --bun tsc -p tsconfig.json --noEmit"
|
|
25
|
-
},
|
|
26
|
-
"os": [
|
|
27
|
-
"darwin",
|
|
28
|
-
"linux",
|
|
29
|
-
"win32"
|
|
30
|
-
],
|
|
31
|
-
"cpu": [
|
|
32
|
-
"x64",
|
|
33
|
-
"arm64"
|
|
34
|
-
],
|
|
35
|
-
"engines": {
|
|
36
|
-
"node": ">=18"
|
|
37
|
-
},
|
|
38
56
|
"publishConfig": {
|
|
39
|
-
"registry": "https://
|
|
57
|
+
"registry": "https://packages.vibes.dev",
|
|
40
58
|
"access": "public"
|
|
59
|
+
},
|
|
60
|
+
"vibes": {
|
|
61
|
+
"visibility": "public",
|
|
62
|
+
"tier": "public",
|
|
63
|
+
"compositionRoots": [
|
|
64
|
+
"vibes.mjs",
|
|
65
|
+
"checkout.mjs"
|
|
66
|
+
],
|
|
67
|
+
"plugins": [
|
|
68
|
+
"@vibesdotdev/plugins/consumer.plugin",
|
|
69
|
+
"@vibesdotdev/infra-core/service",
|
|
70
|
+
"@vibesdotdev/integrations-vibes/services",
|
|
71
|
+
"@vibesdotdev/infra-core/plugin",
|
|
72
|
+
"@vibesdotdev/infra-core/generate/plugin",
|
|
73
|
+
"@vibesdotdev/infra-deploy/plugin",
|
|
74
|
+
"@vibesdotdev/infra-deploy/cli/plugin",
|
|
75
|
+
"@vibesdotdev/pm/plugin",
|
|
76
|
+
"@vibesdotdev/pm/cli/plugin",
|
|
77
|
+
"@vibesdotdev/platform/cli/plugin",
|
|
78
|
+
"@vibesdotdev/platform/fleets/cli/plugin",
|
|
79
|
+
"@vibesdotdev/workboard/marshal/cli/plugin",
|
|
80
|
+
"@vibesdotdev/sync/plugin",
|
|
81
|
+
"@vibesdotdev/sync/cli/plugin",
|
|
82
|
+
"@vibesdotdev/studio/cli/plugin",
|
|
83
|
+
"@vibesdotdev/projects/app/cli/plugin",
|
|
84
|
+
"@vibesdotdev/plugins/tui/plugin"
|
|
85
|
+
],
|
|
86
|
+
"config": {
|
|
87
|
+
"runtime.host": {
|
|
88
|
+
"environmentTier": "local"
|
|
89
|
+
},
|
|
90
|
+
"infra.services": {
|
|
91
|
+
"environment": "production"
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
"registry": {
|
|
95
|
+
"repositoryId": "80ee5ed7-a88d-49f8-86e8-f867006d1b4d",
|
|
96
|
+
"directory": "npm-bin"
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
"description": "Vibes CLI. Starts the public plugin host with no setup command.",
|
|
100
|
+
"type": "module",
|
|
101
|
+
"license": "MIT",
|
|
102
|
+
"bin": {
|
|
103
|
+
"vibes": "./vibes.mjs"
|
|
104
|
+
},
|
|
105
|
+
"repository": {
|
|
106
|
+
"type": "git",
|
|
107
|
+
"url": "ssh://git@git.vibes.dev/vibesdotdev/cli-bin.git",
|
|
108
|
+
"directory": "npm-bin"
|
|
109
|
+
},
|
|
110
|
+
"gitHead": "a7f6e9d14b82eb7b4e792d85047b071108d7f190",
|
|
111
|
+
"_vibes_source": {
|
|
112
|
+
"repo": "ssh://git@git.vibes.dev/vibesdotdev/cli-bin.git",
|
|
113
|
+
"sha": "a7f6e9d14b82eb7b4e792d85047b071108d7f190",
|
|
114
|
+
"workspaceDigest": "sha256:5d4d9f9b903fb38485a09b0f2c4cc1c33d839d24c11048f23dff55177ab7a24a"
|
|
41
115
|
}
|
|
42
116
|
}
|
package/vibes.mjs
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
import { loadedCliHostDeclaration } from '@vibesdotdev/host-bun/resolution-root';
|
|
3
|
+
import { startHost } from '@vibesdotdev/plugins/host-start.mjs';
|
|
4
|
+
// The published package identity is the executable's declaration: its version
|
|
5
|
+
// is what `vibes --version` reports, and `vibes.plugins` is the public plugin
|
|
6
|
+
// selection this package installs as `dependencies` and composes at the graph
|
|
7
|
+
// it was installed into. `vibes.config` is the executable's own config block
|
|
8
|
+
// (the environment tier credentials resolve under, the services environment).
|
|
9
|
+
// Nothing here lists a plugin or a setting.
|
|
10
|
+
import manifest from './package.json' with { type: 'json' };
|
|
11
|
+
|
|
12
|
+
await startHost({
|
|
13
|
+
host: {
|
|
14
|
+
...loadedCliHostDeclaration({
|
|
15
|
+
scriptUrl: import.meta.url,
|
|
16
|
+
hostEntryUrl: import.meta.resolve('@vibesdotdev/plugins/host-start.mjs')
|
|
17
|
+
}),
|
|
18
|
+
version: manifest.version
|
|
19
|
+
},
|
|
20
|
+
hostPluginSpecifiers: manifest.vibes.plugins,
|
|
21
|
+
hostConfig: manifest.vibes.config
|
|
22
|
+
});
|
package/README.md
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
# Vibes CLI
|
|
2
|
-
|
|
3
|
-
Published npm wrapper for the public `vibes` binary.
|
|
4
|
-
|
|
5
|
-
## Installation
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npm install -g @vibesdotdev/bin
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
Or with bun:
|
|
12
|
-
|
|
13
|
-
```bash
|
|
14
|
-
bun add -g @vibesdotdev/bin
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
## Usage
|
|
18
|
-
|
|
19
|
-
The package downloads a platform-specific `vibes` binary during `postinstall` and exposes it through the package `bin` field.
|
|
20
|
-
|
|
21
|
-
Set `VIBES_BINARY_MIRROR` to override the release download base URL. The default
|
|
22
|
-
mirror is `https://assets.vibes.dev/downloads/cli`. The installer verifies the
|
|
23
|
-
download against `SHA256SUMS.txt` from the same mirror before completing.
|
|
24
|
-
|
|
25
|
-
To inspect the exact npm tarball before release:
|
|
26
|
-
|
|
27
|
-
```bash
|
|
28
|
-
npm run pack:dry-run
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
To publish from this package after npm auth is configured:
|
|
32
|
-
|
|
33
|
-
```bash
|
|
34
|
-
npm run publish:npm
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
See [https://vibes.dev](https://vibes.dev) for documentation.
|
package/bin/vibes
DELETED
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// Cross-platform launcher for the vibes CLI binary.
|
|
3
|
-
//
|
|
4
|
-
// npm's bin field is static, but the published package downloads a
|
|
5
|
-
// platform-specific binary at install time (scripts/postinstall.js):
|
|
6
|
-
// - Unix: overwrites THIS file (bin/vibes) with the binary itself,
|
|
7
|
-
// so subsequent invocations skip Node entirely.
|
|
8
|
-
// - Windows: writes bin/vibes.exe alongside this file. npm-on-Windows
|
|
9
|
-
// generates a vibes.cmd that does `node bin/vibes`, so this
|
|
10
|
-
// shim has to be a JS file that spawns the .exe. Without it,
|
|
11
|
-
// Windows would try to execute a shell script and fail.
|
|
12
|
-
//
|
|
13
|
-
// If neither artifact is present, postinstall didn't complete — surface a
|
|
14
|
-
// clear error rather than silently doing nothing.
|
|
15
|
-
|
|
16
|
-
'use strict';
|
|
17
|
-
|
|
18
|
-
const { spawnSync } = require('child_process');
|
|
19
|
-
const fs = require('fs');
|
|
20
|
-
const os = require('os');
|
|
21
|
-
const path = require('path');
|
|
22
|
-
|
|
23
|
-
const binDir = __dirname;
|
|
24
|
-
const installerPath = path.join(binDir, '..', 'scripts', 'postinstall.js');
|
|
25
|
-
const exePath = path.join(binDir, 'vibes.exe');
|
|
26
|
-
|
|
27
|
-
function getPersistentBinDir() {
|
|
28
|
-
if (process.env.VIBES_INSTALL_DIR) return process.env.VIBES_INSTALL_DIR;
|
|
29
|
-
|
|
30
|
-
const bunGlobalBin = readCommandOutput('bun', ['pm', 'bin', '-g']);
|
|
31
|
-
if (bunGlobalBin) return bunGlobalBin;
|
|
32
|
-
|
|
33
|
-
if (process.env.BUN_INSTALL) return path.join(process.env.BUN_INSTALL, 'bin');
|
|
34
|
-
|
|
35
|
-
if (process.platform === 'win32') {
|
|
36
|
-
const base = process.env.LOCALAPPDATA || path.join(os.homedir(), 'AppData', 'Local');
|
|
37
|
-
return path.join(base, 'Programs', 'vibes', 'bin');
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
if (process.env.XDG_BIN_HOME) return process.env.XDG_BIN_HOME;
|
|
41
|
-
return path.join(os.homedir(), '.local', 'bin');
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function readCommandOutput(command, args) {
|
|
45
|
-
const result = spawnSync(command, args, {
|
|
46
|
-
encoding: 'utf8',
|
|
47
|
-
stdio: ['ignore', 'pipe', 'ignore'],
|
|
48
|
-
windowsHide: true
|
|
49
|
-
});
|
|
50
|
-
if (result.error || result.status !== 0) return undefined;
|
|
51
|
-
const value = result.stdout.trim();
|
|
52
|
-
return value.length > 0 ? value : undefined;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function getPersistentBinaryPath() {
|
|
56
|
-
return path.join(getPersistentBinDir(), process.platform === 'win32' ? 'vibes.exe' : 'vibes');
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
function runInstaller() {
|
|
60
|
-
const result = spawnSync(process.execPath, [installerPath], {
|
|
61
|
-
stdio: 'inherit',
|
|
62
|
-
windowsHide: false,
|
|
63
|
-
env: { ...process.env, VIBES_INSTALL_PERSISTENT: '1' }
|
|
64
|
-
});
|
|
65
|
-
if (result.error) {
|
|
66
|
-
process.stderr.write(`Failed to run installer: ${result.error.message}\n`);
|
|
67
|
-
process.exit(1);
|
|
68
|
-
}
|
|
69
|
-
if (result.status !== 0) {
|
|
70
|
-
process.exit(result.status === null ? 1 : result.status);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
function reportMissingBinary() {
|
|
75
|
-
process.stderr.write('Error: vibes binary not installed.\n');
|
|
76
|
-
process.stderr.write('\n');
|
|
77
|
-
process.stderr.write('The installer could not place the platform binary.\n');
|
|
78
|
-
process.stderr.write('\n');
|
|
79
|
-
process.stderr.write('If the problem persists, see https://github.com/vibesdotdev/monorepo/issues\n');
|
|
80
|
-
process.exit(1);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function isStillNodeShim(filePath) {
|
|
84
|
-
try {
|
|
85
|
-
const content = fs.readFileSync(filePath, 'utf8');
|
|
86
|
-
return content.includes('Cross-platform launcher for the vibes CLI binary');
|
|
87
|
-
} catch {
|
|
88
|
-
return false;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
if (process.platform === 'win32') {
|
|
93
|
-
const persistentPath = getPersistentBinaryPath();
|
|
94
|
-
if (fs.existsSync(persistentPath)) {
|
|
95
|
-
const result = spawnSync(persistentPath, process.argv.slice(2), {
|
|
96
|
-
stdio: 'inherit',
|
|
97
|
-
windowsHide: false
|
|
98
|
-
});
|
|
99
|
-
if (result.error) {
|
|
100
|
-
process.stderr.write(`Failed to spawn ${persistentPath}: ${result.error.message}\n`);
|
|
101
|
-
process.exit(1);
|
|
102
|
-
}
|
|
103
|
-
process.exit(result.status === null ? 1 : result.status);
|
|
104
|
-
}
|
|
105
|
-
if (!fs.existsSync(exePath)) {
|
|
106
|
-
runInstaller();
|
|
107
|
-
}
|
|
108
|
-
if (!fs.existsSync(exePath)) {
|
|
109
|
-
reportMissingBinary();
|
|
110
|
-
}
|
|
111
|
-
const result = spawnSync(exePath, process.argv.slice(2), {
|
|
112
|
-
stdio: 'inherit',
|
|
113
|
-
windowsHide: false
|
|
114
|
-
});
|
|
115
|
-
if (result.error) {
|
|
116
|
-
process.stderr.write(`Failed to spawn vibes.exe: ${result.error.message}\n`);
|
|
117
|
-
process.exit(1);
|
|
118
|
-
}
|
|
119
|
-
process.exit(result.status === null ? 1 : result.status);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
const persistentPath = getPersistentBinaryPath();
|
|
123
|
-
if (fs.existsSync(persistentPath) && !isStillNodeShim(persistentPath)) {
|
|
124
|
-
const result = spawnSync(persistentPath, process.argv.slice(2), {
|
|
125
|
-
stdio: 'inherit',
|
|
126
|
-
windowsHide: false
|
|
127
|
-
});
|
|
128
|
-
if (result.error) {
|
|
129
|
-
process.stderr.write(`Failed to spawn ${persistentPath}: ${result.error.message}\n`);
|
|
130
|
-
process.exit(1);
|
|
131
|
-
}
|
|
132
|
-
process.exit(result.status === null ? 1 : result.status);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
runInstaller();
|
|
136
|
-
|
|
137
|
-
if (!fs.existsSync(persistentPath) || isStillNodeShim(persistentPath)) {
|
|
138
|
-
reportMissingBinary();
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
const result = spawnSync(persistentPath, process.argv.slice(2), {
|
|
142
|
-
stdio: 'inherit',
|
|
143
|
-
windowsHide: false
|
|
144
|
-
});
|
|
145
|
-
if (result.error) {
|
|
146
|
-
process.stderr.write(`Failed to spawn vibes: ${result.error.message}\n`);
|
|
147
|
-
process.exit(1);
|
|
148
|
-
}
|
|
149
|
-
process.exit(result.status === null ? 1 : result.status);
|
package/scripts/postinstall.js
DELETED
|
@@ -1,310 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
const https = require('https');
|
|
4
|
-
const http = require('http');
|
|
5
|
-
const crypto = require('crypto');
|
|
6
|
-
const { spawnSync } = require('child_process');
|
|
7
|
-
const fs = require('fs');
|
|
8
|
-
const path = require('path');
|
|
9
|
-
const os = require('os');
|
|
10
|
-
const BASE_URL = process.env.VIBES_BINARY_MIRROR || 'https://assets.vibes.dev/downloads/cli';
|
|
11
|
-
|
|
12
|
-
function getPlatform() {
|
|
13
|
-
const platform = os.platform();
|
|
14
|
-
if (platform === 'win32') return 'win32';
|
|
15
|
-
if (platform === 'darwin') return 'darwin';
|
|
16
|
-
return 'linux';
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function getArch() {
|
|
20
|
-
const arch = os.arch();
|
|
21
|
-
if (arch === 'x64') return 'x64';
|
|
22
|
-
if (arch === 'arm64') return 'arm64';
|
|
23
|
-
// Node on macOS can report 'arm' for Apple Silicon
|
|
24
|
-
if (arch === 'arm' && getPlatform() === 'darwin') return 'arm64';
|
|
25
|
-
return 'x64';
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function getBinaryName() {
|
|
29
|
-
const platform = getPlatform();
|
|
30
|
-
const arch = getArch();
|
|
31
|
-
const baseName = `vibes-${platform}-${arch}`;
|
|
32
|
-
return platform === 'win32' ? `${baseName}.exe` : baseName;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function getOutputPath() {
|
|
36
|
-
const platform = getPlatform();
|
|
37
|
-
if (process.env.VIBES_INSTALL_PERSISTENT === '1') {
|
|
38
|
-
const dir = getPersistentBinDir();
|
|
39
|
-
const outputName = platform === 'win32' ? 'vibes.exe' : 'vibes';
|
|
40
|
-
return path.join(dir, outputName);
|
|
41
|
-
}
|
|
42
|
-
const dir = path.join(__dirname, '..', 'bin');
|
|
43
|
-
const outputName = platform === 'win32' ? 'vibes.exe' : 'vibes';
|
|
44
|
-
return path.join(dir, outputName);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
function getPersistentBinDir() {
|
|
48
|
-
if (process.env.VIBES_INSTALL_DIR) return process.env.VIBES_INSTALL_DIR;
|
|
49
|
-
|
|
50
|
-
const bunGlobalBin = readCommandOutput('bun', ['pm', 'bin', '-g']);
|
|
51
|
-
if (bunGlobalBin) return bunGlobalBin;
|
|
52
|
-
|
|
53
|
-
if (process.env.BUN_INSTALL) return path.join(process.env.BUN_INSTALL, 'bin');
|
|
54
|
-
|
|
55
|
-
if (process.platform === 'win32') {
|
|
56
|
-
const base = process.env.LOCALAPPDATA || path.join(os.homedir(), 'AppData', 'Local');
|
|
57
|
-
return path.join(base, 'Programs', 'vibes', 'bin');
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (process.env.XDG_BIN_HOME) return process.env.XDG_BIN_HOME;
|
|
61
|
-
|
|
62
|
-
// POSIX fallback used by Linux distributions and many shell setups. If it is
|
|
63
|
-
// not on PATH, the installer prints a warning with the exact directory.
|
|
64
|
-
return path.join(os.homedir(), '.local', 'bin');
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
function readCommandOutput(command, args) {
|
|
68
|
-
const result = spawnSync(command, args, {
|
|
69
|
-
encoding: 'utf8',
|
|
70
|
-
stdio: ['ignore', 'pipe', 'ignore'],
|
|
71
|
-
windowsHide: true
|
|
72
|
-
});
|
|
73
|
-
if (result.error || result.status !== 0) return undefined;
|
|
74
|
-
const value = result.stdout.trim();
|
|
75
|
-
return value.length > 0 ? value : undefined;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function pathHasDir(dir) {
|
|
79
|
-
const pathValue = process.env.PATH || '';
|
|
80
|
-
const resolvedDir = path.resolve(dir);
|
|
81
|
-
return pathValue
|
|
82
|
-
.split(path.delimiter)
|
|
83
|
-
.filter(Boolean)
|
|
84
|
-
.some((entry) => path.resolve(entry) === resolvedDir);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
function showProgress(total, current) {
|
|
88
|
-
if (total > 0) {
|
|
89
|
-
const percent = Math.round((current / total) * 100);
|
|
90
|
-
const bar = '[' + '='.repeat(Math.floor(percent / 5)) + ' '.repeat(20 - Math.floor(percent / 5)) + ']';
|
|
91
|
-
process.stdout.write(`\r${bar} ${percent}%`);
|
|
92
|
-
} else {
|
|
93
|
-
process.stdout.write('.');
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
function download(url, dest, callback) {
|
|
98
|
-
const protocol = url.startsWith('https') ? https : http;
|
|
99
|
-
|
|
100
|
-
const request = protocol.get(url, { timeout: 30000 }, (response) => {
|
|
101
|
-
// Handle redirects
|
|
102
|
-
if (response.statusCode >= 300 && response.statusCode < 400 && response.headers.location) {
|
|
103
|
-
download(response.headers.location, dest, callback);
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
if (response.statusCode !== 200) {
|
|
108
|
-
callback(new Error(`Failed to download: HTTP ${response.statusCode}`));
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
const total = parseInt(response.headers['content-length'], 10);
|
|
113
|
-
let downloaded = 0;
|
|
114
|
-
|
|
115
|
-
const fp = fs.openSync(dest, 'w');
|
|
116
|
-
response.on('data', (chunk) => {
|
|
117
|
-
downloaded += chunk.length;
|
|
118
|
-
showProgress(total, downloaded);
|
|
119
|
-
fs.writeSync(fp, chunk);
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
response.on('end', () => {
|
|
123
|
-
fs.closeSync(fp);
|
|
124
|
-
console.log();
|
|
125
|
-
callback(null);
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
response.on('error', (err) => {
|
|
129
|
-
fs.closeSync(fp);
|
|
130
|
-
callback(err);
|
|
131
|
-
});
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
request.on('error', (err) => {
|
|
135
|
-
callback(err);
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
request.on('timeout', () => {
|
|
139
|
-
request.destroy();
|
|
140
|
-
callback(new Error('Download timed out'));
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
function fetchText(url, callback) {
|
|
145
|
-
const protocol = url.startsWith('https') ? https : http;
|
|
146
|
-
|
|
147
|
-
const request = protocol.get(url, { timeout: 30000 }, (response) => {
|
|
148
|
-
if (response.statusCode >= 300 && response.statusCode < 400 && response.headers.location) {
|
|
149
|
-
fetchText(response.headers.location, callback);
|
|
150
|
-
return;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
if (response.statusCode !== 200) {
|
|
154
|
-
callback(new Error(`HTTP ${response.statusCode}`));
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
let body = '';
|
|
159
|
-
response.setEncoding('utf8');
|
|
160
|
-
response.on('data', (chunk) => {
|
|
161
|
-
body += chunk;
|
|
162
|
-
});
|
|
163
|
-
response.on('end', () => callback(null, body));
|
|
164
|
-
response.on('error', callback);
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
request.on('error', callback);
|
|
168
|
-
request.on('timeout', () => {
|
|
169
|
-
request.destroy();
|
|
170
|
-
callback(new Error('Download timed out'));
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
function verifyChecksum(binaryName, filePath) {
|
|
175
|
-
return new Promise((resolve, reject) => {
|
|
176
|
-
if (process.env.VIBES_SKIP_CHECKSUM === '1') {
|
|
177
|
-
console.warn('Warning: VIBES_SKIP_CHECKSUM=1 set; skipping checksum verification.');
|
|
178
|
-
resolve();
|
|
179
|
-
return;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
const checksumUrl = `${BASE_URL}/SHA256SUMS.txt`;
|
|
183
|
-
fetchText(checksumUrl, (err, text) => {
|
|
184
|
-
if (err) {
|
|
185
|
-
reject(new Error(`Could not fetch checksum file from ${checksumUrl}: ${err.message}`));
|
|
186
|
-
return;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
const line = text
|
|
190
|
-
.split(/\r?\n/)
|
|
191
|
-
.find((entry) => entry.trim().endsWith(` ${binaryName}`));
|
|
192
|
-
if (!line) {
|
|
193
|
-
reject(new Error(`No checksum entry for ${binaryName} in ${checksumUrl}`));
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
const expected = line.trim().split(/\s+/)[0];
|
|
198
|
-
const actual = crypto.createHash('sha256').update(fs.readFileSync(filePath)).digest('hex');
|
|
199
|
-
if (actual !== expected) {
|
|
200
|
-
reject(new Error(`Checksum mismatch for ${binaryName}`));
|
|
201
|
-
return;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
console.log('Verified release checksum');
|
|
205
|
-
resolve();
|
|
206
|
-
});
|
|
207
|
-
});
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
function makeExecutable(filePath) {
|
|
211
|
-
const platform = getPlatform();
|
|
212
|
-
if (platform === 'win32') return;
|
|
213
|
-
|
|
214
|
-
try {
|
|
215
|
-
fs.chmodSync(filePath, 0o755);
|
|
216
|
-
} catch (err) {
|
|
217
|
-
console.error('Warning: Could not chmod +x:', err.message);
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
function isWorkspaceInstall() {
|
|
222
|
-
// Explicit opt-out (set in CI, the monorepo's bun install, or any env that
|
|
223
|
-
// already has the binary built locally and doesn't want network on install).
|
|
224
|
-
if (process.env.VIBES_SKIP_BINARY_DOWNLOAD === '1') return true;
|
|
225
|
-
|
|
226
|
-
// When this package is installed from the npm registry, the realpath of the
|
|
227
|
-
// script location includes `/node_modules/` (the unpacked tarball path). When
|
|
228
|
-
// bun installs us via a workspace link, realpath dereferences the symlink to
|
|
229
|
-
// the monorepo source — which lives outside any `node_modules` directory. We
|
|
230
|
-
// use this asymmetry to skip downloads cleanly inside the workspace while
|
|
231
|
-
// failing loudly for real end-user installs.
|
|
232
|
-
try {
|
|
233
|
-
const real = fs.realpathSync(__dirname);
|
|
234
|
-
const sep = path.sep;
|
|
235
|
-
return !real.includes(`${sep}node_modules${sep}`);
|
|
236
|
-
} catch {
|
|
237
|
-
return false;
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
async function main() {
|
|
242
|
-
if (isWorkspaceInstall()) {
|
|
243
|
-
console.log('Vibes CLI installer: workspace install detected, skipping binary download.');
|
|
244
|
-
return;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
const binaryName = getBinaryName();
|
|
248
|
-
const outputPath = getOutputPath();
|
|
249
|
-
const url = `${BASE_URL}/${binaryName}`;
|
|
250
|
-
|
|
251
|
-
console.log(`Vibes CLI installer`);
|
|
252
|
-
console.log(`Platform: ${getPlatform()}, Arch: ${getArch()}`);
|
|
253
|
-
console.log(`Downloading ${binaryName}...`);
|
|
254
|
-
|
|
255
|
-
// Ensure bin directory exists
|
|
256
|
-
const binDir = path.dirname(outputPath);
|
|
257
|
-
if (!fs.existsSync(binDir)) {
|
|
258
|
-
fs.mkdirSync(binDir, { recursive: true });
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
// Check if already exists and up-to-date
|
|
262
|
-
if (fs.existsSync(outputPath)) {
|
|
263
|
-
try {
|
|
264
|
-
fs.unlinkSync(outputPath);
|
|
265
|
-
} catch (err) {
|
|
266
|
-
console.error('Could not remove existing binary:', err.message);
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
return new Promise((resolve, reject) => {
|
|
271
|
-
download(url, outputPath, (err) => {
|
|
272
|
-
if (err) {
|
|
273
|
-
console.error();
|
|
274
|
-
console.error('Error:', err.message);
|
|
275
|
-
console.error(`Could not download binary from ${url}`);
|
|
276
|
-
console.error();
|
|
277
|
-
console.error('To resolve:');
|
|
278
|
-
console.error(` - Confirm a release exists at ${BASE_URL}`);
|
|
279
|
-
console.error(` - Confirm ${BASE_URL}/SHA256SUMS.txt is reachable and contains ${binaryName}`);
|
|
280
|
-
console.error(' - Or point VIBES_BINARY_MIRROR at an alternate download base URL');
|
|
281
|
-
console.error(' - Or download the binary manually and place it at:');
|
|
282
|
-
console.error(` ${outputPath}`);
|
|
283
|
-
console.error(' - Or set VIBES_SKIP_BINARY_DOWNLOAD=1 to skip this step');
|
|
284
|
-
console.error(' - Or set VIBES_SKIP_CHECKSUM=1 only if you trust the mirror and need to bypass checksum verification');
|
|
285
|
-
reject(err);
|
|
286
|
-
return;
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
verifyChecksum(binaryName, outputPath)
|
|
290
|
-
.then(() => {
|
|
291
|
-
makeExecutable(outputPath);
|
|
292
|
-
console.log(`Installed to ${outputPath}`);
|
|
293
|
-
const outputDir = path.dirname(outputPath);
|
|
294
|
-
if (process.env.VIBES_INSTALL_PERSISTENT === '1' && !pathHasDir(outputDir)) {
|
|
295
|
-
console.warn(`Warning: ${outputDir} is not on PATH. Add it to run \`vibes\` directly.`);
|
|
296
|
-
}
|
|
297
|
-
resolve();
|
|
298
|
-
})
|
|
299
|
-
.catch(reject);
|
|
300
|
-
});
|
|
301
|
-
});
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
main().catch((err) => {
|
|
305
|
-
console.error('Installation failed:', err.message);
|
|
306
|
-
// End-user installs reach here when isWorkspaceInstall() was false above
|
|
307
|
-
// (i.e., the script lives under node_modules) and the download failed. Fail
|
|
308
|
-
// loud so the user sees a broken install instead of a silently empty bin/.
|
|
309
|
-
process.exit(1);
|
|
310
|
-
});
|