clawdroid 1.0.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mithun Gowda B
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,261 @@
1
+ # ClawDroid
2
+
3
+ [![npm version](https://img.shields.io/npm/v/clawdroid?color=blue&label=npm)](https://www.npmjs.com/package/clawdroid)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+ [![Node.js](https://img.shields.io/badge/Node.js-18%2B-green?logo=node.js)](https://nodejs.org/)
6
+ [![Android](https://img.shields.io/badge/Android-10%2B-brightgreen?logo=android)](https://www.android.com/)
7
+ [![Termux](https://img.shields.io/badge/Termux-F--Droid-orange)](https://f-droid.org/packages/com.termux/)
8
+ [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/NOSYTLABS/clawdroid/pulls)
9
+
10
+ > Run optimized OpenClaw AI Gateway on Android using Termux with automatic proot Ubuntu setup and Bionic Bypass fix.
11
+
12
+ <p align="center">
13
+ <img src="https://img.shields.io/badge/Platform-Android%20%7C%20Termux-blue" alt="Platform">
14
+ <img src="https://img.shields.io/badge/Status-Active-success" alt="Status">
15
+ </p>
16
+
17
+ ---
18
+
19
+ ## Features
20
+
21
+ - **One-Command Setup** - Automatically installs proot-distro, Ubuntu, Node.js 22, and OpenClaw
22
+ - **Bionic Bypass** - Fixes `os.networkInterfaces()` crash on Android's Bionic libc
23
+ - **Smart Loading** - Shows spinner until gateway is actually ready
24
+ - **Pass-through Commands** - Run any OpenClaw command directly via `clawdroid`
25
+ - **Optimized for Android** - Pre-configured for mobile performance
26
+
27
+ ---
28
+
29
+ ## Quick Install
30
+
31
+ ### One-liner (recommended)
32
+
33
+ ```bash
34
+ curl -fsSL https://raw.githubusercontent.com/NOSYTLABS/clawdroid/main/install.sh | bash
35
+ ```
36
+
37
+ ### Or via npm
38
+
39
+ ```bash
40
+ npm install -g clawdroid
41
+ clawdroid setup
42
+ ```
43
+
44
+ ---
45
+
46
+ ## Requirements
47
+
48
+ | Requirement | Details |
49
+ |-------------|---------|
50
+ | **Android** | 10 or higher |
51
+ | **Termux** | From [F-Droid](https://f-droid.org/packages/com.termux/) (NOT Play Store) |
52
+ | **Storage** | ~2GB for Ubuntu + OpenClaw |
53
+
54
+ ---
55
+
56
+ ## Usage
57
+
58
+ ```bash
59
+ # First-time setup (installs proot + Ubuntu + Node.js + OpenClaw)
60
+ clawdroid setup
61
+
62
+ # Check installation status
63
+ clawdroid status
64
+
65
+ # Update OpenClaw to latest version
66
+ clawdroid update
67
+
68
+ # Start OpenClaw gateway
69
+ clawdroid start
70
+
71
+ # Run onboarding to configure API keys
72
+ clawdroid onboarding
73
+
74
+ # Enter Ubuntu shell
75
+ clawdroid shell
76
+
77
+ # Any OpenClaw command works directly
78
+ clawdroid doctor
79
+ clawdroid gateway --verbose
80
+ ```
81
+
82
+ > **Pro Tip:** Use `clawdroid gateway status` to check detailed health or `clawdroid logs --follow` to watch the gateway in real-time.
83
+
84
+ ---
85
+
86
+ ## How It Works
87
+
88
+ ```
89
+ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
90
+ │ Termux │ │ proot-distro │ │ Ubuntu │
91
+ │ clawdroid │ ──► │ │ ──► │ OpenClaw │
92
+ │ │ │ Bionic Bypass │ │ Gateway │
93
+ └─────────────────┘ └─────────────────┘ └─────────────────┘
94
+ ```
95
+
96
+ 1. **clawdroid** runs in Termux
97
+ 2. Commands are passed through **proot-distro** with Bionic Bypass
98
+ 3. **OpenClaw** runs inside Ubuntu environment
99
+
100
+ ---
101
+
102
+ ## Configuration
103
+
104
+ ### Onboarding
105
+
106
+ When running `clawdroid onboarding`:
107
+
108
+ - **Binding**: Select `Loopback (127.0.0.1)` for non-rooted devices
109
+ - **API Keys**: Add your Gemini/OpenAI/Claude keys
110
+
111
+ ### Battery Optimization
112
+
113
+ > **Important:** Disable battery optimization for Termux
114
+
115
+ Settings → Apps → Termux → Battery → **Unrestricted**
116
+
117
+ ---
118
+
119
+ ## Dashboard
120
+
121
+ Access the web dashboard at: **http://127.0.0.1:18789**
122
+
123
+ | Command | Description |
124
+ |---------|-------------|
125
+ | `/status` | Check gateway status |
126
+ | `/think high` | Enable high-quality thinking |
127
+ | `/reset` | Reset session |
128
+
129
+ ---
130
+
131
+ ## Troubleshooting
132
+
133
+ ### Gateway won't start
134
+
135
+ ```bash
136
+ # Check status
137
+ clawdroid status
138
+
139
+ # Re-run setup if needed
140
+ clawdroid setup
141
+
142
+ # Make sure onboarding is complete
143
+ clawdroid onboarding
144
+ ```
145
+
146
+ ### "os.networkInterfaces" error
147
+
148
+ Bionic Bypass not configured. Run:
149
+
150
+ ```bash
151
+ clawdroid setup
152
+ ```
153
+
154
+ ### Process killed in background
155
+
156
+ Disable battery optimization for Termux in Android settings.
157
+
158
+ ### Permission denied
159
+
160
+ ```bash
161
+ termux-setup-storage
162
+ ```
163
+
164
+ ---
165
+
166
+ ## Manual Setup
167
+
168
+ <details>
169
+ <summary>Click to expand manual installation steps</summary>
170
+
171
+ ### 1. Install proot-distro and Ubuntu
172
+
173
+ ```bash
174
+ pkg update && pkg install -y proot-distro
175
+ proot-distro install ubuntu
176
+ ```
177
+
178
+ ### 2. Setup Node.js in Ubuntu
179
+
180
+ ```bash
181
+ proot-distro login ubuntu
182
+ apt update && apt install -y curl
183
+ curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
184
+ apt install -y nodejs
185
+ npm install -g openclaw
186
+ ```
187
+
188
+ ### 3. Create Bionic Bypass
189
+
190
+ ```bash
191
+ mkdir -p ~/.openclawd
192
+ cat > ~/.openclawd/bionic-bypass.js << 'EOF'
193
+ const os = require('os');
194
+ const originalNetworkInterfaces = os.networkInterfaces;
195
+ os.networkInterfaces = function() {
196
+ try {
197
+ const interfaces = originalNetworkInterfaces.call(os);
198
+ if (interfaces && Object.keys(interfaces).length > 0) {
199
+ return interfaces;
200
+ }
201
+ } catch (e) {}
202
+ return {
203
+ lo: [{
204
+ address: '127.0.0.1',
205
+ netmask: '255.0.0.0',
206
+ family: 'IPv4',
207
+ mac: '00:00:00:00:00:00',
208
+ internal: true,
209
+ cidr: '127.0.0.1/8'
210
+ }]
211
+ };
212
+ };
213
+ EOF
214
+ ```
215
+
216
+ ### 4. Add to bashrc
217
+
218
+ ```bash
219
+ echo 'export NODE_OPTIONS="--require ~/.openclawd/bionic-bypass.js"' >> ~/.bashrc
220
+ source ~/.bashrc
221
+ ```
222
+
223
+ ### 5. Run OpenClaw
224
+
225
+ ```bash
226
+ openclaw onboarding # Select "Loopback (127.0.0.1)"
227
+ openclaw gateway --verbose
228
+ ```
229
+
230
+ </details>
231
+
232
+ ---
233
+
234
+ ## Credits
235
+
236
+ - Developed by **NOSYTLABS**
237
+ - Powered by [OpenClaw](https://github.com/anthropics/openclaw)
238
+
239
+ ---
240
+
241
+ ## Contributing
242
+
243
+ Contributions are welcome! Please feel free to submit a Pull Request.
244
+
245
+ 1. Fork the repository
246
+ 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
247
+ 3. Commit your changes (`git commit -m 'Add amazing feature'`)
248
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
249
+ 5. Open a Pull Request
250
+
251
+ ---
252
+
253
+ ## License
254
+
255
+ MIT License - see [LICENSE](LICENSE) file for details.
256
+
257
+ ---
258
+
259
+ <p align="center">
260
+ Made with ❤️ by NOSYTLABS
261
+ </p>
package/bin/clawdroid ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { main } from '../lib/index.js';
4
+
5
+ main(process.argv.slice(2)).catch((err) => {
6
+ console.error('Error:', err.message);
7
+ process.exit(1);
8
+ });
package/install.sh ADDED
@@ -0,0 +1,72 @@
1
+ #!/bin/bash
2
+ #
3
+ # ClawDroid Installer
4
+ # One-liner: curl -fsSL https://raw.githubusercontent.com/NOSYTLABS/clawdroid/main/install.sh | bash
5
+ #
6
+
7
+ set -e
8
+
9
+ # Colors
10
+ RED='\033[0;31m'
11
+ GREEN='\033[0;32m'
12
+ YELLOW='\033[1;33m'
13
+ BLUE='\033[0;34m'
14
+ NC='\033[0m'
15
+
16
+ echo -e "${BLUE}"
17
+ cat << "EOF"
18
+ ."". ."".
19
+ | | | | CLAWDROID
20
+ \ \._./ / Installer
21
+ '-./ \.-'
22
+ / \
23
+ /_____\
24
+ EOF
25
+ echo -e "${NC}"
26
+
27
+ # Check if running in Termux
28
+ if [ ! -d "/data/data/com.termux" ] && [ -z "$TERMUX_VERSION" ]; then
29
+ echo -e "${YELLOW}Warning:${NC} Not running in Termux - some features may not work"
30
+ fi
31
+
32
+ # Update and install packages
33
+ echo -e "\n${BLUE}[1/3]${NC} Installing required packages..."
34
+
35
+ # Optimize Termux repo access and update
36
+ echo -e " ${BLUE}•${NC} Updating Termux repositories..."
37
+ pkg update -y -o Dpkg::Options::="--force-confnew" || true
38
+ pkg upgrade -y -o Dpkg::Options::="--force-confnew" || true
39
+
40
+ echo -e " ${BLUE}•${NC} Installing dependencies..."
41
+ pkg install -y nodejs-lts git proot-distro android-tools termux-api
42
+
43
+ echo -e " ${GREEN}✓${NC} Node.js $(node --version)"
44
+ echo -e " ${GREEN}✓${NC} npm $(npm --version)"
45
+ echo -e " ${GREEN}✓${NC} git installed"
46
+ echo -e " ${GREEN}✓${NC} proot-distro installed"
47
+ echo -e " ${GREEN}✓${NC} adb $(adb version | head -n 1)"
48
+ echo -e " ${GREEN}✓${NC} termux-api installed"
49
+
50
+ # Install clawdroid from npm
51
+ echo -e "\n${BLUE}[2/3]${NC} Installing clawdroid..."
52
+ npm install -g clawdroid
53
+
54
+ echo -e "\n${BLUE}[3/3]${NC} Verifying Android tools..."
55
+ adb start-server >/dev/null 2>&1 || true
56
+ adb devices || true
57
+
58
+ echo -e "\n${GREEN}═══════════════════════════════════════════${NC}"
59
+ echo -e "${GREEN}Installation complete!${NC}"
60
+ echo -e "${GREEN}═══════════════════════════════════════════${NC}"
61
+ echo ""
62
+ echo -e "${YELLOW}Next steps:${NC}"
63
+ echo " 1. Run setup: clawdroid setup"
64
+ echo " 2. Run onboarding: clawdroid onboarding"
65
+ echo " → Select 'Loopback (127.0.0.1)' when asked!"
66
+ echo " 3. Start gateway: clawdroid start"
67
+ echo ""
68
+ echo -e "Dashboard: ${BLUE}http://127.0.0.1:18789${NC}"
69
+ echo ""
70
+ echo -e "${YELLOW}Tip:${NC} Disable battery optimization for Termux in Android settings"
71
+ echo -e "${YELLOW}Tip:${NC} Install Termux:API app from F-Droid for camera, wakelock, and sensors"
72
+ echo ""
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Bionic Bypass - Fixes os.networkInterfaces() on Android
3
+ *
4
+ * Android's Bionic libc blocks certain network interface queries.
5
+ * This module provides a workaround by returning a mock interface.
6
+ */
7
+
8
+ import fs from 'fs';
9
+ import path from 'path';
10
+
11
+ const BYPASS_SCRIPT = `
12
+ // ClawDroid Bionic Bypass - Auto-generated
13
+ const os = require('os');
14
+ const originalNetworkInterfaces = os.networkInterfaces;
15
+
16
+ os.networkInterfaces = function() {
17
+ try {
18
+ const interfaces = originalNetworkInterfaces.call(os);
19
+ if (interfaces && Object.keys(interfaces).length > 0) {
20
+ return interfaces;
21
+ }
22
+ } catch (e) {
23
+ // Bionic blocked the call, use fallback
24
+ }
25
+
26
+ // Return mock loopback interface
27
+ return {
28
+ lo: [
29
+ {
30
+ address: '127.0.0.1',
31
+ netmask: '255.0.0.0',
32
+ family: 'IPv4',
33
+ mac: '00:00:00:00:00:00',
34
+ internal: true,
35
+ cidr: '127.0.0.1/8'
36
+ }
37
+ ]
38
+ };
39
+ };
40
+ `;
41
+
42
+ export function getBypassScriptPath() {
43
+ const homeDir = process.env.HOME || '/data/data/com.termux/files/home';
44
+ return path.join(homeDir, '.clawdroid', 'bionic-bypass.js');
45
+ }
46
+
47
+ export function installBypass() {
48
+ const scriptPath = getBypassScriptPath();
49
+ const scriptDir = path.dirname(scriptPath);
50
+
51
+ if (!fs.existsSync(scriptDir)) {
52
+ fs.mkdirSync(scriptDir, { recursive: true });
53
+ }
54
+
55
+ fs.writeFileSync(scriptPath, BYPASS_SCRIPT, 'utf8');
56
+ fs.chmodSync(scriptPath, '644');
57
+
58
+ return scriptPath;
59
+ }
60
+
61
+ export function getNodeOptions() {
62
+ const scriptPath = getBypassScriptPath();
63
+ return `--require "${scriptPath}"`;
64
+ }
65
+
66
+ export function isAndroid() {
67
+ return process.platform === 'android' ||
68
+ fs.existsSync('/data/data/com.termux') ||
69
+ process.env.TERMUX_VERSION !== undefined;
70
+ }
71
+
72
+ export function checkBypassInstalled() {
73
+ const scriptPath = getBypassScriptPath();
74
+ return fs.existsSync(scriptPath);
75
+ }
package/lib/index.js ADDED
@@ -0,0 +1,334 @@
1
+ /**
2
+ * ClawDroid - Main entry point
3
+ */
4
+
5
+ import {
6
+ configureTermux,
7
+ getInstallStatus,
8
+ installProot,
9
+ installUbuntu,
10
+ setupProotUbuntu,
11
+ setupBionicBypassInProot,
12
+ runInProot,
13
+ runInProotWithCallback
14
+ } from './installer.js';
15
+ import { isAndroid } from './bionic-bypass.js';
16
+ import { spawn } from 'child_process';
17
+
18
+ const VERSION = '1.0.0';
19
+
20
+ function printBanner() {
21
+ console.log(`
22
+
23
+ CLAWDROID
24
+
25
+
26
+ `);
27
+ }
28
+
29
+ function printHelp() {
30
+ console.log(`
31
+ Usage: clawdroid [command] [args...]
32
+
33
+ If run without arguments, it starts the OpenClaw gateway.
34
+
35
+ Commands:
36
+ start Start OpenClaw gateway (Default)
37
+ setup Full installation (proot + Ubuntu + OpenClaw)
38
+ update Update OpenClaw to the latest version
39
+ repair Re-install OpenClaw and dependencies
40
+ status Check installation status
41
+ shell Open Ubuntu shell with OpenClaw ready
42
+ help Show this help message
43
+
44
+ Any other command is passed directly to openclaw in proot:
45
+ clawdroid onboarding → openclaw onboarding
46
+ clawdroid gateway -v → openclaw gateway -v
47
+ clawdroid doctor → openclaw doctor
48
+ clawdroid <anything> → openclaw <anything>
49
+
50
+ Examples:
51
+ clawdroid # Start gateway
52
+ clawdroid setup # First-time setup
53
+ clawdroid update # Update OpenClaw
54
+ clawdroid repair # Fix installation
55
+ clawdroid shell # Enter Ubuntu shell
56
+ `);
57
+ }
58
+
59
+ async function runSetup() {
60
+ console.log('Starting ClawDroid setup for Termux...\n');
61
+ console.log('This will install: proot-distro → Ubuntu → Node.js 22 → OpenClaw\n');
62
+
63
+ if (!isAndroid()) {
64
+ console.log('Warning: This package is designed for Android/Termux.');
65
+ console.log('Some features may not work on other platforms.\n');
66
+ }
67
+
68
+ let status = getInstallStatus();
69
+
70
+ // Step 1: Install proot-distro
71
+ console.log('[1/5] Checking proot-distro...');
72
+ if (!status.proot) {
73
+ console.log(' Installing proot-distro...');
74
+ installProot();
75
+ } else {
76
+ console.log(' ✓ proot-distro installed');
77
+ }
78
+ console.log('');
79
+
80
+ // Step 2: Install Ubuntu
81
+ console.log('[2/5] Checking Ubuntu in proot...');
82
+ status = getInstallStatus();
83
+ if (!status.ubuntu) {
84
+ console.log(' Installing Ubuntu (this takes a while)...');
85
+ installUbuntu();
86
+ } else {
87
+ console.log(' ✓ Ubuntu installed');
88
+ }
89
+ console.log('');
90
+
91
+ // Step 3: Setup Node.js and OpenClaw in Ubuntu
92
+ console.log('[3/5] Setting up Node.js and OpenClaw in Ubuntu...');
93
+ status = getInstallStatus();
94
+ if (!status.openClawInProot) {
95
+ setupProotUbuntu();
96
+ } else {
97
+ console.log(' ✓ OpenClaw already installed in proot');
98
+ }
99
+ console.log('');
100
+
101
+ // Step 4: Setup Bionic Bypass in proot
102
+ console.log('[4/5] Setting up Bionic Bypass in proot...');
103
+ setupBionicBypassInProot();
104
+ console.log('');
105
+
106
+ // Step 5: Configure Termux wake-lock
107
+ console.log('[5/5] Configuring Termux...');
108
+ configureTermux();
109
+ console.log('');
110
+
111
+ // Done
112
+ console.log('═══════════════════════════════════════════');
113
+ console.log('Setup complete!');
114
+ console.log('');
115
+ console.log('Next steps:');
116
+ console.log(' 1. Run onboarding: clawdroid onboarding');
117
+ console.log(' → Select "Loopback (127.0.0.1)" when asked!');
118
+ console.log(' 2. Start gateway: clawdroid start');
119
+ console.log('');
120
+ console.log('Dashboard: http://127.0.0.1:18789');
121
+ console.log('═══════════════════════════════════════════');
122
+ }
123
+
124
+ function showStatus() {
125
+ // Quick loading while checking proot
126
+ process.stdout.write('Checking installation status...');
127
+ const status = getInstallStatus();
128
+ process.stdout.write('\r' + ' '.repeat(35) + '\r');
129
+
130
+ console.log('Installation Status:\n');
131
+
132
+ console.log('Termux:');
133
+ console.log(` proot-distro: ${status.proot ? '✓ installed' : '✗ missing'}`);
134
+ console.log(` Ubuntu (proot): ${status.ubuntu ? '✓ installed' : '✗ not installed'}`);
135
+ console.log('');
136
+
137
+ if (status.ubuntu) {
138
+ console.log('Inside Ubuntu:');
139
+ console.log(` OpenClaw: ${status.openClawInProot ? '✓ installed' : '✗ not installed'}`);
140
+ console.log(` Bionic Bypass: ${status.bionicBypassInProot ? '✓ configured' : '✗ not configured'}`);
141
+ console.log('');
142
+ }
143
+
144
+ if (status.proot && status.ubuntu && status.openClawInProot) {
145
+ console.log('Status: ✓ Ready to run!');
146
+ console.log('');
147
+ console.log('Commands:');
148
+ console.log(' clawdroid start # Start gateway');
149
+ console.log(' clawdroid onboarding # Configure API keys');
150
+ console.log(' clawdroid shell # Enter Ubuntu shell');
151
+ } else {
152
+ console.log('Status: ✗ Setup incomplete');
153
+ console.log('Run: clawdroid setup');
154
+ }
155
+ }
156
+
157
+ function updateOpenClaw() {
158
+ const status = getInstallStatus();
159
+
160
+ if (!status.proot || !status.ubuntu) {
161
+ console.error('proot/Ubuntu not installed. Run: clawdroid setup');
162
+ process.exit(1);
163
+ }
164
+
165
+ console.log('Updating OpenClaw to the latest version...');
166
+
167
+ // Use runInProotWithCallback to show real-time output
168
+ const proc = runInProotWithCallback('npm install -g openclaw@latest', () => {
169
+ console.log('npm output:');
170
+ });
171
+
172
+ proc.on('close', (code) => {
173
+ if (code === 0) {
174
+ console.log('\n✓ OpenClaw updated successfully!');
175
+ console.log('Run "clawdroid start" to launch the gateway.');
176
+ } else {
177
+ console.error(`\n✗ Update failed with code ${code}`);
178
+ }
179
+ });
180
+ }
181
+
182
+ function startGateway() {
183
+ const status = getInstallStatus();
184
+
185
+ if (!status.proot || !status.ubuntu) {
186
+ console.error('proot/Ubuntu not installed. Run: clawdroid setup');
187
+ process.exit(1);
188
+ }
189
+
190
+ if (!status.openClawInProot) {
191
+ console.error('OpenClaw not installed in proot. Run: clawdroid setup');
192
+ process.exit(1);
193
+ }
194
+
195
+ // Loading animation until dashboard responds
196
+ const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
197
+ let i = 0;
198
+ let started = false;
199
+ const DASHBOARD_URL = 'http://127.0.0.1:18789';
200
+
201
+ const spinner = setInterval(() => {
202
+ if (!started) {
203
+ process.stdout.write(`\r${frames[i++ % frames.length]} Starting OpenClaw gateway...`);
204
+ }
205
+ }, 80);
206
+
207
+ // Poll dashboard until it responds
208
+ const checkDashboard = setInterval(async () => {
209
+ if (started) return;
210
+ try {
211
+ const response = await fetch(DASHBOARD_URL, { method: 'HEAD', signal: AbortSignal.timeout(1000) });
212
+ if (response.ok || response.status < 500) {
213
+ started = true;
214
+ clearInterval(spinner);
215
+ clearInterval(checkDashboard);
216
+ process.stdout.write('\r' + ' '.repeat(40) + '\r');
217
+ console.log('✓ OpenClaw gateway started!\n');
218
+ console.log(`Dashboard: ${DASHBOARD_URL}`);
219
+ console.log('Press Ctrl+C to stop\n');
220
+ console.log('─'.repeat(45) + '\n');
221
+ }
222
+ } catch { /* ignore polling errors */ }
223
+ }, 500);
224
+
225
+ // Start gateway in background (suppress output until ready)
226
+ const gateway = runInProot('openclaw gateway --verbose');
227
+
228
+ gateway.on('error', (err) => {
229
+ clearInterval(spinner);
230
+ clearInterval(checkDashboard);
231
+ console.error('\nFailed to start gateway:', err.message);
232
+ });
233
+
234
+ gateway.on('close', (code) => {
235
+ clearInterval(spinner);
236
+ clearInterval(checkDashboard);
237
+ if (!started) {
238
+ console.log('\nGateway exited before starting. Run: clawdroid onboarding');
239
+ }
240
+ console.log(`Gateway exited with code ${code}`);
241
+ });
242
+ }
243
+
244
+ function runOpenclawCommand(args) {
245
+ const status = getInstallStatus();
246
+
247
+ if (!status.proot || !status.ubuntu || !status.openClawInProot) {
248
+ console.error('Setup not complete. Run: clawdroid setup');
249
+ process.exit(1);
250
+ }
251
+
252
+ const command = args.join(' ');
253
+ console.log(`Running: openclaw ${command}\n`);
254
+
255
+ // Special hint for onboarding
256
+ if (args[0] === 'onboarding') {
257
+ console.log('TIP: Select "Loopback (127.0.0.1)" when asked for binding!\n');
258
+ }
259
+
260
+ const proc = runInProot(`openclaw ${command}`);
261
+
262
+ proc.on('error', (err) => {
263
+ console.error('Failed to run command:', err.message);
264
+ });
265
+ }
266
+
267
+ function openShell() {
268
+ const status = getInstallStatus();
269
+
270
+ if (!status.proot || !status.ubuntu) {
271
+ console.error('proot/Ubuntu not installed. Run: clawdroid setup');
272
+ process.exit(1);
273
+ }
274
+
275
+ console.log('Entering Ubuntu shell (with Bionic Bypass)...');
276
+ console.log('Type "exit" to return to Termux\n');
277
+
278
+ const shell = spawn('proot-distro', ['login', 'ubuntu'], {
279
+ stdio: 'inherit'
280
+ });
281
+
282
+ shell.on('error', (err) => {
283
+ console.error('Failed to open shell:', err.message);
284
+ });
285
+ }
286
+
287
+ export async function main(args) {
288
+ const command = args[0] || 'start'; // Default to start
289
+
290
+ printBanner();
291
+
292
+ switch (command) {
293
+ case 'setup':
294
+ case 'install':
295
+ await runSetup();
296
+ break;
297
+
298
+ case 'status':
299
+ showStatus();
300
+ break;
301
+
302
+ case 'update':
303
+ updateOpenClaw();
304
+ break;
305
+
306
+ case 'repair':
307
+ console.log('Repairing installation...');
308
+ await setupProotUbuntu();
309
+ setupBionicBypassInProot();
310
+ console.log('Repair complete!');
311
+ break;
312
+
313
+ case 'start':
314
+ case 'run':
315
+ startGateway();
316
+ break;
317
+
318
+ case 'shell':
319
+ case 'ubuntu':
320
+ openShell();
321
+ break;
322
+
323
+ case 'help':
324
+ case '--help':
325
+ case '-h':
326
+ printHelp();
327
+ break;
328
+
329
+ default:
330
+ // Pass any other command to openclaw in proot
331
+ runOpenclawCommand(args);
332
+ break;
333
+ }
334
+ }
@@ -0,0 +1,325 @@
1
+ /**
2
+ * ClawDroid Installer - Handles environment setup for Termux
3
+ */
4
+
5
+ import { execSync, spawn } from 'child_process';
6
+ import fs from 'fs';
7
+ import path from 'path';
8
+ import { installBypass, getBypassScriptPath, getNodeOptions } from './bionic-bypass.js';
9
+
10
+ const HOME = process.env.HOME || '/data/data/com.termux/files/home';
11
+ const BASHRC = path.join(HOME, '.bashrc');
12
+ const ZSHRC = path.join(HOME, '.zshrc');
13
+ const PROOT_ROOTFS = '/data/data/com.termux/files/usr/var/lib/proot-distro/installed-rootfs';
14
+ const PROOT_UBUNTU_ROOT = path.join(PROOT_ROOTFS, 'ubuntu', 'root');
15
+
16
+ export function checkDependencies() {
17
+ const deps = {
18
+ node: false,
19
+ npm: false,
20
+ git: false,
21
+ proot: false
22
+ };
23
+
24
+ try {
25
+ execSync('node --version', { stdio: 'pipe' });
26
+ deps.node = true;
27
+ } catch { /* not installed */ }
28
+
29
+ try {
30
+ execSync('npm --version', { stdio: 'pipe' });
31
+ deps.npm = true;
32
+ } catch { /* not installed */ }
33
+
34
+ try {
35
+ execSync('git --version', { stdio: 'pipe' });
36
+ deps.git = true;
37
+ } catch { /* not installed */ }
38
+
39
+ try {
40
+ execSync('which proot-distro', { stdio: 'pipe' });
41
+ deps.proot = true;
42
+ } catch { /* not installed */ }
43
+
44
+ return deps;
45
+ }
46
+
47
+ export function installTermuxDeps() {
48
+ console.log('Installing Termux dependencies...');
49
+
50
+ const packages = ['nodejs-lts', 'git', 'openssh'];
51
+
52
+ try {
53
+ execSync('pkg update -y', { stdio: 'inherit' });
54
+ execSync(`pkg install -y ${packages.join(' ')}`, { stdio: 'inherit' });
55
+ return true;
56
+ } catch (err) {
57
+ console.error('Failed to install Termux packages:', err.message);
58
+ return false;
59
+ }
60
+ }
61
+
62
+ export function setupBionicBypass() {
63
+ console.log('Setting up Bionic Bypass...');
64
+
65
+ const scriptPath = installBypass();
66
+ const nodeOptions = getNodeOptions();
67
+ const exportLine = `export NODE_OPTIONS="${nodeOptions}"`;
68
+
69
+ // Add to shell configs
70
+ for (const rcFile of [BASHRC, ZSHRC]) {
71
+ if (fs.existsSync(rcFile)) {
72
+ const content = fs.readFileSync(rcFile, 'utf8');
73
+ if (!content.includes('bionic-bypass')) {
74
+ fs.appendFileSync(rcFile, `\n# ClawDroid Bionic Bypass\n${exportLine}\n`);
75
+ console.log(`Updated ${path.basename(rcFile)}`);
76
+ }
77
+ }
78
+ }
79
+
80
+ // Also set for current session
81
+ process.env.NODE_OPTIONS = nodeOptions;
82
+
83
+ return scriptPath;
84
+ }
85
+
86
+ export function installOpenClaw() {
87
+ console.log('Installing OpenClaw...');
88
+
89
+ try {
90
+ execSync('npm install -g openclaw', { stdio: 'inherit' });
91
+ return true;
92
+ } catch (err) {
93
+ console.error('Failed to install OpenClaw:', err.message);
94
+ console.log('You may need to install it manually: npm install -g openclaw');
95
+ return false;
96
+ }
97
+ }
98
+
99
+ export function configureTermux() {
100
+ console.log('Configuring Termux for background operation...');
101
+
102
+ // Create wake-lock script
103
+ const wakeLockScript = path.join(HOME, '.clawdroid', 'wakelock.sh');
104
+ const wakeLockContent = `#!/bin/bash
105
+ # Keep Termux awake while OpenClaw runs
106
+ termux-wake-lock
107
+ trap "termux-wake-unlock" EXIT
108
+ exec "$@"
109
+ `;
110
+
111
+ fs.writeFileSync(wakeLockScript, wakeLockContent, 'utf8');
112
+ fs.chmodSync(wakeLockScript, '755');
113
+
114
+ console.log('Wake-lock script created');
115
+ console.log('');
116
+ console.log('IMPORTANT: Disable battery optimization for Termux in Android settings!');
117
+
118
+ return true;
119
+ }
120
+
121
+ export function getInstallStatus() {
122
+ const PROOT_ROOTFS = '/data/data/com.termux/files/usr/var/lib/proot-distro/installed-rootfs';
123
+
124
+ // Check proot-distro
125
+ let hasProot = false;
126
+ try {
127
+ execSync('command -v proot-distro', { stdio: 'pipe' });
128
+ hasProot = true;
129
+ } catch { /* not installed */ }
130
+
131
+ // Check if ubuntu is installed by checking rootfs directory
132
+ let hasUbuntu = false;
133
+ try {
134
+ hasUbuntu = fs.existsSync(path.join(PROOT_ROOTFS, 'ubuntu'));
135
+ } catch { /* check failed */ }
136
+
137
+ // Check if openclaw exists in proot ubuntu
138
+ let hasOpenClawInProot = false;
139
+ if (hasUbuntu) {
140
+ try {
141
+ execSync('proot-distro login ubuntu -- bash -c "command -v openclaw"', { stdio: 'pipe', timeout: 15000 });
142
+ hasOpenClawInProot = true;
143
+ } catch { /* not installed */ }
144
+ }
145
+
146
+ // Check bionic bypass in proot
147
+ let hasBionicBypassInProot = false;
148
+ try {
149
+ const prootBypassPath = path.join(PROOT_ROOTFS, 'ubuntu', 'root', '.clawdroid', 'bionic-bypass.js');
150
+ hasBionicBypassInProot = fs.existsSync(prootBypassPath);
151
+ } catch { /* check failed */ }
152
+
153
+ return {
154
+ proot: hasProot,
155
+ ubuntu: hasUbuntu,
156
+ openClawInProot: hasOpenClawInProot,
157
+ bionicBypassInProot: hasBionicBypassInProot,
158
+ // Legacy (for termux-native mode)
159
+ bionicBypass: fs.existsSync(getBypassScriptPath()),
160
+ nodeOptions: process.env.NODE_OPTIONS?.includes('bionic-bypass') || false,
161
+ openClaw: (() => {
162
+ try {
163
+ execSync('command -v openclaw', { stdio: 'pipe' });
164
+ return true;
165
+ } catch { return false; }
166
+ })()
167
+ };
168
+ }
169
+
170
+ export function installProot() {
171
+ console.log('Installing proot-distro...');
172
+ try {
173
+ execSync('pkg install -y proot-distro', { stdio: 'inherit' });
174
+ return true;
175
+ } catch (err) {
176
+ console.error('Failed to install proot-distro:', err.message);
177
+ return false;
178
+ }
179
+ }
180
+
181
+ export function installUbuntu() {
182
+ console.log('Installing Ubuntu in proot (this may take a while)...');
183
+ try {
184
+ execSync('proot-distro install ubuntu', { stdio: 'inherit' });
185
+ return true;
186
+ } catch (err) {
187
+ console.error('Failed to install Ubuntu:', err.message);
188
+ return false;
189
+ }
190
+ }
191
+
192
+ export function setupProotUbuntu() {
193
+ console.log('Setting up Node.js and OpenClaw in Ubuntu...');
194
+
195
+ // Optimized setup script with better memory management and error handling
196
+ const setupScript = `
197
+ set -e
198
+
199
+ # Optimize apt
200
+ echo 'Acquire::ForceIPv4 "true";' > /etc/apt/apt.conf.d/99force-ipv4
201
+
202
+ echo "Updating package lists..."
203
+ apt update && apt upgrade -y
204
+
205
+ echo "Installing core dependencies..."
206
+ apt install -y curl wget git build-essential python3
207
+
208
+ echo "Setting up Node.js 22..."
209
+ curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
210
+ apt install -y nodejs
211
+
212
+ # Verify Node.js
213
+ node -v
214
+ npm -v
215
+
216
+ echo "Installing OpenClaw..."
217
+ npm install -g openclaw --loglevel=error
218
+
219
+ # Cleanup to save space
220
+ apt autoremove -y
221
+ apt clean
222
+ `;
223
+
224
+ try {
225
+ execSync(`proot-distro login ubuntu -- bash -c '${setupScript}'`, { stdio: 'inherit' });
226
+ return true;
227
+ } catch (err) {
228
+ console.error('Failed to setup Ubuntu:', err.message);
229
+ return false;
230
+ }
231
+ }
232
+
233
+ export function setupBionicBypassInProot() {
234
+ console.log('Setting up Bionic Bypass in proot Ubuntu...');
235
+
236
+ const bypassScript = `
237
+ const os = require('os');
238
+ const originalNetworkInterfaces = os.networkInterfaces;
239
+ os.networkInterfaces = function() {
240
+ try {
241
+ const interfaces = originalNetworkInterfaces.call(os);
242
+ if (interfaces && Object.keys(interfaces).length > 0) {
243
+ return interfaces;
244
+ }
245
+ } catch (e) {}
246
+ return {
247
+ lo: [{
248
+ address: '127.0.0.1',
249
+ netmask: '255.0.0.0',
250
+ family: 'IPv4',
251
+ mac: '00:00:00:00:00:00',
252
+ internal: true,
253
+ cidr: '127.0.0.1/8'
254
+ }]
255
+ };
256
+ };
257
+ `;
258
+
259
+ const prootBypassPath = path.join(PROOT_UBUNTU_ROOT, '.clawdroid', 'bionic-bypass.js');
260
+ const prootBypassDir = path.dirname(prootBypassPath);
261
+
262
+ try {
263
+ if (!fs.existsSync(prootBypassDir)) {
264
+ fs.mkdirSync(prootBypassDir, { recursive: true });
265
+ }
266
+ fs.writeFileSync(prootBypassPath, bypassScript, 'utf8');
267
+
268
+ // Add to bashrc in proot
269
+ const prootBashrc = path.join(PROOT_UBUNTU_ROOT, '.bashrc');
270
+ const exportLine = 'export NODE_OPTIONS="--require /root/.clawdroid/bionic-bypass.js"';
271
+
272
+ let bashrcContent = '';
273
+ if (fs.existsSync(prootBashrc)) {
274
+ bashrcContent = fs.readFileSync(prootBashrc, 'utf8');
275
+ }
276
+
277
+ if (!bashrcContent.includes('bionic-bypass')) {
278
+ fs.appendFileSync(prootBashrc, `\n# ClawDroid Bionic Bypass\n${exportLine}\n`);
279
+ }
280
+
281
+ console.log('Bionic Bypass configured in proot Ubuntu');
282
+ return true;
283
+ } catch (err) {
284
+ console.error('Failed to setup Bionic Bypass in proot:', err.message);
285
+ return false;
286
+ }
287
+ }
288
+
289
+ export function runInProot(command) {
290
+ const nodeOptions = '--require /root/.clawdroid/bionic-bypass.js';
291
+ return spawn('proot-distro', ['login', 'ubuntu', '--', 'bash', '-c', `export NODE_OPTIONS="${nodeOptions}" && ${command}`], {
292
+ stdio: 'inherit'
293
+ });
294
+ }
295
+
296
+ export function runInProotWithCallback(command, onFirstOutput) {
297
+ const nodeOptions = '--require /root/.clawdroid/bionic-bypass.js';
298
+ let firstOutput = true;
299
+
300
+ const proc = spawn('proot-distro', ['login', 'ubuntu', '--', 'bash', '-c', `export NODE_OPTIONS="${nodeOptions}" && ${command}`], {
301
+ stdio: ['inherit', 'pipe', 'pipe']
302
+ });
303
+
304
+ proc.stdout.on('data', (data) => {
305
+ if (firstOutput) {
306
+ firstOutput = false;
307
+ onFirstOutput();
308
+ }
309
+ process.stdout.write(data);
310
+ });
311
+
312
+ proc.stderr.on('data', (data) => {
313
+ if (firstOutput) {
314
+ firstOutput = false;
315
+ onFirstOutput();
316
+ }
317
+ // Filter out harmless proot warnings
318
+ const str = data.toString();
319
+ if (!str.includes('proot warning') && !str.includes("can't sanitize")) {
320
+ process.stderr.write(data);
321
+ }
322
+ });
323
+
324
+ return proc;
325
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Post-install script - runs after npm install
3
+ */
4
+
5
+ import { isAndroid, installBypass, getNodeOptions } from './bionic-bypass.js';
6
+
7
+ function main() {
8
+ console.log('\n📱 ClawDroid post-install\n');
9
+
10
+ if (!isAndroid()) {
11
+ console.log('Not running on Android/Termux - skipping Bionic Bypass setup.');
12
+ console.log('You can still use this package on other systems.\n');
13
+ return;
14
+ }
15
+
16
+ // Install the bypass script
17
+ try {
18
+ const scriptPath = installBypass();
19
+ console.log(`✓ Bionic Bypass installed at: ${scriptPath}`);
20
+ } catch (err) {
21
+ console.error('✗ Failed to install Bionic Bypass:', err.message);
22
+ return;
23
+ }
24
+
25
+ // Show instructions
26
+ const nodeOptions = getNodeOptions();
27
+
28
+ console.log('\n' + '═'.repeat(50));
29
+ console.log('IMPORTANT: Add this to your shell config (~/.bashrc):');
30
+ console.log('═'.repeat(50));
31
+ console.log(`\nexport NODE_OPTIONS="${nodeOptions}"\n`);
32
+ console.log('Or run: clawdroid setup');
33
+ console.log('═'.repeat(50) + '\n');
34
+ }
35
+
36
+ main();
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "clawdroid",
3
+ "version": "1.0.0",
4
+ "description": "ClawDroid - Optimized OpenClaw AI Gateway for Android Termux",
5
+ "main": "lib/index.js",
6
+ "type": "module",
7
+ "bin": {
8
+ "clawdroid": "bin/clawdroid"
9
+ },
10
+ "scripts": {
11
+ "postinstall": "node lib/postinstall.js"
12
+ },
13
+ "keywords": [
14
+ "openclaw",
15
+ "termux",
16
+ "android",
17
+ "ai",
18
+ "gateway",
19
+ "gemini",
20
+ "claude"
21
+ ],
22
+ "author": "NOSYTLABS",
23
+ "license": "MIT",
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "git+https://github.com/NOSYTLABS/clawdroid.git"
27
+ },
28
+ "homepage": "https://github.com/NOSYTLABS/clawdroid#readme",
29
+ "bugs": {
30
+ "url": "https://github.com/NOSYTLABS/clawdroid/issues"
31
+ },
32
+ "engines": {
33
+ "node": ">=18.0.0"
34
+ },
35
+ "os": [
36
+ "android",
37
+ "linux"
38
+ ],
39
+ "dependencies": {
40
+ "chalk": "^5.3.0",
41
+ "inquirer": "^9.2.12",
42
+ "ora": "^7.0.1"
43
+ }
44
+ }