nylorun 0.4.0-beta → 0.5.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,16 +1,16 @@
1
1
  /**
2
- * A local stack's Compose file (Runtime Architecture §14.3), written to
3
- * `<Host root>/docker/compose.yaml` by `nylorun start`. Each stack is one installation with
4
- * one Tenant (tenancy.md §6): its own Compose project (`nylorun-<name>`, the file's `name`),
5
- * volumes, network and ports. Everything else that varies (ports, the Postgres password,
6
- * UID/GID, the Host root, the images, the stack's name) comes from `docker/.env`.
2
+ * A local Tenant's Compose file (Runtime Architecture §14.3), written to
3
+ * `<Host root>/docker/compose.yaml` by `nylorun start`. Each local Tenant is one installation
4
+ * (tenancy.md §6): its own Compose project (`nylorun-<name>`, the file's `name`), volumes,
5
+ * network and ports. Everything else that varies (ports, the Postgres password, UID/GID, the
6
+ * Host root, the images, the Tenant's name) comes from `docker/.env`.
7
7
  *
8
- * The Tenant's state is the stack's Postgres database, executed through Restate, with its
8
+ * The Tenant's state is its Postgres database, executed through Restate, with its
9
9
  * history in s2-lite; the Runtime's /ready checks all three. Postgres initialises the
10
10
  * database with C collation (`--locale=C`) and runs with `wal_level=logical`: the stream
11
11
  * relay feeds s2-lite from the record over logical replication (Durable Streams), and
12
12
  * `max_slot_wal_keep_size` caps the WAL a stuck relay can hold. The Runtime creates the
13
- * Tenant on its first start, named after the stack (`NYLORUN_TENANT_NAME`), with the derived
13
+ * Tenant on its first start, with its name (`NYLORUN_TENANT_NAME`) and the derived
14
14
  * principals of `NYLORUN_DERIVED_PRINCIPALS` (`project` for the Project link).
15
15
  *
16
16
  * Restate signs requests to the Worker endpoint with the private key in
@@ -1,17 +1,17 @@
1
1
  import { PINNED_IMAGES } from "./images.js";
2
2
  /**
3
- * A local stack's Compose file (Runtime Architecture §14.3), written to
4
- * `<Host root>/docker/compose.yaml` by `nylorun start`. Each stack is one installation with
5
- * one Tenant (tenancy.md §6): its own Compose project (`nylorun-<name>`, the file's `name`),
6
- * volumes, network and ports. Everything else that varies (ports, the Postgres password,
7
- * UID/GID, the Host root, the images, the stack's name) comes from `docker/.env`.
3
+ * A local Tenant's Compose file (Runtime Architecture §14.3), written to
4
+ * `<Host root>/docker/compose.yaml` by `nylorun start`. Each local Tenant is one installation
5
+ * (tenancy.md §6): its own Compose project (`nylorun-<name>`, the file's `name`), volumes,
6
+ * network and ports. Everything else that varies (ports, the Postgres password, UID/GID, the
7
+ * Host root, the images, the Tenant's name) comes from `docker/.env`.
8
8
  *
9
- * The Tenant's state is the stack's Postgres database, executed through Restate, with its
9
+ * The Tenant's state is its Postgres database, executed through Restate, with its
10
10
  * history in s2-lite; the Runtime's /ready checks all three. Postgres initialises the
11
11
  * database with C collation (`--locale=C`) and runs with `wal_level=logical`: the stream
12
12
  * relay feeds s2-lite from the record over logical replication (Durable Streams), and
13
13
  * `max_slot_wal_keep_size` caps the WAL a stuck relay can hold. The Runtime creates the
14
- * Tenant on its first start, named after the stack (`NYLORUN_TENANT_NAME`), with the derived
14
+ * Tenant on its first start, with its name (`NYLORUN_TENANT_NAME`) and the derived
15
15
  * principals of `NYLORUN_DERIVED_PRINCIPALS` (`project` for the Project link).
16
16
  *
17
17
  * Restate signs requests to the Worker endpoint with the private key in
@@ -126,7 +126,7 @@ services:
126
126
  NYLORUN_HOME: /nylorun
127
127
  NYLORUN_PACKING: combined
128
128
  # The Tenant the Runtime creates on its first start (later starts open it).
129
- NYLORUN_TENANT_NAME: \${NYLORUN_STACK_NAME:?run nylorun start}
129
+ NYLORUN_TENANT_NAME: \${NYLORUN_TENANT_NAME:?run nylorun start}
130
130
  NYLORUN_DERIVED_PRINCIPALS: \${NYLORUN_DERIVED_PRINCIPALS:-project}
131
131
  # Model calls, remote MCP calls and deliveries go through the gateway, and vault writes
132
132
  # and token signing through its keys service: this container never reads a credential
@@ -136,12 +136,12 @@ services:
136
136
  NYLORUN_GATES_TOKEN: \${NYLORUN_GATES_TOKEN:?run nylorun start}
137
137
  NYLORUN_LISTEN_HOST: 0.0.0.0
138
138
  NYLORUN_LISTEN_PORT: "4000"
139
- # Host headers the Runtime accepts: the stack network name, and the
139
+ # Host headers the Runtime accepts: its name on the Compose network, and the
140
140
  # published port as clients on this machine address it.
141
141
  NYLORUN_ALLOWED_HOSTS: runtime:4000,localhost:\${NYLORUN_PORT},127.0.0.1:\${NYLORUN_PORT}
142
142
  NYLORUN_PUBLIC_URL: http://localhost:\${NYLORUN_PORT} # reported by /v1/admin/status
143
143
  # The Admin API on its own listener, published on loopback only; Studio reaches it on
144
- # the stack network. Port 4000 serves the Tenant API alone.
144
+ # the Compose network. Port 4000 serves the Tenant API alone.
145
145
  NYLORUN_ADMIN_LISTEN_PORT: "4001"
146
146
  NYLORUN_ADMIN_ALLOWED_HOSTS: runtime:4001,localhost:\${NYLORUN_ADMIN_PORT},127.0.0.1:\${NYLORUN_ADMIN_PORT}
147
147
  NYLORUN_DATABASE_URL: postgres://nylorun:\${NYLORUN_POSTGRES_PASSWORD}@postgres:5432/nylorun
@@ -158,7 +158,7 @@ services:
158
158
  host.docker.internal: host-gateway # the Docker host, also on Linux Docker Engine
159
159
  volumes:
160
160
  - \${NYLORUN_HOST_ROOT:?run nylorun start}:/nylorun # Host root
161
- # Empty and read-only over the vault key (keys/) and the stack's secrets (docker/):
161
+ # Empty and read-only over the vault key (keys/) and the Compose secrets (docker/):
162
162
  # only the gateway reads the key, and only Restate its private key.
163
163
  - type: tmpfs
164
164
  target: /nylorun/keys
@@ -192,6 +192,8 @@ services:
192
192
  NYLORUN_STUDIO_PUBLIC_PORT: \${NYLORUN_STUDIO_PORT}
193
193
  # Exact origins that may frame Studio (Babai Desktop); kept in .env.
194
194
  NYLORUN_STUDIO_FRAME_ANCESTORS: \${NYLORUN_STUDIO_FRAME_ANCESTORS:-}
195
+ # Studio's anonymous usage analytics; empty when telemetry is off.
196
+ NYLORUN_STUDIO_ANALYTICS_ID: \${NYLORUN_STUDIO_ANALYTICS_ID:-}
195
197
  volumes:
196
198
  - \${NYLORUN_HOST_ROOT}/host-credentials.json:/run/nylorun/host-credentials.json:ro
197
199
  ports:
@@ -45,7 +45,7 @@ export async function checkDocker(docker) {
45
45
  return {
46
46
  docker: {
47
47
  ok: false,
48
- problem: "Docker is required for the Nylorun stack, and the docker command was not found. Install Docker Desktop, OrbStack, Colima or another Docker engine with Compose v2, then retry.",
48
+ problem: "Docker is required for local Nylorun Tenants, and the docker command was not found. Install Docker Desktop, OrbStack, Colima or another Docker engine with Compose v2, then retry.",
49
49
  },
50
50
  };
51
51
  if (server.code !== 0)
@@ -29,8 +29,13 @@ export interface StackEnv {
29
29
  studioImage: string;
30
30
  /** Exact origins that may frame Studio, separated by spaces (persists). */
