@trops/dash-core 0.1.170 → 0.1.172

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.
@@ -828,49 +828,57 @@ var themeFromUrlEvents$1 = {
828
828
  * IPC communication between main and renderer processes.
829
829
  */
830
830
 
831
- const WS_CONNECT$1 = "ws-connect";
832
- const WS_CONNECT_COMPLETE = "ws-connect-complete";
833
- const WS_CONNECT_ERROR = "ws-connect-error";
834
-
835
- const WS_DISCONNECT$1 = "ws-disconnect";
836
- const WS_DISCONNECT_COMPLETE = "ws-disconnect-complete";
837
- const WS_DISCONNECT_ERROR = "ws-disconnect-error";
838
-
839
- const WS_SEND$1 = "ws-send";
840
- const WS_SEND_COMPLETE = "ws-send-complete";
841
- const WS_SEND_ERROR = "ws-send-error";
842
-
843
- const WS_STATUS$1 = "ws-status";
844
- const WS_STATUS_COMPLETE = "ws-status-complete";
845
- const WS_STATUS_ERROR = "ws-status-error";
846
-
847
- const WS_MESSAGE$1 = "ws-message";
848
-
849
- const WS_STATUS_CHANGE$1 = "ws-status-change";
850
-
851
- const WS_GET_ALL$1 = "ws-get-all";
852
- const WS_GET_ALL_COMPLETE = "ws-get-all-complete";
853
- const WS_GET_ALL_ERROR = "ws-get-all-error";
854
-
855
- var webSocketEvents$1 = {
856
- WS_CONNECT: WS_CONNECT$1,
857
- WS_CONNECT_COMPLETE,
858
- WS_CONNECT_ERROR,
859
- WS_DISCONNECT: WS_DISCONNECT$1,
860
- WS_DISCONNECT_COMPLETE,
861
- WS_DISCONNECT_ERROR,
862
- WS_SEND: WS_SEND$1,
863
- WS_SEND_COMPLETE,
864
- WS_SEND_ERROR,
865
- WS_STATUS: WS_STATUS$1,
866
- WS_STATUS_COMPLETE,
867
- WS_STATUS_ERROR,
868
- WS_MESSAGE: WS_MESSAGE$1,
869
- WS_STATUS_CHANGE: WS_STATUS_CHANGE$1,
870
- WS_GET_ALL: WS_GET_ALL$1,
871
- WS_GET_ALL_COMPLETE,
872
- WS_GET_ALL_ERROR,
873
- };
831
+ var webSocketEvents$1;
832
+ var hasRequiredWebSocketEvents;
833
+
834
+ function requireWebSocketEvents () {
835
+ if (hasRequiredWebSocketEvents) return webSocketEvents$1;
836
+ hasRequiredWebSocketEvents = 1;
837
+ const WS_CONNECT = "ws-connect";
838
+ const WS_CONNECT_COMPLETE = "ws-connect-complete";
839
+ const WS_CONNECT_ERROR = "ws-connect-error";
840
+
841
+ const WS_DISCONNECT = "ws-disconnect";
842
+ const WS_DISCONNECT_COMPLETE = "ws-disconnect-complete";
843
+ const WS_DISCONNECT_ERROR = "ws-disconnect-error";
844
+
845
+ const WS_SEND = "ws-send";
846
+ const WS_SEND_COMPLETE = "ws-send-complete";
847
+ const WS_SEND_ERROR = "ws-send-error";
848
+
849
+ const WS_STATUS = "ws-status";
850
+ const WS_STATUS_COMPLETE = "ws-status-complete";
851
+ const WS_STATUS_ERROR = "ws-status-error";
852
+
853
+ const WS_MESSAGE = "ws-message";
854
+
855
+ const WS_STATUS_CHANGE = "ws-status-change";
856
+
857
+ const WS_GET_ALL = "ws-get-all";
858
+ const WS_GET_ALL_COMPLETE = "ws-get-all-complete";
859
+ const WS_GET_ALL_ERROR = "ws-get-all-error";
860
+
861
+ webSocketEvents$1 = {
862
+ WS_CONNECT,
863
+ WS_CONNECT_COMPLETE,
864
+ WS_CONNECT_ERROR,
865
+ WS_DISCONNECT,
866
+ WS_DISCONNECT_COMPLETE,
867
+ WS_DISCONNECT_ERROR,
868
+ WS_SEND,
869
+ WS_SEND_COMPLETE,
870
+ WS_SEND_ERROR,
871
+ WS_STATUS,
872
+ WS_STATUS_COMPLETE,
873
+ WS_STATUS_ERROR,
874
+ WS_MESSAGE,
875
+ WS_STATUS_CHANGE,
876
+ WS_GET_ALL,
877
+ WS_GET_ALL_COMPLETE,
878
+ WS_GET_ALL_ERROR,
879
+ };
880
+ return webSocketEvents$1;
881
+ }
874
882
 
875
883
  /**
876
884
  * Event Constants File - MCP Dash Server Events
@@ -923,7 +931,7 @@ const sessionEvents = sessionEvents$1;
923
931
  const notificationEvents = notificationEvents$1;
924
932
  const schedulerEvents = schedulerEvents$1;
925
933
  const themeFromUrlEvents = themeFromUrlEvents$1;
926
- const webSocketEvents = webSocketEvents$1;
934
+ const webSocketEvents = requireWebSocketEvents();
927
935
  const mcpDashServerEvents = mcpDashServerEvents$1;
928
936
 
929
937
  const publicEvents = {
@@ -1207,7 +1215,7 @@ const { getFileContents: getFileContents$7 } = file;
1207
1215
  const configFilename$5 = "workspaces.json";
1208
1216
  const appName$7 = "Dashboard";
1209
1217
 
1210
- const workspaceController$1 = {
1218
+ const workspaceController$2 = {
1211
1219
  /**
1212
1220
  * createWorkspace
1213
1221
  *
@@ -1449,7 +1457,7 @@ const workspaceController$1 = {
1449
1457
  },
1450
1458
  };
1451
1459
 
1452
- var workspaceController_1 = workspaceController$1;
1460
+ var workspaceController_1 = workspaceController$2;
1453
1461
 
1454
1462
  const { app: app$9 } = require$$0$2;
1455
1463
  const path$f = require$$1$2;
@@ -1459,7 +1467,7 @@ const { getFileContents: getFileContents$6 } = file;
1459
1467
  const configFilename$4 = "themes.json";
1460
1468
  const appName$6 = "Dashboard";
1461
1469
 
1462
- const themeController$3 = {
1470
+ const themeController$4 = {
1463
1471
  /**
1464
1472
  * saveTheme
1465
1473
  * Create a new Theme that can be used in the application
@@ -1590,7 +1598,7 @@ const themeController$3 = {
1590
1598
  },
1591
1599
  };
1592
1600
 
1593
- var themeController_1 = themeController$3;
1601
+ var themeController_1 = themeController$4;
1594
1602
 
1595
1603
  /**
1596
1604
  * Utils/tranaform
@@ -26864,7 +26872,7 @@ async function searchThemes(query = "", filters = {}) {
26864
26872
  return searchRegistry$1(query, { ...filters, type: "theme" });
26865
26873
  }
26866
26874
 
26867
- var registryController$2 = {
26875
+ var registryController$3 = {
26868
26876
  fetchRegistryIndex,
26869
26877
  searchRegistry: searchRegistry$1,
26870
26878
  searchDashboards,
@@ -31843,8 +31851,8 @@ const path$2 = require$$1$2;
31843
31851
  const { app: app$2, dialog: dialog$1 } = require$$0$2;
31844
31852
  const AdmZip$1 = require$$3$4;
31845
31853
 
31846
- const themeController$2 = themeController_1;
31847
- const registryController$1 = registryController$2;
31854
+ const themeController$3 = themeController_1;
31855
+ const registryController$2 = registryController$3;
31848
31856
  const registryApiController$1 = registryApiController$2;
31849
31857
  const {
31850
31858
  getAuthStatus,
@@ -31950,7 +31958,7 @@ function extractColors(themeData) {
31950
31958
  async function prepareThemeForPublish$1(win, appId, themeKey, options = {}) {
31951
31959
  try {
31952
31960
  // Read the theme data
31953
- const themesResult = themeController$2.listThemesForApplication(win, appId);
31961
+ const themesResult = themeController$3.listThemesForApplication(win, appId);
31954
31962
  if (themesResult.error) {
31955
31963
  return {
31956
31964
  success: false,
@@ -32074,7 +32082,7 @@ async function prepareThemeForPublish$1(win, appId, themeKey, options = {}) {
32074
32082
  async function installThemeFromRegistry$1(win, appId, packageName) {
32075
32083
  try {
32076
32084
  // Look up the package
32077
- const pkg = await registryController$1.getPackage(packageName);
32085
+ const pkg = await registryController$2.getPackage(packageName);
32078
32086
  if (!pkg) {
32079
32087
  return {
32080
32088
  success: false,
@@ -32161,7 +32169,7 @@ async function installThemeFromRegistry$1(win, appId, packageName) {
32161
32169
  const themeKey = pkg.displayName || pkg.name;
32162
32170
 
32163
32171
  // Save via themeController
32164
- const saveResult = themeController$2.saveThemeForApplication(
32172
+ const saveResult = themeController$3.saveThemeForApplication(
32165
32173
  win,
32166
32174
  appId,
32167
32175
  themeKey,
@@ -32198,7 +32206,7 @@ async function installThemeFromRegistry$1(win, appId, packageName) {
32198
32206
  */
32199
32207
  function getThemePublishPreview$1(appId, themeKey) {
32200
32208
  try {
32201
- const themesResult = themeController$2.listThemesForApplication(null, appId);
32209
+ const themesResult = themeController$3.listThemesForApplication(null, appId);
32202
32210
  if (themesResult.error) {
32203
32211
  return {
32204
32212
  success: false,
@@ -32264,8 +32272,8 @@ const {
32264
32272
  buildProviderRequirements,
32265
32273
  applyEventWiringToLayout,
32266
32274
  } = dashboardConfigUtils$1;
32267
- const { searchRegistry, getPackage } = registryController$2;
32268
- const themeController$1 = themeController_1;
32275
+ const { searchRegistry, getPackage } = registryController$3;
32276
+ const themeController$2 = themeController_1;
32269
32277
 
32270
32278
  const configFilename = "workspaces.json";
32271
32279
  const appName$1 = "Dashboard";
@@ -32345,7 +32353,7 @@ async function exportDashboardConfig$1(
32345
32353
  // 4. Bundle theme if workspace has a themeKey
32346
32354
  if (workspace.themeKey) {
32347
32355
  try {
32348
- const themeResult = themeController$1.listThemesForApplication(
32356
+ const themeResult = themeController$2.listThemesForApplication(
32349
32357
  win,
32350
32358
  appId,
32351
32359
  );
@@ -32700,7 +32708,7 @@ async function processDashboardConfig(
32700
32708
  if (dashboardConfig.theme) {
32701
32709
  const bundledTheme = dashboardConfig.theme;
32702
32710
  try {
32703
- const themeResult = themeController$1.listThemesForApplication(win, appId);
32711
+ const themeResult = themeController$2.listThemesForApplication(win, appId);
32704
32712
  const existingThemes = themeResult.themes || {};
32705
32713
  const themeKey = bundledTheme.key;
32706
32714
 
@@ -32714,7 +32722,7 @@ async function processDashboardConfig(
32714
32722
  installedAt: new Date().toISOString(),
32715
32723
  };
32716
32724
  }
32717
- themeController$1.saveThemeForApplication(
32725
+ themeController$2.saveThemeForApplication(
32718
32726
  win,
32719
32727
  appId,
32720
32728
  themeKey,
@@ -32990,7 +32998,7 @@ async function checkCompatibility$1(dashboardWidgets, widgetRegistry = null) {
32990
32998
  const {
32991
32999
  checkDashboardCompatibility,
32992
33000
  } = dashboardConfigUtils$1;
32993
- const { fetchRegistryIndex } = registryController$2;
33001
+ const { fetchRegistryIndex } = registryController$3;
32994
33002
 
32995
33003
  const installedWidgets = widgetRegistry ? widgetRegistry.getWidgets() : [];
32996
33004
 
@@ -33112,7 +33120,7 @@ async function prepareDashboardForPublish$1(
33112
33120
  // 4. Bundle theme if workspace has a themeKey
33113
33121
  if (workspace.themeKey) {
33114
33122
  try {
33115
- const themeResult = themeController$1.listThemesForApplication(
33123
+ const themeResult = themeController$2.listThemesForApplication(
33116
33124
  win,
33117
33125
  appId,
33118
33126
  );
@@ -33145,7 +33153,7 @@ async function prepareDashboardForPublish$1(
33145
33153
  }
33146
33154
 
33147
33155
  // 6. Check which widgets exist in the registry (soft warning, not blocking)
33148
- const { fetchRegistryIndex } = registryController$2;
33156
+ const { fetchRegistryIndex } = registryController$3;
33149
33157
  let registryPackages = [];
33150
33158
  let registryCheckFailed = false;
33151
33159
  try {
@@ -33292,7 +33300,7 @@ async function getDashboardPreview$1(packageName, widgetRegistry = null) {
33292
33300
  buildDashboardPreview,
33293
33301
  checkDashboardCompatibility,
33294
33302
  } = dashboardConfigUtils$1;
33295
- const { getPackage, fetchRegistryIndex } = registryController$2;
33303
+ const { getPackage, fetchRegistryIndex } = registryController$3;
33296
33304
 
33297
33305
  const pkg = await getPackage(packageName);
33298
33306
  if (!pkg) {
@@ -33337,7 +33345,7 @@ async function getDashboardPreview$1(packageName, widgetRegistry = null) {
33337
33345
  */
33338
33346
  async function checkDashboardUpdatesForApp$1(appId) {
33339
33347
  const { checkDashboardUpdates } = dashboardConfigUtils$1;
33340
- const { fetchRegistryIndex } = registryController$2;
33348
+ const { fetchRegistryIndex } = registryController$3;
33341
33349
 
33342
33350
  try {
33343
33351
  const filename = path$1.join(
@@ -45243,7 +45251,7 @@ function interpolate(template, credentials) {
45243
45251
  * @param {object} extra - Additional fields (error, retryCount, retryIn, etc.)
45244
45252
  */
45245
45253
  function broadcastStatusChange(providerName, status, extra = {}) {
45246
- const { WS_STATUS_CHANGE } = webSocketEvents$1;
45254
+ const { WS_STATUS_CHANGE } = requireWebSocketEvents();
45247
45255
  const { BrowserWindow } = require$$0$2;
45248
45256
 
45249
45257
  const payload = { provider: providerName, status, ...extra };
@@ -45261,7 +45269,7 @@ function broadcastStatusChange(providerName, status, extra = {}) {
45261
45269
  * @param {*} data - The message data
45262
45270
  */
45263
45271
  function broadcastMessage(providerName, data) {
45264
- const { WS_MESSAGE } = webSocketEvents$1;
45272
+ const { WS_MESSAGE } = requireWebSocketEvents();
45265
45273
  const { BrowserWindow } = require$$0$2;
45266
45274
 
45267
45275
  const payload = {
@@ -66056,6 +66064,7 @@ let httpServer = null;
66056
66064
  let transport = null;
66057
66065
  let startTime = null;
66058
66066
  let connectionCount = 0;
66067
+ let activeWin = null;
66059
66068
 
66060
66069
  // --- Rate Limiting ---
66061
66070
  const RATE_LIMIT = 60; // requests per minute
@@ -66102,7 +66111,7 @@ const registeredResources = [];
66102
66111
  * Register a tool to be exposed via the MCP server.
66103
66112
  * Call this before starting the server (or restart after registering).
66104
66113
  */
66105
- function registerTool(toolDef) {
66114
+ function registerTool$2(toolDef) {
66106
66115
  registeredTools.push(toolDef);
66107
66116
  }
66108
66117
 
@@ -66144,8 +66153,43 @@ function saveMcpServerSettings(win, mcpSettings) {
66144
66153
  settingsController$1.saveSettingsForApplication(win, settings);
66145
66154
  }
66146
66155
 
66156
+ // --- App ID Resolution ---
66157
+ /**
66158
+ * Resolve the appId by scanning the userData/Dashboard directory for
66159
+ * subdirectories containing workspaces.json. Falls back to the default.
66160
+ */
66161
+ function resolveAppId() {
66162
+ const { app } = require$$0$2;
66163
+ const fs = require$$0$3;
66164
+ const path = require$$1$2;
66165
+ const dashboardDir = path.join(app.getPath("userData"), "Dashboard");
66166
+ try {
66167
+ const entries = fs.readdirSync(dashboardDir, { withFileTypes: true });
66168
+ for (const entry of entries) {
66169
+ if (entry.isDirectory()) {
66170
+ const wsFile = path.join(dashboardDir, entry.name, "workspaces.json");
66171
+ if (fs.existsSync(wsFile)) {
66172
+ return entry.name;
66173
+ }
66174
+ }
66175
+ }
66176
+ } catch (e) {
66177
+ // Directory may not exist yet
66178
+ }
66179
+ return "@trops/dash-electron";
66180
+ }
66181
+
66182
+ /**
66183
+ * Get the current server context (win + appId) for tool handlers.
66184
+ * Returns null if the server is not running.
66185
+ */
66186
+ function getServerContext() {
66187
+ if (!activeWin) return null;
66188
+ return { win: activeWin, appId: resolveAppId() };
66189
+ }
66190
+
66147
66191
  // --- Controller ---
66148
- const mcpDashServerController$2 = {
66192
+ const mcpDashServerController$3 = {
66149
66193
  /**
66150
66194
  * Start the MCP Dash server.
66151
66195
  * @param {BrowserWindow} win
@@ -66163,7 +66207,7 @@ const mcpDashServerController$2 = {
66163
66207
  const serverSettings = getMcpServerSettings(win);
66164
66208
  const port = options.port || serverSettings.port || 3141;
66165
66209
  const token =
66166
- serverSettings.token || mcpDashServerController$2.getOrCreateToken(win);
66210
+ serverSettings.token || mcpDashServerController$3.getOrCreateToken(win);
66167
66211
 
66168
66212
  // Create McpServer
66169
66213
  mcpServer = new McpServer({
@@ -66257,6 +66301,7 @@ const mcpDashServerController$2 = {
66257
66301
 
66258
66302
  startTime = Date.now();
66259
66303
  connectionCount = 0;
66304
+ activeWin = win;
66260
66305
  startCleanup();
66261
66306
 
66262
66307
  // Save enabled state
@@ -66317,6 +66362,7 @@ const mcpDashServerController$2 = {
66317
66362
  transport = null;
66318
66363
  startTime = null;
66319
66364
  connectionCount = 0;
66365
+ activeWin = null;
66320
66366
 
66321
66367
  // Update settings
66322
66368
  if (win) {
@@ -66339,8 +66385,8 @@ const mcpDashServerController$2 = {
66339
66385
  * Restart the server (stop + start).
66340
66386
  */
66341
66387
  restartServer: async (win, options = {}) => {
66342
- await mcpDashServerController$2.stopServer(win);
66343
- return mcpDashServerController$2.startServer(win, options);
66388
+ await mcpDashServerController$3.stopServer(win);
66389
+ return mcpDashServerController$3.startServer(win, options);
66344
66390
  },
66345
66391
 
66346
66392
  /**
@@ -66380,7 +66426,7 @@ const mcpDashServerController$2 = {
66380
66426
  const serverSettings = getMcpServerSettings(win);
66381
66427
  if (serverSettings.enabled) {
66382
66428
  console.log("[mcpDashServer] Auto-starting server...");
66383
- return mcpDashServerController$2.startServer(win, {
66429
+ return mcpDashServerController$3.startServer(win, {
66384
66430
  port: serverSettings.port,
66385
66431
  });
66386
66432
  }
@@ -66388,11 +66434,12 @@ const mcpDashServerController$2 = {
66388
66434
  },
66389
66435
 
66390
66436
  // Expose registration functions for other controllers
66391
- registerTool,
66437
+ registerTool: registerTool$2,
66392
66438
  registerResource,
66439
+ getServerContext,
66393
66440
  };
66394
66441
 
66395
- var mcpDashServerController_1 = mcpDashServerController$2;
66442
+ var mcpDashServerController_1 = mcpDashServerController$3;
66396
66443
 
66397
66444
  /**
66398
66445
  * clientFactories.js
@@ -66825,7 +66872,7 @@ const {
66825
66872
  matchTailwindFamily,
66826
66873
  generateThemeFromPalette,
66827
66874
  } = paletteToThemeMapper_1;
66828
- const mcpDashServerController$1 = mcpDashServerController_1;
66875
+ const mcpDashServerController$2 = mcpDashServerController_1;
66829
66876
 
66830
66877
  var controller = {
66831
66878
  showDialog,
@@ -66908,7 +66955,7 @@ var controller = {
66908
66955
  assignRoles,
66909
66956
  matchTailwindFamily,
66910
66957
  generateThemeFromPalette,
66911
- mcpDashServerController: mcpDashServerController$1,
66958
+ mcpDashServerController: mcpDashServerController$2,
66912
66959
  };
66913
66960
 
66914
66961
  const { ipcRenderer: ipcRenderer$q } = require$$0$2;
@@ -68921,6 +68968,1118 @@ const mcpDashServerApi$2 = {
68921
68968
 
68922
68969
  var mcpDashServerApi_1 = mcpDashServerApi$2;
68923
68970
 
68971
+ /**
68972
+ * toolDefinitions.js
68973
+ *
68974
+ * MCP tool schemas for dashboard/workspace operations and app stats.
68975
+ * Each definition includes name, description, and JSON Schema inputSchema.
68976
+ */
68977
+
68978
+ const dashboardTools$1 = [
68979
+ {
68980
+ name: "list_dashboards",
68981
+ description: "List all dashboards with their IDs, names, and widget counts",
68982
+ inputSchema: {
68983
+ type: "object",
68984
+ properties: {},
68985
+ required: [],
68986
+ },
68987
+ },
68988
+ {
68989
+ name: "get_dashboard",
68990
+ description:
68991
+ "Get full details of a dashboard including layout and widgets. Omit dashboardId to get the active dashboard.",
68992
+ inputSchema: {
68993
+ type: "object",
68994
+ properties: {
68995
+ dashboardId: {
68996
+ type: "string",
68997
+ description:
68998
+ "Dashboard ID. Omit to get the currently active dashboard.",
68999
+ },
69000
+ },
69001
+ required: [],
69002
+ },
69003
+ },
69004
+ {
69005
+ name: "create_dashboard",
69006
+ description: "Create a new dashboard with the given name",
69007
+ inputSchema: {
69008
+ type: "object",
69009
+ properties: {
69010
+ name: {
69011
+ type: "string",
69012
+ description: "Display name for the new dashboard",
69013
+ },
69014
+ },
69015
+ required: ["name"],
69016
+ },
69017
+ },
69018
+ {
69019
+ name: "delete_dashboard",
69020
+ description:
69021
+ "Delete a dashboard by ID. Cannot delete the last remaining dashboard.",
69022
+ inputSchema: {
69023
+ type: "object",
69024
+ properties: {
69025
+ dashboardId: {
69026
+ type: "string",
69027
+ description: "ID of the dashboard to delete",
69028
+ },
69029
+ },
69030
+ required: ["dashboardId"],
69031
+ },
69032
+ },
69033
+ {
69034
+ name: "get_app_stats",
69035
+ description:
69036
+ "Get application statistics: counts of dashboards, widgets, themes, and providers",
69037
+ inputSchema: {
69038
+ type: "object",
69039
+ properties: {},
69040
+ required: [],
69041
+ },
69042
+ },
69043
+ ];
69044
+
69045
+ const widgetTools$1 = [
69046
+ {
69047
+ name: "add_widget",
69048
+ description:
69049
+ "Add a widget to a dashboard by component name. Use list_widgets or search_widgets to find available widget names.",
69050
+ inputSchema: {
69051
+ type: "object",
69052
+ properties: {
69053
+ dashboardId: {
69054
+ type: "string",
69055
+ description:
69056
+ "Dashboard ID to add the widget to. Omit to use the active dashboard.",
69057
+ },
69058
+ widgetName: {
69059
+ type: "string",
69060
+ description:
69061
+ "Component name of the widget to add (e.g. 'Clock', 'WeatherWidget')",
69062
+ },
69063
+ },
69064
+ required: ["widgetName"],
69065
+ },
69066
+ },
69067
+ {
69068
+ name: "remove_widget",
69069
+ description: "Remove a widget instance from a dashboard by its ID",
69070
+ inputSchema: {
69071
+ type: "object",
69072
+ properties: {
69073
+ dashboardId: {
69074
+ type: "string",
69075
+ description: "Dashboard ID. Omit to use the active dashboard.",
69076
+ },
69077
+ widgetId: {
69078
+ type: "string",
69079
+ description: "ID of the widget instance to remove",
69080
+ },
69081
+ },
69082
+ required: ["widgetId"],
69083
+ },
69084
+ },
69085
+ {
69086
+ name: "configure_widget",
69087
+ description:
69088
+ "Update a widget's configuration. The config object is merged into the existing config.",
69089
+ inputSchema: {
69090
+ type: "object",
69091
+ properties: {
69092
+ dashboardId: {
69093
+ type: "string",
69094
+ description: "Dashboard ID. Omit to use the active dashboard.",
69095
+ },
69096
+ widgetId: {
69097
+ type: "string",
69098
+ description: "ID of the widget instance to configure",
69099
+ },
69100
+ config: {
69101
+ type: "object",
69102
+ description:
69103
+ "Configuration object to merge into existing widget config",
69104
+ },
69105
+ },
69106
+ required: ["widgetId", "config"],
69107
+ },
69108
+ },
69109
+ {
69110
+ name: "list_widgets",
69111
+ description:
69112
+ "List available widgets from the registry, including name, description, and provider info",
69113
+ inputSchema: {
69114
+ type: "object",
69115
+ properties: {},
69116
+ required: [],
69117
+ },
69118
+ },
69119
+ {
69120
+ name: "search_widgets",
69121
+ description:
69122
+ "Search the widget registry by keyword. Returns matching widgets with name, description, and provider info.",
69123
+ inputSchema: {
69124
+ type: "object",
69125
+ properties: {
69126
+ query: {
69127
+ type: "string",
69128
+ description:
69129
+ "Search keyword to match against widget names, descriptions, and tags",
69130
+ },
69131
+ },
69132
+ required: ["query"],
69133
+ },
69134
+ },
69135
+ ];
69136
+
69137
+ var toolDefinitions = { dashboardTools: dashboardTools$1, widgetTools: widgetTools$1 };
69138
+
69139
+ /**
69140
+ * toolHandlers.js
69141
+ *
69142
+ * MCP tool handlers for dashboard/workspace CRUD and app statistics.
69143
+ * Each handler delegates to existing controllers via getServerContext().
69144
+ */
69145
+ const mcpDashServerController$1 = mcpDashServerController_1;
69146
+ const workspaceController$1 = workspaceController_1;
69147
+ const themeController$1 = themeController_1;
69148
+ const providerController$1 = requireProviderController();
69149
+
69150
+ /**
69151
+ * Helper: get win + appId or throw a descriptive error.
69152
+ */
69153
+ function requireContext() {
69154
+ const ctx = mcpDashServerController$1.getServerContext();
69155
+ if (!ctx) {
69156
+ throw new Error("MCP server is not running or has no active window");
69157
+ }
69158
+ return ctx;
69159
+ }
69160
+
69161
+ /**
69162
+ * Helper: count widgets in a workspace's layout array.
69163
+ * Widgets are layout items whose component is registered and is not a container.
69164
+ */
69165
+ function countWidgets(layout) {
69166
+ if (!Array.isArray(layout)) return 0;
69167
+ return layout.filter(
69168
+ (item) =>
69169
+ item.component &&
69170
+ item.component !== "Container" &&
69171
+ item.component !== "LayoutContainer" &&
69172
+ item.component !== "LayoutGridContainer",
69173
+ ).length;
69174
+ }
69175
+
69176
+ /**
69177
+ * list_dashboards — Returns all workspaces with id, name, widget count, active state.
69178
+ */
69179
+ async function handleListDashboards$1() {
69180
+ const { win, appId } = requireContext();
69181
+ const result = workspaceController$1.listWorkspacesForApplication(win, appId);
69182
+
69183
+ if (result.error) {
69184
+ return {
69185
+ content: [
69186
+ {
69187
+ type: "text",
69188
+ text: JSON.stringify({ error: result.message }),
69189
+ },
69190
+ ],
69191
+ isError: true,
69192
+ };
69193
+ }
69194
+
69195
+ const dashboards = (result.workspaces || []).map((ws, index) => ({
69196
+ id: String(ws.id),
69197
+ name: ws.name || ws.label || `Dashboard ${index + 1}`,
69198
+ widgetCount: countWidgets(ws.layout),
69199
+ isActive: index === 0,
69200
+ }));
69201
+
69202
+ return {
69203
+ content: [{ type: "text", text: JSON.stringify(dashboards, null, 2) }],
69204
+ };
69205
+ }
69206
+
69207
+ /**
69208
+ * get_dashboard — Returns full details for a dashboard by ID (or the active one).
69209
+ */
69210
+ async function handleGetDashboard$1({ dashboardId }) {
69211
+ const { win, appId } = requireContext();
69212
+ const result = workspaceController$1.listWorkspacesForApplication(win, appId);
69213
+
69214
+ if (result.error) {
69215
+ return {
69216
+ content: [
69217
+ {
69218
+ type: "text",
69219
+ text: JSON.stringify({ error: result.message }),
69220
+ },
69221
+ ],
69222
+ isError: true,
69223
+ };
69224
+ }
69225
+
69226
+ const workspaces = result.workspaces || [];
69227
+ let workspace;
69228
+
69229
+ if (dashboardId) {
69230
+ workspace = workspaces.find((ws) => String(ws.id) === dashboardId);
69231
+ if (!workspace) {
69232
+ return {
69233
+ content: [
69234
+ {
69235
+ type: "text",
69236
+ text: JSON.stringify({
69237
+ error: `Dashboard not found: ${dashboardId}`,
69238
+ }),
69239
+ },
69240
+ ],
69241
+ isError: true,
69242
+ };
69243
+ }
69244
+ } else {
69245
+ // Return first workspace as the "active" one
69246
+ workspace = workspaces[0];
69247
+ if (!workspace) {
69248
+ return {
69249
+ content: [
69250
+ {
69251
+ type: "text",
69252
+ text: JSON.stringify({
69253
+ error: "No dashboards exist",
69254
+ }),
69255
+ },
69256
+ ],
69257
+ isError: true,
69258
+ };
69259
+ }
69260
+ }
69261
+
69262
+ const widgets = (workspace.layout || [])
69263
+ .filter(
69264
+ (item) =>
69265
+ item.component &&
69266
+ item.component !== "Container" &&
69267
+ item.component !== "LayoutContainer" &&
69268
+ item.component !== "LayoutGridContainer",
69269
+ )
69270
+ .map((item) => ({
69271
+ id: String(item.id),
69272
+ type: item.component,
69273
+ config: item.config || {},
69274
+ }));
69275
+
69276
+ const detail = {
69277
+ id: String(workspace.id),
69278
+ name: workspace.name || workspace.label || "Dashboard",
69279
+ layout: workspace.layout || [],
69280
+ widgets,
69281
+ theme: workspace.theme || null,
69282
+ };
69283
+
69284
+ return {
69285
+ content: [{ type: "text", text: JSON.stringify(detail, null, 2) }],
69286
+ };
69287
+ }
69288
+
69289
+ /**
69290
+ * create_dashboard — Creates a new workspace with the given name.
69291
+ */
69292
+ async function handleCreateDashboard$1({ name }) {
69293
+ if (!name || typeof name !== "string" || !name.trim()) {
69294
+ return {
69295
+ content: [
69296
+ {
69297
+ type: "text",
69298
+ text: JSON.stringify({
69299
+ error: "name is required and must be a non-empty string",
69300
+ }),
69301
+ },
69302
+ ],
69303
+ isError: true,
69304
+ };
69305
+ }
69306
+
69307
+ const { win, appId } = requireContext();
69308
+
69309
+ const newWorkspace = {
69310
+ id: Date.now(),
69311
+ name: name.trim(),
69312
+ label: name.trim(),
69313
+ type: "workspace",
69314
+ version: 1,
69315
+ menuId: 1,
69316
+ layout: [
69317
+ {
69318
+ id: 1,
69319
+ order: 1,
69320
+ component: "Container",
69321
+ parentId: 0,
69322
+ items: [],
69323
+ },
69324
+ ],
69325
+ };
69326
+
69327
+ const result = workspaceController$1.saveWorkspaceForApplication(
69328
+ win,
69329
+ appId,
69330
+ newWorkspace,
69331
+ );
69332
+
69333
+ if (result.error) {
69334
+ return {
69335
+ content: [
69336
+ {
69337
+ type: "text",
69338
+ text: JSON.stringify({ error: result.message }),
69339
+ },
69340
+ ],
69341
+ isError: true,
69342
+ };
69343
+ }
69344
+
69345
+ return {
69346
+ content: [
69347
+ {
69348
+ type: "text",
69349
+ text: JSON.stringify(
69350
+ { id: String(newWorkspace.id), name: newWorkspace.name },
69351
+ null,
69352
+ 2,
69353
+ ),
69354
+ },
69355
+ ],
69356
+ };
69357
+ }
69358
+
69359
+ /**
69360
+ * delete_dashboard — Deletes a workspace by ID. Rejects if it's the last one.
69361
+ */
69362
+ async function handleDeleteDashboard$1({ dashboardId }) {
69363
+ if (!dashboardId || typeof dashboardId !== "string") {
69364
+ return {
69365
+ content: [
69366
+ {
69367
+ type: "text",
69368
+ text: JSON.stringify({
69369
+ error: "dashboardId is required",
69370
+ }),
69371
+ },
69372
+ ],
69373
+ isError: true,
69374
+ };
69375
+ }
69376
+
69377
+ const { win, appId } = requireContext();
69378
+
69379
+ // Check how many dashboards exist
69380
+ const listResult = workspaceController$1.listWorkspacesForApplication(
69381
+ win,
69382
+ appId,
69383
+ );
69384
+ const workspaces = listResult.workspaces || [];
69385
+
69386
+ if (workspaces.length <= 1) {
69387
+ return {
69388
+ content: [
69389
+ {
69390
+ type: "text",
69391
+ text: JSON.stringify({
69392
+ error: "Cannot delete the last remaining dashboard",
69393
+ }),
69394
+ },
69395
+ ],
69396
+ isError: true,
69397
+ };
69398
+ }
69399
+
69400
+ // Verify the dashboard exists
69401
+ const exists = workspaces.some((ws) => String(ws.id) === dashboardId);
69402
+ if (!exists) {
69403
+ return {
69404
+ content: [
69405
+ {
69406
+ type: "text",
69407
+ text: JSON.stringify({
69408
+ error: `Dashboard not found: ${dashboardId}`,
69409
+ }),
69410
+ },
69411
+ ],
69412
+ isError: true,
69413
+ };
69414
+ }
69415
+
69416
+ // Use numeric ID if stored as number
69417
+ const targetWs = workspaces.find((ws) => String(ws.id) === dashboardId);
69418
+ const result = workspaceController$1.deleteWorkspaceForApplication(
69419
+ win,
69420
+ appId,
69421
+ targetWs.id,
69422
+ );
69423
+
69424
+ if (result.error) {
69425
+ return {
69426
+ content: [
69427
+ {
69428
+ type: "text",
69429
+ text: JSON.stringify({ error: result.message }),
69430
+ },
69431
+ ],
69432
+ isError: true,
69433
+ };
69434
+ }
69435
+
69436
+ return {
69437
+ content: [
69438
+ {
69439
+ type: "text",
69440
+ text: JSON.stringify({
69441
+ success: true,
69442
+ deleted: dashboardId,
69443
+ remaining: (result.workspaces || []).length,
69444
+ }),
69445
+ },
69446
+ ],
69447
+ };
69448
+ }
69449
+
69450
+ /**
69451
+ * get_app_stats — Returns counts of dashboards, widgets, themes, and providers.
69452
+ */
69453
+ async function handleGetAppStats$1() {
69454
+ const { win, appId } = requireContext();
69455
+
69456
+ // Dashboards + widget count
69457
+ const wsResult = workspaceController$1.listWorkspacesForApplication(win, appId);
69458
+ const workspaces = wsResult.workspaces || [];
69459
+ const dashboardCount = workspaces.length;
69460
+ const widgetCount = workspaces.reduce(
69461
+ (sum, ws) => sum + countWidgets(ws.layout),
69462
+ 0,
69463
+ );
69464
+
69465
+ // Themes
69466
+ const themeResult = themeController$1.listThemesForApplication(win, appId);
69467
+ const themes = themeResult.themes || {};
69468
+ const themeCount = Object.keys(themes).length;
69469
+
69470
+ // Providers
69471
+ const providerResult = providerController$1.listProviders(win, appId);
69472
+ const providers = providerResult.providers || {};
69473
+ const providerCount = Object.keys(providers).length;
69474
+
69475
+ const stats = {
69476
+ dashboardCount,
69477
+ widgetCount,
69478
+ themeCount,
69479
+ providerCount,
69480
+ };
69481
+
69482
+ return {
69483
+ content: [{ type: "text", text: JSON.stringify(stats, null, 2) }],
69484
+ };
69485
+ }
69486
+
69487
+ // --- Widget Tool Handlers ---
69488
+
69489
+ const registryController$1 = registryController$3;
69490
+
69491
+ /**
69492
+ * Helper: find a workspace by ID or return the first (active) one.
69493
+ */
69494
+ function findWorkspace(workspaces, dashboardId) {
69495
+ if (dashboardId) {
69496
+ const ws = workspaces.find((w) => String(w.id) === dashboardId);
69497
+ if (!ws) {
69498
+ return {
69499
+ error: true,
69500
+ response: {
69501
+ content: [
69502
+ {
69503
+ type: "text",
69504
+ text: JSON.stringify({
69505
+ error: `Dashboard not found: ${dashboardId}`,
69506
+ }),
69507
+ },
69508
+ ],
69509
+ isError: true,
69510
+ },
69511
+ };
69512
+ }
69513
+ return { workspace: ws };
69514
+ }
69515
+ if (!workspaces.length) {
69516
+ return {
69517
+ error: true,
69518
+ response: {
69519
+ content: [
69520
+ {
69521
+ type: "text",
69522
+ text: JSON.stringify({ error: "No dashboards exist" }),
69523
+ },
69524
+ ],
69525
+ isError: true,
69526
+ },
69527
+ };
69528
+ }
69529
+ return { workspace: workspaces[0] };
69530
+ }
69531
+
69532
+ /**
69533
+ * Helper: generate the next unique layout item ID within a workspace.
69534
+ */
69535
+ function nextLayoutId(layout) {
69536
+ if (!Array.isArray(layout) || layout.length === 0) return 1;
69537
+ const maxId = layout.reduce(
69538
+ (max, item) => Math.max(max, Number(item.id) || 0),
69539
+ 0,
69540
+ );
69541
+ return maxId + 1;
69542
+ }
69543
+
69544
+ /**
69545
+ * add_widget — Add a widget to a dashboard by component name.
69546
+ */
69547
+ async function handleAddWidget$1({ dashboardId, widgetName }) {
69548
+ if (!widgetName || typeof widgetName !== "string" || !widgetName.trim()) {
69549
+ return {
69550
+ content: [
69551
+ {
69552
+ type: "text",
69553
+ text: JSON.stringify({
69554
+ error: "widgetName is required and must be a non-empty string",
69555
+ }),
69556
+ },
69557
+ ],
69558
+ isError: true,
69559
+ };
69560
+ }
69561
+
69562
+ const { win, appId } = requireContext();
69563
+ const result = workspaceController$1.listWorkspacesForApplication(win, appId);
69564
+ if (result.error) {
69565
+ return {
69566
+ content: [
69567
+ { type: "text", text: JSON.stringify({ error: result.message }) },
69568
+ ],
69569
+ isError: true,
69570
+ };
69571
+ }
69572
+
69573
+ const found = findWorkspace(result.workspaces || [], dashboardId);
69574
+ if (found.error) return found.response;
69575
+
69576
+ const workspace = found.workspace;
69577
+ const layout = workspace.layout || [];
69578
+
69579
+ // Find the first container to add the widget into
69580
+ const container = layout.find(
69581
+ (item) =>
69582
+ item.component === "Container" ||
69583
+ item.component === "LayoutContainer" ||
69584
+ item.component === "LayoutGridContainer",
69585
+ );
69586
+ const parentId = container ? container.id : 0;
69587
+
69588
+ const newId = nextLayoutId(layout);
69589
+ const maxOrder = layout.reduce(
69590
+ (max, item) => Math.max(max, Number(item.order) || 0),
69591
+ 0,
69592
+ );
69593
+
69594
+ const newItem = {
69595
+ id: newId,
69596
+ order: maxOrder + 1,
69597
+ component: widgetName.trim(),
69598
+ parentId,
69599
+ config: {},
69600
+ };
69601
+
69602
+ workspace.layout = [...layout, newItem];
69603
+
69604
+ const saveResult = workspaceController$1.saveWorkspaceForApplication(
69605
+ win,
69606
+ appId,
69607
+ workspace,
69608
+ );
69609
+ if (saveResult.error) {
69610
+ return {
69611
+ content: [
69612
+ {
69613
+ type: "text",
69614
+ text: JSON.stringify({ error: saveResult.message }),
69615
+ },
69616
+ ],
69617
+ isError: true,
69618
+ };
69619
+ }
69620
+
69621
+ return {
69622
+ content: [
69623
+ {
69624
+ type: "text",
69625
+ text: JSON.stringify(
69626
+ {
69627
+ widgetId: String(newId),
69628
+ name: widgetName.trim(),
69629
+ dashboardId: String(workspace.id),
69630
+ },
69631
+ null,
69632
+ 2,
69633
+ ),
69634
+ },
69635
+ ],
69636
+ };
69637
+ }
69638
+
69639
+ /**
69640
+ * remove_widget — Remove a widget instance from a dashboard.
69641
+ */
69642
+ async function handleRemoveWidget$1({ dashboardId, widgetId }) {
69643
+ if (!widgetId || typeof widgetId !== "string") {
69644
+ return {
69645
+ content: [
69646
+ {
69647
+ type: "text",
69648
+ text: JSON.stringify({ error: "widgetId is required" }),
69649
+ },
69650
+ ],
69651
+ isError: true,
69652
+ };
69653
+ }
69654
+
69655
+ const { win, appId } = requireContext();
69656
+ const result = workspaceController$1.listWorkspacesForApplication(win, appId);
69657
+ if (result.error) {
69658
+ return {
69659
+ content: [
69660
+ { type: "text", text: JSON.stringify({ error: result.message }) },
69661
+ ],
69662
+ isError: true,
69663
+ };
69664
+ }
69665
+
69666
+ const found = findWorkspace(result.workspaces || [], dashboardId);
69667
+ if (found.error) return found.response;
69668
+
69669
+ const workspace = found.workspace;
69670
+ const layout = workspace.layout || [];
69671
+
69672
+ const exists = layout.some((item) => String(item.id) === widgetId);
69673
+ if (!exists) {
69674
+ return {
69675
+ content: [
69676
+ {
69677
+ type: "text",
69678
+ text: JSON.stringify({
69679
+ error: `Widget not found: ${widgetId}`,
69680
+ }),
69681
+ },
69682
+ ],
69683
+ isError: true,
69684
+ };
69685
+ }
69686
+
69687
+ workspace.layout = layout.filter((item) => String(item.id) !== widgetId);
69688
+
69689
+ const saveResult = workspaceController$1.saveWorkspaceForApplication(
69690
+ win,
69691
+ appId,
69692
+ workspace,
69693
+ );
69694
+ if (saveResult.error) {
69695
+ return {
69696
+ content: [
69697
+ {
69698
+ type: "text",
69699
+ text: JSON.stringify({ error: saveResult.message }),
69700
+ },
69701
+ ],
69702
+ isError: true,
69703
+ };
69704
+ }
69705
+
69706
+ return {
69707
+ content: [
69708
+ {
69709
+ type: "text",
69710
+ text: JSON.stringify({
69711
+ success: true,
69712
+ removed: widgetId,
69713
+ remainingWidgets: countWidgets(workspace.layout),
69714
+ }),
69715
+ },
69716
+ ],
69717
+ };
69718
+ }
69719
+
69720
+ /**
69721
+ * configure_widget — Update widget settings (partial merge).
69722
+ */
69723
+ async function handleConfigureWidget$1({ dashboardId, widgetId, config }) {
69724
+ if (!widgetId || typeof widgetId !== "string") {
69725
+ return {
69726
+ content: [
69727
+ {
69728
+ type: "text",
69729
+ text: JSON.stringify({ error: "widgetId is required" }),
69730
+ },
69731
+ ],
69732
+ isError: true,
69733
+ };
69734
+ }
69735
+
69736
+ if (!config || typeof config !== "object" || Array.isArray(config)) {
69737
+ return {
69738
+ content: [
69739
+ {
69740
+ type: "text",
69741
+ text: JSON.stringify({
69742
+ error: "config is required and must be an object",
69743
+ }),
69744
+ },
69745
+ ],
69746
+ isError: true,
69747
+ };
69748
+ }
69749
+
69750
+ const { win, appId } = requireContext();
69751
+ const result = workspaceController$1.listWorkspacesForApplication(win, appId);
69752
+ if (result.error) {
69753
+ return {
69754
+ content: [
69755
+ { type: "text", text: JSON.stringify({ error: result.message }) },
69756
+ ],
69757
+ isError: true,
69758
+ };
69759
+ }
69760
+
69761
+ const found = findWorkspace(result.workspaces || [], dashboardId);
69762
+ if (found.error) return found.response;
69763
+
69764
+ const workspace = found.workspace;
69765
+ const layout = workspace.layout || [];
69766
+ const item = layout.find((i) => String(i.id) === widgetId);
69767
+
69768
+ if (!item) {
69769
+ return {
69770
+ content: [
69771
+ {
69772
+ type: "text",
69773
+ text: JSON.stringify({
69774
+ error: `Widget not found: ${widgetId}`,
69775
+ }),
69776
+ },
69777
+ ],
69778
+ isError: true,
69779
+ };
69780
+ }
69781
+
69782
+ // Merge config
69783
+ item.config = { ...(item.config || {}), ...config };
69784
+
69785
+ const saveResult = workspaceController$1.saveWorkspaceForApplication(
69786
+ win,
69787
+ appId,
69788
+ workspace,
69789
+ );
69790
+ if (saveResult.error) {
69791
+ return {
69792
+ content: [
69793
+ {
69794
+ type: "text",
69795
+ text: JSON.stringify({ error: saveResult.message }),
69796
+ },
69797
+ ],
69798
+ isError: true,
69799
+ };
69800
+ }
69801
+
69802
+ return {
69803
+ content: [
69804
+ {
69805
+ type: "text",
69806
+ text: JSON.stringify(
69807
+ {
69808
+ widgetId,
69809
+ component: item.component,
69810
+ config: item.config,
69811
+ },
69812
+ null,
69813
+ 2,
69814
+ ),
69815
+ },
69816
+ ],
69817
+ };
69818
+ }
69819
+
69820
+ /**
69821
+ * list_widgets — List available widgets from the registry.
69822
+ */
69823
+ async function handleListWidgets$1() {
69824
+ try {
69825
+ const index = await registryController$1.fetchRegistryIndex();
69826
+ const packages = index.packages || [];
69827
+
69828
+ const widgets = [];
69829
+ for (const pkg of packages) {
69830
+ // Skip non-widget packages
69831
+ if (pkg.type && pkg.type !== "widget") continue;
69832
+
69833
+ for (const w of pkg.widgets || []) {
69834
+ widgets.push({
69835
+ name: w.name || pkg.name,
69836
+ displayName: w.displayName || w.name || pkg.displayName || pkg.name,
69837
+ description: w.description || pkg.description || "",
69838
+ icon: w.icon || pkg.icon || null,
69839
+ package: pkg.name,
69840
+ providers: (w.providers || pkg.providers || []).map((p) => ({
69841
+ type: p.type,
69842
+ providerClass: p.providerClass || "api",
69843
+ required: p.required !== false,
69844
+ })),
69845
+ });
69846
+ }
69847
+
69848
+ // If a package has no widgets array, treat the package itself as a widget
69849
+ if (!pkg.widgets || pkg.widgets.length === 0) {
69850
+ widgets.push({
69851
+ name: pkg.name,
69852
+ displayName: pkg.displayName || pkg.name,
69853
+ description: pkg.description || "",
69854
+ icon: pkg.icon || null,
69855
+ package: pkg.name,
69856
+ providers: (pkg.providers || []).map((p) => ({
69857
+ type: p.type,
69858
+ providerClass: p.providerClass || "api",
69859
+ required: p.required !== false,
69860
+ })),
69861
+ });
69862
+ }
69863
+ }
69864
+
69865
+ return {
69866
+ content: [
69867
+ {
69868
+ type: "text",
69869
+ text: JSON.stringify({ widgets, count: widgets.length }, null, 2),
69870
+ },
69871
+ ],
69872
+ };
69873
+ } catch (err) {
69874
+ return {
69875
+ content: [
69876
+ {
69877
+ type: "text",
69878
+ text: JSON.stringify({
69879
+ error: `Failed to fetch widget registry: ${err.message}`,
69880
+ }),
69881
+ },
69882
+ ],
69883
+ isError: true,
69884
+ };
69885
+ }
69886
+ }
69887
+
69888
+ /**
69889
+ * search_widgets — Search the registry by keyword.
69890
+ */
69891
+ async function handleSearchWidgets$1({ query }) {
69892
+ if (!query || typeof query !== "string" || !query.trim()) {
69893
+ return {
69894
+ content: [
69895
+ {
69896
+ type: "text",
69897
+ text: JSON.stringify({
69898
+ error: "query is required and must be a non-empty string",
69899
+ }),
69900
+ },
69901
+ ],
69902
+ isError: true,
69903
+ };
69904
+ }
69905
+
69906
+ try {
69907
+ const result = await registryController$1.searchRegistry(query.trim());
69908
+ const packages = result.packages || [];
69909
+
69910
+ const widgets = [];
69911
+ for (const pkg of packages) {
69912
+ if (pkg.type && pkg.type !== "widget") continue;
69913
+
69914
+ for (const w of pkg.widgets || []) {
69915
+ widgets.push({
69916
+ name: w.name || pkg.name,
69917
+ displayName: w.displayName || w.name || pkg.displayName || pkg.name,
69918
+ description: w.description || pkg.description || "",
69919
+ icon: w.icon || pkg.icon || null,
69920
+ package: pkg.name,
69921
+ providers: (w.providers || pkg.providers || []).map((p) => ({
69922
+ type: p.type,
69923
+ providerClass: p.providerClass || "api",
69924
+ required: p.required !== false,
69925
+ })),
69926
+ });
69927
+ }
69928
+
69929
+ if (!pkg.widgets || pkg.widgets.length === 0) {
69930
+ widgets.push({
69931
+ name: pkg.name,
69932
+ displayName: pkg.displayName || pkg.name,
69933
+ description: pkg.description || "",
69934
+ icon: pkg.icon || null,
69935
+ package: pkg.name,
69936
+ providers: (pkg.providers || []).map((p) => ({
69937
+ type: p.type,
69938
+ providerClass: p.providerClass || "api",
69939
+ required: p.required !== false,
69940
+ })),
69941
+ });
69942
+ }
69943
+ }
69944
+
69945
+ return {
69946
+ content: [
69947
+ {
69948
+ type: "text",
69949
+ text: JSON.stringify(
69950
+ { query: query.trim(), widgets, count: widgets.length },
69951
+ null,
69952
+ 2,
69953
+ ),
69954
+ },
69955
+ ],
69956
+ };
69957
+ } catch (err) {
69958
+ return {
69959
+ content: [
69960
+ {
69961
+ type: "text",
69962
+ text: JSON.stringify({
69963
+ error: `Failed to search widget registry: ${err.message}`,
69964
+ }),
69965
+ },
69966
+ ],
69967
+ isError: true,
69968
+ };
69969
+ }
69970
+ }
69971
+
69972
+ var toolHandlers = {
69973
+ handleListDashboards: handleListDashboards$1,
69974
+ handleGetDashboard: handleGetDashboard$1,
69975
+ handleCreateDashboard: handleCreateDashboard$1,
69976
+ handleDeleteDashboard: handleDeleteDashboard$1,
69977
+ handleGetAppStats: handleGetAppStats$1,
69978
+ handleAddWidget: handleAddWidget$1,
69979
+ handleRemoveWidget: handleRemoveWidget$1,
69980
+ handleConfigureWidget: handleConfigureWidget$1,
69981
+ handleListWidgets: handleListWidgets$1,
69982
+ handleSearchWidgets: handleSearchWidgets$1,
69983
+ };
69984
+
69985
+ /**
69986
+ * dashboardTools.js
69987
+ *
69988
+ * Registers dashboard/workspace MCP tools with the MCP Dash server.
69989
+ * Call registerDashboardTools() during app startup (before or after server start).
69990
+ */
69991
+
69992
+ const { registerTool: registerTool$1 } = mcpDashServerController_1;
69993
+ const { dashboardTools } = toolDefinitions;
69994
+ const {
69995
+ handleListDashboards,
69996
+ handleGetDashboard,
69997
+ handleCreateDashboard,
69998
+ handleDeleteDashboard,
69999
+ handleGetAppStats,
70000
+ } = toolHandlers;
70001
+
70002
+ // Map tool names to handler functions
70003
+ const handlerMap$1 = {
70004
+ list_dashboards: handleListDashboards,
70005
+ get_dashboard: handleGetDashboard,
70006
+ create_dashboard: handleCreateDashboard,
70007
+ delete_dashboard: handleDeleteDashboard,
70008
+ get_app_stats: handleGetAppStats,
70009
+ };
70010
+
70011
+ /**
70012
+ * Register all dashboard tools with the MCP server controller.
70013
+ */
70014
+ function registerDashboardTools$1() {
70015
+ for (const tool of dashboardTools) {
70016
+ const handler = handlerMap$1[tool.name];
70017
+ if (!handler) {
70018
+ console.warn(`[dashboardTools] No handler found for tool: ${tool.name}`);
70019
+ continue;
70020
+ }
70021
+ registerTool$1({
70022
+ name: tool.name,
70023
+ description: tool.description,
70024
+ inputSchema: tool.inputSchema,
70025
+ handler,
70026
+ });
70027
+ }
70028
+ console.log(
70029
+ `[dashboardTools] Registered ${dashboardTools.length} dashboard tools`,
70030
+ );
70031
+ }
70032
+
70033
+ var dashboardTools_1 = { registerDashboardTools: registerDashboardTools$1 };
70034
+
70035
+ /**
70036
+ * widgetTools.js
70037
+ *
70038
+ * Registers widget MCP tools with the MCP Dash server.
70039
+ * Call registerWidgetTools() during app startup (before or after server start).
70040
+ */
70041
+
70042
+ const { registerTool } = mcpDashServerController_1;
70043
+ const { widgetTools } = toolDefinitions;
70044
+ const {
70045
+ handleAddWidget,
70046
+ handleRemoveWidget,
70047
+ handleConfigureWidget,
70048
+ handleListWidgets,
70049
+ handleSearchWidgets,
70050
+ } = toolHandlers;
70051
+
70052
+ // Map tool names to handler functions
70053
+ const handlerMap = {
70054
+ add_widget: handleAddWidget,
70055
+ remove_widget: handleRemoveWidget,
70056
+ configure_widget: handleConfigureWidget,
70057
+ list_widgets: handleListWidgets,
70058
+ search_widgets: handleSearchWidgets,
70059
+ };
70060
+
70061
+ /**
70062
+ * Register all widget tools with the MCP server controller.
70063
+ */
70064
+ function registerWidgetTools$1() {
70065
+ for (const tool of widgetTools) {
70066
+ const handler = handlerMap[tool.name];
70067
+ if (!handler) {
70068
+ console.warn(`[widgetTools] No handler found for tool: ${tool.name}`);
70069
+ continue;
70070
+ }
70071
+ registerTool({
70072
+ name: tool.name,
70073
+ description: tool.description,
70074
+ inputSchema: tool.inputSchema,
70075
+ handler,
70076
+ });
70077
+ }
70078
+ console.log(`[widgetTools] Registered ${widgetTools.length} widget tools`);
70079
+ }
70080
+
70081
+ var widgetTools_1 = { registerWidgetTools: registerWidgetTools$1 };
70082
+
68924
70083
  /**
68925
70084
  * dashboardRatingsApi.js
68926
70085
  *
@@ -69177,7 +70336,7 @@ const settingsController = settingsController_1;
69177
70336
  const providerController = requireProviderController();
69178
70337
  const layoutController = layoutController_1;
69179
70338
  const mcpController = mcpControllerExports;
69180
- const registryController = registryController$2;
70339
+ const registryController = registryController$3;
69181
70340
  const algoliaController = algoliaController_1;
69182
70341
  const openaiController = openaiController_1;
69183
70342
  const menuItemsController = menuItemsController_1;
@@ -69241,6 +70400,12 @@ const widgetRegistry = widgetRegistryExports;
69241
70400
  const widgetCompiler = widgetCompiler$1;
69242
70401
  const dynamicWidgetLoader = dynamicWidgetLoaderExports;
69243
70402
 
70403
+ // --- MCP Dash Server Tools ---
70404
+ const { registerDashboardTools } = dashboardTools_1;
70405
+ const { registerWidgetTools } = widgetTools_1;
70406
+ registerDashboardTools();
70407
+ registerWidgetTools();
70408
+
69244
70409
  // --- Schema ---
69245
70410
  const dashboardConfigValidator = dashboardConfigValidator$1;
69246
70411
  const dashboardConfigUtils = dashboardConfigUtils$1;
@@ -69332,6 +70497,10 @@ var electron = {
69332
70497
 
69333
70498
  // Setup helpers
69334
70499
  setupCacheHandlers: clientCache.setupCacheHandlers.bind(clientCache),
70500
+
70501
+ // MCP Dash Server Tools
70502
+ registerDashboardTools,
70503
+ registerWidgetTools,
69335
70504
  };
69336
70505
 
69337
70506
  var index = /*@__PURE__*/getDefaultExportFromCjs(electron);