@oomol-lab/open-flow 0.1.0-beta.65 → 0.1.0-beta.66

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 (49) hide show
  1. package/dist/browser/{createResourceDialog-BAJXbzNH.js → createResourceDialog-C-Si_cYs.js} +2 -2
  2. package/dist/browser/flow-authoring-node.d.ts +12 -3
  3. package/dist/browser/flow-authoring.js +114 -19
  4. package/dist/browser/flow-change-schema.d.ts +3 -1
  5. package/dist/browser/flow-change.d.ts +15 -3
  6. package/dist/browser/flow-change.js +111 -16
  7. package/dist/browser/{flowChanges-DkvG5uDq.js → flowChanges-T4_R5p1f.js} +2654 -1858
  8. package/dist/browser/{flowRunInputEditorStore-B2Rw4VsT.js → flowRunInputEditorStore-DJqmR6Qh.js} +3 -2
  9. package/dist/browser/{flowWorkspace-BEp-lxqF.js → flowWorkspace-C0J5C0oM.js} +700 -224
  10. package/dist/browser/{icons-Db2Jb2iX.js → icons-BD3m0RQq.js} +4484 -4370
  11. package/dist/browser/preview.css +152 -64
  12. package/dist/browser/preview.js +4460 -3412
  13. package/dist/browser/ui.css +85 -3
  14. package/dist/browser/ui.js +8 -5
  15. package/dist/browser/workbench.css +152 -64
  16. package/dist/browser/workbench.js +146 -57
  17. package/dist/browser/{workbenchSelect-C-jf6NIM.js → workbenchSelect-B-PFpF_Q.js} +1 -1
  18. package/dist/command/index.js +49 -49
  19. package/dist/common/authoring.d.ts +7 -5
  20. package/dist/common/authoringExamples.d.ts +3 -3
  21. package/dist/common/authoringFields.d.ts +20 -0
  22. package/dist/common/authoringSchema.d.ts +404 -15
  23. package/dist/common/control-api-conformance.js +384 -137
  24. package/dist/common/control-api.d.ts +63 -7
  25. package/dist/common/control-api.js +3562 -3428
  26. package/dist/common/control-requests.d.ts +10 -3
  27. package/dist/common/control-requests.js +418 -43
  28. package/dist/common/decision.js +28 -3
  29. package/dist/common/flow-encoding.d.ts +4 -2
  30. package/dist/common/flow-encoding.js +144 -10
  31. package/dist/common/flow-graph.d.ts +1 -1
  32. package/dist/common/flow-semantics.d.ts +12 -2
  33. package/dist/common/flow-semantics.js +146 -33
  34. package/dist/common/integration-trigger.js +28 -3
  35. package/dist/common/liveDetails.d.ts +26 -11
  36. package/dist/common/mcp.d.ts +6 -3
  37. package/dist/common/mcp.js +203 -84
  38. package/dist/common/openapi.js +28 -3
  39. package/dist/common/poll-trigger.js +28 -3
  40. package/dist/common/run-events.d.ts +2 -0
  41. package/dist/common/run-events.js +9 -3
  42. package/dist/common/scheduler.d.ts +10 -1
  43. package/dist/common/scheduler.js +167 -45
  44. package/dist/common/trigger-contract.d.ts +2 -0
  45. package/dist/common/webhook-trigger.js +28 -3
  46. package/dist/common/workflow.d.ts +93 -0
  47. package/dist/common/workflow.js +10491 -0
  48. package/package.json +5 -1
  49. package/skills/open-flow/references/flow-authoring.md +26 -16
@@ -6619,6 +6619,7 @@ var port = object$1({
6619
6619
  nullable: boolean(),
6620
6620
  handle: text
6621
6621
  });
6622
+ var workflowInputDefs = array(port.strict());
6622
6623
  var input = port.extend({ value: json.optional() });
6623
6624
  var group = object$1({
6624
6625
  collapsed: boolean().optional(),
@@ -6776,6 +6777,11 @@ var managedFields = object$1({
6776
6777
  messageHandle: text,
6777
6778
  inputs: record$1(text, agentValue)
6778
6779
  }).optional()
6780
+ }),
6781
+ strictObject({
6782
+ kind: literal("workflow"),
6783
+ flowId: text,
6784
+ revisionId: text
6779
6785
  })
6780
6786
  ])
6781
6787
  });
@@ -6884,6 +6890,12 @@ var base = {
6884
6890
  timeoutMs: number().optional()
6885
6891
  };
