@trops/dash-core 0.1.491 → 0.1.493
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 +664 -181
- package/dist/electron/index.js.map +1 -1
- package/dist/index.esm.js +644 -190
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +644 -190
- package/dist/index.js.map +1 -1
- package/package.json +118 -114
- package/scripts/scanWidgetManifestCli.js +202 -0
package/package.json
CHANGED
|
@@ -1,117 +1,121 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
},
|
|
12
|
-
"./electron": {
|
|
13
|
-
"require": "./dist/electron/index.js"
|
|
14
|
-
}
|
|
2
|
+
"name": "@trops/dash-core",
|
|
3
|
+
"version": "0.1.493",
|
|
4
|
+
"description": "Core framework for Dash dashboard applications",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.esm.js",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"import": "./dist/index.esm.js",
|
|
10
|
+
"require": "./dist/index.js"
|
|
15
11
|
},
|
|
16
|
-
"
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
"
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
"
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
"
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
"
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
"
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
12
|
+
"./electron": {
|
|
13
|
+
"require": "./dist/electron/index.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"scripts/scanWidgetManifestCli.js"
|
|
19
|
+
],
|
|
20
|
+
"bin": {
|
|
21
|
+
"dash-scan-manifest": "scripts/scanWidgetManifestCli.js"
|
|
22
|
+
},
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "npm run build:renderer && npm run build:electron",
|
|
25
|
+
"build:renderer": "rollup -c rollup.config.renderer.mjs",
|
|
26
|
+
"build:electron": "rollup -c rollup.config.electron.mjs && mkdir -p dist/mcp && cp electron/mcp/mcpServerCatalog.json dist/mcp/ && cp electron/mcp/knownExternalMcpServers.json dist/mcp/ && rm -rf dist/mcp/servers && cp -r electron/mcp/servers dist/mcp/ && node scripts/inject-secrets.js",
|
|
27
|
+
"clean": "rm -rf dist",
|
|
28
|
+
"prepublishOnly": "npm run clean && npm run build",
|
|
29
|
+
"test:mcp": "node --test electron/controller/mcpController.test.js electron/mcp/mcpServerCatalog.test.js electron/mcp/installExternalMcpTool.test.js",
|
|
30
|
+
"test:untracked-pin": "node scripts/test-untracked-sources-pin.js",
|
|
31
|
+
"check:untracked": "node scripts/check-untracked-sources.js",
|
|
32
|
+
"test": "jest --watchAll=false",
|
|
33
|
+
"prettify": "prettier --write \"src/**/*.{js,jsx,ts,tsx}\" \"electron/**/*.js\"",
|
|
34
|
+
"ci": "./scripts/ci.sh",
|
|
35
|
+
"ci:commit": "./scripts/ci.sh --commit",
|
|
36
|
+
"ci:push": "./scripts/ci.sh --push",
|
|
37
|
+
"ci:pr": "./scripts/ci.sh --pr",
|
|
38
|
+
"ci:release": "./scripts/ci.sh --release",
|
|
39
|
+
"prdize": "node scripts/prdize.js"
|
|
40
|
+
},
|
|
41
|
+
"peerDependencies": {
|
|
42
|
+
"@headlessui/react": "1.4",
|
|
43
|
+
"@heroicons/react": "^2.0.16",
|
|
44
|
+
"@trops/dash-react": ">=0.1.187",
|
|
45
|
+
"prop-types": "^15.8.1",
|
|
46
|
+
"react": "^18.2.0",
|
|
47
|
+
"react-dnd": "^16.0.1",
|
|
48
|
+
"react-dnd-html5-backend": "^16.0.1",
|
|
49
|
+
"react-dom": "^18.2.0",
|
|
50
|
+
"react-instantsearch-hooks-web": "^6.26.0",
|
|
51
|
+
"react-router-dom": "^6.3.0",
|
|
52
|
+
"tailwindcss": "^3.2.7"
|
|
53
|
+
},
|
|
54
|
+
"dependencies": {
|
|
55
|
+
"@anthropic-ai/sdk": "^0.39.0",
|
|
56
|
+
"@fortawesome/fontawesome-svg-core": "^6.1.1",
|
|
57
|
+
"@fortawesome/free-brands-svg-icons": "^6.1.1",
|
|
58
|
+
"@fortawesome/free-solid-svg-icons": "^6.1.1",
|
|
59
|
+
"@fortawesome/react-fontawesome": "^0.1.18",
|
|
60
|
+
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
61
|
+
"adm-zip": "^0.5.16",
|
|
62
|
+
"algoliasearch": "^4.13.0",
|
|
63
|
+
"clsx": "^2.1.1",
|
|
64
|
+
"croner": "^10.0.1",
|
|
65
|
+
"css": "^3.0.0",
|
|
66
|
+
"csv-parser": "^3.0.0",
|
|
67
|
+
"deep-equal": "^2.2.0",
|
|
68
|
+
"electron-store": "^8.0.1",
|
|
69
|
+
"esbuild": "^0.25.12",
|
|
70
|
+
"JSONStream": "^1.3.5",
|
|
71
|
+
"live-plugin-manager": "^0.17.1",
|
|
72
|
+
"marked": "^17.0.5",
|
|
73
|
+
"minimist": "^1.2.8",
|
|
74
|
+
"node-forge": "^1.3.1",
|
|
75
|
+
"node-vibrant": "^4.0.4",
|
|
76
|
+
"objects-to-csv": "^1.3.6",
|
|
77
|
+
"openai": "^4.30.0",
|
|
78
|
+
"quickjs-emscripten": "^0.32.0",
|
|
79
|
+
"ws": "^8.19.0",
|
|
80
|
+
"xml2js": "^0.6.2",
|
|
81
|
+
"xtreamer": "^1.1.2",
|
|
82
|
+
"zod": "^3.23.8"
|
|
83
|
+
},
|
|
84
|
+
"devDependencies": {
|
|
85
|
+
"@babel/cli": "^7.22.0",
|
|
86
|
+
"@babel/core": "^7.22.0",
|
|
87
|
+
"@babel/plugin-transform-runtime": "^7.22.0",
|
|
88
|
+
"@babel/preset-env": "^7.22.0",
|
|
89
|
+
"@babel/preset-react": "^7.22.0",
|
|
90
|
+
"@babel/preset-typescript": "^7.28.5",
|
|
91
|
+
"@babel/runtime": "^7.22.0",
|
|
92
|
+
"@rollup/plugin-babel": "^6.0.0",
|
|
93
|
+
"@rollup/plugin-commonjs": "^25.0.0",
|
|
94
|
+
"@rollup/plugin-json": "^6.0.0",
|
|
95
|
+
"@rollup/plugin-node-resolve": "^15.0.0",
|
|
96
|
+
"@rollup/plugin-strip": "^3.0.0",
|
|
97
|
+
"@rollup/plugin-typescript": "^11.0.0",
|
|
98
|
+
"@testing-library/dom": "^10.4.1",
|
|
99
|
+
"@testing-library/jest-dom": "^6.9.1",
|
|
100
|
+
"@testing-library/react": "^14.0.0",
|
|
101
|
+
"@testing-library/user-event": "^14.6.1",
|
|
102
|
+
"babel-jest": "^30.2.0",
|
|
103
|
+
"jest": "^30.2.0",
|
|
104
|
+
"jest-environment-jsdom": "^30.2.0",
|
|
105
|
+
"prettier": "^3.0.0",
|
|
106
|
+
"react": "^18.2.0",
|
|
107
|
+
"react-dom": "^18.2.0",
|
|
108
|
+
"rollup": "^3.25.0",
|
|
109
|
+
"rollup-plugin-peer-deps-external": "^2.2.4",
|
|
110
|
+
"tslib": "^2.8.1",
|
|
111
|
+
"typescript": "^5.0.0"
|
|
112
|
+
},
|
|
113
|
+
"publishConfig": {
|
|
114
|
+
"access": "public"
|
|
115
|
+
},
|
|
116
|
+
"repository": {
|
|
117
|
+
"type": "git",
|
|
118
|
+
"url": "https://github.com/trops/dash-core.git"
|
|
119
|
+
},
|
|
120
|
+
"license": "MIT"
|
|
117
121
|
}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* scanWidgetManifestCli.js
|
|
4
|
+
*
|
|
5
|
+
* CLI shim around electron/utils/manifestScanner.js. Run from a widget
|
|
6
|
+
* package root to compare detected MCP usage against the package's
|
|
7
|
+
* `dash.permissions.mcp` block.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* npx dash-scan-manifest # scan ./, print diff (default --check)
|
|
11
|
+
* npx dash-scan-manifest <dir> # scan <dir>
|
|
12
|
+
* npx dash-scan-manifest --init # write missing manifest into package.json
|
|
13
|
+
* npx dash-scan-manifest --json # machine-readable output
|
|
14
|
+
*
|
|
15
|
+
* Exit codes:
|
|
16
|
+
* 0 no missing entries (manifest is complete or scan found nothing)
|
|
17
|
+
* 1 scan found tool usage not declared in the manifest
|
|
18
|
+
* 2 invalid arguments / unreadable directory
|
|
19
|
+
*/
|
|
20
|
+
"use strict";
|
|
21
|
+
|
|
22
|
+
const fs = require("fs");
|
|
23
|
+
const path = require("path");
|
|
24
|
+
|
|
25
|
+
// Find the scanner in either the repo layout (electron/) or the
|
|
26
|
+
// published package layout (dist/electron/). Whichever exists wins.
|
|
27
|
+
const scannerPath = (() => {
|
|
28
|
+
const distPath = path.join(
|
|
29
|
+
__dirname,
|
|
30
|
+
"..",
|
|
31
|
+
"dist",
|
|
32
|
+
"electron",
|
|
33
|
+
"utils",
|
|
34
|
+
"manifestScanner.js",
|
|
35
|
+
);
|
|
36
|
+
if (fs.existsSync(distPath)) return distPath;
|
|
37
|
+
return path.join(__dirname, "..", "electron", "utils", "manifestScanner.js");
|
|
38
|
+
})();
|
|
39
|
+
const { scanForMcpUsage } = require(scannerPath);
|
|
40
|
+
|
|
41
|
+
function parseArgs(argv) {
|
|
42
|
+
const args = { dir: null, mode: "check", json: false };
|
|
43
|
+
for (const a of argv) {
|
|
44
|
+
if (a === "--init") args.mode = "init";
|
|
45
|
+
else if (a === "--check") args.mode = "check";
|
|
46
|
+
else if (a === "--json") args.json = true;
|
|
47
|
+
else if (a.startsWith("--")) {
|
|
48
|
+
console.error(`Unknown flag: ${a}`);
|
|
49
|
+
process.exit(2);
|
|
50
|
+
} else {
|
|
51
|
+
args.dir = a;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (!args.dir) args.dir = process.cwd();
|
|
55
|
+
return args;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function readPackageJson(dir) {
|
|
59
|
+
const p = path.join(dir, "package.json");
|
|
60
|
+
if (!fs.existsSync(p)) return { path: p, pkg: null };
|
|
61
|
+
try {
|
|
62
|
+
return { path: p, pkg: JSON.parse(fs.readFileSync(p, "utf8")) };
|
|
63
|
+
} catch (e) {
|
|
64
|
+
console.error(`Could not read ${p}: ${e.message}`);
|
|
65
|
+
process.exit(2);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function getDeclaredManifest(pkg) {
|
|
70
|
+
return pkg?.dash?.permissions?.mcp || null;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function diff(detected, declared) {
|
|
74
|
+
// detected: { servers: { [name]: { tools[] } } }
|
|
75
|
+
// declared: { [name]: { tools[], readPaths[], writePaths[] } } | null
|
|
76
|
+
const missing = {}; // detected but not declared
|
|
77
|
+
const declaredServers = (declared && declared) || {};
|
|
78
|
+
for (const [name, entry] of Object.entries(detected.servers)) {
|
|
79
|
+
const declTools = declaredServers[name]?.tools || [];
|
|
80
|
+
const missingTools = entry.tools.filter((t) => !declTools.includes(t));
|
|
81
|
+
if (!declaredServers[name] || missingTools.length > 0) {
|
|
82
|
+
missing[name] = {
|
|
83
|
+
tools: missingTools.length > 0 ? missingTools : entry.tools,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return { missing };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function buildSyntheticManifest(detected) {
|
|
91
|
+
const out = {};
|
|
92
|
+
for (const [name, entry] of Object.entries(detected.servers)) {
|
|
93
|
+
out[name] = {
|
|
94
|
+
tools: entry.tools,
|
|
95
|
+
readPaths: [],
|
|
96
|
+
writePaths: [],
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
return out;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function main() {
|
|
103
|
+
const args = parseArgs(process.argv.slice(2));
|
|
104
|
+
const dir = path.resolve(args.dir);
|
|
105
|
+
|
|
106
|
+
if (!fs.existsSync(dir) || !fs.statSync(dir).isDirectory()) {
|
|
107
|
+
console.error(`Directory not found: ${dir}`);
|
|
108
|
+
process.exit(2);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const detected = scanForMcpUsage({ dir });
|
|
112
|
+
const { path: pkgPath, pkg } = readPackageJson(dir);
|
|
113
|
+
const declared = getDeclaredManifest(pkg);
|
|
114
|
+
const d = diff(detected, declared);
|
|
115
|
+
|
|
116
|
+
if (args.json) {
|
|
117
|
+
console.log(
|
|
118
|
+
JSON.stringify(
|
|
119
|
+
{
|
|
120
|
+
dir,
|
|
121
|
+
detected: detected.servers,
|
|
122
|
+
declared: declared || null,
|
|
123
|
+
missing: d.missing,
|
|
124
|
+
warnings: detected.warnings,
|
|
125
|
+
},
|
|
126
|
+
null,
|
|
127
|
+
2,
|
|
128
|
+
),
|
|
129
|
+
);
|
|
130
|
+
process.exit(Object.keys(d.missing).length > 0 ? 1 : 0);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (args.mode === "init") {
|
|
134
|
+
if (!pkg) {
|
|
135
|
+
console.error(
|
|
136
|
+
`No package.json found in ${dir}. --init requires an existing package.json.`,
|
|
137
|
+
);
|
|
138
|
+
process.exit(2);
|
|
139
|
+
}
|
|
140
|
+
if (declared) {
|
|
141
|
+
console.error(
|
|
142
|
+
`package.json already declares dash.permissions.mcp. --init refuses to overwrite. Use --check to see the diff.`,
|
|
143
|
+
);
|
|
144
|
+
process.exit(2);
|
|
145
|
+
}
|
|
146
|
+
pkg.dash = pkg.dash || {};
|
|
147
|
+
pkg.dash.permissions = pkg.dash.permissions || {};
|
|
148
|
+
pkg.dash.permissions.mcp = buildSyntheticManifest(detected);
|
|
149
|
+
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf8");
|
|
150
|
+
console.log(`Wrote starter manifest to ${pkgPath}.`);
|
|
151
|
+
console.log(
|
|
152
|
+
"Review the readPaths and writePaths arrays — the scanner cannot infer paths.",
|
|
153
|
+
);
|
|
154
|
+
process.exit(0);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// --check (default)
|
|
158
|
+
console.log(`Scanned: ${dir}`);
|
|
159
|
+
if (Object.keys(detected.servers).length === 0) {
|
|
160
|
+
console.log("No literal MCP usage detected.");
|
|
161
|
+
} else {
|
|
162
|
+
console.log("\nDetected MCP usage:");
|
|
163
|
+
for (const [name, entry] of Object.entries(detected.servers)) {
|
|
164
|
+
console.log(
|
|
165
|
+
` ${name}: ${entry.tools.join(", ") || "(no literal tools)"}`,
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (detected.warnings.length > 0) {
|
|
171
|
+
console.log(
|
|
172
|
+
`\n${detected.warnings.length} dynamic call(s) — scanner could not analyze:`,
|
|
173
|
+
);
|
|
174
|
+
for (const w of detected.warnings) {
|
|
175
|
+
console.log(` ${w.file}:${w.line} [${w.kind}] ${w.snippet}`);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (declared) {
|
|
180
|
+
console.log("\nDeclared manifest:");
|
|
181
|
+
for (const [name, entry] of Object.entries(declared)) {
|
|
182
|
+
console.log(` ${name}: ${(entry.tools || []).join(", ") || "(empty)"}`);
|
|
183
|
+
}
|
|
184
|
+
} else {
|
|
185
|
+
console.log("\nNo dash.permissions.mcp block in package.json.");
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (Object.keys(d.missing).length > 0) {
|
|
189
|
+
console.log("\nMissing in manifest:");
|
|
190
|
+
for (const [name, entry] of Object.entries(d.missing)) {
|
|
191
|
+
console.log(` ${name}: ${entry.tools.join(", ")}`);
|
|
192
|
+
}
|
|
193
|
+
console.log(
|
|
194
|
+
"\nRun `dash-scan-manifest --init` to write a starter manifest.",
|
|
195
|
+
);
|
|
196
|
+
process.exit(1);
|
|
197
|
+
}
|
|
198
|
+
console.log("\nManifest looks complete.");
|
|
199
|
+
process.exit(0);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
main();
|