openclaw-droid 2.0.2 → 2.0.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.
Potentially problematic release.
This version of openclaw-droid might be problematic. Click here for more details.
- package/README.md +210 -204
- package/SECURITY.md +210 -210
- package/bin/openclawdx +7 -7
- package/install.sh +93 -57
- package/lib/bionic-bypass.js +64 -64
- package/lib/env.js +49 -49
- package/lib/index.js +25 -25
- package/lib/installer.js +300 -291
- package/lib/utils.js +117 -117
- package/overlay_daemon.py +105 -105
- package/package.json +1 -1
package/lib/installer.js
CHANGED
|
@@ -20,71 +20,80 @@ export function checkDependencies() {
|
|
|
20
20
|
proot: false
|
|
21
21
|
};
|
|
22
22
|
|
|
23
|
-
try {
|
|
24
|
-
safeExecSync('node --version', { stdio: 'pipe' });
|
|
25
|
-
deps.node = true;
|
|
26
|
-
} catch (err) {
|
|
27
|
-
logger.debug('Node.js check failed:', err.message);
|
|
28
|
-
}
|
|
29
|
-
try {
|
|
30
|
-
safeExecSync('npm --version', { stdio: 'pipe' });
|
|
31
|
-
deps.npm = true;
|
|
32
|
-
} catch (err) {
|
|
33
|
-
logger.debug('npm check failed:', err.message);
|
|
34
|
-
}
|
|
35
|
-
try {
|
|
36
|
-
safeExecSync('git --version', { stdio: 'pipe' });
|
|
37
|
-
deps.git = true;
|
|
38
|
-
} catch (err) {
|
|
39
|
-
logger.debug('git check failed:', err.message);
|
|
40
|
-
}
|
|
41
|
-
try {
|
|
42
|
-
safeExecSync('which proot-distro', { stdio: 'pipe' });
|
|
43
|
-
deps.proot = true;
|
|
44
|
-
} catch (err) {
|
|
45
|
-
logger.debug('proot-distro check failed:', err.message);
|
|
23
|
+
try {
|
|
24
|
+
safeExecSync('node --version', { stdio: 'pipe' });
|
|
25
|
+
deps.node = true;
|
|
26
|
+
} catch (err) {
|
|
27
|
+
logger.debug('Node.js check failed:', err.message);
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
safeExecSync('npm --version', { stdio: 'pipe' });
|
|
31
|
+
deps.npm = true;
|
|
32
|
+
} catch (err) {
|
|
33
|
+
logger.debug('npm check failed:', err.message);
|
|
34
|
+
}
|
|
35
|
+
try {
|
|
36
|
+
safeExecSync('git --version', { stdio: 'pipe' });
|
|
37
|
+
deps.git = true;
|
|
38
|
+
} catch (err) {
|
|
39
|
+
logger.debug('git check failed:', err.message);
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
safeExecSync('which proot-distro', { stdio: 'pipe' });
|
|
43
|
+
deps.proot = true;
|
|
44
|
+
} catch (err) {
|
|
45
|
+
logger.debug('proot-distro check failed:', err.message);
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
return deps;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
export function installTermuxDeps() {
|
|
52
|
-
console.log('Installing Termux dependencies...');
|
|
53
|
-
const packages = ['nodejs-lts', 'git', 'openssh', 'python', 'termux-
|
|
54
|
-
try {
|
|
55
|
-
safeExecSync('pkg update -y', { stdio: 'inherit', timeout: 180000 });
|
|
56
|
-
safeExecSync('pkg upgrade -y', { stdio: 'inherit', timeout: 300000 });
|
|
57
|
-
|
|
58
|
-
console.log('Enabling X11 repository...');
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
51
|
+
export function installTermuxDeps() {
|
|
52
|
+
console.log('Installing Termux dependencies...');
|
|
53
|
+
const packages = ['nodejs-lts', 'git', 'openssh', 'python', 'termux-api'];
|
|
54
|
+
try {
|
|
55
|
+
safeExecSync('pkg update -y', { stdio: 'inherit', timeout: 180000 });
|
|
56
|
+
safeExecSync('pkg upgrade -y', { stdio: 'inherit', timeout: 300000 });
|
|
57
|
+
|
|
58
|
+
console.log('Enabling X11 repository...');
|
|
59
|
+
try {
|
|
60
|
+
safeExecSync('pkg install -y x11-repo', { stdio: 'inherit', timeout: 60000 });
|
|
61
|
+
} catch (err) {
|
|
62
|
+
logger.warn('x11-repo not available. termux-gui may not install.');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
safeExecSync(`pkg install -y ${packages.join(' ')}`, { stdio: 'inherit', timeout: 300000 });
|
|
66
|
+
try {
|
|
67
|
+
safeExecSync('pkg install -y termux-gui', { stdio: 'inherit', timeout: 120000 });
|
|
68
|
+
} catch (err) {
|
|
69
|
+
logger.warn('termux-gui not available. Overlay features will be disabled.');
|
|
70
|
+
}
|
|
71
|
+
safeExecSync('npm install -g npm@latest', { stdio: 'inherit', timeout: 120000 });
|
|
72
|
+
|
|
73
|
+
const checks = [
|
|
74
|
+
['node --version', 'Node.js'],
|
|
75
|
+
['npm --version', 'npm'],
|
|
76
|
+
['git --version', 'git'],
|
|
77
|
+
['command -v proot-distro', 'proot-distro'],
|
|
78
|
+
['command -v python', 'python'],
|
|
79
|
+
['command -v termux-wake-lock', 'termux-api'],
|
|
80
|
+
['python -c "import termuxgui"', 'termux-gui']
|
|
81
|
+
];
|
|
82
|
+
|
|
83
|
+
for (const [cmd, label] of checks) {
|
|
84
|
+
try {
|
|
85
|
+
safeExecSync(cmd, { stdio: 'pipe', timeout: 3000 });
|
|
86
|
+
} catch (err) {
|
|
87
|
+
logger.warn(`Optional dependency missing: ${label} - install may still work`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return true;
|
|
92
|
+
} catch (err) {
|
|
93
|
+
console.error('Failed to install Termux packages:', err.message);
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
88
97
|
|
|
89
98
|
export function setupBionicBypass() {
|
|
90
99
|
console.log('Setting up Bionic Bypass...');
|
|
@@ -127,189 +136,189 @@ if [ ! -d "$TMPDIR" ]; then mkdir -p "$TMPDIR"; fi
|
|
|
127
136
|
return scriptPath;
|
|
128
137
|
}
|
|
129
138
|
|
|
130
|
-
export function installOpenClaw() {
|
|
131
|
-
console.log('Installing OpenClaw...');
|
|
132
|
-
try {
|
|
133
|
-
execSync('npm install -g openclaw@latest', { stdio: 'inherit' });
|
|
134
|
-
return true;
|
|
135
|
-
} catch (err) {
|
|
136
|
-
console.error('Failed to install OpenClaw:', err.message);
|
|
137
|
-
return false;
|
|
138
|
-
}
|
|
139
|
+
export function installOpenClaw() {
|
|
140
|
+
console.log('Installing OpenClaw...');
|
|
141
|
+
try {
|
|
142
|
+
execSync('npm install -g openclaw@latest', { stdio: 'inherit' });
|
|
143
|
+
return true;
|
|
144
|
+
} catch (err) {
|
|
145
|
+
console.error('Failed to install OpenClaw:', err.message);
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
139
148
|
}
|
|
140
149
|
|
|
141
|
-
export function configureTermux() {
|
|
142
|
-
console.log('Configuring Termux for background operation...');
|
|
143
|
-
const configDir = path.join(HOME, '.openclaw');
|
|
144
|
-
if (!fs.existsSync(configDir)) {
|
|
145
|
-
ensureDirectoryExists(configDir);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
const prefix = process.env.PREFIX || '/data/data/com.termux/files/usr';
|
|
149
|
-
const tmpOpenClawDir = path.join(prefix, 'tmp', 'openclaw');
|
|
150
|
-
if (!fs.existsSync(tmpOpenClawDir)) {
|
|
151
|
-
ensureDirectoryExists(tmpOpenClawDir);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
const openclawConfigPath = path.join(configDir, 'openclaw.json');
|
|
155
|
-
let config = {};
|
|
156
|
-
|
|
157
|
-
if (fs.existsSync(openclawConfigPath)) {
|
|
158
|
-
try {
|
|
159
|
-
config = JSON.parse(fs.readFileSync(openclawConfigPath, 'utf8'));
|
|
160
|
-
} catch (e) {
|
|
161
|
-
logger.warn('Warning: Failed to parse existing openclaw.json, starting fresh.');
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
let modified = false;
|
|
166
|
-
|
|
167
|
-
// Ensure gateway.bind = lan
|
|
168
|
-
if (!config.gateway) config.gateway = {};
|
|
169
|
-
if (config.gateway.bind !== 'lan') {
|
|
170
|
-
config.gateway.bind = 'lan';
|
|
171
|
-
modified = true;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// Ensure logging.file is correct
|
|
175
|
-
const expectedLogFile = path.join(tmpOpenClawDir, 'openclaw-YYYY-MM-DD.log');
|
|
176
|
-
if (!config.logging) config.logging = {};
|
|
177
|
-
if (!config.logging.level) {
|
|
178
|
-
config.logging.level = 'info';
|
|
179
|
-
modified = true;
|
|
180
|
-
}
|
|
181
|
-
if (config.logging.file !== expectedLogFile) {
|
|
182
|
-
config.logging.file = expectedLogFile;
|
|
183
|
-
modified = true;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
if (modified || !fs.existsSync(openclawConfigPath)) {
|
|
187
|
-
safeWriteFileSync(openclawConfigPath, JSON.stringify(config, null, 2), 'utf8');
|
|
188
|
-
console.log(' ✓ Updated openclaw.json config');
|
|
189
|
-
} else {
|
|
190
|
-
console.log(' ✓ openclaw.json config is up to date');
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
const wakeLockScript = path.join(configDir, 'wakelock.sh');
|
|
194
|
-
const wakeLockContent = `#!/bin/bash
|
|
195
|
-
termux-wake-lock
|
|
196
|
-
trap "termux-wake-unlock" EXIT
|
|
197
|
-
exec "$@"
|
|
198
|
-
`;
|
|
199
|
-
|
|
200
|
-
safeWriteFileSync(wakeLockScript, wakeLockContent, 'utf8');
|
|
201
|
-
setSecurePermissions(wakeLockScript, '750');
|
|
202
|
-
|
|
203
|
-
// Copy overlay_daemon.py to HOME for easy access
|
|
204
|
-
try {
|
|
205
|
-
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
206
|
-
const pkgRoot = path.join(__dirname, '..');
|
|
207
|
-
const sourceOverlay = path.join(pkgRoot, 'overlay_daemon.py');
|
|
208
|
-
const destOverlay = path.join(HOME, 'overlay_daemon.py');
|
|
209
|
-
|
|
210
|
-
if (fs.existsSync(sourceOverlay)) {
|
|
211
|
-
fs.copyFileSync(sourceOverlay, destOverlay);
|
|
212
|
-
setSecurePermissions(destOverlay, '750');
|
|
213
|
-
console.log(` ✓ Copied overlay_daemon.py to ${destOverlay}`);
|
|
214
|
-
}
|
|
215
|
-
} catch (err) {
|
|
216
|
-
logger.warn('Failed to copy overlay_daemon.py:', err);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
return true;
|
|
150
|
+
export function configureTermux() {
|
|
151
|
+
console.log('Configuring Termux for background operation...');
|
|
152
|
+
const configDir = path.join(HOME, '.openclaw');
|
|
153
|
+
if (!fs.existsSync(configDir)) {
|
|
154
|
+
ensureDirectoryExists(configDir);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const prefix = process.env.PREFIX || '/data/data/com.termux/files/usr';
|
|
158
|
+
const tmpOpenClawDir = path.join(prefix, 'tmp', 'openclaw');
|
|
159
|
+
if (!fs.existsSync(tmpOpenClawDir)) {
|
|
160
|
+
ensureDirectoryExists(tmpOpenClawDir);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const openclawConfigPath = path.join(configDir, 'openclaw.json');
|
|
164
|
+
let config = {};
|
|
165
|
+
|
|
166
|
+
if (fs.existsSync(openclawConfigPath)) {
|
|
167
|
+
try {
|
|
168
|
+
config = JSON.parse(fs.readFileSync(openclawConfigPath, 'utf8'));
|
|
169
|
+
} catch (e) {
|
|
170
|
+
logger.warn('Warning: Failed to parse existing openclaw.json, starting fresh.');
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
let modified = false;
|
|
175
|
+
|
|
176
|
+
// Ensure gateway.bind = lan
|
|
177
|
+
if (!config.gateway) config.gateway = {};
|
|
178
|
+
if (config.gateway.bind !== 'lan') {
|
|
179
|
+
config.gateway.bind = 'lan';
|
|
180
|
+
modified = true;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Ensure logging.file is correct
|
|
184
|
+
const expectedLogFile = path.join(tmpOpenClawDir, 'openclaw-YYYY-MM-DD.log');
|
|
185
|
+
if (!config.logging) config.logging = {};
|
|
186
|
+
if (!config.logging.level) {
|
|
187
|
+
config.logging.level = 'info';
|
|
188
|
+
modified = true;
|
|
189
|
+
}
|
|
190
|
+
if (config.logging.file !== expectedLogFile) {
|
|
191
|
+
config.logging.file = expectedLogFile;
|
|
192
|
+
modified = true;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (modified || !fs.existsSync(openclawConfigPath)) {
|
|
196
|
+
safeWriteFileSync(openclawConfigPath, JSON.stringify(config, null, 2), 'utf8');
|
|
197
|
+
console.log(' ✓ Updated openclaw.json config');
|
|
198
|
+
} else {
|
|
199
|
+
console.log(' ✓ openclaw.json config is up to date');
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const wakeLockScript = path.join(configDir, 'wakelock.sh');
|
|
203
|
+
const wakeLockContent = `#!/bin/bash
|
|
204
|
+
termux-wake-lock
|
|
205
|
+
trap "termux-wake-unlock" EXIT
|
|
206
|
+
exec "$@"
|
|
207
|
+
`;
|
|
208
|
+
|
|
209
|
+
safeWriteFileSync(wakeLockScript, wakeLockContent, 'utf8');
|
|
210
|
+
setSecurePermissions(wakeLockScript, '750');
|
|
211
|
+
|
|
212
|
+
// Copy overlay_daemon.py to HOME for easy access
|
|
213
|
+
try {
|
|
214
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
215
|
+
const pkgRoot = path.join(__dirname, '..');
|
|
216
|
+
const sourceOverlay = path.join(pkgRoot, 'overlay_daemon.py');
|
|
217
|
+
const destOverlay = path.join(HOME, 'overlay_daemon.py');
|
|
218
|
+
|
|
219
|
+
if (fs.existsSync(sourceOverlay)) {
|
|
220
|
+
fs.copyFileSync(sourceOverlay, destOverlay);
|
|
221
|
+
setSecurePermissions(destOverlay, '750');
|
|
222
|
+
console.log(` ✓ Copied overlay_daemon.py to ${destOverlay}`);
|
|
223
|
+
}
|
|
224
|
+
} catch (err) {
|
|
225
|
+
logger.warn('Failed to copy overlay_daemon.py:', err);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return true;
|
|
220
229
|
}
|
|
221
230
|
|
|
222
|
-
export function getInstallStatus() {
|
|
223
|
-
let hasProot = false;
|
|
224
|
-
try {
|
|
225
|
-
safeExecSync('command -v proot-distro', { stdio: 'pipe', timeout: 5000 });
|
|
226
|
-
hasProot = true;
|
|
227
|
-
} catch (err) {
|
|
228
|
-
logger.debug('Proot-distro check failed:', err.message);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
let hasUbuntu = false;
|
|
232
|
-
try {
|
|
233
|
-
hasUbuntu = fs.existsSync(path.join(PROOT_ROOTFS, 'ubuntu'));
|
|
234
|
-
} catch (err) {
|
|
235
|
-
logger.debug('Ubuntu check failed:', err.message);
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
let hasOpenClawInProot = false;
|
|
239
|
-
if (hasUbuntu) {
|
|
240
|
-
// Optimization: Check for binary file existence directly to avoid expensive proot-distro login
|
|
241
|
-
const ubuntuFsRoot = path.join(PROOT_ROOTFS, 'ubuntu');
|
|
242
|
-
const possiblePaths = [
|
|
243
|
-
path.join(ubuntuFsRoot, 'usr', 'local', 'bin', 'openclaw'),
|
|
244
|
-
path.join(ubuntuFsRoot, 'usr', 'bin', 'openclaw')
|
|
245
|
-
];
|
|
246
|
-
|
|
247
|
-
if (possiblePaths.some(p => fs.existsSync(p))) {
|
|
248
|
-
hasOpenClawInProot = true;
|
|
249
|
-
} else {
|
|
250
|
-
// Fallback: Slow check using proot-distro (for custom installations)
|
|
251
|
-
try {
|
|
252
|
-
const checkCmd = 'test -f /usr/local/bin/openclaw || test -f /usr/bin/openclaw || command -v openclaw';
|
|
253
|
-
safeExecSync(`proot-distro login ubuntu -- bash -c "${checkCmd}"`, { stdio: 'pipe', timeout: 15000 });
|
|
254
|
-
hasOpenClawInProot = true;
|
|
255
|
-
} catch (err) {
|
|
256
|
-
logger.debug('OpenClaw in proot check failed:', err.message);
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
let hasBionicBypassInProot = false;
|
|
262
|
-
try {
|
|
263
|
-
const prootBypassPath = path.join(PROOT_ROOTFS, 'ubuntu', 'root', '.openclaw', 'bionic-bypass.js');
|
|
264
|
-
hasBionicBypassInProot = fs.existsSync(prootBypassPath);
|
|
265
|
-
} catch (err) {
|
|
266
|
-
logger.debug('Bionic bypass in proot check failed:', err.message);
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
return {
|
|
270
|
-
proot: hasProot,
|
|
271
|
-
ubuntu: hasUbuntu,
|
|
272
|
-
openClawInProot: hasOpenClawInProot,
|
|
273
|
-
bionicBypassInProot: hasBionicBypassInProot,
|
|
274
|
-
bionicBypass: fs.existsSync(getBypassScriptPath()),
|
|
275
|
-
nodeOptions: process.env.NODE_OPTIONS?.includes('bionic-bypass') || false,
|
|
276
|
-
openClaw: (() => {
|
|
277
|
-
try {
|
|
278
|
-
safeExecSync('command -v openclaw', { stdio: 'pipe', timeout: 5000 });
|
|
279
|
-
return true;
|
|
280
|
-
} catch (err) {
|
|
281
|
-
logger.debug('OpenClaw check failed:', err.message);
|
|
282
|
-
return false;
|
|
283
|
-
}
|
|
284
|
-
})(),
|
|
285
|
-
python: (() => {
|
|
286
|
-
try {
|
|
287
|
-
safeExecSync('command -v python', { stdio: 'pipe', timeout: 5000 });
|
|
288
|
-
return true;
|
|
289
|
-
} catch (err) {
|
|
290
|
-
logger.debug('Python check failed:', err.message);
|
|
291
|
-
return false;
|
|
292
|
-
}
|
|
293
|
-
})(),
|
|
294
|
-
termuxGui: (() => {
|
|
295
|
-
try {
|
|
296
|
-
safeExecSync('python -c "import termuxgui"', { stdio: 'pipe', timeout: 5000 });
|
|
297
|
-
return true;
|
|
298
|
-
} catch (err) {
|
|
299
|
-
logger.debug('Termux GUI check failed:', err.message);
|
|
300
|
-
return false;
|
|
301
|
-
}
|
|
302
|
-
})(),
|
|
303
|
-
termuxApi: (() => {
|
|
304
|
-
try {
|
|
305
|
-
safeExecSync('command -v termux-wake-lock', { stdio: 'pipe', timeout: 5000 });
|
|
306
|
-
return true;
|
|
307
|
-
} catch (err) {
|
|
308
|
-
logger.debug('Termux API check failed:', err.message);
|
|
309
|
-
return false;
|
|
310
|
-
}
|
|
311
|
-
})()
|
|
312
|
-
};
|
|
231
|
+
export function getInstallStatus() {
|
|
232
|
+
let hasProot = false;
|
|
233
|
+
try {
|
|
234
|
+
safeExecSync('command -v proot-distro', { stdio: 'pipe', timeout: 5000 });
|
|
235
|
+
hasProot = true;
|
|
236
|
+
} catch (err) {
|
|
237
|
+
logger.debug('Proot-distro check failed:', err.message);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
let hasUbuntu = false;
|
|
241
|
+
try {
|
|
242
|
+
hasUbuntu = fs.existsSync(path.join(PROOT_ROOTFS, 'ubuntu'));
|
|
243
|
+
} catch (err) {
|
|
244
|
+
logger.debug('Ubuntu check failed:', err.message);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
let hasOpenClawInProot = false;
|
|
248
|
+
if (hasUbuntu) {
|
|
249
|
+
// Optimization: Check for binary file existence directly to avoid expensive proot-distro login
|
|
250
|
+
const ubuntuFsRoot = path.join(PROOT_ROOTFS, 'ubuntu');
|
|
251
|
+
const possiblePaths = [
|
|
252
|
+
path.join(ubuntuFsRoot, 'usr', 'local', 'bin', 'openclaw'),
|
|
253
|
+
path.join(ubuntuFsRoot, 'usr', 'bin', 'openclaw')
|
|
254
|
+
];
|
|
255
|
+
|
|
256
|
+
if (possiblePaths.some(p => fs.existsSync(p))) {
|
|
257
|
+
hasOpenClawInProot = true;
|
|
258
|
+
} else {
|
|
259
|
+
// Fallback: Slow check using proot-distro (for custom installations)
|
|
260
|
+
try {
|
|
261
|
+
const checkCmd = 'test -f /usr/local/bin/openclaw || test -f /usr/bin/openclaw || command -v openclaw';
|
|
262
|
+
safeExecSync(`proot-distro login ubuntu -- bash -c "${checkCmd}"`, { stdio: 'pipe', timeout: 15000 });
|
|
263
|
+
hasOpenClawInProot = true;
|
|
264
|
+
} catch (err) {
|
|
265
|
+
logger.debug('OpenClaw in proot check failed:', err.message);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
let hasBionicBypassInProot = false;
|
|
271
|
+
try {
|
|
272
|
+
const prootBypassPath = path.join(PROOT_ROOTFS, 'ubuntu', 'root', '.openclaw', 'bionic-bypass.js');
|
|
273
|
+
hasBionicBypassInProot = fs.existsSync(prootBypassPath);
|
|
274
|
+
} catch (err) {
|
|
275
|
+
logger.debug('Bionic bypass in proot check failed:', err.message);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
return {
|
|
279
|
+
proot: hasProot,
|
|
280
|
+
ubuntu: hasUbuntu,
|
|
281
|
+
openClawInProot: hasOpenClawInProot,
|
|
282
|
+
bionicBypassInProot: hasBionicBypassInProot,
|
|
283
|
+
bionicBypass: fs.existsSync(getBypassScriptPath()),
|
|
284
|
+
nodeOptions: process.env.NODE_OPTIONS?.includes('bionic-bypass') || false,
|
|
285
|
+
openClaw: (() => {
|
|
286
|
+
try {
|
|
287
|
+
safeExecSync('command -v openclaw', { stdio: 'pipe', timeout: 5000 });
|
|
288
|
+
return true;
|
|
289
|
+
} catch (err) {
|
|
290
|
+
logger.debug('OpenClaw check failed:', err.message);
|
|
291
|
+
return false;
|
|
292
|
+
}
|
|
293
|
+
})(),
|
|
294
|
+
python: (() => {
|
|
295
|
+
try {
|
|
296
|
+
safeExecSync('command -v python', { stdio: 'pipe', timeout: 5000 });
|
|
297
|
+
return true;
|
|
298
|
+
} catch (err) {
|
|
299
|
+
logger.debug('Python check failed:', err.message);
|
|
300
|
+
return false;
|
|
301
|
+
}
|
|
302
|
+
})(),
|
|
303
|
+
termuxGui: (() => {
|
|
304
|
+
try {
|
|
305
|
+
safeExecSync('python -c "import termuxgui"', { stdio: 'pipe', timeout: 5000 });
|
|
306
|
+
return true;
|
|
307
|
+
} catch (err) {
|
|
308
|
+
logger.debug('Termux GUI check failed:', err.message);
|
|
309
|
+
return false;
|
|
310
|
+
}
|
|
311
|
+
})(),
|
|
312
|
+
termuxApi: (() => {
|
|
313
|
+
try {
|
|
314
|
+
safeExecSync('command -v termux-wake-lock', { stdio: 'pipe', timeout: 5000 });
|
|
315
|
+
return true;
|
|
316
|
+
} catch (err) {
|
|
317
|
+
logger.debug('Termux API check failed:', err.message);
|
|
318
|
+
return false;
|
|
319
|
+
}
|
|
320
|
+
})()
|
|
321
|
+
};
|
|
313
322
|
}
|
|
314
323
|
|
|
315
324
|
export function installProot() {
|
|
@@ -334,58 +343,58 @@ export function installUbuntu() {
|
|
|
334
343
|
}
|
|
335
344
|
}
|
|
336
345
|
|
|
337
|
-
export function setupProotUbuntu() {
|
|
338
|
-
console.log('Setting up Node.js and OpenClaw in Ubuntu...');
|
|
339
|
-
|
|
340
|
-
console.log('\n⚠️ IMPORTANT: COMPILATION WARNING ⚠️');
|
|
341
|
-
console.log('OpenClaw depends on llama.cpp, which must be compiled from source.');
|
|
342
|
-
console.log('This process can take 15-30 MINUTES on a mobile device.');
|
|
343
|
-
console.log('Please be patient and DO NOT exit the installation.');
|
|
344
|
-
console.log('It may look stuck at "make" or "g++" - this is normal.\n');
|
|
345
|
-
|
|
346
|
-
// Wait a moment for the user to read
|
|
347
|
-
safeExecSync('sleep 5', { stdio: 'inherit', timeout: 10000 });
|
|
348
|
-
|
|
349
|
-
const setupScript = `
|
|
350
|
-
set -e
|
|
351
|
-
apt update
|
|
352
|
-
sleep 2
|
|
353
|
-
apt upgrade -y
|
|
354
|
-
sleep 2
|
|
355
|
-
apt install -y curl wget git build-essential python3
|
|
356
|
-
sleep 2
|
|
357
|
-
curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
|
|
358
|
-
apt install -y nodejs
|
|
359
|
-
sleep 2
|
|
360
|
-
npm install -g npm@latest
|
|
361
|
-
sleep 2
|
|
362
|
-
npm uninstall -g openclaw
|
|
363
|
-
sleep 2
|
|
364
|
-
npm install -g openclaw@latest
|
|
365
|
-
sleep 2
|
|
366
|
-
|
|
367
|
-
# Pre-configure openclaw.json
|
|
368
|
-
mkdir -p /root/.openclaw
|
|
369
|
-
cat > /root/.openclaw/openclaw.json << 'EOF'
|
|
370
|
-
{
|
|
371
|
-
"gateway": {
|
|
372
|
-
"bind": "lan"
|
|
373
|
-
},
|
|
374
|
-
"logging": {
|
|
375
|
-
"level": "info",
|
|
376
|
-
"file": "/root/.openclaw/openclaw-YYYY-MM-DD.log"
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
EOF
|
|
380
|
-
`;
|
|
381
|
-
|
|
382
|
-
try {
|
|
383
|
-
safeExecSync(`proot-distro login ubuntu -- bash -c '${setupScript}'`, { stdio: 'inherit', timeout: 3600000 });
|
|
384
|
-
return true;
|
|
385
|
-
} catch (err) {
|
|
386
|
-
logger.error('Failed to setup Ubuntu:', err);
|
|
387
|
-
return false;
|
|
388
|
-
}
|
|
346
|
+
export function setupProotUbuntu() {
|
|
347
|
+
console.log('Setting up Node.js and OpenClaw in Ubuntu...');
|
|
348
|
+
|
|
349
|
+
console.log('\n⚠️ IMPORTANT: COMPILATION WARNING ⚠️');
|
|
350
|
+
console.log('OpenClaw depends on llama.cpp, which must be compiled from source.');
|
|
351
|
+
console.log('This process can take 15-30 MINUTES on a mobile device.');
|
|
352
|
+
console.log('Please be patient and DO NOT exit the installation.');
|
|
353
|
+
console.log('It may look stuck at "make" or "g++" - this is normal.\n');
|
|
354
|
+
|
|
355
|
+
// Wait a moment for the user to read
|
|
356
|
+
safeExecSync('sleep 5', { stdio: 'inherit', timeout: 10000 });
|
|
357
|
+
|
|
358
|
+
const setupScript = `
|
|
359
|
+
set -e
|
|
360
|
+
apt update
|
|
361
|
+
sleep 2
|
|
362
|
+
apt upgrade -y
|
|
363
|
+
sleep 2
|
|
364
|
+
apt install -y curl wget git build-essential python3
|
|
365
|
+
sleep 2
|
|
366
|
+
curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
|
|
367
|
+
apt install -y nodejs
|
|
368
|
+
sleep 2
|
|
369
|
+
npm install -g npm@latest
|
|
370
|
+
sleep 2
|
|
371
|
+
npm uninstall -g openclaw
|
|
372
|
+
sleep 2
|
|
373
|
+
npm install -g openclaw@latest
|
|
374
|
+
sleep 2
|
|
375
|
+
|
|
376
|
+
# Pre-configure openclaw.json
|
|
377
|
+
mkdir -p /root/.openclaw
|
|
378
|
+
cat > /root/.openclaw/openclaw.json << 'EOF'
|
|
379
|
+
{
|
|
380
|
+
"gateway": {
|
|
381
|
+
"bind": "lan"
|
|
382
|
+
},
|
|
383
|
+
"logging": {
|
|
384
|
+
"level": "info",
|
|
385
|
+
"file": "/root/.openclaw/openclaw-YYYY-MM-DD.log"
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
EOF
|
|
389
|
+
`;
|
|
390
|
+
|
|
391
|
+
try {
|
|
392
|
+
safeExecSync(`proot-distro login ubuntu -- bash -c '${setupScript}'`, { stdio: 'inherit', timeout: 3600000 });
|
|
393
|
+
return true;
|
|
394
|
+
} catch (err) {
|
|
395
|
+
logger.error('Failed to setup Ubuntu:', err);
|
|
396
|
+
return false;
|
|
397
|
+
}
|
|
389
398
|
}
|
|
390
399
|
|
|
391
400
|
export function setupBionicBypassInProot() {
|