Skip to content
This repository was archived by the owner on Aug 6, 2026. It is now read-only.

Commit d2aa7b7

Browse files
refactor(mobile): finalize portability boundary (#3642)
Co-authored-by: posthog[bot] <206114724+posthog[bot]@users.noreply.github.com> Co-authored-by: richardsolomou <2622273+richardsolomou@users.noreply.github.com>
1 parent dd419cf commit d2aa7b7

42 files changed

Lines changed: 2402 additions & 2601 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

apps/code/snapshots.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -544,10 +544,26 @@ snapshots:
544544
hash: v1.k4693efd2.fdbf0c24cb386c4345279db3e648efe72aa8a2a984d491361522f62074a771c9.2QmRxRMWYFFfBFrbMm0Dm9rWcvd1lfRbc0egfzoESnY
545545
loops-loopslistview--long-mixed-list--light:
546546
hash: v1.k4693efd2.aa17d9b6f40fbd3914bd742951db9f90add0bd233c54170803c8483aeb45b43b.yXpqqGczOq1uW5k4Ie7ddNTnne-cFTglZ9cL800pXB4
547+
loops-loopslistview--shared-page-header--dark:
548+
hash: v1.k4693efd2.14ab860dcb0df51b4019f012288e45f3a2c4c23fa08e809efef8c04b5687fe36.qoMLHprZmV2wON156NBbl3sqP84a4nXgdYm1H6WpTVM
549+
loops-loopslistview--shared-page-header--light:
550+
hash: v1.k4693efd2.23be5408ff3b4a912a0ce0457af8638124b99a01c88a499d0f4204cee2c62487.dGBP1K08MA2Fvhml-BPl5eFra8U83JXmy04NK9wOQnM
547551
loops-loopslistview--with-builder-sessions--dark:
548552
hash: v1.k4693efd2.df4a1a4764e1de7b69905814b09c30d9b43f705f5e66c7ad83829c567d4faa1a.jthufoX_KPbbxScjj3pPBA4lEtT9Ym6zUCH-v1759GM
549553
loops-loopslistview--with-builder-sessions--light:
550554
hash: v1.k4693efd2.eb65c38bb0de7efedbc0d7a6c27a6695528e2e6b60949617e7d22335b1e68c8b.fJr9uykvc8S7LI_ASXk5KRqxXCwIqh6ld9zfzs4shP0
555+
primitives-pageheader--title-only--dark:
556+
hash: v1.k4693efd2.f7f8c560b1e5cf20050189e10fc0f129e555ba672300a7a09bef5827c171a743.yP9Pp_k51agu_9Ri55Y7uCAPBQ1UTeUQJA9U9dPMKfQ
557+
primitives-pageheader--title-only--light:
558+
hash: v1.k4693efd2.23cc3ecf3368b1afa7c82030bfdf970038cc08f2fc368638793cc2531c192449.TKV1iBYKoxlh2zUHTcn20XcgiSSxnwxl8RMtOtiZulA
559+
primitives-pageheader--with-chip-and-actions--dark:
560+
hash: v1.k4693efd2.77944f2c03180f0398b569a135a2255da1f4443f5adcb37b34cf3c0bb5600a68.QLDr2Jxc7qZBh3BzoKafcC6uOGKcySrM29MyCNbkClU
561+
primitives-pageheader--with-chip-and-actions--light:
562+
hash: v1.k4693efd2.43898a2a38227b59fbe8ee7ea768ae9b411dd3069147b33900f893295ddaece5.qMZmk5VbZYivoAvC9L2IoXjhNUKeCrL9R5y9u_1cJ9c
563+
primitives-pageheader--with-tabs-and-filters--dark:
564+
hash: v1.k4693efd2.499090cdf01f81168a5a827ce5ea98e3e7e92481ec1348aa99cd908b13d011f8.PU0bMVAyZlVLBJ_1jzlaDQ_IEnkkNhg6sDQ_Qqv3TSg
565+
primitives-pageheader--with-tabs-and-filters--light:
566+
hash: v1.k4693efd2.f0fd2447dd5730b62ca844dbcad158cffec22dc4c1eb7cab3ed012d207eaa401.BVQgU-A9LPUC10qrDgIs2shYu9cl7FAwnFcUfE5BkSM
551567
scouts-scoutsfleetlist--filtered-to-you--dark:
552568
hash: v1.k4693efd2.a3af6e76ef36598eaa347bedc4430878ed62754660166398e0576a9978cd084b.x3Ky-O6HOw0srWdOmnnKJwFNpmGmQVWip0t7CwVaRXY
553569
scouts-scoutsfleetlist--filtered-to-you--light:

apps/mobile/app.json

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,8 @@
55
"version": "1.0.0",
66
"orientation": "portrait",
77
"userInterfaceStyle": "automatic",
8-
"newArchEnabled": true,
9-
"bundler": "metro",
108
"scheme": "posthog",
119
"icon": "./assets/app-icon.png",
12-
"splash": {
13-
"image": "./assets/splash-icon.png",
14-
"resizeMode": "contain",
15-
"backgroundColor": "#0f0f0f"
16-
},
1710
"ios": {
1811
"icon": "./assets/app.icon",
1912
"supportsTablet": true,
@@ -33,7 +26,6 @@
3326
"foregroundImage": "./assets/adaptive-icon.png",
3427
"backgroundColor": "#FFFFFF"
3528
},
36-
"edgeToEdgeEnabled": true,
3729
"predictiveBackGestureEnabled": false,
3830
"package": "com.posthog.code.mobile",
3931
"permissions": [
@@ -60,12 +52,7 @@
6052
},
6153
"plugins": [
6254
"expo-router",
63-
[
64-
"expo-av",
65-
{
66-
"microphonePermission": "Allow PostHog to use your microphone for voice-to-text input"
67-
}
68-
],
55+
"expo-audio",
6956
[
7057
"expo-camera",
7158
{
@@ -120,7 +107,18 @@
120107
"microphonePermission": "Allow PostHog to use your microphone for voice-to-text input",
121108
"speechRecognitionPermission": "Allow PostHog to transcribe your voice input on-device"
122109
}
123-
]
110+
],
111+
"expo-secure-store",
112+
[
113+
"expo-splash-screen",
114+
{
115+
"image": "./assets/splash-icon.png",
116+
"resizeMode": "contain",
117+
"backgroundColor": "#0f0f0f"
118+
}
119+
],
120+
"expo-status-bar",
121+
"expo-web-browser"
124122
],
125123
"extra": {
126124
"router": {},

apps/mobile/package.json

Lines changed: 56 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,25 @@
2323
"format": "biome format --write .",
2424
"clean": "node ../../scripts/rimraf.mjs .turbo .expo"
2525
},
26+
"expo": {
27+
"doctor": {
28+
"reactNativeDirectoryCheck": {
29+
"exclude": [
30+
"posthog-react-native-session-replay"
31+
]
32+
}
33+
},
34+
"install": {
35+
"exclude": [
36+
"react",
37+
"react-dom",
38+
"typescript"
39+
]
40+
}
41+
},
2642
"dependencies": {
27-
"@expo/ui": "0.2.0-beta.9",
43+
"@expo/metro-runtime": "~57.0.7",
44+
"@expo/ui": "57.0.7",
2845
"@modelcontextprotocol/ext-apps": "^1.2.2",
2946
"@modelcontextprotocol/sdk": "^1.29.0",
3047
"@posthog/api-client": "workspace:*",
@@ -34,47 +51,49 @@
3451
"@react-native-community/netinfo": "^12.0.1",
3552
"@tanstack/react-query": "^5.90.12",
3653
"date-fns": "^4.1.0",
37-
"expo": "~54.0.27",
38-
"expo-application": "~7.0.8",
39-
"expo-auth-session": "^7.0.10",
40-
"expo-av": "~16.0.8",
41-
"expo-camera": "^55.0.15",
42-
"expo-clipboard": "^55.0.13",
43-
"expo-constants": "~18.0.11",
44-
"expo-crypto": "^15.0.8",
45-
"expo-dev-client": "~6.0.20",
46-
"expo-device": "~8.0.10",
47-
"expo-document-picker": "~14.0.8",
48-
"expo-file-system": "~19.0.21",
49-
"expo-font": "^14.0.10",
50-
"expo-glass-effect": "~0.1.8",
51-
"expo-haptics": "^55.0.14",
52-
"expo-image-picker": "~17.0.11",
53-
"expo-linear-gradient": "^15.0.8",
54-
"expo-linking": "~8.0.10",
55-
"expo-localization": "~17.0.8",
56-
"expo-notifications": "~0.32.12",
57-
"expo-router": "~6.0.17",
58-
"expo-secure-store": "^15.0.8",
59-
"expo-speech-recognition": "^3.1.2",
60-
"expo-splash-screen": "~31.0.12",
61-
"expo-status-bar": "~3.0.9",
62-
"expo-system-ui": "~6.0.9",
63-
"expo-web-browser": "^15.0.10",
54+
"expo": "~57.0.8",
55+
"expo-application": "~57.0.2",
56+
"expo-audio": "~57.0.3",
57+
"expo-auth-session": "^57.0.5",
58+
"expo-camera": "^57.0.3",
59+
"expo-clipboard": "^57.0.1",
60+
"expo-constants": "~57.0.7",
61+
"expo-crypto": "^57.0.1",
62+
"expo-dev-client": "~57.0.9",
63+
"expo-device": "~57.0.1",
64+
"expo-document-picker": "~57.0.1",
65+
"expo-file-system": "~57.0.1",
66+
"expo-font": "^57.0.1",
67+
"expo-glass-effect": "~57.0.1",
68+
"expo-haptics": "^57.0.1",
69+
"expo-image-picker": "~57.0.6",
70+
"expo-linear-gradient": "^57.0.1",
71+
"expo-linking": "~57.0.4",
72+
"expo-localization": "~57.0.1",
73+
"expo-notifications": "~57.0.7",
74+
"expo-router": "~57.0.8",
75+
"expo-secure-store": "^57.0.1",
76+
"expo-speech-recognition": "^56.0.1",
77+
"expo-splash-screen": "~57.0.5",
78+
"expo-status-bar": "~57.0.1",
79+
"expo-system-ui": "~57.0.1",
80+
"expo-web-browser": "^57.0.2",
6481
"highlight.js": "^11.11.1",
6582
"nativewind": "^4.2.1",
6683
"phosphor-react-native": "^3.0.2",
6784
"posthog-react-native": "^4.18.0",
6885
"posthog-react-native-session-replay": "^1.6.0",
69-
"react": "19.2.6",
70-
"react-native": "0.81.5",
71-
"react-native-keyboard-controller": "1.18.5",
72-
"react-native-reanimated": "~4.1.1",
73-
"react-native-safe-area-context": "~5.6.2",
74-
"react-native-screens": "~4.16.0",
75-
"react-native-svg": "^15.15.1",
86+
"react": "catalog:",
87+
"react-dom": "catalog:",
88+
"react-native": "0.86.0",
89+
"react-native-keyboard-controller": "1.21.9",
90+
"react-native-reanimated": "~4.5.0",
91+
"react-native-safe-area-context": "~5.7.0",
92+
"react-native-screens": "~4.26.2",
93+
"react-native-svg": "^15.15.4",
7694
"react-native-web": "^0.21.2",
77-
"react-native-webview": "^13.13.5",
95+
"react-native-webview": "^13.16.1",
96+
"react-native-worklets": "0.10.0",
7897
"zustand": "^4.5.7"
7998
},
8099
"devDependencies": {
@@ -83,7 +102,7 @@
83102
"@types/react-test-renderer": "^19.1.0",
84103
"@vitejs/plugin-react": "^4.7.0",
85104
"react-native-svg-transformer": "^1.5.3",
86-
"react-test-renderer": "^19.2.6",
105+
"react-test-renderer": "19.2.6",
87106
"tailwindcss": "^3.4.18",
88107
"typescript": "~5.9.2",
89108
"vite": "^6.4.1",

apps/mobile/src/app/(tabs)/inbox.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ export default function InboxScreen() {
7171
visibleReports: reports,
7272
totalCount,
7373
filters: {
74+
surface: "mobile",
7475
sourceProductFilter,
7576
statusFilter,
7677
suggestedReviewerFilter,

apps/mobile/src/app/mcp-servers/installation/[id].tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { Text } from "@components/text";
22
import type { McpApprovalState } from "@posthog/api-client/types";
3-
import { isStdioMcpServer } from "@posthog/core/mcp-servers/presentation";
43
import { router, useLocalSearchParams } from "expo-router";
54
import {
65
ArrowsClockwise,
@@ -29,6 +28,7 @@ import {
2928
useUpdateMcpToolApproval,
3029
} from "@/features/mcp/hooks";
3130
import { reauthorizeInstallation } from "@/features/mcp/oauth";
31+
import { isStdioMcpServer } from "@/features/mcp/presentation";
3232
import { getMcpConnectionManager } from "@/features/mcp/service";
3333
import { useScreenInsets } from "@/hooks/useScreenInsets";
3434
import { logger } from "@/lib/logger";

apps/mobile/src/app/mcp-servers/template/[id].tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { Text } from "@components/text";
2-
import { isStdioMcpServer } from "@posthog/core/mcp-servers/presentation";
32
import { router, useLocalSearchParams } from "expo-router";
43
import { Lock, Warning } from "phosphor-react-native";
54
import { useMemo, useState } from "react";
@@ -18,6 +17,7 @@ import {
1817
useMcpMarketplace,
1918
} from "@/features/mcp/hooks";
2019
import { installTemplateWithOAuth } from "@/features/mcp/oauth";
20+
import { isStdioMcpServer } from "@/features/mcp/presentation";
2121
import { useScreenInsets } from "@/hooks/useScreenInsets";
2222
import { logger } from "@/lib/logger";
2323
import { openExternalUrl } from "@/lib/openExternalUrl";

apps/mobile/src/app/task/index.tsx

Lines changed: 32 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
DEFAULT_CLAUDE_EXECUTION_MODE,
44
getAvailableModes,
55
} from "@posthog/core/sessions/executionModes";
6+
import { resolveCloudComposerModelChange } from "@posthog/core/task-detail/composerModelPolicy";
67
import {
78
DEFAULT_GATEWAY_MODEL,
89
DEFAULT_REASONING_EFFORT,
@@ -56,10 +57,10 @@ import {
5657
import type { PendingAttachment } from "@/features/tasks/composer/attachments/types";
5758
import { DotBackground } from "@/features/tasks/composer/DotBackground";
5859
import {
59-
getMobileModelOptions,
60+
getComposerModelOptions,
61+
getConfigOptionLabel,
62+
getMobileExecutionModes,
6063
getModelConfigOption,
61-
getModelLabel,
62-
resolveAvailableModel,
6364
} from "@/features/tasks/composer/options";
6465
import { Pill } from "@/features/tasks/composer/Pill";
6566
import { RepositoryPickerInline } from "@/features/tasks/composer/RepositoryPickerInline";
@@ -88,7 +89,7 @@ import { getPostHogApiClient } from "@/lib/posthogApiClient";
8889
import { toRgba, useThemeColors } from "@/lib/theme";
8990

9091
const log = logger.scope("task-create");
91-
const EXECUTION_MODES = getAvailableModes();
92+
const EXECUTION_MODES = getMobileExecutionModes(getAvailableModes());
9293

9394
const SUGGESTIONS = [
9495
"Create or update my CLAUDE.md file",
@@ -129,9 +130,10 @@ export default function NewTaskScreen() {
129130
const { insets, bottom } = useScreenInsets();
130131
const keyboard = useReanimatedKeyboardAnimation();
131132
const restingBottom = bottom("compact");
132-
const { configOptions, hasLiveConfig } = useCloudTaskConfigOptions("claude");
133+
const { configOptions, hasLiveConfig, isConfigReady } =
134+
useCloudTaskConfigOptions("claude");
133135
const modelConfigOption = getModelConfigOption(configOptions);
134-
const mobileModelOptions = getMobileModelOptions(modelConfigOption);
136+
const mobileModelOptions = getComposerModelOptions(modelConfigOption);
135137
const {
136138
error,
137139
hasGithubIntegration,
@@ -214,12 +216,14 @@ export default function NewTaskScreen() {
214216

215217
useEffect(() => {
216218
if (!hasLiveConfig) return;
217-
const availableModel = resolveAvailableModel(modelConfigOption, model);
218-
if (availableModel === model) return;
219-
setModel(availableModel);
220-
if (!isSupportedReasoningEffort("claude", availableModel, reasoning)) {
221-
setReasoning(DEFAULT_REASONING_EFFORT);
222-
}
219+
const next = resolveCloudComposerModelChange({
220+
adapter: "claude",
221+
modelOption: modelConfigOption,
222+
requestedModel: model,
223+
reasoning,
224+
});
225+
if (next.model !== model) setModel(next.model);
226+
if (next.reasoning !== reasoning) setReasoning(next.reasoning);
223227
}, [hasLiveConfig, model, modelConfigOption, reasoning]);
224228
const [creating, setCreating] = useState(false);
225229
const [repoSheetOpen, setRepoSheetOpen] = useState(false);
@@ -411,7 +415,7 @@ export default function NewTaskScreen() {
411415

412416
const hasContent = !!prompt.trim() || attachments.length > 0;
413417
const canSubmit =
414-
hasLiveConfig &&
418+
isConfigReady &&
415419
hasContent &&
416420
isRepositorySelectionComplete(selection) &&
417421
!creating;
@@ -424,7 +428,7 @@ export default function NewTaskScreen() {
424428
useWarmTask({
425429
repository: selection.repository,
426430
githubIntegrationId: selection.integrationId,
427-
composerIsEmpty: !hasContent || !hasLiveConfig,
431+
composerIsEmpty: !hasContent || !isConfigReady,
428432
runtimeAdapter: "claude",
429433
model,
430434
reasoningEffort: showReasoningPill ? reasoning : null,
@@ -649,7 +653,12 @@ export default function NewTaskScreen() {
649653

650654
<Pill
651655
icon={<Robot size={14} color={themeColors.gray[11]} />}
652-
label={getModelLabel(modelConfigOption, model)}
656+
label={
657+
getConfigOptionLabel(
658+
modelConfigOption.options,
659+
model,
660+
) ?? model
661+
}
653662
onPress={() => setModelSheetOpen(true)}
654663
/>
655664

@@ -769,10 +778,14 @@ export default function NewTaskScreen() {
769778
title="Model"
770779
value={model}
771780
onChange={(value) => {
772-
setModel(value);
773-
if (!isSupportedReasoningEffort("claude", value, reasoning)) {
774-
setReasoning(DEFAULT_REASONING_EFFORT);
775-
}
781+
const next = resolveCloudComposerModelChange({
782+
adapter: "claude",
783+
modelOption: modelConfigOption,
784+
requestedModel: value,
785+
reasoning,
786+
});
787+
setModel(next.model);
788+
setReasoning(next.reasoning);
776789
}}
777790
onClose={() => setModelSheetOpen(false)}
778791
options={mobileModelOptions.map((modelOption) => ({

apps/mobile/src/features/inbox/activityLog.test.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
import {
22
attributionLabel,
3-
parseDiffLines,
4-
selectActivityArtefacts,
5-
shortSha,
63
taskRunLabel,
74
} from "@posthog/core/inbox/activityLog";
85
import type { AnySignalReportArtefact } from "@posthog/shared/domain-types";
96
import { describe, expect, it } from "vitest";
7+
import {
8+
parseDiffLines,
9+
selectActivityArtefacts,
10+
shortSha,
11+
} from "./activityLog";
1012

1113
function commit(id: string, createdAt: string): AnySignalReportArtefact {
1214
return {

0 commit comments

Comments
 (0)