Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
5f1147c
fix(web): detect outdated nightly servers (#8124)
t3dotgg Aug 24, 2026
8287f2c
fix(web): align usage page skeleton layout (#8111)
tris203 Aug 24, 2026
883e1a3
fix(web): make terminal links appear clickable only when clickable (#…
flamboh Aug 24, 2026
a09f921
fix(web): make Windows file links clickable in chat (#8081)
t3dotgg Aug 24, 2026
a1379db
fix(web): sort usage models by token count (#8108)
RakshithBhat03 Aug 24, 2026
9996038
fix: open agent file links in the file viewer (#8098)
StiensWout Aug 24, 2026
c034f51
fix(server): stop routine events from rescanning thread history (#8150)
t3dotgg Aug 25, 2026
2394998
fix(deps): stop pnpm installs from changing the lockfile (#8163)
t3dotgg Aug 25, 2026
143341b
feat(web): settle and restore threads with a keyboard shortcut (#8089)
t3dotgg Aug 25, 2026
63eb042
perf(desktop): cut macOS signing calls by 81% (#8093)
t3dotgg Aug 25, 2026
3c75eb1
feat: link pull requests to threads (#8160)
t3dotgg Aug 25, 2026
bd9ed2b
feat(web): safely attach HEIC photos as JPEG images (#8161)
t3dotgg Aug 25, 2026
bce6809
feat(mobile): track device models and OS versions (#8169)
t3dotgg Aug 25, 2026
afc8342
fix(grok): bound cumulative tool output updates (#7279)
lnieuwenhuis Aug 25, 2026
e6d487e
fix(web): delay thread shortcut hints by 200 ms (#8172)
t3dotgg Aug 25, 2026
43f723f
fix(server): stop probing Cursor until enabled (#8175)
t3dotgg Aug 25, 2026
1a4a759
docs(release): verify remote updates with database migrations (#8177)
t3dotgg Aug 25, 2026
1baf991
fix(server): keep provider CLIs available in the macOS service (#8173)
t3dotgg Aug 25, 2026
c7222ca
feat(claude): compact old threads before they burn through usage (#8144)
t3dotgg Aug 25, 2026
589a9d0
fix(client-runtime): retry queries after connection interruption (#8117)
tris203 Aug 25, 2026
06de9e9
fix(server): keep previously used providers working after upgrades (#…
t3dotgg Aug 25, 2026
c6b8bb8
feat(desktop): build macOS previews from a PR label (#8182)
t3dotgg Aug 25, 2026
5d76653
fix(web): thread jump hints no longer stick after a dictation paste (…
t3dotgg Aug 25, 2026
e67074f
fix(web): keep grouped project renames (#7831)
MohtashamMurshid Aug 25, 2026
082e6ea
feat(web): reveal chat file chips in the system file manager (#7140)
SunkenInTime Aug 25, 2026
994372b
fix(server): push no longer writes a feature branch's commits to its …
t3dotgg Aug 25, 2026
5041777
chore(deps): bump @clerk/electron to 0.0.37 (#8240)
t3dotgg Aug 26, 2026
badae6a
feat(server): fetch legacy model classification from a hosted manifes…
t3dotgg Aug 26, 2026
860caaa
chore(release): prepare v0.0.34
t3-code[bot] Aug 26, 2026
b0a0281
fix(desktop): let Clerk UI receive stable auth fixes (#8248)
t3dotgg Aug 26, 2026
3b86ef9
fix(app): un-settled threads return to the top of the list (#8231)
t3dotgg Aug 26, 2026
a3a8cbd
perf(ci): cut about a minute from every release (#8250)
t3dotgg Aug 26, 2026
33b650a
feat(ci): download macOS preview DMGs without signing in (#8243)
t3dotgg Aug 27, 2026
f925d63
fix(codex): accept Codex 0.150 multi-agent events (#8346)
t3dotgg Aug 27, 2026
d3c24a1
chore(release): prepare v0.0.35
t3-code[bot] Aug 27, 2026
ead4ce5
fix(grok): improve skills, plans, usage, and turn reliability (#8358)
t3dotgg Aug 27, 2026
230c5d4
fix(server): recover stale Codex approval callbacks (#5195)
luckyPipewrench Aug 27, 2026
64ca3b6
test(server): remove duplicate missing worktree test (#8252)
t3-code[bot] Aug 27, 2026
a6797b3
fix(server): replay all un-applied events during projection bootstrap…
krutftw Aug 27, 2026
73f8cfc
test: remove low-signal test files (#8397)
t3-code[bot] Aug 27, 2026
f6f2be3
test: prune trivial error and layout tests (#8400)
t3-code[bot] Aug 27, 2026
348367d
Fix Android adaptive launcher icon (#4332)
colonelpanic8 Aug 27, 2026
e2d4d12
feat(web): split provider settings into list and editor (#8380)
t3dotgg Aug 27, 2026
94401d0
fix(codex): accept Codex 0.150 account plans (#8447)
gsimone Aug 27, 2026
b0ae3f3
fix(tooling): allow ignored-only staged changes (#8468)
juliusmarminge Aug 28, 2026
b982847
fix(mobile): keep iOS home header stable (#8467)
juliusmarminge Aug 28, 2026
f1e6f0c
fix(web): stop showing red x summaries for ordinary tool failures (#8…
t3dotgg Aug 28, 2026
850e458
fix(mobile): refine Git action toast glass styling (#8399)
juliusmarminge Aug 28, 2026
2fbe313
fix(desktop): allow preview automation in agent-created threads (#8483)
t3dotgg Aug 28, 2026
c8aba25
test(web): remove redundant cache key test (#8484)
t3-code[bot] Aug 28, 2026
5766dfb
fix(release): move nightly schedule to minute 38
t3dotgg Aug 28, 2026
f276e63
fix(web): stabilize the provider settings editor (#8472)
t3dotgg Aug 28, 2026
7068e86
fix(web): open GitHub pull requests in browser when loading fails (#8…
t3dotgg Aug 28, 2026
49f6241
fix(codex): show sub-agent models (#8502)
t3dotgg Aug 28, 2026
88be563
feat(analytics): report connected client platforms (#8481)
t3dotgg Aug 28, 2026
8f49132
feat(server): accept PDF, ZIP, and other file uploads up to 50MB (#8235)
t3dotgg Aug 28, 2026
4c51b4c
feat(web): toggle thread pin from the keyboard
ipanasenko Aug 28, 2026
9257bd8
fix(web): add back button to project settings (#8168)
StiensWout Aug 28, 2026
018d7f2
refactor(mobile): compile semantic themes for Uniwind (#7327)
juliusmarminge Aug 28, 2026
a940ce5
chore(upstream): merge pingdotgg/t3code@018d7f27
claude Aug 28, 2026
0a26585
test(server): keep the migration id pin anchored at Marcode's 33
claude Aug 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
8 changes: 4 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ on:
branches:
- main

permissions:
contents: read

concurrency:
group: ci-${{ github.event.pull_request.number || github.sha }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
Expand Down Expand Up @@ -52,10 +55,7 @@ jobs:
run: vp run build:desktop

- name: Verify preload bundle output
run: |
test -f apps/desktop/dist-electron/preload.cjs
grep -nE "desktopBridge|getLocalEnvironmentBootstrap|PICK_FOLDER_CHANNEL|wsUrl" apps/desktop/dist-electron/preload.cjs
grep -n "__clerk_internal_electron_passkeys" apps/desktop/dist-electron/preload.cjs
run: node apps/desktop/scripts/verify-preload-bundle.mjs

# Everything except `t3` (apps/server). `--parallel` drops the package
# dependency ordering that `vp run` applies by default: these `test` tasks
Expand Down
361 changes: 361 additions & 0 deletions .github/workflows/desktop-macos-preview.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,361 @@
name: Desktop macOS Preview

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

permissions:
contents: read

# Build events and cleanup events use separate groups: a push must cancel a
# stale in-flight build, but must never cancel a cleanup run mid-delete. The
# publish job re-checks PR state before uploading to cover the reverse race.
concurrency:
group: desktop-macos-preview-${{ github.event.pull_request.number }}-${{ contains(fromJSON('["closed", "unlabeled"]'), github.event.action) && 'cleanup' || 'build' }}
# Cleanup runs must complete (a close event right after an unlabel queues
# behind the running cleanup instead of canceling it mid-delete), and events
# that skip the build job, such as adding an unrelated label, must not
# cancel an in-flight build either.
cancel-in-progress: ${{ !contains(fromJSON('["closed", "unlabeled"]'), github.event.action) && (github.event.action != 'labeled' || github.event.label.name == 'preview:mac') }}

jobs:
# Builds run PR code, so this job keeps a read-only token. Publishing to the
# release happens in the publish job below, which never checks out PR code.
build:
name: Build macOS Apple Silicon preview
if: >-
github.event.action != 'closed' &&
github.event.action != 'unlabeled' &&
github.event.pull_request.head.repo.full_name == github.repository &&
contains(github.event.pull_request.labels.*.name, 'preview:mac') &&
(github.event.action != 'labeled' || github.event.label.name == 'preview:mac')
runs-on: blacksmith-12vcpu-macos-26
timeout-minutes: 30
outputs:
dmg_name: ${{ steps.build.outputs.dmg_name }}
version: ${{ steps.version.outputs.version }}
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: false

- name: Install desktop dependencies
run: vp install --filter=@t3tools/desktop... --filter=t3... --filter=@t3tools/scripts...

- name: Cache resource monitor
id: resource_monitor_cache
uses: actions/cache@v6
with:
path: native/resource-monitor/target/aarch64-apple-darwin/release/t3-resource-monitor
key: resource-monitor-aarch64-apple-darwin-${{ hashFiles('native/resource-monitor/Cargo.lock', 'native/resource-monitor/Cargo.toml', 'native/resource-monitor/src/**') }}

- name: Setup Rust
if: steps.resource_monitor_cache.outputs.cache-hit != 'true'
uses: dtolnay/rust-toolchain@stable
with:
targets: aarch64-apple-darwin

- id: version
name: Set preview version and public configuration
shell: bash
env:
PR_NUMBER: ${{ github.event.pull_request.number }}
run: |
set -euo pipefail

base_version="$(node -p "require('./apps/desktop/package.json').version")"
preview_version="${base_version}-pr.${PR_NUMBER}.${GITHUB_RUN_NUMBER}"
node scripts/update-release-package-versions.ts "$preview_version"
cp .env.example .env

echo "version=$preview_version" >> "$GITHUB_OUTPUT"

- id: build
name: Build unsigned macOS DMG
shell: bash
env:
T3CODE_DESKTOP_REUSE_RESOURCE_MONITOR: ${{ steps.resource_monitor_cache.outputs.cache-hit == 'true' }}
PREVIEW_VERSION: ${{ steps.version.outputs.version }}
run: |
set -euo pipefail

vp run dist:desktop:artifact \
--platform mac \
--target dmg \
--arch arm64 \
--build-version "$PREVIEW_VERSION" \
--verbose

shopt -s nullglob
dmg_files=(release/*.dmg)
if (( ${#dmg_files[@]} != 1 )); then
printf 'Expected one DMG, found %s.\n' "${#dmg_files[@]}" >&2
exit 1
fi
printf 'dmg_name=%s\n' "$(basename "${dmg_files[0]}")" >> "$GITHUB_OUTPUT"

# archive: false uploads the file as its own artifact named after the
# file, so the publish job downloads by *.dmg pattern, not by name.
- name: Upload macOS DMG
uses: actions/upload-artifact@v7
with:
path: release/*.dmg
if-no-files-found: error
archive: false
overwrite: true
retention-days: 7

# Release assets download without a GitHub account, unlike workflow
# artifacts. All preview DMGs live on one rolling prerelease tagged
# "desktop-preview" (release.yml only matches v*.*.* tags), so publishing a
# build never notifies release watchers. This job holds the write token and
# only handles the artifact the build job produced; it never runs PR code.
publish:
name: Publish anonymous download
needs: build
runs-on: blacksmith-8vcpu-ubuntu-2404
timeout-minutes: 10
permissions:
contents: write
pull-requests: write
steps:
- name: Download macOS DMG
uses: actions/download-artifact@v8
with:
pattern: "*.dmg"
merge-multiple: true
path: release

- id: upload
name: Upload DMG to the rolling preview release
shell: bash
env:
GH_TOKEN: ${{ github.token }}
PR_NUMBER: ${{ github.event.pull_request.number }}
DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
run: |
set -euo pipefail

tag="desktop-preview"

# True while the PR is open and still carries the preview label.
preview_eligible() {
[[ "$(gh pr view "$PR_NUMBER" --repo "$GITHUB_REPOSITORY" \
--json state,labels \
--jq '.state + " " + (.labels | map(.name) | contains(["preview:mac"]) | tostring)')" == "OPEN true" ]]
}

# The build ran for many minutes. If the PR closed or lost the label
# meanwhile, cleanup already ran in its own concurrency group, so
# publishing now would resurrect a deleted download.
if ! preview_eligible; then
echo "PR closed or preview label removed while building. Skipping publish."
exit 0
fi

dmg_path="$(find release -type f -name '*.dmg' -print -quit)"
if [[ -z "$dmg_path" ]]; then
echo "No DMG found in the downloaded artifact." >&2
exit 1
fi

# The filename comes out of the build, which runs PR code. Requiring
# this PR's marker keeps a build from clobbering or deleting another
# PR's asset, since those names carry a different -pr.N. marker.
if [[ "$(basename "$dmg_path")" != *"-pr.${PR_NUMBER}."* ]]; then
echo "DMG name '$(basename "$dmg_path")' does not carry this PR's -pr.${PR_NUMBER}. marker. Refusing to publish." >&2
exit 1
fi

if ! gh release view "$tag" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
# "|| true" tolerates a concurrent publish job creating the
# release between the check and the create.
gh release create "$tag" \
--repo "$GITHUB_REPOSITORY" \
--target "$DEFAULT_BRANCH" \
--prerelease \
--title "Desktop preview builds" \
--notes "Rolling unsigned desktop builds from pull requests with a preview label. Each download is removed when its pull request closes or loses the label. Install stable builds from the latest release instead." \
|| true
fi

# Keep one DMG per PR: drop this PR's older builds first. The
# trailing dot keeps -pr.12. from matching -pr.123. builds.
gh release view "$tag" --repo "$GITHUB_REPOSITORY" --json assets --jq '.assets[].name' \
| { grep -F -- "-pr.${PR_NUMBER}." || true; } \
| while read -r asset; do
gh release delete-asset "$tag" "$asset" --repo "$GITHUB_REPOSITORY" --yes \
|| echo "Asset $asset was already removed by a concurrent run."
done

gh release upload "$tag" "$dmg_path" --repo "$GITHUB_REPOSITORY" --clobber

# Re-check after uploading. A cleanup run that started during the
# upload listed assets before ours existed, so it cannot delete it.
# Whichever writer acts last sees the final PR state; if the preview
# became ineligible, delete what we just uploaded.
if ! preview_eligible; then
gh release delete-asset "$tag" "$(basename "$dmg_path")" --repo "$GITHUB_REPOSITORY" --yes \
|| echo "Asset was already removed by a concurrent run."
echo "PR closed or preview label removed during upload. Removed the download."
exit 0
fi

echo "download_url=https://github.com/${GITHUB_REPOSITORY}/releases/download/${tag}/$(basename "$dmg_path")" >> "$GITHUB_OUTPUT"

- name: Comment download link
if: steps.upload.outputs.download_url != ''
uses: actions/github-script@v8
env:
DOWNLOAD_URL: ${{ steps.upload.outputs.download_url }}
DMG_NAME: ${{ needs.build.outputs.dmg_name }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
PREVIEW_VERSION: ${{ needs.build.outputs.version }}
with:
script: |
const { data: pullRequest } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.payload.pull_request.number,
});
if (
pullRequest.head.sha !== process.env.HEAD_SHA ||
pullRequest.state !== "open" ||
!pullRequest.labels.some((label) => label.name === "preview:mac")
) {
core.info("Skipping the outdated macOS preview comment.");
return;
}

const marker = "<!-- desktop-macos-preview -->";
const body = [
marker,
"### macOS preview",
"",
`[Download Apple Silicon DMG](${process.env.DOWNLOAD_URL})`,
"",
`Version: ${process.env.PREVIEW_VERSION}`,
`Commit: ${process.env.HEAD_SHA.slice(0, 7)}`,
"",
"Unsigned build. Clear quarantine before opening:",
"```sh",
`xattr -d com.apple.quarantine ~/Downloads/${process.env.DMG_NAME}`,
"```",
"",
"No GitHub sign-in is needed. The download stays available until this PR closes or the preview label is removed.",
].join("\n");

const comments = await github.paginate(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,
});
}

# The way out: closing the PR or removing the label deletes its DMG from the
# rolling release and updates the PR comment to say so.
cleanup:
name: Remove preview download
if: >-
github.event.pull_request.head.repo.full_name == github.repository &&
((github.event.action == 'closed' && contains(github.event.pull_request.labels.*.name, 'preview:mac')) ||
(github.event.action == 'unlabeled' && github.event.label.name == 'preview:mac'))
runs-on: blacksmith-8vcpu-ubuntu-2404
timeout-minutes: 10
permissions:
contents: write
pull-requests: write
steps:
- id: delete
name: Delete this PR's preview assets
shell: bash
env:
GH_TOKEN: ${{ github.token }}
PR_NUMBER: ${{ github.event.pull_request.number }}
run: |
set -euo pipefail

tag="desktop-preview"

# A stale cleanup must not delete a download that became valid
# again. If the PR is open and labeled once more, the next publish
# owns this PR's assets and replaces them itself.
if [[ "$(gh pr view "$PR_NUMBER" --repo "$GITHUB_REPOSITORY" \
--json state,labels \
--jq '.state + " " + (.labels | map(.name) | contains(["preview:mac"]) | tostring)')" == "OPEN true" ]]; then
echo "PR is open and labeled again. Skipping cleanup."
echo "removed=false" >> "$GITHUB_OUTPUT"
exit 0
fi

echo "removed=true" >> "$GITHUB_OUTPUT"

if ! gh release view "$tag" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
echo "No preview release exists. Nothing to clean up."
exit 0
fi

gh release view "$tag" --repo "$GITHUB_REPOSITORY" --json assets --jq '.assets[].name' \
| { grep -F -- "-pr.${PR_NUMBER}." || true; } \
| while read -r asset; do
gh release delete-asset "$tag" "$asset" --repo "$GITHUB_REPOSITORY" --yes \
|| echo "Asset $asset was already removed by a concurrent run."
done

- name: Mark the preview comment as removed
if: steps.delete.outputs.removed == 'true'
uses: actions/github-script@v8
with:
script: |
const marker = "<!-- desktop-macos-preview -->";
const comments = await github.paginate(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) {
return;
}

await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existing.id,
body: [
marker,
"### macOS preview",
"",
"The preview download was removed because this PR closed or the preview label was removed.",
].join("\n"),
});
Loading
Loading