Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
283 commits
Select commit Hold shift + click to select a range
4539e77
perf(web): the HTML render frame compiles without manual memoization …
juliusmarminge Oct 17, 2026
9e88a4f
perf(web): the sidebar update capsule compiles without manual memoiza…
juliusmarminge Oct 17, 2026
3c6df71
perf(web): the terminal session hooks compile without manual memoizat…
juliusmarminge Oct 17, 2026
6ad62b8
perf(web): the project file picker compiles without manual memoizatio…
juliusmarminge Oct 17, 2026
72b3340
perf(web): the sidebar chrome compiles without manual memoization (#2…
juliusmarminge Oct 17, 2026
41edad8
perf(web): the file context menu hooks compile without manual memoiza…
juliusmarminge Oct 17, 2026
2ff8e74
perf(web): the snapshot shortcut recorder compiles without manual mem…
juliusmarminge Oct 17, 2026
2a337fe
perf(web): the pull request linking hook compiles without manual memo…
juliusmarminge Oct 17, 2026
66eee62
perf(web): the port discovery hooks compile without manual memoizatio…
juliusmarminge Oct 17, 2026
dc060b1
perf(web): the new-thread link route compiles without manual memoizat…
juliusmarminge Oct 17, 2026
2643821
perf(web): the Electron browser host compiles with the React Compiler…
juliusmarminge Oct 17, 2026
d859445
perf(web): the CSV table preview compiles without manual memoization …
juliusmarminge Oct 17, 2026
8e49f23
perf(web): the thread lineage panel compiles without manual memoizati…
juliusmarminge Oct 17, 2026
de9756a
perf(web): the open panel pull request URL hook compiles without manu…
juliusmarminge Oct 17, 2026
cba00ae
perf(web): highlighted code tokens compile without manual memoization…
juliusmarminge Oct 17, 2026
383d8cc
perf(web): scoped settings hooks compile without manual memoization (…
juliusmarminge Oct 17, 2026
c5310c2
perf(web): the HTML document frame compiles without manual memoizatio…
juliusmarminge Oct 17, 2026
36c1fe5
perf(web): the new project hook compiles without manual memoization (…
juliusmarminge Oct 17, 2026
165fa98
perf(web): the scratch project hook compiles without manual memoizati…
juliusmarminge Oct 17, 2026
92b8967
perf(web): the expanded image dialog compiles without manual memoizat…
juliusmarminge Oct 17, 2026
d209e56
perf(web): the sidebar project groups hook compiles without manual me…
juliusmarminge Oct 17, 2026
9439b1a
perf(web): review file patches compile without manual memoization (#2…
juliusmarminge Oct 17, 2026
436ff01
perf(web): the draft hero headline compiles without manual memoizatio…
juliusmarminge Oct 17, 2026
3f5c16f
perf(web): settings project groups compile without manual memoization…
juliusmarminge Oct 17, 2026
3ba121e
perf(web): the chat route layout compiles without manual memoization …
juliusmarminge Oct 17, 2026
aca2b2a
perf(web): scoped model availability compiles without manual memoizat…
juliusmarminge Oct 17, 2026
e3a578f
perf(web): the environment hooks compile without manual memoization (…
juliusmarminge Oct 17, 2026
11f6676
perf(web): the provider settings panel compiles with the React Compil…
juliusmarminge Oct 17, 2026
15a8774
perf(web): the code block language picker compiles without manual mem…
juliusmarminge Oct 17, 2026
afb8da0
perf(web): the right panel tabs compile with the React Compiler (#20662)
juliusmarminge Oct 17, 2026
934398b
perf(web): settings search availability compiles without manual memoi…
juliusmarminge Oct 17, 2026
37db94e
perf(web): the editor preference hooks compile without manual memoiza…
juliusmarminge Oct 17, 2026
99fac26
perf(web): the code view file reveal hook compiles without manual mem…
juliusmarminge Oct 17, 2026
35548e2
perf(web): the command output panel compiles without manual memoizati…
juliusmarminge Oct 17, 2026
65d352e
perf(web): the annotatable diff view compiles without manual memoizat…
juliusmarminge Oct 17, 2026
4a9516d
perf(web): the chat header compiles with the React Compiler (#20656)
juliusmarminge Oct 17, 2026
a9fb608
perf(web): the theme library compiles with the React Compiler (#20655)
juliusmarminge Oct 17, 2026
4e8c01c
perf(web): the chat canvas compiles without manual memoization (#20654)
juliusmarminge Oct 17, 2026
d42681d
perf(web): useResizableWidth compiles without manual memoization (#20…
juliusmarminge Oct 17, 2026
c7fe6d3
perf(web): device controls compile without manual memoization (#20652)
juliusmarminge Oct 17, 2026
ec9f8e8
perf(web): file breadcrumbs compile with the React Compiler (#20651)
juliusmarminge Oct 17, 2026
c8b3ebf
perf(web): the changed files tree compiles without manual memoization…
juliusmarminge Oct 17, 2026
db2d0eb
perf(web): the provider update dismissal hook compiles without manual…
juliusmarminge Oct 17, 2026
472a62a
perf(web): the sidebar primitives compile with the React Compiler (#2…
juliusmarminge Oct 17, 2026
9b62eae
perf(web): the settings layout compiles without manual memoization (#…
juliusmarminge Oct 17, 2026
0ed3ae8
perf(web): the remote open hook compiles without manual memoization (…
juliusmarminge Oct 17, 2026
9578a59
perf(web): usePreviewBridge compiles with the React Compiler (#20644)
juliusmarminge Oct 17, 2026
b6dde72
perf(web): the citation chip compiles without manual memoization (#20…
juliusmarminge Oct 17, 2026
f63f026
perf(web): useHtmlRenderTheme compiles without manual memoization (#2…
juliusmarminge Oct 17, 2026
f22415a
perf(web): project content search compiles with the React Compiler (#…
juliusmarminge Oct 17, 2026
6a0587c
perf(web): the agent connect surface compiles without manual memoizat…
juliusmarminge Oct 17, 2026
0fdbb37
perf(web): the theme editor host compiles without manual memoization …
juliusmarminge Oct 17, 2026
478b06c
perf(web): the first-run gate compiles with the React Compiler (#20637)
juliusmarminge Oct 17, 2026
e6a1260
perf(web): the settings scope context compiles without manual memoiza…
juliusmarminge Oct 17, 2026
f99d12b
perf(web): the worktree base branch picker compiles without manual me…
juliusmarminge Oct 17, 2026
452d032
perf(web): the project file scripts hook compiles without manual memo…
juliusmarminge Oct 17, 2026
1b41060
perf(web): the diff file tree compiles with the React Compiler (#20631)
juliusmarminge Oct 17, 2026
d4c49bd
perf(web): thread status indicators compile without manual memoizatio…
juliusmarminge Oct 17, 2026
e544a4a
perf(web): useMediaQuery compiles without manual memoization (#20629)
juliusmarminge Oct 17, 2026
0b0f4db
perf(web): the source control settings compile with the React Compile…
juliusmarminge Oct 17, 2026
ef643a3
perf(web): scheduled task settings compile without manual memoization…
juliusmarminge Oct 17, 2026
530d119
perf(web): the remove-cloned-project hook compiles without manual mem…
juliusmarminge Oct 17, 2026
145b154
perf(web): resource telemetry diagnostics compile without manual memo…
juliusmarminge Oct 17, 2026
e36d0b2
perf(web): the archived threads hook compiles without manual memoizat…
juliusmarminge Oct 17, 2026
ecb973a
perf(web): the Connect onboarding dialog compiles with the React Comp…
juliusmarminge Oct 17, 2026
99544c9
perf(web): redacted sensitive text compiles without manual memoizatio…
juliusmarminge Oct 17, 2026
a9c0bb6
perf(web): the pull request stack hook compiles without manual memoiz…
juliusmarminge Oct 17, 2026
f241e79
perf(web): the resource telemetry hook compiles without manual memoiz…
juliusmarminge Oct 17, 2026
a37e0f3
perf(web): the provider settings form compiles without manual memoiza…
juliusmarminge Oct 17, 2026
a4f6caf
perf(web): the provider models section compiles with the React Compil…
juliusmarminge Oct 17, 2026
1b13922
perf(web): the CLI authorize surface compiles without manual memoizat…
juliusmarminge Oct 17, 2026
d6df197
perf(web): the pull request thread dialog compiles without manual mem…
juliusmarminge Oct 17, 2026
3f60d4d
perf(web): the assistant citation target hook compiles with the React…
juliusmarminge Oct 17, 2026
54d0900
perf(web): the device state hooks compile without manual memoization …
juliusmarminge Oct 17, 2026
a8dcb96
perf(web): the provider accent color picker compiles without manual m…
juliusmarminge Oct 17, 2026
e08b38a
perf(web): the T3 Connect account pages hook compiles without manual …
juliusmarminge Oct 17, 2026
97a9ca1
perf(web): the session scope hooks compile without manual memoization…
juliusmarminge Oct 17, 2026
196950a
perf(web): the provider update notification compiles without manual m…
juliusmarminge Oct 17, 2026
89a24e8
perf(web): the open-source notices panel compiles with the React Comp…
juliusmarminge Oct 17, 2026
23d40e0
perf(web): the project icon picker compiles without manual memoizatio…
juliusmarminge Oct 17, 2026
41f56d9
perf(web): the project scans hook compiles without manual memoization…
juliusmarminge Oct 17, 2026
54b1915
perf(web): the thread context drop hook compiles with the React Compi…
juliusmarminge Oct 17, 2026
2182353
perf(web): the local provider update groups compile without manual me…
juliusmarminge Oct 17, 2026
ed16d9f
perf(web): thread find navigation compiles without manual memoization…
juliusmarminge Oct 17, 2026
7591b64
perf(web): the font previews compile with the React Compiler (#20601)
juliusmarminge Oct 17, 2026
c36880e
perf(web): project actions settings compile without manual memoizatio…
juliusmarminge Oct 17, 2026
0b110ce
perf(web): the thread find bar compiles with the React Compiler (#20600)
juliusmarminge Oct 17, 2026
dec20ce
perf(web): the project scripts control compiles without manual memoiz…
juliusmarminge Oct 17, 2026
d915777
perf(web): keybindings settings compile without manual memoization (#…
juliusmarminge Oct 17, 2026
e648318
perf(web): the model picker sidebar compiles with the React Compiler …
juliusmarminge Oct 17, 2026
4c22df2
perf(web): the composer path search hook compiles without manual memo…
juliusmarminge Oct 17, 2026
855cd16
perf(web): the font picker compiles with the React Compiler (#20594)
juliusmarminge Oct 17, 2026
6515be7
perf(web): the project clone toasts compile without manual memoizatio…
juliusmarminge Oct 17, 2026
4e3f936
perf(web): the pending user input panel compiles with the React Compi…
juliusmarminge Oct 17, 2026
ed866ae
perf(web): useTurnDiffSummaries compiles without manual memoization (…
juliusmarminge Oct 17, 2026
789f605
perf(web): the provider update pill compiles with the React Compiler …
juliusmarminge Oct 17, 2026
d15f208
perf(web): the no-projects hero compiles without manual memoization (…
juliusmarminge Oct 17, 2026
567bc55
perf(web): useActiveThreadRef compiles without manual memoization (#2…
juliusmarminge Oct 17, 2026
54bffb9
perf(web): the custom model editor compiles without manual memoizatio…
juliusmarminge Oct 17, 2026
20851e3
perf(web): the root route compiles with the React Compiler (#20585)
juliusmarminge Oct 17, 2026
ede009e
perf(web): the diff worker pool provider compiles without manual memo…
juliusmarminge Oct 17, 2026
f0e060a
perf(web): the CLI command settings row compiles without manual memoi…
juliusmarminge Oct 17, 2026
6b563bb
perf(web): the composer banner stack compiles with the React Compiler…
juliusmarminge Oct 17, 2026
6f68d6d
perf(web): the primary session state hook compiles without manual mem…
juliusmarminge Oct 17, 2026
2814dc9
perf(web): the index route compiles with the React Compiler (#20580)
juliusmarminge Oct 17, 2026
6d22719
perf(web): the command palette results compile without manual memoiza…
juliusmarminge Oct 17, 2026
a793011
perf(web): the add provider dialog compiles without manual memoizatio…
juliusmarminge Oct 17, 2026
dd1ab3f
perf(web): useOrchestrationCommand compiles without manual memoizatio…
juliusmarminge Oct 17, 2026
2bb92ba
perf(web): the environment selector compiles without manual memoizati…
juliusmarminge Oct 17, 2026
9434bfd
perf(web): default theme adoption compiles with the React Compiler (#…
juliusmarminge Oct 17, 2026
745ca81
perf(web): useAtomQueryRunner compiles without manual memoization (#2…
juliusmarminge Oct 17, 2026
ef2d631
perf(web): the env mode selector compiles without manual memoization …
juliusmarminge Oct 17, 2026
242ec0e
perf(web): highlighted search lines compile without manual memoizatio…
juliusmarminge Oct 17, 2026
5069553
perf(web): the server update banner compiles without manual memoizati…
juliusmarminge Oct 17, 2026
8e6ace6
perf(web): the app sidebar layout compiles with the React Compiler (#…
juliusmarminge Oct 17, 2026
3ff9a73
perf(web): useAtomCommand compiles without manual memoization (#20568)
juliusmarminge Oct 17, 2026
7383cce
perf(web): the branch toolbar selector compiles without manual memoiz…
juliusmarminge Oct 17, 2026
95e6d92
perf(web): the composer state hooks compile without manual memoizatio…
juliusmarminge Oct 17, 2026
366106a
perf(web): the escape-to-go-back hook compiles without manual memoiza…
juliusmarminge Oct 17, 2026
63318a5
perf(web): the guide tour compiles without manual memoization (#20563)
juliusmarminge Oct 17, 2026
3603057
perf(web): the onboarding completion hook compiles without manual mem…
juliusmarminge Oct 17, 2026
1e42057
perf(web): the guide stop compiles without manual memoization (#20560)
juliusmarminge Oct 17, 2026
7492012
perf(web): the prompt link page compiles with the React Compiler (#20…
juliusmarminge Oct 17, 2026
095fdac
perf(web): the hosted browser webview compiles with the React Compile…
juliusmarminge Oct 17, 2026
78c0d7d
perf(web): the branch picker compiles without manual memoization (#20…
juliusmarminge Oct 17, 2026
7e850a0
perf(web): useStableCallback compiles without manual memoization (#20…
juliusmarminge Oct 17, 2026
fea5380
perf(web): the find reveal ref compiles without manual memoization (#…
juliusmarminge Oct 17, 2026
65ebf8f
perf(web): the primary cloud link hook compiles without manual memoiz…
juliusmarminge Oct 17, 2026
70d5cfb
perf(web): the project action editor resets its form without an effec…
juliusmarminge Oct 17, 2026
687f1e9
perf(web): the zoomable image compiles without manual memoization (#2…
juliusmarminge Oct 17, 2026
d94ea2c
perf(web): the PR guide diff loader compiles with the React Compiler …
juliusmarminge Oct 17, 2026
b78296a
perf(web): the traits picker compiles without manual memoization (#20…
juliusmarminge Oct 17, 2026
22585fd
perf(web): the managed relay hooks compile without manual memoization…
juliusmarminge Oct 17, 2026
b82d2e3
perf(web): the guide excerpt compiles without manual memoization (#20…
juliusmarminge Oct 17, 2026
16e6a6a
perf(web): AnimatedHeight compiles with the React Compiler (#20562)
juliusmarminge Oct 17, 2026
4576827
perf(web): the browser favicon store compiles without manual memoizat…
juliusmarminge Oct 17, 2026
7a08cdf
perf(web): the browser surface slot compiles with the React Compiler …
juliusmarminge Oct 17, 2026
8fcdcfe
perf(web): the link opener hook compiles without manual memoization (…
juliusmarminge Oct 17, 2026
02d48ae
perf(web): the guide file diff compiles without manual memoization (#…
juliusmarminge Oct 17, 2026
82f40d7
perf(web): the settings sidebar compiles with the React Compiler (#20…
juliusmarminge Oct 17, 2026
cffabdb
perf(web): Codex setup compiles with the React Compiler (#20674)
juliusmarminge Oct 17, 2026
fcda161
perf(web): chat markdown compiles with the React Compiler (#20715)
juliusmarminge Oct 17, 2026
2520821
perf(web): the device stream view compiles without manual memoization…
juliusmarminge Oct 17, 2026
33672c4
perf(web): the load-balancing hook compiles with the React Compiler (…
juliusmarminge Oct 17, 2026
a72b58e
fix(web): settings search keeps the clamped highlight when results sh…
juliusmarminge Oct 17, 2026
8254505
perf(web): the provider update launch notification compiles with the …
juliusmarminge Oct 17, 2026
0752826
perf(web): the model picker compiles without manual memoization (#20706)
juliusmarminge Oct 17, 2026
2993dfc
feat(web): step reasoning effort from the keyboard (#19928)
Bil0000 Oct 17, 2026
3ba883e
perf(web): the item inspector compiles without manual memoization (#2…
juliusmarminge Oct 17, 2026
e2e9b4d
fix(mobile): dev pairing link no longer opens Home inside a sheet (#2…
PixPMusic Oct 17, 2026
47683f6
fix(server): webhook request values reach the agent marked as request…
juliusmarminge Oct 17, 2026
c9b8f21
refactor(client-runtime): decide learned routes and session reuse in …
juliusmarminge Oct 17, 2026
bfe804d
refactor(web): thread find compiles under the strict React Compiler r…
juliusmarminge Oct 17, 2026
07fa354
test(web): chat markdown, timeline, and diff reveal tests pass the st…
juliusmarminge Oct 17, 2026
b38aa02
perf(web): Git actions control compiles without manual memoization (#…
juliusmarminge Oct 17, 2026
aa28bde
refactor(web): the theme search section compiles without manual memoi…
juliusmarminge Oct 17, 2026
8653c8f
fix(server): keep sensitive values out of settings reads, startup log…
juliusmarminge Oct 17, 2026
b3d0564
refactor(web): the thread pull requests panel keeps its caching witho…
juliusmarminge Oct 17, 2026
01e634a
refactor(web): scoped settings stay cached without "use memo" (#20767)
juliusmarminge Oct 17, 2026
68ed8d3
refactor(web): settings search items stay cached without "use memo" (…
juliusmarminge Oct 17, 2026
3af41ed
refactor(web): the file browser keeps its caching without "use memo" …
juliusmarminge Oct 17, 2026
341738b
refactor(web): the pull request stack hook keeps its caching without …
juliusmarminge Oct 17, 2026
0ad3fd6
refactor(web): the pull request thread dialog keeps its caching witho…
juliusmarminge Oct 17, 2026
37ea8a8
refactor(web): the MCP app frame keeps its caching without "use memo"…
juliusmarminge Oct 17, 2026
36cde6f
refactor(web): the changed files tree keeps its caching without "use …
juliusmarminge Oct 17, 2026
fc73c24
refactor(web): sidebar resize options stay cached without "use memo" …
juliusmarminge Oct 17, 2026
0a3806c
refactor(web): paginated branches keep their caching without "use mem…
juliusmarminge Oct 17, 2026
9554194
refactor(web): pull request markdown keeps its caching without "use m…
juliusmarminge Oct 17, 2026
4dd6a65
refactor(web): the pull request detail panel keeps its caching with f…
juliusmarminge Oct 17, 2026
64b16d8
refactor(web): the open panel pull request URL keeps its caching with…
juliusmarminge Oct 17, 2026
3b61890
refactor(web): the command output panel keeps its caching without "us…
juliusmarminge Oct 17, 2026
b7e376e
fix(client-runtime): the agents pill counts background agents from ea…
juliusmarminge Oct 17, 2026
c783897
refactor(web): the diff panel keeps its caching without "use memo" ho…
juliusmarminge Oct 17, 2026
d4314e8
refactor(web): the composer builds model options without a "use memo"…
juliusmarminge Oct 17, 2026
8dbfd92
refactor(web): the preview bridge keeps its stable thread ref without…
juliusmarminge Oct 17, 2026
ba9e9f5
refactor(web): the pull request code tab keeps its caching with one "…
juliusmarminge Oct 17, 2026
275e7de
refactor(web): provider models keep their caching without "use memo" …
juliusmarminge Oct 17, 2026
583ad66
refactor(web): the thread lineage panel keeps its caching without "us…
juliusmarminge Oct 17, 2026
3f480b8
refactor(web): the attachment preview keeps its caching without "use …
juliusmarminge Oct 17, 2026
4500480
refactor(web): the pending user input panel keeps its caching without…
juliusmarminge Oct 17, 2026
e6c0c5e
refactor(web): the queued runs control keeps its caching without "use…
juliusmarminge Oct 17, 2026
83ffe0a
refactor(web): the open-in picker keeps its caching without "use memo…
juliusmarminge Oct 17, 2026
a89a797
refactor(web): highlighted tokens keep their caching without "use mem…
juliusmarminge Oct 17, 2026
c0fda31
refactor(web): merged settings stay cached without "use memo" (#20765)
juliusmarminge Oct 17, 2026
edc703b
fix(server): a running Claude workflow member shows its answer so far…
juliusmarminge Oct 17, 2026
1e43699
refactor(web): the keybindings panel keeps its caching without "use m…
juliusmarminge Oct 17, 2026
bcd3c12
refactor(web): linked pull request status keeps its caching without "…
juliusmarminge Oct 17, 2026
af39520
refactor(web): the new-thread hook keeps its caching without "use mem…
juliusmarminge Oct 17, 2026
73af712
refactor(web): review file patches keep their caching without "use me…
juliusmarminge Oct 17, 2026
f4da080
chore(web): React compiler rules apply to every web file (#20791)
juliusmarminge Oct 17, 2026
8e0d5e5
refactor(server): resolve project and worktree folders in one place (…
juliusmarminge Oct 17, 2026
73d70a4
refactor(server): route git config through one env helper and end opt…
juliusmarminge Oct 17, 2026
144aae4
test(web): React tests run compiled in a real browser (#20797)
juliusmarminge Oct 17, 2026
23a5c77
fix(android): menu icons take taps (#20802)
juliusmarminge Oct 17, 2026
b987b57
fix(android): a composer focused through an app switch stays above th…
juliusmarminge Oct 17, 2026
b30f0df
refactor(web): the usage chart keeps its caching without "use memo" (…
juliusmarminge Oct 17, 2026
55ca0bb
refactor(web): pull request detail keeps its caching without "use mem…
juliusmarminge Oct 17, 2026
2c722ba
refactor(web): the legacy sidebar keeps its caching without "use memo…
juliusmarminge Oct 17, 2026
1c33a19
refactor(web): turn diff summaries keep their caching without "use me…
juliusmarminge Oct 17, 2026
805b98e
refactor(web): the pull requests page keeps its caching without "use …
juliusmarminge Oct 17, 2026
c60afa2
refactor(web): the terminal drawer keeps its caching without "use mem…
juliusmarminge Oct 17, 2026
44ecfd6
refactor(web): the model picker keeps its caching without "use memo" …
juliusmarminge Oct 17, 2026
78f8d38
refactor(web): pull request code tab keeps its caching without "use m…
juliusmarminge Oct 17, 2026
8eddd16
refactor(web): find reveal refs stay cached without "use memo" (#20818)
juliusmarminge Oct 17, 2026
767da3b
refactor(web): the branch selector keeps its caching without "use mem…
juliusmarminge Oct 17, 2026
efdaa4b
refactor(web): the guide excerpt keeps its caching without "use memo"…
juliusmarminge Oct 17, 2026
f9baf51
refactor(web): chat composer keeps its caching without "use memo" (#2…
juliusmarminge Oct 17, 2026
8c67f77
refactor(web): the usage page keeps its caching without "use memo" (#…
juliusmarminge Oct 17, 2026
f03378f
refactor(web): the hosted browser webview keeps its caching without "…
juliusmarminge Oct 17, 2026
e6ced71
refactor(web): the command palette provider lookup keeps its caching …
juliusmarminge Oct 17, 2026
2fbd431
chore(web): lint rejects "use memo" directives (#20843)
juliusmarminge Oct 17, 2026
2171c50
perf(web): relative "checked" labels re-render only when their text c…
juliusmarminge Oct 17, 2026
da0792e
perf(web): toggling a client setting no longer re-renders every setti…
juliusmarminge Oct 17, 2026
1994d63
perf(web): typing in the ACP registry search no longer re-renders eve…
juliusmarminge Oct 17, 2026
734e887
perf(web): searching keybindings only renders rows entering or leavin…
juliusmarminge Oct 17, 2026
74ca17b
perf(web): unchanged model picker rows skip re-rendering while search…
juliusmarminge Oct 17, 2026
489d08a
perf(web): router updates no longer re-render thread route consumers …
juliusmarminge Oct 17, 2026
130f4a2
perf(web): a minute tick no longer re-renders every sidebar thread ro…
juliusmarminge Oct 17, 2026
759f68f
test(web): jsdom-leftovers tests run in a real browser (#20862)
juliusmarminge Oct 17, 2026
e4fb9f2
test(web): hook-harness tests run in a real browser (#20866)
juliusmarminge Oct 17, 2026
a75a6d7
test(web): misc-b tests run in a real browser (#20869)
juliusmarminge Oct 17, 2026
476a010
test(web): settings tests run in a real browser (#20872)
juliusmarminge Oct 17, 2026
ecd95d5
test(web): misc-a tests run in a real browser (#20868)
juliusmarminge Oct 17, 2026
b827ca4
test(web): chat tests run in a real browser (#20870)
juliusmarminge Oct 17, 2026
89b42bf
test(web): browser tests from different checkouts no longer fight ove…
juliusmarminge Oct 17, 2026
52d593c
fix(web): chat view no longer renders twice per update (#20847)
juliusmarminge Oct 17, 2026
1d00edb
perf(web): markdown replies no longer re-render on reconnects and con…
juliusmarminge Oct 17, 2026
ecb938d
perf(web): provider status pushes no longer re-render every timeline …
juliusmarminge Oct 17, 2026
bc5f754
perf(client): a reconnect snapshot keeps unchanged skills and provide…
juliusmarminge Oct 17, 2026
5c8528f
perf(web): a client setting write only re-renders readers whose value…
juliusmarminge Oct 17, 2026
f96aebe
perf(web): right panel tabs no longer all re-render on unrelated chat…
juliusmarminge Oct 17, 2026
d56c479
perf(web): opening chat and usage dialogs no longer re-renders the wh…
juliusmarminge Oct 17, 2026
812b700
perf(web): typing in form dialogs no longer re-renders the dialog chr…
juliusmarminge Oct 17, 2026
87ce906
fix(web): a project action's error belongs to the request that opened…
juliusmarminge Oct 17, 2026
efef7cb
test(web): the open-in picker test waits for the menu to close (#20892)
juliusmarminge Oct 17, 2026
2fae0f9
perf(web): opening an image preview no longer re-renders the chat vie…
juliusmarminge Oct 17, 2026
edb2155
perf(web): another thread streaming no longer re-renders the app root…
juliusmarminge Oct 17, 2026
4d679a6
perf(client): equal query refetches no longer re-render PR rows (#20850)
juliusmarminge Oct 17, 2026
4a5dade
perf(client): provider status pushes no longer re-render environment …
juliusmarminge Oct 17, 2026
db5919d
perf(web): a provider status push no longer re-renders every provider…
juliusmarminge Oct 17, 2026
07680cf
test(web): onboarding and usage tests run in a real browser (#20902)
juliusmarminge Oct 17, 2026
c20eab4
test(web): pr-and-diff tests run in a real browser (#20901)
juliusmarminge Oct 17, 2026
da7c4f2
test(web): chat markdown and timeline tests run in a real browser (#2…
juliusmarminge Oct 17, 2026
133f57a
test(web): provider, usage and relationship tests run in a real brows…
juliusmarminge Oct 17, 2026
4b1024d
perf(web): the open thread's chat chrome no longer re-renders on ever…
juliusmarminge Oct 17, 2026
d5b7095
test(web): every React test runs in a real browser (#20944)
juliusmarminge Oct 17, 2026
25159b6
fix(release): release tests install Chromium for the web browser test…
juliusmarminge Oct 17, 2026
7e0418a
fix(server): drop V1 projections nothing reads after the V2 upgrade (…
juliusmarminge Oct 17, 2026
13aa882
feat(server): t3 doctor can delete the database from before 0.1.0 (#2…
juliusmarminge Oct 17, 2026
b99dcdf
chore: 🔀 merge upstream nightly v0.1.1-nightly.20261017.3272
chamaquita-d3[bot] Oct 17, 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
  •  
  •  
  •  
25 changes: 25 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,31 @@ jobs:
- name: Setup Vite+
uses: ./.github/actions/setup-ci-deps

# The browser project runs React tests in headless Chromium. Same cache key as
# test_server, so both jobs share one downloaded browser.
- name: Resolve Playwright version
id: playwright_version
run: echo "version=$(node -p "require('./apps/web/node_modules/playwright/package.json').version")" >> "$GITHUB_OUTPUT"

- name: Cache Chromium
id: chromium_cache
uses: actions/cache@v6
with:
path: ~/.cache/ms-playwright
key: playwright-chromium-shell-${{ runner.os }}-${{ runner.arch }}-${{ steps.playwright_version.outputs.version }}

- name: Install Chromium for web browser tests
if: steps.chromium_cache.outputs.cache-hit != 'true'
run: node apps/web/node_modules/playwright/cli.js install --only-shell chromium

- name: Install missing Chromium system dependencies
run: |
browser=$(find "$HOME/.cache/ms-playwright" -name chrome-headless-shell -type f -print -quit)
test -n "$browser"
if ldd "$browser" | grep '=> not found'; then
node apps/web/node_modules/playwright/cli.js install-deps chromium
fi

- name: Test
run: vp run --filter @t3tools/web test

Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,10 @@ jobs:
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
# The web package's browser project runs React tests in headless Chromium.
- name: Install Chromium for web browser tests
run: node apps/web/node_modules/playwright/cli.js install --with-deps --only-shell chromium

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,15 @@ final class T3SegmentedControlView: ExpoView {
}
}
var selectedIndex = -1 { didSet { updateSelection() } }
var trackColor: UIColor = .secondarySystemBackground { didSet { control.backgroundColor = trackColor } }
var selectedColor: UIColor = .secondarySystemFill { didSet { control.selectedSegmentTintColor = selectedColor } }
var textColor: UIColor = .label { didSet { updateColors() } }
var mutedColor: UIColor = .secondaryLabel { didSet { updateColors() } }
var trackColor: UIColor = .secondarySystemBackground { didSet { if trackColor != oldValue { control.backgroundColor = trackColor } } }
var selectedColor: UIColor = .secondarySystemFill { didSet { if selectedColor != oldValue { control.selectedSegmentTintColor = selectedColor } } }
var textColor: UIColor = .label { didSet { if textColor != oldValue { updateColors() } } }
var mutedColor: UIColor = .secondaryLabel { didSet { if mutedColor != oldValue { updateColors() } } }
var appearance = "light" {
didSet { overrideUserInterfaceStyle = appearance == "dark" ? .dark : .light }
didSet {
guard appearance != oldValue else { return }
overrideUserInterfaceStyle = appearance == "dark" ? .dark : .light
}
}

required init(appContext: AppContext? = nil) {
Expand All @@ -31,11 +34,20 @@ final class T3SegmentedControlView: ExpoView {

override func layoutSubviews() {
super.layoutSubviews()
control.frame = bounds
guard control.frame != bounds else { return }
UIView.performWithoutAnimation {
control.frame = bounds
}
}

private func updateSelection() {
control.selectedSegmentIndex = labels.indices.contains(selectedIndex) ? selectedIndex : UISegmentedControl.noSegment
let index = labels.indices.contains(selectedIndex) ? selectedIndex : UISegmentedControl.noSegment
// React echoes native selections while UIKit is still settling the glass lens.
guard control.selectedSegmentIndex != index else { return }
UIView.performWithoutAnimation {
control.selectedSegmentIndex = index
control.layoutIfNeeded()
}
}

private func updateColors() {
Expand Down
29 changes: 23 additions & 6 deletions apps/mobile/src/components/ui/MenuPopup.android.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,31 @@ import {
Text,
} from "@expo/ui/jetpack-compose";
import { defaultMinSize, padding, size, width } from "@expo/ui/jetpack-compose/modifiers";
import { View } from "react-native";
import { Pressable } from "react-native";
import { resolveScaledTextRole } from "../../lib/appearancePreferences";

import { useAndroidControlSizing } from "./useAndroidControlSizing";
import { useAppearancePreferences } from "../../features/settings/appearance/AppearancePreferencesProvider";
import type { MenuPopupProps } from "./MenuPopup";
import { isAppSymbolName, SymbolView, type AppSymbolName } from "./AppSymbol";

// The glyph is a React Native view hosted in the Compose row, and its native host consumes
// every touch over it, so the row's onClick never sees a tap on the icon. The glyph runs the
// row's action itself; the row stays the accessible element.
function MenuIcon(props: {
readonly name: AppSymbolName;
readonly onPress: () => void;
readonly destructive?: boolean;
readonly disabled?: boolean;
}) {
const { iconSize } = useAndroidControlSizing();
return (
<RNHostView matchContents modifiers={[size(iconSize, iconSize)]}>
<View
<Pressable
accessible={false}
focusable={false}
disabled={props.disabled}
onPress={props.onPress}
style={{ width: iconSize, height: iconSize }}
importantForAccessibility="no-hide-descendants"
>
Expand All @@ -40,7 +48,7 @@ function MenuIcon(props: {
: "accent-foreground"
}
/>
</View>
</Pressable>
</RNHostView>
);
}
Expand All @@ -60,7 +68,7 @@ export function MenuPopup(props: MenuPopupProps) {
{props.parent ? (
<DropdownMenuItem onClick={props.onBack} modifiers={itemModifiers}>
<DropdownMenuItem.LeadingIcon>
<MenuIcon name="arrow.left" />
<MenuIcon name="arrow.left" onPress={props.onBack} />
</DropdownMenuItem.LeadingIcon>
<DropdownMenuItem.Text>
<Text color={foreground} style={{ typography: "bodyLarge", ...body }}>
Expand Down Expand Up @@ -88,6 +96,7 @@ export function MenuPopup(props: MenuPopupProps) {
<DropdownMenuItem.LeadingIcon>
<MenuIcon
name={action.image}
onPress={() => props.onPress(action)}
destructive={action.attributes?.destructive}
disabled={action.attributes?.disabled}
/>
Expand Down Expand Up @@ -116,11 +125,19 @@ export function MenuPopup(props: MenuPopupProps) {
</DropdownMenuItem.Text>
{(action.subactions?.length ?? 0) > 0 ? (
<DropdownMenuItem.TrailingIcon>
<MenuIcon name="chevron.right" disabled={action.attributes?.disabled} />
<MenuIcon
name="chevron.right"
onPress={() => props.onPress(action)}
disabled={action.attributes?.disabled}
/>
</DropdownMenuItem.TrailingIcon>
) : action.state === "on" ? (
<DropdownMenuItem.TrailingIcon>
<MenuIcon name="checkmark" disabled={action.attributes?.disabled} />
<MenuIcon
name="checkmark"
onPress={() => props.onPress(action)}
disabled={action.attributes?.disabled}
/>
</DropdownMenuItem.TrailingIcon>
) : null}
</DropdownMenuItem>
Expand Down
6 changes: 3 additions & 3 deletions apps/mobile/src/components/ui/SegmentedControl.ios.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@ export function SegmentedControl<Value extends string | number>(
) {
const { colors, colorScheme } = useControlTheme();
const trackColor = flattenThemeColor(
themeColorWithAlpha(colors["--color-primary"], colorScheme === "dark" ? 0.18 : 0.07),
themeColorWithAlpha(colors["--color-prominent-action"], colorScheme === "dark" ? 0.18 : 0.07),
colors["--color-screen"],
);
const selectedColor =
colorScheme === "dark" ? colors["--color-primary"] : colors["--color-secondary"];
colorScheme === "dark" ? colors["--color-prominent-action"] : colors["--color-secondary"];
const selectedTextColor =
colorScheme === "dark"
? colors["--color-primary-foreground"]
? colors["--color-prominent-action-foreground"]
: colors["--color-secondary-foreground"];
return (
<View className={props.className}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ export function ConnectionsNewRouteScreen({
);

const connectAndClose = useCallback(
async (pairingUrl: string, replaceWithHome: boolean) => {
async (pairingUrl: string) => {
setIsSubmitting(true);
onChangeConnectionPairingUrl(pairingUrl);
try {
Expand All @@ -166,7 +166,9 @@ export function ConnectionsNewRouteScreen({
: Haptics.NotificationFeedbackType.Error,
);
if (AsyncResult.isSuccess(result)) {
if (replaceWithHome || !navigation.canGoBack()) {
// Return to whatever opened the sheet. Replacing it with Home would
// nest Home inside any sheet still below it.
if (!navigation.canGoBack()) {
navigation.dispatch(StackActions.replace("Home"));
} else {
navigation.goBack();
Expand All @@ -180,7 +182,7 @@ export function ConnectionsNewRouteScreen({
);

const handleSubmit = useCallback(async () => {
await connectAndClose(buildPairingUrl(hostInput, codeInput), false);
await connectAndClose(buildPairingUrl(hostInput, codeInput));
}, [codeInput, connectAndClose, hostInput]);

useEffect(() => {
Expand All @@ -189,7 +191,7 @@ export function ConnectionsNewRouteScreen({
}

attemptedAutoConnectRef.current = routePairingUrl;
void connectAndClose(routePairingUrl, true);
void connectAndClose(routePairingUrl);
}, [connectAndClose, routePairingUrl, shouldAutoConnect]);

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -685,7 +685,6 @@ export function PullRequestRouteScreen({ route }: StaticScreenProps<PullRequestP
>
<PullRequestIdentity pr={identity} params={params} />
<SegmentedControl
className={Platform.OS === "android" ? undefined : "bg-grouped-card"}
options={[
{ value: "overview", label: "Overview" },
...(guidesEnabled
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ import {
type AtomCommandResult,
} from "@t3tools/client-runtime/state/runtime";
import type { ProviderAuthResponse, ServerProvider } from "@t3tools/contracts";
import { useAtomValue } from "@effect/atom-react";
import { useRef, useState } from "react";
import { Linking, Pressable, ScrollView, TextInput, View } from "react-native";
import { useSafeAreaInsets } from "react-native-safe-area-context";

import { AppText as Text } from "../../components/ui/AppText";
import { ScreenScrollView } from "../../components/ui/ScreenScrollView";
import { environmentPresentations } from "../../state/presentation";
import { useEnvironmentQuery } from "../../state/query";
import { serverEnvironment } from "../../state/server";
import { useAtomCommand } from "../../state/use-atom-command";
Expand All @@ -25,6 +27,7 @@ import { useSettingsEnvironmentFilter, type SettingsTarget } from "./settings-en

export function SettingsProviderAccountsRouteScreen() {
const { selectedTargets } = useSettingsEnvironmentFilter();
const providersByEnvironment = useAtomValue(environmentPresentations.providersByEnvironmentAtom);
const insets = useSafeAreaInsets();
return (
<>
Expand All @@ -41,7 +44,7 @@ export function SettingsProviderAccountsRouteScreen() {
) : (
selectedTargets.map((environment) => (
<SettingsSection key={environment.environmentId} title={environment.label}>
{environment.serverConfig.providers
{(providersByEnvironment.get(environment.environmentId) ?? [])
.filter(
(provider) =>
provider.setup?.canAuthenticate ||
Expand All @@ -54,7 +57,7 @@ export function SettingsProviderAccountsRouteScreen() {
provider={provider}
/>
))}
{!environment.serverConfig.providers.some(
{!(providersByEnvironment.get(environment.environmentId) ?? []).some(
(provider) =>
provider.setup?.canAuthenticate ||
(provider.driver === "acpRegistry" && provider.installed),
Expand Down
20 changes: 17 additions & 3 deletions apps/mobile/src/features/threads/QuestionAttachments.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { convertPastedImagesToAttachments } from "../../lib/composerImages";
import { PROVIDER_SEND_TURN_MAX_ATTACHMENTS, type UserInputQuestion } from "@t3tools/contracts";
import { useAtomValue } from "@effect/atom-react";
import { View } from "react-native";
import { useEffect, useRef, useState } from "react";
import { useEffect, useEffectEvent, useRef, useState } from "react";
import { ComposerAttachmentButton } from "./ComposerAttachmentButton";
import { ComposerAttachmentStrip } from "../../components/ComposerAttachmentStrip";
import { pickComposerFiles, pickComposerMedia } from "../../lib/composerImages";
Expand Down Expand Up @@ -49,6 +49,14 @@ export function QuestionAttachments(props: {
props.requestId,
props.question.id,
]);
// A focused input that unmounts never delivers its onBlur, so release focus here or
// the screen would keep treating the keyboard as owned by a removed input.
const focusedRef = useRef(false);
const onInputFocusChange = props.onInputFocusChange;
const releaseFocus = useEffectEvent(() => {
if (focusedRef.current) onInputFocusChange?.(false);
});
useEffect(() => () => releaseFocus(), []);
const pickerScope = useRef<{ key: string; active: boolean } | null>(null);
useEffect(() => {
const scope = { key: scopeKey, active: true };
Expand Down Expand Up @@ -197,8 +205,14 @@ export function QuestionAttachments(props: {
submitBehavior={props.question.initialAnswer !== undefined ? "newline" : undefined}
editable={!props.disabled}
onChangeText={props.onChangeText}
onFocus={() => props.onInputFocusChange?.(true)}
onBlur={() => props.onInputFocusChange?.(false)}
onFocus={() => {
focusedRef.current = true;
onInputFocusChange?.(true);
}}
onBlur={() => {
focusedRef.current = false;
onInputFocusChange?.(false);
}}
placeholder="Or type a custom answer"
className="min-h-[54px] rounded-2xl border border-input-border bg-input px-3.5 py-3 font-sans text-base text-foreground"
/>
Expand Down
26 changes: 11 additions & 15 deletions apps/mobile/src/features/threads/ThreadDetailScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -360,26 +360,22 @@ export const ThreadDetailScreen = memo(function ThreadDetailScreen(props: Thread
const insets = useSafeAreaInsets();
const isKeyboardVisible = useKeyboardState((state) => state.isVisible);
const liveKeyboardHeight = useKeyboardState((state) => state.height);
// Android can swallow the IME hide callbacks when the app is backgrounded
// mid keyboard-hide (the reported repro: send — which blurs and starts the
// hide — then Home within a second). The keyboard library's height AND
// visibility then stay frozen open, so gating the sticky translation on
// visibility alone still strands the composer after resume. Quarantine the
// translation on every Android resume instead; any sign of a live keyboard
// stream — an owned input gaining focus, or any visibility/height movement —
// lifts it. A healthy resume sees no visual difference (the translation is
// already zero while the keyboard is closed). A composer that stayed focused
// keeps its keyboard: the microphone permission check pauses the activity
// mid-dictation, and quarantining then dropped the composer under the IME.
// Android can swallow the IME hide callbacks when the app is backgrounded mid keyboard-hide
// (the reported repro: send — which blurs and starts the hide — then Home within a second). The
// keyboard library's height AND visibility then stay frozen open, so gating the sticky
// translation on visibility alone still strands the composer after resume. An input that kept
// focus through the switch is exempt: Android restores its keyboard unchanged, so no keyboard
// or focus event would ever lift the quarantine. Hiding the keyboard with Back keeps focus, so
// Back then Home mid-hide takes the exemption and can still strand the composer.
const [keyboardStateSuspect, setKeyboardStateSuspect] = useState(false);
const composerFocusedRef = useRef(false);
const ownedInputFocusedRef = useRef(false);
useEffect(() => {
if (Platform.OS !== "android") {
return;
}
const subscription = AppState.addEventListener("change", (state) => {
if (state === "active" && !composerFocusedRef.current) {
setKeyboardStateSuspect(true);
if (state === "active") {
setKeyboardStateSuspect(!ownedInputFocusedRef.current);
}
});
return () => {
Expand All @@ -390,6 +386,7 @@ export const ThreadDetailScreen = memo(function ThreadDetailScreen(props: Thread
setKeyboardStateSuspect(false);
}, [isKeyboardVisible, liveKeyboardHeight]);
const handleOwnedInputFocusChange = useCallback((focused: boolean) => {
ownedInputFocusedRef.current = focused;
if (focused) {
setKeyboardStateSuspect(false);
}
Expand Down Expand Up @@ -429,7 +426,6 @@ export const ThreadDetailScreen = memo(function ThreadDetailScreen(props: Thread
const [composerFocused, setComposerFocused] = useState(false);
const handleComposerFocusChange = useCallback(
(focused: boolean) => {
composerFocusedRef.current = focused;
setComposerFocused(focused);
handleOwnedInputFocusChange(focused);
},
Expand Down
2 changes: 1 addition & 1 deletion apps/mobile/src/features/usage/ChatGptUsageSummary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export function ChatGptUsageSummary({
}: {
selectedEnvironmentIds: ReadonlySet<EnvironmentId> | null;
}) {
const presentations = useAtomValue(environmentPresentations.presentationsAtom);
const presentations = useAtomValue(environmentPresentations.presentationsWithProvidersAtom);
const selected =
selectedEnvironmentIds === null
? presentations
Expand Down
4 changes: 2 additions & 2 deletions apps/mobile/src/features/usage/UsageLimitsPooled.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ export function UsageLimitsSection({
readonly selectedEnvironmentIds: ReadonlySet<EnvironmentId> | null;
readonly cursorPrompt?: ReactNode;
}) {
const presentations = useAtomValue(environmentPresentations.presentationsAtom);
const presentations = useAtomValue(environmentPresentations.presentationsWithProvidersAtom);
const selected =
selectedEnvironmentIds === null
? presentations
Expand Down Expand Up @@ -345,7 +345,7 @@ type AccountScreenProps = StaticScreenProps<{

export function UsageLimitAccountScreen({ route }: AccountScreenProps) {
const insets = useSafeAreaInsets();
const presentations = useAtomValue(environmentPresentations.presentationsAtom);
const presentations = useAtomValue(environmentPresentations.presentationsWithProvidersAtom);
const { accountKey, windowId, windowKind, environmentIds, now } = route.params;
const selectedIds =
environmentIds === null ? null : new Set(environmentIds.map((id) => EnvironmentId.make(id)));
Expand Down
Loading
Loading