clawdex-mobile 3.0.0 → 4.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.
@@ -29,14 +29,15 @@ jobs:
29
29
  - "clawdex-mobile"
30
30
  steps:
31
31
  - name: Checkout
32
- uses: actions/checkout@v4
32
+ uses: actions/checkout@v5
33
33
 
34
34
  - name: Setup Node.js
35
- uses: actions/setup-node@v4
35
+ uses: actions/setup-node@v5
36
36
  with:
37
37
  node-version: "20"
38
38
  cache: npm
39
39
  cache-dependency-path: package-lock.json
40
+ package-manager-cache: false
40
41
 
41
42
  - name: Install dependencies
42
43
  run: npm ci
@@ -56,7 +57,7 @@ jobs:
56
57
  timeout-minutes: 20
57
58
  steps:
58
59
  - name: Checkout
59
- uses: actions/checkout@v4
60
+ uses: actions/checkout@v5
60
61
 
61
62
  - name: Setup Rust toolchain
62
63
  uses: dtolnay/rust-toolchain@stable
@@ -16,23 +16,76 @@ permissions:
16
16
  contents: write
17
17
 
18
18
  jobs:
19
+ build_bridge_binaries:
20
+ name: Build bridge binary (${{ matrix.package_target }})
21
+ runs-on: ${{ matrix.runner }}
22
+ timeout-minutes: 30
23
+ strategy:
24
+ fail-fast: false
25
+ matrix:
26
+ include:
27
+ - runner: macos-14
28
+ package_target: darwin-arm64
29
+ rust_target: aarch64-apple-darwin
30
+ binary_path: services/rust-bridge/target/aarch64-apple-darwin/release/codex-rust-bridge
31
+ - runner: ubuntu-latest
32
+ package_target: linux-x64
33
+ rust_target: x86_64-unknown-linux-gnu
34
+ binary_path: services/rust-bridge/target/x86_64-unknown-linux-gnu/release/codex-rust-bridge
35
+ - runner: windows-latest
36
+ package_target: win32-x64
37
+ rust_target: x86_64-pc-windows-msvc
38
+ binary_path: services/rust-bridge/target/x86_64-pc-windows-msvc/release/codex-rust-bridge.exe
39
+ steps:
40
+ - name: Checkout
41
+ uses: actions/checkout@v5
42
+
43
+ - name: Setup Node.js
44
+ uses: actions/setup-node@v5
45
+ with:
46
+ node-version: "20"
47
+ package-manager-cache: false
48
+
49
+ - name: Setup Rust toolchain
50
+ uses: dtolnay/rust-toolchain@stable
51
+ with:
52
+ targets: ${{ matrix.rust_target }}
53
+
54
+ - name: Cache Rust dependencies
55
+ uses: Swatinem/rust-cache@v2
56
+
57
+ - name: Build bridge binary
58
+ working-directory: services/rust-bridge
59
+ run: cargo build --release --locked --target ${{ matrix.rust_target }}
60
+
61
+ - name: Stage packaged bridge binary
62
+ run: node scripts/bridge-binary.js stage --target ${{ matrix.package_target }} --from ${{ matrix.binary_path }}
63
+
64
+ - name: Upload bridge artifact
65
+ uses: actions/upload-artifact@v6
66
+ with:
67
+ name: bridge-binaries-${{ matrix.package_target }}
68
+ path: vendor/bridge-binaries/${{ matrix.package_target }}/
69
+
19
70
  publish:
20
71
  name: Publish package to npm
72
+ needs: build_bridge_binaries
21
73
  runs-on: ubuntu-latest
22
74
  timeout-minutes: 30
23
75
  steps:
24
76
  - name: Checkout
25
- uses: actions/checkout@v4
77
+ uses: actions/checkout@v5
26
78
  with:
27
79
  fetch-depth: 0
28
80
 
29
81
  - name: Setup Node.js
30
- uses: actions/setup-node@v4
82
+ uses: actions/setup-node@v5
31
83
  with:
32
84
  node-version: "20"
33
85
  registry-url: "https://registry.npmjs.org"
34
86
  cache: npm
35
87
  cache-dependency-path: package-lock.json
88
+ package-manager-cache: false
36
89
 
37
90
  - name: Setup Rust toolchain
38
91
  uses: dtolnay/rust-toolchain@stable
