nylorun 0.12.2-beta → 0.14.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 +74 -0
- package/README.md +142 -37
- package/dist/cli.js +13 -18
- package/dist/client/access/commands.d.ts +8 -0
- package/dist/client/access/commands.js +33 -0
- package/dist/client/cli.d.ts +2 -0
- package/dist/client/cli.js +106 -0
- package/dist/client/doctor.d.ts +26 -0
- package/dist/client/doctor.js +72 -0
- package/dist/client/installation/commands.d.ts +7 -0
- package/dist/client/installation/commands.js +82 -0
- package/dist/client/model/configure.d.ts +58 -0
- package/dist/client/model/configure.js +294 -0
- package/dist/client/model/host-model.d.ts +4 -0
- package/dist/client/model/host-model.js +13 -0
- package/dist/client/model/pi-ai.d.ts +26 -0
- package/dist/client/model/pi-ai.js +104 -0
- package/dist/client/project/connection.d.ts +36 -0
- package/dist/client/project/connection.js +80 -0
- package/dist/client/project/env.d.ts +3 -0
- package/dist/client/project/env.js +19 -0
- package/dist/command.d.ts +8 -0
- package/dist/command.js +23 -0
- package/dist/errors.d.ts +1 -1
- package/dist/errors.js +1 -1
- package/dist/nylo.d.ts +2 -0
- package/dist/nylo.js +9 -0
- package/dist/project/link.d.ts +2 -1
- package/dist/project/link.js +5 -2
- package/dist/stack/commands.js +1 -1
- package/dist/stack/compose-file.js +10 -1
- package/dist/stack/mcp.d.ts +5 -3
- package/dist/stack/mcp.js +30 -18
- package/dist/stack/sandbox.d.ts +1 -1
- package/dist/stack/sandbox.js +23 -22
- package/dist/stack/versions.d.ts +2 -2
- package/dist/stack/versions.js +3 -3
- package/package.json +13 -9
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type ManagementClient } from "@nylorun/admin";
|
|
2
|
+
import { type ProjectCredentials, type ProjectLink as LinkFile } from "@nylorun/core/project";
|
|
3
|
+
/**
|
|
4
|
+
* The Project link (format 3), which `nylorun start` writes and `nylo` only reads with
|
|
5
|
+
* `@nylorun/core/project`'s reader. `tenantId` is information: the installation serves one
|
|
6
|
+
* Tenant, so nothing selects it.
|
|
7
|
+
*/
|
|
8
|
+
export type ProjectLink = LinkFile & {
|
|
9
|
+
format: 3;
|
|
10
|
+
};
|
|
11
|
+
/** The Project's link; one of an older nylorun (formats 0 to 2) is refused. */
|
|
12
|
+
export declare function readLink(projectRoot: string): Promise<ProjectLink | undefined>;
|
|
13
|
+
/**
|
|
14
|
+
* The Project's credentials (mode 0600), which `nylorun start` writes beside the link: the
|
|
15
|
+
* application key and its principal, and the management key and its principal when it issued
|
|
16
|
+
* one. A format 0 file's legacy `executors` map is ignored.
|
|
17
|
+
*/
|
|
18
|
+
export declare function readCredentials(projectRoot: string): Promise<ProjectCredentials | undefined>;
|
|
19
|
+
/** The installation `nylo` acts on: a Runtime URL, an application key and a management key. */
|
|
20
|
+
export interface LinkedConnection {
|
|
21
|
+
url: string;
|
|
22
|
+
/** The application key (Runtime API); absent when only a management key is set. */
|
|
23
|
+
key?: string;
|
|
24
|
+
/** The management key (Management API), when there is one. */
|
|
25
|
+
managementKey?: string;
|
|
26
|
+
/** The Project link it came from, when it came from one. */
|
|
27
|
+
link?: ProjectLink;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* The Project's link and credentials, else `NYLORUN_RUNTIME_URL` with `NYLORUN_SERVER_KEY`, or
|
|
31
|
+
* `NYLORUN_MANAGEMENT_KEY`, or both; `NYLORUN_MANAGEMENT_KEY` also stands in for a Project
|
|
32
|
+
* credentials file without one. The installation serves one Tenant, so nothing names it.
|
|
33
|
+
*/
|
|
34
|
+
export declare function linkedConnection(projectRoot: string, env?: Readonly<Record<string, string | undefined>>): Promise<LinkedConnection>;
|
|
35
|
+
/** The Management API client of `connection`; refused without a management key. */
|
|
36
|
+
export declare function managementClient(connection: LinkedConnection): ManagementClient;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { chmod } from "node:fs/promises";
|
|
2
|
+
import { createManagementClient } from "@nylorun/admin";
|
|
3
|
+
import { ProjectFileError, projectCredentialsPath, projectLinkPath, readProjectCredentials, readProjectLink, } from "@nylorun/core/project";
|
|
4
|
+
import { CliError } from "../../errors.js";
|
|
5
|
+
/** The Project's link; one of an older nylorun (formats 0 to 2) is refused. */
|
|
6
|
+
export async function readLink(projectRoot) {
|
|
7
|
+
const path = projectLinkPath(projectRoot);
|
|
8
|
+
let link;
|
|
9
|
+
try {
|
|
10
|
+
link = readProjectLink(projectRoot);
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
if (!(error instanceof ProjectFileError))
|
|
14
|
+
throw error;
|
|
15
|
+
throw new CliError(error.reason === "newer"
|
|
16
|
+
? `Project link at ${path} has an unsupported format. Upgrade nylorun.`
|
|
17
|
+
: `Invalid Project link at ${path}. Remove .nylorun/link.json and run "npx nylorun start".`, 1);
|
|
18
|
+
}
|
|
19
|
+
if (link === undefined)
|
|
20
|
+
return undefined;
|
|
21
|
+
if (link.format !== 3)
|
|
22
|
+
throw new CliError(`The Project link at ${path} is from an older nylorun. Run "npx nylorun start" in this project to link it again.`, 1);
|
|
23
|
+
return { ...link, format: 3 };
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The Project's credentials (mode 0600), which `nylorun start` writes beside the link: the
|
|
27
|
+
* application key and its principal, and the management key and its principal when it issued
|
|
28
|
+
* one. A format 0 file's legacy `executors` map is ignored.
|
|
29
|
+
*/
|
|
30
|
+
export async function readCredentials(projectRoot) {
|
|
31
|
+
const path = projectCredentialsPath(projectRoot);
|
|
32
|
+
let credentials;
|
|
33
|
+
try {
|
|
34
|
+
credentials = readProjectCredentials(projectRoot);
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
if (!(error instanceof ProjectFileError))
|
|
38
|
+
throw error;
|
|
39
|
+
throw new CliError(error.reason === "newer"
|
|
40
|
+
? `Project credentials at ${path} have an unsupported format. Upgrade nylorun.`
|
|
41
|
+
: `Invalid Project credentials at ${path}. Remove .nylorun/credentials.json and run "npx nylorun start".`, 1);
|
|
42
|
+
}
|
|
43
|
+
if (credentials)
|
|
44
|
+
await chmod(path, 0o600);
|
|
45
|
+
return credentials;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* The Project's link and credentials, else `NYLORUN_RUNTIME_URL` with `NYLORUN_SERVER_KEY`, or
|
|
49
|
+
* `NYLORUN_MANAGEMENT_KEY`, or both; `NYLORUN_MANAGEMENT_KEY` also stands in for a Project
|
|
50
|
+
* credentials file without one. The installation serves one Tenant, so nothing names it.
|
|
51
|
+
*/
|
|
52
|
+
export async function linkedConnection(projectRoot, env = process.env) {
|
|
53
|
+
const link = await readLink(projectRoot);
|
|
54
|
+
const credentials = await readCredentials(projectRoot);
|
|
55
|
+
const managementKey = env.NYLORUN_MANAGEMENT_KEY?.trim();
|
|
56
|
+
if (link && credentials) {
|
|
57
|
+
const management = credentials.managementKey ?? managementKey;
|
|
58
|
+
return {
|
|
59
|
+
url: link.hostUrl,
|
|
60
|
+
key: credentials.applicationKey,
|
|
61
|
+
...(management ? { managementKey: management } : {}),
|
|
62
|
+
link,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
const url = env.NYLORUN_RUNTIME_URL?.trim();
|
|
66
|
+
const key = env.NYLORUN_SERVER_KEY?.trim();
|
|
67
|
+
if (url && (key || managementKey))
|
|
68
|
+
return {
|
|
69
|
+
url: url.replace(/\/$/, ""),
|
|
70
|
+
...(key ? { key } : {}),
|
|
71
|
+
...(managementKey ? { managementKey } : {}),
|
|
72
|
+
};
|
|
73
|
+
throw new CliError(`No Project link in ${projectRoot}. Run "npx nylorun start" in this project to start its Tenant and link it, or set NYLORUN_RUNTIME_URL and NYLORUN_SERVER_KEY (or NYLORUN_MANAGEMENT_KEY).`, 1);
|
|
74
|
+
}
|
|
75
|
+
/** The Management API client of `connection`; refused without a management key. */
|
|
76
|
+
export function managementClient(connection) {
|
|
77
|
+
if (!connection.managementKey)
|
|
78
|
+
throw new CliError(`No management key for the Tenant at ${connection.url}: run npx nylorun start, or set NYLORUN_MANAGEMENT_KEY.`, 1);
|
|
79
|
+
return createManagementClient({ url: connection.url, key: connection.managementKey });
|
|
80
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { findProjectRoot } from "@nylorun/core/project";
|
|
2
|
+
import { readCredentials, readLink } from "./connection.js";
|
|
3
|
+
/** Two `export` lines for `nylo env` (was `nylorun status --env`, F2-7). */
|
|
4
|
+
export async function printLinkedEnvExports(projectRoot = process.cwd()) {
|
|
5
|
+
const root = findProjectRoot(projectRoot) ?? projectRoot;
|
|
6
|
+
const link = await readLink(root);
|
|
7
|
+
const credentials = await readCredentials(root);
|
|
8
|
+
if (!link || !credentials) {
|
|
9
|
+
console.log('# No Project link in this directory. Run "npx nylorun start" in this project to start its Tenant and link it.');
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
console.log(`export NYLORUN_RUNTIME_URL=${shellQuote(link.hostUrl)}`);
|
|
13
|
+
console.log(`export NYLORUN_SERVER_KEY=${shellQuote(credentials.applicationKey)}`);
|
|
14
|
+
}
|
|
15
|
+
export function shellQuote(value) {
|
|
16
|
+
if (/^[A-Za-z0-9_./:-]+$/.test(value))
|
|
17
|
+
return value;
|
|
18
|
+
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
19
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Both commands refuse native Windows before acting; WSL2 runs them. */
|
|
2
|
+
export declare function refuseNativeWindows(): void;
|
|
3
|
+
/**
|
|
4
|
+
* Run a command (`nylorun` or `nylo`) and exit once stdout and stderr are flushed: with
|
|
5
|
+
* `process.exitCode` (0 when unset), or after printing a failure's message with its
|
|
6
|
+
* `CliError` exit code (else 1).
|
|
7
|
+
*/
|
|
8
|
+
export declare function runCommand(main: () => Promise<void>): void;
|
package/dist/command.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { CliError } from "./errors.js";
|
|
2
|
+
/** Both commands refuse native Windows before acting; WSL2 runs them. */
|
|
3
|
+
export function refuseNativeWindows() {
|
|
4
|
+
if (process.platform === "win32")
|
|
5
|
+
throw new CliError("Nylorun does not run on native Windows. Use WSL2: install Node 24 and Docker (Docker Desktop's WSL integration) inside your WSL distribution and run nylorun there (https://learn.microsoft.com/windows/wsl/install).", 1);
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Run a command (`nylorun` or `nylo`) and exit once stdout and stderr are flushed: with
|
|
9
|
+
* `process.exitCode` (0 when unset), or after printing a failure's message with its
|
|
10
|
+
* `CliError` exit code (else 1).
|
|
11
|
+
*/
|
|
12
|
+
export function runCommand(main) {
|
|
13
|
+
void main().then(() => finish(process.exitCode === undefined ? 0 : Number(process.exitCode)), (error) => {
|
|
14
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
15
|
+
return finish(error instanceof CliError ? error.exitCode : 1);
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
async function finish(code) {
|
|
19
|
+
process.exitCode = code;
|
|
20
|
+
for (const stream of [process.stdout, process.stderr])
|
|
21
|
+
await new Promise((resolve) => stream.write("", () => resolve()));
|
|
22
|
+
process.exit(code);
|
|
23
|
+
}
|
package/dist/errors.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** Exit codes are part of
|
|
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
package/dist/nylo.d.ts
ADDED
package/dist/nylo.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import "./baseline.js";
|
|
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.
|
|
6
|
+
runCommand(async () => {
|
|
7
|
+
const { main } = await import("./client/cli.js");
|
|
8
|
+
await main(process.argv.slice(2));
|
|
9
|
+
});
|
package/dist/project/link.d.ts
CHANGED
|
@@ -31,7 +31,8 @@ export interface KeyCredentials {
|
|
|
31
31
|
export declare function readProjectCredentials(projectRoot: string): Promise<KeyCredentials | undefined>;
|
|
32
32
|
/**
|
|
33
33
|
* A credentials file (format 0 or 1): the Project's, or one the nylorun commands keep in the
|
|
34
|
-
* Host root. Undefined when absent or unreadable, so `start` replaces it
|
|
34
|
+
* Host root. Undefined when absent or unreadable, so `start` replaces it; a newer format is an
|
|
35
|
+
* error, as for the link, so this release never rewrites it in its own.
|
|
35
36
|
*/
|
|
36
37
|
export declare function readCredentialsFile(path: string): Promise<KeyCredentials | undefined>;
|
|
37
38
|
/** `.nylorun/credentials.json` (format 1, mode 0600). */
|
package/dist/project/link.js
CHANGED
|
@@ -49,14 +49,17 @@ export async function readProjectCredentials(projectRoot) {
|
|
|
49
49
|
}
|
|
50
50
|
/**
|
|
51
51
|
* A credentials file (format 0 or 1): the Project's, or one the nylorun commands keep in the
|
|
52
|
-
* Host root. Undefined when absent or unreadable, so `start` replaces it
|
|
52
|
+
* Host root. Undefined when absent or unreadable, so `start` replaces it; a newer format is an
|
|
53
|
+
* error, as for the link, so this release never rewrites it in its own.
|
|
53
54
|
*/
|
|
54
55
|
export async function readCredentialsFile(path) {
|
|
55
56
|
let value;
|
|
56
57
|
try {
|
|
57
58
|
value = readCredentials(path);
|
|
58
59
|
}
|
|
59
|
-
catch {
|
|
60
|
+
catch (error) {
|
|
61
|
+
if (error instanceof ProjectFileError && error.reason === "newer")
|
|
62
|
+
throw new CliError(`Newer credentials at ${error.path}. Upgrade nylorun, or remove the file and run "npx nylorun start" again.`, 1);
|
|
60
63
|
return undefined;
|
|
61
64
|
}
|
|
62
65
|
if (!value)
|
package/dist/stack/commands.js
CHANGED
|
@@ -561,7 +561,7 @@ async function linkProject(ctx, started, tenantId) {
|
|
|
561
561
|
deps.err(`Seeded the Tenant from .env: ${set.join(", ")}.`);
|
|
562
562
|
}
|
|
563
563
|
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
|
|
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".`);
|
|
565
565
|
}
|
|
566
566
|
}
|
|
567
567
|
const START_USAGE = "nylorun start [--tenant <name>] [--no-link] [--no-studio] [--allow-downgrade] [--studio-embed-origin <origin>]... [--studio-embed-origin-reset] [--restate-ui]";
|
|
@@ -238,7 +238,16 @@ ${sandboxes ? SANDBOXES_GATES_PORT : ""} # Egress and the stores; the harness
|
|
|
238
238
|
NYLORUN_HARNESS: \${NYLORUN_HARNESS:-remote}
|
|
239
239
|
NYLORUN_HARNESS_LISTEN_PORT: "4200"
|
|
240
240
|
NYLORUN_HARNESS_ALLOWED_HOSTS: runtime:4200${sandboxes ? SANDBOXES_HARNESS_HOST : ""}
|
|
241
|
-
NYLORUN_HARNESS_TOKEN: \${NYLORUN_HARNESS_TOKEN:?run nylorun start}
|
|
241
|
+
NYLORUN_HARNESS_TOKEN: \${NYLORUN_HARNESS_TOKEN:?run nylorun start}
|
|
242
|
+
# Traces (R7.2): from the shell that runs \`nylorun start\`. Unset, they are
|
|
243
|
+
# empty and the Runtime exports nothing. A collector on this machine is host.docker.internal.
|
|
244
|
+
OTEL_EXPORTER_OTLP_ENDPOINT: \${OTEL_EXPORTER_OTLP_ENDPOINT:-}
|
|
245
|
+
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: \${OTEL_EXPORTER_OTLP_TRACES_ENDPOINT:-}
|
|
246
|
+
OTEL_EXPORTER_OTLP_HEADERS: \${OTEL_EXPORTER_OTLP_HEADERS:-}
|
|
247
|
+
OTEL_SERVICE_NAME: \${OTEL_SERVICE_NAME:-}
|
|
248
|
+
OTEL_RESOURCE_ATTRIBUTES: \${OTEL_RESOURCE_ATTRIBUTES:-}
|
|
249
|
+
OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT: \${OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT:-}
|
|
250
|
+
NYLORUN_TRACE_CONTENT: \${NYLORUN_TRACE_CONTENT:-}${sandboxes ? SANDBOXES_RUNTIME_ENV : ""}${identity ? IDENTITY_RUNTIME_ENV : ""}
|
|
242
251
|
extra_hosts:
|
|
243
252
|
host.docker.internal: host-gateway # the Docker host, also on Linux Docker Engine
|
|
244
253
|
volumes:
|
package/dist/stack/mcp.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { McpPreview } from "@nylorun/core/contracts";
|
|
2
2
|
import { type StackDeps } from "./commands.js";
|
|
3
|
-
export declare const mcpUsage = " mcp inspect <url> [--server <name>] [--
|
|
3
|
+
export declare const mcpUsage = " 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)";
|
|
4
|
+
/** What `--vault` says since protocol 11. */
|
|
5
|
+
export declare const MCP_VAULT_REMOVED = "--vault was removed in protocol 11: a credential is a secret of an Environment, in its own vault. Pass --environment <id> to send that Environment's credential for the URL.";
|
|
4
6
|
/** What the removed `connect` subcommand says since protocol 10. */
|
|
5
|
-
export declare const MCP_CONNECT_REMOVED
|
|
7
|
+
export declare const MCP_CONNECT_REMOVED: string;
|
|
6
8
|
/** A preview as a person reads it: the server, a table of tools, the renames, or the sign-in hint. */
|
|
7
|
-
export declare function previewLines(preview: McpPreview): string[];
|
|
9
|
+
export declare function previewLines(preview: McpPreview, environmentId?: string): string[];
|
|
8
10
|
/** `nylorun mcp <inspect|connect> ...` */
|
|
9
11
|
export declare function mcpCommand(deps: StackDeps, args: readonly string[]): Promise<number>;
|
package/dist/stack/mcp.js
CHANGED
|
@@ -2,30 +2,39 @@
|
|
|
2
2
|
* `nylorun mcp inspect <url>`: a remote MCP server's tools before an agent names it (R2b C12),
|
|
3
3
|
* through the running local Tenant's Management API (`POST /v1/tenant/mcp/preview`) with the
|
|
4
4
|
* Project link's management key, else the Host root's (`runningTenantApi`). It never starts the
|
|
5
|
-
* Tenant, and the Runtime never calls a tool.
|
|
6
|
-
*
|
|
5
|
+
* Tenant, and the Runtime never calls a tool. `--environment <id>` sends that Environment's
|
|
6
|
+
* credential for the URL (protocol 11; it replaced `--vault`); an Environment's secrets are
|
|
7
|
+
* written on the Runtime API (`client.environments.secrets.put` of `@nylorun/agents`). Its
|
|
8
|
+
* `connect` subcommand (MCP OAuth) was removed in protocol 10, and says so.
|
|
7
9
|
*/
|
|
8
10
|
import { PROTOCOL_HEADER, PROTOCOL_VERSION } from "@nylorun/core/compatibility";
|
|
9
11
|
import { CliError } from "../errors.js";
|
|
10
12
|
import { parseStackFlags, runningTenantApi } from "./commands.js";
|
|
11
|
-
export const mcpUsage = ` mcp inspect <url> [--server <name>] [--
|
|
12
|
-
list a remote MCP server's tools with
|
|
13
|
-
credential for <url
|
|
14
|
-
that it needs a person's sign-in (the
|
|
15
|
-
|
|
13
|
+
export const mcpUsage = ` mcp inspect <url> [--server <name>] [--environment <id>] [--sse] [--tenant <name>] [--json]
|
|
14
|
+
list a remote MCP server's tools, with Environment <id>'s
|
|
15
|
+
credential for <url> (none without it): model names, schema
|
|
16
|
+
sizes, renames, or that it needs a person's sign-in (the
|
|
17
|
+
Runtime calls no tool)`;
|
|
18
|
+
const INSPECT_USAGE = "nylorun mcp inspect <url> [--server <name>] [--environment <id>] [--sse] [--tenant <name>] [--json]";
|
|
19
|
+
/** Where a credential for an MCP server goes since protocol 11. */
|
|
20
|
+
const SECRET_HINT = "write it as a bearer or headers secret of an Environment (client.environments.secrets.put of @nylorun/agents, or Studio)";
|
|
21
|
+
/** What `--vault` says since protocol 11. */
|
|
22
|
+
export const MCP_VAULT_REMOVED = "--vault was removed in protocol 11: a credential is a secret of an Environment, in its own vault. Pass --environment <id> to send that Environment's credential for the URL.";
|
|
16
23
|
/** What the removed `connect` subcommand says since protocol 10. */
|
|
17
|
-
export const MCP_CONNECT_REMOVED =
|
|
24
|
+
export const MCP_CONNECT_REMOVED = `The connect subcommand of nylorun mcp was removed with MCP OAuth (protocol 10): ${SECRET_HINT.replace("write it", "write the server's key")}, or reach a server that needs a person's sign-in through a gateway (a secret with via). See its tools with nylorun mcp inspect <url> --environment <id>.`;
|
|
18
25
|
/** The preview takes up to 15 s in the Runtime; the hop gets a margin. */
|
|
19
26
|
const PREVIEW_TIMEOUT_MS = 30_000;
|
|
20
27
|
const DESCRIPTION_CHARS = 60;
|
|
21
28
|
const usageError = (message) => new CliError(message, 2);
|
|
22
29
|
async function inspect(deps, args) {
|
|
23
|
-
|
|
30
|
+
if (args.some((arg) => arg === "--vault" || arg.startsWith("--vault=")))
|
|
31
|
+
throw usageError(MCP_VAULT_REMOVED);
|
|
32
|
+
const flags = parseStackFlags(args, { booleans: ["--json", "--sse"], values: ["--server", "--environment", "--tenant"] }, INSPECT_USAGE);
|
|
24
33
|
if (flags.rest.length !== 1)
|
|
25
34
|
throw usageError(`Usage: ${INSPECT_USAGE}`);
|
|
26
35
|
const url = flags.rest[0];
|
|
27
36
|
const name = flags.values.get("--server");
|
|
28
|
-
const
|
|
37
|
+
const environmentId = flags.values.get("--environment");
|
|
29
38
|
const tenant = flags.values.get("--tenant");
|
|
30
39
|
const api = await runningTenantApi(deps, tenant === undefined ? {} : { name: tenant });
|
|
31
40
|
const response = await deps.fetch(`${api.runtimeUrl}/v1/tenant/mcp/preview`, {
|
|
@@ -40,7 +49,7 @@ async function inspect(deps, args) {
|
|
|
40
49
|
url,
|
|
41
50
|
...(flags.booleans.has("--sse") ? { type: "sse" } : {}),
|
|
42
51
|
...(name === undefined ? {} : { name }),
|
|
43
|
-
...(
|
|
52
|
+
...(environmentId === undefined ? {} : { environmentId }),
|
|
44
53
|
}),
|
|
45
54
|
redirect: "error",
|
|
46
55
|
signal: AbortSignal.timeout(PREVIEW_TIMEOUT_MS),
|
|
@@ -60,15 +69,17 @@ async function inspect(deps, args) {
|
|
|
60
69
|
deps.out(JSON.stringify(preview, null, 2));
|
|
61
70
|
return 0;
|
|
62
71
|
}
|
|
63
|
-
for (const line of previewLines(preview))
|
|
72
|
+
for (const line of previewLines(preview, environmentId))
|
|
64
73
|
deps.out(line);
|
|
65
74
|
return 0;
|
|
66
75
|
}
|
|
67
76
|
/** A preview as a person reads it: the server, a table of tools, the renames, or the sign-in hint. */
|
|
68
|
-
export function previewLines(preview) {
|
|
77
|
+
export function previewLines(preview, environmentId) {
|
|
69
78
|
const credential = preview.credentialSent
|
|
70
|
-
?
|
|
71
|
-
:
|
|
79
|
+
? `with Environment ${environmentId ?? "(unnamed)"}'s credential`
|
|
80
|
+
: environmentId === undefined
|
|
81
|
+
? "with no credential (pass --environment <id> to send an Environment's)"
|
|
82
|
+
: `with no credential (Environment ${environmentId} holds none for this URL)`;
|
|
72
83
|
if (preview.authRequired) {
|
|
73
84
|
const metadata = preview.authRequired.resourceMetadata;
|
|
74
85
|
const servers = Array.isArray(metadata?.authorization_servers)
|
|
@@ -76,13 +87,14 @@ export function previewLines(preview) {
|
|
|
76
87
|
: [];
|
|
77
88
|
return [
|
|
78
89
|
preview.credentialSent
|
|
79
|
-
? `The MCP server at ${preview.url} answered 401: it rejected
|
|
90
|
+
? `The MCP server at ${preview.url} answered 401: it rejected Environment ${environmentId ?? "(unnamed)"}'s credential.`
|
|
80
91
|
: `The MCP server at ${preview.url} answered 401: it needs a credential.`,
|
|
81
92
|
...(servers.length > 0
|
|
82
93
|
? [`It signs people in with ${servers.join(", ")} (${preview.authRequired.resourceMetadataUrl}).`]
|
|
83
94
|
: []),
|
|
84
|
-
|
|
85
|
-
"through a gateway that keeps each person's sign-in
|
|
95
|
+
`Nylorun holds no OAuth client: ${SECRET_HINT.replace("write it", "write the server's API key")},`,
|
|
96
|
+
"and pass --environment <id>; or reach it through a gateway that keeps each person's sign-in",
|
|
97
|
+
"(a secret with via and an identity header).",
|
|
86
98
|
];
|
|
87
99
|
}
|
|
88
100
|
const info = preview.serverInfo;
|
package/dist/stack/sandbox.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { type StackDeps } from "./commands.js";
|
|
2
|
-
export declare const sandboxUsage = " sandbox ls [--tenant <name>] [--label <key=value>]... [--json]\n the Tenant's
|
|
2
|
+
export declare const sandboxUsage = " sandbox ls [--tenant <name>] [--label <key=value>]... [--json]\n the Tenant's Environments: id, kind, state, sessions and labels\n sandbox rm <id> [--tenant <name>] delete an Environment: its sandbox, files and vault\n (refused while a turn runs in it)\n sandbox enable --context <name> [--tenant <name>] [--host-address <ip>] [--bind-address <ip>] [--no-pull]\n run the Tenant's sandboxes as pods on that kubeconfig context (agent-sandbox v1.0.5)\n sandbox disable [--tenant <name>] [--delete-namespace]\n stop the sandboxes service and forget the cluster\n sandbox status [--tenant <name>] [--json]\n the cluster, the sandboxes service's readiness and what it reports";
|
|
3
3
|
/** `nylorun sandbox <ls|rm|enable|disable|status> ...` */
|
|
4
4
|
export declare function sandboxCommand(deps: StackDeps, args: readonly string[]): Promise<number>;
|
package/dist/stack/sandbox.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `nylorun sandbox ls | rm`: the running local Tenant's
|
|
3
|
-
*
|
|
4
|
-
* Tenant. `nylorun sandbox enable|disable|status` (sandbox pods on a cluster,
|
|
5
|
-
* `../sandbox/commands.ts`.
|
|
2
|
+
* `nylorun sandbox ls | rm`: the running local Tenant's Environments (protocol 11: each holds one
|
|
3
|
+
* sandbox and one vault), through its Runtime API with the application key (`runningTenantApi`).
|
|
4
|
+
* Neither starts the Tenant. `nylorun sandbox enable|disable|status` (sandbox pods on a cluster,
|
|
5
|
+
* F7.2) live in `../sandbox/commands.ts`.
|
|
6
6
|
*/
|
|
7
7
|
import { PROTOCOL_HEADER, PROTOCOL_VERSION } from "@nylorun/core/compatibility";
|
|
8
8
|
import { CliError } from "../errors.js";
|
|
@@ -10,8 +10,9 @@ import { runSandboxCommand, sandboxUsage as clusterUsage } from "../sandbox/comm
|
|
|
10
10
|
import { spawnKubectl } from "../sandbox/kubectl.js";
|
|
11
11
|
import { parseStackFlags, runningTenantApi } from "./commands.js";
|
|
12
12
|
export const sandboxUsage = ` sandbox ls [--tenant <name>] [--label <key=value>]... [--json]
|
|
13
|
-
the Tenant's
|
|
14
|
-
sandbox rm <id> [--tenant <name>] delete
|
|
13
|
+
the Tenant's Environments: id, kind, state, sessions and labels
|
|
14
|
+
sandbox rm <id> [--tenant <name>] delete an Environment: its sandbox, files and vault
|
|
15
|
+
(refused while a turn runs in it)
|
|
15
16
|
${clusterUsage}`;
|
|
16
17
|
const usageError = (message) => new CliError(message, 2);
|
|
17
18
|
async function call(deps, api, method, path) {
|
|
@@ -26,8 +27,8 @@ async function call(deps, api, method, path) {
|
|
|
26
27
|
signal: AbortSignal.timeout(15_000),
|
|
27
28
|
});
|
|
28
29
|
const body = (await response.json().catch(() => ({})));
|
|
29
|
-
if (response.status === 404 &&
|
|
30
|
-
throw new CliError(`Tenant ${api.name} runs a Runtime without
|
|
30
|
+
if (response.status === 404 && /^\/v1\/environments(\?|$)/.test(path))
|
|
31
|
+
throw new CliError(`Tenant ${api.name} runs a Runtime without Environments. Update it: npx nylorun@latest start.`, 1);
|
|
31
32
|
if (!response.ok && response.status !== 404)
|
|
32
33
|
throw new CliError(`${method} ${path} returned ${response.status}${typeof body.message === "string" ? `: ${body.message}` : ""}`, 1);
|
|
33
34
|
return { status: response.status, body };
|
|
@@ -50,24 +51,24 @@ async function ls(deps, args) {
|
|
|
50
51
|
const name = flags.values.get("--tenant");
|
|
51
52
|
const api = await runningTenantApi(deps, name === undefined ? {} : { name });
|
|
52
53
|
const search = query.toString();
|
|
53
|
-
const { body } = await call(deps, api, "GET", `/v1/
|
|
54
|
-
const
|
|
54
|
+
const { body } = await call(deps, api, "GET", `/v1/environments${search ? `?${search}` : ""}`);
|
|
55
|
+
const environments = (body.environments ?? []);
|
|
55
56
|
if (flags.booleans.has("--json")) {
|
|
56
|
-
deps.out(JSON.stringify(
|
|
57
|
+
deps.out(JSON.stringify(environments, null, 2));
|
|
57
58
|
return 0;
|
|
58
59
|
}
|
|
59
|
-
if (
|
|
60
|
-
deps.out(`No
|
|
60
|
+
if (environments.length === 0) {
|
|
61
|
+
deps.out(`No Environments on Tenant ${api.name}.`);
|
|
61
62
|
return 0;
|
|
62
63
|
}
|
|
63
64
|
const rows = [
|
|
64
65
|
["ID", "KIND", "STATE", "SESSIONS", "LABELS"],
|
|
65
|
-
...
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
String(
|
|
70
|
-
labelsText(
|
|
66
|
+
...environments.map((environment) => [
|
|
67
|
+
environment.id,
|
|
68
|
+
environment.kind,
|
|
69
|
+
environment.state,
|
|
70
|
+
String(environment.sessions.length),
|
|
71
|
+
labelsText(environment.labels),
|
|
71
72
|
]),
|
|
72
73
|
];
|
|
73
74
|
const widths = rows[0].map((_, column) => Math.max(...rows.map((row) => row[column].length)));
|
|
@@ -85,12 +86,12 @@ async function rm(deps, args) {
|
|
|
85
86
|
const id = flags.rest[0];
|
|
86
87
|
const name = flags.values.get("--tenant");
|
|
87
88
|
const api = await runningTenantApi(deps, name === undefined ? {} : { name });
|
|
88
|
-
const { status, body } = await call(deps, api, "DELETE", `/v1/
|
|
89
|
+
const { status, body } = await call(deps, api, "DELETE", `/v1/environments/${encodeURIComponent(id)}`);
|
|
89
90
|
if (status === 404 || body.deleted !== true) {
|
|
90
|
-
deps.err(`No
|
|
91
|
+
deps.err(`No Environment ${id} on Tenant ${api.name}.`);
|
|
91
92
|
return 1;
|
|
92
93
|
}
|
|
93
|
-
deps.out(`Deleted
|
|
94
|
+
deps.out(`Deleted Environment ${id}: its sandbox, files and vault.`);
|
|
94
95
|
return 0;
|
|
95
96
|
}
|
|
96
97
|
/** `nylorun sandbox <ls|rm|enable|disable|status> ...` */
|
package/dist/stack/versions.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
/** An image this CLI release pins in `
|
|
1
|
+
/** An image this CLI release pins in its `package.json` `nylorun` (D7). */
|
|
2
2
|
export type PinnedImage = "runtime" | "studio";
|
|
3
3
|
/**
|
|
4
|
-
* The version this CLI release pins for an image, from `
|
|
4
|
+
* The version this CLI release pins for an image, from its `package.json`
|
|
5
5
|
* `nylorun.runtime` or `nylorun.studio`: the tag of `ghcr.io/nylorun/<name>`
|
|
6
6
|
* a local Tenant runs unless `NYLORUN_RUNTIME_IMAGE` / `NYLORUN_STUDIO_IMAGE`
|
|
7
7
|
* overrides it. The release tooling writes both pins.
|
package/dist/stack/versions.js
CHANGED
|
@@ -3,11 +3,11 @@ import { dirname, join } from "node:path";
|
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
import { CliError } from "../errors.js";
|
|
5
5
|
function cliPackageJsonPath() {
|
|
6
|
-
// src/stack/*.ts and dist/stack/*.js both sit two levels below
|
|
6
|
+
// src/stack/*.ts and dist/stack/*.js both sit two levels below the package root.
|
|
7
7
|
return join(dirname(fileURLToPath(import.meta.url)), "..", "..", "package.json");
|
|
8
8
|
}
|
|
9
9
|
/**
|
|
10
|
-
* The version this CLI release pins for an image, from `
|
|
10
|
+
* The version this CLI release pins for an image, from its `package.json`
|
|
11
11
|
* `nylorun.runtime` or `nylorun.studio`: the tag of `ghcr.io/nylorun/<name>`
|
|
12
12
|
* a local Tenant runs unless `NYLORUN_RUNTIME_IMAGE` / `NYLORUN_STUDIO_IMAGE`
|
|
13
13
|
* overrides it. The release tooling writes both pins.
|
|
@@ -22,7 +22,7 @@ export function pinnedVersion(name) {
|
|
|
22
22
|
}
|
|
23
23
|
const version = raw?.nylorun?.[name];
|
|
24
24
|
if (typeof version !== "string" || version.trim() === "") {
|
|
25
|
-
throw new CliError(`
|
|
25
|
+
throw new CliError(`nylorun's package.json is missing "nylorun.${name}" (the pinned ${name} image version).`, 1);
|
|
26
26
|
}
|
|
27
27
|
return version;
|
|
28
28
|
}
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nylorun",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0-beta",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
|
-
"description": "Set up and run local Nylorun Tenants (Runtime and Studio) with Docker Compose",
|
|
6
|
+
"description": "Set up and run local Nylorun Tenants (Runtime and Studio) with Docker Compose (nylorun), and the Runtime client of the linked installation (nylo)",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
9
|
"url": "git+https://github.com/nylorun/agents.git",
|
|
10
|
-
"directory": "nylorun"
|
|
10
|
+
"directory": "cli/nylorun"
|
|
11
11
|
},
|
|
12
12
|
"files": [
|
|
13
13
|
"dist",
|
|
@@ -23,25 +23,29 @@
|
|
|
23
23
|
"node": ">=24.0.0"
|
|
24
24
|
},
|
|
25
25
|
"scripts": {
|
|
26
|
-
"build": "npm run clean && node
|
|
26
|
+
"build": "npm run clean && node ../../scripts/check-typescript-version.mjs && tsc -p tsconfig.json",
|
|
27
27
|
"clean": "node -e \"import('node:fs').then(({rmSync})=>rmSync('dist',{recursive:true,force:true}))\"",
|
|
28
28
|
"check": "npm run build && npm test && node scripts/check-package.mjs",
|
|
29
29
|
"test": "vitest run --passWithNoTests",
|
|
30
30
|
"prepack": "npm run build"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@nylorun/core": "0.
|
|
33
|
+
"@nylorun/core": "0.20.0-beta",
|
|
34
|
+
"@nylorun/admin": "0.16.0-beta"
|
|
34
35
|
},
|
|
35
36
|
"devDependencies": {
|
|
37
|
+
"@earendil-works/pi-ai": "0.99.1",
|
|
38
|
+
"@nylorun/agents": "file:../../sdks/agents",
|
|
36
39
|
"typescript": "npm:@typescript/typescript6@^6.0.2",
|
|
37
|
-
"@types/node": "^26.
|
|
40
|
+
"@types/node": "^26.6.4",
|
|
38
41
|
"vitest": "^5.0.2"
|
|
39
42
|
},
|
|
40
43
|
"bin": {
|
|
41
|
-
"nylorun": "dist/cli.js"
|
|
44
|
+
"nylorun": "dist/cli.js",
|
|
45
|
+
"nylo": "dist/nylo.js"
|
|
42
46
|
},
|
|
43
47
|
"nylorun": {
|
|
44
|
-
"runtime": "0.
|
|
45
|
-
"studio": "0.
|
|
48
|
+
"runtime": "0.24.0-beta",
|
|
49
|
+
"studio": "0.24.0-beta"
|
|
46
50
|
}
|
|
47
51
|
}
|