@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,623 @@
1
+ import { mkdtemp, readFile, rm } from "node:fs/promises";
2
+ import { join, resolve } from "node:path";
3
+ import { tmpdir } from "node:os";
4
+ import { z } from "zod/v4";
5
+ import { APPROVAL_STATUSES, FN, isTerminalRunStatus } from "@reasonlayer/protocol";
6
+ import { runTestRun } from "@reasonlayer/runner";
7
+ import { buildWorkflow } from "../bundler/index.js";
8
+ import { RlConvexClient } from "./convex.js";
9
+ import { createCheckout, endLocalSession, readLocalSession, } from "./workspace-local.js";
10
+ import { sdkVersion } from "./sdk-package.js";
11
+ import { uploadStorage } from "./storage-upload.js";
12
+ export function createOperationRuntime(config, client = new RlConvexClient(config)) {
13
+ return { config, client };
14
+ }
15
+ export const DEFAULT_POLL_INTERVAL_MS = 1000;
16
+ export const DEFAULT_RUN_TIMEOUT_MS = 600_000;
17
+ async function readJson(path) {
18
+ return JSON.parse(await readFile(path, "utf8"));
19
+ }
20
+ function omitUndefined(value) {
21
+ return Object.fromEntries(Object.entries(value).filter(([, v]) => v !== undefined));
22
+ }
23
+ function sleep(ms) {
24
+ return new Promise((resolveSleep) => setTimeout(resolveSleep, ms));
25
+ }
26
+ function contentTypeFor(path) {
27
+ if (path.endsWith(".json"))
28
+ return "application/json";
29
+ if (path.endsWith(".js") || path.endsWith(".mjs"))
30
+ return "application/javascript";
31
+ return "application/octet-stream";
32
+ }
33
+ async function uploadFile(client, token, path, uploadUrlFunction, uploadUrlArgs = {}) {
34
+ const bytes = await readFile(path);
35
+ return await uploadStorage(async () => await client.mutation(uploadUrlFunction, { token, ...uploadUrlArgs }), bytes, { contentType: contentTypeFor(path), label: path });
36
+ }
37
+ export async function validateWorkflow(entry) {
38
+ const temp = await mkdtemp(join(tmpdir(), "rl-validate-"));
39
+ try {
40
+ const result = await buildWorkflow(entry, temp);
41
+ if (!result.ok)
42
+ return result;
43
+ return { ok: true, manifest: result.manifest, ir: result.ir };
44
+ }
45
+ finally {
46
+ await rm(temp, { recursive: true, force: true });
47
+ }
48
+ }
49
+ export async function buildProject(entry, outDir) {
50
+ const result = await buildWorkflow(entry, outDir);
51
+ if (!result.ok)
52
+ return result;
53
+ return { ok: true, manifest: result.manifest, outDir: result.outDir };
54
+ }
55
+ async function createTestArtifactFromDist(distDir, runtime, flueVersion) {
56
+ const dist = resolve(distDir);
57
+ const manifest = await readJson(join(dist, "manifest.json"));
58
+ const irJson = await readFile(join(dist, manifest.artifacts.ir), "utf8");
59
+ const { client, config } = runtime;
60
+ const stepsBundle = await uploadFile(client, config.token, join(dist, manifest.artifacts.steps), FN.testArtifactsGenerateUploadUrl);
61
+ const agentBundle = manifest.artifacts.agents
62
+ ? await uploadFile(client, config.token, join(dist, manifest.artifacts.agents), FN.testArtifactsGenerateUploadUrl)
63
+ : undefined;
64
+ const created = await client.mutation(FN.testArtifactsCreate, omitUndefined({
65
+ token: config.token,
66
+ irJson,
67
+ stepsBundleId: stepsBundle.storageId,
68
+ stepsBundleSha256: stepsBundle.sha256,
69
+ agentBundleId: agentBundle?.storageId,
70
+ agentBundleSha256: agentBundle?.sha256,
71
+ sdkVersion: await sdkVersion(),
72
+ flueVersion,
73
+ }));
74
+ return {
75
+ testArtifactId: created.testArtifactId,
76
+ workflowId: created.workflowId,
77
+ inputSchema: JSON.parse(created.inputSchemaJsonText),
78
+ expiresAt: created.expiresAt,
79
+ };
80
+ }
81
+ export async function runWorkflow(runtime, options) {
82
+ const { client, config } = runtime;
83
+ const latest = await client.query(FN.deploymentsLatestFor, {
84
+ token: config.token,
85
+ workflowId: options.workflowId,
86
+ });
87
+ if (!latest)
88
+ throw new Error(`no deployment found for workflow "${options.workflowId}"`);
89
+ const created = await client.mutation(FN.runsCreate, omitUndefined({
90
+ token: config.token,
91
+ deploymentId: latest.deploymentId,
92
+ input: options.input,
93
+ runKey: options.runKey,
94
+ }));
95
+ if (!options.wait)
96
+ return created;
97
+ const deadline = Date.now() + options.timeoutMs;
98
+ while (Date.now() < deadline) {
99
+ const run = await client.query(FN.runsGet, { token: config.token, runId: created.runId });
100
+ if (isTerminalRunStatus(run.status))
101
+ return { ...run, deduped: created.deduped };
102
+ await (options.sleep ?? sleep)(options.pollIntervalMs);
103
+ }
104
+ throw new Error(`run ${created.runId} did not finish within ${options.timeoutMs}ms`);
105
+ }
106
+ export async function devWorkflow(runtime, options) {
107
+ const temp = await mkdtemp(join(tmpdir(), "rl-dev-"));
108
+ try {
109
+ const built = await buildWorkflow(options.workflow, temp);
110
+ if (!built.ok)
111
+ return { ok: false, errors: built.errors };
112
+ const artifact = await createTestArtifactFromDist(built.outDir, runtime, built.flueVersion);
113
+ const created = await runtime.client.mutation(FN.runsCreateTest, {
114
+ token: runtime.config.token,
115
+ testArtifactId: artifact.testArtifactId,
116
+ input: options.input,
117
+ ...(options.runKey !== undefined ? { runKey: options.runKey } : {}),
118
+ });
119
+ if (!created.executorToken) {
120
+ throw new Error("test run executor token was not returned");
121
+ }
122
+ options.onRunCreated?.({ runId: created.runId, deduped: created.deduped });
123
+ const run = await runTestRun({
124
+ convexUrl: runtime.config.convexUrl,
125
+ token: runtime.config.token,
126
+ runId: created.runId,
127
+ executorToken: created.executorToken,
128
+ pollIntervalMs: options.pollIntervalMs,
129
+ ...(options.concurrency !== undefined ? { concurrency: options.concurrency } : {}),
130
+ ...(options.signal !== undefined ? { signal: options.signal } : {}),
131
+ });
132
+ return {
133
+ ok: true,
134
+ ...run,
135
+ deduped: created.deduped,
136
+ testArtifactId: artifact.testArtifactId,
137
+ expiresAt: artifact.expiresAt,
138
+ };
139
+ }
140
+ finally {
141
+ await rm(temp, { recursive: true, force: true });
142
+ }
143
+ }
144
+ export async function runOperation(operation, ctx, args) {
145
+ const validated = z.object(operation.inputSchema).passthrough().safeParse(args);
146
+ if (!validated.success) {
147
+ throw new Error(`invalid ${operation.name} input: ${z.prettifyError(validated.error)}`);
148
+ }
149
+ const parsed = validated.data;
150
+ if (!operation.call)
151
+ return await operation.run(ctx, parsed);
152
+ const runtime = requireRuntime(ctx);
153
+ const forwarded = omitUndefined(Object.fromEntries(Object.keys(operation.inputSchema).map((key) => [key, parsed[key]])));
154
+ return await runtime.client[operation.call.kind](operation.call.fn, {
155
+ token: runtime.config.token,
156
+ ...forwarded,
157
+ });
158
+ }
159
+ function requireRuntime(ctx) {
160
+ if (!ctx.runtime)
161
+ throw new Error("operation requires Reasonlayer config");
162
+ return ctx.runtime;
163
+ }
164
+ function optionalNumberArg(args, key) {
165
+ const value = args[key];
166
+ return typeof value === "number" ? value : undefined;
167
+ }
168
+ function optionalStringArg(args, key) {
169
+ const value = args[key];
170
+ return typeof value === "string" ? value : undefined;
171
+ }
172
+ export const operationTable = [
173
+ {
174
+ name: "validate",
175
+ title: "Validate workflow",
176
+ description: "Compile and bundle a workflow in a temporary directory, returning structured errors.",
177
+ inputSchema: { workflow: z.string() },
178
+ surfaces: ["cli"],
179
+ run: async (_ctx, args) => await validateWorkflow(args["workflow"]),
180
+ },
181
+ {
182
+ name: "whoami",
183
+ title: "Current org",
184
+ description: "Return the configured Reasonlayer organization identity.",
185
+ inputSchema: {},
186
+ surfaces: ["cli"],
187
+ call: { kind: "query", fn: FN.orgsWhoami },
188
+ },
189
+ {
190
+ name: "bootstrap_dev_org",
191
+ title: "Bootstrap dev org",
192
+ description: "Self-provision a development organization for the token being logged in.",
193
+ inputSchema: { name: z.string() },
194
+ surfaces: ["cli"],
195
+ call: { kind: "mutation", fn: FN.orgsBootstrapDev },
196
+ },
197
+ {
198
+ name: "init_workspace",
199
+ title: "Initialize workflow workspace",
200
+ description: "Create a draft workflow, materialize a checkout, and start its detached watcher.",
201
+ inputSchema: { workflowId: z.string(), targetDir: z.string().optional() },
202
+ surfaces: ["cli"],
203
+ run: async (ctx, args) => await createCheckout(requireRuntime(ctx), {
204
+ workflowId: args["workflowId"],
205
+ mode: "init",
206
+ ...(optionalStringArg(args, "targetDir") !== undefined
207
+ ? { targetDir: optionalStringArg(args, "targetDir") }
208
+ : {}),
209
+ }),
210
+ },
211
+ {
212
+ name: "pull_workspace",
213
+ title: "Pull workflow workspace",
214
+ description: "Materialize the cloud draft head in a fresh checkout and start its watcher.",
215
+ inputSchema: { workflowId: z.string(), targetDir: z.string().optional() },
216
+ surfaces: ["cli"],
217
+ run: async (ctx, args) => await createCheckout(requireRuntime(ctx), {
218
+ workflowId: args["workflowId"],
219
+ mode: "pull",
220
+ ...(optionalStringArg(args, "targetDir") !== undefined
221
+ ? { targetDir: optionalStringArg(args, "targetDir") }
222
+ : {}),
223
+ }),
224
+ },
225
+ {
226
+ name: "done_workspace",
227
+ title: "Finish workspace session",
228
+ description: "End the authoring session, stop its watcher, and remove the ephemeral checkout.",
229
+ inputSchema: {},
230
+ surfaces: ["cli"],
231
+ run: async (ctx) => await endLocalSession(requireRuntime(ctx)),
232
+ },
233
+ {
234
+ name: "workspace_status",
235
+ title: "Workspace status",
236
+ description: "Read watcher liveness, compile state, and draft-versus-published state.",
237
+ inputSchema: {},
238
+ surfaces: ["cli"],
239
+ run: async (ctx) => {
240
+ const runtime = requireRuntime(ctx);
241
+ const session = await readLocalSession();
242
+ return await runtime.client.query(FN.workspacesStatus, {
243
+ token: runtime.config.token,
244
+ workflowId: session.workflowId,
245
+ sessionId: session.sessionId,
246
+ });
247
+ },
248
+ },
249
+ {
250
+ name: "publish_workspace",
251
+ title: "Publish workspace",
252
+ description: "Promote the latest green draft artifact to an immutable version.",
253
+ inputSchema: {},
254
+ surfaces: ["cli"],
255
+ run: async (ctx) => {
256
+ const runtime = requireRuntime(ctx);
257
+ const session = await readLocalSession();
258
+ return await runtime.client.mutation(FN.workspacesPublish, {
259
+ token: runtime.config.token,
260
+ workflowId: session.workflowId,
261
+ });
262
+ },
263
+ },
264
+ {
265
+ name: "list_workflow_versions",
266
+ title: "List workflow versions",
267
+ description: "List immutable published versions for a workflow.",
268
+ inputSchema: { workflowId: z.string() },
269
+ surfaces: ["cli"],
270
+ call: { kind: "query", fn: FN.workspacesListVersions },
271
+ },
272
+ {
273
+ name: "publish_workflow_version",
274
+ title: "Publish previous workflow version",
275
+ description: "Make a selected immutable version the workflow's published version.",
276
+ inputSchema: { workflowId: z.string(), versionId: z.string() },
277
+ surfaces: ["cli"],
278
+ call: { kind: "mutation", fn: FN.workspacesRollback },
279
+ },
280
+ {
281
+ name: "build",
282
+ title: "Build workflow",
283
+ description: "Compile and bundle a workflow to a local dist directory.",
284
+ inputSchema: { workflow: z.string(), outDir: z.string().optional() },
285
+ surfaces: ["cli"],
286
+ run: async (_ctx, args) => await buildProject(args["workflow"], optionalStringArg(args, "outDir") ?? "dist"),
287
+ },
288
+ {
289
+ name: "run",
290
+ title: "Run workflow",
291
+ description: "Start a run for the latest deployment of a workflow and optionally wait for completion.",
292
+ inputSchema: {
293
+ workflowId: z.string(),
294
+ input: z.unknown().optional(),
295
+ runKey: z.string().optional(),
296
+ wait: z.boolean().optional(),
297
+ pollIntervalMs: z.number().optional(),
298
+ timeoutMs: z.number().optional(),
299
+ },
300
+ surfaces: ["cli"],
301
+ run: async (ctx, args) => await runWorkflow(requireRuntime(ctx), {
302
+ workflowId: args["workflowId"],
303
+ input: args["input"] ?? {},
304
+ ...(optionalStringArg(args, "runKey") !== undefined
305
+ ? { runKey: optionalStringArg(args, "runKey") }
306
+ : {}),
307
+ wait: args["wait"] !== false,
308
+ pollIntervalMs: optionalNumberArg(args, "pollIntervalMs") ?? DEFAULT_POLL_INTERVAL_MS,
309
+ timeoutMs: optionalNumberArg(args, "timeoutMs") ?? DEFAULT_RUN_TIMEOUT_MS,
310
+ ...(typeof args["sleep"] === "function"
311
+ ? { sleep: args["sleep"] }
312
+ : {}),
313
+ }),
314
+ },
315
+ {
316
+ name: "dev",
317
+ title: "Run workflow from source",
318
+ description: "Build a workflow from source, create an ephemeral test run, and execute it locally.",
319
+ inputSchema: {
320
+ workflow: z.string(),
321
+ input: z.unknown().optional(),
322
+ runKey: z.string().optional(),
323
+ pollIntervalMs: z.number().optional(),
324
+ timeoutMs: z.number().optional(),
325
+ concurrency: z.number().optional(),
326
+ },
327
+ surfaces: ["cli"],
328
+ run: async (ctx, args) => await devWorkflow(requireRuntime(ctx), {
329
+ workflow: args["workflow"],
330
+ input: args["input"] ?? {},
331
+ ...(optionalStringArg(args, "runKey") !== undefined
332
+ ? { runKey: optionalStringArg(args, "runKey") }
333
+ : {}),
334
+ pollIntervalMs: optionalNumberArg(args, "pollIntervalMs") ?? DEFAULT_POLL_INTERVAL_MS,
335
+ timeoutMs: optionalNumberArg(args, "timeoutMs") ?? DEFAULT_RUN_TIMEOUT_MS,
336
+ ...(optionalNumberArg(args, "concurrency") !== undefined
337
+ ? { concurrency: optionalNumberArg(args, "concurrency") }
338
+ : {}),
339
+ ...(args["signal"] instanceof AbortSignal ? { signal: args["signal"] } : {}),
340
+ ...(typeof args["onRunCreated"] === "function"
341
+ ? { onRunCreated: args["onRunCreated"] }
342
+ : {}),
343
+ }),
344
+ },
345
+ {
346
+ name: "list_runs",
347
+ title: "List runs",
348
+ description: "List recent runs for the configured Reasonlayer org.",
349
+ inputSchema: { limit: z.number().optional() },
350
+ surfaces: ["cli"],
351
+ call: { kind: "query", fn: FN.runsList },
352
+ },
353
+ {
354
+ name: "inspect",
355
+ title: "Inspect run",
356
+ description: "Read run, step, usage, and paginated transcript state for a Reasonlayer run.",
357
+ inputSchema: {
358
+ runId: z.string(),
359
+ transcriptCursor: z.string().optional(),
360
+ transcriptLimit: z.number().optional(),
361
+ },
362
+ surfaces: ["cli"],
363
+ run: async (ctx, args) => {
364
+ const { client, config } = requireRuntime(ctx);
365
+ const runId = args["runId"];
366
+ const [inspection, transcript] = await Promise.all([
367
+ client.query(FN.runsInspect, { token: config.token, runId }),
368
+ client.query(FN.transcriptsList, omitUndefined({
369
+ token: config.token,
370
+ runId,
371
+ cursor: optionalStringArg(args, "transcriptCursor"),
372
+ limit: optionalNumberArg(args, "transcriptLimit") ?? 100,
373
+ })),
374
+ ]);
375
+ return { ...inspection, transcript };
376
+ },
377
+ },
378
+ {
379
+ name: "get_deployment",
380
+ title: "Get deployment",
381
+ description: "Read deployment metadata, bundle provenance, and environment build status.",
382
+ inputSchema: { deploymentId: z.string() },
383
+ surfaces: ["cli"],
384
+ call: { kind: "query", fn: FN.deploymentsGet },
385
+ },
386
+ {
387
+ name: "cancel_run",
388
+ title: "Cancel run",
389
+ description: "Cancel a running Reasonlayer run.",
390
+ inputSchema: { runId: z.string() },
391
+ surfaces: ["cli"],
392
+ call: { kind: "mutation", fn: FN.runsCancel },
393
+ },
394
+ {
395
+ name: "cancel_step",
396
+ title: "Cancel step",
397
+ description: "Cancel a live executable step attempt. The authored retry policy still applies.",
398
+ inputSchema: { runId: z.string(), stepId: z.string(), invocationKey: z.string().optional() },
399
+ surfaces: ["cli"],
400
+ call: { kind: "mutation", fn: FN.runsCancelStep },
401
+ },
402
+ {
403
+ name: "retry_run",
404
+ title: "Retry run",
405
+ description: "Retry a failed Reasonlayer run, reusing succeeded step outputs.",
406
+ inputSchema: { runId: z.string() },
407
+ surfaces: ["cli"],
408
+ call: { kind: "mutation", fn: FN.runsRetry },
409
+ },
410
+ {
411
+ name: "set_secret",
412
+ title: "Set secret",
413
+ description: "Set or replace an encrypted org secret.",
414
+ inputSchema: { name: z.string(), value: z.string() },
415
+ surfaces: ["cli"],
416
+ call: { kind: "mutation", fn: FN.secretsSet },
417
+ },
418
+ {
419
+ name: "list_secrets",
420
+ title: "List secrets",
421
+ description: "List encrypted org secret names and timestamps without exposing values.",
422
+ inputSchema: {},
423
+ surfaces: ["cli"],
424
+ call: { kind: "query", fn: FN.secretsList },
425
+ },
426
+ {
427
+ name: "remove_secret",
428
+ title: "Remove secret",
429
+ description: "Delete an encrypted org secret.",
430
+ inputSchema: { name: z.string() },
431
+ surfaces: ["cli"],
432
+ call: { kind: "mutation", fn: FN.secretsRemove },
433
+ },
434
+ {
435
+ name: "set_variable",
436
+ title: "Set workflow variable",
437
+ description: "Set a structured workflow variable override for future runs.",
438
+ inputSchema: { workflowId: z.string(), name: z.string(), value: z.unknown() },
439
+ surfaces: ["cli"],
440
+ call: { kind: "mutation", fn: FN.variablesSet },
441
+ },
442
+ {
443
+ name: "list_variables",
444
+ title: "List workflow variables",
445
+ description: "List declared workflow variables, defaults, and current overrides.",
446
+ inputSchema: { workflowId: z.string() },
447
+ surfaces: ["cli"],
448
+ call: { kind: "query", fn: FN.variablesList },
449
+ },
450
+ {
451
+ name: "remove_variable",
452
+ title: "Remove workflow variable override",
453
+ description: "Remove a workflow variable override so its declared default applies.",
454
+ inputSchema: { workflowId: z.string(), name: z.string() },
455
+ surfaces: ["cli"],
456
+ call: { kind: "mutation", fn: FN.variablesRemove },
457
+ },
458
+ {
459
+ name: "list_reviews",
460
+ title: "List reviews",
461
+ description: "List review approvals for the configured Reasonlayer org.",
462
+ inputSchema: {
463
+ status: z.enum(APPROVAL_STATUSES).optional(),
464
+ limit: z.number().optional(),
465
+ },
466
+ surfaces: ["cli"],
467
+ call: { kind: "query", fn: FN.approvalsList },
468
+ },
469
+ {
470
+ name: "approve_review",
471
+ title: "Approve review",
472
+ description: "Resolve a pending review with a decision matching the step output schema.",
473
+ inputSchema: { approvalId: z.string(), decision: z.unknown() },
474
+ surfaces: ["cli"],
475
+ call: { kind: "mutation", fn: FN.approvalsApprove },
476
+ },
477
+ {
478
+ name: "reject_review",
479
+ title: "Reject review",
480
+ description: "Reject a pending review and resume the run as a step failure.",
481
+ inputSchema: { approvalId: z.string(), reason: z.string().optional() },
482
+ surfaces: ["cli"],
483
+ call: { kind: "mutation", fn: FN.approvalsReject },
484
+ },
485
+ {
486
+ name: "list_triggers",
487
+ title: "List triggers",
488
+ description: "List named workflow triggers and their subscribed countdown state.",
489
+ inputSchema: {},
490
+ surfaces: ["cli"],
491
+ call: { kind: "query", fn: FN.triggersList },
492
+ },
493
+ {
494
+ name: "set_trigger_enabled",
495
+ title: "Enable or disable trigger",
496
+ description: "Change operator enablement without changing authored trigger configuration.",
497
+ inputSchema: { triggerId: z.string(), enabled: z.boolean() },
498
+ surfaces: ["cli"],
499
+ call: { kind: "mutation", fn: FN.triggersSetEnabled },
500
+ },
501
+ {
502
+ name: "delete_workflow",
503
+ title: "Delete workflow",
504
+ description: "Delete a workflow, its versions, deployments, triggers, and stored artifacts.",
505
+ inputSchema: { workflowId: z.string() },
506
+ surfaces: ["cli"],
507
+ call: { kind: "mutation", fn: FN.deploymentsDeleteWorkflow },
508
+ },
509
+ {
510
+ name: "create_token",
511
+ title: "Create token",
512
+ description: "Create a scoped platform token.",
513
+ inputSchema: {
514
+ label: z.string(),
515
+ scopes: z.array(z.string()),
516
+ workflowIds: z.array(z.string()).optional(),
517
+ expiresAt: z.number().optional(),
518
+ },
519
+ surfaces: ["cli"],
520
+ call: { kind: "mutation", fn: FN.tokensCreate },
521
+ },
522
+ {
523
+ name: "list_tokens",
524
+ title: "List tokens",
525
+ description: "List scoped platform tokens without revealing their values.",
526
+ inputSchema: {},
527
+ surfaces: ["cli"],
528
+ call: { kind: "query", fn: FN.tokensList },
529
+ },
530
+ {
531
+ name: "revoke_token",
532
+ title: "Revoke token",
533
+ description: "Revoke a scoped platform token.",
534
+ inputSchema: { tokenId: z.string() },
535
+ surfaces: ["cli"],
536
+ call: { kind: "mutation", fn: FN.tokensRevoke },
537
+ },
538
+ {
539
+ name: "list_devices",
540
+ title: "List devices",
541
+ description: "List registered devices for the configured Reasonlayer org.",
542
+ inputSchema: {},
543
+ surfaces: ["cli"],
544
+ call: { kind: "query", fn: FN.devicesList },
545
+ },
546
+ {
547
+ name: "register_device",
548
+ title: "Register device",
549
+ description: "Register a device and return its durable secret once.",
550
+ inputSchema: {
551
+ name: z.string(),
552
+ settings: z.record(z.string(), z.unknown()).optional(),
553
+ },
554
+ surfaces: ["cli"],
555
+ call: { kind: "action", fn: FN.devicesRegister },
556
+ },
557
+ {
558
+ name: "bind_device_handle",
559
+ title: "Bind device handle",
560
+ description: "Bind or rebind a workflow device handle to a registered machine.",
561
+ inputSchema: { handle: z.string(), deviceId: z.string() },
562
+ surfaces: ["cli"],
563
+ call: { kind: "mutation", fn: FN.devicesBindHandle },
564
+ },
565
+ {
566
+ name: "update_device",
567
+ title: "Update device",
568
+ description: "Update a registered device's name, enabled state, or settings.",
569
+ inputSchema: {
570
+ deviceId: z.string(),
571
+ name: z.string().optional(),
572
+ enabled: z.boolean().optional(),
573
+ settings: z.record(z.string(), z.unknown()).optional(),
574
+ },
575
+ surfaces: ["cli"],
576
+ call: { kind: "mutation", fn: FN.devicesUpdate },
577
+ },
578
+ {
579
+ name: "rotate_device_secret",
580
+ title: "Rotate device secret",
581
+ description: "Rotate a registered device's durable secret. The new secret is returned once.",
582
+ inputSchema: { deviceId: z.string() },
583
+ surfaces: ["cli"],
584
+ call: { kind: "mutation", fn: FN.devicesRotateSecret },
585
+ },
586
+ {
587
+ name: "list_device_profiles",
588
+ title: "List device profiles",
589
+ description: "List browser profiles, optionally scoped to one device.",
590
+ inputSchema: { deviceId: z.string().optional() },
591
+ surfaces: ["cli"],
592
+ call: { kind: "query", fn: FN.devicesListProfiles },
593
+ },
594
+ {
595
+ name: "create_device_profile",
596
+ title: "Create device profile",
597
+ description: "Create or re-enable a browser profile for a device.",
598
+ inputSchema: {
599
+ deviceId: z.string(),
600
+ profileKey: z.string(),
601
+ label: z.string().optional(),
602
+ },
603
+ surfaces: ["cli"],
604
+ call: { kind: "mutation", fn: FN.devicesCreateProfile },
605
+ },
606
+ {
607
+ name: "request_device_profile_login",
608
+ title: "Request device profile login",
609
+ description: "Ask a device daemon to complete login for a browser profile.",
610
+ inputSchema: { profileId: z.string(), message: z.string().optional() },
611
+ surfaces: ["cli"],
612
+ call: { kind: "mutation", fn: FN.devicesRequestProfileLogin },
613
+ },
614
+ ];
615
+ export function operationsForSurface(surface) {
616
+ return operationTable.filter((operation) => operation.surfaces.includes(surface));
617
+ }
618
+ export function operationByName(name) {
619
+ return operationTable.find((operation) => operation.name === name);
620
+ }
621
+ export function operationForSurfaceByName(surface, name) {
622
+ return operationsForSurface(surface).find((operation) => operation.name === name);
623
+ }
@@ -0,0 +1,18 @@
1
+ export declare const SDK_ROOT: string;
2
+ export declare function sdkVersion(): Promise<string>;
3
+ /** A single semver release, with no range operator — what a checkout may pin. */
4
+ export declare const EXACT_VERSION: RegExp;
5
+ /**
6
+ * The Flue runtime a checkout must install to match this SDK. It is the SDK's
7
+ * own dependency because the bundled runner resolves Flue from the SDK's tree —
8
+ * so read it, never copy it. It must be exact: scaffolds write it straight into
9
+ * a checkout pin, and a range there is not a pin.
10
+ */
11
+ export declare function pairedFlueRuntimeVersion(): Promise<string>;
12
+ export interface SdkProvenance {
13
+ version: string;
14
+ installSource: "installed" | "local checkout";
15
+ repoRoot?: string;
16
+ label: string;
17
+ }
18
+ export declare function sdkProvenance(): Promise<SdkProvenance>;
@@ -0,0 +1,45 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { dirname, parse, resolve, sep } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ const MODULE_PATH = fileURLToPath(import.meta.url);
5
+ export const SDK_ROOT = resolve(dirname(MODULE_PATH), "../..");
6
+ let manifestPromise;
7
+ function sdkManifest() {
8
+ manifestPromise ??= readFile(resolve(SDK_ROOT, "package.json"), "utf8")
9
+ .then((text) => JSON.parse(text));
10
+ return manifestPromise;
11
+ }
12
+ export function sdkVersion() {
13
+ return sdkManifest().then((manifest) => manifest.version);
14
+ }
15
+ /** A single semver release, with no range operator — what a checkout may pin. */
16
+ export const EXACT_VERSION = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
17
+ /**
18
+ * The Flue runtime a checkout must install to match this SDK. It is the SDK's
19
+ * own dependency because the bundled runner resolves Flue from the SDK's tree —
20
+ * so read it, never copy it. It must be exact: scaffolds write it straight into
21
+ * a checkout pin, and a range there is not a pin.
22
+ */
23
+ export async function pairedFlueRuntimeVersion() {
24
+ const spec = (await sdkManifest()).dependencies?.["@flue/runtime"];
25
+ if (!spec)
26
+ throw new Error("@reasonlayer/sdk declares no @flue/runtime dependency");
27
+ if (!EXACT_VERSION.test(spec)) {
28
+ throw new Error(`@reasonlayer/sdk must depend on an exact @flue/runtime version; found "${spec}"`);
29
+ }
30
+ return spec;
31
+ }
32
+ export async function sdkProvenance() {
33
+ const version = await sdkVersion();
34
+ const segments = MODULE_PATH.slice(parse(MODULE_PATH).root.length).split(sep);
35
+ if (segments.includes("node_modules")) {
36
+ return { version, installSource: "installed", label: `rl ${version} (installed)` };
37
+ }
38
+ const repoRoot = resolve(SDK_ROOT, "../..");
39
+ return {
40
+ version,
41
+ installSource: "local checkout",
42
+ repoRoot,
43
+ label: `rl ${version} (local checkout: ${repoRoot})`,
44
+ };
45
+ }