@nylorun/runtime 0.17.0-beta → 0.19.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 (223) hide show
  1. package/CHANGELOG.md +149 -0
  2. package/README.md +88 -58
  3. package/dist/adapters/execution/restate.d.ts +1 -3
  4. package/dist/adapters/execution/restate.js +4 -31
  5. package/dist/adapters/replication/pgoutput.js +1 -1
  6. package/dist/adapters/sandbox/local.js +1 -1
  7. package/dist/adapters/sandbox/virtual.js +1 -1
  8. package/dist/api/ag-ui/routes.js +1 -1
  9. package/dist/api/ag-ui/translate.d.ts +1 -3
  10. package/dist/api/ag-ui/translate.js +2 -17
  11. package/dist/api/components.d.ts +4871 -2614
  12. package/dist/api/components.js +12 -11
  13. package/dist/api/gate/routes.d.ts +7 -8
  14. package/dist/api/gate/routes.js +58 -52
  15. package/dist/api/http/app.d.ts +6 -0
  16. package/dist/api/http/app.js +18 -14
  17. package/dist/api/http/define.d.ts +14 -2
  18. package/dist/api/http/define.js +34 -15
  19. package/dist/api/http/routes/access.d.ts +3 -3
  20. package/dist/api/http/routes/access.js +18 -17
  21. package/dist/api/http/routes/artifacts.js +2 -4
  22. package/dist/api/http/routes/files.d.ts +8 -0
  23. package/dist/api/http/routes/files.js +77 -0
  24. package/dist/api/http/routes/keys.d.ts +10 -0
  25. package/dist/api/http/routes/keys.js +64 -0
  26. package/dist/api/http/routes/me.js +5 -2
  27. package/dist/api/http/routes/reads.d.ts +66 -0
  28. package/dist/api/http/routes/reads.js +127 -0
  29. package/dist/api/http/routes/sandboxes.js +7 -4
  30. package/dist/api/http/routes/sessions.js +25 -8
  31. package/dist/api/http/routes/tenant.js +15 -18
  32. package/dist/api/http/routes/vaults.d.ts +10 -9
  33. package/dist/api/http/routes/vaults.js +27 -23
  34. package/dist/api/openapi.d.ts +10 -11
  35. package/dist/api/openapi.js +291 -61
  36. package/dist/artifacts/links.js +1 -1
  37. package/dist/core/flow-host.d.ts +44 -23
  38. package/dist/core/flow-host.js +88 -106
  39. package/dist/core/provider.d.ts +4 -1
  40. package/dist/core/provider.js +6 -1
  41. package/dist/core/sandbox-routes.d.ts +0 -9
  42. package/dist/core/sandbox-routes.js +2 -21
  43. package/dist/execution/memory.d.ts +4 -5
  44. package/dist/execution/memory.js +11 -25
  45. package/dist/execution/types.d.ts +3 -33
  46. package/dist/execution/types.js +2 -12
  47. package/dist/gates/http-tool.d.ts +86 -0
  48. package/dist/gates/http-tool.js +197 -0
  49. package/dist/gates/mcp-handler.d.ts +3 -0
  50. package/dist/gates/mcp-handler.js +1 -3
  51. package/dist/gates/meter.d.ts +2 -2
  52. package/dist/gates/meter.js +6 -0
  53. package/dist/gates/tenant-vaults.d.ts +5 -9
  54. package/dist/gates/tool-calls.d.ts +7 -15
  55. package/dist/gates/tool-calls.js +4 -4
  56. package/dist/gates/tool-client.d.ts +1 -1
  57. package/dist/gates/tool-client.js +23 -47
  58. package/dist/gates/tool-contract.d.ts +27 -39
  59. package/dist/gates/tool-contract.js +30 -21
  60. package/dist/gates/tool-gate.d.ts +25 -24
  61. package/dist/gates/tool-gate.js +11 -7
  62. package/dist/harness/calls.d.ts +10 -4
  63. package/dist/harness/calls.js +15 -6
  64. package/dist/harness/executors.d.ts +1 -1
  65. package/dist/harness/executors.js +17 -12
  66. package/dist/harness/main.d.ts +2 -2
  67. package/dist/harness/main.js +5 -13
  68. package/dist/harness/service.d.ts +4 -5
  69. package/dist/harness/service.js +9 -2
  70. package/dist/harness-api/in-process.js +2 -2
  71. package/dist/harness-api/record.d.ts +6 -3
  72. package/dist/harness-api/record.js +65 -72
  73. package/dist/harness-api/server.d.ts +1 -9
  74. package/dist/harness-api/server.js +19 -17
  75. package/dist/harness-api/start.js +1 -5
  76. package/dist/harness-api/workspace.js +2 -3
  77. package/dist/harness-api/ws-server.js +1 -1
  78. package/dist/host/app.d.ts +2 -9
  79. package/dist/host/app.js +15 -25
  80. package/dist/host/config-for.d.ts +1 -5
  81. package/dist/host/config-for.js +0 -3
  82. package/dist/host/config.d.ts +0 -5
  83. package/dist/host/create-host.d.ts +3 -33
  84. package/dist/host/create-host.js +18 -94
  85. package/dist/host/environment.d.ts +0 -3
  86. package/dist/host/environment.js +0 -9
  87. package/dist/host/gates.d.ts +4 -1
  88. package/dist/host/gates.js +3 -2
  89. package/dist/host/http.d.ts +1 -2
  90. package/dist/host/http.js +1 -7
  91. package/dist/host/index.d.ts +2 -2
  92. package/dist/host/index.js +2 -2
  93. package/dist/host/main.js +27 -34
  94. package/dist/host/operate.d.ts +29 -0
  95. package/dist/host/operate.js +223 -0
  96. package/dist/host/stack-config.d.ts +12 -12
  97. package/dist/host/stack-config.js +5 -32
  98. package/dist/index.d.ts +1 -1
  99. package/dist/index.js +1 -1
  100. package/dist/infra/workers.d.ts +1 -1
  101. package/dist/keys/keys.js +2 -2
  102. package/dist/management-openapi.json +6491 -0
  103. package/dist/mcp/connect.d.ts +8 -4
  104. package/dist/mcp/connect.js +6 -26
  105. package/dist/mcp/pool.d.ts +5 -9
  106. package/dist/mcp/pool.js +8 -19
  107. package/dist/mcp/snapshot.d.ts +8 -2
  108. package/dist/mcp/snapshot.js +29 -2
  109. package/dist/media.d.ts +1 -1
  110. package/dist/media.js +1 -1
  111. package/dist/model/pi-model.js +3 -0
  112. package/dist/openapi.json +4700 -12350
  113. package/dist/reads/access.d.ts +4 -0
  114. package/dist/reads/access.js +12 -0
  115. package/dist/reads/cursor.d.ts +11 -0
  116. package/dist/reads/cursor.js +80 -0
  117. package/dist/reads/types.d.ts +25 -0
  118. package/dist/reads/types.js +1 -0
  119. package/dist/sandbox/manager.d.ts +16 -0
  120. package/dist/sandbox/manager.js +40 -0
  121. package/dist/sandbox/session-sandbox.js +13 -3
  122. package/dist/sandbox/skills.d.ts +13 -0
  123. package/dist/sandbox/skills.js +46 -0
  124. package/dist/sandbox/types.d.ts +2 -2
  125. package/dist/store/ownership.d.ts +9 -0
  126. package/dist/store/ownership.js +13 -0
  127. package/dist/store/postgres/connect.d.ts +2 -0
  128. package/dist/store/postgres/connect.js +29 -0
  129. package/dist/store/postgres/drizzle/0011_key_roles.sql +3 -0
  130. package/dist/store/postgres/drizzle/0012_session_reads.sql +8 -0
  131. package/dist/store/postgres/drizzle/0013_definition_files.sql +16 -0
  132. package/dist/store/postgres/drizzle/0014_action_endpoints_removed.sql +2 -0
  133. package/dist/store/postgres/drizzle/meta/_journal.json +28 -0
  134. package/dist/store/postgres/reads.d.ts +3 -0
  135. package/dist/store/postgres/reads.js +272 -0
  136. package/dist/store/postgres/schema.d.ts +294 -489
  137. package/dist/store/postgres/schema.js +41 -76
  138. package/dist/store/postgres/store.js +51 -154
  139. package/dist/store/postgres/tenant.d.ts +34 -2
  140. package/dist/store/postgres/tenant.js +16 -32
  141. package/dist/store/types.d.ts +27 -96
  142. package/dist/store/types.js +0 -1
  143. package/dist/streams/control.d.ts +0 -2
  144. package/dist/streams/control.js +0 -5
  145. package/dist/streams/types.d.ts +1 -10
  146. package/dist/tenant/advance.d.ts +3 -3
  147. package/dist/tenant/advance.js +10 -7
  148. package/dist/tenant/auth.d.ts +14 -9
  149. package/dist/tenant/auth.js +24 -28
  150. package/dist/tenant/cause.d.ts +3 -3
  151. package/dist/tenant/cause.js +1 -1
  152. package/dist/tenant/commands.d.ts +2 -18
  153. package/dist/tenant/commands.js +35 -172
  154. package/dist/tenant/context.d.ts +14 -24
  155. package/dist/tenant/definition-files.d.ts +24 -0
  156. package/dist/tenant/definition-files.js +103 -0
  157. package/dist/tenant/effects.d.ts +18 -20
  158. package/dist/tenant/effects.js +56 -119
  159. package/dist/tenant/ephemeral.d.ts +7 -6
  160. package/dist/tenant/ephemeral.js +3 -11
  161. package/dist/tenant/host-token.js +1 -1
  162. package/dist/tenant/jwt.js +1 -1
  163. package/dist/tenant/module.d.ts +1 -4
  164. package/dist/tenant/module.js +3 -12
  165. package/dist/tenant/operator-keys.d.ts +34 -8
  166. package/dist/tenant/operator-keys.js +50 -18
  167. package/dist/tenant/outbound.d.ts +10 -1
  168. package/dist/tenant/outbound.js +44 -27
  169. package/dist/tenant/paths.d.ts +1 -1
  170. package/dist/tenant/paths.js +1 -3
  171. package/dist/tenant/principals.d.ts +11 -2
  172. package/dist/tenant/principals.js +27 -8
  173. package/dist/tenant/run-token.js +3 -3
  174. package/dist/tenant/runtime.d.ts +4 -6
  175. package/dist/tenant/runtime.js +19 -18
  176. package/dist/tenant/sandboxes.d.ts +4 -1
  177. package/dist/tenant/sandboxes.js +11 -0
  178. package/dist/tenant/scheduler.d.ts +1 -5
  179. package/dist/tenant/scheduler.js +2 -5
  180. package/dist/tenant/session-streams.d.ts +2 -1
  181. package/dist/tenant/session-streams.js +39 -5
  182. package/dist/tenant/session.d.ts +8 -41
  183. package/dist/tenant/session.js +0 -37
  184. package/dist/tenant/sessions.js +16 -8
  185. package/dist/tenant/signing-keys.d.ts +3 -3
  186. package/dist/tenant/signing-keys.js +5 -5
  187. package/dist/tenant/skill-tool.d.ts +20 -0
  188. package/dist/tenant/skill-tool.js +72 -0
  189. package/dist/tenant/slim.d.ts +1 -1
  190. package/dist/tenant/slim.js +1 -1
  191. package/dist/tenant/status.js +7 -12
  192. package/dist/tenant/store-pg.d.ts +15 -0
  193. package/dist/tenant/store-pg.js +7 -3
  194. package/dist/tenant/streams.d.ts +3 -10
  195. package/dist/tenant/streams.js +1 -24
  196. package/dist/tenant/sweep.js +0 -5
  197. package/dist/tenant/transcript.d.ts +2 -2
  198. package/dist/tenant/transcript.js +2 -2
  199. package/dist/tenant/types.d.ts +15 -22
  200. package/dist/tenant/worker.d.ts +1 -3
  201. package/dist/tenant/worker.js +3 -8
  202. package/dist/vault/sources.d.ts +7 -1
  203. package/dist/vault/sources.js +22 -11
  204. package/dist/version.d.ts +1 -1
  205. package/dist/version.js +1 -1
  206. package/package.json +4 -4
  207. package/dist/admin-openapi.json +0 -904
  208. package/dist/api/http/routes/actions.d.ts +0 -8
  209. package/dist/api/http/routes/actions.js +0 -75
  210. package/dist/api/http/routes/endpoints.d.ts +0 -7
  211. package/dist/api/http/routes/endpoints.js +0 -100
  212. package/dist/host/admin-api.d.ts +0 -30
  213. package/dist/host/admin-api.js +0 -140
  214. package/dist/mcp/stdio.d.ts +0 -17
  215. package/dist/mcp/stdio.js +0 -82
  216. package/dist/tenant/actions.d.ts +0 -14
  217. package/dist/tenant/actions.js +0 -29
  218. package/dist/tenant/delivery-token.d.ts +0 -41
  219. package/dist/tenant/delivery-token.js +0 -104
  220. package/dist/tenant/delivery.d.ts +0 -62
  221. package/dist/tenant/delivery.js +0 -481
  222. package/dist/tenant/endpoints.d.ts +0 -67
  223. package/dist/tenant/endpoints.js +0 -90
