@bian-womp/spark-workbench 0.2.94 → 0.3.1

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 (55) hide show
  1. package/lib/cjs/index.cjs +204 -240
  2. package/lib/cjs/index.cjs.map +1 -1
  3. package/lib/cjs/src/examples/reactflow/App.d.ts.map +1 -1
  4. package/lib/cjs/src/index.d.ts +1 -0
  5. package/lib/cjs/src/index.d.ts.map +1 -1
  6. package/lib/cjs/src/misc/DefaultNodeHeader.d.ts +1 -2
  7. package/lib/cjs/src/misc/DefaultNodeHeader.d.ts.map +1 -1
  8. package/lib/cjs/src/misc/WorkbenchCanvas.d.ts.map +1 -1
  9. package/lib/cjs/src/misc/WorkbenchStudio.d.ts +1 -3
  10. package/lib/cjs/src/misc/WorkbenchStudio.d.ts.map +1 -1
  11. package/lib/cjs/src/misc/context/WorkbenchContext.d.ts +8 -6
  12. package/lib/cjs/src/misc/context/WorkbenchContext.d.ts.map +1 -1
  13. package/lib/cjs/src/misc/context/WorkbenchContext.provider.d.ts.map +1 -1
  14. package/lib/cjs/src/misc/context-menu/ContextMenuHandlers.d.ts +6 -2
  15. package/lib/cjs/src/misc/context-menu/ContextMenuHandlers.d.ts.map +1 -1
  16. package/lib/cjs/src/misc/context-menu/ContextMenuHelpers.d.ts +1 -1
  17. package/lib/cjs/src/misc/context-menu/ContextMenuHelpers.d.ts.map +1 -1
  18. package/lib/cjs/src/misc/context-menu/NodeContextMenu.d.ts +1 -1
  19. package/lib/cjs/src/misc/context-menu/NodeContextMenu.d.ts.map +1 -1
  20. package/lib/cjs/src/runtime/AbstractGraphRunner.d.ts +9 -7
  21. package/lib/cjs/src/runtime/AbstractGraphRunner.d.ts.map +1 -1
  22. package/lib/cjs/src/runtime/IGraphRunner.d.ts +18 -7
  23. package/lib/cjs/src/runtime/IGraphRunner.d.ts.map +1 -1
  24. package/lib/cjs/src/runtime/LocalGraphRunner.d.ts +7 -4
  25. package/lib/cjs/src/runtime/LocalGraphRunner.d.ts.map +1 -1
  26. package/lib/cjs/src/runtime/RemoteGraphRunner.d.ts +11 -9
  27. package/lib/cjs/src/runtime/RemoteGraphRunner.d.ts.map +1 -1
  28. package/lib/esm/index.js +207 -243
  29. package/lib/esm/index.js.map +1 -1
  30. package/lib/esm/src/examples/reactflow/App.d.ts.map +1 -1
  31. package/lib/esm/src/index.d.ts +1 -0
  32. package/lib/esm/src/index.d.ts.map +1 -1
  33. package/lib/esm/src/misc/DefaultNodeHeader.d.ts +1 -2
  34. package/lib/esm/src/misc/DefaultNodeHeader.d.ts.map +1 -1
  35. package/lib/esm/src/misc/WorkbenchCanvas.d.ts.map +1 -1
  36. package/lib/esm/src/misc/WorkbenchStudio.d.ts +1 -3
  37. package/lib/esm/src/misc/WorkbenchStudio.d.ts.map +1 -1
  38. package/lib/esm/src/misc/context/WorkbenchContext.d.ts +8 -6
  39. package/lib/esm/src/misc/context/WorkbenchContext.d.ts.map +1 -1
  40. package/lib/esm/src/misc/context/WorkbenchContext.provider.d.ts.map +1 -1
  41. package/lib/esm/src/misc/context-menu/ContextMenuHandlers.d.ts +6 -2
  42. package/lib/esm/src/misc/context-menu/ContextMenuHandlers.d.ts.map +1 -1
  43. package/lib/esm/src/misc/context-menu/ContextMenuHelpers.d.ts +1 -1
  44. package/lib/esm/src/misc/context-menu/ContextMenuHelpers.d.ts.map +1 -1
  45. package/lib/esm/src/misc/context-menu/NodeContextMenu.d.ts +1 -1
  46. package/lib/esm/src/misc/context-menu/NodeContextMenu.d.ts.map +1 -1
  47. package/lib/esm/src/runtime/AbstractGraphRunner.d.ts +9 -7
  48. package/lib/esm/src/runtime/AbstractGraphRunner.d.ts.map +1 -1
  49. package/lib/esm/src/runtime/IGraphRunner.d.ts +18 -7
  50. package/lib/esm/src/runtime/IGraphRunner.d.ts.map +1 -1
  51. package/lib/esm/src/runtime/LocalGraphRunner.d.ts +7 -4
  52. package/lib/esm/src/runtime/LocalGraphRunner.d.ts.map +1 -1
  53. package/lib/esm/src/runtime/RemoteGraphRunner.d.ts +11 -9
  54. package/lib/esm/src/runtime/RemoteGraphRunner.d.ts.map +1 -1
  55. package/package.json +4 -4
