@reasonlayer/sdk 0.0.1
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/LICENSE +201 -0
- package/README.md +35 -0
- package/bin/rl.mjs +75 -0
- package/dist/builder.d.ts +38 -0
- package/dist/builder.js +41 -0
- package/dist/bundler/index.d.ts +32 -0
- package/dist/bundler/index.js +143 -0
- package/dist/bundler/lint.d.ts +13 -0
- package/dist/bundler/lint.js +74 -0
- package/dist/bundler/node.d.ts +10 -0
- package/dist/bundler/node.js +55 -0
- package/dist/bundler/smoke.d.ts +12 -0
- package/dist/bundler/smoke.js +70 -0
- package/dist/bundler/worker.d.ts +31 -0
- package/dist/bundler/worker.js +214 -0
- package/dist/cli/args.d.ts +9 -0
- package/dist/cli/args.js +71 -0
- package/dist/cli/config.d.ts +38 -0
- package/dist/cli/config.js +94 -0
- package/dist/cli/convex.d.ts +9 -0
- package/dist/cli/convex.js +25 -0
- package/dist/cli/format.d.ts +11 -0
- package/dist/cli/format.js +140 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +721 -0
- package/dist/cli/keychain.d.ts +21 -0
- package/dist/cli/keychain.js +100 -0
- package/dist/cli/login-browser.d.ts +22 -0
- package/dist/cli/login-browser.js +106 -0
- package/dist/cli/mcp.d.ts +3 -0
- package/dist/cli/mcp.js +36 -0
- package/dist/cli/operations.d.ts +106 -0
- package/dist/cli/operations.js +623 -0
- package/dist/cli/sdk-package.d.ts +18 -0
- package/dist/cli/sdk-package.js +45 -0
- package/dist/cli/storage-upload.d.ts +9 -0
- package/dist/cli/storage-upload.js +21 -0
- package/dist/cli/watcher-compile.d.ts +1 -0
- package/dist/cli/watcher-compile.js +20 -0
- package/dist/cli/watcher-process.d.ts +1 -0
- package/dist/cli/watcher-process.js +312 -0
- package/dist/cli/worker-host.d.ts +10 -0
- package/dist/cli/worker-host.js +120 -0
- package/dist/cli/workspace-files.d.ts +12 -0
- package/dist/cli/workspace-files.js +91 -0
- package/dist/cli/workspace-local.d.ts +27 -0
- package/dist/cli/workspace-local.js +310 -0
- package/dist/cli/workspace-session.d.ts +13 -0
- package/dist/cli/workspace-session.js +12 -0
- package/dist/compile.d.ts +27 -0
- package/dist/compile.js +834 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +5 -0
- package/dist/schedule-validation.d.ts +1 -0
- package/dist/schedule-validation.js +16 -0
- package/dist/selector-schema.d.ts +26 -0
- package/dist/selector-schema.js +780 -0
- package/dist/selectors.d.ts +25 -0
- package/dist/selectors.js +99 -0
- package/dist/testkit.d.ts +32 -0
- package/dist/testkit.js +161 -0
- package/dist/types.d.ts +184 -0
- package/dist/types.js +110 -0
- package/node_modules/@reasonlayer/integrations/dist/catalog.d.ts +4937 -0
- package/node_modules/@reasonlayer/integrations/dist/catalog.js +20 -0
- package/node_modules/@reasonlayer/integrations/dist/generated/slack.d.ts +3014 -0
- package/node_modules/@reasonlayer/integrations/dist/generated/slack.js +3101 -0
- package/node_modules/@reasonlayer/integrations/dist/index.d.ts +2 -0
- package/node_modules/@reasonlayer/integrations/dist/index.js +1 -0
- package/node_modules/@reasonlayer/integrations/dist/internal/definitions.d.ts +44 -0
- package/node_modules/@reasonlayer/integrations/dist/internal/definitions.js +52 -0
- package/node_modules/@reasonlayer/integrations/dist/internal/transport.d.ts +7 -0
- package/node_modules/@reasonlayer/integrations/dist/internal/transport.js +48 -0
- package/node_modules/@reasonlayer/integrations/dist/testkit.d.ts +1 -0
- package/node_modules/@reasonlayer/integrations/dist/testkit.js +1 -0
- package/node_modules/@reasonlayer/integrations/package.json +26 -0
- package/node_modules/@reasonlayer/protocol/dist/dispatch.d.ts +10 -0
- package/node_modules/@reasonlayer/protocol/dist/dispatch.js +58 -0
- package/node_modules/@reasonlayer/protocol/dist/envelope.d.ts +9 -0
- package/node_modules/@reasonlayer/protocol/dist/envelope.js +1 -0
- package/node_modules/@reasonlayer/protocol/dist/environments.d.ts +7 -0
- package/node_modules/@reasonlayer/protocol/dist/environments.js +7 -0
- package/node_modules/@reasonlayer/protocol/dist/events.d.ts +313 -0
- package/node_modules/@reasonlayer/protocol/dist/events.js +20 -0
- package/node_modules/@reasonlayer/protocol/dist/index.d.ts +18 -0
- package/node_modules/@reasonlayer/protocol/dist/index.js +9 -0
- package/node_modules/@reasonlayer/protocol/dist/ir.d.ts +252 -0
- package/node_modules/@reasonlayer/protocol/dist/ir.js +116 -0
- package/node_modules/@reasonlayer/protocol/dist/permissions.d.ts +5 -0
- package/node_modules/@reasonlayer/protocol/dist/permissions.js +30 -0
- package/node_modules/@reasonlayer/protocol/dist/readmodels.d.ts +617 -0
- package/node_modules/@reasonlayer/protocol/dist/readmodels.js +36 -0
- package/node_modules/@reasonlayer/protocol/dist/runtime.d.ts +67 -0
- package/node_modules/@reasonlayer/protocol/dist/runtime.js +66 -0
- package/node_modules/@reasonlayer/protocol/dist/scheduling.d.ts +69 -0
- package/node_modules/@reasonlayer/protocol/dist/scheduling.js +126 -0
- package/node_modules/@reasonlayer/protocol/dist/selector.d.ts +23 -0
- package/node_modules/@reasonlayer/protocol/dist/selector.js +77 -0
- package/node_modules/@reasonlayer/protocol/dist/tasks.d.ts +69 -0
- package/node_modules/@reasonlayer/protocol/dist/tasks.js +6 -0
- package/node_modules/@reasonlayer/protocol/dist/validate.d.ts +6 -0
- package/node_modules/@reasonlayer/protocol/dist/validate.js +18 -0
- package/node_modules/@reasonlayer/protocol/package.json +21 -0
- package/node_modules/@reasonlayer/runner/dist/environment-materializer.d.ts +13 -0
- package/node_modules/@reasonlayer/runner/dist/environment-materializer.js +92 -0
- package/node_modules/@reasonlayer/runner/dist/flue-transcript.d.ts +17 -0
- package/node_modules/@reasonlayer/runner/dist/flue-transcript.js +182 -0
- package/node_modules/@reasonlayer/runner/dist/index.d.ts +184 -0
- package/node_modules/@reasonlayer/runner/dist/index.js +884 -0
- package/node_modules/@reasonlayer/runner/dist/mcp-supervisor.d.ts +15 -0
- package/node_modules/@reasonlayer/runner/dist/mcp-supervisor.js +142 -0
- package/node_modules/@reasonlayer/runner/dist/sandbox-env.d.ts +36 -0
- package/node_modules/@reasonlayer/runner/dist/sandbox-env.js +171 -0
- package/node_modules/@reasonlayer/runner/dist/task-child.d.ts +1 -0
- package/node_modules/@reasonlayer/runner/dist/task-child.js +72 -0
- package/node_modules/@reasonlayer/runner/package.json +21 -0
- package/package.json +65 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { connectMcpServer } from "@flue/runtime";
|
|
2
|
+
import type { EnvironmentIR } from "@reasonlayer/protocol";
|
|
3
|
+
import type { ToolDefinition } from "@flue/runtime";
|
|
4
|
+
export interface McpSupervisorOptions {
|
|
5
|
+
taskEnv: Record<string, string>;
|
|
6
|
+
signal?: AbortSignal;
|
|
7
|
+
connect?: typeof connectMcpServer;
|
|
8
|
+
startupTimeoutMs?: number;
|
|
9
|
+
}
|
|
10
|
+
export interface StartedMcpServers {
|
|
11
|
+
env: Record<string, string>;
|
|
12
|
+
tools: ToolDefinition[];
|
|
13
|
+
close(): Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
export declare function startMcpServers(environment: EnvironmentIR | undefined, options: McpSupervisorOptions): Promise<StartedMcpServers>;
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { createServer } from "node:net";
|
|
3
|
+
import { setTimeout as delay } from "node:timers/promises";
|
|
4
|
+
import { connectMcpServer } from "@flue/runtime";
|
|
5
|
+
import { mcpUrlEnvName } from "@reasonlayer/protocol";
|
|
6
|
+
const DEFAULT_STARTUP_TIMEOUT_MS = 15_000;
|
|
7
|
+
async function openPort() {
|
|
8
|
+
return await new Promise((resolve, reject) => {
|
|
9
|
+
const server = createServer();
|
|
10
|
+
server.on("error", reject);
|
|
11
|
+
server.listen(0, "127.0.0.1", () => {
|
|
12
|
+
const address = server.address();
|
|
13
|
+
const port = typeof address === "object" && address ? address.port : 0;
|
|
14
|
+
server.close((err) => {
|
|
15
|
+
if (err)
|
|
16
|
+
reject(err);
|
|
17
|
+
else
|
|
18
|
+
resolve(port);
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
function resolveSecret(taskEnv, secret, location) {
|
|
24
|
+
const value = taskEnv[secret.name];
|
|
25
|
+
if (value === undefined)
|
|
26
|
+
throw new Error(`missing secret "${secret.name}" for ${location}`);
|
|
27
|
+
return value;
|
|
28
|
+
}
|
|
29
|
+
function resolveSecretRecord(taskEnv, values, location) {
|
|
30
|
+
if (!values || Object.keys(values).length === 0)
|
|
31
|
+
return undefined;
|
|
32
|
+
return Object.fromEntries(Object.entries(values).map(([key, secret]) => [
|
|
33
|
+
key,
|
|
34
|
+
resolveSecret(taskEnv, secret, `${location}.${key}`),
|
|
35
|
+
]));
|
|
36
|
+
}
|
|
37
|
+
async function connectWithRetry(name, url, headers, connect, process, startupTimeoutMs) {
|
|
38
|
+
const deadline = Date.now() + startupTimeoutMs;
|
|
39
|
+
let lastError;
|
|
40
|
+
while (Date.now() <= deadline) {
|
|
41
|
+
if (process && process.process.exitCode !== null) {
|
|
42
|
+
throw new Error(`MCP server "${name}" exited before it became ready: ${process.stderr.trim() || `exit ${process.process.exitCode}`}`);
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
return await connect(name, {
|
|
46
|
+
url,
|
|
47
|
+
...(headers !== undefined ? { headers } : {}),
|
|
48
|
+
timeoutMs: 5_000,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
lastError = err;
|
|
53
|
+
await delay(100);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
throw new Error(`MCP server "${name}" did not become ready: ${lastError instanceof Error ? lastError.message : String(lastError)}`);
|
|
57
|
+
}
|
|
58
|
+
function spawnLocalServer(name, server, taskEnv, url, port) {
|
|
59
|
+
if (server.transport && server.transport !== "http") {
|
|
60
|
+
throw new Error(`MCP server "${name}" uses unsupported transport "${server.transport}"`);
|
|
61
|
+
}
|
|
62
|
+
const secretEnv = resolveSecretRecord(taskEnv, server.env, `mcp.${name}.env`);
|
|
63
|
+
const child = spawn(server.command, {
|
|
64
|
+
env: {
|
|
65
|
+
...process.env,
|
|
66
|
+
...(secretEnv ?? {}),
|
|
67
|
+
PORT: String(port),
|
|
68
|
+
MCP_PORT: String(port),
|
|
69
|
+
RL_MCP_URL: url,
|
|
70
|
+
[mcpUrlEnvName(name)]: url,
|
|
71
|
+
},
|
|
72
|
+
shell: true,
|
|
73
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
74
|
+
});
|
|
75
|
+
const local = { name, process: child, stderr: "" };
|
|
76
|
+
child.stderr?.setEncoding("utf8");
|
|
77
|
+
child.stderr?.on("data", (chunk) => {
|
|
78
|
+
local.stderr += chunk;
|
|
79
|
+
});
|
|
80
|
+
return local;
|
|
81
|
+
}
|
|
82
|
+
async function closeLocal(process) {
|
|
83
|
+
if (process.process.exitCode !== null || process.process.killed)
|
|
84
|
+
return;
|
|
85
|
+
process.process.kill("SIGTERM");
|
|
86
|
+
await Promise.race([
|
|
87
|
+
new Promise((resolve) => process.process.once("close", () => resolve())),
|
|
88
|
+
delay(500).then(() => {
|
|
89
|
+
if (process.process.exitCode === null)
|
|
90
|
+
process.process.kill("SIGKILL");
|
|
91
|
+
}),
|
|
92
|
+
]);
|
|
93
|
+
}
|
|
94
|
+
export async function startMcpServers(environment, options) {
|
|
95
|
+
if (!environment?.mcp || Object.keys(environment.mcp).length === 0) {
|
|
96
|
+
return { env: {}, tools: [], close: async () => { } };
|
|
97
|
+
}
|
|
98
|
+
const connect = options.connect ?? connectMcpServer;
|
|
99
|
+
const startupTimeoutMs = options.startupTimeoutMs ?? DEFAULT_STARTUP_TIMEOUT_MS;
|
|
100
|
+
const env = {};
|
|
101
|
+
const locals = [];
|
|
102
|
+
const connections = [];
|
|
103
|
+
const tools = [];
|
|
104
|
+
try {
|
|
105
|
+
for (const [name, server] of Object.entries(environment.mcp)) {
|
|
106
|
+
if (server.kind === "command") {
|
|
107
|
+
const port = await openPort();
|
|
108
|
+
const url = `http://127.0.0.1:${port}/mcp`;
|
|
109
|
+
env[mcpUrlEnvName(name)] = url;
|
|
110
|
+
const local = spawnLocalServer(name, server, options.taskEnv, url, port);
|
|
111
|
+
locals.push(local);
|
|
112
|
+
const connection = await connectWithRetry(name, url, undefined, connect, local, startupTimeoutMs);
|
|
113
|
+
connections.push(connection);
|
|
114
|
+
tools.push(...connection.tools);
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
const headers = resolveSecretRecord(options.taskEnv, server.headers, `mcp.${name}.headers`);
|
|
118
|
+
env[mcpUrlEnvName(name)] = server.url;
|
|
119
|
+
const connection = await connectWithRetry(name, server.url, headers, connect, undefined, startupTimeoutMs);
|
|
120
|
+
connections.push(connection);
|
|
121
|
+
tools.push(...connection.tools);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
catch (err) {
|
|
125
|
+
await Promise.allSettled(connections.map((connection) => connection.close()));
|
|
126
|
+
await Promise.allSettled(locals.map((local) => closeLocal(local)));
|
|
127
|
+
throw err;
|
|
128
|
+
}
|
|
129
|
+
const abort = () => {
|
|
130
|
+
void Promise.allSettled(locals.map((local) => closeLocal(local)));
|
|
131
|
+
};
|
|
132
|
+
options.signal?.addEventListener("abort", abort, { once: true });
|
|
133
|
+
return {
|
|
134
|
+
env,
|
|
135
|
+
tools,
|
|
136
|
+
async close() {
|
|
137
|
+
options.signal?.removeEventListener("abort", abort);
|
|
138
|
+
await Promise.allSettled(connections.map((connection) => connection.close()));
|
|
139
|
+
await Promise.allSettled(locals.map((local) => closeLocal(local)));
|
|
140
|
+
},
|
|
141
|
+
};
|
|
142
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type ChildProcess } from "node:child_process";
|
|
2
|
+
import type { FileStat, SandboxApi, SessionEnv } from "@flue/runtime";
|
|
3
|
+
export type { SandboxApi } from "@flue/runtime";
|
|
4
|
+
export interface NodeSandboxApiOptions {
|
|
5
|
+
cwd?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function killProcessGroup(child: ChildProcess, signal: NodeJS.Signals): void;
|
|
8
|
+
export declare class NodeSandboxApi implements SandboxApi {
|
|
9
|
+
readonly cwd: string;
|
|
10
|
+
constructor(options?: NodeSandboxApiOptions);
|
|
11
|
+
readFile(path: string): Promise<string>;
|
|
12
|
+
readFileBuffer(path: string): Promise<Uint8Array>;
|
|
13
|
+
writeFile(path: string, content: string | Uint8Array): Promise<void>;
|
|
14
|
+
stat(path: string): Promise<FileStat>;
|
|
15
|
+
readdir(path: string): Promise<string[]>;
|
|
16
|
+
exists(path: string): Promise<boolean>;
|
|
17
|
+
mkdir(path: string, options?: {
|
|
18
|
+
recursive?: boolean;
|
|
19
|
+
}): Promise<void>;
|
|
20
|
+
rm(path: string, options?: {
|
|
21
|
+
recursive?: boolean;
|
|
22
|
+
force?: boolean;
|
|
23
|
+
}): Promise<void>;
|
|
24
|
+
exec(command: string, options?: {
|
|
25
|
+
cwd?: string;
|
|
26
|
+
env?: Record<string, string>;
|
|
27
|
+
timeoutMs?: number;
|
|
28
|
+
signal?: AbortSignal;
|
|
29
|
+
}): Promise<{
|
|
30
|
+
stdout: string;
|
|
31
|
+
stderr: string;
|
|
32
|
+
exitCode: number;
|
|
33
|
+
}>;
|
|
34
|
+
}
|
|
35
|
+
export declare function createNodeSandboxApi(options?: NodeSandboxApiOptions): SandboxApi;
|
|
36
|
+
export declare function createNodeSandboxSessionEnv(cwd?: string): SessionEnv;
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { constants } from "node:fs";
|
|
3
|
+
import { access, lstat, mkdir, readdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
4
|
+
import { resolve } from "node:path";
|
|
5
|
+
import { createSandboxSessionEnv } from "@flue/runtime";
|
|
6
|
+
export function killProcessGroup(child, signal) {
|
|
7
|
+
if (!child.pid || child.exitCode !== null || child.killed)
|
|
8
|
+
return;
|
|
9
|
+
try {
|
|
10
|
+
if (process.platform === "win32")
|
|
11
|
+
child.kill(signal);
|
|
12
|
+
else
|
|
13
|
+
process.kill(-child.pid, signal);
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
try {
|
|
17
|
+
child.kill(signal);
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
// Process already exited.
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function exitCodeForSignal(signal) {
|
|
25
|
+
if (!signal)
|
|
26
|
+
return 1;
|
|
27
|
+
const signalNumbers = {
|
|
28
|
+
SIGHUP: 1,
|
|
29
|
+
SIGINT: 2,
|
|
30
|
+
SIGQUIT: 3,
|
|
31
|
+
SIGILL: 4,
|
|
32
|
+
SIGTRAP: 5,
|
|
33
|
+
SIGABRT: 6,
|
|
34
|
+
SIGBUS: 7,
|
|
35
|
+
SIGFPE: 8,
|
|
36
|
+
SIGKILL: 9,
|
|
37
|
+
SIGUSR1: 10,
|
|
38
|
+
SIGSEGV: 11,
|
|
39
|
+
SIGUSR2: 12,
|
|
40
|
+
SIGPIPE: 13,
|
|
41
|
+
SIGALRM: 14,
|
|
42
|
+
SIGTERM: 15,
|
|
43
|
+
};
|
|
44
|
+
return 128 + (signalNumbers[signal] ?? 0);
|
|
45
|
+
}
|
|
46
|
+
export class NodeSandboxApi {
|
|
47
|
+
cwd;
|
|
48
|
+
constructor(options = {}) {
|
|
49
|
+
this.cwd = resolve(options.cwd ?? process.cwd());
|
|
50
|
+
}
|
|
51
|
+
async readFile(path) {
|
|
52
|
+
return await readFile(path, "utf8");
|
|
53
|
+
}
|
|
54
|
+
async readFileBuffer(path) {
|
|
55
|
+
return new Uint8Array(await readFile(path));
|
|
56
|
+
}
|
|
57
|
+
async writeFile(path, content) {
|
|
58
|
+
await writeFile(path, typeof content === "string" ? content : Buffer.from(content));
|
|
59
|
+
}
|
|
60
|
+
async stat(path) {
|
|
61
|
+
const stat = await lstat(path);
|
|
62
|
+
return {
|
|
63
|
+
isFile: stat.isFile(),
|
|
64
|
+
isDirectory: stat.isDirectory(),
|
|
65
|
+
...(stat.isSymbolicLink() ? { isSymbolicLink: true } : {}),
|
|
66
|
+
size: stat.size,
|
|
67
|
+
mtime: stat.mtime,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
async readdir(path) {
|
|
71
|
+
return await readdir(path);
|
|
72
|
+
}
|
|
73
|
+
async exists(path) {
|
|
74
|
+
try {
|
|
75
|
+
await access(path, constants.F_OK);
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
async mkdir(path, options) {
|
|
83
|
+
await mkdir(path, { recursive: options?.recursive });
|
|
84
|
+
}
|
|
85
|
+
async rm(path, options) {
|
|
86
|
+
await rm(path, { recursive: options?.recursive, force: options?.force });
|
|
87
|
+
}
|
|
88
|
+
async exec(command, options = {}) {
|
|
89
|
+
if (options.signal?.aborted) {
|
|
90
|
+
return { stdout: "", stderr: "command aborted before start\n", exitCode: 130 };
|
|
91
|
+
}
|
|
92
|
+
return await new Promise((resolveExec, reject) => {
|
|
93
|
+
let stdout = "";
|
|
94
|
+
let stderr = "";
|
|
95
|
+
let timedOut = false;
|
|
96
|
+
let aborted = false;
|
|
97
|
+
let settled = false;
|
|
98
|
+
let timeout;
|
|
99
|
+
const child = spawn(command, {
|
|
100
|
+
cwd: options.cwd ?? this.cwd,
|
|
101
|
+
detached: process.platform !== "win32",
|
|
102
|
+
env: { ...process.env, ...(options.env ?? {}) },
|
|
103
|
+
shell: true,
|
|
104
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
105
|
+
});
|
|
106
|
+
const finish = (result) => {
|
|
107
|
+
if (settled)
|
|
108
|
+
return;
|
|
109
|
+
settled = true;
|
|
110
|
+
if (timeout)
|
|
111
|
+
clearTimeout(timeout);
|
|
112
|
+
options.signal?.removeEventListener("abort", abort);
|
|
113
|
+
resolveExec(result);
|
|
114
|
+
};
|
|
115
|
+
const terminate = () => {
|
|
116
|
+
if (child.exitCode !== null || child.killed)
|
|
117
|
+
return;
|
|
118
|
+
killProcessGroup(child, "SIGTERM");
|
|
119
|
+
setTimeout(() => {
|
|
120
|
+
if (child.exitCode === null)
|
|
121
|
+
killProcessGroup(child, "SIGKILL");
|
|
122
|
+
}, 250).unref?.();
|
|
123
|
+
};
|
|
124
|
+
const abort = () => {
|
|
125
|
+
aborted = true;
|
|
126
|
+
stderr += "command aborted\n";
|
|
127
|
+
terminate();
|
|
128
|
+
};
|
|
129
|
+
timeout =
|
|
130
|
+
options.timeoutMs !== undefined
|
|
131
|
+
? setTimeout(() => {
|
|
132
|
+
timedOut = true;
|
|
133
|
+
stderr += `command timed out after ${options.timeoutMs}ms\n`;
|
|
134
|
+
terminate();
|
|
135
|
+
}, options.timeoutMs)
|
|
136
|
+
: undefined;
|
|
137
|
+
timeout?.unref?.();
|
|
138
|
+
options.signal?.addEventListener("abort", abort, { once: true });
|
|
139
|
+
child.stdout.setEncoding("utf8");
|
|
140
|
+
child.stderr.setEncoding("utf8");
|
|
141
|
+
child.stdout.on("data", (chunk) => {
|
|
142
|
+
stdout += chunk;
|
|
143
|
+
});
|
|
144
|
+
child.stderr.on("data", (chunk) => {
|
|
145
|
+
stderr += chunk;
|
|
146
|
+
});
|
|
147
|
+
child.on("error", (err) => {
|
|
148
|
+
if (timedOut)
|
|
149
|
+
finish({ stdout, stderr, exitCode: 124 });
|
|
150
|
+
else if (aborted)
|
|
151
|
+
finish({ stdout, stderr, exitCode: 130 });
|
|
152
|
+
else
|
|
153
|
+
reject(err);
|
|
154
|
+
});
|
|
155
|
+
child.on("close", (code, signal) => {
|
|
156
|
+
if (timedOut)
|
|
157
|
+
finish({ stdout, stderr, exitCode: 124 });
|
|
158
|
+
else if (aborted)
|
|
159
|
+
finish({ stdout, stderr, exitCode: 130 });
|
|
160
|
+
else
|
|
161
|
+
finish({ stdout, stderr, exitCode: code ?? exitCodeForSignal(signal) });
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
export function createNodeSandboxApi(options = {}) {
|
|
167
|
+
return new NodeSandboxApi(options);
|
|
168
|
+
}
|
|
169
|
+
export function createNodeSandboxSessionEnv(cwd = process.cwd()) {
|
|
170
|
+
return createSandboxSessionEnv(createNodeSandboxApi({ cwd }), cwd);
|
|
171
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { executeClaimTask, } from "./index.js";
|
|
2
|
+
let controller;
|
|
3
|
+
let forcedExit;
|
|
4
|
+
function send(message) {
|
|
5
|
+
return new Promise((resolve) => {
|
|
6
|
+
if (!process.send) {
|
|
7
|
+
resolve();
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
process.send(message, () => resolve());
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
function exitAfterError(message, code) {
|
|
14
|
+
void send({ type: "result", result: { kind: "error", message } }).finally(() => process.exit(code));
|
|
15
|
+
}
|
|
16
|
+
process.once("SIGTERM", () => {
|
|
17
|
+
controller?.abort();
|
|
18
|
+
forcedExit = setTimeout(() => process.exit(143), 4_500);
|
|
19
|
+
forcedExit.unref?.();
|
|
20
|
+
});
|
|
21
|
+
process.once("message", (message) => {
|
|
22
|
+
if (!message || message.type !== "run") {
|
|
23
|
+
exitAfterError("invalid task child message", 1);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
void (async () => {
|
|
27
|
+
controller = new AbortController();
|
|
28
|
+
const reporter = {
|
|
29
|
+
push: async (event) => {
|
|
30
|
+
await send({ type: "transcript", event });
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
let result;
|
|
34
|
+
try {
|
|
35
|
+
const convexUrl = message.options?.convexUrl;
|
|
36
|
+
if (!convexUrl)
|
|
37
|
+
throw new Error("task child message is missing convexUrl");
|
|
38
|
+
const output = await executeClaimTask(message.claim, {
|
|
39
|
+
convexUrl,
|
|
40
|
+
...(message.options?.cacheDir !== undefined ? { cacheDir: message.options.cacheDir } : {}),
|
|
41
|
+
...(message.options?.materializeEnvironments !== undefined
|
|
42
|
+
? { materializeEnvironments: message.options.materializeEnvironments }
|
|
43
|
+
: {}),
|
|
44
|
+
...(message.options?.verifyDeviceEnvironments !== undefined
|
|
45
|
+
? { verifyDeviceEnvironments: message.options.verifyDeviceEnvironments }
|
|
46
|
+
: {}),
|
|
47
|
+
signal: controller.signal,
|
|
48
|
+
reporter,
|
|
49
|
+
});
|
|
50
|
+
result = { kind: "ok", output };
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
if (controller.signal.aborted) {
|
|
54
|
+
result = { kind: "canceled" };
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
result = {
|
|
58
|
+
kind: "error",
|
|
59
|
+
message: err instanceof Error ? err.message : String(err),
|
|
60
|
+
...(err instanceof Error && err.stack !== undefined ? { stack: err.stack } : {}),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
finally {
|
|
65
|
+
if (forcedExit)
|
|
66
|
+
clearTimeout(forcedExit);
|
|
67
|
+
}
|
|
68
|
+
await send({ type: "result", result });
|
|
69
|
+
process.disconnect?.();
|
|
70
|
+
process.exit(0);
|
|
71
|
+
})();
|
|
72
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@reasonlayer/runner",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"import": "./dist/index.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "pnpm --filter @reasonlayer/protocol build && pnpm --filter @reasonlayer/integrations build && tsc -p tsconfig.json",
|
|
18
|
+
"test": "vitest run --passWithNoTests",
|
|
19
|
+
"typecheck": "pnpm --filter @reasonlayer/protocol build && pnpm --filter @reasonlayer/integrations build && tsc -p tsconfig.json --noEmit"
|
|
20
|
+
}
|
|
21
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@reasonlayer/sdk",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Author, validate, and compile Reasonlayer workflows.",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/reasonlayer/rl-1.git",
|
|
9
|
+
"directory": "packages/sdk"
|
|
10
|
+
},
|
|
11
|
+
"publishConfig": {
|
|
12
|
+
"access": "public"
|
|
13
|
+
},
|
|
14
|
+
"type": "module",
|
|
15
|
+
"files": [
|
|
16
|
+
"bin",
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"exports": {
|
|
20
|
+
".": {
|
|
21
|
+
"types": "./dist/index.d.ts",
|
|
22
|
+
"import": "./dist/index.js"
|
|
23
|
+
},
|
|
24
|
+
"./bundler": {
|
|
25
|
+
"types": "./dist/bundler/index.d.ts",
|
|
26
|
+
"import": "./dist/bundler/index.js"
|
|
27
|
+
},
|
|
28
|
+
"./testkit": {
|
|
29
|
+
"types": "./dist/testkit.d.ts",
|
|
30
|
+
"import": "./dist/testkit.js"
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"bin": {
|
|
34
|
+
"rl": "./bin/rl.mjs"
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "pnpm --filter @reasonlayer/runner build && tsc -p tsconfig.json",
|
|
38
|
+
"prepack": "pnpm build && node scripts/package-bundled-dependencies.mjs prepare",
|
|
39
|
+
"postpack": "node scripts/package-bundled-dependencies.mjs restore",
|
|
40
|
+
"test": "pnpm build && vitest run --exclude test/pinning.test.ts && vitest run test/pinning.test.ts",
|
|
41
|
+
"typecheck": "pnpm --filter @reasonlayer/runner build && tsc -p tsconfig.typecheck.json --noEmit"
|
|
42
|
+
},
|
|
43
|
+
"bundleDependencies": [
|
|
44
|
+
"@reasonlayer/integrations",
|
|
45
|
+
"@reasonlayer/protocol",
|
|
46
|
+
"@reasonlayer/runner"
|
|
47
|
+
],
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"@cfworker/json-schema": "^4.1.1",
|
|
50
|
+
"@flue/runtime": "1.0.0-beta.8",
|
|
51
|
+
"@napi-rs/keyring": "^1.3.0",
|
|
52
|
+
"@reasonlayer/integrations": "0.1.0",
|
|
53
|
+
"@reasonlayer/protocol": "0.1.0",
|
|
54
|
+
"@reasonlayer/runner": "0.1.0",
|
|
55
|
+
"@valibot/to-json-schema": "^1.3.0",
|
|
56
|
+
"convex": "^1.42.1",
|
|
57
|
+
"cron-parser": "5.6.1",
|
|
58
|
+
"esbuild": "^0.25.5",
|
|
59
|
+
"valibot": "^1.1.0",
|
|
60
|
+
"zod": "^4.4.3"
|
|
61
|
+
},
|
|
62
|
+
"devDependencies": {
|
|
63
|
+
"vitest": "^3.2.0"
|
|
64
|
+
}
|
|
65
|
+
}
|