@mgsoftwarebv/mg-dashboard-mcp 7.2.0 → 7.3.1

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
@@ -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, bigint } from 'drizzle-orm/pg-core';
23
+ import { pgTable, timestamp, jsonb, uuid, boolean, text, pgEnum, integer, uniqueIndex, index, check, bigint } 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;
@@ -683,10 +683,10 @@ var TRIGGER_TOOL_MODULE_MAP = {
683
683
  "trigger-run": "ci_cd"
684
684
  };
685
685
  async function discoverInstance(projectSlug, conn, proxy, sshExec2) {
686
- const sql25 = `SELECT re.\\"apiKey\\" FROM \\"RuntimeEnvironment\\" re JOIN \\"Project\\" p ON re.\\"projectId\\" = p.id WHERE p.slug='${projectSlug}' AND re.slug='prod' LIMIT 1`;
686
+ const sql26 = `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
687
  const cmd = [
688
688
  `PORT=$(docker port "${WA_CONTAINER}" 3000/tcp 2>/dev/null | head -1 | sed 's/.*://')`,
689
- `KEY=$(docker exec "${PG_CONTAINER}" psql -U postgres -d main -t -A -c "${sql25}" 2>/dev/null | tr -d '[:space:]')`,
689
+ `KEY=$(docker exec "${PG_CONTAINER}" psql -U postgres -d main -t -A -c "${sql26}" 2>/dev/null | tr -d '[:space:]')`,
690
690
  'echo "$PORT|$KEY"'
691
691
  ].join(" && ");
692
692
  const result = await sshExec2(conn, cmd, proxy);
@@ -707,8 +707,8 @@ async function discoverInstance(projectSlug, conn, proxy, sshExec2) {
707
707
  return { port, apiKey: apiKey2 };
708
708
  }
709
709
  async function fetchRunLogs(runId, conn, proxy, sshExec2) {
710
- const sql25 = `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`;
711
- const cmd = `docker exec "${PG_CONTAINER}" psql -U postgres -d main -t -A -c "${sql25}" 2>/dev/null`;
710
+ 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`;
711
+ const cmd = `docker exec "${PG_CONTAINER}" psql -U postgres -d main -t -A -c "${sql26}" 2>/dev/null`;
712
712
  const result = await sshExec2(conn, cmd, proxy);
713
713
  const output = result.stdout.trim();
714
714
  if (!output) return "";
@@ -790,8 +790,8 @@ async function handleTriggerTool(name, args2, deps) {
790
790
  switch (name) {
791
791
  // -----------------------------------------------------------------
792
792
  case "trigger-list": {
793
- const sql25 = 'SELECT slug, name FROM \\"Project\\" ORDER BY name';
794
- const cmd = `docker exec "${PG_CONTAINER}" psql -U postgres -d main -t -A -c "${sql25}" 2>/dev/null`;
793
+ const sql26 = 'SELECT slug, name FROM \\"Project\\" ORDER BY name';
794
+ const cmd = `docker exec "${PG_CONTAINER}" psql -U postgres -d main -t -A -c "${sql26}" 2>/dev/null`;
795
795
  const result = await sshExec2(conn, cmd, proxy);
796
796
  const output = result.stdout.trim();
797
797
  if (!output) {
@@ -956,9 +956,9 @@ async function fetchAndFormatRun(conn, proxy, sshExec2, instance, runId) {
956
956
  return { content: [{ type: "text", text: `Invalid API response:
957
957
  ${rawJson.substring(0, 500)}` }] };
958
958
  }
959
- let text8 = formatRunDetail(run);
960
- if (logs) text8 += "\n\n--- Logs ---\n" + logs;
961
- return { content: [{ type: "text", text: text8 }] };
959
+ let text9 = formatRunDetail(run);
960
+ if (logs) text9 += "\n\n--- Logs ---\n" + logs;
961
+ return { content: [{ type: "text", text: text9 }] };
962
962
  }
963
963
  async function waitForCompletion(conn, proxy, sshExec2, instance, runId, waitSeconds) {
964
964
  const pollInterval = 3e3;
@@ -980,10 +980,10 @@ async function waitForCompletion(conn, proxy, sshExec2, instance, runId, waitSec
980
980
  continue;
981
981
  }
982
982
  if (TERMINAL_STATUSES.has(run.status)) {
983
- let text8 = formatRunDetail(run);
983
+ let text9 = formatRunDetail(run);
984
984
  const logs = await fetchRunLogs(runId, conn, proxy, sshExec2);
985
- if (logs) text8 += "\n\n--- Logs ---\n" + logs;
986
- return { content: [{ type: "text", text: text8 }] };
985
+ if (logs) text9 += "\n\n--- Logs ---\n" + logs;
986
+ return { content: [{ type: "text", text: text9 }] };
987
987
  }
988
988
  }
989
989
  return {
@@ -1845,7 +1845,7 @@ var ZodType = class {
1845
1845
  const result = await (isAsync(maybeAsyncResult) ? maybeAsyncResult : Promise.resolve(maybeAsyncResult));
1846
1846
  return handleResult(ctx, result);
1847
1847
  }
1848
- refine(check, message) {
1848
+ refine(check2, message) {
1849
1849
  const getIssueProperties = (val) => {
1850
1850
  if (typeof message === "string" || typeof message === "undefined") {
1851
1851
  return { message };
@@ -1856,7 +1856,7 @@ var ZodType = class {
1856
1856
  }
1857
1857
  };
1858
1858
  return this._refinement((val, ctx) => {
1859
- const result = check(val);
1859
+ const result = check2(val);
1860
1860
  const setError = () => ctx.addIssue({
1861
1861
  code: ZodIssueCode.custom,
1862
1862
  ...getIssueProperties(val)
@@ -1879,9 +1879,9 @@ var ZodType = class {
1879
1879
  }
1880
1880
  });
1881
1881
  }
1882
- refinement(check, refinementData) {
1882
+ refinement(check2, refinementData) {
1883
1883
  return this._refinement((val, ctx) => {
1884
- if (!check(val)) {
1884
+ if (!check2(val)) {
1885
1885
  ctx.addIssue(typeof refinementData === "function" ? refinementData(val, ctx) : refinementData);
1886
1886
  return false;
1887
1887
  } else {
@@ -2101,70 +2101,70 @@ var ZodString = class _ZodString extends ZodType {
2101
2101
  }
2102
2102
  const status = new ParseStatus();
2103
2103
  let ctx = void 0;
2104
- for (const check of this._def.checks) {
2105
- if (check.kind === "min") {
2106
- if (input.data.length < check.value) {
2104
+ for (const check2 of this._def.checks) {
2105
+ if (check2.kind === "min") {
2106
+ if (input.data.length < check2.value) {
2107
2107
  ctx = this._getOrReturnCtx(input, ctx);
2108
2108
  addIssueToContext(ctx, {
2109
2109
  code: ZodIssueCode.too_small,
2110
- minimum: check.value,
2110
+ minimum: check2.value,
2111
2111
  type: "string",
2112
2112
  inclusive: true,
2113
2113
  exact: false,
2114
- message: check.message
2114
+ message: check2.message
2115
2115
  });
2116
2116
  status.dirty();
2117
2117
  }
2118
- } else if (check.kind === "max") {
2119
- if (input.data.length > check.value) {
2118
+ } else if (check2.kind === "max") {
2119
+ if (input.data.length > check2.value) {
2120
2120
  ctx = this._getOrReturnCtx(input, ctx);
2121
2121
  addIssueToContext(ctx, {
2122
2122
  code: ZodIssueCode.too_big,
2123
- maximum: check.value,
2123
+ maximum: check2.value,
2124
2124
  type: "string",
2125
2125
  inclusive: true,
2126
2126
  exact: false,
2127
- message: check.message
2127
+ message: check2.message
2128
2128
  });
2129
2129
  status.dirty();
2130
2130
  }
2131
- } else if (check.kind === "length") {
2132
- const tooBig = input.data.length > check.value;
2133
- const tooSmall = input.data.length < check.value;
2131
+ } else if (check2.kind === "length") {
2132
+ const tooBig = input.data.length > check2.value;
2133
+ const tooSmall = input.data.length < check2.value;
2134
2134
  if (tooBig || tooSmall) {
2135
2135
  ctx = this._getOrReturnCtx(input, ctx);
2136
2136
  if (tooBig) {
2137
2137
  addIssueToContext(ctx, {
2138
2138
  code: ZodIssueCode.too_big,
2139
- maximum: check.value,
2139
+ maximum: check2.value,
2140
2140
  type: "string",
2141
2141
  inclusive: true,
2142
2142
  exact: true,
2143
- message: check.message
2143
+ message: check2.message
2144
2144
  });
2145
2145
  } else if (tooSmall) {
2146
2146
  addIssueToContext(ctx, {
2147
2147
  code: ZodIssueCode.too_small,
2148
- minimum: check.value,
2148
+ minimum: check2.value,
2149
2149
  type: "string",
2150
2150
  inclusive: true,
2151
2151
  exact: true,
2152
- message: check.message
2152
+ message: check2.message
2153
2153
  });
2154
2154
  }
2155
2155
  status.dirty();
2156
2156
  }
2157
- } else if (check.kind === "email") {
2157
+ } else if (check2.kind === "email") {
2158
2158
  if (!emailRegex.test(input.data)) {
2159
2159
  ctx = this._getOrReturnCtx(input, ctx);
2160
2160
  addIssueToContext(ctx, {
2161
2161
  validation: "email",
2162
2162
  code: ZodIssueCode.invalid_string,
2163
- message: check.message
2163
+ message: check2.message
2164
2164
  });
2165
2165
  status.dirty();
2166
2166
  }
2167
- } else if (check.kind === "emoji") {
2167
+ } else if (check2.kind === "emoji") {
2168
2168
  if (!emojiRegex) {
2169
2169
  emojiRegex = new RegExp(_emojiRegex, "u");
2170
2170
  }
@@ -2173,61 +2173,61 @@ var ZodString = class _ZodString extends ZodType {
2173
2173
  addIssueToContext(ctx, {
2174
2174
  validation: "emoji",
2175
2175
  code: ZodIssueCode.invalid_string,
2176
- message: check.message
2176
+ message: check2.message
2177
2177
  });
2178
2178
  status.dirty();
2179
2179
  }
2180
- } else if (check.kind === "uuid") {
2180
+ } else if (check2.kind === "uuid") {
2181
2181
  if (!uuidRegex.test(input.data)) {
2182
2182
  ctx = this._getOrReturnCtx(input, ctx);
2183
2183
  addIssueToContext(ctx, {
2184
2184
  validation: "uuid",
2185
2185
  code: ZodIssueCode.invalid_string,
2186
- message: check.message
2186
+ message: check2.message
2187
2187
  });
2188
2188
  status.dirty();
2189
2189
  }
2190
- } else if (check.kind === "nanoid") {
2190
+ } else if (check2.kind === "nanoid") {
2191
2191
  if (!nanoidRegex.test(input.data)) {
2192
2192
  ctx = this._getOrReturnCtx(input, ctx);
2193
2193
  addIssueToContext(ctx, {
2194
2194
  validation: "nanoid",
2195
2195
  code: ZodIssueCode.invalid_string,
2196
- message: check.message
2196
+ message: check2.message
2197
2197
  });
2198
2198
  status.dirty();
2199
2199
  }
2200
- } else if (check.kind === "cuid") {
2200
+ } else if (check2.kind === "cuid") {
2201
2201
  if (!cuidRegex.test(input.data)) {
2202
2202
  ctx = this._getOrReturnCtx(input, ctx);
2203
2203
  addIssueToContext(ctx, {
2204
2204
  validation: "cuid",
2205
2205
  code: ZodIssueCode.invalid_string,
2206
- message: check.message
2206
+ message: check2.message
2207
2207
  });
2208
2208
  status.dirty();
2209
2209
  }
2210
- } else if (check.kind === "cuid2") {
2210
+ } else if (check2.kind === "cuid2") {
2211
2211
  if (!cuid2Regex.test(input.data)) {
2212
2212
  ctx = this._getOrReturnCtx(input, ctx);
2213
2213
  addIssueToContext(ctx, {
2214
2214
  validation: "cuid2",
2215
2215
  code: ZodIssueCode.invalid_string,
2216
- message: check.message
2216
+ message: check2.message
2217
2217
  });
2218
2218
  status.dirty();
2219
2219
  }
2220
- } else if (check.kind === "ulid") {
2220
+ } else if (check2.kind === "ulid") {
2221
2221
  if (!ulidRegex.test(input.data)) {
2222
2222
  ctx = this._getOrReturnCtx(input, ctx);
2223
2223
  addIssueToContext(ctx, {
2224
2224
  validation: "ulid",
2225
2225
  code: ZodIssueCode.invalid_string,
2226
- message: check.message
2226
+ message: check2.message
2227
2227
  });
2228
2228
  status.dirty();
2229
2229
  }
2230
- } else if (check.kind === "url") {
2230
+ } else if (check2.kind === "url") {
2231
2231
  try {
2232
2232
  new URL(input.data);
2233
2233
  } catch {
@@ -2235,153 +2235,153 @@ var ZodString = class _ZodString extends ZodType {
2235
2235
  addIssueToContext(ctx, {
2236
2236
  validation: "url",
2237
2237
  code: ZodIssueCode.invalid_string,
2238
- message: check.message
2238
+ message: check2.message
2239
2239
  });
2240
2240
  status.dirty();
2241
2241
  }
2242
- } else if (check.kind === "regex") {
2243
- check.regex.lastIndex = 0;
2244
- const testResult = check.regex.test(input.data);
2242
+ } else if (check2.kind === "regex") {
2243
+ check2.regex.lastIndex = 0;
2244
+ const testResult = check2.regex.test(input.data);
2245
2245
  if (!testResult) {
2246
2246
  ctx = this._getOrReturnCtx(input, ctx);
2247
2247
  addIssueToContext(ctx, {
2248
2248
  validation: "regex",
2249
2249
  code: ZodIssueCode.invalid_string,
2250
- message: check.message
2250
+ message: check2.message
2251
2251
  });
2252
2252
  status.dirty();
2253
2253
  }
2254
- } else if (check.kind === "trim") {
2254
+ } else if (check2.kind === "trim") {
2255
2255
  input.data = input.data.trim();
2256
- } else if (check.kind === "includes") {
2257
- if (!input.data.includes(check.value, check.position)) {
2256
+ } else if (check2.kind === "includes") {
2257
+ if (!input.data.includes(check2.value, check2.position)) {
2258
2258
  ctx = this._getOrReturnCtx(input, ctx);
2259
2259
  addIssueToContext(ctx, {
2260
2260
  code: ZodIssueCode.invalid_string,
2261
- validation: { includes: check.value, position: check.position },
2262
- message: check.message
2261
+ validation: { includes: check2.value, position: check2.position },
2262
+ message: check2.message
2263
2263
  });
2264
2264
  status.dirty();
2265
2265
  }
2266
- } else if (check.kind === "toLowerCase") {
2266
+ } else if (check2.kind === "toLowerCase") {
2267
2267
  input.data = input.data.toLowerCase();
2268
- } else if (check.kind === "toUpperCase") {
2268
+ } else if (check2.kind === "toUpperCase") {
2269
2269
  input.data = input.data.toUpperCase();
2270
- } else if (check.kind === "startsWith") {
2271
- if (!input.data.startsWith(check.value)) {
2270
+ } else if (check2.kind === "startsWith") {
2271
+ if (!input.data.startsWith(check2.value)) {
2272
2272
  ctx = this._getOrReturnCtx(input, ctx);
2273
2273
  addIssueToContext(ctx, {
2274
2274
  code: ZodIssueCode.invalid_string,
2275
- validation: { startsWith: check.value },
2276
- message: check.message
2275
+ validation: { startsWith: check2.value },
2276
+ message: check2.message
2277
2277
  });
2278
2278
  status.dirty();
2279
2279
  }
2280
- } else if (check.kind === "endsWith") {
2281
- if (!input.data.endsWith(check.value)) {
2280
+ } else if (check2.kind === "endsWith") {
2281
+ if (!input.data.endsWith(check2.value)) {
2282
2282
  ctx = this._getOrReturnCtx(input, ctx);
2283
2283
  addIssueToContext(ctx, {
2284
2284
  code: ZodIssueCode.invalid_string,
2285
- validation: { endsWith: check.value },
2286
- message: check.message
2285
+ validation: { endsWith: check2.value },
2286
+ message: check2.message
2287
2287
  });
2288
2288
  status.dirty();
2289
2289
  }
2290
- } else if (check.kind === "datetime") {
2291
- const regex = datetimeRegex(check);
2290
+ } else if (check2.kind === "datetime") {
2291
+ const regex = datetimeRegex(check2);
2292
2292
  if (!regex.test(input.data)) {
2293
2293
  ctx = this._getOrReturnCtx(input, ctx);
2294
2294
  addIssueToContext(ctx, {
2295
2295
  code: ZodIssueCode.invalid_string,
2296
2296
  validation: "datetime",
2297
- message: check.message
2297
+ message: check2.message
2298
2298
  });
2299
2299
  status.dirty();
2300
2300
  }
2301
- } else if (check.kind === "date") {
2301
+ } else if (check2.kind === "date") {
2302
2302
  const regex = dateRegex;
2303
2303
  if (!regex.test(input.data)) {
2304
2304
  ctx = this._getOrReturnCtx(input, ctx);
2305
2305
  addIssueToContext(ctx, {
2306
2306
  code: ZodIssueCode.invalid_string,
2307
2307
  validation: "date",
2308
- message: check.message
2308
+ message: check2.message
2309
2309
  });
2310
2310
  status.dirty();
2311
2311
  }
2312
- } else if (check.kind === "time") {
2313
- const regex = timeRegex(check);
2312
+ } else if (check2.kind === "time") {
2313
+ const regex = timeRegex(check2);
2314
2314
  if (!regex.test(input.data)) {
2315
2315
  ctx = this._getOrReturnCtx(input, ctx);
2316
2316
  addIssueToContext(ctx, {
2317
2317
  code: ZodIssueCode.invalid_string,
2318
2318
  validation: "time",
2319
- message: check.message
2319
+ message: check2.message
2320
2320
  });
2321
2321
  status.dirty();
2322
2322
  }
2323
- } else if (check.kind === "duration") {
2323
+ } else if (check2.kind === "duration") {
2324
2324
  if (!durationRegex.test(input.data)) {
2325
2325
  ctx = this._getOrReturnCtx(input, ctx);
2326
2326
  addIssueToContext(ctx, {
2327
2327
  validation: "duration",
2328
2328
  code: ZodIssueCode.invalid_string,
2329
- message: check.message
2329
+ message: check2.message
2330
2330
  });
2331
2331
  status.dirty();
2332
2332
  }
2333
- } else if (check.kind === "ip") {
2334
- if (!isValidIP(input.data, check.version)) {
2333
+ } else if (check2.kind === "ip") {
2334
+ if (!isValidIP(input.data, check2.version)) {
2335
2335
  ctx = this._getOrReturnCtx(input, ctx);
2336
2336
  addIssueToContext(ctx, {
2337
2337
  validation: "ip",
2338
2338
  code: ZodIssueCode.invalid_string,
2339
- message: check.message
2339
+ message: check2.message
2340
2340
  });
2341
2341
  status.dirty();
2342
2342
  }
2343
- } else if (check.kind === "jwt") {
2344
- if (!isValidJWT(input.data, check.alg)) {
2343
+ } else if (check2.kind === "jwt") {
2344
+ if (!isValidJWT(input.data, check2.alg)) {
2345
2345
  ctx = this._getOrReturnCtx(input, ctx);
2346
2346
  addIssueToContext(ctx, {
2347
2347
  validation: "jwt",
2348
2348
  code: ZodIssueCode.invalid_string,
2349
- message: check.message
2349
+ message: check2.message
2350
2350
  });
2351
2351
  status.dirty();
2352
2352
  }
2353
- } else if (check.kind === "cidr") {
2354
- if (!isValidCidr(input.data, check.version)) {
2353
+ } else if (check2.kind === "cidr") {
2354
+ if (!isValidCidr(input.data, check2.version)) {
2355
2355
  ctx = this._getOrReturnCtx(input, ctx);
2356
2356
  addIssueToContext(ctx, {
2357
2357
  validation: "cidr",
2358
2358
  code: ZodIssueCode.invalid_string,
2359
- message: check.message
2359
+ message: check2.message
2360
2360
  });
2361
2361
  status.dirty();
2362
2362
  }
2363
- } else if (check.kind === "base64") {
2363
+ } else if (check2.kind === "base64") {
2364
2364
  if (!base64Regex.test(input.data)) {
2365
2365
  ctx = this._getOrReturnCtx(input, ctx);
2366
2366
  addIssueToContext(ctx, {
2367
2367
  validation: "base64",
2368
2368
  code: ZodIssueCode.invalid_string,
2369
- message: check.message
2369
+ message: check2.message
2370
2370
  });
2371
2371
  status.dirty();
2372
2372
  }
2373
- } else if (check.kind === "base64url") {
2373
+ } else if (check2.kind === "base64url") {
2374
2374
  if (!base64urlRegex.test(input.data)) {
2375
2375
  ctx = this._getOrReturnCtx(input, ctx);
2376
2376
  addIssueToContext(ctx, {
2377
2377
  validation: "base64url",
2378
2378
  code: ZodIssueCode.invalid_string,
2379
- message: check.message
2379
+ message: check2.message
2380
2380
  });
2381
2381
  status.dirty();
2382
2382
  }
2383
2383
  } else {
2384
- util.assertNever(check);
2384
+ util.assertNever(check2);
2385
2385
  }
2386
2386
  }
2387
2387
  return { status: status.value, value: input.data };
@@ -2393,10 +2393,10 @@ var ZodString = class _ZodString extends ZodType {
2393
2393
  ...errorUtil.errToObj(message)
2394
2394
  });
2395
2395
  }
2396
- _addCheck(check) {
2396
+ _addCheck(check2) {
2397
2397
  return new _ZodString({
2398
2398
  ...this._def,
2399
- checks: [...this._def.checks, check]
2399
+ checks: [...this._def.checks, check2]
2400
2400
  });
2401
2401
  }
2402
2402
  email(message) {
@@ -2661,67 +2661,67 @@ var ZodNumber = class _ZodNumber extends ZodType {
2661
2661
  }
2662
2662
  let ctx = void 0;
2663
2663
  const status = new ParseStatus();
2664
- for (const check of this._def.checks) {
2665
- if (check.kind === "int") {
2664
+ for (const check2 of this._def.checks) {
2665
+ if (check2.kind === "int") {
2666
2666
  if (!util.isInteger(input.data)) {
2667
2667
  ctx = this._getOrReturnCtx(input, ctx);
2668
2668
  addIssueToContext(ctx, {
2669
2669
  code: ZodIssueCode.invalid_type,
2670
2670
  expected: "integer",
2671
2671
  received: "float",
2672
- message: check.message
2672
+ message: check2.message
2673
2673
  });
2674
2674
  status.dirty();
2675
2675
  }
2676
- } else if (check.kind === "min") {
2677
- const tooSmall = check.inclusive ? input.data < check.value : input.data <= check.value;
2676
+ } else if (check2.kind === "min") {
2677
+ const tooSmall = check2.inclusive ? input.data < check2.value : input.data <= check2.value;
2678
2678
  if (tooSmall) {
2679
2679
  ctx = this._getOrReturnCtx(input, ctx);
2680
2680
  addIssueToContext(ctx, {
2681
2681
  code: ZodIssueCode.too_small,
2682
- minimum: check.value,
2682
+ minimum: check2.value,
2683
2683
  type: "number",
2684
- inclusive: check.inclusive,
2684
+ inclusive: check2.inclusive,
2685
2685
  exact: false,
2686
- message: check.message
2686
+ message: check2.message
2687
2687
  });
2688
2688
  status.dirty();
2689
2689
  }
2690
- } else if (check.kind === "max") {
2691
- const tooBig = check.inclusive ? input.data > check.value : input.data >= check.value;
2690
+ } else if (check2.kind === "max") {
2691
+ const tooBig = check2.inclusive ? input.data > check2.value : input.data >= check2.value;
2692
2692
  if (tooBig) {
2693
2693
  ctx = this._getOrReturnCtx(input, ctx);
2694
2694
  addIssueToContext(ctx, {
2695
2695
  code: ZodIssueCode.too_big,
2696
- maximum: check.value,
2696
+ maximum: check2.value,
2697
2697
  type: "number",
2698
- inclusive: check.inclusive,
2698
+ inclusive: check2.inclusive,
2699
2699
  exact: false,
2700
- message: check.message
2700
+ message: check2.message
2701
2701
  });
2702
2702
  status.dirty();
2703
2703
  }
2704
- } else if (check.kind === "multipleOf") {
2705
- if (floatSafeRemainder(input.data, check.value) !== 0) {
2704
+ } else if (check2.kind === "multipleOf") {
2705
+ if (floatSafeRemainder(input.data, check2.value) !== 0) {
2706
2706
  ctx = this._getOrReturnCtx(input, ctx);
2707
2707
  addIssueToContext(ctx, {
2708
2708
  code: ZodIssueCode.not_multiple_of,
2709
- multipleOf: check.value,
2710
- message: check.message
2709
+ multipleOf: check2.value,
2710
+ message: check2.message
2711
2711
  });
2712
2712
  status.dirty();
2713
2713
  }
2714
- } else if (check.kind === "finite") {
2714
+ } else if (check2.kind === "finite") {
2715
2715
  if (!Number.isFinite(input.data)) {
2716
2716
  ctx = this._getOrReturnCtx(input, ctx);
2717
2717
  addIssueToContext(ctx, {
2718
2718
  code: ZodIssueCode.not_finite,
2719
- message: check.message
2719
+ message: check2.message
2720
2720
  });
2721
2721
  status.dirty();
2722
2722
  }
2723
2723
  } else {
2724
- util.assertNever(check);
2724
+ util.assertNever(check2);
2725
2725
  }
2726
2726
  }
2727
2727
  return { status: status.value, value: input.data };
@@ -2752,10 +2752,10 @@ var ZodNumber = class _ZodNumber extends ZodType {
2752
2752
  ]
2753
2753
  });
2754
2754
  }
2755
- _addCheck(check) {
2755
+ _addCheck(check2) {
2756
2756
  return new _ZodNumber({
2757
2757
  ...this._def,
2758
- checks: [...this._def.checks, check]
2758
+ checks: [...this._def.checks, check2]
2759
2759
  });
2760
2760
  }
2761
2761
  int(message) {
@@ -2890,45 +2890,45 @@ var ZodBigInt = class _ZodBigInt extends ZodType {
2890
2890
  }
2891
2891
  let ctx = void 0;
2892
2892
  const status = new ParseStatus();
2893
- for (const check of this._def.checks) {
2894
- if (check.kind === "min") {
2895
- const tooSmall = check.inclusive ? input.data < check.value : input.data <= check.value;
2893
+ for (const check2 of this._def.checks) {
2894
+ if (check2.kind === "min") {
2895
+ const tooSmall = check2.inclusive ? input.data < check2.value : input.data <= check2.value;
2896
2896
  if (tooSmall) {
2897
2897
  ctx = this._getOrReturnCtx(input, ctx);
2898
2898
  addIssueToContext(ctx, {
2899
2899
  code: ZodIssueCode.too_small,
2900
2900
  type: "bigint",
2901
- minimum: check.value,
2902
- inclusive: check.inclusive,
2903
- message: check.message
2901
+ minimum: check2.value,
2902
+ inclusive: check2.inclusive,
2903
+ message: check2.message
2904
2904
  });
2905
2905
  status.dirty();
2906
2906
  }
2907
- } else if (check.kind === "max") {
2908
- const tooBig = check.inclusive ? input.data > check.value : input.data >= check.value;
2907
+ } else if (check2.kind === "max") {
2908
+ const tooBig = check2.inclusive ? input.data > check2.value : input.data >= check2.value;
2909
2909
  if (tooBig) {
2910
2910
  ctx = this._getOrReturnCtx(input, ctx);
2911
2911
  addIssueToContext(ctx, {
2912
2912
  code: ZodIssueCode.too_big,
2913
2913
  type: "bigint",
2914
- maximum: check.value,
2915
- inclusive: check.inclusive,
2916
- message: check.message
2914
+ maximum: check2.value,
2915
+ inclusive: check2.inclusive,
2916
+ message: check2.message
2917
2917
  });
2918
2918
  status.dirty();
2919
2919
  }
2920
- } else if (check.kind === "multipleOf") {
2921
- if (input.data % check.value !== BigInt(0)) {
2920
+ } else if (check2.kind === "multipleOf") {
2921
+ if (input.data % check2.value !== BigInt(0)) {
2922
2922
  ctx = this._getOrReturnCtx(input, ctx);
2923
2923
  addIssueToContext(ctx, {
2924
2924
  code: ZodIssueCode.not_multiple_of,
2925
- multipleOf: check.value,
2926
- message: check.message
2925
+ multipleOf: check2.value,
2926
+ message: check2.message
2927
2927
  });
2928
2928
  status.dirty();
2929
2929
  }
2930
2930
  } else {
2931
- util.assertNever(check);
2931
+ util.assertNever(check2);
2932
2932
  }
2933
2933
  }
2934
2934
  return { status: status.value, value: input.data };
@@ -2968,10 +2968,10 @@ var ZodBigInt = class _ZodBigInt extends ZodType {
2968
2968
  ]
2969
2969
  });
2970
2970
  }
2971
- _addCheck(check) {
2971
+ _addCheck(check2) {
2972
2972
  return new _ZodBigInt({
2973
2973
  ...this._def,
2974
- checks: [...this._def.checks, check]
2974
+ checks: [...this._def.checks, check2]
2975
2975
  });
2976
2976
  }
2977
2977
  positive(message) {
@@ -3091,35 +3091,35 @@ var ZodDate = class _ZodDate extends ZodType {
3091
3091
  }
3092
3092
  const status = new ParseStatus();
3093
3093
  let ctx = void 0;
3094
- for (const check of this._def.checks) {
3095
- if (check.kind === "min") {
3096
- if (input.data.getTime() < check.value) {
3094
+ for (const check2 of this._def.checks) {
3095
+ if (check2.kind === "min") {
3096
+ if (input.data.getTime() < check2.value) {
3097
3097
  ctx = this._getOrReturnCtx(input, ctx);
3098
3098
  addIssueToContext(ctx, {
3099
3099
  code: ZodIssueCode.too_small,
3100
- message: check.message,
3100
+ message: check2.message,
3101
3101
  inclusive: true,
3102
3102
  exact: false,
3103
- minimum: check.value,
3103
+ minimum: check2.value,
3104
3104
  type: "date"
3105
3105
  });
3106
3106
  status.dirty();
3107
3107
  }
3108
- } else if (check.kind === "max") {
3109
- if (input.data.getTime() > check.value) {
3108
+ } else if (check2.kind === "max") {
3109
+ if (input.data.getTime() > check2.value) {
3110
3110
  ctx = this._getOrReturnCtx(input, ctx);
3111
3111
  addIssueToContext(ctx, {
3112
3112
  code: ZodIssueCode.too_big,
3113
- message: check.message,
3113
+ message: check2.message,
3114
3114
  inclusive: true,
3115
3115
  exact: false,
3116
- maximum: check.value,
3116
+ maximum: check2.value,
3117
3117
  type: "date"
3118
3118
  });
3119
3119
  status.dirty();
3120
3120
  }
3121
3121
  } else {
3122
- util.assertNever(check);
3122
+ util.assertNever(check2);
3123
3123
  }
3124
3124
  }
3125
3125
  return {
@@ -3127,10 +3127,10 @@ var ZodDate = class _ZodDate extends ZodType {
3127
3127
  value: new Date(input.data.getTime())
3128
3128
  };
3129
3129
  }
3130
- _addCheck(check) {
3130
+ _addCheck(check2) {
3131
3131
  return new _ZodDate({
3132
3132
  ...this._def,
3133
- checks: [...this._def.checks, check]
3133
+ checks: [...this._def.checks, check2]
3134
3134
  });
3135
3135
  }
3136
3136
  min(minDate, message) {
@@ -3670,10 +3670,10 @@ var ZodObject = class _ZodObject extends ZodType {
3670
3670
  // }) as any;
3671
3671
  // return merged;
3672
3672
  // }
3673
- catchall(index6) {
3673
+ catchall(index7) {
3674
3674
  return new _ZodObject({
3675
3675
  ...this._def,
3676
- catchall: index6
3676
+ catchall: index7
3677
3677
  });
3678
3678
  }
3679
3679
  pick(mask) {
@@ -3991,9 +3991,9 @@ function mergeValues(a, b) {
3991
3991
  return { valid: false };
3992
3992
  }
3993
3993
  const newArray = [];
3994
- for (let index6 = 0; index6 < a.length; index6++) {
3995
- const itemA = a[index6];
3996
- const itemB = b[index6];
3994
+ for (let index7 = 0; index7 < a.length; index7++) {
3995
+ const itemA = a[index7];
3996
+ const itemB = b[index7];
3997
3997
  const sharedValue = mergeValues(itemA, itemB);
3998
3998
  if (!sharedValue.valid) {
3999
3999
  return { valid: false };
@@ -4199,10 +4199,10 @@ var ZodMap = class extends ZodType {
4199
4199
  }
4200
4200
  const keyType = this._def.keyType;
4201
4201
  const valueType = this._def.valueType;
4202
- const pairs = [...ctx.data.entries()].map(([key, value], index6) => {
4202
+ const pairs = [...ctx.data.entries()].map(([key, value], index7) => {
4203
4203
  return {
4204
- key: keyType._parse(new ParseInputLazyPath(ctx, key, ctx.path, [index6, "key"])),
4205
- value: valueType._parse(new ParseInputLazyPath(ctx, value, ctx.path, [index6, "value"]))
4204
+ key: keyType._parse(new ParseInputLazyPath(ctx, key, ctx.path, [index7, "key"])),
4205
+ value: valueType._parse(new ParseInputLazyPath(ctx, value, ctx.path, [index7, "value"]))
4206
4206
  };
4207
4207
  });
4208
4208
  if (ctx.common.async) {
@@ -4990,10 +4990,10 @@ function cleanParams(params, data) {
4990
4990
  const p2 = typeof p === "string" ? { message: p } : p;
4991
4991
  return p2;
4992
4992
  }
4993
- function custom(check, _params = {}, fatal) {
4994
- if (check)
4993
+ function custom(check2, _params = {}, fatal) {
4994
+ if (check2)
4995
4995
  return ZodAny.create().superRefine((data, ctx) => {
4996
- const r = check(data);
4996
+ const r = check2(data);
4997
4997
  if (r instanceof Promise) {
4998
4998
  return r.then((r2) => {
4999
4999
  if (!r2) {
@@ -5184,6 +5184,11 @@ var contentSnapshotKind = pgEnum("content_snapshot_kind", [
5184
5184
  "corpus",
5185
5185
  "source"
5186
5186
  ]);
5187
+ var contentCandidateStatus = pgEnum("content_candidate_status", [
5188
+ "candidate",
5189
+ "used",
5190
+ "rejected"
5191
+ ]);
5187
5192
  var contentSources = pgTable(
5188
5193
  "content_sources",
5189
5194
  {
@@ -5239,6 +5244,12 @@ var contentEvidencePacks = pgTable(
5239
5244
  openQuestions: jsonb("open_questions").$type().notNull().default([]),
5240
5245
  verbatimWarnings: jsonb("verbatim_warnings").$type().notNull().default([]),
5241
5246
  limitations: jsonb("limitations").$type().notNull().default([]),
5247
+ /**
5248
+ * Order-independent signature of topic + canonical URL set (packSignature).
5249
+ * Lets the reuse-first save path return a fresh stored pack without
5250
+ * re-researching when the same urls/topic are shared again.
5251
+ */
5252
+ sourceSignature: text("source_signature"),
5242
5253
  metadata: jsonb("metadata").$type().notNull().default({}),
5243
5254
  createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
5244
5255
  updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
@@ -5246,7 +5257,8 @@ var contentEvidencePacks = pgTable(
5246
5257
  (table) => [
5247
5258
  index("content_evidence_packs_project_idx").on(table.projectKey),
5248
5259
  index("content_evidence_packs_ticket_idx").on(table.ticketNumber),
5249
- index("content_evidence_packs_generated_idx").on(table.generatedAt.desc())
5260
+ index("content_evidence_packs_generated_idx").on(table.generatedAt.desc()),
5261
+ index("content_evidence_packs_signature_idx").on(table.sourceSignature)
5250
5262
  ]
5251
5263
  );
5252
5264
  pgTable(
@@ -5363,6 +5375,14 @@ pgTable(
5363
5375
  headings: jsonb("headings").$type().notNull().default([]),
5364
5376
  internalLinks: jsonb("internal_links").$type().notNull().default([]),
5365
5377
  metadata: jsonb("metadata").$type().notNull().default({}),
5378
+ /**
5379
+ * Run that captured this snapshot (managed site content sync, 2026-DASMG-042).
5380
+ * Soft pointer (no Drizzle .references() to avoid a schema import cycle); the
5381
+ * DB foreign key is declared in the migration.
5382
+ */
5383
+ ingestionRunId: uuid("ingestion_run_id"),
5384
+ /** Source git commit / deploy id this snapshot was captured for, when known. */
5385
+ sourceCommit: text("source_commit"),
5366
5386
  capturedAt: timestamp("captured_at", { withTimezone: true }).notNull().defaultNow(),
5367
5387
  createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow()
5368
5388
  },
@@ -5376,6 +5396,7 @@ pgTable(
5376
5396
  table.capturedAt.desc()
5377
5397
  ),
5378
5398
  index("content_snapshots_text_hash_idx").on(table.textHash),
5399
+ index("content_snapshots_ingestion_run_idx").on(table.ingestionRunId),
5379
5400
  uniqueIndex("content_snapshots_corpus_hash_uidx").on(
5380
5401
  table.corpusItemId,
5381
5402
  table.textHash
@@ -5386,6 +5407,57 @@ pgTable(
5386
5407
  )
5387
5408
  ]
5388
5409
  );
5410
+ pgTable(
5411
+ "content_site_candidates",
5412
+ {
5413
+ id: uuid("id").primaryKey().defaultRandom(),
5414
+ contentSourceId: uuid("content_source_id").references(
5415
+ () => contentSources.id,
5416
+ { onDelete: "cascade" }
5417
+ ),
5418
+ packId: uuid("pack_id").references(() => contentEvidencePacks.id, {
5419
+ onDelete: "cascade"
5420
+ }),
5421
+ /** Managed site (2026-DASMG-042) when known; soft pointer, no FK to avoid a schema cycle. */
5422
+ managedSiteId: uuid("managed_site_id"),
5423
+ projectKey: text("project_key"),
5424
+ siteKey: text("site_key"),
5425
+ domain: text("domain"),
5426
+ status: contentCandidateStatus("status").notNull().default("candidate"),
5427
+ reason: text("reason"),
5428
+ score: integer("score"),
5429
+ /** The corpus page produced from this content, set when status becomes used. */
5430
+ usedCorpusItemId: uuid("used_corpus_item_id").references(
5431
+ () => contentCorpusItems.id,
5432
+ { onDelete: "set null" }
5433
+ ),
5434
+ usedUrl: text("used_url"),
5435
+ usedAt: timestamp("used_at", { withTimezone: true }),
5436
+ ticketNumber: text("ticket_number"),
5437
+ metadata: jsonb("metadata").$type().notNull().default({}),
5438
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
5439
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
5440
+ },
5441
+ (table) => [
5442
+ index("content_site_candidates_source_idx").on(table.contentSourceId),
5443
+ index("content_site_candidates_pack_idx").on(table.packId),
5444
+ index("content_site_candidates_managed_site_idx").on(table.managedSiteId),
5445
+ index("content_site_candidates_project_idx").on(table.projectKey),
5446
+ index("content_site_candidates_status_idx").on(table.status),
5447
+ uniqueIndex("content_site_candidates_source_site_uidx").on(table.contentSourceId, table.managedSiteId).where(
5448
+ sql`content_source_id IS NOT NULL AND managed_site_id IS NOT NULL`
5449
+ ),
5450
+ uniqueIndex("content_site_candidates_pack_site_uidx").on(table.packId, table.managedSiteId).where(sql`pack_id IS NOT NULL AND managed_site_id IS NOT NULL`),
5451
+ check(
5452
+ "content_site_candidates_subject_chk",
5453
+ sql`content_source_id IS NOT NULL OR pack_id IS NOT NULL`
5454
+ ),
5455
+ check(
5456
+ "content_site_candidates_target_chk",
5457
+ sql`managed_site_id IS NOT NULL OR project_key IS NOT NULL OR domain IS NOT NULL`
5458
+ )
5459
+ ]
5460
+ );
5389
5461
  var managedServerOs = pgEnum("managed_server_os", [
5390
5462
  "linux",
5391
5463
  "windows",
@@ -5961,6 +6033,103 @@ pgTable(
5961
6033
  index("github_webhook_secret_owner_idx").on(table.owner)
5962
6034
  ]
5963
6035
  );
6036
+ var managedSiteSyncMode = pgEnum("managed_site_sync_mode", [
6037
+ "sitemap",
6038
+ "git",
6039
+ "hybrid",
6040
+ "manual"
6041
+ ]);
6042
+ var contentIngestionTrigger = pgEnum("content_ingestion_trigger", [
6043
+ "manual",
6044
+ "git_push",
6045
+ "deploy",
6046
+ "cron",
6047
+ "sitemap"
6048
+ ]);
6049
+ var contentIngestionStatus = pgEnum("content_ingestion_status", [
6050
+ "queued",
6051
+ "running",
6052
+ "completed",
6053
+ "partial",
6054
+ "failed"
6055
+ ]);
6056
+ var managedSites = pgTable(
6057
+ "managed_sites",
6058
+ {
6059
+ id: uuid("id").primaryKey().defaultRandom(),
6060
+ projectKey: text("project_key").notNull(),
6061
+ siteKey: text("site_key"),
6062
+ name: text("name"),
6063
+ domain: text("domain").notNull(),
6064
+ /** GitHub repo (owner/repo) that publishes this site, when git-driven. */
6065
+ repo: text("repo"),
6066
+ /** Branch whose pushes trigger a sync; null = any branch. */
6067
+ branch: text("branch"),
6068
+ sitemapUrl: text("sitemap_url"),
6069
+ sourceType: contentSourceType("source_type").notNull().default("own_site"),
6070
+ enabled: boolean("enabled").notNull().default(true),
6071
+ syncMode: managedSiteSyncMode("sync_mode").notNull().default("sitemap"),
6072
+ /** Git path -> URL mapping rules used to turn changed files into URLs. */
6073
+ pathUrlMap: jsonb("path_url_map").$type().notNull().default([]),
6074
+ /** Per-run URL cap; null = use the engine default. */
6075
+ maxUrlsPerRun: integer("max_urls_per_run"),
6076
+ /** When true, changed pages are flagged for an MG SEO CLI follow-up (soft handoff). */
6077
+ exportToSeoCli: boolean("export_to_seo_cli").notNull().default(false),
6078
+ lastSyncAt: timestamp("last_sync_at", { withTimezone: true }),
6079
+ /** Soft pointer to the most recent run (no FK to avoid a cycle). */
6080
+ lastRunId: uuid("last_run_id"),
6081
+ metadata: jsonb("metadata").$type().notNull().default({}),
6082
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
6083
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
6084
+ },
6085
+ (table) => [
6086
+ uniqueIndex("managed_sites_project_domain_uidx").on(
6087
+ table.projectKey,
6088
+ table.domain
6089
+ ),
6090
+ index("managed_sites_repo_idx").on(table.repo),
6091
+ index("managed_sites_enabled_idx").on(table.enabled),
6092
+ index("managed_sites_project_idx").on(table.projectKey)
6093
+ ]
6094
+ );
6095
+ pgTable(
6096
+ "content_ingestion_runs",
6097
+ {
6098
+ id: uuid("id").primaryKey().defaultRandom(),
6099
+ siteId: uuid("site_id").notNull().references(() => managedSites.id, { onDelete: "cascade" }),
6100
+ projectKey: text("project_key"),
6101
+ triggerType: contentIngestionTrigger("trigger_type").notNull(),
6102
+ status: contentIngestionStatus("status").notNull().default("queued"),
6103
+ /** Trigger.dev run id handling this ingestion, when dispatched. */
6104
+ triggerRunId: text("trigger_run_id"),
6105
+ sourceCommit: text("source_commit"),
6106
+ sourceRef: text("source_ref"),
6107
+ changedUrls: jsonb("changed_urls").$type().notNull().default([]),
6108
+ skippedUrls: jsonb("skipped_urls").$type().notNull().default([]),
6109
+ failedUrls: jsonb("failed_urls").$type().notNull().default([]),
6110
+ limitations: jsonb("limitations").$type().notNull().default([]),
6111
+ /** Corpus item ids touched by this run (for QC / MG SEO CLI handoff). */
6112
+ corpusItemIds: jsonb("corpus_item_ids").$type().notNull().default([]),
6113
+ changedCount: integer("changed_count").notNull().default(0),
6114
+ skippedCount: integer("skipped_count").notNull().default(0),
6115
+ failedCount: integer("failed_count").notNull().default(0),
6116
+ /** Set when changed pages were flagged for an MG SEO CLI follow-up. */
6117
+ qcMarked: boolean("qc_marked").notNull().default(false),
6118
+ error: text("error"),
6119
+ startedAt: timestamp("started_at", { withTimezone: true }),
6120
+ finishedAt: timestamp("finished_at", { withTimezone: true }),
6121
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow()
6122
+ },
6123
+ (table) => [
6124
+ index("content_ingestion_runs_site_idx").on(
6125
+ table.siteId,
6126
+ table.createdAt.desc()
6127
+ ),
6128
+ index("content_ingestion_runs_status_idx").on(table.status),
6129
+ index("content_ingestion_runs_trigger_run_idx").on(table.triggerRunId),
6130
+ index("content_ingestion_runs_project_idx").on(table.projectKey)
6131
+ ]
6132
+ );
5964
6133
  var GITHUB_API = "https://api.github.com";
5965
6134
  var ReleaseProfileQuickCreateError = class extends Error {
5966
6135
  constructor(message, code = "INTERNAL_SERVER_ERROR") {
@@ -7291,7 +7460,7 @@ function getEncryptionKey() {
7291
7460
  throw new Error("ENCRYPTION_KEY must be a 64-character hex string");
7292
7461
  return buf;
7293
7462
  }
7294
- function encrypt(text8) {
7463
+ function encrypt(text9) {
7295
7464
  const key = getEncryptionKey();
7296
7465
  const iv = randomBytes(ENC_IV_LENGTH);
7297
7466
  const cipher = createCipheriv(
@@ -7299,7 +7468,7 @@ function encrypt(text8) {
7299
7468
  new Uint8Array(key),
7300
7469
  new Uint8Array(iv)
7301
7470
  );
7302
- let encrypted = cipher.update(text8, "utf8", "hex");
7471
+ let encrypted = cipher.update(text9, "utf8", "hex");
7303
7472
  encrypted += cipher.final("hex");
7304
7473
  const authTag = cipher.getAuthTag();
7305
7474
  return Buffer.concat([
@@ -8019,10 +8188,10 @@ async function r2GetObjectRange(bucket, key, range) {
8019
8188
  const body = result.Body;
8020
8189
  if (!body?.transformToString)
8021
8190
  throw new Error("R2 returned no readable body");
8022
- const text8 = await body.transformToString();
8191
+ const text9 = await body.transformToString();
8023
8192
  const header = `# range: bytes ${range.offset}-${end} of ${size} (${effectiveLen} bytes)`;
8024
8193
  return `${header}
8025
- ${text8}`;
8194
+ ${text9}`;
8026
8195
  } catch (e) {
8027
8196
  throw r2WrapError(bucket, key, e);
8028
8197
  }
@@ -8385,15 +8554,15 @@ async function sftpRead(opts, filePath, proxy, options) {
8385
8554
  clearTimeout(timer);
8386
8555
  cleanup?.();
8387
8556
  cleanup = void 0;
8388
- const text8 = Buffer.concat(
8557
+ const text9 = Buffer.concat(
8389
8558
  chunks.map((ch) => new Uint8Array(ch))
8390
8559
  ).toString("utf-8");
8391
8560
  if (!isWholeFileRequest) {
8392
8561
  const header = `# range: bytes ${offset}-${offset + effectiveLen - 1} of ${total} (${effectiveLen} bytes)`;
8393
8562
  resolve(`${header}
8394
- ${text8}`);
8563
+ ${text9}`);
8395
8564
  } else {
8396
- resolve(text8);
8565
+ resolve(text9);
8397
8566
  }
8398
8567
  });
8399
8568
  rs.on("error", (e) => {
@@ -8441,7 +8610,16 @@ var RAW_JSON_TOOLS = /* @__PURE__ */ new Set([
8441
8610
  "save_content_quality_run",
8442
8611
  "list_content_snapshots",
8443
8612
  "link_content_pack_to_ticket",
8444
- "prune_content_snapshots"
8613
+ "prune_content_snapshots",
8614
+ "add_site_candidates",
8615
+ "list_site_candidates",
8616
+ "set_candidate_status",
8617
+ // Managed site content sync (2026-DASMG-042) — compact JSON consumed verbatim.
8618
+ "register_managed_site",
8619
+ "update_managed_site",
8620
+ "list_managed_sites",
8621
+ "trigger_content_sync",
8622
+ "get_content_sync_status"
8445
8623
  ]);
8446
8624
  var TOOL_CACHE_TTL_MS = {
8447
8625
  "list-servers": 6e4,
@@ -8542,11 +8720,11 @@ function getKnownContainers(serverId, maxAgeMs = 5 * 6e4) {
8542
8720
  if (Date.now() - e.capturedAt > maxAgeMs) return void 0;
8543
8721
  return e.names;
8544
8722
  }
8545
- function truncateForLLM(text8, maxBytes) {
8546
- const totalBytes = Buffer.byteLength(text8, "utf8");
8723
+ function truncateForLLM(text9, maxBytes) {
8724
+ const totalBytes = Buffer.byteLength(text9, "utf8");
8547
8725
  if (totalBytes <= maxBytes)
8548
- return { text: text8, truncated: false, totalBytes, shownBytes: totalBytes };
8549
- const buf = Buffer.from(text8, "utf8");
8726
+ return { text: text9, truncated: false, totalBytes, shownBytes: totalBytes };
8727
+ const buf = Buffer.from(text9, "utf8");
8550
8728
  let cut = maxBytes;
8551
8729
  while (cut > 0 && (buf[cut] & 192) === 128) cut--;
8552
8730
  const head = buf.subarray(0, cut).toString("utf8");
@@ -8577,10 +8755,10 @@ function postprocessResult(result, meta) {
8577
8755
  if (!result.content?.length) return result;
8578
8756
  if (RAW_JSON_TOOLS.has(meta.toolName)) return result;
8579
8757
  const block = result.content[0];
8580
- let text8 = String(block.text ?? "");
8581
- const trunc = truncateForLLM(text8, RESPONSE_MAX_BYTES);
8758
+ let text9 = String(block.text ?? "");
8759
+ const trunc = truncateForLLM(text9, RESPONSE_MAX_BYTES);
8582
8760
  if (trunc.truncated) {
8583
- text8 = trunc.text + "\n\n... " + buildTruncationHint(
8761
+ text9 = trunc.text + "\n\n... " + buildTruncationHint(
8584
8762
  meta.toolName,
8585
8763
  meta.args,
8586
8764
  trunc.totalBytes,
@@ -8594,11 +8772,11 @@ function postprocessResult(result, meta) {
8594
8772
  const parts = [`took ${tookStr}`, sizeStr];
8595
8773
  if (meta.serverIdLabel) parts.push(`server: ${meta.serverIdLabel}`);
8596
8774
  if (meta.cached) parts.push("cached");
8597
- text8 = `${text8}
8775
+ text9 = `${text9}
8598
8776
 
8599
8777
  [${parts.join(", ")}]`;
8600
8778
  }
8601
- return { ...result, content: [{ ...block, text: text8 }] };
8779
+ return { ...result, content: [{ ...block, text: text9 }] };
8602
8780
  }
8603
8781
  function buildPipelineScript(commands, shell, marker, stopOnError) {
8604
8782
  if (shell === "powershell") {
@@ -9384,11 +9562,11 @@ CREATE TABLE IF NOT EXISTS _mcp_migrations (
9384
9562
  applied_by TEXT
9385
9563
  );
9386
9564
  `.trim();
9387
- function normaliseMigrationSql(sql25) {
9388
- return sql25.replace(/\r\n/g, "\n").trim() + "\n";
9565
+ function normaliseMigrationSql(sql26) {
9566
+ return sql26.replace(/\r\n/g, "\n").trim() + "\n";
9389
9567
  }
9390
- function migrationSha256(sql25) {
9391
- return createHash("sha256").update(sql25.replace(/\r\n/g, "\n"), "utf8").digest("hex");
9568
+ function migrationSha256(sql26) {
9569
+ return createHash("sha256").update(sql26.replace(/\r\n/g, "\n"), "utf8").digest("hex");
9392
9570
  }
9393
9571
  function dollarQuoteTag(value) {
9394
9572
  let tag = "_mcp";
@@ -10961,6 +11139,223 @@ var TOOLS = [
10961
11139
  }
10962
11140
  }
10963
11141
  },
11142
+ {
11143
+ name: "add_site_candidates",
11144
+ description: "Record which site(s) a stored source or research pack could be interesting for, for reuse later (2026-DASMG-041). Attach one or more candidates to a contentSourceId and/or packId; each candidate targets a managedSiteId (preferred) or a projectKey/domain. Re-adding the same (subject, target) updates instead of duplicating.",
11145
+ inputSchema: {
11146
+ type: "object",
11147
+ properties: {
11148
+ contentSourceId: { type: "string", description: "content_sources.id (the source to suggest)." },
11149
+ packId: { type: "string", description: "content_evidence_packs.id (the pack to suggest)." },
11150
+ candidates: {
11151
+ type: "array",
11152
+ description: "Target sites. Each needs a managedSiteId, projectKey or domain.",
11153
+ items: {
11154
+ type: "object",
11155
+ properties: {
11156
+ managedSiteId: { type: "string", description: "managed_sites.id (preferred when managed)." },
11157
+ projectKey: { type: "string", description: "Project identifier (fallback)." },
11158
+ siteKey: { type: "string", description: "Site identifier within the project." },
11159
+ domain: { type: "string", description: "Site domain, e.g. klant.nl (fallback)." },
11160
+ reason: { type: "string", description: "Why this content fits the site." },
11161
+ score: { type: "integer", description: "Optional relevance score 0-100." }
11162
+ }
11163
+ }
11164
+ },
11165
+ ticketNumber: { type: "string", description: "Related ticket number." },
11166
+ metadata: { type: "object" }
11167
+ },
11168
+ required: ["candidates"]
11169
+ }
11170
+ },
11171
+ {
11172
+ name: "list_site_candidates",
11173
+ description: "List content/site candidates (2026-DASMG-041): filter by managedSiteId / projectKey / domain, contentSourceId, packId, status. Use status=candidate to find unused content suggested for a site. Compact; paginated; includes the source title / pack topic for context.",
11174
+ inputSchema: {
11175
+ type: "object",
11176
+ properties: {
11177
+ managedSiteId: { type: "string", description: "managed_sites.id filter." },
11178
+ projectKey: { type: "string", description: "Project filter." },
11179
+ domain: { type: "string", description: "Domain filter." },
11180
+ contentSourceId: { type: "string", description: "content_sources.id filter." },
11181
+ packId: { type: "string", description: "content_evidence_packs.id filter." },
11182
+ status: {
11183
+ type: "string",
11184
+ enum: ["candidate", "used", "rejected"],
11185
+ description: "candidate = suggested, used = published there, rejected = not a fit."
11186
+ },
11187
+ limit: { type: "integer", description: "Max rows (default 20, max 100)." },
11188
+ offset: { type: "integer", description: "Pagination offset." }
11189
+ }
11190
+ }
11191
+ },
11192
+ {
11193
+ name: "set_candidate_status",
11194
+ description: "Update a candidate's status (2026-DASMG-041). Set status=used to mark the content as used on the site (stamps usedAt and records usedCorpusItemId / usedUrl), or rejected when it is not a fit.",
11195
+ inputSchema: {
11196
+ type: "object",
11197
+ properties: {
11198
+ id: { type: "string", description: "content_site_candidates.id (uuid)." },
11199
+ status: {
11200
+ type: "string",
11201
+ enum: ["candidate", "used", "rejected"],
11202
+ description: "New status for the candidate."
11203
+ },
11204
+ usedCorpusItemId: {
11205
+ type: "string",
11206
+ description: "content_corpus_items.id of the page produced (when used)."
11207
+ },
11208
+ usedUrl: { type: "string", description: "URL of the page produced (when used)." },
11209
+ reason: { type: "string", description: "Optional note for the status change." }
11210
+ },
11211
+ required: ["id", "status"]
11212
+ }
11213
+ },
11214
+ {
11215
+ name: "register_managed_site",
11216
+ description: "Register (or upsert by projectKey+domain) a site for content sync (2026-DASMG-042): domain, optional repo/branch + sitemapUrl, syncMode and a git pathUrlMap. Optional + additive \u2014 external/unmanaged sites still work via extract_article without this. Enables git-push/cron/manual ingestion that re-indexes only CHANGED pages into the corpus (hash-skips unchanged ones).",
11217
+ inputSchema: {
11218
+ type: "object",
11219
+ properties: {
11220
+ projectKey: { type: "string", description: "Project identifier (required)." },
11221
+ domain: { type: "string", description: "Site domain, e.g. example.nl (required)." },
11222
+ siteKey: { type: "string", description: "Optional site identifier within the project." },
11223
+ name: { type: "string", description: "Human-friendly site name." },
11224
+ repo: { type: "string", description: "GitHub repo owner/repo that publishes the site (for git pushes)." },
11225
+ branch: { type: "string", description: "Branch whose pushes trigger a sync; omit for any branch." },
11226
+ sitemapUrl: { type: "string", description: "Sitemap URL for sitemap/hybrid detection." },
11227
+ sourceType: {
11228
+ type: "string",
11229
+ enum: [
11230
+ "own_site",
11231
+ "client_site",
11232
+ "external_source",
11233
+ "competitor",
11234
+ "news",
11235
+ "government",
11236
+ "supplier",
11237
+ "unknown"
11238
+ ],
11239
+ description: "Provenance label for produced corpus items (default own_site)."
11240
+ },
11241
+ enabled: { type: "boolean", description: "Whether syncs run (default true)." },
11242
+ syncMode: {
11243
+ type: "string",
11244
+ enum: ["sitemap", "git", "hybrid", "manual"],
11245
+ description: "Change detection: sitemap (lastmod/hash), git (changed paths via pathUrlMap), hybrid (both), manual (only on trigger_content_sync)."
11246
+ },
11247
+ pathUrlMap: {
11248
+ type: "array",
11249
+ items: { type: "object" },
11250
+ description: "Git path -> URL rules ([{pathPrefix,urlPrefix}])."
11251
+ },
11252
+ maxUrlsPerRun: { type: "integer", description: "Per-run URL cap (default 200)." },
11253
+ exportToSeoCli: {
11254
+ type: "boolean",
11255
+ description: "Flag changed pages for an MG SEO CLI follow-up (soft handoff)."
11256
+ },
11257
+ metadata: { type: "object" }
11258
+ },
11259
+ required: ["projectKey", "domain"]
11260
+ }
11261
+ },
11262
+ {
11263
+ name: "update_managed_site",
11264
+ description: "Update an existing managed site by id (2026-DASMG-042). Only the provided fields change \u2014 enable/disable, switch syncMode, set sitemapUrl/pathUrlMap, etc.",
11265
+ inputSchema: {
11266
+ type: "object",
11267
+ properties: {
11268
+ id: { type: "string", description: "managed_sites.id (uuid, required)." },
11269
+ name: { type: "string", description: "Human-friendly site name." },
11270
+ domain: { type: "string", description: "Site domain." },
11271
+ siteKey: { type: "string", description: "Site identifier within the project." },
11272
+ repo: { type: "string", description: "GitHub repo owner/repo." },
11273
+ branch: { type: "string", description: "Branch whose pushes trigger a sync." },
11274
+ sitemapUrl: { type: "string", description: "Sitemap URL." },
11275
+ sourceType: {
11276
+ type: "string",
11277
+ enum: [
11278
+ "own_site",
11279
+ "client_site",
11280
+ "external_source",
11281
+ "competitor",
11282
+ "news",
11283
+ "government",
11284
+ "supplier",
11285
+ "unknown"
11286
+ ]
11287
+ },
11288
+ enabled: { type: "boolean", description: "Enable/disable syncs." },
11289
+ syncMode: {
11290
+ type: "string",
11291
+ enum: ["sitemap", "git", "hybrid", "manual"]
11292
+ },
11293
+ pathUrlMap: { type: "array", items: { type: "object" } },
11294
+ maxUrlsPerRun: { type: "integer", description: "Per-run URL cap." },
11295
+ exportToSeoCli: { type: "boolean" },
11296
+ metadata: { type: "object" }
11297
+ },
11298
+ required: ["id"]
11299
+ }
11300
+ },
11301
+ {
11302
+ name: "list_managed_sites",
11303
+ description: "List managed sites (2026-DASMG-042), filter by projectKey/domain/repo/enabledOnly. Compact, paginated.",
11304
+ inputSchema: {
11305
+ type: "object",
11306
+ properties: {
11307
+ projectKey: { type: "string", description: "Project filter." },
11308
+ domain: { type: "string", description: "Domain filter." },
11309
+ repo: { type: "string", description: "Repo filter (owner/repo)." },
11310
+ enabledOnly: { type: "boolean", description: "Only enabled sites." },
11311
+ limit: { type: "integer", description: "Max rows (default 50, max 200)." },
11312
+ offset: { type: "integer", description: "Pagination offset." }
11313
+ }
11314
+ }
11315
+ },
11316
+ {
11317
+ name: "trigger_content_sync",
11318
+ description: "Start a content ingestion run for a managed site (2026-DASMG-042) by siteId, or projectKey+domain. Detects changed pages (sitemap/git/hash), re-indexes only changes into the corpus and snapshots the previous version. Returns the runId; poll get_content_sync_status for results.",
11319
+ inputSchema: {
11320
+ type: "object",
11321
+ properties: {
11322
+ siteId: { type: "string", description: "managed_sites.id (uuid)." },
11323
+ projectKey: { type: "string", description: "Project identifier (with domain)." },
11324
+ domain: { type: "string", description: "Site domain (with projectKey)." },
11325
+ triggerType: {
11326
+ type: "string",
11327
+ enum: ["manual", "git_push", "deploy", "cron", "sitemap"],
11328
+ description: "Trigger label recorded on the run (default manual)."
11329
+ },
11330
+ sourceCommit: { type: "string", description: "Source git commit/deploy id, when known." },
11331
+ sourceRef: { type: "string", description: "Source git ref, when known." },
11332
+ urls: {
11333
+ type: "array",
11334
+ items: { type: "string" },
11335
+ description: "Restrict the run to these URLs (skips detection)."
11336
+ },
11337
+ changedPaths: {
11338
+ type: "array",
11339
+ items: { type: "string" },
11340
+ description: "Changed repo paths to map to URLs via pathUrlMap."
11341
+ }
11342
+ }
11343
+ }
11344
+ },
11345
+ {
11346
+ name: "get_content_sync_status",
11347
+ description: "Read ingestion run status (2026-DASMG-042): by runId (that run), or by siteId / projectKey+domain (recent runs). Returns changed/skipped/failed counts, the changed URLs, limitations and the site summary.",
11348
+ inputSchema: {
11349
+ type: "object",
11350
+ properties: {
11351
+ runId: { type: "string", description: "content_ingestion_runs.id (uuid)." },
11352
+ siteId: { type: "string", description: "managed_sites.id (uuid)." },
11353
+ projectKey: { type: "string", description: "Project identifier (with domain)." },
11354
+ domain: { type: "string", description: "Site domain (with projectKey)." },
11355
+ limit: { type: "integer", description: "Max recent runs to return (default 10)." }
11356
+ }
11357
+ }
11358
+ },
10964
11359
  {
10965
11360
  name: "search-team-memory",
10966
11361
  description: "Search the team's ENTIRE past Cursor history (every developer, every project) for how something was handled before. Use this FIRST, before investigating from scratch, whenever you: hit a non-trivial bug or error, are about to build something that may have been done before, need a project-specific convention/gotcha, or the user asks 'have we done X', 'how did we fix Y', or 'did we solve this already'. Hybrid semantic + keyword search over mirrored conversations. Returns ranked past chats with repo, date, a solution snippet and a similarity score. Phrase the query as the problem in natural language (e.g. 'release pipeline PM2 deploy fails with module not found').",
@@ -11061,7 +11456,7 @@ var TOOLS = [
11061
11456
  // ----- Trigger.dev -----
11062
11457
  ...TRIGGER_TOOLS
11063
11458
  ];
11064
- var MCP_VERSION = "7.0.5";
11459
+ var MCP_VERSION = "7.3.0";
11065
11460
  async function handleListTools() {
11066
11461
  if (!authContext) return { tools: TOOLS };
11067
11462
  const allowedTools = authContext.allowedTools;
@@ -11280,7 +11675,10 @@ async function executeToolCall(name, a, _serverId) {
11280
11675
  case "save_content_quality_run":
11281
11676
  case "list_content_snapshots":
11282
11677
  case "link_content_pack_to_ticket":
11283
- case "prune_content_snapshots": {
11678
+ case "prune_content_snapshots":
11679
+ case "add_site_candidates":
11680
+ case "list_site_candidates":
11681
+ case "set_candidate_status": {
11284
11682
  const res = await fetch(`${dashboardBaseUrl}/api/tools/content-registry`, {
11285
11683
  method: "POST",
11286
11684
  headers: {
@@ -11305,6 +11703,39 @@ async function executeToolCall(name, a, _serverId) {
11305
11703
  content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
11306
11704
  };
11307
11705
  }
11706
+ // ----- Managed site content sync (2026-DASMG-042) -----
11707
+ // The 5 PUBLIC managed-site tools proxy to one dispatcher route; the tool
11708
+ // name is the dispatcher `action`, args forwarded verbatim as `params`
11709
+ // (the route validates them and only allows the public actions).
11710
+ case "register_managed_site":
11711
+ case "update_managed_site":
11712
+ case "list_managed_sites":
11713
+ case "trigger_content_sync":
11714
+ case "get_content_sync_status": {
11715
+ const res = await fetch(`${dashboardBaseUrl}/api/tools/managed-site`, {
11716
+ method: "POST",
11717
+ headers: {
11718
+ "content-type": "application/json",
11719
+ authorization: `Bearer ${apiKey}`
11720
+ },
11721
+ body: JSON.stringify({ action: name, params: a })
11722
+ });
11723
+ if (!res.ok) {
11724
+ const detail = await res.text().catch(() => "");
11725
+ return {
11726
+ content: [
11727
+ {
11728
+ type: "text",
11729
+ text: `Error: ${name} failed (${res.status}). ${detail.slice(0, 300)}`
11730
+ }
11731
+ ]
11732
+ };
11733
+ }
11734
+ const data = await res.json();
11735
+ return {
11736
+ content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
11737
+ };
11738
+ }
11308
11739
  // ----- Team memory -----
11309
11740
  case "search-team-memory": {
11310
11741
  const query = typeof a.query === "string" ? a.query.trim() : "";
@@ -11346,7 +11777,7 @@ async function executeToolCall(name, a, _serverId) {
11346
11777
  ]
11347
11778
  };
11348
11779
  }
11349
- const lines = data.hits.map((hit, index6) => {
11780
+ const lines = data.hits.map((hit, index7) => {
11350
11781
  const when = hit.lastMessageAt ? new Date(hit.lastMessageAt).toISOString().slice(0, 10) : "unknown date";
11351
11782
  const repo = hit.repo ?? "unknown repo";
11352
11783
  const sim = hit.similarity !== null ? ` \xB7 ${(hit.similarity * 100).toFixed(0)}% match` : "";
@@ -11356,7 +11787,7 @@ async function executeToolCall(name, a, _serverId) {
11356
11787
  ...Array.isArray(hit.tech) ? hit.tech.slice(0, 4) : []
11357
11788
  ].filter(Boolean);
11358
11789
  const tags = facets.length > 0 ? ` \xB7 ${facets.join(", ")}` : "";
11359
- return `${index6 + 1}. [${repo} \xB7 ${when}${sim}${tags}] ${hit.title}
11790
+ return `${index7 + 1}. [${repo} \xB7 ${when}${sim}${tags}] ${hit.title}
11360
11791
  id: ${hit.id}
11361
11792
  ${(hit.summary ?? hit.snippet).replace(/\s+/g, " ").slice(0, 500)}`;
11362
11793
  });
@@ -12541,8 +12972,8 @@ ${sample.join("\n")}${files.length > 5 ? `
12541
12972
  };
12542
12973
  const filtered = sortRows(applyFilter(only.rows));
12543
12974
  if (format === "json") {
12544
- const text9 = filtered.map((c) => JSON.stringify(c)).join("\n") || "(no containers)";
12545
- return { content: [{ type: "text", text: text9 }] };
12975
+ const text10 = filtered.map((c) => JSON.stringify(c)).join("\n") || "(no containers)";
12976
+ return { content: [{ type: "text", text: text10 }] };
12546
12977
  }
12547
12978
  if (groupByProject) {
12548
12979
  const groups = /* @__PURE__ */ new Map();
@@ -12569,8 +13000,8 @@ ${sample.join("\n")}${files.length > 5 ? `
12569
13000
  }
12570
13001
  const header = `${"NAMES".padEnd(36)} ${"IMAGE".padEnd(40)} ${"STATUS".padEnd(24)} ${"HEALTH".padEnd(10)} ${"PORTS".padEnd(40)} PROJECT`;
12571
13002
  const body = filtered.map((r) => `${fmtRow(r)} ${r.Project || ""}`);
12572
- const text8 = filtered.length === 0 ? "(no containers match)" : [header, ...body].join("\n");
12573
- return { content: [{ type: "text", text: text8 }] };
13003
+ const text9 = filtered.length === 0 ? "(no containers match)" : [header, ...body].join("\n");
13004
+ return { content: [{ type: "text", text: text9 }] };
12574
13005
  }
12575
13006
  if (format === "json") {
12576
13007
  const lines = [];