@electerm/electerm-react 2.3.151 → 2.3.176

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 (56) hide show
  1. package/client/common/constants.js +4 -2
  2. package/client/common/db.js +2 -1
  3. package/client/common/download.jsx +1 -1
  4. package/client/common/error-handler.jsx +1 -1
  5. package/client/common/fetch.jsx +1 -1
  6. package/client/common/init-setting-item.js +7 -0
  7. package/client/components/common/modal.jsx +89 -0
  8. package/client/components/common/modal.styl +77 -0
  9. package/client/components/common/notification-with-details.jsx +34 -0
  10. package/client/components/file-transfer/conflict-resolve.jsx +2 -1
  11. package/client/components/file-transfer/transfer-speed-format.js +6 -0
  12. package/client/components/file-transfer/transfer.jsx +5 -2
  13. package/client/components/file-transfer/transports-action-store.jsx +14 -1
  14. package/client/components/main/connection-hopping-warnning.jsx +1 -1
  15. package/client/components/main/main.jsx +2 -0
  16. package/client/components/quick-commands/qm.styl +0 -10
  17. package/client/components/quick-commands/quick-command-item.jsx +2 -5
  18. package/client/components/quick-commands/quick-commands-box.jsx +12 -23
  19. package/client/components/setting-panel/setting-common.jsx +4 -3
  20. package/client/components/setting-panel/setting-modal.jsx +2 -1
  21. package/client/components/setting-panel/start-session-select.jsx +146 -21
  22. package/client/components/setting-panel/text-bg-modal.jsx +15 -4
  23. package/client/components/setting-sync/setting-sync-form.jsx +1 -1
  24. package/client/components/sftp/file-info-modal.jsx +2 -1
  25. package/client/components/sftp/file-item.jsx +2 -0
  26. package/client/components/sftp/sftp-entry.jsx +1 -1
  27. package/client/components/sftp/sftp.styl +1 -1
  28. package/client/components/sidebar/info-modal.jsx +53 -34
  29. package/client/components/sidebar/info.styl +0 -7
  30. package/client/components/ssh-config/ssh-config-load-notify.jsx +1 -1
  31. package/client/components/tabs/index.jsx +6 -58
  32. package/client/components/tabs/layout-menu.jsx +75 -0
  33. package/client/components/tabs/layout-select.jsx +60 -0
  34. package/client/components/tabs/tabs.styl +64 -0
  35. package/client/components/tabs/workspace-save-modal.jsx +117 -0
  36. package/client/components/tabs/workspace-select.jsx +79 -0
  37. package/client/components/terminal/attach-addon-custom.js +7 -1
  38. package/client/components/terminal/terminal-interactive.jsx +2 -1
  39. package/client/components/terminal/terminal.jsx +1 -2
  40. package/client/components/text-editor/text-editor.jsx +2 -1
  41. package/client/components/tree-list/move-item-modal.jsx +2 -1
  42. package/client/components/vnc/vnc-session.jsx +2 -2
  43. package/client/components/widgets/widget-control.jsx +12 -6
  44. package/client/components/widgets/widget-form.jsx +16 -18
  45. package/client/components/widgets/widget-instance.jsx +44 -9
  46. package/client/components/widgets/widget-notification-with-details.jsx +34 -0
  47. package/client/css/basic.styl +3 -1
  48. package/client/css/includes/box.styl +2 -2
  49. package/client/store/common.js +9 -5
  50. package/client/store/init-state.js +4 -0
  51. package/client/store/load-data.js +15 -6
  52. package/client/store/mcp-handler.js +640 -0
  53. package/client/store/store.js +4 -0
  54. package/client/store/widgets.js +4 -0
  55. package/client/store/workspace.js +108 -0
  56. package/package.json +1 -1
