@openagt/dashboard 0.9.0 → 0.11.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 (223) hide show
  1. package/README.md +9 -17
  2. package/dist/built-in.d.ts +45 -16
  3. package/dist/built-in.d.ts.map +1 -1
  4. package/dist/built-in.js +95 -32
  5. package/dist/built-in.js.map +1 -1
  6. package/dist/cli.d.ts +4 -10
  7. package/dist/cli.d.ts.map +1 -1
  8. package/dist/cli.js +11 -67
  9. package/dist/cli.js.map +1 -1
  10. package/dist/client.d.ts +2 -1
  11. package/dist/client.d.ts.map +1 -1
  12. package/dist/client.js +3 -4
  13. package/dist/client.js.map +1 -1
  14. package/dist/daemon-runtime.d.ts +12 -12
  15. package/dist/daemon-runtime.d.ts.map +1 -1
  16. package/dist/daemon-runtime.js +97 -37
  17. package/dist/daemon-runtime.js.map +1 -1
  18. package/dist/daemon.d.ts +3 -14
  19. package/dist/daemon.d.ts.map +1 -1
  20. package/dist/daemon.js +15 -26
  21. package/dist/daemon.js.map +1 -1
  22. package/dist/dashboard/bridge-endpoints.d.ts +5 -5
  23. package/dist/dashboard/bridge-endpoints.js +5 -5
  24. package/dist/dashboard/http.d.ts +1 -1
  25. package/dist/dashboard/http.js +1 -1
  26. package/dist/dashboard/machine-call.d.ts +10 -0
  27. package/dist/dashboard/machine-call.d.ts.map +1 -0
  28. package/dist/dashboard/machine-call.js +86 -0
  29. package/dist/dashboard/machine-call.js.map +1 -0
  30. package/dist/dashboard/relay-endpoints.d.ts +26 -17
  31. package/dist/dashboard/relay-endpoints.d.ts.map +1 -1
  32. package/dist/dashboard/relay-endpoints.js +70 -27
  33. package/dist/dashboard/relay-endpoints.js.map +1 -1
  34. package/dist/dashboard/remote-run.d.ts +77 -32
  35. package/dist/dashboard/remote-run.d.ts.map +1 -1
  36. package/dist/dashboard/remote-run.js +120 -42
  37. package/dist/dashboard/remote-run.js.map +1 -1
  38. package/dist/dashboard/rpc-serve.d.ts +19 -25
  39. package/dist/dashboard/rpc-serve.d.ts.map +1 -1
  40. package/dist/dashboard/rpc-serve.js +11 -22
  41. package/dist/dashboard/rpc-serve.js.map +1 -1
  42. package/dist/dashboard/screen.d.ts +53 -0
  43. package/dist/dashboard/screen.d.ts.map +1 -0
  44. package/dist/dashboard/screen.js +175 -0
  45. package/dist/dashboard/screen.js.map +1 -0
  46. package/dist/dashboard/server.d.ts +18 -19
  47. package/dist/dashboard/server.d.ts.map +1 -1
  48. package/dist/dashboard/server.js +52 -81
  49. package/dist/dashboard/server.js.map +1 -1
  50. package/dist/dashboard/start-branch.d.ts +32 -0
  51. package/dist/dashboard/start-branch.d.ts.map +1 -0
  52. package/dist/dashboard/start-branch.js +47 -0
  53. package/dist/dashboard/start-branch.js.map +1 -0
  54. package/dist/dashboard/types.d.ts +6 -14
  55. package/dist/dashboard/types.d.ts.map +1 -1
  56. package/dist/dashboard/web-start-endpoints.d.ts +2 -2
  57. package/dist/dashboard/web-start-endpoints.js +1 -1
  58. package/dist/dashboard-bundle/assets/main-9Xb8Ao4p.css +2 -0
  59. package/dist/dashboard-bundle/assets/main-DTyyQ0jM.js +140 -0
  60. package/dist/dashboard-bundle/assets/{module-v213KWfH.js → module-DKd-4BTU.js} +4 -4
  61. package/dist/dashboard-bundle/host/module.js +1 -1
  62. package/dist/dashboard-bundle/index.html +3 -3
  63. package/dist/dashboard-rpc/context.d.ts +4 -4
  64. package/dist/dashboard-rpc/context.js +5 -5
  65. package/dist/dashboard-rpc/context.js.map +1 -1
  66. package/dist/dashboard-rpc/control.d.ts +1 -1
  67. package/dist/dashboard-rpc/control.js +7 -7
  68. package/dist/dashboard-rpc/control.js.map +1 -1
  69. package/dist/dashboard-rpc/events.d.ts +1 -1
  70. package/dist/dashboard-rpc/events.js +1 -1
  71. package/dist/dashboard-rpc/index.d.ts +2 -1
  72. package/dist/dashboard-rpc/index.d.ts.map +1 -1
  73. package/dist/dashboard-rpc/index.js +5 -3
  74. package/dist/dashboard-rpc/index.js.map +1 -1
  75. package/dist/dashboard-rpc/machines.d.ts +52 -0
  76. package/dist/dashboard-rpc/machines.d.ts.map +1 -0
  77. package/dist/dashboard-rpc/machines.js +82 -0
  78. package/dist/dashboard-rpc/machines.js.map +1 -0
  79. package/dist/dashboard-rpc/modules.d.ts +1 -1
  80. package/dist/dashboard-rpc/modules.js +2 -2
  81. package/dist/dashboard-rpc/modules.js.map +1 -1
  82. package/dist/dashboard-rpc/projects.d.ts +2 -0
  83. package/dist/dashboard-rpc/projects.d.ts.map +1 -1
  84. package/dist/dashboard-rpc/projects.js +10 -2
  85. package/dist/dashboard-rpc/projects.js.map +1 -1
  86. package/dist/dashboard-rpc/reads.d.ts +3 -4
  87. package/dist/dashboard-rpc/reads.d.ts.map +1 -1
  88. package/dist/dashboard-rpc/reads.js +5 -6
  89. package/dist/dashboard-rpc/reads.js.map +1 -1
  90. package/dist/dashboard-rpc/relay-agent.d.ts +3 -3
  91. package/dist/dashboard-rpc/relay-agent.js +3 -3
  92. package/dist/dashboard-rpc/relay-dispatch.d.ts +4 -4
  93. package/dist/dashboard-rpc/relay-dispatch.d.ts.map +1 -1
  94. package/dist/dashboard-rpc/relay-dispatch.js +7 -7
  95. package/dist/dashboard-rpc/relay-dispatch.js.map +1 -1
  96. package/dist/dashboard-rpc/skills.d.ts +80 -0
  97. package/dist/dashboard-rpc/skills.d.ts.map +1 -0
  98. package/dist/dashboard-rpc/skills.js +84 -0
  99. package/dist/dashboard-rpc/skills.js.map +1 -0
  100. package/dist/dashboard-rpc/test-context.js +1 -1
  101. package/dist/dashboard-rpc/test-context.js.map +1 -1
  102. package/dist/events.d.ts +4 -3
  103. package/dist/events.d.ts.map +1 -1
  104. package/dist/loopback-host.d.ts +3 -5
  105. package/dist/loopback-host.d.ts.map +1 -1
  106. package/dist/loopback-host.js +3 -5
  107. package/dist/loopback-host.js.map +1 -1
  108. package/dist/machine-link.d.ts +21 -0
  109. package/dist/machine-link.d.ts.map +1 -0
  110. package/dist/machine-link.js +20 -0
  111. package/dist/machine-link.js.map +1 -0
  112. package/dist/module-server.d.ts +1 -1
  113. package/dist/module-types/dashboard/components/ui/switch.d.ts +7 -0
  114. package/dist/module-types/dashboard/lib/draft-handoff.d.ts +5 -9
  115. package/dist/module-types/dashboard/module/index.d.ts +46 -0
  116. package/dist/module-types/src/built-in.d.ts +45 -16
  117. package/dist/module-types/src/client.d.ts +2 -1
  118. package/dist/module-types/src/dashboard/bridge-endpoints.d.ts +5 -5
  119. package/dist/module-types/src/dashboard/http.d.ts +1 -1
  120. package/dist/module-types/src/dashboard/machine-call.d.ts +9 -0
  121. package/dist/module-types/src/dashboard/remote-run.d.ts +77 -32
  122. package/dist/module-types/src/dashboard/rpc-serve.d.ts +19 -25
  123. package/dist/module-types/src/dashboard/start-branch.d.ts +31 -0
  124. package/dist/module-types/src/dashboard/types.d.ts +6 -14
  125. package/dist/module-types/src/dashboard-rpc/context.d.ts +4 -4
  126. package/dist/module-types/src/dashboard-rpc/control.d.ts +1 -1
  127. package/dist/module-types/src/dashboard-rpc/events.d.ts +1 -1
  128. package/dist/module-types/src/dashboard-rpc/index.d.ts +2 -1
  129. package/dist/module-types/src/dashboard-rpc/machines.d.ts +51 -0
  130. package/dist/module-types/src/dashboard-rpc/modules.d.ts +1 -1
  131. package/dist/module-types/src/dashboard-rpc/projects.d.ts +2 -0
  132. package/dist/module-types/src/dashboard-rpc/reads.d.ts +3 -4
  133. package/dist/module-types/src/dashboard-rpc/relay-agent.d.ts +3 -3
  134. package/dist/module-types/src/dashboard-rpc/skills.d.ts +79 -0
  135. package/dist/module-types/src/events.d.ts +4 -3
  136. package/dist/module-types/src/loopback-host.d.ts +3 -5
  137. package/dist/module-types/src/machine-link.d.ts +20 -0
  138. package/dist/module-types/src/openagent-dir.d.ts +3 -5
  139. package/dist/module-types/src/project-commands.d.ts +4 -0
  140. package/dist/module-types/src/project-hooks.d.ts +8 -5
  141. package/dist/module-types/src/project-modules.d.ts +8 -6
  142. package/dist/module-types/src/registry.d.ts +59 -16
  143. package/dist/module-types/src/repository-address.d.ts +22 -0
  144. package/dist/module-types/src/screens.d.ts +13 -0
  145. package/dist/module-types/src/store/agent-store.d.ts +2 -2
  146. package/dist/module-types/src/store/branches.d.ts +1 -1
  147. package/dist/module-types/src/store/git-host.d.ts +1 -1
  148. package/dist/module-types/src/store/queue.d.ts +1 -1
  149. package/dist/module-types/src/store/runs.d.ts +1 -1
  150. package/dist/module-types/src/store/tickets.d.ts +1 -1
  151. package/dist/module-types/src/version.d.ts +1 -0
  152. package/dist/openagent-dir.d.ts +3 -5
  153. package/dist/openagent-dir.d.ts.map +1 -1
  154. package/dist/openagent-dir.js +3 -5
  155. package/dist/openagent-dir.js.map +1 -1
  156. package/dist/package-services.d.ts +27 -0
  157. package/dist/package-services.d.ts.map +1 -0
  158. package/dist/package-services.js +62 -0
  159. package/dist/package-services.js.map +1 -0
  160. package/dist/project-commands.d.ts +4 -0
  161. package/dist/project-commands.d.ts.map +1 -1
  162. package/dist/project-commands.js.map +1 -1
  163. package/dist/project-hooks.d.ts +8 -5
  164. package/dist/project-hooks.d.ts.map +1 -1
  165. package/dist/project-hooks.js +9 -6
  166. package/dist/project-hooks.js.map +1 -1
  167. package/dist/project-modules.d.ts +8 -6
  168. package/dist/project-modules.d.ts.map +1 -1
  169. package/dist/project-modules.js +7 -13
  170. package/dist/project-modules.js.map +1 -1
  171. package/dist/project.d.ts.map +1 -1
  172. package/dist/project.js +1 -2
  173. package/dist/project.js.map +1 -1
  174. package/dist/registry.d.ts +59 -16
  175. package/dist/registry.d.ts.map +1 -1
  176. package/dist/registry.js +91 -20
  177. package/dist/registry.js.map +1 -1
  178. package/dist/repository-address.d.ts +23 -0
  179. package/dist/repository-address.d.ts.map +1 -0
  180. package/dist/repository-address.js +38 -0
  181. package/dist/repository-address.js.map +1 -0
  182. package/dist/screens.d.ts +14 -0
  183. package/dist/screens.d.ts.map +1 -0
  184. package/dist/screens.js +40 -0
  185. package/dist/screens.js.map +1 -0
  186. package/dist/store/agent-store.d.ts +2 -2
  187. package/dist/store/agent-store.d.ts.map +1 -1
  188. package/dist/store/branches.d.ts +1 -1
  189. package/dist/store/branches.js +1 -1
  190. package/dist/store/git-host.d.ts +1 -1
  191. package/dist/store/git-host.js +2 -2
  192. package/dist/store/git-host.js.map +1 -1
  193. package/dist/store/queue.d.ts +1 -1
  194. package/dist/store/queue.js +1 -1
  195. package/dist/store/runs.d.ts +1 -1
  196. package/dist/store/runs.js +1 -1
  197. package/dist/store/test-branches.d.ts +0 -8
  198. package/dist/store/test-branches.d.ts.map +1 -1
  199. package/dist/store/test-branches.js +0 -24
  200. package/dist/store/test-branches.js.map +1 -1
  201. package/dist/store/tickets.d.ts +1 -1
  202. package/dist/store/tickets.js +1 -1
  203. package/dist/version.d.ts +2 -0
  204. package/dist/version.d.ts.map +1 -0
  205. package/dist/version.js +26 -0
  206. package/dist/version.js.map +1 -0
  207. package/package.json +19 -13
  208. package/dist/dashboard-bundle/assets/main-B98UOA3_.js +0 -140
  209. package/dist/dashboard-bundle/assets/main-ByRjbCiA.css +0 -2
  210. package/dist/dashboard-rpc/devices.d.ts +0 -9
  211. package/dist/dashboard-rpc/devices.d.ts.map +0 -1
  212. package/dist/dashboard-rpc/devices.js +0 -12
  213. package/dist/dashboard-rpc/devices.js.map +0 -1
  214. package/dist/install.d.ts +0 -31
  215. package/dist/install.d.ts.map +0 -1
  216. package/dist/install.js +0 -54
  217. package/dist/install.js.map +0 -1
  218. package/dist/module-types/src/dashboard-rpc/devices.d.ts +0 -8
  219. package/dist/module-types/src/openagent-gitignore.d.ts +0 -11
  220. package/dist/openagent-gitignore.d.ts +0 -12
  221. package/dist/openagent-gitignore.d.ts.map +0 -1
  222. package/dist/openagent-gitignore.js +0 -19
  223. package/dist/openagent-gitignore.js.map +0 -1
