@trops/dash-core 0.1.411 → 0.1.413
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 +110 -12
- package/dist/electron/index.js.map +1 -1
- package/dist/index.esm.js +7 -1
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/electron/index.js
CHANGED
|
@@ -51663,15 +51663,26 @@ const cliController$2 = {
|
|
|
51663
51663
|
|
|
51664
51664
|
// Auto-wire the hosted Dash MCP server so the assistant can use Dash
|
|
51665
51665
|
// tools (apply_theme, create_dashboard, add_widget, etc.) without
|
|
51666
|
-
// the user running `claude mcp add dash ...` themselves. We
|
|
51667
|
-
//
|
|
51668
|
-
//
|
|
51666
|
+
// the user running `claude mcp add dash ...` themselves. We write
|
|
51667
|
+
// the JSON to a short-lived temp file and pass its path via
|
|
51668
|
+
// --mcp-config; merges with any user-configured MCPs so their
|
|
51669
|
+
// other tools (github, slack, etc.) remain available.
|
|
51670
|
+
//
|
|
51671
|
+
// We use a file, not inline JSON, because the inline form is
|
|
51672
|
+
// fragile on Windows: shell:true hands the arg to cmd.exe which
|
|
51673
|
+
// tokenizes on embedded whitespace inside the JSON (notably in
|
|
51674
|
+
// "Authorization: Bearer <UUID>" and the URL). Even with proper
|
|
51675
|
+
// windowsQuote escaping, cmd.exe's `""` handling inside /d /s /c
|
|
51676
|
+
// drops tokens — the user sees "MCP config file not found" with
|
|
51677
|
+
// fragments of the JSON prepended to cwd. Writing the JSON to a
|
|
51678
|
+
// file avoids every layer of that problem.
|
|
51669
51679
|
//
|
|
51670
51680
|
// Prereqs: the Dash MCP server is running and has issued a bearer
|
|
51671
51681
|
// token. If either is missing (server disabled, first launch before
|
|
51672
51682
|
// auto-start completes), we silently skip — the assistant still
|
|
51673
51683
|
// works for non-Dash queries, and the setup banner remains visible
|
|
51674
51684
|
// as a manual fallback.
|
|
51685
|
+
let mcpConfigFilePath = null;
|
|
51675
51686
|
try {
|
|
51676
51687
|
const mcpDashServerController = mcpDashServerController_1;
|
|
51677
51688
|
const status = mcpDashServerController.getStatus?.(win);
|
|
@@ -51694,7 +51705,18 @@ const cliController$2 = {
|
|
|
51694
51705
|
},
|
|
51695
51706
|
},
|
|
51696
51707
|
});
|
|
51697
|
-
|
|
51708
|
+
const os = require("os");
|
|
51709
|
+
const path = require("path");
|
|
51710
|
+
const fs = require("fs");
|
|
51711
|
+
// Unique per-request filename so concurrent assistant calls
|
|
51712
|
+
// don't race on the same file. The token is sensitive, so
|
|
51713
|
+
// mode 0600 — owner read/write only.
|
|
51714
|
+
mcpConfigFilePath = path.join(
|
|
51715
|
+
os.tmpdir(),
|
|
51716
|
+
`dash-mcp-config-${requestId}.json`,
|
|
51717
|
+
);
|
|
51718
|
+
fs.writeFileSync(mcpConfigFilePath, mcpConfig, { mode: 0o600 });
|
|
51719
|
+
args.push("--mcp-config", mcpConfigFilePath);
|
|
51698
51720
|
}
|
|
51699
51721
|
}
|
|
51700
51722
|
} catch (err) {
|
|
@@ -51705,6 +51727,19 @@ const cliController$2 = {
|
|
|
51705
51727
|
);
|
|
51706
51728
|
}
|
|
51707
51729
|
|
|
51730
|
+
// Best-effort cleanup of the temp MCP config file. Called from
|
|
51731
|
+
// both child exit handlers and the outer catch. Safe to call
|
|
51732
|
+
// multiple times — becomes a no-op after the first unlink.
|
|
51733
|
+
const cleanupMcpConfigFile = () => {
|
|
51734
|
+
if (!mcpConfigFilePath) return;
|
|
51735
|
+
try {
|
|
51736
|
+
require("fs").unlinkSync(mcpConfigFilePath);
|
|
51737
|
+
} catch {
|
|
51738
|
+
// File may already be gone; ignore.
|
|
51739
|
+
}
|
|
51740
|
+
mcpConfigFilePath = null;
|
|
51741
|
+
};
|
|
51742
|
+
|
|
51708
51743
|
if (model) {
|
|
51709
51744
|
args.push("--model", model);
|
|
51710
51745
|
}
|
|
@@ -51908,6 +51943,7 @@ const cliController$2 = {
|
|
|
51908
51943
|
});
|
|
51909
51944
|
|
|
51910
51945
|
child.on("error", (err) => {
|
|
51946
|
+
cleanupMcpConfigFile();
|
|
51911
51947
|
activeProcesses.delete(requestId);
|
|
51912
51948
|
safeSend(win, LLM_STREAM_ERROR$2, {
|
|
51913
51949
|
requestId,
|
|
@@ -51917,6 +51953,7 @@ const cliController$2 = {
|
|
|
51917
51953
|
});
|
|
51918
51954
|
|
|
51919
51955
|
child.on("close", (code) => {
|
|
51956
|
+
cleanupMcpConfigFile();
|
|
51920
51957
|
activeProcesses.delete(requestId);
|
|
51921
51958
|
|
|
51922
51959
|
// Process any remaining buffer
|
|
@@ -51980,6 +52017,7 @@ const cliController$2 = {
|
|
|
51980
52017
|
}
|
|
51981
52018
|
});
|
|
51982
52019
|
} catch (err) {
|
|
52020
|
+
cleanupMcpConfigFile();
|
|
51983
52021
|
activeProcesses.delete(requestId);
|
|
51984
52022
|
safeSend(win, LLM_STREAM_ERROR$2, {
|
|
51985
52023
|
requestId,
|
|
@@ -63429,6 +63467,29 @@ function extractEventWiring$1(layout) {
|
|
|
63429
63467
|
return wiring;
|
|
63430
63468
|
}
|
|
63431
63469
|
|
|
63470
|
+
/**
|
|
63471
|
+
* Strip a `<scope>/` or `@<scope>/` prefix from a potentially-scoped
|
|
63472
|
+
* package name. Widgets installed from the registry carry
|
|
63473
|
+
* `w.name = "@scope/pkg"` alongside `w.scope = "scope"`; downstream
|
|
63474
|
+
* code builds `${scope}/${packageName}` for display and for registry
|
|
63475
|
+
* keys, so `packageName` must be the bare name or the scope doubles
|
|
63476
|
+
* (e.g. `@trops/@ai-built/pipeline` instead of `@trops/pipeline`).
|
|
63477
|
+
*
|
|
63478
|
+
* @param {string} fullName Potentially scoped (e.g. "@ai-built/pipeline" or "ai-built/pipeline")
|
|
63479
|
+
* @param {string} scope Scope to strip (e.g. "ai-built" or "@ai-built")
|
|
63480
|
+
* @returns {string} The bare package name
|
|
63481
|
+
*/
|
|
63482
|
+
function stripScopePrefix(fullName, scope) {
|
|
63483
|
+
if (!fullName) return fullName || "";
|
|
63484
|
+
if (!scope) return fullName;
|
|
63485
|
+
const bareScope = scope.startsWith("@") ? scope.slice(1) : scope;
|
|
63486
|
+
const variants = [`@${bareScope}/`, `${bareScope}/`];
|
|
63487
|
+
for (const v of variants) {
|
|
63488
|
+
if (fullName.startsWith(v)) return fullName.slice(v.length);
|
|
63489
|
+
}
|
|
63490
|
+
return fullName;
|
|
63491
|
+
}
|
|
63492
|
+
|
|
63432
63493
|
/**
|
|
63433
63494
|
* Build the widget dependencies array from component names and
|
|
63434
63495
|
* installed widget metadata.
|
|
@@ -63470,7 +63531,9 @@ function buildWidgetDependencies$1(
|
|
|
63470
63531
|
for (const w of installedWidgets) {
|
|
63471
63532
|
if (w.componentNames && w.componentNames.includes(name)) {
|
|
63472
63533
|
if (!scope && w.scope) scope = w.scope;
|
|
63473
|
-
if (!packageName || packageName === name)
|
|
63534
|
+
if (!packageName || packageName === name) {
|
|
63535
|
+
packageName = stripScopePrefix(w.name, w.scope || scope) || "";
|
|
63536
|
+
}
|
|
63474
63537
|
version = w.version || "*";
|
|
63475
63538
|
author =
|
|
63476
63539
|
typeof w.author === "string" ? w.author : w.author?.name || "";
|
|
@@ -63483,8 +63546,9 @@ function buildWidgetDependencies$1(
|
|
|
63483
63546
|
if (componentConfigs && componentConfigs[name]) {
|
|
63484
63547
|
const config = componentConfigs[name];
|
|
63485
63548
|
if (!scope && config.scope) scope = config.scope;
|
|
63486
|
-
if ((!packageName || packageName === name) && config.packageName)
|
|
63487
|
-
packageName = config.packageName;
|
|
63549
|
+
if ((!packageName || packageName === name) && config.packageName) {
|
|
63550
|
+
packageName = stripScopePrefix(config.packageName, scope);
|
|
63551
|
+
}
|
|
63488
63552
|
if (config.id && !scope) {
|
|
63489
63553
|
const idParts = config.id.split(".");
|
|
63490
63554
|
if (idParts.length === 3) {
|
|
@@ -73155,7 +73219,38 @@ async function prepareWidgetForPublish$1(appId, packageId, options = {}) {
|
|
|
73155
73219
|
}
|
|
73156
73220
|
}
|
|
73157
73221
|
|
|
73158
|
-
// 5.
|
|
73222
|
+
// 5. Normalize dash.json's author field. The AI Widget Builder
|
|
73223
|
+
// scaffolds new @ai-built/* widgets with `author: "AI Assistant"`
|
|
73224
|
+
// as the placeholder, which ships unchanged to the registry and
|
|
73225
|
+
// is what installers see under the package's author — regardless
|
|
73226
|
+
// of who actually published it. If dash.json exists and its
|
|
73227
|
+
// author is blank or that placeholder, rewrite with the
|
|
73228
|
+
// publisher's registry display name (or username) before we zip
|
|
73229
|
+
// the package. Any other user-set author is preserved.
|
|
73230
|
+
const authorOverride =
|
|
73231
|
+
(options.authorName && options.authorName.trim()) ||
|
|
73232
|
+
profile?.displayName ||
|
|
73233
|
+
profile?.username ||
|
|
73234
|
+
"";
|
|
73235
|
+
if (authorOverride && fs.existsSync(dashJsonPath)) {
|
|
73236
|
+
try {
|
|
73237
|
+
const dashJson = JSON.parse(fs.readFileSync(dashJsonPath, "utf8"));
|
|
73238
|
+
const current = (dashJson.author || "").trim();
|
|
73239
|
+
const isPlaceholder = !current || current === "AI Assistant";
|
|
73240
|
+
if (isPlaceholder && dashJson.author !== authorOverride) {
|
|
73241
|
+
dashJson.author = authorOverride;
|
|
73242
|
+
fs.writeFileSync(
|
|
73243
|
+
dashJsonPath,
|
|
73244
|
+
JSON.stringify(dashJson, null, 2) + "\n",
|
|
73245
|
+
);
|
|
73246
|
+
}
|
|
73247
|
+
} catch {
|
|
73248
|
+
// Best-effort only — a malformed dash.json will surface later
|
|
73249
|
+
// during manifest generation with a clearer error.
|
|
73250
|
+
}
|
|
73251
|
+
}
|
|
73252
|
+
|
|
73253
|
+
// 6. Build manifest using the widget's component configs. The
|
|
73159
73254
|
// registry cache may be missing widgets (orphaned / locally-
|
|
73160
73255
|
// registered packages), so fall back to scanning the package's
|
|
73161
73256
|
// .dash.js files from disk.
|
|
@@ -73179,24 +73274,27 @@ async function prepareWidgetForPublish$1(appId, packageId, options = {}) {
|
|
|
73179
73274
|
tags: options.tags,
|
|
73180
73275
|
icon: options.icon,
|
|
73181
73276
|
category: options.category,
|
|
73182
|
-
authorName
|
|
73277
|
+
// Prefer the caller-supplied authorName; otherwise fall back to
|
|
73278
|
+
// the publisher's registry profile so the manifest author matches
|
|
73279
|
+
// the (now-rewritten) dash.json we just zipped.
|
|
73280
|
+
authorName: options.authorName || authorOverride || undefined,
|
|
73183
73281
|
appOrigin: appId,
|
|
73184
73282
|
});
|
|
73185
73283
|
|
|
73186
|
-
//
|
|
73284
|
+
// 7. Zip the widget directory to a temp file
|
|
73187
73285
|
const zipName = `widget-${manifest.scope}-${manifest.name}-v${manifest.version}.zip`;
|
|
73188
73286
|
const zipPath = path.join(app.getPath("temp"), zipName);
|
|
73189
73287
|
const zip = new AdmZip();
|
|
73190
73288
|
addDirToZip(zip, widget.path);
|
|
73191
73289
|
zip.writeZip(zipPath);
|
|
73192
73290
|
|
|
73193
|
-
//
|
|
73291
|
+
// 8. Publish to registry
|
|
73194
73292
|
const registryResult = await registryApiController$1.publishToRegistry(
|
|
73195
73293
|
zipPath,
|
|
73196
73294
|
manifest,
|
|
73197
73295
|
);
|
|
73198
73296
|
|
|
73199
|
-
//
|
|
73297
|
+
// 9. On failure: revert package.json (if we bumped) and surface details
|
|
73200
73298
|
if (!registryResult.success) {
|
|
73201
73299
|
if (newVersion !== previousVersion) {
|
|
73202
73300
|
try {
|