package/lib/cjs/index.cjs CHANGED
@@ -927,31 +927,21 @@ class AbstractGraphRunner {
927
927
  this.engine.dispose();
928
928
  this.engine = undefined;
929
929
  // Emit status but keep runtime alive
930
- if (this.runningKind) {
931
- this.runningKind = undefined;
932
- this.emit("status", { running: false, engine: undefined });
933
- }
934
- }
935
- async switchEngine(opts) {
936
- if (!this.engine || !this.runtime) {
937
- throw new Error("No engine running to switch from");
938
- }
939
- // Wait for current engine to be idle
940
- await this.whenIdle();
941
- // Capture current state
942
- const currentInputs = { ...this.stagedInputs };
943
- // Stop current engine
944
- this.stop();
945
- // Ensure runtime is in a clean state (resumed)
946
- this.runtime.resume();
947
- // Create and launch new engine (to be implemented by subclasses)
948
- await this.createAndLaunchEngine(opts);
949
- // Re-apply staged inputs to new engine using runner's setInputs method
950
- // This ensures consistency and proper handling of staged inputs
951
- for (const [nodeId, map] of Object.entries(currentInputs)) {
952
- await this.setInputs(nodeId, map);
930
+ if (this.runMode) {
931
+ this.runMode = undefined;
932
+ this.emit("status", { running: false, runMode: undefined });
953
933
  }
954
934
  }
935
+ setRunMode(runMode) {
936
+ if (!this.engine) {
937
+ throw new Error("Cannot set run mode: engine not running");
938
+ }
939
+ // Update engine run mode (this will update pause/resume state)
940
+ this.engine.setRunMode(runMode);
941
+ // Update local state and emit status event
942
+ this.runMode = runMode;
943
+ this.emit("status", { running: true, runMode: this.runMode });
944
+ }
955
945
  getInputDefaults(def) {
956
946
  const out = {};
957
947
  for (const n of def.nodes) {
@@ -980,16 +970,16 @@ class AbstractGraphRunner {
980
970
  this.engine = undefined;
981
971
  this.runtime?.dispose();
982
972
  this.runtime = undefined;
983
- if (this.runningKind) {
984
- this.runningKind = undefined;
985
- this.emit("status", { running: false, engine: undefined });
973
+ if (this.runMode) {
974
+ this.runMode = undefined;
975
+ this.emit("status", { running: false, runMode: undefined });
986
976
  }
987
977
  }
988
978
  isRunning() {
989
979
  return !!this.engine;
990
980
  }
991
- getRunningEngine() {
992
- return this.runningKind;
981
+ getRunMode() {
982
+ return this.runMode;
993
983
  }
994
984
  // Optional undo/redo support
995
985
  async undo() {
@@ -1084,7 +1074,7 @@ class LocalGraphRunner extends AbstractGraphRunner {
1084
1074
  if (!this.runtime)
1085
1075
  throw new Error("Runtime not built");
1086
1076
  // Use shared engine factory
1087
- this.engine = sparkGraph.createEngine(this.runtime, opts);
1077
+ this.engine = new sparkGraph.UnifiedEngine(this.runtime, opts?.runMode);
1088
1078
  if (!this.engine)
1089
1079
  throw new Error("Failed to create engine");
1090
1080
  this.engine.on("value", (e) => this.emit("value", e));
@@ -1092,36 +1082,34 @@ class LocalGraphRunner extends AbstractGraphRunner {
1092
1082
  this.engine.on("invalidate", (e) => this.emit("invalidate", e));
1093
1083
  this.engine.on("stats", (e) => this.emit("stats", e));
1094
1084
  this.engine.launch(opts?.invalidate);
1095
- this.runningKind = opts?.engine ?? "push";
1096
- this.emit("status", { running: true, engine: this.runningKind });
1085
+ this.runMode = opts?.runMode ?? "manual";
1086
+ this.emit("status", { running: true, runMode: this.runMode });
1097
1087
  for (const [nodeId, map] of Object.entries(this.stagedInputs)) {
1098
1088
  this.engine.setInputs(nodeId, map);
1099
1089
  }
1100
1090
  }
1101
- async step() {
1102
- const eng = this.engine;
1103
- if (eng && eng instanceof sparkGraph.StepEngine)
1104
- await eng.step();
1091
+ async computeNode(nodeId, options) {
1092
+ if (this.engine)
1093
+ await this.engine.computeNode(nodeId, options);
1105
1094
  }
1106
- async computeNode(nodeId) {
1107
- const eng = this.engine;
1108
- if (eng && eng instanceof sparkGraph.PullEngine)
1109
- await eng.computeNode(nodeId);
1095
+ async runFromHere(nodeId) {
1096
+ if (this.engine)
1097
+ await this.engine.runFromHere(nodeId);
1110
1098
  }
1111
- async flush() {
1112
- const eng = this.engine;
1113
- if (eng && eng instanceof sparkGraph.BatchedEngine)
1114
- await eng.flush();
1099
+ cancelNodeRuns(nodeIds) {
1100
+ if (this.engine) {
1101
+ this.engine.cancelNodeRuns(nodeIds);
1102
+ }
1115
1103
  }
1116
1104
  getOutputs(def) {
1117
1105
  const out = {};
1118
- if (!this.runtime)
1106
+ if (!this.engine)
1119
1107
  return out;
1120
1108
  for (const n of def.nodes) {
1121
1109
  const desc = this.registry.nodes.get(n.typeId);
1122
1110
  const handles = Object.keys(desc?.outputs ?? {});
1123
1111
  for (const h of handles) {
1124
- const v = this.runtime.getOutput(n.nodeId, h);
1112
+ const v = this.engine.getOutput(n.nodeId, h);
1125
1113
  if (v !== undefined) {
1126
1114
  if (!out[n.nodeId])
1127
1115
  out[n.nodeId] = {};
@@ -1154,19 +1142,8 @@ class LocalGraphRunner extends AbstractGraphRunner {
1154
1142
  return out;
1155
1143
  }
1156
1144
  triggerExternal(nodeId, event, options) {
1157
- // Handle dry option: pause runtime before triggering, resume after
1158
- const wasPaused = this.runtime?.isPaused() ?? false;
1159
- if (options?.dry && !wasPaused && this.runtime) {
1160
- this.runtime.pause();
1161
- }
1162
- try {
1163
- this.engine?.triggerExternal(nodeId, event);
1164
- }
1165
- finally {
1166
- if (options?.dry && !wasPaused && this.runtime) {
1167
- this.runtime.resume();
1168
- }
1169
- }
1145
+ // Engine handles dry option via AbstractEngine
1146
+ this.engine?.triggerExternal(nodeId, event, options);
1170
1147
  }
1171
1148
  // Batch update multiple inputs on a node and trigger a single run
1172
1149
  setInputs(nodeId, inputs, options) {
@@ -1182,40 +1159,23 @@ class LocalGraphRunner extends AbstractGraphRunner {
1182
1159
  this.stagedInputs[nodeId][handle] = value;
1183
1160
  }
1184
1161
  }
1185
- // Handle dry option: pause runtime before setting inputs, resume after
1186
- const wasPaused = this.runtime?.isPaused() ?? false;
1187
- if (options?.dry && !wasPaused && this.runtime) {
1188
- this.runtime.pause();
1189
- }
1190
- try {
1191
- if (this.engine) {
1192
- this.engine.setInputs(nodeId, inputs);
1193
- }
1194
- else {
1195
- // Not running: emit a single synthetic value event per handle; UI will coalesce
1196
- console.warn("Engine does not exists");
1197
- for (const [handle, value] of Object.entries(inputs)) {
1198
- this.emit("value", { nodeId, handle, value, io: "input" });
1199
- }
1200
- }
1162
+ if (this.engine) {
1163
+ // Engine handles dry option via AbstractEngine
1164
+ this.engine.setInputs(nodeId, inputs, options);
1201
1165
  }
1202
- finally {
1203
- if (options?.dry && !wasPaused && this.runtime) {
1204
- this.runtime.resume();
1166
+ else {
1167
+ // Not running: emit a single synthetic value event per handle; UI will coalesce
1168
+ // Note: dry option doesn't apply when engine doesn't exist (no execution to prevent)
1169
+ console.warn("Engine does not exists");
1170
+ for (const [handle, value] of Object.entries(inputs)) {
1171
+ this.emit("value", { nodeId, handle, value, io: "input" });
1205
1172
  }
1206
1173
  }
1207
1174
  }
1208
1175
  copyOutputs(fromNodeId, toNodeId, options) {
1209
- if (!this.runtime)
1210
- return;
1211
- // Get outputs from source node
1212
- const fromNode = this.runtime.getNodeData(fromNodeId);
1213
- if (!fromNode?.outputs)
1214
- return;
1215
- // Copy outputs to target node using hydrate
1216
- // hydrate already pauses internally, so we don't need to handle dry option here
1217
- // reemit: !options?.dry means don't propagate downstream if dry mode
1218
- this.runtime.hydrate({ outputs: { [toNodeId]: { ...fromNode.outputs } } }, { reemit: !options?.dry });
1176
+ if (this.engine) {
1177
+ this.engine.copyOutputs(fromNodeId, toNodeId, options);
1178
+ }
1219
1179
  }
1220
1180
  async snapshotFull() {
1221
1181
  const def = undefined; // UI will supply def/positions on download for local
@@ -1316,7 +1276,7 @@ class RemoteGraphRunner extends AbstractGraphRunner {
1316
1276
  }
1317
1277
  this.registryFetching = true;
1318
1278
  try {
1319
- const desc = await client.describeRegistry();
1279
+ const desc = await client.api.describeRegistry();
1320
1280
  // Register types
1321
1281
  for (const t of desc.types) {
1322
1282
  if (t.options) {
@@ -1418,7 +1378,7 @@ class RemoteGraphRunner extends AbstractGraphRunner {
1418
1378
  }
1419
1379
  }
1420
1380
  /**
1421
- * Build RuntimeApiClient config from RemoteExecutionBackend config.
1381
+ * Build RemoteRuntimeClient config from RemoteExecutionBackend config.
1422
1382
  */
1423
1383
  buildClientConfig(backend) {
1424
1384
  if (backend.kind === "remote-http") {
@@ -1441,7 +1401,7 @@ class RemoteGraphRunner extends AbstractGraphRunner {
1441
1401
  */
1442
1402
  setupClientSubscriptions(client) {
1443
1403
  // Subscribe to transport status changes
1444
- // Convert RuntimeApiClient.TransportStatus to IGraphRunner.TransportStatus
1404
+ // Convert RemoteRuntimeClient.TransportStatus to IGraphRunner.TransportStatus
1445
1405
  // Only emit status if it matches this runner's ID
1446
1406
  this.transportStatusUnsubscribe = client.onTransportStatus((status) => {
1447
1407
  if (status.runnerId && status.runnerId !== this.runnerId)
@@ -1491,7 +1451,7 @@ class RemoteGraphRunner extends AbstractGraphRunner {
1491
1451
  }
1492
1452
  };
1493
1453
  // Create client with wrapped custom event handler
1494
- const client = new sparkRemote.RuntimeApiClient(clientConfig, {
1454
+ const client = new sparkRemote.RemoteRuntimeClient(clientConfig, {
1495
1455
  onCustomEvent: wrappedOnCustomEvent,
1496
1456
  runnerId: this.runnerId,
1497
1457
  });
@@ -1541,7 +1501,7 @@ class RemoteGraphRunner extends AbstractGraphRunner {
1541
1501
  // Auto-handle registry-changed invalidations from remote
1542
1502
  // We listen on invalidate and if reason matches, we rehydrate registry and emit a registry event
1543
1503
  this.ensureClient().then(async (client) => {
1544
- const eng = client.getEngine();
1504
+ const eng = client.engine;
1545
1505
  if (!this.listenersBound) {
1546
1506
  eng.on("invalidate", async (e) => {
1547
1507
  if (e.reason === "registry-changed") {
@@ -1605,7 +1565,7 @@ class RemoteGraphRunner extends AbstractGraphRunner {
1605
1565
  // Remote: forward update and await completion
1606
1566
  const client = await this.ensureClient();
1607
1567
  try {
1608
- await client.update(def, options);
1568
+ await client.api.update(def, options);
1609
1569
  this.emit("invalidate", { reason: "graph-updated" });
1610
1570
  this.lastDef = def;
1611
1571
  }
@@ -1618,13 +1578,13 @@ class RemoteGraphRunner extends AbstractGraphRunner {
1618
1578
  super.launch(def, opts);
1619
1579
  // Remote: build remotely then launch
1620
1580
  this.ensureClient().then(async (client) => {
1621
- await client.build(def);
1581
+ await client.api.build(def);
1622
1582
  // Signal UI after remote build as well
1623
1583
  this.emit("invalidate", { reason: "graph-built" });
1624
1584
  this.lastDef = def;
1625
1585
  // Hydrate current remote inputs/outputs (including defaults) into cache
1626
1586
  try {
1627
- const snap = await client.snapshot();
1587
+ const snap = await client.api.snapshot();
1628
1588
  for (const [nodeId, map] of Object.entries(snap.inputs || {})) {
1629
1589
  for (const [handle, value] of Object.entries(map || {})) {
1630
1590
  this.valueCache.set(`${nodeId}.${handle}`, {
@@ -1653,9 +1613,9 @@ class RemoteGraphRunner extends AbstractGraphRunner {
1653
1613
  async createAndLaunchEngine(opts) {
1654
1614
  const client = await this.ensureClient();
1655
1615
  // Configure and launch engine on the backend
1656
- await client.launch(opts);
1616
+ await client.api.launch(opts);
1657
1617
  // Get the remote engine proxy and wire up event listeners
1658
- const eng = client.getEngine();
1618
+ const eng = client.engine;
1659
1619
  if (!this.listenersBound) {
1660
1620
  eng.on("value", (e) => {
1661
1621
  this.valueCache.set(`${e.nodeId}.${e.handle}`, {
@@ -1671,11 +1631,11 @@ class RemoteGraphRunner extends AbstractGraphRunner {
1671
1631
  this.listenersBound = true;
1672
1632
  }
1673
1633
  this.engine = eng;
1674
- this.runningKind = opts?.engine ?? "push";
1675
- this.emit("status", { running: true, engine: this.runningKind });
1634
+ this.runMode = opts?.runMode ?? "manual";
1635
+ this.emit("status", { running: true, runMode: this.runMode });
1676
1636
  // Re-apply staged inputs using client.setInputs for consistency
1677
1637
  for (const [nodeId, map] of Object.entries(this.stagedInputs)) {
1678
- await eng.setInputs(nodeId, map).catch(() => {
1638
+ await eng.setInputs(nodeId, map, undefined).catch(() => {
1679
1639
  // Ignore errors during launch - inputs will be set when user calls setInputs
1680
1640
  });
1681
1641
  }
@@ -1698,45 +1658,27 @@ class RemoteGraphRunner extends AbstractGraphRunner {
1698
1658
  await this.createAndLaunchEngine(opts);
1699
1659
  });
1700
1660
  }
1701
- async switchEngine(opts) {
1661
+ setRunMode(runMode) {
1702
1662
  if (!this.engine) {
1703
- throw new Error("No engine running to switch from");
1704
- }
1705
- // Wait for current engine to be idle
1706
- await this.whenIdle();
1707
- // Capture current state
1708
- const currentInputs = { ...this.stagedInputs };
1709
- // For remote runners, we cannot call this.stop() because it sends a Dispose
1710
- // command that destroys the graphRuntime on the backend. Instead, we rely on
1711
- // the backend's launch() method to dispose the old engine and create a new one.
1712
- // Reconfigure engine on the backend (this will dispose old engine and create new one)
1713
- const client = await this.ensureClient();
1714
- await client.launch(opts);
1715
- // Get the remote engine proxy (should be the same RemoteEngine instance)
1716
- const eng = client.getEngine();
1717
- // Update local state to reflect new engine kind
1718
- // Note: The RemoteEngine instance itself doesn't change, but the backend engine does
1719
- this.engine = eng;
1720
- this.runningKind = opts?.engine ?? "push";
1721
- this.emit("status", { running: true, engine: this.runningKind });
1722
- // Re-apply staged inputs using client.setInputs for consistency
1723
- for (const [nodeId, map] of Object.entries(currentInputs)) {
1724
- await eng.setInputs(nodeId, map).catch(() => {
1725
- // Ignore errors during engine switch - inputs will be set when user calls setInputs
1726
- });
1663
+ throw new Error("Cannot set run mode: engine not running");
1727
1664
  }
1665
+ // Update engine run mode (sends SetRunMode command to backend)
1666
+ this.engine.setRunMode(runMode);
1667
+ // Update local state and emit status event
1668
+ this.runMode = runMode;
1669
+ this.emit("status", { running: true, runMode: this.runMode });
1728
1670
  }
1729
- async step() {
1671
+ async computeNode(nodeId, options) {
1730
1672
  const client = await this.ensureClient();
1731
- await client.step();
1673
+ await client.engine.computeNode(nodeId, options);
1732
1674
  }
1733
- async computeNode(nodeId) {
1675
+ async runFromHere(nodeId) {
1734
1676
  const client = await this.ensureClient();
1735
- await client.computeNode(nodeId);
1677
+ await client.engine.runFromHere(nodeId);
1736
1678
  }
1737
- async flush() {
1679
+ async cancelNodeRuns(nodeIds) {
1738
1680
  const client = await this.ensureClient();
1739
- await client.flush();
1681
+ await client.engine.cancelNodeRuns(nodeIds);
1740
1682
  }
1741
1683
  async setInputs(nodeId, inputs, options) {
1742
1684
  // Update staged inputs (for getInputs to work correctly)
@@ -1752,7 +1694,7 @@ class RemoteGraphRunner extends AbstractGraphRunner {
1752
1694
  }
1753
1695
  try {
1754
1696
  const client = await this.ensureClient();
1755
- await client.getEngine()?.setInputs(nodeId, inputs, options);
1697
+ await client.engine.setInputs(nodeId, inputs, options);
1756
1698
  }
1757
1699
  catch (err) {
1758
1700
  // Emit synthetic events if connection fails
@@ -1764,20 +1706,20 @@ class RemoteGraphRunner extends AbstractGraphRunner {
1764
1706
  }
1765
1707
  async copyOutputs(fromNodeId, toNodeId, options) {
1766
1708
  const client = await this.ensureClient();
1767
- await client.getEngine()?.copyOutputs(fromNodeId, toNodeId, options);
1709
+ await client.engine.copyOutputs(fromNodeId, toNodeId, options);
1768
1710
  }
1769
1711
  async triggerExternal(nodeId, event, options) {
1770
1712
  const client = await this.ensureClient();
1771
- await client.getEngine()?.triggerExternal(nodeId, event, options);
1713
+ await client.engine.triggerExternal(nodeId, event, options);
1772
1714
  }
1773
1715
  async setViewport(viewport) {
1774
1716
  const client = await this.ensureClient();
1775
- await client.setViewport(viewport);
1717
+ await client.api.setViewport(viewport);
1776
1718
  }
1777
1719
  async coerce(from, to, value) {
1778
1720
  const client = await this.ensureClient();
1779
1721
  try {
1780
- return await client.coerce(from, to, value);
1722
+ return await client.api.coerce(from, to, value);
1781
1723
  }
1782
1724
  catch {
1783
1725
  return value;
@@ -1785,12 +1727,12 @@ class RemoteGraphRunner extends AbstractGraphRunner {
1785
1727
  }
1786
1728
  async setExtData(data) {
1787
1729
  const client = await this.ensureClient();
1788
- await client.setExtData(data);
1730
+ await client.api.setExtData(data);
1789
1731
  }
1790
1732
  async commit(reason) {
1791
1733
  const client = await this.ensureClient();
1792
1734
  try {
1793
- const history = await client.commit(reason);
1735
+ const history = await client.api.commit(reason);
1794
1736
  return history;
1795
1737
  }
1796
1738
  catch (err) {
@@ -1801,7 +1743,7 @@ class RemoteGraphRunner extends AbstractGraphRunner {
1801
1743
  async undo() {
1802
1744
  const client = await this.ensureClient();
1803
1745
  try {
1804
- return await client.undo();
1746
+ return await client.api.undo();
1805
1747
  }
1806
1748
  catch {
1807
1749
  return false;
@@ -1810,7 +1752,7 @@ class RemoteGraphRunner extends AbstractGraphRunner {
1810
1752
  async redo() {
1811
1753
  const client = await this.ensureClient();
1812
1754
  try {
1813
- return await client.redo();
1755
+ return await client.api.redo();
1814
1756
  }
1815
1757
  catch {
1816
1758
  return false;
@@ -1819,7 +1761,7 @@ class RemoteGraphRunner extends AbstractGraphRunner {
1819
1761
  async snapshotFull() {
1820
1762
  const client = await this.ensureClient();
1821
1763
  try {
1822
- return await client.snapshotFull();
1764
+ return await client.api.snapshotFull();
1823
1765
  }
1824
1766
  catch {
1825
1767
  return { def: undefined, environment: {}, inputs: {}, outputs: {} };
@@ -1830,7 +1772,9 @@ class RemoteGraphRunner extends AbstractGraphRunner {
1830
1772
  this.hydrateValueCache(payload, { dry: options?.dry });
1831
1773
  // Then sync with backend
1832
1774
  const client = await this.ensureClient();
1833
- await client.applySnapshotFull(payload, { skipBuild: options?.skipBuild });
1775
+ await client.api.applySnapshotFull(payload, {
1776
+ skipBuild: options?.skipBuild,
1777
+ });
1834
1778
  }
1835
1779
  /**
1836
1780
  * Hydrates the local valueCache from a snapshot and emits value events.
@@ -1874,12 +1818,12 @@ class RemoteGraphRunner extends AbstractGraphRunner {
1874
1818
  async setEnvironment(env, opts) {
1875
1819
  // Use client if available, otherwise ensure client and then set environment
1876
1820
  if (this.client) {
1877
- await this.client.setEnvironment(env, opts);
1821
+ await this.client.api.setEnvironment(env, opts);
1878
1822
  }
1879
1823
  else {
1880
1824
  try {
1881
1825
  const client = await this.ensureClient();
1882
- await client.setEnvironment(env, opts);
1826
+ await client.api.setEnvironment(env, opts);
1883
1827
  }
1884
1828
  catch {
1885
1829
  // Silently fail if connection not available
@@ -1887,7 +1831,7 @@ class RemoteGraphRunner extends AbstractGraphRunner {
1887
1831
  }
1888
1832
  }
1889
1833
  getEnvironment() {
1890
- // Interface requires sync return, but RuntimeApiClient.getEnvironment() is async.
1834
+ // Interface requires sync return, but RemoteRuntimeClient.getEnvironment() is async.
1891
1835
  // Returns undefined synchronously; callers needing the actual value should:
1892
1836
  // - Use snapshotFull() which includes environment
1893
1837
  // - Call client.getEnvironment() directly if they have access to the client
@@ -3657,6 +3601,7 @@ function computeInvalidatedFromMetadata(metadata) {
3657
3601
  function WorkbenchProvider({ wb, runner, overrides, uiVersion, children, }) {
3658
3602
  const [nodeStatus, setNodeStatus] = React.useState({});
3659
3603
  const [edgeStatus, setEdgeStatus] = React.useState({});
3604
+ const [runMode, setRunModeState] = React.useState("manual");
3660
3605
  const [events, setEvents] = React.useState([]);
3661
3606
  const clearEvents = React.useCallback(() => setEvents([]), []);
3662
3607
  const [systemErrors, setSystemErrors] = React.useState([]);
@@ -3721,6 +3666,24 @@ function WorkbenchProvider({ wb, runner, overrides, uiVersion, children, }) {
3721
3666
  const graphUiTick = useWorkbenchGraphUiTick(wb);
3722
3667
  const versionTick = useWorkbenchVersionTick(runner);
3723
3668
  const valuesTick = versionTick + graphTick + graphUiTick;
3669
+ // Keep local runMode state loosely in sync with runner status.
3670
+ // - Seed from runner.getRunMode() on mount if available.
3671
+ // - On status events, update only when a non-undefined runMode is reported,
3672
+ // so the UI preserves the last selected mode after stop().
3673
+ React.useEffect(() => {
3674
+ const initialMode = runner.getRunMode();
3675
+ if (initialMode) {
3676
+ setRunModeState(initialMode);
3677
+ }
3678
+ const offRunnerStatus = runner.on("status", (status) => {
3679
+ if (status.runMode) {
3680
+ setRunModeState(status.runMode);
3681
+ }
3682
+ });
3683
+ return () => {
3684
+ offRunnerStatus();
3685
+ };
3686
+ }, [runner]);
3724
3687
  // Def and IO values
3725
3688
  const inputsMap = React.useMemo(() => runner.getInputs(wb.def), [runner, wb, wb.def, valuesTick]);
3726
3689
  const inputDefaultsMap = React.useMemo(() => runner.getInputDefaults(wb.def), [runner, wb, wb.def, valuesTick]);
@@ -4414,16 +4377,37 @@ function WorkbenchProvider({ wb, runner, overrides, uiVersion, children, }) {
4414
4377
  };
4415
4378
  }, [runner, wb]);
4416
4379
  const isRunning = React.useCallback(() => runner.isRunning(), [runner]);
4417
- const engineKind = React.useCallback(() => runner.getRunningEngine(), [runner]);
4418
- const start = React.useCallback((engine) => {
4419
- try {
4420
- runner.launch(wb.def, { engine });
4421
- }
4422
- catch { }
4423
- }, [runner, wb]);
4380
+ const getRunMode = React.useCallback(() => runner.getRunMode(), [runner]);
4424
4381
  const stop = React.useCallback(() => runner.stop(), [runner]);
4425
- const step = React.useCallback(() => runner.step(), [runner]);
4426
- const flush = React.useCallback(() => runner.flush(), [runner]);
4382
+ // Run mode actions
4383
+ const setRunMode = React.useCallback((mode) => {
4384
+ if (mode === runMode)
4385
+ return;
4386
+ const wasRunning = runner.isRunning();
4387
+ if (wasRunning) {
4388
+ // Use setRunMode to change run mode without rebuilding
4389
+ try {
4390
+ runner.setRunMode(mode);
4391
+ setRunModeState(mode);
4392
+ }
4393
+ catch (err) {
4394
+ console.error("Failed to set run mode:", err);
4395
+ }
4396
+ }
4397
+ else {
4398
+ // Just update state if not running (will be applied on next launch)
4399
+ setRunModeState(mode);
4400
+ }
4401
+ }, [runMode, runner]);
4402
+ const runNodeAction = React.useCallback(async (nodeId) => {
4403
+ await runner.computeNode(nodeId);
4404
+ }, [runner]);
4405
+ const runFromHereAction = React.useCallback(async (nodeId) => {
4406
+ await runner.runFromHere(nodeId);
4407
+ }, [runner]);
4408
+ const abortNodeAction = React.useCallback((nodeId) => {
4409
+ runner.cancelNodeRuns([nodeId]);
4410
+ }, [runner]);
4427
4411
  const validationByNode = React.useMemo(() => {
4428
4412
  const inputs = {};
4429
4413
  const outputs = {};
@@ -4515,11 +4499,13 @@ function WorkbenchProvider({ wb, runner, overrides, uiVersion, children, }) {
4515
4499
  removeRegistryError,
4516
4500
  removeInputValidationError,
4517
4501
  isRunning,
4518
- engineKind,
4519
- start,
4502
+ getRunMode,
4520
4503
  stop,
4521
- step,
4522
- flush,
4504
+ runMode,
4505
+ setRunMode,
4506
+ runNode: runNodeAction,
4507
+ runFromHere: runFromHereAction,
4508
+ abortNode: abortNodeAction,
4523
4509
  runAutoLayout,
4524
4510
  updateEdgeType,
4525
4511
  triggerExternal,
@@ -4555,11 +4541,13 @@ function WorkbenchProvider({ wb, runner, overrides, uiVersion, children, }) {
4555
4541
  events,
4556
4542
  clearEvents,
4557
4543
  isRunning,
4558
- engineKind,
4559
- start,
4544
+ getRunMode,
4560
4545
  stop,
4561
- step,
4562
- flush,
4546
+ runMode,
4547
+ setRunMode,
4548
+ runNodeAction,
4549
+ runFromHereAction,
4550
+ abortNodeAction,
4563
4551
  runAutoLayout,
4564
4552
  wb,
4565
4553
  runner,
@@ -4577,7 +4565,7 @@ function IssueBadge({ level, title, size = 12, className, }) {
4577
4565
  return (jsxRuntime.jsx("button", { type: "button", className: `inline-flex items-center justify-center shrink-0 ${colorClass} ${className ?? ""}`, title: title, style: { width: size, height: size }, children: level === "error" ? (jsxRuntime.jsx(react$1.XCircleIcon, { size: size, weight: "fill" })) : (jsxRuntime.jsx(react$1.WarningCircleIcon, { size: size, weight: "fill" })) }));
4578
4566
  }
4579
4567
 
4580
- function DefaultNodeHeader({ id, typeId, validation, right, showId, onInvalidate, }) {
4568
+ function DefaultNodeHeader({ id, typeId, validation, right, showId, }) {
4581
4569
  const ctx = useWorkbenchContext();
4582
4570
  const [isEditing, setIsEditing] = React.useState(false);
4583
4571
  const [editValue, setEditValue] = React.useState("");
@@ -4595,18 +4583,6 @@ function DefaultNodeHeader({ id, typeId, validation, right, showId, onInvalidate
4595
4583
  const desc = ctx.wb.registry.nodes.get(node.typeId);
4596
4584
  return desc?.displayName || node.typeId;
4597
4585
  }, [ctx, id, typeId]);
4598
- const handleInvalidate = React.useCallback(() => {
4599
- try {
4600
- if (onInvalidate)
4601
- return onInvalidate();
4602
- const kind = ctx.engineKind?.();
4603
- if (kind === "pull")
4604
- ctx.runner.computeNode(id);
4605
- else
4606
- ctx.triggerExternal?.(id, { type: "invalidate" });
4607
- }
4608
- catch { }
4609
- }, [ctx, id, onInvalidate]);
4610
4586
  const handleDoubleClick = React.useCallback((e) => {
4611
4587
  // Only allow editing if typeId is provided (enables renaming)
4612
4588
  if (!typeId)
@@ -4651,10 +4627,16 @@ function DefaultNodeHeader({ id, typeId, validation, right, showId, onInvalidate
4651
4627
  return (jsxRuntime.jsxs("div", { className: "flex items-center justify-center px-2 border-b border-solid border-gray-500 dark:border-gray-400 text-gray-600 dark:text-gray-300", style: {
4652
4628
  maxHeight: NODE_HEADER_HEIGHT_PX,
4653
4629
  minHeight: NODE_HEADER_HEIGHT_PX,
4654
- }, children: [isEditing ? (jsxRuntime.jsx("input", { ref: inputRef, type: "text", value: editValue, onChange: (e) => setEditValue(e.target.value), onBlur: handleSave, onKeyDown: handleKeyDown, onClick: (e) => e.stopPropagation(), onMouseDown: (e) => e.stopPropagation(), className: "flex-1 h-full text-sm bg-transparent border border-blue-500 rounded px-1 outline-none wb-nodrag", style: { lineHeight: `${NODE_HEADER_HEIGHT_PX}px` } })) : (jsxRuntime.jsx("strong", { className: `react-flow__node-title flex-1 h-full text-sm select-none truncate ${typeId ? "cursor-text" : ""}`, style: { lineHeight: `${NODE_HEADER_HEIGHT_PX}px` }, onDoubleClick: handleDoubleClick, title: typeId ? "Double-click to rename" : undefined, children: displayName })), jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [jsxRuntime.jsx("button", { className: "w-4 h-4 border border-gray-400 rounded text-[10px] leading-3 flex items-center justify-center", title: "Invalidate and re-run", onClick: (e) => {
4655
- e.stopPropagation();
4656
- handleInvalidate();
4657
- }, children: jsxRuntime.jsx(react$1.ArrowClockwiseIcon, { size: 10 }) }), right, validation.issues && validation.issues.length > 0 && (jsxRuntime.jsx(IssueBadge, { level: validation.issues.some((i) => i.level === "error")
4630
+ }, children: [isEditing ? (jsxRuntime.jsx("input", { ref: inputRef, type: "text", value: editValue, onChange: (e) => setEditValue(e.target.value), onBlur: handleSave, onKeyDown: handleKeyDown, onClick: (e) => e.stopPropagation(), onMouseDown: (e) => e.stopPropagation(), className: "flex-1 h-full text-sm bg-transparent border border-blue-500 rounded px-1 outline-none wb-nodrag", style: { lineHeight: `${NODE_HEADER_HEIGHT_PX}px` } })) : (jsxRuntime.jsx("strong", { className: `react-flow__node-title flex-1 h-full text-sm select-none truncate ${typeId ? "cursor-text" : ""}`, style: { lineHeight: `${NODE_HEADER_HEIGHT_PX}px` }, onDoubleClick: handleDoubleClick, title: typeId ? "Double-click to rename" : undefined, children: displayName })), jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [ctx.runMode === "manual" && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("button", { onClick: (e) => {
4631
+ e.stopPropagation();
4632
+ ctx.abortNode(id);
4633
+ }, className: "w-4 h-4 flex items-center justify-center hover:bg-gray-200 dark:hover:bg-gray-700 rounded text-gray-600 dark:text-gray-400 hover:text-red-600 dark:hover:text-red-400 transition-colors", title: "Abort node", children: jsxRuntime.jsx(react$1.StopIcon, { size: 10, weight: "fill" }) }), jsxRuntime.jsx("button", { onClick: (e) => {
4634
+ e.stopPropagation();
4635
+ void ctx.runFromHere(id);
4636
+ }, className: "w-4 h-4 flex items-center justify-center hover:bg-gray-200 dark:hover:bg-gray-700 rounded text-gray-600 dark:text-gray-400 hover:text-blue-600 dark:hover:text-blue-400 transition-colors", title: "Run from here", children: jsxRuntime.jsx(react$1.PlayIcon, { size: 10, weight: "fill" }) }), jsxRuntime.jsx("button", { onClick: (e) => {
4637
+ e.stopPropagation();
4638
+ void ctx.runNode(id);
4639
+ }, className: "w-4 h-4 flex items-center justify-center hover:bg-gray-200 dark:hover:bg-gray-700 rounded text-gray-600 dark:text-gray-400 hover:text-green-600 dark:hover:text-green-400 transition-colors", title: "Run node", children: jsxRuntime.jsx(react$1.Circle, { size: 10, weight: "fill" }) })] })), right, validation.issues && validation.issues.length > 0 && (jsxRuntime.jsx(IssueBadge, { level: validation.issues.some((i) => i.level === "error")
4658
4640
  ? "error"
4659
4641
  : "warning", size: 12, className: "w-3 h-3", title: validation.issues
4660
4642
  .map((v) => `${v.code}: ${v.message}`)
@@ -4808,7 +4790,7 @@ const DefaultEdge = React.memo(function DefaultEdge({ id, sourceX, sourceY, targ
4808
4790
  return (jsxRuntime.jsx(react.BaseEdge, { id: id, path: edgePath, style: style, markerEnd: markerEnd }));
4809
4791
  });
4810
4792
 
4811
- function createNodeContextMenuHandlers(nodeId, wb, runner, registry, outputsMap, outputTypesMap, onClose, getDefaultNodeSize, onCopyResult) {
4793
+ function createNodeContextMenuHandlers(nodeId, wb, runner, registry, outputsMap, outputTypesMap, onClose, getDefaultNodeSize, onCopyResult, runNode, runFromHere) {
4812
4794
  return {
4813
4795
  onDelete: () => {
4814
4796
  wb.removeNode(nodeId, { commit: true });
@@ -4828,13 +4810,24 @@ function createNodeContextMenuHandlers(nodeId, wb, runner, registry, outputsMap,
4828
4810
  });
4829
4811
  onClose();
4830
4812
  },
4831
- onRunPull: async () => {
4832
- try {
4833
- await runner.computeNode(nodeId);
4813
+ onRunNode: runNode
4814
+ ? async () => {
4815
+ try {
4816
+ await runNode(nodeId);
4817
+ }
4818
+ catch { }
4819
+ onClose();
4834
4820
  }
4835
- catch { }
4836
- onClose();
4837
- },
4821
+ : undefined,
4822
+ onRunFromHere: runFromHere
4823
+ ? async () => {
4824
+ try {
4825
+ await runFromHere(nodeId);
4826
+ }
4827
+ catch { }
4828
+ onClose();
4829
+ }
4830
+ : undefined,
4838
4831
  onBake: async (handleId) => {
4839
4832
  const nodePosition = wb.getPositions()[nodeId] || { x: 0, y: 0 };
4840
4833
  const typeId = outputTypesMap?.[nodeId]?.[handleId];
@@ -5416,7 +5409,7 @@ function DefaultContextMenu({ open, clientPos, handlers, registry, nodeIds, enab
5416
5409
  !handlers.onRedo && jsxRuntime.jsx("div", { className: "h-px bg-gray-200 my-1" }), jsxRuntime.jsxs("div", { className: "px-2 py-1 font-semibold text-gray-700", children: ["Add Node", " ", jsxRuntime.jsxs("span", { className: "text-gray-500 font-normal", children: ["(", totalCount, ")"] })] }), jsxRuntime.jsx("div", { className: "px-2 pb-1", children: jsxRuntime.jsx("input", { ref: inputRef, type: "text", value: query, onChange: (e) => setQuery(e.target.value), placeholder: "Filter nodes...", className: "w-full border border-gray-300 rounded px-2 py-1 text-sm outline-none focus:border-gray-400 select-text", onClick: (e) => e.stopPropagation(), onMouseDown: (e) => e.stopPropagation(), onWheel: (e) => e.stopPropagation() }) }), jsxRuntime.jsx("div", { className: "max-h-60 overflow-auto", children: totalCount > 0 ? (renderTree(root)) : (jsxRuntime.jsx("div", { className: "px-3 py-2 text-gray-400", children: "No matches" })) })] }));
5417
5410
  }
5418
5411
 
5419
- function NodeContextMenu({ open, clientPos, nodeId, handlers, canRunPull, bakeableOutputs, enableKeyboardShortcuts = true, keyboardShortcuts = {
5412
+ function NodeContextMenu({ open, clientPos, nodeId, handlers, bakeableOutputs, runMode, enableKeyboardShortcuts = true, keyboardShortcuts = {
5420
5413
  copy: "⌘/Ctrl + C",
5421
5414
  duplicate: "⌘/Ctrl + E",
5422
5415
  duplicateWithEdges: "⌘/Ctrl + Shift + E",
@@ -5459,7 +5452,7 @@ function NodeContextMenu({ open, clientPos, nodeId, handlers, canRunPull, bakeab
5459
5452
  return (jsxRuntime.jsxs("div", { ref: ref, tabIndex: -1, className: "fixed z-[1000] bg-white border border-gray-300 rounded-lg shadow-lg p-1 min-w-[180px] text-sm text-gray-700 select-none", style: { left: x, top: y }, onClick: (e) => e.stopPropagation(), onMouseDown: (e) => e.stopPropagation(), onWheel: (e) => e.stopPropagation(), onContextMenu: (e) => {
5460
5453
  e.preventDefault();
5461
5454
  e.stopPropagation();
5462
- }, children: [jsxRuntime.jsxs("div", { className: "px-2 py-1 font-semibold text-gray-700", children: ["Node (", nodeId, ")"] }), jsxRuntime.jsx(ContextMenuButton, { label: "Delete", onClick: handlers.onDelete, shortcut: keyboardShortcuts.delete, enableKeyboardShortcuts: enableKeyboardShortcuts }), jsxRuntime.jsx(ContextMenuButton, { label: "Duplicate", onClick: handlers.onDuplicate, shortcut: keyboardShortcuts.duplicate, enableKeyboardShortcuts: enableKeyboardShortcuts }), jsxRuntime.jsx(ContextMenuButton, { label: "Duplicate with edges", onClick: handlers.onDuplicateWithEdges, shortcut: keyboardShortcuts.duplicateWithEdges, enableKeyboardShortcuts: enableKeyboardShortcuts }), canRunPull && (jsxRuntime.jsx("button", { className: "block w-full text-left px-2 py-1 hover:bg-gray-100", onClick: handlers.onRunPull, children: "Run (pull)" })), jsxRuntime.jsx("div", { className: "h-px bg-gray-200 my-1" }), jsxRuntime.jsx(ContextMenuButton, { label: "Copy", onClick: handlers.onCopy, shortcut: keyboardShortcuts.copy, enableKeyboardShortcuts: enableKeyboardShortcuts }), jsxRuntime.jsx("button", { className: "block w-full text-left px-2 py-1 hover:bg-gray-100", onClick: handlers.onCopyId, children: "Copy Node ID" }), bakeableOutputs.length > 0 && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { className: "h-px bg-gray-200 my-1" }), jsxRuntime.jsx("div", { className: "px-2 py-1 font-semibold text-gray-700", children: "Bake" }), bakeableOutputs.map((h) => (jsxRuntime.jsxs("button", { className: "block w-full text-left px-2 py-1 hover:bg-gray-100", onClick: () => handlers.onBake(h), children: ["Bake: ", h] }, h)))] }))] }));
5455
+ }, children: [jsxRuntime.jsxs("div", { className: "px-2 py-1 font-semibold text-gray-700", children: ["Node (", nodeId, ")"] }), jsxRuntime.jsx(ContextMenuButton, { label: "Delete", onClick: handlers.onDelete, shortcut: keyboardShortcuts.delete, enableKeyboardShortcuts: enableKeyboardShortcuts }), jsxRuntime.jsx(ContextMenuButton, { label: "Duplicate", onClick: handlers.onDuplicate, shortcut: keyboardShortcuts.duplicate, enableKeyboardShortcuts: enableKeyboardShortcuts }), jsxRuntime.jsx(ContextMenuButton, { label: "Duplicate with edges", onClick: handlers.onDuplicateWithEdges, shortcut: keyboardShortcuts.duplicateWithEdges, enableKeyboardShortcuts: enableKeyboardShortcuts }), runMode === "manual" && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [handlers.onRunNode && (jsxRuntime.jsx("button", { className: "block w-full text-left px-2 py-1 hover:bg-gray-100", onClick: handlers.onRunNode, children: "Run node" })), handlers.onRunFromHere && (jsxRuntime.jsx("button", { className: "block w-full text-left px-2 py-1 hover:bg-gray-100", onClick: handlers.onRunFromHere, children: "Run from here" }))] })), jsxRuntime.jsx("div", { className: "h-px bg-gray-200 my-1" }), jsxRuntime.jsx(ContextMenuButton, { label: "Copy", onClick: handlers.onCopy, shortcut: keyboardShortcuts.copy, enableKeyboardShortcuts: enableKeyboardShortcuts }), jsxRuntime.jsx("button", { className: "block w-full text-left px-2 py-1 hover:bg-gray-100", onClick: handlers.onCopyId, children: "Copy Node ID" }), bakeableOutputs.length > 0 && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { className: "h-px bg-gray-200 my-1" }), jsxRuntime.jsx("div", { className: "px-2 py-1 font-semibold text-gray-700", children: "Bake" }), bakeableOutputs.map((h) => (jsxRuntime.jsxs("button", { className: "block w-full text-left px-2 py-1 hover:bg-gray-100", onClick: () => handlers.onBake(h), children: ["Bake: ", h] }, h)))] }))] }));
5463
5456
  }
5464
5457
 
5465
5458
  function SelectionContextMenu({ open, clientPos, handlers, enableKeyboardShortcuts = true, keyboardShortcuts = {
@@ -5546,7 +5539,7 @@ function useKeyboardShortcutToast() {
5546
5539
  }
5547
5540
 
5548
5541
  const WorkbenchCanvas = React.forwardRef(({ showValues, toString, toElement, getDefaultNodeSize }, ref) => {
5549
- const { wb, inputsMap, inputDefaultsMap, outputsMap, outputTypesMap, valuesTick, nodeStatus, edgeStatus, validationByNode, validationByEdge, uiVersion, registryVersion, runner, engineKind, overrides, } = useWorkbenchContext();
5542
+ const { wb, inputsMap, inputDefaultsMap, outputsMap, outputTypesMap, valuesTick, nodeStatus, edgeStatus, validationByNode, validationByEdge, uiVersion, registryVersion, runner, overrides, runNode, runFromHere, runMode, } = useWorkbenchContext();
5550
5543
  const nodeValidation = validationByNode;
5551
5544
  const edgeValidation = validationByEdge.errors;
5552
5545
  const [historyState, setHistoryState] = React.useState(wb.getHistory());
@@ -5986,7 +5979,7 @@ const WorkbenchCanvas = React.forwardRef(({ showValues, toString, toElement, get
5986
5979
  };
5987
5980
  const baseHandlers = createNodeContextMenuHandlers(nodeAtMenu, wb, runner, wb.registry, outputsMap, outputTypesMap, onCloseNodeMenu, overrides?.getDefaultNodeSize, (data) => {
5988
5981
  storage.set(data);
5989
- });
5982
+ }, runNode, runFromHere);
5990
5983
  if (overrides?.getNodeContextMenuHandlers) {
5991
5984
  return overrides.getNodeContextMenuHandlers(wb, nodeAtMenu, baseHandlers);
5992
5985
  }
@@ -6004,7 +5997,6 @@ const WorkbenchCanvas = React.forwardRef(({ showValues, toString, toElement, get
6004
5997
  overrides?.getNodeContextMenuHandlers,
6005
5998
  overrides?.getCopiedDataStorage,
6006
5999
  ]);
6007
- const canRunPull = React.useMemo(() => engineKind()?.toString() === "pull", [engineKind]);
6008
6000
  const bakeableOutputs = React.useMemo(() => {
6009
6001
  if (!nodeAtMenu)
6010
6002
  return [];
@@ -6209,15 +6201,15 @@ const WorkbenchCanvas = React.forwardRef(({ showValues, toString, toElement, get
6209
6201
  ? { enableKeyboardShortcuts, keyboardShortcuts }
6210
6202
  : {}) })) : (jsxRuntime.jsx(DefaultContextMenu, { open: menuOpen, clientPos: menuPos, handlers: defaultContextMenuHandlers, registry: wb.registry, nodeIds: nodeIds, enableKeyboardShortcuts: enableKeyboardShortcuts, keyboardShortcuts: keyboardShortcuts })), !!nodeAtMenu &&
6211
6203
  nodeContextMenuHandlers &&
6212
- (NodeContextMenuRenderer ? (jsxRuntime.jsx(NodeContextMenuRenderer, { open: nodeMenuOpen, clientPos: nodeMenuPos, nodeId: nodeAtMenu, handlers: nodeContextMenuHandlers, canRunPull: canRunPull, bakeableOutputs: bakeableOutputs, ...(enableKeyboardShortcuts !== false
6204
+ (NodeContextMenuRenderer ? (jsxRuntime.jsx(NodeContextMenuRenderer, { open: nodeMenuOpen, clientPos: nodeMenuPos, nodeId: nodeAtMenu, handlers: nodeContextMenuHandlers, bakeableOutputs: bakeableOutputs, runMode: runMode, wb: wb, ...(enableKeyboardShortcuts !== false
6213
6205
  ? { enableKeyboardShortcuts, keyboardShortcuts }
6214
- : {}) })) : (jsxRuntime.jsx(NodeContextMenu, { open: nodeMenuOpen, clientPos: nodeMenuPos, nodeId: nodeAtMenu, handlers: nodeContextMenuHandlers, canRunPull: canRunPull, bakeableOutputs: bakeableOutputs, enableKeyboardShortcuts: enableKeyboardShortcuts, keyboardShortcuts: keyboardShortcuts }))), selectionMenuOpen &&
6206
+ : {}) })) : (jsxRuntime.jsx(NodeContextMenu, { open: nodeMenuOpen, clientPos: nodeMenuPos, nodeId: nodeAtMenu, handlers: nodeContextMenuHandlers, bakeableOutputs: bakeableOutputs, runMode: runMode }))), selectionMenuOpen &&
6215
6207
  selectionMenuPos &&
6216
6208
  (SelectionContextMenuRenderer ? (jsxRuntime.jsx(SelectionContextMenuRenderer, { open: selectionMenuOpen, clientPos: selectionMenuPos, handlers: selectionContextMenuHandlers, enableKeyboardShortcuts: enableKeyboardShortcuts, keyboardShortcuts: keyboardShortcuts })) : (jsxRuntime.jsx(SelectionContextMenu, { open: selectionMenuOpen, clientPos: selectionMenuPos, handlers: selectionContextMenuHandlers, enableKeyboardShortcuts: enableKeyboardShortcuts, keyboardShortcuts: keyboardShortcuts })))] }) }), toast && (jsxRuntime.jsx(KeyboardShortcutToast, { message: toast.message, onClose: hideToast }, toast.id))] }));
6217
6209
  });
6218
6210
 
6219
- function WorkbenchStudioCanvas({ autoScroll, onAutoScrollChange, example, onExampleChange, engine, onEngineChange, backendKind, onBackendKindChange, httpBaseUrl, onHttpBaseUrlChange, wsUrl, onWsUrlChange, debug, onDebugChange, showValues, onShowValuesChange, hideWorkbench, onHideWorkbenchChange, overrides, onInit, onChange, }) {
6220
- const { wb, runner, selectedNodeId, runAutoLayout } = useWorkbenchContext();
6211
+ function WorkbenchStudioCanvas({ autoScroll, onAutoScrollChange, example, onExampleChange, backendKind, onBackendKindChange, httpBaseUrl, onHttpBaseUrlChange, wsUrl, onWsUrlChange, debug, onDebugChange, showValues, onShowValuesChange, hideWorkbench, onHideWorkbenchChange, overrides, onInit, onChange, }) {
6212
+ const { wb, runner, selectedNodeId, runAutoLayout, runMode, setRunMode, isRunning, } = useWorkbenchContext();
6221
6213
  const [transportStatus, setTransportStatus] = React.useState({
6222
6214
  state: "local",
6223
6215
  });
@@ -6226,8 +6218,7 @@ function WorkbenchStudioCanvas({ autoScroll, onAutoScrollChange, example, onExam
6226
6218
  ? computeEffectiveHandles(selectedNode, wb.registry)
6227
6219
  : { inputs: {}, outputs: {}, inputDefaults: {} };
6228
6220
  const [exampleState, setExampleState] = React.useState(example ?? "");
6229
- const isGraphRunning = runner.isRunning();
6230
- const engineKind = runner.getRunningEngine();
6221
+ const isGraphRunning = isRunning();
6231
6222
  // Render Start/Stop button based on transport and runner state
6232
6223
  const renderStartStopButton = React.useCallback(() => {
6233
6224
  // Check if transport is connecting/retrying
@@ -6243,14 +6234,11 @@ function WorkbenchStudioCanvas({ autoScroll, onAutoScrollChange, example, onExam
6243
6234
  return (jsxRuntime.jsxs("button", { className: "border rounded px-2 py-1.5 text-red-700 border-red-600 flex items-center gap-1 disabled:opacity-50 disabled:text-gray-400 disabled:border-gray-300", onClick: () => runner.stop(), disabled: !canControl, title: canControl ? "Stop engine" : "Waiting for connection", children: [jsxRuntime.jsx(react$1.StopIcon, { size: 16, weight: "fill" }), jsxRuntime.jsx("span", { className: "font-medium ml-1", children: "Stop" })] }));
6244
6235
  }
6245
6236
  return (jsxRuntime.jsxs("button", { className: "border rounded px-2 py-1.5 text-green-700 border-green-600 flex items-center gap-1 disabled:text-gray-400 disabled:border-gray-300 disabled:opacity-50", onClick: (evt) => {
6246
- const kind = engine;
6247
- if (!kind)
6248
- return alert("Select an engine first.");
6249
6237
  if (evt.shiftKey && !confirm("Invalidate and re-run graph?"))
6250
6238
  return;
6251
6239
  try {
6252
6240
  runner.launch(wb.def, {
6253
- engine: kind,
6241
+ runMode,
6254
6242
  invalidate: evt.shiftKey,
6255
6243
  });
6256
6244
  }
@@ -6258,12 +6246,10 @@ function WorkbenchStudioCanvas({ autoScroll, onAutoScrollChange, example, onExam
6258
6246
  const message = err instanceof Error ? err.message : String(err);
6259
6247
  alert(message);
6260
6248
  }
6261
- }, disabled: !engine || !canControl, title: !engine
6262
- ? "Select an engine first"
6263
- : !canControl
6264
- ? "Waiting for connection"
6265
- : "Start engine", children: [jsxRuntime.jsx(react$1.PlayIcon, { size: 16, weight: "fill" }), jsxRuntime.jsx("span", { className: "font-medium ml-1", children: "Start" })] }));
6266
- }, [transportStatus, isGraphRunning, runner, engine, wb]);
6249
+ }, disabled: !canControl, title: !canControl
6250
+ ? "Waiting for connection"
6251
+ : `Start ${runMode === "manual" ? "manual" : "auto"} mode`, children: [jsxRuntime.jsx(react$1.PlayIcon, { size: 16, weight: "fill" }), jsxRuntime.jsx("span", { className: "font-medium ml-1", children: "Start" })] }));
6252
+ }, [transportStatus, isGraphRunning, runner, runMode, wb]);
6267
6253
  const defaultExamples = React.useMemo(() => [
6268
6254
  {
6269
6255
  id: "simple",
@@ -6445,8 +6431,6 @@ function WorkbenchStudioCanvas({ autoScroll, onAutoScrollChange, example, onExam
6445
6431
  return () => off();
6446
6432
  }, [runner, backendKind]);
6447
6433
  React.useEffect(() => {
6448
- if (!engine)
6449
- return;
6450
6434
  if (isGraphRunning)
6451
6435
  return;
6452
6436
  // Only auto-launch for local backend; require explicit Start for remote
@@ -6455,12 +6439,12 @@ function WorkbenchStudioCanvas({ autoScroll, onAutoScrollChange, example, onExam
6455
6439
  if (!wb.def.nodes || wb.def.nodes.length === 0)
6456
6440
  return;
6457
6441
  try {
6458
- runner.launch(wb.def, { engine: engine });
6442
+ runner.launch(wb.def, { runMode });
6459
6443
  }
6460
6444
  catch {
6461
6445
  // ignore
6462
6446
  }
6463
- }, [engine, runner, isGraphRunning, wb, backendKind]);
6447
+ }, [runMode, runner, isGraphRunning, wb, backendKind]);
6464
6448
  const baseSetInput = React.useCallback((handle, raw) => {
6465
6449
  if (!selectedNodeId)
6466
6450
  return;
@@ -6630,38 +6614,18 @@ function WorkbenchStudioCanvas({ autoScroll, onAutoScrollChange, example, onExam
6630
6614
  return overrides.toElement(baseToElement, { registry: wb.registry });
6631
6615
  return baseToElement;
6632
6616
  }, [overrides, baseToElement, wb.registry]);
6633
- return (jsxRuntime.jsxs("div", { className: "w-full h-screen flex flex-col", children: [jsxRuntime.jsxs("div", { className: "p-2 border-b border-gray-300 flex gap-2 items-center", children: [isGraphRunning ? (jsxRuntime.jsxs("span", { className: "ml-2 text-sm text-green-700", children: ["Running: ", engineKind] })) : (jsxRuntime.jsx("span", { className: "ml-2 text-sm text-gray-500", children: "Stopped" })), jsxRuntime.jsxs("span", { className: "ml-2 flex items-center gap-1 text-xs", title: transportStatus.kind || undefined, children: [transportStatus.state === "local" && (jsxRuntime.jsx(react$1.PlugsConnectedIcon, { size: 14, className: "text-gray-500" })), transportStatus.state === "connecting" && (jsxRuntime.jsx(react$1.ClockClockwiseIcon, { size: 14, className: "text-amber-600 animate-pulse" })), transportStatus.state === "connected" && (jsxRuntime.jsx(react$1.WifiHighIcon, { size: 14, className: "text-green-600" })), transportStatus.state === "disconnected" && (jsxRuntime.jsx(react$1.WifiSlashIcon, { size: 14, className: "text-red-600" })), transportStatus.state === "retrying" && (jsxRuntime.jsx(react$1.ClockClockwiseIcon, { size: 14, className: "text-amber-700 animate-pulse" }))] }), jsxRuntime.jsxs("select", { className: "border border-gray-300 rounded px-2 py-1", value: exampleState, onChange: (e) => applyExample(e.target.value), disabled: isGraphRunning, title: isGraphRunning ? "Stop engine before switching example" : undefined, children: [jsxRuntime.jsx("option", { value: "", children: "Select Example\u2026" }), examples.map((ex) => (jsxRuntime.jsx("option", { value: ex.id, children: ex.label }, ex.id)))] }), jsxRuntime.jsxs("select", { className: "border border-gray-300 rounded px-2 py-1", value: backendKind, onChange: (e) => onBackendKindChange(e.target.value), disabled: isGraphRunning, title: isGraphRunning ? "Stop engine before switching backend" : undefined, children: [jsxRuntime.jsx("option", { value: "local", children: "Local" }), jsxRuntime.jsx("option", { value: "remote-http", children: "Remote (HTTP)" }), jsxRuntime.jsx("option", { value: "remote-ws", children: "Remote (WebSocket)" })] }), backendKind === "remote-http" && !!onHttpBaseUrlChange && (jsxRuntime.jsx("input", { className: "border border-gray-300 rounded px-2 py-1 w-72", placeholder: "http://127.0.0.1:18080", value: httpBaseUrl, onChange: (e) => onHttpBaseUrlChange(e.target.value) })), backendKind === "remote-ws" && !!onWsUrlChange && (jsxRuntime.jsx("input", { className: "border border-gray-300 rounded px-2 py-1 w-72", placeholder: "ws://127.0.0.1:18081", value: wsUrl, onChange: (e) => onWsUrlChange(e.target.value) })), jsxRuntime.jsxs("select", { className: "border border-gray-300 rounded px-2 py-1", value: engineKind ?? engine ?? "", onChange: async (e) => {
6634
- const kind = e.target.value || undefined;
6635
- const currentEngine = runner.getRunningEngine();
6636
- // If engine is running and user selected a different engine, switch it
6637
- if (runner.isRunning() &&
6638
- currentEngine &&
6639
- kind &&
6640
- kind !== currentEngine) {
6641
- try {
6642
- await runner.switchEngine({
6643
- engine: kind,
6644
- batched: { flushIntervalMs: 0 },
6645
- hybrid: { windowMs: 250, batchThreshold: 3 },
6646
- });
6647
- onEngineChange?.(kind);
6648
- }
6649
- catch (err) {
6650
- const message = err instanceof Error ? err.message : String(err);
6651
- alert(`Failed to switch engine: ${message}`);
6652
- // Reset dropdown to current engine
6653
- e.target.value = currentEngine;
6654
- }
6655
- }
6656
- else {
6657
- // Normal change when not running
6658
- onEngineChange?.(kind);
6617
+ return (jsxRuntime.jsxs("div", { className: "w-full h-screen flex flex-col", children: [jsxRuntime.jsxs("div", { className: "p-2 border-b border-gray-300 flex gap-2 items-center", children: [isGraphRunning ? (jsxRuntime.jsxs("span", { className: "ml-2 text-sm text-green-700", children: ["Running: ", runMode === "manual" ? "Manual" : "Auto"] })) : (jsxRuntime.jsx("span", { className: "ml-2 text-sm text-gray-500", children: "Stopped" })), jsxRuntime.jsxs("span", { className: "ml-2 flex items-center gap-1 text-xs", title: transportStatus.kind || undefined, children: [transportStatus.state === "local" && (jsxRuntime.jsx(react$1.PlugsConnectedIcon, { size: 14, className: "text-gray-500" })), transportStatus.state === "connecting" && (jsxRuntime.jsx(react$1.ClockClockwiseIcon, { size: 14, className: "text-amber-600 animate-pulse" })), transportStatus.state === "connected" && (jsxRuntime.jsx(react$1.WifiHighIcon, { size: 14, className: "text-green-600" })), transportStatus.state === "disconnected" && (jsxRuntime.jsx(react$1.WifiSlashIcon, { size: 14, className: "text-red-600" })), transportStatus.state === "retrying" && (jsxRuntime.jsx(react$1.ClockClockwiseIcon, { size: 14, className: "text-amber-700 animate-pulse" }))] }), jsxRuntime.jsxs("select", { className: "border border-gray-300 rounded px-2 py-1", value: exampleState, onChange: (e) => applyExample(e.target.value), disabled: isGraphRunning, title: isGraphRunning ? "Stop engine before switching example" : undefined, children: [jsxRuntime.jsx("option", { value: "", children: "Select Example\u2026" }), examples.map((ex) => (jsxRuntime.jsx("option", { value: ex.id, children: ex.label }, ex.id)))] }), jsxRuntime.jsxs("select", { className: "border border-gray-300 rounded px-2 py-1", value: backendKind, onChange: (e) => onBackendKindChange(e.target.value), disabled: isGraphRunning, title: isGraphRunning ? "Stop engine before switching backend" : undefined, children: [jsxRuntime.jsx("option", { value: "local", children: "Local" }), jsxRuntime.jsx("option", { value: "remote-http", children: "Remote (HTTP)" }), jsxRuntime.jsx("option", { value: "remote-ws", children: "Remote (WebSocket)" })] }), backendKind === "remote-http" && !!onHttpBaseUrlChange && (jsxRuntime.jsx("input", { className: "border border-gray-300 rounded px-2 py-1 w-72", placeholder: "http://127.0.0.1:18080", value: httpBaseUrl, onChange: (e) => onHttpBaseUrlChange(e.target.value) })), backendKind === "remote-ws" && !!onWsUrlChange && (jsxRuntime.jsx("input", { className: "border border-gray-300 rounded px-2 py-1 w-72", placeholder: "ws://127.0.0.1:18081", value: wsUrl, onChange: (e) => onWsUrlChange(e.target.value) })), jsxRuntime.jsxs("select", { className: "border border-gray-300 rounded px-2 py-1", value: runMode, onChange: async (e) => {
6618
+ const mode = e.target.value;
6619
+ if (mode !== runMode) {
6620
+ await setRunMode(mode);
6659
6621
  }
6660
- }, children: [jsxRuntime.jsx("option", { value: "", children: "Select Engine\u2026" }), jsxRuntime.jsx("option", { value: "push", children: "Push" }), jsxRuntime.jsx("option", { value: "batched", children: "Batched" }), jsxRuntime.jsx("option", { value: "pull", children: "Pull" }), jsxRuntime.jsx("option", { value: "hybrid", children: "Hybrid" }), jsxRuntime.jsx("option", { value: "step", children: "Step" })] }), engineKind === "step" && (jsxRuntime.jsx("button", { className: "border border-gray-300 rounded p-1", onClick: () => runner.step(), disabled: !isGraphRunning, title: "Step", children: jsxRuntime.jsx(react$1.PlayPauseIcon, { size: 24 }) })), engineKind === "batched" && (jsxRuntime.jsx("button", { className: "border border-gray-300 rounded p-1", onClick: () => runner.flush(), disabled: !isGraphRunning, title: "Flush", children: jsxRuntime.jsx(react$1.LightningIcon, { size: 24 }) })), renderStartStopButton(), jsxRuntime.jsx("button", { className: "border border-gray-300 rounded p-1", onClick: runAutoLayout, children: jsxRuntime.jsx(react$1.TreeStructureIcon, { size: 24 }) }), jsxRuntime.jsx("button", { className: "border border-gray-300 rounded p-1", onClick: () => canvasRef.current?.fitView?.(), title: "Fit View", children: jsxRuntime.jsx(react$1.CornersOutIcon, { size: 24 }) }), jsxRuntime.jsx("button", { className: "border border-gray-300 rounded p-1", onClick: download$1, children: jsxRuntime.jsx(react$1.DownloadIcon, { size: 24 }) }), jsxRuntime.jsx("input", { ref: uploadInputRef, type: "file", accept: "application/json,.json", className: "hidden", onChange: onUploadPicked }), jsxRuntime.jsx("button", { className: "border border-gray-300 rounded p-1", onClick: triggerUpload, children: jsxRuntime.jsx(react$1.UploadIcon, { size: 24 }) }), jsxRuntime.jsx("button", { className: "border border-gray-300 rounded p-1", onClick: async () => {
6622
+ }, disabled: isGraphRunning, title: isGraphRunning
6623
+ ? "Stop before switching run mode"
6624
+ : "Select run mode", children: [jsxRuntime.jsx("option", { value: "manual", children: "Manual" }), jsxRuntime.jsx("option", { value: "auto", children: "Auto" })] }), renderStartStopButton(), jsxRuntime.jsx("button", { className: "border border-gray-300 rounded p-1", onClick: runAutoLayout, children: jsxRuntime.jsx(react$1.TreeStructureIcon, { size: 24 }) }), jsxRuntime.jsx("button", { className: "border border-gray-300 rounded p-1", onClick: () => canvasRef.current?.fitView?.(), title: "Fit View", children: jsxRuntime.jsx(react$1.CornersOutIcon, { size: 24 }) }), jsxRuntime.jsx("button", { className: "border border-gray-300 rounded p-1", onClick: download$1, children: jsxRuntime.jsx(react$1.DownloadIcon, { size: 24 }) }), jsxRuntime.jsx("input", { ref: uploadInputRef, type: "file", accept: "application/json,.json", className: "hidden", onChange: onUploadPicked }), jsxRuntime.jsx("button", { className: "border border-gray-300 rounded p-1", onClick: triggerUpload, children: jsxRuntime.jsx(react$1.UploadIcon, { size: 24 }) }), jsxRuntime.jsx("button", { className: "border border-gray-300 rounded p-1", onClick: async () => {
6661
6625
  await downloadCanvasThumbnail(canvasContainerRef.current);
6662
6626
  }, title: "Download Flow Thumbnail (SVG)", children: jsxRuntime.jsx(react$1.ImageIcon, { size: 24 }) }), jsxRuntime.jsxs("label", { className: "flex items-center gap-1", children: [jsxRuntime.jsx("input", { type: "checkbox", checked: debug, onChange: (e) => onDebugChange(e.target.checked) }), jsxRuntime.jsx(react$1.BugBeetleIcon, { size: 24, weight: debug ? "fill" : undefined })] }), jsxRuntime.jsxs("label", { className: "flex items-center gap-1", children: [jsxRuntime.jsx("input", { type: "checkbox", checked: showValues, onChange: (e) => onShowValuesChange(e.target.checked) }), jsxRuntime.jsx(react$1.ListBulletsIcon, { size: 24, weight: showValues ? "fill" : undefined })] })] }), jsxRuntime.jsxs("div", { className: "flex flex-1 min-h-0", children: [jsxRuntime.jsx("div", { className: "flex-1 min-w-0", ref: canvasContainerRef, children: jsxRuntime.jsx(WorkbenchCanvas, { ref: canvasRef, showValues: showValues, toString: toString, toElement: toElement, getDefaultNodeSize: overrides?.getDefaultNodeSize }) }), jsxRuntime.jsx(Inspector, { setInput: setInput, debug: debug, autoScroll: autoScroll, hideWorkbench: hideWorkbench, onAutoScrollChange: onAutoScrollChange, onHideWorkbenchChange: onHideWorkbenchChange, toString: toString, contextPanel: overrides?.contextPanel })] })] }));
6663
6627
  }
6664
- function WorkbenchStudio({ engine, onEngineChange, example, onExampleChange, backendKind, onBackendKindChange, httpBaseUrl, onHttpBaseUrlChange, wsUrl, onWsUrlChange, debug, onDebugChange, showValues, onShowValuesChange, hideWorkbench, onHideWorkbenchChange, autoScroll, onAutoScrollChange, backendOptions, overrides, onInit, onChange, }) {
6628
+ function WorkbenchStudio({ example, onExampleChange, backendKind, onBackendKindChange, httpBaseUrl, onHttpBaseUrlChange, wsUrl, onWsUrlChange, debug, onDebugChange, showValues, onShowValuesChange, hideWorkbench, onHideWorkbenchChange, autoScroll, onAutoScrollChange, backendOptions, overrides, onInit, onChange, }) {
6665
6629
  const [registry, setRegistry] = React.useState(sparkGraph.createSimpleGraphRegistry());
6666
6630
  const [wb] = React.useState(() => new InMemoryWorkbench({ ui: new DefaultUIExtensionRegistry() }));
6667
6631
  // Store previous runner for cleanup
@@ -6731,7 +6695,7 @@ function WorkbenchStudio({ engine, onEngineChange, example, onExampleChange, bac
6731
6695
  runner.dispose();
6732
6696
  onBackendKindChange(v);
6733
6697
  }, [isGraphRunning]);
6734
- return (jsxRuntime.jsx(WorkbenchProvider, { wb: wb, runner: runner, overrides: overrides, uiVersion: uiVersion, children: jsxRuntime.jsx(WorkbenchStudioCanvas, { setRegistry: setRegistry, autoScroll: autoScroll, onAutoScrollChange: onAutoScrollChange, example: example, onExampleChange: onExampleChange, engine: engine, onEngineChange: onEngineChange, backendKind: backendKind, onBackendKindChange: onBackendKindChangeWithDispose, httpBaseUrl: httpBaseUrl, onHttpBaseUrlChange: onHttpBaseUrlChange, wsUrl: wsUrl, onWsUrlChange: onWsUrlChange, debug: debug, onDebugChange: onDebugChange, showValues: showValues, onShowValuesChange: onShowValuesChange, hideWorkbench: hideWorkbench, onHideWorkbenchChange: onHideWorkbenchChange, overrides: overrides, onInit: onInit, onChange: onChange }) }));
6698
+ return (jsxRuntime.jsx(WorkbenchProvider, { wb: wb, runner: runner, overrides: overrides, uiVersion: uiVersion, children: jsxRuntime.jsx(WorkbenchStudioCanvas, { setRegistry: setRegistry, autoScroll: autoScroll, onAutoScrollChange: onAutoScrollChange, example: example, onExampleChange: onExampleChange, backendKind: backendKind, onBackendKindChange: onBackendKindChangeWithDispose, httpBaseUrl: httpBaseUrl, onHttpBaseUrlChange: onHttpBaseUrlChange, wsUrl: wsUrl, onWsUrlChange: onWsUrlChange, debug: debug, onDebugChange: onDebugChange, showValues: showValues, onShowValuesChange: onShowValuesChange, hideWorkbench: hideWorkbench, onHideWorkbenchChange: onHideWorkbenchChange, overrides: overrides, onInit: onInit, onChange: onChange }) }));
6735
6699
  }
6736
6700
 
6737
6701
  exports.AbstractWorkbench = AbstractWorkbench;