@trops/dash-core 0.1.533 → 0.1.534

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.
@@ -1642,7 +1642,7 @@ var themeController_1 = themeController$5;
1642
1642
  */
1643
1643
 
1644
1644
  const path$j = require$$1$1;
1645
- const fs$f = require$$0$2;
1645
+ const fs$g = require$$0$2;
1646
1646
  const { app: app$c } = require$$0$1;
1647
1647
 
1648
1648
  const APP_NAME = "Dashboard";
@@ -1691,8 +1691,8 @@ function readDataDirectoryFromSettings() {
1691
1691
  APP_NAME,
1692
1692
  "settings.json",
1693
1693
  );
1694
- if (!fs$f.existsSync(settingsPath)) return undefined;
1695
- const raw = fs$f.readFileSync(settingsPath, "utf8");
1694
+ if (!fs$g.existsSync(settingsPath)) return undefined;
1695
+ const raw = fs$g.readFileSync(settingsPath, "utf8");
1696
1696
  const settings = JSON.parse(raw);
1697
1697
  const dir = settings && settings.dataDirectory;
1698
1698
  if (typeof dir === "string" && dir) return dir;
@@ -1725,10 +1725,10 @@ function safePath$3(requested, allowedRoots) {
1725
1725
  // parent chain can't trick us.
1726
1726
  let real = resolved;
1727
1727
  try {
1728
- real = fs$f.realpathSync(resolved);
1728
+ real = fs$g.realpathSync(resolved);
1729
1729
  } catch (_e) {
1730
1730
  try {
1731
- const parent = fs$f.realpathSync(path$j.dirname(resolved));
1731
+ const parent = fs$g.realpathSync(path$j.dirname(resolved));
1732
1732
  real = path$j.join(parent, path$j.basename(resolved));
1733
1733
  } catch (_e2) {
1734
1734
  // Parent doesn't exist either. Use the resolved-but-not-
@@ -1741,7 +1741,7 @@ function safePath$3(requested, allowedRoots) {
1741
1741
  for (const root of allowedRoots) {
1742
1742
  let realRoot = root;
1743
1743
  try {
1744
- if (fs$f.existsSync(root)) realRoot = fs$f.realpathSync(root);
1744
+ if (fs$g.existsSync(root)) realRoot = fs$g.realpathSync(root);
1745
1745
  } catch (_e) {
1746
1746
  // root doesn't exist or isn't reachable — keep as-is for
1747
1747
  // the comparison below
@@ -1809,7 +1809,7 @@ var safePath_1 = {
1809
1809
  * clearCache() → void // test-only
1810
1810
  */
1811
1811
 
1812
- const fs$e = require$$0$2;
1812
+ const fs$f = require$$0$2;
1813
1813
  const path$i = require$$1$1;
1814
1814
  const { app: app$b } = require$$0$1;
1815
1815
 
@@ -1825,9 +1825,9 @@ function grantsFilePath() {
1825
1825
 
1826
1826
  function loadFromDisk() {
1827
1827
  const p = grantsFilePath();
1828
- if (!fs$e.existsSync(p)) return {};
1828
+ if (!fs$f.existsSync(p)) return {};
1829
1829
  try {
1830
- const raw = fs$e.readFileSync(p, "utf8");
1830
+ const raw = fs$f.readFileSync(p, "utf8");
1831
1831
  const parsed = JSON.parse(raw);
1832
1832
  if (!parsed || typeof parsed !== "object") return {};
1833
1833
  return parsed;
@@ -1847,9 +1847,9 @@ function writeToDisk(data) {
1847
1847
  const tmp = p + ".tmp";
1848
1848
  // Ensure parent dir exists (userData should already, but be defensive
1849
1849
  // for first-launch / freshly-cleared profile cases).
1850
- fs$e.mkdirSync(path$i.dirname(p), { recursive: true });
1851
- fs$e.writeFileSync(tmp, JSON.stringify(data, null, 2), "utf8");
1852
- fs$e.renameSync(tmp, p);
1850
+ fs$f.mkdirSync(path$i.dirname(p), { recursive: true });
1851
+ fs$f.writeFileSync(tmp, JSON.stringify(data, null, 2), "utf8");
1852
+ fs$f.renameSync(tmp, p);
1853
1853
  }
1854
1854
 
1855
1855
  // Recognized origins for a persisted grant.
@@ -2481,7 +2481,7 @@ function commonjsRequire(path) {
2481
2481
  * Runs in the Electron main process at widget install time.
2482
2482
  */
2483
2483
 
2484
- const fs$d = require$$0$2;
2484
+ const fs$e = require$$0$2;
2485
2485
  const path$h = require$$1$1;
2486
2486
 
2487
2487
  /**
@@ -2535,7 +2535,7 @@ function getEsbuildDiagnostics() {
2535
2535
  ? path$h.join(archDir, "esbuild.exe")
2536
2536
  : path$h.join(archDir, "bin", "esbuild");
2537
2537
  diagnostics.nativeBinaryPath = candidate;
2538
- diagnostics.nativeBinaryExists = fs$d.existsSync(candidate);
2538
+ diagnostics.nativeBinaryExists = fs$e.existsSync(candidate);
2539
2539
  } catch (err) {
2540
2540
  diagnostics.archResolveError = err.message;
2541
2541
  }
@@ -2582,25 +2582,25 @@ async function healthCheck() {
2582
2582
  */
2583
2583
  function findWidgetsDir$2(widgetPath) {
2584
2584
  const direct = path$h.join(widgetPath, "widgets");
2585
- if (fs$d.existsSync(direct)) {
2585
+ if (fs$e.existsSync(direct)) {
2586
2586
  return direct;
2587
2587
  }
2588
2588
 
2589
2589
  // Check configs/widgets/ (packageZip.js nests .dash.js files here)
2590
2590
  const configsWidgets = path$h.join(widgetPath, "configs", "widgets");
2591
- if (fs$d.existsSync(configsWidgets)) {
2591
+ if (fs$e.existsSync(configsWidgets)) {
2592
2592
  return configsWidgets;
2593
2593
  }
2594
2594
 
2595
2595
  // Check configs/ directory (used by packageZip.js for distributed widgets)
2596
2596
  const configs = path$h.join(widgetPath, "configs");
2597
- if (fs$d.existsSync(configs)) {
2597
+ if (fs$e.existsSync(configs)) {
2598
2598
  return configs;
2599
2599
  }
2600
2600
 
2601
2601
  // Check one level deeper for nested ZIP extraction
2602
2602
  try {
2603
- const entries = fs$d.readdirSync(widgetPath, { withFileTypes: true });
2603
+ const entries = fs$e.readdirSync(widgetPath, { withFileTypes: true });
2604
2604
  const subdirs = entries.filter(
2605
2605
  (e) =>
2606
2606
  e.isDirectory() &&
@@ -2611,7 +2611,7 @@ function findWidgetsDir$2(widgetPath) {
2611
2611
 
2612
2612
  for (const subdir of subdirs) {
2613
2613
  const nested = path$h.join(widgetPath, subdir.name, "widgets");
2614
- if (fs$d.existsSync(nested)) {
2614
+ if (fs$e.existsSync(nested)) {
2615
2615
  console.log(`[WidgetCompiler] Found nested widgets/ at ${nested}`);
2616
2616
  return nested;
2617
2617
  }
@@ -2645,7 +2645,7 @@ async function compileWidget$1(widgetPath) {
2645
2645
  }
2646
2646
 
2647
2647
  // Discover .dash.js config files
2648
- const files = fs$d.readdirSync(widgetsDir);
2648
+ const files = fs$e.readdirSync(widgetsDir);
2649
2649
  const dashFiles = files.filter((f) => f.endsWith(".dash.js"));
2650
2650
 
2651
2651
  if (dashFiles.length === 0) {
@@ -2667,7 +2667,7 @@ async function compileWidget$1(widgetPath) {
2667
2667
  const componentName = dashFile.replace(".dash.js", "");
2668
2668
  const componentFile = `${componentName}.js`;
2669
2669
  const componentFilePath = path$h.join(widgetsDir, componentFile);
2670
- const hasComponent = fs$d.existsSync(componentFilePath);
2670
+ const hasComponent = fs$e.existsSync(componentFilePath);
2671
2671
 
2672
2672
  // Import the config (always)
2673
2673
  imports.push(
@@ -2705,11 +2705,11 @@ async function compileWidget$1(widgetPath) {
2705
2705
 
2706
2706
  try {
2707
2707
  // Ensure dist/ directory exists
2708
- if (!fs$d.existsSync(distDir)) {
2709
- fs$d.mkdirSync(distDir, { recursive: true });
2708
+ if (!fs$e.existsSync(distDir)) {
2709
+ fs$e.mkdirSync(distDir, { recursive: true });
2710
2710
  }
2711
2711
 
2712
- fs$d.writeFileSync(entryPath, entryContent, "utf8");
2712
+ fs$e.writeFileSync(entryPath, entryContent, "utf8");
2713
2713
 
2714
2714
  console.log(
2715
2715
  `[WidgetCompiler] Compiling ${dashFiles.length} component(s) from ${widgetPath}`,
@@ -2765,8 +2765,8 @@ async function compileWidget$1(widgetPath) {
2765
2765
  } finally {
2766
2766
  // Clean up temporary entry file
2767
2767
  try {
2768
- if (fs$d.existsSync(entryPath)) {
2769
- fs$d.unlinkSync(entryPath);
2768
+ if (fs$e.existsSync(entryPath)) {
2769
+ fs$e.unlinkSync(entryPath);
2770
2770
  }
2771
2771
  } catch (cleanupError) {
2772
2772
  // Non-fatal
@@ -2798,7 +2798,7 @@ var widgetCompiler$1 = {
2798
2798
  * Integrates with ComponentManager for automatic registration
2799
2799
  */
2800
2800
 
2801
- const fs$c = require$$0$2;
2801
+ const fs$d = require$$0$2;
2802
2802
  const path$g = require$$1$1;
2803
2803
  const vm = require$$2;
2804
2804
  const { findWidgetsDir: findWidgetsDir$1 } = widgetCompiler$1;
@@ -2891,10 +2891,10 @@ class DynamicWidgetLoader {
2891
2891
  const componentPath = path$g.join(widgetsDir, `${componentName}.js`);
2892
2892
  const configPath = path$g.join(widgetsDir, `${componentName}.dash.js`);
2893
2893
 
2894
- if (!fs$c.existsSync(componentPath)) {
2894
+ if (!fs$d.existsSync(componentPath)) {
2895
2895
  throw new Error(`Component file not found: ${componentPath}`);
2896
2896
  }
2897
- if (!fs$c.existsSync(configPath)) {
2897
+ if (!fs$d.existsSync(configPath)) {
2898
2898
  throw new Error(`Config file not found: ${configPath}`);
2899
2899
  }
2900
2900
 
@@ -2945,7 +2945,7 @@ class DynamicWidgetLoader {
2945
2945
  */
2946
2946
  async loadConfigFile(configPath) {
2947
2947
  try {
2948
- const source = fs$c.readFileSync(configPath, "utf8");
2948
+ const source = fs$d.readFileSync(configPath, "utf8");
2949
2949
 
2950
2950
  let exportMatch = source.match(/export\s+default\s+({[\s\S]*});?\s*$/);
2951
2951
 
@@ -3013,7 +3013,7 @@ class DynamicWidgetLoader {
3013
3013
  return [];
3014
3014
  }
3015
3015
 
3016
- const files = fs$c.readdirSync(widgetsDir);
3016
+ const files = fs$d.readdirSync(widgetsDir);
3017
3017
  const widgets = new Set();
3018
3018
 
3019
3019
  files.forEach((file) => {
@@ -3499,7 +3499,7 @@ var registryAuthController$2 = {
3499
3499
  * Test-only. Drops the in-process cache so tests can re-read.
3500
3500
  */
3501
3501
 
3502
- const fs$b = require$$0$2;
3502
+ const fs$c = require$$0$2;
3503
3503
  const path$f = require$$1$1;
3504
3504
  const os$2 = require$$2$1;
3505
3505
  const { app: app$a } = require$$0$1;
@@ -3599,12 +3599,12 @@ function resolveWidgetPackagePath(widgetId) {
3599
3599
  function getWidgetMcpPermissions$1(widgetId) {
3600
3600
  if (_cache.has(widgetId)) return _cache.get(widgetId);
3601
3601
  const pkgPath = resolveWidgetPackagePath(widgetId);
3602
- if (!pkgPath || !fs$b.existsSync(pkgPath)) {
3602
+ if (!pkgPath || !fs$c.existsSync(pkgPath)) {
3603
3603
  _cache.set(widgetId, null);
3604
3604
  return null;
3605
3605
  }
3606
3606
  try {
3607
- const raw = fs$b.readFileSync(pkgPath, "utf8");
3607
+ const raw = fs$c.readFileSync(pkgPath, "utf8");
3608
3608
  const pkg = JSON.parse(raw);
3609
3609
  const perms = parseManifestPermissions(pkg);
3610
3610
  _cache.set(widgetId, perms);
@@ -3654,7 +3654,7 @@ var widgetPermissions = {
3654
3654
  * (Slices 1-3) is the actual boundary.
3655
3655
  */
3656
3656
 
3657
- const fs$a = require$$0$2;
3657
+ const fs$b = require$$0$2;
3658
3658
  const path$e = require$$1$1;
3659
3659
 
3660
3660
  const SOURCE_EXTENSIONS = new Set([
@@ -3708,7 +3708,7 @@ function readSourceFiles(dir) {
3708
3708
  function walk(current, relBase) {
3709
3709
  let entries;
3710
3710
  try {
3711
- entries = fs$a.readdirSync(current, { withFileTypes: true });
3711
+ entries = fs$b.readdirSync(current, { withFileTypes: true });
3712
3712
  } catch {
3713
3713
  return;
3714
3714
  }
@@ -3725,7 +3725,7 @@ function readSourceFiles(dir) {
3725
3725
  try {
3726
3726
  result.push({
3727
3727
  relPath: rel,
3728
- source: fs$a.readFileSync(abs, "utf8"),
3728
+ source: fs$b.readFileSync(abs, "utf8"),
3729
3729
  });
3730
3730
  } catch {
3731
3731
  // unreadable — skip
@@ -7623,7 +7623,7 @@ function requireTransform () {
7623
7623
  }
7624
7624
 
7625
7625
  const { app: app$9 } = require$$0$1;
7626
- var fs$9 = require$$0$2;
7626
+ var fs$a = require$$0$2;
7627
7627
  const path$d = require$$1$1;
7628
7628
  const events$5 = events$8;
7629
7629
  const { getFileContents: getFileContents$5, writeToFile: writeToFile$2 } = file;
@@ -7646,8 +7646,8 @@ function _loadFlags$1() {
7646
7646
  appName$5,
7647
7647
  "settings.json",
7648
7648
  );
7649
- if (!fs$9.existsSync(settingsPath)) return null;
7650
- return JSON.parse(fs$9.readFileSync(settingsPath, "utf8"));
7649
+ if (!fs$a.existsSync(settingsPath)) return null;
7650
+ return JSON.parse(fs$a.readFileSync(settingsPath, "utf8"));
7651
7651
  } catch (_e) {
7652
7652
  return null;
7653
7653
  }
@@ -7904,7 +7904,7 @@ const dataController$1 = {
7904
7904
  // intent, plus realpath/symlink protection.
7905
7905
  const resolvedFilepath = safePath$2(toFilepath, getAllowedRoots$1("data"));
7906
7906
 
7907
- const writeStream = fs$9.createWriteStream(resolvedFilepath);
7907
+ const writeStream = fs$a.createWriteStream(resolvedFilepath);
7908
7908
 
7909
7909
  https$3
7910
7910
  .get(url, (resp) => {
@@ -8280,7 +8280,7 @@ var dataController_1 = dataController$1;
8280
8280
 
8281
8281
  const { app: app$8 } = require$$0$1;
8282
8282
  const path$c = require$$1$1;
8283
- const fs$8 = require$$0$2;
8283
+ const fs$9 = require$$0$2;
8284
8284
  const { getFileContents: getFileContents$4, writeToFile: writeToFile$1 } = file;
8285
8285
 
8286
8286
  const configFilename$3 = "settings.json";
@@ -8288,15 +8288,15 @@ const appName$4 = "Dashboard";
8288
8288
 
8289
8289
  // Helper function to recursively copy directory
8290
8290
  function copyDirectory(source, destination) {
8291
- if (!fs$8.existsSync(destination)) {
8292
- fs$8.mkdirSync(destination, { recursive: true });
8291
+ if (!fs$9.existsSync(destination)) {
8292
+ fs$9.mkdirSync(destination, { recursive: true });
8293
8293
  }
8294
8294
 
8295
- const files = fs$8.readdirSync(source);
8295
+ const files = fs$9.readdirSync(source);
8296
8296
  for (const file of files) {
8297
8297
  const srcPath = path$c.join(source, file);
8298
8298
  const destPath = path$c.join(destination, file);
8299
- const stat = fs$8.lstatSync(srcPath);
8299
+ const stat = fs$9.lstatSync(srcPath);
8300
8300
 
8301
8301
  // Skip symlinks to prevent following links to sensitive files
8302
8302
  if (stat.isSymbolicLink()) {
@@ -8307,7 +8307,7 @@ function copyDirectory(source, destination) {
8307
8307
  if (stat.isDirectory()) {
8308
8308
  copyDirectory(srcPath, destPath);
8309
8309
  } else {
8310
- fs$8.copyFileSync(srcPath, destPath);
8310
+ fs$9.copyFileSync(srcPath, destPath);
8311
8311
  }
8312
8312
  }
8313
8313
  }
@@ -8425,11 +8425,11 @@ const settingsController$4 = {
8425
8425
  setDataDirectory: (win, newPath) => {
8426
8426
  try {
8427
8427
  // Validate the path exists and is a directory
8428
- if (!fs$8.existsSync(newPath)) {
8429
- fs$8.mkdirSync(newPath, { recursive: true });
8428
+ if (!fs$9.existsSync(newPath)) {
8429
+ fs$9.mkdirSync(newPath, { recursive: true });
8430
8430
  }
8431
8431
 
8432
- const stats = fs$8.statSync(newPath);
8432
+ const stats = fs$9.statSync(newPath);
8433
8433
  if (!stats.isDirectory()) {
8434
8434
  throw new Error("Path is not a directory");
8435
8435
  }
@@ -8506,12 +8506,12 @@ const settingsController$4 = {
8506
8506
  }
8507
8507
 
8508
8508
  // Validate paths
8509
- if (!fs$8.existsSync(resolvedOldPath)) {
8509
+ if (!fs$9.existsSync(resolvedOldPath)) {
8510
8510
  throw new Error("Source directory does not exist");
8511
8511
  }
8512
8512
 
8513
- if (!fs$8.existsSync(resolvedNewPath)) {
8514
- fs$8.mkdirSync(resolvedNewPath, { recursive: true });
8513
+ if (!fs$9.existsSync(resolvedNewPath)) {
8514
+ fs$9.mkdirSync(resolvedNewPath, { recursive: true });
8515
8515
  }
8516
8516
 
8517
8517
  // Copy files
@@ -26946,7 +26946,7 @@ const {
26946
26946
  StreamableHTTPClientTransport,
26947
26947
  } = streamableHttp$1;
26948
26948
  const path$a = require$$1$1;
26949
- const fs$7 = require$$0$2;
26949
+ const fs$8 = require$$0$2;
26950
26950
  const os$1 = require$$2$1;
26951
26951
  const responseCache$2 = responseCache_1;
26952
26952
  const { gateToolCall, gateToolCallWithJit } = permissionGate;
@@ -26967,8 +26967,8 @@ function loadSettingsForFlags() {
26967
26967
  "Dashboard",
26968
26968
  "settings.json",
26969
26969
  );
26970
- if (!fs$7.existsSync(settingsPath)) return null;
26971
- const raw = fs$7.readFileSync(settingsPath, "utf8");
26970
+ if (!fs$8.existsSync(settingsPath)) return null;
26971
+ const raw = fs$8.readFileSync(settingsPath, "utf8");
26972
26972
  return JSON.parse(raw);
26973
26973
  } catch (_e) {
26974
26974
  return null;
@@ -27135,7 +27135,7 @@ function getShellPath$1() {
27135
27135
  fallbackDirs.push(`${home}/.nodenv/shims`);
27136
27136
  try {
27137
27137
  const nvmDir = `${home}/.nvm/versions/node`;
27138
- const versions = fs$7.readdirSync(nvmDir).sort();
27138
+ const versions = fs$8.readdirSync(nvmDir).sort();
27139
27139
  if (versions.length > 0) {
27140
27140
  // Find the highest compatible version (v18/v20/v22)
27141
27141
  for (let i = versions.length - 1; i >= 0; i--) {
@@ -27271,15 +27271,15 @@ async function refreshGoogleOAuthToken(tokenRefresh) {
27271
27271
  const credPath = tokenRefresh.credentialsPath.replace(/^~/, home);
27272
27272
  const keysPath = tokenRefresh.oauthKeysPath.replace(/^~/, home);
27273
27273
 
27274
- if (!fs$7.existsSync(credPath) || !fs$7.existsSync(keysPath)) {
27274
+ if (!fs$8.existsSync(credPath) || !fs$8.existsSync(keysPath)) {
27275
27275
  console.log(
27276
27276
  "[mcpController] Token refresh skipped: credential files not found",
27277
27277
  );
27278
27278
  return;
27279
27279
  }
27280
27280
 
27281
- const credentials = JSON.parse(fs$7.readFileSync(credPath, "utf8"));
27282
- const keysFile = JSON.parse(fs$7.readFileSync(keysPath, "utf8"));
27281
+ const credentials = JSON.parse(fs$8.readFileSync(credPath, "utf8"));
27282
+ const keysFile = JSON.parse(fs$8.readFileSync(keysPath, "utf8"));
27283
27283
  const keyData = keysFile.installed || keysFile.web;
27284
27284
 
27285
27285
  if (
@@ -27348,7 +27348,7 @@ async function refreshGoogleOAuthToken(tokenRefresh) {
27348
27348
  credentials.refresh_token = body.refresh_token;
27349
27349
  }
27350
27350
 
27351
- fs$7.writeFileSync(credPath, JSON.stringify(credentials, null, 2));
27351
+ fs$8.writeFileSync(credPath, JSON.stringify(credentials, null, 2));
27352
27352
  console.log("[mcpController] Google OAuth token refreshed successfully");
27353
27353
  }
27354
27354
 
@@ -27998,13 +27998,13 @@ const mcpController$3 = {
27998
27998
  "mcpServerCatalog.json",
27999
27999
  );
28000
28000
 
28001
- if (!fs$7.existsSync(catalogPath)) {
28001
+ if (!fs$8.existsSync(catalogPath)) {
28002
28002
  return {
28003
28003
  catalog: [],
28004
28004
  };
28005
28005
  }
28006
28006
 
28007
- const catalogData = fs$7.readFileSync(catalogPath, "utf8");
28007
+ const catalogData = fs$8.readFileSync(catalogPath, "utf8");
28008
28008
  const catalog = JSON.parse(catalogData);
28009
28009
 
28010
28010
  return {
@@ -28039,11 +28039,11 @@ const mcpController$3 = {
28039
28039
  "knownExternalMcpServers.json",
28040
28040
  );
28041
28041
 
28042
- if (!fs$7.existsSync(catalogPath)) {
28042
+ if (!fs$8.existsSync(catalogPath)) {
28043
28043
  return { success: true, servers: [] };
28044
28044
  }
28045
28045
 
28046
- const catalogData = fs$7.readFileSync(catalogPath, "utf8");
28046
+ const catalogData = fs$8.readFileSync(catalogPath, "utf8");
28047
28047
  const catalog = JSON.parse(catalogData);
28048
28048
 
28049
28049
  return {
@@ -28108,8 +28108,8 @@ const mcpController$3 = {
28108
28108
  const destPath = to.replace(/^~/, os$1.homedir());
28109
28109
  const destDir = require$$1$1.dirname(destPath);
28110
28110
  try {
28111
- fs$7.mkdirSync(destDir, { recursive: true });
28112
- fs$7.copyFileSync(sourcePath, destPath);
28111
+ fs$8.mkdirSync(destDir, { recursive: true });
28112
+ fs$8.copyFileSync(sourcePath, destPath);
28113
28113
  } catch (err) {
28114
28114
  return {
28115
28115
  error: true,
@@ -28278,7 +28278,7 @@ var mcpControllerExports = mcpController$4.exports;
28278
28278
  */
28279
28279
 
28280
28280
  const path$9 = require$$1$1;
28281
- const fs$6 = require$$0$2;
28281
+ const fs$7 = require$$0$2;
28282
28282
  const os = require$$2$1;
28283
28283
  const { toPackageId } = packageId;
28284
28284
  const { getStoredToken: getStoredToken$3 } = registryAuthController$2;
@@ -28354,12 +28354,12 @@ async function fetchRegistryIndex(forceRefresh = false) {
28354
28354
  if (isDev()) {
28355
28355
  // In dev mode, try local test file first
28356
28356
  const testPath = getTestRegistryPath();
28357
- if (fs$6.existsSync(testPath)) {
28357
+ if (fs$7.existsSync(testPath)) {
28358
28358
  console.log(
28359
28359
  "[RegistryController] Loading test registry from:",
28360
28360
  testPath,
28361
28361
  );
28362
- const raw = fs$6.readFileSync(testPath, "utf8");
28362
+ const raw = fs$7.readFileSync(testPath, "utf8");
28363
28363
  indexData = JSON.parse(raw);
28364
28364
  } else {
28365
28365
  // Fall back to API (supports DASH_REGISTRY_URL as full-URL override)
@@ -28786,8 +28786,8 @@ async function fetchPackageSource(packageName, componentName = null) {
28786
28786
  let configCode = "";
28787
28787
  let widgetName = null;
28788
28788
 
28789
- if (fs$6.existsSync(widgetsDir)) {
28790
- const files = fs$6.readdirSync(widgetsDir);
28789
+ if (fs$7.existsSync(widgetsDir)) {
28790
+ const files = fs$7.readdirSync(widgetsDir);
28791
28791
  const dashFiles = files.filter((f) => f.endsWith(".dash.js"));
28792
28792
  const componentFiles = files.filter(
28793
28793
  (f) => f.endsWith(".js") && !f.endsWith(".dash.js") && f !== "index.js",
@@ -28809,7 +28809,7 @@ async function fetchPackageSource(packageName, componentName = null) {
28809
28809
  if (!configFile) configFile = dashFiles[0];
28810
28810
 
28811
28811
  if (configFile) {
28812
- configCode = fs$6.readFileSync(path$9.join(widgetsDir, configFile), "utf8");
28812
+ configCode = fs$7.readFileSync(path$9.join(widgetsDir, configFile), "utf8");
28813
28813
  widgetName = configFile.replace(/\.dash\.js$/, "");
28814
28814
  }
28815
28815
 
@@ -28823,7 +28823,7 @@ async function fetchPackageSource(packageName, componentName = null) {
28823
28823
  if (!componentFile) componentFile = componentFiles[0];
28824
28824
 
28825
28825
  if (componentFile) {
28826
- componentCode = fs$6.readFileSync(
28826
+ componentCode = fs$7.readFileSync(
28827
28827
  path$9.join(widgetsDir, componentFile),
28828
28828
  "utf8",
28829
28829
  );
@@ -28833,15 +28833,15 @@ async function fetchPackageSource(packageName, componentName = null) {
28833
28833
 
28834
28834
  let bundleSource = null;
28835
28835
  const bundlePath = path$9.join(tempDir, "dist", "index.cjs.js");
28836
- if (fs$6.existsSync(bundlePath)) {
28837
- bundleSource = fs$6.readFileSync(bundlePath, "utf8");
28836
+ if (fs$7.existsSync(bundlePath)) {
28837
+ bundleSource = fs$7.readFileSync(bundlePath, "utf8");
28838
28838
  }
28839
28839
 
28840
28840
  let dashMeta = {};
28841
28841
  const dashPath = path$9.join(tempDir, "dash.json");
28842
- if (fs$6.existsSync(dashPath)) {
28842
+ if (fs$7.existsSync(dashPath)) {
28843
28843
  try {
28844
- dashMeta = JSON.parse(fs$6.readFileSync(dashPath, "utf8"));
28844
+ dashMeta = JSON.parse(fs$7.readFileSync(dashPath, "utf8"));
28845
28845
  } catch {
28846
28846
  // Ignore — metadata is optional for preview
28847
28847
  }
@@ -28860,7 +28860,7 @@ async function fetchPackageSource(packageName, componentName = null) {
28860
28860
  };
28861
28861
  } finally {
28862
28862
  try {
28863
- fs$6.rmSync(tempDir, { recursive: true, force: true });
28863
+ fs$7.rmSync(tempDir, { recursive: true, force: true });
28864
28864
  } catch (err) {
28865
28865
  console.warn(
28866
28866
  `[RegistryController] Failed to clean up preview temp dir ${tempDir}:`,
@@ -28880,7 +28880,7 @@ var registryController$3 = {
28880
28880
  fetchPackageSource,
28881
28881
  };
28882
28882
 
28883
- var fs$5 = require$$0$2;
28883
+ var fs$6 = require$$0$2;
28884
28884
  var JSONStream = require$$4$1;
28885
28885
  const algoliasearch$1 = require$$2$3;
28886
28886
  const path$8 = require$$3$3;
@@ -28921,7 +28921,7 @@ let AlgoliaIndex$1 = class AlgoliaIndex {
28921
28921
  var batchNumber = 1;
28922
28922
 
28923
28923
  // create the readStream to parse the large file (json)
28924
- var readStream = fs$5.createReadStream(filepath).pipe(parser);
28924
+ var readStream = fs$6.createReadStream(filepath).pipe(parser);
28925
28925
 
28926
28926
  var batch = [];
28927
28927
 
@@ -28935,7 +28935,7 @@ let AlgoliaIndex$1 = class AlgoliaIndex {
28935
28935
  // lets write to the batch file
28936
28936
  if (countForBatch === batchSize) {
28937
28937
  // write to the batch file
28938
- var writeStream = fs$5.createWriteStream(
28938
+ var writeStream = fs$6.createWriteStream(
28939
28939
  batchFilepath + "/batch_" + batchNumber + ".json",
28940
28940
  );
28941
28941
  writeStream.write(JSON.stringify(batch));
@@ -28986,11 +28986,11 @@ let AlgoliaIndex$1 = class AlgoliaIndex {
28986
28986
  return new Promise((resolve, reject) => {
28987
28987
  try {
28988
28988
  checkDirectory(directoryPath);
28989
- fs$5.readdir(directoryPath, (err, files) => {
28989
+ fs$6.readdir(directoryPath, (err, files) => {
28990
28990
  if (err) reject(err);
28991
28991
  if (files) {
28992
28992
  files.forEach((file) => {
28993
- fs$5.unlinkSync(path$8.join(directoryPath, file));
28993
+ fs$6.unlinkSync(path$8.join(directoryPath, file));
28994
28994
  });
28995
28995
  resolve();
28996
28996
  }
@@ -29009,7 +29009,7 @@ let AlgoliaIndex$1 = class AlgoliaIndex {
29009
29009
  ) {
29010
29010
  try {
29011
29011
  // read the directory...
29012
- const files = await fs$5.readdirSync(batchFilepath);
29012
+ const files = await fs$6.readdirSync(batchFilepath);
29013
29013
  let results = [];
29014
29014
  for (const fileIndex in files) {
29015
29015
  // for each file lets read the file and then push to algolia
@@ -29038,7 +29038,7 @@ let AlgoliaIndex$1 = class AlgoliaIndex {
29038
29038
 
29039
29039
  async readFile(filepath) {
29040
29040
  return await new Promise((resolve, reject) => {
29041
- fs$5.readFile(filepath, "utf8", (err, data) => {
29041
+ fs$6.readFile(filepath, "utf8", (err, data) => {
29042
29042
  if (err) {
29043
29043
  reject(err);
29044
29044
  }
@@ -29188,7 +29188,7 @@ var algolia = AlgoliaIndex$1;
29188
29188
  const algoliasearch = require$$2$3;
29189
29189
  const events$3 = events$8;
29190
29190
  const AlgoliaIndex = algolia;
29191
- var fs$4 = require$$0$2;
29191
+ var fs$5 = require$$0$2;
29192
29192
  const { safePath, getAllowedRoots } = safePath_1;
29193
29193
 
29194
29194
  const algoliaController$1 = {
@@ -29297,7 +29297,7 @@ const algoliaController$1 = {
29297
29297
  // init the Algolia Index helper
29298
29298
  const a = new AlgoliaIndex(appId, apiKey, indexName);
29299
29299
  // create the write stream to store the hits
29300
- const writeStream = fs$4.createWriteStream(toFilename);
29300
+ const writeStream = fs$5.createWriteStream(toFilename);
29301
29301
  writeStream.write("[");
29302
29302
 
29303
29303
  let sep = "";
@@ -49390,7 +49390,7 @@ streamableHttp.StreamableHTTPServerTransport = StreamableHTTPServerTransport$1;
49390
49390
  * https.createServer({ key, cert }, handler);
49391
49391
  */
49392
49392
 
49393
- const fs$3 = require$$0$2;
49393
+ const fs$4 = require$$0$2;
49394
49394
  const path$6 = require$$1$1;
49395
49395
  const forge = require$$2$4;
49396
49396
 
@@ -49404,10 +49404,10 @@ function getOrCreateCert$1(certsDir) {
49404
49404
  const keyPath = path$6.join(certsDir, "key.pem");
49405
49405
 
49406
49406
  // Return existing cert if valid
49407
- if (fs$3.existsSync(certPath) && fs$3.existsSync(keyPath)) {
49407
+ if (fs$4.existsSync(certPath) && fs$4.existsSync(keyPath)) {
49408
49408
  try {
49409
- const cert = fs$3.readFileSync(certPath, "utf8");
49410
- const key = fs$3.readFileSync(keyPath, "utf8");
49409
+ const cert = fs$4.readFileSync(certPath, "utf8");
49410
+ const key = fs$4.readFileSync(keyPath, "utf8");
49411
49411
  // Verify cert is not expired
49412
49412
  const parsed = forge.pki.certificateFromPem(cert);
49413
49413
  if (parsed.validity.notAfter > new Date()) {
@@ -49473,9 +49473,9 @@ function getOrCreateCert$1(certsDir) {
49473
49473
  const keyPem = forge.pki.privateKeyToPem(keys.privateKey);
49474
49474
 
49475
49475
  // Write to disk
49476
- fs$3.mkdirSync(certsDir, { recursive: true });
49477
- fs$3.writeFileSync(certPath, certPem, { mode: 0o644 });
49478
- fs$3.writeFileSync(keyPath, keyPem, { mode: 0o600 });
49476
+ fs$4.mkdirSync(certsDir, { recursive: true });
49477
+ fs$4.writeFileSync(certPath, certPem, { mode: 0o644 });
49478
+ fs$4.writeFileSync(keyPath, keyPem, { mode: 0o600 });
49479
49479
 
49480
49480
  console.log(`[tlsCert] Certificate saved to ${certsDir}`);
49481
49481
 
@@ -56904,6 +56904,74 @@ var dashboardConfigValidator$1 = {
56904
56904
  CURRENT_SCHEMA_VERSION: CURRENT_SCHEMA_VERSION$1,
56905
56905
  };
56906
56906
 
56907
+ /**
56908
+ * aggregateWidgetPermissions
56909
+ *
56910
+ * Pure helper that unions every widget's `dash.permissions.mcp` block
56911
+ * into a single dashboard-level summary. Each input entry carries
56912
+ * `{ packageId, version, permissions }`; this function ignores
56913
+ * packageId / version (they belong on the per-widget entry in the
56914
+ * manifest) and just produces the merged `{ server: { tools, readPaths,
56915
+ * writePaths } }` shape suitable for top-level display.
56916
+ *
56917
+ * The aggregate is a UX convenience for "what does this dashboard
56918
+ * need overall?" The authoritative source remains the per-widget
56919
+ * permissions block embedded next to each widget dependency in the
56920
+ * registry manifest — those carry their pinned version, so installers
56921
+ * can be sure the disclosure matches what they're about to fetch.
56922
+ */
56923
+
56924
+ var aggregateWidgetPermissions_1;
56925
+ var hasRequiredAggregateWidgetPermissions;
56926
+
56927
+ function requireAggregateWidgetPermissions () {
56928
+ if (hasRequiredAggregateWidgetPermissions) return aggregateWidgetPermissions_1;
56929
+ hasRequiredAggregateWidgetPermissions = 1;
56930
+
56931
+ function aggregateWidgetPermissions(entries) {
56932
+ const out = {};
56933
+ if (!Array.isArray(entries)) return out;
56934
+ for (const entry of entries) {
56935
+ if (!entry || typeof entry !== "object") continue;
56936
+ const perms = entry.permissions;
56937
+ if (!perms || typeof perms !== "object") continue;
56938
+ for (const [serverName, raw] of Object.entries(perms)) {
56939
+ if (!raw || typeof raw !== "object") continue;
56940
+ if (!out[serverName]) {
56941
+ out[serverName] = { tools: [], readPaths: [], writePaths: [] };
56942
+ }
56943
+ mergeStringArray(out[serverName], "tools", raw.tools);
56944
+ mergeStringArray(out[serverName], "readPaths", raw.readPaths);
56945
+ mergeStringArray(out[serverName], "writePaths", raw.writePaths);
56946
+ }
56947
+ }
56948
+ // Drop empty arrays from the output to keep the manifest small.
56949
+ for (const serverName of Object.keys(out)) {
56950
+ const block = out[serverName];
56951
+ if (block.tools.length === 0) delete block.tools;
56952
+ if (block.readPaths.length === 0) delete block.readPaths;
56953
+ if (block.writePaths.length === 0) delete block.writePaths;
56954
+ // If the server has no content at all, drop the server entry too.
56955
+ if (Object.keys(block).length === 0) delete out[serverName];
56956
+ }
56957
+ // Re-add `tools: []` for tests that expect the field to exist.
56958
+ // (Handled implicitly by mergeStringArray; just leaves out empty.)
56959
+ return out;
56960
+ }
56961
+
56962
+ function mergeStringArray(target, key, source) {
56963
+ if (!Array.isArray(source)) return;
56964
+ const set = new Set(target[key]);
56965
+ for (const item of source) {
56966
+ if (typeof item === "string" && item) set.add(item);
56967
+ }
56968
+ target[key] = Array.from(set);
56969
+ }
56970
+
56971
+ aggregateWidgetPermissions_1 = { aggregateWidgetPermissions };
56972
+ return aggregateWidgetPermissions_1;
56973
+ }
56974
+
56907
56975
  /**
56908
56976
  * dashboardConfigUtils.js
56909
56977
  *
@@ -57479,7 +57547,16 @@ function generateRegistryManifest(dashboardConfig, options = {}) {
57479
57547
  const scopedPackageId = remappedScope
57480
57548
  ? `@${remappedScope.replace(/^@/, "")}/${bareName}`
57481
57549
  : bareName;
57482
- return {
57550
+ // Slice 13c: pair each widget dependency with its
57551
+ // `dash.permissions.mcp` block, sourced from the publisher's
57552
+ // local install at publish time. The block stays paired with
57553
+ // the pinned version next to it (`version` field above) so
57554
+ // installers can verify "the permissions disclosure was
57555
+ // computed against the version we're about to fetch."
57556
+ const permEntry = (options.widgetPermissions || []).find(
57557
+ (p) => p && p.packageId === scopedPackageId,
57558
+ );
57559
+ const out = {
57483
57560
  id: w.id,
57484
57561
  scope: remappedScope,
57485
57562
  packageName: bareName,
@@ -57495,11 +57572,28 @@ function generateRegistryManifest(dashboardConfig, options = {}) {
57495
57572
  required: w.required !== false,
57496
57573
  author: w.author || "",
57497
57574
  };
57575
+ if (permEntry && permEntry.permissions) {
57576
+ out.permissions = permEntry.permissions;
57577
+ }
57578
+ return out;
57498
57579
  }),
57499
57580
  providers: dashboardConfig.providers || [],
57500
57581
  eventWiring: dashboardConfig.eventWiring || [],
57501
57582
  };
57502
57583
 
57584
+ // Slice 13c: top-level aggregated permissions for fast UI summary.
57585
+ // The per-widget permissions on `manifest.widgets[i].permissions`
57586
+ // remain the authoritative version-pinned source.
57587
+ if (Array.isArray(options.widgetPermissions)) {
57588
+ const {
57589
+ aggregateWidgetPermissions,
57590
+ } = requireAggregateWidgetPermissions();
57591
+ const aggregated = aggregateWidgetPermissions(options.widgetPermissions);
57592
+ if (Object.keys(aggregated).length > 0) {
57593
+ manifest.permissions = aggregated;
57594
+ }
57595
+ }
57596
+
57503
57597
  if (options.appOrigin || dashboardConfig.appOrigin) {
57504
57598
  manifest.appOrigin = options.appOrigin || dashboardConfig.appOrigin;
57505
57599
  }
@@ -58135,7 +58229,7 @@ var dashboardConfigUtils$1 = {
58135
58229
  * Handles publishing packages and generating registry URLs.
58136
58230
  */
58137
58231
 
58138
- const fs$2 = require$$0$2;
58232
+ const fs$3 = require$$0$2;
58139
58233
  const path$5 = require$$1$1;
58140
58234
  const { getStoredToken: getStoredToken$2 } = registryAuthController$2;
58141
58235
 
@@ -58162,7 +58256,7 @@ async function publishToRegistry$1(zipPath, manifest) {
58162
58256
 
58163
58257
  try {
58164
58258
  // Read the ZIP file
58165
- const zipBuffer = fs$2.readFileSync(zipPath);
58259
+ const zipBuffer = fs$3.readFileSync(zipPath);
58166
58260
 
58167
58261
  // Create FormData with the ZIP and manifest
58168
58262
  const formData = new FormData();
@@ -58372,7 +58466,7 @@ function requireWidgetPublishManifest () {
58372
58466
  })),
58373
58467
  }));
58374
58468
 
58375
- return {
58469
+ const manifest = {
58376
58470
  scope,
58377
58471
  name,
58378
58472
  displayName: options.displayName || packageJson.displayName || name,
@@ -58393,6 +58487,48 @@ function requireWidgetPublishManifest () {
58393
58487
  appOrigin: options.appOrigin || "",
58394
58488
  publishedAt: new Date().toISOString(),
58395
58489
  };
58490
+
58491
+ // Slice 13c: forward `dash.permissions.mcp` from package.json into
58492
+ // the registry manifest so installers can show "what tools does
58493
+ // this widget need" before downloading. The block is computed by
58494
+ // the install/publish/boot scanner pipeline (slice 13a/13b) and
58495
+ // sanitized here on the way out.
58496
+ const sanitizedPermissions = sanitizePermissionsBlock(
58497
+ packageJson?.dash?.permissions?.mcp,
58498
+ );
58499
+ if (sanitizedPermissions) manifest.permissions = sanitizedPermissions;
58500
+
58501
+ return manifest;
58502
+ }
58503
+
58504
+ /**
58505
+ * Defensive sanitizer — keeps the published manifest safe even if a
58506
+ * widget's package.json has a malformed permissions block. Drops
58507
+ * non-object server values and filters tools/readPaths/writePaths
58508
+ * down to non-empty strings. Returns null if the block has no
58509
+ * surviving content (caller omits the field entirely).
58510
+ */
58511
+ function sanitizePermissionsBlock(raw) {
58512
+ if (!raw || typeof raw !== "object") return null;
58513
+ const out = {};
58514
+ for (const [serverName, value] of Object.entries(raw)) {
58515
+ if (!value || typeof value !== "object") continue;
58516
+ const block = {};
58517
+ if (Array.isArray(value.tools)) {
58518
+ const tools = value.tools.filter((t) => typeof t === "string" && t);
58519
+ if (tools.length > 0) block.tools = tools;
58520
+ }
58521
+ if (Array.isArray(value.readPaths)) {
58522
+ const r = value.readPaths.filter((p) => typeof p === "string" && p);
58523
+ if (r.length > 0) block.readPaths = r;
58524
+ }
58525
+ if (Array.isArray(value.writePaths)) {
58526
+ const w = value.writePaths.filter((p) => typeof p === "string" && p);
58527
+ if (w.length > 0) block.writePaths = w;
58528
+ }
58529
+ if (Object.keys(block).length > 0) out[serverName] = block;
58530
+ }
58531
+ return Object.keys(out).length > 0 ? out : null;
58396
58532
  }
58397
58533
 
58398
58534
  widgetPublishManifest = {
@@ -60806,6 +60942,81 @@ async function prepareDashboardForPublish$1(
60806
60942
  registryCheckFailed = true;
60807
60943
  }
60808
60944
 
60945
+ // Slice 13c: collect each widget's local `dash.permissions.mcp`
60946
+ // block and pair it with the version on disk. This array becomes
60947
+ // the source-of-truth for both the per-widget `permissions` field
60948
+ // on each manifest.widgets[] entry AND the top-level aggregated
60949
+ // `manifest.permissions` block. Includes third-party widgets too
60950
+ // — every dashboard dependency lives under widgets/ on the
60951
+ // publisher's machine, scanner pipeline (slice 13a/b) keeps each
60952
+ // package.json's permissions block fresh.
60953
+ const widgetPermissions = [];
60954
+ const installedWidgets = widgetRegistry
60955
+ ? widgetRegistry.getWidgets() || []
60956
+ : [];
60957
+ const unpinnedDeps = [];
60958
+ for (const w of dashboardConfig.widgets || []) {
60959
+ const remappedScope =
60960
+ resolvedCallerScope && w.scope && w.scope !== resolvedCallerScope
60961
+ ? resolvedCallerScope
60962
+ : w.scope || "";
60963
+ const bareName = (w.packageName || w.package || "").replace(
60964
+ /^@[^/]+\//,
60965
+ "",
60966
+ );
60967
+ const scopedPackageId = remappedScope
60968
+ ? `@${String(remappedScope).replace(/^@/, "")}/${bareName}`
60969
+ : bareName;
60970
+ // Version-pin guard: refuse to publish a dashboard whose widget
60971
+ // dep has no concrete version. Otherwise the permissions block
60972
+ // we ship would be computed against one version while installers
60973
+ // resolve `*` to potentially-newer versions with a different
60974
+ // tool surface.
60975
+ if (!w.version || w.version === "*") {
60976
+ unpinnedDeps.push(scopedPackageId);
60977
+ continue;
60978
+ }
60979
+ // Find the installed copy by trying a few aliases — registry
60980
+ // entries are usually `@scope/name`, but local conventions
60981
+ // sometimes elide the @.
60982
+ const match = installedWidgets.find((iw) => {
60983
+ if (!iw) return false;
60984
+ const candidates = new Set();
60985
+ if (iw.packageId) candidates.add(iw.packageId);
60986
+ if (iw.name) candidates.add(iw.name);
60987
+ return (
60988
+ candidates.has(scopedPackageId) ||
60989
+ candidates.has(`${remappedScope}/${bareName}`) ||
60990
+ candidates.has(bareName)
60991
+ );
60992
+ });
60993
+ if (!match || !match.path) continue;
60994
+ const pkgJsonPath = path$3.join(match.path, "package.json");
60995
+ if (!fs.existsSync(pkgJsonPath)) continue;
60996
+ try {
60997
+ const pkg = JSON.parse(fs.readFileSync(pkgJsonPath, "utf8"));
60998
+ const perms = pkg?.dash?.permissions?.mcp;
60999
+ if (perms && typeof perms === "object") {
61000
+ widgetPermissions.push({
61001
+ packageId: scopedPackageId,
61002
+ version: w.version,
61003
+ permissions: perms,
61004
+ });
61005
+ }
61006
+ } catch (e) {
61007
+ console.warn(
61008
+ `[DashboardConfigController] Could not read permissions from ${pkgJsonPath}:`,
61009
+ e.message,
61010
+ );
61011
+ }
61012
+ }
61013
+ if (unpinnedDeps.length > 0) {
61014
+ return {
61015
+ success: false,
61016
+ error: `Cannot publish dashboard with unpinned widget versions: ${unpinnedDeps.join(", ")}. Reinstall these widgets from the registry to lock their versions before publishing.`,
61017
+ };
61018
+ }
61019
+
60809
61020
  // 8. Generate registry manifest — pass callerScope so local-only
60810
61021
  // scopes (e.g. `@ai-built/…`) get rewritten to the publisher's
60811
61022
  // actual registry scope on the way out.
@@ -60817,6 +61028,7 @@ async function prepareDashboardForPublish$1(
60817
61028
  appOrigin: appId,
60818
61029
  visibility: options.visibility || "public",
60819
61030
  version: nextVersion,
61031
+ widgetPermissions,
60820
61032
  });
60821
61033
 
60822
61034
  // 9. Show save dialog for the publish package
@@ -61381,7 +61593,7 @@ var notificationController_1 = notificationController$2;
61381
61593
  */
61382
61594
 
61383
61595
  const { app: app$2 } = require$$0$1;
61384
- const fs$1 = require$$0$2;
61596
+ const fs$2 = require$$0$2;
61385
61597
  const path$2 = require$$1$1;
61386
61598
  const WebSocket = require$$3$4;
61387
61599
  const {
@@ -61397,8 +61609,8 @@ function _loadFlags() {
61397
61609
  "Dashboard",
61398
61610
  "settings.json",
61399
61611
  );
61400
- if (!fs$1.existsSync(settingsPath)) return null;
61401
- return JSON.parse(fs$1.readFileSync(settingsPath, "utf8"));
61612
+ if (!fs$2.existsSync(settingsPath)) return null;
61613
+ return JSON.parse(fs$2.readFileSync(settingsPath, "utf8"));
61402
61614
  } catch (_e) {
61403
61615
  return null;
61404
61616
  }
@@ -63022,7 +63234,7 @@ var dashboardRatingsController = {
63022
63234
  * - Batch-publish from the dashboard publish dialog
63023
63235
  */
63024
63236
 
63025
- const fs = require$$0$2;
63237
+ const fs$1 = require$$0$2;
63026
63238
  const path = require$$1$1;
63027
63239
  const AdmZip = require$$3$1;
63028
63240
  const { app } = require$$0$1;
@@ -63125,17 +63337,17 @@ function cleanupProvidersInWidgetPackage(widgetPath) {
63125
63337
  try {
63126
63338
  const widgetsDir =
63127
63339
  findWidgetsDir(widgetPath) || path.join(widgetPath, "widgets");
63128
- if (!fs.existsSync(widgetsDir)) return summary;
63129
- for (const file of fs.readdirSync(widgetsDir)) {
63340
+ if (!fs$1.existsSync(widgetsDir)) return summary;
63341
+ for (const file of fs$1.readdirSync(widgetsDir)) {
63130
63342
  if (!file.endsWith(".dash.js")) continue;
63131
63343
  const filePath = path.join(widgetsDir, file);
63132
63344
  try {
63133
- const original = fs.readFileSync(filePath, "utf8");
63345
+ const original = fs$1.readFileSync(filePath, "utf8");
63134
63346
  summary.filesScanned++;
63135
63347
  const { source: deduped, dropped } =
63136
63348
  dedupProvidersInDashSource(original);
63137
63349
  if (dropped > 0 && deduped !== original) {
63138
- fs.writeFileSync(filePath, deduped, "utf8");
63350
+ fs$1.writeFileSync(filePath, deduped, "utf8");
63139
63351
  summary.filesRewritten++;
63140
63352
  summary.totalDropped += dropped;
63141
63353
  console.log(
@@ -63167,8 +63379,8 @@ async function scanWidgetConfigs(widgetPath) {
63167
63379
  try {
63168
63380
  const widgetsDir =
63169
63381
  findWidgetsDir(widgetPath) || path.join(widgetPath, "widgets");
63170
- if (!fs.existsSync(widgetsDir)) return [];
63171
- const files = fs.readdirSync(widgetsDir);
63382
+ if (!fs$1.existsSync(widgetsDir)) return [];
63383
+ const files = fs$1.readdirSync(widgetsDir);
63172
63384
  const configs = [];
63173
63385
  for (const file of files) {
63174
63386
  if (!file.endsWith(".dash.js")) continue;
@@ -63275,7 +63487,7 @@ function serializeDashConfig(config) {
63275
63487
  */
63276
63488
  async function stageOverrides(srcDir, dstDir, overrides) {
63277
63489
  // Copy the whole package tree into dstDir.
63278
- fs.cpSync(srcDir, dstDir, {
63490
+ fs$1.cpSync(srcDir, dstDir, {
63279
63491
  recursive: true,
63280
63492
  filter: (src) => {
63281
63493
  const base = path.basename(src);
@@ -63288,10 +63500,10 @@ async function stageOverrides(srcDir, dstDir, overrides) {
63288
63500
  if (!overrides || Object.keys(overrides).length === 0) return [];
63289
63501
 
63290
63502
  const widgetsDir = findWidgetsDir(dstDir) || path.join(dstDir, "widgets");
63291
- if (!fs.existsSync(widgetsDir)) return [];
63503
+ if (!fs$1.existsSync(widgetsDir)) return [];
63292
63504
 
63293
63505
  const rewritten = [];
63294
- const files = fs.readdirSync(widgetsDir);
63506
+ const files = fs$1.readdirSync(widgetsDir);
63295
63507
  for (const file of files) {
63296
63508
  if (!file.endsWith(".dash.js")) continue;
63297
63509
  const filePath = path.join(widgetsDir, file);
@@ -63327,7 +63539,7 @@ async function stageOverrides(srcDir, dstDir, overrides) {
63327
63539
  }
63328
63540
  if (!changed) continue;
63329
63541
 
63330
- fs.writeFileSync(filePath, serializeDashConfig(cfg));
63542
+ fs$1.writeFileSync(filePath, serializeDashConfig(cfg));
63331
63543
  rewritten.push(file);
63332
63544
  }
63333
63545
  return rewritten;
@@ -63395,7 +63607,7 @@ function scanForPersonalPaths(packagePath) {
63395
63607
  if (findings.length >= MAX_FINDINGS) return;
63396
63608
  let entries;
63397
63609
  try {
63398
- entries = fs.readdirSync(absDir, { withFileTypes: true });
63610
+ entries = fs$1.readdirSync(absDir, { withFileTypes: true });
63399
63611
  } catch {
63400
63612
  return;
63401
63613
  }
@@ -63414,9 +63626,9 @@ function scanForPersonalPaths(packagePath) {
63414
63626
  if (!SCANNABLE_EXTS.has(ext)) continue;
63415
63627
  let content;
63416
63628
  try {
63417
- const stat = fs.statSync(abs);
63629
+ const stat = fs$1.statSync(abs);
63418
63630
  if (stat.size > MAX_FILE_SIZE) continue;
63419
- content = fs.readFileSync(abs, "utf8");
63631
+ content = fs$1.readFileSync(abs, "utf8");
63420
63632
  } catch {
63421
63633
  continue;
63422
63634
  }
@@ -63448,7 +63660,7 @@ function scanForPersonalPaths(packagePath) {
63448
63660
  * Recursively add a directory to a ZIP, skipping excluded dirs + dotfiles.
63449
63661
  */
63450
63662
  function addDirToZip(zip, absDir, relDir = "") {
63451
- const entries = fs.readdirSync(absDir, { withFileTypes: true });
63663
+ const entries = fs$1.readdirSync(absDir, { withFileTypes: true });
63452
63664
  for (const entry of entries) {
63453
63665
  if (ZIP_EXCLUDE_DIRS.has(entry.name)) continue;
63454
63666
  if (entry.name.startsWith(".")) continue;
@@ -63458,7 +63670,7 @@ function addDirToZip(zip, absDir, relDir = "") {
63458
63670
  addDirToZip(zip, abs, rel);
63459
63671
  } else if (entry.isFile()) {
63460
63672
  try {
63461
- zip.addFile(rel, fs.readFileSync(abs));
63673
+ zip.addFile(rel, fs$1.readFileSync(abs));
63462
63674
  } catch (err) {
63463
63675
  console.warn(`[widgetRegistry] skip ${rel}: ${err.message}`);
63464
63676
  }
@@ -63519,12 +63731,12 @@ async function prepareWidgetForPublish$1(appId, packageId, options = {}) {
63519
63731
  const pkgJsonPath = path.join(widget.path, "package.json");
63520
63732
  const dashJsonPath = path.join(widget.path, "dash.json");
63521
63733
  let pkgJson;
63522
- if (fs.existsSync(pkgJsonPath)) {
63523
- pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, "utf8"));
63524
- } else if (fs.existsSync(dashJsonPath)) {
63734
+ if (fs$1.existsSync(pkgJsonPath)) {
63735
+ pkgJson = JSON.parse(fs$1.readFileSync(pkgJsonPath, "utf8"));
63736
+ } else if (fs$1.existsSync(dashJsonPath)) {
63525
63737
  // Registry-installed widgets only have dash.json — synthesize
63526
63738
  // the fields the publish flow needs from it.
63527
- const dashJson = JSON.parse(fs.readFileSync(dashJsonPath, "utf8"));
63739
+ const dashJson = JSON.parse(fs$1.readFileSync(dashJsonPath, "utf8"));
63528
63740
  pkgJson = {
63529
63741
  name: dashJson.name ? `@${callerScope}/${dashJson.name}` : packageId,
63530
63742
  version: dashJson.version || "1.0.0",
@@ -63558,8 +63770,8 @@ async function prepareWidgetForPublish$1(appId, packageId, options = {}) {
63558
63770
  if (merged) {
63559
63771
  // Re-read pkgJson so subsequent steps in this function see the
63560
63772
  // updated manifest (the version bump below uses pkgJson too).
63561
- if (fs.existsSync(pkgJsonPath)) {
63562
- pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, "utf8"));
63773
+ if (fs$1.existsSync(pkgJsonPath)) {
63774
+ pkgJson = JSON.parse(fs$1.readFileSync(pkgJsonPath, "utf8"));
63563
63775
  }
63564
63776
  }
63565
63777
  } catch (e) {
@@ -63593,12 +63805,12 @@ async function prepareWidgetForPublish$1(appId, packageId, options = {}) {
63593
63805
  if (newVersion !== previousVersion) {
63594
63806
  pkgJson.version = newVersion;
63595
63807
  // Persist to whichever metadata file exists
63596
- if (fs.existsSync(pkgJsonPath)) {
63597
- fs.writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 2) + "\n");
63598
- } else if (fs.existsSync(dashJsonPath)) {
63599
- const dashJson = JSON.parse(fs.readFileSync(dashJsonPath, "utf8"));
63808
+ if (fs$1.existsSync(pkgJsonPath)) {
63809
+ fs$1.writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 2) + "\n");
63810
+ } else if (fs$1.existsSync(dashJsonPath)) {
63811
+ const dashJson = JSON.parse(fs$1.readFileSync(dashJsonPath, "utf8"));
63600
63812
  dashJson.version = newVersion;
63601
- fs.writeFileSync(
63813
+ fs$1.writeFileSync(
63602
63814
  dashJsonPath,
63603
63815
  JSON.stringify(dashJson, null, 2) + "\n",
63604
63816
  );
@@ -63618,14 +63830,14 @@ async function prepareWidgetForPublish$1(appId, packageId, options = {}) {
63618
63830
  profile?.displayName ||
63619
63831
  profile?.username ||
63620
63832
  "";
63621
- if (authorOverride && fs.existsSync(dashJsonPath)) {
63833
+ if (authorOverride && fs$1.existsSync(dashJsonPath)) {
63622
63834
  try {
63623
- const dashJson = JSON.parse(fs.readFileSync(dashJsonPath, "utf8"));
63835
+ const dashJson = JSON.parse(fs$1.readFileSync(dashJsonPath, "utf8"));
63624
63836
  const current = (dashJson.author || "").trim();
63625
63837
  const isPlaceholder = !current || current === "AI Assistant";
63626
63838
  if (isPlaceholder && dashJson.author !== authorOverride) {
63627
63839
  dashJson.author = authorOverride;
63628
- fs.writeFileSync(
63840
+ fs$1.writeFileSync(
63629
63841
  dashJsonPath,
63630
63842
  JSON.stringify(dashJson, null, 2) + "\n",
63631
63843
  );
@@ -63695,7 +63907,7 @@ async function prepareWidgetForPublish$1(appId, packageId, options = {}) {
63695
63907
  typeof options.defaultsOverride === "object" &&
63696
63908
  Object.keys(options.defaultsOverride).length > 0;
63697
63909
  const stagedDir = hasOverrides
63698
- ? fs.mkdtempSync(path.join(app.getPath("temp"), `dash-publish-stage-`))
63910
+ ? fs$1.mkdtempSync(path.join(app.getPath("temp"), `dash-publish-stage-`))
63699
63911
  : null;
63700
63912
  let registryResult;
63701
63913
  try {
@@ -63738,7 +63950,7 @@ async function prepareWidgetForPublish$1(appId, packageId, options = {}) {
63738
63950
  if (newVersion !== previousVersion) {
63739
63951
  try {
63740
63952
  pkgJson.version = previousVersion;
63741
- fs.writeFileSync(
63953
+ fs$1.writeFileSync(
63742
63954
  pkgJsonPath,
63743
63955
  JSON.stringify(pkgJson, null, 2) + "\n",
63744
63956
  );
@@ -63756,14 +63968,14 @@ async function prepareWidgetForPublish$1(appId, packageId, options = {}) {
63756
63968
 
63757
63969
  // Clean up the temp zip on success.
63758
63970
  try {
63759
- fs.unlinkSync(zipPath);
63971
+ fs$1.unlinkSync(zipPath);
63760
63972
  } catch {
63761
63973
  /* ignore */
63762
63974
  }
63763
63975
  } finally {
63764
63976
  if (stagedDir) {
63765
63977
  try {
63766
- fs.rmSync(stagedDir, { recursive: true, force: true });
63978
+ fs$1.rmSync(stagedDir, { recursive: true, force: true });
63767
63979
  } catch {
63768
63980
  /* best effort */
63769
63981
  }
@@ -63804,9 +64016,9 @@ async function inspectWidgetPackage$1(packageId) {
63804
64016
 
63805
64017
  let pkgJson = {};
63806
64018
  const pkgJsonPath = path.join(widget.path, "package.json");
63807
- if (fs.existsSync(pkgJsonPath)) {
64019
+ if (fs$1.existsSync(pkgJsonPath)) {
63808
64020
  try {
63809
- pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, "utf8"));
64021
+ pkgJson = JSON.parse(fs$1.readFileSync(pkgJsonPath, "utf8"));
63810
64022
  } catch {
63811
64023
  /* ignore */
63812
64024
  }