@@ -115,13 +115,22 @@ export async function addTabFromCommandLine (store, opts) {
115
115
  export default (Store) => {
116
116
  Store.prototype.openInitSessions = function () {
117
117
  const { store } = window
118
- const arr = store.config.onStartSessions || []
119
- for (const s of arr) {
120
- store.onSelectBookmark(s)
121
- }
122
- if (!arr.length && store.config.initDefaultTabOnStart) {
123
- store.initFirstTab()
118
+ const onStartSessions = store.config.onStartSessions
119
+
120
+ // If onStartSessions is a string, it's a workspace ID
121
+ if (typeof onStartSessions === 'string' && onStartSessions) {
122
+ store.loadWorkspace(onStartSessions)
123
+ } else {
124
+ // Otherwise, it's an array of bookmark IDs
125
+ const arr = Array.isArray(onStartSessions) ? onStartSessions : []
126
+ for (const s of arr) {
127
+ store.onSelectBookmark(s)
128
+ }
129
+ if (!arr.length && store.config.initDefaultTabOnStart) {
130
+ store.initFirstTab()
131
+ }
124
132
  }
133
+
125
134
  store.confirmLoad()
126
135
  const { initTime, loadTime } = window.pre.runSync('getLoadTime')
127
136
  if (loadTime) {
@@ -0,0 +1,640 @@
1
+ /**
2
+ * MCP (Model Context Protocol) handler for store
3
+ * Handles IPC requests from the MCP server widget
4
+ */
5
+
6
+ import uid from '../common/uid'
7
+ import { settingMap } from '../common/constants'
8
+
9
+ export default Store => {
10
+ // Initialize MCP handler - called when MCP widget is started
11
+ Store.prototype.initMcpHandler = function () {
12
+ const { ipcOnEvent } = window.pre
13
+ // Listen for MCP requests from main process
14
+ ipcOnEvent('mcp-request', (event, request) => {
15
+ const { requestId, action, data } = request
16
+ if (action === 'tool-call') {
17
+ window.store.handleMcpToolCall(requestId, data.toolName, data.args)
18
+ }
19
+ })
20
+ }
21
+
22
+ // Handle individual tool calls
23
+ Store.prototype.handleMcpToolCall = async function (requestId, toolName, args) {
24
+ const { store } = window
25
+
26
+ try {
27
+ let result
28
+
29
+ switch (toolName) {
30
+ // Bookmark operations
31
+ case 'list_bookmarks':
32
+ result = store.mcpListBookmarks(args)
33
+ break
34
+ case 'get_bookmark':
35
+ result = store.mcpGetBookmark(args)
36
+ break
37
+ case 'add_bookmark':
38
+ result = await store.mcpAddBookmark(args)
39
+ break
40
+ case 'edit_bookmark':
41
+ result = store.mcpEditBookmark(args)
42
+ break
43
+ case 'delete_bookmark':
44
+ result = store.mcpDeleteBookmark(args)
45
+ break
46
+ case 'open_bookmark':
47
+ result = store.mcpOpenBookmark(args)
48
+ break
49
+
50
+ // Bookmark group operations
51
+ case 'list_bookmark_groups':
52
+ result = store.mcpListBookmarkGroups()
53
+ break
54
+ case 'add_bookmark_group':
55
+ result = await store.mcpAddBookmarkGroup(args)
56
+ break
57
+
58
+ // Quick command operations
59
+ case 'list_quick_commands':
60
+ result = store.mcpListQuickCommands()
61
+ break
62
+ case 'add_quick_command':
63
+ result = store.mcpAddQuickCommand(args)
64
+ break
65
+ case 'run_quick_command':
66
+ result = store.mcpRunQuickCommand(args)
67
+ break
68
+ case 'delete_quick_command':
69
+ result = store.mcpDeleteQuickCommand(args)
70
+ break
71
+
72
+ // Tab operations
73
+ case 'list_tabs':
74
+ result = store.mcpListTabs()
75
+ break
76
+ case 'get_active_tab':
77
+ result = store.mcpGetActiveTab()
78
+ break
79
+ case 'switch_tab':
80
+ result = store.mcpSwitchTab(args)
81
+ break
82
+ case 'close_tab':
83
+ result = store.mcpCloseTab(args)
84
+ break
85
+ case 'reload_tab':
86
+ result = store.mcpReloadTab(args)
87
+ break
88
+ case 'duplicate_tab':
89
+ result = store.mcpDuplicateTab(args)
90
+ break
91
+ case 'open_local_terminal':
92
+ result = store.mcpOpenLocalTerminal()
93
+ break
94
+
95
+ // Terminal operations
96
+ case 'send_terminal_command':
97
+ result = store.mcpSendTerminalCommand(args)
98
+ break
99
+ case 'get_terminal_selection':
100
+ result = store.mcpGetTerminalSelection(args)
101
+ break
102
+ case 'get_terminal_output':
103
+ result = store.mcpGetTerminalOutput(args)
104
+ break
105
+
106
+ // History operations
107
+ case 'list_history':
108
+ result = store.mcpListHistory(args)
109
+ break
110
+ case 'clear_history':
111
+ result = store.mcpClearHistory()
112
+ break
113
+
114
+ // Transfer operations
115
+ case 'list_transfers':
116
+ result = store.mcpListTransfers()
117
+ break
118
+ case 'list_transfer_history':
119
+ result = store.mcpListTransferHistory(args)
120
+ break
121
+
122
+ // Settings operations
123
+ case 'get_settings':
124
+ result = store.mcpGetSettings()
125
+ break
126
+ case 'list_terminal_themes':
127
+ result = store.mcpListTerminalThemes()
128
+ break
129
+ case 'list_ui_themes':
130
+ result = store.mcpListUiThemes()
131
+ break
132
+
133
+ default:
134
+ throw new Error(`Unknown tool: ${toolName}`)
135
+ }
136
+
137
+ window.api.sendMcpResponse({
138
+ requestId,
139
+ result
140
+ })
141
+ } catch (error) {
142
+ window.api.sendMcpResponse({
143
+ requestId,
144
+ error: error.message
145
+ })
146
+ }
147
+ }
148
+
149
+ // ==================== Bookmark APIs ====================
150
+
151
+ Store.prototype.mcpListBookmarks = function (args = {}) {
152
+ const { store } = window
153
+ let bookmarks = store.bookmarks
154
+
155
+ if (args.groupId) {
156
+ const group = store.bookmarkGroups.find(g => g.id === args.groupId)
157
+ if (group && group.bookmarkIds) {
158
+ const idSet = new Set(group.bookmarkIds)
159
+ bookmarks = bookmarks.filter(b => idSet.has(b.id))
160
+ }
161
+ }
162
+
163
+ return bookmarks.map(b => ({
164
+ id: b.id,
165
+ title: b.title,
166
+ host: b.host,
167
+ port: b.port,
168
+ username: b.username,
169
+ type: b.type || 'ssh',
170
+ color: b.color
171
+ }))
172
+ }
173
+
174
+ Store.prototype.mcpGetBookmark = function (args) {
175
+ const { store } = window
176
+ const bookmark = store.bookmarks.find(b => b.id === args.id)
177
+ if (!bookmark) {
178
+ throw new Error(`Bookmark not found: ${args.id}`)
179
+ }
180
+ // Return bookmark without sensitive data
181
+ const { password, passphrase, privateKey, ...safeBookmark } = bookmark
182
+ return safeBookmark
183
+ }
184
+
185
+ Store.prototype.mcpAddBookmark = async function (args) {
186
+ const { store } = window
187
+ const bookmark = {
188
+ id: uid(),
189
+ title: args.title,
190
+ host: args.host || '',
191
+ port: args.port || 22,
192
+ username: args.username || '',
193
+ password: args.password || '',
194
+ type: args.type || 'local',
195
+ term: 'xterm-256color',
196
+ ...args
197
+ }
198
+
199
+ store.addItem(bookmark, settingMap.bookmarks)
200
+
201
+ return {
202
+ success: true,
203
+ id: bookmark.id,
204
+ message: `Bookmark "${bookmark.title}" created`
205
+ }
206
+ }
207
+
208
+ Store.prototype.mcpEditBookmark = function (args) {
209
+ const { store } = window
210
+ const { id, updates } = args
211
+
212
+ const bookmark = store.bookmarks.find(b => b.id === id)
213
+ if (!bookmark) {
214
+ throw new Error(`Bookmark not found: ${id}`)
215
+ }
216
+
217
+ store.editItem(id, updates, settingMap.bookmarks)
218
+
219
+ return {
220
+ success: true,
221
+ message: `Bookmark "${bookmark.title}" updated`
222
+ }
223
+ }
224
+
225
+ Store.prototype.mcpDeleteBookmark = function (args) {
226
+ const { store } = window
227
+ const bookmark = store.bookmarks.find(b => b.id === args.id)
228
+ if (!bookmark) {
229
+ throw new Error(`Bookmark not found: ${args.id}`)
230
+ }
231
+
232
+ store.delItem({ id: args.id }, settingMap.bookmarks)
233
+
234
+ return {
235
+ success: true,
236
+ message: `Bookmark "${bookmark.title}" deleted`
237
+ }
238
+ }
239
+
240
+ Store.prototype.mcpOpenBookmark = function (args) {
241
+ const { store } = window
242
+ const bookmark = store.bookmarks.find(b => b.id === args.id)
243
+ if (!bookmark) {
244
+ throw new Error(`Bookmark not found: ${args.id}`)
245
+ }
246
+
247
+ store.onSelectBookmark(args.id)
248
+
249
+ return {
250
+ success: true,
251
+ message: `Opened bookmark "${bookmark.title}"`
252
+ }
253
+ }
254
+
255
+ // ==================== Bookmark Group APIs ====================
256
+
257
+ Store.prototype.mcpListBookmarkGroups = function () {
258
+ const { store } = window
259
+ return store.bookmarkGroups.map(g => ({
260
+ id: g.id,
261
+ title: g.title,
262
+ level: g.level,
263
+ bookmarkCount: (g.bookmarkIds || []).length,
264
+ subgroupCount: (g.bookmarkGroupIds || []).length
265
+ }))
266
+ }
267
+
268
+ Store.prototype.mcpAddBookmarkGroup = async function (args) {
269
+ const { store } = window
270
+ const group = {
271
+ id: uid(),
272
+ title: args.title,
273
+ bookmarkIds: [],
274
+ bookmarkGroupIds: [],
275
+ level: args.parentId ? 2 : 1
276
+ }
277
+
278
+ await store.addBookmarkGroup(group)
279
+
280
+ return {
281
+ success: true,
282
+ id: group.id,
283
+ message: `Bookmark group "${group.title}" created`
284
+ }
285
+ }
286
+
287
+ // ==================== Quick Command APIs ====================
288
+
289
+ Store.prototype.mcpListQuickCommands = function () {
290
+ const { store } = window
291
+ return store.quickCommands.map(q => ({
292
+ id: q.id,
293
+ name: q.name,
294
+ command: q.command,
295
+ commands: q.commands,
296
+ inputOnly: q.inputOnly,
297
+ labels: q.labels
298
+ }))
299
+ }
300
+
301
+ Store.prototype.mcpAddQuickCommand = function (args) {
302
+ const { store } = window
303
+ const qm = {
304
+ id: uid(),
305
+ name: args.name,
306
+ command: args.command,
307
+ inputOnly: args.inputOnly || false,
308
+ labels: args.labels || []
309
+ }
310
+
311
+ store.addQuickCommand(qm)
312
+
313
+ return {
314
+ success: true,
315
+ id: qm.id,
316
+ message: `Quick command "${qm.name}" created`
317
+ }
318
+ }
319
+
320
+ Store.prototype.mcpRunQuickCommand = function (args) {
321
+ const { store } = window
322
+ const qm = store.quickCommands.find(q => q.id === args.id)
323
+ if (!qm) {
324
+ throw new Error(`Quick command not found: ${args.id}`)
325
+ }
326
+
327
+ store.runQuickCommandItem(args.id)
328
+
329
+ return {
330
+ success: true,
331
+ message: `Executed quick command "${qm.name}"`
332
+ }
333
+ }
334
+
335
+ Store.prototype.mcpDeleteQuickCommand = function (args) {
336
+ const { store } = window
337
+ const qm = store.quickCommands.find(q => q.id === args.id)
338
+ if (!qm) {
339
+ throw new Error(`Quick command not found: ${args.id}`)
340
+ }
341
+
342
+ store.delQuickCommand({ id: args.id })
343
+
344
+ return {
345
+ success: true,
346
+ message: `Deleted quick command "${qm.name}"`
347
+ }
348
+ }
349
+
350
+ // ==================== Tab APIs ====================
351
+
352
+ Store.prototype.mcpListTabs = function () {
353
+ const { store } = window
354
+ return store.tabs.map(t => ({
355
+ id: t.id,
356
+ title: t.title,
357
+ host: t.host,
358
+ type: t.type || 'local',
359
+ status: t.status,
360
+ isTransporting: t.isTransporting,
361
+ batch: t.batch
362
+ }))
363
+ }
364
+
365
+ Store.prototype.mcpGetActiveTab = function () {
366
+ const { store } = window
367
+ const tab = store.currentTab
368
+ if (!tab) {
369
+ return { activeTabId: null, tab: null }
370
+ }
371
+ return {
372
+ activeTabId: store.activeTabId,
373
+ tab: {
374
+ id: tab.id,
375
+ title: tab.title,
376
+ host: tab.host,
377
+ type: tab.type || 'local',
378
+ status: tab.status
379
+ }
380
+ }
381
+ }
382
+
383
+ Store.prototype.mcpSwitchTab = function (args) {
384
+ const { store } = window
385
+ const tab = store.tabs.find(t => t.id === args.tabId)
386
+ if (!tab) {
387
+ throw new Error(`Tab not found: ${args.tabId}`)
388
+ }
389
+
390
+ store.activeTabId = args.tabId
391
+ if (tab.batch !== undefined) {
392
+ store[`activeTabId${tab.batch}`] = args.tabId
393
+ }
394
+
395
+ return {
396
+ success: true,
397
+ message: `Switched to tab "${tab.title}"`
398
+ }
399
+ }
400
+
401
+ Store.prototype.mcpCloseTab = function (args) {
402
+ const { store } = window
403
+ const tab = store.tabs.find(t => t.id === args.tabId)
404
+ if (!tab) {
405
+ throw new Error(`Tab not found: ${args.tabId}`)
406
+ }
407
+
408
+ store.delTab(args.tabId)
409
+
410
+ return {
411
+ success: true,
412
+ message: `Closed tab "${tab.title}"`
413
+ }
414
+ }
415
+
416
+ Store.prototype.mcpReloadTab = function (args) {
417
+ const { store } = window
418
+ const tabId = args.tabId || store.activeTabId
419
+ const tab = store.tabs.find(t => t.id === tabId)
420
+ if (!tab) {
421
+ throw new Error(`Tab not found: ${tabId}`)
422
+ }
423
+
424
+ store.reloadTab(tabId)
425
+
426
+ return {
427
+ success: true,
428
+ message: `Reloaded tab "${tab.title}"`
429
+ }
430
+ }
431
+
432
+ Store.prototype.mcpDuplicateTab = function (args) {
433
+ const { store } = window
434
+ const tab = store.tabs.find(t => t.id === args.tabId)
435
+ if (!tab) {
436
+ throw new Error(`Tab not found: ${args.tabId}`)
437
+ }
438
+
439
+ store.duplicateTab(args.tabId)
440
+
441
+ return {
442
+ success: true,
443
+ message: `Duplicated tab "${tab.title}"`
444
+ }
445
+ }
446
+
447
+ Store.prototype.mcpOpenLocalTerminal = function () {
448
+ const { store } = window
449
+ store.addTab()
450
+ const newTabId = store.activeTabId
451
+
452
+ return {
453
+ success: true,
454
+ tabId: newTabId,
455
+ message: 'Opened new local terminal'
456
+ }
457
+ }
458
+
459
+ // ==================== Terminal APIs ====================
460
+
461
+ Store.prototype.mcpSendTerminalCommand = function (args) {
462
+ const { store } = window
463
+ const tabId = args.tabId || store.activeTabId
464
+ const command = args.command
465
+
466
+ if (!tabId) {
467
+ throw new Error('No active terminal')
468
+ }
469
+
470
+ if (command === undefined || command === null) {
471
+ throw new Error('No command provided')
472
+ }
473
+
474
+ store.runQuickCommand(command, args.inputOnly || false)
475
+
476
+ return {
477
+ success: true,
478
+ message: 'Command sent to terminal'
479
+ }
480
+ }
481
+
482
+ Store.prototype.mcpGetTerminalSelection = function (args) {
483
+ const { store } = window
484
+ const { refs } = require('../components/common/ref')
485
+ const tabId = args.tabId || store.activeTabId
486
+
487
+ if (!tabId) {
488
+ throw new Error('No active terminal')
489
+ }
490
+
491
+ const term = refs.get('term-' + tabId)
492
+ if (!term || !term.term) {
493
+ throw new Error('Terminal not found')
494
+ }
495
+
496
+ const selection = term.term.getSelection()
497
+
498
+ return {
499
+ selection: selection || '',
500
+ tabId
501
+ }
502
+ }
503
+
504
+ Store.prototype.mcpGetTerminalOutput = function (args) {
505
+ const { store } = window
506
+ const { refs } = require('../components/common/ref')
507
+ const tabId = args.tabId || store.activeTabId
508
+ const lineCount = args.lines || 50
509
+
510
+ if (!tabId) {
511
+ throw new Error('No active terminal')
512
+ }
513
+
514
+ const term = refs.get('term-' + tabId)
515
+ if (!term || !term.term) {
516
+ throw new Error('Terminal not found')
517
+ }
518
+
519
+ const buffer = term.term.buffer.active
520
+ if (!buffer) {
521
+ throw new Error('Terminal buffer not available')
522
+ }
523
+
524
+ const cursorY = buffer.cursorY || 0
525
+ const baseY = buffer.baseY || 0
526
+ const totalLines = buffer.length || 0
527
+
528
+ // Calculate the actual content range
529
+ // baseY is the scroll offset, cursorY is cursor position in viewport
530
+ const actualContentEnd = baseY + cursorY + 1
531
+ const startLine = Math.max(0, actualContentEnd - lineCount)
532
+ const endLine = Math.min(totalLines, actualContentEnd)
533
+ const lines = []
534
+
535
+ for (let i = startLine; i < endLine; i++) {
536
+ const line = buffer.getLine(i)
537
+ if (line) {
538
+ const text = line.translateToString(true)
539
+ lines.push(text)
540
+ }
541
+ }
542
+
543
+ return {
544
+ output: lines.join('\n'),
545
+ lineCount: lines.length,
546
+ cursorY,
547
+ baseY,
548
+ tabId
549
+ }
550
+ }
551
+
552
+ // ==================== History APIs ====================
553
+
554
+ Store.prototype.mcpListHistory = function (args = {}) {
555
+ const { store } = window
556
+ const limit = args.limit || 50
557
+ const history = store.history.slice(0, limit)
558
+
559
+ return history.map(h => ({
560
+ id: h.id,
561
+ title: h.title,
562
+ host: h.host,
563
+ type: h.type,
564
+ time: h.time
565
+ }))
566
+ }
567
+
568
+ Store.prototype.mcpClearHistory = function () {
569
+ const { store } = window
570
+ store.history = []
571
+
572
+ return {
573
+ success: true,
574
+ message: 'History cleared'
575
+ }
576
+ }
577
+
578
+ // ==================== Transfer APIs ====================
579
+
580
+ Store.prototype.mcpListTransfers = function () {
581
+ const { store } = window
582
+ return store.fileTransfers.map(t => ({
583
+ id: t.id,
584
+ localPath: t.localPath,
585
+ remotePath: t.remotePath,
586
+ type: t.type,
587
+ percent: t.percent,
588
+ status: t.status
589
+ }))
590
+ }
591
+
592
+ Store.prototype.mcpListTransferHistory = function (args = {}) {
593
+ const { store } = window
594
+ const limit = args.limit || 50
595
+ return store.transferHistory.slice(0, limit).map(t => ({
596
+ id: t.id,
597
+ localPath: t.localPath,
598
+ remotePath: t.remotePath,
599
+ type: t.type,
600
+ status: t.status,
601
+ time: t.time
602
+ }))
603
+ }
604
+
605
+ // ==================== Settings APIs ====================
606
+
607
+ Store.prototype.mcpGetSettings = function () {
608
+ const { store } = window
609
+ // Return safe settings (no sensitive data)
610
+ const config = store.config
611
+ const safeConfig = {
612
+ theme: config.theme,
613
+ language: config.language,
614
+ fontSize: config.fontSize,
615
+ fontFamily: config.fontFamily,
616
+ terminalType: config.terminalType,
617
+ cursorStyle: config.cursorStyle,
618
+ cursorBlink: config.cursorBlink,
619
+ scrollback: config.scrollback
620
+ }
621
+ return safeConfig
622
+ }
623
+
624
+ Store.prototype.mcpListTerminalThemes = function () {
625
+ const { store } = window
626
+ return store.terminalThemes.map(t => ({
627
+ id: t.id,
628
+ name: t.name,
629
+ themeLight: t.themeLight
630
+ }))
631
+ }
632
+
633
+ Store.prototype.mcpListUiThemes = function () {
634
+ const { store } = window
635
+ return (store.uiThemes || []).map(t => ({
636
+ id: t.id,
637
+ name: t.name
638
+ }))
639
+ }
640
+ }
@@ -25,6 +25,8 @@ import batchInputHistory from './batch-input-history'
25
25
  import transferExtend from './transfer-list'
26
26
  import addressBookmarkExtend from './address-bookmark'
27
27
  import widgetsExtend from './widgets'
28
+ import mcpHandlerExtend from './mcp-handler'
29
+ import workspaceExtend from './workspace'
28
30
  import isColorDark from '../common/is-color-dark'
29
31
  import { getReverseColor } from '../common/reverse-color'
30
32
  import { uniq } from 'lodash-es'
@@ -297,5 +299,7 @@ batchInputHistory(Store)
297
299
  transferExtend(Store)
298
300
  addressBookmarkExtend(Store)
299
301
  widgetsExtend(Store)
302
+ mcpHandlerExtend(Store)
303
+ workspaceExtend(Store)
300
304
 
301
305
  export const StateStore = Store
@@ -16,6 +16,10 @@ export default Store => {
16
16
  }
17
17
 
18
18
  Store.prototype.runWidget = async (widgetId, config) => {
19
+ // If this is MCP server widget, initialize MCP handler first
20
+ if (widgetId === 'mcp-server') {
21
+ window.store.initMcpHandler()
22
+ }
19
23
  return window.pre.runGlobalAsync('runWidget', widgetId, config)
20
24
  }
21
25