Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
d37a9b0
feat(mobile): add thread title regeneration (#6253)
chrisdeeming Aug 12, 2026
63e6fae
chore: add dara to vouched (#6259)
maria-rcks Aug 12, 2026
5a84614
fix(web): align the composer model picker (#6252)
t3-code[bot] Aug 12, 2026
e1378a1
fix(mobile): keep ordered lists inside user bubbles (#6154)
none23 Aug 12, 2026
b54bfc9
feat(web): a better right panel empty state (#6258)
StiensWout Aug 12, 2026
6fd088a
fix(web): align mobile onboarding header (#6293)
t3-code[bot] Aug 12, 2026
849bac8
fix(connect): preserve CLI OAuth parameters through browser sign-in (…
juliusmarminge Aug 12, 2026
e321667
fix(web): prevent changed files header overlap (#6314)
t3-code[bot] Aug 12, 2026
f131228
fix(web): theme Clerk surfaces (#6300)
StiensWout Aug 12, 2026
b73232b
feat(web): reset sidebar width on double click (#6320)
extoci Aug 12, 2026
8601797
fix(web): align update toast release notes link (#6322)
t3-code[bot] Aug 12, 2026
770946d
fix(web): render tooltips above dropdowns (#6241)
extoci Aug 12, 2026
8d24b51
fix(web): open modified PR clicks in browser (#6278)
t3-code[bot] Aug 12, 2026
18918d1
Fix mobile command popover glass rendering (#6370)
juliusmarminge Aug 12, 2026
e3a9c25
test(mobile): seed snoozed showcase threads (#5155)
PixPMusic Aug 12, 2026
9666b87
fix(web): preserve appearance mode when changing themes (#6343)
extoci Aug 12, 2026
d0b8d63
feat(connect): deregister account environments from any client (#4844)
StiensWout Aug 12, 2026
b28f9bf
feat(web): pull request surfaces — filters & qualifiers, all-server l…
Bil0000 Aug 12, 2026
2eb099f
fix(web): cmd+click sidebar PR numbers open in the browser (#6378)
t3dotgg Aug 12, 2026
ac1264e
feat(web): project favicon and workspace icons in command subtitles (…
gsimone Aug 12, 2026
da6253b
web/settings: fix source control scan on relay environments (#6230)
dominic-r Aug 12, 2026
33f9705
fix(web): make reset zoom hover visible (#6385)
t3-code[bot] Aug 12, 2026
1e59b4c
fix(web): keep the typed prompt when a draft changes repo (#6393)
t3dotgg Aug 12, 2026
6bc6cb6
fix(web): keep diff file lists scrollable past expanded files (#6423)
dominic-r Aug 13, 2026
df19f6c
fix(server): align Codex collaboration prompts (#6432)
none23 Aug 13, 2026
5015d7c
fix(web): keep turn minimap stable as composer grows (#6414)
extoci Aug 13, 2026
dcf0dfd
chore(turbo): ingest upstream through v0.0.34-nightly.20260813.1084
Aug 13, 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
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.42",
"version": "0.0.43",
"private": true,
"type": "module",
"main": "dist-electron/main.cjs",
Expand Down
2 changes: 2 additions & 0 deletions apps/mobile/src/features/home/HomeRouteScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export function HomeRouteScreen() {
pinThread,
unpinThread,
movePinnedThread,
regenerateThreadTitle,
unsettleThread,
} = useThreadListActions();
const pendingTasks = usePendingNewTasks();
Expand Down Expand Up @@ -186,6 +187,7 @@ export function HomeRouteScreen() {
onPinThread={pinThread}
onUnpinThread={unpinThread}
onMovePinnedThread={movePinnedThread}
onRegenerateThreadTitle={regenerateThreadTitle}
onEnvironmentChange={setSelectedEnvironmentId}
onProjectChange={setSelectedProjectKey}
onOpenSettings={() =>
Expand Down
24 changes: 24 additions & 0 deletions apps/mobile/src/features/home/HomeScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ interface HomeScreenProps {
thread: EnvironmentThreadShell,
direction: "up" | "down",
) => Promise<boolean>;
readonly onRegenerateThreadTitle: (thread: EnvironmentThreadShell) => Promise<boolean>;
readonly onSelectPendingTask: (pendingTask: PendingNewTask) => void;
readonly onDeletePendingTask: (pendingTask: PendingNewTask) => void;
readonly onNewThreadInProject: (project: EnvironmentProject) => void;
Expand Down Expand Up @@ -544,6 +545,12 @@ export function HomeScreen(props: HomeScreenProps) {
},
[props.onUnpinThread],
);
const handleRegenerateThreadTitle = useCallback(
(thread: EnvironmentThreadShell) => {
void props.onRegenerateThreadTitle(thread);
},
[props.onRegenerateThreadTitle],
);
const handleDeleteThread = props.onDeleteThread;
const handleUnsettleThread = props.onUnsettleThread;
// The settled tail renders in pages; expansion resets when the filter
Expand Down Expand Up @@ -621,6 +628,15 @@ export function HomeScreen(props: HomeScreenProps) {
}
return supported;
}, [serverConfigs]);
const titleRegenerationEnvironmentIds = useMemo(() => {
const supported = new Set<EnvironmentId>();
for (const [environmentId, config] of serverConfigs) {
if (config.environment.capabilities.threadTitleRegeneration === true) {
supported.add(environmentId);
}
}
return supported;
}, [serverConfigs]);
// Canonical arranged pinned order (reorder-capable threads only) for the
// Move up/down position flags. Computed from all shells, not the rendered
// list, so search/scope filtering never disables or misdirects a move.
Expand Down Expand Up @@ -817,6 +833,8 @@ export function HomeScreen(props: HomeScreenProps) {
onSelectThread={props.onSelectThread}
onDeleteThread={handleDeleteThread}
onArchiveThread={props.onArchiveThread}
onRegenerateThreadTitle={handleRegenerateThreadTitle}
titleRegenerationSupported={titleRegenerationEnvironmentIds.has(thread.environmentId)}
settlementSupported={settlementEnvironmentIds.has(thread.environmentId)}
onSettleThread={handleSettleThread}
snoozeSupported={snoozeEnvironmentIds.has(thread.environmentId)}
Expand Down Expand Up @@ -848,6 +866,7 @@ export function HomeScreen(props: HomeScreenProps) {
arrangedPinnedKeys,
handleMovePinnedThread,
handlePinThread,
handleRegenerateThreadTitle,
handleSettleThread,
handleSnoozeThread,
handleUnpinThread,
Expand All @@ -869,6 +888,7 @@ export function HomeScreen(props: HomeScreenProps) {
snoozeEnvironmentIds,
threadListV2Items,
threadSearchMatchByKey,
titleRegenerationEnvironmentIds,
toggleSettledShelf,
toggleSnoozedShelf,
v2ProjectTitleByProjectKey,
Expand Down Expand Up @@ -973,6 +993,8 @@ export function HomeScreen(props: HomeScreenProps) {
searchQuery={props.searchQuery}
onArchiveThread={props.onArchiveThread}
onDeleteThread={props.onDeleteThread}
onRegenerateThreadTitle={handleRegenerateThreadTitle}
titleRegenerationSupported={titleRegenerationEnvironmentIds.has(thread.environmentId)}
onSelectThread={props.onSelectThread}
onSwipeableClose={handleSwipeableClose}
onSwipeableWillOpen={handleSwipeableWillOpen}
Expand All @@ -994,6 +1016,7 @@ export function HomeScreen(props: HomeScreenProps) {
[
handleSwipeableClose,
handleSwipeableWillOpen,
handleRegenerateThreadTitle,
projectCwdByKey,
props.onArchiveThread,
props.onDeletePendingTask,
Expand All @@ -1004,6 +1027,7 @@ export function HomeScreen(props: HomeScreenProps) {
props.searchQuery,
props.savedConnectionsById,
threadSearchMatchByKey,
titleRegenerationEnvironmentIds,
updateGroupDisplay,
],
);
Expand Down
56 changes: 56 additions & 0 deletions apps/mobile/src/features/home/useThreadListActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,15 @@ function environmentSupportsPinReorder(environmentId: EnvironmentThreadShell["en
);
}

function environmentSupportsTitleRegeneration(
environmentId: EnvironmentThreadShell["environmentId"],
) {
return (
appAtomRegistry.get(environmentServerConfigsAtom).get(environmentId)?.environment.capabilities
.threadTitleRegeneration === true
);
}

type ThreadListAction = "archive" | "unarchive" | "delete" | "settle" | "unsettle";

const ACTION_VERBS: Record<ThreadListAction, string> = {
Expand Down Expand Up @@ -227,13 +236,18 @@ export function useThreadListActions(): {
thread: EnvironmentThreadShell,
direction: "up" | "down",
) => Promise<boolean>;
readonly regenerateThreadTitle: (thread: EnvironmentThreadShell) => Promise<boolean>;
} {
const executeAction = useThreadActionExecutor();
const snoozeMutation = useAtomCommand(threadEnvironment.snooze, { reportFailure: false });
const unsnoozeMutation = useAtomCommand(threadEnvironment.unsnooze, { reportFailure: false });
const pinMutation = useAtomCommand(threadEnvironment.pin, { reportFailure: false });
const unpinMutation = useAtomCommand(threadEnvironment.unpin, { reportFailure: false });
const updateThreadMetadata = useAtomCommand(threadEnvironment.updateMetadata, {
reportFailure: false,
});
const snoozeInFlightThreadKeys = useRef(new Set<string>());
const titleRegenerationInFlightThreadKeys = useRef(new Set<string>());

const archiveThread = useCallback(
(thread: EnvironmentThreadShell) => {
Expand Down Expand Up @@ -405,6 +419,47 @@ export function useThreadListActions(): {
},
[unpinMutation],
);
const regenerateThreadTitle = useCallback(
async (thread: EnvironmentThreadShell) => {
const key = scopedThreadKey(thread.environmentId, thread.id);
if (
thread.titleRegeneration != null ||
titleRegenerationInFlightThreadKeys.current.has(key)
) {
return false;
}
if (!environmentSupportsTitleRegeneration(thread.environmentId)) {
Alert.alert(
"Could not regenerate title",
"This environment's server does not support title regeneration yet. Update the server to regenerate thread titles.",
);
return false;
}

titleRegenerationInFlightThreadKeys.current.add(key);
selectionHaptic();
try {
const result = await updateThreadMetadata({
environmentId: thread.environmentId,
input: { threadId: thread.id, regenerateTitle: true },
});
if (result._tag === "Failure") {
const error = Cause.squash(result.cause);
Alert.alert(
"Could not regenerate title",
error instanceof Error && error.message.trim().length > 0
? error.message
: "The thread title could not be regenerated.",
);
return false;
}
return true;
} finally {
titleRegenerationInFlightThreadKeys.current.delete(key);
}
},
[updateThreadMetadata],
);

// Move up / Move down for the pinned block. Computed against the CANONICAL
// keyed pinned order (not the rendered list), so the move is valid even
Expand Down Expand Up @@ -497,6 +552,7 @@ export function useThreadListActions(): {
pinThread,
unpinThread,
movePinnedThread,
regenerateThreadTitle,
};
}

Expand Down
31 changes: 6 additions & 25 deletions apps/mobile/src/features/threads/ComposerCommandPopover.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { isLiquidGlassSupported, LiquidGlassView } from "@callstack/liquid-glass";
import type { ComposerTriggerKind } from "@t3tools/shared/composerTrigger";
import type { ServerProviderSkill, ServerProviderSlashCommand } from "@t3tools/contracts";
import { SymbolView } from "../../components/AppSymbol";
import { memo } from "react";
import { Pressable, ScrollView, useColorScheme, View, type ViewStyle } from "react-native";

import { AppText as Text } from "../../components/AppText";
import { GlassSurface } from "../../components/GlassSurface";
import { PierreEntryIcon } from "../../components/PierreEntryIcon";
export type ComposerCommandItem =
| {
Expand Down Expand Up @@ -56,33 +56,14 @@ function PopoverSurface(props: {
...props.style,
};

if (isLiquidGlassSupported) {
return (
<LiquidGlassView
effect="clear"
interactive={false}
tintColor={props.isDarkMode ? "rgba(30,30,32,0.95)" : "rgba(255,255,255,0.92)"}
colorScheme={props.isDarkMode ? "dark" : "light"}
style={baseStyle}
>
{props.children}
</LiquidGlassView>
);
}

return (
<View
style={[
baseStyle,
{
backgroundColor: props.isDarkMode ? "rgba(44,44,46,0.96)" : "rgba(255,255,255,0.96)",
borderWidth: 1,
borderColor: props.isDarkMode ? "rgba(255,255,255,0.08)" : "rgba(0,0,0,0.06)",
},
]}
<GlassSurface
glassEffectStyle="clear"
tintColor={props.isDarkMode ? "rgba(30,30,32,0.95)" : "rgba(255,255,255,0.92)"}
style={baseStyle}
>
{props.children}
</View>
</GlassSurface>
);
}

Expand Down
6 changes: 5 additions & 1 deletion apps/mobile/src/features/threads/ThreadFeed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ import { useMarkdownCodeHighlight } from "./markdownCodeHighlightState";
import { useAssetUrl } from "../../state/assets";
import { resolveWorkspaceRelativeFilePath } from "../files/filePath";

const WIDE_MARKDOWN_BLOCK_OPTIONS = {
includeOrderedLists: Platform.OS === "android",
} as const;

const MESSAGE_TIME_FORMATTER = new Intl.DateTimeFormat(undefined, {
hour: "numeric",
minute: "2-digit",
Expand Down Expand Up @@ -888,7 +892,7 @@ function renderFeedEntry(
// children during the unclamped pass and never moves them once the width
// is clamped, so the paragraphs around the block end up drawn on top of
// each other. Pinning the width removes that pass.
const hasWideBlock = hasWideMarkdownBlock(message.text);
const hasWideBlock = hasWideMarkdownBlock(message.text, WIDE_MARKDOWN_BLOCK_OPTIONS);
const assistantTurnStillInProgress =
message.role === "assistant" &&
props.unsettledTurnId !== null &&
Expand Down
16 changes: 16 additions & 0 deletions apps/mobile/src/features/threads/ThreadNavigationSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ function ThreadNavigationSidebarPane(
pinThread,
unpinThread,
movePinnedThread,
regenerateThreadTitle,
} = useThreadListActions();
const threadListV2Enabled = useThreadListV2Enabled();
const pendingTasks = usePendingNewTasks();
Expand Down Expand Up @@ -511,6 +512,15 @@ function ThreadNavigationSidebarPane(
}
return supported;
}, [serverConfigs]);
const titleRegenerationEnvironmentIds = useMemo(() => {
const supported = new Set<EnvironmentId>();
for (const [environmentId, config] of serverConfigs) {
if (config.environment.capabilities.threadTitleRegeneration === true) {
supported.add(environmentId);
}
}
return supported;
}, [serverConfigs]);
// Canonical arranged pinned order for Move up/down flags — computed from
// all shells so search/scope filtering never disables a valid move.
const arrangedPinnedKeys = useMemo(() => {
Expand Down Expand Up @@ -956,6 +966,8 @@ function ThreadNavigationSidebarPane(
onSelectThread={handleSelectThread}
onDeleteThread={confirmDeleteThread}
onArchiveThread={archiveThread}
onRegenerateThreadTitle={regenerateThreadTitle}
titleRegenerationSupported={titleRegenerationEnvironmentIds.has(thread.environmentId)}
settlementSupported={settlementEnvironmentIds.has(thread.environmentId)}
onSettleThread={settleThread}
snoozeSupported={snoozeEnvironmentIds.has(thread.environmentId)}
Expand Down Expand Up @@ -1073,6 +1085,8 @@ function ThreadNavigationSidebarPane(
fullSwipeWidth={props.width - 20}
onArchiveThread={archiveThread}
onDeleteThread={confirmDeleteThread}
onRegenerateThreadTitle={regenerateThreadTitle}
titleRegenerationSupported={titleRegenerationEnvironmentIds.has(thread.environmentId)}
onSelectThread={handleSelectThread}
onSwipeableClose={handleSwipeableClose}
onSwipeableWillOpen={handleSwipeableWillOpen}
Expand Down Expand Up @@ -1109,13 +1123,15 @@ function ThreadNavigationSidebarPane(
projectByKey,
projectCwdByKey,
projectTitleByProjectKey,
regenerateThreadTitle,
props.onNewThreadInProject,
props.searchQuery,
props.selectedThreadKey,
props.width,
savedConnectionsById,
serverConfigs,
threadSearchMatchByKey,
titleRegenerationEnvironmentIds,
settleThread,
settlementEnvironmentIds,
showMoreSettled,
Expand Down
Loading
Loading