Skip to content

Commit a03c2ef

Browse files
Merge branch 'main' into fix/diagnostics-border-radius
2 parents 238d8ac + c8a606c commit a03c2ef

973 files changed

Lines changed: 54699 additions & 12426 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.agents/skills/test-t3-mobile/SKILL.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ This installs the dev client for the checkout's native fingerprint: from the
3838
device, the local cache, or the shared cache in seconds, building once only
3939
when no machine has that fingerprint yet (5-15 minutes, logged to the file it
4040
names). The device id may be omitted when exactly one device is booted. It
41-
prints one JSON line; on failure it names the next command. Authorized mobile
42-
verification includes that step unless the user prohibits it.
41+
prints one JSON line; on failure it names the next command. Mobile verification
42+
includes that step unless the user prohibits it.
4343

4444
For a device you opened in an agent-device session elsewhere (a device pool,
4545
cloud, or remote host), run `vp run mobile:install <ios|android> --session <s>`

‎.github/VOUCHED.td‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ github:myacoub91
5959
github:naMqe-h
6060
github:nateEc
6161
github:naveed949
62+
github:nexxeln
6263
github:nmggithub
6364
github:Noojuno
6465
github:notkainoa

‎.github/actions/setup-ci-deps/action.yml‎

Lines changed: 75 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,14 @@ inputs:
55
description: Read-only credential for the private maintainer task cache
66
required: false
77
default: ""
8+
install:
9+
description: Set to "false" to set up Vite+ only, with no pnpm store or install
10+
required: false
11+
default: "true"
12+
install-args:
13+
description: Arguments for `vp install`, such as filters. Empty installs the whole workspace.
14+
required: false
15+
default: ""
816
runs:
917
using: composite
1018
steps:
@@ -19,10 +27,11 @@ runs:
1927
echo "node=$(jq -r '.engines.node' package.json)" >> "$GITHUB_OUTPUT"
2028
echo "pnpm=$(jq -r '.packageManager' package.json)" >> "$GITHUB_OUTPUT"
2129
30+
# Pinned because release-desktop.yml signs builds with this action in the job.
2231
- name: Cache Vite+
2332
id: vp_cache
2433
if: steps.vp.outputs.version != ''
25-
uses: actions/cache@v6
34+
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
2635
with:
2736
path: ~/.vite-plus
2837
key: vite-plus-home-v2-${{ runner.os }}-${{ runner.arch }}-${{ steps.vp.outputs.version }}-node${{ steps.vp.outputs.node }}-${{ steps.vp.outputs.pnpm }}
@@ -38,38 +47,93 @@ runs:
3847
echo "$HOME/.vite-plus/bin" >> "$GITHUB_PATH"
3948
"$HOME/.vite-plus/bin/vp" env use "${{ steps.vp.outputs.node }}"
4049
50+
# vp gives each Node.js download attempt 10 minutes by default, so one
51+
# stalled stream holds the job that long. It retries 3 times and resumes
52+
# partial bytes, so a shorter limit costs a slow download only a retry.
4153
- name: Setup Vite+
4254
if: steps.vp_cache.outputs.cache-hit != 'true'
43-
uses: voidzero-dev/setup-vp@v1
55+
uses: voidzero-dev/setup-vp@250f29ce396baf5e8f24498e17c0dfdebabc26eb # v1
56+
env:
57+
VP_DOWNLOAD_TIMEOUT: "120"
4458
with:
4559
node-version-file: package.json
4660
cache: false
4761
run-install: false
4862