@@ -191,6 +191,11 @@ export interface ModulePanel {
191
191
  * on it, and hands it the file as `reveal`. Without such a tab, those rows open nothing.
192
192
  */
193
193
  changes?: true;
194
+ /**
195
+ * This tab shows a run's live screen ({@link ModuleHost.watchScreen}). The chat's row of a live
196
+ * screen then opens the side panel on it. Without such a tab, that row is a line of text.
197
+ */
198
+ screen?: true;
194
199
  /** The tab's contents. */
195
200
  Panel: ComponentType<ModulePanelProps>;
196
201
  }
@@ -290,7 +295,47 @@ export interface ModuleHost {
290
295
  configureRun(projectId: string, prompt: string): void;
291
296
  /** The project's runs the dashboard knows: the ones running, and the recorded ones when the project records them. */
292
297
  agents(projectId: string): Promise<ModuleAgent[]>;
298
+ /**
299
+ * The other computers a run can be sent to, as saved on this one, each with the OpenAgent it
300
+ * runs, beside this computer's own: how a page tells that a machine fell behind this computer.
301
+ */
302
+ machines(): Promise<ModuleMachines>;
303
+ /**
304
+ * Save the machine a link names: the link another OpenAgent gives for a new device, as a person
305
+ * pastes it under Machines. This computer is let in there with it, once, and keeps its key.
306
+ */
307
+ addMachine(link: string, label?: string): Promise<MachineAdded>;
308
+ /**
309
+ * What the live screen of a run shows, as the screen's own stream of bytes, until `signal` ends
310
+ * it; nothing when the run has no live screen. OpenAgent asks the computer the run is on, which
311
+ * may be another machine: the bytes are that computer's, to read as data and never to run.
312
+ */
313
+ watchScreen(projectId: string, agentId: string, signal: AbortSignal): Promise<ReadableStream<Uint8Array> | undefined>;
314
+ /** Send the live screen of a run what the person did on it, as JSON; whether the screen took it. */
315
+ sendToScreen(projectId: string, agentId: string, input: unknown): Promise<boolean>;
293
316
  }
