@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.
- package/CHANGELOG.md +30 -0
- package/README.md +29 -61
- package/dist/config.d.ts +1 -1
- package/dist/configuration.d.ts +3 -0
- package/dist/configuration.js +3 -0
- package/dist/contracts.d.ts +4 -2
- package/dist/core/main.js +40 -0
- package/dist/core/provider.d.ts +12 -0
- package/dist/core/provider.js +60 -0
- package/dist/core/runtime.d.ts +50 -0
- package/dist/core/runtime.js +877 -0
- package/dist/core/store.d.ts +16 -0
- package/dist/core/store.js +101 -0
- package/dist/index.d.ts +6 -11
- package/dist/index.js +4 -6
- package/dist/model/defaults.d.ts +1 -1
- package/dist/model/http-model.d.ts +1 -1
- package/dist/node/local-sessions.js +17 -0
- package/dist/server/host.d.ts +42 -4
- package/dist/server/host.js +69 -3
- package/dist/session/api.d.ts +10 -0
- package/dist/session/api.js +15 -0
- package/dist/session/default.d.ts +5 -0
- package/dist/session/default.js +30 -0
- package/dist/session/handle.d.ts +27 -0
- package/dist/session/handle.js +199 -0
- package/dist/session/index.d.ts +2 -0
- package/dist/session/index.js +2 -0
- package/dist/sessions/host.d.ts +11 -1
- package/dist/sessions/host.js +75 -7
- package/dist/sessions/store.d.ts +1 -0
- package/dist/sessions/store.js +3 -0
- package/package.json +16 -11
- package/dist/cli.d.ts +0 -2
- package/dist/cli.js +0 -100
- package/dist/dev-entry.js +0 -2
- package/dist/dev.d.ts +0 -2
- package/dist/dev.js +0 -126
- package/dist/environment.d.ts +0 -2
- package/dist/environment.js +0 -64
- package/dist/launcher.d.ts +0 -1
- package/dist/launcher.js +0 -33
- package/dist/model/configure.d.ts +0 -12
- package/dist/model/configure.js +0 -155
- /package/dist/{dev-entry.d.ts → core/main.d.ts} +0 -0
package/dist/sessions/host.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { BuiltAgent,
|
|
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;
|
package/dist/sessions/host.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { isHarnessError } from "@nylorun/
|
|
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
|
|
148
|
-
|
|
149
|
-
|
|
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 (
|
|
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
|
|
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
|
+
}
|
package/dist/sessions/store.d.ts
CHANGED
|
@@ -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>;
|
package/dist/sessions/store.js
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nylorun/runtime",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
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": ">=
|
|
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.
|
|
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
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
package/dist/dev.d.ts
DELETED
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
|
-
}
|
package/dist/environment.d.ts
DELETED
package/dist/environment.js
DELETED
|
@@ -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
|
-
}
|
package/dist/launcher.d.ts
DELETED
|
@@ -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>;
|