@oxygen-agent/cli 1.377.3 → 1.591.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/README.md +1 -1
  2. package/dist/column-run-notices.d.ts +11 -0
  3. package/dist/column-run-notices.js +37 -0
  4. package/dist/command-manifest.js +13 -8
  5. package/dist/help.js +79 -16
  6. package/dist/index.js +3812 -460
  7. package/dist/skills.js +106 -1
  8. package/node_modules/@oxygen/formula/dist/coerce.d.ts +8 -0
  9. package/node_modules/@oxygen/formula/dist/coerce.js +10 -0
  10. package/node_modules/@oxygen/formula/dist/evaluate.d.ts +31 -0
  11. package/node_modules/@oxygen/formula/dist/evaluate.js +248 -0
  12. package/node_modules/@oxygen/formula/dist/expression.d.ts +64 -0
  13. package/node_modules/@oxygen/formula/dist/expression.js +428 -0
  14. package/node_modules/@oxygen/formula/dist/formula-functions.d.ts +71 -0
  15. package/node_modules/@oxygen/formula/dist/formula-functions.js +1100 -0
  16. package/node_modules/@oxygen/formula/dist/index.d.ts +17 -0
  17. package/node_modules/@oxygen/formula/dist/index.js +17 -0
  18. package/node_modules/@oxygen/formula/dist/value-normalizers.d.ts +30 -0
  19. package/node_modules/@oxygen/formula/dist/value-normalizers.js +80 -0
  20. package/node_modules/@oxygen/formula/package.json +26 -0
  21. package/node_modules/@oxygen/recipe-sdk/dist/index.d.ts +30 -0
  22. package/node_modules/@oxygen/recipe-sdk/dist/index.js +2 -2
  23. package/node_modules/@oxygen/shared/dist/billing-anchors.d.ts +60 -0
  24. package/node_modules/@oxygen/shared/dist/billing-anchors.js +135 -0
  25. package/node_modules/@oxygen/shared/dist/billing.d.ts +99 -5
  26. package/node_modules/@oxygen/shared/dist/billing.js +185 -8
  27. package/node_modules/@oxygen/shared/dist/call-outcomes.d.ts +59 -0
  28. package/node_modules/@oxygen/shared/dist/call-outcomes.js +73 -0
  29. package/node_modules/@oxygen/shared/dist/cli-result.js +1 -0
  30. package/node_modules/@oxygen/shared/dist/credit-guidance.js +3 -1
  31. package/node_modules/@oxygen/shared/dist/crm-reply-events.d.ts +35 -0
  32. package/node_modules/@oxygen/shared/dist/crm-reply-events.js +31 -0
  33. package/node_modules/@oxygen/shared/dist/dial-guardrail-overrides.d.ts +50 -0
  34. package/node_modules/@oxygen/shared/dist/dial-guardrail-overrides.js +65 -0
  35. package/node_modules/@oxygen/shared/dist/directory.d.ts +1 -1
  36. package/node_modules/@oxygen/shared/dist/directory.js +1 -0
  37. package/node_modules/@oxygen/shared/dist/file-import.js +58 -11
  38. package/node_modules/@oxygen/shared/dist/hosted-ai.d.ts +15 -0
  39. package/node_modules/@oxygen/shared/dist/hosted-ai.js +19 -0
  40. package/node_modules/@oxygen/shared/dist/index.d.ts +9 -0
  41. package/node_modules/@oxygen/shared/dist/index.js +9 -0
  42. package/node_modules/@oxygen/shared/dist/linkedin-quota-denial.d.ts +31 -0
  43. package/node_modules/@oxygen/shared/dist/linkedin-quota-denial.js +56 -0
  44. package/node_modules/@oxygen/shared/dist/linkedin-sequences.d.ts +5 -4
  45. package/node_modules/@oxygen/shared/dist/linkedin-sequences.js +5 -4
  46. package/node_modules/@oxygen/shared/dist/linkedin-url.d.ts +22 -0
  47. package/node_modules/@oxygen/shared/dist/linkedin-url.js +7 -4
  48. package/node_modules/@oxygen/shared/dist/log.js +41 -2
  49. package/node_modules/@oxygen/shared/dist/microsoft-consent-url.d.ts +7 -0
  50. package/node_modules/@oxygen/shared/dist/microsoft-consent-url.js +29 -0
  51. package/node_modules/@oxygen/shared/dist/object-storage.d.ts +31 -0
  52. package/node_modules/@oxygen/shared/dist/object-storage.js +61 -0
  53. package/node_modules/@oxygen/shared/dist/plan-limits.d.ts +636 -0
  54. package/node_modules/@oxygen/shared/dist/plan-limits.js +199 -0
  55. package/node_modules/@oxygen/shared/dist/pricing-sheet.d.ts +89 -23
  56. package/node_modules/@oxygen/shared/dist/pricing-sheet.js +88 -24
  57. package/node_modules/@oxygen/shared/dist/sequence-crm-events.d.ts +291 -0
  58. package/node_modules/@oxygen/shared/dist/sequence-crm-events.js +224 -0
  59. package/node_modules/@oxygen/shared/dist/sequence-template.d.ts +42 -1
  60. package/node_modules/@oxygen/shared/dist/sequence-template.js +0 -0
  61. package/node_modules/@oxygen/shared/dist/sequences.d.ts +287 -24
  62. package/node_modules/@oxygen/shared/dist/sequences.js +940 -60
  63. package/node_modules/@oxygen/shared/dist/spend-safety.d.ts +70 -0
  64. package/node_modules/@oxygen/shared/dist/spend-safety.js +106 -0
  65. package/node_modules/@oxygen/shared/dist/tags.d.ts +90 -1
  66. package/node_modules/@oxygen/shared/dist/tags.js +122 -6
  67. package/node_modules/@oxygen/shared/dist/version.d.ts +1 -1
  68. package/node_modules/@oxygen/shared/dist/version.js +1 -1
  69. package/node_modules/@oxygen/shared/dist/workflow-trigger-metadata.d.ts +1 -1
  70. package/node_modules/@oxygen/shared/dist/workflow-trigger-metadata.js +4 -0
  71. package/node_modules/@oxygen/shared/package.json +95 -0
  72. package/node_modules/@oxygen/workflows/dist/event-dispatch.d.ts +126 -0
  73. package/node_modules/@oxygen/workflows/dist/event-dispatch.js +173 -0
  74. package/node_modules/@oxygen/workflows/dist/graph/expression.d.ts +78 -0
  75. package/node_modules/@oxygen/workflows/dist/graph/expression.js +700 -0
  76. package/node_modules/@oxygen/workflows/dist/graph/index.d.ts +20 -0
  77. package/node_modules/@oxygen/workflows/dist/graph/index.js +20 -0
  78. package/node_modules/@oxygen/workflows/dist/graph/lint.d.ts +4 -0
  79. package/node_modules/@oxygen/workflows/dist/graph/lint.js +812 -0
  80. package/node_modules/@oxygen/workflows/dist/graph/manifest-schema.d.ts +501 -0
  81. package/node_modules/@oxygen/workflows/dist/graph/manifest-schema.js +200 -0
  82. package/node_modules/@oxygen/workflows/dist/graph/params.d.ts +86 -0
  83. package/node_modules/@oxygen/workflows/dist/graph/params.js +173 -0
  84. package/node_modules/@oxygen/workflows/dist/graph/remap.d.ts +48 -0
  85. package/node_modules/@oxygen/workflows/dist/graph/remap.js +213 -0
  86. package/node_modules/@oxygen/workflows/dist/graph/topology.d.ts +46 -0
  87. package/node_modules/@oxygen/workflows/dist/graph/topology.js +280 -0
  88. package/node_modules/@oxygen/workflows/dist/graph/types.d.ts +270 -0
  89. package/node_modules/@oxygen/workflows/dist/graph/types.js +93 -0
  90. package/node_modules/@oxygen/workflows/dist/index.d.ts +113 -1
  91. package/node_modules/@oxygen/workflows/dist/index.js +179 -13
  92. package/node_modules/@oxygen/workflows/dist/tool-effects.d.ts +1 -0
  93. package/node_modules/@oxygen/workflows/dist/tool-effects.js +19 -0
  94. package/node_modules/@oxygen/workflows/dist/usage-estimate.js +135 -4
  95. package/node_modules/@oxygen/workflows/package.json +4 -0
  96. package/package.json +7 -5