31
31
  studioFrameAncestors: string;
32
- /** The stack's name: the name of the Tenant its Runtime creates. */
33
- stackName: string;
32
+ /**
33
+ * The Google Analytics measurement id Studio reports page views to, or empty
34
+ * when telemetry is off. Decided again on every start.
35
+ */
36
+ studioAnalyticsId: string;
37
+ /** The Tenant's name, which the Runtime gives the Tenant it creates. */
38
+ tenantName: string;
34
39
  /**
35
40
  * Derived principals the Runtime registers on its Tenant, comma-separated (persists);
36
41
  * always includes `project`, the Project link's principal.
@@ -23,7 +23,8 @@ const KEYS = {
23
23
  runtimeImage: "NYLORUN_RUNTIME_IMAGE",
24
24
  studioImage: "NYLORUN_STUDIO_IMAGE",
25
25
  studioFrameAncestors: "NYLORUN_STUDIO_FRAME_ANCESTORS",
26
- stackName: "NYLORUN_STACK_NAME",
26
+ studioAnalyticsId: "NYLORUN_STUDIO_ANALYTICS_ID",
27
+ tenantName: "NYLORUN_TENANT_NAME",
27
28
  derivedPrincipals: "NYLORUN_DERIVED_PRINCIPALS",
28
29
  };
29
30
  /** Compose .env values: single quotes keep a value literal (no interpolation). */
