clawdex-mobile 1.3.2 → 2.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.
Files changed (48) hide show
  1. package/.github/workflows/ci.yml +1 -1
  2. package/.github/workflows/npm-release.yml +18 -0
  3. package/AGENTS.md +3 -3
  4. package/README.md +101 -541
  5. package/apps/mobile/.env.example +1 -2
  6. package/apps/mobile/App.tsx +261 -68
  7. package/apps/mobile/app.json +31 -5
  8. package/apps/mobile/assets/brand/splash-icon-white.png +0 -0
  9. package/apps/mobile/eas.json +30 -0
  10. package/apps/mobile/package.json +22 -21
  11. package/apps/mobile/plugins/withAndroidCleartextTraffic.js +14 -0
  12. package/apps/mobile/src/api/__tests__/ws.test.ts +44 -6
  13. package/apps/mobile/src/api/chatMapping.ts +48 -8
  14. package/apps/mobile/src/api/client.ts +6 -0
  15. package/apps/mobile/src/api/types.ts +11 -0
  16. package/apps/mobile/src/api/ws.ts +52 -10
  17. package/apps/mobile/src/bridgeUrl.ts +105 -0
  18. package/apps/mobile/src/components/ActivityBar.tsx +32 -13
  19. package/apps/mobile/src/components/ChatHeader.tsx +3 -2
  20. package/apps/mobile/src/components/ChatInput.tsx +246 -91
  21. package/apps/mobile/src/components/ChatMessage.tsx +108 -4
  22. package/apps/mobile/src/config.ts +11 -29
  23. package/apps/mobile/src/hooks/useVoiceRecorder.ts +264 -0
  24. package/apps/mobile/src/navigation/DrawerContent.tsx +18 -8
  25. package/apps/mobile/src/screens/GitScreen.tsx +1 -1
  26. package/apps/mobile/src/screens/MainScreen.tsx +906 -268
  27. package/apps/mobile/src/screens/OnboardingScreen.tsx +1132 -0
  28. package/apps/mobile/src/screens/PrivacyScreen.tsx +1 -1
  29. package/apps/mobile/src/screens/SettingsScreen.tsx +65 -1
  30. package/apps/mobile/src/screens/TerminalScreen.tsx +1 -1
  31. package/apps/mobile/src/screens/TermsScreen.tsx +1 -1
  32. package/docs/app-review-notes.md +7 -2
  33. package/docs/eas-builds.md +91 -0
  34. package/docs/realtime-streaming-limitations.md +84 -0
  35. package/docs/setup-and-operations.md +239 -0
  36. package/docs/troubleshooting.md +121 -0
  37. package/docs/voice-transcription.md +87 -0
  38. package/package.json +8 -16
  39. package/scripts/setup-secure-dev.sh +122 -8
  40. package/scripts/setup-wizard.sh +342 -122
  41. package/scripts/start-bridge-secure.sh +7 -1
  42. package/scripts/sync-versions.js +63 -0
  43. package/services/rust-bridge/.env.example +1 -1
  44. package/services/rust-bridge/Cargo.lock +1104 -23
  45. package/services/rust-bridge/Cargo.toml +3 -1
  46. package/services/rust-bridge/package.json +1 -1
  47. package/services/rust-bridge/src/main.rs +587 -12
  48. package/apps/mobile/metro.config.js +0 -3
