@bpmnkit/core 0.1.0 → 0.1.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.
Files changed (63) hide show
  1. package/README.md +2 -0
  2. package/dist/bpmn/agentic.d.ts +121 -0
  3. package/dist/bpmn/agentic.js +97 -0
  4. package/dist/bpmn/auto-layout.d.ts +5 -5
  5. package/dist/bpmn/auto-layout.js +592 -36
  6. package/dist/bpmn/bpmn-builder.d.ts +56 -0
  7. package/dist/bpmn/bpmn-builder.js +155 -182
  8. package/dist/bpmn/bpmn-model.d.ts +39 -2
  9. package/dist/bpmn/bpmn-parser.js +48 -2
  10. package/dist/bpmn/bpmn-serializer.js +33 -0
  11. package/dist/bpmn/compact.js +11 -1
  12. package/dist/bpmn/di-planes.d.ts +13 -0
  13. package/dist/bpmn/di-planes.js +20 -0
  14. package/dist/bpmn/optimize/agentic.d.ts +10 -0
  15. package/dist/bpmn/optimize/agentic.js +88 -0
  16. package/dist/bpmn/optimize/deploy.d.ts +16 -0
  17. package/dist/bpmn/optimize/deploy.js +143 -0
  18. package/dist/bpmn/optimize/feel-syntax.d.ts +12 -0
  19. package/dist/bpmn/optimize/feel-syntax.js +87 -0
  20. package/dist/bpmn/optimize/feel.js +5 -2
  21. package/dist/bpmn/optimize/flow.js +22 -2
  22. package/dist/bpmn/optimize/index.js +20 -9
  23. package/dist/bpmn/optimize/tasks.js +1 -0
  24. package/dist/bpmn/optimize/types.d.ts +10 -1
  25. package/dist/bpmn/svg.js +22 -3
  26. package/dist/bpmn/type-guards.d.ts +7 -1
  27. package/dist/bpmn/type-guards.js +13 -0
  28. package/dist/bpmn/zeebe-extensions.d.ts +27 -0
  29. package/dist/bpmn/zeebe-extensions.js +38 -0
  30. package/dist/index.d.ts +9 -3
  31. package/dist/index.js +4 -1
  32. package/dist/layout/annotations.js +36 -1
  33. package/dist/layout/collaboration/alignment.d.ts +26 -0
  34. package/dist/layout/collaboration/alignment.js +66 -0
  35. package/dist/layout/collaboration/ordering.d.ts +21 -0
  36. package/dist/layout/collaboration/ordering.js +102 -0
  37. package/dist/layout/index.d.ts +1 -0
  38. package/dist/layout/layout-engine.d.ts +13 -3
  39. package/dist/layout/layout-engine.js +9 -4
  40. package/dist/layout/semantic/bands.d.ts +19 -0
  41. package/dist/layout/semantic/bands.js +324 -0
  42. package/dist/layout/semantic/graph.d.ts +29 -0
  43. package/dist/layout/semantic/graph.js +217 -0
  44. package/dist/layout/semantic/index.d.ts +13 -0
  45. package/dist/layout/semantic/index.js +181 -0
  46. package/dist/layout/semantic/place.d.ts +40 -0
  47. package/dist/layout/semantic/place.js +271 -0
  48. package/dist/layout/semantic/route.d.ts +14 -0
  49. package/dist/layout/semantic/route.js +454 -0
  50. package/dist/layout/types.d.ts +17 -0
  51. package/dist/plan/compile.d.ts +39 -0
  52. package/dist/plan/compile.js +380 -0
  53. package/dist/plan/extract.d.ts +31 -0
  54. package/dist/plan/extract.js +248 -0
  55. package/dist/plan/index.d.ts +6 -0
  56. package/dist/plan/index.js +5 -0
  57. package/dist/plan/merge.d.ts +13 -0
  58. package/dist/plan/merge.js +80 -0
  59. package/dist/plan/slug.d.ts +5 -0
  60. package/dist/plan/slug.js +22 -0
  61. package/dist/plan/types.d.ts +225 -0
  62. package/dist/plan/types.js +13 -0
  63. package/package.json +2 -2
@@ -4,11 +4,15 @@ import type { RestConnectorConfig } from "./rest-connector.js";
4
4
  export interface ElementOptions {
5
5
  name?: string;
6
6
  isForCompensation?: boolean;
7
+ /** Free-text documentation (`<bpmn:documentation>`). Used by the AI Agent connector as a tool description. */
8
+ documentation?: string;
7
9
  }
8
10
  /** Options for send/receive task elements. */
9
11
  export interface MessageTaskOptions extends ElementOptions {
10
12
  /** Message name — generates or reuses a root <bpmn:message> and sets messageRef. */
11
13
  messageName?: string;
14
+ /** FEEL expression correlating this message to a specific process instance (`zeebe:subscription`). */
15
+ correlationKey?: string;
12
16
  }
