Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
357 commits
Select commit Hold shift + click to select a range
6175acc
merge: reconcile plugin PR 16050 with current main
saphid Oct 19, 2026
7e9e7fe
merge: reconcile plugin PR 16051 with current main
saphid Oct 19, 2026
3bef9c6
chore: resolve #16041 conflicts with current main
saphid Oct 19, 2026
9d6c95a
chore: resolve #16045 conflicts with current main
saphid Oct 19, 2026
8be6c1b
chore: resolve #16046 conflicts with current main
saphid Oct 19, 2026
39e3f91
merge: integrate current main into panel host
saphid Oct 20, 2026
116c5b8
merge: integrate current main and migrate device panel coverage
saphid Oct 20, 2026
9bdb7b9
merge: integrate current main into files panel
saphid Oct 20, 2026
304575b
fix(web): scope file open shortcuts to the active panel
saphid Oct 20, 2026
274afa0
merge: integrate current main into #16045
saphid Oct 20, 2026
c6559e0
fix(web): scope file open shortcuts to the active panel
saphid Oct 20, 2026
ed6ec16
test(web): supply the file browser composer action
saphid Oct 20, 2026
3e56355
merge: integrate current main into #16046
saphid Oct 20, 2026
7cca359
fix(web): scope file open shortcuts to the active panel
saphid Oct 20, 2026
8e387b4
test(web): supply the file browser composer action
saphid Oct 20, 2026
6461543
fix(mobile): keep browser controls below contribution statuses
saphid Oct 20, 2026
ed343be
merge: integrate current main into plugin host
saphid Oct 20, 2026
eb0af4b
fix(web): scope file open shortcuts to the active panel
saphid Oct 20, 2026
f492102
fix(mobile): keep browser controls below contribution statuses
saphid Oct 20, 2026
ecee4ae
fix(mobile): include status overlays in sent-message anchoring
saphid Oct 20, 2026
f109887
fix(web): retain device operation state for its starting thread
saphid Oct 20, 2026
9e66b60
test(server): provide plugins to config RPC integration
saphid Oct 20, 2026
614c4f2
merge: integrate current main into plugin events
saphid Oct 20, 2026
8f6fb77
fix(web): scope file open shortcuts to the active panel
saphid Oct 20, 2026
8ffd03d
fix(mobile): keep browser controls below contribution statuses
saphid Oct 20, 2026
8aac62c
fix(mobile): include status overlays in sent-message anchoring
saphid Oct 20, 2026
0e65401
test(server): provide plugins to config RPC integration
saphid Oct 20, 2026
0dcc5b4
merge: integrate current main into #16049
saphid Oct 20, 2026
176e6c3
fix(web): scope file open shortcuts to the active panel
saphid Oct 20, 2026
ae01f73
fix(mobile): keep browser controls below contribution statuses
saphid Oct 20, 2026
c57260e
fix(mobile): include status overlays in sent-message anchoring
saphid Oct 20, 2026
6adc994
test(server): provide plugins to config RPC integration
saphid Oct 20, 2026
7cc224b
test(server): verify plugin grants reach the composed runtime
saphid Oct 20, 2026
119b576
merge: integrate current main into #16050
saphid Oct 20, 2026
1e3f457
fix(web): scope file open shortcuts to the active panel
saphid Oct 20, 2026
41d7242
fix(mobile): keep browser controls below contribution statuses
saphid Oct 20, 2026
25c0e76
fix(mobile): include status overlays in sent-message anchoring
saphid Oct 20, 2026
fcc1b22
test(server): provide plugins to config RPC integration
saphid Oct 20, 2026
aeab172
fix(clients): follow current panel and mobile module APIs
saphid Oct 20, 2026
618802f
test(server): verify plugin grants reach the composed runtime
saphid Oct 20, 2026
89eeb46
test(server): provide plugin settings to config RPC integration
saphid Oct 20, 2026
59b93e0
fix(server): preserve live secret writers during temporary cleanup
saphid Oct 20, 2026
d39875f
merge: preserve plugin settings alongside current main
saphid Oct 20, 2026
3621e50
fix(clients): preserve current panel tests and detail tabs
saphid Oct 20, 2026
2b5d254
fix(plugins): bound source traversal and preserve cancellation ownership
saphid Oct 20, 2026
be0b931
fix(web): default the registered pull request detail tab
saphid Oct 20, 2026
0cabfdc
test(plugins): synchronize the first persisted cursor reconciliation
saphid Oct 20, 2026
3e3282b
test(plugins): seed the persisted cursor timestamp
saphid Oct 20, 2026
a8a475b
style(plugins): name the event quarantine effect
saphid Oct 20, 2026
4ebc2b3
merge: propagate verified plugin settings repairs into actions
saphid Oct 20, 2026
127d23a
fix(clients): reject stale plugin actions and pin action subscriptions
saphid Oct 20, 2026
bd212ad
fix(mobile): validate the slash command trigger kind
saphid Oct 20, 2026
38b76c3
fix(runtime): retain the shared session pin for plugin action streams
saphid Oct 20, 2026
f48abd2
merge: preserve PR 15010 behavior on current main
saphid Oct 20, 2026
fadaff3
test(server): provide plugin actions at the config RPC boundary
saphid Oct 20, 2026
0ae5507
test(mobile): configure the plugin action hook environment
saphid Oct 20, 2026
cdaf638
merge: preserve panel host with current diff session behavior
saphid Oct 20, 2026
b006774
test(web): adapt current diff tests to the panel host
saphid Oct 20, 2026
1e261e2
merge: preserve device panel guards and current main test imports
saphid Oct 20, 2026
09aa8ca
merge: preserve files panels and current pull request identity
saphid Oct 20, 2026
f48f6d6
fix(web): import detail tab type from the panel store
saphid Oct 20, 2026
746f10d
fix(web): default registered pull request detail tab
saphid Oct 20, 2026
fecc4f1
merge: preserve contribution status and files regression coverage
saphid Oct 20, 2026
dd57467
merge: retain mobile status geometry with current panel foundations
saphid Oct 20, 2026
5665be2
merge: preserve plugin host and migrations after current main
saphid Oct 20, 2026
0e14003
fix(server): bound plugin source walks and protect supervisor handoffs
saphid Oct 20, 2026
b818ad5
merge: preserve plugin events and delegated completion transactions
saphid Oct 20, 2026
4876dfc
fix(server): reconcile persisted plugin event cursors
saphid Oct 20, 2026
5133ae4
refactor(server): keep event sink helpers under their operation spans
saphid Oct 20, 2026
08b7f23
merge: preserve plugin tool runtime and inherited event repairs
saphid Oct 20, 2026
edaf580
test(server): deduplicate runtime session import after main integration
saphid Oct 20, 2026
3ea0333
refactor(server): preserve plugin event sink operation tracing
saphid Oct 20, 2026
12ec158
refactor(server): preserve plugin event sink operation tracing
saphid Oct 20, 2026
4c09c75
fix(plugins): carry verified session and recovery repairs
saphid Oct 20, 2026
5cebb0c
fix(plugins): carry verified session and recovery repairs
saphid Oct 20, 2026
918e883
fix(plugins): carry verified session and recovery repairs
saphid Oct 20, 2026
e3db3e6
fix(plugins): carry verified session and recovery repairs
saphid Oct 20, 2026
52f6768
fix(plugins): carry verified session and recovery repairs
saphid Oct 20, 2026
94e8e62
fix(plugins): carry verified session and recovery repairs
saphid Oct 20, 2026
c043f6b
fix(plugins): carry verified session and recovery repairs
saphid Oct 20, 2026
995e4fc
fix(plugins): carry verified session and recovery repairs
saphid Oct 20, 2026
bf013c6
fix(plugins): carry verified session and recovery repairs
saphid Oct 20, 2026
e41dec0
fix(web): match registry fixtures to available panels
saphid Oct 20, 2026
4a62560
fix(plugins): carry verified session and recovery repairs
saphid Oct 20, 2026
0b48776
fix(web): supply the panel host in PR tab restoration test
saphid Oct 20, 2026
65a86e0
fix(web): supply the panel host in PR tab restoration test
saphid Oct 20, 2026
a03587c
fix(web): supply the panel host in PR tab restoration test
saphid Oct 20, 2026
42bac51
fix(web): supply the panel host in PR tab restoration test
saphid Oct 20, 2026
2da00e3
fix(web): supply the panel host in PR tab restoration test
saphid Oct 20, 2026
55c8d53
fix(web): supply the panel host in PR tab restoration test
saphid Oct 20, 2026
54042f1
fix(web): supply the panel host in PR tab restoration test
saphid Oct 20, 2026
aaec5c3
fix(web): supply the panel host in PR tab restoration test
saphid Oct 20, 2026
a7350b7
refactor(web): integrate panel host with main component boundaries
saphid Oct 23, 2026
192bc98
refactor(web): preserve device and terminal panels on current main
saphid Oct 23, 2026
040202c
fix(web): preserve scoped device operation errors across thread switches
saphid Oct 23, 2026
babbab1
refactor(web): integrate files and pull request panels with main
saphid Oct 23, 2026
eff86b0
chore(pi): integrate main while preserving extension statuses
saphid Oct 23, 2026
30dbe3f
chore(pi): preserve main blank-question validation in status stack
saphid Oct 23, 2026
c8294eb
chore(mobile): integrate main while preserving Pi status geometry
saphid Oct 23, 2026
29eca2a
fix(plugins): integrate main and preserve revocation and shutdown safety
saphid Oct 23, 2026
472b696
fix(plugins): integrate event feed with current persistence and outcomes
saphid Oct 23, 2026
aa0aefc
fix(plugins): integrate tool grants with current session lifecycle
saphid Oct 23, 2026
79ac3bc
fix(plugins): reconcile preview migrations and retain private setting…
saphid Oct 23, 2026
1d03951
fix(plugins): preserve actions across extracted composer entry points
saphid Oct 23, 2026
555e926
fix: integrate current main while preserving PR 15010 behavior
saphid Oct 23, 2026
e82f610
fix(plugins): repair current CI fixtures and preserve scoped behavior
saphid Oct 23, 2026
03a544e
fix(plugins): repair current CI fixtures and preserve scoped behavior
saphid Oct 23, 2026
7b3fcea
fix(plugins): repair current CI fixtures and preserve scoped behavior
saphid Oct 23, 2026
6433423
fix(plugins): repair current CI fixtures and preserve scoped behavior
saphid Oct 23, 2026
fa1404b
fix(plugins): repair current CI fixtures and preserve scoped behavior
saphid Oct 23, 2026
25f29b9
fix(plugins): repair current CI fixtures and preserve scoped behavior
saphid Oct 23, 2026
d3062cc
fix(plugins): repair current CI fixtures and preserve scoped behavior
saphid Oct 23, 2026
cf941d9
docs(plugins): describe persisted swap recovery accurately
saphid Oct 23, 2026
d95a5b7
docs(plugins): describe persisted swap recovery accurately
saphid Oct 23, 2026
7ad8af2
docs(plugins): describe persisted swap recovery accurately
saphid Oct 23, 2026
ab9055e
docs(plugins): describe persisted swap recovery accurately
saphid Oct 23, 2026
a8f4c62
docs(plugins): describe persisted swap recovery accurately
saphid Oct 23, 2026
83f31b0
fix(plugins): repair current CI fixtures and preserve scoped behavior
saphid Oct 23, 2026
753e629
fix(plugins): repair current CI fixtures and preserve scoped behavior
saphid Oct 23, 2026
c52345b
fix(web): align lazy panel fixtures with current runtime contracts
saphid Oct 23, 2026
b1af53d
fix(web): align lazy panel fixtures with current runtime contracts
saphid Oct 23, 2026
221c2c5
fix(web): align lazy panel fixtures with current runtime contracts
saphid Oct 23, 2026
5665e03
fix(web): align lazy panel fixtures with current runtime contracts
saphid Oct 23, 2026
87d37a3
fix(web): align lazy panel fixtures with current runtime contracts
saphid Oct 23, 2026
50dbc1b
fix(web): align lazy panel fixtures with current runtime contracts
saphid Oct 23, 2026
c6ddef4
fix(web): align lazy panel fixtures with current runtime contracts
saphid Oct 23, 2026
3bc1b4c
fix(web): align lazy panel fixtures with current runtime contracts
saphid Oct 23, 2026
78a6d79
fix(web): align lazy panel fixtures with current runtime contracts
saphid Oct 23, 2026
9c5651c
test(web): align plugin render lifecycle and available panel counters
saphid Oct 23, 2026
812bcf6
test(web): align plugin render lifecycle and available panel counters
saphid Oct 23, 2026
22002e4
test(web): align plugin render lifecycle and available panel counters
saphid Oct 23, 2026
ae72863
test(web): align plugin render lifecycle and available panel counters
saphid Oct 23, 2026
45d329b
test(web): align plugin render lifecycle and available panel counters
saphid Oct 23, 2026
a1c136e
test(web): align plugin render lifecycle and available panel counters
saphid Oct 23, 2026
f728641
test(web): align plugin render lifecycle and available panel counters
saphid Oct 23, 2026
f23aeac
test(web): align plugin render lifecycle and available panel counters
saphid Oct 23, 2026
b259d1e
test(web): align plugin render lifecycle and available panel counters
saphid Oct 23, 2026
1182393
Merge remote-tracking branch 'origin/main' into ready/plugins-15010-2…
saphid Oct 31, 2026
6af59a7
Merge branch 'ready/plugins-15010-20261031' into ready/plugins-16038-…
saphid Oct 31, 2026
2ca4b4c
fix(web): adapt panel fixtures to current browser bridge and registry
saphid Oct 31, 2026
b2f7da8
fix(web): integrate current device and terminal behavior into panel host
saphid Oct 31, 2026
6898fd2
fix(web): integrate current file preview behavior into Files panel host
saphid Oct 31, 2026
fbb7a0f
test(web): retain current file-preview regressions through panel host
saphid Oct 31, 2026
27b43a3
fix(pi): preserve current provider and sharing behavior in status int…
saphid Oct 31, 2026
fd8bf13
fix(mobile): preserve current layout alongside Pi statuses
saphid Oct 31, 2026
4024f16
fix(plugins): integrate event feed with current orchestration and mig…
saphid Oct 31, 2026
a13adfa
fix(web): format migrated device fixtures and remove obsolete prop type
saphid Oct 31, 2026
cf7c376
fix(plugins): preserve MCP context and subagent credential boundaries
saphid Oct 31, 2026
edf44f9
fix(plugins): retain current secrets behavior and append settings mig…
saphid Oct 31, 2026
134cb43
test(web): adapt panel fixtures to current host and focus APIs
saphid Oct 31, 2026
94375a3
fix(plugins): integrate actions with current palette and linked envir…
saphid Oct 31, 2026
5c62ee3
test(web): preserve current entity and focus exports in panel fixtures
saphid Oct 31, 2026
2ca936d
test(web): inherit current Device and terminal fixtures
saphid Oct 31, 2026
faf50a4
test(web): adapt terminal attachment fixture to session atoms
saphid Oct 31, 2026
cec9e9b
test(web): isolate breadcrumb fixtures from browser defaults and edit…
saphid Oct 31, 2026
4254cbd
fix(plugins): carry updated parent layer into #16045
saphid Oct 31, 2026
17e0646
test(web): follow moved source-control actions and primary environmen…
saphid Oct 31, 2026
74953e1
fix(plugins): carry updated parent layer into #16048
saphid Oct 31, 2026
50614e4
fix(plugins): carry updated parent layer into #16045
saphid Oct 31, 2026
132b358
fix(plugins): carry updated parent layer into #16046
saphid Oct 31, 2026
e069d44
test(plugins): cover preview ledgers against newer main migration slots
saphid Oct 31, 2026
39f8d29
fix(web): preserve scoped file actions and make panel readiness fixtu…
saphid Oct 31, 2026
a500f29
fix(plugins): carry updated parent layer into #16046
saphid Oct 31, 2026
08c76cf
fix(plugins): carry updated parent layer into #16048
saphid Oct 31, 2026
0b36b43
fix(pi): retain desktop contracts and current panel dependencies
saphid Oct 31, 2026
255d6aa
fix(plugins): carry updated parent layer into #16046
saphid Oct 31, 2026
b3047a4
fix(plugins): carry updated parent layer into #16048
saphid Oct 31, 2026
cccc834
fix(pi): align regression fixtures with current runtime services
saphid Oct 31, 2026
871a02e
fix(plugins): carry updated parent layer into #16046
saphid Oct 31, 2026
91c565d
fix(plugins): carry updated parent layer into #16048
saphid Oct 31, 2026
ca955aa
fix(pi): provide all runtime fixtures and scoped file insertion callb…
saphid Oct 31, 2026
580d1af
fix(plugins): carry updated parent layer into #16048
saphid Oct 31, 2026
bd935e0
refactor(mobile): keep status layout constraints concise
saphid Oct 31, 2026
6fe5de3
fix(plugins): carry updated parent layer into #16048
saphid Oct 31, 2026
397485d
fix(plugins): migrate preview ledgers after current main schema
saphid Oct 31, 2026
f589b1e
fix(plugins): carry updated parent layer into #16049
saphid Oct 31, 2026
a9fb7b0
fix(plugins): retain settings preview upgrade cases on current migrat…
saphid Oct 31, 2026
5aad8a2
fix(plugins): carry updated parent layer into #16051
saphid Oct 31, 2026
502200c
fix(plugins): align event runtime with current layers and Effect conv…
saphid Oct 31, 2026
d6a613f
fix(plugins): carry updated parent layer into #16049
saphid Oct 31, 2026
d3071ec
fix(plugins): carry updated parent layer into #16050
saphid Oct 31, 2026
f2af4d4
fix(plugins): carry updated parent layer into #16051
saphid Oct 31, 2026
5ce70b7
fix(plugins): include tool services in the current context budget
saphid Oct 31, 2026
e3e24ed
fix(plugins): carry updated parent layer into #16050
saphid Oct 31, 2026
5a710a5
fix(plugins): carry updated parent layer into #16051
saphid Oct 31, 2026
4215861
refactor(plugins): keep API constraints concise
saphid Oct 31, 2026
6c42067
refactor(plugins): keep API constraints concise
saphid Oct 31, 2026
f252bbe
refactor(plugins): retain settings lock within its named Effect function
saphid Oct 31, 2026
43d023e
fix(plugins): carry updated parent layer into #16051
saphid Oct 31, 2026
72b2de2
refactor(plugins): keep API constraints concise
saphid Oct 31, 2026
27c6da1
fix(plugins): align host call functions and IPC fixture with checks
saphid Oct 31, 2026
c53a344
fix(plugins): carry updated parent layer into #16051
saphid Oct 31, 2026
66d47b7
refactor(plugins): keep action constraints and formatting current
saphid Oct 31, 2026
21b6cfe
fix(plugins): integrate current palette imports and session fixtures
saphid Oct 31, 2026
0695c8a
fix(plugins): use current environment subscriptions and composer fixt…
saphid Oct 31, 2026
5643879
Merge main into Device panel and refresh terminal fixture
saphid Oct 31, 2026
16ce06a
fix(web): preserve side chats in Files panel integration
saphid Oct 31, 2026
9ae02bf
fix(pi): integrate current panels and repair status fixtures
saphid Oct 31, 2026
134cbf9
test(web): align Preview host fixture with panel integration
saphid Oct 31, 2026
1421862
fix(plugins): integrate repaired Pi parent layer
saphid Oct 31, 2026
190c3c2
Merge current main into plugin actions
saphid Oct 31, 2026
2166d35
fix(plugins): integrate event migrations after project organization
saphid Oct 31, 2026
5471276
fix(plugins): integrate current event layer into plugin tools
saphid Oct 31, 2026
06628d6
fix(plugins): integrate settings migration after main project organiz…
saphid Oct 31, 2026
7c5f4ed
fix(plugins): preserve project ordering in command palette actions
saphid Oct 31, 2026
9046e97
test(server): mark checkpoint fixtures as regular threads
saphid Oct 31, 2026
96615f6
fix(web): retain plugin actions after prompt text
saphid Oct 31, 2026
199ad34
style(plugins): format main integration for #16051
saphid Oct 31, 2026
5baff2c
fix(plugins): inherit schema bounds and process-instance secret cleanup
saphid Oct 31, 2026
6ae49c6
Merge commit '79f1fadfc6020b820d541ca4691d2feebb15dd1b' into ready/pa…
saphid Oct 31, 2026
a52ddac
fix(plugins): enforce agent modes and harden inherited view reads
saphid Oct 31, 2026
5bb50dc
fix(server): restart continuation checks before repeating side effect…
xlurie Nov 1, 2026
6dddccb
fix(shared): /Model with a query still opens the model picker (#27837)
samkelly880 Nov 1, 2026
aa33734
fix(server): empty primary cookie no longer blocks bearer auth (#27848)
samkelly880 Nov 1, 2026
a62452a
perf(mobile): text files open in half the time on a remote host (#27850)
camchis Nov 1, 2026
bc448b8
fix(web): composer fallback keeps the effort of a model saved under a…
mkantautas Nov 1, 2026
dabab45
perf(server): skip no-op settlement decisions (#27897)
omar7550 Nov 1, 2026
34cfd24
fix(codex): a failed write to the app-server no longer leaves request…
trevoedwards Nov 1, 2026
626d602
perf(server): projects without a repository stop spawning git on ever…
Pyseph Nov 1, 2026
4773ab7
fix(server): scheduled tasks start from the default branch, not alway…
tuanvumaihuynh Nov 1, 2026
ef4c658
fix(server): subagent threads no longer inherit a pending title job (…
Dreighto Nov 1, 2026
77a728e
fix(web): show mixed automatic defaults across environments (#28005)
jtatum Nov 1, 2026
1794830
fix(client): the folder browser shows folders added or removed while …
Umais-Adeed Nov 1, 2026
fad507c
fix(mobile): chat folds stay closed until tapped, as on web and deskt…
Umais-Adeed Nov 1, 2026
71d52eb
fix(web): align composer context icons and space their labels (#28083)
voltcrash Nov 1, 2026
5651d76
fix(web): horizontal scrolling inside diff and file panes no longer s…
EtanHey Nov 1, 2026
1f9d4de
fix(server): remember T3 Connect HTTP/2 fallback across restarts (#28…
voltcrash Nov 1, 2026
7f443ab
fix(server): provider updates no longer time out mid-download (#28132)
Ajraba04 Nov 1, 2026
4c91892
fix(server): delegate_task accepts the inherited options orchestrator…
EtanHey Nov 1, 2026
be58795
fix(mobile): finished threads leave Working once the grace ends (#28169)
playcations Nov 1, 2026
c77f755
fix(web): sidebar drops a deleted project's filter with the local env…
NotAnNvidiaFan Nov 1, 2026
f513369
fix(web): terminal URLs like redis:// no longer become broken file li…
tiliakoos Nov 1, 2026
dc102e5
fix(web): skill menus show loading while project skills arrive (#28209)
NotAnNvidiaFan Nov 1, 2026
77c885e
fix(desktop): SnapShots keep working on Hyprland after an app update …
Rhinomcd Nov 1, 2026
6717d92
fix(web): Tab completes folder names in the add-project browser (#28243)
morahan Nov 1, 2026
9ff0fac
fix(web): make Changes and PR Code file lists resizable (#28244)
wrymn Nov 1, 2026
2f777bd
perf(web): main thread updates no longer re-render an open side chat …
Yuruzuu Nov 1, 2026
6d25fa1
perf(server): skip unused parent data when forking threads (#28265)
Yuruzuu Nov 1, 2026
13c3c2e
perf(server): stop summarizing side chat context at its cap (#28266)
Yuruzuu Nov 1, 2026
39bca53
perf(web): typing in a thread no longer re-renders sidebar drafts (#2…
Yuruzuu Nov 1, 2026
ee29f11
fix(scripts): Alchemy reference sync reads the catalog version (#28268)
only21mil Nov 1, 2026
96b0377
docs(mobile): mobile README links the store apps instead of calling t…
only21mil Nov 1, 2026
35df72f
perf(web): render minimap highlights without extra nodes (#28270)
Yuruzuu Nov 1, 2026
906156b
fix(ci): a change to the T3 Connect troubleshooting guide runs the se…
only21mil Nov 1, 2026
cc5760a
fix(scripts): report:renders works on machines without ~/.cache (#28274)
only21mil Nov 1, 2026
c9f47c1
docs: composer banner guidance names a consumer that still exists (#2…
only21mil Nov 1, 2026
5732bbe
docs(mobile): name the Android 16 Agent Live Updates switch in the no…
only21mil Nov 1, 2026
416c3a5
chore(plugins): merge main into plugin actions branch
saphid Nov 1, 2026
ce48e45
fix(web): prevent composer image thumbnail flicker (#28499)
Yash-Singh1 Nov 1, 2026
03ebdc8
chore(plugins): merge main into plugin actions branch
saphid Nov 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .github/scripts/ci-changes.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ const EXTRA_OWNERS = [
[/^native\/browser-secret\//, ["@t3tools/desktop"]],
[/^native\/kde-snap-shot\//, ["@t3tools/desktop"]],
[/^native\/libghostty-vt\//, ["@t3tools/web"]],
// apps/server/src/cloud/ConnectReachability.test.ts checks the guide's headings.
[/^docs\/user\/t3-connect-troubleshooting\.md$/, ["t3"]],
];
const RUST = /^native\/(resource-monitor|kde-snap-shot|hyprland-snap-shot)\//;

Expand Down Expand Up @@ -92,11 +94,11 @@ function readWorkspace() {

// [] means inert; null means unknown and requires every job.
function ownersOf(file, packages) {
if (INERT.some((pattern) => pattern.test(file))) return [];
const extra = EXTRA_OWNERS.flatMap(([pattern, names]) => (pattern.test(file) ? names : []));
if (INERT.some((pattern) => pattern.test(file))) return extra;
// A manifest can change dependencies or versions other packages read.
if (path.posix.basename(file) === "package.json") return null;
if (RUNS_EVERYTHING.some((pattern) => pattern.test(file))) return null;
const extra = EXTRA_OWNERS.flatMap(([pattern, names]) => (pattern.test(file) ? names : []));
// scripts/build-desktop-artifact.test.ts reads the crates' sources.
if (RUST.test(file)) return ["@t3tools/scripts", ...extra];

Expand Down
2 changes: 1 addition & 1 deletion .macroscope/check-run-agents/ui-consistency.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ The reference for how this codebase wants UI built is the composer banner system

- `ComposerBanner.tsx` exports one object of small slot components (`Root`, `Row`, `Icon`, `Content`, `Actions`, `Dismiss`, `Children`, and so on). Each slot owns its own Tailwind classes, exposes a `data-slot` attribute, takes `className` and spreads the rest of its props, and uses `cn` so callers can adjust without overriding. Variants and density are props on `Root`, not ad hoc class strings at call sites. Where a slot needs a real control it renders `Button` from `ui/` rather than a styled `<button>`.
- `ComposerBannerStack.tsx` composes those slots into the ordered stack and owns only stack behavior (priority, expand and collapse, dismiss transitions).
- Consumers such as `ComposerActivityStatus.tsx`, `ComposerStashBadge.tsx`, and `ComposerPlanFollowUpBanner.tsx` are a few lines of `<ComposerBanner.Row><ComposerBanner.Icon/><ComposerBanner.Content>…` with no styling of their own.
- Consumers such as `ComposerPlanFollowUpBanner.tsx` are a few lines of `<ComposerBanner.Row><ComposerBanner.Icon/><ComposerBanner.Content>…` and style only their own content.

Hold new and changed UI to that shape:

Expand Down
17 changes: 17 additions & 0 deletions apps/desktop/src/snapShot/DesktopSnapShot.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,7 @@ import * as DesktopClientSettings from "../settings/DesktopClientSettings.ts";
import * as DesktopWindow from "../window/DesktopWindow.ts";
import * as DesktopSnapShot from "./DesktopSnapShot.ts";
import * as SnapShotAccessibility from "./SnapShotAccessibility.ts";
import { CaptureSetupRequiredError } from "./linuxCaptureSession.ts";

const accessibilityApp = {
byPid: accessibilityByPidMock,
Expand Down Expand Up @@ -1875,6 +1876,22 @@ it.effect("capture fails closed while snapshots are disabled", () => {
).pipe(Effect.provide(layerTest("win32")));
});

it.effect("points capture setup failures at SnapShot settings", () => {
vi.stubEnv("XDG_SESSION_TYPE", "wayland");
linuxCaptureMock.mockRejectedValueOnce(new CaptureSetupRequiredError("Install the helper."));
return Effect.scoped(
Effect.gen(function* () {
const service = yield* DesktopSnapShot.make;
yield* service.configure(enabledSettings());
const failure = yield* Effect.flip(service.capture);
assert.equal(failure.operation, "setup-required");
}),
).pipe(
Effect.provide(layerTest("linux", { makeDirectory: () => Effect.void })),
Effect.ensuring(Effect.sync(() => vi.unstubAllEnvs())),
);
});

it.effect(
"keeps saved preferences but rechecks access and shortcut delivery after changing desktops",
() => {
Expand Down
10 changes: 7 additions & 3 deletions apps/desktop/src/snapShot/DesktopSnapShot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import { niriSocketPath } from "./NiriSnapShot.ts";
import { CaptureShortcutConfig, niriCaptureConfigPath } from "./CaptureShortcutConfig.ts";
import type { PortalCaptureShortcut } from "./PortalCaptureShortcut.ts";
import {
CaptureSetupRequiredError,
isGnomeCaptureSession,
niriCaptureBinding,
portalShortcutTrigger,
Expand Down Expand Up @@ -128,6 +129,7 @@ const DesktopSnapShotOperation = Schema.Literals([
"disabled",
"no-window-selected",
"window-unavailable",
"setup-required",
"capture",
]);

Expand Down Expand Up @@ -155,6 +157,8 @@ export class DesktopSnapShotError extends Schema.TaggedError<DesktopSnapShotErro
return "No window was selected.";
case "window-unavailable":
return "The active window is not available for capture.";
case "setup-required":
return "Finish SnapShot setup in Settings → SnapShots.";
case "capture":
return "Could not capture the active window.";
}
Expand All @@ -164,9 +168,9 @@ export class DesktopSnapShotError extends Schema.TaggedError<DesktopSnapShotErro
const isDesktopSnapShotError = Schema.is(DesktopSnapShotError);

function captureFailure(cause: unknown, captureId?: string): DesktopSnapShotError {
return isDesktopSnapShotError(cause)
? cause
: new DesktopSnapShotError({ operation: "capture", captureId, cause });
if (isDesktopSnapShotError(cause)) return cause;
const operation = cause instanceof CaptureSetupRequiredError ? "setup-required" : "capture";
return new DesktopSnapShotError({ operation, captureId, cause });
}

export class DesktopSnapShot extends Context.Service<
Expand Down
15 changes: 15 additions & 0 deletions apps/desktop/src/snapShot/HyprlandSnapShot.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
hyprlandCaptureExecutable,
hyprlandCaptureShortcut,
} from "./HyprlandSnapShot.ts";
import { CaptureSetupRequiredError } from "./linuxCaptureSession.ts";

let directory: string;
let paths: { bundle: string; dataHome: string };
Expand Down Expand Up @@ -86,6 +87,20 @@ it("updates explicitly and removes only its helper", async () => {
expect((await setup.state()).status).toBe("not-installed");
expect(await NodeFSP.readFile(unrelated, "utf8")).toBe("keep");
});
it("updates a helper left stale by an app update before capturing", async () => {
await setup.perform("install-hyprland-helper");
await NodeFSP.writeFile(paths.bundle, "update");
const result = await captureHyprlandWindow(paths);
expect(result.png).toEqual(png);
expect(await NodeFSP.readFile(hyprlandCaptureExecutable(paths), "utf8")).toBe("update");
result.feedback?.close();
});
it("leaves first-time installation to explicit setup", async () => {
await expect(captureHyprlandWindow(paths)).rejects.toBeInstanceOf(CaptureSetupRequiredError);
await expect(NodeFSP.stat(hyprlandCaptureExecutable(paths))).rejects.toMatchObject({
code: "ENOENT",
});
});
it("does not overwrite a linked executable", async () => {
const executable = hyprlandCaptureExecutable(paths);
await NodeFSP.mkdir(NodePath.dirname(executable), { recursive: true });
Expand Down
14 changes: 10 additions & 4 deletions apps/desktop/src/snapShot/HyprlandSnapShot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import * as NodeURL from "node:url";
import * as Schema from "effect/Schema";
import type { DesktopCaptureHelperState } from "@t3tools/contracts";
import type { LinuxWindowSnapshot } from "./LinuxSnapShot.ts";
import { readPortalPng } from "./linuxCaptureSession.ts";
import { CaptureSetupRequiredError, readPortalPng } from "./linuxCaptureSession.ts";
import { startNativeCaptureFeedback } from "./NativeCaptureFeedback.ts";
import { HYPRLAND_CAPTURE_ACTION } from "./linuxCaptureSession.ts";
export { isHyprlandCaptureSession } from "./linuxCaptureSession.ts";
Expand Down Expand Up @@ -167,9 +167,15 @@ export async function captureHyprlandWindow(
paths: HyprlandCapturePaths,
options?: { readonly flash: boolean; readonly animate: boolean },
): Promise<LinuxWindowSnapshot> {
const state = await new HyprlandCaptureSetup(paths).state();
if (state.status !== "ready")
throw new Error(`${state.message} Open Settings → SnapShots to continue setup.`);
const setup = new HyprlandCaptureSetup(paths);
let state = await setup.state();
if (state.status === "update-required") {
await setup.perform("install-hyprland-helper").catch((cause: unknown) => {
throw new CaptureSetupRequiredError(state.message, { cause });
});
state = await setup.state();
}
if (state.status !== "ready") throw new CaptureSetupRequiredError(state.message);
const executable = hyprlandCaptureExecutable(paths);
const directory = await NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "t3-hyprland-capture-"));
const cleanup = () => NodeFSP.rm(directory, { recursive: true, force: true });
Expand Down
5 changes: 2 additions & 3 deletions apps/desktop/src/snapShot/KdeSnapShot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import type { DesktopCaptureHelperState } from "@t3tools/contracts";

import { escapeDesktopEntryExecArgument } from "../app/DesktopLinuxUrlHandler.ts";
import type { LinuxWindowSnapshot } from "./LinuxSnapShot.ts";
import { readPortalPng } from "./linuxCaptureSession.ts";
import { CaptureSetupRequiredError, readPortalPng } from "./linuxCaptureSession.ts";
import { startNativeCaptureFeedback } from "./NativeCaptureFeedback.ts";
export { isKdeCaptureSession } from "./linuxCaptureSession.ts";

Expand Down Expand Up @@ -215,8 +215,7 @@ export async function captureKdeWindow(
options?: { readonly flash: boolean; readonly animate: boolean },
): Promise<LinuxWindowSnapshot> {
const state = await new KdeCaptureSetup(paths).state();
if (state.status !== "ready")
throw new Error(`${state.message} Open Settings → SnapShots to continue setup.`);
if (state.status !== "ready") throw new CaptureSetupRequiredError(state.message);
const { executable } = kdeCapturePaths(paths);
const directory = await NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "t3-kde-capture-"));
let retained = false;
Expand Down
6 changes: 6 additions & 0 deletions apps/desktop/src/snapShot/linuxCaptureSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ import { nativeImage } from "electron";
// Keep dbus-next out of desktop detection and PNG reads in the main process.

export const HYPRLAND_CAPTURE_ACTION = "capture-window";

export class CaptureSetupRequiredError extends Error {
constructor(state: string, options?: ErrorOptions) {
super(`${state} Open Settings → SnapShots to continue setup.`, options);
}
}
export const NIRI_CAPTURE_PATH = "/com/t3tools/SnapShot";
export const NIRI_CAPTURE_INTERFACE = "com.t3tools.SnapShot";

Expand Down
4 changes: 2 additions & 2 deletions apps/mobile/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# T3 Code Mobile

> [!WARNING]
> T3 Code Mobile is currently in development and is not distributed yet. If you want to try it out, you can build it from source.
> [!NOTE]
> To install the released app from the App Store or Google Play, see [Mobile app](../../docs/user/install.md#mobile-app). This guide covers building it from source.

## Quickstart

Expand Down
16 changes: 7 additions & 9 deletions apps/mobile/src/features/files/ThreadFilesRouteScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ import {
isMarkdownPreviewFile,
isSvgImagePreviewFile,
isVideoPreviewFile,
needsWorkspaceFileContents,
} from "./filePath";
import { useWorkspaceFileAssetUrlState } from "./workspaceFileAssetUrl";

Expand Down Expand Up @@ -707,15 +708,12 @@ export function ThreadFileScreen(props: ThreadFileRouteScreenProps) {
const handleRetryPreview = () => {
void assetPreview.refresh().finally(() => setPreviewRevision((current) => current + 1));
};
const needsFileContents =
!metadataPending &&
directoryPath === null &&
relativePath !== null &&
!isVideoFile &&
!isAudioFile &&
(resolvedActiveMode === "source" ||
isMarkdownPreviewFile(relativePath) ||
filePreviewDelimiter({ name: relativePath }) !== null);
// Metadata is needed only to distinguish directories; file contents can load concurrently.
const needsFileContents = needsWorkspaceFileContents({
relativePath,
metadataKind: metadata.data?.kind,
activeMode: resolvedActiveMode,
});
const fileQuery = useEnvironmentQuery(
canReadFiles &&
environmentId !== null &&
Expand Down
9 changes: 9 additions & 0 deletions apps/mobile/src/features/files/filePath.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { describe, expect, it } from "vite-plus/test";

import {
fileRoutePathSegments,
needsWorkspaceFileContents,
resolveFileLinkPath,
resolveWorkspaceRelativeFilePath,
} from "./filePath";
Expand Down Expand Up @@ -49,3 +50,11 @@ describe("resolveWorkspaceRelativeFilePath", () => {
expect(resolveWorkspaceRelativeFilePath(null, "/repo/main.ts")).toBeNull();
});
});

describe("needsWorkspaceFileContents", () => {
it("reads a text file while its metadata is still pending, but not a directory", () => {
const input = { relativePath: "package.json", activeMode: "source" } as const;
expect(needsWorkspaceFileContents({ ...input, metadataKind: undefined })).toBe(true);
expect(needsWorkspaceFileContents({ ...input, metadataKind: "directory" })).toBe(false);
});
});
19 changes: 19 additions & 0 deletions apps/mobile/src/features/files/filePath.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { FilesystemEntryMetadata } from "@t3tools/contracts";
import { filePreviewDelimiter } from "@t3tools/shared/delimitedPreview";
import { joinPath, resolvePathLinkTarget } from "@t3tools/shared/fileLinks";
import {
isWorkspaceAudioPreviewPath,
Expand Down Expand Up @@ -109,6 +111,23 @@ export function isMarkdownPreviewFile(path: string): boolean {
return /\.(?:md|mdx)$/i.test(path.split(/[?#]/, 1)[0] ?? "");
}

export function needsWorkspaceFileContents(input: {
readonly relativePath: string | null;
readonly metadataKind: FilesystemEntryMetadata["kind"] | undefined;
readonly activeMode: "preview" | "source";
}): boolean {
const path = input.relativePath;
return (
input.metadataKind !== "directory" &&
path !== null &&
!isVideoPreviewFile(path) &&
!isAudioPreviewFile(path) &&
(input.activeMode === "source" ||
isMarkdownPreviewFile(path) ||
filePreviewDelimiter({ name: path }) !== null)
);
}

export function fileHeaderSubtitle(projectName: string, relativePath: string): string {
const parentDir = relativePath.slice(
0,
Expand Down
36 changes: 35 additions & 1 deletion apps/mobile/src/features/keyboard/CommandPalette.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ import {
type EnvironmentThreadSearchMatch,
type ShownOrder,
} from "@t3tools/client-runtime/state/thread-search";
import { isListedThreadLineage, THREAD_JUMP_KEYBINDING_COMMANDS } from "@t3tools/contracts";
import {
AuthOrchestrationOperateScope,
isListedThreadLineage,
THREAD_JUMP_KEYBINDING_COMMANDS,
} from "@t3tools/contracts";
import {
foldSearchQuery,
PALETTE_MESSAGE_LIMIT,
Expand Down Expand Up @@ -53,6 +57,8 @@ import { requestThreadMessageJump } from "../threads/threadMessageJump";
import { threadEnvironment } from "../../state/threads";
import { useAtomCommand } from "../../state/use-atom-command";
import { serverEnvironment } from "../../state/server";
import { runPluginAction, usePluginActions } from "../../state/plugin-actions";
import { useEnvironmentScope } from "../../state/session";
import { useWorkspaceEnvironments } from "../../state/workspace";
import { useSavedRemoteConnections } from "../../state/use-remote-environment-registry";
import { useAppearancePreferences } from "../settings/appearance/AppearancePreferencesProvider";
Expand All @@ -62,6 +68,7 @@ import { useStartTriage } from "../triage/useStartTriage";
import { useNewTaskFlow } from "../threads/new-task-flow-provider";
import { useActiveNewTask } from "../../state/active-new-task";
import {
buildPluginActionPaletteItems,
filterCommandPaletteItems,
nextPaletteIndex,
type CommandPaletteItem,
Expand Down Expand Up @@ -102,6 +109,7 @@ const ACTION_ICONS: Record<string, AppSymbolName> = {

function itemIcon(item: CommandPaletteItem): AppSymbolName {
if (item.kind === "thread") return "text.bubble";
if (item.key.startsWith("plugin-action:")) return "cube";
return ACTION_ICONS[item.key] ?? "ellipsis";
}

Expand Down Expand Up @@ -231,6 +239,17 @@ export function CommandPalette(props: {
const activeThread = useThreadShell(activeThreadRef);
const visitThread = useAtomCommand(threadEnvironment.visit, { reportFailure: false });
const environments = useWorkspaceEnvironments();
// Plugin actions belong to the open thread's environment, else the first connected one.
const pluginActionEnvironmentId =
activeThreadRef?.environmentId ??
environments.find((environment) => environment.connectionState === "connected")
?.environmentId ??
null;
const pluginActions = usePluginActions(pluginActionEnvironmentId);
const canRunPluginActions = useEnvironmentScope(
pluginActionEnvironmentId,
AuthOrchestrationOperateScope,
);
const { savedConnectionsById } = useSavedRemoteConnections();
const [query, setQuery] = useState("");
// Ranking is relative to when the palette opened, so rows do not reorder as time passes.
Expand Down Expand Up @@ -401,6 +420,18 @@ export function CommandPalette(props: {
})),
);
}
if (pluginActionEnvironmentId !== null) {
actions.push(
...buildPluginActionPaletteItems({
actions: pluginActions,
canOperate: canRunPluginActions,
environmentId: pluginActionEnvironmentId,
threadId: activeThread?.id ?? null,
projectId: activeThread?.projectId ?? null,
runAction: (input) => void runPluginAction(input),
}),
);
}
const openProjects = projects.filter((project) => project.archivedAt == null);
const projectItems: CommandPaletteItem[] = [
...openProjects.filter((project) => project.pinnedAt != null),
Expand Down Expand Up @@ -467,6 +498,9 @@ export function CommandPalette(props: {
environments.length,
canTriage,
navigation,
canRunPluginActions,
pluginActionEnvironmentId,
pluginActions,
projects,
runCommand,
savedConnectionsById,
Expand Down
Loading
Loading