@@ -0,0 +1,223 @@
1
+ /**
2
+ * `nylorun-operate`: the Host's one-shot operator command, run inside the runtime container
3
+ * (`docker compose exec runtime nylorun-operate …`, `kubectl exec … -- nylorun-operate …`). It
4
+ * reads the Tenant's database from `NYLORUN_DATABASE_URL`, as the Host does, does one job and
5
+ * exits. Being able to run it is the authorization: whoever can exec into the container holds
6
+ * the installation. It never migrates or creates the Tenant: the Host does that.
7
+ *
8
+ * nylorun-operate status [--json]
9
+ * nylorun-operate keys list [--json]
10
+ * nylorun-operate keys put <id> [--role application|management] [--json]
11
+ * nylorun-operate keys rm <id> [--json]
12
+ *
13
+ * `status` says whether the Tenant is open and, when it is not, why: from the database (no
14
+ * Tenant yet, an old layout, a schema newer or older than this Runtime) and from the running
15
+ * Host's `/ready` on this container's listen port. It needs no key, so it works when the Tenant
16
+ * cannot open. `keys put` prints the new key once on stdout (with `--json`, the whole
17
+ * response). Exit codes: 0 done (`status`: the Tenant is open), 1 refused (an id, a role),
18
+ * 2 the Tenant cannot be opened (`status` still prints it), 64 usage.
19
+ */
20
+ import { pathToFileURL } from "node:url";
21
+ import { HOST_PROTOCOL } from "@nylorun/core/compatibility";
22
+ import { createPostgresClient } from "../store/postgres/connect.js";
23
+ import { database } from "../store/postgres/db.js";
24
+ import { assertCurrentLayout, expectedSchemaVersion, readSchemaVersion, } from "../store/postgres/migrate.js";
25
+ import { createPostgresSessionStore } from "../store/postgres/store.js";
26
+ import { readTenantEnvelope } from "../store/postgres/tenant.js";
27
+ import { openError, TenantOpenError } from "../tenant/cause.js";
28
+ import { operatorKeys } from "../tenant/operator-keys.js";
29
+ import { RUNTIME_VERSION } from "../version.js";
30
+ import { DEFAULT_CONTAINER_LISTEN_PORT } from "./stack-config.js";
31
+ export const EXIT_REFUSED = 1;
32
+ export const EXIT_TENANT = 2;
33
+ export const EXIT_USAGE = 64;
34
+ const USAGE = `Usage:
35
+ nylorun-operate status [--json]
36
+ nylorun-operate keys list [--json]
37
+ nylorun-operate keys put <id> [--role application|management] [--json]
38
+ nylorun-operate keys rm <id> [--json]`;
39
+ class Exit extends Error {
40
+ code;
41
+ constructor(code, message) {
42
+ super(message);
43
+ this.code = code;
44
+ }
45
+ }
46
+ /** Runs one command; resolves to the exit code. */
47
+ export async function runOperate(argv, io) {
48
+ try {
49
+ if (argv[0] === "status") {
50
+ const json = argv[1] === "--json";
51
+ if (argv.length > (json ? 2 : 1))
52
+ throw new Exit(EXIT_USAGE, USAGE);
53
+ return await status(io, json);
54
+ }
55
+ const command = parse(argv);
56
+ const url = io.env.NYLORUN_DATABASE_URL;
57
+ if (!url)
58
+ throw new Exit(EXIT_TENANT, "NYLORUN_DATABASE_URL is not set: run this inside the runtime container");
59
+ const sql = createPostgresClient(url, { max: 1 });
60
+ try {
61
+ const keys = operatorKeys(await openStore(sql));
62
+ return await command(keys, io);
63
+ }
64
+ finally {
65
+ await sql.end({ timeout: 5 });
66
+ }
67
+ }
68
+ catch (error) {
69
+ if (error instanceof Exit) {
70
+ io.err(error.message);
71
+ return error.code;
72
+ }
73
+ io.err(`nylorun-operate failed: ${error instanceof Error ? error.message : String(error)}`);
74
+ return EXIT_TENANT;
75
+ }
76
+ }
77
+ function parse(argv) {
78
+ const [group, verb, ...rest] = argv;
79
+ if (group !== "keys")
80
+ throw new Exit(EXIT_USAGE, USAGE);
81
+ const json = rest.includes("--json");
82
+ const args = rest.filter((arg) => arg !== "--json");
83
+ switch (verb) {
84
+ case "list":
85
+ if (args.length > 0)
86
+ throw new Exit(EXIT_USAGE, USAGE);
87
+ return async (keys, io) => {
88
+ const list = await keys.list();
89
+ if (json)
90
+ io.out(JSON.stringify({ keys: list }));
91
+ else
92
+ for (const key of list)
93
+ io.out(`${key.id}\t${key.role}\t${key.createdAt}`);
94
+ return 0;
95
+ };
96
+ case "put": {
97
+ const [id, ...flags] = args;
98
+ if (!id || id.startsWith("-"))
99
+ throw new Exit(EXIT_USAGE, USAGE);
100
+ let role = "application";
101
+ if (flags.length > 0) {
102
+ const value = flags[0] === "--role" ? flags[1] : undefined;
103
+ if (flags.length !== 2 || (value !== "application" && value !== "management"))
104
+ throw new Exit(EXIT_USAGE, USAGE);
105
+ role = value;
106
+ }
107
+ return async (keys, io) => {
108
+ const put = await keys.put(id, role);
109
+ if ("reason" in put)
110
+ throw new Exit(EXIT_REFUSED, put.message);
111
+ if (json)
112
+ io.out(JSON.stringify(put));
113
+ else {
114
+ io.out(put.key);
115
+ io.err(`${put.rotated ? "Rotated" : "Created"} ${put.role} key ${put.id}. It is shown this once.`);
116
+ }
117
+ return 0;
118
+ };
119
+ }
120
+ case "rm": {
121
+ const [id] = args;
122
+ if (!id || args.length !== 1)
123
+ throw new Exit(EXIT_USAGE, USAGE);
124
+ return async (keys, io) => {
125
+ const deleted = await keys.delete(id);
126
+ if (typeof deleted !== "boolean")
127
+ throw new Exit(EXIT_REFUSED, deleted.message);
128
+ if (json)
129
+ io.out(JSON.stringify({ id, deleted }));
130
+ else
131
+ io.err(deleted ? `Deleted key ${id}.` : `There is no key ${id}.`);
132
+ return 0;
133
+ };
134
+ }
135
+ default:
136
+ throw new Exit(EXIT_USAGE, USAGE);
137
+ }
138
+ }
139
+ async function status(io, json) {
140
+ const tenant = await tenantStatus(io);
141
+ const report = {
142
+ version: RUNTIME_VERSION,
143
+ protocol: { min: HOST_PROTOCOL.min, max: HOST_PROTOCOL.max, features: [...HOST_PROTOCOL.features] },
144
+ tenant,
145
+ };
146
+ if (json)
147
+ io.out(JSON.stringify(report));
148
+ else {
149
+ io.out(`Runtime ${report.version}, protocol ${report.protocol.min}–${report.protocol.max}`);
150
+ const named = tenant.name ? `${tenant.name} (${tenant.id})` : "none";
151
+ io.out(`Tenant ${named}: ${tenant.state}${tenant.cause ? ` (${tenant.cause})` : ""}`);
152
+ if (tenant.message)
153
+ io.out(tenant.message);
154
+ }
155
+ return tenant.state === "open" ? 0 : EXIT_TENANT;
156
+ }
157
+ /** The Tenant from its database, then from the running Host's `/ready`. */
158
+ async function tenantStatus(io) {
159
+ const url = io.env.NYLORUN_DATABASE_URL;
160
+ if (!url)
161
+ return unavailable(null, "NYLORUN_DATABASE_URL is not set: run this inside the runtime container");
162
+ const sql = createPostgresClient(url, { max: 1 });
163
+ let envelope;
164
+ try {
165
+ const db = database(sql);
166
+ await assertCurrentLayout(db);
167
+ envelope = await readTenantEnvelope(db);
168
+ if (!envelope)
169
+ return unavailable(null, "The database holds no Tenant yet: the Runtime creates it when it starts");
170
+ const version = (await readSchemaVersion(db)) ?? 0;
171
+ const expected = expectedSchemaVersion();
172
+ if (version > expected)
173
+ throw openError("schema-too-new", `The Tenant's schema is at version ${version}, this Runtime's is ${expected}: it was migrated by a newer Runtime`);
174
+ if (version < expected)
175
+ return unavailable(envelope, `The Tenant's schema is at version ${version}, this Runtime's is ${expected}: the Runtime migrates it when it starts; if it is running, its log says why it did not`);
176
+ }
177
+ catch (error) {
178
+ if (error instanceof TenantOpenError)
179
+ return { ...unavailable(envelope ?? null, `${error.message}. Repair: ${error.repair}`), cause: error.code };
180
+ return unavailable(envelope ?? null, `The database cannot be read: ${error instanceof Error ? error.message : String(error)}`);
181
+ }
182
+ finally {
183
+ await sql.end({ timeout: 5 });
184
+ }
185
+ const port = io.env.NYLORUN_LISTEN_PORT ?? String(DEFAULT_CONTAINER_LISTEN_PORT);
186
+ const ready = `http://127.0.0.1:${port}/ready`;
187
+ let answer;
188
+ try {
189
+ const response = await (io.fetch ?? fetch)(ready, { signal: AbortSignal.timeout(5000) });
190
+ answer = (await response.json());
191
+ }
192
+ catch {
193
+ return unavailable(envelope, `The Runtime is not answering at ${ready}: it is stopped or still starting`);
194
+ }
195
+ if (answer.checks?.tenant !== true)
196
+ return unavailable(envelope, "The Runtime is running but has not opened the Tenant: its log names the cause");
197
+ return { id: envelope.id, name: envelope.name, state: "open" };
198
+ }
199
+ function unavailable(envelope, message) {
200
+ return { id: envelope?.id ?? null, name: envelope?.name ?? null, state: "unavailable", message };
201
+ }
202
+ /** The Tenant's store, when the Host has created and migrated it to this Runtime's schema. */
203
+ async function openStore(sql) {
204
+ const db = database(sql);
205
+ const envelope = await readTenantEnvelope(db).catch((error) => {
206
+ throw new Exit(EXIT_TENANT, `The Tenant's database cannot be read: ${error instanceof Error ? error.message : String(error)}`);
207
+ });
208
+ if (!envelope)
209
+ throw new Exit(EXIT_TENANT, "The database holds no Tenant yet: start the Runtime first");
210
+ const version = await readSchemaVersion(db);
211
+ const expected = expectedSchemaVersion();
212
+ if (version !== expected)
213
+ throw new Exit(EXIT_TENANT, `The Tenant's schema is at version ${version ?? "none"}, this Runtime's is ${expected}: start the Runtime to migrate it, or run the Runtime's own image`);
214
+ return createPostgresSessionStore({ sql, tenantId: envelope.id, schemaVersion: expected });
215
+ }
216
+ if (import.meta.url === pathToFileURL(process.argv[1] ?? "").href) {
217
+ const code = await runOperate(process.argv.slice(2), {
218
+ env: process.env,
219
+ out: (line) => process.stdout.write(`${line}\n`),
220
+ err: (line) => process.stderr.write(`${line}\n`),
221
+ });
222
+ process.exitCode = code;
223
+ }
@@ -123,7 +123,7 @@ export interface HarnessServiceConfig {
123
123
  pod?: PodHostConfig;
124
124
  /** `NYLORUN_GATES_URL`: the gates service its model and MCP calls cross, with run tokens. */
125
125
  gatesUrl: string;
126
- /** `NYLORUN_HARNESS_ROOT`: its sandboxes, plugin data, home and tmp. Default `/harness`. */
126
+ /** `NYLORUN_HARNESS_ROOT`: its sandboxes. Default `/harness`. */
127
127
  root: string;
128
128
  /** `/health` on `127.0.0.1:<NYLORUN_HARNESS_HEALTH_PORT>` (default 4300). */
129
129
  healthPort: number;
@@ -149,7 +149,7 @@ export interface StackConfig {
149
149
  sandboxes?: SandboxesConfig;
150
150
  /**
151
151
  * Present when the process runs core or loop and `NYLORUN_GATES_URL` is set: its model calls,
152
- * remote MCP calls and Action deliveries cross the gates service. Required for loop in
152
+ * remote MCP calls and HTTP tool calls cross the gates service. Required for loop in
153
153
  * container mode; outside a container (a development Host, tests) the loop may make them in
154
154
  * its own process.
155
155
  */
@@ -172,19 +172,13 @@ export interface StackConfig {
172
172
  listen?: ContainerListen;
173
173
  endpoints: StackEndpoints;
174
174
  /**
175
- * The URL clients use to reach this Host (`NYLORUN_PUBLIC_URL`), reported by
176
- * `/v1/admin/status`. In container mode the bind address (`0.0.0.0:4000`)
177
- * means nothing outside the container.
175
+ * The URL clients use to reach this Host (`NYLORUN_PUBLIC_URL`). In container mode the bind
176
+ * address (`0.0.0.0:4000`) means nothing outside the container.
178
177
  */
179
178
  publicUrl?: string;
180
179
  /**
181
- * The operator listener in container mode (`NYLORUN_ADMIN_LISTEN_PORT`, `…_HOST`,
182
- * `…_ALLOWED_HOSTS`). Absent: one listener serves the Admin API and the Tenant API.
183
- */
184
- operator?: ContainerListen;
185
- /**
186
- * How the Runtime may call Action endpoints: `NYLORUN_ENDPOINT_LOOPBACK=docker-host` (the local
187
- * stack: `localhost` means the machine that runs Docker), `NYLORUN_ENDPOINT_PRIVATE`
180
+ * How the Runtime may call MCP servers and HTTP tools: `NYLORUN_ENDPOINT_LOOPBACK=docker-host`
181
+ * (the local stack: `localhost` means the machine that runs Docker), `NYLORUN_ENDPOINT_PRIVATE`
188
182
  * (`allow` or `refuse`) and `NYLORUN_ENDPOINT_HTTP` (`allow` or `refuse`).
189
183
  */
190
184
  delivery?: {
@@ -228,6 +222,12 @@ export interface TenantSettings {
228
222
  * `trusted-issuers`), read once at boot (`host/main.ts`). Absent: no issuer is trusted.
229
223
  */
230
224
  identityFile?: string;
225
+ /**
226
+ * `NYLORUN_MANAGEMENT_KEY_FILE`: a file holding a management key (64 hex characters), which
227
+ * the Host registers as the principal `bootstrap` at every start, replacing its key when the
228
+ * file changed (protocol 8). For installations where no one can run `nylorun-operate`.
229
+ */
230
+ managementKeyFile?: string;
231
231
  }
232
232
  export declare class StackConfigError extends Error {
233
233
  constructor(message: string);
@@ -225,30 +225,6 @@ function parseListen(env) {
225
225
  const allowedHosts = [...new Set([...explicit, ...loopbackForms(port)])];
226
226
  return { host, port, allowedHosts };
227
227
  }
228
- function parseAdminListen(env) {
229
- const rawPort = read(env, "NYLORUN_ADMIN_LISTEN_PORT");
230
- const rawHost = read(env, "NYLORUN_ADMIN_LISTEN_HOST");
231
- const rawAllowed = read(env, "NYLORUN_ADMIN_ALLOWED_HOSTS");
232
- if (rawPort === undefined) {
233
- if (rawHost !== undefined || rawAllowed !== undefined)
234
- throw new StackConfigError("NYLORUN_ADMIN_LISTEN_PORT is required with NYLORUN_ADMIN_LISTEN_HOST or NYLORUN_ADMIN_ALLOWED_HOSTS");
235
- return undefined;
236
- }
237
- const host = rawHost ?? DEFAULT_CONTAINER_LISTEN_HOST;
238
- if (/\s|\//.test(host))
239
- throw new StackConfigError(`NYLORUN_ADMIN_LISTEN_HOST is not an address: ${host}`);
240
- const port = parsePort("NYLORUN_ADMIN_LISTEN_PORT", rawPort);
241
- const explicit = rawAllowed === undefined
242
- ? []
243
- : rawAllowed
244
- .split(",")
245
- .map((entry) => entry.trim())
246
- .filter((entry) => entry !== "")
247
- .map((entry) => normalizeAllowedHost("NYLORUN_ADMIN_ALLOWED_HOSTS", entry));
248
- if (explicit.length === 0 && !isLoopbackAddress(host))
249
- throw new StackConfigError(`NYLORUN_ADMIN_ALLOWED_HOSTS is required when NYLORUN_ADMIN_LISTEN_HOST is ${host}: list the Host headers operators send, e.g. runtime:${port},localhost:<published port>`);
250
- return { host, port, allowedHosts: [...new Set([...explicit, ...loopbackForms(port)])] };
251
- }
252
228
  const IDENTITY_KEY = /^publickeyv1_[1-9A-HJ-NP-Za-km-z]{32,64}$/;
253
229
  function parseIdentityKeys(env) {
254
230
  const raw = read(env, "NYLORUN_RESTATE_IDENTITY_KEY");
@@ -271,15 +247,12 @@ export function parseStackConfig(env, argv) {
271
247
  // The image sets NYLORUN_LISTEN_*: only the API's processes read them.
272
248
  const servesApi = services.has("core") || services.has("loop");
273
249
  const listen = servesApi ? parseListen(env) : undefined;
274
- const operator = servesApi ? parseAdminListen(env) : undefined;
275
250
  const gates = services.has("gates") || services.has("keys") ? parseGates(env) : undefined;
276
251
  const egress = services.has("egress") ? parseEgress(env) : undefined;
277
- // The gates service's clients: the loop's model and tool calls, and core's endpoint pings.
252
+ // The gates service's clients: the loop's model and tool calls.
278
253
  const modelGate = servesApi ? parseModelGate(env) : undefined;
279
254
  // The keys service is the gateway's unless NYLORUN_KEYS_URL names another listener.
280
255
  const keys = servesApi ? (parseKeysEndpoint(env) ?? modelGate) : undefined;
281
- if (operator && listen && operator.port === listen.port)
282
- throw new StackConfigError("NYLORUN_ADMIN_LISTEN_PORT must differ from NYLORUN_LISTEN_PORT");
283
256
  if (services.has("loop") && listen && !modelGate)
284
257
  throw new StackConfigError("NYLORUN_GATES_URL is required for the loop service in a container: model calls go through the gates service (the gateway container), so the loop never holds a model credential. Set NYLORUN_GATES_URL and NYLORUN_GATES_TOKEN (`nylorun start` sets both)");
285
258
  const rawPacking = read(env, "NYLORUN_PACKING");
@@ -326,9 +299,8 @@ export function parseStackConfig(env, argv) {
326
299
  const harnessListener = harnessMode === "remote" || sandboxes
327
300
  ? parseHarnessListener(env, harnessMode === "remote")
328
301
  : undefined;
329
- if (harnessListener &&
330
- [listen?.port, operator?.port].includes(harnessListener.listen.port))
331
- throw new StackConfigError("NYLORUN_HARNESS_LISTEN_PORT must differ from NYLORUN_LISTEN_PORT and NYLORUN_ADMIN_LISTEN_PORT");
302
+ if (harnessListener && listen?.port === harnessListener.listen.port)
303
+ throw new StackConfigError("NYLORUN_HARNESS_LISTEN_PORT must differ from NYLORUN_LISTEN_PORT");
332
304
  const delivery = parseDelivery(env);
333
305
  const tenant = servesApi ? parseTenant(env) : undefined;
334
306
  const objectStore = parseObjectStore(env);
@@ -346,7 +318,6 @@ export function parseStackConfig(env, argv) {
346
318
  ...(harnessMode ? { harnessMode } : {}),
347
319
  ...(harnessListener ? { harnessListener } : {}),
348
320
  ...(sandboxes ? { sandboxes } : {}),
349
- ...(operator ? { operator } : {}),
350
321
  ...(delivery ? { delivery } : {}),
351
322
  ...(tenant ? { tenant } : {}),
352
323
  ...(objectStore ? { objectStore } : {}),
@@ -379,10 +350,12 @@ function parseTenant(env) {
379
350
  if (id !== undefined && !isTenantId(id))
380
351
  throw new StackConfigError(`NYLORUN_TENANT_ID must be a Tenant id (tn_ and 26 Crockford characters), not ${id}`);
381
352
  const identityFile = read(env, "NYLORUN_IDENTITY_FILE");
353
+ const managementKeyFile = read(env, "NYLORUN_MANAGEMENT_KEY_FILE");
382
354
  return {
383
355
  ...(id ? { id } : {}),
384
356
  name: read(env, "NYLORUN_TENANT_NAME") ?? "default",
385
357
  ...(identityFile ? { identityFile } : {}),
358
+ ...(managementKeyFile ? { managementKeyFile } : {}),
386
359
  };
387
360
  }
388
361
  const GATES_TOKEN = /^[0-9a-f]{64,}$/i;
package/dist/index.d.ts CHANGED
@@ -8,6 +8,6 @@ export type { ResolverConfig } from "./vault/sources.js";
8
8
  export type { RuntimeAgent } from "./contracts.js";
9
9
  export { IMAGE_MEDIA_TYPES, MAX_IMAGE_BYTES, decodeImageBase64, validateImageBytes, } from "./media.js";
10
10
  export type { RuntimeModelAdapter } from "./contracts.js";
11
- export { baselineEnvironment, hostProcessEnvironment, tenantChildEnvironment, } from "./host/environment.js";
11
+ export { baselineEnvironment, hostProcessEnvironment, } from "./host/environment.js";
12
12
  export type { HostProcessPathInputs } from "./host/environment.js";
13
13
  export type { HostConfigFile, HostCredentialsFile, } from "./host/config.js";
package/dist/index.js CHANGED
@@ -4,4 +4,4 @@ export { parseIdentityFile, IdentityFileError, } from "./tenant/identity-file.js
4
4
  export { createTrustedIssuers, } from "./tenant/issuers.js";
5
5
  export { scriptedModel, gatewayModel } from "./core/provider.js";
6
6
  export { IMAGE_MEDIA_TYPES, MAX_IMAGE_BYTES, decodeImageBase64, validateImageBytes, } from "./media.js";
7
- export { baselineEnvironment, hostProcessEnvironment, tenantChildEnvironment, } from "./host/environment.js";
7
+ export { baselineEnvironment, hostProcessEnvironment, } from "./host/environment.js";
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * | Services | Serves | `execution.start` |
5
5
  * | --- | --- | --- |
6
- * | `core` | Tenant API, Admin API, SSE | **never**: wakes, timers and sweep arming go through Restate's ingress, which needs no Worker endpoint |
6
+ * | `core` | Runtime and Management APIs, SSE | **never**: wakes, timers and sweep arming go through Restate's ingress, which needs no Worker endpoint |
7
7
  * | `loop` | the Restate endpoint (`NylorunSession.advance`, `NylorunTenant.sweep`, timers) | yes |
8
8
  * | `core,loop` | both (the local stack's `runtime` container) | yes |
9
9
  *
package/dist/keys/keys.js CHANGED
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * The keys seam (blueprint §14, F4.2): everything that needs the vault key. Vault writes that
3
3
  * touch a secret (creating and rotating a credential, setting and selecting the host model;
4
- * rotation and selection decrypt the old secret first) and all token signing (subject and
5
- * delivery tokens, signing-key rotation) run here, whole, so the process that calls them never
4
+ * rotation and selection decrypt the old secret first) and all token signing (capability
5
+ * links, run and host tokens, signing-key rotation) run here, whole, so the process that calls them never
6
6
  * holds the key or a private signing key.
7
7
  *
8
8
  * MCP OAuth connect (F9-D14) runs here too: discovery, registration, the code exchange and the