Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
2ea51bd
fix(server): OpenCode model parsing drops models with a slash in the …
arhxam Aug 11, 2026
59d0c92
fix(web): persist sidebar shelf collapse state (#5136)
PixPMusic Aug 11, 2026
f973097
perf(web): skip base64 for oversized image candidates (#5220)
tarik02 Aug 11, 2026
1fa315e
fix(server): skip Linux libc detection on Windows/macOS (#5354)
bkntr Aug 11, 2026
c14bcca
fix(server): advertise 256-color TERM on Windows terminals (#5693)
yassiEmp Aug 11, 2026
9c7622d
fix(server): handle unborn HEAD in VCS status (#5944)
t3-code[bot] Aug 11, 2026
f5fce74
fix(pull-requests): route self-hosted GitLab remotes (#6061)
GuilhermeVieiraDev Aug 11, 2026
752acbf
feat: add ability to create a new thread in the current project with …
UtkarshUsername Aug 11, 2026
65b005f
feat(web): add Copy Thread ID to the sidebar and chat header thread c…
UtkarshUsername Aug 11, 2026
6676f9c
fix(mobile): stabilize thread composer and interactions (#5986)
juliusmarminge Aug 11, 2026
c842c6f
Add hourly past-24-hour usage view (#6170)
juliusmarminge Aug 11, 2026
3da7f9c
fix(mobile): guard App Store release versions (#6177)
juliusmarminge Aug 11, 2026
ac4780f
fix(web): restore typography font sizes to defaults (#6172)
StiensWout Aug 11, 2026
b30a9bc
feat(web): make environment artwork theme aware (#6183)
juliusmarminge Aug 11, 2026
6befe42
fix(shared): normalize a bare Windows drive root the same as C:\ / C:…
arhxam Aug 11, 2026
220e573
fix(shared): detect Azure DevOps SSH remotes (ssh.dev.azure.com) (#6187)
arhxam Aug 11, 2026
44621c3
feat(web): add back buttons for the pull requests and usage pages in …
UtkarshUsername Aug 11, 2026
1e355a2
fix(web): render dropdowns above toasts (#6165)
Brechard Aug 11, 2026
57b1052
fix(web): thread error banner dismiss survives reconnect and rerender…
myacoub91 Aug 11, 2026
3517201
fix(web): use a clearer pull action icon (#6194)
extoci Aug 11, 2026
083fa4a
feat(web): use OKLCH for theme palettes (#6036)
StiensWout Aug 11, 2026
2db0845
fix(web): use upload icon for disabled push action (#6207)
t3-code[bot] Aug 11, 2026
f0b57ca
feat(web): add Open VSX theme search (#5654)
t3-code[bot] Aug 11, 2026
c196f42
fix(web): clean up composer resize animation (#6209)
extoci Aug 11, 2026
52e5a75
feat(web): compact sidebar footer actions (#6210)
maria-rcks Aug 11, 2026
560d4a4
fix(web): keep sidebar wordmark visible at minimum width (#6246)
extoci Aug 11, 2026
d37a9b0
feat(mobile): add thread title regeneration (#6253)
chrisdeeming Aug 12, 2026
63e6fae
chore: add dara to vouched (#6259)
maria-rcks Aug 12, 2026
8efed5a
Merge upstream/main into Phoenix (28 commits, e5c82d7..63e6fae)
roughcoder Aug 12, 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
1 change: 1 addition & 0 deletions .github/VOUCHED.td
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,4 @@ github:shivamhwp
github:jappyjan
github:justsomelegs
github:UtkarshUsername
github:SunkenInTime
93 changes: 83 additions & 10 deletions .github/workflows/mobile-eas-production.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ name: Mobile EAS Production
#
# Every merge to main that touches the mobile app reconciles, per platform:
# 1. Store builds: if the latest production build's version differs from
# app.config.ts, cut a new build with --auto-submit (TestFlight +
# Play internal track). Bumping `version` is therefore all it takes to
# app.config.ts, cut a new build and submit it (TestFlight + Play internal
# track). Bumping `version` is therefore all it takes to
# start the next release train — the first build of a version enters
# external-TestFlight beta review immediately, and later builds of the
# same version auto-approve. Releasing to the App Store stays a manual
# App Store Connect step.
# same version auto-approve until that version is released. After App
# Store approval, Apple closes the release train and `version` must be
# bumped before another iOS build can be submitted. Releasing to the App
# Store stays a manual App Store Connect step.
# 2. OTA: publish a production-channel update for each platform where at
# least one finished production build matches the current native
# fingerprint. Old-version binaries with a matching fingerprint receive
Expand Down Expand Up @@ -42,6 +44,10 @@ on:
- ios
- android
- all
version:
description: "Optional build version override (blank uses app.config.ts; an override is committed before building)"
required: false
type: string
message:
description: "OTA update message (mode=update only)"
required: false
Expand Down Expand Up @@ -89,11 +95,21 @@ jobs:
echo "EXPO_TOKEN is not available; skipping EAS production job."
fi

- id: version_app_token
name: Mint release app token for version override
if: steps.expo-token.outputs.present == 'true' && github.event_name == 'workflow_dispatch' && inputs.mode == 'build' && inputs.version != ''
uses: actions/create-github-app-token@v2
with:
app-id: ${{ secrets.RELEASE_APP_ID }}
private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}
owner: ${{ github.repository_owner }}

- name: Checkout
if: steps.expo-token.outputs.present == 'true'
uses: actions/checkout@v6
with:
fetch-depth: 0
token: ${{ steps.version_app_token.outputs.token || github.token }}
# No sparse-checkout here: it makes actions/checkout fetch with
# --filter=blob:none, and eas-cli archives the project via
# `git clone --depth 1 file://<workspace>`, which fails (exit 128)
Expand Down Expand Up @@ -135,6 +151,65 @@ jobs:
EXPO_TOKEN: ${{ secrets.EXPO_TOKEN }}
run: eas env:pull production --non-interactive

- name: Apply manual version override
if: steps.version_app_token.outcome == 'success'
env:
GH_TOKEN: ${{ steps.version_app_token.outputs.token }}
APP_SLUG: ${{ steps.version_app_token.outputs.app-slug }}
RELEASE_VERSION: ${{ inputs.version }}
run: |
if [ "$GITHUB_REF_TYPE" != "branch" ]; then
echo "Version overrides require dispatching this workflow from a branch; received $GITHUB_REF_TYPE '$GITHUB_REF_NAME'." >&2
exit 1
fi
if ! [[ "$RELEASE_VERSION" =~ ^[0-9]+(\.[0-9]+){1,2}$ ]]; then
echo "Version override must contain two or three dot-separated integers; received '$RELEASE_VERSION'." >&2
exit 1
fi

node --input-type=module -e '
import fs from "node:fs";
const path = "apps/mobile/app.config.ts";
const source = fs.readFileSync(path, "utf8");
const next = source.replace(
/^( version: ")[^"]+(".*)$/m,
`$1${process.env.RELEASE_VERSION}$2`,
);
if (next === source && !source.includes(` version: "${process.env.RELEASE_VERSION}"`)) {
throw new Error("Could not update app version");
}
fs.writeFileSync(path, next);
'
vp fmt apps/mobile/app.config.ts

if git diff --quiet -- apps/mobile/app.config.ts; then
echo "app.config.ts is already at $RELEASE_VERSION; no version commit needed."
exit 0
fi

user_id="$(gh api "/users/${APP_SLUG}[bot]" --jq .id)"
git config user.name "${APP_SLUG}[bot]"
git config user.email "${user_id}+${APP_SLUG}[bot]@users.noreply.github.com"
git add apps/mobile/app.config.ts
git commit \
-m "chore(mobile): bump app version to $RELEASE_VERSION" \
-m "Co-authored-by: codex <codex@users.noreply.github.com>"
git push origin "HEAD:refs/heads/${GITHUB_REF_NAME}"

- name: Summarize manual build version
if: steps.expo-token.outputs.present == 'true' && github.event_name == 'workflow_dispatch' && inputs.mode == 'build'
working-directory: apps/mobile
run: |
version="$(npx expo config --json --type public | jq -r '.version')"
{
echo "## Manual production build"
echo
echo "- App version: \`$version\`"
echo "- Platform: \`${{ inputs.platform }}\`"
echo
echo "> Apple closes an iOS release train after App Store approval. Before building iOS, confirm \`$version\` is newer than the approved App Store version."
} >> "$GITHUB_STEP_SUMMARY"

- name: Build and submit (manual)
if: steps.expo-token.outputs.present == 'true' && github.event_name == 'workflow_dispatch' && inputs.mode == 'build'
working-directory: apps/mobile
Expand All @@ -157,10 +232,8 @@ jobs:

# No --status filter on build:list: an in-queue/in-progress build must
# count as existing, or every merge during the build window would cut a
# duplicate. Builds started here stay attached to this serialized run so
# the queued run for a later merge cannot overtake them and lose its OTA.
# After an errored build, retry via workflow_dispatch mode=build — pushes
# won't re-trigger it until the app version changes.
# duplicate. After an errored build, retry via workflow_dispatch
# mode=build — pushes won't re-trigger it until the app version changes.
- id: store_builds
name: Ensure store builds exist for the current app version
if: steps.expo-token.outputs.present == 'true' && github.event_name == 'push'
Expand All @@ -178,8 +251,8 @@ jobs:
continue
fi
echo "$platform: latest production build is $latest, app.config.ts says $version — building"
if eas build --platform "$platform" --profile production --auto-submit --non-interactive; then
echo ":building_construction: $platform: cut production build for $version (auto-submitted)" >> "$GITHUB_STEP_SUMMARY"
if eas build --platform "$platform" --profile production --auto-submit --non-interactive --no-wait; then
echo ":building_construction: $platform: scheduled production build and submission for $version" >> "$GITHUB_STEP_SUMMARY"
else
failed=1
echo ":x: $platform: production build or submission failed for $version" >> "$GITHUB_STEP_SUMMARY"
Expand Down
2 changes: 1 addition & 1 deletion apps/mobile/app.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ const config: ExpoConfig = {
slug: "t3-code",
platforms: ["ios", "android"],
scheme: variant.scheme,
version: "1.0.2",
version: "1.0.3",
runtimeVersion: {
// Fingerprint (not appVersion) so an OTA only reaches binaries whose native
// project — native deps, config plugins, AND patches/ — matches the update.
Expand Down
2 changes: 1 addition & 1 deletion apps/mobile/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
"@expo-google-fonts/dm-sans": "^0.4.2",
"@expo/metro-runtime": "~56.0.15",
"@expo/ui": "~56.0.18",
"@legendapp/list": "3.3.3",
"@legendapp/list": "catalog:",
"@noble/curves": "catalog:",
"@noble/hashes": "catalog:",
"@pierre/diffs": "catalog:",
Expand Down
33 changes: 20 additions & 13 deletions apps/mobile/src/Stack.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import { AppText as Text } from "./components/AppText";
import { getCompactBrandHeaderOptions } from "./components/CompactBrandTitle";
import { ArchivedThreadsRouteScreen } from "./features/archive/ArchivedThreadsRouteScreen";
import { useAgentNotificationNavigation } from "./features/agent-awareness/notificationNavigation";
import { ClerkSettingsSheetDetentProvider } from "./features/cloud/ClerkSettingsSheetDetent";
import { ConnectOnboardingRouteScreen } from "./features/cloud/ConnectOnboardingRouteScreen";
import { useConnectOnboardingNavigation } from "./features/cloud/connectOnboardingNavigation";
import { ThreadFilesTreeScreen, ThreadFileScreen } from "./features/files/ThreadFilesRouteScreen";
Expand Down Expand Up @@ -134,7 +133,7 @@ const LEGAL_DOCUMENT_HEADER_OPTIONS: AppScreenOptions = {
presentation: "fullScreenModal",
};

const SettingsSheetStack = createNativeStackNavigator({
const SettingsContentStack = createNativeStackNavigator({
initialRouteName: "Settings",
screenOptions: {
...GLASS_HEADER_OPTIONS,
Expand Down Expand Up @@ -198,20 +197,30 @@ const SettingsSheetStack = createNativeStackNavigator({
title: "Usage",
},
}),
},
});

// The outer stack never owns visible chrome. Settings routes render inside a
// nested stack whose native header remains mounted, while Clerk owns auth chrome.
// Keeping bar visibility invariant avoids iOS 26's headerless-to-headered jump.
const SettingsSheetStack = createNativeStackNavigator({
initialRouteName: "SettingsContent",
screenOptions: {
headerShown: false,
},
screens: {
SettingsContent: createNativeStackScreen({
screen: SettingsContentStack,
linking: "",
}),
SettingsAuth: createNativeStackScreen({
screen: SettingsAuthRouteScreen,
linking: "auth",
options: {
title: "Sign in",
},
}),
SettingsWaitlist: createNativeStackScreen({
// Keep the old deep link working after the Connect GA launch.
screen: SettingsAuthRouteScreen,
linking: "waitlist",
options: {
title: "Sign in",
},
}),
},
});
Expand Down Expand Up @@ -347,11 +356,9 @@ function RootStackLayout(props: {
<HardwareKeyboardCommandProvider pathname={pathname}>
<ThreadOutboxDrainWorker />
<ShowcaseCaptureCoordinator pathname={pathname} />
<ClerkSettingsSheetDetentProvider initiallyExpanded={false}>
<AdaptiveWorkspaceLayout pathname={workspacePathname}>
{props.children}
</AdaptiveWorkspaceLayout>
</ClerkSettingsSheetDetentProvider>
<AdaptiveWorkspaceLayout pathname={workspacePathname}>
{props.children}
</AdaptiveWorkspaceLayout>
</HardwareKeyboardCommandProvider>
);
}
Expand Down
27 changes: 26 additions & 1 deletion apps/mobile/src/components/ControlPill.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
type ComponentProps,
type ReactElement,
type ReactNode,
useRef,
} from "react";
import { Platform, Pressable, useColorScheme, View } from "react-native";
import { useThemeColor } from "../lib/useThemeColor";
Expand All @@ -21,10 +22,31 @@ export function ControlPill(props: {
readonly label?: string;
readonly accessibilityLabel?: string;
readonly onPress?: () => void;
readonly activateOnPressIn?: boolean;
readonly variant?: "circle" | "pill" | "primary" | "danger";
readonly disabled?: boolean;
readonly className?: string;
}) {
const variant = props.variant ?? "circle";
const activatedOnPressInRef = useRef(false);

const handlePressIn = () => {
activatedOnPressInRef.current = true;
props.onPress?.();
};
const handlePressOut = () => {
// Pressability invokes onPressOut immediately before onPress on release.
// Defer the reset so onPress can identify the same physical gesture.
setTimeout(() => {
activatedOnPressInRef.current = false;
}, 0);
};
const handlePress = () => {
if (activatedOnPressInRef.current) {
return;
}
props.onPress?.();
};

const iconColor = useThemeColor("--color-icon");
const iconSubtle = useThemeColor("--color-icon-subtle");
Expand Down Expand Up @@ -54,6 +76,7 @@ export function ControlPill(props: {
: variant === "danger"
? "bg-danger"
: "bg-subtle",
props.className,
);
const labelClassName = cn(
"text-center text-xs font-t3-bold",
Expand All @@ -68,7 +91,9 @@ export function ControlPill(props: {
<Pressable
accessibilityLabel={props.accessibilityLabel ?? props.label}
accessibilityRole="button"
onPress={props.onPress}
onPress={props.activateOnPressIn ? handlePress : props.onPress}
onPressIn={props.activateOnPressIn ? handlePressIn : undefined}
onPressOut={props.activateOnPressIn ? handlePressOut : undefined}
disabled={props.disabled}
className={containerClassName}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { useFocusEffect } from "@react-navigation/native";
import { useCallback, useMemo, useState } from "react";

import { useSavedRemoteConnections } from "../../state/use-remote-environment-registry";
import { useClerkSettingsSheetDetent } from "../cloud/ClerkSettingsSheetDetent";
import { useArchivedThreadListActions } from "../home/useThreadListActions";
import {
ArchivedThreadsScreen,
Expand All @@ -18,7 +17,6 @@ import {
} from "./useArchivedThreadSnapshots";

export function ArchivedThreadsRouteScreen() {
const { expand } = useClerkSettingsSheetDetent();
const { savedConnectionsById } = useSavedRemoteConnections();
const [searchQuery, setSearchQuery] = useState("");
const [selectedEnvironmentId, setSelectedEnvironmentId] = useState<EnvironmentId | null>(null);
Expand Down Expand Up @@ -70,9 +68,8 @@ export function ArchivedThreadsRouteScreen() {

useFocusEffect(
useCallback(() => {
expand();
refresh();
}, [expand, refresh]),
}, [refresh]),
);

return (
Expand Down
44 changes: 0 additions & 44 deletions apps/mobile/src/features/cloud/ClerkSettingsSheetDetent.tsx

This file was deleted.

4 changes: 2 additions & 2 deletions apps/mobile/src/features/cloud/connectOnboardingNavigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import { appAtomRegistry } from "../../state/atom-registry";
import { clearConnectOnboardingRequest, connectOnboardingRequestAtom } from "./connectOnboarding";
import { isConnectOnboardingOptedOut } from "./connectOnboardingOptOut";

// Sign-in happens inside the Settings sheet; give its detent/session-state
// transitions a beat to settle before presenting another formSheet on top.
// Sign-in happens inside the Settings sheet; give its session-state transition
// a beat to settle before presenting another formSheet on top.
const PRESENT_ONBOARDING_DELAY_MS = 600;

/**
Expand Down
Loading
Loading