workflowskill 0.2.1 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,1977 +0,0 @@
1
- import { parse } from "yaml";
2
- import { z } from "zod";
3
- import Anthropic from "@anthropic-ai/sdk";
4
- import { existsSync, readFileSync } from "node:fs";
5
- import { dirname, join } from "node:path";
6
- import { fileURLToPath } from "node:url";
7
-
8
- //#region src/parser/extract.ts
9
- /**
10
- * Extract YAML frontmatter from SKILL.md content.
11
- * Frontmatter is delimited by --- at the start of the file.
12
- */
13
- function extractFrontmatter(content) {
14
- return content.replace(/\r\n/g, "\n").match(/^---\n([\s\S]*?)\n---/)?.[1] ?? null;
15
- }
16
- /**
17
- * Extract the ```workflow fenced code block from SKILL.md content.
18
- * Returns the YAML content inside the block.
19
- * Throws if no workflow block is found.
20
- */
21
- function extractWorkflowBlock(content) {
22
- const match = content.replace(/\r\n/g, "\n").match(/```workflow\s*\n([\s\S]*?)\n```/);
23
- if (!match?.[1]) throw new ExtractError("No ```workflow fenced code block found in SKILL.md. WorkflowSkill definitions must be wrapped in a ```workflow block.");
24
- return match[1];
25
- }
26
- /**
27
- * Extract both frontmatter and workflow block from SKILL.md content.
28
- */
29
- function extract(content) {
30
- return {
31
- frontmatter: extractFrontmatter(content),
32
- workflowYaml: extractWorkflowBlock(content)
33
- };
34
- }
35
- /** Error thrown during extraction. */
36
- var ExtractError = class extends Error {
37
- constructor(message) {
38
- super(message);
39
- this.name = "ExtractError";
40
- }
41
- };
42
-
43
- //#endregion
44
- //#region src/parser/schema.ts
45
- const schemaTypeEnum = z.enum([
46
- "string",
47
- "int",
48
- "float",
49
- "boolean",
50
- "array",
51
- "object"
52
- ]);
53
- const nestedFieldSchema = z.object({
54
- type: schemaTypeEnum,
55
- value: z.unknown().optional(),
56
- items: z.record(z.string(), z.unknown()).optional(),
57
- properties: z.record(z.string(), z.unknown()).optional()
58
- });
59
- const fieldSchema = z.object({
60
- type: schemaTypeEnum,
61
- value: z.unknown().optional(),
62
- default: z.unknown().optional(),
63
- items: nestedFieldSchema.optional(),
64
- properties: z.record(z.string(), z.union([z.string(), nestedFieldSchema])).optional()
65
- }).transform((obj) => {
66
- const { default: legacy, ...rest } = obj;
67
- if (rest.value === void 0 && legacy !== void 0) rest.value = legacy;
68
- return rest;
69
- });
70
- const workflowInputSchema = z.object({
71
- type: schemaTypeEnum,
72
- default: z.unknown().optional(),
73
- value: z.unknown().optional(),
74
- items: nestedFieldSchema.optional(),
75
- properties: z.record(z.string(), z.union([z.string(), nestedFieldSchema])).optional()
76
- }).transform((obj) => {
77
- const { value: legacy, ...rest } = obj;
78
- if (rest.default === void 0 && legacy !== void 0) rest.default = legacy;
79
- return rest;
80
- });
81
- const workflowOutputBaseSchema = z.object({
82
- type: schemaTypeEnum,
83
- value: z.unknown().optional(),
84
- default: z.unknown().optional(),
85
- source: z.string().optional(),
86
- items: nestedFieldSchema.optional(),
87
- properties: z.record(z.string(), z.union([z.string(), nestedFieldSchema])).optional()
88
- }).transform((obj) => {
89
- const { source, default: legacy, ...rest } = obj;
90
- if (rest.value === void 0 && source !== void 0) rest.value = source;
91
- if (rest.value === void 0 && legacy !== void 0) rest.value = legacy;
92
- return rest;
93
- });
94
- const workflowOutputSchema = workflowOutputBaseSchema;
95
- const stepInputBaseSchema = z.object({
96
- type: schemaTypeEnum,
97
- value: z.unknown().optional(),
98
- default: z.unknown().optional(),
99
- source: z.string().optional(),
100
- items: nestedFieldSchema.optional(),
101
- properties: z.record(z.string(), z.union([z.string(), nestedFieldSchema])).optional()
102
- }).transform((obj) => {
103
- const { source, default: legacy, ...rest } = obj;
104
- if (rest.value === void 0 && source !== void 0) rest.value = source;
105
- if (rest.value === void 0 && legacy !== void 0) rest.value = legacy;
106
- return rest;
107
- });
108
- const stepInputSchema = stepInputBaseSchema;
109
- const stepOutputBaseSchema = z.object({
110
- type: schemaTypeEnum,
111
- value: z.unknown().optional(),
112
- default: z.unknown().optional(),
113
- source: z.string().optional(),
114
- items: nestedFieldSchema.optional(),
115
- properties: z.record(z.string(), z.union([z.string(), nestedFieldSchema])).optional()
116
- }).transform((obj) => {
117
- const { source, default: legacy, ...rest } = obj;
118
- if (rest.value === void 0 && source !== void 0) rest.value = source;
119
- if (rest.value === void 0 && legacy !== void 0) rest.value = legacy;
120
- return rest;
121
- });
122
- const stepOutputSchema = stepOutputBaseSchema;
123
- const retryPolicySchema = z.object({
124
- max: z.number().int().positive(),
125
- delay: z.string(),
126
- backoff: z.number().positive()
127
- });
128
- const stepBaseSchema = z.object({
129
- id: z.string().min(1),
130
- type: z.enum([
131
- "tool",
132
- "llm",
133
- "transform",
134
- "conditional",
135
- "exit"
136
- ]),
137
- description: z.string().optional(),
138
- inputs: z.record(z.string(), stepInputSchema).default({}),
139
- outputs: z.record(z.string(), stepOutputSchema).default({}),
140
- condition: z.string().optional(),
141
- each: z.string().optional(),
142
- delay: z.string().optional(),
143
- on_error: z.enum(["fail", "ignore"]).optional(),
144
- retry: retryPolicySchema.optional()
145
- });
146
- const toolStepSchema = stepBaseSchema.extend({
147
- type: z.literal("tool"),
148
- tool: z.string().min(1)
149
- });
150
- const llmStepSchema = stepBaseSchema.extend({
151
- type: z.literal("llm"),
152
- model: z.string().optional(),
153
- prompt: z.string().min(1),
154
- response_format: z.record(z.string(), z.unknown()).optional()
155
- });
156
- const transformFilterStepSchema = stepBaseSchema.extend({
157
- type: z.literal("transform"),
158
- operation: z.literal("filter"),
159
- where: z.string().min(1)
160
- });
161
- const transformMapStepSchema = stepBaseSchema.extend({
162
- type: z.literal("transform"),
163
- operation: z.literal("map"),
164
- expression: z.record(z.string(), z.unknown())
165
- });
166
- const transformSortStepSchema = stepBaseSchema.extend({
167
- type: z.literal("transform"),
168
- operation: z.literal("sort"),
169
- field: z.string().min(1),
170
- direction: z.enum(["asc", "desc"]).optional()
171
- });
172
- const conditionalStepSchema = stepBaseSchema.extend({
173
- type: z.literal("conditional"),
174
- condition: z.string().min(1),
175
- then: z.array(z.string()).min(1),
176
- else: z.array(z.string()).optional()
177
- });
178
- const exitStepSchema = stepBaseSchema.extend({
179
- type: z.literal("exit"),
180
- status: z.enum(["success", "failed"]),
181
- output: z.union([z.string(), z.record(z.string(), z.unknown())]).optional()
182
- });
183
- const transformStepSchema = z.discriminatedUnion("operation", [
184
- transformFilterStepSchema,
185
- transformMapStepSchema,
186
- transformSortStepSchema
187
- ]);
188
- const stepSchema = z.union([
189
- toolStepSchema,
190
- llmStepSchema,
191
- transformStepSchema,
192
- conditionalStepSchema,
193
- exitStepSchema
194
- ]);
195
- const workflowDefinitionSchema = z.object({
196
- inputs: z.record(z.string(), workflowInputSchema).default({}),
197
- outputs: z.record(z.string(), workflowOutputSchema).default({}),
198
- steps: z.array(stepSchema).min(1, "Workflow must have at least one step")
199
- });
200
- const skillFrontmatterSchema = z.object({
201
- name: z.string().min(1),
202
- description: z.string().min(1)
203
- }).passthrough();
204
-
205
- //#endregion
206
- //#region src/parser/index.ts
207
- /** Error thrown when parsing fails. Includes structured details. */
208
- var ParseError = class extends Error {
209
- constructor(message, details = []) {
210
- super(message);
211
- this.details = details;
212
- this.name = "ParseError";
213
- }
214
- };
215
- /**
216
- * Convert Zod errors to our ParseErrorDetail format.
217
- */
218
- function zodToDetails(err) {
219
- return err.issues.map((issue) => ({
220
- path: issue.path.join("."),
221
- message: issue.message
222
- }));
223
- }
224
- /**
225
- * Parse a raw YAML string into a validated WorkflowDefinition.
226
- * Use this when you already have the YAML content (e.g., from extractWorkflowBlock).
227
- */
228
- function parseWorkflowYaml(yaml) {
229
- let raw;
230
- try {
231
- raw = parse(yaml);
232
- } catch (err) {
233
- throw new ParseError(`Invalid YAML: ${err instanceof Error ? err.message : String(err)}`);
234
- }
235
- const result = workflowDefinitionSchema.safeParse(raw);
236
- if (!result.success) throw new ParseError("Workflow validation failed", zodToDetails(result.error));
237
- return result.data;
238
- }
239
- /**
240
- * Parse a SKILL.md file content into a fully typed ParsedSkill.
241
- * Extracts frontmatter and workflow block, validates both.
242
- */
243
- function parseSkillMd(content) {
244
- let extracted;
245
- try {
246
- extracted = extract(content);
247
- } catch (err) {
248
- if (err instanceof ExtractError) throw new ParseError(err.message);
249
- throw err;
250
- }
251
- let frontmatter;
252
- if (extracted.frontmatter) {
253
- let rawFrontmatter;
254
- try {
255
- rawFrontmatter = parse(extracted.frontmatter);
256
- } catch (err) {
257
- throw new ParseError(`Invalid frontmatter YAML: ${err instanceof Error ? err.message : String(err)}`);
258
- }
259
- const fmResult = skillFrontmatterSchema.safeParse(rawFrontmatter);
260
- if (!fmResult.success) throw new ParseError("Frontmatter validation failed", zodToDetails(fmResult.error));
261
- frontmatter = fmResult.data;
262
- } else throw new ParseError("SKILL.md must have YAML frontmatter with name and description");
263
- const workflow = parseWorkflowYaml(extracted.workflowYaml);
264
- return {
265
- frontmatter,
266
- workflow
267
- };
268
- }
269
- /**
270
- * Parse just the workflow block from SKILL.md content.
271
- * Useful when you only need the workflow definition without frontmatter.
272
- */
273
- function parseWorkflowFromMd(content) {
274
- let yaml;
275
- try {
276
- yaml = extractWorkflowBlock(content);
277
- } catch (err) {
278
- if (err instanceof ExtractError) throw new ParseError(err.message);
279
- throw err;
280
- }
281
- return parseWorkflowYaml(yaml);
282
- }
283
-
284
- //#endregion
285
- //#region src/expression/lexer.ts
286
- var LexError = class extends Error {
287
- constructor(message, position) {
288
- super(message);
289
- this.position = position;
290
- this.name = "LexError";
291
- }
292
- };
293
- function lex(input) {
294
- const tokens = [];
295
- let pos = 0;
296
- while (pos < input.length) {
297
- if (/\s/.test(input[pos])) {
298
- pos++;
299
- continue;
300
- }
301
- const ch = input[pos];
302
- if (ch === "$") {
303
- const start = pos;
304
- pos++;
305
- let name = "";
306
- while (pos < input.length && /[a-zA-Z_]/.test(input[pos])) {
307
- name += input[pos];
308
- pos++;
309
- }
310
- if (!name) throw new LexError(`Expected identifier after $`, start);
311
- tokens.push({
312
- type: "DOLLAR_REF",
313
- value: name,
314
- position: start
315
- });
316
- continue;
317
- }
318
- if (ch === ".") {
319
- tokens.push({
320
- type: "DOT",
321
- value: ".",
322
- position: pos
323
- });
324
- pos++;
325
- continue;
326
- }
327
- if (ch === "(") {
328
- tokens.push({
329
- type: "LPAREN",
330
- value: "(",
331
- position: pos
332
- });
333
- pos++;
334
- continue;
335
- }
336
- if (ch === ")") {
337
- tokens.push({
338
- type: "RPAREN",
339
- value: ")",
340
- position: pos
341
- });
342
- pos++;
343
- continue;
344
- }
345
- if (ch === "[") {
346
- tokens.push({
347
- type: "LBRACKET",
348
- value: "[",
349
- position: pos
350
- });
351
- pos++;
352
- continue;
353
- }
354
- if (ch === "]") {
355
- tokens.push({
356
- type: "RBRACKET",
357
- value: "]",
358
- position: pos
359
- });
360
- pos++;
361
- continue;
362
- }
363
- if (pos + 1 < input.length) {
364
- const twoChar = input[pos] + input[pos + 1];
365
- if (twoChar === "==") {
366
- tokens.push({
367
- type: "EQ",
368
- value: "==",
369
- position: pos
370
- });
371
- pos += 2;
372
- continue;
373
- }
374
- if (twoChar === "!=") {
375
- tokens.push({
376
- type: "NEQ",
377
- value: "!=",
378
- position: pos
379
- });
380
- pos += 2;
381
- continue;
382
- }
383
- if (twoChar === ">=") {
384
- tokens.push({
385
- type: "GTE",
386
- value: ">=",
387
- position: pos
388
- });
389
- pos += 2;
390
- continue;
391
- }
392
- if (twoChar === "<=") {
393
- tokens.push({
394
- type: "LTE",
395
- value: "<=",
396
- position: pos
397
- });
398
- pos += 2;
399
- continue;
400
- }
401
- if (twoChar === "&&") {
402
- tokens.push({
403
- type: "AND",
404
- value: "&&",
405
- position: pos
406
- });
407
- pos += 2;
408
- continue;
409
- }
410
- if (twoChar === "||") {
411
- tokens.push({
412
- type: "OR",
413
- value: "||",
414
- position: pos
415
- });
416
- pos += 2;
417
- continue;
418
- }
419
- }
420
- if (ch === ">") {
421
- tokens.push({
422
- type: "GT",
423
- value: ">",
424
- position: pos
425
- });
426
- pos++;
427
- continue;
428
- }
429
- if (ch === "<") {
430
- tokens.push({
431
- type: "LT",
432
- value: "<",
433
- position: pos
434
- });
435
- pos++;
436
- continue;
437
- }
438
- if (ch === "!") {
439
- tokens.push({
440
- type: "NOT",
441
- value: "!",
442
- position: pos
443
- });
444
- pos++;
445
- continue;
446
- }
447
- if (/[0-9]/.test(ch) || ch === "-" && pos + 1 < input.length && /[0-9]/.test(input[pos + 1])) {
448
- const start = pos;
449
- if (ch === "-") pos++;
450
- while (pos < input.length && /[0-9]/.test(input[pos])) pos++;
451
- if (pos < input.length && input[pos] === ".") {
452
- pos++;
453
- while (pos < input.length && /[0-9]/.test(input[pos])) pos++;
454
- }
455
- tokens.push({
456
- type: "NUMBER",
457
- value: input.slice(start, pos),
458
- position: start
459
- });
460
- continue;
461
- }
462
- if (ch === "\"" || ch === "'") {
463
- const quote = ch;
464
- const start = pos;
465
- pos++;
466
- let str = "";
467
- while (pos < input.length && input[pos] !== quote) {
468
- if (input[pos] === "\\" && pos + 1 < input.length) pos++;
469
- str += input[pos];
470
- pos++;
471
- }
472
- if (pos >= input.length) throw new LexError(`Unterminated string literal`, start);
473
- pos++;
474
- tokens.push({
475
- type: "STRING",
476
- value: str,
477
- position: start
478
- });
479
- continue;
480
- }
481
- if (/[a-zA-Z_]/.test(ch)) {
482
- const start = pos;
483
- while (pos < input.length && /[a-zA-Z0-9_]/.test(input[pos])) pos++;
484
- const word = input.slice(start, pos);
485
- if (word === "true" || word === "false") tokens.push({
486
- type: "BOOLEAN",
487
- value: word,
488
- position: start
489
- });
490
- else if (word === "null") tokens.push({
491
- type: "NULL",
492
- value: word,
493
- position: start
494
- });
495
- else if (word === "contains") tokens.push({
496
- type: "CONTAINS",
497
- value: word,
498
- position: start
499
- });
500
- else tokens.push({
501
- type: "IDENTIFIER",
502
- value: word,
503
- position: start
504
- });
505
- continue;
506
- }
507
- throw new LexError(`Unexpected character: ${ch}`, pos);
508
- }
509
- tokens.push({
510
- type: "EOF",
511
- value: "",
512
- position: pos
513
- });
514
- return tokens;
515
- }
516
-
517
- //#endregion
518
- //#region src/expression/parser.ts
519
- var ParseExprError = class extends Error {
520
- constructor(message, position) {
521
- super(message);
522
- this.position = position;
523
- this.name = "ParseExprError";
524
- }
525
- };
526
- function parseExpression(tokens) {
527
- let pos = 0;
528
- function current() {
529
- return tokens[pos];
530
- }
531
- function expect(type) {
532
- const tok = current();
533
- if (tok.type !== type) throw new ParseExprError(`Expected ${type} but got ${tok.type} ("${tok.value}")`, tok.position);
534
- pos++;
535
- return tok;
536
- }
537
- function peek() {
538
- return tokens[pos];
539
- }
540
- function parseOr() {
541
- let left = parseAnd();
542
- while (peek().type === "OR") {
543
- const op = current().value;
544
- pos++;
545
- const right = parseAnd();
546
- left = {
547
- kind: "binary",
548
- operator: op,
549
- left,
550
- right
551
- };
552
- }
553
- return left;
554
- }
555
- function parseAnd() {
556
- let left = parseComparison();
557
- while (peek().type === "AND") {
558
- const op = current().value;
559
- pos++;
560
- const right = parseComparison();
561
- left = {
562
- kind: "binary",
563
- operator: op,
564
- left,
565
- right
566
- };
567
- }
568
- return left;
569
- }
570
- function parseComparison() {
571
- let left = parseUnary();
572
- const t = peek().type;
573
- if (t === "EQ" || t === "NEQ" || t === "GT" || t === "GTE" || t === "LT" || t === "LTE" || t === "CONTAINS") {
574
- const op = current().value;
575
- pos++;
576
- const right = parseUnary();
577
- left = {
578
- kind: "binary",
579
- operator: op,
580
- left,
581
- right
582
- };
583
- }
584
- return left;
585
- }
586
- function parseUnary() {
587
- if (peek().type === "NOT") {
588
- const op = current().value;
589
- pos++;
590
- return {
591
- kind: "unary",
592
- operator: op,
593
- operand: parseUnary()
594
- };
595
- }
596
- return parsePrimary();
597
- }
598
- function parsePrimary() {
599
- const tok = peek();
600
- if (tok.type === "LPAREN") {
601
- pos++;
602
- const expr = parseOr();
603
- expect("RPAREN");
604
- return expr;
605
- }
606
- if (tok.type === "DOLLAR_REF") {
607
- pos++;
608
- let node = {
609
- kind: "reference",
610
- name: tok.value
611
- };
612
- while (peek().type === "DOT" || peek().type === "LBRACKET") if (peek().type === "DOT") {
613
- pos++;
614
- const prop = current();
615
- if (prop.type === "IDENTIFIER" || prop.type === "DOLLAR_REF") {
616
- pos++;
617
- node = {
618
- kind: "property_access",
619
- object: node,
620
- property: prop.value
621
- };
622
- } else if (prop.type === "NUMBER") {
623
- pos++;
624
- node = {
625
- kind: "property_access",
626
- object: node,
627
- property: prop.value
628
- };
629
- } else throw new ParseExprError(`Expected property name after '.', got ${prop.type}`, prop.position);
630
- } else {
631
- pos++;
632
- const indexExpr = parseOr();
633
- expect("RBRACKET");
634
- node = {
635
- kind: "index_access",
636
- object: node,
637
- index: indexExpr
638
- };
639
- }
640
- return node;
641
- }
642
- if (tok.type === "NUMBER") {
643
- pos++;
644
- return {
645
- kind: "literal",
646
- value: tok.value.includes(".") ? parseFloat(tok.value) : parseInt(tok.value, 10)
647
- };
648
- }
649
- if (tok.type === "STRING") {
650
- pos++;
651
- return {
652
- kind: "literal",
653
- value: tok.value
654
- };
655
- }
656
- if (tok.type === "BOOLEAN") {
657
- pos++;
658
- return {
659
- kind: "literal",
660
- value: tok.value === "true"
661
- };
662
- }
663
- if (tok.type === "NULL") {
664
- pos++;
665
- return {
666
- kind: "literal",
667
- value: null
668
- };
669
- }
670
- throw new ParseExprError(`Unexpected token: ${tok.type} ("${tok.value}")`, tok.position);
671
- }
672
- const ast = parseOr();
673
- if (peek().type !== "EOF") {
674
- const leftover = peek();
675
- throw new ParseExprError(`Unexpected token after expression: ${leftover.type} ("${leftover.value}")`, leftover.position);
676
- }
677
- return ast;
678
- }
679
-
680
- //#endregion
681
- //#region src/expression/evaluator.ts
682
- var EvalError = class extends Error {
683
- constructor(message) {
684
- super(message);
685
- this.name = "EvalError";
686
- }
687
- };
688
- /**
689
- * Evaluate an AST node against a runtime context.
690
- * Returns the resolved value (primitive, object, array, or null).
691
- */
692
- function evaluate(node, context) {
693
- switch (node.kind) {
694
- case "reference": return resolveReference(node.name, context);
695
- case "property_access": return resolvePropertyAccess(node, context);
696
- case "index_access": return resolveIndexAccess(node, context);
697
- case "literal": return node.value;
698
- case "binary": return evaluateBinary(node.operator, node.left, node.right, context);
699
- case "unary": return evaluateUnary(node.operator, node.operand, context);
700
- }
701
- }
702
- function resolveReference(name, context) {
703
- switch (name) {
704
- case "inputs": return context.inputs;
705
- case "steps": return context.steps;
706
- case "item": return context.item;
707
- case "index": return context.index;
708
- case "result": return context.result;
709
- default: throw new EvalError(`Unknown reference: $${name}`);
710
- }
711
- }
712
- function resolvePropertyAccess(node, context) {
713
- const obj = evaluate(node.object, context);
714
- if (obj === null || obj === void 0) return;
715
- if (node.property === "length" && Array.isArray(obj)) return obj.length;
716
- if (typeof obj === "object") return obj[node.property];
717
- }
718
- function resolveIndexAccess(node, context) {
719
- const obj = evaluate(node.object, context);
720
- const idx = evaluate(node.index, context);
721
- if (obj === null || obj === void 0) return;
722
- if (Array.isArray(obj) && typeof idx === "number") return obj[idx];
723
- if (typeof obj === "object") {
724
- const key = typeof idx === "number" ? String(idx) : idx;
725
- if (typeof key === "string") return obj[key];
726
- }
727
- }
728
- function evaluateBinary(op, left, right, context) {
729
- const lval = evaluate(left, context);
730
- const rval = evaluate(right, context);
731
- switch (op) {
732
- case "==": return lval === rval;
733
- case "!=": return lval !== rval;
734
- case ">": return toNumber(lval) > toNumber(rval);
735
- case "<": return toNumber(lval) < toNumber(rval);
736
- case ">=": return toNumber(lval) >= toNumber(rval);
737
- case "<=": return toNumber(lval) <= toNumber(rval);
738
- case "&&": return isTruthy(lval) && isTruthy(rval);
739
- case "||": return isTruthy(lval) || isTruthy(rval);
740
- case "contains":
741
- if (Array.isArray(lval)) return lval.includes(rval);
742
- return String(lval ?? "").includes(String(rval ?? ""));
743
- default: throw new EvalError(`Unknown operator: ${op}`);
744
- }
745
- }
746
- function evaluateUnary(op, operand, context) {
747
- const val = evaluate(operand, context);
748
- switch (op) {
749
- case "!": return !isTruthy(val);
750
- default: throw new EvalError(`Unknown unary operator: ${op}`);
751
- }
752
- }
753
- function toNumber(val) {
754
- if (typeof val === "number") return val;
755
- if (typeof val === "string") {
756
- const n = Number(val);
757
- if (!isNaN(n)) return n;
758
- }
759
- if (typeof val === "boolean") return val ? 1 : 0;
760
- return 0;
761
- }
762
- function isTruthy(val) {
763
- if (val === null || val === void 0) return false;
764
- if (typeof val === "boolean") return val;
765
- if (typeof val === "number") return val !== 0;
766
- if (typeof val === "string") return val.length > 0;
767
- if (Array.isArray(val)) return val.length > 0;
768
- return true;
769
- }
770
-
771
- //#endregion
772
- //#region src/expression/index.ts
773
- /**
774
- * Resolve a single expression string against a runtime context.
775
- * Used for source, condition, where, each, and output fields.
776
- * Example: "$steps.fetch.output.messages.length >= 5"
777
- */
778
- function resolveExpression(expr, context) {
779
- return evaluate(parseExpression(lex(expr)), context);
780
- }
781
- /**
782
- * Interpolate $-references in a prompt template string.
783
- * Only resolves references and property access (no operators).
784
- * Objects/arrays are serialized as JSON. Null → empty string.
785
- *
786
- * Example: "Score this email: $steps.fetch.output.subject"
787
- */
788
- function interpolatePrompt(template, context) {
789
- return template.replace(/\$([a-zA-Z_][a-zA-Z0-9_]*)(\.[a-zA-Z_][a-zA-Z0-9_]*|\[[^\]]*\])*/g, (match) => {
790
- try {
791
- return stringify(resolveExpression(match, context));
792
- } catch {
793
- return match;
794
- }
795
- });
796
- }
797
- /**
798
- * Returns true if the string contains at least one ${...} template block.
799
- */
800
- function containsTemplate(value) {
801
- return /\$\{[^}]+\}/.test(value);
802
- }
803
- /**
804
- * Resolve a ${...} template string against a runtime context.
805
- *
806
- * Two modes:
807
- * - Whole-value `${ref}` (nothing else) — type is preserved (not coerced to string).
808
- * - Multi-block — each `${ref}` is evaluated and spliced into the surrounding string.
809
- * Use `$${` to produce a literal `${` inside a template.
810
- *
811
- * Inside `${...}`, references omit the leading `$` (the `$` is part of the delimiter).
812
- * Example: `"https://example.com?q=${inputs.query}"` → resolves `$inputs.query`.
813
- */
814
- function resolveTemplate(template, context) {
815
- const single = template.match(/^\$\{([^}]+)\}$/);
816
- if (single) return resolveExpression("$" + single[1], context);
817
- return template.replace(/\$\$\{|\$\{([^}]+)\}/g, (match, expr) => {
818
- if (match === "$${") return "${";
819
- return stringify(resolveExpression("$" + expr, context));
820
- });
821
- }
822
- /**
823
- * Coerce a value to its string representation for prompt interpolation.
824
- * Per the spec: objects/arrays → JSON, null → empty string.
825
- */
826
- function stringify(value) {
827
- if (value === null || value === void 0) return "";
828
- if (typeof value === "string") return value;
829
- if (typeof value === "number" || typeof value === "boolean") return String(value);
830
- return JSON.stringify(value);
831
- }
832
-
833
- //#endregion
834
- //#region src/parser/parse-content.ts
835
- /**
836
- * Parse content that is either a full SKILL.md or a bare workflow YAML block.
837
- * Never throws — failures are encoded in the returned union.
838
- */
839
- function parseContent(content) {
840
- if (!content.trim()) return {
841
- ok: false,
842
- message: "Content is empty"
843
- };
844
- try {
845
- const skill = parseSkillMd(content);
846
- return {
847
- ok: true,
848
- workflow: skill.workflow,
849
- name: skill.frontmatter.name
850
- };
851
- } catch {}
852
- try {
853
- return {
854
- ok: true,
855
- workflow: parseWorkflowFromMd(content),
856
- name: void 0
857
- };
858
- } catch (err) {
859
- let message;
860
- let details;
861
- if (err instanceof ParseError) {
862
- message = err.message;
863
- details = err.details.length > 0 ? err.details : void 0;
864
- } else message = err instanceof Error ? err.message : String(err);
865
- return {
866
- ok: false,
867
- message,
868
- details
869
- };
870
- }
871
- }
872
-
873
- //#endregion
874
- //#region src/validator/index.ts
875
- /**
876
- * Validate a workflow definition before execution.
877
- * Checks structural correctness, reference graph, type compatibility, and tool availability.
878
- * Returns all errors found — does not fail fast.
879
- */
880
- function validateWorkflow(workflow, toolAdapter) {
881
- const errors = [];
882
- const stepMap = /* @__PURE__ */ new Map();
883
- const stepOrder = /* @__PURE__ */ new Map();
884
- for (let i = 0; i < workflow.steps.length; i++) {
885
- const step = workflow.steps[i];
886
- stepOrder.set(step.id, i);
887
- if (stepMap.has(step.id)) errors.push({
888
- path: `steps[${i}].id`,
889
- message: `Duplicate step ID "${step.id}"`
890
- });
891
- stepMap.set(step.id, step);
892
- }
893
- const branchStepIds = /* @__PURE__ */ new Set();
894
- for (const step of workflow.steps) if (step.type === "conditional") {
895
- for (const id of step.then) branchStepIds.add(id);
896
- if (step.else) for (const id of step.else) branchStepIds.add(id);
897
- }
898
- for (let i = 0; i < workflow.steps.length; i++) {
899
- const step = workflow.steps[i];
900
- const path = `steps[${i}]`;
901
- if (step.each && step.type === "exit") errors.push({
902
- path: `${path}.each`,
903
- message: `"each" is not valid on exit steps`
904
- });
905
- if (step.each && step.type === "conditional") errors.push({
906
- path: `${path}.each`,
907
- message: `"each" is not valid on conditional steps`
908
- });
909
- if (step.delay && !step.each) errors.push({
910
- path: `${path}.delay`,
911
- message: `"delay" requires "each" to be present`
912
- });
913
- if (step.type === "tool" && toolAdapter && !toolAdapter.has(step.tool)) errors.push({
914
- path: `${path}.tool`,
915
- message: `Tool "${step.tool}" is not registered`
916
- });
917
- for (const [inputName, input] of Object.entries(step.inputs)) if (typeof input.value === "string" && hasStepReferences(input.value)) validateSourceReference(input.value, step.id, `${path}.inputs.${inputName}.value`, stepMap, stepOrder, branchStepIds, errors);
918
- if (step.condition) validateExpressionReferences(step.condition, step.id, `${path}.condition`, stepMap, stepOrder, branchStepIds, errors);
919
- if (step.each) validateExpressionReferences(step.each, step.id, `${path}.each`, stepMap, stepOrder, branchStepIds, errors);
920
- if (step.type === "conditional") validateBranchReferences(step, i, stepMap, errors);
921
- if (step.type === "exit" && step.output) {
922
- if (typeof step.output === "string") validateExpressionReferences(step.output, step.id, `${path}.output`, stepMap, stepOrder, branchStepIds, errors);
923
- else for (const [key, val] of Object.entries(step.output)) if (typeof val === "string" && val.startsWith("$")) validateExpressionReferences(val, step.id, `${path}.output.${key}`, stepMap, stepOrder, branchStepIds, errors);
924
- }
925
- }
926
- for (const [outputName, outputDef] of Object.entries(workflow.outputs)) if (typeof outputDef.value === "string" && hasStepReferences(outputDef.value)) {
927
- const refs = extractStepReferences(outputDef.value);
928
- for (const refId of refs) if (!stepMap.has(refId)) errors.push({
929
- path: `outputs.${outputName}.value`,
930
- message: `References undefined step "${refId}"`
931
- });
932
- }
933
- const cycleErrors = detectCycles(workflow.steps, stepMap);
934
- errors.push(...cycleErrors);
935
- return {
936
- valid: errors.length === 0,
937
- errors
938
- };
939
- }
940
- /**
941
- * Extract step IDs referenced from an expression or template string.
942
- * Handles both expression form ($steps.<id>) and template form (${steps.<id>...}).
943
- */
944
- function extractStepReferences(expr) {
945
- const refs = [];
946
- const exprRegex = /\$steps\.([a-zA-Z_][a-zA-Z0-9_]*)/g;
947
- const tmplRegex = /\$\{steps\.([a-zA-Z_][a-zA-Z0-9_]*)/g;
948
- let match;
949
- while ((match = exprRegex.exec(expr)) !== null) refs.push(match[1]);
950
- while ((match = tmplRegex.exec(expr)) !== null) refs.push(match[1]);
951
- return [...new Set(refs)];
952
- }
953
- /** Returns true if the string contains $steps references in either expression or template form. */
954
- function hasStepReferences(value) {
955
- return value.startsWith("$steps.") || /\$\{steps\./.test(value);
956
- }
957
- /**
958
- * Validate that a source expression references valid, earlier-defined steps.
959
- */
960
- function validateSourceReference(source, currentStepId, path, stepMap, stepOrder, branchStepIds, errors) {
961
- const refs = extractStepReferences(source);
962
- const currentOrder = stepOrder.get(currentStepId) ?? -1;
963
- for (const refId of refs) if (!stepMap.has(refId)) errors.push({
964
- path,
965
- message: `References undefined step "${refId}"`
966
- });
967
- else if ((stepOrder.get(refId) ?? -1) >= currentOrder && !branchStepIds.has(currentStepId)) errors.push({
968
- path,
969
- message: `Step "${currentStepId}" references step "${refId}" which is not declared before it`
970
- });
971
- }
972
- /**
973
- * Validate expression references (condition, each, output).
974
- */
975
- function validateExpressionReferences(expr, currentStepId, path, stepMap, stepOrder, branchStepIds, errors) {
976
- const refs = extractStepReferences(expr);
977
- const currentOrder = stepOrder.get(currentStepId) ?? -1;
978
- for (const refId of refs) if (!stepMap.has(refId)) errors.push({
979
- path,
980
- message: `References undefined step "${refId}"`
981
- });
982
- else if ((stepOrder.get(refId) ?? -1) >= currentOrder && !branchStepIds.has(currentStepId)) errors.push({
983
- path,
984
- message: `Step "${currentStepId}" references step "${refId}" which is not declared before it`
985
- });
986
- }
987
- /**
988
- * Validate conditional step branch references.
989
- */
990
- function validateBranchReferences(step, stepIndex, stepMap, errors) {
991
- const path = `steps[${stepIndex}]`;
992
- for (const id of step.then) if (!stepMap.has(id)) errors.push({
993
- path: `${path}.then`,
994
- message: `Branch references undefined step "${id}"`
995
- });
996
- if (step.else) {
997
- for (const id of step.else) if (!stepMap.has(id)) errors.push({
998
- path: `${path}.else`,
999
- message: `Branch references undefined step "${id}"`
1000
- });
1001
- }
1002
- }
1003
- /**
1004
- * Detect cycles in the step reference graph.
1005
- * Steps form a DAG through $steps references. Cycles would cause infinite loops.
1006
- */
1007
- function detectCycles(steps, stepMap) {
1008
- const errors = [];
1009
- const deps = /* @__PURE__ */ new Map();
1010
- for (const step of steps) {
1011
- const stepDeps = /* @__PURE__ */ new Set();
1012
- for (const input of Object.values(step.inputs)) if (typeof input.value === "string") for (const ref of extractStepReferences(input.value)) stepDeps.add(ref);
1013
- if (step.condition) for (const ref of extractStepReferences(step.condition)) stepDeps.add(ref);
1014
- if (step.each) for (const ref of extractStepReferences(step.each)) stepDeps.add(ref);
1015
- deps.set(step.id, stepDeps);
1016
- }
1017
- const visited = /* @__PURE__ */ new Set();
1018
- const inStack = /* @__PURE__ */ new Set();
1019
- function dfs(nodeId, pathStack) {
1020
- if (inStack.has(nodeId)) {
1021
- const cycleStart = pathStack.indexOf(nodeId);
1022
- const cycle = pathStack.slice(cycleStart).concat(nodeId);
1023
- errors.push({
1024
- path: `steps`,
1025
- message: `Cycle detected: ${cycle.join(" → ")}`
1026
- });
1027
- return true;
1028
- }
1029
- if (visited.has(nodeId)) return false;
1030
- visited.add(nodeId);
1031
- inStack.add(nodeId);
1032
- pathStack.push(nodeId);
1033
- const nodeDeps = deps.get(nodeId) ?? /* @__PURE__ */ new Set();
1034
- for (const dep of nodeDeps) if (stepMap.has(dep)) dfs(dep, pathStack);
1035
- pathStack.pop();
1036
- inStack.delete(nodeId);
1037
- return false;
1038
- }
1039
- for (const step of steps) if (!visited.has(step.id)) dfs(step.id, []);
1040
- return errors;
1041
- }
1042
- /**
1043
- * Parse content and validate the workflow in one synchronous call.
1044
- * Matches the shape of the plugin's ValidateResult exactly.
1045
- */
1046
- function validateWorkflowSkill(options) {
1047
- const { content, toolAdapter } = options;
1048
- const parsed = parseContent(content);
1049
- if (!parsed.ok) return {
1050
- valid: false,
1051
- errors: parsed.details ?? [{
1052
- path: "parse",
1053
- message: parsed.message
1054
- }]
1055
- };
1056
- const result = validateWorkflow(parsed.workflow, toolAdapter);
1057
- if (!result.valid) return {
1058
- valid: false,
1059
- errors: result.errors
1060
- };
1061
- const stepTypes = [...new Set(parsed.workflow.steps.map((s) => s.type))];
1062
- return {
1063
- valid: true,
1064
- errors: [],
1065
- name: parsed.name,
1066
- stepCount: parsed.workflow.steps.length,
1067
- stepTypes
1068
- };
1069
- }
1070
-
1071
- //#endregion
1072
- //#region src/adapters/anthropic-llm-adapter.ts
1073
- /** Model alias map: short names → full model IDs. */
1074
- const MODEL_ALIASES = {
1075
- haiku: "claude-haiku-4-5-20251001",
1076
- sonnet: "claude-sonnet-4-6",
1077
- opus: "claude-opus-4-6"
1078
- };
1079
- const DEFAULT_MODEL = "claude-haiku-4-5-20251001";
1080
- function resolveModel(model, fallback = DEFAULT_MODEL) {
1081
- if (!model) return fallback;
1082
- return MODEL_ALIASES[model] ?? model;
1083
- }
1084
- var AnthropicLLMAdapter = class {
1085
- client;
1086
- constructor(apiKey) {
1087
- this.client = new Anthropic({
1088
- apiKey,
1089
- timeout: 12e4,
1090
- maxRetries: 1
1091
- });
1092
- }
1093
- async call(model, prompt, responseFormat) {
1094
- let fullPrompt = prompt;
1095
- if (responseFormat && Object.keys(responseFormat).length > 0) fullPrompt += `\n\nRespond with valid JSON matching this schema: ${JSON.stringify(responseFormat)}`;
1096
- const response = await this.client.messages.create({
1097
- model: resolveModel(model),
1098
- max_tokens: 4096,
1099
- messages: [{
1100
- role: "user",
1101
- content: fullPrompt
1102
- }]
1103
- });
1104
- const textBlock = response.content.find((block) => block.type === "text");
1105
- return {
1106
- text: textBlock && "text" in textBlock ? textBlock.text : "",
1107
- tokens: {
1108
- input: response.usage.input_tokens,
1109
- output: response.usage.output_tokens
1110
- }
1111
- };
1112
- }
1113
- };
1114
-
1115
- //#endregion
1116
- //#region src/tools/builtin-tool-adapter.ts
1117
- var BuiltinToolAdapter = class BuiltinToolAdapter {
1118
- tools = /* @__PURE__ */ new Map();
1119
- register(descriptor, handler) {
1120
- this.tools.set(descriptor.name, {
1121
- handler,
1122
- descriptor
1123
- });
1124
- }
1125
- has(toolName) {
1126
- return this.tools.has(toolName);
1127
- }
1128
- list() {
1129
- return [...this.tools.values()].map((t) => t.descriptor);
1130
- }
1131
- async invoke(toolName, args) {
1132
- const entry = this.tools.get(toolName);
1133
- if (!entry) return {
1134
- output: null,
1135
- error: `Tool "${toolName}" not registered`
1136
- };
1137
- return entry.handler(args);
1138
- }
1139
- /**
1140
- * Create a BuiltinToolAdapter with all bundled tools registered.
1141
- */
1142
- static async create() {
1143
- const adapter = new BuiltinToolAdapter();
1144
- const scrapeMod = await import("./web-scrape-GeEM_JNl.mjs");
1145
- adapter.register(scrapeMod.descriptor, scrapeMod.handler);
1146
- return adapter;
1147
- }
1148
- };
1149
-
1150
- //#endregion
1151
- //#region src/config/index.ts
1152
- /**
1153
- * Parse a .env file into key-value pairs.
1154
- * Supports KEY=VALUE format, blank lines, and # comments.
1155
- * Values may be optionally quoted with single or double quotes.
1156
- */
1157
- function parseDotenv(content) {
1158
- const vars = {};
1159
- for (const line of content.split("\n")) {
1160
- const trimmed = line.trim();
1161
- if (!trimmed || trimmed.startsWith("#")) continue;
1162
- const eqIdx = trimmed.indexOf("=");
1163
- if (eqIdx === -1) continue;
1164
- const key = trimmed.slice(0, eqIdx).trim();
1165
- let value = trimmed.slice(eqIdx + 1).trim();
1166
- if (value.startsWith("\"") && value.endsWith("\"") || value.startsWith("'") && value.endsWith("'")) value = value.slice(1, -1);
1167
- vars[key] = value;
1168
- }
1169
- return vars;
1170
- }
1171
- /**
1172
- * Find the package root by walking up from this module's directory
1173
- * until we find a directory containing package.json.
1174
- */
1175
- function findPackageRoot() {
1176
- let dir = dirname(fileURLToPath(import.meta.url));
1177
- while (true) {
1178
- if (existsSync(join(dir, "package.json"))) return dir;
1179
- const parent = dirname(dir);
1180
- if (parent === dir) break;
1181
- dir = parent;
1182
- }
1183
- }
1184
- /**
1185
- * Load configuration from environment variables, with .env fallback.
1186
- * Environment variables take precedence over .env file values.
1187
- *
1188
- * .env search order:
1189
- * 1. Explicit `cwd` parameter (for tests)
1190
- * 2. Package root (found by walking up from this module)
1191
- * 3. process.cwd()
1192
- */
1193
- function loadConfig(cwd) {
1194
- let dotenvVars = {};
1195
- const searchDirs = cwd ? [cwd] : [findPackageRoot(), process.cwd()].filter((d) => d !== void 0);
1196
- for (const dir of searchDirs) try {
1197
- dotenvVars = parseDotenv(readFileSync(join(dir, ".env"), "utf-8"));
1198
- break;
1199
- } catch {}
1200
- const get = (key) => process.env[key] ?? dotenvVars[key];
1201
- const config = {};
1202
- const anthropicKey = get("ANTHROPIC_API_KEY");
1203
- if (anthropicKey) config.anthropicApiKey = anthropicKey;
1204
- return config;
1205
- }
1206
-
1207
- //#endregion
1208
- //#region src/executor/transform.ts
1209
- /**
1210
- * Execute a transform step.
1211
- * Returns an object with the first declared output key mapped to the transformed array.
1212
- */
1213
- function executeTransform(step, resolvedInputs, context) {
1214
- const items = getInputArray(resolvedInputs);
1215
- let result;
1216
- switch (step.operation) {
1217
- case "filter":
1218
- result = executeFilter(step, items, context);
1219
- break;
1220
- case "map":
1221
- result = executeMap(step, items, context);
1222
- break;
1223
- case "sort":
1224
- result = executeSort(step, items);
1225
- break;
1226
- }
1227
- return { [Object.keys(step.outputs)[0] ?? "items"]: result };
1228
- }
1229
- /** Find the array to transform from resolved inputs. */
1230
- function getInputArray(inputs) {
1231
- if ("items" in inputs && Array.isArray(inputs.items)) return inputs.items;
1232
- for (const val of Object.values(inputs)) if (Array.isArray(val)) return val;
1233
- const first = Object.values(inputs)[0];
1234
- return first != null ? [first] : [];
1235
- }
1236
- /** Filter: keep items where the `where` expression is truthy. */
1237
- function executeFilter(step, items, context) {
1238
- return items.filter((item, index) => {
1239
- const itemCtx = {
1240
- ...context,
1241
- item,
1242
- index
1243
- };
1244
- return Boolean(resolveExpression(step.where, itemCtx));
1245
- });
1246
- }
1247
- /** Map: project each item into a new shape using the `expression` object. */
1248
- function executeMap(step, items, context) {
1249
- return items.map((item, index) => {
1250
- const itemCtx = {
1251
- ...context,
1252
- item,
1253
- index
1254
- };
1255
- const result = {};
1256
- for (const [key, expr] of Object.entries(step.expression)) result[key] = resolveMapValue(expr, itemCtx);
1257
- return result;
1258
- });
1259
- }
1260
- /**
1261
- * Resolve a map expression value.
1262
- * - String starting with `$` → expression reference
1263
- * - Non-string primitive (number, boolean, null) → pass through as literal
1264
- * - Object (non-array) → recurse, applying same rules to each value
1265
- * - String not starting with `$` → literal string
1266
- */
1267
- function resolveMapValue(value, context) {
1268
- if (typeof value === "string") {
1269
- if (value.startsWith("$")) return resolveExpression(value, context);
1270
- return value;
1271
- }
1272
- if (value !== null && typeof value === "object" && !Array.isArray(value)) {
1273
- const result = {};
1274
- for (const [k, v] of Object.entries(value)) result[k] = resolveMapValue(v, context);
1275
- return result;
1276
- }
1277
- return value;
1278
- }
1279
- /** Sort: order items by a field path in the given direction (default: asc). */
1280
- function executeSort(step, items) {
1281
- const direction = step.direction ?? "asc";
1282
- return [...items].sort((a, b) => {
1283
- const aVal = getNestedField(a, step.field);
1284
- const bVal = getNestedField(b, step.field);
1285
- if (aVal == null && bVal == null) return 0;
1286
- if (aVal == null) return 1;
1287
- if (bVal == null) return -1;
1288
- if (aVal < bVal) return direction === "asc" ? -1 : 1;
1289
- if (aVal > bVal) return direction === "asc" ? 1 : -1;
1290
- return 0;
1291
- });
1292
- }
1293
- /** Access a nested field by dot-notation path (e.g., "user.name"). */
1294
- function getNestedField(obj, path) {
1295
- const parts = path.split(".");
1296
- let current = obj;
1297
- for (const part of parts) {
1298
- if (current == null || typeof current !== "object") return void 0;
1299
- current = current[part];
1300
- }
1301
- return current;
1302
- }
1303
-
1304
- //#endregion
1305
- //#region src/executor/conditional.ts
1306
- /**
1307
- * Execute a conditional step.
1308
- * Evaluates the condition expression and returns the branch to execute.
1309
- * The runtime is responsible for executing the branch steps.
1310
- */
1311
- function executeConditional(step, context) {
1312
- const conditionResult = resolveExpression(step.condition, context);
1313
- if (Boolean(conditionResult)) return {
1314
- branch: "then",
1315
- stepIds: step.then
1316
- };
1317
- else if (step.else) return {
1318
- branch: "else",
1319
- stepIds: step.else
1320
- };
1321
- else return {
1322
- branch: null,
1323
- stepIds: []
1324
- };
1325
- }
1326
-
1327
- //#endregion
1328
- //#region src/executor/exit.ts
1329
- /**
1330
- * Execute an exit step.
1331
- * Output can be:
1332
- * - A string expression: resolved against context
1333
- * - An object literal: each string value starting with $ is resolved, others kept as-is
1334
- * - Undefined: null output
1335
- */
1336
- function executeExit(step, context) {
1337
- let output = null;
1338
- if (step.output) if (typeof step.output === "string") output = resolveExpression(step.output, context);
1339
- else output = resolveOutputObject(step.output, context);
1340
- return {
1341
- status: step.status,
1342
- output
1343
- };
1344
- }
1345
- function resolveOutputObject(obj, context) {
1346
- const result = {};
1347
- for (const [key, val] of Object.entries(obj)) if (typeof val === "string") if (val.startsWith("$$")) result[key] = val.slice(1);
1348
- else if (containsTemplate(val)) result[key] = resolveTemplate(val, context);
1349
- else if (val.startsWith("$")) result[key] = resolveExpression(val, context);
1350
- else result[key] = val;
1351
- else result[key] = val;
1352
- return result;
1353
- }
1354
-
1355
- //#endregion
1356
- //#region src/executor/types.ts
1357
- /** Error thrown by step executors. */
1358
- var StepExecutionError = class extends Error {
1359
- constructor(message, retriable = false, context) {
1360
- super(message);
1361
- this.retriable = retriable;
1362
- this.context = context;
1363
- this.name = "StepExecutionError";
1364
- }
1365
- };
1366
-
1367
- //#endregion
1368
- //#region src/executor/tool.ts
1369
- /**
1370
- * Execute a tool step.
1371
- * Passes resolved inputs as the tool's arguments. Returns the tool's response.
1372
- * The runtime does not interpret the response (per spec).
1373
- */
1374
- async function executeTool(step, resolvedInputs, toolAdapter) {
1375
- const result = await toolAdapter.invoke(step.tool, resolvedInputs);
1376
- if (result.error) throw new StepExecutionError(result.error, true, { tool: step.tool });
1377
- return { output: result.output };
1378
- }
1379
-
1380
- //#endregion
1381
- //#region src/executor/llm.ts
1382
- /**
1383
- * Execute an LLM step.
1384
- * Interpolates $-references in the prompt, calls the model, and returns the response.
1385
- * The response_format field is passed as a hint but not enforced (per spec).
1386
- * If the response is valid JSON, it's parsed; otherwise returned as text.
1387
- */
1388
- async function executeLLM(step, _resolvedInputs, context, llmAdapter) {
1389
- const prompt = interpolatePrompt(step.prompt, context);
1390
- let result;
1391
- try {
1392
- result = await llmAdapter.call(step.model, prompt, step.response_format);
1393
- } catch (err) {
1394
- throw new StepExecutionError(err instanceof Error ? err.message : String(err), true);
1395
- }
1396
- let output = result.text;
1397
- try {
1398
- output = JSON.parse(result.text);
1399
- } catch {}
1400
- return {
1401
- output,
1402
- tokens: result.tokens
1403
- };
1404
- }
1405
-
1406
- //#endregion
1407
- //#region src/executor/index.ts
1408
- /**
1409
- * Dispatch a step to the appropriate executor.
1410
- * The runtime calls this for each step in the execution loop.
1411
- */
1412
- async function dispatch(step, resolvedInputs, context, toolAdapter, llmAdapter) {
1413
- switch (step.type) {
1414
- case "tool": return {
1415
- kind: "output",
1416
- ...await executeTool(step, resolvedInputs, toolAdapter)
1417
- };
1418
- case "llm": return {
1419
- kind: "output",
1420
- ...await executeLLM(step, resolvedInputs, context, llmAdapter)
1421
- };
1422
- case "transform": return {
1423
- kind: "output",
1424
- output: executeTransform(step, resolvedInputs, context)
1425
- };
1426
- case "conditional": return {
1427
- kind: "branch",
1428
- ...executeConditional(step, context)
1429
- };
1430
- case "exit": return {
1431
- kind: "exit",
1432
- ...executeExit(step, context)
1433
- };
1434
- }
1435
- }
1436
-
1437
- //#endregion
1438
- //#region src/runtime/index.ts
1439
- /** Resolve a value field:
1440
- * 1. starts with $$ → strip one $ (literal escape)
1441
- * 2. contains ${...} → template interpolation
1442
- * 3. starts with $ → whole expression
1443
- * 4. otherwise → literal
1444
- */
1445
- function resolveValue(value, context) {
1446
- if (typeof value !== "string") return value;
1447
- if (value.startsWith("$$")) return value.slice(1);
1448
- if (containsTemplate(value)) return resolveTemplate(value, context);
1449
- if (value.startsWith("$")) return resolveExpression(value, context);
1450
- return value;
1451
- }
1452
- /** Emit a runtime event if a callback is registered. */
1453
- function emit(onEvent, event) {
1454
- onEvent?.(event);
1455
- }
1456
- var WorkflowExecutionError = class extends Error {
1457
- constructor(message, validationErrors) {
1458
- super(message);
1459
- this.validationErrors = validationErrors;
1460
- this.name = "WorkflowExecutionError";
1461
- }
1462
- };
1463
- /**
1464
- * Build a minimal RunLog for a pre-execution failure (parse or validate phase).
1465
- * Every run attempt — even those that fail before execution begins — produces a structured artifact.
1466
- */
1467
- function buildFailedRunLog(workflowName, error, startedAt) {
1468
- const now = /* @__PURE__ */ new Date();
1469
- const start = startedAt ?? now;
1470
- const durationMs = now.getTime() - start.getTime();
1471
- return {
1472
- id: crypto.randomUUID(),
1473
- workflow: workflowName,
1474
- status: "failed",
1475
- summary: {
1476
- steps_executed: 0,
1477
- steps_skipped: 0,
1478
- total_tokens: 0,
1479
- total_duration_ms: durationMs
1480
- },
1481
- started_at: start.toISOString(),
1482
- completed_at: now.toISOString(),
1483
- duration_ms: durationMs,
1484
- inputs: {},
1485
- steps: [],
1486
- outputs: {},
1487
- error
1488
- };
1489
- }
1490
- /**
1491
- * Execute a workflow and produce a run log.
1492
- * Phase 1: Validate the workflow definition.
1493
- * Phase 2: Execute steps in declaration order following the 8-step lifecycle.
1494
- */
1495
- async function runWorkflow(options) {
1496
- const { onEvent } = options;
1497
- const startedAt = /* @__PURE__ */ new Date();
1498
- const validation = validateWorkflow(options.workflow, options.toolAdapter);
1499
- if (!validation.valid) {
1500
- const message = `Workflow validation failed: ${validation.errors.map((e) => e.message).join("; ")}`;
1501
- return buildFailedRunLog(options.workflowName ?? "unnamed", {
1502
- phase: "validate",
1503
- message,
1504
- details: validation.errors
1505
- }, startedAt);
1506
- }
1507
- const workflowName = options.workflowName ?? "unnamed";
1508
- emit(onEvent, {
1509
- type: "workflow_start",
1510
- workflow: workflowName,
1511
- totalSteps: options.workflow.steps.length
1512
- });
1513
- const inputs = applyDefaults(options.workflow.inputs, options.inputs ?? {});
1514
- const context = {
1515
- inputs,
1516
- steps: {}
1517
- };
1518
- const stepRecords = [];
1519
- const branchStepIds = collectBranchStepIds(options.workflow.steps);
1520
- const stepMap = new Map(options.workflow.steps.map((s) => [s.id, s]));
1521
- let workflowStatus = "success";
1522
- let workflowOutput = null;
1523
- let exitFired = false;
1524
- let halted = false;
1525
- for (const step of options.workflow.steps) {
1526
- if (halted) break;
1527
- if (branchStepIds.has(step.id)) continue;
1528
- const result = await executeStepLifecycle(step, context, stepMap, branchStepIds, options.toolAdapter, options.llmAdapter, onEvent);
1529
- stepRecords.push(...result.records);
1530
- if (result.exit) {
1531
- halted = true;
1532
- exitFired = true;
1533
- workflowStatus = result.exit.status === "failed" ? "failed" : "success";
1534
- workflowOutput = result.exit.output;
1535
- } else if (result.failed) {
1536
- halted = true;
1537
- workflowStatus = "failed";
1538
- } else workflowOutput = context.steps[step.id]?.output ?? null;
1539
- }
1540
- const recordedIds = new Set(stepRecords.map((r) => r.id));
1541
- for (const step of options.workflow.steps) if (!recordedIds.has(step.id)) {
1542
- const reason = branchStepIds.has(step.id) ? "Branch not selected" : "Workflow halted";
1543
- emit(onEvent, {
1544
- type: "step_skip",
1545
- stepId: step.id,
1546
- reason
1547
- });
1548
- stepRecords.push({
1549
- id: step.id,
1550
- executor: step.type,
1551
- status: "skipped",
1552
- reason,
1553
- duration_ms: 0
1554
- });
1555
- }
1556
- const outputs = buildWorkflowOutputs(options.workflow, workflowOutput, context, exitFired);
1557
- const completedAt = /* @__PURE__ */ new Date();
1558
- const durationMs = completedAt.getTime() - startedAt.getTime();
1559
- let stepsExecuted = 0;
1560
- let stepsSkipped = 0;
1561
- let totalTokens = 0;
1562
- for (const rec of stepRecords) {
1563
- if (rec.status === "skipped") stepsSkipped++;
1564
- else stepsExecuted++;
1565
- if (rec.tokens) totalTokens += rec.tokens.input + rec.tokens.output;
1566
- }
1567
- const summary = {
1568
- steps_executed: stepsExecuted,
1569
- steps_skipped: stepsSkipped,
1570
- total_tokens: totalTokens,
1571
- total_duration_ms: durationMs
1572
- };
1573
- emit(onEvent, {
1574
- type: "workflow_complete",
1575
- status: workflowStatus,
1576
- duration_ms: durationMs,
1577
- summary
1578
- });
1579
- return {
1580
- id: crypto.randomUUID(),
1581
- workflow: workflowName,
1582
- status: workflowStatus,
1583
- summary,
1584
- started_at: startedAt.toISOString(),
1585
- completed_at: completedAt.toISOString(),
1586
- duration_ms: durationMs,
1587
- inputs,
1588
- steps: stepRecords,
1589
- outputs
1590
- };
1591
- }
1592
- /**
1593
- * Parse content and execute the workflow in one call. Never throws.
1594
- * Empty or unparseable content → failed RunLog (phase: 'parse').
1595
- * Unexpected execution exception → failed RunLog (phase: 'execute').
1596
- * Validation failures are handled internally by runWorkflow.
1597
- */
1598
- async function runWorkflowSkill(options) {
1599
- const { content, inputs, toolAdapter, llmAdapter, workflowName = "inline", onEvent } = options;
1600
- const startedAt = /* @__PURE__ */ new Date();
1601
- const parsed = parseContent(content);
1602
- if (!parsed.ok) return buildFailedRunLog(workflowName, {
1603
- phase: "parse",
1604
- message: parsed.message,
1605
- details: parsed.details
1606
- }, startedAt);
1607
- const resolvedName = parsed.name ?? workflowName;
1608
- try {
1609
- return await runWorkflow({
1610
- workflow: parsed.workflow,
1611
- inputs,
1612
- toolAdapter,
1613
- llmAdapter,
1614
- workflowName: resolvedName,
1615
- onEvent
1616
- });
1617
- } catch (err) {
1618
- return buildFailedRunLog(resolvedName, {
1619
- phase: "execute",
1620
- message: err instanceof Error ? err.message : String(err)
1621
- }, startedAt);
1622
- }
1623
- }
1624
- /**
1625
- * Execute one step through the 9-step lifecycle:
1626
- * 1. Guard 2. Resolve inputs 3. Iterate (each) 4. Dispatch
1627
- * 5. Map outputs 6. Validate output 7. Retry 8. Handle errors 9. Record
1628
- */
1629
- async function executeStepLifecycle(step, context, stepMap, branchStepIds, toolAdapter, llmAdapter, onEvent) {
1630
- const startTime = performance.now();
1631
- const records = [];
1632
- if (step.condition && step.type !== "conditional") {
1633
- if (!resolveExpression(step.condition, context)) {
1634
- context.steps[step.id] = { output: null };
1635
- emit(onEvent, {
1636
- type: "step_skip",
1637
- stepId: step.id,
1638
- reason: "Guard condition evaluated to false"
1639
- });
1640
- records.push({
1641
- id: step.id,
1642
- executor: step.type,
1643
- status: "skipped",
1644
- reason: "Guard condition evaluated to false",
1645
- duration_ms: Math.round(performance.now() - startTime)
1646
- });
1647
- return { records };
1648
- }
1649
- }
1650
- emit(onEvent, {
1651
- type: "step_start",
1652
- stepId: step.id,
1653
- stepType: step.type,
1654
- tool: step.type === "tool" ? step.tool : void 0
1655
- });
1656
- if (step.each) return executeWithEach(step, context, stepMap, branchStepIds, toolAdapter, llmAdapter, startTime, onEvent);
1657
- const resolvedInputs = resolveInputs(step.inputs, context, step.id);
1658
- try {
1659
- const { result, retries } = await dispatchWithRetry(step, resolvedInputs, context, toolAdapter, llmAdapter, onEvent);
1660
- if (result.kind === "exit") {
1661
- context.steps[step.id] = { output: result.output };
1662
- const durationMs = Math.round(performance.now() - startTime);
1663
- emit(onEvent, {
1664
- type: "step_complete",
1665
- stepId: step.id,
1666
- status: "success",
1667
- duration_ms: durationMs
1668
- });
1669
- records.push({
1670
- id: step.id,
1671
- executor: "exit",
1672
- status: "success",
1673
- duration_ms: durationMs,
1674
- inputs: resolvedInputs,
1675
- output: result.output,
1676
- retries
1677
- });
1678
- return {
1679
- records,
1680
- exit: {
1681
- status: result.status,
1682
- output: result.output
1683
- }
1684
- };
1685
- }
1686
- if (result.kind === "branch") {
1687
- const branchRecords = await executeBranch(result.stepIds, context, stepMap, branchStepIds, toolAdapter, llmAdapter, onEvent);
1688
- const lastBranchStepId = result.stepIds[result.stepIds.length - 1];
1689
- const conditionalOutput = lastBranchStepId ? context.steps[lastBranchStepId]?.output ?? null : null;
1690
- context.steps[step.id] = { output: conditionalOutput };
1691
- const durationMs = Math.round(performance.now() - startTime);
1692
- emit(onEvent, {
1693
- type: "step_complete",
1694
- stepId: step.id,
1695
- status: "success",
1696
- duration_ms: durationMs
1697
- });
1698
- records.push({
1699
- id: step.id,
1700
- executor: "conditional",
1701
- status: "success",
1702
- duration_ms: durationMs,
1703
- inputs: resolvedInputs,
1704
- output: conditionalOutput,
1705
- retries
1706
- });
1707
- records.push(...branchRecords.records);
1708
- return {
1709
- records,
1710
- exit: branchRecords.exit,
1711
- failed: branchRecords.failed
1712
- };
1713
- }
1714
- const mappedOutput = applyStepOutputMapping(step.outputs, result.output, context);
1715
- context.steps[step.id] = { output: mappedOutput };
1716
- const durationMs = Math.round(performance.now() - startTime);
1717
- emit(onEvent, {
1718
- type: "step_complete",
1719
- stepId: step.id,
1720
- status: "success",
1721
- duration_ms: durationMs,
1722
- tokens: result.tokens
1723
- });
1724
- records.push({
1725
- id: step.id,
1726
- executor: step.type,
1727
- status: "success",
1728
- duration_ms: durationMs,
1729
- inputs: resolvedInputs,
1730
- output: mappedOutput,
1731
- tokens: result.tokens,
1732
- retries
1733
- });
1734
- return { records };
1735
- } catch (err) {
1736
- return handleStepError(step, err, context, startTime, resolvedInputs, void 0, onEvent);
1737
- }
1738
- }
1739
- async function executeWithEach(step, context, _stepMap, _branchStepIds, toolAdapter, llmAdapter, startTime, onEvent) {
1740
- const records = [];
1741
- const eachArray = resolveExpression(step.each, context);
1742
- if (!Array.isArray(eachArray)) return handleStepError(step, new StepExecutionError(`each expression must resolve to an array, got ${typeof eachArray}`), context, startTime, void 0, void 0, onEvent);
1743
- const baseResolvedInputs = resolveInputs(step.inputs, context, step.id);
1744
- const results = [];
1745
- let totalTokens;
1746
- let totalRetries;
1747
- try {
1748
- for (let i = 0; i < eachArray.length; i++) {
1749
- const itemContext = {
1750
- ...context,
1751
- item: eachArray[i],
1752
- index: i
1753
- };
1754
- const { result, retries } = await dispatchWithRetry(step, resolveInputs(step.inputs, itemContext, step.id), itemContext, toolAdapter, llmAdapter, onEvent);
1755
- if (retries) {
1756
- totalRetries = totalRetries ?? {
1757
- attempts: 0,
1758
- errors: []
1759
- };
1760
- totalRetries.attempts += retries.attempts;
1761
- totalRetries.errors.push(...retries.errors);
1762
- }
1763
- if (result.kind === "output") {
1764
- const mappedIterOutput = applyStepOutputMapping(step.outputs, result.output, itemContext);
1765
- results.push(mappedIterOutput);
1766
- if (result.tokens) {
1767
- totalTokens = totalTokens ?? {
1768
- input: 0,
1769
- output: 0
1770
- };
1771
- totalTokens.input += result.tokens.input;
1772
- totalTokens.output += result.tokens.output;
1773
- }
1774
- }
1775
- emit(onEvent, {
1776
- type: "each_progress",
1777
- stepId: step.id,
1778
- current: i + 1,
1779
- total: eachArray.length
1780
- });
1781
- if (step.delay && i < eachArray.length - 1) await sleep(parseDelay(step.delay));
1782
- }
1783
- } catch (err) {
1784
- return handleStepError(step, err, context, startTime, baseResolvedInputs, totalRetries, onEvent);
1785
- }
1786
- context.steps[step.id] = { output: results };
1787
- const durationMs = Math.round(performance.now() - startTime);
1788
- emit(onEvent, {
1789
- type: "step_complete",
1790
- stepId: step.id,
1791
- status: "success",
1792
- duration_ms: durationMs,
1793
- tokens: totalTokens,
1794
- iterations: eachArray.length
1795
- });
1796
- records.push({
1797
- id: step.id,
1798
- executor: step.type,
1799
- status: "success",
1800
- duration_ms: durationMs,
1801
- inputs: baseResolvedInputs,
1802
- iterations: eachArray.length,
1803
- tokens: totalTokens,
1804
- output: results,
1805
- retries: totalRetries
1806
- });
1807
- return { records };
1808
- }
1809
- async function executeBranch(stepIds, context, stepMap, branchStepIds, toolAdapter, llmAdapter, onEvent) {
1810
- const records = [];
1811
- for (const stepId of stepIds) {
1812
- const branchStep = stepMap.get(stepId);
1813
- if (!branchStep) continue;
1814
- const result = await executeStepLifecycle(branchStep, context, stepMap, branchStepIds, toolAdapter, llmAdapter, onEvent);
1815
- records.push(...result.records);
1816
- if (result.exit) return {
1817
- records,
1818
- exit: result.exit
1819
- };
1820
- if (result.failed) return {
1821
- records,
1822
- failed: true
1823
- };
1824
- }
1825
- return { records };
1826
- }
1827
- async function dispatchWithRetry(step, resolvedInputs, context, toolAdapter, llmAdapter, onEvent) {
1828
- const retryPolicy = "retry" in step ? step.retry : void 0;
1829
- const maxRetries = retryPolicy?.max ?? 0;
1830
- const baseDelay = retryPolicy ? parseDelay(retryPolicy.delay) : 0;
1831
- const backoff = retryPolicy?.backoff ?? 1;
1832
- let attempts = 0;
1833
- const retryErrors = [];
1834
- for (;;) try {
1835
- return {
1836
- result: await dispatch(step, resolvedInputs, context, toolAdapter, llmAdapter),
1837
- retries: attempts > 0 ? {
1838
- attempts,
1839
- errors: retryErrors
1840
- } : void 0
1841
- };
1842
- } catch (err) {
1843
- if (!(err instanceof StepExecutionError && err.retriable && attempts < maxRetries)) {
1844
- if (attempts > 0 && err instanceof Error) err.__retries = {
1845
- attempts,
1846
- errors: retryErrors
1847
- };
1848
- throw err;
1849
- }
1850
- const errorMessage = err instanceof Error ? err.message : String(err);
1851
- retryErrors.push(errorMessage);
1852
- attempts++;
1853
- emit(onEvent, {
1854
- type: "step_retry",
1855
- stepId: step.id,
1856
- attempt: attempts,
1857
- error: errorMessage
1858
- });
1859
- await sleep(baseDelay * Math.pow(backoff, attempts - 1));
1860
- }
1861
- }
1862
- function handleStepError(step, err, context, startTime, resolvedInputs, retries, onEvent) {
1863
- let errorMessage = err instanceof Error ? err.message : String(err);
1864
- if (err instanceof StepExecutionError && err.context?.tool) errorMessage = `Tool "${err.context.tool}": ${errorMessage}`;
1865
- const effectiveRetries = retries ?? (err instanceof Error ? err.__retries : void 0);
1866
- const onError = step.on_error ?? "fail";
1867
- const durationMs = Math.round(performance.now() - startTime);
1868
- context.steps[step.id] = { output: null };
1869
- const record = {
1870
- id: step.id,
1871
- executor: step.type,
1872
- status: "failed",
1873
- duration_ms: durationMs,
1874
- inputs: resolvedInputs,
1875
- error: errorMessage,
1876
- retries: effectiveRetries
1877
- };
1878
- emit(onEvent, {
1879
- type: "step_error",
1880
- stepId: step.id,
1881
- error: errorMessage,
1882
- onError
1883
- });
1884
- emit(onEvent, {
1885
- type: "step_complete",
1886
- stepId: step.id,
1887
- status: "failed",
1888
- duration_ms: durationMs
1889
- });
1890
- if (onError === "ignore") return { records: [record] };
1891
- return {
1892
- records: [record],
1893
- failed: true
1894
- };
1895
- }
1896
- function resolveInputs(stepInputs, context, stepId) {
1897
- const resolved = {};
1898
- for (const [key, input] of Object.entries(stepInputs)) if (input.value !== void 0) try {
1899
- resolved[key] = resolveValue(input.value, context);
1900
- } catch (err) {
1901
- const expr = typeof input.value === "string" ? input.value : JSON.stringify(input.value);
1902
- throw new StepExecutionError(`${stepId ? `Step "${stepId}" input "${key}"` : `Input "${key}"`}: failed to resolve expression ${expr}: ${err instanceof Error ? err.message : String(err)}`, false, { expression: typeof input.value === "string" ? input.value : void 0 });
1903
- }
1904
- return resolved;
1905
- }
1906
- function applyDefaults(schema, provided) {
1907
- const result = { ...provided };
1908
- for (const [key, def] of Object.entries(schema)) if (!(key in result) && def.default !== void 0) result[key] = def.default;
1909
- return result;
1910
- }
1911
- function collectBranchStepIds(steps) {
1912
- const ids = /* @__PURE__ */ new Set();
1913
- for (const step of steps) if (step.type === "conditional") {
1914
- for (const id of step.then) ids.add(id);
1915
- if (step.else) for (const id of step.else) ids.add(id);
1916
- }
1917
- return ids;
1918
- }
1919
- /**
1920
- * Apply step output value mapping.
1921
- * For each declared output with a `value` expression, resolve against the raw executor result.
1922
- * Outputs without `value` pass through from raw output by key name (backwards compatible).
1923
- */
1924
- function applyStepOutputMapping(stepOutputs, rawOutput, context) {
1925
- if (!Object.values(stepOutputs).some((o) => o.value !== void 0)) return rawOutput;
1926
- const tempContext = {
1927
- ...context,
1928
- result: rawOutput
1929
- };
1930
- const mapped = {};
1931
- for (const [key, outputDef] of Object.entries(stepOutputs)) if (outputDef.value !== void 0) mapped[key] = resolveValue(outputDef.value, tempContext);
1932
- else if (rawOutput !== null && typeof rawOutput === "object" && !Array.isArray(rawOutput)) mapped[key] = rawOutput[key] ?? null;
1933
- else mapped[key] = null;
1934
- return mapped;
1935
- }
1936
- function buildWorkflowOutputs(workflow, finalOutput, context, exitFired) {
1937
- const outputKeys = Object.keys(workflow.outputs);
1938
- if (outputKeys.length === 0) return {};
1939
- if (exitFired) {
1940
- if (finalOutput !== null && typeof finalOutput === "object" && !Array.isArray(finalOutput)) {
1941
- const outputObj = finalOutput;
1942
- const result = {};
1943
- for (const key of outputKeys) result[key] = outputObj[key] ?? null;
1944
- return result;
1945
- }
1946
- if (outputKeys.length === 1) return { [outputKeys[0]]: finalOutput };
1947
- return { [outputKeys[0]]: finalOutput };
1948
- }
1949
- if (Object.values(workflow.outputs).some((o) => o.value !== void 0)) {
1950
- const result = {};
1951
- for (const [key, outputDef] of Object.entries(workflow.outputs)) if (outputDef.value !== void 0) result[key] = resolveValue(outputDef.value, context);
1952
- else if (finalOutput !== null && typeof finalOutput === "object" && !Array.isArray(finalOutput)) result[key] = finalOutput[key] ?? null;
1953
- else result[key] = null;
1954
- return result;
1955
- }
1956
- if (finalOutput !== null && typeof finalOutput === "object" && !Array.isArray(finalOutput)) {
1957
- const outputObj = finalOutput;
1958
- const result = {};
1959
- for (const key of outputKeys) result[key] = outputObj[key] ?? null;
1960
- return result;
1961
- }
1962
- if (outputKeys.length === 1) return { [outputKeys[0]]: finalOutput };
1963
- return { [outputKeys[0]]: finalOutput };
1964
- }
1965
- function parseDelay(delay) {
1966
- const match = delay.match(/^(\d+)(ms|s)$/);
1967
- if (!match) return 0;
1968
- const value = parseInt(match[1], 10);
1969
- return match[2] === "s" ? value * 1e3 : value;
1970
- }
1971
- function sleep(ms) {
1972
- return new Promise((resolve) => setTimeout(resolve, ms));
1973
- }
1974
-
1975
- //#endregion
1976
- export { parseSkillMd as C, ParseError as S, parseWorkflowYaml as T, interpolatePrompt as _, dispatch as a, ParseExprError as b, StepExecutionError as c, executeTransform as d, loadConfig as f, validateWorkflowSkill as g, validateWorkflow as h, runWorkflowSkill as i, executeExit as l, AnthropicLLMAdapter as m, buildFailedRunLog as n, executeLLM as o, BuiltinToolAdapter as p, runWorkflow as r, executeTool as s, WorkflowExecutionError as t, executeConditional as u, resolveExpression as v, parseWorkflowFromMd as w, LexError as x, EvalError as y };
1977
- //# sourceMappingURL=runtime-CD81H1bx.mjs.map