@xaidenlabs/uso 1.1.69 → 1.1.71
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 +1 -1
- package/src/commands/address.js +32 -0
- package/src/commands/init.js +218 -209
- package/src/commands/uninstall.js +27 -0
- package/src/platforms/wsl.js +43 -3
- package/src/utils/wallet.js +66 -22
package/package.json
CHANGED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const shell = require('shelljs');
|
|
2
|
+
const os = require('os');
|
|
3
|
+
const { log } = require('../utils/logger');
|
|
4
|
+
const { isStealthMode } = require('../utils/stealth');
|
|
5
|
+
const { runWsl } = require('../utils/wsl-bridge');
|
|
6
|
+
|
|
7
|
+
const address = async () => {
|
|
8
|
+
const stealth = isStealthMode();
|
|
9
|
+
|
|
10
|
+
try {
|
|
11
|
+
let result;
|
|
12
|
+
|
|
13
|
+
if (stealth.enabled) {
|
|
14
|
+
// Run solana address inside WSL
|
|
15
|
+
result = runWsl('solana address', { distro: stealth.distro });
|
|
16
|
+
} else {
|
|
17
|
+
// Run solana address natively
|
|
18
|
+
result = shell.exec('solana address', { silent: true });
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (result.code === 0) {
|
|
22
|
+
log.success(result.stdout.trim());
|
|
23
|
+
} else {
|
|
24
|
+
const errorMsg = result.stderr || result.stdout;
|
|
25
|
+
log.error(errorMsg.trim());
|
|
26
|
+
}
|
|
27
|
+
} catch (e) {
|
|
28
|
+
log.error(`Error getting wallet address: ${e.message}`);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
module.exports = { address };
|
package/src/commands/init.js
CHANGED
|
@@ -1,241 +1,250 @@
|
|
|
1
|
-
const os = require(
|
|
2
|
-
const shell = require(
|
|
3
|
-
const { log, spinner } = require(
|
|
4
|
-
const { installWindows } = require(
|
|
5
|
-
const { installMacOS } = require(
|
|
6
|
-
const { installLinux } = require(
|
|
7
|
-
const { getCargoBinPath } = require(
|
|
8
|
-
const { checkRust, checkSolana, checkAnchor } = require(
|
|
9
|
-
const { ensureWalletInteractive } = require(
|
|
10
|
-
const path = require(
|
|
11
|
-
const fs = require(
|
|
12
|
-
|
|
13
|
-
const { installWsl, installWslFeature } = require(
|
|
1
|
+
const os = require("os");
|
|
2
|
+
const shell = require("shelljs");
|
|
3
|
+
const { log, spinner } = require("../utils/logger");
|
|
4
|
+
const { installWindows } = require("../platforms/windows");
|
|
5
|
+
const { installMacOS } = require("../platforms/macos");
|
|
6
|
+
const { installLinux } = require("../platforms/linux");
|
|
7
|
+
const { getCargoBinPath } = require("../utils/paths");
|
|
8
|
+
const { checkRust, checkSolana, checkAnchor } = require("./doctor");
|
|
9
|
+
const { ensureWalletInteractive } = require("../utils/wallet");
|
|
10
|
+
const path = require("path");
|
|
11
|
+
const fs = require("fs");
|
|
12
|
+
|
|
13
|
+
const { installWsl, installWslFeature } = require("../platforms/wsl");
|
|
14
14
|
|
|
15
15
|
const init = async (component, options) => {
|
|
16
|
-
|
|
16
|
+
const platform = os.platform();
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
// --- On Windows, ALWAYS use the WSL path ---
|
|
19
|
+
if (platform === "win32") {
|
|
20
|
+
const hasWslBinary = !!shell.which("wsl");
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
22
|
+
if (!hasWslBinary) {
|
|
23
|
+
// WSL is not installed at all — request admin elevation to enable the feature
|
|
24
|
+
log.header("🐧 Windows Subsystem for Linux (WSL) not found.");
|
|
25
|
+
log.info("🛡️ Requesting administrator permission to install WSL...");
|
|
26
|
+
log.info(
|
|
27
|
+
"👉 Please click 'Yes' in the UAC popup that appears to allow this.",
|
|
28
|
+
);
|
|
29
|
+
console.log("");
|
|
28
30
|
|
|
29
|
-
|
|
31
|
+
const wslInstalled = await installWslFeature();
|
|
30
32
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// If wsl.exe is now available, continue straight into the Ubuntu setup.
|
|
37
|
-
// On some machines this still needs a reboot, but we let the distro phase
|
|
38
|
-
// run immediately so setup can continue as far as the system allows.
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// WSL binary is present — run the full WSL toolchain install
|
|
42
|
-
await installWsl();
|
|
33
|
+
if (!wslInstalled && !shell.which("wsl")) {
|
|
34
|
+
// installWslFeature already printed the relevant error/reboot message
|
|
43
35
|
return;
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
if (component) {
|
|
47
|
-
component = component.toLowerCase();
|
|
48
|
-
log.info(`🎯 Targeted installation: ${component}`);
|
|
49
|
-
|
|
50
|
-
if (component === 'rust') {
|
|
51
|
-
if (checkRust(true)) {
|
|
52
|
-
log.success("✅ Rust is already installed.");
|
|
53
|
-
return;
|
|
54
|
-
}
|
|
55
|
-
log.info("🦀 Installing Rust...");
|
|
56
|
-
let success = false;
|
|
57
|
-
if (platform === 'win32') success = await installWindows(true, false);
|
|
58
|
-
else if (platform === 'darwin') success = await installMacOS(true, false);
|
|
59
|
-
else success = await installLinux(true, false);
|
|
60
|
-
|
|
61
|
-
if (success) log.success("✅ Rust installed successfully.");
|
|
62
|
-
else log.error("❌ Rust installation failed.");
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (component === 'solana') {
|
|
67
|
-
if (checkSolana(true)) {
|
|
68
|
-
log.success("✅ Solana CLI is already installed.");
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
log.info("☀️ Installing Solana CLI...");
|
|
72
|
-
let success = false;
|
|
73
|
-
if (platform === 'win32') success = await installWindows(false, true);
|
|
74
|
-
else if (platform === 'darwin') success = await installMacOS(false, true);
|
|
75
|
-
else success = await installLinux(false, true);
|
|
76
|
-
|
|
77
|
-
if (success) log.success("✅ Solana CLI installed successfully.");
|
|
78
|
-
else log.error("❌ Solana CLI installation failed.");
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
36
|
+
}
|
|
81
37
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
// Fall through to Anchor installation logic below, but skip others
|
|
88
|
-
} else if (component !== 'anchor') { // If it's not rust, solana, or anchor
|
|
89
|
-
log.error(`❌ Unknown component: ${component}. Available: rust, solana, anchor`);
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
38
|
+
// If wsl.exe is now available, continue straight into the Ubuntu setup.
|
|
39
|
+
// On some machines this still needs a reboot, but we let the distro phase
|
|
40
|
+
// run immediately so setup can continue as far as the system allows.
|
|
92
41
|
}
|
|
93
42
|
|
|
94
|
-
//
|
|
43
|
+
// WSL binary is present — run the full WSL toolchain install
|
|
44
|
+
await installWsl();
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
95
47
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
const hasAnchor = checkAnchor(true);
|
|
48
|
+
if (component) {
|
|
49
|
+
component = component.toLowerCase();
|
|
50
|
+
log.info(`🎯 Targeted installation: ${component}`);
|
|
100
51
|
|
|
101
|
-
if (component ===
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
52
|
+
if (component === "rust") {
|
|
53
|
+
if (checkRust(true)) {
|
|
54
|
+
log.success("✅ Rust is already installed.");
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
log.info("🦀 Installing Rust...");
|
|
58
|
+
let success = false;
|
|
59
|
+
if (platform === "win32") success = await installWindows(true, false);
|
|
60
|
+
else if (platform === "darwin") success = await installMacOS(true, false);
|
|
61
|
+
else success = await installLinux(true, false);
|
|
62
|
+
|
|
63
|
+
if (success) log.success("✅ Rust installed successfully.");
|
|
64
|
+
else log.error("❌ Rust installation failed.");
|
|
65
|
+
return;
|
|
110
66
|
}
|
|
111
67
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
log.success("
|
|
115
|
-
await ensureWalletInteractive();
|
|
68
|
+
if (component === "solana") {
|
|
69
|
+
if (checkSolana(true)) {
|
|
70
|
+
log.success("✅ Solana CLI is already installed.");
|
|
116
71
|
return;
|
|
72
|
+
}
|
|
73
|
+
log.info("☀️ Installing Solana CLI...");
|
|
74
|
+
let success = false;
|
|
75
|
+
if (platform === "win32") success = await installWindows(false, true);
|
|
76
|
+
else if (platform === "darwin") success = await installMacOS(false, true);
|
|
77
|
+
else success = await installLinux(false, true);
|
|
78
|
+
|
|
79
|
+
if (success) log.success("✅ Solana CLI installed successfully.");
|
|
80
|
+
else log.error("❌ Solana CLI installation failed.");
|
|
81
|
+
return;
|
|
117
82
|
}
|
|
118
83
|
|
|
119
|
-
if (
|
|
120
|
-
|
|
121
|
-
log.
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
if (platform === 'win32') {
|
|
133
|
-
spin.stop();
|
|
134
|
-
success = await installWindows(installRust, installSolana);
|
|
135
|
-
} else if (platform === 'darwin') {
|
|
136
|
-
spin.stop();
|
|
137
|
-
success = await installMacOS(installRust, installSolana);
|
|
138
|
-
} else {
|
|
139
|
-
spin.stop();
|
|
140
|
-
success = await installLinux(installRust, installSolana);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
if (!success) {
|
|
144
|
-
log.error("❌ Platform-specific installation failed.");
|
|
145
|
-
return;
|
|
146
|
-
}
|
|
147
|
-
} catch (e) {
|
|
148
|
-
spin.stop();
|
|
149
|
-
log.error(e.message);
|
|
150
|
-
return;
|
|
151
|
-
}
|
|
84
|
+
if (component === "anchor") {
|
|
85
|
+
if (checkAnchor(true)) {
|
|
86
|
+
log.success("✅ Anchor is already installed.");
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
// Fall through to Anchor installation logic below, but skip others
|
|
90
|
+
} else if (component !== "anchor") {
|
|
91
|
+
// If it's not rust, solana, or anchor
|
|
92
|
+
log.error(
|
|
93
|
+
`❌ Unknown component: ${component}. Available: rust, solana, anchor`,
|
|
94
|
+
);
|
|
95
|
+
return;
|
|
152
96
|
}
|
|
97
|
+
}
|
|
153
98
|
|
|
154
|
-
|
|
155
|
-
if (!hasAnchor && (!component || component === 'anchor')) {
|
|
156
|
-
log.info("⚓ Installing Anchor Framework...");
|
|
99
|
+
// --- FULL INSTALLATION / ANCHOR ONLY FLOW ---
|
|
157
100
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
101
|
+
// If authenticating for just Anchor, we assume Rust/Solana are prerequisites or we skip them
|
|
102
|
+
let installRust = !checkRust(true);
|
|
103
|
+
let installSolana = !checkSolana(true);
|
|
104
|
+
const hasAnchor = checkAnchor(true);
|
|
161
105
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
106
|
+
if (component === "anchor") {
|
|
107
|
+
// ensuring prerequisites for anchor
|
|
108
|
+
if (installRust) {
|
|
109
|
+
log.warn("⚠️ Rust is required for Anchor but not installed.");
|
|
110
|
+
// asking or just failing? For granular, let's just fail or warn.
|
|
111
|
+
// But let's proceed to install Anchor logic which handles cargo check
|
|
112
|
+
}
|
|
113
|
+
installRust = false; // Don't run platform installers for these
|
|
114
|
+
installSolana = false;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Validating state for full install
|
|
118
|
+
if (!component && !installRust && !installSolana && hasAnchor) {
|
|
119
|
+
log.success("🎉 Everything is already installed!");
|
|
120
|
+
await ensureWalletInteractive();
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (!component) {
|
|
125
|
+
log.header("🔍 Checking current environment state...");
|
|
126
|
+
log.info(`\n📦 Missing components:`);
|
|
127
|
+
if (installRust) log.error(" - Rust");
|
|
128
|
+
if (installSolana) log.error(" - Solana CLI");
|
|
129
|
+
if (!hasAnchor) log.error(" - Anchor");
|
|
130
|
+
console.log("");
|
|
131
|
+
|
|
132
|
+
const spin = spinner("Starting Installation...").start();
|
|
133
|
+
|
|
134
|
+
try {
|
|
135
|
+
let success = false;
|
|
136
|
+
|
|
137
|
+
if (platform === "win32") {
|
|
138
|
+
spin.stop();
|
|
139
|
+
success = await installWindows(installRust, installSolana);
|
|
140
|
+
} else if (platform === "darwin") {
|
|
141
|
+
spin.stop();
|
|
142
|
+
success = await installMacOS(installRust, installSolana);
|
|
143
|
+
} else {
|
|
144
|
+
spin.stop();
|
|
145
|
+
success = await installLinux(installRust, installSolana);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (!success) {
|
|
149
|
+
log.error("❌ Platform-specific installation failed.");
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
} catch (e) {
|
|
153
|
+
spin.stop();
|
|
154
|
+
log.error(e.message);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Install Anchor (Universal) - Runs if component='anchor' OR full install
|
|
160
|
+
if (!hasAnchor && (!component || component === "anchor")) {
|
|
161
|
+
log.info("⚓ Installing Anchor Framework...");
|
|
162
|
+
|
|
163
|
+
const cargoBin = getCargoBinPath();
|
|
164
|
+
const cargoExe = platform === "win32" ? "cargo.exe" : "cargo";
|
|
165
|
+
const avmExe = platform === "win32" ? "avm.exe" : "avm";
|
|
166
|
+
|
|
167
|
+
// Resolve cargo command
|
|
168
|
+
let cargoCmd = cargoExe;
|
|
169
|
+
if (fs.existsSync(path.join(cargoBin, cargoExe))) {
|
|
170
|
+
cargoCmd = `"${path.join(cargoBin, cargoExe)}"`;
|
|
171
|
+
} else if (!installRust && checkRust(true)) {
|
|
172
|
+
cargoCmd = "cargo";
|
|
173
|
+
}
|
|
169
174
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
log.warn("⚠️ AVM installation failed. Trying fallback...");
|
|
205
|
-
fallbackDirectInstall(cargoCmd);
|
|
206
|
-
}
|
|
207
|
-
} else {
|
|
208
|
-
shell.exec(`${avmCmd} use latest`);
|
|
209
|
-
log.success("✅ Anchor installed.");
|
|
210
|
-
}
|
|
175
|
+
log.subHeader(`Using cargo: ${cargoCmd}`);
|
|
176
|
+
|
|
177
|
+
// Try installing AVM first (Preferred)
|
|
178
|
+
log.info(" Attempting AVM install...");
|
|
179
|
+
const avmInstall = shell.exec(
|
|
180
|
+
`${cargoCmd} install --git https://github.com/coral-xyz/anchor avm --locked --force`,
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
if (avmInstall.code === 0) {
|
|
184
|
+
// Use AVM
|
|
185
|
+
let avmCmd = avmExe;
|
|
186
|
+
if (fs.existsSync(path.join(cargoBin, avmExe))) {
|
|
187
|
+
avmCmd = `"${path.join(cargoBin, avmExe)}"`;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
log.subHeader(`Using avm: ${avmCmd}`);
|
|
191
|
+
const avmUse = shell.exec(`${avmCmd} install latest`);
|
|
192
|
+
|
|
193
|
+
// Detect Permission Error for AVM
|
|
194
|
+
if (avmUse.code !== 0) {
|
|
195
|
+
const output = avmUse.stderr + avmUse.stdout;
|
|
196
|
+
if (output.includes("os error 1314") && platform === "win32") {
|
|
197
|
+
log.warn("⚠️ AVM Permission denied (Symlink creation failed).");
|
|
198
|
+
log.info("🛡️ Triggering Run as Administrator (UAC) for Anchor...");
|
|
199
|
+
const absAvmPath = path.join(cargoBin, avmExe);
|
|
200
|
+
const elevateCmd = `powershell -Command "Start-Process -FilePath '${absAvmPath}' -ArgumentList 'install latest' -Verb RunAs -Wait; Start-Process -FilePath '${absAvmPath}' -ArgumentList 'use latest' -Verb RunAs -Wait"`;
|
|
201
|
+
const elevatedRun = shell.exec(elevateCmd);
|
|
202
|
+
|
|
203
|
+
if (elevatedRun.code === 0) {
|
|
204
|
+
log.success("✅ Anchor installed (Elevated).");
|
|
205
|
+
} else {
|
|
206
|
+
log.error("❌ Elevated installation failed. Trying fallback...");
|
|
207
|
+
fallbackDirectInstall(cargoCmd);
|
|
208
|
+
}
|
|
211
209
|
} else {
|
|
212
|
-
|
|
213
|
-
|
|
210
|
+
log.warn("⚠️ AVM installation failed. Trying fallback...");
|
|
211
|
+
fallbackDirectInstall(cargoCmd);
|
|
214
212
|
}
|
|
215
|
-
|
|
216
|
-
|
|
213
|
+
} else {
|
|
214
|
+
shell.exec(`${avmCmd} use latest`);
|
|
215
|
+
log.success("✅ Anchor installed.");
|
|
216
|
+
}
|
|
217
|
+
} else {
|
|
218
|
+
log.error("❌ Failed to install AVM via Cargo.");
|
|
219
|
+
return;
|
|
217
220
|
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
221
|
+
} else if (component === "anchor" && hasAnchor) {
|
|
222
|
+
log.success("✅ Anchor is already installed.");
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (!component) {
|
|
226
|
+
log.header("\n✅ Uso Setup Complete!");
|
|
227
|
+
await ensureWalletInteractive();
|
|
228
|
+
|
|
229
|
+
if (installRust || installSolana || !hasAnchor) {
|
|
230
|
+
log.warn(
|
|
231
|
+
"👉 Please RESTART your terminal/VS Code to ensure all PATH variables are updated.",
|
|
232
|
+
);
|
|
228
233
|
}
|
|
234
|
+
log.info("🚀 Try running: uso verify");
|
|
235
|
+
}
|
|
229
236
|
};
|
|
230
237
|
|
|
231
238
|
const fallbackDirectInstall = (cargoCmd) => {
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
+
log.info("👉 Falling back to direct 'anchor-cli' installation...");
|
|
240
|
+
const directInstall = shell.exec(
|
|
241
|
+
`${cargoCmd} install --git https://github.com/coral-xyz/anchor anchor-cli --locked --force`,
|
|
242
|
+
);
|
|
243
|
+
if (directInstall.code !== 0) {
|
|
244
|
+
log.error("❌ Failed to install Anchor via fallback method.");
|
|
245
|
+
} else {
|
|
246
|
+
log.success("✅ Anchor installed (Direct Cargo).");
|
|
247
|
+
}
|
|
239
248
|
};
|
|
240
249
|
|
|
241
250
|
module.exports = { init };
|
|
@@ -331,6 +331,33 @@ const uninstall = async (component) => {
|
|
|
331
331
|
}
|
|
332
332
|
}
|
|
333
333
|
|
|
334
|
+
// 3.5 Remove WSL Distro (if stealth mode is active)
|
|
335
|
+
if (stealth.enabled && os.platform() === "win32") {
|
|
336
|
+
const removeWslDistro = await askQuestion(
|
|
337
|
+
"\n🐧 Remove WSL Ubuntu distro completely? (y/N): ",
|
|
338
|
+
);
|
|
339
|
+
if (removeWslDistro.toLowerCase() === "y") {
|
|
340
|
+
log.warn(`⚠️ This will completely remove the ${stealth.distro} distro and all its data.`);
|
|
341
|
+
const confirmWslRemoval = await askQuestion(
|
|
342
|
+
"💥 Type 'REMOVE WSL' to confirm distro removal: ",
|
|
343
|
+
);
|
|
344
|
+
if (confirmWslRemoval === "REMOVE WSL") {
|
|
345
|
+
log.info(`Unregistering ${stealth.distro} distro...`);
|
|
346
|
+
const unregisterCmd = `wsl --unregister ${stealth.distro}`;
|
|
347
|
+
const result = runOrElevate(
|
|
348
|
+
unregisterCmd,
|
|
349
|
+
`Unregister WSL distro ${stealth.distro}`,
|
|
350
|
+
{ enabled: false, distro: stealth.distro },
|
|
351
|
+
);
|
|
352
|
+
if (result) {
|
|
353
|
+
log.success(`✅ ${stealth.distro} distro removed.`);
|
|
354
|
+
}
|
|
355
|
+
} else {
|
|
356
|
+
log.info("WSL distro removal cancelled.");
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
334
361
|
// 4. WALLET REMOVAL (DANGER)
|
|
335
362
|
const walletPath = path.join(os.homedir(), ".config", "solana", "id.json");
|
|
336
363
|
const wslWalletPath = "$HOME/.config/solana/id.json";
|
package/src/platforms/wsl.js
CHANGED
|
@@ -281,14 +281,54 @@ source $HOME/.cargo/env 2>/dev/null || true
|
|
|
281
281
|
export PATH="$HOME/.local/share/solana/install/active_release/bin:$PATH"
|
|
282
282
|
if ! command -v solana &> /dev/null; then
|
|
283
283
|
echo "☀️ Installing Solana CLI..."
|
|
284
|
-
|
|
284
|
+
|
|
285
|
+
# Helper to download with retries and proper SSL handling
|
|
286
|
+
install_solana_with_retry() {
|
|
287
|
+
local url="$1"
|
|
288
|
+
local description="$2"
|
|
289
|
+
local max_attempts=3
|
|
290
|
+
local attempt=1
|
|
291
|
+
|
|
292
|
+
while [ $attempt -le $max_attempts ]; do
|
|
293
|
+
if [ $attempt -gt 1 ]; then
|
|
294
|
+
echo " Retry attempt $attempt/$max_attempts..."
|
|
295
|
+
sleep 2
|
|
296
|
+
fi
|
|
297
|
+
|
|
298
|
+
# Download installer script with SSL options and timeout
|
|
299
|
+
if curl --proto '=https' --tlsv1.2 -sSf --max-time 60 --connect-timeout 10 \
|
|
300
|
+
--cacert /etc/ssl/certs/ca-certificates.crt \
|
|
301
|
+
"$url" > /tmp/solana_install.sh 2>/dev/null; then
|
|
302
|
+
# Execute the downloaded script
|
|
303
|
+
if bash /tmp/solana_install.sh; then
|
|
304
|
+
rm -f /tmp/solana_install.sh
|
|
305
|
+
return 0
|
|
306
|
+
fi
|
|
307
|
+
fi
|
|
308
|
+
|
|
309
|
+
attempt=$((attempt + 1))
|
|
310
|
+
done
|
|
311
|
+
|
|
312
|
+
rm -f /tmp/solana_install.sh
|
|
313
|
+
return 1
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
solana_installed=0
|
|
317
|
+
|
|
318
|
+
# Try official Solana release
|
|
319
|
+
if install_solana_with_retry "https://release.solana.com/stable/install" "Solana"; then
|
|
320
|
+
solana_installed=1
|
|
285
321
|
echo "✅ Solana installed."
|
|
286
|
-
|
|
322
|
+
# Fallback to Agave (community-maintained)
|
|
323
|
+
elif install_solana_with_retry "https://release.anza.xyz/stable/install" "Agave"; then
|
|
324
|
+
solana_installed=1
|
|
287
325
|
echo "✅ Solana installed (via Agave)."
|
|
288
326
|
else
|
|
289
327
|
FAILURES="$FAILURES solana"
|
|
290
|
-
echo "⚠️ Solana install
|
|
328
|
+
echo "⚠️ Solana install failed after retries. Network or certificate issue detected."
|
|
329
|
+
echo " Run 'uso init' again to retry."
|
|
291
330
|
fi
|
|
331
|
+
|
|
292
332
|
export PATH="$HOME/.local/share/solana/install/active_release/bin:$PATH"
|
|
293
333
|
else
|
|
294
334
|
echo "✅ Solana already installed."
|
package/src/utils/wallet.js
CHANGED
|
@@ -4,6 +4,8 @@ const path = require('path');
|
|
|
4
4
|
const fs = require('fs');
|
|
5
5
|
const readline = require('readline');
|
|
6
6
|
const { log } = require('./logger');
|
|
7
|
+
const { isStealthMode } = require('./stealth');
|
|
8
|
+
const { runWsl } = require('./wsl-bridge');
|
|
7
9
|
|
|
8
10
|
const resolveSolanaKeygen = () => {
|
|
9
11
|
// 1. Try PATH first
|
|
@@ -25,12 +27,31 @@ const resolveSolanaKeygen = () => {
|
|
|
25
27
|
* Returns true if wallet exists (or was created), false if user declined.
|
|
26
28
|
*/
|
|
27
29
|
const ensureWalletInteractive = async () => {
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
+
const stealth = isStealthMode();
|
|
31
|
+
|
|
32
|
+
// When in stealth mode, wallet is in WSL home
|
|
33
|
+
let walletDir, walletPath;
|
|
34
|
+
if (stealth.enabled) {
|
|
35
|
+
walletDir = '$HOME/.config/solana';
|
|
36
|
+
walletPath = '$HOME/.config/solana/id.json';
|
|
37
|
+
} else {
|
|
38
|
+
walletDir = path.join(os.homedir(), '.config', 'solana');
|
|
39
|
+
walletPath = path.join(walletDir, 'id.json');
|
|
40
|
+
}
|
|
30
41
|
|
|
31
|
-
if
|
|
32
|
-
|
|
33
|
-
|
|
42
|
+
// Check if wallet exists
|
|
43
|
+
if (stealth.enabled) {
|
|
44
|
+
// Check inside WSL
|
|
45
|
+
const checkWallet = runWsl('test -f $HOME/.config/solana/id.json && echo "exists"', { distro: stealth.distro });
|
|
46
|
+
if (checkWallet.code === 0 && checkWallet.stdout.includes('exists')) {
|
|
47
|
+
log.info("🔑 Wallet found (in WSL).");
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
} else {
|
|
51
|
+
if (fs.existsSync(walletPath)) {
|
|
52
|
+
log.info("🔑 Wallet found.");
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
34
55
|
}
|
|
35
56
|
|
|
36
57
|
const rl = readline.createInterface({
|
|
@@ -45,28 +66,51 @@ const ensureWalletInteractive = async () => {
|
|
|
45
66
|
rl.close();
|
|
46
67
|
if (answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes') {
|
|
47
68
|
log.info("🔑 Generating wallet...");
|
|
48
|
-
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
if (stealth.enabled) {
|
|
72
|
+
// Create wallet inside WSL
|
|
73
|
+
const mkdirCmd = 'mkdir -p $HOME/.config/solana';
|
|
74
|
+
runWsl(mkdirCmd, { distro: stealth.distro });
|
|
75
|
+
|
|
76
|
+
// Run solana-keygen inside WSL with interactive mode
|
|
77
|
+
const { spawnSync } = require('child_process');
|
|
78
|
+
const wslCmd = `wsl -d ${stealth.distro} -e bash -c "solana-keygen new --outfile \\$HOME/.config/solana/id.json"`;
|
|
79
|
+
spawnSync('cmd.exe', ['/c', wslCmd], { stdio: 'inherit' });
|
|
80
|
+
|
|
81
|
+
// Verify wallet was created in WSL
|
|
82
|
+
const verifyCmd = runWsl('test -f $HOME/.config/solana/id.json && echo "exists"', { distro: stealth.distro });
|
|
83
|
+
if (verifyCmd.code === 0 && verifyCmd.stdout.includes('exists')) {
|
|
84
|
+
log.success("✅ Wallet generated (in WSL).");
|
|
85
|
+
resolve(true);
|
|
86
|
+
} else {
|
|
87
|
+
log.warn("❌ Creation cancelled or failed.");
|
|
88
|
+
resolve(false);
|
|
89
|
+
}
|
|
90
|
+
} else {
|
|
91
|
+
// Create wallet natively on Windows
|
|
92
|
+
if (!fs.existsSync(walletDir)) fs.mkdirSync(walletDir, { recursive: true });
|
|
49
93
|
|
|
50
|
-
|
|
94
|
+
const keygenCmd = resolveSolanaKeygen();
|
|
51
95
|
|
|
52
|
-
|
|
53
|
-
|
|
96
|
+
// Use spawnSync to allow interactive input (passphrase)
|
|
97
|
+
const { spawnSync } = require('child_process');
|
|
54
98
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
99
|
+
// We need to strip quotes for spawn
|
|
100
|
+
let cmd = keygenCmd;
|
|
101
|
+
if (cmd.startsWith('"') && cmd.endsWith('"')) cmd = cmd.slice(1, -1);
|
|
58
102
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
spawnSync(cmd, ['new', '--outfile', walletPath], { stdio: 'inherit', shell: true });
|
|
103
|
+
// We use 'new' command which might prompt for passphrase
|
|
104
|
+
spawnSync(cmd, ['new', '--outfile', walletPath], { stdio: 'inherit', shell: true });
|
|
62
105
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
106
|
+
if (fs.existsSync(walletPath)) {
|
|
107
|
+
log.success("✅ Wallet generated.");
|
|
108
|
+
resolve(true);
|
|
109
|
+
} else {
|
|
110
|
+
// User might have cancelled via Ctrl+C in the subprocess
|
|
111
|
+
log.warn("❌ Creation cancelled or failed.");
|
|
112
|
+
resolve(false);
|
|
113
|
+
}
|
|
70
114
|
}
|
|
71
115
|
} catch (e) {
|
|
72
116
|
log.error("❌ Failed to generate wallet: " + e.message);
|