@boboddy/sdk 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -14434,6 +14434,140 @@ function extractInlineComputedSignals(policy) {
14434
14434
  return [...byKey.values()];
14435
14435
  }
14436
14436
 
14437
+ // src/definitions/advancement-policies/cohort-advancement-policy.ts
14438
+ var cohortAdvancementEventTypeValues = ["continue", "block"];
14439
+ function serializeCohortCondition(condition) {
14440
+ if (condition._tag === "signal") {
14441
+ return {
14442
+ fact: typeof condition.signal === "string" ? condition.signal : condition.signal.key,
14443
+ operator: condition.operator,
14444
+ value: condition.value
14445
+ };
14446
+ }
14447
+ if (condition._tag === "all") {
14448
+ return { all: condition.conditions.map(serializeCohortCondition) };
14449
+ }
14450
+ return { any: condition.conditions.map(serializeCohortCondition) };
14451
+ }
14452
+ function serializeCohortRule(rule) {
14453
+ return {
14454
+ conditions: { [rule.mode]: rule.conditions.map(serializeCohortCondition) },
14455
+ event: {
14456
+ type: rule.outcome,
14457
+ ...rule.outcomeJson ? { params: rule.outcomeJson } : {}
14458
+ }
14459
+ };
14460
+ }
14461
+ function serializeCohortAdvancementPolicy(policy) {
14462
+ if (!policy) {
14463
+ return { rules: [], defaultEventType: "continue", defaultEventParamsJson: null };
14464
+ }
14465
+ return {
14466
+ rules: (policy.rules ?? []).map(serializeCohortRule),
14467
+ defaultEventType: policy.default,
14468
+ defaultEventParamsJson: policy.defaultParamsJson ?? null
14469
+ };
14470
+ }
14471
+ function visitCohortSignalConditions(conditions, visit) {
14472
+ for (const c of conditions) {
14473
+ if (c._tag === "signal") {
14474
+ visit(c);
14475
+ } else {
14476
+ visitCohortSignalConditions(c.conditions, visit);
14477
+ }
14478
+ }
14479
+ }
14480
+ function isSameStepSignalsListDefinition(a, b) {
14481
+ return JSON.stringify(a.ops) === JSON.stringify(b.ops) && JSON.stringify(a.reducer) === JSON.stringify(b.reducer);
14482
+ }
14483
+ function extractInlineStepSignalsListDefinitions(policy) {
14484
+ if (!policy?.rules)
14485
+ return [];
14486
+ const byKey = new Map;
14487
+ for (const rule of policy.rules) {
14488
+ visitCohortSignalConditions(rule.conditions, (cond) => {
14489
+ if (typeof cond.signal === "string")
14490
+ return;
14491
+ const inline = cond.signal;
14492
+ const def = {
14493
+ key: inline.key,
14494
+ ops: inline.ops,
14495
+ reducer: inline.reducer
14496
+ };
14497
+ const existing = byKey.get(def.key);
14498
+ if (existing) {
14499
+ if (!isSameStepSignalsListDefinition(existing, def)) {
14500
+ throw new Error(`Conflicting inline stepSignalsList definitions for key "${def.key}"`);
14501
+ }
14502
+ return;
14503
+ }
14504
+ byKey.set(def.key, def);
14505
+ });
14506
+ }
14507
+ return [...byKey.values()];
14508
+ }
14509
+
14510
+ // src/definitions/pipelines/chain-graph.ts
14511
+ function tryOrderChainNodeDefinitions(nodeDefinitions, dependencyEdges) {
14512
+ const nodesByKey = new Map;
14513
+ for (const nodeDefinition of nodeDefinitions) {
14514
+ nodesByKey.set(nodeDefinition.nodeKey, nodeDefinition);
14515
+ }
14516
+ const outgoing = new Map;
14517
+ const incomingCount = new Map;
14518
+ for (const nodeDefinition of nodeDefinitions) {
14519
+ incomingCount.set(nodeDefinition.nodeKey, 0);
14520
+ }
14521
+ for (const edge of dependencyEdges) {
14522
+ if (!nodesByKey.has(edge.fromNodeKey) || !nodesByKey.has(edge.toNodeKey)) {
14523
+ return null;
14524
+ }
14525
+ if (outgoing.has(edge.fromNodeKey))
14526
+ return null;
14527
+ outgoing.set(edge.fromNodeKey, edge.toNodeKey);
14528
+ incomingCount.set(edge.toNodeKey, (incomingCount.get(edge.toNodeKey) ?? 0) + 1);
14529
+ }
14530
+ for (const count of incomingCount.values()) {
14531
+ if (count > 1)
14532
+ return null;
14533
+ }
14534
+ if (nodeDefinitions.length === 0)
14535
+ return [];
14536
+ const roots = nodeDefinitions.filter((nodeDefinition) => (incomingCount.get(nodeDefinition.nodeKey) ?? 0) === 0);
14537
+ if (roots.length !== 1)
14538
+ return null;
14539
+ const rootNode = roots[0];
14540
+ if (!rootNode)
14541
+ return null;
14542
+ const ordered = [];
14543
+ const visited = new Set;
14544
+ let currentKey = rootNode.nodeKey;
14545
+ while (currentKey !== undefined) {
14546
+ if (visited.has(currentKey))
14547
+ return null;
14548
+ visited.add(currentKey);
14549
+ const currentNode = nodesByKey.get(currentKey);
14550
+ if (!currentNode)
14551
+ return null;
14552
+ ordered.push(currentNode);
14553
+ currentKey = outgoing.get(currentKey);
14554
+ }
14555
+ if (ordered.length !== nodeDefinitions.length)
14556
+ return null;
14557
+ return ordered;
14558
+ }
14559
+ function buildChainDependencyEdges(orderedNodes) {
14560
+ const dependencyEdges = [];
14561
+ for (let index = 0;index < orderedNodes.length - 1; index += 1) {
14562
+ const from = orderedNodes[index];
14563
+ const to = orderedNodes[index + 1];
14564
+ if (!from || !to)
14565
+ continue;
14566
+ dependencyEdges.push({ fromNodeKey: from.nodeKey, toNodeKey: to.nodeKey });
14567
+ }
14568
+ return dependencyEdges;
14569
+ }
14570
+
14437
14571
  // src/definitions/pipelines/define-pipeline.ts
