@mgsoftwarebv/mg-dashboard-mcp 7.4.4 → 7.4.6

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.
Files changed (2) hide show
  1. package/dist/index.js +572 -185
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -20,7 +20,7 @@ import { sql } from 'drizzle-orm';
20
20
  import { once } from 'events';
21
21
  import { lookup } from 'dns/promises';
22
22
  import { connect } from 'tls';
23
- import { pgTable, timestamp, jsonb, uuid, boolean, text, pgEnum, integer, uniqueIndex, index, check, bigint, foreignKey } from 'drizzle-orm/pg-core';
23
+ import { pgTable, timestamp, jsonb, uuid, boolean, text, pgEnum, integer, uniqueIndex, index, check, bigint, doublePrecision, foreignKey } from 'drizzle-orm/pg-core';
24
24
  import { HeadObjectCommand, ListObjectsV2Command, DeleteObjectsCommand, S3Client, DeleteObjectCommand, CreateMultipartUploadCommand, UploadPartCommand, CompleteMultipartUploadCommand, AbortMultipartUploadCommand, PutObjectCommand, GetObjectCommand, CopyObjectCommand } from '@aws-sdk/client-s3';
25
25
 
26
26
  var __defProp = Object.defineProperty;
@@ -703,10 +703,10 @@ var TRIGGER_TOOL_MODULE_MAP = {
703
703
  "trigger-env": "settings"
704
704
  };
705
705
  async function discoverInstance(projectSlug, conn, proxy, sshExec2) {
706
- const sql26 = `SELECT re.\\"apiKey\\" || '~~' || p.\\"externalRef\\" FROM \\"RuntimeEnvironment\\" re JOIN \\"Project\\" p ON re.\\"projectId\\" = p.id WHERE p.slug='${projectSlug}' AND re.slug='prod' LIMIT 1`;
706
+ const sql28 = `SELECT re.\\"apiKey\\" || '~~' || p.\\"externalRef\\" FROM \\"RuntimeEnvironment\\" re JOIN \\"Project\\" p ON re.\\"projectId\\" = p.id WHERE p.slug='${projectSlug}' AND re.slug='prod' LIMIT 1`;
707
707
  const cmd = [
708
708
  `PORT=$(docker port "${WA_CONTAINER}" 3000/tcp 2>/dev/null | head -1 | sed 's/.*://')`,
709
- `ROW=$(docker exec "${PG_CONTAINER}" psql -U postgres -d main -t -A -c "${sql26}" 2>/dev/null | tr -d '[:space:]')`,
709
+ `ROW=$(docker exec "${PG_CONTAINER}" psql -U postgres -d main -t -A -c "${sql28}" 2>/dev/null | tr -d '[:space:]')`,
710
710
  'echo "$PORT|$ROW"'
711
711
  ].join(" && ");
712
712
  const result = await sshExec2(conn, cmd, proxy);
@@ -728,8 +728,8 @@ async function discoverInstance(projectSlug, conn, proxy, sshExec2) {
728
728
  return { port, apiKey: apiKey2, projectRef: projectRef || "" };
729
729
  }
730
730
  async function fetchRunLogs(runId, conn, proxy, sshExec2) {
731
- const sql26 = `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`;
732
- const cmd = `docker exec "${PG_CONTAINER}" psql -U postgres -d main -t -A -c "${sql26}" 2>/dev/null`;
731
+ 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`;
732
+ const cmd = `docker exec "${PG_CONTAINER}" psql -U postgres -d main -t -A -c "${sql28}" 2>/dev/null`;
733
733
  const result = await sshExec2(conn, cmd, proxy);
734
734
  const output = result.stdout.trim();
735
735
  if (!output) return "";
@@ -811,8 +811,8 @@ async function handleTriggerTool(name, args2, deps) {
811
811
  switch (name) {
812
812
  // -----------------------------------------------------------------
813
813
  case "trigger-list": {
814
- const sql26 = 'SELECT slug, name FROM \\"Project\\" ORDER BY name';
815
- const cmd = `docker exec "${PG_CONTAINER}" psql -U postgres -d main -t -A -c "${sql26}" 2>/dev/null`;
814
+ const sql28 = 'SELECT slug, name FROM \\"Project\\" ORDER BY name';
815
+ const cmd = `docker exec "${PG_CONTAINER}" psql -U postgres -d main -t -A -c "${sql28}" 2>/dev/null`;
816
816
  const result = await sshExec2(conn, cmd, proxy);
817
817
  const output = result.stdout.trim();
818
818
  if (!output) {
@@ -990,9 +990,9 @@ ${raw2.substring(0, 500)}` }] };
990
990
  return { content: [{ type: "text", text: `No environment variables for ${project}/${env}.` }] };
991
991
  }
992
992
  const lines = vars.map((v) => `${v.isSecret ? "[secret]" : " "} ${v.name}`).sort();
993
- const text10 = `Env vars for ${project}/${env} (${vars.length}) \u2014 values hidden, use action="get" with a key:
993
+ const text12 = `Env vars for ${project}/${env} (${vars.length}) \u2014 values hidden, use action="get" with a key:
994
994
  ` + "-".repeat(50) + "\n" + lines.join("\n");
995
- return { content: [{ type: "text", text: text10 }] };
995
+ return { content: [{ type: "text", text: text12 }] };
996
996
  }
997
997
  if (action === "get") {
998
998
  const key2 = String(args2.key ?? "");
@@ -1079,9 +1079,9 @@ async function fetchAndFormatRun(conn, proxy, sshExec2, instance, runId) {
1079
1079
  return { content: [{ type: "text", text: `Invalid API response:
1080
1080
  ${rawJson.substring(0, 500)}` }] };
1081
1081
  }
1082
- let text10 = formatRunDetail(run);
1083
- if (logs) text10 += "\n\n--- Logs ---\n" + logs;
1084
- return { content: [{ type: "text", text: text10 }] };
1082
+ let text12 = formatRunDetail(run);
1083
+ if (logs) text12 += "\n\n--- Logs ---\n" + logs;
1084
+ return { content: [{ type: "text", text: text12 }] };
1085
1085
  }
1086
1086
  async function waitForCompletion(conn, proxy, sshExec2, instance, runId, waitSeconds) {
1087
1087
  const pollInterval = 3e3;
@@ -1103,10 +1103,10 @@ async function waitForCompletion(conn, proxy, sshExec2, instance, runId, waitSec
1103
1103
  continue;
1104
1104
  }
1105
1105
  if (TERMINAL_STATUSES.has(run.status)) {
1106
- let text10 = formatRunDetail(run);
1106
+ let text12 = formatRunDetail(run);
1107
1107
  const logs = await fetchRunLogs(runId, conn, proxy, sshExec2);
1108
- if (logs) text10 += "\n\n--- Logs ---\n" + logs;
1109
- return { content: [{ type: "text", text: text10 }] };
1108
+ if (logs) text12 += "\n\n--- Logs ---\n" + logs;
1109
+ return { content: [{ type: "text", text: text12 }] };
1110
1110
  }
1111
1111
  }
1112
1112
  return {
@@ -1968,7 +1968,7 @@ var ZodType = class {
1968
1968
  const result = await (isAsync(maybeAsyncResult) ? maybeAsyncResult : Promise.resolve(maybeAsyncResult));
1969
1969
  return handleResult(ctx, result);
1970
1970
  }
1971
- refine(check2, message) {
1971
+ refine(check3, message) {
1972
1972
  const getIssueProperties = (val) => {
1973
1973
  if (typeof message === "string" || typeof message === "undefined") {
1974
1974
  return { message };
@@ -1979,7 +1979,7 @@ var ZodType = class {
1979
1979
  }
1980
1980
  };
1981
1981
  return this._refinement((val, ctx) => {
1982
- const result = check2(val);
1982
+ const result = check3(val);
1983
1983
  const setError = () => ctx.addIssue({
1984
1984
  code: ZodIssueCode.custom,
1985
1985
  ...getIssueProperties(val)
@@ -2002,9 +2002,9 @@ var ZodType = class {
2002
2002
  }
2003
2003
  });
2004
2004
  }
2005
- refinement(check2, refinementData) {
2005
+ refinement(check3, refinementData) {
2006
2006
  return this._refinement((val, ctx) => {
2007
- if (!check2(val)) {
2007
+ if (!check3(val)) {
2008
2008
  ctx.addIssue(typeof refinementData === "function" ? refinementData(val, ctx) : refinementData);
2009
2009
  return false;
2010
2010
  } else {
@@ -2224,70 +2224,70 @@ var ZodString = class _ZodString extends ZodType {
2224
2224
  }
2225
2225
  const status = new ParseStatus();
2226
2226
  let ctx = void 0;
2227
- for (const check2 of this._def.checks) {
2228
- if (check2.kind === "min") {
2229
- if (input.data.length < check2.value) {
2227
+ for (const check3 of this._def.checks) {
2228
+ if (check3.kind === "min") {
2229
+ if (input.data.length < check3.value) {
2230
2230
  ctx = this._getOrReturnCtx(input, ctx);
2231
2231
  addIssueToContext(ctx, {
2232
2232
  code: ZodIssueCode.too_small,
2233
- minimum: check2.value,
2233
+ minimum: check3.value,
2234
2234
  type: "string",
2235
2235
  inclusive: true,
2236
2236
  exact: false,
2237
- message: check2.message
2237
+ message: check3.message
2238
2238
  });
2239
2239
  status.dirty();
2240
2240
  }
2241
- } else if (check2.kind === "max") {
2242
- if (input.data.length > check2.value) {
2241
+ } else if (check3.kind === "max") {
2242
+ if (input.data.length > check3.value) {
2243
2243
  ctx = this._getOrReturnCtx(input, ctx);
2244
2244
  addIssueToContext(ctx, {
2245
2245
  code: ZodIssueCode.too_big,
2246
- maximum: check2.value,
2246
+ maximum: check3.value,
2247
2247
  type: "string",
2248
2248
  inclusive: true,
2249
2249
  exact: false,
2250
- message: check2.message
2250
+ message: check3.message
2251
2251
  });
2252
2252
  status.dirty();
2253
2253
  }
2254
- } else if (check2.kind === "length") {
2255
- const tooBig = input.data.length > check2.value;
2256
- const tooSmall = input.data.length < check2.value;
2254
+ } else if (check3.kind === "length") {
2255
+ const tooBig = input.data.length > check3.value;
2256
+ const tooSmall = input.data.length < check3.value;
2257
2257
  if (tooBig || tooSmall) {
2258
2258
  ctx = this._getOrReturnCtx(input, ctx);
2259
2259
  if (tooBig) {
2260
2260
  addIssueToContext(ctx, {
2261
2261
  code: ZodIssueCode.too_big,
2262
- maximum: check2.value,
2262
+ maximum: check3.value,
2263
2263
  type: "string",
2264
2264
  inclusive: true,
2265
2265
  exact: true,
2266
- message: check2.message
2266
+ message: check3.message
2267
2267
  });
2268
2268
  } else if (tooSmall) {
2269
2269
  addIssueToContext(ctx, {
2270
2270
  code: ZodIssueCode.too_small,
2271
- minimum: check2.value,
2271
+ minimum: check3.value,
2272
2272
  type: "string",
2273
2273
  inclusive: true,
2274
2274
  exact: true,
2275
- message: check2.message
2275
+ message: check3.message
2276
2276
  });
2277
2277
  }
2278
2278
  status.dirty();
2279
2279
  }
2280
- } else if (check2.kind === "email") {
2280
+ } else if (check3.kind === "email") {
2281
2281
  if (!emailRegex.test(input.data)) {
2282
2282
  ctx = this._getOrReturnCtx(input, ctx);
2283
2283
  addIssueToContext(ctx, {
2284
2284
  validation: "email",
2285
2285
  code: ZodIssueCode.invalid_string,
2286
- message: check2.message
2286
+ message: check3.message
2287
2287
  });
2288
2288
  status.dirty();
2289
2289
  }
2290
- } else if (check2.kind === "emoji") {
2290
+ } else if (check3.kind === "emoji") {
2291
2291
  if (!emojiRegex) {
2292
2292
  emojiRegex = new RegExp(_emojiRegex, "u");
2293
2293
  }
@@ -2296,61 +2296,61 @@ var ZodString = class _ZodString extends ZodType {
2296
2296
  addIssueToContext(ctx, {
2297
2297
  validation: "emoji",
2298
2298
  code: ZodIssueCode.invalid_string,
2299
- message: check2.message
2299
+ message: check3.message
2300
2300
  });
2301
2301
  status.dirty();
2302
2302
  }
2303
- } else if (check2.kind === "uuid") {
2303
+ } else if (check3.kind === "uuid") {
2304
2304
  if (!uuidRegex.test(input.data)) {
2305
2305
  ctx = this._getOrReturnCtx(input, ctx);
2306
2306
  addIssueToContext(ctx, {
2307
2307
  validation: "uuid",
2308
2308
  code: ZodIssueCode.invalid_string,
2309
- message: check2.message
2309
+ message: check3.message
2310
2310
  });
2311
2311
  status.dirty();
2312
2312
  }
2313
- } else if (check2.kind === "nanoid") {
2313
+ } else if (check3.kind === "nanoid") {
2314
2314
  if (!nanoidRegex.test(input.data)) {
2315
2315
  ctx = this._getOrReturnCtx(input, ctx);
2316
2316
  addIssueToContext(ctx, {
2317
2317
  validation: "nanoid",
2318
2318
  code: ZodIssueCode.invalid_string,
2319
- message: check2.message
2319
+ message: check3.message
2320
2320
  });
2321
2321
  status.dirty();
2322
2322
  }
2323
- } else if (check2.kind === "cuid") {
2323
+ } else if (check3.kind === "cuid") {
2324
2324
  if (!cuidRegex.test(input.data)) {
2325
2325
  ctx = this._getOrReturnCtx(input, ctx);
2326
2326
  addIssueToContext(ctx, {
2327
2327
  validation: "cuid",
2328
2328
  code: ZodIssueCode.invalid_string,
2329
- message: check2.message
2329
+ message: check3.message
2330
2330
  });
2331
2331
  status.dirty();
2332
2332
  }
2333
- } else if (check2.kind === "cuid2") {
2333
+ } else if (check3.kind === "cuid2") {
2334
2334
  if (!cuid2Regex.test(input.data)) {
2335
2335
  ctx = this._getOrReturnCtx(input, ctx);
2336
2336
  addIssueToContext(ctx, {
2337
2337
  validation: "cuid2",
2338
2338
  code: ZodIssueCode.invalid_string,
2339
- message: check2.message
2339
+ message: check3.message
2340
2340
  });
2341
2341
  status.dirty();
2342
2342
  }
2343
- } else if (check2.kind === "ulid") {
2343
+ } else if (check3.kind === "ulid") {
2344
2344
  if (!ulidRegex.test(input.data)) {
2345
2345
  ctx = this._getOrReturnCtx(input, ctx);
2346
2346
  addIssueToContext(ctx, {
2347
2347
  validation: "ulid",
2348
2348
  code: ZodIssueCode.invalid_string,
2349
- message: check2.message
2349
+ message: check3.message
2350
2350
  });
2351
2351
  status.dirty();
2352
2352
  }
2353
- } else if (check2.kind === "url") {
2353
+ } else if (check3.kind === "url") {
2354
2354
  try {
2355
2355
  new URL(input.data);
2356
2356
  } catch {
@@ -2358,153 +2358,153 @@ var ZodString = class _ZodString extends ZodType {
2358
2358
  addIssueToContext(ctx, {
2359
2359
  validation: "url",
2360
2360
  code: ZodIssueCode.invalid_string,
2361
- message: check2.message
2361
+ message: check3.message
2362
2362
  });
2363
2363
  status.dirty();
2364
2364
  }
2365
- } else if (check2.kind === "regex") {
2366
- check2.regex.lastIndex = 0;
2367
- const testResult = check2.regex.test(input.data);
2365
+ } else if (check3.kind === "regex") {
2366
+ check3.regex.lastIndex = 0;
2367
+ const testResult = check3.regex.test(input.data);
2368
2368
  if (!testResult) {
2369
2369
  ctx = this._getOrReturnCtx(input, ctx);
2370
2370
  addIssueToContext(ctx, {
2371
2371
  validation: "regex",
2372
2372
  code: ZodIssueCode.invalid_string,
2373
- message: check2.message
2373
+ message: check3.message
2374
2374
  });
2375
2375
  status.dirty();
2376
2376
  }
2377
- } else if (check2.kind === "trim") {
2377
+ } else if (check3.kind === "trim") {
2378
2378
  input.data = input.data.trim();
2379
- } else if (check2.kind === "includes") {
2380
- if (!input.data.includes(check2.value, check2.position)) {
2379
+ } else if (check3.kind === "includes") {
2380
+ if (!input.data.includes(check3.value, check3.position)) {
2381
2381
  ctx = this._getOrReturnCtx(input, ctx);
2382
2382
  addIssueToContext(ctx, {
2383
2383
  code: ZodIssueCode.invalid_string,
2384
- validation: { includes: check2.value, position: check2.position },
2385
- message: check2.message
2384
+ validation: { includes: check3.value, position: check3.position },
2385
+ message: check3.message
2386
2386
  });
2387
2387
  status.dirty();
2388
2388
  }
2389
- } else if (check2.kind === "toLowerCase") {
2389
+ } else if (check3.kind === "toLowerCase") {
2390
2390
  input.data = input.data.toLowerCase();
2391
- } else if (check2.kind === "toUpperCase") {
2391
+ } else if (check3.kind === "toUpperCase") {
2392
2392
  input.data = input.data.toUpperCase();
2393
- } else if (check2.kind === "startsWith") {
2394
- if (!input.data.startsWith(check2.value)) {
2393
+ } else if (check3.kind === "startsWith") {
2394
+ if (!input.data.startsWith(check3.value)) {
2395
2395
  ctx = this._getOrReturnCtx(input, ctx);
2396
2396
  addIssueToContext(ctx, {
2397
2397
  code: ZodIssueCode.invalid_string,
2398
- validation: { startsWith: check2.value },
2399
- message: check2.message
2398
+ validation: { startsWith: check3.value },
2399
+ message: check3.message
2400
2400
  });
2401
2401
  status.dirty();
2402
2402
  }
2403
- } else if (check2.kind === "endsWith") {
2404
- if (!input.data.endsWith(check2.value)) {
2403
+ } else if (check3.kind === "endsWith") {
2404
+ if (!input.data.endsWith(check3.value)) {
2405
2405
  ctx = this._getOrReturnCtx(input, ctx);
2406
2406
  addIssueToContext(ctx, {
2407
2407
  code: ZodIssueCode.invalid_string,
2408
- validation: { endsWith: check2.value },
2409
- message: check2.message
2408
+ validation: { endsWith: check3.value },
2409
+ message: check3.message
2410
2410
  });
2411
2411
  status.dirty();
2412
2412
  }
2413
- } else if (check2.kind === "datetime") {
2414
- const regex = datetimeRegex(check2);
2413
+ } else if (check3.kind === "datetime") {
2414
+ const regex = datetimeRegex(check3);
2415
2415
  if (!regex.test(input.data)) {
2416
2416
  ctx = this._getOrReturnCtx(input, ctx);
2417
2417
  addIssueToContext(ctx, {
2418
2418
  code: ZodIssueCode.invalid_string,
2419
2419
  validation: "datetime",
2420
- message: check2.message
2420
+ message: check3.message
2421
2421
  });
2422
2422
  status.dirty();
2423
2423
  }
2424
- } else if (check2.kind === "date") {
2424
+ } else if (check3.kind === "date") {
2425
2425
  const regex = dateRegex;
2426
2426
  if (!regex.test(input.data)) {
2427
2427
  ctx = this._getOrReturnCtx(input, ctx);
2428
2428
  addIssueToContext(ctx, {
2429
2429
  code: ZodIssueCode.invalid_string,
2430
2430
  validation: "date",
2431
- message: check2.message
2431
+ message: check3.message
2432
2432
  });
2433
2433
  status.dirty();
2434
2434
  }
2435
- } else if (check2.kind === "time") {
2436
- const regex = timeRegex(check2);
2435
+ } else if (check3.kind === "time") {
2436
+ const regex = timeRegex(check3);
2437
2437
  if (!regex.test(input.data)) {
2438
2438
  ctx = this._getOrReturnCtx(input, ctx);
2439
2439
  addIssueToContext(ctx, {
2440
2440
  code: ZodIssueCode.invalid_string,
2441
2441
  validation: "time",
2442
- message: check2.message
2442
+ message: check3.message
2443
2443
  });
2444
2444
  status.dirty();
2445
2445
  }
2446
- } else if (check2.kind === "duration") {
2446
+ } else if (check3.kind === "duration") {
2447
2447
  if (!durationRegex.test(input.data)) {
2448
2448
  ctx = this._getOrReturnCtx(input, ctx);
2449
2449
  addIssueToContext(ctx, {
2450
2450
  validation: "duration",
2451
2451
  code: ZodIssueCode.invalid_string,
2452
- message: check2.message
2452
+ message: check3.message
2453
2453
  });
2454
2454
  status.dirty();
2455
2455
  }
2456
- } else if (check2.kind === "ip") {
2457
- if (!isValidIP(input.data, check2.version)) {
2456
+ } else if (check3.kind === "ip") {
2457
+ if (!isValidIP(input.data, check3.version)) {
2458
2458
  ctx = this._getOrReturnCtx(input, ctx);
2459
2459
  addIssueToContext(ctx, {
2460
2460
  validation: "ip",
2461
2461
  code: ZodIssueCode.invalid_string,
2462
- message: check2.message
2462
+ message: check3.message
2463
2463
  });
2464
2464
  status.dirty();
2465
2465
  }
2466
- } else if (check2.kind === "jwt") {
2467
- if (!isValidJWT(input.data, check2.alg)) {
2466
+ } else if (check3.kind === "jwt") {
2467
+ if (!isValidJWT(input.data, check3.alg)) {
2468
2468
  ctx = this._getOrReturnCtx(input, ctx);
2469
2469
  addIssueToContext(ctx, {
2470
2470
  validation: "jwt",
2471
2471
  code: ZodIssueCode.invalid_string,
2472
- message: check2.message
2472
+ message: check3.message
2473
2473
  });
2474
2474
  status.dirty();
2475
2475
  }
2476
- } else if (check2.kind === "cidr") {
2477
- if (!isValidCidr(input.data, check2.version)) {
2476
+ } else if (check3.kind === "cidr") {
2477
+ if (!isValidCidr(input.data, check3.version)) {
2478
2478
  ctx = this._getOrReturnCtx(input, ctx);
2479
2479
  addIssueToContext(ctx, {
2480
2480
  validation: "cidr",
2481
2481
  code: ZodIssueCode.invalid_string,
2482
- message: check2.message
2482
+ message: check3.message
2483
2483
  });
2484
2484
  status.dirty();
2485
2485
  }
2486
- } else if (check2.kind === "base64") {
2486
+ } else if (check3.kind === "base64") {
2487
2487
  if (!base64Regex.test(input.data)) {
2488
2488
  ctx = this._getOrReturnCtx(input, ctx);
2489
2489
  addIssueToContext(ctx, {
2490
2490
  validation: "base64",
2491
2491
  code: ZodIssueCode.invalid_string,
2492
- message: check2.message
2492
+ message: check3.message
2493
2493
  });
2494
2494
  status.dirty();
2495
2495
  }
2496
- } else if (check2.kind === "base64url") {
2496
+ } else if (check3.kind === "base64url") {
2497
2497
  if (!base64urlRegex.test(input.data)) {
2498
2498
  ctx = this._getOrReturnCtx(input, ctx);
2499
2499
  addIssueToContext(ctx, {
2500
2500
  validation: "base64url",
2501
2501
  code: ZodIssueCode.invalid_string,
2502
- message: check2.message
2502
+ message: check3.message
2503
2503
  });
2504
2504
  status.dirty();
2505
2505
  }
2506
2506
  } else {
2507
- util.assertNever(check2);
2507
+ util.assertNever(check3);
2508
2508
  }
2509
2509
  }
2510
2510
  return { status: status.value, value: input.data };
@@ -2516,10 +2516,10 @@ var ZodString = class _ZodString extends ZodType {
2516
2516
  ...errorUtil.errToObj(message)
2517
2517
  });
2518
2518
  }
2519
- _addCheck(check2) {
2519
+ _addCheck(check3) {
2520
2520
  return new _ZodString({
2521
2521
  ...this._def,
2522
- checks: [...this._def.checks, check2]
2522
+ checks: [...this._def.checks, check3]
2523
2523
  });
2524
2524
  }
2525
2525
  email(message) {
@@ -2784,67 +2784,67 @@ var ZodNumber = class _ZodNumber extends ZodType {
2784
2784
  }
2785
2785
  let ctx = void 0;
2786
2786
  const status = new ParseStatus();
2787
- for (const check2 of this._def.checks) {
2788
- if (check2.kind === "int") {
2787
+ for (const check3 of this._def.checks) {
2788
+ if (check3.kind === "int") {
2789
2789
  if (!util.isInteger(input.data)) {
2790
2790
  ctx = this._getOrReturnCtx(input, ctx);
2791
2791
  addIssueToContext(ctx, {
2792
2792
  code: ZodIssueCode.invalid_type,
2793
2793
  expected: "integer",
2794
2794
  received: "float",
2795
- message: check2.message
2795
+ message: check3.message
2796
2796
  });
2797
2797
  status.dirty();
2798
2798
  }
2799
- } else if (check2.kind === "min") {
2800
- const tooSmall = check2.inclusive ? input.data < check2.value : input.data <= check2.value;
2799
+ } else if (check3.kind === "min") {
2800
+ const tooSmall = check3.inclusive ? input.data < check3.value : input.data <= check3.value;
2801
2801
  if (tooSmall) {
2802
2802
  ctx = this._getOrReturnCtx(input, ctx);
2803
2803
  addIssueToContext(ctx, {
2804
2804
  code: ZodIssueCode.too_small,
2805
- minimum: check2.value,
2805
+ minimum: check3.value,
2806
2806
  type: "number",
2807
- inclusive: check2.inclusive,
2807
+ inclusive: check3.inclusive,
2808
2808
  exact: false,
2809
- message: check2.message
2809
+ message: check3.message
2810
2810
  });
2811
2811
  status.dirty();
2812
2812
  }
2813
- } else if (check2.kind === "max") {
2814
- const tooBig = check2.inclusive ? input.data > check2.value : input.data >= check2.value;
2813
+ } else if (check3.kind === "max") {
2814
+ const tooBig = check3.inclusive ? input.data > check3.value : input.data >= check3.value;
2815
2815
  if (tooBig) {
2816
2816
  ctx = this._getOrReturnCtx(input, ctx);
2817
2817
  addIssueToContext(ctx, {
2818
2818
  code: ZodIssueCode.too_big,
2819
- maximum: check2.value,
2819
+ maximum: check3.value,
2820
2820
  type: "number",
2821
- inclusive: check2.inclusive,
2821
+ inclusive: check3.inclusive,
2822
2822
  exact: false,
2823
- message: check2.message
2823
+ message: check3.message
2824
2824
  });
2825
2825
  status.dirty();
2826
2826
  }
2827
- } else if (check2.kind === "multipleOf") {
2828
- if (floatSafeRemainder(input.data, check2.value) !== 0) {
2827
+ } else if (check3.kind === "multipleOf") {
2828
+ if (floatSafeRemainder(input.data, check3.value) !== 0) {
2829
2829
  ctx = this._getOrReturnCtx(input, ctx);
2830
2830
  addIssueToContext(ctx, {
2831
2831
  code: ZodIssueCode.not_multiple_of,
2832
- multipleOf: check2.value,
2833
- message: check2.message
2832
+ multipleOf: check3.value,
2833
+ message: check3.message
2834
2834
  });
2835
2835
  status.dirty();
2836
2836
  }
2837
- } else if (check2.kind === "finite") {
2837
+ } else if (check3.kind === "finite") {
2838
2838
  if (!Number.isFinite(input.data)) {
2839
2839
  ctx = this._getOrReturnCtx(input, ctx);
2840
2840
  addIssueToContext(ctx, {
2841
2841
  code: ZodIssueCode.not_finite,
2842
- message: check2.message
2842
+ message: check3.message
2843
2843
  });
2844
2844
  status.dirty();
2845
2845
  }
2846
2846
  } else {
2847
- util.assertNever(check2);
2847
+ util.assertNever(check3);
2848
2848
  }
2849
2849
  }
2850
2850
  return { status: status.value, value: input.data };
@@ -2875,10 +2875,10 @@ var ZodNumber = class _ZodNumber extends ZodType {
2875
2875
  ]
2876
2876
  });
2877
2877
  }
2878
- _addCheck(check2) {
2878
+ _addCheck(check3) {
2879
2879
  return new _ZodNumber({
2880
2880
  ...this._def,
2881
- checks: [...this._def.checks, check2]
2881
+ checks: [...this._def.checks, check3]
2882
2882
  });
2883
2883
  }
2884
2884
  int(message) {
@@ -3013,45 +3013,45 @@ var ZodBigInt = class _ZodBigInt extends ZodType {
3013
3013
  }
3014
3014
  let ctx = void 0;
3015
3015
  const status = new ParseStatus();
3016
- for (const check2 of this._def.checks) {
3017
- if (check2.kind === "min") {
3018
- const tooSmall = check2.inclusive ? input.data < check2.value : input.data <= check2.value;
3016
+ for (const check3 of this._def.checks) {
3017
+ if (check3.kind === "min") {
3018
+ const tooSmall = check3.inclusive ? input.data < check3.value : input.data <= check3.value;
3019
3019
  if (tooSmall) {
3020
3020
  ctx = this._getOrReturnCtx(input, ctx);
3021
3021
  addIssueToContext(ctx, {
3022
3022
  code: ZodIssueCode.too_small,
3023
3023
  type: "bigint",
3024
- minimum: check2.value,
3025
- inclusive: check2.inclusive,
3026
- message: check2.message
3024
+ minimum: check3.value,
3025
+ inclusive: check3.inclusive,
3026
+ message: check3.message
3027
3027
  });
3028
3028
  status.dirty();
3029
3029
  }
3030
- } else if (check2.kind === "max") {
3031
- const tooBig = check2.inclusive ? input.data > check2.value : input.data >= check2.value;
3030
+ } else if (check3.kind === "max") {
3031
+ const tooBig = check3.inclusive ? input.data > check3.value : input.data >= check3.value;
3032
3032
  if (tooBig) {
3033
3033
  ctx = this._getOrReturnCtx(input, ctx);
3034
3034
  addIssueToContext(ctx, {
3035
3035
  code: ZodIssueCode.too_big,
3036
3036
  type: "bigint",
3037
- maximum: check2.value,
3038
- inclusive: check2.inclusive,
3039
- message: check2.message
3037
+ maximum: check3.value,
3038
+ inclusive: check3.inclusive,
3039
+ message: check3.message
3040
3040
  });
3041
3041
  status.dirty();
3042
3042
  }
3043
- } else if (check2.kind === "multipleOf") {
3044
- if (input.data % check2.value !== BigInt(0)) {
3043
+ } else if (check3.kind === "multipleOf") {
3044
+ if (input.data % check3.value !== BigInt(0)) {
3045
3045
  ctx = this._getOrReturnCtx(input, ctx);
3046
3046
  addIssueToContext(ctx, {
3047
3047
  code: ZodIssueCode.not_multiple_of,
3048
- multipleOf: check2.value,
3049
- message: check2.message
3048
+ multipleOf: check3.value,
3049
+ message: check3.message
3050
3050
  });
3051
3051
  status.dirty();
3052
3052
  }
3053
3053
  } else {
3054
- util.assertNever(check2);
3054
+ util.assertNever(check3);
3055
3055
  }
3056
3056
  }
3057
3057
  return { status: status.value, value: input.data };
@@ -3091,10 +3091,10 @@ var ZodBigInt = class _ZodBigInt extends ZodType {
3091
3091
  ]
3092
3092
  });
3093
3093
  }
3094
- _addCheck(check2) {
3094
+ _addCheck(check3) {
3095
3095
  return new _ZodBigInt({
3096
3096
  ...this._def,
3097
- checks: [...this._def.checks, check2]
3097
+ checks: [...this._def.checks, check3]
3098
3098
  });
3099
3099
  }
3100
3100
  positive(message) {
@@ -3214,35 +3214,35 @@ var ZodDate = class _ZodDate extends ZodType {
3214
3214
  }
3215
3215
  const status = new ParseStatus();
3216
3216
  let ctx = void 0;
3217
- for (const check2 of this._def.checks) {
3218
- if (check2.kind === "min") {
3219
- if (input.data.getTime() < check2.value) {
3217
+ for (const check3 of this._def.checks) {
3218
+ if (check3.kind === "min") {
3219
+ if (input.data.getTime() < check3.value) {
3220
3220
  ctx = this._getOrReturnCtx(input, ctx);
3221
3221
  addIssueToContext(ctx, {
3222
3222
  code: ZodIssueCode.too_small,
3223
- message: check2.message,
3223
+ message: check3.message,
3224
3224
  inclusive: true,
3225
3225
  exact: false,
3226
- minimum: check2.value,
3226
+ minimum: check3.value,
3227
3227
  type: "date"
3228
3228
  });
3229
3229
  status.dirty();
3230
3230
  }
3231
- } else if (check2.kind === "max") {
3232
- if (input.data.getTime() > check2.value) {
3231
+ } else if (check3.kind === "max") {
3232
+ if (input.data.getTime() > check3.value) {
3233
3233
  ctx = this._getOrReturnCtx(input, ctx);
3234
3234
  addIssueToContext(ctx, {
3235
3235
  code: ZodIssueCode.too_big,
3236
- message: check2.message,
3236
+ message: check3.message,
3237
3237
  inclusive: true,
3238
3238
  exact: false,
3239
- maximum: check2.value,
3239
+ maximum: check3.value,
3240
3240
  type: "date"
3241
3241
  });
3242
3242
  status.dirty();
3243
3243
  }
3244
3244
  } else {
3245
- util.assertNever(check2);
3245
+ util.assertNever(check3);
3246
3246
  }
3247
3247
  }
3248
3248
  return {
@@ -3250,10 +3250,10 @@ var ZodDate = class _ZodDate extends ZodType {
3250
3250
  value: new Date(input.data.getTime())
3251
3251
  };
3252
3252
  }
3253
- _addCheck(check2) {
3253
+ _addCheck(check3) {
3254
3254
  return new _ZodDate({
3255
3255
  ...this._def,
3256
- checks: [...this._def.checks, check2]
3256
+ checks: [...this._def.checks, check3]
3257
3257
  });
3258
3258
  }
3259
3259
  min(minDate, message) {
@@ -3793,10 +3793,10 @@ var ZodObject = class _ZodObject extends ZodType {
3793
3793
  // }) as any;
3794
3794
  // return merged;
3795
3795
  // }
3796
- catchall(index8) {
3796
+ catchall(index9) {
3797
3797
  return new _ZodObject({
3798
3798
  ...this._def,
3799
- catchall: index8
3799
+ catchall: index9
3800
3800
  });
3801
3801
  }
3802
3802
  pick(mask) {
@@ -4114,9 +4114,9 @@ function mergeValues(a, b) {
4114
4114
  return { valid: false };
4115
4115
  }
4116
4116
  const newArray = [];
4117
- for (let index8 = 0; index8 < a.length; index8++) {
4118
- const itemA = a[index8];
4119
- const itemB = b[index8];
4117
+ for (let index9 = 0; index9 < a.length; index9++) {
4118
+ const itemA = a[index9];
4119
+ const itemB = b[index9];
4120
4120
  const sharedValue = mergeValues(itemA, itemB);
4121
4121
  if (!sharedValue.valid) {
4122
4122
  return { valid: false };
@@ -4322,10 +4322,10 @@ var ZodMap = class extends ZodType {
4322
4322
  }
4323
4323
  const keyType = this._def.keyType;
4324
4324
  const valueType = this._def.valueType;
4325
- const pairs = [...ctx.data.entries()].map(([key, value], index8) => {
4325
+ const pairs = [...ctx.data.entries()].map(([key, value], index9) => {
4326
4326
  return {
4327
- key: keyType._parse(new ParseInputLazyPath(ctx, key, ctx.path, [index8, "key"])),
4328
- value: valueType._parse(new ParseInputLazyPath(ctx, value, ctx.path, [index8, "value"]))
4327
+ key: keyType._parse(new ParseInputLazyPath(ctx, key, ctx.path, [index9, "key"])),
4328
+ value: valueType._parse(new ParseInputLazyPath(ctx, value, ctx.path, [index9, "value"]))
4329
4329
  };
4330
4330
  });
4331
4331
  if (ctx.common.async) {
@@ -5113,10 +5113,10 @@ function cleanParams(params, data) {
5113
5113
  const p2 = typeof p === "string" ? { message: p } : p;
5114
5114
  return p2;
5115
5115
  }
5116
- function custom(check2, _params = {}, fatal) {
5117
- if (check2)
5116
+ function custom(check3, _params = {}, fatal) {
5117
+ if (check3)
5118
5118
  return ZodAny.create().superRefine((data, ctx) => {
5119
- const r = check2(data);
5119
+ const r = check3(data);
5120
5120
  if (r instanceof Promise) {
5121
5121
  return r.then((r2) => {
5122
5122
  if (!r2) {
@@ -6123,6 +6123,128 @@ pgTable(
6123
6123
  index("dns_migration_mailbox_migration_idx").on(table.migrationId)
6124
6124
  ]
6125
6125
  );
6126
+ var directoryLinkType = pgEnum("directory_link_type", [
6127
+ "dofollow",
6128
+ "nofollow",
6129
+ "conditional"
6130
+ ]);
6131
+ var directoryPricing = pgEnum("directory_pricing", [
6132
+ "free",
6133
+ "freemium",
6134
+ "paid"
6135
+ ]);
6136
+ var directoryRegion = pgEnum("directory_region", ["nl", "intl"]);
6137
+ var directoryAutomationLevel = pgEnum("directory_automation_level", [
6138
+ "auto",
6139
+ "semi",
6140
+ "manual"
6141
+ ]);
6142
+ var directorySubmissionStatus = pgEnum(
6143
+ "directory_submission_status",
6144
+ [
6145
+ "pending",
6146
+ "queued",
6147
+ "submitted",
6148
+ "verification_needed",
6149
+ "awaiting_review",
6150
+ "live",
6151
+ "rejected",
6152
+ "failed",
6153
+ "manual"
6154
+ ]
6155
+ );
6156
+ var linkDirectory = pgTable(
6157
+ "link_directory",
6158
+ {
6159
+ id: uuid("id").primaryKey().defaultRandom(),
6160
+ name: text("name").notNull(),
6161
+ url: text("url").notNull(),
6162
+ submitUrl: text("submit_url").notNull(),
6163
+ dr: integer("dr").notNull().default(0),
6164
+ linkType: directoryLinkType("link_type").notNull().default("nofollow"),
6165
+ pricing: directoryPricing("pricing").notNull().default("free"),
6166
+ category: text("category").notNull().default("General Directory"),
6167
+ region: directoryRegion("region").notNull().default("intl"),
6168
+ automationLevel: directoryAutomationLevel("automation_level").notNull().default("auto"),
6169
+ enabled: boolean("enabled").notNull().default(false),
6170
+ formMapping: jsonb("form_mapping").$type(),
6171
+ lastCheckedAt: timestamp("last_checked_at", { withTimezone: true }),
6172
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
6173
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
6174
+ },
6175
+ (table) => [
6176
+ uniqueIndex("link_directory_submit_url_uidx").on(table.submitUrl),
6177
+ index("link_directory_enabled_dr_idx").on(table.enabled, table.dr),
6178
+ index("link_directory_region_idx").on(table.region)
6179
+ ]
6180
+ );
6181
+ var linkBuildingClient = pgTable(
6182
+ "link_building_client",
6183
+ {
6184
+ id: uuid("id").primaryKey().defaultRandom(),
6185
+ name: text("name").notNull(),
6186
+ websiteUrl: text("website_url").notNull(),
6187
+ mailboxAddress: text("mailbox_address"),
6188
+ refrontMailAccountId: text("refront_mail_account_id"),
6189
+ profile: jsonb("profile").$type().notNull().default({}),
6190
+ weeklyPace: integer("weekly_pace").notNull().default(12),
6191
+ autoSubmit: boolean("auto_submit").notNull().default(false),
6192
+ startingDr: doublePrecision("starting_dr"),
6193
+ currentDr: doublePrecision("current_dr"),
6194
+ isActive: boolean("is_active").notNull().default(true),
6195
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
6196
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
6197
+ },
6198
+ (table) => [
6199
+ uniqueIndex("link_building_client_website_uidx").on(table.websiteUrl),
6200
+ index("link_building_client_active_idx").on(table.isActive)
6201
+ ]
6202
+ );
6203
+ pgTable(
6204
+ "directory_submission",
6205
+ {
6206
+ id: uuid("id").primaryKey().defaultRandom(),
6207
+ clientId: uuid("client_id").notNull().references(() => linkBuildingClient.id, { onDelete: "cascade" }),
6208
+ directoryId: uuid("directory_id").notNull().references(() => linkDirectory.id, { onDelete: "cascade" }),
6209
+ status: directorySubmissionStatus("status").notNull().default("pending"),
6210
+ listingUrl: text("listing_url"),
6211
+ dofollowConfirmed: boolean("dofollow_confirmed"),
6212
+ screenshotPath: text("screenshot_path"),
6213
+ log: jsonb("log").$type().notNull().default({}),
6214
+ queuedAt: timestamp("queued_at", { withTimezone: true }),
6215
+ submittedAt: timestamp("submitted_at", { withTimezone: true }),
6216
+ verifiedAt: timestamp("verified_at", { withTimezone: true }),
6217
+ lastError: text("last_error"),
6218
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
6219
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
6220
+ },
6221
+ (table) => [
6222
+ uniqueIndex("directory_submission_client_directory_uidx").on(
6223
+ table.clientId,
6224
+ table.directoryId
6225
+ ),
6226
+ index("directory_submission_status_idx").on(table.status),
6227
+ index("directory_submission_client_status_idx").on(
6228
+ table.clientId,
6229
+ table.status
6230
+ )
6231
+ ]
6232
+ );
6233
+ pgTable(
6234
+ "client_dr_snapshot",
6235
+ {
6236
+ id: uuid("id").primaryKey().defaultRandom(),
6237
+ clientId: uuid("client_id").notNull().references(() => linkBuildingClient.id, { onDelete: "cascade" }),
6238
+ dr: doublePrecision("dr").notNull(),
6239
+ measuredAt: timestamp("measured_at", { withTimezone: true }).notNull().defaultNow()
6240
+ },
6241
+ (table) => [
6242
+ index("client_dr_snapshot_client_measured_idx").on(
6243
+ table.clientId,
6244
+ table.measuredAt
6245
+ )
6246
+ ]
6247
+ );
6126
6248
  var githubToken = pgTable(
6127
6249
  "github_token",
6128
6250
  {
@@ -6253,6 +6375,42 @@ pgTable(
6253
6375
  index("content_ingestion_runs_project_idx").on(table.projectKey)
6254
6376
  ]
6255
6377
  );
6378
+ pgTable(
6379
+ "refront_source_sync_state",
6380
+ {
6381
+ id: text("id").primaryKey().default("singleton"),
6382
+ boilerHeadSha: text("boiler_head_sha"),
6383
+ boilerTreeHash: text("boiler_tree_hash"),
6384
+ webHeadSha: text("web_head_sha"),
6385
+ webTreeHash: text("web_tree_hash"),
6386
+ status: text("status").notNull().default("idle"),
6387
+ direction: text("direction"),
6388
+ prRepoFullName: text("pr_repo_full_name"),
6389
+ prNumber: integer("pr_number"),
6390
+ prUrl: text("pr_url"),
6391
+ prBranch: text("pr_branch"),
6392
+ prExpectedTreeHash: text("pr_expected_tree_hash"),
6393
+ pendingBoilerHeadSha: text("pending_boiler_head_sha"),
6394
+ pendingBoilerTreeHash: text("pending_boiler_tree_hash"),
6395
+ pendingWebHeadSha: text("pending_web_head_sha"),
6396
+ pendingWebTreeHash: text("pending_web_tree_hash"),
6397
+ consumedWebHeadSha: text("consumed_web_head_sha"),
6398
+ consumedWebTreeHash: text("consumed_web_tree_hash"),
6399
+ conflictAttemptCount: integer("conflict_attempt_count").notNull().default(0),
6400
+ errorMessage: text("error_message"),
6401
+ lastCheckedAt: timestamp("last_checked_at", { withTimezone: true }),
6402
+ syncStartedAt: timestamp("sync_started_at", { withTimezone: true }),
6403
+ completedAt: timestamp("completed_at", { withTimezone: true }),
6404
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
6405
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
6406
+ },
6407
+ (table) => [
6408
+ check(
6409
+ "refront_source_sync_state_singleton_check",
6410
+ sql`${table.id} = 'singleton'`
6411
+ )
6412
+ ]
6413
+ );
6256
6414
  var repoFunnel = pgTable(
6257
6415
  "repo_funnel",
6258
6416
  {
@@ -7710,7 +7868,7 @@ function getEncryptionKey() {
7710
7868
  throw new Error("ENCRYPTION_KEY must be a 64-character hex string");
7711
7869
  return buf;
7712
7870
  }
7713
- function encrypt(text10) {
7871
+ function encrypt(text12) {
7714
7872
  const key = getEncryptionKey();
7715
7873
  const iv = randomBytes(ENC_IV_LENGTH);
7716
7874
  const cipher = createCipheriv(
@@ -7718,7 +7876,7 @@ function encrypt(text10) {
7718
7876
  new Uint8Array(key),
7719
7877
  new Uint8Array(iv)
7720
7878
  );
7721
- let encrypted = cipher.update(text10, "utf8", "hex");
7879
+ let encrypted = cipher.update(text12, "utf8", "hex");
7722
7880
  encrypted += cipher.final("hex");
7723
7881
  const authTag = cipher.getAuthTag();
7724
7882
  return Buffer.concat([
@@ -8438,10 +8596,10 @@ async function r2GetObjectRange(bucket, key, range) {
8438
8596
  const body = result.Body;
8439
8597
  if (!body?.transformToString)
8440
8598
  throw new Error("R2 returned no readable body");
8441
- const text10 = await body.transformToString();
8599
+ const text12 = await body.transformToString();
8442
8600
  const header = `# range: bytes ${range.offset}-${end} of ${size} (${effectiveLen} bytes)`;
