@xaidenlabs/uso 1.1.3 → 1.1.4
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/workflow.js +56 -75
package/package.json
CHANGED
package/src/commands/workflow.js
CHANGED
|
@@ -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
|
-
//
|
|
39
|
-
|
|
40
|
-
|
|
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
|
-
|
|
59
|
-
|
|
60
|
-
|
|
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.
|
|
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
|
-
|
|
73
|
-
}
|
|
37
|
+
log.info("🔑 Requesting elevated access (build will run in background)...\n");
|
|
74
38
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
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
|
-
|
|
47
|
+
} else {
|
|
48
|
+
log.error(`❌ '${command}' failed.`);
|
|
83
49
|
}
|
|
84
|
-
|
|
85
|
-
log.error(`❌ '${command}' failed.`);
|
|
86
50
|
};
|
|
87
51
|
|
|
88
52
|
/**
|
|
@@ -94,28 +58,40 @@ 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
|
|
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(
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
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
|
+
const scriptContent = [
|
|
73
|
+
`Set-Location "${cwd}"`,
|
|
74
|
+
`$env:PATH = [System.Environment]::GetEnvironmentVariable("PATH", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("PATH", "User")`,
|
|
75
|
+
`try {`,
|
|
76
|
+
` anchor ${command} ${args.join(' ')} 2>&1 | Tee-Object -FilePath "${logFile}" -Append`,
|
|
77
|
+
` $LASTEXITCODE | Out-File -FilePath "${doneFile}" -Encoding utf8`,
|
|
78
|
+
`} catch {`,
|
|
79
|
+
` $_.Exception.Message | Out-File -FilePath "${logFile}" -Encoding utf8 -Append`,
|
|
80
|
+
` "1" | Out-File -FilePath "${doneFile}" -Encoding utf8`,
|
|
81
|
+
`}`,
|
|
82
|
+
].join('\n');
|
|
83
|
+
|
|
84
|
+
fs.writeFileSync(scriptFile, scriptContent, 'utf8');
|
|
85
|
+
|
|
86
|
+
// Launch hidden elevated process using the script file
|
|
87
|
+
const elevateCmd = `powershell -Command "Start-Process powershell -ArgumentList '-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', '${scriptFile.replace(/\\/g, '\\\\')}' -Verb RunAs -WindowStyle Hidden"`;
|
|
114
88
|
|
|
115
89
|
const elevateResult = shell.exec(elevateCmd, { silent: true });
|
|
116
90
|
|
|
117
91
|
if (elevateResult.code !== 0) {
|
|
118
92
|
log.error("❌ Failed to launch elevated process. Was the UAC prompt declined?");
|
|
93
|
+
// Cleanup
|
|
94
|
+
try { fs.unlinkSync(scriptFile); } catch (e) { /* ignore */ }
|
|
119
95
|
resolve();
|
|
120
96
|
return;
|
|
121
97
|
}
|
|
@@ -126,14 +102,17 @@ const runElevatedWithProgress = (command, args = []) => {
|
|
|
126
102
|
|
|
127
103
|
const pollInterval = setInterval(() => {
|
|
128
104
|
try {
|
|
129
|
-
if
|
|
105
|
+
// Check if process finished
|
|
106
|
+
if (fs.existsSync(doneFileNormal)) {
|
|
130
107
|
clearInterval(pollInterval);
|
|
131
108
|
|
|
132
|
-
const exitCode = fs.readFileSync(
|
|
133
|
-
const fullLog = fs.readFileSync(
|
|
109
|
+
const exitCode = fs.readFileSync(doneFileNormal, 'utf8').trim();
|
|
110
|
+
const fullLog = fs.readFileSync(logFileNormal, 'utf8');
|
|
134
111
|
|
|
135
|
-
|
|
136
|
-
try { fs.unlinkSync(
|
|
112
|
+
// Cleanup temp files
|
|
113
|
+
try { fs.unlinkSync(logFileNormal); } catch (e) { /* ignore */ }
|
|
114
|
+
try { fs.unlinkSync(doneFileNormal); } catch (e) { /* ignore */ }
|
|
115
|
+
try { fs.unlinkSync(scriptFile); } catch (e) { /* ignore */ }
|
|
137
116
|
|
|
138
117
|
if (exitCode === '0') {
|
|
139
118
|
spin.succeed(`'${command}' completed successfully (elevated).`);
|
|
@@ -141,6 +120,7 @@ const runElevatedWithProgress = (command, args = []) => {
|
|
|
141
120
|
spin.fail(`'${command}' failed (elevated, exit code: ${exitCode}).`);
|
|
142
121
|
}
|
|
143
122
|
|
|
123
|
+
// Print the captured output
|
|
144
124
|
if (fullLog.trim()) {
|
|
145
125
|
console.log('\n' + fullLog.trim());
|
|
146
126
|
}
|
|
@@ -150,9 +130,9 @@ const runElevatedWithProgress = (command, args = []) => {
|
|
|
150
130
|
}
|
|
151
131
|
|
|
152
132
|
// Read new content for live progress
|
|
153
|
-
const stats = fs.statSync(
|
|
133
|
+
const stats = fs.statSync(logFileNormal);
|
|
154
134
|
if (stats.size > lastSize) {
|
|
155
|
-
const content = fs.readFileSync(
|
|
135
|
+
const content = fs.readFileSync(logFileNormal, 'utf8');
|
|
156
136
|
const lines = content.trim().split('\n').filter(l => l.trim());
|
|
157
137
|
if (lines.length > 0) {
|
|
158
138
|
const lastLine = lines[lines.length - 1].trim();
|
|
@@ -168,9 +148,10 @@ const runElevatedWithProgress = (command, args = []) => {
|
|
|
168
148
|
|
|
169
149
|
// Safety timeout: 10 minutes
|
|
170
150
|
setTimeout(() => {
|
|
171
|
-
if (!fs.existsSync(
|
|
151
|
+
if (!fs.existsSync(doneFileNormal)) {
|
|
172
152
|
clearInterval(pollInterval);
|
|
173
153
|
spin.fail("Timed out waiting for elevated process (10 min).");
|
|
154
|
+
try { fs.unlinkSync(scriptFile); } catch (e) { /* ignore */ }
|
|
174
155
|
resolve();
|
|
175
156
|
}
|
|
176
157
|
}, 10 * 60 * 1000);
|