@oharness/server 0.9.2 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/dist/i18n.js +356 -62
  2. package/dist/i18n.js.map +1 -1
  3. package/dist/main.js +4 -0
  4. package/dist/main.js.map +1 -1
  5. package/dist/page/client/account.js +430 -23
  6. package/dist/page/client/account.js.map +1 -1
  7. package/dist/page/client/base.js +20 -1
  8. package/dist/page/client/base.js.map +1 -1
  9. package/dist/page/client/composer.js +709 -58
  10. package/dist/page/client/composer.js.map +1 -1
  11. package/dist/page/client/computer.d.ts +27 -0
  12. package/dist/page/client/computer.js +358 -0
  13. package/dist/page/client/computer.js.map +1 -0
  14. package/dist/page/client/dialogs.js +93 -6
  15. package/dist/page/client/dialogs.js.map +1 -1
  16. package/dist/page/client/events.js +94 -7
  17. package/dist/page/client/events.js.map +1 -1
  18. package/dist/page/client/files.js +86 -1
  19. package/dist/page/client/files.js.map +1 -1
  20. package/dist/page/client/index.js +4 -0
  21. package/dist/page/client/index.js.map +1 -1
  22. package/dist/page/client/panels.js +12 -6
  23. package/dist/page/client/panels.js.map +1 -1
  24. package/dist/page/client/routines.js +296 -41
  25. package/dist/page/client/routines.js.map +1 -1
  26. package/dist/page/client/shell.js +229 -51
  27. package/dist/page/client/shell.js.map +1 -1
  28. package/dist/page/client/state.js +273 -19
  29. package/dist/page/client/state.js.map +1 -1
  30. package/dist/page/client/tasks.d.ts +8 -0
  31. package/dist/page/client/tasks.js +293 -0
  32. package/dist/page/client/tasks.js.map +1 -0
  33. package/dist/page/client/transcript.js +174 -6
  34. package/dist/page/client/transcript.js.map +1 -1
  35. package/dist/page/client/usage.js +1 -11
  36. package/dist/page/client/usage.js.map +1 -1
  37. package/dist/page/style.js +706 -104
  38. package/dist/page/style.js.map +1 -1
  39. package/dist/page.js +161 -54
  40. package/dist/page.js.map +1 -1
  41. package/dist/prefs.d.ts +14 -0
  42. package/dist/prefs.js +8 -1
  43. package/dist/prefs.js.map +1 -1
  44. package/dist/remote-crypto.d.ts +78 -0
  45. package/dist/remote-crypto.js +216 -0
  46. package/dist/remote-crypto.js.map +1 -0
  47. package/dist/remote.d.ts +103 -0
  48. package/dist/remote.js +498 -0
  49. package/dist/remote.js.map +1 -0
  50. package/dist/server.d.ts +70 -0
  51. package/dist/server.js +1291 -49
  52. package/dist/server.js.map +1 -1
  53. package/dist/starters.d.ts +92 -0
  54. package/dist/starters.js +213 -0
  55. package/dist/starters.js.map +1 -0
  56. package/dist/theme.js +5 -0
  57. package/dist/theme.js.map +1 -1
  58. package/dist/turn-shots.d.ts +27 -0
  59. package/dist/turn-shots.js +71 -0
  60. package/dist/turn-shots.js.map +1 -0
  61. package/package.json +2 -2