8443
8601
  return `${header}
8444
- ${text10}`;
8602
+ ${text12}`;
8445
8603
  } catch (e) {
8446
8604
  throw r2WrapError(bucket, key, e);
8447
8605
  }
@@ -8804,15 +8962,15 @@ async function sftpRead(opts, filePath, proxy, options) {
8804
8962
  clearTimeout(timer);
8805
8963
  cleanup?.();
8806
8964
  cleanup = void 0;
8807
- const text10 = Buffer.concat(
8965
+ const text12 = Buffer.concat(
8808
8966
  chunks.map((ch) => new Uint8Array(ch))
8809
8967
  ).toString("utf-8");
8810
8968
  if (!isWholeFileRequest) {
8811
8969
  const header = `# range: bytes ${offset}-${offset + effectiveLen - 1} of ${total} (${effectiveLen} bytes)`;
8812
8970
  resolve(`${header}
8813
- ${text10}`);
8971
+ ${text12}`);
8814
8972
  } else {
8815
- resolve(text10);
8973
+ resolve(text12);
8816
8974
  }
8817
8975
  });
8818
8976
  rs.on("error", (e) => {
@@ -8959,11 +9117,11 @@ function getKnownContainers(serverId, maxAgeMs = 5 * 6e4) {
8959
9117
  if (Date.now() - e.capturedAt > maxAgeMs) return void 0;
8960
9118
  return e.names;
8961
9119
  }
8962
- function truncateForLLM(text10, maxBytes) {
8963
- const totalBytes = Buffer.byteLength(text10, "utf8");
9120
+ function truncateForLLM(text12, maxBytes) {
9121
+ const totalBytes = Buffer.byteLength(text12, "utf8");
8964
9122
  if (totalBytes <= maxBytes)
8965
- return { text: text10, truncated: false, totalBytes, shownBytes: totalBytes };
8966
- const buf = Buffer.from(text10, "utf8");
9123
+ return { text: text12, truncated: false, totalBytes, shownBytes: totalBytes };
9124
+ const buf = Buffer.from(text12, "utf8");
8967
9125
  let cut = maxBytes;
8968
9126
  while (cut > 0 && (buf[cut] & 192) === 128) cut--;
8969
9127
  const head = buf.subarray(0, cut).toString("utf8");
@@ -8994,10 +9152,10 @@ function postprocessResult(result, meta) {
8994
9152
  if (!result.content?.length) return result;
8995
9153
  if (RAW_JSON_TOOLS.has(meta.toolName)) return result;
8996
9154
  const block = result.content[0];
8997
- let text10 = String(block.text ?? "");
8998
- const trunc = truncateForLLM(text10, RESPONSE_MAX_BYTES);
9155
+ let text12 = String(block.text ?? "");
9156
+ const trunc = truncateForLLM(text12, RESPONSE_MAX_BYTES);
8999
9157
  if (trunc.truncated) {
9000
- text10 = trunc.text + "\n\n... " + buildTruncationHint(
9158
+ text12 = trunc.text + "\n\n... " + buildTruncationHint(
9001
9159
  meta.toolName,
9002
9160
  meta.args,
9003
9161
  trunc.totalBytes,
@@ -9011,11 +9169,11 @@ function postprocessResult(result, meta) {
9011
9169
  const parts = [`took ${tookStr}`, sizeStr];
9012
9170
  if (meta.serverIdLabel) parts.push(`server: ${meta.serverIdLabel}`);
9013
9171
  if (meta.cached) parts.push("cached");
9014
- text10 = `${text10}
9172
+ text12 = `${text12}
9015
9173
 
9016
9174
  [${parts.join(", ")}]`;
