@trops/dash-core 0.1.382 → 0.1.384
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.
- package/dist/electron/index.js +181 -23
- package/dist/electron/index.js.map +1 -1
- package/dist/index.esm.js +74 -14
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +74 -14
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/electron/index.js
CHANGED
|
@@ -18,7 +18,8 @@ var require$$8$1 = require('https');
|
|
|
18
18
|
var require$$0$6 = require('@modelcontextprotocol/sdk/client/index.js');
|
|
19
19
|
var require$$1$4 = require('@modelcontextprotocol/sdk/client/stdio.js');
|
|
20
20
|
var require$$0$5 = require('pkce-challenge');
|
|
21
|
-
var require$$
|
|
21
|
+
var require$$5$1 = require('os');
|
|
22
|
+
var require$$7 = require('child_process');
|
|
22
23
|
var require$$2$2 = require('algoliasearch');
|
|
23
24
|
var require$$3$3 = require('node:path');
|
|
24
25
|
var require$$0$7 = require('openai');
|
|
@@ -28,7 +29,6 @@ var require$$1$5 = require('crypto');
|
|
|
28
29
|
var require$$0$8 = require('http');
|
|
29
30
|
var require$$1$6 = require('http2');
|
|
30
31
|
var require$$2$3 = require('node-forge');
|
|
31
|
-
var require$$2$5 = require('os');
|
|
32
32
|
var require$$3$4 = require('adm-zip');
|
|
33
33
|
var require$$4$1 = require('url');
|
|
34
34
|
var require$$2$4 = require('vm');
|
|
@@ -25629,6 +25629,7 @@ const {
|
|
|
25629
25629
|
} = streamableHttp$1;
|
|
25630
25630
|
const path$c = require$$1$2;
|
|
25631
25631
|
const fs$8 = require$$0$2;
|
|
25632
|
+
const os = require$$5$1;
|
|
25632
25633
|
const responseCache$2 = responseCache_1;
|
|
25633
25634
|
|
|
25634
25635
|
/**
|
|
@@ -25676,6 +25677,8 @@ function isReadOnlyTool(toolName) {
|
|
|
25676
25677
|
*/
|
|
25677
25678
|
const DEFAULT_TOOL_CACHE_TTL = 5000;
|
|
25678
25679
|
|
|
25680
|
+
const IS_WINDOWS$1 = process.platform === "win32";
|
|
25681
|
+
|
|
25679
25682
|
/**
|
|
25680
25683
|
* Cached shell PATH result (resolved once, reused for all spawns).
|
|
25681
25684
|
*/
|
|
@@ -25712,11 +25715,21 @@ function isNodeEsmError(errorText) {
|
|
|
25712
25715
|
function getShellPath$1() {
|
|
25713
25716
|
if (_shellPath$1 !== null) return _shellPath$1;
|
|
25714
25717
|
|
|
25715
|
-
|
|
25718
|
+
// Windows: skip the POSIX shell-path discovery entirely. The nvm /
|
|
25719
|
+
// homebrew / volta fallback dirs below are *nix-specific, and
|
|
25720
|
+
// Windows Electron apps typically inherit a working PATH from the
|
|
25721
|
+
// launcher. Users managing Node via nvm-windows or fnm should
|
|
25722
|
+
// already have their shims on PATH.
|
|
25723
|
+
if (IS_WINDOWS$1) {
|
|
25724
|
+
_shellPath$1 = process.env.PATH || "";
|
|
25725
|
+
return _shellPath$1;
|
|
25726
|
+
}
|
|
25727
|
+
|
|
25728
|
+
const { execSync } = require$$7;
|
|
25716
25729
|
const fallbackDirs = ["/usr/local/bin", "/opt/homebrew/bin"];
|
|
25717
25730
|
|
|
25718
25731
|
// Scan nvm versions, tracking both latest and best compatible version
|
|
25719
|
-
const home =
|
|
25732
|
+
const home = os.homedir();
|
|
25720
25733
|
let compatibleNvmBin = null;
|
|
25721
25734
|
if (home) {
|
|
25722
25735
|
fallbackDirs.push(`${home}/.volta/bin`);
|
|
@@ -25855,7 +25868,7 @@ function interpolate$1(template, credentials) {
|
|
|
25855
25868
|
* @param {object} tokenRefresh { credentialsPath, oauthKeysPath }
|
|
25856
25869
|
*/
|
|
25857
25870
|
async function refreshGoogleOAuthToken(tokenRefresh) {
|
|
25858
|
-
const home =
|
|
25871
|
+
const home = os.homedir();
|
|
25859
25872
|
const credPath = tokenRefresh.credentialsPath.replace(/^~/, home);
|
|
25860
25873
|
const keysPath = tokenRefresh.oauthKeysPath.replace(/^~/, home);
|
|
25861
25874
|
|
|
@@ -26051,7 +26064,7 @@ const mcpController$2 = {
|
|
|
26051
26064
|
// Merge static env vars from mcpConfig (with ~ expansion)
|
|
26052
26065
|
if (mcpConfig.staticEnv) {
|
|
26053
26066
|
Object.entries(mcpConfig.staticEnv).forEach(([envVar, value]) => {
|
|
26054
|
-
env[envVar] = value.replace(/^~/,
|
|
26067
|
+
env[envVar] = value.replace(/^~/, os.homedir());
|
|
26055
26068
|
});
|
|
26056
26069
|
}
|
|
26057
26070
|
|
|
@@ -26542,7 +26555,7 @@ const mcpController$2 = {
|
|
|
26542
26555
|
* @returns {{ success } | { error, message }}
|
|
26543
26556
|
*/
|
|
26544
26557
|
runAuth: async (win, mcpConfig, credentials, authCommand) => {
|
|
26545
|
-
const { spawn } = require$$
|
|
26558
|
+
const { spawn } = require$$7;
|
|
26546
26559
|
|
|
26547
26560
|
const env = cleanEnvForChildProcess();
|
|
26548
26561
|
|
|
@@ -26551,7 +26564,7 @@ const mcpController$2 = {
|
|
|
26551
26564
|
const { from, to } = authCommand.setup.copyCredential;
|
|
26552
26565
|
const sourcePath = credentials?.[from];
|
|
26553
26566
|
if (sourcePath) {
|
|
26554
|
-
const destPath = to.replace(/^~/,
|
|
26567
|
+
const destPath = to.replace(/^~/, os.homedir());
|
|
26555
26568
|
const destDir = require$$1$2.dirname(destPath);
|
|
26556
26569
|
try {
|
|
26557
26570
|
fs$8.mkdirSync(destDir, { recursive: true });
|
|
@@ -26586,7 +26599,7 @@ const mcpController$2 = {
|
|
|
26586
26599
|
// Merge static env vars from authCommand with ~ expansion
|
|
26587
26600
|
if (authCommand.staticEnv) {
|
|
26588
26601
|
Object.entries(authCommand.staticEnv).forEach(([key, value]) => {
|
|
26589
|
-
env[key] = value.replace(/^~/,
|
|
26602
|
+
env[key] = value.replace(/^~/, os.homedir());
|
|
26590
26603
|
});
|
|
26591
26604
|
}
|
|
26592
26605
|
|
|
@@ -26602,6 +26615,8 @@ const mcpController$2 = {
|
|
|
26602
26615
|
const proc = spawn(authCommand.command, resolvedArgs, {
|
|
26603
26616
|
env,
|
|
26604
26617
|
stdio: ["ignore", "pipe", "pipe"],
|
|
26618
|
+
// Needed so Windows can launch .cmd/.bat wrappers (npx.cmd, etc).
|
|
26619
|
+
shell: IS_WINDOWS$1,
|
|
26605
26620
|
});
|
|
26606
26621
|
|
|
26607
26622
|
let stdout = "";
|
|
@@ -28149,7 +28164,7 @@ var pluginController_1 = pluginController$1;
|
|
|
28149
28164
|
* can use the Chat widget without a separate API key.
|
|
28150
28165
|
*/
|
|
28151
28166
|
|
|
28152
|
-
const { spawn, execSync } = require$$
|
|
28167
|
+
const { spawn, execSync } = require$$7;
|
|
28153
28168
|
const {
|
|
28154
28169
|
LLM_STREAM_DELTA: LLM_STREAM_DELTA$2,
|
|
28155
28170
|
LLM_STREAM_TOOL_CALL: LLM_STREAM_TOOL_CALL$2,
|
|
@@ -28158,6 +28173,8 @@ const {
|
|
|
28158
28173
|
LLM_STREAM_ERROR: LLM_STREAM_ERROR$2,
|
|
28159
28174
|
} = llmEvents$1;
|
|
28160
28175
|
|
|
28176
|
+
const IS_WINDOWS = process.platform === "win32";
|
|
28177
|
+
|
|
28161
28178
|
/**
|
|
28162
28179
|
* Cached shell PATH result (resolved once, reused for all spawns).
|
|
28163
28180
|
* Same pattern as mcpController.js.
|
|
@@ -28167,6 +28184,13 @@ let _shellPath = null;
|
|
|
28167
28184
|
function getShellPath() {
|
|
28168
28185
|
if (_shellPath !== null) return _shellPath;
|
|
28169
28186
|
|
|
28187
|
+
// Windows: no POSIX login-shell trick — just use the inherited PATH,
|
|
28188
|
+
// which is typically correct for GUI-launched Electron apps.
|
|
28189
|
+
if (IS_WINDOWS) {
|
|
28190
|
+
_shellPath = process.env.PATH || "";
|
|
28191
|
+
return _shellPath;
|
|
28192
|
+
}
|
|
28193
|
+
|
|
28170
28194
|
try {
|
|
28171
28195
|
const shell = process.env.SHELL || "/bin/bash";
|
|
28172
28196
|
_shellPath = execSync(`${shell} -ilc 'echo -n "$PATH"'`, {
|
|
@@ -28181,7 +28205,7 @@ function getShellPath() {
|
|
|
28181
28205
|
}
|
|
28182
28206
|
|
|
28183
28207
|
/**
|
|
28184
|
-
* Cached CLI binary path (resolved once via `which
|
|
28208
|
+
* Cached CLI binary path (resolved once via `which` / `where`).
|
|
28185
28209
|
*/
|
|
28186
28210
|
let _cliBinaryPath = undefined; // undefined = not yet checked
|
|
28187
28211
|
|
|
@@ -28190,11 +28214,21 @@ function resolveCliBinary() {
|
|
|
28190
28214
|
|
|
28191
28215
|
try {
|
|
28192
28216
|
const fullPath = getShellPath();
|
|
28193
|
-
|
|
28217
|
+
// `where` on Windows, `which` everywhere else. `where` may list
|
|
28218
|
+
// multiple matches on separate lines (e.g. claude.cmd + claude.ps1)
|
|
28219
|
+
// — take the first hit.
|
|
28220
|
+
const lookup = IS_WINDOWS ? "where claude" : "which claude";
|
|
28221
|
+
const result = execSync(lookup, {
|
|
28194
28222
|
encoding: "utf8",
|
|
28195
28223
|
timeout: 5000,
|
|
28196
28224
|
env: { ...process.env, PATH: fullPath },
|
|
28197
|
-
})
|
|
28225
|
+
});
|
|
28226
|
+
_cliBinaryPath = IS_WINDOWS
|
|
28227
|
+
? result
|
|
28228
|
+
.split(/\r?\n/)
|
|
28229
|
+
.find((l) => l.trim())
|
|
28230
|
+
?.trim() || null
|
|
28231
|
+
: result.trim();
|
|
28198
28232
|
} catch {
|
|
28199
28233
|
_cliBinaryPath = null;
|
|
28200
28234
|
}
|
|
@@ -28208,6 +28242,33 @@ function resolveCliBinary() {
|
|
|
28208
28242
|
*/
|
|
28209
28243
|
const activeProcesses = new Map();
|
|
28210
28244
|
|
|
28245
|
+
/**
|
|
28246
|
+
* Kill a child process and its descendants. On Windows, spawning with
|
|
28247
|
+
* shell:true (needed for .cmd targets) means child.kill() only
|
|
28248
|
+
* terminates the cmd.exe — the real CLI keeps running. Use taskkill
|
|
28249
|
+
* with /T (tree) /F (force) to clean up.
|
|
28250
|
+
*/
|
|
28251
|
+
function killChildTree(child) {
|
|
28252
|
+
if (!child || child.killed || typeof child.pid !== "number") return;
|
|
28253
|
+
if (IS_WINDOWS) {
|
|
28254
|
+
try {
|
|
28255
|
+
execSync(`taskkill /pid ${child.pid} /T /F`, {
|
|
28256
|
+
stdio: "ignore",
|
|
28257
|
+
timeout: 5000,
|
|
28258
|
+
});
|
|
28259
|
+
} catch {
|
|
28260
|
+
// Fall back to plain kill — best-effort
|
|
28261
|
+
try {
|
|
28262
|
+
child.kill();
|
|
28263
|
+
} catch {
|
|
28264
|
+
/* ignore */
|
|
28265
|
+
}
|
|
28266
|
+
}
|
|
28267
|
+
} else {
|
|
28268
|
+
child.kill("SIGTERM");
|
|
28269
|
+
}
|
|
28270
|
+
}
|
|
28271
|
+
|
|
28211
28272
|
/**
|
|
28212
28273
|
* Session IDs for conversation continuity.
|
|
28213
28274
|
* Map<widgetUuid, sessionId>
|
|
@@ -28269,11 +28330,21 @@ const cliController$2 = {
|
|
|
28269
28330
|
// to — causing long reasoning loops or silent hangs. We pass only the
|
|
28270
28331
|
// caller's `systemPrompt` as context.
|
|
28271
28332
|
//
|
|
28333
|
+
// --permission-mode bypassPermissions: in an embedded in-app assistant,
|
|
28334
|
+
// the user has already opted into the configured MCP servers (they
|
|
28335
|
+
// ran `claude mcp add` themselves). Prompting for tool-use approval
|
|
28336
|
+
// on every call produces "I need permission to..." replies instead of
|
|
28337
|
+
// actual actions. Bypassing matches the user's intent — if they
|
|
28338
|
+
// didn't want the assistant to use a tool, they wouldn't have
|
|
28339
|
+
// configured it.
|
|
28340
|
+
//
|
|
28272
28341
|
// (We intentionally avoid `--bare` — it also disables keychain reads,
|
|
28273
28342
|
// which breaks OAuth login for users authenticated via `claude login`.)
|
|
28274
28343
|
const args = [
|
|
28275
28344
|
"-p",
|
|
28276
28345
|
"--disable-slash-commands",
|
|
28346
|
+
"--permission-mode",
|
|
28347
|
+
"bypassPermissions",
|
|
28277
28348
|
"--output-format",
|
|
28278
28349
|
"stream-json",
|
|
28279
28350
|
"--verbose",
|
|
@@ -28319,6 +28390,10 @@ const cliController$2 = {
|
|
|
28319
28390
|
const spawnOpts = {
|
|
28320
28391
|
env: { ...process.env, PATH: fullPath },
|
|
28321
28392
|
stdio: ["pipe", "pipe", "pipe"],
|
|
28393
|
+
// On Windows, the Claude CLI is typically installed as claude.cmd
|
|
28394
|
+
// (a batch wrapper). Node's child_process.spawn can't launch .cmd
|
|
28395
|
+
// files directly without a shell — ENOENT otherwise.
|
|
28396
|
+
shell: IS_WINDOWS,
|
|
28322
28397
|
};
|
|
28323
28398
|
if (cwd) {
|
|
28324
28399
|
const fs = require("fs");
|
|
@@ -28523,7 +28598,7 @@ const cliController$2 = {
|
|
|
28523
28598
|
abortRequest: (requestId) => {
|
|
28524
28599
|
const child = activeProcesses.get(requestId);
|
|
28525
28600
|
if (child) {
|
|
28526
|
-
child
|
|
28601
|
+
killChildTree(child);
|
|
28527
28602
|
activeProcesses.delete(requestId);
|
|
28528
28603
|
return { success: true };
|
|
28529
28604
|
}
|
|
@@ -28580,7 +28655,7 @@ const cliController$2 = {
|
|
|
28580
28655
|
// Kill any active processes for this widget
|
|
28581
28656
|
for (const [reqId, child] of activeProcesses) {
|
|
28582
28657
|
if (reqId.startsWith(widgetUuid)) {
|
|
28583
|
-
child
|
|
28658
|
+
killChildTree(child);
|
|
28584
28659
|
activeProcesses.delete(reqId);
|
|
28585
28660
|
}
|
|
28586
28661
|
}
|
|
@@ -28631,7 +28706,7 @@ const dashboardTools$1 = [
|
|
|
28631
28706
|
{
|
|
28632
28707
|
name: "create_dashboard",
|
|
28633
28708
|
description:
|
|
28634
|
-
"Create a new dashboard with the given name.
|
|
28709
|
+
"Create a new dashboard with the given name. Defaults to a 1×1 grid layout if `layout` is omitted — the resulting dashboard has a single cell ready for a widget. Pass an explicit `layout` object to use different dimensions. Pass `layout: null` only if the caller specifically wants a layout-less container dashboard (rare — widgets cannot be added without further editing). Returns the dashboard ID.",
|
|
28635
28710
|
inputSchema: {
|
|
28636
28711
|
type: "object",
|
|
28637
28712
|
properties: {
|
|
@@ -49252,6 +49327,7 @@ var jsonSchemaToZod_1 = { jsonSchemaToZod: jsonSchemaToZod$1, jsonSchemaProperty
|
|
|
49252
49327
|
|
|
49253
49328
|
const https$2 = require$$8$1;
|
|
49254
49329
|
const { randomUUID } = require$$1$5;
|
|
49330
|
+
const { BrowserWindow } = require$$0$1;
|
|
49255
49331
|
const { McpServer } = mcp;
|
|
49256
49332
|
const {
|
|
49257
49333
|
StreamableHTTPServerTransport,
|
|
@@ -49260,6 +49336,52 @@ const {
|
|
|
49260
49336
|
const settingsController$3 = settingsController_1;
|
|
49261
49337
|
const { getOrCreateCert } = tlsCert;
|
|
49262
49338
|
|
|
49339
|
+
// Tool-name prefixes that indicate a mutation. After a successful call
|
|
49340
|
+
// to any of these, the renderer is notified via "dash-mcp:state-changed"
|
|
49341
|
+
// so it can refresh the relevant UI slice (themes, dashboards, widgets,
|
|
49342
|
+
// providers, etc.) without requiring a manual reload.
|
|
49343
|
+
const MUTATING_PREFIXES = [
|
|
49344
|
+
"create_",
|
|
49345
|
+
"add_",
|
|
49346
|
+
"remove_",
|
|
49347
|
+
"delete_",
|
|
49348
|
+
"update_",
|
|
49349
|
+
"apply_",
|
|
49350
|
+
"install_",
|
|
49351
|
+
"move_",
|
|
49352
|
+
"set_",
|
|
49353
|
+
"configure_",
|
|
49354
|
+
];
|
|
49355
|
+
|
|
49356
|
+
function isMutatingTool(name) {
|
|
49357
|
+
return MUTATING_PREFIXES.some((p) => name.startsWith(p));
|
|
49358
|
+
}
|
|
49359
|
+
|
|
49360
|
+
function broadcastStateChanged(toolName, result) {
|
|
49361
|
+
// Best-effort parse of the tool's first text content block. MCP tool
|
|
49362
|
+
// results are of shape { content: [{ type: "text", text: "<json>" }] }.
|
|
49363
|
+
// Expose the parsed JSON as `result` so renderers can act on specifics
|
|
49364
|
+
// (e.g. the new dashboard ID from create_dashboard) without a round
|
|
49365
|
+
// trip back to fetch state.
|
|
49366
|
+
let parsed = null;
|
|
49367
|
+
try {
|
|
49368
|
+
const firstText = result?.content?.find?.((c) => c.type === "text")?.text;
|
|
49369
|
+
if (firstText) parsed = JSON.parse(firstText);
|
|
49370
|
+
} catch {
|
|
49371
|
+
/* leave null */
|
|
49372
|
+
}
|
|
49373
|
+
const payload = { toolName, result: parsed };
|
|
49374
|
+
for (const win of BrowserWindow.getAllWindows()) {
|
|
49375
|
+
if (!win.isDestroyed()) {
|
|
49376
|
+
try {
|
|
49377
|
+
win.webContents.send("dash-mcp:state-changed", payload);
|
|
49378
|
+
} catch {
|
|
49379
|
+
/* ignore */
|
|
49380
|
+
}
|
|
49381
|
+
}
|
|
49382
|
+
}
|
|
49383
|
+
}
|
|
49384
|
+
|
|
49263
49385
|
// --- State ---
|
|
49264
49386
|
let mcpServer = null;
|
|
49265
49387
|
let httpsServer = null;
|
|
@@ -49343,14 +49465,22 @@ const { jsonSchemaToZod } = jsonSchemaToZod_1;
|
|
|
49343
49465
|
function applyRegistrations(server) {
|
|
49344
49466
|
for (const tool of registeredTools) {
|
|
49345
49467
|
const zodSchema = jsonSchemaToZod(tool.inputSchema);
|
|
49468
|
+
// Wrap mutating tool handlers so a successful invocation broadcasts
|
|
49469
|
+
// "dash-mcp:state-changed" to all renderer windows. Read-only tools
|
|
49470
|
+
// (list_, get_, search_) are passed through unwrapped.
|
|
49471
|
+
const mutating = isMutatingTool(tool.name);
|
|
49472
|
+
const handler = mutating
|
|
49473
|
+
? async (...args) => {
|
|
49474
|
+
const result = await tool.handler(...args);
|
|
49475
|
+
if (result && !result.isError) {
|
|
49476
|
+
broadcastStateChanged(tool.name, result);
|
|
49477
|
+
}
|
|
49478
|
+
return result;
|
|
49479
|
+
}
|
|
49480
|
+
: tool.handler;
|
|
49346
49481
|
// server.tool() expects a raw Zod shape (e.g. { name: z.string() }),
|
|
49347
49482
|
// NOT a z.object() wrapper. Extract .shape from the Zod object.
|
|
49348
|
-
server.tool(
|
|
49349
|
-
tool.name,
|
|
49350
|
-
tool.description,
|
|
49351
|
-
zodSchema.shape || {},
|
|
49352
|
-
tool.handler,
|
|
49353
|
-
);
|
|
49483
|
+
server.tool(tool.name, tool.description, zodSchema.shape || {}, handler);
|
|
49354
49484
|
}
|
|
49355
49485
|
for (const resource of registeredResources) {
|
|
49356
49486
|
server.resource(
|
|
@@ -50645,7 +50775,7 @@ var schedulerController_1 = schedulerController$2;
|
|
|
50645
50775
|
(function (module) {
|
|
50646
50776
|
const fs = require$$0$2;
|
|
50647
50777
|
const path = require$$1$2;
|
|
50648
|
-
const os = require$$
|
|
50778
|
+
const os = require$$5$1;
|
|
50649
50779
|
const AdmZip = require$$3$4;
|
|
50650
50780
|
const { fileURLToPath } = require$$4$1;
|
|
50651
50781
|
const { app, ipcMain, BrowserWindow } = require$$0$1;
|
|
@@ -58871,6 +59001,17 @@ async function handleCreateDashboard$1({ name, layout }) {
|
|
|
58871
59001
|
};
|
|
58872
59002
|
}
|
|
58873
59003
|
|
|
59004
|
+
// Default to a 1×1 grid when the caller omits `layout`. A bare
|
|
59005
|
+
// container dashboard has no grid cells, so widgets can't be added
|
|
59006
|
+
// without further editing — even a single-cell grid avoids that
|
|
59007
|
+
// dead-end while staying unopinionated about layout. Callers that
|
|
59008
|
+
// want a specific size pass an explicit `layout` object. Callers
|
|
59009
|
+
// that genuinely want a layout-less container must pass
|
|
59010
|
+
// `layout: null` explicitly.
|
|
59011
|
+
if (layout === undefined) {
|
|
59012
|
+
layout = { rows: 1, cols: 1 };
|
|
59013
|
+
}
|
|
59014
|
+
|
|
58874
59015
|
// Validate optional layout parameter
|
|
58875
59016
|
if (layout !== undefined && layout !== null) {
|
|
58876
59017
|
if (typeof layout !== "object" || Array.isArray(layout)) {
|
|
@@ -74759,6 +74900,23 @@ const mcpDashServerApi$2 = {
|
|
|
74759
74900
|
* @returns {Promise<string>}
|
|
74760
74901
|
*/
|
|
74761
74902
|
getToken: () => ipcRenderer$3.invoke(MCP_DASH_SERVER_GET_TOKEN, {}),
|
|
74903
|
+
|
|
74904
|
+
/**
|
|
74905
|
+
* Subscribe to state-change notifications fired after any mutating
|
|
74906
|
+
* MCP tool call (create_*, add_*, apply_*, remove_*, update_*,
|
|
74907
|
+
* move_*, configure_*, set_*, delete_*, install_*). The callback
|
|
74908
|
+
* receives { toolName }. Use this to refresh renderer state (theme,
|
|
74909
|
+
* dashboards, widgets, providers) so MCP-driven changes are
|
|
74910
|
+
* reflected in the UI without requiring a manual reload.
|
|
74911
|
+
*
|
|
74912
|
+
* @param {(payload: { toolName: string }) => void} callback
|
|
74913
|
+
* @returns {() => void} unsubscribe function
|
|
74914
|
+
*/
|
|
74915
|
+
onStateChanged: (callback) => {
|
|
74916
|
+
const handler = (_event, payload) => callback(payload);
|
|
74917
|
+
ipcRenderer$3.on("dash-mcp:state-changed", handler);
|
|
74918
|
+
return () => ipcRenderer$3.removeListener("dash-mcp:state-changed", handler);
|
|
74919
|
+
},
|
|
74762
74920
|
};
|
|
74763
74921
|
|
|
74764
74922
|
var mcpDashServerApi_1 = mcpDashServerApi$2;
|