@trops/dash-core 0.1.649 → 0.1.650

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.
@@ -21,7 +21,7 @@ var require$$11 = require('https');
21
21
  var require$$0$8 = require('@modelcontextprotocol/sdk/client/index.js');
22
22
  var require$$1$6 = require('@modelcontextprotocol/sdk/client/stdio.js');
23
23
  var require$$0$7 = require('pkce-challenge');
24
- var require$$13 = require('child_process');
24
+ var require$$14 = require('child_process');
25
25
  var require$$1$5 = require('http');
26
26
  var require$$2$2 = require('algoliasearch');
27
27
  var require$$3$2 = require('node:path');
@@ -37264,6 +37264,128 @@ var mcpServerKey = {
37264
37264
  SEP,
37265
37265
  };
37266
37266
 
37267
+ /**
37268
+ * mcpStartError.js — explain why an MCP server failed to start.
37269
+ *
37270
+ * A stdio server that exits during startup (a missing token, a bad path)
37271
+ * surfaces from the MCP SDK as "MCP error -32000: Connection closed". The
37272
+ * real reason is on the server's stderr, e.g. Slack's
37273
+ * {"level":"fatal","message":"Authentication required: …"}
37274
+ * This turns that into "Slack couldn't start: Authentication required: ….
37275
+ * Check its settings in Settings › Providers." — one trimmed line, with
37276
+ * anything that looks like a secret redacted.
37277
+ */
37278
+
37279
+ const NEXT_STEP = "Check its settings in Settings › Providers.";
37280
+ const MAX_REASON = 300;
37281
+
37282
+ // SDK messages that say nothing about the cause.
37283
+ const UNINFORMATIVE = /connection closed|-32000|process exited|terminated/i;
37284
+ // A line worth showing.
37285
+ const ERRORISH =
37286
+ /error|required|fatal|denied|not found|invalid|missing|unauthori[sz]ed|forbidden|failed/i;
37287
+ // Noise around a crash: stack frames, Node banners, the npx wrapper.
37288
+ const NOISE = [
37289
+ /^at\s/,
37290
+ /^node:/,
37291
+ /^Node\.js v/,
37292
+ /^throw\s/,
37293
+ /^\^+$/,
37294
+ /Command failed:/,
37295
+ ];
37296
+
37297
+ const SECRETS = [
37298
+ [/\bxox[a-z]-[A-Za-z0-9-]+/g, "[redacted]"], // Slack
37299
+ [/\bsk-[A-Za-z0-9_-]{10,}/g, "[redacted]"], // OpenAI / Anthropic style
37300
+ [/\bgh[pousr]_[A-Za-z0-9]{20,}/g, "[redacted]"], // GitHub
37301
+ [/\bBearer\s+\S+/gi, "Bearer [redacted]"],
37302
+ // Long random-looking strings (letters and digits mixed).
37303
+ [
37304
+ /\b(?=[A-Za-z0-9_-]*\d)(?=[A-Za-z0-9_-]*[A-Za-z])[A-Za-z0-9_-]{32,}\b/g,
37305
+ "[redacted]",
37306
+ ],
37307
+ ];
37308
+
37309
+ function redact(text) {
37310
+ return SECRETS.reduce((t, [re, sub]) => t.replace(re, sub), text);
37311
+ }
37312
+
37313
+ function jsonReason(line) {
37314
+ if (!line.startsWith("{")) return null;
37315
+ try {
37316
+ const obj = JSON.parse(line);
37317
+ const level = String(obj.level || obj.severity || "").toLowerCase();
37318
+ const msg = obj.message || obj.msg || obj.error;
37319
+ if (typeof msg !== "string" || !msg.trim()) return null;
37320
+ if (level && !/fatal|error|crit|panic/.test(level)) return null;
37321
+ return msg.trim();
37322
+ } catch (_e) {
37323
+ return null;
37324
+ }
37325
+ }
37326
+
37327
+ /** The most useful line of a failed server's stderr, or null. */
37328
+ function reasonFromStderr(stderr) {
37329
+ const lines = String(stderr || "")
37330
+ .split(/\r?\n/)
37331
+ .map((l) => l.trim())
37332
+ .filter(Boolean);
37333
+ // A structured fatal/error log line is the most precise.
37334
+ for (let i = lines.length - 1; i >= 0; i--) {
37335
+ const r = jsonReason(lines[i]);
37336
+ if (r) return r;
37337
+ }
37338
+ for (let i = lines.length - 1; i >= 0; i--) {
37339
+ const line = lines[i];
37340
+ if (NOISE.some((re) => re.test(line))) continue;
37341
+ if (!ERRORISH.test(line)) continue;
37342
+ return line.replace(/^(Error|Fatal|FATAL|ERROR):\s*/, "");
37343
+ }
37344
+ return null;
37345
+ }
37346
+
37347
+ /**
37348
+ * @param {{ serverName: string, message: string, stderr?: string|null }} args
37349
+ * @returns {string} the message to show
37350
+ */
37351
+ function describeStartFailure$1({ serverName, message, stderr }) {
37352
+ if (message && !UNINFORMATIVE.test(message)) return message;
37353
+ const name = serverName || "The MCP server";
37354
+ const raw = reasonFromStderr(stderr);
37355
+ if (!raw)
37356
+ return `${name} couldn't start (it closed the connection). ${NEXT_STEP}`;
37357
+ let reason = redact(raw).replace(/[.\s]+$/, "");
37358
+ if (reason.length > MAX_REASON)
37359
+ reason = reason.slice(0, MAX_REASON).trimEnd() + "…";
37360
+ return `${name} couldn't start: ${reason}. ${NEXT_STEP}`;
37361
+ }
37362
+
37363
+ /**
37364
+ * The last `limit` characters of a stream (a failed server's stderr), so a
37365
+ * chatty server can't grow memory without bound.
37366
+ */
37367
+ let StderrTail$1 = class StderrTail {
37368
+ constructor(limit = 4096) {
37369
+ this._limit = limit;
37370
+ this._text = "";
37371
+ }
37372
+
37373
+ push(chunk) {
37374
+ this._text += Buffer.isBuffer(chunk)
37375
+ ? chunk.toString("utf8")
37376
+ : String(chunk);
37377
+ if (this._text.length > this._limit) {
37378
+ this._text = this._text.slice(-this._limit);
37379
+ }
37380
+ }
37381
+
37382
+ text() {
37383
+ return this._text;
37384
+ }
37385
+ };
37386
+
37387
+ var mcpStartError = { describeStartFailure: describeStartFailure$1, StderrTail: StderrTail$1 };
37388
+
37267
37389
  /**
37268
37390
  * toolSources.js — how a bot finds, starts, and uses the user's Dash MCP
37269
37391
  * providers (the integrations configured under Settings → Providers).
@@ -37896,6 +38018,7 @@ const os$2 = require$$2;
37896
38018
  const responseCache$2 = responseCache_1;
37897
38019
  const { gateToolCall, gateToolCallWithJit } = permissionGate;
37898
38020
  const { serverKey, parseServerKey } = mcpServerKey;
38021
+ const { describeStartFailure, StderrTail } = mcpStartError;
37899
38022
  const { connectedServersFromMap } = toolSources;
37900
38023
  const { applyPathScopeToCredentials } = mcpScopeResolver;
37901
38024
  const { readEnforceFlag: readEnforceFlag$1, readJitFlag: readJitFlag$1 } = securityFlags;
@@ -38070,7 +38193,7 @@ function getShellPath$1() {
38070
38193
  return _shellPath$1;
38071
38194
  }
38072
38195
 
38073
- const { execSync } = require$$13;
38196
+ const { execSync } = require$$14;
38074
38197
  const fallbackDirs = ["/usr/local/bin", "/opt/homebrew/bin"];
38075
38198
 
38076
38199
  // Scan nvm versions, tracking both latest and best compatible version
@@ -38418,6 +38541,9 @@ const mcpController$3 = {
38418
38541
 
38419
38542
  // 3. Fresh start — wrap in a promise and track it
38420
38543
  const startPromise = (async () => {
38544
+ // A stdio server's recent stderr — the real reason when it exits
38545
+ // during startup (e.g. a missing token).
38546
+ let stderrTail = null;
38421
38547
  try {
38422
38548
  // Stop if in stale/error state
38423
38549
  if (activeServers.has(key)) {
@@ -38569,7 +38695,15 @@ const mcpController$3 = {
38569
38695
  command: resolved.command,
38570
38696
  args,
38571
38697
  env: resolved.env,
38698
+ stderr: "pipe",
38572
38699
  });
38700
+ stderrTail = new StderrTail();
38701
+ if (transport.stderr) {
38702
+ transport.stderr.on("data", (chunk) => {
38703
+ stderrTail.push(chunk);
38704
+ process.stderr.write(chunk);
38705
+ });
38706
+ }
38573
38707
  }
38574
38708
 
38575
38709
  // Update status to connecting
@@ -38659,6 +38793,13 @@ const mcpController$3 = {
38659
38793
  errorMessage =
38660
38794
  "This MCP server is incompatible with your system Node.js version. " +
38661
38795
  "Install Node.js v22 (LTS) using nvm and restart the app.";
38796
+ } else {
38797
+ // "Connection closed" says nothing; use the server's own reason.
38798
+ errorMessage = describeStartFailure({
38799
+ serverName,
38800
+ message: error.message,
38801
+ stderr: stderrTail ? stderrTail.text() : "",
38802
+ });
38662
38803
  }
38663
38804
 
38664
38805
  // Mark as error state
@@ -39196,7 +39337,7 @@ const mcpController$3 = {
39196
39337
  * @returns {{ success } | { error, message }}
39197
39338
  */
39198
39339
  runAuth: async (win, mcpConfig, credentials, authCommand) => {
39199
- const { spawn } = require$$13;
39340
+ const { spawn } = require$$14;
39200
39341
 
39201
39342
  const env = cleanEnvForChildProcess();
39202
39343
 
@@ -60061,7 +60202,7 @@ var mcpDashServerController_1 = mcpDashServerController$4;
60061
60202
  * can use the Chat widget without a separate API key.
60062
60203
  */
60063
60204
 
60064
- const { spawn, execSync } = require$$13;
60205
+ const { spawn, execSync } = require$$14;
60065
60206
  const {
60066
60207
  LLM_STREAM_DELTA: LLM_STREAM_DELTA$2,
60067
60208
  LLM_STREAM_TOOL_CALL: LLM_STREAM_TOOL_CALL$2,