6886
6892
  var node = union([
6893
+ strictObject({
6894
+ ...base,
6895
+ kind: literal("outputs"),
6896
+ outputDefs: array(port.strict()),
6897
+ outputMappings: inputs
6898
+ }).omit({ inputs: true }),
6887
6899
  object$1({
6888
6900
  ...base,
6889
6901
  inputs: record$1(text, never()),
@@ -6916,6 +6928,11 @@ var node = union([
6916
6928
  ...trigger,
6917
6929
  kind: literal("manual")
6918
6930
  }),
6931
+ strictObject({
6932
+ ...trigger,
6933
+ kind: literal("start"),
6934
+ inputDefs: workflowInputDefs
6935
+ }),
6919
6936
  strictObject({
6920
6937
  ...trigger,
6921
6938
  kind: literal("error"),
@@ -6980,7 +6997,7 @@ var module = object$1({
6980
6997
  imports: strings,
6981
6998
  source: text
6982
6999
  });
6983
- var document = preprocess(rejectRetiredDefinitions, object$1({
7000
+ var document = preprocess(normalizeDocument, object$1({
6984
7001
  bindings: record$1(text, binding),
6985
7002
  graph
6986
7003
  }));
@@ -6989,7 +7006,9 @@ object$1({
6989
7006
  literal(2),
6990
7007
  literal(4),
6991
7008
  literal(5),
6992
- literal(6)
7009
+ literal(6),
7010
+ literal(7),
7011
+ literal(8)
6993
7012
  ]),
6994
7013
  document,
6995
7014
  modules: record$1(text, module)
@@ -6997,13 +7016,19 @@ object$1({
6997
7016
  kind: literal("open-flow-flow-revision"),
6998
7017
  version: literal(1)
6999
7018
  });
7000
- function rejectRetiredDefinitions(value) {
7019
+ function normalizeDocument(value) {
7001
7020
  const candidate = record(value);
7002
7021
  if (candidate.tasks !== void 0 && (candidate.tasks === null || typeof candidate.tasks !== "object" || Array.isArray(candidate.tasks) || Object.keys(candidate.tasks).length > 0)) throw new TypeError("Independent Task definitions are no longer supported.");
7003
7022
  if (Object.values(record(record(candidate.graph).nodes)).some((candidateNode) => Object.hasOwn(record(candidateNode), "taskId"))) throw new TypeError("Task references are no longer supported.");
7004
7023
  const subflows = candidate.subflows;
7005
7024
  if (subflows !== void 0 && (subflows === null || typeof subflows !== "object" || Array.isArray(subflows) || Object.keys(subflows).length > 0)) throw new TypeError("Subflows are no longer supported.");
7006
7025
  if (Object.values(record(record(candidate.graph).nodes)).some((candidateNode) => record(candidateNode).kind === "subflow")) throw new TypeError("Subflow nodes are no longer supported.");
7026
+ if ([
7027
+ "inputDefs",
7028
+ "outputDefs",
7029
+ "outputMappings"
7030
+ ].some((field) => Object.hasOwn(candidate, field))) throw new TypeError("Workflow interface configuration must belong to Start and Outputs nodes.");
7031
+ if (Object.values(record(record(candidate.graph).nodes)).some((candidateNode) => record(candidateNode).kind == "start" && Object.hasOwn(record(candidateNode), "parameters"))) throw new TypeError("Legacy Start.parameters is unsupported; configure node.inputDefs.");
7007
7032
  return value;
7008
7033
  }
7009
7034
  function record(value) {
@@ -7203,6 +7228,7 @@ function conditionOperands(node) {
7203
7228
  }] : []])));
7204
7229
  }
7205
7230
  function nodeInputMappings(node) {
7231
+ if (node.kind == "outputs") return node.outputMappings;
7206
7232
  if (node.kind != "condition") return "inputs" in node ? node.inputs : {};
7207
7233
  return Object.fromEntries(conditionOperands(node).flatMap(({ handle, operand }) => operand.kind == "source" ? [[handle, {
7208
7234
  kind: "sources",
@@ -7433,6 +7459,17 @@ function decodeConnectorCapabilities(value) {
7433
7459
  };
7434
7460
  });
7435
7461
  }
7462
+ function isTriggerNode(node) {
7463
+ return [
7464
+ "manual",
7465
+ "start",
7466
+ "error",
7467
+ "webhook",
7468
+ "cron",
7469
+ "poll",
7470
+ "integration"
7471
+ ].includes(node.kind);
7472
+ }
7436
7473
  //#endregion
7437
7474
  //#region src/json-schema-subset/utils.ts
7438
7475
  var nextId = 0;
@@ -11298,6 +11335,7 @@ function triggerOutputDefinitions(trigger) {
11298
11335
  switch (trigger.kind) {
11299
11336
  case "error": return errorOutputs;
11300
11337
  case "manual": return [];
11338
+ case "start": return trigger.inputDefs;
11301
11339
  case "cron": return cronOutputs;
11302
11340
  case "poll":
11303
11341
  case "integration": return trigger.definition.outputs;
@@ -11317,6 +11355,15 @@ function matchesTriggerOutputs(trigger, outputs) {
11317
11355
  const ports = triggerOutputDefinitions(trigger);
11318
11356
  return new Set(ports.map((port) => port.handle)).size === ports.length && Object.keys(outputs).length === ports.length && ports.every((port) => Object.hasOwn(outputs, port.handle) && (outputs[port.handle] === null && port.nullable || matchesSchema(outputs[port.handle], port.jsonSchema)));
11319
11357
  }
11358
+ /** Resolve caller-supplied Start parameters into the complete output snapshot used by execution. */
11359
+ function normalizeTriggerOutputs(trigger, outputs) {
11360
+ if (!isJsonObject(outputs)) return;
11361
+ const normalized = trigger.kind == "start" ? {
11362
+ ...outputs,
11363
+ ...Object.fromEntries(trigger.inputDefs.filter((port) => port.nullable && !Object.hasOwn(outputs, port.handle)).map((port) => [port.handle, null]))
11364
+ } : outputs;
11365
+ return matchesTriggerOutputs(trigger, normalized) ? normalized : void 0;
11366
+ }
11320
11367
  //#endregion
11321
11368
  //#region src/execution/common/engineContract.ts
11322
11369
  var currentEngineContract = "open-flow-engine/v5";
@@ -11711,16 +11758,22 @@ function canonicalOperand(operand) {
11711
11758
  };
11712
11759
  }
11713
11760
  function canonicalNode(value) {
11714
- if (!("inputs" in value)) return canonicalTriggerNode(value);
11761
+ if (isTriggerNode(value)) return canonicalTriggerNode(value);
11715
11762
  const common = {
11716
11763
  ...value.description == null ? {} : { description: value.description },
11717
11764
  ...value.icon == null ? {} : { icon: value.icon },
11718
- inputs: canonicalInputs(value.inputs),
11765
+ ...value.kind == "outputs" ? {} : { inputs: canonicalInputs(value.inputs) },
11719
11766
  ...value.name == null ? {} : { name: value.name },
11720
11767
  ...value.maxExecutions == null ? {} : { maxExecutions: value.maxExecutions },
11721
11768
  ...value.timeoutMs == null ? {} : { timeoutMs: value.timeoutMs }
11722
11769
  };
11723
11770
  switch (value.kind) {
11771
+ case "outputs": return {
11772
+ ...common,
11773
+ kind: value.kind,
11774
+ outputDefs: canonicalPorts(value.outputDefs),
11775
+ outputMappings: canonicalInputs(value.outputMappings)
11776
+ };
11724
11777
  case "condition": return {
11725
11778
  ...common,
11726
11779
  cases: value.cases.map((item) => ({
@@ -11900,6 +11953,10 @@ function canonicalTriggerNode(trigger) {
11900
11953
  ...trigger.sourceFlowIds == null ? {} : { sourceFlowIds: [...trigger.sourceFlowIds] }
11901
11954
  };
11902
11955
  case "manual": return common(trigger.kind);
11956
+ case "start": return {
11957
+ ...common(trigger.kind),
11958
+ inputDefs: canonicalPorts(trigger.inputDefs)
11959
+ };
11903
11960
  case "webhook": return {
11904
11961
  ...common(trigger.kind),
11905
11962
  bodyFields: trigger.bodyFields.map((input) => ({
@@ -11982,7 +12039,10 @@ function graphDiagnostic(code, message, path, values, mismatch) {
11982
12039
  };
11983
12040
  }
11984
12041
  function validateTrigger(triggerId, trigger, path, diagnostics) {
11985
- const outputHandles = triggerOutputDefinitions(trigger).map((port) => port.handle);
12042
+ if (trigger.kind == "start") return;
12043
+ const outputs = triggerOutputDefinitions(trigger);
12044
+ if (outputs.some((port) => hasRetiredRef(port.jsonSchema))) diagnostics.push(graphDiagnostic("graph.schema-unsupported", "Runtime Ref schemas are not supported.", path));
12045
+ const outputHandles = outputs.map((port) => port.handle);
11986
12046
  if (new Set(outputHandles).size !== outputHandles.length) diagnostics.push(graphDiagnostic("graph.port-duplicate", "Trigger output handles must be unique.", `${path}/definition/outputs`));
11987
12047
  if (trigger.kind == "webhook") {
11988
12048
  if (!webhookSupportsBody(trigger.method) && trigger.bodyFields.length > 0) diagnostics.push(graphDiagnostic("trigger.webhook-body-unsupported", "GET Webhook triggers cannot declare request body fields.", `${path}/bodyFields`));
@@ -12008,6 +12068,7 @@ function validateTrigger(triggerId, trigger, path, diagnostics) {
12008
12068
  }
12009
12069
  function nodeInputPorts(node) {
12010
12070
  switch (node.kind) {
12071
+ case "outputs": return portsByHandle(node.outputDefs);
12011
12072
  case "condition": return conditionInputPorts(node);
12012
12073
  case "value": return {};
12013
12074
  case "task": return portsByHandle([...node.task.inputs, ...node.additionalInputs ?? []]);
@@ -12018,6 +12079,7 @@ function nodeInputPorts(node) {
12018
12079
  case "poll":
12019
12080
  case "error":
12020
12081
  case "manual":
12082
+ case "start":
12021
12083
  case "webhook": return {};
12022
12084
  }
12023
12085
  }
@@ -12064,6 +12126,7 @@ function resolutionOutputPorts(node) {
12064
12126
  }
12065
12127
  function nodeOutputPorts(node) {
12066
12128
  switch (node.kind) {
12129
+ case "outputs":
12067
12130
  case "condition": return {};
12068
12131
  case "value": return portsByHandle(node.values);
12069
12132
  case "task": return portsByHandle(node.task.outputs);
@@ -12074,6 +12137,7 @@ function nodeOutputPorts(node) {
12074
12137
  case "poll":
12075
12138
  case "error":
12076
12139
  case "manual":
12140
+ case "start":
12077
12141
  case "webhook": return triggerOutputPorts(node);
12078
12142
  }
12079
12143
  }
@@ -12191,7 +12255,7 @@ function graphPaths(graph) {
12191
12255
  routes.push(next);
12192
12256
  }
12193
12257
  }
12194
- const nextRoutes = edges.length == 0 ? "inputs" in node ? [{}] : [{ $trigger: id }] : routes;
12258
+ const nextRoutes = edges.length == 0 ? isTriggerNode(node) ? [{ $trigger: id }] : [{}] : routes;
12195
12259
  const previous = paths.get(id) ?? [];
12196
12260
  if (parents.size != (ancestors.get(id)?.size ?? 0) || resolutions.size != (resolutionOutputs.get(id)?.size ?? 0) || nextRoutes.length != previous.length || nextRoutes.some((route) => !previous.some((known) => routeCovers(known, route) && routeCovers(route, known)))) changed = true;
12197
12261
  ancestors.set(id, parents);
@@ -12274,14 +12338,16 @@ function validateGraph(graph, document, path, diagnostics) {
12274
12338
  const analysis = graphPaths(graph);
12275
12339
  const errorTriggers = Object.entries(graph.nodes).filter(([, node]) => node.kind == "error");
12276
12340
  if (errorTriggers.length > 1) for (const [nodeId] of errorTriggers) diagnostics.push(graphDiagnostic("graph.error-trigger-duplicate", "A graph can contain only one Flow Error node.", `${path}/nodes/${nodeId}`));
12277
- const manualTriggers = Object.entries(graph.nodes).filter(([, node]) => node.kind == "manual");
12278
- if (manualTriggers.length > 1) for (const [nodeId] of manualTriggers) diagnostics.push(graphDiagnostic("graph.manual-trigger-duplicate", "A graph can contain only one manual Trigger.", `${path}/nodes/${nodeId}`));
12341
+ const outputNodes = Object.entries(graph.nodes).filter(([, node]) => node.kind == "outputs");
12342
+ if (outputNodes.length > 1) for (const [nodeId] of outputNodes) diagnostics.push(graphDiagnostic("graph.outputs-duplicate", "A graph can contain only one Outputs node.", `${path}/nodes/${nodeId}`));
12343
+ const startTriggers = Object.entries(graph.nodes).filter(([, node]) => node.kind == "manual" || node.kind == "start");
12344
+ if (startTriggers.length > 1) for (const [nodeId] of startTriggers) diagnostics.push(graphDiagnostic("graph.start-trigger-duplicate", "A graph can contain only one Start Trigger.", `${path}/nodes/${nodeId}`));
12279
12345
  const seen = /* @__PURE__ */ new Set();
12280
12346
  for (const [index, edge] of graph.edges.entries()) {
12281
12347
  const edgePath = `${path}/edges/${index}`;
12282
12348
  const source = graph.nodes[edge.source];
12283
12349
  const target = graph.nodes[edge.target];
12284
- if (source == null || target == null || !("inputs" in target)) diagnostics.push(graphDiagnostic("graph.edge-invalid", "Execution edges require an existing source and an executable target.", edgePath));
12350
+ if (source == null || source.kind == "outputs" || target == null || isTriggerNode(target)) diagnostics.push(graphDiagnostic("graph.edge-invalid", "Execution edges require an existing source and an executable target.", edgePath));
12285
12351
  else if (source.kind == "condition" || isResolutionNode(source)) {
12286
12352
  const exits = isResolutionNode(source) ? Object.keys(resolutionOutputPorts(source)) : [...source.cases.map((item) => item.output), otherwiseOutput];
12287
12353
  if (edge.sourceHandle == null || !exits.some((exit) => exit == edge.sourceHandle)) diagnostics.push(graphDiagnostic("graph.edge-invalid", "Choose a declared execution branch.", edgePath));
@@ -12296,13 +12362,12 @@ function validateGraph(graph, document, path, diagnostics) {
12296
12362
  }
12297
12363
  for (const [nodeId, node] of Object.entries(graph.nodes)) {
12298
12364
  const nodePath = `${path}/nodes/${nodeId}`;
12299
- if ("inputs" in node && node.maxExecutions != null && (!Number.isSafeInteger(node.maxExecutions) || node.maxExecutions < 1)) diagnostics.push(graphDiagnostic("node.max-executions-invalid", "Maximum executions must be a positive safe integer.", `${nodePath}/maxExecutions`));
12300
- if (!("inputs" in node)) {
12301
- if (triggerOutputDefinitions(node).some((port) => hasRetiredRef(port.jsonSchema))) diagnostics.push(graphDiagnostic("graph.schema-unsupported", "Runtime Ref schemas are not supported.", nodePath));
12365
+ if (!isTriggerNode(node) && node.maxExecutions != null && (!Number.isSafeInteger(node.maxExecutions) || node.maxExecutions < 1)) diagnostics.push(graphDiagnostic("node.max-executions-invalid", "Maximum executions must be a positive safe integer.", `${nodePath}/maxExecutions`));
12366
+ if (isTriggerNode(node)) {
12302
12367
  validateTrigger(nodeId, node, nodePath, diagnostics);
12303
12368
  continue;
12304
12369
  }
12305
- for (const [handle, mapping] of Object.entries(nodeInputMappings(node))) if (!mappingAvailable(graph, nodeId, mapping, analysis)) diagnostics.push(graphDiagnostic("graph.source-unavailable", "Input sources must reference execution ancestors, respect pending Wait decisions, and never provide multiple values on the same path.", `${nodePath}/inputs/${handle}`));
12370
+ for (const [handle, mapping] of Object.entries(nodeInputMappings(node))) if (!mappingAvailable(graph, nodeId, mapping, analysis)) diagnostics.push(graphDiagnostic("graph.source-unavailable", "Input sources must reference execution ancestors, respect pending Wait decisions, and never provide multiple values on the same path.", node.kind == "outputs" ? `${nodePath}/outputMappings/${handle.replaceAll("~", "~0").replaceAll("/", "~1")}` : `${nodePath}/inputs/${handle}`));
12306
12371
  const inputPorts = nodeInputPorts(node);
12307
12372
  if (node.kind == "task") {
12308
12373
  const ports = [...node.task.inputs, ...node.additionalInputs ?? []];
@@ -12319,7 +12384,7 @@ function validateGraph(graph, document, path, diagnostics) {
12319
12384
  if ([...Object.values(inputPorts), ...Object.values(nodeOutputPorts(node))].some((port) => hasRetiredRef(port.jsonSchema))) diagnostics.push(graphDiagnostic("graph.schema-unsupported", "Runtime Ref schemas are not supported.", nodePath));
12320
12385
  const inputs = new Set(Object.keys(inputPorts));
12321
12386
  for (const [handle, mapping] of Object.entries(nodeInputMappings(node))) {
12322
- const mappingPath = `${nodePath}/inputs/${handle}`;
12387
+ const mappingPath = node.kind == "outputs" ? `${nodePath}/outputMappings/${handle.replaceAll("~", "~0").replaceAll("/", "~1")}` : `${nodePath}/inputs/${handle}`;
12323
12388
  if (!inputs.has(handle)) diagnostics.push(graphDiagnostic("graph.input-missing", `Node "${nodeId}" does not expose input "${handle}".`, mappingPath, {
12324
12389
  handle,
12325
12390
  nodeId
@@ -12369,6 +12434,14 @@ function validateGraph(graph, document, path, diagnostics) {
12369
12434
  }
12370
12435
  function validateFlowGraph(revision) {
12371
12436
  const diagnostics = [];
12437
+ for (const [id, node] of Object.entries(revision.document.graph.nodes)) {
12438
+ if (node.kind != "start" && node.kind != "outputs") continue;
12439
+ const field = node.kind == "start" ? "inputDefs" : "outputDefs";
12440
+ const ports = node.kind == "start" ? node.inputDefs : node.outputDefs;
12441
+ const path = `/document/graph/nodes/${id.replaceAll("~", "~0").replaceAll("/", "~1")}/${field}`;
12442
+ if (new Set(ports.map((port) => port.handle)).size != ports.length) diagnostics.push(graphDiagnostic("graph.port-duplicate", "Workflow interface names must be unique.", path));
12443
+ if (ports.some((port) => hasRetiredRef(port.jsonSchema))) diagnostics.push(graphDiagnostic("graph.schema-unsupported", "Runtime Ref schemas are not supported.", path));
12444
+ }
12372
12445
  for (const [bindingId, binding] of Object.entries(revision.document.bindings)) if (binding.kind == "variable" && !validVariableName(binding.target)) diagnostics.push(graphDiagnostic("binding.variable-invalid", `Variable binding "${bindingId}" has an invalid target.`, `/document/bindings/${bindingId}/target`, { bindingId }));
12373
12446
  validateGraph(revision.document.graph, revision.document, "/document/graph", diagnostics);
12374
12447
  return diagnostics;
@@ -24056,7 +24129,7 @@ function flowDependencies(content, triggerId) {
24056
24129
  }
24057
24130
  function visitGraph(value) {
24058
24131
  for (const [, node] of entries(value.nodes)) {
24059
- if ("inputs" in node) visitInputMappings(nodeInputMappings(node));
24132
+ if (!isTriggerNode(node)) visitInputMappings(nodeInputMappings(node));
24060
24133
  switch (node.kind) {
24061
24134
  case "condition": break;
24062
24135
  case "task": if ("moduleId" in node.task) visitModule(node.task.moduleId);
@@ -24072,21 +24145,29 @@ function flowDependencies(content, triggerId) {
24072
24145
  }
24073
24146
  async function flowClosure(content) {
24074
24147
  const dependencies = flowDependencies(content);
24075
- const { bindings, modules } = dependencies;
24076
24148
  return {
24077
24149
  dependencies,
24078
- digest: await digestBytes(canonicalJsonBytes({
24079
- bindings: Object.fromEntries([...bindings].toSorted().map((id) => [id, content.document.bindings[id] ?? null])),
24080
- graph: canonicalRevisionGraph(content, content.document.graph),
24081
- kind: "open-flow-semantic-closure",
24082
- ...content.modelVersion < 6 ? { subflows: {} } : {},
24083
- modelVersion: content.modelVersion,
24084
- modules: Object.fromEntries([...modules].toSorted().map((id) => [id, content.modules[id] == null ? null : canonicalModule(content.modules[id])])),
24085
- ...content.modelVersion < 6 ? { tasks: {} } : {},
24086
- version: 2
24087
- }))
24150
+ digest: await digestBytes(closureBytes(content, dependencies))
24088
24151
  };
24089
24152
  }
24153
+ /** Canonical semantic bytes, also used by transactional storage upgrades. */
24154
+ function encodeFlowClosure(content, triggerId) {
24155
+ const scoped = triggerId == null ? content : runRevision(content, triggerId);
24156
+ return closureBytes(scoped, flowDependencies(scoped));
24157
+ }
24158
+ function closureBytes(content, dependencies) {
24159
+ const { bindings, modules } = dependencies;
24160
+ return canonicalJsonBytes({
24161
+ bindings: Object.fromEntries([...bindings].toSorted().map((id) => [id, content.document.bindings[id] ?? null])),
24162
+ graph: canonicalRevisionGraph(content, content.document.graph),
24163
+ kind: "open-flow-semantic-closure",
24164
+ ...content.modelVersion < 6 ? { subflows: {} } : {},
24165
+ modelVersion: content.modelVersion,
24166
+ modules: Object.fromEntries([...modules].toSorted().map((id) => [id, content.modules[id] == null ? null : canonicalModule(content.modules[id])])),
24167
+ ...content.modelVersion < 6 ? { tasks: {} } : {},
24168
+ version: 2
24169
+ });
24170
+ }
24090
24171
  function variableBindings(revision, bindingIds) {
24091
24172
  return Object.fromEntries([...bindingIds].flatMap((bindingId) => {
24092
24173
  const binding = revision.document.bindings[bindingId];
@@ -24103,6 +24184,7 @@ function flowResourceReferences(content) {
24103
24184
  });
24104
24185
  }
24105
24186
  return {
24187
+ calledFlowIds: [...new Set(Object.values(content.document.graph.nodes).flatMap((node) => node.kind == "task" && "executor" in node.task && node.task.executor.kind == "workflow" && node.task.executor.flowId ? [node.task.executor.flowId] : []))].toSorted(),
24106
24188
  variableNames: [...new Set(Object.values(variableBindings(content, flowDependencies(content).bindings)))].toSorted(),
24107
24189
  connections: [...connections].toSorted(([left], [right]) => left < right ? -1 : left > right ? 1 : 0).map(([, value]) => value),
24108
24190
  errorSourceFlowIds: [...new Set(Object.values(content.document.graph.nodes).flatMap((node) => node.kind == "error" ? node.sourceFlowIds ?? [] : []))].toSorted()
@@ -24113,18 +24195,30 @@ function validRunTrigger(revision, value) {
24113
24195
  const trigger = value;
24114
24196
  if (Object.keys(trigger).some((key) => key != "nodeId" && key != "outputs") || typeof trigger.nodeId != "string" || !Object.hasOwn(trigger, "outputs")) return false;
24115
24197
  const node = revision.document.graph.nodes[trigger.nodeId];
24116
- return node != null && !("inputs" in node) && matchesTriggerOutputs(node, trigger.outputs);
24198
+ return node != null && isTriggerNode(node) && matchesTriggerOutputs(node, trigger.outputs);
24199
+ }
24200
+ function normalizeRunTrigger(revision, value) {
24201
+ if (value == null || typeof value != "object" || Array.isArray(value)) return;
24202
+ const trigger = value;
24203
+ if (Object.keys(trigger).some((key) => key != "nodeId" && key != "outputs") || typeof trigger.nodeId != "string" || !Object.hasOwn(trigger, "outputs")) return;
24204
+ const node = revision.document.graph.nodes[trigger.nodeId];
24205
+ if (node == null || !isTriggerNode(node)) return;
24206
+ const outputs = normalizeTriggerOutputs(node, trigger.outputs);
24207
+ return outputs == null ? void 0 : {
24208
+ nodeId: trigger.nodeId,
24209
+ outputs
24210
+ };
24117
24211
  }
24118
24212
  function validateFlowInputs(revision, value) {
24119
24213
  if (value == null || typeof value != "object" || Array.isArray(value)) return "invalid";
24120
24214
  const graph = revision.document.graph;
24121
24215
  for (const [nodeId, candidate] of Object.entries(value)) {
24122
24216
  const node = graph.nodes[nodeId];
24123
- if (node == null || !("inputs" in node) || node.kind == "condition" || candidate == null || typeof candidate != "object" || Array.isArray(candidate)) return "invalid";
24217
+ if (node == null || isTriggerNode(node) || node.kind == "condition" || candidate == null || typeof candidate != "object" || Array.isArray(candidate)) return "invalid";
24124
24218
  const inputs = nodeInputPorts(node);
24125
24219
  for (const handle of Object.keys(candidate)) {
24126
24220
  const port = inputs[handle];
24127
- if (port == null || hasRetiredRef(port.jsonSchema) || node.inputs[handle] != null || Object.hasOwn(port, "value")) return "invalid";
24221
+ if (port == null || hasRetiredRef(port.jsonSchema) || nodeInputMappings(node)[handle] != null || Object.hasOwn(port, "value")) return "invalid";
24128
24222
  }
24129
24223
  }
24130
24224
  return "valid";
@@ -24208,6 +24302,17 @@ async function validateFlow(revision, engine) {
24208
24302
  message,
24209
24303
  path: `/document/graph/nodes/${nodeId}/task/executor`
24210
24304
  });
24305
+ if (task.executor.kind == "connector" && task.executor.action == "leina.send_notification") {
24306
+ const mapping = node.inputs.leinaId;
24307
+ const value = inputValue(mapping, nodeInputPorts(node).leinaId?.value);
24308
+ if ((mapping?.kind != "sources" || mapping.sources.length == 0) && (typeof value != "string" || value.trim().length == 0)) checked.diagnostics.push({
24309
+ code: "leina.robot-required",
24310
+ column: 0,
24311
+ line: 1,
24312
+ message: "Select a Leina robot or bind its identifier to an input source.",
24313
+ path: `/document/graph/nodes/${nodeId}/inputs/leinaId`
24314
+ });
24315
+ }
24211
24316
  if (task.executor.kind == "connector" && task.executor.action.length == 0) checked.diagnostics.push({
24212
24317
  code: "task.connector-incomplete",
24213
24318
  column: 0,
@@ -24241,7 +24346,10 @@ function runRevision(revision, triggerId) {
24241
24346
  for (const nodeId of reachable) {
24242
24347
  const node = graph.nodes[nodeId];
24243
24348
  if (node == null) continue;
24244
- nodes[nodeId] = !("inputs" in node) ? node : {
24349
+ nodes[nodeId] = node.kind == "outputs" ? {
24350
+ ...node,
24351
+ outputMappings: inputs(nodeId, node.outputMappings)
24352
+ } : isTriggerNode(node) ? node : {
24245
24353
  ...node,
24246
24354
  inputs: inputs(nodeId, node.inputs)
24247
24355
  };
@@ -24270,7 +24378,7 @@ async function prepareFlow(revision, engineContract, triggerId) {
24270
24378
  if (engine == null) return { kind: "engine-unsupported" };
24271
24379
  if (triggerId != null) {
24272
24380
  const trigger = revision.document.graph.nodes[triggerId];
24273
- if (trigger == null || "inputs" in trigger) return {
24381
+ if (trigger == null || !isTriggerNode(trigger)) return {
24274
24382
  kind: "flow-invalid",
24275
24383
  validation: {
24276
24384
  closure: await flowClosure(revision),
@@ -24293,10 +24401,15 @@ async function prepareFlow(revision, engineContract, triggerId) {
24293
24401
  validation
24294
24402
  };
24295
24403
  const { closure } = validation;
24404
+ const start = Object.values(revision.document.graph.nodes).find((node) => node.kind == "start");
24405
+ const outputs = Object.values(revision.document.graph.nodes).find((node) => node.kind == "outputs");
24296
24406
  return {
24297
24407
  flow: {
24298
24408
  closureDigest: closure.digest,
24299
24409
  engineContract,
24410
+ inputDefs: start?.inputDefs ?? [],
24411
+ outputDefs: outputs?.outputDefs ?? [],
24412
+ outputMappings: outputs?.outputMappings ?? {},
24300
24413
  graph: revision.document.graph,
24301
24414
  modules: Object.fromEntries([...closure.dependencies.modules].toSorted().map((id) => [id, revision.modules[id]]))
24302
24415
  },
@@ -24330,4 +24443,4 @@ function codeActions(flow) {
24330
24443
  return Object.values(flow.graph.nodes).flatMap((node) => node.kind == "task" && "moduleId" in node.task ? node.task.capabilities ?? [] : []);
24331
24444
  }
24332
24445
  //#endregion
24333
- export { agentActions, agentInput, agentToolInput, agentToolSchema, availableOutputs, codeActions, connectionUsage, createRuntimeProgram, flowClosure, flowDependencies, flowResourceReferences, graphOrder, matchesSchema, matchesTriggerOutputs, nodeInputPorts, prepareFlow, removeConnectionUsage, renderPrompt, schemaValidationErrors, triggerOutputDefinitions, triggerOutputPorts, validRunTrigger, validateFlow, validateFlowInputs, validateModules, variableBindings, variableInputCompatible };
24446
+ export { agentActions, agentInput, agentToolInput, agentToolSchema, availableOutputs, codeActions, connectionUsage, createRuntimeProgram, encodeFlowClosure, flowClosure, flowDependencies, flowResourceReferences, graphOrder, matchesSchema, matchesTriggerOutputs, nodeInputPorts, normalizeRunTrigger, normalizeTriggerOutputs, prepareFlow, removeConnectionUsage, renderPrompt, schemaValidationErrors, triggerOutputDefinitions, triggerOutputPorts, validRunTrigger, validateFlow, validateFlowInputs, validateModules, variableBindings, variableInputCompatible };
@@ -6702,6 +6702,7 @@ var port = object({
6702
6702
  nullable: boolean(),
6703
6703
  handle: text
6704
6704
  });
6705
+ var workflowInputDefs = array(port.strict());
6705
6706
  var input = port.extend({ value: json.optional() });
6706
6707
  var group = object({
6707
6708
  collapsed: boolean().optional(),
@@ -6859,6 +6860,11 @@ var managedFields = object({
6859
6860
  messageHandle: text,
6860
6861
  inputs: record$2(text, agentValue)
6861
6862
  }).optional()
6863
+ }),
6864
+ strictObject({
6865
+ kind: literal("workflow"),
6866
+ flowId: text,
6867
+ revisionId: text
6862
6868
  })
6863
6869
  ])
6864
6870
  });
@@ -6967,6 +6973,12 @@ var base = {
6967
6973
  timeoutMs: number().optional()
6968
6974
  };
6969
6975
  var node = union([
6976
+ strictObject({
6977
+ ...base,
6978
+ kind: literal("outputs"),
6979
+ outputDefs: array(port.strict()),
6980
+ outputMappings: inputs
6981
+ }).omit({ inputs: true }),
6970
6982
  object({
6971
6983
  ...base,
6972
6984
  inputs: record$2(text, never()),
@@ -6999,6 +7011,11 @@ var node = union([
6999
7011
  ...trigger,
7000
7012
  kind: literal("manual")
7001
7013
  }),
7014
+ strictObject({
7015
+ ...trigger,
7016
+ kind: literal("start"),
7017
+ inputDefs: workflowInputDefs
7018
+ }),
7002
7019
  strictObject({
7003
7020
  ...trigger,
7004
7021
  kind: literal("error"),
@@ -7063,7 +7080,7 @@ var module = object({
7063
7080
  imports: strings,
7064
7081
  source: text
7065
7082
  });
7066
- var document = preprocess(rejectRetiredDefinitions, object({
7083
+ var document = preprocess(normalizeDocument, object({
7067
7084
  bindings: record$2(text, binding),
7068
7085
  graph
7069
7086
  }));
@@ -7072,7 +7089,9 @@ object({
7072
7089
  literal(2),
7073
7090
  literal(4),
7074
7091
  literal(5),
7075
- literal(6)
7092
+ literal(6),
7093
+ literal(7),
7094
+ literal(8)
7076
7095
  ]),
7077
7096
  document,
7078
7097
  modules: record$2(text, module)
@@ -7080,13 +7099,19 @@ object({
7080
7099
  kind: literal("open-flow-flow-revision"),
7081
7100
  version: literal(1)
7082
7101
  });
7083
- function rejectRetiredDefinitions(value) {
7102
+ function normalizeDocument(value) {
7084
7103
  const candidate = record$1(value);
7085
7104
  if (candidate.tasks !== void 0 && (candidate.tasks === null || typeof candidate.tasks !== "object" || Array.isArray(candidate.tasks) || Object.keys(candidate.tasks).length > 0)) throw new TypeError("Independent Task definitions are no longer supported.");
7086
7105
  if (Object.values(record$1(record$1(candidate.graph).nodes)).some((candidateNode) => Object.hasOwn(record$1(candidateNode), "taskId"))) throw new TypeError("Task references are no longer supported.");
7087
7106
  const subflows = candidate.subflows;
7088
7107
  if (subflows !== void 0 && (subflows === null || typeof subflows !== "object" || Array.isArray(subflows) || Object.keys(subflows).length > 0)) throw new TypeError("Subflows are no longer supported.");
7089
7108
  if (Object.values(record$1(record$1(candidate.graph).nodes)).some((candidateNode) => record$1(candidateNode).kind === "subflow")) throw new TypeError("Subflow nodes are no longer supported.");
7109
+ if ([
7110
+ "inputDefs",
7111
+ "outputDefs",
7112
+ "outputMappings"
7113
+ ].some((field) => Object.hasOwn(candidate, field))) throw new TypeError("Workflow interface configuration must belong to Start and Outputs nodes.");
7114
+ if (Object.values(record$1(record$1(candidate.graph).nodes)).some((candidateNode) => record$1(candidateNode).kind == "start" && Object.hasOwn(record$1(candidateNode), "parameters"))) throw new TypeError("Legacy Start.parameters is unsupported; configure node.inputDefs.");
7090
7115
  return value;
7091
7116
  }
7092
7117
  function record$1(value) {
@@ -1,13 +1,26 @@
1
1
  import type { RevisionContent } from '../browser/flow-change.js';
2
2
  import type { Publication, TriggerBinding } from './control-api.js';
3
3
  import { z } from 'zod';
4
+ import { flowInputFieldsView } from './authoringSchema.js';
4
5
  declare const entrySchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
6
+ nodeId: z.ZodString;
7
+ name: z.ZodString;
8
+ description: z.ZodOptional<z.ZodString>;
9
+ type: z.ZodLiteral<"start">;
10
+ config: z.ZodObject<{
11
+ inputDefs: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
12
+ schema: z.ZodOptional<z.ZodJSONSchema>;
13
+ nullable: z.ZodOptional<z.ZodBoolean>;
14
+ description: z.ZodOptional<z.ZodString>;
15
+ }, z.core.$strict>>>;
16
+ }, z.core.$strict>;
17
+ }, z.core.$strip>, z.ZodObject<{
5
18
  nodeId: z.ZodString;
6
19
  name: z.ZodString;
7
20
  description: z.ZodOptional<z.ZodString>;
8
21
  type: z.ZodLiteral<"manual">;
9
- config: z.ZodObject<{}, z.core.$strict>;
10
- }, z.core.$strict>, z.ZodObject<{
22
+ config: z.ZodObject<{}, z.core.$strip>;
23
+ }, z.core.$strip>, z.ZodObject<{
11
24
  nodeId: z.ZodString;
12
25
  name: z.ZodString;
13
26
  description: z.ZodOptional<z.ZodString>;
@@ -36,7 +49,7 @@ declare const entrySchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
36
49
  }, z.core.$strict>>;
37
50
  }, z.core.$strict>;
38
51
  binding: z.ZodPipe<z.ZodUnknown, z.ZodTransform<TriggerBinding, unknown>>;
39
- }, z.core.$strict>, z.ZodObject<{
52
+ }, z.core.$strip>, z.ZodObject<{
40
53
  nodeId: z.ZodString;
41
54
  name: z.ZodString;
42
55
  description: z.ZodOptional<z.ZodString>;
@@ -59,7 +72,7 @@ declare const entrySchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
59
72
  }, z.core.$strip>]>>;
60
73
  }, z.core.$strict>;
61
74
  binding: z.ZodPipe<z.ZodUnknown, z.ZodTransform<TriggerBinding, unknown>>;
62
- }, z.core.$strict>, z.ZodObject<{
75
+ }, z.core.$strip>, z.ZodObject<{
63
76
  nodeId: z.ZodString;
64
77
  name: z.ZodString;
65
78
  description: z.ZodOptional<z.ZodString>;
@@ -68,7 +81,7 @@ declare const entrySchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
68
81
  sourceFlowIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
69
82
  }, z.core.$strict>;
70
83
  binding: z.ZodPipe<z.ZodUnknown, z.ZodTransform<TriggerBinding, unknown>>;
71
- }, z.core.$strict>, z.ZodObject<{
84
+ }, z.core.$strip>, z.ZodObject<{
72
85
  nodeId: z.ZodString;
73
86
  name: z.ZodString;
74
87
  description: z.ZodOptional<z.ZodString>;
@@ -76,9 +89,9 @@ declare const entrySchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
76
89
  inputs: z.ZodRecord<z.ZodString, z.ZodDiscriminatedUnion<[z.ZodObject<{
77
90
  kind: z.ZodLiteral<"value">;
78
91
  value: z.ZodJSONSchema;
79
- }, z.core.$strict>, z.ZodObject<{
92
+ }, z.core.$strip>, z.ZodObject<{
80
93
  kind: z.ZodLiteral<"unset">;
81
- }, z.core.$strict>], "kind">>;
94
+ }, z.core.$strip>], "kind">>;
82
95
  type: z.ZodLiteral<"poll">;
83
96
  config: z.ZodObject<{
84
97
  key: z.ZodString;
@@ -100,7 +113,7 @@ declare const entrySchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
100
113
  }, z.core.$strip>]>>;
101
114
  }, z.core.$strict>;
102
115
  binding: z.ZodPipe<z.ZodUnknown, z.ZodTransform<TriggerBinding, unknown>>;
103
- }, z.core.$strict>, z.ZodObject<{
116
+ }, z.core.$strip>, z.ZodObject<{
104
117
  nodeId: z.ZodString;
105
118
  name: z.ZodString;
106
119
  description: z.ZodOptional<z.ZodString>;
@@ -108,25 +121,27 @@ declare const entrySchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
108
121
  inputs: z.ZodRecord<z.ZodString, z.ZodDiscriminatedUnion<[z.ZodObject<{
109
122
  kind: z.ZodLiteral<"value">;
110
123
  value: z.ZodJSONSchema;
111
- }, z.core.$strict>, z.ZodObject<{
124
+ }, z.core.$strip>, z.ZodObject<{
112
125
  kind: z.ZodLiteral<"unset">;
113
- }, z.core.$strict>], "kind">>;
126
+ }, z.core.$strip>], "kind">>;
114
127
  type: z.ZodLiteral<"integration">;
115
128
  config: z.ZodObject<{
116
129
  key: z.ZodString;
117
130
  connectionId: z.ZodOptional<z.ZodString>;
118
131
  }, z.core.$strict>;
119
132
  binding: z.ZodPipe<z.ZodUnknown, z.ZodTransform<TriggerBinding, unknown>>;
120
- }, z.core.$strict>], "type">;
133
+ }, z.core.$strip>], "type">;
121
134
  export type LiveEntry = z.infer<typeof entrySchema>;
122
135
  export type LiveDetails = {
123
136
  readonly flowId: string;
124
137
  readonly version: 1;
125
138
  } & ({
139
+ readonly inputDefs: null;
126
140
  readonly publication: null;
127
141
  readonly status: 'not-published';
128
142
  readonly entries: readonly [];
129
143
  } | {
144
+ readonly inputDefs: z.infer<typeof flowInputFieldsView>;
130
145
  readonly publication: Publication;
131
146
  readonly status: 'runnable' | 'suspended';
132
147
  readonly enabled: boolean;
@@ -161,7 +161,7 @@ export declare const mcpTools: {
161
161
  value: {
162
162
  revision?: string | undefined;
163
163
  query: string;
164
- type?: "agent" | "approval" | "code" | "condition" | "connector" | "cron" | "decision" | "error" | "integration" | "llm" | "manual" | "openapi" | "poll" | "value" | "wait" | "webhook" | undefined;
164
+ type?: "agent" | "approval" | "code" | "condition" | "connector" | "cron" | "decision" | "error" | "integration" | "llm" | "openapi" | "outputs" | "poll" | "start" | "value" | "wait" | "webhook" | "workflow" | undefined;
165
165
  offset: number;
166
166
  limit: number;
167
167
  flowId: string;
@@ -193,7 +193,7 @@ export declare const mcpTools: {
193
193
  };
194
194
  validate(value: unknown): {
195
195
  value: {
196
- type?: "agent" | "approval" | "code" | "condition" | "connector" | "cron" | "decision" | "error" | "integration" | "llm" | "manual" | "openapi" | "poll" | "value" | "wait" | "webhook" | undefined;
196
+ type?: "agent" | "approval" | "code" | "condition" | "connector" | "cron" | "decision" | "error" | "integration" | "llm" | "openapi" | "outputs" | "poll" | "start" | "value" | "wait" | "webhook" | "workflow" | undefined;
197
197
  action?: string | undefined;
198
198
  flowId?: string | undefined;
199
199
  };
@@ -321,7 +321,7 @@ export declare const mcpTools: {
321
321
  edits: ({
322
322
  op: "node.add";
323
323
  as: string;
324
- type: "agent" | "approval" | "code" | "condition" | "connector" | "cron" | "decision" | "error" | "integration" | "llm" | "manual" | "openapi" | "poll" | "value" | "wait" | "webhook";
324
+ type: "agent" | "approval" | "code" | "condition" | "connector" | "cron" | "decision" | "error" | "integration" | "llm" | "openapi" | "outputs" | "poll" | "start" | "value" | "wait" | "webhook" | "workflow";
325
325
  name: string;
326
326
  config?: Record<string, z.JSONType> | undefined;
327
327
  inputs?: Record<string, {
@@ -365,6 +365,9 @@ export declare const mcpTools: {
365
365
  config?: Record<string, z.JSONType> | undefined;
366
366
  } | undefined;
367
367
  clear?: string[][] | undefined;
368
+ } | {
369
+ op: "node.refresh";
370
+ node: string;
368
371
  } | {
369
372
  op: "node.remove";
370
373
  node: string;