Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
658 commits
Select commit Hold shift + click to select a range
54c5a93
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
2744149
docs(plugins): describe persisted swap recovery accurately
saphid Oct 23, 2026
8516058
docs(plugins): describe persisted swap recovery accurately
saphid Oct 23, 2026
b0f342c
docs(plugins): describe persisted swap recovery accurately
saphid Oct 23, 2026
59e2d08
docs(plugins): describe persisted swap recovery accurately
saphid Oct 23, 2026
fa2e61c
docs(plugins): describe persisted swap recovery accurately
saphid Oct 23, 2026
c5e51a1
docs(plugins): describe persisted swap recovery accurately
saphid Oct 23, 2026
ba3b754
docs(plugins): describe persisted swap recovery accurately
saphid Oct 23, 2026
add8886
docs(plugins): describe persisted swap recovery accurately
saphid Oct 23, 2026
4b442c4
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
f8e1e0f
fix(web): align lazy panel fixtures with current runtime contracts
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
959c1d7
fix(plugins): bind npm swap outcomes to each replacement attempt
saphid Oct 23, 2026
c84d736
fix(plugins): expose replacement identity in settlement service
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
0470917
fix(web): align lazy panel fixtures with current runtime contracts
saphid Oct 23, 2026
480a0c4
fix(web): align lazy panel fixtures with current runtime contracts
saphid Oct 23, 2026
0ddc856
fix(web): align lazy panel fixtures with current runtime contracts
saphid Oct 23, 2026
5520179
fix(web): align lazy panel fixtures with current runtime contracts
saphid Oct 23, 2026
0f09a5a
fix(web): align lazy panel fixtures with current runtime contracts
saphid Oct 23, 2026
70d8233
fix(web): align lazy panel fixtures with current runtime contracts
saphid Oct 23, 2026
a581bde
fix(web): align lazy panel fixtures with current runtime contracts
saphid Oct 23, 2026
617871c
fix(web): align lazy panel fixtures with current runtime contracts
saphid Oct 23, 2026
2cc3d41
fix(web): align lazy panel fixtures with current runtime contracts
saphid Oct 23, 2026
cdaf7e7
test(web): migrate remaining plugin fixtures to disposable renders
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
bfe9bca
test(web): align plugin render lifecycle and available panel counters
saphid Oct 23, 2026
1ada22b
test(web): align plugin render lifecycle and available panel counters
saphid Oct 23, 2026
eb65f12
test(web): align plugin render lifecycle and available panel counters
saphid Oct 23, 2026
d66ac26
test(web): align plugin render lifecycle and available panel counters
saphid Oct 23, 2026
651af0d
test(web): align plugin render lifecycle and available panel counters
saphid Oct 23, 2026
1aad672
test(web): align plugin render lifecycle and available panel counters
saphid Oct 23, 2026
681cd0c
test(web): align plugin render lifecycle and available panel counters
saphid Oct 23, 2026
1e63052
test(web): align plugin render lifecycle and available panel counters
saphid Oct 23, 2026
db846ae
test(web): align plugin render lifecycle and available panel counters
saphid Oct 23, 2026
7d5cb86
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
35f6f3a
fix(plugins): retain current panel shortcuts and environment capabili…
saphid Oct 31, 2026
3f3f1be
fix(plugins): integrate updated stack beneath feat(server): install p…
saphid Oct 31, 2026
faf50a4
test(web): adapt terminal attachment fixture to session atoms
saphid Oct 31, 2026
bda69a3
fix(plugins): port plugin management into current settings navigation
saphid Oct 31, 2026
2803dfb
fix(plugins): integrate updated stack beneath feat(web,mobile): fill …
saphid Oct 31, 2026
e2e5535
fix(plugins): integrate updated stack beneath feat(web,mobile): insta…
saphid Oct 31, 2026
8e3fb1c
fix(plugins): integrate updated stack beneath feat(web,mobile): show …
saphid Oct 31, 2026
d0ecdd7
fix(plugins): integrate updated stack beneath feat(server,web,mobile)…
saphid Oct 31, 2026
357cb19
fix(plugins): integrate updated stack beneath feat(server,web,mobile)…
saphid Oct 31, 2026
4a67760
fix(plugins): enrich current provider start without restoring old han…
saphid Oct 31, 2026
cec9e9b
test(web): isolate breadcrumb fixtures from browser defaults and edit…
saphid Oct 31, 2026
a23b15c
fix(plugins): preserve current projections and guest commands in exam…
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
498e967
fix(plugins): carry updated parent layer into #16053
saphid Oct 31, 2026
4f28602
fix(plugins): carry updated parent layer into #16054
saphid Oct 31, 2026
12f3a67
fix(plugins): carry updated parent layer into #16058
saphid Oct 31, 2026
c290752
fix(plugins): carry updated parent layer into #16055
saphid Oct 31, 2026
73e86b4
fix(plugins): carry updated parent layer into #16056
saphid Oct 31, 2026
05af997
fix(plugins): carry updated parent layer into #16057
saphid Oct 31, 2026
cae8790
fix(plugins): carry updated parent layer into #16061
saphid Oct 31, 2026
36d4e8b
fix(plugins): carry updated parent layer into #16062
saphid Oct 31, 2026
de3e1b8
fix(plugins): carry updated parent layer into #16063
saphid Oct 31, 2026
d7f1ef4
fix(plugins): carry updated parent layer into #16065
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
b271162
fix(plugins): carry updated parent layer into #16053
saphid Oct 31, 2026
1bcfdd9
fix(plugins): retain npm transactions and current management locking
saphid Oct 31, 2026
6ee9988
fix(plugins): carry updated parent layer into #16058
saphid Oct 31, 2026
ae9bc28
fix(plugins): carry updated parent layer into #16061
saphid Oct 31, 2026
f7098be
fix(plugins): carry updated parent layer into #16055
saphid Oct 31, 2026
32fa13b
fix(plugins): carry updated parent layer into #16056
saphid Oct 31, 2026
e9ff063
fix(plugins): carry updated parent layer into #16057
saphid Oct 31, 2026
1ac4e3c
fix(plugins): carry updated parent layer into #16062
saphid Oct 31, 2026
4d93003
fix(plugins): carry updated parent layer into #16063
saphid Oct 31, 2026
49cbdff
fix(plugins): carry updated parent layer into #16065
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
16811d6
fix(plugins): carry updated parent layer into #16053
saphid Oct 31, 2026
56afefc
fix(plugins): carry updated parent layer into #16054
saphid Oct 31, 2026
a9ee1d8
fix(plugins): carry updated parent layer into #16058
saphid Oct 31, 2026
d6c6a2e
fix(plugins): carry updated parent layer into #16061
saphid Oct 31, 2026
5d31815
fix(plugins): carry updated parent layer into #16055
saphid Oct 31, 2026
c827db6
fix(plugins): carry updated parent layer into #16056
saphid Oct 31, 2026
d87a780
fix(plugins): carry updated parent layer into #16057
saphid Oct 31, 2026
197f225
fix(plugins): carry updated parent layer into #16062
saphid Oct 31, 2026
a28179b
fix(plugins): carry updated parent layer into #16063
saphid Oct 31, 2026
064b5fd
fix(plugins): carry updated parent layer into #16065
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
32a2a74
fix(plugins): carry updated parent layer into #16053
saphid Oct 31, 2026
72b2de2
refactor(plugins): keep API constraints concise
saphid Oct 31, 2026
08e0ac9
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
58eeaa5
fix(plugins): carry updated parent layer into #16053
saphid Oct 31, 2026
f3e7bfc
fix(plugins): carry updated parent layer into #16054
saphid Oct 31, 2026
07e6602
refactor(plugins): keep API constraints concise
saphid Oct 31, 2026
66d47b7
refactor(plugins): keep action constraints and formatting current
saphid Oct 31, 2026
9fbbef6
fix(plugins): carry updated parent layer into #16053
saphid Oct 31, 2026
7d066d7
fix(plugins): carry updated parent layer into #16054
saphid Oct 31, 2026
21b6cfe
fix(plugins): integrate current palette imports and session fixtures
saphid Oct 31, 2026
8ef5ef5
fix(plugins): carry updated parent layer into #16053
saphid Oct 31, 2026
d7b4390
fix(plugins): carry updated parent layer into #16054
saphid Oct 31, 2026
0695c8a
fix(plugins): use current environment subscriptions and composer fixt…
saphid Oct 31, 2026
d512025
fix(plugins): carry updated parent layer into #16053
saphid Oct 31, 2026
ad018ff
fix(plugins): carry updated parent layer into #16054
saphid Oct 31, 2026
7cd341d
style(plugins): format view isolation constraints
saphid Oct 31, 2026
6703b10
fix(plugins): align view lifecycle and RPC test fixtures
saphid Oct 31, 2026
0fba174
fix(plugins): preserve side chats alongside registered plugin panels
saphid Oct 31, 2026
b8021ea
fix(plugins): update panel labels and session fixtures with side chats
saphid Oct 31, 2026
7219112
fix(plugins): carry updated parent layer into #16054
saphid Oct 31, 2026
1657277
fix(plugins): name locked npm methods and update checkpoint fixtures
saphid Oct 31, 2026
e5c2b03
fix(plugins): keep inline actions after side-chat integration
saphid Oct 31, 2026
2393929
refactor(plugins): keep API constraints concise
saphid Oct 31, 2026
8b4988d
refactor(plugins): keep API constraints concise
saphid Oct 31, 2026
a8d5916
refactor(plugins): keep API constraints concise
saphid Oct 31, 2026
11b92ff
refactor(plugins): keep API constraints concise
saphid Oct 31, 2026
e491a58
refactor(plugins): keep API constraints concise
saphid Oct 31, 2026
bc6685c
fix(plugins): keep npm mutation locks in named service functions
saphid Oct 31, 2026
dd1c441
fix(plugins): align client lifecycle and environment APIs
saphid Oct 31, 2026
54b9635
fix(plugins): align client lifecycle and environment APIs
saphid Oct 31, 2026
65e27ca
fix(plugins): carry updated parent layer into #16055
saphid Oct 31, 2026
13e5892
refactor(plugins): keep API constraints concise
saphid Oct 31, 2026
a78bdab
fix(plugins): generate management route for current Settings
saphid Oct 31, 2026
b02d25e
fix(plugins): align client lifecycle and environment APIs
saphid Oct 31, 2026
77627b8
fix(plugins): align client lifecycle and environment APIs
saphid Oct 31, 2026
c14a653
fix(plugins): align client lifecycle and environment APIs
saphid Oct 31, 2026
8efa46c
fix(plugins): add inbound telemetry to management sessions
saphid Oct 31, 2026
20bbc5f
fix(plugins): carry updated parent layer into #16056
saphid Oct 31, 2026
e8367e5
fix(plugins): align management web fixtures with current settings
saphid Oct 31, 2026
2192e08
fix(plugins): carry updated parent layer into #16056
saphid Oct 31, 2026
6acda82
fix(plugins): align client lifecycle and environment APIs
saphid Oct 31, 2026
198a471
refactor(plugins): keep API constraints concise
saphid Oct 31, 2026
3373c29
style(plugins): format settings forms integration
saphid Oct 31, 2026
8a5edd5
fix(plugins): expose forms in current Plugins settings
saphid Oct 31, 2026
15acd3a
fix(plugins): align client lifecycle and environment APIs
saphid Oct 31, 2026
ab9837a
fix(plugins): carry updated parent layer into #16057
saphid Oct 31, 2026
6fc2228
fix(plugins): expose forms state in isolated dialog fixture
saphid Oct 31, 2026
b8b611d
fix(plugins): carry updated parent layer into #16057
saphid Oct 31, 2026
4b36b7a
fix(plugins): align client lifecycle and environment APIs
saphid Oct 31, 2026
5687a04
style(plugins): format current stack integration
saphid Oct 31, 2026
8b3a7e4
fix(plugins): carry updated parent layer into #16058
saphid Oct 31, 2026
facad9d
fix(plugins): explain native npm cache invalidation lifecycle
saphid Oct 31, 2026
48e4065
fix(plugins): carry updated parent layer into #16058
saphid Oct 31, 2026
556c36f
fix(plugins): carry latest main into contribution summaries
saphid Oct 31, 2026
383c100
fix(plugins): carry updated parent layer into #16061
saphid Oct 31, 2026
aec7fe3
style(plugins): keep view-stream revocation constraints concise
saphid Oct 31, 2026
bd2a90c
fix(plugins): carry updated parent layer into #16061
saphid Oct 31, 2026
5965f31
style(plugins): format current stack integration
saphid Oct 31, 2026
d48095f
fix(plugins): carry updated parent layer into #16062
saphid Oct 31, 2026
2cc9528
fix(plugins): align status constraints and host-call fixture functions
saphid Oct 31, 2026
4849edd
fix(plugins): align client lifecycle and environment APIs
saphid Oct 31, 2026
5e111ce
fix(plugins): carry updated parent layer into #16062
saphid Oct 31, 2026
0448c43
fix(plugins): carry current parent and side-chat invariants into #16063
saphid Oct 31, 2026
f38c73d
fix(plugins): align notification expiry and environment fixture with …
saphid Oct 31, 2026
adf4e5d
fix(plugins): carry current parent and side-chat invariants into #16063
saphid Oct 31, 2026
bcf80d7
fix(plugins): carry current parent and side-chat invariants into #16065
saphid Oct 31, 2026
01a6db0
test(plugins): return current environment hook shape in notification …
saphid Oct 31, 2026
6cf2280
fix(plugins): carry current parent and side-chat invariants into #16063
saphid Oct 31, 2026
2eaa547
style(plugins): format current stack integration
saphid Oct 31, 2026
e1b2bcd
fix(plugins): align enrichment fixtures with current snapshot contracts
saphid Oct 31, 2026
ff76a0a
fix(plugins): carry current parent and side-chat invariants into #16065
saphid Oct 31, 2026
9d85a95
fix(plugins): await stalled handler before advancing cancellation clock
saphid Oct 31, 2026
be75ce3
style(plugins): format cancellation receipt fixture
saphid Oct 31, 2026
10bd58d
fix(plugins): carry current parent and side-chat invariants into #16065
saphid Oct 31, 2026
941f039
style(plugins): format current stack integration
saphid Oct 31, 2026
3c54889
test(plugins): remove duplicate and unused approval fixture imports
saphid Oct 31, 2026
293a938
fix(plugins): retain current projection node filter without duplication
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
1c4932d
fix(plugins): integrate project organization and cover slot 76 previews
saphid Oct 31, 2026
42c773f
fix(plugins): reconcile previews around project organization migration
saphid Oct 31, 2026
5d6ab0f
Merge commit '2359643cffa6ba9ee84d6f2694b935de54a8013e' into ready/pa…
saphid Oct 31, 2026
5d28e21
fix(plugins): integrate management with current project organization
saphid Oct 31, 2026
340ae13
fix(plugins): carry repaired parent layer into #16056
saphid Oct 31, 2026
c9e8b36
fix(plugins): carry repaired parent layer into #16057
saphid Oct 31, 2026
b9330f8
fix(plugins): carry repaired parent layer into #16058
saphid Oct 31, 2026
6c30094
fix(plugins): carry repaired parent layer into #16061
saphid Oct 31, 2026
f1da8ae
fix(plugins): preserve project organization in notification capabilities
saphid Oct 31, 2026
acb6e79
fix(plugins): carry repaired parent layer into #16063
saphid Oct 31, 2026
2c12db4
fix(plugins): carry repaired parent layer into #16065
saphid Oct 31, 2026
9de50ee
fix(plugins): carry validated schema, secret and frame safeguards
saphid Oct 31, 2026
c85e98c
Merge commit '79f1fadfc6020b820d541ca4691d2feebb15dd1b' into ready/pa…
saphid Oct 31, 2026
2d6634e
fix(plugins): enforce agent modes and harden inherited view reads
saphid Oct 31, 2026
a81bb24
fix(plugins): recheck approval authorization before committing replies
saphid Oct 31, 2026
88e9f68
chore(plugins): merge main into example plugins branch
saphid Nov 1, 2026
540f6aa
chore(plugins): refresh example plugins against main
saphid Nov 1, 2026
e011db5
chore(plugins): merge current main into example plugins
maria-rcks Nov 1, 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 apps/desktop/src/window/DesktopWindow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import * as ElectronApp from "../electron/ElectronApp.ts";
import * as DesktopRendererHistory from "../telemetry/DesktopRendererHistory.ts";
import { makeQuitShortcutHandler } from "./QuitHold.ts";
import { copyContextMenuImage } from "./ContextMenuImage.ts";
import { shouldVetoViewFrameNavigation } from "./pluginViewNavigation.ts";