package/dist/remote.js ADDED
@@ -0,0 +1,498 @@
1
+ import { randomBytes } from "node:crypto";
2
+ import { MacHandshake, SealedSession, b64, loadIdentity, newIdentity, readHello } from "./remote-crypto.js";
3
+ import { hostname } from "node:os";
4
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
5
+ import path from "node:path";
6
+ import { userPath } from "@oharness/engine/paths.ts";
7
+ /**
8
+ * Remote control: this machine, reachable from a phone through the relay.
9
+ *
10
+ * The Mac dials out — it never listens on anything but loopback — and holds
11
+ * one WebSocket to the relay while remote is on. A phone on the same account
12
+ * opens a channel to it; each request that arrives on the channel is replayed
13
+ * against this process's own HTTP server, so the phone speaks exactly the
14
+ * routes the page speaks and there is no second API to keep in step.
15
+ *
16
+ * A channel is useless until its handshake (remote-crypto.ts) finishes: the
17
+ * phone proves which device it is, the Mac proves it is this Mac, and every
18
+ * frame after that is sealed end to end. A phone this Mac has not seen before
19
+ * is then held until someone at the Mac allows it — the same account is what
20
+ * gets a phone to the door, and the Allow is what opens it. Both screens show
21
+ * a six-digit code derived from the handshake, so a relay that put itself in
22
+ * the middle would be caught by two codes that disagree.
23
+ *
24
+ * Once a channel is ready, inside each sealed frame:
25
+ *
26
+ * ← {pair: "ok"} | {pair: "pending", code} | {pair: "denied"}
27
+ * → {id, method, path, query?, body?} ← {id, status, body}
28
+ * → {id, subscribe: "/events"} ← {sub: id, event} … ← {sub: id, end: true}
29
+ * → {id, unsubscribe: <sub id>} ← {id, status: 200, body: {ok: true}}
30
+ */
31
+ /**
32
+ * What a phone may ask for. Chat and its controls, read-only views of what the
33
+ * agent produced — not the terminal, the browser, the file system, settings,
34
+ * sign-in or computer use. A route not here is refused before anything runs.
35
+ */
36
+ export const REMOTE_ROUTES = new Set([
37
+ "GET /state",
38
+ "GET /sessions",
39
+ "GET /open",
40
+ "GET /history",
41
+ "GET /projects",
42
+ "GET /models",
43
+ "GET /changes",
44
+ "GET /artifacts",
45
+ "GET /usage",
46
+ "GET /context",
47
+ "GET /provider-icon",
48
+ "POST /session",
49
+ "POST /prompt",
50
+ "POST /permission",
51
+ "POST /question",
52
+ "POST /interrupt",
53
+ "POST /unqueue",
54
+ "POST /sendnow",
55
+ "POST /mode",
56
+ "POST /effort",
57
+ "POST /upload",
58
+ "POST /upload/drop",
59
+ "POST /model",
60
+ // Background tasks: the list, one task's conversation, and stopping,
61
+ // dismissing or messaging one — the same reach over a conversation's work
62
+ // as /prompt and /interrupt, and the page's own routes for it.
63
+ "GET /tasks",
64
+ "GET /task",
65
+ "POST /task",
66
+ ]);
67
+ /** Subscriptions a phone may hold: the event stream the page itself listens to. */
68
+ const REMOTE_STREAMS = new Set(["/events"]);
69
+ /** `POST /session` does more than open and switch; a phone gets those two only. */
70
+ const SESSION_ACTIONS = new Set(["resume", "new", "focus"]);
71
+ /** The relay a Mac dials when nothing names another. */
72
+ export const DEFAULT_RELAY = "wss://relay.oharness.ai/v1/connect";
73
+ /**
74
+ * Where remote control connects, and whether this run is told to use it
75
+ * whatever the setting says.
76
+ *
77
+ * OHARNESS_REMOTE_RELAY names another relay for development (a local one is
78
+ * `ws://127.0.0.1:4490/v1/connect`) and, as it did before there was a switch,
79
+ * turns remote on by itself. Without it the relay is ours and the switch in
80
+ * Settings decides.
81
+ */
82
+ export function remoteRelay(env = process.env) {
83
+ const named = env["OHARNESS_REMOTE_RELAY"]?.trim();
84
+ return named ? { relay: named, always: true } : { relay: DEFAULT_RELAY, always: false };
85
+ }
86
+ const MAX_BACKOFF_MS = 30_000;
87
+ const NO_TOKEN_RETRY_MS = 5_000;
88
+ const remoteFile = () => userPath("remote.json");
89
+ async function readRemoteFile() {
90
+ try {
91
+ return JSON.parse(await readFile(remoteFile(), "utf8"));
92
+ }
93
+ catch {
94
+ return {};
95
+ }
96
+ }
97
+ async function writeRemoteFile(value) {
98
+ await mkdir(path.dirname(remoteFile()), { recursive: true });
99
+ // 0600: it holds this Mac's private identity key.
100
+ await writeFile(remoteFile(), JSON.stringify(value, null, 2) + "\n", { mode: 0o600 });
101
+ }
102
+ /**
103
+ * This Mac's id and identity for remote control, made on first use and kept
104
+ * in ~/.oharness/remote.json. The identity is what a phone pins: replacing it
105
+ * makes every paired phone refuse this Mac until it is paired again.
106
+ */
107
+ export async function remoteMachine() {
108
+ const stored = await readRemoteFile();
109
+ let id = typeof stored.machineId === "string" && /^[A-Za-z0-9_-]{8,64}$/.test(stored.machineId) ? stored.machineId : "";
110
+ let identity;
111
+ try {
112
+ if (typeof stored.identity === "string")
113
+ identity = loadIdentity(stored.identity);
114
+ }
115
+ catch {
116
+ identity = undefined;
117
+ }
118
+ if (!id || !identity) {
119
+ id ||= `mac-${randomBytes(12).toString("base64url")}`;
120
+ const made = identity ? undefined : newIdentity();
121
+ identity ??= made.identity;
122
+ await writeRemoteFile({ ...stored, machineId: id, ...(made ? { identity: made.pkcs8, devices: [] } : {}) });
123
+ }
124
+ return { machine: { id, name: hostname().replace(/\.local$/, "") }, identity };
125
+ }
126
+ export async function pairedDevices() {
127
+ const stored = await readRemoteFile();
128
+ if (!Array.isArray(stored.devices))
129
+ return [];
130
+ return stored.devices.filter((d) => !!d && typeof d === "object" && typeof d.id === "string" && typeof d.publicKey === "string");
131
+ }
132
+ async function savePairedDevice(device) {
133
+ const stored = await readRemoteFile();
134
+ const others = (await pairedDevices()).filter((d) => d.id !== device.id);
135
+ await writeRemoteFile({ ...stored, devices: [...others, device] });
136
+ }
137
+ export async function revokeDevice(id) {
138
+ const stored = await readRemoteFile();
139
+ const devices = await pairedDevices();
140
+ const kept = devices.filter((d) => d.id !== id);
141
+ if (kept.length === devices.length)
142
+ return false;
143
+ await writeRemoteFile({ ...stored, devices: kept });
144
+ return true;
145
+ }
146
+ export function startRemote(options) {
147
+ const log = options.log ?? (() => { });
148
+ const local = new URL(options.local);
149
+ const localToken = local.searchParams.get("token") ?? "";
150
+ const channels = new Map();
151
+ let socket;
152
+ let connected = false;
153
+ let stopped = false;
154
+ let signedOut = false;
155
+ let backoff = 1000;
156
+ let retry;
157
+ function relaySend(message) {
158
+ if (socket?.readyState === WebSocket.OPEN)
159
+ socket.send(JSON.stringify(message));
160
+ }
161
+ /** A sealed frame to a phone. Nothing but the handshake ever goes out in the clear. */
162
+ function reply(channelId, message) {
163
+ const sealed = channels.get(channelId)?.sealed;
164
+ if (sealed)
165
+ relaySend({ t: "data", channel: channelId, data: sealed.seal(message) });
166
+ }
167
+ function closeChannel(id) {
168
+ const channel = channels.get(id);
169
+ if (!channel)
170
+ return;
171
+ for (const controller of channel.subscriptions.values())
172
+ controller.abort();
173
+ if (channel.waiting) {
174
+ channel.waiting.abort();
175
+ options.withdrawn?.(id);
176
+ }
177
+ channels.delete(id);
178
+ }
179
+ /** Ends a channel this side no longer trusts, and tells the relay so the phone hears it. */
180
+ function drop(id, why) {
181
+ log(`remote: closed a channel — ${why}`);
182
+ closeChannel(id);
183
+ relaySend({ t: "close", channel: id });
184
+ }
185
+ async function forward(request) {
186
+ const method = String(request.method ?? "GET").toUpperCase();
187
+ const route = String(request.path ?? "");
188
+ if (!REMOTE_ROUTES.has(`${method} ${route}`)) {
189
+ return { status: 403, body: { error: `${method} ${route} is not available remotely` } };
190
+ }
191
+ if (route === "/session") {
192
+ const action = request.body?.action;
193
+ if (typeof action !== "string" || !SESSION_ACTIONS.has(action)) {
194
+ return { status: 403, body: { error: "that session action is not available remotely" } };
195
+ }
196
+ }
197
+ // Running with no approvals at all is a decision made at the Mac, not from a phone.
198
+ if (route === "/mode" && request.body?.mode === "bypassPermissions") {
199
+ return { status: 403, body: { error: "bypass mode can only be turned on at the Mac" } };
200
+ }
201
+ const url = new URL(route, local.origin);
202
+ for (const [key, value] of Object.entries(request.query ?? {})) {
203
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
204
+ url.searchParams.set(key, String(value));
205
+ }
206
+ }
207
+ // A file from the phone rides the JSON frame as base64; the upload route
208
+ // takes it as the raw bytes a browser would send, with its name and type.
209
+ const upload = route === "/upload" ? request.body : undefined;
210
+ if (upload && typeof upload.base64 !== "string") {
211
+ return { status: 400, body: { error: "upload needs base64" } };
212
+ }
213
+ const response = await fetch(url, {
214
+ method,
215
+ headers: {
216
+ authorization: `Bearer ${localToken}`,
217
+ ...(upload
218
+ ? {
219
+ "content-type": typeof upload.type === "string" ? upload.type : "application/octet-stream",
220
+ // A header carries ASCII only; the page sends names the same way.
221
+ "x-filename": typeof upload.name === "string" ? upload.name.replace(/[^\x20-\x7e]/g, "_").slice(0, 200) : "file",
222
+ }
223
+ : method === "POST" ? { "content-type": "application/json" } : {}),
224
+ },
225
+ ...(upload
226
+ ? { body: Buffer.from(upload.base64, "base64") }
227
+ : method === "POST" ? { body: JSON.stringify(request.body ?? {}) } : {}),
228
+ signal: AbortSignal.timeout(60_000),
229
+ });
230
+ // An image (a vendor's icon) cannot ride in a JSON frame as it is.
231
+ const type = response.headers.get("content-type") ?? "";
232
+ if (type.startsWith("image/")) {
233
+ const bytes = Buffer.from(await response.arrayBuffer());
234
+ return { status: response.status, body: { type, base64: bytes.toString("base64") } };
235
+ }
236
+ const text = await response.text();
237
+ let body = text;
238
+ try {
239
+ body = text ? JSON.parse(text) : null;
240
+ }
241
+ catch {
242
+ // Not JSON: handed over as the text it is.
243
+ }
244
+ return { status: response.status, body };
245
+ }
246
+ /** Relay one SSE stream from the local server, event by event, until aborted. */
247
+ async function subscribe(channelId, channel, id, route) {
248
+ const controller = new AbortController();
249
+ channel.subscriptions.set(id, controller);
250
+ try {
251
+ const response = await fetch(new URL(route, local.origin), {
252
+ headers: { authorization: `Bearer ${localToken}`, accept: "text/event-stream" },
253
+ signal: controller.signal,
254
+ });
255
+ if (!response.ok || !response.body)
256
+ throw new Error(`HTTP ${response.status}`);
257
+ const decoder = new TextDecoder();
258
+ let buffered = "";
259
+ for await (const chunk of response.body) {
260
+ buffered += decoder.decode(chunk, { stream: true });
261
+ let boundary;
262
+ while ((boundary = buffered.indexOf("\n\n")) >= 0) {
263
+ const block = buffered.slice(0, boundary);
264
+ buffered = buffered.slice(boundary + 2);
265
+ const data = block
266
+ .split("\n")
267
+ .filter((line) => line.startsWith("data:"))
268
+ .map((line) => line.slice(5).replace(/^ /, ""))
269
+ .join("\n");
270
+ if (!data)
271
+ continue;
272
+ let event;
273
+ try {
274
+ event = JSON.parse(data);
275
+ }
276
+ catch {
277
+ continue; // A line that is not JSON is not an event the page would act on either.
278
+ }
279
+ // Another phone's pairing, code and all, is the Mac's business, not this phone's.
280
+ if (typeof event.type === "string" && event.type.startsWith("remote_"))
281
+ continue;
282
+ reply(channelId, { sub: id, event });
283
+ }
284
+ }
285
+ reply(channelId, { sub: id, end: true });
286
+ }
287
+ catch (err) {
288
+ if (!controller.signal.aborted) {
289
+ reply(channelId, { sub: id, end: true, error: err instanceof Error ? err.message : String(err) });
290
+ }
291
+ }
292
+ finally {
293
+ channel.subscriptions.delete(id);
294
+ }
295
+ }
296
+ /**
297
+ * One frame from a phone. Synchronous up to the point a request is handed
298
+ * off, because sealed frames carry counters that must be opened in the
299
+ * order they arrived.
300
+ */
301
+ function onData(channelId, raw) {
302
+ const channel = channels.get(channelId);
303
+ if (!channel)
304
+ return;
305
+ try {
306
+ switch (channel.stage) {
307
+ case "hello": {
308
+ const hello = readHello(JSON.parse(raw));
309
+ if (hello.device.id !== channel.announced.id)
310
+ throw new Error("the hello names a different device");
311
+ channel.handshake = new MacHandshake(channelId, hello, options.identity);
312
+ channel.stage = "proof";
313
+ relaySend({ t: "data", channel: channelId, data: JSON.stringify(channel.handshake.welcome()) });
314
+ return;
315
+ }
316
+ case "proof": {
317
+ const handshake = channel.handshake;
318
+ channel.sealed = handshake.accept(JSON.parse(raw));
319
+ void admit(channelId, channel, handshake);
320
+ return;
321
+ }
322
+ case "pairing":
323
+ // Nothing is acted on before the Mac says yes; opened only to keep the counter in step.
324
+ channel.sealed.open(raw);
325
+ return;
326
+ case "ready":
327
+ void handle(channelId, channel, channel.sealed.open(raw));
328
+ return;
329
+ }
330
+ }
331
+ catch (err) {
332
+ drop(channelId, err instanceof Error ? err.message : String(err));
333
+ }
334
+ }
335
+ /** A known phone goes straight in; a new one waits for the person at the Mac. */
336
+ async function admit(channelId, channel, handshake) {
337
+ const { device, identity } = handshake.hello;
338
+ const publicKey = b64(identity);
339
+ const known = (await pairedDevices()).some((d) => d.id === device.id && d.publicKey === publicKey);
340
+ if (channels.get(channelId) !== channel)
341
+ return;
342
+ if (known) {
343
+ channel.stage = "ready";
344
+ reply(channelId, { pair: "ok" });
345
+ log(`remote: ${device.name} connected`);
346
+ return;
347
+ }
348
+ channel.stage = "pairing";
349
+ channel.waiting = new AbortController();
350
+ reply(channelId, { pair: "pending", code: handshake.code });
351
+ log(`remote: ${device.name} asks to pair, code ${handshake.code}`);
352
+ let allowed = false;
353
+ try {
354
+ allowed = await options.approve({ id: channelId, device, code: handshake.code }, channel.waiting.signal);
355
+ }
356
+ catch {
357
+ allowed = false;
358
+ }
359
+ if (channels.get(channelId) !== channel)
360
+ return;
361
+ channel.waiting = undefined;
362
+ if (!allowed) {
363
+ reply(channelId, { pair: "denied" });
364
+ return drop(channelId, `${device.name} was not allowed`);
365
+ }
366
+ await savePairedDevice({ id: device.id, name: device.name, publicKey, pairedAt: Date.now() });
367
+ channel.stage = "ready";
368
+ reply(channelId, { pair: "ok" });
369
+ log(`remote: ${device.name} paired`);
370
+ }
371
+ async function handle(channelId, channel, request) {
372
+ if (typeof request.id !== "number")
373
+ return;
374
+ if (typeof request.subscribe === "string") {
375
+ if (!REMOTE_STREAMS.has(request.subscribe)) {
376
+ return reply(channelId, { sub: request.id, end: true, error: "not available remotely" });
377
+ }
378
+ void subscribe(channelId, channel, request.id, request.subscribe);
379
+ return;
380
+ }
381
+ if (typeof request.unsubscribe === "number") {
382
+ channel.subscriptions.get(request.unsubscribe)?.abort();
383
+ return reply(channelId, { id: request.id, status: 200, body: { ok: true } });
384
+ }
385
+ try {
386
+ reply(channelId, { id: request.id, ...(await forward(request)) });
387
+ }
388
+ catch (err) {
389
+ reply(channelId, { id: request.id, status: 502, body: { error: err instanceof Error ? err.message : String(err) } });
390
+ }
391
+ }
392
+ function onMessage(raw) {
393
+ let message;
394
+ try {
395
+ message = JSON.parse(raw);
396
+ }
397
+ catch {
398
+ return;
399
+ }
400
+ const channel = typeof message["channel"] === "string" ? message["channel"] : "";
401
+ switch (message["t"]) {
402
+ case "ready":
403
+ connected = true;
404
+ backoff = 1000;
405
+ log(`remote: online as ${options.machine.name}`);
406
+ break;
407
+ case "open": {
408
+ const device = message["device"];
409
+ if (!channel || !device || typeof device.id !== "string")
410
+ return;
411
+ channels.set(channel, { announced: device, stage: "hello", subscriptions: new Map() });
412
+ break;
413
+ }
414
+ case "data":
415
+ if (typeof message["data"] === "string")
416
+ onData(channel, message["data"]);
417
+ break;
418
+ case "close":
419
+ closeChannel(channel);
420
+ break;
421
+ case "error":
422
+ log(`remote: relay said ${String(message["code"])}`);
423
+ break;
424
+ }
425
+ }
426
+ async function connect() {
427
+ if (stopped)
428
+ return;
429
+ const token = await options.token().catch(() => undefined);
430
+ if (stopped)
431
+ return;
432
+ if (!token) {
433
+ // Said once, not every few seconds for as long as nobody signs in.
434
+ if (!signedOut)
435
+ log("remote: no account token — sign in to use remote control");
436
+ signedOut = true;
437
+ // Looked for again soon, so signing in brings the Mac online in seconds
438
+ // rather than at the end of a backoff that grew while nobody was.
439
+ retry = setTimeout(() => void connect(), NO_TOKEN_RETRY_MS);
440
+ retry.unref?.();
441
+ return;
442
+ }
443
+ signedOut = false;
444
+ const ws = new WebSocket(options.relay);
445
+ socket = ws;
446
+ ws.addEventListener("open", () => {
447
+ ws.send(JSON.stringify({ t: "hello", v: 1, role: "host", token, machine: options.machine }));
448
+ });
449
+ ws.addEventListener("message", (event) => {
450
+ if (typeof event.data === "string")
451
+ onMessage(event.data);
452
+ });
453
+ ws.addEventListener("close", (event) => {
454
+ if (socket !== ws)
455
+ return;
456
+ connected = false;
457
+ for (const id of [...channels.keys()])
458
+ closeChannel(id);
459
+ // Refused credentials will be refused again; wait for the longest step
460
+ // rather than hammering the relay with a token it has already turned down.
461
+ if (event.code === 4401)
462
+ backoff = MAX_BACKOFF_MS;
463
+ schedule();
464
+ });
465
+ ws.addEventListener("error", () => {
466
+ // "close" follows and does the retrying.
467
+ });
468
+ }
469
+ function schedule() {
470
+ if (stopped)
471
+ return;
472
+ retry = setTimeout(() => void connect(), backoff);
473
+ retry.unref?.();
474
+ backoff = Math.min(backoff * 2, MAX_BACKOFF_MS);
475
+ }
476
+ void connect();
477
+ return {
478
+ get connected() {
479
+ return connected;
480
+ },
481
+ forget(deviceId) {
482
+ for (const [id, channel] of [...channels]) {
483
+ if (channel.announced.id === deviceId)
484
+ drop(id, `${channel.announced.name} was forgotten`);
485
+ }
486
+ },
487
+ close() {
488
+ stopped = true;
489
+ if (retry)
490
+ clearTimeout(retry);
491
+ for (const id of [...channels.keys()])
492
+ closeChannel(id);
493
+ socket?.close();
494
+ socket = undefined;
495
+ },
496
+ };
497
+ }
498
+ //# sourceMappingURL=remote.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote.js","sourceRoot":"","sources":["../src/remote.ts"],"names":[],"mappings":"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"}
package/dist/server.d.ts CHANGED
@@ -3,7 +3,9 @@ import type { Session } from "@oharness/engine/agent/session.ts";
3
3
  import { Harness } from "@oharness/engine/harness.ts";