9017
9175
  }
9018
- return { ...result, content: [{ ...block, text: text10 }] };
9176
+ return { ...result, content: [{ ...block, text: text12 }] };
9019
9177
  }
9020
9178
  function buildPipelineScript(commands, shell, marker, stopOnError) {
9021
9179
  if (shell === "powershell") {
@@ -9801,11 +9959,11 @@ CREATE TABLE IF NOT EXISTS _mcp_migrations (
9801
9959
  applied_by TEXT
9802
9960
  );
9803
9961
  `.trim();
9804
- function normaliseMigrationSql(sql26) {
9805
- return sql26.replace(/\r\n/g, "\n").trim() + "\n";
9962
+ function normaliseMigrationSql(sql28) {
9963
+ return sql28.replace(/\r\n/g, "\n").trim() + "\n";
9806
9964
  }
9807
- function migrationSha256(sql26) {
9808
- return createHash("sha256").update(sql26.replace(/\r\n/g, "\n"), "utf8").digest("hex");
9965
+ function migrationSha256(sql28) {
9966
+ return createHash("sha256").update(sql28.replace(/\r\n/g, "\n"), "utf8").digest("hex");
9809
9967
  }
9810
9968
  function dollarQuoteTag(value) {
9811
9969
  let tag = "_mcp";
@@ -11522,6 +11680,67 @@ var TOOLS = [
11522
11680
  }
11523
11681
  }
11524
11682
  },
11683
+ {
11684
+ name: "search-wiki",
11685
+ description: "Search the team's curated knowledge wiki (the distilled layer ABOVE team memory): compiled pages about how systems actually work, customer setups/quirks, and known recurring issues with their standard fixes. Check this BEFORE search-team-memory \u2014 it is smaller, curated, and deduplicated, so a hit here is usually the complete answer. Every page lists its `sources` (team-memory ids, ticket numbers, commits): follow those with get-team-memory for full raw detail instead of broad searches. Fall back to search-team-memory when nothing relevant comes back or the page's `updated` date looks stale.",
11686
+ inputSchema: {
11687
+ type: "object",
11688
+ properties: {
11689
+ query: {
11690
+ type: "string",
11691
+ description: "The topic/problem in natural language, e.g. 'deploy pipeline failure modes' or 'customer acme integrations'."
11692
+ },
11693
+ limit: {
11694
+ type: "number",
11695
+ description: "Max pages to return (1-20, default 5)."
11696
+ }
11697
+ },
11698
+ required: ["query"]
11699
+ }
11700
+ },
11701
+ {
11702
+ name: "get-wiki-page",
11703
+ description: "Fetch one full knowledge-wiki page (markdown + frontmatter + sources) by the `slug` from a search-wiki result. The `sources` list is the provenance: team-memory ids (fetch via get-team-memory), ticket numbers, and commits.",
11704
+ inputSchema: {
11705
+ type: "object",
11706
+ properties: {
11707
+ slug: {
11708
+ type: "string",
11709
+ description: "Page slug from a search-wiki hit, e.g. 'wiki/engineering/team-memory'."
11710
+ }
11711
+ },
11712
+ required: ["slug"]
11713
+ }
11714
+ },
11715
+ {
11716
+ name: "flag-wiki-page",
11717
+ description: "Report that a knowledge-wiki page was WRONG, outdated or incomplete when you actually used it during real work. This is the wiki's feedback loop: open flags jump the daily reviewer queue and show in the backoffice review panel, so the page gets fixed instead of misleading the next agent. Call it right after discovering the mismatch, with a concrete `detail` of what was wrong and what turned out to be true.",
11718
+ inputSchema: {
11719
+ type: "object",
11720
+ properties: {
11721
+ slug: {
11722
+ type: "string",
11723
+ description: "Slug of the page that misled you, e.g. 'wiki/known-issues/pm2-stale-env-after-reload'."
11724
+ },
11725
+ kind: {
11726
+ type: "string",
11727
+ enum: [
11728
+ "feedback",
11729
+ "stale",
11730
+ "duplicate",
11731
+ "unverified",
11732
+ "obsolete-candidate"
11733
+ ],
11734
+ description: "feedback (default) = wrong/incomplete in practice; stale = outdated vs current reality; duplicate = covers the same thing as another page; obsolete-candidate = the described system/practice appears no longer in use."
11735
+ },
11736
+ detail: {
11737
+ type: "string",
11738
+ description: "What was wrong and what is actually true (be concrete: the claim, the observed reality, ticket/commit refs if any). Min 5 chars."
11739
+ }
11740
+ },
11741
+ required: ["slug", "detail"]
11742
+ }
11743
+ },
11525
11744
  // ----- Cursor Remote (Agent Control) -----
11526
11745
  {
11527
11746
  name: "cursor-remote-list",
@@ -11831,7 +12050,7 @@ async function executeToolCall(name, a, _serverId) {
11831
12050
  ]
11832
12051
  };
11833
12052
  }
11834
- const lines = data.hits.map((hit, index8) => {
12053
+ const lines = data.hits.map((hit, index9) => {
11835
12054
  const when = hit.lastMessageAt ? new Date(hit.lastMessageAt).toISOString().slice(0, 10) : "unknown date";
11836
12055
  const repo = hit.repo ?? "unknown repo";
11837
12056
  const sim = hit.similarity !== null ? ` \xB7 ${(hit.similarity * 100).toFixed(0)}% match` : "";
@@ -11841,7 +12060,7 @@ async function executeToolCall(name, a, _serverId) {
11841
12060
  ...Array.isArray(hit.tech) ? hit.tech.slice(0, 4) : []
11842
12061
  ].filter(Boolean);
11843
12062
  const tags = facets.length > 0 ? ` \xB7 ${facets.join(", ")}` : "";
11844
- return `${index8 + 1}. [${repo} \xB7 ${when}${sim}${tags}] ${hit.title}
12063
+ return `${index9 + 1}. [${repo} \xB7 ${when}${sim}${tags}] ${hit.title}
11845
12064
  id: ${hit.id}
11846
12065
  ${(hit.summary ?? hit.snippet).replace(/\s+/g, " ").slice(0, 500)}`;
11847
12066
  });
