Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
484a6c7
refactor(shared): extract task contracts and model policy
richardsolomou Jul 24, 2026
ec5fb80
fix(models): preserve GLM effort policy
richardsolomou Jul 24, 2026
fa2dda4
test(ui): wait for async content
richardsolomou Jul 24, 2026
0960bc3
test(ui): isolate plan approval presentation
richardsolomou Jul 24, 2026
3f608f2
fix(shared): Preserve canonical task artifacts
richardsolomou Jul 28, 2026
9c4235c
test(agent): match canonical model picker order
richardsolomou Jul 28, 2026
b4e9084
Merge main into shared cloud task foundations
richardsolomou Jul 29, 2026
b69d17d
refactor(api-client): extract cloud task transport
richardsolomou Jul 24, 2026
01aec6d
refactor(core): extract cloud task policies
richardsolomou Jul 24, 2026
53e5383
refactor(core): rename cloud task service as engine
richardsolomou Jul 24, 2026
2245a2e
refactor(core): extract portable cloud task engine
richardsolomou Jul 24, 2026
36f9b39
refactor(core): extract repository integration semantics
richardsolomou Jul 24, 2026
3003336
refactor(core): extract pending prompt recovery
richardsolomou Jul 24, 2026
b5204c8
refactor(core): extract plan approval presentation
richardsolomou Jul 24, 2026
7ccd259
refactor(core): extract permission option presentation
richardsolomou Jul 24, 2026
046422e
refactor(core): extract composer controls
richardsolomou Jul 24, 2026
37f1c0b
refactor(core): extract composer model policy
richardsolomou Jul 24, 2026
0a1c884
fix(core): prefer streamed plan content
richardsolomou Jul 24, 2026
e27b337
refactor(core): extract session presentation semantics
richardsolomou Jul 24, 2026
04a7f52
refactor(api-client): expose shared automation contracts
richardsolomou Jul 24, 2026
0b25fcd
refactor(core): extract inbox presentation semantics
richardsolomou Jul 24, 2026
afa5cb6
refactor(core): extract inbox activity presentation
richardsolomou Jul 24, 2026
a7e4e28
refactor(core): extract portability contracts
richardsolomou Jul 24, 2026
1f3ad6a
refactor(ui): reuse inbox identifier formatting
richardsolomou Jul 24, 2026
0c3e6fb
refactor(mobile): adopt shared task runtime
richardsolomou Jul 24, 2026
5299c52
fix(mobile): preserve permission mode on resume
richardsolomou Jul 24, 2026
2b5d2a5
refactor(mobile): finish shared task adoption
richardsolomou Jul 24, 2026
d98d556
refactor(mobile): adopt repository and inbox transport
richardsolomou Jul 24, 2026
2a5f225
refactor(mobile): adopt shared MCP and composer policies
richardsolomou Jul 24, 2026
0d46bfb
refactor(mobile): adopt shared presentation semantics
richardsolomou Jul 24, 2026
57df2f0
test(mobile): use shared inbox helpers
richardsolomou Jul 24, 2026
807299f
refactor(mobile): finalize shared portability boundary
richardsolomou Jul 24, 2026
38e8dc7
fix(mobile): align portable runtime dependencies
richardsolomou Jul 24, 2026
9284b42
chore(mobile): Upgrade to Expo 57
richardsolomou Jul 28, 2026
587ac90
chore: merge main into portability cleanup
richardsolomou Jul 29, 2026
aae980f
chore(visual): update storybook baselines
posthog[bot] Jul 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions apps/code/snapshots.yml
Original file line number Diff line number Diff line change
Expand Up @@ -544,10 +544,26 @@ snapshots:
hash: v1.k4693efd2.fdbf0c24cb386c4345279db3e648efe72aa8a2a984d491361522f62074a771c9.2QmRxRMWYFFfBFrbMm0Dm9rWcvd1lfRbc0egfzoESnY
loops-loopslistview--long-mixed-list--light:
hash: v1.k4693efd2.aa17d9b6f40fbd3914bd742951db9f90add0bd233c54170803c8483aeb45b43b.yXpqqGczOq1uW5k4Ie7ddNTnne-cFTglZ9cL800pXB4
loops-loopslistview--shared-page-header--dark:
hash: v1.k4693efd2.14ab860dcb0df51b4019f012288e45f3a2c4c23fa08e809efef8c04b5687fe36.qoMLHprZmV2wON156NBbl3sqP84a4nXgdYm1H6WpTVM
loops-loopslistview--shared-page-header--light:
hash: v1.k4693efd2.23be5408ff3b4a912a0ce0457af8638124b99a01c88a499d0f4204cee2c62487.dGBP1K08MA2Fvhml-BPl5eFra8U83JXmy04NK9wOQnM
loops-loopslistview--with-builder-sessions--dark:
hash: v1.k4693efd2.df4a1a4764e1de7b69905814b09c30d9b43f705f5e66c7ad83829c567d4faa1a.jthufoX_KPbbxScjj3pPBA4lEtT9Ym6zUCH-v1759GM
loops-loopslistview--with-builder-sessions--light:
hash: v1.k4693efd2.eb65c38bb0de7efedbc0d7a6c27a6695528e2e6b60949617e7d22335b1e68c8b.fJr9uykvc8S7LI_ASXk5KRqxXCwIqh6ld9zfzs4shP0
primitives-pageheader--title-only--dark:
hash: v1.k4693efd2.f7f8c560b1e5cf20050189e10fc0f129e555ba672300a7a09bef5827c171a743.yP9Pp_k51agu_9Ri55Y7uCAPBQ1UTeUQJA9U9dPMKfQ
primitives-pageheader--title-only--light:
hash: v1.k4693efd2.23cc3ecf3368b1afa7c82030bfdf970038cc08f2fc368638793cc2531c192449.TKV1iBYKoxlh2zUHTcn20XcgiSSxnwxl8RMtOtiZulA
primitives-pageheader--with-chip-and-actions--dark:
hash: v1.k4693efd2.77944f2c03180f0398b569a135a2255da1f4443f5adcb37b34cf3c0bb5600a68.QLDr2Jxc7qZBh3BzoKafcC6uOGKcySrM29MyCNbkClU
primitives-pageheader--with-chip-and-actions--light:
hash: v1.k4693efd2.43898a2a38227b59fbe8ee7ea768ae9b411dd3069147b33900f893295ddaece5.qMZmk5VbZYivoAvC9L2IoXjhNUKeCrL9R5y9u_1cJ9c
primitives-pageheader--with-tabs-and-filters--dark:
hash: v1.k4693efd2.499090cdf01f81168a5a827ce5ea98e3e7e92481ec1348aa99cd908b13d011f8.PU0bMVAyZlVLBJ_1jzlaDQ_IEnkkNhg6sDQ_Qqv3TSg
primitives-pageheader--with-tabs-and-filters--light:
hash: v1.k4693efd2.f0fd2447dd5730b62ca844dbcad158cffec22dc4c1eb7cab3ed012d207eaa401.BVQgU-A9LPUC10qrDgIs2shYu9cl7FAwnFcUfE5BkSM
scouts-scoutsfleetlist--filtered-to-you--dark:
hash: v1.k4693efd2.a3af6e76ef36598eaa347bedc4430878ed62754660166398e0576a9978cd084b.x3Ky-O6HOw0srWdOmnnKJwFNpmGmQVWip0t7CwVaRXY
scouts-scoutsfleetlist--filtered-to-you--light:
Expand Down
28 changes: 13 additions & 15 deletions apps/mobile/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,8 @@
"version": "1.0.0",
"orientation": "portrait",
"userInterfaceStyle": "automatic",
"newArchEnabled": true,
"bundler": "metro",
"scheme": "posthog",
"icon": "./assets/app-icon.png",
"splash": {
"image": "./assets/splash-icon.png",
"resizeMode": "contain",
"backgroundColor": "#0f0f0f"
},
"ios": {
"icon": "./assets/app.icon",
"supportsTablet": true,
Expand All @@ -33,7 +26,6 @@
"foregroundImage": "./assets/adaptive-icon.png",
"backgroundColor": "#FFFFFF"
},
"edgeToEdgeEnabled": true,
"predictiveBackGestureEnabled": false,
"package": "com.posthog.code.mobile",
"permissions": [
Expand All @@ -60,12 +52,7 @@
},
"plugins": [
"expo-router",
[
"expo-av",
{
"microphonePermission": "Allow PostHog to use your microphone for voice-to-text input"
}
],
"expo-audio",
[
"expo-camera",
{
Expand Down Expand Up @@ -120,7 +107,18 @@
"microphonePermission": "Allow PostHog to use your microphone for voice-to-text input",
"speechRecognitionPermission": "Allow PostHog to transcribe your voice input on-device"
}
]
],
"expo-secure-store",
[
"expo-splash-screen",
{
"image": "./assets/splash-icon.png",
"resizeMode": "contain",
"backgroundColor": "#0f0f0f"
}
],
"expo-status-bar",
"expo-web-browser"
],
"extra": {
"router": {},
Expand Down
93 changes: 56 additions & 37 deletions apps/mobile/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,25 @@
"format": "biome format --write .",
"clean": "node ../../scripts/rimraf.mjs .turbo .expo"
},
"expo": {
"doctor": {
"reactNativeDirectoryCheck": {
"exclude": [
"posthog-react-native-session-replay"
]
}
},
"install": {
"exclude": [
"react",
"react-dom",
"typescript"
]
}
},
"dependencies": {
"@expo/ui": "0.2.0-beta.9",
"@expo/metro-runtime": "~57.0.7",
"@expo/ui": "57.0.7",
"@modelcontextprotocol/ext-apps": "^1.2.2",
"@modelcontextprotocol/sdk": "^1.29.0",
"@posthog/api-client": "workspace:*",
Expand All @@ -34,47 +51,49 @@
"@react-native-community/netinfo": "^12.0.1",
"@tanstack/react-query": "^5.90.12",
"date-fns": "^4.1.0",
"expo": "~54.0.27",
"expo-application": "~7.0.8",
"expo-auth-session": "^7.0.10",
"expo-av": "~16.0.8",
"expo-camera": "^55.0.15",
"expo-clipboard": "^55.0.13",
"expo-constants": "~18.0.11",
"expo-crypto": "^15.0.8",
"expo-dev-client": "~6.0.20",
"expo-device": "~8.0.10",
"expo-document-picker": "~14.0.8",
"expo-file-system": "~19.0.21",
"expo-font": "^14.0.10",
"expo-glass-effect": "~0.1.8",
"expo-haptics": "^55.0.14",
"expo-image-picker": "~17.0.11",
"expo-linear-gradient": "^15.0.8",
"expo-linking": "~8.0.10",
"expo-localization": "~17.0.8",
"expo-notifications": "~0.32.12",
"expo-router": "~6.0.17",
"expo-secure-store": "^15.0.8",
"expo-speech-recognition": "^3.1.2",
"expo-splash-screen": "~31.0.12",
"expo-status-bar": "~3.0.9",
"expo-system-ui": "~6.0.9",
"expo-web-browser": "^15.0.10",
"expo": "~57.0.8",
"expo-application": "~57.0.2",
"expo-audio": "~57.0.3",
"expo-auth-session": "^57.0.5",
"expo-camera": "^57.0.3",
"expo-clipboard": "^57.0.1",
"expo-constants": "~57.0.7",
"expo-crypto": "^57.0.1",
"expo-dev-client": "~57.0.9",
"expo-device": "~57.0.1",
"expo-document-picker": "~57.0.1",
"expo-file-system": "~57.0.1",
"expo-font": "^57.0.1",
"expo-glass-effect": "~57.0.1",
"expo-haptics": "^57.0.1",
"expo-image-picker": "~57.0.6",
"expo-linear-gradient": "^57.0.1",
"expo-linking": "~57.0.4",
"expo-localization": "~57.0.1",
"expo-notifications": "~57.0.7",
"expo-router": "~57.0.8",
"expo-secure-store": "^57.0.1",
"expo-speech-recognition": "^56.0.1",
"expo-splash-screen": "~57.0.5",
"expo-status-bar": "~57.0.1",
"expo-system-ui": "~57.0.1",
"expo-web-browser": "^57.0.2",
"highlight.js": "^11.11.1",
"nativewind": "^4.2.1",
"phosphor-react-native": "^3.0.2",
"posthog-react-native": "^4.18.0",
"posthog-react-native-session-replay": "^1.6.0",
"react": "19.2.6",
"react-native": "0.81.5",
"react-native-keyboard-controller": "1.18.5",
"react-native-reanimated": "~4.1.1",
"react-native-safe-area-context": "~5.6.2",
"react-native-screens": "~4.16.0",
"react-native-svg": "^15.15.1",
"react": "catalog:",
"react-dom": "catalog:",
"react-native": "0.86.0",
"react-native-keyboard-controller": "1.21.9",
"react-native-reanimated": "~4.5.0",
"react-native-safe-area-context": "~5.7.0",
"react-native-screens": "~4.26.2",
"react-native-svg": "^15.15.4",
"react-native-web": "^0.21.2",
"react-native-webview": "^13.13.5",
"react-native-webview": "^13.16.1",
"react-native-worklets": "0.10.0",
"zustand": "^4.5.7"
},
"devDependencies": {
Expand All @@ -83,7 +102,7 @@
"@types/react-test-renderer": "^19.1.0",
"@vitejs/plugin-react": "^4.7.0",
"react-native-svg-transformer": "^1.5.3",
"react-test-renderer": "^19.2.6",
"react-test-renderer": "19.2.6",
"tailwindcss": "^3.4.18",
"typescript": "~5.9.2",
"vite": "^6.4.1",
Expand Down
1 change: 1 addition & 0 deletions apps/mobile/src/app/(tabs)/inbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ export default function InboxScreen() {
visibleReports: reports,
totalCount,
filters: {
surface: "mobile",
sourceProductFilter,
statusFilter,
suggestedReviewerFilter,
Expand Down
2 changes: 1 addition & 1 deletion apps/mobile/src/app/mcp-servers/installation/[id].tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Text } from "@components/text";
import type { McpApprovalState } from "@posthog/api-client/types";
import { isStdioMcpServer } from "@posthog/core/mcp-servers/presentation";
import { router, useLocalSearchParams } from "expo-router";
import {
ArrowsClockwise,
Expand Down Expand Up @@ -29,6 +28,7 @@ import {
useUpdateMcpToolApproval,
} from "@/features/mcp/hooks";
import { reauthorizeInstallation } from "@/features/mcp/oauth";
import { isStdioMcpServer } from "@/features/mcp/presentation";
import { getMcpConnectionManager } from "@/features/mcp/service";
import { useScreenInsets } from "@/hooks/useScreenInsets";
import { logger } from "@/lib/logger";
Expand Down
2 changes: 1 addition & 1 deletion apps/mobile/src/app/mcp-servers/template/[id].tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { Text } from "@components/text";
import { isStdioMcpServer } from "@posthog/core/mcp-servers/presentation";
import { router, useLocalSearchParams } from "expo-router";
import { Lock, Warning } from "phosphor-react-native";
import { useMemo, useState } from "react";
Expand All @@ -18,6 +17,7 @@ import {
useMcpMarketplace,
} from "@/features/mcp/hooks";
import { installTemplateWithOAuth } from "@/features/mcp/oauth";
import { isStdioMcpServer } from "@/features/mcp/presentation";
import { useScreenInsets } from "@/hooks/useScreenInsets";
import { logger } from "@/lib/logger";
import { openExternalUrl } from "@/lib/openExternalUrl";
Expand Down
51 changes: 32 additions & 19 deletions apps/mobile/src/app/task/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
DEFAULT_CLAUDE_EXECUTION_MODE,
getAvailableModes,
} from "@posthog/core/sessions/executionModes";
import { resolveCloudComposerModelChange } from "@posthog/core/task-detail/composerModelPolicy";
import {
DEFAULT_GATEWAY_MODEL,
DEFAULT_REASONING_EFFORT,
Expand Down Expand Up @@ -56,10 +57,10 @@ import {
import type { PendingAttachment } from "@/features/tasks/composer/attachments/types";
import { DotBackground } from "@/features/tasks/composer/DotBackground";
import {
getMobileModelOptions,
getComposerModelOptions,
getConfigOptionLabel,
getMobileExecutionModes,
getModelConfigOption,
getModelLabel,
resolveAvailableModel,
} from "@/features/tasks/composer/options";
import { Pill } from "@/features/tasks/composer/Pill";
import { RepositoryPickerInline } from "@/features/tasks/composer/RepositoryPickerInline";
Expand Down Expand Up @@ -88,7 +89,7 @@ import { getPostHogApiClient } from "@/lib/posthogApiClient";
import { toRgba, useThemeColors } from "@/lib/theme";

const log = logger.scope("task-create");
const EXECUTION_MODES = getAvailableModes();
const EXECUTION_MODES = getMobileExecutionModes(getAvailableModes());

const SUGGESTIONS = [
"Create or update my CLAUDE.md file",
Expand Down Expand Up @@ -129,9 +130,10 @@ export default function NewTaskScreen() {
const { insets, bottom } = useScreenInsets();
const keyboard = useReanimatedKeyboardAnimation();
const restingBottom = bottom("compact");
const { configOptions, hasLiveConfig } = useCloudTaskConfigOptions("claude");
const { configOptions, hasLiveConfig, isConfigReady } =
useCloudTaskConfigOptions("claude");
const modelConfigOption = getModelConfigOption(configOptions);
const mobileModelOptions = getMobileModelOptions(modelConfigOption);
const mobileModelOptions = getComposerModelOptions(modelConfigOption);
const {
error,
hasGithubIntegration,
Expand Down Expand Up @@ -214,12 +216,14 @@ export default function NewTaskScreen() {

useEffect(() => {
if (!hasLiveConfig) return;
const availableModel = resolveAvailableModel(modelConfigOption, model);
if (availableModel === model) return;
setModel(availableModel);
if (!isSupportedReasoningEffort("claude", availableModel, reasoning)) {
setReasoning(DEFAULT_REASONING_EFFORT);
}
const next = resolveCloudComposerModelChange({
adapter: "claude",
modelOption: modelConfigOption,
requestedModel: model,
reasoning,
});
if (next.model !== model) setModel(next.model);
if (next.reasoning !== reasoning) setReasoning(next.reasoning);
}, [hasLiveConfig, model, modelConfigOption, reasoning]);
const [creating, setCreating] = useState(false);
const [repoSheetOpen, setRepoSheetOpen] = useState(false);
Expand Down Expand Up @@ -411,7 +415,7 @@ export default function NewTaskScreen() {

const hasContent = !!prompt.trim() || attachments.length > 0;
const canSubmit =
hasLiveConfig &&
isConfigReady &&
hasContent &&
isRepositorySelectionComplete(selection) &&
!creating;
Expand All @@ -424,7 +428,7 @@ export default function NewTaskScreen() {
useWarmTask({
repository: selection.repository,
githubIntegrationId: selection.integrationId,
composerIsEmpty: !hasContent || !hasLiveConfig,
composerIsEmpty: !hasContent || !isConfigReady,
runtimeAdapter: "claude",
model,
reasoningEffort: showReasoningPill ? reasoning : null,
Expand Down Expand Up @@ -649,7 +653,12 @@ export default function NewTaskScreen() {

<Pill
icon={<Robot size={14} color={themeColors.gray[11]} />}
label={getModelLabel(modelConfigOption, model)}
label={
getConfigOptionLabel(
modelConfigOption.options,
model,
) ?? model
}
onPress={() => setModelSheetOpen(true)}
/>

Expand Down Expand Up @@ -769,10 +778,14 @@ export default function NewTaskScreen() {
title="Model"
value={model}
onChange={(value) => {
setModel(value);
if (!isSupportedReasoningEffort("claude", value, reasoning)) {
setReasoning(DEFAULT_REASONING_EFFORT);
}
const next = resolveCloudComposerModelChange({
adapter: "claude",
modelOption: modelConfigOption,
requestedModel: value,
reasoning,
});
setModel(next.model);
setReasoning(next.reasoning);
}}
onClose={() => setModelSheetOpen(false)}
options={mobileModelOptions.map((modelOption) => ({
Expand Down
8 changes: 5 additions & 3 deletions apps/mobile/src/features/inbox/activityLog.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import {
attributionLabel,
parseDiffLines,
selectActivityArtefacts,
shortSha,
taskRunLabel,
} from "@posthog/core/inbox/activityLog";
import type { AnySignalReportArtefact } from "@posthog/shared/domain-types";
import { describe, expect, it } from "vitest";
import {
parseDiffLines,
selectActivityArtefacts,
shortSha,
} from "./activityLog";

function commit(id: string, createdAt: string): AnySignalReportArtefact {
return {
Expand Down
Loading
Loading