nylorun 0.14.0-beta → 0.15.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 (71) hide show
  1. package/CHANGELOG.md +105 -0
  2. package/README.md +226 -144
  3. package/dist/cli.js +141 -47
  4. package/dist/client/agents.d.ts +6 -0
  5. package/dist/client/agents.js +148 -0
  6. package/dist/client/artifacts.d.ts +4 -0
  7. package/dist/client/artifacts.js +210 -0
  8. package/dist/client/doctor.d.ts +7 -2
  9. package/dist/client/doctor.js +14 -13
  10. package/dist/client/environment-manifests.d.ts +10 -0
  11. package/dist/client/environment-manifests.js +173 -0
  12. package/dist/client/environments.d.ts +4 -0
  13. package/dist/client/environments.js +295 -0
  14. package/dist/client/io.d.ts +31 -0
  15. package/dist/client/io.js +72 -0
  16. package/dist/{stack → client}/mcp.d.ts +2 -2
  17. package/dist/{stack → client}/mcp.js +14 -12
  18. package/dist/client/model/pi-ai.d.ts +3 -3
  19. package/dist/client/model/pi-ai.js +4 -4
  20. package/dist/client/models.d.ts +13 -0
  21. package/dist/client/models.js +203 -0
  22. package/dist/client/runtime.d.ts +40 -0
  23. package/dist/client/runtime.js +134 -0
  24. package/dist/client/sessions.d.ts +4 -0
  25. package/dist/client/sessions.js +295 -0
  26. package/dist/client/settings.d.ts +12 -0
  27. package/dist/client/settings.js +103 -0
  28. package/dist/client/signing-keys.d.ts +3 -0
  29. package/dist/client/signing-keys.js +32 -0
  30. package/dist/client/target.d.ts +33 -0
  31. package/dist/client/target.js +65 -0
  32. package/dist/client/tenant.d.ts +22 -0
  33. package/dist/client/tenant.js +176 -0
  34. package/dist/doctor.js +3 -3
  35. package/dist/nylo.js +20 -4
  36. package/dist/sandbox/cluster-file.d.ts +1 -1
  37. package/dist/sandbox/commands.d.ts +1 -1
  38. package/dist/sandbox/commands.js +7 -7
  39. package/dist/sandbox/manifests.d.ts +1 -1
  40. package/dist/sandbox/manifests.js +1 -1
  41. package/dist/sandbox/probe.d.ts +1 -1
  42. package/dist/stack/commands.d.ts +9 -4
  43. package/dist/stack/commands.js +22 -26
  44. package/dist/stack/compose-file.d.ts +1 -1
  45. package/dist/stack/compose-file.js +12 -12
  46. package/dist/stack/env-file.d.ts +2 -2
  47. package/dist/stack/env-file.js +2 -2
  48. package/dist/stack/images.d.ts +1 -1
  49. package/dist/stack/images.js +1 -1
  50. package/dist/stack/index.d.ts +1 -10
  51. package/dist/stack/index.js +3 -19
  52. package/dist/stack/keys.d.ts +2 -2
  53. package/dist/stack/keys.js +14 -11
  54. package/dist/stack/paths.d.ts +1 -1
  55. package/dist/stack/prepare.d.ts +1 -1
  56. package/dist/stack/stacks.js +1 -1
  57. package/dist/telemetry.d.ts +2 -2
  58. package/dist/telemetry.js +4 -4
  59. package/package.json +6 -5
  60. package/dist/client/access/commands.d.ts +0 -8
  61. package/dist/client/access/commands.js +0 -33
  62. package/dist/client/cli.d.ts +0 -2
  63. package/dist/client/cli.js +0 -106
  64. package/dist/client/installation/commands.d.ts +0 -7
  65. package/dist/client/installation/commands.js +0 -82
  66. package/dist/client/project/connection.d.ts +0 -36
  67. package/dist/client/project/connection.js +0 -80
  68. package/dist/client/project/env.d.ts +0 -3
  69. package/dist/client/project/env.js +0 -19
  70. package/dist/stack/sandbox.d.ts +0 -4
  71. package/dist/stack/sandbox.js +0 -107
