@xaidenlabs/uso 1.1.81 → 1.1.83
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/README.md +45 -0
- package/bin/index.js +19 -1
- package/package.json +1 -1
- package/src/commands/agent.js +295 -0
- package/src/commands/uninstall.js +3 -92
- package/src/platforms/wsl.js +0 -68
package/README.md
CHANGED
|
@@ -10,6 +10,7 @@ USO is a zero-friction CLI toolchain that installs, manages, and runs your entir
|
|
|
10
10
|
|
|
11
11
|
- [Installation](#installation)
|
|
12
12
|
- [Quick Start](#quick-start)
|
|
13
|
+
- [AI Agent (New)](#ai-agent-new)
|
|
13
14
|
- [Stealth WSL Mode (Windows)](#stealth-wsl-mode-windows)
|
|
14
15
|
- [Full Environment Setup](#full-environment-setup)
|
|
15
16
|
- [Granular Installation](#granular-installation)
|
|
@@ -66,6 +67,48 @@ uso dev
|
|
|
66
67
|
|
|
67
68
|
---
|
|
68
69
|
|
|
70
|
+
## AI Agent (New)
|
|
71
|
+
|
|
72
|
+
USO isn't just a command runner — it's an **Autonomous AI Agent** that can write code, build programs, debug errors, and deploy. Powered by ReAct (Reason + Act) architecture, the agent thinks step-by-step and uses tools to accomplish your goals.
|
|
73
|
+
|
|
74
|
+
### 1. Configure an LLM Provider
|
|
75
|
+
|
|
76
|
+
The agent needs an LLM to think. It supports four providers out of the box:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
# Option A: Local & Free (Ollama)
|
|
80
|
+
# Install from ollama.com, then run:
|
|
81
|
+
ollama pull llama3.1:8b
|
|
82
|
+
|
|
83
|
+
# Option B: GitHub Models (Free with GitHub Account)
|
|
84
|
+
uso agent-config --github-token <your-github-pat>
|
|
85
|
+
|
|
86
|
+
# Option C: Gemini
|
|
87
|
+
uso agent-config --gemini-key <your-api-key>
|
|
88
|
+
|
|
89
|
+
# Option D: OpenAI
|
|
90
|
+
uso agent-config --openai-key <your-api-key>
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### 2. Give it a Goal
|
|
94
|
+
|
|
95
|
+
Just tell the agent what you want to do. It will check your environment, plan a strategy, execute the commands, and automatically self-heal if any step fails.
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
# General environment fixing
|
|
99
|
+
uso agent "Check my Solana development environment and fix any missing tools"
|
|
100
|
+
|
|
101
|
+
# Build and test cycle
|
|
102
|
+
uso agent "Build my program and run the tests. If tests fail, fix the errors."
|
|
103
|
+
|
|
104
|
+
# Deployment
|
|
105
|
+
uso agent "Deploy my staking program to devnet and airdrop SOL if I don't have enough."
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
The agent runs a continuous FSM loop (`plan` → `execute` → `validate` → `heal`), streaming its thoughts and actions directly to your terminal.
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
69
112
|
## Stealth WSL Mode (Windows Only)
|
|
70
113
|
|
|
71
114
|
**The recommended mode for Windows developers.** Stealth Mode deploys a hidden WSL2 Linux environment (the "Uso Engine") that runs all your tooling inside Linux while you stay in PowerShell.
|
|
@@ -397,6 +440,8 @@ npm uninstall -g @xaidenlabs/uso
|
|
|
397
440
|
| `uso init rust` | `uso install rust` | Install Rust only |
|
|
398
441
|
| `uso init solana` | `uso install solana` | Install Solana CLI only |
|
|
399
442
|
| `uso init anchor` | `uso install anchor` | Install Anchor Framework only |
|
|
443
|
+
| `uso agent <goal>` | — | Run the Autonomous AI Agent |
|
|
444
|
+
| `uso agent-config` | — | Configure Agent LLM providers |
|
|
400
445
|
| `uso doctor` | — | Diagnose environment |
|
|
401
446
|
| `uso verify` | — | End-to-end verification build |
|
|
402
447
|
| `uso create <name>` | — | Scaffold a new Anchor project |
|
package/bin/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
1
|
+
#!/usr/bin/env node
|
|
2
2
|
const { program } = require('commander');
|
|
3
3
|
const { init } = require('../src/commands/init');
|
|
4
4
|
const { doctor } = require('../src/commands/doctor');
|
|
@@ -6,6 +6,7 @@ const { verify } = require('../src/commands/verify');
|
|
|
6
6
|
const { create } = require('../src/commands/create');
|
|
7
7
|
const { build, test, deploy, clean, unblock, airdrop, address, balance, validator, dev } = require('../src/commands/workflow');
|
|
8
8
|
const { uninstall } = require('../src/commands/uninstall');
|
|
9
|
+
const { agent, agentConfig } = require('../src/commands/agent');
|
|
9
10
|
|
|
10
11
|
program
|
|
11
12
|
.name('uso')
|
|
@@ -101,4 +102,21 @@ program
|
|
|
101
102
|
.description('Uninstall uso components (rust, solana, anchor) or all')
|
|
102
103
|
.action(uninstall);
|
|
103
104
|
|
|
105
|
+
program
|
|
106
|
+
.command('agent [goal...]')
|
|
107
|
+
.description('Start the AI Agent to accomplish a goal autonomously')
|
|
108
|
+
.option('--model <model>', 'LLM model to use (e.g., llama3.1:8b, gemini-2.0-flash, openai/gpt-4o)')
|
|
109
|
+
.option('--provider <provider>', 'Force a specific LLM provider (ollama, gemini, openai, github)')
|
|
110
|
+
.option('--max-loops <n>', 'Maximum reasoning iterations', '3')
|
|
111
|
+
.option('--verbose', 'Show full reasoning traces')
|
|
112
|
+
.action(agent);
|
|
113
|
+
|
|
114
|
+
program
|
|
115
|
+
.command('agent-config')
|
|
116
|
+
.description('Configure API keys and preferences for the AI Agent')
|
|
117
|
+
.option('--gemini-key <key>', 'Set Gemini API key')
|
|
118
|
+
.option('--openai-key <key>', 'Set OpenAI API key')
|
|
119
|
+
.option('--github-token <token>', 'Set GitHub Models PAT token')
|
|
120
|
+
.action(agentConfig);
|
|
121
|
+
|
|
104
122
|
program.parse(process.argv);
|
package/package.json
CHANGED
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
const os = require("os");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const chalk = require("chalk");
|
|
4
|
+
const { log, spinner } = require("../utils/logger");
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* `uso agent "<goal>"` — Run the AI Agent to accomplish a goal.
|
|
8
|
+
*
|
|
9
|
+
* This command handler:
|
|
10
|
+
* 1. Loads agent config from ~/.uso-agent.json
|
|
11
|
+
* 2. Resolves an LLM provider (Ollama → GitHub → Gemini → OpenAI)
|
|
12
|
+
* 3. Runs the ReAct FSM loop
|
|
13
|
+
* 4. Streams reasoning + actions to the terminal with styled output
|
|
14
|
+
*/
|
|
15
|
+
const agent = async (goalParts, options) => {
|
|
16
|
+
// Commander passes args differently depending on definition
|
|
17
|
+
const goalArray = Array.isArray(goalParts) ? goalParts : [goalParts];
|
|
18
|
+
const goal = goalArray.filter(Boolean).join(" ").trim();
|
|
19
|
+
|
|
20
|
+
if (!goal) {
|
|
21
|
+
log.error("❌ No goal provided.");
|
|
22
|
+
log.info('Usage: uso agent "Deploy my staking program to devnet"');
|
|
23
|
+
log.info(' uso agent "Check my environment and fix any issues"');
|
|
24
|
+
log.info(' uso agent "Build and test my program"');
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Dynamic import of uso-core (ESM from CJS)
|
|
29
|
+
let UsoAgent, loadAgentConfig;
|
|
30
|
+
try {
|
|
31
|
+
const core = require("../../packages/uso-core/dist/cjs/index.js");
|
|
32
|
+
UsoAgent = core.UsoAgent;
|
|
33
|
+
loadAgentConfig = core.loadAgentConfig;
|
|
34
|
+
} catch (err) {
|
|
35
|
+
log.error("❌ uso-core agent module not found.");
|
|
36
|
+
log.warn(
|
|
37
|
+
"Run 'cd packages/uso-core && npm run build' to compile the agent.",
|
|
38
|
+
);
|
|
39
|
+
log.warn(`Detail: ${err.message}`);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const config = loadAgentConfig();
|
|
44
|
+
|
|
45
|
+
// Override config from CLI flags
|
|
46
|
+
if (options.model) {
|
|
47
|
+
// Try to infer provider from model name
|
|
48
|
+
if (options.model.includes("/")) {
|
|
49
|
+
// GitHub Models format: "openai/gpt-4o-mini"
|
|
50
|
+
config.github = { ...config.github, model: options.model };
|
|
51
|
+
} else if (options.model.startsWith("gemini")) {
|
|
52
|
+
config.gemini = { ...config.gemini, model: options.model };
|
|
53
|
+
} else if (
|
|
54
|
+
options.model.startsWith("gpt") ||
|
|
55
|
+
options.model.startsWith("o1") ||
|
|
56
|
+
options.model.startsWith("o3")
|
|
57
|
+
) {
|
|
58
|
+
config.openai = { ...config.openai, model: options.model };
|
|
59
|
+
} else {
|
|
60
|
+
config.ollama = { ...config.ollama, model: options.model };
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const maxLoops = parseInt(options.maxLoops || "3", 10);
|
|
65
|
+
|
|
66
|
+
// ─── Banner ────────────────────────────────────────────────
|
|
67
|
+
console.log();
|
|
68
|
+
console.log(
|
|
69
|
+
chalk.bold.cyan(" ┌─────────────────────────────────────────┐"),
|
|
70
|
+
);
|
|
71
|
+
console.log(
|
|
72
|
+
chalk.bold.cyan(" │") +
|
|
73
|
+
chalk.bold.white(" USO Agent v1.0 ") +
|
|
74
|
+
chalk.bold.cyan("│"),
|
|
75
|
+
);
|
|
76
|
+
console.log(
|
|
77
|
+
chalk.bold.cyan(" │") +
|
|
78
|
+
chalk.dim(" Autonomous Solana DevOps Engine ") +
|
|
79
|
+
chalk.bold.cyan("│"),
|
|
80
|
+
);
|
|
81
|
+
console.log(
|
|
82
|
+
chalk.bold.cyan(" └─────────────────────────────────────────┘"),
|
|
83
|
+
);
|
|
84
|
+
console.log();
|
|
85
|
+
console.log(chalk.dim(" Goal: ") + chalk.white.bold(goal));
|
|
86
|
+
console.log(chalk.dim(" Max iterations: ") + chalk.yellow(maxLoops));
|
|
87
|
+
console.log();
|
|
88
|
+
|
|
89
|
+
// ─── FSM Callbacks (render to terminal) ────────────────────
|
|
90
|
+
const callbacks = {
|
|
91
|
+
onPhaseChange: (phase, state) => {
|
|
92
|
+
const phases = {
|
|
93
|
+
planning: "🧠 Planning",
|
|
94
|
+
executing: "⚡ Executing",
|
|
95
|
+
validating: "✅ Validating",
|
|
96
|
+
healing: "🔧 Self-Healing",
|
|
97
|
+
};
|
|
98
|
+
if (phases[phase]) {
|
|
99
|
+
console.log(chalk.dim(` ── ${phases[phase]} ──`));
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
|
|
103
|
+
onThought: (thought, state) => {
|
|
104
|
+
console.log(chalk.blue(" 💭 ") + chalk.italic(thought));
|
|
105
|
+
},
|
|
106
|
+
|
|
107
|
+
onToolCall: (toolName, params, state) => {
|
|
108
|
+
const paramStr = Object.keys(params).length > 0
|
|
109
|
+
? chalk.dim(` ${JSON.stringify(params).slice(0, 80)}`)
|
|
110
|
+
: "";
|
|
111
|
+
console.log(chalk.yellow(" 🔧 ") + chalk.bold(toolName) + paramStr);
|
|
112
|
+
},
|
|
113
|
+
|
|
114
|
+
onObservation: (observation, success, state) => {
|
|
115
|
+
const lines = observation.split("\n").slice(0, 10);
|
|
116
|
+
const color = success ? chalk.green : chalk.red;
|
|
117
|
+
const icon = success ? " ✅ " : " ❌ ";
|
|
118
|
+
|
|
119
|
+
for (const line of lines) {
|
|
120
|
+
if (line.trim()) {
|
|
121
|
+
console.log(color(icon + line.trim().slice(0, 120)));
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (observation.split("\n").length > 10) {
|
|
125
|
+
console.log(chalk.dim(" ... (output truncated)"));
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
|
|
129
|
+
onIteration: (iteration, maxIterations, state) => {
|
|
130
|
+
console.log(
|
|
131
|
+
chalk.dim(`\n ─── Iteration ${iteration}/${maxIterations} ───`),
|
|
132
|
+
);
|
|
133
|
+
},
|
|
134
|
+
|
|
135
|
+
onComplete: (summary, state) => {
|
|
136
|
+
console.log();
|
|
137
|
+
console.log(chalk.green.bold(" ✅ GOAL ACCOMPLISHED"));
|
|
138
|
+
console.log(chalk.green(" " + summary));
|
|
139
|
+
console.log();
|
|
140
|
+
},
|
|
141
|
+
|
|
142
|
+
onFailed: (reason, state) => {
|
|
143
|
+
console.log();
|
|
144
|
+
console.log(chalk.red.bold(" ❌ GOAL FAILED"));
|
|
145
|
+
console.log(chalk.red(" " + reason));
|
|
146
|
+
console.log();
|
|
147
|
+
},
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
// ─── Run Agent ─────────────────────────────────────────────
|
|
151
|
+
const spin = spinner("Resolving LLM provider...").start();
|
|
152
|
+
|
|
153
|
+
try {
|
|
154
|
+
const usoAgent = new UsoAgent(config);
|
|
155
|
+
|
|
156
|
+
// Resolve LLM first to show which provider is being used
|
|
157
|
+
const llmDiag = await usoAgent.diagnoseLlm();
|
|
158
|
+
const available = llmDiag.filter((d) => d.available);
|
|
159
|
+
|
|
160
|
+
if (available.length === 0) {
|
|
161
|
+
spin.fail("No LLM provider available.");
|
|
162
|
+
console.log();
|
|
163
|
+
log.error("The USO Agent needs at least one LLM to reason.");
|
|
164
|
+
console.log();
|
|
165
|
+
log.info("Options (pick any):");
|
|
166
|
+
log.info(" 1. Install Ollama (free, local): https://ollama.com");
|
|
167
|
+
log.info(" Then run: ollama pull llama3.1:8b");
|
|
168
|
+
log.info(
|
|
169
|
+
" 2. uso agent-config --github-token <your-github-pat>",
|
|
170
|
+
);
|
|
171
|
+
log.info(
|
|
172
|
+
" 3. uso agent-config --gemini-key <your-api-key>",
|
|
173
|
+
);
|
|
174
|
+
log.info(
|
|
175
|
+
" 4. uso agent-config --openai-key <your-api-key>",
|
|
176
|
+
);
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
spin.succeed(
|
|
181
|
+
`LLM: ${chalk.bold(available[0].name)} ${chalk.dim(`(${available.length} provider${available.length > 1 ? "s" : ""} available)`)}`,
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
// Run the agent
|
|
185
|
+
const result = await usoAgent.run({
|
|
186
|
+
goal,
|
|
187
|
+
provider: options.provider,
|
|
188
|
+
maxIterations: maxLoops,
|
|
189
|
+
verbose: !!options.verbose,
|
|
190
|
+
callbacks,
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
// ─── Summary ───────────────────────────────────────────
|
|
194
|
+
console.log(chalk.dim(" ─────────────────────────────────────────"));
|
|
195
|
+
console.log(
|
|
196
|
+
chalk.dim(" Provider: ") + chalk.white(result.llmProvider),
|
|
197
|
+
);
|
|
198
|
+
console.log(
|
|
199
|
+
chalk.dim(" Iterations: ") +
|
|
200
|
+
chalk.white(`${result.totalIterations}/${maxLoops}`),
|
|
201
|
+
);
|
|
202
|
+
console.log(
|
|
203
|
+
chalk.dim(" Duration: ") +
|
|
204
|
+
chalk.white(`${(result.durationMs / 1000).toFixed(1)}s`),
|
|
205
|
+
);
|
|
206
|
+
console.log(
|
|
207
|
+
chalk.dim(" Status: ") +
|
|
208
|
+
(result.success
|
|
209
|
+
? chalk.green.bold("SUCCESS")
|
|
210
|
+
: chalk.red.bold("FAILED")),
|
|
211
|
+
);
|
|
212
|
+
console.log();
|
|
213
|
+
|
|
214
|
+
process.exitCode = result.success ? 0 : 1;
|
|
215
|
+
} catch (err) {
|
|
216
|
+
spin.fail("Agent failed to start.");
|
|
217
|
+
log.error(`Error: ${err.message}`);
|
|
218
|
+
process.exitCode = 1;
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* `uso agent-config` — Configure API keys and preferences.
|
|
224
|
+
*/
|
|
225
|
+
const agentConfig = async (options) => {
|
|
226
|
+
let setApiKey, loadAgentConfig, saveAgentConfig;
|
|
227
|
+
try {
|
|
228
|
+
const core = require("../../packages/uso-core/dist/cjs/index.js");
|
|
229
|
+
setApiKey = core.setApiKey;
|
|
230
|
+
loadAgentConfig = core.loadAgentConfig;
|
|
231
|
+
saveAgentConfig = core.saveAgentConfig;
|
|
232
|
+
} catch (err) {
|
|
233
|
+
log.error("❌ uso-core agent module not found.");
|
|
234
|
+
log.warn("Run 'cd packages/uso-core && npm run build' to compile.");
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Set API keys from flags
|
|
239
|
+
if (options.geminiKey) {
|
|
240
|
+
setApiKey("gemini", options.geminiKey);
|
|
241
|
+
log.success("✅ Gemini API key saved.");
|
|
242
|
+
}
|
|
243
|
+
if (options.openaiKey) {
|
|
244
|
+
setApiKey("openai", options.openaiKey);
|
|
245
|
+
log.success("✅ OpenAI API key saved.");
|
|
246
|
+
}
|
|
247
|
+
if (options.githubToken) {
|
|
248
|
+
setApiKey("github", options.githubToken);
|
|
249
|
+
log.success("✅ GitHub Models token saved.");
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Show current config
|
|
253
|
+
if (!options.geminiKey && !options.openaiKey && !options.githubToken) {
|
|
254
|
+
const config = loadAgentConfig();
|
|
255
|
+
console.log();
|
|
256
|
+
console.log(chalk.bold("USO Agent Configuration"));
|
|
257
|
+
console.log(chalk.dim("Config file: ~/.uso-agent.json"));
|
|
258
|
+
console.log();
|
|
259
|
+
console.log(chalk.bold("LLM Providers:"));
|
|
260
|
+
console.log(
|
|
261
|
+
` Ollama: model=${chalk.cyan(config.ollama?.model || "llama3.1:8b")} url=${chalk.dim(config.ollama?.baseUrl || "http://localhost:11434")}`,
|
|
262
|
+
);
|
|
263
|
+
console.log(
|
|
264
|
+
` GitHub: model=${chalk.cyan(config.github?.model || "openai/gpt-4o-mini")} token=${config.github?.token ? chalk.green("SET") : chalk.red("NOT SET")}`,
|
|
265
|
+
);
|
|
266
|
+
console.log(
|
|
267
|
+
` Gemini: model=${chalk.cyan(config.gemini?.model || "gemini-2.0-flash")} key=${config.gemini?.apiKey ? chalk.green("SET") : chalk.red("NOT SET")}`,
|
|
268
|
+
);
|
|
269
|
+
console.log(
|
|
270
|
+
` OpenAI: model=${chalk.cyan(config.openai?.model || "gpt-4o-mini")} key=${config.openai?.apiKey ? chalk.green("SET") : chalk.red("NOT SET")}`,
|
|
271
|
+
);
|
|
272
|
+
console.log();
|
|
273
|
+
console.log(chalk.bold("Agent Settings:"));
|
|
274
|
+
console.log(
|
|
275
|
+
` Max iterations: ${chalk.cyan(config.agent?.maxIterations || 3)}`,
|
|
276
|
+
);
|
|
277
|
+
console.log(
|
|
278
|
+
` Confirm destructive: ${chalk.cyan(config.agent?.confirmDestructive ?? true)}`,
|
|
279
|
+
);
|
|
280
|
+
console.log();
|
|
281
|
+
console.log(chalk.dim("Set API keys:"));
|
|
282
|
+
console.log(
|
|
283
|
+
chalk.dim(" uso agent-config --gemini-key <key>"),
|
|
284
|
+
);
|
|
285
|
+
console.log(
|
|
286
|
+
chalk.dim(" uso agent-config --openai-key <key>"),
|
|
287
|
+
);
|
|
288
|
+
console.log(
|
|
289
|
+
chalk.dim(" uso agent-config --github-token <token>"),
|
|
290
|
+
);
|
|
291
|
+
console.log();
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
module.exports = { agent, agentConfig };
|
|
@@ -100,98 +100,6 @@ const uninstallAnchorComponents = (stealth) => {
|
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
log.success("Anchor removal steps completed.");
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Runs a command and attempts to elevate privileges if it fails with a permission error.
|
|
107
|
-
*/
|
|
108
|
-
const runOrElevate = (
|
|
109
|
-
command,
|
|
110
|
-
description,
|
|
111
|
-
stealth = { enabled: false, distro: "Ubuntu" },
|
|
112
|
-
) => {
|
|
113
|
-
if (stealth.enabled) {
|
|
114
|
-
const result = runInStealth(command, stealth, true);
|
|
115
|
-
|
|
116
|
-
if (result.code === 0) {
|
|
117
|
-
if (result.stdout) console.log(result.stdout);
|
|
118
|
-
return true;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
if (result.stdout) console.log(result.stdout);
|
|
122
|
-
if (result.stderr) console.error(result.stderr);
|
|
123
|
-
log.error(`❌ Command failed in WSL: ${description}`);
|
|
124
|
-
return false;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// We run without silent:true initially to let the user see output,
|
|
128
|
-
// but detecting the error code is what matters.
|
|
129
|
-
// actually, to detect the specific string "os error 1314", we need to capture output.
|
|
130
|
-
// So we run silently first? Or we just run and if it fails, we assume it *might* be elevation if on Windows?
|
|
131
|
-
// Let's run synchronously and capture output.
|
|
132
|
-
|
|
133
|
-
const result = shell.exec(command, { silent: true });
|
|
134
|
-
|
|
135
|
-
if (result.code === 0) {
|
|
136
|
-
console.log(result.stdout);
|
|
137
|
-
return true;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// Print the error output to the user
|
|
141
|
-
console.log(result.stdout);
|
|
142
|
-
console.error(result.stderr);
|
|
143
|
-
|
|
144
|
-
const output = result.stderr + result.stdout;
|
|
145
|
-
|
|
146
|
-
// Check for common permission errors
|
|
147
|
-
// "os error 1314" is specific to Windows symlink privilege
|
|
148
|
-
if (
|
|
149
|
-
(output.includes("os error 1314") ||
|
|
150
|
-
output.includes("EPERM") ||
|
|
151
|
-
output.includes("permission denied")) &&
|
|
152
|
-
os.platform() === "win32"
|
|
153
|
-
) {
|
|
154
|
-
log.warn(`⚠️ Permission denied during: ${description}`);
|
|
155
|
-
log.info("🛡️ Triggering Run as Administrator (UAC) to retry...");
|
|
156
|
-
|
|
157
|
-
// Construct PowerShell command to run cmd /c <command> as admin
|
|
158
|
-
// We need to be careful with quoting.
|
|
159
|
-
const escapedCommand = command.replace(/'/g, "''"); // Basic PowerShell escaping for single quotes
|
|
160
|
-
const elevateCmd = `powershell -Command "Start-Process -FilePath 'cmd.exe' -ArgumentList '/c ${escapedCommand}' -Verb RunAs -Wait"`;
|
|
161
|
-
|
|
162
|
-
const elevatedRun = shell.exec(elevateCmd);
|
|
163
|
-
|
|
164
|
-
if (elevatedRun.code === 0) {
|
|
165
|
-
log.success(`✅ ${description} completed (Elevated).`);
|
|
166
|
-
return true;
|
|
167
|
-
} else {
|
|
168
|
-
log.error(`❌ Elevated execution failed for: ${description}`);
|
|
169
|
-
return false;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
log.error(`❌ Command failed: ${description}`);
|
|
174
|
-
return false;
|
|
175
|
-
};
|
|
176
|
-
|
|
177
|
-
const uninstall = async (component) => {
|
|
178
|
-
const stealth = getStealthContext();
|
|
179
|
-
log.header("🗑️ USO Uninstallation & Cleanup");
|
|
180
|
-
if (stealth.enabled) {
|
|
181
|
-
log.info(
|
|
182
|
-
`🐧 Stealth Mode detected. Uninstall targets WSL distro: ${stealth.distro}`,
|
|
183
|
-
);
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
if (component) {
|
|
187
|
-
component = component.toLowerCase();
|
|
188
|
-
log.info(`🎯 Targeted uninstallation: ${component}`);
|
|
189
|
-
|
|
190
|
-
if (component === "anchor") {
|
|
191
|
-
const anchorInstalled = commandExists("anchor", stealth);
|
|
192
|
-
if (anchorInstalled) {
|
|
193
|
-
log.info("Removing Anchor...");
|
|
194
|
-
uninstallAnchorComponents(stealth);
|
|
195
103
|
} else {
|
|
196
104
|
log.success("✅ Anchor is not installed.");
|
|
197
105
|
}
|
|
@@ -362,6 +270,7 @@ const uninstall = async (component) => {
|
|
|
362
270
|
}
|
|
363
271
|
}
|
|
364
272
|
|
|
273
|
+
<<<<<<< HEAD
|
|
365
274
|
// 3.5 Remove WSL Distro (if stealth mode is active)
|
|
366
275
|
if (stealth.enabled && os.platform() === "win32") {
|
|
367
276
|
const removeWslDistro = await askQuestion(
|
|
@@ -391,6 +300,8 @@ const uninstall = async (component) => {
|
|
|
391
300
|
}
|
|
392
301
|
}
|
|
393
302
|
|
|
303
|
+
=======
|
|
304
|
+
>>>>>>> d47ca156cb2a252419c54c520c7fcd0f0c18c525
|
|
394
305
|
// 4. WALLET REMOVAL (DANGER)
|
|
395
306
|
const walletPath = path.join(os.homedir(), ".config", "solana", "id.json");
|
|
396
307
|
const wslWalletPath = "$HOME/.config/solana/id.json";
|
package/src/platforms/wsl.js
CHANGED
|
@@ -41,74 +41,6 @@ run_with_progress() {
|
|
|
41
41
|
}
|
|
42
42
|
`.replace(/\r\n/g, "\n");
|
|
43
43
|
|
|
44
|
-
/**
|
|
45
|
-
* Installs the WSL Windows Feature via an elevated PowerShell UAC prompt.
|
|
46
|
-
* This is needed when `wsl.exe` is not present on the system at all.
|
|
47
|
-
* Returns true if WSL is now available after the attempt, false otherwise.
|
|
48
|
-
*/
|
|
49
|
-
const installWslFeature = async () => {
|
|
50
|
-
log.warn(
|
|
51
|
-
"⚠️ WSL (Windows Subsystem for Linux) is not installed on this machine.",
|
|
52
|
-
);
|
|
53
|
-
log.info("🛡️ Administrator permission is required to install WSL.");
|
|
54
|
-
log.info(
|
|
55
|
-
"👉 A UAC (User Account Control) popup will appear — please click 'Yes' to allow the installation.",
|
|
56
|
-
);
|
|
57
|
-
console.log("");
|
|
58
|
-
|
|
59
|
-
// Run `wsl --install --no-distribution` elevated.
|
|
60
|
-
// --no-distribution: only enables the WSL feature, does not pull a distro yet.
|
|
61
|
-
// We wait for it to finish (-Wait) so we can check the result.
|
|
62
|
-
const elevateCmd = `powershell -Command "Start-Process -FilePath 'wsl.exe' -ArgumentList '--install', '--no-distribution' -Verb RunAs -Wait"`;
|
|
63
|
-
const result = shell.exec(elevateCmd, { silent: false });
|
|
64
|
-
|
|
65
|
-
if (result.code !== 0) {
|
|
66
|
-
// User likely denied UAC or the command failed
|
|
67
|
-
log.error("❌ WSL installation was cancelled or failed.");
|
|
68
|
-
log.warn(
|
|
69
|
-
"👉 To install manually, open PowerShell as Administrator and run:",
|
|
70
|
-
);
|
|
71
|
-
console.log(chalk.bold.yellow(" wsl --install"));
|
|
72
|
-
return false;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// Verify wsl is now available
|
|
76
|
-
const check = shell.exec("wsl --status", { silent: true });
|
|
77
|
-
if (check.code !== 0) {
|
|
78
|
-
// WSL was just installed — a reboot is almost certainly required
|
|
79
|
-
log.warn(
|
|
80
|
-
"⚠️ WSL feature has been installed, but a system restart is required to complete setup.",
|
|
81
|
-
);
|
|
82
|
-
log.warn(
|
|
83
|
-
"👉 Please RESTART your computer, then run `uso install` again to set up the toolchain.",
|
|
84
|
-
);
|
|
85
|
-
return false; // Signal caller that we need a restart before proceeding
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
log.success("✅ WSL feature installed successfully.");
|
|
89
|
-
return true;
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
const installWsl = async () => {
|
|
93
|
-
log.header("🐧 Configuring Stealth WSL Environment...");
|
|
94
|
-
|
|
95
|
-
// 1. Check if WSL is enabled
|
|
96
|
-
if (!shell.which("wsl")) {
|
|
97
|
-
log.error("❌ WSL is not enabled on this Windows machine.");
|
|
98
|
-
log.warn(
|
|
99
|
-
"👉 Please enable 'Windows Subsystem for Linux' in 'Turn Windows features on or off'.",
|
|
100
|
-
);
|
|
101
|
-
log.warn("👉 Or run this in PowerShell as Admin: wsl --install");
|
|
102
|
-
return false;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// 2. Install Ubuntu silently (Branded as Uso Engine)
|
|
106
|
-
// We use 'wsl -d Ubuntu -e true' to check if it's installed and runnable.
|
|
107
|
-
// 'wsl -l -v' output is notoriously unreliable due to charset encoding (UTF-16) on Windows.
|
|
108
|
-
const checkDistro = shell.exec(`wsl -d ${WSL_DISTRO} -e true`, {
|
|
109
|
-
silent: true,
|
|
110
|
-
});
|
|
111
|
-
|
|
112
44
|
// If exit code is 0, it's installed and working.
|
|
113
45
|
if (checkDistro.code !== 0) {
|
|
114
46
|
log.info(
|