@trops/dash-core 0.1.629 → 0.1.631

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.
@@ -1184,7 +1184,7 @@ var secureStoreController$1 = {
1184
1184
  decryptString,
1185
1185
  };
1186
1186
 
1187
- const path$p = require$$1$2;
1187
+ const path$q = require$$1$2;
1188
1188
  const {
1189
1189
  readFileSync,
1190
1190
  writeFileSync: writeFileSync$3,
@@ -1202,7 +1202,7 @@ const {
1202
1202
  function ensureDirectoryExistence$1(filePath) {
1203
1203
  try {
1204
1204
  // isDirectory
1205
- var dirname = path$p.dirname(filePath);
1205
+ var dirname = path$q.dirname(filePath);
1206
1206
  // check if the directory exists...return true
1207
1207
  // if not, we can pass in the dirname as the filepath
1208
1208
  // and check each directory recursively.
@@ -1317,7 +1317,7 @@ function removeFilesFromDirectory(directory, excludeFiles = []) {
1317
1317
 
1318
1318
  for (const file of files) {
1319
1319
  if (!excludeFiles.includes(file)) {
1320
- unlinkSync(path$p.join(directory, file), (err) => {
1320
+ unlinkSync(path$q.join(directory, file), (err) => {
1321
1321
  if (err) throw err;
1322
1322
  });
1323
1323
  }
@@ -1335,7 +1335,7 @@ var file = {
1335
1335
  };
1336
1336
 
1337
1337
  const { app: app$g } = require$$0$2;
1338
- const path$o = require$$1$2;
1338
+ const path$p = require$$1$2;
1339
1339
  const { writeFileSync: writeFileSync$2 } = require$$0$3;
1340
1340
  const { getFileContents: getFileContents$7 } = file;
1341
1341
 
@@ -1382,7 +1382,7 @@ const workspaceController$3 = {
1382
1382
  saveWorkspaceForApplication: (win, appId, workspaceObject) => {
1383
1383
  try {
1384
1384
  // filename to the pages file (live pages)
1385
- const filename = path$o.join(
1385
+ const filename = path$p.join(
1386
1386
  app$g.getPath("userData"),
1387
1387
  appName$7,
1388
1388
  appId,
@@ -1431,7 +1431,7 @@ const workspaceController$3 = {
1431
1431
  saveMenuItemsForApplication: (win, appId, menuItems) => {
1432
1432
  try {
1433
1433
  // filename to the workspaces file
1434
- const filename = path$o.join(
1434
+ const filename = path$p.join(
1435
1435
  app$g.getPath("userData"),
1436
1436
  appName$7,
1437
1437
  appId,
@@ -1480,7 +1480,7 @@ const workspaceController$3 = {
1480
1480
  */
1481
1481
  deleteWorkspaceForApplication: (win, appId, workspaceId) => {
1482
1482
  try {
1483
- const filename = path$o.join(
1483
+ const filename = path$p.join(
1484
1484
  app$g.getPath("userData"),
1485
1485
  appName$7,
1486
1486
  appId,
@@ -1514,7 +1514,7 @@ const workspaceController$3 = {
1514
1514
 
1515
1515
  listWorkspacesForApplication: (win, appId) => {
1516
1516
  try {
1517
- const filename = path$o.join(
1517
+ const filename = path$p.join(
1518
1518
  app$g.getPath("userData"),
1519
1519
  appName$7,
1520
1520
  appId,
@@ -1542,7 +1542,7 @@ const workspaceController$3 = {
1542
1542
 
1543
1543
  listMenuItemsForApplication: (win, appId) => {
1544
1544
  try {
1545
- const filename = path$o.join(
1545
+ const filename = path$p.join(
1546
1546
  app$g.getPath("userData"),
1547
1547
  appName$7,
1548
1548
  appId,
@@ -1587,7 +1587,7 @@ const workspaceController$3 = {
1587
1587
  var workspaceController_1 = workspaceController$3;
1588
1588
 
1589
1589
  const { app: app$f } = require$$0$2;
1590
- const path$n = require$$1$2;
1590
+ const path$o = require$$1$2;
1591
1591
  const { writeFileSync: writeFileSync$1 } = require$$0$3;
1592
1592
  const { getFileContents: getFileContents$6 } = file;
1593
1593
 
@@ -1607,7 +1607,7 @@ const themeController$5 = {
1607
1607
  saveThemeForApplication: (win, appId, name, obj) => {
1608
1608
  try {
1609
1609
  // filename to the pages file (live pages)
1610
- const filename = path$n.join(
1610
+ const filename = path$o.join(
1611
1611
  app$f.getPath("userData"),
1612
1612
  appName$6,
1613
1613
  appId,
@@ -1653,7 +1653,7 @@ const themeController$5 = {
1653
1653
  */
1654
1654
  listThemesForApplication: (win, appId) => {
1655
1655
  try {
1656
- const filename = path$n.join(
1656
+ const filename = path$o.join(
1657
1657
  app$f.getPath("userData"),
1658
1658
  appName$6,
1659
1659
  appId,
@@ -1695,7 +1695,7 @@ const themeController$5 = {
1695
1695
  */
1696
1696
  deleteThemeForApplication: (win, appId, themeKey) => {
1697
1697
  try {
1698
- const filename = path$n.join(
1698
+ const filename = path$o.join(
1699
1699
  app$f.getPath("userData"),
1700
1700
  appName$6,
1701
1701
  appId,
@@ -1772,7 +1772,7 @@ var themeController_1 = themeController$5;
1772
1772
  * `/data/`.
1773
1773
  */
1774
1774
 
1775
- const path$m = require$$1$2;
1775
+ const path$n = require$$1$2;
1776
1776
  const fs$i = require$$0$3;
1777
1777
  const { app: app$e } = require$$0$2;
1778
1778
 
@@ -1786,7 +1786,7 @@ function getAllowedRoots$2(category) {
1786
1786
  const userData = app$e.getPath("userData");
1787
1787
  switch (category) {
1788
1788
  case "data": {
1789
- const def = path$m.join(userData, APP_NAME, "data");
1789
+ const def = path$n.join(userData, APP_NAME, "data");
1790
1790
  // The user can configure a custom data directory in
1791
1791
  // Settings → General → Data Directory. If set, that
1792
1792
  // location is ALSO an allowed root. We don't replace the
@@ -1796,11 +1796,11 @@ function getAllowedRoots$2(category) {
1796
1796
  return override ? [def, override] : [def];
1797
1797
  }
1798
1798
  case "themes":
1799
- return [path$m.join(userData, APP_NAME, "themes")];
1799
+ return [path$n.join(userData, APP_NAME, "themes")];
1800
1800
  case "widgets":
1801
- return [path$m.join(userData, "widgets")];
1801
+ return [path$n.join(userData, "widgets")];
1802
1802
  case "plugins":
1803
- return [path$m.join(userData, "plugins")];
1803
+ return [path$n.join(userData, "plugins")];
1804
1804
  case "downloads":
1805
1805
  return [app$e.getPath("downloads")];
1806
1806
  default:
@@ -1817,7 +1817,7 @@ function getAllowedRoots$2(category) {
1817
1817
  */
1818
1818
  function readDataDirectoryFromSettings() {
1819
1819
  try {
1820
- const settingsPath = path$m.join(
1820
+ const settingsPath = path$n.join(
1821
1821
  app$e.getPath("userData"),
1822
1822
  APP_NAME,
1823
1823
  "settings.json",
@@ -1849,7 +1849,7 @@ function safePath$4(requested, allowedRoots) {
1849
1849
  throw new Error("safePath: allowedRoots must be a non-empty array");
1850
1850
  }
1851
1851
 
1852
- const resolved = path$m.resolve(requested);
1852
+ const resolved = path$n.resolve(requested);
1853
1853
 
1854
1854
  // Real-path through symlinks. If the file doesn't exist yet (a
1855
1855
  // create-new operation), real-path the parent so a symlink in the
@@ -1859,8 +1859,8 @@ function safePath$4(requested, allowedRoots) {
1859
1859
  real = fs$i.realpathSync(resolved);
1860
1860
  } catch (_e) {
1861
1861
  try {
1862
- const parent = fs$i.realpathSync(path$m.dirname(resolved));
1863
- real = path$m.join(parent, path$m.basename(resolved));
1862
+ const parent = fs$i.realpathSync(path$n.dirname(resolved));
1863
+ real = path$n.join(parent, path$n.basename(resolved));
1864
1864
  } catch (_e2) {
1865
1865
  // Parent doesn't exist either. Use the resolved-but-not-
1866
1866
  // real path; the caller's mkdirSync will happen inside the
@@ -1879,7 +1879,7 @@ function safePath$4(requested, allowedRoots) {
1879
1879
  }
1880
1880
  // Exact match OR strictly-inside (with separator to prevent
1881
1881
  // /data-evil/ matching /data/).
1882
- if (real === realRoot || real.startsWith(realRoot + path$m.sep)) {
1882
+ if (real === realRoot || real.startsWith(realRoot + path$n.sep)) {
1883
1883
  return real;
1884
1884
  }
1885
1885
  }
@@ -1941,7 +1941,7 @@ var safePath_1 = {
1941
1941
  */
1942
1942
 
1943
1943
  const fs$h = require$$0$3;
1944
- const path$l = require$$1$2;
1944
+ const path$m = require$$1$2;
1945
1945
  const { app: app$d } = require$$0$2;
1946
1946
 
1947
1947
  const FILE_NAME = "widgetMcpGrants.json";
@@ -1951,7 +1951,7 @@ const FILE_NAME = "widgetMcpGrants.json";
1951
1951
  let _cache$1 = null;
1952
1952
 
1953
1953
  function grantsFilePath() {
1954
- return path$l.join(app$d.getPath("userData"), FILE_NAME);
1954
+ return path$m.join(app$d.getPath("userData"), FILE_NAME);
1955
1955
  }
1956
1956
 
1957
1957
  function loadFromDisk() {
@@ -1978,7 +1978,7 @@ function writeToDisk(data) {
1978
1978
  const tmp = p + ".tmp";
1979
1979
  // Ensure parent dir exists (userData should already, but be defensive
1980
1980
  // for first-launch / freshly-cleared profile cases).
1981
- fs$h.mkdirSync(path$l.dirname(p), { recursive: true });
1981
+ fs$h.mkdirSync(path$m.dirname(p), { recursive: true });
1982
1982
  fs$h.writeFileSync(tmp, JSON.stringify(data, null, 2), "utf8");
1983
1983
  fs$h.renameSync(tmp, p);
1984
1984
  }
@@ -2687,7 +2687,7 @@ function commonjsRequire(path) {
2687
2687
  */
2688
2688
 
2689
2689
  const fs$g = require$$0$3;
2690
- const path$k = require$$1$2;
2690
+ const path$l = require$$1$2;
2691
2691
 
2692
2692
  /**
2693
2693
  * Structured error thrown by compileWidget() when the underlying
@@ -2722,7 +2722,7 @@ function getEsbuildDiagnostics() {
2722
2722
 
2723
2723
  try {
2724
2724
  const pkgJsonPath = require.resolve("esbuild/package.json");
2725
- diagnostics.esbuildPackageDir = path$k.dirname(pkgJsonPath);
2725
+ diagnostics.esbuildPackageDir = path$l.dirname(pkgJsonPath);
2726
2726
  diagnostics.esbuildVersion = commonjsRequire(pkgJsonPath).version;
2727
2727
  } catch (err) {
2728
2728
  diagnostics.esbuildResolveError = err.message;
@@ -2732,13 +2732,13 @@ function getEsbuildDiagnostics() {
2732
2732
  const archPkgJson = require.resolve(
2733
2733
  `${diagnostics.archPackage}/package.json`,
2734
2734
  );
2735
- const archDir = path$k.dirname(archPkgJson);
2735
+ const archDir = path$l.dirname(archPkgJson);
2736
2736
  // esbuild's native binary on macOS/Linux is bin/esbuild;
2737
2737
  // on Windows it's esbuild.exe at the package root.
2738
2738
  const candidate =
2739
2739
  process.platform === "win32"
2740
- ? path$k.join(archDir, "esbuild.exe")
2741
- : path$k.join(archDir, "bin", "esbuild");
2740
+ ? path$l.join(archDir, "esbuild.exe")
2741
+ : path$l.join(archDir, "bin", "esbuild");
2742
2742
  diagnostics.nativeBinaryPath = candidate;
2743
2743
  diagnostics.nativeBinaryExists = fs$g.existsSync(candidate);
2744
2744
  } catch (err) {
@@ -2786,19 +2786,19 @@ async function healthCheck() {
2786
2786
  * @returns {string|null} Path to the widgets/ directory, or null
2787
2787
  */
2788
2788
  function findWidgetsDir$2(widgetPath) {
2789
- const direct = path$k.join(widgetPath, "widgets");
2789
+ const direct = path$l.join(widgetPath, "widgets");
2790
2790
  if (fs$g.existsSync(direct)) {
2791
2791
  return direct;
2792
2792
  }
2793
2793
 
2794
2794
  // Check configs/widgets/ (packageZip.js nests .dash.js files here)
2795
- const configsWidgets = path$k.join(widgetPath, "configs", "widgets");
2795
+ const configsWidgets = path$l.join(widgetPath, "configs", "widgets");
2796
2796
  if (fs$g.existsSync(configsWidgets)) {
2797
2797
  return configsWidgets;
2798
2798
  }
2799
2799
 
2800
2800
  // Check configs/ directory (used by packageZip.js for distributed widgets)
2801
- const configs = path$k.join(widgetPath, "configs");
2801
+ const configs = path$l.join(widgetPath, "configs");
2802
2802
  if (fs$g.existsSync(configs)) {
2803
2803
  return configs;
2804
2804
  }
@@ -2815,7 +2815,7 @@ function findWidgetsDir$2(widgetPath) {
2815
2815
  );
2816
2816
 
2817
2817
  for (const subdir of subdirs) {
2818
- const nested = path$k.join(widgetPath, subdir.name, "widgets");
2818
+ const nested = path$l.join(widgetPath, subdir.name, "widgets");
2819
2819
  if (fs$g.existsSync(nested)) {
2820
2820
  console.log(`[WidgetCompiler] Found nested widgets/ at ${nested}`);
2821
2821
  return nested;
@@ -2864,14 +2864,14 @@ async function compileWidget$1(widgetPath) {
2864
2864
  // Compute relative path from the entry file (in widgetPath) to widgetsDir,
2865
2865
  // since widgetsDir may be nested (e.g., ./weather-widget/widgets/).
2866
2866
  const relWidgetsDir =
2867
- "./" + path$k.relative(widgetPath, widgetsDir).split(path$k.sep).join("/");
2867
+ "./" + path$l.relative(widgetPath, widgetsDir).split(path$l.sep).join("/");
2868
2868
  const imports = [];
2869
2869
  const exportParts = [];
2870
2870
 
2871
2871
  for (const dashFile of dashFiles) {
2872
2872
  const componentName = dashFile.replace(".dash.js", "");
2873
2873
  const componentFile = `${componentName}.js`;
2874
- const componentFilePath = path$k.join(widgetsDir, componentFile);
2874
+ const componentFilePath = path$l.join(widgetsDir, componentFile);
2875
2875
  const hasComponent = fs$g.existsSync(componentFilePath);
2876
2876
 
2877
2877
  // Import the config (always)
@@ -2904,9 +2904,9 @@ async function compileWidget$1(widgetPath) {
2904
2904
  const entryContent = [...imports, "", ...exportParts, ""].join("\n");
2905
2905
 
2906
2906
  // Write temporary entry file in the widget root
2907
- const entryPath = path$k.join(widgetPath, "__compile_entry.js");
2908
- const distDir = path$k.join(widgetPath, "dist");
2909
- const outPath = path$k.join(distDir, "index.cjs.js");
2907
+ const entryPath = path$l.join(widgetPath, "__compile_entry.js");
2908
+ const distDir = path$l.join(widgetPath, "dist");
2909
+ const outPath = path$l.join(distDir, "index.cjs.js");
2910
2910
 
2911
2911
  try {
2912
2912
  // Ensure dist/ directory exists
@@ -9525,7 +9525,7 @@ var dashConfigParser = { parseDashConfig: parseDashConfig$1, DashConfigParseErro
9525
9525
  */
9526
9526
 
9527
9527
  const fs$f = require$$0$3;
9528
- const path$j = require$$1$2;
9528
+ const path$k = require$$1$2;
9529
9529
  const { findWidgetsDir: findWidgetsDir$1 } = widgetCompiler$1;
9530
9530
  const { parseDashConfig } = dashConfigParser;
9531
9531
 
@@ -9566,9 +9566,9 @@ class DynamicWidgetLoader {
9566
9566
  );
9567
9567
 
9568
9568
  const widgetsDir =
9569
- findWidgetsDir$1(widgetPath) || path$j.join(widgetPath, "widgets");
9570
- const componentPath = path$j.join(widgetsDir, `${componentName}.js`);
9571
- const configPath = path$j.join(widgetsDir, `${componentName}.dash.js`);
9569
+ findWidgetsDir$1(widgetPath) || path$k.join(widgetPath, "widgets");
9570
+ const componentPath = path$k.join(widgetsDir, `${componentName}.js`);
9571
+ const configPath = path$k.join(widgetsDir, `${componentName}.dash.js`);
9572
9572
 
9573
9573
  if (!fs$f.existsSync(componentPath)) {
9574
9574
  throw new Error(`Component file not found: ${componentPath}`);
@@ -10246,7 +10246,7 @@ var registryAuthController$2 = {
10246
10246
  */
10247
10247
 
10248
10248
  const fs$e = require$$0$3;
10249
- const path$i = require$$1$2;
10249
+ const path$j = require$$1$2;
10250
10250
  const os$3 = require$$2;
10251
10251
  const { app: app$c } = require$$0$2;
10252
10252
 
@@ -10263,7 +10263,7 @@ function expandHome(p) {
10263
10263
  if (typeof p !== "string" || !p) return p;
10264
10264
  if (p === "~") return os$3.homedir();
10265
10265
  if (p.startsWith("~/") || p.startsWith("~\\")) {
10266
- return path$i.join(os$3.homedir(), p.slice(2));
10266
+ return path$j.join(os$3.homedir(), p.slice(2));
10267
10267
  }
10268
10268
  return p;
10269
10269
  }
@@ -10373,10 +10373,10 @@ function dottedComponentIdToPackageId(widgetId) {
10373
10373
  function resolveWidgetPackagePath(widgetId) {
10374
10374
  const packageId = dottedComponentIdToPackageId(widgetId);
10375
10375
  if (typeof packageId !== "string" || !packageId) return null;
10376
- const widgetsRoot = path$i.join(app$c.getPath("userData"), "widgets");
10376
+ const widgetsRoot = path$j.join(app$c.getPath("userData"), "widgets");
10377
10377
  // Split scope from name for "@scope/name" form.
10378
10378
  const parts = packageId.startsWith("@") ? packageId.split("/") : [packageId];
10379
- return path$i.join(widgetsRoot, ...parts, "package.json");
10379
+ return path$j.join(widgetsRoot, ...parts, "package.json");
10380
10380
  }
10381
10381
 
10382
10382
  /**
@@ -10468,7 +10468,7 @@ var widgetPermissions = {
10468
10468
  */
10469
10469
 
10470
10470
  const fs$d = require$$0$3;
10471
- const path$h = require$$1$2;
10471
+ const path$i = require$$1$2;
10472
10472
 
10473
10473
  const SOURCE_EXTENSIONS = new Set([
10474
10474
  ".js",
@@ -10526,13 +10526,13 @@ function readSourceFiles(dir) {
10526
10526
  return;
10527
10527
  }
10528
10528
  for (const entry of entries) {
10529
- const abs = path$h.join(current, entry.name);
10530
- const rel = relBase ? path$h.join(relBase, entry.name) : entry.name;
10529
+ const abs = path$i.join(current, entry.name);
10530
+ const rel = relBase ? path$i.join(relBase, entry.name) : entry.name;
10531
10531
  if (entry.isDirectory()) {
10532
10532
  if (skipDirs.has(entry.name)) continue;
10533
10533
  walk(abs, rel);
10534
10534
  } else if (entry.isFile()) {
10535
- const ext = path$h.extname(entry.name).toLowerCase();
10535
+ const ext = path$i.extname(entry.name).toLowerCase();
10536
10536
  if (!SOURCE_EXTENSIONS.has(ext)) continue;
10537
10537
  if (result.length >= SCAN_FILE_LIMIT) return;
10538
10538
  try {
@@ -10558,7 +10558,7 @@ function scanForMcpUsage(input) {
10558
10558
  let fileList = [];
10559
10559
  if (input.files && typeof input.files === "object") {
10560
10560
  for (const [relPath, source] of Object.entries(input.files)) {
10561
- const ext = path$h.extname(relPath).toLowerCase();
10561
+ const ext = path$i.extname(relPath).toLowerCase();
10562
10562
  if (!SOURCE_EXTENSIONS.has(ext)) continue;
10563
10563
  if (typeof source !== "string") continue;
10564
10564
  fileList.push({ relPath, source });
@@ -10671,7 +10671,7 @@ var manifestScanner = {
10671
10671
  */
10672
10672
 
10673
10673
  const fs$c = require$$0$3;
10674
- const path$g = require$$1$2;
10674
+ const path$h = require$$1$2;
10675
10675
  const { safePath: safePath$3 } = safePath_1;
10676
10676
 
10677
10677
  const NAME_RE = /^@?[a-z0-9][a-z0-9.-]*(\/[a-z0-9][a-z0-9.-]*)?$/i;
@@ -10692,8 +10692,8 @@ function loadWidgetManifest(folderPath) {
10692
10692
  return { ok: false, error: `folder does not exist: ${folderPath}` };
10693
10693
  }
10694
10694
 
10695
- const dashJsonPath = path$g.join(folderPath, "dash.json");
10696
- const packageJsonPath = path$g.join(folderPath, "package.json");
10695
+ const dashJsonPath = path$h.join(folderPath, "dash.json");
10696
+ const packageJsonPath = path$h.join(folderPath, "package.json");
10697
10697
 
10698
10698
  let raw;
10699
10699
  let source;
@@ -10764,7 +10764,7 @@ function loadWidgetManifest(folderPath) {
10764
10764
 
10765
10765
  // entry: optional with sensible default. Validate when present.
10766
10766
  let entry = typeof raw.entry === "string" ? raw.entry : "widgets";
10767
- if (path$g.isAbsolute(entry) || entry.split(/[/\\]/).includes("..")) {
10767
+ if (path$h.isAbsolute(entry) || entry.split(/[/\\]/).includes("..")) {
10768
10768
  return {
10769
10769
  ok: false,
10770
10770
  error: "manifest.entry must be relative and must not contain `..`",
@@ -10775,15 +10775,15 @@ function loadWidgetManifest(folderPath) {
10775
10775
  // folder root after realpath. If the entry doesn't yet exist on
10776
10776
  // disk (common during validate-only flows), fall back to a plain
10777
10777
  // resolve-and-prefix check.
10778
- const candidate = path$g.join(folderPath, entry);
10778
+ const candidate = path$h.join(folderPath, entry);
10779
10779
  if (fs$c.existsSync(candidate)) {
10780
10780
  safePath$3(candidate, [folderPath]);
10781
10781
  } else {
10782
- const resolved = path$g.resolve(candidate);
10783
- const rootResolved = path$g.resolve(folderPath);
10782
+ const resolved = path$h.resolve(candidate);
10783
+ const rootResolved = path$h.resolve(folderPath);
10784
10784
  if (
10785
10785
  resolved !== rootResolved &&
10786
- !resolved.startsWith(rootResolved + path$g.sep)
10786
+ !resolved.startsWith(rootResolved + path$h.sep)
10787
10787
  ) {
10788
10788
  return {
10789
10789
  ok: false,
@@ -10862,7 +10862,7 @@ function walkSourceContainment(rootPath) {
10862
10862
  const stat = fs$c.lstatSync(current);
10863
10863
  if (stat.isDirectory()) {
10864
10864
  for (const entry of fs$c.readdirSync(current)) {
10865
- stack.push(path$g.join(current, entry));
10865
+ stack.push(path$h.join(current, entry));
10866
10866
  }
10867
10867
  }
10868
10868
  // Symlinks: lstat gives us the symlink-itself; safePath above
@@ -17464,7 +17464,7 @@ function requireTransform () {
17464
17464
 
17465
17465
  const { app: app$b } = require$$0$2;
17466
17466
  var fs$b = require$$0$3;
17467
- const path$f = require$$1$2;
17467
+ const path$g = require$$1$2;
17468
17468
  const events$5 = events$8;
17469
17469
  const { getFileContents: getFileContents$5, writeToFile: writeToFile$2 } = file;
17470
17470
  const { safePath: safePath$2, getAllowedRoots: getAllowedRoots$1 } = safePath_1;
@@ -17481,7 +17481,7 @@ const { readEnforceFlag: readEnforceFlag$2, readJitFlag: readJitFlag$2 } = secur
17481
17481
  // domain-neutral name is a separate slice).
17482
17482
  function _loadFlags$1() {
17483
17483
  try {
17484
- const settingsPath = path$f.join(
17484
+ const settingsPath = path$g.join(
17485
17485
  app$b.getPath("userData"),
17486
17486
  appName$5,
17487
17487
  "settings.json",
@@ -17567,7 +17567,7 @@ const dataController$1 = {
17567
17567
  // Validate the renderer-supplied filename is contained within
17568
17568
  // the data directory. path.join doesn't reject `..` segments;
17569
17569
  // safePath does.
17570
- const candidate = path$f.join(
17570
+ const candidate = path$g.join(
17571
17571
  app$b.getPath("userData"),
17572
17572
  appName$5,
17573
17573
  appId,
@@ -17928,7 +17928,7 @@ const dataController$1 = {
17928
17928
  if (data) {
17929
17929
  // Validate filename is contained within the data directory.
17930
17930
  // path.join doesn't reject `..` segments; safePath does.
17931
- const candidate = path$f.join(
17931
+ const candidate = path$g.join(
17932
17932
  app$b.getPath("userData"),
17933
17933
  appName$5,
17934
17934
  "data",
@@ -18037,7 +18037,7 @@ const dataController$1 = {
18037
18037
  try {
18038
18038
  if (filename) {
18039
18039
  // filename to the pages file (live pages)
18040
- const fromFilename = path$f.join(
18040
+ const fromFilename = path$g.join(
18041
18041
  app$b.getPath("userData"),
18042
18042
  appName$5,
18043
18043
  "data",
@@ -18275,7 +18275,7 @@ var migrations = {
18275
18275
  */
18276
18276
 
18277
18277
  const { app: app$a } = require$$0$2;
18278
- const path$e = require$$1$2;
18278
+ const path$f = require$$1$2;
18279
18279
  const fs$a = require$$0$3;
18280
18280
  const { getFileContents: getFileContents$4, writeToFile: writeToFile$1 } = file;
18281
18281
  const { migrateSettings, CURRENT_SCHEMA_VERSION: CURRENT_SCHEMA_VERSION$2 } = migrations;
@@ -18291,8 +18291,8 @@ function copyDirectory(source, destination) {
18291
18291
 
18292
18292
  const files = fs$a.readdirSync(source);
18293
18293
  for (const file of files) {
18294
- const srcPath = path$e.join(source, file);
18295
- const destPath = path$e.join(destination, file);
18294
+ const srcPath = path$f.join(source, file);
18295
+ const destPath = path$f.join(destination, file);
18296
18296
  const stat = fs$a.lstatSync(srcPath);
18297
18297
 
18298
18298
  // Skip symlinks to prevent following links to sensitive files
@@ -18320,7 +18320,7 @@ const settingsController$4 = {
18320
18320
  try {
18321
18321
  if (data) {
18322
18322
  // <appId>/settings.json
18323
- const filename = path$e.join(
18323
+ const filename = path$f.join(
18324
18324
  app$a.getPath("userData"),
18325
18325
  appName$4,
18326
18326
  configFilename$3,
@@ -18364,7 +18364,7 @@ const settingsController$4 = {
18364
18364
  getSettingsForApplication: (win) => {
18365
18365
  try {
18366
18366
  // <appId>/settings.json
18367
- const filename = path$e.join(
18367
+ const filename = path$f.join(
18368
18368
  app$a.getPath("userData"),
18369
18369
  appName$4,
18370
18370
  configFilename$3,
@@ -18412,7 +18412,7 @@ const settingsController$4 = {
18412
18412
  */
18413
18413
  getDataDirectory: (win) => {
18414
18414
  try {
18415
- const settingsPath = path$e.join(
18415
+ const settingsPath = path$f.join(
18416
18416
  app$a.getPath("userData"),
18417
18417
  appName$4,
18418
18418
  configFilename$3,
@@ -18420,7 +18420,7 @@ const settingsController$4 = {
18420
18420
  const settings = getFileContents$4(settingsPath, {});
18421
18421
  const userDataDir =
18422
18422
  settings.userDataDirectory ||
18423
- path$e.join(app$a.getPath("userData"), appName$4);
18423
+ path$f.join(app$a.getPath("userData"), appName$4);
18424
18424
 
18425
18425
  console.log("[settingsController] Data directory retrieved successfully");
18426
18426
  // Return the data for ipcMain.handle() - modern promise-based approach
@@ -18457,7 +18457,7 @@ const settingsController$4 = {
18457
18457
  }
18458
18458
 
18459
18459
  // Update settings
18460
- const settingsPath = path$e.join(
18460
+ const settingsPath = path$f.join(
18461
18461
  app$a.getPath("userData"),
18462
18462
  appName$4,
18463
18463
  configFilename$3,
@@ -18491,11 +18491,11 @@ const settingsController$4 = {
18491
18491
  migrateDataDirectory: (win, oldPath, newPath) => {
18492
18492
  try {
18493
18493
  // Resolve paths to prevent traversal
18494
- const resolvedOldPath = path$e.resolve(oldPath);
18495
- const resolvedNewPath = path$e.resolve(newPath);
18494
+ const resolvedOldPath = path$f.resolve(oldPath);
18495
+ const resolvedNewPath = path$f.resolve(newPath);
18496
18496
 
18497
18497
  // Validate oldPath is the current configured data directory
18498
- const settingsCheckPath = path$e.join(
18498
+ const settingsCheckPath = path$f.join(
18499
18499
  app$a.getPath("userData"),
18500
18500
  appName$4,
18501
18501
  configFilename$3,
@@ -18503,8 +18503,8 @@ const settingsController$4 = {
18503
18503
  const currentSettings = getFileContents$4(settingsCheckPath, {});
18504
18504
  const currentDataDir =
18505
18505
  currentSettings.userDataDirectory ||
18506
- path$e.join(app$a.getPath("userData"), appName$4);
18507
- if (resolvedOldPath !== path$e.resolve(currentDataDir)) {
18506
+ path$f.join(app$a.getPath("userData"), appName$4);
18507
+ if (resolvedOldPath !== path$f.resolve(currentDataDir)) {
18508
18508
  throw new Error("Source path must be the current data directory");
18509
18509
  }
18510
18510
 
@@ -18540,7 +18540,7 @@ const settingsController$4 = {
18540
18540
  copyDirectory(resolvedOldPath, resolvedNewPath);
18541
18541
 
18542
18542
  // Update settings to use new path
18543
- const settingsPath = path$e.join(
18543
+ const settingsPath = path$f.join(
18544
18544
  app$a.getPath("userData"),
18545
18545
  appName$4,
18546
18546
  configFilename$3,
@@ -19294,7 +19294,7 @@ function requireProviderController () {
19294
19294
  }
19295
19295
 
19296
19296
  const { app: app$9 } = require$$0$2;
19297
- const path$d = require$$1$2;
19297
+ const path$e = require$$1$2;
19298
19298
  const events$4 = events$8;
19299
19299
  const { getFileContents: getFileContents$3 } = file;
19300
19300
 
@@ -19310,7 +19310,7 @@ const layoutController$1 = {
19310
19310
  */
19311
19311
  listLayoutsForApplication: (win, appId) => {
19312
19312
  try {
19313
- const filename = path$d.join(
19313
+ const filename = path$e.join(
19314
19314
  app$9.getPath("userData"),
19315
19315
  appName$3,
19316
19316
  appId,
@@ -37571,7 +37571,7 @@ const {
37571
37571
  const {
37572
37572
  StreamableHTTPClientTransport,
37573
37573
  } = streamableHttp$1;
37574
- const path$c = require$$1$2;
37574
+ const path$d = require$$1$2;
37575
37575
  const fs$9 = require$$0$3;
37576
37576
  const os$2 = require$$2;
37577
37577
  const responseCache$2 = responseCache_1;
@@ -37588,7 +37588,7 @@ const { app: app$8 } = require$$0$2;
37588
37588
  */
37589
37589
  function loadSettingsForFlags() {
37590
37590
  try {
37591
- const settingsPath = path$c.join(
37591
+ const settingsPath = path$d.join(
37592
37592
  app$8.getPath("userData"),
37593
37593
  "Dashboard",
37594
37594
  "settings.json",
@@ -38234,7 +38234,7 @@ const mcpController$3 = {
38234
38234
  }
38235
38235
 
38236
38236
  // Interpolate {{MCP_DIR}} in args to resolve local MCP server scripts
38237
- const mcpDir = path$c.join(__dirname, "..", "mcp");
38237
+ const mcpDir = path$d.join(__dirname, "..", "mcp");
38238
38238
  for (let i = 0; i < args.length; i++) {
38239
38239
  if (
38240
38240
  typeof args[i] === "string" &&
@@ -38779,7 +38779,7 @@ const mcpController$3 = {
38779
38779
  */
38780
38780
  getCatalog: (win) => {
38781
38781
  try {
38782
- const catalogPath = path$c.join(
38782
+ const catalogPath = path$d.join(
38783
38783
  __dirname,
38784
38784
  "..",
38785
38785
  "mcp",
@@ -38820,7 +38820,7 @@ const mcpController$3 = {
38820
38820
  */
38821
38821
  getKnownExternalCatalog: () => {
38822
38822
  try {
38823
- const catalogPath = path$c.join(
38823
+ const catalogPath = path$d.join(
38824
38824
  __dirname,
38825
38825
  "..",
38826
38826
  "mcp",
@@ -38933,7 +38933,7 @@ const mcpController$3 = {
38933
38933
  }
38934
38934
 
38935
38935
  // Interpolate {{MCP_DIR}} in authCommand args (same as startServer)
38936
- const mcpDir = path$c.join(__dirname, "..", "mcp");
38936
+ const mcpDir = path$d.join(__dirname, "..", "mcp");
38937
38937
  const resolvedArgs = (authCommand.args || []).map((arg) =>
38938
38938
  typeof arg === "string" && arg.includes("{{MCP_DIR}}")
38939
38939
  ? arg.replace(/\{\{MCP_DIR\}\}/g, mcpDir)
@@ -39065,7 +39065,7 @@ var mcpControllerExports = mcpController$4.exports;
39065
39065
  * - Support two-level browsing: packages (bundles) and widgets within packages
39066
39066
  */
39067
39067
 
39068
- const path$b = require$$1$2;
39068
+ const path$c = require$$1$2;
39069
39069
  const fs$8 = require$$0$3;
39070
39070
  const os$1 = require$$2;
39071
39071
  const { toPackageId } = packageId;
@@ -39091,7 +39091,7 @@ function getCacheKey() {
39091
39091
  * Get the local test registry path for dev mode
39092
39092
  */
39093
39093
  function getTestRegistryPath() {
39094
- return path$b.join(__dirname, "..", "registry", "test-registry-index.json");
39094
+ return path$c.join(__dirname, "..", "registry", "test-registry-index.json");
39095
39095
  }
39096
39096
 
39097
39097
  /**
@@ -39707,7 +39707,7 @@ async function fetchPackageSource(packageName, componentName = null) {
39707
39707
 
39708
39708
  const zip = new AdmZip(buffer);
39709
39709
  const safeName = (pkg.name || "pkg").replace(/[^a-zA-Z0-9-_]/g, "_");
39710
- const tempDir = path$b.join(
39710
+ const tempDir = path$c.join(
39711
39711
  os$1.tmpdir(),
39712
39712
  `dash-registry-preview-${safeName}-${Date.now()}`,
39713
39713
  );
@@ -39716,7 +39716,7 @@ async function fetchPackageSource(packageName, componentName = null) {
39716
39716
  validateZipEntries(zip, tempDir);
39717
39717
  zip.extractAllTo(tempDir, true);
39718
39718
 
39719
- const widgetsDir = path$b.join(tempDir, "widgets");
39719
+ const widgetsDir = path$c.join(tempDir, "widgets");
39720
39720
  let componentCode = "";
39721
39721
  let configCode = "";
39722
39722
  let widgetName = null;
@@ -39744,7 +39744,7 @@ async function fetchPackageSource(packageName, componentName = null) {
39744
39744
  if (!configFile) configFile = dashFiles[0];
39745
39745
 
39746
39746
  if (configFile) {
39747
- configCode = fs$8.readFileSync(path$b.join(widgetsDir, configFile), "utf8");
39747
+ configCode = fs$8.readFileSync(path$c.join(widgetsDir, configFile), "utf8");
39748
39748
  widgetName = configFile.replace(/\.dash\.js$/, "");
39749
39749
  }
39750
39750
 
@@ -39759,7 +39759,7 @@ async function fetchPackageSource(packageName, componentName = null) {
39759
39759
 
39760
39760
  if (componentFile) {
39761
39761
  componentCode = fs$8.readFileSync(
39762
- path$b.join(widgetsDir, componentFile),
39762
+ path$c.join(widgetsDir, componentFile),
39763
39763
  "utf8",
39764
39764
  );
39765
39765
  if (!widgetName) widgetName = componentFile.replace(/\.js$/, "");
@@ -39767,13 +39767,13 @@ async function fetchPackageSource(packageName, componentName = null) {
39767
39767
  }
39768
39768
 
39769
39769
  let bundleSource = null;
39770
- const bundlePath = path$b.join(tempDir, "dist", "index.cjs.js");
39770
+ const bundlePath = path$c.join(tempDir, "dist", "index.cjs.js");
39771
39771
  if (fs$8.existsSync(bundlePath)) {
39772
39772
  bundleSource = fs$8.readFileSync(bundlePath, "utf8");
39773
39773
  }
39774
39774
 
39775
39775
  let dashMeta = {};
39776
- const dashPath = path$b.join(tempDir, "dash.json");
39776
+ const dashPath = path$c.join(tempDir, "dash.json");
39777
39777
  if (fs$8.existsSync(dashPath)) {
39778
39778
  try {
39779
39779
  dashMeta = JSON.parse(fs$8.readFileSync(dashPath, "utf8"));
@@ -39886,7 +39886,7 @@ async function fetchPackageManifest(packageName) {
39886
39886
 
39887
39887
  const zip = new AdmZip(buffer);
39888
39888
  const safeName = (pkg.name || "pkg").replace(/[^a-zA-Z0-9-_]/g, "_");
39889
- const tempDir = path$b.join(
39889
+ const tempDir = path$c.join(
39890
39890
  os$1.tmpdir(),
39891
39891
  `dash-registry-manifest-${safeName}-${Date.now()}`,
39892
39892
  );
@@ -39955,7 +39955,7 @@ var registryController$3 = {
39955
39955
  var fs$7 = require$$0$3;
39956
39956
  var JSONStream = require$$4$1;
39957
39957
  const algoliasearch$1 = require$$2$2;
39958
- const path$a = require$$3$2;
39958
+ const path$b = require$$3$2;
39959
39959
  const { ensureDirectoryExistence, checkDirectory } = file;
39960
39960
 
39961
39961
  let AlgoliaIndex$1 = class AlgoliaIndex {
@@ -40062,7 +40062,7 @@ let AlgoliaIndex$1 = class AlgoliaIndex {
40062
40062
  if (err) reject(err);
40063
40063
  if (files) {
40064
40064
  files.forEach((file) => {
40065
- fs$7.unlinkSync(path$a.join(directoryPath, file));
40065
+ fs$7.unlinkSync(path$b.join(directoryPath, file));
40066
40066
  });
40067
40067
  resolve();
40068
40068
  }
@@ -40085,7 +40085,7 @@ let AlgoliaIndex$1 = class AlgoliaIndex {
40085
40085
  let results = [];
40086
40086
  for (const fileIndex in files) {
40087
40087
  // for each file lets read the file and then push to algolia
40088
- const pathToBatch = path$a.join(batchFilepath, files[fileIndex]);
40088
+ const pathToBatch = path$b.join(batchFilepath, files[fileIndex]);
40089
40089
  const fileContents = await this.readFile(pathToBatch);
40090
40090
  if (fileContents) {
40091
40091
  if ("data" in fileContents && "filepath" in fileContents) {
@@ -40623,7 +40623,7 @@ function upsertMenuItem$1(items, menuItem) {
40623
40623
  var upsertMenuItem_1 = { upsertMenuItem: upsertMenuItem$1 };
40624
40624
 
40625
40625
  const { app: app$7 } = require$$0$2;
40626
- const path$9 = require$$1$2;
40626
+ const path$a = require$$1$2;
40627
40627
  const { writeFileSync } = require$$0$3;
40628
40628
  const { getFileContents: getFileContents$2 } = file;
40629
40629
  const { upsertMenuItem } = upsertMenuItem_1;
@@ -40634,7 +40634,7 @@ const appName$2 = "Dashboard";
40634
40634
  const menuItemsController$1 = {
40635
40635
  saveMenuItemForApplication: (win, appId, menuItem) => {
40636
40636
  try {
40637
- const filename = path$9.join(
40637
+ const filename = path$a.join(
40638
40638
  app$7.getPath("userData"),
40639
40639
  appName$2,
40640
40640
  appId,
@@ -40653,7 +40653,7 @@ const menuItemsController$1 = {
40653
40653
 
40654
40654
  listMenuItemsForApplication: (win, appId) => {
40655
40655
  try {
40656
- const filename = path$9.join(
40656
+ const filename = path$a.join(
40657
40657
  app$7.getPath("userData"),
40658
40658
  appName$2,
40659
40659
  appId,
@@ -59028,7 +59028,7 @@ streamableHttp.StreamableHTTPServerTransport = StreamableHTTPServerTransport$1;
59028
59028
  */
59029
59029
 
59030
59030
  const fs$5 = require$$0$3;
59031
- const path$8 = require$$1$2;
59031
+ const path$9 = require$$1$2;
59032
59032
  const forge = require$$2$4;
59033
59033
 
59034
59034
  /**
@@ -59037,8 +59037,8 @@ const forge = require$$2$4;
59037
59037
  * @returns {{ cert: string, key: string }} PEM-encoded certificate and private key
59038
59038
  */
59039
59039
  function getOrCreateCert$1(certsDir) {
59040
- const certPath = path$8.join(certsDir, "cert.pem");
59041
- const keyPath = path$8.join(certsDir, "key.pem");
59040
+ const certPath = path$9.join(certsDir, "cert.pem");
59041
+ const keyPath = path$9.join(certsDir, "key.pem");
59042
59042
 
59043
59043
  // Return existing cert if valid
59044
59044
  if (fs$5.existsSync(certPath) && fs$5.existsSync(keyPath)) {
@@ -68586,7 +68586,7 @@ var publisherKeyController$1 = {
68586
68586
  */
68587
68587
 
68588
68588
  const fs$4 = require$$0$3;
68589
- const path$7 = require$$1$2;
68589
+ const path$8 = require$$1$2;
68590
68590
  const { getStoredToken: getStoredToken$2 } = registryAuthController$2;
68591
68591
  const { signZipBuffer: signZipBuffer$1 } = publisherKeyController$1;
68592
68592
 
@@ -68648,7 +68648,7 @@ async function publishToRegistry$1(zipPath, manifest) {
68648
68648
  formData.append(
68649
68649
  "file",
68650
68650
  new Blob([zipBuffer], { type: "application/zip" }),
68651
- path$7.basename(zipPath),
68651
+ path$8.basename(zipPath),
68652
68652
  );
68653
68653
  formData.append("manifest", JSON.stringify(manifest));
68654
68654
  formData.append("signature", signing.signature);
@@ -68935,7 +68935,7 @@ function requireWidgetPublishManifest () {
68935
68935
  * Mirrors dashboardConfigController patterns for ZIP creation, manifest generation,
68936
68936
  * and registry interaction.
68937
68937
  */
68938
- const path$6 = require$$1$2;
68938
+ const path$7 = require$$1$2;
68939
68939
  const { app: app$5, dialog: dialog$2 } = require$$0$2;
68940
68940
  const AdmZip$2 = require$$5;
68941
68941
 
@@ -69483,7 +69483,7 @@ async function installThemeFromRegistry$1(win, appId, packageName) {
69483
69483
  // Validate entry path (security: prevent path traversal)
69484
69484
  if (
69485
69485
  themeEntry.entryName.includes("..") ||
69486
- path$6.isAbsolute(themeEntry.entryName)
69486
+ path$7.isAbsolute(themeEntry.entryName)
69487
69487
  ) {
69488
69488
  return {
69489
69489
  success: false,
@@ -69717,7 +69717,7 @@ var themeRegistryController$1 = {
69717
69717
  */
69718
69718
 
69719
69719
  const { app: app$4, dialog: dialog$1 } = require$$0$2;
69720
- const path$5 = require$$1$2;
69720
+ const path$6 = require$$1$2;
69721
69721
  const AdmZip$1 = require$$5;
69722
69722
  const { getFileContents: getFileContents$1 } = file;
69723
69723
  const {
@@ -69766,7 +69766,7 @@ async function exportDashboardConfig$1(
69766
69766
  ) {
69767
69767
  try {
69768
69768
  // 1. Read workspace from workspaces.json
69769
- const filename = path$5.join(
69769
+ const filename = path$6.join(
69770
69770
  app$4.getPath("userData"),
69771
69771
  appName$1,
69772
69772
  appId,
@@ -69880,7 +69880,7 @@ async function exportDashboardConfig$1(
69880
69880
 
69881
69881
  const { canceled, filePath } = await dialog$1.showSaveDialog(win, {
69882
69882
  title: "Export Dashboard as ZIP",
69883
- defaultPath: path$5.join(
69883
+ defaultPath: path$6.join(
69884
69884
  app$4.getPath("desktop"),
69885
69885
  `dashboard-${sanitizedName}.zip`,
69886
69886
  ),
@@ -69946,7 +69946,7 @@ async function selectDashboardFile$1(win) {
69946
69946
 
69947
69947
  // Extract and validate
69948
69948
  const zip = new AdmZip$1(zipPath);
69949
- const tempDir = path$5.join(app$4.getPath("temp"), "dash-import");
69949
+ const tempDir = path$6.join(app$4.getPath("temp"), "dash-import");
69950
69950
  const { validateZipEntries } = widgetRegistryExports;
69951
69951
  validateZipEntries(zip, tempDir);
69952
69952
 
@@ -70056,7 +70056,7 @@ async function importDashboardConfig$1(
70056
70056
  const zip = new AdmZip$1(zipPath);
70057
70057
 
70058
70058
  // Validate ZIP entries for path traversal
70059
- const tempDir = path$5.join(app$4.getPath("temp"), "dash-import");
70059
+ const tempDir = path$6.join(app$4.getPath("temp"), "dash-import");
70060
70060
  const { validateZipEntries } = widgetRegistryExports;
70061
70061
  validateZipEntries(zip, tempDir);
70062
70062
 
@@ -70696,7 +70696,7 @@ async function installDashboardFromRegistry$1(
70696
70696
  const zip = new AdmZip$1(zipBuffer);
70697
70697
 
70698
70698
  // 3. Validate ZIP entries
70699
- const tempDir = path$5.join(app$4.getPath("temp"), "dash-registry-import");
70699
+ const tempDir = path$6.join(app$4.getPath("temp"), "dash-registry-import");
70700
70700
  const { validateZipEntries } = widgetRegistryExports;
70701
70701
  validateZipEntries(zip, tempDir);
70702
70702
 
@@ -70832,7 +70832,7 @@ async function collectDashboardDependencies$1(
70832
70832
  ) {
70833
70833
  try {
70834
70834
  // 1. Read workspace
70835
- const filename = path$5.join(
70835
+ const filename = path$6.join(
70836
70836
  app$4.getPath("userData"),
70837
70837
  appName$1,
70838
70838
  appId,
@@ -71111,7 +71111,7 @@ async function prepareDashboardForPublish$1(
71111
71111
  const { resolveNextVersion } = requireWidgetPublishManifest();
71112
71112
 
71113
71113
  // 1. Read workspace
71114
- const filename = path$5.join(
71114
+ const filename = path$6.join(
71115
71115
  app$4.getPath("userData"),
71116
71116
  appName$1,
71117
71117
  appId,
@@ -71421,7 +71421,7 @@ async function prepareDashboardForPublish$1(
71421
71421
  );
71422
71422
  });
71423
71423
  if (!match || !match.path) continue;
71424
- const pkgJsonPath = path$5.join(match.path, "package.json");
71424
+ const pkgJsonPath = path$6.join(match.path, "package.json");
71425
71425
  if (!fs.existsSync(pkgJsonPath)) continue;
71426
71426
  try {
71427
71427
  const pkg = JSON.parse(fs.readFileSync(pkgJsonPath, "utf8"));
@@ -71465,7 +71465,7 @@ async function prepareDashboardForPublish$1(
71465
71465
  const sanitizedName = manifest.name;
71466
71466
  const { canceled, filePath } = await dialog$1.showSaveDialog(win, {
71467
71467
  title: "Save Dashboard Package for Registry",
71468
- defaultPath: path$5.join(
71468
+ defaultPath: path$6.join(
71469
71469
  app$4.getPath("desktop"),
71470
71470
  `dashboard-${sanitizedName}-v${manifest.version}.zip`,
71471
71471
  ),
@@ -71633,7 +71633,7 @@ async function checkDashboardUpdatesForApp$1(appId) {
71633
71633
  const { fetchRegistryIndex } = registryController$3;
71634
71634
 
71635
71635
  try {
71636
- const filename = path$5.join(
71636
+ const filename = path$6.join(
71637
71637
  app$4.getPath("userData"),
71638
71638
  appName$1,
71639
71639
  appId,
@@ -71704,7 +71704,7 @@ function getProviderSetupManifest$1(appId, requiredProviders = []) {
71704
71704
  */
71705
71705
  function getDashboardPublishPreview$1(appId, workspaceId, widgetRegistry = null) {
71706
71706
  try {
71707
- const filename = path$5.join(
71707
+ const filename = path$6.join(
71708
71708
  app$4.getPath("userData"),
71709
71709
  appName$1,
71710
71710
  appId,
@@ -72341,7 +72341,7 @@ var notificationController_1 = notificationController$2;
72341
72341
 
72342
72342
  const { app: app$3 } = require$$0$2;
72343
72343
  const fs$3 = require$$0$3;
72344
- const path$4 = require$$1$2;
72344
+ const path$5 = require$$1$2;
72345
72345
  const WebSocket = require$$3$3;
72346
72346
  const {
72347
72347
  gateNetworkCall,
@@ -72351,7 +72351,7 @@ const { readEnforceFlag, readJitFlag } = securityFlags;
72351
72351
 
72352
72352
  function _loadFlags() {
72353
72353
  try {
72354
- const settingsPath = path$4.join(
72354
+ const settingsPath = path$5.join(
72355
72355
  app$3.getPath("userData"),
72356
72356
  "Dashboard",
72357
72357
  "settings.json",
@@ -73668,7 +73668,7 @@ var widgetMountTokenController$1 = { setupWidgetMountTokenHandlers };
73668
73668
  * the host and the store together.
73669
73669
  */
73670
73670
 
73671
- const path$3 = require$$1$2;
73671
+ const path$4 = require$$1$2;
73672
73672
  const { app: app$2 } = require$$0$2;
73673
73673
  const Store = require$$0$5;
73674
73674
 
@@ -73684,7 +73684,7 @@ function createElectronHost$1() {
73684
73684
  const store = new Store({ name: "dash-bots" });
73685
73685
  const budgetStore = new Store({ name: "dash-bot-budgets" });
73686
73686
  const memoryStore = new Store({ name: "dash-bot-memory" });
73687
- const botsRoot = path$3.join(app$2.getPath("userData"), "bots");
73687
+ const botsRoot = path$4.join(app$2.getPath("userData"), "bots");
73688
73688
 
73689
73689
  return {
73690
73690
  paths: { botsRoot },
@@ -73769,6 +73769,9 @@ function withDefaults$1(def = {}) {
73769
73769
  provider: null,
73770
73770
  model: null,
73771
73771
  modelSelection: { mode: "recommended" },
73772
+ // null → derive the engine from the provider (tool-loop). A bot may pin a
73773
+ // specific engine id here (e.g. "claude-agent").
73774
+ engine: null,
73772
73775
  mcpServers: [],
73773
73776
  allowedTools: [],
73774
73777
  approvalPolicy: "ask",
@@ -73806,6 +73809,13 @@ function validateBotDefinition$1(def) {
73806
73809
  errors.push("provider must be null or a non-empty string");
73807
73810
  }
73808
73811
  }
73812
+ // engine may be null (derive from provider) or a non-empty string (an engine
73813
+ // id). The runner surfaces an unknown id at run time.
73814
+ if (def.engine !== null && def.engine !== undefined) {
73815
+ if (typeof def.engine !== "string" || !def.engine) {
73816
+ errors.push("engine must be null or a non-empty string");
73817
+ }
73818
+ }
73809
73819
  if (!APPROVAL_POLICIES.has(def.approvalPolicy)) {
73810
73820
  errors.push(
73811
73821
  `approvalPolicy must be one of ${[...APPROVAL_POLICIES].join(", ")}`,
@@ -73867,7 +73877,7 @@ var botSchema = {
73867
73877
  */
73868
73878
 
73869
73879
  const fs$2 = require$$0$3;
73870
- const path$2 = require$$1$2;
73880
+ const path$3 = require$$1$2;
73871
73881
  const {
73872
73882
  newBotId,
73873
73883
  isValidBotId,
@@ -73917,7 +73927,7 @@ let BotStore$1 = class BotStore {
73917
73927
  if (!isValidBotId(id)) {
73918
73928
  throw new Error(`BotStore: invalid bot id "${id}"`);
73919
73929
  }
73920
- return path$2.join(this._botsRoot, id, "files");
73930
+ return path$3.join(this._botsRoot, id, "files");
73921
73931
  }
73922
73932
 
73923
73933
  /** @returns {object[]} all bot definitions */
@@ -73988,7 +73998,7 @@ let BotStore$1 = class BotStore {
73988
73998
  this._save(data);
73989
73999
 
73990
74000
  if (isValidBotId(id)) {
73991
- fs$2.rmSync(path$2.join(this._botsRoot, id), {
74001
+ fs$2.rmSync(path$3.join(this._botsRoot, id), {
73992
74002
  recursive: true,
73993
74003
  force: true,
73994
74004
  });
@@ -74202,6 +74212,11 @@ var approvalsExports = approvals.exports;
74202
74212
  * Gate every tool call routes through before executing.
74203
74213
  * @property {(toolName: string, input: any) => Promise<{text: string, isError?: boolean}>} executeTool
74204
74214
  * Execute an approved tool call (wraps mcpController in production).
74215
+ * @property {string} [botId] The running bot's id.
74216
+ * @property {string} [workingDir] Sandbox dir for engines with native file/shell tools.
74217
+ * @property {string} [approvalPolicy] "ask" | "allow" — for engines that run their own tool loop.
74218
+ * @property {(request: object) => {id: string, promise: Promise<any>}} [createApproval]
74219
+ * Create a pending approval + await the decision (for engine-native tools).
74205
74220
  *
74206
74221
  * BotEvent — the normalized stream every engine yields:
74207
74222
  * { type: "text", text }
@@ -74277,7 +74292,7 @@ var toolLoopEngine$2 = {exports: {}};
74277
74292
  * [Symbol.asyncIterator]: () => AsyncIterator<any>
74278
74293
  * }}
74279
74294
  */
74280
- function createEventStream$1() {
74295
+ function createEventStream$2() {
74281
74296
  /** @type {any[]} */
74282
74297
  const queue = [];
74283
74298
  /** @type {Array<{ resolve: (r: IteratorResult<any>) => void }>} */
@@ -74318,7 +74333,7 @@ function createEventStream$1() {
74318
74333
  };
74319
74334
  }
74320
74335
 
74321
- var eventStream = { createEventStream: createEventStream$1 };
74336
+ var eventStream = { createEventStream: createEventStream$2 };
74322
74337
 
74323
74338
  /**
74324
74339
  * anthropicAdapter.js
@@ -74596,7 +74611,7 @@ var openAICompatibleAdapter_1 = openAICompatibleAdapter$1;
74596
74611
  * runner to persist, and read back from ctx.session on the next run.
74597
74612
  */
74598
74613
 
74599
- const { createEventStream } = eventStream;
74614
+ const { createEventStream: createEventStream$1 } = eventStream;
74600
74615
  const anthropicAdapter = anthropicAdapter_1;
74601
74616
  const openAICompatibleAdapter = openAICompatibleAdapter_1;
74602
74617
 
@@ -74730,7 +74745,7 @@ const toolLoopEngine$1 = {
74730
74745
  capabilities: { builtInTools: false, skills: false, nativeSessions: false },
74731
74746
 
74732
74747
  run(ctx) {
74733
- const stream = createEventStream();
74748
+ const stream = createEventStream$1();
74734
74749
  (async () => {
74735
74750
  try {
74736
74751
  await runLoop(ctx, stream);
@@ -74753,21 +74768,224 @@ toolLoopEngine$2.exports.ADAPTERS = ADAPTERS;
74753
74768
 
74754
74769
  var toolLoopEngineExports = toolLoopEngine$2.exports;
74755
74770
 
74771
+ var claudeAgentEngine$2 = {exports: {}};
74772
+
74773
+ /**
74774
+ * claudeAgentEngine.js
74775
+ *
74776
+ * A BotEngine backed by the Claude Agent SDK (`@anthropic-ai/claude-agent-sdk`),
74777
+ * giving bots native file/shell/code tools and SDK-managed sessions (PRD FR-007).
74778
+ * The provider-neutral tool-loop engine stays the default; a bot opts into this
74779
+ * engine via its `engine` field.
74780
+ *
74781
+ * Design (P1 MVP — built-in tools first):
74782
+ * - The SDK is ESM-only, so it's loaded via dynamic import() at run time (a test
74783
+ * seam lets tests inject a fake `query`). The module itself loads clean under
74784
+ * plain Node (NFR-006) — nothing vendor-specific is required at load.
74785
+ * - Tool permission routes through `canUseTool`, gated by the bot's
74786
+ * approvalPolicy: "allow" runs tools without prompting; "ask" creates a
74787
+ * pending approval via the same registry the Activity panel reads, and awaits.
74788
+ * - The SDK's working directory is confined to the bot's sandbox (ctx.workingDir)
74789
+ * so file ops default there. Bridging the bot's *configured MCP servers* into
74790
+ * the SDK is deferred; this MVP uses the SDK's built-in tools.
74791
+ */
74792
+
74793
+ const { createEventStream } = eventStream;
74794
+
74795
+ // Test seam: injected fake `query` implementation (see __setQueryForTest).
74796
+ let _queryImpl = null;
74797
+
74798
+ /** @param {Function|null} fn */
74799
+ function __setQueryForTest(fn) {
74800
+ _queryImpl = fn;
74801
+ }
74802
+
74803
+ async function _loadQuery() {
74804
+ if (_queryImpl) return _queryImpl;
74805
+ const mod = await import('@anthropic-ai/claude-agent-sdk');
74806
+ return mod.query;
74807
+ }
74808
+
74809
+ /** Extract normalized events from one SDK assistant message's content blocks. */
74810
+ function* _fromAssistant(message) {
74811
+ const blocks = (message && message.content) || [];
74812
+ for (const b of blocks) {
74813
+ if (!b) continue;
74814
+ if (b.type === "text" && b.text) {
74815
+ yield { type: "text", text: b.text };
74816
+ } else if (b.type === "tool_use") {
74817
+ yield { type: "tool_call", id: b.id, name: b.name, input: b.input };
74818
+ }
74819
+ }
74820
+ }
74821
+
74822
+ /** Extract tool_result events from one SDK user message's content blocks. */
74823
+ function* _fromUser(message) {
74824
+ const blocks = (message && message.content) || [];
74825
+ for (const b of blocks) {
74826
+ if (!b || b.type !== "tool_result") continue;
74827
+ let text = "";
74828
+ if (typeof b.content === "string") text = b.content;
74829
+ else if (Array.isArray(b.content)) {
74830
+ text = b.content
74831
+ .filter((c) => c && c.type === "text")
74832
+ .map((c) => c.text)
74833
+ .join("\n");
74834
+ }
74835
+ yield {
74836
+ type: "tool_result",
74837
+ id: b.tool_use_id,
74838
+ output: text,
74839
+ isError: !!b.is_error,
74840
+ };
74841
+ }
74842
+ }
74843
+
74844
+ /** Build the SDK canUseTool hook from the run context. */
74845
+ function _makeCanUseTool(ctx) {
74846
+ return async function canUseTool(toolName, input) {
74847
+ if (ctx.signal && ctx.signal.aborted) {
74848
+ return { behavior: "deny", message: "run aborted" };
74849
+ }
74850
+ // Trusted bot → run tools without prompting.
74851
+ if (ctx.approvalPolicy === "allow") {
74852
+ return { behavior: "allow", updatedInput: input };
74853
+ }
74854
+ // Otherwise gate through the approval queue (shown in the Activity panel).
74855
+ if (typeof ctx.createApproval !== "function") {
74856
+ return { behavior: "deny", message: "no approval channel available" };
74857
+ }
74858
+ const { promise } = ctx.createApproval({
74859
+ botId: ctx.botId,
74860
+ workspaceId: ctx.workspaceId,
74861
+ toolName,
74862
+ input,
74863
+ engine: "claude-agent",
74864
+ });
74865
+ const decision = await promise;
74866
+ return decision && decision.allow
74867
+ ? { behavior: "allow", updatedInput: input }
74868
+ : {
74869
+ behavior: "deny",
74870
+ message: (decision && decision.reason) || "approval denied",
74871
+ };
74872
+ };
74873
+ }
74874
+
74875
+ async function _runAgent(ctx, stream) {
74876
+ const query = await _loadQuery();
74877
+
74878
+ // Auth: prefer the Claude Code CLI session (zero-config); fall back to the
74879
+ // bot's Anthropic API key. NOTE: this sets a process-global env var — fine for
74880
+ // the common single-key case; per-run isolation is a follow-up.
74881
+ if (ctx.credentials && ctx.credentials.apiKey) {
74882
+ process.env.ANTHROPIC_API_KEY = ctx.credentials.apiKey;
74883
+ }
74884
+
74885
+ const options = {
74886
+ model: ctx.model,
74887
+ systemPrompt: ctx.systemPrompt || { type: "preset", preset: "claude_code" },
74888
+ permissionMode: "default",
74889
+ canUseTool: _makeCanUseTool(ctx),
74890
+ };
74891
+ if (ctx.maxTurns) options.maxTurns = ctx.maxTurns;
74892
+ if (ctx.workingDir) options.cwd = ctx.workingDir;
74893
+ if (ctx.session && ctx.session.id) options.resume = ctx.session.id;
74894
+
74895
+ const q = query({ prompt: ctx.prompt || "", options });
74896
+
74897
+ // Cooperative cancellation → SDK interrupt.
74898
+ if (ctx.signal) {
74899
+ ctx.signal.addEventListener("abort", () => {
74900
+ try {
74901
+ if (typeof q.interrupt === "function") q.interrupt();
74902
+ } catch (_e) {
74903
+ /* best effort */
74904
+ }
74905
+ });
74906
+ }
74907
+
74908
+ let sessionId = null;
74909
+ let usage = null;
74910
+ let stopReason = "end";
74911
+ try {
74912
+ for await (const msg of q) {
74913
+ if (msg && msg.session_id) sessionId = msg.session_id;
74914
+ if (!msg) continue;
74915
+ if (msg.type === "assistant") {
74916
+ for (const ev of _fromAssistant(msg.message)) stream.push(ev);
74917
+ } else if (msg.type === "user") {
74918
+ for (const ev of _fromUser(msg.message)) stream.push(ev);
74919
+ } else if (msg.type === "result") {
74920
+ stopReason = msg.subtype || "end";
74921
+ const u = msg.usage || {};
74922
+ usage = {
74923
+ inputTokens: u.input_tokens || 0,
74924
+ outputTokens: u.output_tokens || 0,
74925
+ };
74926
+ }
74927
+ if (ctx.signal && ctx.signal.aborted) break;
74928
+ }
74929
+ } finally {
74930
+ if (typeof q.close === "function") {
74931
+ try {
74932
+ q.close();
74933
+ } catch (_e) {
74934
+ /* best effort */
74935
+ }
74936
+ }
74937
+ }
74938
+
74939
+ if (sessionId) stream.push({ type: "session", session: { id: sessionId } });
74940
+ stream.push({ type: "done", stopReason, usage });
74941
+ }
74942
+
74943
+ /** @type {import("./BotEngine").BotEngine} */
74944
+ const claudeAgentEngine$1 = {
74945
+ id: "claude-agent",
74946
+ capabilities: { builtInTools: true, skills: true, nativeSessions: true },
74947
+
74948
+ run(ctx) {
74949
+ const stream = createEventStream();
74950
+ (async () => {
74951
+ try {
74952
+ await _runAgent(ctx, stream);
74953
+ } catch (err) {
74954
+ stream.push({
74955
+ type: "error",
74956
+ message: (err && err.message) || "Claude Agent engine error",
74957
+ code: (err && err.code) || "CLAUDE_AGENT_ERROR",
74958
+ });
74959
+ } finally {
74960
+ stream.end();
74961
+ }
74962
+ })();
74963
+ return stream;
74964
+ },
74965
+ };
74966
+
74967
+ claudeAgentEngine$2.exports = claudeAgentEngine$1;
74968
+ claudeAgentEngine$2.exports.__setQueryForTest = __setQueryForTest;
74969
+
74970
+ var claudeAgentEngineExports = claudeAgentEngine$2.exports;
74971
+
74756
74972
  /**
74757
74973
  * engines/index.js
74758
74974
  *
74759
74975
  * Builds the Bot Factory engine registry. Requiring this module registers the
74760
74976
  * built-in engines; consumers resolve them via getEngine(id).
74761
74977
  *
74762
- * At launch only the provider-neutral tool-loop engine is registered (covers
74763
- * Anthropic + OpenAI + xAI via adapters). The Claude Agent SDK engine is a
74764
- * later addition and will register here too.
74978
+ * The provider-neutral tool-loop engine (covers Anthropic + OpenAI + xAI via
74979
+ * adapters) is the default. The Claude Agent SDK engine adds native file/shell
74980
+ * tools + SDK sessions for bots that opt in via their `engine` field.
74765
74981
  */
74766
74982
 
74767
74983
  const { registerEngine, getEngine, listEngines } = BotEngine;
74768
74984
  const toolLoopEngine = toolLoopEngineExports;
74985
+ const claudeAgentEngine = claudeAgentEngineExports;
74769
74986
 
74770
74987
  registerEngine(toolLoopEngine);
74988
+ registerEngine(claudeAgentEngine);
74771
74989
 
74772
74990
  var engines$1 = { getEngine, listEngines, registerEngine };
74773
74991
 
@@ -75093,6 +75311,7 @@ let BotRunner$1 = class BotRunner {
75093
75311
  : null;
75094
75312
 
75095
75313
  const ctx = {
75314
+ botId,
75096
75315
  prompt: opts.prompt,
75097
75316
  model: profile.model,
75098
75317
  credentials: profile.credentials,
@@ -75106,6 +75325,11 @@ let BotRunner$1 = class BotRunner {
75106
75325
  requestPermission,
75107
75326
  executeTool,
75108
75327
  workspaceId: bot.workspaceId,
75328
+ // For engines with their own agent loop + native tools (claude-agent):
75329
+ // a sandbox dir, the approval policy, and a direct approval channel.
75330
+ workingDir: profile.workingDir,
75331
+ approvalPolicy: bot.approvalPolicy,
75332
+ createApproval: (request) => this._approvals.create(request),
75109
75333
  };
75110
75334
 
75111
75335
  for await (const event of engine.run(ctx)) {
@@ -75897,6 +76121,7 @@ var mcpResult = { normalizeMcpResult: normalizeMcpResult$1 };
75897
76121
  * injected/portable modules; this file is the boundary.
75898
76122
  */
75899
76123
 
76124
+ const path$2 = require$$1$2;
75900
76125
  const { Cron } = require$$1$3;
75901
76126
  const { createElectronHost } = host;
75902
76127
  const BotStore = BotStoreExports;
@@ -75982,6 +76207,7 @@ const botController$1 = {
75982
76207
  this._appId = appId;
75983
76208
 
75984
76209
  const host = createElectronHost();
76210
+ this._botsRoot = host.paths && host.paths.botsRoot;
75985
76211
  this._store = new BotStore({
75986
76212
  persistence: host.persistence,
75987
76213
  paths: host.paths,
@@ -76254,11 +76480,17 @@ const botController$1 = {
76254
76480
 
76255
76481
  return {
76256
76482
  providerId,
76257
- engineId: provider.engine,
76483
+ // A bot may pin an engine (e.g. "claude-agent"); otherwise derive it from
76484
+ // the provider (tool-loop for anthropic/openai/xai).
76485
+ engineId: bot.engine || provider.engine,
76258
76486
  adapterId: provider.adapter,
76259
76487
  baseURL: provider.baseURL,
76260
76488
  model,
76261
76489
  credentials,
76490
+ // Sandbox dir for engines with native file/shell tools (claude-agent).
76491
+ workingDir: this._botsRoot
76492
+ ? path$2.join(this._botsRoot, bot.id, "files")
76493
+ : undefined,
76262
76494
  };
76263
76495
  },
76264
76496