clawdex-mobile 2.0.1 → 3.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 (71) hide show
  1. package/.github/workflows/pages.yml +41 -0
  2. package/AGENTS.md +263 -110
  3. package/README.md +1 -1
  4. package/apps/mobile/.env.example +2 -2
  5. package/apps/mobile/App.tsx +175 -14
  6. package/apps/mobile/app.json +27 -9
  7. package/apps/mobile/eas.json +14 -4
  8. package/apps/mobile/package.json +13 -13
  9. package/apps/mobile/src/api/__tests__/chatMapping.test.ts +219 -0
  10. package/apps/mobile/src/api/__tests__/client.test.ts +579 -6
  11. package/apps/mobile/src/api/__tests__/ws.test.ts +27 -0
  12. package/apps/mobile/src/api/account.ts +47 -0
  13. package/apps/mobile/src/api/chatMapping.ts +435 -18
  14. package/apps/mobile/src/api/client.ts +296 -36
  15. package/apps/mobile/src/api/rateLimits.ts +143 -0
  16. package/apps/mobile/src/api/types.ts +106 -0
  17. package/apps/mobile/src/api/ws.ts +10 -1
  18. package/apps/mobile/src/components/ChatHeader.tsx +12 -12
  19. package/apps/mobile/src/components/ChatInput.tsx +154 -88
  20. package/apps/mobile/src/components/ChatMessage.tsx +548 -93
  21. package/apps/mobile/src/components/ComposerUsageLimits.tsx +167 -0
  22. package/apps/mobile/src/components/SelectionSheet.tsx +466 -0
  23. package/apps/mobile/src/components/ToolBlock.tsx +17 -15
  24. package/apps/mobile/src/components/VoiceRecordingWaveform.tsx +181 -0
  25. package/apps/mobile/src/components/WorkspacePickerModal.tsx +572 -0
  26. package/apps/mobile/src/components/__tests__/chat-input-layout.test.ts +35 -0
  27. package/apps/mobile/src/components/__tests__/chatImageSource.test.ts +44 -0
  28. package/apps/mobile/src/components/__tests__/composerUsageLimits.test.ts +138 -0
  29. package/apps/mobile/src/components/__tests__/voiceWaveform.test.ts +31 -0
  30. package/apps/mobile/src/components/chat-input-layout.ts +59 -0
  31. package/apps/mobile/src/components/chatImageSource.ts +86 -0
  32. package/apps/mobile/src/components/usageLimitBadges.ts +109 -0
  33. package/apps/mobile/src/components/voiceWaveform.ts +46 -0
  34. package/apps/mobile/src/config.ts +9 -2
  35. package/apps/mobile/src/hooks/useVoiceRecorder.ts +8 -1
  36. package/apps/mobile/src/navigation/DrawerContent.tsx +607 -457
  37. package/apps/mobile/src/navigation/__tests__/chatThreadTree.test.ts +89 -0
  38. package/apps/mobile/src/navigation/__tests__/drawerChats.test.ts +65 -0
  39. package/apps/mobile/src/navigation/chatThreadTree.ts +191 -0
  40. package/apps/mobile/src/navigation/drawerChats.ts +9 -0
  41. package/apps/mobile/src/screens/GitScreen.tsx +2 -0
  42. package/apps/mobile/src/screens/MainScreen.tsx +4244 -1237
  43. package/apps/mobile/src/screens/OnboardingScreen.tsx +2 -0
  44. package/apps/mobile/src/screens/SettingsScreen.tsx +256 -226
  45. package/apps/mobile/src/screens/TerminalScreen.tsx +2 -5
  46. package/apps/mobile/src/screens/__tests__/agentThreadDisplay.test.ts +80 -0
  47. package/apps/mobile/src/screens/__tests__/agentThreads.test.ts +170 -0
  48. package/apps/mobile/src/screens/__tests__/planCardState.test.ts +88 -0
  49. package/apps/mobile/src/screens/__tests__/subAgentTranscript.test.ts +102 -0
  50. package/apps/mobile/src/screens/__tests__/transcriptMessages.test.ts +97 -0
  51. package/apps/mobile/src/screens/agentThreadDisplay.ts +261 -0
  52. package/apps/mobile/src/screens/agentThreads.ts +167 -0
  53. package/apps/mobile/src/screens/planCardState.ts +40 -0
  54. package/apps/mobile/src/screens/subAgentTranscript.ts +149 -0
  55. package/apps/mobile/src/screens/transcriptMessages.ts +102 -0
  56. package/apps/mobile/src/theme.ts +6 -12
  57. package/docs/codex-app-server-cli-gap-tracker.md +14 -5
  58. package/docs/privacy-policy.md +54 -0
  59. package/docs/setup-and-operations.md +4 -3
  60. package/docs/terms-of-service.md +33 -0
  61. package/package.json +3 -3
  62. package/services/mac-bridge/package.json +6 -6
  63. package/services/rust-bridge/Cargo.lock +56 -47
  64. package/services/rust-bridge/Cargo.toml +1 -1
  65. package/services/rust-bridge/package.json +1 -1
  66. package/services/rust-bridge/src/main.rs +507 -9
  67. package/site/index.html +54 -0
  68. package/site/privacy/index.html +80 -0
  69. package/site/styles.css +135 -0
  70. package/site/support/index.html +51 -0
  71. package/site/terms/index.html +68 -0
