@oomol-lab/open-flow 0.1.0-beta.76 → 0.1.0-beta.78

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 (74) hide show
  1. package/README.md +3 -0
  2. package/dist/browser/{ContentIcon-Cm1hbVzW.js → ContentIcon-CMn0c-kl.js} +99 -6
  3. package/dist/browser/{FlowCanvas-NzKtla_c.js → FlowCanvas-BQGBcfoL.js} +1709 -613
  4. package/dist/browser/{createResourceDialog-BgdedQqu.js → createResourceDialog-DCGxfKFM.js} +63 -57
  5. package/dist/browser/{dialog-aSElFFw2.js → dialog-WzR4CRFH.js} +76 -77
  6. package/dist/browser/{exportSvg-Dcz4HTo_.js → exportSvg-CYwyYiuH.js} +2 -2
  7. package/dist/browser/{flowChanges-NZyS7HSp.js → flowChanges-Bz4dbDN_.js} +6875 -11091
  8. package/dist/browser/{flowWorkspace-Bl0SDehy.js → flowWorkspace-BI6L6a4r.js} +1415 -3037
  9. package/dist/browser/licenses.md +1 -1
  10. package/dist/browser/preview.css +619 -462
  11. package/dist/browser/preview.js +9016 -14956
  12. package/dist/browser/theme.css +4 -2
  13. package/dist/browser/{tooltip-3XMK9jkr.js → tooltip-BDcVTNpu.js} +65 -2
  14. package/dist/browser/{typeScriptSession-C9sBGOKZ.js → typeScriptSession-CRoezJPN.js} +1 -1
  15. package/dist/browser/ui.css +112 -24
  16. package/dist/browser/ui.js +3 -2
  17. package/dist/browser/workbench.css +10020 -9842
  18. package/dist/browser/workbench.d.ts +5 -2
  19. package/dist/browser/workbench.js +2382 -2668
  20. package/dist/browser/{workbenchSelect-DBGP7Y4Z.js → workbenchSelect-DtAd0zc4.js} +2 -2
  21. package/dist/command/index.js +48 -48
  22. package/dist/common/authoring.d.ts +4 -4
  23. package/dist/common/authoringExamples.d.ts +3 -2
  24. package/dist/common/authoringSchema.d.ts +15 -4
  25. package/dist/common/control-api-conformance.js +155 -15
  26. package/dist/common/control-api-errors.d.ts +12 -0
  27. package/dist/common/control-api.d.ts +39 -2
  28. package/dist/common/control-api.js +180 -37
  29. package/dist/common/control-requests.d.ts +23 -3
  30. package/dist/common/control-requests.js +141 -14
  31. package/dist/common/engine-contract.d.ts +3 -2
  32. package/dist/common/flow-authoring.js +47 -7
  33. package/dist/common/flow-change-schema.d.ts +1 -1
  34. package/dist/common/flow-change.d.ts +2 -2
  35. package/dist/common/flow-change.js +48 -8
  36. package/dist/common/flow-encoding.js +47 -7
  37. package/dist/common/flow-semantics.js +86 -8
  38. package/dist/common/flow-state.d.ts +100 -0
  39. package/dist/common/flow-state.js +5794 -0
  40. package/dist/common/mcp.d.ts +96 -3
  41. package/dist/common/mcp.js +158 -13
  42. package/dist/common/run-events.js +19 -8
  43. package/dist/common/runtime-contract.d.ts +14 -0
  44. package/dist/common/runtime-contract.js +124 -17
  45. package/dist/common/runtime-nodejs-compat.js +11 -12
  46. package/dist/common/scheduler-node-execution.d.ts +1 -0
  47. package/dist/common/scheduler.d.ts +2 -1
  48. package/dist/common/scheduler.js +95 -40
  49. package/dist/common/state-conformance.d.ts +16 -0
  50. package/dist/common/tags.d.ts +4 -0
  51. package/dist/index.d.ts +11 -0
  52. package/package.json +5 -1
  53. package/src/control/common/api.ts +101 -11
  54. package/src/control/common/authoring.ts +7 -1
  55. package/src/control/common/authoringExamples.ts +9 -0
  56. package/src/control/common/authoringSchema.ts +18 -12
  57. package/src/control/common/errors.ts +6 -0
  58. package/src/control/common/flowDecoders.ts +1 -0
  59. package/src/control/common/mcp.ts +16 -0
  60. package/src/control/common/requests.ts +16 -2
  61. package/src/control/common/tags.ts +20 -0
  62. package/src/execution/common/events.ts +22 -7
  63. package/src/execution/common/node-execution.ts +3 -0
  64. package/src/execution/common/scheduler.ts +29 -13
  65. package/src/flow/common/change.ts +2 -1
  66. package/src/flow/common/changeSchema.ts +11 -1
  67. package/src/flow/common/errorHandling.ts +1 -1
  68. package/src/flow/common/semantics.ts +27 -1
  69. package/src/runtime/common/engineContract.ts +6 -3
  70. package/src/runtime/common/nodejsGuest.generated.json +11 -12
  71. package/src/runtime/common/runtime.ts +122 -7
  72. package/src/state/common/conformance.ts +81 -0
  73. package/src/state/common/state.ts +141 -0
  74. package/src/types/index.ts +11 -0