4
4
  import type { PermissionRequest } from "@oharness/engine/agent/permissions.ts";
5
5
  import type { QuestionRequest, QuestionResult } from "@oharness/engine/tools/questions.ts";
6
+ import type { Message } from "@oharness/engine/core/types.ts";
6
7
  import type { SettingsScope } from "@oharness/engine/agent/settings.ts";
8
+ import type { ComputerUsePlugin } from "@oharness/engine/computer/plugin.ts";
7
9
  import type { ScheduleRun } from "@oharness/engine/schedule/scheduler.ts";
8
10
  import type { BrowserTargetFactory, BrowserUsePlugin } from "@oharness/engine";
9
11
  /**
@@ -23,6 +25,29 @@ export interface WebServerOptions {
23
25
  port?: number;
24
26
  /** Defaults to loopback. Changing it publishes agent control to the network. */
25
27
  host?: string;
28
+ /**
29
+ * Remote control through a relay (remote.ts). The Mac dials out; a phone on
30
+ * the same account that this page has allowed can then drive it.
31
+ *
32
+ * Given, it makes remote control something this page offers: a switch in
33
+ * Settings, saved in prefs and off until somebody turns it on. Left out,
34
+ * there is no switch and nothing dials anywhere.
35
+ */
36
+ remote?: {
37
+ /** `wss://…/v1/connect` — `remoteRelay()` says which. */
38
+ relay: string;
39
+ /**
40
+ * On for this run whatever the setting says: a relay named in the
41
+ * environment, as remote control was switched on before it had a setting.
42
+ */
43
+ always?: boolean;
44
+ /**
45
+ * The account token presented to the relay, asked again on every
46
+ * reconnect. Defaults to OHARNESS_REMOTE_TOKEN, else the signed-in
47
+ * OHarness account.
48
+ */
49
+ token?: () => Promise<string | undefined>;
50
+ };
26
51
  /**
27
52
  * How the harness for another project is built.
28
53
  *
@@ -43,6 +68,24 @@ export interface WebServerOptions {
43
68
  */