@@ -0,0 +1,126 @@
1
+ import type { JsonSchema, JsonSchemaValidationIssue, WorkflowEventFilter } from "./index.js";
2
+ /**
3
+ * Read a dot-delimited path out of an event payload.
4
+ *
5
+ * Returns `found` separately from `value` so `exists` / `not_exists` filters can
6
+ * distinguish "the key is absent" from "the key is present and holds
7
+ * undefined/null" — collapsing those two would make `not_exists` fire on an
8
+ * explicit null, which is a real value the producer chose to send.
9
+ *
10
+ * Uses Object.hasOwn so inherited/prototype keys never satisfy a filter.
11
+ */
12
+ export declare function readWorkflowEventJsonPath(value: Record<string, unknown>, path: string): {
13
+ found: boolean;
14
+ value: unknown;
15
+ };
16
+ /**
17
+ * Structural equality for filter comparisons. JSON-serialization equality is
18
+ * deliberate: filter values arrive as JSON from a stored trigger manifest, so
19
+ * two values are equal exactly when they round-trip identically.
20
+ */
21
+ export declare function workflowEventJsonEqual(left: unknown, right: unknown): boolean;
22
+ /**
23
+ * Does this payload satisfy every filter declared on the trigger?
24
+ *
25
+ * No filters (absent, not an array, or empty) means "match everything" — a
26
+ * trigger that declares no narrowing wants every event of its source+type.
27
+ *
28
+ * A malformed filter entry returns false (the whole trigger does not match)
29
+ * rather than being skipped. Ignoring an unparseable filter would silently
30
+ * WIDEN the trigger to fire on events the author meant to exclude; failing
31
+ * closed keeps a broken filter from becoming an unintended fan-out.
32
+ */
33
+ export declare function matchesWorkflowEventFilters(payload: Record<string, unknown>, filters: unknown): boolean;
34
+ /**
35
+ * The run idempotency key for one (event, trigger) delivery.
36
+ *
37
+ * Precedence, most to least specific:
38
+ * 1. the trigger's declared `idempotency_key_path` resolved against the payload
39
+ * — lets a producer dedupe on its own domain id (e.g. the provider's
40
+ * contact id) across redeliveries that carry different envelope ids;
41
+ * 2. an explicit caller-supplied key;
42
+ * 3. the provider's external event id (the redelivery guard webhooks carry);
43
+ * 4. the recorded event's own id, which is unique by construction.
44
+ *
45
+ * The `event:<source>:<type>:` prefix scopes the key so two different event
46
+ * types carrying the same domain id can never collide into one run.
47
+ *
48
+ * Takes scalars rather than db rows so both the web and worker callers — whose
49
+ * row types come from different drizzle schemas — can share one implementation.
50
+ */
51
+ export declare function workflowEventRunIdempotencyKey(input: {
52
+ eventId: string;
53
+ eventSource: string;
54
+ eventType: string;
55
+ triggerMetadata: Record<string, unknown> | null | undefined;
56
+ payload: Record<string, unknown>;
57
+ explicitKey?: string | null;
58
+ externalEventId?: string | null;
59
+ }): string;
60
+ /**
61
+ * The verdict for one candidate delivery, before any state is written.
62
+ *
63
+ * `skipped` is a normal outcome (the trigger asked not to see this payload);
64
+ * `failed` means the payload reached a trigger that wanted it but could not be
65
+ * run. Callers record the distinction on the delivery row, so an operator can
66
+ * tell "my filter excluded it" from "my workflow's input schema rejected it".
67
+ */
68
+ export type WorkflowEventDeliveryPlan = {
69
+ status: "deliverable";
70
+ } | {
71
+ status: "skipped";
72
+ reason: "filters_not_matched";
73
+ } | {
74
+ status: "failed";
75
+ error: {
76
+ ok: false;
77
+ error: {
78
+ code: "invalid_input";
79
+ message: string;
80
+ details: {
81
+ issues: JsonSchemaValidationIssue[];
82
+ };
83
+ };
84
+ };
85
+ };
86
+ /**
87
+ * Decide whether one event payload should produce a run for one trigger.
88
+ *
89
+ * Order matters: filters run BEFORE schema validation. A trigger that filtered
90
+ * an event out never wanted it, so validating that payload against the
91
+ * workflow's input schema would manufacture a spurious `failed` delivery (and a
92
+ * misleading "your workflow rejected this input" error) for an event the author
93
+ * deliberately excluded.
94
+ *
95
+ * `validateSchema` is injected rather than imported to keep this module free of
96
+ * a runtime dependency on index.ts (see the note at the top of the file).
97
+ */
98
+ export declare function planWorkflowEventDelivery(input: {
99
+ payload: Record<string, unknown>;
100
+ filters: unknown;
101
+ inputSchema: JsonSchema | undefined;
102
+ validateSchema: (value: unknown, schema: JsonSchema | undefined) => JsonSchemaValidationIssue[];
103
+ }): WorkflowEventDeliveryPlan;
104
+ /**
105
+ * Per-run credit estimate for the standing `workflow_trigger` budget check.
106
+ *
107
+ * A triggered live run's projected spend is the per-run ceiling it carries — the
108
+ * call-time max_credits (run metadata), else the trigger's declared
109
+ * trigger_max_credits, else the manifest's declared max_credits, else 0.
110
+ *
111
+ * A 0 estimate makes daily/monthly caps reactive (they block the first run after
112
+ * the window crosses the cap) and per_run-window caps inert; a declared cap
113
+ * makes the gate preventive. That is the same trade-off the cron monitor
114
+ * carries, and both paths must price a run identically or the same workflow
115
+ * would be gated differently depending on which process fired it.
116
+ *
117
+ * Numeric strings are coerced: a cap that round-tripped through JSON as "500"
118
+ * must still price the run, or the projection counts a ceiling the run does not
119
+ * actually carry.
120
+ */
121
+ export declare function estimateWorkflowTriggerRunCredits(runMetadata: Record<string, unknown> | null | undefined, triggerMetadata: Record<string, unknown> | null | undefined, manifest: unknown): number;
122
+ /**
123
+ * Filters declared on a stored trigger's metadata, coerced to the manifest type.
124
+ * Stored metadata is untyped jsonb; this keeps the cast in one place.
125
+ */
126
+ export declare function readWorkflowEventTriggerFilters(triggerMetadata: Record<string, unknown> | null | undefined): WorkflowEventFilter[] | undefined;
@@ -0,0 +1,173 @@
1
+ /**
2
+ * Read a dot-delimited path out of an event payload.
3
+ *
4
+ * Returns `found` separately from `value` so `exists` / `not_exists` filters can
5
+ * distinguish "the key is absent" from "the key is present and holds
6
+ * undefined/null" — collapsing those two would make `not_exists` fire on an
7
+ * explicit null, which is a real value the producer chose to send.
8
+ *
9
+ * Uses Object.hasOwn so inherited/prototype keys never satisfy a filter.
10
+ */
11
+ export function readWorkflowEventJsonPath(value, path) {
12
+ let current = value;
13
+ for (const part of path.split(".")) {
14
+ if (!part)
15
+ return { found: false, value: undefined };
16
+ if (!current || typeof current !== "object" || Array.isArray(current)) {
17
+ return { found: false, value: undefined };
18
+ }
19
+ const record = current;
20
+ if (!Object.hasOwn(record, part))
21
+ return { found: false, value: undefined };
22
+ current = record[part];
23
+ }
24
+ return { found: true, value: current };
25
+ }
26
+ /**
27
+ * Structural equality for filter comparisons. JSON-serialization equality is
28
+ * deliberate: filter values arrive as JSON from a stored trigger manifest, so
29
+ * two values are equal exactly when they round-trip identically.
30
+ */
31
+ export function workflowEventJsonEqual(left, right) {
32
+ return JSON.stringify(left) === JSON.stringify(right);
33
+ }
34
+ /**
35
+ * Does this payload satisfy every filter declared on the trigger?
36
+ *
37
+ * No filters (absent, not an array, or empty) means "match everything" — a
38
+ * trigger that declares no narrowing wants every event of its source+type.
39
+ *
40
+ * A malformed filter entry returns false (the whole trigger does not match)
41
+ * rather than being skipped. Ignoring an unparseable filter would silently
42
+ * WIDEN the trigger to fire on events the author meant to exclude; failing
43
+ * closed keeps a broken filter from becoming an unintended fan-out.
44
+ */
45
+ export function matchesWorkflowEventFilters(payload, filters) {
46
+ if (!Array.isArray(filters) || filters.length === 0)
47
+ return true;
48
+ return filters.every((filter) => {
49
+ if (!filter || typeof filter !== "object" || Array.isArray(filter))
50
+ return false;
51
+ const path = typeof filter.path === "string"
52
+ ? filter.path.trim()
53
+ : "";
54
+ const op = filter.op;
55
+ if (!path)
56
+ return false;
57
+ const current = readWorkflowEventJsonPath(payload, path);
58
+ if (op === "exists")
59
+ return current.found;
60
+ if (op === "not_exists")
61
+ return !current.found;
62
+ if (op === "eq") {
63
+ return current.found && workflowEventJsonEqual(current.value, filter.value);
64
+ }
65
+ if (op === "neq") {
66
+ return !current.found || !workflowEventJsonEqual(current.value, filter.value);
67
+ }
68
+ return false;
69
+ });
70
+ }
71
+ /**
72
+ * The run idempotency key for one (event, trigger) delivery.
73
+ *
74
+ * Precedence, most to least specific:
75
+ * 1. the trigger's declared `idempotency_key_path` resolved against the payload
76
+ * — lets a producer dedupe on its own domain id (e.g. the provider's
77
+ * contact id) across redeliveries that carry different envelope ids;
78
+ * 2. an explicit caller-supplied key;
79
+ * 3. the provider's external event id (the redelivery guard webhooks carry);
80
+ * 4. the recorded event's own id, which is unique by construction.
81
+ *
82
+ * The `event:<source>:<type>:` prefix scopes the key so two different event
83
+ * types carrying the same domain id can never collide into one run.
84
+ *
85
+ * Takes scalars rather than db rows so both the web and worker callers — whose
86
+ * row types come from different drizzle schemas — can share one implementation.
87
+ */
88
+ export function workflowEventRunIdempotencyKey(input) {
89
+ const idempotencyPath = typeof input.triggerMetadata?.idempotency_key_path === "string"
90
+ ? input.triggerMetadata.idempotency_key_path
91
+ : null;
92
+ const pathValue = idempotencyPath
93
+ ? readWorkflowEventJsonPath(input.payload, idempotencyPath)
94
+ : null;
95
+ const key = pathValue?.found && typeof pathValue.value === "string" && pathValue.value.trim()
96
+ ? pathValue.value.trim()
97
+ : input.explicitKey?.trim() || input.externalEventId?.trim() || input.eventId;
98
+ return `event:${input.eventSource}:${input.eventType}:${key}`;
99
+ }
100
+ /**
101
+ * Decide whether one event payload should produce a run for one trigger.
102
+ *
103
+ * Order matters: filters run BEFORE schema validation. A trigger that filtered
104
+ * an event out never wanted it, so validating that payload against the
105
+ * workflow's input schema would manufacture a spurious `failed` delivery (and a
106
+ * misleading "your workflow rejected this input" error) for an event the author
107
+ * deliberately excluded.
108
+ *
109
+ * `validateSchema` is injected rather than imported to keep this module free of
110
+ * a runtime dependency on index.ts (see the note at the top of the file).
111
+ */
112
+ export function planWorkflowEventDelivery(input) {
113
+ if (!matchesWorkflowEventFilters(input.payload, input.filters)) {
114
+ return { status: "skipped", reason: "filters_not_matched" };
115
+ }
116
+ if (input.inputSchema) {
117
+ const issues = input.validateSchema(input.payload, input.inputSchema);
118
+ if (issues.length > 0) {
119
+ return {
120
+ status: "failed",
121
+ error: {
122
+ ok: false,
123
+ error: {
124
+ code: "invalid_input",
125
+ message: "Workflow event payload does not match the workflow input schema.",
126
+ details: { issues },
127
+ },
128
+ },
129
+ };
130
+ }
131
+ }
132
+ return { status: "deliverable" };
133
+ }
134
+ /**
135
+ * Per-run credit estimate for the standing `workflow_trigger` budget check.
136
+ *
137
+ * A triggered live run's projected spend is the per-run ceiling it carries — the
138
+ * call-time max_credits (run metadata), else the trigger's declared
139
+ * trigger_max_credits, else the manifest's declared max_credits, else 0.
140
+ *
141
+ * A 0 estimate makes daily/monthly caps reactive (they block the first run after
142
+ * the window crosses the cap) and per_run-window caps inert; a declared cap
143
+ * makes the gate preventive. That is the same trade-off the cron monitor
144
+ * carries, and both paths must price a run identically or the same workflow
145
+ * would be gated differently depending on which process fired it.
146
+ *
147
+ * Numeric strings are coerced: a cap that round-tripped through JSON as "500"
148
+ * must still price the run, or the projection counts a ceiling the run does not
149
+ * actually carry.
150
+ */
151
+ export function estimateWorkflowTriggerRunCredits(runMetadata, triggerMetadata, manifest) {
152
+ const manifestCap = manifest?.max_credits;
153
+ const candidates = [
154
+ runMetadata?.max_credits,
155
+ runMetadata?.maxCredits,
156
+ triggerMetadata?.trigger_max_credits,
157
+ manifestCap,
158
+ ];
159
+ for (const raw of candidates) {
160
+ const value = typeof raw === "number" ? raw : Number(raw);
161
+ if (Number.isFinite(value) && value > 0)
162
+ return value;
163
+ }
164
+ return 0;
165
+ }
166
+ /**
167
+ * Filters declared on a stored trigger's metadata, coerced to the manifest type.
168
+ * Stored metadata is untyped jsonb; this keeps the cast in one place.
169
+ */
170
+ export function readWorkflowEventTriggerFilters(triggerMetadata) {
171
+ const filters = triggerMetadata?.filters;
172
+ return Array.isArray(filters) ? filters : undefined;
173
+ }
@@ -0,0 +1,78 @@
1
+ import type { WorkflowCompareOp, WorkflowCondition, WorkflowValueRef } from "./types.js";
2
+ /**
3
+ * The data a v2 run exposes to its value refs.
4
+ *
5
+ * `steps` is keyed by node id and always present (an empty object before the
6
+ * first node completes); `trigger` and `loop` are absent until a run supplies
7
+ * them. `contextProfile` / `contextAssets` carry the Knowledge-layer values the
8
+ * `context_profile` / `context_asset` refs read.
9
+ */
10
+ export type WorkflowRunScope = {
11
+ trigger?: {
12
+ input?: unknown;
13
+ payload?: unknown;
14
+ };
15
+ steps: Record<string, {
16
+ output?: unknown;
17
+ }>;
18
+ loop?: Record<string, {
19
+ item?: unknown;
20
+ index?: number;
21
+ }>;
22
+ contextProfile?: unknown;
23
+ contextAssets?: Record<string, unknown>;
24
+ };
25
+ /** The roots a `ref` path may start from. Anything else is not a scope path. */
26
+ export declare const SCOPE_PATH_ROOTS: ReadonlySet<string>;
27
+ export declare const WORKFLOW_COMPARE_OPS: ReadonlySet<WorkflowCompareOp>;
28
+ /** Operators that take no right operand. */
29
+ export declare const UNARY_COMPARE_OPS: ReadonlySet<WorkflowCompareOp>;
30
+ /**
31
+ * Split a path expression into its segments, or return null when the expression
32
+ * is malformed or reaches a blocked segment.
33
+ *
34
+ * Grammar: dotted keys with optional index suffixes —
35
+ * steps.find_person.output.emails[0].address
36
+ * trigger.input["odd.key"]
37
+ *
38
+ * Returning null (rather than throwing) is what lets `resolvePath` stay total;
39
+ * the linter uses the same parser to reject the path at authoring time, so a
40
+ * typo surfaces in lint rather than as a silently empty value at run time.
41
+ */
42
+ export declare function parseScopePath(path: string): string[] | null;
43
+ /** Resolve a dotted (+ `[n]`) scope path. Missing or malformed → undefined. */
44
+ export declare function resolvePath(path: string, scope: WorkflowRunScope): unknown;
45
+ /**
46
+ * Substitute every `{{ path }}` placeholder. The result is always a string:
47
+ * blanks render as "", scalars as their text, objects/arrays as compact JSON.
48
+ * `{{}}` (no path) is literal text, not a binding.
49
+ */
50
+ export declare function renderTemplate(template: string, scope: WorkflowRunScope): string;
51
+ export declare function resolveValueRef(ref: WorkflowValueRef, scope: WorkflowRunScope): unknown;
52
+ export declare function evaluateCondition(condition: WorkflowCondition, scope: WorkflowRunScope): boolean;
53
+ /**
54
+ * Compile a `matches` pattern, or return null when it is unsafe or invalid.
55
+ *
56
+ * Choice: conservative STATIC REJECTION rather than a linear (Thompson NFA)
57
+ * matcher. A linear engine would be several hundred lines of new, security-load-
58
+ * bearing code in a module the browser also bundles, whereas the patterns real
59
+ * GTM authors write (domain suffixes, job-title keywords, ID formats) never need
60
+ * the constructs rejected here. Rejected: sources over 200 characters,
61
+ * lookaround, backreferences, and a quantified group whose body itself contains
62
+ * an unbounded quantifier — the `(a+)+` family that drives catastrophic
63
+ * backtracking. Everything else compiles as a normal RegExp.
64
+ *
65
+ * The linter calls this at authoring time and reports `invalid_condition`, so a
66
+ * rejected pattern is a lint error the author sees, not a silent run-time false.
67
+ */
68
+ export declare function compileConditionPattern(pattern: string): RegExp | null;
69
+ /**
70
+ * Node ids a ref or condition reads, in first-seen order.
71
+ *
72
+ * `steps.<id>...` and `loop.<id>...` paths name a node exactly. Formula refs are
73
+ * a superset: the tokenizer's bare identifiers may name a node, a workflow
74
+ * input, or a loop, and nothing in the expression distinguishes them — callers
75
+ * that need certainty (edge inference, dependency ordering) intersect the result
76
+ * with the manifest's declared node ids.
77
+ */
78
+ export declare function referencedNodeIds(ref: WorkflowValueRef | WorkflowCondition): string[];