solforge 0.2.10 → 0.2.12
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/package.json +4 -5
- package/src/cli/main.ts +8 -2
- package/start.cjs +277 -0
- package/cli.cjs +0 -159
- package/scripts/postinstall.cjs +0 -118
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "solforge",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.12",
|
|
4
4
|
"module": "index.ts",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -13,10 +13,10 @@
|
|
|
13
13
|
"url": "https://github.com/nitishxyz/solforge/issues"
|
|
14
14
|
},
|
|
15
15
|
"bin": {
|
|
16
|
-
"solforge": "
|
|
16
|
+
"solforge": "start.cjs"
|
|
17
17
|
},
|
|
18
18
|
"files": [
|
|
19
|
-
"
|
|
19
|
+
"start.cjs",
|
|
20
20
|
"scripts",
|
|
21
21
|
"src",
|
|
22
22
|
"server",
|
|
@@ -37,8 +37,7 @@
|
|
|
37
37
|
"build:gui": "bun build src/gui/src/main.tsx --outdir src/gui/public/build --target=browser --minify",
|
|
38
38
|
"cli": "bun src/cli/main.ts",
|
|
39
39
|
"lint": "biome check",
|
|
40
|
-
"
|
|
41
|
-
"prepack": "chmod +x cli.cjs || true"
|
|
40
|
+
"prepack": "chmod +x start.cjs || true"
|
|
42
41
|
},
|
|
43
42
|
"devDependencies": {
|
|
44
43
|
"@biomejs/biome": "2.2.4",
|
package/src/cli/main.ts
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
// Minimal, fast CLI router with @clack/prompts for UX
|
|
2
2
|
import * as p from "@clack/prompts";
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
import { readFileSync } from "fs";
|
|
4
|
+
import { join, dirname } from "path";
|
|
5
|
+
import { fileURLToPath } from "url";
|
|
6
|
+
|
|
7
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
const pkgPath = join(__dirname, "../../package.json");
|
|
9
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
|
|
10
|
+
const VERSION = pkg.version;
|
|
5
11
|
|
|
6
12
|
// Robust arg parsing for both bun script and compiled binary
|
|
7
13
|
const known = new Set([
|
package/start.cjs
ADDED
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// SolForge CLI bootstrapper
|
|
3
|
+
// - Checks if solforge binary exists in PATH (preinstalled/global)
|
|
4
|
+
// - Downloads and installs to ~/.local/bin if not found
|
|
5
|
+
// - Falls back to Bun-based TS entry if available
|
|
6
|
+
|
|
7
|
+
const fs = require("node:fs");
|
|
8
|
+
const path = require("node:path");
|
|
9
|
+
const https = require("node:https");
|
|
10
|
+
const os = require("node:os");
|
|
11
|
+
const { spawn, spawnSync } = require("node:child_process");
|
|
12
|
+
|
|
13
|
+
function pkg() {
|
|
14
|
+
// Resolve package.json next to this file regardless of install location
|
|
15
|
+
const p = path.join(__dirname, "package.json");
|
|
16
|
+
try {
|
|
17
|
+
return require(p);
|
|
18
|
+
} catch {
|
|
19
|
+
return { version: "" };
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function isInWorkspace() {
|
|
24
|
+
return (
|
|
25
|
+
fs.existsSync(path.join(__dirname, "src")) &&
|
|
26
|
+
fs.existsSync(path.join(__dirname, "package.json"))
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function findBinaryInPath() {
|
|
31
|
+
const pathDirs = (process.env.PATH || "").split(path.delimiter);
|
|
32
|
+
const ext = process.platform === "win32" ? ".exe" : "";
|
|
33
|
+
const binName = "solforge" + ext;
|
|
34
|
+
|
|
35
|
+
for (const dir of pathDirs) {
|
|
36
|
+
const binPath = path.join(dir, binName);
|
|
37
|
+
if (fs.existsSync(binPath)) {
|
|
38
|
+
try {
|
|
39
|
+
const stat = fs.statSync(binPath);
|
|
40
|
+
if (stat.isFile() && binPath !== __filename) {
|
|
41
|
+
const result = spawnSync("file", [binPath], { encoding: "utf8" });
|
|
42
|
+
if (!result.stdout || !result.stdout.includes("script text")) {
|
|
43
|
+
return binPath;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
} catch (err) {}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function assetName() {
|
|
53
|
+
const p = process.platform;
|
|
54
|
+
const a = process.arch;
|
|
55
|
+
if (p === "darwin" && a === "arm64") return "solforge-darwin-arm64";
|
|
56
|
+
if (p === "darwin" && a === "x64") return "solforge-darwin-x64";
|
|
57
|
+
if (p === "linux" && a === "x64") return "solforge-linux-x64";
|
|
58
|
+
if (p === "linux" && a === "arm64") return "solforge-linux-arm64";
|
|
59
|
+
if (p === "win32" && a === "x64") return "solforge-windows-x64.exe";
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function downloadWithProgress(url, dest) {
|
|
64
|
+
return new Promise((resolve, reject) => {
|
|
65
|
+
const file = fs.createWriteStream(dest);
|
|
66
|
+
let totalBytes = 0;
|
|
67
|
+
let downloadedBytes = 0;
|
|
68
|
+
|
|
69
|
+
function handleRedirect(response) {
|
|
70
|
+
if (
|
|
71
|
+
response.statusCode >= 300 &&
|
|
72
|
+
response.statusCode < 400 &&
|
|
73
|
+
response.headers.location
|
|
74
|
+
) {
|
|
75
|
+
https.get(response.headers.location, handleRedirect);
|
|
76
|
+
} else if (response.statusCode === 200) {
|
|
77
|
+
totalBytes = Number.parseInt(
|
|
78
|
+
response.headers["content-length"] || "0",
|
|
79
|
+
10
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
response.on("data", (chunk) => {
|
|
83
|
+
downloadedBytes += chunk.length;
|
|
84
|
+
if (totalBytes > 0) {
|
|
85
|
+
const percent = ((downloadedBytes / totalBytes) * 100).toFixed(1);
|
|
86
|
+
const downloadedMB = (downloadedBytes / 1024 / 1024).toFixed(1);
|
|
87
|
+
const totalMB = (totalBytes / 1024 / 1024).toFixed(1);
|
|
88
|
+
process.stdout.write(
|
|
89
|
+
`\rDownloading: ${percent}% (${downloadedMB}MB / ${totalMB}MB)`
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
response.pipe(file);
|
|
95
|
+
file.on("finish", () => {
|
|
96
|
+
file.close();
|
|
97
|
+
process.stdout.write("\n");
|
|
98
|
+
resolve();
|
|
99
|
+
});
|
|
100
|
+
} else {
|
|
101
|
+
reject(new Error(`Download failed: ${response.statusCode}`));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
https.get(url, handleRedirect).on("error", (err) => {
|
|
106
|
+
file.close();
|
|
107
|
+
reject(err);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function updateShellProfile(userBin) {
|
|
113
|
+
if (process.platform === "win32") return;
|
|
114
|
+
|
|
115
|
+
const shell = process.env.SHELL || "";
|
|
116
|
+
let configFile;
|
|
117
|
+
let shellType;
|
|
118
|
+
|
|
119
|
+
if (shell.includes("zsh")) {
|
|
120
|
+
configFile = path.resolve(os.homedir(), ".zshrc");
|
|
121
|
+
shellType = "zsh";
|
|
122
|
+
} else if (shell.includes("bash")) {
|
|
123
|
+
configFile = path.resolve(os.homedir(), ".bashrc");
|
|
124
|
+
shellType = "bash";
|
|
125
|
+
} else {
|
|
126
|
+
configFile = path.resolve(os.homedir(), ".profile");
|
|
127
|
+
shellType = "shell";
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const pathExport = 'export PATH="$HOME/.local/bin:$PATH"';
|
|
131
|
+
|
|
132
|
+
try {
|
|
133
|
+
let fileContent = "";
|
|
134
|
+
if (fs.existsSync(configFile)) {
|
|
135
|
+
fileContent = fs.readFileSync(configFile, "utf8");
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (fileContent.includes(".local/bin")) {
|
|
139
|
+
console.log(`✓ PATH already configured in ${configFile}`);
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
fs.appendFileSync(configFile, `\n${pathExport}\n`);
|
|
144
|
+
console.log(`✓ Added ${userBin} to PATH in ${configFile}`);
|
|
145
|
+
console.log(`✓ Restart your ${shellType} or run: source ${configFile}`);
|
|
146
|
+
} catch (error) {
|
|
147
|
+
console.log(`⚠️ Could not automatically update ${configFile}`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
async function install() {
|
|
152
|
+
try {
|
|
153
|
+
const asset = assetName();
|
|
154
|
+
if (!asset) {
|
|
155
|
+
throw new Error(`Unsupported platform: ${process.platform}-${process.arch}`);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const { version, repository } = pkg();
|
|
159
|
+
const repo =
|
|
160
|
+
process.env.SOLFORGE_REPO ||
|
|
161
|
+
(repository &&
|
|
162
|
+
(typeof repository === "string"
|
|
163
|
+
? repository.replace(/^github:/, "")
|
|
164
|
+
: repository.url &&
|
|
165
|
+
(repository.url.match(/github\.com[:/](.+?)\.git$/) || [])[1])) ||
|
|
166
|
+
"nitishxyz/solforge";
|
|
167
|
+
|
|
168
|
+
const url = `https://github.com/${repo}/releases/latest/download/${asset}`;
|
|
169
|
+
|
|
170
|
+
console.log(`Installing solforge (${process.platform}/${process.arch})...`);
|
|
171
|
+
|
|
172
|
+
const userBin = path.resolve(os.homedir(), ".local", "bin");
|
|
173
|
+
fs.mkdirSync(userBin, { recursive: true });
|
|
174
|
+
const ext = process.platform === "win32" ? ".exe" : "";
|
|
175
|
+
const binPath = path.resolve(userBin, `solforge${ext}`);
|
|
176
|
+
|
|
177
|
+
await downloadWithProgress(url, binPath);
|
|
178
|
+
|
|
179
|
+
fs.chmodSync(binPath, 0o755);
|
|
180
|
+
|
|
181
|
+
const result = spawnSync(binPath, ["--version"], { encoding: "utf8" });
|
|
182
|
+
if (result.status === 0) {
|
|
183
|
+
console.log("\n✓ solforge installed successfully!");
|
|
184
|
+
console.log(`Version: ${result.stdout.trim()}`);
|
|
185
|
+
console.log(`Location: ${binPath}`);
|
|
186
|
+
|
|
187
|
+
const pathDirs = (process.env.PATH || "").split(path.delimiter);
|
|
188
|
+
if (!pathDirs.includes(userBin)) {
|
|
189
|
+
updateShellProfile(userBin);
|
|
190
|
+
console.log(`\n⚠️ Add ${userBin} to your PATH:`);
|
|
191
|
+
console.log(
|
|
192
|
+
` echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc`
|
|
193
|
+
);
|
|
194
|
+
console.log(
|
|
195
|
+
` Or for zsh: echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zshrc`
|
|
196
|
+
);
|
|
197
|
+
} else {
|
|
198
|
+
console.log(`✓ ${userBin} already in PATH`);
|
|
199
|
+
}
|
|
200
|
+
} else {
|
|
201
|
+
console.log(`\n✓ Installed to ${binPath}`);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
console.log("\nRun: solforge --help");
|
|
205
|
+
return binPath;
|
|
206
|
+
} catch (error) {
|
|
207
|
+
console.error("Failed to install solforge CLI:", error.message);
|
|
208
|
+
console.error("\nPlease try installing manually:");
|
|
209
|
+
console.error(" curl -fsSL https://sh.solforge.sh | sh");
|
|
210
|
+
process.exit(1);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function run(cmd, args) {
|
|
215
|
+
return new Promise((resolve) => {
|
|
216
|
+
const child = spawn(cmd, args, { stdio: "inherit" });
|
|
217
|
+
child.on("exit", (code) => resolve(typeof code === "number" ? code : 0));
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
(async () => {
|
|
222
|
+
// Fast path for --version/--help without booting the app
|
|
223
|
+
const args = process.argv.slice(2);
|
|
224
|
+
if (
|
|
225
|
+
args.includes("-v") ||
|
|
226
|
+
args.includes("--version") ||
|
|
227
|
+
args[0] === "version"
|
|
228
|
+
) {
|
|
229
|
+
console.log(pkg().version || "");
|
|
230
|
+
process.exit(0);
|
|
231
|
+
}
|
|
232
|
+
if (args.includes("-h") || args.includes("--help") || args[0] === "help") {
|
|
233
|
+
console.log(`
|
|
234
|
+
solforge <command>
|
|
235
|
+
|
|
236
|
+
Commands:
|
|
237
|
+
(no command) Run setup then start RPC & WS servers
|
|
238
|
+
rpc start Start RPC & WS servers
|
|
239
|
+
start Alias for 'rpc start'
|
|
240
|
+
config init Create sf.config.json in CWD
|
|
241
|
+
config get <key> Read a config value (dot path)
|
|
242
|
+
config set <k> <v> Set a config value
|
|
243
|
+
airdrop --to <pubkey> --sol <amount> Airdrop SOL via RPC faucet
|
|
244
|
+
mint Interactive: pick mint, receiver, amount
|
|
245
|
+
token clone <mint> Clone SPL token mint + accounts
|
|
246
|
+
program clone <programId> Clone program code (and optionally accounts)
|
|
247
|
+
program accounts clone <programId> Clone accounts owned by program
|
|
248
|
+
|
|
249
|
+
Options:
|
|
250
|
+
-h, --help Show help
|
|
251
|
+
-v, --version Show version
|
|
252
|
+
--network Bind servers to 0.0.0.0 (LAN access)
|
|
253
|
+
-y, --ci Non-interactive; auto-accept prompts (use existing config)
|
|
254
|
+
`);
|
|
255
|
+
process.exit(0);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (isInWorkspace()) {
|
|
259
|
+
const bun = process.env.SOLFORGE_BUN || "bun";
|
|
260
|
+
const entry = path.join(__dirname, "src", "cli", "main.ts");
|
|
261
|
+
const code = await run(bun, [entry, ...process.argv.slice(2)]);
|
|
262
|
+
process.exit(code);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const pathBinary = findBinaryInPath();
|
|
266
|
+
if (pathBinary) {
|
|
267
|
+
const code = await run(pathBinary, process.argv.slice(2));
|
|
268
|
+
process.exit(code);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const installedPath = await install();
|
|
272
|
+
|
|
273
|
+
if (process.argv.length > 2) {
|
|
274
|
+
const code = await run(installedPath, process.argv.slice(2));
|
|
275
|
+
process.exit(code);
|
|
276
|
+
}
|
|
277
|
+
})();
|
package/cli.cjs
DELETED
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// SolForge CLI bootstrapper
|
|
3
|
-
// - Prefers a prebuilt vendor binary (downloaded via postinstall or on first run)
|
|
4
|
-
// - Falls back to Bun-based TS entry if available
|
|
5
|
-
|
|
6
|
-
const fs = require("node:fs");
|
|
7
|
-
const path = require("node:path");
|
|
8
|
-
const https = require("node:https");
|
|
9
|
-
const { spawn } = require("node:child_process");
|
|
10
|
-
|
|
11
|
-
function pkg() {
|
|
12
|
-
// Resolve package.json next to this file regardless of install location
|
|
13
|
-
const p = path.join(__dirname, "package.json");
|
|
14
|
-
try {
|
|
15
|
-
return require(p);
|
|
16
|
-
} catch {
|
|
17
|
-
return { version: "" };
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function assetName() {
|
|
22
|
-
const p = process.platform;
|
|
23
|
-
const a = process.arch;
|
|
24
|
-
if (p === "darwin" && a === "arm64") return "solforge-darwin-arm64";
|
|
25
|
-
if (p === "darwin" && a === "x64") return "solforge-darwin-x64";
|
|
26
|
-
if (p === "linux" && a === "x64") return "solforge-linux-x64";
|
|
27
|
-
if (p === "linux" && a === "arm64") return "solforge-linux-arm64";
|
|
28
|
-
if (p === "win32" && a === "x64") return "solforge-windows-x64.exe";
|
|
29
|
-
return null;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function vendorPath() {
|
|
33
|
-
const name = assetName();
|
|
34
|
-
if (!name) return null;
|
|
35
|
-
return path.join(__dirname, "vendor", name);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function download(url, outPath) {
|
|
39
|
-
return new Promise((resolve, reject) => {
|
|
40
|
-
const req = https.get(url, (res) => {
|
|
41
|
-
if (
|
|
42
|
-
[301, 302, 307, 308].includes(res.statusCode) &&
|
|
43
|
-
res.headers.location
|
|
44
|
-
) {
|
|
45
|
-
return resolve(download(res.headers.location, outPath));
|
|
46
|
-
}
|
|
47
|
-
if (res.statusCode !== 200) {
|
|
48
|
-
return reject(new Error(`HTTP ${res.statusCode}`));
|
|
49
|
-
}
|
|
50
|
-
const file = fs.createWriteStream(outPath, {
|
|
51
|
-
mode: process.platform === "win32" ? undefined : 0o755,
|
|
52
|
-
});
|
|
53
|
-
res.pipe(file);
|
|
54
|
-
file.on("finish", () => file.close(() => resolve()));
|
|
55
|
-
file.on("error", reject);
|
|
56
|
-
});
|
|
57
|
-
req.on("error", reject);
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
async function ensureBinary() {
|
|
62
|
-
const vp = vendorPath();
|
|
63
|
-
if (!vp) return null;
|
|
64
|
-
if (fs.existsSync(vp)) return vp;
|
|
65
|
-
|
|
66
|
-
// Respect opt-out
|
|
67
|
-
if (
|
|
68
|
-
String(process.env.SOLFORGE_SKIP_DOWNLOAD || "").toLowerCase() === "true"
|
|
69
|
-
) {
|
|
70
|
-
return null;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const { version, repository } = pkg();
|
|
74
|
-
const repo =
|
|
75
|
-
process.env.SOLFORGE_REPO ||
|
|
76
|
-
(repository &&
|
|
77
|
-
(typeof repository === "string"
|
|
78
|
-
? repository.replace(/^github:/, "")
|
|
79
|
-
: repository.url &&
|
|
80
|
-
(repository.url.match(/github\.com[:/](.+?)\.git$/) || [])[1])) ||
|
|
81
|
-
"nitishxyz/solforge";
|
|
82
|
-
if (!version) return null;
|
|
83
|
-
const asset = path.basename(vp);
|
|
84
|
-
const url = `https://github.com/${repo}/releases/download/v${version}/${asset}`;
|
|
85
|
-
|
|
86
|
-
try {
|
|
87
|
-
fs.mkdirSync(path.dirname(vp), { recursive: true });
|
|
88
|
-
await download(url, vp);
|
|
89
|
-
if (process.platform !== "win32") {
|
|
90
|
-
try {
|
|
91
|
-
fs.chmodSync(vp, 0o755);
|
|
92
|
-
} catch {}
|
|
93
|
-
}
|
|
94
|
-
return fs.existsSync(vp) ? vp : null;
|
|
95
|
-
} catch {
|
|
96
|
-
return null;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function run(cmd, args) {
|
|
101
|
-
return new Promise((resolve) => {
|
|
102
|
-
const child = spawn(cmd, args, { stdio: "inherit" });
|
|
103
|
-
child.on("exit", (code) => resolve(typeof code === "number" ? code : 0));
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
(async () => {
|
|
108
|
-
// Fast path for --version/--help without booting the app
|
|
109
|
-
const args = process.argv.slice(2);
|
|
110
|
-
if (
|
|
111
|
-
args.includes("-v") ||
|
|
112
|
-
args.includes("--version") ||
|
|
113
|
-
args[0] === "version"
|
|
114
|
-
) {
|
|
115
|
-
console.log(pkg().version || "");
|
|
116
|
-
process.exit(0);
|
|
117
|
-
}
|
|
118
|
-
if (args.includes("-h") || args.includes("--help") || args[0] === "help") {
|
|
119
|
-
console.log(`
|
|
120
|
-
solforge <command>
|
|
121
|
-
|
|
122
|
-
Commands:
|
|
123
|
-
(no command) Run setup then start RPC & WS servers
|
|
124
|
-
rpc start Start RPC & WS servers
|
|
125
|
-
start Alias for 'rpc start'
|
|
126
|
-
config init Create sf.config.json in CWD
|
|
127
|
-
config get <key> Read a config value (dot path)
|
|
128
|
-
config set <k> <v> Set a config value
|
|
129
|
-
airdrop --to <pubkey> --sol <amount> Airdrop SOL via RPC faucet
|
|
130
|
-
mint Interactive: pick mint, receiver, amount
|
|
131
|
-
token clone <mint> Clone SPL token mint + accounts
|
|
132
|
-
program clone <programId> Clone program code (and optionally accounts)
|
|
133
|
-
program accounts clone <programId> Clone accounts owned by program
|
|
134
|
-
|
|
135
|
-
Options:
|
|
136
|
-
-h, --help Show help
|
|
137
|
-
-v, --version Show version
|
|
138
|
-
--network Bind servers to 0.0.0.0 (LAN access)
|
|
139
|
-
-y, --ci Non-interactive; auto-accept prompts (use existing config)
|
|
140
|
-
`);
|
|
141
|
-
process.exit(0);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
const vp = await ensureBinary();
|
|
145
|
-
if (vp) {
|
|
146
|
-
const code = await run(vp, process.argv.slice(2));
|
|
147
|
-
process.exit(code);
|
|
148
|
-
}
|
|
149
|
-
// Fallback: try to run TS entry via Bun
|
|
150
|
-
const bun = process.env.SOLFORGE_BUN || "bun";
|
|
151
|
-
const entry = path.join(__dirname, "src", "cli", "main.ts");
|
|
152
|
-
const code = await run(bun, [entry, ...process.argv.slice(2)]);
|
|
153
|
-
if (code !== 0) {
|
|
154
|
-
console.error(
|
|
155
|
-
"solforge: failed to run binary and Bun fallback. Install Bun or ensure a release asset exists.",
|
|
156
|
-
);
|
|
157
|
-
}
|
|
158
|
-
process.exit(code);
|
|
159
|
-
})();
|
package/scripts/postinstall.cjs
DELETED
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/*
|
|
3
|
-
SolForge postinstall: fetch the platform-specific prebuilt binary from GitHub Releases.
|
|
4
|
-
- Skips if SOLFORGE_SKIP_DOWNLOAD=true
|
|
5
|
-
- Falls back silently on errors (CLI will still work via Bun if installed)
|
|
6
|
-
*/
|
|
7
|
-
const fs = require("node:fs");
|
|
8
|
-
const path = require("node:path");
|
|
9
|
-
const https = require("node:https");
|
|
10
|
-
|
|
11
|
-
function log(msg) {
|
|
12
|
-
console.log(`[solforge] ${msg}`);
|
|
13
|
-
}
|
|
14
|
-
function warn(msg) {
|
|
15
|
-
console.warn(`[solforge] ${msg}`);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
if (String(process.env.SOLFORGE_SKIP_DOWNLOAD || "").toLowerCase() === "true") {
|
|
19
|
-
log("Skipping binary download due to SOLFORGE_SKIP_DOWNLOAD=true");
|
|
20
|
-
process.exit(0);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function assetName() {
|
|
24
|
-
const p = process.platform;
|
|
25
|
-
const a = process.arch;
|
|
26
|
-
if (p === "darwin" && a === "arm64") return "solforge-darwin-arm64";
|
|
27
|
-
if (p === "darwin" && a === "x64") return "solforge-darwin-x64";
|
|
28
|
-
if (p === "linux" && a === "x64") return "solforge-linux-x64";
|
|
29
|
-
if (p === "linux" && a === "arm64") return "solforge-linux-arm64";
|
|
30
|
-
if (p === "win32" && a === "x64") return "solforge-windows-x64.exe";
|
|
31
|
-
return null;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function getRepo() {
|
|
35
|
-
try {
|
|
36
|
-
const pkg = require(path.join(__dirname, "..", "package.json"));
|
|
37
|
-
if (pkg.repository) {
|
|
38
|
-
if (typeof pkg.repository === "string")
|
|
39
|
-
return pkg.repository.replace(/^github:/, "");
|
|
40
|
-
if (pkg.repository.url) {
|
|
41
|
-
const m = pkg.repository.url.match(/github\.com[:/](.+?)\.git$/);
|
|
42
|
-
if (m) return m[1];
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
} catch {}
|
|
46
|
-
return process.env.SOLFORGE_REPO || "nitishxyz/solforge";
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function getVersion() {
|
|
50
|
-
try {
|
|
51
|
-
const pkg = require(path.join(__dirname, "..", "package.json"));
|
|
52
|
-
return pkg.version;
|
|
53
|
-
} catch {
|
|
54
|
-
return process.env.npm_package_version || "";
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const name = assetName();
|
|
59
|
-
if (!name) {
|
|
60
|
-
warn(`No prebuilt binary for ${process.platform}/${process.arch}; skipping`);
|
|
61
|
-
process.exit(0);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const version = getVersion();
|
|
65
|
-
if (!version) {
|
|
66
|
-
warn("Unable to determine package version; skipping binary download");
|
|
67
|
-
process.exit(0);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const repo = getRepo();
|
|
71
|
-
const url = `https://github.com/${repo}/releases/download/v${version}/${name}`;
|
|
72
|
-
|
|
73
|
-
const vendorDir = path.join(__dirname, "..", "vendor");
|
|
74
|
-
const outPath = path.join(vendorDir, name);
|
|
75
|
-
|
|
76
|
-
if (fs.existsSync(outPath)) {
|
|
77
|
-
log(`Binary already present at vendor/${name}`);
|
|
78
|
-
process.exit(0);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
fs.mkdirSync(vendorDir, { recursive: true });
|
|
82
|
-
|
|
83
|
-
function download(to, from, cb, redirects = 0) {
|
|
84
|
-
const req = https.get(from, (res) => {
|
|
85
|
-
if (
|
|
86
|
-
[301, 302, 307, 308].includes(res.statusCode) &&
|
|
87
|
-
res.headers.location &&
|
|
88
|
-
redirects < 5
|
|
89
|
-
) {
|
|
90
|
-
return download(to, res.headers.location, cb, redirects + 1);
|
|
91
|
-
}
|
|
92
|
-
if (res.statusCode !== 200) {
|
|
93
|
-
return cb(new Error(`HTTP ${res.statusCode} for ${from}`));
|
|
94
|
-
}
|
|
95
|
-
const file = fs.createWriteStream(to, { mode: 0o755 });
|
|
96
|
-
res.pipe(file);
|
|
97
|
-
file.on("finish", () => file.close(cb));
|
|
98
|
-
});
|
|
99
|
-
req.on("error", (err) => cb(err));
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
log(`Fetching ${name} for v${version}...`);
|
|
103
|
-
download(outPath, url, (err) => {
|
|
104
|
-
if (err) {
|
|
105
|
-
warn(`Could not download prebuilt binary: ${err.message}`);
|
|
106
|
-
warn("CLI will fall back to running via Bun if available.");
|
|
107
|
-
try {
|
|
108
|
-
fs.unlinkSync(outPath);
|
|
109
|
-
} catch {}
|
|
110
|
-
process.exit(0);
|
|
111
|
-
}
|
|
112
|
-
if (process.platform !== "win32") {
|
|
113
|
-
try {
|
|
114
|
-
fs.chmodSync(outPath, 0o755);
|
|
115
|
-
} catch {}
|
|
116
|
-
}
|
|
117
|
-
log(`Installed vendor/${name}`);
|
|
118
|
-
});
|