Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
89ee692
fix(web): persist diff view mode (#5731)
leorivastech Aug 8, 2026
c2f8cb7
feat(web): show how many subagents are running at a glance (#5745)
t3dotgg Aug 8, 2026
be01b28
fix(web): add missing cursor-pointer styling to dropdowns and interac…
naMqe-h Aug 9, 2026
e70cdb4
fix(server): stop Claude resume handshakes from completing turns that…
gfsaaser24 Aug 9, 2026
49964e3
chore: vouch gfsaaser24 (#5761)
t3dotgg Aug 9, 2026
7b2cf43
chore: vouch saphid (#5763)
t3dotgg Aug 9, 2026
89c320d
fix(server): stop Codex threads with queued follow-ups (#5762)
t3dotgg Aug 9, 2026
70c423a
fix(web): usage page loses the cost quality panel, gains a back butto…
t3dotgg Aug 9, 2026
a6c9b41
feat(server): agents can now open the images you paste into chat (#5757)
t3dotgg Aug 9, 2026
5208bde
fix(web): pinned reorder no longer reshuffles while writes land (#5767)
t3dotgg Aug 9, 2026
288d8e3
feat(web): overhaul project settings into a real settings page (#5768)
t3dotgg Aug 9, 2026
886195e
fix(web): usage totals no longer jump while devices report in (#5772)
t3dotgg Aug 9, 2026
5bb8c03
fix(server): settle no longer leaves monitors and dev servers running…
t3dotgg Aug 9, 2026
6dbffa0
feat: pick worktree or current checkout per project (#5766)
t3dotgg Aug 9, 2026
6f69b44
fix(web): sidebar rows show the branch again, not a truncated plan st…
t3dotgg Aug 9, 2026
ddaa6af
feat(server): vp run migrate-dev-db seeds worktree dev dbs with real …
t3dotgg Aug 9, 2026
05eb051
feat(web): keep unsent drafts one click away in the sidebar (#5777)
t3dotgg Aug 9, 2026
076e904
feat(web): project icons can be chosen manually (#5775)
t3dotgg Aug 9, 2026
ba9c9ae
fix(server): one greedy agent process no longer takes down the whole …
t3dotgg Aug 9, 2026
963ebf5
ci: label-gated hosted-web preview deploys (#5465)
t3dotgg Aug 9, 2026
1a003e3
Add cross-platform mobile usage dashboard (#5743)
juliusmarminge Aug 9, 2026
977b4d6
Merge remote-tracking branch 'upstream/main' into t3code/ingest-upstr…
Aug 9, 2026
8856664
chore(turbo): remap the multi-chat sidebar seam and re-anchor upstrea…
Aug 9, 2026
da968fc
fix(server): provide ServerConfig to the new provider binding tests
Aug 9, 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 @@ -15,6 +15,7 @@ github:chrisdeeming
github:chuks-qua
github:cursoragent
github:gbarros-dev
github:gfsaaser24
github:github-actions[bot]
github:hwanseoc
github:jamesx0416
Expand All @@ -26,6 +27,7 @@ github:Noojuno
github:notkainoa
github:PatrickBauer
github:realAhmedRoach
github:saphid
github:shiroyasha9
github:StiensWout
github:Yash-Singh1
Expand Down
132 changes: 132 additions & 0 deletions .github/workflows/web-preview.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
name: Web Preview

# Label a PR `preview:web` to get a hosted-web preview deployment on Vercel for
# that push and every subsequent push. The deployment is a plain (non-prod,
# non-aliased) deploy into the existing hosted-web Vercel project, so the
# latest/nightly channel aliases are never touched.
#
# The build intentionally omits the T3 Connect cloud config (Clerk keys, relay
# URL): previews boot as the hosted-static app with manual pairing only. Pair a
# server into a preview with `t3 pair --tailscale` (or any reachable HTTPS
# backend) and open the pairing URL against the preview origin.
#
# The preview must be opened at the exact deployment URL from the PR comment.
# Vite bakes that URL in as the hosted origin (via VERCEL_URL), and
# `isHostedStaticApp` matches on origin, so branch-alias URLs will not
# self-identify as the hosted app.

on:
pull_request:
types: [labeled, synchronize, reopened]

permissions:
contents: read
pull-requests: write

concurrency:
group: web-preview-${{ github.event.pull_request.number }}
cancel-in-progress: true

jobs:
deploy:
name: Deploy web preview
# Same-repo PRs only: fork PRs do not receive the Vercel secrets, and this
# workflow should skip rather than fail for them. On `labeled` events, only
# the preview label itself triggers a deploy.
if: >-
github.event.pull_request.head.repo.full_name == github.repository &&
contains(github.event.pull_request.labels.*.name, 'preview:web') &&
(github.event.action != 'labeled' || github.event.label.name == 'preview:web')
runs-on: blacksmith-8vcpu-ubuntu-2404
timeout-minutes: 10
env:
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
VERCEL_TEAM_SLUG: ${{ vars.VERCEL_TEAM_SLUG }}
steps:
- name: Checkout
uses: actions/checkout@v6
with:
ref: ${{ github.event.pull_request.head.sha }}
sparse-checkout: |
/*
!/.repos/
sparse-checkout-cone-mode: false

- name: Setup Vite+
uses: voidzero-dev/setup-vp@v1
with:
node-version-file: package.json
cache: true
run-install: |
args:
- --filter=@t3tools/scripts...
- --filter=@t3tools/web...

- id: deploy
name: Deploy preview
shell: bash
run: |
set -euo pipefail

if [[ -z "${VERCEL_TOKEN:-}" || -z "${VERCEL_ORG_ID:-}" || -z "${VERCEL_PROJECT_ID:-}" ]]; then
echo "Missing one or more required Vercel secrets: VERCEL_TOKEN, VERCEL_ORG_ID, VERCEL_PROJECT_ID." >&2
exit 1
fi

vercel_scope="${VERCEL_TEAM_SLUG:-$VERCEL_ORG_ID}"

deployment_url="$(
vp dlx vercel@53.1.1 deploy \
--archive=tgz \
--yes \
--token "$VERCEL_TOKEN" \
--scope "$vercel_scope"
)"

echo "Deployed $deployment_url"
echo "deployment_url=$deployment_url" >> "$GITHUB_OUTPUT"

- name: Comment deployment URL
uses: actions/github-script@v8
env:
DEPLOYMENT_URL: ${{ steps.deploy.outputs.deployment_url }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
with:
script: |
const marker = "<!-- web-preview-deploy -->";
const body = [
marker,
"### Web preview",
"",
`${process.env.DEPLOYMENT_URL} (for ${process.env.HEAD_SHA.slice(0, 7)})`,
"",
"Open this exact URL — the hosted-app origin is baked in at build time.",
"Pair a server into it with `t3 pair --tailscale`, or paste a host + pairing",
"code under Settings → Connections.",
].join("\n");

const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.pull_request.number,
per_page: 100,
});
const existing = comments.find((comment) => comment.body?.includes(marker));

if (existing) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existing.id,
body,
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.pull_request.number,
body,
});
}
44 changes: 32 additions & 12 deletions .t3-turbo/customizations.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,10 @@
"status": "implemented",
"summary": "The canonical Turbo icon and registered web, desktop, mobile, marketing, and widget derivatives remain present.",
"checks": [
{ "path": "t3turbo.png", "markers": [] },
{
"path": "t3turbo.png",
"markers": []
},
{
"path": "scripts/lib/turbo-brand-assets.ts",
"markers": [
Expand All @@ -65,13 +68,34 @@
"path": "scripts/export-turbo-icons.ts",
"markers": ["TURBO_BRAND_ASSET_PATHS", "--check"]
},
{ "path": "assets/turbo/t3turbo-windows.ico", "markers": [] },
{ "path": "assets/turbo/t3turbo.icns", "markers": [] },
{ "path": "assets/turbo/t3turbo-ios-1024.png", "markers": [] },
{ "path": "assets/turbo/t3turbo-web-favicon.ico", "markers": [] },
{ "path": "apps/mobile/assets/t3turbo-android-monochrome.png", "markers": [] },
{ "path": "apps/mobile/assets/t3turbo-android-notification.png", "markers": [] },
{ "path": "apps/mobile/assets/widget/T3Mark.png", "markers": [] },
{
"path": "assets/turbo/t3turbo-windows.ico",
"markers": []
},
{
"path": "assets/turbo/t3turbo.icns",
"markers": []
},
{
"path": "assets/turbo/t3turbo-ios-1024.png",
"markers": []
},
{
"path": "assets/turbo/t3turbo-web-favicon.ico",
"markers": []
},
{
"path": "apps/mobile/assets/t3turbo-android-monochrome.png",
"markers": []
},
{
"path": "apps/mobile/assets/t3turbo-android-notification.png",
"markers": []
},
{
"path": "apps/mobile/assets/widget/T3Mark.png",
"markers": []
},
{
"path": "apps/mobile/app.config.ts",
"markers": [
Expand Down Expand Up @@ -435,10 +459,6 @@
"path": "apps/web/src/components/Sidebar.tsx",
"markers": ["openChatPaneTarget({ kind: \"server\", threadRef }, chatPaneSide)"]
},
{
"path": "apps/web/src/components/SidebarV2.tsx",
"markers": ["openChatPaneTarget({ kind: \"server\", threadRef }, chatPaneSide)"]
},
{
"path": "apps/web/src/turbo/chatPanes/chatPaneContextMenu.test.ts",
"markers": ["offers the right and left split actions"]
Expand Down
8 changes: 4 additions & 4 deletions .t3-turbo/upstream.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"repository": "pingdotgg/t3code",
"branch": "main",
"mainSha": "239ef1c54df2f657912ccb5b8e25193d49d90417",
"nightlyTag": "v0.0.32-nightly.20260807.1023",
"nightlySha": "23f0a1ae38cb1fc510a499ef2b3602f5ae98d0c9",
"version": "0.0.32-nightly.20260803.986"
"mainSha": "1a003e383ac6b10258b8100c2617d938c4f06c69",
"nightlyTag": "v0.0.33-nightly.20260809.1042",
"nightlySha": "963ebf5bd7cce00d40ff60c258b34c12dcab271e",
"version": "0.0.33-nightly.20260809.1042"
}
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ Full docs live in [docs/](./docs). There's no docs site yet.
- [Install and first run](./docs/user/install.md)
- [Permission modes](./docs/user/permission-modes.md)
- [Keyboard shortcuts](./docs/user/keybindings.md)
- [Customize a project icon](./docs/user/project-settings.md)
- [Remote access from a phone or another machine](./docs/user/remote-access.md)
- [Keeping app and server in sync](./docs/user/updating.md)
- [Source control integrations](./docs/user/source-control.md)
Expand Down
8 changes: 8 additions & 0 deletions apps/mobile/src/Stack.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import { SettingsAuthRouteScreen } from "./features/settings/SettingsAuthRouteSc
import { SettingsEnvironmentsRouteScreen } from "./features/settings/SettingsEnvironmentsRouteScreen";
import { SettingsLegalRouteScreen } from "./features/settings/SettingsLegalRouteScreen";
import { SettingsProjectGroupingRouteScreen } from "./features/settings/SettingsProjectGroupingRouteScreen";
import { UsageRouteScreen } from "./features/usage/UsageRouteScreen";
import { SettingsRouteScreen } from "./features/settings/SettingsRouteScreen";
import { ShowcaseCaptureCoordinator } from "./features/showcase/ShowcaseCaptureCoordinator";
import {
Expand Down Expand Up @@ -190,6 +191,13 @@ const SettingsSheetStack = createNativeStackNavigator({
title: "Client Storage",
},
}),
SettingsUsage: createNativeStackScreen({
screen: UsageRouteScreen,
linking: "usage",
options: {
title: "Usage",
},
}),
SettingsAuth: createNativeStackScreen({
screen: SettingsAuthRouteScreen,
linking: "auth",
Expand Down
2 changes: 2 additions & 0 deletions apps/mobile/src/components/AppSymbol.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
IconBellRinging,
IconBolt,
IconCamera,
IconChartBar,
IconCheck,
IconChevronDown,
IconCode,
Expand Down Expand Up @@ -97,6 +98,7 @@ const ANDROID_ICON_BY_SF_SYMBOL: Partial<Record<SFSymbol, Icon>> = {
"bolt.circle": IconBolt,
"bolt.horizontal.circle": IconBolt,
camera: IconCamera,
"chart.bar.xaxis": IconChartBar,
checkmark: IconCheck,
"checkmark.circle": IconCircleCheck,
clock: IconClock,
Expand Down
7 changes: 6 additions & 1 deletion apps/mobile/src/components/ProjectFavicon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,18 @@ export function ProjectFavicon(props: {
readonly size?: number;
readonly projectTitle: string;
readonly workspaceRoot?: string | null;
readonly faviconPath?: string | null;
}) {
const size = props.size ?? 42;
const faviconUrl = useAssetUrl(
props.environmentId,
props.workspaceRoot === null || props.workspaceRoot === undefined
? null
: { _tag: "project-favicon", cwd: props.workspaceRoot },
: {
_tag: "project-favicon",
cwd: props.workspaceRoot,
...(props.faviconPath ? { path: props.faviconPath } : {}),
},
);
const renderableFaviconUrl = isProjectFaviconFallbackUrl(faviconUrl) ? null : faviconUrl;
const cacheKey =
Expand Down
1 change: 1 addition & 0 deletions apps/mobile/src/features/archive/ArchivedThreadsScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,7 @@ function ProjectGroupLabel(props: {
<View className="flex-row items-center gap-2.5 px-1 pb-2">
<ProjectFavicon
environmentId={props.project.environmentId}
faviconPath={props.project.faviconPath}
projectTitle={props.project.title}
size={18}
workspaceRoot={props.project.workspaceRoot}
Expand Down
1 change: 1 addition & 0 deletions apps/mobile/src/features/settings/SettingsRouteScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,7 @@ function GeneralSettingsSection() {
return (
<SettingsSection title="General">
<SettingsRow icon="folder" label="Project Grouping" target="SettingsProjectGrouping" />
<SettingsRow icon="chart.bar.xaxis" label="Usage" target="SettingsUsage" />
</SettingsSection>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export type SettingsSheetTarget =
| "SettingsArchive"
| "SettingsAppearance"
| "SettingsProjectGrouping"
| "SettingsClientStorage";
| "SettingsClientStorage"
| "SettingsUsage";

export type SettingsLegalDocumentTarget = "SettingsLegal";
2 changes: 2 additions & 0 deletions apps/mobile/src/features/threads/NewTaskRouteScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,7 @@ export function NewTaskRouteScreen({ route }: StaticScreenProps<NewTaskRoutePara
<View className="h-7 w-7 items-center justify-center">
<ProjectFavicon
environmentId={scope.representative.environmentId}
faviconPath={scope.representative.faviconPath}
size={20}
projectTitle={scope.title}
workspaceRoot={scope.representative.workspaceRoot}
Expand Down Expand Up @@ -330,6 +331,7 @@ export function NewTaskRouteScreen({ route }: StaticScreenProps<NewTaskRoutePara
>
<ProjectFavicon
environmentId={project.environmentId}
faviconPath={project.faviconPath}
size={18}
projectTitle={project.title}
workspaceRoot={project.workspaceRoot}
Expand Down
Loading
Loading