@@ -43,6 +96,13 @@ jobs:
43
96
  - name: Install dependencies
44
97
  run: npm ci
45
98
 
99
+ - name: Download packaged bridge binaries
100
+ uses: actions/download-artifact@v7
101
+ with:
102
+ pattern: bridge-binaries-*
103
+ path: .
104
+ merge-multiple: true
105
+
46
106
  - name: Verify Rust bridge compiles
47
107
  working-directory: services/rust-bridge
48
108
  run: cargo check --locked
@@ -26,7 +26,7 @@ jobs:
26
26
  url: ${{ steps.deployment.outputs.page_url }}
27
27
  steps:
28
28
  - name: Checkout
29
- uses: actions/checkout@v4
29
+ uses: actions/checkout@v5
30
30
 
31
31
  - name: Configure Pages
32
32
  uses: actions/configure-pages@v5
package/README.md CHANGED
@@ -41,6 +41,8 @@ clawdex init
41
41
 
42
42
  This is the primary starting point.
43
43
 
44
+ Published npm releases bundle prebuilt Rust bridge binaries for `darwin-arm64`, `linux-x64`, and `win32-x64`, so supported hosts do not need to compile the bridge during normal startup. Intel Macs are not packaged in the npm release and fall back to a local Rust build if needed. The interactive shell-based setup helpers are still macOS/Linux-oriented today.
45
+
44
46
  `clawdex init` guides you through:
45
47
 
46
48
  1. bridge mode selection: `Local (LAN)` or `Tailscale`
@@ -48,6 +50,8 @@ This is the primary starting point.
48
50
  3. phone readiness checks for selected mode
49
51
  4. optional bridge launch in the foreground (release build)
50
52
 
53
+ This flow is bridge-only. The mobile app is already shipped, so no Expo dev server is required to pair your phone.
54
+
51
55
  When the bridge starts, it prints a pairing QR:
52
56
 
53
57
  - preferred: QR contains both `bridgeUrl + bridgeToken` (one-scan onboarding)
@@ -103,7 +107,7 @@ Optional for simulators/emulators:
103
107
  From repo root:
104
108
 
105
109
  - `npm run setup:wizard` — guided secure setup + optional bridge start
106
- - `npm run stop:services` — stop running bridge (and Expo if running)
110
+ - `npm run stop:services` — stop running bridge (and local Expo if running)
107
111
  - `npm run secure:setup` — generate/update secure env
108
112
  - `npm run secure:bridge` — start rust bridge from `.env.secure` (release profile)
109
113
  - `npm run secure:bridge:dev` — start rust bridge in dev profile
@@ -140,7 +144,14 @@ npm run secure:bridge
140
144
 
141
145
  Keep `npm run secure:bridge` running in foreground. It prints pairing QR and bridge logs.
142
146
 
143
- In a second terminal, start the app runtime:
147
+ On supported published installs, this uses the bundled bridge binary directly instead of compiling Rust on startup. Source checkouts still build from Cargo when a packaged binary is unavailable.
148
+
149
+ Then open the installed mobile app and pair it:
150
+
151
+ - preferred: scan the bridge QR to autofill URL + token
152
+ - fallback: enter the bridge URL and token manually
153
+
154
+ For local mobile development only, start Expo from the repo:
144
155
 
