@xaidenlabs/uso 1.1.67 → 1.1.69
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 +36 -36
- package/src/commands/doctor.js +202 -126
- package/src/commands/init.js +4 -3
- package/src/commands/uninstall.js +374 -199
- package/src/commands/workflow.js +443 -356
- package/src/platforms/linux.js +1 -1
- package/src/platforms/wsl.js +329 -203
|
@@ -1,240 +1,415 @@
|
|
|
1
|
-
const shell = require(
|
|
2
|
-
const { log, spinner } = require(
|
|
3
|
-
const readline = require(
|
|
4
|
-
const fs = require(
|
|
5
|
-
const path = require(
|
|
6
|
-
const os = require(
|
|
1
|
+
const shell = require("shelljs");
|
|
2
|
+
const { log, spinner } = require("../utils/logger");
|
|
3
|
+
const readline = require("readline");
|
|
4
|
+
const fs = require("fs");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
const os = require("os");
|
|
7
|
+
const { isStealthMode } = require("../utils/stealth");
|
|
8
|
+
const { runWsl } = require("../utils/wsl-bridge");
|
|
7
9
|
|
|
8
10
|
const askQuestion = (query) => {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
const rl = readline.createInterface({
|
|
12
|
+
input: process.stdin,
|
|
13
|
+
output: process.stdout,
|
|
14
|
+
});
|
|
15
|
+
return new Promise((resolve) =>
|
|
16
|
+
rl.question(query, (ans) => {
|
|
17
|
+
rl.close();
|
|
18
|
+
resolve(ans);
|
|
19
|
+
}),
|
|
20
|
+
);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const getStealthContext = () => {
|
|
24
|
+
if (os.platform() !== "win32") return { enabled: false, distro: "Ubuntu" };
|
|
25
|
+
return isStealthMode();
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const runInStealth = (command, stealth, silent = true) => {
|
|
29
|
+
const envSetup =
|
|
30
|
+
'source $HOME/.cargo/env 2>/dev/null; export PATH="$HOME/.local/share/solana/install/active_release/bin:$HOME/.avm/bin:$PATH"';
|
|
31
|
+
return runWsl(`${envSetup} && ${command}`, {
|
|
32
|
+
distro: stealth.distro,
|
|
33
|
+
execOpts: { silent },
|
|
34
|
+
});
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const commandExists = (command, stealth) => {
|
|
38
|
+
if (stealth.enabled) {
|
|
39
|
+
const result = runInStealth(`command -v ${command}`, stealth, true);
|
|
40
|
+
return result.code === 0;
|
|
41
|
+
}
|
|
42
|
+
return !!shell.which(command);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const wslPathExists = (wslPath, stealth) => {
|
|
46
|
+
const result = runInStealth(`[ -e "${wslPath}" ]`, stealth, true);
|
|
47
|
+
return result.code === 0;
|
|
17
48
|
};
|
|
18
49
|
|
|
19
50
|
/**
|
|
20
51
|
* Runs a command and attempts to elevate privileges if it fails with a permission error.
|
|
21
52
|
*/
|
|
22
|
-
const runOrElevate = (
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const result = shell.exec(command, { silent: true });
|
|
53
|
+
const runOrElevate = (
|
|
54
|
+
command,
|
|
55
|
+
description,
|
|
56
|
+
stealth = { enabled: false, distro: "Ubuntu" },
|
|
57
|
+
) => {
|
|
58
|
+
if (stealth.enabled) {
|
|
59
|
+
const result = runInStealth(command, stealth, true);
|
|
30
60
|
|
|
31
61
|
if (result.code === 0) {
|
|
32
|
-
|
|
33
|
-
|
|
62
|
+
if (result.stdout) console.log(result.stdout);
|
|
63
|
+
return true;
|
|
34
64
|
}
|
|
35
65
|
|
|
36
|
-
|
|
37
|
-
console.
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
// Check for common permission errors
|
|
43
|
-
// "os error 1314" is specific to Windows symlink privilege
|
|
44
|
-
if ((output.includes("os error 1314") || output.includes("EPERM") || output.includes("permission denied")) && os.platform() === 'win32') {
|
|
45
|
-
log.warn(`⚠️ Permission denied during: ${description}`);
|
|
46
|
-
log.info("🛡️ Triggering Run as Administrator (UAC) to retry...");
|
|
66
|
+
if (result.stdout) console.log(result.stdout);
|
|
67
|
+
if (result.stderr) console.error(result.stderr);
|
|
68
|
+
log.error(`❌ Command failed in WSL: ${description}`);
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
47
71
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
72
|
+
// We run without silent:true initially to let the user see output,
|
|
73
|
+
// but detecting the error code is what matters.
|
|
74
|
+
// actually, to detect the specific string "os error 1314", we need to capture output.
|
|
75
|
+
// So we run silently first? Or we just run and if it fails, we assume it *might* be elevation if on Windows?
|
|
76
|
+
// Let's run synchronously and capture output.
|
|
52
77
|
|
|
53
|
-
|
|
78
|
+
const result = shell.exec(command, { silent: true });
|
|
54
79
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
80
|
+
if (result.code === 0) {
|
|
81
|
+
console.log(result.stdout);
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Print the error output to the user
|
|
86
|
+
console.log(result.stdout);
|
|
87
|
+
console.error(result.stderr);
|
|
88
|
+
|
|
89
|
+
const output = result.stderr + result.stdout;
|
|
90
|
+
|
|
91
|
+
// Check for common permission errors
|
|
92
|
+
// "os error 1314" is specific to Windows symlink privilege
|
|
93
|
+
if (
|
|
94
|
+
(output.includes("os error 1314") ||
|
|
95
|
+
output.includes("EPERM") ||
|
|
96
|
+
output.includes("permission denied")) &&
|
|
97
|
+
os.platform() === "win32"
|
|
98
|
+
) {
|
|
99
|
+
log.warn(`⚠️ Permission denied during: ${description}`);
|
|
100
|
+
log.info("🛡️ Triggering Run as Administrator (UAC) to retry...");
|
|
101
|
+
|
|
102
|
+
// Construct PowerShell command to run cmd /c <command> as admin
|
|
103
|
+
// We need to be careful with quoting.
|
|
104
|
+
const escapedCommand = command.replace(/'/g, "''"); // Basic PowerShell escaping for single quotes
|
|
105
|
+
const elevateCmd = `powershell -Command "Start-Process -FilePath 'cmd.exe' -ArgumentList '/c ${escapedCommand}' -Verb RunAs -Wait"`;
|
|
106
|
+
|
|
107
|
+
const elevatedRun = shell.exec(elevateCmd);
|
|
108
|
+
|
|
109
|
+
if (elevatedRun.code === 0) {
|
|
110
|
+
log.success(`✅ ${description} completed (Elevated).`);
|
|
111
|
+
return true;
|
|
112
|
+
} else {
|
|
113
|
+
log.error(`❌ Elevated execution failed for: ${description}`);
|
|
114
|
+
return false;
|
|
62
115
|
}
|
|
116
|
+
}
|
|
63
117
|
|
|
64
|
-
|
|
65
|
-
|
|
118
|
+
log.error(`❌ Command failed: ${description}`);
|
|
119
|
+
return false;
|
|
66
120
|
};
|
|
67
121
|
|
|
68
122
|
const uninstall = async (component) => {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
123
|
+
const stealth = getStealthContext();
|
|
124
|
+
log.header("🗑️ USO Uninstallation & Cleanup");
|
|
125
|
+
if (stealth.enabled) {
|
|
126
|
+
log.info(
|
|
127
|
+
`🐧 Stealth Mode detected. Uninstall targets WSL distro: ${stealth.distro}`,
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (component) {
|
|
132
|
+
component = component.toLowerCase();
|
|
133
|
+
log.info(`🎯 Targeted uninstallation: ${component}`);
|
|
134
|
+
|
|
135
|
+
if (component === "anchor") {
|
|
136
|
+
const anchorInstalled = commandExists("anchor", stealth);
|
|
137
|
+
if (anchorInstalled) {
|
|
138
|
+
log.info("Removing Anchor...");
|
|
139
|
+
// Try avm uninstall first if available
|
|
140
|
+
if (commandExists("avm", stealth)) {
|
|
141
|
+
runOrElevate(
|
|
142
|
+
"avm uninstall latest",
|
|
143
|
+
"Uninstall Anchor (AVM)",
|
|
144
|
+
stealth,
|
|
145
|
+
);
|
|
90
146
|
}
|
|
147
|
+
runOrElevate(
|
|
148
|
+
"cargo uninstall anchor-cli",
|
|
149
|
+
"Uninstall anchor-cli",
|
|
150
|
+
stealth,
|
|
151
|
+
);
|
|
152
|
+
runOrElevate("cargo uninstall avm", "Uninstall avm", stealth);
|
|
153
|
+
log.success("Anchor removal steps completed.");
|
|
154
|
+
} else {
|
|
155
|
+
log.success("✅ Anchor is not installed.");
|
|
156
|
+
}
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
91
159
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
} catch (err) {
|
|
110
|
-
log.warn(`Failed to remove ${localShareSolana} directly: ${err.message}`);
|
|
111
|
-
log.info("Trying to remove via elevated command...");
|
|
112
|
-
runOrElevate(`rmdir /s /q "${localShareSolana}"`, `Remove folder ${localShareSolana}`);
|
|
113
|
-
}
|
|
114
|
-
} else {
|
|
115
|
-
log.warn(`Could not find Solana folder at ${localShareSolana}. It might be removed already.`);
|
|
116
|
-
}
|
|
117
|
-
} else {
|
|
118
|
-
log.success("✅ Solana CLI is not installed.");
|
|
119
|
-
}
|
|
120
|
-
return;
|
|
160
|
+
if (component === "solana") {
|
|
161
|
+
// Check PATH first
|
|
162
|
+
let solanaInstalled = commandExists("solana", stealth);
|
|
163
|
+
const localShareSolana = path.join(
|
|
164
|
+
os.homedir(),
|
|
165
|
+
".local",
|
|
166
|
+
"share",
|
|
167
|
+
"solana",
|
|
168
|
+
);
|
|
169
|
+
const wslSolanaPath = "$HOME/.local/share/solana";
|
|
170
|
+
|
|
171
|
+
// If not found in PATH, check default location
|
|
172
|
+
if (!solanaInstalled) {
|
|
173
|
+
if (stealth.enabled) {
|
|
174
|
+
solanaInstalled = wslPathExists(wslSolanaPath, stealth);
|
|
175
|
+
} else if (fs.existsSync(localShareSolana)) {
|
|
176
|
+
solanaInstalled = true;
|
|
121
177
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (solanaInstalled) {
|
|
181
|
+
log.info("Removing Solana CLI...");
|
|
182
|
+
|
|
183
|
+
if (stealth.enabled) {
|
|
184
|
+
runOrElevate(
|
|
185
|
+
`rm -rf "${wslSolanaPath}"`,
|
|
186
|
+
`Remove folder ${wslSolanaPath}`,
|
|
187
|
+
stealth,
|
|
188
|
+
);
|
|
189
|
+
log.success(`Removed ${wslSolanaPath}`);
|
|
190
|
+
} else {
|
|
191
|
+
if (fs.existsSync(localShareSolana)) {
|
|
192
|
+
try {
|
|
193
|
+
fs.rmSync(localShareSolana, { recursive: true, force: true });
|
|
194
|
+
log.success(`Removed ${localShareSolana}`);
|
|
195
|
+
} catch (err) {
|
|
196
|
+
log.warn(
|
|
197
|
+
`Failed to remove ${localShareSolana} directly: ${err.message}`,
|
|
198
|
+
);
|
|
199
|
+
log.info("Trying to remove via elevated command...");
|
|
200
|
+
runOrElevate(
|
|
201
|
+
`rmdir /s /q "${localShareSolana}"`,
|
|
202
|
+
`Remove folder ${localShareSolana}`,
|
|
203
|
+
stealth,
|
|
204
|
+
);
|
|
130
205
|
}
|
|
131
|
-
|
|
206
|
+
} else {
|
|
207
|
+
log.warn(
|
|
208
|
+
`Could not find Solana folder at ${localShareSolana}. It might be removed already.`,
|
|
209
|
+
);
|
|
210
|
+
}
|
|
132
211
|
}
|
|
133
|
-
|
|
134
|
-
log.
|
|
135
|
-
|
|
212
|
+
} else {
|
|
213
|
+
log.success("✅ Solana CLI is not installed.");
|
|
214
|
+
}
|
|
215
|
+
return;
|
|
136
216
|
}
|
|
137
217
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
218
|
+
if (component === "rust") {
|
|
219
|
+
const rustInstalled = commandExists("rustc", stealth);
|
|
220
|
+
if (rustInstalled) {
|
|
221
|
+
log.info("Running rustup self uninstall...");
|
|
222
|
+
runOrElevate("rustup self uninstall -y", "Uninstall Rust", stealth);
|
|
223
|
+
} else {
|
|
224
|
+
log.success("✅ Rust is not installed.");
|
|
225
|
+
}
|
|
226
|
+
return;
|
|
147
227
|
}
|
|
148
228
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
229
|
+
log.error(
|
|
230
|
+
`❌ Unknown component: ${component}. Available: rust, solana, anchor`,
|
|
231
|
+
);
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// --- FULL INTERACTIVE UNINSTALL ---
|
|
236
|
+
|
|
237
|
+
log.warn("This process allows you to remove components installed by uso.");
|
|
238
|
+
log.warn("Please be careful, especially with wallet removal!");
|
|
239
|
+
|
|
240
|
+
const proceed = await askQuestion(
|
|
241
|
+
"👉 Do you want to proceed with uninstallation? (y/N): ",
|
|
242
|
+
);
|
|
243
|
+
if (proceed.toLowerCase() !== "y") {
|
|
244
|
+
log.info("Operation cancelled.");
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// 1. Uninstall Anchor
|
|
249
|
+
const anchorInstalled = commandExists("anchor", stealth);
|
|
250
|
+
if (anchorInstalled) {
|
|
251
|
+
const removeAnchor = await askQuestion(
|
|
252
|
+
"\n⚓ Remove Anchor Framework? (y/N): ",
|
|
253
|
+
);
|
|
254
|
+
if (removeAnchor.toLowerCase() === "y") {
|
|
255
|
+
log.info("Removing Anchor...");
|
|
256
|
+
// Try avm uninstall first if available
|
|
257
|
+
if (commandExists("avm", stealth)) {
|
|
258
|
+
runOrElevate("avm uninstall latest", "Uninstall Anchor (AVM)", stealth);
|
|
259
|
+
}
|
|
260
|
+
runOrElevate(
|
|
261
|
+
"cargo uninstall anchor-cli",
|
|
262
|
+
"Uninstall anchor-cli",
|
|
263
|
+
stealth,
|
|
264
|
+
);
|
|
265
|
+
runOrElevate("cargo uninstall avm", "Uninstall avm", stealth);
|
|
266
|
+
log.success("Anchor removal steps completed.");
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// 2. Uninstall Solana
|
|
271
|
+
let solanaInstalled = commandExists("solana", stealth);
|
|
272
|
+
const localShareSolana = path.join(os.homedir(), ".local", "share", "solana");
|
|
273
|
+
const wslSolanaPath = "$HOME/.local/share/solana";
|
|
274
|
+
|
|
275
|
+
// If not found in PATH, check default location (like doctor does)
|
|
276
|
+
if (!solanaInstalled) {
|
|
277
|
+
if (stealth.enabled) {
|
|
278
|
+
solanaInstalled = wslPathExists(wslSolanaPath, stealth);
|
|
279
|
+
} else if (fs.existsSync(localShareSolana)) {
|
|
280
|
+
solanaInstalled = true;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (solanaInstalled) {
|
|
285
|
+
const removeSolana = await askQuestion("\n☀️ Remove Solana CLI? (y/N): ");
|
|
286
|
+
if (removeSolana.toLowerCase() === "y") {
|
|
287
|
+
log.info("Removing Solana CLI...");
|
|
288
|
+
|
|
289
|
+
// Default locations
|
|
290
|
+
// const localShareSolana = path.join(os.homedir(), '.local', 'share', 'solana'); // Already defined
|
|
291
|
+
|
|
292
|
+
if (stealth.enabled) {
|
|
293
|
+
runOrElevate(
|
|
294
|
+
`rm -rf "${wslSolanaPath}"`,
|
|
295
|
+
`Remove folder ${wslSolanaPath}`,
|
|
296
|
+
stealth,
|
|
297
|
+
);
|
|
298
|
+
log.success(`Removed ${wslSolanaPath}`);
|
|
299
|
+
} else {
|
|
300
|
+
if (fs.existsSync(localShareSolana)) {
|
|
301
|
+
try {
|
|
302
|
+
fs.rmSync(localShareSolana, { recursive: true, force: true });
|
|
303
|
+
log.success(`Removed ${localShareSolana}`);
|
|
304
|
+
} catch (err) {
|
|
305
|
+
log.warn(
|
|
306
|
+
`Failed to remove ${localShareSolana} directly: ${err.message}`,
|
|
307
|
+
);
|
|
308
|
+
log.info("Trying to remove via elevated command...");
|
|
309
|
+
runOrElevate(
|
|
310
|
+
`rmdir /s /q "${localShareSolana}"`,
|
|
311
|
+
`Remove folder ${localShareSolana}`,
|
|
312
|
+
stealth,
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
} else {
|
|
316
|
+
log.warn(
|
|
317
|
+
`Could not find Solana at ${localShareSolana}. It might be already removed.`,
|
|
318
|
+
);
|
|
162
319
|
}
|
|
320
|
+
}
|
|
163
321
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
if (
|
|
171
|
-
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// 3. Uninstall Rust
|
|
325
|
+
const rustInstalled = commandExists("rustc", stealth);
|
|
326
|
+
if (rustInstalled) {
|
|
327
|
+
const removeRust = await askQuestion("\n🦀 Remove Rust? (y/N): ");
|
|
328
|
+
if (removeRust.toLowerCase() === "y") {
|
|
329
|
+
log.info("Running rustup self uninstall...");
|
|
330
|
+
runOrElevate("rustup self uninstall -y", "Uninstall Rust", stealth);
|
|
172
331
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// 4. WALLET REMOVAL (DANGER)
|
|
335
|
+
const walletPath = path.join(os.homedir(), ".config", "solana", "id.json");
|
|
336
|
+
const wslWalletPath = "$HOME/.config/solana/id.json";
|
|
337
|
+
const hasNativeWallet = fs.existsSync(walletPath);
|
|
338
|
+
const hasWslWallet = stealth.enabled
|
|
339
|
+
? wslPathExists(wslWalletPath, stealth)
|
|
340
|
+
: false;
|
|
341
|
+
|
|
342
|
+
if (hasNativeWallet || hasWslWallet) {
|
|
343
|
+
log.error("\n⚠️ DANGER ZONE ⚠️");
|
|
344
|
+
if (hasNativeWallet) log.warn(`Found a Solana wallet at: ${walletPath}`);
|
|
345
|
+
if (hasWslWallet)
|
|
346
|
+
log.warn(`Found a Solana wallet in WSL at: ${wslWalletPath}`);
|
|
347
|
+
log.warn(
|
|
348
|
+
"If you delete this without a backup, your funds will be LOST FOREVER.",
|
|
349
|
+
);
|
|
350
|
+
|
|
351
|
+
const removeWallet = await askQuestion(
|
|
352
|
+
"💥 Do you REALLY want to delete this wallet? (type 'DELETE' to confirm): ",
|
|
353
|
+
);
|
|
354
|
+
if (removeWallet === "DELETE") {
|
|
355
|
+
if (hasNativeWallet) {
|
|
356
|
+
try {
|
|
357
|
+
fs.unlinkSync(walletPath);
|
|
358
|
+
log.success("Native wallet deleted.");
|
|
359
|
+
|
|
360
|
+
// Clean up parent config dir if empty
|
|
361
|
+
const configDir = path.dirname(walletPath);
|
|
362
|
+
try {
|
|
363
|
+
if (fs.readdirSync(configDir).length === 0) {
|
|
364
|
+
fs.rmSync(configDir, { recursive: true, force: true });
|
|
193
365
|
}
|
|
366
|
+
} catch (e) {}
|
|
367
|
+
} catch (err) {
|
|
368
|
+
log.error(`Failed to delete native wallet: ${err.message}`);
|
|
194
369
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
if (hasWslWallet) {
|
|
373
|
+
const deleted = runOrElevate(
|
|
374
|
+
`rm -f "${wslWalletPath}"`,
|
|
375
|
+
"Delete WSL wallet",
|
|
376
|
+
stealth,
|
|
377
|
+
);
|
|
378
|
+
if (deleted) {
|
|
379
|
+
// Best effort cleanup of config dir if empty.
|
|
380
|
+
runOrElevate(
|
|
381
|
+
'rmdir "$HOME/.config/solana" 2>/dev/null || true',
|
|
382
|
+
"Cleanup WSL wallet config directory",
|
|
383
|
+
stealth,
|
|
384
|
+
);
|
|
385
|
+
log.success("WSL wallet deleted.");
|
|
204
386
|
}
|
|
387
|
+
}
|
|
388
|
+
} else {
|
|
389
|
+
log.info("Skipping wallet deletion.");
|
|
205
390
|
}
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
// Clean up parent config dir if empty
|
|
221
|
-
const configDir = path.dirname(walletPath);
|
|
222
|
-
try {
|
|
223
|
-
if (fs.readdirSync(configDir).length === 0) {
|
|
224
|
-
fs.rmSync(configDir, { recursive: true, force: true });
|
|
225
|
-
}
|
|
226
|
-
} catch (e) { }
|
|
227
|
-
} catch (err) {
|
|
228
|
-
log.error(`Failed to delete wallet: ${err.message}`);
|
|
229
|
-
}
|
|
230
|
-
} else {
|
|
231
|
-
log.info("Skipping wallet deletion.");
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
if (stealth.enabled) {
|
|
394
|
+
const configPath = path.join(os.homedir(), ".uso-config.json");
|
|
395
|
+
if (fs.existsSync(configPath)) {
|
|
396
|
+
const disableStealth = await askQuestion(
|
|
397
|
+
"\n🐧 Disable Stealth WSL mode for USO? (y/N): ",
|
|
398
|
+
);
|
|
399
|
+
if (disableStealth.toLowerCase() === "y") {
|
|
400
|
+
try {
|
|
401
|
+
fs.rmSync(configPath, { force: true });
|
|
402
|
+
log.success("Stealth mode config removed.");
|
|
403
|
+
} catch (err) {
|
|
404
|
+
log.warn(`Failed to remove stealth config: ${err.message}`);
|
|
232
405
|
}
|
|
406
|
+
}
|
|
233
407
|
}
|
|
408
|
+
}
|
|
234
409
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
410
|
+
log.header("\n✅ Cleanup complete.");
|
|
411
|
+
log.info("To remove the 'uso' tool itself, run:");
|
|
412
|
+
log.info(" npm uninstall -g uso");
|
|
238
413
|
};
|
|
239
414
|
|
|
240
415
|
module.exports = { uninstall };
|