@nylorun/cli 0.9.0-beta → 0.12.0-beta
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/CHANGELOG.md +94 -0
- package/README.md +20 -13
- package/dist/access/commands.d.ts +8 -24
- package/dist/access/commands.js +10 -121
- package/dist/cli.js +14 -14
- package/dist/doctor.d.ts +1 -1
- package/dist/doctor.js +7 -6
- package/dist/installation/commands.d.ts +4 -17
- package/dist/installation/commands.js +21 -82
- package/dist/model/configure.d.ts +3 -6
- package/dist/model/configure.js +3 -16
- package/dist/model/host-model.d.ts +3 -17
- package/dist/model/host-model.js +10 -23
- package/dist/project/connection.d.ts +11 -4
- package/dist/project/connection.js +27 -7
- package/dist/project/credentials.d.ts +5 -2
- package/dist/project/credentials.js +5 -0
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,99 @@
|
|
|
1
1
|
# @nylorun/cli
|
|
2
2
|
|
|
3
|
+
## 0.12.0-beta
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- c135267: **Action endpoints are removed (manifest-only agents, M6).** The Runtime runs no code of yours during a session: an agent's tools are HTTP tools, remote MCP servers, agents used as tools and the Runtime's built-ins. Protocol stays 8; the `action-endpoints` feature is gone, so a client that requires it is refused. See MIGRATION.md, "Action endpoints are removed".
|
|
8
|
+
|
|
9
|
+
- **Breaking (`@nylorun/core`):** the `Action`, endpoint (`PutEndpointsRequest`, `Endpoint`, `EndpointHealth`, …) and delivery schemas, `SIGNATURE_HEADER`, `OUTCOME_HEADER`, `DELIVERY_TOKEN_TYPE` and the `action.*` events (`action.pending`, `.delivered`, `.delivery_failed`, `.completed`, `.uncertain`) are removed, and `ToolDefinition.background` with them. `ActionOutcome` is renamed `EffectOutcome`. Tenant status loses `checks.endpoints`, `agents[].registered` and `agents[].endpoint`, and `counts.pendingActions`; the session view loses `actions`. A `turn.paused` interaction carries the tool call's `callId`. New `codeToolsOf` and `codeToolRefusal` name a definition's tools that would run your code. The Harness API is v2 (`HARNESS_API_VERSION = 2`): `TurnStart.options.holdMs` and `effect.resolved` are removed.
|
|
10
|
+
- **Breaking (`@nylorun/harness`):** held runs are gone: `createHarness` loses `holdMs`, and `apiHost` its `hold` option.
|
|
11
|
+
- **Breaking (`@nylorun/agents`):** `createActionHandler`, `executeAction`, `createActionSandbox`, `definitionDeclaresSandbox`, `isActionSandboxTool` and the `Action`, `ActionOutcome`, `ActionHandler`, `ActionHandlerOptions`, `RegisterOptions`, `ExecuteActionOptions` and `ExecutableDefinition` types are removed. `saveAgent` refuses a code tool (`tool({ run })`) or a flow tool stage before sending; its `implementationVersion` is optional (`NYLORUN_IMPLEMENTATION_VERSION`, else `dev`).
|
|
12
|
+
- **Breaking (`@nylorun/runtime`):** `/v1/endpoints` and `/v1/actions/*` answer `404`; delivery tokens, the deliverer, background tools, held runs (`TenantConfig.actionHoldMs`), `DurableExecution.deliver`, the Restate `NylorunAction` object, the `action_result` wake and the gates service's `/nylorun/v1/deliveries` are removed, and a migration drops the `actions` and `endpoints` tables. `PUT /v1/agents/:id` refuses a definition with a code tool or a flow tool stage (`400`); a tool the Runtime cannot run fails with `tool.unavailable`. The fixture model answers in text when the agent offers no `lookup_order` tool.
|
|
13
|
+
- **Breaking (`@nylorun/cli`):** `nylo endpoints` is removed (a usage error that says why); `nylo status` shows uncertain effects instead of pending Actions.
|
|
14
|
+
- **Breaking (`@nylorun/create-agent`):** the starter saves its agent with `saveAgent` and runs no server: no Action endpoint, `PORT` or `NYLORUN_ACTIONS_URL`. Its assistant has no tools, with a commented `http()` tool to start from.
|
|
15
|
+
- `nylorun`: the local stack's comments speak of MCP servers and HTTP tools on this machine, not Action endpoints.
|
|
16
|
+
- `@nylorun/studio`: the `action.*` event views and delivery status are removed; the chat shows `tool.completed`, and the Agent Manifest tab lists tools without a target as code tools.
|
|
17
|
+
|
|
18
|
+
### Patch Changes
|
|
19
|
+
|
|
20
|
+
- Pin agents to the tested release.
|
|
21
|
+
- Pin admin to the tested release.
|
|
22
|
+
- Updated dependencies [4bd2a0b]
|
|
23
|
+
- Updated dependencies [a64aaca]
|
|
24
|
+
- Updated dependencies [40b7648]
|
|
25
|
+
- Updated dependencies [713e676]
|
|
26
|
+
- Updated dependencies [c135267]
|
|
27
|
+
- Updated dependencies [d36f0d9]
|
|
28
|
+
- Updated dependencies [107b07d]
|
|
29
|
+
- Updated dependencies
|
|
30
|
+
- Updated dependencies
|
|
31
|
+
- @nylorun/agents@0.16.0-beta
|
|
32
|
+
- @nylorun/admin@0.11.1-beta
|
|
33
|
+
|
|
34
|
+
## 0.11.0-beta
|
|
35
|
+
|
|
36
|
+
### Minor Changes
|
|
37
|
+
|
|
38
|
+
- 3b3bdc6: **The clients use management keys (Runtime and Management APIs, step A3).** The protocol stays at 7; every client keeps working against a protocol 7 Runtime's routes.
|
|
39
|
+
|
|
40
|
+
- `nylorun`: `nylorun start` keeps an application key (`project`) and a management key (`project-management`) for a Project, in `<Host root>/project-credentials.json` and the Project's `.nylorun/credentials.json` (still format 1, with new `managementKey` and `managementPrincipalId` fields). A credentials file holding only an application key gains a management key at the next start. Commands outside a project keep `cli` and `cli-management`. Keys are issued through `nylorun-operate` in the runtime container instead of the Admin API, and `nylorun key put <id> --management` puts a management key. Seeding the Tenant and `nylorun mcp connect` use the management key (`/v1/tenant/vaults`). Studio reaches the Runtime's public listener.
|
|
41
|
+
- `@nylorun/cli`: `status`, `reset`, `configure`, `doctor` and `access signing-keys` use the Management API through `@nylorun/admin` with the Project's management key, or `NYLORUN_MANAGEMENT_KEY`.
|
|
42
|
+
- `@nylorun/studio`: local Studio needs no login. A request on the published loopback address (`localhost` or `127.0.0.1` at Studio's port) acts as signed in; hosts behind a sign-in proxy and embedding keep their login, and state-changing requests still need Studio's own `Origin`. Studio learns its Tenant from `GET /v1/tenant` with its key instead of the Admin API, and its Connections page manages vaults through `@nylorun/admin/client` at `/v1/tenant/vaults`.
|
|
43
|
+
- **Breaking (`@nylorun/admin`, `@nylorun/runtime`): Studio's key is derived from the admin key alone.** `deriveStudioToken(adminKey)` takes no Tenant id (HMAC-SHA256 over `nylorun/studio/v2`). The Host registers the new key's hash at its next start, replacing the old one; an app that embeds Studio and derives its key must update.
|
|
44
|
+
- `@nylorun/core`: `ProjectCredentialsFileSchema` gains optional `managementKey` and `managementPrincipalId`.
|
|
45
|
+
|
|
46
|
+
- 7f763c3: **The Admin API and the operator listener are gone (Runtime and Management APIs, step A5).** Host work moves to the machine: `nylorun` runs `nylorun-operate` inside the runtime container, and every remote client uses the Runtime API or the Management API.
|
|
47
|
+
|
|
48
|
+
- **Breaking (`@nylorun/runtime`):** `/v1/admin/*` (status, host, shutdown, keys, openapi.json) is removed; it answers like any unknown route. The operator listener, `NYLORUN_ADMIN_LISTEN_PORT`, `NYLORUN_ADMIN_LISTEN_HOST`, `NYLORUN_ADMIN_ALLOWED_HOSTS` and `host.json`'s `adminPort` are gone, and so is the `admin-openapi.json` package file. Stop the Host with SIGTERM. `nylorun-operate status [--json]` reports the version, protocol and the Tenant's id, name, state and cause, exiting 2 when the Tenant is not open. `/ready` adds `harness: { mode, connected }` while the Tenant is open. `startEphemeralRuntime` loses `operatorListener` and `adminUrl`. The admin key stays: it derives Studio's key.
|
|
49
|
+
- **Breaking (`@nylorun/admin`):** `createAdmin()` is the Management API client (`tenant`, `keys`, `models`, `vaults`, `signingKeys`, `settings`) with a management key: explicit `{ url, key }`, else `NYLORUN_RUNTIME_URL` + `NYLORUN_MANAGEMENT_KEY`, else the Project link's or the local Host root's management key. `status()`, `adminUrl`, the Admin API keys, `NYLORUN_ADMIN_URL`/`NYLORUN_ADMIN_KEY` and `OPERATOR_KEYS_FEATURE` are removed; `deriveStudioToken` and `mintStudioLoginToken` stay.
|
|
50
|
+
- **Breaking (`@nylorun/core`):** `admin-status` leaves `PROTOCOL_FEATURES` (the Host still advertises it for protocol 5–7 clients) and `operator-keys` is removed; `AdminStatusSchema`, `AdminHostStatusSchema`, `HostAggregateSchema` and `HostShutdownResponseSchema` are removed.
|
|
51
|
+
- **Breaking (`nylorun`):** no admin port: `NYLORUN_ADMIN_PORT` is no longer written or published (an existing one is ignored). `nylorun start` waits for `/ready`, and `nylorun status` reads readiness from `/ready` and the Tenant from `nylorun-operate status`.
|
|
52
|
+
- `@nylorun/cli`: `nylo status` no longer falls back to the Admin API; when the Tenant does not answer it points to `npx nylorun status`.
|
|
53
|
+
|
|
54
|
+
### Patch Changes
|
|
55
|
+
|
|
56
|
+
- Pin agents to the tested release.
|
|
57
|
+
- Pin admin to the tested release.
|
|
58
|
+
- Updated dependencies [3b3bdc6]
|
|
59
|
+
- Updated dependencies [a6108f4]
|
|
60
|
+
- Updated dependencies [b28bdd7]
|
|
61
|
+
- Updated dependencies [7f763c3]
|
|
62
|
+
- Updated dependencies [98b0d37]
|
|
63
|
+
- Updated dependencies [c66d8ed]
|
|
64
|
+
- Updated dependencies
|
|
65
|
+
- Updated dependencies
|
|
66
|
+
- @nylorun/agents@0.15.0-beta
|
|
67
|
+
- @nylorun/admin@0.11.0-beta
|
|
68
|
+
|
|
69
|
+
## 0.10.0-beta
|
|
70
|
+
|
|
71
|
+
### Major Changes
|
|
72
|
+
|
|
73
|
+
- bd478ee: **Subject tokens, browser keys and derived principals leave open source (F9 I3, protocol 7).** Upgrade these with the Runtime: they speak protocol 7, which this Runtime serves beside 4, 5 and 6; protocol 6 clients keep working on every route that remains. Browsers and apps present a trusted issuer's token (F9 I2), servers an operator key (F9 I1), and a person's own credentials come from the operator's credential resolver (F9 C1). See MIGRATION.md.
|
|
74
|
+
|
|
75
|
+
- **Breaking (`@nylorun/runtime`, `@nylorun/core`): subject tokens are gone.** `POST /v1/tokens`, `POST /v1/access/revocations`, subject-token verification, revocation epochs and the `subject.revoked` stream signal are removed; the routes answer `404`, and a JWT no trusted issuer signed is the opaque `404`. A stream opened with a token now ends only at its expiry (`event: nylorun.closed`, reason `token_expired`; `StreamClosedFrame` loses `revoked`). Migration `0010_oss_auth_removals` drops the `subject_epochs`, `subject_usage` and `publishable_keys` tables. The `token` caller is a trusted issuer's token only: it loses `role`, `limits` and `epoch`, and `issuer` is always set; `GET /v1/me` no longer reports `via: token`. Core drops `SUBJECT_TOKEN_TYPE`, `SUBJECT_TOKEN_AUDIENCE`, `subjectTokenIssuer` (the Runtime's own tokens use `tenantTokenIssuer`, same value), `CreateTokenRequest`/`Response`, `RevokeSubject*`, `SubjectTokenClaims`, `TOKEN_TTL_MIN_SECONDS` and `TOKEN_TTL_DEFAULT_SECONDS`; `TOKEN_SCOPES` is `agents:read`, `sessions:own`, `sandboxes:write`.
|
|
76
|
+
- **Breaking (`@nylorun/runtime`, `@nylorun/core`): the access policy and role limits are gone.** `GET`/`PUT /v1/access/policy` answer `404`, a turn is never refused with `429 limit_exceeded` for a role (limit requests at your proxy), and an existing `access.policy` setting is ignored. Core drops `AccessPolicy*`, `AccessRole*`, `RoleLimits*`, `DEFAULT_ACCESS_POLICY`, `PutAccessPolicyRequest` and `ROLE_NAME_PATTERN`.
|
|
77
|
+
- **Breaking (`@nylorun/runtime`, `@nylorun/core`): publishable keys and the Runtime's CORS are gone.** `/v1/access/publishable-keys*` answer `404`, `Nylorun-Key` is ignored, `NYLORUN_BROWSER_ACCESS` and `browserAccess` (host.json, `createHost`, `startEphemeralRuntime`) are removed, and the Runtime sends no CORS headers. A request with `Origin` reaches the Tenant routes of the public listener with no toggle: a trusted issuer's token is served, an application key or delivery token is `403 origin_rejected`; admin routes, `/health`, `/ready` and the operator listener still refuse `Origin`. Any `OPTIONS` request is `204` with `Allow` and no CORS header: the operator's proxy answers preflights. Route declarations lose `browser` (`x-nylorun-browser` leaves the OpenAPI document) and the `publishable` credential; the token security scheme is `issuerToken`. Core drops `PUBLISHABLE_KEY_HEADER`, `PUBLISHABLE_KEY_PATTERN`, `PUBLISHABLE_KEY_ID_PATTERN`, `tenantOfPublishableKey`, `newPublishableKey`, `newPublishableKeyId`, `PublishableKey*`, `OriginEntrySchema`, `originAllowed` and `LOOPBACK_ORIGIN_WILDCARDS`.
|
|
78
|
+
- **Breaking (`@nylorun/runtime`, `@nylorun/core`, `@nylorun/agents`): vault routes are application-only, and `vaults:own` is retired.** Every `/v1/vaults` route takes an application key acting for no one (operator keys, Studio); a request acting for a subject or a trusted issuer's token gets `403 scope_required`. `vaults:own` leaves `SUBJECT_SCOPES`, `TOKEN_SCOPES` and the issuer scopes; `Nylorun-Scopes` may still name it and it grants nothing. Existing user vaults stay attachable to their own owner's sessions. `client.createVault` takes `{ scope: "installation" }` or `ownerUserId`, and `client.listVaults()` takes an optional owner.
|
|
79
|
+
- **Breaking (`@nylorun/runtime`, `@nylorun/core`, `@nylorun/admin`, `nylorun`): derived principals are gone.** Only Studio's key is derived from the admin key. `NYLORUN_DERIVED_PRINCIPALS` is ignored and no longer written, `hostPrincipals` takes no `derived`, `startEphemeralRuntime` no `derivedPrincipals`, and `@nylorun/admin` drops `deriveTenantKey`, `PROJECT_PRINCIPAL_ID` and `admin.deriveTenantKey`. Keys an earlier Host derived stay in the database and keep working as ordinary keys; replace them with operator keys. Core renames `DERIVED_PRINCIPAL_ID_PATTERN` to `APPLICATION_KEY_ID_PATTERN`.
|
|
80
|
+
- **Breaking (`@nylorun/agents`):** `createTokenEndpoint`, `createBrowserClient` and the `@nylorun/agents/browser` entry, `client.tokens`, `TokensClient`, `PublishableKeysClient`, `client.access.getPolicy`/`putPolicy`/`revokeSubject`/`publishableKeys` and `Destination.publishableKey` are removed. `client.access.signingKeys` and `client.access.jwks()` stay, and `Destination.token` takes a trusted issuer's tokens.
|
|
81
|
+
- **Breaking (`@nylorun/cli`):** `nylo access policy|keys|revoke|token` are removed and name what replaces them; `nylo access signing-keys list|rotate|revoke` stays.
|
|
82
|
+
- **Breaking (`@nylorun/core`, `@nylorun/agents`, `@nylorun/studio`): the Studio embed message `open.babai` is now `open.session`** (`{ sessionId }`): it asks the embedding app to open that session in its own UI. Studio sends no such message itself.
|
|
83
|
+
- **Breaking (`nylorun`): Studio embedding is opt-in.** No origin may frame Studio by default; list your app's origins with `nylorun start --studio-embed-origin <origin>`. A Tenant's `.env` from an earlier nylorun keeps the origins it had until `--studio-embed-origin-reset`.
|
|
84
|
+
- `PROTOCOL_VERSION` is 7 and `HOST_PROTOCOL` 4–7; the Host features `subject-tokens`, `browser-access` and `derived-principals` are removed. `@nylorun/studio` and `@nylorun/create-agent` speak protocol 7.
|
|
85
|
+
|
|
86
|
+
### Patch Changes
|
|
87
|
+
|
|
88
|
+
- Pin agents to the tested release.
|
|
89
|
+
- Pin admin to the tested release.
|
|
90
|
+
- Updated dependencies [5cfaed9]
|
|
91
|
+
- Updated dependencies [bd478ee]
|
|
92
|
+
- Updated dependencies
|
|
93
|
+
- Updated dependencies
|
|
94
|
+
- @nylorun/agents@0.14.0-beta
|
|
95
|
+
- @nylorun/admin@0.10.0-beta
|
|
96
|
+
|
|
3
97
|
## 0.9.0-beta
|
|
4
98
|
|
|
5
99
|
### Major Changes
|
package/README.md
CHANGED
|
@@ -17,16 +17,19 @@ npx @nylorun/cli status # the linked Tenant
|
|
|
17
17
|
```sh
|
|
18
18
|
nylo status [--json] # the Tenant, its checks and counts
|
|
19
19
|
nylo reset [--sessions|--sandboxes|--all] [--yes]
|
|
20
|
-
nylo
|
|
21
|
-
nylo access … # access policy, publishable and signing keys, subject tokens
|
|
20
|
+
nylo access signing-keys … # the Tenant's signing keys: list, rotate, revoke
|
|
22
21
|
nylo configure # set or replace the Tenant's model provider
|
|
23
22
|
nylo env # export lines for the linked Project
|
|
24
|
-
nylo doctor sandbox [--json] # sandbox backend via the
|
|
23
|
+
nylo doctor sandbox [--json] # sandbox backend via the Management API
|
|
25
24
|
```
|
|
26
25
|
|
|
27
26
|
Every command acts on the linked installation: the Project link and
|
|
28
27
|
credentials (below), or `NYLORUN_RUNTIME_URL` and `NYLORUN_SERVER_KEY` when the
|
|
29
28
|
Project has no link. An installation serves one Tenant, so nothing selects it.
|
|
29
|
+
`status`, `reset`, `access`, `configure` and `doctor` use the Management API
|
|
30
|
+
with the Project's management key, or `NYLORUN_MANAGEMENT_KEY` (with
|
|
31
|
+
`NYLORUN_RUNTIME_URL` when there is no link); `endpoints` uses the Runtime API
|
|
32
|
+
with the application key.
|
|
30
33
|
|
|
31
34
|
Local Tenant commands (`up`, `down`, `start`, `stop`, `logs`, `studio`) exit 2
|
|
32
35
|
naming `npx nylorun <command>`. `nylo tenant …` exits 2: `npx nylorun start`
|
|
@@ -37,11 +40,11 @@ replace `nylo tenant status|reset|endpoints`. `nylorun dev` was removed: run
|
|
|
37
40
|
|
|
38
41
|
## `nylo status`
|
|
39
42
|
|
|
40
|
-
Reads the
|
|
41
|
-
Runtime URL, the checks, the counts and the sandbox
|
|
43
|
+
Reads the Management API's status (`GET /v1/tenant`, with a management key) and
|
|
44
|
+
prints the Tenant, the Runtime URL, the checks, the counts and the sandbox
|
|
42
45
|
backend. When the Tenant is not open it does not answer; `nylo status` then
|
|
43
|
-
|
|
44
|
-
|
|
46
|
+
fails and says to run `npx nylorun status`, which reports why from the
|
|
47
|
+
Runtime's container (`nylorun-operate status`).
|
|
45
48
|
|
|
46
49
|
## `nylo reset`
|
|
47
50
|
|
|
@@ -55,16 +58,18 @@ not in a terminal. The Project link and credentials are kept.
|
|
|
55
58
|
|
|
56
59
|
- `.nylorun/link.json`: `{ format: 3, tenant, hostUrl, hostId, tenantId }`
|
|
57
60
|
(`tenant` is the local Tenant's name; `tenantId` is information)
|
|
58
|
-
- `.nylorun/credentials.json
|
|
59
|
-
|
|
61
|
+
- `.nylorun/credentials.json` (0600): the application key `project` and the
|
|
62
|
+
management key `project-management`, with their ids (`applicationKey`,
|
|
63
|
+
`principalId`, `managementKey`, `managementPrincipalId`)
|
|
60
64
|
- `.nylorun/.gitignore` containing `*`
|
|
61
65
|
|
|
62
66
|
A link from an older nylorun (format 0 to 2): `nylo` refuses it and says to run
|
|
63
67
|
`npx nylorun start`, which links the project again.
|
|
64
68
|
|
|
65
|
-
`
|
|
66
|
-
|
|
67
|
-
|
|
69
|
+
`createClient` in `@nylorun/agents` reads the link (or the two variables), so the
|
|
70
|
+
project's `npm run dev` and `npm start`, which save its agents, need no Nylorun tool.
|
|
71
|
+
`nylo endpoints` was removed with Action endpoints (protocol 8): the Runtime runs no code
|
|
72
|
+
of yours during a session.
|
|
68
73
|
|
|
69
74
|
```sh
|
|
70
75
|
eval "$(npx @nylorun/cli env)"
|
|
@@ -86,7 +91,9 @@ eval "$(npx @nylorun/cli env)"
|
|
|
86
91
|
| Symptom | What to do |
|
|
87
92
|
| --- | --- |
|
|
88
93
|
| No Runtime answers | `npx nylorun start`, then `npx nylorun status` |
|
|
89
|
-
| Tenant not open | `
|
|
94
|
+
| Tenant not open | `npx nylorun status` shows the cause and its `repair` |
|
|
95
|
+
| No management key | `npx nylorun start` in the project writes one; elsewhere set `NYLORUN_MANAGEMENT_KEY` |
|
|
96
|
+
| `403 key_role_mismatch` | The key belongs to the other API: a management key for the Management API, an application key for the Runtime API |
|
|
90
97
|
| Old Project link refused | `npx nylorun start` in the project |
|
|
91
98
|
| `426` from the Runtime | Upgrade the CLI, or pin a matching older set |
|
|
92
99
|
|
|
@@ -1,24 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
agents: "*";
|
|
10
|
-
limits: {
|
|
11
|
-
turnsPerHour: number;
|
|
12
|
-
concurrentTurns: number;
|
|
13
|
-
};
|
|
14
|
-
};
|
|
15
|
-
};
|
|
16
|
-
anon: {
|
|
17
|
-
scopes: never[];
|
|
18
|
-
agents: never[];
|
|
19
|
-
};
|
|
20
|
-
tokens: {
|
|
21
|
-
maxTtlSeconds: number;
|
|
22
|
-
};
|
|
23
|
-
};
|
|
24
|
-
export declare function accessCommand(input: readonly string[], client?: () => Promise<AgentsClient>): Promise<void>;
|
|
1
|
+
/**
|
|
2
|
+
* `nylo access`: the linked Tenant's signing keys, which sign capability links and run tokens,
|
|
3
|
+
* through the Management API with the Project's management key. (Subject tokens, the
|
|
4
|
+
* access policy, browser keys and revocations left the Runtime in protocol 7.)
|
|
5
|
+
*/
|
|
6
|
+
import type { ManagementClient } from "@nylorun/admin";
|
|
7
|
+
export declare const accessUsage = "nylo access signing-keys <list|rotate|revoke>\n\n signing-keys list list the signing keys\n signing-keys rotate [--force] rotate; --force ends outstanding links and run tokens\n signing-keys revoke <kid> revoke a previous or standby key";
|
|
8
|
+
export declare function accessCommand(input: readonly string[], client?: () => Promise<ManagementClient>): Promise<void>;
|
package/dist/access/commands.js
CHANGED
|
@@ -1,91 +1,20 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `nylo access`: the linked Tenant's access policy, signing keys and revocations, and a
|
|
3
|
-
* development command that mints a subject token (Host feature `subject-tokens`). Uses the
|
|
4
|
-
* Project's application key, like every other Tenant command.
|
|
5
|
-
*/
|
|
6
|
-
import { readFile } from "node:fs/promises";
|
|
7
|
-
import { createClient, resolveConnection, } from "@nylorun/agents";
|
|
8
1
|
import { CliError } from "../errors.js";
|
|
9
|
-
|
|
2
|
+
import { linkedConnection, managementClient } from "../project/connection.js";
|
|
3
|
+
import { findProjectRoot } from "../project/root.js";
|
|
4
|
+
export const accessUsage = `nylo access signing-keys <list|rotate|revoke>
|
|
10
5
|
|
|
11
|
-
policy get print the access policy
|
|
12
|
-
policy set <file> replace it with a JSON file
|
|
13
|
-
policy init write a starter "user" role (sessions:own agents:read, every agent,
|
|
14
|
-
60 turns per hour, 2 at once)
|
|
15
6
|
signing-keys list list the signing keys
|
|
16
|
-
signing-keys rotate [--force] rotate; --force
|
|
17
|
-
signing-keys revoke <kid> revoke a previous or standby key
|
|
18
|
-
keys list list the publishable keys
|
|
19
|
-
keys create --name <n> [--origin <o>]…
|
|
20
|
-
a publishable key for a web page or an app
|
|
21
|
-
(origins: https://app.example.com or http://localhost:*)
|
|
22
|
-
keys set-origins <id> [<o>…] replace a key's origins ([] for native apps only)
|
|
23
|
-
keys revoke <id> revoke a publishable key
|
|
24
|
-
revoke <subject> end a subject's tokens and open streams
|
|
25
|
-
token --subject <s> --role <r> [--ttl <seconds>]
|
|
26
|
-
mint a subject token (for trying the API with curl)`;
|
|
27
|
-
/** The starter policy `policy init` writes. */
|
|
28
|
-
export const STARTER_POLICY = {
|
|
29
|
-
version: 1,
|
|
30
|
-
roles: {
|
|
31
|
-
user: {
|
|
32
|
-
scopes: ["sessions:own", "agents:read"],
|
|
33
|
-
agents: "*",
|
|
34
|
-
limits: { turnsPerHour: 60, concurrentTurns: 2 },
|
|
35
|
-
},
|
|
36
|
-
},
|
|
37
|
-
anon: { scopes: [], agents: [] },
|
|
38
|
-
tokens: { maxTtlSeconds: 600 },
|
|
39
|
-
};
|
|
7
|
+
signing-keys rotate [--force] rotate; --force ends outstanding links and run tokens
|
|
8
|
+
signing-keys revoke <kid> revoke a previous or standby key`;
|
|
40
9
|
const usageError = (message = accessUsage) => new CliError(message, 2);
|
|
41
10
|
async function linkedClient() {
|
|
42
|
-
|
|
43
|
-
try {
|
|
44
|
-
connection = await resolveConnection();
|
|
45
|
-
}
|
|
46
|
-
catch (error) {
|
|
47
|
-
throw new CliError(error instanceof Error ? error.message : String(error), 1);
|
|
48
|
-
}
|
|
49
|
-
return createClient({ url: connection.url, key: connection.key });
|
|
11
|
+
return managementClient(await linkedConnection(findProjectRoot() ?? process.cwd()));
|
|
50
12
|
}
|
|
51
13
|
const print = (value) => console.log(JSON.stringify(value, null, 2));
|
|
52
|
-
function option(args, name) {
|
|
53
|
-
const index = args.indexOf(name);
|
|
54
|
-
if (index === -1)
|
|
55
|
-
return undefined;
|
|
56
|
-
const value = args[index + 1];
|
|
57
|
-
if (!value || value.startsWith("--"))
|
|
58
|
-
throw usageError(`${name} requires a value.`);
|
|
59
|
-
args.splice(index, 2);
|
|
60
|
-
return value;
|
|
61
|
-
}
|
|
62
14
|
export async function accessCommand(input, client = linkedClient) {
|
|
63
|
-
const [topic, action, ...
|
|
64
|
-
const args = [...rest];
|
|
65
|
-
if (topic === "policy") {
|
|
66
|
-
if (action === "get" && args.length === 0)
|
|
67
|
-
return print(await (await client()).access.getPolicy());
|
|
68
|
-
if (action === "init" && args.length === 0)
|
|
69
|
-
return print(await (await client()).access.putPolicy(STARTER_POLICY));
|
|
70
|
-
if (action === "set" && args.length === 1) {
|
|
71
|
-
let parsed;
|
|
72
|
-
try {
|
|
73
|
-
parsed = JSON.parse(await readFile(args[0], "utf8"));
|
|
74
|
-
}
|
|
75
|
-
catch (error) {
|
|
76
|
-
throw new CliError(`Could not read ${args[0]}: ${error instanceof Error ? error.message : String(error)}`, 1);
|
|
77
|
-
}
|
|
78
|
-
// Accept the file as the policy itself or as `{ policy }`, as `policy get` prints it.
|
|
79
|
-
const candidate = parsed && typeof parsed === "object" && "policy" in parsed
|
|
80
|
-
? parsed.policy
|
|
81
|
-
: parsed;
|
|
82
|
-
// The Runtime validates it and names what is wrong.
|
|
83
|
-
return print(await (await client()).access.putPolicy(candidate));
|
|
84
|
-
}
|
|
85
|
-
throw usageError();
|
|
86
|
-
}
|
|
15
|
+
const [topic, action, ...args] = input;
|
|
87
16
|
if (topic === "signing-keys") {
|
|
88
|
-
const keys = async () => (await client()).
|
|
17
|
+
const keys = async () => (await client()).signingKeys;
|
|
89
18
|
if (action === "list" && args.length === 0)
|
|
90
19
|
return print(await (await keys()).list());
|
|
91
20
|
if (action === "rotate") {
|
|
@@ -98,47 +27,7 @@ export async function accessCommand(input, client = linkedClient) {
|
|
|
98
27
|
return print(await (await keys()).revoke(args[0]));
|
|
99
28
|
throw usageError();
|
|
100
29
|
}
|
|
101
|
-
if (topic === "keys")
|
|
102
|
-
|
|
103
|
-
if (action === "list" && args.length === 0)
|
|
104
|
-
return print(await (await keys()).list());
|
|
105
|
-
if (action === "create") {
|
|
106
|
-
const name = option(args, "--name");
|
|
107
|
-
const origins = [];
|
|
108
|
-
for (let origin = option(args, "--origin"); origin; origin = option(args, "--origin"))
|
|
109
|
-
origins.push(origin);
|
|
110
|
-
if (!name || args.length > 0)
|
|
111
|
-
throw usageError();
|
|
112
|
-
return print(await (await keys()).create({ name, origins }));
|
|
113
|
-
}
|
|
114
|
-
if (action === "set-origins" && args.length >= 1) {
|
|
115
|
-
const [keyId, ...origins] = args;
|
|
116
|
-
return print(await (await keys()).update(keyId, { origins }));
|
|
117
|
-
}
|
|
118
|
-
if (action === "revoke" && args.length === 1)
|
|
119
|
-
return print(await (await keys()).revoke(args[0]));
|
|
120
|
-
throw usageError();
|
|
121
|
-
}
|
|
122
|
-
if (topic === "revoke") {
|
|
123
|
-
if (!action || args.length > 0)
|
|
124
|
-
throw usageError();
|
|
125
|
-
return print(await (await client()).access.revokeSubject(action));
|
|
126
|
-
}
|
|
127
|
-
if (topic === "token") {
|
|
128
|
-
const all = [action, ...args].filter((arg) => arg !== undefined);
|
|
129
|
-
const subject = option(all, "--subject");
|
|
130
|
-
const role = option(all, "--role");
|
|
131
|
-
const ttl = option(all, "--ttl");
|
|
132
|
-
if (!subject || !role || all.length > 0)
|
|
133
|
-
throw usageError();
|
|
134
|
-
const ttlSeconds = ttl === undefined ? undefined : Number(ttl);
|
|
135
|
-
if (ttlSeconds !== undefined && !Number.isInteger(ttlSeconds))
|
|
136
|
-
throw usageError("--ttl must be a whole number of seconds.");
|
|
137
|
-
return print(await (await client()).tokens.create({
|
|
138
|
-
subject,
|
|
139
|
-
role,
|
|
140
|
-
...(ttlSeconds === undefined ? {} : { ttlSeconds }),
|
|
141
|
-
}));
|
|
142
|
-
}
|
|
30
|
+
if (topic === "policy" || topic === "keys" || topic === "revoke" || topic === "token")
|
|
31
|
+
throw usageError(`nylo access ${topic} was removed: the Runtime no longer mints subject tokens or keeps an access policy, browser keys or revocations (protocol 7). Trust your identity provider's tokens with an identity file, and give servers an application key (nylorun key put <id>).`);
|
|
143
32
|
throw usageError();
|
|
144
33
|
}
|
package/dist/cli.js
CHANGED
|
@@ -5,22 +5,18 @@ import { putHostModel } from "./model/host-model.js";
|
|
|
5
5
|
import { CliError } from "./errors.js";
|
|
6
6
|
import { findProjectRoot } from "./project/root.js";
|
|
7
7
|
import { printLinkedEnvExports } from "./project/env.js";
|
|
8
|
-
import { linkedConnection } from "./project/connection.js";
|
|
8
|
+
import { linkedConnection, managementClient } from "./project/connection.js";
|
|
9
9
|
import { accessCommand } from "./access/commands.js";
|
|
10
|
-
import {
|
|
11
|
-
const usage = `nylo <status|reset|
|
|
10
|
+
import { resetCommand, statusCommand } from "./installation/commands.js";
|
|
11
|
+
const usage = `nylo <status|reset|access|configure|env|doctor>
|
|
12
12
|
|
|
13
13
|
Runtime client for the linked installation and its one Tenant (the Project link that
|
|
14
|
-
npx nylorun start writes, or NYLORUN_RUNTIME_URL
|
|
14
|
+
npx nylorun start writes, or NYLORUN_RUNTIME_URL with NYLORUN_SERVER_KEY, and
|
|
15
|
+
NYLORUN_MANAGEMENT_KEY for status, reset, access, configure and doctor):
|
|
15
16
|
status [--json] the Tenant, its checks and counts
|
|
16
17
|
reset [--sessions|--sandboxes|--all] [--yes]
|
|
17
18
|
clear the Tenant's sessions, sandboxes or all its data
|
|
18
|
-
|
|
19
|
-
access policy get|set <file>|init the access policy for subject tokens (nylo access --help)
|
|
20
|
-
access keys list|create|set-origins|revoke publishable keys for web pages and apps
|
|
21
|
-
access signing-keys list|rotate|revoke the Tenant's token signing keys
|
|
22
|
-
access revoke <subject> end a subject's tokens and open streams
|
|
23
|
-
access token --subject <s> --role <r> mint a subject token for trying the API
|
|
19
|
+
access signing-keys list|rotate|revoke the Tenant's token signing keys (nylo access --help)
|
|
24
20
|
configure set the linked Tenant's model provider
|
|
25
21
|
env print the linked Project's NYLORUN_* variables as exports
|
|
26
22
|
doctor sandbox [--json] show which sandbox backend this Tenant's Host offers
|
|
@@ -33,7 +29,10 @@ const LOCAL_COMMANDS = new Set([
|
|
|
33
29
|
]);
|
|
34
30
|
const TENANT_REMOVED = `nylo tenant was removed: an installation serves one Tenant.
|
|
35
31
|
Run "npx nylorun start" in your project to create its Tenant and the Project link.
|
|
36
|
-
Then use nylo status
|
|
32
|
+
Then use nylo status and nylo reset on the linked installation.`;
|
|
33
|
+
const ENDPOINTS_REMOVED = `nylo endpoints was removed: the Runtime runs no code of yours during a session,
|
|
34
|
+
so there are no Action endpoints. An agent's tools are http() tools and remote MCP servers
|
|
35
|
+
(see MIGRATION.md).`;
|
|
37
36
|
function parseFlags(args, allowed = {}) {
|
|
38
37
|
const booleans = new Set();
|
|
39
38
|
const values = new Map();
|
|
@@ -82,7 +81,7 @@ async function main() {
|
|
|
82
81
|
if (command === "reset")
|
|
83
82
|
return await resetCommand(args);
|
|
84
83
|
if (command === "endpoints")
|
|
85
|
-
|
|
84
|
+
throw usageError(ENDPOINTS_REMOVED);
|
|
86
85
|
if (command === "access") {
|
|
87
86
|
if (args[0] === "--help" || args[0] === "-h" || args.length === 0) {
|
|
88
87
|
const { accessUsage } = await import("./access/commands.js");
|
|
@@ -114,6 +113,7 @@ async function main() {
|
|
|
114
113
|
throw usageError(usage);
|
|
115
114
|
const projectRoot = findProjectRoot() ?? process.cwd();
|
|
116
115
|
const auth = await linkedConnection(projectRoot);
|
|
116
|
+
const admin = managementClient(auth);
|
|
117
117
|
const controller = new AbortController();
|
|
118
118
|
const cancel = (signal) => controller.abort(new ConfigurationCancelled(signal));
|
|
119
119
|
process.once("SIGINT", () => cancel("SIGINT"));
|
|
@@ -121,12 +121,12 @@ async function main() {
|
|
|
121
121
|
const health = await fetch(`${auth.url}/health`).catch(() => undefined);
|
|
122
122
|
if (!health?.ok)
|
|
123
123
|
throw new CliError(`No Runtime is listening at ${auth.url}. Start the local Tenant with "npx nylorun start".`, 6);
|
|
124
|
-
const catalog = await fetchModelCatalog(
|
|
124
|
+
const catalog = await fetchModelCatalog(admin);
|
|
125
125
|
const prompted = await configureProvider({
|
|
126
126
|
signal: controller.signal,
|
|
127
127
|
catalog,
|
|
128
128
|
});
|
|
129
|
-
await putHostModel(
|
|
129
|
+
await putHostModel(admin, prompted);
|
|
130
130
|
return;
|
|
131
131
|
}
|
|
132
132
|
throw usageError(usage);
|
package/dist/doctor.d.ts
CHANGED
|
@@ -19,7 +19,7 @@ export type SandboxReport = {
|
|
|
19
19
|
};
|
|
20
20
|
};
|
|
21
21
|
};
|
|
22
|
-
/** `nylo doctor sandbox`: Tenant sandbox report via the
|
|
22
|
+
/** `nylo doctor sandbox`: Tenant sandbox report via the Management API (F2-4). */
|
|
23
23
|
export declare function doctorSandbox(options: {
|
|
24
24
|
json: boolean;
|
|
25
25
|
}): Promise<void>;
|
package/dist/doctor.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { release } from "node:os";
|
|
2
|
-
import { createClient, resolveConnection } from "@nylorun/agents";
|
|
3
2
|
import { CliError } from "./errors.js";
|
|
3
|
+
import { linkedConnection, managementClient } from "./project/connection.js";
|
|
4
|
+
import { findProjectRoot } from "./project/root.js";
|
|
4
5
|
function platformLine() {
|
|
5
6
|
const os = process.platform === "darwin"
|
|
6
7
|
? "macOS"
|
|
@@ -9,12 +10,12 @@ function platformLine() {
|
|
|
9
10
|
: process.platform;
|
|
10
11
|
return `${os} (kernel ${release()}) · ${process.arch}`;
|
|
11
12
|
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
return
|
|
13
|
+
/** The Tenant's sandbox report (`GET /v1/tenant/sandbox`, Management API). */
|
|
14
|
+
async function fetchSandboxReport() {
|
|
15
|
+
const connection = await linkedConnection(findProjectRoot() ?? process.cwd());
|
|
16
|
+
return (await managementClient(connection).settings.sandbox.get());
|
|
16
17
|
}
|
|
17
|
-
/** `nylo doctor sandbox`: Tenant sandbox report via the
|
|
18
|
+
/** `nylo doctor sandbox`: Tenant sandbox report via the Management API (F2-4). */
|
|
18
19
|
export async function doctorSandbox(options) {
|
|
19
20
|
let report;
|
|
20
21
|
try {
|
|
@@ -1,20 +1,7 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
|
+
* `nylo status [--json]`: the Tenant, its checks and counts. A Tenant that is not open does not
|
|
3
|
+
* answer: `npx nylorun status` reports why.
|
|
4
|
+
*/
|
|
2
5
|
export declare function statusCommand(args: readonly string[]): Promise<void>;
|
|
3
6
|
/** `nylo reset [--sessions|--sandboxes|--all] [--yes]`; `--all` asks first. */
|
|
4
7
|
export declare function resetCommand(args: readonly string[]): Promise<void>;
|
|
5
|
-
/** `nylo endpoints [--json]` and `nylo endpoints ping <agent>`. */
|
|
6
|
-
export declare function endpointsCommand(args: readonly string[]): Promise<void>;
|
|
7
|
-
/** One line of `nylo endpoints`: the agent, its URL and version, and how it is doing. */
|
|
8
|
-
export declare function endpointLine(endpoint: {
|
|
9
|
-
agentId: string;
|
|
10
|
-
url: string;
|
|
11
|
-
implementationVersion: string;
|
|
12
|
-
health: {
|
|
13
|
-
consecutiveFailures: number;
|
|
14
|
-
lastSuccessAt?: string;
|
|
15
|
-
lastError?: {
|
|
16
|
-
code: string;
|
|
17
|
-
message: string;
|
|
18
|
-
};
|
|
19
|
-
};
|
|
20
|
-
}): string;
|
|
@@ -1,63 +1,42 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `nylo status
|
|
3
|
-
*
|
|
2
|
+
* `nylo status` and `nylo reset`: the linked installation's one Tenant, through the Management
|
|
3
|
+
* API (the Project's management key).
|
|
4
4
|
*/
|
|
5
5
|
import { createInterface } from "node:readline/promises";
|
|
6
|
-
import { randomUUID } from "node:crypto";
|
|
7
|
-
import { createAdmin } from "@nylorun/admin";
|
|
8
|
-
import { createClient } from "@nylorun/agents";
|
|
9
6
|
import { CliError } from "../errors.js";
|
|
10
|
-
import { linkedConnection } from "../project/connection.js";
|
|
7
|
+
import { linkedConnection, managementClient } from "../project/connection.js";
|
|
11
8
|
import { findProjectRoot } from "../project/root.js";
|
|
12
9
|
const projectRoot = () => findProjectRoot() ?? process.cwd();
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
/**
|
|
11
|
+
* `nylo status [--json]`: the Tenant, its checks and counts. A Tenant that is not open does not
|
|
12
|
+
* answer: `npx nylorun status` reports why.
|
|
13
|
+
*/
|
|
15
14
|
export async function statusCommand(args) {
|
|
16
15
|
const json = args.includes("--json");
|
|
17
16
|
if (args.some((a) => a !== "--json"))
|
|
18
17
|
throw new CliError("Usage: nylo status [--json]", 2);
|
|
19
18
|
const root = projectRoot();
|
|
20
19
|
const connection = await linkedConnection(root);
|
|
21
|
-
|
|
20
|
+
const admin = managementClient(connection);
|
|
21
|
+
let body;
|
|
22
22
|
try {
|
|
23
|
-
|
|
24
|
-
if (json) {
|
|
25
|
-
console.log(JSON.stringify(body, null, 2));
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
console.log(`${body.tenant.name} ${body.tenant.id}`);
|
|
29
|
-
console.log(`runtime ${connection.url}`);
|
|
30
|
-
console.log(`path ${body.path}`);
|
|
31
|
-
console.log(`checks ${Object.entries(body.checks)
|
|
32
|
-
.map(([k, v]) => `${k}=${v ? "ok" : "fail"}`)
|
|
33
|
-
.join(" ")}`);
|
|
34
|
-
console.log(`counts sessions=${body.counts.sessions} running=${body.counts.runningSessions} pending=${body.counts.pendingActions}`);
|
|
35
|
-
console.log(`sandbox ${body.sandbox.backend ?? "none"}`);
|
|
36
|
-
return;
|
|
23
|
+
body = await admin.tenant.status();
|
|
37
24
|
}
|
|
38
25
|
catch (error) {
|
|
39
|
-
|
|
40
|
-
reason = error;
|
|
41
|
-
}
|
|
42
|
-
let tenant;
|
|
43
|
-
try {
|
|
44
|
-
tenant = (await createAdmin({ cwd: root }).status()).tenant;
|
|
45
|
-
}
|
|
46
|
-
catch {
|
|
47
|
-
throw new CliError(reason instanceof Error
|
|
48
|
-
? reason.message
|
|
49
|
-
: `The Tenant at ${connection.url} is not reachable.`, 1);
|
|
26
|
+
throw new CliError(`${(error instanceof Error ? error.message : `The Tenant at ${connection.url} is not reachable`).replace(/\.?$/, ".")} Run "npx nylorun status" to see the Tenant's state and why it is not open.`, 1);
|
|
50
27
|
}
|
|
51
28
|
if (json) {
|
|
52
|
-
console.log(JSON.stringify(
|
|
29
|
+
console.log(JSON.stringify(body, null, 2));
|
|
53
30
|
return;
|
|
54
31
|
}
|
|
55
|
-
console.log(`${tenant.name
|
|
32
|
+
console.log(`${body.tenant.name} ${body.tenant.id}`);
|
|
56
33
|
console.log(`runtime ${connection.url}`);
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
34
|
+
console.log(`path ${body.path}`);
|
|
35
|
+
console.log(`checks ${Object.entries(body.checks)
|
|
36
|
+
.map(([k, v]) => `${k}=${v ? "ok" : "fail"}`)
|
|
37
|
+
.join(" ")}`);
|
|
38
|
+
console.log(`counts sessions=${body.counts.sessions} running=${body.counts.runningSessions} uncertain=${body.counts.uncertainEffects}`);
|
|
39
|
+
console.log(`sandbox ${body.sandbox.backend ?? "none"}`);
|
|
61
40
|
}
|
|
62
41
|
const RESET_USAGE = "Usage: nylo reset [--sessions|--sandboxes|--all] [--yes]";
|
|
63
42
|
const SCOPES = { "--sessions": "sessions", "--sandboxes": "sandboxes", "--all": "all" };
|
|
@@ -73,14 +52,11 @@ export async function resetCommand(args) {
|
|
|
73
52
|
const connection = await linkedConnection(projectRoot());
|
|
74
53
|
const tenant = connection.link?.tenant;
|
|
75
54
|
const target = tenant ? `Tenant ${tenant} (${connection.url})` : `the Tenant on ${connection.url}`;
|
|
55
|
+
const admin = managementClient(connection);
|
|
76
56
|
if (scope === "all" && !yes)
|
|
77
57
|
await confirmOrThrow(`Reset ALL data of ${target}? The Project link and credentials are kept. [y/N] `);
|
|
78
58
|
try {
|
|
79
|
-
await
|
|
80
|
-
requestId: randomUUID(),
|
|
81
|
-
scope,
|
|
82
|
-
activeWork: "drain",
|
|
83
|
-
});
|
|
59
|
+
await admin.tenant.reset({ scope, activeWork: "drain" });
|
|
84
60
|
}
|
|
85
61
|
catch (error) {
|
|
86
62
|
throw new CliError(error instanceof Error ? error.message : `Tenant reset failed: ${String(error)}`, 1);
|
|
@@ -102,40 +78,3 @@ async function confirmOrThrow(prompt) {
|
|
|
102
78
|
rl.close();
|
|
103
79
|
}
|
|
104
80
|
}
|
|
105
|
-
/** `nylo endpoints [--json]` and `nylo endpoints ping <agent>`. */
|
|
106
|
-
export async function endpointsCommand(args) {
|
|
107
|
-
if (args[0] === "ping") {
|
|
108
|
-
const agentId = args[1];
|
|
109
|
-
if (!agentId || args.length > 2)
|
|
110
|
-
throw new CliError("Usage: nylo endpoints ping <agent>", 2);
|
|
111
|
-
const client = clientFor(await linkedConnection(projectRoot()));
|
|
112
|
-
const answer = await client.transport.json(`/v1/endpoints/${encodeURIComponent(agentId)}/ping`, "POST");
|
|
113
|
-
console.log(`${answer.agentId} serves ${answer.implementationVersion}${answer.manifestHash ? ` ${answer.manifestHash}` : ""}`);
|
|
114
|
-
return;
|
|
115
|
-
}
|
|
116
|
-
const json = args.includes("--json");
|
|
117
|
-
if (args.some((a) => a !== "--json"))
|
|
118
|
-
throw new CliError("Usage: nylo endpoints [--json] | nylo endpoints ping <agent>", 2);
|
|
119
|
-
const client = clientFor(await linkedConnection(projectRoot()));
|
|
120
|
-
const body = await client.transport.json("/v1/endpoints", "GET");
|
|
121
|
-
if (json) {
|
|
122
|
-
console.log(JSON.stringify(body, null, 2));
|
|
123
|
-
return;
|
|
124
|
-
}
|
|
125
|
-
if (body.endpoints.length === 0) {
|
|
126
|
-
console.log("No Action endpoints. Register one with createActionHandler(...).register({ url }).");
|
|
127
|
-
return;
|
|
128
|
-
}
|
|
129
|
-
for (const endpoint of body.endpoints)
|
|
130
|
-
console.log(endpointLine(endpoint));
|
|
131
|
-
}
|
|
132
|
-
/** One line of `nylo endpoints`: the agent, its URL and version, and how it is doing. */
|
|
133
|
-
export function endpointLine(endpoint) {
|
|
134
|
-
const { health } = endpoint;
|
|
135
|
-
const state = health.consecutiveFailures > 0
|
|
136
|
-
? `failing (${health.consecutiveFailures}): ${health.lastError?.message || health.lastError?.code || "unknown"}`
|
|
137
|
-
: health.lastSuccessAt
|
|
138
|
-
? `ok (last ${health.lastSuccessAt})`
|
|
139
|
-
: "no deliveries yet";
|
|
140
|
-
return `${endpoint.agentId} ${endpoint.url} ${endpoint.implementationVersion} ${state}`;
|
|
141
|
-
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Readable, Writable } from "node:stream";
|
|
2
2
|
import type { Credential } from "@earendil-works/pi-ai";
|
|
3
|
+
import type { ManagementClient } from "@nylorun/admin";
|
|
3
4
|
export declare class ConfigurationCancelled extends Error {
|
|
4
5
|
readonly signal: "SIGINT" | "SIGTERM";
|
|
5
6
|
readonly exitCode: number;
|
|
@@ -37,12 +38,8 @@ export type Selection = Readonly<{
|
|
|
37
38
|
baseUrl: string;
|
|
38
39
|
}>;
|
|
39
40
|
}>;
|
|
40
|
-
/**
|
|
41
|
-
export declare function fetchModelCatalog(
|
|
42
|
-
url: string;
|
|
43
|
-
key: string;
|
|
44
|
-
fetchImpl?: typeof fetch;
|
|
45
|
-
}): Promise<ModelCatalog>;
|
|
41
|
+
/** The Tenant's model catalog (`GET /v1/tenant/models`, Management API). */
|
|
42
|
+
export declare function fetchModelCatalog(admin: ManagementClient): Promise<ModelCatalog>;
|
|
46
43
|
export declare function configureProvider(options?: {
|
|
47
44
|
signal?: AbortSignal;
|
|
48
45
|
root?: string;
|
package/dist/model/configure.js
CHANGED
|
@@ -109,22 +109,9 @@ function modelsFor(selection, credentials, catalog) {
|
|
|
109
109
|
},
|
|
110
110
|
};
|
|
111
111
|
}
|
|
112
|
-
/**
|
|
113
|
-
export async function fetchModelCatalog(
|
|
114
|
-
|
|
115
|
-
const { PROTOCOL_HEADER, PROTOCOL_VERSION } = await import("@nylorun/agents");
|
|
116
|
-
const response = await fetchImpl(`${options.url.replace(/\/$/, "")}/v1/tenant/models`, {
|
|
117
|
-
headers: {
|
|
118
|
-
authorization: `Bearer ${options.key}`,
|
|
119
|
-
[PROTOCOL_HEADER]: String(PROTOCOL_VERSION),
|
|
120
|
-
Accept: "application/json",
|
|
121
|
-
},
|
|
122
|
-
signal: AbortSignal.timeout(10_000),
|
|
123
|
-
});
|
|
124
|
-
if (!response.ok) {
|
|
125
|
-
throw new Error(`Runtime model catalog returned ${response.status}`);
|
|
126
|
-
}
|
|
127
|
-
return (await response.json());
|
|
112
|
+
/** The Tenant's model catalog (`GET /v1/tenant/models`, Management API). */
|
|
113
|
+
export async function fetchModelCatalog(admin) {
|
|
114
|
+
return await admin.models.catalog();
|
|
128
115
|
}
|
|
129
116
|
// Internal options also allow isolated prompt tests without changing process globals.
|
|
130
117
|
export async function configureProvider(options = {}) {
|
|
@@ -1,18 +1,4 @@
|
|
|
1
|
+
import type { ManagementClient } from "@nylorun/admin";
|
|
1
2
|
import type { PromptedModel } from "./configure.js";
|
|
2
|
-
/**
|
|
3
|
-
|
|
4
|
-
readonly configured: false;
|
|
5
|
-
} | {
|
|
6
|
-
readonly configured: true;
|
|
7
|
-
readonly provider: string;
|
|
8
|
-
readonly model: string;
|
|
9
|
-
readonly authType: "api_key" | "oauth";
|
|
10
|
-
readonly baseUrl?: string;
|
|
11
|
-
readonly settings?: {
|
|
12
|
-
contextWindow?: number;
|
|
13
|
-
maxTokens?: number;
|
|
14
|
-
};
|
|
15
|
-
};
|
|
16
|
-
/** Set the installation's Tenant model provider (`PUT /v1/tenant/model`). */
|
|
17
|
-
export declare function putHostModel(runtimeUrl: string, serverKey: string, model: PromptedModel, fetchImpl?: typeof fetch): Promise<HostModelView>;
|
|
18
|
-
export {};
|
|
3
|
+
/** Set the installation's Tenant model provider (`PUT /v1/tenant/model`, Management API). */
|
|
4
|
+
export declare function putHostModel(admin: ManagementClient, model: PromptedModel): ReturnType<ManagementClient["models"]["put"]>;
|
package/dist/model/host-model.js
CHANGED
|
@@ -1,26 +1,13 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
body: JSON.stringify({
|
|
13
|
-
requestId: randomUUID(),
|
|
14
|
-
idempotencyKey: randomUUID(),
|
|
15
|
-
provider: model.provider,
|
|
16
|
-
model: model.model,
|
|
17
|
-
...(model.baseUrl ? { baseUrl: model.baseUrl } : {}),
|
|
18
|
-
...(model.settings ? { settings: model.settings } : {}),
|
|
19
|
-
auth: model.auth,
|
|
20
|
-
}),
|
|
2
|
+
/** Set the installation's Tenant model provider (`PUT /v1/tenant/model`, Management API). */
|
|
3
|
+
export async function putHostModel(admin, model) {
|
|
4
|
+
return await admin.models.put({
|
|
5
|
+
idempotencyKey: randomUUID(),
|
|
6
|
+
provider: model.provider,
|
|
7
|
+
model: model.model,
|
|
8
|
+
...(model.baseUrl ? { baseUrl: model.baseUrl } : {}),
|
|
9
|
+
...(model.settings ? { settings: model.settings } : {}),
|
|
10
|
+
// A prompted credential is complete: pi-ai's type leaves its fields optional.
|
|
11
|
+
auth: model.auth,
|
|
21
12
|
});
|
|
22
|
-
const body = (await response.json().catch(() => ({})));
|
|
23
|
-
if (!response.ok)
|
|
24
|
-
throw new Error(body.message ?? `Runtime rejected the model provider (${response.status})`);
|
|
25
|
-
return body;
|
|
26
13
|
}
|
|
@@ -1,13 +1,20 @@
|
|
|
1
|
+
import { type ManagementClient } from "@nylorun/admin";
|
|
1
2
|
import { type ProjectLink } from "./link.js";
|
|
2
|
-
/** The installation `nylo` acts on: a Runtime URL
|
|
3
|
+
/** The installation `nylo` acts on: a Runtime URL, an application key and a management key. */
|
|
3
4
|
export interface LinkedConnection {
|
|
4
5
|
url: string;
|
|
5
|
-
key
|
|
6
|
+
/** The application key (Runtime API); absent when only a management key is set. */
|
|
7
|
+
key?: string;
|
|
8
|
+
/** The management key (Management API), when there is one. */
|
|
9
|
+
managementKey?: string;
|
|
6
10
|
/** The Project link it came from, when it came from one. */
|
|
7
11
|
link?: ProjectLink;
|
|
8
12
|
}
|
|
9
13
|
/**
|
|
10
|
-
* The Project's link and credentials, else `NYLORUN_RUNTIME_URL`
|
|
11
|
-
*
|
|
14
|
+
* The Project's link and credentials, else `NYLORUN_RUNTIME_URL` with `NYLORUN_SERVER_KEY`, or
|
|
15
|
+
* `NYLORUN_MANAGEMENT_KEY`, or both; `NYLORUN_MANAGEMENT_KEY` also stands in for a Project
|
|
16
|
+
* credentials file without one. The installation serves one Tenant, so nothing names it.
|
|
12
17
|
*/
|
|
13
18
|
export declare function linkedConnection(projectRoot: string, env?: Readonly<Record<string, string | undefined>>): Promise<LinkedConnection>;
|
|
19
|
+
/** The Management API client of `connection`; refused without a management key. */
|
|
20
|
+
export declare function managementClient(connection: LinkedConnection): ManagementClient;
|
|
@@ -1,18 +1,38 @@
|
|
|
1
|
+
import { createManagementClient } from "@nylorun/admin";
|
|
1
2
|
import { CliError } from "../errors.js";
|
|
2
3
|
import { readCredentials } from "./credentials.js";
|
|
3
4
|
import { readLink } from "./link.js";
|
|
4
5
|
/**
|
|
5
|
-
* The Project's link and credentials, else `NYLORUN_RUNTIME_URL`
|
|
6
|
-
*
|
|
6
|
+
* The Project's link and credentials, else `NYLORUN_RUNTIME_URL` with `NYLORUN_SERVER_KEY`, or
|
|
7
|
+
* `NYLORUN_MANAGEMENT_KEY`, or both; `NYLORUN_MANAGEMENT_KEY` also stands in for a Project
|
|
8
|
+
* credentials file without one. The installation serves one Tenant, so nothing names it.
|
|
7
9
|
*/
|
|
8
10
|
export async function linkedConnection(projectRoot, env = process.env) {
|
|
9
11
|
const link = await readLink(projectRoot);
|
|
10
12
|
const credentials = await readCredentials(projectRoot);
|
|
11
|
-
|
|
12
|
-
|
|
13
|
+
const managementKey = env.NYLORUN_MANAGEMENT_KEY?.trim();
|
|
14
|
+
if (link && credentials) {
|
|
15
|
+
const management = credentials.managementKey ?? managementKey;
|
|
16
|
+
return {
|
|
17
|
+
url: link.hostUrl,
|
|
18
|
+
key: credentials.applicationKey,
|
|
19
|
+
...(management ? { managementKey: management } : {}),
|
|
20
|
+
link,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
13
23
|
const url = env.NYLORUN_RUNTIME_URL?.trim();
|
|
14
24
|
const key = env.NYLORUN_SERVER_KEY?.trim();
|
|
15
|
-
if (url && key)
|
|
16
|
-
return {
|
|
17
|
-
|
|
25
|
+
if (url && (key || managementKey))
|
|
26
|
+
return {
|
|
27
|
+
url: url.replace(/\/$/, ""),
|
|
28
|
+
...(key ? { key } : {}),
|
|
29
|
+
...(managementKey ? { managementKey } : {}),
|
|
30
|
+
};
|
|
31
|
+
throw new CliError(`No Project link in ${projectRoot}. Run "npx nylorun start" in this project to start its Tenant and link it, or set NYLORUN_RUNTIME_URL and NYLORUN_SERVER_KEY (or NYLORUN_MANAGEMENT_KEY).`, 1);
|
|
32
|
+
}
|
|
33
|
+
/** The Management API client of `connection`; refused without a management key. */
|
|
34
|
+
export function managementClient(connection) {
|
|
35
|
+
if (!connection.managementKey)
|
|
36
|
+
throw new CliError(`No management key for the Tenant at ${connection.url}: run npx nylorun start, or set NYLORUN_MANAGEMENT_KEY.`, 1);
|
|
37
|
+
return createManagementClient({ url: connection.url, key: connection.managementKey });
|
|
18
38
|
}
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Project-local credentials (mode 0600): the application key and its principal
|
|
3
|
-
*
|
|
2
|
+
* Project-local credentials (mode 0600): the application key and its principal, and the
|
|
3
|
+
* management key and its principal when `nylorun start` issued one. A format 0 file may still
|
|
4
|
+
* carry a legacy `executors` map from before protocol 3; it is ignored.
|
|
4
5
|
*/
|
|
5
6
|
export interface ProjectCredentials {
|
|
6
7
|
format: 0 | 1;
|
|
7
8
|
applicationKey: string;
|
|
8
9
|
principalId: string;
|
|
10
|
+
managementKey?: string;
|
|
11
|
+
managementPrincipalId?: string;
|
|
9
12
|
}
|
|
10
13
|
/** The Project's credentials, which `nylorun start` writes beside the link. */
|
|
11
14
|
export declare function readCredentials(projectRoot: string): Promise<ProjectCredentials | undefined>;
|
|
@@ -25,6 +25,11 @@ export async function readCredentials(projectRoot) {
|
|
|
25
25
|
format,
|
|
26
26
|
applicationKey: value.applicationKey,
|
|
27
27
|
principalId: value.principalId,
|
|
28
|
+
...(typeof value.managementKey === "string" &&
|
|
29
|
+
/^[0-9a-f]{64}$/.test(value.managementKey) &&
|
|
30
|
+
typeof value.managementPrincipalId === "string"
|
|
31
|
+
? { managementKey: value.managementKey, managementPrincipalId: value.managementPrincipalId }
|
|
32
|
+
: {}),
|
|
28
33
|
};
|
|
29
34
|
}
|
|
30
35
|
catch (error) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nylorun/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0-beta",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"description": "Nylorun Runtime client: the linked installation's Tenant, its access and its model provider",
|
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
"prepack": "npm run build"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@nylorun/agents": "0.
|
|
34
|
-
"@nylorun/admin": "0.
|
|
33
|
+
"@nylorun/agents": "0.16.0-beta",
|
|
34
|
+
"@nylorun/admin": "0.11.1-beta",
|
|
35
35
|
"@earendil-works/pi-ai": "0.99.1"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|