@trops/dash-core 0.1.489 → 0.1.491

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/index.esm.js CHANGED
@@ -1626,9 +1626,10 @@ var ElectronDashboardApi = /*#__PURE__*/function () {
1626
1626
  key: "mcpStartServer",
1627
1627
  value: function mcpStartServer(serverName, mcpConfig, credentials, onSuccess, onError) {
1628
1628
  var _this20 = this;
1629
+ var workspaceId = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : null;
1629
1630
  if (this.api !== null) {
1630
1631
  try {
1631
- this.api.mcp.startServer(serverName, mcpConfig, credentials).then(function (result) {
1632
+ this.api.mcp.startServer(serverName, mcpConfig, credentials, workspaceId).then(function (result) {
1632
1633
  onSuccess(_this20.events.MCP_START_SERVER_COMPLETE, result);
1633
1634
  })["catch"](function (error) {
1634
1635
  onError(_this20.events.MCP_START_SERVER_ERROR, error);
@@ -1647,9 +1648,10 @@ var ElectronDashboardApi = /*#__PURE__*/function () {
1647
1648
  key: "mcpStopServer",
1648
1649
  value: function mcpStopServer(serverName, onSuccess, onError) {
1649
1650
  var _this21 = this;
1651
+ var workspaceId = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
1650
1652
  if (this.api !== null) {
1651
1653
  try {
1652
- this.api.mcp.stopServer(serverName).then(function (result) {
1654
+ this.api.mcp.stopServer(serverName, workspaceId).then(function (result) {
1653
1655
  onSuccess(_this21.events.MCP_STOP_SERVER_COMPLETE, result);
1654
1656
  })["catch"](function (error) {
1655
1657
  onError(_this21.events.MCP_STOP_SERVER_ERROR, error);
@@ -1668,9 +1670,13 @@ var ElectronDashboardApi = /*#__PURE__*/function () {
1668
1670
  key: "mcpCallTool",
1669
1671
  value: function mcpCallTool(serverName, toolName, args, allowedTools, onSuccess, onError) {
1670
1672
  var _this22 = this;
1673
+ var workspaceId = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : null;
1671
1674
  if (this.api !== null) {
1672
1675
  try {
1673
- this.api.mcp.callTool(serverName, toolName, args, allowedTools).then(function (result) {
1676
+ // widgetId is not threaded here; mcpApi.callTool defaults it to
1677
+ // null. Slice 3a: workspaceId scopes the MCP server process per
1678
+ // workspace.
1679
+ this.api.mcp.callTool(serverName, toolName, args, allowedTools, null, workspaceId).then(function (result) {
1674
1680
  onSuccess(_this22.events.MCP_CALL_TOOL_COMPLETE, result);
1675
1681
  })["catch"](function (error) {
1676
1682
  onError(_this22.events.MCP_CALL_TOOL_ERROR, error);
@@ -1689,9 +1695,10 @@ var ElectronDashboardApi = /*#__PURE__*/function () {
1689
1695
  key: "mcpListTools",
1690
1696
  value: function mcpListTools(serverName, onSuccess, onError) {
1691
1697
  var _this23 = this;
1698
+ var workspaceId = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
1692
1699
  if (this.api !== null) {
1693
1700
  try {
1694
- this.api.mcp.listTools(serverName).then(function (result) {
1701
+ this.api.mcp.listTools(serverName, workspaceId).then(function (result) {
1695
1702
  onSuccess(_this23.events.MCP_LIST_TOOLS_COMPLETE, result);
1696
1703
  })["catch"](function (error) {
1697
1704
  onError(_this23.events.MCP_LIST_TOOLS_ERROR, error);
@@ -1710,9 +1717,10 @@ var ElectronDashboardApi = /*#__PURE__*/function () {
1710
1717
  key: "mcpListResources",
1711
1718
  value: function mcpListResources(serverName, onSuccess, onError) {
1712
1719
  var _this24 = this;
1720
+ var workspaceId = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
1713
1721
  if (this.api !== null) {
1714
1722
  try {
1715
- this.api.mcp.listResources(serverName).then(function (result) {
1723
+ this.api.mcp.listResources(serverName, workspaceId).then(function (result) {
1716
1724
  onSuccess(_this24.events.MCP_LIST_RESOURCES_COMPLETE, result);
1717
1725
  })["catch"](function (error) {
1718
1726
  onError(_this24.events.MCP_LIST_RESOURCES_ERROR, error);
@@ -1731,9 +1739,10 @@ var ElectronDashboardApi = /*#__PURE__*/function () {
1731
1739
  key: "mcpReadResource",
1732
1740
  value: function mcpReadResource(serverName, uri, onSuccess, onError) {
1733
1741
  var _this25 = this;
1742
+ var workspaceId = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : null;
1734
1743
  if (this.api !== null) {
1735
1744
  try {
1736
- this.api.mcp.readResource(serverName, uri).then(function (result) {
1745
+ this.api.mcp.readResource(serverName, uri, workspaceId).then(function (result) {
1737
1746
  onSuccess(_this25.events.MCP_READ_RESOURCE_COMPLETE, result);
1738
1747
  })["catch"](function (error) {
1739
1748
  onError(_this25.events.MCP_READ_RESOURCE_ERROR, error);
@@ -1752,9 +1761,10 @@ var ElectronDashboardApi = /*#__PURE__*/function () {
1752
1761
  key: "mcpGetServerStatus",
1753
1762
  value: function mcpGetServerStatus(serverName, onSuccess, onError) {
1754
1763
  var _this26 = this;
1764
+ var workspaceId = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
1755
1765
  if (this.api !== null) {
1756
1766
  try {
1757
- this.api.mcp.getServerStatus(serverName).then(function (result) {
1767
+ this.api.mcp.getServerStatus(serverName, workspaceId).then(function (result) {
1758
1768
  onSuccess(_this26.events.MCP_SERVER_STATUS_COMPLETE, result);
1759
1769
  })["catch"](function (error) {
1760
1770
  onError(_this26.events.MCP_SERVER_STATUS_ERROR, error);
@@ -29102,17 +29112,27 @@ var useWidgetProviders = function useWidgetProviders() {
29102
29112
 
29103
29113
  /**
29104
29114
  * Module-level shared state for MCP server connections.
29105
- * Prevents multiple hook instances (e.g., 4 widgets using "slack") from
29106
- * each firing their own IPC startServer call.
29115
+ * Prevents multiple hook instances (e.g., 4 widgets on the same dashboard
29116
+ * using "slack") from each firing their own IPC startServer call.
29107
29117
  *
29108
- * serverStates: tracks connection result + consumer reference count per server
29109
- * pendingConnects: deduplicates in-flight IPC calls so only 1 fires per server
29118
+ * Slice 3a: keys are scoped per `(workspaceId, serverName)` so two
29119
+ * dashboards using the same provider name don't share renderer state
29120
+ * (the main process spawns separate server instances for each).
29121
+ *
29122
+ * serverStates: tracks connection result + consumer reference count
29123
+ * pendingConnects: deduplicates in-flight IPC calls
29110
29124
  */
29111
29125
  var serverStates = new Map();
29112
- // Map<serverName, { status, tools, resources, consumerCount }>
29126
+ // Map<`${workspaceId}::${serverName}`, { status, tools, resources, consumerCount }>
29113
29127
 
29114
29128
  var pendingConnects$1 = new Map();
29115
- // Map<serverName, Promise<result>>
29129
+ // Map<`${workspaceId}::${serverName}`, Promise<result>>
29130
+
29131
+ var NO_WORKSPACE = "__no_workspace__";
29132
+ function rendererStateKey(workspaceId, serverName) {
29133
+ var wid = workspaceId && typeof workspaceId === "string" ? workspaceId : NO_WORKSPACE;
29134
+ return wid + "::" + serverName;
29135
+ }
29116
29136
 
29117
29137
  /**
29118
29138
  * useMcpProvider Hook
@@ -29281,7 +29301,8 @@ var useMcpProvider = function useMcpProvider(providerType) {
29281
29301
  * even when multiple hook instances call connect() simultaneously.
29282
29302
  */
29283
29303
  var connect = useCallback(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
29284
- var cached, statusResult, result, state, connectPromise, _result, _t2, _t3;
29304
+ var _workspace$workspaceD2;
29305
+ var workspaceId, stateKey, cached, statusResult, result, state, connectPromise, _result, _t2, _t3;
29285
29306
  return _regeneratorRuntime.wrap(function (_context) {
29286
29307
  while (1) switch (_context.prev = _context.next) {
29287
29308
  case 0:
@@ -29312,9 +29333,15 @@ var useMcpProvider = function useMcpProvider(providerType) {
29312
29333
  setError("Provider \"".concat(selectedProviderName, "\" has no MCP configuration"));
29313
29334
  return _context.abrupt("return");
29314
29335
  case 4:
29315
- // 1. Already connected at module level? Verify with main process before trusting cache.
29336
+ // Slice 3a: scope state per (workspace, provider). Two dashboards
29337
+ // using the same provider name get separate server instances in the
29338
+ // main process, so the renderer state must mirror that or one
29339
+ // dashboard's "connected" cache will short-circuit a second
29340
+ // dashboard's connect that needs its own backing process.
29341
+ workspaceId = (workspace === null || workspace === void 0 || (_workspace$workspaceD2 = workspace.workspaceData) === null || _workspace$workspaceD2 === void 0 ? void 0 : _workspace$workspaceD2.id) || null;
29342
+ stateKey = rendererStateKey(workspaceId, selectedProviderName); // 1. Already connected at module level? Verify with main process before trusting cache.
29316
29343
  // The server may have been stopped externally (e.g., Test Connection in settings).
29317
- cached = serverStates.get(selectedProviderName);
29344
+ cached = serverStates.get(stateKey);
29318
29345
  if (!(cached && cached.status === "connected")) {
29319
29346
  _context.next = 9;
29320
29347
  break;
@@ -29326,7 +29353,7 @@ var useMcpProvider = function useMcpProvider(providerType) {
29326
29353
  return resolve(result);
29327
29354
  }, function (event, err) {
29328
29355
  return reject(err);
29329
- });
29356
+ }, workspaceId);
29330
29357
  });
29331
29358
  case 6:
29332
29359
  statusResult = _context.sent;
@@ -29339,25 +29366,25 @@ var useMcpProvider = function useMcpProvider(providerType) {
29339
29366
  return _context.abrupt("return");
29340
29367
  case 7:
29341
29368
  // Server was stopped externally — clear stale cache and reconnect
29342
- serverStates["delete"](selectedProviderName);
29369
+ serverStates["delete"](stateKey);
29343
29370
  _context.next = 9;
29344
29371
  break;
29345
29372
  case 8:
29346
29373
  _context.prev = 8;
29347
29374
  _context["catch"](5);
29348
- serverStates["delete"](selectedProviderName);
29375
+ serverStates["delete"](stateKey);
29349
29376
  case 9:
29350
29377
  setIsConnecting(true);
29351
29378
  setError(null);
29352
29379
 
29353
29380
  // 2. Another hook instance already connecting? Piggyback on its promise
29354
- if (!pendingConnects$1.has(selectedProviderName)) {
29381
+ if (!pendingConnects$1.has(stateKey)) {
29355
29382
  _context.next = 17;
29356
29383
  break;
29357
29384
  }
29358
29385
  _context.prev = 10;
29359
29386
  _context.next = 11;
29360
- return pendingConnects$1.get(selectedProviderName);
29387
+ return pendingConnects$1.get(stateKey);
29361
29388
  case 11:
29362
29389
  result = _context.sent;
29363
29390
  if (mountedRef.current) {
@@ -29376,7 +29403,7 @@ var useMcpProvider = function useMcpProvider(providerType) {
29376
29403
  return _context.abrupt("return");
29377
29404
  case 13:
29378
29405
  // Increment consumer count and apply
29379
- state = serverStates.get(selectedProviderName);
29406
+ state = serverStates.get(stateKey);
29380
29407
  if (state) state.consumerCount++;
29381
29408
  applyResult(result);
29382
29409
  _context.next = 16;
@@ -29399,9 +29426,9 @@ var useMcpProvider = function useMcpProvider(providerType) {
29399
29426
  // 3. First caller — fire the IPC call and share the promise
29400
29427
  connectPromise = new Promise(function (resolve, reject) {
29401
29428
  dashApi.mcpStartServer(selectedProviderName, provider.mcpConfig, provider.credentials, function (event, result) {
29402
- pendingConnects$1["delete"](selectedProviderName);
29429
+ pendingConnects$1["delete"](stateKey);
29403
29430
  if (result.error) {
29404
- serverStates.set(selectedProviderName, {
29431
+ serverStates.set(stateKey, {
29405
29432
  status: "error",
29406
29433
  tools: [],
29407
29434
  resources: [],
@@ -29412,7 +29439,7 @@ var useMcpProvider = function useMcpProvider(providerType) {
29412
29439
  }
29413
29440
 
29414
29441
  // Store in module-level shared state
29415
- serverStates.set(selectedProviderName, {
29442
+ serverStates.set(stateKey, {
29416
29443
  status: "connected",
29417
29444
  tools: result.tools || [],
29418
29445
  resources: result.resources || [],
@@ -29420,17 +29447,17 @@ var useMcpProvider = function useMcpProvider(providerType) {
29420
29447
  });
29421
29448
  resolve(result);
29422
29449
  }, function (event, err) {
29423
- pendingConnects$1["delete"](selectedProviderName);
29424
- serverStates.set(selectedProviderName, {
29450
+ pendingConnects$1["delete"](stateKey);
29451
+ serverStates.set(stateKey, {
29425
29452
  status: "error",
29426
29453
  tools: [],
29427
29454
  resources: [],
29428
29455
  consumerCount: 0
29429
29456
  });
29430
29457
  reject(err);
29431
- });
29458
+ }, workspaceId);
29432
29459
  });
29433
- pendingConnects$1.set(selectedProviderName, connectPromise);
29460
+ pendingConnects$1.set(stateKey, connectPromise);
29434
29461
  _context.prev = 18;
29435
29462
  _context.next = 19;
29436
29463
  return connectPromise;
@@ -29471,14 +29498,15 @@ var useMcpProvider = function useMcpProvider(providerType) {
29471
29498
  return _context.stop();
29472
29499
  }
29473
29500
  }, _callee, null, [[5, 8], [10, 14], [18, 22]]);
29474
- })), [dashApi, provider, providerType, selectedProviderName, applyResult]);
29501
+ })), [dashApi, provider, providerType, selectedProviderName, applyResult, workspace]);
29475
29502
 
29476
29503
  /**
29477
29504
  * Disconnect from the MCP server.
29478
29505
  * Only sends the IPC stop call when this is the last consumer.
29479
29506
  */
29480
29507
  var disconnect = useCallback(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
29481
- var state;
29508
+ var _workspace$workspaceD3;
29509
+ var workspaceId, stateKey, state;
29482
29510
  return _regeneratorRuntime.wrap(function (_context2) {
29483
29511
  while (1) switch (_context2.prev = _context2.next) {
29484
29512
  case 0:
@@ -29488,7 +29516,9 @@ var useMcpProvider = function useMcpProvider(providerType) {
29488
29516
  }
29489
29517
  return _context2.abrupt("return");
29490
29518
  case 1:
29491
- state = serverStates.get(selectedProviderName);
29519
+ workspaceId = (workspace === null || workspace === void 0 || (_workspace$workspaceD3 = workspace.workspaceData) === null || _workspace$workspaceD3 === void 0 ? void 0 : _workspace$workspaceD3.id) || null;
29520
+ stateKey = rendererStateKey(workspaceId, selectedProviderName);
29521
+ state = serverStates.get(stateKey);
29492
29522
  if (!state) {
29493
29523
  _context2.next = 3;
29494
29524
  break;
@@ -29507,7 +29537,7 @@ var useMcpProvider = function useMcpProvider(providerType) {
29507
29537
  return _context2.abrupt("return");
29508
29538
  case 2:
29509
29539
  // Last consumer — actually stop the server
29510
- serverStates["delete"](selectedProviderName);
29540
+ serverStates["delete"](stateKey);
29511
29541
  case 3:
29512
29542
  // Clear state synchronously BEFORE the IPC call so that
29513
29543
  // a subsequent connect() won't short-circuit on stale connectedRef
@@ -29516,29 +29546,31 @@ var useMcpProvider = function useMcpProvider(providerType) {
29516
29546
  setResources([]);
29517
29547
  setStatus("disconnected");
29518
29548
  connectedRef.current = false;
29519
- pendingConnects$1["delete"](selectedProviderName);
29549
+ pendingConnects$1["delete"](stateKey);
29520
29550
  return _context2.abrupt("return", new Promise(function (resolve) {
29521
29551
  dashApi.mcpStopServer(selectedProviderName, function () {
29522
29552
  return resolve();
29523
29553
  }, function (event, err) {
29524
29554
  resolve();
29525
- });
29555
+ }, workspaceId);
29526
29556
  }));
29527
29557
  case 4:
29528
29558
  case "end":
29529
29559
  return _context2.stop();
29530
29560
  }
29531
29561
  }, _callee2);
29532
- })), [dashApi, selectedProviderName]);
29562
+ })), [dashApi, selectedProviderName, workspace]);
29533
29563
 
29534
29564
  /**
29535
29565
  * Call a tool on the MCP server
29536
29566
  */
29537
29567
  var callTool = useCallback(/*#__PURE__*/function () {
29538
29568
  var _ref3 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee3(toolName) {
29569
+ var _workspace$workspaceD4;
29539
29570
  var args,
29540
29571
  widgetRequiredTools,
29541
29572
  isRequired,
29573
+ workspaceId,
29542
29574
  _args3 = arguments;
29543
29575
  return _regeneratorRuntime.wrap(function (_context3) {
29544
29576
  while (1) switch (_context3.prev = _context3.next) {
@@ -29565,6 +29597,10 @@ var useMcpProvider = function useMcpProvider(providerType) {
29565
29597
  isRequired = widgetRequiredTools === null || widgetRequiredTools === void 0 ? void 0 : widgetRequiredTools.includes(toolName);
29566
29598
  throw new Error("Tool \"".concat(toolName, "\" is not allowed for this widget. Allowed tools: ").concat(effectiveAllowedTools.join(", ")).concat(isRequired ? ". Note: \"".concat(toolName, "\" is declared as a required tool by this widget \u2014 update the provider's allowed tools in Settings \u2192 Providers.") : ""));
29567
29599
  case 2:
29600
+ // Slice 3a: scope the MCP server process per workspace. The
29601
+ // workspace UUID is the canonical "current dashboard" identity
29602
+ // (see useNotifications, useScheduler for the same pattern).
29603
+ workspaceId = (workspace === null || workspace === void 0 || (_workspace$workspaceD4 = workspace.workspaceData) === null || _workspace$workspaceD4 === void 0 ? void 0 : _workspace$workspaceD4.id) || null;
29568
29604
  return _context3.abrupt("return", new Promise(function (resolve, reject) {
29569
29605
  var timeout = setTimeout(function () {
29570
29606
  reject(new Error("Tool call \"".concat(toolName, "\" timed out after 30s")));
@@ -29579,7 +29615,7 @@ var useMcpProvider = function useMcpProvider(providerType) {
29579
29615
  }, function (event, err) {
29580
29616
  clearTimeout(timeout);
29581
29617
  reject(new Error((err === null || err === void 0 ? void 0 : err.message) || "Failed to call MCP tool"));
29582
- });
29618
+ }, workspaceId);
29583
29619
  }));
29584
29620
  case 3:
29585
29621
  case "end":
@@ -29590,7 +29626,7 @@ var useMcpProvider = function useMcpProvider(providerType) {
29590
29626
  return function (_x) {
29591
29627
  return _ref3.apply(this, arguments);
29592
29628
  };
29593
- }(), [dashApi, selectedProviderName, effectiveAllowedTools, widgetData, providerType]);
29629
+ }(), [dashApi, selectedProviderName, effectiveAllowedTools, widgetData, providerType, workspace]);
29594
29630
 
29595
29631
  /**
29596
29632
  * Read a resource from the MCP server
@@ -29648,7 +29684,10 @@ var useMcpProvider = function useMcpProvider(providerType) {
29648
29684
 
29649
29685
  // Decrement consumer count; only stop server if last consumer
29650
29686
  if (connectedRef.current && dashApi && selectedProviderName) {
29651
- var state = serverStates.get(selectedProviderName);
29687
+ var _workspace$workspaceD5;
29688
+ var workspaceId = (workspace === null || workspace === void 0 || (_workspace$workspaceD5 = workspace.workspaceData) === null || _workspace$workspaceD5 === void 0 ? void 0 : _workspace$workspaceD5.id) || null;
29689
+ var stateKey = rendererStateKey(workspaceId, selectedProviderName);
29690
+ var state = serverStates.get(stateKey);
29652
29691
  if (state) {
29653
29692
  state.consumerCount = Math.max(0, state.consumerCount - 1);
29654
29693
  if (state.consumerCount > 0) {
@@ -29657,12 +29696,12 @@ var useMcpProvider = function useMcpProvider(providerType) {
29657
29696
  }
29658
29697
 
29659
29698
  // Last consumer — stop the server
29660
- serverStates["delete"](selectedProviderName);
29699
+ serverStates["delete"](stateKey);
29661
29700
  }
29662
- dashApi.mcpStopServer(selectedProviderName, function () {}, function () {});
29701
+ dashApi.mcpStopServer(selectedProviderName, function () {}, function () {}, workspaceId);
29663
29702
  }
29664
29703
  };
29665
- }, [dashApi, selectedProviderName]);
29704
+ }, [dashApi, selectedProviderName, workspace]);
29666
29705
  return {
29667
29706
  isConnected: isConnected,
29668
29707
  isConnecting: isConnecting,
@@ -48552,6 +48591,243 @@ var AiAssistantSection = function AiAssistantSection() {
48552
48591
  });
48553
48592
  };
48554
48593
 
48594
+ var PrivacySecuritySection = function PrivacySecuritySection() {
48595
+ var _useState = useState([]),
48596
+ _useState2 = _slicedToArray(_useState, 2),
48597
+ rows = _useState2[0],
48598
+ setRows = _useState2[1];
48599
+ var _useState3 = useState(true),
48600
+ _useState4 = _slicedToArray(_useState3, 2),
48601
+ loading = _useState4[0],
48602
+ setLoading = _useState4[1];
48603
+ var _useState5 = useState(null),
48604
+ _useState6 = _slicedToArray(_useState5, 2),
48605
+ error = _useState6[0],
48606
+ setError = _useState6[1];
48607
+ var reload = useCallback(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
48608
+ var _api$widgetMcp, api, result, _t;
48609
+ return _regeneratorRuntime.wrap(function (_context) {
48610
+ while (1) switch (_context.prev = _context.next) {
48611
+ case 0:
48612
+ setError(null);
48613
+ _context.prev = 1;
48614
+ api = typeof window !== "undefined" ? window.mainApi : null;
48615
+ if (api !== null && api !== void 0 && (_api$widgetMcp = api.widgetMcp) !== null && _api$widgetMcp !== void 0 && _api$widgetMcp.listAll) {
48616
+ _context.next = 2;
48617
+ break;
48618
+ }
48619
+ setRows([]);
48620
+ setLoading(false);
48621
+ return _context.abrupt("return");
48622
+ case 2:
48623
+ _context.next = 3;
48624
+ return api.widgetMcp.listAll();
48625
+ case 3:
48626
+ result = _context.sent;
48627
+ setRows(Array.isArray(result) ? result : []);
48628
+ _context.next = 5;
48629
+ break;
48630
+ case 4:
48631
+ _context.prev = 4;
48632
+ _t = _context["catch"](1);
48633
+ setError((_t === null || _t === void 0 ? void 0 : _t.message) || String(_t));
48634
+ case 5:
48635
+ _context.prev = 5;
48636
+ setLoading(false);
48637
+ return _context.finish(5);
48638
+ case 6:
48639
+ case "end":
48640
+ return _context.stop();
48641
+ }
48642
+ }, _callee, null, [[1, 4, 5, 6]]);
48643
+ })), []);
48644
+ useEffect(function () {
48645
+ reload();
48646
+ }, [reload]);
48647
+ var revokeWidget = /*#__PURE__*/function () {
48648
+ var _ref2 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2(widgetId) {
48649
+ var _window$mainApi, _window$mainApi$revok, _t2;
48650
+ return _regeneratorRuntime.wrap(function (_context2) {
48651
+ while (1) switch (_context2.prev = _context2.next) {
48652
+ case 0:
48653
+ _context2.prev = 0;
48654
+ _context2.next = 1;
48655
+ return (_window$mainApi = window.mainApi) === null || _window$mainApi === void 0 || (_window$mainApi = _window$mainApi.widgetMcp) === null || _window$mainApi === void 0 || (_window$mainApi$revok = _window$mainApi.revoke) === null || _window$mainApi$revok === void 0 ? void 0 : _window$mainApi$revok.call(_window$mainApi, widgetId);
48656
+ case 1:
48657
+ reload();
48658
+ _context2.next = 3;
48659
+ break;
48660
+ case 2:
48661
+ _context2.prev = 2;
48662
+ _t2 = _context2["catch"](0);
48663
+ setError((_t2 === null || _t2 === void 0 ? void 0 : _t2.message) || String(_t2));
48664
+ case 3:
48665
+ case "end":
48666
+ return _context2.stop();
48667
+ }
48668
+ }, _callee2, null, [[0, 2]]);
48669
+ }));
48670
+ return function revokeWidget(_x) {
48671
+ return _ref2.apply(this, arguments);
48672
+ };
48673
+ }();
48674
+ var revokeServer = /*#__PURE__*/function () {
48675
+ var _ref3 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee3(widgetId, serverName) {
48676
+ var _window$mainApi2, _window$mainApi2$revo, _t3;
48677
+ return _regeneratorRuntime.wrap(function (_context3) {
48678
+ while (1) switch (_context3.prev = _context3.next) {
48679
+ case 0:
48680
+ _context3.prev = 0;
48681
+ _context3.next = 1;
48682
+ return (_window$mainApi2 = window.mainApi) === null || _window$mainApi2 === void 0 || (_window$mainApi2 = _window$mainApi2.widgetMcp) === null || _window$mainApi2 === void 0 || (_window$mainApi2$revo = _window$mainApi2.revokeServer) === null || _window$mainApi2$revo === void 0 ? void 0 : _window$mainApi2$revo.call(_window$mainApi2, widgetId, serverName);
48683
+ case 1:
48684
+ reload();
48685
+ _context3.next = 3;
48686
+ break;
48687
+ case 2:
48688
+ _context3.prev = 2;
48689
+ _t3 = _context3["catch"](0);
48690
+ setError((_t3 === null || _t3 === void 0 ? void 0 : _t3.message) || String(_t3));
48691
+ case 3:
48692
+ case "end":
48693
+ return _context3.stop();
48694
+ }
48695
+ }, _callee3, null, [[0, 2]]);
48696
+ }));
48697
+ return function revokeServer(_x2, _x3) {
48698
+ return _ref3.apply(this, arguments);
48699
+ };
48700
+ }();
48701
+ if (loading) {
48702
+ return /*#__PURE__*/jsx("div", {
48703
+ className: "flex flex-col p-6",
48704
+ children: /*#__PURE__*/jsx("span", {
48705
+ className: "text-sm opacity-60",
48706
+ children: "Loading\u2026"
48707
+ })
48708
+ });
48709
+ }
48710
+ return /*#__PURE__*/jsxs("div", {
48711
+ className: "flex flex-col space-y-6 p-6",
48712
+ children: [/*#__PURE__*/jsxs("div", {
48713
+ className: "flex flex-col space-y-2",
48714
+ children: [/*#__PURE__*/jsx(SubHeading3, {
48715
+ title: "Widget MCP permissions",
48716
+ padding: false
48717
+ }), /*#__PURE__*/jsx("span", {
48718
+ className: "text-xs opacity-60",
48719
+ children: "Tools and paths each widget is allowed to call via MCP. Granted paths are visible to other widgets in the same dashboard that use the same MCP server. Revoke any time."
48720
+ })]
48721
+ }), error && /*#__PURE__*/jsx("div", {
48722
+ className: "text-xs text-red-400 bg-red-900 bg-opacity-20 border border-red-700 rounded p-3",
48723
+ children: error
48724
+ }), rows.length === 0 && /*#__PURE__*/jsx("div", {
48725
+ className: "text-sm opacity-60",
48726
+ children: "No widgets have requested MCP permissions yet."
48727
+ }), rows.map(function (_ref4) {
48728
+ var widgetId = _ref4.widgetId,
48729
+ declared = _ref4.declared,
48730
+ granted = _ref4.granted;
48731
+ return /*#__PURE__*/jsx(WidgetGrantRow, {
48732
+ widgetId: widgetId,
48733
+ declared: declared,
48734
+ granted: granted,
48735
+ onRevokeWidget: function onRevokeWidget() {
48736
+ return revokeWidget(widgetId);
48737
+ },
48738
+ onRevokeServer: function onRevokeServer(serverName) {
48739
+ return revokeServer(widgetId, serverName);
48740
+ }
48741
+ }, widgetId);
48742
+ })]
48743
+ });
48744
+ };
48745
+ var WidgetGrantRow = function WidgetGrantRow(_ref5) {
48746
+ var widgetId = _ref5.widgetId,
48747
+ declared = _ref5.declared,
48748
+ granted = _ref5.granted,
48749
+ onRevokeWidget = _ref5.onRevokeWidget,
48750
+ onRevokeServer = _ref5.onRevokeServer;
48751
+ var declaredServers = declared && declared.servers || {};
48752
+ var grantedServers = granted && granted.servers || {};
48753
+ var allServerNames = Array.from(new Set([].concat(_toConsumableArray(Object.keys(declaredServers)), _toConsumableArray(Object.keys(grantedServers)))));
48754
+ return /*#__PURE__*/jsxs("div", {
48755
+ className: "flex flex-col space-y-3 border border-gray-700 rounded p-3",
48756
+ children: [/*#__PURE__*/jsxs("div", {
48757
+ className: "flex flex-row items-center justify-between",
48758
+ children: [/*#__PURE__*/jsx("span", {
48759
+ className: "text-sm font-mono break-all",
48760
+ children: widgetId
48761
+ }), Object.keys(grantedServers).length > 0 && /*#__PURE__*/jsx(Button, {
48762
+ title: "Revoke all",
48763
+ onClick: onRevokeWidget
48764
+ })]
48765
+ }), !declared && !granted && /*#__PURE__*/jsx("span", {
48766
+ className: "text-xs opacity-50",
48767
+ children: "(no manifest, no grant \u2014 should not happen)"
48768
+ }), allServerNames.map(function (serverName) {
48769
+ var decl = declaredServers[serverName] || {};
48770
+ var grant = grantedServers[serverName];
48771
+ return /*#__PURE__*/jsxs("div", {
48772
+ className: "flex flex-col space-y-2 border-t border-gray-800 pt-2",
48773
+ children: [/*#__PURE__*/jsxs("div", {
48774
+ className: "flex flex-row items-center justify-between",
48775
+ children: [/*#__PURE__*/jsxs("span", {
48776
+ className: "text-xs uppercase tracking-wider opacity-70",
48777
+ children: [serverName, !grant && /*#__PURE__*/jsx("span", {
48778
+ className: "ml-2 text-amber-400 normal-case tracking-normal",
48779
+ children: "(declared, not granted)"
48780
+ })]
48781
+ }), grant && /*#__PURE__*/jsx(Button, {
48782
+ title: "Revoke server",
48783
+ onClick: function onClick() {
48784
+ return onRevokeServer(serverName);
48785
+ }
48786
+ })]
48787
+ }), /*#__PURE__*/jsx(PermsList, {
48788
+ label: "Tools",
48789
+ declaredItems: decl.tools || [],
48790
+ grantedItems: (grant === null || grant === void 0 ? void 0 : grant.tools) || []
48791
+ }), /*#__PURE__*/jsx(PermsList, {
48792
+ label: "Read paths",
48793
+ declaredItems: decl.readPaths || [],
48794
+ grantedItems: (grant === null || grant === void 0 ? void 0 : grant.readPaths) || []
48795
+ }), /*#__PURE__*/jsx(PermsList, {
48796
+ label: "Write paths",
48797
+ declaredItems: decl.writePaths || [],
48798
+ grantedItems: (grant === null || grant === void 0 ? void 0 : grant.writePaths) || []
48799
+ })]
48800
+ }, serverName);
48801
+ })]
48802
+ });
48803
+ };
48804
+ var PermsList = function PermsList(_ref6) {
48805
+ var label = _ref6.label,
48806
+ declaredItems = _ref6.declaredItems,
48807
+ grantedItems = _ref6.grantedItems;
48808
+ if (declaredItems.length === 0 && grantedItems.length === 0) return null;
48809
+ var grantedSet = new Set(grantedItems);
48810
+ var declaredSet = new Set(declaredItems);
48811
+ var all = Array.from(new Set([].concat(_toConsumableArray(declaredItems), _toConsumableArray(grantedItems))));
48812
+ return /*#__PURE__*/jsxs("div", {
48813
+ className: "flex flex-col space-y-1",
48814
+ children: [/*#__PURE__*/jsx("span", {
48815
+ className: "text-xs opacity-50",
48816
+ children: label
48817
+ }), all.map(function (item) {
48818
+ var isGranted = grantedSet.has(item);
48819
+ var isDeclared = declaredSet.has(item);
48820
+ return /*#__PURE__*/jsxs("span", {
48821
+ className: "text-xs font-mono break-all ".concat(isGranted ? "opacity-100" : isDeclared ? "opacity-50 line-through" : "opacity-100 text-amber-400"),
48822
+ children: [item, !isDeclared && isGranted && /*#__PURE__*/jsx("span", {
48823
+ className: "ml-2 opacity-60",
48824
+ children: "(no longer declared)"
48825
+ })]
48826
+ }, item);
48827
+ })]
48828
+ });
48829
+ };
48830
+
48555
48831
  var SECTIONS = [{
48556
48832
  key: "general",
48557
48833
  label: "General",
@@ -48592,6 +48868,10 @@ var SECTIONS = [{
48592
48868
  key: "ai-assistant",
48593
48869
  label: "AI Assistant",
48594
48870
  icon: "wand-magic-sparkles"
48871
+ }, {
48872
+ key: "privacy-security",
48873
+ label: "Privacy & Security",
48874
+ icon: "shield-halved"
48595
48875
  }];
48596
48876
  var AppSettingsModal = function AppSettingsModal(_ref) {
48597
48877
  var isOpen = _ref.isOpen,
@@ -48779,6 +49059,9 @@ var AppSettingsModal = function AppSettingsModal(_ref) {
48779
49059
  }), activeSection === "ai-assistant" && /*#__PURE__*/jsx("div", {
48780
49060
  className: "flex-1 overflow-y-auto p-6 ".concat(panelStyles.textColor || "text-gray-200"),
48781
49061
  children: /*#__PURE__*/jsx(AiAssistantSection, {})
49062
+ }), activeSection === "privacy-security" && /*#__PURE__*/jsx("div", {
49063
+ className: "flex-1 overflow-y-auto ".concat(panelStyles.textColor || "text-gray-200"),
49064
+ children: /*#__PURE__*/jsx(PrivacySecuritySection, {})
48782
49065
  })]
48783
49066
  }), /*#__PURE__*/jsx(SettingsModal.Footer, {
48784
49067
  children: /*#__PURE__*/jsx("div", {