yaver-feedback-react-native 0.2.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/README.md ADDED
@@ -0,0 +1,690 @@
1
+ # @yaver/feedback-react-native
2
+
3
+ Visual feedback SDK for Yaver. Lets testers and developers shake their phone (or tap a floating button) to capture screenshots, record voice notes, and send bug reports directly to a Yaver agent running on a dev machine. Built for vibe coding workflows where feedback needs to flow fast.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @yaver/feedback-react-native
9
+ ```
10
+
11
+ ### Peer dependencies
12
+
13
+ For full functionality, install these optional peer dependencies:
14
+
15
+ ```bash
16
+ # Device discovery (stored connections)
17
+ npm install @react-native-async-storage/async-storage
18
+
19
+ # Screenshots
20
+ npm install react-native-view-shot
21
+
22
+ # Voice notes
23
+ npm install react-native-audio-recorder-player
24
+ ```
25
+
26
+ ## Quick Start
27
+
28
+ ```tsx
29
+ import { YaverFeedback, BlackBox, FeedbackModal } from '@yaver/feedback-react-native';
30
+
31
+ // Initialize once at app startup
32
+ YaverFeedback.init({
33
+ agentUrl: 'http://192.168.1.10:18080',
34
+ authToken: 'your-sdk-token', // SDK token (recommended) or CLI token
35
+ trigger: 'shake',
36
+ });
37
+
38
+ // Start Black Box flight recorder
39
+ BlackBox.start();
40
+ BlackBox.wrapConsole(); // opt-in: stream console.log/warn/error to the agent
41
+
42
+ // Add FeedbackModal to your root component
43
+ function App() {
44
+ return (
45
+ <>
46
+ <YourApp />
47
+ <FeedbackModal />
48
+ </>
49
+ );
50
+ }
51
+ ```
52
+
53
+ Shake your phone to open the feedback modal. Take screenshots, record voice notes, and send everything to your Yaver agent in one tap.
54
+
55
+ ## Authentication
56
+
57
+ The SDK uses **bearer token auth** for all requests to the agent. Two token types are supported:
58
+
59
+ ### SDK Tokens (recommended)
60
+
61
+ SDK tokens are **long-lived (1 year)** and **independent from CLI session tokens**. CLI reauth (`yaver auth`) does NOT invalidate SDK tokens.
62
+
63
+ ```bash
64
+ # Create an SDK token
65
+ yaver sdk-token create --label "AcmeStore dev"
66
+ # prints: 4a8f...b3c2
67
+ ```
68
+
69
+ Use in your SDK config:
70
+ ```tsx
71
+ YaverFeedback.init({
72
+ authToken: '4a8f...b3c2', // SDK token
73
+ agentUrl: 'http://192.168.1.10:18080',
74
+ });
75
+ ```
76
+
77
+ Or via env var for build-time injection:
78
+ ```bash
79
+ # .env.yaver (gitignored)
80
+ YAVER_SDK_TOKEN=4a8f...b3c2
81
+ YAVER_AGENT_URL=http://192.168.1.10:18080
82
+ ```
83
+
84
+ ### CLI Token (fallback)
85
+
86
+ The SDK can share the CLI session token directly. This works because each `yaver auth` creates a **new session** without invalidating old ones. The old token stays valid until it expires (1 year) or is explicitly revoked via "logout everywhere".
87
+
88
+ ```bash
89
+ # .env.yaver (fallback)
90
+ YAVER_AUTH_TOKEN=abc123...
91
+ ```
92
+
93
+ ### Token Validation Flow
94
+
95
+ ```
96
+ SDK request → Agent HTTP server
97
+ 1. Exact match with agent's own token → Allow (fast path)
98
+ 2. Token in cache → userId match → Allow/Deny
99
+ 3. Try Convex /auth/validate (session token)
100
+ 4. Try Convex /sdk/token/validate (SDK token)
101
+ → Cache result → userId match → Allow/Deny
102
+ ```
103
+
104
+ Both token types resolve to the same `userId`. The agent checks `userId` equality, not token equality.
105
+
106
+ ### Token Lifecycle
107
+
108
+ | Event | CLI Token | SDK Token |
109
+ |-------|-----------|-----------|
110
+ | `yaver auth` (reauth) | New token created, old stays valid | Unaffected |
111
+ | `yaver signout` | Current session deleted | Unaffected |
112
+ | `yaver signout --all` | ALL sessions deleted | Unaffected |
113
+ | SDK token revoke | Unaffected | Revoked |
114
+ | Token expiry | 1 year from last refresh | 1 year from creation |
115
+
116
+ ### Security
117
+
118
+ The SDK implements defense-in-depth with 6 security layers:
119
+
120
+ **1. Scope Restriction** — SDK tokens can only access feedback/blackbox/voice/builds endpoints. They CANNOT execute tasks, run commands, access the vault, or shut down the agent.
121
+
122
+ ```bash
123
+ # Default scopes (safe for embedding in app builds)
124
+ yaver sdk-token create --label "AcmeStore"
125
+ # → scopes: feedback, blackbox, voice, builds
126
+
127
+ # Narrow scopes (feedback only)
128
+ yaver sdk-token create --scopes feedback,blackbox
129
+ ```
130
+
131
+ **2. IP Binding** — Restrict tokens to specific networks:
132
+ ```bash
133
+ yaver sdk-token create --allowed-ips 192.168.1.0/24
134
+ ```
135
+
136
+ **3. Agent-side IP Allowlist** — Block all requests from outside your network:
137
+ ```bash
138
+ yaver serve --allow-ips 192.168.1.0/24,10.0.0.0/8
139
+ ```
140
+
141
+ **4. Token Rotation** — Rotate tokens without downtime (5-minute grace period):
142
+ ```typescript
143
+ const { token } = await client.rotateToken();
144
+ // Old token valid for 5 more minutes
145
+ ```
146
+
147
+ ```bash
148
+ # Short-lived tokens for CI/CD
149
+ yaver sdk-token create --expires 24h
150
+ ```
151
+
152
+ **5. New Device Alerts** — When an SDK token is used from a new IP, a security event is logged to Convex. Query via `GET /security/events`.
153
+
154
+ **6. HTTPS on LAN** — Agent auto-generates a self-signed TLS cert and serves HTTPS on port 18443. The cert fingerprint is exposed via `/health` and the LAN beacon for cert pinning.
155
+
156
+ **General rules:**
157
+ - **Never commit tokens to source control** — use `.env.yaver` (gitignored) or env vars
158
+ - SDK tokens can be revoked independently: `POST /sdk/token/revoke`
159
+ - Even if an SDK token is stolen, it cannot run code on your machine (scope restriction)
160
+ - The Convex backend validates tokens against your account only
161
+
162
+ ## Black Box (Flight Recorder)
163
+
164
+ Continuous streaming of app events to the agent. The agent keeps a ring buffer (last 1000 events per device) and injects context into fix prompts — so the AI agent already knows what the app was doing when you ask for a fix.
165
+
166
+ ```tsx
167
+ import { BlackBox } from '@yaver/feedback-react-native';
168
+
169
+ // Start streaming (call after YaverFeedback.init)
170
+ BlackBox.start({
171
+ flushInterval: 2000, // send buffered events every 2s (default)
172
+ maxBufferSize: 50, // flush immediately at 50 events (default)
173
+ appName: 'AcmeStore',
174
+ });
175
+
176
+ // Logging
177
+ BlackBox.log('Cart updated', 'CartScreen');
178
+ BlackBox.warn('Low inventory', 'ProductCard');
179
+ BlackBox.error('Payment failed', 'Checkout', { orderId: '123' });
180
+
181
+ // Navigation tracking
182
+ BlackBox.navigation('ProductDetail', 'Home');
183
+
184
+ // Network monitoring
185
+ BlackBox.networkRequest('GET', '/api/products', 200, 142);
186
+ BlackBox.networkRequest('POST', '/api/order', 500, 3200);
187
+
188
+ // State changes (Redux actions, context updates, etc.)
189
+ BlackBox.stateChange('Cart cleared', { itemCount: 0 });
190
+
191
+ // Render performance
192
+ BlackBox.render('ProductList', 16.5);
193
+
194
+ // Error capture (also feeds into YaverFeedback error buffer)
195
+ BlackBox.captureError(new Error('Null ref'), false, { component: 'CartIcon' });
196
+
197
+ // Console wrapping (opt-in — SDK never auto-hooks)
198
+ BlackBox.wrapConsole(); // intercept console.log/warn/error
199
+ BlackBox.unwrapConsole(); // restore originals
200
+
201
+ // Error handler wrapper (pass-through, streams in real-time)
202
+ const existing = ErrorUtils.getGlobalHandler();
203
+ ErrorUtils.setGlobalHandler(BlackBox.wrapErrorHandler(existing));
204
+
205
+ // Control
206
+ BlackBox.stop(); // flush remaining events + stop timer
207
+ BlackBox.isStreaming; // check if active
208
+ ```
209
+
210
+ ### Event Types
211
+
212
+ | Type | Description | Example |
213
+ |------|-------------|---------|
214
+ | `log` | Console output (info/warn/error) | `BlackBox.log('User signed in')` |
215
+ | `error` | Caught exceptions with stack traces | `BlackBox.captureError(err)` |
216
+ | `navigation` | Screen transitions | `BlackBox.navigation('Cart', 'Home')` |
217
+ | `lifecycle` | App state (mount, background, foreground) | `BlackBox.lifecycle('app_background')` |
218
+ | `network` | HTTP requests/responses | `BlackBox.networkRequest('POST', '/api/pay', 500)` |
219
+ | `state` | State mutations | `BlackBox.stateChange('theme toggled')` |
220
+ | `render` | Component render with duration | `BlackBox.render('FlatList', 32.1)` |
221
+
222
+ ### Resilience
223
+
224
+ - Failed flushes re-add events to the buffer (capped at 2x maxBufferSize)
225
+ - `YaverFeedback.setEnabled(false)` pauses BlackBox; `setEnabled(true)` resumes it
226
+ - BlackBox shares auth config with YaverFeedback (no separate init needed)
227
+
228
+ ## Device Discovery
229
+
230
+ Three strategies (tried in order):
231
+
232
+ 1. **Convex cloud** — fetch agent IP from Convex device registry (for cloud machines or cross-network)
233
+ 2. **Stored connection** — try cached URL from last successful connection (AsyncStorage)
234
+ 3. **LAN scan** — probe common LAN subnets (`192.168.1.*`, `192.168.0.*`, `10.0.0.*`, `10.0.1.*`)
235
+
236
+ ### Convex discovery (recommended for teams)
237
+
238
+ No hardcoded IP needed — the SDK fetches the agent's IP from Convex:
239
+
240
+ ```typescript
241
+ YaverFeedback.init({
242
+ convexUrl: 'https://your-app.convex.site',
243
+ authToken: 'your-token',
244
+ preferredDeviceId: 'abc123', // optional — first online device if omitted
245
+ });
246
+ ```
247
+
248
+ ### Auto-discovery (no agentUrl needed)
249
+
250
+ ```typescript
251
+ YaverFeedback.init({
252
+ authToken: 'your-token',
253
+ trigger: 'shake',
254
+ // No agentUrl — SDK discovers it automatically on first report
255
+ });
256
+ ```
257
+
258
+ ### Manual discovery
259
+
260
+ ```typescript
261
+ import { YaverDiscovery } from '@yaver/feedback-react-native';
262
+
263
+ // Full discovery (Convex → stored → LAN scan)
264
+ const result = await YaverDiscovery.discover({
265
+ convexUrl: 'https://your-app.convex.site',
266
+ authToken: 'your-token',
267
+ });
268
+
269
+ // Probe a specific URL
270
+ const agent = await YaverDiscovery.probe('http://192.168.1.42:18080');
271
+
272
+ // Connect and store for future sessions
273
+ await YaverDiscovery.connect('http://192.168.1.42:18080');
274
+
275
+ // Clear stored connection
276
+ await YaverDiscovery.clear();
277
+ ```
278
+
279
+ ## Connection Screen
280
+
281
+ A full-screen UI for discovering and connecting to a Yaver agent. Shows connection status, URL/token inputs, auto-discover button, and a Start/Stop testing toggle with recording timer.
282
+
283
+ ```tsx
284
+ import { YaverConnectionScreen } from '@yaver/feedback-react-native';
285
+
286
+ function App() {
287
+ return (
288
+ <>
289
+ <YourApp />
290
+ {__DEV__ && <YaverConnectionScreen />}
291
+ </>
292
+ );
293
+ }
294
+ ```
295
+
296
+ The connection screen auto-discovers agents on mount and provides:
297
+ - Green/red connection status indicator
298
+ - Text inputs for agent URL (pre-filled from discovery) and auth token
299
+ - "Auto-discover" button to scan the network
300
+ - "Connect" button for manual connection
301
+ - "Start Testing" / "Stop & Send" toggle with recording timer
302
+
303
+ ## Three Feedback Modes
304
+
305
+ ### Live
306
+
307
+ Events are streamed to the agent as they happen. The agent can respond with commentary in real-time.
308
+
309
+ ```typescript
310
+ YaverFeedback.init({
311
+ agentUrl: 'http://192.168.1.10:18080',
312
+ authToken: 'your-token',
313
+ feedbackMode: 'live',
314
+ agentCommentaryLevel: 5, // Agent responds to what it sees
315
+ });
316
+ ```
317
+
318
+ ### Narrated
319
+
320
+ Record everything (screenshots, voice notes), then send the full bundle when you tap "Stop & Send". Good for walkthrough-style bug reports.
321
+
322
+ ```typescript
323
+ YaverFeedback.init({
324
+ agentUrl: 'http://192.168.1.10:18080',
325
+ authToken: 'your-token',
326
+ feedbackMode: 'narrated',
327
+ });
328
+ ```
329
+
330
+ ### Batch (default)
331
+
332
+ Collect everything and dump it all at the end when you tap "Send Report". The classic bug report flow.
333
+
334
+ ```typescript
335
+ YaverFeedback.init({
336
+ agentUrl: 'http://192.168.1.10:18080',
337
+ authToken: 'your-token',
338
+ feedbackMode: 'batch',
339
+ });
340
+ ```
341
+
342
+ ## Agent Commentary Levels
343
+
344
+ In live mode, the agent can comment on what it sees in real-time. Control verbosity with `agentCommentaryLevel` (0-10):
345
+
346
+ | Level | Behavior |
347
+ |-------|----------|
348
+ | 0 | Silent (default) |
349
+ | 1-3 | Only critical observations |
350
+ | 4-6 | Moderate commentary |
351
+ | 7-9 | Detailed observations and suggestions |
352
+ | 10 | Agent comments on everything it sees |
353
+
354
+ Commentary messages appear in a chat-like view inside the feedback modal.
355
+
356
+ ## Voice-Driven Live Coding
357
+
358
+ In live mode, the feedback modal shows a "Speak to Fix" button. When you tap it:
359
+
360
+ 1. Records your voice (uses `react-native-audio-recorder-player`)
361
+ 2. Sends the recording to the agent as a `voice_command` event
362
+ 3. The agent can transcribe and act on your instruction
363
+
364
+ This enables a hands-free workflow: see a bug, say what to fix, and the agent makes the change.
365
+
366
+ ## Error Capture
367
+
368
+ Capture JS errors with full stack traces and attach them to feedback reports. The agent gets file names, line numbers, and optional context — goes straight to the right line.
369
+
370
+ **No conflicts with Sentry, Crashlytics, Bugsnag, or any other tool.** The SDK never auto-hooks global error handlers. You explicitly insert it into your error chain wherever you want.
371
+
372
+ ### Option 1: Wrap the error handler (recommended)
373
+
374
+ ```typescript
375
+ import { ErrorUtils } from 'react-native';
376
+
377
+ // Insert Yaver into the error chain — works alongside Sentry, Crashlytics, etc.
378
+ const existing = ErrorUtils.getGlobalHandler();
379
+ ErrorUtils.setGlobalHandler(YaverFeedback.wrapErrorHandler(existing));
380
+
381
+ // Other tools can still wrap after this. The chain stays intact:
382
+ // Sentry → Yaver wrapper → original RN handler
383
+ ```
384
+
385
+ `wrapErrorHandler` returns a pass-through function that records the error in Yaver's ring buffer, then calls the next handler. It never swallows errors.
386
+
387
+ ### Option 2: Manual attach (in catch blocks)
388
+
389
+ ```typescript
390
+ try {
391
+ await riskyOperation();
392
+ } catch (err) {
393
+ YaverFeedback.attachError(err, {
394
+ context: 'checkout-flow',
395
+ userId: currentUser.id,
396
+ cartItems: cart.length,
397
+ });
398
+ throw err; // still propagate
399
+ }
400
+ ```
401
+
402
+ ### What the agent receives
403
+
404
+ ```json
405
+ {
406
+ "errors": [
407
+ {
408
+ "message": "Cannot read property 'id' of undefined",
409
+ "stack": [
410
+ "at CheckoutButton.handlePress (CheckoutScreen.tsx:47)",
411
+ "at processQueue (react-native/Libraries/Renderer/...)"
412
+ ],
413
+ "isFatal": false,
414
+ "timestamp": 1742812200000,
415
+ "metadata": {
416
+ "context": "checkout-flow",
417
+ "cartItems": 3
418
+ }
419
+ }
420
+ ]
421
+ }
422
+ ```
423
+
424
+ ### API
425
+
426
+ | Method | Description |
427
+ |--------|-------------|
428
+ | `attachError(error, metadata?)` | Manually attach an error with optional context |
429
+ | `wrapErrorHandler(next?)` | Returns a pass-through handler for the error chain |
430
+ | `getCapturedErrors()` | Get the current error buffer |
431
+ | `clearCapturedErrors()` | Clear the error buffer |
432
+
433
+ ## Configuration
434
+
435
+ ```typescript
436
+ YaverFeedback.init({
437
+ // Required
438
+ authToken: 'your-token', // Auth token for the agent
439
+
440
+ // Optional
441
+ agentUrl: 'http://192.168.1.10:18080', // Agent URL (auto-discovered if omitted)
442
+ trigger: 'shake', // 'shake' | 'floating-button' | 'manual'
443
+ enabled: true, // Default: __DEV__ (auto-disabled in production)
444
+ maxRecordingDuration: 120, // Max recording duration in seconds (default: 120)
445
+ feedbackMode: 'batch', // 'live' | 'narrated' | 'batch' (default: 'batch')
446
+ agentCommentaryLevel: 0, // 0-10 (default: 0, only relevant in live mode)
447
+ maxCapturedErrors: 5, // Error ring buffer size (default: 5)
448
+ });
449
+ ```
450
+
451
+ ## Trigger Modes
452
+
453
+ ### Shake (default)
454
+
455
+ Shake the device to open the feedback modal. Uses the built-in shake event on iOS and `ShakeEvent` on Android.
456
+
457
+ ```typescript
458
+ YaverFeedback.init({ authToken, trigger: 'shake' });
459
+ ```
460
+
461
+ ### Floating Button
462
+
463
+ A small draggable "Y" button overlays the app. Tap to open the feedback modal.
464
+
465
+ ```tsx
466
+ import { FloatingButton, FeedbackModal, YaverFeedback } from '@yaver/feedback-react-native';
467
+
468
+ function App() {
469
+ return (
470
+ <>
471
+ <YourApp />
472
+ <FloatingButton onPress={() => YaverFeedback.startReport()} />
473
+ <FeedbackModal />
474
+ </>
475
+ );
476
+ }
477
+ ```
478
+
479
+ ### Manual
480
+
481
+ Trigger feedback collection programmatically from anywhere in your app.
482
+
483
+ ```typescript
484
+ import { YaverFeedback } from '@yaver/feedback-react-native';
485
+
486
+ // In a button handler, debug menu, etc.
487
+ YaverFeedback.startReport();
488
+ ```
489
+
490
+ ## P2P Client
491
+
492
+ For direct communication with the Yaver agent beyond feedback:
493
+
494
+ ```typescript
495
+ import { P2PClient } from '@yaver/feedback-react-native';
496
+
497
+ const client = new P2PClient('http://192.168.1.10:18080', 'your-token');
498
+
499
+ // Health check
500
+ const isUp = await client.health();
501
+
502
+ // Get agent info
503
+ const info = await client.info();
504
+ // { hostname: 'MacBook-Air', version: '1.45.0', platform: 'darwin' }
505
+
506
+ // Upload feedback bundle
507
+ const reportId = await client.uploadFeedback(bundle);
508
+
509
+ // Builds
510
+ const builds = await client.listBuilds();
511
+ const build = await client.startBuild('ios');
512
+ const url = client.getArtifactUrl(build.id);
513
+
514
+ // Voice
515
+ const voiceCap = await client.voiceStatus();
516
+ const { text, provider } = await client.transcribeVoice('/path/to/audio.wav');
517
+
518
+ // Autonomous test sessions
519
+ const { sessionId } = await client.startTestSession();
520
+ const session = await client.getTestSession();
521
+ await client.stopTestSession();
522
+
523
+ // Update connection dynamically (e.g. after re-discovery)
524
+ client.setBaseUrl('http://10.0.0.2:18080');
525
+ client.setAuthToken('new-token');
526
+ ```
527
+
528
+ ## How It Works
529
+
530
+ 1. User triggers feedback (shake, button tap, or manual call)
531
+ 2. Feedback modal opens with mode selector (Live / Narrated / Batch)
532
+ 3. User captures screenshots, records voice notes, or speaks commands
533
+ 4. In live mode: events stream to the agent in real-time, agent can respond with commentary
534
+ 5. In narrated/batch mode: everything is collected and uploaded on send
535
+ 6. SDK uploads via multipart POST to `/feedback` (or streams to `/feedback/stream`)
536
+ 7. The agent receives the report and can create a task from it
537
+
538
+ All data flows directly to your dev machine via the Yaver agent. Nothing goes through third-party servers.
539
+
540
+ ## Development vs Production
541
+
542
+ By default, the SDK is only enabled when `__DEV__` is `true` (React Native's built-in dev mode flag). In production builds, the SDK is automatically disabled and all methods are no-ops.
543
+
544
+ Override this behavior:
545
+
546
+ ```typescript
547
+ // Force enable in production (e.g., for internal beta testers)
548
+ YaverFeedback.init({ authToken, enabled: true });
549
+
550
+ // Disable at runtime
551
+ YaverFeedback.setEnabled(false);
552
+ ```
553
+
554
+ ## Requirements
555
+
556
+ - React Native >= 0.70
557
+ - React >= 18
558
+ - Yaver CLI running on your dev machine (`yaver serve`)
559
+ - Optional: `@react-native-async-storage/async-storage` for device discovery persistence
560
+ - Optional: `react-native-view-shot` for screenshots
561
+ - Optional: `react-native-audio-recorder-player` for voice notes
562
+
563
+ ## API Reference
564
+
565
+ ### YaverFeedback
566
+
567
+ | Method | Description |
568
+ |--------|-------------|
569
+ | `init(config)` | Initialize the SDK with agent URL, auth token, and options |
570
+ | `startReport()` | Manually trigger the feedback modal (auto-discovers if needed) |
571
+ | `isInitialized()` | Check if the SDK has been initialized |
572
+ | `setEnabled(bool)` | Enable or disable at runtime |
573
+ | `isEnabled()` | Check if the SDK is currently enabled |
574
+ | `getP2PClient()` | Get the P2P client instance |
575
+ | `getFeedbackMode()` | Get the current feedback mode |
576
+ | `getCommentaryLevel()` | Get the agent commentary level (0-10) |
577
+ | `attachError(error, metadata?)` | Manually attach an error with optional context |
578
+ | `getCapturedErrors()` | Get the current captured errors buffer |
579
+ | `clearCapturedErrors()` | Clear the captured errors buffer |
580
+
581
+ ### YaverDiscovery
582
+
583
+ | Method | Description |
584
+ |--------|-------------|
585
+ | `discover()` | Try stored connection, then scan LAN |
586
+ | `probe(url)` | Probe a specific URL for an agent |
587
+ | `connect(url)` | Connect and store for future sessions |
588
+ | `getStored()` | Get cached connection from storage |
589
+ | `store(result)` | Cache a discovery result |
590
+ | `clear()` | Clear stored connection |
591
+
592
+ ### BlackBox
593
+
594
+ | Method | Description |
595
+ |--------|-------------|
596
+ | `start(config?)` | Start streaming events to the agent |
597
+ | `stop()` | Flush remaining events and stop |
598
+ | `isStreaming` | Whether streaming is active (getter) |
599
+ | `log(msg, source?, meta?)` | Log an info message |
600
+ | `warn(msg, source?, meta?)` | Log a warning |
601
+ | `error(msg, source?, meta?)` | Log an error |
602
+ | `captureError(err, isFatal?, meta?)` | Capture error with stack trace |
603
+ | `navigation(route, prevRoute?, meta?)` | Record screen navigation |
604
+ | `lifecycle(event, meta?)` | Record app lifecycle event |
605
+ | `networkRequest(method, url, status?, duration?, meta?)` | Record HTTP request |
606
+ | `stateChange(description, meta?)` | Record state mutation |
607
+ | `render(component, duration?, meta?)` | Record render event |
608
+ | `wrapConsole()` | Intercept console.log/warn/error |
609
+ | `unwrapConsole()` | Restore original console methods |
610
+ | `wrapErrorHandler(next?)` | Pass-through error handler with real-time streaming |
611
+
612
+ ### P2PClient
613
+
614
+ | Method | Description |
615
+ |--------|-------------|
616
+ | `health()` | Health check (returns boolean) |
617
+ | `info()` | Get agent hostname, version, platform |
618
+ | `uploadFeedback(bundle)` | Upload feedback bundle via multipart POST |
619
+ | `streamFeedback(events)` | Stream feedback events in live mode |
620
+ | `listBuilds()` | List available builds |
621
+ | `startBuild(platform)` | Start a build for the given platform |
622
+ | `getArtifactUrl(buildId)` | Get download URL for a build artifact |
623
+ | `voiceStatus()` | Get voice capability info |
624
+ | `transcribeVoice(audioUri)` | Send audio for transcription |
625
+ | `startTestSession()` | Start autonomous test session |
626
+ | `stopTestSession()` | Stop test session |
627
+ | `getTestSession()` | Get test session status + fixes |
628
+ | `setBaseUrl(url)` | Update connection URL |
629
+ | `setAuthToken(token)` | Update auth token |
630
+
631
+ ### Components
632
+
633
+ | Component | Description |
634
+ |-----------|-------------|
635
+ | `FeedbackModal` | Modal with mode selector, commentary, screenshots, voice |
636
+ | `FloatingButton` | Draggable overlay button to trigger feedback |
637
+ | `YaverConnectionScreen` | Full-screen device discovery and connection UI |
638
+
639
+ ### Helpers
640
+
641
+ | Function | Description |
642
+ |----------|-------------|
643
+ | `captureScreenshot()` | Capture the current screen (requires `react-native-view-shot`) |
644
+ | `startAudioRecording()` | Start recording a voice note |
645
+ | `stopAudioRecording()` | Stop recording, returns `{ path, duration }` |
646
+ | `uploadFeedback(url, token, bundle)` | Upload a feedback bundle to the agent |
647
+
648
+ ## Agent Endpoints
649
+
650
+ The SDK communicates with these agent HTTP endpoints:
651
+
652
+ | Endpoint | Method | Description |
653
+ |----------|--------|-------------|
654
+ | `/health` | GET | Health check (no auth) |
655
+ | `/feedback` | POST | Upload feedback bundle (multipart) |
656
+ | `/feedback/stream` | POST | Stream live feedback events |
657
+ | `/blackbox/events` | POST | Batch stream Black Box events |
658
+ | `/blackbox/subscribe` | GET | SSE live log stream |
659
+ | `/blackbox/context` | GET | Get generated prompt context |
660
+ | `/builds` | GET/POST | List or start builds |
661
+ | `/voice/status` | GET | Voice capability info |
662
+ | `/voice/transcribe` | POST | Send audio for transcription |
663
+ | `/test-app/start` | POST | Start autonomous test session |
664
+ | `/test-app/stop` | POST | Stop test session |
665
+ | `/test-app/status` | GET | Test session status + fixes |
666
+
667
+ ## Architecture
668
+
669
+ ```
670
+ ┌──────────────────┐ HTTP (Bearer auth) ┌──────────────────┐
671
+ │ Your App │────────────────────────────►│ Yaver Agent │
672
+ │ + Feedback SDK │ feedback, blackbox events │ (Go CLI) │
673
+ │ + BlackBox │ screenshots, voice, video │ on your machine │
674
+ │ │◄────────────────────────────│ │
675
+ │ │ fixes, build status, voice │ runs AI agent │
676
+ └──────────────────┘ └──────────────────┘
677
+ │ │
678
+ │ Auth only │ Auth only
679
+ ▼ ▼
680
+ ┌─────────────────────────────────────────────────────────────────────┐
681
+ │ Convex Backend │
682
+ │ Token validation + device registry (no task data stored) │
683
+ └─────────────────────────────────────────────────────────────────────┘
684
+ ```
685
+
686
+ All feedback data flows P2P between your app and the agent. Convex handles only auth and device discovery.
687
+
688
+ ## License
689
+
690
+ MIT