@trops/dash-core 0.1.82 → 0.1.84

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.
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var require$$0 = require('electron');
3
+ var require$$0$1 = require('electron');
4
4
  var require$$1 = require('electron-store');
5
5
  var require$$1$1 = require('path');
6
6
  var require$$2 = require('fs');
@@ -11,23 +11,23 @@ var require$$3 = require('xml2js');
11
11
  var require$$4 = require('JSONStream');
12
12
  var require$$5 = require('stream');
13
13
  var require$$6 = require('csv-parser');
14
- var require$$0$1 = require('image-downloader');
14
+ var require$$0$2 = require('image-downloader');
15
15
  var require$$2$2 = require('get-pixels');
16
16
  var require$$3$1 = require('extract-colors');
17
17
  var require$$8 = require('https');
18
- var require$$0$2 = require('@modelcontextprotocol/sdk/client/index.js');
18
+ var require$$0$3 = require('@modelcontextprotocol/sdk/client/index.js');
19
19
  var require$$1$3 = require('@modelcontextprotocol/sdk/client/stdio.js');
20
20
  var require$$2$3 = require('@modelcontextprotocol/sdk/client/streamableHttp.js');
21
21
  var require$$5$2 = require('child_process');
22
22
  var require$$2$4 = require('algoliasearch');
23
23
  var require$$3$2 = require('node:path');
24
- var require$$0$3 = require('openai');
24
+ var require$$0$4 = require('openai');
25
25
  require('live-plugin-manager');
26
- var require$$0$4 = require('@anthropic-ai/sdk');
27
- var require$$2$6 = require('os');
28
- var require$$3$3 = require('adm-zip');
26
+ var require$$0$5 = require('@anthropic-ai/sdk');
27
+ var require$$2$5 = require('adm-zip');
28
+ var require$$2$7 = require('os');
29
29
  var require$$4$1 = require('url');
30
- var require$$2$5 = require('vm');
30
+ var require$$2$6 = require('vm');
31
31
 