44
69
  browserTarget?: BrowserTargetFactory;
45
70
  browserUsePlugin?: BrowserUsePlugin;
71
+ /**
72
+ * Computer Use, for the harnesses this server builds. Only the desktop app
73
+ * has one: it ships the native helper and holds the OS grants. Routines are
74
+ * never given it — a run nobody is watching does not get the screen.
75
+ */
76
+ computerUsePlugin?: ComputerUsePlugin;
77
+ /**
78
+ * Restart the app. macOS applies a Screen Recording grant only to a process
79
+ * started after it, so the permission card offers this once it is granted.
80
+ */
81
+ onRelaunch?: () => void;
82
+ /**
83
+ * The app macOS holds the grants for — the one the person has to switch on
84
+ * in System Settings. "OHarness" when packaged; a development run is
85
+ * Electron.app, and a card naming OHarness there sent people to a switch
86
+ * that was already on.
87
+ */
88
+ computerGrantee?: string;
46
89
  /**
47
90
  * Told when a turn starts waiting on a person — once, not again on a replay.
48
91
  * The desktop shell uses it to notify while its window is in the background;
@@ -103,10 +146,37 @@ export interface WebServer {
103
146
  }>;
104
147
  /** Answers `ask_user` from the page, the same way. */
105
148
  readonly questionPrompt: (request: QuestionRequest, signal: AbortSignal) => Promise<QuestionResult>;
