@openagt/dashboard 0.10.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.
- package/README.md +1 -6
- package/dist/built-in.d.ts +8 -1
- package/dist/built-in.d.ts.map +1 -1
- package/dist/built-in.js +12 -3
- package/dist/built-in.js.map +1 -1
- package/dist/cli.d.ts +4 -10
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +11 -67
- package/dist/cli.js.map +1 -1
- package/dist/client.d.ts +2 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +3 -4
- package/dist/client.js.map +1 -1
- package/dist/daemon-runtime.d.ts +12 -12
- package/dist/daemon-runtime.d.ts.map +1 -1
- package/dist/daemon-runtime.js +96 -35
- package/dist/daemon-runtime.js.map +1 -1
- package/dist/daemon.d.ts +3 -14
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +15 -26
- package/dist/daemon.js.map +1 -1
- package/dist/dashboard/bridge-endpoints.d.ts +5 -5
- package/dist/dashboard/bridge-endpoints.js +5 -5
- package/dist/dashboard/http.d.ts +1 -1
- package/dist/dashboard/http.js +1 -1
- package/dist/dashboard/machine-call.d.ts +10 -0
- package/dist/dashboard/machine-call.d.ts.map +1 -0
- package/dist/dashboard/machine-call.js +86 -0
- package/dist/dashboard/machine-call.js.map +1 -0
- package/dist/dashboard/relay-endpoints.d.ts +26 -17
- package/dist/dashboard/relay-endpoints.d.ts.map +1 -1
- package/dist/dashboard/relay-endpoints.js +70 -27
- package/dist/dashboard/relay-endpoints.js.map +1 -1
- package/dist/dashboard/remote-run.d.ts +77 -32
- package/dist/dashboard/remote-run.d.ts.map +1 -1
- package/dist/dashboard/remote-run.js +120 -42
- package/dist/dashboard/remote-run.js.map +1 -1
- package/dist/dashboard/rpc-serve.d.ts +19 -25
- package/dist/dashboard/rpc-serve.d.ts.map +1 -1
- package/dist/dashboard/rpc-serve.js +11 -22
- package/dist/dashboard/rpc-serve.js.map +1 -1
- package/dist/dashboard/screen.d.ts +53 -0
- package/dist/dashboard/screen.d.ts.map +1 -0
- package/dist/dashboard/screen.js +175 -0
- package/dist/dashboard/screen.js.map +1 -0
- package/dist/dashboard/server.d.ts +18 -19
- package/dist/dashboard/server.d.ts.map +1 -1
- package/dist/dashboard/server.js +52 -81
- package/dist/dashboard/server.js.map +1 -1
- package/dist/dashboard/types.d.ts +6 -14
- package/dist/dashboard/types.d.ts.map +1 -1
- package/dist/dashboard/web-start-endpoints.d.ts +2 -2
- package/dist/dashboard/web-start-endpoints.js +1 -1
- package/dist/dashboard-bundle/assets/main-9Xb8Ao4p.css +2 -0
- package/dist/dashboard-bundle/assets/main-DTyyQ0jM.js +140 -0
- package/dist/dashboard-bundle/assets/{module-gKz-ZvkG.js → module-DKd-4BTU.js} +4 -4
- package/dist/dashboard-bundle/host/module.js +1 -1
- package/dist/dashboard-bundle/index.html +3 -3
- package/dist/dashboard-rpc/context.d.ts +4 -4
- package/dist/dashboard-rpc/context.js +5 -5
- package/dist/dashboard-rpc/context.js.map +1 -1
- package/dist/dashboard-rpc/control.d.ts +1 -1
- package/dist/dashboard-rpc/control.js +7 -7
- package/dist/dashboard-rpc/control.js.map +1 -1
- package/dist/dashboard-rpc/events.d.ts +1 -1
- package/dist/dashboard-rpc/events.js +1 -1
- package/dist/dashboard-rpc/index.d.ts +1 -1
- package/dist/dashboard-rpc/index.d.ts.map +1 -1
- package/dist/dashboard-rpc/index.js +3 -3
- package/dist/dashboard-rpc/index.js.map +1 -1
- package/dist/dashboard-rpc/machines.d.ts +52 -0
- package/dist/dashboard-rpc/machines.d.ts.map +1 -0
- package/dist/dashboard-rpc/machines.js +82 -0
- package/dist/dashboard-rpc/machines.js.map +1 -0
- package/dist/dashboard-rpc/modules.d.ts +1 -1
- package/dist/dashboard-rpc/modules.js +2 -2
- package/dist/dashboard-rpc/modules.js.map +1 -1
- package/dist/dashboard-rpc/projects.d.ts +2 -0
- package/dist/dashboard-rpc/projects.d.ts.map +1 -1
- package/dist/dashboard-rpc/projects.js +3 -2
- package/dist/dashboard-rpc/projects.js.map +1 -1
- package/dist/dashboard-rpc/reads.d.ts +3 -4
- package/dist/dashboard-rpc/reads.d.ts.map +1 -1
- package/dist/dashboard-rpc/reads.js +5 -6
- package/dist/dashboard-rpc/reads.js.map +1 -1
- package/dist/dashboard-rpc/relay-agent.d.ts +3 -3
- package/dist/dashboard-rpc/relay-agent.js +3 -3
- package/dist/dashboard-rpc/relay-dispatch.d.ts +4 -4
- package/dist/dashboard-rpc/relay-dispatch.d.ts.map +1 -1
- package/dist/dashboard-rpc/relay-dispatch.js +7 -7
- package/dist/dashboard-rpc/relay-dispatch.js.map +1 -1
- package/dist/dashboard-rpc/test-context.js +1 -1
- package/dist/dashboard-rpc/test-context.js.map +1 -1
- package/dist/events.d.ts +4 -3
- package/dist/events.d.ts.map +1 -1
- package/dist/loopback-host.d.ts +3 -5
- package/dist/loopback-host.d.ts.map +1 -1
- package/dist/loopback-host.js +3 -5
- package/dist/loopback-host.js.map +1 -1
- package/dist/machine-link.d.ts +21 -0
- package/dist/machine-link.d.ts.map +1 -0
- package/dist/machine-link.js +20 -0
- package/dist/machine-link.js.map +1 -0
- package/dist/module-server.d.ts +1 -1
- package/dist/module-types/dashboard/lib/draft-handoff.d.ts +5 -9
- package/dist/module-types/dashboard/module/index.d.ts +45 -0
- package/dist/module-types/src/built-in.d.ts +8 -1
- package/dist/module-types/src/client.d.ts +2 -1
- package/dist/module-types/src/dashboard/bridge-endpoints.d.ts +5 -5
- package/dist/module-types/src/dashboard/http.d.ts +1 -1
- package/dist/module-types/src/dashboard/machine-call.d.ts +9 -0
- package/dist/module-types/src/dashboard/remote-run.d.ts +77 -32
- package/dist/module-types/src/dashboard/rpc-serve.d.ts +19 -25
- package/dist/module-types/src/dashboard/types.d.ts +6 -14
- package/dist/module-types/src/dashboard-rpc/context.d.ts +4 -4
- package/dist/module-types/src/dashboard-rpc/control.d.ts +1 -1
- package/dist/module-types/src/dashboard-rpc/events.d.ts +1 -1
- package/dist/module-types/src/dashboard-rpc/index.d.ts +1 -1
- package/dist/module-types/src/dashboard-rpc/machines.d.ts +51 -0
- package/dist/module-types/src/dashboard-rpc/modules.d.ts +1 -1
- package/dist/module-types/src/dashboard-rpc/projects.d.ts +2 -0
- package/dist/module-types/src/dashboard-rpc/reads.d.ts +3 -4
- package/dist/module-types/src/dashboard-rpc/relay-agent.d.ts +3 -3
- package/dist/module-types/src/events.d.ts +4 -3
- package/dist/module-types/src/loopback-host.d.ts +3 -5
- package/dist/module-types/src/machine-link.d.ts +20 -0
- package/dist/module-types/src/registry.d.ts +59 -16
- package/dist/module-types/src/repository-address.d.ts +22 -0
- package/dist/module-types/src/screens.d.ts +13 -0
- package/dist/module-types/src/store/agent-store.d.ts +2 -2
- package/dist/module-types/src/version.d.ts +1 -0
- package/dist/package-services.d.ts +27 -0
- package/dist/package-services.d.ts.map +1 -0
- package/dist/package-services.js +62 -0
- package/dist/package-services.js.map +1 -0
- package/dist/registry.d.ts +59 -16
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +91 -20
- package/dist/registry.js.map +1 -1
- package/dist/repository-address.d.ts +23 -0
- package/dist/repository-address.d.ts.map +1 -0
- package/dist/repository-address.js +38 -0
- package/dist/repository-address.js.map +1 -0
- package/dist/screens.d.ts +14 -0
- package/dist/screens.d.ts.map +1 -0
- package/dist/screens.js +40 -0
- package/dist/screens.js.map +1 -0
- package/dist/store/agent-store.d.ts +2 -2
- package/dist/store/agent-store.d.ts.map +1 -1
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +26 -0
- package/dist/version.js.map +1 -0
- package/package.json +13 -10
- package/dist/dashboard-bundle/assets/main-Q7JMdMJI.css +0 -2
- package/dist/dashboard-bundle/assets/main-fDZWGOub.js +0 -140
- package/dist/dashboard-rpc/devices.d.ts +0 -9
- package/dist/dashboard-rpc/devices.d.ts.map +0 -1
- package/dist/dashboard-rpc/devices.js +0 -12
- package/dist/dashboard-rpc/devices.js.map +0 -1
- package/dist/install.d.ts +0 -31
- package/dist/install.d.ts.map +0 -1
- package/dist/install.js +0 -54
- package/dist/install.js.map +0 -1
- package/dist/module-types/src/dashboard-rpc/devices.d.ts +0 -8
- package/dist/module-types/src/openagent-gitignore.d.ts +0 -11
- package/dist/openagent-gitignore.d.ts +0 -12
- package/dist/openagent-gitignore.d.ts.map +0 -1
- package/dist/openagent-gitignore.js +0 -19
- package/dist/openagent-gitignore.js.map +0 -1
|
@@ -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
|
|
7
|
-
*
|
|
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
|
|
10
|
+
* the browser never talks cross-origin and the key never leaves the two daemons (issue #1067 (b)).
|
|
11
11
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
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
|
-
/**
|
|
17
|
-
export interface
|
|
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
|
-
|
|
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
|
-
/**
|
|
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
|
-
*
|
|
28
|
-
*
|
|
29
|
-
|
|
30
|
-
|
|
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
|
|
69
|
+
export declare function leaveRemote(machine: MachineAccess & {
|
|
70
|
+
door: string;
|
|
71
|
+
}): Promise<boolean>;
|
|
33
72
|
/**
|
|
34
|
-
* Start an agent on the remote daemon
|
|
35
|
-
* id). A non-2xx or a transport failure surfaces as an
|
|
36
|
-
* same shape a local refusal has, so the caller does
|
|
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<
|
|
78
|
+
export declare function startRemoteAgent(target: RemoteTarget, body: RelayStartBody): Promise<RelayStartResult>;
|
|
39
79
|
/**
|
|
40
|
-
* Relay one run-scoped RPC to the
|
|
41
|
-
* holds
|
|
42
|
-
* {fn, args} to the remote's /_relay/rpc
|
|
43
|
-
* result. Throws on an unreachable
|
|
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 (
|
|
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.
|
|
58
|
-
* run
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
91
|
-
* card would say, kept here because that card is on the
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
76
|
-
* only `Host` a real user's browser can send is a loopback
|
|
77
|
-
* anything else is a rebound name and is rejected. An absent `Host` is rejected too
|
|
78
|
-
*
|
|
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
|
|
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`
|
|
94
|
-
*
|
|
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,
|
|
104
|
-
host?: string;
|
|
105
|
-
}): (req: IncomingMessage, res: ServerResponse) => Promise<boolean>;
|
|
99
|
+
export declare function makeRpcMount(context: DashboardContext): (req: IncomingMessage, res: ServerResponse) => Promise<boolean>;
|
|
@@ -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
|
|
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
|
|
88
|
-
* daemon
|
|
89
|
-
* back into the local agent view.
|
|
90
|
-
*
|
|
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
|
-
|
|
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
|
|
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
|
|
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 *
|
|
36
|
-
* local to 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
|
|
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
|
|
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,7 +6,7 @@ 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 {
|
|
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
11
|
export { onProjectSkills, sendChangeSkills, sendCommitSkills, type ProjectSkills, type ProjectSkill, type ChangeSkillsResult } from './skills.js';
|
|
12
12
|
import { streamAgentEvents } from './events.js';
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/** A saved machine as the browser sees it: no key. */
|
|
2
|
+
export interface Machine {
|
|
3
|
+
id: string;
|
|
4
|
+
label: string;
|
|
5
|
+
url: string;
|
|
6
|
+
}
|
|
7
|
+
export type AddMachineResult = {
|
|
8
|
+
ok: true;
|
|
9
|
+
machine: Machine;
|
|
10
|
+
} | {
|
|
11
|
+
ok: false;
|
|
12
|
+
error: string;
|
|
13
|
+
};
|
|
14
|
+
/** The saved machines, newest first. */
|
|
15
|
+
export declare function onMachines(): Promise<Machine[]>;
|
|
16
|
+
/**
|
|
17
|
+
* Save the machine a pasted link names: the link another OpenAgent gives for a new device. This
|
|
18
|
+
* computer is let in there with the link's code, once, and keeps the key it is answered. Adding
|
|
19
|
+
* a machine again, with a new link, replaces its name and the key, and the key it had there
|
|
20
|
+
* before is taken out.
|
|
21
|
+
*/
|
|
22
|
+
export declare function sendAddMachine(pasted: string, label?: string): Promise<AddMachineResult>;
|
|
23
|
+
export type RemoveMachineResult = {
|
|
24
|
+
ok: true;
|
|
25
|
+
} | {
|
|
26
|
+
ok: false;
|
|
27
|
+
error: string;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Take a saved machine off the list, and this computer out of the machine: its key there stops
|
|
31
|
+
* working. Not while a run is at work there, which is read with that key. Taking the key out is
|
|
32
|
+
* not waited for: a machine that cannot be reached right now keeps it until this computer is
|
|
33
|
+
* removed there, among its devices.
|
|
34
|
+
*/
|
|
35
|
+
export declare function sendRemoveMachine(id: string): Promise<RemoveMachineResult>;
|
|
36
|
+
/** Whether each saved machine answers right now, by id: one short call to each, with this computer's key. */
|
|
37
|
+
export declare function onMachinesReachable(): Promise<Record<string, boolean>>;
|
|
38
|
+
/** This computer's OpenAgent, and the one each saved machine runs. */
|
|
39
|
+
export interface MachineVersions {
|
|
40
|
+
/** This computer's own. */
|
|
41
|
+
version: string;
|
|
42
|
+
/** Each saved machine, with its version when it answers and says. */
|
|
43
|
+
machines: (Machine & {
|
|
44
|
+
version?: string;
|
|
45
|
+
})[];
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* The saved machines with the OpenAgent each runs, beside this computer's own: how a page tells
|
|
49
|
+
* that a machine fell behind this computer. One short call to each, with this computer's key.
|
|
50
|
+
*/
|
|
51
|
+
export declare function onMachineVersions(): Promise<MachineVersions>;
|
|
@@ -38,7 +38,7 @@ export declare function runModuleCommand(projectId: string, pkg: string, args: s
|
|
|
38
38
|
* Call read `name` of a module's server part in one project: how a module's browser part reads
|
|
39
39
|
* what a command cannot answer fast enough. Refused for an unknown project, a package that is not
|
|
40
40
|
* a module of that project, and a module with no server part. A read whose input names a run this
|
|
41
|
-
* daemon relays to a
|
|
41
|
+
* daemon relays to a saved machine (`input.agentId`) is read over there, by that machine's own
|
|
42
42
|
* copy of the module, since the run's checkout is there.
|
|
43
43
|
*/
|
|
44
44
|
export declare function readModule(projectId: string, pkg: string, name: string, input: unknown): Promise<ModuleReadResult>;
|
|
@@ -58,6 +58,8 @@ export interface ProjectLauncher {
|
|
|
58
58
|
gitHost: boolean;
|
|
59
59
|
/** Whether the project's repository has an `origin` remote; without one nothing can be published, so the publish menu stops at the commit. */
|
|
60
60
|
remote: boolean;
|
|
61
|
+
/** The address the project's repository was cloned from, the name another machine knows the project by; absent, the project cannot be sent to one. */
|
|
62
|
+
address?: string;
|
|
61
63
|
/**
|
|
62
64
|
* The two branches an agent can start from here, for the launcher's "start from" chip: `main`,
|
|
63
65
|
* the name of origin's default branch, and `local`, the branch the project's folder is on now.
|
|
@@ -31,7 +31,7 @@ import type { BridgeAnswer, BridgeContact, BridgeVersion } from '../dashboard/br
|
|
|
31
31
|
* may have just self-healed a dead agent to `stopped` (#716), and that freshly-archived row can
|
|
32
32
|
* lag `listAgents` by a poll — keeping it regardless leaves the row visible with no flicker.
|
|
33
33
|
*
|
|
34
|
-
* An agent relayed to a
|
|
34
|
+
* An agent relayed to a saved machine (#1067) lives only in the daemon's memory, never on disk, so
|
|
35
35
|
* its in-memory stub is merged in too (#1077): that is what re-opens it after a dashboard reload
|
|
36
36
|
* instead of losing it.
|
|
37
37
|
*/
|
|
@@ -168,9 +168,8 @@ export declare function onBridgeStatus(): Promise<{
|
|
|
168
168
|
*
|
|
169
169
|
* Only while the bridge is on, so a daemon with the feature off never hands the secret to a
|
|
170
170
|
* page. Revealing it here is not a new exposure: anyone who can load this dashboard can already
|
|
171
|
-
* start runs on this machine
|
|
172
|
-
*
|
|
173
|
-
* `~/.openagent.json` and copy a field out of it.
|
|
171
|
+
* start runs on this machine. What it replaces is the alternative, which was telling people to
|
|
172
|
+
* open `~/.openagent.json` and copy a field out of it.
|
|
174
173
|
*/
|
|
175
174
|
export declare function onBridgeToken(): Promise<string | null>;
|
|
176
175
|
/**
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Run a run-scoped RPC locally, or relay it to the
|
|
3
|
-
* relaying to a
|
|
2
|
+
* Run a run-scoped RPC locally, or relay it to the machine when `agentId` names an agent this daemon is
|
|
3
|
+
* relaying to a saved one (#1067 slice 2). For an ordinary local agent the remote lookup is empty and
|
|
4
4
|
* `local()` runs unchanged. For a remote agent there is no local checkout, so the call is forwarded to the
|
|
5
|
-
*
|
|
5
|
+
* machine with this computer's key there; if the machine is unreachable, or no longer lets this computer in, `unreachable` is returned - the same empty/error
|
|
6
6
|
* shape `local()` gives on a failed read - so the caller never special-cases a remote agent.
|
|
7
7
|
*/
|
|
8
8
|
export declare function relayOr<T>(agentId: string | undefined, fn: string, args: unknown[], local: () => Promise<T>, unreachable: T): Promise<T>;
|
|
@@ -102,11 +102,12 @@ export type OpenAgentEvent = {
|
|
|
102
102
|
event: DriverEvent;
|
|
103
103
|
}
|
|
104
104
|
/**
|
|
105
|
-
* A live screen something the agent ran is showing:
|
|
106
|
-
*
|
|
105
|
+
* A live screen something the agent ran is showing: where it answers, on the loopback of the
|
|
106
|
+
* computer the run is on, live while it is the newest open screen at that address and the run
|
|
107
107
|
* has not ended. `label` names what it showed then. The same address with `ended` says the
|
|
108
108
|
* screen has gone. A diary line a command appends itself (agent-driver's `DIARY_ENV`);
|
|
109
|
-
* OpenAgent
|
|
109
|
+
* OpenAgent passes a watcher's calls on to the address (dashboard/screen.ts) and knows nothing
|
|
110
|
+
* of what the screen is.
|
|
110
111
|
*/
|
|
111
112
|
| {
|
|
112
113
|
kind: 'screen';
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Loopback-address helpers,
|
|
3
|
-
* token, #1051) and the RPC mount (rejecting a rebound `Host`). A leaf module on purpose:
|
|
4
|
-
* `daemon.ts` imports the dashboard, so the mount cannot import these back out of it.
|
|
2
|
+
* Loopback-address helpers, for the RPC mount (rejecting a cross-origin page and a rebound `Host`).
|
|
5
3
|
*/
|
|
6
4
|
/**
|
|
7
|
-
* True when `host` is a loopback address the browser reaches without leaving the machine
|
|
8
|
-
* A bind-all (`0.0.0.0`, `::`) or a routable address is not
|
|
5
|
+
* True when `host` is a loopback address the browser reaches without leaving the machine.
|
|
6
|
+
* A bind-all (`0.0.0.0`, `::`) or a routable address is not.
|
|
9
7
|
*
|
|
10
8
|
* The IPv4 check matches the whole `127.0.0.0/8` range but only as an address: a bare
|
|
11
9
|
* `startsWith('127.')` also accepts a *registrable name* like `127.evil.com`, which is exactly the
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read the link another computer's OpenAgent gives for a new device (its Settings, Devices, Add
|
|
3
|
+
* device): where this computer is let in, and the code that lets it in once. The code rides the
|
|
4
|
+
* link after the `#`. A server's link carries one thing more after the code and a dot: what the
|
|
5
|
+
* server's key is known by. Not a web address is `null`, and so is a link with no code.
|
|
6
|
+
*
|
|
7
|
+
* A leaf with no Node in it: the dashboard reads a paste with it as the person types, and the
|
|
8
|
+
* daemon reads it again before it asks to be let in.
|
|
9
|
+
*/
|
|
10
|
+
export interface MachineLink {
|
|
11
|
+
/** Where the other OpenAgent answers, as an origin (`http://studio.local:4201`). */
|
|
12
|
+
url: string;
|
|
13
|
+
/** Where this computer asks to be let in, and later takes itself out: the link without its code. */
|
|
14
|
+
door: string;
|
|
15
|
+
/** The code, good once. */
|
|
16
|
+
code: string;
|
|
17
|
+
/** What the machine's key is known by, when the link says: a call then goes only to a machine that shows that key. */
|
|
18
|
+
pin?: string;
|
|
19
|
+
}
|
|
20
|
+
export declare function parseMachineLink(pasted: string): MachineLink | null;
|