@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.
@@ -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 pass an
51667
- // inline --mcp-config every spawn; merges with any user-configured
51668
- // MCPs so their other tools (github, slack, etc.) remain available.
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
- args.push("--mcp-config", mcpConfig);
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) packageName = w.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. Build manifest using the widget's component configs. The
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: options.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
- // 6. Zip the widget directory to a temp file
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
- // 7. Publish to registry
73291
+ // 8. Publish to registry
73194
73292
  const registryResult = await registryApiController$1.publishToRegistry(
73195
73293
  zipPath,
73196
73294
  manifest,
73197
73295
  );
73198
73296
 
73199
- // 8. On failure: revert package.json (if we bumped) and surface details
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 {