@nylorun/runtime 0.5.0-beta → 0.6.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 (45) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +29 -61
  3. package/dist/config.d.ts +1 -1
  4. package/dist/configuration.d.ts +3 -0
  5. package/dist/configuration.js +3 -0
  6. package/dist/contracts.d.ts +4 -2
  7. package/dist/core/main.js +40 -0
  8. package/dist/core/provider.d.ts +12 -0
  9. package/dist/core/provider.js +60 -0
  10. package/dist/core/runtime.d.ts +50 -0
  11. package/dist/core/runtime.js +877 -0
  12. package/dist/core/store.d.ts +16 -0
  13. package/dist/core/store.js +101 -0
  14. package/dist/index.d.ts +6 -11
  15. package/dist/index.js +4 -6
  16. package/dist/model/defaults.d.ts +1 -1
  17. package/dist/model/http-model.d.ts +1 -1
  18. package/dist/node/local-sessions.js +17 -0
  19. package/dist/server/host.d.ts +42 -4
  20. package/dist/server/host.js +69 -3
  21. package/dist/session/api.d.ts +10 -0
  22. package/dist/session/api.js +15 -0
  23. package/dist/session/default.d.ts +5 -0
  24. package/dist/session/default.js +30 -0
  25. package/dist/session/handle.d.ts +27 -0
  26. package/dist/session/handle.js +199 -0
  27. package/dist/session/index.d.ts +2 -0
  28. package/dist/session/index.js +2 -0
  29. package/dist/sessions/host.d.ts +11 -1
  30. package/dist/sessions/host.js +75 -7
  31. package/dist/sessions/store.d.ts +1 -0
  32. package/dist/sessions/store.js +3 -0
  33. package/package.json +16 -11
  34. package/dist/cli.d.ts +0 -2
  35. package/dist/cli.js +0 -100
  36. package/dist/dev-entry.js +0 -2
  37. package/dist/dev.d.ts +0 -2
  38. package/dist/dev.js +0 -126
  39. package/dist/environment.d.ts +0 -2
  40. package/dist/environment.js +0 -64
  41. package/dist/launcher.d.ts +0 -1
  42. package/dist/launcher.js +0 -33
  43. package/dist/model/configure.d.ts +0 -12
  44. package/dist/model/configure.js +0 -155
  45. /package/dist/{dev-entry.d.ts → core/main.d.ts} +0 -0
@@ -0,0 +1,2 @@
1
+ export { createSessionHandle, resolveWait, type OpenSessionOptions, type SessionHandle, type SessionRuntime, } from "./handle.js";
2
+ export { getDefaultRuntime, setDefaultRuntime, installDefaultRuntimeFactory, } from "./default.js";
@@ -0,0 +1,2 @@
1
+ export { createSessionHandle, resolveWait, } from "./handle.js";
2
+ export { getDefaultRuntime, setDefaultRuntime, installDefaultRuntimeFactory, } from "./default.js";
@@ -1,4 +1,5 @@
1
- import type { BuiltAgent, ExecutionInput, ModelAdapter, RunResult } from "@nylorun/harness";
1
+ import type { BuiltAgent, JsonObject, ModelAdapter } from "@nylorun/core/define";
2
+ import type { ExecutionInput, ExecutionState, RunResult } from "@nylorun/harness";
2
3
  import type { CanonicalEvent, SessionStore, StoredSession, SessionSummary } from "./store.js";
