@nylorun/cli 0.3.0-beta → 0.4.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.
Files changed (44) hide show
  1. package/CHANGELOG.md +50 -1
  2. package/README.md +55 -78
  3. package/dist/{runtime/baseline.js → baseline.js} +0 -1
  4. package/dist/cli.d.ts +1 -1
  5. package/dist/cli.js +34 -115
  6. package/dist/doctor.d.ts +1 -12
  7. package/dist/doctor.js +6 -96
  8. package/dist/home.d.ts +6 -0
  9. package/dist/home.js +15 -0
  10. package/dist/model/host-model.js +1 -1
  11. package/dist/project/create-tenant.d.ts +3 -1
  12. package/dist/project/create-tenant.js +3 -2
  13. package/dist/project/credentials.js +1 -1
  14. package/dist/project/env.d.ts +3 -0
  15. package/dist/project/env.js +21 -0
  16. package/dist/project/link.js +1 -1
  17. package/dist/project/root.js +2 -1
  18. package/dist/project/seed.d.ts +6 -0
  19. package/dist/project/seed.js +9 -7
  20. package/dist/tenant/commands.js +73 -14
  21. package/package.json +6 -9
  22. package/dist/dev-entry.d.ts +0 -5
  23. package/dist/dev-entry.js +0 -7
  24. package/dist/dev.d.ts +0 -47
  25. package/dist/dev.js +0 -278
  26. package/dist/launcher.d.ts +0 -5
  27. package/dist/launcher.js +0 -7
  28. package/dist/project/attach.d.ts +0 -32
  29. package/dist/project/attach.js +0 -241
  30. package/dist/runtime/commands.d.ts +0 -16
  31. package/dist/runtime/commands.js +0 -292
  32. package/dist/runtime/ephemeral.d.ts +0 -37
  33. package/dist/runtime/ephemeral.js +0 -84
  34. package/dist/runtime/exit-codes.d.ts +0 -9
  35. package/dist/runtime/exit-codes.js +0 -43
  36. package/dist/runtime/index.d.ts +0 -8
  37. package/dist/runtime/index.js +0 -6
  38. package/dist/runtime/launcher.d.ts +0 -81
  39. package/dist/runtime/launcher.js +0 -243
  40. package/dist/runtime/progress.d.ts +0 -10
  41. package/dist/runtime/progress.js +0 -8
  42. package/dist/runtime/version.d.ts +0 -6
  43. package/dist/runtime/version.js +0 -27
  44. /package/dist/{runtime/baseline.d.ts → baseline.d.ts} +0 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,52 @@
1
1
  # @nylorun/cli
2
2
 
