@nylorun/cli 0.6.0-beta → 0.8.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.
@@ -1,38 +1,12 @@
1
1
  import { randomUUID } from "node:crypto";
2
- import { readFileSync } from "node:fs";
3
- import { join } from "node:path";
4
- import { PROTOCOL_HEADER, PROTOCOL_VERSION, TENANT_HEADER, } from "@nylorun/agents";
5
- import { configureProvider } from "./configure.js";
6
- import { loadProjectEnvironment } from "../environment.js";
7
- function tenantHeaders(serverKey, tenantId) {
8
- return {
9
- authorization: `Bearer ${serverKey}`,
10
- [TENANT_HEADER]: tenantId,
11
- [PROTOCOL_HEADER]: String(PROTOCOL_VERSION),
12
- };
13
- }
14
- function resolveTenantId(explicit) {
15
- const tenant = explicit?.trim() || process.env.NYLORUN_TENANT?.trim();
16
- if (!tenant) {
17
- throw new Error("Set NYLORUN_TENANT (or pass tenant via Project link) before calling Tenant model routes");
18
- }
19
- return tenant;
20
- }
21
- export async function getHostModel(runtimeUrl, serverKey, tenantId) {
22
- const tenant = resolveTenantId(tenantId);
23
- const response = await fetch(`${runtimeUrl}/v1/tenant/model`, {
24
- headers: tenantHeaders(serverKey, tenant),
25
- });
26
- if (!response.ok)
27
- throw new Error(`Runtime model status returned ${response.status}`);
28
- return response.json();
29
- }
30
- export async function putHostModel(runtimeUrl, serverKey, model, tenantId) {
31
- const tenant = resolveTenantId(tenantId);
32
- const response = await fetch(`${runtimeUrl}/v1/tenant/model`, {
2
+ import { PROTOCOL_HEADER, PROTOCOL_VERSION } from "@nylorun/agents";
3
+ /** Set the installation's Tenant model provider (`PUT /v1/tenant/model`). */
4
+ export async function putHostModel(runtimeUrl, serverKey, model, fetchImpl = fetch) {
5
+ const response = await fetchImpl(`${runtimeUrl}/v1/tenant/model`, {
33
6
  method: "PUT",
34
7
  headers: {
35
- ...tenantHeaders(serverKey, tenant),
8
+ authorization: `Bearer ${serverKey}`,
9
+ [PROTOCOL_HEADER]: String(PROTOCOL_VERSION),
36
10
  "content-type": "application/json",
37
11
  },
38
12
  body: JSON.stringify({
@@ -50,57 +24,3 @@ export async function putHostModel(runtimeUrl, serverKey, model, tenantId) {
50
24
  throw new Error(body.message ?? `Runtime rejected the model provider (${response.status})`);
51
25
  return body;
52
26
  }
53
- export async function ensureHostModel(options) {
54
- const current = await getHostModel(options.runtimeUrl, options.serverKey, options.tenantId);
55
- if (current.configured)
56
- return;
57
- const env = options.env ?? loadProjectEnvironment(options.root ?? process.cwd());
58
- if (env.NYLORUN_DEV_MODEL?.trim() === "fixture")
59
- return;
60
- const seeded = seedFromEnv(env, options.root ?? process.cwd());
61
- if (seeded) {
62
- await putHostModel(options.runtimeUrl, options.serverKey, seeded, options.tenantId);
63
- return;
64
- }
65
- if (process.stdin.isTTY && process.stdout.isTTY) {
66
- const prompted = await configureProvider({
67
- root: options.root,
68
- signal: options.signal,
69
- });
70
- await putHostModel(options.runtimeUrl, options.serverKey, prompted, options.tenantId);
71
- return;
72
- }
73
- throw new Error("Model provider is not configured. Run nylo configure in a terminal to set it up, or open Studio.");
74
- }
75
- function seedFromEnv(env, root) {
76
- const provider = env.MODEL_PROVIDER?.trim();
77
- const model = env.MODEL?.trim();
78
- if (!provider || !model)
79
- return undefined;
80
- const baseUrl = env.MODEL_PROVIDER_BASE_URL?.trim();
81
- const key = env.MODEL_PROVIDER_API_KEY;
82
- const auth = key
83
- ? { type: "api_key", key }
84
- : legacyCredential(root, provider);
85
- if (!auth)
86
- return undefined;
87
- return {
88
- provider,
89
- model,
90
- ...(baseUrl ? { baseUrl } : {}),
91
- auth,
92
- };
93
- }
94
- function legacyCredential(root, provider) {
95
- for (const relative of [".nylorun/auth.json", ".env/auth.json"]) {
96
- try {
97
- const all = JSON.parse(readFileSync(join(root, relative), "utf8"));
98
- const credential = all[provider];
99
- if (credential?.type === "api_key" || credential?.type === "oauth")
100
- return credential;
101
- }
102
- catch {
103
- /* A project without a legacy credential file is set up interactively. */
104
- }
105
- }
106
- }
@@ -0,0 +1,13 @@
1
+ import { type ProjectLink } from "./link.js";
2
+ /** The installation `nylo` acts on: a Runtime URL and an application key. */
3
+ export interface LinkedConnection {
4
+ url: string;
5
+ key: string;
6
+ /** The Project link it came from, when it came from one. */
7
+ link?: ProjectLink;
8
+ }
9
+ /**
10
+ * The Project's link and credentials, else `NYLORUN_RUNTIME_URL` and `NYLORUN_SERVER_KEY`. The
11
+ * installation serves one Tenant, so nothing names it.
12
+ */
13
+ export declare function linkedConnection(projectRoot: string, env?: Readonly<Record<string, string | undefined>>): Promise<LinkedConnection>;
@@ -0,0 +1,18 @@
1
+ import { CliError } from "../errors.js";
2
+ import { readCredentials } from "./credentials.js";
3
+ import { readLink } from "./link.js";
4
+ /**
5
+ * The Project's link and credentials, else `NYLORUN_RUNTIME_URL` and `NYLORUN_SERVER_KEY`. The
6
+ * installation serves one Tenant, so nothing names it.
7
+ */
8
+ export async function linkedConnection(projectRoot, env = process.env) {
9
+ const link = await readLink(projectRoot);
10
+ const credentials = await readCredentials(projectRoot);
11
+ if (link && credentials)
12
+ return { url: link.hostUrl, key: credentials.applicationKey, link };
13
+ const url = env.NYLORUN_RUNTIME_URL?.trim();
14
+ const key = env.NYLORUN_SERVER_KEY?.trim();
15
+ if (url && key)
16
+ return { url: url.replace(/\/$/, ""), key };
17
+ 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.`, 1);
18
+ }
@@ -7,11 +7,5 @@ export interface ProjectCredentials {
7
7
  applicationKey: string;
8
8
  principalId: string;
9
9
  }
10
- /** The Project's credentials, or with `tenantId` the key kept for that Tenant. */
11
- export declare function readCredentials(projectRoot: string, tenantId?: string): Promise<ProjectCredentials | undefined>;
12
- export declare function writeCredentials(projectRoot: string, credentials: {
13
- applicationKey: string;
14
- principalId: string;
15
- format?: 0 | 1;
16
- }, tenantId?: string): Promise<void>;
17
- export declare function removeCredentials(projectRoot: string, tenantId?: string): Promise<void>;
10
+ /** The Project's credentials, which `nylorun start` writes beside the link. */
11
+ export declare function readCredentials(projectRoot: string): Promise<ProjectCredentials | undefined>;
@@ -1,17 +1,16 @@
1
- import { chmod, readFile, rename, rm, writeFile } from "node:fs/promises";
2
- import { randomUUID } from "node:crypto";
1
+ import { chmod, readFile } from "node:fs/promises";
3
2
  import { CliError } from "../errors.js";
4
- import { credentialsPath, ensureProjectNylorunDir, } from "./link.js";
5
- /** The Project's credentials, or with `tenantId` the key kept for that Tenant. */
6
- export async function readCredentials(projectRoot, tenantId) {
7
- const path = credentialsPath(projectRoot, tenantId);
3
+ import { credentialsPath } from "./link.js";
4
+ /** The Project's credentials, which `nylorun start` writes beside the link. */
5
+ export async function readCredentials(projectRoot) {
6
+ const path = credentialsPath(projectRoot);
8
7
  try {
9
8
  const value = JSON.parse(await readFile(path, "utf8"));
10
9
  if (typeof value?.applicationKey !== "string" ||
11
10
  !/^[0-9a-f]{64}$/.test(value.applicationKey) ||
12
11
  typeof value?.principalId !== "string" ||
13
12
  value.principalId.length === 0) {
14
- throw new CliError(`Invalid Project credentials at ${path}. Remove .nylorun/credentials.json and run nylo tenant create.`, 1);
13
+ throw new CliError(`Invalid Project credentials at ${path}. Remove .nylorun/credentials.json and run "npx nylorun start".`, 1);
15
14
  }
16
15
  const format = value.format === undefined || value.format === 0
17
16
  ? 0
@@ -34,25 +33,3 @@ export async function readCredentials(projectRoot, tenantId) {
34
33
  throw error;
35
34
  }
36
35
  }
37
- export async function writeCredentials(projectRoot, credentials, tenantId) {
38
- await ensureProjectNylorunDir(projectRoot);
39
- const path = credentialsPath(projectRoot, tenantId);
40
- const temporary = `${path}.${randomUUID()}.tmp`;
41
- // Version 1 writes format 1 with only the application key and principal (D§3.7).
42
- const body = `${JSON.stringify({
43
- format: credentials.format ?? 1,
44
- applicationKey: credentials.applicationKey,
45
- principalId: credentials.principalId,
46
- }, null, 2)}\n`;
47
- try {
48
- await writeFile(temporary, body, { mode: 0o600 });
49
- await rename(temporary, path);
50
- await chmod(path, 0o600);
51
- }
52
- finally {
53
- await rm(temporary, { force: true });
54
- }
55
- }
56
- export async function removeCredentials(projectRoot, tenantId) {
57
- await rm(credentialsPath(projectRoot, tenantId), { force: true });
58
- }
@@ -1,3 +1,3 @@
1
- /** Three `export` lines for `nylo env` (was `nylorun status --env`, F2-7). */
1
+ /** Two `export` lines for `nylo env` (was `nylorun status --env`, F2-7). */
2
2
  export declare function printLinkedEnvExports(projectRoot?: string): Promise<void>;
3
3
  export declare function shellQuote(value: string): string;
@@ -1,18 +1,17 @@
1
1
  import { readCredentials } from "./credentials.js";
2
2
  import { readLink } from "./link.js";
3
3
  import { findProjectRoot } from "./root.js";
4
- /** Three `export` lines for `nylo env` (was `nylorun status --env`, F2-7). */
4
+ /** Two `export` lines for `nylo env` (was `nylorun status --env`, F2-7). */
5
5
  export async function printLinkedEnvExports(projectRoot = process.cwd()) {
6
6
  const root = findProjectRoot(projectRoot) ?? projectRoot;
7
7
  const link = await readLink(root);
8
8
  const credentials = await readCredentials(root);
9
9
  if (!link || !credentials) {
10
- console.log("# No Project link in this directory. Run nylo tenant create to create one.");
10
+ console.log('# No Project link in this directory. Run "npx nylorun start" in this project to start its Tenant and link it.');
11
11
  return;
12
12
  }
13
13
  console.log(`export NYLORUN_RUNTIME_URL=${shellQuote(link.hostUrl)}`);
14
14
  console.log(`export NYLORUN_SERVER_KEY=${shellQuote(credentials.applicationKey)}`);
15
- console.log(`export NYLORUN_TENANT=${shellQuote(link.tenantId)}`);
16
15
  }
17
16
  export function shellQuote(value) {
18
17
  if (/^[A-Za-z0-9_./:-]+$/.test(value))
@@ -1,24 +1,17 @@
1
- /** Project-local link to a Runtime Host Tenant (D§3.7, format 0|1). */
1
+ /**
2
+ * Project-local link to an installation (format 3). `nylorun start` writes it; `nylo` only
3
+ * reads it. `tenantId` is information: the installation serves one Tenant, so nothing selects it.
4
+ */
2
5
  export interface ProjectLink {
3
- format: 0 | 1;
6
+ format: 3;
7
+ /** The local Tenant the link names (`~/.nylorun/tenants/<tenant>/`). */
8
+ tenant?: string;
4
9
  hostUrl: string;
5
10
  hostId: string;
6
- tenantId: string;
11
+ tenantId?: string;
7
12
  }
8
13
  export declare function nylorunDir(projectRoot: string): string;
9
14
  export declare function linkPath(projectRoot: string): string;
10
- /**
11
- * `.nylorun/credentials.json`, or with `tenantId` the key `nylo tenant use`
12
- * kept for a Tenant the Project was linked to before (`credentials.<id>.json`).
13
- */
14
- export declare function credentialsPath(projectRoot: string, tenantId?: string): string;
15
- /**
16
- * Create `.nylorun/` mode 0700 with a private `.gitignore` containing `*`.
17
- * The Project's own `.gitignore` is never edited.
18
- */
19
- export declare function ensureProjectNylorunDir(projectRoot: string): Promise<string>;
15
+ /** `.nylorun/credentials.json`. */
16
+ export declare function credentialsPath(projectRoot: string): string;
20
17
  export declare function readLink(projectRoot: string): Promise<ProjectLink | undefined>;
21
- export declare function writeLink(projectRoot: string, link: Omit<ProjectLink, "format"> & {
22
- format?: 0 | 1;
23
- }): Promise<void>;
24
- export declare function removeLink(projectRoot: string): Promise<void>;
@@ -1,7 +1,5 @@
1
- import { mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
1
+ import { readFile } from "node:fs/promises";
2
2
  import { join } from "node:path";
3
- import { randomUUID } from "node:crypto";
4
- import { isTenantId } from "@nylorun/agents";
5
3
  import { CliError } from "../errors.js";
6
4
  export function nylorunDir(projectRoot) {
7
5
  return join(projectRoot, ".nylorun");
@@ -9,73 +7,46 @@ export function nylorunDir(projectRoot) {
9
7
  export function linkPath(projectRoot) {
10
8
  return join(nylorunDir(projectRoot), "link.json");
11
9
  }
12
- /**
13
- * `.nylorun/credentials.json`, or with `tenantId` the key `nylo tenant use`
14
- * kept for a Tenant the Project was linked to before (`credentials.<id>.json`).
15
- */
16
- export function credentialsPath(projectRoot, tenantId) {
17
- return join(nylorunDir(projectRoot), tenantId === undefined ? "credentials.json" : `credentials.${tenantId}.json`);
18
- }
19
- /**
20
- * Create `.nylorun/` mode 0700 with a private `.gitignore` containing `*`.
21
- * The Project's own `.gitignore` is never edited.
22
- */
23
- export async function ensureProjectNylorunDir(projectRoot) {
24
- const dir = nylorunDir(projectRoot);
25
- await mkdir(dir, { recursive: true, mode: 0o700 });
26
- await writeFile(join(dir, ".gitignore"), "*\n", { mode: 0o600 }).catch(async () => {
27
- await writeFile(join(dir, ".gitignore"), "*\n", { mode: 0o600 });
28
- });
29
- return dir;
10
+ /** `.nylorun/credentials.json`. */
11
+ export function credentialsPath(projectRoot) {
12
+ return join(nylorunDir(projectRoot), "credentials.json");
30
13
  }
31
14
  export async function readLink(projectRoot) {
15
+ const path = linkPath(projectRoot);
16
+ let value;
17
+ let raw;
32
18
  try {
33
- const value = JSON.parse(await readFile(linkPath(projectRoot), "utf8"));
34
- if (typeof value?.hostUrl !== "string" ||
35
- typeof value?.hostId !== "string" ||
36
- typeof value?.tenantId !== "string" ||
37
- !isTenantId(value.tenantId)) {
38
- throw new CliError(`Invalid Project link at ${linkPath(projectRoot)}. Remove .nylorun/link.json and run nylo tenant create.`, 1);
39
- }
40
- const format = value.format === undefined || value.format === 0
41
- ? 0
42
- : value.format === 1
43
- ? 1
44
- : undefined;
45
- if (format === undefined) {
46
- throw new CliError(`Project link at ${linkPath(projectRoot)} has an unsupported format. Upgrade the CLI.`, 1);
47
- }
48
- return {
49
- format,
50
- hostUrl: value.hostUrl.replace(/\/$/, ""),
51
- hostId: value.hostId,
52
- tenantId: value.tenantId,
53
- };
19
+ raw = await readFile(path, "utf8");
54
20
  }
55
21
  catch (error) {
56
22
  if (error.code === "ENOENT")
57
23
  return undefined;
58
24
  throw error;
59
25
  }
60
- }
61
- export async function writeLink(projectRoot, link) {
62
- await ensureProjectNylorunDir(projectRoot);
63
- const path = linkPath(projectRoot);
64
- const temporary = `${path}.${randomUUID()}.tmp`;
65
- const body = `${JSON.stringify({
66
- format: link.format ?? 1,
67
- hostUrl: link.hostUrl.replace(/\/$/, ""),
68
- hostId: link.hostId,
69
- tenantId: link.tenantId,
70
- }, null, 2)}\n`;
71
26
  try {
72
- await writeFile(temporary, body, { mode: 0o600 });
73
- await rename(temporary, path);
27
+ value = JSON.parse(raw);
74
28
  }
75
- finally {
76
- await rm(temporary, { force: true });
29
+ catch {
30
+ throw new CliError(`Invalid Project link at ${path}. Remove .nylorun/link.json and run "npx nylorun start".`, 1);
77
31
  }
78
- }
79
- export async function removeLink(projectRoot) {
80
- await rm(linkPath(projectRoot), { force: true });
32
+ // Formats 0 to 2 are from older releases.
33
+ if (value?.format === undefined ||
34
+ value.format === 0 ||
35
+ value.format === 1 ||
36
+ value.format === 2)
37
+ 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);
38
+ if (value.format !== 3)
39
+ throw new CliError(`Project link at ${path} has an unsupported format. Upgrade the CLI.`, 1);
40
+ if (typeof value.hostUrl !== "string" ||
41
+ typeof value.hostId !== "string" ||
42
+ (value.tenant !== undefined && typeof value.tenant !== "string") ||
43
+ (value.tenantId !== undefined && typeof value.tenantId !== "string"))
44
+ throw new CliError(`Invalid Project link at ${path}. Remove .nylorun/link.json and run "npx nylorun start".`, 1);
45
+ return {
46
+ format: 3,
47
+ ...(value.tenant ? { tenant: value.tenant } : {}),
48
+ hostUrl: value.hostUrl.replace(/\/$/, ""),
49
+ hostId: value.hostId,
50
+ ...(value.tenantId ? { tenantId: value.tenantId } : {}),
51
+ };
81
52
  }
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@nylorun/cli",
3
- "version": "0.6.0-beta",
3
+ "version": "0.8.0-beta",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
- "description": "Nylorun Runtime client: Tenants, Project links and model providers",
6
+ "description": "Nylorun Runtime client: the linked installation's Tenant, its access and its model provider",
7
7
  "repository": {
8
8
  "type": "git",
9
9
  "url": "git+https://github.com/nylorun/agents.git",
@@ -30,8 +30,8 @@
30
30
  "prepack": "npm run build"
31
31
  },
32
32
  "dependencies": {
33
- "@nylorun/agents": "0.10.0-beta",
34
- "@nylorun/admin": "0.6.0-beta",
33
+ "@nylorun/agents": "0.12.0-beta",
34
+ "@nylorun/admin": "0.8.0-beta",
35
35
  "@earendil-works/pi-ai": "0.99.1"
36
36
  },
37
37
  "devDependencies": {
@@ -1,28 +0,0 @@
1
- import { type Admin } from "@nylorun/admin";
2
- import { type ProjectCredentials } from "./credentials.js";
3
- import { type ProjectLink } from "./link.js";
4
- export interface CreateTenantOptions {
5
- /** Prefer an already-resolved Admin (local Host or explicit). */
6
- admin: Admin;
7
- hostId: string;
8
- projectRoot: string;
9
- name?: string;
10
- /** Override Host URL written into the link (defaults to admin.url). */
11
- hostUrl?: string;
12
- }
13
- export interface CreateTenantResult {
14
- link: ProjectLink;
15
- credentials: ProjectCredentials;
16
- envelope: {
17
- id: string;
18
- name: string;
19
- };
20
- }
21
- /** The Project's `package.json` name, else its directory name. */
22
- export declare function defaultTenantName(projectRoot: string): Promise<string>;
23
- /**
24
- * Create a Tenant via `@nylorun/admin` and write format-1 link + credentials.
25
- */
26
- export declare function createProjectTenant(options: CreateTenantOptions): Promise<CreateTenantResult>;
27
- /** Resolve Admin from the local Host root (host.json and the admin key). */
28
- export declare function localAdmin(home?: string): Admin;
@@ -1,66 +0,0 @@
1
- import { readFile } from "node:fs/promises";
2
- import { basename, join } from "node:path";
3
- import { createAdmin } from "@nylorun/admin";
4
- import { newPrincipalId } from "@nylorun/agents";
5
- import { CliError } from "../errors.js";
6
- import { writeCredentials, } from "./credentials.js";
7
- import { writeLink } from "./link.js";
8
- /** The Project's `package.json` name, else its directory name. */
9
- export async function defaultTenantName(projectRoot) {
10
- try {
11
- const pkg = JSON.parse(await readFile(join(projectRoot, "package.json"), "utf8"));
12
- if (typeof pkg.name === "string" && pkg.name.trim())
13
- return pkg.name.trim();
14
- }
15
- catch {
16
- /* fall through */
17
- }
18
- const base = basename(projectRoot);
19
- return base && base.length > 0 ? base : "project";
20
- }
21
- /**
22
- * Create a Tenant via `@nylorun/admin` and write format-1 link + credentials.
23
- */
24
- export async function createProjectTenant(options) {
25
- const name = options.name ?? (await defaultTenantName(options.projectRoot));
26
- const admin = options.admin;
27
- let created;
28
- try {
29
- created = await admin.createTenant({ name });
30
- }
31
- catch (error) {
32
- throw new CliError(error instanceof Error
33
- ? error.message
34
- : `Could not create Tenant: ${String(error)}`, 1);
35
- }
36
- const hostUrl = (options.hostUrl ?? admin.url).replace(/\/$/, "");
37
- // CLIENTS-CCR: admin.createTenant should also return principalId (D§4.2 /
38
- // credentials.json). Until then, mint a local id for the credentials file;
39
- // agents resolveConnection only needs applicationKey.
40
- const principalId = "principalId" in created &&
41
- typeof created.principalId === "string"
42
- ? created.principalId
43
- : newPrincipalId();
44
- const credentials = {
45
- format: 1,
46
- applicationKey: created.applicationKey,
47
- principalId,
48
- };
49
- const link = {
50
- format: 1,
51
- hostUrl,
52
- hostId: options.hostId,
53
- tenantId: created.tenant.id,
54
- };
55
- await writeCredentials(options.projectRoot, credentials);
56
- await writeLink(options.projectRoot, link);
57
- return {
58
- link,
59
- credentials,
60
- envelope: { id: created.tenant.id, name: created.tenant.name },
61
- };
62
- }
63
- /** Resolve Admin from the local Host root (host.json and the admin key). */
64
- export function localAdmin(home) {
65
- return createAdmin(home ? { home } : undefined);
66
- }
@@ -1,25 +0,0 @@
1
- export interface SeedOptions {
2
- hostUrl: string;
3
- tenantId: string;
4
- applicationKey: string;
5
- projectRoot: string;
6
- /** Pre-loaded env map; when omitted, read `.env` without mutating process.env. */
7
- env?: Readonly<Record<string, string>>;
8
- fetchImpl?: typeof fetch;
9
- signal?: AbortSignal;
10
- /**
11
- * Seed the Tenant-level fixture model (`fixtureModel: true`, Host feature
12
- * `tenant-fixture-model`) and skip the Project's model credential.
13
- */
14
- fixtureModel?: boolean;
15
- }
16
- /**
17
- * Seed non-secret Tenant config via `PUT /v1/tenant/config/seed`.
18
- * Model secrets go through the model route into the Tenant vault (F3).
19
- * `.env` is read as a value map only — never written back or applied to process.env.
20
- */
21
- export declare function seedTenantFromProject(options: SeedOptions): Promise<{
22
- applied: string[];
23
- kept: string[];
24
- model?: string;
25
- }>;
@@ -1,96 +0,0 @@
1
- import { readFileSync } from "node:fs";
2
- import { join } from "node:path";
3
- import { randomUUID } from "node:crypto";
4
- import { PROTOCOL_HEADER, PROTOCOL_VERSION, TENANT_HEADER, } from "@nylorun/agents";
5
- import { CliError } from "../errors.js";
6
- import { putHostModel } from "../model/host-model.js";
7
- import { loadProjectEnvironment } from "../environment.js";
8
- function tenantHeaders(applicationKey, tenantId) {
9
- return {
10
- authorization: `Bearer ${applicationKey}`,
11
- [TENANT_HEADER]: tenantId,
12
- [PROTOCOL_HEADER]: String(PROTOCOL_VERSION),
13
- };
14
- }
15
- /**
16
- * Seed non-secret Tenant config via `PUT /v1/tenant/config/seed`.
17
- * Model secrets go through the model route into the Tenant vault (F3).
18
- * `.env` is read as a value map only — never written back or applied to process.env.
19
- */
20
- export async function seedTenantFromProject(options) {
21
- const env = options.env ?? loadProjectEnvironment(options.projectRoot);
22
- const fetchImpl = options.fetchImpl ?? fetch;
23
- const sandboxRaw = env.NYLORUN_SANDBOX?.trim();
24
- const sandbox = sandboxRaw === "auto" || sandboxRaw === "virtual"
25
- ? { backend: sandboxRaw }
26
- : undefined;
27
- let applied = [];
28
- let kept = [];
29
- if (sandbox || options.fixtureModel) {
30
- const response = await fetchImpl(`${options.hostUrl.replace(/\/$/, "")}/v1/tenant/config/seed`, {
31
- method: "PUT",
32
- headers: {
33
- ...tenantHeaders(options.applicationKey, options.tenantId),
34
- "content-type": "application/json",
35
- },
36
- body: JSON.stringify({
37
- requestId: randomUUID(),
38
- ...(sandbox ? { sandbox } : {}),
39
- ...(options.fixtureModel ? { fixtureModel: true } : {}),
40
- }),
41
- signal: options.signal ?? AbortSignal.timeout(15_000),
42
- });
43
- if (!response.ok) {
44
- throw new CliError(`Tenant config seed failed (${response.status}): ${await response
45
- .text()
46
- .catch(() => "")}`, 1);
47
- }
48
- const body = (await response.json());
49
- applied = body.applied ?? [];
50
- kept = body.kept ?? [];
51
- }
52
- // A fixture-model Tenant never calls a real model: its credential stays out of it.
53
- let model;
54
- if (!options.fixtureModel && env.NYLORUN_DEV_MODEL?.trim() !== "fixture") {
55
- const seeded = modelFromEnv(env, options.projectRoot);
56
- if (seeded) {
57
- await putHostModel(options.hostUrl, options.applicationKey, seeded, options.tenantId);
58
- model = `${seeded.provider}/${seeded.model}`;
59
- }
60
- }
61
- return { applied, kept, ...(model ? { model } : {}) };
62
- }
63
- function modelFromEnv(env, projectRoot) {
64
- const provider = env.MODEL_PROVIDER?.trim();
65
- const model = env.MODEL?.trim();
66
- if (!provider || !model)
67
- return undefined;
68
- const baseUrl = env.MODEL_PROVIDER_BASE_URL?.trim();
69
- const key = env.MODEL_PROVIDER_API_KEY;
70
- if (key) {
71
- return {
72
- provider,
73
- model,
74
- ...(baseUrl ? { baseUrl } : {}),
75
- auth: { type: "api_key", key },
76
- };
77
- }
78
- for (const relative of [".nylorun/auth.json", ".env/auth.json"]) {
79
- try {
80
- const all = JSON.parse(readFileSync(join(projectRoot, relative), "utf8"));
81
- const credential = all[provider];
82
- if (credential?.type === "api_key" || credential?.type === "oauth") {
83
- return {
84
- provider,
85
- model,
86
- ...(baseUrl ? { baseUrl } : {}),
87
- auth: credential,
88
- };
89
- }
90
- }
91
- catch {
92
- /* absent */
93
- }
94
- }
95
- return undefined;
96
- }
@@ -1,18 +0,0 @@
1
- import { type AdminTenant } from "@nylorun/admin";
2
- /** Exact-and-unique name or id match. */
3
- export declare function matchTenant(tenants: readonly AdminTenant[], nameOrId: string): AdminTenant;
4
- export declare function tenantCommand(args: readonly string[]): Promise<void>;
5
- /** One line of `nylo tenant endpoints`: the agent, its URL and version, and how it is doing. */
6
- export declare function endpointLine(endpoint: {
7
- agentId: string;
8
- url: string;
9
- implementationVersion: string;
10
- health: {
11
- consecutiveFailures: number;
12
- lastSuccessAt?: string;
13
- lastError?: {
14
- code: string;
15
- message: string;
16
- };
17
- };
18
- }): string;