3
4
  export interface SubmitOptions {
4
5
  readonly runId?: string;
@@ -8,6 +9,8 @@ export interface SubmitOptions {
8
9
  readonly secrets?: readonly string[];
9
10
  readonly onEvent?: (event: CanonicalEvent) => void;
10
11
  readonly started?: Record<string, unknown>;
12
+ /** Seed `ExecutionState.state` when creating a new checkpoint (openSession). */
13
+ readonly sessionState?: JsonObject;
11
14
  }
12
15
  /** The built-in single-process coordinator. Storage adapters do not implement execution. */
13
16
  export declare class SessionHost {
@@ -21,9 +24,16 @@ export declare class SessionHost {
21
24
  private key;
22
25
  read(agentId: string, sessionId: string): Promise<StoredSession | undefined>;
23
26
  list(agentId: string): Promise<readonly SessionSummary[]>;
27
+ delete(agentId: string, sessionId: string): Promise<boolean>;
24
28
  subscribe(agentId: string, sessionId: string, listener: (event: CanonicalEvent) => void): () => void;
25
29
  submit(agent: BuiltAgent<any, any>, sessionId: string, input: ExecutionInput, options: SubmitOptions): Promise<RunResult<any>>;
26
30
  cancel(agent: BuiltAgent<any, any>, sessionId: string): Promise<void>;
27
31
  interrupt(agent: BuiltAgent<any, any>, sessionId: string, input: ExecutionInput, options: SubmitOptions): Promise<RunResult<any>>;
28
32
  close(): Promise<void>;
29
33
  }
34
+ /**
35
+ * Map DX `wait-resolve` onto harness approve/respond/settle using wait metadata.
36
+ * Engine `ExecutionInput` already includes `wait-resolve`; resume is wired via
37
+ * existing interaction/deferred kinds until full wait-id resume lands.
38
+ */
39
+ export declare function resolveEngineInput(state: ExecutionState | undefined, input: ExecutionInput): ExecutionInput;
@@ -1,4 +1,5 @@
1
- import { isHarnessError } from "@nylorun/harness";
1
+ import { HarnessError, isHarnessError } from "@nylorun/core/define";
2
+ import { bindingFromAgent, createRunState, run, } from "@nylorun/harness/run";
2
3
  import { scrub } from "../redact.js";
3
4
  /** The built-in single-process coordinator. Storage adapters do not implement execution. */
4
5
  export class SessionHost {
@@ -26,6 +27,19 @@ export class SessionHost {
26
27
  ? { ...session, status: "interrupted" }
27
28
  : session);
28
29
  }
30
+ async delete(agentId, sessionId) {
31
+ const key = this.key(agentId, sessionId);
32
+ if (this.active.has(key))
33
+ throw new Error("Cannot delete a session while a run is active");
34
+ if ("delete" in this.store && typeof this.store.delete === "function")
35
+ return this.store.delete(agentId, sessionId);
36
+ const existing = await this.store.get(agentId, sessionId);
37
+ if (!existing)
38
+ return false;
39
+ // Stores without delete: archive by removing via put tombstone is not supported;
40
+ // require ManagedSessionStore.delete or memorySessions.delete.
41
+ throw new Error("Session store does not support delete");
42
+ }
29
43
  subscribe(agentId, sessionId, listener) {
30
44
  const key = this.key(agentId, sessionId);
31
45
  let listeners = this.listeners.get(key);
@@ -144,17 +158,21 @@ export class SessionHost {
144
158
  ...(typeof input === "string" ? { input } : {}),
145
159
  });
146
160
  await save();
147
- const result = await agent.run({
148
- state: document.state,
149
- input,
161
+ const binding = bindingFromAgent(agent);
162
+ const engineInput = resolveEngineInput(document.state, input);
163
+ const state = ensureEngineState(binding, document.state, options.sessionState);
164
+ const result = await run({
165
+ binding,
166
+ state,
167
+ input: engineInput,
150
168
  info: options.info,
151
169
  signal: controller.signal,
152
170
  onModelCall: options.onModelCall,
153
171
  onEvent: (event) => {
154
172
  add(event.type, event);
155
173
  },
156
- record: async (state) => {
157
- document = { ...document, state };
174
+ record: async (next) => {
175
+ document = { ...document, state: next };
158
176
  await save();
159
177
  },
160
178
  });
@@ -235,7 +253,9 @@ export class SessionHost {
235
253
  throw new Error("This session was interrupted; reconcile its external effects before cancellation.");
236
254
  if (stored?.state?.status !== "paused")
237
255
  return;
238
- const result = await agent.run({
256
+ const binding = bindingFromAgent(agent);
257
+ const result = await run({
258
+ binding,
239
259
  state: stored.state,
240
260
  input: { kind: "continue" },
241
261
  signal: AbortSignal.abort(new Error("Paused execution cancelled")),
@@ -289,3 +309,51 @@ export class SessionHost {
289
309
  await this.store.close();
290
310
  }
291
311
  }
312
+ function ensureEngineState(binding, existing, sessionState) {
313
+ if (existing) {
314
+ if (!sessionState || Object.keys(existing.state ?? {}).length > 0)
315
+ return existing;
316
+ return {
317
+ ...existing,
318
+ state: { ...(existing.state ?? {}), ...sessionState },
319
+ };
320
+ }
321
+ return createRunState(binding, {
322
+ ...(sessionState ? { state: sessionState } : {}),
323
+ });
324
+ }
325
+ /**
326
+ * Map DX `wait-resolve` onto harness approve/respond/settle using wait metadata.
327
+ * Engine `ExecutionInput` already includes `wait-resolve`; resume is wired via
328
+ * existing interaction/deferred kinds until full wait-id resume lands.
329
+ */
330
+ export function resolveEngineInput(state, input) {
331
+ if (typeof input !== "object" || !("kind" in input) || input.kind !== "wait-resolve")
332
+ return input;
333
+ const call = state?.plan?.calls.find((item) => item.wait?.waitId === input.waitId);
334
+ if (!call)
335
+ throw new HarnessError("execution.invalid-input", "No pending wait matches waitId");
336
+ if (call.status === "interaction" && call.interaction) {
337
+ if (call.interaction.kind === "approval")
338
+ return {
339
+ kind: "approve",
340
+ interactionId: call.interaction.id,
341
+ approved: input.value !== false && input.value !== "false",
342
+ };
343
+ return {
344
+ kind: "respond",
345
+ interactionId: call.interaction.id,
346
+ value: input.value ?? null,
347
+ };
348
+ }
349
+ if (call.status === "deferred")
350
+ return {
351
+ kind: "settle",
352
+ invocationId: call.invocationId,
353
+ outcome: {
354
+ kind: "completed",
355
+ output: input.value ?? null,
356
+ },
357
+ };
358
+ throw new HarnessError("execution.invalid-input", "Wait is no longer pending");
359
+ }
@@ -32,6 +32,7 @@ export interface SessionStore {
32
32
  get(agentId: string, sessionId: string): Promise<StoredSession | undefined>;
33
33
  put(agentId: string, sessionId: string, session: StoredSession): Promise<void>;
34
34
  list(agentId: string): Promise<readonly SessionSummary[]>;
35
+ delete?(agentId: string, sessionId: string): Promise<boolean>;
35
36
  }
36
37
  export interface ManagedSessionStore extends SessionStore {
37
38
  close(): Promise<void>;
@@ -26,5 +26,8 @@ export function memorySessions() {
26
26
  .map(sessionSummary)
27
27
  .sort((a, b) => b.startedAt - a.startedAt);
28
28
  },
29
+ async delete(agentId, sessionId) {
30
+ return documents.delete(key(agentId, sessionId));
31
+ },
29
32
  };
30
33
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@nylorun/runtime",
3
- "version": "0.5.0-beta",
4
- "description": "Portable agent runtime, Hono protocol router, model providers, and the Nylorun CLI.",
3
+ "version": "0.6.0-beta",
4
+ "description": "SQLite agent execution host and model providers.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
7
7
  "repository": {
@@ -10,10 +10,7 @@
10
10
  "directory": "runtime"
11
11
  },
12
12
  "engines": {
13
- "node": ">=22.19.0"
14
- },
15
- "bin": {
16
- "nylorun": "dist/cli.js"
13
+ "node": ">=24.0.0"
17
14
  },
18
15
  "exports": {
19
16
  ".": {
@@ -23,6 +20,15 @@
23
20
  "./node": {
24
21
  "types": "./dist/node/index.d.ts",
25
22
  "import": "./dist/node/index.js"
23
+ },
24
+ "./core": {
25
+ "types": "./dist/core/runtime.d.ts",
26
+ "import": "./dist/core/runtime.js"
27
+ },
28
+ "./server": "./dist/core/main.js",
29
+ "./configuration": {
30
+ "types": "./dist/configuration.d.ts",
31
+ "import": "./dist/configuration.js"
26
32
  }
27
33
  },
28
34
  "files": [
@@ -41,15 +47,14 @@
41
47
  "typecheck": "node ../scripts/check-typescript-version.mjs && tsc -p tsconfig.json --noEmit",
42
48
  "test": "vitest run",
43
49
  "prepack": "npm run build",
44
- "clean": "node -e \"import('node:fs').then(({rmSync})=>rmSync('dist',{recursive:true,force:true}))\""
50
+ "clean": "node -e \"import('node:fs').then(({rmSync})=>rmSync('dist',{recursive:true,force:true}))\"",
51
+ "start": "node dist/core/main.js"
45
52
  },
46
53
  "dependencies": {
47
54
  "@earendil-works/pi-ai": "0.85.1",
48
55
  "@hono/node-server": "^2.1.1",
49
- "@nylorun/harness": "0.13.0-beta"
50
- },
51
- "peerDependencies": {
52
- "hono": "^4.13.7"
56
+ "@nylorun/harness": "0.15.0-beta",
57
+ "@nylorun/core": "0.1.1-beta"
53
58
  },
54
59
  "devDependencies": {
55
60
  "@types/node": "^26.5.0",
package/dist/cli.d.ts DELETED
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- export {};
package/dist/cli.js DELETED
@@ -1,100 +0,0 @@
1
- #!/usr/bin/env node
2
- import { join } from "node:path";
3
- import { pathToFileURL } from "node:url";
4
- import { createRequire } from "node:module";
5
- import { ConfigurationCancelled, configureProvider, } from "./model/configure.js";
6
- import { loadProjectEnvironment } from "./environment.js";
7
- import { develop } from "./dev.js";
8
- const usage = `nylorun <configure|dev|start|studio>
9
- dev [--no-studio] [--no-open]
10
- start [entry]
11
- configure
12
- studio --agent-url <http(s)-url> [--port <n>] [--no-open]`;
13
- async function startStudio(agentServerUrl, open, port) {
14
- let entry;
15
- try {
16
- entry = createRequire(join(process.cwd(), "package.json")).resolve("@nylorun/studio");
17
- }
18
- catch {
19
- throw new Error("Install @nylorun/studio to use the Studio dashboard.");
20
- }
21
- const studio = await import(pathToFileURL(entry).href);
22
- return studio.startStudio({
23
- agentServerUrl,
24
- open,
25
- ...(port === undefined ? {} : { port }),
26
- });
27
- }
28
- function parsePort(value) {
29
- if (value === undefined)
30
- return undefined;
31
- const port = Number(value);
32
- if (!Number.isInteger(port) || port < 1 || port > 65535)
33
- throw new Error("--port must be an integer between 1 and 65535.");
34
- return port;
35
- }
36
- async function main() {
37
- const [command, ...args] = process.argv.slice(2);
38
- if (!command || command === "--help" || command === "-h")
39
- return void console.log(usage);
40
- if (["configure", "dev", "start"].includes(command))
41
- loadProjectEnvironment();
42
- if (command === "start") {
43
- if (args.length > 1 || args[0]?.startsWith("--"))
44
- throw new Error(usage);
45
- await (await import("./launcher.js")).start(args[0]);
46
- return;
47
- }
48
- if (command === "dev") {
49
- process.exitCode = await develop(args);
50
- return;
51
- }
52
- if (command === "configure") {
53
- if (args.length)
54
- throw new Error(usage);
55
- const controller = new AbortController();
56
- const cancel = (signal) => controller.abort(new ConfigurationCancelled(signal));
57
- process.once("SIGINT", () => cancel("SIGINT"));
58
- process.once("SIGTERM", () => cancel("SIGTERM"));
59
- await configureProvider({ signal: controller.signal });
60
- return;
61
- }
62
- if (command !== "studio")
63
- throw new Error(usage);
64
- let agentUrl;
65
- let port;
66
- let open = true;
67
- for (let index = 0; index < args.length; index += 1) {
68
- const arg = args[index];
69
- if (arg === "--agent-url") {
70
- if (agentUrl !== undefined)
71
- throw new Error("--agent-url may only be supplied once.");
72
- agentUrl = args[++index];
73
- if (!agentUrl || agentUrl.startsWith("--"))
74
- throw new Error("--agent-url requires a value.");
75
- }
76
- else if (arg === "--port") {
77
- if (port !== undefined)
78
- throw new Error("--port may only be supplied once.");
79
- port = parsePort(args[++index]);
80
- }
81
- else if (arg === "--no-open" && open)
82
- open = false;
83
- else
84
- throw new Error(usage);
85
- }
86
- if (!agentUrl)
87
- throw new Error("--agent-url is required.");
88
- const dashboard = await startStudio(agentUrl, open, port);
89
- console.log(`Studio on ${dashboard.address}`);
90
- await new Promise((resolve, reject) => {
91
- const close = () => void dashboard.close().then(resolve, reject);
92
- process.once("SIGINT", close);
93
- process.once("SIGTERM", close);
94
- });
95
- }
96
- void main().catch((error) => {
97
- console.error(error instanceof Error ? error.message : String(error));
98
- process.exitCode =
99
- error instanceof ConfigurationCancelled ? error.exitCode : 1;
100
- });
package/dist/dev-entry.js DELETED
@@ -1,2 +0,0 @@
1
- import { start } from "./launcher.js";
2
- await start(process.argv[2] ?? "src/index.ts", true);
package/dist/dev.d.ts DELETED
@@ -1,2 +0,0 @@
1
- /** Runs project development tooling without copying a supervisor into each application. */
2
- export declare function develop(args: readonly string[]): Promise<number>;
package/dist/dev.js DELETED
@@ -1,126 +0,0 @@
1
- import { spawn } from "node:child_process";
2
- import { createRequire } from "node:module";
3
- import { join } from "node:path";
4
- import { fileURLToPath } from "node:url";
5
- import { setTimeout as delay } from "node:timers/promises";
6
- /** Runs project development tooling without copying a supervisor into each application. */
7
- export async function develop(args) {
8
- const usage = "Usage: nylorun dev [--no-studio] [--no-open]";
9
- if (new Set(args).size !== args.length ||
10
- args.some((arg) => !["--no-studio", "--no-open"].includes(arg)))
11
- throw new Error(usage);
12
- const port = Number(process.env.PORT ?? "3000");
13
- if (!Number.isInteger(port) || port < 1 || port > 65535)
14
- throw new Error("PORT must be an integer between 1 and 65535.");
15
- const require = createRequire(join(process.cwd(), "package.json"));
16
- let tsx;
17
- try {
18
- tsx = require.resolve("tsx/cli");
19
- }
20
- catch {
21
- throw new Error("Install tsx in your project to use nylorun dev.");
22
- }
23
- if (!args.includes("--no-studio")) {
24
- try {
25
- require.resolve("@nylorun/studio");
26
- }
27
- catch {
28
- throw new Error("Install @nylorun/studio or use nylorun dev --no-studio.");
29
- }
30
- }
31
- const controller = new AbortController();
32
- const children = new Set();
33
- const exits = [];
34
- let result = 0;
35
- let force;
36
- const stop = (code, signal = "SIGTERM") => {
37
- if (controller.signal.aborted)
38
- return;
39
- result = code;
40
- controller.abort();
41
- for (const child of children)
42
- child.kill(signal);
43
- force = setTimeout(() => {
44
- for (const child of children)
45
- child.kill("SIGKILL");
46
- }, 5_000);
47
- force.unref();
48
- };
49
- const interrupt = () => stop(130, "SIGINT");
50
- const terminate = () => stop(143);
51
- process.once("SIGINT", interrupt);
52
- process.once("SIGTERM", terminate);
53
- const launch = (argv) => {
54
- const child = spawn(process.execPath, argv, {
55
- stdio: "inherit",
56
- env: { ...process.env, NYLORUN_DEV: "1" },
57
- });
58
- children.add(child);
59
- exits.push(new Promise((resolve) => {
60
- child.once("error", (error) => {
61
- console.error(`Could not start development process: ${error.message}`);
62
- stop(1);
63
- });
64
- child.once("close", (code, signal) => {
65
- children.delete(child);
66
- stop(code ?? (signal === "SIGINT" ? 130 : signal === "SIGTERM" ? 143 : 1));
67
- resolve();
68
- });
69
- }));
70
- };
71
- try {
72
- launch([
73
- tsx,
74
- "watch",
75
- fileURLToPath(new URL("./dev-entry.js", import.meta.url)),
76
- "src/index.ts",
77
- ]);
78
- if (!args.includes("--no-studio")) {
79
- const url = `http://127.0.0.1:${port}/agents/v1/agents`;
80
- const deadline = Date.now() + 20_000;
81
- let ready = false;
82
- while (!controller.signal.aborted && Date.now() < deadline) {
83
- try {
84
- const response = await fetch(url, {
85
- signal: AbortSignal.any([
86
- controller.signal,
87
- AbortSignal.timeout(500),
88
- ]),
89
- });
90
- ready = response.ok;
91
- await response.body?.cancel();
92
- if (ready)
93
- break;
94
- }
95
- catch {
96
- /* Watch mode may still be compiling or restarting the app. */
97
- }
98
- await delay(50, undefined, { signal: controller.signal }).catch(() => { });
99
- }
100
- if (!controller.signal.aborted) {
101
- if (!ready)
102
- throw new Error(`Application did not become ready at ${url} within 20 seconds.`);
103
- launch([
104
- fileURLToPath(new URL("./cli.js", import.meta.url)),
105
- "studio",
106
- "--agent-url",
107
- `http://localhost:${port}/agents`,
108
- ...(args.includes("--no-open") ? ["--no-open"] : []),
109
- ]);
110
- }
111
- }
112
- await Promise.all(exits);
113
- }
114
- catch (error) {
115
- stop(1);
116
- await Promise.all(exits);
117
- throw error;
118
- }
119
- finally {
120
- if (force !== undefined)
121
- clearTimeout(force);
122
- process.removeListener("SIGINT", interrupt);
123
- process.removeListener("SIGTERM", terminate);
124
- }
125
- return result;
126
- }
@@ -1,2 +0,0 @@
1
- export declare function loadProjectEnvironment(root?: string): void;
2
- export declare function saveEnvironment(root: string, updates: Record<string, string | undefined>, signal?: AbortSignal): Promise<void>;
@@ -1,64 +0,0 @@
1
- import { readFileSync, statSync } from "node:fs";
2
- import { writeFile, rename, rm } from "node:fs/promises";
3
- import { join } from "node:path";
4
- import { randomUUID } from "node:crypto";
5
- import { loadEnvFile } from "node:process";
6
- export function loadProjectEnvironment(root = process.cwd()) {
7
- const file = join(root, ".env");
8
- try {
9
- if (statSync(file).isDirectory())
10
- throw new Error("The .env directory must be migrated manually: back it up, create a .env file with MODEL_PROVIDER, MODEL and MODEL_PROVIDER_API_KEY, and move OAuth credentials to .nylorun/auth.json. See the Runtime migration guide.");
11
- }
12
- catch (error) {
13
- if (error.code === "ENOENT")
14
- return;
15
- throw error;
16
- }
17
- loadEnvFile(file);
18
- }
19
- // Match complete dotenv assignments, including quoted multiline values.
20
- const assignment = /^(?:export\s+)?([\w]+)[\t ]*=[\t ]*(?:"[^"]*"|'[^']*'|`[^`]*`|[^#\r\n]*)([^\r\n]*)(?:\r?\n|$)/gm;
21
- export async function saveEnvironment(root, updates, signal) {
22
- const file = join(root, ".env");
23
- let contents = "";
24
- try {
25
- contents = readFileSync(file, "utf8");
26
- }
27
- catch (error) {
28
- if (error.code !== "ENOENT")
29
- throw error;
30
- }
31
- const encode = (value) => {
32
- // Node's dotenv parser has no general quote-escaping syntax. Select a
33
- // delimiter absent from the value rather than changing the credential.
34
- for (const quote of ["'", '"', "`"]) {
35
- if (!value.includes(quote) && !(quote === '"' && /\\[nr]/.test(value)))
36
- return quote + value + quote;
37
- }
38
- throw new Error("This value contains all dotenv quote delimiters; set it through your process environment instead.");
39
- };
40
- const remaining = new Set(Object.keys(updates));
41
- contents = contents.replace(assignment, (whole, key, suffix) => {
42
- if (!(key in updates))
43
- return whole;
44
- if (!remaining.delete(key))
45
- return "";
46
- return updates[key] === undefined
47
- ? ""
48
- : `${key}=${encode(updates[key])}${suffix}\n`;
49
- });
50
- if (contents && !contents.endsWith("\n"))
51
- contents += "\n";
52
- for (const key of remaining)
53
- if (updates[key] !== undefined)
54
- contents += `${key}=${encode(updates[key])}\n`;
55
- const temporary = join(root, `.env-${randomUUID()}.tmp`);
56
- try {
57
- await writeFile(temporary, contents, { mode: 0o600, signal });
58
- signal?.throwIfAborted();
59
- await rename(temporary, file);
60
- }
61
- finally {
62
- await rm(temporary, { force: true });
63
- }
64
- }
@@ -1 +0,0 @@
1
- export declare function start(entry?: string, development?: boolean): Promise<void>;
package/dist/launcher.js DELETED
@@ -1,33 +0,0 @@
1
- import { serve } from "@hono/node-server";
2
- import { resolve } from "node:path";
3
- import { pathToFileURL } from "node:url";
4
- import { installNodeModelFactory, installRuntimeLifecycle, } from "./model/defaults.js";
5
- import { piModel } from "./model/pi-model.js";
6
- import { loadProjectEnvironment } from "./environment.js";
7
- export async function start(entry = "dist/src/index.js", development = false) {
8
- loadProjectEnvironment();
9
- if (development)
10
- process.env.NYLORUN_DEV = "1";
11
- else
12
- delete process.env.NYLORUN_DEV;
13
- const port = Number(process.env.PORT ?? "3000");
14
- if (!Number.isInteger(port) || port < 1 || port > 65535)
15
- throw new Error("PORT must be an integer between 1 and 65535.");
16
- const shutdowns = new Set();
17
- installRuntimeLifecycle((close) => shutdowns.add(close));
18
- installNodeModelFactory((options) => piModel({ onPreview: options.onPreview, media: options.media }));
19
- const { default: app } = await import(pathToFileURL(resolve(entry)).href);
20
- if (!app || typeof app.fetch !== "function")
21
- throw new Error(`${entry} must export a Hono application with 'export default app' and a callable fetch.`);
22
- const server = serve({ fetch: app.fetch.bind(app), port }, (info) => {
23
- console.log(`Server is running on http://localhost:${info.port}`);
24
- });
25
- const stop = () => {
26
- process.removeListener("SIGINT", stop);
27
- process.removeListener("SIGTERM", stop);
28
- void Promise.allSettled([...shutdowns].map((close) => close())).then(() => server.close());
29
- setTimeout(() => process.exit(0), 5_000).unref();
30
- };
31
- process.once("SIGINT", stop);
32
- process.once("SIGTERM", stop);
33
- }
@@ -1,12 +0,0 @@
1
- import type { Readable, Writable } from "node:stream";
2
- export declare class ConfigurationCancelled extends Error {
3
- readonly signal: "SIGINT" | "SIGTERM";
4
- readonly exitCode: number;
5
- constructor(signal: "SIGINT" | "SIGTERM");
6
- }
7
- export declare function configureProvider(options?: {
8
- signal?: AbortSignal;
9
- root?: string;
10
- input?: Readable;
11
- output?: Writable;
12
- }): Promise<void>;