3
+ ## 0.4.0-beta
4
+
5
+ ### Minor Changes
6
+
7
+ - bf1c2da: **The local Runtime and Studio run as a Docker Compose stack that the CLI manages; Studio ships only as its image (breaking beta).**
8
+
9
+ - `nylorun start` writes `<Host root>/stack/compose.yaml` and `.env` (mode 0600) and starts Postgres, Restate, s2-lite, the Runtime and Studio on loopback ports, with the Runtime and Studio images this CLI pins (`nylorun.runtime`, `nylorun.studio`; `NYLORUN_RUNTIME_IMAGE` and `NYLORUN_STUDIO_IMAGE` override them). `nylorun stop` keeps the volumes; `nylorun status [--json] [--env]` reports services and health; `nylorun reset [--yes]` deletes the volumes and every Tenant.
10
+ - `nylorun dev` starts the stack if it is not running, creates the Project's Tenant on first run, opens Studio on that Tenant through a single-use login URL (`next=/tenants/<id>`), and runs the application with `NYLORUN_RUNTIME_URL=http://localhost:<port>`. `--no-open` prints the URL only; `--no-studio` skips Studio. `--local-ui` is removed (exit 2).
11
+ - `nylorun logs` and `nylorun studio` are the stack commands (`nylorun stack <command>` still works). `nylorun studio` lands on the linked Project's Tenant.
12
+ - `nylorun runtime up|down|restart|run|status|logs` and the `up`/`down` aliases are removed; they exit 2 and name `nylorun start|stop|status|logs`. `nylorun runtime status --env` is now `nylorun status --env`.
13
+ - `nylorun doctor` checks Node 24+, Docker, Compose v2 and the stack's health; `doctor runtime` is an alias of it.
14
+ - `@nylorun/studio` is private and ships only as `ghcr.io/nylorun/studio`: `startStudio`, the hosted (`local.nylorun.studio`) and local UI modes, pairing, the `nylorun-studio` bin and the UI bundle download are removed.
15
+ - `npm create @nylorun/agent` no longer adds `@nylorun/studio` or a `studio` script, checks for Docker with Compose v2 instead of a global `@nylorun/runtime`, and accepts `--no-studio` only as a deprecated no-op.
16
+
17
+ - bf1c2da: **`nylorun dev --ephemeral` runs on the Docker stack, with a Tenant-level fixture model (breaking beta).**
18
+
19
+ - `nylorun dev --ephemeral` creates a temporary Tenant through `@nylorun/admin` (no Project link written), seeds it from `.env` with the fixture model, opens Studio on it and runs the watcher; the Tenant is deleted with its active work cancelled when the watcher ends, Ctrl-C included. It needs a Runtime that advertises `tenant-fixture-model`.
20
+ - `PUT /v1/tenant/config/seed` accepts `fixtureModel: true`, stored as Tenant setting `model.fixture`: that Tenant's model calls use the Runtime's fixture model while other Tenants on the Host keep theirs. `HOST_PROTOCOL` advertises the new optional feature `tenant-fixture-model` (`OPTIONAL_HOST_FEATURES` in `@nylorun/core/compatibility`); clients do not require it.
21
+ - `startEphemeralRuntime()` keeps its signature but its Tenants live in memory instead of SQLite under the Host root; nothing survives `close()`.
22
+ - Closing a Tenant waits for running advances at most the advance grace period (30 s by default) and then abandons them; their lease lapses and the next advance takes over.
23
+ - A Worker stop, Tenant close or ended Restate attempt no longer fails or cancels the turn it interrupts: outcomes already returned are recorded, nothing is settled, and the next advance resumes the turn from its checkpoint. Only a user cancel settles `cancelled`; an advance deadline fails the turn with the deadline's message.
24
+
25
+ - ba1b239: **`nylorun` sets up the local stack; `@nylorun/cli` becomes the Runtime client `nylo` (breaking beta).**
26
+
27
+ - New unscoped package **`nylorun`**: `npx nylorun up` sets up the Docker stack on the first run and starts it after that, from any directory; `npx nylorun down` stops it (volumes are kept). `up` and `down` are aliases of `start` and `stop`. It also owns `status`, `logs`, `studio`, `reset` and `doctor`, pins the Runtime and Studio images (`package.json` `nylorun.runtime` / `nylorun.studio`), depends on `@nylorun/core` only, and never creates Tenants.
28
+ - **`@nylorun/cli`** is the Runtime client with the command **`nylo`**: `nylo tenant create [name]` (creates the Tenant; in a project, writes the Project link and seeds the model provider and sandbox from `.env`), `nylo tenant current|list|use|status|reset|delete`, `nylo configure`, `nylo env` (was `nylorun status --env`) and `nylo doctor sandbox`. It no longer provides the `nylorun` command or the stack commands.
29
+ - **Removed:** `nylorun dev` and `nylorun dev --ephemeral`. Link once with `nylo tenant create`, then run the project's own `npm run dev`. Moved commands exit 2 and name their replacement.
30
+ - **Starter:** the generated project depends on `@nylorun/agents` only (no Nylorun devDependency); `dev` is `tsx watch --env-file-if-exists=.env src/main.ts`. `npm create @nylorun/agent` installs the project and prints the next steps (`npx nylorun up`, `npx @nylorun/cli tenant create`, `npm run dev`) instead of starting development; `--no-open` is accepted and ignored.
31
+ - `connectAgents` names those steps when it finds no Runtime connection. Runtime repair hints, model errors and core's sandbox message name `nylo` and `nylorun up`.
32
+
33
+ - bf1c2da: **The microsandbox backend is removed; the Runtime runs sandbox tools on the virtual backend only.** The optional `microsandbox` dependency is gone. `sandbox.backend` and `NYLORUN_SANDBOX` accept `auto` or `virtual`, and `auto` selects `virtual`. A Tenant that stored `microsandbox` reads it as `auto`. `nylorun doctor sandbox` and the `nylorun dev` banner report only the virtual shell.
34
+ - bf1c2da: **Tenants can register a Studio principal.** `CreateTenantRequest` gains optional `studioCredentialHash` behind the new protocol feature `studio-principal`; the Runtime stores it as application principal `studio`, and idempotent create compares it too. `@nylorun/admin` exports `deriveStudioToken(adminKey, tenantId)` (HMAC-SHA256 over `nylorun/studio/v1`, NUL, Tenant id) and `createTenant` sends the hash of that key, so Studio can reach any Tenant's API with a key derived from the admin key. Clients require the new feature, so upgrade the Runtime with them.
35
+ - 1d84b3e: **Native Windows is no longer supported; Windows developers use WSL2.** Nylorun runs on macOS and Linux. On native Windows, `nylorun` and `npm create @nylorun/agent` stop with WSL2 guidance. Install Node 24 and Docker (Docker Desktop's WSL integration) inside your WSL distribution and keep projects in its Linux filesystem. The Windows-only process handling (`taskkill`, `.cmd` shims, `npm.cmd`) is removed. `nylorun doctor` reports WSL as `Linux (WSL: <distribution>)`.
36
+
37
+ ### Patch Changes
38
+
39
+ - 1d84b3e: Opening the browser no longer crashes the CLI when no opener is installed (no `xdg-open` on a minimal Linux or WSL): it reports that and leaves the printed Studio URL to open by hand. Inside WSL, the CLI opens the Windows browser with `wslview`.
40
+ - Pin agents to the tested release.
41
+ - Pin admin to the tested release.
42
+ - Updated dependencies [ba1b239]
43
+ - Updated dependencies [bf1c2da]
44
+ - Updated dependencies [bf1c2da]
45
+ - Updated dependencies
46
+ - Updated dependencies
47
+ - @nylorun/agents@0.7.0-beta
48
+ - @nylorun/admin@0.3.0-beta
49
+
3
50
  ## 0.3.0-beta
4
51
 
5
52
  ### Minor Changes
@@ -9,7 +56,9 @@
9
56
  - Dependencies: `@nylorun/agents` and `@nylorun/admin` only (no `@nylorun/runtime`, no `@nylorun/studio`).
10
57
  - `nylorun runtime …` finds `nylorun-runtime` on PATH and checks its launcher and Host protocol; a missing or incompatible Runtime exits 1 with the install command for the recommended version (`package.json` `nylorun.runtime`). Nothing is downloaded. `nylorun doctor runtime` checks the prerequisites.
11
58
  - `nylorun dev` runs the application entry under `tsx watch`; creates Tenants through `@nylorun/admin`.
12
- - **Removed:** `nylorun serve`, `nylorun studio`, `--no-studio`, in-process Project runner.
59
+ - **Removed:** `nylorun serve` and the in-process Project runner. `nylorun studio`
60
+ remains the Project-aware Studio command, and `nylorun dev --no-studio`
61
+ remains the headless development path.
13
62
  - Install as a **devDependency**; production `start` is `node dist/src/main.js`.
14
63
 
15
64
  - c49efed: **Breaking (pre-1.0 minor):** Replace a single SQLite Runtime per Project or home directory with a **Runtime Host** that serves isolated **Tenants**, selected by `Nylorun-Tenant` and negotiated with `Nylorun-Protocol` (protocol `2`, feature `runtime-tenants`). Vocabulary: Host root + Tenant + Project link.
package/README.md CHANGED
@@ -1,108 +1,85 @@
1
1
  # @nylorun/cli
2
2
 
3
- The local `nylorun` executable. Depends on `@nylorun/agents` and `@nylorun/admin`
4
- only among Nylorun packages — it runs the installed Runtime's **launcher** as a
5
- process and never imports `@nylorun/runtime`. Vocabulary:
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:
6
8
  [runtime/src/CONTEXT.md](../runtime/src/CONTEXT.md).
7
9
 
8
- Prerequisites, installed by the developer (the CLI never downloads them):
9
-
10
10
  ```sh
11
- node --version # 24 or newer
12
- npm install --global @nylorun/runtime # provides nylorun-runtime
13
- nylorun doctor runtime # checks both
11
+ npx nylorun up # the local stack (nylorun)
12
+ npx @nylorun/cli tenant create # this project's Tenant, linked in .nylorun/
14
13
  ```
15
14
 
15
+ ## Commands
16
+
16
17
  ```sh
17
- nylorun runtime up # launcher: start the Host
18
- nylorun runtime down # stop the Host; keep Tenants and host.json
19
- nylorun runtime status # Host id, address, version, Tenant list
20
- nylorun runtime status --env # export lines for the linked Project
21
- nylorun runtime logs [--follow] # Host + Tenant logs
22
- nylorun runtime restart # restart onto the installed Runtime
23
- nylorun runtime run # attached foreground Host
24
- nylorun dev [entry] # up → link/create Tenant → tsx watch entry
25
- nylorun dev --ephemeral # temporary Host root + one Tenant
26
- nylorun dev --local-ui # also start Studio with a local dashboard
27
- nylorun studio [--local-ui] # start Studio (launch URL + proxy token)
28
- nylorun configure # replace model credential on the linked Tenant
29
- nylorun tenant list|delete|status|reset
30
- nylorun doctor runtime # prerequisites: Node 24+, installed Runtime
31
- nylorun doctor sandbox # sandbox backend via Tenant API
18
+ nylo tenant create [name] # create a Tenant; in a Project, link it and seed it from .env
19
+ nylo tenant current|list [--json]|use <name-or-id>|status [--json]|reset|delete
20
+ nylo configure # set or replace the model provider on the linked Tenant
21
+ nylo env # export lines for the linked Project
22
+ nylo doctor sandbox [--json] # sandbox backend via the Tenant API
32
23
  ```
33
24
 
34
- `nylorun serve` remains removed. Production `start` is
35
- `node dist/src/main.js` with `connectAgents` in the application.
36
- `--local-ui` cannot be combined with `--no-studio`.
37
-
38
- ## The launcher
39
-
40
- `nylorun runtime …` finds `nylorun-runtime` on PATH, checks that it speaks
41
- launcher protocol 1 and a compatible Host protocol, and invokes it with
42
- `--json`. The Host runs on the same Node, from the installed
43
- `@nylorun/runtime`. When the launcher is missing or incompatible, the command
44
- exits 1 with the install command for the recommended version
45
- (`cli/package.json` `nylorun.runtime`). A project devDependency on
46
- `@nylorun/runtime` also works, because npm scripts put `node_modules/.bin` on
47
- PATH. See [building a desktop client](../docs/building-a-desktop-client.md)
48
- for the launcher contract.
49
-
50
- `dev` starts (or reuses) the Host via the launcher, creates a Tenant through
51
- `@nylorun/admin` when the Project has no link, writes format-1 link +
52
- credentials, and spawns `tsx watch <entry>` with
53
- `NYLORUN_RUNTIME_URL`, `NYLORUN_TENANT` and `NYLORUN_SERVER_KEY`. The ready
54
- banner hints `Studio: npm run studio`, or prints the Studio `launchUrl` when
55
- started with `--local-ui`. Ctrl-C stops the child; the Host stays up.
56
- `nylorun studio` resolves `@nylorun/studio`, supplies `cacheDir` from the Host
57
- root (`NYLORUN_HOME` / `~/.nylorun`, never cwd), and prints `launchUrl`.
58
-
59
- ## Host root, Tenants and Project link
60
-
61
- The **Host root** is `NYLORUN_HOME` or `~/.nylorun` (resolved absolute once).
62
- It holds `host.json`, admin credentials and every Tenant; the Runtime itself
63
- is installed by npm. Isolation is per **Tenant**, not per Project directory.
25
+ Local stack commands (`up`, `down`, `start`, `stop`, `status`, `logs`,
26
+ `studio`, `reset`) exit 2 naming `npx nylorun <command>`. `nylorun dev` was
27
+ removed: link once with `nylo tenant create`, then run the project's own
28
+ `npm run dev` (`tsx watch src/main.ts`).
29
+
30
+ ## `nylo tenant create`
31
+
32
+ The Admin API connection resolves from `NYLORUN_ADMIN_URL` and
33
+ `NYLORUN_ADMIN_KEY`, else from the local Host root (`NYLORUN_HOME` or
34
+ `~/.nylorun`: `host.json` and the admin key that `nylorun up` wrote). With no
35
+ Runtime answering, it exits 6 and names `npx nylorun up`.
36
+
37
+ Inside a Project (the nearest `.nylorun/` or `package.json`):
38
+
39
+ 1. Creates the Tenant, named after `package.json` unless a name is given.
40
+ 2. Writes the format-1 link and credentials (see below). A Project that is
41
+ already linked is refused: use `nylo tenant use` or `nylo tenant delete`.
42
+ 3. Seeds the Tenant from `.env`: `NYLORUN_SANDBOX`, and the model provider from
43
+ `MODEL_PROVIDER`, `MODEL`, `MODEL_PROVIDER_API_KEY` (or a credential in
44
+ `.nylorun/auth.json`) into the Tenant vault. Without them it says to set the
45
+ provider in Studio or with `nylo configure`.
46
+
47
+ Outside a Project it creates the Tenant and prints the three `NYLORUN_*`
48
+ exports once; the Host keeps only a hash of the application key.
49
+
50
+ ## Project link
64
51
 
65
52
  A **Project** stores only:
66
53
 
67
- - `.nylorun/link.json` — `{ format, hostUrl, hostId, tenantId }`
68
- - `.nylorun/credentials.json` — application key and principal id (0600); no
54
+ - `.nylorun/link.json`: `{ format, hostUrl, hostId, tenantId }`
55
+ - `.nylorun/credentials.json`: application key and principal id (0600), no
69
56
  executor tokens
70
57
  - `.nylorun/.gitignore` containing `*`
71
58
 
59
+ `connectAgents` in `@nylorun/agents` reads the link (or the three variables),
60
+ so the project's `npm run dev` and `npm start` need no Nylorun tool.
61
+
72
62
  ```sh
73
- eval "$(npx nylorun runtime status --env)"
63
+ eval "$(npx @nylorun/cli env)"
74
64
  # → NYLORUN_RUNTIME_URL, NYLORUN_SERVER_KEY, NYLORUN_TENANT
75
65
  ```
76
66
 
77
- Port defaults to `8787` on loopback. On first Host setup, if that port is
78
- taken, the launcher picks a free loopback port and persists it. Explicit
79
- `--port` is strict.
80
-
81
67
  ## Exit codes
82
68
 
83
69
  | Code | Meaning |
84
70
  | --- | --- |
85
- | 0 | Success, including `down` when nothing was running |
86
- | 1 | Generic failure / launcher operation failed |
87
- | 2 | Usage error |
88
- | 3 | `runtime status` or `logs`: not running |
89
- | 4 | Port held by another process |
90
- | 5 | Protocol / feature incompatible with this CLI |
91
- | 7 | The Host did not become ready |
71
+ | 0 | Success |
72
+ | 1 | Generic failure |
73
+ | 2 | Usage error, or a moved or removed command |
74
+ | 6 | No Runtime at the linked or local URL |
92
75
  | 130 / 143 | SIGINT / SIGTERM |
93
76
 
94
- Install the CLI as a **devDependency**. Generated applications keep
95
- `@nylorun/agents` alone in production dependencies.
96
-
97
77
  ## Troubleshooting
98
78
 
99
79
  | Symptom | What to do |
100
80
  | --- | --- |
101
- | Quarantined Tenant | `nylorun tenant status` shows reason and `repair` |
102
- | `426` / exit 5 | Upgrade CLI / Runtime pin, or pin a matching older set |
103
- | Port conflict | Stop the other process or `nylorun runtime up --port <n>` |
104
- | Logs | `nylorun runtime logs --follow` |
105
- | Runtime not installed | `npm install --global @nylorun/runtime`; `nylorun doctor runtime` checks |
106
-
107
- See [package architecture](../docs/design/package-architecture.md) and
108
- [MIGRATION.md](../MIGRATION.md#runtime-clients-and-admin-api-breaking-beta).
81
+ | No Runtime answers | `npx nylorun up`, then `npx nylorun status` |
82
+ | Quarantined Tenant | `nylo tenant status` shows the reason and `repair` |
83
+ | `426` from the Runtime | Upgrade the CLI, or pin a matching older set |
84
+
85
+ See [MIGRATION.md](../MIGRATION.md).
@@ -1,5 +1,4 @@
1
1
  /**
2
- * // CLIENTS-CCR: owned by WS-F1 (moves from cli/src/host/baseline.ts).
3
2
  * Snapshot of the process environment at CLI module load.
4
3
  */
5
4
  const snapshot = Object.freeze({
package/dist/cli.d.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- import "./runtime/baseline.js";
2
+ import "./baseline.js";
package/dist/cli.js CHANGED
@@ -1,28 +1,27 @@
1
1
  #!/usr/bin/env node
2
- import "./runtime/baseline.js";
3
- import { createRequire } from "node:module";
4
- import { join } from "node:path";
2
+ import "./baseline.js";
5
3
  import { ConfigurationCancelled, configureProvider, fetchModelCatalog, } from "./model/configure.js";
6
4
  import { putHostModel } from "./model/host-model.js";
7
- import { develop, developmentPreflight, startStudio } from "./dev.js";
8
5
  import { CliError } from "./errors.js";
9
- import { runtimeCommand, runtimeUsage } from "./runtime/commands.js";
10
- import { findProjectRoot, requireProjectRoot } from "./project/root.js";
11
- import { printLinkedEnvExports } from "./project/attach.js";
6
+ import { findProjectRoot } from "./project/root.js";
7
+ import { printLinkedEnvExports } from "./project/env.js";
12
8
  import { readLink as readProjectLink } from "./project/link.js";
13
9
  import { readCredentials as readProjectCredentials } from "./project/credentials.js";
14
10
  import { tenantCommand } from "./tenant/commands.js";
15
- import { resolveHome } from "./runtime/launcher.js";
16
- const usage = `nylorun <runtime|up|down|logs|dev|studio|configure|doctor|tenant>
11
+ const usage = `nylo <tenant|configure|env|doctor>
17
12
 
18
- ${runtimeUsage}
13
+ Runtime client (the local stack's Runtime, or any Runtime by URL and key):
14
+ tenant create [name] create a Tenant; in a Project, link it and seed it from .env
15
+ tenant current|list [--json]|use <name-or-id>|status [--json]|reset|delete
16
+ configure set the linked Tenant's model provider
17
+ env print the linked Project's NYLORUN_* variables as exports
18
+ doctor sandbox [--json] show which sandbox backend this Tenant's Host offers
19
19
 
20
- dev [entry] [--ephemeral] [--local-ui] [--no-studio] [--no-open]
21
- studio [--local-ui] [--port <n>] [--no-open]
22
- configure
23
- doctor runtime [--json] check the prerequisites: Node 24+ and an installed Runtime
24
- doctor sandbox [--json] show which sandbox backend this Tenant's Host offers
25
- tenant current|list [--json]|use <name-or-id>|status [--json]|reset|delete`;
20
+ The local stack is managed by the nylorun package: npx nylorun up|down|status|logs|studio`;
21
+ /** Local stack commands, which moved to the nylorun package. */
22
+ const STACK_COMMANDS = new Set([
23
+ "up", "down", "start", "stop", "status", "logs", "studio", "reset", "stack", "runtime", "restart", "run",
24
+ ]);
26
25
  function parseFlags(args, allowed = {}) {
27
26
  const booleans = new Set();
28
27
  const values = new Map();
@@ -58,14 +57,6 @@ function parseFlags(args, allowed = {}) {
58
57
  return { rest, booleans, values };
59
58
  }
60
59
  const usageError = (message) => new CliError(message, 2);
61
- function parsePort(value) {
62
- if (value === undefined || !/^\d+$/u.test(value))
63
- throw usageError(`Invalid --port: ${value ?? "(missing)"}`);
64
- const port = Number(value);
65
- if (!Number.isInteger(port) || port < 1 || port > 65535)
66
- throw usageError(`Invalid --port: ${value}`);
67
- return port;
68
- }
69
60
  async function resolveLinkedAuth(projectRoot) {
70
61
  const link = await readProjectLink(projectRoot);
71
62
  const credentials = await readProjectCredentials(projectRoot);
@@ -83,106 +74,34 @@ async function resolveLinkedAuth(projectRoot) {
83
74
  if (url && key && tenantId) {
84
75
  return { url, key, tenantId, tenantName: tenantId };
85
76
  }
86
- throw new CliError(`No Project link in ${projectRoot}. Run nylorun dev, or set NYLORUN_RUNTIME_URL, NYLORUN_SERVER_KEY and NYLORUN_TENANT.`, 1);
77
+ throw new CliError(`No Project link in ${projectRoot}. Run nylo tenant create, or set NYLORUN_RUNTIME_URL, NYLORUN_SERVER_KEY and NYLORUN_TENANT.`, 1);
87
78
  }
88
79
  async function main() {
89
- const [rawCommand, ...rawArgs] = process.argv.slice(2);
90
- if (!rawCommand || rawCommand === "--help" || rawCommand === "-h")
80
+ const [command, ...args] = process.argv.slice(2);
81
+ if (!command || command === "--help" || command === "-h")
91
82
  return void console.log(usage);
92
- const aliases = {
93
- up: "up",
94
- down: "down",
95
- logs: "logs",
96
- };
97
- const command = rawCommand in aliases ? "runtime" : rawCommand;
98
- const args = rawCommand in aliases ? [aliases[rawCommand], ...rawArgs] : rawArgs;
83
+ if (process.platform === "win32")
84
+ 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);
99
85
  if (command === "tenant")
100
86
  return await tenantCommand(args);
101
- if (command === "runtime") {
102
- // F2-7: envHook prints the linked Project's three variables.
103
- return await runtimeCommand(args, {
104
- envHook: async () => {
105
- const root = findProjectRoot() ?? process.cwd();
106
- await printLinkedEnvExports(root);
107
- },
108
- });
87
+ if (command === "env") {
88
+ if (args.length)
89
+ throw usageError("Usage: nylo env");
90
+ await printLinkedEnvExports(findProjectRoot() ?? process.cwd());
91
+ return;
109
92
  }
110
93
  if (command === "doctor") {
111
94
  const [topic, ...options] = args;
112
- if ((topic !== "sandbox" && topic !== "runtime") ||
113
- options.some((option) => option !== "--json"))
114
- throw usageError("Usage: nylorun doctor runtime|sandbox [--json]");
115
- const { doctorRuntime, doctorSandbox } = await import("./doctor.js");
116
- const json = options.includes("--json");
117
- if (topic === "runtime")
118
- await doctorRuntime({ json });
119
- else
120
- await doctorSandbox({ json });
121
- return;
122
- }
123
- if (command === "dev") {
124
- const flags = parseFlags(args, {
125
- booleans: ["--ephemeral", "--local-ui", "--no-studio", "--no-open"],
126
- });
127
- if (flags.rest.length > 1)
128
- throw usageError(usage);
129
- if (flags.booleans.has("--local-ui") && flags.booleans.has("--no-studio"))
130
- throw usageError("--local-ui cannot be combined with --no-studio.");
131
- requireProjectRoot();
132
- developmentPreflight([
133
- ...flags.rest,
134
- ...[...flags.booleans],
135
- ]);
136
- process.exitCode = await develop({
137
- ...(flags.rest[0] ? { entry: flags.rest[0] } : {}),
138
- flags: [...flags.booleans],
139
- });
140
- return;
141
- }
142
- if (command === "serve") {
143
- throw usageError("nylorun serve was removed. Use nylorun dev [entry] in development, or node dist/src/main.js with NYLORUN_RUNTIME_URL, NYLORUN_TENANT and NYLORUN_SERVER_KEY.");
144
- }
145
- if (command === "studio") {
146
- const flags = parseFlags(args, {
147
- booleans: ["--local-ui", "--no-open"],
148
- values: ["--port"],
149
- });
150
- if (flags.rest.length)
151
- throw usageError(usage);
152
- const projectRoot = findProjectRoot() ?? process.cwd();
153
- // Surface missing Studio early with the same Install message as preflight.
154
- try {
155
- createRequire(join(projectRoot, "package.json")).resolve("@nylorun/studio");
156
- }
157
- catch {
158
- throw new Error("Install @nylorun/studio to use the Studio dashboard.");
159
- }
160
- const auth = await resolveLinkedAuth(projectRoot);
161
- const localUi = flags.booleans.has("--local-ui");
162
- // I2: startStudio default is hosted; `--local-ui` forces local + cacheDir.
163
- const dashboard = await startStudio({
164
- runtimeUrl: auth.url,
165
- serverKey: auth.key,
166
- tenant: { id: auth.tenantId, name: auth.tenantName },
167
- open: !flags.booleans.has("--no-open"),
168
- localUi,
169
- cacheDir: resolveHome(),
170
- projectRoot,
171
- ...(flags.values.has("--port")
172
- ? { port: parsePort(flags.values.get("--port")) }
173
- : {}),
174
- });
175
- console.log(`Studio ${dashboard.launchUrl}`);
176
- if (!localUi && dashboard.launchUrl.startsWith("https://local.nylorun.studio")) {
177
- console.log(`Safari or offline: nylorun studio --local-ui`);
178
- }
179
- await new Promise((resolve, reject) => {
180
- const close = () => void dashboard.close().then(resolve, reject);
181
- process.once("SIGINT", close);
182
- process.once("SIGTERM", close);
183
- });
95
+ if (topic !== "sandbox" || options.some((option) => option !== "--json"))
96
+ throw usageError("Usage: nylo doctor sandbox [--json]. Check the local stack with npx nylorun doctor.");
97
+ const { doctorSandbox } = await import("./doctor.js");
98
+ await doctorSandbox({ json: options.includes("--json") });
184
99
  return;
185
100
  }
101
+ if (command === "dev")
102
+ throw usageError("nylorun dev was removed: run nylo tenant create once in your project, then your project's npm run dev.");
103
+ if (STACK_COMMANDS.has(command))
104
+ throw usageError(`The local stack moved to the nylorun package: npx nylorun ${command}`);
186
105
  if (command === "configure") {
187
106
  const flags = parseFlags(args);
188
107
  if (flags.rest.length)
@@ -195,7 +114,7 @@ async function main() {
195
114
  process.once("SIGTERM", () => cancel("SIGTERM"));
196
115
  const health = await fetch(`${auth.url}/health`).catch(() => undefined);
197
116
  if (!health?.ok)
198
- throw new CliError(`No Runtime Host is listening at ${auth.url}. Start one with "nylorun runtime up".`, 6);
117
+ throw new CliError(`No Runtime is listening at ${auth.url}. Start the local stack with "npx nylorun up".`, 6);
199
118
  const catalog = await fetchModelCatalog({
200
119
  url: auth.url,
201
120
  key: auth.key,
package/dist/doctor.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- import { type AgentManifest } from "@nylorun/agents";
2
1
  export type SandboxReport = {
3
2
  preference: string;
4
3
  backend: string | null;
@@ -13,17 +12,7 @@ export type SandboxReport = {
13
12
  }[];
14
13
  defaultImage?: string;
15
14
  };
16
- /**
17
- * `nylorun doctor runtime`: check the two prerequisites (Node 24+ and an
18
- * installed `@nylorun/runtime`) and print the fix for each one that fails.
19
- * Exits 1 when a prerequisite is missing; installs nothing.
20
- */
21
- export declare function doctorRuntime(options: {
22
- json: boolean;
23
- }): Promise<void>;
24
- /** `nylorun doctor sandbox`: Tenant sandbox report via the Tenant API (F2-4). */
15
+ /** `nylo doctor sandbox`: Tenant sandbox report via the Tenant API (F2-4). */
25
16
  export declare function doctorSandbox(options: {
26
17
  json: boolean;
27
18
  }): Promise<void>;
28
- /** One line for the dev banner, or undefined when no connected agent declares a sandbox. */
29
- export declare function sandboxBanner(runtimeUrl: string, serverKey: string, manifests: readonly AgentManifest[], tenantId: string): Promise<string | undefined>;
package/dist/doctor.js CHANGED
@@ -1,18 +1,11 @@
1
1
  import { release } from "node:os";
2
- import { PROTOCOL_HEADER, PROTOCOL_VERSION, TENANT_HEADER, createClient, resolveConnection, } from "@nylorun/agents";
2
+ import { createClient, resolveConnection } from "@nylorun/agents";
3
3
  import { CliError } from "./errors.js";
4
- import { launcher, resolveHome, runtimeInstallCommand } from "./runtime/launcher.js";
5
- /** Oldest Node the Runtime runs on (it needs node:sqlite). */
6
- const MIN_NODE_MAJOR = 24;
7
- const LABEL = {
8
- microsandbox: "microsandbox VM",
9
- virtual: "virtual shell",
10
- };
11
4
  function platformLine() {
12
5
  const os = process.platform === "darwin"
13
6
  ? "macOS"
14
- : process.platform === "win32"
15
- ? "Windows"
7
+ : process.env.WSL_DISTRO_NAME
8
+ ? `Linux (WSL: ${process.env.WSL_DISTRO_NAME})`
16
9
  : process.platform;
17
10
  return `${os} (kernel ${release()}) · ${process.arch}`;
18
11
  }
@@ -25,54 +18,7 @@ async function fetchSandboxReport(options) {
25
18
  });
26
19
  return client.transport.json("/v1/tenant/sandbox", "GET", undefined);
27
20
  }
28
- /**
29
- * `nylorun doctor runtime`: check the two prerequisites (Node 24+ and an
30
- * installed `@nylorun/runtime`) and print the fix for each one that fails.
31
- * Exits 1 when a prerequisite is missing; installs nothing.
32
- */
33
- export async function doctorRuntime(options) {
34
- const nodeOk = Number(process.versions.node.split(".")[0]) >= MIN_NODE_MAJOR;
35
- let runtime;
36
- try {
37
- const handle = await launcher(resolveHome());
38
- runtime = { ok: true, ...handle.runtime };
39
- }
40
- catch (error) {
41
- runtime = {
42
- ok: false,
43
- problem: error instanceof Error ? error.message : String(error),
44
- };
45
- }
46
- if (options.json) {
47
- console.log(JSON.stringify({
48
- node: { version: process.versions.node, ok: nodeOk },
49
- runtime,
50
- install: runtimeInstallCommand(),
51
- }, null, 2));
52
- }
53
- else {
54
- const rows = [
55
- [
56
- "node",
57
- nodeOk
58
- ? `✓ ${process.versions.node}`
59
- : `✗ ${process.versions.node}: install Node ${MIN_NODE_MAJOR} or newer`,
60
- ],
61
- [
62
- "runtime",
63
- runtime.ok
64
- ? `✓ ${runtime.version} · ${runtime.bin}`
65
- : `✗ ${runtime.problem.split("\n")[0]}\n ${runtimeInstallCommand()}`,
66
- ],
67
- ];
68
- const width = Math.max(...rows.map(([key]) => key.length)) + 2;
69
- for (const [key, value] of rows)
70
- console.log(` ${key.padEnd(width)}${value}`);
71
- }
72
- if (!nodeOk || !runtime.ok)
73
- process.exitCode = 1;
74
- }
75
- /** `nylorun doctor sandbox`: Tenant sandbox report via the Tenant API (F2-4). */
21
+ /** `nylo doctor sandbox`: Tenant sandbox report via the Tenant API (F2-4). */
76
22
  export async function doctorSandbox(options) {
77
23
  let report;
78
24
  try {
@@ -96,7 +42,7 @@ export async function doctorSandbox(options) {
96
42
  rows.push([
97
43
  "preference",
98
44
  report.preference === "auto"
99
- ? "auto (seed Tenant sandbox.backend via nylorun dev / .env NYLORUN_SANDBOX)"
45
+ ? "auto (seed Tenant sandbox.backend via nylo tenant create / .env NYLORUN_SANDBOX)"
100
46
  : report.preference,
101
47
  ]);
102
48
  rows.push([
@@ -109,41 +55,5 @@ export async function doctorSandbox(options) {
109
55
  for (const [key, value] of rows)
110
56
  console.log(` ${key.padEnd(width)}${value}`);
111
57
  if (report.backend === "virtual")
112
- console.log("\n The virtual shell emulates bash in the Runtime process; it is not a VM boundary.\n" +
113
- " For hardware isolation use macOS on Apple Silicon or Linux with KVM.");
114
- }
115
- /** One line for the dev banner, or undefined when no connected agent declares a sandbox. */
116
- export async function sandboxBanner(runtimeUrl, serverKey, manifests, tenantId) {
117
- const capability = manifests
118
- .flatMap((manifest) => manifest.capabilities)
119
- .find((item) => item.sandbox);
120
- if (!capability)
121
- return undefined;
122
- let report;
123
- try {
124
- const response = await fetch(`${runtimeUrl}/v1/tenant/sandbox`, {
125
- headers: {
126
- authorization: `Bearer ${serverKey}`,
127
- [TENANT_HEADER]: tenantId,
128
- [PROTOCOL_HEADER]: String(PROTOCOL_VERSION),
129
- },
130
- signal: AbortSignal.timeout(10_000),
131
- });
132
- if (response.ok)
133
- report = (await response.json());
134
- }
135
- catch {
136
- /* ignore */
137
- }
138
- if (!report)
139
- return undefined;
140
- const doctor = "run `npx nylorun doctor sandbox` for options";
141
- if (!report.backend)
142
- return `sandbox: unavailable (${report.reason}) · ${doctor}`;
143
- const image = capability.sandbox?.image ?? report.defaultImage;
144
- const network = capability.sandbox?.network?.preset ?? "dev";
145
- const fellBack = report.preference === "auto" && report.backend !== report.probes[0]?.name;
146
- return fellBack
147
- ? `sandbox: ${LABEL[report.backend] ?? report.backend} (${report.reason}) · ${doctor}`
148
- : `sandbox: ${LABEL[report.backend] ?? report.backend}${report.backend === "microsandbox" && image ? ` · image ${image}` : ""} · network: ${network}`;
58
+ console.log("\n The virtual shell emulates bash in the Runtime process; it is not a VM boundary.");
149
59
  }
package/dist/home.d.ts ADDED
@@ -0,0 +1,6 @@
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.
5
+ */
6
+ export declare function resolveHome(home?: string, env?: Readonly<Record<string, string | undefined>>): string;
package/dist/home.js ADDED
@@ -0,0 +1,15 @@
1
+ import { homedir } from "node:os";
2
+ import { join, resolve } from "node:path";
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.
7
+ */
8
+ export function resolveHome(home, env = process.env) {
9
+ if (home !== undefined && home.trim() !== "")
10
+ return resolve(home);
11
+ const fromEnv = env.NYLORUN_HOME?.trim();
12
+ if (fromEnv)
13
+ return resolve(fromEnv);
14
+ return resolve(join(homedir(), ".nylorun"));
15
+ }
@@ -69,7 +69,7 @@ export async function ensureHostModel(options) {
69
69
  await putHostModel(options.runtimeUrl, options.serverKey, prompted, options.tenantId);
70
70
  return;
71
71
  }
72
- throw new Error("Model provider is not configured. Run nylorun dev in a terminal to set it up, or open Studio.");
72
+ throw new Error("Model provider is not configured. Run nylo configure in a terminal to set it up, or open Studio.");
73
73
  }
74
74
  function seedFromEnv(env, root) {
75
75
  const provider = env.MODEL_PROVIDER?.trim();