@@ -0,0 +1,176 @@
1
+ import { CliError } from "../errors.js";
2
+ import { parseStackFlags } from "../stack/commands.js";
3
+ import { keyCommand, keyUsage } from "../stack/keys.js";
4
+ import { printJson, printTable } from "./io.js";
5
+ import { mcpCommand, mcpUsage } from "./mcp.js";
6
+ import { callsCommand, modelsCommand, modelsUsage, usageCommand, usageUsage } from "./models.js";
7
+ import { budgetsCommand, coverageCommand, settingsCommand, settingsUsage, toolPolicyCommand, } from "./settings.js";
8
+ import { signingKeysCommand, signingKeysUsage } from "./signing-keys.js";
9
+ import { connect, managementClient, messageOf, remoteConnection } from "./target.js";
10
+ export const tenantUsage = `nylorun tenant <command>
11
+
12
+ The Management API of the installation's one Tenant, with a management key: the local Tenant
13
+ --tenant names (else the linked project's, else the default one), or the installation that
14
+ NYLORUN_RUNTIME_URL and NYLORUN_MANAGEMENT_KEY name.
15
+
16
+ reset [--sessions|--environments|--all] [--yes] [--tenant <name>]
17
+ clear the Tenant's sessions, Environments or all its data
18
+ (the Project link and keys stay)
19
+ ${keyUsage}
20
+ ${signingKeysUsage}
21
+ ${modelsUsage}
22
+ ${usageUsage}
23
+ ${settingsUsage}
24
+ ${mcpUsage}
25
+
26
+ A put reads a JSON body from a file, or from stdin for -, and replaces the whole document; what
27
+ budgets, tool-policy and settings artifacts get print, put takes back. An API key is read from
28
+ stdin, never from the arguments.`;
29
+ const usageError = (message) => new CliError(message, 2);
30
+ /** The Management API client of the installation `--tenant` (or the environment) names. */
31
+ export async function tenantClient(deps, tenant) {
32
+ const connection = await connect(deps, "management", tenant);
33
+ return { connection, admin: managementClient(deps, connection) };
34
+ }
35
+ /**
36
+ * `nylorun status` for an installation the environment names (`NYLORUN_RUNTIME_URL` and
37
+ * `NYLORUN_MANAGEMENT_KEY`): the Tenant, its checks and counts. A local Tenant's status is the
38
+ * stack's (`stack/commands.ts`).
39
+ */
40
+ export async function remoteStatus(deps, args) {
41
+ const usage = "nylorun status [--tenant <name>] [--json]";
42
+ const flags = parseStackFlags(args, { booleans: ["--json"] }, usage);
43
+ if (flags.rest.length)
44
+ throw usageError(`Usage: ${usage}`);
45
+ const { connection, admin } = await tenantClient(deps, undefined);
46
+ let body;
47
+ try {
48
+ body = await admin.tenant.status();
49
+ }
50
+ catch (error) {
51
+ throw new CliError(`${messageOf(error)} The installation at ${connection.url} did not answer.`, 1);
52
+ }
53
+ if (flags.booleans.has("--json")) {
54
+ deps.out(JSON.stringify(body, null, 2));
55
+ return 0;
56
+ }
57
+ deps.out(`${body.tenant.name} ${body.tenant.id}`);
58
+ deps.out(`runtime ${connection.url}`);
59
+ deps.out(`path ${body.path}`);
60
+ deps.out(`checks ${Object.entries(body.checks)
61
+ .map(([k, v]) => `${k}=${v ? "ok" : "fail"}`)
62
+ .join(" ")}`);
63
+ deps.out(`counts sessions=${body.counts.sessions} running=${body.counts.runningSessions} uncertain=${body.counts.uncertainEffects}`);
64
+ deps.out(`sandbox ${body.sandbox.backend ?? "none"}`);
65
+ return 0;
66
+ }
67
+ const RESET_USAGE = "nylorun tenant reset [--sessions|--environments|--all] [--yes] [--tenant <name>]";
68
+ const SCOPES = { "--sessions": "sessions", "--environments": "environments", "--all": "all" };
69
+ /** `nylorun tenant reset`; `--all` asks first. */
70
+ async function reset(deps, args) {
71
+ const flags = parseStackFlags(args, { booleans: ["--yes", ...Object.keys(SCOPES)], values: ["--tenant"], aliases: { "-y": "--yes" } }, RESET_USAGE);
72
+ if (flags.rest.length)
73
+ throw usageError(`Usage: ${RESET_USAGE}`);
74
+ const chosen = Object.keys(SCOPES).filter((flag) => flags.booleans.has(flag));
75
+ if (chosen.length > 1)
76
+ throw usageError("Pass only one of --sessions, --environments, --all.");
77
+ const scope = chosen.length ? SCOPES[chosen[0]] : "sessions";
78
+ const { connection, admin } = await tenantClient(deps, flags.values.get("--tenant"));
79
+ if (scope === "all" && !flags.booleans.has("--yes")) {
80
+ if (!deps.confirm)
81
+ throw usageError("Confirmation required; pass --yes for non-interactive use.");
82
+ if (!(await deps.confirm(`Reset ALL data of ${connection.label}? The Project link and keys are kept. [y/N] `))) {
83
+ deps.err("Cancelled.");
84
+ return 1;
85
+ }
86
+ }
87
+ try {
88
+ await admin.tenant.reset({ scope, activeWork: "drain" });
89
+ }
90
+ catch (error) {
91
+ throw new CliError(`Tenant reset failed: ${messageOf(error)}`, 1);
92
+ }
93
+ deps.out(`Reset ${connection.label} (${scope}).`);
94
+ return 0;
95
+ }
96
+ /**
97
+ * `nylorun tenant keys`: through the Management API on an installation the environment names
98
+ * (application keys only), else on the local Tenant through `nylorun-operate`.
99
+ */
100
+ async function keys(deps, args) {
101
+ if (args.includes("--tenant") || !remoteConnection(deps.env, "management"))
102
+ return keyCommand(deps, args);
103
+ const [verb, ...rest] = args;
104
+ const { admin, connection } = await tenantClient(deps, undefined);
105
+ if (verb === "put") {
106
+ const usage = "nylorun tenant keys put <id>";
107
+ const flags = parseStackFlags(rest, { booleans: ["--management"] }, usage);
108
+ if (flags.booleans.has("--management"))
109
+ throw new CliError("Management keys are issued only on the Runtime's machine: run nylorun tenant keys put <id> --management there.", 2);
110
+ if (flags.rest.length !== 1)
111
+ throw usageError(`Usage: ${usage}`);
112
+ const key = await admin.keys.put(flags.rest[0]);
113
+ deps.out(key.key);
114
+ deps.err(`${key.rotated ? "Rotated" : "Created"} application key ${key.id} on ${connection.label}${key.rotated ? " (the previous key no longer works)" : ""}. Store it now: it is not shown again.`);
115
+ return 0;
116
+ }
117
+ if (verb === "list" || verb === "ls") {
118
+ const usage = "nylorun tenant keys list [--json]";
119
+ const flags = parseStackFlags(rest, { booleans: ["--json"] }, usage);
120
+ if (flags.rest.length)
121
+ throw usageError(`Usage: ${usage}`);
122
+ const list = await admin.keys.list();
123
+ if (flags.booleans.has("--json"))
124
+ printJson(deps, list);
125
+ else
126
+ printTable(deps, [["ID", "ROLE", "CREATED"], ...list.map((key) => [key.id, key.role, key.createdAt])]);
127
+ return 0;
128
+ }
129
+ if (verb === "rm" || verb === "delete") {
130
+ const usage = "nylorun tenant keys rm <id>";
131
+ const flags = parseStackFlags(rest, {}, usage);
132
+ if (flags.rest.length !== 1)
133
+ throw usageError(`Usage: ${usage}`);
134
+ const id = flags.rest[0];
135
+ if (!(await admin.keys.delete(id))) {
136
+ deps.err(`No key ${id} on ${connection.label}.`);
137
+ return 1;
138
+ }
139
+ deps.out(`Deleted key ${id}: it no longer works.`);
140
+ return 0;
141
+ }
142
+ throw usageError(`Usage:\n${keyUsage}`);
143
+ }
144
+ /** `nylorun tenant <group> ...` */
145
+ export async function tenantCommand(deps, args) {
146
+ const [group, ...rest] = args;
147
+ if (group === "--help" || group === "-h") {
148
+ deps.out(tenantUsage);
149
+ return 0;
150
+ }
151
+ if (!group)
152
+ throw usageError(tenantUsage);
153
+ if (group === "reset")
154
+ return reset(deps, rest);
155
+ if (group === "keys" || group === "key")
156
+ return keys(deps, rest);
157
+ if (group === "signing-keys")
158
+ return signingKeysCommand(deps, rest);
159
+ if (group === "models" || group === "model")
160
+ return modelsCommand(deps, rest);
161
+ if (group === "usage")
162
+ return usageCommand(deps, rest);
163
+ if (group === "calls")
164
+ return callsCommand(deps, rest);
165
+ if (group === "budgets")
166
+ return budgetsCommand(deps, rest);
167
+ if (group === "tool-policy")
168
+ return toolPolicyCommand(deps, rest);
169
+ if (group === "settings")
170
+ return settingsCommand(deps, rest);
171
+ if (group === "coverage")
172
+ return coverageCommand(deps, rest);
173
+ if (group === "mcp")
174
+ return mcpCommand(deps, rest);
175
+ throw usageError(`Unknown tenant command ${group}.\n${tenantUsage}`);
176
+ }
package/dist/doctor.js CHANGED
@@ -75,7 +75,7 @@ export async function doctorStack(options) {
75
75
  ? `- ${local.name} stopped (Compose project ${local.project}): run nylorun up`
76
76
  : local.runtime.healthy
77
77
  ? `✓ ${local.name} running (Compose project ${local.project})`
78
- : `✗ ${local.name} running, but the Runtime does not answer: see nylorun status and nylorun logs runtime`,
78
+ : `✗ ${local.name} running, but the Runtime does not answer: see nylorun status and nylorun local logs runtime`,
79
79
  ]);
