Skip to content

Commit 2b929fc

Browse files
Jinwoo-Horca-ide
andcommitted
fix: terminal output duplication on mobile
Remove duplicate onPtyData call in pty.ts that caused every daemon-backed PTY data event to be dispatched twice through dataListeners, doubling all terminal output sent to mobile clients. Also: clean up registerSubscriptionCleanup to evict stale listeners on reconnect, add regression tests, fix CI lint/type errors, add mobile UX improvements (worktree creation, settings, about screen). Co-authored-by: Orca <help@stably.ai>
1 parent 61611a7 commit 2b929fc

18 files changed

Lines changed: 905 additions & 124 deletions

File tree

mobile/app/_layout.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ export default function RootLayout() {
2323
headerTitle: () => <OrcaLogo size={22} />
2424
}}
2525
/>
26-
<Stack.Screen name="pair-scan" options={{ title: 'Pair Host' }} />
26+
<Stack.Screen name="pair-scan" options={{ headerShown: false }} />
27+
<Stack.Screen name="settings" options={{ headerShown: false }} />
28+
<Stack.Screen name="about" options={{ headerShown: false }} />
2729
<Stack.Screen name="h" options={{ headerShown: false }} />
2830
</Stack>
2931
</>

mobile/app/about.tsx

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
import { View, Text, StyleSheet, Pressable, Linking } from 'react-native'
2+
import { useSafeAreaInsets } from 'react-native-safe-area-context'
3+
import { useRouter } from 'expo-router'
4+
import { ChevronLeft, Globe } from 'lucide-react-native'
5+
import Svg, { Path } from 'react-native-svg'
6+
import { OrcaLogo } from '../src/components/OrcaLogo'
7+
import { colors, spacing, typography } from '../src/theme/mobile-theme'
8+
9+
function GithubIcon({ size = 16, color = colors.textSecondary }) {
10+
return (
11+
<Svg width={size} height={size} viewBox="0 0 24 24" fill={color}>
12+
<Path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0 0 24 12c0-6.63-5.37-12-12-12z" />
13+
</Svg>
14+
)
15+
}
16+
17+
function XIcon({ size = 16, color = colors.textSecondary }) {
18+
return (
19+
<Svg width={size} height={size} viewBox="0 0 24 24" fill={color}>
20+
<Path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z" />
21+
</Svg>
22+
)
23+
}
24+
25+
export default function AboutScreen() {
26+
const router = useRouter()
27+
const insets = useSafeAreaInsets()
28+
29+
return (
30+
<View style={[styles.container, { paddingTop: insets.top + spacing.sm }]}>
31+
<View style={styles.topRow}>
32+
<Pressable style={styles.backButton} onPress={() => router.back()}>
33+
<ChevronLeft size={22} color={colors.textSecondary} />
34+
</Pressable>
35+
<Text style={styles.heading}>About</Text>
36+
</View>
37+
38+
<View style={styles.brand}>
39+
<OrcaLogo size={28} />
40+
<Text style={styles.brandName}>Orca</Text>
41+
<Text style={styles.brandSub}>Open-source agent IDE for 100x builders</Text>
42+
</View>
43+
44+
<View style={styles.section}>
45+
<Pressable
46+
style={({ pressed }) => [styles.row, pressed && styles.rowPressed]}
47+
onPress={() => void Linking.openURL('https://onOrca.dev')}
48+
>
49+
<Globe size={16} color={colors.textSecondary} />
50+
<Text style={styles.rowLabel}>Website</Text>
51+
<Text style={styles.rowValue}>onOrca.dev</Text>
52+
</Pressable>
53+
<View style={styles.separator} />
54+
<Pressable
55+
style={({ pressed }) => [styles.row, pressed && styles.rowPressed]}
56+
onPress={() => void Linking.openURL('https://github.com/stablyai/orca')}
57+
>
58+
<GithubIcon />
59+
<Text style={styles.rowLabel}>GitHub</Text>
60+
<Text style={styles.rowValue}>stablyai/orca</Text>
61+
</Pressable>
62+
<View style={styles.separator} />
63+
<Pressable
64+
style={({ pressed }) => [styles.row, pressed && styles.rowPressed]}
65+
onPress={() => void Linking.openURL('https://x.com/orca_build')}
66+
>
67+
<XIcon />
68+
<Text style={styles.rowLabel}>X</Text>
69+
<Text style={styles.rowValue}>@orca_build</Text>
70+
</Pressable>
71+
</View>
72+
</View>
73+
)
74+
}
75+
76+
const styles = StyleSheet.create({
77+
container: {
78+
flex: 1,
79+
backgroundColor: colors.bgBase,
80+
padding: spacing.lg
81+
},
82+
topRow: {
83+
flexDirection: 'row',
84+
alignItems: 'center',
85+
marginBottom: spacing.xl
86+
},
87+
backButton: {
88+
width: 36,
89+
height: 36,
90+
borderRadius: 18,
91+
alignItems: 'center',
92+
justifyContent: 'center',
93+
marginRight: spacing.sm
94+
},
95+
heading: {
96+
fontSize: 20,
97+
fontWeight: '700',
98+
color: colors.textPrimary
99+
},
100+
brand: {
101+
alignItems: 'center',
102+
paddingVertical: spacing.xl,
103+
marginBottom: spacing.lg
104+
},
105+
brandName: {
106+
fontSize: 22,
107+
fontWeight: '800',
108+
color: colors.textPrimary,
109+
marginTop: spacing.sm
110+
},
111+
brandSub: {
112+
fontSize: 13,
113+
color: colors.textMuted,
114+
marginTop: spacing.xs
115+
},
116+
section: {
117+
backgroundColor: colors.bgPanel,
118+
borderRadius: 12,
119+
overflow: 'hidden'
120+
},
121+
row: {
122+
flexDirection: 'row',
123+
alignItems: 'center',
124+
gap: spacing.sm + 2,
125+
paddingVertical: spacing.md,
126+
paddingHorizontal: spacing.md + 2
127+
},
128+
rowPressed: {
129+
backgroundColor: colors.bgRaised
130+
},
131+
rowLabel: {
132+
flex: 1,
133+
fontSize: typography.bodySize,
134+
fontWeight: '500',
135+
color: colors.textPrimary
136+
},
137+
rowValue: {
138+
fontSize: typography.bodySize,
139+
color: colors.accentBlue
140+
},
141+
separator: {
142+
height: StyleSheet.hairlineWidth,
143+
backgroundColor: colors.borderSubtle,
144+
marginHorizontal: spacing.md
145+
}
146+
})

0 commit comments

Comments
 (0)