@nylorun/cli 0.6.0-beta → 0.8.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 CHANGED
@@ -1,5 +1,63 @@
1
1
  # @nylorun/cli
2
2
 
3
+ ## 0.8.0-beta
4
+
5
+ ### Minor Changes
6
+
7
+ - 4b9906f: **Breaking: "Tenant" replaces "stack", and `nylorun start` works anywhere.** Each local installation holds one Tenant, and its name is the Tenant's name, so help, output, errors and docs say Tenant. See MIGRATION.md.
8
+
9
+ - **Breaking (`nylorun`): selection.** Every command acts on the Tenant `--tenant <name>` names (replaces `--name`, which is removed), else `NYLORUN_TENANT` (replaces `NYLORUN_STACK`), else the Project link's `tenant`; `start` in a project names a new one after the project directory. Outside a project, or with `start --no-link`, commands act on the Tenant `default`. In a project without a link, commands other than `start` exit 2 and list the machine's Tenants. A name starting with `tn_` (a Tenant id) is refused.
10
+ - **Breaking (`nylorun`): files.** Host roots are under `~/.nylorun/tenants/<name>/` (was `~/.nylorun/stacks/<name>/`) with `tenant.json` (was `stack.json`); the `.env` key is `NYLORUN_TENANT_NAME` (was `NYLORUN_STACK_NAME`); `NYLORUN_COMPOSE_PROJECT` replaces `NYLORUN_STACK_PROJECT`. Compose projects stay `nylorun-<name>`. Every command first moves 0.4 Host roots from `~/.nylorun/stacks/` to `~/.nylorun/tenants/` (renaming `stack.json` and the `.env` key), so they keep their volumes and keys. `nylorun ls` lists only directories with `tenant.json`.
11
+ - **Breaking (`nylorun`): removed.** `nylorun legacy` and all handling of the single stack of releases before 0.4; the hidden `nylorun stack <cmd>` alias; `nylorun doctor stack|runtime`. Output says Tenant: `ls` prints `TENANT` and JSON `{ "tenants": [...] }`, `status` prints the Tenant id on its own line, and `doctor`'s row is `tenant`.
12
+ - **Breaking: Project link format 3.** `.nylorun/link.json` is `{ "format": 3, "tenant", "tenantId", "hostUrl", "hostId" }`; `tenant` replaces `stack`. `@nylorun/agents`, `@nylorun/cli` and `@nylorun/admin` refuse an older link and name `npx nylorun start`, which rewrites it. `@nylorun/core`'s `ProjectLinkFileSchema` parses formats 0–3 with `tenant`.
13
+ - **Breaking (`@nylorun/admin`):** `createAdmin({ tenant })` replaces `{ stack }`, `tenantHostRoot(name)` replaces `stackHostRoot(name)`, and local resolution reads `NYLORUN_TENANT` and the link's `tenant`.
14
+ - `@nylorun/cli`: `status` and `endpoints` drop the `stack` line and JSON key; messages say Tenant. `@nylorun/agents`: a Runtime too old for the client says "update the Runtime (npx nylorun@latest start)". `@nylorun/studio`: setup hints say Tenant. `@nylorun/create-agent`: the next steps describe `npx nylorun@beta start` as this project's Tenant and its link.
15
+
16
+ ### Patch Changes
17
+
18
+ - Pin agents to the tested release.
19
+ - Pin admin to the tested release.
20
+ - Updated dependencies [4b9906f]
21
+ - Updated dependencies
22
+ - Updated dependencies
23
+ - @nylorun/agents@0.12.0-beta
24
+ - @nylorun/admin@0.8.0-beta
25
+
26
+ ## 0.7.0-beta
27
+
28
+ ### Major Changes
29
+
30
+ - 5ca1923: **Clients for one Tenant per installation: a stack per project, nothing selects a Tenant.** Upgrade these with the Runtime; they speak protocol 5. Existing stacks are left as they are: see MIGRATION.md.
31
+
32
+ - **Breaking (`nylorun`): one stack per project.** `nylorun start` in a project creates the project's stack (named after the project directory, or `--name`; Host root `~/.nylorun/stacks/<name>/`, Compose project `nylorun-<name>`, its own free ports and volumes), waits for its Runtime to create the stack's Tenant, writes the Project link (`.nylorun/link.json` format 2: `stack`, `hostUrl`, `hostId`, `tenantId`) and `.nylorun/credentials.json` (the key of the derived principal `project`, derived from the stack's admin key), and seeds the model provider from the project's `.env`. `nylorun ls` lists the machine's stacks and `nylorun delete <name>` removes one with its volumes and Host root. `nylorun status` shows the stack's Tenant; `nylorun studio` opens it. The old single stack under `~/.nylorun` is never touched: `start` notes it, and `nylorun legacy stop|delete` handles it. Every stack command takes `--name <stack>` (or `NYLORUN_STACK`, or the Project link's stack); `start --no-link` starts a stack without linking the directory; `nylorun reset` resets the selected stack only. The runtime container's healthcheck is now `/health`, so a Tenant that cannot open is reported by `start` from the Admin status at once instead of after a 300 s wait. `NYLORUN_HOME` still overrides the Host root. Stacks start and stop only when you say so.
33
+ - **Breaking (`@nylorun/cli`): no Tenant commands.** `nylo tenant create|use|list|current|delete` are removed; `nylo status`, `nylo reset` and `nylo endpoints` replace `nylo tenant status|reset|endpoints` on the linked installation. `nylo env` prints `NYLORUN_RUNTIME_URL` and `NYLORUN_SERVER_KEY` only. `nylo` no longer writes Project links.
34
+ - **Breaking (`@nylorun/agents`): no Tenant to name.** The `tenant` option (`createClient`, `Transport`, `resolveConnection`, `createActionHandler({ runtime })`, `JwksCache`) and `NYLORUN_TENANT` are gone, and no request sends `Nylorun-Tenant`; a connection is a URL and a key. A Project link of format 0 or 1 is refused with `connection_missing`, naming `npx nylorun start`. `verifyDeliveryToken`'s `tenantId` is optional: without it any Tenant issuer is accepted, since the installation's keys bind it. `TENANT_HEADER` is no longer re-exported.
35
+ - **Breaking (`@nylorun/admin`): status only.** `createTenant`, `listTenants`, `getTenant` and `deleteTenant` are removed; `status().tenant` names the Host's Tenant, and `deriveTenantKey` / `deriveStudioToken` derive its keys. Local Host resolution reads the stack's Host root (`stack` option, `NYLORUN_STACK`, or the Project link's `stack`); `NYLORUN_HOME` and `home` still override it. `stackHostRoot(name)` is exported.
36
+ - **Breaking (`@nylorun/studio`): Studio serves its installation's Tenant.** The Tenant picker, list and create are gone, with `/_studio/tenants`; `/` opens `/tenants/<id>`. The `/tenants/:tenant` routes and the login token's `tenant` claim stay for embedders and must name that Tenant. The proxy sends no `Nylorun-Tenant`.
37
+ - **`@nylorun/create-agent`:** the next steps are `npx nylorun start`, then `npm run dev`.
38
+ - `@nylorun/core`: `ProjectLinkFileSchema` accepts format 2 with `stack`, and `tenantId` is optional; `ERROR_CODES` loses `tenant_conflict` and `active_work`.
39
+
40
+ - 5ca1923: **One Tenant per installation: a database per Tenant, protocol 5.** A Runtime serves exactly one Tenant, the one its Postgres database holds. Two Tenants are two installations.
41
+
42
+ - **Breaking: fresh start.** The Tenant's state is in the fixed schema `nylorun` of its own database and its record in `nylorun_streams`, keyed by session (no `tenant_id`). A database written by an earlier Runtime (`tenant_<id>` schemas, or a record keyed by Tenant) is refused: the Host stays up but not ready, and `/v1/admin/status` names the cause `database-layout-old`. Point the Runtime at a new database (with the local stack, a new stack); the old one is never changed.
43
+ - **The Host creates its Tenant** on first start, in the migration transaction: `NYLORUN_TENANT_ID` (default a new id), `NYLORUN_TENANT_NAME` (default `default`), the Studio principal and the derived principals of `NYLORUN_DERIVED_PRINCIPALS` (comma-separated, default `project`), whose keys the admin key derives (`deriveTenantKey`). Later starts open the same Tenant and add derived principals configured since.
44
+ - **Breaking: no Tenant catalog.** `/v1/admin/tenants` and `/v1/admin/tenants/{tenantId}` are gone (404). `AdminStatus.tenants[]` is replaced by `AdminStatus.tenant` (`id`, `name`, `state: open | unavailable`, `envelope`, and `cause` when it could not be opened). `CreateTenantRequestSchema`, `AdminTenantSchema`, `AdminTenantStatusSchema`, `AdminTenantListSchema` and `QuarantineSchema` leave `@nylorun/core`; `HostTenantSchema` and `TenantCauseSchema` replace them. `@nylorun/admin`'s `listTenants`, `getTenant`, `deleteTenant` and `createTenant` are removed (see below).
45
+ - **Readiness instead of quarantine.** A Tenant that cannot be opened (`schema-too-new`, `kek-missing`, `migration-failed`, `envelope-invalid`, `database-layout-old`, …) fails `/ready` (check `tenant`, which replaces `discovery`) and is reported with its repair in `/v1/admin/status` and the log; every Tenant request gets the opaque 404. A failure outside it (Postgres unreachable) is retried.
46
+ - **Protocol 5.** `PROTOCOL_VERSION = 5`; the Host serves protocols 4 and 5 for one release. Clients no longer require `runtime-tenants`; the Host still advertises it. No request needs `Nylorun-Tenant`: a request without it reaches the Host's Tenant, and one naming another Tenant (or a malformed one), or a publishable key of another Tenant, gets the opaque 404. The OpenAPI documents drop the header parameter and the Admin Tenant routes.
47
+ - **Paths.** The Tenant directory is `<Host root>/tenant/` (was `tenants/<id>/`); `trash/` and the SQLite move to it are gone. The gates service serves its database's Tenant, and its `Nylorun-Tenant` header is optional (when sent, it must name that Tenant).
48
+ - **Breaking: `startEphemeralRuntime` needs a database; the in-memory Session Store is removed.** `StartEphemeralRuntimeOptions.database` is required: a Postgres URL, for which the Runtime opens a pool and ends it on `close()`, or a pool the caller ends. It creates its Tenant in that database through the same bootstrap as a Host, or serves the Tenant the database already holds; the data stays after `close()`, so give each test Tenant a database of its own. Durable Streams and scheduling stay in process. See `MIGRATION.md`.
49
+
50
+ ### Patch Changes
51
+
52
+ - Pin agents to the tested release.
53
+ - Pin admin to the tested release.
54
+ - Updated dependencies [5ca1923]
55
+ - Updated dependencies [5ca1923]
56
+ - Updated dependencies
57
+ - Updated dependencies
58
+ - @nylorun/agents@0.11.0-beta
59
+ - @nylorun/admin@0.7.0-beta
60
+
3
61
  ## 0.6.0-beta
4
62
 
5
63
  ### Minor Changes
package/README.md CHANGED
@@ -1,83 +1,74 @@
1
1
  # @nylorun/cli
2
2
 
3
- The Runtime client, command `nylo`: it acts on a Runtime's Tenants, the local
4
- stack's or any Runtime reachable by URL and key. Setting up and running the
5
- local stack is [`nylorun`](../nylorun/README.md)'s job; the two packages are
6
- independent and never call each other. Depends on `@nylorun/agents` and
7
- `@nylorun/admin` only among Nylorun packages. Vocabulary:
3
+ The Runtime client, command `nylo`: it acts on the one Tenant of an
4
+ installation, a local Tenant or any Runtime reachable by URL and key. Setting up
5
+ and running local Tenants is [`nylorun`](../nylorun/README.md)'s job; the two
6
+ packages are independent and never call each other. Depends on
7
+ `@nylorun/agents` and `@nylorun/admin` only among Nylorun packages. Vocabulary:
8
8
  [runtime/src/CONTEXT.md](../runtime/src/CONTEXT.md).
9
9
 
10
10
  ```sh
11
- npx nylorun up # the local stack (nylorun)
12
- npx @nylorun/cli tenant create # this project's Tenant, linked in .nylorun/
13
- npx @nylorun/cli tenant use <id> # or: link a Tenant created in Studio
11
+ npx nylorun start # in the project: its Tenant and the Project link
12
+ npx @nylorun/cli status # the linked Tenant
14
13
  ```
15
14
 
16
15
  ## Commands
17
16
 
18
17
  ```sh
19
- nylo tenant create [name] # create a Tenant; in a Project, link it and seed it from .env
20
- nylo tenant current|list [--json]|use <name-or-id>|status [--json]|reset|delete
21
- nylo configure # set or replace the model provider on the linked Tenant
18
+ nylo status [--json] # the Tenant, its checks and counts
19
+ nylo reset [--sessions|--sandboxes|--all] [--yes]
20
+ nylo endpoints [--json]|ping <agent> # the registered Action endpoints and their health
21
+ nylo access … # access policy, publishable and signing keys, subject tokens
22
+ nylo configure # set or replace the Tenant's model provider
22
23
  nylo env # export lines for the linked Project
23
24
  nylo doctor sandbox [--json] # sandbox backend via the Tenant API
24
25
  ```
25
26
 
26
- Local stack commands (`up`, `down`, `start`, `stop`, `status`, `logs`,
27
- `studio`, `reset`) exit 2 naming `npx nylorun <command>`. `nylorun dev` was
28
- removed: link once with `nylo tenant create`, then run the project's own
29
- `npm run dev` (`tsx watch src/main.ts`).
27
+ Every command acts on the linked installation: the Project link and
28
+ credentials (below), or `NYLORUN_RUNTIME_URL` and `NYLORUN_SERVER_KEY` when the
29
+ Project has no link. An installation serves one Tenant, so nothing selects it.
30
30
 
31
- ## `nylo tenant create`
31
+ Local Tenant commands (`up`, `down`, `start`, `stop`, `logs`, `studio`) exit 2
32
+ naming `npx nylorun <command>`. `nylo tenant …` exits 2: `npx nylorun start`
33
+ creates the project's Tenant and the link, and `nylo status|reset|endpoints`
34
+ replace `nylo tenant status|reset|endpoints`. `nylorun dev` was removed: run
35
+ `npx nylorun start` once, then the project's own `npm run dev`
36
+ (`tsx watch src/main.ts`).
32
37
 
33
- The Admin API connection resolves from `NYLORUN_ADMIN_URL` and
34
- `NYLORUN_ADMIN_KEY`, else from the local Host root (`NYLORUN_HOME` or
35
- `~/.nylorun`: `host.json` and the admin key that `nylorun up` wrote). With no
36
- Runtime answering, it exits 6 and names `npx nylorun up`.
38
+ ## `nylo status`
37
39
 
38
- Inside a Project (the nearest `.nylorun/` or `package.json`):
40
+ Reads the Tenant API status (`GET /v1/tenant`) and prints the Tenant, the
41
+ Runtime URL, the checks, the counts and the sandbox
42
+ backend. When the Tenant is not open it does not answer; `nylo status` then
43
+ asks the Admin API (`/v1/admin/status`, through the local Tenant's Host root or
44
+ `NYLORUN_ADMIN_URL` and `NYLORUN_ADMIN_KEY`) and prints why, with the repair.
39
45
 
40
- 1. Creates the Tenant, named after `package.json` unless a name is given.
41
- 2. Writes the format-1 link and credentials (see below). A Project that is
42
- already linked is refused: use `nylo tenant use` or `nylo tenant delete`.
43
- 3. Seeds the Tenant from `.env`: `NYLORUN_SANDBOX`, and the model provider from
44
- `MODEL_PROVIDER`, `MODEL`, `MODEL_PROVIDER_API_KEY` (or a credential in
45
- `.nylorun/auth.json`) into the Tenant vault. Without them it says to set the
46
- provider in Studio or with `nylo configure`.
46
+ ## `nylo reset`
47
47
 
48
- Outside a Project it creates the Tenant and prints the three `NYLORUN_*`
49
- exports once; the Host keeps only a hash of the application key.
50
-
51
- ## `nylo tenant use <name-or-id>`
52
-
53
- Links the Project to another Tenant on the local Host. It uses the first key
54
- that the Tenant accepts:
55
-
56
- 1. The Project's `.nylorun/credentials.json`.
57
- 2. A key it kept when the Project last left that Tenant
58
- (`.nylorun/credentials.<tenantId>.json`).
59
- 3. The key of the derived principal `project`, computed from this machine's
60
- admin key. Every Tenant created in Studio registers that principal, so
61
- Studio's **Connect your code** step needs only this command.
62
-
63
- When it replaces an application key (shown only once, when the Tenant was
64
- created), it keeps that key as `.nylorun/credentials.<tenantId>.json`, so
65
- `nylo tenant use <that id>` switches back.
48
+ Clears the Tenant's sessions (the default), its sandboxes, or all its data
49
+ (`--all`), after draining work in flight. `--all` asks first; pass `--yes` when
50
+ not in a terminal. The Project link and credentials are kept.
66
51
 
67
52
  ## Project link
68
53
 
69
- A **Project** stores only:
54
+ `npx nylorun start` writes it; `nylo` only reads it. A **Project** stores only:
70
55
 
71
- - `.nylorun/link.json`: `{ format, hostUrl, hostId, tenantId }`
72
- - `.nylorun/credentials.json`: application key and principal id (0600)
56
+ - `.nylorun/link.json`: `{ format: 3, tenant, hostUrl, hostId, tenantId }`
57
+ (`tenant` is the local Tenant's name; `tenantId` is information)
58
+ - `.nylorun/credentials.json`: the key of the derived principal `project` and
59
+ its id (0600)
73
60
  - `.nylorun/.gitignore` containing `*`
74
61
 
75
- `createActionHandler` and `createClient` in `@nylorun/agents` read the link (or the three variables),
76
- so the project's `npm run dev` and `npm start` need no Nylorun tool.
62
+ A link from an older nylorun (format 0 to 2): `nylo` refuses it and says to run
63
+ `npx nylorun start`, which links the project again.
64
+
65
+ `createActionHandler` and `createClient` in `@nylorun/agents` read the link (or
66
+ the two variables), so the project's `npm run dev` and `npm start` need no
67
+ Nylorun tool.
77
68
 
78
69
  ```sh
79
70
  eval "$(npx @nylorun/cli env)"
80
- # → NYLORUN_RUNTIME_URL, NYLORUN_SERVER_KEY, NYLORUN_TENANT
71
+ # → NYLORUN_RUNTIME_URL, NYLORUN_SERVER_KEY
81
72
  ```
82
73
 
83
74
  ## Exit codes
@@ -94,8 +85,9 @@ eval "$(npx @nylorun/cli env)"
94
85
 
95
86
  | Symptom | What to do |
96
87
  | --- | --- |
97
- | No Runtime answers | `npx nylorun up`, then `npx nylorun status` |
98
- | Quarantined Tenant | `nylo tenant status` shows the reason and `repair` |
88
+ | No Runtime answers | `npx nylorun start`, then `npx nylorun status` |
89
+ | Tenant not open | `nylo status` shows the cause and its `repair` |
90
+ | Old Project link refused | `npx nylorun start` in the project |
99
91
  | `426` from the Runtime | Upgrade the CLI, or pin a matching older set |
100
92
 
101
93
  See [MIGRATION.md](../MIGRATION.md).
@@ -46,11 +46,7 @@ async function linkedClient() {
46
46
  catch (error) {
47
47
  throw new CliError(error instanceof Error ? error.message : String(error), 1);
48
48
  }
49
- return createClient({
50
- url: connection.url,
51
- key: connection.key,
52
- tenant: connection.tenant,
53
- });
49
+ return createClient({ url: connection.url, key: connection.key });
54
50
  }
55
51
  const print = (value) => console.log(JSON.stringify(value, null, 2));
56
52
  function option(args, name) {
package/dist/cli.js CHANGED
@@ -5,16 +5,17 @@ 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 { readLink as readProjectLink } from "./project/link.js";
9
- import { readCredentials as readProjectCredentials } from "./project/credentials.js";
10
- import { tenantCommand } from "./tenant/commands.js";
8
+ import { linkedConnection } from "./project/connection.js";
11
9
  import { accessCommand } from "./access/commands.js";
12
- const usage = `nylo <tenant|access|configure|env|doctor>
10
+ import { endpointsCommand, resetCommand, statusCommand, } from "./installation/commands.js";
11
+ const usage = `nylo <status|reset|endpoints|access|configure|env|doctor>
13
12
 
14
- Runtime client (the local stack's Runtime, or any Runtime by URL and key):
15
- tenant create [name] create a Tenant; in a Project, link it and seed it from .env
16
- tenant use <name-or-id> link this Project to a Tenant, e.g. one created in Studio
17
- tenant current|list [--json]|status [--json]|reset|delete
13
+ Runtime client for the linked installation and its one Tenant (the Project link that
14
+ npx nylorun start writes, or NYLORUN_RUNTIME_URL and NYLORUN_SERVER_KEY):
15
+ status [--json] the Tenant, its checks and counts
16
+ reset [--sessions|--sandboxes|--all] [--yes]
17
+ clear the Tenant's sessions, sandboxes or all its data
18
+ endpoints [--json]|ping <agent> the registered Action endpoints and their health
18
19
  access policy get|set <file>|init the access policy for subject tokens (nylo access --help)
19
20
  access keys list|create|set-origins|revoke publishable keys for web pages and apps
20
21
  access signing-keys list|rotate|revoke the Tenant's token signing keys
@@ -24,11 +25,15 @@ Runtime client (the local stack's Runtime, or any Runtime by URL and key):
24
25
  env print the linked Project's NYLORUN_* variables as exports
25
26
  doctor sandbox [--json] show which sandbox backend this Tenant's Host offers
26
27
 
27
- The local stack is managed by the nylorun package: npx nylorun up|down|status|logs|studio`;
28
- /** Local stack commands, which moved to the nylorun package. */
29
- const STACK_COMMANDS = new Set([
30
- "up", "down", "start", "stop", "status", "logs", "studio", "reset", "stack", "runtime", "restart", "run",
28
+ Local Tenants are run by the nylorun package: npx nylorun start in a project creates its
29
+ Tenant and the Project link.`;
30
+ /** Local Tenant commands, which the nylorun package runs. */
31
+ const LOCAL_COMMANDS = new Set([
32
+ "up", "down", "start", "stop", "logs", "studio", "runtime", "restart", "run",
31
33
  ]);
34
+ const TENANT_REMOVED = `nylo tenant was removed: an installation serves one Tenant.
35
+ Run "npx nylorun start" in your project to create its Tenant and the Project link.
36
+ Then use nylo status, nylo reset and nylo endpoints on the linked installation.`;
32
37
  function parseFlags(args, allowed = {}) {
33
38
  const booleans = new Set();
34
39
  const values = new Map();
@@ -64,25 +69,6 @@ function parseFlags(args, allowed = {}) {
64
69
  return { rest, booleans, values };
65
70
  }
66
71
  const usageError = (message) => new CliError(message, 2);
67
- async function resolveLinkedAuth(projectRoot) {
68
- const link = await readProjectLink(projectRoot);
69
- const credentials = await readProjectCredentials(projectRoot);
70
- if (link && credentials) {
71
- return {
72
- url: link.hostUrl,
73
- key: credentials.applicationKey,
74
- tenantId: link.tenantId,
75
- tenantName: link.tenantId,
76
- };
77
- }
78
- const url = process.env.NYLORUN_RUNTIME_URL?.trim();
79
- const key = process.env.NYLORUN_SERVER_KEY?.trim();
80
- const tenantId = process.env.NYLORUN_TENANT?.trim();
81
- if (url && key && tenantId) {
82
- return { url, key, tenantId, tenantName: tenantId };
83
- }
84
- throw new CliError(`No Project link in ${projectRoot}. Run nylo tenant create, or set NYLORUN_RUNTIME_URL, NYLORUN_SERVER_KEY and NYLORUN_TENANT.`, 1);
85
- }
86
72
  async function main() {
87
73
  const [command, ...args] = process.argv.slice(2);
88
74
  if (!command || command === "--help" || command === "-h")
@@ -90,7 +76,13 @@ async function main() {
90
76
  if (process.platform === "win32")
91
77
  throw new CliError("Nylorun does not run on native Windows. Use WSL2: install Node 24 and Docker (Docker Desktop's WSL integration) inside your WSL distribution and run nylorun there (https://learn.microsoft.com/windows/wsl/install).", 1);
92
78
  if (command === "tenant")
93
- return await tenantCommand(args);
79
+ throw usageError(TENANT_REMOVED);
80
+ if (command === "status")
81
+ return await statusCommand(args);
82
+ if (command === "reset")
83
+ return await resetCommand(args);
84
+ if (command === "endpoints")
85
+ return await endpointsCommand(args);
94
86
  if (command === "access") {
95
87
  if (args[0] === "--help" || args[0] === "-h" || args.length === 0) {
96
88
  const { accessUsage } = await import("./access/commands.js");
@@ -107,38 +99,34 @@ async function main() {
107
99
  if (command === "doctor") {
108
100
  const [topic, ...options] = args;
109
101
  if (topic !== "sandbox" || options.some((option) => option !== "--json"))
110
- throw usageError("Usage: nylo doctor sandbox [--json]. Check the local stack with npx nylorun doctor.");
102
+ throw usageError("Usage: nylo doctor sandbox [--json]. Check the local Tenant with npx nylorun doctor.");
111
103
  const { doctorSandbox } = await import("./doctor.js");
112
104
  await doctorSandbox({ json: options.includes("--json") });
113
105
  return;
114
106
  }
115
107
  if (command === "dev")
116
- throw usageError("nylorun dev was removed: run nylo tenant create once in your project, then your project's npm run dev.");
117
- if (STACK_COMMANDS.has(command))
118
- throw usageError(`The local stack moved to the nylorun package: npx nylorun ${command}`);
108
+ throw usageError('nylorun dev was removed: run "npx nylorun start" once in your project, then your project\'s npm run dev.');
109
+ if (LOCAL_COMMANDS.has(command))
110
+ throw usageError(`Local Tenants are run by the nylorun package: npx nylorun ${command}`);
119
111
  if (command === "configure") {
120
112
  const flags = parseFlags(args);
121
113
  if (flags.rest.length)
122
114
  throw usageError(usage);
123
115
  const projectRoot = findProjectRoot() ?? process.cwd();
124
- const auth = await resolveLinkedAuth(projectRoot);
116
+ const auth = await linkedConnection(projectRoot);
125
117
  const controller = new AbortController();
126
118
  const cancel = (signal) => controller.abort(new ConfigurationCancelled(signal));
127
119
  process.once("SIGINT", () => cancel("SIGINT"));
128
120
  process.once("SIGTERM", () => cancel("SIGTERM"));
129
121
  const health = await fetch(`${auth.url}/health`).catch(() => undefined);
130
122
  if (!health?.ok)
131
- throw new CliError(`No Runtime is listening at ${auth.url}. Start the local stack with "npx nylorun up".`, 6);
132
- const catalog = await fetchModelCatalog({
133
- url: auth.url,
134
- key: auth.key,
135
- tenantId: auth.tenantId,
136
- });
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({ url: auth.url, key: auth.key });
137
125
  const prompted = await configureProvider({
138
126
  signal: controller.signal,
139
127
  catalog,
140
128
  });
141
- await putHostModel(auth.url, auth.key, prompted, auth.tenantId);
129
+ await putHostModel(auth.url, auth.key, prompted);
142
130
  return;
143
131
  }
144
132
  throw usageError(usage);
package/dist/doctor.js CHANGED
@@ -11,11 +11,7 @@ function platformLine() {
11
11
  }
12
12
  async function fetchSandboxReport(options) {
13
13
  const connection = await resolveConnection(options);
14
- const client = createClient({
15
- url: connection.url,
16
- key: connection.key,
17
- tenant: connection.tenant,
18
- });
14
+ const client = createClient({ url: connection.url, key: connection.key });
19
15
  return client.transport.json("/v1/tenant/sandbox", "GET", undefined);
20
16
  }
21
17
  /** `nylo doctor sandbox`: Tenant sandbox report via the Tenant API (F2-4). */
@@ -42,7 +38,7 @@ export async function doctorSandbox(options) {
42
38
  rows.push([
43
39
  "preference",
44
40
  report.preference === "auto"
45
- ? "auto (seed Tenant sandbox.backend via nylo tenant create / .env NYLORUN_SANDBOX)"
41
+ ? "auto (npx nylorun start seeds the Tenant's sandbox.backend from .env NYLORUN_SANDBOX)"
46
42
  : report.preference,
47
43
  ]);
48
44
  if (report.config)
package/dist/home.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
- * The Host root: an explicit home, `NYLORUN_HOME`, or `~/.nylorun`. The stack
3
- * bind-mounts it into the Runtime and Studio containers, and `@nylorun/admin`
4
- * reads `host.json` and the admin key from it.
2
+ * Where `nylo` keeps its own files (the installation id): an explicit home,
3
+ * `NYLORUN_HOME`, or `~/.nylorun`, which holds the local Tenants' Host roots
4
+ * (`tenants/<name>/`). `@nylorun/admin` resolves a Tenant's Host root itself.
5
5
  */
6
6
  export declare function resolveHome(home?: string, env?: Readonly<Record<string, string | undefined>>): string;
package/dist/home.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import { homedir } from "node:os";
2
2
  import { join, resolve } from "node:path";
3
3
  /**
4
- * The Host root: an explicit home, `NYLORUN_HOME`, or `~/.nylorun`. The stack
5
- * bind-mounts it into the Runtime and Studio containers, and `@nylorun/admin`
6
- * reads `host.json` and the admin key from it.
4
+ * Where `nylo` keeps its own files (the installation id): an explicit home,
5
+ * `NYLORUN_HOME`, or `~/.nylorun`, which holds the local Tenants' Host roots
6
+ * (`tenants/<name>/`). `@nylorun/admin` resolves a Tenant's Host root itself.
7
7
  */
8
8
  export function resolveHome(home, env = process.env) {
9
9
  if (home !== undefined && home.trim() !== "")
@@ -0,0 +1,20 @@
1
+ /** `nylo status [--json]`: the Tenant, its checks and counts; the Host's cause when it is not open. */
2
+ export declare function statusCommand(args: readonly string[]): Promise<void>;
3
+ /** `nylo reset [--sessions|--sandboxes|--all] [--yes]`; `--all` asks first. */
4
+ 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;
@@ -0,0 +1,141 @@
1
+ /**
2
+ * `nylo status`, `nylo reset` and `nylo endpoints`: the linked installation's one Tenant,
3
+ * through the Tenant API with the Project's application key.
4
+ */
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
+ import { CliError } from "../errors.js";
10
+ import { linkedConnection } from "../project/connection.js";
11
+ import { findProjectRoot } from "../project/root.js";
12
+ const projectRoot = () => findProjectRoot() ?? process.cwd();
13
+ const clientFor = (connection) => createClient({ url: connection.url, key: connection.key });
14
+ /** `nylo status [--json]`: the Tenant, its checks and counts; the Host's cause when it is not open. */
15
+ export async function statusCommand(args) {
16
+ const json = args.includes("--json");
17
+ if (args.some((a) => a !== "--json"))
18
+ throw new CliError("Usage: nylo status [--json]", 2);
19
+ const root = projectRoot();
20
+ const connection = await linkedConnection(root);
21
+ let reason;
22
+ try {
23
+ const body = await clientFor(connection).transport.json("/v1/tenant", "GET");
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;
37
+ }
38
+ catch (error) {
39
+ // A Tenant that is not open does not answer: the Admin API says why.
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);
50
+ }
51
+ if (json) {
52
+ console.log(JSON.stringify({ tenant }, null, 2));
53
+ return;
54
+ }
55
+ console.log(`${tenant.name ?? "(unreadable)"} ${tenant.id ?? "(unknown)"} ${tenant.state}`);
56
+ console.log(`runtime ${connection.url}`);
57
+ if (tenant.cause) {
58
+ console.log(`reason ${tenant.cause.code}: ${tenant.cause.message}`);
59
+ console.log(`repair ${tenant.cause.repair}`);
60
+ }
61
+ }
62
+ const RESET_USAGE = "Usage: nylo reset [--sessions|--sandboxes|--all] [--yes]";
63
+ const SCOPES = { "--sessions": "sessions", "--sandboxes": "sandboxes", "--all": "all" };
64
+ /** `nylo reset [--sessions|--sandboxes|--all] [--yes]`; `--all` asks first. */
65
+ export async function resetCommand(args) {
66
+ const yes = args.includes("--yes");
67
+ const flags = args.filter((a) => a !== "--yes");
68
+ if (flags.some((f) => !(f in SCOPES)) || args.filter((a) => a === "--yes").length > 1)
69
+ throw new CliError(RESET_USAGE, 2);
70
+ if (flags.length > 1)
71
+ throw new CliError("Pass only one of --sessions, --sandboxes, --all.", 2);
72
+ const scope = flags.length ? SCOPES[flags[0]] : "sessions";
73
+ const connection = await linkedConnection(projectRoot());
74
+ const tenant = connection.link?.tenant;
75
+ const target = tenant ? `Tenant ${tenant} (${connection.url})` : `the Tenant on ${connection.url}`;
76
+ if (scope === "all" && !yes)
77
+ await confirmOrThrow(`Reset ALL data of ${target}? The Project link and credentials are kept. [y/N] `);
78
+ try {
79
+ await clientFor(connection).transport.json("/v1/tenant/reset", "POST", {
80
+ requestId: randomUUID(),
81
+ scope,
82
+ activeWork: "drain",
83
+ });
84
+ }
85
+ catch (error) {
86
+ throw new CliError(error instanceof Error ? error.message : `Tenant reset failed: ${String(error)}`, 1);
87
+ }
88
+ console.log(`Reset ${target} (${scope}).`);
89
+ }
90
+ async function confirmOrThrow(prompt) {
91
+ if (!process.stdin.isTTY || !process.stdout.isTTY) {
92
+ throw new CliError("Confirmation required; pass --yes for non-interactive use.", 2);
93
+ }
94
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
95
+ try {
96
+ const answer = (await rl.question(prompt)).trim().toLowerCase();
97
+ if (answer !== "y" && answer !== "yes") {
98
+ throw new CliError("Cancelled.", 1);
99
+ }
100
+ }
101
+ finally {
102
+ rl.close();
103
+ }
104
+ }
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
+ }
@@ -41,7 +41,6 @@ export type Selection = Readonly<{
41
41
  export declare function fetchModelCatalog(options: {
42
42
  url: string;
43
43
  key: string;
44
- tenantId: string;
45
44
  fetchImpl?: typeof fetch;
46
45
  }): Promise<ModelCatalog>;
47
46
  export declare function configureProvider(options?: {
@@ -112,11 +112,10 @@ function modelsFor(selection, credentials, catalog) {
112
112
  /** Fetch GET /v1/tenant/models when a connection is available. */
113
113
  export async function fetchModelCatalog(options) {
114
114
  const fetchImpl = options.fetchImpl ?? fetch;
115
- const { PROTOCOL_HEADER, PROTOCOL_VERSION, TENANT_HEADER } = await import("@nylorun/agents");
115
+ const { PROTOCOL_HEADER, PROTOCOL_VERSION } = await import("@nylorun/agents");
116
116
  const response = await fetchImpl(`${options.url.replace(/\/$/, "")}/v1/tenant/models`, {
117
117
  headers: {
118
118
  authorization: `Bearer ${options.key}`,
119
- [TENANT_HEADER]: options.tenantId,
120
119
  [PROTOCOL_HEADER]: String(PROTOCOL_VERSION),
121
120
  Accept: "application/json",
122
121
  },
@@ -1,4 +1,4 @@
1
- import { type PromptedModel } from "./configure.js";
1
+ import type { PromptedModel } from "./configure.js";
2
2
  /** Wire shape of GET/PUT `/v1/tenant/model` — local copy so CLI stays off `@nylorun/core`. */
3
3
  type HostModelView = {
4
4
  readonly configured: false;
@@ -13,14 +13,6 @@ type HostModelView = {
13
13
  maxTokens?: number;
14
14
  };
15
15
  };
16
- export declare function getHostModel(runtimeUrl: string, serverKey: string, tenantId?: string): Promise<HostModelView>;
17
- export declare function putHostModel(runtimeUrl: string, serverKey: string, model: PromptedModel, tenantId?: string): Promise<HostModelView>;
18
- export declare function ensureHostModel(options: {
19
- runtimeUrl: string;
20
- serverKey: string;
21
- tenantId: string;
22
- root?: string;
23
- env?: Readonly<Record<string, string>>;
24
- signal?: AbortSignal;
25
- }): Promise<void>;
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>;
26
18
  export {};