@scarn/sdk 0.0.0-stage → 0.0.0
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/dist/chunk-4361gxk0.js +166 -0
- package/dist/chunk-4vehh3dq.js +333 -0
- package/dist/chunk-56e4kp0a.js +162 -0
- package/dist/chunk-5mmj03ah.js +1074 -0
- package/dist/chunk-631ffb6r.js +57 -0
- package/dist/chunk-91p9vzcs.js +1453 -0
- package/dist/chunk-9s07v9r1.js +30 -0
- package/dist/chunk-b21233rt.js +78 -0
- package/dist/chunk-dnn39qt4.js +13539 -0
- package/dist/chunk-eg1hcvhb.js +300 -0
- package/dist/chunk-g0rdnn0r.js +95 -0
- package/dist/chunk-h9yxx0hd.js +116 -0
- package/dist/chunk-njd6npf0.js +35 -0
- package/dist/chunk-ny07ncb9.js +330 -0
- package/dist/chunk-p6kc9wq8.js +97 -0
- package/dist/chunk-qpw5wt1p.js +257 -0
- package/dist/chunk-rq3q8vg7.js +1094 -0
- package/dist/chunk-s0gap8r8.js +14 -0
- package/dist/chunk-tfm5hjzm.js +100 -0
- package/dist/chunk-ynk2bjae.js +1686 -0
- package/dist/chunk-zpqyjgb4.js +49 -0
- package/dist/client.d.ts +4 -0
- package/dist/client.js +57 -0
- package/dist/contracts/artifact-markers.d.ts +42 -0
- package/dist/contracts/artifact-markers.js +15 -0
- package/dist/contracts/artifacts.d.ts +67 -0
- package/dist/contracts/artifacts.js +25 -0
- package/dist/contracts/pipeline-document/built-ins.d.ts +23 -0
- package/dist/contracts/pipeline-document/conditions/operators.d.ts +8 -0
- package/dist/contracts/pipeline-document/index.d.ts +11 -0
- package/dist/contracts/pipeline-document/index.js +97 -0
- package/dist/contracts/pipeline-document/json.d.ts +35 -0
- package/dist/contracts/pipeline-document/routes.d.ts +16 -0
- package/dist/contracts/pipeline-document/schema.d.ts +780 -0
- package/dist/contracts/pipeline-document/step-contract.d.ts +11 -0
- package/dist/contracts/step-artifact-submissions.d.ts +71 -0
- package/dist/contracts/step-artifact-submissions.js +174 -0
- package/dist/defaults/atomic-json-file.d.ts +10 -0
- package/dist/defaults/auth-file.d.ts +14 -0
- package/dist/defaults/base-url.d.ts +1 -0
- package/dist/defaults/config-file.d.ts +46 -0
- package/dist/defaults/home-dir.d.ts +3 -0
- package/dist/defaults/index.d.ts +12 -0
- package/dist/defaults/index.js +1239 -0
- package/dist/defaults/legacy-config-migration.d.ts +27 -0
- package/dist/defaults/load-push-defaults.d.ts +25 -0
- package/dist/defaults/project-config.d.ts +32 -0
- package/dist/defaults/project-ref.d.ts +34 -0
- package/dist/definitions/artifacts/artifact.d.ts +62 -0
- package/dist/definitions/artifacts/index.d.ts +1 -0
- package/dist/definitions/pipelines/define-default-pipeline-assignment.d.ts +263 -0
- package/dist/definitions/pipelines/index.d.ts +3 -0
- package/dist/definitions/pipelines/index.js +24 -0
- package/dist/definitions/pipelines/pipeline-definitions-client.d.ts +208 -0
- package/dist/definitions/pipelines/work-item-fields.d.ts +93 -0
- package/dist/definitions/steps/compile-mcps.d.ts +34 -0
- package/dist/definitions/steps/define-code-step.d.ts +84 -0
- package/dist/definitions/steps/define-mcp.d.ts +79 -0
- package/dist/definitions/steps/define-step.d.ts +137 -0
- package/dist/definitions/steps/env.d.ts +136 -0
- package/dist/definitions/steps/index.d.ts +14 -0
- package/dist/definitions/steps/index.js +73 -0
- package/dist/definitions/steps/mcp-server-config.d.ts +102 -0
- package/dist/definitions/steps/prompt-template.d.ts +24 -0
- package/dist/definitions/steps/repo.d.ts +67 -0
- package/dist/definitions/steps/runtime.d.ts +115 -0
- package/dist/definitions/steps/step-definitions-client.d.ts +400 -0
- package/dist/definitions/steps/step-features.d.ts +109 -0
- package/dist/definitions/steps/step-handle.d.ts +25 -0
- package/dist/definitions/steps/step-ref.d.ts +19 -0
- package/dist/definitions/validation/index.d.ts +2 -0
- package/dist/definitions/validation/index.js +17 -0
- package/dist/definitions/validation/validate-artifact-markers.d.ts +3 -0
- package/dist/definitions/validation/validate-artifacts.d.ts +7 -0
- package/dist/definitions/validation/validate-definition-specs.d.ts +16 -0
- package/dist/definitions/validation/validate-env.d.ts +15 -0
- package/dist/definitions/validation/validate-repo.d.ts +13 -0
- package/dist/definitions/validation/validate-runtime.d.ts +12 -0
- package/dist/definitions/validation/validation-issue.d.ts +11 -0
- package/dist/devcontainer-config-path.d.ts +21 -0
- package/dist/devcontainer-config-path.js +13 -0
- package/dist/env-vars.d.ts +136 -0
- package/dist/env-vars.js +35 -0
- package/dist/eslint.d.ts +42 -0
- package/dist/eslint.js +125 -0
- package/dist/generated/client/client.gen.d.ts +2 -0
- package/dist/generated/client/index.d.ts +8 -0
- package/dist/generated/client/types.gen.d.ts +117 -0
- package/dist/generated/client/utils.gen.d.ts +33 -0
- package/dist/generated/client.gen.d.ts +12 -0
- package/dist/generated/core/auth.gen.d.ts +18 -0
- package/dist/generated/core/bodySerializer.gen.d.ts +25 -0
- package/dist/generated/core/params.gen.d.ts +43 -0
- package/dist/generated/core/pathSerializer.gen.d.ts +33 -0
- package/dist/generated/core/queryKeySerializer.gen.d.ts +18 -0
- package/dist/generated/core/serverSentEvents.gen.d.ts +71 -0
- package/dist/generated/core/types.gen.d.ts +78 -0
- package/dist/generated/core/utils.gen.d.ts +19 -0
- package/dist/generated/index.d.ts +2 -0
- package/dist/generated/sdk.gen.d.ts +302 -0
- package/dist/generated/types.gen.d.ts +18368 -0
- package/dist/git-url/git-remote.d.ts +30 -0
- package/dist/git-url/git-repo-identity.d.ts +44 -0
- package/dist/git-url/git-repo-identity.js +159 -0
- package/dist/git-url/parse-git-host.d.ts +23 -0
- package/dist/health-checks.d.ts +169 -0
- package/dist/health-checks.js +19 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +293 -0
- package/dist/jsonc.d.ts +3 -0
- package/dist/jsonc.js +11 -0
- package/dist/managed-runtimes.d.ts +20 -0
- package/dist/managed-runtimes.js +13 -0
- package/dist/opencode-mcp.d.ts +313 -0
- package/dist/opencode-mcp.js +29 -0
- package/dist/pipelines/chain.d.ts +7 -0
- package/dist/pipelines/compile-args.d.ts +12 -0
- package/dist/pipelines/compile-chain.d.ts +9 -0
- package/dist/pipelines/compile-checks.d.ts +16 -0
- package/dist/pipelines/compile-state.d.ts +30 -0
- package/dist/pipelines/condition-data.d.ts +78 -0
- package/dist/pipelines/conditions.d.ts +47 -0
- package/dist/pipelines/context.d.ts +16 -0
- package/dist/pipelines/define-pipeline.d.ts +32 -0
- package/dist/pipelines/each.d.ts +5 -0
- package/dist/pipelines/errors.d.ts +26 -0
- package/dist/pipelines/handles.d.ts +29 -0
- package/dist/pipelines/index.d.ts +18 -0
- package/dist/pipelines/index.js +80 -0
- package/dist/pipelines/model.d.ts +103 -0
- package/dist/pipelines/nodes.d.ts +54 -0
- package/dist/pipelines/ref-types.d.ts +54 -0
- package/dist/pipelines/refs.d.ts +80 -0
- package/dist/pipelines/registry.d.ts +12 -0
- package/dist/pipelines/source.d.ts +17 -0
- package/dist/pipelines/types.d.ts +160 -0
- package/dist/push/code-step-lookup.d.ts +32 -0
- package/dist/push/code-step-lookup.js +11 -0
- package/dist/push/collect-definitions.d.ts +70 -0
- package/dist/push/collect-pipeline-documents.d.ts +14 -0
- package/dist/push/index.d.ts +6 -0
- package/dist/push/index.js +328 -0
- package/dist/push/push-from-directory.d.ts +37 -0
- package/dist/repo-config.d.ts +80 -0
- package/dist/repo-config.js +23 -0
- package/dist/scarn-config-parser.d.ts +29 -0
- package/dist/scarn-config-parser.js +9 -0
- package/dist/task-plane-client.d.ts +489 -0
- package/dist/z.d.ts +7 -0
- package/package.json +132 -4
- package/README.md +0 -3
|
@@ -0,0 +1,1094 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import {
|
|
3
|
+
captureSite,
|
|
4
|
+
PipelineBuildError2,
|
|
5
|
+
AuthoringError,
|
|
6
|
+
pendingChains,
|
|
7
|
+
registerNode,
|
|
8
|
+
registerTarget,
|
|
9
|
+
registerEach,
|
|
10
|
+
nodeOf,
|
|
11
|
+
targetOf,
|
|
12
|
+
eachOf,
|
|
13
|
+
chainOf,
|
|
14
|
+
requireNode,
|
|
15
|
+
waitHandle,
|
|
16
|
+
bareStepHandle
|
|
17
|
+
} from "./chunk-eg1hcvhb.js";
|
|
18
|
+
import {
|
|
19
|
+
jsonPointer2
|
|
20
|
+
} from "./chunk-4vehh3dq.js";
|
|
21
|
+
import {
|
|
22
|
+
decisionResultSchema2,
|
|
23
|
+
REPLY_RESULT_SCHEMA2,
|
|
24
|
+
CONVERSATION_RESULT_SCHEMA2,
|
|
25
|
+
REPLY_INPUT_SCHEMA2,
|
|
26
|
+
ERROR_SCHEMA2
|
|
27
|
+
} from "./chunk-5mmj03ah.js";
|
|
28
|
+
import {
|
|
29
|
+
toJSONSchema
|
|
30
|
+
} from "./chunk-dnn39qt4.js";
|
|
31
|
+
|
|
32
|
+
// src/pipelines/refs.ts
|
|
33
|
+
var REF = Symbol("scarn.ref");
|
|
34
|
+
var active = null;
|
|
35
|
+
var currentOwners = [];
|
|
36
|
+
function withOwners(owners, run) {
|
|
37
|
+
const previous = currentOwners;
|
|
38
|
+
currentOwners = owners;
|
|
39
|
+
try {
|
|
40
|
+
return run();
|
|
41
|
+
} finally {
|
|
42
|
+
currentOwners = previous;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function withTracker(tracker, run) {
|
|
46
|
+
const previous = active;
|
|
47
|
+
active = tracker;
|
|
48
|
+
try {
|
|
49
|
+
return run();
|
|
50
|
+
} finally {
|
|
51
|
+
active = previous;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function setTrackerPointer(pointer) {
|
|
55
|
+
if (active !== null) {
|
|
56
|
+
active.pointer = pointer;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
var COERCION_HINT = "a placeholder stands for a value that only exists when the pipeline runs, so it can't be compared, converted or used in JS logic. Use a condition helper such as equal(...) or greaterThan(...), in a .next(...) route's when to branch";
|
|
60
|
+
function coercionError(path) {
|
|
61
|
+
throw new AuthoringError(`"${path === "" ? "element" : path}" was coerced to a primitive: ${COERCION_HINT}`);
|
|
62
|
+
}
|
|
63
|
+
function propertySchema(schema, key) {
|
|
64
|
+
if (key === "length") {
|
|
65
|
+
return { type: "integer" };
|
|
66
|
+
}
|
|
67
|
+
if (typeof schema !== "object") {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (/^\d+$/.test(key) && schema.items !== undefined) {
|
|
71
|
+
return schema.items;
|
|
72
|
+
}
|
|
73
|
+
return schema.properties?.[key];
|
|
74
|
+
}
|
|
75
|
+
function spreadKeys(data) {
|
|
76
|
+
const schema = data.schema;
|
|
77
|
+
if (typeof schema !== "object" || schema.properties === undefined || schema.type !== undefined && schema.type !== "object") {
|
|
78
|
+
throw new AuthoringError(`can't spread "${data.path}": its JSON Schema doesn't declare its properties, so the args it expands to aren't known. Pass each arg explicitly`);
|
|
79
|
+
}
|
|
80
|
+
return Object.keys(schema.properties);
|
|
81
|
+
}
|
|
82
|
+
function joinPath(path, key) {
|
|
83
|
+
return path === "" ? key : `${path}.${key}`;
|
|
84
|
+
}
|
|
85
|
+
function makePlaceholder(data) {
|
|
86
|
+
const children = new Map;
|
|
87
|
+
const child = (key) => {
|
|
88
|
+
const cached = children.get(key);
|
|
89
|
+
if (cached !== undefined) {
|
|
90
|
+
return cached;
|
|
91
|
+
}
|
|
92
|
+
const created = createChild(key);
|
|
93
|
+
children.set(key, created);
|
|
94
|
+
return created;
|
|
95
|
+
};
|
|
96
|
+
const spreadChild = (key) => makePlaceholder({
|
|
97
|
+
...data,
|
|
98
|
+
path: joinPath(data.path, key),
|
|
99
|
+
schema: propertySchema(data.schema, key),
|
|
100
|
+
record: data.record
|
|
101
|
+
});
|
|
102
|
+
const createChild = (key) => {
|
|
103
|
+
const record = active === null ? null : {
|
|
104
|
+
path: joinPath(data.path, key),
|
|
105
|
+
site: captureSite(),
|
|
106
|
+
pointer: active.pointer,
|
|
107
|
+
parent: data.record,
|
|
108
|
+
used: false,
|
|
109
|
+
hasChildren: false
|
|
110
|
+
};
|
|
111
|
+
if (record !== null) {
|
|
112
|
+
active?.records.push(record);
|
|
113
|
+
if (data.record !== null) {
|
|
114
|
+
data.record.hasChildren = true;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return makePlaceholder({
|
|
118
|
+
path: joinPath(data.path, key),
|
|
119
|
+
scope: data.scope,
|
|
120
|
+
schema: propertySchema(data.schema, key),
|
|
121
|
+
field: data.field,
|
|
122
|
+
record,
|
|
123
|
+
owner: data.owner,
|
|
124
|
+
reach: data.reach
|
|
125
|
+
});
|
|
126
|
+
};
|
|
127
|
+
let spreading;
|
|
128
|
+
return new Proxy(Object.create(null), {
|
|
129
|
+
get(_target, key) {
|
|
130
|
+
if (typeof key === "string" && key === spreading) {
|
|
131
|
+
spreading = undefined;
|
|
132
|
+
return spreadChild(key);
|
|
133
|
+
}
|
|
134
|
+
if (key === REF) {
|
|
135
|
+
return data;
|
|
136
|
+
}
|
|
137
|
+
if (key === Symbol.toPrimitive || key === "valueOf" || key === "toString" || key === "toJSON") {
|
|
138
|
+
return () => coercionError(data.path);
|
|
139
|
+
}
|
|
140
|
+
if (typeof key === "symbol" || key === "then") {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
return child(key);
|
|
144
|
+
},
|
|
145
|
+
has(_target, key) {
|
|
146
|
+
return key === REF;
|
|
147
|
+
},
|
|
148
|
+
ownKeys() {
|
|
149
|
+
return spreadKeys(data);
|
|
150
|
+
},
|
|
151
|
+
getOwnPropertyDescriptor(_target, key) {
|
|
152
|
+
if (typeof key !== "string") {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
spreading = key;
|
|
156
|
+
return {
|
|
157
|
+
configurable: true,
|
|
158
|
+
enumerable: true,
|
|
159
|
+
writable: false,
|
|
160
|
+
value: spreadChild(key)
|
|
161
|
+
};
|
|
162
|
+
},
|
|
163
|
+
set() {
|
|
164
|
+
throw new AuthoringError(`can't assign to "${data.path}"`);
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
function rootPlaceholder(path, schema, options = {}) {
|
|
169
|
+
const record = active === null ? null : {
|
|
170
|
+
path,
|
|
171
|
+
site: captureSite(),
|
|
172
|
+
pointer: active.pointer,
|
|
173
|
+
parent: null,
|
|
174
|
+
used: false,
|
|
175
|
+
hasChildren: false
|
|
176
|
+
};
|
|
177
|
+
if (record !== null) {
|
|
178
|
+
active?.records.push(record);
|
|
179
|
+
}
|
|
180
|
+
return makePlaceholder({
|
|
181
|
+
path,
|
|
182
|
+
scope: options.scope ?? "document",
|
|
183
|
+
schema,
|
|
184
|
+
field: options.field,
|
|
185
|
+
record,
|
|
186
|
+
owner: options.owner ?? null,
|
|
187
|
+
reach: options.reach
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
function refData(value) {
|
|
191
|
+
if ((typeof value === "object" || typeof value === "function") && value !== null && REF in value) {
|
|
192
|
+
return value[REF];
|
|
193
|
+
}
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
function markUsed(data) {
|
|
197
|
+
for (let record = data.record;record !== null; record = record.parent) {
|
|
198
|
+
record.used = true;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
function useRef(data) {
|
|
202
|
+
markUsed(data);
|
|
203
|
+
if (data.field !== undefined) {
|
|
204
|
+
active?.fields.push(data.field);
|
|
205
|
+
}
|
|
206
|
+
if (data.reach !== undefined && active !== null) {
|
|
207
|
+
active.reaches.push({
|
|
208
|
+
node: data.reach,
|
|
209
|
+
pointer: active.pointer,
|
|
210
|
+
site: data.record?.site ?? null
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
if (data.owner !== null && !currentOwners.includes(data.owner)) {
|
|
214
|
+
throw new AuthoringError(`"${data.path}" comes from another callback's r: "result", "input" and "error" mean this node's own values in each callback. Use r.node(handle) to reach back to another node`, data.record?.site ?? null);
|
|
215
|
+
}
|
|
216
|
+
return data.path;
|
|
217
|
+
}
|
|
218
|
+
function unusedReads(tracker) {
|
|
219
|
+
return tracker.records.filter((record) => !record.used && !record.hasChildren);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// src/pipelines/condition-data.ts
|
|
223
|
+
class ConditionData {
|
|
224
|
+
node;
|
|
225
|
+
site;
|
|
226
|
+
constructor(node, site = captureSite()) {
|
|
227
|
+
this.node = node;
|
|
228
|
+
this.site = site;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
class ComputedData {
|
|
233
|
+
node;
|
|
234
|
+
site;
|
|
235
|
+
constructor(node, site = captureSite()) {
|
|
236
|
+
this.node = node;
|
|
237
|
+
this.site = site;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
function conditionData(value) {
|
|
241
|
+
if (value instanceof ConditionData) {
|
|
242
|
+
return value;
|
|
243
|
+
}
|
|
244
|
+
throw new AuthoringError(`${typeof value === "boolean" ? "a JS boolean" : "this value"} is not a condition: build conditions with the helpers (equal, greaterThan, all, ...), not JS operators`);
|
|
245
|
+
}
|
|
246
|
+
function requireRef(value, what) {
|
|
247
|
+
const data = refData(value);
|
|
248
|
+
if (data === undefined) {
|
|
249
|
+
throw new AuthoringError(`${what} must be a reference (r.result..., r.input..., ...)`);
|
|
250
|
+
}
|
|
251
|
+
return data;
|
|
252
|
+
}
|
|
253
|
+
function refPath(ref, scope, side) {
|
|
254
|
+
if (side === "right" && ref.scope === "element") {
|
|
255
|
+
throw new AuthoringError(`"${ref.path}" is relative to a list element and can only be the left side of a condition inside some / every / none / count`, ref.record?.site ?? null);
|
|
256
|
+
}
|
|
257
|
+
if (side === "left" && ref.scope !== scope) {
|
|
258
|
+
throw new AuthoringError(scope === "element" ? `"${ref.path}" is a full reference, but inside some / every / none / count the left side must come from the element parameter` : `"${ref.path}" is relative to a list element and can only be used inside that list's callback`, ref.record?.site ?? null);
|
|
259
|
+
}
|
|
260
|
+
return useRef(ref);
|
|
261
|
+
}
|
|
262
|
+
function leftPath(ref, scope) {
|
|
263
|
+
const path = refPath(ref, scope, "left");
|
|
264
|
+
if (path === "") {
|
|
265
|
+
throw new AuthoringError("a condition on the whole element isn't supported; compare one of its fields", ref.record?.site ?? null);
|
|
266
|
+
}
|
|
267
|
+
return path;
|
|
268
|
+
}
|
|
269
|
+
function compileComputed(computed, scope) {
|
|
270
|
+
if ("refs" in computed) {
|
|
271
|
+
const source = computed.refs.map((ref) => leftPath(ref, scope));
|
|
272
|
+
return computed.weights === undefined ? { source } : { source, weights: computed.weights };
|
|
273
|
+
}
|
|
274
|
+
const path = leftPath(computed.list, scope);
|
|
275
|
+
if (computed.field !== undefined) {
|
|
276
|
+
return { source: { path, field: leftPath(computed.field, "element") } };
|
|
277
|
+
}
|
|
278
|
+
if (computed.where !== undefined) {
|
|
279
|
+
return {
|
|
280
|
+
source: { path, where: compileCondition(computed.where, "element") }
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
return { source: { path } };
|
|
284
|
+
}
|
|
285
|
+
function compileRight(right) {
|
|
286
|
+
switch (right.kind) {
|
|
287
|
+
case "none":
|
|
288
|
+
return {};
|
|
289
|
+
case "value":
|
|
290
|
+
return { value: right.value };
|
|
291
|
+
case "ref":
|
|
292
|
+
return { ref: refPath(right.ref, "document", "right") };
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
function compileCondition(data, scope = "document") {
|
|
296
|
+
const node = data.node;
|
|
297
|
+
switch (node.kind) {
|
|
298
|
+
case "all":
|
|
299
|
+
case "any":
|
|
300
|
+
return {
|
|
301
|
+
[node.kind]: node.items.map((item) => compileCondition(item, scope))
|
|
302
|
+
};
|
|
303
|
+
case "not":
|
|
304
|
+
return { not: compileCondition(node.item, scope) };
|
|
305
|
+
case "list":
|
|
306
|
+
return {
|
|
307
|
+
path: leftPath(node.list, scope),
|
|
308
|
+
op: node.op,
|
|
309
|
+
where: compileCondition(node.where, "element")
|
|
310
|
+
};
|
|
311
|
+
case "compare": {
|
|
312
|
+
if (node.left.kind === "ref") {
|
|
313
|
+
return {
|
|
314
|
+
path: leftPath(node.left.ref, scope),
|
|
315
|
+
op: node.op,
|
|
316
|
+
...compileRight(node.right)
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
const { source, weights } = compileComputed(node.left.computed, scope);
|
|
320
|
+
return {
|
|
321
|
+
[node.left.computed.fn]: source,
|
|
322
|
+
...weights === undefined ? {} : { weights },
|
|
323
|
+
op: node.op,
|
|
324
|
+
...compileRight(node.right)
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// src/pipelines/compile-args.ts
|
|
331
|
+
function literal(value, path) {
|
|
332
|
+
if (refData(value) !== undefined) {
|
|
333
|
+
throw new AuthoringError(`"${path}" is a literal containing a reference; an arg is either a reference or a plain JSON value. Pass the reference as its own arg, or a reference to the whole object`);
|
|
334
|
+
}
|
|
335
|
+
if (value === null || typeof value === "string" || typeof value === "boolean") {
|
|
336
|
+
return value;
|
|
337
|
+
}
|
|
338
|
+
if (typeof value === "number") {
|
|
339
|
+
if (!Number.isFinite(value)) {
|
|
340
|
+
throw new AuthoringError(`"${path}" is ${String(value)}, which isn't JSON`);
|
|
341
|
+
}
|
|
342
|
+
return value;
|
|
343
|
+
}
|
|
344
|
+
if (Array.isArray(value)) {
|
|
345
|
+
return value.map((item, index) => literal(item, `${path}.${String(index)}`));
|
|
346
|
+
}
|
|
347
|
+
if (typeof value === "object" && Object.getPrototypeOf(value) === Object.prototype) {
|
|
348
|
+
const out = {};
|
|
349
|
+
for (const [key, item] of Object.entries(value)) {
|
|
350
|
+
if (item !== undefined) {
|
|
351
|
+
out[key] = literal(item, `${path}.${key}`);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
return out;
|
|
355
|
+
}
|
|
356
|
+
throw new AuthoringError(`"${path}" is a ${typeof value}, which isn't a JSON value`);
|
|
357
|
+
}
|
|
358
|
+
function refArg(name, data) {
|
|
359
|
+
if (data.scope === "element") {
|
|
360
|
+
throw new AuthoringError(`"${name}" is a list element from some / every / none / count; those exist only inside the condition`, data.record?.site ?? null);
|
|
361
|
+
}
|
|
362
|
+
return useRef(data);
|
|
363
|
+
}
|
|
364
|
+
function compileArg(name, value) {
|
|
365
|
+
const data = refData(value);
|
|
366
|
+
if (data !== undefined) {
|
|
367
|
+
return refArg(name, data);
|
|
368
|
+
}
|
|
369
|
+
if (Array.isArray(value) && value.some((item) => refData(item) !== undefined)) {
|
|
370
|
+
return {
|
|
371
|
+
list: value.map((item, index) => {
|
|
372
|
+
const path = `${name}.${String(index)}`;
|
|
373
|
+
const element = refData(item);
|
|
374
|
+
return element === undefined ? { value: literal(item, path) } : refArg(path, element);
|
|
375
|
+
})
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
return { value: literal(value, name) };
|
|
379
|
+
}
|
|
380
|
+
function argEntries(args) {
|
|
381
|
+
return Object.entries(args).filter(([, value]) => value !== undefined);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// src/pipelines/compile-state.ts
|
|
385
|
+
function newState() {
|
|
386
|
+
return {
|
|
387
|
+
nodes: new Map,
|
|
388
|
+
issues: [],
|
|
389
|
+
sourceMap: {},
|
|
390
|
+
tracker: { records: [], fields: [], reaches: [], pointer: "" },
|
|
391
|
+
usedChains: new Set
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
function issue(state, site, pointer, message) {
|
|
395
|
+
state.issues.push({ site, pointer: jsonPointer2(pointer), message });
|
|
396
|
+
}
|
|
397
|
+
function mapSource(state, pointer, site) {
|
|
398
|
+
const key = jsonPointer2(pointer);
|
|
399
|
+
if (site !== null && state.sourceMap[key] === undefined) {
|
|
400
|
+
state.sourceMap[key] = site;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
function attempt(state, pointer, site, run) {
|
|
404
|
+
const previous = state.tracker.pointer;
|
|
405
|
+
setTrackerPointer(jsonPointer2(pointer));
|
|
406
|
+
try {
|
|
407
|
+
return run();
|
|
408
|
+
} catch (error) {
|
|
409
|
+
if (error instanceof AuthoringError) {
|
|
410
|
+
issue(state, error.site ?? site, pointer, error.message);
|
|
411
|
+
} else {
|
|
412
|
+
issue(state, site, pointer, error instanceof Error ? error.message : String(error));
|
|
413
|
+
}
|
|
414
|
+
return;
|
|
415
|
+
} finally {
|
|
416
|
+
setTrackerPointer(previous);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
function place(state, def, site, pointer) {
|
|
420
|
+
const existing = state.nodes.get(def.id);
|
|
421
|
+
if (existing === undefined) {
|
|
422
|
+
const placed = {
|
|
423
|
+
def,
|
|
424
|
+
chain: undefined,
|
|
425
|
+
json: {}
|
|
426
|
+
};
|
|
427
|
+
state.nodes.set(def.id, placed);
|
|
428
|
+
mapSource(state, ["nodes", def.id], def.site);
|
|
429
|
+
return placed;
|
|
430
|
+
}
|
|
431
|
+
if (existing.def !== def) {
|
|
432
|
+
issue(state, site, pointer, `two different handles use the node id "${def.id}"; give one a different id (step.as("...") for steps)`);
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
435
|
+
return existing;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// src/pipelines/context.ts
|
|
439
|
+
function schemaOf(node, source) {
|
|
440
|
+
if (node.kind === "step") {
|
|
441
|
+
if (source === "result" && node.conversation) {
|
|
442
|
+
return CONVERSATION_RESULT_SCHEMA2;
|
|
443
|
+
}
|
|
444
|
+
return (source === "result" ? node.resultSchema : node.inputSchema) ?? undefined;
|
|
445
|
+
}
|
|
446
|
+
if (node.kind === "wait") {
|
|
447
|
+
return source === "result" ? node.resultSchema : node.inputSchema ?? undefined;
|
|
448
|
+
}
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
function reach(target) {
|
|
452
|
+
const node = requireNode(target, "r.node(...)");
|
|
453
|
+
if (node.kind !== "step" && node.kind !== "wait") {
|
|
454
|
+
throw new Error(`r.node("${node.id}"): ${node.kind} nodes have no result or input`);
|
|
455
|
+
}
|
|
456
|
+
return {
|
|
457
|
+
get result() {
|
|
458
|
+
return rootPlaceholder(`nodes.${node.id}.result`, schemaOf(node, "result"), { reach: node.id });
|
|
459
|
+
},
|
|
460
|
+
get input() {
|
|
461
|
+
return rootPlaceholder(`nodes.${node.id}.input`, schemaOf(node, "input"), { reach: node.id });
|
|
462
|
+
}
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
function makeContext(node, kind) {
|
|
466
|
+
const context = { node: reach };
|
|
467
|
+
const owned = (path, schema) => ({
|
|
468
|
+
get: () => rootPlaceholder(path, schema, { owner: context }),
|
|
469
|
+
enumerable: true
|
|
470
|
+
});
|
|
471
|
+
if (kind === "next") {
|
|
472
|
+
Object.defineProperties(context, {
|
|
473
|
+
result: owned("result", schemaOf(node, "result")),
|
|
474
|
+
input: owned("input", schemaOf(node, "input"))
|
|
475
|
+
});
|
|
476
|
+
} else {
|
|
477
|
+
Object.defineProperties(context, {
|
|
478
|
+
error: owned("error", ERROR_SCHEMA2),
|
|
479
|
+
input: owned("input", schemaOf(node, "input"))
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
return context;
|
|
483
|
+
}
|
|
484
|
+
function makeItem(itemsSchema) {
|
|
485
|
+
const owner = {};
|
|
486
|
+
return { item: rootPlaceholder("item", itemsSchema, { owner }), owner };
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
// src/pipelines/compile-chain.ts
|
|
490
|
+
function resolve(spec, context) {
|
|
491
|
+
const node = nodeOf(spec);
|
|
492
|
+
if (node !== undefined && node.kind !== "succeed" && node.kind !== "fail") {
|
|
493
|
+
return { target: { node, args: undefined, site: null } };
|
|
494
|
+
}
|
|
495
|
+
const value = typeof spec === "function" ? spec(context) : spec;
|
|
496
|
+
const target = targetOf(value);
|
|
497
|
+
if (target !== undefined) {
|
|
498
|
+
return { target };
|
|
499
|
+
}
|
|
500
|
+
const bare = nodeOf(value);
|
|
501
|
+
if (bare !== undefined) {
|
|
502
|
+
return { target: { node: bare, args: undefined, site: null } };
|
|
503
|
+
}
|
|
504
|
+
const each = eachOf(value);
|
|
505
|
+
if (each !== undefined) {
|
|
506
|
+
return { each };
|
|
507
|
+
}
|
|
508
|
+
throw new AuthoringError(chainOf(value) !== undefined ? "a chain isn't a target; put chains in flow and target the step (step(args) or a bare step)" : "this isn't a target: call a step with its args, or use a bare step, decision, succeed or fail");
|
|
509
|
+
}
|
|
510
|
+
function compileArgs(state, target, owners, pointer) {
|
|
511
|
+
if (target.args === undefined) {
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
514
|
+
const entries = attempt(state, pointer, target.site, () => argEntries(target.args ?? {}));
|
|
515
|
+
const out = {};
|
|
516
|
+
for (const [name, value] of entries ?? []) {
|
|
517
|
+
const compiled = attempt(state, [...pointer, name], target.site, () => withOwners(owners, () => compileArg(name, value)));
|
|
518
|
+
if (compiled !== undefined) {
|
|
519
|
+
out[name] = compiled;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
return out;
|
|
523
|
+
}
|
|
524
|
+
function itemsOf(schema) {
|
|
525
|
+
return typeof schema === "object" ? schema.items : undefined;
|
|
526
|
+
}
|
|
527
|
+
function compileEach(state, each, owners, pointer) {
|
|
528
|
+
const over = attempt(state, [...pointer, "each", "over"], each.site, () => withOwners(owners, () => useRef(each.over)));
|
|
529
|
+
const { item, owner } = makeItem(itemsOf(each.over.schema));
|
|
530
|
+
const start = attempt(state, pointer, each.site, () => {
|
|
531
|
+
const value = each.start(item);
|
|
532
|
+
const target = targetOf(value);
|
|
533
|
+
if (target === undefined || target.partial === true) {
|
|
534
|
+
throw new AuthoringError(eachOf(value) !== undefined ? "an each's start can't be another each; start the lane at a step, and put the nested each in that step's chain" : target?.partial === true ? "an each's start can't be a .partial(...) target; start the lane at a step" : "an each's start must return a target, such as step({ ... })", each.site);
|
|
535
|
+
}
|
|
536
|
+
return target;
|
|
537
|
+
});
|
|
538
|
+
if (over === undefined || start === undefined) {
|
|
539
|
+
return;
|
|
540
|
+
}
|
|
541
|
+
const json = targetJson(state, start, [...owners, owner], pointer);
|
|
542
|
+
const options = {
|
|
543
|
+
...each.maxConcurrency === undefined ? {} : { maxConcurrency: each.maxConcurrency },
|
|
544
|
+
...each.toleratedFailures === undefined ? {} : { toleratedFailures: { ...each.toleratedFailures } }
|
|
545
|
+
};
|
|
546
|
+
const transition = { to: json["to"], each: { over, ...options } };
|
|
547
|
+
if (json["args"] !== undefined) {
|
|
548
|
+
transition["args"] = json["args"];
|
|
549
|
+
}
|
|
550
|
+
return transition;
|
|
551
|
+
}
|
|
552
|
+
function targetJson(state, target, owners, pointer) {
|
|
553
|
+
place(state, target.node, target.site, pointer);
|
|
554
|
+
mapSource(state, pointer, target.site);
|
|
555
|
+
const args = compileArgs(state, target, owners, [...pointer, "args"]);
|
|
556
|
+
const json = args === undefined ? { to: target.node.id } : { to: target.node.id, args };
|
|
557
|
+
if (target.partial === true) {
|
|
558
|
+
json["partial"] = true;
|
|
559
|
+
}
|
|
560
|
+
return json;
|
|
561
|
+
}
|
|
562
|
+
function compileTransition(state, spec, context, pointer, site, kind) {
|
|
563
|
+
const resolved = attempt(state, pointer, site, () => withOwners(context === null ? [] : [context], () => resolve(spec, context)));
|
|
564
|
+
if (resolved === undefined) {
|
|
565
|
+
return;
|
|
566
|
+
}
|
|
567
|
+
const owners = context === null ? [] : [context];
|
|
568
|
+
if (resolved.each !== undefined) {
|
|
569
|
+
if (kind !== "next") {
|
|
570
|
+
issue(state, resolved.each.site ?? site, pointer, "each is only valid as a target in .next(...)");
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
return compileEach(state, resolved.each, owners, pointer);
|
|
574
|
+
}
|
|
575
|
+
const target = resolved.target;
|
|
576
|
+
if (target === undefined) {
|
|
577
|
+
return;
|
|
578
|
+
}
|
|
579
|
+
if (target.partial === true && kind !== "next") {
|
|
580
|
+
issue(state, target.site ?? site, pointer, ".partial(...) is only valid as a target in .next(...)");
|
|
581
|
+
return;
|
|
582
|
+
}
|
|
583
|
+
return targetJson(state, { ...target, site: target.site ?? site }, owners, pointer);
|
|
584
|
+
}
|
|
585
|
+
function wireChain(state, value, site) {
|
|
586
|
+
const chain = chainOf(value);
|
|
587
|
+
if (chain === undefined || chain.next === undefined) {
|
|
588
|
+
issue(state, site, [], "flow only takes finished chains (ending in .next(...))");
|
|
589
|
+
return;
|
|
590
|
+
}
|
|
591
|
+
const id = chain.node.id;
|
|
592
|
+
const placed = place(state, chain.node, chain.site, ["nodes", id]);
|
|
593
|
+
if (placed === undefined) {
|
|
594
|
+
return;
|
|
595
|
+
}
|
|
596
|
+
if (placed.chain !== undefined) {
|
|
597
|
+
issue(state, chain.site, ["nodes", id], `"${id}" is wired twice: it already has a chain in flow. Give each node one chain`);
|
|
598
|
+
return;
|
|
599
|
+
}
|
|
600
|
+
placed.chain = chain;
|
|
601
|
+
state.usedChains.add(chain);
|
|
602
|
+
wireBody(state, chain, placed.json);
|
|
603
|
+
}
|
|
604
|
+
function wireBody(state, chain, json) {
|
|
605
|
+
const id = chain.node.id;
|
|
606
|
+
if (chain.retry.length > 0) {
|
|
607
|
+
json["retry"] = chain.retry.map((entry) => ({
|
|
608
|
+
on: [...entry.on],
|
|
609
|
+
maxAttempts: entry.maxAttempts
|
|
610
|
+
}));
|
|
611
|
+
}
|
|
612
|
+
const catches = chain.catch.map((entry, index) => {
|
|
613
|
+
const pointer = ["nodes", id, "catch", index];
|
|
614
|
+
const context = makeContext(chain.node, "catch");
|
|
615
|
+
const target = compileTransition(state, entry.target, context, pointer, entry.site, "catch");
|
|
616
|
+
return { on: [...entry.on], ...target };
|
|
617
|
+
});
|
|
618
|
+
if (catches.length > 0) {
|
|
619
|
+
json["catch"] = catches;
|
|
620
|
+
}
|
|
621
|
+
const next = chain.next;
|
|
622
|
+
if (next === undefined) {
|
|
623
|
+
return;
|
|
624
|
+
}
|
|
625
|
+
const context = makeContext(chain.node, "next");
|
|
626
|
+
const compileRoute = (when, target, pointer) => {
|
|
627
|
+
mapSource(state, pointer, next.site);
|
|
628
|
+
const entry = {};
|
|
629
|
+
if (when !== undefined) {
|
|
630
|
+
const compiled = attempt(state, [...pointer, "when"], next.site, () => withOwners([context], () => compileCondition(conditionData(when(context)))));
|
|
631
|
+
if (compiled !== undefined) {
|
|
632
|
+
entry["when"] = compiled;
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
const compiled = compileTransition(state, target, context, pointer, next.site, "next");
|
|
636
|
+
return { ...entry, ...compiled };
|
|
637
|
+
};
|
|
638
|
+
const out = {};
|
|
639
|
+
if (next.match === "all") {
|
|
640
|
+
out["match"] = "all";
|
|
641
|
+
} else if (next.routes.length > 1) {
|
|
642
|
+
next.routes.forEach((route, index) => {
|
|
643
|
+
if (route.when === undefined) {
|
|
644
|
+
issue(state, next.site, ["nodes", id, "next", "routes", index], `"${id}" has more than one route, so in "first" mode every route needs a "when"; move this target to "otherwise", or use match: "all"`);
|
|
645
|
+
}
|
|
646
|
+
});
|
|
647
|
+
}
|
|
648
|
+
out["routes"] = next.routes.map((route, index) => compileRoute(route.when, route.target, [
|
|
649
|
+
"nodes",
|
|
650
|
+
id,
|
|
651
|
+
"next",
|
|
652
|
+
"routes",
|
|
653
|
+
index
|
|
654
|
+
]));
|
|
655
|
+
if (next.otherwise !== undefined) {
|
|
656
|
+
out["otherwise"] = compileRoute(undefined, next.otherwise, [
|
|
657
|
+
"nodes",
|
|
658
|
+
id,
|
|
659
|
+
"next",
|
|
660
|
+
"otherwise"
|
|
661
|
+
]);
|
|
662
|
+
}
|
|
663
|
+
json["next"] = out;
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
// src/pipelines/compile-checks.ts
|
|
667
|
+
function targetsOf(json) {
|
|
668
|
+
const next = json["next"];
|
|
669
|
+
const entries = [
|
|
670
|
+
...next?.routes ?? [],
|
|
671
|
+
...next?.otherwise === undefined ? [] : [next.otherwise],
|
|
672
|
+
...json["catch"] ?? []
|
|
673
|
+
];
|
|
674
|
+
return entries.flatMap((entry) => entry.to === undefined ? [] : [entry.to]);
|
|
675
|
+
}
|
|
676
|
+
function checkReachable(state, start) {
|
|
677
|
+
const seen = new Set;
|
|
678
|
+
const queue = start === undefined ? [] : [start];
|
|
679
|
+
while (queue.length > 0) {
|
|
680
|
+
const id = queue.shift() ?? "";
|
|
681
|
+
if (seen.has(id)) {
|
|
682
|
+
continue;
|
|
683
|
+
}
|
|
684
|
+
seen.add(id);
|
|
685
|
+
const placed = state.nodes.get(id);
|
|
686
|
+
if (placed !== undefined) {
|
|
687
|
+
queue.push(...targetsOf(placed.json));
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
for (const [id, placed] of state.nodes) {
|
|
691
|
+
if (!seen.has(id)) {
|
|
692
|
+
issue(state, placed.chain?.site ?? placed.def.site, ["nodes", id], `"${id}" is unreachable: nothing targets it from start`);
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
function checkDecisionActions(state) {
|
|
697
|
+
for (const [id, placed] of state.nodes) {
|
|
698
|
+
const def = placed.def;
|
|
699
|
+
if (def.kind === "wait" && def.for === "decision" && (def.actions ?? []).length === 0) {
|
|
700
|
+
issue(state, def.site, ["nodes", id, "actions"], `decision "${id}" has no actions; give it at least one, such as { approve: { label: "Approve" } }`);
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
function checkReaches(state) {
|
|
705
|
+
for (const use of state.tracker.reaches) {
|
|
706
|
+
if (!state.nodes.has(use.node)) {
|
|
707
|
+
state.issues.push({
|
|
708
|
+
site: use.site,
|
|
709
|
+
pointer: use.pointer,
|
|
710
|
+
message: `r.node(...) reaches back to "${use.node}", which isn't in this pipeline`
|
|
711
|
+
});
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
function checkUnusedReads(state) {
|
|
716
|
+
for (const record of unusedReads(state.tracker)) {
|
|
717
|
+
state.issues.push({
|
|
718
|
+
site: record.site,
|
|
719
|
+
pointer: record.pointer,
|
|
720
|
+
message: `"${record.path}" is read but never used in an arg, each or condition. JS logic on placeholders (?:, &&, ||, !, if) runs once at build time and picks one branch; use a condition helper in a .next(...) route's when`
|
|
721
|
+
});
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
function workItemFields(state) {
|
|
725
|
+
const fields = {};
|
|
726
|
+
for (const field of state.tracker.fields) {
|
|
727
|
+
const existing = fields[field.alias];
|
|
728
|
+
if (existing !== undefined && existing !== field.label) {
|
|
729
|
+
issue(state, null, ["workItemFields", field.alias], `work-item field "${field.alias}" is used with two labels: "${existing}" and "${field.label}"`);
|
|
730
|
+
} else {
|
|
731
|
+
fields[field.alias] = field.label;
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
return Object.keys(fields).length === 0 ? undefined : fields;
|
|
735
|
+
}
|
|
736
|
+
function unusedChainWarnings(state) {
|
|
737
|
+
const warnings = [];
|
|
738
|
+
for (const chain of pendingChains) {
|
|
739
|
+
const placed = state.nodes.get(chain.node.id);
|
|
740
|
+
if (state.usedChains.has(chain)) {
|
|
741
|
+
pendingChains.delete(chain);
|
|
742
|
+
} else if (placed !== undefined && placed.def === chain.node) {
|
|
743
|
+
pendingChains.delete(chain);
|
|
744
|
+
warnings.push({
|
|
745
|
+
site: chain.site,
|
|
746
|
+
pointer: `/nodes/${chain.node.id}`,
|
|
747
|
+
message: `a chain for "${chain.node.id}" was built but never put in flow, so it has no effect`
|
|
748
|
+
});
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
return warnings;
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
// src/pipelines/define-pipeline.ts
|
|
755
|
+
function nodeJson(placed) {
|
|
756
|
+
const def = placed.def;
|
|
757
|
+
const settings = placed.chain?.settings ?? {};
|
|
758
|
+
const title = settings.title ?? ("title" in def ? def.title : undefined);
|
|
759
|
+
const head = { kind: def.kind };
|
|
760
|
+
if (title !== undefined) {
|
|
761
|
+
head["title"] = title;
|
|
762
|
+
}
|
|
763
|
+
if (def.kind === "step") {
|
|
764
|
+
head["step"] = def.step;
|
|
765
|
+
} else if (def.kind === "wait") {
|
|
766
|
+
head["for"] = def.for;
|
|
767
|
+
if (def.actions !== null) {
|
|
768
|
+
head["actions"] = def.actions.map((action) => ({ ...action }));
|
|
769
|
+
}
|
|
770
|
+
} else if (def.kind === "fail") {
|
|
771
|
+
if (def.error !== undefined)
|
|
772
|
+
head["error"] = def.error;
|
|
773
|
+
if (def.cause !== undefined)
|
|
774
|
+
head["cause"] = def.cause;
|
|
775
|
+
}
|
|
776
|
+
for (const [key, value] of Object.entries(settings)) {
|
|
777
|
+
if (key !== "title" && value !== undefined) {
|
|
778
|
+
head[key] = value;
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
return { ...head, ...placed.json };
|
|
782
|
+
}
|
|
783
|
+
function orderedNodes(state) {
|
|
784
|
+
const entries = [...state.nodes];
|
|
785
|
+
const seq = ([, placed]) => placed.def.kind === "succeed" || placed.def.kind === "fail" ? placed.def.seq : -1;
|
|
786
|
+
return [
|
|
787
|
+
...entries.filter((entry) => seq(entry) < 0),
|
|
788
|
+
...entries.filter((entry) => seq(entry) >= 0).sort((a, b) => seq(a) - seq(b))
|
|
789
|
+
];
|
|
790
|
+
}
|
|
791
|
+
function stepCatalog(state) {
|
|
792
|
+
const steps = {};
|
|
793
|
+
for (const { def } of state.nodes.values()) {
|
|
794
|
+
if (def.kind === "step" && def.local) {
|
|
795
|
+
steps[def.step] = {
|
|
796
|
+
inputSchema: def.inputSchema ?? true,
|
|
797
|
+
resultSchema: def.conversation ? null : def.resultSchema ?? true,
|
|
798
|
+
errors: [...def.errors]
|
|
799
|
+
};
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
return steps;
|
|
803
|
+
}
|
|
804
|
+
function compile(config, site) {
|
|
805
|
+
const state = newState();
|
|
806
|
+
const start = withTracker(state.tracker, () => {
|
|
807
|
+
const transition = compileTransition(state, config.start, null, ["start"], site, "start");
|
|
808
|
+
for (const chain of config.flow) {
|
|
809
|
+
wireChain(state, chain, site);
|
|
810
|
+
}
|
|
811
|
+
return transition;
|
|
812
|
+
});
|
|
813
|
+
checkReachable(state, typeof start?.["to"] === "string" ? start["to"] : undefined);
|
|
814
|
+
checkDecisionActions(state);
|
|
815
|
+
checkReaches(state);
|
|
816
|
+
checkUnusedReads(state);
|
|
817
|
+
const fields = workItemFields(state);
|
|
818
|
+
const warnings = unusedChainWarnings(state);
|
|
819
|
+
if (state.issues.length > 0 || start === undefined) {
|
|
820
|
+
throw new PipelineBuildError2(config.key, state.issues);
|
|
821
|
+
}
|
|
822
|
+
const nodes = {};
|
|
823
|
+
for (const [id, placed] of orderedNodes(state)) {
|
|
824
|
+
nodes[id] = nodeJson(placed);
|
|
825
|
+
}
|
|
826
|
+
const document = {
|
|
827
|
+
schemaVersion: 1,
|
|
828
|
+
key: config.key,
|
|
829
|
+
...config.title === undefined ? {} : { title: config.title },
|
|
830
|
+
...fields === undefined ? {} : { workItemFields: fields },
|
|
831
|
+
start,
|
|
832
|
+
nodes
|
|
833
|
+
};
|
|
834
|
+
return {
|
|
835
|
+
_tag: "pipeline_document",
|
|
836
|
+
key: config.key,
|
|
837
|
+
document,
|
|
838
|
+
sourceMap: {
|
|
839
|
+
"": site ?? { file: "<unknown>", line: 0, column: 0 },
|
|
840
|
+
...state.sourceMap
|
|
841
|
+
},
|
|
842
|
+
steps: stepCatalog(state),
|
|
843
|
+
warnings
|
|
844
|
+
};
|
|
845
|
+
}
|
|
846
|
+
function definePipeline2(config) {
|
|
847
|
+
return compile(config, captureSite());
|
|
848
|
+
}
|
|
849
|
+
// src/pipelines/nodes.ts
|
|
850
|
+
function inputSchemaJson(input) {
|
|
851
|
+
return input === undefined ? null : toJSONSchema(input);
|
|
852
|
+
}
|
|
853
|
+
function decision2(id, options) {
|
|
854
|
+
const actions = Object.entries(options.actions).map(([key, action]) => ({
|
|
855
|
+
key,
|
|
856
|
+
label: action.label,
|
|
857
|
+
body: action.body ?? "optional"
|
|
858
|
+
}));
|
|
859
|
+
return waitHandle({
|
|
860
|
+
kind: "wait",
|
|
861
|
+
id,
|
|
862
|
+
for: "decision",
|
|
863
|
+
actions,
|
|
864
|
+
inputSchema: inputSchemaJson(options.input),
|
|
865
|
+
resultSchema: decisionResultSchema2(actions),
|
|
866
|
+
site: captureSite()
|
|
867
|
+
});
|
|
868
|
+
}
|
|
869
|
+
function reply2(id) {
|
|
870
|
+
return waitHandle({
|
|
871
|
+
kind: "wait",
|
|
872
|
+
id,
|
|
873
|
+
for: "reply",
|
|
874
|
+
actions: null,
|
|
875
|
+
inputSchema: {
|
|
876
|
+
type: "object",
|
|
877
|
+
properties: { questions: REPLY_INPUT_SCHEMA2 },
|
|
878
|
+
required: ["questions"]
|
|
879
|
+
},
|
|
880
|
+
resultSchema: REPLY_RESULT_SCHEMA2,
|
|
881
|
+
site: captureSite()
|
|
882
|
+
});
|
|
883
|
+
}
|
|
884
|
+
var terminalSeq = 0;
|
|
885
|
+
function terminal(node) {
|
|
886
|
+
const value = Object.freeze({ _tag: "pipeline_target", to: node.id });
|
|
887
|
+
registerNode(value, node);
|
|
888
|
+
return registerTarget(value, {
|
|
889
|
+
node,
|
|
890
|
+
args: undefined,
|
|
891
|
+
site: node.site
|
|
892
|
+
});
|
|
893
|
+
}
|
|
894
|
+
function succeed2(id, options = {}) {
|
|
895
|
+
return terminal({
|
|
896
|
+
kind: "succeed",
|
|
897
|
+
id,
|
|
898
|
+
seq: terminalSeq++,
|
|
899
|
+
...options.title === undefined ? {} : { title: options.title },
|
|
900
|
+
site: captureSite()
|
|
901
|
+
});
|
|
902
|
+
}
|
|
903
|
+
function fail2(id, options = {}) {
|
|
904
|
+
return terminal({
|
|
905
|
+
kind: "fail",
|
|
906
|
+
id,
|
|
907
|
+
seq: terminalSeq++,
|
|
908
|
+
...options.title === undefined ? {} : { title: options.title },
|
|
909
|
+
...options.error === undefined ? {} : { error: options.error },
|
|
910
|
+
...options.cause === undefined ? {} : { cause: options.cause },
|
|
911
|
+
site: captureSite()
|
|
912
|
+
});
|
|
913
|
+
}
|
|
914
|
+
function stepRef2(key) {
|
|
915
|
+
return bareStepHandle({ key, inputSchemaJson: null, resultSchemaJson: null, errors: [] }, false);
|
|
916
|
+
}
|
|
917
|
+
var workItem2 = {
|
|
918
|
+
get title() {
|
|
919
|
+
return rootPlaceholder("workItem.title", {
|
|
920
|
+
type: "string"
|
|
921
|
+
});
|
|
922
|
+
}
|
|
923
|
+
};
|
|
924
|
+
function workItemField2(alias, label) {
|
|
925
|
+
return rootPlaceholder(`workItem.fields.${alias}`, undefined, {
|
|
926
|
+
field: { alias, label }
|
|
927
|
+
});
|
|
928
|
+
}
|
|
929
|
+
// src/pipelines/each.ts
|
|
930
|
+
function each2(over, second, third) {
|
|
931
|
+
const data = refData(over);
|
|
932
|
+
if (data === undefined) {
|
|
933
|
+
throw new AuthoringError("each needs an array reference to iterate over");
|
|
934
|
+
}
|
|
935
|
+
const options = third === undefined ? {} : second;
|
|
936
|
+
const start = third ?? second;
|
|
937
|
+
if (typeof start !== "function") {
|
|
938
|
+
throw new AuthoringError("each needs a start callback: (item) => step({ ... })");
|
|
939
|
+
}
|
|
940
|
+
return registerEach(Object.freeze({ _tag: "pipeline_each" }), {
|
|
941
|
+
over: data,
|
|
942
|
+
maxConcurrency: options.maxConcurrency,
|
|
943
|
+
toleratedFailures: options.toleratedFailures,
|
|
944
|
+
start,
|
|
945
|
+
site: captureSite()
|
|
946
|
+
});
|
|
947
|
+
}
|
|
948
|
+
// src/pipelines/conditions.ts
|
|
949
|
+
function toCondition(data) {
|
|
950
|
+
return data;
|
|
951
|
+
}
|
|
952
|
+
function toComputed(data) {
|
|
953
|
+
return data;
|
|
954
|
+
}
|
|
955
|
+
function right(value) {
|
|
956
|
+
const data = refData(value);
|
|
957
|
+
if (data !== undefined) {
|
|
958
|
+
return { kind: "ref", ref: data };
|
|
959
|
+
}
|
|
960
|
+
if (value === undefined) {
|
|
961
|
+
throw new AuthoringError("a condition's right side can't be undefined");
|
|
962
|
+
}
|
|
963
|
+
return { kind: "value", value };
|
|
964
|
+
}
|
|
965
|
+
var NO_RIGHT = Symbol("no right side");
|
|
966
|
+
function compare(op, left, value) {
|
|
967
|
+
const leftNode = left instanceof ComputedData ? { kind: "computed", computed: left.node } : {
|
|
968
|
+
kind: "ref",
|
|
969
|
+
ref: requireRef(left, `the left side of "${op}"`)
|
|
970
|
+
};
|
|
971
|
+
return toCondition(new ConditionData({
|
|
972
|
+
kind: "compare",
|
|
973
|
+
left: leftNode,
|
|
974
|
+
op,
|
|
975
|
+
right: value === NO_RIGHT ? { kind: "none" } : right(value)
|
|
976
|
+
}));
|
|
977
|
+
}
|
|
978
|
+
function equal2(left, value) {
|
|
979
|
+
return compare("equal", left, value);
|
|
980
|
+
}
|
|
981
|
+
function notEqual2(left, value) {
|
|
982
|
+
return compare("notEqual", left, value);
|
|
983
|
+
}
|
|
984
|
+
function lessThan2(left, value) {
|
|
985
|
+
return compare("lessThan", left, value);
|
|
986
|
+
}
|
|
987
|
+
function lessThanInclusive2(left, value) {
|
|
988
|
+
return compare("lessThanInclusive", left, value);
|
|
989
|
+
}
|
|
990
|
+
function greaterThan2(left, value) {
|
|
991
|
+
return compare("greaterThan", left, value);
|
|
992
|
+
}
|
|
993
|
+
function greaterThanInclusive2(left, value) {
|
|
994
|
+
return compare("greaterThanInclusive", left, value);
|
|
995
|
+
}
|
|
996
|
+
function exists2(left) {
|
|
997
|
+
return compare("exists", left, NO_RIGHT);
|
|
998
|
+
}
|
|
999
|
+
function isEmpty2(left) {
|
|
1000
|
+
return compare("isEmpty", left, NO_RIGHT);
|
|
1001
|
+
}
|
|
1002
|
+
function contains2(left, value) {
|
|
1003
|
+
return compare("contains", left, value);
|
|
1004
|
+
}
|
|
1005
|
+
function startsWith2(left, value) {
|
|
1006
|
+
return compare("startsWith", left, value);
|
|
1007
|
+
}
|
|
1008
|
+
function endsWith2(left, value) {
|
|
1009
|
+
return compare("endsWith", left, value);
|
|
1010
|
+
}
|
|
1011
|
+
function matches2(left, pattern) {
|
|
1012
|
+
return compare("matches", left, pattern);
|
|
1013
|
+
}
|
|
1014
|
+
function before2(left, date) {
|
|
1015
|
+
return compare("before", left, date);
|
|
1016
|
+
}
|
|
1017
|
+
function after2(left, date) {
|
|
1018
|
+
return compare("after", left, date);
|
|
1019
|
+
}
|
|
1020
|
+
function all2(...conditions) {
|
|
1021
|
+
return toCondition(new ConditionData({ kind: "all", items: conditions.map(conditionData) }));
|
|
1022
|
+
}
|
|
1023
|
+
function any2(...conditions) {
|
|
1024
|
+
return toCondition(new ConditionData({ kind: "any", items: conditions.map(conditionData) }));
|
|
1025
|
+
}
|
|
1026
|
+
function not2(condition) {
|
|
1027
|
+
return toCondition(new ConditionData({ kind: "not", item: conditionData(condition) }));
|
|
1028
|
+
}
|
|
1029
|
+
function element(list) {
|
|
1030
|
+
const items = typeof list.schema === "object" ? list.schema.items : undefined;
|
|
1031
|
+
return rootPlaceholder("", items, { scope: "element" });
|
|
1032
|
+
}
|
|
1033
|
+
function select(callback, item) {
|
|
1034
|
+
return callback(item);
|
|
1035
|
+
}
|
|
1036
|
+
function list(op, over, where) {
|
|
1037
|
+
const data = requireRef(over, `the list of "${op}"`);
|
|
1038
|
+
const item = element(data);
|
|
1039
|
+
return toCondition(new ConditionData({
|
|
1040
|
+
kind: "list",
|
|
1041
|
+
list: data,
|
|
1042
|
+
op,
|
|
1043
|
+
where: conditionData(where(item))
|
|
1044
|
+
}));
|
|
1045
|
+
}
|
|
1046
|
+
function some2(over, where) {
|
|
1047
|
+
return list("some", over, where);
|
|
1048
|
+
}
|
|
1049
|
+
function every2(over, where) {
|
|
1050
|
+
return list("every", over, where);
|
|
1051
|
+
}
|
|
1052
|
+
function none2(over, where) {
|
|
1053
|
+
return list("none", over, where);
|
|
1054
|
+
}
|
|
1055
|
+
function reduce(fn, source, field, weights) {
|
|
1056
|
+
if (Array.isArray(source)) {
|
|
1057
|
+
const refs = source.map((value) => requireRef(value, `each value of "${fn}"`));
|
|
1058
|
+
return toComputed(new ComputedData(weights === undefined ? { fn, refs } : { fn, refs, weights }));
|
|
1059
|
+
}
|
|
1060
|
+
const data = requireRef(source, `the list of "${fn}"`);
|
|
1061
|
+
if (field === undefined) {
|
|
1062
|
+
throw new AuthoringError(`"${fn}" over a list needs a field selector, for example (x) => x.score`);
|
|
1063
|
+
}
|
|
1064
|
+
return toComputed(new ComputedData({
|
|
1065
|
+
fn,
|
|
1066
|
+
list: data,
|
|
1067
|
+
field: requireRef(select(field, element(data)), `the field of "${fn}"`)
|
|
1068
|
+
}));
|
|
1069
|
+
}
|
|
1070
|
+
function sum2(source, field) {
|
|
1071
|
+
return reduce("sum", source, field);
|
|
1072
|
+
}
|
|
1073
|
+
function avg2(source, second) {
|
|
1074
|
+
return typeof second === "function" ? reduce("avg", source, second) : reduce("avg", source, undefined, second?.weights);
|
|
1075
|
+
}
|
|
1076
|
+
function min2(source, field) {
|
|
1077
|
+
return reduce("min", source, field);
|
|
1078
|
+
}
|
|
1079
|
+
function max2(source, field) {
|
|
1080
|
+
return reduce("max", source, field);
|
|
1081
|
+
}
|
|
1082
|
+
function count2(source, where) {
|
|
1083
|
+
if (Array.isArray(source)) {
|
|
1084
|
+
const refs = source.map((value) => requireRef(value, 'each value of "count"'));
|
|
1085
|
+
return toComputed(new ComputedData({ fn: "count", refs }));
|
|
1086
|
+
}
|
|
1087
|
+
const data = requireRef(source, 'the list of "count"');
|
|
1088
|
+
return toComputed(new ComputedData(where === undefined ? { fn: "count", list: data } : {
|
|
1089
|
+
fn: "count",
|
|
1090
|
+
list: data,
|
|
1091
|
+
where: conditionData(select(where, element(data)))
|
|
1092
|
+
}));
|
|
1093
|
+
}
|
|
1094
|
+
export { definePipeline2, decision2, reply2, succeed2, fail2, stepRef2, workItem2, workItemField2, each2, equal2, notEqual2, lessThan2, lessThanInclusive2, greaterThan2, greaterThanInclusive2, exists2, isEmpty2, contains2, startsWith2, endsWith2, matches2, before2, after2, all2, any2, not2, some2, every2, none2, sum2, avg2, min2, max2, count2 };
|