317
+ /** A saved machine, as a module sees it: never this computer's key there. */
318
+ export interface ModuleMachine {
319
+ /** Where the machine answers, as an origin (`https://203.0.113.5`): what it is known by. */
320
+ id: string;
321
+ label: string;
322
+ url: string;
323
+ /** The OpenAgent it runs; absent for a machine that does not answer right now. */
324
+ version?: string;
325
+ }
326
+ /** What {@link ModuleHost.machines} answers. */
327
+ export interface ModuleMachines {
328
+ /** This computer's own OpenAgent. */
329
+ version: string;
330
+ machines: ModuleMachine[];
331
+ }
332
+ /** How saving a machine went: done, or stopped, with the reason. */
333
+ export type MachineAdded = {
334
+ ok: true;
335
+ } | {
336
+ ok: false;
337
+ error: string;
338
+ };
294
339
  /** What the dashboard knows about the module it is serving: every service but the commands and the reads, which it binds to the package. */
295
340
  export type ModuleHostBase = Omit<ModuleHost, 'runCommand' | 'act' | 'read'>;
296
341
  /**
@@ -314,6 +359,7 @@ export { Badge } from '../components/ui/badge.js';
314
359
  export { Card, CardHeader, CardTitle, CardContent } from '../components/ui/card.js';
315
360
  export { Skeleton } from '../components/ui/skeleton.js';
316
361
  export { Checkbox } from '../components/ui/checkbox.js';
362
+ export { Switch } from '../components/ui/switch.js';
317
363
  export { Input } from '../components/ui/input.js';
318
364
  export { Popover, PopoverContent, PopoverTrigger } from '../components/ui/popover.js';
319
365
  export { RangeSlider } from '../components/ui/slider.js';
@@ -1,37 +1,66 @@
1
1
  import type { CleanupReport } from './dashboard/types.js';
2
2
  import { type ProjectPackage, type ProvidedCommand, type ProvidedCommandLookup } from '@openagt/agent-data';
3
3
  /**
4
- * The packages OpenAgent ships for every project, by name: dependencies of OpenAgent
5
- * itself, resolved from its own install, so a project installs nothing for them and an empty
6
- * folder starts an agent and shows it. Each comes through the same contract as a project's own
7
- * package: a module by its `./dashboard` export, a provider of a kind of data and the writer of
8
- * its hook lines by its `openagent` key. This list is the one place OpenAgent names a
9
- * package, and a project's own copy of any of them wins.
4
+ * The packages OpenAgent brings, by name: dependencies of OpenAgent itself, resolved from its
5
+ * own install, so a project installs nothing for them and an empty folder starts an agent and
6
+ * shows it. Each comes through the same contract as any package: a module by its `./dashboard`
7
+ * export, a provider of a kind of data and the writer of its hook lines by its `openagent` key.
8
+ * These two lists are the one place OpenAgent names a package. One of these names among a
9
+ * project's own dependencies is not read: OpenAgent's copy, and the rules below for which
10
+ * project has it, are the only ones.
10
11
  */
12
+ /** The packages every project has: an agent cannot start, be shown or be put on a git host without them, and the door to this computer and the servers it installed OpenAgent on are no project's to pick. */
11
13
  export declare const BUILT_IN_PACKAGES: readonly string[];
