@mgsoftwarebv/mg-dashboard-mcp 7.0.7 → 7.0.8

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/index.js CHANGED
@@ -619,6 +619,12 @@ var TERMINAL_STATUSES = /* @__PURE__ */ new Set([
619
619
  "INTERRUPTED",
620
620
  "EXPIRED"
621
621
  ]);
622
+ var EXECUTE_PIPELINE_TASK = "execute-pipeline";
623
+ function validateExecutePipelineTestPayload(payload) {
624
+ const stepIds = payload.stepIds;
625
+ if (Array.isArray(stepIds) && stepIds.length > 0) return null;
626
+ return 'execute-pipeline requires real stepIds from a release row. Use a lightweight task (e.g. "hello-world") for connectivity checks, or pass a payload with releaseId (UUID) and non-empty stepIds.';
627
+ }
622
628
  var TRIGGER_SERVER_ID = "03659d55-e194-400d-b82a-bf6457371ded";
623
629
  var COMPOSE_PROJECT = "mg-dashboard-supabase-trigger";
624
630
  var PG_CONTAINER = `${COMPOSE_PROJECT}-postgres-1`;
@@ -678,10 +684,10 @@ var TRIGGER_TOOL_MODULE_MAP = {
678
684
  "trigger-run": "ci_cd"
679
685
  };