@@ -4,7 +4,6 @@ import {
4
4
  Alert,
5
5
  Linking,
6
6
  Pressable,
7
- SafeAreaView,
8
7
  ScrollView,
9
8
  StyleSheet,
10
9
  Text,
@@ -12,6 +11,7 @@ import {
12
11
  } from 'react-native';
13
12
  import { BlurView } from 'expo-blur';
14
13
  import { LinearGradient } from 'expo-linear-gradient';
14
+ import { SafeAreaView } from 'react-native-safe-area-context';
15
15
 
16
16
  import { colors, radius, spacing, typography } from '../theme';
17
17
 
@@ -6,12 +6,12 @@ import {
6
6
  ActivityIndicator,
7
7
  Modal,
8
8
  Pressable,
9
- SafeAreaView,
10
9
  ScrollView,
11
10
  StyleSheet,
12
11
  Text,
13
12
  View,
14
13
  } from 'react-native';
14
+ import { SafeAreaView } from 'react-native-safe-area-context';
15
15
 
16
16
  import type { HostBridgeApiClient } from '../api/client';
17
17
  import type { ApprovalMode, ModelOption, ReasoningEffort } from '../api/types';
@@ -30,6 +30,8 @@ interface SettingsScreenProps {
30
30
  effort: ReasoningEffort | null
31
31
  ) => void;
32
32
  onApprovalModeChange?: (mode: ApprovalMode) => void;
33
+ onEditBridgeUrl?: () => void;
34
+ onResetOnboarding?: () => void;
33
35
  onOpenDrawer: () => void;
34
36
  onOpenPrivacy: () => void;
35
37
  onOpenTerms: () => void;
@@ -44,6 +46,8 @@ export function SettingsScreen({
44
46
  approvalMode,
45
47
  onDefaultModelSettingsChange,
46
48
  onApprovalModeChange,
49
+ onEditBridgeUrl,
50
+ onResetOnboarding,
47
51
  onOpenDrawer,
48
52
  onOpenPrivacy,
49
53
  onOpenTerms,
@@ -301,6 +305,26 @@ export function SettingsScreen({
301
305
  <Text selectable style={styles.valueText}>
302
306
  {bridgeUrl}
303
307
  </Text>
308
+ <Pressable
309
+ onPress={onEditBridgeUrl}
310
+ style={({ pressed }) => [
311
+ styles.bridgeEditBtn,
312
+ pressed && styles.bridgeEditBtnPressed,
313
+ ]}
314
+ >
315
+ <Ionicons name="swap-horizontal-outline" size={15} color={colors.textPrimary} />
316
+ <Text style={styles.bridgeEditBtnText}>Change bridge URL</Text>
317
+ </Pressable>
318
+ <Pressable
319
+ onPress={onResetOnboarding}
320
+ style={({ pressed }) => [
321
+ styles.bridgeResetBtn,
322
+ pressed && styles.bridgeResetBtnPressed,
323
+ ]}
324
+ >
325
+ <Ionicons name="refresh-circle-outline" size={15} color={colors.error} />
326
+ <Text style={styles.bridgeResetBtnText}>Reset onboarding</Text>
327
+ </Pressable>
304
328
  </BlurView>
305
329
 
306
330
  <Text style={[styles.sectionLabel, styles.sectionLabelGap]}>Health</Text>
@@ -569,6 +593,46 @@ const styles = StyleSheet.create({
569
593
  paddingVertical: spacing.md,
570
594
  fontSize: 14,
571
595
  },
596
+ bridgeEditBtn: {
597
+ marginBottom: spacing.md,
598
+ borderRadius: radius.md,
599
+ borderWidth: 1,
600
+ borderColor: colors.border,
601
+ backgroundColor: colors.bgMain,
602
+ flexDirection: 'row',
603
+ alignItems: 'center',
604
+ justifyContent: 'center',
605
+ gap: spacing.xs,
606
+ paddingVertical: spacing.sm,
607
+ },
608
+ bridgeEditBtnPressed: {
609
+ opacity: 0.82,
610
+ },
611
+ bridgeEditBtnText: {
612
+ ...typography.caption,
613
+ color: colors.textPrimary,
614
+ fontWeight: '600',
615
+ },
616
+ bridgeResetBtn: {
617
+ marginBottom: spacing.md,
618
+ borderRadius: radius.md,
619
+ borderWidth: 1,
620
+ borderColor: colors.error,
621
+ backgroundColor: 'rgba(239, 68, 68, 0.08)',
622
+ flexDirection: 'row',
623
+ alignItems: 'center',
624
+ justifyContent: 'center',
625
+ gap: spacing.xs,
626
+ paddingVertical: spacing.sm,
627
+ },
628
+ bridgeResetBtnPressed: {
629
+ opacity: 0.82,
630
+ },
631
+ bridgeResetBtnText: {
632
+ ...typography.caption,
633
+ color: colors.error,
634
+ fontWeight: '700',
635
+ },
572
636
  row: {
573
637
  flexDirection: 'row',
574
638
  justifyContent: 'space-between',
@@ -5,13 +5,13 @@ import {
5
5
  KeyboardAvoidingView,
6
6
  Platform,
7
7
  Pressable,
8
- SafeAreaView,
9
8
  ScrollView,
10
9
  StyleSheet,
11
10
  Text,
12
11
  TextInput,
13
12
  View,
14
13
  } from 'react-native';
14
+ import { SafeAreaView } from 'react-native-safe-area-context';
15
15
 
16
16
  import type { HostBridgeApiClient } from '../api/client';
17
17
  import type { HostBridgeWsClient } from '../api/ws';
@@ -4,7 +4,6 @@ import {
4
4
  Alert,
5
5
  Linking,
6
6
  Pressable,
7
- SafeAreaView,
8
7
  ScrollView,
9
8
  StyleSheet,
10
9
  Text,
@@ -12,6 +11,7 @@ import {
12
11
  } from 'react-native';
13
12
  import { BlurView } from 'expo-blur';
14
13
  import { LinearGradient } from 'expo-linear-gradient';
14
+ import { SafeAreaView } from 'react-native-safe-area-context';
15
15
 
16
16
  import { colors, radius, spacing, typography } from '../theme';
17
17
 
@@ -57,12 +57,17 @@ BRIDGE_CORS_ORIGINS=http://localhost:19006,http://localhost:8081
57
57
  - In `apps/mobile/.env`, set:
58
58
 
59
59
  ```env
60
- EXPO_PUBLIC_HOST_BRIDGE_URL=http://<mac-lan-ip>:8787
61
60
  EXPO_PUBLIC_HOST_BRIDGE_TOKEN=<review-token>
62
61
  EXPO_PUBLIC_PRIVACY_POLICY_URL=https://<your-policy-url>
63
62
  EXPO_PUBLIC_TERMS_OF_SERVICE_URL=https://<your-terms-url>
64
63
  ```
65
64
 
65
+ - In app onboarding, enter:
66
+
67
+ ```text
68
+ http://<mac-lan-ip>:8787
69
+ ```
70
+
66
71
  ## Reviewer Walkthrough
67
72
 
68
73
  1. Launch app.
@@ -76,7 +81,7 @@ EXPO_PUBLIC_TERMS_OF_SERVICE_URL=https://<your-terms-url>
76
81
  ## Security And Privacy Notes For Review
77
82
 
78
83
  - Bridge auth token is required by default.
79
- - WebSocket auth uses Authorization header (query-token fallback is opt-in only).
84
+ - WebSocket auth uses Authorization headers and supports query-token fallback for Android compatibility.
80
85
  - Bridge can be run localhost-only; LAN mode is user-configured.
81
86
  - Terminal commands are constrained by server-side allowlist and can be fully disabled.
82
87
  - Requested command working directory is constrained within configured bridge root.
@@ -0,0 +1,91 @@
1
+ # EAS Builds and Distribution
2
+
3
+ Use this guide for standalone app builds/distribution.
4
+
5
+ ## Where To Run EAS Commands
6
+
7
+ Run EAS commands from `apps/mobile`.
8
+
9
+ Why:
10
+
11
+ - Expo app config is in `apps/mobile/app.json`
12
+ - EAS config is in `apps/mobile/eas.json`
13
+
14
+ ```bash
15
+ cd apps/mobile
16
+ ```
17
+
18
+ You can also run from repo root with workspace scoping:
19
+
20
+ ```bash
21
+ npm exec --workspace apps/mobile -- eas <command>
22
+ ```
23
+
24
+ ## Prerequisites
25
+
26
+ - `eas-cli` installed (`npm install -g eas-cli`)
27
+ - Logged in (`eas login`)
28
+ - Expo project linked (`eas project:info`)
29
+
30
+ ## Build Profiles
31
+
32
+ Current profiles in `apps/mobile/eas.json`:
33
+
34
+ - `development` (dev client, internal distribution)
35
+ - `preview` (internal distribution)
36
+ - `production` (store/prod, auto-increment)
37
+
38
+ ## Common Build Commands
39
+
40
+ From `apps/mobile`:
41
+
42
+ ```bash
43
+ # Internal/dev-client builds
44
+ eas build --platform ios --profile development
45
+ eas build --platform android --profile development
46
+
47
+ # Internal preview builds
48
+ eas build --platform ios --profile preview
49
+ eas build --platform android --profile preview
50
+
51
+ # Production builds
52
+ eas build --platform ios --profile production
53
+ eas build --platform android --profile production
54
+
55
+ # Both platforms
56
+ eas build --platform all --profile preview
57
+ ```
58
+
59
+ Track builds:
60
+
61
+ ```bash
62
+ eas build:list --limit 10
63
+ eas build:view <BUILD_ID>
64
+ ```
65
+
66
+ ## Submit To Stores
67
+
68
+ ```bash
69
+ eas submit --platform ios --latest --profile production
70
+ eas submit --platform android --latest --profile production
71
+ ```
72
+
73
+ ## Local Native Build Option (No EAS Cloud)
74
+
75
+ If you want local native builds instead:
76
+
77
+ ```bash
78
+ npx expo run:ios
79
+ npx expo run:android
80
+ ```
81
+
82
+ For iOS local device/signed builds, Apple signing/tooling is still required.
83
+
84
+ ## iOS Distribution Reality
85
+
86
+ Without a public App Store release, iOS distribution still requires Apple provisioning paths:
87
+
88
+ 1. Internal/dev provisioning with device allowlist
89
+ 2. TestFlight private testing
90
+
91
+ Cloud builds are possible without public App Store listing, but signing/provisioning requirements still apply.
@@ -75,3 +75,87 @@ To get strict realtime parity across CLI and mobile, move to a single live event
75
75
  2. Make clients attach to the exact same running app-server stream/session boundary.
76
76
 
77
77
  Without this architectural change, the hybrid model remains the pragmatic and low-risk approach.
78
+
79
+ ## Incident Note: February 28, 2026 Live-Sync Regression
80
+
81
+ ### Symptom
82
+ Mobile chat showed persisted messages, but did not show live activity/reasoning updates (`codex/event/*`, `thread/status/changed`) for CLI-origin turns.
83
+
84
+ ### Root Cause
85
+ Rust bridge rollout discovery scheduler used a modulo condition that could never become true when the discovery interval was `1`.
86
+
87
+ - Previous behavior: discovery did not run for that interval value.
88
+ - Effect: rollout files were not tracked, so no CLI live-tail notifications were emitted.
89
+
90
+ ### Fix Applied
91
+ Live-sync discovery scheduling was hardened so it is valid for all interval values and always runs on first tick.
92
+
93
+ Operational result:
94
+
95
+ 1. Rollout files are discovered consistently.
96
+ 2. CLI-origin event lines are tailed and converted into bridge notifications.
97
+ 3. Mobile receives activity/reasoning status in realtime again.
98
+
99
+ ## Optimization Backlog (Live-Sync Observability + Reliability)
100
+
101
+ ### 1) Add `bridge/liveSync/status` RPC (recommended next)
102
+
103
+ Goal: make rollout tailing state visible from mobile/Postman without guessing.
104
+
105
+ Suggested response payload:
106
+
107
+ 1. Sessions root currently in use (`CODEX_HOME` resolved path).
108
+ 2. Discovery config (`pollIntervalMs`, `discoveryIntervalTicks`, `maxTrackedFiles`).
109
+ 3. Tracked files list:
110
+ - file path
111
+ - thread id
112
+ - originator
113
+ - include/exclude flag
114
+ - include/exclude reason
115
+ - current offset
116
+ - last seen timestamp
117
+ 4. Summary counters:
118
+ - files discovered
119
+ - files included
120
+ - lines parsed
121
+ - lines dropped (invalid JSON / filtered / duplicate)
122
+ - notifications emitted by method bucket
123
+ 5. Last error (if any) in discovery/poll loop.
124
+
125
+ Why this helps:
126
+
127
+ 1. Explains "why no live updates" immediately.
128
+ 2. Reduces debugging time for CLI vs mobile parity issues.
129
+ 3. Enables lightweight health checks and QA verification.
130
+
131
+ ### 2) Add discovery/poll loop metrics
132
+
133
+ Expose counters for:
134
+
135
+ 1. discovery runs
136
+ 2. poll runs
137
+ 3. per-file parse errors
138
+ 4. event mapping misses
139
+ 5. replay buffer writes/drops
140
+
141
+ These can be returned by the status RPC and optionally logged to stderr in dev mode.
142
+
143
+ ### 3) Add dedup + mapping diagnostics for dropped events
144
+
145
+ Track bounded recent reasons for dropped lines:
146
+
147
+ 1. duplicate hash
148
+ 2. unsupported rollout record type
149
+ 3. missing thread id
150
+ 4. originator filtered
151
+
152
+ This will clarify whether events are not emitted due to filtering or malformed source lines.
153
+
154
+ ### 4) Add a short runbook for operators
155
+
156
+ When live updates are missing, check in this order:
157
+
158
+ 1. `bridge/events/replay` contains recent `codex/event/*` or not.
159
+ 2. `bridge/liveSync/status` include/exclude reason for newest rollout file.
160
+ 3. newest rollout file `session_meta.originator` and resolved thread id fields.
161
+ 4. mobile selected thread id matches emitted thread id.
@@ -0,0 +1,239 @@
1
+ # Setup and Operations
2
+
3
+ This guide is the detailed companion to the top-level `README.md`.
4
+
5
+ ## Onboarding Output Cues
6
+
7
+ After `clawdex init`, expected sequence:
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
14
+
15
+ ## Manual Secure Setup (No Wizard)
16
+
17
+ ### 1) Install dependencies
18
+
19
+ ```bash
20
+ npm install
21
+ ```
22
+
23
+ ### 2) Generate secure runtime config
24
+
25
+ ```bash
26
+ npm run secure:setup
27
+ ```
28
+
29
+ Creates/updates:
30
+
31
+ - `.env.secure` (bridge runtime config + token)
32
+ - `apps/mobile/.env` (mobile token + optional runtime knobs)
33
+
34
+ ### 3) Start bridge
35
+
36
+ ```bash
37
+ npm run secure:bridge
38
+ ```
39
+
40
+ ### 4) Start Expo
41
+
42
+ ```bash
43
+ npm run mobile
44
+ ```
45
+
46
+ `npm run mobile` uses `scripts/start-expo.sh`, which sets `REACT_NATIVE_PACKAGER_HOSTNAME` from your secure config so QR resolution is predictable.
47
+
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
+ ## Advanced Knobs
51
+
52
+ Optional environment variables:
53
+
54
+ - `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
57
+ - `EXPO_AUTO_REPAIR=true` — auto-repair React Native runtime on `npm run mobile`
58
+ - `EXPO_CLEAR_CACHE=true` — force `expo start --clear` via `npm run mobile`
59
+
60
+ ## Teardown / Cleanup
61
+
62
+ ```bash
63
+ npm run teardown
64
+ ```
65
+
66
+ Can:
67
+
68
+ - stop Expo + bridge
69
+ - remove generated artifacts (`.env.secure`, `.bridge.log`, `.expo.log`, pid files)
70
+ - optionally reset `apps/mobile/.env` from `.env.example`
71
+ - optionally run `tailscale down`
72
+
73
+ Non-interactive mode:
74
+
75
+ ```bash
76
+ npm run teardown -- --yes
77
+ ```
78
+
79
+ ## Environment Reference
80
+
81
+ ### Bridge runtime (`.env.secure`, generated)
82
+
83
+ | Variable | Purpose |
84
+ |---|---|
85
+ | `BRIDGE_HOST` | bind host for rust bridge |
86
+ | `BRIDGE_PORT` | bridge port (default `8787`) |
87
+ | `BRIDGE_AUTH_TOKEN` | required auth token |
88
+ | `BRIDGE_ALLOW_QUERY_TOKEN_AUTH` | query-token auth fallback |
89
+ | `CODEX_CLI_BIN` | codex executable |
90
+ | `BRIDGE_WORKDIR` | absolute working directory for terminal/git |
91
+ | `BRIDGE_ALLOW_OUTSIDE_ROOT_CWD` | allow terminal/git `cwd` outside `BRIDGE_WORKDIR` |
92
+
93
+ ### Mobile runtime (`apps/mobile/.env`, generated/updated)
94
+
95
+ | Variable | Purpose |
96
+ |---|---|
97
+ | `EXPO_PUBLIC_HOST_BRIDGE_TOKEN` | token sent by mobile client |
98
+ | `EXPO_PUBLIC_ALLOW_QUERY_TOKEN_AUTH` | query-token behavior for WebSocket auth fallback |
99
+ | `EXPO_PUBLIC_ALLOW_INSECURE_REMOTE_BRIDGE` | suppress insecure-HTTP warning |
100
+ | `EXPO_PUBLIC_PRIVACY_POLICY_URL` | in-app Privacy link |
101
+ | `EXPO_PUBLIC_TERMS_OF_SERVICE_URL` | in-app Terms link |
102
+
103
+ ## Production Readiness Checklist
104
+
105
+ - Keep bridge network-private only (Tailscale/private LAN/VPN + host firewall)
106
+ - Require `BRIDGE_AUTH_TOKEN`
107
+ - Keep `BRIDGE_ALLOW_QUERY_TOKEN_AUTH=true` only on private networks (required for Android WS auth fallback)
108
+ - Do not set `BRIDGE_ALLOW_INSECURE_NO_AUTH=true` outside local debugging
109
+ - Scope `BRIDGE_WORKDIR` to minimal required root
110
+ - Use strict default approvals on mobile
111
+ - Treat `Session`/`Allow similar` approval actions as privileged
112
+ - Run bridge under a supervisor with restart policy
113
+ - Rotate bridge tokens periodically and on device loss
114
+ - Keep `codex`, Node deps, Expo SDK, and OS patches updated
115
+
116
+ ## Verifying Setup
117
+
118
+ ### Bridge health
119
+
120
+ ```bash
121
+ source .env.secure
122
+ curl "http://$BRIDGE_HOST:$BRIDGE_PORT/health"
123
+ ```
124
+
125
+ Expected response contains `"status":"ok"`.
126
+
127
+ ### In-app smoke test
128
+
129
+ 1. Open app and verify Settings reports bridge connected
130
+ 2. Set `Start Directory` from sidebar (optional)
131
+ 3. Create a chat and send a prompt
132
+ 4. Switch to Plan mode and send prompt that triggers clarifying options
133
+ 5. Verify clarification flow can submit
134
+ 6. Open Git from header and verify status/diff/commit/push behavior
135
+ 7. Test attachment menu (`+`) with workspace path + phone file/image
136
+ 8. Run long task and verify stop button interrupts run and transcript logs stop
137
+
138
+ ## Chat Controls (Workspace, Model, Mode, Approvals)
139
+
140
+ ### Choosing Start Directory
141
+
142
+ 1. Open sidebar
143
+ 2. Under `Start Directory`, pick:
144
+ - `Bridge default workspace`, or
145
+ - a discovered workspace path from existing chats
146
+
147
+ Behavior:
148
+
149
+ - Applies to new chats
150
+ - Existing chats retain their own workspace unless changed
151
+
152
+ ### Model and Slash Commands
153
+
154
+ Supported mobile slash commands:
155
+
156
+ - `/help`
157
+ - `/new`
158
+ - `/model [model-id]`
159
+ - `/plan [on|off|prompt]`
160
+ - `/status`
161
+ - `/rename <new-name>`
162
+ - `/compact`
163
+ - `/review`
164
+ - `/fork`
165
+ - `/diff`
166
+
167
+ ### Plan Mode and Clarifications
168
+
169
+ - Plan mode is sent through `turn/start` via structured `collaborationMode`
170
+ - App can auto-switch to plan mode on plan events or when server requests it
171
+ - Structured clarifications open a dedicated modal
172
+ - Numbered plain-text options are rendered as tappable fallback choices
173
+
174
+ ### Approval UX
175
+
176
+ Approval banner actions:
177
+
178
+ - `Deny`
179
+ - `Allow once`
180
+ - `Session`
181
+ - `Allow similar` (when available)
182
+
183
+ Approval events are surfaced via `bridge/approval.requested` and `bridge/approval.resolved`.
184
+
185
+ ## NPM Release Automation
186
+
187
+ Workflow: `.github/workflows/npm-release.yml`
188
+
189
+ Required repo secret:
190
+
191
+ - `NPM_TOKEN`
192
+
193
+ Typical release flow (from `main`):
194
+
195
+ ```bash
196
+ npm version patch
197
+ git push origin main --follow-tags
198
+ ```
199
+
200
+ Automation verifies tag/version consistency and publishes to npm.
201
+
202
+ ## API Summary (Rust Bridge)
203
+
204
+ ### Endpoints
205
+
206
+ - `GET /health`
207
+ - `GET /rpc` (WebSocket JSON-RPC)
208
+
209
+ ### Forwarded methods
210
+
211
+ - `thread/*`
212
+ - `turn/*` (includes `turn/interrupt`)
213
+ - `review/start`
214
+ - `model/list`
215
+ - `skills/list`
216
+ - `app/list`
217
+
218
+ ### Bridge RPC methods
219
+
220
+ - `bridge/health/read`
221
+ - `bridge/terminal/exec`
222
+ - `bridge/attachments/upload`
223
+ - `bridge/voice/transcribe`
224
+ - `bridge/git/status`
225
+ - `bridge/git/diff`
226
+ - `bridge/git/commit`
227
+ - `bridge/git/push`
228
+ - `bridge/approvals/list`
229
+ - `bridge/approvals/resolve`
230
+ - `bridge/userInput/resolve`
231
+
232
+ ### Notifications (examples)
233
+
234
+ - `turn/*`, `item/*`
235
+ - `bridge/approval.*`
236
+ - `bridge/userInput.*`
237
+ - `bridge/terminal/completed`
238
+ - `bridge/git/updated`
239
+ - `bridge/connection/state`