Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
2e66b1f
fix(web): live background-work banner no longer hides behind the upda…
t3dotgg Aug 7, 2026
b792ed9
fix(web): stabilize chat timeline positioning (#5449)
jmeistrich Aug 7, 2026
7963cc7
feat(server): record runtime mode per turn and on mode changes (#5593)
t3dotgg Aug 7, 2026
b2ee17d
feat(web): thread actions from the chat header title (#5592)
t3dotgg Aug 7, 2026
a17459e
fix(mobile): avoid iOS terminal reset on clear (#5440)
justynleung Aug 7, 2026
33a03c8
fix(mobile): pad scroll views above Android nav bar (#5415)
StoneCotton Aug 7, 2026
bd422fd
fix(mobile): keep Android chat text from showing through the composer…
PollyGlot Aug 7, 2026
af281c9
fix(mobile): repair Clerk auth navigation headers (#5140)
gabrielelpidio Aug 7, 2026
bfc69e4
Bump mobile app version to 1.0.2 (#5588)
juliusmarminge Aug 7, 2026
61b51ae
feat(web): click the pin icon to unpin a thread (#5578)
UtkarshUsername Aug 7, 2026
239ef1c
fix(web): show the correctly matching shortcut in new thread button's…
UtkarshUsername Aug 7, 2026
be1a836
chore(release): prepare v0.0.32
t3-code[bot] Aug 7, 2026
6d70e6d
fix(mobile): reconnects no longer shift the thread list (#5372)
t3dotgg Aug 7, 2026
5661c61
feat(web): drag pinned threads into your own order (#5581)
t3dotgg Aug 7, 2026
9528021
feat(connections): manage environment availability
DominicVonk Aug 7, 2026
e2cd238
chore(ci): vouch StiensWout (#5637)
t3-code[bot] Aug 7, 2026
72d673a
feat(desktop): remember recently used sites in the Browser panel (#5270)
chrisdeeming Aug 7, 2026
82406bc
chore: vouch chrisdeeming (#5641)
t3-code[bot] Aug 7, 2026
97f8cd1
Merge branch 'main' into codex/environment-management-ui
DominicVonk Aug 7, 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
2 changes: 2 additions & 0 deletions .github/VOUCHED.td
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
# Keep entries sorted alphabetically.
github:adityavardhansharma
github:binbandit
github:chrisdeeming
github:chuks-qua
github:cursoragent
github:gbarros-dev
Expand All @@ -26,6 +27,7 @@ github:notkainoa
github:PatrickBauer
github:realAhmedRoach
github:shiroyasha9
github:StiensWout
github:Yash-Singh1
github:eggfriedrice24
github:Ymit24
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@t3tools/desktop",
"version": "0.0.31",
"version": "0.0.32",
"private": true,
"type": "module",
"main": "dist-electron/main.cjs",
Expand Down
1 change: 1 addition & 0 deletions apps/desktop/src/app/DesktopConnectionCatalogStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,7 @@ const migrateSavedEnvironmentRecords = Effect.fn(
return {
schemaVersion: 1,
targets,
disabledEnvironmentIds: [],
profiles,
credentials,
remoteDpopTokens: [],
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.1",
version: "1.0.2",
runtimeVersion: {
// Fingerprint (not appVersion) so an OTA only reaches binaries whose native
// project — native deps, config plugins, AND patches/ — matches the update.
Expand Down
6 changes: 6 additions & 0 deletions apps/mobile/modules/t3-terminal/ios/T3TerminalView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,12 @@ public final class T3TerminalView: ExpoView, UITextFieldDelegate {
return
}

if buffer.isEmpty {
feedData(Data("\u{1B}[3J\u{1B}[H\u{1B}[2J".utf8))
lastAppliedBuffer = ""
return
}

if buffer.hasPrefix(lastAppliedBuffer) {
let suffix = String(buffer.dropFirst(lastAppliedBuffer.count))
feedData(Data(suffix.utf8))
Expand Down
23 changes: 13 additions & 10 deletions apps/mobile/src/components/CompactBrandTitle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,18 @@ import { NATIVE_LIQUID_GLASS_SUPPORTED } from "../native/native-glass";
const IOS_NATIVE_LEADING_TITLE_OFFSET = -6;
const IPAD_NATIVE_LEADING_TITLE_OFFSET = 7;

/**
* Horizontal correction applied to content rendered in the brand title slot,
* shared with the connection-status swap so both align identically.
*/
export function brandTitleOffset(nativeLeadingItem: boolean): number {
if (Platform.OS !== "ios") return 0;
if (nativeLeadingItem) {
return Platform.isPad ? IPAD_NATIVE_LEADING_TITLE_OFFSET : IOS_NATIVE_LEADING_TITLE_OFFSET;
}
return Platform.isPad ? IPAD_HOME_TITLE_OFFSET : 0;
}

/**
* Compact brand lockup sized for native navigation bars.
*/
Expand All @@ -28,16 +40,7 @@ export function CompactBrandTitle(
const mutedColor = useThemeColor("--color-foreground-muted");
const subtleColor = useThemeColor("--color-subtle");
const stageLabel = resolveMobileStageLabel(Constants.expoConfig?.extra?.appVariant);
const titleOffset =
Platform.OS !== "ios"
? 0
: props.nativeLeadingItem
? Platform.isPad
? IPAD_NATIVE_LEADING_TITLE_OFFSET
: IOS_NATIVE_LEADING_TITLE_OFFSET
: Platform.isPad
? IPAD_HOME_TITLE_OFFSET
: 0;
const titleOffset = brandTitleOffset(props.nativeLeadingItem === true);

return (
<View
Expand Down
2 changes: 2 additions & 0 deletions apps/mobile/src/connection/migration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ function migrateConnection(
label: connection.environmentLabel,
}),
}),
{ enabled: true },
);
}

Expand Down Expand Up @@ -84,6 +85,7 @@ function migrateConnection(
token: connection.bearerToken,
}),
}),
{ enabled: true },
);
}

Expand Down
28 changes: 25 additions & 3 deletions apps/mobile/src/connection/storage.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
ConnectionPersistenceError,
ConnectionActivationStore,
ConnectionRegistrationStore,
ConnectionTargetStore,
registerConnectionInCatalog,
Expand All @@ -20,7 +21,12 @@ import * as Option from "effect/Option";
import * as CatalogStore from "./catalog-store";

function targetPersistenceError(
operation: "list-targets" | "register-connection" | "remove-connection",
operation:
| "list-targets"
| "register-connection"
| "remove-connection"
| "list-activation"
| "set-activation",
error: ConnectionTransientError,
) {
return new ConnectionPersistenceError({
Expand All @@ -40,15 +46,30 @@ export const connectionStorageLayer = Layer.effectContext(
),
});
const registrationStore = ConnectionRegistrationStore.of({
register: (registration) =>
register: (registration, options) =>
catalog
.update((document) => registerConnectionInCatalog(document, registration))
.update((document) => registerConnectionInCatalog(document, registration, options))
.pipe(Effect.mapError((error) => targetPersistenceError("register-connection", error))),
remove: (target) =>
catalog
.update((document) => removeConnectionFromCatalog(document, target))
.pipe(Effect.mapError((error) => targetPersistenceError("remove-connection", error))),
});
const activationStore = ConnectionActivationStore.of({
listDisabled: catalog.read.pipe(
Effect.map((document) => new Set(document.disabledEnvironmentIds)),
Effect.mapError((error) => targetPersistenceError("list-activation", error)),
),
setEnabled: (environmentId, enabled) =>
catalog
.update((document) => ({
...document,
disabledEnvironmentIds: enabled
? document.disabledEnvironmentIds.filter((candidate) => candidate !== environmentId)
: [...new Set([...document.disabledEnvironmentIds, environmentId])],
}))
.pipe(Effect.mapError((error) => targetPersistenceError("set-activation", error))),
});
const profileStore = ProfileStore.make({
get: (connectionId) =>
catalog.read.pipe(
Expand Down Expand Up @@ -130,6 +151,7 @@ export const connectionStorageLayer = Layer.effectContext(
});
return Context.make(ConnectionTargetStore, targetStore).pipe(
Context.add(ConnectionRegistrationStore, registrationStore),
Context.add(ConnectionActivationStore, activationStore),
Context.add(ProfileStore.ConnectionProfileStore, profileStore),
Context.add(CredentialStore.ConnectionCredentialStore, credentialStore),
Context.add(TokenStore.RemoteDpopAccessTokenStore, remoteTokenStore),
Expand Down
55 changes: 45 additions & 10 deletions apps/mobile/src/features/cloud/ConnectOnboardingRouteScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,19 @@ import { NativeHeaderToolbar } from "../../native/StackHeader";
import { useAuth } from "@clerk/expo";
import { StackActions, useNavigation } from "@react-navigation/native";
import { useCallback, useEffect, useState } from "react";
import { Platform, Pressable, RefreshControl, ScrollView, View } from "react-native";
import {
Platform,
Pressable,
RefreshControl,
ScrollView,
View,
} from "react-native";
import { useSafeAreaInsets } from "react-native-safe-area-context";

import { reportAtomCommandResult, settlePromise } from "@t3tools/client-runtime/state/runtime";
import {
reportAtomCommandResult,
settlePromise,
} from "@t3tools/client-runtime/state/runtime";
import { AndroidSheetHeader } from "../../components/AndroidScreenHeader";
import { AppText as Text } from "../../components/AppText";
import { useRemoteConnections } from "../../state/use-remote-environment-registry";
Expand Down Expand Up @@ -38,14 +47,20 @@ export function ConnectOnboardingRouteScreen() {
}
}, [navigation]);

return hasCloudPublicConfig() ? <ConfiguredConnectOnboardingRouteScreen /> : null;
return hasCloudPublicConfig() ? (
<ConfiguredConnectOnboardingRouteScreen />
) : null;
}

function ConfiguredConnectOnboardingRouteScreen() {
const navigation = useNavigation();
const insets = useSafeAreaInsets();
const { isSignedIn, userId } = useAuth({ treatPendingAsSignedOut: false });
const { connectedEnvironments, onReconnectEnvironment } = useRemoteConnections();
const {
connectedEnvironments,
onReconnectEnvironment,
onSetEnvironmentEnabled,
} = useRemoteConnections();
const { refreshRelayEnvironments } = useConnectionController();
const { connectedCloudEnvironments } = splitEnvironmentSections({
connectedEnvironments,
Expand Down Expand Up @@ -73,8 +88,12 @@ function ConfiguredConnectOnboardingRouteScreen() {
const handleDontShowAgain = useCallback(() => {
void (async () => {
if (userId) {
const result = await settlePromise(() => optOutOfConnectOnboarding(userId));
reportAtomCommandResult(result, { label: "connect onboarding opt-out" });
const result = await settlePromise(() =>
optOutOfConnectOnboarding(userId),
);
reportAtomCommandResult(result, {
label: "connect onboarding opt-out",
});
}
navigation.goBack();
})();
Expand All @@ -85,11 +104,21 @@ function ConfiguredConnectOnboardingRouteScreen() {
{Platform.OS === "android" ? (
<AndroidSheetHeader
title="Set up T3 Connect"
actions={[{ accessibilityLabel: "Close", icon: "xmark", onPress: handleClose }]}
actions={[
{
accessibilityLabel: "Close",
icon: "xmark",
onPress: handleClose,
},
]}
/>
) : (
<NativeHeaderToolbar placement="right">
<NativeHeaderToolbar.Button icon="xmark" onPress={handleClose} separateBackground />
<NativeHeaderToolbar.Button
icon="xmark"
onPress={handleClose}
separateBackground
/>
</NativeHeaderToolbar>
)}
<ScrollView
Expand All @@ -104,13 +133,17 @@ function ConfiguredConnectOnboardingRouteScreen() {
paddingTop: 16,
}}
refreshControl={
<RefreshControl refreshing={isPullRefreshing} onRefresh={handlePullRefresh} />
<RefreshControl
refreshing={isPullRefreshing}
onRefresh={handlePullRefresh}
/>
}
>
{isSignedIn ? (
<CloudEnvironmentRows
connectedCloudEnvironments={connectedCloudEnvironments}
onReconnectEnvironment={onReconnectEnvironment}
onSetEnvironmentEnabled={onSetEnvironmentEnabled}
showHeader={false}
/>
) : (
Expand All @@ -128,7 +161,9 @@ function ConfiguredConnectOnboardingRouteScreen() {
onPress={handleDontShowAgain}
className="items-center py-1 active:opacity-70"
>
<Text className="text-xs text-foreground-muted">{"Don't show this again"}</Text>
<Text className="text-xs text-foreground-muted">
{"Don't show this again"}
</Text>
</Pressable>
) : null}
</ScrollView>
Expand Down
Loading
Loading