80
80
  if (local.state === "running") {
81
81
  rows.push([
@@ -88,7 +88,7 @@ export async function doctorStack(options) {
88
88
  "gateway",
89
89
  local.gateway.healthy
90
90
  ? `✓ ${local.gateway.state} · combined packing (runtime: core,loop; gateway: gates)`
91
- : `✗ ${local.gateway.state}: model calls fail; see nylorun logs gateway`,
91
+ : `✗ ${local.gateway.state}: model calls fail; see nylorun local logs gateway`,
92
92
  ]);
93
93
  rows.push([
94
94
  "harness",
@@ -96,7 +96,7 @@ export async function doctorStack(options) {
96
96
  ? "- in-process (NYLORUN_HARNESS=in-process in .env)"
97
97
  : local.harness.healthy
98
98
  ? `✓ ${local.harness.state} · remote (agent turns, MCP servers, workspaces)`
99
- : `✗ ${local.harness.state}: turns do not run; see nylorun logs harness`,
99
+ : `✗ ${local.harness.state}: turns do not run; see nylorun local logs harness`,
100
100
  ]);
101
101
  if (local.tenant)
102
102
  rows.push([
package/dist/nylo.js CHANGED
@@ -1,9 +1,25 @@
1
1
  #!/usr/bin/env node
2
2
  import "./baseline.js";
3
3
  import { runCommand } from "./command.js";
4
- // `nylo`, the Runtime client (client/). `nylorun`'s entry never imports it, so `npx nylorun start`
5
- // loads none of it, nor @nylorun/admin.
4
+ import { CliError } from "./errors.js";
5
+ /**
6
+ * `nylo` became part of `nylorun`. For one release this command names the `nylorun` command that
7
+ * replaces each of its own and exits 2; a later release removes it.
8
+ */
9
+ const REPLACEMENTS = {
10
+ status: "nylorun status",
11
+ reset: "nylorun tenant reset",
12
+ access: "nylorun tenant signing-keys list|rotate|revoke",
13
+ configure: "nylorun tenant models set",
14
+ doctor: "nylorun doctor sandbox",
15
+ env: 'nothing: the SDKs read the Project link themselves; for a process outside the project, "nylorun tenant keys put <id>" and the Runtime URL "nylorun status" prints',
16
+ };
17
+ function nyloMessage(argv) {
18
+ const replacement = REPLACEMENTS[argv[0] ?? ""];
19
+ return replacement
20
+ ? `nylo is part of nylorun now: nylo ${argv[0]} is ${replacement}.`
21
+ : "nylo is part of nylorun now: run nylorun --help.";
22
+ }
6
23
  runCommand(async () => {
7
- const { main } = await import("./client/cli.js");
8
- await main(process.argv.slice(2));
24
+ throw new CliError(nyloMessage(process.argv.slice(2)), 2);
9
25
  });
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * `<Host root>/sandboxes/`: what the sandboxes service mounts read-only. `cluster.json`
3
- * records the cluster `nylorun sandbox enable` installed into; `token` is the
3
+ * records the cluster `nylorun local sandbox enable` installed into; `token` is the
4
4
  * ServiceAccount token (0600). Only the sandboxes container reads them: the runtime
5
5
  * container sees an empty mount there.
6
6
  */
@@ -37,5 +37,5 @@ export declare function installCluster(deps: SandboxDeps, input: {
37
37
  egress: number;
38
38
  };
39
39
  }): Promise<InstallResult>;
40
- /** `nylorun sandbox <enable|disable|status>`. */
40
+ /** `nylorun local sandbox <enable|disable|status>`. */
41
41
  export declare function runSandboxCommand(args: readonly string[], deps: SandboxDeps): Promise<number>;
@@ -16,7 +16,7 @@ export const sandboxUsage = ` sandbox enable --context <name> [--tenant <name>]
16
16
  stop the sandboxes service and forget the cluster
17
17
  sandbox status [--tenant <name>] [--json]
18
18
  the cluster, the sandboxes service's readiness and what it reports`;
19
- const ENABLE_USAGE = "nylorun sandbox enable --context <name> [--tenant <name>] [--host-address <ip>] [--bind-address <ip>] [--no-pull]";
19
+ const ENABLE_USAGE = "nylorun local sandbox enable --context <name> [--tenant <name>] [--host-address <ip>] [--bind-address <ip>] [--no-pull]";
20
20
  /** The default workload image (D36), pre-pulled with the Runtime image. */
21
21
  export const DEFAULT_SANDBOX_IMAGE = "python:3.13-slim";
22
22
  /** Preferred host ports for the Harness API, gates and egress (pods reach them). */
@@ -141,7 +141,7 @@ async function enable(deps, args) {
141
141
  throw usageError(`Usage: ${ENABLE_USAGE}`);
142
142
  const context = flags.values.get("--context");
143
143
  if (!context)
144
- throw usageError(`nylorun sandbox enable needs --context <name>: the kubeconfig context to run pods in (never the current one implicitly). Usage: ${ENABLE_USAGE}`);
144
+ throw usageError(`nylorun local sandbox enable needs --context <name>: the kubeconfig context to run pods in (never the current one implicitly). Usage: ${ENABLE_USAGE}`);
145
145
  const hostAddress = flags.values.get("--host-address");
146
146
  const bindAddress = flags.values.get("--bind-address");
147
147
  if (hostAddress)
@@ -191,7 +191,7 @@ async function enable(deps, args) {
191
191
  await restartTenant(stack, { name: tenant.name, sandboxes: settings });
192
192
  const ready = await stack.docker.stream(tenant.compose("up", "--detach", "--wait", "--wait-timeout", "120", "sandboxes"));
193
193
  if (ready !== 0)
194
- throw new CliError(`The sandboxes service did not become ready (image ${images.sandboxes}). See "nylorun logs sandboxes" and "nylorun sandbox status".`, 7);
194
+ throw new CliError(`The sandboxes service did not become ready (image ${images.sandboxes}). See "nylorun local logs sandboxes" and "nylorun local sandbox status".`, 7);
195
195
  const c = installed.cluster;
196
196
  stack.out(`Sandboxes ${tenant.name} enabled on ${c.context} (namespace ${c.namespace}, agent-sandbox ${c.controllerVersion})`);
197
197
  stack.out(`Pods reach ${c.hostAddress} on ports ${c.ports.harness}, ${c.ports.gates}, ${c.ports.egress}; NetworkPolicy enforced (probed ${c.networkPolicy.probedAt})`);
@@ -199,7 +199,7 @@ async function enable(deps, args) {
199
199
  }
200
200
  async function disable(deps, args) {
201
201
  const { stack } = deps;
202
- const usage = "nylorun sandbox disable [--tenant <name>] [--delete-namespace]";
202
+ const usage = "nylorun local sandbox disable [--tenant <name>] [--delete-namespace]";
203
203
  const flags = parseStackFlags(args, { booleans: ["--delete-namespace"], values: ["--tenant"] }, usage);
204
204
  if (flags.rest.length)
205
205
  throw usageError(`Usage: ${usage}`);
@@ -229,7 +229,7 @@ async function disable(deps, args) {
229
229
  const INFO_SCRIPT = "fetch(process.env.NYLORUN_SANDBOXES_URL+'/v1/info',{headers:{authorization:'Bearer '+process.env.NYLORUN_SANDBOXES_TOKEN},signal:AbortSignal.timeout(5000)}).then(async r=>{process.stdout.write(await r.text());process.exit(r.ok?0:1)},()=>process.exit(1))";
230
230
  async function status(deps, args) {
231
231
  const { stack } = deps;
232
- const usage = "nylorun sandbox status [--tenant <name>] [--json]";
232
+ const usage = "nylorun local sandbox status [--tenant <name>] [--json]";
233
233
  const flags = parseStackFlags(args, { booleans: ["--json"], values: ["--tenant"] }, usage);
234
234
  if (flags.rest.length)
235
235
  throw usageError(`Usage: ${usage}`);
@@ -240,7 +240,7 @@ async function status(deps, args) {
240
240
  if (flags.booleans.has("--json"))
241
241
  stack.out(JSON.stringify({ enabled: false }, null, 2));
242
242
  else
243
- stack.out(`Sandboxes are not enabled for Tenant ${tenant.name}. Run "nylorun sandbox enable --context <name>".`);
243
+ stack.out(`Sandboxes are not enabled for Tenant ${tenant.name}. Run "nylorun local sandbox enable --context <name>".`);
244
244
  return 3;
245
245
  }
246
246
  await dockerPreflight(stack.docker);
@@ -271,7 +271,7 @@ const COMMANDS = {
271
271
  disable,
272
272
  status,
273
273
  };
274
- /** `nylorun sandbox <enable|disable|status>`. */
274
+ /** `nylorun local sandbox <enable|disable|status>`. */
275
275
  export async function runSandboxCommand(args, deps) {
276
276
  const [name, ...rest] = args;
277
277
  const command = name === undefined ? undefined : COMMANDS[name];
@@ -1,5 +1,5 @@
1
1
  /**
2
- * What `nylorun sandbox enable` installs into a cluster. The agent-sandbox controller is
2
+ * What `nylorun local sandbox enable` installs into a cluster. The agent-sandbox controller is
3
3
  * pinned (D32, Experiment 2): v1.0.5, API agents.x-k8s.io/v1beta1, its release manifest
4
4
  * verified by sha256 before it is applied. It is never upgraded or uninstalled here.
5
5
  */
@@ -1,6 +1,6 @@
1
1
  import { createHash } from "node:crypto";
2
2
  /**
3
- * What `nylorun sandbox enable` installs into a cluster. The agent-sandbox controller is
3
+ * What `nylorun local sandbox enable` installs into a cluster. The agent-sandbox controller is
4
4
  * pinned (D32, Experiment 2): v1.0.5, API agents.x-k8s.io/v1beta1, its release manifest
5
5
  * verified by sha256 before it is applied. It is never upgraded or uninstalled here.
6
6
  */
@@ -2,7 +2,7 @@ import type { DockerRunner } from "../stack/docker.js";
2
2
  import type { PortProbe } from "../stack/ports.js";
3
3
  import type { Kube } from "./kubectl.js";
4
4
  /**
5
- * The NetworkPolicy probe `nylorun sandbox enable` runs before it trusts a cluster (D32), in
5
+ * The NetworkPolicy probe `nylorun local sandbox enable` runs before it trusts a cluster (D32), in
6
6
  * a throwaway namespace `nylorun-sbx-probe-<random>`:
7
7
  *
8
8
  * - a `control` pod (no policy) must reach a `peer` pod and the allowed host port, which
@@ -5,7 +5,7 @@ import type { PortProbe } from "./ports.js";
5
5
  import { type FetchLike } from "./studio-login.js";
6
6
  import { type OperateEndpoint } from "./operator-keys.js";
7
7
  export declare const STACK_SERVICES: readonly ["postgres", "restate", "s2-lite", "rustfs", "gateway", "runtime", "harness", "studio"];
8
- export declare const stackUsage: string;
8
+ export declare const stackUsage = " up|start [--tenant <name>] [--no-link] [--no-studio] [--allow-downgrade] [--studio-embed-origin <origin>]... [--studio-embed-origin-reset] [--restate-ui]\n start the project's Tenant, creating it and the Project link (.nylorun/link.json,\n credentials.json) on the first run; print the Runtime and Studio URLs (it opens no\n browser). --tenant attaches to (or creates) a named Tenant; --no-link\n starts the default Tenant (or --tenant's) without linking the current directory;\n --restate-ui (or NYLORUN_RESTATE_UI=1) publishes Restate's UI on loopback for debugging\n down|stop [--tenant <name> | --all] stop the Tenant's containers (--all: every Tenant's); keep volumes\n status [--tenant <name>] [--json] the Tenant, its id, services, endpoints and Runtime health\n studio [--tenant <name>] [--no-open]\n sign a browser in to Studio on the Tenant; --no-open prints the login URL; start the Tenant if it is stopped";
9
9
  export interface StackDeps {
10
10
  /** Environment snapshot (NYLORUN_HOME, NYLORUN_TENANT, image overrides, NYLORUN_COMPOSE_PROJECT). */
11
11
  env: Readonly<Record<string, string | undefined>>;
@@ -22,6 +22,11 @@ export interface StackDeps {
22
22
  confirm?(question: string): Promise<boolean>;
23
23
  /** A developer is at a terminal. */
24
24
  interactive?: boolean;
25
+ /** Standard input, for a body or a secret piped in; undefined when there is none. */
26
+ stdin?: {
27
+ isTTY: boolean;
28
+ text(): Promise<string>;
29
+ };
25
30
  /** Open `url` in a browser; false when no browser could be started. */
26
31
  openBrowser(url: string): Promise<boolean>;
27
32
  /** Is this process id alive? (launcher-managed Runtime detection) */
@@ -137,7 +142,7 @@ export interface StackEndpoints {
137
142
  /** This call started the Runtime (it was not running before). */
138
143
  started: boolean;
139
144
  }
140
- /** The running Tenant's APIs and their keys (`nylorun sandbox`). */
145
+ /** The running Tenant's APIs and their keys (`nylorun local sandbox`). */
141
146
  export interface TenantApi {
142
147
  /** The Tenant's name. */
143
148
  name: string;
@@ -179,7 +184,7 @@ export declare function ensureStack(deps: StackDeps, options: {
179
184
  studio: boolean;
180
185
  name?: string;
181
186
  }): Promise<StackEndpoints>;
182
- /** A started Tenant as `nylorun sandbox` sees it. */
187
+ /** A started Tenant as `nylorun local sandbox` sees it. */
183
188
  export interface SelectedTenant {
184
189
  name: string;
185
190
  paths: StackPaths;
@@ -187,7 +192,7 @@ export interface SelectedTenant {
187
192
  /** `docker compose` arguments for this Tenant's project and files. */
188
193
  compose(...args: string[]): string[];
189
194
  }
190
- /** The Tenant `nylorun sandbox` acts on; it must have been started once. */
195
+ /** The Tenant `nylorun local sandbox` acts on; it must have been started once. */
191
196
  export declare function selectTenant(deps: StackDeps, options?: {
192
197
  name?: string;
193
198
  }): Promise<SelectedTenant>;
@@ -38,13 +38,8 @@ export const stackUsage = ` up|start [--tenant <name>] [--no-link] [--no-studio
38
38
  --restate-ui (or NYLORUN_RESTATE_UI=1) publishes Restate's UI on loopback for debugging
39
39
  down|stop [--tenant <name> | --all] stop the Tenant's containers (--all: every Tenant's); keep volumes
40
40
  status [--tenant <name>] [--json] the Tenant, its id, services, endpoints and Runtime health
41
- logs [service] [--tenant <name>] [-f] [--tail <n>]
42
- container logs (${STACK_SERVICES.join(", ")})
43
41
  studio [--tenant <name>] [--no-open]
44
- sign a browser in to Studio on the Tenant; --no-open prints the login URL; start the Tenant if it is stopped
45
- reset [--tenant <name>] [--yes] delete the Tenant's data (volumes, tenant/ and vault key); the next start creates it anew
46
- ls [--json] the Tenants on this machine, with their memory in use
47
- delete <tenant> --yes remove a Tenant: containers, volumes and its Host root, with the vault key (KEK)`;
42
+ sign a browser in to Studio on the Tenant; --no-open prints the login URL; start the Tenant if it is stopped`;
48
43
  const usageError = (message) => new CliError(message, 2);
49
44
  /** The Compose project of Tenant `name`: `nylorun-<name>`, or `NYLORUN_COMPOSE_PROJECT`. */
50
45
  export function stackProject(env, name) {
@@ -166,7 +161,8 @@ export function parseStackFlags(args, allowed, usage) {
166
161
  for (let index = 0; index < args.length; index += 1) {
167
162
  const raw = args[index];
168
163
  const arg = allowed.aliases?.[raw] ?? raw;
169
- if (!arg.startsWith("-")) {
164
+ // `-` alone is an argument: standard input.
165
+ if (arg === "-" || !arg.startsWith("-")) {
170
166
  rest.push(arg);
171
167
  continue;
172
168
  }
@@ -224,7 +220,7 @@ async function waitForHealth(ctx, runtimeUrl, hostId) {
224
220
  return health;
225
221
  }
226
222
  if (Date.now() > deadline)
227
- throw new CliError(`The Runtime did not answer ${runtimeUrl}/health. See "nylorun logs runtime".`, 7);
223
+ throw new CliError(`The Runtime did not answer ${runtimeUrl}/health. See "nylorun local logs runtime".`, 7);
228
224
  await sleep(ctx.deps.pollMs ?? 500);
229
225
  }
230
226
  }
@@ -284,7 +280,7 @@ function tenantCauseMessage(ctx, tenant) {
284
280
  ? ` This nylorun pins Runtime ${ctx.deps.runtimeVersion}, older than the Tenant's database: update nylorun (npx nylorun@latest start).`
285
281
  : "";
286
282
  const message = tenant.message ? `: ${tenant.message.replace(/\.?$/, ".")}` : ".";
287
- return `Tenant ${ctx.name} is unavailable (${tenant.cause})${message}${hint} See "nylorun logs runtime".`;
283
+ return `Tenant ${ctx.name} is unavailable (${tenant.cause})${message}${hint} See "nylorun local logs runtime".`;
288
284
  }
289
285
  /**
290
286
  * Wait until the Tenant is open (`/ready`'s `tenant` check): the Runtime creates it on the
@@ -304,7 +300,7 @@ async function waitForTenant(ctx, runtimeUrl) {
304
300
  if (!open && tenant?.cause)
305
301
  throw new CliError(tenantCauseMessage(ctx, tenant), 7);
306
302
  if (late)
307
- throw new CliError(`Tenant ${ctx.name} did not open (${runtimeUrl}/ready: ${open ? "open, but nylorun-operate status did not answer" : "not open"})${tenant?.message ? `: ${tenant.message.replace(/\.$/, "")}` : ""}. See "nylorun status" and "nylorun logs runtime".`, 7);
303
+ throw new CliError(`Tenant ${ctx.name} did not open (${runtimeUrl}/ready: ${open ? "open, but nylorun-operate status did not answer" : "not open"})${tenant?.message ? `: ${tenant.message.replace(/\.$/, "")}` : ""}. See "nylorun status" and "nylorun local logs runtime".`, 7);
308
304
  }
309
305
  await sleep(ctx.deps.pollMs ?? 500);
310
306
  }
@@ -394,7 +390,7 @@ async function bringUp(ctx, options) {
394
390
  await refuseDowngrade(ctx, options.allowDowngrade ?? false);
395
391
  const legacy = await oldVolumes(deps.docker, ctx.project);
396
392
  if (legacy.old.length && !legacy.current)
397
- throw new CliError(`Tenant ${ctx.name} was created by nylorun 0.5; its data is in the old volumes ${legacy.old.join(", ")}. Run "nylorun reset --tenant ${ctx.name}" to start it fresh; that also removes the old volumes (or drop them yourself with "docker volume rm ${legacy.old.join(" ")}").`, 3);
393
+ throw new CliError(`Tenant ${ctx.name} was created by nylorun 0.5; its data is in the old volumes ${legacy.old.join(", ")}. Run "nylorun local reset --tenant ${ctx.name}" to start it fresh; that also removes the old volumes (or drop them yourself with "docker volume rm ${legacy.old.join(" ")}").`, 3);
398
394
  const base = nylorunRoot(deps);
399
395
  const telemetry = await readTelemetry(base);
400
396
  const analytics = telemetryDecision(deps.env, telemetry).enabled;
@@ -437,21 +433,21 @@ async function bringUp(ctx, options) {
437
433
  const tenant = await operateStatus(ctx);
438
434
  if (tenant?.cause)
439
435
  throw new CliError(tenantCauseMessage(ctx, tenant), 7);
440
- throw new CliError(`docker compose up failed (exit ${up}). See "nylorun logs runtime", "nylorun logs gateway", "nylorun logs harness" and "nylorun status".`, 7);
436
+ throw new CliError(`docker compose up failed (exit ${up}). See "nylorun local logs runtime", "nylorun local logs gateway", "nylorun local logs harness" and "nylorun status".`, 7);
441
437
  }
442
438
  await waitForHealth(ctx, runtimeUrl, prepared.host.hostId);
443
439
  // Without --wait: a cluster that is down must not fail the start; sessions refuse pods.
444
440
  if (prepared.env.sandboxes) {
445
441
  const sandboxes = await deps.docker.stream(composeArgs(ctx, "up", "--detach", "sandboxes"));
446
442
  if (sandboxes !== 0)
447
- deps.err(`Warning: the sandboxes service did not start. See "nylorun logs sandboxes".`);
443
+ deps.err(`Warning: the sandboxes service did not start. See "nylorun local logs sandboxes".`);
448
444
  }
449
445
  let studioStarted = false;
450
446
  if (options.studio) {
451
447
  const studio = await deps.docker.stream(composeArgs(ctx, "up", "--detach", "--wait", "--wait-timeout", "120", "studio"));
452
448
  studioStarted = studio === 0;
453
449
  if (!studioStarted)
454
- deps.err(`Warning: Studio did not start (image ${prepared.env.studioImage}). The Runtime is up; see "nylorun logs studio".`);
450
+ deps.err(`Warning: Studio did not start (image ${prepared.env.studioImage}). The Runtime is up; see "nylorun local logs studio".`);
455
451
  }
456
452
  return {
457
453
  runtimeUrl,
@@ -561,7 +557,7 @@ async function linkProject(ctx, started, tenantId) {
561
557
  deps.err(`Seeded the Tenant from .env: ${set.join(", ")}.`);
562
558
  }
563
559
  catch (error) {
564
- deps.err(`Warning: could not seed the Tenant from .env (${error instanceof Error ? error.message : String(error)}). Set the model in Studio or with "npx -p nylorun nylo configure".`);
560
+ deps.err(`Warning: could not seed the Tenant from .env (${error instanceof Error ? error.message : String(error)}). Set the model in Studio or with "npx nylorun tenant models set".`);
565
561
  }
566
562
  }
567
563
  const START_USAGE = "nylorun start [--tenant <name>] [--no-link] [--no-studio] [--allow-downgrade] [--studio-embed-origin <origin>]... [--studio-embed-origin-reset] [--restate-ui]";
@@ -777,14 +773,14 @@ async function status(deps, args) {
777
773
  out(`Embeds ${result.studio.embedOrigins.join(" ")} (may show Studio in a frame)`);
778
774
  out(`Gateway ${result.gateway.state} (the Model Gate; model calls fail while it is down)`);
779
775
  out(result.harness.mode === "remote"
780
- ? `Harness ${result.harness.state}, remote${result.harness.connected === undefined ? "" : `, ${result.harness.connected} connected`} (agent turns, MCP servers and workspaces; "nylorun logs harness")`
776
+ ? `Harness ${result.harness.state}, remote${result.harness.connected === undefined ? "" : `, ${result.harness.connected} connected`} (agent turns, MCP servers and workspaces; "nylorun local logs harness")`
781
777
  : `Harness in-process (NYLORUN_HARNESS=in-process in .env: turns run in the runtime container)`);
782
778
  out(result.restate.url
783
779
  ? `Restate UI ${result.restate.url} (unauthenticated; published by --restate-ui)`
784
780
  : `Restate UI not published (nylorun start --restate-ui)`);
785
781
  const sandboxes = result.services.find((s) => s.service === "sandboxes");
786
782
  if (sandboxes)
787
- out(`Sandboxes ${[sandboxes.state, sandboxes.health].filter(Boolean).join(", ")} (see "nylorun sandbox status")`);
783
+ out(`Sandboxes ${[sandboxes.state, sandboxes.health].filter(Boolean).join(", ")} (see "nylorun local sandbox status")`);
788
784
  out(`Services ${STACK_SERVICES.map((name) => {
789
785
  const service = result.services.find((s) => s.service === name);
790
786
  const state = service
@@ -796,7 +792,7 @@ async function status(deps, args) {
796
792
  return result.runtime.healthy ? 0 : 3;
797
793
  }
798
794
  async function logs(deps, args) {
799
- const usage = `nylorun logs [${STACK_SERVICES.join("|")}] [--tenant <name>] [-f] [--tail <n>]`;
795
+ const usage = `nylorun local logs [${STACK_SERVICES.join("|")}] [--tenant <name>] [-f] [--tail <n>]`;
800
796
  const flags = parseStackFlags(args, { booleans: ["--follow"], values: ["--tail", "--tenant"], aliases: { "-f": "--follow" } }, usage);
801
797
  if (flags.rest.length > 1)
802
798
  throw usageError(`Usage: ${usage}`);
@@ -812,7 +808,7 @@ async function logs(deps, args) {
812
808
  return await deps.docker.stream(composeArgs(ctx, "logs", ...(flags.booleans.has("--follow") ? ["--follow"] : []), ...(tail !== undefined ? ["--tail", tail] : []), ...(service ? [service] : [])));
813
809
  }
814
810
  async function reset(deps, args) {
815
- const usage = "nylorun reset [--tenant <name>] [--yes]";
811
+ const usage = "nylorun local reset [--tenant <name>] [--yes]";
816
812
  const flags = parseStackFlags(args, { booleans: ["--yes"], values: ["--tenant"], aliases: { "-y": "--yes" } }, usage);
817
813
  if (flags.rest.length)
818
814
  throw usageError(`Usage: ${usage}`);
@@ -821,7 +817,7 @@ async function reset(deps, args) {
821
817
  if (!flags.booleans.has("--yes")) {
822
818
  const question = `Delete Tenant ${ctx.name}'s volumes (Compose project ${ctx.project}), its Tenant directory ${paths.tenant} and its vault key ${paths.vaultKey}? Its data is lost, and the next start creates the Tenant anew, with a new id. [y/N] `;
823
819
  if (!deps.confirm)
824
- throw usageError(`nylorun reset deletes all of Tenant ${ctx.name}'s data; pass --yes to confirm when not in a terminal.`);
820
+ throw usageError(`nylorun local reset deletes all of Tenant ${ctx.name}'s data; pass --yes to confirm when not in a terminal.`);
825
821
  if (!(await deps.confirm(question))) {
826
822
  deps.err("Reset cancelled.");
827
823
  return 1;
@@ -856,7 +852,7 @@ async function composeProjects(docker) {
856
852
  }
857
853
  }
858
854
  async function ls(deps, args) {
859
- const usage = "nylorun ls [--json]";
855
+ const usage = "nylorun local ls [--json]";
860
856
  const flags = parseStackFlags(args, { booleans: ["--json"] }, usage);
861
857
  if (flags.rest.length)
862
858
  throw usageError(`Usage: ${usage}`);
@@ -912,7 +908,7 @@ async function ls(deps, args) {
912
908
  return 0;
913
909
  }
914
910
  async function deleteStack(deps, args) {
915
- const usage = "nylorun delete <tenant> --yes";
911
+ const usage = "nylorun local delete <tenant> --yes";
916
912
  const flags = parseStackFlags(args, { booleans: ["--yes"], aliases: { "-y": "--yes" } }, usage);
917
913
  const [name, ...extra] = flags.rest;
918
914
  if (name === undefined || extra.length)
@@ -921,9 +917,9 @@ async function deleteStack(deps, args) {
921
917
  const base = nylorunRoot(deps);
922
918
  const ctx = { deps, project: stackProject(deps.env, name), paths: stackPaths(tenantRoot(base, name)) };
923
919
  if (!existsSync(ctx.paths.root))
924
- throw new CliError(`No Tenant ${name} under ${tenantsDir(base)}. See "nylorun ls".`, 3);
920
+ throw new CliError(`No Tenant ${name} under ${tenantsDir(base)}. See "nylorun local ls".`, 3);
925
921
  if (!flags.booleans.has("--yes"))
926
- throw usageError(`nylorun delete removes Tenant ${name}: its containers, volumes and Host root ${ctx.paths.root}, with its vault key (KEK) and all its data. This cannot be undone; pass --yes to confirm.`);
922
+ throw usageError(`nylorun local delete removes Tenant ${name}: its containers, volumes and Host root ${ctx.paths.root}, with its vault key (KEK) and all its data. This cannot be undone; pass --yes to confirm.`);
927
923
  await dockerPreflight(deps.docker);
928
924
  const files = existsSync(ctx.paths.compose) && existsSync(ctx.paths.env);
929
925
  await composeDown(ctx, files
@@ -1051,7 +1047,7 @@ export async function runningTenantApi(deps, options = {}) {
1051
1047
  export async function ensureStack(deps, options) {
1052
1048
  return await ensureSelected(await selectStack(deps, options.name === undefined ? {} : { name: options.name }), options);
1053
1049
  }
1054
- /** The Tenant `nylorun sandbox` acts on; it must have been started once. */
1050
+ /** The Tenant `nylorun local sandbox` acts on; it must have been started once. */
1055
1051
  export async function selectTenant(deps, options = {}) {
1056
1052
  await tidyMachine(deps);
1057
1053
  const ctx = await selectStack(deps, options);
@@ -1115,7 +1111,7 @@ async function studio(deps, args, options = {}) {
1115
1111
  if (running.started)
1116
1112
  deps.out(`Runtime ${running.runtimeUrl}`);
1117
1113
  if (!running.studioUp)
1118
- throw new CliError(`Studio did not start. See "nylorun logs studio".`, 7);
1114
+ throw new CliError(`Studio did not start. See "nylorun local logs studio".`, 7);
1119
1115
  // Studio serves the one Tenant; the link's Tenant id stands in while it is opening.
1120
1116
  let next = options.next;
1121
1117
  if (next === undefined) {
@@ -41,7 +41,7 @@
41
41
  * gateway receive it (NYLORUN_OBJECT_STORE_*). The runtime creates the bucket at boot and
42
42
  * reaches the store through its `s3` BlobStore.
43
43
  *
44
- * With `sandboxes` (after `nylorun sandbox enable`, F7.2) the `sandboxes` service runs the
44
+ * With `sandboxes` (after `nylorun local sandbox enable`, F7.2) the `sandboxes` service runs the
45
45
  * agent-sandbox driver: the only container holding the cluster credentials
46
46
  * (`<Host root>/sandboxes`, read-only), not published, reached by the runtime alone with
47
47
  * NYLORUN_SANDBOXES_TOKEN. The runtime gets an empty read-only mount over that directory.