@@ -3,6 +3,99 @@ import { z } from 'zod';
3
3
  export declare const mcpProtocolVersion = "2026-07-28";
4
4
  export declare const mcpInstructions: string;
5
5
  export declare const mcpTools: {
6
+ flow_state: {
7
+ description: string;
8
+ annotations: {
9
+ readOnlyHint: boolean;
10
+ destructiveHint: boolean;
11
+ idempotentHint: boolean;
12
+ openWorldHint: boolean;
13
+ };
14
+ inputSchema: {
15
+ '~standard': {
16
+ version: 1;
17
+ vendor: string;
18
+ jsonSchema: {
19
+ input: () => Record<string, unknown>;
20
+ output: () => Record<string, unknown>;
21
+ };
22
+ validate(value: unknown): {
23
+ value: {
24
+ scope: "draft" | "live";
25
+ values?: boolean | undefined;
26
+ flowId: string;
27
+ };
28
+ } | {
29
+ issues: {
30
+ message: string;
31
+ path: string[];
32
+ }[];
33
+ };
34
+ };
35
+ };
36
+ };
37
+ flow_state_clear: {
38
+ description: string;
39
+ annotations: {
40
+ readOnlyHint: boolean;
41
+ destructiveHint: boolean;
42
+ idempotentHint: boolean;
43
+ openWorldHint: boolean;
44
+ };
45
+ inputSchema: {
46
+ '~standard': {
47
+ version: 1;
48
+ vendor: string;
49
+ jsonSchema: {
50
+ input: () => Record<string, unknown>;
51
+ output: () => Record<string, unknown>;
52
+ };
53
+ validate(value: unknown): {
54
+ value: {
55
+ scope: "draft" | "live";
56
+ key?: string | undefined;
57
+ flowId: string;
58
+ };
59
+ } | {
60
+ issues: {
61
+ message: string;
62
+ path: string[];
63
+ }[];
64
+ };
65
+ };
66
+ };
67
+ };
68
+ flow_dedupe_clear: {
69
+ description: string;
70
+ annotations: {
71
+ readOnlyHint: boolean;
72
+ destructiveHint: boolean;
73
+ idempotentHint: boolean;
74
+ openWorldHint: boolean;
75
+ };
76
+ inputSchema: {
77
+ '~standard': {
78
+ version: 1;
79
+ vendor: string;
80
+ jsonSchema: {
81
+ input: () => Record<string, unknown>;
82
+ output: () => Record<string, unknown>;
83
+ };
84
+ validate(value: unknown): {
85
+ value: {
86
+ scope: "draft" | "live";
87
+ space: string;
88
+ flowId: string;
89
+ };
90
+ } | {
91
+ issues: {
92
+ message: string;
93
+ path: string[];
94
+ }[];
95
+ };
96
+ };
97
+ };
98
+ };
6
99
  flow_canvas: {
7
100
  description: string;
8
101
  annotations: {
@@ -161,7 +254,7 @@ export declare const mcpTools: {
161
254
  value: {
162
255
  revision?: string | undefined;
163
256
  query: string;
164
- type?: "agent" | "approval" | "code" | "condition" | "connector" | "cron" | "decision" | "error" | "http-request" | "integration" | "llm" | "openapi" | "outputs" | "poll" | "start" | "value" | "wait" | "webhook" | "webhook-response" | "workflow" | undefined;
257
+ type?: "agent" | "approval" | "code" | "condition" | "connector" | "cron" | "decision" | "error" | "http-request" | "integration" | "llm" | "openapi" | "outputs" | "poll" | "skip-duplicates" | "start" | "value" | "wait" | "webhook" | "webhook-response" | "workflow" | undefined;
165
258
  offset: number;
166
259
  limit: number;
167
260
  flowId: string;
@@ -193,7 +286,7 @@ export declare const mcpTools: {
193
286
  };
194
287
  validate(value: unknown): {
195
288
  value: {
196
- type?: "agent" | "approval" | "code" | "condition" | "connector" | "cron" | "decision" | "error" | "http-request" | "integration" | "llm" | "openapi" | "outputs" | "poll" | "start" | "value" | "wait" | "webhook" | "webhook-response" | "workflow" | undefined;
289
+ type?: "agent" | "approval" | "code" | "condition" | "connector" | "cron" | "decision" | "error" | "http-request" | "integration" | "llm" | "openapi" | "outputs" | "poll" | "skip-duplicates" | "start" | "value" | "wait" | "webhook" | "webhook-response" | "workflow" | undefined;
197
290
  action?: string | undefined;
198
291
  flowId?: string | undefined;
199
292
  };
@@ -321,7 +414,7 @@ export declare const mcpTools: {
321
414
  edits: ({
322
415
  op: "node.add";
323
416
  as: string;
324
- type: "agent" | "approval" | "code" | "condition" | "connector" | "cron" | "decision" | "error" | "http-request" | "integration" | "llm" | "openapi" | "outputs" | "poll" | "start" | "value" | "wait" | "webhook" | "webhook-response" | "workflow";
417
+ type: "agent" | "approval" | "code" | "condition" | "connector" | "cron" | "decision" | "error" | "http-request" | "integration" | "llm" | "openapi" | "outputs" | "poll" | "skip-duplicates" | "start" | "value" | "wait" | "webhook" | "webhook-response" | "workflow";
325
418
  name: string;
326
419
  onError?: "error" | "stop" | undefined;
327
420
  retry?: {
@@ -8846,6 +8846,46 @@ var httpRequestConfigSchema = strictObject({
8846
8846
  statusPolicy: _enum(["success", "all"]).default("success")
8847
8847
  });
8848
8848
  var httpRequestExecutorSchema = httpRequestConfigSchema.extend({ kind: literal("http-request") });
8849
+ //#endregion
8850
+ //#region src/state/common/state.ts
8851
+ var stateQuerySchema = strictObject({
8852
+ scope: _enum(["draft", "live"]),
8853
+ values: boolean().optional()
8854
+ });
8855
+ var stateClearSchema = strictObject({
8856
+ scope: _enum(["draft", "live"]),
8857
+ key: string$1().min(1).refine((key) => new TextEncoder().encode(key).length <= 256).optional()
8858
+ });
8859
+ var dedupeClearSchema = strictObject({
8860
+ scope: _enum(["draft", "live"]),
8861
+ space: string$1().regex(/^(flow|node:.+)$/)
8862
+ });
8863
+ var skipDuplicatesConfigSchema = strictObject({ fields: array(string$1().refine((field) => field.length > 0 && field.split(".").every((part) => part.length > 0), "Use a nonempty dot-separated field path.")).refine((fields) => new Set(fields).size === fields.length, "Identity fields must be distinct.").default([]) });
8864
+ var skipDuplicatesExecutorSchema = skipDuplicatesConfigSchema.extend({ kind: literal("skip-duplicates") });
8865
+ var flowStateViewSchema = object({
8866
+ version: literal(1),
8867
+ scope: _enum(["draft", "live"]),
8868
+ limits: object({
8869
+ maxValueBytes: number().positive(),
8870
+ maxValues: number().int().positive(),
8871
+ maxSpaces: number().int().positive(),
8872
+ maxIdentities: number().positive(),
8873
+ maxRunWrites: number().positive()
8874
+ }),
8875
+ values: array(object({
8876
+ key: string$1(),
8877
+ size: number().nonnegative(),
8878
+ updatedAt: number(),
8879
+ value: json$4().optional()
8880
+ })),
8881
+ spaces: array(object({
8882
+ space: string$1(),
8883
+ count: number().nonnegative(),
8884
+ pendingCount: number().nonnegative(),
8885
+ reservedCount: number().nonnegative(),
8886
+ updatedAt: number()
8887
+ }))
8888
+ });
8849
8889
  function checkJsonDepth(value, depth = 0) {
8850
8890
  if (depth > 64) throw new TypeError("Value exceeds the maximum JSON depth.");
8851
8891
  if (value != null && typeof value == "object") for (const child of Object.values(value)) checkJsonDepth(child, depth + 1);
@@ -9134,7 +9174,8 @@ var managedFields = object({
9134
9174
  flowId: text,
9135
9175
  revisionId: text
9136
9176
  }),
9137
- httpRequestExecutorSchema
9177
+ httpRequestExecutorSchema,
9178
+ skipDuplicatesExecutorSchema
9138
9179
  ])
9139
9180
  });
9140
9181
  var managed = managedFields.transform(limitDecisionTask);
@@ -9404,7 +9445,8 @@ var revision = object({
9404
9445
  literal(9),
9405
9446
  literal(10),
9406
9447
  literal(11),
9407
- literal(12)
9448
+ literal(12),
9449
+ literal(13)
9408
9450
  ]),
9409
9451
  document,
9410
9452
  modules: record$2(text, module)
@@ -9605,6 +9647,7 @@ array(union([...new Map(Object.entries(shapes).map(([kind, shape]) => [kind, sha
9605
9647
  ...shape
9606
9648
  })])).values()])).min(1);
9607
9649
  function checkModelVersion(content) {
9650
+ if (content.modelVersion < 13 && Object.values(content.document.graph.nodes).some((candidateNode) => candidateNode.kind === "task" && "executor" in candidateNode.task && candidateNode.task.executor.kind === "skip-duplicates")) throw new Error("Skip Duplicates requires Flow model v13.");
9608
9651
  if (content.modelVersion < 12 && Object.values(content.document.graph.nodes).some((candidateNode) => candidateNode.kind == "task" && "moduleId" in candidateNode.task && candidateNode.task.capabilities?.some((item) => item.kind == "http"))) throw new TypeError("Code HTTP access requires Flow model version 12.");
9609
9652
  if (content.modelVersion < 11 && Object.values(content.document.graph.nodes).some((candidateNode) => candidateNode.kind == "task" && "executor" in candidateNode.task && candidateNode.task.executor.kind == "http-request")) throw new TypeError("HTTP Request requires Flow model version 11.");
9610
9653
  if (content.modelVersion < 11 && Object.values(content.document.graph.nodes).some((candidateNode) => candidateNode.kind == "task" && ("moduleId" in candidateNode.task ? candidateNode.task.capabilities?.some((item) => item.kind == "workflow") : candidateNode.task.executor.kind == "agent" && candidateNode.task.executor.tools.some((item) => item.kind == "workflow")))) throw new TypeError("Workflow tools require Flow model version 11.");
@@ -9636,8 +9679,8 @@ function resourceNameIssue(value) {
9636
9679
  }
9637
9680
  //#endregion
9638
9681
  //#region src/runtime/common/engineContract.ts
9639
- /** v9 is a single contract: the Node compatibility builtins, `context.fetch`, and no `context.egress`. */
9640
- var currentEngineContract = "open-flow-engine/v9";
9682
+ /** v10 adds persistent Flow State to the published v9 Node compatibility and fetch contract. */
9683
+ var currentEngineContract = "open-flow-engine/v10";
9641
9684
  /** The published v8 Node compatibility contract, retained for existing Publications and Runs. */
9642
9685
  var nodejsEngineContract = "open-flow-engine/v8/nodejs-compat-v1";
9643
9686
  var platformSource = (contract) => `export const engineContract = ${JSON.stringify(contract)}
@@ -9682,13 +9725,19 @@ var nodejsContract = {
9682
9725
  ].flatMap((name) => [name, `node:${name}`])),
9683
9726
  platformSource: platformSource(nodejsEngineContract)
9684
9727
  };
9685
- var currentContract = {
9728
+ var v9Contract = {
9686
9729
  ...nodejsContract,
9687
9730
  codeFetch: true,
9731
+ platformSource: platformSource("open-flow-engine/v9")
9732
+ };
9733
+ var currentContract = {
9734
+ ...v9Contract,
9735
+ flowState: true,
9688
9736
  platformSource: platformSource(currentEngineContract)
9689
9737
  };
9690
9738
  function findEngineContract(contract) {
9691
- if (contract == "open-flow-engine/v9") return currentContract;
9739
+ if (contract == "open-flow-engine/v10") return currentContract;
9740
+ if (contract == "open-flow-engine/v9") return v9Contract;
9692
9741
  if (contract == "open-flow-engine/v8") return v8Contract;
9693
9742
  if (contract == "open-flow-engine/v8/nodejs-compat-v1") return nodejsContract;
9694
9743
  if (contract == "open-flow-engine/v7" || contract == "open-flow-engine/v7/nodejs-compat-v1") return {
@@ -9755,6 +9804,7 @@ var type = _enum([
9755
9804
  "decision",
9756
9805
  "openapi",
9757
9806
  "http-request",
9807
+ "skip-duplicates",
9758
9808
  "condition",
9759
9809
  "value",
9760
9810
  "wait",
@@ -9885,6 +9935,7 @@ var authoringConfigurations = {
9885
9935
  "connector": authoringDefinitionSchemas.connector.omit({ outputMode: true }).strict(),
9886
9936
  "openapi": authoringOpenApiSchema,
9887
9937
  "http-request": httpRequestConfigSchema,
9938
+ "skip-duplicates": skipDuplicatesConfigSchema,
9888
9939
  "agent": authoringDefinitionSchemas.agent.omit({
9889
9940
  prompt: true,
9890
9941
  tools: true
@@ -10160,11 +10211,14 @@ var controlErrorCode = {
10160
10211
  triggerKeyInvalid: "trigger-key.invalid",
10161
10212
  triggerKeyNotFound: "trigger-key.not-found",
10162
10213
  triggerNotFound: "trigger.not-found",
10214
+ tagInvalid: "tag.invalid",
10215
+ tagConflict: "tag.conflict",
10216
+ tagNotFound: "tag.not-found",
10163
10217
  variableInvalid: "variable.invalid",
10164
10218
  variableLimitReached: "variable.limit-reached",
10165
10219
  variableNotFound: "variable.not-found"
10166
10220
  };
10167
- controlErrorCode.eventSourceInvalid, controlErrorCode.eventSourceIdentityUnavailable, controlErrorCode.eventSourceNotFound, controlErrorCode.eventSourceConflict, controlErrorCode.authenticationRequired, controlErrorCode.authorizationDenied, controlErrorCode.bindingUnresolved, controlErrorCode.connectorActionNotFound, controlErrorCode.connectorAccessConflict, controlErrorCode.connectorAccessInvalid, controlErrorCode.connectorAccessRequired, controlErrorCode.connectorAccessUnsupported, controlErrorCode.connectorUnconfigured, controlErrorCode.connectorUnavailable, controlErrorCode.connectorConsoleUnconfigured, controlErrorCode.engineUnavailable, controlErrorCode.engineUnsupported, controlErrorCode.flowInvalid, controlErrorCode.flowRepairRequired, controlErrorCode.flowUpgradeRequired, controlErrorCode.flowNotFound, controlErrorCode.flowBusy, controlErrorCode.flowConflict, controlErrorCode.flowPresentationConflict, controlErrorCode.flowRevisionConflict, controlErrorCode.liveConflict, controlErrorCode.liveNotFound, controlErrorCode.pageInvalidCursor, controlErrorCode.publicationConflict, controlErrorCode.publicationNotFound, controlErrorCode.publicationUnsupported, controlErrorCode.publishOperationNotFound, controlErrorCode.routeNotFound, controlErrorCode.runConflict, controlErrorCode.runEventsExpired, controlErrorCode.runInvalid, controlErrorCode.runNotFound, controlErrorCode.runNotTerminal, controlErrorCode.runOverloaded, controlErrorCode.runWaitNotFound, controlErrorCode.triggerKeyInvalid, controlErrorCode.triggerKeyNotFound, controlErrorCode.triggerNotFound, controlErrorCode.variableInvalid, controlErrorCode.variableLimitReached, controlErrorCode.variableNotFound;
10221
+ controlErrorCode.eventSourceInvalid, controlErrorCode.eventSourceIdentityUnavailable, controlErrorCode.eventSourceNotFound, controlErrorCode.eventSourceConflict, controlErrorCode.authenticationRequired, controlErrorCode.authorizationDenied, controlErrorCode.bindingUnresolved, controlErrorCode.connectorActionNotFound, controlErrorCode.connectorAccessConflict, controlErrorCode.connectorAccessInvalid, controlErrorCode.connectorAccessRequired, controlErrorCode.connectorAccessUnsupported, controlErrorCode.connectorUnconfigured, controlErrorCode.connectorUnavailable, controlErrorCode.connectorConsoleUnconfigured, controlErrorCode.engineUnavailable, controlErrorCode.engineUnsupported, controlErrorCode.flowInvalid, controlErrorCode.flowRepairRequired, controlErrorCode.flowUpgradeRequired, controlErrorCode.flowNotFound, controlErrorCode.flowBusy, controlErrorCode.flowConflict, controlErrorCode.flowPresentationConflict, controlErrorCode.flowRevisionConflict, controlErrorCode.liveConflict, controlErrorCode.liveNotFound, controlErrorCode.pageInvalidCursor, controlErrorCode.publicationConflict, controlErrorCode.publicationNotFound, controlErrorCode.publicationUnsupported, controlErrorCode.publishOperationNotFound, controlErrorCode.routeNotFound, controlErrorCode.runConflict, controlErrorCode.runEventsExpired, controlErrorCode.runInvalid, controlErrorCode.runNotFound, controlErrorCode.runNotTerminal, controlErrorCode.runOverloaded, controlErrorCode.runWaitNotFound, controlErrorCode.triggerKeyInvalid, controlErrorCode.triggerKeyNotFound, controlErrorCode.triggerNotFound, controlErrorCode.tagInvalid, controlErrorCode.tagConflict, controlErrorCode.tagNotFound, controlErrorCode.variableInvalid, controlErrorCode.variableLimitReached, controlErrorCode.variableNotFound;
10168
10222
  var ApiError = class extends Error {
10169
10223
  constructor(status, code, message, details) {
10170
10224
  super(message);
@@ -11430,6 +11484,7 @@ function flow$1(value) {
11430
11484
  publicationId: string(target.publicationId),
11431
11485
  revisionId: string(target.revisionId)
11432
11486
  } },
11487
+ tagIds: source.tagIds === void 0 ? [] : strings(source.tagIds),
11433
11488
  createdAt: string(source.createdAt),
11434
11489
  ...source.connectorTeamId == null ? {} : { connectorTeamId: string(source.connectorTeamId) },
11435
11490
  draftRevisionId: string(source.draftRevisionId),
@@ -11864,6 +11919,33 @@ function randomId() {
11864
11919
  return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`;
11865
11920
  }
11866
11921
  //#endregion
11922
+ //#region src/control/common/tags.ts
11923
+ function normalizeFlowQuery(query = {}) {
11924
+ return {
11925
+ query: query.query?.trim().toLowerCase() ?? "",
11926
+ tagIds: [...new Set(query.tagIds ?? [])].toSorted(),
11927
+ untagged: query.untagged ?? false
11928
+ };
11929
+ }
11930
+ function decodeTag(value) {
11931
+ const source = record(value);
11932
+ if (source.version != 1) return invalidResponse();
11933
+ return {
11934
+ tagId: string(source.tagId),
11935
+ name: string(source.name),
11936
+ version: 1
11937
+ };
11938
+ }
11939
+ function decodeTagListItem(value) {
11940
+ const source = record(value);
11941
+ const referenceCount = integer(source.referenceCount);
11942
+ if (referenceCount < 0) return invalidResponse();
11943
+ return {
11944
+ ...decodeTag(source),
11945
+ referenceCount
11946
+ };
11947
+ }
11948
+ //#endregion
11867
11949
  //#region src/control/common/api.ts
11868
11950
  function decodeRunEvent(value) {
11869
11951
  const source = record(value);
@@ -11967,7 +12049,7 @@ function decodeRunEvent(value) {
11967
12049
  switch (kind) {
11968
12050
  case "node.started": {
11969
12051
  const nodeKind = payload.nodeKind;
11970
- if (nodeKind !== void 0 && nodeKind !== "approval" && nodeKind !== "condition" && nodeKind !== "connector" && nodeKind !== "javascript" && nodeKind !== "decision" && nodeKind !== "openapi" && nodeKind !== "http-request" && nodeKind !== "llm" && nodeKind !== "agent" && nodeKind !== "value" && nodeKind !== "outputs" && nodeKind !== "webhook-response" && nodeKind !== "workflow" && nodeKind !== "wait") return invalidResponse();
12052
+ if (nodeKind !== void 0 && nodeKind !== "approval" && nodeKind !== "condition" && nodeKind !== "connector" && nodeKind !== "javascript" && nodeKind !== "decision" && nodeKind !== "openapi" && nodeKind !== "http-request" && nodeKind !== "skip-duplicates" && nodeKind !== "llm" && nodeKind !== "agent" && nodeKind !== "value" && nodeKind !== "outputs" && nodeKind !== "webhook-response" && nodeKind !== "workflow" && nodeKind !== "wait") return invalidResponse();
11971
12053
  return {
11972
12054
  ...base,
11973
12055
  kind,
@@ -12094,6 +12176,10 @@ var ControlClient = class {
12094
12176
  }
12095
12177
  async listFlows(options = {}) {
12096
12178
  const parameters = new URLSearchParams();
12179
+ const filter = normalizeFlowQuery(options);
12180
+ if (filter.query) parameters.set("query", filter.query);
12181
+ if (filter.tagIds.length) parameters.set("tagIds", filter.tagIds.join(","));
12182
+ if (filter.untagged) parameters.set("untagged", "true");
12097
12183
  if (options.cursor != null) parameters.set("cursor", options.cursor);
12098
12184
  if (options.limit != null) parameters.set("limit", String(options.limit));
12099
12185
  if (options.includeTotal != null) parameters.set("includeTotal", String(options.includeTotal));
@@ -12183,15 +12269,18 @@ var ControlClient = class {
12183
12269
  file,
12184
12270
  name: options.name,
12185
12271
  teamId: options.teamId,
12272
+ tagIds: options.tagIds,
12186
12273
  version: 1
12187
12274
  })
12188
12275
  }));
12189
12276
  }
12190
- async createFlow(name, idempotencyKey = `flow-${randomId()}`, teamId) {
12277
+ async createFlow(name, idempotencyKey = `flow-${randomId()}`, teamId, tagIds, initialPresentation) {
12191
12278
  return flow$1(await this.request("/v1/flows", {
12192
12279
  body: JSON.stringify({
12193
12280
  name,
12194
12281
  ...teamId == null ? {} : { teamId },
12282
+ ...tagIds == null ? {} : { tagIds },
12283
+ ...initialPresentation == null ? {} : { presentation: initialPresentation },
12195
12284
  version: 1
12196
12285
  }),
12197
12286
  headers: { "idempotency-key": idempotencyKey },
@@ -12226,15 +12315,68 @@ var ControlClient = class {
12226
12315
  if (source.version != 1 || !Array.isArray(source.listeners)) return invalidResponse();
12227
12316
  return source.listeners.map(errorListener);
12228
12317
  }
12229
- async renameFlow(flowId, name) {
12230
- return flow$1(await this.request(`/v1/flows/${segment(flowId)}`, {
12318
+ async listTags(signal) {
12319
+ const source = record(await this.request("/v1/tags", { signal }));
12320
+ if (source.version != 1 || !Array.isArray(source.tags)) return invalidResponse();
12321
+ return {
12322
+ tags: source.tags.map(decodeTagListItem),
12323
+ version: 1
12324
+ };
12325
+ }
12326
+ async createTag(name) {
12327
+ return decodeTag(await this.request("/v1/tags", {
12328
+ method: "POST",
12231
12329
  body: JSON.stringify({
12232
12330
  name,
12233
12331
  version: 1
12234
- }),
12235
- method: "PATCH"
12332
+ })
12333
+ }));
12334
+ }
12335
+ async renameTag(tagId, name) {
12336
+ return decodeTag(await this.request(`/v1/tags/${segment(tagId)}`, {
12337
+ method: "PATCH",
12338
+ body: JSON.stringify({
12339
+ name,
12340
+ version: 1
12341
+ })
12342
+ }));
12343
+ }
12344
+ async deleteTag(tagId) {
12345
+ if (record(await this.request(`/v1/tags/${segment(tagId)}`, { method: "DELETE" })).version != 1) invalidResponse();
12346
+ }
12347
+ async setFlowTags(flowId, tagIds) {
12348
+ return flow$1(await this.request(`/v1/flows/${segment(flowId)}/tags`, {
12349
+ method: "PUT",
12350
+ body: JSON.stringify({
12351
+ tagIds,
12352
+ version: 1
12353
+ })
12236
12354
  }));
12237
12355
  }
12356
+ async updateFlow(flowId, changes) {
12357
+ return flow$1(await this.request(`/v1/flows/${segment(flowId)}`, {
12358
+ method: "PATCH",
12359
+ body: JSON.stringify({
12360
+ ...changes,
12361
+ version: 1
12362
+ })
12363
+ }));
12364
+ }
12365
+ async getFlowState(flowId, scope, values = false) {
12366
+ const result = flowStateViewSchema.safeParse(await this.request(`/v1/flows/${segment(flowId)}/state?scope=${scope}&values=${values}`));
12367
+ return result.success && result.data.scope === scope ? result.data : invalidResponse();
12368
+ }
12369
+ async clearFlowState(flowId, scope, key) {
12370
+ const source = record(await this.request(`/v1/flows/${segment(flowId)}/state?scope=${scope}${key == null ? "" : `&key=${encodeURIComponent(key)}`}`, { method: "DELETE" }));
12371
+ if (source.version !== 1 || source.cleared !== true) invalidResponse();
12372
+ }
12373
+ async clearFlowDedupe(flowId, scope, space) {
12374
+ const source = record(await this.request(`/v1/flows/${segment(flowId)}/dedupe?scope=${scope}&space=${encodeURIComponent(space)}`, { method: "DELETE" }));
12375
+ if (source.version !== 1 || source.cleared !== true) invalidResponse();
12376
+ }
12377
+ async renameFlow(flowId, name) {
12378
+ return this.updateFlow(flowId, { name });
12379
+ }
12238
12380
  async deleteFlow(flowId) {
12239
12381
  return flow$1(await this.request(`/v1/flows/${segment(flowId)}`, { method: "DELETE" }));
12240
12382
  }
@@ -12986,6 +13128,9 @@ function tool(description, schema, readOnly, idempotent = true) {
12986
13128
  };
12987
13129
  }
12988
13130
  var mcpTools = {
13131
+ flow_state: tool("Inspect Flow state usage, business keys and deduplication spaces. Values are omitted unless requested. Scope is required.", stateQuerySchema.extend({ flowId: flow }), true),
13132
+ flow_state_clear: tool("Delete one business state key or clear all business values. Explicit draft/live scope is required; live changes production state immediately.", stateClearSchema.extend({ flowId: flow }), false),
13133
+ flow_dedupe_clear: tool("Clear one deduplication space (flow or node:<id>). Explicit draft/live scope is required; live changes production history immediately.", dedupeClearSchema.extend({ flowId: flow }), false),
12989
13134
  flow_canvas: tool("Broadcast a transient canvas command to connected Workbenches viewing this Flow. Success only confirms Server broadcast, not delivery or execution. No replay, session selection or Presentation save. Pan uses screen pixels (positive right/down); zoom is an absolute ratio (0.1–3); fit includes all nodes. Repeating pan moves again.", strictObject({
12990
13135
  flowId: flow,
12991
13136
  command: canvasCommandSchema
@@ -54,6 +54,7 @@ var nodeKinds = /* @__PURE__ */ new Set([
54
54
  "javascript",
55
55
  "openapi",
56
56
  "http-request",
57
+ "skip-duplicates",
57
58
  "llm",
58
59
  "value",
59
60
  "wait",
@@ -80,12 +81,12 @@ function nodeKind(value) {
80
81
  function runId(event) {
81
82
  return string(event.runId, "Runtime event runId");
82
83
  }
83
- function nodeContext(event, flows, platformRunId) {
84
+ function nodeContext(event, flows, platformRunId, identify) {
84
85
  const rawRunId = runId(event);
85
86
  const flowId = flows.get(rawRunId);
86
87
  if (flowId == null) throw new TypeError("Runtime node event preceded its run.started event.");
87
88
  return {
88
- executionId: projectExecutionId(platformRunId, rawRunId, string(event.jobId, "Runtime node event jobId")),
89
+ executionId: identify("execution", platformRunId, rawRunId, string(event.jobId, "Runtime node event jobId")),
89
90
  flowId,
90
91
  nodeId: string(event.nodeId, "Runtime node event nodeId"),
91
92
  rawRunId
@@ -138,6 +139,16 @@ function createEventProjector(platformRunId, nodeFailureCodes) {
138
139
  const jobs = /* @__PURE__ */ new Map();
139
140
  const nodeProgressBuckets = /* @__PURE__ */ new Map();
140
141
  const runProgressBuckets = /* @__PURE__ */ new Map();
142
+ const identities = /* @__PURE__ */ new Map();
143
+ const identify = (prefix, ...parts) => {
144
+ const key = JSON.stringify([prefix, ...parts]);
145
+ let identity = identities.get(key);
146
+ if (identity == null) {
147
+ identity = opaqueId(prefix, ...parts);
148
+ identities.set(key, identity);
149
+ }
150
+ return identity;
151
+ };
141
152
  return async (value) => {
142
153
  const event = object(value, "Runtime event");
143
154
  const type = string(event.type, "Runtime event type");
@@ -156,8 +167,8 @@ function createEventProjector(platformRunId, nodeFailureCodes) {
156
167
  kind: "run.started",
157
168
  payload: {
158
169
  flowId,
159
- ...parentRunId === void 0 ? {} : { parentScopeId: await opaqueId("scope", platformRunId, parentRunId) },
160
- scopeId: await opaqueId("scope", platformRunId, rawRunId)
170
+ ...parentRunId === void 0 ? {} : { parentScopeId: await identify("scope", platformRunId, parentRunId) },
171
+ scopeId: await identify("scope", platformRunId, rawRunId)
161
172
  }
162
173
  };
163
174
  }
@@ -174,7 +185,7 @@ function createEventProjector(platformRunId, nodeFailureCodes) {
174
185
  payload: {
175
186
  flowId,
176
187
  progress: event.progress,
177
- scopeId: await opaqueId("scope", platformRunId, rawRunId)
188
+ scopeId: await identify("scope", platformRunId, rawRunId)
178
189
  }
179
190
  };
180
191
  }
@@ -182,7 +193,7 @@ function createEventProjector(platformRunId, nodeFailureCodes) {
182
193
  const rawRunId = runId(event);
183
194
  if (type == "run.failed" && rawRunId == platformRunId && event.failure != null) {
184
195
  const failure = object(event.failure, "Runtime terminal failure");
185
- const context = nodeContext(failure, flows, platformRunId);
196
+ const context = nodeContext(failure, flows, platformRunId, identify);
186
197
  return {
187
198
  kind: "node.failed",
188
199
  payload: {
@@ -200,13 +211,13 @@ function createEventProjector(platformRunId, nodeFailureCodes) {
200
211
  return;
201
212
  }
202
213
  if (type == "node.started" || type == "node.progress" || type == "node.artifact" || type == "node.log" || type == "node.completed" || type == "node.failed") {
203
- const context = nodeContext(event, flows, platformRunId);
214
+ const context = nodeContext(event, flows, platformRunId, identify);
204
215
  const executionId = await context.executionId;
205
216
  const payload = {
206
217
  executionId,
207
218
  flowId: context.flowId,
208
219
  nodeId: context.nodeId,
209
- scopeId: await opaqueId("scope", platformRunId, context.rawRunId),
220
+ scopeId: await identify("scope", platformRunId, context.rawRunId),
210
221
  ...event.systemOutputs === void 0 ? {} : { systemOutputs: object(event.systemOutputs, "Runtime system outputs") },
211
222
  ...event.handled === true ? { handled: true } : {}
212
223
  };
@@ -1,5 +1,19 @@
1
1
  import type { CodeModule, ConnectorCapability, TaskCapability, JsonValue } from './flow-model.js';
2
2
  export { currentEngineContract, nodejsEngineContract, findEngineContract, type EngineContract } from './engine-contract.js';
3
+ /** Serialized into the guest; keep validation and helpers self-contained. */
4
+ export declare function createState(invoke: (kind: string, payload: JsonValue) => Promise<RuntimeCapabilityResponse>): {
5
+ state: Readonly<{
6
+ get(key: unknown): Promise<JsonValue>;
7
+ set(key: unknown, value: unknown): Promise<void>;
8
+ insert(key: unknown, value: unknown): Promise<boolean>;
9
+ delete(key: unknown): Promise<void>;
10
+ list(): Promise<string[]>;
11
+ }>;
12
+ dedupe: Readonly<{
13
+ insert(ids: unknown): Promise<boolean[]>;
14
+ has(ids: unknown): Promise<boolean[]>;
15
+ }>;
16
+ };
3
17
  export type RuntimeModule = Pick<CodeModule, 'imports' | 'source'>;
4
18
  /** Snapshot a Task result before JSON transport can discard or coerce invalid values. */
5
19
  export declare function snapshotRuntimeResult(value: unknown): JsonValue | undefined;