@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.
Files changed (117) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +35 -0
  3. package/bin/rl.mjs +75 -0
  4. package/dist/builder.d.ts +38 -0
  5. package/dist/builder.js +41 -0
  6. package/dist/bundler/index.d.ts +32 -0
  7. package/dist/bundler/index.js +143 -0
  8. package/dist/bundler/lint.d.ts +13 -0
  9. package/dist/bundler/lint.js +74 -0
  10. package/dist/bundler/node.d.ts +10 -0
  11. package/dist/bundler/node.js +55 -0
  12. package/dist/bundler/smoke.d.ts +12 -0
  13. package/dist/bundler/smoke.js +70 -0
  14. package/dist/bundler/worker.d.ts +31 -0
  15. package/dist/bundler/worker.js +214 -0
  16. package/dist/cli/args.d.ts +9 -0
  17. package/dist/cli/args.js +71 -0
  18. package/dist/cli/config.d.ts +38 -0
  19. package/dist/cli/config.js +94 -0
  20. package/dist/cli/convex.d.ts +9 -0
  21. package/dist/cli/convex.js +25 -0
  22. package/dist/cli/format.d.ts +11 -0
  23. package/dist/cli/format.js +140 -0
  24. package/dist/cli/index.d.ts +1 -0
  25. package/dist/cli/index.js +721 -0
  26. package/dist/cli/keychain.d.ts +21 -0
  27. package/dist/cli/keychain.js +100 -0
  28. package/dist/cli/login-browser.d.ts +22 -0
  29. package/dist/cli/login-browser.js +106 -0
  30. package/dist/cli/mcp.d.ts +3 -0
  31. package/dist/cli/mcp.js +36 -0
  32. package/dist/cli/operations.d.ts +106 -0
  33. package/dist/cli/operations.js +623 -0
  34. package/dist/cli/sdk-package.d.ts +18 -0
  35. package/dist/cli/sdk-package.js +45 -0
  36. package/dist/cli/storage-upload.d.ts +9 -0
  37. package/dist/cli/storage-upload.js +21 -0
  38. package/dist/cli/watcher-compile.d.ts +1 -0
  39. package/dist/cli/watcher-compile.js +20 -0
  40. package/dist/cli/watcher-process.d.ts +1 -0
  41. package/dist/cli/watcher-process.js +312 -0
  42. package/dist/cli/worker-host.d.ts +10 -0
  43. package/dist/cli/worker-host.js +120 -0
  44. package/dist/cli/workspace-files.d.ts +12 -0
  45. package/dist/cli/workspace-files.js +91 -0
  46. package/dist/cli/workspace-local.d.ts +27 -0
  47. package/dist/cli/workspace-local.js +310 -0
  48. package/dist/cli/workspace-session.d.ts +13 -0
  49. package/dist/cli/workspace-session.js +12 -0
  50. package/dist/compile.d.ts +27 -0
  51. package/dist/compile.js +834 -0
  52. package/dist/index.d.ts +10 -0
  53. package/dist/index.js +5 -0
  54. package/dist/schedule-validation.d.ts +1 -0
  55. package/dist/schedule-validation.js +16 -0
  56. package/dist/selector-schema.d.ts +26 -0
  57. package/dist/selector-schema.js +780 -0
  58. package/dist/selectors.d.ts +25 -0
  59. package/dist/selectors.js +99 -0
  60. package/dist/testkit.d.ts +32 -0
  61. package/dist/testkit.js +161 -0
  62. package/dist/types.d.ts +184 -0
  63. package/dist/types.js +110 -0
  64. package/node_modules/@reasonlayer/integrations/dist/catalog.d.ts +4937 -0
  65. package/node_modules/@reasonlayer/integrations/dist/catalog.js +20 -0
  66. package/node_modules/@reasonlayer/integrations/dist/generated/slack.d.ts +3014 -0
  67. package/node_modules/@reasonlayer/integrations/dist/generated/slack.js +3101 -0
  68. package/node_modules/@reasonlayer/integrations/dist/index.d.ts +2 -0
  69. package/node_modules/@reasonlayer/integrations/dist/index.js +1 -0
  70. package/node_modules/@reasonlayer/integrations/dist/internal/definitions.d.ts +44 -0
  71. package/node_modules/@reasonlayer/integrations/dist/internal/definitions.js +52 -0
  72. package/node_modules/@reasonlayer/integrations/dist/internal/transport.d.ts +7 -0
  73. package/node_modules/@reasonlayer/integrations/dist/internal/transport.js +48 -0
  74. package/node_modules/@reasonlayer/integrations/dist/testkit.d.ts +1 -0
  75. package/node_modules/@reasonlayer/integrations/dist/testkit.js +1 -0
  76. package/node_modules/@reasonlayer/integrations/package.json +26 -0
  77. package/node_modules/@reasonlayer/protocol/dist/dispatch.d.ts +10 -0
  78. package/node_modules/@reasonlayer/protocol/dist/dispatch.js +58 -0
  79. package/node_modules/@reasonlayer/protocol/dist/envelope.d.ts +9 -0
  80. package/node_modules/@reasonlayer/protocol/dist/envelope.js +1 -0
  81. package/node_modules/@reasonlayer/protocol/dist/environments.d.ts +7 -0
  82. package/node_modules/@reasonlayer/protocol/dist/environments.js +7 -0
  83. package/node_modules/@reasonlayer/protocol/dist/events.d.ts +313 -0
  84. package/node_modules/@reasonlayer/protocol/dist/events.js +20 -0
  85. package/node_modules/@reasonlayer/protocol/dist/index.d.ts +18 -0
  86. package/node_modules/@reasonlayer/protocol/dist/index.js +9 -0
  87. package/node_modules/@reasonlayer/protocol/dist/ir.d.ts +252 -0
  88. package/node_modules/@reasonlayer/protocol/dist/ir.js +116 -0
  89. package/node_modules/@reasonlayer/protocol/dist/permissions.d.ts +5 -0
  90. package/node_modules/@reasonlayer/protocol/dist/permissions.js +30 -0
  91. package/node_modules/@reasonlayer/protocol/dist/readmodels.d.ts +617 -0
  92. package/node_modules/@reasonlayer/protocol/dist/readmodels.js +36 -0
  93. package/node_modules/@reasonlayer/protocol/dist/runtime.d.ts +67 -0
  94. package/node_modules/@reasonlayer/protocol/dist/runtime.js +66 -0
  95. package/node_modules/@reasonlayer/protocol/dist/scheduling.d.ts +69 -0
  96. package/node_modules/@reasonlayer/protocol/dist/scheduling.js +126 -0
  97. package/node_modules/@reasonlayer/protocol/dist/selector.d.ts +23 -0
  98. package/node_modules/@reasonlayer/protocol/dist/selector.js +77 -0
  99. package/node_modules/@reasonlayer/protocol/dist/tasks.d.ts +69 -0
  100. package/node_modules/@reasonlayer/protocol/dist/tasks.js +6 -0
  101. package/node_modules/@reasonlayer/protocol/dist/validate.d.ts +6 -0
  102. package/node_modules/@reasonlayer/protocol/dist/validate.js +18 -0
  103. package/node_modules/@reasonlayer/protocol/package.json +21 -0
  104. package/node_modules/@reasonlayer/runner/dist/environment-materializer.d.ts +13 -0
  105. package/node_modules/@reasonlayer/runner/dist/environment-materializer.js +92 -0
  106. package/node_modules/@reasonlayer/runner/dist/flue-transcript.d.ts +17 -0
  107. package/node_modules/@reasonlayer/runner/dist/flue-transcript.js +182 -0
  108. package/node_modules/@reasonlayer/runner/dist/index.d.ts +184 -0
  109. package/node_modules/@reasonlayer/runner/dist/index.js +884 -0
  110. package/node_modules/@reasonlayer/runner/dist/mcp-supervisor.d.ts +15 -0
  111. package/node_modules/@reasonlayer/runner/dist/mcp-supervisor.js +142 -0
  112. package/node_modules/@reasonlayer/runner/dist/sandbox-env.d.ts +36 -0
  113. package/node_modules/@reasonlayer/runner/dist/sandbox-env.js +171 -0
  114. package/node_modules/@reasonlayer/runner/dist/task-child.d.ts +1 -0
  115. package/node_modules/@reasonlayer/runner/dist/task-child.js +72 -0
  116. package/node_modules/@reasonlayer/runner/package.json +21 -0
  117. package/package.json +65 -0