149
+ /** Stop a conversation's running turn, as the page's stop button does. */
150
+ interrupt(sessionId: string): void;
106
151
  }
107
152
  export declare function startWebServer(opts: WebServerOptions): Promise<WebServer>;
153
+ /** An upload waiting for the prompt that will carry it. */
154
+ export interface Staged {
155
+ name: string;
156
+ mediaType: string;
157
+ data: Buffer;
158
+ /** When it arrived, for the sweep. */
159
+ at: number;
160
+ }
108
161
  /** One thing the composer's + menu attached to a message. */
109
162
  export interface Reference {
110
163
  kind: "file" | "folder" | "connector" | "plugin" | "skill";
111
164
  value: string;
112
165
  }
166
+ /**
167
+ * The user's message, with what they attached.
168
+ *
169
+ * An image goes to the model as an image. A PDF goes whole, as a document the
170
+ * model reads page by page, when the model reads them (`documents`). A text
171
+ * file is pasted in. Anything else — and every PDF too — is saved in the
172
+ * project, under .oharness/attachments/<session>/, and its path given, so the
173
+ * agent can open it with its own tools: a spreadsheet with Python, a model
174
+ * that takes no PDFs with a PDF tool. Binary files used to be skipped, and
175
+ * the person was left believing the agent had read what it never received.
176
+ */
177
+ /** A user message's text without the attachment lines buildMessage adds to it. */
178
+ export declare function withoutAttachmentNotes(text: string): string;
179
+ export declare function buildMessage(prompt: string, staged: Staged[], opts: {
180
+ documents: boolean;
181
+ saveDir: string;
182
+ }): Promise<Message[]>;