Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
8262db7
feat(preview): run the browser on the environment server
maria-rcks Oct 3, 2026
5797b04
fix(preview): bound streams and preserve server browser interactions
maria-rcks Oct 3, 2026
db37859
fix(preview): restore presentation and cold client synchronization
maria-rcks Oct 4, 2026
4ed7d74
fix(preview): handle cold opens and recover stream credentials
maria-rcks Oct 4, 2026
b1f5846
fix(preview): isolate restarted tabs and forward mouse chords
maria-rcks Oct 4, 2026
88bfb70
fix(preview): open client tabs when the server browser is off and ski…
maria-rcks Oct 4, 2026
9f17d49
fix(preview): keep load failures, local clipboard, and Cmd editing sh…
maria-rcks Oct 4, 2026
895d46d
fix(preview): stop forwarding Shift+Delete cut to the remote page
maria-rcks Oct 4, 2026
a563eea
fix(preview): keep Shift+Insert paste local
maria-rcks Oct 4, 2026
0b20ab6
fix(preview): gate server tabs in the preview service and harden stre…
maria-rcks Oct 4, 2026
158e975
fix(mobile): keep zero-width spaces in committed IME text
maria-rcks Oct 4, 2026
3478c8d
fix(web): drop the input sentinel from committed IME text
maria-rcks Oct 4, 2026
b9ac5dd
refactor(preview): simplify server browser and client stream plumbing
maria-rcks Oct 4, 2026
88e874e
fix(preview): preserve agent typing and seed recording startup
maria-rcks Oct 4, 2026
cee5b66
fix(preview): retain static recording duration and restore viewer size
maria-rcks Oct 4, 2026
2315e23
fix(preview): tolerate recording limit during final frame
maria-rcks Oct 4, 2026
dd3186c
fix(preview): isolate dot-named browser profiles
maria-rcks Oct 4, 2026
00e7e9e
fix(preview): await final captured recording frame
maria-rcks Oct 4, 2026
7501518
fix(preview): isolate agent tabs and coordinate browser control
maria-rcks Oct 4, 2026
467975b
fix(preview): drain navigation before browser handoff
maria-rcks Oct 4, 2026
b7676d0
fix(preview): preserve selectors and trusted browser state
maria-rcks Oct 4, 2026
0d044e0
fix(preview): validate ref selector engine boundaries
maria-rcks Oct 4, 2026
b8afa0c
fix(preview): return from dialog-opening clicks and name stale refs
juliusmarminge Oct 5, 2026
44f2791
fix(preview): clear server-browser profile data with the desktop copy
juliusmarminge Oct 5, 2026
4c57b75
fix(preview): let server tabs leave a fixed viewport
juliusmarminge Oct 5, 2026
7449878
fix(preview): discard a server tab closed while it is still opening
juliusmarminge Oct 5, 2026
6cbd133
refactor(preview): hoist the tab-not-found guard
juliusmarminge Oct 5, 2026
0cb794b
feat(preview): open server-browser popups as tabs that keep their opener
juliusmarminge Oct 5, 2026
2ef3701
feat(preview): send server-browser copy and cut to the viewer's clipb…
juliusmarminge Oct 5, 2026
7c5b6ba
feat(preview): hand server-browser downloads to the viewer
juliusmarminge Oct 5, 2026
7104759
test(preview): drive the download test without a manual runtime
juliusmarminge Oct 5, 2026
3969aa4
feat(preview): answer server-browser file pickers with the viewer's f…
juliusmarminge Oct 5, 2026
62b8db4
docs(preview): describe clipboard, files, and popups on host browser …
juliusmarminge Oct 5, 2026
be9657b
feat(preview): cap server-browser agent tabs and close idle ones
juliusmarminge Oct 5, 2026
3e10c0b
feat(preview): let agents upload files to server-browser pages
juliusmarminge Oct 5, 2026
9d4753f
feat(preview): give agents hover, select, drag, and click options
juliusmarminge Oct 5, 2026
e8bd4ff
fix(preview): label the new browser tools in the work log
juliusmarminge Oct 5, 2026
e451e2b
fix(preview): a slow tool-icon status read no longer drops the browse…
juliusmarminge Oct 5, 2026
ed86113
feat(preview): show the agent's cursor on server-browser tabs
juliusmarminge Oct 5, 2026
e9d1b3c
fix(preview): server recordings draw the agent cursor, not a human arrow
juliusmarminge Oct 5, 2026
58f77d2
refactor(preview): the server always owns the browser engine
juliusmarminge Oct 5, 2026
1a6d777
feat(desktop): relay a preview tab's debugger as a CDP endpoint
juliusmarminge Oct 5, 2026
29ea140
feat(desktop): carry desktop browser tabs to the server over bootstra…
juliusmarminge Oct 5, 2026
50fece9
feat(preview): the server drives tabs the desktop app renders
juliusmarminge Oct 5, 2026
8cf26ad
feat(web): the desktop app renders its own server's browser tabs nati…
juliusmarminge Oct 5, 2026
5fb8504
refactor(preview): remove the web app's desktop automation host
juliusmarminge Oct 5, 2026
7ff6219
refactor(desktop): delete the desktop's own agent automation
juliusmarminge Oct 5, 2026
9b04714
docs(preview): browser tabs belong to the environment on every surface
juliusmarminge Oct 5, 2026
21e334c
feat(preview): draw the agent cursor on tabs the desktop renders
juliusmarminge Oct 5, 2026
41f6c1e
fix(preview): follow main's Effect 4.0.1 imports and thread-scoped MC…
juliusmarminge Oct 5, 2026
dd6a15b
refactor(preview): server browser tabs and HTML renders share one hea…
juliusmarminge Oct 5, 2026
54876c2
feat(preview): explain browser host setup instead of dropping Chrome'…
juliusmarminge Oct 5, 2026
f7c5711
chore(preview): drop code the server engine left unused
juliusmarminge Oct 6, 2026
5056e7b
test(preview): viewers learn which host setup the browser needs
juliusmarminge Oct 6, 2026
71362b3
feat(server): `t3 browser setup` fixes the host for the shared browser
juliusmarminge Oct 6, 2026
1ccf37a
feat(preview): viewers show the host setup command, ready to copy
juliusmarminge Oct 6, 2026
f5d4387
docs(preview): browser host setup is one command
juliusmarminge Oct 6, 2026
2f7091f
test(preview): hoist the host setup decoder
juliusmarminge Oct 6, 2026
d345eb3
fix(preview): keep desktop-rendered tabs in step with the server
juliusmarminge Oct 6, 2026
20b6a81
test(mcp): follow main's layer names in the server ARIA tests
juliusmarminge Oct 6, 2026
0debf80
fix(preview): agents see why their server browser tab failed
juliusmarminge Oct 6, 2026
129b9e8
feat(preview): the same browser controls for every tab, served by its…
juliusmarminge Oct 6, 2026
06078ec
fix(web): apply a server tab's appearance and zoom after its desktop …
juliusmarminge Oct 6, 2026
9e94130
fix(preview): use catchTags for the repo lint rule
juliusmarminge Oct 6, 2026
623eff6
fix(preview): keep file pickers and the newest control state for stal…
juliusmarminge Oct 6, 2026
a65322e
fix(preview): a profile reopened during its clear waits for the deletion
juliusmarminge Oct 6, 2026
6fade76
fix(web): confirm before clearing a profile that closes server tabs
juliusmarminge Oct 6, 2026
abd20fd
fix(mobile): drop stale browser control while the stream reconnects a…
juliusmarminge Oct 6, 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
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,9 @@ jobs:
# No Electron setup here: `t3` (apps/server) has no Electron dependency
# and none of its tests touch the runtime. Only the non-server `test`
# job, which covers @t3tools/desktop, needs the download.
- name: Install Chromium for server browser integration tests
run: node apps/server/node_modules/playwright-core/cli.js install --with-deps --only-shell chromium

