@trops/dash-core 0.1.504 → 0.1.506
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/electron/index.js +628 -297
- package/dist/electron/index.js.map +1 -1
- package/dist/index.esm.js +11 -1
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +11 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/electron/index.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
var require$$0$1 = require('electron');
|
|
4
4
|
var require$$1$1 = require('path');
|
|
5
5
|
var require$$0$2 = require('fs');
|
|
6
|
-
var require$$
|
|
6
|
+
var require$$9$1 = require('objects-to-csv');
|
|
7
7
|
var require$$1$2 = require('readline');
|
|
8
8
|
var require$$2 = require('xtreamer');
|
|
9
9
|
var require$$3$1 = require('xml2js');
|
|
@@ -11,7 +11,7 @@ var require$$4 = require('JSONStream');
|
|
|
11
11
|
var require$$5 = require('stream');
|
|
12
12
|
var require$$6 = require('csv-parser');
|
|
13
13
|
var require$$0$3 = require('quickjs-emscripten');
|
|
14
|
-
var require$$
|
|
14
|
+
var require$$11 = require('https');
|
|
15
15
|
var require$$0$5 = require('@modelcontextprotocol/sdk/client/index.js');
|
|
16
16
|
var require$$1$3 = require('@modelcontextprotocol/sdk/client/stdio.js');
|
|
17
17
|
var require$$0$4 = require('pkce-challenge');
|
|
@@ -28,13 +28,13 @@ var require$$0$7 = require('openai');
|
|
|
28
28
|
require('live-plugin-manager');
|
|
29
29
|
var require$$0$a = require('@anthropic-ai/sdk');
|
|
30
30
|
var require$$3$4 = require('crypto');
|
|
31
|
-
var require$$8$
|
|
31
|
+
var require$$8$1 = require('zod');
|
|
32
32
|
var require$$0$8 = require('http');
|
|
33
33
|
var require$$1$5 = require('http2');
|
|
34
34
|
var require$$2$4 = require('node-forge');
|
|
35
35
|
var require$$0$9 = require('css');
|
|
36
36
|
var require$$1$6 = require('node-vibrant/node');
|
|
37
|
-
var require$$
|
|
37
|
+
var require$$3$5 = require('ws');
|
|
38
38
|
|
|
39
39
|
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
|
|
40
40
|
|
|
@@ -1054,7 +1054,7 @@ var secureStoreController$1 = {
|
|
|
1054
1054
|
decryptString,
|
|
1055
1055
|
};
|
|
1056
1056
|
|
|
1057
|
-
const path$
|
|
1057
|
+
const path$n = require$$1$1;
|
|
1058
1058
|
const {
|
|
1059
1059
|
readFileSync,
|
|
1060
1060
|
writeFileSync: writeFileSync$3,
|
|
@@ -1072,7 +1072,7 @@ const {
|
|
|
1072
1072
|
function ensureDirectoryExistence$1(filePath) {
|
|
1073
1073
|
try {
|
|
1074
1074
|
// isDirectory
|
|
1075
|
-
var dirname = path$
|
|
1075
|
+
var dirname = path$n.dirname(filePath);
|
|
1076
1076
|
// check if the directory exists...return true
|
|
1077
1077
|
// if not, we can pass in the dirname as the filepath
|
|
1078
1078
|
// and check each directory recursively.
|
|
@@ -1187,7 +1187,7 @@ function removeFilesFromDirectory(directory, excludeFiles = []) {
|
|
|
1187
1187
|
|
|
1188
1188
|
for (const file of files) {
|
|
1189
1189
|
if (!excludeFiles.includes(file)) {
|
|
1190
|
-
unlinkSync(path$
|
|
1190
|
+
unlinkSync(path$n.join(directory, file), (err) => {
|
|
1191
1191
|
if (err) throw err;
|
|
1192
1192
|
});
|
|
1193
1193
|
}
|
|
@@ -1204,8 +1204,8 @@ var file = {
|
|
|
1204
1204
|
checkDirectory: checkDirectory$1,
|
|
1205
1205
|
};
|
|
1206
1206
|
|
|
1207
|
-
const { app: app$
|
|
1208
|
-
const path$
|
|
1207
|
+
const { app: app$f } = require$$0$1;
|
|
1208
|
+
const path$m = require$$1$1;
|
|
1209
1209
|
const { writeFileSync: writeFileSync$2 } = require$$0$2;
|
|
1210
1210
|
const { getFileContents: getFileContents$7 } = file;
|
|
1211
1211
|
|
|
@@ -1252,8 +1252,8 @@ const workspaceController$3 = {
|
|
|
1252
1252
|
saveWorkspaceForApplication: (win, appId, workspaceObject) => {
|
|
1253
1253
|
try {
|
|
1254
1254
|
// filename to the pages file (live pages)
|
|
1255
|
-
const filename = path$
|
|
1256
|
-
app$
|
|
1255
|
+
const filename = path$m.join(
|
|
1256
|
+
app$f.getPath("userData"),
|
|
1257
1257
|
appName$7,
|
|
1258
1258
|
appId,
|
|
1259
1259
|
configFilename$5,
|
|
@@ -1301,8 +1301,8 @@ const workspaceController$3 = {
|
|
|
1301
1301
|
saveMenuItemsForApplication: (win, appId, menuItems) => {
|
|
1302
1302
|
try {
|
|
1303
1303
|
// filename to the workspaces file
|
|
1304
|
-
const filename = path$
|
|
1305
|
-
app$
|
|
1304
|
+
const filename = path$m.join(
|
|
1305
|
+
app$f.getPath("userData"),
|
|
1306
1306
|
appName$7,
|
|
1307
1307
|
appId,
|
|
1308
1308
|
configFilename$5,
|
|
@@ -1350,8 +1350,8 @@ const workspaceController$3 = {
|
|
|
1350
1350
|
*/
|
|
1351
1351
|
deleteWorkspaceForApplication: (win, appId, workspaceId) => {
|
|
1352
1352
|
try {
|
|
1353
|
-
const filename = path$
|
|
1354
|
-
app$
|
|
1353
|
+
const filename = path$m.join(
|
|
1354
|
+
app$f.getPath("userData"),
|
|
1355
1355
|
appName$7,
|
|
1356
1356
|
appId,
|
|
1357
1357
|
configFilename$5,
|
|
@@ -1384,8 +1384,8 @@ const workspaceController$3 = {
|
|
|
1384
1384
|
|
|
1385
1385
|
listWorkspacesForApplication: (win, appId) => {
|
|
1386
1386
|
try {
|
|
1387
|
-
const filename = path$
|
|
1388
|
-
app$
|
|
1387
|
+
const filename = path$m.join(
|
|
1388
|
+
app$f.getPath("userData"),
|
|
1389
1389
|
appName$7,
|
|
1390
1390
|
appId,
|
|
1391
1391
|
configFilename$5,
|
|
@@ -1412,8 +1412,8 @@ const workspaceController$3 = {
|
|
|
1412
1412
|
|
|
1413
1413
|
listMenuItemsForApplication: (win, appId) => {
|
|
1414
1414
|
try {
|
|
1415
|
-
const filename = path$
|
|
1416
|
-
app$
|
|
1415
|
+
const filename = path$m.join(
|
|
1416
|
+
app$f.getPath("userData"),
|
|
1417
1417
|
appName$7,
|
|
1418
1418
|
appId,
|
|
1419
1419
|
configFilename$5,
|
|
@@ -1456,8 +1456,8 @@ const workspaceController$3 = {
|
|
|
1456
1456
|
|
|
1457
1457
|
var workspaceController_1 = workspaceController$3;
|
|
1458
1458
|
|
|
1459
|
-
const { app: app$
|
|
1460
|
-
const path$
|
|
1459
|
+
const { app: app$e } = require$$0$1;
|
|
1460
|
+
const path$l = require$$1$1;
|
|
1461
1461
|
const { writeFileSync: writeFileSync$1 } = require$$0$2;
|
|
1462
1462
|
const { getFileContents: getFileContents$6 } = file;
|
|
1463
1463
|
|
|
@@ -1477,8 +1477,8 @@ const themeController$5 = {
|
|
|
1477
1477
|
saveThemeForApplication: (win, appId, name, obj) => {
|
|
1478
1478
|
try {
|
|
1479
1479
|
// filename to the pages file (live pages)
|
|
1480
|
-
const filename = path$
|
|
1481
|
-
app$
|
|
1480
|
+
const filename = path$l.join(
|
|
1481
|
+
app$e.getPath("userData"),
|
|
1482
1482
|
appName$6,
|
|
1483
1483
|
appId,
|
|
1484
1484
|
configFilename$4,
|
|
@@ -1523,8 +1523,8 @@ const themeController$5 = {
|
|
|
1523
1523
|
*/
|
|
1524
1524
|
listThemesForApplication: (win, appId) => {
|
|
1525
1525
|
try {
|
|
1526
|
-
const filename = path$
|
|
1527
|
-
app$
|
|
1526
|
+
const filename = path$l.join(
|
|
1527
|
+
app$e.getPath("userData"),
|
|
1528
1528
|
appName$6,
|
|
1529
1529
|
appId,
|
|
1530
1530
|
configFilename$4,
|
|
@@ -1565,8 +1565,8 @@ const themeController$5 = {
|
|
|
1565
1565
|
*/
|
|
1566
1566
|
deleteThemeForApplication: (win, appId, themeKey) => {
|
|
1567
1567
|
try {
|
|
1568
|
-
const filename = path$
|
|
1569
|
-
app$
|
|
1568
|
+
const filename = path$l.join(
|
|
1569
|
+
app$e.getPath("userData"),
|
|
1570
1570
|
appName$6,
|
|
1571
1571
|
appId,
|
|
1572
1572
|
configFilename$4,
|
|
@@ -1642,9 +1642,9 @@ var themeController_1 = themeController$5;
|
|
|
1642
1642
|
* `/data/`.
|
|
1643
1643
|
*/
|
|
1644
1644
|
|
|
1645
|
-
const path$
|
|
1646
|
-
const fs$
|
|
1647
|
-
const { app: app$
|
|
1645
|
+
const path$k = require$$1$1;
|
|
1646
|
+
const fs$f = require$$0$2;
|
|
1647
|
+
const { app: app$d } = require$$0$1;
|
|
1648
1648
|
|
|
1649
1649
|
const APP_NAME = "Dashboard";
|
|
1650
1650
|
|
|
@@ -1653,10 +1653,10 @@ const APP_NAME = "Dashboard";
|
|
|
1653
1653
|
* @returns {string[]} ordered allowed roots for that category
|
|
1654
1654
|
*/
|
|
1655
1655
|
function getAllowedRoots$2(category) {
|
|
1656
|
-
const userData = app$
|
|
1656
|
+
const userData = app$d.getPath("userData");
|
|
1657
1657
|
switch (category) {
|
|
1658
1658
|
case "data": {
|
|
1659
|
-
const def = path$
|
|
1659
|
+
const def = path$k.join(userData, APP_NAME, "data");
|
|
1660
1660
|
// The user can configure a custom data directory in
|
|
1661
1661
|
// Settings → General → Data Directory. If set, that
|
|
1662
1662
|
// location is ALSO an allowed root. We don't replace the
|
|
@@ -1666,13 +1666,13 @@ function getAllowedRoots$2(category) {
|
|
|
1666
1666
|
return override ? [def, override] : [def];
|
|
1667
1667
|
}
|
|
1668
1668
|
case "themes":
|
|
1669
|
-
return [path$
|
|
1669
|
+
return [path$k.join(userData, APP_NAME, "themes")];
|
|
1670
1670
|
case "widgets":
|
|
1671
|
-
return [path$
|
|
1671
|
+
return [path$k.join(userData, "widgets")];
|
|
1672
1672
|
case "plugins":
|
|
1673
|
-
return [path$
|
|
1673
|
+
return [path$k.join(userData, "plugins")];
|
|
1674
1674
|
case "downloads":
|
|
1675
|
-
return [app$
|
|
1675
|
+
return [app$d.getPath("downloads")];
|
|
1676
1676
|
default:
|
|
1677
1677
|
throw new Error("safePath: unknown allowed-roots category: " + category);
|
|
1678
1678
|
}
|
|
@@ -1687,13 +1687,13 @@ function getAllowedRoots$2(category) {
|
|
|
1687
1687
|
*/
|
|
1688
1688
|
function readDataDirectoryFromSettings() {
|
|
1689
1689
|
try {
|
|
1690
|
-
const settingsPath = path$
|
|
1691
|
-
app$
|
|
1690
|
+
const settingsPath = path$k.join(
|
|
1691
|
+
app$d.getPath("userData"),
|
|
1692
1692
|
APP_NAME,
|
|
1693
1693
|
"settings.json",
|
|
1694
1694
|
);
|
|
1695
|
-
if (!fs$
|
|
1696
|
-
const raw = fs$
|
|
1695
|
+
if (!fs$f.existsSync(settingsPath)) return undefined;
|
|
1696
|
+
const raw = fs$f.readFileSync(settingsPath, "utf8");
|
|
1697
1697
|
const settings = JSON.parse(raw);
|
|
1698
1698
|
const dir = settings && settings.dataDirectory;
|
|
1699
1699
|
if (typeof dir === "string" && dir) return dir;
|
|
@@ -1719,18 +1719,18 @@ function safePath$3(requested, allowedRoots) {
|
|
|
1719
1719
|
throw new Error("safePath: allowedRoots must be a non-empty array");
|
|
1720
1720
|
}
|
|
1721
1721
|
|
|
1722
|
-
const resolved = path$
|
|
1722
|
+
const resolved = path$k.resolve(requested);
|
|
1723
1723
|
|
|
1724
1724
|
// Real-path through symlinks. If the file doesn't exist yet (a
|
|
1725
1725
|
// create-new operation), real-path the parent so a symlink in the
|
|
1726
1726
|
// parent chain can't trick us.
|
|
1727
1727
|
let real = resolved;
|
|
1728
1728
|
try {
|
|
1729
|
-
real = fs$
|
|
1729
|
+
real = fs$f.realpathSync(resolved);
|
|
1730
1730
|
} catch (_e) {
|
|
1731
1731
|
try {
|
|
1732
|
-
const parent = fs$
|
|
1733
|
-
real = path$
|
|
1732
|
+
const parent = fs$f.realpathSync(path$k.dirname(resolved));
|
|
1733
|
+
real = path$k.join(parent, path$k.basename(resolved));
|
|
1734
1734
|
} catch (_e2) {
|
|
1735
1735
|
// Parent doesn't exist either. Use the resolved-but-not-
|
|
1736
1736
|
// real path; the caller's mkdirSync will happen inside the
|
|
@@ -1742,14 +1742,14 @@ function safePath$3(requested, allowedRoots) {
|
|
|
1742
1742
|
for (const root of allowedRoots) {
|
|
1743
1743
|
let realRoot = root;
|
|
1744
1744
|
try {
|
|
1745
|
-
if (fs$
|
|
1745
|
+
if (fs$f.existsSync(root)) realRoot = fs$f.realpathSync(root);
|
|
1746
1746
|
} catch (_e) {
|
|
1747
1747
|
// root doesn't exist or isn't reachable — keep as-is for
|
|
1748
1748
|
// the comparison below
|
|
1749
1749
|
}
|
|
1750
1750
|
// Exact match OR strictly-inside (with separator to prevent
|
|
1751
1751
|
// /data-evil/ matching /data/).
|
|
1752
|
-
if (real === realRoot || real.startsWith(realRoot + path$
|
|
1752
|
+
if (real === realRoot || real.startsWith(realRoot + path$k.sep)) {
|
|
1753
1753
|
return real;
|
|
1754
1754
|
}
|
|
1755
1755
|
}
|
|
@@ -1810,9 +1810,9 @@ var safePath_1 = {
|
|
|
1810
1810
|
* clearCache() → void // test-only
|
|
1811
1811
|
*/
|
|
1812
1812
|
|
|
1813
|
-
const fs$
|
|
1814
|
-
const path$
|
|
1815
|
-
const { app: app$
|
|
1813
|
+
const fs$e = require$$0$2;
|
|
1814
|
+
const path$j = require$$1$1;
|
|
1815
|
+
const { app: app$c } = require$$0$1;
|
|
1816
1816
|
|
|
1817
1817
|
const FILE_NAME = "widgetMcpGrants.json";
|
|
1818
1818
|
|
|
@@ -1821,14 +1821,14 @@ const FILE_NAME = "widgetMcpGrants.json";
|
|
|
1821
1821
|
let _cache$1 = null;
|
|
1822
1822
|
|
|
1823
1823
|
function grantsFilePath() {
|
|
1824
|
-
return path$
|
|
1824
|
+
return path$j.join(app$c.getPath("userData"), FILE_NAME);
|
|
1825
1825
|
}
|
|
1826
1826
|
|
|
1827
1827
|
function loadFromDisk() {
|
|
1828
1828
|
const p = grantsFilePath();
|
|
1829
|
-
if (!fs$
|
|
1829
|
+
if (!fs$e.existsSync(p)) return {};
|
|
1830
1830
|
try {
|
|
1831
|
-
const raw = fs$
|
|
1831
|
+
const raw = fs$e.readFileSync(p, "utf8");
|
|
1832
1832
|
const parsed = JSON.parse(raw);
|
|
1833
1833
|
if (!parsed || typeof parsed !== "object") return {};
|
|
1834
1834
|
return parsed;
|
|
@@ -1848,9 +1848,9 @@ function writeToDisk(data) {
|
|
|
1848
1848
|
const tmp = p + ".tmp";
|
|
1849
1849
|
// Ensure parent dir exists (userData should already, but be defensive
|
|
1850
1850
|
// for first-launch / freshly-cleared profile cases).
|
|
1851
|
-
fs$
|
|
1852
|
-
fs$
|
|
1853
|
-
fs$
|
|
1851
|
+
fs$e.mkdirSync(path$j.dirname(p), { recursive: true });
|
|
1852
|
+
fs$e.writeFileSync(tmp, JSON.stringify(data, null, 2), "utf8");
|
|
1853
|
+
fs$e.renameSync(tmp, p);
|
|
1854
1854
|
}
|
|
1855
1855
|
|
|
1856
1856
|
// Recognized origins for a persisted grant.
|
|
@@ -1935,6 +1935,12 @@ function sanitizePerms(perms) {
|
|
|
1935
1935
|
? raw.writePaths.filter((p) => typeof p === "string")
|
|
1936
1936
|
: [],
|
|
1937
1937
|
};
|
|
1938
|
+
} else if (name === "network") {
|
|
1939
|
+
domains.network = {
|
|
1940
|
+
hosts: Array.isArray(raw.hosts)
|
|
1941
|
+
? raw.hosts.filter((h) => typeof h === "string")
|
|
1942
|
+
: [],
|
|
1943
|
+
};
|
|
1938
1944
|
}
|
|
1939
1945
|
// Future domains plug in here. Unknown domain names are dropped.
|
|
1940
1946
|
}
|
|
@@ -1952,13 +1958,13 @@ function sanitizePerms(perms) {
|
|
|
1952
1958
|
return out;
|
|
1953
1959
|
}
|
|
1954
1960
|
|
|
1955
|
-
function getGrant$
|
|
1961
|
+
function getGrant$4(widgetId) {
|
|
1956
1962
|
if (typeof widgetId !== "string" || !widgetId) return null;
|
|
1957
1963
|
const all = ensureCache();
|
|
1958
1964
|
return all[widgetId] || null;
|
|
1959
1965
|
}
|
|
1960
1966
|
|
|
1961
|
-
function setGrant$
|
|
1967
|
+
function setGrant$4(widgetId, perms) {
|
|
1962
1968
|
if (typeof widgetId !== "string" || !widgetId) return false;
|
|
1963
1969
|
const sanitized = sanitizePerms(perms);
|
|
1964
1970
|
if (!sanitized) return false;
|
|
@@ -2039,8 +2045,8 @@ function clearCache$1() {
|
|
|
2039
2045
|
}
|
|
2040
2046
|
|
|
2041
2047
|
var grantedPermissions = {
|
|
2042
|
-
getGrant: getGrant$
|
|
2043
|
-
setGrant: setGrant$
|
|
2048
|
+
getGrant: getGrant$4,
|
|
2049
|
+
setGrant: setGrant$4,
|
|
2044
2050
|
revokeGrant: revokeGrant$1,
|
|
2045
2051
|
revokeServer: revokeServer$1,
|
|
2046
2052
|
listAllGrants: listAllGrants$1,
|
|
@@ -2159,7 +2165,7 @@ function validateRequest(req) {
|
|
|
2159
2165
|
*
|
|
2160
2166
|
* `scope` informs the caller how to write the resulting grant.
|
|
2161
2167
|
*/
|
|
2162
|
-
function requestApproval$
|
|
2168
|
+
function requestApproval$3(req, opts = {}) {
|
|
2163
2169
|
const validation = validateRequest(req);
|
|
2164
2170
|
if (validation) {
|
|
2165
2171
|
return Promise.reject(new Error(validation));
|
|
@@ -2251,7 +2257,7 @@ function setupJitConsentHandlers() {
|
|
|
2251
2257
|
}
|
|
2252
2258
|
|
|
2253
2259
|
var jitConsent$1 = {
|
|
2254
|
-
requestApproval: requestApproval$
|
|
2260
|
+
requestApproval: requestApproval$3,
|
|
2255
2261
|
setupJitConsentHandlers,
|
|
2256
2262
|
_handleResponse,
|
|
2257
2263
|
_resetForTest,
|
|
@@ -2295,8 +2301,8 @@ var jitConsent$1 = {
|
|
|
2295
2301
|
* read-only entry) stay synchronous.
|
|
2296
2302
|
*/
|
|
2297
2303
|
|
|
2298
|
-
const { getGrant: getGrant$
|
|
2299
|
-
const { requestApproval: requestApproval$
|
|
2304
|
+
const { getGrant: getGrant$3, setGrant: setGrant$3 } = grantedPermissions;
|
|
2305
|
+
const { requestApproval: requestApproval$2 } = jitConsent$1;
|
|
2300
2306
|
|
|
2301
2307
|
// Action names treated as writes. Anything not in this set is a read.
|
|
2302
2308
|
// Conservative — when in doubt, classify as a read so write-protected
|
|
@@ -2315,7 +2321,7 @@ function isFsWriteAction(action) {
|
|
|
2315
2321
|
return WRITE_ACTIONS.has(action);
|
|
2316
2322
|
}
|
|
2317
2323
|
|
|
2318
|
-
function _isNoGrantDenial$
|
|
2324
|
+
function _isNoGrantDenial$2(reason) {
|
|
2319
2325
|
return (
|
|
2320
2326
|
typeof reason === "string" && /no fs permissions granted/i.test(reason)
|
|
2321
2327
|
);
|
|
@@ -2352,7 +2358,7 @@ function gateFsCall$1({ widgetId, action, args }) {
|
|
|
2352
2358
|
};
|
|
2353
2359
|
}
|
|
2354
2360
|
|
|
2355
|
-
const grant = getGrant$
|
|
2361
|
+
const grant = getGrant$3(widgetId);
|
|
2356
2362
|
const fsPerms = grant && grant.domains && grant.domains.fs;
|
|
2357
2363
|
if (!fsPerms) {
|
|
2358
2364
|
return {
|
|
@@ -2453,11 +2459,11 @@ async function gateFsCallWithJit$1(req, opts = {}) {
|
|
|
2453
2459
|
const initial = gateFsCall$1(req);
|
|
2454
2460
|
if (initial.allow) return initial;
|
|
2455
2461
|
if (!opts.enableJit) return initial;
|
|
2456
|
-
if (!_isNoGrantDenial$
|
|
2462
|
+
if (!_isNoGrantDenial$2(initial.reason)) return initial;
|
|
2457
2463
|
|
|
2458
2464
|
let decision;
|
|
2459
2465
|
try {
|
|
2460
|
-
decision = await requestApproval$
|
|
2466
|
+
decision = await requestApproval$2(
|
|
2461
2467
|
{
|
|
2462
2468
|
widgetId: req.widgetId,
|
|
2463
2469
|
domain: "fs",
|
|
@@ -2506,9 +2512,9 @@ async function gateFsCallWithJit$1(req, opts = {}) {
|
|
|
2506
2512
|
addition.grantOrigin = "live";
|
|
2507
2513
|
|
|
2508
2514
|
try {
|
|
2509
|
-
const current = getGrant$
|
|
2515
|
+
const current = getGrant$3(req.widgetId);
|
|
2510
2516
|
const merged = _mergeFsGrant(current, addition);
|
|
2511
|
-
setGrant$
|
|
2517
|
+
setGrant$3(req.widgetId, merged);
|
|
2512
2518
|
} catch (e) {
|
|
2513
2519
|
return {
|
|
2514
2520
|
allow: false,
|
|
@@ -2528,6 +2534,232 @@ var fsGate = {
|
|
|
2528
2534
|
WRITE_ACTIONS,
|
|
2529
2535
|
};
|
|
2530
2536
|
|
|
2537
|
+
/**
|
|
2538
|
+
* networkGate.js
|
|
2539
|
+
*
|
|
2540
|
+
* Per-widget gate for outbound-network IPC actions (Phase 3 of JIT
|
|
2541
|
+
* consent). Same shape as `fsGate.js` but for hostname-based scoping.
|
|
2542
|
+
*
|
|
2543
|
+
* Channels currently gated by this:
|
|
2544
|
+
* - readDataFromURL (dataController) — fetch a URL into a file
|
|
2545
|
+
* - wsConnect (webSocketController) — open a WebSocket
|
|
2546
|
+
*
|
|
2547
|
+
* Channels NOT gated:
|
|
2548
|
+
* - WS_SEND/DISCONNECT/STATUS/GET_ALL — operate on already-authorized
|
|
2549
|
+
* connections, intentionally shared across widgets via the
|
|
2550
|
+
* `consumers: Set<webContentsId>` design.
|
|
2551
|
+
* - THEME_EXTRACT_FROM_URL — admin-only callers (Settings panels);
|
|
2552
|
+
* no widget caller exists in the codebase.
|
|
2553
|
+
*
|
|
2554
|
+
* Grant shape (under `grant.domains.network`):
|
|
2555
|
+
* {
|
|
2556
|
+
* hosts: ["api.example.com", "*", ...]
|
|
2557
|
+
* }
|
|
2558
|
+
*
|
|
2559
|
+
* Hostname matching:
|
|
2560
|
+
* - Exact match (case-insensitive)
|
|
2561
|
+
* - "*" wildcard in the grant matches any host (escape hatch;
|
|
2562
|
+
* surfaced in the JIT modal as "no host scope — risky")
|
|
2563
|
+
* - Subdomain wildcards ("*.example.com") are NOT supported in this
|
|
2564
|
+
* slice — deferred to a follow-up.
|
|
2565
|
+
*
|
|
2566
|
+
* URL parsing uses the WHATWG URL constructor. Malformed URLs deny
|
|
2567
|
+
* synchronously and do NOT escalate to JIT (a JIT prompt would let a
|
|
2568
|
+
* widget probe URL parser quirks, which we'd rather not).
|
|
2569
|
+
*
|
|
2570
|
+
* JIT escalation: when the runtime calls `gateNetworkCallWithJit` and
|
|
2571
|
+
* the gate denies for "no network permissions granted", a
|
|
2572
|
+
* permission-required IPC fires and the user's response is merged
|
|
2573
|
+
* into the persisted grant. Other denial reasons (host not in
|
|
2574
|
+
* allowlist, malformed url, missing url) stay synchronous.
|
|
2575
|
+
*/
|
|
2576
|
+
|
|
2577
|
+
const { getGrant: getGrant$2, setGrant: setGrant$2 } = grantedPermissions;
|
|
2578
|
+
const { requestApproval: requestApproval$1 } = jitConsent$1;
|
|
2579
|
+
|
|
2580
|
+
function _isNoGrantDenial$1(reason) {
|
|
2581
|
+
return (
|
|
2582
|
+
typeof reason === "string" && /no network permissions granted/i.test(reason)
|
|
2583
|
+
);
|
|
2584
|
+
}
|
|
2585
|
+
|
|
2586
|
+
function _hostMatches(host, allowedList) {
|
|
2587
|
+
if (!Array.isArray(allowedList) || allowedList.length === 0) return false;
|
|
2588
|
+
if (allowedList.includes("*")) return true;
|
|
2589
|
+
const lower = host.toLowerCase();
|
|
2590
|
+
return allowedList.some(
|
|
2591
|
+
(h) => typeof h === "string" && h.toLowerCase() === lower,
|
|
2592
|
+
);
|
|
2593
|
+
}
|
|
2594
|
+
|
|
2595
|
+
function _parseHost(url) {
|
|
2596
|
+
try {
|
|
2597
|
+
return new URL(url).hostname;
|
|
2598
|
+
} catch {
|
|
2599
|
+
return null;
|
|
2600
|
+
}
|
|
2601
|
+
}
|
|
2602
|
+
|
|
2603
|
+
/**
|
|
2604
|
+
* Synchronous gate evaluation.
|
|
2605
|
+
* @returns {{ allow: true } | { allow: false, reason: string }}
|
|
2606
|
+
*/
|
|
2607
|
+
function gateNetworkCall$2({ widgetId, action, args }) {
|
|
2608
|
+
if (!widgetId) {
|
|
2609
|
+
return {
|
|
2610
|
+
allow: false,
|
|
2611
|
+
reason: "no widgetId supplied; cannot determine network permissions",
|
|
2612
|
+
};
|
|
2613
|
+
}
|
|
2614
|
+
|
|
2615
|
+
const url = args && typeof args === "object" ? args.url : null;
|
|
2616
|
+
if (typeof url !== "string" || !url) {
|
|
2617
|
+
return {
|
|
2618
|
+
allow: false,
|
|
2619
|
+
reason:
|
|
2620
|
+
"network gate: action '" +
|
|
2621
|
+
action +
|
|
2622
|
+
"' requires args.url (got: " +
|
|
2623
|
+
JSON.stringify(url) +
|
|
2624
|
+
")",
|
|
2625
|
+
};
|
|
2626
|
+
}
|
|
2627
|
+
|
|
2628
|
+
const host = _parseHost(url);
|
|
2629
|
+
if (!host) {
|
|
2630
|
+
return {
|
|
2631
|
+
allow: false,
|
|
2632
|
+
reason: "network gate: malformed url '" + url + "'",
|
|
2633
|
+
};
|
|
2634
|
+
}
|
|
2635
|
+
|
|
2636
|
+
const grant = getGrant$2(widgetId);
|
|
2637
|
+
const netPerms = grant && grant.domains && grant.domains.network;
|
|
2638
|
+
if (!netPerms) {
|
|
2639
|
+
return {
|
|
2640
|
+
allow: false,
|
|
2641
|
+
reason:
|
|
2642
|
+
"widget '" +
|
|
2643
|
+
widgetId +
|
|
2644
|
+
"' has no network permissions granted; user must approve at runtime or in Settings → Privacy & Security",
|
|
2645
|
+
};
|
|
2646
|
+
}
|
|
2647
|
+
|
|
2648
|
+
if (_hostMatches(host, netPerms.hosts)) {
|
|
2649
|
+
return { allow: true };
|
|
2650
|
+
}
|
|
2651
|
+
return {
|
|
2652
|
+
allow: false,
|
|
2653
|
+
reason:
|
|
2654
|
+
"network gate: host '" +
|
|
2655
|
+
host +
|
|
2656
|
+
"' rejected — not in allowed hosts for widget '" +
|
|
2657
|
+
widgetId +
|
|
2658
|
+
"'",
|
|
2659
|
+
};
|
|
2660
|
+
}
|
|
2661
|
+
|
|
2662
|
+
/**
|
|
2663
|
+
* Merge an approved JIT decision's grant into the widget's existing
|
|
2664
|
+
* grant under domains.network. Mirrors fsGate._mergeFsGrant.
|
|
2665
|
+
*/
|
|
2666
|
+
function _mergeNetworkGrant(current, addition) {
|
|
2667
|
+
const out = {
|
|
2668
|
+
grantOrigin: addition.grantOrigin || current?.grantOrigin || null,
|
|
2669
|
+
servers: { ...(current?.servers || {}) },
|
|
2670
|
+
domains: { ...(current?.domains || {}) },
|
|
2671
|
+
};
|
|
2672
|
+
const additionNet = addition?.domains?.network;
|
|
2673
|
+
if (additionNet) {
|
|
2674
|
+
const existingNet = out.domains.network || { hosts: [] };
|
|
2675
|
+
out.domains.network = {
|
|
2676
|
+
hosts: [
|
|
2677
|
+
...new Set([
|
|
2678
|
+
...(existingNet.hosts || []),
|
|
2679
|
+
...(Array.isArray(additionNet.hosts) ? additionNet.hosts : []),
|
|
2680
|
+
]),
|
|
2681
|
+
],
|
|
2682
|
+
};
|
|
2683
|
+
}
|
|
2684
|
+
return out;
|
|
2685
|
+
}
|
|
2686
|
+
|
|
2687
|
+
/**
|
|
2688
|
+
* Async gate that escalates "no network grant" denials to a JIT
|
|
2689
|
+
* consent prompt when `opts.enableJit` is true. On approval, merges
|
|
2690
|
+
* the decision's grant blob into the persisted grant and re-evaluates.
|
|
2691
|
+
*/
|
|
2692
|
+
async function gateNetworkCallWithJit$2(req, opts = {}) {
|
|
2693
|
+
const initial = gateNetworkCall$2(req);
|
|
2694
|
+
if (initial.allow) return initial;
|
|
2695
|
+
if (!opts.enableJit) return initial;
|
|
2696
|
+
if (!_isNoGrantDenial$1(initial.reason)) return initial;
|
|
2697
|
+
|
|
2698
|
+
let decision;
|
|
2699
|
+
try {
|
|
2700
|
+
decision = await requestApproval$1(
|
|
2701
|
+
{
|
|
2702
|
+
widgetId: req.widgetId,
|
|
2703
|
+
domain: "network",
|
|
2704
|
+
action: req.action,
|
|
2705
|
+
args: req.args || {},
|
|
2706
|
+
},
|
|
2707
|
+
{ timeoutMs: opts.timeoutMs },
|
|
2708
|
+
);
|
|
2709
|
+
} catch (e) {
|
|
2710
|
+
return {
|
|
2711
|
+
allow: false,
|
|
2712
|
+
reason:
|
|
2713
|
+
"JIT consent " +
|
|
2714
|
+
(e && e.message ? e.message : "failed") +
|
|
2715
|
+
"; original denial: " +
|
|
2716
|
+
initial.reason,
|
|
2717
|
+
};
|
|
2718
|
+
}
|
|
2719
|
+
|
|
2720
|
+
if (!decision || decision.approve !== true) {
|
|
2721
|
+
return {
|
|
2722
|
+
allow: false,
|
|
2723
|
+
reason:
|
|
2724
|
+
"user declined JIT consent for widget '" +
|
|
2725
|
+
req.widgetId +
|
|
2726
|
+
"' calling network '" +
|
|
2727
|
+
req.action +
|
|
2728
|
+
"'",
|
|
2729
|
+
};
|
|
2730
|
+
}
|
|
2731
|
+
|
|
2732
|
+
const host = _parseHost(req.args?.url) || "*";
|
|
2733
|
+
const addition =
|
|
2734
|
+
decision.granted && typeof decision.granted === "object"
|
|
2735
|
+
? decision.granted
|
|
2736
|
+
: {
|
|
2737
|
+
grantOrigin: "live",
|
|
2738
|
+
domains: { network: { hosts: [host] } },
|
|
2739
|
+
};
|
|
2740
|
+
addition.grantOrigin = "live";
|
|
2741
|
+
|
|
2742
|
+
try {
|
|
2743
|
+
const current = getGrant$2(req.widgetId);
|
|
2744
|
+
const merged = _mergeNetworkGrant(current, addition);
|
|
2745
|
+
setGrant$2(req.widgetId, merged);
|
|
2746
|
+
} catch (e) {
|
|
2747
|
+
return {
|
|
2748
|
+
allow: false,
|
|
2749
|
+
reason:
|
|
2750
|
+
"JIT consent: failed to persist network grant: " +
|
|
2751
|
+
(e && e.message ? e.message : String(e)),
|
|
2752
|
+
};
|
|
2753
|
+
}
|
|
2754
|
+
|
|
2755
|
+
return gateNetworkCall$2(req);
|
|
2756
|
+
}
|
|
2757
|
+
|
|
2758
|
+
var networkGate = {
|
|
2759
|
+
gateNetworkCall: gateNetworkCall$2,
|
|
2760
|
+
gateNetworkCallWithJit: gateNetworkCallWithJit$2,
|
|
2761
|
+
};
|
|
2762
|
+
|
|
2531
2763
|
/**
|
|
2532
2764
|
* securityFlags.js
|
|
2533
2765
|
*
|
|
@@ -2549,15 +2781,15 @@ var fsGate = {
|
|
|
2549
2781
|
* settings.json IO.
|
|
2550
2782
|
*/
|
|
2551
2783
|
|
|
2552
|
-
function readEnforceFlag$
|
|
2784
|
+
function readEnforceFlag$3(settings) {
|
|
2553
2785
|
return settings?.security?.enforceWidgetMcpPermissions !== false;
|
|
2554
2786
|
}
|
|
2555
2787
|
|
|
2556
|
-
function readJitFlag$
|
|
2788
|
+
function readJitFlag$3(settings) {
|
|
2557
2789
|
return settings?.security?.enableJitConsent !== false;
|
|
2558
2790
|
}
|
|
2559
2791
|
|
|
2560
|
-
var securityFlags = { readEnforceFlag: readEnforceFlag$
|
|
2792
|
+
var securityFlags = { readEnforceFlag: readEnforceFlag$3, readJitFlag: readJitFlag$3 };
|
|
2561
2793
|
|
|
2562
2794
|
/**
|
|
2563
2795
|
* safeJsExecutor.js
|
|
@@ -3258,28 +3490,32 @@ function requireTransform () {
|
|
|
3258
3490
|
return transform;
|
|
3259
3491
|
}
|
|
3260
3492
|
|
|
3261
|
-
const { app: app$
|
|
3262
|
-
var fs$
|
|
3263
|
-
const path$
|
|
3493
|
+
const { app: app$b } = require$$0$1;
|
|
3494
|
+
var fs$d = require$$0$2;
|
|
3495
|
+
const path$i = require$$1$1;
|
|
3264
3496
|
const events$5 = events$8;
|
|
3265
3497
|
const { getFileContents: getFileContents$5, writeToFile: writeToFile$2 } = file;
|
|
3266
3498
|
const { safePath: safePath$2, getAllowedRoots: getAllowedRoots$1 } = safePath_1;
|
|
3267
3499
|
const { gateFsCall, gateFsCallWithJit } = fsGate;
|
|
3268
|
-
const {
|
|
3500
|
+
const {
|
|
3501
|
+
gateNetworkCall: gateNetworkCall$1,
|
|
3502
|
+
gateNetworkCallWithJit: gateNetworkCallWithJit$1,
|
|
3503
|
+
} = networkGate;
|
|
3504
|
+
const { readEnforceFlag: readEnforceFlag$2, readJitFlag: readJitFlag$2 } = securityFlags;
|
|
3269
3505
|
|
|
3270
3506
|
// Reads the enforcement + JIT flags from settings.json. Mirrors the
|
|
3271
3507
|
// helper in mcpController. The flag is shared across MCP and fs domains
|
|
3272
3508
|
// — see Phase 2 plan for rationale (the cosmetic rename to a
|
|
3273
3509
|
// domain-neutral name is a separate slice).
|
|
3274
|
-
function _loadFlags() {
|
|
3510
|
+
function _loadFlags$1() {
|
|
3275
3511
|
try {
|
|
3276
|
-
const settingsPath = path$
|
|
3277
|
-
app$
|
|
3512
|
+
const settingsPath = path$i.join(
|
|
3513
|
+
app$b.getPath("userData"),
|
|
3278
3514
|
appName$5,
|
|
3279
3515
|
"settings.json",
|
|
3280
3516
|
);
|
|
3281
|
-
if (!fs$
|
|
3282
|
-
return JSON.parse(fs$
|
|
3517
|
+
if (!fs$d.existsSync(settingsPath)) return null;
|
|
3518
|
+
return JSON.parse(fs$d.readFileSync(settingsPath, "utf8"));
|
|
3283
3519
|
} catch (_e) {
|
|
3284
3520
|
return null;
|
|
3285
3521
|
}
|
|
@@ -3293,10 +3529,10 @@ function _loadFlags() {
|
|
|
3293
3529
|
* @returns {Promise<boolean>}
|
|
3294
3530
|
*/
|
|
3295
3531
|
async function _runFsGate(win, action, widgetId, args, errorEvent) {
|
|
3296
|
-
const settings = _loadFlags();
|
|
3297
|
-
if (!readEnforceFlag$
|
|
3532
|
+
const settings = _loadFlags$1();
|
|
3533
|
+
if (!readEnforceFlag$2(settings)) return true; // gate disabled
|
|
3298
3534
|
if (!widgetId) return true; // legacy callers without widgetId — see plan
|
|
3299
|
-
const gate = readJitFlag$
|
|
3535
|
+
const gate = readJitFlag$2(settings)
|
|
3300
3536
|
? await gateFsCallWithJit({ widgetId, action, args }, { enableJit: true })
|
|
3301
3537
|
: gateFsCall({ widgetId, action, args });
|
|
3302
3538
|
if (gate.allow) return true;
|
|
@@ -3309,10 +3545,34 @@ async function _runFsGate(win, action, widgetId, args, errorEvent) {
|
|
|
3309
3545
|
return false;
|
|
3310
3546
|
}
|
|
3311
3547
|
|
|
3548
|
+
/**
|
|
3549
|
+
* Phase 3 network gate. Same shape as _runFsGate but for outbound
|
|
3550
|
+
* URLs. Mirrors fs's "disabled / no widgetId / sync vs async" branching.
|
|
3551
|
+
*/
|
|
3552
|
+
async function _runNetworkGate$1(win, action, widgetId, args, errorEvent) {
|
|
3553
|
+
const settings = _loadFlags$1();
|
|
3554
|
+
if (!readEnforceFlag$2(settings)) return true;
|
|
3555
|
+
if (!widgetId) return true;
|
|
3556
|
+
const gate = readJitFlag$2(settings)
|
|
3557
|
+
? await gateNetworkCallWithJit$1(
|
|
3558
|
+
{ widgetId, action, args },
|
|
3559
|
+
{ enableJit: true },
|
|
3560
|
+
)
|
|
3561
|
+
: gateNetworkCall$1({ widgetId, action, args });
|
|
3562
|
+
if (gate.allow) return true;
|
|
3563
|
+
if (win && errorEvent) {
|
|
3564
|
+
win.webContents.send(errorEvent, {
|
|
3565
|
+
success: false,
|
|
3566
|
+
message: "network permission gate: " + gate.reason,
|
|
3567
|
+
});
|
|
3568
|
+
}
|
|
3569
|
+
return false;
|
|
3570
|
+
}
|
|
3571
|
+
|
|
3312
3572
|
// Convert Json to Csv
|
|
3313
|
-
const ObjectsToCsv = require$$
|
|
3573
|
+
const ObjectsToCsv = require$$9$1;
|
|
3314
3574
|
const Transform = requireTransform();
|
|
3315
|
-
const https$3 = require$$
|
|
3575
|
+
const https$3 = require$$11;
|
|
3316
3576
|
const appName$5 = "Dashboard";
|
|
3317
3577
|
|
|
3318
3578
|
const dataController$1 = {
|
|
@@ -3329,8 +3589,8 @@ const dataController$1 = {
|
|
|
3329
3589
|
// Validate the renderer-supplied filename is contained within
|
|
3330
3590
|
// the data directory. path.join doesn't reject `..` segments;
|
|
3331
3591
|
// safePath does.
|
|
3332
|
-
const candidate = path$
|
|
3333
|
-
app$
|
|
3592
|
+
const candidate = path$i.join(
|
|
3593
|
+
app$b.getPath("userData"),
|
|
3334
3594
|
appName$5,
|
|
3335
3595
|
appId,
|
|
3336
3596
|
"data",
|
|
@@ -3468,7 +3728,18 @@ const dataController$1 = {
|
|
|
3468
3728
|
}
|
|
3469
3729
|
},
|
|
3470
3730
|
|
|
3471
|
-
readDataFromURL: (win, url, toFilepath) => {
|
|
3731
|
+
readDataFromURL: async (win, url, toFilepath, widgetId = null) => {
|
|
3732
|
+
// Phase 3 network gate. Runs before HTTPS-protocol + safePath
|
|
3733
|
+
// checks so JIT can prompt the user without leaking URL parser
|
|
3734
|
+
// edge cases through error timing.
|
|
3735
|
+
const gateOk = await _runNetworkGate$1(
|
|
3736
|
+
win,
|
|
3737
|
+
"readDataFromURL",
|
|
3738
|
+
widgetId,
|
|
3739
|
+
{ url },
|
|
3740
|
+
events$5.READ_DATA_URL_ERROR,
|
|
3741
|
+
);
|
|
3742
|
+
if (!gateOk) return;
|
|
3472
3743
|
try {
|
|
3473
3744
|
// Validate URL is https protocol only
|
|
3474
3745
|
let parsedUrl;
|
|
@@ -3488,7 +3759,7 @@ const dataController$1 = {
|
|
|
3488
3759
|
// intent, plus realpath/symlink protection.
|
|
3489
3760
|
const resolvedFilepath = safePath$2(toFilepath, getAllowedRoots$1("data"));
|
|
3490
3761
|
|
|
3491
|
-
const writeStream = fs$
|
|
3762
|
+
const writeStream = fs$d.createWriteStream(resolvedFilepath);
|
|
3492
3763
|
|
|
3493
3764
|
https$3
|
|
3494
3765
|
.get(url, (resp) => {
|
|
@@ -3670,8 +3941,8 @@ const dataController$1 = {
|
|
|
3670
3941
|
if (data) {
|
|
3671
3942
|
// Validate filename is contained within the data directory.
|
|
3672
3943
|
// path.join doesn't reject `..` segments; safePath does.
|
|
3673
|
-
const candidate = path$
|
|
3674
|
-
app$
|
|
3944
|
+
const candidate = path$i.join(
|
|
3945
|
+
app$b.getPath("userData"),
|
|
3675
3946
|
appName$5,
|
|
3676
3947
|
"data",
|
|
3677
3948
|
filename,
|
|
@@ -3772,8 +4043,8 @@ const dataController$1 = {
|
|
|
3772
4043
|
try {
|
|
3773
4044
|
if (filename) {
|
|
3774
4045
|
// filename to the pages file (live pages)
|
|
3775
|
-
const fromFilename = path$
|
|
3776
|
-
app$
|
|
4046
|
+
const fromFilename = path$i.join(
|
|
4047
|
+
app$b.getPath("userData"),
|
|
3777
4048
|
appName$5,
|
|
3778
4049
|
"data",
|
|
3779
4050
|
filename,
|
|
@@ -3853,9 +4124,9 @@ var dataController_1 = dataController$1;
|
|
|
3853
4124
|
* settingsController
|
|
3854
4125
|
*/
|
|
3855
4126
|
|
|
3856
|
-
const { app: app$
|
|
3857
|
-
const path$
|
|
3858
|
-
const fs$
|
|
4127
|
+
const { app: app$a } = require$$0$1;
|
|
4128
|
+
const path$h = require$$1$1;
|
|
4129
|
+
const fs$c = require$$0$2;
|
|
3859
4130
|
const { getFileContents: getFileContents$4, writeToFile: writeToFile$1 } = file;
|
|
3860
4131
|
|
|
3861
4132
|
const configFilename$3 = "settings.json";
|
|
@@ -3863,15 +4134,15 @@ const appName$4 = "Dashboard";
|
|
|
3863
4134
|
|
|
3864
4135
|
// Helper function to recursively copy directory
|
|
3865
4136
|
function copyDirectory(source, destination) {
|
|
3866
|
-
if (!fs$
|
|
3867
|
-
fs$
|
|
4137
|
+
if (!fs$c.existsSync(destination)) {
|
|
4138
|
+
fs$c.mkdirSync(destination, { recursive: true });
|
|
3868
4139
|
}
|
|
3869
4140
|
|
|
3870
|
-
const files = fs$
|
|
4141
|
+
const files = fs$c.readdirSync(source);
|
|
3871
4142
|
for (const file of files) {
|
|
3872
|
-
const srcPath = path$
|
|
3873
|
-
const destPath = path$
|
|
3874
|
-
const stat = fs$
|
|
4143
|
+
const srcPath = path$h.join(source, file);
|
|
4144
|
+
const destPath = path$h.join(destination, file);
|
|
4145
|
+
const stat = fs$c.lstatSync(srcPath);
|
|
3875
4146
|
|
|
3876
4147
|
// Skip symlinks to prevent following links to sensitive files
|
|
3877
4148
|
if (stat.isSymbolicLink()) {
|
|
@@ -3882,7 +4153,7 @@ function copyDirectory(source, destination) {
|
|
|
3882
4153
|
if (stat.isDirectory()) {
|
|
3883
4154
|
copyDirectory(srcPath, destPath);
|
|
3884
4155
|
} else {
|
|
3885
|
-
fs$
|
|
4156
|
+
fs$c.copyFileSync(srcPath, destPath);
|
|
3886
4157
|
}
|
|
3887
4158
|
}
|
|
3888
4159
|
}
|
|
@@ -3898,8 +4169,8 @@ const settingsController$4 = {
|
|
|
3898
4169
|
try {
|
|
3899
4170
|
if (data) {
|
|
3900
4171
|
// <appId>/settings.json
|
|
3901
|
-
const filename = path$
|
|
3902
|
-
app$
|
|
4172
|
+
const filename = path$h.join(
|
|
4173
|
+
app$a.getPath("userData"),
|
|
3903
4174
|
appName$4,
|
|
3904
4175
|
configFilename$3,
|
|
3905
4176
|
);
|
|
@@ -3934,8 +4205,8 @@ const settingsController$4 = {
|
|
|
3934
4205
|
getSettingsForApplication: (win) => {
|
|
3935
4206
|
try {
|
|
3936
4207
|
// <appId>/settings.json
|
|
3937
|
-
const filename = path$
|
|
3938
|
-
app$
|
|
4208
|
+
const filename = path$h.join(
|
|
4209
|
+
app$a.getPath("userData"),
|
|
3939
4210
|
appName$4,
|
|
3940
4211
|
configFilename$3,
|
|
3941
4212
|
);
|
|
@@ -3965,15 +4236,15 @@ const settingsController$4 = {
|
|
|
3965
4236
|
*/
|
|
3966
4237
|
getDataDirectory: (win) => {
|
|
3967
4238
|
try {
|
|
3968
|
-
const settingsPath = path$
|
|
3969
|
-
app$
|
|
4239
|
+
const settingsPath = path$h.join(
|
|
4240
|
+
app$a.getPath("userData"),
|
|
3970
4241
|
appName$4,
|
|
3971
4242
|
configFilename$3,
|
|
3972
4243
|
);
|
|
3973
4244
|
const settings = getFileContents$4(settingsPath, {});
|
|
3974
4245
|
const userDataDir =
|
|
3975
4246
|
settings.userDataDirectory ||
|
|
3976
|
-
path$
|
|
4247
|
+
path$h.join(app$a.getPath("userData"), appName$4);
|
|
3977
4248
|
|
|
3978
4249
|
console.log("[settingsController] Data directory retrieved successfully");
|
|
3979
4250
|
// Return the data for ipcMain.handle() - modern promise-based approach
|
|
@@ -4000,18 +4271,18 @@ const settingsController$4 = {
|
|
|
4000
4271
|
setDataDirectory: (win, newPath) => {
|
|
4001
4272
|
try {
|
|
4002
4273
|
// Validate the path exists and is a directory
|
|
4003
|
-
if (!fs$
|
|
4004
|
-
fs$
|
|
4274
|
+
if (!fs$c.existsSync(newPath)) {
|
|
4275
|
+
fs$c.mkdirSync(newPath, { recursive: true });
|
|
4005
4276
|
}
|
|
4006
4277
|
|
|
4007
|
-
const stats = fs$
|
|
4278
|
+
const stats = fs$c.statSync(newPath);
|
|
4008
4279
|
if (!stats.isDirectory()) {
|
|
4009
4280
|
throw new Error("Path is not a directory");
|
|
4010
4281
|
}
|
|
4011
4282
|
|
|
4012
4283
|
// Update settings
|
|
4013
|
-
const settingsPath = path$
|
|
4014
|
-
app$
|
|
4284
|
+
const settingsPath = path$h.join(
|
|
4285
|
+
app$a.getPath("userData"),
|
|
4015
4286
|
appName$4,
|
|
4016
4287
|
configFilename$3,
|
|
4017
4288
|
);
|
|
@@ -4044,20 +4315,20 @@ const settingsController$4 = {
|
|
|
4044
4315
|
migrateDataDirectory: (win, oldPath, newPath) => {
|
|
4045
4316
|
try {
|
|
4046
4317
|
// Resolve paths to prevent traversal
|
|
4047
|
-
const resolvedOldPath = path$
|
|
4048
|
-
const resolvedNewPath = path$
|
|
4318
|
+
const resolvedOldPath = path$h.resolve(oldPath);
|
|
4319
|
+
const resolvedNewPath = path$h.resolve(newPath);
|
|
4049
4320
|
|
|
4050
4321
|
// Validate oldPath is the current configured data directory
|
|
4051
|
-
const settingsCheckPath = path$
|
|
4052
|
-
app$
|
|
4322
|
+
const settingsCheckPath = path$h.join(
|
|
4323
|
+
app$a.getPath("userData"),
|
|
4053
4324
|
appName$4,
|
|
4054
4325
|
configFilename$3,
|
|
4055
4326
|
);
|
|
4056
4327
|
const currentSettings = getFileContents$4(settingsCheckPath, {});
|
|
4057
4328
|
const currentDataDir =
|
|
4058
4329
|
currentSettings.userDataDirectory ||
|
|
4059
|
-
path$
|
|
4060
|
-
if (resolvedOldPath !== path$
|
|
4330
|
+
path$h.join(app$a.getPath("userData"), appName$4);
|
|
4331
|
+
if (resolvedOldPath !== path$h.resolve(currentDataDir)) {
|
|
4061
4332
|
throw new Error("Source path must be the current data directory");
|
|
4062
4333
|
}
|
|
4063
4334
|
|
|
@@ -4081,20 +4352,20 @@ const settingsController$4 = {
|
|
|
4081
4352
|
}
|
|
4082
4353
|
|
|
4083
4354
|
// Validate paths
|
|
4084
|
-
if (!fs$
|
|
4355
|
+
if (!fs$c.existsSync(resolvedOldPath)) {
|
|
4085
4356
|
throw new Error("Source directory does not exist");
|
|
4086
4357
|
}
|
|
4087
4358
|
|
|
4088
|
-
if (!fs$
|
|
4089
|
-
fs$
|
|
4359
|
+
if (!fs$c.existsSync(resolvedNewPath)) {
|
|
4360
|
+
fs$c.mkdirSync(resolvedNewPath, { recursive: true });
|
|
4090
4361
|
}
|
|
4091
4362
|
|
|
4092
4363
|
// Copy files
|
|
4093
4364
|
copyDirectory(resolvedOldPath, resolvedNewPath);
|
|
4094
4365
|
|
|
4095
4366
|
// Update settings to use new path
|
|
4096
|
-
const settingsPath = path$
|
|
4097
|
-
app$
|
|
4367
|
+
const settingsPath = path$h.join(
|
|
4368
|
+
app$a.getPath("userData"),
|
|
4098
4369
|
appName$4,
|
|
4099
4370
|
configFilename$3,
|
|
4100
4371
|
);
|
|
@@ -4758,8 +5029,8 @@ function requireProviderController () {
|
|
|
4758
5029
|
return providerController_1;
|
|
4759
5030
|
}
|
|
4760
5031
|
|
|
4761
|
-
const { app: app$
|
|
4762
|
-
const path$
|
|
5032
|
+
const { app: app$9 } = require$$0$1;
|
|
5033
|
+
const path$g = require$$1$1;
|
|
4763
5034
|
const events$4 = events$8;
|
|
4764
5035
|
const { getFileContents: getFileContents$3 } = file;
|
|
4765
5036
|
|
|
@@ -4775,8 +5046,8 @@ const layoutController$1 = {
|
|
|
4775
5046
|
*/
|
|
4776
5047
|
listLayoutsForApplication: (win, appId) => {
|
|
4777
5048
|
try {
|
|
4778
|
-
const filename = path$
|
|
4779
|
-
app$
|
|
5049
|
+
const filename = path$g.join(
|
|
5050
|
+
app$9.getPath("userData"),
|
|
4780
5051
|
appName$3,
|
|
4781
5052
|
appId,
|
|
4782
5053
|
configFilename$2,
|
|
@@ -22439,15 +22710,15 @@ const {
|
|
|
22439
22710
|
const {
|
|
22440
22711
|
StreamableHTTPClientTransport,
|
|
22441
22712
|
} = streamableHttp$1;
|
|
22442
|
-
const path$
|
|
22443
|
-
const fs$
|
|
22713
|
+
const path$f = require$$1$1;
|
|
22714
|
+
const fs$b = require$$0$2;
|
|
22444
22715
|
const os$2 = require$$2$1;
|
|
22445
22716
|
const responseCache$2 = responseCache_1;
|
|
22446
22717
|
const { gateToolCall, gateToolCallWithJit } = permissionGate;
|
|
22447
22718
|
const { serverKey, parseServerKey } = mcpServerKey;
|
|
22448
22719
|
const { applyPathScopeToCredentials } = mcpScopeResolver;
|
|
22449
|
-
const { readEnforceFlag, readJitFlag } = securityFlags;
|
|
22450
|
-
const { app: app$
|
|
22720
|
+
const { readEnforceFlag: readEnforceFlag$1, readJitFlag: readJitFlag$1 } = securityFlags;
|
|
22721
|
+
const { app: app$8 } = require$$0$1;
|
|
22451
22722
|
|
|
22452
22723
|
/**
|
|
22453
22724
|
* Load the user's settings.json (or null on absence/parse error). The
|
|
@@ -22456,13 +22727,13 @@ const { app: app$7 } = require$$0$1;
|
|
|
22456
22727
|
*/
|
|
22457
22728
|
function loadSettingsForFlags() {
|
|
22458
22729
|
try {
|
|
22459
|
-
const settingsPath = path$
|
|
22460
|
-
app$
|
|
22730
|
+
const settingsPath = path$f.join(
|
|
22731
|
+
app$8.getPath("userData"),
|
|
22461
22732
|
"Dashboard",
|
|
22462
22733
|
"settings.json",
|
|
22463
22734
|
);
|
|
22464
|
-
if (!fs$
|
|
22465
|
-
const raw = fs$
|
|
22735
|
+
if (!fs$b.existsSync(settingsPath)) return null;
|
|
22736
|
+
const raw = fs$b.readFileSync(settingsPath, "utf8");
|
|
22466
22737
|
return JSON.parse(raw);
|
|
22467
22738
|
} catch (_e) {
|
|
22468
22739
|
return null;
|
|
@@ -22475,13 +22746,13 @@ function loadSettingsForFlags() {
|
|
|
22475
22746
|
// confirm-on-disable dialog. See electron/utils/securityFlags.js for
|
|
22476
22747
|
// the pinned default semantics.
|
|
22477
22748
|
function isWidgetPermissionEnforcementEnabled() {
|
|
22478
|
-
return readEnforceFlag(loadSettingsForFlags());
|
|
22749
|
+
return readEnforceFlag$1(loadSettingsForFlags());
|
|
22479
22750
|
}
|
|
22480
22751
|
|
|
22481
22752
|
// JIT consent flag. **Default ON.** Same semantics as the enforcement
|
|
22482
22753
|
// flag — explicit false to opt out, otherwise on.
|
|
22483
22754
|
function isJitConsentEnabled() {
|
|
22484
|
-
return readJitFlag(loadSettingsForFlags());
|
|
22755
|
+
return readJitFlag$1(loadSettingsForFlags());
|
|
22485
22756
|
}
|
|
22486
22757
|
|
|
22487
22758
|
/**
|
|
@@ -22629,7 +22900,7 @@ function getShellPath$1() {
|
|
|
22629
22900
|
fallbackDirs.push(`${home}/.nodenv/shims`);
|
|
22630
22901
|
try {
|
|
22631
22902
|
const nvmDir = `${home}/.nvm/versions/node`;
|
|
22632
|
-
const versions = fs$
|
|
22903
|
+
const versions = fs$b.readdirSync(nvmDir).sort();
|
|
22633
22904
|
if (versions.length > 0) {
|
|
22634
22905
|
// Find the highest compatible version (v18/v20/v22)
|
|
22635
22906
|
for (let i = versions.length - 1; i >= 0; i--) {
|
|
@@ -22765,15 +23036,15 @@ async function refreshGoogleOAuthToken(tokenRefresh) {
|
|
|
22765
23036
|
const credPath = tokenRefresh.credentialsPath.replace(/^~/, home);
|
|
22766
23037
|
const keysPath = tokenRefresh.oauthKeysPath.replace(/^~/, home);
|
|
22767
23038
|
|
|
22768
|
-
if (!fs$
|
|
23039
|
+
if (!fs$b.existsSync(credPath) || !fs$b.existsSync(keysPath)) {
|
|
22769
23040
|
console.log(
|
|
22770
23041
|
"[mcpController] Token refresh skipped: credential files not found",
|
|
22771
23042
|
);
|
|
22772
23043
|
return;
|
|
22773
23044
|
}
|
|
22774
23045
|
|
|
22775
|
-
const credentials = JSON.parse(fs$
|
|
22776
|
-
const keysFile = JSON.parse(fs$
|
|
23046
|
+
const credentials = JSON.parse(fs$b.readFileSync(credPath, "utf8"));
|
|
23047
|
+
const keysFile = JSON.parse(fs$b.readFileSync(keysPath, "utf8"));
|
|
22777
23048
|
const keyData = keysFile.installed || keysFile.web;
|
|
22778
23049
|
|
|
22779
23050
|
if (
|
|
@@ -22798,7 +23069,7 @@ async function refreshGoogleOAuthToken(tokenRefresh) {
|
|
|
22798
23069
|
|
|
22799
23070
|
console.log("[mcpController] Refreshing Google OAuth token...");
|
|
22800
23071
|
|
|
22801
|
-
const https = require$$
|
|
23072
|
+
const https = require$$11;
|
|
22802
23073
|
const postData = [
|
|
22803
23074
|
`client_id=${encodeURIComponent(keyData.client_id)}`,
|
|
22804
23075
|
`client_secret=${encodeURIComponent(keyData.client_secret)}`,
|
|
@@ -22842,7 +23113,7 @@ async function refreshGoogleOAuthToken(tokenRefresh) {
|
|
|
22842
23113
|
credentials.refresh_token = body.refresh_token;
|
|
22843
23114
|
}
|
|
22844
23115
|
|
|
22845
|
-
fs$
|
|
23116
|
+
fs$b.writeFileSync(credPath, JSON.stringify(credentials, null, 2));
|
|
22846
23117
|
console.log("[mcpController] Google OAuth token refreshed successfully");
|
|
22847
23118
|
}
|
|
22848
23119
|
|
|
@@ -23029,7 +23300,7 @@ const mcpController$3 = {
|
|
|
23029
23300
|
}
|
|
23030
23301
|
|
|
23031
23302
|
// Interpolate {{MCP_DIR}} in args to resolve local MCP server scripts
|
|
23032
|
-
const mcpDir = path$
|
|
23303
|
+
const mcpDir = path$f.join(__dirname, "..", "mcp");
|
|
23033
23304
|
for (let i = 0; i < args.length; i++) {
|
|
23034
23305
|
if (
|
|
23035
23306
|
typeof args[i] === "string" &&
|
|
@@ -23480,20 +23751,20 @@ const mcpController$3 = {
|
|
|
23480
23751
|
*/
|
|
23481
23752
|
getCatalog: (win) => {
|
|
23482
23753
|
try {
|
|
23483
|
-
const catalogPath = path$
|
|
23754
|
+
const catalogPath = path$f.join(
|
|
23484
23755
|
__dirname,
|
|
23485
23756
|
"..",
|
|
23486
23757
|
"mcp",
|
|
23487
23758
|
"mcpServerCatalog.json",
|
|
23488
23759
|
);
|
|
23489
23760
|
|
|
23490
|
-
if (!fs$
|
|
23761
|
+
if (!fs$b.existsSync(catalogPath)) {
|
|
23491
23762
|
return {
|
|
23492
23763
|
catalog: [],
|
|
23493
23764
|
};
|
|
23494
23765
|
}
|
|
23495
23766
|
|
|
23496
|
-
const catalogData = fs$
|
|
23767
|
+
const catalogData = fs$b.readFileSync(catalogPath, "utf8");
|
|
23497
23768
|
const catalog = JSON.parse(catalogData);
|
|
23498
23769
|
|
|
23499
23770
|
return {
|
|
@@ -23521,18 +23792,18 @@ const mcpController$3 = {
|
|
|
23521
23792
|
*/
|
|
23522
23793
|
getKnownExternalCatalog: () => {
|
|
23523
23794
|
try {
|
|
23524
|
-
const catalogPath = path$
|
|
23795
|
+
const catalogPath = path$f.join(
|
|
23525
23796
|
__dirname,
|
|
23526
23797
|
"..",
|
|
23527
23798
|
"mcp",
|
|
23528
23799
|
"knownExternalMcpServers.json",
|
|
23529
23800
|
);
|
|
23530
23801
|
|
|
23531
|
-
if (!fs$
|
|
23802
|
+
if (!fs$b.existsSync(catalogPath)) {
|
|
23532
23803
|
return { success: true, servers: [] };
|
|
23533
23804
|
}
|
|
23534
23805
|
|
|
23535
|
-
const catalogData = fs$
|
|
23806
|
+
const catalogData = fs$b.readFileSync(catalogPath, "utf8");
|
|
23536
23807
|
const catalog = JSON.parse(catalogData);
|
|
23537
23808
|
|
|
23538
23809
|
return {
|
|
@@ -23597,8 +23868,8 @@ const mcpController$3 = {
|
|
|
23597
23868
|
const destPath = to.replace(/^~/, os$2.homedir());
|
|
23598
23869
|
const destDir = require$$1$1.dirname(destPath);
|
|
23599
23870
|
try {
|
|
23600
|
-
fs$
|
|
23601
|
-
fs$
|
|
23871
|
+
fs$b.mkdirSync(destDir, { recursive: true });
|
|
23872
|
+
fs$b.copyFileSync(sourcePath, destPath);
|
|
23602
23873
|
} catch (err) {
|
|
23603
23874
|
return {
|
|
23604
23875
|
error: true,
|
|
@@ -23634,7 +23905,7 @@ const mcpController$3 = {
|
|
|
23634
23905
|
}
|
|
23635
23906
|
|
|
23636
23907
|
// Interpolate {{MCP_DIR}} in authCommand args (same as startServer)
|
|
23637
|
-
const mcpDir = path$
|
|
23908
|
+
const mcpDir = path$f.join(__dirname, "..", "mcp");
|
|
23638
23909
|
const resolvedArgs = (authCommand.args || []).map((arg) =>
|
|
23639
23910
|
typeof arg === "string" && arg.includes("{{MCP_DIR}}")
|
|
23640
23911
|
? arg.replace(/\{\{MCP_DIR\}\}/g, mcpDir)
|
|
@@ -24182,8 +24453,8 @@ function commonjsRequire(path) {
|
|
|
24182
24453
|
* Runs in the Electron main process at widget install time.
|
|
24183
24454
|
*/
|
|
24184
24455
|
|
|
24185
|
-
const fs$
|
|
24186
|
-
const path$
|
|
24456
|
+
const fs$a = require$$0$2;
|
|
24457
|
+
const path$e = require$$1$1;
|
|
24187
24458
|
|
|
24188
24459
|
/**
|
|
24189
24460
|
* Structured error thrown by compileWidget() when the underlying
|
|
@@ -24218,7 +24489,7 @@ function getEsbuildDiagnostics() {
|
|
|
24218
24489
|
|
|
24219
24490
|
try {
|
|
24220
24491
|
const pkgJsonPath = require.resolve("esbuild/package.json");
|
|
24221
|
-
diagnostics.esbuildPackageDir = path$
|
|
24492
|
+
diagnostics.esbuildPackageDir = path$e.dirname(pkgJsonPath);
|
|
24222
24493
|
diagnostics.esbuildVersion = commonjsRequire(pkgJsonPath).version;
|
|
24223
24494
|
} catch (err) {
|
|
24224
24495
|
diagnostics.esbuildResolveError = err.message;
|
|
@@ -24228,15 +24499,15 @@ function getEsbuildDiagnostics() {
|
|
|
24228
24499
|
const archPkgJson = require.resolve(
|
|
24229
24500
|
`${diagnostics.archPackage}/package.json`,
|
|
24230
24501
|
);
|
|
24231
|
-
const archDir = path$
|
|
24502
|
+
const archDir = path$e.dirname(archPkgJson);
|
|
24232
24503
|
// esbuild's native binary on macOS/Linux is bin/esbuild;
|
|
24233
24504
|
// on Windows it's esbuild.exe at the package root.
|
|
24234
24505
|
const candidate =
|
|
24235
24506
|
process.platform === "win32"
|
|
24236
|
-
? path$
|
|
24237
|
-
: path$
|
|
24507
|
+
? path$e.join(archDir, "esbuild.exe")
|
|
24508
|
+
: path$e.join(archDir, "bin", "esbuild");
|
|
24238
24509
|
diagnostics.nativeBinaryPath = candidate;
|
|
24239
|
-
diagnostics.nativeBinaryExists = fs$
|
|
24510
|
+
diagnostics.nativeBinaryExists = fs$a.existsSync(candidate);
|
|
24240
24511
|
} catch (err) {
|
|
24241
24512
|
diagnostics.archResolveError = err.message;
|
|
24242
24513
|
}
|
|
@@ -24282,26 +24553,26 @@ async function healthCheck() {
|
|
|
24282
24553
|
* @returns {string|null} Path to the widgets/ directory, or null
|
|
24283
24554
|
*/
|
|
24284
24555
|
function findWidgetsDir$2(widgetPath) {
|
|
24285
|
-
const direct = path$
|
|
24286
|
-
if (fs$
|
|
24556
|
+
const direct = path$e.join(widgetPath, "widgets");
|
|
24557
|
+
if (fs$a.existsSync(direct)) {
|
|
24287
24558
|
return direct;
|
|
24288
24559
|
}
|
|
24289
24560
|
|
|
24290
24561
|
// Check configs/widgets/ (packageZip.js nests .dash.js files here)
|
|
24291
|
-
const configsWidgets = path$
|
|
24292
|
-
if (fs$
|
|
24562
|
+
const configsWidgets = path$e.join(widgetPath, "configs", "widgets");
|
|
24563
|
+
if (fs$a.existsSync(configsWidgets)) {
|
|
24293
24564
|
return configsWidgets;
|
|
24294
24565
|
}
|
|
24295
24566
|
|
|
24296
24567
|
// Check configs/ directory (used by packageZip.js for distributed widgets)
|
|
24297
|
-
const configs = path$
|
|
24298
|
-
if (fs$
|
|
24568
|
+
const configs = path$e.join(widgetPath, "configs");
|
|
24569
|
+
if (fs$a.existsSync(configs)) {
|
|
24299
24570
|
return configs;
|
|
24300
24571
|
}
|
|
24301
24572
|
|
|
24302
24573
|
// Check one level deeper for nested ZIP extraction
|
|
24303
24574
|
try {
|
|
24304
|
-
const entries = fs$
|
|
24575
|
+
const entries = fs$a.readdirSync(widgetPath, { withFileTypes: true });
|
|
24305
24576
|
const subdirs = entries.filter(
|
|
24306
24577
|
(e) =>
|
|
24307
24578
|
e.isDirectory() &&
|
|
@@ -24311,8 +24582,8 @@ function findWidgetsDir$2(widgetPath) {
|
|
|
24311
24582
|
);
|
|
24312
24583
|
|
|
24313
24584
|
for (const subdir of subdirs) {
|
|
24314
|
-
const nested = path$
|
|
24315
|
-
if (fs$
|
|
24585
|
+
const nested = path$e.join(widgetPath, subdir.name, "widgets");
|
|
24586
|
+
if (fs$a.existsSync(nested)) {
|
|
24316
24587
|
console.log(`[WidgetCompiler] Found nested widgets/ at ${nested}`);
|
|
24317
24588
|
return nested;
|
|
24318
24589
|
}
|
|
@@ -24346,7 +24617,7 @@ async function compileWidget$1(widgetPath) {
|
|
|
24346
24617
|
}
|
|
24347
24618
|
|
|
24348
24619
|
// Discover .dash.js config files
|
|
24349
|
-
const files = fs$
|
|
24620
|
+
const files = fs$a.readdirSync(widgetsDir);
|
|
24350
24621
|
const dashFiles = files.filter((f) => f.endsWith(".dash.js"));
|
|
24351
24622
|
|
|
24352
24623
|
if (dashFiles.length === 0) {
|
|
@@ -24360,15 +24631,15 @@ async function compileWidget$1(widgetPath) {
|
|
|
24360
24631
|
// Compute relative path from the entry file (in widgetPath) to widgetsDir,
|
|
24361
24632
|
// since widgetsDir may be nested (e.g., ./weather-widget/widgets/).
|
|
24362
24633
|
const relWidgetsDir =
|
|
24363
|
-
"./" + path$
|
|
24634
|
+
"./" + path$e.relative(widgetPath, widgetsDir).split(path$e.sep).join("/");
|
|
24364
24635
|
const imports = [];
|
|
24365
24636
|
const exportParts = [];
|
|
24366
24637
|
|
|
24367
24638
|
for (const dashFile of dashFiles) {
|
|
24368
24639
|
const componentName = dashFile.replace(".dash.js", "");
|
|
24369
24640
|
const componentFile = `${componentName}.js`;
|
|
24370
|
-
const componentFilePath = path$
|
|
24371
|
-
const hasComponent = fs$
|
|
24641
|
+
const componentFilePath = path$e.join(widgetsDir, componentFile);
|
|
24642
|
+
const hasComponent = fs$a.existsSync(componentFilePath);
|
|
24372
24643
|
|
|
24373
24644
|
// Import the config (always)
|
|
24374
24645
|
imports.push(
|
|
@@ -24400,17 +24671,17 @@ async function compileWidget$1(widgetPath) {
|
|
|
24400
24671
|
const entryContent = [...imports, "", ...exportParts, ""].join("\n");
|
|
24401
24672
|
|
|
24402
24673
|
// Write temporary entry file in the widget root
|
|
24403
|
-
const entryPath = path$
|
|
24404
|
-
const distDir = path$
|
|
24405
|
-
const outPath = path$
|
|
24674
|
+
const entryPath = path$e.join(widgetPath, "__compile_entry.js");
|
|
24675
|
+
const distDir = path$e.join(widgetPath, "dist");
|
|
24676
|
+
const outPath = path$e.join(distDir, "index.cjs.js");
|
|
24406
24677
|
|
|
24407
24678
|
try {
|
|
24408
24679
|
// Ensure dist/ directory exists
|
|
24409
|
-
if (!fs$
|
|
24410
|
-
fs$
|
|
24680
|
+
if (!fs$a.existsSync(distDir)) {
|
|
24681
|
+
fs$a.mkdirSync(distDir, { recursive: true });
|
|
24411
24682
|
}
|
|
24412
24683
|
|
|
24413
|
-
fs$
|
|
24684
|
+
fs$a.writeFileSync(entryPath, entryContent, "utf8");
|
|
24414
24685
|
|
|
24415
24686
|
console.log(
|
|
24416
24687
|
`[WidgetCompiler] Compiling ${dashFiles.length} component(s) from ${widgetPath}`,
|
|
@@ -24466,8 +24737,8 @@ async function compileWidget$1(widgetPath) {
|
|
|
24466
24737
|
} finally {
|
|
24467
24738
|
// Clean up temporary entry file
|
|
24468
24739
|
try {
|
|
24469
|
-
if (fs$
|
|
24470
|
-
fs$
|
|
24740
|
+
if (fs$a.existsSync(entryPath)) {
|
|
24741
|
+
fs$a.unlinkSync(entryPath);
|
|
24471
24742
|
}
|
|
24472
24743
|
} catch (cleanupError) {
|
|
24473
24744
|
// Non-fatal
|
|
@@ -24499,8 +24770,8 @@ var widgetCompiler$1 = {
|
|
|
24499
24770
|
* Integrates with ComponentManager for automatic registration
|
|
24500
24771
|
*/
|
|
24501
24772
|
|
|
24502
|
-
const fs$
|
|
24503
|
-
const path$
|
|
24773
|
+
const fs$9 = require$$0$2;
|
|
24774
|
+
const path$d = require$$1$1;
|
|
24504
24775
|
const vm = require$$2$2;
|
|
24505
24776
|
const { findWidgetsDir: findWidgetsDir$1 } = widgetCompiler$1;
|
|
24506
24777
|
|
|
@@ -24588,14 +24859,14 @@ class DynamicWidgetLoader {
|
|
|
24588
24859
|
);
|
|
24589
24860
|
|
|
24590
24861
|
const widgetsDir =
|
|
24591
|
-
findWidgetsDir$1(widgetPath) || path$
|
|
24592
|
-
const componentPath = path$
|
|
24593
|
-
const configPath = path$
|
|
24862
|
+
findWidgetsDir$1(widgetPath) || path$d.join(widgetPath, "widgets");
|
|
24863
|
+
const componentPath = path$d.join(widgetsDir, `${componentName}.js`);
|
|
24864
|
+
const configPath = path$d.join(widgetsDir, `${componentName}.dash.js`);
|
|
24594
24865
|
|
|
24595
|
-
if (!fs$
|
|
24866
|
+
if (!fs$9.existsSync(componentPath)) {
|
|
24596
24867
|
throw new Error(`Component file not found: ${componentPath}`);
|
|
24597
24868
|
}
|
|
24598
|
-
if (!fs$
|
|
24869
|
+
if (!fs$9.existsSync(configPath)) {
|
|
24599
24870
|
throw new Error(`Config file not found: ${configPath}`);
|
|
24600
24871
|
}
|
|
24601
24872
|
|
|
@@ -24646,7 +24917,7 @@ class DynamicWidgetLoader {
|
|
|
24646
24917
|
*/
|
|
24647
24918
|
async loadConfigFile(configPath) {
|
|
24648
24919
|
try {
|
|
24649
|
-
const source = fs$
|
|
24920
|
+
const source = fs$9.readFileSync(configPath, "utf8");
|
|
24650
24921
|
|
|
24651
24922
|
let exportMatch = source.match(/export\s+default\s+({[\s\S]*});?\s*$/);
|
|
24652
24923
|
|
|
@@ -24714,7 +24985,7 @@ class DynamicWidgetLoader {
|
|
|
24714
24985
|
return [];
|
|
24715
24986
|
}
|
|
24716
24987
|
|
|
24717
|
-
const files = fs$
|
|
24988
|
+
const files = fs$9.readdirSync(widgetsDir);
|
|
24718
24989
|
const widgets = new Set();
|
|
24719
24990
|
|
|
24720
24991
|
files.forEach((file) => {
|
|
@@ -24790,10 +25061,10 @@ var dynamicWidgetLoaderExports = dynamicWidgetLoader$3.exports;
|
|
|
24790
25061
|
* Test-only. Drops the in-process cache so tests can re-read.
|
|
24791
25062
|
*/
|
|
24792
25063
|
|
|
24793
|
-
const fs$
|
|
24794
|
-
const path$
|
|
25064
|
+
const fs$8 = require$$0$2;
|
|
25065
|
+
const path$c = require$$1$1;
|
|
24795
25066
|
const os$1 = require$$2$1;
|
|
24796
|
-
const { app: app$
|
|
25067
|
+
const { app: app$7 } = require$$0$1;
|
|
24797
25068
|
|
|
24798
25069
|
// Cache: widgetId → permissions | null. Populated lazily on first
|
|
24799
25070
|
// lookup; invalidated when a widget is installed/uninstalled (the
|
|
@@ -24808,7 +25079,7 @@ function expandHome(p) {
|
|
|
24808
25079
|
if (typeof p !== "string" || !p) return p;
|
|
24809
25080
|
if (p === "~") return os$1.homedir();
|
|
24810
25081
|
if (p.startsWith("~/") || p.startsWith("~\\")) {
|
|
24811
|
-
return path$
|
|
25082
|
+
return path$c.join(os$1.homedir(), p.slice(2));
|
|
24812
25083
|
}
|
|
24813
25084
|
return p;
|
|
24814
25085
|
}
|
|
@@ -24848,10 +25119,10 @@ function parseManifestPermissions(packageJson) {
|
|
|
24848
25119
|
*/
|
|
24849
25120
|
function resolveWidgetPackagePath(widgetId) {
|
|
24850
25121
|
if (typeof widgetId !== "string" || !widgetId) return null;
|
|
24851
|
-
const widgetsRoot = path$
|
|
25122
|
+
const widgetsRoot = path$c.join(app$7.getPath("userData"), "widgets");
|
|
24852
25123
|
// Split scope from name for "@scope/name" form.
|
|
24853
25124
|
const parts = widgetId.startsWith("@") ? widgetId.split("/") : [widgetId];
|
|
24854
|
-
return path$
|
|
25125
|
+
return path$c.join(widgetsRoot, ...parts, "package.json");
|
|
24855
25126
|
}
|
|
24856
25127
|
|
|
24857
25128
|
/**
|
|
@@ -24865,12 +25136,12 @@ function resolveWidgetPackagePath(widgetId) {
|
|
|
24865
25136
|
function getWidgetMcpPermissions$1(widgetId) {
|
|
24866
25137
|
if (_cache.has(widgetId)) return _cache.get(widgetId);
|
|
24867
25138
|
const pkgPath = resolveWidgetPackagePath(widgetId);
|
|
24868
|
-
if (!pkgPath || !fs$
|
|
25139
|
+
if (!pkgPath || !fs$8.existsSync(pkgPath)) {
|
|
24869
25140
|
_cache.set(widgetId, null);
|
|
24870
25141
|
return null;
|
|
24871
25142
|
}
|
|
24872
25143
|
try {
|
|
24873
|
-
const raw = fs$
|
|
25144
|
+
const raw = fs$8.readFileSync(pkgPath, "utf8");
|
|
24874
25145
|
const pkg = JSON.parse(raw);
|
|
24875
25146
|
const perms = parseManifestPermissions(pkg);
|
|
24876
25147
|
_cache.set(widgetId, perms);
|
|
@@ -24919,8 +25190,8 @@ var widgetPermissions = {
|
|
|
24919
25190
|
* (Slices 1-3) is the actual boundary.
|
|
24920
25191
|
*/
|
|
24921
25192
|
|
|
24922
|
-
const fs$
|
|
24923
|
-
const path$
|
|
25193
|
+
const fs$7 = require$$0$2;
|
|
25194
|
+
const path$b = require$$1$1;
|
|
24924
25195
|
|
|
24925
25196
|
const SOURCE_EXTENSIONS = new Set([
|
|
24926
25197
|
".js",
|
|
@@ -24973,24 +25244,24 @@ function readSourceFiles(dir) {
|
|
|
24973
25244
|
function walk(current, relBase) {
|
|
24974
25245
|
let entries;
|
|
24975
25246
|
try {
|
|
24976
|
-
entries = fs$
|
|
25247
|
+
entries = fs$7.readdirSync(current, { withFileTypes: true });
|
|
24977
25248
|
} catch {
|
|
24978
25249
|
return;
|
|
24979
25250
|
}
|
|
24980
25251
|
for (const entry of entries) {
|
|
24981
|
-
const abs = path$
|
|
24982
|
-
const rel = relBase ? path$
|
|
25252
|
+
const abs = path$b.join(current, entry.name);
|
|
25253
|
+
const rel = relBase ? path$b.join(relBase, entry.name) : entry.name;
|
|
24983
25254
|
if (entry.isDirectory()) {
|
|
24984
25255
|
if (skipDirs.has(entry.name)) continue;
|
|
24985
25256
|
walk(abs, rel);
|
|
24986
25257
|
} else if (entry.isFile()) {
|
|
24987
|
-
const ext = path$
|
|
25258
|
+
const ext = path$b.extname(entry.name).toLowerCase();
|
|
24988
25259
|
if (!SOURCE_EXTENSIONS.has(ext)) continue;
|
|
24989
25260
|
if (result.length >= SCAN_FILE_LIMIT) return;
|
|
24990
25261
|
try {
|
|
24991
25262
|
result.push({
|
|
24992
25263
|
relPath: rel,
|
|
24993
|
-
source: fs$
|
|
25264
|
+
source: fs$7.readFileSync(abs, "utf8"),
|
|
24994
25265
|
});
|
|
24995
25266
|
} catch {
|
|
24996
25267
|
// unreadable — skip
|
|
@@ -25010,7 +25281,7 @@ function scanForMcpUsage(input) {
|
|
|
25010
25281
|
let fileList = [];
|
|
25011
25282
|
if (input.files && typeof input.files === "object") {
|
|
25012
25283
|
for (const [relPath, source] of Object.entries(input.files)) {
|
|
25013
|
-
const ext = path$
|
|
25284
|
+
const ext = path$b.extname(relPath).toLowerCase();
|
|
25014
25285
|
if (!SOURCE_EXTENSIONS.has(ext)) continue;
|
|
25015
25286
|
if (typeof source !== "string") continue;
|
|
25016
25287
|
fileList.push({ relPath, source });
|
|
@@ -27146,8 +27417,8 @@ var widgetRegistryExports = widgetRegistry$1.exports;
|
|
|
27146
27417
|
* - Support two-level browsing: packages (bundles) and widgets within packages
|
|
27147
27418
|
*/
|
|
27148
27419
|
|
|
27149
|
-
const path$
|
|
27150
|
-
const fs$
|
|
27420
|
+
const path$a = require$$1$1;
|
|
27421
|
+
const fs$6 = require$$0$2;
|
|
27151
27422
|
const os = require$$2$1;
|
|
27152
27423
|
const { toPackageId } = packageId;
|
|
27153
27424
|
const { getStoredToken: getStoredToken$3 } = registryAuthController$2;
|
|
@@ -27183,7 +27454,7 @@ function getCacheKey() {
|
|
|
27183
27454
|
* Get the local test registry path for dev mode
|
|
27184
27455
|
*/
|
|
27185
27456
|
function getTestRegistryPath() {
|
|
27186
|
-
return path$
|
|
27457
|
+
return path$a.join(__dirname, "..", "registry", "test-registry-index.json");
|
|
27187
27458
|
}
|
|
27188
27459
|
|
|
27189
27460
|
/**
|
|
@@ -27223,12 +27494,12 @@ async function fetchRegistryIndex(forceRefresh = false) {
|
|
|
27223
27494
|
if (isDev()) {
|
|
27224
27495
|
// In dev mode, try local test file first
|
|
27225
27496
|
const testPath = getTestRegistryPath();
|
|
27226
|
-
if (fs$
|
|
27497
|
+
if (fs$6.existsSync(testPath)) {
|
|
27227
27498
|
console.log(
|
|
27228
27499
|
"[RegistryController] Loading test registry from:",
|
|
27229
27500
|
testPath,
|
|
27230
27501
|
);
|
|
27231
|
-
const raw = fs$
|
|
27502
|
+
const raw = fs$6.readFileSync(testPath, "utf8");
|
|
27232
27503
|
indexData = JSON.parse(raw);
|
|
27233
27504
|
} else {
|
|
27234
27505
|
// Fall back to API (supports DASH_REGISTRY_URL as full-URL override)
|
|
@@ -27641,7 +27912,7 @@ async function fetchPackageSource(packageName, componentName = null) {
|
|
|
27641
27912
|
|
|
27642
27913
|
const zip = new AdmZip(buffer);
|
|
27643
27914
|
const safeName = (pkg.name || "pkg").replace(/[^a-zA-Z0-9-_]/g, "_");
|
|
27644
|
-
const tempDir = path$
|
|
27915
|
+
const tempDir = path$a.join(
|
|
27645
27916
|
os.tmpdir(),
|
|
27646
27917
|
`dash-registry-preview-${safeName}-${Date.now()}`,
|
|
27647
27918
|
);
|
|
@@ -27650,13 +27921,13 @@ async function fetchPackageSource(packageName, componentName = null) {
|
|
|
27650
27921
|
validateZipEntries(zip, tempDir);
|
|
27651
27922
|
zip.extractAllTo(tempDir, true);
|
|
27652
27923
|
|
|
27653
|
-
const widgetsDir = path$
|
|
27924
|
+
const widgetsDir = path$a.join(tempDir, "widgets");
|
|
27654
27925
|
let componentCode = "";
|
|
27655
27926
|
let configCode = "";
|
|
27656
27927
|
let widgetName = null;
|
|
27657
27928
|
|
|
27658
|
-
if (fs$
|
|
27659
|
-
const files = fs$
|
|
27929
|
+
if (fs$6.existsSync(widgetsDir)) {
|
|
27930
|
+
const files = fs$6.readdirSync(widgetsDir);
|
|
27660
27931
|
const dashFiles = files.filter((f) => f.endsWith(".dash.js"));
|
|
27661
27932
|
const componentFiles = files.filter(
|
|
27662
27933
|
(f) => f.endsWith(".js") && !f.endsWith(".dash.js") && f !== "index.js",
|
|
@@ -27678,7 +27949,7 @@ async function fetchPackageSource(packageName, componentName = null) {
|
|
|
27678
27949
|
if (!configFile) configFile = dashFiles[0];
|
|
27679
27950
|
|
|
27680
27951
|
if (configFile) {
|
|
27681
|
-
configCode = fs$
|
|
27952
|
+
configCode = fs$6.readFileSync(path$a.join(widgetsDir, configFile), "utf8");
|
|
27682
27953
|
widgetName = configFile.replace(/\.dash\.js$/, "");
|
|
27683
27954
|
}
|
|
27684
27955
|
|
|
@@ -27692,8 +27963,8 @@ async function fetchPackageSource(packageName, componentName = null) {
|
|
|
27692
27963
|
if (!componentFile) componentFile = componentFiles[0];
|
|
27693
27964
|
|
|
27694
27965
|
if (componentFile) {
|
|
27695
|
-
componentCode = fs$
|
|
27696
|
-
path$
|
|
27966
|
+
componentCode = fs$6.readFileSync(
|
|
27967
|
+
path$a.join(widgetsDir, componentFile),
|
|
27697
27968
|
"utf8",
|
|
27698
27969
|
);
|
|
27699
27970
|
if (!widgetName) widgetName = componentFile.replace(/\.js$/, "");
|
|
@@ -27701,16 +27972,16 @@ async function fetchPackageSource(packageName, componentName = null) {
|
|
|
27701
27972
|
}
|
|
27702
27973
|
|
|
27703
27974
|
let bundleSource = null;
|
|
27704
|
-
const bundlePath = path$
|
|
27705
|
-
if (fs$
|
|
27706
|
-
bundleSource = fs$
|
|
27975
|
+
const bundlePath = path$a.join(tempDir, "dist", "index.cjs.js");
|
|
27976
|
+
if (fs$6.existsSync(bundlePath)) {
|
|
27977
|
+
bundleSource = fs$6.readFileSync(bundlePath, "utf8");
|
|
27707
27978
|
}
|
|
27708
27979
|
|
|
27709
27980
|
let dashMeta = {};
|
|
27710
|
-
const dashPath = path$
|
|
27711
|
-
if (fs$
|
|
27981
|
+
const dashPath = path$a.join(tempDir, "dash.json");
|
|
27982
|
+
if (fs$6.existsSync(dashPath)) {
|
|
27712
27983
|
try {
|
|
27713
|
-
dashMeta = JSON.parse(fs$
|
|
27984
|
+
dashMeta = JSON.parse(fs$6.readFileSync(dashPath, "utf8"));
|
|
27714
27985
|
} catch {
|
|
27715
27986
|
// Ignore — metadata is optional for preview
|
|
27716
27987
|
}
|
|
@@ -27729,7 +28000,7 @@ async function fetchPackageSource(packageName, componentName = null) {
|
|
|
27729
28000
|
};
|
|
27730
28001
|
} finally {
|
|
27731
28002
|
try {
|
|
27732
|
-
fs$
|
|
28003
|
+
fs$6.rmSync(tempDir, { recursive: true, force: true });
|
|
27733
28004
|
} catch (err) {
|
|
27734
28005
|
console.warn(
|
|
27735
28006
|
`[RegistryController] Failed to clean up preview temp dir ${tempDir}:`,
|
|
@@ -27749,10 +28020,10 @@ var registryController$3 = {
|
|
|
27749
28020
|
fetchPackageSource,
|
|
27750
28021
|
};
|
|
27751
28022
|
|
|
27752
|
-
var fs$
|
|
28023
|
+
var fs$5 = require$$0$2;
|
|
27753
28024
|
var JSONStream = require$$4;
|
|
27754
28025
|
const algoliasearch$1 = require$$2$3;
|
|
27755
|
-
const path$
|
|
28026
|
+
const path$9 = require$$3$3;
|
|
27756
28027
|
const { ensureDirectoryExistence, checkDirectory } = file;
|
|
27757
28028
|
|
|
27758
28029
|
let AlgoliaIndex$1 = class AlgoliaIndex {
|
|
@@ -27790,7 +28061,7 @@ let AlgoliaIndex$1 = class AlgoliaIndex {
|
|
|
27790
28061
|
var batchNumber = 1;
|
|
27791
28062
|
|
|
27792
28063
|
// create the readStream to parse the large file (json)
|
|
27793
|
-
var readStream = fs$
|
|
28064
|
+
var readStream = fs$5.createReadStream(filepath).pipe(parser);
|
|
27794
28065
|
|
|
27795
28066
|
var batch = [];
|
|
27796
28067
|
|
|
@@ -27804,7 +28075,7 @@ let AlgoliaIndex$1 = class AlgoliaIndex {
|
|
|
27804
28075
|
// lets write to the batch file
|
|
27805
28076
|
if (countForBatch === batchSize) {
|
|
27806
28077
|
// write to the batch file
|
|
27807
|
-
var writeStream = fs$
|
|
28078
|
+
var writeStream = fs$5.createWriteStream(
|
|
27808
28079
|
batchFilepath + "/batch_" + batchNumber + ".json",
|
|
27809
28080
|
);
|
|
27810
28081
|
writeStream.write(JSON.stringify(batch));
|
|
@@ -27855,11 +28126,11 @@ let AlgoliaIndex$1 = class AlgoliaIndex {
|
|
|
27855
28126
|
return new Promise((resolve, reject) => {
|
|
27856
28127
|
try {
|
|
27857
28128
|
checkDirectory(directoryPath);
|
|
27858
|
-
fs$
|
|
28129
|
+
fs$5.readdir(directoryPath, (err, files) => {
|
|
27859
28130
|
if (err) reject(err);
|
|
27860
28131
|
if (files) {
|
|
27861
28132
|
files.forEach((file) => {
|
|
27862
|
-
fs$
|
|
28133
|
+
fs$5.unlinkSync(path$9.join(directoryPath, file));
|
|
27863
28134
|
});
|
|
27864
28135
|
resolve();
|
|
27865
28136
|
}
|
|
@@ -27878,11 +28149,11 @@ let AlgoliaIndex$1 = class AlgoliaIndex {
|
|
|
27878
28149
|
) {
|
|
27879
28150
|
try {
|
|
27880
28151
|
// read the directory...
|
|
27881
|
-
const files = await fs$
|
|
28152
|
+
const files = await fs$5.readdirSync(batchFilepath);
|
|
27882
28153
|
let results = [];
|
|
27883
28154
|
for (const fileIndex in files) {
|
|
27884
28155
|
// for each file lets read the file and then push to algolia
|
|
27885
|
-
const pathToBatch = path$
|
|
28156
|
+
const pathToBatch = path$9.join(batchFilepath, files[fileIndex]);
|
|
27886
28157
|
const fileContents = await this.readFile(pathToBatch);
|
|
27887
28158
|
if (fileContents) {
|
|
27888
28159
|
if ("data" in fileContents && "filepath" in fileContents) {
|
|
@@ -27907,7 +28178,7 @@ let AlgoliaIndex$1 = class AlgoliaIndex {
|
|
|
27907
28178
|
|
|
27908
28179
|
async readFile(filepath) {
|
|
27909
28180
|
return await new Promise((resolve, reject) => {
|
|
27910
|
-
fs$
|
|
28181
|
+
fs$5.readFile(filepath, "utf8", (err, data) => {
|
|
27911
28182
|
if (err) {
|
|
27912
28183
|
reject(err);
|
|
27913
28184
|
}
|
|
@@ -28057,7 +28328,7 @@ var algolia = AlgoliaIndex$1;
|
|
|
28057
28328
|
const algoliasearch = require$$2$3;
|
|
28058
28329
|
const events$3 = events$8;
|
|
28059
28330
|
const AlgoliaIndex = algolia;
|
|
28060
|
-
var fs$
|
|
28331
|
+
var fs$4 = require$$0$2;
|
|
28061
28332
|
const { safePath, getAllowedRoots } = safePath_1;
|
|
28062
28333
|
|
|
28063
28334
|
const algoliaController$1 = {
|
|
@@ -28166,7 +28437,7 @@ const algoliaController$1 = {
|
|
|
28166
28437
|
// init the Algolia Index helper
|
|
28167
28438
|
const a = new AlgoliaIndex(appId, apiKey, indexName);
|
|
28168
28439
|
// create the write stream to store the hits
|
|
28169
|
-
const writeStream = fs$
|
|
28440
|
+
const writeStream = fs$4.createWriteStream(toFilename);
|
|
28170
28441
|
writeStream.write("[");
|
|
28171
28442
|
|
|
28172
28443
|
let sep = "";
|
|
@@ -28419,8 +28690,8 @@ function upsertMenuItem$1(items, menuItem) {
|
|
|
28419
28690
|
|
|
28420
28691
|
var upsertMenuItem_1 = { upsertMenuItem: upsertMenuItem$1 };
|
|
28421
28692
|
|
|
28422
|
-
const { app: app$
|
|
28423
|
-
const path$
|
|
28693
|
+
const { app: app$6 } = require$$0$1;
|
|
28694
|
+
const path$8 = require$$1$1;
|
|
28424
28695
|
const { writeFileSync } = require$$0$2;
|
|
28425
28696
|
const { getFileContents: getFileContents$2 } = file;
|
|
28426
28697
|
const { upsertMenuItem } = upsertMenuItem_1;
|
|
@@ -28431,8 +28702,8 @@ const appName$2 = "Dashboard";
|
|
|
28431
28702
|
const menuItemsController$1 = {
|
|
28432
28703
|
saveMenuItemForApplication: (win, appId, menuItem) => {
|
|
28433
28704
|
try {
|
|
28434
|
-
const filename = path$
|
|
28435
|
-
app$
|
|
28705
|
+
const filename = path$8.join(
|
|
28706
|
+
app$6.getPath("userData"),
|
|
28436
28707
|
appName$2,
|
|
28437
28708
|
appId,
|
|
28438
28709
|
configFilename$1,
|
|
@@ -28450,8 +28721,8 @@ const menuItemsController$1 = {
|
|
|
28450
28721
|
|
|
28451
28722
|
listMenuItemsForApplication: (win, appId) => {
|
|
28452
28723
|
try {
|
|
28453
|
-
const filename = path$
|
|
28454
|
-
app$
|
|
28724
|
+
const filename = path$8.join(
|
|
28725
|
+
app$6.getPath("userData"),
|
|
28455
28726
|
appName$2,
|
|
28456
28727
|
appId,
|
|
28457
28728
|
configFilename$1,
|
|
@@ -28476,14 +28747,14 @@ const menuItemsController$1 = {
|
|
|
28476
28747
|
|
|
28477
28748
|
var menuItemsController_1 = menuItemsController$1;
|
|
28478
28749
|
|
|
28479
|
-
const path$
|
|
28480
|
-
const { app: app$
|
|
28750
|
+
const path$7 = require$$1$1;
|
|
28751
|
+
const { app: app$5 } = require$$0$1;
|
|
28481
28752
|
|
|
28482
28753
|
const pluginController$1 = {
|
|
28483
28754
|
install: (win, packageName, filepath) => {
|
|
28484
28755
|
try {
|
|
28485
|
-
const rootPath = path$
|
|
28486
|
-
app$
|
|
28756
|
+
const rootPath = path$7.join(
|
|
28757
|
+
app$5.getPath("userData"),
|
|
28487
28758
|
"plugins",
|
|
28488
28759
|
packageName,
|
|
28489
28760
|
);
|
|
@@ -45747,7 +46018,7 @@ const completable_js_1 = completable;
|
|
|
45747
46018
|
const uriTemplate_js_1 = uriTemplate;
|
|
45748
46019
|
const toolNameValidation_js_1 = toolNameValidation;
|
|
45749
46020
|
const mcp_server_js_1 = mcpServer$1;
|
|
45750
|
-
const zod_1 = require$$8$
|
|
46021
|
+
const zod_1 = require$$8$1;
|
|
45751
46022
|
/**
|
|
45752
46023
|
* High-level MCP server that provides a simpler API for working with resources, tools, and prompts.
|
|
45753
46024
|
* For advanced usage (like sending notifications or setting custom request handlers), use the underlying
|
|
@@ -48278,8 +48549,8 @@ streamableHttp.StreamableHTTPServerTransport = StreamableHTTPServerTransport$1;
|
|
|
48278
48549
|
* https.createServer({ key, cert }, handler);
|
|
48279
48550
|
*/
|
|
48280
48551
|
|
|
48281
|
-
const fs$
|
|
48282
|
-
const path$
|
|
48552
|
+
const fs$3 = require$$0$2;
|
|
48553
|
+
const path$6 = require$$1$1;
|
|
48283
48554
|
const forge = require$$2$4;
|
|
48284
48555
|
|
|
48285
48556
|
/**
|
|
@@ -48288,14 +48559,14 @@ const forge = require$$2$4;
|
|
|
48288
48559
|
* @returns {{ cert: string, key: string }} PEM-encoded certificate and private key
|
|
48289
48560
|
*/
|
|
48290
48561
|
function getOrCreateCert$1(certsDir) {
|
|
48291
|
-
const certPath = path$
|
|
48292
|
-
const keyPath = path$
|
|
48562
|
+
const certPath = path$6.join(certsDir, "cert.pem");
|
|
48563
|
+
const keyPath = path$6.join(certsDir, "key.pem");
|
|
48293
48564
|
|
|
48294
48565
|
// Return existing cert if valid
|
|
48295
|
-
if (fs$
|
|
48566
|
+
if (fs$3.existsSync(certPath) && fs$3.existsSync(keyPath)) {
|
|
48296
48567
|
try {
|
|
48297
|
-
const cert = fs$
|
|
48298
|
-
const key = fs$
|
|
48568
|
+
const cert = fs$3.readFileSync(certPath, "utf8");
|
|
48569
|
+
const key = fs$3.readFileSync(keyPath, "utf8");
|
|
48299
48570
|
// Verify cert is not expired
|
|
48300
48571
|
const parsed = forge.pki.certificateFromPem(cert);
|
|
48301
48572
|
if (parsed.validity.notAfter > new Date()) {
|
|
@@ -48361,9 +48632,9 @@ function getOrCreateCert$1(certsDir) {
|
|
|
48361
48632
|
const keyPem = forge.pki.privateKeyToPem(keys.privateKey);
|
|
48362
48633
|
|
|
48363
48634
|
// Write to disk
|
|
48364
|
-
fs$
|
|
48365
|
-
fs$
|
|
48366
|
-
fs$
|
|
48635
|
+
fs$3.mkdirSync(certsDir, { recursive: true });
|
|
48636
|
+
fs$3.writeFileSync(certPath, certPem, { mode: 0o644 });
|
|
48637
|
+
fs$3.writeFileSync(keyPath, keyPem, { mode: 0o600 });
|
|
48367
48638
|
|
|
48368
48639
|
console.log(`[tlsCert] Certificate saved to ${certsDir}`);
|
|
48369
48640
|
|
|
@@ -48380,7 +48651,7 @@ var tlsCert = { getOrCreateCert: getOrCreateCert$1 };
|
|
|
48380
48651
|
* for Zod schemas in tool input validation (safeParseAsync).
|
|
48381
48652
|
*/
|
|
48382
48653
|
|
|
48383
|
-
const z$1 = require$$8$
|
|
48654
|
+
const z$1 = require$$8$1;
|
|
48384
48655
|
|
|
48385
48656
|
/**
|
|
48386
48657
|
* Convert a JSON Schema property definition to a Zod v3 schema.
|
|
@@ -48473,7 +48744,7 @@ var jsonSchemaToZod_1 = { jsonSchemaToZod: jsonSchemaToZod$1, jsonSchemaProperty
|
|
|
48473
48744
|
* - Rate limiting via token bucket (60 req/min)
|
|
48474
48745
|
*/
|
|
48475
48746
|
|
|
48476
|
-
const https$1 = require$$
|
|
48747
|
+
const https$1 = require$$11;
|
|
48477
48748
|
const { randomUUID } = require$$3$4;
|
|
48478
48749
|
const { BrowserWindow: BrowserWindow$1 } = require$$0$1;
|
|
48479
48750
|
const { McpServer } = mcp;
|
|
@@ -48604,7 +48875,7 @@ function registerPrompt$1(promptDef) {
|
|
|
48604
48875
|
registeredPrompts.push(promptDef);
|
|
48605
48876
|
}
|
|
48606
48877
|
|
|
48607
|
-
const z = require$$8$
|
|
48878
|
+
const z = require$$8$1;
|
|
48608
48879
|
const { jsonSchemaToZod } = jsonSchemaToZod_1;
|
|
48609
48880
|
|
|
48610
48881
|
/**
|
|
@@ -50282,7 +50553,7 @@ var themeFromUrlErrors$1 = {
|
|
|
50282
50553
|
|
|
50283
50554
|
const css = require$$0$9;
|
|
50284
50555
|
const { Vibrant } = require$$1$6;
|
|
50285
|
-
const https = require$$
|
|
50556
|
+
const https = require$$11;
|
|
50286
50557
|
const http = require$$0$8;
|
|
50287
50558
|
const { URL: URL$1 } = require$$4$1;
|
|
50288
50559
|
const {
|
|
@@ -57023,8 +57294,8 @@ var dashboardConfigUtils$1 = {
|
|
|
57023
57294
|
* Handles publishing packages and generating registry URLs.
|
|
57024
57295
|
*/
|
|
57025
57296
|
|
|
57026
|
-
const fs$
|
|
57027
|
-
const path$
|
|
57297
|
+
const fs$2 = require$$0$2;
|
|
57298
|
+
const path$5 = require$$1$1;
|
|
57028
57299
|
const { getStoredToken: getStoredToken$2 } = registryAuthController$2;
|
|
57029
57300
|
|
|
57030
57301
|
const REGISTRY_BASE_URL =
|
|
@@ -57050,14 +57321,14 @@ async function publishToRegistry$1(zipPath, manifest) {
|
|
|
57050
57321
|
|
|
57051
57322
|
try {
|
|
57052
57323
|
// Read the ZIP file
|
|
57053
|
-
const zipBuffer = fs$
|
|
57324
|
+
const zipBuffer = fs$2.readFileSync(zipPath);
|
|
57054
57325
|
|
|
57055
57326
|
// Create FormData with the ZIP and manifest
|
|
57056
57327
|
const formData = new FormData();
|
|
57057
57328
|
formData.append(
|
|
57058
57329
|
"file",
|
|
57059
57330
|
new Blob([zipBuffer], { type: "application/zip" }),
|
|
57060
|
-
path$
|
|
57331
|
+
path$5.basename(zipPath),
|
|
57061
57332
|
);
|
|
57062
57333
|
formData.append("manifest", JSON.stringify(manifest));
|
|
57063
57334
|
|
|
@@ -57299,8 +57570,8 @@ function requireWidgetPublishManifest () {
|
|
|
57299
57570
|
* Mirrors dashboardConfigController patterns for ZIP creation, manifest generation,
|
|
57300
57571
|
* and registry interaction.
|
|
57301
57572
|
*/
|
|
57302
|
-
const path$
|
|
57303
|
-
const { app: app$
|
|
57573
|
+
const path$4 = require$$1$1;
|
|
57574
|
+
const { app: app$4, dialog: dialog$1 } = require$$0$1;
|
|
57304
57575
|
const AdmZip$2 = require$$3$2;
|
|
57305
57576
|
|
|
57306
57577
|
const themeController$3 = themeController_1;
|
|
@@ -57805,7 +58076,7 @@ async function installThemeFromRegistry$1(win, appId, packageName) {
|
|
|
57805
58076
|
// Validate entry path (security: prevent path traversal)
|
|
57806
58077
|
if (
|
|
57807
58078
|
themeEntry.entryName.includes("..") ||
|
|
57808
|
-
path$
|
|
58079
|
+
path$4.isAbsolute(themeEntry.entryName)
|
|
57809
58080
|
) {
|
|
57810
58081
|
return {
|
|
57811
58082
|
success: false,
|
|
@@ -58038,8 +58309,8 @@ var themeRegistryController$1 = {
|
|
|
58038
58309
|
* applies event wiring. (Import is implemented in DASH-13.)
|
|
58039
58310
|
*/
|
|
58040
58311
|
|
|
58041
|
-
const { app: app$
|
|
58042
|
-
const path$
|
|
58312
|
+
const { app: app$3, dialog } = require$$0$1;
|
|
58313
|
+
const path$3 = require$$1$1;
|
|
58043
58314
|
const AdmZip$1 = require$$3$2;
|
|
58044
58315
|
const { getFileContents: getFileContents$1 } = file;
|
|
58045
58316
|
const {
|
|
@@ -58088,8 +58359,8 @@ async function exportDashboardConfig$1(
|
|
|
58088
58359
|
) {
|
|
58089
58360
|
try {
|
|
58090
58361
|
// 1. Read workspace from workspaces.json
|
|
58091
|
-
const filename = path$
|
|
58092
|
-
app$
|
|
58362
|
+
const filename = path$3.join(
|
|
58363
|
+
app$3.getPath("userData"),
|
|
58093
58364
|
appName$1,
|
|
58094
58365
|
appId,
|
|
58095
58366
|
configFilename,
|
|
@@ -58202,8 +58473,8 @@ async function exportDashboardConfig$1(
|
|
|
58202
58473
|
|
|
58203
58474
|
const { canceled, filePath } = await dialog.showSaveDialog(win, {
|
|
58204
58475
|
title: "Export Dashboard as ZIP",
|
|
58205
|
-
defaultPath: path$
|
|
58206
|
-
app$
|
|
58476
|
+
defaultPath: path$3.join(
|
|
58477
|
+
app$3.getPath("desktop"),
|
|
58207
58478
|
`dashboard-${sanitizedName}.zip`,
|
|
58208
58479
|
),
|
|
58209
58480
|
filters: [{ name: "ZIP Archive", extensions: ["zip"] }],
|
|
@@ -58268,7 +58539,7 @@ async function selectDashboardFile$1(win) {
|
|
|
58268
58539
|
|
|
58269
58540
|
// Extract and validate
|
|
58270
58541
|
const zip = new AdmZip$1(zipPath);
|
|
58271
|
-
const tempDir = path$
|
|
58542
|
+
const tempDir = path$3.join(app$3.getPath("temp"), "dash-import");
|
|
58272
58543
|
const { validateZipEntries } = widgetRegistryExports;
|
|
58273
58544
|
validateZipEntries(zip, tempDir);
|
|
58274
58545
|
|
|
@@ -58378,7 +58649,7 @@ async function importDashboardConfig$1(
|
|
|
58378
58649
|
const zip = new AdmZip$1(zipPath);
|
|
58379
58650
|
|
|
58380
58651
|
// Validate ZIP entries for path traversal
|
|
58381
|
-
const tempDir = path$
|
|
58652
|
+
const tempDir = path$3.join(app$3.getPath("temp"), "dash-import");
|
|
58382
58653
|
const { validateZipEntries } = widgetRegistryExports;
|
|
58383
58654
|
validateZipEntries(zip, tempDir);
|
|
58384
58655
|
|
|
@@ -59018,7 +59289,7 @@ async function installDashboardFromRegistry$1(
|
|
|
59018
59289
|
const zip = new AdmZip$1(zipBuffer);
|
|
59019
59290
|
|
|
59020
59291
|
// 3. Validate ZIP entries
|
|
59021
|
-
const tempDir = path$
|
|
59292
|
+
const tempDir = path$3.join(app$3.getPath("temp"), "dash-registry-import");
|
|
59022
59293
|
const { validateZipEntries } = widgetRegistryExports;
|
|
59023
59294
|
validateZipEntries(zip, tempDir);
|
|
59024
59295
|
|
|
@@ -59154,8 +59425,8 @@ async function collectDashboardDependencies$1(
|
|
|
59154
59425
|
) {
|
|
59155
59426
|
try {
|
|
59156
59427
|
// 1. Read workspace
|
|
59157
|
-
const filename = path$
|
|
59158
|
-
app$
|
|
59428
|
+
const filename = path$3.join(
|
|
59429
|
+
app$3.getPath("userData"),
|
|
59159
59430
|
appName$1,
|
|
59160
59431
|
appId,
|
|
59161
59432
|
configFilename,
|
|
@@ -59433,8 +59704,8 @@ async function prepareDashboardForPublish$1(
|
|
|
59433
59704
|
const { resolveNextVersion } = requireWidgetPublishManifest();
|
|
59434
59705
|
|
|
59435
59706
|
// 1. Read workspace
|
|
59436
|
-
const filename = path$
|
|
59437
|
-
app$
|
|
59707
|
+
const filename = path$3.join(
|
|
59708
|
+
app$3.getPath("userData"),
|
|
59438
59709
|
appName$1,
|
|
59439
59710
|
appId,
|
|
59440
59711
|
configFilename,
|
|
@@ -59711,8 +59982,8 @@ async function prepareDashboardForPublish$1(
|
|
|
59711
59982
|
const sanitizedName = manifest.name;
|
|
59712
59983
|
const { canceled, filePath } = await dialog.showSaveDialog(win, {
|
|
59713
59984
|
title: "Save Dashboard Package for Registry",
|
|
59714
|
-
defaultPath: path$
|
|
59715
|
-
app$
|
|
59985
|
+
defaultPath: path$3.join(
|
|
59986
|
+
app$3.getPath("desktop"),
|
|
59716
59987
|
`dashboard-${sanitizedName}-v${manifest.version}.zip`,
|
|
59717
59988
|
),
|
|
59718
59989
|
filters: [{ name: "ZIP Archive", extensions: ["zip"] }],
|
|
@@ -59879,8 +60150,8 @@ async function checkDashboardUpdatesForApp$1(appId) {
|
|
|
59879
60150
|
const { fetchRegistryIndex } = registryController$3;
|
|
59880
60151
|
|
|
59881
60152
|
try {
|
|
59882
|
-
const filename = path$
|
|
59883
|
-
app$
|
|
60153
|
+
const filename = path$3.join(
|
|
60154
|
+
app$3.getPath("userData"),
|
|
59884
60155
|
appName$1,
|
|
59885
60156
|
appId,
|
|
59886
60157
|
configFilename,
|
|
@@ -59950,8 +60221,8 @@ function getProviderSetupManifest$1(appId, requiredProviders = []) {
|
|
|
59950
60221
|
*/
|
|
59951
60222
|
function getDashboardPublishPreview$1(appId, workspaceId, widgetRegistry = null) {
|
|
59952
60223
|
try {
|
|
59953
|
-
const filename = path$
|
|
59954
|
-
app$
|
|
60224
|
+
const filename = path$3.join(
|
|
60225
|
+
app$3.getPath("userData"),
|
|
59955
60226
|
appName$1,
|
|
59956
60227
|
appId,
|
|
59957
60228
|
configFilename,
|
|
@@ -60259,9 +60530,50 @@ var notificationController_1 = notificationController$2;
|
|
|
60259
60530
|
*
|
|
60260
60531
|
* Uses the `ws` package (installed in dash-electron) for WebSocket clients.
|
|
60261
60532
|
* Multiple widgets referencing the same provider share a single socket.
|
|
60533
|
+
*
|
|
60534
|
+
* Phase 3 (network domain JIT) gates `connect` by hostname when a
|
|
60535
|
+
* widgetId is supplied. Once a connection exists, `send` /
|
|
60536
|
+
* `disconnect` / `getStatus` / `getAll` operate on the
|
|
60537
|
+
* already-authorized socket and are intentionally NOT re-gated —
|
|
60538
|
+
* connections are designed to be shared across widgets via the
|
|
60539
|
+
* `consumers: Set` field, and re-gating sends would break that.
|
|
60262
60540
|
*/
|
|
60263
60541
|
|
|
60264
|
-
const
|
|
60542
|
+
const { app: app$2 } = require$$0$1;
|
|
60543
|
+
const fs$1 = require$$0$2;
|
|
60544
|
+
const path$2 = require$$1$1;
|
|
60545
|
+
const WebSocket = require$$3$5;
|
|
60546
|
+
const {
|
|
60547
|
+
gateNetworkCall,
|
|
60548
|
+
gateNetworkCallWithJit,
|
|
60549
|
+
} = networkGate;
|
|
60550
|
+
const { readEnforceFlag, readJitFlag } = securityFlags;
|
|
60551
|
+
|
|
60552
|
+
function _loadFlags() {
|
|
60553
|
+
try {
|
|
60554
|
+
const settingsPath = path$2.join(
|
|
60555
|
+
app$2.getPath("userData"),
|
|
60556
|
+
"Dashboard",
|
|
60557
|
+
"settings.json",
|
|
60558
|
+
);
|
|
60559
|
+
if (!fs$1.existsSync(settingsPath)) return null;
|
|
60560
|
+
return JSON.parse(fs$1.readFileSync(settingsPath, "utf8"));
|
|
60561
|
+
} catch (_e) {
|
|
60562
|
+
return null;
|
|
60563
|
+
}
|
|
60564
|
+
}
|
|
60565
|
+
|
|
60566
|
+
async function _runNetworkGate(action, widgetId, args) {
|
|
60567
|
+
const settings = _loadFlags();
|
|
60568
|
+
if (!readEnforceFlag(settings)) return { allow: true };
|
|
60569
|
+
if (!widgetId) return { allow: true }; // legacy callers
|
|
60570
|
+
return readJitFlag(settings)
|
|
60571
|
+
? await gateNetworkCallWithJit(
|
|
60572
|
+
{ widgetId, action, args },
|
|
60573
|
+
{ enableJit: true },
|
|
60574
|
+
)
|
|
60575
|
+
: gateNetworkCall({ widgetId, action, args });
|
|
60576
|
+
}
|
|
60265
60577
|
|
|
60266
60578
|
/**
|
|
60267
60579
|
* Active WebSocket connections
|
|
@@ -60692,7 +61004,26 @@ const webSocketController$1 = {
|
|
|
60692
61004
|
* @param {object} config - { url, headers, subprotocols, credentials }
|
|
60693
61005
|
* @returns {{ success, providerName, status } | { error, message }}
|
|
60694
61006
|
*/
|
|
60695
|
-
connect: async (win, providerName, config) => {
|
|
61007
|
+
connect: async (win, providerName, config, widgetId = null) => {
|
|
61008
|
+
// Phase 3 network gate — fires only when an explicit widgetId is
|
|
61009
|
+
// supplied. The interpolated URL (with credentials substituted) is
|
|
61010
|
+
// what we actually open the socket to, so the gate uses it for
|
|
61011
|
+
// hostname extraction.
|
|
61012
|
+
const interpolatedForGate = config?.credentials
|
|
61013
|
+
? interpolate(config.url, config.credentials)
|
|
61014
|
+
: config?.url;
|
|
61015
|
+
const gateResult = await _runNetworkGate("wsConnect", widgetId, {
|
|
61016
|
+
url: interpolatedForGate,
|
|
61017
|
+
});
|
|
61018
|
+
if (!gateResult.allow) {
|
|
61019
|
+
return {
|
|
61020
|
+
error: true,
|
|
61021
|
+
message: "network permission gate: " + gateResult.reason,
|
|
61022
|
+
providerName,
|
|
61023
|
+
status: STATUS.ERROR,
|
|
61024
|
+
};
|
|
61025
|
+
}
|
|
61026
|
+
|
|
60696
61027
|
// 1. Already connected? Return existing connection
|
|
60697
61028
|
const existing = activeConnections.get(providerName);
|
|
60698
61029
|
if (existing && existing.status === STATUS.CONNECTED) {
|
|
@@ -62728,8 +63059,8 @@ const dataApi$2 = {
|
|
|
62728
63059
|
ipcRenderer$m.invoke(READ_JSON, { filepath, objectCount });
|
|
62729
63060
|
},
|
|
62730
63061
|
|
|
62731
|
-
readDataFromURL: (url, toFilepath) => {
|
|
62732
|
-
ipcRenderer$m.invoke(READ_DATA_URL, { url, toFilepath });
|
|
63062
|
+
readDataFromURL: (url, toFilepath, widgetId = null) => {
|
|
63063
|
+
ipcRenderer$m.invoke(READ_DATA_URL, { url, toFilepath, widgetId });
|
|
62733
63064
|
},
|
|
62734
63065
|
|
|
62735
63066
|
/*
|
|
@@ -64732,8 +65063,8 @@ const webSocketApi$2 = {
|
|
|
64732
65063
|
* @param {object} config { url, headers, subprotocols, credentials }
|
|
64733
65064
|
* @returns {Promise<{ success, providerName, status } | { error, message }>}
|
|
64734
65065
|
*/
|
|
64735
|
-
connect: (providerName, config) =>
|
|
64736
|
-
ipcRenderer$4.invoke(WS_CONNECT, { providerName, config }),
|
|
65066
|
+
connect: (providerName, config, widgetId = null) =>
|
|
65067
|
+
ipcRenderer$4.invoke(WS_CONNECT, { providerName, config, widgetId }),
|
|
64737
65068
|
|
|
64738
65069
|
/**
|
|
64739
65070
|
* disconnect
|