nylorun 0.8.0-beta → 0.11.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 +138 -0
- package/README.md +78 -34
- package/dist/cli.js +12 -2
- package/dist/doctor.js +2 -2
- package/dist/project/link.d.ts +21 -7
- package/dist/project/link.js +30 -6
- package/dist/project/seed.d.ts +2 -1
- package/dist/project/seed.js +5 -5
- package/dist/stack/commands.d.ts +39 -12
- package/dist/stack/commands.js +163 -111
- package/dist/stack/compose-file.d.ts +15 -14
- package/dist/stack/compose-file.js +40 -41
- package/dist/stack/env-file.d.ts +3 -17
- package/dist/stack/env-file.js +6 -41
- package/dist/stack/host-files.d.ts +0 -3
- package/dist/stack/host-files.js +2 -3
- package/dist/stack/index.d.ts +6 -0
- package/dist/stack/index.js +12 -1
- package/dist/stack/keys.d.ts +4 -0
- package/dist/stack/keys.js +74 -0
- package/dist/stack/mcp.d.ts +8 -0
- package/dist/stack/mcp.js +114 -0
- package/dist/stack/operator-keys.d.ts +39 -0
- package/dist/stack/operator-keys.js +138 -0
- package/dist/stack/paths.d.ts +18 -12
- package/dist/stack/paths.js +5 -7
- package/dist/stack/ports.d.ts +0 -2
- package/dist/stack/ports.js +0 -2
- package/dist/stack/prepare.d.ts +2 -4
- package/dist/stack/prepare.js +4 -7
- package/dist/stack/sandbox.js +1 -1
- package/package.json +4 -4
- package/dist/project/derived-key.d.ts +0 -8
- package/dist/project/derived-key.js +0 -18
|
@@ -13,8 +13,7 @@
|
|
|
13
13
|
* database with C collation (`--locale=C`) and runs with `wal_level=logical`: the stream
|
|
14
14
|
* relay feeds s2-lite from the record over logical replication (Durable Streams), and
|
|
15
15
|
* `max_slot_wal_keep_size` caps the WAL a stuck relay can hold. The Runtime creates the
|
|
16
|
-
* Tenant on its first start, with its name (`NYLORUN_TENANT_NAME`)
|
|
17
|
-
* principals of `NYLORUN_DERIVED_PRINCIPALS` (`project` for the Project link).
|
|
16
|
+
* Tenant on its first start, with its name (`NYLORUN_TENANT_NAME`).
|
|
18
17
|
*
|
|
19
18
|
* Restate signs requests to the Worker endpoint with the private key in
|
|
20
19
|
* `docker/restate-identity.pem`, mounted read-only; the Runtime gets the public
|
|
@@ -23,17 +22,17 @@
|
|
|
23
22
|
* The combined packing (blueprint D12): the `runtime` container runs the core
|
|
24
23
|
* and loop services, and the `gateway` container runs gates: the Model Gate,
|
|
25
24
|
* which alone reads model credentials, and the Tool Gate (F4.1), which alone
|
|
26
|
-
* holds remote MCP connections and their credentials and
|
|
27
|
-
*
|
|
25
|
+
* holds remote MCP connections and their credentials and makes every HTTP tool
|
|
26
|
+
* request. Every model call, remote MCP call and HTTP tool call of the loop crosses it
|
|
28
27
|
* (NYLORUN_GATES_URL, with NYLORUN_GATES_TOKEN from `.env`, or a run's token from the
|
|
29
|
-
* harness)
|
|
28
|
+
* harness). The gateway also runs keys (F4.2): the only
|
|
30
29
|
* holder of the vault key, it runs every vault write that touches a secret and signs
|
|
31
30
|
* every token (NYLORUN_KEYS_URL). The gateway mounts only the Host's Tenant directory
|
|
32
31
|
* (`tenant/`) and its keys directory (`keys/`, the vault key), read-only: never
|
|
33
32
|
* host-credentials.json. The runtime mounts the Host root with `keys/` and `docker/`
|
|
34
33
|
* covered by empty read-only mounts, so it can read neither the vault key nor
|
|
35
34
|
* Restate's private key and `.env`. The runtime does not wait for the gateway: while
|
|
36
|
-
* it is down, model and
|
|
35
|
+
* it is down, model, MCP and HTTP tool calls fail, vault writes and
|
|
37
36
|
* token minting answer 503, and the session takes the next message.
|
|
38
37
|
*
|
|
39
38
|
* The Object store (blueprint D35) is RustFS, single node and single drive, pinned by digest,
|
|
@@ -54,23 +53,25 @@
|
|
|
54
53
|
* CONNECT with the egress token, to the hosts the sandbox spec allows). The two HTTP listeners
|
|
55
54
|
* accept that address as a Host.
|
|
56
55
|
*
|
|
57
|
-
* The harness (F6.2, `harness: "remote"`, the default) runs every agent turn
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
* paths on this machine; the runtime mounts it there too). NYLORUN_HARNESS=in-process in `.env`
|
|
64
|
-
* rolls back to turns in the runtime container, without the harness service.
|
|
56
|
+
* The harness (F6.2, `harness: "remote"`, the default) runs every agent turn and workspace in
|
|
57
|
+
* its own container: the runtime image with `--service harness`, connected to core's Harness
|
|
58
|
+
* API (`ws://runtime:4200/nylorun/harness/v1`) with NYLORUN_HARNESS_TOKEN, its only
|
|
59
|
+
* credential, and calling models and remote MCP servers through the gateway with each run's
|
|
60
|
+
* token. It mounts only the Tenant's `sandboxes/` under `/harness`. NYLORUN_HARNESS=in-process
|
|
61
|
+
* in `.env` rolls back to turns in the runtime container, without the harness service.
|
|
65
62
|
*
|
|
66
63
|
* Three networks: `store` (internal: no egress) joins Postgres, s2-lite, Restate and RustFS to
|
|
67
64
|
* the runtime and the gateway; `harness` joins the harness to the runtime and the gateway only;
|
|
68
65
|
* `default` carries egress and the published ports (runtime, gateway, Studio, sandboxes).
|
|
69
66
|
* Restate's admin port (its UI, unauthenticated) is published, and Restate joins `default`,
|
|
70
67
|
* only with `restateUi` (`nylorun start --restate-ui`).
|
|
68
|
+
*
|
|
69
|
+
* With `identity` (when `<Host root>/identity.yaml` exists) the runtime reads its trusted issuers
|
|
70
|
+
* from it, through the Host root mount (NYLORUN_IDENTITY_FILE=/nylorun/identity.yaml).
|
|
71
71
|
*/
|
|
72
72
|
export declare function renderComposeFile(project: string, name: string, options?: {
|
|
73
73
|
sandboxes?: true;
|
|
74
74
|
harness?: "remote" | "in-process";
|
|
75
75
|
restateUi?: true;
|
|
76
|
+
identity?: true;
|
|
76
77
|
}): string;
|
|
@@ -14,8 +14,7 @@ import { PINNED_IMAGES } from "./images.js";
|
|
|
14
14
|
* database with C collation (`--locale=C`) and runs with `wal_level=logical`: the stream
|
|
15
15
|
* relay feeds s2-lite from the record over logical replication (Durable Streams), and
|
|
16
16
|
* `max_slot_wal_keep_size` caps the WAL a stuck relay can hold. The Runtime creates the
|
|
17
|
-
* Tenant on its first start, with its name (`NYLORUN_TENANT_NAME`)
|
|
18
|
-
* principals of `NYLORUN_DERIVED_PRINCIPALS` (`project` for the Project link).
|
|
17
|
+
* Tenant on its first start, with its name (`NYLORUN_TENANT_NAME`).
|
|
19
18
|
*
|
|
20
19
|
* Restate signs requests to the Worker endpoint with the private key in
|
|
21
20
|
* `docker/restate-identity.pem`, mounted read-only; the Runtime gets the public
|
|
@@ -24,17 +23,17 @@ import { PINNED_IMAGES } from "./images.js";
|
|
|
24
23
|
* The combined packing (blueprint D12): the `runtime` container runs the core
|
|
25
24
|
* and loop services, and the `gateway` container runs gates: the Model Gate,
|
|
26
25
|
* which alone reads model credentials, and the Tool Gate (F4.1), which alone
|
|
27
|
-
* holds remote MCP connections and their credentials and
|
|
28
|
-
*
|
|
26
|
+
* holds remote MCP connections and their credentials and makes every HTTP tool
|
|
27
|
+
* request. Every model call, remote MCP call and HTTP tool call of the loop crosses it
|
|
29
28
|
* (NYLORUN_GATES_URL, with NYLORUN_GATES_TOKEN from `.env`, or a run's token from the
|
|
30
|
-
* harness)
|
|
29
|
+
* harness). The gateway also runs keys (F4.2): the only
|
|
31
30
|
* holder of the vault key, it runs every vault write that touches a secret and signs
|
|
32
31
|
* every token (NYLORUN_KEYS_URL). The gateway mounts only the Host's Tenant directory
|
|
33
32
|
* (`tenant/`) and its keys directory (`keys/`, the vault key), read-only: never
|
|
34
33
|
* host-credentials.json. The runtime mounts the Host root with `keys/` and `docker/`
|
|
35
34
|
* covered by empty read-only mounts, so it can read neither the vault key nor
|
|
36
35
|
* Restate's private key and `.env`. The runtime does not wait for the gateway: while
|
|
37
|
-
* it is down, model and
|
|
36
|
+
* it is down, model, MCP and HTTP tool calls fail, vault writes and
|
|
38
37
|
* token minting answer 503, and the session takes the next message.
|
|
39
38
|
*
|
|
40
39
|
* The Object store (blueprint D35) is RustFS, single node and single drive, pinned by digest,
|
|
@@ -55,23 +54,25 @@ import { PINNED_IMAGES } from "./images.js";
|
|
|
55
54
|
* CONNECT with the egress token, to the hosts the sandbox spec allows). The two HTTP listeners
|
|
56
55
|
* accept that address as a Host.
|
|
57
56
|
*
|
|
58
|
-
* The harness (F6.2, `harness: "remote"`, the default) runs every agent turn
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
* paths on this machine; the runtime mounts it there too). NYLORUN_HARNESS=in-process in `.env`
|
|
65
|
-
* rolls back to turns in the runtime container, without the harness service.
|
|
57
|
+
* The harness (F6.2, `harness: "remote"`, the default) runs every agent turn and workspace in
|
|
58
|
+
* its own container: the runtime image with `--service harness`, connected to core's Harness
|
|
59
|
+
* API (`ws://runtime:4200/nylorun/harness/v1`) with NYLORUN_HARNESS_TOKEN, its only
|
|
60
|
+
* credential, and calling models and remote MCP servers through the gateway with each run's
|
|
61
|
+
* token. It mounts only the Tenant's `sandboxes/` under `/harness`. NYLORUN_HARNESS=in-process
|
|
62
|
+
* in `.env` rolls back to turns in the runtime container, without the harness service.
|
|
66
63
|
*
|
|
67
64
|
* Three networks: `store` (internal: no egress) joins Postgres, s2-lite, Restate and RustFS to
|
|
68
65
|
* the runtime and the gateway; `harness` joins the harness to the runtime and the gateway only;
|
|
69
66
|
* `default` carries egress and the published ports (runtime, gateway, Studio, sandboxes).
|
|
70
67
|
* Restate's admin port (its UI, unauthenticated) is published, and Restate joins `default`,
|
|
71
68
|
* only with `restateUi` (`nylorun start --restate-ui`).
|
|
69
|
+
*
|
|
70
|
+
* With `identity` (when `<Host root>/identity.yaml` exists) the runtime reads its trusted issuers
|
|
71
|
+
* from it, through the Host root mount (NYLORUN_IDENTITY_FILE=/nylorun/identity.yaml).
|
|
72
72
|
*/
|
|
73
73
|
export function renderComposeFile(project, name, options = {}) {
|
|
74
74
|
const sandboxes = options.sandboxes === true;
|
|
75
|
+
const identity = options.identity === true;
|
|
75
76
|
const remote = (options.harness ?? "remote") === "remote";
|
|
76
77
|
const restateUi = options.restateUi === true;
|
|
77
78
|
return `# Written by \`nylorun start\`; rewritten on every start. Settings live in .env.
|
|
@@ -173,10 +174,14 @@ ${restateUi ? RESTATE_UI : RESTATE_CLOSED} healthcheck:
|
|
|
173
174
|
NYLORUN_OBJECT_STORE_ENDPOINT: http://rustfs:9000
|
|
174
175
|
NYLORUN_OBJECT_STORE_ACCESS_KEY: nylorun
|
|
175
176
|
NYLORUN_OBJECT_STORE_SECRET_KEY: \${NYLORUN_OBJECT_STORE_SECRET_KEY:?run nylorun start}
|
|
176
|
-
#
|
|
177
|
-
NYLORUN_ENDPOINT_LOOPBACK: docker-host
|
|
177
|
+
# MCP servers and HTTP tools on this machine: \`localhost\` in their URLs means the Docker host.
|
|
178
|
+
NYLORUN_ENDPOINT_LOOPBACK: docker-host
|
|
179
|
+
# Your credential resolver, for people's own MCP credentials (DEPLOYMENT.md, Credentials);
|
|
180
|
+
# unset by default. Set both in the shell that runs \`nylorun start\`.
|
|
181
|
+
NYLORUN_RESOLVER_URL: \${NYLORUN_RESOLVER_URL:-}
|
|
182
|
+
NYLORUN_RESOLVER_TOKEN: \${NYLORUN_RESOLVER_TOKEN:-}${sandboxes ? SANDBOXES_GATEWAY_ENV : ""}
|
|
178
183
|
extra_hosts:
|
|
179
|
-
host.docker.internal: host-gateway # model servers, MCP servers and
|
|
184
|
+
host.docker.internal: host-gateway # model servers, MCP servers and HTTP tools on this machine
|
|
180
185
|
volumes:
|
|
181
186
|
# The Tenant's homes and its vault key only, read-only.
|
|
182
187
|
- \${NYLORUN_HOST_ROOT:?run nylorun start}/tenant:/nylorun/tenant:ro
|
|
@@ -206,8 +211,7 @@ ${sandboxes ? SANDBOXES_GATES_PORT : ""} # Egress and the stores; the harness
|
|
|
206
211
|
NYLORUN_PACKING: combined
|
|
207
212
|
# The Tenant the Runtime creates on its first start (later starts open it).
|
|
208
213
|
NYLORUN_TENANT_NAME: \${NYLORUN_TENANT_NAME:?run nylorun start}
|
|
209
|
-
|
|
210
|
-
# Model calls, remote MCP calls and deliveries go through the gateway, and vault writes
|
|
214
|
+
# Model calls, remote MCP calls and HTTP tool calls go through the gateway, and vault writes
|
|
211
215
|
# and token signing through its keys service: this container never reads a credential
|
|
212
216
|
# or the vault key.
|
|
213
217
|
NYLORUN_GATES_URL: http://gateway:4100
|
|
@@ -218,11 +222,7 @@ ${sandboxes ? SANDBOXES_GATES_PORT : ""} # Egress and the stores; the harness
|
|
|
218
222
|
# Host headers the Runtime accepts: its name on the Compose network, and the
|
|
219
223
|
# published port as clients on this machine address it.
|
|
220
224
|
NYLORUN_ALLOWED_HOSTS: runtime:4000,localhost:\${NYLORUN_PORT},127.0.0.1:\${NYLORUN_PORT}
|
|
221
|
-
NYLORUN_PUBLIC_URL: http://localhost:\${NYLORUN_PORT}
|
|
222
|
-
# The Admin API on its own listener, published on loopback only; Studio reaches it on
|
|
223
|
-
# the Compose network. Port 4000 serves the Tenant API alone.
|
|
224
|
-
NYLORUN_ADMIN_LISTEN_PORT: "4001"
|
|
225
|
-
NYLORUN_ADMIN_ALLOWED_HOSTS: runtime:4001,localhost:\${NYLORUN_ADMIN_PORT},127.0.0.1:\${NYLORUN_ADMIN_PORT}
|
|
225
|
+
NYLORUN_PUBLIC_URL: http://localhost:\${NYLORUN_PORT}
|
|
226
226
|
NYLORUN_DATABASE_URL: postgres://nylorun:\${NYLORUN_POSTGRES_PASSWORD}@postgres:5432/nylorun
|
|
227
227
|
NYLORUN_RESTATE_INGRESS_URL: http://restate:8080
|
|
228
228
|
NYLORUN_RESTATE_ADMIN_URL: http://restate:9070
|
|
@@ -235,14 +235,14 @@ ${sandboxes ? SANDBOXES_GATES_PORT : ""} # Egress and the stores; the harness
|
|
|
235
235
|
NYLORUN_OBJECT_STORE_ENDPOINT: http://rustfs:9000
|
|
236
236
|
NYLORUN_OBJECT_STORE_ACCESS_KEY: nylorun
|
|
237
237
|
NYLORUN_OBJECT_STORE_SECRET_KEY: \${NYLORUN_OBJECT_STORE_SECRET_KEY:?run nylorun start}
|
|
238
|
-
#
|
|
238
|
+
# MCP servers and HTTP tools on this machine: \`localhost\` in their URLs means the Docker host.
|
|
239
239
|
NYLORUN_ENDPOINT_LOOPBACK: docker-host
|
|
240
240
|
# Agent turns, MCP servers and workspaces run in the harness container, which connects to
|
|
241
241
|
# this listener with NYLORUN_HARNESS_TOKEN. NYLORUN_HARNESS=in-process in .env rolls back.
|
|
242
242
|
NYLORUN_HARNESS: \${NYLORUN_HARNESS:-remote}
|
|
243
243
|
NYLORUN_HARNESS_LISTEN_PORT: "4200"
|
|
244
244
|
NYLORUN_HARNESS_ALLOWED_HOSTS: runtime:4200${sandboxes ? SANDBOXES_HARNESS_HOST : ""}
|
|
245
|
-
NYLORUN_HARNESS_TOKEN: \${NYLORUN_HARNESS_TOKEN:?run nylorun start}${sandboxes ? SANDBOXES_RUNTIME_ENV : ""}
|
|
245
|
+
NYLORUN_HARNESS_TOKEN: \${NYLORUN_HARNESS_TOKEN:?run nylorun start}${sandboxes ? SANDBOXES_RUNTIME_ENV : ""}${identity ? IDENTITY_RUNTIME_ENV : ""}
|
|
246
246
|
extra_hosts:
|
|
247
247
|
host.docker.internal: host-gateway # the Docker host, also on Linux Docker Engine
|
|
248
248
|
volumes:
|
|
@@ -258,13 +258,10 @@ ${sandboxes ? SANDBOXES_GATES_PORT : ""} # Egress and the stores; the harness
|
|
|
258
258
|
read_only: true
|
|
259
259
|
tmpfs: { size: 4096, mode: 0755 } # empty, and listable by the runtime user${sandboxes ? SANDBOXES_RUNTIME_MOUNT : ""}
|
|
260
260
|
- workspaces:/workspaces
|
|
261
|
-
# Plugin roots on this machine, at their own path (as for the harness), for NYLORUN_HARNESS=in-process.
|
|
262
|
-
- \${NYLORUN_HOST_ROOT:?run nylorun start}/plugins:\${NYLORUN_HOST_ROOT:?run nylorun start}/plugins:ro
|
|
263
261
|
networks: [default, store, harness]
|
|
264
262
|
ports:
|
|
265
|
-
- "127.0.0.1:\${NYLORUN_PORT:?run nylorun start}:4000" #
|
|
266
|
-
|
|
267
|
-
healthcheck: # liveness: a Tenant that cannot open is reported by nylorun start from the Admin status, not by a 300 s wait
|
|
263
|
+
- "127.0.0.1:\${NYLORUN_PORT:?run nylorun start}:4000" # Runtime and Management APIs, SSE, browsers${sandboxes ? SANDBOXES_RUNTIME_PORT : ""}
|
|
264
|
+
healthcheck: # liveness: a Tenant that cannot open is reported by nylorun start (/ready, nylorun-operate status), not by a 300 s wait
|
|
268
265
|
test: ["CMD", "node", "-e", "fetch('http://localhost:4000/health').then(r=>process.exit(r.ok?0:1),()=>process.exit(1))"]
|
|
269
266
|
interval: 2s
|
|
270
267
|
timeout: 5s
|
|
@@ -279,7 +276,7 @@ ${sandboxes ? SANDBOXES_GATES_PORT : ""} # Egress and the stores; the harness
|
|
|
279
276
|
depends_on:
|
|
280
277
|
runtime: { condition: service_healthy }
|
|
281
278
|
environment:
|
|
282
|
-
NYLORUN_RUNTIME_URL: http://runtime:
|
|
279
|
+
NYLORUN_RUNTIME_URL: http://runtime:4000 # the public listener: Runtime and Management API
|
|
283
280
|
NYLORUN_ADMIN_KEY_FILE: /run/nylorun/host-credentials.json
|
|
284
281
|
PORT: "3000"
|
|
285
282
|
# Studio's Host check accepts localhost/127.0.0.1 on the published port.
|
|
@@ -287,10 +284,13 @@ ${sandboxes ? SANDBOXES_GATES_PORT : ""} # Egress and the stores; the harness
|
|
|
287
284
|
# Browsers share cookies across ports of one host: a cookie per Tenant keeps the
|
|
288
285
|
# sessions of two Studios on localhost apart.
|
|
289
286
|
NYLORUN_STUDIO_SESSION_COOKIE: nylorun_studio_${name}
|
|
290
|
-
# Exact origins that may frame Studio (
|
|
287
|
+
# Exact origins that may frame Studio (none by default: embedding is opt-in); kept in .env.
|
|
291
288
|
NYLORUN_STUDIO_FRAME_ANCESTORS: \${NYLORUN_STUDIO_FRAME_ANCESTORS:-}
|
|
292
289
|
# Studio's anonymous usage analytics; empty when telemetry is off.
|
|
293
290
|
NYLORUN_STUDIO_ANALYTICS_ID: \${NYLORUN_STUDIO_ANALYTICS_ID:-}
|
|
291
|
+
# Extra Host values Studio serves behind a sign-in proxy (studio.acme.dev),
|
|
292
|
+
# comma-separated; from the environment of nylorun start.
|
|
293
|
+
NYLORUN_STUDIO_ALLOWED_HOSTS: \${NYLORUN_STUDIO_ALLOWED_HOSTS:-}
|
|
294
294
|
volumes:
|
|
295
295
|
- \${NYLORUN_HOST_ROOT}/host-credentials.json:/run/nylorun/host-credentials.json:ro
|
|
296
296
|
networks: [default]
|
|
@@ -332,13 +332,13 @@ const RESTATE_UI = ` networks: [store, default]
|
|
|
332
332
|
- "127.0.0.1:\${NYLORUN_RESTATE_PORT:?run nylorun start}:9070" # Restate UI and admin (unauthenticated): nylorun start --restate-ui
|
|
333
333
|
`;
|
|
334
334
|
/**
|
|
335
|
-
* The harness service (F6.2): agent turns
|
|
335
|
+
* The harness service (F6.2): agent turns and workspaces, apart from core.
|
|
336
336
|
* It holds the harness token only; models and remote MCP servers are reached through the
|
|
337
337
|
* gateway with each run's token. Healthy once connected to core's Harness API.
|
|
338
338
|
*/
|
|
339
339
|
function harnessService(project) {
|
|
340
340
|
return `
|
|
341
|
-
harness: # agent turns
|
|
341
|
+
harness: # agent turns and workspaces; holds only the harness token; not published
|
|
342
342
|
image: \${NYLORUN_RUNTIME_IMAGE:?run nylorun start}
|
|
343
343
|
container_name: ${project}-harness
|
|
344
344
|
labels: *tenant
|
|
@@ -353,13 +353,8 @@ function harnessService(project) {
|
|
|
353
353
|
NYLORUN_GATES_URL: http://gateway:4100
|
|
354
354
|
NYLORUN_HARNESS_ROOT: /harness
|
|
355
355
|
volumes:
|
|
356
|
-
# The Tenant's workspaces
|
|
356
|
+
# The Tenant's workspaces; nothing else.
|
|
357
357
|
- \${NYLORUN_HOST_ROOT:?run nylorun start}/tenant/sandboxes:/harness/sandboxes
|
|
358
|
-
- \${NYLORUN_HOST_ROOT:?run nylorun start}/tenant/plugin-data:/harness/plugin-data
|
|
359
|
-
- \${NYLORUN_HOST_ROOT:?run nylorun start}/tenant/home:/harness/home
|
|
360
|
-
- \${NYLORUN_HOST_ROOT:?run nylorun start}/tenant/tmp:/harness/tmp
|
|
361
|
-
# Plugin roots on this machine, read-only, at their own path: agents name them so.
|
|
362
|
-
- \${NYLORUN_HOST_ROOT:?run nylorun start}/plugins:\${NYLORUN_HOST_ROOT:?run nylorun start}/plugins:ro
|
|
363
358
|
networks: [harness]
|
|
364
359
|
healthcheck: # healthy once connected to core's Harness API
|
|
365
360
|
test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:4300/health').then(r=>r.json()).then(b=>process.exit(b.connected?0:1),()=>process.exit(1))"]
|
|
@@ -373,6 +368,10 @@ function harnessService(project) {
|
|
|
373
368
|
* The runtime reaches the sandboxes service on the Compose network with its token, and serves
|
|
374
369
|
* the Harness API to sandbox pods (F7.2) on the Docker host's address.
|
|
375
370
|
*/
|
|
371
|
+
/** The identity file (`<Host root>/identity.yaml`): the trusted issuers, read at boot. */
|
|
372
|
+
const IDENTITY_RUNTIME_ENV = `
|
|
373
|
+
# Trusted issuers (<Host root>/identity.yaml): JWTs from the operator's identity provider.
|
|
374
|
+
NYLORUN_IDENTITY_FILE: /nylorun/identity.yaml`;
|
|
376
375
|
const SANDBOXES_RUNTIME_ENV = `
|
|
377
376
|
# The sandboxes service (nylorun sandbox enable): pods on the Tenant's cluster.
|
|
378
377
|
NYLORUN_SANDBOXES_URL: http://sandboxes:4300
|
package/dist/stack/env-file.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Origins that may embed Studio by default:
|
|
3
|
-
*
|
|
2
|
+
* Origins that may embed Studio by default: none. Embedding is opt-in: the operator lists
|
|
3
|
+
* the exact origins of the app that frames Studio (`--studio-embed-origin`, Studio §8.9).
|
|
4
4
|
*/
|
|
5
|
-
export declare const DEFAULT_STUDIO_FRAME_ANCESTORS: readonly [
|
|
5
|
+
export declare const DEFAULT_STUDIO_FRAME_ANCESTORS: readonly string[];
|
|
6
6
|
/**
|
|
7
7
|
* Settings in `docker/.env` (mode 0600). Ports, the password and the gates token
|
|
8
8
|
* persist; the Restate identity public key is derived from `restate-identity.pem`.
|
|
@@ -10,8 +10,6 @@ export declare const DEFAULT_STUDIO_FRAME_ANCESTORS: readonly ["nylorun://localh
|
|
|
10
10
|
export interface StackEnv {
|
|
11
11
|
/** Published Runtime port (loopback): the Tenant API. */
|
|
12
12
|
runtimePort: number;
|
|
13
|
-
/** Published operator port (loopback): the Admin API. */
|
|
14
|
-
adminPort: number;
|
|
15
13
|
/** Published Studio port (loopback). */
|
|
16
14
|
studioPort: number;
|
|
17
15
|
/** Restate UI and admin port (loopback), published only with `restateUi`. */
|
|
@@ -57,11 +55,6 @@ export interface StackEnv {
|
|
|
57
55
|
studioAnalyticsId: string;
|
|
58
56
|
/** The Tenant's name, which the Runtime gives the Tenant it creates. */
|
|
59
57
|
tenantName: string;
|
|
60
|
-
/**
|
|
61
|
-
* Derived principals the Runtime registers on its Tenant, comma-separated (persists);
|
|
62
|
-
* always includes `project`, the Project link's principal.
|
|
63
|
-
*/
|
|
64
|
-
derivedPrincipals: string;
|
|
65
58
|
/** Present once `nylorun sandbox enable` ran for the Tenant (F7.2). */
|
|
66
59
|
sandboxes?: SandboxStackEnv;
|
|
67
60
|
}
|
|
@@ -84,17 +77,11 @@ export interface SandboxStackEnv {
|
|
|
84
77
|
}
|
|
85
78
|
export type HarnessMode = "remote" | "in-process";
|
|
86
79
|
export declare function renderEnvFile(env: StackEnv): string;
|
|
87
|
-
/**
|
|
88
|
-
* `NYLORUN_DERIVED_PRINCIPALS`: comma-separated principal ids, as the Runtime accepts them
|
|
89
|
-
* (not `studio`), with `project` first so the Project link's key always works.
|
|
90
|
-
*/
|
|
91
|
-
export declare function parseDerivedPrincipals(raw: string, source: string): string[];
|
|
92
80
|
/** Parse KEY=value lines; comments and blank lines are skipped. */
|
|
93
81
|
export declare function parseEnvLines(text: string): Map<string, string>;
|
|
94
82
|
/** The settings that persist across starts, from an existing .env. */
|
|
95
83
|
export interface PersistedStackEnv {
|
|
96
84
|
runtimePort?: number;
|
|
97
|
-
adminPort?: number;
|
|
98
85
|
studioPort?: number;
|
|
99
86
|
restatePort?: number;
|
|
100
87
|
/** Whether the last start published Restate's UI (`NYLORUN_RESTATE_UI=1`). */
|
|
@@ -106,7 +93,6 @@ export interface PersistedStackEnv {
|
|
|
106
93
|
objectStoreSecretKey?: string;
|
|
107
94
|
/** Validated origins; absent when the line is missing (an older .env). */
|
|
108
95
|
studioFrameAncestors?: string[];
|
|
109
|
-
derivedPrincipals?: string[];
|
|
110
96
|
sandboxes?: SandboxStackEnv;
|
|
111
97
|
}
|
|
112
98
|
export declare function parsePersisted(text: string): PersistedStackEnv;
|
package/dist/stack/env-file.js
CHANGED
|
@@ -1,14 +1,10 @@
|
|
|
1
|
-
import { DERIVED_PRINCIPAL_ID_PATTERN } from "@nylorun/core/compatibility";
|
|
2
1
|
import { parseFrameAncestors } from "@nylorun/core/contracts";
|
|
3
2
|
import { CliError } from "../errors.js";
|
|
4
3
|
/**
|
|
5
|
-
* Origins that may embed Studio by default:
|
|
6
|
-
*
|
|
4
|
+
* Origins that may embed Studio by default: none. Embedding is opt-in: the operator lists
|
|
5
|
+
* the exact origins of the app that frames Studio (`--studio-embed-origin`, Studio §8.9).
|
|
7
6
|
*/
|
|
8
|
-
export const DEFAULT_STUDIO_FRAME_ANCESTORS = [
|
|
9
|
-
"nylorun://localhost",
|
|
10
|
-
"http://nylorun.localhost",
|
|
11
|
-
];
|
|
7
|
+
export const DEFAULT_STUDIO_FRAME_ANCESTORS = [];
|
|
12
8
|
const SANDBOX_KEYS = {
|
|
13
9
|
token: "NYLORUN_SANDBOXES_TOKEN",
|
|
14
10
|
image: "NYLORUN_SANDBOXES_IMAGE",
|
|
@@ -20,7 +16,6 @@ const SANDBOX_KEYS = {
|
|
|
20
16
|
};
|
|
21
17
|
const KEYS = {
|
|
22
18
|
runtimePort: "NYLORUN_PORT",
|
|
23
|
-
adminPort: "NYLORUN_ADMIN_PORT",
|
|
24
19
|
studioPort: "NYLORUN_STUDIO_PORT",
|
|
25
20
|
restatePort: "NYLORUN_RESTATE_PORT",
|
|
26
21
|
restateUi: "NYLORUN_RESTATE_UI",
|
|
@@ -38,7 +33,6 @@ const KEYS = {
|
|
|
38
33
|
studioFrameAncestors: "NYLORUN_STUDIO_FRAME_ANCESTORS",
|
|
39
34
|
studioAnalyticsId: "NYLORUN_STUDIO_ANALYTICS_ID",
|
|
40
35
|
tenantName: "NYLORUN_TENANT_NAME",
|
|
41
|
-
derivedPrincipals: "NYLORUN_DERIVED_PRINCIPALS",
|
|
42
36
|
};
|
|
43
37
|
/** Compose .env values: single quotes keep a value literal (no interpolation). */
|
|
44
38
|
function quote(key, value) {
|
|
@@ -68,7 +62,6 @@ export function renderEnvFile(env) {
|
|
|
68
62
|
"",
|
|
69
63
|
"# Published on 127.0.0.1; clients use http://localhost:<port>.",
|
|
70
64
|
line("runtimePort"),
|
|
71
|
-
line("adminPort"),
|
|
72
65
|
line("studioPort"),
|
|
73
66
|
"# Restate's UI and admin (unauthenticated) are published only with",
|
|
74
67
|
"# nylorun start --restate-ui (or NYLORUN_RESTATE_UI=1); decided on every start.",
|
|
@@ -104,8 +97,8 @@ export function renderEnvFile(env) {
|
|
|
104
97
|
line("runtimeImage"),
|
|
105
98
|
line("studioImage"),
|
|
106
99
|
"",
|
|
107
|
-
"# Exact origins that may show Studio in a frame
|
|
108
|
-
"# starts;
|
|
100
|
+
"# Exact origins that may show Studio in a frame; none by default. Kept across",
|
|
101
|
+
"# starts; add with nylorun start --studio-embed-origin <origin>.",
|
|
109
102
|
line("studioFrameAncestors"),
|
|
110
103
|
"",
|
|
111
104
|
"# Studio's anonymous usage analytics; empty when off. Set on every start: turn",
|
|
@@ -113,10 +106,8 @@ export function renderEnvFile(env) {
|
|
|
113
106
|
line("studioAnalyticsId"),
|
|
114
107
|
"",
|
|
115
108
|
"# The Tenant's name, which the Runtime gives the Tenant it creates on the first",
|
|
116
|
-
"# start
|
|
117
|
-
"# from the admin key; `project` is the Project link's).",
|
|
109
|
+
"# start.",
|
|
118
110
|
line("tenantName"),
|
|
119
|
-
line("derivedPrincipals"),
|
|
120
111
|
"",
|
|
121
112
|
...(sandboxes
|
|
122
113
|
? [
|
|
@@ -134,20 +125,6 @@ export function renderEnvFile(env) {
|
|
|
134
125
|
: []),
|
|
135
126
|
].join("\n");
|
|
136
127
|
}
|
|
137
|
-
/**
|
|
138
|
-
* `NYLORUN_DERIVED_PRINCIPALS`: comma-separated principal ids, as the Runtime accepts them
|
|
139
|
-
* (not `studio`), with `project` first so the Project link's key always works.
|
|
140
|
-
*/
|
|
141
|
-
export function parseDerivedPrincipals(raw, source) {
|
|
142
|
-
const ids = raw
|
|
143
|
-
.split(",")
|
|
144
|
-
.map((entry) => entry.trim())
|
|
145
|
-
.filter((entry) => entry !== "");
|
|
146
|
-
for (const id of ids)
|
|
147
|
-
if (!DERIVED_PRINCIPAL_ID_PATTERN.test(id) || id === "studio")
|
|
148
|
-
throw new CliError(`${source} has '${id}': each entry must match ${DERIVED_PRINCIPAL_ID_PATTERN} and not be studio.`, 2);
|
|
149
|
-
return [...new Set(["project", ...ids])];
|
|
150
|
-
}
|
|
151
128
|
/** Parse KEY=value lines; comments and blank lines are skipped. */
|
|
152
129
|
export function parseEnvLines(text) {
|
|
153
130
|
const values = new Map();
|
|
@@ -192,9 +169,6 @@ export function parsePersisted(text) {
|
|
|
192
169
|
const runtimePort = port(values.get(KEYS.runtimePort));
|
|
193
170
|
if (runtimePort)
|
|
194
171
|
out.runtimePort = runtimePort;
|
|
195
|
-
const adminPort = port(values.get(KEYS.adminPort));
|
|
196
|
-
if (adminPort)
|
|
197
|
-
out.adminPort = adminPort;
|
|
198
172
|
const studioPort = port(values.get(KEYS.studioPort));
|
|
199
173
|
if (studioPort)
|
|
200
174
|
out.studioPort = studioPort;
|
|
@@ -218,15 +192,6 @@ export function parsePersisted(text) {
|
|
|
218
192
|
const objectStoreSecretKey = values.get(KEYS.objectStoreSecretKey);
|
|
219
193
|
if (objectStoreSecretKey && /^[0-9a-f]{64}$/i.test(objectStoreSecretKey))
|
|
220
194
|
out.objectStoreSecretKey = objectStoreSecretKey;
|
|
221
|
-
const principals = values.get(KEYS.derivedPrincipals);
|
|
222
|
-
if (principals !== undefined) {
|
|
223
|
-
try {
|
|
224
|
-
out.derivedPrincipals = parseDerivedPrincipals(principals, `${KEYS.derivedPrincipals} in docker/.env`);
|
|
225
|
-
}
|
|
226
|
-
catch {
|
|
227
|
-
/* rewritten from the default on the next start */
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
195
|
const sandboxes = parseSandboxes(values);
|
|
231
196
|
if (sandboxes)
|
|
232
197
|
out.sandboxes = sandboxes;
|
|
@@ -13,8 +13,6 @@ export interface HostConfigFile {
|
|
|
13
13
|
hostId: string;
|
|
14
14
|
host: string;
|
|
15
15
|
port: number;
|
|
16
|
-
/** The operator listener's published port (the Admin API); absent on older Host roots. */
|
|
17
|
-
adminPort?: number;
|
|
18
16
|
runtimeVersion?: string;
|
|
19
17
|
[field: string]: unknown;
|
|
20
18
|
}
|
|
@@ -29,7 +27,6 @@ export declare function readHostConfig(paths: StackPaths): Promise<Record<string
|
|
|
29
27
|
*/
|
|
30
28
|
export declare function writeStackHostConfig(paths: StackPaths, input: {
|
|
31
29
|
port: number;
|
|
32
|
-
adminPort?: number;
|
|
33
30
|
runtimeVersion: string | undefined;
|
|
34
31
|
}): Promise<HostConfigFile>;
|
|
35
32
|
export declare function readAdminKey(paths: StackPaths): Promise<string | undefined>;
|
package/dist/stack/host-files.js
CHANGED
|
@@ -33,7 +33,6 @@ export async function ensureHostLayout(paths) {
|
|
|
33
33
|
paths.tmp,
|
|
34
34
|
paths.tenant,
|
|
35
35
|
...Object.values(paths.harness),
|
|
36
|
-
paths.plugins,
|
|
37
36
|
paths.keys,
|
|
38
37
|
paths.docker,
|
|
39
38
|
])
|
|
@@ -63,7 +62,8 @@ export async function readHostConfig(paths) {
|
|
|
63
62
|
* runtimeVersion when `runtimeVersion` is undefined; refuses a newer format.
|
|
64
63
|
*/
|
|
65
64
|
export async function writeStackHostConfig(paths, input) {
|
|
66
|
-
|
|
65
|
+
// An older Host root's operator port (`adminPort`) is dropped: there is no operator listener.
|
|
66
|
+
const { adminPort: _, ...existing } = (await readHostConfig(paths)) ?? {};
|
|
67
67
|
const format = existing.format;
|
|
68
68
|
if (format !== undefined &&
|
|
69
69
|
(typeof format !== "number" || !Number.isInteger(format) || format > KNOWN_FORMAT))
|
|
@@ -77,7 +77,6 @@ export async function writeStackHostConfig(paths, input) {
|
|
|
77
77
|
hostId,
|
|
78
78
|
host: STACK_CLIENT_HOST,
|
|
79
79
|
port: input.port,
|
|
80
|
-
...(input.adminPort === undefined ? {} : { adminPort: input.adminPort }),
|
|
81
80
|
...(input.runtimeVersion !== undefined ? { runtimeVersion: input.runtimeVersion } : {}),
|
|
82
81
|
};
|
|
83
82
|
await writeAtomic(paths.config, `${JSON.stringify(config, null, 2)}\n`);
|
package/dist/stack/index.d.ts
CHANGED
|
@@ -10,6 +10,12 @@ export declare function stackCommand(name: string, args: readonly string[], env:
|
|
|
10
10
|
/** Entry for `nylorun sandbox ls|rm`. */
|
|
11
11
|
export declare function sandboxCommand(args: readonly string[], env: Readonly<Record<string, string | undefined>>): Promise<number>;
|
|
12
12
|
export { sandboxUsage } from "./sandbox.js";
|
|
13
|
+
/** Entry for `nylorun mcp connect`. */
|
|
14
|
+
export declare function mcpCommand(args: readonly string[], env: Readonly<Record<string, string | undefined>>): Promise<number>;
|
|
15
|
+
export { mcpUsage } from "./mcp.js";
|
|
16
|
+
/** Entry for `nylorun key put|list|rm`. */
|
|
17
|
+
export declare function keyCommand(args: readonly string[], env: Readonly<Record<string, string | undefined>>): Promise<number>;
|
|
18
|
+
export { keyUsage } from "./keys.js";
|
|
13
19
|
/** `nylorun studio`, landing on `next` when given, else on the Tenant's page. */
|
|
14
20
|
export declare function studioCommand(args: readonly string[], env: Readonly<Record<string, string | undefined>>, options?: {
|
|
15
21
|
next?: string;
|
package/dist/stack/index.js
CHANGED
|
@@ -2,7 +2,9 @@ import { spawn } from "node:child_process";
|
|
|
2
2
|
import { createInterface } from "node:readline/promises";
|
|
3
3
|
import { runStackCommand, runStudioCommand } from "./commands.js";
|
|
4
4
|
import { spawnDocker } from "./docker.js";
|
|
5
|
+
import { keyCommand as runKeyCommand } from "./keys.js";
|
|
5
6
|
import { sandboxCommand as runSandboxCommand } from "./sandbox.js";
|
|
7
|
+
import { mcpCommand as runMcpCommand } from "./mcp.js";
|
|
6
8
|
import { pinnedVersion } from "./versions.js";
|
|
7
9
|
import { loopbackPorts } from "./ports.js";
|
|
8
10
|
export { ensureStack, isStackCommand, readStackStatus, stackUsage, studioLoginUrl, tenantStudioPath, STACK_SERVICES, } from "./commands.js";
|
|
@@ -20,7 +22,6 @@ function browserCommand(env) {
|
|
|
20
22
|
*/
|
|
21
23
|
const STACK_ENV_OWNED = [
|
|
22
24
|
"NYLORUN_TENANT_NAME",
|
|
23
|
-
"NYLORUN_DERIVED_PRINCIPALS",
|
|
24
25
|
"NYLORUN_STUDIO_ANALYTICS_ID",
|
|
25
26
|
];
|
|
26
27
|
/** Real dependencies: docker on PATH, global fetch, the terminal. */
|
|
@@ -85,6 +86,16 @@ export async function sandboxCommand(args, env) {
|
|
|
85
86
|
return await runSandboxCommand(defaultStackDeps(env), args);
|
|
86
87
|
}
|
|
87
88
|
export { sandboxUsage } from "./sandbox.js";
|
|
89
|
+
/** Entry for `nylorun mcp connect`. */
|
|
90
|
+
export async function mcpCommand(args, env) {
|
|
91
|
+
return await runMcpCommand(defaultStackDeps(env), args);
|
|
92
|
+
}
|
|
93
|
+
export { mcpUsage } from "./mcp.js";
|
|
94
|
+
/** Entry for `nylorun key put|list|rm`. */
|
|
95
|
+
export async function keyCommand(args, env) {
|
|
96
|
+
return await runKeyCommand(defaultStackDeps(env), args);
|
|
97
|
+
}
|
|
98
|
+
export { keyUsage } from "./keys.js";
|
|
88
99
|
/** `nylorun studio`, landing on `next` when given, else on the Tenant's page. */
|
|
89
100
|
export async function studioCommand(args, env, options = {}) {
|
|
90
101
|
return await runStudioCommand(args, defaultStackDeps(env), options);
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type StackDeps } from "./commands.js";
|
|
2
|
+
export declare const keyUsage = " key put <id> [--management] [--tenant <name>]\n create the Tenant's application key <id> (--management: a management key), or\n rotate it (the old key stops working); prints the key once\n key list [--tenant <name>] [--json] the Tenant's keys: id, role, when issued (never the keys)\n key rm <id> [--tenant <name>] delete key <id>: it stops working at once";
|
|
3
|
+
/** `nylorun key <put|list|rm> ...` */
|
|
4
|
+
export declare function keyCommand(deps: StackDeps, args: readonly string[]): Promise<number>;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `nylorun key put | list | rm`: the running local Tenant's keys, through `nylorun-operate` in its
|
|
3
|
+
* runtime container. Revocable application keys by name, for app servers and other clients, and
|
|
4
|
+
* management keys (`--management`), which only this machine issues; none of these starts the
|
|
5
|
+
* Tenant.
|
|
6
|
+
*/
|
|
7
|
+
import { CliError } from "../errors.js";
|
|
8
|
+
import { parseStackFlags, runningOperate } from "./commands.js";
|
|
9
|
+
import { deleteOperatorKey, listOperatorKeys, putOperatorKey } from "./operator-keys.js";
|
|
10
|
+
export const keyUsage = ` key put <id> [--management] [--tenant <name>]
|
|
11
|
+
create the Tenant's application key <id> (--management: a management key), or
|
|
12
|
+
rotate it (the old key stops working); prints the key once
|
|
13
|
+
key list [--tenant <name>] [--json] the Tenant's keys: id, role, when issued (never the keys)
|
|
14
|
+
key rm <id> [--tenant <name>] delete key <id>: it stops working at once`;
|
|
15
|
+
const usageError = (message) => new CliError(message, 2);
|
|
16
|
+
async function put(deps, args) {
|
|
17
|
+
const usage = "nylorun key put <id> [--management] [--tenant <name>]";
|
|
18
|
+
const flags = parseStackFlags(args, { booleans: ["--management"], values: ["--tenant"] }, usage);
|
|
19
|
+
if (flags.rest.length !== 1)
|
|
20
|
+
throw usageError(`Usage: ${usage}`);
|
|
21
|
+
const id = flags.rest[0];
|
|
22
|
+
const name = flags.values.get("--tenant");
|
|
23
|
+
const running = await runningOperate(deps, name === undefined ? {} : { name });
|
|
24
|
+
const key = await putOperatorKey(running, id, flags.booleans.has("--management") ? "management" : "application");
|
|
25
|
+
// The key alone on stdout, for scripts; it is not shown again.
|
|
26
|
+
deps.out(key.key);
|
|
27
|
+
deps.err(`${key.rotated ? "Rotated" : "Created"} ${key.role} key ${key.id} on Tenant ${running.name}${key.rotated ? " (the previous key no longer works)" : ""}. Store it now: it is not shown again.`);
|
|
28
|
+
return 0;
|
|
29
|
+
}
|
|
30
|
+
async function list(deps, args) {
|
|
31
|
+
const usage = "nylorun key list [--tenant <name>] [--json]";
|
|
32
|
+
const flags = parseStackFlags(args, { booleans: ["--json"], values: ["--tenant"] }, usage);
|
|
33
|
+
if (flags.rest.length)
|
|
34
|
+
throw usageError(`Usage: ${usage}`);
|
|
35
|
+
const name = flags.values.get("--tenant");
|
|
36
|
+
const keys = await listOperatorKeys(await runningOperate(deps, name === undefined ? {} : { name }));
|
|
37
|
+
if (flags.booleans.has("--json")) {
|
|
38
|
+
deps.out(JSON.stringify(keys, null, 2));
|
|
39
|
+
return 0;
|
|
40
|
+
}
|
|
41
|
+
const rows = [["ID", "ROLE", "CREATED"], ...keys.map((key) => [key.id, key.role, key.createdAt])];
|
|
42
|
+
const widths = rows[0].map((_, column) => Math.max(...rows.map((row) => row[column].length)));
|
|
43
|
+
for (const row of rows)
|
|
44
|
+
deps.out(row
|
|
45
|
+
.map((cell, column) => (column === row.length - 1 ? cell : cell.padEnd(widths[column])))
|
|
46
|
+
.join(" "));
|
|
47
|
+
return 0;
|
|
48
|
+
}
|
|
49
|
+
async function rm(deps, args) {
|
|
50
|
+
const usage = "nylorun key rm <id> [--tenant <name>]";
|
|
51
|
+
const flags = parseStackFlags(args, { values: ["--tenant"] }, usage);
|
|
52
|
+
if (flags.rest.length !== 1)
|
|
53
|
+
throw usageError(`Usage: ${usage}`);
|
|
54
|
+
const id = flags.rest[0];
|
|
55
|
+
const name = flags.values.get("--tenant");
|
|
56
|
+
const running = await runningOperate(deps, name === undefined ? {} : { name });
|
|
57
|
+
if (!(await deleteOperatorKey(running, id))) {
|
|
58
|
+
deps.err(`No key ${id} on Tenant ${running.name}.`);
|
|
59
|
+
return 1;
|
|
60
|
+
}
|
|
61
|
+
deps.out(`Deleted key ${id}: it no longer works.`);
|
|
62
|
+
return 0;
|
|
63
|
+
}
|
|
64
|
+
/** `nylorun key <put|list|rm> ...` */
|
|
65
|
+
export async function keyCommand(deps, args) {
|
|
66
|
+
const [sub, ...rest] = args;
|
|
67
|
+
if (sub === "put")
|
|
68
|
+
return put(deps, rest);
|
|
69
|
+
if (sub === "list" || sub === "ls")
|
|
70
|
+
return list(deps, rest);
|
|
71
|
+
if (sub === "rm" || sub === "delete")
|
|
72
|
+
return rm(deps, rest);
|
|
73
|
+
throw usageError(`Usage:\n${keyUsage}`);
|
|
74
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type StackDeps } from "./commands.js";
|
|
2
|
+
export declare const mcpUsage = " mcp connect <url> --server <name> [--vault <id>] [--client-id <id>] [--tenant <name>] [--no-open]\n sign the Tenant in to a remote MCP server with OAuth; the credential goes to the\n installation vault mcp (or --vault), which sessions attach";
|
|
3
|
+
/** The installation vault `connect` uses unless `--vault` names one. */
|
|
4
|
+
export declare const MCP_VAULT_NAME = "mcp";
|
|
5
|
+
/** How long `connect` waits for the browser sign-in: the Runtime keeps it for ten minutes. */
|
|
6
|
+
export declare const CONNECT_TIMEOUT_MS: number;
|
|
7
|
+
/** `nylorun mcp <connect> ...` */
|
|
8
|
+
export declare function mcpCommand(deps: StackDeps, args: readonly string[]): Promise<number>;
|