@trops/dash-core 0.1.383 → 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.
@@ -28330,11 +28330,21 @@ const cliController$2 = {
28330
28330
  // to — causing long reasoning loops or silent hangs. We pass only the
28331
28331
  // caller's `systemPrompt` as context.
28332
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
+ //
28333
28341
  // (We intentionally avoid `--bare` — it also disables keychain reads,
28334
28342
  // which breaks OAuth login for users authenticated via `claude login`.)
28335
28343
  const args = [
28336
28344
  "-p",
28337
28345
  "--disable-slash-commands",
28346
+ "--permission-mode",
28347
+ "bypassPermissions",
28338
28348
  "--output-format",
28339
28349
  "stream-json",
28340
28350
  "--verbose",
@@ -28696,7 +28706,7 @@ const dashboardTools$1 = [
28696
28706
  {
28697
28707
  name: "create_dashboard",
28698
28708
  description:
28699
- "Create a new dashboard with the given name. Optionally provide a layout to create a grid dashboard. Returns the dashboard ID. After creating, use search_widgets or list_widgets to find widgets, then add_widget to populate the dashboard.",
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.",
28700
28710
  inputSchema: {
28701
28711
  type: "object",
28702
28712
  properties: {
@@ -49317,6 +49327,7 @@ var jsonSchemaToZod_1 = { jsonSchemaToZod: jsonSchemaToZod$1, jsonSchemaProperty
49317
49327
 
49318
49328
  const https$2 = require$$8$1;
49319
49329
  const { randomUUID } = require$$1$5;
49330
+ const { BrowserWindow } = require$$0$1;
49320
49331
  const { McpServer } = mcp;
49321
49332
  const {
49322
49333
  StreamableHTTPServerTransport,
@@ -49325,6 +49336,52 @@ const {
49325
49336
  const settingsController$3 = settingsController_1;
49326
49337
  const { getOrCreateCert } = tlsCert;
49327
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
+
49328
49385
  // --- State ---
49329
49386
  let mcpServer = null;
49330
49387
  let httpsServer = null;
@@ -49408,14 +49465,22 @@ const { jsonSchemaToZod } = jsonSchemaToZod_1;
49408
49465
  function applyRegistrations(server) {
49409
49466
  for (const tool of registeredTools) {
49410
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;
49411
49481
  // server.tool() expects a raw Zod shape (e.g. { name: z.string() }),
49412
49482
  // NOT a z.object() wrapper. Extract .shape from the Zod object.
49413
- server.tool(
49414
- tool.name,
49415
- tool.description,
49416
- zodSchema.shape || {},
49417
- tool.handler,
49418
- );
49483
+ server.tool(tool.name, tool.description, zodSchema.shape || {}, handler);
49419
49484
  }
49420
49485
  for (const resource of registeredResources) {
49421
49486
  server.resource(
@@ -58936,6 +59001,17 @@ async function handleCreateDashboard$1({ name, layout }) {
58936
59001
  };
58937
59002
  }
58938
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
+
58939
59015
  // Validate optional layout parameter
58940
59016
  if (layout !== undefined && layout !== null) {
58941
59017
  if (typeof layout !== "object" || Array.isArray(layout)) {
@@ -74824,6 +74900,23 @@ const mcpDashServerApi$2 = {
74824
74900
  * @returns {Promise<string>}
74825
74901
  */
74826
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
+ },
74827
74920
  };
74828
74921
 
74829
74922
  var mcpDashServerApi_1 = mcpDashServerApi$2;