Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
165 commits
Select commit Hold shift + click to select a range
8dd0247
fix(web): restore providers settings heading (#12552)
maria-rcks Sep 19, 2026
7810fb2
Add new GitHub user 'yordis' to VOUCHED.td (#12546)
juliusmarminge Sep 19, 2026
f9e8f57
chore: vouch cestercian (#12638)
juliusmarminge Sep 19, 2026
dcf8942
fix(web): keep desktop annotation screenshots under CSP (#12636)
cestercian Sep 19, 2026
e367256
fix(web): keep typed text when a question option is clicked (#12577)
cestercian Sep 19, 2026
63ff337
fix(server): empty Claude homePath shares continuation with ~/.claude…
cestercian Sep 19, 2026
52d08a1
fix(desktop): include SnapShot app text for Flatpak and GTK4 (#12635)
cestercian Sep 19, 2026
d6f2913
fix(server): surface ACP stderr when cursor-agent exits at session st…
cestercian Sep 19, 2026
599c977
fix(web): align pull request state glyph to top of row (#11268)
akash3444 Sep 20, 2026
7445aa7
fix(web): align menu item icons in pull request detail panel (#11263)
akash3444 Sep 20, 2026
4a560b4
fix(web): honor whitespace settings in pull request diffs (#12438)
Bil0000 Sep 20, 2026
0ff87f2
fix(web): keep citation comment when popover is dismissed (#10831)
flamboh Sep 20, 2026
c14f601
fix(web): keep narrow chat headers readable and aligned (#12453)
shivamhwp Sep 20, 2026
fa1e171
refactor(observability): hold OTLP export settings per signal (#12657)
yordis Sep 20, 2026
ead1dee
fix(web): explain what enabling network access means in its confirmat…
Mnigos Sep 20, 2026
9f0c9f7
fix(web): reuse current PR status in the sidebar (#12545)
flamboh Sep 20, 2026
6a699f0
fix(web): stabilize pull request loading layout (#12721)
flamboh Sep 20, 2026
55c2427
fix(desktop): align preview recording cursors and show input feedback…
juliusmarminge Sep 20, 2026
7ade2d2
fix(web): the Run on / Workspace menu closes after a pick (#12685)
Mnigos Sep 20, 2026
3cfebf4
fix(web): keep portaled menus clickable over Electron drag regions (#…
maria-rcks Sep 20, 2026
5d9e27a
fix(web): render citations in queued messages (#12403)
maria-rcks Sep 20, 2026
2d8f9a8
fix(web): keep the timeline still when the resting composer expands (…
flamboh Sep 20, 2026
45e06f4
fix: composer hero reads project name to screen readers (#12397)
Leos-Khai Sep 20, 2026
f6cc6bc
fix(mobile): respect word wrap in diffs (#12590)
jakeleventhal Sep 20, 2026
adcd908
fix(web): allow full contrast in assistant replies (#12405)
maria-rcks Sep 20, 2026
9334924
fix(web): pull request chips share the link hover preview (#12719)
flamboh Sep 20, 2026
584450a
fix(web): compact the worktree setup glass popover (#12802)
maria-rcks Sep 20, 2026
67285e4
fix(web): route keyboard submit through the primary worktree action (…
maria-rcks Sep 20, 2026
c789cd1
fix(web): skip image inline chip when composer is empty (#12528)
maria-rcks Sep 20, 2026
f4d979a
fix(web): only show notice details when text is clipped (#12760)
t3-code[bot] Sep 20, 2026
9f73ca3
fix(devices): recover simulator streams after failures (#12639)
juliusmarminge Sep 20, 2026
1ba471a
chore(server): bump device tooling versions (#12809)
juliusmarminge Sep 21, 2026
2b17823
fix: allow more attachments without raising the image payload budget …
Bil0000 Sep 21, 2026
051a405
fix(web): device Reconnect starts one stream instead of two (#12808)
juliusmarminge Sep 21, 2026
58f8981
fix(server): tolerate shutting down an iOS simulator that is already …
juliusmarminge Sep 21, 2026
411da2a
feat(web): use the linked pull request row layout on the pull request…
maria-rcks Sep 21, 2026
2efb817
fix(clients): keep backslashes in copied Codex citations (#12243)
Lucenx9 Sep 21, 2026
f7efb53
feat(web): truncate branch names and paths in the middle (#12805)
maria-rcks Sep 21, 2026
dca84ef
fix(web): paste markdown with inline code inside bold, italic, or str…
Gigioxx Sep 21, 2026
a9ab904
feat(web): show the pull request refresh spinning in the detail heade…
maria-rcks Sep 21, 2026
a4bc7de
fix(web): dismiss composer suggestions with Escape (#12836)
Yash-Singh1 Sep 21, 2026
a6cb1dd
fix(mobile): keep the source worktree when starting a thread on a bra…
SunkenInTime Sep 21, 2026
6cc7f70
fix(web): keep composer controls visible while they fit (#12837)
maria-rcks Sep 21, 2026
5c5fa5f
feat(devices): show installed and running tool versions per host (#12…
juliusmarminge Sep 21, 2026
3b836f9
feat(devices): show automatic update progress and host retry (#12817)
juliusmarminge Sep 21, 2026
61b25b8
feat(devices): add read-only update discovery and remote ownership (#…
juliusmarminge Sep 21, 2026
790be6d
fix(devices): safely reclaim obsolete managed tool versions (#12819)
juliusmarminge Sep 21, 2026
30e3649
fix(web): match thread notification icons to sidebar status (#12806)
maria-rcks Sep 21, 2026
f391b88
fix(web): move sidebar shelves as one block (#11772)
maria-rcks Sep 21, 2026
6b0a04a
fix(web): offer undo after unpinning a thread (#10744)
saphid Sep 21, 2026
5781b52
feat(web): undo settle, snooze and archive, with a mod+z shortcut (#1…
juliusmarminge Sep 21, 2026
1eeeabb
fix(mobile): use a proper pull request icon on iOS (#12855)
juliusmarminge Sep 21, 2026
b379b5b
test(web): remove redundant favicon test (#12856)
t3-code[bot] Sep 21, 2026
1de563c
feat(devices): offer manual updates in tool version details (#12877)
juliusmarminge Sep 21, 2026
371b52d
feat(web): answer pull request actions on the row at once (#12843)
maria-rcks Sep 21, 2026
33cb911
fix(mobile): stop iOS autocorrect from rewriting search queries (#12949)
juliusmarminge Sep 21, 2026
2c2fa8c
fix(web): pull request embed chip shows the state icon (#12951)
flamboh Sep 21, 2026
2d377bf
fix(web): dismiss selection actions when pressing buttons (#12950)
Yash-Singh1 Sep 21, 2026
d2a90b9
fix(web): name message copy actions accurately (#12865)
saphid Sep 21, 2026
80d9c18
fix(contracts): old message-sent events without turnId no longer stop…
Mnigos Sep 21, 2026
e1cbb70
fix(web): the custom snooze calendar starts the week where the locale…
Mnigos Sep 21, 2026
76cc9b0
chore(mobile): bump app version to 1.3.0
t3-code[bot] Sep 21, 2026
1262d2f
feat(server): let t3.json limit or disable submodule init in new work…
juliusmarminge Sep 22, 2026
742173a
feat(settings): resolve t3.json inside the project settings resolver …
juliusmarminge Sep 22, 2026
0141bc2
feat(settings): choose how new worktrees initialize submodules (#12955)
juliusmarminge Sep 22, 2026
9a609a4
fix(web): show thread undo notice in the sidebar (#12972)
juliusmarminge Sep 22, 2026
5423ba0
feat(web): merge the comment and review buttons into one composer (#1…
Bil0000 Sep 22, 2026
e65bc1c
fix(web): allow text selection when renaming threads (#12935)
carterwsmith Sep 22, 2026
5a61f50
chore(lint): report className restyling of components/ui exports (#12…
juliusmarminge Sep 22, 2026
c26119a
refactor(web): drop className overrides that repeat the base styles (…
juliusmarminge Sep 22, 2026
438bf46
fix(web): close menus when clicking into the browser tab (#11148)
Gigioxx Sep 22, 2026
b5a0f81
refactor(web): give Spinner and RefreshIcon a size prop (#12985)
juliusmarminge Sep 22, 2026
aff9318
fix(web): retry failed attachment uploads after reconnect (#10338)
StiensWout Sep 22, 2026
da6a85b
fix(web): respect panel motion in composer transitions (#11064)
gsimone Sep 22, 2026
7c2702d
fix(web): read panel animation settings in the composer (#13098)
juliusmarminge Sep 22, 2026
f25a8e4
feat(models): add opus 5.5 without changing existing aliases (#13094)
t3-code[bot] Sep 22, 2026
17e3477
Update model manifest with new timestamps and models
juliusmarminge Sep 22, 2026
c0490e9
refactor(web): use ghost-muted where ghost buttons restyled to muted …
juliusmarminge Sep 22, 2026
1a81ea8
refactor(web): fold repeated overrides into ui defaults (#13021)
juliusmarminge Sep 22, 2026
ce98d41
refactor(web): mark the current menu value with MenuRadioGroup (#13022)
juliusmarminge Sep 22, 2026
ed85694
refactor(web): add an active prop to CommandItem (#13023)
juliusmarminge Sep 22, 2026
bbd5cc0
chore(lint): exempt CollapsibleTrigger from no-restyle (#13024)
juliusmarminge Sep 22, 2026
9515016
refactor(web): use icon-xs where icon buttons were forced to size-6 (…
juliusmarminge Sep 22, 2026
b4f1f18
refactor(web): add radius="none" to ScrollArea (#13026)
juliusmarminge Sep 22, 2026
7b54af9
refactor(web): add font="mono" to Input (#13027)
juliusmarminge Sep 22, 2026
be80e36
refactor(web): add SidebarInput (#13028)
juliusmarminge Sep 22, 2026
8d02447
refactor(web): add a label variant to Badge (#13029)
juliusmarminge Sep 22, 2026
7d658c2
refactor(web): give Skeleton three shapes (#13030)
juliusmarminge Sep 22, 2026
aa2b25d
refactor(web): one wrap width for tooltips, plus a code variant (#13031)
juliusmarminge Sep 22, 2026
f3d3fe4
refactor(web): one vertical rhythm for dialog bodies (#13032)
juliusmarminge Sep 22, 2026
18aa703
refactor(web): ghost-muted icons follow the text; add ghost-destructi…
juliusmarminge Sep 22, 2026
4c9fbf1
refactor(web): InlineButton underlines on hover and takes a tone (#13…
juliusmarminge Sep 22, 2026
d7736e0
refactor(web): one minimum width for menus, three widths for popovers…
juliusmarminge Sep 22, 2026
da89e10
refactor(web): every textarea caps its growth; the diff comment box i…
juliusmarminge Sep 22, 2026
016cdb9
refactor(web): stacked sidebar groups share one inset (#13037)
juliusmarminge Sep 22, 2026
e420ef9
refactor(web): Collapsible stays a plain container (#13038)
juliusmarminge Sep 22, 2026
0fa4a85
refactor(web): show more / show less are ordinary sidebar sub-rows (#…
juliusmarminge Sep 22, 2026
0ee02eb
refactor(web): Empty has three sizes (#13040)
juliusmarminge Sep 22, 2026
4321aa2
refactor(web): one row height for select, combobox and radio items (#…
juliusmarminge Sep 22, 2026
1c2f933
refactor(web): render menu and popover triggers through Button (#13042)
juliusmarminge Sep 22, 2026
83bbfa7
refactor(web): sidebar alerts use the standard variants; one keycap (…
juliusmarminge Sep 22, 2026
f193a68
fix(server): bypass owned caches on explicit provider refresh (#13109)
juliusmarminge Sep 22, 2026
d7819c1
chore(devices): bump agent-device to 0.21.12 (#13124)
juliusmarminge Sep 22, 2026
bed0b4c
chore(mobile): drop dead nitro-markdown tgz override and @expo/metro-…
juliusmarminge Sep 22, 2026
242816a
feat(web): show settings scope as a sentence at the top of the page (…
juliusmarminge Sep 22, 2026
db9a067
refactor(web): move settings scope pickers into breadcrumbs (#13165)
Yash-Singh1 Sep 23, 2026
7e65b22
feat(auth): share provider sign-in flows and credential bindings (#12…
juliusmarminge Sep 23, 2026
ec28eef
refactor(mobile): git sheets use uniwind platform variants instead of…
juliusmarminge Sep 23, 2026
3409651
chore(mobile): name the two project favicon caches by their job (#13160)
juliusmarminge Sep 23, 2026
6dcde21
revert(mobile): git sheets back to Platform.OS ternaries (un-guarded …
juliusmarminge Sep 23, 2026
5d493d6
docs(mobile): document the two mobile routes that intentionally skip …
juliusmarminge Sep 23, 2026
5821b77
refactor(mobile): break module cycles with focused extractions (#13151)
juliusmarminge Sep 23, 2026
f223312
fix(server): generate PR diffs from branch changes (#13170)
Yash-Singh1 Sep 23, 2026
68607c5
fix(web): preserve nested scroll behavior in chat timeline (#13167)
Yash-Singh1 Sep 23, 2026
b954af6
test(web): cover usage model ordering without static markup (#13104)
flamboh Sep 23, 2026
e4422ee
fix(desktop): find linuxbrew node for the WSL backend (#7827)
CodyRay Sep 23, 2026
ca864a2
chore(models): use GPT-6 Luna for text generation (#13115)
extoci Sep 23, 2026
a493946
fix(mobile): keep ordinary offline outbox failures out of console.war…
juliusmarminge Sep 23, 2026
96c4bfa
feat(providers): check remote compatibility ranges (#13130)
juliusmarminge Sep 23, 2026
2eaff08
chore(lint): keep mobile theme escape-hatch allowlist honest (#13146)
juliusmarminge Sep 23, 2026
6975efd
fix(web): the pull request badge reads at the meta size again (#13175)
juliusmarminge Sep 23, 2026
b919961
fix(mobile): uniwind platform variants stay guarded on both platforms…
juliusmarminge Sep 23, 2026
21be723
refactor(mobile): git sheets use uniwind platform variants instead of…
juliusmarminge Sep 23, 2026
db898a3
refactor(mobile): remaining className platform ternaries become class…
juliusmarminge Sep 23, 2026
219c1d2
fix(web): align provider emails without clipping (#13174)
Derpedyea Sep 23, 2026
151324b
perf(mobile): recycle the default v2 home list and scope the snooze m…
juliusmarminge Sep 23, 2026
0c91f68
refactor(mobile): retire the legacy grouped thread list (#13183)
juliusmarminge Sep 23, 2026
5975ec7
fix(server): background PR checks spend less GitHub quota (#13189)
juliusmarminge Sep 23, 2026
18de6bb
fix(server): background PR sync reads summaries in batches (#13198)
juliusmarminge Sep 23, 2026
eafb4a9
fix(server): GitHub PR lookups stop probing owner-qualified heads (#1…
juliusmarminge Sep 23, 2026
aca3c87
chore(mobile): clear the legacy-list deletion fallout (#13203)
juliusmarminge Sep 23, 2026
29931dd
hatch/variant functions (#13191)
juliusmarminge Sep 23, 2026
266d70c
refactor(web): context chips render through one ContextChip component…
juliusmarminge Sep 23, 2026
361b047
refactor(web): ui components drop their secondary className props (#1…
juliusmarminge Sep 23, 2026
866fc90
refactor(web): menu triggers and items stop restyling ui/menu (#13205)
juliusmarminge Sep 23, 2026
2107939
refactor(web): field controls stop restyling Input, Select, Combobox …
juliusmarminge Sep 23, 2026
f465227
refactor(web): app code stops restyling sidebar, popover, table and m…
juliusmarminge Sep 23, 2026
71c9b69
refactor(web): Button consumers outside the composer stop restyling i…
juliusmarminge Sep 23, 2026
0e512db
refactor(web): composer controls own their look instead of restyling …
juliusmarminge Sep 23, 2026
10882be
chore(web): no-restyle fails lint, and the ceiling gate goes (#13210)
juliusmarminge Sep 23, 2026
23c7ab9
fix(mobile): recover from screen render errors (#13197)
juliusmarminge Sep 23, 2026
829af7b
feat(web): navigate back and forward with mod+[ and mod+] (#13212)
juliusmarminge Sep 23, 2026
b21c545
fix(web): sort title matches by recent activity (#13219)
Yash-Singh1 Sep 23, 2026
eb6c170
test(desktop): remove redundant keyring module-load test (#13220)
t3-code[bot] Sep 23, 2026
f5ef0dd
chore(mobile): bump app version to 1.3.1
t3-code[bot] Sep 23, 2026
11e91f1
feat(mobile): capture Live Activities and agent notifications in show…
juliusmarminge Sep 23, 2026
68fb7f4
feat(mobile): manage environment and provider updates (#13302)
juliusmarminge Sep 23, 2026
e407f9b
fix(ci): shard release tests like pull request CI (#13321)
juliusmarminge Sep 23, 2026
effaab9
fix(web): show previous worktree branch on second line (#13314)
Yash-Singh1 Sep 23, 2026
d4cd7d5
fix(providers): restore compatibility ranges for every harness (#13328)
juliusmarminge Sep 24, 2026
894d334
fix(preview): use the visible browser for new agent sessions (#13064)
Bil0000 Sep 24, 2026
e4eb997
fix(server): stop replaying old agent alerts on restart (#13340)
juliusmarminge Sep 24, 2026
c0912de
fix(web): use a brain icon for the effort dropdown (#13309)
t3-code[bot] Sep 24, 2026
6b4b190
fix(desktop): SnapShot shortcut helper no longer adds a Dock icon on …
Gigioxx Sep 24, 2026
9030a60
fix(web): composer chip rings no longer clip at the editor edge (#13301)
flamboh Sep 24, 2026
21e2b7d
fix(web): switches announce their real state to screen readers (#11580)
Leos-Khai Sep 24, 2026
f1add18
fix(shared): preserve final quoted empty CSV records (#11425)
Lucenx9 Sep 24, 2026
78af372
feat(web): add an interactive 3D device workspace (#12787)
juliusmarminge Sep 24, 2026
9383f4a
chore: add scratchyone to vouched list (#13353)
t3-code[bot] Sep 24, 2026
e67abcf
feat(observability): honor the OpenTelemetry kill switch (#13355)
juliusmarminge Sep 24, 2026
353a9e2
Merge remote-tracking branch 'upstream/main' into yordis/chore-sync-u…
yordis Sep 24, 2026
b82ccf7
fix(server): keep upstream's new tests building against the fork's pr…
yordis Sep 24, 2026
07b44af
docs(fork): 0018 and 0022 stop claiming the kill switch as fork-only
yordis Sep 24, 2026
8a98267
fix: keep fork surfaces passing upstream's no-restyle lint and layer …
yordis Sep 24, 2026
1ae75b2
fix(shared): one default signal export, not an upstream copy nobody r…
yordis Sep 24, 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
  •  
  •  
  •  
3 changes: 3 additions & 0 deletions .github/VOUCHED.td
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ github:bil0000
github:binbandit
github:Brechard
github:btsouth
github:cestercian
github:chrisdeeming
github:chuks-qua
github:cursoragent
Expand Down Expand Up @@ -67,6 +68,7 @@ github:realAhmedRoach
github:Rishet11
github:ryanrhughes
github:saphid
github:scratchyone
github:sethwebster
github:shiroyasha9
github:shivamhwp
Expand All @@ -80,3 +82,4 @@ github:vitalyiegorov
github:Yash-Singh1
github:yashranaway
github:Ymit24
github:yordis
14 changes: 13 additions & 1 deletion .github/workflows/mobile-eas-preview.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,19 @@ jobs:
working-directory: apps/mobile
env:
EXPO_TOKEN: ${{ secrets.EXPO_TOKEN }}
run: eas env:pull preview --non-interactive
run: |
eas env:pull preview --non-interactive
# EAS Update disables dotenv loading. Keep the downloaded native config
# in its process environment so Android build and OTA fingerprints match.
node --input-type=module <<'NODE'
import { appendFileSync, readFileSync } from "node:fs";
import { parseEnv } from "node:util";
const env = parseEnv(readFileSync(".env.local", "utf8"));
const googleServicesFile = env.T3CODE_ANDROID_GOOGLE_SERVICES_FILE;
if (googleServicesFile) {
appendFileSync(process.env.GITHUB_ENV, `T3CODE_ANDROID_GOOGLE_SERVICES_FILE=${googleServicesFile}\n`);
}
NODE

- name: Deploy with fingerprint check
if: steps.expo-token.outputs.present == 'true'
Expand Down
11 changes: 11 additions & 0 deletions .github/workflows/mobile-showcase-screenshots.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,17 @@ jobs:
echo "$vp_pnpm_bin" >> "$GITHUB_PATH"
"$vp_pnpm_bin/pnpm" --version

- name: Install AXe
# Locks the simulator and answers the notification prompt for the
# agent-activity scene.
# Homebrew refuses third-party tap formulae until they are trusted;
# older releases have no trust command and install them as is.
run: |
brew tap cameroncooke/axe
if brew commands | grep -qx trust; then brew trust --formula cameroncooke/axe/axe; fi
brew install cameroncooke/axe/axe
axe --version

- name: Capture iOS showcase
run: pnpm screenshots:mobile --platform ios --appearance "${{ inputs.appearance }}" --theme "${{ inputs.theme }}"

Expand Down
71 changes: 68 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -259,13 +259,76 @@ jobs:
- name: Typecheck
run: vp run typecheck

# Keep tests on their own runners, using the same package split and server
# shards as CI, so the release check job does not spend its budget on tests.
test:
name: Release tests
needs: [preflight]
if: ${{ !failure() && !cancelled() && needs.preflight.result == 'success' }}
runs-on: ubuntu-24.04 # blacksmith-8vcpu-ubuntu-2404
timeout-minutes: 10
steps:
- name: Checkout
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
with:
ref: ${{ needs.preflight.outputs.ref }}
sparse-checkout: |
/*
!/.repos/
sparse-checkout-cone-mode: false

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

- name: Ensure Electron runtime is installed
run: vp run --filter @t3tools/desktop ensure:electron

- uses: ./.github/actions/setup-apt-mirrors

- name: Install browser secret helper build libraries
run: sudo apt-get update && sudo apt-get install -y libsecret-1-dev pkg-config
run: |
sudo sed -i 's|http://|https://|g' /etc/apt/blacksmith-ubuntu-mirrors.txt /etc/apt/sources.list.d/ubuntu.sources
sudo apt-get update && sudo apt-get install -y libsecret-1-dev pkg-config build-essential

- name: Test
run: vp run --parallel --concurrency-limit 4 --filter '!t3' --filter '!@t3tools/monorepo' test

test_server:
name: Release server tests ${{ matrix.shard }}
needs: [preflight]
if: ${{ !failure() && !cancelled() && needs.preflight.result == 'success' }}
runs-on: ubuntu-24.04 # blacksmith-8vcpu-ubuntu-2404
timeout-minutes: 10
strategy:
fail-fast: false
matrix:
shard: [1, 2, 3]
steps:
- name: Checkout
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
with:
ref: ${{ needs.preflight.outputs.ref }}
sparse-checkout: |
/*
!/.repos/
sparse-checkout-cone-mode: false

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

# No Electron setup here: `t3` (apps/server) has no Electron dependency
# and none of its tests touch the runtime. Only the non-server `test`
# job, which covers @t3tools/desktop, needs the download.
- name: Test
run: vp run test
run: vp run --filter t3 test --shard ${{ matrix.shard }}/${{ strategy.job-total }}

relay_public_config:
name: Resolve T3 Connect public config
Expand Down Expand Up @@ -645,13 +708,15 @@ jobs:
preflight,
relay_public_config,
quality,
test,
test_server,
desktop_mac_arm64,
desktop_linux_x64,
desktop_linux_arm64,
desktop_win_x64,
desktop_win_arm64,
]
if: ${{ !failure() && !cancelled() && needs.preflight.result == 'success' && needs.relay_public_config.outputs.relay_url != '' && needs.quality.result == 'success' && needs.desktop_mac_arm64.result == 'success' && needs.desktop_linux_x64.result == 'success' && needs.desktop_linux_arm64.result == 'success' && needs.desktop_win_x64.result == 'success' && needs.desktop_win_arm64.result == 'success' }}
if: ${{ !failure() && !cancelled() && needs.preflight.result == 'success' && needs.relay_public_config.outputs.relay_url != '' && needs.quality.result == 'success' && needs.test.result == 'success' && needs.test_server.result == 'success' && needs.desktop_mac_arm64.result == 'success' && needs.desktop_linux_x64.result == 'success' && needs.desktop_linux_arm64.result == 'success' && needs.desktop_win_x64.result == 'success' && needs.desktop_win_arm64.result == 'success' }}
runs-on: ubuntu-24.04 # blacksmith-8vcpu-ubuntu-2404
timeout-minutes: 15
permissions:
Expand Down
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ Full glossary with file links: `docs/internals/glossary.md`
## Taste

- Complexity belongs at the adapter boundary. Orchestration stays pure, UI stays dumb.
- `apps/web/src/components/ui` exports own their look. Pick a `variant` or `size`; do not restyle one with `className`. If none fits and the look is a generic concept, add a variant to the component; a look that belongs to one feature stays in that feature's own component, not in `components/ui`. Layout classes (width, flex, margin, position) belong on the parent. `shadcn/no-restyle` fails lint on violations.
- Inferred types over annotations. `any` is the enemy.
- Comments describe how a thing is used, and move when the code moves. To be used mostly to describe functions, not to annotate every line of behavior.
- Our users drive agents all day and notice a dropped frame, a lying spinner, and a stale label. No continuously repainting animations; they peg the GPU on high-refresh displays.
Expand Down
54 changes: 54 additions & 0 deletions apps/desktop/src/app/DesktopObservability.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,31 @@ describe("DesktopObservability", () => {
);
});

it.effect("exports kill switch warnings through the configured logger", () => {
const requests: Array<ExportedRequest> = [];
return Effect.gen(function* () {
const fileSystem = yield* FileSystem.FileSystem;
const baseDir = yield* fileSystem.makeTempDirectoryScoped({
prefix: "t3-desktop-observability-test-",
});
const environmentLayer = makeEnvironmentLayer(baseDir, true, {
T3CODE_OTLP_LOGS_URL: "https://collector.example.com/v1/logs",
OTEL_SDK_DISABLED: "1",
});

yield* Effect.scoped(
Effect.void.pipe(
Effect.provide(DesktopObservability.layer.pipe(Layer.provideMerge(environmentLayer))),
),
);

assert.include(requests[0]?.body ?? "", "OTEL_SDK_DISABLED=1 was read as false");
}).pipe(
Effect.scoped,
Effect.provide(Layer.mergeAll(NodeServices.layer, collectorLayer(requests))),
);
});

it.effect("reads every signal endpoint from Settings when the environment names none", () => {
const requests: Array<ExportedRequest> = [];
return Effect.gen(function* () {
Expand Down Expand Up @@ -491,4 +516,33 @@ describe("DesktopObservability", () => {
Effect.provide(Layer.mergeAll(NodeServices.layer, collectorLayer(requests))),
);
});

it.effect("stops every export when the OpenTelemetry SDK is disabled", () => {
const requests: Array<ExportedRequest> = [];
return Effect.gen(function* () {
const fileSystem = yield* FileSystem.FileSystem;
const baseDir = yield* fileSystem.makeTempDirectoryScoped({
prefix: "t3-desktop-observability-test-",
});
const environmentLayer = makeEnvironmentLayer(baseDir, true, {
OTEL_SDK_DISABLED: "true",
});
yield* writeObservabilitySettings(environmentLayer, {
otlpTracesUrl: "https://settings.example.com/v1/traces",
otlpLogsUrl: "https://settings.example.com/v1/logs",
});

yield* Effect.scoped(
Effect.logInfo("desktop log stays local when disabled").pipe(
Effect.withSpan("desktop-disabled-test"),
Effect.provide(DesktopObservability.layer.pipe(Layer.provideMerge(environmentLayer))),
),
);

assert.lengthOf(requests, 0);
}).pipe(
Effect.scoped,
Effect.provide(Layer.mergeAll(NodeServices.layer, collectorLayer(requests))),
);
});
});
11 changes: 6 additions & 5 deletions apps/desktop/src/app/DesktopObservability.ts
Original file line number Diff line number Diff line change
Expand Up @@ -620,10 +620,6 @@ const telemetryLayer = Layer.unwrap(
const environment = yield* DesktopEnvironment.DesktopEnvironment;
const resolved = yield* resolveOtlpExport;

for (const warning of resolved.warnings) {
yield* Effect.logWarning(warning);
}

const otlpResource = otlpResourceFor(resolved.resource);

// `Logger.layer` writes the whole logger set rather than adding to it, so
Expand Down Expand Up @@ -718,7 +714,12 @@ const telemetryLayer = Layer.unwrap(
// : { temporality: resolved.metrics.temporality }),
// }).pipe(Layer.provide(serializationFor(resolved.metrics)));

return Layer.mergeAll(loggerLayer, tracerLayer);
// Logged once the loggers above are installed, so the warnings use them.
const otelWarningsLayer = Layer.effectDiscard(
Effect.forEach(resolved.warnings, (warning) => Effect.logWarning(warning)),
);

return otelWarningsLayer.pipe(Layer.provideMerge(Layer.mergeAll(loggerLayer, tracerLayer)));
}),
);

Expand Down
43 changes: 43 additions & 0 deletions apps/desktop/src/backend/DesktopBackendConfiguration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1056,6 +1056,49 @@ describe("DesktopBackendConfiguration", () => {
}).pipe(Effect.scoped, Effect.provide(NodeServices.layer)),
);

it.effect("resolveWsl carries the kill switch into the distro", () =>
Effect.gen(function* () {
const fileSystem = yield* FileSystem.FileSystem;
const baseDir = yield* fileSystem.makeTempDirectoryScoped({
prefix: "t3-desktop-backend-config-test-",
});

const previousWslEnv = process.env.WSLENV;
const previousDisabled = process.env.OTEL_SDK_DISABLED;
try {
delete process.env.WSLENV;
process.env.OTEL_SDK_DISABLED = "true";

yield* Effect.gen(function* () {
const configuration = yield* DesktopBackendConfiguration.DesktopBackendConfiguration;
const config = yield* configuration.resolveWsl({ port: 5050, distro: null });

assert.equal(config.env.OTEL_SDK_DISABLED, "true");
assert.include((config.env.WSLENV ?? "").split(":"), "OTEL_SDK_DISABLED");
}).pipe(
Effect.provide(
DesktopBackendConfiguration.layer.pipe(
Layer.provideMerge(serverExposureLayer),
Layer.provideMerge(DesktopAppSettings.layerTest()),
Layer.provideMerge(DesktopWslServerTree.layerTest()),
Layer.provideMerge(
DesktopWslEnvironment.layerTest({
isAvailable: true,
windowsToWslPath: () => Option.some("/mnt/c/repo/apps/server/src/index.ts"),
getDistroIp: () => Option.some("172.27.0.99"),
}),
),
Layer.provideMerge(makeEnvironmentLayer(baseDir, { platform: "win32" })),
),
),
);
} finally {
restoreEnv("WSLENV", previousWslEnv);
restoreEnv("OTEL_SDK_DISABLED", previousDisabled);
}
}).pipe(Effect.scoped, Effect.provide(NodeServices.layer)),
);

it.effect("resolveWsl preserves existing WSLENV entries when forwarding backend secrets", () =>
Effect.gen(function* () {
const fileSystem = yield* FileSystem.FileSystem;
Expand Down
11 changes: 9 additions & 2 deletions apps/desktop/src/electron/ElectronProtocol.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ describe("ElectronProtocol", () => {
);
assert.include(
response.headers.get("content-security-policy") ?? "",
"connect-src 'self' http: https: ws: wss:",
"connect-src 'self' blob: http: https: ws: wss:",
);
assert.include(
response.headers.get("content-security-policy") ?? "",
Expand Down Expand Up @@ -255,7 +255,14 @@ describe("ElectronProtocol", () => {
"https://clerk.t3.codes",
"https://challenges.cloudflare.com",
]);
assert.deepEqual(directives["connect-src"], ["'self'", "http:", "https:", "ws:", "wss:"]);
assert.deepEqual(directives["connect-src"], [
"'self'",
"blob:",
"http:",
"https:",
"ws:",
"wss:",
]);
assert.deepEqual(directives["img-src"], [
"'self'",
"t3code:",
Expand Down
3 changes: 2 additions & 1 deletion apps/desktop/src/electron/ElectronProtocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ export function makeDesktopContentSecurityPolicy(input: DesktopProtocolRegistrat
// the build-configured Clerk, relay, and OTLP endpoints. Those environment
// origins are not known when this response policy is created, so restrict
// connections by the network schemes the client supports instead of by host.
const connectSources = ["'self'", "http:", "https:", "ws:", "wss:"];
// GLTFLoader fetches embedded textures through blob URLs after parsing the model.
const connectSources = ["'self'", "blob:", "http:", "https:", "ws:", "wss:"];

return [
"default-src 'self'",
Expand Down
3 changes: 3 additions & 0 deletions apps/desktop/src/ipc/channels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const MENU_ACTION_CHANNEL = "desktop:menu-action";
export const PASTE_AS_TEXT_CHANNEL = "desktop:paste-as-text";
export const SNAP_SHOT_EVENT_CHANNEL = "desktop:snap-shot-event";
export const QUIT_SHORTCUT_CHANNEL = "desktop:quit-shortcut";
export const TRACKPAD_SCROLL_END_CHANNEL = "desktop:trackpad-scroll-end";
export const GET_WINDOW_FULLSCREEN_STATE_CHANNEL = "desktop:get-window-fullscreen-state";
export const WINDOW_FULLSCREEN_STATE_CHANNEL = "desktop:window-fullscreen-state";
export const DESKTOP_APP_ACTIVATION_READY_CHANNEL = "desktop:app-activation-ready";
Expand Down Expand Up @@ -113,3 +114,5 @@ export const PREVIEW_POINTER_EVENT_CHANNEL = "desktop:preview-pointer-event";
export const MAC_PERMISSION_HELPER_CHANNEL = "desktop:mac-permission-helper";

export const CHECK_SYSTEM_PERMISSION_CHANNEL = "desktop:check-system-permission";

export const PREVIEW_RECORDING_INPUT_CHANNEL = "desktop:preview-recording-input";
Loading
Loading