nylorun 0.13.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 (76) hide show
  1. package/CHANGELOG.md +153 -0
  2. package/README.md +255 -166
  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 +10 -4
  9. package/dist/client/doctor.js +28 -20
  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/client/mcp.d.ts +11 -0
  17. package/dist/{stack → client}/mcp.js +40 -26
  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/errors.d.ts +1 -1
  36. package/dist/errors.js +1 -1
  37. package/dist/nylo.js +20 -4
  38. package/dist/sandbox/cluster-file.d.ts +1 -1
  39. package/dist/sandbox/commands.d.ts +1 -1
  40. package/dist/sandbox/commands.js +7 -7
  41. package/dist/sandbox/manifests.d.ts +1 -1
  42. package/dist/sandbox/manifests.js +1 -1
  43. package/dist/sandbox/probe.d.ts +1 -1
  44. package/dist/stack/commands.d.ts +9 -4
  45. package/dist/stack/commands.js +22 -26
  46. package/dist/stack/compose-file.d.ts +1 -1
  47. package/dist/stack/compose-file.js +22 -13
  48. package/dist/stack/env-file.d.ts +2 -2
  49. package/dist/stack/env-file.js +2 -2
  50. package/dist/stack/images.d.ts +1 -1
  51. package/dist/stack/images.js +1 -1
  52. package/dist/stack/index.d.ts +1 -10
  53. package/dist/stack/index.js +3 -19
  54. package/dist/stack/keys.d.ts +2 -2
  55. package/dist/stack/keys.js +14 -11
  56. package/dist/stack/paths.d.ts +1 -1
  57. package/dist/stack/prepare.d.ts +1 -1
  58. package/dist/stack/stacks.js +1 -1
  59. package/dist/stack/versions.d.ts +2 -2
  60. package/dist/stack/versions.js +3 -3
  61. package/dist/telemetry.d.ts +2 -2
  62. package/dist/telemetry.js +4 -4
  63. package/package.json +10 -9
  64. package/dist/client/access/commands.d.ts +0 -8
  65. package/dist/client/access/commands.js +0 -33
  66. package/dist/client/cli.d.ts +0 -2
  67. package/dist/client/cli.js +0 -106
  68. package/dist/client/installation/commands.d.ts +0 -7
  69. package/dist/client/installation/commands.js +0 -80
  70. package/dist/client/project/connection.d.ts +0 -36
  71. package/dist/client/project/connection.js +0 -80
  72. package/dist/client/project/env.d.ts +0 -3
  73. package/dist/client/project/env.js +0 -19
  74. package/dist/stack/mcp.d.ts +0 -9
  75. package/dist/stack/sandbox.d.ts +0 -4
  76. package/dist/stack/sandbox.js +0 -106
