@xaidenlabs/uso 1.1.3 → 1.1.5

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xaidenlabs/uso",
3
- "version": "1.1.3",
3
+ "version": "1.1.5",
4
4
  "description": "Universal Solana Orchestrator - A one-command setup tool for Solana and Anchor development environments on Windows, macOS, and Linux.",
5
5
  "bin": {
6
6
  "uso": "bin/index.js"
@@ -4,17 +4,6 @@ const fs = require('fs');
4
4
  const path = require('path');
5
5
  const { log, spinner } = require('../utils/logger');
6
6
 
7
- /**
8
- * Adds a Windows Defender exclusion for a given path (requires elevation).
9
- * Returns true if successful.
10
- */
11
- const addDefenderExclusion = (dirPath) => {
12
- const normalized = dirPath.replace(/\//g, '\\');
13
- const cmd = `powershell -Command "Start-Process powershell -ArgumentList '-NoProfile', '-Command', 'Add-MpPreference -ExclusionPath \\\"${normalized}\\\"' -Verb RunAs -WindowStyle Hidden -Wait"`;
14
- const result = shell.exec(cmd, { silent: true });
15
- return result.code === 0;
16
- };
17
-
18
7
  const runProxyCommand = async (command, args = []) => {
19
8
  // Check if anchor is available
20
9
  if (!shell.which('anchor')) {
@@ -35,54 +24,29 @@ const runProxyCommand = async (command, args = []) => {
35
24
 
36
25
  const output = (execution.stderr || '') + (execution.stdout || '');
37
26
 
38
- // --- Error Detection & Auto-Fix ---
39
-
40
- // 1. Windows Defender / Application Control blocking build scripts (os error 4551)
41
- const isDefenderBlock = output.includes('os error 4551') || output.includes('Application Control policy has blocked');
42
- if (isDefenderBlock && os.platform() === 'win32') {
43
- log.warn("⚠️ Windows Defender is blocking Cargo build scripts.");
44
- log.info("🛡️ Adding project directory to Defender exclusions...\n");
45
-
46
- const cwd = process.cwd();
47
- const cargoHome = path.join(os.homedir(), '.cargo');
48
-
49
- const success = addDefenderExclusion(cwd) && addDefenderExclusion(cargoHome);
50
-
51
- if (success) {
52
- log.success("✅ Defender exclusions added.");
53
- log.info("🔄 Cleaning build cache and retrying...\n");
54
-
55
- // Clean stale blocked artifacts
56
- shell.exec('cargo clean', { silent: true });
27
+ // Detect Windows-specific errors that require elevation
28
+ const isPrivilegeError = output.includes('os error 1314') || output.includes('A required privilege is not held by the client');
29
+ const isAppControlBlock = output.includes('os error 4551') || output.includes('Application Control policy has blocked');
57
30
 
58
- // Retry the command
59
- const retry = shell.exec(fullCommand);
60
- if (retry.code === 0) {
61
- log.success(`✅ '${command}' completed successfully.`);
62
- } else {
63
- log.error(`❌ '${command}' still failed after adding exclusions.`);
64
- log.warn("👉 Try running your terminal as Administrator.");
65
- }
31
+ if ((isPrivilegeError || isAppControlBlock) && os.platform() === 'win32') {
32
+ if (isAppControlBlock) {
33
+ log.warn("⚠️ Windows Application Control is blocking Cargo build scripts.");
66
34
  } else {
67
- log.error(" Could not add Defender exclusions. Was the UAC prompt declined?");
68
- log.info("👉 Manually add exclusions in Windows Security > Virus & threat protection > Exclusions:");
69
- log.info(` - ${cwd}`);
70
- log.info(` - ${cargoHome}`);
35
+ log.warn("⚠️ Windows requires Administrator privileges for this operation.");
71
36
  }
72
- return;
73
- }
37
+ log.info("🔑 Requesting elevated access (build will run in background)...\n");
74
38
 
75
- // 2. Privilege error (os error 1314 — symlink creation requires elevation)
76
- const isPrivilegeError = output.includes('os error 1314') || output.includes('A required privilege is not held by the client');
77
- if (isPrivilegeError && os.platform() === 'win32') {
78
- log.warn("⚠️ Windows requires Administrator privileges for this operation.");
79
- log.info("🔑 Requesting elevated access...\n");
39
+ // Clean stale blocked artifacts before elevated retry
40
+ if (isAppControlBlock) {
41
+ const cleanSpin = spinner('Cleaning blocked build artifacts...').start();
42
+ shell.exec('cargo clean', { silent: true, cwd: process.cwd() });
43
+ cleanSpin.succeed('Build cache cleaned.');
44
+ }
80
45
 
81
46
  await runElevatedWithProgress(command, args);
82
- return;
47
+ } else {
48
+ log.error(`❌ '${command}' failed.`);
83
49
  }
84
-
85
- log.error(`❌ '${command}' failed.`);
86
50
  };
87
51
 
88
52
  /**
@@ -94,28 +58,56 @@ const runElevatedWithProgress = (command, args = []) => {
94
58
  return new Promise((resolve) => {
95
59
  const tmpDir = os.tmpdir();
96
60
  const ts = Date.now();
97
- const logFile = path.join(tmpDir, `uso-elevated-${ts}.log`);
98
- const doneFile = path.join(tmpDir, `uso-elevated-${ts}.done`);
99
- const cwd = process.cwd();
61
+ const logFile = path.join(tmpDir, `uso-elevated-${ts}.log`).replace(/\\/g, '\\\\');
62
+ const doneFile = path.join(tmpDir, `uso-elevated-${ts}.done`).replace(/\\/g, '\\\\');
63
+ const logFileNormal = path.join(tmpDir, `uso-elevated-${ts}.log`);
64
+ const doneFileNormal = path.join(tmpDir, `uso-elevated-${ts}.done`);
65
+ const cwd = process.cwd().replace(/\\/g, '\\\\');
100
66
 
101
67
  // Write an empty log file so we can start reading immediately
102
- fs.writeFileSync(logFile, '', 'utf8');
103
-
104
- const anchorCmd = `anchor ${command} ${args.join(' ')}`;
105
- const innerScript = `
106
- Set-Location '${cwd.replace(/'/g, "''")}';
107
- $output = & cmd /c '${anchorCmd} 2>&1';
108
- $output | Out-File -FilePath '${logFile.replace(/\\/g, '\\\\')}' -Encoding utf8 -Append;
109
- $LASTEXITCODE | Out-File -FilePath '${doneFile.replace(/\\/g, '\\\\')}' -Encoding utf8;
110
- `.replace(/\n/g, ' ').trim();
111
-
112
- // Launch hidden elevated process
113
- const elevateCmd = `powershell -Command "Start-Process powershell -ArgumentList '-NoProfile', '-ExecutionPolicy', 'Bypass', '-Command', '${innerScript.replace(/'/g, "''")}' -Verb RunAs -WindowStyle Hidden"`;
68
+ fs.writeFileSync(logFileNormal, '', 'utf8');
69
+
70
+ // Build a PowerShell script file to avoid quoting hell
71
+ const scriptFile = path.join(tmpDir, `uso-elevated-${ts}.ps1`);
72
+
73
+ // We prepend commands to:
74
+ // 1. Enable Developer Mode (allows unsigned local binaries to run, fixes os error 4551)
75
+ // 2. Add Defender Exclusions (fixes os error 4551 / antivirus slowing builds)
76
+ const scriptContent = [
77
+ `$ErrorActionPreference = 'SilentlyContinue'`,
78
+ `Set-Location "${cwd}"`,
79
+ `try {`,
80
+ ` # 1. Enable Developer Mode`,
81
+ ` reg add "HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\AppModelUnlock" /t REG_DWORD /f /v "AllowDevelopmentWithoutDevLicense" /d "1" | Out-Null`,
82
+ ` `,
83
+ ` # 2. Add/Refresh Defender Exclusions`,
84
+ ` Add-MpPreference -ExclusionPath "${cwd}" -ErrorAction SilentlyContinue`,
85
+ ` Add-MpPreference -ExclusionPath "$env:USERPROFILE\\.cargo" -ErrorAction SilentlyContinue`,
86
+ `} catch {`,
87
+ ` # Ignore setup errors, try to build anyway`,
88
+ `}`,
89
+ ``,
90
+ `$env:PATH = [System.Environment]::GetEnvironmentVariable("PATH", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("PATH", "User")`,
91
+ `try {`,
92
+ ` anchor ${command} ${args.join(' ')} 2>&1 | Tee-Object -FilePath "${logFile}" -Append`,
93
+ ` $LASTEXITCODE | Out-File -FilePath "${doneFile}" -Encoding utf8`,
94
+ `} catch {`,
95
+ ` $_.Exception.Message | Out-File -FilePath "${logFile}" -Encoding utf8 -Append`,
96
+ ` "1" | Out-File -FilePath "${doneFile}" -Encoding utf8`,
97
+ `}`,
98
+ ].join('\n');
99
+
100
+ fs.writeFileSync(scriptFile, scriptContent, 'utf8');
101
+
102
+ // Launch hidden elevated process using the script file
103
+ const elevateCmd = `powershell -Command "Start-Process powershell -ArgumentList '-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', '${scriptFile.replace(/\\/g, '\\\\')}' -Verb RunAs -WindowStyle Hidden"`;
114
104
 
115
105
  const elevateResult = shell.exec(elevateCmd, { silent: true });
116
106
 
117
107
  if (elevateResult.code !== 0) {
118
108
  log.error("❌ Failed to launch elevated process. Was the UAC prompt declined?");
109
+ // Cleanup
110
+ try { fs.unlinkSync(scriptFile); } catch (e) { /* ignore */ }
119
111
  resolve();
120
112
  return;
121
113
  }
@@ -126,14 +118,17 @@ const runElevatedWithProgress = (command, args = []) => {
126
118
 
127
119
  const pollInterval = setInterval(() => {
128
120
  try {
129
- if (fs.existsSync(doneFile)) {
121
+ // Check if process finished
122
+ if (fs.existsSync(doneFileNormal)) {
130
123
  clearInterval(pollInterval);
131
124
 
132
- const exitCode = fs.readFileSync(doneFile, 'utf8').trim();
133
- const fullLog = fs.readFileSync(logFile, 'utf8');
125
+ const exitCode = fs.readFileSync(doneFileNormal, 'utf8').trim();
126
+ const fullLog = fs.readFileSync(logFileNormal, 'utf8');
134
127
 
135
- try { fs.unlinkSync(logFile); } catch (e) { /* ignore */ }
136
- try { fs.unlinkSync(doneFile); } catch (e) { /* ignore */ }
128
+ // Cleanup temp files
129
+ try { fs.unlinkSync(logFileNormal); } catch (e) { /* ignore */ }
130
+ try { fs.unlinkSync(doneFileNormal); } catch (e) { /* ignore */ }
131
+ try { fs.unlinkSync(scriptFile); } catch (e) { /* ignore */ }
137
132
 
138
133
  if (exitCode === '0') {
139
134
  spin.succeed(`'${command}' completed successfully (elevated).`);
@@ -141,6 +136,7 @@ const runElevatedWithProgress = (command, args = []) => {
141
136
  spin.fail(`'${command}' failed (elevated, exit code: ${exitCode}).`);
142
137
  }
143
138
 
139
+ // Print the captured output
144
140
  if (fullLog.trim()) {
145
141
  console.log('\n' + fullLog.trim());
146
142
  }
@@ -150,9 +146,9 @@ const runElevatedWithProgress = (command, args = []) => {
150
146
  }
151
147
 
152
148
  // Read new content for live progress
153
- const stats = fs.statSync(logFile);
149
+ const stats = fs.statSync(logFileNormal);
154
150
  if (stats.size > lastSize) {
155
- const content = fs.readFileSync(logFile, 'utf8');
151
+ const content = fs.readFileSync(logFileNormal, 'utf8');
156
152
  const lines = content.trim().split('\n').filter(l => l.trim());
157
153
  if (lines.length > 0) {
158
154
  const lastLine = lines[lines.length - 1].trim();
@@ -168,9 +164,10 @@ const runElevatedWithProgress = (command, args = []) => {
168
164
 
169
165
  // Safety timeout: 10 minutes
170
166
  setTimeout(() => {
171
- if (!fs.existsSync(doneFile)) {
167
+ if (!fs.existsSync(doneFileNormal)) {
172
168
  clearInterval(pollInterval);
173
169
  spin.fail("Timed out waiting for elevated process (10 min).");
170
+ try { fs.unlinkSync(scriptFile); } catch (e) { /* ignore */ }
174
171
  resolve();
175
172
  }
176
173
  }, 10 * 60 * 1000);