You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 165cd2e
Browse filesBrowse the repository at this point in the historyBrowse files
The pairing settings page waits for its main side only where it needs it. The link and QR code come from the local server's `ServerRef`, so they render without main; the display setting renders only while main is active, so it never offers a switch that cannot answer:
331
+
The pairing settings page waits for its main side only where it needs it. Pairing codes come from the local server's `ServerRef`, so they never wait for main; remote access and the display setting render only while main is active, so the page never offers a switch that cannot answer:
332
332
333
-
<!-- source: src/pairing/page.tsx#display-->
333
+
<!-- source: src/pairing/page.tsx#main-->
334
334
335
335
```tsx
336
-
//Only the display setting needs pairing's main side; the link and QR code come from the server, so they never wait.
337
-
constdisplay= () => {
336
+
//Remote access and the display setting need pairing's main side; codes come from the server, so they never wait.
337
+
constmain= () => {
338
338
const live =props.pairing()
339
339
340
340
returnlive.status==="active"?live:undefined
@@ -441,9 +441,9 @@ legacy: ["summary"],
441
441
442
442
## Build your first extension
443
443
444
-
Pairing shows another device how to reach this machine's server, and keeps the display awake. It is small and uses both processes: a main entry that owns a power-save blocker, and a window entry that adds a settings page and a command. The window asks the local server for its addresses and pairing codes through `ctx.servers`: that server's `ServerRef` is already authenticated in the window, so its credentials never leave main. Each block below is its shipping source.
444
+
Pairing connects another device to this machine's server from anywhere, and keeps the display awake. It is small and uses both processes: a main entry that turns on remote access through the CLI and owns a power-save blocker, and a window entry that adds a settings page and a command. The window asks the local server for its remote address and pairing codes through `ctx.servers`: that server's `ServerRef` is already authenticated in the window, so its credentials never leave main. Each block below is its shipping source.
445
445
446
-
1.**Define the contract.**`contract.ts` holds the tokens other code may import, here the Ipc between pairing's main and window entries. It carries only what needs the main process, the display sleep blocker. The schemas type both sides and encode every value.
446
+
1.**Define the contract.**`contract.ts` holds the tokens other code may import, here the Ipc between pairing's main and window entries. It carries only what needs the main process: remote access, a setting of the background service, and the display sleep blocker. The schemas type both sides and encode every value.
447
447
448
448
<!-- source: src/pairing/contract.ts -->
449
449
@@ -452,12 +452,20 @@ import { Schema } from "effect"
452
452
import { Ipc } from"../sdk"
453
453
454
454
/**
455
-
* Keeps this machine's display awake while another device uses it. The window asks the local server for addresses and
456
-
* pairing codes through its own `ServerRef`; only the display sleep blocker needs the main process.
455
+
* Turns on remote access and keeps this machine's display awake while another device uses it. The window asks the
456
+
* local server for its remote address and pairing codes through its own `ServerRef`; remote access, which changes
457
+
* the background service's settings through the CLI, and the display sleep blocker need the main process.
457
458
*/
458
459
exportconst Pairing =Ipc.define({
459
460
id: "pairing",
460
461
methods: {
462
+
/** Whether remote access is on: the background service serves an OpenTunnel address. */
463
+
remote: { output: Schema.Boolean },
464
+
/**
465
+
* Turns remote access on or off, then starts the background service again. Turning it on the first time creates
466
+
* the tunnel, which can take a minute.
467
+
*/
468
+
setRemote: { input: Schema.Boolean },
461
469
/** Whether main holds the display sleep blocker. */
462
470
screenActive: { output: Schema.Boolean },
463
471
/** Holds or releases the display sleep blocker, and remembers the choice. */
2.**Write the definition.** Pairing provides its Ipc, so its window entry reads it as `ctx.uses.pairing` with no second declaration. Whether main keeps the display awake is a main store, imported once from the key the desktop kept it under before. The addresses pairing links use are a window store, which the settings page reads.
477
+
2.**Write the definition.** Pairing provides its Ipc, so its window entry reads it as `ctx.uses.pairing` with no second declaration. Whether main keeps the display awake is a main store, imported once from the key the desktop kept it under before.
3.**Provide it from main.**`MainSetup<typeof definition>` types `ctx.stores`, which main reads synchronously. A finalizer releases the blocker when the instance goes away.
498
+
3.**Provide it from main.**`MainSetup<typeof definition>` types `ctx.stores`, which main reads synchronously. Remote access runs `opencode service` through `ctx.cli`, with the caller's signal for a read and `ctx.scope.signal` for a change a closing window must not cancel. A finalizer releases the blocker when the instance goes away.
493
499
494
500
<!-- source: src/pairing/main.ts -->
495
501
496
502
```ts
503
+
import { execFile } from"node:child_process"
497
504
import { powerSaveBlocker } from"electron"
498
505
importtype { MainSetup } from"../sdk/main"
499
506
import { Pairing } from"./contract"
@@ -502,9 +509,15 @@ import type definition from "./index"
502
509
/** The display sleep blocker this instance holds, if any. */
503
510
typeBlocker= { id?:number }
504
511
512
+
/** The last `opencode service` command; the next one starts after it settles. */
4.**Write the window entry.** Pairing exists only on desktop, so setup returns at once on the web. The settings page is heavy, so it loads behind `lazy()` and compiles while the app idles; its search entries are indexed without mounting it. The page receives the desktop's own server, found through `ctx.servers` by `builtin`, and `ctx.uses.pairing`. The search entry for the display setting, like the setting itself, exists only while main answers (see `display` under [Live and failure handling](#live-and-failure-handling)).
578
+
4.**Write the window entry.** Pairing exists only on desktop, so setup returns at once on the web. The settings page is heavy, so it loads behind `lazy()` and compiles while the app idles; its search entries are indexed without mounting it. The page receives the desktop's own server, found through `ctx.servers` by `builtin`, and `ctx.uses.pairing`. The search entries for remote access and the display setting, like the settings themselves, exist only while main answers (see `main` under [Live and failure handling](#live-and-failure-handling)).
"custom.invalid": "Enter an HTTP or HTTPS address without a path, such as https://opencode.example.com.",
31
-
"unreachable.title": "Only this computer can reach the OpenCode server",
32
-
"unreachable.description":
33
-
"To pair a device on your network, run this command in a terminal, then reopen Pairing. You can also add a custom address below.",
0 commit comments