14438
14572
  function serializeBinding(binding) {
14439
14573
  if (binding.source === "pipeline_input") {
@@ -14452,15 +14586,42 @@ function serializeBinding(binding) {
14452
14586
  if (binding.source === "literal") {
14453
14587
  return { source: "literal", value: binding.value };
14454
14588
  }
14589
+ if (binding.source === "signals_list") {
14590
+ return { source: "signals_list", stepKey: binding.fanOutStep.key };
14591
+ }
14592
+ if (binding.source === "fan_out_item") {
14593
+ return { source: "fan_out_item" };
14594
+ }
14455
14595
  return { source: "step_output", stepKey: binding.step.key };
14456
14596
  }
14597
+ var isFanOutConfig = (node) => ("nodeType" in node) && node.nodeType === "fanOut";
14598
+ var isCohortGateConfig = (node) => ("nodeType" in node) && node.nodeType === "cohortGate";
14599
+ function serializeInputBindings(input, pipelineInputBindings) {
14600
+ const autoBindings = {
14601
+ workItemTitle: { source: "work_item", field: "title" },
14602
+ workItemDescription: { source: "work_item", field: "description" }
14603
+ };
14604
+ const pipelineBindings = {};
14605
+ for (const [key, binding] of Object.entries(pipelineInputBindings ?? {})) {
14606
+ pipelineBindings[key] = serializeBinding(binding);
14607
+ }
14608
+ const explicitBindings = Object.fromEntries(Object.entries(input ?? {}).filter((entry) => entry[1] !== undefined).map(([key, binding]) => [key, serializeBinding(binding)]));
14609
+ return { ...autoBindings, ...pipelineBindings, ...explicitBindings };
14610
+ }
14457
14611
  function buildPipelineSpec(config2) {
14458
- const steps = config2.steps;
14612
+ const nodes = config2.nodes;
14459
14613
  const stepDefMap = new Map;
14460
- for (const stepConfig of steps) {
14461
- const mapKey = `${stepConfig.step.key}@v${String(stepConfig.step.version)}`;
14614
+ const registerStepDef = (step) => {
14615
+ const mapKey = `${step.key}@v${String(step.version)}`;
14462
14616
  if (!stepDefMap.has(mapKey)) {
14463
- stepDefMap.set(mapKey, stepConfig.step);
14617
+ stepDefMap.set(mapKey, step);
14618
+ }
14619
+ };
14620
+ for (const node of nodes) {
14621
+ if (isFanOutConfig(node)) {
14622
+ registerStepDef(node.fanOutStep);
14623
+ } else if (!isCohortGateConfig(node)) {
14624
+ registerStepDef(node.step);
14464
14625
  }
14465
14626
  }
14466
14627
  let inputSchemaJson = null;
@@ -14471,6 +14632,46 @@ function buildPipelineSpec(config2) {
14471
14632
  inputSchemaJson = null;
14472
14633
  }
14473
14634
  }
14635
+ const nodeDefinitions = nodes.map((node) => {
14636
+ if (isCohortGateConfig(node)) {
14637
+ const serializedPolicy = serializeCohortAdvancementPolicy(node.advanceAll);
14638
+ const inlineStepSignalsListDefinitions = extractInlineStepSignalsListDefinitions(node.advanceAll);
14639
+ return {
14640
+ nodeKey: node.nodeKey,
14641
+ kind: "cohortGate",
14642
+ advanceAllPolicyDefinition: serializedPolicy,
14643
+ stepSignalsListDefinitions: [
14644
+ ...inlineStepSignalsListDefinitions,
14645
+ ...node.stepSignalsListDefinitions ?? []
14646
+ ]
14647
+ };
14648
+ }
14649
+ if (isFanOutConfig(node)) {
14650
+ return {
14651
+ nodeKey: node.fanOutStep.key,
14652
+ kind: "fanOut",
14653
+ stepKey: node.fanOutStep.key,
14654
+ stepName: node.fanOutStep.name,
14655
+ stepDescription: node.fanOutStep.description,
14656
+ inputBindingsJson: serializeInputBindings(node.input, config2.pipelineInputBindings),
14657
+ timeoutSeconds: node.timeout ?? null,
14658
+ overSignalKey: node.overSignalKey,
14659
+ advanceEachPolicyDefinition: serializeCohortAdvancementPolicy(node.advanceEach)
14660
+ };
14661
+ }
14662
+ return {
14663
+ nodeKey: node.step.key,
14664
+ kind: "step",
14665
+ stepKey: node.step.key,
14666
+ stepName: node.step.name,
14667
+ stepDescription: node.step.description,
14668
+ inputBindingsJson: serializeInputBindings(node.input, config2.pipelineInputBindings),
14669
+ timeoutSeconds: node.timeout ?? null,
14670
+ advancementPolicyDefinition: serializeAdvancementPolicy(node.advancement),
14671
+ computedSignalDefinitions: extractInlineComputedSignals(node.advancement)
14672
+ };
14673
+ });
14674
+ const dependencyEdges = buildChainDependencyEdges(nodeDefinitions);
14474
14675
  return {
14475
14676
  key: config2.key,
14476
14677
  name: config2.name,
@@ -14479,31 +14680,8 @@ function buildPipelineSpec(config2) {
14479
14680
  status: config2.status ?? "active",
14480
14681
  inputSchemaJson,
14481
14682
  _stepDefinitions: [...stepDefMap.values()],
14482
- steps: steps.map((stepConfig, index) => {
14483
- const autoBindings = {
14484
- workItemTitle: { source: "work_item", field: "title" },
14485
- workItemDescription: { source: "work_item", field: "description" }
14486
- };
14487
- const pipelineBindings = {};
14488
- for (const [key, binding] of Object.entries(config2.pipelineInputBindings ?? {})) {
14489
- pipelineBindings[key] = serializeBinding(binding);
14490
- }
14491
- const explicitStepBindings = Object.fromEntries(Object.entries(stepConfig.input ?? {}).filter((entry) => entry[1] !== undefined).map(([key, binding]) => [key, serializeBinding(binding)]));
14492
- return {
14493
- stepKey: stepConfig.step.key,
14494
- stepName: stepConfig.step.name,
14495
- stepDescription: stepConfig.step.description,
14496
- position: index + 1,
14497
- inputBindingsJson: {
14498
- ...autoBindings,
14499
- ...pipelineBindings,
14500
- ...explicitStepBindings
14501
- },
14502
- timeoutSeconds: stepConfig.timeout ?? null,
14503
- advancementPolicyDefinition: serializeAdvancementPolicy(stepConfig.advancement),
14504
- computedSignalDefinitions: extractInlineComputedSignals(stepConfig.advancement)
14505
- };
14506
- })
14683
+ nodeDefinitions,
14684
+ dependencyEdges
14507
14685
  };
14508
14686
  }
14509
14687
  // src/definitions/advancement-policies/fluent-rules.ts
@@ -14674,7 +14852,10 @@ function makeStepInputCtx(inputSchema) {
14674
14852
  output(step) {
14675
14853
  return { source: "step_output", step };
14676
14854
  },
14677
- literal: literal2
14855
+ literal: literal2,
14856
+ signalsList(fanOutStep) {
14857
+ return { source: "signals_list", fanOutStep };
14858
+ }
14678
14859
  };
14679
14860
  }
14680
14861
  function literal2(value) {
@@ -14719,61 +14900,247 @@ function mergeStepBindings(pipelineBindings, explicitBindings) {
14719
14900
  return Object.keys(merged).length > 0 ? merged : undefined;
14720
14901
  }
14721
14902
 
14722
- // src/definitions/pipelines/builder.ts
14723
- class PipelineStepAdvancementBuilder {
14724
- inputSchema;
14725
- meta;
14726
- steps;
14727
- pipelineInputBindings;
14728
- pipelineStepInputBindings;
14729
- constructor(inputSchema, meta3, steps, pipelineInputBindings = {}, pipelineStepInputBindings = {}) {
14730
- this.inputSchema = inputSchema;
14731
- this.meta = meta3;
14732
- this.steps = steps;
14733
- this.pipelineInputBindings = pipelineInputBindings;
14734
- this.pipelineStepInputBindings = pipelineStepInputBindings;
14735
- }
14736
- advance(callback) {
14737
- const last = this.steps.at(-1);
14738
- if (!last)
14739
- throw new Error("Internal error: no steps available");
14740
- const ctx = makeAdvanceCtx();
14741
- const result = callback(ctx);
14742
- const policy = {
14743
- defaultOutcome: result.default,
14744
- ...result.rules !== undefined ? { rules: result.rules } : {}
14903
+ // src/definitions/advancement-policies/cohort-fluent-rules.ts
14904
+ var LEAF_BRAND2 = Symbol("boboddy.cohortRule.leaf");
14905
+ var GROUP_BRAND2 = Symbol("boboddy.cohortRule.group");
14906
+ function createCohortSignalRef(signal2) {
14907
+ const leaf = (operator, value) => {
14908
+ const condition = {
14909
+ _tag: "signal",
14910
+ signal: signal2,
14911
+ operator,
14912
+ value
14745
14913
  };
14746
- last.advancement = policy;
14747
- return new PipelineStepBuilder(this.inputSchema, this.meta, this.steps, this.pipelineInputBindings, this.pipelineStepInputBindings);
14748
- }
14914
+ return {
14915
+ [LEAF_BRAND2]: condition,
14916
+ then(outcome, paramsJson) {
14917
+ return {
14918
+ _tag: "rule",
14919
+ mode: "all",
14920
+ conditions: [condition],
14921
+ outcome,
14922
+ ...paramsJson ? { outcomeJson: paramsJson } : {}
14923
+ };
14924
+ }
14925
+ };
14926
+ };
14927
+ return {
14928
+ eq: (v) => leaf("equal", v),
14929
+ ne: (v) => leaf("notEqual", v),
14930
+ gt: (v) => leaf("greaterThan", v),
14931
+ gte: (v) => leaf("greaterThanInclusive", v),
14932
+ lt: (v) => leaf("lessThan", v),
14933
+ lte: (v) => leaf("lessThanInclusive", v),
14934
+ in: (vs) => leaf("in", vs),
14935
+ notIn: (vs) => leaf("notIn", vs),
14936
+ contains: (v) => leaf("contains", v),
14937
+ doesNotContain: (v) => leaf("doesNotContain", v)
14938
+ };
14939
+ }
14940
+ function createCohortLeafFromCondition(condition) {
14941
+ return {
14942
+ [LEAF_BRAND2]: condition,
14943
+ then(outcome, paramsJson) {
14944
+ return {
14945
+ _tag: "rule",
14946
+ mode: "all",
14947
+ conditions: [condition],
14948
+ outcome,
14949
+ ...paramsJson ? { outcomeJson: paramsJson } : {}
14950
+ };
14951
+ }
14952
+ };
14953
+ }
14954
+ function extractCohortCondition(ref) {
14955
+ if (LEAF_BRAND2 in ref)
14956
+ return ref[LEAF_BRAND2];
14957
+ const group = ref[GROUP_BRAND2];
14958
+ return group.mode === "all" ? { _tag: "all", conditions: group.conditions } : { _tag: "any", conditions: group.conditions };
14959
+ }
14960
+ function createCohortGroup(mode, refs) {
14961
+ const conditions = refs.map(extractCohortCondition);
14962
+ return {
14963
+ [GROUP_BRAND2]: { mode, conditions },
14964
+ then(outcome, paramsJson) {
14965
+ return {
14966
+ _tag: "rule",
14967
+ mode,
14968
+ conditions,
14969
+ outcome,
14970
+ ...paramsJson ? { outcomeJson: paramsJson } : {}
14971
+ };
14972
+ }
14973
+ };
14974
+ }
14975
+ function makeKeyedCohortSignalRef(key) {
14976
+ return createCohortSignalRef(key);
14977
+ }
14978
+ function makeAdvanceEachCtx() {
14979
+ return {
14980
+ signal: (key) => makeKeyedCohortSignalRef(key),
14981
+ stepSignals: new Proxy({}, {
14982
+ get(_, key) {
14983
+ if (typeof key === "string")
14984
+ return makeKeyedCohortSignalRef(key);
14985
+ return;
14986
+ }
14987
+ }),
14988
+ all: (...refs) => createCohortGroup("all", refs),
14989
+ any: (...refs) => createCohortGroup("any", refs)
14990
+ };
14991
+ }
14992
+ var branchOutcomeValues = [
14993
+ "continue",
14994
+ "block",
14995
+ "error",
14996
+ "abandoned"
14997
+ ];
14998
+ function summarizeTransformOp(op) {
14999
+ if (op.op === "filter") {
15000
+ return `filter_${op.operator}_${JSON.stringify(op.value)}`;
15001
+ }
15002
+ if (op.op === "sortBy") {
15003
+ return `sortBy_${op.direction}`;
15004
+ }
15005
+ return "unique";
15006
+ }
15007
+ function deriveStepSignalsListKey(ops, reducer) {
15008
+ const pluck = ops.find((op) => op.op === "pluck");
15009
+ const base = `${reducer.op}_${pluck?.signalKey ?? "value"}`;
15010
+ const extras = ops.filter((op) => op.op !== "pluck").map(summarizeTransformOp);
15011
+ const reducerExtra = reducer.op === "join" ? `sep_${reducer.separator}` : null;
15012
+ const suffixParts = [...extras, ...reducerExtra ? [reducerExtra] : []];
15013
+ return suffixParts.length > 0 ? `${base}_${suffixParts.join("_")}` : base;
15014
+ }
15015
+ function createStepSignalsListBuilder(ops) {
15016
+ const withOp = (op) => createStepSignalsListBuilder([...ops, op]);
15017
+ const reduce = (reducer) => {
15018
+ const token = {
15019
+ _tag: "step_signals_list",
15020
+ key: deriveStepSignalsListKey(ops, reducer),
15021
+ ops: [...ops],
15022
+ reducer
15023
+ };
15024
+ return createCohortSignalRef(token);
15025
+ };
15026
+ return {
15027
+ filter: (operator, value) => withOp({ op: "filter", operator, value }),
15028
+ sortBy: (direction = "asc") => withOp({ op: "sortBy", direction }),
15029
+ unique: () => withOp({ op: "unique" }),
15030
+ count: () => reduce({ op: "count" }),
15031
+ sum: () => reduce({ op: "sum" }),
15032
+ avg: () => reduce({ op: "avg" }),
15033
+ min: () => reduce({ op: "min" }),
15034
+ max: () => reduce({ op: "max" }),
15035
+ booleanAll: () => reduce({ op: "booleanAll" }),
15036
+ booleanAny: () => reduce({ op: "booleanAny" }),
15037
+ join: (separator = ",") => reduce({ op: "join", separator }),
15038
+ first: () => reduce({ op: "first" }),
15039
+ last: () => reduce({ op: "last" })
15040
+ };
15041
+ }
15042
+ function makeAdvanceAllCtx() {
15043
+ return {
15044
+ branchOutcomes: {
15045
+ total: () => createCohortSignalRef("branchCount"),
15046
+ count: (outcome) => createCohortSignalRef(`${outcome}Count`),
15047
+ every: (outcome) => createCohortLeafFromCondition({
15048
+ _tag: "signal",
15049
+ signal: `${outcome}Count`,
15050
+ operator: "equal",
15051
+ value: { fact: "branchCount" }
15052
+ }),
15053
+ some: (outcome) => createCohortLeafFromCondition({
15054
+ _tag: "signal",
15055
+ signal: `${outcome}Count`,
15056
+ operator: "greaterThan",
15057
+ value: 0
15058
+ })
15059
+ },
15060
+ stepSignalsList: {
15061
+ pluck: (signalKey) => createStepSignalsListBuilder([{ op: "pluck", signalKey }])
15062
+ },
15063
+ all: (...refs) => createCohortGroup("all", refs),
15064
+ any: (...refs) => createCohortGroup("any", refs)
15065
+ };
15066
+ }
15067
+
15068
+ // src/definitions/pipelines/fan-out-builder.ts
15069
+ function beginFanOut(inputSchema, meta3, nodes, pipelineInputBindings, pipelineStepInputBindings, step, config2) {
15070
+ const baseCtx = makeStepInputCtx(inputSchema);
15071
+ const ctx = {
15072
+ ...baseCtx,
15073
+ item: { source: "fan_out_item" }
15074
+ };
15075
+ const rawInput = config2.input ? config2.input(ctx) : {};
15076
+ const input = mergeStepBindings(pipelineStepInputBindings, normalizeInputMapping(rawInput));
15077
+ const fanOutNodeConfig = {
15078
+ nodeType: "fanOut",
15079
+ fanOutStep: step,
15080
+ overSignalKey: config2.over,
15081
+ ...input ? { input } : {},
15082
+ ...config2.timeout !== undefined ? { timeout: config2.timeout } : {}
15083
+ };
15084
+ const advanceEachCtx = makeAdvanceEachCtx();
15085
+ const advanceEachResult = config2.advance(advanceEachCtx);
15086
+ const advanceEachPolicy = {
15087
+ default: advanceEachResult.default,
15088
+ ...advanceEachResult.rules !== undefined ? { rules: advanceEachResult.rules } : {}
15089
+ };
15090
+ fanOutNodeConfig.advanceEach = advanceEachPolicy;
15091
+ const cohortGateNodeConfig = {
15092
+ nodeType: "cohortGate",
15093
+ nodeKey: `${step.key}__cohortGate`
15094
+ };
15095
+ const advanceAllCtx = makeAdvanceAllCtx();
15096
+ const advanceAllResult = config2.advanceAll(advanceAllCtx);
15097
+ const advanceAllPolicy = {
15098
+ default: advanceAllResult.default,
15099
+ ...advanceAllResult.rules !== undefined ? { rules: advanceAllResult.rules } : {}
15100
+ };
15101
+ cohortGateNodeConfig.advanceAll = advanceAllPolicy;
15102
+ nodes.push(fanOutNodeConfig, cohortGateNodeConfig);
15103
+ return new PipelineStepBuilder(inputSchema, meta3, nodes, pipelineInputBindings, pipelineStepInputBindings);
15104
+ }
15105
+
15106
+ // src/definitions/pipelines/builder.ts
15107
+ function pushStep(inputSchema, meta3, nodes, pipelineInputBindings, pipelineStepInputBindings, step, rawOptions) {
15108
+ const options = rawOptions;
15109
+ const ctx = makeStepInputCtx(inputSchema);
15110
+ const rawInput = options.input ? options.input(ctx) : {};
15111
+ const input = mergeStepBindings(pipelineStepInputBindings, normalizeInputMapping(rawInput));
15112
+ const stepConfig = { step, input };
15113
+ if (options.timeout !== undefined)
15114
+ stepConfig.timeout = options.timeout;
15115
+ const advanceCtx = makeAdvanceCtx();
15116
+ const result = options.advance(advanceCtx);
15117
+ const policy = {
15118
+ defaultOutcome: result.default,
15119
+ ...result.rules !== undefined ? { rules: result.rules } : {}
15120
+ };
15121
+ stepConfig.advancement = policy;
15122
+ nodes.push(stepConfig);
15123
+ return new PipelineStepBuilder(inputSchema, meta3, nodes, pipelineInputBindings, pipelineStepInputBindings);
14749
15124
  }
14750
15125
 
14751
15126
  class PipelineStepBuilder {
14752
15127
  inputSchema;
14753
15128
  meta;
14754
- steps;
15129
+ nodes;
14755
15130
  pipelineInputBindings;
14756
15131
  pipelineStepInputBindings;
14757
- constructor(inputSchema, meta3, steps, pipelineInputBindings = {}, pipelineStepInputBindings = {}) {
15132
+ constructor(inputSchema, meta3, nodes, pipelineInputBindings = {}, pipelineStepInputBindings = {}) {
14758
15133
  this.inputSchema = inputSchema;
14759
15134
  this.meta = meta3;
14760
- this.steps = steps;
15135
+ this.nodes = nodes;
14761
15136
  this.pipelineInputBindings = pipelineInputBindings;
14762
15137
  this.pipelineStepInputBindings = pipelineStepInputBindings;
14763
15138
  }
14764
- step(step, mapper, configFn) {
14765
- const ctx = makeStepInputCtx(this.inputSchema);
14766
- const rawInput = mapper ? mapper(ctx) : {};
14767
- const input = mergeStepBindings(this.pipelineStepInputBindings, normalizeInputMapping(rawInput));
14768
- const stepConfig = { step, input };
14769
- if (configFn) {
14770
- const cfg = {};
14771
- configFn(cfg);
14772
- if (cfg.timeout !== undefined)
14773
- stepConfig.timeout = cfg.timeout;
14774
- }
14775
- this.steps.push(stepConfig);
14776
- return new PipelineStepAdvancementBuilder(this.inputSchema, this.meta, this.steps, this.pipelineInputBindings, this.pipelineStepInputBindings);
15139
+ step(step, options) {
15140
+ return pushStep(this.inputSchema, this.meta, this.nodes, this.pipelineInputBindings, this.pipelineStepInputBindings, step, options);
15141
+ }
15142
+ fanOutStep(step, config2) {
15143
+ return beginFanOut(this.inputSchema, this.meta, this.nodes, this.pipelineInputBindings, this.pipelineStepInputBindings, step, config2);
14777
15144
  }
14778
15145
  build() {
14779
15146
  const config2 = {
@@ -14783,7 +15150,7 @@ class PipelineStepBuilder {
14783
15150
  version: this.meta.version,
14784
15151
  status: this.meta.status,
14785
15152
  input: this.inputSchema,
14786
- steps: this.steps,
15153
+ nodes: this.nodes,
14787
15154
  pipelineInputBindings: this.pipelineInputBindings
14788
15155
  };
14789
15156
  return buildPipelineSpec(config2);
@@ -14793,7 +15160,7 @@ class PipelineStepBuilder {
14793
15160
  class PipelineBuilder {
14794
15161
  inputSchema;
14795
15162
  meta;
14796
- steps = [];
15163
+ nodes = [];
14797
15164
  pipelineInputBindings;
14798
15165
  pipelineStepInputBindings;
14799
15166
  constructor(meta3) {
@@ -14818,19 +15185,8 @@ class PipelineBuilder {
14818
15185
  }
14819
15186
  this.pipelineStepInputBindings = resolveAdditionalStepInputBindings("additionalStepInput", additionalStepInput);
14820
15187
  }
14821
- step(step, mapper, configFn) {
14822
- const ctx = makeStepInputCtx(this.inputSchema);
14823
- const rawInput = mapper ? mapper(ctx) : {};
14824
- const input = mergeStepBindings(this.pipelineStepInputBindings, normalizeInputMapping(rawInput));
14825
- const stepConfig = { step, input };
14826
- if (configFn) {
14827
- const cfg = {};
14828
- configFn(cfg);
14829
- if (cfg.timeout !== undefined)
14830
- stepConfig.timeout = cfg.timeout;
14831
- }
14832
- this.steps.push(stepConfig);
14833
- return new PipelineStepAdvancementBuilder(this.inputSchema, this.meta, this.steps, this.pipelineInputBindings, this.pipelineStepInputBindings);
15188
+ step(step, options) {
15189
+ return pushStep(this.inputSchema, this.meta, this.nodes, this.pipelineInputBindings, this.pipelineStepInputBindings, step, options);
14834
15190
  }
14835
15191
  }
14836
15192
  function pipeline(meta3) {
@@ -15891,7 +16247,7 @@ class StepExecutions extends HeyApiClient {
15891
16247
  class PipelineDefinitions extends HeyApiClient {
15892
16248
  createPipelineDefinition(options) {
15893
16249
  return (options.client ?? this.client).post({
15894
- url: "/api/linear-pipeline-definitions",
16250
+ url: "/api/pipeline-definitions",
15895
16251
  ...options,
15896
16252
  headers: {
15897
16253
  "Content-Type": "application/json",
@@ -15901,7 +16257,7 @@ class PipelineDefinitions extends HeyApiClient {
15901
16257
  }
15902
16258
  upsertPipelineDefinition(options) {
15903
16259
  return (options.client ?? this.client).put({
15904
- url: "/api/linear-pipeline-definitions",
16260
+ url: "/api/pipeline-definitions",
15905
16261
  ...options,
15906
16262
  headers: {
15907
16263
  "Content-Type": "application/json",
@@ -15910,14 +16266,14 @@ class PipelineDefinitions extends HeyApiClient {
15910
16266
  });
15911
16267
  }
15912
16268
  archivePipelineDefinition(options) {
15913
- return (options.client ?? this.client).put({ url: "/api/linear-pipeline-definitions/{linearPipelineDefinitionId}/archive", ...options });
16269
+ return (options.client ?? this.client).put({ url: "/api/pipeline-definitions/{pipelineDefinitionId}/archive", ...options });
15914
16270
  }
15915
16271
  unarchivePipelineDefinition(options) {
15916
- return (options.client ?? this.client).put({ url: "/api/linear-pipeline-definitions/{linearPipelineDefinitionId}/unarchive", ...options });
16272
+ return (options.client ?? this.client).put({ url: "/api/pipeline-definitions/{pipelineDefinitionId}/unarchive", ...options });
15917
16273
  }
15918
16274
  addPipelineStep(options) {
15919
16275
  return (options.client ?? this.client).post({
15920
- url: "/api/linear-pipeline-definitions/{linearPipelineDefinitionId}/steps",
16276
+ url: "/api/pipeline-definitions/{pipelineDefinitionId}/steps",
15921
16277
  ...options,
15922
16278
  headers: {
15923
16279
  "Content-Type": "application/json",
@@ -15926,11 +16282,11 @@ class PipelineDefinitions extends HeyApiClient {
15926
16282
  });
15927
16283
  }
15928
16284
  removePipelineStep(options) {
15929
- return (options.client ?? this.client).delete({ url: "/api/linear-pipeline-definitions/{linearPipelineDefinitionId}/steps/{linearPipelineStepDefinitionId}", ...options });
16285
+ return (options.client ?? this.client).delete({ url: "/api/pipeline-definitions/{pipelineDefinitionId}/steps/{pipelineStepDefinitionId}", ...options });
15930
16286
  }
15931
16287
  updatePipelineStep(options) {
15932
16288
  return (options.client ?? this.client).put({
15933
- url: "/api/linear-pipeline-definitions/{linearPipelineDefinitionId}/steps/{linearPipelineStepDefinitionId}",
16289
+ url: "/api/pipeline-definitions/{pipelineDefinitionId}/steps/{pipelineStepDefinitionId}",
15934
16290
  ...options,
15935
16291
  headers: {
15936
16292
  "Content-Type": "application/json",
@@ -15940,7 +16296,7 @@ class PipelineDefinitions extends HeyApiClient {
15940
16296
  }
15941
16297
  setPipelineStepAdvancementPolicy(options) {
15942
16298
  return (options.client ?? this.client).put({
15943
- url: "/api/linear-pipeline-definitions/{linearPipelineDefinitionId}/steps/{linearPipelineStepDefinitionId}/advancement-policy",
16299
+ url: "/api/pipeline-definitions/{pipelineDefinitionId}/steps/{pipelineStepDefinitionId}/advancement-policy",
15944
16300
  ...options,
15945
16301
  headers: {
15946
16302
  "Content-Type": "application/json",
@@ -15949,20 +16305,20 @@ class PipelineDefinitions extends HeyApiClient {
15949
16305
  });
15950
16306
  }
15951
16307
  getPipelineDefinition(options) {
15952
- return (options.client ?? this.client).get({ url: "/api/linear-pipeline-definitions/{linearPipelineDefinitionId}", ...options });
16308
+ return (options.client ?? this.client).get({ url: "/api/pipeline-definitions/{pipelineDefinitionId}", ...options });
15953
16309
  }
15954
16310
  listPipelineDefinitions(options) {
15955
- return (options.client ?? this.client).get({ url: "/api/projects/{projectId}/linear-pipeline-definitions", ...options });
16311
+ return (options.client ?? this.client).get({ url: "/api/projects/{projectId}/pipeline-definitions", ...options });
15956
16312
  }
15957
16313
  }
15958
16314
 
15959
16315
  class PipelineExecutions extends HeyApiClient {
15960
16316
  listPipelineExecutions(options) {
15961
- return (options.client ?? this.client).get({ url: "/api/linear-pipeline-executions", ...options });
16317
+ return (options.client ?? this.client).get({ url: "/api/pipeline-executions", ...options });
15962
16318
  }
15963
16319
  createPipelineExecution(options) {
15964
16320
  return (options.client ?? this.client).post({
15965
- url: "/api/linear-pipeline-executions",
16321
+ url: "/api/pipeline-executions",
15966
16322
  ...options,
15967
16323
  headers: {
15968
16324
  "Content-Type": "application/json",
@@ -15971,17 +16327,17 @@ class PipelineExecutions extends HeyApiClient {
15971
16327
  });
15972
16328
  }
15973
16329
  startPipelineExecution(options) {
15974
- return (options.client ?? this.client).put({ url: "/api/linear-pipeline-executions/{linearPipelineExecutionId}/start", ...options });
16330
+ return (options.client ?? this.client).put({ url: "/api/pipeline-executions/{pipelineExecutionId}/start", ...options });
15975
16331
  }
15976
16332
  queueFirstPipelineStepRun(options) {
15977
- return (options.client ?? this.client).post({ url: "/api/linear-pipeline-executions/{linearPipelineExecutionId}/step-runs/first", ...options });
16333
+ return (options.client ?? this.client).post({ url: "/api/pipeline-executions/{pipelineExecutionId}/step-runs/first", ...options });
15978
16334
  }
15979
16335
  markPipelineStepRunRunning(options) {
15980
- return (options.client ?? this.client).put({ url: "/api/linear-pipeline-executions/{linearPipelineExecutionId}/step-runs/{linearPipelineStepRunId}/running", ...options });
16336
+ return (options.client ?? this.client).put({ url: "/api/pipeline-executions/{pipelineExecutionId}/step-runs/{pipelineStepRunId}/running", ...options });
15981
16337
  }
15982
16338
  applyPipelineStepResult(options) {
15983
16339
  return (options.client ?? this.client).post({
15984
- url: "/api/linear-pipeline-executions/{linearPipelineExecutionId}/step-runs/{linearPipelineStepRunId}/results",
16340
+ url: "/api/pipeline-executions/{pipelineExecutionId}/step-runs/{pipelineStepRunId}/results",
15985
16341
  ...options,
15986
16342
  headers: {
15987
16343
  "Content-Type": "application/json",
@@ -15991,7 +16347,17 @@ class PipelineExecutions extends HeyApiClient {
15991
16347
  }
15992
16348
  acceptPipelineStepRun(options) {
15993
16349
  return (options.client ?? this.client).post({
15994
- url: "/api/linear-pipeline-executions/{linearPipelineExecutionId}/step-runs/{linearPipelineStepRunId}/accept",
16350
+ url: "/api/pipeline-executions/{pipelineExecutionId}/step-runs/{pipelineStepRunId}/accept",
16351
+ ...options,
16352
+ headers: {
16353
+ "Content-Type": "application/json",
16354
+ ...options.headers
16355
+ }
16356
+ });
16357
+ }
16358
+ acceptPipelineCohort(options) {
16359
+ return (options.client ?? this.client).post({
16360
+ url: "/api/pipeline-executions/{pipelineExecutionId}/cohorts/{originNodeDefinitionId}/accept",
15995
16361
  ...options,
15996
16362
  headers: {
15997
16363
  "Content-Type": "application/json",
@@ -16001,7 +16367,7 @@ class PipelineExecutions extends HeyApiClient {
16001
16367
  }
16002
16368
  rerunPipelineExecution(options) {
16003
16369
  return (options.client ?? this.client).post({
16004
- url: "/api/linear-pipeline-executions/{linearPipelineExecutionId}/rerun",
16370
+ url: "/api/pipeline-executions/{pipelineExecutionId}/rerun",
16005
16371
  ...options,
16006
16372
  headers: {
16007
16373
  "Content-Type": "application/json",
@@ -16010,19 +16376,22 @@ class PipelineExecutions extends HeyApiClient {
16010
16376
  });
16011
16377
  }
16012
16378
  cancelPipelineExecution(options) {
16013
- return (options.client ?? this.client).put({ url: "/api/linear-pipeline-executions/{linearPipelineExecutionId}/cancel", ...options });
16379
+ return (options.client ?? this.client).put({ url: "/api/pipeline-executions/{pipelineExecutionId}/cancel", ...options });
16014
16380
  }
16015
16381
  getPipelineExecution(options) {
16016
- return (options.client ?? this.client).get({ url: "/api/linear-pipeline-executions/{linearPipelineExecutionId}", ...options });
16382
+ return (options.client ?? this.client).get({ url: "/api/pipeline-executions/{pipelineExecutionId}", ...options });
16383
+ }
16384
+ getPipelineExecutionRoutedChain(options) {
16385
+ return (options.client ?? this.client).get({ url: "/api/pipeline-executions/{pipelineExecutionId}/routed-chain", ...options });
16017
16386
  }
16018
16387
  countPipelineExecutionsByPipeline(options) {
16019
- return (options.client ?? this.client).get({ url: "/api/linear-pipeline-executions/counts/by-pipeline", ...options });
16388
+ return (options.client ?? this.client).get({ url: "/api/pipeline-executions/counts/by-pipeline", ...options });
16020
16389
  }
16021
16390
  listPipelineDefinitionStepRollups(options) {
16022
- return (options.client ?? this.client).get({ url: "/api/linear-pipeline-executions/step-rollups/by-definition/{linearPipelineDefinitionId}", ...options });
16391
+ return (options.client ?? this.client).get({ url: "/api/pipeline-executions/step-rollups/by-definition/{pipelineDefinitionId}", ...options });
16023
16392
  }
16024
16393
  listPipelineDefinitionStepRuns(options) {
16025
- return (options.client ?? this.client).get({ url: "/api/linear-pipeline-executions/step-runs/by-definition/{linearPipelineDefinitionId}", ...options });
16394
+ return (options.client ?? this.client).get({ url: "/api/pipeline-executions/step-runs/by-definition/{pipelineDefinitionId}", ...options });
16026
16395
  }
16027
16396
  }
16028
16397
 
@@ -16394,23 +16763,35 @@ var buildPipelineDefinitionsClient = (pipelineDefinitions) => {
16394
16763
  stepDefMap.set(s.key, s);
16395
16764
  }
16396
16765
  }
16397
- const stepDefinitions = spec.steps.map((step) => {
16398
- const stepDef = stepDefMap.get(step.stepKey);
16766
+ const nonStepNode = spec.nodeDefinitions.find((node) => node.kind !== "step");
16767
+ if (nonStepNode) {
16768
+ throw new Error(`Pipeline "${spec.key}" contains a "${nonStepNode.kind}" node ("${nonStepNode.nodeKey}"), ` + `but fan-out pipelines cannot be pushed via the current wire contract yet. ` + `Only "step"-only (chain) pipelines can be pushed with \`upsertFromSpec\` today.`);
16769
+ }
16770
+ const ordered = tryOrderChainNodeDefinitions(spec.nodeDefinitions, spec.dependencyEdges);
16771
+ if (ordered === null) {
16772
+ throw new Error(`Pipeline "${spec.key}" has a malformed step graph: its node and ` + `dependency-edge definitions do not form a single connected, ` + `acyclic chain. This should not happen from the \`pipeline()\` ` + `builder \u2014 check for hand-edited or generated pipeline specs.`);
16773
+ }
16774
+ const stepDefinitions = ordered.map((node, index) => {
16775
+ const stepKey = node.stepKey;
16776
+ if (!stepKey) {
16777
+ throw new Error(`Node "${node.nodeKey}" in pipeline "${spec.key}" has no stepKey.`);
16778
+ }
16779
+ const stepDef = stepDefMap.get(stepKey);
16399
16780
  if (!stepDef) {
16400
- throw new Error(`Step "${step.stepKey}" referenced in pipeline "${spec.key}" was not found on the server. ` + `Run \`boboddy steps push\` first to push your step definitions.`);
16781
+ throw new Error(`Step "${stepKey}" referenced in pipeline "${spec.key}" was not found on the server. ` + `Run \`boboddy steps push\` first to push your step definitions.`);
16401
16782
  }
16402
16783
  return {
16403
16784
  stepDefinitionId: stepDef.id,
16404
16785
  stepDefinitionVersion: stepDef.version,
16405
- key: step.stepKey,
16406
- name: step.stepName,
16407
- description: step.stepDescription,
16408
- position: step.position,
16409
- inputBindingsJson: step.inputBindingsJson,
16410
- timeoutSeconds: step.timeoutSeconds,
16786
+ key: node.nodeKey,
16787
+ name: node.stepName ?? "",
16788
+ description: node.stepDescription ?? null,
16789
+ position: index + 1,
16790
+ inputBindingsJson: node.inputBindingsJson ?? {},
16791
+ timeoutSeconds: node.timeoutSeconds ?? null,
16411
16792
  retryPolicyJson: null,
16412
- advancementPolicyDefinition: step.advancementPolicyDefinition,
16413
- computedSignalDefinitions: step.computedSignalDefinitions
16793
+ advancementPolicyDefinition: node.advancementPolicyDefinition,
16794
+ computedSignalDefinitions: node.computedSignalDefinitions ?? []
16414
16795
  };
16415
16796
  });
16416
16797
  const body = {
@@ -16445,7 +16826,12 @@ function makeLeaf(fact, path, operator, value) {
16445
16826
  return {
16446
16827
  _condition: condition,
16447
16828
  then(outcome) {
16448
- return { _tag: "assignment_rule", conditions: [condition], mode: "all", outcome };
16829
+ return {
16830
+ _tag: "assignment_rule",
16831
+ conditions: [condition],
16832
+ mode: "all",
16833
+ outcome
16834
+ };
16449
16835
  }
16450
16836
  };
16451
16837
  }
@@ -16464,7 +16850,7 @@ function makeFieldRef(fact, path) {
16464
16850
  };
16465
16851
  }
16466
16852
  function makeAssign(pipeline2) {
16467
- if (typeof pipeline2 !== "object" || typeof pipeline2["key"] !== "string" || !Array.isArray(pipeline2["steps"])) {
16853
+ if (typeof pipeline2 !== "object" || typeof pipeline2["key"] !== "string" || !Array.isArray(pipeline2["nodeDefinitions"])) {
16468
16854
  throw new Error("assign() requires a pipeline spec produced by pipeline().build(). " + "Pass the default-exported value from a pipeline definition file.");
16469
16855
  }
16470
16856
  return { _tag: "assign", pipeline: pipeline2 };
@@ -16552,7 +16938,7 @@ function serializeDefaultPipelineAssignment(spec) {
16552
16938
  return serializeAssignmentRule(rule);
16553
16939
  });
16554
16940
  return {
16555
- linearPipelineDefinitionKey: primaryKey,
16941
+ pipelineDefinitionKey: primaryKey,
16556
16942
  rulesJson: { rules: serializedRules },
16557
16943
  defaultEventType: defaultType,
16558
16944
  defaultEventParamsJson: defaultParams,
@@ -16577,7 +16963,6 @@ export {
16577
16963
  buildPipelineSpec,
16578
16964
  Rule,
16579
16965
  PipelineStepBuilder,
16580
- PipelineStepAdvancementBuilder,
16581
16966
  PipelineBuilder,
16582
16967
  DEFAULT_PIPELINE_ASSIGNMENT_FILENAME,
16583
16968
  Computed