@@ -0,0 +1,65 @@
1
+ /**
2
+ * The installation a client command acts on. `--tenant <name>` names a local Tenant. Without it,
3
+ * `NYLORUN_RUNTIME_URL` with the key the API needs names a remote installation:
4
+ * `NYLORUN_MANAGEMENT_KEY` for the Management API (`nylorun tenant`), `NYLORUN_SERVER_KEY` or an
5
+ * identity provider's token in `NYLORUN_TOKEN` for the Runtime API (`NYLORUN_RUNTIME_URL` alone is
6
+ * an app's, as for `createAdmin`). Otherwise the local
7
+ * Tenant the Project link names, else the default one, while it runs (`runningTenantApi`: the
8
+ * Project's keys while they authenticate, else the Host root's own).
9
+ */
10
+ import { createManagementClient } from "@nylorun/admin";
11
+ import { CliError } from "../errors.js";
12
+ import { runningTenantApi } from "../stack/commands.js";
13
+ function variable(env, name) {
14
+ const value = env[name]?.trim();
15
+ return value ? value : undefined;
16
+ }
17
+ /** The remote installation the environment names for `api`, if it names one. */
18
+ export function remoteConnection(env, api) {
19
+ const url = variable(env, "NYLORUN_RUNTIME_URL");
20
+ const managementKey = variable(env, "NYLORUN_MANAGEMENT_KEY");
21
+ const applicationKey = variable(env, "NYLORUN_SERVER_KEY");
22
+ const token = variable(env, "NYLORUN_TOKEN");
23
+ if (!url || (api === "management" ? !managementKey : !applicationKey && !token))
24
+ return undefined;
25
+ return {
26
+ label: url,
27
+ url: url.replace(/\/$/, ""),
28
+ local: false,
29
+ ...(applicationKey ? { applicationKey } : {}),
30
+ ...(managementKey ? { managementKey } : {}),
31
+ // A token is a person's: it wins over the key for the Runtime API.
32
+ ...(token && api === "runtime" ? { token } : {}),
33
+ };
34
+ }
35
+ /** The installation to act on for `api` (module comment). */
36
+ export async function connect(deps, api, tenant) {
37
+ if (tenant === undefined) {
38
+ const remote = remoteConnection(deps.env, api);
39
+ if (remote)
40
+ return remote;
41
+ }
42
+ const local = await runningTenantApi(deps, tenant === undefined ? {} : { name: tenant });
43
+ return {
44
+ label: `Tenant ${local.name}`,
45
+ url: local.runtimeUrl,
46
+ local: true,
47
+ tenant: local.name,
48
+ applicationKey: local.applicationKey,
49
+ managementKey: local.managementKey,
50
+ };
51
+ }
52
+ /** The Management API client of `connection`, through `deps.fetch`. */
53
+ export function managementClient(deps, connection) {
54
+ if (!connection.managementKey)
55
+ throw new CliError(`No management key for ${connection.label}: set NYLORUN_MANAGEMENT_KEY, or on the Runtime's machine run "nylorun tenant keys put <id> --management".`, 1);
56
+ return createManagementClient({
57
+ url: connection.url,
58
+ key: connection.managementKey,
59
+ fetch: (input, init) => deps.fetch(input instanceof Request ? input.url : String(input), init),
60
+ });
61
+ }
62
+ /** `error`'s message, ending in one full stop. */
63
+ export function messageOf(error) {
64
+ return (error instanceof Error ? error.message : String(error)).replace(/\.?$/, ".");
65
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * `nylorun tenant`: the Management API (`/v1/tenant/*`) of the installation's one Tenant, with a
3
+ * management key (`target.ts` picks the installation). Issuing a management key is the one
4
+ * exception: only the Runtime's machine does it, through `nylorun-operate` (`stack/keys.ts`).
5
+ */
6
+ import type { ManagementClient } from "@nylorun/admin";
7
+ import { type StackDeps } from "../stack/commands.js";
8
+ import { type Connection } from "./target.js";
9
+ export declare const tenantUsage = "nylorun tenant <command>\n\nThe Management API of the installation's one Tenant, with a management key: the local Tenant\n--tenant names (else the linked project's, else the default one), or the installation that\nNYLORUN_RUNTIME_URL and NYLORUN_MANAGEMENT_KEY name.\n\n reset [--sessions|--environments|--all] [--yes] [--tenant <name>]\n clear the Tenant's sessions, Environments or all its data\n (the Project link and keys stay)\n keys put <id> [--management] [--tenant <name>]\n create the Tenant's application key <id> (--management: a\n management key, on the Runtime's machine only), or rotate it\n (the old key stops working); prints the key once\n keys list [--tenant <name>] [--json]\n the Tenant's keys: id, role, when issued (never the keys)\n keys rm <id> [--tenant <name>] delete key <id>: it stops working at once\n signing-keys list [--tenant <name>]\n the Tenant's token signing keys\n signing-keys rotate [--force] [--tenant <name>]\n rotate; --force ends outstanding links and run tokens\n signing-keys revoke <kid> [--tenant <name>]\n revoke a previous or standby key\n models catalog [--tenant <name>] [--json]\n every provider and model the Runtime knows\n models providers [--tenant <name>] [--json]\n the providers with a credential, and the one in use\n models get [--tenant <name>] [--json]\n the Tenant's model\n models set [--tenant <name>] sign in to a model provider and set the Tenant's model\n models set --provider <id> --model <id> [--base-url <url>] [--tenant <name>]\n the same with an API key piped in on stdin (CI)\n models select <provider> [--model <id>] [--tenant <name>]\n use a provider that has a credential (default: its model)\n usage [--scope tenant|agent|turn] [--id <id>] [--period day|month|total] [--tenant <name>]\n what the model calls used and cost (JSON)\n calls [--after <cursor>] [--limit <n>] [--tenant <name>]\n every recorded model call, one JSON line each, until\n caught up; prints the cursor to resume from on stderr\n budgets [get | put <file|->] [--tenant <name>]\n the model spend caps; put replaces them all\n tool-policy [get | put <file|->] [--tenant <name>]\n the Tool Gate's rules; put replaces them all\n settings sandbox [get | put <file|->] [--tenant <name>]\n the Environment settings: limits, stop grace, placement\n settings artifacts [get | put <file|->] [--tenant <name>]\n the artifact store's limits\n coverage --agent <id> [--environment <id>] [--tenant <name>] [--json]\n which secret of the Environment each of the agent's MCP\n servers and HTTP tools would get\n mcp inspect <url> [--server <name>] [--environment <id>] [--sse] [--tenant <name>] [--json]\n list a remote MCP server's tools, with Environment <id>'s\n credential for <url> (none without it): model names, schema\n sizes, renames, or that it needs a person's sign-in (the\n Runtime calls no tool)\n\nA put reads a JSON body from a file, or from stdin for -, and replaces the whole document; what\nbudgets, tool-policy and settings artifacts get print, put takes back. An API key is read from\nstdin, never from the arguments.";
10
+ /** The Management API client of the installation `--tenant` (or the environment) names. */
11
+ export declare function tenantClient(deps: StackDeps, tenant: string | undefined): Promise<{
12
+ connection: Connection;
13
+ admin: ManagementClient;
14
+ }>;
15
+ /**
16
+ * `nylorun status` for an installation the environment names (`NYLORUN_RUNTIME_URL` and
17
+ * `NYLORUN_MANAGEMENT_KEY`): the Tenant, its checks and counts. A local Tenant's status is the
18
+ * stack's (`stack/commands.ts`).
19
+ */
20
+ export declare function remoteStatus(deps: StackDeps, args: readonly string[]): Promise<number>;
21
+ /** `nylorun tenant <group> ...` */
22
+ export declare function tenantCommand(deps: StackDeps, args: readonly string[]): Promise<number>;
@@ -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/errors.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- /** Exit codes are part of both commands' contract; see nylorun/README.md ("Exit codes"). */
1
+ /** Exit codes are part of both commands' contract; see cli/nylorun/README.md ("Exit codes"). */
2
2
  export declare class CliError extends Error {
3
3
  readonly exitCode: number;
4
4
  constructor(message: string, exitCode?: number);
package/dist/errors.js CHANGED
@@ -1,4 +1,4 @@
1
- /** Exit codes are part of both commands' contract; see nylorun/README.md ("Exit codes"). */
1
+ /** Exit codes are part of both commands' contract; see cli/nylorun/README.md ("Exit codes"). */
2
2
  export class CliError extends Error {
3
3
  exitCode;
4
4
  constructor(message, exitCode = 1) {
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>;