@boboddy/sdk 0.3.1 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1069,7 +1069,7 @@ class StepExecutions extends HeyApiClient {
1069
1069
  class PipelineDefinitions extends HeyApiClient {
1070
1070
  createPipelineDefinition(options) {
1071
1071
  return (options.client ?? this.client).post({
1072
- url: "/api/linear-pipeline-definitions",
1072
+ url: "/api/pipeline-definitions",
1073
1073
  ...options,
1074
1074
  headers: {
1075
1075
  "Content-Type": "application/json",
@@ -1079,7 +1079,7 @@ class PipelineDefinitions extends HeyApiClient {
1079
1079
  }
1080
1080
  upsertPipelineDefinition(options) {
1081
1081
  return (options.client ?? this.client).put({
1082
- url: "/api/linear-pipeline-definitions",
1082
+ url: "/api/pipeline-definitions",
1083
1083
  ...options,
1084
1084
  headers: {
1085
1085
  "Content-Type": "application/json",
@@ -1088,14 +1088,14 @@ class PipelineDefinitions extends HeyApiClient {
1088
1088
  });
1089
1089
  }
1090
1090
  archivePipelineDefinition(options) {
1091
- return (options.client ?? this.client).put({ url: "/api/linear-pipeline-definitions/{linearPipelineDefinitionId}/archive", ...options });
1091
+ return (options.client ?? this.client).put({ url: "/api/pipeline-definitions/{pipelineDefinitionId}/archive", ...options });
1092
1092
  }
1093
1093
  unarchivePipelineDefinition(options) {
1094
- return (options.client ?? this.client).put({ url: "/api/linear-pipeline-definitions/{linearPipelineDefinitionId}/unarchive", ...options });
1094
+ return (options.client ?? this.client).put({ url: "/api/pipeline-definitions/{pipelineDefinitionId}/unarchive", ...options });
1095
1095
  }
1096
1096
  addPipelineStep(options) {
1097
1097
  return (options.client ?? this.client).post({
1098
- url: "/api/linear-pipeline-definitions/{linearPipelineDefinitionId}/steps",
1098
+ url: "/api/pipeline-definitions/{pipelineDefinitionId}/steps",
1099
1099
  ...options,
1100
1100
  headers: {
1101
1101
  "Content-Type": "application/json",
@@ -1104,11 +1104,11 @@ class PipelineDefinitions extends HeyApiClient {
1104
1104
  });
1105
1105
  }
1106
1106
  removePipelineStep(options) {
1107
- return (options.client ?? this.client).delete({ url: "/api/linear-pipeline-definitions/{linearPipelineDefinitionId}/steps/{linearPipelineStepDefinitionId}", ...options });
1107
+ return (options.client ?? this.client).delete({ url: "/api/pipeline-definitions/{pipelineDefinitionId}/steps/{pipelineStepDefinitionId}", ...options });
1108
1108
  }
1109
1109
  updatePipelineStep(options) {
1110
1110
  return (options.client ?? this.client).put({
1111
- url: "/api/linear-pipeline-definitions/{linearPipelineDefinitionId}/steps/{linearPipelineStepDefinitionId}",
1111
+ url: "/api/pipeline-definitions/{pipelineDefinitionId}/steps/{pipelineStepDefinitionId}",
1112
1112
  ...options,
1113
1113
  headers: {
1114
1114
  "Content-Type": "application/json",
@@ -1118,7 +1118,7 @@ class PipelineDefinitions extends HeyApiClient {
1118
1118
  }
1119
1119
  setPipelineStepAdvancementPolicy(options) {
1120
1120
  return (options.client ?? this.client).put({
1121
- url: "/api/linear-pipeline-definitions/{linearPipelineDefinitionId}/steps/{linearPipelineStepDefinitionId}/advancement-policy",
1121
+ url: "/api/pipeline-definitions/{pipelineDefinitionId}/steps/{pipelineStepDefinitionId}/advancement-policy",
1122
1122
  ...options,
1123
1123
  headers: {
1124
1124
  "Content-Type": "application/json",
@@ -1127,20 +1127,20 @@ class PipelineDefinitions extends HeyApiClient {
1127
1127
  });
1128
1128
  }
1129
1129
  getPipelineDefinition(options) {
1130
- return (options.client ?? this.client).get({ url: "/api/linear-pipeline-definitions/{linearPipelineDefinitionId}", ...options });
1130
+ return (options.client ?? this.client).get({ url: "/api/pipeline-definitions/{pipelineDefinitionId}", ...options });
1131
1131
  }
1132
1132
  listPipelineDefinitions(options) {
1133
- return (options.client ?? this.client).get({ url: "/api/projects/{projectId}/linear-pipeline-definitions", ...options });
1133
+ return (options.client ?? this.client).get({ url: "/api/projects/{projectId}/pipeline-definitions", ...options });
1134
1134
  }
1135
1135
  }
1136
1136
 
1137
1137
  class PipelineExecutions extends HeyApiClient {
1138
1138
  listPipelineExecutions(options) {
1139
- return (options.client ?? this.client).get({ url: "/api/linear-pipeline-executions", ...options });
1139
+ return (options.client ?? this.client).get({ url: "/api/pipeline-executions", ...options });
1140
1140
  }
1141
1141
  createPipelineExecution(options) {
1142
1142
  return (options.client ?? this.client).post({
1143
- url: "/api/linear-pipeline-executions",
1143
+ url: "/api/pipeline-executions",
1144
1144
  ...options,
1145
1145
  headers: {
1146
1146
  "Content-Type": "application/json",
@@ -1149,17 +1149,17 @@ class PipelineExecutions extends HeyApiClient {
1149
1149
  });
1150
1150
  }
1151
1151
  startPipelineExecution(options) {
1152
- return (options.client ?? this.client).put({ url: "/api/linear-pipeline-executions/{linearPipelineExecutionId}/start", ...options });
1152
+ return (options.client ?? this.client).put({ url: "/api/pipeline-executions/{pipelineExecutionId}/start", ...options });
1153
1153
  }
1154
1154
  queueFirstPipelineStepRun(options) {
1155
- return (options.client ?? this.client).post({ url: "/api/linear-pipeline-executions/{linearPipelineExecutionId}/step-runs/first", ...options });
1155
+ return (options.client ?? this.client).post({ url: "/api/pipeline-executions/{pipelineExecutionId}/step-runs/first", ...options });
1156
1156
  }
1157
1157
  markPipelineStepRunRunning(options) {
1158
- return (options.client ?? this.client).put({ url: "/api/linear-pipeline-executions/{linearPipelineExecutionId}/step-runs/{linearPipelineStepRunId}/running", ...options });
1158
+ return (options.client ?? this.client).put({ url: "/api/pipeline-executions/{pipelineExecutionId}/step-runs/{pipelineStepRunId}/running", ...options });
1159
1159
  }
1160
1160
  applyPipelineStepResult(options) {
1161
1161
  return (options.client ?? this.client).post({
1162
- url: "/api/linear-pipeline-executions/{linearPipelineExecutionId}/step-runs/{linearPipelineStepRunId}/results",
1162
+ url: "/api/pipeline-executions/{pipelineExecutionId}/step-runs/{pipelineStepRunId}/results",
1163
1163
  ...options,
1164
1164
  headers: {
1165
1165
  "Content-Type": "application/json",
@@ -1169,7 +1169,17 @@ class PipelineExecutions extends HeyApiClient {
1169
1169
  }
1170
1170
  acceptPipelineStepRun(options) {
1171
1171
  return (options.client ?? this.client).post({
1172
- url: "/api/linear-pipeline-executions/{linearPipelineExecutionId}/step-runs/{linearPipelineStepRunId}/accept",
1172
+ url: "/api/pipeline-executions/{pipelineExecutionId}/step-runs/{pipelineStepRunId}/accept",
1173
+ ...options,
1174
+ headers: {
1175
+ "Content-Type": "application/json",
1176
+ ...options.headers
1177
+ }
1178
+ });
1179
+ }
1180
+ acceptPipelineCohort(options) {
1181
+ return (options.client ?? this.client).post({
1182
+ url: "/api/pipeline-executions/{pipelineExecutionId}/cohorts/{originNodeDefinitionId}/accept",
1173
1183
  ...options,
1174
1184
  headers: {
1175
1185
  "Content-Type": "application/json",
@@ -1179,7 +1189,7 @@ class PipelineExecutions extends HeyApiClient {
1179
1189
  }
1180
1190
  rerunPipelineExecution(options) {
1181
1191
  return (options.client ?? this.client).post({
1182
- url: "/api/linear-pipeline-executions/{linearPipelineExecutionId}/rerun",
1192
+ url: "/api/pipeline-executions/{pipelineExecutionId}/rerun",
1183
1193
  ...options,
1184
1194
  headers: {
1185
1195
  "Content-Type": "application/json",
@@ -1188,19 +1198,32 @@ class PipelineExecutions extends HeyApiClient {
1188
1198
  });
1189
1199
  }
1190
1200
  cancelPipelineExecution(options) {
1191
- return (options.client ?? this.client).put({ url: "/api/linear-pipeline-executions/{linearPipelineExecutionId}/cancel", ...options });
1201
+ return (options.client ?? this.client).put({ url: "/api/pipeline-executions/{pipelineExecutionId}/cancel", ...options });
1202
+ }
1203
+ cancelPipelineExecutions(options) {
1204
+ return (options.client ?? this.client).put({
1205
+ url: "/api/pipeline-executions/batch/cancel",
1206
+ ...options,
1207
+ headers: {
1208
+ "Content-Type": "application/json",
1209
+ ...options.headers
1210
+ }
1211
+ });
1192
1212
  }
1193
1213
  getPipelineExecution(options) {
1194
- return (options.client ?? this.client).get({ url: "/api/linear-pipeline-executions/{linearPipelineExecutionId}", ...options });
1214
+ return (options.client ?? this.client).get({ url: "/api/pipeline-executions/{pipelineExecutionId}", ...options });
1215
+ }
1216
+ getPipelineExecutionRoutedChain(options) {
1217
+ return (options.client ?? this.client).get({ url: "/api/pipeline-executions/{pipelineExecutionId}/routed-chain", ...options });
1195
1218
  }
1196
1219
  countPipelineExecutionsByPipeline(options) {
1197
- return (options.client ?? this.client).get({ url: "/api/linear-pipeline-executions/counts/by-pipeline", ...options });
1220
+ return (options.client ?? this.client).get({ url: "/api/pipeline-executions/counts/by-pipeline", ...options });
1198
1221
  }
1199
1222
  listPipelineDefinitionStepRollups(options) {
1200
- return (options.client ?? this.client).get({ url: "/api/linear-pipeline-executions/step-rollups/by-definition/{linearPipelineDefinitionId}", ...options });
1223
+ return (options.client ?? this.client).get({ url: "/api/pipeline-executions/step-rollups/by-definition/{pipelineDefinitionId}", ...options });
1201
1224
  }
1202
1225
  listPipelineDefinitionStepRuns(options) {
1203
- return (options.client ?? this.client).get({ url: "/api/linear-pipeline-executions/step-runs/by-definition/{linearPipelineDefinitionId}", ...options });
1226
+ return (options.client ?? this.client).get({ url: "/api/pipeline-executions/step-runs/by-definition/{pipelineDefinitionId}", ...options });
1204
1227
  }
1205
1228
  }
1206
1229
 
@@ -1211,6 +1234,19 @@ class WorkItems extends HeyApiClient {
1211
1234
  getWorkItem(options) {
1212
1235
  return (options.client ?? this.client).get({ url: "/api/work-items/{workItemId}", ...options });
1213
1236
  }
1237
+ editWorkItem(options) {
1238
+ return (options.client ?? this.client).patch({
1239
+ url: "/api/work-items/{workItemId}",
1240
+ ...options,
1241
+ headers: {
1242
+ "Content-Type": "application/json",
1243
+ ...options.headers
1244
+ }
1245
+ });
1246
+ }
1247
+ listWorkItemChildren(options) {
1248
+ return (options.client ?? this.client).get({ url: "/api/work-items/{workItemId}/children", ...options });
1249
+ }
1214
1250
  createWorkItem(options) {
1215
1251
  return (options.client ?? this.client).post({
1216
1252
  url: "/api/work-items",
@@ -1261,6 +1297,16 @@ class WorkItems extends HeyApiClient {
1261
1297
  }
1262
1298
  });
1263
1299
  }
1300
+ setWorkItemParent(options) {
1301
+ return (options.client ?? this.client).patch({
1302
+ url: "/api/work-items/{workItemId}/parent",
1303
+ ...options,
1304
+ headers: {
1305
+ "Content-Type": "application/json",
1306
+ ...options.headers
1307
+ }
1308
+ });
1309
+ }
1264
1310
  }
1265
1311
 
1266
1312
  class WorkItemComments extends HeyApiClient {
@@ -1302,6 +1348,25 @@ class WorkItemComments extends HeyApiClient {
1302
1348
  }
1303
1349
  }
1304
1350
 
1351
+ class WorkItemBlocks extends HeyApiClient {
1352
+ listWorkItemBlocks(options) {
1353
+ return (options.client ?? this.client).get({ url: "/api/work-item-blocks", ...options });
1354
+ }
1355
+ createWorkItemBlock(options) {
1356
+ return (options.client ?? this.client).post({
1357
+ url: "/api/work-item-blocks",
1358
+ ...options,
1359
+ headers: {
1360
+ "Content-Type": "application/json",
1361
+ ...options.headers
1362
+ }
1363
+ });
1364
+ }
1365
+ deleteWorkItemBlock(options) {
1366
+ return (options.client ?? this.client).delete({ url: "/api/work-item-blocks/{blockId}", ...options });
1367
+ }
1368
+ }
1369
+
1305
1370
  class ProjectContext extends HeyApiClient {
1306
1371
  listProjectContextEntries(options) {
1307
1372
  return (options.client ?? this.client).get({ url: "/api/projects/{projectId}/context-entries", ...options });
@@ -1510,6 +1575,10 @@ class BoboddyClient extends HeyApiClient {
1510
1575
  get workItemComments() {
1511
1576
  return this._workItemComments ??= new WorkItemComments({ client: this.client });
1512
1577
  }
1578
+ _workItemBlocks;
1579
+ get workItemBlocks() {
1580
+ return this._workItemBlocks ??= new WorkItemBlocks({ client: this.client });
1581
+ }
1513
1582
  _projectContext;
1514
1583
  get projectContext() {
1515
1584
  return this._projectContext ??= new ProjectContext({ client: this.client });
@@ -16326,6 +16395,140 @@ function extractInlineComputedSignals(policy) {
16326
16395
  return [...byKey.values()];
16327
16396
  }
16328
16397
 
16398
+ // src/definitions/advancement-policies/cohort-advancement-policy.ts
16399
+ var cohortAdvancementEventTypeValues = ["continue", "block"];
16400
+ function serializeCohortCondition(condition) {
16401
+ if (condition._tag === "signal") {
16402
+ return {
16403
+ fact: typeof condition.signal === "string" ? condition.signal : condition.signal.key,
16404
+ operator: condition.operator,
16405
+ value: condition.value
16406
+ };
16407
+ }
16408
+ if (condition._tag === "all") {
16409
+ return { all: condition.conditions.map(serializeCohortCondition) };
16410
+ }
16411
+ return { any: condition.conditions.map(serializeCohortCondition) };
16412
+ }
16413
+ function serializeCohortRule(rule) {
16414
+ return {
16415
+ conditions: { [rule.mode]: rule.conditions.map(serializeCohortCondition) },
16416
+ event: {
16417
+ type: rule.outcome,
16418
+ ...rule.outcomeJson ? { params: rule.outcomeJson } : {}
16419
+ }
16420
+ };
16421
+ }
16422
+ function serializeCohortAdvancementPolicy(policy) {
16423
+ if (!policy) {
16424
+ return { rules: [], defaultEventType: "continue", defaultEventParamsJson: null };
16425
+ }
16426
+ return {
16427
+ rules: (policy.rules ?? []).map(serializeCohortRule),
16428
+ defaultEventType: policy.default,
16429
+ defaultEventParamsJson: policy.defaultParamsJson ?? null
16430
+ };
16431
+ }
16432
+ function visitCohortSignalConditions(conditions, visit) {
16433
+ for (const c of conditions) {
16434
+ if (c._tag === "signal") {
16435
+ visit(c);
16436
+ } else {
16437
+ visitCohortSignalConditions(c.conditions, visit);
16438
+ }
16439
+ }
16440
+ }
16441
+ function isSameStepSignalsListDefinition(a, b) {
16442
+ return JSON.stringify(a.ops) === JSON.stringify(b.ops) && JSON.stringify(a.reducer) === JSON.stringify(b.reducer);
16443
+ }
16444
+ function extractInlineStepSignalsListDefinitions(policy) {
16445
+ if (!policy?.rules)
16446
+ return [];
16447
+ const byKey = new Map;
16448
+ for (const rule of policy.rules) {
16449
+ visitCohortSignalConditions(rule.conditions, (cond) => {
16450
+ if (typeof cond.signal === "string")
16451
+ return;
16452
+ const inline = cond.signal;
16453
+ const def = {
16454
+ key: inline.key,
16455
+ ops: inline.ops,
16456
+ reducer: inline.reducer
16457
+ };
16458
+ const existing = byKey.get(def.key);
16459
+ if (existing) {
16460
+ if (!isSameStepSignalsListDefinition(existing, def)) {
16461
+ throw new Error(`Conflicting inline stepSignalsList definitions for key "${def.key}"`);
16462
+ }
16463
+ return;
16464
+ }
16465
+ byKey.set(def.key, def);
16466
+ });
16467
+ }
16468
+ return [...byKey.values()];
16469
+ }
16470
+
16471
+ // src/definitions/pipelines/chain-graph.ts
16472
+ function tryOrderChainNodeDefinitions(nodeDefinitions, dependencyEdges) {
16473
+ const nodesByKey = new Map;
16474
+ for (const nodeDefinition of nodeDefinitions) {
16475
+ nodesByKey.set(nodeDefinition.nodeKey, nodeDefinition);
16476
+ }
16477
+ const outgoing = new Map;
16478
+ const incomingCount = new Map;
16479
+ for (const nodeDefinition of nodeDefinitions) {
16480
+ incomingCount.set(nodeDefinition.nodeKey, 0);
16481
+ }
16482
+ for (const edge of dependencyEdges) {
16483
+ if (!nodesByKey.has(edge.fromNodeKey) || !nodesByKey.has(edge.toNodeKey)) {
16484
+ return null;
16485
+ }
16486
+ if (outgoing.has(edge.fromNodeKey))
16487
+ return null;
16488
+ outgoing.set(edge.fromNodeKey, edge.toNodeKey);
16489
+ incomingCount.set(edge.toNodeKey, (incomingCount.get(edge.toNodeKey) ?? 0) + 1);
16490
+ }
16491
+ for (const count of incomingCount.values()) {
16492
+ if (count > 1)
16493
+ return null;
16494
+ }
16495
+ if (nodeDefinitions.length === 0)
16496
+ return [];
16497
+ const roots = nodeDefinitions.filter((nodeDefinition) => (incomingCount.get(nodeDefinition.nodeKey) ?? 0) === 0);
16498
+ if (roots.length !== 1)
16499
+ return null;
16500
+ const rootNode = roots[0];
16501
+ if (!rootNode)
16502
+ return null;
16503
+ const ordered = [];
16504
+ const visited = new Set;
16505
+ let currentKey = rootNode.nodeKey;
16506
+ while (currentKey !== undefined) {
16507
+ if (visited.has(currentKey))
16508
+ return null;
16509
+ visited.add(currentKey);
16510
+ const currentNode = nodesByKey.get(currentKey);
16511
+ if (!currentNode)
16512
+ return null;
16513
+ ordered.push(currentNode);
16514
+ currentKey = outgoing.get(currentKey);
16515
+ }
16516
+ if (ordered.length !== nodeDefinitions.length)
16517
+ return null;
16518
+ return ordered;
16519
+ }
16520
+ function buildChainDependencyEdges(orderedNodes) {
16521
+ const dependencyEdges = [];
16522
+ for (let index = 0;index < orderedNodes.length - 1; index += 1) {
16523
+ const from = orderedNodes[index];
16524
+ const to = orderedNodes[index + 1];
16525
+ if (!from || !to)
16526
+ continue;
16527
+ dependencyEdges.push({ fromNodeKey: from.nodeKey, toNodeKey: to.nodeKey });
16528
+ }
16529
+ return dependencyEdges;
16530
+ }
16531
+
16329
16532
  // src/definitions/pipelines/define-pipeline.ts
16330
16533
  function serializeBinding(binding) {
16331
16534
  if (binding.source === "pipeline_input") {
@@ -16344,15 +16547,42 @@ function serializeBinding(binding) {
16344
16547
  if (binding.source === "literal") {
16345
16548
  return { source: "literal", value: binding.value };
16346
16549
  }
16550
+ if (binding.source === "signals_list") {
16551
+ return { source: "signals_list", stepKey: binding.fanOutStep.key };
16552
+ }
16553
+ if (binding.source === "fan_out_item") {
16554
+ return { source: "fan_out_item" };
16555
+ }
16347
16556
  return { source: "step_output", stepKey: binding.step.key };
16348
16557
  }
16558
+ var isFanOutConfig = (node) => ("nodeType" in node) && node.nodeType === "fanOut";
16559
+ var isCohortGateConfig = (node) => ("nodeType" in node) && node.nodeType === "cohortGate";
16560
+ function serializeInputBindings(input, pipelineInputBindings) {
16561
+ const autoBindings = {
16562
+ workItemTitle: { source: "work_item", field: "title" },
16563
+ workItemDescription: { source: "work_item", field: "description" }
16564
+ };
16565
+ const pipelineBindings = {};
16566
+ for (const [key, binding] of Object.entries(pipelineInputBindings ?? {})) {
16567
+ pipelineBindings[key] = serializeBinding(binding);
16568
+ }
16569
+ const explicitBindings = Object.fromEntries(Object.entries(input ?? {}).filter((entry) => entry[1] !== undefined).map(([key, binding]) => [key, serializeBinding(binding)]));
16570
+ return { ...autoBindings, ...pipelineBindings, ...explicitBindings };
16571
+ }
16349
16572
  function buildPipelineSpec(config2) {
16350
- const steps = config2.steps;
16573
+ const nodes = config2.nodes;
16351
16574
  const stepDefMap = new Map;
16352
- for (const stepConfig of steps) {
16353
- const mapKey = `${stepConfig.step.key}@v${String(stepConfig.step.version)}`;
16575
+ const registerStepDef = (step) => {
16576
+ const mapKey = `${step.key}@v${String(step.version)}`;
16354
16577
  if (!stepDefMap.has(mapKey)) {
16355
- stepDefMap.set(mapKey, stepConfig.step);
16578
+ stepDefMap.set(mapKey, step);
16579
+ }
16580
+ };
16581
+ for (const node of nodes) {
16582
+ if (isFanOutConfig(node)) {
16583
+ registerStepDef(node.fanOutStep);
16584
+ } else if (!isCohortGateConfig(node)) {
16585
+ registerStepDef(node.step);
16356
16586
  }
16357
16587
  }
16358
16588
  let inputSchemaJson = null;
@@ -16363,6 +16593,46 @@ function buildPipelineSpec(config2) {
16363
16593
  inputSchemaJson = null;
16364
16594
  }
16365
16595
  }
16596
+ const nodeDefinitions = nodes.map((node) => {
16597
+ if (isCohortGateConfig(node)) {
16598
+ const serializedPolicy = serializeCohortAdvancementPolicy(node.advanceAll);
16599
+ const inlineStepSignalsListDefinitions = extractInlineStepSignalsListDefinitions(node.advanceAll);
16600
+ return {
16601
+ nodeKey: node.nodeKey,
16602
+ kind: "cohortGate",
16603
+ advanceAllPolicyDefinition: serializedPolicy,
16604
+ stepSignalsListDefinitions: [
16605
+ ...inlineStepSignalsListDefinitions,
16606
+ ...node.stepSignalsListDefinitions ?? []
16607
+ ]
16608
+ };
16609
+ }
16610
+ if (isFanOutConfig(node)) {
16611
+ return {
16612
+ nodeKey: node.fanOutStep.key,
16613
+ kind: "fanOut",
16614
+ stepKey: node.fanOutStep.key,
16615
+ stepName: node.fanOutStep.name,
16616
+ stepDescription: node.fanOutStep.description,
16617
+ inputBindingsJson: serializeInputBindings(node.input, config2.pipelineInputBindings),
16618
+ timeoutSeconds: node.timeout ?? null,
16619
+ overSignalKey: node.overSignalKey,
16620
+ advanceEachPolicyDefinition: serializeCohortAdvancementPolicy(node.advanceEach)
16621
+ };
16622
+ }
16623
+ return {
16624
+ nodeKey: node.step.key,
16625
+ kind: "step",
16626
+ stepKey: node.step.key,
16627
+ stepName: node.step.name,
16628
+ stepDescription: node.step.description,
16629
+ inputBindingsJson: serializeInputBindings(node.input, config2.pipelineInputBindings),
16630
+ timeoutSeconds: node.timeout ?? null,
16631
+ advancementPolicyDefinition: serializeAdvancementPolicy(node.advancement),
16632
+ computedSignalDefinitions: extractInlineComputedSignals(node.advancement)
16633
+ };
16634
+ });
16635
+ const dependencyEdges = buildChainDependencyEdges(nodeDefinitions);
16366
16636
  return {
16367
16637
  key: config2.key,
16368
16638
  name: config2.name,
@@ -16371,31 +16641,8 @@ function buildPipelineSpec(config2) {
16371
16641
  status: config2.status ?? "active",
16372
16642
  inputSchemaJson,
16373
16643
  _stepDefinitions: [...stepDefMap.values()],
16374
- steps: steps.map((stepConfig, index) => {
16375
- const autoBindings = {
16376
- workItemTitle: { source: "work_item", field: "title" },
16377
- workItemDescription: { source: "work_item", field: "description" }
16378
- };
16379
- const pipelineBindings = {};
16380
- for (const [key, binding] of Object.entries(config2.pipelineInputBindings ?? {})) {
16381
- pipelineBindings[key] = serializeBinding(binding);
16382
- }
16383
- const explicitStepBindings = Object.fromEntries(Object.entries(stepConfig.input ?? {}).filter((entry) => entry[1] !== undefined).map(([key, binding]) => [key, serializeBinding(binding)]));
16384
- return {
16385
- stepKey: stepConfig.step.key,
16386
- stepName: stepConfig.step.name,
16387
- stepDescription: stepConfig.step.description,
16388
- position: index + 1,
16389
- inputBindingsJson: {
16390
- ...autoBindings,
16391
- ...pipelineBindings,
16392
- ...explicitStepBindings
16393
- },
16394
- timeoutSeconds: stepConfig.timeout ?? null,
16395
- advancementPolicyDefinition: serializeAdvancementPolicy(stepConfig.advancement),
16396
- computedSignalDefinitions: extractInlineComputedSignals(stepConfig.advancement)
16397
- };
16398
- })
16644
+ nodeDefinitions,
16645
+ dependencyEdges
16399
16646
  };
16400
16647
  }
16401
16648
  // src/definitions/advancement-policies/fluent-rules.ts
@@ -16566,7 +16813,10 @@ function makeStepInputCtx(inputSchema) {
16566
16813
  output(step) {
16567
16814
  return { source: "step_output", step };
16568
16815
  },
16569
- literal: literal2
16816
+ literal: literal2,
16817
+ signalsList(fanOutStep) {
16818
+ return { source: "signals_list", fanOutStep };
16819
+ }
16570
16820
  };
16571
16821
  }
16572
16822
  function literal2(value) {
@@ -16611,61 +16861,247 @@ function mergeStepBindings(pipelineBindings, explicitBindings) {
16611
16861
  return Object.keys(merged).length > 0 ? merged : undefined;
16612
16862
  }
16613
16863
 
16614
- // src/definitions/pipelines/builder.ts
16615
- class PipelineStepAdvancementBuilder {
16616
- inputSchema;
16617
- meta;
16618
- steps;
16619
- pipelineInputBindings;
16620
- pipelineStepInputBindings;
16621
- constructor(inputSchema, meta3, steps, pipelineInputBindings = {}, pipelineStepInputBindings = {}) {
16622
- this.inputSchema = inputSchema;
16623
- this.meta = meta3;
16624
- this.steps = steps;
16625
- this.pipelineInputBindings = pipelineInputBindings;
16626
- this.pipelineStepInputBindings = pipelineStepInputBindings;
16627
- }
16628
- advance(callback) {
16629
- const last = this.steps.at(-1);
16630
- if (!last)
16631
- throw new Error("Internal error: no steps available");
16632
- const ctx = makeAdvanceCtx();
16633
- const result = callback(ctx);
16634
- const policy = {
16635
- defaultOutcome: result.default,
16636
- ...result.rules !== undefined ? { rules: result.rules } : {}
16864
+ // src/definitions/advancement-policies/cohort-fluent-rules.ts
16865
+ var LEAF_BRAND2 = Symbol("boboddy.cohortRule.leaf");
16866
+ var GROUP_BRAND2 = Symbol("boboddy.cohortRule.group");
16867
+ function createCohortSignalRef(signal2) {
16868
+ const leaf = (operator, value) => {
16869
+ const condition = {
16870
+ _tag: "signal",
16871
+ signal: signal2,
16872
+ operator,
16873
+ value
16637
16874
  };
16638
- last.advancement = policy;
16639
- return new PipelineStepBuilder(this.inputSchema, this.meta, this.steps, this.pipelineInputBindings, this.pipelineStepInputBindings);
16640
- }
16875
+ return {
16876
+ [LEAF_BRAND2]: condition,
16877
+ then(outcome, paramsJson) {
16878
+ return {
16879
+ _tag: "rule",
16880
+ mode: "all",
16881
+ conditions: [condition],
16882
+ outcome,
16883
+ ...paramsJson ? { outcomeJson: paramsJson } : {}
16884
+ };
16885
+ }
16886
+ };
16887
+ };
16888
+ return {
16889
+ eq: (v) => leaf("equal", v),
16890
+ ne: (v) => leaf("notEqual", v),
16891
+ gt: (v) => leaf("greaterThan", v),
16892
+ gte: (v) => leaf("greaterThanInclusive", v),
16893
+ lt: (v) => leaf("lessThan", v),
16894
+ lte: (v) => leaf("lessThanInclusive", v),
16895
+ in: (vs) => leaf("in", vs),
16896
+ notIn: (vs) => leaf("notIn", vs),
16897
+ contains: (v) => leaf("contains", v),
16898
+ doesNotContain: (v) => leaf("doesNotContain", v)
16899
+ };
16900
+ }
16901
+ function createCohortLeafFromCondition(condition) {
16902
+ return {
16903
+ [LEAF_BRAND2]: condition,
16904
+ then(outcome, paramsJson) {
16905
+ return {
16906
+ _tag: "rule",
16907
+ mode: "all",
16908
+ conditions: [condition],
16909
+ outcome,
16910
+ ...paramsJson ? { outcomeJson: paramsJson } : {}
16911
+ };
16912
+ }
16913
+ };
16914
+ }
16915
+ function extractCohortCondition(ref) {
16916
+ if (LEAF_BRAND2 in ref)
16917
+ return ref[LEAF_BRAND2];
16918
+ const group = ref[GROUP_BRAND2];
16919
+ return group.mode === "all" ? { _tag: "all", conditions: group.conditions } : { _tag: "any", conditions: group.conditions };
16920
+ }
16921
+ function createCohortGroup(mode, refs) {
16922
+ const conditions = refs.map(extractCohortCondition);
16923
+ return {
16924
+ [GROUP_BRAND2]: { mode, conditions },
16925
+ then(outcome, paramsJson) {
16926
+ return {
16927
+ _tag: "rule",
16928
+ mode,
16929
+ conditions,
16930
+ outcome,
16931
+ ...paramsJson ? { outcomeJson: paramsJson } : {}
16932
+ };
16933
+ }
16934
+ };
16935
+ }
16936
+ function makeKeyedCohortSignalRef(key) {
16937
+ return createCohortSignalRef(key);
16938
+ }
16939
+ function makeAdvanceEachCtx() {
16940
+ return {
16941
+ signal: (key) => makeKeyedCohortSignalRef(key),
16942
+ stepSignals: new Proxy({}, {
16943
+ get(_, key) {
16944
+ if (typeof key === "string")
16945
+ return makeKeyedCohortSignalRef(key);
16946
+ return;
16947
+ }
16948
+ }),
16949
+ all: (...refs) => createCohortGroup("all", refs),
16950
+ any: (...refs) => createCohortGroup("any", refs)
16951
+ };
16952
+ }
16953
+ var branchOutcomeValues = [
16954
+ "continue",
16955
+ "block",
16956
+ "error",
16957
+ "abandoned"
16958
+ ];
16959
+ function summarizeTransformOp(op) {
16960
+ if (op.op === "filter") {
16961
+ return `filter_${op.operator}_${JSON.stringify(op.value)}`;
16962
+ }
16963
+ if (op.op === "sortBy") {
16964
+ return `sortBy_${op.direction}`;
16965
+ }
16966
+ return "unique";
16967
+ }
16968
+ function deriveStepSignalsListKey(ops, reducer) {
16969
+ const pluck = ops.find((op) => op.op === "pluck");
16970
+ const base = `${reducer.op}_${pluck?.signalKey ?? "value"}`;
16971
+ const extras = ops.filter((op) => op.op !== "pluck").map(summarizeTransformOp);
16972
+ const reducerExtra = reducer.op === "join" ? `sep_${reducer.separator}` : null;
16973
+ const suffixParts = [...extras, ...reducerExtra ? [reducerExtra] : []];
16974
+ return suffixParts.length > 0 ? `${base}_${suffixParts.join("_")}` : base;
16975
+ }
16976
+ function createStepSignalsListBuilder(ops) {
16977
+ const withOp = (op) => createStepSignalsListBuilder([...ops, op]);
16978
+ const reduce = (reducer) => {
16979
+ const token = {
16980
+ _tag: "step_signals_list",
16981
+ key: deriveStepSignalsListKey(ops, reducer),
16982
+ ops: [...ops],
16983
+ reducer
16984
+ };
16985
+ return createCohortSignalRef(token);
16986
+ };
16987
+ return {
16988
+ filter: (operator, value) => withOp({ op: "filter", operator, value }),
16989
+ sortBy: (direction = "asc") => withOp({ op: "sortBy", direction }),
16990
+ unique: () => withOp({ op: "unique" }),
16991
+ count: () => reduce({ op: "count" }),
16992
+ sum: () => reduce({ op: "sum" }),
16993
+ avg: () => reduce({ op: "avg" }),
16994
+ min: () => reduce({ op: "min" }),
16995
+ max: () => reduce({ op: "max" }),
16996
+ booleanAll: () => reduce({ op: "booleanAll" }),
16997
+ booleanAny: () => reduce({ op: "booleanAny" }),
16998
+ join: (separator = ",") => reduce({ op: "join", separator }),
16999
+ first: () => reduce({ op: "first" }),
17000
+ last: () => reduce({ op: "last" })
17001
+ };
17002
+ }
17003
+ function makeAdvanceAllCtx() {
17004
+ return {
17005
+ branchOutcomes: {
17006
+ total: () => createCohortSignalRef("branchCount"),
17007
+ count: (outcome) => createCohortSignalRef(`${outcome}Count`),
17008
+ every: (outcome) => createCohortLeafFromCondition({
17009
+ _tag: "signal",
17010
+ signal: `${outcome}Count`,
17011
+ operator: "equal",
17012
+ value: { fact: "branchCount" }
17013
+ }),
17014
+ some: (outcome) => createCohortLeafFromCondition({
17015
+ _tag: "signal",
17016
+ signal: `${outcome}Count`,
17017
+ operator: "greaterThan",
17018
+ value: 0
17019
+ })
17020
+ },
17021
+ stepSignalsList: {
17022
+ pluck: (signalKey) => createStepSignalsListBuilder([{ op: "pluck", signalKey }])
17023
+ },
17024
+ all: (...refs) => createCohortGroup("all", refs),
17025
+ any: (...refs) => createCohortGroup("any", refs)
17026
+ };
17027
+ }
17028
+
17029
+ // src/definitions/pipelines/fan-out-builder.ts
17030
+ function beginFanOut(inputSchema, meta3, nodes, pipelineInputBindings, pipelineStepInputBindings, step, config2) {
17031
+ const baseCtx = makeStepInputCtx(inputSchema);
17032
+ const ctx = {
17033
+ ...baseCtx,
17034
+ item: { source: "fan_out_item" }
17035
+ };
17036
+ const rawInput = config2.input ? config2.input(ctx) : {};
17037
+ const input = mergeStepBindings(pipelineStepInputBindings, normalizeInputMapping(rawInput));
17038
+ const fanOutNodeConfig = {
17039
+ nodeType: "fanOut",
17040
+ fanOutStep: step,
17041
+ overSignalKey: config2.over,
17042
+ ...input ? { input } : {},
17043
+ ...config2.timeout !== undefined ? { timeout: config2.timeout } : {}
17044
+ };
17045
+ const advanceEachCtx = makeAdvanceEachCtx();
17046
+ const advanceEachResult = config2.advance(advanceEachCtx);
17047
+ const advanceEachPolicy = {
17048
+ default: advanceEachResult.default,
17049
+ ...advanceEachResult.rules !== undefined ? { rules: advanceEachResult.rules } : {}
17050
+ };
17051
+ fanOutNodeConfig.advanceEach = advanceEachPolicy;
17052
+ const cohortGateNodeConfig = {
17053
+ nodeType: "cohortGate",
17054
+ nodeKey: `${step.key}__cohortGate`
17055
+ };
17056
+ const advanceAllCtx = makeAdvanceAllCtx();
17057
+ const advanceAllResult = config2.advanceAll(advanceAllCtx);
17058
+ const advanceAllPolicy = {
17059
+ default: advanceAllResult.default,
17060
+ ...advanceAllResult.rules !== undefined ? { rules: advanceAllResult.rules } : {}
17061
+ };
17062
+ cohortGateNodeConfig.advanceAll = advanceAllPolicy;
17063
+ nodes.push(fanOutNodeConfig, cohortGateNodeConfig);
17064
+ return new PipelineStepBuilder(inputSchema, meta3, nodes, pipelineInputBindings, pipelineStepInputBindings);
17065
+ }
17066
+
17067
+ // src/definitions/pipelines/builder.ts
17068
+ function pushStep(inputSchema, meta3, nodes, pipelineInputBindings, pipelineStepInputBindings, step, rawOptions) {
17069
+ const options = rawOptions;
17070
+ const ctx = makeStepInputCtx(inputSchema);
17071
+ const rawInput = options.input ? options.input(ctx) : {};
17072
+ const input = mergeStepBindings(pipelineStepInputBindings, normalizeInputMapping(rawInput));
17073
+ const stepConfig = { step, input };
17074
+ if (options.timeout !== undefined)
17075
+ stepConfig.timeout = options.timeout;
17076
+ const advanceCtx = makeAdvanceCtx();
17077
+ const result = options.advance(advanceCtx);
17078
+ const policy = {
17079
+ defaultOutcome: result.default,
17080
+ ...result.rules !== undefined ? { rules: result.rules } : {}
17081
+ };
17082
+ stepConfig.advancement = policy;
17083
+ nodes.push(stepConfig);
17084
+ return new PipelineStepBuilder(inputSchema, meta3, nodes, pipelineInputBindings, pipelineStepInputBindings);
16641
17085
  }
16642
17086
 
16643
17087
  class PipelineStepBuilder {
16644
17088
  inputSchema;
16645
17089
  meta;
16646
- steps;
17090
+ nodes;
16647
17091
  pipelineInputBindings;
16648
17092
  pipelineStepInputBindings;
16649
- constructor(inputSchema, meta3, steps, pipelineInputBindings = {}, pipelineStepInputBindings = {}) {
17093
+ constructor(inputSchema, meta3, nodes, pipelineInputBindings = {}, pipelineStepInputBindings = {}) {
16650
17094
  this.inputSchema = inputSchema;
16651
17095
  this.meta = meta3;
16652
- this.steps = steps;
17096
+ this.nodes = nodes;
16653
17097
  this.pipelineInputBindings = pipelineInputBindings;
16654
17098
  this.pipelineStepInputBindings = pipelineStepInputBindings;
16655
17099
  }
16656
- step(step, mapper, configFn) {
16657
- const ctx = makeStepInputCtx(this.inputSchema);
16658
- const rawInput = mapper ? mapper(ctx) : {};
16659
- const input = mergeStepBindings(this.pipelineStepInputBindings, normalizeInputMapping(rawInput));
16660
- const stepConfig = { step, input };
16661
- if (configFn) {
16662
- const cfg = {};
16663
- configFn(cfg);
16664
- if (cfg.timeout !== undefined)
16665
- stepConfig.timeout = cfg.timeout;
16666
- }
16667
- this.steps.push(stepConfig);
16668
- return new PipelineStepAdvancementBuilder(this.inputSchema, this.meta, this.steps, this.pipelineInputBindings, this.pipelineStepInputBindings);
17100
+ step(step, options) {
17101
+ return pushStep(this.inputSchema, this.meta, this.nodes, this.pipelineInputBindings, this.pipelineStepInputBindings, step, options);
17102
+ }
17103
+ fanOutStep(step, config2) {
17104
+ return beginFanOut(this.inputSchema, this.meta, this.nodes, this.pipelineInputBindings, this.pipelineStepInputBindings, step, config2);
16669
17105
  }
16670
17106
  build() {
16671
17107
  const config2 = {
@@ -16675,7 +17111,7 @@ class PipelineStepBuilder {
16675
17111
  version: this.meta.version,
16676
17112
  status: this.meta.status,
16677
17113
  input: this.inputSchema,
16678
- steps: this.steps,
17114
+ nodes: this.nodes,
16679
17115
  pipelineInputBindings: this.pipelineInputBindings
16680
17116
  };
16681
17117
  return buildPipelineSpec(config2);
@@ -16685,7 +17121,7 @@ class PipelineStepBuilder {
16685
17121
  class PipelineBuilder {
16686
17122
  inputSchema;
16687
17123
  meta;
16688
- steps = [];
17124
+ nodes = [];
16689
17125
  pipelineInputBindings;
16690
17126
  pipelineStepInputBindings;
16691
17127
  constructor(meta3) {
@@ -16710,19 +17146,8 @@ class PipelineBuilder {
16710
17146
  }
16711
17147
  this.pipelineStepInputBindings = resolveAdditionalStepInputBindings("additionalStepInput", additionalStepInput);
16712
17148
  }
16713
- step(step, mapper, configFn) {
16714
- const ctx = makeStepInputCtx(this.inputSchema);
16715
- const rawInput = mapper ? mapper(ctx) : {};
16716
- const input = mergeStepBindings(this.pipelineStepInputBindings, normalizeInputMapping(rawInput));
16717
- const stepConfig = { step, input };
16718
- if (configFn) {
16719
- const cfg = {};
16720
- configFn(cfg);
16721
- if (cfg.timeout !== undefined)
16722
- stepConfig.timeout = cfg.timeout;
16723
- }
16724
- this.steps.push(stepConfig);
16725
- return new PipelineStepAdvancementBuilder(this.inputSchema, this.meta, this.steps, this.pipelineInputBindings, this.pipelineStepInputBindings);
17149
+ step(step, options) {
17150
+ return pushStep(this.inputSchema, this.meta, this.nodes, this.pipelineInputBindings, this.pipelineStepInputBindings, step, options);
16726
17151
  }
16727
17152
  }
16728
17153
  function pipeline(meta3) {
@@ -16752,23 +17177,35 @@ var buildPipelineDefinitionsClient = (pipelineDefinitions) => {
16752
17177
  stepDefMap.set(s.key, s);
16753
17178
  }
16754
17179
  }
16755
- const stepDefinitions = spec.steps.map((step) => {
16756
- const stepDef = stepDefMap.get(step.stepKey);
17180
+ const nonStepNode = spec.nodeDefinitions.find((node) => node.kind !== "step");
17181
+ if (nonStepNode) {
17182
+ 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.`);
17183
+ }
17184
+ const ordered = tryOrderChainNodeDefinitions(spec.nodeDefinitions, spec.dependencyEdges);
17185
+ if (ordered === null) {
17186
+ 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.`);
17187
+ }
17188
+ const stepDefinitions = ordered.map((node, index) => {
17189
+ const stepKey = node.stepKey;
17190
+ if (!stepKey) {
17191
+ throw new Error(`Node "${node.nodeKey}" in pipeline "${spec.key}" has no stepKey.`);
17192
+ }
17193
+ const stepDef = stepDefMap.get(stepKey);
16757
17194
  if (!stepDef) {
16758
- 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.`);
17195
+ 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.`);
16759
17196
  }
16760
17197
  return {
16761
17198
  stepDefinitionId: stepDef.id,
16762
17199
  stepDefinitionVersion: stepDef.version,
16763
- key: step.stepKey,
16764
- name: step.stepName,
16765
- description: step.stepDescription,
16766
- position: step.position,
16767
- inputBindingsJson: step.inputBindingsJson,
16768
- timeoutSeconds: step.timeoutSeconds,
17200
+ key: node.nodeKey,
17201
+ name: node.stepName ?? "",
17202
+ description: node.stepDescription ?? null,
17203
+ position: index + 1,
17204
+ inputBindingsJson: node.inputBindingsJson ?? {},
17205
+ timeoutSeconds: node.timeoutSeconds ?? null,
16769
17206
  retryPolicyJson: null,
16770
- advancementPolicyDefinition: step.advancementPolicyDefinition,
16771
- computedSignalDefinitions: step.computedSignalDefinitions
17207
+ advancementPolicyDefinition: node.advancementPolicyDefinition,
17208
+ computedSignalDefinitions: node.computedSignalDefinitions ?? []
16772
17209
  };
16773
17210
  });
16774
17211
  const body = {
@@ -16803,7 +17240,12 @@ function makeLeaf(fact, path, operator, value) {
16803
17240
  return {
16804
17241
  _condition: condition,
16805
17242
  then(outcome) {
16806
- return { _tag: "assignment_rule", conditions: [condition], mode: "all", outcome };
17243
+ return {
17244
+ _tag: "assignment_rule",
17245
+ conditions: [condition],
17246
+ mode: "all",
17247
+ outcome
17248
+ };
16807
17249
  }
16808
17250
  };
16809
17251
  }
@@ -16822,7 +17264,7 @@ function makeFieldRef(fact, path) {
16822
17264
  };
16823
17265
  }
16824
17266
  function makeAssign(pipeline2) {
16825
- if (typeof pipeline2 !== "object" || typeof pipeline2["key"] !== "string" || !Array.isArray(pipeline2["steps"])) {
17267
+ if (typeof pipeline2 !== "object" || typeof pipeline2["key"] !== "string" || !Array.isArray(pipeline2["nodeDefinitions"])) {
16826
17268
  throw new Error("assign() requires a pipeline spec produced by pipeline().build(). " + "Pass the default-exported value from a pipeline definition file.");
16827
17269
  }
16828
17270
  return { _tag: "assign", pipeline: pipeline2 };
@@ -16910,7 +17352,7 @@ function serializeDefaultPipelineAssignment(spec) {
16910
17352
  return serializeAssignmentRule(rule);
16911
17353
  });
16912
17354
  return {
16913
- linearPipelineDefinitionKey: primaryKey,
17355
+ pipelineDefinitionKey: primaryKey,
16914
17356
  rulesJson: { rules: serializedRules },
16915
17357
  defaultEventType: defaultType,
16916
17358
  defaultEventParamsJson: defaultParams,
@@ -17264,6 +17706,7 @@ export {
17264
17706
  artifactKindSchema,
17265
17707
  WorkItems,
17266
17708
  WorkItemComments,
17709
+ WorkItemBlocks,
17267
17710
  Username,
17268
17711
  UserNotifications,
17269
17712
  StepExecutions,
@@ -17275,7 +17718,6 @@ export {
17275
17718
  ProjectIntegrations,
17276
17719
  ProjectContext,
17277
17720
  PipelineStepBuilder,
17278
- PipelineStepAdvancementBuilder,
17279
17721
  PipelineExecutions,
17280
17722
  PipelineDefinitions,
17281
17723
  PipelineBuilder,