@openagt/dashboard 0.10.0 → 0.12.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 +18 -2
- package/dist/built-in.d.ts.map +1 -1
- package/dist/built-in.js +29 -6
- 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/clone-project.d.ts +69 -0
- package/dist/clone-project.d.ts.map +1 -0
- package/dist/clone-project.js +124 -0
- package/dist/clone-project.js.map +1 -0
- 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/module-serve.d.ts +6 -0
- package/dist/dashboard/module-serve.d.ts.map +1 -1
- package/dist/dashboard/module-serve.js +24 -8
- package/dist/dashboard/module-serve.js.map +1 -1
- 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 +28 -25
- package/dist/dashboard/rpc-serve.d.ts.map +1 -1
- package/dist/dashboard/rpc-serve.js +26 -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 +57 -84
- package/dist/dashboard/server.js.map +1 -1
- package/dist/dashboard/types.d.ts +11 -16
- 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-BHMlP40v.css +2 -0
- package/dist/dashboard-bundle/assets/main-D0qZC1r-.js +140 -0
- package/dist/dashboard-bundle/assets/{module-gKz-ZvkG.js → module-ZjyA5WUg.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 +3 -3
- package/dist/dashboard-rpc/index.d.ts.map +1 -1
- package/dist/dashboard-rpc/index.js +5 -5
- 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 +12 -4
- package/dist/dashboard-rpc/modules.d.ts.map +1 -1
- package/dist/dashboard-rpc/modules.js +24 -5
- package/dist/dashboard-rpc/modules.js.map +1 -1
- package/dist/dashboard-rpc/projects.d.ts +18 -0
- package/dist/dashboard-rpc/projects.d.ts.map +1 -1
- package/dist/dashboard-rpc/projects.js +27 -5
- 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/components/QrCode.d.ts +8 -0
- package/dist/module-types/dashboard/lib/draft-handoff.d.ts +5 -9
- package/dist/module-types/dashboard/module/index.d.ts +56 -4
- package/dist/module-types/dashboard/rpc/modules.d.ts +1 -0
- package/dist/module-types/src/built-in.d.ts +18 -2
- package/dist/module-types/src/client.d.ts +2 -1
- package/dist/module-types/src/clone-project.d.ts +68 -0
- 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/module-serve.d.ts +6 -0
- package/dist/module-types/src/dashboard/remote-run.d.ts +77 -32
- package/dist/module-types/src/dashboard/rpc-serve.d.ts +28 -25
- package/dist/module-types/src/dashboard/types.d.ts +11 -16
- 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 +3 -3
- package/dist/module-types/src/dashboard-rpc/machines.d.ts +51 -0
- package/dist/module-types/src/dashboard-rpc/modules.d.ts +12 -4
- package/dist/module-types/src/dashboard-rpc/projects.d.ts +18 -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/pick-directory.d.ts +2 -0
- package/dist/module-types/src/project-modules.d.ts +12 -3
- 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/pick-directory.d.ts +2 -0
- package/dist/pick-directory.d.ts.map +1 -1
- package/dist/pick-directory.js +7 -1
- package/dist/pick-directory.js.map +1 -1
- package/dist/project-modules.d.ts +12 -3
- package/dist/project-modules.d.ts.map +1 -1
- package/dist/project-modules.js +20 -2
- package/dist/project-modules.js.map +1 -1
- 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 +15 -11
- 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
|
@@ -104,13 +104,13 @@ export interface ModuleCard {
|
|
|
104
104
|
}
|
|
105
105
|
/** What a Settings section is rendered with: the projects that have its package. */
|
|
106
106
|
export interface ModuleSettingsProps {
|
|
107
|
-
/** The registered projects whose dependencies include the module's package, in the registry's order. */
|
|
107
|
+
/** The registered projects whose dependencies include the module's package, in the registry's order; none for a package that is the computer's. */
|
|
108
108
|
projects: ModuleProject[];
|
|
109
109
|
}
|
|
110
110
|
/**
|
|
111
111
|
* A section a module adds to the Settings page: the package's own settings, read and written
|
|
112
|
-
* through its own command, drawn after the dashboard's own sections. A package with no
|
|
113
|
-
* registered shows none.
|
|
112
|
+
* through its own command, drawn after the dashboard's own sections. A project's package with no
|
|
113
|
+
* project registered shows none; a package that is the computer's shows its own with no project.
|
|
114
114
|
*/
|
|
115
115
|
export interface ModuleSettings {
|
|
116
116
|
/** Which section this is, for the shell's key and its error line; the section draws its own title. */
|
|
@@ -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
|
}
|
|
@@ -268,6 +273,12 @@ export interface ModuleHost {
|
|
|
268
273
|
* change shows at once instead of at the next sync. A link action's host runs every command so.
|
|
269
274
|
*/
|
|
270
275
|
act(projectId: string, args: string[], command?: string): Promise<ModuleCommandResult>;
|
|
276
|
+
/**
|
|
277
|
+
* Run one of the module package's own commands in no project, for a package that is this
|
|
278
|
+
* computer's (the door to it, its servers): what such a package keeps is the computer's, so
|
|
279
|
+
* its page reads and changes it with no project added. Refused for any other package.
|
|
280
|
+
*/
|
|
281
|
+
runComputerCommand(args: string[], command?: string): Promise<ModuleCommandResult>;
|
|
271
282
|
/**
|
|
272
283
|
* Call one of the module's own server reads (its package's `./server`) in one project, with
|
|
273
284
|
* `input`, a JSON object; `input.agentId` names the run the read is about, when it is about one.
|
|
@@ -290,9 +301,49 @@ export interface ModuleHost {
|
|
|
290
301
|
configureRun(projectId: string, prompt: string): void;
|
|
291
302
|
/** The project's runs the dashboard knows: the ones running, and the recorded ones when the project records them. */
|
|
292
303
|
agents(projectId: string): Promise<ModuleAgent[]>;
|
|
304
|
+
/**
|
|
305
|
+
* The other computers a run can be sent to, as saved on this one, each with the OpenAgent it
|
|
306
|
+
* runs, beside this computer's own: how a page tells that a machine fell behind this computer.
|
|
307
|
+
*/
|
|
308
|
+
machines(): Promise<ModuleMachines>;
|
|
309
|
+
/**
|
|
310
|
+
* Save the machine a link names: the link another OpenAgent gives for a new device, as a person
|
|
311
|
+
* pastes it under Machines. This computer is let in there with it, once, and keeps its key.
|
|
312
|
+
*/
|
|
313
|
+
addMachine(link: string, label?: string): Promise<MachineAdded>;
|
|
314
|
+
/**
|
|
315
|
+
* What the live screen of a run shows, as the screen's own stream of bytes, until `signal` ends
|
|
316
|
+
* it; nothing when the run has no live screen. OpenAgent asks the computer the run is on, which
|
|
317
|
+
* may be another machine: the bytes are that computer's, to read as data and never to run.
|
|
318
|
+
*/
|
|
319
|
+
watchScreen(projectId: string, agentId: string, signal: AbortSignal): Promise<ReadableStream<Uint8Array> | undefined>;
|
|
320
|
+
/** Send the live screen of a run what the person did on it, as JSON; whether the screen took it. */
|
|
321
|
+
sendToScreen(projectId: string, agentId: string, input: unknown): Promise<boolean>;
|
|
322
|
+
}
|
|
323
|
+
/** A saved machine, as a module sees it: never this computer's key there. */
|
|
324
|
+
export interface ModuleMachine {
|
|
325
|
+
/** Where the machine answers, as an origin (`https://203.0.113.5`): what it is known by. */
|
|
326
|
+
id: string;
|
|
327
|
+
label: string;
|
|
328
|
+
url: string;
|
|
329
|
+
/** The OpenAgent it runs; absent for a machine that does not answer right now. */
|
|
330
|
+
version?: string;
|
|
331
|
+
}
|
|
332
|
+
/** What {@link ModuleHost.machines} answers. */
|
|
333
|
+
export interface ModuleMachines {
|
|
334
|
+
/** This computer's own OpenAgent. */
|
|
335
|
+
version: string;
|
|
336
|
+
machines: ModuleMachine[];
|
|
293
337
|
}
|
|
338
|
+
/** How saving a machine went: done, or stopped, with the reason. */
|
|
339
|
+
export type MachineAdded = {
|
|
340
|
+
ok: true;
|
|
341
|
+
} | {
|
|
342
|
+
ok: false;
|
|
343
|
+
error: string;
|
|
344
|
+
};
|
|
294
345
|
/** 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
|
-
export type ModuleHostBase = Omit<ModuleHost, 'runCommand' | 'act' | 'read'>;
|
|
346
|
+
export type ModuleHostBase = Omit<ModuleHost, 'runCommand' | 'act' | 'runComputerCommand' | 'read'>;
|
|
296
347
|
/**
|
|
297
348
|
* The host for one module: the dashboard's services, and its commands bound to the module's own
|
|
298
349
|
* package. `acts` marks every command as an action on the project rather than a page's read: the
|
|
@@ -329,6 +380,7 @@ export { StartAgentButton } from '../components/StartAgentButton.js';
|
|
|
329
380
|
export { LinkActions, type ProjectLinks, type LinkTargets } from '../components/LinkActions.js';
|
|
330
381
|
export { cn } from '../lib/utils.js';
|
|
331
382
|
export { SettingsSection, SettingsRow, SettingsSelectRow, type SettingsOption } from '../components/SettingsRows.js';
|
|
383
|
+
export { QrCode } from '../components/QrCode.js';
|
|
332
384
|
export { useCodingAgents, type CodingAgent } from '../lib/models.js';
|
|
333
385
|
export { MAX_SPEND_OFFSET } from '../../src/preference-defaults.js';
|
|
334
386
|
export { formatRelative, formatDateTime, formatDuration, formatAge } from '../lib/format-date.js';
|
|
@@ -2,4 +2,5 @@ import type * as impl from '../../src/dashboard-rpc/modules.js';
|
|
|
2
2
|
export type * from '../../src/dashboard-rpc/modules.js';
|
|
3
3
|
export declare const onModules: () => Promise<impl.DashboardModule[]>;
|
|
4
4
|
export declare const runModuleCommand: (projectId: string, pkg: string, args: string[], command?: string | undefined, acts?: boolean | undefined) => Promise<import("@openagt/agent-data").PackageCommandResult>;
|
|
5
|
+
export declare const runComputerCommand: (pkg: string, args: string[], command?: string | undefined) => Promise<import("@openagt/agent-data").PackageCommandResult>;
|
|
5
6
|
export declare const readModule: (projectId: string, pkg: string, name: string, input: unknown) => Promise<impl.ModuleReadResult>;
|
|
@@ -5,12 +5,18 @@ import { type ProjectPackage, type ProvidedCommand, type ProvidedCommandLookup }
|
|
|
5
5
|
* own install, so a project installs nothing for them and an empty folder starts an agent and
|
|
6
6
|
* shows it. Each comes through the same contract as any package: a module by its `./dashboard`
|
|
7
7
|
* export, a provider of a kind of data and the writer of its hook lines by its `openagent` key.
|
|
8
|
-
* These
|
|
8
|
+
* These three lists are the one place OpenAgent names a package. One of these names among a
|
|
9
9
|
* project's own dependencies is not read: OpenAgent's copy, and the rules below for which
|
|
10
10
|
* project has it, are the only ones.
|
|
11
11
|
*/
|
|
12
12
|
/** The packages every project has: an agent cannot start, be shown or be put on a git host without them. */
|
|
13
13
|
export declare const BUILT_IN_PACKAGES: readonly string[];
|
|
14
|
+
/**
|
|
15
|
+
* The packages that are this computer's and no project's: the door to it, and the servers it
|
|
16
|
+
* installed OpenAgent on. Their pages show and their commands run with no project added, and
|
|
17
|
+
* what one keeps is in the person's home folder.
|
|
18
|
+
*/
|
|
19
|
+
export declare const COMPUTER_PACKAGES: readonly string[];
|
|
14
20
|
/**
|
|
15
21
|
* The packages a project has once it picked them (#2023). A skill's package is the project's
|
|
16
22
|
* when the project holds the skill's text where the coding agents read it
|
|
@@ -27,11 +33,21 @@ export declare function builtInPackages(): Promise<ProjectPackage[]>;
|
|
|
27
33
|
/**
|
|
28
34
|
* The packages OpenAgent brings to the project at `root`: the ones every project has, and
|
|
29
35
|
* 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.
|
|
36
|
+
* project's files each time, so a skill written or deleted a moment ago counts at once. None of
|
|
37
|
+
* the computer's: no project has those.
|
|
31
38
|
*/
|
|
32
39
|
export declare function builtInPackagesOf(root: string): Promise<ProjectPackage[]>;
|
|
33
40
|
/** The project's own installed packages, less the names OpenAgent brings itself. */
|
|
34
41
|
export declare function ownPackages(root: string): Promise<ProjectPackage[]>;
|
|
42
|
+
/** The packages that are this computer's: see {@link COMPUTER_PACKAGES}. */
|
|
43
|
+
export declare function computerPackages(): Promise<ProjectPackage[]>;
|
|
44
|
+
/**
|
|
45
|
+
* The services of the computer's packages: a package declares
|
|
46
|
+
* `"openagent": { "service": "<command>" }`, and `<command> serve` runs for as long as OpenAgent
|
|
47
|
+
* runs (`package-services.ts`). Only those packages: a service is this computer's, and any
|
|
48
|
+
* other package is a project's.
|
|
49
|
+
*/
|
|
50
|
+
export declare function builtInServices(): Promise<ProvidedCommand[]>;
|
|
35
51
|
/** The directories the commands of OpenAgent's packages sit in: what a hook line's PATH gains after the project's own installed tools. */
|
|
36
52
|
export declare function builtInBinDirs(): Promise<string[]>;
|
|
37
53
|
/** What provides `kind` in the project at `root`: a package the project installed for it, else one OpenAgent brings to this project. */
|
|
@@ -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 {
|
|
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';
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A project added by its repository's address, for a computer that does not have its folder: a
|
|
3
|
+
* server that was just connected has no screen to pick a folder on and no folder to pick. The
|
|
4
|
+
* repository is cloned into `~/projects/<its name>`, in the home of the user OpenAgent runs as,
|
|
5
|
+
* and that folder is then added like any other. Nothing is asked about where: the page says
|
|
6
|
+
* where it went.
|
|
7
|
+
*
|
|
8
|
+
* git clones with the logins this computer has (its credential helper, its SSH keys) and is
|
|
9
|
+
* never let ask a person for one: a repository it cannot read is refused in words.
|
|
10
|
+
*/
|
|
11
|
+
/** Where a repository is cloned from and to. */
|
|
12
|
+
export interface CloneTarget {
|
|
13
|
+
/** What git is given. */
|
|
14
|
+
url: string;
|
|
15
|
+
/** The repository's one name on every machine: see `addressOfRemote`. */
|
|
16
|
+
address: string;
|
|
17
|
+
/** The folder it is cloned into. */
|
|
18
|
+
path: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Read what a person typed as a repository's address: `github.com/you/shop`, the same with
|
|
22
|
+
* `https://` before it, `ssh://git@github.com/you/shop.git`, or `git@github.com:you/shop.git`.
|
|
23
|
+
* Undefined for anything else: a folder on this disk, another kind of address, a name that could
|
|
24
|
+
* be read as an option or lead out of the folder projects are cloned into.
|
|
25
|
+
*/
|
|
26
|
+
export declare function cloneTarget(typed: string, home?: string): CloneTarget | undefined;
|
|
27
|
+
/** How a clone went: the folder the project is in, and whether it was cloned now or was already there. */
|
|
28
|
+
export type Cloned = {
|
|
29
|
+
ok: true;
|
|
30
|
+
path: string;
|
|
31
|
+
cloned: boolean;
|
|
32
|
+
} | {
|
|
33
|
+
ok: false;
|
|
34
|
+
error: string;
|
|
35
|
+
};
|
|
36
|
+
/** Run git and answer how it ended, with what it said on its error side. */
|
|
37
|
+
export type CloneRunner = (args: readonly string[], env: NodeJS.ProcessEnv, timeoutMs: number) => Promise<{
|
|
38
|
+
ok: true;
|
|
39
|
+
} | {
|
|
40
|
+
ok: false;
|
|
41
|
+
said: string;
|
|
42
|
+
timedOut: boolean;
|
|
43
|
+
}>;
|
|
44
|
+
/** Where what a person typed would be cloned to, before anything is cloned: what the page shows to be confirmed. */
|
|
45
|
+
export declare function cloneTargetOf(typed: string, home?: string): {
|
|
46
|
+
ok: true;
|
|
47
|
+
address: string;
|
|
48
|
+
path: string;
|
|
49
|
+
} | {
|
|
50
|
+
ok: false;
|
|
51
|
+
error: string;
|
|
52
|
+
};
|
|
53
|
+
export interface CloneOptions {
|
|
54
|
+
home?: string;
|
|
55
|
+
run?: CloneRunner;
|
|
56
|
+
env?: NodeJS.ProcessEnv;
|
|
57
|
+
timeoutMs?: number;
|
|
58
|
+
/** The person's own way to SSH for git, when they set one; read off git's settings when unsaid. */
|
|
59
|
+
sshCommand?: (env: NodeJS.ProcessEnv) => Promise<string | undefined>;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Clone the repository a person typed the address of into `~/projects/<its name>`. A folder that
|
|
63
|
+
* is already there and holds this very repository is taken as it is; one that holds anything
|
|
64
|
+
* else is never written over, and is refused. The clone is made beside that folder and moved
|
|
65
|
+
* there once it is whole: a clone that fails leaves nothing behind, and one on its way is no
|
|
66
|
+
* folder a second ask could take for the project.
|
|
67
|
+
*/
|
|
68
|
+
export declare function cloneProject(typed: string, opts?: CloneOptions): Promise<Cloned>;
|
|
@@ -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.**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
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
|
|
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,8 +3,12 @@ import { type ProjectsProvider } from './projects.js';
|
|
|
3
3
|
import { type ProjectModule } from '../project-modules.js';
|
|
4
4
|
/** Where module files are served: `/_modules/<project id>/<package>/<file>`, each segment encoded. */
|
|
5
5
|
export declare const MODULES_PREFIX = "/_modules";
|
|
6
|
+
/** Where the files of the computer's modules are served, which are no project's: `/_computer-modules/<package>/<file>`. */
|
|
7
|
+
export declare const COMPUTER_MODULES_PREFIX = "/_computer-modules";
|
|
6
8
|
/** The URL a module's browser part is served at from one project. */
|
|
7
9
|
export declare function moduleUrl(projectId: string, module: Pick<ProjectModule, 'package' | 'entry'>): string;
|
|
10
|
+
/** The URL the browser part of one of the computer's modules is served at. */
|
|
11
|
+
export declare function computerModuleUrl(module: Pick<ProjectModule, 'package' | 'entry'>): string;
|
|
8
12
|
/**
|
|
9
13
|
* Serve one module file (#1774): the project must be registered, the package must be a module of
|
|
10
14
|
* that project, and the file must sit inside the module's browser part's own directory. Anything else is a
|
|
@@ -12,3 +16,5 @@ export declare function moduleUrl(projectId: string, module: Pick<ProjectModule,
|
|
|
12
16
|
* Served as `no-cache`, since a module is rebuilt in place under the same name.
|
|
13
17
|
*/
|
|
14
18
|
export declare function serveModuleFile(req: IncomingMessage, res: ServerResponse, pathname: string, projects?: ProjectsProvider): Promise<void>;
|
|
19
|
+
/** Serve one file of a module that is the computer's: as {@link serveModuleFile}, with no project to be registered. */
|
|
20
|
+
export declare function serveComputerModuleFile(req: IncomingMessage, res: ServerResponse, pathname: string): Promise<void>;
|
|
@@ -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;
|
|
@@ -65,6 +67,15 @@ export interface DashboardContext {
|
|
|
65
67
|
* the mount, its only caller.
|
|
66
68
|
*/
|
|
67
69
|
export declare function isSameOriginRequest(req: IncomingMessage): boolean;
|
|
70
|
+
/**
|
|
71
|
+
* The third guard: a call says its body is JSON. {@link isSameOriginRequest} lets every loopback
|
|
72
|
+
* origin pass, whatever its port, so a page another program serves on this computer (an app an
|
|
73
|
+
* agent previews, a dev server) is let through it. A browser sends such a page's POST without
|
|
74
|
+
* asking only while its content type is one a plain form can have, and JSON is none of them:
|
|
75
|
+
* with JSON it asks first, this server never says yes, and the call is not sent. So a call that
|
|
76
|
+
* is not JSON is refused, and no page of another origin can make one, not even blind.
|
|
77
|
+
*/
|
|
78
|
+
export declare function isJsonRequest(req: IncomingMessage): boolean;
|
|
68
79
|
/**
|
|
69
80
|
* DNS-rebinding guard, the other half of the CSRF check above. A page on `evil.com` whose DNS
|
|
70
81
|
* re-answers as `127.0.0.1` is *same-origin* with this server as far as the browser is concerned,
|
|
@@ -72,16 +83,12 @@ export declare function isSameOriginRequest(req: IncomingMessage): boolean;
|
|
|
72
83
|
* the mount, `sendStart` included, is reachable from a page the user merely visited.
|
|
73
84
|
*
|
|
74
85
|
* 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.
|
|
86
|
+
* asked for (`evil.com`), not the address it resolved to. The dashboard listens on this
|
|
87
|
+
* computer's own address only, so the only `Host` a real user's browser can send is a loopback
|
|
88
|
+
* one — anything else is a rebound name and is rejected. An absent `Host` is rejected too:
|
|
89
|
+
* HTTP/1.1 requires it, and every browser sends it.
|
|
83
90
|
*/
|
|
84
|
-
export declare function isExpectedHost(req: IncomingMessage
|
|
91
|
+
export declare function isExpectedHost(req: IncomingMessage): boolean;
|
|
85
92
|
/** Where the dashboard's RPCs live. One prefix, so the static handler can decline it by path. */
|
|
86
93
|
export declare const RPC_PREFIX = "/_rpc";
|
|
87
94
|
/**
|
|
@@ -90,16 +97,12 @@ export declare const RPC_PREFIX = "/_rpc";
|
|
|
90
97
|
* `sendStart` reaches the daemon's own `startAgent` through the wired {@link DashboardContext}.
|
|
91
98
|
*
|
|
92
99
|
* 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.
|
|
100
|
+
* are requests carrying someone else's `Host` (DNS rebinding: the same page must not reach us by
|
|
101
|
+
* pointing its own name at `127.0.0.1`). Returns whether the request was the RPC surface's.
|
|
97
102
|
*
|
|
98
103
|
* This replaced Telefunc (F3), which required a build-time transform over every `.telefunc.ts`
|
|
99
104
|
* file, a registration table pinning each RPC to the client-baked key of the *dashboard* source
|
|
100
105
|
* path it was re-exported from, and a request-context indirection for wiring that never varied
|
|
101
106
|
* per request. What it bought over this was type-safety across a package boundary that A7 removed.
|
|
102
107
|
*/
|
|
103
|
-
export declare function makeRpcMount(context: DashboardContext,
|
|
104
|
-
host?: string;
|
|
105
|
-
}): (req: IncomingMessage, res: ServerResponse) => Promise<boolean>;
|
|
108
|
+
export declare function makeRpcMount(context: DashboardContext): (req: IncomingMessage, res: ServerResponse) => Promise<boolean>;
|
|
@@ -22,7 +22,8 @@ export type DeleteAgentResult = {
|
|
|
22
22
|
export type AddProjectResult = {
|
|
23
23
|
ok: true;
|
|
24
24
|
alreadyActivated: boolean;
|
|
25
|
-
noRemote?: true;
|
|
25
|
+
noRemote?: true; /** For a project added by its repository's address: the folder it is in. */
|
|
26
|
+
path?: string;
|
|
26
27
|
} | {
|
|
27
28
|
ok: false;
|
|
28
29
|
error: string;
|
|
@@ -56,10 +57,12 @@ export type RemoveProjectResult = {
|
|
|
56
57
|
* never discloses its filesystem layout.
|
|
57
58
|
*/
|
|
58
59
|
export interface OnboardingSuggestion {
|
|
59
|
-
/** The server's working directory, or null when it cannot be offered. */
|
|
60
|
+
/** The server's working directory, or null when it cannot be offered: the home folder is where a service runs, not a project. */
|
|
60
61
|
cwd: string | null;
|
|
61
62
|
/** The project id for {@link cwd} when it is already registered, else null. */
|
|
62
63
|
cwdProjectId: string | null;
|
|
64
|
+
/** Whether this computer can show a window to pick a folder in: one with no screen, as a server, cannot. */
|
|
65
|
+
canPickFolder: boolean;
|
|
63
66
|
}
|
|
64
67
|
/**
|
|
65
68
|
* What a Start carries besides its prompt (#1774): the person's picks, handed to the project's
|
|
@@ -75,7 +78,7 @@ export interface StartAgentOptions {
|
|
|
75
78
|
/**
|
|
76
79
|
* The branch the agent's own branch starts from, as this machine has it, commits that are not
|
|
77
80
|
* 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
|
|
81
|
+
* word that is no branch name refuses the Start. Not sent to another machine: its branches are its own.
|
|
79
82
|
*/
|
|
80
83
|
base?: string;
|
|
81
84
|
/**
|
|
@@ -84,20 +87,12 @@ export interface StartAgentOptions {
|
|
|
84
87
|
*/
|
|
85
88
|
then?: string;
|
|
86
89
|
/**
|
|
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.
|
|
90
|
+
* Run this session on a saved machine (#1067), named by its id: the local daemon relays the
|
|
91
|
+
* start to that machine's daemon, which starts it in its own copy of the project, and streams
|
|
92
|
+
* its events back into the local agent view. Absent = run on this machine. Stripped before the
|
|
93
|
+
* start is forwarded, so the machine starts an ordinary local run and does not relay onward.
|
|
95
94
|
*/
|
|
96
|
-
|
|
97
|
-
url: string;
|
|
98
|
-
token: string;
|
|
99
|
-
label?: string;
|
|
100
|
-
};
|
|
95
|
+
machine?: string;
|
|
101
96
|
}
|
|
102
97
|
/** The outcome of a Start attempt (#345): the id of the run the project's start hook began, or why there is none. */
|
|
103
98
|
export type StartAgentResult = {
|