@@ -38,6 +38,7 @@ const SWIPE_OPEN_DISTANCE = 56;
38
38
  const SWIPE_CLOSE_DISTANCE = 56;
39
39
  const SWIPE_OPEN_VELOCITY = 0.4;
40
40
  const SWIPE_CLOSE_VELOCITY = -0.4;
41
+ const DRAWER_CONTENT_SCALE = 0.94;
41
42
  const APP_SETTINGS_FILE = 'clawdex-app-settings.json';
42
43
  const APP_SETTINGS_VERSION = 3;
43
44
 
@@ -79,10 +80,22 @@ export default function App() {
79
80
  const [defaultReasoningEffort, setDefaultReasoningEffort] =
80
81
  useState<ReasoningEffort | null>(null);
81
82
  const [approvalMode, setApprovalMode] = useState<ApprovalMode>('normal');
83
+ const [showToolCalls, setShowToolCalls] = useState(false);
82
84
  const [drawerOpen, setDrawerOpen] = useState(false);
83
85
  const drawerAnim = useRef(new Animated.Value(-DRAWER_WIDTH)).current;
84
86
  const overlayAnim = useRef(new Animated.Value(0)).current;
85
87
  const { width: screenWidth } = useWindowDimensions();
88
+ const contentShiftOpen = Math.min(DRAWER_WIDTH - 12, screenWidth * 0.74);
89
+ const contentTranslateX = drawerAnim.interpolate({
90
+ inputRange: [-DRAWER_WIDTH, 0],
91
+ outputRange: [0, contentShiftOpen],
92
+ extrapolate: 'clamp',
93
+ });
94
+ const contentScale = drawerAnim.interpolate({
95
+ inputRange: [-DRAWER_WIDTH, 0],
96
+ outputRange: [1, DRAWER_CONTENT_SCALE],
97
+ extrapolate: 'clamp',
98
+ });
86
99
 
87
100
  useEffect(() => {
88
101
  if (!ws) {
@@ -97,9 +110,11 @@ export default function App() {
97
110
  async (
98
111
  nextBridgeUrl: string | null,
99
112
  nextBridgeToken: string | null,
113
+ nextDefaultStartCwd: string | null,
100
114
  nextModelId: string | null,
101
115
  nextEffort: ReasoningEffort | null,
102
- nextApprovalMode: ApprovalMode
116
+ nextApprovalMode: ApprovalMode,
117
+ nextShowToolCalls: boolean
103
118
  ) => {
104
119
  const settingsPath = getAppSettingsPath();
105
120
  if (!settingsPath) {
@@ -110,9 +125,11 @@ export default function App() {
110
125
  version: APP_SETTINGS_VERSION,
111
126
  bridgeUrl: nextBridgeUrl,
112
127
  bridgeToken: nextBridgeToken,
128
+ defaultStartCwd: nextDefaultStartCwd,
113
129
  defaultModelId: nextModelId,
114
130
  defaultReasoningEffort: nextEffort,
115
131
  approvalMode: nextApprovalMode,
132
+ showToolCalls: nextShowToolCalls,
116
133
  });
117
134
 
118
135
  try {
@@ -128,9 +145,11 @@ export default function App() {
128
145
  let cancelled = false;
129
146
 
130
147
  const resetToDefaults = () => {
148
+ setDefaultStartCwd(null);
131
149
  setDefaultModelId(null);
132
150
  setDefaultReasoningEffort(null);
133
151
  setApprovalMode('normal');
152
+ setShowToolCalls(false);
134
153
  };
135
154
 
136
155
  const loadSettings = async () => {
@@ -154,9 +173,11 @@ export default function App() {
154
173
  const resolvedBridgeUrl = parsed.bridgeUrl ?? null;
155
174
  setBridgeUrl(resolvedBridgeUrl);
156
175
  setBridgeToken(parsed.bridgeToken ?? env.hostBridgeToken);
176
+ setDefaultStartCwd(parsed.defaultStartCwd);
157
177
  setDefaultModelId(parsed.defaultModelId);
158
178
  setDefaultReasoningEffort(parsed.defaultReasoningEffort);
159
179
  setApprovalMode(parsed.approvalMode);
180
+ setShowToolCalls(parsed.showToolCalls);
160
181
  } catch {
161
182
  if (!cancelled) {
162
183
  resetToDefaults();
@@ -295,6 +316,12 @@ export default function App() {
295
316
 
296
317
  const handleSelectChat = useCallback(
297
318
  (id: string) => {
319
+ const currentChatId = activeChat?.id ?? selectedChatId;
320
+ if (currentScreen === 'Main' && currentChatId === id) {
321
+ closeDrawer();
322
+ return;
323
+ }
324
+
298
325
  setSelectedChatId(id);
299
326
  setGitChat(null);
300
327
  setCurrentScreen('Main');
@@ -302,7 +329,7 @@ export default function App() {
302
329
  setPendingMainChatSnapshot(null);
303
330
  closeDrawer();
304
331
  },
305
- [closeDrawer]
332
+ [activeChat?.id, closeDrawer, currentScreen, selectedChatId]
306
333
  );
307
334
 
308
335
  const handleNewChat = useCallback(() => {
@@ -325,12 +352,21 @@ export default function App() {
325
352
  void saveAppSettings(
326
353
  bridgeUrl,
327
354
  bridgeToken,
355
+ defaultStartCwd,
328
356
  normalizedModelId,
329
357
  normalizedEffort,
330
- approvalMode
358
+ approvalMode,
359
+ showToolCalls
331
360
  );
332
361
  },
333
- [approvalMode, bridgeToken, bridgeUrl, saveAppSettings]
362
+ [
363
+ approvalMode,
364
+ bridgeToken,
365
+ bridgeUrl,
366
+ defaultStartCwd,
367
+ saveAppSettings,
368
+ showToolCalls,
369
+ ]
334
370
  );
335
371
 
336
372
  const handleApprovalModeChange = useCallback(
@@ -340,12 +376,71 @@ export default function App() {
340
376
  void saveAppSettings(
341
377
  bridgeUrl,
342
378
  bridgeToken,
379
+ defaultStartCwd,
380
+ defaultModelId,
381
+ defaultReasoningEffort,
382
+ normalizedMode,
383
+ showToolCalls
384
+ );
385
+ },
386
+ [
387
+ bridgeToken,
388
+ bridgeUrl,
389
+ defaultStartCwd,
390
+ defaultModelId,
391
+ defaultReasoningEffort,
392
+ saveAppSettings,
393
+ showToolCalls,
394
+ ]
395
+ );
396
+
397
+ const handleShowToolCallsChange = useCallback(
398
+ (nextValue: boolean) => {
399
+ setShowToolCalls(nextValue);
400
+ void saveAppSettings(
401
+ bridgeUrl,
402
+ bridgeToken,
403
+ defaultStartCwd,
343
404
  defaultModelId,
344
405
  defaultReasoningEffort,
345
- normalizedMode
406
+ approvalMode,
407
+ nextValue
346
408
  );
347
409
  },
348
- [bridgeToken, bridgeUrl, defaultModelId, defaultReasoningEffort, saveAppSettings]
410
+ [
411
+ approvalMode,
412
+ bridgeToken,
413
+ bridgeUrl,
414
+ defaultStartCwd,
415
+ defaultModelId,
416
+ defaultReasoningEffort,
417
+ saveAppSettings,
418
+ ]
419
+ );
420
+
421
+ const handleDefaultStartCwdChange = useCallback(
422
+ (nextCwd: string | null) => {
423
+ const normalizedDefaultStartCwd = normalizeDefaultStartCwd(nextCwd);
424
+ setDefaultStartCwd(normalizedDefaultStartCwd);
425
+ void saveAppSettings(
426
+ bridgeUrl,
427
+ bridgeToken,
428
+ normalizedDefaultStartCwd,
429
+ defaultModelId,
430
+ defaultReasoningEffort,
431
+ approvalMode,
432
+ showToolCalls
433
+ );
434
+ },
435
+ [
436
+ approvalMode,
437
+ bridgeToken,
438
+ bridgeUrl,
439
+ defaultModelId,
440
+ defaultReasoningEffort,
441
+ saveAppSettings,
442
+ showToolCalls,
443
+ ]
349
444
  );
350
445
 
351
446
  const handleBridgeUrlSaved = useCallback(
@@ -365,9 +460,11 @@ export default function App() {
365
460
  void saveAppSettings(
366
461
  normalized,
367
462
  normalizeBridgeToken(nextBridgeToken),
463
+ defaultStartCwd,
368
464
  defaultModelId,
369
465
  defaultReasoningEffort,
370
- approvalMode
466
+ approvalMode,
467
+ showToolCalls
371
468
  );
372
469
  setCurrentScreen(onboardingMode === 'edit' ? onboardingReturnScreen : 'Main');
373
470
  setOnboardingMode('edit');
@@ -376,11 +473,13 @@ export default function App() {
376
473
  [
377
474
  approvalMode,
378
475
  closeDrawer,
476
+ defaultStartCwd,
379
477
  defaultModelId,
380
478
  defaultReasoningEffort,
381
479
  onboardingMode,
382
480
  onboardingReturnScreen,
383
481
  saveAppSettings,
482
+ showToolCalls,
384
483
  ]
385
484
  );
386
485
 
@@ -402,14 +501,24 @@ export default function App() {
402
501
  setOnboardingMode('initial');
403
502
  setOnboardingReturnScreen('Main');
404
503
  setCurrentScreen('Onboarding');
405
- void saveAppSettings(null, null, defaultModelId, defaultReasoningEffort, approvalMode);
504
+ void saveAppSettings(
505
+ null,
506
+ null,
507
+ defaultStartCwd,
508
+ defaultModelId,
509
+ defaultReasoningEffort,
510
+ approvalMode,
511
+ showToolCalls
512
+ );
406
513
  closeDrawer();
407
514
  }, [
408
515
  approvalMode,
409
516
  closeDrawer,
517
+ defaultStartCwd,
410
518
  defaultModelId,
411
519
  defaultReasoningEffort,
412
520
  saveAppSettings,
521
+ showToolCalls,
413
522
  ]);
414
523
 
415
524
  const handleCancelOnboarding = useCallback(() => {
@@ -505,13 +614,16 @@ export default function App() {
505
614
  ref={mainRef}
506
615
  api={activeApi}
507
616
  ws={activeWs}
617
+ bridgeUrl={bridgeUrl}
618
+ bridgeToken={bridgeToken}
508
619
  onOpenDrawer={openDrawer}
509
620
  onOpenGit={handleOpenChatGit}
510
621
  defaultStartCwd={defaultStartCwd}
511
622
  defaultModelId={defaultModelId}
512
623
  defaultReasoningEffort={defaultReasoningEffort}
513
624
  approvalMode={approvalMode}
514
- onDefaultStartCwdChange={setDefaultStartCwd}
625
+ showToolCalls={showToolCalls}
626
+ onDefaultStartCwdChange={handleDefaultStartCwdChange}
515
627
  onChatContextChange={handleChatContextChange}
516
628
  pendingOpenChatId={pendingMainChatId}
517
629
  pendingOpenChatSnapshot={pendingMainChatSnapshot}
@@ -532,6 +644,8 @@ export default function App() {
532
644
  onDefaultModelSettingsChange={handleDefaultModelSettingsChange}
533
645
  approvalMode={approvalMode}
534
646
  onApprovalModeChange={handleApprovalModeChange}
647
+ showToolCalls={showToolCalls}
648
+ onShowToolCallsChange={handleShowToolCallsChange}
535
649
  onEditBridgeUrl={handleOpenBridgeUrlSettings}
536
650
  onResetOnboarding={handleResetOnboarding}
537
651
  onOpenDrawer={openDrawer}
@@ -559,13 +673,16 @@ export default function App() {
559
673
  ref={mainRef}
560
674
  api={activeApi}
561
675
  ws={activeWs}
676
+ bridgeUrl={bridgeUrl}
677
+ bridgeToken={bridgeToken}
562
678
  onOpenDrawer={openDrawer}
563
679
  onOpenGit={handleOpenChatGit}
564
680
  defaultStartCwd={defaultStartCwd}
565
681
  defaultModelId={defaultModelId}
566
682
  defaultReasoningEffort={defaultReasoningEffort}
567
683
  approvalMode={approvalMode}
568
- onDefaultStartCwdChange={setDefaultStartCwd}
684
+ showToolCalls={showToolCalls}
685
+ onDefaultStartCwdChange={handleDefaultStartCwdChange}
569
686
  onChatContextChange={handleChatContextChange}
570
687
  pendingOpenChatId={pendingMainChatId}
571
688
  pendingOpenChatSnapshot={pendingMainChatSnapshot}
@@ -582,9 +699,18 @@ export default function App() {
582
699
  <SafeAreaProvider>
583
700
  <View style={styles.root}>
584
701
  {/* Main content */}
585
- <View style={[styles.screen, { width: screenWidth }]}>
702
+ <Animated.View
703
+ style={[
704
+ styles.screenFrame,
705
+ drawerOpen && styles.screenFrameOpen,
706
+ {
707
+ width: screenWidth,
708
+ transform: [{ translateX: contentTranslateX }, { scale: contentScale }],
709
+ },
710
+ ]}
711
+ >
586
712
  {renderScreen()}
587
- </View>
713
+ </Animated.View>
588
714
 
589
715
  {/* Overlay */}
590
716
  <Animated.View
@@ -607,8 +733,6 @@ export default function App() {
607
733
  api={activeApi}
608
734
  ws={activeWs}
609
735
  selectedChatId={selectedChatId}
610
- selectedDefaultCwd={defaultStartCwd}
611
- onSelectDefaultCwd={setDefaultStartCwd}
612
736
  onSelectChat={handleSelectChat}
613
737
  onNewChat={handleNewChat}
614
738
  onNavigate={navigate}
@@ -637,17 +761,21 @@ function getAppSettingsPath(): string | null {
637
761
  function parseAppSettings(raw: string): {
638
762
  bridgeUrl: string | null;
639
763
  bridgeToken: string | null;
764
+ defaultStartCwd: string | null;
640
765
  defaultModelId: string | null;
641
766
  defaultReasoningEffort: ReasoningEffort | null;
642
767
  approvalMode: ApprovalMode;
768
+ showToolCalls: boolean;
643
769
  } {
644
770
  if (typeof raw !== 'string' || raw.trim().length === 0) {
645
771
  return {
646
772
  bridgeUrl: null,
647
773
  bridgeToken: null,
774
+ defaultStartCwd: null,
648
775
  defaultModelId: null,
649
776
  defaultReasoningEffort: null,
650
777
  approvalMode: 'normal',
778
+ showToolCalls: false,
651
779
  };
652
780
  }
653
781
 
@@ -664,15 +792,20 @@ function parseAppSettings(raw: string): {
664
792
  return {
665
793
  bridgeUrl: null,
666
794
  bridgeToken: null,
795
+ defaultStartCwd: null,
667
796
  defaultModelId: null,
668
797
  defaultReasoningEffort: null,
669
798
  approvalMode: 'normal',
799
+ showToolCalls: false,
670
800
  };
671
801
  }
672
802
 
673
803
  return {
674
804
  bridgeUrl: normalizeBridgeUrl((parsed as { bridgeUrl?: unknown }).bridgeUrl),
675
805
  bridgeToken: normalizeBridgeToken((parsed as { bridgeToken?: unknown }).bridgeToken),
806
+ defaultStartCwd: normalizeDefaultStartCwd(
807
+ (parsed as { defaultStartCwd?: unknown }).defaultStartCwd
808
+ ),
676
809
  defaultModelId: normalizeModelId(
677
810
  (parsed as { defaultModelId?: unknown }).defaultModelId
678
811
  ),
@@ -682,14 +815,19 @@ function parseAppSettings(raw: string): {
682
815
  approvalMode: normalizeApprovalMode(
683
816
  (parsed as { approvalMode?: unknown }).approvalMode
684
817
  ),
818
+ showToolCalls: normalizeBoolean(
819
+ (parsed as { showToolCalls?: unknown }).showToolCalls
820
+ ),
685
821
  };
686
822
  } catch {
687
823
  return {
688
824
  bridgeUrl: null,
689
825
  bridgeToken: null,
826
+ defaultStartCwd: null,
690
827
  defaultModelId: null,
691
828
  defaultReasoningEffort: null,
692
829
  approvalMode: 'normal',
830
+ showToolCalls: false,
693
831
  };
694
832
  }
695
833
  }
@@ -711,6 +849,15 @@ function normalizeBridgeToken(value: unknown): string | null {
711
849
  return trimmed.length > 0 ? trimmed : null;
712
850
  }
713
851
 
852
+ function normalizeDefaultStartCwd(value: unknown): string | null {
853
+ if (typeof value !== 'string') {
854
+ return null;
855
+ }
856
+
857
+ const trimmed = value.trim();
858
+ return trimmed.length > 0 ? trimmed : null;
859
+ }
860
+
714
861
  function normalizeModelId(value: unknown): string | null {
715
862
  if (typeof value !== 'string') {
716
863
  return null;
@@ -744,6 +891,10 @@ function normalizeApprovalMode(value: unknown): ApprovalMode {
744
891
  return value === 'yolo' ? 'yolo' : 'normal';
745
892
  }
746
893
 
894
+ function normalizeBoolean(value: unknown): boolean {
895
+ return value === true;
896
+ }
897
+
747
898
  const styles = StyleSheet.create({
748
899
  root: {
749
900
  flex: 1,
@@ -758,6 +909,16 @@ const styles = StyleSheet.create({
758
909
  screen: {
759
910
  flex: 1,
760
911
  },
912
+ screenFrame: {
913
+ flex: 1,
914
+ backgroundColor: colors.bgMain,
915
+ },
916
+ screenFrameOpen: {
917
+ borderRadius: 28,
918
+ borderCurve: 'continuous',
919
+ overflow: 'hidden',
920
+ boxShadow: '0 22px 48px rgba(0, 0, 0, 0.34)',
921
+ },
761
922
  overlay: {
762
923
  ...StyleSheet.absoluteFillObject,
763
924
  backgroundColor: 'rgba(0,0,0,0.5)',
@@ -2,7 +2,9 @@
2
2
  "expo": {
3
3
  "name": "Clawdex Mobile",
4
4
  "slug": "clawdex-mobile",
5
- "version": "2.0.1",
5
+ "scheme": "clawdex",
6
+ "version": "3.0.0",
7
+ "userInterfaceStyle": "dark",
6
8
  "orientation": "portrait",
7
9
  "icon": "./assets/brand/app-icon.png",
8
10
  "splash": {
@@ -12,15 +14,13 @@
12
14
  },
13
15
  "ios": {
14
16
  "supportsTablet": true,
17
+ "appleTeamId": "4NWUS8362L",
15
18
  "infoPlist": {
16
- "NSCameraUsageDescription": "Clawdex uses the camera to scan bridge pairing QR codes.",
17
- "NSMicrophoneUsageDescription": "Clawdex uses the microphone for voice-to-text input.",
18
19
  "ITSAppUsesNonExemptEncryption": false
19
20
  },
20
21
  "bundleIdentifier": "com.mohitpatil973.clawdexmobile"
21
22
  },
22
23
  "android": {
23
- "usesCleartextTraffic": true,
24
24
  "adaptiveIcon": {
25
25
  "foregroundImage": "./assets/brand/adaptive-icon.png",
26
26
  "backgroundColor": "#000000"
@@ -28,9 +28,7 @@
28
28
  "permissions": [
29
29
  "android.permission.CAMERA",
30
30
  "android.permission.RECORD_AUDIO",
31
- "android.permission.MODIFY_AUDIO_SETTINGS",
32
- "android.permission.FOREGROUND_SERVICE",
33
- "android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK"
31
+ "android.permission.MODIFY_AUDIO_SETTINGS"
34
32
  ],
35
33
  "package": "com.mohitpatil973.clawdexmobile"
36
34
  },
@@ -45,10 +43,30 @@
45
43
  "experiments": {
46
44
  "reactCompiler": true
47
45
  },
48
- "jsEngine": "hermes",
49
46
  "plugins": [
50
47
  "./plugins/withAndroidCleartextTraffic",
51
- "expo-audio"
48
+ [
49
+ "expo-camera",
50
+ {
51
+ "cameraPermission": "Clawdex uses the camera to scan bridge pairing QR codes."
52
+ }
53
+ ],
54
+ [
55
+ "expo-image-picker",
56
+ {
57
+ "photosPermission": "Clawdex uses your photo library so you can choose an image from your phone and attach it to a chat prompt or workflow sent to your own host bridge.",
58
+ "cameraPermission": "Clawdex uses the camera to scan bridge pairing QR codes.",
59
+ "microphonePermission": "Clawdex uses the microphone to record a short voice message that is transcribed into your chat input."
60
+ }
61
+ ],
62
+ [
63
+ "expo-audio",
64
+ {
65
+ "microphonePermission": "Clawdex uses the microphone to record a short voice message that is transcribed into your chat input.",
66
+ "enableBackgroundPlayback": false,
67
+ "enableBackgroundRecording": false
68
+ }
69
+ ]
52
70
  ],
53
71
  "extra": {
54
72
  "eas": {
@@ -8,23 +8,33 @@
8
8
  "developmentClient": true,
9
9
  "distribution": "internal",
10
10
  "env": {
11
- "EXPO_PUBLIC_ALLOW_QUERY_TOKEN_AUTH": "true"
11
+ "EXPO_PUBLIC_ALLOW_QUERY_TOKEN_AUTH": "true",
12
+ "EXPO_PUBLIC_PRIVACY_POLICY_URL": "https://mohit-patil.github.io/clawdex-mobile/privacy/",
13
+ "EXPO_PUBLIC_TERMS_OF_SERVICE_URL": "https://mohit-patil.github.io/clawdex-mobile/terms/"
12
14
  }
13
15
  },
14
16
  "preview": {
15
17
  "distribution": "internal",
16
18
  "env": {
17
- "EXPO_PUBLIC_ALLOW_QUERY_TOKEN_AUTH": "true"
19
+ "EXPO_PUBLIC_ALLOW_QUERY_TOKEN_AUTH": "true",
20
+ "EXPO_PUBLIC_PRIVACY_POLICY_URL": "https://mohit-patil.github.io/clawdex-mobile/privacy/",
21
+ "EXPO_PUBLIC_TERMS_OF_SERVICE_URL": "https://mohit-patil.github.io/clawdex-mobile/terms/"
18
22
  }
19
23
  },
20
24
  "production": {
21
25
  "autoIncrement": true,
22
26
  "env": {
23
- "EXPO_PUBLIC_ALLOW_QUERY_TOKEN_AUTH": "true"
27
+ "EXPO_PUBLIC_ALLOW_QUERY_TOKEN_AUTH": "true",
28
+ "EXPO_PUBLIC_PRIVACY_POLICY_URL": "https://mohit-patil.github.io/clawdex-mobile/privacy/",
29
+ "EXPO_PUBLIC_TERMS_OF_SERVICE_URL": "https://mohit-patil.github.io/clawdex-mobile/terms/"
24
30
  }
25
31
  }
26
32
  },
27
33
  "submit": {
28
- "production": {}
34
+ "production": {
35
+ "ios": {
36
+ "ascAppId": "6759833757"
37
+ }
38
+ }
29
39
  }
30
40
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clawdex-mobile",
3
- "version": "2.0.1",
3
+ "version": "3.0.0",
4
4
  "private": true,
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -16,14 +16,14 @@
16
16
  "dependencies": {
17
17
  "@expo/metro-runtime": "~55.0.6",
18
18
  "@expo/vector-icons": "15.0.3",
19
- "expo": "~55.0.3",
20
- "expo-audio": "~55.0.8",
21
- "expo-blur": "~55.0.8",
22
- "expo-camera": "~55.0.9",
23
- "expo-document-picker": "~55.0.8",
19
+ "expo": "~55.0.8",
20
+ "expo-audio": "~55.0.9",
21
+ "expo-blur": "~55.0.10",
22
+ "expo-camera": "~55.0.10",
23
+ "expo-document-picker": "~55.0.9",
24
24
  "expo-file-system": "~55.0.9",
25
- "expo-image-picker": "~55.0.9",
26
- "expo-linear-gradient": "~55.0.8",
25
+ "expo-image-picker": "~55.0.13",
26
+ "expo-linear-gradient": "~55.0.9",
27
27
  "react": "19.2.0",
28
28
  "react-dom": "19.2.0",
29
29
  "react-native": "0.83.2",
@@ -37,14 +37,14 @@
37
37
  },
38
38
  "devDependencies": {
39
39
  "@types/jest": "29.5.14",
40
- "@types/node": "^22.10.1",
40
+ "@types/node": "^22.19.15",
41
41
  "@types/react": "~19.2.10",
42
- "@typescript-eslint/eslint-plugin": "^8.18.1",
43
- "@typescript-eslint/parser": "^8.18.1",
44
- "eslint": "^10.0.0",
42
+ "@typescript-eslint/eslint-plugin": "^8.57.1",
43
+ "@typescript-eslint/parser": "^8.57.1",
44
+ "eslint": "^10.0.3",
45
45
  "globals": "^16.5.0",
46
46
  "jest": "^29.7.0",
47
- "jest-expo": "~55.0.9",
47
+ "jest-expo": "~55.0.11",
48
48
  "typescript": "~5.9.2"
49
49
  },
50
50
  "jest": {