12
- /** The built-in packages, resolved from OpenAgent's own install, once; one that is not installed is skipped. */
14
+ /**
15
+ * The packages a project has once it picked them (#2023). A skill's package is the project's
16
+ * when the project holds the skill's text where the coding agents read it
17
+ * (`.claude/skills/<name>/SKILL.md`, `.agents/skills/<name>/SKILL.md`): the rule the launcher
18
+ * already lists a project's commands by, so deleting the skill's folder takes its page away. A
19
+ * tool with no skill text (the scheduler) is the project's when one of the project's hook lines
20
+ * runs it.
21
+ */
22
+ export declare const PICKED_PACKAGES: readonly string[];
23
+ /** Every name OpenAgent brings itself. */
24
+ export declare const OWN_PACKAGE_NAMES: readonly string[];
25
+ /** Every package OpenAgent brings, resolved from its own install, once; one that is not installed is skipped. */
13
26
  export declare function builtInPackages(): Promise<ProjectPackage[]>;
14
- /** The directories the built-in packages' commands sit in: what a hook line's PATH gains after the project's own installed tools. */
27
+ /**
28
+ * The packages OpenAgent brings to the project at `root`: the ones every project has, and
29
+ * each picked one the project has by its rule (see {@link PICKED_PACKAGES}). Read off the
30
+ * project's files each time, so a skill written or deleted a moment ago counts at once.
31
+ */
32
+ export declare function builtInPackagesOf(root: string): Promise<ProjectPackage[]>;
33
+ /** The project's own installed packages, less the names OpenAgent brings itself. */
34
+ export declare function ownPackages(root: string): Promise<ProjectPackage[]>;
35
+ /**
36
+ * The services of the packages every project has: a package declares
37
+ * `"openagent": { "service": "<command>" }`, and `<command> serve` runs for as long as OpenAgent
38
+ * runs (`package-services.ts`). Only those packages: a service is this computer's, and a package
39
+ * a project picked is that project's.
40
+ */
41
+ export declare function builtInServices(): Promise<ProvidedCommand[]>;
42
+ /** The directories the commands of OpenAgent's packages sit in: what a hook line's PATH gains after the project's own installed tools. */
15
43
  export declare function builtInBinDirs(): Promise<string[]>;
16
- /** What provides `kind` in the project at `root`: one of the project's own packages, else a built-in one. */
44
+ /** What provides `kind` in the project at `root`: a package the project installed for it, else one OpenAgent brings to this project. */
17
45
  export declare function lookupProvided(root: string, kind: string): Promise<ProvidedCommandLookup>;
18
46
  /** {@link lookupProvided}'s command, for a caller that only needs to run it. */
19
47
  export declare function providedCommand(root: string, kind: string): Promise<ProvidedCommand | undefined>;
20
- /** Whether `command` comes from a built-in package the project has no copy of: one the project did not choose. */
21
- export declare function isBuiltIn(root: string, command: ProvidedCommand): Promise<boolean>;
48
+ /** Whether `command` comes from a package OpenAgent brings: one the project did not install. */
49
+ export declare function isBuiltIn(command: ProvidedCommand): boolean;
22
50
  /**
23
51
  * Have every package that writes hook lines write its own into the project at `root`: a package
24
52
  * declares `"openagent": { "hooks": "<command>" }`, and `<command> init`, run in the project,
25
53
  * writes its lines into the project's hooks file, keeping every line already there. The project's
26
- * own packages are asked, then the built-in ones the project has no copy of. Answers one line per
27
- * package that could not write, in words.
54
+ * own packages are asked, then the ones OpenAgent brings to it. Answers one line per package
55
+ * that could not write, in words.
28
56
  */
29
57
  export declare function writeHookLines(root: string): Promise<string[]>;
30
58
  /**
31
59
  * Have every package that declares a clean-up remove what it left in the project at `root`: a
32
60
  * package declares `"openagent": { "cleanup": "<command>" }`, and `<command> cleanup`, run in the
33
- * project, answers `{ ok: true, removed, kept }`. The project's own packages are asked, then the
34
- * built-in ones the project has no copy of, each whatever the one before answered. A package
35
- * that refuses, fails or answers something else is one line in `failed`, in words.
61
+ * project, answers `{ ok: true, removed, kept }`. The project's own packages are asked, then
62
+ * every package OpenAgent brings, also one this project no longer has (what it left stays its
63
+ * own to remove), each whatever the one before answered. A package that refuses, fails or answers
64
+ * something else is one line in `failed`, in words.
36
65
  */
37
66
  export declare function runCleanups(root: string): Promise<CleanupReport>;
@@ -1,6 +1,7 @@
1
1
  export { DRIVERS, DRIVER_LABELS, isDriverName, driverFromImpl, type DriverName } from './driver-names.js';
2
2
  export { PUBLISH_LABELS, isPublishPick, offeredPublishPicks, publishPickIn, type PublishPick } from './publish-levels.js';
3
3
  export { formatOpenAgentEvent } from './terminal.js';
4
+ export { foldScreenRows } from './screens.js';
4
5
  export { formatBytes } from './format-bytes.js';
5
6
  export { errorMessage } from './error-message.js';
6
7
  export { pickedIds } from './events.js';
@@ -10,6 +11,6 @@ export { interventionKey, activityKey } from './dashboard/keys.js';
10
11
  export { SeenTracker } from './dashboard/keyed-watcher.js';
11
12
  export type { ProjectionRead } from './dashboard/projects.js';
12
13
  export { NOTIFICATION_DEFAULTS, MAX_SPEND_OFFSET, notifies, browserNotifyEnabled, notifyCategoryEnabled, type NotifyCategory } from './preference-defaults.js';
13
- export { isLoopbackHost } from './loopback-host.js';
14
+ export { parseMachineLink } from './machine-link.js';
14
15
  export { bridgeChoiceRequest } from './dashboard/bridge-question.js';
15
16
  export { cloudRunState, cloudRunActive, CLOUD_SESSION_WINDOW_MS, type CloudRunState } from './cloud-run-state.js';
