@trops/dash-core 0.1.172 → 0.1.174

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
@@ -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$2(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$2,
66437
+ registerTool: registerTool$3,
66438
66438
  registerResource,
66439
66439
  getServerContext,
66440
66440
  };
@@ -69134,7 +69134,91 @@ const widgetTools$1 = [
69134
69134
  },
69135
69135
  ];
69136
69136
 
69137
- var toolDefinitions = { dashboardTools: dashboardTools$1, widgetTools: widgetTools$1 };
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 };
69138
69222
 
69139
69223
  /**
69140
69224
  * toolHandlers.js
@@ -69969,6 +70053,507 @@ async function handleSearchWidgets$1({ query }) {
69969
70053
  }
69970
70054
  }
69971
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
+
69972
70557
  var toolHandlers = {
69973
70558
  handleListDashboards: handleListDashboards$1,
69974
70559
  handleGetDashboard: handleGetDashboard$1,
@@ -69980,6 +70565,11 @@ var toolHandlers = {
69980
70565
  handleConfigureWidget: handleConfigureWidget$1,
69981
70566
  handleListWidgets: handleListWidgets$1,
69982
70567
  handleSearchWidgets: handleSearchWidgets$1,
70568
+ handleListThemes: handleListThemes$1,
70569
+ handleGetTheme: handleGetTheme$1,
70570
+ handleCreateTheme: handleCreateTheme$1,
70571
+ handleCreateThemeFromUrl: handleCreateThemeFromUrl$1,
70572
+ handleApplyTheme: handleApplyTheme$1,
69983
70573
  };
69984
70574
 
69985
70575
  /**
@@ -69989,7 +70579,7 @@ var toolHandlers = {
69989
70579
  * Call registerDashboardTools() during app startup (before or after server start).
69990
70580
  */
69991
70581
 
69992
- const { registerTool: registerTool$1 } = mcpDashServerController_1;
70582
+ const { registerTool: registerTool$2 } = mcpDashServerController_1;
69993
70583
  const { dashboardTools } = toolDefinitions;
69994
70584
  const {
69995
70585
  handleListDashboards,
@@ -70000,7 +70590,7 @@ const {
70000
70590
  } = toolHandlers;
70001
70591
 
70002
70592
  // Map tool names to handler functions
70003
- const handlerMap$1 = {
70593
+ const handlerMap$2 = {
70004
70594
  list_dashboards: handleListDashboards,
70005
70595
  get_dashboard: handleGetDashboard,
70006
70596
  create_dashboard: handleCreateDashboard,
@@ -70013,12 +70603,12 @@ const handlerMap$1 = {
70013
70603
  */
70014
70604
  function registerDashboardTools$1() {
70015
70605
  for (const tool of dashboardTools) {
70016
- const handler = handlerMap$1[tool.name];
70606
+ const handler = handlerMap$2[tool.name];
70017
70607
  if (!handler) {
70018
70608
  console.warn(`[dashboardTools] No handler found for tool: ${tool.name}`);
70019
70609
  continue;
70020
70610
  }
70021
- registerTool$1({
70611
+ registerTool$2({
70022
70612
  name: tool.name,
70023
70613
  description: tool.description,
70024
70614
  inputSchema: tool.inputSchema,
@@ -70039,7 +70629,7 @@ var dashboardTools_1 = { registerDashboardTools: registerDashboardTools$1 };
70039
70629
  * Call registerWidgetTools() during app startup (before or after server start).
70040
70630
  */
70041
70631
 
70042
- const { registerTool } = mcpDashServerController_1;
70632
+ const { registerTool: registerTool$1 } = mcpDashServerController_1;
70043
70633
  const { widgetTools } = toolDefinitions;
70044
70634
  const {
70045
70635
  handleAddWidget,
@@ -70050,7 +70640,7 @@ const {
70050
70640
  } = toolHandlers;
70051
70641
 
70052
70642
  // Map tool names to handler functions
70053
- const handlerMap = {
70643
+ const handlerMap$1 = {
70054
70644
  add_widget: handleAddWidget,
70055
70645
  remove_widget: handleRemoveWidget,
70056
70646
  configure_widget: handleConfigureWidget,
@@ -70063,12 +70653,12 @@ const handlerMap = {
70063
70653
  */
70064
70654
  function registerWidgetTools$1() {
70065
70655
  for (const tool of widgetTools) {
70066
- const handler = handlerMap[tool.name];
70656
+ const handler = handlerMap$1[tool.name];
70067
70657
  if (!handler) {
70068
70658
  console.warn(`[widgetTools] No handler found for tool: ${tool.name}`);
70069
70659
  continue;
70070
70660
  }
70071
- registerTool({
70661
+ registerTool$1({
70072
70662
  name: tool.name,
70073
70663
  description: tool.description,
70074
70664
  inputSchema: tool.inputSchema,
@@ -70080,6 +70670,54 @@ function registerWidgetTools$1() {
70080
70670
 
70081
70671
  var widgetTools_1 = { registerWidgetTools: registerWidgetTools$1 };
70082
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
+
70083
70721
  /**
70084
70722
  * dashboardRatingsApi.js
70085
70723
  *
@@ -70403,8 +71041,10 @@ const dynamicWidgetLoader = dynamicWidgetLoaderExports;
70403
71041
  // --- MCP Dash Server Tools ---
70404
71042
  const { registerDashboardTools } = dashboardTools_1;
70405
71043
  const { registerWidgetTools } = widgetTools_1;
71044
+ const { registerThemeTools } = themeTools_1;
70406
71045
  registerDashboardTools();
70407
71046
  registerWidgetTools();
71047
+ registerThemeTools();
70408
71048
 
70409
71049
  // --- Schema ---
70410
71050
  const dashboardConfigValidator = dashboardConfigValidator$1;
@@ -70501,6 +71141,7 @@ var electron = {
70501
71141
  // MCP Dash Server Tools
70502
71142
  registerDashboardTools,
70503
71143
  registerWidgetTools,
71144
+ registerThemeTools,
70504
71145
  };
70505
71146
 
70506
71147
  var index = /*@__PURE__*/getDefaultExportFromCjs(electron);