@trops/dash-core 0.1.390 → 0.1.392

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.
@@ -25705,6 +25705,31 @@ function isNodeEsmError(errorText) {
25705
25705
  );
25706
25706
  }
25707
25707
 
25708
+ /**
25709
+ * When a catalog entry says `command: "node"`, spawn Electron itself in
25710
+ * ELECTRON_RUN_AS_NODE mode rather than the user's system node. This
25711
+ * matters in two ways:
25712
+ *
25713
+ * 1. In a packaged app the MCP server scripts live inside app.asar.
25714
+ * Electron's fs patches understand asar paths; a standalone Node
25715
+ * does not, so system `node` + asar path produces MODULE_NOT_FOUND.
25716
+ * 2. The host no longer depends on the user having a compatible Node
25717
+ * version (18–22) installed on PATH — Electron ships its own.
25718
+ *
25719
+ * Other commands (`npx`, shell scripts, etc.) still run via the
25720
+ * resolved shell PATH, so the PATH/nvm discovery elsewhere in this
25721
+ * file stays relevant for them.
25722
+ */
25723
+ function resolveNodeCommand(command, env) {
25724
+ if (command === "node" && process.versions.electron) {
25725
+ return {
25726
+ command: process.execPath,
25727
+ env: { ...env, ELECTRON_RUN_AS_NODE: "1" },
25728
+ };
25729
+ }
25730
+ return { command, env };
25731
+ }
25732
+
25708
25733
  /**
25709
25734
  * Get the user's full shell PATH (including nvm, homebrew, volta, etc.).
25710
25735
  * Electron GUI apps on macOS don't inherit the shell PATH, so we
@@ -26115,10 +26140,11 @@ const mcpController$2 = {
26115
26140
  }
26116
26141
  }
26117
26142
 
26143
+ const resolved = resolveNodeCommand(mcpConfig.command, env);
26118
26144
  transport = new StdioClientTransport({
26119
- command: mcpConfig.command,
26145
+ command: resolved.command,
26120
26146
  args,
26121
- env,
26147
+ env: resolved.env,
26122
26148
  });
26123
26149
  }
26124
26150
 
@@ -26614,8 +26640,9 @@ const mcpController$2 = {
26614
26640
  );
26615
26641
 
26616
26642
  return new Promise((resolve) => {
26617
- const proc = spawn(authCommand.command, resolvedArgs, {
26618
- env,
26643
+ const resolvedCmd = resolveNodeCommand(authCommand.command, env);
26644
+ const proc = spawn(resolvedCmd.command, resolvedArgs, {
26645
+ env: resolvedCmd.env,
26619
26646
  stdio: ["ignore", "pipe", "pipe"],
26620
26647
  // Needed so Windows can launch .cmd/.bat wrappers (npx.cmd, etc).
26621
26648
  shell: IS_WINDOWS$1,
@@ -29711,14 +29738,23 @@ async function searchThemes(query = "", filters = {}) {
29711
29738
  * where the user is browsing registry widgets and wants to see them render
29712
29739
  * inline before choosing to install or remix.
29713
29740
  *
29741
+ * Multi-widget packages (e.g. @trops/clock contains Analog/Digital/Flip/Text
29742
+ * clocks) ship with one .js + .dash.js pair per widget. Pass `componentName`
29743
+ * to pick a specific widget — otherwise we return the alphabetically-first
29744
+ * widget found, which is almost never what the caller wants for UI previews.
29745
+ *
29714
29746
  * @param {string} packageName - Any form accepted by getPackage()
29715
29747
  * (bare name, scoped "scope/name", or displayName)
29748
+ * @param {string} [componentName] - Specific widget inside the package to
29749
+ * return. Matched against file names in `widgets/`. Accepts either a
29750
+ * bare name ("FlipClockWidget") or a dotted scoped id
29751
+ * ("trops.clock.FlipClockWidget") — the last dotted segment is used.
29716
29752
  * @returns {Promise<Object>} {
29717
29753
  * componentCode, configCode, bundleSource, widgetName,
29718
29754
  * displayName, description, packageName, scope, downloadUrl
29719
29755
  * }
29720
29756
  */
