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
@@ -0,0 +1,181 @@
1
+ import { useEffect, useRef, useState } from 'react';
2
+ import { StyleSheet, Text, View } from 'react-native';
3
+ import Animated, {
4
+ useAnimatedStyle,
5
+ useSharedValue,
6
+ withTiming,
7
+ } from 'react-native-reanimated';
8
+
9
+ import { colors, spacing } from '../theme';
10
+ import {
11
+ appendVoiceWaveformSample,
12
+ createVoiceWaveformSeed,
13
+ fallbackVoiceWaveformLevel,
14
+ formatVoiceRecordingDuration,
15
+ normalizeVoiceMetering,
16
+ VOICE_WAVEFORM_BAR_COUNT,
17
+ VOICE_WAVEFORM_SAMPLE_INTERVAL_MS,
18
+ } from './voiceWaveform';
19
+
20
+ const MIN_BAR_HEIGHT = 6;
21
+ const MAX_BAR_HEIGHT = 26;
22
+
23
+ interface VoiceRecordingWaveformProps {
24
+ durationMillis: number;
25
+ metering?: number | null;
26
+ }
27
+
28
+ interface WaveformBarProps {
29
+ ageOpacity: number;
30
+ level: number;
31
+ }
32
+
33
+ function WaveformBar({ ageOpacity, level }: WaveformBarProps) {
34
+ const animatedLevel = useSharedValue(level);
35
+
36
+ useEffect(() => {
37
+ animatedLevel.value = withTiming(level, {
38
+ duration: VOICE_WAVEFORM_SAMPLE_INTERVAL_MS + 30,
39
+ });
40
+ }, [animatedLevel, level]);
41
+
42
+ const animatedStyle = useAnimatedStyle(() => {
43
+ const height =
44
+ MIN_BAR_HEIGHT + animatedLevel.value * (MAX_BAR_HEIGHT - MIN_BAR_HEIGHT);
45
+ const opacity = Math.min(
46
+ 1,
47
+ Math.max(0.18, ageOpacity * (0.45 + animatedLevel.value * 0.55))
48
+ );
49
+
50
+ return {
51
+ height,
52
+ opacity,
53
+ };
54
+ });
55
+
56
+ return (
57
+ <View style={styles.barTrack}>
58
+ <Animated.View style={[styles.bar, animatedStyle]} />
59
+ </View>
60
+ );
61
+ }
62
+
63
+ export function VoiceRecordingWaveform({
64
+ durationMillis,
65
+ metering,
66
+ }: VoiceRecordingWaveformProps) {
67
+ const [samples, setSamples] = useState<number[]>(() =>
68
+ createVoiceWaveformSeed(VOICE_WAVEFORM_BAR_COUNT)
69
+ );
70
+ const meteringRef = useRef<number | null | undefined>(metering);
71
+ meteringRef.current = metering;
72
+
73
+ useEffect(() => {
74
+ let step = 0;
75
+
76
+ setSamples(createVoiceWaveformSeed(VOICE_WAVEFORM_BAR_COUNT));
77
+
78
+ const interval = setInterval(() => {
79
+ step += 1;
80
+ const level =
81
+ meteringRef.current == null
82
+ ? fallbackVoiceWaveformLevel(step)
83
+ : normalizeVoiceMetering(meteringRef.current);
84
+
85
+ setSamples((currentSamples) =>
86
+ appendVoiceWaveformSample(currentSamples, level, VOICE_WAVEFORM_BAR_COUNT)
87
+ );
88
+ }, VOICE_WAVEFORM_SAMPLE_INTERVAL_MS);
89
+
90
+ return () => clearInterval(interval);
91
+ }, []);
92
+
93
+ const formattedDuration = formatVoiceRecordingDuration(durationMillis);
94
+
95
+ return (
96
+ <View
97
+ accessible
98
+ accessibilityLabel={`Voice recording in progress, ${formattedDuration} elapsed`}
99
+ style={styles.container}
100
+ >
101
+ <View style={styles.metaRow}>
102
+ <View style={styles.labelRow}>
103
+ <View style={styles.liveDot} />
104
+ <Text style={styles.label}>Listening</Text>
105
+ </View>
106
+ <Text style={styles.timer}>{formattedDuration}</Text>
107
+ </View>
108
+
109
+ <View style={styles.waveformRow}>
110
+ {samples.map((sample, index) => {
111
+ const denominator = Math.max(1, samples.length - 1);
112
+ const ageOpacity = 0.24 + (index / denominator) * 0.72;
113
+
114
+ return (
115
+ <WaveformBar
116
+ key={String(index)}
117
+ ageOpacity={ageOpacity}
118
+ level={sample}
119
+ />
120
+ );
121
+ })}
122
+ </View>
123
+ </View>
124
+ );
125
+ }
126
+
127
+ const styles = StyleSheet.create({
128
+ container: {
129
+ flex: 1,
130
+ gap: spacing.xs,
131
+ justifyContent: 'center',
132
+ minHeight: 40,
133
+ },
134
+ metaRow: {
135
+ alignItems: 'center',
136
+ flexDirection: 'row',
137
+ justifyContent: 'space-between',
138
+ },
139
+ labelRow: {
140
+ alignItems: 'center',
141
+ flexDirection: 'row',
142
+ gap: spacing.xs,
143
+ },
144
+ liveDot: {
145
+ backgroundColor: colors.error,
146
+ borderRadius: 4,
147
+ height: 8,
148
+ width: 8,
149
+ },
150
+ label: {
151
+ color: colors.textMuted,
152
+ fontSize: 11,
153
+ fontWeight: '600',
154
+ letterSpacing: 0.4,
155
+ textTransform: 'uppercase',
156
+ },
157
+ timer: {
158
+ color: colors.textSecondary,
159
+ fontFamily: 'monospace',
160
+ fontSize: 12,
161
+ fontVariant: ['tabular-nums'],
162
+ },
163
+ waveformRow: {
164
+ alignItems: 'center',
165
+ flexDirection: 'row',
166
+ gap: 3,
167
+ height: MAX_BAR_HEIGHT,
168
+ overflow: 'hidden',
169
+ },
170
+ barTrack: {
171
+ alignItems: 'center',
172
+ height: MAX_BAR_HEIGHT,
173
+ justifyContent: 'center',
174
+ width: 3,
175
+ },
176
+ bar: {
177
+ backgroundColor: colors.textPrimary,
178
+ borderRadius: 999,
179
+ width: 3,
180
+ },
181
+ });