Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
cafdcda
fix(clients): give image attachment chips a blue accent (#26306)
Yash-Singh1 Oct 28, 2026
afc2334
fix(web): prevent image thumbnails from warping during repaints (#26308)
Yash-Singh1 Oct 28, 2026
49582b7
test(web): attachment font and large-text preview tests wait for the …
juliusmarminge Oct 28, 2026
8031991
fix(opencode): subagent sessions follow runtime mode changes (#26302)
juliusmarminge Oct 28, 2026
1f8530e
feat(web): pending approvals show on their timeline row (#26255)
maria-rcks Oct 28, 2026
9b052a2
fix(web): show the platform modifier in the send tooltip (#22436)
UtkarshUsername Oct 28, 2026
feb49e7
fix(web): let theme color pickers use popover glass (#22348)
UtkarshUsername Oct 28, 2026
9bc0419
fix(relay): concurrent link requests can no longer exceed the managed…
juliusmarminge Oct 28, 2026
003ccd3
fix(client-runtime): pairing links can no longer add routes to a save…
juliusmarminge Oct 28, 2026
feb2e32
fix(web): align sidebar button geometry with shared tokens (#22287)
UtkarshUsername Oct 28, 2026
c0f9e36
fix(mobile): pairing deep links can no longer target a saved environm…
juliusmarminge Oct 28, 2026
8e76f94
feat(relay): T3 Chat Pro and Premier accounts get more tunnels (#25931)
t3dotgg Oct 28, 2026
0deb383
test(mobile): pairing link test runs the app's real link parsing (#26…
juliusmarminge Oct 28, 2026
50d3a31
fix: guests see the screenshots the agent shows in its replies (#26323)
t3dotgg Oct 28, 2026
a9418a1
ci(release): releases no longer reinstall Vite+ in every job (#26305)
t3dotgg Oct 28, 2026
f6d3700
ci: server test shards survive a throttled task cache (#26332)
t3dotgg Oct 28, 2026
4e4d4ba
feat(web): boring sidebar groups threads into project folders (#21039)
t3dotgg Oct 28, 2026
9ebca5f
fix(relay): tunnel limit counts abandoned reprovisions and frees fail…
juliusmarminge Oct 28, 2026
cadbdaf
test(web): attachment preview tests wait long enough for cold workers…
t3dotgg Oct 28, 2026
2349c81
refactor(mobile): app link parsing reads top to bottom with pipe (#26…
juliusmarminge Oct 28, 2026
ce66aab
ci(release): Windows CLI builds retry the Node.js download (#26345)
t3dotgg Oct 28, 2026
990e9e0
fix(web): preserve handoffs before superseded attempt folds (#26333)
Yash-Singh1 Oct 28, 2026
441a4eb
feat(web): open tool call diffs in the diff panel (#26304)
Yash-Singh1 Oct 28, 2026
cfc8be9
ci: a stalled Node.js download retries after 2 minutes, not 10 (#26343)
t3dotgg Oct 28, 2026
c3f5e36
fix(server): avoid replaying stale Codex usage limits (#26331)
Yash-Singh1 Oct 28, 2026
ff42480
feat(web): mark PR files viewed with shift-click (#26349)
Yash-Singh1 Oct 28, 2026
9bc4138
refactor: flatten nested call chains (#26350)
juliusmarminge Oct 28, 2026
10e709c
fix(queued-message): avoid duplicate queued message entries (#26355)
Yash-Singh1 Oct 28, 2026
f17c9d2
fix(models): new Claude threads default to Opus 5.5 (#26358)
t3dotgg Oct 28, 2026
a4e1986
docs: T3 Chat Pro and Premier raise the T3 Connect tunnel limit (#26366)
t3dotgg Oct 28, 2026
dac58fa
fix(web): use neutral indicators for inactive source control provider…
UtkarshUsername Oct 28, 2026
cb4fe60
fix(web): show the thread details tooltip (#24864)
UtkarshUsername Oct 28, 2026
975b3dc
fix(client-runtime): keep subagent questions off parent threads (#26367)
Yash-Singh1 Oct 28, 2026
be2ea30
fix(build): keep effect out of the public-config bootstrap (#26371)
juliusmarminge Oct 28, 2026
04cc819
Merge commit 'be2ea30d2b269f1526be3fd556bc5380b4dc01b3' into fix/bots…
fireboltdude1357 Oct 28, 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
66 changes: 55 additions & 11 deletions .github/actions/setup-ci-deps/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ inputs:
description: Read-only credential for the private maintainer task cache
required: false
default: ""
install:
description: Set to "false" to set up Vite+ only, with no pnpm store or install
required: false
default: "true"
install-args:
description: Arguments for `vp install`, such as filters. Empty installs the whole workspace.
required: false
default: ""
runs:
using: composite
steps:
Expand All @@ -19,10 +27,11 @@ runs:
echo "node=$(jq -r '.engines.node' package.json)" >> "$GITHUB_OUTPUT"
echo "pnpm=$(jq -r '.packageManager' package.json)" >> "$GITHUB_OUTPUT"

# Pinned because release-desktop.yml signs builds with this action in the job.
- name: Cache Vite+
id: vp_cache
if: steps.vp.outputs.version != ''
uses: actions/cache@v6
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
with:
path: ~/.vite-plus
key: vite-plus-home-v2-${{ runner.os }}-${{ runner.arch }}-${{ steps.vp.outputs.version }}-node${{ steps.vp.outputs.node }}-${{ steps.vp.outputs.pnpm }}
Expand All @@ -38,38 +47,73 @@ runs:
echo "$HOME/.vite-plus/bin" >> "$GITHUB_PATH"
"$HOME/.vite-plus/bin/vp" env use "${{ steps.vp.outputs.node }}"

# vp gives each Node.js download attempt 10 minutes by default, so one
# stalled stream holds the job that long. It retries 3 times and resumes
# partial bytes, so a shorter limit costs a slow download only a retry.
- name: Setup Vite+
if: steps.vp_cache.outputs.cache-hit != 'true'
uses: voidzero-dev/setup-vp@v1
uses: voidzero-dev/setup-vp@250f29ce396baf5e8f24498e17c0dfdebabc26eb # v1
env:
VP_DOWNLOAD_TIMEOUT: "120"
with:
node-version-file: package.json
cache: false
run-install: false

- name: Resolve pnpm store path
# A shared key lets whichever install saves first, often a small filtered
# one, become every job's store. Each set of install args gets its own.
- name: Resolve pnpm store
id: pnpm_store
if: inputs.install == 'true'
shell: bash
env:
INSTALL_ARGS: ${{ inputs.install-args }}
run: |
store_path="$(vp pm cache dir)"
echo "path=$store_path" >> "$GITHUB_OUTPUT"
echo "path=$(vp pm cache dir)" >> "$GITHUB_OUTPUT"
if [[ -z "$INSTALL_ARGS" ]]; then
echo "namespace=full" >> "$GITHUB_OUTPUT"
else
echo "namespace=filtered-$(printf '%s' "$INSTALL_ARGS" | cksum | cut -d' ' -f1)" >> "$GITHUB_OUTPUT"
fi

# setup-vp's shared cache key ignores install filters. Keep full installs in a
# separate namespace, including fallback restores.
# Filtered installs prefer the current full store, which holds every package,
# over an older store of their own.
# The pnpm store stays a cache tarball on the runner's own disk. A store on a
# Blacksmith sticky disk mounts in under a second, but pnpm then copies every
# package across filesystems instead of hard-linking it: install took 28-49s
# against 9s plus an 11s restore.
- name: Cache full pnpm store
uses: actions/cache@v6
- name: Restore pnpm store
id: pnpm_cache
if: inputs.install == 'true'
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
with:
path: ${{ steps.pnpm_store.outputs.path }}
key: pnpm-full-v1-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('pnpm-lock.yaml', 'pnpm-workspace.yaml', 'package.json') }}
key: pnpm-${{ steps.pnpm_store.outputs.namespace }}-v1-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('pnpm-lock.yaml', 'pnpm-workspace.yaml', 'package.json') }}
restore-keys: |
pnpm-full-v1-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('pnpm-lock.yaml', 'pnpm-workspace.yaml', 'package.json') }}
pnpm-${{ steps.pnpm_store.outputs.namespace }}-v1-${{ runner.os }}-${{ runner.arch }}-
pnpm-full-v1-${{ runner.os }}-${{ runner.arch }}-

- name: Install dependencies
if: inputs.install == 'true'
shell: bash
run: vp install
env:
INSTALL_ARGS: ${{ inputs.install-args }}
# Unquoted so each filter is its own argument.
run: vp install $INSTALL_ARGS

# A filtered install that started from the current full store adds nothing
# worth a second copy of it.
- name: Save pnpm store
if: >-
inputs.install == 'true' &&
steps.pnpm_cache.outputs.cache-hit != 'true' &&
(steps.pnpm_store.outputs.namespace == 'full' ||
steps.pnpm_cache.outputs.cache-matched-key != format('pnpm-full-v1-{0}-{1}-{2}', runner.os, runner.arch, hashFiles('pnpm-lock.yaml', 'pnpm-workspace.yaml', 'package.json')))
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
with:
path: ${{ steps.pnpm_store.outputs.path }}
key: ${{ steps.pnpm_cache.outputs.cache-primary-key }}

- name: Enable shared task cache
if: >-
Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,9 @@ jobs:
id-token: write
name: Test Server ${{ matrix.shard }}
runs-on: blacksmith-4vcpu-ubuntu-2404
timeout-minutes: 10
# Shards take 2-5 minutes. When the shared task cache throttles reads, each
# failed fetch stalls vp for 15-90s, which pushed shards past 10 minutes.
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/deploy-relay.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ jobs:
CLERK_SECRET_KEY: ${{ secrets.CLERK_SECRET_KEY }}
APNS_PRIVATE_KEY: ${{ secrets.APNS_PRIVATE_KEY }}
FCM_SERVICE_ACCOUNT: ${{ secrets.FCM_SERVICE_ACCOUNT }}
T3CHAT_LINK_SECRET: ${{ secrets.T3CHAT_LINK_SECRET }}

- name: Publish relay deploy commit status
uses: actions/github-script@v8
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/relay-preview.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,5 @@ jobs:
PLANETSCALE_API_TOKEN: ${{ secrets.PLANETSCALE_API_TOKEN }}
AXIOM_TOKEN: ${{ secrets.AXIOM_TOKEN }}
CLERK_SECRET_KEY: ${{ secrets.CLERK_SECRET_KEY }}
# Unset by default, so previews keep the T3 Chat link off.
T3CHAT_LINK_SECRET: ${{ secrets.T3CHAT_LINK_SECRET }}
31 changes: 22 additions & 9 deletions .github/workflows/release-desktop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -147,13 +147,6 @@ jobs:
git sparse-checkout set --no-cone '/*' '!/.repos/'
git -c checkout.workers=0 checkout --detach FETCH_HEAD

- name: Setup Vite+
uses: voidzero-dev/setup-vp@250f29ce396baf5e8f24498e17c0dfdebabc26eb # v1
with:
node-version-file: package.json
cache: true
run-install: false

# pnpm checks the lockfile and policy before reusing this result. A missing
# artifact leaves the cache empty, so installation runs the checks again.
- name: Download dependency verification
Expand All @@ -163,10 +156,12 @@ jobs:
name: release-dependency-verification
path: ${{ runner.temp }}/pnpm-metadata

- name: Install desktop dependencies
- name: Setup dependencies
uses: ./.github/actions/setup-ci-deps
with:
install-args: --filter=@t3tools/desktop... --filter=t3... --filter=@t3tools/scripts...
env:
pnpm_config_cache_dir: ${{ runner.temp }}/pnpm-metadata
run: vp install --filter=@t3tools/desktop... --filter=t3... --filter=@t3tools/scripts...

- name: Cache resource monitor
id: resource_monitor_cache
Expand Down Expand Up @@ -259,6 +254,24 @@ jobs:
if [[ "${{ inputs.version }}" =~ -nightly\.[0-9]{8}\.[0-9]+$ ]]; then brand=nightly; fi
node scripts/apply-web-brand-assets.ts "$brand" apps/server/dist/client

# tsdown downloads the target Node with one fetch and no retry, and
# nodejs.org drops that download often enough to fail releases. Seed
# tsdown's cache with a retried, checksum-verified copy instead.
- name: Download target Node.js for the CLI executable
if: inputs.cli_archive && inputs.platform == 'win'
shell: bash
run: |
set -euo pipefail
version="$(node -p 'require("./package.json").engines.node')"
name="node-v$version-win-${{ inputs.arch }}"
dest="${XDG_CACHE_HOME:-$HOME/.cache}/tsdown/node/v$version/win-${{ inputs.arch }}"
dir="$RUNNER_TEMP/node-download"
mkdir -p "$dir" "$dest"
curl -fsSL --retry 5 --retry-all-errors -o "$dir/$name.zip" "https://nodejs.org/dist/v$version/$name.zip"
curl -fsSL --retry 5 --retry-all-errors -o "$dir/SHASUMS256.txt" "https://nodejs.org/dist/v$version/SHASUMS256.txt"
(cd "$dir" && grep " $name.zip\$" SHASUMS256.txt | sha256sum -c -)
unzip -p "$dir/$name.zip" "$name/node.exe" > "$dest/node.exe"

# Setup Vite+ selects the exact engines.node version from package.json.
# Native builds embed that executable; cross-target builds download the
# same version for their target.
Expand Down
98 changes: 29 additions & 69 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -420,14 +420,10 @@ jobs:
!/.repos/
sparse-checkout-cone-mode: false

- name: Setup Vite+
uses: voidzero-dev/setup-vp@v1
- name: Setup dependencies
uses: ./.github/actions/setup-ci-deps
with:
node-version-file: package.json
cache: true
run-install: |
args:
- --filter=t3code-relay...
install-args: --filter=t3code-relay...

# The deployed stack's outputs, read from Alchemy's state store without
# planning or applying. Select the backend explicitly to avoid loading
Expand Down Expand Up @@ -522,13 +518,6 @@ jobs:
!/.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: false

# pnpm checks the lockfile and policy before reusing this result. A missing
# artifact leaves the cache empty, so installation runs the checks again.
- name: Download dependency verification
Expand All @@ -538,10 +527,12 @@ jobs:
name: release-dependency-verification
path: ${{ runner.temp }}/pnpm-metadata

- name: Install bundle dependencies
- name: Setup dependencies
uses: ./.github/actions/setup-ci-deps
with:
install-args: --filter=t3... --filter=@t3tools/web... --filter=@t3tools/desktop... --filter=@t3tools/scripts...
env:
pnpm_config_cache_dir: ${{ runner.temp }}/pnpm-metadata
run: vp install --filter=t3... --filter=@t3tools/web... --filter=@t3tools/desktop... --filter=@t3tools/scripts...

- name: Download relay client tracing config
uses: actions/download-artifact@v8
Expand Down Expand Up @@ -781,14 +772,10 @@ jobs:
!/.repos/
sparse-checkout-cone-mode: false

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

- name: Download all desktop artifacts
uses: actions/download-artifact@v8
Expand Down Expand Up @@ -977,15 +964,10 @@ jobs:
!/.repos/
sparse-checkout-cone-mode: false

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

- name: Build the npm launcher
run: node scripts/build-npm-launcher.ts --version "${{ needs.preflight.outputs.version }}" --output-dir npm-packages
Expand Down Expand Up @@ -1041,15 +1023,10 @@ jobs:
!/.repos/
sparse-checkout-cone-mode: false

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

- name: Download relay client tracing config
uses: actions/download-artifact@v8
Expand Down Expand Up @@ -1145,11 +1122,9 @@ jobs:
sparse-checkout-cone-mode: false

- name: Setup Vite+
uses: voidzero-dev/setup-vp@v1
uses: ./.github/actions/setup-ci-deps
with:
node-version-file: package.json
cache: false
run-install: false
install: false

- name: Alias channel
shell: bash
Expand Down Expand Up @@ -1216,14 +1191,10 @@ jobs:
!/.repos/
sparse-checkout-cone-mode: false

- name: Setup Vite+
uses: voidzero-dev/setup-vp@v1
- name: Setup dependencies
uses: ./.github/actions/setup-ci-deps
with:
node-version-file: package.json
cache: true
run-install: |
args:
- --filter=@t3tools/marketing...
install-args: --filter=@t3tools/marketing...

- id: deploy
name: Build staged deployment
Expand Down Expand Up @@ -1287,11 +1258,9 @@ jobs:
sparse-checkout-cone-mode: false

- name: Setup Vite+
uses: voidzero-dev/setup-vp@v1
uses: ./.github/actions/setup-ci-deps
with:
node-version-file: package.json
cache: false
run-install: false
install: false

- name: Promote marketing site
shell: bash
Expand Down Expand Up @@ -1346,15 +1315,10 @@ jobs:
echo "name=${APP_SLUG}[bot]" >> "$GITHUB_OUTPUT"
echo "email=${user_id}+${APP_SLUG}[bot]@users.noreply.github.com" >> "$GITHUB_OUTPUT"

- name: Setup Vite+
uses: voidzero-dev/setup-vp@v1
- name: Setup dependencies
uses: ./.github/actions/setup-ci-deps
with:
node-version-file: package.json
cache: true
run-install: |
args:
- --filter=@t3tools/scripts...
- --filter=@t3tools/oxlint-plugin-t3code...
install-args: --filter=@t3tools/scripts... --filter=@t3tools/oxlint-plugin-t3code...

- id: update_versions
name: Update version strings
Expand Down Expand Up @@ -1411,14 +1375,10 @@ jobs:
!/.repos/
sparse-checkout-cone-mode: false

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

- name: Read published release notes
if: needs.preflight.outputs.is_prerelease == 'true'
Expand Down
7 changes: 5 additions & 2 deletions apps/desktop/src/app/DesktopAppActivation.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// @effect-diagnostics nodeBuiltinImport:off -- Local socket ownership checks need lstat, an atomic rename, and a directory watch at the Node adapter boundary.
import { pipe } from "effect/Function";
import * as NodeCrypto from "node:crypto";
import * as NodeFS from "node:fs";
import * as NodeFSP from "node:fs/promises";
Expand Down Expand Up @@ -151,8 +152,10 @@ export async function startDesktopAppControlServer(input: {
}

if (!isDesktopAppActivationRequest(parsed)) {
finish(
invalidResponse(requestIdFromUnknown(parsed), "The desktop app request is invalid."),
pipe(
requestIdFromUnknown(parsed),
(requestId) => invalidResponse(requestId, "The desktop app request is invalid."),
finish,
);
return;
}
Expand Down
Loading
Loading