29721
- async function fetchPackageSource(packageName) {
29757
+ async function fetchPackageSource(packageName, componentName = null) {
29722
29758
  if (!packageName) {
29723
29759
  throw new Error("fetchPackageSource: packageName is required");
29724
29760
  }
@@ -29809,14 +29845,40 @@ async function fetchPackageSource(packageName) {
29809
29845
 
29810
29846
  if (fs$5.existsSync(widgetsDir)) {
29811
29847
  const files = fs$5.readdirSync(widgetsDir);
29812
- const configFile = files.find((f) => f.endsWith(".dash.js"));
29848
+ const dashFiles = files.filter((f) => f.endsWith(".dash.js"));
29849
+ const componentFiles = files.filter(
29850
+ (f) => f.endsWith(".js") && !f.endsWith(".dash.js") && f !== "index.js",
29851
+ );
29852
+
29853
+ // Normalize componentName hint: accept "FlipClockWidget" or the
29854
+ // dotted form "trops.clock.FlipClockWidget" (last segment wins).
29855
+ const bareHint =
29856
+ typeof componentName === "string" && componentName.length
29857
+ ? componentName.split(".").pop()
29858
+ : null;
29859
+
29860
+ // Pick the .dash.js pair that matches the hint; fall back to the
29861
+ // first file so pre-hint callers still work.
29862
+ let configFile = null;
29863
+ if (bareHint) {
29864
+ configFile = dashFiles.find((f) => f === `${bareHint}.dash.js`);
29865
+ }
29866
+ if (!configFile) configFile = dashFiles[0];
29867
+
29813
29868
  if (configFile) {
29814
29869
  configCode = fs$5.readFileSync(path$9.join(widgetsDir, configFile), "utf8");
29815
29870
  widgetName = configFile.replace(/\.dash\.js$/, "");
29816
29871
  }
29817
- const componentFile = files.find(
29818
- (f) => f.endsWith(".js") && !f.endsWith(".dash.js"),
29819
- );
29872
+
29873
+ let componentFile = null;
29874
+ if (widgetName) {
29875
+ componentFile = componentFiles.find((f) => f === `${widgetName}.js`);
29876
+ }
29877
+ if (!componentFile && bareHint) {
29878
+ componentFile = componentFiles.find((f) => f === `${bareHint}.js`);
29879
+ }
29880
+ if (!componentFile) componentFile = componentFiles[0];
29881
+
29820
29882
  if (componentFile) {
29821
29883
  componentCode = fs$5.readFileSync(
29822
29884
  path$9.join(widgetsDir, componentFile),
@@ -74400,11 +74462,18 @@ const registryApi$2 = {
74400
74462
  * Discover tab).
74401
74463
  *
74402
74464
  * @param {string} packageName - Name of the package (any form)
74465
+ * @param {string} [componentName] - Specific widget in a multi-widget
74466
+ * package. Accepts either a bare name ("FlipClockWidget") or a dotted
74467
+ * scoped id ("trops.clock.FlipClockWidget").
74403
74468
  * @returns {Promise<Object>} { componentCode, configCode, bundleSource, widgetName, displayName, description, packageName, scope, downloadUrl }
74404
74469
  */
74405
- previewFetch: async (packageName) => {
74470
+ previewFetch: async (packageName, componentName = null) => {
74406
74471
  try {
74407
- return await ipcRenderer$h.invoke("registry:preview-fetch", packageName);
74472
+ return await ipcRenderer$h.invoke(
74473
+ "registry:preview-fetch",
74474
+ packageName,
74475
+ componentName,
74476
+ );
74408
74477
  } catch (error) {
74409
74478
  console.error(
74410
74479
  `[RegistryApi] Error fetching preview source for ${packageName}:`,