const TITLEBAR_HEIGHT = 40;
// Match --workspace-topbar-height in apps/web/src/index.css; native macOS buttons stay 14 points at any zoom.
Expand Down Expand Up @@ -626,6 +627,30 @@ export const make = Effect.gen(function* () {
void runPromise(electronShell.openExternal(url));
}
});
// Plugin views may not navigate themselves; see pluginViewNavigation.ts.
window.webContents.on("will-frame-navigate", (event) => {
if (event.isMainFrame) return;
if (
!shouldVetoViewFrameNavigation({
url: event.url,
frame: event.frame,
initiator: event.initiator,
mainFrame: window.webContents.mainFrame,
})
)
return;
event.preventDefault();
// Only where it tried to go: a path or query can carry the view's data.
const target = URL.parse(event.url);
void runPromise(
logWindowInfo(
"refused a plugin view navigation",
target === null
? { protocol: "invalid" }
: { protocol: target.protocol, host: target.host },
),
);
});

const quitShortcutHandler = makeQuitShortcutHandler({
platform: environment.platform,
Expand Down
84 changes: 84 additions & 0 deletions apps/desktop/src/window/pluginViewNavigation.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { describe, expect, it } from "vite-plus/test";

import { type NavigationFrame, shouldVetoViewFrameNavigation } from "./pluginViewNavigation.ts";

const frame = (
frameToken: string,
url: string,
origin: string,
parent: NavigationFrame | null,
name = "",
): NavigationFrame => ({ frameToken, url, origin, parent, name });

const app = frame("app", "t3code-dev://app/", "t3code-dev://app", null);
const view = frame("view", "about:srcdoc", "null", app, "t3-plugin-view");
const wrapper = frame("wrapper", "about:srcdoc", "null", app, "t3-plugin-view");
const wrappedView = frame("inner", "about:srcdoc", "null", wrapper);

describe("shouldVetoViewFrameNavigation", () => {
it("refuses a view navigating itself, including through a policy wrapper", () => {
for (const target of [view, wrappedView]) {
for (const url of ["about:blank", "http://127.0.0.1:7391/page.html", "data:text/html,x"]) {
expect(
shouldVetoViewFrameNavigation({ url, frame: target, initiator: target, mainFrame: app }),
).toBe(true);
}
}
});

it("refuses a navigation with no known initiator", () => {
expect(
shouldVetoViewFrameNavigation({
url: "http://127.0.0.1:7391/redirect",
frame: view,
initiator: null,
mainFrame: app,
}),
).toBe(true);
});

it("lets the app mount, wrap and dispose views", () => {
const fresh = frame("fresh", "about:blank", "t3code-dev://app", app);
expect(
shouldVetoViewFrameNavigation({
url: "about:srcdoc",
frame: fresh,
initiator: app,
mainFrame: app,
}),
).toBe(false);
const freshInner = frame("fresh-inner", "about:blank", "null", wrapper);
expect(
shouldVetoViewFrameNavigation({
url: "about:srcdoc",
frame: freshInner,
initiator: wrapper,
mainFrame: app,
}),
).toBe(false);
expect(
shouldVetoViewFrameNavigation({
url: "about:blank",
frame: view,
initiator: app,
mainFrame: app,
}),
).toBe(false);
});

it("leaves frames outside views alone", () => {
const other = frame("other", "https://example.com/", "https://example.com", app);
const font = frame("font", "about:srcdoc", "null", app);
const fontChild = frame("font-child", "about:srcdoc", "null", font);
for (const target of [other, font, fontChild]) {
expect(
shouldVetoViewFrameNavigation({
url: "https://example.com/next",
frame: target,
initiator: target,
mainFrame: app,
}),
).toBe(false);
}
});
});
27 changes: 27 additions & 0 deletions apps/desktop/src/window/pluginViewNavigation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// A document's CSP cannot stop frame navigation; Electron vetoes isolated-subtree navigation unless the main frame starts it.
// Allow about:srcdoc mounting; wrapper CSP blocks data: navigation and ping liveness detects about:blank.

export interface NavigationFrame {
readonly url: string;
readonly origin: string;
readonly frameToken: string;
readonly name: string;
readonly parent: NavigationFrame | null;
}

const isViewDocument = (frame: NavigationFrame) =>
frame.name === "t3-plugin-view" && frame.url === "about:srcdoc" && frame.origin === "null";

export function shouldVetoViewFrameNavigation(input: {
readonly url: string;
readonly frame: NavigationFrame | null;
readonly initiator: NavigationFrame | null | undefined;
readonly mainFrame: NavigationFrame;
}): boolean {
let insideView = false;
for (let frame = input.frame; frame !== null; frame = frame.parent) {
if (isViewDocument(frame)) insideView = true;
}
if (!insideView || input.url === "about:srcdoc") return false;
return input.initiator?.frameToken !== input.mainFrame.frameToken;
}
15 changes: 15 additions & 0 deletions apps/mobile/src/Stack.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import {
type RenderFailureProps,
} from "./components/RenderErrorBoundary";
import { ArchivedThreadsRouteScreen } from "./features/archive/ArchivedThreadsRouteScreen";
import { PluginNotificationBannerHost } from "./features/plugins/PluginNotificationBannerHost";
import { ConnectOnboardingRouteScreen } from "./features/cloud/ConnectOnboardingRouteScreen";
import { AttachmentFileScreen } from "./features/files/AttachmentFileScreen";
import { ThreadFilesTreeScreen, ThreadFileScreen } from "./features/files/ThreadFilesRouteScreen";
Expand Down Expand Up @@ -95,6 +96,10 @@ import { SettingsNavigationRouteScreen } from "./features/settings/SettingsNavig
import { SettingsAppearanceRouteScreen } from "./features/settings/SettingsAppearanceRouteScreen";
import { SettingsClientStorageRouteScreen } from "./features/settings/SettingsClientStorageRouteScreen";
import { SettingsDiagnosticsRouteScreen } from "./features/diagnostics/SettingsDiagnosticsRouteScreen";
import {
SettingsPluginRouteScreen,
SettingsPluginsRouteScreen,
} from "./features/settings/SettingsPluginsRouteScreen";
import { SettingsProviderAccountsRouteScreen } from "./features/settings/SettingsProviderAccountsRouteScreen";
import { SettingsAuthRouteScreen } from "./features/settings/SettingsAuthRouteScreen";
import { SettingsEnvironmentDetailRouteScreen } from "./features/settings/SettingsEnvironmentDetailRouteScreen";
Expand Down Expand Up @@ -390,6 +395,15 @@ const SETTINGS_SCREENS = {
headerTitleStyle: { fontSize: 16, fontWeight: "800" },
},
}),
SettingsPlugins: createNativeStackScreen({
screen: SettingsPluginsRouteScreen,
linking: "settings/plugins",
options: { ...SETTINGS_PAGE_OPTIONS, title: "Plugins" },
}),
SettingsPlugin: createNativeStackScreen({
screen: SettingsPluginRouteScreen,
options: { ...SETTINGS_PAGE_OPTIONS, title: "Plugin" },
}),
SettingsScheduledTaskNew: createNativeStackScreen({
screen: SettingsScheduledTaskNewRouteScreen,
linking: "settings/scheduled-tasks/new",
Expand Down Expand Up @@ -544,6 +558,7 @@ function RootStackLayout(props: {
</AdaptiveWorkspaceLayout>
</AndroidWorkspaceTabsProvider>
</WorkspaceConnectionStatusProvider>
<PluginNotificationBannerHost />
</SettingsEnvironmentFilterProvider>
</HardwareKeyboardCommandProvider>
</NewTaskFlowProvider>
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
90 changes: 88 additions & 2 deletions apps/mobile/src/features/keyboard/commandPaletteItems.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
import { describe, expect, it } from "vite-plus/test";
import {
EnvironmentId,
PluginActionId,
ProjectId,
ThreadId,
type PluginAction,
} from "@t3tools/contracts";
import { describe, expect, it, vi } from "vite-plus/test";

import { filterCommandPaletteItems, type CommandPaletteItem } from "./commandPaletteItems";
import {
buildPluginActionPaletteItems,
filterCommandPaletteItems,
type CommandPaletteItem,
} from "./commandPaletteItems";

const NOW = Date.UTC(2026, 9, 23);

Expand Down Expand Up @@ -54,3 +65,78 @@ describe("filterCommandPaletteItems", () => {
expect(filterCommandPaletteItems(items, "> layout", ["siva:one"], NOW)).toEqual([]);
});
});
describe("buildPluginActionPaletteItems", () => {
const environmentId = EnvironmentId.make("environment-1");
const thread = {
environmentId,
threadId: ThreadId.make("thread-1"),
projectId: ProjectId.make("project-1"),
};
const deploy: PluginAction = {
id: PluginActionId.make("installation-1:1:deploy"),
pluginId: "acme.deploy",
pluginName: "Deploy",
name: "deploy",
title: "Deploy this branch",
target: "thread",
placements: ["command-palette"],
};
const refresh: PluginAction = {
...deploy,
id: PluginActionId.make("installation-1:1:refresh"),
name: "refresh",
title: "Refresh caches",
target: "environment",
};

it("runs an offered action in the open thread's environment", () => {
const runAction = vi.fn();
const offered = buildPluginActionPaletteItems({
actions: [deploy],
canOperate: true,
...thread,
runAction,
});
expect(offered.map((item) => item.title)).toEqual(["Deploy this branch"]);

offered[0]?.run();

expect(runAction).toHaveBeenCalledWith({
environmentId: thread.environmentId,
action: deploy,
target: { _tag: "thread", threadId: thread.threadId },
});
});

it("offers environment actions when no thread is open", () => {
const runAction = vi.fn();
const offered = buildPluginActionPaletteItems({
actions: [deploy, refresh],
canOperate: true,
environmentId,
threadId: null,
projectId: null,
runAction,
});
expect(offered.map((item) => item.title)).toEqual(["Refresh caches"]);

offered[0]?.run();

expect(runAction).toHaveBeenCalledWith({
environmentId,
action: refresh,
target: { _tag: "environment" },
});
});

it("offers nothing to a connection that cannot operate the environment", () => {
expect(
buildPluginActionPaletteItems({
actions: [deploy],
canOperate: false,
...thread,
runAction: vi.fn(),
}),
).toEqual([]);
});
});
Loading
Loading