@@ -11943,6 +12162,174 @@ ${facets.join(", ")}` : ""),
11943
12162
  ]
11944
12163
  };
11945
12164
  }
12165
+ // ----- Knowledge wiki: search -----
12166
+ case "search-wiki": {
12167
+ const query = typeof a.query === "string" ? a.query.trim() : "";
12168
+ if (!query) {
12169
+ return { content: [{ type: "text", text: "Error: query is required" }] };
12170
+ }
12171
+ const res = await fetch(`${dashboardBaseUrl}/api/wiki/search`, {
12172
+ method: "POST",
12173
+ headers: {
12174
+ "content-type": "application/json",
12175
+ authorization: `Bearer ${apiKey}`
12176
+ },
12177
+ body: JSON.stringify({
12178
+ query,
12179
+ limit: typeof a.limit === "number" ? a.limit : void 0
12180
+ })
12181
+ });
12182
+ if (!res.ok) {
12183
+ const detail = await res.text().catch(() => "");
12184
+ return {
12185
+ content: [
12186
+ {
12187
+ type: "text",
12188
+ text: `Error: wiki search failed (${res.status}). ${detail.slice(0, 300)}`
12189
+ }
12190
+ ]
12191
+ };
12192
+ }
12193
+ const data = await res.json();
12194
+ if (data.count === 0) {
12195
+ return {
12196
+ content: [
12197
+ {
12198
+ type: "text",
12199
+ text: "No wiki pages matched. Fall back to search-team-memory for raw history \u2014 repeated misses here become insight-scout signals automatically."
12200
+ }
12201
+ ]
12202
+ };
12203
+ }
12204
+ const lines = data.hits.map((hit, index9) => {
12205
+ const sim = hit.similarity !== null ? ` \xB7 ${Math.round(hit.similarity * 100)}% match` : "";
12206
+ const tags = hit.tags.length ? ` \xB7 ${hit.tags.slice(0, 5).join(", ")}` : "";
12207
+ const sources = hit.sources.length ? `
12208
+ sources: ${hit.sources.slice(0, 6).map((s) => `${s.type}:${s.ref}`).join(", ")}` : "";
12209
+ return `${index9 + 1}. [${hit.status} \xB7 updated ${hit.pageUpdatedOn ?? "unknown"}${sim}${tags}] ${hit.title}
12210
+ slug: ${hit.slug}${sources}
12211
+ ${(hit.summary ?? hit.snippet).replace(/\s+/g, " ").slice(0, 400)}`;
12212
+ });
12213
+ return {
12214
+ content: [
12215
+ {
12216
+ type: "text",
12217
+ text: `Found ${data.count} wiki page(s) (${data.mode} search) \u2014 curated team knowledge.
12218
+ Call get-wiki-page with a slug for the full page; follow its sources (team-memory ids, tickets) for raw detail. Treat stale \`updated\` dates as a signal to also check team memory.
12219
+
12220
+ ` + lines.join("\n\n")
12221
+ }
12222
+ ]
12223
+ };
12224
+ }
12225
+ // ----- Knowledge wiki: full page -----
12226
+ case "get-wiki-page": {
12227
+ const slug = typeof a.slug === "string" ? a.slug.trim() : "";
12228
+ if (!slug) {
12229
+ return { content: [{ type: "text", text: "Error: slug is required" }] };
12230
+ }
12231
+ const res = await fetch(`${dashboardBaseUrl}/api/wiki/page`, {
12232
+ method: "POST",
12233
+ headers: {
12234
+ "content-type": "application/json",
12235
+ authorization: `Bearer ${apiKey}`
12236
+ },
12237
+ body: JSON.stringify({ slug })
12238
+ });
12239
+ if (!res.ok) {
12240
+ const detail = await res.text().catch(() => "");
12241
+ return {
12242
+ content: [
12243
+ {
12244
+ type: "text",
12245
+ text: `Error: wiki page fetch failed (${res.status}). ${detail.slice(0, 300)}`
12246
+ }
12247
+ ]
12248
+ };
12249
+ }
12250
+ const data = await res.json();
12251
+ if (!data.found || !data.page) {
12252
+ return {
12253
+ content: [
12254
+ { type: "text", text: `No wiki page found for slug "${slug}".` }
12255
+ ]
12256
+ };
12257
+ }
12258
+ const page = data.page;
12259
+ const sources = page.sources.length ? `
12260
+ Sources: ${page.sources.map((s) => `${s.type}:${s.ref}`).join(", ")}` : "";
12261
+ return {
12262
+ content: [
12263
+ {
12264
+ type: "text",
12265
+ text: `# ${page.title}
12266
+ [${page.slug} \xB7 ${page.status} \xB7 updated ${page.pageUpdatedOn ?? "unknown"}` + (page.tags.length ? ` \xB7 ${page.tags.join(", ")}` : "") + `]${sources}
12267
+
12268
+ ` + page.content
12269
+ }
12270
+ ]
12271
+ };
12272
+ }
12273
+ // ----- Knowledge wiki: feedback flag -----
12274
+ case "flag-wiki-page": {
12275
+ const slug = typeof a.slug === "string" ? a.slug.trim() : "";
12276
+ const detail = typeof a.detail === "string" ? a.detail.trim() : "";
12277
+ if (!slug || detail.length < 5) {
12278
+ return {
12279
+ content: [
12280
+ {
12281
+ type: "text",
12282
+ text: "Error: slug and a concrete detail (min 5 chars) are required"
12283
+ }
12284
+ ]
12285
+ };
12286
+ }
12287
+ const kind = typeof a.kind === "string" && [
12288
+ "feedback",
12289
+ "stale",
12290
+ "duplicate",
12291
+ "unverified",
12292
+ "obsolete-candidate"
12293
+ ].includes(a.kind) ? a.kind : "feedback";
12294
+ const res = await fetch(`${dashboardBaseUrl}/api/wiki/flag`, {
12295
+ method: "POST",
12296
+ headers: {
12297
+ "content-type": "application/json",
12298
+ authorization: `Bearer ${apiKey}`
12299
+ },
12300
+ body: JSON.stringify({ slug, kind, detail })
12301
+ });
12302
+ if (!res.ok) {
12303
+ const errDetail = await res.text().catch(() => "");
12304
+ return {
12305
+ content: [
12306
+ {
12307
+ type: "text",
12308
+ text: `Error: wiki flag failed (${res.status}). ${errDetail.slice(0, 300)}`
12309
+ }
12310
+ ]
12311
+ };
12312
+ }
12313
+ const data = await res.json();
12314
+ if (!data.found || !data.flag) {
12315
+ return {
12316
+ content: [
12317
+ {
12318
+ type: "text",
12319
+ text: `No wiki page found for slug "${slug}" \u2014 nothing flagged. Check the slug via search-wiki.`
12320
+ }
12321
+ ]
12322
+ };
12323
+ }
12324
+ return {
12325
+ content: [
12326
+ {
12327
+ type: "text",
12328
+ text: `Flagged ${data.flag.slug} (${kind}). The daily wiki reviewer will pick it up next run; it also shows in the backoffice review queue.`
12329
+ }
12330
+ ]
12331
+ };
12332
+ }
11946
12333
  // ----- Cursor Remote (Agent Control) -----
