@trops/dash-core 0.1.171 → 0.1.173

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.
@@ -169,7 +169,7 @@ const THEME_LIST_COMPLETE = "theme-list-complete";
169
169
  const THEME_LIST_ERROR = "theme-list-error";
170
170
 
171
171
  const THEME_SAVE$1 = "theme-save";
172
- const THEME_SAVE_COMPLETE = "theme-save-complete";
172
+ const THEME_SAVE_COMPLETE$1 = "theme-save-complete";
173
173
  const THEME_SAVE_ERROR = "theme-save-error";
174
174
 
175
175
  const THEME_DELETE$1 = "theme-delete";
@@ -185,7 +185,7 @@ var themeEvents$1 = {
185
185
  THEME_LIST_COMPLETE,
186
186
  THEME_LIST_ERROR,
187
187
  THEME_SAVE: THEME_SAVE$1,
188
- THEME_SAVE_COMPLETE,
188
+ THEME_SAVE_COMPLETE: THEME_SAVE_COMPLETE$1,
189
189
  THEME_SAVE_ERROR,
190
190
  THEME_DELETE: THEME_DELETE$1,
191
191
  THEME_DELETE_COMPLETE,
@@ -304,7 +304,7 @@ const SETTINGS_GET_COMPLETE = "settings-get-complete";
304
304
  const SETTINGS_GET_ERROR = "settings-get-error";
305
305
 
306
306
  const SETTINGS_SAVE$1 = "settings-save";
307
- const SETTINGS_SAVE_COMPLETE = "settings-save-complete";
307
+ const SETTINGS_SAVE_COMPLETE$1 = "settings-save-complete";
308
308
  const SETTINGS_SAVE_ERROR = "settings-save-error";
309
309
 
310
310
  const SETTINGS_GET_DATA_DIR$1 = "settings-get-data-dir";
@@ -324,7 +324,7 @@ var settingsEvents$1 = {
324
324
  SETTINGS_GET_COMPLETE,
325
325
  SETTINGS_GET_ERROR,
326
326
  SETTINGS_SAVE: SETTINGS_SAVE$1,
327
- SETTINGS_SAVE_COMPLETE,
327
+ SETTINGS_SAVE_COMPLETE: SETTINGS_SAVE_COMPLETE$1,
328
328
  SETTINGS_SAVE_ERROR,
329
329
  SETTINGS_GET_DATA_DIR: SETTINGS_GET_DATA_DIR$1,
330
330
  SETTINGS_GET_DATA_DIR_COMPLETE,
@@ -4294,7 +4294,7 @@ function copyDirectory(source, destination) {
4294
4294
  }
4295
4295
  }
4296
4296
 
4297
- const settingsController$2 = {
4297
+ const settingsController$3 = {
4298
4298
  /**
4299
4299
  * saveSettingsForApplication
4300
4300
  * Save the settings object to a file (settings.json)
@@ -4526,7 +4526,7 @@ const settingsController$2 = {
4526
4526
  },
4527
4527
  };
4528
4528
 
4529
- var settingsController_1 = settingsController$2;
4529
+ var settingsController_1 = settingsController$3;
4530
4530
 
4531
4531
  /**
4532
4532
  * responseCache.js
@@ -26872,7 +26872,7 @@ async function searchThemes(query = "", filters = {}) {
26872
26872
  return searchRegistry$1(query, { ...filters, type: "theme" });
26873
26873
  }
26874
26874
 
26875
- var registryController$2 = {
26875
+ var registryController$3 = {
26876
26876
  fetchRegistryIndex,
26877
26877
  searchRegistry: searchRegistry$1,
26878
26878
  searchDashboards,
@@ -31852,7 +31852,7 @@ const { app: app$2, dialog: dialog$1 } = require$$0$2;
31852
31852
  const AdmZip$1 = require$$3$4;
31853
31853
 
31854
31854
  const themeController$3 = themeController_1;
31855
- const registryController$1 = registryController$2;
31855
+ const registryController$2 = registryController$3;
31856
31856
  const registryApiController$1 = registryApiController$2;
31857
31857
  const {
31858
31858
  getAuthStatus,
@@ -32082,7 +32082,7 @@ async function prepareThemeForPublish$1(win, appId, themeKey, options = {}) {
32082
32082
  async function installThemeFromRegistry$1(win, appId, packageName) {
32083
32083
  try {
32084
32084
  // Look up the package
32085
- const pkg = await registryController$1.getPackage(packageName);
32085
+ const pkg = await registryController$2.getPackage(packageName);
32086
32086
  if (!pkg) {
32087
32087
  return {
32088
32088
  success: false,
@@ -32272,7 +32272,7 @@ const {
32272
32272
  buildProviderRequirements,
32273
32273
  applyEventWiringToLayout,
32274
32274
  } = dashboardConfigUtils$1;
32275
- const { searchRegistry, getPackage } = registryController$2;
32275
+ const { searchRegistry, getPackage } = registryController$3;
32276
32276
  const themeController$2 = themeController_1;
32277
32277
 
32278
32278
  const configFilename = "workspaces.json";
@@ -32998,7 +32998,7 @@ async function checkCompatibility$1(dashboardWidgets, widgetRegistry = null) {
32998
32998
  const {
32999
32999
  checkDashboardCompatibility,
33000
33000
  } = dashboardConfigUtils$1;
33001
- const { fetchRegistryIndex } = registryController$2;
33001
+ const { fetchRegistryIndex } = registryController$3;
33002
33002
 
33003
33003
  const installedWidgets = widgetRegistry ? widgetRegistry.getWidgets() : [];
33004
33004
 
@@ -33153,7 +33153,7 @@ async function prepareDashboardForPublish$1(
33153
33153
  }
33154
33154
 
33155
33155
  // 6. Check which widgets exist in the registry (soft warning, not blocking)
33156
- const { fetchRegistryIndex } = registryController$2;
33156
+ const { fetchRegistryIndex } = registryController$3;
33157
33157
  let registryPackages = [];
33158
33158
  let registryCheckFailed = false;
33159
33159
  try {
@@ -33300,7 +33300,7 @@ async function getDashboardPreview$1(packageName, widgetRegistry = null) {
33300
33300
  buildDashboardPreview,
33301
33301
  checkDashboardCompatibility,
33302
33302
  } = dashboardConfigUtils$1;
33303
- const { getPackage, fetchRegistryIndex } = registryController$2;
33303
+ const { getPackage, fetchRegistryIndex } = registryController$3;
33304
33304
 
33305
33305
  const pkg = await getPackage(packageName);
33306
33306
  if (!pkg) {
@@ -33345,7 +33345,7 @@ async function getDashboardPreview$1(packageName, widgetRegistry = null) {
33345
33345
  */
33346
33346
  async function checkDashboardUpdatesForApp$1(appId) {
33347
33347
  const { checkDashboardUpdates } = dashboardConfigUtils$1;
33348
- const { fetchRegistryIndex } = registryController$2;
33348
+ const { fetchRegistryIndex } = registryController$3;
33349
33349
 
33350
33350
  try {
33351
33351
  const filename = path$1.join(
@@ -39626,13 +39626,13 @@ async function extractColorsFromUrl({
39626
39626
  };
39627
39627
  }
39628
39628
 
39629
- const themeFromUrlController$1 = {
39629
+ const themeFromUrlController$2 = {
39630
39630
  extractColorsFromUrl,
39631
39631
  extractFaviconUrls,
39632
39632
  extractFaviconColors,
39633
39633
  };
39634
39634
 
39635
- var themeFromUrlController_1 = themeFromUrlController$1;
39635
+ var themeFromUrlController_1 = themeFromUrlController$2;
39636
39636
 
39637
39637
  /**
39638
39638
  * themeGenerator.js
@@ -40289,13 +40289,13 @@ function generateThemeFromPalette$1(palette, overrides = {}) {
40289
40289
  };
40290
40290
  }
40291
40291
 
40292
- const paletteToThemeMapper$1 = {
40292
+ const paletteToThemeMapper$2 = {
40293
40293
  assignRoles: assignRoles$1,
40294
40294
  matchTailwindFamily: matchTailwindFamily$1,
40295
40295
  generateThemeFromPalette: generateThemeFromPalette$1,
40296
40296
  };
40297
40297
 
40298
- var paletteToThemeMapper_1 = paletteToThemeMapper$1;
40298
+ var paletteToThemeMapper_1 = paletteToThemeMapper$2;
40299
40299
 
40300
40300
  var bufferUtil$1 = {exports: {}};
40301
40301
 
@@ -46080,9 +46080,9 @@ function stats() {
46080
46080
  };
46081
46081
  }
46082
46082
 
46083
- const extractionCacheController$1 = { get, has, clear, invalidate, stats };
46083
+ const extractionCacheController$2 = { get, has, clear, invalidate, stats };
46084
46084
 
46085
- var extractionCacheController_1 = extractionCacheController$1;
46085
+ var extractionCacheController_1 = extractionCacheController$2;
46086
46086
 
46087
46087
  var mcp = {};
46088
46088
 
@@ -66056,7 +66056,7 @@ const {
66056
66056
  StreamableHTTPServerTransport,
66057
66057
  } = streamableHttp;
66058
66058
 
66059
- const settingsController$1 = settingsController_1;
66059
+ const settingsController$2 = settingsController_1;
66060
66060
 
66061
66061
  // --- State ---
66062
66062
  let mcpServer = null;
@@ -66111,7 +66111,7 @@ const registeredResources = [];
66111
66111
  * Register a tool to be exposed via the MCP server.
66112
66112
  * Call this before starting the server (or restart after registering).
66113
66113
  */
66114
- function registerTool$1(toolDef) {
66114
+ function registerTool$3(toolDef) {
66115
66115
  registeredTools.push(toolDef);
66116
66116
  }
66117
66117
 
@@ -66141,16 +66141,16 @@ function applyRegistrations(server) {
66141
66141
 
66142
66142
  // --- Settings Helpers ---
66143
66143
  function getMcpServerSettings(win) {
66144
- const result = settingsController$1.getSettingsForApplication(win);
66144
+ const result = settingsController$2.getSettingsForApplication(win);
66145
66145
  const settings = result?.settings || {};
66146
66146
  return settings.mcpDashServer || {};
66147
66147
  }
66148
66148
 
66149
66149
  function saveMcpServerSettings(win, mcpSettings) {
66150
- const result = settingsController$1.getSettingsForApplication(win);
66150
+ const result = settingsController$2.getSettingsForApplication(win);
66151
66151
  const settings = result?.settings || {};
66152
66152
  settings.mcpDashServer = mcpSettings;
66153
- settingsController$1.saveSettingsForApplication(win, settings);
66153
+ settingsController$2.saveSettingsForApplication(win, settings);
66154
66154
  }
66155
66155
 
66156
66156
  // --- App ID Resolution ---
@@ -66434,7 +66434,7 @@ const mcpDashServerController$3 = {
66434
66434
  },
66435
66435
 
66436
66436
  // Expose registration functions for other controllers
66437
- registerTool: registerTool$1,
66437
+ registerTool: registerTool$3,
66438
66438
  registerResource,
66439
66439
  getServerContext,
66440
66440
  };
@@ -69042,7 +69042,183 @@ const dashboardTools$1 = [
69042
69042
  },
69043
69043
  ];
69044
69044
 
69045
- var toolDefinitions = { dashboardTools: dashboardTools$1 };
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
+ const themeTools$1 = [
69138
+ {
69139
+ name: "list_themes",
69140
+ description:
69141
+ "List all saved themes with their names and whether they are currently active",
69142
+ inputSchema: {
69143
+ type: "object",
69144
+ properties: {},
69145
+ required: [],
69146
+ },
69147
+ },
69148
+ {
69149
+ name: "get_theme",
69150
+ description:
69151
+ "Get full details of a theme by name, including all color values",
69152
+ inputSchema: {
69153
+ type: "object",
69154
+ properties: {
69155
+ name: {
69156
+ type: "string",
69157
+ description: "Name of the theme to retrieve",
69158
+ },
69159
+ },
69160
+ required: ["name"],
69161
+ },
69162
+ },
69163
+ {
69164
+ name: "create_theme",
69165
+ description:
69166
+ "Create a new theme from a colors object. The colors object should contain color role keys (e.g. primary, secondary, surface, background) mapped to hex values or shade objects.",
69167
+ inputSchema: {
69168
+ type: "object",
69169
+ properties: {
69170
+ name: {
69171
+ type: "string",
69172
+ description: "Display name for the new theme",
69173
+ },
69174
+ colors: {
69175
+ type: "object",
69176
+ description:
69177
+ "Theme colors object with role keys mapped to hex values or shade objects",
69178
+ },
69179
+ },
69180
+ required: ["name", "colors"],
69181
+ },
69182
+ },
69183
+ {
69184
+ name: "create_theme_from_url",
69185
+ description:
69186
+ "Extract brand colors from a website URL and generate a theme. Loads the page, extracts colors from meta tags, CSS variables, computed styles, and favicons, then maps them to theme roles.",
69187
+ inputSchema: {
69188
+ type: "object",
69189
+ properties: {
69190
+ url: {
69191
+ type: "string",
69192
+ description:
69193
+ "Website URL to extract colors from (must start with http:// or https://)",
69194
+ },
69195
+ name: {
69196
+ type: "string",
69197
+ description:
69198
+ "Optional name for the theme. If omitted, a name is derived from the URL hostname.",
69199
+ },
69200
+ },
69201
+ required: ["url"],
69202
+ },
69203
+ },
69204
+ {
69205
+ name: "apply_theme",
69206
+ description:
69207
+ "Apply a saved theme to the active dashboard. The theme must already exist (use list_themes to see available themes).",
69208
+ inputSchema: {
69209
+ type: "object",
69210
+ properties: {
69211
+ name: {
69212
+ type: "string",
69213
+ description: "Name of the theme to apply",
69214
+ },
69215
+ },
69216
+ required: ["name"],
69217
+ },
69218
+ },
69219
+ ];
69220
+
69221
+ var toolDefinitions = { dashboardTools: dashboardTools$1, widgetTools: widgetTools$1, themeTools: themeTools$1 };
69046
69222
 
69047
69223
  /**
69048
69224
  * toolHandlers.js
@@ -69392,12 +69568,1008 @@ async function handleGetAppStats$1() {
69392
69568
  };
69393
69569
  }
69394
69570
 
69571
+ // --- Widget Tool Handlers ---
69572
+
69573
+ const registryController$1 = registryController$3;
69574
+
69575
+ /**
69576
+ * Helper: find a workspace by ID or return the first (active) one.
69577
+ */
69578
+ function findWorkspace(workspaces, dashboardId) {
69579
+ if (dashboardId) {
69580
+ const ws = workspaces.find((w) => String(w.id) === dashboardId);
69581
+ if (!ws) {
69582
+ return {
69583
+ error: true,
69584
+ response: {
69585
+ content: [
69586
+ {
69587
+ type: "text",
69588
+ text: JSON.stringify({
69589
+ error: `Dashboard not found: ${dashboardId}`,
69590
+ }),
69591
+ },
69592
+ ],
69593
+ isError: true,
69594
+ },
69595
+ };
69596
+ }
69597
+ return { workspace: ws };
69598
+ }
69599
+ if (!workspaces.length) {
69600
+ return {
69601
+ error: true,
69602
+ response: {
69603
+ content: [
69604
+ {
69605
+ type: "text",
69606
+ text: JSON.stringify({ error: "No dashboards exist" }),
69607
+ },
69608
+ ],
69609
+ isError: true,
69610
+ },
69611
+ };
69612
+ }
69613
+ return { workspace: workspaces[0] };
69614
+ }
69615
+
69616
+ /**
69617
+ * Helper: generate the next unique layout item ID within a workspace.
69618
+ */
69619
+ function nextLayoutId(layout) {
69620
+ if (!Array.isArray(layout) || layout.length === 0) return 1;
69621
+ const maxId = layout.reduce(
69622
+ (max, item) => Math.max(max, Number(item.id) || 0),
69623
+ 0,
69624
+ );
69625
+ return maxId + 1;
69626
+ }
69627
+
69628
+ /**
69629
+ * add_widget — Add a widget to a dashboard by component name.
69630
+ */
69631
+ async function handleAddWidget$1({ dashboardId, widgetName }) {
69632
+ if (!widgetName || typeof widgetName !== "string" || !widgetName.trim()) {
69633
+ return {
69634
+ content: [
69635
+ {
69636
+ type: "text",
69637
+ text: JSON.stringify({
69638
+ error: "widgetName is required and must be a non-empty string",
69639
+ }),
69640
+ },
69641
+ ],
69642
+ isError: true,
69643
+ };
69644
+ }
69645
+
69646
+ const { win, appId } = requireContext();
69647
+ const result = workspaceController$1.listWorkspacesForApplication(win, appId);
69648
+ if (result.error) {
69649
+ return {
69650
+ content: [
69651
+ { type: "text", text: JSON.stringify({ error: result.message }) },
69652
+ ],
69653
+ isError: true,
69654
+ };
69655
+ }
69656
+
69657
+ const found = findWorkspace(result.workspaces || [], dashboardId);
69658
+ if (found.error) return found.response;
69659
+
69660
+ const workspace = found.workspace;
69661
+ const layout = workspace.layout || [];
69662
+
69663
+ // Find the first container to add the widget into
69664
+ const container = layout.find(
69665
+ (item) =>
69666
+ item.component === "Container" ||
69667
+ item.component === "LayoutContainer" ||
69668
+ item.component === "LayoutGridContainer",
69669
+ );
69670
+ const parentId = container ? container.id : 0;
69671
+
69672
+ const newId = nextLayoutId(layout);
69673
+ const maxOrder = layout.reduce(
69674
+ (max, item) => Math.max(max, Number(item.order) || 0),
69675
+ 0,
69676
+ );
69677
+
69678
+ const newItem = {
69679
+ id: newId,
69680
+ order: maxOrder + 1,
69681
+ component: widgetName.trim(),
69682
+ parentId,
69683
+ config: {},
69684
+ };
69685
+
69686
+ workspace.layout = [...layout, newItem];
69687
+
69688
+ const saveResult = workspaceController$1.saveWorkspaceForApplication(
69689
+ win,
69690
+ appId,
69691
+ workspace,
69692
+ );
69693
+ if (saveResult.error) {
69694
+ return {
69695
+ content: [
69696
+ {
69697
+ type: "text",
69698
+ text: JSON.stringify({ error: saveResult.message }),
69699
+ },
69700
+ ],
69701
+ isError: true,
69702
+ };
69703
+ }
69704
+
69705
+ return {
69706
+ content: [
69707
+ {
69708
+ type: "text",
69709
+ text: JSON.stringify(
69710
+ {
69711
+ widgetId: String(newId),
69712
+ name: widgetName.trim(),
69713
+ dashboardId: String(workspace.id),
69714
+ },
69715
+ null,
69716
+ 2,
69717
+ ),
69718
+ },
69719
+ ],
69720
+ };
69721
+ }
69722
+
69723
+ /**
69724
+ * remove_widget — Remove a widget instance from a dashboard.
69725
+ */
69726
+ async function handleRemoveWidget$1({ dashboardId, widgetId }) {
69727
+ if (!widgetId || typeof widgetId !== "string") {
69728
+ return {
69729
+ content: [
69730
+ {
69731
+ type: "text",
69732
+ text: JSON.stringify({ error: "widgetId is required" }),
69733
+ },
69734
+ ],
69735
+ isError: true,
69736
+ };
69737
+ }
69738
+
69739
+ const { win, appId } = requireContext();
69740
+ const result = workspaceController$1.listWorkspacesForApplication(win, appId);
69741
+ if (result.error) {
69742
+ return {
69743
+ content: [
69744
+ { type: "text", text: JSON.stringify({ error: result.message }) },
69745
+ ],
69746
+ isError: true,
69747
+ };
69748
+ }
69749
+
69750
+ const found = findWorkspace(result.workspaces || [], dashboardId);
69751
+ if (found.error) return found.response;
69752
+
69753
+ const workspace = found.workspace;
69754
+ const layout = workspace.layout || [];
69755
+
69756
+ const exists = layout.some((item) => String(item.id) === widgetId);
69757
+ if (!exists) {
69758
+ return {
69759
+ content: [
69760
+ {
69761
+ type: "text",
69762
+ text: JSON.stringify({
69763
+ error: `Widget not found: ${widgetId}`,
69764
+ }),
69765
+ },
69766
+ ],
69767
+ isError: true,
69768
+ };
69769
+ }
69770
+
69771
+ workspace.layout = layout.filter((item) => String(item.id) !== widgetId);
69772
+
69773
+ const saveResult = workspaceController$1.saveWorkspaceForApplication(
69774
+ win,
69775
+ appId,
69776
+ workspace,
69777
+ );
69778
+ if (saveResult.error) {
69779
+ return {
69780
+ content: [
69781
+ {
69782
+ type: "text",
69783
+ text: JSON.stringify({ error: saveResult.message }),
69784
+ },
69785
+ ],
69786
+ isError: true,
69787
+ };
69788
+ }
69789
+
69790
+ return {
69791
+ content: [
69792
+ {
69793
+ type: "text",
69794
+ text: JSON.stringify({
69795
+ success: true,
69796
+ removed: widgetId,
69797
+ remainingWidgets: countWidgets(workspace.layout),
69798
+ }),
69799
+ },
69800
+ ],
69801
+ };
69802
+ }
69803
+
69804
+ /**
69805
+ * configure_widget — Update widget settings (partial merge).
69806
+ */
69807
+ async function handleConfigureWidget$1({ dashboardId, widgetId, config }) {
69808
+ if (!widgetId || typeof widgetId !== "string") {
69809
+ return {
69810
+ content: [
69811
+ {
69812
+ type: "text",
69813
+ text: JSON.stringify({ error: "widgetId is required" }),
69814
+ },
69815
+ ],
69816
+ isError: true,
69817
+ };
69818
+ }
69819
+
69820
+ if (!config || typeof config !== "object" || Array.isArray(config)) {
69821
+ return {
69822
+ content: [
69823
+ {
69824
+ type: "text",
69825
+ text: JSON.stringify({
69826
+ error: "config is required and must be an object",
69827
+ }),
69828
+ },
69829
+ ],
69830
+ isError: true,
69831
+ };
69832
+ }
69833
+
69834
+ const { win, appId } = requireContext();
69835
+ const result = workspaceController$1.listWorkspacesForApplication(win, appId);
69836
+ if (result.error) {
69837
+ return {
69838
+ content: [
69839
+ { type: "text", text: JSON.stringify({ error: result.message }) },
69840
+ ],
69841
+ isError: true,
69842
+ };
69843
+ }
69844
+
69845
+ const found = findWorkspace(result.workspaces || [], dashboardId);
69846
+ if (found.error) return found.response;
69847
+
69848
+ const workspace = found.workspace;
69849
+ const layout = workspace.layout || [];
69850
+ const item = layout.find((i) => String(i.id) === widgetId);
69851
+
69852
+ if (!item) {
69853
+ return {
69854
+ content: [
69855
+ {
69856
+ type: "text",
69857
+ text: JSON.stringify({
69858
+ error: `Widget not found: ${widgetId}`,
69859
+ }),
69860
+ },
69861
+ ],
69862
+ isError: true,
69863
+ };
69864
+ }
69865
+
69866
+ // Merge config
69867
+ item.config = { ...(item.config || {}), ...config };
69868
+
69869
+ const saveResult = workspaceController$1.saveWorkspaceForApplication(
69870
+ win,
69871
+ appId,
69872
+ workspace,
69873
+ );
69874
+ if (saveResult.error) {
69875
+ return {
69876
+ content: [
69877
+ {
69878
+ type: "text",
69879
+ text: JSON.stringify({ error: saveResult.message }),
69880
+ },
69881
+ ],
69882
+ isError: true,
69883
+ };
69884
+ }
69885
+
69886
+ return {
69887
+ content: [
69888
+ {
69889
+ type: "text",
69890
+ text: JSON.stringify(
69891
+ {
69892
+ widgetId,
69893
+ component: item.component,
69894
+ config: item.config,
69895
+ },
69896
+ null,
69897
+ 2,
69898
+ ),
69899
+ },
69900
+ ],
69901
+ };
69902
+ }
69903
+
69904
+ /**
69905
+ * list_widgets — List available widgets from the registry.
69906
+ */
69907
+ async function handleListWidgets$1() {
69908
+ try {
69909
+ const index = await registryController$1.fetchRegistryIndex();
69910
+ const packages = index.packages || [];
69911
+
69912
+ const widgets = [];
69913
+ for (const pkg of packages) {
69914
+ // Skip non-widget packages
69915
+ if (pkg.type && pkg.type !== "widget") continue;
69916
+
69917
+ for (const w of pkg.widgets || []) {
69918
+ widgets.push({
69919
+ name: w.name || pkg.name,
69920
+ displayName: w.displayName || w.name || pkg.displayName || pkg.name,
69921
+ description: w.description || pkg.description || "",
69922
+ icon: w.icon || pkg.icon || null,
69923
+ package: pkg.name,
69924
+ providers: (w.providers || pkg.providers || []).map((p) => ({
69925
+ type: p.type,
69926
+ providerClass: p.providerClass || "api",
69927
+ required: p.required !== false,
69928
+ })),
69929
+ });
69930
+ }
69931
+
69932
+ // If a package has no widgets array, treat the package itself as a widget
69933
+ if (!pkg.widgets || pkg.widgets.length === 0) {
69934
+ widgets.push({
69935
+ name: pkg.name,
69936
+ displayName: pkg.displayName || pkg.name,
69937
+ description: pkg.description || "",
69938
+ icon: pkg.icon || null,
69939
+ package: pkg.name,
69940
+ providers: (pkg.providers || []).map((p) => ({
69941
+ type: p.type,
69942
+ providerClass: p.providerClass || "api",
69943
+ required: p.required !== false,
69944
+ })),
69945
+ });
69946
+ }
69947
+ }
69948
+
69949
+ return {
69950
+ content: [
69951
+ {
69952
+ type: "text",
69953
+ text: JSON.stringify({ widgets, count: widgets.length }, null, 2),
69954
+ },
69955
+ ],
69956
+ };
69957
+ } catch (err) {
69958
+ return {
69959
+ content: [
69960
+ {
69961
+ type: "text",
69962
+ text: JSON.stringify({
69963
+ error: `Failed to fetch widget registry: ${err.message}`,
69964
+ }),
69965
+ },
69966
+ ],
69967
+ isError: true,
69968
+ };
69969
+ }
69970
+ }
69971
+
69972
+ /**
69973
+ * search_widgets — Search the registry by keyword.
69974
+ */
69975
+ async function handleSearchWidgets$1({ query }) {
69976
+ if (!query || typeof query !== "string" || !query.trim()) {
69977
+ return {
69978
+ content: [
69979
+ {
69980
+ type: "text",
69981
+ text: JSON.stringify({
69982
+ error: "query is required and must be a non-empty string",
69983
+ }),
69984
+ },
69985
+ ],
69986
+ isError: true,
69987
+ };
69988
+ }
69989
+
69990
+ try {
69991
+ const result = await registryController$1.searchRegistry(query.trim());
69992
+ const packages = result.packages || [];
69993
+
69994
+ const widgets = [];
69995
+ for (const pkg of packages) {
69996
+ if (pkg.type && pkg.type !== "widget") continue;
69997
+
69998
+ for (const w of pkg.widgets || []) {
69999
+ widgets.push({
70000
+ name: w.name || pkg.name,
70001
+ displayName: w.displayName || w.name || pkg.displayName || pkg.name,
70002
+ description: w.description || pkg.description || "",
70003
+ icon: w.icon || pkg.icon || null,
70004
+ package: pkg.name,
70005
+ providers: (w.providers || pkg.providers || []).map((p) => ({
70006
+ type: p.type,
70007
+ providerClass: p.providerClass || "api",
70008
+ required: p.required !== false,
70009
+ })),
70010
+ });
70011
+ }
70012
+
70013
+ if (!pkg.widgets || pkg.widgets.length === 0) {
70014
+ widgets.push({
70015
+ name: pkg.name,
70016
+ displayName: pkg.displayName || pkg.name,
70017
+ description: pkg.description || "",
70018
+ icon: pkg.icon || null,
70019
+ package: pkg.name,
70020
+ providers: (pkg.providers || []).map((p) => ({
70021
+ type: p.type,
70022
+ providerClass: p.providerClass || "api",
70023
+ required: p.required !== false,
70024
+ })),
70025
+ });
70026
+ }
70027
+ }
70028
+
70029
+ return {
70030
+ content: [
70031
+ {
70032
+ type: "text",
70033
+ text: JSON.stringify(
70034
+ { query: query.trim(), widgets, count: widgets.length },
70035
+ null,
70036
+ 2,
70037
+ ),
70038
+ },
70039
+ ],
70040
+ };
70041
+ } catch (err) {
70042
+ return {
70043
+ content: [
70044
+ {
70045
+ type: "text",
70046
+ text: JSON.stringify({
70047
+ error: `Failed to search widget registry: ${err.message}`,
70048
+ }),
70049
+ },
70050
+ ],
70051
+ isError: true,
70052
+ };
70053
+ }
70054
+ }
70055
+
70056
+ // --- Theme Tool Handlers ---
70057
+
70058
+ const settingsController$1 = settingsController_1;
70059
+ const themeFromUrlController$1 = themeFromUrlController_1;
70060
+ const paletteToThemeMapper$1 = paletteToThemeMapper_1;
70061
+ const extractionCacheController$1 = extractionCacheController_1;
70062
+ const { THEME_SAVE_COMPLETE, SETTINGS_SAVE_COMPLETE } = events$8;
70063
+
70064
+ /**
70065
+ * list_themes — Returns all saved themes with name, active state, and color summary.
70066
+ */
70067
+ async function handleListThemes$1() {
70068
+ const { win, appId } = requireContext();
70069
+ const result = themeController$1.listThemesForApplication(win, appId);
70070
+
70071
+ if (result.error) {
70072
+ return {
70073
+ content: [
70074
+ { type: "text", text: JSON.stringify({ error: result.message }) },
70075
+ ],
70076
+ isError: true,
70077
+ };
70078
+ }
70079
+
70080
+ const themes = result.themes || {};
70081
+ const settingsResult = settingsController$1.getSettingsForApplication(win);
70082
+ const activeThemeKey = settingsResult?.settings?.theme || null;
70083
+
70084
+ const themeList = Object.keys(themes).map((name) => ({
70085
+ name,
70086
+ isActive: name === activeThemeKey,
70087
+ colors: themes[name],
70088
+ }));
70089
+
70090
+ return {
70091
+ content: [
70092
+ {
70093
+ type: "text",
70094
+ text: JSON.stringify(
70095
+ { themes: themeList, count: themeList.length },
70096
+ null,
70097
+ 2,
70098
+ ),
70099
+ },
70100
+ ],
70101
+ };
70102
+ }
70103
+
70104
+ /**
70105
+ * get_theme — Returns full details of a theme by name.
70106
+ */
70107
+ async function handleGetTheme$1({ name }) {
70108
+ if (!name || typeof name !== "string" || !name.trim()) {
70109
+ return {
70110
+ content: [
70111
+ {
70112
+ type: "text",
70113
+ text: JSON.stringify({
70114
+ error: "name is required and must be a non-empty string",
70115
+ }),
70116
+ },
70117
+ ],
70118
+ isError: true,
70119
+ };
70120
+ }
70121
+
70122
+ const { win, appId } = requireContext();
70123
+ const result = themeController$1.listThemesForApplication(win, appId);
70124
+
70125
+ if (result.error) {
70126
+ return {
70127
+ content: [
70128
+ { type: "text", text: JSON.stringify({ error: result.message }) },
70129
+ ],
70130
+ isError: true,
70131
+ };
70132
+ }
70133
+
70134
+ const themes = result.themes || {};
70135
+ const themeName = name.trim();
70136
+
70137
+ if (!(themeName in themes)) {
70138
+ return {
70139
+ content: [
70140
+ {
70141
+ type: "text",
70142
+ text: JSON.stringify({ error: `Theme not found: ${themeName}` }),
70143
+ },
70144
+ ],
70145
+ isError: true,
70146
+ };
70147
+ }
70148
+
70149
+ const settingsResult = settingsController$1.getSettingsForApplication(win);
70150
+ const activeThemeKey = settingsResult?.settings?.theme || null;
70151
+
70152
+ return {
70153
+ content: [
70154
+ {
70155
+ type: "text",
70156
+ text: JSON.stringify(
70157
+ {
70158
+ name: themeName,
70159
+ isActive: themeName === activeThemeKey,
70160
+ colors: themes[themeName],
70161
+ },
70162
+ null,
70163
+ 2,
70164
+ ),
70165
+ },
70166
+ ],
70167
+ };
70168
+ }
70169
+
70170
+ /**
70171
+ * create_theme — Creates a new theme from a colors object.
70172
+ */
70173
+ async function handleCreateTheme$1({ name, colors }) {
70174
+ if (!name || typeof name !== "string" || !name.trim()) {
70175
+ return {
70176
+ content: [
70177
+ {
70178
+ type: "text",
70179
+ text: JSON.stringify({
70180
+ error: "name is required and must be a non-empty string",
70181
+ }),
70182
+ },
70183
+ ],
70184
+ isError: true,
70185
+ };
70186
+ }
70187
+
70188
+ if (!colors || typeof colors !== "object" || Array.isArray(colors)) {
70189
+ return {
70190
+ content: [
70191
+ {
70192
+ type: "text",
70193
+ text: JSON.stringify({
70194
+ error: "colors is required and must be an object",
70195
+ }),
70196
+ },
70197
+ ],
70198
+ isError: true,
70199
+ };
70200
+ }
70201
+
70202
+ const { win, appId } = requireContext();
70203
+ const themeName = name.trim();
70204
+
70205
+ const result = themeController$1.saveThemeForApplication(
70206
+ win,
70207
+ appId,
70208
+ themeName,
70209
+ colors,
70210
+ );
70211
+
70212
+ if (result.error) {
70213
+ return {
70214
+ content: [
70215
+ { type: "text", text: JSON.stringify({ error: result.message }) },
70216
+ ],
70217
+ isError: true,
70218
+ };
70219
+ }
70220
+
70221
+ // Notify the renderer so the UI updates
70222
+ win.webContents.send(THEME_SAVE_COMPLETE, result);
70223
+
70224
+ return {
70225
+ content: [
70226
+ {
70227
+ type: "text",
70228
+ text: JSON.stringify({ name: themeName, created: true }, null, 2),
70229
+ },
70230
+ ],
70231
+ };
70232
+ }
70233
+
70234
+ /**
70235
+ * create_theme_from_url — Extracts colors from a URL and generates a theme.
70236
+ * Uses a hidden BrowserWindow to load the page and extract styles.
70237
+ */
70238
+ async function handleCreateThemeFromUrl$1({ url, name }) {
70239
+ if (!url || typeof url !== "string" || !url.trim()) {
70240
+ return {
70241
+ content: [
70242
+ {
70243
+ type: "text",
70244
+ text: JSON.stringify({
70245
+ error: "url is required and must be a non-empty string",
70246
+ }),
70247
+ },
70248
+ ],
70249
+ isError: true,
70250
+ };
70251
+ }
70252
+
70253
+ const trimmedUrl = url.trim();
70254
+
70255
+ // Validate URL format
70256
+ if (!trimmedUrl.startsWith("http://") && !trimmedUrl.startsWith("https://")) {
70257
+ return {
70258
+ content: [
70259
+ {
70260
+ type: "text",
70261
+ text: JSON.stringify({
70262
+ error: "url must start with http:// or https://",
70263
+ }),
70264
+ },
70265
+ ],
70266
+ isError: true,
70267
+ };
70268
+ }
70269
+
70270
+ const { win, appId } = requireContext();
70271
+ const { BrowserWindow } = require$$0$2;
70272
+
70273
+ const LOAD_TIMEOUT_MS = 15000;
70274
+
70275
+ try {
70276
+ // Extract colors using a hidden BrowserWindow (same approach as dash-electron IPC handler)
70277
+ const extractionData = await extractionCacheController$1.get(
70278
+ trimmedUrl,
70279
+ async () => {
70280
+ const scanWindow = new BrowserWindow({
70281
+ width: 1280,
70282
+ height: 900,
70283
+ show: false,
70284
+ webPreferences: {
70285
+ nodeIntegration: false,
70286
+ contextIsolation: true,
70287
+ },
70288
+ });
70289
+
70290
+ let destroyed = false;
70291
+ const destroyScanWindow = () => {
70292
+ if (!destroyed) {
70293
+ destroyed = true;
70294
+ scanWindow.destroy();
70295
+ }
70296
+ };
70297
+
70298
+ try {
70299
+ scanWindow.webContents.on("will-navigate", (event) => {
70300
+ event.preventDefault();
70301
+ });
70302
+
70303
+ await new Promise((resolve, reject) => {
70304
+ const timeout = setTimeout(() => {
70305
+ reject(
70306
+ new Error(
70307
+ `Page load timed out after ${LOAD_TIMEOUT_MS}ms for ${trimmedUrl}`,
70308
+ ),
70309
+ );
70310
+ }, LOAD_TIMEOUT_MS);
70311
+
70312
+ scanWindow.webContents.on(
70313
+ "did-fail-load",
70314
+ (event, errorCode, errorDescription) => {
70315
+ clearTimeout(timeout);
70316
+ const desc = errorDescription || `Error code ${errorCode}`;
70317
+ reject(new Error(`Page load failed: ${desc}`));
70318
+ },
70319
+ );
70320
+
70321
+ scanWindow
70322
+ .loadURL(trimmedUrl)
70323
+ .then(() => {
70324
+ clearTimeout(timeout);
70325
+ resolve();
70326
+ })
70327
+ .catch((err) => {
70328
+ clearTimeout(timeout);
70329
+ reject(
70330
+ new Error(`Failed to load ${trimmedUrl}: ${err.message}`),
70331
+ );
70332
+ });
70333
+ });
70334
+
70335
+ const extracted = await scanWindow.webContents.executeJavaScript(`
70336
+ (function() {
70337
+ try {
70338
+ const htmlContent = document.documentElement.outerHTML;
70339
+ let cssContent = '';
70340
+ try {
70341
+ for (const sheet of document.styleSheets) {
70342
+ try {
70343
+ for (const rule of sheet.cssRules) {
70344
+ cssContent += rule.cssText + '\\n';
70345
+ }
70346
+ } catch (e) { /* cross-origin stylesheet */ }
70347
+ }
70348
+ } catch (e) {}
70349
+ const selectors = ['body', 'header', 'nav', 'main', 'footer', 'a', 'button', 'h1', 'h2'];
70350
+ const computedStyles = {};
70351
+ for (const sel of selectors) {
70352
+ const el = document.querySelector(sel);
70353
+ if (!el) continue;
70354
+ const cs = window.getComputedStyle(el);
70355
+ computedStyles[sel] = {
70356
+ color: cs.color,
70357
+ backgroundColor: cs.backgroundColor,
70358
+ borderColor: cs.borderColor,
70359
+ };
70360
+ }
70361
+ return { success: true, htmlContent, cssContent, computedStyles };
70362
+ } catch (e) {
70363
+ return { success: false, error: { type: 'EXTRACTION_FAILED', message: e.message } };
70364
+ }
70365
+ })();
70366
+ `);
70367
+
70368
+ if (!extracted || !extracted.success) {
70369
+ const errMsg =
70370
+ extracted?.error?.message || "Script execution failed";
70371
+ throw new Error(`Color extraction failed: ${errMsg}`);
70372
+ }
70373
+
70374
+ return themeFromUrlController$1.extractColorsFromUrl({
70375
+ htmlContent: extracted.htmlContent,
70376
+ cssContent: extracted.cssContent,
70377
+ computedStyles: extracted.computedStyles,
70378
+ baseUrl: trimmedUrl,
70379
+ });
70380
+ } finally {
70381
+ destroyScanWindow();
70382
+ }
70383
+ },
70384
+ );
70385
+
70386
+ // Map palette to theme
70387
+ const palette = extractionData?.palette || [];
70388
+ if (palette.length === 0) {
70389
+ return {
70390
+ content: [
70391
+ {
70392
+ type: "text",
70393
+ text: JSON.stringify({
70394
+ error: "No colors could be extracted from the URL",
70395
+ }),
70396
+ },
70397
+ ],
70398
+ isError: true,
70399
+ };
70400
+ }
70401
+
70402
+ const { theme: generatedTheme } =
70403
+ paletteToThemeMapper$1.generateThemeFromPalette(palette);
70404
+
70405
+ // Derive theme name from URL hostname if not provided
70406
+ let themeName;
70407
+ if (name && typeof name === "string" && name.trim()) {
70408
+ themeName = name.trim();
70409
+ } else {
70410
+ try {
70411
+ const { URL } = require("url");
70412
+ const parsed = new URL(trimmedUrl);
70413
+ themeName = parsed.hostname.replace(/^www\./, "");
70414
+ } catch {
70415
+ themeName = "url-theme";
70416
+ }
70417
+ }
70418
+
70419
+ // Save the generated theme
70420
+ const saveResult = themeController$1.saveThemeForApplication(
70421
+ win,
70422
+ appId,
70423
+ themeName,
70424
+ generatedTheme,
70425
+ );
70426
+
70427
+ if (saveResult.error) {
70428
+ return {
70429
+ content: [
70430
+ { type: "text", text: JSON.stringify({ error: saveResult.message }) },
70431
+ ],
70432
+ isError: true,
70433
+ };
70434
+ }
70435
+
70436
+ // Notify the renderer
70437
+ win.webContents.send(THEME_SAVE_COMPLETE, saveResult);
70438
+
70439
+ return {
70440
+ content: [
70441
+ {
70442
+ type: "text",
70443
+ text: JSON.stringify(
70444
+ {
70445
+ name: themeName,
70446
+ created: true,
70447
+ colorsExtracted: palette.length,
70448
+ source: trimmedUrl,
70449
+ },
70450
+ null,
70451
+ 2,
70452
+ ),
70453
+ },
70454
+ ],
70455
+ };
70456
+ } catch (err) {
70457
+ return {
70458
+ content: [
70459
+ {
70460
+ type: "text",
70461
+ text: JSON.stringify({
70462
+ error: `Failed to create theme from URL: ${err.message}`,
70463
+ }),
70464
+ },
70465
+ ],
70466
+ isError: true,
70467
+ };
70468
+ }
70469
+ }
70470
+
70471
+ /**
70472
+ * apply_theme — Applies a saved theme to the active dashboard.
70473
+ * Updates settings to set the active theme key and notifies the renderer.
70474
+ */
70475
+ async function handleApplyTheme$1({ name }) {
70476
+ if (!name || typeof name !== "string" || !name.trim()) {
70477
+ return {
70478
+ content: [
70479
+ {
70480
+ type: "text",
70481
+ text: JSON.stringify({
70482
+ error: "name is required and must be a non-empty string",
70483
+ }),
70484
+ },
70485
+ ],
70486
+ isError: true,
70487
+ };
70488
+ }
70489
+
70490
+ const { win, appId } = requireContext();
70491
+ const themeName = name.trim();
70492
+
70493
+ // Verify the theme exists
70494
+ const themeResult = themeController$1.listThemesForApplication(win, appId);
70495
+ if (themeResult.error) {
70496
+ return {
70497
+ content: [
70498
+ {
70499
+ type: "text",
70500
+ text: JSON.stringify({ error: themeResult.message }),
70501
+ },
70502
+ ],
70503
+ isError: true,
70504
+ };
70505
+ }
70506
+
70507
+ const themes = themeResult.themes || {};
70508
+ if (!(themeName in themes)) {
70509
+ return {
70510
+ content: [
70511
+ {
70512
+ type: "text",
70513
+ text: JSON.stringify({
70514
+ error: `Theme not found: ${themeName}. Use list_themes to see available themes.`,
70515
+ }),
70516
+ },
70517
+ ],
70518
+ isError: true,
70519
+ };
70520
+ }
70521
+
70522
+ // Update settings to set the active theme
70523
+ const settingsResult = settingsController$1.getSettingsForApplication(win);
70524
+ const settings = settingsResult?.settings || {};
70525
+ settings.theme = themeName;
70526
+
70527
+ const saveResult = settingsController$1.saveSettingsForApplication(
70528
+ win,
70529
+ settings,
70530
+ );
70531
+
70532
+ if (saveResult.error) {
70533
+ return {
70534
+ content: [
70535
+ {
70536
+ type: "text",
70537
+ text: JSON.stringify({ error: saveResult.message }),
70538
+ },
70539
+ ],
70540
+ isError: true,
70541
+ };
70542
+ }
70543
+
70544
+ // Notify the renderer to update the theme
70545
+ win.webContents.send(SETTINGS_SAVE_COMPLETE, { settings });
70546
+
70547
+ return {
70548
+ content: [
70549
+ {
70550
+ type: "text",
70551
+ text: JSON.stringify({ name: themeName, applied: true }, null, 2),
70552
+ },
70553
+ ],
70554
+ };
70555
+ }
70556
+
69395
70557
  var toolHandlers = {
69396
70558
  handleListDashboards: handleListDashboards$1,
69397
70559
  handleGetDashboard: handleGetDashboard$1,
69398
70560
  handleCreateDashboard: handleCreateDashboard$1,
69399
70561
  handleDeleteDashboard: handleDeleteDashboard$1,
69400
70562
  handleGetAppStats: handleGetAppStats$1,
70563
+ handleAddWidget: handleAddWidget$1,
70564
+ handleRemoveWidget: handleRemoveWidget$1,
70565
+ handleConfigureWidget: handleConfigureWidget$1,
70566
+ handleListWidgets: handleListWidgets$1,
70567
+ handleSearchWidgets: handleSearchWidgets$1,
70568
+ handleListThemes: handleListThemes$1,
70569
+ handleGetTheme: handleGetTheme$1,
70570
+ handleCreateTheme: handleCreateTheme$1,
70571
+ handleCreateThemeFromUrl: handleCreateThemeFromUrl$1,
70572
+ handleApplyTheme: handleApplyTheme$1,
69401
70573
  };
69402
70574
 
69403
70575
  /**
@@ -69407,7 +70579,7 @@ var toolHandlers = {
69407
70579
  * Call registerDashboardTools() during app startup (before or after server start).
69408
70580
  */
69409
70581
 
69410
- const { registerTool } = mcpDashServerController_1;
70582
+ const { registerTool: registerTool$2 } = mcpDashServerController_1;
69411
70583
  const { dashboardTools } = toolDefinitions;
69412
70584
  const {
69413
70585
  handleListDashboards,
@@ -69418,7 +70590,7 @@ const {
69418
70590
  } = toolHandlers;
69419
70591
 
69420
70592
  // Map tool names to handler functions
69421
- const handlerMap = {
70593
+ const handlerMap$2 = {
69422
70594
  list_dashboards: handleListDashboards,
69423
70595
  get_dashboard: handleGetDashboard,
69424
70596
  create_dashboard: handleCreateDashboard,
@@ -69431,12 +70603,12 @@ const handlerMap = {
69431
70603
  */
69432
70604
  function registerDashboardTools$1() {
69433
70605
  for (const tool of dashboardTools) {
69434
- const handler = handlerMap[tool.name];
70606
+ const handler = handlerMap$2[tool.name];
69435
70607
  if (!handler) {
69436
70608
  console.warn(`[dashboardTools] No handler found for tool: ${tool.name}`);
69437
70609
  continue;
69438
70610
  }
69439
- registerTool({
70611
+ registerTool$2({
69440
70612
  name: tool.name,
69441
70613
  description: tool.description,
69442
70614
  inputSchema: tool.inputSchema,
@@ -69450,6 +70622,102 @@ function registerDashboardTools$1() {
69450
70622
 
69451
70623
  var dashboardTools_1 = { registerDashboardTools: registerDashboardTools$1 };
69452
70624
 
70625
+ /**
70626
+ * widgetTools.js
70627
+ *
70628
+ * Registers widget MCP tools with the MCP Dash server.
70629
+ * Call registerWidgetTools() during app startup (before or after server start).
70630
+ */
70631
+
70632
+ const { registerTool: registerTool$1 } = mcpDashServerController_1;
70633
+ const { widgetTools } = toolDefinitions;
70634
+ const {
70635
+ handleAddWidget,
70636
+ handleRemoveWidget,
70637
+ handleConfigureWidget,
70638
+ handleListWidgets,
70639
+ handleSearchWidgets,
70640
+ } = toolHandlers;
70641
+
70642
+ // Map tool names to handler functions
70643
+ const handlerMap$1 = {
70644
+ add_widget: handleAddWidget,
70645
+ remove_widget: handleRemoveWidget,
70646
+ configure_widget: handleConfigureWidget,
70647
+ list_widgets: handleListWidgets,
70648
+ search_widgets: handleSearchWidgets,
70649
+ };
70650
+
70651
+ /**
70652
+ * Register all widget tools with the MCP server controller.
70653
+ */
70654
+ function registerWidgetTools$1() {
70655
+ for (const tool of widgetTools) {
70656
+ const handler = handlerMap$1[tool.name];
70657
+ if (!handler) {
70658
+ console.warn(`[widgetTools] No handler found for tool: ${tool.name}`);
70659
+ continue;
70660
+ }
70661
+ registerTool$1({
70662
+ name: tool.name,
70663
+ description: tool.description,
70664
+ inputSchema: tool.inputSchema,
70665
+ handler,
70666
+ });
70667
+ }
70668
+ console.log(`[widgetTools] Registered ${widgetTools.length} widget tools`);
70669
+ }
70670
+
70671
+ var widgetTools_1 = { registerWidgetTools: registerWidgetTools$1 };
70672
+
70673
+ /**
70674
+ * themeTools.js
70675
+ *
70676
+ * Registers theme MCP tools with the MCP Dash server.
70677
+ * Call registerThemeTools() during app startup (before or after server start).
70678
+ */
70679
+
70680
+ const { registerTool } = mcpDashServerController_1;
70681
+ const { themeTools } = toolDefinitions;
70682
+ const {
70683
+ handleListThemes,
70684
+ handleGetTheme,
70685
+ handleCreateTheme,
70686
+ handleCreateThemeFromUrl,
70687
+ handleApplyTheme,
70688
+ } = toolHandlers;
70689
+
70690
+ // Map tool names to handler functions
70691
+ const handlerMap = {
70692
+ list_themes: handleListThemes,
70693
+ get_theme: handleGetTheme,
70694
+ create_theme: handleCreateTheme,
70695
+ create_theme_from_url: handleCreateThemeFromUrl,
70696
+ apply_theme: handleApplyTheme,
70697
+ };
70698
+
70699
+ /**
70700
+ * Register all theme tools with the MCP server controller.
70701
+ */
70702
+ function registerThemeTools$1() {
70703
+ for (const tool of themeTools) {
70704
+ const handler = handlerMap[tool.name];
70705
+ if (!handler) {
70706
+ console.warn(`[themeTools] No handler found for tool: ${tool.name}`);
70707
+ continue;
70708
+ }
70709
+ registerTool({
70710
+ name: tool.name,
70711
+ description: tool.description,
70712
+ inputSchema: tool.inputSchema,
70713
+ handler,
70714
+ });
70715
+ }
70716
+ console.log(`[themeTools] Registered ${themeTools.length} theme tools`);
70717
+ }
70718
+
70719
+ var themeTools_1 = { registerThemeTools: registerThemeTools$1 };
70720
+
69453
70721
  /**
69454
70722
  * dashboardRatingsApi.js
69455
70723
  *
@@ -69706,7 +70974,7 @@ const settingsController = settingsController_1;
69706
70974
  const providerController = requireProviderController();
69707
70975
  const layoutController = layoutController_1;
69708
70976
  const mcpController = mcpControllerExports;
69709
- const registryController = registryController$2;
70977
+ const registryController = registryController$3;
69710
70978
  const algoliaController = algoliaController_1;
69711
70979
  const openaiController = openaiController_1;
69712
70980
  const menuItemsController = menuItemsController_1;
@@ -69772,7 +71040,11 @@ const dynamicWidgetLoader = dynamicWidgetLoaderExports;
69772
71040
 
69773
71041
  // --- MCP Dash Server Tools ---
69774
71042
  const { registerDashboardTools } = dashboardTools_1;
71043
+ const { registerWidgetTools } = widgetTools_1;
71044
+ const { registerThemeTools } = themeTools_1;
69775
71045
  registerDashboardTools();
71046
+ registerWidgetTools();
71047
+ registerThemeTools();
69776
71048
 
69777
71049
  // --- Schema ---
69778
71050
  const dashboardConfigValidator = dashboardConfigValidator$1;
@@ -69868,6 +71140,8 @@ var electron = {
69868
71140
 
69869
71141
  // MCP Dash Server Tools
69870
71142
  registerDashboardTools,
71143
+ registerWidgetTools,
71144
+ registerThemeTools,
69871
71145
  };
69872
71146
 
69873
71147
  var index = /*@__PURE__*/getDefaultExportFromCjs(electron);