@@ -76,10 +77,14 @@ export function renderEnvFile(env) {
76
77
  "# starts; change with nylorun start --studio-embed-origin <origin>.",
77
78
  line("studioFrameAncestors"),
78
79
  "",
79
- "# The stack's name, which its Runtime gives the Tenant it creates on the first",
80
+ "# Studio's anonymous usage analytics; empty when off. Set on every start: turn",
81
+ "# it off with nylorun telemetry disable or NYLORUN_TELEMETRY_DISABLED=1.",
82
+ line("studioAnalyticsId"),
83
+ "",
84
+ "# The Tenant's name, which the Runtime gives the Tenant it creates on the first",
80
85
  "# start, and the derived principals it registers on that Tenant (keys derived",
81
86
  "# from the admin key; `project` is the Project link's).",
82
- line("stackName"),
87
+ line("tenantName"),
83
88
  line("derivedPrincipals"),
84
89
  "",
85
90
  ].join("\n");
@@ -3,17 +3,17 @@ import type { StackPaths } from "./paths.js";
3
3
  * host.json and host-credentials.json (format 1), which `@nylorun/admin`,
4
4
  * Studio and the Runtime container all read.
5
5
  *
6
- * For the stack, host.json names the client-facing address: `localhost` and
6
+ * For a local Tenant, host.json names the client-facing address: `localhost` and
7
7
  * the published port. The container binds 0.0.0.0:4000 on its own.
8
8
  */
9
- /** Host name clients use for the stack. Studio's cookie is set on this name too. */
9
+ /** Host name clients use for a local Tenant. Studio's cookie is set on this name too. */
10
10
  export declare const STACK_CLIENT_HOST = "localhost";