- name: Test
env:
T3CODE_TRANSFER_BUDGET_REPORT_PATH: ${{ runner.temp }}/t3code-transfer-budget.md
Expand Down
2 changes: 2 additions & 0 deletions apps/desktop/src/backend/DesktopBackendConfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,8 @@ const resolvePrimaryStartConfig = Effect.fn("desktop.backendConfiguration.resolv
tailscaleServePort: backendExposure.tailscaleServePort,
desktopTelemetryFd: 4,
desktopTelemetryControlFd: 5,
desktopBrowserFd: 6,
desktopBrowserControlFd: 7,
...Option.match(input.resourceMonitorPath, {
onNone: () => ({}),
onSome: (resourceMonitorPath) => ({ resourceMonitorPath }),
Expand Down
2 changes: 2 additions & 0 deletions apps/desktop/src/backend/DesktopBackendManager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import * as DesktopApp from "../app/DesktopApp.ts";
import * as DesktopBackendPool from "./DesktopBackendPool.ts";
import * as DesktopObservability from "../app/DesktopObservability.ts";
import * as DesktopTelemetryPublisher from "../telemetry/DesktopTelemetryPublisher.ts";
import * as DesktopBrowserHost from "../preview/DesktopBrowserHost.ts";
import * as DesktopWslEnvironment from "../wsl/DesktopWslEnvironment.ts";

const decodeDesktopBackendBootstrap = Schema.decodeEffect(
Expand Down Expand Up @@ -173,6 +174,7 @@ function makeTestInstance(input: MakeInstanceInput) {
updateCancellations: Stream.empty,
...input.desktopTelemetryPublisher,
}),
DesktopBrowserHost.layer,
DesktopWslEnvironment.layerTest(
input.pruneRuntimes === undefined ? {} : { pruneRuntimes: input.pruneRuntimes },
),
Expand Down
42 changes: 42 additions & 0 deletions apps/desktop/src/backend/DesktopBackendManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ import { waitForHttpReady as waitForHttpReadyShared } from "@t3tools/shared/http

import * as DesktopObservability from "../app/DesktopObservability.ts";
import * as DesktopTelemetryPublisher from "../telemetry/DesktopTelemetryPublisher.ts";
import * as DesktopBrowserHost from "../preview/DesktopBrowserHost.ts";
import * as DesktopWslEnvironment from "../wsl/DesktopWslEnvironment.ts";

const INITIAL_RESTART_DELAY = Duration.millis(500);
Expand Down Expand Up @@ -222,6 +223,10 @@ export type BackendProcessError = typeof BackendProcessError.Type;

interface RunBackendProcessOptions extends DesktopBackendStartConfig {
readonly desktopTelemetryStream: Stream.Stream<Uint8Array>;
/** Events for the desktop's browser tabs, written to `desktopBrowserFd`. */
readonly desktopBrowserStream?: Stream.Stream<Uint8Array>;
/** Each line the backend writes to `desktopBrowserControlFd`. */
readonly onDesktopBrowserCommand?: (line: string) => Effect.Effect<void>;
readonly onDesktopTelemetryControl?: (
message: DesktopTelemetryControlMessageValue,
) => Effect.Effect<void>;
Expand Down Expand Up @@ -472,6 +477,18 @@ export const runBackendProcess = Effect.fn("runBackendProcess")(function* (
type: "output",
};
}
if (
options.bootstrap.desktopBrowserFd !== undefined &&
options.desktopBrowserStream !== undefined
) {
additionalFds[`fd${options.bootstrap.desktopBrowserFd}`] = {
type: "input",
stream: options.desktopBrowserStream,
};
}
if (options.bootstrap.desktopBrowserControlFd !== undefined) {
additionalFds[`fd${options.bootstrap.desktopBrowserControlFd}`] = { type: "output" };
}
}
const command = ChildProcess.make(options.executablePath, options.args, {
cwd: options.cwd,
Expand Down Expand Up @@ -542,6 +559,26 @@ export const runBackendProcess = Effect.fn("runBackendProcess")(function* (
Effect.forkScoped,
);
}
if (
options.bootstrap.desktopBrowserControlFd !== undefined &&
options.onDesktopBrowserCommand !== undefined
) {
const browserFd = options.bootstrap.desktopBrowserControlFd;
const handleCommand = options.onDesktopBrowserCommand;
yield* handle.getOutputFd(browserFd).pipe(
Stream.decodeText(),
Stream.splitLines,
Stream.filter((line) => line.length > 0),
Stream.runForEach(handleCommand),
Effect.catchCause((cause) =>
logBackendProcessWarning("desktop browser command stream stopped", {
fd: browserFd,
cause: Cause.pretty(cause),
}),
),
Effect.forkScoped,
);
}
if (options.captureOutput) {
const outputContext = {
executablePath: options.executablePath,
Expand Down Expand Up @@ -642,6 +679,7 @@ export const makeBackendInstance = Effect.fn("makeBackendInstance")(function* (
| HttpClient.HttpClient
| DesktopObservability.DesktopBackendOutputLogFactory
| DesktopTelemetryPublisher.DesktopTelemetryPublisher
| DesktopBrowserHost.DesktopBrowserHost
| DesktopWslEnvironment.DesktopWslEnvironment
| Scope.Scope
> {
Expand All @@ -650,6 +688,7 @@ export const makeBackendInstance = Effect.fn("makeBackendInstance")(function* (
const backendOutputLogFactory = yield* DesktopObservability.DesktopBackendOutputLogFactory;
const backendOutputLog = yield* backendOutputLogFactory.forInstance(spec.id);
const desktopTelemetryPublisher = yield* DesktopTelemetryPublisher.DesktopTelemetryPublisher;
const desktopBrowserHost = yield* DesktopBrowserHost.DesktopBrowserHost;
const wslEnvironment = yield* DesktopWslEnvironment.DesktopWslEnvironment;
const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
const httpClient = yield* HttpClient.HttpClient;
Expand Down Expand Up @@ -907,6 +946,9 @@ export const makeBackendInstance = Effect.fn("makeBackendInstance")(function* (
const program = runBackendProcess({
...config.value,
desktopTelemetryStream: desktopTelemetryPublisher.encoded,
// Only a bootstrap that names the browser fds (the local primary) gets them.
desktopBrowserStream: desktopBrowserHost.events,
onDesktopBrowserCommand: desktopBrowserHost.handleCommandLine,
onDesktopTelemetryControl: (message) =>
desktopTelemetryPublisher.handleControlForSource(spec.id, message),
onStarted: Effect.fn("desktop.backendInstance.onStarted")(function* (pid) {
Expand Down
2 changes: 2 additions & 0 deletions apps/desktop/src/backend/DesktopBackendPool.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { ChildProcessSpawner } from "effect/process";
import * as DesktopObservability from "../app/DesktopObservability.ts";
import * as DesktopAppSettings from "../settings/DesktopAppSettings.ts";
import * as DesktopTelemetryPublisher from "../telemetry/DesktopTelemetryPublisher.ts";
import * as DesktopBrowserHost from "../preview/DesktopBrowserHost.ts";
import * as ElectronDialog from "../electron/ElectronDialog.ts";
import * as DesktopWindow from "../window/DesktopWindow.ts";
import * as DesktopWslEnvironment from "../wsl/DesktopWslEnvironment.ts";
Expand Down Expand Up @@ -75,6 +76,7 @@ function layerPool(labelRef: Ref.Ref<string>): Layer.Layer<DesktopBackendPool.De
updateCommits: Stream.empty,
updateCancellations: Stream.empty,
}),
DesktopBrowserHost.layer,
Layer.succeed(DesktopBackendConfiguration.DesktopBackendConfiguration, {
resolvePrimary: Effect.die("unexpected primary config resolve"),
resolvePrimaryLabel: Ref.get(labelRef),
Expand Down
2 changes: 2 additions & 0 deletions apps/desktop/src/backend/DesktopBackendPool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ import * as DesktopBackendManager from "./DesktopBackendManager.ts";
import * as DesktopObservability from "../app/DesktopObservability.ts";
import * as DesktopAppSettings from "../settings/DesktopAppSettings.ts";
import * as DesktopTelemetryPublisher from "../telemetry/DesktopTelemetryPublisher.ts";
import * as DesktopBrowserHost from "../preview/DesktopBrowserHost.ts";
import * as DesktopWindow from "../window/DesktopWindow.ts";
import * as DesktopWslEnvironment from "../wsl/DesktopWslEnvironment.ts";
import * as ElectronDialog from "../electron/ElectronDialog.ts";
Expand Down Expand Up @@ -180,6 +181,7 @@ export type BackendInstanceFactoryRequirements =
| HttpClient.HttpClient
| DesktopObservability.DesktopBackendOutputLogFactory
| DesktopTelemetryPublisher.DesktopTelemetryPublisher
| DesktopBrowserHost.DesktopBrowserHost
| DesktopWslEnvironment.DesktopWslEnvironment;

interface ActiveRegisteredInstance {
Expand Down
9 changes: 1 addition & 8 deletions apps/desktop/src/ipc/channels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ export const PREVIEW_REFRESH_CHANNEL = "desktop:preview-refresh";
export const PREVIEW_ZOOM_IN_CHANNEL = "desktop:preview-zoom-in";
export const PREVIEW_ZOOM_OUT_CHANNEL = "desktop:preview-zoom-out";
export const PREVIEW_RESET_ZOOM_CHANNEL = "desktop:preview-reset-zoom";
export const PREVIEW_SET_ZOOM_FACTOR_CHANNEL = "desktop:preview-set-zoom-factor";
export const PREVIEW_HARD_RELOAD_CHANNEL = "desktop:preview-hard-reload";
export const PREVIEW_SET_COLOR_SCHEME_CHANNEL = "desktop:preview-set-color-scheme";
export const PREVIEW_SET_AUDIO_MUTED_CHANNEL = "desktop:preview-set-audio-muted";
Expand All @@ -96,14 +97,6 @@ export const PREVIEW_COPY_ARTIFACT_CHANNEL = "desktop:preview-copy-artifact";
export const PREVIEW_PICTURE_IN_PICTURE_OPEN_CHANNEL = "desktop:preview-pip-open";
export const PREVIEW_PICTURE_IN_PICTURE_CLOSE_CHANNEL = "desktop:preview-pip-close";
export const PREVIEW_PICTURE_IN_PICTURE_FRAME_CHANNEL = "desktop:preview-pip-frame";
export const PREVIEW_AUTOMATION_STATUS_CHANNEL = "desktop:preview-automation-status";
export const PREVIEW_AUTOMATION_SNAPSHOT_CHANNEL = "desktop:preview-automation-snapshot";
export const PREVIEW_AUTOMATION_CLICK_CHANNEL = "desktop:preview-automation-click";
export const PREVIEW_AUTOMATION_TYPE_CHANNEL = "desktop:preview-automation-type";
export const PREVIEW_AUTOMATION_PRESS_CHANNEL = "desktop:preview-automation-press";
export const PREVIEW_AUTOMATION_SCROLL_CHANNEL = "desktop:preview-automation-scroll";
export const PREVIEW_AUTOMATION_EVALUATE_CHANNEL = "desktop:preview-automation-evaluate";
export const PREVIEW_AUTOMATION_WAIT_FOR_CHANNEL = "desktop:preview-automation-wait-for";
export const PREVIEW_RECORDING_START_CHANNEL = "desktop:preview-recording-start";
export const PREVIEW_RECORDING_STOP_CHANNEL = "desktop:preview-recording-stop";
export const PREVIEW_RECORDING_SAVE_CHANNEL = "desktop:preview-recording-save";
Expand Down
26 changes: 0 additions & 26 deletions apps/desktop/src/ipc/methods/preview.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,32 +128,6 @@ describe("preview IPC methods", () => {
),
);

effectIt.effect("returns automation status for long runtime tab ids", () =>
Effect.gen(function* () {
const tabId =
`["environment-1","thread:delegated-task:${"a".repeat(120)}",` +
`"server-epoch-1","preview-1"]`;
const status = {
available: false,
visible: true,
tabId,
url: null,
title: null,
loading: false,
};
const manager = PreviewManager.PreviewManager.of({
automationStatus: () => Effect.succeed(status),
} as unknown as PreviewManager.PreviewManager["Service"]);

expect(tabId.length).toBeGreaterThan(128);
expect(
yield* PreviewIpc.automationStatus
.handler({ tabId })
.pipe(Effect.provideService(PreviewManager.PreviewManager, manager)),
).toEqual(status);
}),
);

it("keeps the public automation status tab id limit", () => {
const encode = Schema.encodeUnknownSync(PreviewAutomationStatus);
const tabId = "t".repeat(129);
Expand Down
110 changes: 13 additions & 97 deletions apps/desktop/src/ipc/methods/preview.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@
import {
DesktopPreviewAnnotationThemeInputSchema,
DesktopPreviewArtifactInputSchema,
DesktopPreviewAutomationClickInputSchema,
DesktopPreviewAutomationEvaluateInputSchema,
DesktopPreviewAutomationPressInputSchema,
DesktopPreviewAutomationScrollInputSchema,
DesktopPreviewAutomationStatusSchema,
DesktopPreviewAutomationTypeInputSchema,
DesktopPreviewAutomationWaitForInputSchema,
DesktopPreviewConfigInputSchema,
DesktopPreviewNavigateInputSchema,
DesktopPreviewRecordingArtifactSchema,
Expand All @@ -16,6 +9,7 @@ import {
DesktopPreviewScreenshotArtifactSchema,
DesktopPreviewSetAudioMutedInputSchema,
DesktopPreviewSetColorSchemeInputSchema,
DesktopPreviewSetZoomFactorInputSchema,
BrowserImportResult,
BrowserImportSource,
DesktopPreviewClearDataInputSchema,
Expand All @@ -24,7 +18,6 @@ import {
DesktopPreviewTabInputSchema,
DesktopPreviewWebviewConfigSchema,
PreviewAnnotationSubmissionResultSchema,
PreviewAutomationSnapshot,
DEFAULT_BROWSER_PROFILE_ID,
INCOGNITO_BROWSER_PROFILE_ID,
} from "@t3tools/contracts";
Expand Down Expand Up @@ -68,9 +61,10 @@ export const createTab = DesktopIpc.makeIpcMethod({
tabId,
zoomFactor,
colorScheme,
serverTab,
}) {
const manager = yield* PreviewManager.PreviewManager;
yield* manager.createTab(tabId, { zoomFactor, colorScheme });
yield* manager.createTab(tabId, { zoomFactor, colorScheme, serverTab });
}),
});

Expand Down Expand Up @@ -157,6 +151,15 @@ export const hardReload = tabMethod(
"desktop.ipc.preview.hardReload",
(manager, tabId) => manager.hardReload(tabId),
);
export const setZoomFactor = DesktopIpc.makeIpcMethod({
channel: IpcChannels.PREVIEW_SET_ZOOM_FACTOR_CHANNEL,
payload: DesktopPreviewSetZoomFactorInputSchema,
result: Schema.Void,
handler: Effect.fn("desktop.ipc.preview.setZoomFactor")(function* ({ tabId, zoomFactor }) {
const manager = yield* PreviewManager.PreviewManager;
yield* manager.setZoomFactor(tabId, zoomFactor);
}),
});
export const setColorScheme = DesktopIpc.makeIpcMethod({
channel: IpcChannels.PREVIEW_SET_COLOR_SCHEME_CHANNEL,
payload: DesktopPreviewSetColorSchemeInputSchema,
Expand Down Expand Up @@ -392,86 +395,6 @@ export const copyArtifactToClipboard = DesktopIpc.makeIpcMethod({
}),
});

export const automationStatus = DesktopIpc.makeIpcMethod({
channel: IpcChannels.PREVIEW_AUTOMATION_STATUS_CHANNEL,
payload: DesktopPreviewTabInputSchema,
result: DesktopPreviewAutomationStatusSchema,
handler: Effect.fn("desktop.ipc.preview.automationStatus")(function* ({ tabId }) {
const manager = yield* PreviewManager.PreviewManager;
return yield* manager.automationStatus(tabId);
}),
});

export const automationSnapshot = DesktopIpc.makeIpcMethod({
channel: IpcChannels.PREVIEW_AUTOMATION_SNAPSHOT_CHANNEL,
payload: DesktopPreviewTabInputSchema,
result: PreviewAutomationSnapshot,
handler: Effect.fn("desktop.ipc.preview.automationSnapshot")(function* ({ tabId }) {
const manager = yield* PreviewManager.PreviewManager;
return yield* manager.automationSnapshot(tabId);
}),
});

export const automationClick = DesktopIpc.makeIpcMethod({
channel: IpcChannels.PREVIEW_AUTOMATION_CLICK_CHANNEL,
payload: DesktopPreviewAutomationClickInputSchema,
result: Schema.Void,
handler: Effect.fn("desktop.ipc.preview.automationClick")(function* ({ tabId, input }) {
const manager = yield* PreviewManager.PreviewManager;
yield* manager.automationClick(tabId, input);
}),
});

export const automationType = DesktopIpc.makeIpcMethod({
channel: IpcChannels.PREVIEW_AUTOMATION_TYPE_CHANNEL,
payload: DesktopPreviewAutomationTypeInputSchema,
result: Schema.Void,
handler: Effect.fn("desktop.ipc.preview.automationType")(function* ({ tabId, input }) {
const manager = yield* PreviewManager.PreviewManager;
yield* manager.automationType(tabId, input);
}),
});

export const automationPress = DesktopIpc.makeIpcMethod({
channel: IpcChannels.PREVIEW_AUTOMATION_PRESS_CHANNEL,
payload: DesktopPreviewAutomationPressInputSchema,
result: Schema.Void,
handler: Effect.fn("desktop.ipc.preview.automationPress")(function* ({ tabId, input }) {
const manager = yield* PreviewManager.PreviewManager;
yield* manager.automationPress(tabId, input);
}),
});

export const automationScroll = DesktopIpc.makeIpcMethod({
channel: IpcChannels.PREVIEW_AUTOMATION_SCROLL_CHANNEL,
payload: DesktopPreviewAutomationScrollInputSchema,
result: Schema.Void,
handler: Effect.fn("desktop.ipc.preview.automationScroll")(function* ({ tabId, input }) {
const manager = yield* PreviewManager.PreviewManager;
yield* manager.automationScroll(tabId, input);
}),
});

export const automationEvaluate = DesktopIpc.makeIpcMethod({
channel: IpcChannels.PREVIEW_AUTOMATION_EVALUATE_CHANNEL,
payload: DesktopPreviewAutomationEvaluateInputSchema,
result: Schema.Unknown,
handler: Effect.fn("desktop.ipc.preview.automationEvaluate")(function* ({ tabId, input }) {
const manager = yield* PreviewManager.PreviewManager;
return yield* manager.automationEvaluate(tabId, input);
}),
});

export const automationWaitFor = DesktopIpc.makeIpcMethod({
channel: IpcChannels.PREVIEW_AUTOMATION_WAIT_FOR_CHANNEL,
payload: DesktopPreviewAutomationWaitForInputSchema,
result: Schema.Void,
handler: Effect.fn("desktop.ipc.preview.automationWaitFor")(function* ({ tabId, input }) {
const manager = yield* PreviewManager.PreviewManager;
yield* manager.automationWaitFor(tabId, input);
}),
});

export const saveRecording = DesktopIpc.makeIpcMethod({
channel: IpcChannels.PREVIEW_RECORDING_SAVE_CHANNEL,
payload: DesktopPreviewRecordingSaveInputSchema,
Expand All @@ -495,6 +418,7 @@ export const methods = [
resetZoom,
hardReload,
setColorScheme,
setZoomFactor,
setAudioMuted,
openDevTools,
clearCookies,
Expand All @@ -508,14 +432,6 @@ export const methods = [
copyArtifactToClipboard,
openPictureInPicture,
closePictureInPicture,
automationStatus,
automationSnapshot,
automationClick,
automationType,
automationPress,
automationScroll,
automationEvaluate,
automationWaitFor,
startRecording,
stopRecording,
saveRecording,
Expand Down
2 changes: 2 additions & 0 deletions apps/desktop/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ import * as DesktopUpdates from "./updates/DesktopUpdates.ts";
import * as BrowserImport from "./preview/BrowserImport/BrowserImport.ts";
import * as LinuxBrowserSecret from "./preview/BrowserImport/LinuxBrowserSecret.ts";
import * as BrowserSession from "./preview/BrowserSession.ts";
import * as DesktopBrowserHost from "./preview/DesktopBrowserHost.ts";
import * as PreviewManager from "./preview/Manager.ts";
import * as DesktopWindow from "./window/DesktopWindow.ts";
import * as DesktopWslBackend from "./wsl/DesktopWslBackend.ts";
Expand Down Expand Up @@ -161,6 +162,7 @@ const layerDesktopServerExposure = DesktopServerExposure.layer.pipe(
);

const layerDesktopPreview = PreviewManager.layer.pipe(
Layer.provideMerge(DesktopBrowserHost.layer),
// Merged rather than provided so the IPC handlers can reach the import
// service alongside the manager; both sit on the same BrowserSession.
Layer.provideMerge(BrowserImport.layer.pipe(Layer.provide(LinuxBrowserSecret.layer))),
Expand Down
Loading
Loading