@@ -0,0 +1,21 @@
1
+ export declare class KeychainUnavailableError extends Error {
2
+ constructor(message: string, options?: {
3
+ cause?: unknown;
4
+ });
5
+ }
6
+ export declare class KeychainAccessError extends Error {
7
+ constructor(message: string, options?: {
8
+ cause?: unknown;
9
+ });
10
+ }
11
+ /** Secret store keyed by account (we pass the Convex deployment URL). */
12
+ export interface KeychainBackend {
13
+ get(account: string): Promise<string | null>;
14
+ set(account: string, secret: string): Promise<void>;
15
+ delete(account: string): Promise<boolean>;
16
+ }
17
+ /** Test seam: swap the OS keychain for an in-memory backend. */
18
+ export declare function setKeychainBackend(backend: KeychainBackend | undefined): void;
19
+ export declare function getToken(account: string): Promise<string | null>;
20
+ export declare function setToken(account: string, token: string): Promise<void>;
21
+ export declare function deleteToken(account: string): Promise<boolean>;
@@ -0,0 +1,100 @@
1
+ /**
2
+ * OS keychain wrapper for the CLI's bearer token. The engine and dashboard tie
3
+ * identity to WorkOS/scoped tokens (spec §11); this keeps the human token out
4
+ * of a plaintext dotfile and in the platform secret store (macOS Keychain,
5
+ * Windows Credential Manager, Linux Secret Service).
6
+ *
7
+ * Keyed by the Convex deployment URL so one machine can hold tokens for several
8
+ * deployments. `get` returns `null` (not an error) when no token is stored.
9
+ * Failures split into two kinds so callers can act on the difference:
10
+ * - {@link KeychainUnavailableError}: the keychain module cannot load at all
11
+ * (unsupported platform / missing native binary). Callers fall through to
12
+ * the RL_TOKEN env path.
13
+ * - {@link KeychainAccessError}: a keychain is present but rejected the
14
+ * operation (locked, prompt denied, ambiguous credential, no storage
15
+ * backend). Callers surface a diagnostic — this is never silently a token
16
+ * "not found".
17
+ */
18
+ const SERVICE = "reasonlayer-cli";
19
+ export class KeychainUnavailableError extends Error {
20
+ constructor(message, options) {
21
+ super(message, options);
22
+ this.name = "KeychainUnavailableError";
23
+ }
24
+ }
25
+ export class KeychainAccessError extends Error {
26
+ constructor(message, options) {
27
+ super(message, options);
28
+ this.name = "KeychainAccessError";
29
+ }
30
+ }
31
+ let override;
32
+ /** Test seam: swap the OS keychain for an in-memory backend. */
33
+ export function setKeychainBackend(backend) {
34
+ override = backend;
35
+ }
36
+ let entryCtor;
37
+ async function loadEntryCtor() {
38
+ if (entryCtor)
39
+ return entryCtor;
40
+ try {
41
+ const mod = await import("@napi-rs/keyring");
42
+ entryCtor = mod.Entry;
43
+ return entryCtor;
44
+ }
45
+ catch (err) {
46
+ throw new KeychainUnavailableError("the OS keychain module could not be loaded", {
47
+ cause: err,
48
+ });
49
+ }
50
+ }
51
+ function reason(err) {
52
+ return err instanceof Error ? err.message : String(err);
53
+ }
54
+ function osBackend() {
55
+ return {
56
+ async get(account) {
57
+ const Entry = await loadEntryCtor();
58
+ try {
59
+ return new Entry(SERVICE, account).getPassword();
60
+ }
61
+ catch (err) {
62
+ throw new KeychainAccessError(`could not read from the OS keychain (${reason(err)})`, {
63
+ cause: err,
64
+ });
65
+ }
66
+ },
67
+ async set(account, secret) {
68
+ const Entry = await loadEntryCtor();
69
+ try {
70
+ new Entry(SERVICE, account).setPassword(secret);
71
+ }
72
+ catch (err) {
73
+ throw new KeychainAccessError(`could not write to the OS keychain (${reason(err)})`, {
74
+ cause: err,
75
+ });
76
+ }
77
+ },
78
+ async delete(account) {
79
+ const Entry = await loadEntryCtor();
80
+ try {
81
+ return new Entry(SERVICE, account).deletePassword();
82
+ }
83
+ catch {
84
+ return false;
85
+ }
86
+ },
87
+ };
88
+ }
89
+ function backend() {
90
+ return override ?? osBackend();
91
+ }
92
+ export function getToken(account) {
93
+ return backend().get(account);
94
+ }
95
+ export function setToken(account, token) {
96
+ return backend().set(account, token);
97
+ }
98
+ export function deleteToken(account) {
99
+ return backend().delete(account);
100
+ }
@@ -0,0 +1,22 @@
1
+ import type { RlxAccount } from "./config.js";
2
+ /**
3
+ * Browser loopback login (spec §12.2). The CLI opens a listener on
4
+ * `127.0.0.1:<random port>`, sends the user to the dashboard's `/cli-login`
5
+ * page with that port and a one-time `state` nonce, and the dashboard — after
6
+ * authenticating the user through WorkOS AuthKit — POSTs the minted access JWT
7
+ * back to the loopback. CORS is locked to the dashboard origin and the `state`
8
+ * nonce binds the callback to this request. No secret is ever typed or pasted.
9
+ */
10
+ export interface LoopbackCredentials {
11
+ token: string;
12
+ account: RlxAccount;
13
+ }
14
+ export interface LoopbackLoginOptions {
15
+ dashboardUrl: string;
16
+ /** Test/override seams. */
17
+ state?: string;
18
+ timeoutMs?: number;
19
+ open?: (url: string) => void;
20
+ onUrl?: (url: string) => void;
21
+ }
22
+ export declare function runLoopbackLogin(options: LoopbackLoginOptions): Promise<LoopbackCredentials>;
@@ -0,0 +1,106 @@
1
+ import { spawn } from "node:child_process";
2
+ import { randomBytes, timingSafeEqual } from "node:crypto";
3
+ import { createServer } from "node:http";
4
+ const DEFAULT_TIMEOUT_MS = 5 * 60 * 1000;
5
+ const MAX_BODY_BYTES = 64 * 1024;
6
+ function openBrowser(url) {
7
+ const [cmd, args] = process.platform === "darwin"
8
+ ? ["open", [url]]
9
+ : process.platform === "win32"
10
+ ? ["cmd", ["/c", "start", "", url]]
11
+ : ["xdg-open", [url]];
12
+ try {
13
+ spawn(cmd, args, { stdio: "ignore", detached: true }).unref();
14
+ }
15
+ catch {
16
+ // Best-effort; the URL is also printed for manual opening.
17
+ }
18
+ }
19
+ function nonceEquals(a, b) {
20
+ const ab = Buffer.from(a);
21
+ const bb = Buffer.from(b);
22
+ return ab.length === bb.length && timingSafeEqual(ab, bb);
23
+ }
24
+ async function readBody(req) {
25
+ const chunks = [];
26
+ let size = 0;
27
+ for await (const chunk of req) {
28
+ size += chunk.length;
29
+ if (size > MAX_BODY_BYTES) {
30
+ req.destroy();
31
+ throw new Error("request body too large");
32
+ }
33
+ chunks.push(chunk);
34
+ }
35
+ return Buffer.concat(chunks).toString("utf8");
36
+ }
37
+ export function runLoopbackLogin(options) {
38
+ const state = options.state ?? randomBytes(24).toString("hex");
39
+ const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
40
+ const origin = new URL(options.dashboardUrl).origin;
41
+ return new Promise((resolvePromise, rejectPromise) => {
42
+ let settled = false;
43
+ const finish = (fn) => {
44
+ if (settled)
45
+ return;
46
+ settled = true;
47
+ clearTimeout(timer);
48
+ server.close();
49
+ fn();
50
+ };
51
+ async function handlePost(req, res) {
52
+ let payload;
53
+ try {
54
+ payload = JSON.parse(await readBody(req));
55
+ }
56
+ catch {
57
+ res.writeHead(400, { "content-type": "application/json" }).end('{"error":"invalid request"}');
58
+ return;
59
+ }
60
+ if (typeof payload.state !== "string" || !nonceEquals(payload.state, state)) {
61
+ res.writeHead(403, { "content-type": "application/json" }).end('{"error":"state mismatch"}');
62
+ return;
63
+ }
64
+ const accessToken = payload.accessToken;
65
+ if (!accessToken) {
66
+ res
67
+ .writeHead(400, { "content-type": "application/json" })
68
+ .end('{"error":"missing accessToken"}');
69
+ return;
70
+ }
71
+ res.writeHead(200, { "content-type": "application/json" }).end('{"ok":true}');
72
+ const account = {
73
+ ...(payload.email !== undefined ? { email: payload.email } : {}),
74
+ ...(payload.orgId !== undefined ? { orgId: payload.orgId } : {}),
75
+ };
76
+ finish(() => resolvePromise({ token: accessToken, account }));
77
+ }
78
+ const server = createServer((req, res) => {
79
+ // Only the dashboard origin may POST the token back to us.
80
+ res.setHeader("Access-Control-Allow-Origin", origin);
81
+ res.setHeader("Access-Control-Allow-Methods", "POST, OPTIONS");
82
+ res.setHeader("Access-Control-Allow-Headers", "Content-Type");
83
+ if (req.method === "OPTIONS") {
84
+ res.writeHead(204).end();
85
+ return;
86
+ }
87
+ if (req.method !== "POST") {
88
+ res.writeHead(405).end();
89
+ return;
90
+ }
91
+ void handlePost(req, res);
92
+ });
93
+ const timer = setTimeout(() => {
94
+ finish(() => rejectPromise(new Error("browser login timed out")));
95
+ }, timeoutMs);
96
+ timer.unref();
97
+ server.on("error", (err) => finish(() => rejectPromise(err)));
98
+ server.listen(0, "127.0.0.1", () => {
99
+ const port = server.address().port;
100
+ const base = options.dashboardUrl.replace(/\/$/, "");
101
+ const url = `${base}/cli-login?callback_port=${port}&state=${state}`;
102
+ options.onUrl?.(url);
103
+ (options.open ?? openBrowser)(url);
104
+ });
105
+ });
106
+ }
@@ -0,0 +1,3 @@
1
+ import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
2
+ export declare function formatMcpResult(value: unknown): CallToolResult;
3
+ export declare function startMcpServer(): Promise<void>;
@@ -0,0 +1,36 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
+ import { loadConfig } from "./config.js";
4
+ import { createOperationRuntime, operationsForSurface, runOperation } from "./operations.js";
5
+ function isStructuredRecord(value) {
6
+ return typeof value === "object" && value !== null && !Array.isArray(value);
7
+ }
8
+ export function formatMcpResult(value) {
9
+ return {
10
+ content: [{ type: "text", text: JSON.stringify(value, null, 2) }],
11
+ structuredContent: isStructuredRecord(value) ? value : { value },
12
+ };
13
+ }
14
+ function errorResult(err) {
15
+ const message = err instanceof Error ? err.message : String(err);
16
+ return { isError: true, content: [{ type: "text", text: message }] };
17
+ }
18
+ export async function startMcpServer() {
19
+ const server = new McpServer({ name: "reasonlayer", version: "0.1.0" });
20
+ const runtime = createOperationRuntime(await loadConfig());
21
+ for (const operation of operationsForSurface("mcp")) {
22
+ server.registerTool(operation.name, {
23
+ title: operation.title,
24
+ description: operation.description,
25
+ inputSchema: operation.inputSchema,
26
+ }, async (args) => {
27
+ try {
28
+ return formatMcpResult(await runOperation(operation, { runtime }, args));
29
+ }
30
+ catch (err) {
31
+ return errorResult(err);
32
+ }
33
+ });
34
+ }
35
+ await server.connect(new StdioServerTransport());
36
+ }
@@ -0,0 +1,106 @@
1
+ import { z } from "zod/v4";
2
+ import { type BuildManifest } from "../bundler/index.js";
3
+ import type { RlConfig } from "./config.js";
4
+ export interface RunOptions {
5
+ workflowId: string;
6
+ input: unknown;
7
+ runKey?: string;
8
+ wait: boolean;
9
+ pollIntervalMs: number;
10
+ timeoutMs: number;
11
+ /** Test seam; production uses real timers. */
12
+ sleep?: (ms: number) => Promise<void>;
13
+ }
14
+ export interface DevRunOptions {
15
+ workflow: string;
16
+ input: unknown;
17
+ runKey?: string;
18
+ pollIntervalMs: number;
19
+ timeoutMs: number;
20
+ concurrency?: number;
21
+ signal?: AbortSignal;
22
+ onRunCreated?: (created: {
23
+ runId: string;
24
+ deduped: boolean;
25
+ }) => void;
26
+ }
27
+ export interface RlClient {
28
+ query<T>(name: string, args: Record<string, unknown>): Promise<T>;
29
+ mutation<T>(name: string, args: Record<string, unknown>): Promise<T>;
30
+ action<T>(name: string, args: Record<string, unknown>): Promise<T>;
31
+ }
32
+ export interface OperationRuntime {
33
+ config: RlConfig;
34
+ client: RlClient;
35
+ }
36
+ export declare function createOperationRuntime(config: RlConfig, client?: RlClient): OperationRuntime;
37
+ export declare const DEFAULT_POLL_INTERVAL_MS = 1000;
38
+ export declare const DEFAULT_RUN_TIMEOUT_MS = 600000;
39
+ export declare function validateWorkflow(entry: string): Promise<{
40
+ ok: true;
41
+ manifest: BuildManifest;
42
+ ir: unknown;
43
+ } | {
44
+ ok: false;
45
+ errors: {
46
+ stepId?: string;
47
+ message: string;
48
+ }[];
49
+ }>;
50
+ export declare function buildProject(entry: string, outDir: string): Promise<{
51
+ ok: true;
52
+ manifest: BuildManifest;
53
+ outDir: string;
54
+ } | {
55
+ ok: false;
56
+ errors: {
57
+ stepId?: string;
58
+ message: string;
59
+ }[];
60
+ }>;
61
+ export declare function runWorkflow(runtime: OperationRuntime, options: RunOptions): Promise<unknown>;
62
+ export declare function devWorkflow(runtime: OperationRuntime, options: DevRunOptions): Promise<{
63
+ ok: false;
64
+ errors: {
65
+ stepId?: string;
66
+ message: string;
67
+ }[];
68
+ } | ({
69
+ ok: true;
70
+ testArtifactId: string;
71
+ expiresAt: number;
72
+ deduped: boolean;
73
+ } & Record<string, unknown>)>;
74
+ export type OperationSurface = "cli";
75
+ export interface OperationRunContext {
76
+ runtime?: OperationRuntime;
77
+ }
78
+ /** A backend function this operation forwards to, with the org token attached. */
79
+ export interface OperationCall {
80
+ kind: "query" | "mutation" | "action";
81
+ fn: string;
82
+ }
83
+ interface OperationCommon {
84
+ name: string;
85
+ title: string;
86
+ description: string;
87
+ inputSchema: Record<string, z.ZodType>;
88
+ surfaces: readonly OperationSurface[];
89
+ }
90
+ /**
91
+ * An operation either forwards its parsed input to one backend function
92
+ * (`call`) or has a local implementation deep enough to name (`run`).
93
+ */
94
+ export type OperationDefinition = (OperationCommon & {
95
+ call: OperationCall;
96
+ run?: undefined;
97
+ }) | (OperationCommon & {
98
+ call?: undefined;
99
+ run: (ctx: OperationRunContext, args: Record<string, unknown>) => Promise<unknown>;
100
+ });
101
+ export declare function runOperation(operation: OperationDefinition, ctx: OperationRunContext, args: Record<string, unknown>): Promise<unknown>;
102
+ export declare const operationTable: OperationDefinition[];
103
+ export declare function operationsForSurface(surface: OperationSurface): OperationDefinition[];
104
+ export declare function operationByName(name: string): OperationDefinition | undefined;
105
+ export declare function operationForSurfaceByName(surface: OperationSurface, name: string): OperationDefinition | undefined;
106
+ export {};