@nylorun/cli 0.2.1-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.
- package/CHANGELOG.md +83 -0
- package/README.md +66 -42
- package/dist/baseline.d.ts +2 -0
- package/dist/baseline.js +10 -0
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +73 -242
- package/dist/doctor.d.ts +15 -4
- package/dist/doctor.js +44 -46
- package/dist/environment.d.ts +4 -1
- package/dist/environment.js +12 -3
- package/dist/home.d.ts +6 -0
- package/dist/home.js +15 -0
- package/dist/model/configure.d.ts +30 -0
- package/dist/model/configure.js +117 -11
- package/dist/model/host-model.d.ts +5 -3
- package/dist/model/host-model.js +37 -16
- package/dist/project/create-tenant.d.ts +28 -0
- package/dist/project/create-tenant.js +66 -0
- package/dist/project/credentials.d.ts +18 -0
- package/dist/project/credentials.js +64 -0
- package/dist/project/env.d.ts +3 -0
- package/dist/project/env.js +21 -0
- package/dist/project/link.d.ts +20 -0
- package/dist/project/link.js +77 -0
- package/dist/project/root.d.ts +9 -0
- package/dist/project/root.js +52 -0
- package/dist/project/seed.d.ts +25 -0
- package/dist/project/seed.js +96 -0
- package/dist/tenant/commands.d.ts +4 -0
- package/dist/tenant/commands.js +321 -0
- package/package.json +6 -6
- package/dist/dev-entry.d.ts +0 -1
- package/dist/dev-entry.js +0 -6
- package/dist/dev.d.ts +0 -6
- package/dist/dev.js +0 -65
- package/dist/launcher.d.ts +0 -5
- package/dist/launcher.js +0 -4
- package/dist/project-runner.d.ts +0 -20
- package/dist/project-runner.js +0 -141
- package/dist/runtime-host.d.ts +0 -39
- package/dist/runtime-host.js +0 -355
- package/dist/scope.d.ts +0 -65
- package/dist/scope.js +0 -191
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,88 @@
|
|
|
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
|
+
|
|
50
|
+
## 0.3.0-beta
|
|
51
|
+
|
|
52
|
+
### Minor Changes
|
|
53
|
+
|
|
54
|
+
- c49efed: **Breaking (pre-1.0 minor):** CLI reaches the local Runtime only through the installed Runtime's launcher.
|
|
55
|
+
|
|
56
|
+
- Dependencies: `@nylorun/agents` and `@nylorun/admin` only (no `@nylorun/runtime`, no `@nylorun/studio`).
|
|
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.
|
|
58
|
+
- `nylorun dev` runs the application entry under `tsx watch`; creates Tenants through `@nylorun/admin`.
|
|
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.
|
|
62
|
+
- Install as a **devDependency**; production `start` is `node dist/src/main.js`.
|
|
63
|
+
|
|
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.
|
|
65
|
+
|
|
66
|
+
- **core:** `PROTOCOL_VERSION = 2`, `HOST_PROTOCOL`, `TENANT_HEADER`, `PROTOCOL_HEADER`, `newTenantId` / `isTenantId`, `checkCompatibility`; health schema gains `hostId` + `protocol` (`service: "nylorun-runtime"`); Tenant/admin wire schemas; Tenant model routes under `/v1/tenant/*`.
|
|
67
|
+
- **runtime:** Host process + Tenant module; Tenant model routes under `/v1/tenant/*`; `startEphemeralRuntime` for tests/embeds; executors via `PUT /v1/executors`; sandbox prefix `nylorun-<tenant-id>-`.
|
|
68
|
+
- **agents:** `createClient({ url, key, tenant })`; Transport sends Tenant + protocol headers; `/health` compatibility cache; `IncompatibleRuntimeError` with upgrade remedies.
|
|
69
|
+
- **cli:** Host root lifecycle (`runtime up|down|status|logs|restart|run`); Project link (`.nylorun/link.json` + `credentials.json`); `tenant` commands; `runtime status --env` exports `NYLORUN_RUNTIME_URL`, `NYLORUN_SERVER_KEY`, `NYLORUN_TENANT`; removed Project/home SQLite selectors.
|
|
70
|
+
- **studio:** `startStudio({ …, tenant: { id, name } })`; proxy forwards Tenant + protocol headers; UI shows Tenant name/short id.
|
|
71
|
+
|
|
72
|
+
### Patch Changes
|
|
73
|
+
|
|
74
|
+
- Pin agents to the tested release.
|
|
75
|
+
- Pin admin to the tested release.
|
|
76
|
+
- Pin runtime to the tested release.
|
|
77
|
+
- Updated dependencies [c49efed]
|
|
78
|
+
- Updated dependencies [c49efed]
|
|
79
|
+
- Updated dependencies [c49efed]
|
|
80
|
+
- Updated dependencies [fd9fd87]
|
|
81
|
+
- Updated dependencies
|
|
82
|
+
- Updated dependencies
|
|
83
|
+
- @nylorun/agents@0.6.0-beta
|
|
84
|
+
- @nylorun/admin@0.2.0-beta
|
|
85
|
+
|
|
3
86
|
## 0.2.1-beta
|
|
4
87
|
|
|
5
88
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -1,61 +1,85 @@
|
|
|
1
1
|
# @nylorun/cli
|
|
2
2
|
|
|
3
|
-
The
|
|
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:
|
|
8
|
+
[runtime/src/CONTEXT.md](../runtime/src/CONTEXT.md).
|
|
4
9
|
|
|
5
10
|
```sh
|
|
6
|
-
nylorun up
|
|
7
|
-
nylorun
|
|
8
|
-
nylorun dev --no-studio
|
|
9
|
-
nylorun serve [entry] # run the compiled build, default dist/agents/index.js
|
|
10
|
-
nylorun configure
|
|
11
|
-
nylorun studio
|
|
12
|
-
nylorun runtime status
|
|
13
|
-
nylorun down # stop the Runtime, keeping SQLite and credentials
|
|
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
|
|
|
16
|
-
##
|
|
15
|
+
## Commands
|
|
17
16
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
17
|
+
```sh
|
|
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
|
|
23
|
+
```
|
|
24
|
+
|
|
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`.
|
|
25
46
|
|
|
26
|
-
|
|
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.
|
|
27
49
|
|
|
28
|
-
|
|
29
|
-
live in `.nylorun/` beside the nearest `package.json`, created on first use and
|
|
30
|
-
added to an existing `.gitignore`. `--global` (and running outside a project)
|
|
31
|
-
uses `~/.nylorun` instead, relocatable with `NYLORUN_HOME`. Both default to
|
|
32
|
-
`127.0.0.1:8787`; `--port` beats `NYLORUN_PORT`, then `PORT`, then the port
|
|
33
|
-
recorded for a running Runtime. `--db` or `NYLORUN_SQLITE_PATH` moves the
|
|
34
|
-
database. `nylorun runtime status --output json` prints the resolved scope for
|
|
35
|
-
scripts, and `nylorun logs [-f]` tails the Runtime's own output.
|
|
50
|
+
## Project link
|
|
36
51
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
52
|
+
A **Project** stores only:
|
|
53
|
+
|
|
54
|
+
- `.nylorun/link.json`: `{ format, hostUrl, hostId, tenantId }`
|
|
55
|
+
- `.nylorun/credentials.json`: application key and principal id (0600), no
|
|
56
|
+
executor tokens
|
|
57
|
+
- `.nylorun/.gitignore` containing `*`
|
|
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
|
+
|
|
62
|
+
```sh
|
|
63
|
+
eval "$(npx @nylorun/cli env)"
|
|
64
|
+
# → NYLORUN_RUNTIME_URL, NYLORUN_SERVER_KEY, NYLORUN_TENANT
|
|
65
|
+
```
|
|
40
66
|
|
|
41
67
|
## Exit codes
|
|
42
68
|
|
|
43
69
|
| Code | Meaning |
|
|
44
70
|
| --- | --- |
|
|
45
|
-
| 0 | Success
|
|
71
|
+
| 0 | Success |
|
|
46
72
|
| 1 | Generic failure |
|
|
47
|
-
| 2 | Usage error |
|
|
48
|
-
|
|
|
49
|
-
| 4 | Port held by another process or another scope |
|
|
50
|
-
| 5 | The running Runtime does not match this CLI |
|
|
51
|
-
| 6 | `--no-autostart` and nothing is listening |
|
|
52
|
-
| 7 | The Runtime did not become healthy |
|
|
73
|
+
| 2 | Usage error, or a moved or removed command |
|
|
74
|
+
| 6 | No Runtime at the linked or local URL |
|
|
53
75
|
| 130 / 143 | SIGINT / SIGTERM |
|
|
54
76
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
77
|
+
## Troubleshooting
|
|
78
|
+
|
|
79
|
+
| Symptom | What to do |
|
|
80
|
+
| --- | --- |
|
|
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 |
|
|
58
84
|
|
|
59
|
-
|
|
60
|
-
interactive prompts and process supervision belong here. Neither runtime nor
|
|
61
|
-
harness depends on this package. See [package architecture](../docs/design/package-architecture.md).
|
|
85
|
+
See [MIGRATION.md](../MIGRATION.md).
|
package/dist/baseline.js
ADDED
package/dist/cli.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
2
|
+
import "./baseline.js";
|
package/dist/cli.js
CHANGED
|
@@ -1,46 +1,42 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import { createRequire } from "node:module";
|
|
5
|
-
import { ConfigurationCancelled, configureProvider, } from "./model/configure.js";
|
|
2
|
+
import "./baseline.js";
|
|
3
|
+
import { ConfigurationCancelled, configureProvider, fetchModelCatalog, } from "./model/configure.js";
|
|
6
4
|
import { putHostModel } from "./model/host-model.js";
|
|
7
|
-
import { develop, developmentPreflight } from "./dev.js";
|
|
8
5
|
import { CliError } from "./errors.js";
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
|
|
6
|
+
import { findProjectRoot } from "./project/root.js";
|
|
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";
|
|
11
|
+
const usage = `nylo <tenant|configure|env|doctor>
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
logs alias for "runtime logs"
|
|
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
|
|
21
19
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Flags are parsed before the scope is resolved so --port can win over a PORT in .env, which
|
|
29
|
-
* is only loaded once the project root is known.
|
|
30
|
-
*/
|
|
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
|
+
]);
|
|
31
25
|
function parseFlags(args, allowed = {}) {
|
|
32
26
|
const booleans = new Set();
|
|
33
27
|
const values = new Map();
|
|
34
28
|
const rest = [];
|
|
35
|
-
const
|
|
36
|
-
const
|
|
37
|
-
const valueNames = new Set(["--port", "--db", ...(allowed.values ?? [])]);
|
|
29
|
+
const booleanNames = new Set(allowed.booleans ?? []);
|
|
30
|
+
const valueNames = new Set(allowed.values ?? []);
|
|
38
31
|
for (let index = 0; index < args.length; index += 1) {
|
|
39
32
|
const arg = args[index];
|
|
40
33
|
if (!arg.startsWith("-")) {
|
|
41
34
|
rest.push(arg);
|
|
42
35
|
continue;
|
|
43
36
|
}
|
|
37
|
+
if (arg === "--global" || arg === "--db") {
|
|
38
|
+
throw usageError(`${arg} was removed. Use the Runtime Host root (NYLORUN_HOME) and a Project link instead.`);
|
|
39
|
+
}
|
|
44
40
|
if (booleanNames.has(arg)) {
|
|
45
41
|
if (booleans.has(arg))
|
|
46
42
|
throw usageError(`${arg} may only be supplied once.`);
|
|
@@ -58,246 +54,81 @@ function parseFlags(args, allowed = {}) {
|
|
|
58
54
|
}
|
|
59
55
|
throw usageError(usage);
|
|
60
56
|
}
|
|
61
|
-
|
|
62
|
-
scope.global = true;
|
|
63
|
-
if (values.has("--port"))
|
|
64
|
-
scope.port = parsePort(values.get("--port"));
|
|
65
|
-
if (values.has("--db"))
|
|
66
|
-
scope.db = values.get("--db");
|
|
67
|
-
return { scope, rest, booleans, values };
|
|
57
|
+
return { rest, booleans, values };
|
|
68
58
|
}
|
|
69
59
|
const usageError = (message) => new CliError(message, 2);
|
|
70
|
-
function
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
(await localCredentials(scope.credentialsPath)).serverKey);
|
|
81
|
-
}
|
|
82
|
-
async function startStudio(agentServerUrl, serverKey, open, port) {
|
|
83
|
-
let entry;
|
|
84
|
-
try {
|
|
85
|
-
entry = createRequire(join(process.cwd(), "package.json")).resolve("@nylorun/studio");
|
|
60
|
+
async function resolveLinkedAuth(projectRoot) {
|
|
61
|
+
const link = await readProjectLink(projectRoot);
|
|
62
|
+
const credentials = await readProjectCredentials(projectRoot);
|
|
63
|
+
if (link && credentials) {
|
|
64
|
+
return {
|
|
65
|
+
url: link.hostUrl,
|
|
66
|
+
key: credentials.applicationKey,
|
|
67
|
+
tenantId: link.tenantId,
|
|
68
|
+
tenantName: link.tenantId,
|
|
69
|
+
};
|
|
86
70
|
}
|
|
87
|
-
|
|
88
|
-
|
|
71
|
+
const url = process.env.NYLORUN_RUNTIME_URL?.trim();
|
|
72
|
+
const key = process.env.NYLORUN_SERVER_KEY?.trim();
|
|
73
|
+
const tenantId = process.env.NYLORUN_TENANT?.trim();
|
|
74
|
+
if (url && key && tenantId) {
|
|
75
|
+
return { url, key, tenantId, tenantName: tenantId };
|
|
89
76
|
}
|
|
90
|
-
|
|
91
|
-
return studio.startStudio({
|
|
92
|
-
runtimeUrl: agentServerUrl,
|
|
93
|
-
serverKey,
|
|
94
|
-
open,
|
|
95
|
-
...(port === undefined ? {} : { port }),
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
function printStatus(status) {
|
|
99
|
-
const { scope, runtime } = status;
|
|
100
|
-
const lines = [
|
|
101
|
-
["Scope", `${scope.kind} (${scope.kind === "project" ? scope.root : scope.dataDir})`],
|
|
102
|
-
["State", status.state],
|
|
103
|
-
["URL", scope.url],
|
|
104
|
-
["PID", runtime?.pid ? String(runtime.pid) : status.pid ? String(status.pid) : undefined],
|
|
105
|
-
["Runtime", status.version],
|
|
106
|
-
["CLI expects", cliRuntimeVersion()],
|
|
107
|
-
["Database", scope.sqlitePath],
|
|
108
|
-
["Log", scope.logPath],
|
|
109
|
-
["Started", runtime?.startedAt],
|
|
110
|
-
];
|
|
111
|
-
const width = Math.max(...lines.map(([label]) => label.length));
|
|
112
|
-
for (const [label, value] of lines)
|
|
113
|
-
if (value !== undefined)
|
|
114
|
-
console.log(`${label.padEnd(width)} ${value}`);
|
|
115
|
-
}
|
|
116
|
-
async function runtimeCommand(args) {
|
|
117
|
-
const [verb, ...rest] = args;
|
|
118
|
-
if (verb === "start") {
|
|
119
|
-
const flags = parseFlags(rest, { booleans: ["--foreground", "--restart"] });
|
|
120
|
-
if (flags.rest.length)
|
|
121
|
-
throw usageError(usage);
|
|
122
|
-
const scope = resolveScope(flags.scope);
|
|
123
|
-
loadScopeEnvironment(scope);
|
|
124
|
-
const before = await hostStatus(scope);
|
|
125
|
-
if (before.state === "running" && !flags.booleans.has("--restart")) {
|
|
126
|
-
console.log(`Runtime already running for ${scope.label} at ${scope.url} (pid ${before.runtime?.pid ?? before.pid}).`);
|
|
127
|
-
warnIncompatible(scope, before);
|
|
128
|
-
return;
|
|
129
|
-
}
|
|
130
|
-
const status = await startHost(scope, {
|
|
131
|
-
foreground: flags.booleans.has("--foreground"),
|
|
132
|
-
restart: flags.booleans.has("--restart"),
|
|
133
|
-
});
|
|
134
|
-
printStatus(status);
|
|
135
|
-
console.log(`\n→ npx nylorun dev`);
|
|
136
|
-
return;
|
|
137
|
-
}
|
|
138
|
-
if (verb === "stop") {
|
|
139
|
-
const flags = parseFlags(rest, { values: ["--timeout"] });
|
|
140
|
-
if (flags.rest.length)
|
|
141
|
-
throw usageError(usage);
|
|
142
|
-
const scope = resolveScope(flags.scope);
|
|
143
|
-
const seconds = flags.values.has("--timeout")
|
|
144
|
-
? Number(flags.values.get("--timeout"))
|
|
145
|
-
: undefined;
|
|
146
|
-
if (seconds !== undefined && (!Number.isFinite(seconds) || seconds <= 0))
|
|
147
|
-
throw usageError("--timeout must be a positive number of seconds.");
|
|
148
|
-
const result = await stopHost(scope, {
|
|
149
|
-
...(seconds === undefined ? {} : { timeoutMs: seconds * 1000 }),
|
|
150
|
-
});
|
|
151
|
-
console.log(result === "stopped"
|
|
152
|
-
? `Stopped the Runtime for ${scope.label}. SQLite and credentials are kept in ${scope.dataDir}.`
|
|
153
|
-
: `No Runtime is running for ${scope.label}.`);
|
|
154
|
-
return;
|
|
155
|
-
}
|
|
156
|
-
if (verb === "status") {
|
|
157
|
-
const flags = parseFlags(rest, { values: ["--output"] });
|
|
158
|
-
if (flags.rest.length)
|
|
159
|
-
throw usageError(usage);
|
|
160
|
-
const output = flags.values.get("--output") ?? "text";
|
|
161
|
-
if (output !== "text" && output !== "json")
|
|
162
|
-
throw usageError("--output must be text or json.");
|
|
163
|
-
const scope = resolveScope(flags.scope);
|
|
164
|
-
const status = await hostStatus(scope);
|
|
165
|
-
if (output === "json")
|
|
166
|
-
console.log(JSON.stringify({
|
|
167
|
-
scope: scope.kind,
|
|
168
|
-
root: scope.kind === "project" ? scope.root : scope.dataDir,
|
|
169
|
-
url: scope.url,
|
|
170
|
-
state: status.state,
|
|
171
|
-
pid: status.runtime?.pid ?? status.pid ?? null,
|
|
172
|
-
runtimeVersion: status.version ?? null,
|
|
173
|
-
cliVersion: cliRuntimeVersion() ?? null,
|
|
174
|
-
scopeId: status.scopeId ?? null,
|
|
175
|
-
sqlitePath: scope.sqlitePath,
|
|
176
|
-
logPath: scope.logPath,
|
|
177
|
-
startedAt: status.runtime?.startedAt ?? null,
|
|
178
|
-
}, null, 2));
|
|
179
|
-
else
|
|
180
|
-
printStatus(status);
|
|
181
|
-
if (status.state !== "running")
|
|
182
|
-
process.exitCode = status.state === "port-conflict" ? 4 : 3;
|
|
183
|
-
return;
|
|
184
|
-
}
|
|
185
|
-
if (verb === "logs") {
|
|
186
|
-
const flags = parseFlags(rest, { booleans: ["-f"], values: ["-n"] });
|
|
187
|
-
if (flags.rest.length)
|
|
188
|
-
throw usageError(usage);
|
|
189
|
-
const lines = flags.values.has("-n") ? Number(flags.values.get("-n")) : 200;
|
|
190
|
-
if (!Number.isInteger(lines) || lines < 1)
|
|
191
|
-
throw usageError("-n must be a positive integer.");
|
|
192
|
-
await tailLog(resolveScope(flags.scope), {
|
|
193
|
-
follow: flags.booleans.has("-f"),
|
|
194
|
-
lines,
|
|
195
|
-
});
|
|
196
|
-
return;
|
|
197
|
-
}
|
|
198
|
-
throw usageError(usage);
|
|
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);
|
|
199
78
|
}
|
|
200
79
|
async function main() {
|
|
201
|
-
const [
|
|
202
|
-
if (!
|
|
80
|
+
const [command, ...args] = process.argv.slice(2);
|
|
81
|
+
if (!command || command === "--help" || command === "-h")
|
|
203
82
|
return void console.log(usage);
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
return
|
|
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);
|
|
85
|
+
if (command === "tenant")
|
|
86
|
+
return await tenantCommand(args);
|
|
87
|
+
if (command === "env") {
|
|
88
|
+
if (args.length)
|
|
89
|
+
throw usageError("Usage: nylo env");
|
|
90
|
+
await printLinkedEnvExports(findProjectRoot() ?? process.cwd());
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
213
93
|
if (command === "doctor") {
|
|
214
94
|
const [topic, ...options] = args;
|
|
215
95
|
if (topic !== "sandbox" || options.some((option) => option !== "--json"))
|
|
216
|
-
throw usageError("Usage:
|
|
96
|
+
throw usageError("Usage: nylo doctor sandbox [--json]. Check the local stack with npx nylorun doctor.");
|
|
217
97
|
const { doctorSandbox } = await import("./doctor.js");
|
|
218
98
|
await doctorSandbox({ json: options.includes("--json") });
|
|
219
99
|
return;
|
|
220
100
|
}
|
|
221
|
-
if (command === "dev")
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
});
|
|
225
|
-
if (flags.rest.length)
|
|
226
|
-
throw usageError(usage);
|
|
227
|
-
const scope = resolveScope(flags.scope);
|
|
228
|
-
loadScopeEnvironment(scope);
|
|
229
|
-
// The port is re-resolved after .env so a project file can set PORT, while --port wins.
|
|
230
|
-
const resolved = resolveScope(flags.scope);
|
|
231
|
-
process.env.PORT = String(resolved.port);
|
|
232
|
-
developmentPreflight([...flags.booleans]);
|
|
233
|
-
// The supervisor checks the host before spawning tsx so port conflicts, version skew and
|
|
234
|
-
// --no-autostart surface with their own exit codes instead of a generic watcher failure.
|
|
235
|
-
await ensureRuntime(resolved, {
|
|
236
|
-
autostart: !flags.booleans.has("--no-autostart"),
|
|
237
|
-
});
|
|
238
|
-
process.exitCode = await develop([...flags.booleans]);
|
|
239
|
-
return;
|
|
240
|
-
}
|
|
241
|
-
if (command === "serve") {
|
|
242
|
-
const flags = parseFlags(args, { booleans: ["--no-autostart"] });
|
|
243
|
-
if (flags.rest.length > 1)
|
|
244
|
-
throw usageError(usage);
|
|
245
|
-
const scope = resolveScope(flags.scope);
|
|
246
|
-
loadScopeEnvironment(scope);
|
|
247
|
-
const resolved = resolveScope(flags.scope);
|
|
248
|
-
// serve runs the project in this process, so runProject's own errors carry their exit
|
|
249
|
-
// codes out; it validates the agent registry before it touches the host.
|
|
250
|
-
await (await import("./launcher.js")).serve(flags.rest[0], {
|
|
251
|
-
autostart: !flags.booleans.has("--no-autostart"),
|
|
252
|
-
scope: resolved,
|
|
253
|
-
});
|
|
254
|
-
return;
|
|
255
|
-
}
|
|
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}`);
|
|
256
105
|
if (command === "configure") {
|
|
257
106
|
const flags = parseFlags(args);
|
|
258
107
|
if (flags.rest.length)
|
|
259
108
|
throw usageError(usage);
|
|
260
|
-
const
|
|
261
|
-
|
|
109
|
+
const projectRoot = findProjectRoot() ?? process.cwd();
|
|
110
|
+
const auth = await resolveLinkedAuth(projectRoot);
|
|
262
111
|
const controller = new AbortController();
|
|
263
112
|
const cancel = (signal) => controller.abort(new ConfigurationCancelled(signal));
|
|
264
113
|
process.once("SIGINT", () => cancel("SIGINT"));
|
|
265
114
|
process.once("SIGTERM", () => cancel("SIGTERM"));
|
|
266
|
-
const
|
|
267
|
-
const health = await fetch(`${scope.url}/health`).catch(() => undefined);
|
|
115
|
+
const health = await fetch(`${auth.url}/health`).catch(() => undefined);
|
|
268
116
|
if (!health?.ok)
|
|
269
|
-
throw new CliError(`No Runtime is listening at ${
|
|
270
|
-
const
|
|
271
|
-
|
|
117
|
+
throw new CliError(`No Runtime is listening at ${auth.url}. Start the local stack with "npx nylorun up".`, 6);
|
|
118
|
+
const catalog = await fetchModelCatalog({
|
|
119
|
+
url: auth.url,
|
|
120
|
+
key: auth.key,
|
|
121
|
+
tenantId: auth.tenantId,
|
|
122
|
+
});
|
|
123
|
+
const prompted = await configureProvider({
|
|
124
|
+
signal: controller.signal,
|
|
125
|
+
catalog,
|
|
126
|
+
});
|
|
127
|
+
await putHostModel(auth.url, auth.key, prompted, auth.tenantId);
|
|
272
128
|
return;
|
|
273
129
|
}
|
|
274
|
-
|
|
275
|
-
throw usageError(usage);
|
|
276
|
-
const flags = parseFlags(args, {
|
|
277
|
-
booleans: ["--no-open"],
|
|
278
|
-
values: ["--runtime-url", "--studio-port"],
|
|
279
|
-
});
|
|
280
|
-
if (flags.rest.length)
|
|
281
|
-
throw usageError(usage);
|
|
282
|
-
const scope = resolveScope(flags.scope);
|
|
283
|
-
const runtimeUrl = flags.values.get("--runtime-url") ?? scope.url;
|
|
284
|
-
const studioPort = flags.values.has("--studio-port")
|
|
285
|
-
? parsePort(flags.values.get("--studio-port"))
|
|
286
|
-
: flags.scope.port !== undefined && flags.values.has("--runtime-url")
|
|
287
|
-
? flags.scope.port
|
|
288
|
-
: undefined;
|
|
289
|
-
const dashboard = await startStudio(runtimeUrl, await serverKeyFor(scope), !flags.booleans.has("--no-open"), studioPort);
|
|
290
|
-
console.log(`Studio on ${dashboard.address}`);
|
|
291
|
-
await new Promise((resolve, reject) => {
|
|
292
|
-
const close = () => void dashboard.close().then(resolve, reject);
|
|
293
|
-
process.once("SIGINT", close);
|
|
294
|
-
process.once("SIGTERM", close);
|
|
295
|
-
});
|
|
130
|
+
throw usageError(usage);
|
|
296
131
|
}
|
|
297
|
-
/**
|
|
298
|
-
* Probing a port that answers but is not a Runtime can leave a pooled connection holding the
|
|
299
|
-
* event loop open, so a finished command exits explicitly once its output has drained.
|
|
300
|
-
*/
|
|
301
132
|
async function finish(code) {
|
|
302
133
|
process.exitCode = code;
|
|
303
134
|
for (const stream of [process.stdout, process.stderr])
|
package/dist/doctor.d.ts
CHANGED
|
@@ -1,7 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
export type SandboxReport = {
|
|
2
|
+
preference: string;
|
|
3
|
+
backend: string | null;
|
|
4
|
+
isolation?: string;
|
|
5
|
+
reason?: string;
|
|
6
|
+
probes: {
|
|
7
|
+
name: string;
|
|
8
|
+
isolation: string;
|
|
9
|
+
available: boolean;
|
|
10
|
+
reason?: string;
|
|
11
|
+
version?: string;
|
|
12
|
+
}[];
|
|
13
|
+
defaultImage?: string;
|
|
14
|
+
};
|
|
15
|
+
/** `nylo doctor sandbox`: Tenant sandbox report via the Tenant API (F2-4). */
|
|
3
16
|
export declare function doctorSandbox(options: {
|
|
4
17
|
json: boolean;
|
|
5
18
|
}): Promise<void>;
|
|
6
|
-
/** One line for the dev banner, or undefined when no connected agent declares a sandbox. */
|
|
7
|
-
export declare function sandboxBanner(runtimeUrl: string, serverKey: string, manifests: readonly AgentManifest[]): Promise<string | undefined>;
|