11947
12334
  case "cursor-remote-list": {
11948
12335
  const onlineOnly = a.onlineOnly === true;
@@ -13026,8 +13413,8 @@ ${sample.join("\n")}${files.length > 5 ? `
13026
13413
  };
13027
13414
  const filtered = sortRows(applyFilter(only.rows));
13028
13415
  if (format === "json") {
13029
- const text11 = filtered.map((c) => JSON.stringify(c)).join("\n") || "(no containers)";
13030
- return { content: [{ type: "text", text: text11 }] };
13416
+ const text13 = filtered.map((c) => JSON.stringify(c)).join("\n") || "(no containers)";
13417
+ return { content: [{ type: "text", text: text13 }] };
13031
13418
  }
13032
13419
  if (groupByProject) {
13033
13420
  const groups = /* @__PURE__ */ new Map();
@@ -13054,8 +13441,8 @@ ${sample.join("\n")}${files.length > 5 ? `
13054
13441
  }
13055
13442
  const header = `${"NAMES".padEnd(36)} ${"IMAGE".padEnd(40)} ${"STATUS".padEnd(24)} ${"HEALTH".padEnd(10)} ${"PORTS".padEnd(40)} PROJECT`;
13056
13443
  const body = filtered.map((r) => `${fmtRow(r)} ${r.Project || ""}`);
13057
- const text10 = filtered.length === 0 ? "(no containers match)" : [header, ...body].join("\n");
13058
- return { content: [{ type: "text", text: text10 }] };
13444
+ const text12 = filtered.length === 0 ? "(no containers match)" : [header, ...body].join("\n");
13445
+ return { content: [{ type: "text", text: text12 }] };
13059
13446
  }
13060
13447
  if (format === "json") {
13061
13448
  const lines = [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mgsoftwarebv/mg-dashboard-mcp",
3
- "version": "7.4.4",
3
+ "version": "7.4.6",
4
4
  "description": "MCP Server for MG Dashboard - SSH, SFTP, Docker, domains, DNS, and environment config tools for Cursor",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",