Repository navigation
merge: sync upstream main through 4c924ff4e6 #72
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
84 commits
Select commit
Hold shift + click to select a range
d0f7a50
feat(models): the model picker checks for new models when it opens (#…
t3dotgg 206a8e6
fix(desktop): close focused DevTools with Cmd+W (#33518)
Yash-Singh1 1676313
chore(mobile): update react-native-pdf-jsi to 6.1.0 and link it on An…
juliusmarminge 2da1b74
fix(mobile): the unfolded Duo sidebar no longer pops back in while re…
juliusmarminge eb6e7fa
fix(models): new models also surface the CLI update that supports the…
t3dotgg 6e4711d
fix(web): clicked workspace areas no longer show the focus ring after…
t3dotgg bf469bb
chore(server): update Claude Agent SDK to 0.3.321 (#33530)
t3dotgg e85e009
fix(web): checking for updates finds provider updates on every machin…
t3dotgg 8ab427c
fix(web): settings say custom instructions cover pull request descrip…
maria-rcks ad9e871
feat(web): send messages while attachments upload (#33092)
maria-rcks ff7aa5a
fix(mobile): Android PDF preview double-tap zoom and easier link taps…
juliusmarminge 3e4d449
chore(release): prepare v0.1.8
t3-code-bot[bot] dd0737d
feat: approve agent sign-ins with T3 Connect instead of a code (#33600)
juliusmarminge ee59ab2
fix(mobile): the composer and search bars move with their iOS columns…
juliusmarminge 9110dc2
ci(mobile): build Android store releases on Blacksmith (#33565)
juliusmarminge 45e0143
fix(web): thread title menu opens without a half-second wait on deskt…
t3dotgg b10cdde
fix(web): a new side chat focuses its message input (#32929)
darioielardi bbdc7dc
perf(opencode): bound usage reads to in-window messages (#33612)
Yash-Singh1 d655e2c
chore(web): upgrade @pierre/diffs to 1.7 and use its built-in find (#…
juliusmarminge e6fa2e3
fix(web): expanding hidden diff context works after a diff refresh (#…
juliusmarminge 9a0d027
feat: approve agent sign-ins on app.t3.codes with T3 Connect (#33632)
juliusmarminge 53bcb9a
perf(cursor): improve account usage scanning (#33636)
Yash-Singh1 ad98905
fix(web): dropdown items over the desktop title bar respond to clicks…
screen-gd eb381a7
fix: hosted agent approval no longer fails with "Your session cannot …
juliusmarminge 6f8c743
fix(web): new threads use the last used project
Yash-Singh1 f6a8a63
fix(mobile): distinguish local ACP instances by name (#32467)
shivamhwp 83862af
ci(mobile): dev clients build on Blacksmith, and mobile:install start…
juliusmarminge 9318fdb
fix(mobile): Android sidebar and composer transitions no longer reflo…
juliusmarminge 9a3f8db
fix(server): price Antigravity Gemini Flash effort variants (#13809)
Ephraim-9 5e59ece
fix(mobile): Android feed stays at its end after the keyboard or side…
juliusmarminge 12085f0
fix(server): Antigravity install no longer fails on a stale Windows C…
juliusmarminge b78c04d
ci(mobile): Android PR preview clients build on Blacksmith (#33618)
juliusmarminge 046efd7
fix(web): scrolling pans expanded images and Mermaid diagrams (#26630)
shivamhwp 5ae9578
fix(desktop): agents see visible:true while the desktop shows their t…
shivamhwp 0c83258
fix(server): allow requested WebMCP writes (#26570)
shivamhwp e2aa223
fix(antigravity): resolve model names from usage metadata (#33661)
Yash-Singh1 16a6c1c
fix(web): show details for background commands (#33647)
Yash-Singh1 f728112
fix(ci): store-build checkouts drop credentials without submodule cle…
juliusmarminge 8226715
fix(web): "Use T3 Code in another app" opens the Grok Bot app (#33663)
juliusmarminge 73fb49d
ci(mobile): keep the Android store AAB as a workflow artifact (#33674)
juliusmarminge 331889a
fix(mobile): hide compose in the detail rail while starting a task (#…
juliusmarminge d1909d6
chore(mobile): bump app version to 2.3.0
t3-code-bot[bot] 20bb685
ci(mobile): version bump commits no longer credit Codex (#33689)
juliusmarminge f6a32db
fix(server): stop PR watch flapping while workflows await approval (#…
shivamhwp e89abad
fix(server): show idle paragraphs before the assistant turn ends (#28…
shivamhwp 6c9adfb
fix(mobile): fit usage view selector beside the date range at large t…
PixPMusic 934c7f8
fix(web): center short PR titles in thread details (#33724)
Yash-Singh1 4c36119
fix(server): Claude threads can allow an MCP app for the session (#33…
t3dotgg 25da7eb
fix(web): reclaim notice says the machine will be offline (#33730)
shivamhwp 577c524
fix(server): detaching a session no longer strands its pending approv…
juliusmarminge eff4566
fix(opencode): long command turns no longer fail when the command req…
juliusmarminge 4168c14
fix(server): a queued message that names no model keeps the model pic…
juliusmarminge 4d9caf1
fix(ssh): tunnel readiness no longer counts ssh's connection time (#3…
juliusmarminge 4f57044
fix(server): preview_evaluate accepts top-level await (#31925)
juliusmarminge 5636b56
fix(server): quitting no longer restarts the relay client mid-shutdow…
juliusmarminge 9e12eca
fix(shared): relative Windows file links open the file (#33643)
juliusmarminge 8d54c8b
fix(server): a steer that restarts a completion wake no longer strand…
juliusmarminge 5dcf69e
fix(server): provider status checks no longer make mise download miss…
juliusmarminge b37c7f6
fix(forgejo): find merged pull requests whose head branch was deleted…
juliusmarminge 65ffcbf
perf(shared): speed up escaped Markdown in long PR descriptions (#33438)
AksharP5 cec8d73
fix(server): a background agent tab survives a desktop window reload …
juliusmarminge ad91636
fix(server): Commit, push & PR no longer pushes the default branch in…
juliusmarminge d47591f
fix(acp): OMP threads show html_render pages (#33677)
juliusmarminge 56064fc
fix(ssh): Intel Mac hosts no longer try to download a missing t3 arch…
juliusmarminge a22068f
fix(server): opening the branch menu no longer wipes PR status (#33263)
juliusmarminge 633438d
fix(server): failed updates report download diagnostics (#33239)
tanav29 e4d86ab
fix(web): remote Lineage rows keep their title when the environment n…
f4llenz 580503e
fix(web): custom snooze footer stays inside the dialog (#33759)
juliusmarminge 2922e8f
fix(desktop): right-clicking a mailto link offers Copy Email Address …
juliusmarminge 7171fdd
fix(acp-registry): commands past the 128th are no longer dropped (#33…
juliusmarminge f8fbc19
fix(server): one finished turn looks up its branch's pull request onc…
juliusmarminge ca796d5
fix(mobile): Android Files sheet scrolls its tree instead of dragging…
RadekManak b48b8ea
fix(web): prompt suggestions show after a steered turn (#33706)
thelogicmatrix 0ca73a1
fix(server): usage prices Claude Mythos 5.2 from its Bedrock rate (#3…
juliusmarminge bcee0f5
fix(server): Claude turns whose CLI exits before its first frame fail…
juliusmarminge fa2f4ff
fix(web): panel resize handles follow touch drags (#33066)
juliusmarminge feb9c6b
fix(server): signed-out Claude instances with their own config dir na…
juliusmarminge 61cb845
perf(server): opening a long thread reads from its latest segments, n…
t3dotgg d1aeed2
fix(server): repos without a remote no longer record failed spans on …
ferhtgoldaraz 5a9866d
fix(mobile): missing files in previews name the checked path instead …
juliusmarminge f12bb62
fix(server): a restart that misses its turn starts as a new turn (#32…
juliusmarminge 4c924ff
fix(desktop): new browser tabs no longer lose waits, clicks and snaps…
juliusmarminge 7114615
Merge upstream pingdotgg/t3code main through 4c924ff4e6 into fork
eyeveil 8932518
fix(client-runtime): environment requests keep the connection label f…
eyeveil File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,126 @@ | ||
| // The Android half of the mobile preview comment. The android job writes the fingerprint and | ||
| // the update; the android-build job adds the client's install link a few minutes later. Each | ||
| // run merges what it knows into the state kept in the comment's first line. | ||
| const MARKER = "mobile-preview-android"; | ||
| const PROJECT_ID = "d763fcb8-d37c-41ea-a773-b54a0ab4a454"; | ||
| const APP_SCHEME = "t3-code"; | ||
|
|
||
| function readState(body) { | ||
| const match = new RegExp(`^<!-- ${MARKER} (\\{.*\\}) -->`).exec(body ?? ""); | ||
| if (!match) return null; | ||
| try { | ||
| const state = JSON.parse(match[1]); | ||
| const text = (value) => (typeof value === "string" ? value : ""); | ||
| return { | ||
| fingerprint: text(state.fingerprint), | ||
| client: text(state.client), | ||
| group: text(state.group), | ||
| }; | ||
| } catch { | ||
| return null; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * New values win; a new fingerprint drops the old fingerprint's client. A build that finishes | ||
| * after the PR moved to another fingerprint changes nothing: its client cannot run the update | ||
| * the comment now shows. | ||
| */ | ||
| function mergeState(previous, next) { | ||
| const buildOnly = Boolean(next.client) && !next.group; | ||
| if ( | ||
| buildOnly && | ||
| previous?.fingerprint && | ||
| next.fingerprint && | ||
| previous.fingerprint !== next.fingerprint | ||
| ) { | ||
| return previous; | ||
| } | ||
| const fingerprint = next.fingerprint || previous?.fingerprint || ""; | ||
| const sameFingerprint = !previous?.fingerprint || previous.fingerprint === fingerprint; | ||
| return { | ||
| fingerprint, | ||
| client: next.client || (sameFingerprint ? (previous?.client ?? "") : ""), | ||
| group: next.group || previous?.group || "", | ||
| }; | ||
| } | ||
|
|
||
| function render(state, runUrl) { | ||
| const qr = `https://qr.expo.dev/eas-update?appScheme=${APP_SCHEME}&projectId=${PROJECT_ID}&groupId=${state.group}`; | ||
| const rows = [ | ||
| `<!-- ${MARKER} ${JSON.stringify(state)} -->`, | ||
| "🤖 Android preview", | ||
| "", | ||
| " | 🤖 Android", | ||
| "--- | ---", | ||
| `Fingerprint | ${state.fingerprint || "n/a"}`, | ||
| `Dev client | ${state.client ? `[Install](${state.client})` : `Building on Blacksmith ([run](${runUrl})); this comment gets the install link when it finishes`}`, | ||
| ]; | ||
| if (state.group) { | ||
| rows.push( | ||
| `Update Details | [Update Permalink](https://expo.dev/projects/${PROJECT_ID}/updates/${state.group})`, | ||
| `Update QR | <a href="${qr}"><img src="${qr}" width="250px" height="250px" /></a>`, | ||
| ); | ||
| } | ||
| return rows.join("\n"); | ||
| } | ||
|
|
||
| async function github(path, init = {}) { | ||
| const response = await fetch(`https://api.github.com${path}`, { | ||
| ...init, | ||
| headers: { | ||
| authorization: `Bearer ${process.env.GH_TOKEN}`, | ||
| accept: "application/vnd.github+json", | ||
| "content-type": "application/json", | ||
| ...init.headers, | ||
| }, | ||
| }); | ||
| if (!response.ok) { | ||
| throw new Error( | ||
| `GitHub ${init.method ?? "GET"} ${path}: ${response.status} ${await response.text()}`, | ||
| ); | ||
| } | ||
| return response.json(); | ||
| } | ||
|
|
||
| async function main() { | ||
| const repository = process.env.GITHUB_REPOSITORY; | ||
| const pr = process.env.PR; | ||
| if (!repository || !pr || !process.env.GH_TOKEN) { | ||
| throw new Error("GITHUB_REPOSITORY, PR and GH_TOKEN are required."); | ||
| } | ||
| const runUrl = `${process.env.GITHUB_SERVER_URL}/${repository}/actions/runs/${process.env.GITHUB_RUN_ID}`; | ||
| let existing = null; | ||
| for (let page = 1; existing === null; page++) { | ||
| const comments = await github( | ||
| `/repos/${repository}/issues/${pr}/comments?per_page=100&page=${page}`, | ||
| ); | ||
| // Only this workflow's own comment: anyone can post the marker, and nobody else's is editable. | ||
| existing = | ||
| comments.find( | ||
| (comment) => | ||
| comment.user?.login === "github-actions[bot]" && readState(comment.body) !== null, | ||
| ) ?? null; | ||
| if (comments.length < 100) break; | ||
| } | ||
| const state = mergeState(readState(existing?.body), { | ||
| fingerprint: process.env.FINGERPRINT ?? "", | ||
| client: process.env.CLIENT ?? "", | ||
| group: process.env.GROUP ?? "", | ||
| }); | ||
| const body = JSON.stringify({ body: render(state, runUrl) }); | ||
| if (existing) { | ||
| await github(`/repos/${repository}/issues/comments/${existing.id}`, { method: "PATCH", body }); | ||
| } else { | ||
| await github(`/repos/${repository}/issues/${pr}/comments`, { method: "POST", body }); | ||
| } | ||
| } | ||
|
|
||
| if (require.main === module) { | ||
| main().catch((error) => { | ||
| console.error(error); | ||
| process.exitCode = 1; | ||
| }); | ||
| } | ||
|
|
||
| module.exports = { mergeState, readState, render }; | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| const assert = require("node:assert/strict"); | ||
| const test = require("node:test"); | ||
|
|
||
| const { mergeState, readState, render } = require("./mobile-preview-comment.cjs"); | ||
|
|
||
| const fingerprint = "c31608b37a8a2dca35ccee39cfd2ec7305042629"; | ||
| const run = "https://github.com/pingdotgg/t3code/actions/runs/1"; | ||
|
|
||
| test("the comment round-trips its state", () => { | ||
| const state = { fingerprint, client: "", group: "8e413a0a" }; | ||
| const body = render(state, run); | ||
| assert.deepEqual(readState(body), state); | ||
| assert.match( | ||
| body, | ||
| /Building on Blacksmith \(\[run\]\(https:\/\/github\.com\/pingdotgg\/t3code\/actions\/runs\/1\)\)/, | ||
| ); | ||
| assert.match( | ||
| body, | ||
| /qr\.expo\.dev\/eas-update\?appScheme=t3-code&projectId=[0-9a-f-]+&groupId=8e413a0a/, | ||
| ); | ||
| assert.equal(readState("🚀 Expo continuous deployment is ready!"), null); | ||
| }); | ||
|
|
||
| test("the build job adds the install link without losing the update", () => { | ||
| const first = mergeState(null, { fingerprint, client: "", group: "8e413a0a" }); | ||
| const built = mergeState(first, { fingerprint, client: "https://expo.dev/a/b", group: "" }); | ||
| assert.deepEqual(built, { fingerprint, client: "https://expo.dev/a/b", group: "8e413a0a" }); | ||
| assert.match(render(built, run), /Dev client \| \[Install\]\(https:\/\/expo\.dev\/a\/b\)/); | ||
| }); | ||
|
|
||
| test("a new fingerprint drops the old client; the same one keeps it", () => { | ||
| const built = { fingerprint, client: "https://expo.dev/a/b", group: "old" }; | ||
| assert.deepEqual(mergeState(built, { fingerprint, client: "", group: "new" }), { | ||
| fingerprint, | ||
| client: "https://expo.dev/a/b", | ||
| group: "new", | ||
| }); | ||
| assert.deepEqual(mergeState(built, { fingerprint: "f".repeat(40), client: "", group: "new" }), { | ||
| fingerprint: "f".repeat(40), | ||
| client: "", | ||
| group: "new", | ||
| }); | ||
| }); | ||
|
|
||
| test("a build that finishes after the PR moved to another fingerprint changes nothing", () => { | ||
| const current = { fingerprint: "f".repeat(40), client: "", group: "new" }; | ||
| assert.deepEqual( | ||
| mergeState(current, { fingerprint, client: "https://expo.dev/a/b", group: "" }), | ||
| current, | ||
| ); | ||
| }); | ||
|
|
||
| test("state from the comment is always three strings", () => { | ||
| assert.deepEqual( | ||
| readState('<!-- mobile-preview-android {"fingerprint":5,"client":null} -->\nx'), | ||
| { | ||
| fingerprint: "", | ||
| client: "", | ||
| group: "", | ||
| }, | ||
| ); | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On consecutive pushes with the same native fingerprint, an earlier Android build can finish while the newer update job writes its comment. Both writers read the old body and replace the whole comment. The last write can restore the older update QR or erase the finished client's install link. Serialize comment writes per PR so each merge reads the previous writer's result.
Prompt To Fix With AI
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note
Written by
claude-opus-5-5on behalf of eyeveilNot fixing this here.
.github/scripts/mobile-preview-comment.cjsis identical to upstream4c924ff4e6d, and on this fork the jobs that write that comment never run. Same-repo PR previews useMobile EAS Preview, which is disabled on issuelt/t3code.Mobile EAS Preview (Fork)runs only for labeled PRs from other repositories. If the race matters, the fix belongs upstream, where those workflows run.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair point that this is an upstream-only sync and a fork-specific fix would create divergence. One qualification: the workflow definitions still include comment writers for labeled external PRs in
mobile-eas-preview-fork.yml; itsandroid-buildcan outlive the preview job, so a later labeled run could overlap it. Andmobile-eas-preview.ymlis not disabled in its YAML—the job condition permits same-repo labeled PRs (though repository settings may disable it).So I agree this needn’t be fixed in this sync, but I wouldn’t conclude the race is impossible for the fork workflow. It’s best treated as an upstream-owned issue and addressed there, or tracked separately if that fork workflow is used.