clawdex-mobile 3.0.0 → 5.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/bin/clawdex.js CHANGED
@@ -10,13 +10,14 @@ function printUsage() {
10
10
  console.log(`Usage: clawdex <command> [options]
11
11
 
12
12
  Commands:
13
- init [--no-start] [--platform <mobile|ios|android>]
14
- Run interactive onboarding and secure setup.
15
- By default, this also starts bridge + Expo at the end.
16
- Use --no-start to skip auto-launch.
13
+ init [--no-start]
14
+ Run interactive bridge onboarding and secure setup.
15
+ By default, this also starts the secure bridge in the foreground.
16
+ Use --no-start to configure only.
17
17
 
18
18
  stop
19
- Stop bridge + Expo services for this project.
19
+ Stop bridge services for this project.
20
+ Also stops a local Expo dev process if one was started from this checkout.
20
21
 
21
22
  upgrade [--version <latest|x.y.z>] [--restart]
22
23
  update [--version <latest|x.y.z>] [--restart]
@@ -146,7 +147,7 @@ function runUpgrade(args) {
146
147
 
147
148
  console.log(`Current clawdex-mobile version: ${previousVersion}`);
148
149
  if (!options.noStop) {
149
- console.log("Stopping running bridge/Expo services before upgrade...");
150
+ console.log("Stopping running local services before upgrade...");
150
151
  const stopResult = runScript("stop-services.sh", [], { exitOnComplete: false });
151
152
  if (!stopResult.ok) {
152
153
  console.error("error: failed to stop services before upgrade.");
Binary file
Binary file
@@ -6,11 +6,14 @@ This guide is the detailed companion to the top-level `README.md`.
6
6
 
7
7
  After `clawdex init`, expected sequence:
8
8
 
9
- 1. Bridge health passes (`Bridge health check passed.`)
10
- 2. Expo starts (`Starting Expo (mobile) in background...`)
11
- 3. You may briefly see a spinner (`Waiting for Expo output - ...`)
12
- 4. Expo output begins (`expo start --host lan`, QR block, `Metro waiting on exp://...`)
13
- 5. Press Enter to detach onboarding while Expo + bridge keep running
9
+ 1. Secure config is written or reused
10
+ 2. The bridge starts in the foreground
11
+ 3. A pairing QR is printed for the mobile app
12
+ 4. Bridge logs stay attached until you stop the process
13
+
14
+ Published npm releases bundle prebuilt bridge binaries for `darwin-arm64`, `darwin-x64`, `linux-x64`, and `win32-x64`. On those hosts, normal bridge startup does not require a Rust compile.
15
+
16
+ `clawdex init` does not run a project-local `npm install` for the published CLI path. The only required npm install there is `npm install -g clawdex-mobile@latest`.
14
17
 
15
18
  ## Manual Secure Setup (No Wizard)
16
19
 
@@ -37,7 +40,13 @@ Creates/updates:
37
40
  npm run secure:bridge
38
41
  ```
39
42
 
40
- ### 4) Start Expo
43
+ ### 4) Pair from the mobile app
44
+
45
+ Open the installed mobile app on your phone, then scan the bridge QR. If needed, enter the bridge URL manually (for example `http://100.x.y.z:8787` or `http://192.168.x.y:8787`). The chosen bridge URL is stored on-device and can be changed later in Settings.
46
+
47
+ ## Local Mobile Development Only
48
+
49
+ If you are developing the mobile app from this repo, start Expo separately:
41
50
 
42
51
  ```bash
43
52
  npm run mobile
@@ -45,15 +54,12 @@ npm run mobile
45
54
 
46
55
  `npm run mobile` uses `scripts/start-expo.sh`, which sets `REACT_NATIVE_PACKAGER_HOSTNAME` from your secure config so QR resolution is predictable.
47
56
 
48
- On first app launch, onboarding will ask for your bridge URL (for example `http://100.x.y.z:8787` or `http://192.168.x.y:8787`). This URL is stored on-device and can be changed later in Settings.
49
-
50
57
  ## Advanced Knobs
51
58
 
52
59
  Optional environment variables:
53
60
 
54
61
  - `CLAWDEX_SETUP_VERBOSE=true` — show full installer output
55
- - `BRIDGE_HEALTH_WAIT_SECS=300` — max wait for bridge `/health`
56
- - `EXPO_OUTPUT_WAIT_SECS=90` — spinner timeout before streaming Expo logs
62
+ - `CLAWDEX_BRIDGE_FORCE_SOURCE_BUILD=true` — ignore a bundled bridge binary and build from local Rust sources instead
57
63
  - `EXPO_AUTO_REPAIR=true` — auto-repair React Native runtime on `npm run mobile`
58
64
  - `EXPO_CLEAR_CACHE=true` — force `expo start --clear` via `npm run mobile`
59
65
 
@@ -65,7 +71,8 @@ npm run teardown
65
71
 
66
72
  Can:
67
73
 
68
- - stop Expo + bridge
74
+ - stop the bridge
75
+ - also stop local Expo if you started it from this repo
69
76
  - remove generated artifacts (`.env.secure`, `.bridge.log`, `.expo.log`, pid files)
70
77
  - optionally reset `apps/mobile/.env` from `.env.example`
71
78
  - optionally run `tailscale down`
@@ -94,7 +101,7 @@ npm run teardown -- --yes
94
101
 
95
102
  | Variable | Purpose |
96
103
  |---|---|
97
- | `EXPO_PUBLIC_HOST_BRIDGE_TOKEN` | token sent by mobile client |
104
+ | `EXPO_PUBLIC_HOST_BRIDGE_TOKEN` | token used by local mobile dev builds |
98
105
  | `EXPO_PUBLIC_ALLOW_QUERY_TOKEN_AUTH` | query-token behavior for WebSocket auth fallback |
99
106
  | `EXPO_PUBLIC_ALLOW_INSECURE_REMOTE_BRIDGE` | suppress insecure-HTTP warning |
100
107
  | `EXPO_PUBLIC_PRIVACY_POLICY_URL` | in-app Privacy link |
@@ -1,23 +1,17 @@
1
1
  # Troubleshooting
2
2
 
3
- ## Onboarding looks stuck before Expo logs appear
3
+ ## Bridge startup seems slow
4
4
 
5
- - Expo startup can be slow on first launch.
6
- - You should see: `Waiting for Expo output ...`
7
- - Increase timeout if needed:
8
-
9
- ```bash
10
- EXPO_OUTPUT_WAIT_SECS=180 clawdex init
11
- ```
12
-
13
- - If Expo never emits logs:
14
-
15
- ```bash
16
- tail -n 120 .expo.log
17
- ```
5
+ - `clawdex init` no longer starts Expo for the shipped app.
6
+ - Published npm installs should use a bundled bridge binary on `darwin-arm64`, `darwin-x64`, `linux-x64`, and `win32-x64`.
7
+ - `clawdex init` should not run a repo `npm install` on the published CLI path.
8
+ - If startup is still compiling Rust, you are usually on a source checkout, an unsupported host, or a package without bundled bridge binaries.
9
+ - The slow parts are usually npm dependency install/repair or the first Rust bridge build on source-based setups.
10
+ - If you want to skip the interactive wizard after initial setup, use `npm run secure:bridge`.
18
11
 
19
12
  ## Expo starts but QR/network is wrong
20
13
 
14
+ - This only applies when you are developing the mobile app locally from the repo.
21
15
  - Re-run `npm run secure:setup`
22
16
  - Confirm `.env.secure` has correct `BRIDGE_HOST`
23
17
  - Restart `npm run mobile`
@@ -38,13 +32,14 @@ npm run stop:services
38
32
 
39
33
  ## Bridge auth errors (`401`, invalid token)
40
34
 
41
- - Ensure `BRIDGE_AUTH_TOKEN` in `.env.secure` matches `EXPO_PUBLIC_HOST_BRIDGE_TOKEN` in `apps/mobile/.env`
42
- - Restart bridge + Expo after token changes
35
+ - For the shipped mobile app, rescan the bridge QR or update the stored token in Settings.
36
+ - For a local dev build, also ensure `BRIDGE_AUTH_TOKEN` in `.env.secure` matches `EXPO_PUBLIC_HOST_BRIDGE_TOKEN` in `apps/mobile/.env`.
37
+ - Restart the bridge after token changes.
43
38
 
44
39
  ## Tailscale issues
45
40
 
46
41
  - Verify host and phone are on the same Tailscale network
47
- - Check host IP (`tailscale ip -4`) and mobile `.env` URL
42
+ - Check host IP (`tailscale ip -4`) and the bridge URL saved in the mobile app
48
43
 
49
44
  ## `codex` not found
50
45
 
@@ -53,6 +48,8 @@ npm run stop:services
53
48
 
54
49
  ## Bridge build fails with `linker 'cc' not found`
55
50
 
51
+ This only applies when the bridge is building from Rust source instead of using a bundled binary.
52
+
56
53
  Install C build tools:
57
54
 
58
55
  ```bash
@@ -106,7 +103,7 @@ npm run start -- --clear
106
103
 
107
104
  ## Plan mode errors (`RPC-32600` invalid `collaborationMode`)
108
105
 
109
- - Restart Expo and reload app bundle
106
+ - Restart the app and reconnect to the bridge
110
107
  - Ensure bridge/mobile revisions match
111
108
  - Run API test if needed:
112
109
 
@@ -118,4 +115,4 @@ npm run -w apps/mobile test -- --runInBand src/api/__tests__/client.test.ts
118
115
 
119
116
  - Ensure revision supports `turn/interrupt`
120
117
  - If run already finished, stop button disappears by design
121
- - Pull latest, restart bridge, reload Expo bundle
118
+ - Pull latest, restart bridge, then retry from the mobile app
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clawdex-mobile",
3
- "version": "3.0.0",
3
+ "version": "5.0.0",
4
4
  "homepage": "https://github.com/Mohit-Patil/clawdex-mobile#readme",
5
5
  "repository": {
6
6
  "type": "git",
@@ -21,11 +21,12 @@
21
21
  "ios": "./scripts/start-expo.sh ios",
22
22
  "android": "./scripts/start-expo.sh android",
23
23
  "bridge": "BRIDGE_WORKDIR=$(pwd) npm run -w @codex/rust-bridge dev",
24
+ "bridge:package:stage-current": "node ./scripts/bridge-binary.js stage-current",
24
25
  "setup:wizard": "./scripts/setup-wizard.sh",
25
26
  "stop:services": "./scripts/stop-services.sh",
26
27
  "secure:setup": "./scripts/setup-secure-dev.sh",
27
- "secure:bridge": "./scripts/start-bridge-secure.sh",
28
- "secure:bridge:dev": "BRIDGE_RUN_MODE=dev ./scripts/start-bridge-secure.sh",
28
+ "secure:bridge": "node ./scripts/start-bridge-secure.js",
29
+ "secure:bridge:dev": "node ./scripts/start-bridge-secure.js --dev",
29
30
  "bridge:ts": "BRIDGE_WORKDIR=$(pwd) npm run -w @codex/mac-bridge dev",
30
31
  "version:sync": "node scripts/sync-versions.js",
31
32
  "build": "npm run --workspaces build",
@@ -0,0 +1,200 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+
4
+ const fs = require("node:fs");
5
+ const os = require("node:os");
6
+ const path = require("node:path");
7
+
8
+ const SUPPORTED_RUNTIME_TARGETS = {
9
+ "darwin-arm64": {
10
+ platform: "darwin",
11
+ arch: "arm64",
12
+ rustTarget: "aarch64-apple-darwin",
13
+ binaryName: "codex-rust-bridge",
14
+ },
15
+ "darwin-x64": {
16
+ platform: "darwin",
17
+ arch: "x64",
18
+ rustTarget: "x86_64-apple-darwin",
19
+ binaryName: "codex-rust-bridge",
20
+ },
21
+ "linux-x64": {
22
+ platform: "linux",
23
+ arch: "x64",
24
+ rustTarget: "x86_64-unknown-linux-gnu",
25
+ binaryName: "codex-rust-bridge",
26
+ },
27
+ "win32-x64": {
28
+ platform: "win32",
29
+ arch: "x64",
30
+ rustTarget: "x86_64-pc-windows-msvc",
31
+ binaryName: "codex-rust-bridge.exe",
32
+ },
33
+ };
34
+
35
+ function repoRoot() {
36
+ return path.resolve(__dirname, "..");
37
+ }
38
+
39
+ function resolveRuntimeTarget(platform = os.platform(), arch = os.arch()) {
40
+ for (const [target, metadata] of Object.entries(SUPPORTED_RUNTIME_TARGETS)) {
41
+ if (metadata.platform === platform && metadata.arch === arch) {
42
+ return target;
43
+ }
44
+ }
45
+ return null;
46
+ }
47
+
48
+ function binaryNameForTarget(target) {
49
+ const metadata = SUPPORTED_RUNTIME_TARGETS[target];
50
+ if (!metadata) {
51
+ throw new Error(`Unsupported bridge target '${target}'.`);
52
+ }
53
+ return metadata.binaryName;
54
+ }
55
+
56
+ function packagedBinaryPath(rootDir = repoRoot(), target = resolveRuntimeTarget()) {
57
+ if (!target) {
58
+ return null;
59
+ }
60
+ return path.join(rootDir, "vendor", "bridge-binaries", target, binaryNameForTarget(target));
61
+ }
62
+
63
+ function builtBinaryPath(rootDir = repoRoot(), platform = os.platform()) {
64
+ const binaryName = platform === "win32" ? "codex-rust-bridge.exe" : "codex-rust-bridge";
65
+ return path.join(rootDir, "services", "rust-bridge", "target", "release", binaryName);
66
+ }
67
+
68
+ function ensureExecutable(filePath) {
69
+ if (process.platform !== "win32") {
70
+ fs.chmodSync(filePath, 0o755);
71
+ }
72
+ }
73
+
74
+ function stageBinary({ rootDir = repoRoot(), from, target = resolveRuntimeTarget() }) {
75
+ if (!from) {
76
+ throw new Error("--from is required.");
77
+ }
78
+ if (!target) {
79
+ throw new Error("No supported runtime target for this host. Pass --target explicitly.");
80
+ }
81
+
82
+ const destination = packagedBinaryPath(rootDir, target);
83
+ if (!destination) {
84
+ throw new Error(`Unable to compute packaged path for target '${target}'.`);
85
+ }
86
+
87
+ fs.mkdirSync(path.dirname(destination), { recursive: true });
88
+ fs.copyFileSync(from, destination);
89
+ ensureExecutable(destination);
90
+ return destination;
91
+ }
92
+
93
+ function parseArgs(argv) {
94
+ const positional = [];
95
+ const flags = {};
96
+
97
+ for (let index = 0; index < argv.length; index += 1) {
98
+ const value = argv[index];
99
+ if (!value.startsWith("--")) {
100
+ positional.push(value);
101
+ continue;
102
+ }
103
+
104
+ const key = value.slice(2);
105
+ const next = argv[index + 1];
106
+ if (!next || next.startsWith("--")) {
107
+ flags[key] = true;
108
+ continue;
109
+ }
110
+ flags[key] = next;
111
+ index += 1;
112
+ }
113
+
114
+ return { positional, flags };
115
+ }
116
+
117
+ function main() {
118
+ const { positional, flags } = parseArgs(process.argv.slice(2));
119
+ const command = positional[0];
120
+ const rootDir = flags.root ? path.resolve(flags.root) : repoRoot();
121
+
122
+ switch (command) {
123
+ case "current-target": {
124
+ const target = resolveRuntimeTarget();
125
+ if (!target) {
126
+ process.exit(1);
127
+ }
128
+ console.log(target);
129
+ return;
130
+ }
131
+ case "has-current-packaged": {
132
+ const filePath = packagedBinaryPath(rootDir);
133
+ if (filePath && fs.existsSync(filePath)) {
134
+ console.log(filePath);
135
+ return;
136
+ }
137
+ process.exit(1);
138
+ return;
139
+ }
140
+ case "current-packaged-path": {
141
+ const target = flags.target || resolveRuntimeTarget();
142
+ const filePath = packagedBinaryPath(rootDir, target);
143
+ if (!filePath) {
144
+ process.exit(1);
145
+ }
146
+ console.log(filePath);
147
+ return;
148
+ }
149
+ case "current-built-path": {
150
+ console.log(builtBinaryPath(rootDir));
151
+ return;
152
+ }
153
+ case "stage-current": {
154
+ const destination = stageBinary({
155
+ rootDir,
156
+ from: builtBinaryPath(rootDir),
157
+ target: flags.target || resolveRuntimeTarget(),
158
+ });
159
+ console.log(destination);
160
+ return;
161
+ }
162
+ case "stage": {
163
+ const destination = stageBinary({
164
+ rootDir,
165
+ from: flags.from ? path.resolve(flags.from) : "",
166
+ target: flags.target || resolveRuntimeTarget(),
167
+ });
168
+ console.log(destination);
169
+ return;
170
+ }
171
+ default:
172
+ console.error("Usage:");
173
+ console.error(" node scripts/bridge-binary.js current-target");
174
+ console.error(" node scripts/bridge-binary.js has-current-packaged");
175
+ console.error(" node scripts/bridge-binary.js current-packaged-path [--target <target>]");
176
+ console.error(" node scripts/bridge-binary.js current-built-path");
177
+ console.error(" node scripts/bridge-binary.js stage-current [--target <target>]");
178
+ console.error(" node scripts/bridge-binary.js stage --from <binary> [--target <target>]");
179
+ process.exit(1);
180
+ }
181
+ }
182
+
183
+ module.exports = {
184
+ SUPPORTED_RUNTIME_TARGETS,
185
+ binaryNameForTarget,
186
+ builtBinaryPath,
187
+ ensureExecutable,
188
+ packagedBinaryPath,
189
+ resolveRuntimeTarget,
190
+ stageBinary,
191
+ };
192
+
193
+ if (require.main === module) {
194
+ try {
195
+ main();
196
+ } catch (error) {
197
+ console.error(error instanceof Error ? error.message : String(error));
198
+ process.exit(1);
199
+ }
200
+ }