openclaw-voice 1.0.0 → 1.0.2

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 (3) hide show
  1. package/README.md +117 -138
  2. package/package.json +6 -3
  3. package/index.ts +0 -9
package/README.md CHANGED
@@ -1,36 +1,40 @@
1
- # OpenClaw Voice (Expo React Native)
1
+ # OpenClaw Voice
2
2
 
3
- ![OpenClawVoice logo](assets/logo-badge.png)
3
+ ![OpenClawVoice logo](https://raw.githubusercontent.com/kyaukyuai/openclaw-voice/main/assets/logo-badge.png)
4
4
 
5
5
  [![Expo SDK 54](https://img.shields.io/badge/Expo-SDK%2054-000020?logo=expo&logoColor=white)](https://expo.dev/)
6
6
  [![React Native 0.81](https://img.shields.io/badge/React%20Native-0.81-61DAFB?logo=react&logoColor=1f2937)](https://reactnative.dev/)
7
7
  [![TypeScript 5.x](https://img.shields.io/badge/TypeScript-5.x-3178C6?logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
8
8
 
9
- A simple voice-first iOS client for OpenClaw Gateway.
9
+ Voice-first OpenClaw experience for mobile and code.
10
10
 
11
- Speak -> edit transcript -> send -> stream response.
11
+ Speak -> edit -> send -> stream response.
12
12
 
13
- ## npm Package Usage
13
+ <p align="center">
14
+ <video
15
+ src="https://github.com/user-attachments/assets/65f799f3-c87b-4c13-8b5f-23491efd5ec5"
16
+ poster="https://raw.githubusercontent.com/kyaukyuai/openclaw-voice/main/docs/screenshots/response-light.png"
17
+ controls
18
+ playsinline
19
+ preload="none"
20
+ width="360"
21
+ >
22
+ Your browser cannot play inline video.
23
+ </video>
24
+ </p>
14
25
 
15
- Install:
26
+ <p align="center">
27
+ <a href="https://github.com/user-attachments/assets/65f799f3-c87b-4c13-8b5f-23491efd5ec5"><strong>Watch demo video (MP4)</strong></a>
28
+ </p>
16
29
 
17
- ```bash
18
- npm install openclaw-voice
19
- ```
30
+ ## Why OpenClaw Voice
20
31
 
21
- Example:
32
+ - Fast voice-to-chat workflow optimized for iOS
33
+ - Reusable `GatewayClient` SDK on npm (`openclaw-voice`)
34
+ - Streaming response handling with reconnect and pairing flow support
35
+ - Secure device identity signing via Ed25519
22
36
 
23
- ```ts
24
- import { GatewayClient } from 'openclaw-voice';
25
-
26
- const client = new GatewayClient('wss://your-openclaw-gateway.example.com', {
27
- token: 'your-token',
28
- clientId: 'openclaw-ios',
29
- displayName: 'OpenClawVoice',
30
- });
31
- ```
32
-
33
- ## Quick Start (5 Minutes)
37
+ ## Run The App (5 Minutes)
34
38
 
35
39
  Prerequisites:
36
40
 
@@ -39,104 +43,127 @@ Prerequisites:
39
43
  - CocoaPods
40
44
  - A running OpenClaw Gateway endpoint (`wss://...`)
41
45
 
42
- Run one command:
46
+ Quick setup:
43
47
 
44
48
  ```bash
45
49
  bash scripts/bootstrap.sh
46
50
  ```
47
51
 
48
- What this does:
52
+ What it does:
49
53
 
50
54
  - Installs dependencies with `npm install`
51
55
  - Generates iOS native project (if missing)
52
56
  - Installs CocoaPods
53
57
  - Launches the app on a physical device (`npm run ios -- --device`)
54
58
 
55
- Or install dependencies manually:
59
+ Manual setup:
56
60
 
57
61
  ```bash
58
62
  npm install
63
+ npm run ios
59
64
  ```
60
65
 
61
- If you prefer simulator:
66
+ ## Use It As npm Package
67
+
68
+ Install:
62
69
 
63
70
  ```bash
64
- npm run ios
71
+ npm install openclaw-voice
72
+ ```
73
+
74
+ Example:
75
+
76
+ ```ts
77
+ import { GatewayClient, setStorage } from 'openclaw-voice';
78
+
79
+ // Optional: set persistent storage for device identity.
80
+ setStorage({
81
+ getString: (key) => localStorage.getItem(key) ?? undefined,
82
+ set: (key, value) => localStorage.setItem(key, value),
83
+ });
84
+
85
+ const client = new GatewayClient('wss://your-openclaw-gateway.example.com', {
86
+ token: 'your-token',
87
+ clientId: 'openclaw-ios',
88
+ displayName: 'OpenClawVoice',
89
+ role: 'operator',
90
+ scopes: ['operator.read', 'operator.write'],
91
+ caps: ['talk'],
92
+ });
93
+
94
+ client.onConnectionStateChange((state) => console.log('connection:', state));
95
+ client.onChatEvent((event) => console.log('chat event:', event.state, event.message));
96
+
97
+ await client.connect();
98
+ const result = await client.chatSend('demo-session-1', 'Hello from openclaw-voice');
99
+ console.log('runId:', result.runId);
65
100
  ```
66
101
 
67
- ## Screenshot
102
+ Notes:
68
103
 
69
- ![OpenClaw Voice UI states](docs/screenshots/openclaw-voice-v4.html.png)
104
+ - Without `setStorage`, identity is in-memory and may require re-pairing after restart.
105
+ - In React Native/Expo, load crypto/base64 polyfills before using the client when needed.
106
+
107
+ ## Screenshots
108
+
109
+ <table>
110
+ <tr>
111
+ <td align="center" width="25%">
112
+ <strong>Idle</strong><br>
113
+ <sub>Connected, waiting for input</sub><br><br>
114
+ <img src="https://raw.githubusercontent.com/kyaukyuai/openclaw-voice/main/docs/screenshots/idle.png" width="200" alt="Idle state" />
115
+ </td>
116
+ <td align="center" width="25%">
117
+ <strong>Ready to Send</strong><br>
118
+ <sub>Transcript ready, tap to send</sub><br><br>
119
+ <img src="https://raw.githubusercontent.com/kyaukyuai/openclaw-voice/main/docs/screenshots/ready-to-send.png" width="200" alt="Ready to send state" />
120
+ </td>
121
+ <td align="center" width="25%">
122
+ <strong>Sending</strong><br>
123
+ <sub>Waiting for Gateway response</sub><br><br>
124
+ <img src="https://raw.githubusercontent.com/kyaukyuai/openclaw-voice/main/docs/screenshots/sending.png" width="200" alt="Sending state" />
125
+ </td>
126
+ <td align="center" width="25%">
127
+ <strong>Response (Light)</strong><br>
128
+ <sub>Streamed response displayed</sub><br><br>
129
+ <img src="https://raw.githubusercontent.com/kyaukyuai/openclaw-voice/main/docs/screenshots/response-light.png" width="200" alt="Response in light theme" />
130
+ </td>
131
+ </tr>
132
+ </table>
70
133
 
71
134
  ## Features
72
135
 
73
136
  - Speech-to-text input using `expo-speech-recognition`
74
137
  - Editable transcript before sending
75
138
  - OpenClaw Gateway connection with URL + token/password
76
- - Streaming chat response rendering
77
- - Conversation history with per-turn status (`WAIT`, `OK`, `ERR`)
78
- - Auto-reconnect capable gateway client
79
- - Persistent settings for gateway URL, token/password, and theme (`dark` / `light`)
80
- - Device identity persistence for gateway auth (Ed25519 key pair)
81
- - Compact UI with header connection status and bottom round action button
82
-
83
- ## Tech Stack
84
-
85
- - Expo SDK 54
86
- - React Native 0.81
87
- - TypeScript
88
- - `expo-speech-recognition`
89
- - `expo-secure-store`
90
- - `expo-crypto`
91
- - `@noble/ed25519` + `@noble/hashes`
139
+ - Streaming response rendering with per-turn states (`WAIT`, `OK`, `ERR`)
140
+ - Auto reconnect support
141
+ - Persistent settings for gateway URL, token/password, and theme
142
+ - Local device identity generation/signing for gateway auth
92
143
 
93
- ## Environment Configuration
144
+ ## Environment Variables
94
145
 
95
- Copy `.env.example` to `.env` and set values for your local environment:
146
+ Copy `.env.example` to `.env`:
96
147
 
97
148
  ```bash
98
149
  cp .env.example .env
99
150
  ```
100
151
 
101
- Available variables:
102
-
103
152
  - `EXPO_PUBLIC_DEFAULT_GATEWAY_URL`
104
153
  - `EXPO_PUBLIC_DEFAULT_THEME` (`light` or `dark`)
105
154
  - `EXPO_PUBLIC_GATEWAY_CLIENT_ID` (default: `openclaw-ios`)
106
155
  - `EXPO_PUBLIC_GATEWAY_DISPLAY_NAME` (default: `OpenClawVoice`)
156
+ - `EXPO_PUBLIC_DEBUG_MODE` (`true` to show warnings in dev, default: `false`)
107
157
 
108
- Notes:
158
+ ## Connection Defaults
109
159
 
110
- - `.env` files are ignored by git.
111
- - Do not commit gateway tokens or secrets.
112
-
113
- ## Project Structure
114
-
115
- | Path | Purpose |
116
- | --- | --- |
117
- | `App.tsx` | Main UI, voice capture flow, transcript editing, gateway connect/send flow, history rendering |
118
- | `src/openclaw/client.ts` | OpenClaw Gateway WebSocket protocol client (handshake, events, requests, reconnect, keepalive) |
119
- | `src/openclaw/protocol.ts` | Protocol v3 types and event/method constants |
120
- | `src/openclaw/device-identity.ts` | Device identity generation/signing for gateway authentication |
121
- | `src/openclaw/storage.ts` | Storage abstraction used by identity module |
122
- | `crypto-polyfill.ts` | `crypto.getRandomValues`, `atob`, `btoa` polyfills for React Native runtime compatibility |
123
- | `scripts/bootstrap.sh` | One-command setup + run for iOS |
124
- | `.env.example` | Sample environment configuration |
125
- | `CONTRIBUTING.md` | Contribution workflow and local checks |
126
- | `docs/TROUBLESHOOTING.md` | Common issues and fixes |
127
- | `app.json` | Expo configuration and microphone/speech permission strings |
128
-
129
- ## How to Use
130
-
131
- 1. Launch the app.
132
- 2. If not connected, the gateway panel opens automatically.
133
- 3. Enter your `Gateway URL` (example: `wss://your-openclaw-gateway.example.com`) and optional `Token / Password`.
134
- 4. Tap `Connect`.
135
- 5. Hold the round mic button to speak.
136
- 6. Release to stop recognition.
137
- 7. Edit transcript if needed.
138
- 8. Tap the send button (same round button state) to submit.
139
- 9. View streamed response in History.
160
+ - `clientId: openclaw-ios`
161
+ - `displayName: OpenClawVoice`
162
+ - `role: operator`
163
+ - `scopes: operator.read, operator.write`
164
+ - `caps: talk`
165
+
166
+ Device identity is generated locally and reused when persistent storage is available.
140
167
 
141
168
  ## Scripts
142
169
 
@@ -147,53 +174,21 @@ Notes:
147
174
  - `npm run typecheck` - Run TypeScript checks
148
175
  - `npm run build:package` - Build npm package files to `dist/`
149
176
 
150
- ## Connection and Auth Notes
151
-
152
- The client currently connects with these defaults:
153
-
154
- - `clientId: openclaw-ios`
155
- - `displayName: OpenClawVoice`
156
- - `role: operator`
157
- - `scopes: operator.read, operator.write`
158
- - `caps: talk`
159
- - Device identity is generated locally and reused via secure persistence when available.
160
- - If identity is reset, the gateway may request pairing again.
161
-
162
- ## Speech Recognition Behavior
163
-
164
- - Language is selectable from the Gateway panel (`日本語 / English`).
165
- - Interim results are shown while speaking.
166
- - Final recognition text is stored in editable transcript.
167
- - Some `aborted/cancelled` recognition errors are intentionally ignored when caused by expected stop flow.
168
-
169
- ## Configuration Persistence
170
-
171
- These values are persisted locally:
172
-
173
- - Gateway URL
174
- - Token/password
175
- - Theme mode
176
- - Device identity record
177
+ ## Security Notes
177
178
 
178
- `expo-secure-store` is used when available. If native module loading fails, the app falls back to in-memory storage for runtime continuity.
179
+ - Do not commit private gateway tokens.
180
+ - Use secure `wss://` endpoints.
181
+ - Preferred exposure path order: Tailscale/WireGuard -> Cloudflare Tunnel + access control -> Hardened VPS reverse proxy.
182
+ - Do not expose raw Gateway ports publicly.
183
+ - Rotate credentials and keep TLS/server packages up to date.
179
184
 
180
185
  ## Troubleshooting
181
186
 
182
- See [docs/TROUBLESHOOTING.md](docs/TROUBLESHOOTING.md) for known issues and fixes.
183
-
184
- ## UI / UX Design Direction
185
-
186
- The current UI is intentionally minimal:
187
-
188
- - Small header with live connection chip
189
- - Gateway settings panel shown only when disconnected
190
- - Card-based transcript/history surfaces with subtle border + shadow
191
- - Bottom round icon-only primary action (mic/send state switch)
192
- - Dark/light theme toggle in header
187
+ See [docs/TROUBLESHOOTING.md](docs/TROUBLESHOOTING.md).
193
188
 
194
189
  ## Contributing
195
190
 
196
- See [CONTRIBUTING.md](CONTRIBUTING.md) for branch/PR workflow and local checks.
191
+ See [CONTRIBUTING.md](CONTRIBUTING.md).
197
192
 
198
193
  ## CI
199
194
 
@@ -203,7 +198,7 @@ GitHub Actions runs on push/PR:
203
198
  - Lint (`npm run lint --if-present`)
204
199
  - Tests (`npm test --if-present`)
205
200
 
206
- Issue and PR templates are available in `.github/`.
201
+ Issue/PR templates are in `.github/`.
207
202
 
208
203
  ## Publish to npm
209
204
 
@@ -212,26 +207,10 @@ npm run build:package
212
207
  npm publish --access public
213
208
  ```
214
209
 
215
- ## Security Notes
216
-
217
- - Do not commit private gateway tokens.
218
- - Use secure `wss://` endpoints.
219
- - Pair only trusted devices in OpenClaw.
220
- - Prefer private network exposure first. Recommended order:
221
- 1. Tailscale/WireGuard private network
222
- 2. Cloudflare Tunnel with access control
223
- 3. Hardened VPS reverse proxy
224
- - Do not expose the Gateway port directly to the public internet.
225
- - If using Cloudflare Tunnel or VPS, require authentication at both layers:
226
- - Edge access control (IdP login / service token / mTLS as applicable)
227
- - Gateway token/password validation
228
- - Restrict source access (ACL / allowlist), rotate tokens regularly, and revoke leaked credentials immediately.
229
- - Keep TLS certificates and server packages updated, and enable request/rate logging for incident response.
230
-
231
210
  ## Acknowledgements
232
211
 
233
- - [`expo-openclaw-chat`](https://github.com/brunobar79/expo-openclaw-chat) for protocol/client reference and implementation ideas.
212
+ - [`expo-openclaw-chat`](https://github.com/brunobar79/expo-openclaw-chat)
234
213
 
235
214
  ## License
236
215
 
237
- This project is licensed under the MIT License. See [LICENSE](LICENSE).
216
+ MIT. See [LICENSE](LICENSE).
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "openclaw-voice",
3
- "version": "1.0.0",
4
- "main": "index.ts",
3
+ "version": "1.0.2",
4
+ "main": "./dist/package.js",
5
5
  "types": "./dist/package.d.ts",
6
6
  "exports": {
7
7
  ".": {
@@ -24,7 +24,10 @@
24
24
  "web": "expo start --web",
25
25
  "typecheck": "tsc --noEmit",
26
26
  "build:package": "tsc -p tsconfig.package.json",
27
- "prepack": "npm run build:package"
27
+ "prepare:publish-manifest": "node scripts/switch-package-manifest.mjs prepare",
28
+ "restore:publish-manifest": "node scripts/switch-package-manifest.mjs restore",
29
+ "prepack": "npm run build:package && npm run prepare:publish-manifest",
30
+ "postpack": "npm run restore:publish-manifest"
28
31
  },
29
32
  "dependencies": {
30
33
  "@expo/vector-icons": "^15.0.3",
package/index.ts DELETED
@@ -1,9 +0,0 @@
1
- import './crypto-polyfill';
2
- import { registerRootComponent } from 'expo';
3
-
4
- import App from './App';
5
-
6
- // registerRootComponent calls AppRegistry.registerComponent('main', () => App);
7
- // It also ensures that whether you load the app in Expo Go or in a native build,
8
- // the environment is set up appropriately
9
- registerRootComponent(App);