mirror of
https://github.com/getpaseo/paseo.git
synced 2026-11-08 17:34:51 +00:00
feat(hosts): connect to saved hosts through a daemon
This commit is contained in:
@@ -64,6 +64,31 @@ Entries may also include `loginErrors`. Structured output preserves numeric valu
|
||||
|
||||
A completed query exits with status `0`, including when individual reports are unavailable or failed. Connection or request failures, unsupported hosts, unknown report IDs, and conflicting selectors exit with status `1` and write the error to stderr. Human output says **No usage reports returned** for an empty result; this does not establish whether account discovery succeeded for every source.
|
||||
|
||||
## Connected hosts
|
||||
|
||||
`--host` selects the daemon whose saved connections you manage. Registrations use their
|
||||
`registrationId`, not their label.
|
||||
|
||||
```sh
|
||||
paseo --host localhost:6767 host add 'ssh://deploy@build-box' --label build-box --meta team=infra
|
||||
paseo --host localhost:6767 host ls --json
|
||||
paseo --host localhost:6767 host inspect hst_123
|
||||
paseo --host localhost:6767 host update hst_123 --meta team=tools --remove-meta obsolete
|
||||
paseo --host localhost:6767 host update hst_123 --connection 'ssh://deploy@new-address'
|
||||
paseo --host localhost:6767 host disable hst_123
|
||||
paseo --host localhost:6767 host enable hst_123
|
||||
paseo --host localhost:6767 host rm hst_123
|
||||
```
|
||||
|
||||
Add accepts TCP/host-and-port, `ws://`/`wss://`, local socket/pipe, SSH, and relay/pairing URLs.
|
||||
SSH connects to an already running daemon. Add `?password=...` to an SSH URI when that daemon requires a password (`&password=...` after `daemonPort`). Unreachable targets remain saved and retry automatically.
|
||||
`ls` includes disabled and failed hosts. `inspect` includes safe connection details and recovery guidance.
|
||||
JSON output never includes connection credentials.
|
||||
|
||||
`update --meta` replaces supplied keys; `--remove-meta` removes keys. Replacing a connection retains
|
||||
the pinned daemon identity. Add `--replace-identity` with `--connection` only after verifying a changed
|
||||
destination. `rm` removes the saved connection; agents and workspaces on that host keep running.
|
||||
|
||||
## Provider diagnostics
|
||||
|
||||
Ask the daemon to inspect the provider environment it actually uses:
|
||||
|
||||
@@ -26,6 +26,26 @@ Local plugins are directory sources installed into one Paseo daemon. A plugin ca
|
||||
|
||||
Plugin code is trusted and unsandboxed. Client surfaces run in the Paseo app. Backend contributions run in a subprocess with access to the daemon machine, including its files, processes, credentials, and network.
|
||||
|
||||
## Connected hosts
|
||||
|
||||
`usePaseo().hosts` in a client surface and `context.paseo.hosts` in a server handler or lifecycle hook
|
||||
use the same [SDK host API](/sdk/reference#clienthosts). They describe the selected daemon's saved
|
||||
connections. Existing `useHosts()` and `getPaseoClient(serverId)` keep describing app-known hosts.
|
||||
|
||||
```ts
|
||||
const remote = await context.paseo.hosts.client("srv_build_box");
|
||||
try {
|
||||
return await remote.workspaces.list();
|
||||
} finally {
|
||||
await remote.dispose();
|
||||
}
|
||||
```
|
||||
|
||||
A returned API owns its observations. Teardown of the plugin API also disposes derived scopes.
|
||||
Keep remote calls inside the handler or lifecycle scope that owns them. Calling B does not forward
|
||||
B's plugin lifecycle hooks to A. Registrations created by a routed plugin retain a source qualified
|
||||
by the authenticated link and originating plugin.
|
||||
|
||||
## Project files
|
||||
|
||||
`paseo plugin init /absolute/path/to/my-plugin` creates:
|
||||
|
||||
@@ -203,6 +203,57 @@ Use `workspace.terminals.create(options?)` and `workspace.terminals.list(options
|
||||
|
||||
`config.patch(patch, requestId?)` validates, persists, and returns an updated configuration. Use this administrative surface for host configuration, not per-agent choices. A patch affects every client and future agent using that daemon.
|
||||
|
||||
## `client.hosts`
|
||||
|
||||
Manage hosts connected to the selected daemon. Both the managing daemon and destination must support connected hosts.
|
||||
|
||||
```ts
|
||||
const directory = await client.hosts.list();
|
||||
const registration = await client.hosts.add({
|
||||
connection: "ssh://deploy@build-box",
|
||||
label: "Build box",
|
||||
metadata: { team: "infra" },
|
||||
sourceKey: "build-box",
|
||||
});
|
||||
await client.hosts.update(registration.registrationId, { enabled: false });
|
||||
await client.hosts.remove(registration.registrationId);
|
||||
```
|
||||
|
||||
`list()` returns `{ self: { serverId, label }, hosts }`. Each host includes its registration and server
|
||||
IDs, label, authenticated source, string metadata, enabled state, connection status, safe target
|
||||
description, last-online/retry timestamps, and an actionable error. Credentials are never returned.
|
||||
A valid but unreachable connection is saved and retried. Invalid syntax fails without saving.
|
||||
|
||||
`update(registrationId, patch)` accepts `label`, `metadata`, `enabled`, `connection`, and
|
||||
`replaceIdentity`. Metadata replaces the whole map. Replacing a connection preserves the expected
|
||||
server ID unless `replaceIdentity: true` explicitly accepts a new destination.
|
||||
|
||||
`observe()` returns an owned subscription. Await `ready`, subscribe for snapshots and `hosts.changed`
|
||||
updates, then call `release()`. Observations restore a current snapshot after reconnect.
|
||||
|
||||
```ts
|
||||
const remote = await client.hosts.client("srv_build_box");
|
||||
try {
|
||||
const workspaces = await remote.workspaces.list();
|
||||
const providers = await remote.providers.listAvailable();
|
||||
await remote.agents.ref("agent_on_build_box").send("Continue the investigation");
|
||||
} finally {
|
||||
await remote.dispose();
|
||||
}
|
||||
```
|
||||
|
||||
`client(serverId)` returns a caller-owned `PaseoApi` bound to that destination through the selected
|
||||
daemon. The ordinary APIs keep their signatures. Paths and IDs belong to the destination. Selecting
|
||||
the local server ID returns a local scope. Routing supports one hop.
|
||||
|
||||
Disposing one scope releases its observations without closing siblings or deleting the saved host.
|
||||
Origin disposal cascades. Offline operations fail; observations recover. A lost result reports
|
||||
`outcome_unknown` and the destination server ID. Inspect before retrying a mutation.
|
||||
|
||||
Host failures expose a stable `code`: `host_unknown`, `host_disabled`, `host_offline`,
|
||||
`permission_denied`, `unsupported_capability`, `authentication_failed`, `server_id_mismatch`,
|
||||
`self_host`, or `duplicate_host`. Discovery does not grant execution authority.
|
||||
|
||||
## Errors and cleanup
|
||||
|
||||
Connection, validation, rejection, and timeout failures reject their promise. Turn outcomes are returned through `PaseoAgentRunResult.status` because permission and provider errors are expected agent states.
|
||||
|
||||
Reference in New Issue
Block a user