49-
- name: Resolve pnpm store path
63+
# A shared key lets whichever install saves first, often a small filtered
64+
# one, become every job's store. Each set of install args gets its own.
65+
- name: Resolve pnpm store
5066
id: pnpm_store
67+
if: inputs.install == 'true'
5168
shell: bash
69+
env:
70+
INSTALL_ARGS: ${{ inputs.install-args }}
5271
run: |
53-
store_path="$(vp pm cache dir)"
54-
echo "path=$store_path" >> "$GITHUB_OUTPUT"
72+
echo "path=$(vp pm cache dir)" >> "$GITHUB_OUTPUT"
73+
metadata_dir="${pnpm_config_cache_dir:-$RUNNER_TEMP/pnpm-metadata}"
74+
echo "pnpm_config_cache_dir=$metadata_dir" >> "$GITHUB_ENV"
75+
echo "verified=$metadata_dir/lockfile-verified.jsonl" >> "$GITHUB_OUTPUT"
76+
if [[ -z "$INSTALL_ARGS" ]]; then
77+
echo "namespace=full" >> "$GITHUB_OUTPUT"
78+
else
79+
echo "namespace=filtered-$(printf '%s' "$INSTALL_ARGS" | cksum | cut -d' ' -f1)" >> "$GITHUB_OUTPUT"
80+
fi
5581
56-
# setup-vp's shared cache key ignores install filters. Keep full installs in a
57-
# separate namespace, including fallback restores.
82+
# Filtered installs prefer the current full store, which holds every package,
83+
# over an older store of their own.
5884
# The pnpm store stays a cache tarball on the runner's own disk. A store on a
5985
# Blacksmith sticky disk mounts in under a second, but pnpm then copies every
6086
# package across filesystems instead of hard-linking it: install took 28-49s
6187
# against 9s plus an 11s restore.
62-
- name: Cache full pnpm store
63-
uses: actions/cache@v6
88+
- name: Restore pnpm store
89+
id: pnpm_cache
90+
if: inputs.install == 'true'
91+
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
6492
with:
6593
path: ${{ steps.pnpm_store.outputs.path }}
66-
key: pnpm-full-v1-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('pnpm-lock.yaml', 'pnpm-workspace.yaml', 'package.json') }}
94+
key: pnpm-${{ steps.pnpm_store.outputs.namespace }}-v1-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('pnpm-lock.yaml', 'pnpm-workspace.yaml', 'package.json') }}
6795
restore-keys: |
96+
pnpm-full-v1-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('pnpm-lock.yaml', 'pnpm-workspace.yaml', 'package.json') }}
97+
pnpm-${{ steps.pnpm_store.outputs.namespace }}-v1-${{ runner.os }}-${{ runner.arch }}-
6898
pnpm-full-v1-${{ runner.os }}-${{ runner.arch }}-
6999
100+
# pnpm accepts an earlier pass for the same lockfile and policy at any age, so
101+
# a cached record skips fetching registry metadata for every package.
102+
- name: Restore lockfile verification
103+
id: pnpm_verified
104+
if: inputs.install == 'true'
105+
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
106+
with:
107+
path: ${{ steps.pnpm_store.outputs.verified }}
108+
key: pnpm-verified-v1-${{ hashFiles('pnpm-lock.yaml', 'pnpm-workspace.yaml', 'package.json') }}
109+
70110
- name: Install dependencies
111+
if: inputs.install == 'true'
71112
shell: bash
72-
run: vp install
113+
env:
114+
INSTALL_ARGS: ${{ inputs.install-args }}
115+
# Unquoted so each filter is its own argument.
116+
run: vp install $INSTALL_ARGS
117+
118+
- name: Save lockfile verification
119+
if: inputs.install == 'true' && steps.pnpm_verified.outputs.cache-hit != 'true'
120+
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
121+
with:
122+
path: ${{ steps.pnpm_store.outputs.verified }}
123+
key: ${{ steps.pnpm_verified.outputs.cache-primary-key }}
124+
125+
# A filtered install that started from the current full store adds nothing
126+
# worth a second copy of it.
127+
- name: Save pnpm store
128+
if: >-
129+
inputs.install == 'true' &&
130+
steps.pnpm_cache.outputs.cache-hit != 'true' &&
131+
(steps.pnpm_store.outputs.namespace == 'full' ||
132+
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')))
133+
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
134+
with:
135+
path: ${{ steps.pnpm_store.outputs.path }}
136+
key: ${{ steps.pnpm_cache.outputs.cache-primary-key }}
73137

74138
- name: Enable shared task cache
75139
if: >-

‎.github/workflows/agent-context-budget.yml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,5 +51,5 @@ jobs:
5151
echo "Accepted by the agent-context-increase label."
5252
exit 0
5353
fi
54-
echo "::error file=$BUDGET::Agent context grew compared to main. Cut the added text, or ask a maintainer to add the agent-context-increase label."
54+
echo "::error file=$BUDGET::Agent context grew compared to main. Cut the added text and rerun the evals that cover it (evals/README.md), or ask a maintainer to add the agent-context-increase label."
5555
exit 1

‎.github/workflows/ci.yml‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,9 @@ jobs:
354354
id-token: write
355355
name: Test Server ${{ matrix.shard }}
356356
runs-on: blacksmith-4vcpu-ubuntu-2404
357-
timeout-minutes: 10
357+
# Shards take 2-5 minutes. When the shared task cache throttles reads, each
358+
# failed fetch stalls vp for 15-90s, which pushed shards past 10 minutes.
359+
timeout-minutes: 20
358360
strategy:
359361
fail-fast: false
360362
matrix:

‎.github/workflows/deploy-relay.yml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ jobs:
8080
CLERK_SECRET_KEY: ${{ secrets.CLERK_SECRET_KEY }}
8181
APNS_PRIVATE_KEY: ${{ secrets.APNS_PRIVATE_KEY }}
8282
FCM_SERVICE_ACCOUNT: ${{ secrets.FCM_SERVICE_ACCOUNT }}
83+
T3CHAT_LINK_SECRET: ${{ secrets.T3CHAT_LINK_SECRET }}
8384

8485
- name: Publish relay deploy commit status
8586
uses: actions/github-script@v8

‎.github/workflows/desktop-macos-preview-publish.yml‎

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -77,16 +77,19 @@ jobs:
7777
return;
7878
}
7979
80-
// workflow_run.pull_requests is empty for fork PRs, so resolve the
81-
// PR from the built commit instead and require exactly one open PR
82-
// from the same head repository and branch. The build baked its
80+
// workflow_run.pull_requests and the commit-to-PR lookup are both
81+
// empty for fork PRs, so list open PRs by head owner and branch
82+
// and require exactly one at the built commit. The build baked its
8383
// PR number into the version, so two candidates would mean the
8484
// asset name could belong to either.
85-
const associated = await github.paginate(
86-
github.rest.repos.listPullRequestsAssociatedWithCommit,
87-
{ owner, repo, commit_sha: run.head_sha, per_page: 100 },
88-
);
89-
const matching = associated.filter(
85+
const open = await github.paginate(github.rest.pulls.list, {
86+
owner,
87+
repo,
88+
state: "open",
89+
head: `${run.head_repository?.owner?.login}:${run.head_branch}`,
90+
per_page: 100,
91+
});
92+
const matching = open.filter(
9093
(candidate) =>
9194
candidate.state === "open" &&
9295
candidate.head.sha === run.head_sha &&
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
name: Mobile EAS Preview (Fork)
2+
3+
# EAS previews for fork PRs. This runs the PR's code with an Expo token: the
4+
# app config and plugins run on this runner, and native builds run on EAS
5+
# with preview signing credentials. The label is the maintainer's sign-off
6+
# that they reviewed that code, so it covers exactly the commit it was applied
7+
# to: this pins that commit and consumes the label before running anything. A
8+
# later push deploys nothing until the label is applied again.
9+
#
10+
# Same-repo PRs deploy on every push while labeled, via mobile-eas-preview.yml.
11+
12+
on:
13+
pull_request_target:
14+
types: [labeled]
15+
16+
permissions:
17+
contents: read
18+
19+
jobs:
20+
preview:
21+
name: EAS Preview
22+
if: >-
23+
github.event.pull_request.head.repo.full_name != github.repository &&
24+
github.event.label.name == '🚀 Mobile Continuous Deployment'
25+
runs-on: blacksmith-8vcpu-ubuntu-2404
26+
concurrency:
27+
group: mobile-eas-preview-fork-${{ github.event.pull_request.number }}
28+
cancel-in-progress: true
29+
permissions:
30+
contents: read
31+
pull-requests: write
32+
env:
33+
APP_VARIANT: preview
34+
NODE_OPTIONS: --max-old-space-size=8192
35+
MOBILE_VERSION_POLICY: fingerprint
36+
steps:
37+
# If a maintainer removed the label first, that removal wins.
38+
- id: consume
39+
name: Consume the deployment label
40+
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
41+
with:
42+
script: |
43+
try {
44+
await github.rest.issues.removeLabel({
45+
owner: context.repo.owner,
46+
repo: context.repo.repo,
47+
issue_number: context.payload.pull_request.number,
48+
name: context.payload.label.name,
49+
});
50+
core.setOutput("consumed", "true");
51+
} catch (error) {
52+
if (error.status !== 404) throw error;
53+
core.info("The label was removed before this run could consume it. Skipping.");
54+
core.setOutput("consumed", "false");
55+
}
56+
57+
- id: expo-token
58+
name: Check for EXPO_PREVIEW_TOKEN
59+
if: steps.consume.outputs.consumed == 'true'
60+
env:
61+
EXPO_TOKEN: ${{ secrets.EXPO_PREVIEW_TOKEN }}
62+
run: |
63+
if [ -n "$EXPO_TOKEN" ]; then
64+
echo "present=true" >> "$GITHUB_OUTPUT"
65+
else
66+
echo "present=false" >> "$GITHUB_OUTPUT"
67+
echo "EXPO_PREVIEW_TOKEN is not set; skipping EAS preview."
68+
fi
69+
70+
# The head SHA from the label event, not the branch, so a push after the
71+
# label cannot swap in unreviewed code. No credentials stay in .git for
72+
# the PR's scripts to read.
73+
- name: Checkout reviewed commit
74+
if: steps.expo-token.outputs.present == 'true'
75+
uses: actions/checkout@v6
76+
with:
77+
ref: ${{ github.event.pull_request.head.sha }}
78+
fetch-depth: 0
79+
persist-credentials: false
80+
# No sparse-checkout: see mobile-eas-preview.yml.
81+
82+
# No caches: pull_request_target saves them under main's scope, where
83+
# trusted workflows with other secrets would restore what PR code wrote.
84+
- name: Setup Vite+
85+
if: steps.expo-token.outputs.present == 'true'
86+
uses: voidzero-dev/setup-vp@v1
87+
with:
88+
node-version-file: package.json
89+
cache: false
90+
run-install: |
91+
args:
92+
- --filter=@t3tools/mobile...
93+
94+
- name: Expose pnpm
95+
if: steps.expo-token.outputs.present == 'true'
96+
run: |
97+
pnpm_version="$(node --print "require('./package.json').packageManager.split('@').pop()")"
98+
vp_pnpm_bin="$HOME/.vite-plus/package_manager/pnpm/$pnpm_version/pnpm/bin"
99+
echo "$vp_pnpm_bin" >> "$GITHUB_PATH"
100+
"$vp_pnpm_bin/pnpm" --version
101+
102+
- name: Setup EAS
103+
if: steps.expo-token.outputs.present == 'true'
104+
uses: expo/expo-github-action@v8
105+
with:
106+
# Pinned and installed with npm for the same reasons as mobile-eas-preview.yml.
107+
eas-version: 21.8.0
108+
eas-cache: false
109+
token: ${{ secrets.EXPO_PREVIEW_TOKEN }}
110+
packager: npm
111+
112+
- name: Pull preview environment variables
113+
if: steps.expo-token.outputs.present == 'true'
114+
working-directory: apps/mobile
115+
env:
116+
EXPO_TOKEN: ${{ secrets.EXPO_PREVIEW_TOKEN }}
117+
run: |
118+
eas env:pull preview --non-interactive
119+
# See mobile-eas-preview.yml: keeps Android build and OTA fingerprints matching.
120+
node --input-type=module <<'NODE'
121+
import { appendFileSync, readFileSync } from "node:fs";
122+
import { parseEnv } from "node:util";
123+
const env = parseEnv(readFileSync(".env.local", "utf8"));
124+
const googleServicesFile = env.T3CODE_ANDROID_GOOGLE_SERVICES_FILE;
125+
if (googleServicesFile) {
126+
appendFileSync(process.env.GITHUB_ENV, `T3CODE_ANDROID_GOOGLE_SERVICES_FILE=${googleServicesFile}\n`);
127+
}
128+
NODE
129+
130+
- name: Deploy with fingerprint check
131+
if: steps.expo-token.outputs.present == 'true'
132+
uses: expo/expo-github-action/continuous-deploy-fingerprint@main
133+
env:
134+
EXPO_TOKEN: ${{ secrets.EXPO_PREVIEW_TOKEN }}
135+
RUNNER_DEBUG: "1"
136+
# The action only comments for pull_request events; this hook gives
137+
# it the PR under pull_request_target. Without it, it skips the comment.
138+
EXPO_TEST_GITHUB_PULL: ${{ github.event.pull_request.number }}
139+
with:
140+
profile: preview:dev
141+
branch: pr-${{ github.event.pull_request.number }}
142+
platform: all
143+
environment: preview
144+
working-directory: apps/mobile
145+
github-token: ${{ secrets.GITHUB_TOKEN }}

0 commit comments

Comments
 (0)