145
156
  ```bash
146
157
  npm run mobile
@@ -150,7 +161,7 @@ npm run mobile
150
161
 
151
162
  On first launch (or after reset):
152
163
 
153
- 1. choose mode (`Local` or `Tailscale`)
164
+ 1. start the bridge on your server
154
165
  2. scan bridge QR to autofill URL + token
155
166
  3. use `Test Connection` (health + authenticated RPC check)
156
167
  4. tap `Continue`
@@ -3,7 +3,7 @@
3
3
  "name": "Clawdex Mobile",
4
4
  "slug": "clawdex-mobile",
5
5
  "scheme": "clawdex",
6
- "version": "3.0.0",
6
+ "version": "4.0.0",
7
7
  "userInterfaceStyle": "dark",
8
8
  "orientation": "portrait",
9
9
  "icon": "./assets/brand/app-icon.png",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clawdex-mobile",
3
- "version": "3.0.0",
3
+ "version": "4.0.0",
4
4
  "private": true,
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -20,6 +20,7 @@
20
20
  "expo-audio": "~55.0.9",
21
21
  "expo-blur": "~55.0.10",
22
22
  "expo-camera": "~55.0.10",
23
+ "expo-clipboard": "~55.0.9",
23
24
  "expo-document-picker": "~55.0.9",
24
25
  "expo-file-system": "~55.0.9",
25
26
  "expo-image-picker": "~55.0.13",
@@ -383,9 +383,9 @@ describe('HostBridgeApiClient', () => {
383
383
  bridgeRoot: '/Users/mohit/work',
384
384
  allowOutsideRootCwd: true,
385
385
  workspaces: [
386
- { path: '/Users/mohit/work/app', chatCount: 3 },
387
- { path: '/Users/mohit/work/docs', chatCount: '1' },
388
- { path: '', chatCount: 99 },
386
+ { path: '/Users/mohit/work/app', chatCount: 3, updatedAt: 1700000000 },
387
+ { path: '/Users/mohit/work/docs', chatCount: '1', updatedAt: '1700001000' },
388
+ { path: '', chatCount: 99, updatedAt: 1700002000 },
389
389
  ],
390
390
  });
391
391
 
@@ -397,8 +397,16 @@ describe('HostBridgeApiClient', () => {
397
397
  bridgeRoot: '/Users/mohit/work',
398
398
  allowOutsideRootCwd: true,
399
399
  workspaces: [
400
- { path: '/Users/mohit/work/app', chatCount: 3 },
401
- { path: '/Users/mohit/work/docs', chatCount: 1 },
400
+ {
401
+ path: '/Users/mohit/work/app',
402
+ chatCount: 3,
403
+ updatedAt: new Date(1700000000 * 1000).toISOString(),
404
+ },
405
+ {
406
+ path: '/Users/mohit/work/docs',
407
+ chatCount: 1,
408
+ updatedAt: new Date(1700001000 * 1000).toISOString(),
409
+ },
402
410
  ],
403
411
  });
404
412
  });
@@ -955,6 +955,29 @@ function normalizeCwd(cwd: string | null | undefined): string | null {
955
955
  return trimmed.length > 0 ? trimmed : null;
956
956
  }
957
957
 
958
+ function readTimestampIso(value: unknown): string | null {
959
+ if (typeof value === 'string') {
960
+ const trimmed = value.trim();
961
+ if (!trimmed) {
962
+ return null;
963
+ }
964
+
965
+ const numeric = Number(trimmed);
966
+ if (Number.isFinite(numeric) && numeric > 0) {
967
+ return new Date((numeric > 1_000_000_000_000 ? numeric : numeric * 1000)).toISOString();
968
+ }
969
+
970
+ const parsedMs = Date.parse(trimmed);
971
+ return Number.isFinite(parsedMs) ? new Date(parsedMs).toISOString() : null;
972
+ }
973
+
974
+ if (typeof value === 'number' && Number.isFinite(value) && value > 0) {
975
+ return new Date((value > 1_000_000_000_000 ? value : value * 1000)).toISOString();
976
+ }
977
+
978
+ return null;
979
+ }
980
+
958
981
  function readWorkspaceListResponse(value: unknown): WorkspaceListResponse {
959
982
  const record = toRecord(value) ?? {};
960
983
  const workspacesRaw = Array.isArray(record.workspaces) ? record.workspaces : [];
@@ -981,10 +1004,12 @@ function readWorkspaceListResponse(value: unknown): WorkspaceListResponse {
981
1004
  : typeof rawChatCount === 'string'
982
1005
  ? Math.max(0, Number.parseInt(rawChatCount, 10) || 0)
983
1006
  : 0;
1007
+ const updatedAt = readTimestampIso(workspace.updatedAt);
984
1008
 
985
1009
  return {
986
1010
  path,
987
1011
  chatCount,
1012
+ ...(updatedAt ? { updatedAt } : {}),
988
1013
  };
989
1014
  })
990
1015
  .filter((entry): entry is WorkspaceListResponse['workspaces'][number] => entry !== null),
@@ -117,6 +117,7 @@ export interface UploadAttachmentResponse {
117
117
  export interface WorkspaceSummary {
118
118
  path: string;
119
119
  chatCount: number;
120
+ updatedAt?: string;
120
121
  }
121
122
 
122
123
  export interface WorkspaceListResponse {