bizydraft 0.1.29__py3-none-any.whl → 0.2.0__py3-none-any.whl

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.

Potentially problematic release.


This version of bizydraft might be problematic. Click here for more details.

@@ -1,4 +1,6 @@
1
1
  import { app } from "../../scripts/app.js";
2
+ import { enableAIAppMode, disableAIAppMode, selectInputNode, deselectInputNode, updateInputNodeWidget, getSelectedInputNodes, clearSelectedInputNodes, toggleExportMode } from "./aiAppHandler.js";
3
+ import { focusNodeOnly } from "./nodeFocusHandler.js";
2
4
 
3
5
  app.registerExtension({
4
6
  name: "comfy.BizyAir.Socket",
@@ -10,28 +12,28 @@ app.registerExtension({
10
12
  socket: null,
11
13
  isConnecting: false,
12
14
  taskRunning: false,
13
-
15
+
14
16
  // 心跳检测
15
17
  pingInterval: 5000, // 5秒发送一次心跳
16
18
  pingTimer: null,
17
19
  pingTimeout: 3000,
18
- pongReceived: false,
20
+ pongReceived: false,
19
21
  pingTimeoutTimer: null, // ping超时计时器
20
-
22
+
21
23
  /**
22
24
  * 开始心跳检测
23
25
  */
24
26
  startPing() {
25
27
  this.stopPing();
26
-
28
+
27
29
  if (!this.socket || this.socket.readyState !== WebSocket.OPEN) {
28
30
  return;
29
31
  }
30
-
32
+
31
33
  // 立即发送一次ping消息
32
34
  this.pongReceived = false;
33
35
  this.socket.send('ping');
34
-
36
+
35
37
  // 设置ping超时检测
36
38
  this.pingTimeoutTimer = setTimeout(() => {
37
39
  if (!this.pongReceived) {
@@ -39,12 +41,12 @@ app.registerExtension({
39
41
  this.reconnect();
40
42
  }
41
43
  }, this.pingTimeout);
42
-
44
+
43
45
  // 设置定时发送ping
44
46
  this.pingTimer = setInterval(() => {
45
47
  if (this.socket && this.socket.readyState === WebSocket.OPEN) {
46
48
  this.pongReceived = false;
47
- this.socket.send('ping');
49
+ this.socket.send('ping');
48
50
  // 设置ping超时检测
49
51
  this.pingTimeoutTimer = setTimeout(() => {
50
52
  // 如果没有收到pong响应
@@ -59,7 +61,7 @@ app.registerExtension({
59
61
  }
60
62
  }, this.pingInterval);
61
63
  },
62
-
64
+
63
65
  /**
64
66
  * 停止心跳检测
65
67
  */
@@ -68,25 +70,25 @@ app.registerExtension({
68
70
  clearInterval(this.pingTimer);
69
71
  this.pingTimer = null;
70
72
  }
71
-
73
+
72
74
  if (this.pingTimeoutTimer) {
73
75
  clearTimeout(this.pingTimeoutTimer);
74
76
  this.pingTimeoutTimer = null;
75
77
  }
76
78
  },
77
-
79
+
78
80
  /**
79
81
  * 重新连接
80
82
  */
81
83
  reconnect() {
82
84
  if (this.isConnecting) {
83
85
  return;
84
- }
85
- const url = this.socket ? this.socket.url : app.api.socket.url;
86
- this.closeSocket();
86
+ }
87
+ const url = this.socket ? this.socket.url : app.api.socket.url;
88
+ this.closeSocket();
87
89
  this.createSocket(url);
88
90
  },
89
-
91
+
90
92
  /**
91
93
  * 创建新的WebSocket连接
92
94
  */
@@ -96,21 +98,21 @@ app.registerExtension({
96
98
  console.log('WebSocket连接已在创建中,避免重复创建');
97
99
  return null;
98
100
  }
99
-
101
+
100
102
  // 标记为连接中
101
103
  this.isConnecting = true;
102
-
104
+
103
105
  // 先关闭现有连接
104
106
  this.closeSocket();
105
-
107
+
106
108
  const url = customUrl || app.api.socket.url;
107
109
  console.log('创建WebSocket连接:', url);
108
-
110
+
109
111
  try {
110
112
  const socket = new WebSocket(url);
111
113
  const dispatchCustomEvent = this.dispatchCustomEvent;
112
114
  const self = this;
113
-
115
+
114
116
  socket.onopen = function() {
115
117
  console.log('WebSocket连接已打开');
116
118
  // 清除连接中标志
@@ -122,19 +124,19 @@ app.registerExtension({
122
124
  // 开始心跳检测
123
125
  self.startPing();
124
126
  };
125
-
127
+
126
128
  socket.onmessage = function (event) {
127
129
  try {
128
130
  // 处理心跳响应
129
131
  if (event.data === 'pong') {
130
132
  // 标记收到pong响应
131
133
  self.pongReceived = true;
132
- return;
133
- }
134
+ return;
135
+ }
134
136
  if (event.data instanceof ArrayBuffer) {
135
137
  const view = new DataView(event.data);
136
138
  const eventType = view.getUint32(0);
137
-
139
+
138
140
  let imageMime;
139
141
  switch (eventType) {
140
142
  case 3:
@@ -177,20 +179,27 @@ app.registerExtension({
177
179
  self.closeSocket(1000);
178
180
  return;
179
181
  }
180
-
182
+
181
183
  const msg = JSON.parse(event.data);
182
184
  window.parent.postMessage({
183
185
  type: 'functionResult',
184
186
  method: 'progress_info_change',
185
187
  result: msg.progress_info
186
188
  }, '*');
187
-
188
189
  switch (msg.type) {
190
+ case 'load_start':
191
+ case 'load_end':
192
+ case 'prompt_id':
193
+ window.parent.postMessage({
194
+ type: 'functionResult',
195
+ method: 'preparingStatus',
196
+ result: msg
197
+ }, '*')
189
198
  case 'status':
190
199
  if (msg.data.sid) {
191
200
  const clientId = msg.data.sid;
192
- window.name = clientId;
193
- sessionStorage.setItem('clientId', clientId);
201
+ window.name = clientId;
202
+ sessionStorage.setItem('clientId', clientId);
194
203
  socket.clientId = clientId;
195
204
  }
196
205
  dispatchCustomEvent('status', msg.data.status ?? null);
@@ -209,6 +218,17 @@ app.registerExtension({
209
218
  }
210
219
  dispatchCustomEvent(msg.type, msg.data);
211
220
  break;
221
+ case 'error':
222
+ self.taskRunning = false;
223
+ dispatchCustomEvent('execution_error', {
224
+ exception_message: msg.data.error_message || 'Unknown error',
225
+ traceback: ['Manual error triggered'],
226
+ executed: [],
227
+ prompt_id: 'manual',
228
+ node_id: '0',
229
+ node_type: 'RunError',
230
+ });
231
+ break;
212
232
  case 'execution_error':
213
233
  case 'execution_interrupted':
214
234
  self.taskRunning = false;
@@ -229,7 +249,7 @@ app.registerExtension({
229
249
  default:
230
250
  const registeredTypes = socket.registeredTypes || new Set();
231
251
  const reportedUnknownMessageTypes = socket.reportedUnknownMessageTypes || new Set();
232
-
252
+
233
253
  if (registeredTypes.has(msg.type)) {
234
254
  app.dispatchEvent(
235
255
  new CustomEvent(msg.type, { detail: msg.data })
@@ -244,7 +264,7 @@ app.registerExtension({
244
264
  console.warn('Unhandled message:', event.data, error);
245
265
  }
246
266
  };
247
-
267
+
248
268
  socket.onerror = function(error) {
249
269
  console.log('WebSocket 错误:', error);
250
270
  // 清除连接中标志
@@ -252,7 +272,7 @@ app.registerExtension({
252
272
  // 停止心跳
253
273
  self.stopPing();
254
274
  };
255
-
275
+
256
276
  socket.onclose = function(event) {
257
277
  console.log('WebSocket 连接已关闭, 状态码:', event.code, event.reason);
258
278
  // 清除连接中标志
@@ -264,10 +284,10 @@ app.registerExtension({
264
284
  // 停止心跳
265
285
  self.stopPing();
266
286
  };
267
-
287
+
268
288
  socket.registeredTypes = new Set();
269
289
  socket.reportedUnknownMessageTypes = new Set();
270
-
290
+
271
291
  // 返回创建的socket,但不要立即使用,等待onopen
272
292
  return socket;
273
293
  } catch (error) {
@@ -288,7 +308,7 @@ app.registerExtension({
288
308
  resolve(this.socket);
289
309
  return;
290
310
  }
291
-
311
+
292
312
  // 如果连接正在创建中,等待一段时间后检查
293
313
  if (this.isConnecting) {
294
314
  console.log('WebSocket连接创建中,等待...');
@@ -303,26 +323,26 @@ app.registerExtension({
303
323
  }, 100); // 每100ms检查一次
304
324
  return;
305
325
  }
306
-
326
+
307
327
  // 创建新连接
308
328
  const socket = this.createSocket(customUrl);
309
329
  if (!socket) {
310
330
  reject(new Error('创建WebSocket连接失败'));
311
331
  return;
312
332
  }
313
-
333
+
314
334
  // 监听连接打开事件
315
335
  socket.addEventListener('open', () => {
316
336
  resolve(socket);
317
337
  });
318
-
338
+
319
339
  // 监听错误事件
320
340
  socket.addEventListener('error', (error) => {
321
341
  reject(error);
322
342
  });
323
343
  });
324
344
  },
325
-
345
+
326
346
  /**
327
347
  * 获取可用的socket连接,如果不存在则创建
328
348
  * 同步版本,可能返回尚未就绪的连接
@@ -332,7 +352,7 @@ app.registerExtension({
332
352
  if (this.socket && this.socket.readyState === WebSocket.OPEN) {
333
353
  return this.socket;
334
354
  }
335
-
355
+
336
356
  // 创建新连接
337
357
  return this.createSocket(customUrl);
338
358
  },
@@ -344,7 +364,7 @@ app.registerExtension({
344
364
  closeSocket(code) {
345
365
  // 先停止心跳
346
366
  this.stopPing();
347
-
367
+
348
368
  if (this.socket) {
349
369
  if (this.socket.readyState === WebSocket.OPEN || this.socket.readyState === WebSocket.CONNECTING) {
350
370
  console.log('关闭WebSocket连接');
@@ -352,10 +372,10 @@ app.registerExtension({
352
372
  }
353
373
  this.socket = null;
354
374
  }
355
-
375
+
356
376
  // 重置任务状态
357
377
  this.taskRunning = false;
358
-
378
+
359
379
  return true;
360
380
  },
361
381
 
@@ -365,7 +385,7 @@ app.registerExtension({
365
385
  changeSocketUrl(newUrl) {
366
386
  const clientId = sessionStorage.getItem("clientId");
367
387
  const fullUrl = newUrl + "?clientId=" + clientId + "&a=1";
368
-
388
+
369
389
  return this.createSocket(fullUrl);
370
390
  },
371
391
 
@@ -402,7 +422,7 @@ app.registerExtension({
402
422
  return false;
403
423
  }
404
424
  },
405
-
425
+
406
426
  getCookie(name) {
407
427
  const value = `; ${document.cookie}`;
408
428
  const parts = value.split(`; ${name}=`);
@@ -411,14 +431,11 @@ app.registerExtension({
411
431
 
412
432
  async setup() {
413
433
  const createSocket = this.createSocket.bind(this);
414
- const getSocket = this.getSocket.bind(this);
415
- const getSocketAsync = this.getSocketAsync.bind(this);
416
434
  const closeSocket = this.closeSocket.bind(this);
417
- const changeSocketUrl = this.changeSocketUrl.bind(this);
418
- const sendSocketMessage = this.sendSocketMessage.bind(this);
419
- const sendPrompt = this.sendPrompt.bind(this);
420
- const startPing = this.startPing.bind(this);
421
- const stopPing = this.stopPing.bind(this);
435
+
436
+ const customErrorStyles = new Map()
437
+
438
+
422
439
 
423
440
  // 方法映射
424
441
  const methods = {
@@ -432,26 +449,6 @@ app.registerExtension({
432
449
  return socket;
433
450
  },
434
451
 
435
- startSocket: async function (params) {
436
- try {
437
- const socket = await getSocketAsync(params.url);
438
- window.parent.postMessage({
439
- type: 'functionResult',
440
- method: 'startSocket',
441
- result: 'Socket连接已启动'
442
- }, '*');
443
- return socket;
444
- } catch (error) {
445
- window.parent.postMessage({
446
- type: 'functionResult',
447
- method: 'startSocket',
448
- result: 'Socket连接失败: ' + error.message,
449
- error: true
450
- }, '*');
451
- return null;
452
- }
453
- },
454
-
455
452
  closeSocket: function () {
456
453
  const result = closeSocket();
457
454
  window.parent.postMessage({
@@ -462,34 +459,6 @@ app.registerExtension({
462
459
  return result;
463
460
  },
464
461
 
465
- changeSocketUrl: function (params) {
466
- if (!params.url) {
467
- console.error('缺少url参数');
468
- return false;
469
- }
470
- const socket = changeSocketUrl(params.url);
471
- window.parent.postMessage({
472
- type: 'functionResult',
473
- method: 'changeSocketUrl',
474
- result: 'Socket URL已更改为' + params.url
475
- }, '*');
476
- return socket;
477
- },
478
-
479
- sendSocketMessage: async function (params) {
480
- if (!params.message) {
481
- console.error('缺少message参数');
482
- return false;
483
- }
484
- const result = await sendSocketMessage(params.message);
485
- window.parent.postMessage({
486
- type: 'functionResult',
487
- method: 'sendSocketMessage',
488
- result: result ? '消息发送成功' : '消息发送失败'
489
- }, '*');
490
- return result;
491
- },
492
-
493
462
  clearCanvas: function () {
494
463
  app.graph.clear();
495
464
  window.parent.postMessage({
@@ -499,11 +468,10 @@ app.registerExtension({
499
468
  }, '*');
500
469
  return true;
501
470
  },
502
-
503
471
  loadWorkflow: function (params) {
504
472
  app.graph.clear();
505
- document.dispatchEvent(new CustomEvent('workflowLoaded', {
506
- detail: params
473
+ document.dispatchEvent(new CustomEvent('workflowLoaded', {
474
+ detail: params.json
507
475
  }));
508
476
  if (params.json.version) {
509
477
  app.loadGraphData(params.json);
@@ -537,6 +505,19 @@ app.registerExtension({
537
505
  }, '*');
538
506
  return graph.workflow;
539
507
  },
508
+ // 新增:获取 workflow 和 output
509
+ getWorkflowWithOutput: async function () {
510
+ const graph = await app.graphToPrompt();
511
+ window.parent.postMessage({
512
+ type: 'functionResult',
513
+ method: 'getWorkflowWithOutput',
514
+ result: {
515
+ workflow: graph.workflow,
516
+ output: graph.output
517
+ }
518
+ }, '*');
519
+ return { workflow: graph.workflow, output: graph.output };
520
+ },
540
521
  saveApiJson: async function (params) {
541
522
  const graph = await app.graphToPrompt();
542
523
  window.parent.postMessage({
@@ -559,9 +540,10 @@ app.registerExtension({
559
540
  try {
560
541
  // 确保有连接
561
542
  // await getSocketAsync();
562
-
543
+
563
544
  const graph = await app.graphToPrompt();
564
545
  const clientId = sessionStorage.getItem("clientId");
546
+ await app.queuePrompt(graph.output);
565
547
  const resPrompt = await fetch("api/prompt", {
566
548
  method: "POST",
567
549
  body: JSON.stringify({
@@ -577,8 +559,45 @@ app.registerExtension({
577
559
  });
578
560
  const resPromptJson = await resPrompt.json();
579
561
  if (resPromptJson.error) {
580
- await app.queuePrompt(graph.output);
562
+ this.openCustomError({
563
+ nodeId: resPromptJson.node_id,
564
+ nodeType: resPromptJson.node_type,
565
+ errorMessage: resPromptJson.error,
566
+ borderColor: '#FF0000'
567
+ })
568
+ return
569
+ }
570
+
571
+ for (const i in resPromptJson.node_errors) {
572
+
573
+ if (resPromptJson.node_errors[i].errors) {
574
+ const err = resPromptJson.node_errors[i].errors[0]
575
+ if (err) return
576
+ this.openCustomError({
577
+ nodeId: i,
578
+ nodeType: err.type,
579
+ errorMessage: err.error,
580
+ borderColor: '#FF0000'
581
+ })
582
+ return
583
+ } else {
584
+ console.log(resPromptJson.node_errors[i])
585
+ }
581
586
  }
587
+
588
+ if (Object.keys(resPromptJson.node_errors).length) return
589
+ graph.workflow.nodes.forEach(node => {
590
+ for (const key in graph.output) {
591
+ if (graph.output[key].class_type === node.type) {
592
+ if (!graph.output[key]._meta) {
593
+ graph.output[key]._meta = {};
594
+ }
595
+ graph.output[key]._meta.id = node.id;
596
+ break; // 找到匹配的就跳出循环
597
+ }
598
+ }
599
+ });
600
+ console.log(graph.output)
582
601
  window.parent.postMessage({
583
602
  type: 'functionResult',
584
603
  method: 'runWorkflow',
@@ -611,7 +630,8 @@ app.registerExtension({
611
630
  }
612
631
  document.cookie = name + "=" + (value || "") + expires + "; path=/";
613
632
  };
614
- console.log("-----------setCookie-----------", params)
633
+ // console.log("-----------setCookie-----------", params)
634
+ // console.log("-----------setCookie-----------", params)
615
635
  setCookie(params.name, params.value, params.days);
616
636
 
617
637
 
@@ -675,11 +695,13 @@ app.registerExtension({
675
695
  return graph.workflow;
676
696
  },
677
697
 
678
- graphToPrompt: async function () {
698
+ graphToPrompt: async function (params) {
699
+ console.log('postEvent.js - graphToPrompt被调用,参数:', params);
679
700
  const graph = await app.graphToPrompt();
680
701
  window.parent.postMessage({
681
702
  type: 'functionResult',
682
703
  method: 'graphToPrompt',
704
+ params: params, // 传递原始参数
683
705
  result: {
684
706
  workflow: graph.workflow,
685
707
  output: graph.output
@@ -703,8 +725,204 @@ app.registerExtension({
703
725
  }, '*');
704
726
  return true;
705
727
  },
728
+
729
+ // AI应用相关方法
730
+ toggleAIAppMode: function(params) {
731
+ const enable = params.enable === true;
732
+ const result = enable ? enableAIAppMode() : disableAIAppMode();
733
+ window.parent.postMessage({
734
+ type: 'functionResult',
735
+ method: 'toggleAIAppMode',
736
+ result: result
737
+ }, '*');
738
+ return result;
739
+ },
740
+
741
+ selectInputNode: function(params) {
742
+ if (!params.nodeId) return false;
743
+ const result = selectInputNode(params.nodeId);
744
+ window.parent.postMessage({
745
+ type: 'functionResult',
746
+ method: 'selectInputNode',
747
+ result: result
748
+ }, '*');
749
+ return result;
750
+ },
751
+
752
+ selectExportNode: function(params) {
753
+ if (!params.nodeId) return false;
754
+ const result = selectInputNode(params.nodeId);
755
+ window.parent.postMessage({
756
+ type: 'functionResult',
757
+ method: 'selectExportNode',
758
+ result: result
759
+ }, '*');
760
+ return result;
761
+ },
762
+
763
+ deselectInputNode: function(params) {
764
+ if (!params.nodeId) return false;
765
+ const result = deselectInputNode(params.nodeId);
766
+ window.parent.postMessage({
767
+ type: 'functionResult',
768
+ method: 'deselectInputNode',
769
+ result: result
770
+ }, '*');
771
+ return result;
772
+ },
773
+
774
+ updateInputNodeWidget: function(params) {
775
+ if (!params.nodeId || params.widgetName === undefined) return false;
776
+ const result = updateInputNodeWidget(params.nodeId, params.widgetName, params.value);
777
+ window.parent.postMessage({
778
+ type: 'functionResult',
779
+ method: 'updateInputNodeWidget',
780
+ result: result
781
+ }, '*');
782
+ return result;
783
+ },
784
+
785
+ getInputNodes: function() {
786
+ const result = getSelectedInputNodes();
787
+ window.parent.postMessage({
788
+ type: 'functionResult',
789
+ method: 'getInputNodes',
790
+ result: result
791
+ }, '*');
792
+ return result;
793
+ },
794
+
795
+ clearInputNodes: function() {
796
+ const result = clearSelectedInputNodes();
797
+ window.parent.postMessage({
798
+ type: 'functionResult',
799
+ method: 'clearInputNodes',
800
+ result: result
801
+ }, '*');
802
+ return result;
803
+ },
804
+ toggleExportMode: function(params) {
805
+ const result = toggleExportMode(params);
806
+ window.parent.postMessage({
807
+ type: 'functionResult',
808
+ method: 'toggleExportMode',
809
+ result: result
810
+ }, '*');
811
+ return result;
812
+ },
813
+ openCustomError: function (params) {
814
+ const { nodeId, nodeType, errorMessage, borderColor='#FF0000' } = params;
815
+ const nodeIds = Array.isArray(nodeId) ? nodeId : [nodeId];
816
+ function injectErrorDialogStyles() {
817
+ const styleId = 'custom-error-dialog-styles';
818
+ if (document.getElementById(styleId)) {
819
+ return; // 样式已经存在
820
+ }
821
+
822
+ const style = document.createElement('style');
823
+ style.id = styleId;
824
+ style.textContent = `
825
+ .comfy-error-report .no-results-placeholder p {
826
+ text-align: left;
827
+ }
828
+ `;
829
+ document.head.appendChild(style);
830
+ };
831
+ injectErrorDialogStyles()
832
+ function simulateExecutionError(nodeId, nodeType, errorMessage, borderColor) {
833
+ // const originalNodeErrorStyle = node.strokeStyles?.['nodeError']
834
+ const node = app.graph.getNodeById(nodeId)
835
+ if (!node) return
836
+ if (!customErrorStyles.has(nodeId)) {
837
+ customErrorStyles.set(nodeId, {
838
+ originalStyle: node.strokeStyles?.['nodeError'],
839
+ customColor: borderColor,
840
+ nodeId: nodeId
841
+ })
842
+ }
843
+ node.strokeStyles = node.strokeStyles || {}
844
+ node.strokeStyles['nodeError'] = function () {
845
+ // if (this.id === nodeId) {
846
+ return { color: borderColor, lineWidth: 2 } // 自定义颜色和线宽
847
+ // }
848
+ }
849
+ const mockErrorEvent = {
850
+ detail: {
851
+ node_id: nodeId,
852
+ node_type: nodeType,
853
+ exception_message: errorMessage,
854
+ exception_type: 'ManualError',
855
+ traceback: ['Manual error triggered'],
856
+ executed: [],
857
+ prompt_id: 'manual',
858
+ timestamp: Date.now()
859
+ }
860
+ }
861
+
862
+ // 手动触发事件监听器
863
+ app.api.dispatchCustomEvent('execution_error', mockErrorEvent.detail)
864
+ }
865
+
866
+ nodeIds.forEach(id => {
867
+ simulateExecutionError(id, nodeType, errorMessage, borderColor)
868
+ })
869
+
870
+ app.canvas.draw(true, true)
871
+ window.parent.postMessage({
872
+ type: 'functionResult',
873
+ method: 'openCustomError',
874
+ result: true
875
+ }, '*');
876
+ },
877
+ clearAllCustomStyles: function () {
878
+ customErrorStyles.forEach((styleInfo, nodeId) => {
879
+ const node = app.graph.getNodeById(nodeId)
880
+ if (!node) return
881
+ console.log(node)
882
+ // 恢复原始样式
883
+ if (styleInfo.originalStyle) {
884
+ node.strokeStyles['nodeError'] = styleInfo.originalStyle
885
+ } else {
886
+ delete node.strokeStyles['nodeError']
887
+ }
888
+
889
+ // 从映射中移除
890
+ customErrorStyles.delete(nodeId)
891
+ })
892
+
893
+ // 重绘画布
894
+ app.canvas.draw(true, true)
895
+ },
896
+ focusNodeOnly: function(params) {
897
+ if (!params.nodeId) return false;
898
+ const result = focusNodeOnly(params.nodeId);
899
+ window.parent.postMessage({
900
+ type: 'functionResult',
901
+ method: 'focusNodeOnly',
902
+ result: result
903
+ }, '*');
904
+ return result;
905
+ },
706
906
  };
707
907
 
908
+ methods.deselectExportNode = function(params) {
909
+ if (params && params.nodeId !== undefined) {
910
+ if (typeof window.deselectInputNode === 'function') {
911
+ window.deselectInputNode(params.nodeId);
912
+ }
913
+ }
914
+ };
915
+ methods.clearExportNodes = function() {
916
+ if (typeof window.clearExportNodes === 'function') {
917
+ window.clearExportNodes();
918
+ }
919
+ };
920
+ // 保存工作流的原始节点颜色信息
921
+ methods.saveOriginalNodeColors = function(params) {
922
+ if (typeof window.saveOriginalNodeColors === 'function') {
923
+ window.saveOriginalNodeColors(params.workflowId);
924
+ }
925
+ };
708
926
  window.addEventListener('message', function (event) {
709
927
  if (event.data && event.data.type === 'callMethod') {
710
928
  const methodName = event.data.method;
@@ -732,5 +950,17 @@ app.registerExtension({
732
950
  }
733
951
  });
734
952
  window.parent.postMessage({ type: 'iframeReady' }, '*');
953
+ app.api.addEventListener('graphChanged', (e) => {
954
+ console.log('Graph 发生变化,当前 workflow JSON:', e.detail)
955
+ window.parent.postMessage({
956
+ type: 'functionResult',
957
+ method: 'workflowChanged',
958
+ result: e.detail
959
+ }, '*');
960
+
961
+ document.dispatchEvent(new CustomEvent('workflowLoaded', {
962
+ detail: e.detail
963
+ }));
964
+ })
735
965
  }
736
966
  });