11
11
  export interface HostConfigFile {
12
12
  format: 1;
13
13
  hostId: string;
14
14
  host: string;
15
15
  port: number;
16
- /** The operator listener's published port (the Admin API); absent on older stacks. */
16
+ /** The operator listener's published port (the Admin API); absent on older Host roots. */
17
17
  adminPort?: number;
18
18
  runtimeVersion?: string;
19
19
  [field: string]: unknown;
@@ -36,7 +36,7 @@ export declare function readAdminKey(paths: StackPaths): Promise<string | undefi
36
36
  /**
37
37
  * The Tenant's vault key in `keys/vault-kek` (32 random bytes, base64, mode 0600), which only the
38
38
  * gateway container mounts (F4.2): created if missing, or moved from `tenant/vault-kek`, where a
39
- * stack before F4.2 kept it. The gateway never creates it.
39
+ * Host root before F4.2 kept it. The gateway never creates it.
40
40
  */
41
41
  export declare function ensureVaultKey(paths: StackPaths): Promise<{
42
42
  created: boolean;
@@ -8,10 +8,10 @@ import { CliError } from "../errors.js";
8
8
  * host.json and host-credentials.json (format 1), which `@nylorun/admin`,
9
9
  * Studio and the Runtime container all read.
10
10
  *
11
- * For the stack, host.json names the client-facing address: `localhost` and
11
+ * For a local Tenant, host.json names the client-facing address: `localhost` and
12
12
  * the published port. The container binds 0.0.0.0:4000 on its own.
13
13
  */
14
- /** Host name clients use for the stack. Studio's cookie is set on this name too. */
14
+ /** Host name clients use for a local Tenant. Studio's cookie is set on this name too. */
15
15
  export const STACK_CLIENT_HOST = "localhost";
16
16
  const KNOWN_FORMAT = 1;
17
17
  const ADMIN_KEY_PATTERN = /^[0-9a-f]{64}$/;
@@ -87,7 +87,7 @@ export async function readAdminKey(paths) {
87
87
  /**
88
88
  * The Tenant's vault key in `keys/vault-kek` (32 random bytes, base64, mode 0600), which only the
89
89
  * gateway container mounts (F4.2): created if missing, or moved from `tenant/vault-kek`, where a
90
- * stack before F4.2 kept it. The gateway never creates it.
90
+ * Host root before F4.2 kept it. The gateway never creates it.
91
91
  */
92
92
  export async function ensureVaultKey(paths) {
93
93
  await mkdir(paths.keys, { recursive: true, mode: 0o700 });
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Images the local stack runs. The Runtime and Studio tags are pinned by this
2
+ * Images a local Tenant runs. The Runtime and Studio tags are pinned by this
3
3
  * CLI release; `NYLORUN_RUNTIME_IMAGE` and `NYLORUN_STUDIO_IMAGE` override them
4
4
  * (local builds, CI images). Postgres, Restate and s2-lite are the official
5
5
  * images, pinned here.
@@ -1,6 +1,6 @@
1
1
  import { pinnedVersion } from "./versions.js";
2
2
  /**
3
- * Images the local stack runs. The Runtime and Studio tags are pinned by this
3
+ * Images a local Tenant runs. The Runtime and Studio tags are pinned by this
4
4
  * CLI release; `NYLORUN_RUNTIME_IMAGE` and `NYLORUN_STUDIO_IMAGE` override them
5
5
  * (local builds, CI images). Postgres, Restate and s2-lite are the official
6
6
  * images, pinned here.
@@ -5,9 +5,9 @@ export { checkDocker } from "./docker.js";
5
5
  export type { Check, DockerChecks } from "./docker.js";
6
6
  /** Real dependencies: docker on PATH, global fetch, the terminal. */
7
7
  export declare function defaultStackDeps(env: Readonly<Record<string, string | undefined>>): StackDeps;
8
- /** Entry for `nylorun start|stop|status|logs|reset|studio|ls|delete|legacy`. */
8
+ /** Entry for `nylorun start|stop|status|logs|reset|studio|ls|delete`. */
9
9
  export declare function stackCommand(name: string, args: readonly string[], env: Readonly<Record<string, string | undefined>>): Promise<number>;
10
- /** `nylorun studio`, landing on `next` when given, else on the stack's Tenant. */
10
+ /** `nylorun studio`, landing on `next` when given, else on the Tenant's page. */
11
11
  export declare function studioCommand(args: readonly string[], env: Readonly<Record<string, string | undefined>>, options?: {
12
12
  next?: string;
13
13
  }): Promise<number>;
@@ -17,7 +17,11 @@ function browserCommand(env) {
17
17
  * Variables `docker/.env` sets for Compose: `nylorun start` writes them there, so the
18
18
  * environment must not override them when Compose interpolates the file.
19
19
  */
20
- const STACK_ENV_OWNED = ["NYLORUN_STACK_NAME", "NYLORUN_DERIVED_PRINCIPALS"];
20
+ const STACK_ENV_OWNED = [
21
+ "NYLORUN_TENANT_NAME",
22
+ "NYLORUN_DERIVED_PRINCIPALS",
23
+ "NYLORUN_STUDIO_ANALYTICS_ID",
24
+ ];
21
25
  /** Real dependencies: docker on PATH, global fetch, the terminal. */
22
26
  export function defaultStackDeps(env) {
23
27
  const interactive = Boolean(process.stdin.isTTY && process.stderr.isTTY);
@@ -71,11 +75,11 @@ export function defaultStackDeps(env) {
71
75
  },
72
76
  };
73
77
  }
74
- /** Entry for `nylorun start|stop|status|logs|reset|studio|ls|delete|legacy`. */
78
+ /** Entry for `nylorun start|stop|status|logs|reset|studio|ls|delete`. */
75
79
  export async function stackCommand(name, args, env) {
76
80
  return await runStackCommand(name, args, defaultStackDeps(env));
77
81
  }
78
- /** `nylorun studio`, landing on `next` when given, else on the stack's Tenant. */
82
+ /** `nylorun studio`, landing on `next` when given, else on the Tenant's page. */
79
83
  export async function studioCommand(args, env, options = {}) {
80
84
  return await runStudioCommand(args, defaultStackDeps(env), options);
81
85
  }
@@ -1,6 +1,6 @@
1
- /** Files under the Host root that the stack commands read and write. */
1
+ /** Files under the Host root that the nylorun commands read and write. */
2
2
  export interface StackPaths {
3
- /** The Host root (`~/.nylorun/stacks/<name>` or `NYLORUN_HOME`), bind-mounted at /nylorun. */
3
+ /** The Host root (`~/.nylorun/tenants/<name>` or `NYLORUN_HOME`), bind-mounted at /nylorun. */
4
4
  root: string;
5
5
  /** host.json: client-facing host and published port, no secrets. */
6
6
  config: string;
@@ -8,7 +8,7 @@ export interface StackPaths {
8
8
  credentials: string;
9
9
  /** host-state.json: written only by a launcher-managed Runtime. */
10
10
  state: string;
11
- /** stack.json: the stack's name and the project it was created for. */
11
+ /** tenant.json: the Tenant's name and the project it was created for. */
12
12
  record: string;
13
13
  /** The Tenant directory: homes, sandboxes, plugin data, logs. */
14
14
  tenant: string;
@@ -7,7 +7,7 @@ export function stackPaths(hostRoot) {
7
7
  config: join(root, "host.json"),
8
8
  credentials: join(root, "host-credentials.json"),
9
9
  state: join(root, "host-state.json"),
10
- record: join(root, "stack.json"),
10
+ record: join(root, "tenant.json"),
11
11
  tenant: join(root, "tenant"),
12
12
  keys: join(root, "keys"),
13
13
  vaultKey: join(root, "keys", "vault-kek"),
@@ -5,7 +5,7 @@ export declare const DEFAULT_PORTS: {
5
5
  readonly studio: 4161;
6
6
  readonly restate: 9070;
7
7
  };
8
- /** How the stack finds ports on 127.0.0.1; injectable for tests. */
8
+ /** How `nylorun start` finds ports on 127.0.0.1; injectable for tests. */
9
9
  export interface PortProbe {
10
10
  isFree(port: number): Promise<boolean>;
11
11
  /** A port the OS reports free right now. */
@@ -14,7 +14,7 @@ export interface PortProbe {
14
14
  export declare const loopbackPorts: PortProbe;
15
15
  /**
16
16
  * Choose a port: the persisted one if any (kept even when busy, because the
17
- * running stack may hold it), else the default when free, else a free one.
17
+ * running Tenant may hold it), else the default when free, else a free one.
18
18
  * Never returns a port in `taken`.
19
19
  */
20
20
  export declare function choosePort(probe: PortProbe, preferred: number, persisted: number | undefined, taken: ReadonlySet<number>): Promise<number>;
@@ -30,7 +30,7 @@ export const loopbackPorts = {
30
30
  };
31
31
  /**
32
32
  * Choose a port: the persisted one if any (kept even when busy, because the
33
- * running stack may hold it), else the default when free, else a free one.
33
+ * running Tenant may hold it), else the default when free, else a free one.
34
34
  * Never returns a port in `taken`.
35
35
  */
36
36
  export async function choosePort(probe, preferred, persisted, taken) {
@@ -10,7 +10,7 @@ export interface PreparedStack {
10
10
  /** True when this run chose the ports (first start). */
11
11
  firstRun: boolean;
12
12
  }
13
- /** Read the persisted stack settings without writing anything. */
13
+ /** Read the persisted Compose settings without writing anything. */
14
14
  export declare function readStackEnv(paths: Pick<StackPaths, "env">): Promise<import("./env-file.js").PersistedStackEnv | undefined>;
15
15
  /**
16
16
  * Write everything `docker compose up` needs under the Host root:
@@ -20,7 +20,7 @@ export declare function readStackEnv(paths: Pick<StackPaths, "env">): Promise<im
20
20
  */
21
21
  export declare function prepareStack(input: {
22
22
  paths: StackPaths;
23
- /** The stack's name (its Tenant's name) and its Compose project. */
23
+ /** The Tenant's name and its Compose project. */
24
24
  name: string;
25
25
  project: string;
26
26
  images: StackImages;
@@ -29,7 +29,7 @@ export declare function prepareStack(input: {
29
29
  /** Recorded in host.json; undefined keeps the recorded version. */
30
30
  runtimeVersion: string | undefined;
31
31
  ports: PortProbe;
32
- /** Ports other stacks keep in their `.env`: never chosen for a port not chosen yet. */
32
+ /** Ports other Tenants keep in their `.env`: never chosen for a port not chosen yet. */
33
33
  reserved?: ReadonlySet<number>;
34
34
  /** `NYLORUN_DERIVED_PRINCIPALS` from the environment of `nylorun start`; else kept. */
35
35
  derivedPrincipals?: string;
@@ -41,4 +41,6 @@ export declare function prepareStack(input: {
41
41
  add?: readonly string[];
42
42
  reset?: boolean;
43
43
  };
44
+ /** The measurement id Studio reports page views to; absent when telemetry is off. */
45
+ studioAnalyticsId?: string;
44
46
  }): Promise<PreparedStack>;
@@ -21,7 +21,7 @@ async function readText(path) {
21
21
  return undefined;
22
22
  }
23
23
  }
24
- /** Read the persisted stack settings without writing anything. */
24
+ /** Read the persisted Compose settings without writing anything. */
25
25
  export async function readStackEnv(paths) {
26
26
  const text = await readText(paths.env);
27
27
  return text === undefined ? undefined : parsePersisted(text);
@@ -76,7 +76,8 @@ export async function prepareStack(input) {
76
76
  runtimeImage: input.images.runtime,
77
77
  studioImage: input.images.studio,
78
78
  studioFrameAncestors,
79
- stackName: input.name,
79
+ studioAnalyticsId: input.studioAnalyticsId ?? "",
80
+ tenantName: input.name,
80
81
  derivedPrincipals: (input.derivedPrincipals?.trim()
81
82
  ? parseDerivedPrincipals(input.derivedPrincipals, "NYLORUN_DERIVED_PRINCIPALS")
82
83
  : (persisted.derivedPrincipals ?? ["project"])).join(","),
@@ -1,47 +1,50 @@
1
1
  /**
2
- * The machine's local stacks (tenancy.md §6): one installation per stack, each with its own
3
- * Host root `~/.nylorun/stacks/<name>/`, Compose project `nylorun-<name>`, ports and volumes.
4
- * `~/.nylorun` itself held the single stack of older releases (the legacy stack).
2
+ * The machine's local Tenants (tenancy.md §6): one installation per Tenant, each with its own
3
+ * Host root `~/.nylorun/tenants/<name>/`, Compose project `nylorun-<name>`, ports and volumes.
5
4
  */
6
- /** A stack name: also part of its Compose project, so Compose's rules apply. */
7
- export declare const STACK_NAME: RegExp;
8
- /** `~/.nylorun`: the stacks, and the legacy stack's files. Tests pass another directory. */
5
+ /** The Tenant a command acts on outside a project when nothing names one. */
6
+ export declare const DEFAULT_TENANT = "default";
7
+ /** A Tenant name: also part of its Compose project, so Compose's rules apply. */
8
+ export declare const TENANT_NAME: RegExp;
9
+ /** `~/.nylorun`: the Tenants and the machine's settings. Tests pass another directory. */
9
10
  export declare function defaultNylorunRoot(): string;
10
- export declare function stacksDir(base: string): string;
11
- export declare function stackRoot(base: string, name: string): string;
12
- export declare function assertStackName(name: string, source: string): string;
13
- /** A directory name as a stack name: lowercased, other characters as `-`, trimmed. */
14
- export declare function sanitizeStackName(raw: string): string;
15
- /** `stack.json` in a Host root: the stack's name and the project it was created for. */
16
- export interface StackRecord {
11
+ export declare function tenantsDir(base: string): string;
12
+ export declare function tenantRoot(base: string, name: string): string;
13
+ export declare function assertTenantName(name: string, source: string): string;
14
+ /** A directory name as a Tenant name: lowercased, other characters as `-`, trimmed. */
15
+ export declare function sanitizeTenantName(raw: string): string;
16
+ /** `tenant.json` in a Host root: the Tenant's name and the project it was created for. */
17
+ export interface TenantRecord {
17
18
  format: 1;
18
19
  name: string;
19
- /** The project directory `nylorun start` created the stack in; absent outside a project. */
20
+ /** The project directory `nylorun start` created the Tenant in; absent outside a project. */
20
21
  project?: string;
21
22
  }
22
- export declare function stackRecordPath(root: string): string;
23
- export declare function readStackRecord(root: string): Promise<StackRecord | undefined>;
24
- export declare function writeStackRecord(root: string, record: Omit<StackRecord, "format">): Promise<void>;
25
- export interface StackEntry {
23
+ export declare function tenantRecordPath(root: string): string;
24
+ export declare function readTenantRecord(root: string): Promise<TenantRecord | undefined>;
25
+ export declare function writeTenantRecord(root: string, record: Omit<TenantRecord, "format">): Promise<void>;
26
+ export interface TenantEntry {
26
27
  name: string;
27
28
  root: string;
28
- record?: StackRecord;
29
+ record: TenantRecord;
29
30
  }
30
- /** The stacks under `<base>/stacks`, by name. */
31
- export declare function listStacks(base: string): Promise<StackEntry[]>;
32
31
  /**
33
- * The stack name for a project without a link: the directory's name, or the first `-2`,
34
- * `-3`, … suffix that no stack of another project directory holds. A stack this project
32
+ * The Tenants under `<base>/tenants`, by name: directories with a `tenant.json` (releases
33
+ * before 0.4 kept other directories there).
34
+ */
35
+ export declare function listTenants(base: string): Promise<TenantEntry[]>;
36
+ /**
37
+ * The Tenant name for a project without a link: the directory's name, or the first `-2`,
38
+ * `-3`, … suffix that no Tenant of another project directory holds. A Tenant this project
35
39
  * directory created keeps its name.
36
40
  */
37
- export declare function chooseStackName(base: string, projectDir: string): Promise<string>;
38
- /** The single stack of older releases: Compose project `nylorun`, Host root `~/.nylorun`. */
39
- export interface LegacyStack {
40
- root: string;
41
- project: "nylorun";
42
- compose: string;
43
- env: string;
44
- }
45
- export declare function legacyStack(base: string): LegacyStack | undefined;
46
- /** What `nylorun legacy delete` removes from `~/.nylorun`: the old layout only, never `stacks/`. */
47
- export declare const LEGACY_ENTRIES: readonly ["host.json", "host-credentials.json", "host-state.json", "stack", "tenants", "home", "tmp", "trash"];
41
+ export declare function chooseTenantName(base: string, projectDir: string): Promise<string>;
42
+ /**
43
+ * Move the Host roots of nylorun 0.4 (`~/.nylorun/stacks/<name>/`) to `tenants/<name>/`, when
44
+ * that is free: `stack.json` becomes `tenant.json`, and `NYLORUN_STACK_NAME` becomes
45
+ * `NYLORUN_TENANT_NAME` in `docker/.env` (and `docker/compose.yaml`, until the next start
46
+ * rewrites it). `stacks/` goes when empty. They move rather than start fresh because Compose
47
+ * project names do not change: a fresh Host root under the same name would reuse the old
48
+ * volumes with new keys.
49
+ */
50
+ export declare function moveStackRoots(base: string, err: (line: string) => void): Promise<void>;