32
32
  function getDefaultExportFromCjs (x) {
33
33
  return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
@@ -578,6 +578,20 @@ var clientCacheEvents$1 = {
578
578
  RESPONSE_CACHE_STATS: RESPONSE_CACHE_STATS$1,
579
579
  };
580
580
 
581
+ /**
582
+ * Dashboard Config Events
583
+ *
584
+ * IPC event constants for dashboard configuration export/import.
585
+ */
586
+
587
+ const DASHBOARD_CONFIG_EXPORT$1 = "dashboard-config-export";
588
+ const DASHBOARD_CONFIG_IMPORT$1 = "dashboard-config-import";
589
+
590
+ var dashboardConfigEvents$1 = {
591
+ DASHBOARD_CONFIG_EXPORT: DASHBOARD_CONFIG_EXPORT$1,
592
+ DASHBOARD_CONFIG_IMPORT: DASHBOARD_CONFIG_IMPORT$1,
593
+ };
594
+
581
595
  /**
582
596
  * Events
583
597
  *
@@ -599,6 +613,7 @@ const menuItemEvents = menuItemEvents$1;
599
613
  const openaiEvents = openaiEvents$1;
600
614
  const llmEvents = llmEvents$1;
601
615
  const clientCacheEvents = clientCacheEvents$1;
616
+ const dashboardConfigEvents = dashboardConfigEvents$1;
602
617
 
603
618
  const publicEvents = {
604
619
  ...dataEvents,
@@ -621,6 +636,7 @@ var events$8 = {
621
636
  ...openaiEvents,
622
637
  ...llmEvents,
623
638
  ...clientCacheEvents,
639
+ ...dashboardConfigEvents,
624
640
  };
625
641
 
626
642
  /**
@@ -629,14 +645,14 @@ var events$8 = {
629
645
  * Open a dialog window for choosing files
630
646
  */
631
647
 
632
- const { dialog } = require$$0;
648
+ const { dialog: dialog$1 } = require$$0$1;
633
649
  const events$7 = events$8;
634
650
 
635
651
  const showDialog$1 = async (win, message, allowFile, extensions = ["*"]) => {
636
652
  const properties =
637
653
  allowFile === true ? ["openFile"] : ["openDirectory", "createDirectory"];
638
654
  const filters = allowFile === true ? [{ name: "Data", extensions }] : [];
639
- const result = await dialog.showOpenDialog({ properties, filters });
655
+ const result = await dialog$1.showOpenDialog({ properties, filters });
640
656
  if (result.canceled || !result.filePaths[0]) return null;
641
657
  return result.filePaths[0];
642
658
  };
@@ -654,11 +670,11 @@ var dialogController$1 = {
654
670
  * secureStore
655
671
  */
656
672
 
657
- const { safeStorage } = require$$0;
673
+ const { safeStorage } = require$$0$1;
658
674
  const Store = require$$1;
659
675
  const events$6 = events$8;
660
676
 
661
- const schema = {
677
+ const schema$1 = {
662
678
  appId: {
663
679
  type: "string",
664
680
  },
@@ -684,7 +700,7 @@ const decryptString = (win, str) => {
684
700
 
685
701
  const saveData$1 = (key, value) => {
686
702
  try {
687
- const store = new Store({ schema });
703
+ const store = new Store({ schema: schema$1 });
688
704
  store.set(key, value);
689
705
  return getData$1(key);
690
706
  } catch (e) {
@@ -694,7 +710,7 @@ const saveData$1 = (key, value) => {
694
710
 
695
711
  const getData$1 = (key) => {
696
712
  try {
697
- const store = new Store({ schema });
713
+ const store = new Store({ schema: schema$1 });
698
714
  const value = store.get(key);
699
715
  if (value) {
700
716
  return { [key]: value };
@@ -714,7 +730,7 @@ var secureStoreController$1 = {
714
730
  getData: getData$1,
715
731
  };
716
732
 
717
- const path$d = require$$1$1;
733
+ const path$e = require$$1$1;
718
734
  const {
719
735
  readFileSync,
720
736
  writeFileSync: writeFileSync$4,
@@ -732,7 +748,7 @@ const {
732
748
  function ensureDirectoryExistence$2(filePath) {
733
749
  try {
734
750
  // isDirectory
735
- var dirname = path$d.dirname(filePath);
751
+ var dirname = path$e.dirname(filePath);
736
752
  // check if the directory exists...return true
737
753
  // if not, we can pass in the dirname as the filepath
738
754
  // and check each directory recursively.
@@ -783,7 +799,7 @@ function checkDirectory$1(dir) {
783
799
  * @param {string} filepath path to the file
784
800
  * @returns
785
801
  */
786
- function getFileContents$6(filepath, defaultReturn = []) {
802
+ function getFileContents$7(filepath, defaultReturn = []) {
787
803
  try {
788
804
  // lets first make sure all is there...
789
805
  ensureDirectoryExistence$2(filepath);
@@ -847,7 +863,7 @@ function removeFilesFromDirectory(directory, excludeFiles = []) {
847
863
 
848
864
  for (const file of files) {
849
865
  if (!excludeFiles.includes(file)) {
850
- unlinkSync(path$d.join(directory, file), (err) => {
866
+ unlinkSync(path$e.join(directory, file), (err) => {
851
867
  if (err) throw err;
852
868
  });
853
869
  }
@@ -858,19 +874,19 @@ function removeFilesFromDirectory(directory, excludeFiles = []) {
858
874
 
859
875
  var file = {
860
876
  ensureDirectoryExistence: ensureDirectoryExistence$2,
861
- getFileContents: getFileContents$6,
877
+ getFileContents: getFileContents$7,
862
878
  writeToFile: writeToFile$2,
863
879
  removeFilesFromDirectory,
864
880
  checkDirectory: checkDirectory$1,
865
881
  };
866
882
 
867
- const { app: app$7 } = require$$0;
868
- const path$c = require$$1$1;
883
+ const { app: app$8 } = require$$0$1;
884
+ const path$d = require$$1$1;
869
885
  const { writeFileSync: writeFileSync$3 } = require$$2;
870
- const { getFileContents: getFileContents$5 } = file;
886
+ const { getFileContents: getFileContents$6 } = file;
871
887
 
872
- const configFilename$4 = "workspaces.json";
873
- const appName$5 = "Dashboard";
888
+ const configFilename$5 = "workspaces.json";
889
+ const appName$6 = "Dashboard";
874
890
 
875
891
  const workspaceController$1 = {
876
892
  /**
@@ -912,13 +928,13 @@ const workspaceController$1 = {
912
928
  saveWorkspaceForApplication: (win, appId, workspaceObject) => {
913
929
  try {
914
930
  // filename to the pages file (live pages)
915
- const filename = path$c.join(
916
- app$7.getPath("userData"),
917
- appName$5,
931
+ const filename = path$d.join(
932
+ app$8.getPath("userData"),
933
+ appName$6,
918
934
  appId,
919
- configFilename$4,
935
+ configFilename$5,
920
936
  );
921
- const workspacesArray = getFileContents$5(filename);
937
+ const workspacesArray = getFileContents$6(filename);
922
938
 
923
939
  // lets check to see if we already have this one!
924
940
  let indexOfExistingItem = null;
@@ -961,13 +977,13 @@ const workspaceController$1 = {
961
977
  saveMenuItemsForApplication: (win, appId, menuItems) => {
962
978
  try {
963
979
  // filename to the workspaces file
964
- const filename = path$c.join(
965
- app$7.getPath("userData"),
966
- appName$5,
980
+ const filename = path$d.join(
981
+ app$8.getPath("userData"),
982
+ appName$6,
967
983
  appId,
968
- configFilename$4,
984
+ configFilename$5,
969
985
  );
970
- const workspacesArray = getFileContents$5(filename);
986
+ const workspacesArray = getFileContents$6(filename);
971
987
 
972
988
  // Update menu items for workspaces
973
989
  // This assumes menuItems is an object with workspace IDs as keys
@@ -1010,13 +1026,13 @@ const workspaceController$1 = {
1010
1026
  */
1011
1027
  deleteWorkspaceForApplication: (win, appId, workspaceId) => {
1012
1028
  try {
1013
- const filename = path$c.join(
1014
- app$7.getPath("userData"),
1015
- appName$5,
1029
+ const filename = path$d.join(
1030
+ app$8.getPath("userData"),
1031
+ appName$6,
1016
1032
  appId,
1017
- configFilename$4,
1033
+ configFilename$5,
1018
1034
  );
1019
- const workspacesArray = getFileContents$5(filename);
1035
+ const workspacesArray = getFileContents$6(filename);
1020
1036
 
1021
1037
  const filtered = workspacesArray.filter(
1022
1038
  (workspace) => workspace.id !== workspaceId,
@@ -1044,14 +1060,14 @@ const workspaceController$1 = {
1044
1060
 
1045
1061
  listWorkspacesForApplication: (win, appId) => {
1046
1062
  try {
1047
- const filename = path$c.join(
1048
- app$7.getPath("userData"),
1049
- appName$5,
1063
+ const filename = path$d.join(
1064
+ app$8.getPath("userData"),
1065
+ appName$6,
1050
1066
  appId,
1051
- configFilename$4,
1067
+ configFilename$5,
1052
1068
  );
1053
1069
 
1054
- const workspacesArray = getFileContents$5(filename);
1070
+ const workspacesArray = getFileContents$6(filename);
1055
1071
  console.log(
1056
1072
  `[workspaceController] Loaded ${workspacesArray.length} workspaces for appId: ${appId}`,
1057
1073
  );
@@ -1072,13 +1088,13 @@ const workspaceController$1 = {
1072
1088
 
1073
1089
  listMenuItemsForApplication: (win, appId) => {
1074
1090
  try {
1075
- const filename = path$c.join(
1076
- app$7.getPath("userData"),
1077
- appName$5,
1091
+ const filename = path$d.join(
1092
+ app$8.getPath("userData"),
1093
+ appName$6,
1078
1094
  appId,
1079
- configFilename$4,
1095
+ configFilename$5,
1080
1096
  );
1081
- const workspacesArray = getFileContents$5(filename);
1097
+ const workspacesArray = getFileContents$6(filename);
1082
1098
 
1083
1099
  // Extract unique menu items from workspaces
1084
1100
  // Each workspace can have a menuId, we need to build the menu items list
@@ -1116,13 +1132,13 @@ const workspaceController$1 = {
1116
1132
 
1117
1133
  var workspaceController_1 = workspaceController$1;
1118
1134
 
1119
- const { app: app$6 } = require$$0;
1120
- const path$b = require$$1$1;
1135
+ const { app: app$7 } = require$$0$1;
1136
+ const path$c = require$$1$1;
1121
1137
  const { writeFileSync: writeFileSync$2 } = require$$2;
1122
- const { getFileContents: getFileContents$4 } = file;
1138
+ const { getFileContents: getFileContents$5 } = file;
1123
1139
 
1124
- const configFilename$3 = "themes.json";
1125
- const appName$4 = "Dashboard";
1140
+ const configFilename$4 = "themes.json";
1141
+ const appName$5 = "Dashboard";
1126
1142
 
1127
1143
  const themeController$1 = {
1128
1144
  /**
@@ -1137,13 +1153,13 @@ const themeController$1 = {
1137
1153
  saveThemeForApplication: (win, appId, name, obj) => {
1138
1154
  try {
1139
1155
  // filename to the pages file (live pages)
1140
- const filename = path$b.join(
1141
- app$6.getPath("userData"),
1142
- appName$4,
1156
+ const filename = path$c.join(
1157
+ app$7.getPath("userData"),
1158
+ appName$5,
1143
1159
  appId,
1144
- configFilename$3,
1160
+ configFilename$4,
1145
1161
  );
1146
- const data = getFileContents$4(filename, {});
1162
+ const data = getFileContents$5(filename, {});
1147
1163
 
1148
1164
  // Add/update the theme based on the name
1149
1165
  if (name in data === false) {
@@ -1183,14 +1199,14 @@ const themeController$1 = {
1183
1199
  */
1184
1200
  listThemesForApplication: (win, appId) => {
1185
1201
  try {
1186
- const filename = path$b.join(
1187
- app$6.getPath("userData"),
1188
- appName$4,
1202
+ const filename = path$c.join(
1203
+ app$7.getPath("userData"),
1204
+ appName$5,
1189
1205
  appId,
1190
- configFilename$3,
1206
+ configFilename$4,
1191
1207
  );
1192
1208
 
1193
- const data = getFileContents$4(filename, {});
1209
+ const data = getFileContents$5(filename, {});
1194
1210
 
1195
1211
  console.log(
1196
1212
  "[themeController] Loading themes from:",
@@ -1225,13 +1241,13 @@ const themeController$1 = {
1225
1241
  */
1226
1242
  deleteThemeForApplication: (win, appId, themeKey) => {
1227
1243
  try {
1228
- const filename = path$b.join(
1229
- app$6.getPath("userData"),
1230
- appName$4,
1244
+ const filename = path$c.join(
1245
+ app$7.getPath("userData"),
1246
+ appName$5,
1231
1247
  appId,
1232
- configFilename$3,
1248
+ configFilename$4,
1233
1249
  );
1234
- const data = getFileContents$4(filename, {});
1250
+ const data = getFileContents$5(filename, {});
1235
1251
 
1236
1252
  if (themeKey in data) {
1237
1253
  delete data[themeKey];
@@ -1272,8 +1288,8 @@ var xmlParser = require$$3;
1272
1288
  var JSONStream$1 = require$$4;
1273
1289
  const stream = require$$5;
1274
1290
  var csv = require$$6;
1275
- const path$a = require$$1$1;
1276
- const { app: app$5 } = require$$0;
1291
+ const path$b = require$$1$1;
1292
+ const { app: app$6 } = require$$0$1;
1277
1293
  const { ensureDirectoryExistence: ensureDirectoryExistence$1 } = file;
1278
1294
 
1279
1295
  const TRANSFORM_APP_NAME = "Dashboard";
@@ -1561,18 +1577,18 @@ let Transform$1 = class Transform {
1561
1577
  }
1562
1578
 
1563
1579
  // Validate file paths are within app data directory
1564
- const appDataDir = path$a.join(app$5.getPath("userData"), TRANSFORM_APP_NAME);
1565
- const resolvedFilepath = path$a.resolve(filepath);
1566
- const resolvedOutFilepath = path$a.resolve(outFilepath);
1580
+ const appDataDir = path$b.join(app$6.getPath("userData"), TRANSFORM_APP_NAME);
1581
+ const resolvedFilepath = path$b.resolve(filepath);
1582
+ const resolvedOutFilepath = path$b.resolve(outFilepath);
1567
1583
 
1568
- if (!resolvedFilepath.startsWith(appDataDir + path$a.sep)) {
1584
+ if (!resolvedFilepath.startsWith(appDataDir + path$b.sep)) {
1569
1585
  return reject(
1570
1586
  new Error(
1571
1587
  "Input file path must be within the application data directory",
1572
1588
  ),
1573
1589
  );
1574
1590
  }
1575
- if (!resolvedOutFilepath.startsWith(appDataDir + path$a.sep)) {
1591
+ if (!resolvedOutFilepath.startsWith(appDataDir + path$b.sep)) {
1576
1592
  return reject(
1577
1593
  new Error(
1578
1594
  "Output file path must be within the application data directory",
@@ -3386,7 +3402,7 @@ var ntc_1 = ntc$1;
3386
3402
  * - extractColorsFromImageURL
3387
3403
  */
3388
3404
 
3389
- const download = require$$0$1;
3405
+ const download = require$$0$2;
3390
3406
  const getPixels = require$$2$2;
3391
3407
  const { extractColors } = require$$3$1;
3392
3408
  const ntc = ntc_1;
@@ -3430,18 +3446,18 @@ async function extractColorsFromImageURL$2(url, toDirectory) {
3430
3446
 
3431
3447
  var color = { extractColorsFromImageURL: extractColorsFromImageURL$2 };
3432
3448
 
3433
- const { app: app$4 } = require$$0;
3449
+ const { app: app$5 } = require$$0$1;
3434
3450
  var fs$7 = require$$2;
3435
- const path$9 = require$$1$1;
3451
+ const path$a = require$$1$1;
3436
3452
  const events$5 = events$8;
3437
- const { getFileContents: getFileContents$3, writeToFile: writeToFile$1 } = file;
3453
+ const { getFileContents: getFileContents$4, writeToFile: writeToFile$1 } = file;
3438
3454
 
3439
3455
  // Convert Json to Csv
3440
3456
  const ObjectsToCsv = require$$5$1;
3441
3457
  const Transform = transform;
3442
3458
  const { extractColorsFromImageURL: extractColorsFromImageURL$1 } = color;
3443
3459
  const https = require$$8;
3444
- const appName$3 = "Dashboard";
3460
+ const appName$4 = "Dashboard";
3445
3461
 
3446
3462
  const dataController$1 = {
3447
3463
  /**
@@ -3455,16 +3471,16 @@ const dataController$1 = {
3455
3471
  convertJsonToCsvFile: (win, appId, jsonObject, toFilename = "test.csv") => {
3456
3472
  try {
3457
3473
  // filename to the pages file (live pages)
3458
- const filename = path$9.join(
3459
- app$4.getPath("userData"),
3460
- appName$3,
3474
+ const filename = path$a.join(
3475
+ app$5.getPath("userData"),
3476
+ appName$4,
3461
3477
  appId,
3462
3478
  "data",
3463
3479
  toFilename,
3464
3480
  );
3465
3481
 
3466
3482
  // make sure the file exists...
3467
- const fileContents = getFileContents$3(filename, "");
3483
+ const fileContents = getFileContents$4(filename, "");
3468
3484
 
3469
3485
  const csv = new ObjectsToCsv(jsonObject);
3470
3486
 
@@ -3583,9 +3599,9 @@ const dataController$1 = {
3583
3599
  }
3584
3600
 
3585
3601
  // Validate toFilepath is within the app data directory
3586
- const appDataDir = path$9.join(app$4.getPath("userData"), appName$3);
3587
- const resolvedFilepath = path$9.resolve(toFilepath);
3588
- if (!resolvedFilepath.startsWith(appDataDir + path$9.sep)) {
3602
+ const appDataDir = path$a.join(app$5.getPath("userData"), appName$4);
3603
+ const resolvedFilepath = path$a.resolve(toFilepath);
3604
+ if (!resolvedFilepath.startsWith(appDataDir + path$a.sep)) {
3589
3605
  throw new Error(
3590
3606
  "File path must be within the application data directory",
3591
3607
  );
@@ -3732,9 +3748,9 @@ const dataController$1 = {
3732
3748
  try {
3733
3749
  if (data) {
3734
3750
  // filename to the pages file (live pages)
3735
- const toFilename = path$9.join(
3736
- app$4.getPath("userData"),
3737
- appName$3,
3751
+ const toFilename = path$a.join(
3752
+ app$5.getPath("userData"),
3753
+ appName$4,
3738
3754
  "data",
3739
3755
  filename,
3740
3756
  );
@@ -3742,7 +3758,7 @@ const dataController$1 = {
3742
3758
  //console.log("saving to file ", toFilename);
3743
3759
 
3744
3760
  // // call this to make sure the directory structure exists
3745
- let fileContents = getFileContents$3(toFilename, returnEmpty);
3761
+ let fileContents = getFileContents$4(toFilename, returnEmpty);
3746
3762
  if (fileContents === null || fileContents === "") {
3747
3763
  fileContents = JSON.stringify(returnEmpty);
3748
3764
  }
@@ -3814,15 +3830,15 @@ const dataController$1 = {
3814
3830
  try {
3815
3831
  if (filename) {
3816
3832
  // filename to the pages file (live pages)
3817
- const fromFilename = path$9.join(
3818
- app$4.getPath("userData"),
3819
- appName$3,
3833
+ const fromFilename = path$a.join(
3834
+ app$5.getPath("userData"),
3835
+ appName$4,
3820
3836
  "data",
3821
3837
  filename,
3822
3838
  );
3823
3839
  console.log("reading from file ", fromFilename, returnIfEmpty);
3824
3840
  // make sure the file exists...
3825
- const fileContents = getFileContents$3(fromFilename, returnIfEmpty);
3841
+ const fileContents = getFileContents$4(fromFilename, returnIfEmpty);
3826
3842
 
3827
3843
  console.log("file contents ", fileContents, fromFilename);
3828
3844
 
@@ -3892,9 +3908,9 @@ const dataController$1 = {
3892
3908
  try {
3893
3909
  console.log(url);
3894
3910
  const fileExtension = ".jpg";
3895
- const filename = path$9.join(
3896
- app$4.getPath("userData"),
3897
- appName$3,
3911
+ const filename = path$a.join(
3912
+ app$5.getPath("userData"),
3913
+ appName$4,
3898
3914
  "@algolia/dash-electron",
3899
3915
  "data",
3900
3916
  "imageExtract" + fileExtension,
@@ -3917,13 +3933,13 @@ var dataController_1 = dataController$1;
3917
3933
  * settingsController
3918
3934
  */
3919
3935
 
3920
- const { app: app$3 } = require$$0;
3921
- const path$8 = require$$1$1;
3936
+ const { app: app$4 } = require$$0$1;
3937
+ const path$9 = require$$1$1;
3922
3938
  const fs$6 = require$$2;
3923
- const { getFileContents: getFileContents$2, writeToFile } = file;
3939
+ const { getFileContents: getFileContents$3, writeToFile } = file;
3924
3940
 
3925
- const configFilename$2 = "settings.json";
3926
- const appName$2 = "Dashboard";
3941
+ const configFilename$3 = "settings.json";
3942
+ const appName$3 = "Dashboard";
3927
3943
 
3928
3944
  // Helper function to recursively copy directory
3929
3945
  function copyDirectory(source, destination) {
@@ -3933,8 +3949,8 @@ function copyDirectory(source, destination) {
3933
3949
 
3934
3950
  const files = fs$6.readdirSync(source);
3935
3951
  for (const file of files) {
3936
- const srcPath = path$8.join(source, file);
3937
- const destPath = path$8.join(destination, file);
3952
+ const srcPath = path$9.join(source, file);
3953
+ const destPath = path$9.join(destination, file);
3938
3954
  const stat = fs$6.lstatSync(srcPath);
3939
3955
 
3940
3956
  // Skip symlinks to prevent following links to sensitive files
@@ -3962,10 +3978,10 @@ const settingsController$1 = {
3962
3978
  try {
3963
3979
  if (data) {
3964
3980
  // <appId>/settings.json
3965
- const filename = path$8.join(
3966
- app$3.getPath("userData"),
3967
- appName$2,
3968
- configFilename$2,
3981
+ const filename = path$9.join(
3982
+ app$4.getPath("userData"),
3983
+ appName$3,
3984
+ configFilename$3,
3969
3985
  );
3970
3986
  writeToFile(filename, JSON.stringify(data, null, 2));
3971
3987
  console.log("[settingsController] Settings saved successfully");
@@ -3998,13 +4014,13 @@ const settingsController$1 = {
3998
4014
  getSettingsForApplication: (win) => {
3999
4015
  try {
4000
4016
  // <appId>/settings.json
4001
- const filename = path$8.join(
4002
- app$3.getPath("userData"),
4003
- appName$2,
4004
- configFilename$2,
4017
+ const filename = path$9.join(
4018
+ app$4.getPath("userData"),
4019
+ appName$3,
4020
+ configFilename$3,
4005
4021
  );
4006
4022
  // make sure the file exists...
4007
- const fileContents = getFileContents$2(filename, {});
4023
+ const fileContents = getFileContents$3(filename, {});
4008
4024
  console.log("[settingsController] Settings loaded successfully");
4009
4025
  // Return the data for ipcMain.handle() - modern promise-based approach
4010
4026
  return {
@@ -4029,15 +4045,15 @@ const settingsController$1 = {
4029
4045
  */
4030
4046
  getDataDirectory: (win) => {
4031
4047
  try {
4032
- const settingsPath = path$8.join(
4033
- app$3.getPath("userData"),
4034
- appName$2,
4035
- configFilename$2,
4048
+ const settingsPath = path$9.join(
4049
+ app$4.getPath("userData"),
4050
+ appName$3,
4051
+ configFilename$3,
4036
4052
  );
4037
- const settings = getFileContents$2(settingsPath, {});
4053
+ const settings = getFileContents$3(settingsPath, {});
4038
4054
  const userDataDir =
4039
4055
  settings.userDataDirectory ||
4040
- path$8.join(app$3.getPath("userData"), appName$2);
4056
+ path$9.join(app$4.getPath("userData"), appName$3);
4041
4057
 
4042
4058
  console.log("[settingsController] Data directory retrieved successfully");
4043
4059
  // Return the data for ipcMain.handle() - modern promise-based approach
@@ -4074,12 +4090,12 @@ const settingsController$1 = {
4074
4090
  }
4075
4091
 
4076
4092
  // Update settings
4077
- const settingsPath = path$8.join(
4078
- app$3.getPath("userData"),
4079
- appName$2,
4080
- configFilename$2,
4093
+ const settingsPath = path$9.join(
4094
+ app$4.getPath("userData"),
4095
+ appName$3,
4096
+ configFilename$3,
4081
4097
  );
4082
- const settings = getFileContents$2(settingsPath, {});
4098
+ const settings = getFileContents$3(settingsPath, {});
4083
4099
  settings.userDataDirectory = newPath;
4084
4100
  writeToFile(settingsPath, JSON.stringify(settings, null, 2));
4085
4101
 
@@ -4108,20 +4124,20 @@ const settingsController$1 = {
4108
4124
  migrateDataDirectory: (win, oldPath, newPath) => {
4109
4125
  try {
4110
4126
  // Resolve paths to prevent traversal
4111
- const resolvedOldPath = path$8.resolve(oldPath);
4112
- const resolvedNewPath = path$8.resolve(newPath);
4127
+ const resolvedOldPath = path$9.resolve(oldPath);
4128
+ const resolvedNewPath = path$9.resolve(newPath);
4113
4129
 
4114
4130
  // Validate oldPath is the current configured data directory
4115
- const settingsCheckPath = path$8.join(
4116
- app$3.getPath("userData"),
4117
- appName$2,
4118
- configFilename$2,
4131
+ const settingsCheckPath = path$9.join(
4132
+ app$4.getPath("userData"),
4133
+ appName$3,
4134
+ configFilename$3,
4119
4135
  );
4120
- const currentSettings = getFileContents$2(settingsCheckPath, {});
4136
+ const currentSettings = getFileContents$3(settingsCheckPath, {});
4121
4137
  const currentDataDir =
4122
4138
  currentSettings.userDataDirectory ||
4123
- path$8.join(app$3.getPath("userData"), appName$2);
4124
- if (resolvedOldPath !== path$8.resolve(currentDataDir)) {
4139
+ path$9.join(app$4.getPath("userData"), appName$3);
4140
+ if (resolvedOldPath !== path$9.resolve(currentDataDir)) {
4125
4141
  throw new Error("Source path must be the current data directory");
4126
4142
  }
4127
4143
 
@@ -4157,12 +4173,12 @@ const settingsController$1 = {
4157
4173
  copyDirectory(resolvedOldPath, resolvedNewPath);
4158
4174
 
4159
4175
  // Update settings to use new path
4160
- const settingsPath = path$8.join(
4161
- app$3.getPath("userData"),
4162
- appName$2,
4163
- configFilename$2,
4176
+ const settingsPath = path$9.join(
4177
+ app$4.getPath("userData"),
4178
+ appName$3,
4179
+ configFilename$3,
4164
4180
  );
4165
- const settings = getFileContents$2(settingsPath, {});
4181
+ const settings = getFileContents$3(settingsPath, {});
4166
4182
  settings.userDataDirectory = resolvedNewPath;
4167
4183
  writeToFile(settingsPath, JSON.stringify(settings, null, 2));
4168
4184
 
@@ -4399,7 +4415,7 @@ function requireClientCache () {
4399
4415
  * Call this once in the consuming app's electron.js alongside setupWidgetRegistryHandlers().
4400
4416
  */
4401
4417
  setupCacheHandlers() {
4402
- const { ipcMain } = require$$0;
4418
+ const { ipcMain } = require$$0$1;
4403
4419
  const responseCache = responseCache_1;
4404
4420
 
4405
4421
  ipcMain.handle(
@@ -4440,7 +4456,7 @@ var hasRequiredProviderController;
4440
4456
  function requireProviderController () {
4441
4457
  if (hasRequiredProviderController) return providerController_1;
4442
4458
  hasRequiredProviderController = 1;
4443
- const { app, safeStorage } = require$$0;
4459
+ const { app, safeStorage } = require$$0$1;
4444
4460
  const path = require$$1$1;
4445
4461
  const { writeFileSync, readFileSync, existsSync } = require$$2;
4446
4462
  const {
@@ -4771,14 +4787,14 @@ function requireProviderController () {
4771
4787
  return providerController_1;
4772
4788
  }
4773
4789
 
4774
- const { app: app$2 } = require$$0;
4775
- const path$7 = require$$1$1;
4790
+ const { app: app$3 } = require$$0$1;
4791
+ const path$8 = require$$1$1;
4776
4792
  const { writeFileSync: writeFileSync$1 } = require$$2;
4777
4793
  const events$4 = events$8;
4778
- const { getFileContents: getFileContents$1 } = file;
4794
+ const { getFileContents: getFileContents$2 } = file;
4779
4795
 
4780
- const configFilename$1 = "layouts.json";
4781
- const appName$1 = "Dashboard";
4796
+ const configFilename$2 = "layouts.json";
4797
+ const appName$2 = "Dashboard";
4782
4798
 
4783
4799
  const layoutController$1 = {
4784
4800
  /**
@@ -4792,13 +4808,13 @@ const layoutController$1 = {
4792
4808
  saveLayoutForApplication: (win, appId, layoutObject) => {
4793
4809
  try {
4794
4810
  // filename to the pages file (live pages)
4795
- const filename = path$7.join(
4796
- app$2.getPath("userData"),
4797
- appName$1,
4811
+ const filename = path$8.join(
4812
+ app$3.getPath("userData"),
4813
+ appName$2,
4798
4814
  appId,
4799
- configFilename$1,
4815
+ configFilename$2,
4800
4816
  );
4801
- const layoutsArray = getFileContents$1(filename);
4817
+ const layoutsArray = getFileContents$2(filename);
4802
4818
 
4803
4819
  // add the pageObject to the pages file
4804
4820
  layoutsArray.push(layoutObject);
@@ -4825,13 +4841,13 @@ const layoutController$1 = {
4825
4841
  */
4826
4842
  listLayoutsForApplication: (win, appId) => {
4827
4843
  try {
4828
- const filename = path$7.join(
4829
- app$2.getPath("userData"),
4830
- appName$1,
4844
+ const filename = path$8.join(
4845
+ app$3.getPath("userData"),
4846
+ appName$2,
4831
4847
  appId,
4832
- configFilename$1,
4848
+ configFilename$2,
4833
4849
  );
4834
- const layoutsArray = getFileContents$1(filename);
4850
+ const layoutsArray = getFileContents$2(filename);
4835
4851
  win.webContents.send(events$4.LAYOUT_LIST_COMPLETE, {
4836
4852
  layouts: layoutsArray,
4837
4853
  });
@@ -4861,14 +4877,14 @@ var mcpController$3 = {exports: {}};
4861
4877
  * Uses @modelcontextprotocol/sdk for protocol handling.
4862
4878
  */
4863
4879
 
4864
- const { Client } = require$$0$2;
4880
+ const { Client } = require$$0$3;
4865
4881
  const {
4866
4882
  StdioClientTransport,
4867
4883
  } = require$$1$3;
4868
4884
  const {
4869
4885
  StreamableHTTPClientTransport,
4870
4886
  } = require$$2$3;
4871
- const path$6 = require$$1$1;
4887
+ const path$7 = require$$1$1;
4872
4888
  const fs$5 = require$$2;
4873
4889
 
4874
4890
  /**
@@ -5285,7 +5301,7 @@ const mcpController$2 = {
5285
5301
  }
5286
5302
 
5287
5303
  // Interpolate {{MCP_DIR}} in args to resolve local MCP server scripts
5288
- const mcpDir = path$6.join(__dirname, "..", "mcp");
5304
+ const mcpDir = path$7.join(__dirname, "..", "mcp");
5289
5305
  for (let i = 0; i < args.length; i++) {
5290
5306
  if (
5291
5307
  typeof args[i] === "string" &&
@@ -5660,7 +5676,7 @@ const mcpController$2 = {
5660
5676
  */
5661
5677
  getCatalog: (win) => {
5662
5678
  try {
5663
- const catalogPath = path$6.join(
5679
+ const catalogPath = path$7.join(
5664
5680
  __dirname,
5665
5681
  "..",
5666
5682
  "mcp",
@@ -5772,7 +5788,7 @@ const mcpController$2 = {
5772
5788
  }
5773
5789
 
5774
5790
  // Interpolate {{MCP_DIR}} in authCommand args (same as startServer)
5775
- const mcpDir = path$6.join(__dirname, "..", "mcp");
5791
+ const mcpDir = path$7.join(__dirname, "..", "mcp");
5776
5792
  const resolvedArgs = (authCommand.args || []).map((arg) =>
5777
5793
  typeof arg === "string" && arg.includes("{{MCP_DIR}}")
5778
5794
  ? arg.replace(/\{\{MCP_DIR\}\}/g, mcpDir)
@@ -5868,7 +5884,7 @@ var mcpControllerExports = mcpController$3.exports;
5868
5884
  * - Support two-level browsing: packages (bundles) and widgets within packages
5869
5885
  */
5870
5886
 
5871
- const path$5 = require$$1$1;
5887
+ const path$6 = require$$1$1;
5872
5888
  const fs$4 = require$$2;
5873
5889
 
5874
5890
  // Default registry URL (GitHub Pages)
@@ -5885,7 +5901,7 @@ let cacheTimestamp = 0;
5885
5901
  * Get the local test registry path for dev mode
5886
5902
  */
5887
5903
  function getTestRegistryPath() {
5888
- return path$5.join(__dirname, "..", "registry", "test-registry-index.json");
5904
+ return path$6.join(__dirname, "..", "registry", "test-registry-index.json");
5889
5905
  }
5890
5906
 
5891
5907
  /**
@@ -6104,7 +6120,7 @@ var registryController$1 = {
6104
6120
  var fs$3 = require$$2;
6105
6121
  var JSONStream = require$$4;
6106
6122
  const algoliasearch$1 = require$$2$4;
6107
- const path$4 = require$$3$2;
6123
+ const path$5 = require$$3$2;
6108
6124
  const { ensureDirectoryExistence, checkDirectory } = file;
6109
6125
 
6110
6126
  let AlgoliaIndex$1 = class AlgoliaIndex {
@@ -6211,7 +6227,7 @@ let AlgoliaIndex$1 = class AlgoliaIndex {
6211
6227
  if (err) reject(err);
6212
6228
  if (files) {
6213
6229
  files.forEach((file) => {
6214
- fs$3.unlinkSync(path$4.join(directoryPath, file));
6230
+ fs$3.unlinkSync(path$5.join(directoryPath, file));
6215
6231
  });
6216
6232
  resolve();
6217
6233
  }
@@ -6234,7 +6250,7 @@ let AlgoliaIndex$1 = class AlgoliaIndex {
6234
6250
  let results = [];
6235
6251
  for (const fileIndex in files) {
6236
6252
  // for each file lets read the file and then push to algolia
6237
- const pathToBatch = path$4.join(batchFilepath, files[fileIndex]);
6253
+ const pathToBatch = path$5.join(batchFilepath, files[fileIndex]);
6238
6254
  const fileContents = await this.readFile(pathToBatch);
6239
6255
  if (fileContents) {
6240
6256
  if ("data" in fileContents && "filepath" in fileContents) {
@@ -6647,7 +6663,7 @@ const algoliaController$1 = {
6647
6663
 
6648
6664
  var algoliaController_1 = algoliaController$1;
6649
6665
 
6650
- const OpenAI = require$$0$3;
6666
+ const OpenAI = require$$0$4;
6651
6667
  const events$2 = events$8;
6652
6668
 
6653
6669
  const openaiController$1 = {
@@ -6688,25 +6704,25 @@ const openaiController$1 = {
6688
6704
 
6689
6705
  var openaiController_1 = openaiController$1;
6690
6706
 
6691
- const { app: app$1 } = require$$0;
6692
- const path$3 = require$$1$1;
6707
+ const { app: app$2 } = require$$0$1;
6708
+ const path$4 = require$$1$1;
6693
6709
  const { writeFileSync } = require$$2;
6694
- const { getFileContents } = file;
6710
+ const { getFileContents: getFileContents$1 } = file;
6695
6711
 
6696
- const configFilename = "menuItems.json";
6697
- const appName = "Dashboard";
6712
+ const configFilename$1 = "menuItems.json";
6713
+ const appName$1 = "Dashboard";
6698
6714
 
6699
6715
  const menuItemsController$1 = {
6700
6716
  saveMenuItemForApplication: (win, appId, menuItem) => {
6701
6717
  try {
6702
6718
  // filename to the pages file (live pages)
6703
- const filename = path$3.join(
6704
- app$1.getPath("userData"),
6705
- appName,
6719
+ const filename = path$4.join(
6720
+ app$2.getPath("userData"),
6721
+ appName$1,
6706
6722
  appId,
6707
- configFilename,
6723
+ configFilename$1,
6708
6724
  );
6709
- const menuItemsArray = getFileContents(filename);
6725
+ const menuItemsArray = getFileContents$1(filename);
6710
6726
 
6711
6727
  menuItemsArray.filter((mi) => mi !== null);
6712
6728
 
@@ -6736,13 +6752,13 @@ const menuItemsController$1 = {
6736
6752
 
6737
6753
  listMenuItemsForApplication: (win, appId) => {
6738
6754
  try {
6739
- const filename = path$3.join(
6740
- app$1.getPath("userData"),
6741
- appName,
6755
+ const filename = path$4.join(
6756
+ app$2.getPath("userData"),
6757
+ appName$1,
6742
6758
  appId,
6743
- configFilename,
6759
+ configFilename$1,
6744
6760
  );
6745
- const menuItemsArray = getFileContents(filename);
6761
+ const menuItemsArray = getFileContents$1(filename);
6746
6762
  const filtered = menuItemsArray.filter((mi) => mi !== null);
6747
6763
  // Return the data for ipcMain.handle() - modern promise-based approach
6748
6764
  return {
@@ -6762,14 +6778,14 @@ const menuItemsController$1 = {
6762
6778
 
6763
6779
  var menuItemsController_1 = menuItemsController$1;
6764
6780
 
6765
- const path$2 = require$$1$1;
6766
- const { app } = require$$0;
6781
+ const path$3 = require$$1$1;
6782
+ const { app: app$1 } = require$$0$1;
6767
6783
 
6768
6784
  const pluginController$1 = {
6769
6785
  install: (win, packageName, filepath) => {
6770
6786
  try {
6771
- const rootPath = path$2.join(
6772
- app.getPath("userData"),
6787
+ const rootPath = path$3.join(
6788
+ app$1.getPath("userData"),
6773
6789
  "plugins",
6774
6790
  packageName,
6775
6791
  );
@@ -7224,7 +7240,7 @@ var cliController_1 = cliController$2;
7224
7240
  * per-request, receiving the full messages array each time.
7225
7241
  */
7226
7242
 
7227
- const Anthropic = require$$0$4;
7243
+ const Anthropic = require$$0$5;
7228
7244
  const mcpController$1 = mcpControllerExports;
7229
7245
  const cliController$1 = cliController_1;
7230
7246
  const {
@@ -7530,6 +7546,899 @@ const llmController$1 = {
7530
7546
 
7531
7547
  var llmController_1 = llmController$1;
7532
7548
 
7549
+ var $schema = "https://json-schema.org/draft/2020-12/schema";
7550
+ var $id = "https://trops.github.io/dash-registry/dashboard-config.schema.json";
7551
+ var title = "Dashboard Configuration";
7552
+ var description = "Schema for portable dashboard configuration files (.dashboard.json)";
7553
+ var type = "object";
7554
+ var required = [
7555
+ "schemaVersion",
7556
+ "name",
7557
+ "workspace",
7558
+ "widgets"
7559
+ ];
7560
+ var properties = {
7561
+ schemaVersion: {
7562
+ type: "string",
7563
+ description: "Schema version for forward compatibility",
7564
+ pattern: "^\\d+\\.\\d+\\.\\d+$",
7565
+ examples: [
7566
+ "1.0.0"
7567
+ ]
7568
+ },
7569
+ name: {
7570
+ type: "string",
7571
+ description: "Display name of the dashboard",
7572
+ minLength: 1,
7573
+ maxLength: 100
7574
+ },
7575
+ description: {
7576
+ type: "string",
7577
+ description: "Human-readable description of the dashboard",
7578
+ maxLength: 1000,
7579
+ "default": ""
7580
+ },
7581
+ author: {
7582
+ type: "object",
7583
+ description: "Dashboard curator/creator (separate from widget authors)",
7584
+ required: [
7585
+ "name"
7586
+ ],
7587
+ properties: {
7588
+ name: {
7589
+ type: "string",
7590
+ description: "Author display name"
7591
+ },
7592
+ id: {
7593
+ type: "string",
7594
+ description: "Author identifier"
7595
+ }
7596
+ },
7597
+ additionalProperties: false
7598
+ },
7599
+ shareable: {
7600
+ type: "boolean",
7601
+ description: "true for user-created dashboards, false for imported. Only shareable dashboards can be published to the registry.",
7602
+ "default": true
7603
+ },
7604
+ tags: {
7605
+ type: "array",
7606
+ description: "Searchable tags for discovery",
7607
+ items: {
7608
+ type: "string",
7609
+ maxLength: 50
7610
+ },
7611
+ maxItems: 20,
7612
+ "default": [
7613
+ ]
7614
+ },
7615
+ icon: {
7616
+ type: "string",
7617
+ description: "FontAwesome icon name",
7618
+ "default": "grip"
7619
+ },
7620
+ screenshots: {
7621
+ type: "array",
7622
+ description: "Screenshot URLs or references",
7623
+ items: {
7624
+ type: "string"
7625
+ },
7626
+ "default": [
7627
+ ]
7628
+ },
7629
+ workspace: {
7630
+ type: "object",
7631
+ description: "Full workspace configuration (DashboardModel JSON)",
7632
+ required: [
7633
+ "layout"
7634
+ ],
7635
+ properties: {
7636
+ id: {
7637
+ description: "Workspace ID (timestamp or number)"
7638
+ },
7639
+ name: {
7640
+ type: "string"
7641
+ },
7642
+ type: {
7643
+ type: "string",
7644
+ "enum": [
7645
+ "layout",
7646
+ "widget",
7647
+ "workspace",
7648
+ "grid"
7649
+ ],
7650
+ "default": "workspace"
7651
+ },
7652
+ label: {
7653
+ type: "string"
7654
+ },
7655
+ version: {
7656
+ "default": 1
7657
+ },
7658
+ layout: {
7659
+ type: "array",
7660
+ description: "Array of layout items (LayoutModel objects)",
7661
+ items: {
7662
+ type: "object"
7663
+ },
7664
+ minItems: 1
7665
+ },
7666
+ menuId: {
7667
+ "default": 1
7668
+ }
7669
+ },
7670
+ additionalProperties: true
7671
+ },
7672
+ widgets: {
7673
+ type: "array",
7674
+ description: "Widget dependencies required by this dashboard",
7675
+ items: {
7676
+ type: "object",
7677
+ required: [
7678
+ "id",
7679
+ "package"
7680
+ ],
7681
+ properties: {
7682
+ id: {
7683
+ type: "string",
7684
+ description: "Widget identifier (e.g., trops.algolia.AlgoliaSearchPage)"
7685
+ },
7686
+ "package": {
7687
+ type: "string",
7688
+ description: "npm package name (e.g., @trops/algolia-search)"
7689
+ },
7690
+ version: {
7691
+ type: "string",
7692
+ description: "Semver range (e.g., ^1.0.0)",
7693
+ "default": "*"
7694
+ },
7695
+ required: {
7696
+ type: "boolean",
7697
+ description: "Whether this widget is required for the dashboard to function",
7698
+ "default": true
7699
+ },
7700
+ author: {
7701
+ type: "string",
7702
+ description: "Original widget author (preserved from widget package metadata)"
7703
+ }
7704
+ },
7705
+ additionalProperties: false
7706
+ }
7707
+ },
7708
+ providers: {
7709
+ type: "array",
7710
+ description: "Provider dependencies required by widgets in this dashboard",
7711
+ items: {
7712
+ type: "object",
7713
+ required: [
7714
+ "type",
7715
+ "providerClass"
7716
+ ],
7717
+ properties: {
7718
+ type: {
7719
+ type: "string",
7720
+ description: "Provider type identifier (e.g., algolia, slack, github)"
7721
+ },
7722
+ providerClass: {
7723
+ type: "string",
7724
+ description: "Provider class: credential or mcp",
7725
+ "enum": [
7726
+ "credential",
7727
+ "mcp"
7728
+ ]
7729
+ },
7730
+ required: {
7731
+ type: "boolean",
7732
+ "default": true
7733
+ },
7734
+ usedBy: {
7735
+ type: "array",
7736
+ description: "Widget component names that use this provider",
7737
+ items: {
7738
+ type: "string"
7739
+ },
7740
+ "default": [
7741
+ ]
7742
+ }
7743
+ },
7744
+ additionalProperties: false
7745
+ },
7746
+ "default": [
7747
+ ]
7748
+ },
7749
+ eventWiring: {
7750
+ type: "array",
7751
+ description: "Pre-configured event connections between widgets",
7752
+ items: {
7753
+ type: "object",
7754
+ required: [
7755
+ "source",
7756
+ "target"
7757
+ ],
7758
+ properties: {
7759
+ source: {
7760
+ type: "object",
7761
+ required: [
7762
+ "widget",
7763
+ "event"
7764
+ ],
7765
+ properties: {
7766
+ widget: {
7767
+ type: "string",
7768
+ description: "Source widget component name"
7769
+ },
7770
+ event: {
7771
+ type: "string",
7772
+ description: "Event name published by source widget"
7773
+ }
7774
+ },
7775
+ additionalProperties: false
7776
+ },
7777
+ target: {
7778
+ type: "object",
7779
+ required: [
7780
+ "widget",
7781
+ "handler"
7782
+ ],
7783
+ properties: {
7784
+ widget: {
7785
+ type: "string",
7786
+ description: "Target widget component name"
7787
+ },
7788
+ handler: {
7789
+ type: "string",
7790
+ description: "Event handler name on target widget"
7791
+ }
7792
+ },
7793
+ additionalProperties: false
7794
+ }
7795
+ },
7796
+ additionalProperties: false
7797
+ },
7798
+ "default": [
7799
+ ]
7800
+ }
7801
+ };
7802
+ var additionalProperties = false;
7803
+ var require$$0 = {
7804
+ $schema: $schema,
7805
+ $id: $id,
7806
+ title: title,
7807
+ description: description,
7808
+ type: type,
7809
+ required: required,
7810
+ properties: properties,
7811
+ additionalProperties: additionalProperties
7812
+ };
7813
+
7814
+ /**
7815
+ * dashboardConfigValidator.js
7816
+ *
7817
+ * Validates dashboard configuration objects against the dashboard-config schema.
7818
+ * Runs in the Electron main process (CJS).
7819
+ *
7820
+ * Uses a lightweight validation approach based on the JSON Schema definition
7821
+ * without requiring a full JSON Schema validator library.
7822
+ */
7823
+
7824
+ const schema = require$$0;
7825
+
7826
+ const CURRENT_SCHEMA_VERSION$1 = "1.0.0";
7827
+
7828
+ /**
7829
+ * Validate a dashboard configuration object.
7830
+ *
7831
+ * @param {Object} config - The dashboard config to validate
7832
+ * @returns {{ valid: boolean, errors: string[] }} Validation result
7833
+ */
7834
+ function validateDashboardConfig$1(config) {
7835
+ const errors = [];
7836
+
7837
+ if (config === null || config === undefined || typeof config !== "object") {
7838
+ return { valid: false, errors: ["Config must be a non-null object"] };
7839
+ }
7840
+
7841
+ // Required fields
7842
+ for (const field of schema.required) {
7843
+ if (!(field in config)) {
7844
+ errors.push(`Missing required field: "${field}"`);
7845
+ }
7846
+ }
7847
+
7848
+ // If required fields are missing, return early — further checks would be noisy
7849
+ if (errors.length > 0) {
7850
+ return { valid: false, errors };
7851
+ }
7852
+
7853
+ // schemaVersion
7854
+ if (typeof config.schemaVersion !== "string") {
7855
+ errors.push(`"schemaVersion" must be a string`);
7856
+ } else if (!/^\d+\.\d+\.\d+$/.test(config.schemaVersion)) {
7857
+ errors.push(
7858
+ `"schemaVersion" must be a semver string (e.g., "1.0.0"), got "${config.schemaVersion}"`,
7859
+ );
7860
+ }
7861
+
7862
+ // name
7863
+ if (typeof config.name !== "string" || config.name.length === 0) {
7864
+ errors.push(`"name" must be a non-empty string`);
7865
+ } else if (config.name.length > 100) {
7866
+ errors.push(`"name" must be 100 characters or fewer`);
7867
+ }
7868
+
7869
+ // description (optional)
7870
+ if ("description" in config && typeof config.description !== "string") {
7871
+ errors.push(`"description" must be a string`);
7872
+ }
7873
+
7874
+ // author (optional)
7875
+ if ("author" in config) {
7876
+ if (
7877
+ typeof config.author !== "object" ||
7878
+ config.author === null ||
7879
+ Array.isArray(config.author)
7880
+ ) {
7881
+ errors.push(`"author" must be an object with at least a "name" field`);
7882
+ } else if (!config.author.name || typeof config.author.name !== "string") {
7883
+ errors.push(`"author.name" must be a non-empty string`);
7884
+ }
7885
+ }
7886
+
7887
+ // shareable (optional)
7888
+ if ("shareable" in config && typeof config.shareable !== "boolean") {
7889
+ errors.push(`"shareable" must be a boolean`);
7890
+ }
7891
+
7892
+ // tags (optional)
7893
+ if ("tags" in config) {
7894
+ if (!Array.isArray(config.tags)) {
7895
+ errors.push(`"tags" must be an array of strings`);
7896
+ } else {
7897
+ for (let i = 0; i < config.tags.length; i++) {
7898
+ if (typeof config.tags[i] !== "string") {
7899
+ errors.push(`"tags[${i}]" must be a string`);
7900
+ }
7901
+ }
7902
+ }
7903
+ }
7904
+
7905
+ // workspace
7906
+ if (typeof config.workspace !== "object" || config.workspace === null) {
7907
+ errors.push(`"workspace" must be an object`);
7908
+ } else {
7909
+ if (!Array.isArray(config.workspace.layout)) {
7910
+ errors.push(`"workspace.layout" must be an array`);
7911
+ } else if (config.workspace.layout.length === 0) {
7912
+ errors.push(`"workspace.layout" must contain at least one layout item`);
7913
+ }
7914
+ }
7915
+
7916
+ // widgets
7917
+ if (!Array.isArray(config.widgets)) {
7918
+ errors.push(`"widgets" must be an array`);
7919
+ } else {
7920
+ for (let i = 0; i < config.widgets.length; i++) {
7921
+ const w = config.widgets[i];
7922
+ if (typeof w !== "object" || w === null) {
7923
+ errors.push(`"widgets[${i}]" must be an object`);
7924
+ continue;
7925
+ }
7926
+ if (!w.id || typeof w.id !== "string") {
7927
+ errors.push(`"widgets[${i}].id" must be a non-empty string`);
7928
+ }
7929
+ if (!w.package || typeof w.package !== "string") {
7930
+ errors.push(`"widgets[${i}].package" must be a non-empty string`);
7931
+ }
7932
+ if ("version" in w && typeof w.version !== "string") {
7933
+ errors.push(`"widgets[${i}].version" must be a string`);
7934
+ }
7935
+ if ("required" in w && typeof w.required !== "boolean") {
7936
+ errors.push(`"widgets[${i}].required" must be a boolean`);
7937
+ }
7938
+ if ("author" in w && typeof w.author !== "string") {
7939
+ errors.push(`"widgets[${i}].author" must be a string`);
7940
+ }
7941
+ }
7942
+ }
7943
+
7944
+ // providers (optional)
7945
+ if ("providers" in config) {
7946
+ if (!Array.isArray(config.providers)) {
7947
+ errors.push(`"providers" must be an array`);
7948
+ } else {
7949
+ const validClasses = ["credential", "mcp"];
7950
+ for (let i = 0; i < config.providers.length; i++) {
7951
+ const p = config.providers[i];
7952
+ if (typeof p !== "object" || p === null) {
7953
+ errors.push(`"providers[${i}]" must be an object`);
7954
+ continue;
7955
+ }
7956
+ if (!p.type || typeof p.type !== "string") {
7957
+ errors.push(
7958
+ `"providers[${i}].type" must be a non-empty string`,
7959
+ );
7960
+ }
7961
+ if (!validClasses.includes(p.providerClass)) {
7962
+ errors.push(
7963
+ `"providers[${i}].providerClass" must be "credential" or "mcp", got "${p.providerClass}"`,
7964
+ );
7965
+ }
7966
+ if ("usedBy" in p && !Array.isArray(p.usedBy)) {
7967
+ errors.push(`"providers[${i}].usedBy" must be an array`);
7968
+ }
7969
+ }
7970
+ }
7971
+ }
7972
+
7973
+ // eventWiring (optional)
7974
+ if ("eventWiring" in config) {
7975
+ if (!Array.isArray(config.eventWiring)) {
7976
+ errors.push(`"eventWiring" must be an array`);
7977
+ } else {
7978
+ for (let i = 0; i < config.eventWiring.length; i++) {
7979
+ const ew = config.eventWiring[i];
7980
+ if (typeof ew !== "object" || ew === null) {
7981
+ errors.push(`"eventWiring[${i}]" must be an object`);
7982
+ continue;
7983
+ }
7984
+ // source
7985
+ if (
7986
+ typeof ew.source !== "object" ||
7987
+ ew.source === null ||
7988
+ !ew.source.widget ||
7989
+ !ew.source.event
7990
+ ) {
7991
+ errors.push(
7992
+ `"eventWiring[${i}].source" must have "widget" and "event" strings`,
7993
+ );
7994
+ }
7995
+ // target
7996
+ if (
7997
+ typeof ew.target !== "object" ||
7998
+ ew.target === null ||
7999
+ !ew.target.widget ||
8000
+ !ew.target.handler
8001
+ ) {
8002
+ errors.push(
8003
+ `"eventWiring[${i}].target" must have "widget" and "handler" strings`,
8004
+ );
8005
+ }
8006
+ }
8007
+ }
8008
+ }
8009
+
8010
+ // Reject unknown top-level fields
8011
+ const allowedFields = Object.keys(schema.properties);
8012
+ for (const key of Object.keys(config)) {
8013
+ if (!allowedFields.includes(key)) {
8014
+ errors.push(`Unknown field: "${key}"`);
8015
+ }
8016
+ }
8017
+
8018
+ return { valid: errors.length === 0, errors };
8019
+ }
8020
+
8021
+ /**
8022
+ * Apply defaults to a dashboard config (fills in optional fields with defaults).
8023
+ *
8024
+ * @param {Object} config - A valid dashboard config
8025
+ * @returns {Object} Config with defaults applied (does not mutate original)
8026
+ */
8027
+ function applyDefaults$1(config) {
8028
+ return {
8029
+ schemaVersion: CURRENT_SCHEMA_VERSION$1,
8030
+ description: "",
8031
+ shareable: true,
8032
+ tags: [],
8033
+ icon: "grip",
8034
+ screenshots: [],
8035
+ providers: [],
8036
+ eventWiring: [],
8037
+ ...config,
8038
+ workspace: {
8039
+ type: "workspace",
8040
+ version: 1,
8041
+ menuId: 1,
8042
+ ...config.workspace,
8043
+ },
8044
+ };
8045
+ }
8046
+
8047
+ var dashboardConfigValidator$1 = {
8048
+ validateDashboardConfig: validateDashboardConfig$1,
8049
+ applyDefaults: applyDefaults$1,
8050
+ CURRENT_SCHEMA_VERSION: CURRENT_SCHEMA_VERSION$1,
8051
+ };
8052
+
8053
+ /**
8054
+ * dashboardConfigUtils.js
8055
+ *
8056
+ * Pure utility functions for dashboard config export/import.
8057
+ * No Electron dependencies — safe to test and reuse anywhere.
8058
+ */
8059
+
8060
+ /**
8061
+ * Collect all widget component names from a workspace layout.
8062
+ * Walks the layout tree and grid cells to find all placed components.
8063
+ *
8064
+ * @param {Array} layout - The workspace layout array
8065
+ * @returns {string[]} Unique component names
8066
+ */
8067
+ function collectComponentNames$1(layout) {
8068
+ const components = new Set();
8069
+
8070
+ for (const item of layout) {
8071
+ // Direct component reference
8072
+ if (item.component && item.type === "widget") {
8073
+ components.add(item.component);
8074
+ }
8075
+
8076
+ // Grid cells
8077
+ if (item.grid) {
8078
+ for (const [key, cell] of Object.entries(item.grid)) {
8079
+ // Grid cells are keyed as "row.col" (e.g., "1.1", "2.3")
8080
+ if (/^\d+\.\d+$/.test(key) && cell && cell.component) {
8081
+ // cell.component can be a string (component name) or a number (layout item id)
8082
+ if (typeof cell.component === "string") {
8083
+ components.add(cell.component);
8084
+ }
8085
+ }
8086
+ }
8087
+ }
8088
+ }
8089
+
8090
+ // Also check child items that reference components via grid
8091
+ // The layout is a flat array — items with type "widget" have a component name
8092
+ for (const item of layout) {
8093
+ if (
8094
+ item.component &&
8095
+ item.component !== "LayoutGridContainer" &&
8096
+ item.component !== "Container"
8097
+ ) {
8098
+ components.add(item.component);
8099
+ }
8100
+ }
8101
+
8102
+ // Remove container components — these are layout containers, not widgets
8103
+ components.delete("LayoutGridContainer");
8104
+ components.delete("Container");
8105
+
8106
+ return Array.from(components);
8107
+ }
8108
+
8109
+ /**
8110
+ * Extract event wiring from a workspace layout.
8111
+ * Reads the `listeners` property from layout items and converts
8112
+ * them to the dashboard config eventWiring format.
8113
+ *
8114
+ * LayoutModel.listeners format:
8115
+ * { "eventName": { "sourceWidget": "handlerName" } }
8116
+ * or
8117
+ * { "eventName": "SourceWidget" }
8118
+ *
8119
+ * Dashboard config eventWiring format:
8120
+ * [{ source: { widget, event }, target: { widget, handler } }]
8121
+ *
8122
+ * @param {Array} layout - The workspace layout array
8123
+ * @returns {Array} Event wiring array
8124
+ */
8125
+ function extractEventWiring$1(layout) {
8126
+ const wiring = [];
8127
+
8128
+ for (const item of layout) {
8129
+ if (!item.listeners || typeof item.listeners !== "object") continue;
8130
+
8131
+ const targetWidget = item.component;
8132
+ if (!targetWidget) continue;
8133
+
8134
+ for (const [eventName, listenerConfig] of Object.entries(
8135
+ item.listeners,
8136
+ )) {
8137
+ if (typeof listenerConfig === "string") {
8138
+ // Simple format: "SourceWidget"
8139
+ wiring.push({
8140
+ source: { widget: listenerConfig, event: eventName },
8141
+ target: { widget: targetWidget, handler: eventName },
8142
+ });
8143
+ } else if (
8144
+ typeof listenerConfig === "object" &&
8145
+ listenerConfig !== null
8146
+ ) {
8147
+ // Object format: { "SourceWidget": "handlerName" }
8148
+ for (const [sourceKey, handlerValue] of Object.entries(
8149
+ listenerConfig,
8150
+ )) {
8151
+ const parts = sourceKey.split(".");
8152
+ const sourceWidget = parts[0];
8153
+
8154
+ let handler = eventName;
8155
+ if (typeof handlerValue === "string") {
8156
+ handler = handlerValue;
8157
+ }
8158
+
8159
+ wiring.push({
8160
+ source: { widget: sourceWidget, event: eventName },
8161
+ target: { widget: targetWidget, handler },
8162
+ });
8163
+ }
8164
+ }
8165
+ }
8166
+ }
8167
+
8168
+ return wiring;
8169
+ }
8170
+
8171
+ /**
8172
+ * Build the widget dependencies array from component names and
8173
+ * installed widget metadata.
8174
+ *
8175
+ * @param {string[]} componentNames - Widget component names from layout
8176
+ * @param {Object} widgetRegistry - WidgetRegistry instance (optional, needs getWidgets())
8177
+ * @returns {Array} Widget dependency objects for the dashboard config
8178
+ */
8179
+ function buildWidgetDependencies$1(componentNames, widgetRegistry = null) {
8180
+ const widgets = [];
8181
+ const seen = new Set();
8182
+
8183
+ for (const name of componentNames) {
8184
+ if (seen.has(name)) continue;
8185
+ seen.add(name);
8186
+
8187
+ let packageName = "";
8188
+ let version = "*";
8189
+ let author = "";
8190
+
8191
+ // Try to resolve from widget registry
8192
+ if (widgetRegistry) {
8193
+ const installedWidgets = widgetRegistry.getWidgets();
8194
+ for (const w of installedWidgets) {
8195
+ if (w.componentNames && w.componentNames.includes(name)) {
8196
+ packageName = w.name || "";
8197
+ version = w.version || "*";
8198
+ author =
8199
+ typeof w.author === "string"
8200
+ ? w.author
8201
+ : w.author?.name || "";
8202
+ break;
8203
+ }
8204
+ }
8205
+ }
8206
+
8207
+ widgets.push({
8208
+ id: packageName ? `${packageName}.${name}` : name,
8209
+ package: packageName || name,
8210
+ version,
8211
+ required: true,
8212
+ author: author || "",
8213
+ });
8214
+ }
8215
+
8216
+ return widgets;
8217
+ }
8218
+
8219
+ /**
8220
+ * Aggregate provider requirements from installed widget configs.
8221
+ *
8222
+ * @param {string[]} componentNames - Widget component names from layout
8223
+ * @param {Object} widgetRegistry - WidgetRegistry instance (optional, needs getWidgets())
8224
+ * @returns {Array} Provider requirement objects for the dashboard config
8225
+ */
8226
+ function buildProviderRequirements$1(componentNames, widgetRegistry = null) {
8227
+ const providerMap = new Map();
8228
+
8229
+ if (!widgetRegistry) return [];
8230
+
8231
+ const installedWidgets = widgetRegistry.getWidgets();
8232
+
8233
+ for (const name of componentNames) {
8234
+ for (const w of installedWidgets) {
8235
+ if (
8236
+ w.providers &&
8237
+ w.componentNames &&
8238
+ w.componentNames.includes(name)
8239
+ ) {
8240
+ for (const p of w.providers) {
8241
+ const key = `${p.type}:${p.providerClass}`;
8242
+ if (!providerMap.has(key)) {
8243
+ providerMap.set(key, {
8244
+ type: p.type,
8245
+ providerClass: p.providerClass,
8246
+ required: p.required !== false,
8247
+ usedBy: [],
8248
+ });
8249
+ }
8250
+ const entry = providerMap.get(key);
8251
+ if (!entry.usedBy.includes(name)) {
8252
+ entry.usedBy.push(name);
8253
+ }
8254
+ }
8255
+ }
8256
+ }
8257
+ }
8258
+
8259
+ return Array.from(providerMap.values());
8260
+ }
8261
+
8262
+ var dashboardConfigUtils$1 = {
8263
+ collectComponentNames: collectComponentNames$1,
8264
+ extractEventWiring: extractEventWiring$1,
8265
+ buildWidgetDependencies: buildWidgetDependencies$1,
8266
+ buildProviderRequirements: buildProviderRequirements$1,
8267
+ };
8268
+
8269
+ /**
8270
+ * dashboardConfigController.js
8271
+ *
8272
+ * Handles export and import of dashboard configuration files.
8273
+ * Runs in the Electron main process.
8274
+ *
8275
+ * Export: serializes a workspace into a .dashboard.json config,
8276
+ * resolving widget dependencies, extracting event wiring from
8277
+ * layout listeners, and aggregating provider requirements.
8278
+ *
8279
+ * Import: validates and processes a .dashboard.json config,
8280
+ * auto-installs missing widgets, creates workspace, and
8281
+ * applies event wiring. (Import is implemented in DASH-13.)
8282
+ */
8283
+
8284
+ const { app, dialog } = require$$0$1;
8285
+ const path$2 = require$$1$1;
8286
+ const AdmZip = require$$2$5;
8287
+ const { getFileContents } = file;
8288
+ const {
8289
+ validateDashboardConfig,
8290
+ applyDefaults,
8291
+ CURRENT_SCHEMA_VERSION,
8292
+ } = dashboardConfigValidator$1;
8293
+ const {
8294
+ collectComponentNames,
8295
+ extractEventWiring,
8296
+ buildWidgetDependencies,
8297
+ buildProviderRequirements,
8298
+ } = dashboardConfigUtils$1;
8299
+
8300
+ const configFilename = "workspaces.json";
8301
+ const appName = "Dashboard";
8302
+
8303
+ /**
8304
+ * Export a workspace as a .dashboard.json config inside a ZIP file.
8305
+ *
8306
+ * @param {BrowserWindow} win - The main window (for dialog)
8307
+ * @param {string} appId - Application identifier
8308
+ * @param {number|string} workspaceId - ID of the workspace to export
8309
+ * @param {Object} options - Export options
8310
+ * @param {string} options.authorName - Dashboard author name
8311
+ * @param {string} options.authorId - Dashboard author ID
8312
+ * @param {Object} widgetRegistry - WidgetRegistry instance (optional)
8313
+ * @returns {Promise<Object>} Result with success flag and file path
8314
+ */
8315
+ async function exportDashboardConfig$1(
8316
+ win,
8317
+ appId,
8318
+ workspaceId,
8319
+ options = {},
8320
+ widgetRegistry = null,
8321
+ ) {
8322
+ try {
8323
+ // 1. Read workspace from workspaces.json
8324
+ const filename = path$2.join(
8325
+ app.getPath("userData"),
8326
+ appName,
8327
+ appId,
8328
+ configFilename,
8329
+ );
8330
+ const workspacesArray = getFileContents(filename);
8331
+ const workspace = workspacesArray.find(
8332
+ (w) => w.id === workspaceId || w.id === Number(workspaceId),
8333
+ );
8334
+
8335
+ if (!workspace) {
8336
+ return {
8337
+ success: false,
8338
+ error: `Workspace not found: ${workspaceId}`,
8339
+ };
8340
+ }
8341
+
8342
+ const layout = workspace.layout || [];
8343
+
8344
+ // 2. Collect components, extract wiring, resolve deps
8345
+ const componentNames = collectComponentNames(layout);
8346
+ const eventWiring = extractEventWiring(layout);
8347
+ const widgets = buildWidgetDependencies(componentNames, widgetRegistry);
8348
+ const providers = buildProviderRequirements(
8349
+ componentNames,
8350
+ widgetRegistry,
8351
+ );
8352
+
8353
+ // 3. Build the dashboard config
8354
+ const dashboardConfig = applyDefaults({
8355
+ schemaVersion: CURRENT_SCHEMA_VERSION,
8356
+ name: workspace.name || workspace.label || "Exported Dashboard",
8357
+ description: options.description || "",
8358
+ author: {
8359
+ name: options.authorName || "",
8360
+ id: options.authorId || "",
8361
+ },
8362
+ shareable: true,
8363
+ tags: options.tags || [],
8364
+ icon: options.icon || "grip",
8365
+ workspace: {
8366
+ id: workspace.id,
8367
+ name: workspace.name,
8368
+ type: workspace.type || "workspace",
8369
+ label: workspace.label || workspace.name,
8370
+ version: workspace.version || 1,
8371
+ layout,
8372
+ menuId: workspace.menuId || 1,
8373
+ },
8374
+ widgets,
8375
+ providers,
8376
+ eventWiring,
8377
+ });
8378
+
8379
+ // 4. Validate the generated config
8380
+ const validation = validateDashboardConfig(dashboardConfig);
8381
+ if (!validation.valid) {
8382
+ return {
8383
+ success: false,
8384
+ error: `Generated config is invalid: ${validation.errors.join(", ")}`,
8385
+ };
8386
+ }
8387
+
8388
+ // 5. Show save dialog
8389
+ const sanitizedName = (workspace.name || "dashboard")
8390
+ .replace(/[^a-zA-Z0-9-_ ]/g, "")
8391
+ .replace(/\s+/g, "-")
8392
+ .toLowerCase();
8393
+
8394
+ const { canceled, filePath } = await dialog.showSaveDialog(win, {
8395
+ title: "Export Dashboard as ZIP",
8396
+ defaultPath: path$2.join(
8397
+ app.getPath("desktop"),
8398
+ `${sanitizedName}.zip`,
8399
+ ),
8400
+ filters: [{ name: "ZIP Archive", extensions: ["zip"] }],
8401
+ });
8402
+
8403
+ if (canceled || !filePath) {
8404
+ return { success: false, canceled: true };
8405
+ }
8406
+
8407
+ // 6. Create ZIP with the config
8408
+ const zip = new AdmZip();
8409
+ const configJson = JSON.stringify(dashboardConfig, null, 2);
8410
+ zip.addFile(
8411
+ `${sanitizedName}.dashboard.json`,
8412
+ Buffer.from(configJson, "utf-8"),
8413
+ );
8414
+
8415
+ zip.writeZip(filePath);
8416
+
8417
+ console.log(
8418
+ `[DashboardConfigController] Exported dashboard to: ${filePath}`,
8419
+ );
8420
+
8421
+ return {
8422
+ success: true,
8423
+ filePath,
8424
+ config: dashboardConfig,
8425
+ };
8426
+ } catch (error) {
8427
+ console.error(
8428
+ "[DashboardConfigController] Error exporting dashboard:",
8429
+ error,
8430
+ );
8431
+ return {
8432
+ success: false,
8433
+ error: error.message,
8434
+ };
8435
+ }
8436
+ }
8437
+
8438
+ var dashboardConfigController$1 = {
8439
+ exportDashboardConfig: exportDashboardConfig$1,
8440
+ };
8441
+
7533
8442
  /**
7534
8443
  * clientFactories.js
7535
8444
  *
@@ -7553,7 +8462,7 @@ clientCache$1.registerFactory("algolia", (credentials) => {
7553
8462
 
7554
8463
  // --- OpenAI ---
7555
8464
  clientCache$1.registerFactory("openai", (credentials) => {
7556
- const OpenAI = require$$0$3;
8465
+ const OpenAI = require$$0$4;
7557
8466
  return new OpenAI({ apiKey: credentials.apiKey });
7558
8467
  });
7559
8468
 
@@ -7616,6 +8525,7 @@ const {
7616
8525
  listMenuItemsForApplication,
7617
8526
  } = menuItemsController_1;
7618
8527
  const { install: pluginInstall } = pluginController_1;
8528
+ const { exportDashboardConfig } = dashboardConfigController$1;
7619
8529
 
7620
8530
  var controller = {
7621
8531
  showDialog,
@@ -7658,9 +8568,10 @@ var controller = {
7658
8568
  listMenuItemsForApplication,
7659
8569
  pluginInstall,
7660
8570
  searchIndex,
8571
+ exportDashboardConfig,
7661
8572
  };
7662
8573
 
7663
- const { ipcRenderer: ipcRenderer$h } = require$$0;
8574
+ const { ipcRenderer: ipcRenderer$i } = require$$0$1;
7664
8575
  const {
7665
8576
  SECURE_STORE_ENCRYPTION_CHECK,
7666
8577
  SECURE_STORE_SET_DATA,
@@ -7672,10 +8583,10 @@ const {
7672
8583
  */
7673
8584
  const secureStoreApi$2 = {
7674
8585
  isEncryptionAvailable: () =>
7675
- ipcRenderer$h.invoke(SECURE_STORE_ENCRYPTION_CHECK, {}),
8586
+ ipcRenderer$i.invoke(SECURE_STORE_ENCRYPTION_CHECK, {}),
7676
8587
  saveData: (key, value) =>
7677
- ipcRenderer$h.invoke(SECURE_STORE_SET_DATA, { key, value }),
7678
- getData: (key) => ipcRenderer$h.invoke(SECURE_STORE_GET_DATA, { key }),
8588
+ ipcRenderer$i.invoke(SECURE_STORE_SET_DATA, { key, value }),
8589
+ getData: (key) => ipcRenderer$i.invoke(SECURE_STORE_GET_DATA, { key }),
7679
8590
  };
7680
8591
 
7681
8592
  var secureStoreApi_1 = secureStoreApi$2;
@@ -7686,7 +8597,7 @@ var secureStoreApi_1 = secureStoreApi$2;
7686
8597
  * Handle the workspace configuration file
7687
8598
  */
7688
8599
 
7689
- const { ipcRenderer: ipcRenderer$g } = require$$0;
8600
+ const { ipcRenderer: ipcRenderer$h } = require$$0$1;
7690
8601
  const {
7691
8602
  WORKSPACE_LIST,
7692
8603
  WORKSPACE_SAVE,
@@ -7703,7 +8614,7 @@ const workspaceApi$2 = {
7703
8614
  */
7704
8615
  listWorkspacesForApplication: (appId) => {
7705
8616
  console.log("listWorkspacesForApplication called with appId:", appId);
7706
- return ipcRenderer$g.invoke(WORKSPACE_LIST, { appId });
8617
+ return ipcRenderer$h.invoke(WORKSPACE_LIST, { appId });
7707
8618
  },
7708
8619
 
7709
8620
  /**
@@ -7714,7 +8625,7 @@ const workspaceApi$2 = {
7714
8625
  * @returns
7715
8626
  */
7716
8627
  saveWorkspaceForApplication: (appId, data) =>
7717
- ipcRenderer$g.invoke(WORKSPACE_SAVE, { appId, data }),
8628
+ ipcRenderer$h.invoke(WORKSPACE_SAVE, { appId, data }),
7718
8629
 
7719
8630
  /**
7720
8631
  * deleteWorkspaceForApplication
@@ -7724,7 +8635,7 @@ const workspaceApi$2 = {
7724
8635
  * @returns
7725
8636
  */
7726
8637
  deleteWorkspaceForApplication: (appId, workspaceId) =>
7727
- ipcRenderer$g.invoke(WORKSPACE_DELETE, { appId, workspaceId }),
8638
+ ipcRenderer$h.invoke(WORKSPACE_DELETE, { appId, workspaceId }),
7728
8639
  };
7729
8640
 
7730
8641
  var workspaceApi_1 = workspaceApi$2;
@@ -7736,15 +8647,15 @@ var workspaceApi_1 = workspaceApi$2;
7736
8647
  */
7737
8648
 
7738
8649
  // ipcRenderer that must be used to invoke the events
7739
- const { ipcRenderer: ipcRenderer$f } = require$$0;
8650
+ const { ipcRenderer: ipcRenderer$g } = require$$0$1;
7740
8651
 
7741
8652
  const { LAYOUT_LIST, LAYOUT_SAVE } = events$8;
7742
8653
 
7743
8654
  const layoutApi$2 = {
7744
8655
  listLayoutsForApplication: (appId) =>
7745
- ipcRenderer$f.invoke(LAYOUT_LIST, { appId }),
8656
+ ipcRenderer$g.invoke(LAYOUT_LIST, { appId }),
7746
8657
  saveLayoutForApplication: (appId, data) =>
7747
- ipcRenderer$f.invoke(LAYOUT_SAVE, { appId, data }),
8658
+ ipcRenderer$g.invoke(LAYOUT_SAVE, { appId, data }),
7748
8659
  };
7749
8660
 
7750
8661
  var layoutApi_1 = layoutApi$2;
@@ -7756,7 +8667,7 @@ var layoutApi_1 = layoutApi$2;
7756
8667
  */
7757
8668
 
7758
8669
  // ipcRenderer that must be used to invoke the events
7759
- const { ipcRenderer: ipcRenderer$e } = require$$0;
8670
+ const { ipcRenderer: ipcRenderer$f } = require$$0$1;
7760
8671
 
7761
8672
  const {
7762
8673
  DATA_JSON_TO_CSV_FILE,
@@ -7775,7 +8686,7 @@ const {
7775
8686
  const dataApi$2 = {
7776
8687
  // convert a json array of objects to a csv string and save to file
7777
8688
  convertJsonToCsvFile: (appId, jsonObject, filename) =>
7778
- ipcRenderer$e.invoke(DATA_JSON_TO_CSV_FILE, {
8689
+ ipcRenderer$f.invoke(DATA_JSON_TO_CSV_FILE, {
7779
8690
  appId,
7780
8691
  jsonObject,
7781
8692
  filename,
@@ -7783,10 +8694,10 @@ const dataApi$2 = {
7783
8694
 
7784
8695
  // convert a json array of objects to a csv string and return a string
7785
8696
  convertJsonToCsvString: (appId, jsonObject) =>
7786
- ipcRenderer$e.invoke(DATA_JSON_TO_CSV_STRING, { appId, jsonObject }),
8697
+ ipcRenderer$f.invoke(DATA_JSON_TO_CSV_STRING, { appId, jsonObject }),
7787
8698
 
7788
8699
  parseXMLStream: (filepath, outpath, start) =>
7789
- ipcRenderer$e.invoke(PARSE_XML_STREAM, {
8700
+ ipcRenderer$f.invoke(PARSE_XML_STREAM, {
7790
8701
  filepath,
7791
8702
  outpath,
7792
8703
  start,
@@ -7800,7 +8711,7 @@ const dataApi$2 = {
7800
8711
  headers = null,
7801
8712
  limit = null,
7802
8713
  ) => {
7803
- ipcRenderer$e.invoke(PARSE_CSV_STREAM, {
8714
+ ipcRenderer$f.invoke(PARSE_CSV_STREAM, {
7804
8715
  filepath,
7805
8716
  outpath,
7806
8717
  delimiter,
@@ -7811,15 +8722,15 @@ const dataApi$2 = {
7811
8722
  },
7812
8723
 
7813
8724
  readLinesFromFile: (filepath, lineCount) => {
7814
- ipcRenderer$e.invoke(READ_LINES, { filepath, lineCount });
8725
+ ipcRenderer$f.invoke(READ_LINES, { filepath, lineCount });
7815
8726
  },
7816
8727
 
7817
8728
  readJSONFromFile: (filepath, objectCount = null) => {
7818
- ipcRenderer$e.invoke(READ_JSON, { filepath, objectCount });
8729
+ ipcRenderer$f.invoke(READ_JSON, { filepath, objectCount });
7819
8730
  },
7820
8731
 
7821
8732
  readDataFromURL: (url, toFilepath) => {
7822
- ipcRenderer$e.invoke(READ_DATA_URL, { url, toFilepath });
8733
+ ipcRenderer$f.invoke(READ_DATA_URL, { url, toFilepath });
7823
8734
  },
7824
8735
 
7825
8736
  /*
@@ -7828,7 +8739,7 @@ const dataApi$2 = {
7828
8739
  * @param {object} returnEmpty the return empty object
7829
8740
  */
7830
8741
  saveData: (data, filename, append, returnEmpty, uuid) =>
7831
- ipcRenderer$e.invoke(DATA_SAVE_TO_FILE, {
8742
+ ipcRenderer$f.invoke(DATA_SAVE_TO_FILE, {
7832
8743
  data,
7833
8744
  filename,
7834
8745
  append,
@@ -7840,14 +8751,14 @@ const dataApi$2 = {
7840
8751
  * @param {string} filename the filename to read (not path)
7841
8752
  */
7842
8753
  readData: (filename, returnEmpty = []) =>
7843
- ipcRenderer$e.invoke(DATA_READ_FROM_FILE, { filename, returnEmpty }),
8754
+ ipcRenderer$f.invoke(DATA_READ_FROM_FILE, { filename, returnEmpty }),
7844
8755
 
7845
8756
  /**
7846
8757
  * transformFile
7847
8758
  * @returns
7848
8759
  */
7849
8760
  transformFile: (filepath, outFilepath, mappingFunctionBody, args) => {
7850
- ipcRenderer$e.invoke(TRANSFORM_FILE, {
8761
+ ipcRenderer$f.invoke(TRANSFORM_FILE, {
7851
8762
  filepath,
7852
8763
  outFilepath,
7853
8764
  mappingFunctionBody,
@@ -7856,7 +8767,7 @@ const dataApi$2 = {
7856
8767
  },
7857
8768
 
7858
8769
  extractColorsFromImageURL: (url) => {
7859
- ipcRenderer$e.invoke(EXTRACT_COLORS_FROM_IMAGE, {
8770
+ ipcRenderer$f.invoke(EXTRACT_COLORS_FROM_IMAGE, {
7860
8771
  url,
7861
8772
  });
7862
8773
  },
@@ -7871,7 +8782,7 @@ var dataApi_1 = dataApi$2;
7871
8782
  */
7872
8783
 
7873
8784
  // ipcRenderer that must be used to invoke the events
7874
- const { ipcRenderer: ipcRenderer$d } = require$$0;
8785
+ const { ipcRenderer: ipcRenderer$e } = require$$0$1;
7875
8786
 
7876
8787
  const {
7877
8788
  SETTINGS_GET,
@@ -7882,14 +8793,14 @@ const {
7882
8793
  } = events$8;
7883
8794
 
7884
8795
  const settingsApi$2 = {
7885
- getSettingsForApplication: () => ipcRenderer$d.invoke(SETTINGS_GET, {}),
8796
+ getSettingsForApplication: () => ipcRenderer$e.invoke(SETTINGS_GET, {}),
7886
8797
  saveSettingsForApplication: (data) =>
7887
- ipcRenderer$d.invoke(SETTINGS_SAVE, { data }),
7888
- getDataDirectory: () => ipcRenderer$d.invoke(SETTINGS_GET_DATA_DIR, {}),
8798
+ ipcRenderer$e.invoke(SETTINGS_SAVE, { data }),
8799
+ getDataDirectory: () => ipcRenderer$e.invoke(SETTINGS_GET_DATA_DIR, {}),
7889
8800
  setDataDirectory: (dataDirectory) =>
7890
- ipcRenderer$d.invoke(SETTINGS_SET_DATA_DIR, { dataDirectory }),
8801
+ ipcRenderer$e.invoke(SETTINGS_SET_DATA_DIR, { dataDirectory }),
7891
8802
  migrateDataDirectory: (oldDirectory, newDirectory) =>
7892
- ipcRenderer$d.invoke(SETTINGS_MIGRATE_DATA_DIR, {
8803
+ ipcRenderer$e.invoke(SETTINGS_MIGRATE_DATA_DIR, {
7893
8804
  oldDirectory,
7894
8805
  newDirectory,
7895
8806
  }),
@@ -7904,7 +8815,7 @@ var settingsApi_1 = settingsApi$2;
7904
8815
  */
7905
8816
 
7906
8817
  // ipcRenderer that must be used to invoke the events
7907
- const { ipcRenderer: ipcRenderer$c } = require$$0;
8818
+ const { ipcRenderer: ipcRenderer$d } = require$$0$1;
7908
8819
 
7909
8820
  const { CHOOSE_FILE } = events$8;
7910
8821
 
@@ -7916,7 +8827,7 @@ const dialogApi$2 = {
7916
8827
  */
7917
8828
  chooseFile: (allowFile = true, extensions = ["*"]) => {
7918
8829
  console.log("dialog api choose file");
7919
- return ipcRenderer$c.invoke(CHOOSE_FILE, { allowFile, extensions });
8830
+ return ipcRenderer$d.invoke(CHOOSE_FILE, { allowFile, extensions });
7920
8831
  },
7921
8832
  };
7922
8833
 
@@ -7935,7 +8846,7 @@ var dialogApi_1 = dialogApi$2;
7935
8846
  * mainApi.widgets.uninstall('Weather')
7936
8847
  */
7937
8848
 
7938
- const { ipcRenderer: ipcRenderer$b } = require$$0;
8849
+ const { ipcRenderer: ipcRenderer$c } = require$$0$1;
7939
8850
 
7940
8851
  const widgetApi$2 = {
7941
8852
  /**
@@ -7944,7 +8855,7 @@ const widgetApi$2 = {
7944
8855
  */
7945
8856
  list: async () => {
7946
8857
  try {
7947
- return await ipcRenderer$b.invoke("widget:list");
8858
+ return await ipcRenderer$c.invoke("widget:list");
7948
8859
  } catch (error) {
7949
8860
  console.error("[WidgetApi] Error listing widgets:", error);
7950
8861
  throw error;
@@ -7958,7 +8869,7 @@ const widgetApi$2 = {
7958
8869
  */
7959
8870
  get: async (widgetName) => {
7960
8871
  try {
7961
- return await ipcRenderer$b.invoke("widget:get", widgetName);
8872
+ return await ipcRenderer$c.invoke("widget:get", widgetName);
7962
8873
  } catch (error) {
7963
8874
  console.error(`[WidgetApi] Error getting widget ${widgetName}:`, error);
7964
8875
  throw error;
@@ -7989,7 +8900,7 @@ const widgetApi$2 = {
7989
8900
  console.log(
7990
8901
  `[WidgetApi] Installing widget: ${widgetName} from ${downloadUrl}`,
7991
8902
  );
7992
- const config = await ipcRenderer$b.invoke(
8903
+ const config = await ipcRenderer$c.invoke(
7993
8904
  "widget:install",
7994
8905
  widgetName,
7995
8906
  downloadUrl,
@@ -8029,7 +8940,7 @@ const widgetApi$2 = {
8029
8940
  console.log(
8030
8941
  `[WidgetApi] Installing local widget: ${widgetName} from ${localPath}`,
8031
8942
  );
8032
- const config = await ipcRenderer$b.invoke(
8943
+ const config = await ipcRenderer$c.invoke(
8033
8944
  "widget:install-local",
8034
8945
  widgetName,
8035
8946
  localPath,
@@ -8060,7 +8971,7 @@ const widgetApi$2 = {
8060
8971
  loadFolder: async (folderPath) => {
8061
8972
  try {
8062
8973
  console.log(`[WidgetApi] Loading widgets from folder: ${folderPath}`);
8063
- const results = await ipcRenderer$b.invoke(
8974
+ const results = await ipcRenderer$c.invoke(
8064
8975
  "widget:load-folder",
8065
8976
  folderPath,
8066
8977
  );
@@ -8084,7 +8995,7 @@ const widgetApi$2 = {
8084
8995
  uninstall: async (widgetName) => {
8085
8996
  try {
8086
8997
  console.log(`[WidgetApi] Uninstalling widget: ${widgetName}`);
8087
- const success = await ipcRenderer$b.invoke("widget:uninstall", widgetName);
8998
+ const success = await ipcRenderer$c.invoke("widget:uninstall", widgetName);
8088
8999
  if (success) {
8089
9000
  console.log(`[WidgetApi] ✓ Widget ${widgetName} uninstalled`);
8090
9001
  } else {
@@ -8107,7 +9018,7 @@ const widgetApi$2 = {
8107
9018
  */
8108
9019
  getCachePath: async () => {
8109
9020
  try {
8110
- return await ipcRenderer$b.invoke("widget:cache-path");
9021
+ return await ipcRenderer$c.invoke("widget:cache-path");
8111
9022
  } catch (error) {
8112
9023
  console.error("[WidgetApi] Error getting cache path:", error);
8113
9024
  throw error;
@@ -8121,7 +9032,7 @@ const widgetApi$2 = {
8121
9032
  */
8122
9033
  getStoragePath: async () => {
8123
9034
  try {
8124
- return await ipcRenderer$b.invoke("widget:storage-path");
9035
+ return await ipcRenderer$c.invoke("widget:storage-path");
8125
9036
  } catch (error) {
8126
9037
  console.error("[WidgetApi] Error getting storage path:", error);
8127
9038
  throw error;
@@ -8138,7 +9049,7 @@ const widgetApi$2 = {
8138
9049
  setStoragePath: async (customPath) => {
8139
9050
  try {
8140
9051
  console.log(`[WidgetApi] Setting storage path to: ${customPath}`);
8141
- const result = await ipcRenderer$b.invoke(
9052
+ const result = await ipcRenderer$c.invoke(
8142
9053
  "widget:set-storage-path",
8143
9054
  customPath,
8144
9055
  );
@@ -8160,7 +9071,7 @@ const widgetApi$2 = {
8160
9071
  */
8161
9072
  getComponentConfigs: async () => {
8162
9073
  try {
8163
- return await ipcRenderer$b.invoke("widget:get-component-configs");
9074
+ return await ipcRenderer$c.invoke("widget:get-component-configs");
8164
9075
  } catch (error) {
8165
9076
  console.error("[WidgetApi] Error getting component configs:", error);
8166
9077
  return [];
@@ -8175,7 +9086,7 @@ const widgetApi$2 = {
8175
9086
  */
8176
9087
  readBundle: async (widgetName) => {
8177
9088
  try {
8178
- return await ipcRenderer$b.invoke("widget:read-bundle", widgetName);
9089
+ return await ipcRenderer$c.invoke("widget:read-bundle", widgetName);
8179
9090
  } catch (error) {
8180
9091
  console.error(
8181
9092
  `[WidgetApi] Error reading bundle for ${widgetName}:`,
@@ -8192,7 +9103,7 @@ const widgetApi$2 = {
8192
9103
  */
8193
9104
  readAllBundles: async () => {
8194
9105
  try {
8195
- return await ipcRenderer$b.invoke("widget:read-all-bundles");
9106
+ return await ipcRenderer$c.invoke("widget:read-all-bundles");
8196
9107
  } catch (error) {
8197
9108
  console.error("[WidgetApi] Error reading all bundles:", error);
8198
9109
  return [];
@@ -8212,7 +9123,7 @@ const widgetApi$2 = {
8212
9123
  * });
8213
9124
  */
8214
9125
  onInstalled: (callback) => {
8215
- ipcRenderer$b.on("widget:installed", (event, data) => {
9126
+ ipcRenderer$c.on("widget:installed", (event, data) => {
8216
9127
  callback(data);
8217
9128
  });
8218
9129
  },
@@ -8230,7 +9141,7 @@ const widgetApi$2 = {
8230
9141
  * });
8231
9142
  */
8232
9143
  onLoaded: (callback) => {
8233
- ipcRenderer$b.on("widgets:loaded", (event, data) => {
9144
+ ipcRenderer$c.on("widgets:loaded", (event, data) => {
8234
9145
  callback(data);
8235
9146
  });
8236
9147
  },
@@ -8241,7 +9152,7 @@ const widgetApi$2 = {
8241
9152
  * @param {Function} callback - The callback to remove
8242
9153
  */
8243
9154
  removeInstalledListener: (callback) => {
8244
- ipcRenderer$b.removeListener("widget:installed", callback);
9155
+ ipcRenderer$c.removeListener("widget:installed", callback);
8245
9156
  },
8246
9157
 
8247
9158
  /**
@@ -8250,7 +9161,7 @@ const widgetApi$2 = {
8250
9161
  * @param {Function} callback - The callback to remove
8251
9162
  */
8252
9163
  removeLoadedListener: (callback) => {
8253
- ipcRenderer$b.removeListener("widgets:loaded", callback);
9164
+ ipcRenderer$c.removeListener("widgets:loaded", callback);
8254
9165
  },
8255
9166
  };
8256
9167
 
@@ -8263,7 +9174,7 @@ var widgetApi_1 = widgetApi$2;
8263
9174
  * Communicates with main process via IPC to handle encryption and file storage
8264
9175
  */
8265
9176
 
8266
- const { ipcRenderer: ipcRenderer$a } = require$$0;
9177
+ const { ipcRenderer: ipcRenderer$b } = require$$0$1;
8267
9178
  const {
8268
9179
  PROVIDER_SAVE,
8269
9180
  PROVIDER_LIST,
@@ -8295,7 +9206,7 @@ const providerApi$2 = {
8295
9206
  mcpConfig = null,
8296
9207
  allowedTools = null,
8297
9208
  ) =>
8298
- ipcRenderer$a.invoke(PROVIDER_SAVE, {
9209
+ ipcRenderer$b.invoke(PROVIDER_SAVE, {
8299
9210
  appId,
8300
9211
  providerName,
8301
9212
  providerType,
@@ -8313,7 +9224,7 @@ const providerApi$2 = {
8313
9224
  * @param {String} appId - the appId specified in the dash initialization
8314
9225
  * @returns {Promise<Array>} Array of provider objects with name, type, credentials
8315
9226
  */
8316
- listProviders: (appId) => ipcRenderer$a.invoke(PROVIDER_LIST, { appId }),
9227
+ listProviders: (appId) => ipcRenderer$b.invoke(PROVIDER_LIST, { appId }),
8317
9228
 
8318
9229
  /**
8319
9230
  * getProvider
@@ -8325,7 +9236,7 @@ const providerApi$2 = {
8325
9236
  * @returns {Promise<Object>} Provider object with name, type, credentials
8326
9237
  */
8327
9238
  getProvider: (appId, providerName) =>
8328
- ipcRenderer$a.invoke(PROVIDER_GET, { appId, providerName }),
9239
+ ipcRenderer$b.invoke(PROVIDER_GET, { appId, providerName }),
8329
9240
 
8330
9241
  /**
8331
9242
  * deleteProvider
@@ -8337,7 +9248,7 @@ const providerApi$2 = {
8337
9248
  * @returns {Promise}
8338
9249
  */
8339
9250
  deleteProvider: (appId, providerName) =>
8340
- ipcRenderer$a.invoke(PROVIDER_DELETE, { appId, providerName }),
9251
+ ipcRenderer$b.invoke(PROVIDER_DELETE, { appId, providerName }),
8341
9252
 
8342
9253
  /**
8343
9254
  * listProvidersForApplication
@@ -8347,14 +9258,14 @@ const providerApi$2 = {
8347
9258
  * @param {String} appId - the appId specified in the dash initialization
8348
9259
  */
8349
9260
  listProvidersForApplication: (appId) => {
8350
- ipcRenderer$a
9261
+ ipcRenderer$b
8351
9262
  .invoke(PROVIDER_LIST, { appId })
8352
9263
  .then((result) => {
8353
9264
  // Emit the event for ElectronDashboardApi to listen to
8354
- ipcRenderer$a.send("PROVIDER_LIST_COMPLETE", result);
9265
+ ipcRenderer$b.send("PROVIDER_LIST_COMPLETE", result);
8355
9266
  })
8356
9267
  .catch((error) => {
8357
- ipcRenderer$a.send("PROVIDER_LIST_ERROR", {
9268
+ ipcRenderer$b.send("PROVIDER_LIST_ERROR", {
8358
9269
  error: error.message,
8359
9270
  });
8360
9271
  });
@@ -8371,7 +9282,7 @@ const providerApi$2 = {
8371
9282
  providerType,
8372
9283
  credentials,
8373
9284
  ) => {
8374
- ipcRenderer$a
9285
+ ipcRenderer$b
8375
9286
  .invoke(PROVIDER_SAVE, {
8376
9287
  appId,
8377
9288
  providerName,
@@ -8379,10 +9290,10 @@ const providerApi$2 = {
8379
9290
  credentials,
8380
9291
  })
8381
9292
  .then((result) => {
8382
- ipcRenderer$a.send("PROVIDER_SAVE_COMPLETE", result);
9293
+ ipcRenderer$b.send("PROVIDER_SAVE_COMPLETE", result);
8383
9294
  })
8384
9295
  .catch((error) => {
8385
- ipcRenderer$a.send("PROVIDER_SAVE_ERROR", {
9296
+ ipcRenderer$b.send("PROVIDER_SAVE_ERROR", {
8386
9297
  error: error.message,
8387
9298
  });
8388
9299
  });
@@ -8394,13 +9305,13 @@ const providerApi$2 = {
8394
9305
  * Event-listener-based version for use with ElectronDashboardApi
8395
9306
  */
8396
9307
  getProviderForApplication: (appId, providerName) => {
8397
- ipcRenderer$a
9308
+ ipcRenderer$b
8398
9309
  .invoke(PROVIDER_GET, { appId, providerName })
8399
9310
  .then((result) => {
8400
- ipcRenderer$a.send("PROVIDER_GET_COMPLETE", result);
9311
+ ipcRenderer$b.send("PROVIDER_GET_COMPLETE", result);
8401
9312
  })
8402
9313
  .catch((error) => {
8403
- ipcRenderer$a.send("PROVIDER_GET_ERROR", {
9314
+ ipcRenderer$b.send("PROVIDER_GET_ERROR", {
8404
9315
  error: error.message,
8405
9316
  });
8406
9317
  });
@@ -8412,13 +9323,13 @@ const providerApi$2 = {
8412
9323
  * Event-listener-based version for use with ElectronDashboardApi
8413
9324
  */
8414
9325
  deleteProviderForApplication: (appId, providerName) => {
8415
- ipcRenderer$a
9326
+ ipcRenderer$b
8416
9327
  .invoke(PROVIDER_DELETE, { appId, providerName })
8417
9328
  .then((result) => {
8418
- ipcRenderer$a.send("PROVIDER_DELETE_COMPLETE", result);
9329
+ ipcRenderer$b.send("PROVIDER_DELETE_COMPLETE", result);
8419
9330
  })
8420
9331
  .catch((error) => {
8421
- ipcRenderer$a.send("PROVIDER_DELETE_ERROR", {
9332
+ ipcRenderer$b.send("PROVIDER_DELETE_ERROR", {
8422
9333
  error: error.message,
8423
9334
  });
8424
9335
  });
@@ -8434,7 +9345,7 @@ var providerApi_1 = providerApi$2;
8434
9345
  * Communicates with main process via IPC to manage MCP server lifecycle.
8435
9346
  */
8436
9347
 
8437
- const { ipcRenderer: ipcRenderer$9 } = require$$0;
9348
+ const { ipcRenderer: ipcRenderer$a } = require$$0$1;
8438
9349
  const {
8439
9350
  MCP_START_SERVER,
8440
9351
  MCP_STOP_SERVER,
@@ -8458,7 +9369,7 @@ const mcpApi$2 = {
8458
9369
  * @returns {Promise<{ success, serverName, tools, status } | { error, message }>}
8459
9370
  */
8460
9371
  startServer: (serverName, mcpConfig, credentials) =>
8461
- ipcRenderer$9.invoke(MCP_START_SERVER, {
9372
+ ipcRenderer$a.invoke(MCP_START_SERVER, {
8462
9373
  serverName,
8463
9374
  mcpConfig,
8464
9375
  credentials,
@@ -8472,7 +9383,7 @@ const mcpApi$2 = {
8472
9383
  * @returns {Promise<{ success, serverName } | { error, message }>}
8473
9384
  */
8474
9385
  stopServer: (serverName) =>
8475
- ipcRenderer$9.invoke(MCP_STOP_SERVER, { serverName }),
9386
+ ipcRenderer$a.invoke(MCP_STOP_SERVER, { serverName }),
8476
9387
 
8477
9388
  /**
8478
9389
  * listTools
@@ -8481,7 +9392,7 @@ const mcpApi$2 = {
8481
9392
  * @param {string} serverName the server name
8482
9393
  * @returns {Promise<{ tools } | { error, message }>}
8483
9394
  */
8484
- listTools: (serverName) => ipcRenderer$9.invoke(MCP_LIST_TOOLS, { serverName }),
9395
+ listTools: (serverName) => ipcRenderer$a.invoke(MCP_LIST_TOOLS, { serverName }),
8485
9396
 
8486
9397
  /**
8487
9398
  * callTool
@@ -8494,7 +9405,7 @@ const mcpApi$2 = {
8494
9405
  * @returns {Promise<{ result } | { error, message }>}
8495
9406
  */
8496
9407
  callTool: (serverName, toolName, args, allowedTools = null) =>
8497
- ipcRenderer$9.invoke(MCP_CALL_TOOL, {
9408
+ ipcRenderer$a.invoke(MCP_CALL_TOOL, {
8498
9409
  serverName,
8499
9410
  toolName,
8500
9411
  args,
@@ -8509,7 +9420,7 @@ const mcpApi$2 = {
8509
9420
  * @returns {Promise<{ resources } | { error, message }>}
8510
9421
  */
8511
9422
  listResources: (serverName) =>
8512
- ipcRenderer$9.invoke(MCP_LIST_RESOURCES, { serverName }),
9423
+ ipcRenderer$a.invoke(MCP_LIST_RESOURCES, { serverName }),
8513
9424
 
8514
9425
  /**
8515
9426
  * readResource
@@ -8520,7 +9431,7 @@ const mcpApi$2 = {
8520
9431
  * @returns {Promise<{ resource } | { error, message }>}
8521
9432
  */
8522
9433
  readResource: (serverName, uri) =>
8523
- ipcRenderer$9.invoke(MCP_READ_RESOURCE, { serverName, uri }),
9434
+ ipcRenderer$a.invoke(MCP_READ_RESOURCE, { serverName, uri }),
8524
9435
 
8525
9436
  /**
8526
9437
  * getServerStatus
@@ -8530,7 +9441,7 @@ const mcpApi$2 = {
8530
9441
  * @returns {Promise<{ status, tools, error }>}
8531
9442
  */
8532
9443
  getServerStatus: (serverName) =>
8533
- ipcRenderer$9.invoke(MCP_SERVER_STATUS, { serverName }),
9444
+ ipcRenderer$a.invoke(MCP_SERVER_STATUS, { serverName }),
8534
9445
 
8535
9446
  /**
8536
9447
  * getCatalog
@@ -8538,7 +9449,7 @@ const mcpApi$2 = {
8538
9449
  *
8539
9450
  * @returns {Promise<{ catalog } | { error, message }>}
8540
9451
  */
8541
- getCatalog: () => ipcRenderer$9.invoke(MCP_GET_CATALOG),
9452
+ getCatalog: () => ipcRenderer$a.invoke(MCP_GET_CATALOG),
8542
9453
 
8543
9454
  /**
8544
9455
  * runAuth
@@ -8550,7 +9461,7 @@ const mcpApi$2 = {
8550
9461
  * @returns {Promise<{ success } | { error, message }>}
8551
9462
  */
8552
9463
  runAuth: (mcpConfig, credentials, authCommand) =>
8553
- ipcRenderer$9.invoke(MCP_RUN_AUTH, { mcpConfig, credentials, authCommand }),
9464
+ ipcRenderer$a.invoke(MCP_RUN_AUTH, { mcpConfig, credentials, authCommand }),
8554
9465
  };
8555
9466
 
8556
9467
  var mcpApi_1 = mcpApi$2;
@@ -8568,7 +9479,7 @@ var mcpApi_1 = mcpApi$2;
8568
9479
  * mainApi.registry.checkUpdates([{ name: "weather-widgets", version: "1.0.0" }])
8569
9480
  */
8570
9481
 
8571
- const { ipcRenderer: ipcRenderer$8 } = require$$0;
9482
+ const { ipcRenderer: ipcRenderer$9 } = require$$0$1;
8572
9483
 
8573
9484
  const registryApi$2 = {
8574
9485
  /**
@@ -8578,7 +9489,7 @@ const registryApi$2 = {
8578
9489
  */
8579
9490
  fetchIndex: async (forceRefresh = false) => {
8580
9491
  try {
8581
- return await ipcRenderer$8.invoke("registry:fetch-index", forceRefresh);
9492
+ return await ipcRenderer$9.invoke("registry:fetch-index", forceRefresh);
8582
9493
  } catch (error) {
8583
9494
  console.error("[RegistryApi] Error fetching index:", error);
8584
9495
  throw error;
@@ -8593,7 +9504,7 @@ const registryApi$2 = {
8593
9504
  */
8594
9505
  search: async (query = "", filters = {}) => {
8595
9506
  try {
8596
- return await ipcRenderer$8.invoke("registry:search", query, filters);
9507
+ return await ipcRenderer$9.invoke("registry:search", query, filters);
8597
9508
  } catch (error) {
8598
9509
  console.error("[RegistryApi] Error searching registry:", error);
8599
9510
  throw error;
@@ -8607,7 +9518,7 @@ const registryApi$2 = {
8607
9518
  */
8608
9519
  getPackage: async (packageName) => {
8609
9520
  try {
8610
- return await ipcRenderer$8.invoke("registry:get-package", packageName);
9521
+ return await ipcRenderer$9.invoke("registry:get-package", packageName);
8611
9522
  } catch (error) {
8612
9523
  console.error(
8613
9524
  `[RegistryApi] Error getting package ${packageName}:`,
@@ -8624,7 +9535,7 @@ const registryApi$2 = {
8624
9535
  */
8625
9536
  checkUpdates: async (installedWidgets = []) => {
8626
9537
  try {
8627
- return await ipcRenderer$8.invoke(
9538
+ return await ipcRenderer$9.invoke(
8628
9539
  "registry:check-updates",
8629
9540
  installedWidgets,
8630
9541
  );
@@ -8643,17 +9554,17 @@ var registryApi_1 = registryApi$2;
8643
9554
  * Handle the theme configuration file
8644
9555
  */
8645
9556
 
8646
- const { ipcRenderer: ipcRenderer$7 } = require$$0;
9557
+ const { ipcRenderer: ipcRenderer$8 } = require$$0$1;
8647
9558
 
8648
9559
  const { THEME_LIST, THEME_SAVE, THEME_DELETE } = events$8;
8649
9560
 
8650
9561
  const themeApi$2 = {
8651
9562
  listThemesForApplication: (appId) =>
8652
- ipcRenderer$7.invoke(THEME_LIST, { appId }),
9563
+ ipcRenderer$8.invoke(THEME_LIST, { appId }),
8653
9564
  saveThemeForApplication: (appId, themeName, themeObject) =>
8654
- ipcRenderer$7.invoke(THEME_SAVE, { appId, themeName, themeObject }),
9565
+ ipcRenderer$8.invoke(THEME_SAVE, { appId, themeName, themeObject }),
8655
9566
  deleteThemeForApplication: (appId, themeKey) =>
8656
- ipcRenderer$7.invoke(THEME_DELETE, { appId, themeKey }),
9567
+ ipcRenderer$8.invoke(THEME_DELETE, { appId, themeKey }),
8657
9568
  };
8658
9569
 
8659
9570
  var themeApi_1 = themeApi$2;
@@ -8665,7 +9576,7 @@ var themeApi_1 = themeApi$2;
8665
9576
  */
8666
9577
 
8667
9578
  // ipcRenderer that must be used to invoke the events
8668
- const { ipcRenderer: ipcRenderer$6 } = require$$0;
9579
+ const { ipcRenderer: ipcRenderer$7 } = require$$0$1;
8669
9580
 
8670
9581
  const {
8671
9582
  ALGOLIA_LIST_INDICES,
@@ -8679,10 +9590,10 @@ const {
8679
9590
 
8680
9591
  const algoliaApi$2 = {
8681
9592
  listIndices: (application) =>
8682
- ipcRenderer$6.invoke(ALGOLIA_LIST_INDICES, application),
9593
+ ipcRenderer$7.invoke(ALGOLIA_LIST_INDICES, application),
8683
9594
 
8684
9595
  browseObjects: (appId, apiKey, indexName) => {
8685
- ipcRenderer$6.invoke(ALGOLIA_BROWSE_OBJECTS, {
9596
+ ipcRenderer$7.invoke(ALGOLIA_BROWSE_OBJECTS, {
8686
9597
  appId,
8687
9598
  apiKey,
8688
9599
  indexName,
@@ -8690,10 +9601,10 @@ const algoliaApi$2 = {
8690
9601
  });
8691
9602
  },
8692
9603
 
8693
- saveSynonyms: () => ipcRenderer$6.invoke(ALGOLIA_SAVE_SYNONYMS, {}),
9604
+ saveSynonyms: () => ipcRenderer$7.invoke(ALGOLIA_SAVE_SYNONYMS, {}),
8694
9605
 
8695
9606
  getAnalyticsForQuery: (application, indexName, query) =>
8696
- ipcRenderer$6.invoke(ALGOLIA_ANALYTICS_FOR_QUERY, {
9607
+ ipcRenderer$7.invoke(ALGOLIA_ANALYTICS_FOR_QUERY, {
8697
9608
  application,
8698
9609
  indexName,
8699
9610
  query,
@@ -8706,7 +9617,7 @@ const algoliaApi$2 = {
8706
9617
  dir,
8707
9618
  createIfNotExists = false,
8708
9619
  ) =>
8709
- ipcRenderer$6.invoke(ALGOLIA_PARTIAL_UPDATE_OBJECTS, {
9620
+ ipcRenderer$7.invoke(ALGOLIA_PARTIAL_UPDATE_OBJECTS, {
8710
9621
  appId,
8711
9622
  apiKey,
8712
9623
  indexName,
@@ -8715,7 +9626,7 @@ const algoliaApi$2 = {
8715
9626
  }),
8716
9627
 
8717
9628
  createBatchesFromFile: (filepath, batchFilepath, batchSize) => {
8718
- ipcRenderer$6.invoke(ALGOLIA_CREATE_BATCH, {
9629
+ ipcRenderer$7.invoke(ALGOLIA_CREATE_BATCH, {
8719
9630
  filepath,
8720
9631
  batchFilepath,
8721
9632
  batchSize,
@@ -8723,7 +9634,7 @@ const algoliaApi$2 = {
8723
9634
  },
8724
9635
 
8725
9636
  browseObjectsToFile: (appId, apiKey, indexName, toFilename, query = "") => {
8726
- ipcRenderer$6.invoke(ALGOLIA_BROWSE_OBJECTS, {
9637
+ ipcRenderer$7.invoke(ALGOLIA_BROWSE_OBJECTS, {
8727
9638
  appId,
8728
9639
  apiKey,
8729
9640
  indexName,
@@ -8733,7 +9644,7 @@ const algoliaApi$2 = {
8733
9644
  },
8734
9645
 
8735
9646
  search: (appId, apiKey, indexName, query = "", options = {}) =>
8736
- ipcRenderer$6.invoke(ALGOLIA_SEARCH, {
9647
+ ipcRenderer$7.invoke(ALGOLIA_SEARCH, {
8737
9648
  appId,
8738
9649
  apiKey,
8739
9650
  indexName,
@@ -8748,14 +9659,14 @@ var algoliaApi_1 = algoliaApi$2;
8748
9659
  * openAI
8749
9660
  */
8750
9661
 
8751
- const { ipcRenderer: ipcRenderer$5 } = require$$0;
9662
+ const { ipcRenderer: ipcRenderer$6 } = require$$0$1;
8752
9663
 
8753
9664
  const { OPENAI_DESCRIBE_IMAGE } = openaiEvents$1;
8754
9665
 
8755
9666
  const openaiApi$2 = {
8756
9667
  // convert a json array of objects to a csv string and save to file
8757
9668
  describeImage: (imageUrl, apiKey, prompt = "What's in this image?") =>
8758
- ipcRenderer$5.invoke(OPENAI_DESCRIBE_IMAGE, { imageUrl, apiKey, prompt }),
9669
+ ipcRenderer$6.invoke(OPENAI_DESCRIBE_IMAGE, { imageUrl, apiKey, prompt }),
8759
9670
  };
8760
9671
 
8761
9672
  var openaiApi_1 = openaiApi$2;
@@ -8766,14 +9677,14 @@ var openaiApi_1 = openaiApi$2;
8766
9677
  */
8767
9678
 
8768
9679
  // ipcRenderer that must be used to invoke the events
8769
- const { ipcRenderer: ipcRenderer$4 } = require$$0;
9680
+ const { ipcRenderer: ipcRenderer$5 } = require$$0$1;
8770
9681
 
8771
9682
  const { MENU_ITEMS_SAVE, MENU_ITEMS_LIST } = events$8;
8772
9683
 
8773
9684
  const menuItemsApi$2 = {
8774
9685
  saveMenuItem: (appId, menuItem) =>
8775
- ipcRenderer$4.invoke(MENU_ITEMS_SAVE, { appId, menuItem }),
8776
- listMenuItems: (appId) => ipcRenderer$4.invoke(MENU_ITEMS_LIST, { appId }),
9686
+ ipcRenderer$5.invoke(MENU_ITEMS_SAVE, { appId, menuItem }),
9687
+ listMenuItems: (appId) => ipcRenderer$5.invoke(MENU_ITEMS_LIST, { appId }),
8777
9688
  };
8778
9689
 
8779
9690
  var menuItemsApi_1 = menuItemsApi$2;
@@ -8785,12 +9696,12 @@ var menuItemsApi_1 = menuItemsApi$2;
8785
9696
  */
8786
9697
 
8787
9698
  // ipcRenderer that must be used to invoke the events
8788
- const { ipcRenderer: ipcRenderer$3 } = require$$0;
9699
+ const { ipcRenderer: ipcRenderer$4 } = require$$0$1;
8789
9700
 
8790
9701
  const pluginApi$2 = {
8791
9702
  install: (packageName, filepath) =>
8792
- ipcRenderer$3.invoke("plugin-install", { packageName, filepath }),
8793
- uninstall: (filepath) => ipcRenderer$3.invoke("plugin-uninstall", filepath),
9703
+ ipcRenderer$4.invoke("plugin-install", { packageName, filepath }),
9704
+ uninstall: (filepath) => ipcRenderer$4.invoke("plugin-uninstall", filepath),
8794
9705
  };
8795
9706
 
8796
9707
  var pluginApi_1 = pluginApi$2;
@@ -8803,7 +9714,7 @@ var pluginApi_1 = pluginApi$2;
8803
9714
  * tool-use events, and request cancellation.
8804
9715
  */
8805
9716
 
8806
- const { ipcRenderer: ipcRenderer$2 } = require$$0;
9717
+ const { ipcRenderer: ipcRenderer$3 } = require$$0$1;
8807
9718
  const {
8808
9719
  LLM_SEND_MESSAGE,
8809
9720
  LLM_ABORT_REQUEST,
@@ -8825,7 +9736,7 @@ const _listenerMap = new Map();
8825
9736
  function _addListener(channel, callback) {
8826
9737
  const id = String(++_nextListenerId);
8827
9738
  const wrapped = (_event, data) => callback(data);
8828
- ipcRenderer$2.on(channel, wrapped);
9739
+ ipcRenderer$3.on(channel, wrapped);
8829
9740
  _listenerMap.set(id, { channel, wrapped });
8830
9741
  return id;
8831
9742
  }
@@ -8840,7 +9751,7 @@ const llmApi$2 = {
8840
9751
  * @returns {Promise<void>}
8841
9752
  */
8842
9753
  sendMessage: (requestId, params) =>
8843
- ipcRenderer$2.invoke(LLM_SEND_MESSAGE, { requestId, ...params }),
9754
+ ipcRenderer$3.invoke(LLM_SEND_MESSAGE, { requestId, ...params }),
8844
9755
 
8845
9756
  /**
8846
9757
  * abortRequest
@@ -8850,7 +9761,7 @@ const llmApi$2 = {
8850
9761
  * @returns {Promise<{ success: boolean }>}
8851
9762
  */
8852
9763
  abortRequest: (requestId) =>
8853
- ipcRenderer$2.invoke(LLM_ABORT_REQUEST, { requestId }),
9764
+ ipcRenderer$3.invoke(LLM_ABORT_REQUEST, { requestId }),
8854
9765
 
8855
9766
  /**
8856
9767
  * listConnectedTools
@@ -8858,7 +9769,7 @@ const llmApi$2 = {
8858
9769
  *
8859
9770
  * @returns {Promise<Array<{ serverName, tools, resources, status }>>}
8860
9771
  */
8861
- listConnectedTools: () => ipcRenderer$2.invoke(LLM_LIST_CONNECTED_TOOLS),
9772
+ listConnectedTools: () => ipcRenderer$3.invoke(LLM_LIST_CONNECTED_TOOLS),
8862
9773
 
8863
9774
  /**
8864
9775
  * checkCliAvailable
@@ -8866,7 +9777,7 @@ const llmApi$2 = {
8866
9777
  *
8867
9778
  * @returns {Promise<{ available: boolean, path?: string }>}
8868
9779
  */
8869
- checkCliAvailable: () => ipcRenderer$2.invoke(LLM_CHECK_CLI_AVAILABLE),
9780
+ checkCliAvailable: () => ipcRenderer$3.invoke(LLM_CHECK_CLI_AVAILABLE),
8870
9781
 
8871
9782
  /**
8872
9783
  * clearCliSession
@@ -8876,7 +9787,7 @@ const llmApi$2 = {
8876
9787
  * @returns {Promise<{ success: boolean }>}
8877
9788
  */
8878
9789
  clearCliSession: (widgetUuid) =>
8879
- ipcRenderer$2.invoke(LLM_CLEAR_CLI_SESSION, { widgetUuid }),
9790
+ ipcRenderer$3.invoke(LLM_CLEAR_CLI_SESSION, { widgetUuid }),
8880
9791
 
8881
9792
  /**
8882
9793
  * getCliSessionStatus
@@ -8886,7 +9797,7 @@ const llmApi$2 = {
8886
9797
  * @returns {Promise<{ hasSession: boolean, sessionId?: string, isProcessActive: boolean }>}
8887
9798
  */
8888
9799
  getCliSessionStatus: (widgetUuid) =>
8889
- ipcRenderer$2.invoke(LLM_CLI_SESSION_STATUS, { widgetUuid }),
9800
+ ipcRenderer$3.invoke(LLM_CLI_SESSION_STATUS, { widgetUuid }),
8890
9801
 
8891
9802
  /**
8892
9803
  * endCliSession
@@ -8896,7 +9807,7 @@ const llmApi$2 = {
8896
9807
  * @returns {Promise<{ success: boolean }>}
8897
9808
  */
8898
9809
  endCliSession: (widgetUuid) =>
8899
- ipcRenderer$2.invoke(LLM_CLI_END_SESSION, { widgetUuid }),
9810
+ ipcRenderer$3.invoke(LLM_CLI_END_SESSION, { widgetUuid }),
8900
9811
 
8901
9812
  // --- Stream event listeners ---
8902
9813
  // Each on* method returns an opaque string ID. Strings cross the
@@ -8930,7 +9841,7 @@ const llmApi$2 = {
8930
9841
  const listenerId = id !== undefined ? String(id) : String(idOrChannel);
8931
9842
  const entry = _listenerMap.get(listenerId);
8932
9843
  if (entry) {
8933
- ipcRenderer$2.removeListener(entry.channel, entry.wrapped);
9844
+ ipcRenderer$3.removeListener(entry.channel, entry.wrapped);
8934
9845
  _listenerMap.delete(listenerId);
8935
9846
  }
8936
9847
  },
@@ -8942,14 +9853,14 @@ const llmApi$2 = {
8942
9853
  */
8943
9854
  removeAllStreamListeners: () => {
8944
9855
  for (const [, entry] of _listenerMap) {
8945
- ipcRenderer$2.removeListener(entry.channel, entry.wrapped);
9856
+ ipcRenderer$3.removeListener(entry.channel, entry.wrapped);
8946
9857
  }
8947
9858
  _listenerMap.clear();
8948
- ipcRenderer$2.removeAllListeners(LLM_STREAM_DELTA);
8949
- ipcRenderer$2.removeAllListeners(LLM_STREAM_TOOL_CALL);
8950
- ipcRenderer$2.removeAllListeners(LLM_STREAM_TOOL_RESULT);
8951
- ipcRenderer$2.removeAllListeners(LLM_STREAM_COMPLETE);
8952
- ipcRenderer$2.removeAllListeners(LLM_STREAM_ERROR);
9859
+ ipcRenderer$3.removeAllListeners(LLM_STREAM_DELTA);
9860
+ ipcRenderer$3.removeAllListeners(LLM_STREAM_TOOL_CALL);
9861
+ ipcRenderer$3.removeAllListeners(LLM_STREAM_TOOL_RESULT);
9862
+ ipcRenderer$3.removeAllListeners(LLM_STREAM_COMPLETE);
9863
+ ipcRenderer$3.removeAllListeners(LLM_STREAM_ERROR);
8953
9864
  },
8954
9865
  };
8955
9866
 
@@ -8963,7 +9874,7 @@ var llmApi_1 = llmApi$2;
8963
9874
  * and manage the response cache.
8964
9875
  */
8965
9876
 
8966
- const { ipcRenderer: ipcRenderer$1 } = require$$0;
9877
+ const { ipcRenderer: ipcRenderer$2 } = require$$0$1;
8967
9878
  const {
8968
9879
  CLIENT_CACHE_INVALIDATE,
8969
9880
  CLIENT_CACHE_INVALIDATE_ALL,
@@ -8980,32 +9891,75 @@ const clientCacheApi$2 = {
8980
9891
  * @returns {Promise<{success: boolean}>}
8981
9892
  */
8982
9893
  invalidate: (appId, providerName) =>
8983
- ipcRenderer$1.invoke(CLIENT_CACHE_INVALIDATE, { appId, providerName }),
9894
+ ipcRenderer$2.invoke(CLIENT_CACHE_INVALIDATE, { appId, providerName }),
8984
9895
 
8985
9896
  /**
8986
9897
  * Invalidate all cached clients.
8987
9898
  *
8988
9899
  * @returns {Promise<{success: boolean}>}
8989
9900
  */
8990
- invalidateAll: () => ipcRenderer$1.invoke(CLIENT_CACHE_INVALIDATE_ALL),
9901
+ invalidateAll: () => ipcRenderer$2.invoke(CLIENT_CACHE_INVALIDATE_ALL),
8991
9902
 
8992
9903
  /**
8993
9904
  * Clear the response cache.
8994
9905
  *
8995
9906
  * @returns {Promise<{success: boolean}>}
8996
9907
  */
8997
- clearResponseCache: () => ipcRenderer$1.invoke(RESPONSE_CACHE_CLEAR),
9908
+ clearResponseCache: () => ipcRenderer$2.invoke(RESPONSE_CACHE_CLEAR),
8998
9909
 
8999
9910
  /**
9000
9911
  * Get response cache statistics.
9001
9912
  *
9002
9913
  * @returns {Promise<{entries: number, inflight: number, keys: string[]}>}
9003
9914
  */
9004
- responseCacheStats: () => ipcRenderer$1.invoke(RESPONSE_CACHE_STATS),
9915
+ responseCacheStats: () => ipcRenderer$2.invoke(RESPONSE_CACHE_STATS),
9005
9916
  };
9006
9917
 
9007
9918
  var clientCacheApi_1 = clientCacheApi$2;
9008
9919
 
9920
+ /**
9921
+ * dashboardConfigApi.js
9922
+ *
9923
+ * IPC bridge for dashboard config export/import (renderer side).
9924
+ * Exposed via contextBridge through mainApi.
9925
+ */
9926
+
9927
+ const { ipcRenderer: ipcRenderer$1 } = require$$0$1;
9928
+ const {
9929
+ DASHBOARD_CONFIG_EXPORT,
9930
+ DASHBOARD_CONFIG_IMPORT,
9931
+ } = events$8;
9932
+
9933
+ const dashboardConfigApi$2 = {
9934
+ /**
9935
+ * Export a workspace as a dashboard config ZIP file.
9936
+ *
9937
+ * @param {string} appId - Application identifier
9938
+ * @param {number|string} workspaceId - ID of the workspace to export
9939
+ * @param {Object} options - Export options (authorName, authorId, description, tags, icon)
9940
+ * @returns {Promise<Object>} Result with success, filePath, and config
9941
+ */
9942
+ exportDashboardConfig: (appId, workspaceId, options = {}) =>
9943
+ ipcRenderer$1.invoke(DASHBOARD_CONFIG_EXPORT, {
9944
+ appId,
9945
+ workspaceId,
9946
+ options,
9947
+ }),
9948
+
9949
+ /**
9950
+ * Import a dashboard config from a ZIP file.
9951
+ * Shows a file picker, validates the config, installs missing widgets,
9952
+ * creates the workspace, and applies event wiring.
9953
+ *
9954
+ * @param {string} appId - Application identifier
9955
+ * @returns {Promise<Object>} Result with success, workspace, and summary
9956
+ */
9957
+ importDashboardConfig: (appId) =>
9958
+ ipcRenderer$1.invoke(DASHBOARD_CONFIG_IMPORT, { appId }),
9959
+ };
9960
+
9961
+ var dashboardConfigApi_1 = dashboardConfigApi$2;
9962
+
9009
9963
  var widgetRegistry$1 = {exports: {}};
9010
9964
 
9011
9965
  var dynamicWidgetLoader$2 = {exports: {}};
@@ -9222,7 +10176,7 @@ var widgetCompiler$1 = { compileWidget, findWidgetsDir: findWidgetsDir$1 };
9222
10176
 
9223
10177
  const fs = require$$2;
9224
10178
  const path = require$$1$1;
9225
- const vm = require$$2$5;
10179
+ const vm = require$$2$6;
9226
10180
  const { findWidgetsDir } = widgetCompiler$1;
9227
10181
 
9228
10182
  class DynamicWidgetLoader {
@@ -9425,10 +10379,10 @@ var dynamicWidgetLoaderExports = dynamicWidgetLoader$2.exports;
9425
10379
  (function (module) {
9426
10380
  const fs = require$$2;
9427
10381
  const path = require$$1$1;
9428
- const os = require$$2$6;
9429
- const AdmZip = require$$3$3;
10382
+ const os = require$$2$7;
10383
+ const AdmZip = require$$2$5;
9430
10384
  const { fileURLToPath } = require$$4$1;
9431
- const { app, ipcMain, BrowserWindow } = require$$0;
10385
+ const { app, ipcMain, BrowserWindow } = require$$0$1;
9432
10386
  const { dynamicWidgetLoader } = dynamicWidgetLoaderExports;
9433
10387
  const { compileWidget, findWidgetsDir } = widgetCompiler$1;
9434
10388
 
@@ -10390,7 +11344,7 @@ var widgetRegistryExports = widgetRegistry$1.exports;
10390
11344
  * contextBridge.exposeInMainWorld("mainApi", defaultMainApi);
10391
11345
  */
10392
11346
 
10393
- const { ipcRenderer, shell } = require$$0;
11347
+ const { ipcRenderer, shell } = require$$0$1;
10394
11348
  const secureStoreApi$1 = secureStoreApi_1;
10395
11349
  const workspaceApi$1 = workspaceApi_1;
10396
11350
  const layoutApi$1 = layoutApi_1;
@@ -10408,6 +11362,7 @@ const menuItemsApi$1 = menuItemsApi_1;
10408
11362
  const pluginApi$1 = pluginApi_1;
10409
11363
  const llmApi$1 = llmApi_1;
10410
11364
  const clientCacheApi$1 = clientCacheApi_1;
11365
+ const dashboardConfigApi$1 = dashboardConfigApi_1;
10411
11366
 
10412
11367
  // Events constants
10413
11368
  const events$1 = events$8;
@@ -10479,6 +11434,7 @@ function createMainApi$1(extensions = {}) {
10479
11434
  menuItems: menuItemsApi$1,
10480
11435
  plugins: pluginApi$1,
10481
11436
  clientCache: clientCacheApi$1,
11437
+ dashboardConfig: dashboardConfigApi$1,
10482
11438
 
10483
11439
  widgetEvent: {
10484
11440
  publish: (eventType, content) => {
@@ -10524,6 +11480,7 @@ const menuItemsController = menuItemsController_1;
10524
11480
  const pluginController = pluginController_1;
10525
11481
  const llmController = llmController_1;
10526
11482
  const cliController = cliController_1;
11483
+ const dashboardConfigController = dashboardConfigController$1;
10527
11484
 
10528
11485
  // --- Utils ---
10529
11486
  const clientCache = requireClientCache();
@@ -10551,6 +11508,7 @@ const menuItemsApi = menuItemsApi_1;
10551
11508
  const pluginApi = pluginApi_1;
10552
11509
  const llmApi = llmApi_1;
10553
11510
  const clientCacheApi = clientCacheApi_1;
11511
+ const dashboardConfigApi = dashboardConfigApi_1;
10554
11512
 
10555
11513
  // --- Events ---
10556
11514
  const events = events$8;
@@ -10560,6 +11518,10 @@ const widgetRegistry = widgetRegistryExports;
10560
11518
  const widgetCompiler = widgetCompiler$1;
10561
11519
  const dynamicWidgetLoader = dynamicWidgetLoaderExports;
10562
11520
 
11521
+ // --- Schema ---
11522
+ const dashboardConfigValidator = dashboardConfigValidator$1;
11523
+ const dashboardConfigUtils = dashboardConfigUtils$1;
11524
+
10563
11525
  // --- Factory: createMainApi ---
10564
11526
  const { createMainApi, defaultMainApi } = mainApi;
10565
11527
 
@@ -10581,6 +11543,7 @@ var electron = {
10581
11543
  pluginController,
10582
11544
  llmController,
10583
11545
  cliController,
11546
+ dashboardConfigController,
10584
11547
 
10585
11548
  // Controller functions (flat) — spread for convenient destructuring
10586
11549
  ...controllers,
@@ -10603,6 +11566,7 @@ var electron = {
10603
11566
  pluginApi,
10604
11567
  llmApi,
10605
11568
  clientCacheApi,
11569
+ dashboardConfigApi,
10606
11570
 
10607
11571
  // Events
10608
11572
  events,
@@ -10620,6 +11584,10 @@ var electron = {
10620
11584
  clientCache,
10621
11585
  responseCache,
10622
11586
 
11587
+ // Schema
11588
+ dashboardConfigValidator,
11589
+ dashboardConfigUtils,
11590
+
10623
11591
  // Setup helpers
10624
11592
  setupCacheHandlers: clientCache.setupCacheHandlers.bind(clientCache),
10625
11593
  };