@@ -5,11 +5,11 @@ export type { BridgeOption, BridgeQuestion } from './bridge-question.js';
5
5
  * The browser bridge (#1237): the one endpoint an extension running in the user's own Claude
6
6
  * session posts to, so a question a cloud agent is parked on becomes visible in the dashboard.
7
7
  *
8
- * **Why this route carries its own token, unlike every other one.** The #1051 guard in
9
- * `startDashboard` only exists on a non-loopback bind, and what protects a loopback daemon is
10
- * the same-origin check on `/_rpc`: a page on another origin is refused outright. This
11
- * route is the first that is *meant* to be reached from another origin, so neither of those
12
- * protects it, and it demands `Authorization: Bearer <daemonToken>` unconditionally instead.
8
+ * **Why this route carries its own token, unlike every other one.** What protects the daemon,
9
+ * which listens on its own computer only, is the same-origin check on `/_rpc`: a page on another
10
+ * origin is refused outright. This route is the first that is *meant* to be reached from another
11
+ * origin, so that check does not protect it, and it demands `Authorization: Bearer <bridgeToken>`
12
+ * unconditionally instead.
13
13
  *
14
14
  * **No CORS headers, on purpose.** An extension's service worker holding `host_permissions`
15
15
  * fetches without a preflight, so the bridge does not need `Access-Control-Allow-Origin` and
@@ -1,7 +1,7 @@
1
1
  import type { IncomingMessage, ServerResponse } from 'node:http';
2
2
  /**
3
3
  * The plumbing every one of the daemon's non-RPC HTTP surfaces shares: the browser bridge
4
- * (`/_bridge`), the web-start queue (`/_web-start`) and the device relay (`/_relay`).
4
+ * (`/_bridge`), the web-start queue (`/_web-start`) and the machine relay (`/_relay`).
5
5
  *
6
6
  * All three answer plain-text statuses, JSON payloads, and read capped JSON request bodies, and
7
7
  * each carried its own copy — two body readers that differed only in which message they rejected
@@ -0,0 +1,9 @@
1
+ /** What a call says when the machine at the address shows another key than the one it was added with. */
2
+ export declare const NOT_THE_MACHINE = "what answers at this address is not the machine that was added: add the machine again, with a new link";
3
+ export interface MachineCall {
4
+ method?: string;
5
+ headers?: Record<string, string>;
6
+ body?: string;
7
+ signal?: AbortSignal;
8
+ }
9
+ export declare function machineFetch(url: string, pin: string | undefined, init?: MachineCall): Promise<Response>;
@@ -3,50 +3,90 @@ import type { OpenAgentEvent } from '../events.js';
3
3
  import type { AgentMeta } from '../store/index.js';
4
4
  import type { StartAgentOptions, StartAgentResult } from './types.js';
5
5
  /**
6
- * The server-side half of "run on a connected device" (#1067). The local daemon holds the saved
7
- * device's token, so it - not the browser - drives the remote daemon: it POSTs the agent to the
6
+ * The server-side half of "run on a saved machine" (#1067). The local daemon holds this computer's
7
+ * key on the saved machine, so it - not the browser - drives the remote daemon: it POSTs the agent to the
8
8
  * remote's `/_relay/start` and then fetch-streams the remote's `/_relay/events` back into a local
9
9
  * {@link EventStream}, which the dashboard reads over its normal same-origin `onEvents` channel. So
10
- * the browser never talks cross-origin and the token never leaves the two daemons (issue #1067 (b)).
10
+ * the browser never talks cross-origin and the key never leaves the two daemons (issue #1067 (b)).
11
11
  *
12
- * Authentication is the shared-token cookie (#1051), sent daemon-to-daemon: `Cookie: oa_daemon=<token>` with no
13
- * `Origin` header. The remote's guard admits a matching cookie without the browser-only `?token=`
14
- * 302, and its `/_rpc` CSRF check (absent Origin passes) is not even on these raw routes.
12
+ * Every call but the ping names its project, by its repository's address
13
+ * (repository-address.ts): a project's folder, and so its id, is another one on each machine.
14
+ *
15
+ * The other OpenAgent listens on its own computer only. What answers at a machine's address is
16
+ * whatever that computer opened to the network, which lets this computer in once, with the code
17
+ * a machine's link carries ({@link enterRemote}), answers a key of this computer's own, and from
18
+ * then on passes each call that carries the key (`Authorization: Bearer`, no `Origin`) to its
19
+ * OpenAgent as that computer's own browser would have made it.
15
20
  */
16
- /** Where a relayed agent executes: the remote daemon's origin and its #1051 token. Memory-only. */
17
- export interface RemoteTarget {
21
+ /** How a machine is reached: where its OpenAgent answers, this computer's key there, and what the machine's own key is known by when its link said. */
22
+ export interface MachineAccess {
18
23
  url: string;
19
- token: string;
24
+ key: string;
25
+ pin?: string;
26
+ }
27
+ /** Where a relayed agent works: a machine, and the project there, by its repository's address. */
28
+ export interface RemoteTarget extends MachineAccess {
29
+ project: string;
20
30
  }
21
- /** The body a relay start forwards to the remote's `/_relay/start`. */
31
+ /** What a relay start forwards to the remote's `/_relay/start`, beside the project. */
22
32
  export interface RelayStartBody {
23
33
  prompt: string;
24
34
  options: StartAgentOptions;
25
35
  }
26
36
  /**
27
- * Health-check a saved device (#1072): a cookie'd `GET /_relay/ping`, true on any 2xx, false on a
28
- * non-2xx, an unreachable host, or the timeout. The token stays in memory for the check only, never
29
- * persisted, same as {@link startRemoteAgent}. This is how the browser's status dots learn reachable
30
- * from not: it has the tokens, the daemon does the cross-origin request.
37
+ * What a machine answers a relayed start with: a Start's own outcome, or `noProject` when it has
38
+ * no project cloned from the address the start named.
39
+ */
40
+ export type RelayStartResult = StartAgentResult | {
41
+ ok: false;
42
+ error: string;
43
+ noProject: true;
44
+ };
45
+ /**
46
+ * Health-check a saved machine (#1072): true when it answers this computer's key. This is how
47
+ * the browser's status dots learn reachable from not.
48
+ */
49
+ export declare function pingRemote(target: MachineAccess): Promise<boolean>;
50
+ /** The OpenAgent a saved machine runs, as its ping tells it; nothing for a machine that does not answer, or does not say. */
51
+ export declare function remoteVersion(target: MachineAccess): Promise<string | undefined>;
52
+ /** What asking to be let in came to: this computer's key there, or why not, in words. */
53
+ export type EnterResult = {
54
+ ok: true;
55
+ key: string;
56
+ } | {
57
+ ok: false;
58
+ error: string;
59
+ };
60
+ /**
61
+ * Ask a machine to let this computer in, with the code its link carries, under `name`. The code
62
+ * is good once: a link used before, or older than a few minutes, is refused.
63
+ */
64
+ export declare function enterRemote(door: string, code: string, name: string, pin?: string): Promise<EnterResult>;
65
+ /**
66
+ * Take this computer out of a machine: its key there stops working. Whether the machine did;
67
+ * one that cannot be reached keeps the key until this computer is removed there by hand.
31
68
  */
32
- export declare function pingRemote(target: RemoteTarget): Promise<boolean>;
69
+ export declare function leaveRemote(machine: MachineAccess & {
70
+ door: string;
71
+ }): Promise<boolean>;
33
72
  /**
34
- * Start an agent on the remote daemon and return its {@link StartAgentResult} (with the remote's own run
35
- * id). A non-2xx or a transport failure surfaces as an `ok: false` result the dashboard shows, the
36
- * same shape a local refusal has, so the caller does not special-case remote errors.
73
+ * Start an agent on the remote daemon, in its project cloned from `target.project`, and return
74
+ * what it answered (with the remote's own run id). A non-2xx or a transport failure surfaces as an
75
+ * `ok: false` result the dashboard shows, the same shape a local refusal has, so the caller does
76
+ * not special-case remote errors.
37
77
  */
38
- export declare function startRemoteAgent(target: RemoteTarget, body: RelayStartBody): Promise<StartAgentResult>;
78
+ export declare function startRemoteAgent(target: RemoteTarget, body: RelayStartBody): Promise<RelayStartResult>;
39
79
  /**
40
- * Relay one run-scoped RPC to the device that owns a remote agent (#1067 slice 2). The local daemon
41
- * holds the device token, so a read/diff/handoff/push/PR for a relayed agent runs ON the device: POST
42
- * {fn, args} to the remote's /_relay/rpc over the shared-token cookie (#1051) (no Origin), returning the device's
43
- * result. Throws on an unreachable device or a non-2xx so the caller falls back to its own empty/error
80
+ * Relay one run-scoped RPC to the machine that owns a remote agent (#1067 slice 2). The local daemon
81
+ * holds this computer's key there, so a read/diff/handoff/push/PR for a relayed agent runs ON the machine: POST
82
+ * {fn, args} to the remote's /_relay/rpc with the key (no Origin), returning the machine's
83
+ * result. Throws on an unreachable machine or a non-2xx so the caller falls back to its own empty/error
44
84
  * shape, the same way a failed local read does.
45
85
  */
46
86
  export declare function relayRpc(target: RemoteTarget, fn: string, args: unknown[]): Promise<unknown>;
47
87
  /**
48
88
  * Fetch-stream a remote agent's newline-delimited events into `onEvent` until the remote closes the
49
- * body, the agent ends, or `cancel()` is called. A 401 (the token was rotated) ends the stream
89
+ * body, the agent ends, or `cancel()` is called. A 401 (this computer was removed there) ends the stream
50
90
  * cleanly rather than as an error, so the dashboard sees a normal `done`, not a lost connection.
51
91
  * Returns a cancel function; calling it aborts the fetch and releases the reader.
52
92
  */
@@ -54,11 +94,12 @@ export declare function streamRemoteEvents(target: RemoteTarget, agentId: string
54
94
  /**
55
95
  * The local daemon's live relayed runs (#1067), keyed by the remote agent id. Registering an agent opens
56
96
  * an {@link EventStream} the dashboard reads through `onEvents`, fed by {@link streamRemoteEvents}
57
- * from the remote. This map is where a saved device's token lives daemon-side: in memory, for the
58
- * run's lifetime.
97
+ * from the remote. The target is the saved machine as it was at the Start. A machine is not
98
+ * removed while a run is at work on it ({@link working}); the runs that ended there before it
99
+ * was removed read as unreachable, and one added again answers for them with its new key ({@link rekey}).
59
100
  *
60
101
  * The `targets` map outlives the event pump (#1067 slice 2): a finished remote agent's post-run reads,
61
- * open-PR and merge still have to reach the device after its event stream has ended, so the device
102
+ * open-PR and merge still have to reach the machine after its event stream has ended, so the machine
62
103
  * target is kept until {@link dispose} clears it, not dropped when the stream closes.
63
104
  *
64
105
  * The `metas` map (#1077) holds a local {@link AgentMeta} stub per relayed agent so `onAgents` can show a
@@ -73,22 +114,26 @@ export declare class RelayedAgents {
73
114
  register(agentId: string, target: RemoteTarget, meta: AgentMeta, projectId: string): void;
74
115
  /** The live event stream for a relayed agent, or undefined when this daemon is not relaying it. */
75
116
  get(agentId: string | undefined): EventStream<OpenAgentEvent> | undefined;
76
- /** The device a relayed agent runs on, kept past the event stream so post-run push/PR still reach it. */
117
+ /** The machine a relayed agent runs on, kept past the event stream so post-run push/PR still reach it. */
77
118
  target(agentId: string | undefined): RemoteTarget | undefined;
119
+ /** Whether a run this daemon follows is still at work on the machine at `url`: its events still stream. */
120
+ working(url: string): boolean;
121
+ /** How the machine at `url` is reached since it was added again, for the runs kept from before: this computer's new key there, and the key the machine is known by. */
122
+ rekey(url: string, key: string, pin?: string): void;
78
123
  /** A project's relayed run stubs (#1077), newest-first, so `onAgents` can surface them in the list. */
79
124
  list(projectId: string): AgentMeta[];
80
125
  /** Fold each relayed event into the agent's list row via the store's own reducer (#1077), so the
81
- * local stub mirrors the device: the terminal status on `end`, the waiting flag while it is parked
126
+ * local stub mirrors the machine: the terminal status on `end`, the waiting flag while it is parked
82
127
  * (#785), the driver once its session starts. Events carry no write time, so this stamps its own. */
83
128
  private apply;
84
129
  /** Close a relayed agent's event stream (not its target). Idempotent. */
85
130
  private endStream;
86
- /** Stop every pump, close every stream, and forget every device target + list stub, on daemon shutdown. */
131
+ /** Stop every pump, close every stream, and forget every machine target + list stub, on daemon shutdown. */
87
132
  dispose(): void;
88
133
  }
89
134
  /**
90
- * Fold one relayed event into the memory-only row of a run on a device: what the device's own
91
- * card would say, kept here because that card is on the device. The events are the ones a run's
135
+ * Fold one relayed event into the memory-only row of a run on a machine: what the machine's own
136
+ * card would say, kept here because that card is on the machine. The events are the ones a run's
92
137
  * diary yields: the agent's session id, its cost, its end.
93
138
  */
94
139
  export declare function foldRelayedEvent(meta: AgentMeta, event: OpenAgentEvent, at: string): AgentMeta;
@@ -7,6 +7,7 @@ import type { BridgeBrowserOwner } from '../bridge-browser.js';
7
7
  import type { ProjectErrorsReader } from '../project-errors.js';
8
8
  import type { AddProjectResult, RemoveProjectResult, StartAgentOptions, StartAgentResult } from './types.js';
9
9
  import type { AgentMeta } from '../store/index.js';
10
+ import type { RemoteTarget } from './remote-run.js';
10
11
  /** Wired by the daemon so `sendStart` can reach the daemon's own `startAgent` closure. */
11
12
  export type StartAgentHandler = (prompt: string, options: StartAgentOptions, projectId?: string) => StartAgentResult | Promise<StartAgentResult>;
12
13
  /** Wired by the daemon so `sendAddProject` can install + register a repo (#433). */
@@ -14,19 +15,20 @@ export type AddProjectHandler = (path: string, share: boolean) => AddProjectResu
14
15
  /** Wired by the daemon so `sendRemoveProject` can take a project off the list, by its id, and with `files` remove what OpenAgent left in its folder. */
15
16
  export type RemoveProjectHandler = (projectId: string, files: boolean) => RemoveProjectResult | Promise<RemoveProjectResult>;
16
17
  /** Resolve an agent to its live event stream: the relay feeds `onEvents` from its own in-memory stream
17
- * rather than a file on disk (#426), and the daemon feeds an agent it is relaying from a device (#1067).
18
+ * rather than a file on disk (#426), and the daemon feeds an agent it is relaying from a machine (#1067).
18
19
  * Returns undefined when there is no in-memory stream, so `onEvents` falls back to tailing the log. */
19
20
  export type EventsSource = (projectId: string, agentId?: string) => AsyncIterable<OpenAgentEvent> | undefined;
20
- /** Look up the device a relayed agent (#1067) executes on, or undefined for an ordinary local agent. The
21
+ /** Look up the machine a relayed agent (#1067) executes on, or undefined for an ordinary local agent. The
21
22
  * daemon wires this from its live relayed-agent map; a run-scoped RPC uses it to forward a remote agent's
22
- * read/steer/handoff to that device instead of resolving a (nonexistent) local checkout. */
23
+ * read/steer/handoff to that machine instead of resolving a (nonexistent) local checkout. */
23
24
  export interface RemoteAgents {
24
- target(agentId: string | undefined): {
25
- url: string;
26
- token: string;
27
- } | undefined;
25
+ target(agentId: string | undefined): RemoteTarget | undefined;
28
26
  /** A project's relayed run stubs (#1077), so `onAgents` can show a remote agent in the list and re-open it after a reload. */
29
27
  list(projectId: string): AgentMeta[];
28
+ /** Whether a run relayed from here is still at work on the machine at `url`. */
29
+ working(url: string): boolean;
30
+ /** How the machine at `url` is reached since it was added again, for the runs kept from before. */
31
+ rekey(url: string, key: string, pin?: string): void;
30
32
  }
31
33
  /**
32
34
  * What every RPC acts through.
@@ -40,10 +42,10 @@ export interface DashboardContext {
40
42
  startAgent: StartAgentHandler;
41
43
  addProject: AddProjectHandler;
42
44
  removeProject: RemoveProjectHandler;
43
- /** The in-memory event stream for an agent relayed from a connected device (#1067), else undefined. */
45
+ /** The in-memory event stream for an agent relayed from a saved machine (#1067), else undefined. */
44
46
  eventsSource: EventsSource;
45
47
  /** The relayed-agent lookup (#1067 slice 2), so a run-scoped RPC can tell a local agent from one
46
- * running on a connected device and forward the call there. */
48
+ * running on a saved machine and forward the call there. */
47
49
  remote: RemoteAgents;
48
50
  /** The user-preferences store (#410), over the registry file. */
49
51
  preferences: PreferencesStore;
@@ -72,16 +74,12 @@ export declare function isSameOriginRequest(req: IncomingMessage): boolean;
72
74
  * the mount, `sendStart` included, is reachable from a page the user merely visited.
73
75
  *
74
76
  * The `Host` header is what still gives the attacker away: it carries the name the browser was
75
- * asked for (`evil.com`), not the address it resolved to. So when we are bound to loopback, the
76
- * only `Host` a real user's browser can send is a loopback one (or the bound address itself) —
77
- * anything else is a rebound name and is rejected. An absent `Host` is rejected too when we are
78
- * enforcing: HTTP/1.1 requires it, and every browser sends it.
79
- *
80
- * A non-loopback bind (`--host`, #1051) is reached by a hostname we cannot predict, so there is
81
- * no allowlist to check against; that case gates behind the shared daemon token instead. Hosts
82
- * that never pass a bind host at all (the relay, which serves a public domain) are unaffected.
77
+ * asked for (`evil.com`), not the address it resolved to. The dashboard listens on this
78
+ * computer's own address only, so the only `Host` a real user's browser can send is a loopback
79
+ * one — anything else is a rebound name and is rejected. An absent `Host` is rejected too:
80
+ * HTTP/1.1 requires it, and every browser sends it.
83
81
  */
84
- export declare function isExpectedHost(req: IncomingMessage, boundHost: string | undefined): boolean;
82
+ export declare function isExpectedHost(req: IncomingMessage): boolean;
85
83
  /** Where the dashboard's RPCs live. One prefix, so the static handler can decline it by path. */
86
84
  export declare const RPC_PREFIX = "/_rpc";
87
85
  /**
@@ -90,16 +88,12 @@ export declare const RPC_PREFIX = "/_rpc";
90
88
  * `sendStart` reaches the daemon's own `startAgent` through the wired {@link DashboardContext}.
91
89
  *
92
90
  * Cross-origin POSTs are rejected (CSRF: a page on evil.com must not steer or start a session), as
93
- * are requests carrying someone else's `Host` when we are bound to loopback (DNS rebinding: the
94
- * same page must not reach us by pointing its own name at `127.0.0.1`). Pass `opts.host` — the
95
- * address the server is bound to — to enable that second check. Returns whether the request was
96
- * the RPC surface's.
91
+ * are requests carrying someone else's `Host` (DNS rebinding: the same page must not reach us by
92
+ * pointing its own name at `127.0.0.1`). Returns whether the request was the RPC surface's.
97
93
  *
98
94
  * This replaced Telefunc (F3), which required a build-time transform over every `.telefunc.ts`
99
95
  * file, a registration table pinning each RPC to the client-baked key of the *dashboard* source
100
96
  * path it was re-exported from, and a request-context indirection for wiring that never varied
101
97
  * per request. What it bought over this was type-safety across a package boundary that A7 removed.
102
98
  */
103
- export declare function makeRpcMount(context: DashboardContext, opts?: {
104
- host?: string;
105
- }): (req: IncomingMessage, res: ServerResponse) => Promise<boolean>;
99
+ export declare function makeRpcMount(context: DashboardContext): (req: IncomingMessage, res: ServerResponse) => Promise<boolean>;
@@ -0,0 +1,31 @@
1
+ /**
2
+ * The branch agents start from in the project at `cwd`: origin's default branch as this clone has
3
+ * it, else the branch the folder is on (a project with no remote starts an agent from its last
4
+ * local commit). `ref` is what git is asked, `name` what a person reads. None where the folder is
5
+ * on no branch, or is no repository.
6
+ */
7
+ export declare function startBranch(cwd: string): Promise<{
8
+ ref: string;
9
+ name: string;
10
+ } | undefined>;
11
+ /** A skill that is in the folder and not on the branch agents start from. */
12
+ export interface Waiting {
13
+ /** The branch it has yet to reach, by name. */
14
+ branch: string;
15
+ /** Whether the branch the folder is on has it: an agent started from that branch does. */
16
+ here: boolean;
17
+ }
18
+ /**
19
+ * Which of the skills `names`, all in the project's folder, are waiting to reach the branch agents
20
+ * start from. A skill is said to be waiting only when that is known: an agent's checkout fetches
21
+ * the remote before it starts, so before a skill is called waiting against a remote branch, this
22
+ * clone's copy of that branch is fetched too (at most once a minute per project), or a pull
23
+ * request merged a moment ago would keep its skill waiting here.
24
+ */
25
+ export declare function waitingSkills(cwd: string, names: readonly string[]): Promise<{
26
+ start?: {
27
+ ref: string;
28
+ name: string;
29
+ };
30
+ waiting: Map<string, Waiting>;
31
+ }>;
@@ -75,7 +75,7 @@ export interface StartAgentOptions {
75
75
  /**
76
76
  * The branch the agent's own branch starts from, as this machine has it, commits that are not
77
77
  * pushed included: the launcher's "My local branch" pick. Absent, origin's default branch. A
78
- * word that is no branch name refuses the Start. Not sent to a device: its branches are its own.
78
+ * word that is no branch name refuses the Start. Not sent to another machine: its branches are its own.
79
79
  */
80
80
  base?: string;
81
81
  /**
@@ -84,20 +84,12 @@ export interface StartAgentOptions {
84
84
  */
85
85
  then?: string;
86
86
  /**
87
- * Run this session on a connected device (#1067): the local daemon relays the start to the remote
88
- * daemon at `url` (authenticating with `token` as the `oa_daemon` cookie) and streams its events
89
- * back into the local agent view. The device `label` rides along (memory-only, like `url`/`token`) so
90
- * the local session list + notice can show which device the agent is on after a reload (#1077).
91
- * Memory-only relay config the dashboard sets at submit time from a saved device. NEVER persisted to
92
- * Preferences or the registry: a device token is a per-browser secret. Absent = run locally.
93
- * Stripped before the start is forwarded, so the remote starts an ordinary local run and does not
94
- * relay onward.
87
+ * Run this session on a saved machine (#1067), named by its id: the local daemon relays the
88
+ * start to that machine's daemon, which starts it in its own copy of the project, and streams
89
+ * its events back into the local agent view. Absent = run on this machine. Stripped before the
90
+ * start is forwarded, so the machine starts an ordinary local run and does not relay onward.
95
91
  */
96
- remote?: {
97
- url: string;
98
- token: string;
99
- label?: string;
100
- };
92
+ machine?: string;
101
93
  }
102
94
  /** The outcome of a Start attempt (#345): the id of the run the project's start hook began, or why there is none. */
103
95
  export type StartAgentResult = {
@@ -22,18 +22,18 @@ export declare function resolveProjectPath(projectId: string): Promise<string |
22
22
  export declare function resolveAgentPath(projectId: string, agentId?: string): Promise<string | undefined>;
23
23
  /**
24
24
  * The in-memory {@link EventsSource} (#426). It answers only for a run this daemon is relaying
25
- * from a connected device (#1067) — such a run has no diary on this machine, since it works in a
25
+ * from a saved machine (#1067) — such a run has no diary on this machine, since it works in a
26
26
  * checkout over there — and returns undefined for an ordinary local run, whose diary `onEvents`
27
27
  * tails off disk.
28
28
  */
29
29
  export declare function contextEventsSource(): EventsSource;
30
30
  /**
31
31
  * The relayed-agent lookup (#1067 slice 2). A run-scoped RPC uses it to tell an ordinary local agent
32
- * (resolve a local checkout) from one running on a connected device (forward the call there).
32
+ * (resolve a local checkout) from one running on a saved machine (forward the call there).
33
33
  *
34
34
  * The one accessor with a default rather than a throw, because "unwired" has a real meaning here:
35
- * a call arriving over `/_relay/rpc` is the *device* side of the relay, and the agent it names is
36
- * local to that device. Forwarding it onward would be a loop, so the honest answer there is that
35
+ * a call arriving over `/_relay/rpc` is the *machine* side of the relay, and the agent it names is
36
+ * local to that machine. Forwarding it onward would be a loop, so the honest answer there is that
37
37
  * nothing is relayed from here.
38
38
  */
39
39
  export declare function contextRemote(): RemoteAgents;
@@ -65,7 +65,7 @@ export declare function sendRemoveWorktree(projectId: string, agentId: string):
65
65
  export declare function sendDeleteAgent(projectId: string, agentId: string): Promise<DeleteAgentResult>;
66
66
  /**
67
67
  * Start a run in the project (#405, #1774): the project's own `start` hook line, reached through
68
- * the daemon's wired `startAgent` (which relays to a connected device when the options name
68
+ * the daemon's wired `startAgent` (which relays to a saved machine when the options name
69
69
  * one). Answers the id of the run the hook began, or why there is none: a project without the
70
70
  * line cannot start a run from here.
71
71
  */
@@ -28,7 +28,7 @@ export type LiveFeedEvent = OpenAgentEvent | StreamSync | PartialMessage;
28
28
  * The `agentId` names the run whose diary is followed; without one there is nothing to stream.
29
29
  *
30
30
  * Two sources, chosen by what is wired. An in-memory stream wins: an agent the daemon is relaying
31
- * from a device (#1067). Otherwise the on-disk log. The daemon's source answers only for relayed
31
+ * from a machine (#1067). Otherwise the on-disk log. The daemon's source answers only for relayed
32
32
  * runs, so an ordinary local agent falls through to tailing the log.
33
33
  *
34
34
  * Only the on-disk tail sends the {@link StreamSync} marker: the in-memory sources have no replay
@@ -6,8 +6,9 @@ export { onPreferences, savePreferences, patchPreferences, onProjectPresets, sav
6
6
  export { type EditorInfo } from '../dashboard/open-in-app.js';
7
7
  export { onQuota } from './quota.js';
8
8
  export { onModels } from './models.js';
9
- export { checkDevices, type DeviceCheck } from './devices.js';
9
+ export { onMachines, sendAddMachine, sendRemoveMachine, onMachinesReachable, onMachineVersions, type Machine, type AddMachineResult, type MachineVersions } from './machines.js';
10
10
  export { onModules, runModuleCommand, readModule, type DashboardModule, type ModuleCommandResult, type ModuleReadResult } from './modules.js';
11
+ export { onProjectSkills, sendChangeSkills, sendCommitSkills, type ProjectSkills, type ProjectSkill, type ChangeSkillsResult } from './skills.js';
11
12
  import { streamAgentEvents } from './events.js';
12
13
  /** One RPC: called with whatever the browser sent, answering with whatever JSON.stringify keeps. */
13
14
  export type RpcHandler = (...args: never[]) => unknown;