680
686
  async function discoverInstance(projectSlug, conn, proxy, sshExec2) {
681
- const sql28 = `SELECT re.\\"apiKey\\" FROM \\"RuntimeEnvironment\\" re JOIN \\"Project\\" p ON re.\\"projectId\\" = p.id WHERE p.slug='${projectSlug}' AND re.slug='prod' LIMIT 1`;
687
+ const sql29 = `SELECT re.\\"apiKey\\" FROM \\"RuntimeEnvironment\\" re JOIN \\"Project\\" p ON re.\\"projectId\\" = p.id WHERE p.slug='${projectSlug}' AND re.slug='prod' LIMIT 1`;
682
688
  const cmd = [
683
689
  `PORT=$(docker port "${WA_CONTAINER}" 3000/tcp 2>/dev/null | head -1 | sed 's/.*://')`,
684
- `KEY=$(docker exec "${PG_CONTAINER}" psql -U postgres -d main -t -A -c "${sql28}" 2>/dev/null | tr -d '[:space:]')`,
690
+ `KEY=$(docker exec "${PG_CONTAINER}" psql -U postgres -d main -t -A -c "${sql29}" 2>/dev/null | tr -d '[:space:]')`,
685
691
  'echo "$PORT|$KEY"'
686
692
  ].join(" && ");
687
693
  const result = await sshExec2(conn, cmd, proxy);
@@ -702,8 +708,8 @@ async function discoverInstance(projectSlug, conn, proxy, sshExec2) {
702
708
  return { port, apiKey: apiKey2 };
703
709
  }
704
710
  async function fetchRunLogs(runId, conn, proxy, sshExec2) {
705
- const sql28 = `SELECT level, message, \\"isError\\", \\"createdAt\\" FROM \\"TaskEvent\\" WHERE \\"runId\\" = '${runId}' AND level IN ('INFO','WARN','ERROR','DEBUG','LOG','TRACE') ORDER BY \\"startTime\\" ASC LIMIT 200`;
706
- const cmd = `docker exec "${PG_CONTAINER}" psql -U postgres -d main -t -A -c "${sql28}" 2>/dev/null`;
711
+ const sql29 = `SELECT level, message, \\"isError\\", \\"createdAt\\" FROM \\"TaskEvent\\" WHERE \\"runId\\" = '${runId}' AND level IN ('INFO','WARN','ERROR','DEBUG','LOG','TRACE') ORDER BY \\"startTime\\" ASC LIMIT 200`;
712
+ const cmd = `docker exec "${PG_CONTAINER}" psql -U postgres -d main -t -A -c "${sql29}" 2>/dev/null`;
707
713
  const result = await sshExec2(conn, cmd, proxy);
708
714
  const output = result.stdout.trim();
709
715
  if (!output) return "";
@@ -785,8 +791,8 @@ async function handleTriggerTool(name, args2, deps) {
785
791
  switch (name) {
786
792
  // -----------------------------------------------------------------
787
793
  case "trigger-list": {
788
- const sql28 = 'SELECT slug, name FROM \\"Project\\" ORDER BY name';
789
- const cmd = `docker exec "${PG_CONTAINER}" psql -U postgres -d main -t -A -c "${sql28}" 2>/dev/null`;
794
+ const sql29 = 'SELECT slug, name FROM \\"Project\\" ORDER BY name';
795
+ const cmd = `docker exec "${PG_CONTAINER}" psql -U postgres -d main -t -A -c "${sql29}" 2>/dev/null`;
790
796
  const result = await sshExec2(conn, cmd, proxy);
791
797
  const output = result.stdout.trim();
792
798
  if (!output) {
@@ -867,8 +873,15 @@ ${rawJson.substring(0, 500)}` }] };
867
873
  throw new Error(`Invalid JSON payload: ${String(args2.payload).substring(0, 200)}`);
868
874
  }
869
875
  }
876
+ const parsedPayload = JSON.parse(payload);
877
+ if (taskId === EXECUTE_PIPELINE_TASK) {
878
+ const validationError = validateExecutePipelineTestPayload(parsedPayload);
879
+ if (validationError) {
880
+ return { content: [{ type: "text", text: `Error: ${validationError}` }] };
881
+ }
882
+ }
870
883
  const triggerBody = JSON.stringify({
871
- payload: JSON.parse(payload),
884
+ payload: parsedPayload,
872
885
  options: { tags: ["mcp-test"], test: true }
873
886
  });
874
887
  const triggerJson = await triggerApi(
@@ -944,9 +957,9 @@ async function fetchAndFormatRun(conn, proxy, sshExec2, instance, runId) {
944
957
  return { content: [{ type: "text", text: `Invalid API response:
945
958
  ${rawJson.substring(0, 500)}` }] };
946
959
  }
947
- let text6 = formatRunDetail(run);
948
- if (logs) text6 += "\n\n--- Logs ---\n" + logs;
949
- return { content: [{ type: "text", text: text6 }] };
960
+ let text7 = formatRunDetail(run);
961
+ if (logs) text7 += "\n\n--- Logs ---\n" + logs;
962
+ return { content: [{ type: "text", text: text7 }] };
950
963
  }
951
964
  async function waitForCompletion(conn, proxy, sshExec2, instance, runId, waitSeconds) {
952
965
  const pollInterval = 3e3;
@@ -968,10 +981,10 @@ async function waitForCompletion(conn, proxy, sshExec2, instance, runId, waitSec
968
981
  continue;
969
982
  }
970
983
  if (TERMINAL_STATUSES.has(run.status)) {
971
- let text6 = formatRunDetail(run);
984
+ let text7 = formatRunDetail(run);
972
985
  const logs = await fetchRunLogs(runId, conn, proxy, sshExec2);
973
- if (logs) text6 += "\n\n--- Logs ---\n" + logs;
974
- return { content: [{ type: "text", text: text6 }] };
986
+ if (logs) text7 += "\n\n--- Logs ---\n" + logs;
987
+ return { content: [{ type: "text", text: text7 }] };
975
988
  }
976
989
  }
977
990
  return {
@@ -3658,10 +3671,10 @@ var ZodObject = class _ZodObject extends ZodType {
3658
3671
  // }) as any;
3659
3672
  // return merged;
3660
3673
  // }
3661
- catchall(index4) {
3674
+ catchall(index5) {
3662
3675
  return new _ZodObject({
3663
3676
  ...this._def,
3664
- catchall: index4
3677
+ catchall: index5
3665
3678
  });
3666
3679
  }
3667
3680
  pick(mask) {
@@ -3979,9 +3992,9 @@ function mergeValues(a, b) {
3979
3992
  return { valid: false };
3980
3993
  }
3981
3994
  const newArray = [];
3982
- for (let index4 = 0; index4 < a.length; index4++) {
3983
- const itemA = a[index4];
3984
- const itemB = b[index4];
3995
+ for (let index5 = 0; index5 < a.length; index5++) {
3996
+ const itemA = a[index5];
3997
+ const itemB = b[index5];
3985
3998
  const sharedValue = mergeValues(itemA, itemB);
3986
3999
  if (!sharedValue.valid) {
3987
4000
  return { valid: false };
@@ -4187,10 +4200,10 @@ var ZodMap = class extends ZodType {
4187
4200
  }
4188
4201
  const keyType = this._def.keyType;
4189
4202
  const valueType = this._def.valueType;
4190
- const pairs = [...ctx.data.entries()].map(([key, value], index4) => {
4203
+ const pairs = [...ctx.data.entries()].map(([key, value], index5) => {
4191
4204
  return {
4192
- key: keyType._parse(new ParseInputLazyPath(ctx, key, ctx.path, [index4, "key"])),
4193
- value: valueType._parse(new ParseInputLazyPath(ctx, value, ctx.path, [index4, "value"]))
4205
+ key: keyType._parse(new ParseInputLazyPath(ctx, key, ctx.path, [index5, "key"])),
4206
+ value: valueType._parse(new ParseInputLazyPath(ctx, value, ctx.path, [index5, "value"]))
4194
4207
  };
4195
4208
  });
4196
4209
  if (ctx.common.async) {
@@ -5716,7 +5729,30 @@ pgTable(
5716
5729
  index("github_token_owner_idx").on(table.owner)
5717
5730
  ]
5718
5731
  );
5732
+ pgTable(
5733
+ "github_webhook_secret",
5734
+ {
5735
+ id: uuid("id").primaryKey().defaultRandom(),
5736
+ label: text("label").notNull(),
5737
+ owner: text("owner"),
5738
+ notes: text("notes"),
5739
+ secretEncrypted: text("secret_encrypted").notNull(),
5740
+ enabled: boolean("enabled").notNull().default(true),
5741
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
5742
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
5743
+ },
5744
+ (table) => [
5745
+ index("github_webhook_secret_label_idx").on(table.label),
5746
+ index("github_webhook_secret_owner_idx").on(table.owner)
5747
+ ]
5748
+ );
5749
+ function assertPipelinePayload(payload) {
5750
+ if (!payload.stepIds?.length) {
5751
+ throw new Error("Cannot trigger execute-pipeline: stepIds is empty");
5752
+ }
5753
+ }
5719
5754
  async function triggerPipeline(payload) {
5755
+ assertPipelinePayload(payload);
5720
5756
  return tasks.trigger(
5721
5757
  "execute-pipeline",
5722
5758
  payload
@@ -6168,6 +6204,24 @@ async function createReleaseForStage(userId, params) {
6168
6204
  if (!triggerAuthorName && userId) {
6169
6205
  triggerAuthorName = await resolveUserDisplayName(userId);
6170
6206
  }
6207
+ const enabledSteps = buildStepList(
6208
+ stage,
6209
+ profile,
6210
+ await resolveBuildStepListOptions({
6211
+ profile,
6212
+ triggerSha,
6213
+ githubToken: token,
6214
+ isManual: triggerType === "manual" || triggerType === "mcp",
6215
+ stageId: params.stageId,
6216
+ deployRetryScripts: stage.deploy_retry_scripts
6217
+ })
6218
+ );
6219
+ if (enabledSteps.length === 0) {
6220
+ throw new CreateReleaseError(
6221
+ "No pipeline steps configured for this stage (enable a PM2/Docker stage_app or deployment_project_server)",
6222
+ "PRECONDITION_FAILED"
6223
+ );
6224
+ }
6171
6225
  const initialStatus = "running";
6172
6226
  let release;
6173
6227
  try {
@@ -6201,18 +6255,6 @@ async function createReleaseForStage(userId, params) {
6201
6255
  "INTERNAL_SERVER_ERROR"
6202
6256
  );
6203
6257
  }
6204
- const enabledSteps = buildStepList(
6205
- stage,
6206
- profile,
6207
- await resolveBuildStepListOptions({
6208
- profile,
6209
- triggerSha,
6210
- githubToken: token,
6211
- isManual: triggerType === "manual" || triggerType === "mcp",
6212
- stageId: params.stageId,
6213
- deployRetryScripts: stage.deploy_retry_scripts
6214
- })
6215
- );
6216
6258
  const stepIds = [];
6217
6259
  try {
6218
6260
  stepIds.push(...await insertReleaseSteps(release.id, enabledSteps));
@@ -7435,7 +7477,7 @@ function getEncryptionKey() {
7435
7477
  throw new Error("ENCRYPTION_KEY must be a 64-character hex string");
7436
7478
  return buf;
7437
7479
  }
7438
- function encrypt(text6) {
7480
+ function encrypt(text7) {
7439
7481
  const key = getEncryptionKey();
7440
7482
  const iv = randomBytes(ENC_IV_LENGTH);
7441
7483
  const cipher = createCipheriv(
@@ -7443,7 +7485,7 @@ function encrypt(text6) {
7443
7485
  new Uint8Array(key),
7444
7486
  new Uint8Array(iv)
7445
7487
  );
7446
- let encrypted = cipher.update(text6, "utf8", "hex");
7488
+ let encrypted = cipher.update(text7, "utf8", "hex");
7447
7489
  encrypted += cipher.final("hex");
7448
7490
  const authTag = cipher.getAuthTag();
7449
7491
  return Buffer.concat([
@@ -8163,10 +8205,10 @@ async function r2GetObjectRange(bucket, key, range) {
8163
8205
  const body = result.Body;
8164
8206
  if (!body?.transformToString)
8165
8207
  throw new Error("R2 returned no readable body");
8166
- const text6 = await body.transformToString();
8208
+ const text7 = await body.transformToString();
8167
8209
  const header = `# range: bytes ${range.offset}-${end} of ${size} (${effectiveLen} bytes)`;
8168
8210
  return `${header}
8169
- ${text6}`;
8211
+ ${text7}`;
8170
8212
  } catch (e) {
8171
8213
  throw r2WrapError(bucket, key, e);
8172
8214
  }
@@ -8529,15 +8571,15 @@ async function sftpRead(opts, filePath, proxy, options) {
8529
8571
  clearTimeout(timer);
8530
8572
  cleanup?.();
8531
8573
  cleanup = void 0;
8532
- const text6 = Buffer.concat(
8574
+ const text7 = Buffer.concat(
8533
8575
  chunks.map((ch) => new Uint8Array(ch))
8534
8576
  ).toString("utf-8");
8535
8577
  if (!isWholeFileRequest) {
8536
8578
  const header = `# range: bytes ${offset}-${offset + effectiveLen - 1} of ${total} (${effectiveLen} bytes)`;
8537
8579
  resolve(`${header}
8538
- ${text6}`);
8580
+ ${text7}`);
8539
8581
  } else {
8540
- resolve(text6);
8582
+ resolve(text7);
8541
8583
  }
8542
8584
  });
8543
8585
  rs.on("error", (e) => {
@@ -8667,11 +8709,11 @@ function getKnownContainers(serverId, maxAgeMs = 5 * 6e4) {
8667
8709
  if (Date.now() - e.capturedAt > maxAgeMs) return void 0;
8668
8710
  return e.names;
8669
8711
  }
8670
- function truncateForLLM(text6, maxBytes) {
8671
- const totalBytes = Buffer.byteLength(text6, "utf8");
8712
+ function truncateForLLM(text7, maxBytes) {
8713
+ const totalBytes = Buffer.byteLength(text7, "utf8");
8672
8714
  if (totalBytes <= maxBytes)
8673
- return { text: text6, truncated: false, totalBytes, shownBytes: totalBytes };
8674
- const buf = Buffer.from(text6, "utf8");
8715
+ return { text: text7, truncated: false, totalBytes, shownBytes: totalBytes };
8716
+ const buf = Buffer.from(text7, "utf8");
8675
8717
  let cut = maxBytes;
8676
8718
  while (cut > 0 && (buf[cut] & 192) === 128) cut--;
8677
8719
  const head = buf.subarray(0, cut).toString("utf8");
@@ -8701,10 +8743,10 @@ function isTransientSshError(stderr, exitCode) {
8701
8743
  function postprocessResult(result, meta) {
8702
8744
  if (!result.content?.length) return result;
8703
8745
  const block = result.content[0];
8704
- let text6 = String(block.text ?? "");
8705
- const trunc = truncateForLLM(text6, RESPONSE_MAX_BYTES);
8746
+ let text7 = String(block.text ?? "");
8747
+ const trunc = truncateForLLM(text7, RESPONSE_MAX_BYTES);
8706
8748
  if (trunc.truncated) {
8707
- text6 = trunc.text + "\n\n... " + buildTruncationHint(
8749
+ text7 = trunc.text + "\n\n... " + buildTruncationHint(
8708
8750
  meta.toolName,
8709
8751
  meta.args,
8710
8752
  trunc.totalBytes,
@@ -8718,11 +8760,11 @@ function postprocessResult(result, meta) {
8718
8760
  const parts = [`took ${tookStr}`, sizeStr];
8719
8761
  if (meta.serverIdLabel) parts.push(`server: ${meta.serverIdLabel}`);
8720
8762
  if (meta.cached) parts.push("cached");
8721
- text6 = `${text6}
8763
+ text7 = `${text7}
8722
8764
 
8723
8765
  [${parts.join(", ")}]`;
8724
8766
  }
8725
- return { ...result, content: [{ ...block, text: text6 }] };
8767
+ return { ...result, content: [{ ...block, text: text7 }] };
8726
8768
  }
8727
8769
  function buildPipelineScript(commands, shell, marker, stopOnError) {
8728
8770
  if (shell === "powershell") {
@@ -9508,11 +9550,11 @@ CREATE TABLE IF NOT EXISTS _mcp_migrations (
9508
9550
  applied_by TEXT
9509
9551
  );
9510
9552
  `.trim();
9511
- function normaliseMigrationSql(sql28) {
9512
- return sql28.replace(/\r\n/g, "\n").trim() + "\n";
9553
+ function normaliseMigrationSql(sql29) {
9554
+ return sql29.replace(/\r\n/g, "\n").trim() + "\n";
9513
9555
  }
9514
- function migrationSha256(sql28) {
9515
- return createHash("sha256").update(normaliseMigrationSql(sql28), "utf8").digest("hex");
9556
+ function migrationSha256(sql29) {
9557
+ return createHash("sha256").update(normaliseMigrationSql(sql29), "utf8").digest("hex");
9516
9558
  }
9517
9559
  function dollarQuoteTag(value) {
9518
9560
  let tag = "_mcp";
@@ -11777,8 +11819,8 @@ ${sample.join("\n")}${files.length > 5 ? `
11777
11819
  };
11778
11820
  const filtered = sortRows(applyFilter(only.rows));
11779
11821
  if (format === "json") {
11780
- const text7 = filtered.map((c) => JSON.stringify(c)).join("\n") || "(no containers)";
11781
- return { content: [{ type: "text", text: text7 }] };
11822
+ const text8 = filtered.map((c) => JSON.stringify(c)).join("\n") || "(no containers)";
11823
+ return { content: [{ type: "text", text: text8 }] };
11782
11824
  }
11783
11825
  if (groupByProject) {
11784
11826
  const groups = /* @__PURE__ */ new Map();
@@ -11805,8 +11847,8 @@ ${sample.join("\n")}${files.length > 5 ? `
11805
11847
  }
11806
11848
  const header = `${"NAMES".padEnd(36)} ${"IMAGE".padEnd(40)} ${"STATUS".padEnd(24)} ${"HEALTH".padEnd(10)} ${"PORTS".padEnd(40)} PROJECT`;
11807
11849
  const body = filtered.map((r) => `${fmtRow(r)} ${r.Project || ""}`);
11808
- const text6 = filtered.length === 0 ? "(no containers match)" : [header, ...body].join("\n");
11809
- return { content: [{ type: "text", text: text6 }] };
11850
+ const text7 = filtered.length === 0 ? "(no containers match)" : [header, ...body].join("\n");
11851
+ return { content: [{ type: "text", text: text7 }] };
11810
11852
  }
11811
11853
  if (format === "json") {
11812
11854
  const lines = [];