@duckflux/runner 0.6.8 → 0.7.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/main.js +1422 -594
- package/package.json +7 -7
- package/src/lint.ts +1 -1
- package/src/main.ts +10 -2
- package/src/run.ts +3 -1
- package/src/server.ts +67 -0
- package/src/validate.ts +1 -1
package/dist/main.js
CHANGED
|
@@ -23,10 +23,10 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
|
23
23
|
var exports_eventhub = {};
|
|
24
24
|
__export(exports_eventhub, {
|
|
25
25
|
createHub: () => createHub,
|
|
26
|
-
MemoryHub: () =>
|
|
26
|
+
MemoryHub: () => MemoryHub2
|
|
27
27
|
});
|
|
28
28
|
|
|
29
|
-
class
|
|
29
|
+
class MemoryHub2 {
|
|
30
30
|
listeners = new Map;
|
|
31
31
|
buffer = new Map;
|
|
32
32
|
closed = false;
|
|
@@ -114,7 +114,7 @@ class MemoryHub {
|
|
|
114
114
|
async function createHub(config) {
|
|
115
115
|
switch (config.backend) {
|
|
116
116
|
case "memory":
|
|
117
|
-
return new
|
|
117
|
+
return new MemoryHub2;
|
|
118
118
|
case "nats":
|
|
119
119
|
throw new Error("NATS backend has been moved to @duckflux/hub-nats. " + "Install it and pass a NatsHub instance via ExecuteOptions.hub instead.");
|
|
120
120
|
case "redis":
|
|
@@ -128,23 +128,26 @@ var init_eventhub = () => {};
|
|
|
128
128
|
// src/main.ts
|
|
129
129
|
import { readFileSync as readFileSync3 } from "fs";
|
|
130
130
|
import { parseArgs } from "util";
|
|
131
|
-
import { dirname as
|
|
131
|
+
import { dirname as dirname5, resolve as resolve5 } from "path";
|
|
132
132
|
|
|
133
|
-
// src/
|
|
134
|
-
import {
|
|
133
|
+
// src/lint.ts
|
|
134
|
+
import { dirname as dirname2 } from "node:path";
|
|
135
135
|
|
|
136
|
-
// ../core/dist/
|
|
136
|
+
// ../core/dist/index.js
|
|
137
137
|
import { createRequire as createRequire2 } from "node:module";
|
|
138
138
|
import { readFile } from "node:fs/promises";
|
|
139
139
|
import { readFileSync } from "node:fs";
|
|
140
140
|
import { constants } from "node:fs";
|
|
141
141
|
import { access } from "node:fs/promises";
|
|
142
142
|
import { resolve } from "node:path";
|
|
143
|
+
import { writeFile } from "node:fs/promises";
|
|
144
|
+
import { join } from "node:path";
|
|
145
|
+
import { appendFile, readFile as readFile2, writeFile as writeFile2 } from "node:fs/promises";
|
|
146
|
+
import { join as join2 } from "node:path";
|
|
147
|
+
import { join as join3 } from "node:path";
|
|
143
148
|
import { spawn } from "node:child_process";
|
|
144
149
|
import { dirname, resolve as resolve2 } from "node:path";
|
|
145
150
|
import { resolve as resolvePath, isAbsolute } from "node:path";
|
|
146
|
-
import { dirname as dirname2, resolve as resolve3 } from "node:path";
|
|
147
|
-
import { env } from "node:process";
|
|
148
151
|
var __create = Object.create;
|
|
149
152
|
var __getProtoOf = Object.getPrototypeOf;
|
|
150
153
|
var __defProp2 = Object.defineProperty;
|
|
@@ -21520,20 +21523,20 @@ var require_compile = __commonJS((exports) => {
|
|
|
21520
21523
|
var validate_1 = require_validate();
|
|
21521
21524
|
|
|
21522
21525
|
class SchemaEnv {
|
|
21523
|
-
constructor(
|
|
21526
|
+
constructor(env) {
|
|
21524
21527
|
var _a;
|
|
21525
21528
|
this.refs = {};
|
|
21526
21529
|
this.dynamicAnchors = {};
|
|
21527
21530
|
let schema;
|
|
21528
|
-
if (typeof
|
|
21529
|
-
schema =
|
|
21530
|
-
this.schema =
|
|
21531
|
-
this.schemaId =
|
|
21532
|
-
this.root =
|
|
21533
|
-
this.baseId = (_a =
|
|
21534
|
-
this.schemaPath =
|
|
21535
|
-
this.localRefs =
|
|
21536
|
-
this.meta =
|
|
21531
|
+
if (typeof env.schema == "object")
|
|
21532
|
+
schema = env.schema;
|
|
21533
|
+
this.schema = env.schema;
|
|
21534
|
+
this.schemaId = env.schemaId;
|
|
21535
|
+
this.root = env.root || this;
|
|
21536
|
+
this.baseId = (_a = env.baseId) !== null && _a !== undefined ? _a : (0, resolve_1.normalizeId)(schema === null || schema === undefined ? undefined : schema[env.schemaId || "$id"]);
|
|
21537
|
+
this.schemaPath = env.schemaPath;
|
|
21538
|
+
this.localRefs = env.localRefs;
|
|
21539
|
+
this.meta = env.meta;
|
|
21537
21540
|
this.$async = schema === null || schema === undefined ? undefined : schema.$async;
|
|
21538
21541
|
this.refs = {};
|
|
21539
21542
|
}
|
|
@@ -21630,7 +21633,7 @@ var require_compile = __commonJS((exports) => {
|
|
|
21630
21633
|
const schOrFunc = root2.refs[ref];
|
|
21631
21634
|
if (schOrFunc)
|
|
21632
21635
|
return schOrFunc;
|
|
21633
|
-
let _sch =
|
|
21636
|
+
let _sch = resolve3.call(this, root2, ref);
|
|
21634
21637
|
if (_sch === undefined) {
|
|
21635
21638
|
const schema = (_a = root2.localRefs) === null || _a === undefined ? undefined : _a[ref];
|
|
21636
21639
|
const { schemaId } = this.opts;
|
|
@@ -21657,7 +21660,7 @@ var require_compile = __commonJS((exports) => {
|
|
|
21657
21660
|
function sameSchemaEnv(s1, s2) {
|
|
21658
21661
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
21659
21662
|
}
|
|
21660
|
-
function
|
|
21663
|
+
function resolve3(root2, ref) {
|
|
21661
21664
|
let sch;
|
|
21662
21665
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
21663
21666
|
ref = sch;
|
|
@@ -21716,15 +21719,15 @@ var require_compile = __commonJS((exports) => {
|
|
|
21716
21719
|
baseId = (0, resolve_1.resolveUrl)(this.opts.uriResolver, baseId, schId);
|
|
21717
21720
|
}
|
|
21718
21721
|
}
|
|
21719
|
-
let
|
|
21722
|
+
let env;
|
|
21720
21723
|
if (typeof schema != "boolean" && schema.$ref && !(0, util_1.schemaHasRulesButRef)(schema, this.RULES)) {
|
|
21721
21724
|
const $ref = (0, resolve_1.resolveUrl)(this.opts.uriResolver, baseId, schema.$ref);
|
|
21722
|
-
|
|
21725
|
+
env = resolveSchema.call(this, root2, $ref);
|
|
21723
21726
|
}
|
|
21724
21727
|
const { schemaId } = this.opts;
|
|
21725
|
-
|
|
21726
|
-
if (
|
|
21727
|
-
return
|
|
21728
|
+
env = env || new SchemaEnv({ schema, schemaId, root: root2, baseId });
|
|
21729
|
+
if (env.schema !== env.root.schema)
|
|
21730
|
+
return env;
|
|
21728
21731
|
return;
|
|
21729
21732
|
}
|
|
21730
21733
|
});
|
|
@@ -22179,7 +22182,7 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
22179
22182
|
}
|
|
22180
22183
|
return uri;
|
|
22181
22184
|
}
|
|
22182
|
-
function
|
|
22185
|
+
function resolve3(baseURI, relativeURI, options) {
|
|
22183
22186
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
22184
22187
|
const resolved = resolveComponent(parse2(baseURI, schemelessOptions), parse2(relativeURI, schemelessOptions), schemelessOptions, true);
|
|
22185
22188
|
schemelessOptions.skipEscape = true;
|
|
@@ -22407,7 +22410,7 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
22407
22410
|
var fastUri = {
|
|
22408
22411
|
SCHEMES,
|
|
22409
22412
|
normalize,
|
|
22410
|
-
resolve:
|
|
22413
|
+
resolve: resolve3,
|
|
22411
22414
|
resolveComponent,
|
|
22412
22415
|
equal,
|
|
22413
22416
|
serialize,
|
|
@@ -23038,8 +23041,8 @@ var require_ref = __commonJS((exports) => {
|
|
|
23038
23041
|
schemaType: "string",
|
|
23039
23042
|
code(cxt) {
|
|
23040
23043
|
const { gen, schema: $ref, it } = cxt;
|
|
23041
|
-
const { baseId, schemaEnv:
|
|
23042
|
-
const { root: root2 } =
|
|
23044
|
+
const { baseId, schemaEnv: env, validateName, opts, self: self2 } = it;
|
|
23045
|
+
const { root: root2 } = env;
|
|
23043
23046
|
if (($ref === "#" || $ref === "#/") && baseId === root2.baseId)
|
|
23044
23047
|
return callRootRef();
|
|
23045
23048
|
const schOrEnv = compile_1.resolveRef.call(self2, root2, baseId, $ref);
|
|
@@ -23049,8 +23052,8 @@ var require_ref = __commonJS((exports) => {
|
|
|
23049
23052
|
return callValidate(schOrEnv);
|
|
23050
23053
|
return inlineRefSchema(schOrEnv);
|
|
23051
23054
|
function callRootRef() {
|
|
23052
|
-
if (
|
|
23053
|
-
return callRef(cxt, validateName,
|
|
23055
|
+
if (env === root2)
|
|
23056
|
+
return callRef(cxt, validateName, env, env.$async);
|
|
23054
23057
|
const rootName = gen.scopeValue("root", { ref: root2 });
|
|
23055
23058
|
return callRef(cxt, (0, codegen_1._)`${rootName}.validate`, root2, root2.$async);
|
|
23056
23059
|
}
|
|
@@ -23080,14 +23083,14 @@ var require_ref = __commonJS((exports) => {
|
|
|
23080
23083
|
exports.getValidate = getValidate;
|
|
23081
23084
|
function callRef(cxt, v, sch, $async) {
|
|
23082
23085
|
const { gen, it } = cxt;
|
|
23083
|
-
const { allErrors, schemaEnv:
|
|
23086
|
+
const { allErrors, schemaEnv: env, opts } = it;
|
|
23084
23087
|
const passCxt = opts.passContext ? names_1.default.this : codegen_1.nil;
|
|
23085
23088
|
if ($async)
|
|
23086
23089
|
callAsyncRef();
|
|
23087
23090
|
else
|
|
23088
23091
|
callSyncRef();
|
|
23089
23092
|
function callAsyncRef() {
|
|
23090
|
-
if (!
|
|
23093
|
+
if (!env.$async)
|
|
23091
23094
|
throw new Error("async schema referenced by sync schema");
|
|
23092
23095
|
const valid = gen.let("valid");
|
|
23093
23096
|
gen.try(() => {
|
|
@@ -26219,6 +26222,234 @@ var init_validate = __esm2(() => {
|
|
|
26219
26222
|
RESERVED_NAMES = new Set(["workflow", "execution", "input", "output", "env", "loop", "event"]);
|
|
26220
26223
|
BUILTIN_ONERROR = new Set(["fail", "skip", "retry"]);
|
|
26221
26224
|
});
|
|
26225
|
+
var exports_json = {};
|
|
26226
|
+
__export2(exports_json, {
|
|
26227
|
+
JsonTraceWriter: () => JsonTraceWriter
|
|
26228
|
+
});
|
|
26229
|
+
|
|
26230
|
+
class JsonTraceWriter {
|
|
26231
|
+
dir;
|
|
26232
|
+
filePath = "";
|
|
26233
|
+
trace = {
|
|
26234
|
+
execution: {
|
|
26235
|
+
id: "",
|
|
26236
|
+
startedAt: "",
|
|
26237
|
+
finishedAt: "",
|
|
26238
|
+
duration: 0,
|
|
26239
|
+
status: "running",
|
|
26240
|
+
inputs: null,
|
|
26241
|
+
output: null
|
|
26242
|
+
},
|
|
26243
|
+
steps: []
|
|
26244
|
+
};
|
|
26245
|
+
constructor(dir) {
|
|
26246
|
+
this.dir = dir;
|
|
26247
|
+
}
|
|
26248
|
+
async open(meta) {
|
|
26249
|
+
this.filePath = join(this.dir, `${meta.id}.json`);
|
|
26250
|
+
this.trace = {
|
|
26251
|
+
execution: {
|
|
26252
|
+
id: meta.id,
|
|
26253
|
+
workflowId: meta.workflowId,
|
|
26254
|
+
workflowName: meta.workflowName,
|
|
26255
|
+
workflowVersion: meta.workflowVersion,
|
|
26256
|
+
startedAt: meta.startedAt,
|
|
26257
|
+
finishedAt: "",
|
|
26258
|
+
duration: 0,
|
|
26259
|
+
status: "running",
|
|
26260
|
+
inputs: meta.inputs,
|
|
26261
|
+
output: null
|
|
26262
|
+
},
|
|
26263
|
+
steps: []
|
|
26264
|
+
};
|
|
26265
|
+
await this.flush();
|
|
26266
|
+
}
|
|
26267
|
+
writeStep(step) {
|
|
26268
|
+
this.trace.steps.push(step);
|
|
26269
|
+
this.flushSync();
|
|
26270
|
+
}
|
|
26271
|
+
async finalize(meta) {
|
|
26272
|
+
this.trace.execution.status = meta.status;
|
|
26273
|
+
this.trace.execution.output = meta.output;
|
|
26274
|
+
this.trace.execution.finishedAt = meta.finishedAt;
|
|
26275
|
+
this.trace.execution.duration = meta.duration;
|
|
26276
|
+
await this.flush();
|
|
26277
|
+
}
|
|
26278
|
+
flushSync() {
|
|
26279
|
+
this.flush().catch(() => {});
|
|
26280
|
+
}
|
|
26281
|
+
async flush() {
|
|
26282
|
+
if (!this.filePath)
|
|
26283
|
+
return;
|
|
26284
|
+
await writeFile(this.filePath, JSON.stringify(this.trace, null, 2), "utf-8");
|
|
26285
|
+
}
|
|
26286
|
+
}
|
|
26287
|
+
var exports_txt = {};
|
|
26288
|
+
__export2(exports_txt, {
|
|
26289
|
+
TxtTraceWriter: () => TxtTraceWriter
|
|
26290
|
+
});
|
|
26291
|
+
function serializeValue(value) {
|
|
26292
|
+
if (value === undefined || value === null)
|
|
26293
|
+
return "none";
|
|
26294
|
+
if (typeof value === "string")
|
|
26295
|
+
return value;
|
|
26296
|
+
return JSON.stringify(value, null, 2);
|
|
26297
|
+
}
|
|
26298
|
+
function formatStep(step) {
|
|
26299
|
+
const lines = [
|
|
26300
|
+
`## [${step.seq}] ${step.name} (${step.type})`,
|
|
26301
|
+
`startedAt: ${step.startedAt}`
|
|
26302
|
+
];
|
|
26303
|
+
if (step.finishedAt)
|
|
26304
|
+
lines.push(`finishedAt: ${step.finishedAt}`);
|
|
26305
|
+
if (step.duration !== undefined)
|
|
26306
|
+
lines.push(`duration: ${step.duration}ms`);
|
|
26307
|
+
lines.push(`status: ${step.status}`);
|
|
26308
|
+
if (step.loopIndex !== undefined)
|
|
26309
|
+
lines.push(`loopIndex: ${step.loopIndex}`);
|
|
26310
|
+
if (step.retries !== undefined && step.retries > 0)
|
|
26311
|
+
lines.push(`retries: ${step.retries}`);
|
|
26312
|
+
lines.push(`input: ${serializeValue(step.input)}`);
|
|
26313
|
+
lines.push(`output: ${serializeValue(step.output)}`);
|
|
26314
|
+
if (step.error)
|
|
26315
|
+
lines.push(`error: ${step.error}`);
|
|
26316
|
+
lines.push("");
|
|
26317
|
+
return lines.join(`
|
|
26318
|
+
`);
|
|
26319
|
+
}
|
|
26320
|
+
|
|
26321
|
+
class TxtTraceWriter {
|
|
26322
|
+
dir;
|
|
26323
|
+
filePath = "";
|
|
26324
|
+
constructor(dir) {
|
|
26325
|
+
this.dir = dir;
|
|
26326
|
+
}
|
|
26327
|
+
async open(meta) {
|
|
26328
|
+
this.filePath = join2(this.dir, `${meta.id}.txt`);
|
|
26329
|
+
const versionStr = meta.workflowVersion !== undefined ? ` (v${meta.workflowVersion})` : "";
|
|
26330
|
+
const workflowLabel = meta.workflowName ?? meta.workflowId ?? "unnamed";
|
|
26331
|
+
const header = [
|
|
26332
|
+
"# execution",
|
|
26333
|
+
`id: ${meta.id}`,
|
|
26334
|
+
`workflow: ${workflowLabel}${versionStr}`,
|
|
26335
|
+
`startedAt: ${meta.startedAt}`,
|
|
26336
|
+
"status: running",
|
|
26337
|
+
"",
|
|
26338
|
+
"# inputs",
|
|
26339
|
+
serializeValue(meta.inputs),
|
|
26340
|
+
"",
|
|
26341
|
+
"# steps",
|
|
26342
|
+
""
|
|
26343
|
+
].join(`
|
|
26344
|
+
`);
|
|
26345
|
+
await writeFile2(this.filePath, header, "utf-8");
|
|
26346
|
+
}
|
|
26347
|
+
async writeStep(step) {
|
|
26348
|
+
if (!this.filePath)
|
|
26349
|
+
return;
|
|
26350
|
+
await appendFile(this.filePath, formatStep(step), "utf-8");
|
|
26351
|
+
}
|
|
26352
|
+
async finalize(meta) {
|
|
26353
|
+
if (!this.filePath)
|
|
26354
|
+
return;
|
|
26355
|
+
const outputSection = [
|
|
26356
|
+
"# output",
|
|
26357
|
+
serializeValue(meta.output),
|
|
26358
|
+
""
|
|
26359
|
+
].join(`
|
|
26360
|
+
`);
|
|
26361
|
+
await appendFile(this.filePath, outputSection, "utf-8");
|
|
26362
|
+
const content = await readFile2(this.filePath, "utf-8");
|
|
26363
|
+
const updated = content.replace(/^status: running$/m, `status: ${meta.status}
|
|
26364
|
+
finishedAt: ${meta.finishedAt}
|
|
26365
|
+
duration: ${meta.duration}ms`);
|
|
26366
|
+
await writeFile2(this.filePath, updated, "utf-8");
|
|
26367
|
+
}
|
|
26368
|
+
}
|
|
26369
|
+
var exports_sqlite = {};
|
|
26370
|
+
__export2(exports_sqlite, {
|
|
26371
|
+
SqliteTraceWriter: () => SqliteTraceWriter
|
|
26372
|
+
});
|
|
26373
|
+
function toJson(value) {
|
|
26374
|
+
if (value === undefined || value === null)
|
|
26375
|
+
return null;
|
|
26376
|
+
if (typeof value === "string")
|
|
26377
|
+
return value;
|
|
26378
|
+
return JSON.stringify(value);
|
|
26379
|
+
}
|
|
26380
|
+
|
|
26381
|
+
class SqliteTraceWriter {
|
|
26382
|
+
dir;
|
|
26383
|
+
db = null;
|
|
26384
|
+
executionId = "";
|
|
26385
|
+
constructor(dir) {
|
|
26386
|
+
this.dir = dir;
|
|
26387
|
+
}
|
|
26388
|
+
async open(meta) {
|
|
26389
|
+
this.executionId = meta.id;
|
|
26390
|
+
const filePath = join3(this.dir, `${meta.id}.sqlite`);
|
|
26391
|
+
const { Database } = await import("bun:sqlite");
|
|
26392
|
+
this.db = new Database(filePath);
|
|
26393
|
+
this.db.exec(`
|
|
26394
|
+
CREATE TABLE IF NOT EXISTS executions (
|
|
26395
|
+
id TEXT PRIMARY KEY,
|
|
26396
|
+
workflow_id TEXT,
|
|
26397
|
+
workflow_name TEXT,
|
|
26398
|
+
workflow_version TEXT,
|
|
26399
|
+
started_at TEXT NOT NULL,
|
|
26400
|
+
finished_at TEXT,
|
|
26401
|
+
duration_ms INTEGER,
|
|
26402
|
+
status TEXT NOT NULL,
|
|
26403
|
+
inputs TEXT,
|
|
26404
|
+
output TEXT
|
|
26405
|
+
);
|
|
26406
|
+
|
|
26407
|
+
CREATE TABLE IF NOT EXISTS steps (
|
|
26408
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
26409
|
+
execution_id TEXT NOT NULL REFERENCES executions(id),
|
|
26410
|
+
seq INTEGER NOT NULL,
|
|
26411
|
+
name TEXT NOT NULL,
|
|
26412
|
+
type TEXT NOT NULL,
|
|
26413
|
+
started_at TEXT,
|
|
26414
|
+
finished_at TEXT,
|
|
26415
|
+
duration_ms INTEGER,
|
|
26416
|
+
status TEXT NOT NULL,
|
|
26417
|
+
input TEXT,
|
|
26418
|
+
output TEXT,
|
|
26419
|
+
error TEXT,
|
|
26420
|
+
retries INTEGER,
|
|
26421
|
+
loop_index INTEGER
|
|
26422
|
+
);
|
|
26423
|
+
`);
|
|
26424
|
+
const insert = this.db.prepare(`
|
|
26425
|
+
INSERT INTO executions (id, workflow_id, workflow_name, workflow_version, started_at, status, inputs)
|
|
26426
|
+
VALUES (?, ?, ?, ?, ?, 'running', ?)
|
|
26427
|
+
`);
|
|
26428
|
+
insert.run(meta.id, meta.workflowId ?? null, meta.workflowName ?? null, meta.workflowVersion !== undefined ? String(meta.workflowVersion) : null, meta.startedAt, toJson(meta.inputs));
|
|
26429
|
+
}
|
|
26430
|
+
writeStep(step) {
|
|
26431
|
+
if (!this.db)
|
|
26432
|
+
return;
|
|
26433
|
+
const insert = this.db.prepare(`
|
|
26434
|
+
INSERT INTO steps
|
|
26435
|
+
(execution_id, seq, name, type, started_at, finished_at, duration_ms, status, input, output, error, retries, loop_index)
|
|
26436
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
26437
|
+
`);
|
|
26438
|
+
insert.run(this.executionId, step.seq, step.name, step.type, step.startedAt ?? null, step.finishedAt ?? null, step.duration ?? null, step.status, toJson(step.input), toJson(step.output), step.error ?? null, step.retries ?? null, step.loopIndex ?? null);
|
|
26439
|
+
}
|
|
26440
|
+
async finalize(meta) {
|
|
26441
|
+
if (!this.db)
|
|
26442
|
+
return;
|
|
26443
|
+
const update = this.db.prepare(`
|
|
26444
|
+
UPDATE executions
|
|
26445
|
+
SET status = ?, output = ?, finished_at = ?, duration_ms = ?
|
|
26446
|
+
WHERE id = ?
|
|
26447
|
+
`);
|
|
26448
|
+
update.run(meta.status, toJson(meta.output), meta.finishedAt, Math.round(meta.duration), this.executionId);
|
|
26449
|
+
this.db.close();
|
|
26450
|
+
this.db = null;
|
|
26451
|
+
}
|
|
26452
|
+
}
|
|
26222
26453
|
function sleep(ms) {
|
|
26223
26454
|
return new Promise((resolve22) => setTimeout(resolve22, ms));
|
|
26224
26455
|
}
|
|
@@ -26345,13 +26576,13 @@ function isMap3(value) {
|
|
|
26345
26576
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
26346
26577
|
}
|
|
26347
26578
|
function mapToEnvVars(input) {
|
|
26348
|
-
const
|
|
26579
|
+
const env = {};
|
|
26349
26580
|
for (const [key, value] of Object.entries(input)) {
|
|
26350
|
-
|
|
26581
|
+
env[key] = typeof value === "string" ? value : String(value);
|
|
26351
26582
|
}
|
|
26352
|
-
return
|
|
26583
|
+
return env;
|
|
26353
26584
|
}
|
|
26354
|
-
async function executeExec(participant, input,
|
|
26585
|
+
async function executeExec(participant, input, env = {}, signal) {
|
|
26355
26586
|
const command = participant.run ?? "";
|
|
26356
26587
|
const participantEnv = participant.env ?? {};
|
|
26357
26588
|
const cwd = participant.cwd ?? process.cwd();
|
|
@@ -26362,7 +26593,7 @@ async function executeExec(participant, input, env2 = {}, signal) {
|
|
|
26362
26593
|
return new Promise((resolve22) => {
|
|
26363
26594
|
try {
|
|
26364
26595
|
const proc = spawn("sh", ["-c", command], {
|
|
26365
|
-
env: { ...process.env, ...
|
|
26596
|
+
env: { ...process.env, ...env, ...participantEnv, ...inputEnvVars },
|
|
26366
26597
|
cwd,
|
|
26367
26598
|
stdio: ["pipe", "pipe", "pipe"]
|
|
26368
26599
|
});
|
|
@@ -26510,7 +26741,7 @@ async function executeHttp(participant, input) {
|
|
|
26510
26741
|
};
|
|
26511
26742
|
}
|
|
26512
26743
|
async function executeMcp(participant, _input) {
|
|
26513
|
-
throw new Error(`mcp participant is not yet implemented (server: ${participant.server ?? "unspecified"}, tool: ${participant.tool ?? "unspecified"}).
|
|
26744
|
+
throw new Error(`mcp participant is not yet implemented (server: ${participant.server ?? "unspecified"}, tool: ${participant.tool ?? "unspecified"}). Use onError to handle this gracefully.`);
|
|
26514
26745
|
}
|
|
26515
26746
|
function toWorkflowInputs(input) {
|
|
26516
26747
|
if (input && typeof input === "object" && !Array.isArray(input)) {
|
|
@@ -26555,12 +26786,12 @@ var init_workflow = __esm2(() => {
|
|
|
26555
26786
|
init_schema();
|
|
26556
26787
|
init_validate();
|
|
26557
26788
|
});
|
|
26558
|
-
async function executeParticipant(participant, input,
|
|
26789
|
+
async function executeParticipant(participant, input, env = {}, basePath, engineExecutor, hub, celContext, ancestorPaths) {
|
|
26559
26790
|
const executor = executors[participant.type];
|
|
26560
26791
|
if (!executor) {
|
|
26561
26792
|
throw new Error(`participant type '${participant.type}' is not yet implemented`);
|
|
26562
26793
|
}
|
|
26563
|
-
return executor(participant, input,
|
|
26794
|
+
return executor(participant, input, env, basePath, engineExecutor, hub, celContext, ancestorPaths);
|
|
26564
26795
|
}
|
|
26565
26796
|
var executors;
|
|
26566
26797
|
var init_participant = __esm2(() => {
|
|
@@ -26568,7 +26799,7 @@ var init_participant = __esm2(() => {
|
|
|
26568
26799
|
init_exec();
|
|
26569
26800
|
init_workflow();
|
|
26570
26801
|
executors = {
|
|
26571
|
-
exec: async (participant, input,
|
|
26802
|
+
exec: async (participant, input, env) => executeExec(participant, input, env),
|
|
26572
26803
|
http: async (participant, input) => executeHttp(participant, input),
|
|
26573
26804
|
workflow: async (participant, input, _env, basePath, engineExecutor, _hub, _celContext, ancestorPaths) => {
|
|
26574
26805
|
if (!basePath) {
|
|
@@ -26796,6 +27027,10 @@ async function executeStep(workflow, state, step, basePath = process.cwd(), engi
|
|
|
26796
27027
|
output: "",
|
|
26797
27028
|
duration: 0
|
|
26798
27029
|
});
|
|
27030
|
+
const loopIndex2 = state.isInsideLoop() ? state.currentLoopIndex() : undefined;
|
|
27031
|
+
const skippedSeq = state.tracer?.startStep(stepName, participant.type, undefined, loopIndex2);
|
|
27032
|
+
if (skippedSeq !== undefined)
|
|
27033
|
+
state.tracer?.endStep(skippedSeq, "skipped");
|
|
26799
27034
|
}
|
|
26800
27035
|
return chain;
|
|
26801
27036
|
}
|
|
@@ -26804,6 +27039,8 @@ async function executeStep(workflow, state, step, basePath = process.cwd(), engi
|
|
|
26804
27039
|
const overrideInput = override?.input !== undefined ? resolveParticipantInput(override.input, state) : undefined;
|
|
26805
27040
|
const mergedWithBase = mergeChainedInput(chain, baseInput);
|
|
26806
27041
|
const mergedInput = mergeChainedInput(mergedWithBase, overrideInput);
|
|
27042
|
+
const loopIndex = state.isInsideLoop() ? state.currentLoopIndex() : undefined;
|
|
27043
|
+
const traceSeq = state.tracer?.startStep(stepName ?? "<anonymous>", participant.type, mergedInput, loopIndex);
|
|
26807
27044
|
state.currentInput = mergedInput;
|
|
26808
27045
|
const strategy = resolveErrorStrategy(override ?? null, participant, workflow.defaults ?? null);
|
|
26809
27046
|
const timeoutMs = resolveTimeout(override ?? null, participant, workflow.defaults ?? null);
|
|
@@ -26881,6 +27118,8 @@ async function executeStep(workflow, state, step, basePath = process.cwd(), engi
|
|
|
26881
27118
|
}
|
|
26882
27119
|
const outputValue = result.parsedOutput ?? result.output;
|
|
26883
27120
|
state.currentOutput = outputValue;
|
|
27121
|
+
if (traceSeq !== undefined)
|
|
27122
|
+
state.tracer?.endStep(traceSeq, result.status, outputValue, undefined, retries);
|
|
26884
27123
|
return outputValue;
|
|
26885
27124
|
} catch (error) {
|
|
26886
27125
|
const message = String(error?.message ?? error);
|
|
@@ -26906,6 +27145,8 @@ async function executeStep(workflow, state, step, basePath = process.cwd(), engi
|
|
|
26906
27145
|
if (stepName) {
|
|
26907
27146
|
state.setResult(stepName, skipResult);
|
|
26908
27147
|
}
|
|
27148
|
+
if (traceSeq !== undefined)
|
|
27149
|
+
state.tracer?.endStep(traceSeq, "skipped", undefined, message);
|
|
26909
27150
|
return chain;
|
|
26910
27151
|
}
|
|
26911
27152
|
if (strategy !== "fail" && strategy !== "retry") {
|
|
@@ -26924,6 +27165,8 @@ async function executeStep(workflow, state, step, basePath = process.cwd(), engi
|
|
|
26924
27165
|
...httpMeta
|
|
26925
27166
|
});
|
|
26926
27167
|
}
|
|
27168
|
+
if (traceSeq !== undefined)
|
|
27169
|
+
state.tracer?.endStep(traceSeq, "failure", undefined, message);
|
|
26927
27170
|
const fallbackResult = await executeStep(workflow, state, fallbackName, basePath, engineExecutor, [...fallbackStack, stepName ?? "<anonymous>"], chain, hub);
|
|
26928
27171
|
return fallbackResult;
|
|
26929
27172
|
}
|
|
@@ -26938,6 +27181,8 @@ async function executeStep(workflow, state, step, basePath = process.cwd(), engi
|
|
|
26938
27181
|
...httpMeta
|
|
26939
27182
|
});
|
|
26940
27183
|
}
|
|
27184
|
+
if (traceSeq !== undefined)
|
|
27185
|
+
state.tracer?.endStep(traceSeq, "failure", undefined, message);
|
|
26941
27186
|
throw error;
|
|
26942
27187
|
}
|
|
26943
27188
|
}
|
|
@@ -26960,7 +27205,7 @@ __export2(exports_wait, {
|
|
|
26960
27205
|
executeWait: () => executeWait
|
|
26961
27206
|
});
|
|
26962
27207
|
function sleep2(ms) {
|
|
26963
|
-
return new Promise((
|
|
27208
|
+
return new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
26964
27209
|
}
|
|
26965
27210
|
async function executeWait(state, waitDef, chain, hub, signal) {
|
|
26966
27211
|
const timeoutMs = waitDef.timeout ? parseDuration(waitDef.timeout) : undefined;
|
|
@@ -27046,21 +27291,38 @@ async function executeControlStep(workflow, state, step, basePath = process.cwd(
|
|
|
27046
27291
|
}
|
|
27047
27292
|
const obj = step;
|
|
27048
27293
|
if ("wait" in obj && Object.keys(obj).length === 1) {
|
|
27049
|
-
const
|
|
27050
|
-
|
|
27294
|
+
const loopIndex = state.isInsideLoop() ? state.currentLoopIndex() : undefined;
|
|
27295
|
+
const traceSeq = state.tracer?.startStep("wait", "wait", undefined, loopIndex);
|
|
27296
|
+
try {
|
|
27297
|
+
const { executeWait: executeWait2 } = await Promise.resolve().then(() => (init_wait(), exports_wait));
|
|
27298
|
+
const result = await executeWait2(state, obj.wait, chain, hub, signal);
|
|
27299
|
+
if (traceSeq !== undefined)
|
|
27300
|
+
state.tracer?.endStep(traceSeq, "success", result);
|
|
27301
|
+
return result;
|
|
27302
|
+
} catch (err) {
|
|
27303
|
+
if (traceSeq !== undefined)
|
|
27304
|
+
state.tracer?.endStep(traceSeq, "failure", undefined, String(err?.message ?? err));
|
|
27305
|
+
throw err;
|
|
27306
|
+
}
|
|
27051
27307
|
}
|
|
27052
27308
|
if ("set" in obj && Object.keys(obj).length === 1) {
|
|
27053
27309
|
const setDef = obj.set;
|
|
27054
27310
|
const ctx = state.toCelContext();
|
|
27311
|
+
const loopIndex = state.isInsideLoop() ? state.currentLoopIndex() : undefined;
|
|
27312
|
+
const traceSeq = state.tracer?.startStep("set", "set", setDef, loopIndex);
|
|
27055
27313
|
if (!state.executionMeta.context) {
|
|
27056
27314
|
state.executionMeta.context = {};
|
|
27057
27315
|
}
|
|
27058
27316
|
for (const [key, expr] of Object.entries(setDef)) {
|
|
27059
27317
|
if (RESERVED_SET_KEYS.has(key)) {
|
|
27318
|
+
if (traceSeq !== undefined)
|
|
27319
|
+
state.tracer?.endStep(traceSeq, "failure", undefined, `set key '${key}' uses a reserved name`);
|
|
27060
27320
|
throw new Error(`set key '${key}' uses a reserved name`);
|
|
27061
27321
|
}
|
|
27062
27322
|
state.executionMeta.context[key] = evaluateCel(expr, ctx);
|
|
27063
27323
|
}
|
|
27324
|
+
if (traceSeq !== undefined)
|
|
27325
|
+
state.tracer?.endStep(traceSeq, "success", state.executionMeta.context);
|
|
27064
27326
|
return chain;
|
|
27065
27327
|
}
|
|
27066
27328
|
if ("loop" in obj && Object.keys(obj).length === 1) {
|
|
@@ -27077,6 +27339,8 @@ async function executeControlStep(workflow, state, step, basePath = process.cwd(
|
|
|
27077
27339
|
maxIterations = loopDef.max ?? Number.POSITIVE_INFINITY;
|
|
27078
27340
|
}
|
|
27079
27341
|
const hasMax = loopDef.max !== undefined;
|
|
27342
|
+
const outerLoopIndex = state.isInsideLoop() ? state.currentLoopIndex() : undefined;
|
|
27343
|
+
const loopTraceSeq = state.tracer?.startStep(loopAs ?? "loop", "loop", undefined, outerLoopIndex);
|
|
27080
27344
|
state.pushLoop(loopAs);
|
|
27081
27345
|
let loopChain = chain;
|
|
27082
27346
|
try {
|
|
@@ -27100,6 +27364,12 @@ async function executeControlStep(workflow, state, step, basePath = process.cwd(
|
|
|
27100
27364
|
iterations += 1;
|
|
27101
27365
|
state.incrementLoop();
|
|
27102
27366
|
}
|
|
27367
|
+
if (loopTraceSeq !== undefined)
|
|
27368
|
+
state.tracer?.endStep(loopTraceSeq, "success", loopChain);
|
|
27369
|
+
} catch (err) {
|
|
27370
|
+
if (loopTraceSeq !== undefined)
|
|
27371
|
+
state.tracer?.endStep(loopTraceSeq, "failure", undefined, String(err?.message ?? err));
|
|
27372
|
+
throw err;
|
|
27103
27373
|
} finally {
|
|
27104
27374
|
state.popLoop();
|
|
27105
27375
|
}
|
|
@@ -27108,29 +27378,54 @@ async function executeControlStep(workflow, state, step, basePath = process.cwd(
|
|
|
27108
27378
|
if ("parallel" in obj && Object.keys(obj).length === 1) {
|
|
27109
27379
|
const parallelSteps = obj.parallel;
|
|
27110
27380
|
const controller = new AbortController;
|
|
27381
|
+
const loopIndex = state.isInsideLoop() ? state.currentLoopIndex() : undefined;
|
|
27382
|
+
const parallelTraceSeq = state.tracer?.startStep("parallel", "parallel", undefined, loopIndex);
|
|
27111
27383
|
const branchSignal = signal ? AbortSignal.any([signal, controller.signal]) : controller.signal;
|
|
27112
|
-
|
|
27113
|
-
|
|
27114
|
-
|
|
27115
|
-
|
|
27116
|
-
|
|
27117
|
-
|
|
27118
|
-
|
|
27119
|
-
|
|
27120
|
-
|
|
27384
|
+
try {
|
|
27385
|
+
const results = await Promise.all(parallelSteps.map(async (parallelStep) => {
|
|
27386
|
+
try {
|
|
27387
|
+
return await executeControlStep(workflow, state, parallelStep, basePath, engineExecutor, chain, hub, branchSignal);
|
|
27388
|
+
} catch (error) {
|
|
27389
|
+
controller.abort();
|
|
27390
|
+
throw error;
|
|
27391
|
+
}
|
|
27392
|
+
}));
|
|
27393
|
+
if (parallelTraceSeq !== undefined)
|
|
27394
|
+
state.tracer?.endStep(parallelTraceSeq, "success", results);
|
|
27395
|
+
return results;
|
|
27396
|
+
} catch (err) {
|
|
27397
|
+
if (parallelTraceSeq !== undefined)
|
|
27398
|
+
state.tracer?.endStep(parallelTraceSeq, "failure", undefined, String(err?.message ?? err));
|
|
27399
|
+
throw err;
|
|
27400
|
+
}
|
|
27121
27401
|
}
|
|
27122
27402
|
if ("if" in obj && Object.keys(obj).length === 1) {
|
|
27123
27403
|
const ifDef = obj.if;
|
|
27124
27404
|
const condition = evaluateCel(ifDef.condition, state.toCelContext());
|
|
27405
|
+
const loopIndex = state.isInsideLoop() ? state.currentLoopIndex() : undefined;
|
|
27406
|
+
const ifTraceSeq = state.tracer?.startStep("if", "if", { condition: ifDef.condition }, loopIndex);
|
|
27125
27407
|
if (typeof condition !== "boolean") {
|
|
27408
|
+
if (ifTraceSeq !== undefined)
|
|
27409
|
+
state.tracer?.endStep(ifTraceSeq, "failure", undefined, `if.condition must evaluate to boolean, got ${typeof condition}`);
|
|
27126
27410
|
throw new Error(`if.condition must evaluate to boolean, got ${typeof condition}`);
|
|
27127
27411
|
}
|
|
27128
|
-
|
|
27129
|
-
|
|
27130
|
-
|
|
27131
|
-
|
|
27412
|
+
try {
|
|
27413
|
+
let result;
|
|
27414
|
+
if (condition) {
|
|
27415
|
+
result = await executeSequential(workflow, state, ifDef.then, basePath, engineExecutor, chain, hub, signal);
|
|
27416
|
+
} else if (ifDef.else) {
|
|
27417
|
+
result = await executeSequential(workflow, state, ifDef.else, basePath, engineExecutor, chain, hub, signal);
|
|
27418
|
+
} else {
|
|
27419
|
+
result = chain;
|
|
27420
|
+
}
|
|
27421
|
+
if (ifTraceSeq !== undefined)
|
|
27422
|
+
state.tracer?.endStep(ifTraceSeq, "success", result);
|
|
27423
|
+
return result;
|
|
27424
|
+
} catch (err) {
|
|
27425
|
+
if (ifTraceSeq !== undefined)
|
|
27426
|
+
state.tracer?.endStep(ifTraceSeq, "failure", undefined, String(err?.message ?? err));
|
|
27427
|
+
throw err;
|
|
27132
27428
|
}
|
|
27133
|
-
return chain;
|
|
27134
27429
|
}
|
|
27135
27430
|
return executeStep(workflow, state, step, basePath, engineExecutor, [], chain, hub, signal);
|
|
27136
27431
|
}
|
|
@@ -27140,7 +27435,92 @@ var init_control = __esm2(() => {
|
|
|
27140
27435
|
init_sequential();
|
|
27141
27436
|
RESERVED_SET_KEYS = new Set(["workflow", "execution", "input", "output", "env", "loop", "event"]);
|
|
27142
27437
|
});
|
|
27143
|
-
|
|
27438
|
+
|
|
27439
|
+
class MemoryHub {
|
|
27440
|
+
listeners = new Map;
|
|
27441
|
+
buffer = new Map;
|
|
27442
|
+
closed = false;
|
|
27443
|
+
async publish(event, payload) {
|
|
27444
|
+
if (this.closed)
|
|
27445
|
+
throw new Error("hub is closed");
|
|
27446
|
+
const envelope = { name: event, payload };
|
|
27447
|
+
let buf = this.buffer.get(event);
|
|
27448
|
+
if (!buf) {
|
|
27449
|
+
buf = [];
|
|
27450
|
+
this.buffer.set(event, buf);
|
|
27451
|
+
}
|
|
27452
|
+
buf.push(envelope);
|
|
27453
|
+
const listeners = this.listeners.get(event);
|
|
27454
|
+
if (listeners) {
|
|
27455
|
+
for (const listener of listeners) {
|
|
27456
|
+
listener(envelope);
|
|
27457
|
+
}
|
|
27458
|
+
}
|
|
27459
|
+
}
|
|
27460
|
+
async publishAndWaitAck(event, payload, _timeoutMs) {
|
|
27461
|
+
await this.publish(event, payload);
|
|
27462
|
+
}
|
|
27463
|
+
async* subscribe(event, signal) {
|
|
27464
|
+
if (this.closed)
|
|
27465
|
+
return;
|
|
27466
|
+
const buffered = this.buffer.get(event);
|
|
27467
|
+
if (buffered) {
|
|
27468
|
+
for (const envelope of buffered) {
|
|
27469
|
+
if (signal?.aborted)
|
|
27470
|
+
return;
|
|
27471
|
+
yield envelope;
|
|
27472
|
+
}
|
|
27473
|
+
}
|
|
27474
|
+
const queue = [];
|
|
27475
|
+
let resolve3 = null;
|
|
27476
|
+
const listener = (envelope) => {
|
|
27477
|
+
queue.push(envelope);
|
|
27478
|
+
if (resolve3) {
|
|
27479
|
+
resolve3();
|
|
27480
|
+
resolve3 = null;
|
|
27481
|
+
}
|
|
27482
|
+
};
|
|
27483
|
+
let listeners = this.listeners.get(event);
|
|
27484
|
+
if (!listeners) {
|
|
27485
|
+
listeners = new Set;
|
|
27486
|
+
this.listeners.set(event, listeners);
|
|
27487
|
+
}
|
|
27488
|
+
listeners.add(listener);
|
|
27489
|
+
const onAbort = () => {
|
|
27490
|
+
listeners.delete(listener);
|
|
27491
|
+
if (resolve3) {
|
|
27492
|
+
resolve3();
|
|
27493
|
+
resolve3 = null;
|
|
27494
|
+
}
|
|
27495
|
+
};
|
|
27496
|
+
if (signal) {
|
|
27497
|
+
signal.addEventListener("abort", onAbort);
|
|
27498
|
+
}
|
|
27499
|
+
try {
|
|
27500
|
+
while (!this.closed && !signal?.aborted) {
|
|
27501
|
+
if (queue.length > 0) {
|
|
27502
|
+
yield queue.shift();
|
|
27503
|
+
} else {
|
|
27504
|
+
await new Promise((r) => {
|
|
27505
|
+
resolve3 = r;
|
|
27506
|
+
});
|
|
27507
|
+
}
|
|
27508
|
+
}
|
|
27509
|
+
} finally {
|
|
27510
|
+
listeners.delete(listener);
|
|
27511
|
+
if (signal) {
|
|
27512
|
+
signal.removeEventListener("abort", onAbort);
|
|
27513
|
+
}
|
|
27514
|
+
}
|
|
27515
|
+
}
|
|
27516
|
+
async close() {
|
|
27517
|
+
this.closed = true;
|
|
27518
|
+
for (const listeners of this.listeners.values()) {
|
|
27519
|
+
listeners.clear();
|
|
27520
|
+
}
|
|
27521
|
+
this.listeners.clear();
|
|
27522
|
+
}
|
|
27523
|
+
}
|
|
27144
27524
|
init_parser3();
|
|
27145
27525
|
init_schema();
|
|
27146
27526
|
init_validate();
|
|
@@ -27304,357 +27684,220 @@ function validateInputs(inputDefs, provided) {
|
|
|
27304
27684
|
resolved
|
|
27305
27685
|
};
|
|
27306
27686
|
}
|
|
27307
|
-
|
|
27687
|
+
init_cel();
|
|
27688
|
+
init_cel();
|
|
27689
|
+
init_parser3();
|
|
27690
|
+
init_schema();
|
|
27691
|
+
init_validate();
|
|
27308
27692
|
|
|
27309
|
-
class
|
|
27310
|
-
|
|
27311
|
-
|
|
27312
|
-
|
|
27313
|
-
|
|
27314
|
-
|
|
27315
|
-
|
|
27316
|
-
|
|
27317
|
-
|
|
27318
|
-
|
|
27319
|
-
|
|
27320
|
-
|
|
27321
|
-
|
|
27322
|
-
this.inputs = { ...inputs };
|
|
27323
|
-
this.workflowInputs = { ...inputs };
|
|
27324
|
-
this.workflowMeta = {};
|
|
27325
|
-
this.executionMeta = {
|
|
27326
|
-
id: crypto.randomUUID(),
|
|
27693
|
+
class TraceCollector {
|
|
27694
|
+
openSteps = new Map;
|
|
27695
|
+
seq = 0;
|
|
27696
|
+
truncateAt;
|
|
27697
|
+
writer;
|
|
27698
|
+
constructor(truncateAt = 1e6) {
|
|
27699
|
+
this.truncateAt = truncateAt;
|
|
27700
|
+
}
|
|
27701
|
+
startStep(name, type3, input, loopIndex) {
|
|
27702
|
+
this.seq += 1;
|
|
27703
|
+
this.openSteps.set(this.seq, {
|
|
27704
|
+
name,
|
|
27705
|
+
type: type3,
|
|
27327
27706
|
startedAt: new Date().toISOString(),
|
|
27328
|
-
|
|
27329
|
-
|
|
27330
|
-
|
|
27331
|
-
this.currentInput = undefined;
|
|
27332
|
-
this.currentOutput = undefined;
|
|
27333
|
-
this.chainValue = undefined;
|
|
27334
|
-
this.eventPayload = undefined;
|
|
27335
|
-
this.ancestorPaths = new Set;
|
|
27336
|
-
this.results = new Map;
|
|
27337
|
-
this.loopStack = [];
|
|
27338
|
-
}
|
|
27339
|
-
setResult(stepName, result) {
|
|
27340
|
-
this.results.set(stepName, result);
|
|
27341
|
-
}
|
|
27342
|
-
getResult(stepName) {
|
|
27343
|
-
return this.results.get(stepName);
|
|
27344
|
-
}
|
|
27345
|
-
getAllResults() {
|
|
27346
|
-
const out = {};
|
|
27347
|
-
for (const [k, v] of this.results.entries())
|
|
27348
|
-
out[k] = v;
|
|
27349
|
-
return out;
|
|
27350
|
-
}
|
|
27351
|
-
pushLoop(as) {
|
|
27352
|
-
this.loopStack.push({ index: 0, as });
|
|
27353
|
-
}
|
|
27354
|
-
incrementLoop() {
|
|
27355
|
-
const top = this.loopStack[this.loopStack.length - 1];
|
|
27356
|
-
if (top)
|
|
27357
|
-
top.index += 1;
|
|
27358
|
-
}
|
|
27359
|
-
popLoop() {
|
|
27360
|
-
this.loopStack.pop();
|
|
27361
|
-
}
|
|
27362
|
-
currentLoopIndex() {
|
|
27363
|
-
const top = this.loopStack[this.loopStack.length - 1];
|
|
27364
|
-
return top ? top.index : 0;
|
|
27365
|
-
}
|
|
27366
|
-
setLoopLast(last2) {
|
|
27367
|
-
const top = this.loopStack[this.loopStack.length - 1];
|
|
27368
|
-
if (top)
|
|
27369
|
-
top.last = last2;
|
|
27370
|
-
}
|
|
27371
|
-
currentLoopContext() {
|
|
27372
|
-
const top = this.loopStack[this.loopStack.length - 1];
|
|
27373
|
-
if (!top)
|
|
27374
|
-
return { index: 0, iteration: 1, first: true, last: false };
|
|
27375
|
-
return {
|
|
27376
|
-
index: top.index,
|
|
27377
|
-
iteration: top.index + 1,
|
|
27378
|
-
first: top.index === 0,
|
|
27379
|
-
last: top.last ?? false,
|
|
27380
|
-
as: top.as
|
|
27381
|
-
};
|
|
27382
|
-
}
|
|
27383
|
-
toCelContext() {
|
|
27384
|
-
const ctx = {};
|
|
27385
|
-
for (const [name, res] of this.results.entries()) {
|
|
27386
|
-
ctx[name] = {
|
|
27387
|
-
output: res.parsedOutput ?? res.output,
|
|
27388
|
-
status: res.status,
|
|
27389
|
-
startedAt: res.startedAt,
|
|
27390
|
-
finishedAt: res.finishedAt,
|
|
27391
|
-
duration: res.duration,
|
|
27392
|
-
retries: res.retries ?? 0,
|
|
27393
|
-
error: res.error,
|
|
27394
|
-
cwd: res.cwd
|
|
27395
|
-
};
|
|
27396
|
-
}
|
|
27397
|
-
ctx["workflow"] = {
|
|
27398
|
-
id: this.workflowMeta.id,
|
|
27399
|
-
name: this.workflowMeta.name,
|
|
27400
|
-
version: this.workflowMeta.version,
|
|
27401
|
-
inputs: this.workflowInputs,
|
|
27402
|
-
output: null
|
|
27403
|
-
};
|
|
27404
|
-
ctx["execution"] = { ...this.executionMeta };
|
|
27405
|
-
ctx["input"] = this.currentInput ?? {};
|
|
27406
|
-
ctx["output"] = this.currentOutput ?? {};
|
|
27407
|
-
ctx["env"] = { ...env };
|
|
27408
|
-
const loopCtx = this.currentLoopContext();
|
|
27409
|
-
const loopObj = {
|
|
27410
|
-
index: loopCtx.index,
|
|
27411
|
-
iteration: loopCtx.iteration,
|
|
27412
|
-
first: loopCtx.first,
|
|
27413
|
-
last: loopCtx.last
|
|
27414
|
-
};
|
|
27415
|
-
if (loopCtx.as) {
|
|
27416
|
-
ctx[`_${loopCtx.as}`] = loopObj;
|
|
27417
|
-
}
|
|
27418
|
-
ctx["_loop"] = loopObj;
|
|
27419
|
-
ctx["loop"] = loopObj;
|
|
27420
|
-
ctx["event"] = this.eventPayload ?? {};
|
|
27421
|
-
ctx["now"] = Math.floor(Date.now() / 1000);
|
|
27422
|
-
return ctx;
|
|
27423
|
-
}
|
|
27424
|
-
resolveOutput(outputDef, celEvaluator) {
|
|
27425
|
-
const ctx = this.toCelContext();
|
|
27426
|
-
if (typeof outputDef === "object" && "map" in outputDef && "schema" in outputDef) {
|
|
27427
|
-
const result2 = {};
|
|
27428
|
-
for (const [k, expr] of Object.entries(outputDef.map)) {
|
|
27429
|
-
result2[k] = celEvaluator(expr, ctx);
|
|
27430
|
-
}
|
|
27431
|
-
return result2;
|
|
27432
|
-
}
|
|
27433
|
-
if (typeof outputDef === "string") {
|
|
27434
|
-
return celEvaluator(outputDef, ctx);
|
|
27435
|
-
}
|
|
27436
|
-
const result = {};
|
|
27437
|
-
for (const k of Object.keys(outputDef)) {
|
|
27438
|
-
const expr = outputDef[k];
|
|
27439
|
-
result[k] = celEvaluator(expr, ctx);
|
|
27440
|
-
}
|
|
27441
|
-
return result;
|
|
27442
|
-
}
|
|
27443
|
-
}
|
|
27444
|
-
async function executeWorkflow(workflow, inputs = {}, basePath = process.cwd(), options = {}) {
|
|
27445
|
-
const { result: inputResult, resolved } = validateInputs(workflow.inputs, inputs);
|
|
27446
|
-
if (!inputResult.valid) {
|
|
27447
|
-
throw new Error(`input validation failed: ${JSON.stringify(inputResult.errors)}`);
|
|
27448
|
-
}
|
|
27449
|
-
const state = new WorkflowState(resolved);
|
|
27450
|
-
state.workflowMeta = {
|
|
27451
|
-
id: workflow.id,
|
|
27452
|
-
name: workflow.name,
|
|
27453
|
-
version: workflow.version
|
|
27454
|
-
};
|
|
27455
|
-
state.executionMeta.number = options.executionNumber ?? 1;
|
|
27456
|
-
if (options.cwd) {
|
|
27457
|
-
state.executionMeta.cwd = options.cwd;
|
|
27458
|
-
}
|
|
27459
|
-
const startedAt = performance.now();
|
|
27460
|
-
if (options._ancestorPaths) {
|
|
27461
|
-
state.ancestorPaths = options._ancestorPaths;
|
|
27462
|
-
}
|
|
27463
|
-
const engineExecutor = async (subWorkflow, subInputs, subBasePath) => {
|
|
27464
|
-
return executeWorkflow(subWorkflow, subInputs, subBasePath, {
|
|
27465
|
-
...options,
|
|
27466
|
-
_ancestorPaths: state.ancestorPaths
|
|
27707
|
+
startMs: performance.now(),
|
|
27708
|
+
input: input !== undefined ? this.truncate(input) : undefined,
|
|
27709
|
+
loopIndex
|
|
27467
27710
|
});
|
|
27468
|
-
|
|
27469
|
-
let chain;
|
|
27470
|
-
for (const step of workflow.flow) {
|
|
27471
|
-
chain = await executeControlStep(workflow, state, step, basePath, engineExecutor, chain, options.hub);
|
|
27711
|
+
return this.seq;
|
|
27472
27712
|
}
|
|
27473
|
-
|
|
27474
|
-
|
|
27475
|
-
|
|
27476
|
-
|
|
27477
|
-
|
|
27478
|
-
|
|
27479
|
-
|
|
27480
|
-
|
|
27481
|
-
|
|
27482
|
-
|
|
27483
|
-
|
|
27484
|
-
|
|
27485
|
-
|
|
27486
|
-
|
|
27487
|
-
|
|
27488
|
-
|
|
27489
|
-
|
|
27490
|
-
|
|
27491
|
-
}
|
|
27492
|
-
|
|
27493
|
-
|
|
27494
|
-
|
|
27495
|
-
if (!schemaValidation.valid) {
|
|
27496
|
-
throw new Error(`schema validation failed: ${JSON.stringify(schemaValidation.errors)}`);
|
|
27713
|
+
endStep(seq, status, output, error, retries) {
|
|
27714
|
+
const open = this.openSteps.get(seq);
|
|
27715
|
+
if (!open)
|
|
27716
|
+
return;
|
|
27717
|
+
this.openSteps.delete(seq);
|
|
27718
|
+
const finishedAt = new Date().toISOString();
|
|
27719
|
+
const duration = Math.max(0, performance.now() - open.startMs);
|
|
27720
|
+
const step = {
|
|
27721
|
+
seq,
|
|
27722
|
+
name: open.name,
|
|
27723
|
+
type: open.type,
|
|
27724
|
+
startedAt: open.startedAt,
|
|
27725
|
+
finishedAt,
|
|
27726
|
+
duration: Math.round(duration),
|
|
27727
|
+
status,
|
|
27728
|
+
...open.input !== undefined ? { input: open.input } : {},
|
|
27729
|
+
...output !== undefined ? { output: this.truncate(output) } : {},
|
|
27730
|
+
...error !== undefined ? { error } : {},
|
|
27731
|
+
...retries !== undefined && retries > 0 ? { retries } : {},
|
|
27732
|
+
...open.loopIndex !== undefined ? { loopIndex: open.loopIndex } : {}
|
|
27733
|
+
};
|
|
27734
|
+
this.writer?.writeStep(step);
|
|
27497
27735
|
}
|
|
27498
|
-
|
|
27499
|
-
|
|
27500
|
-
|
|
27501
|
-
|
|
27736
|
+
truncate(value) {
|
|
27737
|
+
if (value == null)
|
|
27738
|
+
return value;
|
|
27739
|
+
const str = typeof value === "string" ? value : JSON.stringify(value);
|
|
27740
|
+
const bytes = new TextEncoder().encode(str);
|
|
27741
|
+
if (bytes.length <= this.truncateAt)
|
|
27742
|
+
return value;
|
|
27743
|
+
const cut = new TextDecoder().decode(bytes.slice(0, this.truncateAt));
|
|
27744
|
+
return cut + "...[truncated]";
|
|
27502
27745
|
}
|
|
27503
|
-
return executeWorkflow(workflow, inputs, workflowBasePath, options);
|
|
27504
27746
|
}
|
|
27505
27747
|
init_control();
|
|
27506
27748
|
init_sequential();
|
|
27507
|
-
init_errors();
|
|
27508
|
-
init_timeout();
|
|
27509
27749
|
init_wait();
|
|
27750
|
+
init_emit();
|
|
27510
27751
|
|
|
27511
|
-
// src/
|
|
27512
|
-
|
|
27513
|
-
const
|
|
27514
|
-
|
|
27515
|
-
|
|
27516
|
-
|
|
27517
|
-
|
|
27518
|
-
|
|
27519
|
-
|
|
27520
|
-
|
|
27521
|
-
|
|
27522
|
-
|
|
27752
|
+
// src/lint.ts
|
|
27753
|
+
function collectLintWarnings(workflow) {
|
|
27754
|
+
const warnings = [];
|
|
27755
|
+
const participants = workflow.participants ?? {};
|
|
27756
|
+
collectFlowWarnings(workflow.flow ?? [], participants, warnings);
|
|
27757
|
+
return warnings;
|
|
27758
|
+
}
|
|
27759
|
+
function collectFlowWarnings(flow, participants, warnings, basePath = "flow") {
|
|
27760
|
+
for (const [index, step] of flow.entries()) {
|
|
27761
|
+
const stepPath = `${basePath}[${index}]`;
|
|
27762
|
+
if (!step || typeof step !== "object")
|
|
27763
|
+
continue;
|
|
27764
|
+
const obj = step;
|
|
27765
|
+
if (obj.loop && Object.keys(obj).length === 1) {
|
|
27766
|
+
const loopDef = obj.loop;
|
|
27767
|
+
if (loopDef.until == null && loopDef.max == null) {
|
|
27768
|
+
warnings.push({
|
|
27769
|
+
path: `${stepPath}.loop`,
|
|
27770
|
+
message: "loop has no 'until' and no 'max' — this will be rejected at runtime"
|
|
27771
|
+
});
|
|
27772
|
+
}
|
|
27773
|
+
collectFlowWarnings(loopDef.steps ?? [], participants, warnings, `${stepPath}.loop.steps`);
|
|
27774
|
+
continue;
|
|
27523
27775
|
}
|
|
27524
|
-
|
|
27525
|
-
|
|
27526
|
-
const
|
|
27527
|
-
|
|
27528
|
-
|
|
27529
|
-
|
|
27530
|
-
|
|
27531
|
-
|
|
27776
|
+
if (obj.parallel && Object.keys(obj).length === 1) {
|
|
27777
|
+
const parallelSteps = obj.parallel;
|
|
27778
|
+
const branchSetKeys = new Map;
|
|
27779
|
+
for (const [branchIdx, branch] of parallelSteps.entries()) {
|
|
27780
|
+
const setKeys = collectSetKeys(branch);
|
|
27781
|
+
for (const key of setKeys) {
|
|
27782
|
+
const branches = branchSetKeys.get(key) ?? [];
|
|
27783
|
+
branches.push(branchIdx);
|
|
27784
|
+
branchSetKeys.set(key, branches);
|
|
27785
|
+
}
|
|
27532
27786
|
}
|
|
27533
|
-
|
|
27787
|
+
for (const [key, branches] of branchSetKeys) {
|
|
27788
|
+
if (branches.length > 1) {
|
|
27789
|
+
warnings.push({
|
|
27790
|
+
path: `${stepPath}.parallel`,
|
|
27791
|
+
message: `branches [${branches.join(", ")}] both write to '${key}' via set — race condition risk`
|
|
27792
|
+
});
|
|
27793
|
+
}
|
|
27794
|
+
}
|
|
27795
|
+
collectFlowWarnings(parallelSteps, participants, warnings, `${stepPath}.parallel`);
|
|
27796
|
+
continue;
|
|
27534
27797
|
}
|
|
27535
|
-
|
|
27536
|
-
|
|
27537
|
-
|
|
27538
|
-
|
|
27539
|
-
|
|
27540
|
-
|
|
27541
|
-
|
|
27542
|
-
|
|
27543
|
-
|
|
27544
|
-
|
|
27545
|
-
|
|
27798
|
+
if ("type" in obj && !obj.as) {
|
|
27799
|
+
warnings.push({
|
|
27800
|
+
path: stepPath,
|
|
27801
|
+
message: "inline participant without 'as' — its output cannot be referenced by name"
|
|
27802
|
+
});
|
|
27803
|
+
continue;
|
|
27804
|
+
}
|
|
27805
|
+
if (obj.if && Object.keys(obj).length === 1) {
|
|
27806
|
+
const ifDef = obj.if;
|
|
27807
|
+
collectFlowWarnings(ifDef.then ?? [], participants, warnings, `${stepPath}.if.then`);
|
|
27808
|
+
if (ifDef.else) {
|
|
27809
|
+
collectFlowWarnings(ifDef.else, participants, warnings, `${stepPath}.if.else`);
|
|
27546
27810
|
}
|
|
27547
|
-
throw err;
|
|
27548
27811
|
}
|
|
27549
27812
|
}
|
|
27550
|
-
console.error(`Error: unknown event backend "${backend}". Supported: memory, nats, redis`);
|
|
27551
|
-
throw new Error(`unknown event backend: ${backend}`);
|
|
27552
27813
|
}
|
|
27553
|
-
function
|
|
27554
|
-
|
|
27555
|
-
|
|
27556
|
-
|
|
27557
|
-
|
|
27558
|
-
|
|
27559
|
-
|
|
27560
|
-
|
|
27561
|
-
|
|
27562
|
-
|
|
27563
|
-
|
|
27564
|
-
|
|
27565
|
-
|
|
27566
|
-
|
|
27567
|
-
|
|
27814
|
+
function collectSetKeys(step) {
|
|
27815
|
+
if (!step || typeof step !== "object")
|
|
27816
|
+
return [];
|
|
27817
|
+
const obj = step;
|
|
27818
|
+
if ("set" in obj && Object.keys(obj).length === 1) {
|
|
27819
|
+
return Object.keys(obj.set);
|
|
27820
|
+
}
|
|
27821
|
+
const keys3 = [];
|
|
27822
|
+
if (obj.loop) {
|
|
27823
|
+
const loopDef = obj.loop;
|
|
27824
|
+
for (const s of loopDef.steps ?? []) {
|
|
27825
|
+
keys3.push(...collectSetKeys(s));
|
|
27826
|
+
}
|
|
27827
|
+
}
|
|
27828
|
+
if (obj.if) {
|
|
27829
|
+
const ifDef = obj.if;
|
|
27830
|
+
for (const s of ifDef.then ?? []) {
|
|
27831
|
+
keys3.push(...collectSetKeys(s));
|
|
27832
|
+
}
|
|
27833
|
+
if (ifDef.else) {
|
|
27834
|
+
for (const s of ifDef.else) {
|
|
27835
|
+
keys3.push(...collectSetKeys(s));
|
|
27568
27836
|
}
|
|
27569
27837
|
}
|
|
27570
27838
|
}
|
|
27571
|
-
return
|
|
27839
|
+
return keys3;
|
|
27572
27840
|
}
|
|
27573
|
-
async function
|
|
27841
|
+
async function lintCommand(filePath) {
|
|
27574
27842
|
if (!filePath) {
|
|
27575
|
-
console.error("Usage:
|
|
27843
|
+
console.error("Usage: quack lint <workflow.yaml>");
|
|
27576
27844
|
return 1;
|
|
27577
27845
|
}
|
|
27578
|
-
let inputs = {};
|
|
27579
27846
|
try {
|
|
27580
|
-
|
|
27581
|
-
|
|
27582
|
-
|
|
27583
|
-
|
|
27847
|
+
const workflow = await parseWorkflowFile(filePath);
|
|
27848
|
+
const schemaRes = validateSchema(workflow);
|
|
27849
|
+
if (!schemaRes.valid) {
|
|
27850
|
+
console.error("Schema validation failed:");
|
|
27851
|
+
for (const e of schemaRes.errors) {
|
|
27852
|
+
console.error(` - ${e.path}: ${e.message}`);
|
|
27584
27853
|
}
|
|
27585
|
-
|
|
27586
|
-
|
|
27587
|
-
|
|
27588
|
-
|
|
27589
|
-
|
|
27590
|
-
|
|
27591
|
-
|
|
27854
|
+
return 1;
|
|
27855
|
+
}
|
|
27856
|
+
const basePath = dirname2(filePath);
|
|
27857
|
+
const semanticRes = await validateSemantic(workflow, basePath);
|
|
27858
|
+
if (!semanticRes.valid) {
|
|
27859
|
+
console.error("Semantic validation failed:");
|
|
27860
|
+
for (const e of semanticRes.errors) {
|
|
27861
|
+
console.error(` - ${e.path}: ${e.message}`);
|
|
27592
27862
|
}
|
|
27863
|
+
return 1;
|
|
27593
27864
|
}
|
|
27594
|
-
|
|
27595
|
-
|
|
27596
|
-
|
|
27597
|
-
|
|
27598
|
-
|
|
27599
|
-
const parsed = JSON.parse(content);
|
|
27600
|
-
if (typeof parsed === "object" && parsed !== null)
|
|
27601
|
-
inputs = { ...inputs, ...parsed };
|
|
27602
|
-
} catch (err) {
|
|
27603
|
-
console.error("Failed to read input file:", err);
|
|
27604
|
-
return 1;
|
|
27865
|
+
const warnings = collectLintWarnings(workflow);
|
|
27866
|
+
if (warnings.length > 0) {
|
|
27867
|
+
console.warn("Warnings:");
|
|
27868
|
+
for (const w of warnings) {
|
|
27869
|
+
console.warn(` - ${w.path}: ${w.message}`);
|
|
27605
27870
|
}
|
|
27606
27871
|
}
|
|
27607
|
-
|
|
27608
|
-
|
|
27609
|
-
inputs = { ...inputs, ...parseInputFlags(parsed) };
|
|
27610
|
-
}
|
|
27611
|
-
}
|
|
27612
|
-
let hub;
|
|
27613
|
-
try {
|
|
27614
|
-
hub = await createHubFromFlags(cliValues);
|
|
27615
|
-
} catch {
|
|
27616
|
-
return 1;
|
|
27617
|
-
}
|
|
27618
|
-
const options = {
|
|
27619
|
-
hub,
|
|
27620
|
-
cwd: cliValues?.cwd,
|
|
27621
|
-
verbose: cliValues?.verbose,
|
|
27622
|
-
quiet: cliValues?.quiet
|
|
27623
|
-
};
|
|
27624
|
-
try {
|
|
27625
|
-
const res = await runWorkflowFromFile(filePath, inputs, options);
|
|
27626
|
-
const output = res.output;
|
|
27627
|
-
if (output === undefined || output === null) {} else if (typeof output === "string") {
|
|
27628
|
-
process.stdout.write(output);
|
|
27629
|
-
} else {
|
|
27630
|
-
console.log(JSON.stringify(output, null, 2));
|
|
27631
|
-
}
|
|
27632
|
-
return res.success ? 0 : 2;
|
|
27872
|
+
console.log("valid");
|
|
27873
|
+
return 0;
|
|
27633
27874
|
} catch (err) {
|
|
27634
|
-
|
|
27635
|
-
console.error("Error:", msg);
|
|
27636
|
-
if (cliValues?.verbose && err instanceof Error && err.stack) {
|
|
27637
|
-
console.error(err.stack);
|
|
27638
|
-
}
|
|
27875
|
+
console.error("Error during lint:", err && err.message ? err.message : err);
|
|
27639
27876
|
return 1;
|
|
27640
|
-
} finally {
|
|
27641
|
-
await hub?.close();
|
|
27642
27877
|
}
|
|
27643
27878
|
}
|
|
27644
27879
|
|
|
27645
|
-
// src/
|
|
27646
|
-
import {
|
|
27880
|
+
// src/run.ts
|
|
27881
|
+
import { readFile as readFile5 } from "node:fs/promises";
|
|
27647
27882
|
|
|
27648
|
-
// ../core/dist/index.js
|
|
27883
|
+
// ../core/dist/engine/index.js
|
|
27649
27884
|
import { createRequire as createRequire3 } from "node:module";
|
|
27650
27885
|
import { readFile as readFile3 } from "node:fs/promises";
|
|
27651
27886
|
import { readFileSync as readFileSync2 } from "node:fs";
|
|
27652
27887
|
import { constants as constants2 } from "node:fs";
|
|
27653
27888
|
import { access as access2 } from "node:fs/promises";
|
|
27654
|
-
import { resolve as
|
|
27889
|
+
import { resolve as resolve3 } from "node:path";
|
|
27890
|
+
import { writeFile as writeFile3 } from "node:fs/promises";
|
|
27891
|
+
import { join as join4 } from "node:path";
|
|
27892
|
+
import { appendFile as appendFile2, readFile as readFile22, writeFile as writeFile22 } from "node:fs/promises";
|
|
27893
|
+
import { join as join22 } from "node:path";
|
|
27894
|
+
import { join as join32 } from "node:path";
|
|
27655
27895
|
import { spawn as spawn2 } from "node:child_process";
|
|
27656
27896
|
import { dirname as dirname3, resolve as resolve22 } from "node:path";
|
|
27657
27897
|
import { resolve as resolvePath2, isAbsolute as isAbsolute2 } from "node:path";
|
|
27898
|
+
import { dirname as dirname22, resolve as resolve32 } from "node:path";
|
|
27899
|
+
import { mkdir } from "node:fs/promises";
|
|
27900
|
+
import { env } from "node:process";
|
|
27658
27901
|
var __create2 = Object.create;
|
|
27659
27902
|
var __getProtoOf2 = Object.getPrototypeOf;
|
|
27660
27903
|
var __defProp3 = Object.defineProperty;
|
|
@@ -49140,7 +49383,7 @@ var require_compile2 = __commonJS2((exports) => {
|
|
|
49140
49383
|
const schOrFunc = root22.refs[ref];
|
|
49141
49384
|
if (schOrFunc)
|
|
49142
49385
|
return schOrFunc;
|
|
49143
|
-
let _sch =
|
|
49386
|
+
let _sch = resolve4.call(this, root22, ref);
|
|
49144
49387
|
if (_sch === undefined) {
|
|
49145
49388
|
const schema2 = (_a = root22.localRefs) === null || _a === undefined ? undefined : _a[ref];
|
|
49146
49389
|
const { schemaId } = this.opts;
|
|
@@ -49167,7 +49410,7 @@ var require_compile2 = __commonJS2((exports) => {
|
|
|
49167
49410
|
function sameSchemaEnv(s1, s2) {
|
|
49168
49411
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
49169
49412
|
}
|
|
49170
|
-
function
|
|
49413
|
+
function resolve4(root22, ref) {
|
|
49171
49414
|
let sch;
|
|
49172
49415
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
49173
49416
|
ref = sch;
|
|
@@ -49689,7 +49932,7 @@ var require_fast_uri2 = __commonJS2((exports, module) => {
|
|
|
49689
49932
|
}
|
|
49690
49933
|
return uri;
|
|
49691
49934
|
}
|
|
49692
|
-
function
|
|
49935
|
+
function resolve4(baseURI, relativeURI, options) {
|
|
49693
49936
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
49694
49937
|
const resolved = resolveComponent(parse22(baseURI, schemelessOptions), parse22(relativeURI, schemelessOptions), schemelessOptions, true);
|
|
49695
49938
|
schemelessOptions.skipEscape = true;
|
|
@@ -49917,7 +50160,7 @@ var require_fast_uri2 = __commonJS2((exports, module) => {
|
|
|
49917
50160
|
var fastUri = {
|
|
49918
50161
|
SCHEMES,
|
|
49919
50162
|
normalize,
|
|
49920
|
-
resolve:
|
|
50163
|
+
resolve: resolve4,
|
|
49921
50164
|
resolveComponent,
|
|
49922
50165
|
equal,
|
|
49923
50166
|
serialize,
|
|
@@ -53711,7 +53954,7 @@ async function validateSemantic2(workflow, basePath) {
|
|
|
53711
53954
|
for (const [name, participant] of Object.entries(participants)) {
|
|
53712
53955
|
if (participant.type !== "workflow")
|
|
53713
53956
|
continue;
|
|
53714
|
-
const resolvedPath =
|
|
53957
|
+
const resolvedPath = resolve3(basePath, participant.path);
|
|
53715
53958
|
const exists = await access2(resolvedPath, constants2.F_OK).then(() => true, () => false);
|
|
53716
53959
|
if (!exists) {
|
|
53717
53960
|
errors.push({
|
|
@@ -53729,6 +53972,237 @@ var init_validate2 = __esm3(() => {
|
|
|
53729
53972
|
RESERVED_NAMES2 = new Set(["workflow", "execution", "input", "output", "env", "loop", "event"]);
|
|
53730
53973
|
BUILTIN_ONERROR2 = new Set(["fail", "skip", "retry"]);
|
|
53731
53974
|
});
|
|
53975
|
+
var exports_json2 = {};
|
|
53976
|
+
__export3(exports_json2, {
|
|
53977
|
+
JsonTraceWriter: () => JsonTraceWriter2
|
|
53978
|
+
});
|
|
53979
|
+
|
|
53980
|
+
class JsonTraceWriter2 {
|
|
53981
|
+
dir;
|
|
53982
|
+
filePath = "";
|
|
53983
|
+
trace = {
|
|
53984
|
+
execution: {
|
|
53985
|
+
id: "",
|
|
53986
|
+
startedAt: "",
|
|
53987
|
+
finishedAt: "",
|
|
53988
|
+
duration: 0,
|
|
53989
|
+
status: "running",
|
|
53990
|
+
inputs: null,
|
|
53991
|
+
output: null
|
|
53992
|
+
},
|
|
53993
|
+
steps: []
|
|
53994
|
+
};
|
|
53995
|
+
constructor(dir) {
|
|
53996
|
+
this.dir = dir;
|
|
53997
|
+
}
|
|
53998
|
+
async open(meta) {
|
|
53999
|
+
this.filePath = join4(this.dir, `${meta.id}.json`);
|
|
54000
|
+
this.trace = {
|
|
54001
|
+
execution: {
|
|
54002
|
+
id: meta.id,
|
|
54003
|
+
workflowId: meta.workflowId,
|
|
54004
|
+
workflowName: meta.workflowName,
|
|
54005
|
+
workflowVersion: meta.workflowVersion,
|
|
54006
|
+
startedAt: meta.startedAt,
|
|
54007
|
+
finishedAt: "",
|
|
54008
|
+
duration: 0,
|
|
54009
|
+
status: "running",
|
|
54010
|
+
inputs: meta.inputs,
|
|
54011
|
+
output: null
|
|
54012
|
+
},
|
|
54013
|
+
steps: []
|
|
54014
|
+
};
|
|
54015
|
+
await this.flush();
|
|
54016
|
+
}
|
|
54017
|
+
writeStep(step) {
|
|
54018
|
+
this.trace.steps.push(step);
|
|
54019
|
+
this.flushSync();
|
|
54020
|
+
}
|
|
54021
|
+
async finalize(meta) {
|
|
54022
|
+
this.trace.execution.status = meta.status;
|
|
54023
|
+
this.trace.execution.output = meta.output;
|
|
54024
|
+
this.trace.execution.finishedAt = meta.finishedAt;
|
|
54025
|
+
this.trace.execution.duration = meta.duration;
|
|
54026
|
+
await this.flush();
|
|
54027
|
+
}
|
|
54028
|
+
flushSync() {
|
|
54029
|
+
this.flush().catch(() => {});
|
|
54030
|
+
}
|
|
54031
|
+
async flush() {
|
|
54032
|
+
if (!this.filePath)
|
|
54033
|
+
return;
|
|
54034
|
+
await writeFile3(this.filePath, JSON.stringify(this.trace, null, 2), "utf-8");
|
|
54035
|
+
}
|
|
54036
|
+
}
|
|
54037
|
+
var init_json = () => {};
|
|
54038
|
+
var exports_txt2 = {};
|
|
54039
|
+
__export3(exports_txt2, {
|
|
54040
|
+
TxtTraceWriter: () => TxtTraceWriter2
|
|
54041
|
+
});
|
|
54042
|
+
function serializeValue2(value) {
|
|
54043
|
+
if (value === undefined || value === null)
|
|
54044
|
+
return "none";
|
|
54045
|
+
if (typeof value === "string")
|
|
54046
|
+
return value;
|
|
54047
|
+
return JSON.stringify(value, null, 2);
|
|
54048
|
+
}
|
|
54049
|
+
function formatStep2(step) {
|
|
54050
|
+
const lines = [
|
|
54051
|
+
`## [${step.seq}] ${step.name} (${step.type})`,
|
|
54052
|
+
`startedAt: ${step.startedAt}`
|
|
54053
|
+
];
|
|
54054
|
+
if (step.finishedAt)
|
|
54055
|
+
lines.push(`finishedAt: ${step.finishedAt}`);
|
|
54056
|
+
if (step.duration !== undefined)
|
|
54057
|
+
lines.push(`duration: ${step.duration}ms`);
|
|
54058
|
+
lines.push(`status: ${step.status}`);
|
|
54059
|
+
if (step.loopIndex !== undefined)
|
|
54060
|
+
lines.push(`loopIndex: ${step.loopIndex}`);
|
|
54061
|
+
if (step.retries !== undefined && step.retries > 0)
|
|
54062
|
+
lines.push(`retries: ${step.retries}`);
|
|
54063
|
+
lines.push(`input: ${serializeValue2(step.input)}`);
|
|
54064
|
+
lines.push(`output: ${serializeValue2(step.output)}`);
|
|
54065
|
+
if (step.error)
|
|
54066
|
+
lines.push(`error: ${step.error}`);
|
|
54067
|
+
lines.push("");
|
|
54068
|
+
return lines.join(`
|
|
54069
|
+
`);
|
|
54070
|
+
}
|
|
54071
|
+
|
|
54072
|
+
class TxtTraceWriter2 {
|
|
54073
|
+
dir;
|
|
54074
|
+
filePath = "";
|
|
54075
|
+
constructor(dir) {
|
|
54076
|
+
this.dir = dir;
|
|
54077
|
+
}
|
|
54078
|
+
async open(meta) {
|
|
54079
|
+
this.filePath = join22(this.dir, `${meta.id}.txt`);
|
|
54080
|
+
const versionStr = meta.workflowVersion !== undefined ? ` (v${meta.workflowVersion})` : "";
|
|
54081
|
+
const workflowLabel = meta.workflowName ?? meta.workflowId ?? "unnamed";
|
|
54082
|
+
const header = [
|
|
54083
|
+
"# execution",
|
|
54084
|
+
`id: ${meta.id}`,
|
|
54085
|
+
`workflow: ${workflowLabel}${versionStr}`,
|
|
54086
|
+
`startedAt: ${meta.startedAt}`,
|
|
54087
|
+
"status: running",
|
|
54088
|
+
"",
|
|
54089
|
+
"# inputs",
|
|
54090
|
+
serializeValue2(meta.inputs),
|
|
54091
|
+
"",
|
|
54092
|
+
"# steps",
|
|
54093
|
+
""
|
|
54094
|
+
].join(`
|
|
54095
|
+
`);
|
|
54096
|
+
await writeFile22(this.filePath, header, "utf-8");
|
|
54097
|
+
}
|
|
54098
|
+
async writeStep(step) {
|
|
54099
|
+
if (!this.filePath)
|
|
54100
|
+
return;
|
|
54101
|
+
await appendFile2(this.filePath, formatStep2(step), "utf-8");
|
|
54102
|
+
}
|
|
54103
|
+
async finalize(meta) {
|
|
54104
|
+
if (!this.filePath)
|
|
54105
|
+
return;
|
|
54106
|
+
const outputSection = [
|
|
54107
|
+
"# output",
|
|
54108
|
+
serializeValue2(meta.output),
|
|
54109
|
+
""
|
|
54110
|
+
].join(`
|
|
54111
|
+
`);
|
|
54112
|
+
await appendFile2(this.filePath, outputSection, "utf-8");
|
|
54113
|
+
const content = await readFile22(this.filePath, "utf-8");
|
|
54114
|
+
const updated = content.replace(/^status: running$/m, `status: ${meta.status}
|
|
54115
|
+
finishedAt: ${meta.finishedAt}
|
|
54116
|
+
duration: ${meta.duration}ms`);
|
|
54117
|
+
await writeFile22(this.filePath, updated, "utf-8");
|
|
54118
|
+
}
|
|
54119
|
+
}
|
|
54120
|
+
var init_txt = () => {};
|
|
54121
|
+
var exports_sqlite2 = {};
|
|
54122
|
+
__export3(exports_sqlite2, {
|
|
54123
|
+
SqliteTraceWriter: () => SqliteTraceWriter2
|
|
54124
|
+
});
|
|
54125
|
+
function toJson2(value) {
|
|
54126
|
+
if (value === undefined || value === null)
|
|
54127
|
+
return null;
|
|
54128
|
+
if (typeof value === "string")
|
|
54129
|
+
return value;
|
|
54130
|
+
return JSON.stringify(value);
|
|
54131
|
+
}
|
|
54132
|
+
|
|
54133
|
+
class SqliteTraceWriter2 {
|
|
54134
|
+
dir;
|
|
54135
|
+
db = null;
|
|
54136
|
+
executionId = "";
|
|
54137
|
+
constructor(dir) {
|
|
54138
|
+
this.dir = dir;
|
|
54139
|
+
}
|
|
54140
|
+
async open(meta) {
|
|
54141
|
+
this.executionId = meta.id;
|
|
54142
|
+
const filePath = join32(this.dir, `${meta.id}.sqlite`);
|
|
54143
|
+
const { Database } = await import("bun:sqlite");
|
|
54144
|
+
this.db = new Database(filePath);
|
|
54145
|
+
this.db.exec(`
|
|
54146
|
+
CREATE TABLE IF NOT EXISTS executions (
|
|
54147
|
+
id TEXT PRIMARY KEY,
|
|
54148
|
+
workflow_id TEXT,
|
|
54149
|
+
workflow_name TEXT,
|
|
54150
|
+
workflow_version TEXT,
|
|
54151
|
+
started_at TEXT NOT NULL,
|
|
54152
|
+
finished_at TEXT,
|
|
54153
|
+
duration_ms INTEGER,
|
|
54154
|
+
status TEXT NOT NULL,
|
|
54155
|
+
inputs TEXT,
|
|
54156
|
+
output TEXT
|
|
54157
|
+
);
|
|
54158
|
+
|
|
54159
|
+
CREATE TABLE IF NOT EXISTS steps (
|
|
54160
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
54161
|
+
execution_id TEXT NOT NULL REFERENCES executions(id),
|
|
54162
|
+
seq INTEGER NOT NULL,
|
|
54163
|
+
name TEXT NOT NULL,
|
|
54164
|
+
type TEXT NOT NULL,
|
|
54165
|
+
started_at TEXT,
|
|
54166
|
+
finished_at TEXT,
|
|
54167
|
+
duration_ms INTEGER,
|
|
54168
|
+
status TEXT NOT NULL,
|
|
54169
|
+
input TEXT,
|
|
54170
|
+
output TEXT,
|
|
54171
|
+
error TEXT,
|
|
54172
|
+
retries INTEGER,
|
|
54173
|
+
loop_index INTEGER
|
|
54174
|
+
);
|
|
54175
|
+
`);
|
|
54176
|
+
const insert = this.db.prepare(`
|
|
54177
|
+
INSERT INTO executions (id, workflow_id, workflow_name, workflow_version, started_at, status, inputs)
|
|
54178
|
+
VALUES (?, ?, ?, ?, ?, 'running', ?)
|
|
54179
|
+
`);
|
|
54180
|
+
insert.run(meta.id, meta.workflowId ?? null, meta.workflowName ?? null, meta.workflowVersion !== undefined ? String(meta.workflowVersion) : null, meta.startedAt, toJson2(meta.inputs));
|
|
54181
|
+
}
|
|
54182
|
+
writeStep(step) {
|
|
54183
|
+
if (!this.db)
|
|
54184
|
+
return;
|
|
54185
|
+
const insert = this.db.prepare(`
|
|
54186
|
+
INSERT INTO steps
|
|
54187
|
+
(execution_id, seq, name, type, started_at, finished_at, duration_ms, status, input, output, error, retries, loop_index)
|
|
54188
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
54189
|
+
`);
|
|
54190
|
+
insert.run(this.executionId, step.seq, step.name, step.type, step.startedAt ?? null, step.finishedAt ?? null, step.duration ?? null, step.status, toJson2(step.input), toJson2(step.output), step.error ?? null, step.retries ?? null, step.loopIndex ?? null);
|
|
54191
|
+
}
|
|
54192
|
+
async finalize(meta) {
|
|
54193
|
+
if (!this.db)
|
|
54194
|
+
return;
|
|
54195
|
+
const update = this.db.prepare(`
|
|
54196
|
+
UPDATE executions
|
|
54197
|
+
SET status = ?, output = ?, finished_at = ?, duration_ms = ?
|
|
54198
|
+
WHERE id = ?
|
|
54199
|
+
`);
|
|
54200
|
+
update.run(meta.status, toJson2(meta.output), meta.finishedAt, Math.round(meta.duration), this.executionId);
|
|
54201
|
+
this.db.close();
|
|
54202
|
+
this.db = null;
|
|
54203
|
+
}
|
|
54204
|
+
}
|
|
54205
|
+
var init_sqlite = () => {};
|
|
53732
54206
|
function sleep3(ms) {
|
|
53733
54207
|
return new Promise((resolve23) => setTimeout(resolve23, ms));
|
|
53734
54208
|
}
|
|
@@ -54020,7 +54494,7 @@ async function executeHttp2(participant, input) {
|
|
|
54020
54494
|
};
|
|
54021
54495
|
}
|
|
54022
54496
|
async function executeMcp2(participant, _input) {
|
|
54023
|
-
throw new Error(`mcp participant is not yet implemented (server: ${participant.server ?? "unspecified"}, tool: ${participant.tool ?? "unspecified"}).
|
|
54497
|
+
throw new Error(`mcp participant is not yet implemented (server: ${participant.server ?? "unspecified"}, tool: ${participant.tool ?? "unspecified"}). Use onError to handle this gracefully.`);
|
|
54024
54498
|
}
|
|
54025
54499
|
function toWorkflowInputs2(input) {
|
|
54026
54500
|
if (input && typeof input === "object" && !Array.isArray(input)) {
|
|
@@ -54306,6 +54780,10 @@ async function executeStep2(workflow, state, step, basePath = process.cwd(), eng
|
|
|
54306
54780
|
output: "",
|
|
54307
54781
|
duration: 0
|
|
54308
54782
|
});
|
|
54783
|
+
const loopIndex2 = state.isInsideLoop() ? state.currentLoopIndex() : undefined;
|
|
54784
|
+
const skippedSeq = state.tracer?.startStep(stepName, participant.type, undefined, loopIndex2);
|
|
54785
|
+
if (skippedSeq !== undefined)
|
|
54786
|
+
state.tracer?.endStep(skippedSeq, "skipped");
|
|
54309
54787
|
}
|
|
54310
54788
|
return chain;
|
|
54311
54789
|
}
|
|
@@ -54314,6 +54792,8 @@ async function executeStep2(workflow, state, step, basePath = process.cwd(), eng
|
|
|
54314
54792
|
const overrideInput = override?.input !== undefined ? resolveParticipantInput2(override.input, state) : undefined;
|
|
54315
54793
|
const mergedWithBase = mergeChainedInput2(chain, baseInput);
|
|
54316
54794
|
const mergedInput = mergeChainedInput2(mergedWithBase, overrideInput);
|
|
54795
|
+
const loopIndex = state.isInsideLoop() ? state.currentLoopIndex() : undefined;
|
|
54796
|
+
const traceSeq = state.tracer?.startStep(stepName ?? "<anonymous>", participant.type, mergedInput, loopIndex);
|
|
54317
54797
|
state.currentInput = mergedInput;
|
|
54318
54798
|
const strategy = resolveErrorStrategy2(override ?? null, participant, workflow.defaults ?? null);
|
|
54319
54799
|
const timeoutMs = resolveTimeout2(override ?? null, participant, workflow.defaults ?? null);
|
|
@@ -54391,6 +54871,8 @@ async function executeStep2(workflow, state, step, basePath = process.cwd(), eng
|
|
|
54391
54871
|
}
|
|
54392
54872
|
const outputValue = result.parsedOutput ?? result.output;
|
|
54393
54873
|
state.currentOutput = outputValue;
|
|
54874
|
+
if (traceSeq !== undefined)
|
|
54875
|
+
state.tracer?.endStep(traceSeq, result.status, outputValue, undefined, retries);
|
|
54394
54876
|
return outputValue;
|
|
54395
54877
|
} catch (error) {
|
|
54396
54878
|
const message = String(error?.message ?? error);
|
|
@@ -54416,6 +54898,8 @@ async function executeStep2(workflow, state, step, basePath = process.cwd(), eng
|
|
|
54416
54898
|
if (stepName) {
|
|
54417
54899
|
state.setResult(stepName, skipResult);
|
|
54418
54900
|
}
|
|
54901
|
+
if (traceSeq !== undefined)
|
|
54902
|
+
state.tracer?.endStep(traceSeq, "skipped", undefined, message);
|
|
54419
54903
|
return chain;
|
|
54420
54904
|
}
|
|
54421
54905
|
if (strategy !== "fail" && strategy !== "retry") {
|
|
@@ -54434,6 +54918,8 @@ async function executeStep2(workflow, state, step, basePath = process.cwd(), eng
|
|
|
54434
54918
|
...httpMeta
|
|
54435
54919
|
});
|
|
54436
54920
|
}
|
|
54921
|
+
if (traceSeq !== undefined)
|
|
54922
|
+
state.tracer?.endStep(traceSeq, "failure", undefined, message);
|
|
54437
54923
|
const fallbackResult = await executeStep2(workflow, state, fallbackName, basePath, engineExecutor, [...fallbackStack, stepName ?? "<anonymous>"], chain, hub);
|
|
54438
54924
|
return fallbackResult;
|
|
54439
54925
|
}
|
|
@@ -54448,6 +54934,8 @@ async function executeStep2(workflow, state, step, basePath = process.cwd(), eng
|
|
|
54448
54934
|
...httpMeta
|
|
54449
54935
|
});
|
|
54450
54936
|
}
|
|
54937
|
+
if (traceSeq !== undefined)
|
|
54938
|
+
state.tracer?.endStep(traceSeq, "failure", undefined, message);
|
|
54451
54939
|
throw error;
|
|
54452
54940
|
}
|
|
54453
54941
|
}
|
|
@@ -54470,7 +54958,7 @@ __export3(exports_wait2, {
|
|
|
54470
54958
|
executeWait: () => executeWait2
|
|
54471
54959
|
});
|
|
54472
54960
|
function sleep22(ms) {
|
|
54473
|
-
return new Promise((
|
|
54961
|
+
return new Promise((resolve33) => setTimeout(resolve33, ms));
|
|
54474
54962
|
}
|
|
54475
54963
|
async function executeWait2(state, waitDef, chain, hub, signal) {
|
|
54476
54964
|
const timeoutMs = waitDef.timeout ? parseDuration2(waitDef.timeout) : undefined;
|
|
@@ -54556,21 +55044,38 @@ async function executeControlStep2(workflow, state, step, basePath = process.cwd
|
|
|
54556
55044
|
}
|
|
54557
55045
|
const obj = step;
|
|
54558
55046
|
if ("wait" in obj && Object.keys(obj).length === 1) {
|
|
54559
|
-
const
|
|
54560
|
-
|
|
55047
|
+
const loopIndex = state.isInsideLoop() ? state.currentLoopIndex() : undefined;
|
|
55048
|
+
const traceSeq = state.tracer?.startStep("wait", "wait", undefined, loopIndex);
|
|
55049
|
+
try {
|
|
55050
|
+
const { executeWait: executeWait22 } = await Promise.resolve().then(() => (init_wait2(), exports_wait2));
|
|
55051
|
+
const result = await executeWait22(state, obj.wait, chain, hub, signal);
|
|
55052
|
+
if (traceSeq !== undefined)
|
|
55053
|
+
state.tracer?.endStep(traceSeq, "success", result);
|
|
55054
|
+
return result;
|
|
55055
|
+
} catch (err) {
|
|
55056
|
+
if (traceSeq !== undefined)
|
|
55057
|
+
state.tracer?.endStep(traceSeq, "failure", undefined, String(err?.message ?? err));
|
|
55058
|
+
throw err;
|
|
55059
|
+
}
|
|
54561
55060
|
}
|
|
54562
55061
|
if ("set" in obj && Object.keys(obj).length === 1) {
|
|
54563
55062
|
const setDef = obj.set;
|
|
54564
55063
|
const ctx = state.toCelContext();
|
|
55064
|
+
const loopIndex = state.isInsideLoop() ? state.currentLoopIndex() : undefined;
|
|
55065
|
+
const traceSeq = state.tracer?.startStep("set", "set", setDef, loopIndex);
|
|
54565
55066
|
if (!state.executionMeta.context) {
|
|
54566
55067
|
state.executionMeta.context = {};
|
|
54567
55068
|
}
|
|
54568
55069
|
for (const [key, expr] of Object.entries(setDef)) {
|
|
54569
55070
|
if (RESERVED_SET_KEYS2.has(key)) {
|
|
55071
|
+
if (traceSeq !== undefined)
|
|
55072
|
+
state.tracer?.endStep(traceSeq, "failure", undefined, `set key '${key}' uses a reserved name`);
|
|
54570
55073
|
throw new Error(`set key '${key}' uses a reserved name`);
|
|
54571
55074
|
}
|
|
54572
55075
|
state.executionMeta.context[key] = evaluateCel2(expr, ctx);
|
|
54573
55076
|
}
|
|
55077
|
+
if (traceSeq !== undefined)
|
|
55078
|
+
state.tracer?.endStep(traceSeq, "success", state.executionMeta.context);
|
|
54574
55079
|
return chain;
|
|
54575
55080
|
}
|
|
54576
55081
|
if ("loop" in obj && Object.keys(obj).length === 1) {
|
|
@@ -54587,6 +55092,8 @@ async function executeControlStep2(workflow, state, step, basePath = process.cwd
|
|
|
54587
55092
|
maxIterations = loopDef.max ?? Number.POSITIVE_INFINITY;
|
|
54588
55093
|
}
|
|
54589
55094
|
const hasMax = loopDef.max !== undefined;
|
|
55095
|
+
const outerLoopIndex = state.isInsideLoop() ? state.currentLoopIndex() : undefined;
|
|
55096
|
+
const loopTraceSeq = state.tracer?.startStep(loopAs ?? "loop", "loop", undefined, outerLoopIndex);
|
|
54590
55097
|
state.pushLoop(loopAs);
|
|
54591
55098
|
let loopChain = chain;
|
|
54592
55099
|
try {
|
|
@@ -54610,6 +55117,12 @@ async function executeControlStep2(workflow, state, step, basePath = process.cwd
|
|
|
54610
55117
|
iterations += 1;
|
|
54611
55118
|
state.incrementLoop();
|
|
54612
55119
|
}
|
|
55120
|
+
if (loopTraceSeq !== undefined)
|
|
55121
|
+
state.tracer?.endStep(loopTraceSeq, "success", loopChain);
|
|
55122
|
+
} catch (err) {
|
|
55123
|
+
if (loopTraceSeq !== undefined)
|
|
55124
|
+
state.tracer?.endStep(loopTraceSeq, "failure", undefined, String(err?.message ?? err));
|
|
55125
|
+
throw err;
|
|
54613
55126
|
} finally {
|
|
54614
55127
|
state.popLoop();
|
|
54615
55128
|
}
|
|
@@ -54618,29 +55131,54 @@ async function executeControlStep2(workflow, state, step, basePath = process.cwd
|
|
|
54618
55131
|
if ("parallel" in obj && Object.keys(obj).length === 1) {
|
|
54619
55132
|
const parallelSteps = obj.parallel;
|
|
54620
55133
|
const controller = new AbortController;
|
|
55134
|
+
const loopIndex = state.isInsideLoop() ? state.currentLoopIndex() : undefined;
|
|
55135
|
+
const parallelTraceSeq = state.tracer?.startStep("parallel", "parallel", undefined, loopIndex);
|
|
54621
55136
|
const branchSignal = signal ? AbortSignal.any([signal, controller.signal]) : controller.signal;
|
|
54622
|
-
|
|
54623
|
-
|
|
54624
|
-
|
|
54625
|
-
|
|
54626
|
-
|
|
54627
|
-
|
|
54628
|
-
|
|
54629
|
-
|
|
54630
|
-
|
|
55137
|
+
try {
|
|
55138
|
+
const results = await Promise.all(parallelSteps.map(async (parallelStep) => {
|
|
55139
|
+
try {
|
|
55140
|
+
return await executeControlStep2(workflow, state, parallelStep, basePath, engineExecutor, chain, hub, branchSignal);
|
|
55141
|
+
} catch (error) {
|
|
55142
|
+
controller.abort();
|
|
55143
|
+
throw error;
|
|
55144
|
+
}
|
|
55145
|
+
}));
|
|
55146
|
+
if (parallelTraceSeq !== undefined)
|
|
55147
|
+
state.tracer?.endStep(parallelTraceSeq, "success", results);
|
|
55148
|
+
return results;
|
|
55149
|
+
} catch (err) {
|
|
55150
|
+
if (parallelTraceSeq !== undefined)
|
|
55151
|
+
state.tracer?.endStep(parallelTraceSeq, "failure", undefined, String(err?.message ?? err));
|
|
55152
|
+
throw err;
|
|
55153
|
+
}
|
|
54631
55154
|
}
|
|
54632
55155
|
if ("if" in obj && Object.keys(obj).length === 1) {
|
|
54633
55156
|
const ifDef = obj.if;
|
|
54634
55157
|
const condition = evaluateCel2(ifDef.condition, state.toCelContext());
|
|
55158
|
+
const loopIndex = state.isInsideLoop() ? state.currentLoopIndex() : undefined;
|
|
55159
|
+
const ifTraceSeq = state.tracer?.startStep("if", "if", { condition: ifDef.condition }, loopIndex);
|
|
54635
55160
|
if (typeof condition !== "boolean") {
|
|
55161
|
+
if (ifTraceSeq !== undefined)
|
|
55162
|
+
state.tracer?.endStep(ifTraceSeq, "failure", undefined, `if.condition must evaluate to boolean, got ${typeof condition}`);
|
|
54636
55163
|
throw new Error(`if.condition must evaluate to boolean, got ${typeof condition}`);
|
|
54637
55164
|
}
|
|
54638
|
-
|
|
54639
|
-
|
|
54640
|
-
|
|
54641
|
-
|
|
55165
|
+
try {
|
|
55166
|
+
let result;
|
|
55167
|
+
if (condition) {
|
|
55168
|
+
result = await executeSequential2(workflow, state, ifDef.then, basePath, engineExecutor, chain, hub, signal);
|
|
55169
|
+
} else if (ifDef.else) {
|
|
55170
|
+
result = await executeSequential2(workflow, state, ifDef.else, basePath, engineExecutor, chain, hub, signal);
|
|
55171
|
+
} else {
|
|
55172
|
+
result = chain;
|
|
55173
|
+
}
|
|
55174
|
+
if (ifTraceSeq !== undefined)
|
|
55175
|
+
state.tracer?.endStep(ifTraceSeq, "success", result);
|
|
55176
|
+
return result;
|
|
55177
|
+
} catch (err) {
|
|
55178
|
+
if (ifTraceSeq !== undefined)
|
|
55179
|
+
state.tracer?.endStep(ifTraceSeq, "failure", undefined, String(err?.message ?? err));
|
|
55180
|
+
throw err;
|
|
54642
55181
|
}
|
|
54643
|
-
return chain;
|
|
54644
55182
|
}
|
|
54645
55183
|
return executeStep2(workflow, state, step, basePath, engineExecutor, [], chain, hub, signal);
|
|
54646
55184
|
}
|
|
@@ -54650,92 +55188,7 @@ var init_control2 = __esm3(() => {
|
|
|
54650
55188
|
init_sequential2();
|
|
54651
55189
|
RESERVED_SET_KEYS2 = new Set(["workflow", "execution", "input", "output", "env", "loop", "event"]);
|
|
54652
55190
|
});
|
|
54653
|
-
|
|
54654
|
-
class MemoryHub2 {
|
|
54655
|
-
listeners = new Map;
|
|
54656
|
-
buffer = new Map;
|
|
54657
|
-
closed = false;
|
|
54658
|
-
async publish(event, payload) {
|
|
54659
|
-
if (this.closed)
|
|
54660
|
-
throw new Error("hub is closed");
|
|
54661
|
-
const envelope = { name: event, payload };
|
|
54662
|
-
let buf = this.buffer.get(event);
|
|
54663
|
-
if (!buf) {
|
|
54664
|
-
buf = [];
|
|
54665
|
-
this.buffer.set(event, buf);
|
|
54666
|
-
}
|
|
54667
|
-
buf.push(envelope);
|
|
54668
|
-
const listeners = this.listeners.get(event);
|
|
54669
|
-
if (listeners) {
|
|
54670
|
-
for (const listener of listeners) {
|
|
54671
|
-
listener(envelope);
|
|
54672
|
-
}
|
|
54673
|
-
}
|
|
54674
|
-
}
|
|
54675
|
-
async publishAndWaitAck(event, payload, _timeoutMs) {
|
|
54676
|
-
await this.publish(event, payload);
|
|
54677
|
-
}
|
|
54678
|
-
async* subscribe(event, signal) {
|
|
54679
|
-
if (this.closed)
|
|
54680
|
-
return;
|
|
54681
|
-
const buffered = this.buffer.get(event);
|
|
54682
|
-
if (buffered) {
|
|
54683
|
-
for (const envelope of buffered) {
|
|
54684
|
-
if (signal?.aborted)
|
|
54685
|
-
return;
|
|
54686
|
-
yield envelope;
|
|
54687
|
-
}
|
|
54688
|
-
}
|
|
54689
|
-
const queue = [];
|
|
54690
|
-
let resolve5 = null;
|
|
54691
|
-
const listener = (envelope) => {
|
|
54692
|
-
queue.push(envelope);
|
|
54693
|
-
if (resolve5) {
|
|
54694
|
-
resolve5();
|
|
54695
|
-
resolve5 = null;
|
|
54696
|
-
}
|
|
54697
|
-
};
|
|
54698
|
-
let listeners = this.listeners.get(event);
|
|
54699
|
-
if (!listeners) {
|
|
54700
|
-
listeners = new Set;
|
|
54701
|
-
this.listeners.set(event, listeners);
|
|
54702
|
-
}
|
|
54703
|
-
listeners.add(listener);
|
|
54704
|
-
const onAbort = () => {
|
|
54705
|
-
listeners.delete(listener);
|
|
54706
|
-
if (resolve5) {
|
|
54707
|
-
resolve5();
|
|
54708
|
-
resolve5 = null;
|
|
54709
|
-
}
|
|
54710
|
-
};
|
|
54711
|
-
if (signal) {
|
|
54712
|
-
signal.addEventListener("abort", onAbort);
|
|
54713
|
-
}
|
|
54714
|
-
try {
|
|
54715
|
-
while (!this.closed && !signal?.aborted) {
|
|
54716
|
-
if (queue.length > 0) {
|
|
54717
|
-
yield queue.shift();
|
|
54718
|
-
} else {
|
|
54719
|
-
await new Promise((r) => {
|
|
54720
|
-
resolve5 = r;
|
|
54721
|
-
});
|
|
54722
|
-
}
|
|
54723
|
-
}
|
|
54724
|
-
} finally {
|
|
54725
|
-
listeners.delete(listener);
|
|
54726
|
-
if (signal) {
|
|
54727
|
-
signal.removeEventListener("abort", onAbort);
|
|
54728
|
-
}
|
|
54729
|
-
}
|
|
54730
|
-
}
|
|
54731
|
-
async close() {
|
|
54732
|
-
this.closed = true;
|
|
54733
|
-
for (const listeners of this.listeners.values()) {
|
|
54734
|
-
listeners.clear();
|
|
54735
|
-
}
|
|
54736
|
-
this.listeners.clear();
|
|
54737
|
-
}
|
|
54738
|
-
}
|
|
55191
|
+
init_cel2();
|
|
54739
55192
|
init_parser32();
|
|
54740
55193
|
init_schema2();
|
|
54741
55194
|
init_validate2();
|
|
@@ -54899,147 +55352,514 @@ function validateInputs2(inputDefs, provided) {
|
|
|
54899
55352
|
resolved
|
|
54900
55353
|
};
|
|
54901
55354
|
}
|
|
54902
|
-
init_cel2();
|
|
54903
|
-
init_cel2();
|
|
54904
|
-
init_parser32();
|
|
54905
|
-
init_schema2();
|
|
54906
|
-
init_validate2();
|
|
54907
|
-
init_control2();
|
|
54908
|
-
init_sequential2();
|
|
54909
|
-
init_wait2();
|
|
54910
|
-
init_emit2();
|
|
54911
55355
|
|
|
54912
|
-
|
|
54913
|
-
|
|
54914
|
-
|
|
54915
|
-
|
|
54916
|
-
|
|
54917
|
-
|
|
55356
|
+
class TraceCollector2 {
|
|
55357
|
+
openSteps = new Map;
|
|
55358
|
+
seq = 0;
|
|
55359
|
+
truncateAt;
|
|
55360
|
+
writer;
|
|
55361
|
+
constructor(truncateAt = 1e6) {
|
|
55362
|
+
this.truncateAt = truncateAt;
|
|
55363
|
+
}
|
|
55364
|
+
startStep(name, type3, input, loopIndex) {
|
|
55365
|
+
this.seq += 1;
|
|
55366
|
+
this.openSteps.set(this.seq, {
|
|
55367
|
+
name,
|
|
55368
|
+
type: type3,
|
|
55369
|
+
startedAt: new Date().toISOString(),
|
|
55370
|
+
startMs: performance.now(),
|
|
55371
|
+
input: input !== undefined ? this.truncate(input) : undefined,
|
|
55372
|
+
loopIndex
|
|
55373
|
+
});
|
|
55374
|
+
return this.seq;
|
|
55375
|
+
}
|
|
55376
|
+
endStep(seq, status, output, error, retries) {
|
|
55377
|
+
const open = this.openSteps.get(seq);
|
|
55378
|
+
if (!open)
|
|
55379
|
+
return;
|
|
55380
|
+
this.openSteps.delete(seq);
|
|
55381
|
+
const finishedAt = new Date().toISOString();
|
|
55382
|
+
const duration = Math.max(0, performance.now() - open.startMs);
|
|
55383
|
+
const step = {
|
|
55384
|
+
seq,
|
|
55385
|
+
name: open.name,
|
|
55386
|
+
type: open.type,
|
|
55387
|
+
startedAt: open.startedAt,
|
|
55388
|
+
finishedAt,
|
|
55389
|
+
duration: Math.round(duration),
|
|
55390
|
+
status,
|
|
55391
|
+
...open.input !== undefined ? { input: open.input } : {},
|
|
55392
|
+
...output !== undefined ? { output: this.truncate(output) } : {},
|
|
55393
|
+
...error !== undefined ? { error } : {},
|
|
55394
|
+
...retries !== undefined && retries > 0 ? { retries } : {},
|
|
55395
|
+
...open.loopIndex !== undefined ? { loopIndex: open.loopIndex } : {}
|
|
55396
|
+
};
|
|
55397
|
+
this.writer?.writeStep(step);
|
|
55398
|
+
}
|
|
55399
|
+
truncate(value) {
|
|
55400
|
+
if (value == null)
|
|
55401
|
+
return value;
|
|
55402
|
+
const str = typeof value === "string" ? value : JSON.stringify(value);
|
|
55403
|
+
const bytes = new TextEncoder().encode(str);
|
|
55404
|
+
if (bytes.length <= this.truncateAt)
|
|
55405
|
+
return value;
|
|
55406
|
+
const cut = new TextDecoder().decode(bytes.slice(0, this.truncateAt));
|
|
55407
|
+
return cut + "...[truncated]";
|
|
55408
|
+
}
|
|
54918
55409
|
}
|
|
54919
|
-
function
|
|
54920
|
-
|
|
54921
|
-
|
|
54922
|
-
|
|
54923
|
-
|
|
54924
|
-
|
|
54925
|
-
|
|
54926
|
-
|
|
54927
|
-
|
|
54928
|
-
|
|
54929
|
-
|
|
54930
|
-
|
|
54931
|
-
|
|
54932
|
-
|
|
54933
|
-
|
|
54934
|
-
|
|
55410
|
+
async function createTraceWriter(dir, format) {
|
|
55411
|
+
await mkdir(dir, { recursive: true });
|
|
55412
|
+
if (format === "json") {
|
|
55413
|
+
const { JsonTraceWriter: JsonTraceWriter22 } = await Promise.resolve().then(() => (init_json(), exports_json2));
|
|
55414
|
+
return new JsonTraceWriter22(dir);
|
|
55415
|
+
}
|
|
55416
|
+
if (format === "txt") {
|
|
55417
|
+
const { TxtTraceWriter: TxtTraceWriter22 } = await Promise.resolve().then(() => (init_txt(), exports_txt2));
|
|
55418
|
+
return new TxtTraceWriter22(dir);
|
|
55419
|
+
}
|
|
55420
|
+
if (format === "sqlite") {
|
|
55421
|
+
const { SqliteTraceWriter: SqliteTraceWriter22 } = await Promise.resolve().then(() => (init_sqlite(), exports_sqlite2));
|
|
55422
|
+
return new SqliteTraceWriter22(dir);
|
|
55423
|
+
}
|
|
55424
|
+
throw new Error(`unknown trace format: ${format}`);
|
|
55425
|
+
}
|
|
55426
|
+
init_control2();
|
|
55427
|
+
|
|
55428
|
+
class WorkflowState {
|
|
55429
|
+
inputs;
|
|
55430
|
+
results;
|
|
55431
|
+
loopStack;
|
|
55432
|
+
workflowInputs;
|
|
55433
|
+
workflowMeta;
|
|
55434
|
+
executionMeta;
|
|
55435
|
+
currentInput;
|
|
55436
|
+
currentOutput;
|
|
55437
|
+
chainValue;
|
|
55438
|
+
eventPayload;
|
|
55439
|
+
ancestorPaths;
|
|
55440
|
+
tracer;
|
|
55441
|
+
constructor(inputs = {}) {
|
|
55442
|
+
this.inputs = { ...inputs };
|
|
55443
|
+
this.workflowInputs = { ...inputs };
|
|
55444
|
+
this.workflowMeta = {};
|
|
55445
|
+
this.executionMeta = {
|
|
55446
|
+
id: crypto.randomUUID(),
|
|
55447
|
+
startedAt: new Date().toISOString(),
|
|
55448
|
+
status: "running",
|
|
55449
|
+
cwd: process.cwd()
|
|
55450
|
+
};
|
|
55451
|
+
this.currentInput = undefined;
|
|
55452
|
+
this.currentOutput = undefined;
|
|
55453
|
+
this.chainValue = undefined;
|
|
55454
|
+
this.eventPayload = undefined;
|
|
55455
|
+
this.ancestorPaths = new Set;
|
|
55456
|
+
this.results = new Map;
|
|
55457
|
+
this.loopStack = [];
|
|
55458
|
+
}
|
|
55459
|
+
setResult(stepName, result) {
|
|
55460
|
+
this.results.set(stepName, result);
|
|
55461
|
+
}
|
|
55462
|
+
getResult(stepName) {
|
|
55463
|
+
return this.results.get(stepName);
|
|
55464
|
+
}
|
|
55465
|
+
getAllResults() {
|
|
55466
|
+
const out = {};
|
|
55467
|
+
for (const [k, v] of this.results.entries())
|
|
55468
|
+
out[k] = v;
|
|
55469
|
+
return out;
|
|
55470
|
+
}
|
|
55471
|
+
pushLoop(as) {
|
|
55472
|
+
this.loopStack.push({ index: 0, as });
|
|
55473
|
+
}
|
|
55474
|
+
incrementLoop() {
|
|
55475
|
+
const top = this.loopStack[this.loopStack.length - 1];
|
|
55476
|
+
if (top)
|
|
55477
|
+
top.index += 1;
|
|
55478
|
+
}
|
|
55479
|
+
popLoop() {
|
|
55480
|
+
this.loopStack.pop();
|
|
55481
|
+
}
|
|
55482
|
+
currentLoopIndex() {
|
|
55483
|
+
const top = this.loopStack[this.loopStack.length - 1];
|
|
55484
|
+
return top ? top.index : 0;
|
|
55485
|
+
}
|
|
55486
|
+
setLoopLast(last22) {
|
|
55487
|
+
const top = this.loopStack[this.loopStack.length - 1];
|
|
55488
|
+
if (top)
|
|
55489
|
+
top.last = last22;
|
|
55490
|
+
}
|
|
55491
|
+
isInsideLoop() {
|
|
55492
|
+
return this.loopStack.length > 0;
|
|
55493
|
+
}
|
|
55494
|
+
currentLoopContext() {
|
|
55495
|
+
const top = this.loopStack[this.loopStack.length - 1];
|
|
55496
|
+
if (!top)
|
|
55497
|
+
return { index: 0, iteration: 1, first: true, last: false };
|
|
55498
|
+
return {
|
|
55499
|
+
index: top.index,
|
|
55500
|
+
iteration: top.index + 1,
|
|
55501
|
+
first: top.index === 0,
|
|
55502
|
+
last: top.last ?? false,
|
|
55503
|
+
as: top.as
|
|
55504
|
+
};
|
|
55505
|
+
}
|
|
55506
|
+
toCelContext() {
|
|
55507
|
+
const ctx = {};
|
|
55508
|
+
for (const [name, res] of this.results.entries()) {
|
|
55509
|
+
ctx[name] = {
|
|
55510
|
+
output: res.parsedOutput ?? res.output,
|
|
55511
|
+
status: res.status,
|
|
55512
|
+
startedAt: res.startedAt,
|
|
55513
|
+
finishedAt: res.finishedAt,
|
|
55514
|
+
duration: res.duration,
|
|
55515
|
+
retries: res.retries ?? 0,
|
|
55516
|
+
error: res.error,
|
|
55517
|
+
cwd: res.cwd
|
|
55518
|
+
};
|
|
54935
55519
|
}
|
|
54936
|
-
|
|
54937
|
-
|
|
54938
|
-
|
|
54939
|
-
|
|
54940
|
-
|
|
54941
|
-
|
|
54942
|
-
|
|
54943
|
-
|
|
54944
|
-
|
|
54945
|
-
|
|
54946
|
-
|
|
54947
|
-
|
|
54948
|
-
|
|
54949
|
-
|
|
54950
|
-
|
|
54951
|
-
|
|
54952
|
-
|
|
54953
|
-
|
|
55520
|
+
ctx["workflow"] = {
|
|
55521
|
+
id: this.workflowMeta.id,
|
|
55522
|
+
name: this.workflowMeta.name,
|
|
55523
|
+
version: this.workflowMeta.version,
|
|
55524
|
+
inputs: this.workflowInputs,
|
|
55525
|
+
output: null
|
|
55526
|
+
};
|
|
55527
|
+
ctx["execution"] = { ...this.executionMeta };
|
|
55528
|
+
ctx["input"] = this.currentInput ?? {};
|
|
55529
|
+
ctx["output"] = this.currentOutput ?? {};
|
|
55530
|
+
ctx["env"] = { ...env };
|
|
55531
|
+
const loopCtx = this.currentLoopContext();
|
|
55532
|
+
const loopObj = {
|
|
55533
|
+
index: loopCtx.index,
|
|
55534
|
+
iteration: loopCtx.iteration,
|
|
55535
|
+
first: loopCtx.first,
|
|
55536
|
+
last: loopCtx.last
|
|
55537
|
+
};
|
|
55538
|
+
if (loopCtx.as) {
|
|
55539
|
+
ctx[`_${loopCtx.as}`] = loopObj;
|
|
55540
|
+
}
|
|
55541
|
+
ctx["_loop"] = loopObj;
|
|
55542
|
+
ctx["loop"] = loopObj;
|
|
55543
|
+
ctx["event"] = this.eventPayload ?? {};
|
|
55544
|
+
ctx["now"] = Math.floor(Date.now() / 1000);
|
|
55545
|
+
return ctx;
|
|
55546
|
+
}
|
|
55547
|
+
resolveOutput(outputDef, celEvaluator) {
|
|
55548
|
+
const ctx = this.toCelContext();
|
|
55549
|
+
if (typeof outputDef === "object" && "map" in outputDef && "schema" in outputDef) {
|
|
55550
|
+
const result2 = {};
|
|
55551
|
+
for (const [k, expr] of Object.entries(outputDef.map)) {
|
|
55552
|
+
result2[k] = celEvaluator(expr, ctx);
|
|
54954
55553
|
}
|
|
54955
|
-
|
|
54956
|
-
continue;
|
|
55554
|
+
return result2;
|
|
54957
55555
|
}
|
|
54958
|
-
if (
|
|
54959
|
-
|
|
54960
|
-
path: stepPath,
|
|
54961
|
-
message: "inline participant without 'as' — its output cannot be referenced by name"
|
|
54962
|
-
});
|
|
54963
|
-
continue;
|
|
55556
|
+
if (typeof outputDef === "string") {
|
|
55557
|
+
return celEvaluator(outputDef, ctx);
|
|
54964
55558
|
}
|
|
54965
|
-
|
|
54966
|
-
|
|
54967
|
-
|
|
54968
|
-
|
|
54969
|
-
|
|
55559
|
+
const result = {};
|
|
55560
|
+
for (const k of Object.keys(outputDef)) {
|
|
55561
|
+
const expr = outputDef[k];
|
|
55562
|
+
result[k] = celEvaluator(expr, ctx);
|
|
55563
|
+
}
|
|
55564
|
+
return result;
|
|
55565
|
+
}
|
|
55566
|
+
}
|
|
55567
|
+
async function executeWorkflow(workflow, inputs = {}, basePath = process.cwd(), options = {}) {
|
|
55568
|
+
const { result: inputResult, resolved } = validateInputs2(workflow.inputs, inputs);
|
|
55569
|
+
if (!inputResult.valid) {
|
|
55570
|
+
throw new Error(`input validation failed: ${JSON.stringify(inputResult.errors)}`);
|
|
55571
|
+
}
|
|
55572
|
+
const state = new WorkflowState(resolved);
|
|
55573
|
+
state.workflowMeta = {
|
|
55574
|
+
id: workflow.id,
|
|
55575
|
+
name: workflow.name,
|
|
55576
|
+
version: workflow.version
|
|
55577
|
+
};
|
|
55578
|
+
state.executionMeta.number = options.executionNumber ?? 1;
|
|
55579
|
+
if (options.cwd) {
|
|
55580
|
+
state.executionMeta.cwd = options.cwd;
|
|
55581
|
+
}
|
|
55582
|
+
const startedAtMs = performance.now();
|
|
55583
|
+
const startedAtIso = state.executionMeta.startedAt;
|
|
55584
|
+
if (options._ancestorPaths) {
|
|
55585
|
+
state.ancestorPaths = options._ancestorPaths;
|
|
55586
|
+
}
|
|
55587
|
+
if (options.traceDir && !options._ancestorPaths) {
|
|
55588
|
+
const collector = new TraceCollector2;
|
|
55589
|
+
const writer = await createTraceWriter(options.traceDir, options.traceFormat ?? "json");
|
|
55590
|
+
collector.writer = writer;
|
|
55591
|
+
state.tracer = collector;
|
|
55592
|
+
await writer.open({
|
|
55593
|
+
id: state.executionMeta.id,
|
|
55594
|
+
workflowId: workflow.id,
|
|
55595
|
+
workflowName: workflow.name,
|
|
55596
|
+
workflowVersion: workflow.version,
|
|
55597
|
+
startedAt: startedAtIso,
|
|
55598
|
+
inputs: resolved
|
|
55599
|
+
});
|
|
55600
|
+
}
|
|
55601
|
+
const engineExecutor = async (subWorkflow, subInputs, subBasePath) => {
|
|
55602
|
+
return executeWorkflow(subWorkflow, subInputs, subBasePath, {
|
|
55603
|
+
...options,
|
|
55604
|
+
_ancestorPaths: state.ancestorPaths
|
|
55605
|
+
});
|
|
55606
|
+
};
|
|
55607
|
+
let output;
|
|
55608
|
+
let success = false;
|
|
55609
|
+
try {
|
|
55610
|
+
let chain;
|
|
55611
|
+
for (const step of workflow.flow) {
|
|
55612
|
+
chain = await executeControlStep2(workflow, state, step, basePath, engineExecutor, chain, options.hub);
|
|
55613
|
+
}
|
|
55614
|
+
if (workflow.output !== undefined) {
|
|
55615
|
+
output = state.resolveOutput(workflow.output, evaluateCel2);
|
|
55616
|
+
if (typeof workflow.output === "object" && "schema" in workflow.output && "map" in workflow.output && typeof output === "object" && output !== null) {
|
|
55617
|
+
validateOutputSchema2(workflow.output.schema, output);
|
|
54970
55618
|
}
|
|
55619
|
+
} else {
|
|
55620
|
+
output = chain;
|
|
55621
|
+
}
|
|
55622
|
+
const steps = state.getAllResults();
|
|
55623
|
+
success = !Object.values(steps).some((step) => step.status === "failure");
|
|
55624
|
+
state.executionMeta.status = success ? "success" : "failure";
|
|
55625
|
+
return {
|
|
55626
|
+
success,
|
|
55627
|
+
output,
|
|
55628
|
+
steps,
|
|
55629
|
+
duration: Math.max(0, performance.now() - startedAtMs)
|
|
55630
|
+
};
|
|
55631
|
+
} finally {
|
|
55632
|
+
if (state.tracer?.writer) {
|
|
55633
|
+
const duration = Math.max(0, performance.now() - startedAtMs);
|
|
55634
|
+
await state.tracer.writer.finalize({
|
|
55635
|
+
status: success ? "success" : "failure",
|
|
55636
|
+
output: output ?? null,
|
|
55637
|
+
finishedAt: new Date().toISOString(),
|
|
55638
|
+
duration
|
|
55639
|
+
}).catch(() => {});
|
|
54971
55640
|
}
|
|
54972
55641
|
}
|
|
54973
55642
|
}
|
|
54974
|
-
function
|
|
54975
|
-
|
|
54976
|
-
|
|
54977
|
-
|
|
54978
|
-
|
|
54979
|
-
return Object.keys(obj.set);
|
|
55643
|
+
async function runWorkflowFromFile(filePath, inputs = {}, options = {}) {
|
|
55644
|
+
const workflow = await parseWorkflowFile2(filePath);
|
|
55645
|
+
const schemaValidation = validateSchema2(workflow);
|
|
55646
|
+
if (!schemaValidation.valid) {
|
|
55647
|
+
throw new Error(`schema validation failed: ${JSON.stringify(schemaValidation.errors)}`);
|
|
54980
55648
|
}
|
|
54981
|
-
const
|
|
54982
|
-
|
|
54983
|
-
|
|
54984
|
-
|
|
54985
|
-
|
|
55649
|
+
const workflowBasePath = dirname22(resolve32(filePath));
|
|
55650
|
+
const semanticValidation = await validateSemantic2(workflow, workflowBasePath);
|
|
55651
|
+
if (!semanticValidation.valid) {
|
|
55652
|
+
throw new Error(`semantic validation failed: ${JSON.stringify(semanticValidation.errors)}`);
|
|
55653
|
+
}
|
|
55654
|
+
return executeWorkflow(workflow, inputs, workflowBasePath, options);
|
|
55655
|
+
}
|
|
55656
|
+
init_control2();
|
|
55657
|
+
init_sequential2();
|
|
55658
|
+
init_errors2();
|
|
55659
|
+
init_timeout2();
|
|
55660
|
+
init_wait2();
|
|
55661
|
+
|
|
55662
|
+
// src/run.ts
|
|
55663
|
+
async function createHubFromFlags(values3) {
|
|
55664
|
+
const backend = values3?.["event-backend"] ?? "memory";
|
|
55665
|
+
if (backend === "memory") {
|
|
55666
|
+
const { MemoryHub: MemoryHub3 } = await Promise.resolve().then(() => (init_eventhub(), exports_eventhub));
|
|
55667
|
+
return new MemoryHub3;
|
|
55668
|
+
}
|
|
55669
|
+
if (backend === "nats") {
|
|
55670
|
+
const url = values3?.["nats-url"];
|
|
55671
|
+
if (!url) {
|
|
55672
|
+
console.error("Error: --nats-url is required when using the NATS backend");
|
|
55673
|
+
throw new Error("missing --nats-url");
|
|
55674
|
+
}
|
|
55675
|
+
const stream = values3?.["nats-stream"] ?? "duckflux-events";
|
|
55676
|
+
try {
|
|
55677
|
+
const { NatsHub } = await import("@duckflux/hub-nats");
|
|
55678
|
+
return await NatsHub.create({ url, stream });
|
|
55679
|
+
} catch (err) {
|
|
55680
|
+
if (err instanceof Error && (err.message.includes("Cannot find module") || err.message.includes("Cannot find package"))) {
|
|
55681
|
+
console.error("Error: install @duckflux/hub-nats to use the NATS backend");
|
|
55682
|
+
throw new Error("@duckflux/hub-nats not installed");
|
|
55683
|
+
}
|
|
55684
|
+
throw err;
|
|
54986
55685
|
}
|
|
54987
55686
|
}
|
|
54988
|
-
if (
|
|
54989
|
-
const
|
|
54990
|
-
|
|
54991
|
-
|
|
55687
|
+
if (backend === "redis") {
|
|
55688
|
+
const addr = values3?.["redis-addr"] ?? "localhost:6379";
|
|
55689
|
+
const db = Number(values3?.["redis-db"] ?? "0");
|
|
55690
|
+
try {
|
|
55691
|
+
const { RedisHub } = await import("@duckflux/hub-redis");
|
|
55692
|
+
return await RedisHub.create({ addr, db });
|
|
55693
|
+
} catch (err) {
|
|
55694
|
+
if (err instanceof Error && (err.message.includes("Cannot find module") || err.message.includes("Cannot find package"))) {
|
|
55695
|
+
console.error("Error: install @duckflux/hub-redis to use the Redis backend");
|
|
55696
|
+
throw new Error("@duckflux/hub-redis not installed");
|
|
55697
|
+
}
|
|
55698
|
+
throw err;
|
|
54992
55699
|
}
|
|
54993
|
-
|
|
54994
|
-
|
|
54995
|
-
|
|
55700
|
+
}
|
|
55701
|
+
console.error(`Error: unknown event backend "${backend}". Supported: memory, nats, redis`);
|
|
55702
|
+
throw new Error(`unknown event backend: ${backend}`);
|
|
55703
|
+
}
|
|
55704
|
+
function parseInputFlags(arr) {
|
|
55705
|
+
const out = {};
|
|
55706
|
+
if (!arr)
|
|
55707
|
+
return out;
|
|
55708
|
+
for (const item of arr) {
|
|
55709
|
+
const idx = item.indexOf("=");
|
|
55710
|
+
if (idx === -1) {
|
|
55711
|
+
out[item] = true;
|
|
55712
|
+
} else {
|
|
55713
|
+
const k = item.slice(0, idx);
|
|
55714
|
+
const v = item.slice(idx + 1);
|
|
55715
|
+
try {
|
|
55716
|
+
out[k] = JSON.parse(v);
|
|
55717
|
+
} catch {
|
|
55718
|
+
out[k] = v;
|
|
54996
55719
|
}
|
|
54997
55720
|
}
|
|
54998
55721
|
}
|
|
54999
|
-
return
|
|
55722
|
+
return out;
|
|
55000
55723
|
}
|
|
55001
|
-
async function
|
|
55724
|
+
async function runCommand(filePath, cliValues) {
|
|
55002
55725
|
if (!filePath) {
|
|
55003
|
-
console.error("Usage:
|
|
55726
|
+
console.error("Usage: quack run <workflow.yaml> [--input k=v] [--input-file file.json] [--cwd dir]");
|
|
55004
55727
|
return 1;
|
|
55005
55728
|
}
|
|
55729
|
+
let inputs = {};
|
|
55006
55730
|
try {
|
|
55007
|
-
|
|
55008
|
-
|
|
55009
|
-
|
|
55010
|
-
|
|
55011
|
-
for (const e of schemaRes.errors) {
|
|
55012
|
-
console.error(` - ${e.path}: ${e.message}`);
|
|
55731
|
+
if (process.stdin && !process.stdin.isTTY) {
|
|
55732
|
+
let stdin = "";
|
|
55733
|
+
for await (const chunk of process.stdin) {
|
|
55734
|
+
stdin += chunk;
|
|
55013
55735
|
}
|
|
55014
|
-
|
|
55015
|
-
|
|
55016
|
-
|
|
55017
|
-
|
|
55018
|
-
|
|
55019
|
-
|
|
55020
|
-
|
|
55021
|
-
console.error(` - ${e.path}: ${e.message}`);
|
|
55736
|
+
stdin = stdin.trim();
|
|
55737
|
+
if (stdin.length > 0) {
|
|
55738
|
+
try {
|
|
55739
|
+
const parsed = JSON.parse(stdin);
|
|
55740
|
+
if (typeof parsed === "object" && parsed !== null)
|
|
55741
|
+
inputs = { ...inputs, ...parsed };
|
|
55742
|
+
} catch {}
|
|
55022
55743
|
}
|
|
55023
|
-
return 1;
|
|
55024
55744
|
}
|
|
55025
|
-
|
|
55026
|
-
|
|
55027
|
-
|
|
55028
|
-
|
|
55029
|
-
|
|
55745
|
+
} catch {}
|
|
55746
|
+
if (cliValues) {
|
|
55747
|
+
if (cliValues["input-file"]) {
|
|
55748
|
+
try {
|
|
55749
|
+
const content = await readFile5(String(cliValues["input-file"]), "utf-8");
|
|
55750
|
+
const parsed = JSON.parse(content);
|
|
55751
|
+
if (typeof parsed === "object" && parsed !== null)
|
|
55752
|
+
inputs = { ...inputs, ...parsed };
|
|
55753
|
+
} catch (err) {
|
|
55754
|
+
console.error("Failed to read input file:", err);
|
|
55755
|
+
return 1;
|
|
55030
55756
|
}
|
|
55031
55757
|
}
|
|
55032
|
-
|
|
55033
|
-
|
|
55758
|
+
if (cliValues.input) {
|
|
55759
|
+
const parsed = Array.isArray(cliValues.input) ? cliValues.input : [cliValues.input];
|
|
55760
|
+
inputs = { ...inputs, ...parseInputFlags(parsed) };
|
|
55761
|
+
}
|
|
55762
|
+
}
|
|
55763
|
+
let hub;
|
|
55764
|
+
try {
|
|
55765
|
+
hub = await createHubFromFlags(cliValues);
|
|
55766
|
+
} catch {
|
|
55767
|
+
return 1;
|
|
55768
|
+
}
|
|
55769
|
+
const options = {
|
|
55770
|
+
hub,
|
|
55771
|
+
cwd: cliValues?.cwd,
|
|
55772
|
+
verbose: cliValues?.verbose,
|
|
55773
|
+
quiet: cliValues?.quiet,
|
|
55774
|
+
traceDir: cliValues?.["trace-dir"],
|
|
55775
|
+
traceFormat: cliValues?.["trace-format"] ?? "json"
|
|
55776
|
+
};
|
|
55777
|
+
try {
|
|
55778
|
+
const res = await runWorkflowFromFile(filePath, inputs, options);
|
|
55779
|
+
const output = res.output;
|
|
55780
|
+
if (output === undefined || output === null) {} else if (typeof output === "string") {
|
|
55781
|
+
process.stdout.write(output);
|
|
55782
|
+
} else {
|
|
55783
|
+
console.log(JSON.stringify(output, null, 2));
|
|
55784
|
+
}
|
|
55785
|
+
return res.success ? 0 : 2;
|
|
55034
55786
|
} catch (err) {
|
|
55035
|
-
|
|
55787
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
55788
|
+
console.error("Error:", msg);
|
|
55789
|
+
if (cliValues?.verbose && err instanceof Error && err.stack) {
|
|
55790
|
+
console.error(err.stack);
|
|
55791
|
+
}
|
|
55036
55792
|
return 1;
|
|
55793
|
+
} finally {
|
|
55794
|
+
await hub?.close();
|
|
55037
55795
|
}
|
|
55038
55796
|
}
|
|
55039
55797
|
|
|
55798
|
+
// src/server.ts
|
|
55799
|
+
import { existsSync } from "node:fs";
|
|
55800
|
+
import { join as join6 } from "node:path";
|
|
55801
|
+
import { spawn as spawn3, execSync } from "node:child_process";
|
|
55802
|
+
import { createInterface } from "node:readline";
|
|
55803
|
+
async function ensureServerPackage(cwd) {
|
|
55804
|
+
const serverBin = join6(cwd, "node_modules", ".bin", "duckflux-server");
|
|
55805
|
+
const serverPkg = join6(cwd, "node_modules", "@duckflux", "server");
|
|
55806
|
+
if (existsSync(serverBin) || existsSync(serverPkg))
|
|
55807
|
+
return true;
|
|
55808
|
+
const rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
55809
|
+
const answer = await new Promise((resolve4) => {
|
|
55810
|
+
rl.question(`
|
|
55811
|
+
@duckflux/server is not installed. Install it now? [Y/n] `, resolve4);
|
|
55812
|
+
});
|
|
55813
|
+
rl.close();
|
|
55814
|
+
if (answer.trim().toLowerCase() === "n") {
|
|
55815
|
+
console.error("Cancelled. Run `bun add @duckflux/server -D` to install manually.");
|
|
55816
|
+
return false;
|
|
55817
|
+
}
|
|
55818
|
+
console.error("Installing @duckflux/server...");
|
|
55819
|
+
try {
|
|
55820
|
+
execSync("bun add @duckflux/server -D", { cwd, stdio: "inherit" });
|
|
55821
|
+
return true;
|
|
55822
|
+
} catch {
|
|
55823
|
+
try {
|
|
55824
|
+
execSync("npm install @duckflux/server --save-dev", { cwd, stdio: "inherit" });
|
|
55825
|
+
return true;
|
|
55826
|
+
} catch {
|
|
55827
|
+
console.error("Failed to install @duckflux/server. Please install it manually.");
|
|
55828
|
+
return false;
|
|
55829
|
+
}
|
|
55830
|
+
}
|
|
55831
|
+
}
|
|
55832
|
+
async function serverCommand(values3) {
|
|
55833
|
+
const cwd = values3["cwd"] ?? process.cwd();
|
|
55834
|
+
const installed = await ensureServerPackage(cwd);
|
|
55835
|
+
if (!installed)
|
|
55836
|
+
return 1;
|
|
55837
|
+
const args = [];
|
|
55838
|
+
if (values3["trace-dir"])
|
|
55839
|
+
args.push("--trace-dir", values3["trace-dir"]);
|
|
55840
|
+
if (values3["workflow-dir"])
|
|
55841
|
+
args.push("--workflow-dir", values3["workflow-dir"]);
|
|
55842
|
+
if (values3["port"])
|
|
55843
|
+
args.push("--port", values3["port"]);
|
|
55844
|
+
const child = spawn3("bunx", ["@duckflux/server", ...args], {
|
|
55845
|
+
cwd,
|
|
55846
|
+
stdio: "inherit",
|
|
55847
|
+
env: process.env
|
|
55848
|
+
});
|
|
55849
|
+
return new Promise((resolve4) => {
|
|
55850
|
+
child.on("error", (err) => {
|
|
55851
|
+
console.error("Failed to start duckflux server:", err.message);
|
|
55852
|
+
resolve4(1);
|
|
55853
|
+
});
|
|
55854
|
+
child.on("exit", (code) => resolve4(code ?? 0));
|
|
55855
|
+
process.on("SIGINT", () => child.kill("SIGINT"));
|
|
55856
|
+
process.on("SIGTERM", () => child.kill("SIGTERM"));
|
|
55857
|
+
});
|
|
55858
|
+
}
|
|
55859
|
+
|
|
55040
55860
|
// src/validate.ts
|
|
55041
|
-
import { readFile as
|
|
55042
|
-
import { dirname as
|
|
55861
|
+
import { readFile as readFile6 } from "node:fs/promises";
|
|
55862
|
+
import { dirname as dirname4 } from "node:path";
|
|
55043
55863
|
|
|
55044
55864
|
// src/run.ts
|
|
55045
55865
|
function parseInputFlags2(arr) {
|
|
@@ -55066,7 +55886,7 @@ function parseInputFlags2(arr) {
|
|
|
55066
55886
|
// src/validate.ts
|
|
55067
55887
|
async function validateCommand(filePath, cliValues) {
|
|
55068
55888
|
if (!filePath) {
|
|
55069
|
-
console.error("Usage:
|
|
55889
|
+
console.error("Usage: quack validate <workflow.yaml> [--input k=v] [--input-file file.json]");
|
|
55070
55890
|
return 1;
|
|
55071
55891
|
}
|
|
55072
55892
|
let inputs = {};
|
|
@@ -55077,7 +55897,7 @@ async function validateCommand(filePath, cliValues) {
|
|
|
55077
55897
|
}
|
|
55078
55898
|
if (cliValues["input-file"]) {
|
|
55079
55899
|
try {
|
|
55080
|
-
const content = await
|
|
55900
|
+
const content = await readFile6(String(cliValues["input-file"]), "utf-8");
|
|
55081
55901
|
const parsed = JSON.parse(content);
|
|
55082
55902
|
if (typeof parsed === "object" && parsed !== null)
|
|
55083
55903
|
inputs = { ...inputs, ...parsed };
|
|
@@ -55104,8 +55924,8 @@ async function validateCommand(filePath, cliValues) {
|
|
|
55104
55924
|
}
|
|
55105
55925
|
} catch {}
|
|
55106
55926
|
try {
|
|
55107
|
-
const workflow = await
|
|
55108
|
-
const schemaRes =
|
|
55927
|
+
const workflow = await parseWorkflowFile(filePath);
|
|
55928
|
+
const schemaRes = validateSchema(workflow);
|
|
55109
55929
|
if (!schemaRes.valid) {
|
|
55110
55930
|
console.error("Schema validation failed:");
|
|
55111
55931
|
for (const e of schemaRes.errors) {
|
|
@@ -55113,8 +55933,8 @@ async function validateCommand(filePath, cliValues) {
|
|
|
55113
55933
|
}
|
|
55114
55934
|
return 1;
|
|
55115
55935
|
}
|
|
55116
|
-
const basePath =
|
|
55117
|
-
const semanticRes = await
|
|
55936
|
+
const basePath = dirname4(filePath);
|
|
55937
|
+
const semanticRes = await validateSemantic(workflow, basePath);
|
|
55118
55938
|
if (!semanticRes.valid) {
|
|
55119
55939
|
console.error("Semantic validation failed:");
|
|
55120
55940
|
for (const e of semanticRes.errors) {
|
|
@@ -55122,7 +55942,7 @@ async function validateCommand(filePath, cliValues) {
|
|
|
55122
55942
|
}
|
|
55123
55943
|
return 1;
|
|
55124
55944
|
}
|
|
55125
|
-
const { result: inputsResult, resolved } =
|
|
55945
|
+
const { result: inputsResult, resolved } = validateInputs(workflow.inputs, inputs);
|
|
55126
55946
|
if (!inputsResult.valid) {
|
|
55127
55947
|
console.error("Input validation failed:");
|
|
55128
55948
|
for (const e of inputsResult.errors) {
|
|
@@ -55141,7 +55961,7 @@ async function validateCommand(filePath, cliValues) {
|
|
|
55141
55961
|
// src/main.ts
|
|
55142
55962
|
function getVersion() {
|
|
55143
55963
|
try {
|
|
55144
|
-
const pkg = JSON.parse(readFileSync3(
|
|
55964
|
+
const pkg = JSON.parse(readFileSync3(resolve5(dirname5(new URL(import.meta.url).pathname), "../package.json"), "utf-8"));
|
|
55145
55965
|
return pkg.version ?? "0.0.0";
|
|
55146
55966
|
} catch {
|
|
55147
55967
|
return "0.0.0";
|
|
@@ -55161,7 +55981,11 @@ if (__require.main == __require.module) {
|
|
|
55161
55981
|
"nats-url": { type: "string" },
|
|
55162
55982
|
"nats-stream": { type: "string", default: "duckflux-events" },
|
|
55163
55983
|
"redis-addr": { type: "string", default: "localhost:6379" },
|
|
55164
|
-
"redis-db": { type: "string", default: "0" }
|
|
55984
|
+
"redis-db": { type: "string", default: "0" },
|
|
55985
|
+
"trace-dir": { type: "string" },
|
|
55986
|
+
"trace-format": { type: "string", default: "json" },
|
|
55987
|
+
"workflow-dir": { type: "string" },
|
|
55988
|
+
port: { type: "string", default: "3000" }
|
|
55165
55989
|
},
|
|
55166
55990
|
allowPositionals: true
|
|
55167
55991
|
});
|
|
@@ -55183,9 +56007,13 @@ if (__require.main == __require.module) {
|
|
|
55183
56007
|
const exitCode = await validateCommand(file, values3);
|
|
55184
56008
|
if (typeof exitCode === "number" && exitCode !== 0)
|
|
55185
56009
|
process.exit(exitCode);
|
|
56010
|
+
} else if (cmd === "server") {
|
|
56011
|
+
const exitCode = await serverCommand(values3);
|
|
56012
|
+
if (typeof exitCode === "number" && exitCode !== 0)
|
|
56013
|
+
process.exit(exitCode);
|
|
55186
56014
|
} else {
|
|
55187
56015
|
console.error("Unknown command:", cmd);
|
|
55188
|
-
console.error("Available commands: run, lint, validate, version");
|
|
56016
|
+
console.error("Available commands: run, lint, validate, version, server");
|
|
55189
56017
|
process.exit(1);
|
|
55190
56018
|
}
|
|
55191
56019
|
}
|