@reasonlayer/sdk 0.0.1-rc.3
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/node.d.ts +10 -0
- package/dist/bundler/node.js +55 -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/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/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/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,67 @@
|
|
|
1
|
+
export declare const FN: {
|
|
2
|
+
readonly orgsWhoami: "orgs:whoami";
|
|
3
|
+
readonly orgsBootstrapDev: "orgs:bootstrapDev";
|
|
4
|
+
readonly deploymentsGet: "deployments:get";
|
|
5
|
+
readonly deploymentsLatestFor: "deployments:latestFor";
|
|
6
|
+
readonly deploymentsDeleteWorkflow: "deployments:deleteWorkflow";
|
|
7
|
+
readonly workspacesStartSession: "workspaces:startSession";
|
|
8
|
+
readonly workspacesCheckout: "workspaces:checkout";
|
|
9
|
+
readonly workspacesMissingBlobs: "workspaces:missingBlobs";
|
|
10
|
+
readonly workspacesAvailableBundles: "workspaces:availableBundles";
|
|
11
|
+
readonly workspacesGenerateUploadUrl: "workspaces:generateUploadUrl";
|
|
12
|
+
readonly workspacesMirror: "workspaces:mirror";
|
|
13
|
+
readonly workspacesRecordCompile: "workspaces:recordCompile";
|
|
14
|
+
readonly workspacesRecordCompileError: "workspaces:recordCompileError";
|
|
15
|
+
readonly workspacesHeartbeat: "workspaces:heartbeat";
|
|
16
|
+
readonly workspacesEndSession: "workspaces:endSession";
|
|
17
|
+
readonly workspacesPublish: "workspaces:publish";
|
|
18
|
+
readonly workspacesRollback: "workspaces:rollback";
|
|
19
|
+
readonly workspacesStatus: "workspaces:status";
|
|
20
|
+
readonly workspacesListVersions: "workspaces:listVersions";
|
|
21
|
+
readonly testArtifactsGenerateUploadUrl: "testArtifacts:generateUploadUrl";
|
|
22
|
+
readonly testArtifactsCreate: "testArtifacts:create";
|
|
23
|
+
readonly secretsSet: "secrets:set";
|
|
24
|
+
readonly secretsList: "secrets:list";
|
|
25
|
+
readonly secretsRemove: "secrets:remove";
|
|
26
|
+
readonly variablesSet: "variables:set";
|
|
27
|
+
readonly variablesList: "variables:list";
|
|
28
|
+
readonly variablesRemove: "variables:remove";
|
|
29
|
+
readonly runsCreate: "runs:create";
|
|
30
|
+
readonly runsCreateTest: "runs:createTest";
|
|
31
|
+
readonly runsGet: "runs:get";
|
|
32
|
+
readonly runsInspect: "runs:inspect";
|
|
33
|
+
readonly runsList: "runs:list";
|
|
34
|
+
readonly runsCancel: "runs:cancel";
|
|
35
|
+
readonly runsCancelStep: "runs:cancelStep";
|
|
36
|
+
readonly runsRetry: "runs:retry";
|
|
37
|
+
readonly tasksClaimNextForRun: "tasks:claimNextForRun";
|
|
38
|
+
readonly tasksClaimDeviceNext: "tasks:claimDeviceNext";
|
|
39
|
+
readonly tasksClaimDispatched: "tasks:claimDispatched";
|
|
40
|
+
readonly tasksRecordSpawned: "tasks:recordSpawned";
|
|
41
|
+
readonly tasksHeartbeat: "tasks:heartbeat";
|
|
42
|
+
readonly tasksComplete: "tasks:complete";
|
|
43
|
+
readonly integrationsExecuteTaskAction: "integrations:executeTaskAction";
|
|
44
|
+
readonly transcriptsIngest: "transcripts:ingest";
|
|
45
|
+
readonly transcriptsList: "transcripts:list";
|
|
46
|
+
readonly approvalsList: "approvals:list";
|
|
47
|
+
readonly approvalsApprove: "approvals:approve";
|
|
48
|
+
readonly approvalsReject: "approvals:reject";
|
|
49
|
+
readonly triggersList: "triggers:list";
|
|
50
|
+
readonly triggersSetEnabled: "triggers:setEnabled";
|
|
51
|
+
readonly tokensCreate: "tokens:create";
|
|
52
|
+
readonly tokensList: "tokens:list";
|
|
53
|
+
readonly tokensRevoke: "tokens:revoke";
|
|
54
|
+
readonly devicesRegister: "devices:register";
|
|
55
|
+
readonly devicesList: "devices:list";
|
|
56
|
+
readonly devicesBindHandle: "devices:bindHandle";
|
|
57
|
+
readonly devicesUpdate: "devices:update";
|
|
58
|
+
readonly devicesRotateSecret: "devices:rotateSecret";
|
|
59
|
+
readonly devicesListProfiles: "devices:listProfiles";
|
|
60
|
+
readonly devicesCreateProfile: "devices:createProfile";
|
|
61
|
+
readonly devicesRequestProfileLogin: "devices:requestProfileLogin";
|
|
62
|
+
readonly devicesPendingProfileLogins: "devices:pendingProfileLogins";
|
|
63
|
+
readonly devicesCompleteProfileLogin: "devices:completeProfileLogin";
|
|
64
|
+
};
|
|
65
|
+
export type FnName = (typeof FN)[keyof typeof FN];
|
|
66
|
+
export declare const LEASE_DEFAULT_MS = 30000;
|
|
67
|
+
export declare const LEASE_FLOOR_MS = 1000;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
export const FN = {
|
|
2
|
+
orgsWhoami: "orgs:whoami",
|
|
3
|
+
orgsBootstrapDev: "orgs:bootstrapDev",
|
|
4
|
+
deploymentsGet: "deployments:get",
|
|
5
|
+
deploymentsLatestFor: "deployments:latestFor",
|
|
6
|
+
deploymentsDeleteWorkflow: "deployments:deleteWorkflow",
|
|
7
|
+
workspacesStartSession: "workspaces:startSession",
|
|
8
|
+
workspacesCheckout: "workspaces:checkout",
|
|
9
|
+
workspacesMissingBlobs: "workspaces:missingBlobs",
|
|
10
|
+
workspacesAvailableBundles: "workspaces:availableBundles",
|
|
11
|
+
workspacesGenerateUploadUrl: "workspaces:generateUploadUrl",
|
|
12
|
+
workspacesMirror: "workspaces:mirror",
|
|
13
|
+
workspacesRecordCompile: "workspaces:recordCompile",
|
|
14
|
+
workspacesRecordCompileError: "workspaces:recordCompileError",
|
|
15
|
+
workspacesHeartbeat: "workspaces:heartbeat",
|
|
16
|
+
workspacesEndSession: "workspaces:endSession",
|
|
17
|
+
workspacesPublish: "workspaces:publish",
|
|
18
|
+
workspacesRollback: "workspaces:rollback",
|
|
19
|
+
workspacesStatus: "workspaces:status",
|
|
20
|
+
workspacesListVersions: "workspaces:listVersions",
|
|
21
|
+
testArtifactsGenerateUploadUrl: "testArtifacts:generateUploadUrl",
|
|
22
|
+
testArtifactsCreate: "testArtifacts:create",
|
|
23
|
+
secretsSet: "secrets:set",
|
|
24
|
+
secretsList: "secrets:list",
|
|
25
|
+
secretsRemove: "secrets:remove",
|
|
26
|
+
variablesSet: "variables:set",
|
|
27
|
+
variablesList: "variables:list",
|
|
28
|
+
variablesRemove: "variables:remove",
|
|
29
|
+
runsCreate: "runs:create",
|
|
30
|
+
runsCreateTest: "runs:createTest",
|
|
31
|
+
runsGet: "runs:get",
|
|
32
|
+
runsInspect: "runs:inspect",
|
|
33
|
+
runsList: "runs:list",
|
|
34
|
+
runsCancel: "runs:cancel",
|
|
35
|
+
runsCancelStep: "runs:cancelStep",
|
|
36
|
+
runsRetry: "runs:retry",
|
|
37
|
+
tasksClaimNextForRun: "tasks:claimNextForRun",
|
|
38
|
+
tasksClaimDeviceNext: "tasks:claimDeviceNext",
|
|
39
|
+
tasksClaimDispatched: "tasks:claimDispatched",
|
|
40
|
+
tasksRecordSpawned: "tasks:recordSpawned",
|
|
41
|
+
tasksHeartbeat: "tasks:heartbeat",
|
|
42
|
+
tasksComplete: "tasks:complete",
|
|
43
|
+
integrationsExecuteTaskAction: "integrations:executeTaskAction",
|
|
44
|
+
transcriptsIngest: "transcripts:ingest",
|
|
45
|
+
transcriptsList: "transcripts:list",
|
|
46
|
+
approvalsList: "approvals:list",
|
|
47
|
+
approvalsApprove: "approvals:approve",
|
|
48
|
+
approvalsReject: "approvals:reject",
|
|
49
|
+
triggersList: "triggers:list",
|
|
50
|
+
triggersSetEnabled: "triggers:setEnabled",
|
|
51
|
+
tokensCreate: "tokens:create",
|
|
52
|
+
tokensList: "tokens:list",
|
|
53
|
+
tokensRevoke: "tokens:revoke",
|
|
54
|
+
devicesRegister: "devices:register",
|
|
55
|
+
devicesList: "devices:list",
|
|
56
|
+
devicesBindHandle: "devices:bindHandle",
|
|
57
|
+
devicesUpdate: "devices:update",
|
|
58
|
+
devicesRotateSecret: "devices:rotateSecret",
|
|
59
|
+
devicesListProfiles: "devices:listProfiles",
|
|
60
|
+
devicesCreateProfile: "devices:createProfile",
|
|
61
|
+
devicesRequestProfileLogin: "devices:requestProfileLogin",
|
|
62
|
+
devicesPendingProfileLogins: "devices:pendingProfileLogins",
|
|
63
|
+
devicesCompleteProfileLogin: "devices:completeProfileLogin",
|
|
64
|
+
};
|
|
65
|
+
export const LEASE_DEFAULT_MS = 30_000;
|
|
66
|
+
export const LEASE_FLOOR_MS = 1_000;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { ActionStepIR, AgentStepIR, CodeStepIR, MapChildStepIR, MapStepIR, ReviewStepIR, StepIR, WorkflowIR } from "./ir.js";
|
|
2
|
+
import { type SelectorContext } from "./selector.js";
|
|
3
|
+
export type InputStep = ActionStepIR | CodeStepIR | AgentStepIR | ReviewStepIR | MapChildStepIR;
|
|
4
|
+
export interface MapExpansionItem {
|
|
5
|
+
key: string;
|
|
6
|
+
item: unknown;
|
|
7
|
+
childIndex: number;
|
|
8
|
+
}
|
|
9
|
+
export type StepRunStatus = "pending" | "running" | "succeeded" | "failed" | "skipped" | "canceled" | "expired";
|
|
10
|
+
export interface StepRunState {
|
|
11
|
+
stepId: string;
|
|
12
|
+
status: StepRunStatus;
|
|
13
|
+
error?: string;
|
|
14
|
+
}
|
|
15
|
+
export type BlockingStepRunStatus = Exclude<StepRunStatus, "pending" | "running" | "succeeded"> | "missing";
|
|
16
|
+
export interface DependencyBlocker {
|
|
17
|
+
stepId: string;
|
|
18
|
+
status: BlockingStepRunStatus;
|
|
19
|
+
error?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface MapChildResult {
|
|
22
|
+
status: StepRunStatus;
|
|
23
|
+
output?: unknown;
|
|
24
|
+
childIndex?: number;
|
|
25
|
+
invocationKey?: string;
|
|
26
|
+
error?: string;
|
|
27
|
+
}
|
|
28
|
+
export type MapCollapseResult = {
|
|
29
|
+
ok: true;
|
|
30
|
+
output: unknown[];
|
|
31
|
+
childrenSucceeded: number;
|
|
32
|
+
childrenTotal: number;
|
|
33
|
+
} | {
|
|
34
|
+
ok: false;
|
|
35
|
+
error: string;
|
|
36
|
+
childrenSucceeded: number;
|
|
37
|
+
childrenTotal: number;
|
|
38
|
+
};
|
|
39
|
+
export declare function stepDependencies(step: StepIR): string[];
|
|
40
|
+
export declare function isTerminalStepRunStatus(status: StepRunStatus): boolean;
|
|
41
|
+
export declare function readySteps(ir: WorkflowIR, args: {
|
|
42
|
+
outputs: Record<string, unknown>;
|
|
43
|
+
startedStepIds: Iterable<string>;
|
|
44
|
+
}): StepIR[];
|
|
45
|
+
export declare function dependencyBlockers(step: StepIR, args: {
|
|
46
|
+
outputs: Record<string, unknown>;
|
|
47
|
+
stepStates: ReadonlyMap<string, StepRunState>;
|
|
48
|
+
}): DependencyBlocker[];
|
|
49
|
+
export declare function doomedSteps(ir: WorkflowIR, args: {
|
|
50
|
+
outputs: Record<string, unknown>;
|
|
51
|
+
startedStepIds: Iterable<string>;
|
|
52
|
+
stepStates: ReadonlyMap<string, StepRunState>;
|
|
53
|
+
}): Array<{
|
|
54
|
+
step: StepIR;
|
|
55
|
+
blockers: DependencyBlocker[];
|
|
56
|
+
}>;
|
|
57
|
+
export declare function workflowStepsComplete(ir: WorkflowIR, stepStates: ReadonlyMap<string, StepRunState>): boolean;
|
|
58
|
+
export declare function workflowOutputReady(ir: WorkflowIR, args: {
|
|
59
|
+
outputs: Record<string, unknown>;
|
|
60
|
+
stepStates: ReadonlyMap<string, StepRunState>;
|
|
61
|
+
}): boolean;
|
|
62
|
+
export declare function workflowOutputBlockers(ir: WorkflowIR, args: {
|
|
63
|
+
outputs: Record<string, unknown>;
|
|
64
|
+
stepStates: ReadonlyMap<string, StepRunState>;
|
|
65
|
+
}): DependencyBlocker[];
|
|
66
|
+
export declare function expandMapStep(step: MapStepIR, context: SelectorContext): MapExpansionItem[];
|
|
67
|
+
export declare function evaluateStepInput(step: InputStep, context: SelectorContext): unknown;
|
|
68
|
+
export declare function evaluateWorkflowOutput(ir: WorkflowIR, context: SelectorContext): unknown;
|
|
69
|
+
export declare function collapseMapChildren(children: MapChildResult[]): MapCollapseResult;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { evaluateSelector, referencedStepIds, } from "./selector.js";
|
|
2
|
+
const TERMINAL_STEP_STATUSES = new Set([
|
|
3
|
+
"succeeded",
|
|
4
|
+
"failed",
|
|
5
|
+
"skipped",
|
|
6
|
+
"canceled",
|
|
7
|
+
"expired",
|
|
8
|
+
]);
|
|
9
|
+
function unique(values) {
|
|
10
|
+
return Array.from(new Set(values));
|
|
11
|
+
}
|
|
12
|
+
export function stepDependencies(step) {
|
|
13
|
+
return step.kind === "map"
|
|
14
|
+
? unique([...referencedStepIds(step.over), ...referencedStepIds(step.step.input)])
|
|
15
|
+
: unique(referencedStepIds(step.input));
|
|
16
|
+
}
|
|
17
|
+
export function isTerminalStepRunStatus(status) {
|
|
18
|
+
return TERMINAL_STEP_STATUSES.has(status);
|
|
19
|
+
}
|
|
20
|
+
function blockerStatusFor(status) {
|
|
21
|
+
switch (status) {
|
|
22
|
+
case "failed":
|
|
23
|
+
case "skipped":
|
|
24
|
+
case "canceled":
|
|
25
|
+
case "expired":
|
|
26
|
+
return status;
|
|
27
|
+
case "pending":
|
|
28
|
+
case "running":
|
|
29
|
+
case "succeeded":
|
|
30
|
+
return "missing";
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export function readySteps(ir, args) {
|
|
34
|
+
const started = new Set(args.startedStepIds);
|
|
35
|
+
return Object.values(ir.steps).filter((step) => !started.has(step.id) &&
|
|
36
|
+
stepDependencies(step).every((dependency) => dependency in args.outputs));
|
|
37
|
+
}
|
|
38
|
+
export function dependencyBlockers(step, args) {
|
|
39
|
+
return stepDependencies(step).flatMap((dependency) => {
|
|
40
|
+
if (dependency in args.outputs)
|
|
41
|
+
return [];
|
|
42
|
+
const state = args.stepStates.get(dependency);
|
|
43
|
+
if (!state || !isTerminalStepRunStatus(state.status))
|
|
44
|
+
return [];
|
|
45
|
+
return [{
|
|
46
|
+
stepId: dependency,
|
|
47
|
+
status: blockerStatusFor(state.status),
|
|
48
|
+
...(state.error !== undefined ? { error: state.error } : {}),
|
|
49
|
+
}];
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
export function doomedSteps(ir, args) {
|
|
53
|
+
const started = new Set(args.startedStepIds);
|
|
54
|
+
return Object.values(ir.steps).flatMap((step) => {
|
|
55
|
+
if (started.has(step.id))
|
|
56
|
+
return [];
|
|
57
|
+
const blockers = dependencyBlockers(step, args);
|
|
58
|
+
return blockers.length > 0 ? [{ step, blockers }] : [];
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
export function workflowStepsComplete(ir, stepStates) {
|
|
62
|
+
return Object.values(ir.steps).every((step) => {
|
|
63
|
+
const state = stepStates.get(step.id);
|
|
64
|
+
return state !== undefined && isTerminalStepRunStatus(state.status);
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
export function workflowOutputReady(ir, args) {
|
|
68
|
+
return workflowOutputBlockers(ir, args).length === 0;
|
|
69
|
+
}
|
|
70
|
+
export function workflowOutputBlockers(ir, args) {
|
|
71
|
+
return unique(referencedStepIds(ir.output)).flatMap((stepId) => {
|
|
72
|
+
const state = args.stepStates.get(stepId);
|
|
73
|
+
if (state?.status === "succeeded" && stepId in args.outputs)
|
|
74
|
+
return [];
|
|
75
|
+
if (!state)
|
|
76
|
+
return [{ stepId, status: "missing" }];
|
|
77
|
+
return [{
|
|
78
|
+
stepId,
|
|
79
|
+
status: blockerStatusFor(state.status),
|
|
80
|
+
...(state.error !== undefined ? { error: state.error } : {}),
|
|
81
|
+
}];
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
export function expandMapStep(step, context) {
|
|
85
|
+
const over = evaluateSelector(step.over, context);
|
|
86
|
+
if (!Array.isArray(over)) {
|
|
87
|
+
throw new Error(`map step "${step.id}": over selector did not yield an array`);
|
|
88
|
+
}
|
|
89
|
+
const seen = new Set();
|
|
90
|
+
const items = [];
|
|
91
|
+
for (const item of over) {
|
|
92
|
+
const key = String(evaluateSelector(step.key, { ...context, mapItem: item }));
|
|
93
|
+
if (seen.has(key))
|
|
94
|
+
continue;
|
|
95
|
+
seen.add(key);
|
|
96
|
+
items.push({ key, item, childIndex: items.length });
|
|
97
|
+
}
|
|
98
|
+
return items;
|
|
99
|
+
}
|
|
100
|
+
export function evaluateStepInput(step, context) {
|
|
101
|
+
return evaluateSelector(step.input, context);
|
|
102
|
+
}
|
|
103
|
+
export function evaluateWorkflowOutput(ir, context) {
|
|
104
|
+
return evaluateSelector(ir.output, context);
|
|
105
|
+
}
|
|
106
|
+
export function collapseMapChildren(children) {
|
|
107
|
+
const survivors = children
|
|
108
|
+
.filter((child) => child.status === "succeeded")
|
|
109
|
+
.sort((a, b) => (a.childIndex ?? 0) - (b.childIndex ?? 0));
|
|
110
|
+
const childrenSucceeded = survivors.length;
|
|
111
|
+
const childrenTotal = children.length;
|
|
112
|
+
if (childrenSucceeded === 0 && childrenTotal > 0) {
|
|
113
|
+
return {
|
|
114
|
+
ok: false,
|
|
115
|
+
error: `all ${childrenTotal} map children failed`,
|
|
116
|
+
childrenSucceeded,
|
|
117
|
+
childrenTotal,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
return {
|
|
121
|
+
ok: true,
|
|
122
|
+
output: survivors.map((child) => child.output),
|
|
123
|
+
childrenSucceeded,
|
|
124
|
+
childrenTotal,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SelectorIR evaluation — pure JS over JSON (spec §3.3: interpretation of
|
|
3
|
+
* data, safe in the engine). Shared by the engine interpreter and the SDK
|
|
4
|
+
* test kit so the two cannot drift.
|
|
5
|
+
*/
|
|
6
|
+
import type { SelectorIR } from "./ir.js";
|
|
7
|
+
export interface SelectorContext {
|
|
8
|
+
input: unknown;
|
|
9
|
+
/** Outputs of completed steps, keyed by step id. */
|
|
10
|
+
stepOutputs: Record<string, unknown>;
|
|
11
|
+
/** Present only while evaluating a map child's selectors. */
|
|
12
|
+
mapItem?: unknown;
|
|
13
|
+
/** Resolved workflow-variable snapshot fixed at run creation. */
|
|
14
|
+
variables?: Record<string, unknown>;
|
|
15
|
+
}
|
|
16
|
+
export declare function getPath(value: unknown, path: readonly string[]): unknown;
|
|
17
|
+
export declare class SelectorEvalError extends Error {
|
|
18
|
+
}
|
|
19
|
+
export declare function evaluateSelector(selector: SelectorIR, ctx: SelectorContext): unknown;
|
|
20
|
+
/** Every step id a selector references — the dependency edge set for readiness. */
|
|
21
|
+
export declare function referencedStepIds(selector: SelectorIR): string[];
|
|
22
|
+
/** True if the selector (recursively) uses mapItem — only legal inside a map child. */
|
|
23
|
+
export declare function usesMapItem(selector: SelectorIR): boolean;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SelectorIR evaluation — pure JS over JSON (spec §3.3: interpretation of
|
|
3
|
+
* data, safe in the engine). Shared by the engine interpreter and the SDK
|
|
4
|
+
* test kit so the two cannot drift.
|
|
5
|
+
*/
|
|
6
|
+
export function getPath(value, path) {
|
|
7
|
+
let current = value;
|
|
8
|
+
for (const key of path) {
|
|
9
|
+
if (current === null || current === undefined)
|
|
10
|
+
return undefined;
|
|
11
|
+
current = current[key];
|
|
12
|
+
}
|
|
13
|
+
return current;
|
|
14
|
+
}
|
|
15
|
+
export class SelectorEvalError extends Error {
|
|
16
|
+
}
|
|
17
|
+
export function evaluateSelector(selector, ctx) {
|
|
18
|
+
switch (selector.kind) {
|
|
19
|
+
case "input":
|
|
20
|
+
return getPath(ctx.input, selector.path);
|
|
21
|
+
case "step": {
|
|
22
|
+
if (!(selector.stepId in ctx.stepOutputs)) {
|
|
23
|
+
throw new SelectorEvalError(`selector references step "${selector.stepId}" which has no output yet`);
|
|
24
|
+
}
|
|
25
|
+
return getPath(ctx.stepOutputs[selector.stepId], selector.path);
|
|
26
|
+
}
|
|
27
|
+
case "variable": {
|
|
28
|
+
if (!ctx.variables || !Object.prototype.hasOwnProperty.call(ctx.variables, selector.name)) {
|
|
29
|
+
throw new SelectorEvalError(`selector references undeclared variable "${selector.name}"`);
|
|
30
|
+
}
|
|
31
|
+
return getPath(ctx.variables[selector.name], selector.path);
|
|
32
|
+
}
|
|
33
|
+
case "literal":
|
|
34
|
+
return selector.value;
|
|
35
|
+
case "object": {
|
|
36
|
+
const result = {};
|
|
37
|
+
for (const [key, field] of Object.entries(selector.fields)) {
|
|
38
|
+
result[key] = evaluateSelector(field, ctx);
|
|
39
|
+
}
|
|
40
|
+
return result;
|
|
41
|
+
}
|
|
42
|
+
case "array":
|
|
43
|
+
return selector.items.map((item) => evaluateSelector(item, ctx));
|
|
44
|
+
case "mapItem": {
|
|
45
|
+
if (!("mapItem" in ctx)) {
|
|
46
|
+
throw new SelectorEvalError("mapItem selector evaluated outside a map child");
|
|
47
|
+
}
|
|
48
|
+
return getPath(ctx.mapItem, selector.path);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/** Every step id a selector references — the dependency edge set for readiness. */
|
|
53
|
+
export function referencedStepIds(selector) {
|
|
54
|
+
switch (selector.kind) {
|
|
55
|
+
case "step":
|
|
56
|
+
return [selector.stepId];
|
|
57
|
+
case "object":
|
|
58
|
+
return Object.values(selector.fields).flatMap(referencedStepIds);
|
|
59
|
+
case "array":
|
|
60
|
+
return selector.items.flatMap(referencedStepIds);
|
|
61
|
+
default:
|
|
62
|
+
return [];
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/** True if the selector (recursively) uses mapItem — only legal inside a map child. */
|
|
66
|
+
export function usesMapItem(selector) {
|
|
67
|
+
switch (selector.kind) {
|
|
68
|
+
case "mapItem":
|
|
69
|
+
return true;
|
|
70
|
+
case "object":
|
|
71
|
+
return Object.values(selector.fields).some(usesMapItem);
|
|
72
|
+
case "array":
|
|
73
|
+
return selector.items.some(usesMapItem);
|
|
74
|
+
default:
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The task contract (spec §7.1). The task row in Convex is the protocol
|
|
3
|
+
* runners speak — not the workflow component. Cloud runners and device
|
|
4
|
+
* daemons claim and complete tasks through scoped credentials.
|
|
5
|
+
*/
|
|
6
|
+
import type { EnvironmentIR, HostIR } from "./ir.js";
|
|
7
|
+
export type TaskKind = "code" | "agent" | "action";
|
|
8
|
+
export type TaskStatus = "queued" | "dispatching" | "spawning" | "claimed" | "done" | "canceled" | "expired";
|
|
9
|
+
/** Identifies one step execution attempt; carried by reporting credentials, not repeated per event (spec §8.1). */
|
|
10
|
+
export interface StepLocator {
|
|
11
|
+
runId: string;
|
|
12
|
+
stepId: string;
|
|
13
|
+
invocationKey: string;
|
|
14
|
+
attempt: number;
|
|
15
|
+
}
|
|
16
|
+
interface TaskSpecBase extends StepLocator {
|
|
17
|
+
taskId: string;
|
|
18
|
+
orgId: string;
|
|
19
|
+
input: unknown;
|
|
20
|
+
/** JSON text because Convex values reject JSON Schema's `$schema` key. */
|
|
21
|
+
outputSchemaJsonText: string;
|
|
22
|
+
timeoutMs?: number;
|
|
23
|
+
host: HostIR;
|
|
24
|
+
}
|
|
25
|
+
interface BundleTaskSpecBase extends TaskSpecBase {
|
|
26
|
+
/** Download URL for the runner bundle that contains this step's export. */
|
|
27
|
+
bundleUrl: string | null;
|
|
28
|
+
/** Hex sha256 of the bundle bytes; runners verify after download. */
|
|
29
|
+
bundleSha256?: string;
|
|
30
|
+
/** The step id inside the bundle; map children use mapChildId(mapId). */
|
|
31
|
+
entryStepId: string;
|
|
32
|
+
moduleRef: string;
|
|
33
|
+
exportName: string;
|
|
34
|
+
/** Secrets injected only into the claim response; never persisted or logged. */
|
|
35
|
+
env: Record<string, string>;
|
|
36
|
+
environmentHash?: string;
|
|
37
|
+
environment?: EnvironmentIR;
|
|
38
|
+
templateAlias?: string;
|
|
39
|
+
}
|
|
40
|
+
export interface CodeTaskSpec extends BundleTaskSpecBase {
|
|
41
|
+
kind: "code";
|
|
42
|
+
}
|
|
43
|
+
export interface AgentTaskSpec extends BundleTaskSpecBase {
|
|
44
|
+
kind: "agent";
|
|
45
|
+
framework: "flue";
|
|
46
|
+
catalogTools: string[];
|
|
47
|
+
}
|
|
48
|
+
export interface ActionTaskSpec extends TaskSpecBase {
|
|
49
|
+
kind: "action";
|
|
50
|
+
/** Stable Reasonlayer catalog action id; provider details remain server-side. */
|
|
51
|
+
actionId: string;
|
|
52
|
+
}
|
|
53
|
+
export type TaskSpec = CodeTaskSpec | AgentTaskSpec | ActionTaskSpec;
|
|
54
|
+
/** The terminal report a runner produces. */
|
|
55
|
+
export type TaskResult = {
|
|
56
|
+
kind: "ok";
|
|
57
|
+
output: unknown;
|
|
58
|
+
} | {
|
|
59
|
+
kind: "error";
|
|
60
|
+
message: string;
|
|
61
|
+
stack?: string;
|
|
62
|
+
} | {
|
|
63
|
+
kind: "canceled";
|
|
64
|
+
};
|
|
65
|
+
/** What the engine's awaited task event resolves with (timeout comes from the sentinel, not the runner). */
|
|
66
|
+
export type TaskEvent = TaskResult | {
|
|
67
|
+
kind: "timeout";
|
|
68
|
+
};
|
|
69
|
+
export {};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON Schema validation shared by the Convex engine and SDK test kit. The
|
|
3
|
+
* validator uses no codegen, so it remains safe for Convex runtime code.
|
|
4
|
+
*/
|
|
5
|
+
import type { JsonSchema } from "./ir.js";
|
|
6
|
+
export declare function validateAgainstSchema(value: unknown, schema: JsonSchema, what: string): void;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON Schema validation shared by the Convex engine and SDK test kit. The
|
|
3
|
+
* validator uses no codegen, so it remains safe for Convex runtime code.
|
|
4
|
+
*/
|
|
5
|
+
import { Validator } from "@cfworker/json-schema";
|
|
6
|
+
export function validateAgainstSchema(value, schema, what) {
|
|
7
|
+
// @cfworker/json-schema annotates schemas while dereferencing them.
|
|
8
|
+
const mutableSchema = JSON.parse(JSON.stringify(schema));
|
|
9
|
+
const validator = new Validator(mutableSchema, "7", false);
|
|
10
|
+
const result = validator.validate(value);
|
|
11
|
+
if (!result.valid) {
|
|
12
|
+
const details = result.errors
|
|
13
|
+
.slice(0, 5)
|
|
14
|
+
.map((e) => `${e.instanceLocation}: ${e.error}`)
|
|
15
|
+
.join("; ");
|
|
16
|
+
throw new Error(`${what} does not match schema — ${details}`);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@reasonlayer/protocol",
|
|
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": "tsc -p tsconfig.json",
|
|
18
|
+
"test": "vitest run --passWithNoTests",
|
|
19
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type EnvironmentIR } from "@reasonlayer/protocol";
|
|
2
|
+
import { NodeSandboxApi } from "./sandbox-env.js";
|
|
3
|
+
export interface MaterializedEnvironment {
|
|
4
|
+
prefix: string;
|
|
5
|
+
env: Record<string, string>;
|
|
6
|
+
}
|
|
7
|
+
export type EnvironmentExec = NodeSandboxApi["exec"];
|
|
8
|
+
export interface EnvironmentMaterializerOptions {
|
|
9
|
+
/** Test seam; production uses NodeSandboxApi rooted at process.cwd(). */
|
|
10
|
+
exec?: EnvironmentExec;
|
|
11
|
+
}
|
|
12
|
+
export declare function materializeEnvironment(environment: EnvironmentIR, rootDir?: string, options?: EnvironmentMaterializerOptions): Promise<MaterializedEnvironment>;
|
|
13
|
+
export declare function verifyEnvironmentBinaries(environment: EnvironmentIR, options?: EnvironmentMaterializerOptions): Promise<void>;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { constants } from "node:fs";
|
|
2
|
+
import { access, mkdir, writeFile } from "node:fs/promises";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { declaredEnvironmentExecutables, shellQuote, } from "@reasonlayer/protocol";
|
|
5
|
+
import { NodeSandboxApi } from "./sandbox-env.js";
|
|
6
|
+
function defaultExec() {
|
|
7
|
+
const api = new NodeSandboxApi({ cwd: process.cwd() });
|
|
8
|
+
return api.exec.bind(api);
|
|
9
|
+
}
|
|
10
|
+
function pathWith(...entries) {
|
|
11
|
+
return [...entries, process.env["PATH"] ?? ""].filter(Boolean).join(":");
|
|
12
|
+
}
|
|
13
|
+
async function exists(path) {
|
|
14
|
+
try {
|
|
15
|
+
await access(path, constants.F_OK);
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export async function materializeEnvironment(environment, rootDir = join(process.cwd(), ".rl", "environments"), options = {}) {
|
|
23
|
+
const prefix = join(rootDir, environment.envHash);
|
|
24
|
+
const readyFile = join(prefix, ".ready");
|
|
25
|
+
const binDir = join(prefix, "bin");
|
|
26
|
+
const venvDir = join(prefix, "venv");
|
|
27
|
+
const venvBinDir = join(venvDir, "bin");
|
|
28
|
+
const rootfsDir = join(prefix, "rootfs");
|
|
29
|
+
const exec = options.exec ?? defaultExec();
|
|
30
|
+
await mkdir(prefix, { recursive: true });
|
|
31
|
+
await mkdir(rootfsDir, { recursive: true });
|
|
32
|
+
if (!(await exists(readyFile))) {
|
|
33
|
+
await mkdir(binDir, { recursive: true });
|
|
34
|
+
if (environment.npm?.length) {
|
|
35
|
+
const result = await exec(`npm install --global --prefix ${shellQuote(prefix)} ${environment.npm.map(shellQuote).join(" ")}`, { timeoutMs: 10 * 60 * 1000 });
|
|
36
|
+
if (result.exitCode !== 0)
|
|
37
|
+
throw new Error(`npm environment install failed: ${result.stderr}`);
|
|
38
|
+
}
|
|
39
|
+
if (environment.pip?.length) {
|
|
40
|
+
const create = await exec(`python3 -m venv ${shellQuote(venvDir)}`, {
|
|
41
|
+
timeoutMs: 2 * 60 * 1000,
|
|
42
|
+
});
|
|
43
|
+
if (create.exitCode !== 0)
|
|
44
|
+
throw new Error(`python venv creation failed: ${create.stderr}`);
|
|
45
|
+
const install = await exec(`${shellQuote(join(venvBinDir, "pip"))} install ${environment.pip.map(shellQuote).join(" ")}`, { timeoutMs: 10 * 60 * 1000 });
|
|
46
|
+
if (install.exitCode !== 0)
|
|
47
|
+
throw new Error(`pip environment install failed: ${install.stderr}`);
|
|
48
|
+
}
|
|
49
|
+
for (const executable of declaredEnvironmentExecutables(environment)) {
|
|
50
|
+
const result = await exec(`command -v ${shellQuote(executable)}`, { timeoutMs: 10_000 });
|
|
51
|
+
if (result.exitCode !== 0) {
|
|
52
|
+
throw new Error(`declared executable "${executable}" is not installed locally`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
for (const file of environment.files ?? []) {
|
|
56
|
+
const localDest = join(rootfsDir, file.path.replace(/^\/+/, ""));
|
|
57
|
+
await mkdir(dirname(localDest), { recursive: true });
|
|
58
|
+
await writeFile(localDest, Buffer.from(file.contentBase64, "base64"));
|
|
59
|
+
}
|
|
60
|
+
const env = {
|
|
61
|
+
PATH: pathWith(binDir, venvBinDir),
|
|
62
|
+
RL_ENV_PREFIX: prefix,
|
|
63
|
+
RL_ENV_ROOTFS: rootfsDir,
|
|
64
|
+
};
|
|
65
|
+
for (const command of environment.setup ?? []) {
|
|
66
|
+
const result = await exec(command, { cwd: rootfsDir, env, timeoutMs: 10 * 60 * 1000 });
|
|
67
|
+
if (result.exitCode !== 0)
|
|
68
|
+
throw new Error(`environment setup failed: ${result.stderr}`);
|
|
69
|
+
}
|
|
70
|
+
await writeFile(readyFile, `${new Date().toISOString()}\n`);
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
prefix,
|
|
74
|
+
env: {
|
|
75
|
+
PATH: pathWith(binDir, venvBinDir),
|
|
76
|
+
RL_ENV_PREFIX: prefix,
|
|
77
|
+
RL_ENV_ROOTFS: rootfsDir,
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
export async function verifyEnvironmentBinaries(environment, options = {}) {
|
|
82
|
+
const exec = options.exec ?? defaultExec();
|
|
83
|
+
const missing = [];
|
|
84
|
+
for (const executable of declaredEnvironmentExecutables(environment)) {
|
|
85
|
+
const result = await exec(`command -v ${shellQuote(executable)}`, { timeoutMs: 10_000 });
|
|
86
|
+
if (result.exitCode !== 0)
|
|
87
|
+
missing.push(executable);
|
|
88
|
+
}
|
|
89
|
+
if (missing.length > 0) {
|
|
90
|
+
throw new Error(`device is missing declared environment binaries: ${missing.join(", ")}`);
|
|
91
|
+
}
|
|
92
|
+
}
|