13
17
  /** Options for creating a start event. */
14
18
  export interface StartEventOptions extends ElementOptions {
@@ -58,6 +62,11 @@ export interface ServiceTaskOptions {
58
62
  };
59
63
  /** Task header key-value pairs. */
60
64
  taskHeaders?: Record<string, string>;
65
+ /** Zeebe property key-value pairs (`zeebe:properties`/`zeebe:property`). */
66
+ zeebeProperties?: Array<{
67
+ name: string;
68
+ value: string;
69
+ }>;
61
70
  /** Zeebe modeler template ID. */
62
71
  modelerTemplate?: string;
63
72
  /** Zeebe modeler template version. */
@@ -66,6 +75,8 @@ export interface ServiceTaskOptions {
66
75
  modelerTemplateIcon?: string;
67
76
  /** Mark this task as a compensation handler. */
68
77
  isForCompensation?: boolean;
78
+ /** Free-text documentation (`<bpmn:documentation>`). Used by the AI Agent connector as a tool description. */
79
+ documentation?: string;
69
80
  }
70
81
  /** Options for creating a script task. */
71
82
  export interface ScriptTaskOptions {
@@ -77,6 +88,8 @@ export interface ScriptTaskOptions {
77
88
  resultVariable: string;
78
89
  /** Mark this task as a compensation handler. */
79
90
  isForCompensation?: boolean;
91
+ /** Free-text documentation (`<bpmn:documentation>`). */
92
+ documentation?: string;
80
93
  }
81
94
  /** Options for creating a user task. */
82
95
  export interface UserTaskOptions {
@@ -88,6 +101,20 @@ export interface UserTaskOptions {
88
101
  zeebeUserTask?: boolean;
89
102
  /** Mark this task as a compensation handler. */
90
103
  isForCompensation?: boolean;
104
+ /** Free-text documentation (`<bpmn:documentation>`). */
105
+ documentation?: string;
106
+ /** Static assignee (`zeebe:assignmentDefinition assignee`). FEEL expressions must start with "=". */
107
+ assignee?: string;
108
+ /** Candidate groups, comma-separated or a FEEL expression (`zeebe:assignmentDefinition candidateGroups`). */
109
+ candidateGroups?: string;
110
+ /** Candidate users, comma-separated or a FEEL expression (`zeebe:assignmentDefinition candidateUsers`). */
111
+ candidateUsers?: string;
112
+ /** Due date — ISO 8601 or FEEL expression (`zeebe:taskSchedule dueDate`). */
113
+ dueDate?: string;
114
+ /** Follow-up date — ISO 8601 or FEEL expression (`zeebe:taskSchedule followUpDate`). */
115
+ followUpDate?: string;
116
+ /** Task priority 0-100, default 50 (`zeebe:priorityDefinition`). */
117
+ priority?: number;
91
118
  }
92
119
  /** Options for creating a call activity. */
93
120
  export interface CallActivityOptions {
@@ -99,6 +126,8 @@ export interface CallActivityOptions {
99
126
  propagateAllChildVariables?: boolean;
100
127
  /** Mark this activity as a compensation handler. */
101
128
  isForCompensation?: boolean;
129
+ /** Free-text documentation (`<bpmn:documentation>`). */
130
+ documentation?: string;
102
131
  }
103
132
  /** Options for creating a business rule task. */
104
133
  export interface BusinessRuleTaskOptions {
@@ -112,6 +141,8 @@ export interface BusinessRuleTaskOptions {
112
141
  resultVariable?: string;
113
142
  /** Mark this task as a compensation handler. */
114
143
  isForCompensation?: boolean;
144
+ /** Free-text documentation (`<bpmn:documentation>`). */
145
+ documentation?: string;
115
146
  }
116
147
  /** Options for gateway elements. */
117
148
  export interface GatewayOptions extends ElementOptions {
@@ -128,6 +159,8 @@ export interface IntermediateCatchEventOptions extends ElementOptions {
128
159
  timerCycle?: string;
129
160
  /** Message name — creates a message catch event (aspirational). */
130
161
  messageName?: string;
162
+ /** FEEL expression correlating this message to a specific process instance (`zeebe:subscription`). Required for a deployable message catch when `messageName` is set. */
163
+ correlationKey?: string;
131
164
  /** Signal name — creates a signal catch event (aspirational). */
132
165
  signalName?: string;
133
166
  }
@@ -175,6 +208,8 @@ export interface BoundaryEventOptions extends ElementOptions {
175
208
  timerCycle?: string;
176
209
  /** Message name — creates a message boundary event (aspirational). */
177
210
  messageName?: string;
211
+ /** FEEL expression correlating this message to a specific process instance (`zeebe:subscription`). Required for a deployable message boundary event when `messageName` is set. */
212
+ correlationKey?: string;
178
213
  /** Signal name — creates a signal boundary event (aspirational). */
179
214
  signalName?: string;
180
215
  /** Creates a compensation boundary event. */
@@ -217,6 +252,11 @@ export interface AdHocSubProcessOptions extends ElementOptions {
217
252
  };
218
253
  /** Task header key-value pairs. */
219
254
  taskHeaders?: Record<string, string>;
255
+ /** Zeebe property key-value pairs (`zeebe:properties`/`zeebe:property`). */
256
+ zeebeProperties?: Array<{
257
+ name: string;
258
+ value: string;
259
+ }>;
220
260
  /** Multi-instance loop configuration. */
221
261
  loopCharacteristics?: {
222
262
  inputCollection: string;
@@ -231,6 +271,13 @@ export interface AdHocSubProcessOptions extends ElementOptions {
231
271
  modelerTemplateVersion?: string;
232
272
  /** Zeebe modeler template icon (data URI). */
233
273
  modelerTemplateIcon?: string;
274
+ /**
275
+ * FEEL expression evaluated after each tool activity completes; ends the
276
+ * ad-hoc scope when true (`bpmn:completionCondition`).
277
+ */
278
+ completionCondition?: string;
279
+ /** Whether still-running inner activity instances are cancelled once the completion condition is met (default true). */
280
+ cancelRemainingInstances?: boolean;
234
281
  }
235
282
  /**
236
283
  * Builder for a single named branch path from a gateway.
@@ -354,6 +401,15 @@ export declare class SubProcessContentBuilder {
354
401
  /** @internal */
355
402
  constructor(rootMessages?: BpmnMessage[]);
356
403
  private addElement;
404
+ /**
405
+ * Add an element with no sequence-flow wiring and no cursor movement.
406
+ *
407
+ * Used for ad-hoc sub-process tool activities, which the AI Agent connector
408
+ * requires to be root nodes (no incoming sequence flow, not a boundary event).
409
+ * Unlike `serviceTask()`/`userTask()`/etc., this does not auto-connect from
410
+ * the current cursor and does not move it.
411
+ */
412
+ addDisconnected(element: BpmnFlowElement): this;
357
413
  startEvent(id?: string, options?: StartEventOptions): this;
358
414
  endEvent(id?: string, options?: EndEventOptions): this;
359
415
  intermediateThrowEvent(id?: string, options?: IntermediateThrowEventOptions): this;
@@ -15,6 +15,12 @@ function resolveMessage(messageName, rootMessages) {
15
15
  }
16
16
  return existing.id;
17
17
  }
18
+ /** Builds the `zeebe:subscription` extension element for a correlated message catch. */
19
+ function buildMessageSubscriptionExt(correlationKey) {
20
+ if (!correlationKey)
21
+ return [];
22
+ return zeebeExtensionsToXmlElements({ subscription: { correlationKey } });
23
+ }
18
24
  function buildEventDefinitions(opts, rootErrors, rootMessages, rootSignals, rootEscalations) {
19
25
  const defs = [];
20
26
  if (opts.timerDuration || opts.timerDate || opts.timerCycle) {
@@ -86,6 +92,7 @@ function makeFlowElement(id, type, options) {
86
92
  name: options?.name,
87
93
  incoming: [],
88
94
  outgoing: [],
95
+ documentation: options?.documentation,
89
96
  extensionElements: options?.extensionElements ?? [],
90
97
  unknownAttributes: {},
91
98
  };
@@ -127,6 +134,7 @@ function makeFlowElement(id, type, options) {
127
134
  sequenceFlows: [],
128
135
  textAnnotations: [],
129
136
  associations: [],
137
+ groups: [],
130
138
  };
131
139
  case "adHocSubProcess":
132
140
  return {
@@ -136,6 +144,7 @@ function makeFlowElement(id, type, options) {
136
144
  sequenceFlows: [],
137
145
  textAnnotations: [],
138
146
  associations: [],
147
+ groups: [],
139
148
  };
140
149
  case "eventSubProcess":
141
150
  return {
@@ -145,6 +154,7 @@ function makeFlowElement(id, type, options) {
145
154
  sequenceFlows: [],
146
155
  textAnnotations: [],
147
156
  associations: [],
157
+ groups: [],
148
158
  };
149
159
  case "transaction":
150
160
  return {
@@ -154,7 +164,10 @@ function makeFlowElement(id, type, options) {
154
164
  sequenceFlows: [],
155
165
  textAnnotations: [],
156
166
  associations: [],
167
+ groups: [],
157
168
  };
169
+ default:
170
+ return { ...base, type };
158
171
  }
159
172
  }
160
173
  function buildMultiInstance(options) {
@@ -226,6 +239,9 @@ function buildServiceTaskExtensions(options) {
226
239
  })),
227
240
  };
228
241
  }
242
+ if (options.zeebeProperties) {
243
+ extensions.properties = { properties: options.zeebeProperties };
244
+ }
229
245
  return zeebeExtensionsToXmlElements(extensions);
230
246
  }
231
247
  function makeConditionExpression(expression) {
@@ -234,6 +250,72 @@ function makeConditionExpression(expression) {
234
250
  attributes: { "xsi:type": "bpmn:tFormalExpression" },
235
251
  };
236
252
  }
253
+ /** Builds the Zeebe extension elements + completion condition shared by all `adHocSubProcess()` overloads. */
254
+ function buildAdHocSubProcessExtensions(options) {
255
+ const zeebeExt = {};
256
+ if (options?.taskDefinition) {
257
+ zeebeExt.taskDefinition = options.taskDefinition;
258
+ }
259
+ if (options?.ioMapping) {
260
+ zeebeExt.ioMapping = {
261
+ inputs: options.ioMapping.inputs ?? [],
262
+ outputs: options.ioMapping.outputs ?? [],
263
+ };
264
+ }
265
+ if (options?.taskHeaders) {
266
+ zeebeExt.taskHeaders = {
267
+ headers: Object.entries(options.taskHeaders).map(([key, value]) => ({ key, value })),
268
+ };
269
+ }
270
+ if (options?.zeebeProperties) {
271
+ zeebeExt.properties = { properties: options.zeebeProperties };
272
+ }
273
+ const extensionElements = zeebeExtensionsToXmlElements(zeebeExt);
274
+ const adHocAttrs = {};
275
+ if (options?.activeElementsCollection) {
276
+ adHocAttrs.activeElementsCollection = options.activeElementsCollection;
277
+ }
278
+ if (options?.outputCollection)
279
+ adHocAttrs.outputCollection = options.outputCollection;
280
+ if (options?.outputElement)
281
+ adHocAttrs.outputElement = options.outputElement;
282
+ if (Object.keys(adHocAttrs).length > 0) {
283
+ extensionElements.push({ name: "zeebe:adHoc", attributes: adHocAttrs, children: [] });
284
+ }
285
+ return {
286
+ extensionElements,
287
+ completionCondition: options?.completionCondition
288
+ ? makeConditionExpression(options.completionCondition)
289
+ : undefined,
290
+ };
291
+ }
292
+ /** Applies modeler-template attrs, sub-process contents, loop characteristics, and completion condition. */
293
+ function finalizeAdHocSubProcessEl(element, options, sub, completionCondition) {
294
+ if (options?.modelerTemplate)
295
+ element.unknownAttributes["zeebe:modelerTemplate"] = options.modelerTemplate;
296
+ if (options?.modelerTemplateVersion) {
297
+ element.unknownAttributes["zeebe:modelerTemplateVersion"] = options.modelerTemplateVersion;
298
+ }
299
+ if (options?.modelerTemplateIcon) {
300
+ element.unknownAttributes["zeebe:modelerTemplateIcon"] = options.modelerTemplateIcon;
301
+ }
302
+ if (element.type !== "adHocSubProcess")
303
+ return;
304
+ element.flowElements = sub._elements;
305
+ element.sequenceFlows = sub._flows;
306
+ element.textAnnotations = sub._textAnnotations;
307
+ element.associations = sub._associations;
308
+ if (options?.loopCharacteristics) {
309
+ element.loopCharacteristics = buildAdHocLoopCharacteristics(options.loopCharacteristics);
310
+ }
311
+ else if (options?.multiInstance) {
312
+ element.loopCharacteristics = buildMultiInstance(options.multiInstance);
313
+ }
314
+ element.completionCondition = completionCondition;
315
+ if (options?.cancelRemainingInstances !== undefined) {
316
+ element.cancelRemainingInstances = options.cancelRemainingInstances;
317
+ }
318
+ }
237
319
  // ---------------------------------------------------------------------------
238
320
  // Element factory functions — shared by all three builder classes
239
321
  // ---------------------------------------------------------------------------
@@ -247,6 +329,7 @@ function makeServiceTaskEl(id, options) {
247
329
  unknownAttributes["zeebe:modelerTemplateIcon"] = options.modelerTemplateIcon;
248
330
  const el = makeFlowElement(id, "serviceTask", {
249
331
  name: options.name,
332
+ documentation: options.documentation,
250
333
  extensionElements: buildServiceTaskExtensions(options),
251
334
  });
252
335
  el.unknownAttributes = unknownAttributes;
@@ -257,6 +340,7 @@ function makeServiceTaskEl(id, options) {
257
340
  function makeScriptTaskEl(id, options) {
258
341
  const el = makeFlowElement(id, "scriptTask", {
259
342
  name: options.name,
343
+ documentation: options.documentation,
260
344
  extensionElements: zeebeExtensionsToXmlElements({
261
345
  unknownElements: [
262
346
  {
@@ -275,8 +359,27 @@ function makeUserTaskEl(id, options) {
275
359
  const ext = zeebeExtensionsToXmlElements({
276
360
  ...(options?.zeebeUserTask ? { userTask: true } : {}),
277
361
  ...(options?.formId ? { formDefinition: { formId: options.formId } } : {}),
362
+ ...(options?.assignee || options?.candidateGroups || options?.candidateUsers
363
+ ? {
364
+ assignmentDefinition: {
365
+ assignee: options?.assignee,
366
+ candidateGroups: options?.candidateGroups,
367
+ candidateUsers: options?.candidateUsers,
368
+ },
369
+ }
370
+ : {}),
371
+ ...(options?.dueDate || options?.followUpDate
372
+ ? { taskSchedule: { dueDate: options?.dueDate, followUpDate: options?.followUpDate } }
373
+ : {}),
374
+ ...(options?.priority !== undefined
375
+ ? { priorityDefinition: { priority: String(options.priority) } }
376
+ : {}),
377
+ });
378
+ const el = makeFlowElement(id, "userTask", {
379
+ name: options?.name,
380
+ documentation: options?.documentation,
381
+ extensionElements: ext,
278
382
  });
279
- const el = makeFlowElement(id, "userTask", { name: options?.name, extensionElements: ext });
280
383
  if (options?.isForCompensation)
281
384
  el.isForCompensation = true;
282
385
  return el;
@@ -296,6 +399,7 @@ function makeBusinessRuleTaskEl(id, options) {
296
399
  }
297
400
  const el = makeFlowElement(id, "businessRuleTask", {
298
401
  name: options?.name,
402
+ documentation: options?.documentation,
299
403
  extensionElements: ext,
300
404
  });
301
405
  if (options?.isForCompensation)
@@ -309,6 +413,7 @@ function makeCallActivityEl(id, options) {
309
413
  }
310
414
  const el = makeFlowElement(id, "callActivity", {
311
415
  name: options.name,
416
+ documentation: options.documentation,
312
417
  extensionElements: zeebeExtensionsToXmlElements({
313
418
  unknownElements: [{ name: "zeebe:calledElement", attributes: attrs, children: [] }],
314
419
  }),
@@ -661,7 +766,10 @@ export class BranchBuilder {
661
766
  return this.addElement(el);
662
767
  }
663
768
  intermediateCatchEvent(id, options) {
664
- const el = makeFlowElement(id ?? generateId("IntermediateCatchEvent"), "intermediateCatchEvent", options);
769
+ const el = makeFlowElement(id ?? generateId("IntermediateCatchEvent"), "intermediateCatchEvent", {
770
+ ...options,
771
+ extensionElements: buildMessageSubscriptionExt(options?.correlationKey),
772
+ });
665
773
  if (el.type === "intermediateCatchEvent" && options) {
666
774
  el.eventDefinitions = buildEventDefinitions(options, this.rootErrors, this.rootMessages, this.rootSignals, this.rootEscalations);
667
775
  }
@@ -692,7 +800,10 @@ export class BranchBuilder {
692
800
  * cursor to return to the task afterward.
693
801
  */
694
802
  boundaryEvent(id, options) {
695
- const element = makeFlowElement(id, "boundaryEvent", options);
803
+ const element = makeFlowElement(id, "boundaryEvent", {
804
+ ...options,
805
+ extensionElements: buildMessageSubscriptionExt(options.correlationKey),
806
+ });
696
807
  if (element.type === "boundaryEvent") {
697
808
  element.attachedToRef = options.attachedTo;
698
809
  element.cancelActivity = options.cancelActivity;
@@ -764,68 +875,13 @@ export class BranchBuilder {
764
875
  resolved.content(sub);
765
876
  insertJoinGateways(sub._elements, sub._flows);
766
877
  recomputeIncomingOutgoing(sub._elements, sub._flows);
767
- const zeebeExt = {};
768
- if (resolved.options?.taskDefinition) {
769
- zeebeExt.taskDefinition = resolved.options.taskDefinition;
770
- }
771
- if (resolved.options?.ioMapping) {
772
- zeebeExt.ioMapping = {
773
- inputs: resolved.options.ioMapping.inputs ?? [],
774
- outputs: resolved.options.ioMapping.outputs ?? [],
775
- };
776
- }
777
- if (resolved.options?.taskHeaders) {
778
- zeebeExt.taskHeaders = {
779
- headers: Object.entries(resolved.options.taskHeaders).map(([key, value]) => ({
780
- key,
781
- value,
782
- })),
783
- };
784
- }
785
- const extensionElements = zeebeExtensionsToXmlElements(zeebeExt);
786
- const adHocAttrs = {};
787
- if (resolved.options?.activeElementsCollection) {
788
- adHocAttrs.activeElementsCollection = resolved.options.activeElementsCollection;
789
- }
790
- if (resolved.options?.outputCollection) {
791
- adHocAttrs.outputCollection = resolved.options.outputCollection;
792
- }
793
- if (resolved.options?.outputElement) {
794
- adHocAttrs.outputElement = resolved.options.outputElement;
795
- }
796
- if (Object.keys(adHocAttrs).length > 0) {
797
- extensionElements.push({
798
- name: "zeebe:adHoc",
799
- attributes: adHocAttrs,
800
- children: [],
801
- });
802
- }
878
+ const { extensionElements, completionCondition } = buildAdHocSubProcessExtensions(resolved.options);
803
879
  const element = makeFlowElement(id, "adHocSubProcess", {
804
880
  name: resolved.options?.name,
881
+ documentation: resolved.options?.documentation,
805
882
  extensionElements,
806
883
  });
807
- if (resolved.options?.modelerTemplate) {
808
- element.unknownAttributes["zeebe:modelerTemplate"] = resolved.options.modelerTemplate;
809
- }
810
- if (resolved.options?.modelerTemplateVersion) {
811
- element.unknownAttributes["zeebe:modelerTemplateVersion"] =
812
- resolved.options.modelerTemplateVersion;
813
- }
814
- if (resolved.options?.modelerTemplateIcon) {
815
- element.unknownAttributes["zeebe:modelerTemplateIcon"] = resolved.options.modelerTemplateIcon;
816
- }
817
- if (element.type === "adHocSubProcess") {
818
- element.flowElements = sub._elements;
819
- element.sequenceFlows = sub._flows;
820
- element.textAnnotations = sub._textAnnotations;
821
- element.associations = sub._associations;
822
- if (resolved.options?.loopCharacteristics) {
823
- element.loopCharacteristics = buildAdHocLoopCharacteristics(resolved.options.loopCharacteristics);
824
- }
825
- else if (resolved.options?.multiInstance) {
826
- element.loopCharacteristics = buildMultiInstance(resolved.options.multiInstance);
827
- }
828
- }
884
+ finalizeAdHocSubProcessEl(element, resolved.options, sub, completionCondition);
829
885
  return this.addElement(element);
830
886
  }
831
887
  /** Add an event sub-process. Triggered by its start event — no incoming or outgoing sequence flows. */
@@ -947,6 +1003,21 @@ export class SubProcessContentBuilder {
947
1003
  this.lastNodeId = element.id;
948
1004
  return this;
949
1005
  }
1006
+ /**
1007
+ * Add an element with no sequence-flow wiring and no cursor movement.
1008
+ *
1009
+ * Used for ad-hoc sub-process tool activities, which the AI Agent connector
1010
+ * requires to be root nodes (no incoming sequence flow, not a boundary event).
1011
+ * Unlike `serviceTask()`/`userTask()`/etc., this does not auto-connect from
1012
+ * the current cursor and does not move it.
1013
+ */
1014
+ addDisconnected(element) {
1015
+ if (this._elements.some((n) => n.id === element.id)) {
1016
+ throw new Error(`Duplicate element ID "${element.id}" in sub-process`);
1017
+ }
1018
+ this._elements.push(element);
1019
+ return this;
1020
+ }
950
1021
  // ---- Events ----
951
1022
  startEvent(id, options) {
952
1023
  const el = makeFlowElement(id ?? generateId("StartEvent"), "startEvent", options);
@@ -970,7 +1041,10 @@ export class SubProcessContentBuilder {
970
1041
  return this.addElement(el);
971
1042
  }
972
1043
  intermediateCatchEvent(id, options) {
973
- const el = makeFlowElement(id ?? generateId("IntermediateCatchEvent"), "intermediateCatchEvent", options);
1044
+ const el = makeFlowElement(id ?? generateId("IntermediateCatchEvent"), "intermediateCatchEvent", {
1045
+ ...options,
1046
+ extensionElements: buildMessageSubscriptionExt(options?.correlationKey),
1047
+ });
974
1048
  if (el.type === "intermediateCatchEvent" && options)
975
1049
  el.eventDefinitions = buildEventDefinitions(options);
976
1050
  return this.addElement(el);
@@ -1125,7 +1199,10 @@ export class SubProcessContentBuilder {
1125
1199
  * cursor to return to the task afterward.
1126
1200
  */
1127
1201
  boundaryEvent(id, options) {
1128
- const element = makeFlowElement(id, "boundaryEvent", options);
1202
+ const element = makeFlowElement(id, "boundaryEvent", {
1203
+ ...options,
1204
+ extensionElements: buildMessageSubscriptionExt(options.correlationKey),
1205
+ });
1129
1206
  if (element.type === "boundaryEvent") {
1130
1207
  element.attachedToRef = options.attachedTo;
1131
1208
  element.cancelActivity = options.cancelActivity;
@@ -1194,68 +1271,13 @@ export class SubProcessContentBuilder {
1194
1271
  resolved.content(sub);
1195
1272
  insertJoinGateways(sub._elements, sub._flows);
1196
1273
  recomputeIncomingOutgoing(sub._elements, sub._flows);
1197
- const zeebeExt = {};
1198
- if (resolved.options?.taskDefinition) {
1199
- zeebeExt.taskDefinition = resolved.options.taskDefinition;
1200
- }
1201
- if (resolved.options?.ioMapping) {
1202
- zeebeExt.ioMapping = {
1203
- inputs: resolved.options.ioMapping.inputs ?? [],
1204
- outputs: resolved.options.ioMapping.outputs ?? [],
1205
- };
1206
- }
1207
- if (resolved.options?.taskHeaders) {
1208
- zeebeExt.taskHeaders = {
1209
- headers: Object.entries(resolved.options.taskHeaders).map(([key, value]) => ({
1210
- key,
1211
- value,
1212
- })),
1213
- };
1214
- }
1215
- const extensionElements = zeebeExtensionsToXmlElements(zeebeExt);
1216
- const adHocAttrs = {};
1217
- if (resolved.options?.activeElementsCollection) {
1218
- adHocAttrs.activeElementsCollection = resolved.options.activeElementsCollection;
1219
- }
1220
- if (resolved.options?.outputCollection) {
1221
- adHocAttrs.outputCollection = resolved.options.outputCollection;
1222
- }
1223
- if (resolved.options?.outputElement) {
1224
- adHocAttrs.outputElement = resolved.options.outputElement;
1225
- }
1226
- if (Object.keys(adHocAttrs).length > 0) {
1227
- extensionElements.push({
1228
- name: "zeebe:adHoc",
1229
- attributes: adHocAttrs,
1230
- children: [],
1231
- });
1232
- }
1274
+ const { extensionElements, completionCondition } = buildAdHocSubProcessExtensions(resolved.options);
1233
1275
  const element = makeFlowElement(id, "adHocSubProcess", {
1234
1276
  name: resolved.options?.name,
1277
+ documentation: resolved.options?.documentation,
1235
1278
  extensionElements,
1236
1279
  });
1237
- if (resolved.options?.modelerTemplate) {
1238
- element.unknownAttributes["zeebe:modelerTemplate"] = resolved.options.modelerTemplate;
1239
- }
1240
- if (resolved.options?.modelerTemplateVersion) {
1241
- element.unknownAttributes["zeebe:modelerTemplateVersion"] =
1242
- resolved.options.modelerTemplateVersion;
1243
- }
1244
- if (resolved.options?.modelerTemplateIcon) {
1245
- element.unknownAttributes["zeebe:modelerTemplateIcon"] = resolved.options.modelerTemplateIcon;
1246
- }
1247
- if (element.type === "adHocSubProcess") {
1248
- element.flowElements = sub._elements;
1249
- element.sequenceFlows = sub._flows;
1250
- element.textAnnotations = sub._textAnnotations;
1251
- element.associations = sub._associations;
1252
- if (resolved.options?.loopCharacteristics) {
1253
- element.loopCharacteristics = buildAdHocLoopCharacteristics(resolved.options.loopCharacteristics);
1254
- }
1255
- else if (resolved.options?.multiInstance) {
1256
- element.loopCharacteristics = buildMultiInstance(resolved.options.multiInstance);
1257
- }
1258
- }
1280
+ finalizeAdHocSubProcessEl(element, resolved.options, sub, completionCondition);
1259
1281
  return this.addElement(element);
1260
1282
  }
1261
1283
  /** Add an event sub-process. Triggered by its start event — no incoming or outgoing sequence flows. */
@@ -1415,7 +1437,10 @@ export class ProcessBuilder {
1415
1437
  /** Add an intermediate catch event (timer, message, signal). */
1416
1438
  intermediateCatchEvent(id, options) {
1417
1439
  const nodeId = id ?? generateId("IntermediateCatchEvent");
1418
- const element = makeFlowElement(nodeId, "intermediateCatchEvent", options);
1440
+ const element = makeFlowElement(nodeId, "intermediateCatchEvent", {
1441
+ ...options,
1442
+ extensionElements: buildMessageSubscriptionExt(options?.correlationKey),
1443
+ });
1419
1444
  if (element.type === "intermediateCatchEvent" && options) {
1420
1445
  element.eventDefinitions = buildEventDefinitions(options, this.rootErrors, this.rootMessages, this.rootSignals, this.rootEscalations);
1421
1446
  }
@@ -1429,7 +1454,10 @@ export class ProcessBuilder {
1429
1454
  * They start a new outgoing chain from the boundary event itself.
1430
1455
  */
1431
1456
  boundaryEvent(id, options) {
1432
- const element = makeFlowElement(id, "boundaryEvent", options);
1457
+ const element = makeFlowElement(id, "boundaryEvent", {
1458
+ ...options,
1459
+ extensionElements: buildMessageSubscriptionExt(options.correlationKey),
1460
+ });
1433
1461
  if (element.type === "boundaryEvent") {
1434
1462
  element.attachedToRef = options.attachedTo;
1435
1463
  element.cancelActivity = options.cancelActivity;
@@ -1684,69 +1712,13 @@ export class ProcessBuilder {
1684
1712
  resolved.content(sub);
1685
1713
  insertJoinGateways(sub._elements, sub._flows);
1686
1714
  recomputeIncomingOutgoing(sub._elements, sub._flows);
1687
- const zeebeExt = {};
1688
- if (resolved.options?.taskDefinition) {
1689
- zeebeExt.taskDefinition = resolved.options.taskDefinition;
1690
- }
1691
- if (resolved.options?.ioMapping) {
1692
- zeebeExt.ioMapping = {
1693
- inputs: resolved.options.ioMapping.inputs ?? [],
1694
- outputs: resolved.options.ioMapping.outputs ?? [],
1695
- };
1696
- }
1697
- if (resolved.options?.taskHeaders) {
1698
- zeebeExt.taskHeaders = {
1699
- headers: Object.entries(resolved.options.taskHeaders).map(([key, value]) => ({
1700
- key,
1701
- value,
1702
- })),
1703
- };
1704
- }
1705
- const extensionElements = zeebeExtensionsToXmlElements(zeebeExt);
1706
- // zeebe:adHoc element
1707
- const adHocAttrs = {};
1708
- if (resolved.options?.activeElementsCollection) {
1709
- adHocAttrs.activeElementsCollection = resolved.options.activeElementsCollection;
1710
- }
1711
- if (resolved.options?.outputCollection) {
1712
- adHocAttrs.outputCollection = resolved.options.outputCollection;
1713
- }
1714
- if (resolved.options?.outputElement) {
1715
- adHocAttrs.outputElement = resolved.options.outputElement;
1716
- }
1717
- if (Object.keys(adHocAttrs).length > 0) {
1718
- extensionElements.push({
1719
- name: "zeebe:adHoc",
1720
- attributes: adHocAttrs,
1721
- children: [],
1722
- });
1723
- }
1715
+ const { extensionElements, completionCondition } = buildAdHocSubProcessExtensions(resolved.options);
1724
1716
  const element = makeFlowElement(id, "adHocSubProcess", {
1725
1717
  name: resolved.options?.name,
1718
+ documentation: resolved.options?.documentation,
1726
1719
  extensionElements,
1727
1720
  });
1728
- if (resolved.options?.modelerTemplate) {
1729
- element.unknownAttributes["zeebe:modelerTemplate"] = resolved.options.modelerTemplate;
1730
- }
1731
- if (resolved.options?.modelerTemplateVersion) {
1732
- element.unknownAttributes["zeebe:modelerTemplateVersion"] =
1733
- resolved.options.modelerTemplateVersion;
1734
- }
1735
- if (resolved.options?.modelerTemplateIcon) {
1736
- element.unknownAttributes["zeebe:modelerTemplateIcon"] = resolved.options.modelerTemplateIcon;
1737
- }
1738
- if (element.type === "adHocSubProcess") {
1739
- element.flowElements = sub._elements;
1740
- element.sequenceFlows = sub._flows;
1741
- element.textAnnotations = sub._textAnnotations;
1742
- element.associations = sub._associations;
1743
- if (resolved.options?.loopCharacteristics) {
1744
- element.loopCharacteristics = buildAdHocLoopCharacteristics(resolved.options.loopCharacteristics);
1745
- }
1746
- else if (resolved.options?.multiInstance) {
1747
- element.loopCharacteristics = buildMultiInstance(resolved.options.multiInstance);
1748
- }
1749
- }
1721
+ finalizeAdHocSubProcessEl(element, resolved.options, sub, completionCondition);
1750
1722
  this.addFlowElement(element);
1751
1723
  return this;
1752
1724
  }
@@ -1855,6 +1827,7 @@ export class ProcessBuilder {
1855
1827
  sequenceFlows: this.sequenceFlows,
1856
1828
  textAnnotations: this._textAnnotations,
1857
1829
  associations: this._associations,
1830
+ groups: [],
1858
1831
  unknownAttributes: {},
1859
1832
  };
1860
1833
  const defs = {